summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS58
-rw-r--r--Documentation/ABI/removed/devfs2
-rw-r--r--Documentation/CodingStyle17
-rw-r--r--Documentation/DocBook/Makefile19
-rw-r--r--Documentation/DocBook/kernel-api.tmpl73
-rw-r--r--Documentation/DocBook/librs.tmpl16
-rw-r--r--Documentation/DocBook/man/Makefile3
-rw-r--r--Documentation/MSI-HOWTO.txt6
-rw-r--r--Documentation/SubmitChecklist4
-rw-r--r--Documentation/SubmittingDrivers15
-rw-r--r--Documentation/SubmittingPatches3
-rw-r--r--Documentation/accounting/getdelays.c20
-rw-r--r--Documentation/arm/Interrupts2
-rw-r--r--Documentation/arm/Samsung-S3C24XX/H1940.txt4
-rw-r--r--Documentation/auxdisplay/cfag12864b6
-rw-r--r--Documentation/binfmt_misc.txt2
-rw-r--r--Documentation/blackfin/00-INDEX11
-rw-r--r--Documentation/blackfin/Filesystems169
-rw-r--r--Documentation/blackfin/cache-lock.txt48
-rw-r--r--Documentation/blackfin/cachefeatures.txt65
-rw-r--r--Documentation/block/ioprio.txt8
-rw-r--r--Documentation/cciss.txt13
-rw-r--r--Documentation/cpu-freq/cpufreq-stats.txt2
-rw-r--r--Documentation/cpu-hotplug.txt9
-rw-r--r--Documentation/crypto/api-intro.txt6
-rw-r--r--Documentation/device-mapper/delay.txt26
-rw-r--r--Documentation/dontdiff4
-rw-r--r--Documentation/driver-model/devres.txt2
-rw-r--r--Documentation/driver-model/platform.txt4
-rw-r--r--Documentation/dvb/README.dvb-usb2
-rw-r--r--Documentation/dvb/contributors.txt2
-rw-r--r--Documentation/fb/arkfb.txt68
-rw-r--r--Documentation/fb/aty128fb.txt4
-rw-r--r--Documentation/fb/deferred_io.txt75
-rw-r--r--Documentation/fb/framebuffer.txt16
-rw-r--r--Documentation/fb/imacfb.txt2
-rw-r--r--Documentation/fb/s3fb.txt12
-rw-r--r--Documentation/fb/sstfb.txt4
-rw-r--r--Documentation/fb/vt8623fb.txt64
-rw-r--r--Documentation/feature-removal-schedule.txt84
-rw-r--r--Documentation/filesystems/Locking8
-rw-r--r--Documentation/filesystems/hpfs.txt2
-rw-r--r--Documentation/filesystems/jfs.txt8
-rw-r--r--Documentation/filesystems/ntfs.txt2
-rw-r--r--Documentation/filesystems/proc.txt40
-rw-r--r--Documentation/filesystems/relay.txt2
-rw-r--r--Documentation/filesystems/vfat.txt7
-rw-r--r--Documentation/filesystems/vfs.txt23
-rw-r--r--Documentation/filesystems/xip.txt2
-rw-r--r--Documentation/fujitsu/frv/gdbstub.txt2
-rw-r--r--Documentation/hwmon/adm10262
-rw-r--r--Documentation/hwmon/coretemp36
-rw-r--r--Documentation/hwmon/gl518sm2
-rw-r--r--Documentation/hwmon/lm832
-rw-r--r--Documentation/hwmon/max665053
-rw-r--r--Documentation/hwmon/sis55952
-rw-r--r--Documentation/hwmon/smsc47m111
-rw-r--r--Documentation/hwmon/smsc47m1927
-rw-r--r--Documentation/hwmon/sysfs-interface7
-rw-r--r--Documentation/hwmon/via686a2
-rw-r--r--Documentation/hwmon/w83792d2
-rw-r--r--Documentation/i2c/busses/i2c-i8102
-rw-r--r--Documentation/i2c/busses/i2c-nforce22
-rw-r--r--Documentation/i2c/busses/i2c-sis96x2
-rw-r--r--Documentation/i2c/busses/i2c-via2
-rw-r--r--Documentation/i2c/busses/i2c-viapro2
-rw-r--r--Documentation/i2c/i2c-protocol2
-rw-r--r--Documentation/i2c/porting-clients18
-rw-r--r--Documentation/i2c/summary29
-rw-r--r--Documentation/i2c/writing-clients415
-rw-r--r--Documentation/i2o/README4
-rw-r--r--Documentation/i386/boot.txt122
-rw-r--r--Documentation/ia64/aliasing-test.c247
-rw-r--r--Documentation/ia64/aliasing.txt71
-rw-r--r--Documentation/ia64/err_inject.txt1068
-rw-r--r--Documentation/input/atarikbd.txt4
-rw-r--r--Documentation/input/input-programming.txt125
-rw-r--r--Documentation/input/xpad.txt6
-rw-r--r--Documentation/ioctl-number.txt3
-rw-r--r--Documentation/isdn/CREDITS4
-rw-r--r--Documentation/isdn/README2
-rw-r--r--Documentation/isdn/README.icn4
-rw-r--r--Documentation/java.txt2
-rw-r--r--Documentation/kbuild/modules.txt2
-rw-r--r--Documentation/kernel-docs.txt2
-rw-r--r--Documentation/kernel-parameters.txt93
-rw-r--r--Documentation/kprobes.txt34
-rw-r--r--Documentation/laptop-mode.txt2
-rw-r--r--Documentation/m68k/README.buddha2
-rw-r--r--Documentation/magic-number.txt2
-rw-r--r--Documentation/md.txt72
-rw-r--r--Documentation/netlabel/introduction.txt2
-rw-r--r--Documentation/networking/6pack.txt2
-rw-r--r--Documentation/networking/NAPI_HOWTO.txt2
-rw-r--r--Documentation/networking/bcm43xx.txt97
-rw-r--r--Documentation/networking/packet_mmap.txt2
-rw-r--r--Documentation/networking/slicecom.hun2
-rw-r--r--Documentation/networking/slicecom.txt4
-rw-r--r--Documentation/networking/tms380tr.txt42
-rw-r--r--Documentation/networking/udplite.txt2
-rw-r--r--Documentation/networking/wan-router.txt4
-rw-r--r--Documentation/oops-tracing.txt3
-rw-r--r--Documentation/pci.txt14
-rw-r--r--Documentation/pcieaer-howto.txt2
-rw-r--r--Documentation/pcmcia/driver.txt30
-rw-r--r--Documentation/pnp.txt2
-rw-r--r--Documentation/power/basic-pm-debugging.txt106
-rw-r--r--Documentation/power/drivers-testing.txt42
-rw-r--r--Documentation/power/interface.txt29
-rw-r--r--Documentation/power/pci.txt2
-rw-r--r--Documentation/power/states.txt13
-rw-r--r--Documentation/power/swsusp.txt16
-rw-r--r--Documentation/power/userland-swsusp.txt26
-rw-r--r--Documentation/powerpc/booting-without-of.txt264
-rw-r--r--Documentation/rtc.txt7
-rw-r--r--Documentation/s390/Debugging390.txt2
-rw-r--r--Documentation/scsi/aacraid.txt7
-rw-r--r--Documentation/scsi/aha152x.txt2
-rw-r--r--Documentation/scsi/aic7xxx.txt2
-rw-r--r--Documentation/scsi/aic7xxx_old.txt2
-rw-r--r--Documentation/scsi/ncr53c8xx.txt7
-rw-r--r--Documentation/scsi/st.txt2
-rw-r--r--Documentation/scsi/sym53c8xx_2.txt2
-rw-r--r--Documentation/scsi/tmscsim.txt2
-rw-r--r--Documentation/sh/clk.txt32
-rw-r--r--Documentation/sony-laptop.txt25
-rw-r--r--Documentation/sonypi.txt2
-rw-r--r--Documentation/sound/oss/mwave2
-rw-r--r--Documentation/spi/pxa2xx2
-rw-r--r--Documentation/spi/spi-summary43
-rw-r--r--Documentation/spi/spidev307
-rw-r--r--Documentation/sysctl/kernel.txt4
-rw-r--r--Documentation/sysctl/vm.txt23
-rw-r--r--Documentation/sysrq.txt4
-rw-r--r--Documentation/thinkpad-acpi.txt (renamed from Documentation/ibm-acpi.txt)585
-rw-r--r--Documentation/tty.txt4
-rw-r--r--Documentation/usb/CREDITS2
-rw-r--r--Documentation/usb/usb-serial.txt8
-rw-r--r--Documentation/video4linux/README.pvrusb22
-rw-r--r--Documentation/video4linux/Zoran2
-rw-r--r--Documentation/video4linux/meye.txt9
-rw-r--r--Documentation/video4linux/ov511.txt4
-rw-r--r--Documentation/vm/slabinfo.c1221
-rw-r--r--Documentation/vm/slub.txt113
-rw-r--r--Documentation/x86_64/boot-options.txt14
-rw-r--r--Documentation/x86_64/fake-numa-for-cpusets66
-rw-r--r--Documentation/x86_64/machinecheck7
-rw-r--r--Kbuild11
-rw-r--r--MAINTAINERS170
-rw-r--r--Makefile17
-rw-r--r--arch/alpha/Kconfig.debug8
-rw-r--r--arch/alpha/boot/bootpz.c6
-rw-r--r--arch/alpha/boot/misc.c2
-rw-r--r--arch/alpha/boot/tools/objstrip.c1
-rw-r--r--arch/alpha/kernel/err_common.c1
-rw-r--r--arch/alpha/kernel/err_ev6.c1
-rw-r--r--arch/alpha/kernel/err_ev7.c1
-rw-r--r--arch/alpha/kernel/osf_sys.c21
-rw-r--r--arch/alpha/kernel/process.c1
-rw-r--r--arch/alpha/kernel/setup.c9
-rw-r--r--arch/alpha/kernel/signal.c1
-rw-r--r--arch/alpha/kernel/smp.c1
-rw-r--r--arch/alpha/kernel/srmcons.c4
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S2
-rw-r--r--arch/alpha/mm/fault.c1
-rw-r--r--arch/arm/Kconfig22
-rw-r--r--arch/arm/Makefile5
-rw-r--r--arch/arm/boot/compressed/head-at91rm9200.S6
-rw-r--r--arch/arm/boot/compressed/misc.c2
-rw-r--r--arch/arm/common/sa1111.c1
-rw-r--r--arch/arm/common/sharpsl_pm.c2
-rw-r--r--arch/arm/common/via82c505.c1
-rw-r--r--arch/arm/configs/ixp4xx_defconfig2
-rw-r--r--arch/arm/configs/picotux200_defconfig1386
-rw-r--r--arch/arm/kernel/Makefile4
-rw-r--r--arch/arm/kernel/ecard.c31
-rw-r--r--arch/arm/kernel/ecard.h56
-rw-r--r--arch/arm/kernel/head-nommu.S2
-rw-r--r--arch/arm/kernel/head.S8
-rw-r--r--arch/arm/kernel/init_task.c2
-rw-r--r--arch/arm/kernel/irq.c3
-rw-r--r--arch/arm/kernel/module.c4
-rw-r--r--arch/arm/kernel/process.c4
-rw-r--r--arch/arm/kernel/ptrace.c22
-rw-r--r--arch/arm/kernel/ptrace.h39
-rw-r--r--arch/arm/kernel/signal.c22
-rw-r--r--arch/arm/kernel/smp.c4
-rw-r--r--arch/arm/kernel/stacktrace.c73
-rw-r--r--arch/arm/kernel/stacktrace.h9
-rw-r--r--arch/arm/kernel/time.c4
-rw-r--r--arch/arm/kernel/traps.c38
-rw-r--r--arch/arm/kernel/vmlinux.lds.S17
-rw-r--r--arch/arm/lib/backtrace.S165
-rw-r--r--arch/arm/lib/getuser.S2
-rw-r--r--arch/arm/lib/putuser.S2
-rw-r--r--arch/arm/mach-aaec2000/core.c2
-rw-r--r--arch/arm/mach-at91/Kconfig9
-rw-r--r--arch/arm/mach-at91/Makefile1
-rw-r--r--arch/arm/mach-at91/at91rm9200.c19
-rw-r--r--arch/arm/mach-at91/at91rm9200_time.c2
-rw-r--r--arch/arm/mach-at91/at91sam9260.c7
-rw-r--r--arch/arm/mach-at91/at91sam9261.c19
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c10
-rw-r--r--arch/arm/mach-at91/at91sam9263.c48
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c124
-rw-r--r--arch/arm/mach-at91/at91sam926x_time.c2
-rw-r--r--arch/arm/mach-at91/board-picotux200.c166
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c10
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c52
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c70
-rw-r--r--arch/arm/mach-at91/pm.c1
-rw-r--r--arch/arm/mach-clps711x/time.c2
-rw-r--r--arch/arm/mach-clps7500/core.c2
-rw-r--r--arch/arm/mach-ebsa110/core.c2
-rw-r--r--arch/arm/mach-ebsa110/io.c40
-rw-r--r--arch/arm/mach-ep93xx/clock.c5
-rw-r--r--arch/arm/mach-ep93xx/core.c2
-rw-r--r--arch/arm/mach-footbridge/dc21285-timer.c2
-rw-r--r--arch/arm/mach-footbridge/dc21285.c1
-rw-r--r--arch/arm/mach-footbridge/isa-timer.c2
-rw-r--r--arch/arm/mach-h720x/cpu-h7201.c2
-rw-r--r--arch/arm/mach-h720x/cpu-h7202.c2
-rw-r--r--arch/arm/mach-imx/time.c2
-rw-r--r--arch/arm/mach-integrator/core.c2
-rw-r--r--arch/arm/mach-integrator/pci.c1
-rw-r--r--arch/arm/mach-integrator/pci_v3.c1
-rw-r--r--arch/arm/mach-iop13xx/Makefile1
-rw-r--r--arch/arm/mach-iop13xx/io.c10
-rw-r--r--arch/arm/mach-iop13xx/iq81340mc.c5
-rw-r--r--arch/arm/mach-iop13xx/iq81340sc.c5
-rw-r--r--arch/arm/mach-iop13xx/pci.c16
-rw-r--r--arch/arm/mach-iop13xx/setup.c6
-rw-r--r--arch/arm/mach-iop13xx/tpmi.c234
-rw-r--r--arch/arm/mach-iop32x/Kconfig8
-rw-r--r--arch/arm/mach-iop32x/iq31244.c11
-rw-r--r--arch/arm/mach-iop32x/iq80321.c3
-rw-r--r--arch/arm/mach-iop33x/Kconfig8
-rw-r--r--arch/arm/mach-iop33x/iq80331.c3
-rw-r--r--arch/arm/mach-iop33x/iq80332.c3
-rw-r--r--arch/arm/mach-ixp2000/core.c24
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c6
-rw-r--r--arch/arm/mach-ixp23xx/core.c2
-rw-r--r--arch/arm/mach-ixp4xx/Kconfig22
-rw-r--r--arch/arm/mach-ixp4xx/Makefile2
-rw-r--r--arch/arm/mach-ixp4xx/common-pci.c4
-rw-r--r--arch/arm/mach-ixp4xx/common.c124
-rw-r--r--arch/arm/mach-ixp4xx/dsmg600-pci.c74
-rw-r--r--arch/arm/mach-ixp4xx/dsmg600-power.c125
-rw-r--r--arch/arm/mach-ixp4xx/dsmg600-setup.c175
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-pci.c2
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-setup.c18
-rw-r--r--arch/arm/mach-lh7a40x/irq-lh7a400.c1
-rw-r--r--arch/arm/mach-lh7a40x/irq-lh7a404.c1
-rw-r--r--arch/arm/mach-lh7a40x/irq-lpd7a40x.c1
-rw-r--r--arch/arm/mach-lh7a40x/time.c2
-rw-r--r--arch/arm/mach-netx/time.c2
-rw-r--r--arch/arm/mach-ns9xxx/Kconfig15
-rw-r--r--arch/arm/mach-ns9xxx/Makefile1
-rw-r--r--arch/arm/mach-ns9xxx/board-jscc9p9360.c17
-rw-r--r--arch/arm/mach-ns9xxx/board-jscc9p9360.h13
-rw-r--r--arch/arm/mach-ns9xxx/mach-cc9p9360js.c29
-rw-r--r--arch/arm/mach-ns9xxx/time.c2
-rw-r--r--arch/arm/mach-omap1/Kconfig7
-rw-r--r--arch/arm/mach-omap1/Makefile1
-rw-r--r--arch/arm/mach-omap1/board-fsample.c2
-rw-r--r--arch/arm/mach-omap1/board-h3.c2
-rw-r--r--arch/arm/mach-omap1/board-innovator.c2
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c2
-rw-r--r--arch/arm/mach-omap1/devices.c71
-rw-r--r--arch/arm/mach-omap1/io.c4
-rw-r--r--arch/arm/mach-omap1/irq.c1
-rw-r--r--arch/arm/mach-omap1/mailbox.c206
-rw-r--r--arch/arm/mach-omap1/pm.c8
-rw-r--r--arch/arm/mach-omap1/time.c206
-rw-r--r--arch/arm/mach-omap2/Kconfig2
-rw-r--r--arch/arm/mach-omap2/board-h4.c14
-rw-r--r--arch/arm/mach-omap2/devices.c66
-rw-r--r--arch/arm/mach-omap2/gpmc.c12
-rw-r--r--arch/arm/mach-omap2/io.c21
-rw-r--r--arch/arm/mach-omap2/mailbox.c318
-rw-r--r--arch/arm/mach-omap2/pm.c2
-rw-r--r--arch/arm/mach-omap2/timer-gp.c2
-rw-r--r--arch/arm/mach-pnx4008/pm.c39
-rw-r--r--arch/arm/mach-pnx4008/time.c2
-rw-r--r--arch/arm/mach-pxa/generic.c4
-rw-r--r--arch/arm/mach-pxa/irq.c73
-rw-r--r--arch/arm/mach-pxa/lpd270.c4
-rw-r--r--arch/arm/mach-pxa/lubbock.c2
-rw-r--r--arch/arm/mach-pxa/mainstone.c4
-rw-r--r--arch/arm/mach-pxa/pm.c5
-rw-r--r--arch/arm/mach-pxa/pxa27x.c4
-rw-r--r--arch/arm/mach-pxa/ssp.c12
-rw-r--r--arch/arm/mach-pxa/time.c2
-rw-r--r--arch/arm/mach-realview/core.c2
-rw-r--r--arch/arm/mach-rpc/riscpc.c35
-rw-r--r--arch/arm/mach-s3c2410/bast-irq.c1
-rw-r--r--arch/arm/mach-s3c2410/irq.c1
-rw-r--r--arch/arm/mach-s3c2410/mach-amlm5900.c7
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c12
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c9
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c12
-rw-r--r--arch/arm/mach-s3c2410/mach-qt2410.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c14
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c16
-rw-r--r--arch/arm/mach-s3c2410/sleep.S2
-rw-r--r--arch/arm/mach-s3c2412/Kconfig9
-rw-r--r--arch/arm/mach-s3c2412/irq.c1
-rw-r--r--arch/arm/mach-s3c2412/mach-smdk2413.c7
-rw-r--r--arch/arm/mach-s3c2412/mach-vstms.c12
-rw-r--r--arch/arm/mach-s3c2440/irq.c1
-rw-r--r--arch/arm/mach-s3c2440/mach-anubis.c17
-rw-r--r--arch/arm/mach-s3c2440/mach-nexcoder.c13
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris.c16
-rw-r--r--arch/arm/mach-s3c2440/mach-rx3715.c8
-rw-r--r--arch/arm/mach-s3c2440/mach-smdk2440.c7
-rw-r--r--arch/arm/mach-s3c2443/irq.c1
-rw-r--r--arch/arm/mach-s3c2443/mach-smdk2443.c7
-rw-r--r--arch/arm/mach-sa1100/clock.c24
-rw-r--r--arch/arm/mach-sa1100/h3600.c2
-rw-r--r--arch/arm/mach-sa1100/irq.c1
-rw-r--r--arch/arm/mach-sa1100/neponset.c1
-rw-r--r--arch/arm/mach-sa1100/pm.c8
-rw-r--r--arch/arm/mach-sa1100/time.c2
-rw-r--r--arch/arm/mach-shark/core.c2
-rw-r--r--arch/arm/mach-shark/irq.c1
-rw-r--r--arch/arm/mach-versatile/core.c131
-rw-r--r--arch/arm/mach-versatile/pci.c1
-rw-r--r--arch/arm/mm/Kconfig32
-rw-r--r--arch/arm/mm/Makefile3
-rw-r--r--arch/arm/mm/abort-ev7.S32
-rw-r--r--arch/arm/mm/alignment.c1
-rw-r--r--arch/arm/mm/cache-v7.S253
-rw-r--r--arch/arm/mm/context.c17
-rw-r--r--arch/arm/mm/fault.c7
-rw-r--r--arch/arm/mm/init.c1
-rw-r--r--arch/arm/mm/ioremap.c80
-rw-r--r--arch/arm/mm/mm.h10
-rw-r--r--arch/arm/mm/mmap.c3
-rw-r--r--arch/arm/mm/mmu.c349
-rw-r--r--arch/arm/mm/nommu.c12
-rw-r--r--arch/arm/mm/proc-macros.S12
-rw-r--r--arch/arm/mm/proc-v7.S262
-rw-r--r--arch/arm/mm/proc-xscale.S28
-rw-r--r--arch/arm/oprofile/backtrace.c69
-rw-r--r--arch/arm/plat-iop/io.c4
-rw-r--r--arch/arm/plat-iop/pci.c140
-rw-r--r--arch/arm/plat-iop/time.c10
-rw-r--r--arch/arm/plat-omap/Kconfig14
-rw-r--r--arch/arm/plat-omap/Makefile5
-rw-r--r--arch/arm/plat-omap/clock.c37
-rw-r--r--arch/arm/plat-omap/common.c58
-rw-r--r--arch/arm/plat-omap/debug-leds.c314
-rw-r--r--arch/arm/plat-omap/devices.c80
-rw-r--r--arch/arm/plat-omap/dma.c25
-rw-r--r--arch/arm/plat-omap/dmtimer.c4
-rw-r--r--arch/arm/plat-omap/fb.c305
-rw-r--r--arch/arm/plat-omap/gpio.c616
-rw-r--r--arch/arm/plat-omap/mailbox.c509
-rw-r--r--arch/arm/plat-omap/mailbox.h100
-rw-r--r--arch/arm/plat-omap/mcbsp.c15
-rw-r--r--arch/arm/plat-omap/sram.c56
-rw-r--r--arch/arm/plat-omap/timer32k.c141
-rw-r--r--arch/arm/plat-omap/usb.c199
-rw-r--r--arch/arm/plat-s3c24xx/clock.c12
-rw-r--r--arch/arm/plat-s3c24xx/cpu.c38
-rw-r--r--arch/arm/plat-s3c24xx/dma.c13
-rw-r--r--arch/arm/plat-s3c24xx/irq.c1
-rw-r--r--arch/arm/plat-s3c24xx/pm.c28
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x-irq.c1
-rw-r--r--arch/arm/plat-s3c24xx/sleep.S2
-rw-r--r--arch/arm/plat-s3c24xx/time.c2
-rw-r--r--arch/arm/vfp/vfpdouble.c1
-rw-r--r--arch/arm/vfp/vfpsingle.c1
-rw-r--r--arch/arm26/Kconfig3
-rw-r--r--arch/arm26/boot/compressed/misc.c2
-rw-r--r--arch/arm26/kernel/armksyms.c1
-rw-r--r--arch/arm26/kernel/ptrace.c1
-rw-r--r--arch/arm26/kernel/signal.c1
-rw-r--r--arch/arm26/mm/memc.c8
-rw-r--r--arch/avr32/Makefile2
-rw-r--r--arch/avr32/kernel/kprobes.c2
-rw-r--r--arch/avr32/kernel/process.c6
-rw-r--r--arch/avr32/kernel/ptrace.c7
-rw-r--r--arch/avr32/kernel/syscall_table.S1
-rw-r--r--arch/avr32/kernel/traps.c16
-rw-r--r--arch/avr32/kernel/vmlinux.lds.c2
-rw-r--r--arch/avr32/mach-at32ap/clock.c2
-rw-r--r--arch/avr32/mm/dma-coherent.c12
-rw-r--r--arch/avr32/mm/fault.c2
-rw-r--r--arch/blackfin/Kconfig989
-rw-r--r--arch/blackfin/Makefile80
-rw-r--r--arch/blackfin/boot/Makefile27
-rw-r--r--arch/blackfin/defconfig1314
-rw-r--r--arch/blackfin/kernel/Makefile14
-rw-r--r--arch/blackfin/kernel/asm-offsets.c136
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c742
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c637
-rw-r--r--arch/blackfin/kernel/bfin_ksyms.c119
-rw-r--r--arch/blackfin/kernel/dma-mapping.c183
-rw-r--r--arch/blackfin/kernel/dualcore_test.c49
-rw-r--r--arch/blackfin/kernel/entry.S94
-rw-r--r--arch/blackfin/kernel/flat.c101
-rw-r--r--arch/blackfin/kernel/init_task.c60
-rw-r--r--arch/blackfin/kernel/irqchip.c147
-rw-r--r--arch/blackfin/kernel/module.c429
-rw-r--r--arch/blackfin/kernel/process.c394
-rw-r--r--arch/blackfin/kernel/ptrace.c430
-rw-r--r--arch/blackfin/kernel/setup.c902
-rw-r--r--arch/blackfin/kernel/signal.c356
-rw-r--r--arch/blackfin/kernel/sys_bfin.c115
-rw-r--r--arch/blackfin/kernel/time.c326
-rw-r--r--arch/blackfin/kernel/traps.c649
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S228
-rw-r--r--arch/blackfin/lib/Makefile11
-rw-r--r--arch/blackfin/lib/ashldi3.c58
-rw-r--r--arch/blackfin/lib/ashrdi3.c59
-rw-r--r--arch/blackfin/lib/checksum.c140
-rw-r--r--arch/blackfin/lib/divsi3.S216
-rw-r--r--arch/blackfin/lib/gcclib.h47
-rw-r--r--arch/blackfin/lib/ins.S69
-rw-r--r--arch/blackfin/lib/lshrdi3.c72
-rw-r--r--arch/blackfin/lib/memchr.S70
-rw-r--r--arch/blackfin/lib/memcmp.S110
-rw-r--r--arch/blackfin/lib/memcpy.S142
-rw-r--r--arch/blackfin/lib/memmove.S103
-rw-r--r--arch/blackfin/lib/memset.S109
-rw-r--r--arch/blackfin/lib/modsi3.S79
-rw-r--r--arch/blackfin/lib/muldi3.c99
-rw-r--r--arch/blackfin/lib/outs.S62
-rw-r--r--arch/blackfin/lib/smulsi3_highpart.S30
-rw-r--r--arch/blackfin/lib/strcmp.c11
-rw-r--r--arch/blackfin/lib/strcpy.c11
-rw-r--r--arch/blackfin/lib/strncmp.c11
-rw-r--r--arch/blackfin/lib/strncpy.c11
-rw-r--r--arch/blackfin/lib/udivsi3.S298
-rw-r--r--arch/blackfin/lib/umodsi3.S66
-rw-r--r--arch/blackfin/lib/umulsi3_highpart.S23
-rw-r--r--arch/blackfin/mach-bf533/Kconfig92
-rw-r--r--arch/blackfin/mach-bf533/Makefile9
-rw-r--r--arch/blackfin/mach-bf533/boards/Makefile8
-rw-r--r--arch/blackfin/mach-bf533/boards/cm_bf533.c267
-rw-r--r--arch/blackfin/mach-bf533/boards/ezkit.c224
-rw-r--r--arch/blackfin/mach-bf533/boards/generic_board.c95
-rw-r--r--arch/blackfin/mach-bf533/boards/stamp.c321
-rw-r--r--arch/blackfin/mach-bf533/cpu.c161
-rw-r--r--arch/blackfin/mach-bf533/head.S774
-rw-r--r--arch/blackfin/mach-bf533/ints-priority.c65
-rw-r--r--arch/blackfin/mach-bf537/Kconfig141
-rw-r--r--arch/blackfin/mach-bf537/Makefile9
-rw-r--r--arch/blackfin/mach-bf537/boards/Makefile9
-rw-r--r--arch/blackfin/mach-bf537/boards/cm_bf537.c364
-rw-r--r--arch/blackfin/mach-bf537/boards/eth_mac.c51
-rw-r--r--arch/blackfin/mach-bf537/boards/generic_board.c445
-rw-r--r--arch/blackfin/mach-bf537/boards/led.S183
-rw-r--r--arch/blackfin/mach-bf537/boards/pnav10.c523
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c615
-rw-r--r--arch/blackfin/mach-bf537/cpu.c161
-rw-r--r--arch/blackfin/mach-bf537/head.S602
-rw-r--r--arch/blackfin/mach-bf537/ints-priority.c74
-rw-r--r--arch/blackfin/mach-bf561/Kconfig222
-rw-r--r--arch/blackfin/mach-bf561/Makefile9
-rw-r--r--arch/blackfin/mach-bf561/boards/Makefile7
-rw-r--r--arch/blackfin/mach-bf561/boards/cm_bf561.c289
-rw-r--r--arch/blackfin/mach-bf561/boards/ezkit.c147
-rw-r--r--arch/blackfin/mach-bf561/boards/generic_board.c82
-rw-r--r--arch/blackfin/mach-bf561/coreb.c402
-rw-r--r--arch/blackfin/mach-bf561/head.S512
-rw-r--r--arch/blackfin/mach-bf561/ints-priority.c108
-rw-r--r--arch/blackfin/mach-common/Makefile12
-rw-r--r--arch/blackfin/mach-common/cache.S253
-rw-r--r--arch/blackfin/mach-common/cacheinit.S137
-rw-r--r--arch/blackfin/mach-common/cplbhdlr.S130
-rw-r--r--arch/blackfin/mach-common/cplbinfo.c211
-rw-r--r--arch/blackfin/mach-common/cplbmgr.S607
-rw-r--r--arch/blackfin/mach-common/dpmc.S418
-rw-r--r--arch/blackfin/mach-common/entry.S1207
-rw-r--r--arch/blackfin/mach-common/interrupt.S253
-rw-r--r--arch/blackfin/mach-common/ints-priority-dc.c476
-rw-r--r--arch/blackfin/mach-common/ints-priority-sc.c577
-rw-r--r--arch/blackfin/mach-common/irqpanic.c194
-rw-r--r--arch/blackfin/mach-common/lock.S204
-rw-r--r--arch/blackfin/mach-common/pm.c181
-rw-r--r--arch/blackfin/mm/Makefile5
-rw-r--r--arch/blackfin/mm/blackfin_sram.c540
-rw-r--r--arch/blackfin/mm/blackfin_sram.h38
-rw-r--r--arch/blackfin/mm/init.c208
-rw-r--r--arch/blackfin/oprofile/Kconfig29
-rw-r--r--arch/blackfin/oprofile/Makefile14
-rw-r--r--arch/blackfin/oprofile/common.c168
-rw-r--r--arch/blackfin/oprofile/op_blackfin.h98
-rw-r--r--arch/blackfin/oprofile/op_model_bf533.c161
-rw-r--r--arch/blackfin/oprofile/timer_int.c74
-rw-r--r--arch/cris/arch-v10/kernel/ptrace.c1
-rw-r--r--arch/cris/arch-v10/kernel/signal.c1
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig2
-rw-r--r--arch/cris/arch-v32/drivers/pci/dma.c2
-rw-r--r--arch/cris/arch-v32/kernel/fasttimer.c30
-rw-r--r--arch/cris/arch-v32/kernel/ptrace.c1
-rw-r--r--arch/cris/arch-v32/vmlinux.lds.S1
-rw-r--r--arch/cris/kernel/crisksyms.c1
-rw-r--r--arch/cris/kernel/profile.c81
-rw-r--r--arch/cris/kernel/ptrace.c1
-rw-r--r--arch/frv/Kconfig4
-rw-r--r--arch/frv/kernel/entry.S10
-rw-r--r--arch/frv/kernel/irq.c1
-rw-r--r--arch/frv/kernel/process.c4
-rw-r--r--arch/frv/kernel/ptrace.c1
-rw-r--r--arch/frv/kernel/semaphore.c2
-rw-r--r--arch/frv/kernel/setup.c4
-rw-r--r--arch/frv/kernel/signal.c1
-rw-r--r--arch/frv/kernel/sys_frv.c1
-rw-r--r--arch/frv/kernel/vmlinux.lds.S1
-rw-r--r--arch/frv/mm/elf-fdpic.c5
-rw-r--r--arch/frv/mm/pgalloc.c24
-rw-r--r--arch/h8300/Kconfig8
-rw-r--r--arch/h8300/Kconfig.debug4
-rw-r--r--arch/h8300/Makefile2
-rw-r--r--arch/h8300/boot/Makefile12
-rw-r--r--arch/h8300/boot/compressed/Makefile37
-rw-r--r--arch/h8300/boot/compressed/head.S47
-rw-r--r--arch/h8300/boot/compressed/misc.c219
-rw-r--r--arch/h8300/kernel/Makefile6
-rw-r--r--arch/h8300/kernel/asm-offsets.c2
-rw-r--r--arch/h8300/kernel/irq.c211
-rw-r--r--arch/h8300/kernel/ptrace.c1
-rw-r--r--arch/h8300/kernel/setup.c3
-rw-r--r--arch/h8300/kernel/sys_h8300.c1
-rw-r--r--arch/h8300/kernel/time.c54
-rw-r--r--arch/h8300/mm/kmap.c4
-rw-r--r--arch/h8300/platform/h8300h/Makefile2
-rw-r--r--arch/h8300/platform/h8300h/entry.S4
-rw-r--r--arch/h8300/platform/h8300h/generic/Makefile2
-rw-r--r--arch/h8300/platform/h8300h/ints_h8300h.c85
-rw-r--r--arch/h8300/platform/h8s/entry.S17
-rw-r--r--arch/i386/Kconfig47
-rw-r--r--arch/i386/Kconfig.cpu39
-rw-r--r--arch/i386/Kconfig.debug10
-rw-r--r--arch/i386/Makefile2
-rw-r--r--arch/i386/Makefile.cpu9
-rw-r--r--arch/i386/boot/Makefile4
-rw-r--r--arch/i386/boot/compressed/misc.c2
-rw-r--r--arch/i386/boot/setup.S24
-rw-r--r--arch/i386/defconfig74
-rw-r--r--arch/i386/kernel/Makefile5
-rw-r--r--arch/i386/kernel/acpi/boot.c2
-rw-r--r--arch/i386/kernel/acpi/earlyquirk.c26
-rw-r--r--arch/i386/kernel/alternative.c102
-rw-r--r--arch/i386/kernel/apic.c23
-rw-r--r--arch/i386/kernel/apm.c13
-rw-r--r--arch/i386/kernel/asm-offsets.c18
-rw-r--r--arch/i386/kernel/cpu/Makefile4
-rw-r--r--arch/i386/kernel/cpu/amd.c15
-rw-r--r--arch/i386/kernel/cpu/bugs.c191
-rw-r--r--arch/i386/kernel/cpu/centaur.c10
-rw-r--r--arch/i386/kernel/cpu/common.c217
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c21
-rw-r--r--arch/i386/kernel/cpu/cpufreq/p4-clockmod.c31
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.c6
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.h2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c10
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-lib.c1
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-smi.c2
-rw-r--r--arch/i386/kernel/cpu/cyrix.c21
-rw-r--r--arch/i386/kernel/cpu/intel.c4
-rw-r--r--arch/i386/kernel/cpu/intel_cacheinfo.c2
-rw-r--r--arch/i386/kernel/cpu/mcheck/k7.c13
-rw-r--r--arch/i386/kernel/cpu/mcheck/mce.c3
-rw-r--r--arch/i386/kernel/cpu/mcheck/p4.c16
-rw-r--r--arch/i386/kernel/cpu/mcheck/therm_throt.c4
-rw-r--r--arch/i386/kernel/cpu/mtrr/generic.c101
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c11
-rw-r--r--arch/i386/kernel/cpu/nexgen.c10
-rw-r--r--arch/i386/kernel/cpu/perfctr-watchdog.c658
-rw-r--r--arch/i386/kernel/cpu/proc.c3
-rw-r--r--arch/i386/kernel/cpu/rise.c9
-rw-r--r--arch/i386/kernel/cpu/transmeta.c16
-rw-r--r--arch/i386/kernel/cpu/umc.c10
-rw-r--r--arch/i386/kernel/cpuid.c2
-rw-r--r--arch/i386/kernel/crash.c2
-rw-r--r--arch/i386/kernel/doublefault.c29
-rw-r--r--arch/i386/kernel/e820.c64
-rw-r--r--arch/i386/kernel/efi.c28
-rw-r--r--arch/i386/kernel/entry.S23
-rw-r--r--arch/i386/kernel/head.S118
-rw-r--r--arch/i386/kernel/i386_ksyms.c2
-rw-r--r--arch/i386/kernel/i8253.c2
-rw-r--r--arch/i386/kernel/i8259.c1
-rw-r--r--arch/i386/kernel/io_apic.c43
-rw-r--r--arch/i386/kernel/ioport.c4
-rw-r--r--arch/i386/kernel/irq.c3
-rw-r--r--arch/i386/kernel/kprobes.c27
-rw-r--r--arch/i386/kernel/ldt.c1
-rw-r--r--arch/i386/kernel/legacy_serial.c67
-rw-r--r--arch/i386/kernel/microcode.c59
-rw-r--r--arch/i386/kernel/mpparse.c3
-rw-r--r--arch/i386/kernel/msr.c108
-rw-r--r--arch/i386/kernel/nmi.c834
-rw-r--r--arch/i386/kernel/paravirt.c522
-rw-r--r--arch/i386/kernel/pci-dma.c2
-rw-r--r--arch/i386/kernel/process.c38
-rw-r--r--arch/i386/kernel/ptrace.c1
-rw-r--r--arch/i386/kernel/quirks.c69
-rw-r--r--arch/i386/kernel/reboot.c55
-rw-r--r--arch/i386/kernel/reboot_fixups.c2
-rw-r--r--arch/i386/kernel/signal.c1
-rw-r--r--arch/i386/kernel/smp.c305
-rw-r--r--arch/i386/kernel/smpboot.c147
-rw-r--r--arch/i386/kernel/sys_i386.c1
-rw-r--r--arch/i386/kernel/syscall_table.S1
-rw-r--r--arch/i386/kernel/sysenter.c269
-rw-r--r--arch/i386/kernel/time.c2
-rw-r--r--arch/i386/kernel/trampoline.S12
-rw-r--r--arch/i386/kernel/traps.c55
-rw-r--r--arch/i386/kernel/tsc.c13
-rw-r--r--arch/i386/kernel/verify_cpu.S65
-rw-r--r--arch/i386/kernel/vm86.c1
-rw-r--r--arch/i386/kernel/vmi.c131
-rw-r--r--arch/i386/kernel/vmiclock.c318
-rw-r--r--arch/i386/kernel/vmitime.c482
-rw-r--r--arch/i386/kernel/vmlinux.lds.S24
-rw-r--r--arch/i386/kernel/vsyscall.lds.S4
-rw-r--r--arch/i386/lib/bitops.c4
-rw-r--r--arch/i386/lib/checksum.S69
-rw-r--r--arch/i386/lib/getuser.S26
-rw-r--r--arch/i386/lib/msr-on-cpu.c73
-rw-r--r--arch/i386/lib/putuser.S39
-rw-r--r--arch/i386/lib/usercopy.c7
-rw-r--r--arch/i386/mach-default/setup.c2
-rw-r--r--arch/i386/mach-generic/bigsmp.c2
-rw-r--r--arch/i386/mach-generic/es7000.c41
-rw-r--r--arch/i386/mach-generic/probe.c2
-rw-r--r--arch/i386/mach-visws/setup.c2
-rw-r--r--arch/i386/mach-visws/visws_apic.c1
-rw-r--r--arch/i386/mach-voyager/setup.c8
-rw-r--r--arch/i386/mach-voyager/voyager_basic.c4
-rw-r--r--arch/i386/mach-voyager/voyager_cat.c4
-rw-r--r--arch/i386/mach-voyager/voyager_smp.c114
-rw-r--r--arch/i386/mach-voyager/voyager_thread.c70
-rw-r--r--arch/i386/mm/fault.c64
-rw-r--r--arch/i386/mm/highmem.c10
-rw-r--r--arch/i386/mm/hugetlbpage.c7
-rw-r--r--arch/i386/mm/init.c188
-rw-r--r--arch/i386/mm/pageattr.c6
-rw-r--r--arch/i386/mm/pgtable.c94
-rw-r--r--arch/i386/oprofile/nmi_int.c6
-rw-r--r--arch/i386/oprofile/nmi_timer_int.c3
-rw-r--r--arch/i386/pci/fixup.c2
-rw-r--r--arch/i386/pci/i386.c4
-rw-r--r--arch/i386/pci/init.c2
-rw-r--r--arch/i386/pci/mmconfig-shared.c25
-rw-r--r--arch/i386/power/cpu.c1
-rw-r--r--arch/i386/power/suspend.c14
-rw-r--r--arch/ia64/Kconfig13
-rw-r--r--arch/ia64/defconfig1
-rw-r--r--arch/ia64/hp/sim/boot/fw-emu.c2
-rw-r--r--arch/ia64/ia32/ia32_ldt.c1
-rw-r--r--arch/ia64/ia32/ia32_signal.c1
-rw-r--r--arch/ia64/ia32/ia32_support.c6
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/crash.c4
-rw-r--r--arch/ia64/kernel/efi.c56
-rw-r--r--arch/ia64/kernel/entry.S7
-rw-r--r--arch/ia64/kernel/err_inject.c295
-rw-r--r--arch/ia64/kernel/iosapic.c1
-rw-r--r--arch/ia64/kernel/irq_ia64.c1
-rw-r--r--arch/ia64/kernel/ivt.S19
-rw-r--r--arch/ia64/kernel/kprobes.c32
-rw-r--r--arch/ia64/kernel/mca.c5
-rw-r--r--arch/ia64/kernel/mca_asm.S24
-rw-r--r--arch/ia64/kernel/mca_drv.c1
-rw-r--r--arch/ia64/kernel/palinfo.c2
-rw-r--r--arch/ia64/kernel/patch.c20
-rw-r--r--arch/ia64/kernel/perfmon.c1
-rw-r--r--arch/ia64/kernel/process.c3
-rw-r--r--arch/ia64/kernel/salinfo.c3
-rw-r--r--arch/ia64/kernel/setup.c7
-rw-r--r--arch/ia64/kernel/signal.c1
-rw-r--r--arch/ia64/kernel/smpboot.c1
-rw-r--r--arch/ia64/kernel/sys_ia64.c8
-rw-r--r--arch/ia64/kernel/time.c2
-rw-r--r--arch/ia64/kernel/topology.c2
-rw-r--r--arch/ia64/kernel/traps.c18
-rw-r--r--arch/ia64/kernel/unaligned.c1
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S7
-rw-r--r--arch/ia64/lib/csum_partial_copy.c2
-rw-r--r--arch/ia64/mm/discontig.c2
-rw-r--r--arch/ia64/mm/fault.c3
-rw-r--r--arch/ia64/mm/hugetlbpage.c9
-rw-r--r--arch/ia64/mm/init.c13
-rw-r--r--arch/ia64/mm/ioremap.c78
-rw-r--r--arch/ia64/pci/pci.c3
-rw-r--r--arch/ia64/sn/kernel/huberror.c1
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c4
-rw-r--r--arch/ia64/sn/kernel/xpc_main.c4
-rw-r--r--arch/ia64/sn/kernel/xpnet.c1
-rw-r--r--arch/m32r/kernel/m32r_ksyms.c1
-rw-r--r--arch/m32r/kernel/signal.c1
-rw-r--r--arch/m32r/kernel/smpboot.c1
-rw-r--r--arch/m32r/kernel/sys_m32r.c1
-rw-r--r--arch/m32r/kernel/vmlinux.lds.S2
-rw-r--r--arch/m32r/mm/fault-nommu.c1
-rw-r--r--arch/m32r/mm/fault.c1
-rw-r--r--arch/m68k/Kconfig3
-rw-r--r--arch/m68k/Makefile2
-rw-r--r--arch/m68k/amiga/amiints.c2
-rw-r--r--arch/m68k/amiga/cia.c4
-rw-r--r--arch/m68k/amiga/config.c1091
-rw-r--r--arch/m68k/apollo/dn_ints.c2
-rw-r--r--arch/m68k/atari/Makefile1
-rw-r--r--arch/m68k/atari/ataints.c2
-rw-r--r--arch/m68k/atari/atakeyb.c730
-rw-r--r--arch/m68k/atari/atasound.h33
-rw-r--r--arch/m68k/atari/config.c998
-rw-r--r--arch/m68k/atari/debug.c482
-rw-r--r--arch/m68k/kernel/entry.S2
-rw-r--r--arch/m68k/kernel/head.S2
-rw-r--r--arch/m68k/kernel/ints.c4
-rw-r--r--arch/m68k/kernel/ptrace.c1
-rw-r--r--arch/m68k/kernel/setup.c368
-rw-r--r--arch/m68k/lib/checksum.c3
-rw-r--r--arch/m68k/mac/baboon.c32
-rw-r--r--arch/m68k/mac/config.c167
-rw-r--r--arch/m68k/mac/debug.c331
-rw-r--r--arch/m68k/mac/macints.c2
-rw-r--r--arch/m68k/mac/oss.c18
-rw-r--r--arch/m68k/mac/psc.c21
-rw-r--r--arch/m68k/mac/via.c284
-rw-r--r--arch/m68k/mvme16x/rtc.c1
-rw-r--r--arch/m68k/q40/config.c272
-rw-r--r--arch/m68k/q40/q40ints.c2
-rw-r--r--arch/m68k/sun3/sun3ints.c4
-rw-r--r--arch/m68k/sun3x/prom.c132
-rw-r--r--arch/m68knommu/Kconfig.debug2
-rw-r--r--arch/m68knommu/kernel/asm-offsets.c2
-rw-r--r--arch/m68knommu/kernel/dma.c1
-rw-r--r--arch/m68knommu/kernel/ptrace.c1
-rw-r--r--arch/m68knommu/kernel/sys_m68k.c1
-rw-r--r--arch/mips/Kconfig11
-rw-r--r--arch/mips/Makefile2
-rw-r--r--arch/mips/cobalt/Makefile2
-rw-r--r--arch/mips/cobalt/buttons.c54
-rw-r--r--arch/mips/configs/rbhma4500_defconfig31
-rw-r--r--arch/mips/kernel/asm-offsets.c2
-rw-r--r--arch/mips/kernel/early_printk.c5
-rw-r--r--arch/mips/kernel/irixelf.c1
-rw-r--r--arch/mips/kernel/irixioctl.c1
-rw-r--r--arch/mips/kernel/irixsig.c1
-rw-r--r--arch/mips/kernel/ptrace.c1
-rw-r--r--arch/mips/kernel/signal.c1
-rw-r--r--arch/mips/kernel/signal32.c1
-rw-r--r--arch/mips/kernel/signal_n32.c1
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/stacktrace.c22
-rw-r--r--arch/mips/kernel/syscall.c1
-rw-r--r--arch/mips/kernel/traps.c1
-rw-r--r--arch/mips/kernel/unaligned.c1
-rw-r--r--arch/mips/kernel/vmlinux.lds.S2
-rw-r--r--arch/mips/lib/iomap.c1
-rw-r--r--arch/mips/math-emu/dsemul.c1
-rw-r--r--arch/mips/mips-boards/sim/Makefile3
-rw-r--r--arch/mips/mips-boards/sim/sim_platform.c35
-rw-r--r--arch/mips/mm/fault.c1
-rw-r--r--arch/mips/pci/fixup-sb1250.c4
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_serial.c165
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c1
-rw-r--r--arch/mips/sni/irq.c2
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c19
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/setup.c20
-rw-r--r--arch/parisc/configs/c3000_defconfig1
-rw-r--r--arch/parisc/hpux/fs.c1
-rw-r--r--arch/parisc/hpux/ioctl.c1
-rw-r--r--arch/parisc/kernel/asm-offsets.c2
-rw-r--r--arch/parisc/kernel/irq.c2
-rw-r--r--arch/parisc/kernel/ptrace.c1
-rw-r--r--arch/parisc/kernel/signal.c1
-rw-r--r--arch/parisc/kernel/signal32.c1
-rw-r--r--arch/parisc/kernel/sys_parisc.c6
-rw-r--r--arch/parisc/kernel/traps.c1
-rw-r--r--arch/parisc/kernel/unwind.c5
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S2
-rw-r--r--arch/powerpc/Kconfig500
-rw-r--r--arch/powerpc/Kconfig.debug34
-rw-r--r--arch/powerpc/Makefile9
-rw-r--r--arch/powerpc/boot/.gitignore3
-rw-r--r--arch/powerpc/boot/44x.c40
-rw-r--r--arch/powerpc/boot/44x.h16
-rw-r--r--arch/powerpc/boot/Makefile143
-rw-r--r--arch/powerpc/boot/crt0.S37
-rw-r--r--arch/powerpc/boot/cuboot-83xx.c68
-rw-r--r--arch/powerpc/boot/cuboot-85xx.c69
-rw-r--r--arch/powerpc/boot/cuboot-ebony.c42
-rw-r--r--arch/powerpc/boot/dcr.h87
-rw-r--r--arch/powerpc/boot/devtree.c307
-rw-r--r--arch/powerpc/boot/dts/ebony.dts307
-rw-r--r--arch/powerpc/boot/dts/holly.dts198
-rw-r--r--arch/powerpc/boot/dts/kuroboxHD.dts7
-rw-r--r--arch/powerpc/boot/dts/kuroboxHG.dts7
-rw-r--r--arch/powerpc/boot/dts/lite5200.dts12
-rw-r--r--arch/powerpc/boot/dts/lite5200b.dts12
-rw-r--r--arch/powerpc/boot/dts/mpc7448hpc2.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8272ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8313erdb.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc832x_mds.dts3
-rw-r--r--arch/powerpc/boot/dts/mpc832x_rdb.dts289
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitx.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitxgp.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc834x_mds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc836x_mds.dts5
-rw-r--r--arch/powerpc/boot/dts/mpc8540ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8541cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8544ds.dts136
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8555cds.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8568mds.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc8641_hpcn.dts25
-rw-r--r--arch/powerpc/boot/dts/mpc866ads.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc885ads.dts1
-rw-r--r--arch/powerpc/boot/ebony.c129
-rw-r--r--arch/powerpc/boot/elf.h8
-rw-r--r--arch/powerpc/boot/elf_util.c76
-rw-r--r--arch/powerpc/boot/flatdevtree.c199
-rw-r--r--arch/powerpc/boot/flatdevtree.h7
-rw-r--r--arch/powerpc/boot/flatdevtree_misc.c42
-rw-r--r--arch/powerpc/boot/gunzip_util.c206
-rw-r--r--arch/powerpc/boot/gunzip_util.h45
-rw-r--r--arch/powerpc/boot/holly.c38
-rw-r--r--arch/powerpc/boot/main.c369
-rw-r--r--arch/powerpc/boot/mktree.c10
-rw-r--r--arch/powerpc/boot/ns16550.c9
-rw-r--r--arch/powerpc/boot/of.c21
-rw-r--r--arch/powerpc/boot/ops.h103
-rw-r--r--arch/powerpc/boot/ppcboot.h108
-rw-r--r--arch/powerpc/boot/reg.h22
-rw-r--r--arch/powerpc/boot/simple_alloc.c31
-rw-r--r--arch/powerpc/boot/stdio.h5
-rw-r--r--arch/powerpc/boot/treeboot-ebony.c34
-rwxr-xr-xarch/powerpc/boot/wrapper65
-rw-r--r--arch/powerpc/boot/zImage.coff.lds.S3
-rw-r--r--arch/powerpc/boot/zImage.lds.S1
-rw-r--r--arch/powerpc/configs/cell_defconfig57
-rw-r--r--arch/powerpc/configs/ebony_defconfig905
-rw-r--r--arch/powerpc/configs/g5_defconfig2
-rw-r--r--arch/powerpc/configs/holly_defconfig1070
-rw-r--r--arch/powerpc/configs/maple_defconfig2
-rw-r--r--arch/powerpc/configs/mpc832x_mds_defconfig67
-rw-r--r--arch/powerpc/configs/mpc832x_rdb_defconfig1300
-rw-r--r--arch/powerpc/configs/mpc836x_mds_defconfig42
-rw-r--r--arch/powerpc/configs/mpc8544_ds_defconfig1077
-rw-r--r--arch/powerpc/configs/ppc64_defconfig2
-rw-r--r--arch/powerpc/configs/ps3_defconfig329
-rw-r--r--arch/powerpc/kernel/Makefile7
-rw-r--r--arch/powerpc/kernel/align.c56
-rw-r--r--arch/powerpc/kernel/asm-offsets.c24
-rw-r--r--arch/powerpc/kernel/btext.c22
-rw-r--r--arch/powerpc/kernel/cpu_setup_pa6t.S2
-rw-r--r--arch/powerpc/kernel/cputable.c14
-rw-r--r--arch/powerpc/kernel/entry_32.S1
-rw-r--r--arch/powerpc/kernel/head_44x.S48
-rw-r--r--arch/powerpc/kernel/head_64.S16
-rw-r--r--arch/powerpc/kernel/ibmebus.c288
-rw-r--r--arch/powerpc/kernel/idle.c5
-rw-r--r--arch/powerpc/kernel/idle_power4.S21
-rw-r--r--arch/powerpc/kernel/iommu.c35
-rw-r--r--arch/powerpc/kernel/irq.c40
-rw-r--r--arch/powerpc/kernel/kprobes.c77
-rw-r--r--arch/powerpc/kernel/legacy_serial.c41
-rw-r--r--arch/powerpc/kernel/lparcfg.c58
-rw-r--r--arch/powerpc/kernel/lparmap.c3
-rw-r--r--arch/powerpc/kernel/machine_kexec_64.c14
-rw-r--r--arch/powerpc/kernel/misc_32.S4
-rw-r--r--arch/powerpc/kernel/msi.c38
-rw-r--r--arch/powerpc/kernel/of_device.c115
-rw-r--r--arch/powerpc/kernel/of_platform.c6
-rw-r--r--arch/powerpc/kernel/pci_32.c44
-rw-r--r--arch/powerpc/kernel/pci_64.c43
-rw-r--r--arch/powerpc/kernel/pci_dn.c9
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c2
-rw-r--r--arch/powerpc/kernel/process.c55
-rw-r--r--arch/powerpc/kernel/prom.c167
-rw-r--r--arch/powerpc/kernel/prom_init.c67
-rw-r--r--arch/powerpc/kernel/prom_parse.c76
-rw-r--r--arch/powerpc/kernel/ptrace.c1
-rw-r--r--arch/powerpc/kernel/rtas-proc.c4
-rw-r--r--arch/powerpc/kernel/rtas.c19
-rw-r--r--arch/powerpc/kernel/rtas_pci.c14
-rw-r--r--arch/powerpc/kernel/setup-common.c68
-rw-r--r--arch/powerpc/kernel/setup_32.c17
-rw-r--r--arch/powerpc/kernel/setup_64.c15
-rw-r--r--arch/powerpc/kernel/signal_32.c1
-rw-r--r--arch/powerpc/kernel/signal_64.c1
-rw-r--r--arch/powerpc/kernel/smp.c77
-rw-r--r--arch/powerpc/kernel/suspend.c24
-rw-r--r--arch/powerpc/kernel/swsusp.c43
-rw-r--r--arch/powerpc/kernel/swsusp_64.c24
-rw-r--r--arch/powerpc/kernel/swsusp_asm64.S228
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c4
-rw-r--r--arch/powerpc/kernel/syscalls.c1
-rw-r--r--arch/powerpc/kernel/sysfs.c21
-rw-r--r--arch/powerpc/kernel/time.c2
-rw-r--r--arch/powerpc/kernel/traps.c92
-rw-r--r--arch/powerpc/kernel/udbg.c22
-rw-r--r--arch/powerpc/kernel/udbg_16550.c23
-rw-r--r--arch/powerpc/kernel/vdso.c1
-rw-r--r--arch/powerpc/kernel/vio.c23
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S6
-rw-r--r--arch/powerpc/lib/copyuser_64.S6
-rw-r--r--arch/powerpc/lib/dma-noncoherent.c4
-rw-r--r--arch/powerpc/lib/locks.c4
-rw-r--r--arch/powerpc/lib/mem_64.S6
-rw-r--r--arch/powerpc/lib/memcpy_64.S6
-rw-r--r--arch/powerpc/lib/sstep.c45
-rw-r--r--arch/powerpc/mm/44x_mmu.c82
-rw-r--r--arch/powerpc/mm/Makefile1
-rw-r--r--arch/powerpc/mm/fault.c44
-rw-r--r--arch/powerpc/mm/hash_low_32.S22
-rw-r--r--arch/powerpc/mm/hash_low_64.S10
-rw-r--r--arch/powerpc/mm/hash_native_64.c86
-rw-r--r--arch/powerpc/mm/hash_utils_64.c249
-rw-r--r--arch/powerpc/mm/hugetlbpage.c547
-rw-r--r--arch/powerpc/mm/init_32.c4
-rw-r--r--arch/powerpc/mm/init_64.c23
-rw-r--r--arch/powerpc/mm/lmb.c4
-rw-r--r--arch/powerpc/mm/mem.c29
-rw-r--r--arch/powerpc/mm/mmu_context_64.c10
-rw-r--r--arch/powerpc/mm/mmu_decl.h8
-rw-r--r--arch/powerpc/mm/numa.c27
-rw-r--r--arch/powerpc/mm/pgtable_32.c104
-rw-r--r--arch/powerpc/mm/ppc_mmu_32.c6
-rw-r--r--arch/powerpc/mm/slb.c11
-rw-r--r--arch/powerpc/mm/slb_low.S52
-rw-r--r--arch/powerpc/mm/slice.c633
-rw-r--r--arch/powerpc/mm/stab.c2
-rw-r--r--arch/powerpc/mm/tlb_32.c4
-rw-r--r--arch/powerpc/mm/tlb_64.c80
-rw-r--r--arch/powerpc/oprofile/Makefile2
-rw-r--r--arch/powerpc/oprofile/common.c3
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c5
-rw-r--r--arch/powerpc/oprofile/op_model_pa6t.c234
-rw-r--r--arch/powerpc/platforms/44x/44x.h8
-rw-r--r--arch/powerpc/platforms/44x/Kconfig56
-rw-r--r--arch/powerpc/platforms/44x/Makefile2
-rw-r--r--arch/powerpc/platforms/44x/ebony.c73
-rw-r--r--arch/powerpc/platforms/44x/misc_44x.S57
-rw-r--r--arch/powerpc/platforms/4xx/Kconfig372
-rw-r--r--arch/powerpc/platforms/52xx/Kconfig36
-rw-r--r--arch/powerpc/platforms/52xx/Makefile2
-rw-r--r--arch/powerpc/platforms/52xx/efika.c30
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c40
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pm.c191
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_sleep.S154
-rw-r--r--arch/powerpc/platforms/82xx/Kconfig45
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx.c6
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c12
-rw-r--r--arch/powerpc/platforms/83xx/Kconfig15
-rw-r--r--arch/powerpc/platforms/83xx/Makefile1
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.h19
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c139
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.h23
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_mds.c1
-rw-r--r--arch/powerpc/platforms/83xx/pci.c2
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig38
-rw-r--r--arch/powerpc/platforms/85xx/Makefile1
-rw-r--r--arch/powerpc/platforms/85xx/mpc8544_ds.c144
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c4
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c3
-rw-r--r--arch/powerpc/platforms/85xx/pci.c2
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig18
-rw-r--r--arch/powerpc/platforms/86xx/Makefile2
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c6
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c2
-rw-r--r--arch/powerpc/platforms/86xx/pci.c4
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig67
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c8
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads.h2
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads_setup.c6
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads.h2
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads_setup.c6
-rw-r--r--arch/powerpc/platforms/Kconfig260
-rw-r--r--arch/powerpc/platforms/Makefile3
-rw-r--r--arch/powerpc/platforms/cell/Kconfig39
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c112
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c168
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.h5
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c181
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c10
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c4
-rw-r--r--arch/powerpc/platforms/cell/iommu.c16
-rw-r--r--arch/powerpc/platforms/cell/ras.c160
-rw-r--r--arch/powerpc/platforms/cell/setup.c14
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c12
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c172
-rw-r--r--arch/powerpc/platforms/cell/spu_coredump.c34
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c18
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile2
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c7
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c49
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c19
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c211
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c228
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c10
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c47
-rw-r--r--arch/powerpc/platforms/cell/spufs/lscsa_alloc.c181
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c123
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c114
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h34
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c37
-rw-r--r--arch/powerpc/platforms/celleb/Kconfig9
-rw-r--r--arch/powerpc/platforms/celleb/iommu.c6
-rw-r--r--arch/powerpc/platforms/celleb/pci.c18
-rw-r--r--arch/powerpc/platforms/celleb/setup.c12
-rw-r--r--arch/powerpc/platforms/chrp/Kconfig11
-rw-r--r--arch/powerpc/platforms/chrp/nvram.c2
-rw-r--r--arch/powerpc/platforms/chrp/pci.c27
-rw-r--r--arch/powerpc/platforms/chrp/setup.c54
-rw-r--r--arch/powerpc/platforms/chrp/smp.c1
-rw-r--r--arch/powerpc/platforms/chrp/time.c13
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig274
-rw-r--r--arch/powerpc/platforms/embedded6xx/Makefile1
-rw-r--r--arch/powerpc/platforms/embedded6xx/holly.c317
-rw-r--r--arch/powerpc/platforms/embedded6xx/linkstation.c8
-rw-r--r--arch/powerpc/platforms/embedded6xx/ls_uart.c4
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c34
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig8
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c4
-rw-r--r--arch/powerpc/platforms/iseries/irq.c4
-rw-r--r--arch/powerpc/platforms/iseries/pci.c5
-rw-r--r--arch/powerpc/platforms/iseries/setup.c10
-rw-r--r--arch/powerpc/platforms/iseries/smp.c1
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c3
-rw-r--r--arch/powerpc/platforms/maple/Kconfig17
-rw-r--r--arch/powerpc/platforms/maple/pci.c20
-rw-r--r--arch/powerpc/platforms/maple/setup.c19
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig19
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile3
-rw-r--r--arch/powerpc/platforms/pasemi/cpufreq.c312
-rw-r--r--arch/powerpc/platforms/pasemi/gpio_mdio.c339
-rw-r--r--arch/powerpc/platforms/pasemi/idle.c9
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c6
-rw-r--r--arch/powerpc/platforms/pasemi/pasemi.h8
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c29
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c34
-rw-r--r--arch/powerpc/platforms/powermac/Kconfig20
-rw-r--r--arch/powerpc/platforms/powermac/backlight.c9
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c25
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c24
-rw-r--r--arch/powerpc/platforms/powermac/feature.c127
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c17
-rw-r--r--arch/powerpc/platforms/powermac/nvram.c4
-rw-r--r--arch/powerpc/platforms/powermac/pci.c71
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c2
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_core.c5
-rw-r--r--arch/powerpc/platforms/powermac/pic.c10
-rw-r--r--arch/powerpc/platforms/powermac/setup.c182
-rw-r--r--arch/powerpc/platforms/powermac/smp.c30
-rw-r--r--arch/powerpc/platforms/powermac/time.c38
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c6
-rw-r--r--arch/powerpc/platforms/prep/Kconfig9
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig16
-rw-r--r--arch/powerpc/platforms/ps3/htab.c5
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c234
-rw-r--r--arch/powerpc/platforms/ps3/mm.c1
-rw-r--r--arch/powerpc/platforms/ps3/setup.c7
-rw-r--r--arch/powerpc/platforms/ps3/smp.c6
-rw-r--r--arch/powerpc/platforms/ps3/spu.c18
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig10
-rw-r--r--arch/powerpc/platforms/pseries/Makefile6
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c321
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c92
-rw-r--r--arch/powerpc/platforms/pseries/eeh_event.c8
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c4
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c73
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c10
-rw-r--r--arch/powerpc/platforms/pseries/msi.c270
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c2
-rw-r--r--arch/powerpc/platforms/pseries/pci.c3
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c2
-rw-r--r--arch/powerpc/platforms/pseries/power.c8
-rw-r--r--arch/powerpc/platforms/pseries/ras.c3
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c46
-rw-r--r--arch/powerpc/platforms/pseries/xics.c21
-rw-r--r--arch/powerpc/sysdev/Makefile10
-rw-r--r--arch/powerpc/sysdev/dart_iommu.c50
-rw-r--r--arch/powerpc/sysdev/dcr.c14
-rw-r--r--arch/powerpc/sysdev/fsl_pcie.c (renamed from arch/powerpc/platforms/86xx/mpc86xx_pcie.c)2
-rw-r--r--arch/powerpc/sysdev/fsl_pcie.h94
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c92
-rw-r--r--arch/powerpc/sysdev/mpic.c192
-rw-r--r--arch/powerpc/sysdev/mpic.h38
-rw-r--r--arch/powerpc/sysdev/mpic_msi.c183
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c186
-rw-r--r--arch/powerpc/sysdev/pmi.c29
-rw-r--r--arch/powerpc/sysdev/qe_lib/Kconfig10
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe.c4
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_io.c6
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_fast.c3
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_slow.c4
-rw-r--r--arch/powerpc/sysdev/rom.c32
-rw-r--r--arch/powerpc/sysdev/timer.c71
-rw-r--r--arch/powerpc/sysdev/tsi108_dev.c21
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c14
-rw-r--r--arch/powerpc/sysdev/uic.c342
-rw-r--r--arch/powerpc/xmon/xmon.c14
-rw-r--r--arch/ppc/8260_io/enet.c1
-rw-r--r--arch/ppc/8260_io/fcc_enet.c1
-rw-r--r--arch/ppc/8xx_io/Kconfig4
-rw-r--r--arch/ppc/8xx_io/Makefile1
-rw-r--r--arch/ppc/8xx_io/cs4218.h166
-rw-r--r--arch/ppc/8xx_io/cs4218_tdm.c2833
-rw-r--r--arch/ppc/8xx_io/enet.c1
-rw-r--r--arch/ppc/boot/common/misc-common.c15
-rw-r--r--arch/ppc/boot/simple/Makefile1
-rw-r--r--arch/ppc/boot/simple/uartlite_tty.c37
-rw-r--r--arch/ppc/kernel/asm-offsets.c3
-rw-r--r--arch/ppc/kernel/entry.S1
-rw-r--r--arch/ppc/kernel/ppc_htab.c1
-rw-r--r--arch/ppc/kernel/smp.c1
-rw-r--r--arch/ppc/kernel/vmlinux.lds.S2
-rw-r--r--arch/ppc/platforms/4xx/Kconfig15
-rw-r--r--arch/ppc/platforms/4xx/Makefile1
-rw-r--r--arch/ppc/platforms/4xx/ocotea.c4
-rw-r--r--arch/ppc/platforms/4xx/taishan.c2
-rw-r--r--arch/ppc/platforms/4xx/virtex.c56
-rw-r--r--arch/ppc/platforms/4xx/virtex.h34
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml300.c65
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml300.h45
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml403.c66
-rw-r--r--arch/ppc/platforms/4xx/xilinx_ml403.h49
-rw-r--r--arch/ppc/platforms/4xx/xparameters/xparameters.h60
-rw-r--r--arch/ppc/platforms/mpc866ads_setup.c2
-rw-r--r--arch/ppc/platforms/rpxclassic.h4
-rw-r--r--arch/ppc/platforms/rpxhiox.h41
-rw-r--r--arch/ppc/platforms/rpxlite.h4
-rw-r--r--arch/ppc/syslib/Makefile3
-rw-r--r--arch/ppc/syslib/cpc710.h81
-rw-r--r--arch/ppc/syslib/ipic.c2
-rw-r--r--arch/ppc/syslib/m8xx_setup.c2
-rw-r--r--arch/ppc/syslib/ppc4xx_sgdma.c2
-rw-r--r--arch/ppc/syslib/virtex_devices.c233
-rw-r--r--arch/ppc/syslib/virtex_devices.h34
-rw-r--r--arch/s390/Kconfig3
-rw-r--r--arch/s390/appldata/appldata_base.c2
-rw-r--r--arch/s390/appldata/appldata_net_sum.c5
-rw-r--r--arch/s390/crypto/Kconfig2
-rw-r--r--arch/s390/crypto/aes_s390.c15
-rw-r--r--arch/s390/kernel/asm-offsets.c2
-rw-r--r--arch/s390/kernel/compat_signal.c1
-rw-r--r--arch/s390/kernel/dis.c2
-rw-r--r--arch/s390/kernel/ipl.c32
-rw-r--r--arch/s390/kernel/kprobes.c30
-rw-r--r--arch/s390/kernel/process.c1
-rw-r--r--arch/s390/kernel/setup.c111
-rw-r--r--arch/s390/kernel/signal.c1
-rw-r--r--arch/s390/kernel/smp.c3
-rw-r--r--arch/s390/kernel/stacktrace.c18
-rw-r--r--arch/s390/kernel/sys_s390.c1
-rw-r--r--arch/s390/kernel/time.c1
-rw-r--r--arch/s390/kernel/traps.c17
-rw-r--r--arch/s390/kernel/vmlinux.lds.S2
-rw-r--r--arch/s390/mm/fault.c42
-rw-r--r--arch/sh/Kconfig120
-rw-r--r--arch/sh/Kconfig.debug20
-rw-r--r--arch/sh/Makefile6
-rw-r--r--arch/sh/boards/hp6xx/Makefile4
-rw-r--r--arch/sh/boards/hp6xx/pm.c8
-rw-r--r--arch/sh/boards/hp6xx/setup.c67
-rw-r--r--arch/sh/boards/landisk/Makefile2
-rw-r--r--arch/sh/boards/landisk/gio.c167
-rw-r--r--arch/sh/boards/landisk/io.c250
-rw-r--r--arch/sh/boards/landisk/irq.c83
-rw-r--r--arch/sh/boards/landisk/landisk_pwb.c346
-rw-r--r--arch/sh/boards/landisk/psw.c143
-rw-r--r--arch/sh/boards/landisk/rtc.c91
-rw-r--r--arch/sh/boards/landisk/setup.c164
-rw-r--r--arch/sh/boards/lboxre2/Makefile5
-rw-r--r--arch/sh/boards/lboxre2/irq.c31
-rw-r--r--arch/sh/boards/lboxre2/setup.c85
-rw-r--r--arch/sh/boards/renesas/r7780rp/Kconfig18
-rw-r--r--arch/sh/boards/renesas/r7780rp/Makefile6
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7780rp.c21
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq-r7785rp.c29
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq.c25
-rw-r--r--arch/sh/boards/renesas/r7780rp/setup.c78
-rw-r--r--arch/sh/boards/se/770x/io.c2
-rw-r--r--arch/sh/boards/se/770x/irq.c57
-rw-r--r--arch/sh/boards/se/770x/setup.c30
-rw-r--r--arch/sh/boards/se/7722/Makefile10
-rw-r--r--arch/sh/boards/se/7722/irq.c101
-rw-r--r--arch/sh/boards/se/7722/setup.c148
-rw-r--r--arch/sh/boards/se/7751/setup.c150
-rw-r--r--arch/sh/boards/se/7780/Makefile10
-rw-r--r--arch/sh/boards/se/7780/irq.c89
-rw-r--r--arch/sh/boards/se/7780/setup.c122
-rw-r--r--arch/sh/configs/lboxre2_defconfig1271
-rw-r--r--arch/sh/configs/r7780rp_defconfig108
-rw-r--r--arch/sh/configs/r7785rp_defconfig1334
-rw-r--r--arch/sh/configs/se7705_defconfig106
-rw-r--r--arch/sh/configs/se7712_defconfig1088
-rw-r--r--arch/sh/configs/se7722_defconfig980
-rw-r--r--arch/sh/configs/se7780_defconfig1309
-rw-r--r--arch/sh/drivers/Kconfig10
-rw-r--r--arch/sh/drivers/Makefile3
-rw-r--r--arch/sh/drivers/dma/Kconfig20
-rw-r--r--arch/sh/drivers/dma/Makefile4
-rw-r--r--arch/sh/drivers/dma/dmabrg.c196
-rw-r--r--arch/sh/drivers/heartbeat.c13
-rw-r--r--arch/sh/drivers/pci/Makefile5
-rw-r--r--arch/sh/drivers/pci/fixups-lboxre2.c41
-rw-r--r--arch/sh/drivers/pci/fixups-se7780.c60
-rw-r--r--arch/sh/drivers/pci/ops-landisk.c4
-rw-r--r--arch/sh/drivers/pci/ops-lboxre2.c63
-rw-r--r--arch/sh/drivers/pci/ops-r7780rp.c27
-rw-r--r--arch/sh/drivers/pci/ops-se7780.c96
-rw-r--r--arch/sh/drivers/pci/ops-sh4.c6
-rw-r--r--arch/sh/drivers/pci/pci-sh4.h2
-rw-r--r--arch/sh/drivers/pci/pci-sh7751.c15
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c45
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.h19
-rw-r--r--arch/sh/drivers/pci/pci-st40.c1
-rw-r--r--arch/sh/kernel/Makefile1
-rw-r--r--arch/sh/kernel/cf-enabler.c28
-rw-r--r--arch/sh/kernel/cpu/clock.c102
-rw-r--r--arch/sh/kernel/cpu/init.c19
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile2
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c3
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c56
-rw-r--r--arch/sh/kernel/cpu/sh2a/Makefile5
-rw-r--r--arch/sh/kernel/cpu/sh2a/opcode_helper.c55
-rw-r--r--arch/sh/kernel/cpu/sh2a/probe.c1
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile1
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S2
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S13
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c3
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c54
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c29
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c60
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile6
-rw-r--r--arch/sh/kernel/cpu/sh4/clock-sh4-202.c3
-rw-r--r--arch/sh/kernel/cpu/sh4/ex.S62
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c3
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c8
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh73180.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7343.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c600
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7770.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7780.c2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7785.c162
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c103
-rw-r--r--arch/sh/kernel/crash_dump.c46
-rw-r--r--arch/sh/kernel/early_printk.c18
-rw-r--r--arch/sh/kernel/irq.c5
-rw-r--r--arch/sh/kernel/kgdb_stub.c490
-rw-r--r--arch/sh/kernel/machine_kexec.c29
-rw-r--r--arch/sh/kernel/process.c24
-rw-r--r--arch/sh/kernel/ptrace.c1
-rw-r--r--arch/sh/kernel/setup.c269
-rw-r--r--arch/sh/kernel/sh_ksyms.c4
-rw-r--r--arch/sh/kernel/signal.c14
-rw-r--r--arch/sh/kernel/stacktrace.c11
-rw-r--r--arch/sh/kernel/sys_sh.c1
-rw-r--r--arch/sh/kernel/syscalls.S1
-rw-r--r--arch/sh/kernel/time.c172
-rw-r--r--arch/sh/kernel/timers/timer-cmt.c2
-rw-r--r--arch/sh/kernel/timers/timer-mtu2.c2
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c188
-rw-r--r--arch/sh/kernel/traps.c63
-rw-r--r--arch/sh/kernel/vmlinux.lds.S49
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.c2
-rw-r--r--arch/sh/lib/Makefile4
-rw-r--r--arch/sh/lib/delay.c5
-rw-r--r--arch/sh/lib/udivdi3.c16
-rw-r--r--arch/sh/mm/Kconfig27
-rw-r--r--arch/sh/mm/fault-nommu.c1
-rw-r--r--arch/sh/mm/fault.c39
-rw-r--r--arch/sh/mm/hugetlbpage.c1
-rw-r--r--arch/sh/mm/init.c199
-rw-r--r--arch/sh/mm/pmb.c6
-rw-r--r--arch/sh/tools/mach-types2
-rw-r--r--arch/sh64/kernel/early_printk.c8
-rw-r--r--arch/sh64/kernel/irq.c1
-rw-r--r--arch/sh64/kernel/pci_sh5.c1
-rw-r--r--arch/sh64/kernel/sh_ksyms.c1
-rw-r--r--arch/sh64/kernel/signal.c1
-rw-r--r--arch/sh64/kernel/sys_sh64.c1
-rw-r--r--arch/sh64/kernel/traps.c1
-rw-r--r--arch/sh64/kernel/unwind.c6
-rw-r--r--arch/sh64/kernel/vmlinux.lds.S2
-rw-r--r--arch/sh64/mach-cayman/iomap.c1
-rw-r--r--arch/sh64/mm/fault.c1
-rw-r--r--arch/sh64/mm/hugetlbpage.c1
-rw-r--r--arch/sh64/mm/tlbmiss.c1
-rw-r--r--arch/sparc/kernel/asm-offsets.c2
-rw-r--r--arch/sparc/kernel/head.S2
-rw-r--r--arch/sparc/kernel/irq.c1
-rw-r--r--arch/sparc/kernel/process.c1
-rw-r--r--arch/sparc/kernel/setup.c2
-rw-r--r--arch/sparc/kernel/signal.c1
-rw-r--r--arch/sparc/kernel/smp.c1
-rw-r--r--arch/sparc/kernel/sun4d_irq.c1
-rw-r--r--arch/sparc/kernel/sun4d_smp.c1
-rw-r--r--arch/sparc/kernel/sun4m_smp.c3
-rw-r--r--arch/sparc/kernel/sunos_ioctl.c1
-rw-r--r--arch/sparc/kernel/sys_solaris.c1
-rw-r--r--arch/sparc/kernel/systbls.S2
-rw-r--r--arch/sparc/kernel/traps.c2
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S2
-rw-r--r--arch/sparc/lib/bitext.c1
-rw-r--r--arch/sparc/mm/fault.c3
-rw-r--r--arch/sparc/mm/srmmu.c2
-rw-r--r--arch/sparc64/Kconfig5
-rw-r--r--arch/sparc64/defconfig71
-rw-r--r--arch/sparc64/kernel/Makefile2
-rw-r--r--arch/sparc64/kernel/central.c6
-rw-r--r--arch/sparc64/kernel/ebus.c3
-rw-r--r--arch/sparc64/kernel/irq.c16
-rw-r--r--arch/sparc64/kernel/kprobes.c13
-rw-r--r--arch/sparc64/kernel/pci.c83
-rw-r--r--arch/sparc64/kernel/pci_common.c46
-rw-r--r--arch/sparc64/kernel/pci_fire.c390
-rw-r--r--arch/sparc64/kernel/pci_impl.h124
-rw-r--r--arch/sparc64/kernel/pci_iommu.c26
-rw-r--r--arch/sparc64/kernel/pci_psycho.c264
-rw-r--r--arch/sparc64/kernel/pci_sabre.c204
-rw-r--r--arch/sparc64/kernel/pci_schizo.c352
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c298
-rw-r--r--arch/sparc64/kernel/process.c1
-rw-r--r--arch/sparc64/kernel/prom.c112
-rw-r--r--arch/sparc64/kernel/sbus.c12
-rw-r--r--arch/sparc64/kernel/signal.c1
-rw-r--r--arch/sparc64/kernel/signal32.c1
-rw-r--r--arch/sparc64/kernel/smp.c7
-rw-r--r--arch/sparc64/kernel/stacktrace.c20
-rw-r--r--arch/sparc64/kernel/sunos_ioctl32.c1
-rw-r--r--arch/sparc64/kernel/sys_sparc.c1
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c14
-rw-r--r--arch/sparc64/kernel/systbls.S3
-rw-r--r--arch/sparc64/kernel/traps.c17
-rw-r--r--arch/sparc64/kernel/unaligned.c1
-rw-r--r--arch/sparc64/mm/fault.c48
-rw-r--r--arch/sparc64/mm/hugetlbpage.c7
-rw-r--r--arch/sparc64/mm/init.c24
-rw-r--r--arch/sparc64/mm/tsb.c5
-rw-r--r--arch/sparc64/solaris/ioctl.c3
-rw-r--r--arch/sparc64/solaris/ipc.c1
-rw-r--r--arch/sparc64/solaris/misc.c1
-rw-r--r--arch/sparc64/solaris/signal.c1
-rw-r--r--arch/sparc64/solaris/socket.c1
-rw-r--r--arch/sparc64/solaris/socksys.c1
-rw-r--r--arch/um/Kconfig16
-rw-r--r--arch/um/Kconfig.scsi58
-rw-r--r--arch/um/defconfig1
-rw-r--r--arch/um/drivers/chan_kern.c1
-rw-r--r--arch/um/drivers/chan_user.c14
-rw-r--r--arch/um/drivers/cow_sys.h18
-rw-r--r--arch/um/drivers/daemon_user.c31
-rw-r--r--arch/um/drivers/fd.c1
-rw-r--r--arch/um/drivers/harddog_user.c1
-rw-r--r--arch/um/drivers/line.c1
-rw-r--r--arch/um/drivers/mcast_user.c16
-rw-r--r--arch/um/drivers/mconsole_kern.c1
-rw-r--r--arch/um/drivers/mconsole_user.c1
-rw-r--r--arch/um/drivers/mmapper_kern.c1
-rw-r--r--arch/um/drivers/net_kern.c165
-rw-r--r--arch/um/drivers/net_user.c4
-rw-r--r--arch/um/drivers/pcap_kern.c27
-rw-r--r--arch/um/drivers/pcap_user.c61
-rw-r--r--arch/um/drivers/port_user.c1
-rw-r--r--arch/um/drivers/pty.c2
-rw-r--r--arch/um/drivers/slip_user.c7
-rw-r--r--arch/um/drivers/slirp_user.c4
-rw-r--r--arch/um/drivers/ssl.c5
-rw-r--r--arch/um/drivers/stdio_console.c5
-rw-r--r--arch/um/drivers/tty.c1
-rw-r--r--arch/um/drivers/ubd_kern.c351
-rw-r--r--arch/um/drivers/ubd_user.c16
-rw-r--r--arch/um/drivers/xterm.c1
-rw-r--r--arch/um/include/arch.h15
-rw-r--r--arch/um/include/as-layout.h35
-rw-r--r--arch/um/include/common-offsets.h2
-rw-r--r--arch/um/include/kern_util.h13
-rw-r--r--arch/um/include/net_kern.h2
-rw-r--r--arch/um/include/net_user.h2
-rw-r--r--arch/um/include/os.h17
-rw-r--r--arch/um/include/skas/mode_kern_skas.h2
-rw-r--r--arch/um/include/sysdep-i386/archsetjmp.h2
-rw-r--r--arch/um/include/sysdep-x86_64/archsetjmp.h2
-rw-r--r--arch/um/include/tlb.h8
-rw-r--r--arch/um/include/tt/uaccess-tt.h2
-rw-r--r--arch/um/include/um_malloc.h1
-rw-r--r--arch/um/include/user.h29
-rw-r--r--arch/um/include/user_util.h69
-rw-r--r--arch/um/kernel/exec.c2
-rw-r--r--arch/um/kernel/init_task.c1
-rw-r--r--arch/um/kernel/initrd.c33
-rw-r--r--arch/um/kernel/irq.c16
-rw-r--r--arch/um/kernel/ksyms.c2
-rw-r--r--arch/um/kernel/mem.c4
-rw-r--r--arch/um/kernel/physmem.c230
-rw-r--r--arch/um/kernel/process.c125
-rw-r--r--arch/um/kernel/reboot.c1
-rw-r--r--arch/um/kernel/signal.c1
-rw-r--r--arch/um/kernel/skas/exec.c12
-rw-r--r--arch/um/kernel/skas/process.c11
-rw-r--r--arch/um/kernel/skas/tlb.c87
-rw-r--r--arch/um/kernel/smp.c28
-rw-r--r--arch/um/kernel/syscall.c1
-rw-r--r--arch/um/kernel/sysrq.c1
-rw-r--r--arch/um/kernel/time.c19
-rw-r--r--arch/um/kernel/tlb.c226
-rw-r--r--arch/um/kernel/trap.c50
-rw-r--r--arch/um/kernel/tt/exec_kern.c1
-rw-r--r--arch/um/kernel/tt/exec_user.c1
-rw-r--r--arch/um/kernel/tt/gdb.c3
-rw-r--r--arch/um/kernel/tt/include/mode_kern-tt.h52
-rw-r--r--arch/um/kernel/tt/mem.c1
-rw-r--r--arch/um/kernel/tt/mem_user.c1
-rw-r--r--arch/um/kernel/tt/process_kern.c4
-rw-r--r--arch/um/kernel/tt/ptproxy/proxy.c6
-rw-r--r--arch/um/kernel/tt/ptproxy/ptrace.c1
-rw-r--r--arch/um/kernel/tt/ptproxy/sysdep.c1
-rw-r--r--arch/um/kernel/tt/ptproxy/wait.c1
-rw-r--r--arch/um/kernel/tt/syscall_user.c1
-rw-r--r--arch/um/kernel/tt/tlb.c1
-rw-r--r--arch/um/kernel/tt/tracer.c1
-rw-r--r--arch/um/kernel/tt/trap_user.c1
-rw-r--r--arch/um/kernel/tt/uaccess_user.c1
-rw-r--r--arch/um/kernel/um_arch.c84
-rw-r--r--arch/um/os-Linux/aio.c61
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c66
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c44
-rw-r--r--arch/um/os-Linux/file.c47
-rw-r--r--arch/um/os-Linux/helper.c31
-rw-r--r--arch/um/os-Linux/irq.c1
-rw-r--r--arch/um/os-Linux/main.c23
-rw-r--r--arch/um/os-Linux/mem.c15
-rw-r--r--arch/um/os-Linux/process.c47
-rw-r--r--arch/um/os-Linux/sigio.c164
-rw-r--r--arch/um/os-Linux/signal.c1
-rw-r--r--arch/um/os-Linux/skas/mem.c77
-rw-r--r--arch/um/os-Linux/skas/process.c192
-rw-r--r--arch/um/os-Linux/skas/trap.c49
-rw-r--r--arch/um/os-Linux/start_up.c173
-rw-r--r--arch/um/os-Linux/sys-i386/tls.c2
-rw-r--r--arch/um/os-Linux/time.c1
-rw-r--r--arch/um/os-Linux/trap.c1
-rw-r--r--arch/um/os-Linux/tt.c4
-rw-r--r--arch/um/os-Linux/tty_log.c28
-rw-r--r--arch/um/os-Linux/util.c26
-rw-r--r--arch/um/sys-i386/bugs.c78
-rw-r--r--arch/um/sys-i386/fault.c18
-rw-r--r--arch/um/sys-i386/ptrace_user.c17
-rw-r--r--arch/um/sys-i386/signal.c84
-rw-r--r--arch/um/sys-i386/tls.c11
-rw-r--r--arch/um/sys-i386/user-offsets.c10
-rw-r--r--arch/um/sys-ppc/sigcontext.c1
-rw-r--r--arch/um/sys-x86_64/bugs.c104
-rw-r--r--arch/um/sys-x86_64/fault.c30
-rw-r--r--arch/um/sys-x86_64/signal.c32
-rw-r--r--arch/um/sys-x86_64/user-offsets.c6
-rw-r--r--arch/v850/Kconfig4
-rw-r--r--arch/v850/kernel/asm-offsets.c2
-rw-r--r--arch/v850/kernel/entry.S2
-rw-r--r--arch/v850/kernel/process.c1
-rw-r--r--arch/v850/kernel/ptrace.c1
-rw-r--r--arch/v850/kernel/signal.c1
-rw-r--r--arch/v850/kernel/syscalls.c1
-rw-r--r--arch/v850/kernel/time.c75
-rw-r--r--arch/x86_64/Kconfig62
-rw-r--r--arch/x86_64/Makefile4
-rw-r--r--arch/x86_64/boot/Makefile2
-rw-r--r--arch/x86_64/boot/compressed/Makefile12
-rw-r--r--arch/x86_64/boot/compressed/head.S339
-rw-r--r--arch/x86_64/boot/compressed/misc.c247
-rw-r--r--arch/x86_64/boot/compressed/vmlinux.lds44
-rw-r--r--arch/x86_64/boot/compressed/vmlinux.scr9
-rw-r--r--arch/x86_64/boot/setup.S85
-rw-r--r--arch/x86_64/boot/video.S2043
-rw-r--r--arch/x86_64/defconfig184
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c10
-rw-r--r--arch/x86_64/ia32/ia32_signal.c1
-rw-r--r--arch/x86_64/ia32/ia32entry.S7
-rw-r--r--arch/x86_64/ia32/syscall32.c1
-rw-r--r--arch/x86_64/kernel/Makefile9
-rw-r--r--arch/x86_64/kernel/acpi/sleep.c24
-rw-r--r--arch/x86_64/kernel/acpi/wakeup.S286
-rw-r--r--arch/x86_64/kernel/aperture.c5
-rw-r--r--arch/x86_64/kernel/apic.c36
-rw-r--r--arch/x86_64/kernel/asm-offsets.c10
-rw-r--r--arch/x86_64/kernel/bugs.c21
-rw-r--r--arch/x86_64/kernel/cpufreq/Kconfig19
-rw-r--r--arch/x86_64/kernel/crash.c2
-rw-r--r--arch/x86_64/kernel/e820.c31
-rw-r--r--arch/x86_64/kernel/early-quirks.c13
-rw-r--r--arch/x86_64/kernel/early_printk.c25
-rw-r--r--arch/x86_64/kernel/entry.S5
-rw-r--r--arch/x86_64/kernel/functionlist1284
-rw-r--r--arch/x86_64/kernel/genapic.c104
-rw-r--r--arch/x86_64/kernel/genapic_cluster.c137
-rw-r--r--arch/x86_64/kernel/genapic_flat.c25
-rw-r--r--arch/x86_64/kernel/head.S340
-rw-r--r--arch/x86_64/kernel/head64.c41
-rw-r--r--arch/x86_64/kernel/i8259.c1
-rw-r--r--arch/x86_64/kernel/io_apic.c38
-rw-r--r--arch/x86_64/kernel/ioport.c2
-rw-r--r--arch/x86_64/kernel/irq.c2
-rw-r--r--arch/x86_64/kernel/kprobes.c29
-rw-r--r--arch/x86_64/kernel/ldt.c1
-rw-r--r--arch/x86_64/kernel/machine_kexec.c16
-rw-r--r--arch/x86_64/kernel/mce.c36
-rw-r--r--arch/x86_64/kernel/mce_amd.c2
-rw-r--r--arch/x86_64/kernel/mpparse.c3
-rw-r--r--arch/x86_64/kernel/nmi.c680
-rw-r--r--arch/x86_64/kernel/pci-calgary.c2
-rw-r--r--arch/x86_64/kernel/pci-gart.c4
-rw-r--r--arch/x86_64/kernel/pci-nommu.c2
-rw-r--r--arch/x86_64/kernel/pci-swiotlb.c2
-rw-r--r--arch/x86_64/kernel/process.c14
-rw-r--r--arch/x86_64/kernel/ptrace.c1
-rw-r--r--arch/x86_64/kernel/reboot.c2
-rw-r--r--arch/x86_64/kernel/setup.c26
-rw-r--r--arch/x86_64/kernel/setup64.c5
-rw-r--r--arch/x86_64/kernel/signal.c7
-rw-r--r--arch/x86_64/kernel/smp.c29
-rw-r--r--arch/x86_64/kernel/smpboot.c50
-rw-r--r--arch/x86_64/kernel/stacktrace.c8
-rw-r--r--arch/x86_64/kernel/suspend.c19
-rw-r--r--arch/x86_64/kernel/suspend_asm.S7
-rw-r--r--arch/x86_64/kernel/sys_x86_64.c4
-rw-r--r--arch/x86_64/kernel/syscall.c1
-rw-r--r--arch/x86_64/kernel/time.c76
-rw-r--r--arch/x86_64/kernel/trampoline.S123
-rw-r--r--arch/x86_64/kernel/traps.c54
-rw-r--r--arch/x86_64/kernel/tsc.c17
-rw-r--r--arch/x86_64/kernel/tsc_sync.c4
-rw-r--r--arch/x86_64/kernel/verify_cpu.S119
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S20
-rw-r--r--arch/x86_64/kernel/vsyscall.c70
-rw-r--r--arch/x86_64/mm/fault.c9
-rw-r--r--arch/x86_64/mm/init.c167
-rw-r--r--arch/x86_64/mm/ioremap.c9
-rw-r--r--arch/x86_64/mm/k8topology.c9
-rw-r--r--arch/x86_64/mm/numa.c306
-rw-r--r--arch/x86_64/mm/pageattr.c16
-rw-r--r--arch/x86_64/mm/srat.c8
-rw-r--r--arch/xtensa/kernel/asm-offsets.c2
-rw-r--r--arch/xtensa/kernel/pci-dma.c2
-rw-r--r--arch/xtensa/kernel/process.c1
-rw-r--r--arch/xtensa/kernel/ptrace.c1
-rw-r--r--arch/xtensa/kernel/signal.c1
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S2
-rw-r--r--arch/xtensa/kernel/xtensa_ksyms.c1
-rw-r--r--arch/xtensa/platform-iss/network.c2
-rw-r--r--arch/xtensa/platform-iss/setup.c1
-rw-r--r--block/as-iosched.c8
-rw-r--r--block/cfq-iosched.c859
-rw-r--r--block/elevator.c17
-rw-r--r--block/genhd.c65
-rw-r--r--block/ioctl.c4
-rw-r--r--block/ll_rw_blk.c15
-rw-r--r--block/scsi_ioctl.c4
-rw-r--r--crypto/Kconfig15
-rw-r--r--crypto/Makefile2
-rw-r--r--crypto/ablkcipher.c83
-rw-r--r--crypto/algapi.c169
-rw-r--r--crypto/blkcipher.c72
-rw-r--r--crypto/cbc.c11
-rw-r--r--crypto/cryptd.c375
-rw-r--r--crypto/cryptomgr.c65
-rw-r--r--crypto/ecb.c11
-rw-r--r--crypto/hash.c2
-rw-r--r--crypto/hmac.c11
-rw-r--r--crypto/lrw.c11
-rw-r--r--crypto/michael_mic.c4
-rw-r--r--crypto/pcbc.c11
-rw-r--r--crypto/tcrypt.c121
-rw-r--r--crypto/xcbc.c12
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig44
-rw-r--r--drivers/acpi/Makefile10
-rw-r--r--drivers/acpi/acpi_memhotplug.c13
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/container.c6
-rw-r--r--drivers/acpi/dock.c25
-rw-r--r--drivers/acpi/ec.c495
-rw-r--r--drivers/acpi/glue.c46
-rw-r--r--drivers/acpi/i2c_ec.c403
-rw-r--r--drivers/acpi/i2c_ec.h23
-rw-r--r--drivers/acpi/ibm_acpi.c2798
-rw-r--r--drivers/acpi/osl.c1
-rw-r--r--drivers/acpi/processor_core.c4
-rw-r--r--drivers/acpi/processor_idle.c12
-rw-r--r--drivers/acpi/processor_perflib.c46
-rw-r--r--drivers/acpi/sbs.c1291
-rw-r--r--drivers/acpi/scan.c6
-rw-r--r--drivers/acpi/sleep/main.c80
-rw-r--r--drivers/acpi/sleep/proc.c37
-rw-r--r--drivers/acpi/tables/tbfadt.c12
-rw-r--r--drivers/ata/Kconfig55
-rw-r--r--drivers/ata/Makefile2
-rw-r--r--drivers/ata/ahci.c501
-rw-r--r--drivers/ata/ata_generic.c32
-rw-r--r--drivers/ata/ata_piix.c62
-rw-r--r--drivers/ata/libata-core.c1248
-rw-r--r--drivers/ata/libata-eh.c77
-rw-r--r--drivers/ata/libata-scsi.c85
-rw-r--r--drivers/ata/libata-sff.c636
-rw-r--r--drivers/ata/libata.h10
-rw-r--r--drivers/ata/pata_ali.c74
-rw-r--r--drivers/ata/pata_amd.c100
-rw-r--r--drivers/ata/pata_artop.c33
-rw-r--r--drivers/ata/pata_atiixp.c30
-rw-r--r--drivers/ata/pata_cmd640.c312
-rw-r--r--drivers/ata/pata_cmd64x.c34
-rw-r--r--drivers/ata/pata_cs5520.c145
-rw-r--r--drivers/ata/pata_cs5530.c15
-rw-r--r--drivers/ata/pata_cs5535.c25
-rw-r--r--drivers/ata/pata_cypress.c14
-rw-r--r--drivers/ata/pata_efar.c36
-rw-r--r--drivers/ata/pata_hpt366.c30
-rw-r--r--drivers/ata/pata_hpt37x.c390
-rw-r--r--drivers/ata/pata_hpt3x2n.c75
-rw-r--r--drivers/ata/pata_hpt3x3.c22
-rw-r--r--drivers/ata/pata_icside.c686
-rw-r--r--drivers/ata/pata_isapnp.c44
-rw-r--r--drivers/ata/pata_it8213.c40
-rw-r--r--drivers/ata/pata_it821x.c36
-rw-r--r--drivers/ata/pata_ixp4xx_cf.c40
-rw-r--r--drivers/ata/pata_jmicron.c7
-rw-r--r--drivers/ata/pata_legacy.c45
-rw-r--r--drivers/ata/pata_marvell.c25
-rw-r--r--drivers/ata/pata_mpc52xx.c49
-rw-r--r--drivers/ata/pata_mpiix.c45
-rw-r--r--drivers/ata/pata_netcell.c31
-rw-r--r--drivers/ata/pata_ns87410.c12
-rw-r--r--drivers/ata/pata_oldpiix.c12
-rw-r--r--drivers/ata/pata_opti.c9
-rw-r--r--drivers/ata/pata_optidma.c59
-rw-r--r--drivers/ata/pata_pcmcia.c77
-rw-r--r--drivers/ata/pata_pdc2027x.c163
-rw-r--r--drivers/ata/pata_pdc202xx_old.c45
-rw-r--r--drivers/ata/pata_platform.c44
-rw-r--r--drivers/ata/pata_qdi.c47
-rw-r--r--drivers/ata/pata_radisys.c37
-rw-r--r--drivers/ata/pata_rz1000.c28
-rw-r--r--drivers/ata/pata_sc1200.c1
-rw-r--r--drivers/ata/pata_scc.c51
-rw-r--r--drivers/ata/pata_serverworks.c36
-rw-r--r--drivers/ata/pata_sil680.c17
-rw-r--r--drivers/ata/pata_sis.c115
-rw-r--r--drivers/ata/pata_sl82c105.c7
-rw-r--r--drivers/ata/pata_triflex.c10
-rw-r--r--drivers/ata/pata_via.c30
-rw-r--r--drivers/ata/pata_winbond.c101
-rw-r--r--drivers/ata/pdc_adma.c85
-rw-r--r--drivers/ata/sata_inic162x.c101
-rw-r--r--drivers/ata/sata_mv.c213
-rw-r--r--drivers/ata/sata_nv.c135
-rw-r--r--drivers/ata/sata_promise.c398
-rw-r--r--drivers/ata/sata_qstor.c62
-rw-r--r--drivers/ata/sata_sil.c118
-rw-r--r--drivers/ata/sata_sil24.c132
-rw-r--r--drivers/ata/sata_sis.c50
-rw-r--r--drivers/ata/sata_svw.c109
-rw-r--r--drivers/ata/sata_sx4.c150
-rw-r--r--drivers/ata/sata_uli.c65
-rw-r--r--drivers/ata/sata_via.c222
-rw-r--r--drivers/ata/sata_vsc.c72
-rw-r--r--drivers/atm/adummy.c1
-rw-r--r--drivers/base/Makefile4
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c16
-rw-r--r--drivers/base/class.c18
-rw-r--r--drivers/base/core.c29
-rw-r--r--drivers/base/dd.c41
-rw-r--r--drivers/base/devres.c32
-rw-r--r--drivers/base/firmware.c6
-rw-r--r--drivers/base/platform.c28
-rw-r--r--drivers/base/power/shutdown.c4
-rw-r--r--drivers/base/sys.c14
-rw-r--r--drivers/base/topology.c3
-rw-r--r--drivers/block/acsi_slm.c1
-rw-r--r--drivers/block/amiflop.c2
-rw-r--r--drivers/block/aoe/aoecmd.c8
-rw-r--r--drivers/block/cciss.c288
-rw-r--r--drivers/block/cciss_scsi.c1
-rw-r--r--drivers/block/floppy.c7
-rw-r--r--drivers/block/loop.c194
-rw-r--r--drivers/block/nbd.c15
-rw-r--r--drivers/block/rd.c4
-rw-r--r--drivers/block/umem.c1
-rw-r--r--drivers/bluetooth/hci_usb.c6
-rw-r--r--drivers/cdrom/cdrom.c2
-rw-r--r--drivers/char/Kconfig15
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/ali-agp.c2
-rw-r--r--drivers/char/agp/alpha-agp.c2
-rw-r--r--drivers/char/agp/amd64-agp.c13
-rw-r--r--drivers/char/agp/generic.c22
-rw-r--r--drivers/char/agp/intel-agp.c8
-rw-r--r--drivers/char/agp/nvidia-agp.c9
-rw-r--r--drivers/char/agp/parisc-agp.c2
-rw-r--r--drivers/char/agp/sgi-agp.c5
-rw-r--r--drivers/char/agp/sis-agp.c278
-rw-r--r--drivers/char/agp/sworks-agp.c23
-rw-r--r--drivers/char/agp/uninorth-agp.c2
-rw-r--r--drivers/char/amiserial.c4
-rw-r--r--drivers/char/briq_panel.c9
-rw-r--r--drivers/char/consolemap.c6
-rw-r--r--drivers/char/cs5535_gpio.c1
-rw-r--r--drivers/char/cyclades.c2581
-rw-r--r--drivers/char/digi.h71
-rw-r--r--drivers/char/drm/README.drm16
-rw-r--r--drivers/char/drm/ati_pcigart.c84
-rw-r--r--drivers/char/drm/drm.h4
-rw-r--r--drivers/char/drm/drmP.h30
-rw-r--r--drivers/char/drm/drm_bufs.c75
-rw-r--r--drivers/char/drm/drm_dma.c2
-rw-r--r--drivers/char/drm/drm_drv.c15
-rw-r--r--drivers/char/drm/drm_fops.c96
-rw-r--r--drivers/char/drm/drm_hashtab.c17
-rw-r--r--drivers/char/drm/drm_hashtab.h1
-rw-r--r--drivers/char/drm/drm_irq.c4
-rw-r--r--drivers/char/drm/drm_lock.c134
-rw-r--r--drivers/char/drm/drm_mm.c2
-rw-r--r--drivers/char/drm/drm_os_linux.h3
-rw-r--r--drivers/char/drm/drm_pciids.h4
-rw-r--r--drivers/char/drm/drm_proc.c2
-rw-r--r--drivers/char/drm/drm_stub.c1
-rw-r--r--drivers/char/drm/drm_vm.c104
-rw-r--r--drivers/char/drm/i915_dma.c3
-rw-r--r--drivers/char/drm/r128_cce.c3
-rw-r--r--drivers/char/drm/r128_drv.h2
-rw-r--r--drivers/char/drm/r300_reg.h2
-rw-r--r--drivers/char/drm/radeon_cp.c79
-rw-r--r--drivers/char/drm/radeon_drm.h1
-rw-r--r--drivers/char/drm/radeon_drv.h24
-rw-r--r--drivers/char/drm/radeon_state.c52
-rw-r--r--drivers/char/drm/sis_drv.c2
-rw-r--r--drivers/char/drm/via_dma.c111
-rw-r--r--drivers/char/drm/via_drv.c3
-rw-r--r--drivers/char/drm/via_drv.h5
-rw-r--r--drivers/char/drm/via_mm.h40
-rw-r--r--drivers/char/ds1620.c1
-rw-r--r--drivers/char/dsp56k.c1
-rw-r--r--drivers/char/dtlk.c15
-rw-r--r--drivers/char/ec3104_keyb.c1
-rw-r--r--drivers/char/epca.c2
-rw-r--r--drivers/char/genrtc.c6
-rw-r--r--drivers/char/hangcheck-timer.c1
-rw-r--r--drivers/char/hvc_console.c61
-rw-r--r--drivers/char/hvc_iseries.c4
-rw-r--r--drivers/char/hvc_vio.c4
-rw-r--r--drivers/char/hvsi.c4
-rw-r--r--drivers/char/hw_random/Kconfig14
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/intel-rng.c219
-rw-r--r--drivers/char/hw_random/pasemi-rng.c156
-rw-r--r--drivers/char/hw_random/via-rng.c1
-rw-r--r--drivers/char/i8k.c1
-rw-r--r--drivers/char/ip27-rtc.c1
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c235
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c136
-rw-r--r--drivers/char/isicom.c3
-rw-r--r--drivers/char/keyboard.c103
-rw-r--r--drivers/char/lp.c8
-rw-r--r--drivers/char/mem.c9
-rw-r--r--drivers/char/misc.c27
-rw-r--r--drivers/char/moxa.c8
-rw-r--r--drivers/char/mxser.c1
-rw-r--r--drivers/char/mxser_new.c1
-rw-r--r--drivers/char/n_r3964.c4
-rw-r--r--drivers/char/pcmcia/Kconfig1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c46
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c7
-rw-r--r--drivers/char/pcmcia/synclink_cs.c1
-rw-r--r--drivers/char/ppdev.c3
-rw-r--r--drivers/char/riscom8.c2
-rw-r--r--drivers/char/rocket.c33
-rw-r--r--drivers/char/rocket_int.h4
-rw-r--r--drivers/char/rtc.c2
-rw-r--r--drivers/char/selection.c2
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/sonypi.c53
-rw-r--r--drivers/char/synclink.c7
-rw-r--r--drivers/char/synclink_gt.c34
-rw-r--r--drivers/char/sysrq.c1
-rw-r--r--drivers/char/tipar.c2
-rw-r--r--drivers/char/tpm/Kconfig2
-rw-r--r--drivers/char/tpm/tpm.c36
-rw-r--r--drivers/char/tpm/tpm.h6
-rw-r--r--drivers/char/tpm/tpm_atmel.h8
-rw-r--r--drivers/char/tpm/tpm_infineon.c231
-rw-r--r--drivers/char/tty_io.c80
-rw-r--r--drivers/char/vc_screen.c19
-rw-r--r--drivers/char/vt.c304
-rw-r--r--drivers/char/vt_ioctl.c2
-rw-r--r--drivers/char/watchdog/Kconfig2
-rw-r--r--drivers/char/watchdog/omap_wdt.c1
-rw-r--r--drivers/char/watchdog/sc1200wdt.c1
-rw-r--r--drivers/char/watchdog/scx200_wdt.c2
-rw-r--r--drivers/clocksource/acpi_pm.c2
-rw-r--r--drivers/cpufreq/Kconfig61
-rw-r--r--drivers/cpufreq/cpufreq.c50
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c2
-rw-r--r--drivers/cpufreq/cpufreq_stats.c2
-rw-r--r--drivers/crypto/Kconfig18
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/padlock.c58
-rw-r--r--drivers/edac/i82875p_edac.c13
-rw-r--r--drivers/eisa/virtual_root.c2
-rw-r--r--drivers/firmware/efivars.c12
-rw-r--r--drivers/hid/Kconfig2
-rw-r--r--drivers/hid/Makefile4
-rw-r--r--drivers/hid/hid-core.c10
-rw-r--r--drivers/hid/hid-input.c27
-rw-r--r--drivers/hid/usbhid/Kconfig149
-rw-r--r--drivers/hid/usbhid/Makefile35
-rw-r--r--drivers/hid/usbhid/hid-core.c (renamed from drivers/usb/input/hid-core.c)491
-rw-r--r--drivers/hid/usbhid/hid-ff.c (renamed from drivers/usb/input/hid-ff.c)2
-rw-r--r--drivers/hid/usbhid/hid-lgff.c (renamed from drivers/usb/input/hid-lgff.c)1
-rw-r--r--drivers/hid/usbhid/hid-pidff.c (renamed from drivers/usb/input/hid-pidff.c)0
-rw-r--r--drivers/hid/usbhid/hid-plff.c (renamed from drivers/usb/input/hid-plff.c)0
-rw-r--r--drivers/hid/usbhid/hid-quirks.c681
-rw-r--r--drivers/hid/usbhid/hid-tmff.c (renamed from drivers/usb/input/hid-tmff.c)0
-rw-r--r--drivers/hid/usbhid/hid-zpff.c (renamed from drivers/usb/input/hid-zpff.c)0
-rw-r--r--drivers/hid/usbhid/hiddev.c (renamed from drivers/usb/input/hiddev.c)0
-rw-r--r--drivers/hid/usbhid/usbhid.h (renamed from drivers/usb/input/usbhid.h)0
-rw-r--r--drivers/hid/usbhid/usbkbd.c (renamed from drivers/usb/input/usbkbd.c)13
-rw-r--r--drivers/hid/usbhid/usbmouse.c (renamed from drivers/usb/input/usbmouse.c)15
-rw-r--r--drivers/hwmon/Kconfig170
-rw-r--r--drivers/hwmon/Makefile4
-rw-r--r--drivers/hwmon/ad7418.c373
-rw-r--r--drivers/hwmon/ams/ams-core.c11
-rw-r--r--drivers/hwmon/ams/ams-i2c.c12
-rw-r--r--drivers/hwmon/ams/ams-pmu.c4
-rw-r--r--drivers/hwmon/applesmc.c1340
-rw-r--r--drivers/hwmon/coretemp.c408
-rw-r--r--drivers/hwmon/f71805f.c16
-rw-r--r--drivers/hwmon/hdaps.c38
-rw-r--r--drivers/hwmon/hwmon-vid.c6
-rw-r--r--drivers/hwmon/lm75.c82
-rw-r--r--drivers/hwmon/lm78.c662
-rw-r--r--drivers/hwmon/lm87.c2
-rw-r--r--drivers/hwmon/max6650.c693
-rw-r--r--drivers/hwmon/pc87427.c15
-rw-r--r--drivers/hwmon/smsc47b397.c228
-rw-r--r--drivers/hwmon/smsc47m1.c606
-rw-r--r--drivers/hwmon/smsc47m192.c4
-rw-r--r--drivers/hwmon/vt1211.c13
-rw-r--r--drivers/hwmon/w83627hf.c670
-rw-r--r--drivers/hwmon/w83781d.c1205
-rw-r--r--drivers/i2c/Kconfig18
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/algos/Kconfig8
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c286
-rw-r--r--drivers/i2c/algos/i2c-algo-sgi.c9
-rw-r--r--drivers/i2c/busses/Kconfig151
-rw-r--r--drivers/i2c/busses/Makefile4
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-at91.c1
-rw-r--r--drivers/i2c/busses/i2c-bfin-twi.c644
-rw-r--r--drivers/i2c/busses/i2c-elektor.c51
-rw-r--r--drivers/i2c/busses/i2c-gpio.c215
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-isa.c43
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c2
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c2
-rw-r--r--drivers/i2c/busses/i2c-mpc.c1
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c2
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c6
-rw-r--r--drivers/i2c/busses/i2c-omap.c3
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c144
-rw-r--r--drivers/i2c/busses/i2c-parport.c26
-rw-r--r--drivers/i2c/busses/i2c-pasemi.c2
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c36
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-pxa.c33
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c96
-rw-r--r--drivers/i2c/busses/i2c-simtec.c186
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-tiny-usb.c277
-rw-r--r--drivers/i2c/busses/i2c-viapro.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c4
-rw-r--r--drivers/i2c/chips/Kconfig21
-rw-r--r--drivers/i2c/chips/tps65010.c4
-rw-r--r--drivers/i2c/i2c-boardinfo.c90
-rw-r--r--drivers/i2c/i2c-core.c662
-rw-r--r--drivers/i2c/i2c-core.h31
-rw-r--r--drivers/i2c/i2c-dev.c1
-rw-r--r--drivers/ide/cris/ide-cris.c9
-rw-r--r--drivers/ide/legacy/ide-cs.c1
-rw-r--r--drivers/ide/pci/aec62xx.c22
-rw-r--r--drivers/ide/pci/alim15x3.c7
-rw-r--r--drivers/ide/pci/cmd64x.c537
-rw-r--r--drivers/ide/pci/hpt366.c7
-rw-r--r--drivers/ide/pci/it821x.c126
-rw-r--r--drivers/ide/pci/pdc202xx_new.c5
-rw-r--r--drivers/ide/pci/siimage.c14
-rw-r--r--drivers/ide/pci/sl82c105.c247
-rw-r--r--drivers/ide/ppc/pmac.c18
-rw-r--r--drivers/ieee1394/Kconfig52
-rw-r--r--drivers/ieee1394/config_roms.c93
-rw-r--r--drivers/ieee1394/config_roms.h20
-rw-r--r--drivers/ieee1394/csr1212.c870
-rw-r--r--drivers/ieee1394/csr1212.h483
-rw-r--r--drivers/ieee1394/dma.c24
-rw-r--r--drivers/ieee1394/dma.h22
-rw-r--r--drivers/ieee1394/dv1394.c1
-rw-r--r--drivers/ieee1394/eth1394.c798
-rw-r--r--drivers/ieee1394/eth1394.h25
-rw-r--r--drivers/ieee1394/highlevel.c89
-rw-r--r--drivers/ieee1394/highlevel.h55
-rw-r--r--drivers/ieee1394/hosts.c24
-rw-r--r--drivers/ieee1394/hosts.h10
-rw-r--r--drivers/ieee1394/ieee1394_core.c461
-rw-r--r--drivers/ieee1394/ieee1394_core.h100
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c43
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h20
-rw-r--r--drivers/ieee1394/iso.c85
-rw-r--r--drivers/ieee1394/iso.h35
-rw-r--r--drivers/ieee1394/nodemgr.c63
-rw-r--r--drivers/ieee1394/nodemgr.h24
-rw-r--r--drivers/ieee1394/ohci1394.c12
-rw-r--r--drivers/ieee1394/ohci1394.h4
-rw-r--r--drivers/ieee1394/raw1394.c4
-rw-r--r--drivers/ieee1394/sbp2.c39
-rw-r--r--drivers/ieee1394/sbp2.h8
-rw-r--r--drivers/ieee1394/video1394.c1
-rw-r--r--drivers/infiniband/core/cm.c1
-rw-r--r--drivers/infiniband/core/fmr_pool.c32
-rw-r--r--drivers/infiniband/core/iwcm.c1
-rw-r--r--drivers/infiniband/core/mad.c2
-rw-r--r--drivers/infiniband/core/mad_priv.h1
-rw-r--r--drivers/infiniband/core/multicast.c1
-rw-r--r--drivers/infiniband/core/sa_query.c1
-rw-r--r--drivers/infiniband/core/user_mad.c1
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c1
-rw-r--r--drivers/infiniband/core/uverbs_main.c2
-rw-r--r--drivers/infiniband/core/verbs.c4
-rw-r--r--drivers/infiniband/hw/amso1100/c2.h2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cq.c16
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c3
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c3
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c19
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.h6
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c14
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c69
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c6
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c7
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c14
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.h8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c68
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mmap.c64
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c52
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c55
-rw-r--r--drivers/infiniband/hw/ipath/ipath_srq.c55
-rw-r--r--drivers/infiniband/hw/ipath/ipath_stats.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h24
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c12
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.h1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c13
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c14
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c89
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c2
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c2
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c3
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c27
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h1
-rw-r--r--drivers/input/Kconfig2
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/evbug.c32
-rw-r--r--drivers/input/evdev.c242
-rw-r--r--drivers/input/ff-core.c3
-rw-r--r--drivers/input/input.c267
-rw-r--r--drivers/input/joydev.c188
-rw-r--r--drivers/input/joystick/Kconfig18
-rw-r--r--drivers/input/joystick/Makefile1
-rw-r--r--drivers/input/joystick/a3d.c9
-rw-r--r--drivers/input/joystick/adi.c9
-rw-r--r--drivers/input/joystick/analog.c11
-rw-r--r--drivers/input/joystick/cobra.c9
-rw-r--r--drivers/input/joystick/db9.c25
-rw-r--r--drivers/input/joystick/gamecon.c24
-rw-r--r--drivers/input/joystick/gf2k.c10
-rw-r--r--drivers/input/joystick/grip.c9
-rw-r--r--drivers/input/joystick/grip_mp.c11
-rw-r--r--drivers/input/joystick/guillemot.c9
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c10
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c26
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c22
-rw-r--r--drivers/input/joystick/iforce/iforce-serio.c2
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c13
-rw-r--r--drivers/input/joystick/iforce/iforce.h4
-rw-r--r--drivers/input/joystick/interact.c8
-rw-r--r--drivers/input/joystick/magellan.c3
-rw-r--r--drivers/input/joystick/sidewinder.c9
-rw-r--r--drivers/input/joystick/spaceball.c3
-rw-r--r--drivers/input/joystick/spaceorb.c3
-rw-r--r--drivers/input/joystick/stinger.c3
-rw-r--r--drivers/input/joystick/tmdc.c9
-rw-r--r--drivers/input/joystick/turbografx.c25
-rw-r--r--drivers/input/joystick/twidjoy.c4
-rw-r--r--drivers/input/joystick/warrior.c3
-rw-r--r--drivers/input/joystick/xpad.c (renamed from drivers/usb/input/xpad.c)23
-rw-r--r--drivers/input/keyboard/Kconfig21
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/aaed2000_kbd.c63
-rw-r--r--drivers/input/keyboard/atakbd.c134
-rw-r--r--drivers/input/keyboard/atkbd.c7
-rw-r--r--drivers/input/keyboard/corgikbd.c3
-rw-r--r--drivers/input/keyboard/gpio_keys.c22
-rw-r--r--drivers/input/keyboard/hil_kbd.c89
-rw-r--r--drivers/input/keyboard/hilkbd.c8
-rw-r--r--drivers/input/keyboard/lkkbd.c7
-rw-r--r--drivers/input/keyboard/locomokbd.c2
-rw-r--r--drivers/input/keyboard/newtonkbd.c3
-rw-r--r--drivers/input/keyboard/omap-keypad.c3
-rw-r--r--drivers/input/keyboard/pxa27x_keyboard.c258
-rw-r--r--drivers/input/keyboard/spitzkbd.c3
-rw-r--r--drivers/input/keyboard/stowaway.c3
-rw-r--r--drivers/input/keyboard/sunkbd.c8
-rw-r--r--drivers/input/keyboard/xtkbd.c3
-rw-r--r--drivers/input/misc/Kconfig111
-rw-r--r--drivers/input/misc/Makefile11
-rw-r--r--drivers/input/misc/ati_remote.c (renamed from drivers/usb/input/ati_remote.c)42
-rw-r--r--drivers/input/misc/ati_remote2.c (renamed from drivers/usb/input/ati_remote2.c)20
-rw-r--r--drivers/input/misc/cobalt_btns.c172
-rw-r--r--drivers/input/misc/input-polldev.c171
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c11
-rw-r--r--drivers/input/misc/keyspan_remote.c (renamed from drivers/usb/input/keyspan_remote.c)29
-rw-r--r--drivers/input/misc/m68kspkr.c2
-rw-r--r--drivers/input/misc/map_to_7segment.h (renamed from drivers/usb/input/map_to_7segment.h)0
-rw-r--r--drivers/input/misc/pcspkr.c2
-rw-r--r--drivers/input/misc/powermate.c (renamed from drivers/usb/input/powermate.c)37
-rw-r--r--drivers/input/misc/sparcspkr.c6
-rw-r--r--drivers/input/misc/uinput.c11
-rw-r--r--drivers/input/misc/wistron_btns.c685
-rw-r--r--drivers/input/misc/yealink.c (renamed from drivers/usb/input/yealink.c)38
-rw-r--r--drivers/input/misc/yealink.h (renamed from drivers/usb/input/yealink.h)0
-rw-r--r--drivers/input/mouse/Kconfig98
-rw-r--r--drivers/input/mouse/Makefile10
-rw-r--r--drivers/input/mouse/alps.c13
-rw-r--r--drivers/input/mouse/alps.h18
-rw-r--r--drivers/input/mouse/appletouch.c (renamed from drivers/usb/input/appletouch.c)29
-rw-r--r--drivers/input/mouse/atarimouse.c160
-rw-r--r--drivers/input/mouse/hil_ptr.c97
-rw-r--r--drivers/input/mouse/lifebook.c195
-rw-r--r--drivers/input/mouse/lifebook.h11
-rw-r--r--drivers/input/mouse/logips2pp.c7
-rw-r--r--drivers/input/mouse/logips2pp.h7
-rw-r--r--drivers/input/mouse/psmouse-base.c50
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/sermouse.c19
-rw-r--r--drivers/input/mouse/synaptics.c111
-rw-r--r--drivers/input/mouse/synaptics.h18
-rw-r--r--drivers/input/mouse/touchkit_ps2.c100
-rw-r--r--drivers/input/mouse/touchkit_ps2.h24
-rw-r--r--drivers/input/mouse/trackpoint.h9
-rw-r--r--drivers/input/mouse/vsxxxaa.c3
-rw-r--r--drivers/input/mousedev.c442
-rw-r--r--drivers/input/power.c166
-rw-r--r--drivers/input/serio/hil_mlc.c505
-rw-r--r--drivers/input/serio/hp_sdc.c427
-rw-r--r--drivers/input/serio/hp_sdc_mlc.c227
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h24
-rw-r--r--drivers/input/serio/i8042.c42
-rw-r--r--drivers/input/tablet/Kconfig74
-rw-r--r--drivers/input/tablet/Makefile12
-rw-r--r--drivers/input/tablet/acecad.c (renamed from drivers/usb/input/acecad.c)30
-rw-r--r--drivers/input/tablet/aiptek.c (renamed from drivers/usb/input/aiptek.c)38
-rw-r--r--drivers/input/tablet/gtco.c (renamed from drivers/usb/input/gtco.c)634
-rw-r--r--drivers/input/tablet/kbtab.c (renamed from drivers/usb/input/kbtab.c)24
-rw-r--r--drivers/input/tablet/wacom.h (renamed from drivers/usb/input/wacom.h)2
-rw-r--r--drivers/input/tablet/wacom_sys.c (renamed from drivers/usb/input/wacom_sys.c)24
-rw-r--r--drivers/input/tablet/wacom_wac.c (renamed from drivers/usb/input/wacom_wac.c)2
-rw-r--r--drivers/input/tablet/wacom_wac.h (renamed from drivers/usb/input/wacom_wac.h)4
-rw-r--r--drivers/input/touchscreen/Kconfig60
-rw-r--r--drivers/input/touchscreen/Makefile17
-rw-r--r--drivers/input/touchscreen/ads7846.c30
-rw-r--r--drivers/input/touchscreen/corgi_ts.c3
-rw-r--r--drivers/input/touchscreen/elo.c3
-rw-r--r--drivers/input/touchscreen/gunze.c2
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c9
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c2
-rw-r--r--drivers/input/touchscreen/mtouch.c2
-rw-r--r--drivers/input/touchscreen/penmount.c3
-rw-r--r--drivers/input/touchscreen/touchright.c2
-rw-r--r--drivers/input/touchscreen/touchwin.c2
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c26
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c (renamed from drivers/usb/input/usbtouchscreen.c)15
-rw-r--r--drivers/input/tsdev.c178
-rw-r--r--drivers/isdn/capi/Kconfig2
-rw-r--r--drivers/isdn/capi/capi.c34
-rw-r--r--drivers/isdn/capi/capiutil.c8
-rw-r--r--drivers/isdn/divert/divert_procfs.c1
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c14
-rw-r--r--drivers/isdn/hardware/eicon/capimain.c1
-rw-r--r--drivers/isdn/hardware/eicon/dbgioctl.h198
-rw-r--r--drivers/isdn/hardware/eicon/divamnt.c1
-rw-r--r--drivers/isdn/hardware/eicon/divasi.c1
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c1
-rw-r--r--drivers/isdn/hardware/eicon/divasync.h2
-rw-r--r--drivers/isdn/hardware/eicon/main_if.h50
-rw-r--r--drivers/isdn/hardware/eicon/platform.h1
-rw-r--r--drivers/isdn/hisax/hfc_usb.c5
-rw-r--r--drivers/isdn/hisax/netjet.c1
-rw-r--r--drivers/isdn/hysdn/boardergo.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c5
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c2
-rw-r--r--drivers/kvm/kvm.h100
-rw-r--r--drivers/kvm/kvm_main.c795
-rw-r--r--drivers/kvm/kvm_svm.h13
-rw-r--r--drivers/kvm/kvm_vmx.h14
-rw-r--r--drivers/kvm/mmu.c154
-rw-r--r--drivers/kvm/paging_tmpl.h12
-rw-r--r--drivers/kvm/svm.c197
-rw-r--r--drivers/kvm/svm.h6
-rw-r--r--drivers/kvm/vmx.c273
-rw-r--r--drivers/kvm/x86_emulate.c51
-rw-r--r--drivers/kvm/x86_emulate.h32
-rw-r--r--drivers/leds/leds-h1940.c2
-rw-r--r--drivers/macintosh/Kconfig14
-rw-r--r--drivers/macintosh/adb.c42
-rw-r--r--drivers/macintosh/ans-lcd.c9
-rw-r--r--drivers/macintosh/apm_emu.c526
-rw-r--r--drivers/macintosh/mac_hid.c10
-rw-r--r--drivers/macintosh/macio-adb.c16
-rw-r--r--drivers/macintosh/macio_asic.c100
-rw-r--r--drivers/macintosh/macio_sysfs.c27
-rw-r--r--drivers/macintosh/rack-meter.c2
-rw-r--r--drivers/macintosh/smu.c10
-rw-r--r--drivers/macintosh/therm_adt746x.c13
-rw-r--r--drivers/macintosh/therm_pm72.c9
-rw-r--r--drivers/macintosh/therm_windtunnel.c5
-rw-r--r--drivers/macintosh/via-cuda.c60
-rw-r--r--drivers/macintosh/via-macii.c582
-rw-r--r--drivers/macintosh/via-pmu-led.c43
-rw-r--r--drivers/macintosh/via-pmu.c67
-rw-r--r--drivers/macintosh/via-pmu68k.c3
-rw-r--r--drivers/macintosh/windfarm_core.c1
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c6
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c4
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c10
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c10
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c6
-rw-r--r--drivers/mca/mca-bus.c28
-rw-r--r--drivers/mca/mca-driver.c13
-rw-r--r--drivers/md/Kconfig9
-rw-r--r--drivers/md/Makefile1
-rw-r--r--drivers/md/bitmap.c8
-rw-r--r--drivers/md/dm-bio-list.h26
-rw-r--r--drivers/md/dm-crypt.c93
-rw-r--r--drivers/md/dm-delay.c383
-rw-r--r--drivers/md/dm-exception-store.c54
-rw-r--r--drivers/md/dm-hw-handler.h1
-rw-r--r--drivers/md/dm-io.c232
-rw-r--r--drivers/md/dm-io.h83
-rw-r--r--drivers/md/dm-log.c77
-rw-r--r--drivers/md/dm-mpath.c3
-rw-r--r--drivers/md/dm-raid1.c187
-rw-r--r--drivers/md/dm-table.c10
-rw-r--r--drivers/md/dm.c3
-rw-r--r--drivers/md/kcopyd.c28
-rw-r--r--drivers/md/md.c188
-rw-r--r--drivers/md/raid1.c1
-rw-r--r--drivers/md/raid5.c6
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c3
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h1
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c2
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c2
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c4
-rw-r--r--drivers/media/dvb/frontends/tda10021.c2
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c1
-rw-r--r--drivers/media/radio/dsbr100.c1
-rw-r--r--drivers/media/video/Kconfig6
-rw-r--r--drivers/media/video/adv7170.c1
-rw-r--r--drivers/media/video/adv7175.c1
-rw-r--r--drivers/media/video/bt819.c1
-rw-r--r--drivers/media/video/bt856.c1
-rw-r--r--drivers/media/video/bt866.c1
-rw-r--r--drivers/media/video/cpia.h1
-rw-r--r--drivers/media/video/cpia_pp.c1
-rw-r--r--drivers/media/video/cx2341x.c1
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c2
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c1
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c2
-rw-r--r--drivers/media/video/cx88/cx88-video.c2
-rw-r--r--drivers/media/video/dabusb.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/video/meye.c62
-rw-r--r--drivers/media/video/meye.h2
-rw-r--r--drivers/media/video/ov511.h1
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_priv.h1
-rw-r--r--drivers/media/video/planb.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c1
-rw-r--r--drivers/media/video/pwc/philips.txt6
-rw-r--r--drivers/media/video/saa7111.c1
-rw-r--r--drivers/media/video/saa7114.c1
-rw-r--r--drivers/media/video/saa711x.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c1
-rw-r--r--drivers/media/video/saa7185.c1
-rw-r--r--drivers/media/video/se401.h1
-rw-r--r--drivers/media/video/tvaudio.c1
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c1
-rw-r--r--drivers/media/video/usbvideo/vicam.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c1
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c1
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c1
-rw-r--r--drivers/media/video/v4l1-compat.c1
-rw-r--r--drivers/media/video/v4l2-common.c1
-rw-r--r--drivers/media/video/videodev.c1
-rw-r--r--drivers/media/video/zoran_driver.c2
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt2
-rw-r--r--drivers/message/fusion/mptbase.c29
-rw-r--r--drivers/message/fusion/mptbase.h1
-rw-r--r--drivers/message/fusion/mptscsih.c35
-rw-r--r--drivers/message/fusion/mptspi.c36
-rw-r--r--drivers/message/i2o/i2o_lan.h159
-rw-r--r--drivers/mfd/ucb1x00-ts.c1
-rw-r--r--drivers/misc/Kconfig84
-rw-r--r--drivers/misc/Makefile3
-rw-r--r--drivers/misc/asus-laptop.c151
-rw-r--r--drivers/misc/blink.c27
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c1
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c1
-rw-r--r--drivers/misc/phantom.c463
-rw-r--r--drivers/misc/sony-laptop.c2131
-rw-r--r--drivers/misc/thinkpad_acpi.c4312
-rw-r--r--drivers/misc/thinkpad_acpi.h572
-rw-r--r--drivers/misc/tifm_7xx1.c353
-rw-r--r--drivers/misc/tifm_core.c305
-rw-r--r--drivers/mmc/Kconfig114
-rw-r--r--drivers/mmc/Makefile33
-rw-r--r--drivers/mmc/card/Kconfig16
-rw-r--r--drivers/mmc/card/Makefile11
-rw-r--r--drivers/mmc/card/block.c (renamed from drivers/mmc/mmc_block.c)55
-rw-r--r--drivers/mmc/card/queue.c (renamed from drivers/mmc/mmc_queue.c)12
-rw-r--r--drivers/mmc/card/queue.h (renamed from drivers/mmc/mmc_queue.h)0
-rw-r--r--drivers/mmc/core/Kconfig16
-rw-r--r--drivers/mmc/core/Makefile11
-rw-r--r--drivers/mmc/core/core.c729
-rw-r--r--drivers/mmc/core/core.h70
-rw-r--r--drivers/mmc/core/mmc.c537
-rw-r--r--drivers/mmc/core/mmc_ops.c276
-rw-r--r--drivers/mmc/core/mmc_ops.h27
-rw-r--r--drivers/mmc/core/sd.c587
-rw-r--r--drivers/mmc/core/sd_ops.c316
-rw-r--r--drivers/mmc/core/sd_ops.h25
-rw-r--r--drivers/mmc/core/sysfs.c (renamed from drivers/mmc/mmc_sysfs.c)11
-rw-r--r--drivers/mmc/core/sysfs.h (renamed from drivers/mmc/mmc.h)10
-rw-r--r--drivers/mmc/host/Kconfig102
-rw-r--r--drivers/mmc/host/Makefile18
-rw-r--r--drivers/mmc/host/at91_mci.c (renamed from drivers/mmc/at91_mci.c)1
-rw-r--r--drivers/mmc/host/au1xmmc.c (renamed from drivers/mmc/au1xmmc.c)1
-rw-r--r--drivers/mmc/host/au1xmmc.h (renamed from drivers/mmc/au1xmmc.h)0
-rw-r--r--drivers/mmc/host/imxmmc.c (renamed from drivers/mmc/imxmmc.c)1
-rw-r--r--drivers/mmc/host/imxmmc.h (renamed from drivers/mmc/imxmmc.h)0
-rw-r--r--drivers/mmc/host/mmci.c (renamed from drivers/mmc/mmci.c)1
-rw-r--r--drivers/mmc/host/mmci.h (renamed from drivers/mmc/mmci.h)0
-rw-r--r--drivers/mmc/host/omap.c (renamed from drivers/mmc/omap.c)56
-rw-r--r--drivers/mmc/host/pxamci.c (renamed from drivers/mmc/pxamci.c)5
-rw-r--r--drivers/mmc/host/pxamci.h (renamed from drivers/mmc/pxamci.h)0
-rw-r--r--drivers/mmc/host/sdhci.c (renamed from drivers/mmc/sdhci.c)43
-rw-r--r--drivers/mmc/host/sdhci.h (renamed from drivers/mmc/sdhci.h)4
-rw-r--r--drivers/mmc/host/tifm_sd.c1091
-rw-r--r--drivers/mmc/host/wbsd.c (renamed from drivers/mmc/wbsd.c)205
-rw-r--r--drivers/mmc/host/wbsd.h (renamed from drivers/mmc/wbsd.h)9
-rw-r--r--drivers/mmc/mmc.c1724
-rw-r--r--drivers/mmc/tifm_sd.c987
-rw-r--r--drivers/mtd/devices/Kconfig4
-rw-r--r--drivers/mtd/devices/block2mtd.c6
-rw-r--r--drivers/mtd/devices/doc2000.c1
-rw-r--r--drivers/mtd/devices/doc2001.c1
-rw-r--r--drivers/mtd/devices/doc2001plus.c1
-rw-r--r--drivers/mtd/devices/docecc.c1
-rw-r--r--drivers/mtd/inftlmount.c1
-rw-r--r--drivers/mtd/maps/Kconfig2
-rw-r--r--drivers/mtd/maps/nettel.c2
-rw-r--r--drivers/mtd/maps/physmap_of.c8
-rw-r--r--drivers/mtd/mtd_blkdevs.c4
-rw-r--r--drivers/mtd/nand/cs553x_nand.c1
-rw-r--r--drivers/mtd/nftlcore.c1
-rw-r--r--drivers/mtd/onenand/onenand_base.c2
-rw-r--r--drivers/mtd/ubi/eba.c3
-rw-r--r--drivers/net/3c509.c6
-rw-r--r--drivers/net/3c59x.c2
-rw-r--r--drivers/net/7990.c6
-rw-r--r--drivers/net/Kconfig46
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/Space.c4
-rw-r--r--drivers/net/a2065.c8
-rw-r--r--drivers/net/ariadne.c1
-rw-r--r--drivers/net/arm/at91_ether.c49
-rw-r--r--drivers/net/arm/at91_ether.h49
-rw-r--r--drivers/net/atl1/atl1_ethtool.c19
-rw-r--r--drivers/net/atl1/atl1_hw.c44
-rw-r--r--drivers/net/atl1/atl1_main.c83
-rw-r--r--drivers/net/atl1/atl1_param.c33
-rw-r--r--drivers/net/atp.c8
-rw-r--r--drivers/net/au1000_eth.c1
-rw-r--r--drivers/net/bmac.c5
-rw-r--r--drivers/net/bnx2.c974
-rw-r--r--drivers/net/bnx2.h65
-rw-r--r--drivers/net/bnx2_fw.h1697
-rw-r--r--drivers/net/bnx2_fw2.h7868
-rw-r--r--drivers/net/bonding/bond_main.c61
-rw-r--r--drivers/net/chelsio/Makefile4
-rw-r--r--drivers/net/chelsio/common.h6
-rw-r--r--drivers/net/chelsio/cphy.h16
-rw-r--r--drivers/net/chelsio/gmac.h10
-rw-r--r--drivers/net/chelsio/ixf1010.c505
-rw-r--r--drivers/net/chelsio/mac.c2
-rw-r--r--drivers/net/chelsio/mv88e1xxx.c8
-rw-r--r--drivers/net/chelsio/mv88x201x.c8
-rw-r--r--drivers/net/chelsio/my3126.c8
-rw-r--r--drivers/net/chelsio/pm3393.c8
-rw-r--r--drivers/net/chelsio/subr.c199
-rw-r--r--drivers/net/chelsio/vsc7326.c2
-rw-r--r--drivers/net/chelsio/vsc8244.c367
-rw-r--r--drivers/net/chelsio/vsc8244_reg.h172
-rw-r--r--drivers/net/cxgb3/version.h4
-rw-r--r--drivers/net/dm9000.c15
-rw-r--r--drivers/net/e100.c159
-rw-r--r--drivers/net/e1000/e1000.h3
-rw-r--r--drivers/net/e1000/e1000_ethtool.c34
-rw-r--r--drivers/net/e1000/e1000_main.c47
-rw-r--r--drivers/net/e1000/e1000_param.c4
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/eexpress.c9
-rw-r--r--drivers/net/ehea/ehea.h42
-rw-r--r--drivers/net/ehea/ehea_ethtool.c115
-rw-r--r--drivers/net/ehea/ehea_main.c943
-rw-r--r--drivers/net/ehea/ehea_phyp.c6
-rw-r--r--drivers/net/ehea/ehea_phyp.h6
-rw-r--r--drivers/net/ehea/ehea_qmr.c184
-rw-r--r--drivers/net/ehea/ehea_qmr.h16
-rw-r--r--drivers/net/epic100.c10
-rw-r--r--drivers/net/fec_8xx/fec_main.c1
-rw-r--r--drivers/net/fec_8xx/fec_mii.c1
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c1
-rw-r--r--drivers/net/fs_enet/mac-fcc.c1
-rw-r--r--drivers/net/fs_enet/mac-fec.c1
-rw-r--r--drivers/net/fs_enet/mac-scc.c1
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c1
-rw-r--r--drivers/net/fs_enet/mii-fec.c1
-rw-r--r--drivers/net/hamradio/Kconfig2
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c13
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c1
-rw-r--r--drivers/net/ibmveth.c10
-rw-r--r--drivers/net/irda/donauboe.h2
-rw-r--r--drivers/net/irda/pxaficp_ir.c12
-rw-r--r--drivers/net/irda/sir_dev.c1
-rw-r--r--drivers/net/irda/sir_dongle.c1
-rw-r--r--drivers/net/irda/smsc-ircc2.c112
-rw-r--r--drivers/net/irda/vlsi_ir.c1
-rw-r--r--drivers/net/ixgb/ixgb.h3
-rw-r--r--drivers/net/ixgb/ixgb_ee.c2
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c4
-rw-r--r--drivers/net/ixgb/ixgb_main.c4
-rw-r--r--drivers/net/ixgb/ixgb_osdep.h1
-rw-r--r--drivers/net/ixgb/ixgb_param.c8
-rw-r--r--drivers/net/jazzsonic.c27
-rw-r--r--drivers/net/lasi_82596.c1
-rw-r--r--drivers/net/mac8390.c245
-rw-r--r--drivers/net/mac89x0.c88
-rw-r--r--drivers/net/mace.c4
-rw-r--r--drivers/net/macmace.c591
-rw-r--r--drivers/net/macsonic.c65
-rw-r--r--drivers/net/meth.h2
-rw-r--r--drivers/net/mii.c57
-rw-r--r--drivers/net/mipsnet.c53
-rw-r--r--drivers/net/mv643xx_eth.c59
-rw-r--r--drivers/net/mv643xx_eth.h4
-rw-r--r--drivers/net/myri10ge/myri10ge.c261
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h20
-rw-r--r--drivers/net/natsemi.c71
-rw-r--r--drivers/net/ne.c123
-rw-r--r--drivers/net/ne2k-pci.c3
-rw-r--r--drivers/net/netxen/netxen_nic.h189
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c212
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h12
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c401
-rw-r--r--drivers/net/netxen/netxen_nic_hw.h85
-rw-r--r--drivers/net/netxen/netxen_nic_init.c130
-rw-r--r--drivers/net/netxen/netxen_nic_isr.c101
-rw-r--r--drivers/net/netxen/netxen_nic_main.c769
-rw-r--r--drivers/net/netxen/netxen_nic_niu.c168
-rw-r--r--drivers/net/netxen/netxen_nic_phan_reg.h134
-rw-r--r--drivers/net/ns83820.c1
-rw-r--r--drivers/net/pasemi_mac.c404
-rw-r--r--drivers/net/pasemi_mac.h23
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c14
-rw-r--r--drivers/net/pcnet32.c159
-rw-r--r--drivers/net/phy/mdio_bus.c19
-rw-r--r--drivers/net/phy/phy.c200
-rw-r--r--drivers/net/phy/phy_device.c114
-rw-r--r--drivers/net/ppp_generic.c1
-rw-r--r--drivers/net/pppox.c8
-rwxr-xr-xdrivers/net/qla3xxx.c371
-rwxr-xr-xdrivers/net/qla3xxx.h33
-rw-r--r--drivers/net/s2io-regs.h2
-rw-r--r--drivers/net/s2io.c78
-rw-r--r--drivers/net/s2io.h8
-rw-r--r--drivers/net/sb1250-mac.c294
-rw-r--r--drivers/net/sgiseeq.c28
-rw-r--r--drivers/net/sis900.c9
-rw-r--r--drivers/net/sk98lin/skge.c20
-rw-r--r--drivers/net/skfp/h/lnkstat.h84
-rw-r--r--drivers/net/skge.c39
-rw-r--r--drivers/net/skge.h10
-rw-r--r--drivers/net/sky2.c17
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/net/smc91x.h81
-rw-r--r--drivers/net/sonic.c32
-rw-r--r--drivers/net/spider_net.c4
-rw-r--r--drivers/net/sun3_82586.c5
-rw-r--r--drivers/net/sundance.c3
-rw-r--r--drivers/net/sungem.c2
-rw-r--r--drivers/net/sungem_phy.c2
-rw-r--r--drivers/net/tc35815.c2553
-rw-r--r--drivers/net/tg3.c218
-rw-r--r--drivers/net/tg3.h18
-rw-r--r--drivers/net/tokenring/madgemc.c1
-rw-r--r--drivers/net/tokenring/smctr.c1
-rw-r--r--drivers/net/tsi108_eth.c12
-rw-r--r--drivers/net/tsi108_eth.h9
-rw-r--r--drivers/net/tulip/21142.c1
-rw-r--r--drivers/net/tulip/dmfe.c118
-rw-r--r--drivers/net/tulip/interrupt.c6
-rw-r--r--drivers/net/tulip/media.c40
-rw-r--r--drivers/net/tulip/pnic.c1
-rw-r--r--drivers/net/tulip/pnic2.c1
-rw-r--r--drivers/net/tulip/timer.c1
-rw-r--r--drivers/net/tulip/tulip.h10
-rw-r--r--drivers/net/tulip/tulip_core.c6
-rw-r--r--drivers/net/tulip/winbond-840.c4
-rw-r--r--drivers/net/tulip/xircom_cb.c2
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/ucc_geth.c956
-rw-r--r--drivers/net/ucc_geth.h114
-rw-r--r--drivers/net/ucc_geth_mii.c279
-rw-r--r--drivers/net/ucc_geth_mii.h100
-rw-r--r--drivers/net/ucc_geth_phy.c785
-rw-r--r--drivers/net/ucc_geth_phy.h217
-rw-r--r--drivers/net/wan/cosa.c1
-rw-r--r--drivers/net/wan/hdlc_cisco.c29
-rw-r--r--drivers/net/wan/hdlc_fr.c18
-rw-r--r--drivers/net/wan/lmc/lmc_media.c1
-rw-r--r--drivers/net/wan/lmc/lmc_proto.c1
-rw-r--r--drivers/net/wan/pc300_tty.c1
-rw-r--r--drivers/net/wireless/Kconfig25
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/README25
-rw-r--r--drivers/net/wireless/airo.c71
-rw-r--r--drivers/net/wireless/airport.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h3
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c23
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.h4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c196
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h4
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c9
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c2
-rw-r--r--drivers/net/wireless/ipw2100.c4
-rw-r--r--drivers/net/wireless/ipw2200.c47
-rw-r--r--drivers/net/wireless/libertas/11d.c754
-rw-r--r--drivers/net/wireless/libertas/11d.h105
-rw-r--r--drivers/net/wireless/libertas/LICENSE16
-rw-r--r--drivers/net/wireless/libertas/Makefile21
-rw-r--r--drivers/net/wireless/libertas/README1044
-rw-r--r--drivers/net/wireless/libertas/assoc.c588
-rw-r--r--drivers/net/wireless/libertas/assoc.h30
-rw-r--r--drivers/net/wireless/libertas/cmd.c1958
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c1031
-rw-r--r--drivers/net/wireless/libertas/debugfs.c1935
-rw-r--r--drivers/net/wireless/libertas/debugfs.h6
-rw-r--r--drivers/net/wireless/libertas/decl.h83
-rw-r--r--drivers/net/wireless/libertas/defs.h369
-rw-r--r--drivers/net/wireless/libertas/dev.h403
-rw-r--r--drivers/net/wireless/libertas/ethtool.c184
-rw-r--r--drivers/net/wireless/libertas/fw.c361
-rw-r--r--drivers/net/wireless/libertas/fw.h13
-rw-r--r--drivers/net/wireless/libertas/host.h338
-rw-r--r--drivers/net/wireless/libertas/hostcmd.h693
-rw-r--r--drivers/net/wireless/libertas/if_bootcmd.c38
-rw-r--r--drivers/net/wireless/libertas/if_usb.c952
-rw-r--r--drivers/net/wireless/libertas/if_usb.h109
-rw-r--r--drivers/net/wireless/libertas/ioctl.c2500
-rw-r--r--drivers/net/wireless/libertas/join.c1055
-rw-r--r--drivers/net/wireless/libertas/join.h64
-rw-r--r--drivers/net/wireless/libertas/main.c1258
-rw-r--r--drivers/net/wireless/libertas/radiotap.h57
-rw-r--r--drivers/net/wireless/libertas/rx.c459
-rw-r--r--drivers/net/wireless/libertas/sbi.h40
-rw-r--r--drivers/net/wireless/libertas/scan.c2044
-rw-r--r--drivers/net/wireless/libertas/scan.h216
-rw-r--r--drivers/net/wireless/libertas/thread.h52
-rw-r--r--drivers/net/wireless/libertas/tx.c285
-rw-r--r--drivers/net/wireless/libertas/types.h289
-rw-r--r--drivers/net/wireless/libertas/version.h8
-rw-r--r--drivers/net/wireless/libertas/wext.c2769
-rw-r--r--drivers/net/wireless/libertas/wext.h147
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c2
-rw-r--r--drivers/net/wireless/strip.c4
-rw-r--r--drivers/net/wireless/todo.txt15
-rw-r--r--drivers/net/wireless/wavelan_cs.c4
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c47
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c23
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c18
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h11
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c91
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c317
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c24
-rw-r--r--drivers/net/yellowfin.c1
-rw-r--r--drivers/parisc/hppb.c2
-rw-r--r--drivers/parisc/lba_pci.c1
-rw-r--r--drivers/parisc/led.c4
-rw-r--r--drivers/parisc/pdc_stable.c94
-rw-r--r--drivers/parport/parport_cs.c2
-rw-r--r--drivers/parport/parport_mfc3.c1
-rw-r--r--drivers/parport/parport_pc.c70
-rw-r--r--drivers/parport/parport_serial.c10
-rw-r--r--drivers/parport/parport_sunbpp.c1
-rw-r--r--drivers/parport/share.c5
-rw-r--r--drivers/pci/Kconfig31
-rw-r--r--drivers/pci/bus.c4
-rw-r--r--drivers/pci/hotplug/Kconfig25
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c1
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c1
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c4
-rw-r--r--drivers/pci/hotplug/cpcihp_zt5550.c6
-rw-r--r--drivers/pci/hotplug/fakephp.c2
-rw-r--r--drivers/pci/hotplug/ibmphp_core.c1
-rw-r--r--drivers/pci/hotplug/ibmphp_hpc.c1
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c5
-rw-r--r--drivers/pci/hotplug/pciehp.h19
-rw-r--r--drivers/pci/hotplug/pciehp_core.c82
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c616
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c34
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c27
-rw-r--r--drivers/pci/hotplug/rpaphp.h8
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c211
-rw-r--r--drivers/pci/hotplug/rpaphp_pci.c167
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c49
-rw-r--r--drivers/pci/hotplug/shpchp.h2
-rw-r--r--drivers/pci/hotplug/shpchp_core.c2
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c3
-rw-r--r--drivers/pci/msi.c399
-rw-r--r--drivers/pci/pci-acpi.c4
-rw-r--r--drivers/pci/pci-driver.c21
-rw-r--r--drivers/pci/pci-sysfs.c9
-rw-r--r--drivers/pci/pci.c34
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c42
-rw-r--r--drivers/pci/proc.c1
-rw-r--r--drivers/pci/quirks.c115
-rw-r--r--drivers/pci/search.c3
-rw-r--r--drivers/pci/setup-bus.c21
-rw-r--r--drivers/pci/setup-res.c6
-rw-r--r--drivers/pcmcia/at91_cf.c3
-rw-r--r--drivers/pcmcia/cs.c1
-rw-r--r--drivers/pcmcia/ds.c113
-rw-r--r--drivers/pcmcia/pxa2xx_mainstone.c1
-rw-r--r--drivers/pcmcia/pxa2xx_sharpsl.c1
-rw-r--r--drivers/pcmcia/socket_sysfs.c1
-rw-r--r--drivers/pnp/core.c11
-rw-r--r--drivers/pnp/pnpacpi/core.c55
-rw-r--r--drivers/pnp/pnpbios/core.c17
-rw-r--r--drivers/pnp/quirks.c30
-rw-r--r--drivers/ps3/ps3av.c108
-rw-r--r--drivers/ps3/ps3av_cmd.c20
-rw-r--r--drivers/ps3/vuart.c16
-rw-r--r--drivers/rtc/Kconfig274
-rw-r--r--drivers/rtc/Makefile9
-rw-r--r--drivers/rtc/class.c118
-rw-r--r--drivers/rtc/hctosys.c14
-rw-r--r--drivers/rtc/interface.c86
-rw-r--r--drivers/rtc/rtc-at91rm9200.c32
-rw-r--r--drivers/rtc/rtc-bfin.c445
-rw-r--r--drivers/rtc/rtc-cmos.c79
-rw-r--r--drivers/rtc/rtc-core.h70
-rw-r--r--drivers/rtc/rtc-dev.c184
-rw-r--r--drivers/rtc/rtc-ds1553.c2
-rw-r--r--drivers/rtc/rtc-lib.c81
-rw-r--r--drivers/rtc/rtc-max6900.c311
-rw-r--r--drivers/rtc/rtc-omap.c57
-rw-r--r--drivers/rtc/rtc-pl031.c2
-rw-r--r--drivers/rtc/rtc-proc.c68
-rw-r--r--drivers/rtc/rtc-rs5c313.c405
-rw-r--r--drivers/rtc/rtc-s3c.c26
-rw-r--r--drivers/rtc/rtc-sa1100.c4
-rw-r--r--drivers/rtc/rtc-sh.c8
-rw-r--r--drivers/rtc/rtc-sysfs.c129
-rw-r--r--drivers/rtc/rtc-test.c6
-rw-r--r--drivers/rtc/rtc-vr41xx.c32
-rw-r--r--drivers/s390/block/dasd.c45
-rw-r--r--drivers/s390/block/dasd_eckd.c81
-rw-r--r--drivers/s390/block/dasd_fba.c2
-rw-r--r--drivers/s390/block/dasd_int.h2
-rw-r--r--drivers/s390/char/sclp_rw.c2
-rw-r--r--drivers/s390/char/tape.h1
-rw-r--r--drivers/s390/char/tape_3590.c29
-rw-r--r--drivers/s390/char/tape_3590.h4
-rw-r--r--drivers/s390/char/tape_core.c3
-rw-r--r--drivers/s390/cio/qdio.c277
-rw-r--r--drivers/s390/cio/qdio.h56
-rw-r--r--drivers/s390/net/netiucv.c5
-rw-r--r--drivers/s390/net/qeth.h3
-rw-r--r--drivers/s390/net/qeth_eddp.c4
-rw-r--r--drivers/s390/net/qeth_eddp.h3
-rw-r--r--drivers/s390/net/qeth_main.c124
-rw-r--r--drivers/s390/net/qeth_mpc.c101
-rw-r--r--drivers/s390/net/qeth_mpc.h220
-rw-r--r--drivers/s390/net/qeth_sys.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c90
-rw-r--r--drivers/s390/scsi/zfcp_def.h41
-rw-r--r--drivers/s390/scsi/zfcp_erp.c91
-rw-r--r--drivers/s390/scsi/zfcp_ext.h4
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c60
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c51
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c9
-rw-r--r--drivers/sbus/char/bpp.c3
-rw-r--r--drivers/sbus/char/rtc.c1
-rw-r--r--drivers/sbus/char/vfc_dev.c1
-rw-r--r--drivers/sbus/sbus.c1
-rw-r--r--drivers/scsi/BusLogic.c73
-rw-r--r--drivers/scsi/Kconfig28
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/aacraid/aachba.c402
-rw-r--r--drivers/scsi/aacraid/aacraid.h76
-rw-r--r--drivers/scsi/aacraid/commctrl.c286
-rw-r--r--drivers/scsi/aacraid/comminit.c7
-rw-r--r--drivers/scsi/aacraid/commsup.c118
-rw-r--r--drivers/scsi/aacraid/dpcsup.c42
-rw-r--r--drivers/scsi/aacraid/linit.c65
-rw-r--r--drivers/scsi/aacraid/nark.c3
-rw-r--r--drivers/scsi/aacraid/rkt.c3
-rw-r--r--drivers/scsi/aacraid/rx.c117
-rw-r--r--drivers/scsi/aacraid/sa.c1
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx12
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx10
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c6
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx.h5
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h1
-rw-r--r--drivers/scsi/aic94xx/Makefile2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c1
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c1
-rw-r--r--drivers/scsi/atari_NCR5380.c4398
-rw-r--r--drivers/scsi/atari_scsi.c377
-rw-r--r--drivers/scsi/atari_scsi.h174
-rw-r--r--drivers/scsi/ch.c9
-rw-r--r--drivers/scsi/constants.c274
-rw-r--r--drivers/scsi/dc395x.c6
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h48
-rw-r--r--drivers/scsi/dpt/dpti_ioctl.h2
-rw-r--r--drivers/scsi/dpt/dptsig.h4
-rw-r--r--drivers/scsi/dpt_i2o.c20
-rw-r--r--drivers/scsi/eata_generic.h7
-rw-r--r--drivers/scsi/esp_scsi.c11
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c80
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h2
-rw-r--r--drivers/scsi/ibmvscsi/ibmvstgt.c50
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c7
-rw-r--r--drivers/scsi/ipr.c636
-rw-r--r--drivers/scsi/ipr.h74
-rw-r--r--drivers/scsi/iscsi_tcp.c21
-rw-r--r--drivers/scsi/libiscsi.c29
-rw-r--r--drivers/scsi/libsas/sas_expander.c1
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c36
-rw-r--r--drivers/scsi/libsrp.c13
-rw-r--r--drivers/scsi/lpfc/lpfc.h33
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c212
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h32
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c24
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h28
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c552
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c884
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c518
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c3
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c307
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c109
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c427
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h12
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h6
-rw-r--r--drivers/scsi/mac53c94.c2
-rw-r--r--drivers/scsi/megaraid.c22
-rw-r--r--drivers/scsi/megaraid.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c2
-rw-r--r--drivers/scsi/mesh.c16
-rw-r--r--drivers/scsi/osst.c1
-rw-r--r--drivers/scsi/pci2000.h197
-rw-r--r--drivers/scsi/pcmcia/Kconfig9
-rw-r--r--drivers/scsi/qla1280.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h13
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c207
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c15
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c16
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c13
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c11
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c4
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h9
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c18
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c18
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c19
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c9
-rw-r--r--drivers/scsi/scsi.c47
-rw-r--r--drivers/scsi/scsi_debug.c1
-rw-r--r--drivers/scsi/scsi_error.c20
-rw-r--r--drivers/scsi/scsi_lib.c12
-rw-r--r--drivers/scsi/scsi_scan.c2
-rw-r--r--drivers/scsi/scsi_sysfs.c54
-rw-r--r--drivers/scsi/scsi_tgt_if.c6
-rw-r--r--drivers/scsi/scsi_tgt_lib.c261
-rw-r--r--drivers/scsi/scsi_tgt_priv.h5
-rw-r--r--drivers/scsi/scsi_transport_fc.c160
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c6
-rw-r--r--drivers/scsi/sd.c405
-rw-r--r--drivers/scsi/sg.c14
-rw-r--r--drivers/scsi/sni_53c710.c2
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/st.c1
-rw-r--r--drivers/scsi/sun_esp.c1
-rw-r--r--drivers/scsi/tmscsim.c227
-rw-r--r--drivers/scsi/tmscsim.h12
-rw-r--r--drivers/serial/8250.c125
-rw-r--r--drivers/serial/Kconfig117
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/amba-pl010.c295
-rw-r--r--drivers/serial/atmel_serial.c9
-rw-r--r--drivers/serial/atmel_serial.h3
-rw-r--r--drivers/serial/bfin_5xx.c1012
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c12
-rw-r--r--drivers/serial/crisv10.h136
-rw-r--r--drivers/serial/icom.c1
-rw-r--r--drivers/serial/imx.c268
-rw-r--r--drivers/serial/jsm/jsm_neo.c7
-rw-r--r--drivers/serial/jsm/jsm_tty.c1
-rw-r--r--drivers/serial/mpc52xx_uart.c7
-rw-r--r--drivers/serial/mpsc.c25
-rw-r--r--drivers/serial/of_serial.c7
-rw-r--r--drivers/serial/pmac_zilog.c12
-rw-r--r--drivers/serial/pxa.c8
-rw-r--r--drivers/serial/s3c2410.c6
-rw-r--r--drivers/serial/serial_core.c41
-rw-r--r--drivers/serial/serial_txx9.c32
-rw-r--r--drivers/serial/sh-sci.c113
-rw-r--r--drivers/serial/sh-sci.h83
-rw-r--r--drivers/serial/sunsu.c8
-rw-r--r--drivers/spi/Kconfig27
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/atmel_spi.c5
-rw-r--r--drivers/spi/au1550_spi.c974
-rw-r--r--drivers/spi/spi.c33
-rw-r--r--drivers/spi/spi_bfin5xx.c1313
-rw-r--r--drivers/spi/spi_butterfly.c83
-rw-r--r--drivers/spi/spi_s3c24xx.c2
-rw-r--r--drivers/spi/spidev.c584
-rw-r--r--drivers/telephony/ixj.c3
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/Makefile12
-rw-r--r--drivers/usb/atm/usbatm.c3
-rw-r--r--drivers/usb/class/cdc-acm.c1
-rw-r--r--drivers/usb/class/usblp.c1
-rw-r--r--drivers/usb/core/hub.c1
-rw-r--r--drivers/usb/core/inode.c1
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/gadget/at91_udc.c1
-rw-r--r--drivers/usb/gadget/dummy_hcd.c1
-rw-r--r--drivers/usb/gadget/ether.c1
-rw-r--r--drivers/usb/gadget/goku_udc.c1
-rw-r--r--drivers/usb/gadget/net2280.c1
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c4
-rw-r--r--drivers/usb/gadget/serial.c1
-rw-r--r--drivers/usb/gadget/zero.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c1
-rw-r--r--drivers/usb/host/ehci-ps3.c11
-rw-r--r--drivers/usb/host/ohci-hcd.c1
-rw-r--r--drivers/usb/host/ohci-ppc-of.c4
-rw-r--r--drivers/usb/host/ohci-ps3.c12
-rw-r--r--drivers/usb/host/ohci-pxa27x.c4
-rw-r--r--drivers/usb/host/sl811-hcd.c1
-rw-r--r--drivers/usb/host/u132-hcd.c1
-rw-r--r--drivers/usb/image/mdc800.c1
-rw-r--r--drivers/usb/image/microtek.c1
-rw-r--r--drivers/usb/input/Kconfig370
-rw-r--r--drivers/usb/input/Makefile55
-rw-r--r--drivers/usb/input/itmtouch.c271
-rw-r--r--drivers/usb/input/mtouchusb.c332
-rw-r--r--drivers/usb/input/touchkitusb.c392
-rw-r--r--drivers/usb/misc/auerswald.c2
-rw-r--r--drivers/usb/misc/idmouse.c1
-rw-r--r--drivers/usb/misc/legousbtower.c1
-rw-r--r--drivers/usb/misc/rio500.c1
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c3
-rw-r--r--drivers/usb/mon/mon_main.c1
-rw-r--r--drivers/usb/net/kaweth.c1
-rw-r--r--drivers/usb/net/pegasus.c10
-rw-r--r--drivers/usb/net/pegasus.h3
-rw-r--r--drivers/usb/net/usbnet.h2
-rw-r--r--drivers/usb/serial/Kconfig2
-rw-r--r--drivers/usb/serial/aircable.c4
-rw-r--r--drivers/usb/serial/io_edgeport.c4
-rw-r--r--drivers/usb/serial/usb-serial.c1
-rw-r--r--drivers/usb/storage/usb.h1
-rw-r--r--drivers/video/Kconfig196
-rw-r--r--drivers/video/Makefile27
-rw-r--r--drivers/video/arcfb.c28
-rw-r--r--drivers/video/arkfb.c1200
-rw-r--r--drivers/video/atafb.c2801
-rw-r--r--drivers/video/atafb.h36
-rw-r--r--drivers/video/atafb_iplan2p2.c293
-rw-r--r--drivers/video/atafb_iplan2p4.c308
-rw-r--r--drivers/video/atafb_iplan2p8.c345
-rw-r--r--drivers/video/atafb_mfb.c112
-rw-r--r--drivers/video/atafb_utils.h400
-rw-r--r--drivers/video/aty/ati_ids.h2
-rw-r--r--drivers/video/aty/aty128fb.c29
-rw-r--r--drivers/video/aty/atyfb_base.c40
-rw-r--r--drivers/video/aty/mach64_ct.c8
-rw-r--r--drivers/video/aty/mach64_cursor.c1
-rw-r--r--drivers/video/aty/radeon_base.c11
-rw-r--r--drivers/video/aty/radeon_i2c.c1
-rw-r--r--drivers/video/aty/radeon_monitor.c11
-rw-r--r--drivers/video/aty/radeon_pm.c14
-rw-r--r--drivers/video/aty/radeonfb.h4
-rw-r--r--drivers/video/backlight/Kconfig8
-rw-r--r--drivers/video/backlight/Makefile1
-rw-r--r--drivers/video/backlight/cr_bllcd.c287
-rw-r--r--drivers/video/cfbcopyarea.c14
-rw-r--r--drivers/video/cfbfillrect.c68
-rw-r--r--drivers/video/cirrusfb.c69
-rw-r--r--drivers/video/console/fbcon.c136
-rw-r--r--drivers/video/console/fonts.c10
-rw-r--r--drivers/video/console/mdacon.c3
-rw-r--r--drivers/video/console/promcon.c3
-rw-r--r--drivers/video/console/softcursor.c2
-rw-r--r--drivers/video/console/sticon.c2
-rw-r--r--drivers/video/console/sticore.c2
-rw-r--r--drivers/video/console/vgacon.c20
-rw-r--r--drivers/video/controlfb.c16
-rw-r--r--drivers/video/display/Kconfig24
-rw-r--r--drivers/video/display/Makefile6
-rw-r--r--drivers/video/display/display-sysfs.c217
-rw-r--r--drivers/video/epson1355fb.c21
-rw-r--r--drivers/video/fb_defio.c151
-rw-r--r--drivers/video/fb_draw.h72
-rw-r--r--drivers/video/fb_sys_fops.c104
-rw-r--r--drivers/video/fbmem.c131
-rw-r--r--drivers/video/fbmon.c169
-rw-r--r--drivers/video/fbsysfs.c2
-rw-r--r--drivers/video/g364fb.c1
-rw-r--r--drivers/video/hecubafb.c471
-rw-r--r--drivers/video/i810/i810.h2
-rw-r--r--drivers/video/i810/i810_main.c2
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c3
-rw-r--r--drivers/video/intelfb/intelfbhw.c34
-rw-r--r--drivers/video/logo/Kconfig30
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c2
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c2
-rw-r--r--drivers/video/matrox/matroxfb_accel.c2
-rw-r--r--drivers/video/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/matrox/matroxfb_misc.c2
-rw-r--r--drivers/video/modedb.c4
-rw-r--r--drivers/video/neofb.c1
-rw-r--r--drivers/video/nvidia/nv_accel.c76
-rw-r--r--drivers/video/nvidia/nv_hw.c22
-rw-r--r--drivers/video/nvidia/nv_i2c.c94
-rw-r--r--drivers/video/nvidia/nv_local.h4
-rw-r--r--drivers/video/nvidia/nv_of.c8
-rw-r--r--drivers/video/nvidia/nv_setup.c5
-rw-r--r--drivers/video/nvidia/nv_type.h8
-rw-r--r--drivers/video/nvidia/nvidia.c82
-rw-r--r--drivers/video/offb.c32
-rw-r--r--drivers/video/platinumfb.c1
-rw-r--r--drivers/video/pm2fb.c246
-rw-r--r--drivers/video/ps3fb.c128
-rw-r--r--drivers/video/pvr2fb.c4
-rw-r--r--drivers/video/pxafb.c6
-rw-r--r--drivers/video/riva/fbdev.c22
-rw-r--r--drivers/video/riva/nv4ref.h2445
-rw-r--r--drivers/video/riva/nv_driver.c6
-rw-r--r--drivers/video/riva/riva_hw.c12
-rw-r--r--drivers/video/riva/rivafb-i2c.c41
-rw-r--r--drivers/video/riva/rivafb.h2
-rw-r--r--drivers/video/s3fb.c49
-rw-r--r--drivers/video/savage/savagefb-i2c.c22
-rw-r--r--drivers/video/savage/savagefb.h10
-rw-r--r--drivers/video/savage/savagefb_driver.c39
-rw-r--r--drivers/video/sis/osdef.h5
-rw-r--r--drivers/video/sis/sis.h51
-rw-r--r--drivers/video/sis/sis_main.c106
-rw-r--r--drivers/video/skeletonfb.c219
-rw-r--r--drivers/video/sm501fb.c2
-rw-r--r--drivers/video/stifb.c1
-rw-r--r--drivers/video/sunxvr2500.c277
-rw-r--r--drivers/video/sunxvr500.c443
-rw-r--r--drivers/video/svgalib.c55
-rw-r--r--drivers/video/syscopyarea.c378
-rw-r--r--drivers/video/sysfillrect.c334
-rw-r--r--drivers/video/sysimgblt.c291
-rw-r--r--drivers/video/tgafb.c425
-rw-r--r--drivers/video/valkyriefb.c1
-rw-r--r--drivers/video/vermilion/Makefile5
-rw-r--r--drivers/video/vermilion/cr_pll.c208
-rw-r--r--drivers/video/vermilion/vermilion.c1195
-rw-r--r--drivers/video/vermilion/vermilion.h260
-rw-r--r--drivers/video/vfb.c8
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/video/vgastate.c26
-rw-r--r--drivers/video/vt8623fb.c927
-rw-r--r--drivers/video/xilinxfb.c381
-rw-r--r--drivers/w1/masters/Kconfig8
-rw-r--r--drivers/w1/masters/Makefile2
-rw-r--r--drivers/w1/masters/ds1wm.c468
-rw-r--r--drivers/w1/w1.c2
-rw-r--r--drivers/w1/w1_int.c3
-rw-r--r--drivers/zorro/proc.c5
-rw-r--r--drivers/zorro/zorro-sysfs.c3
-rw-r--r--drivers/zorro/zorro.c3
-rw-r--r--fs/9p/vfs_addr.c1
-rw-r--r--fs/9p/vfs_dentry.c1
-rw-r--r--fs/9p/vfs_dir.c1
-rw-r--r--fs/9p/vfs_file.c1
-rw-r--r--fs/9p/vfs_inode.c1
-rw-r--r--fs/9p/vfs_super.c1
-rw-r--r--fs/Kconfig18
-rw-r--r--fs/Kconfig.binfmt2
-rw-r--r--fs/adfs/super.c3
-rw-r--r--fs/affs/file.c6
-rw-r--r--fs/affs/super.c3
-rw-r--r--fs/afs/Makefile5
-rw-r--r--fs/afs/afs_fs.h2
-rw-r--r--fs/afs/callback.c11
-rw-r--r--fs/afs/cmservice.c1
-rw-r--r--fs/afs/dir.c22
-rw-r--r--fs/afs/file.c107
-rw-r--r--fs/afs/fsclient.c368
-rw-r--r--fs/afs/inode.c70
-rw-r--r--fs/afs/internal.h104
-rw-r--r--fs/afs/main.c4
-rw-r--r--fs/afs/misc.c1
-rw-r--r--fs/afs/mntpt.c16
-rw-r--r--fs/afs/netdevices.c68
-rw-r--r--fs/afs/rxrpc.c82
-rw-r--r--fs/afs/security.c12
-rw-r--r--fs/afs/server.c3
-rw-r--r--fs/afs/super.c106
-rw-r--r--fs/afs/use-rtnetlink.c473
-rw-r--r--fs/afs/vlocation.c19
-rw-r--r--fs/afs/vnode.c121
-rw-r--r--fs/afs/write.c835
-rw-r--r--fs/aio.c13
-rw-r--r--fs/attr.c1
-rw-r--r--fs/autofs4/inode.c1
-rw-r--r--fs/autofs4/root.c1
-rw-r--r--fs/bad_inode.c1
-rw-r--r--fs/befs/linuxvfs.c3
-rw-r--r--fs/bfs/inode.c3
-rw-r--r--fs/binfmt_elf.c5
-rw-r--r--fs/binfmt_elf_fdpic.c1
-rw-r--r--fs/binfmt_em86.c1
-rw-r--r--fs/binfmt_misc.c17
-rw-r--r--fs/binfmt_script.c1
-rw-r--r--fs/bio.c44
-rw-r--r--fs/block_dev.c15
-rw-r--r--fs/buffer.c84
-rw-r--r--fs/cifs/CHANGES22
-rw-r--r--fs/cifs/README43
-rw-r--r--fs/cifs/TODO69
-rw-r--r--fs/cifs/cifs_fs_sb.h14
-rw-r--r--fs/cifs/cifs_unicode.c4
-rw-r--r--fs/cifs/cifsfs.c82
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h2
-rw-r--r--fs/cifs/cifspdu.h32
-rw-r--r--fs/cifs/cifsproto.h7
-rw-r--r--fs/cifs/cifssmb.c130
-rw-r--r--fs/cifs/connect.c140
-rw-r--r--fs/cifs/dir.c2
-rw-r--r--fs/cifs/file.c130
-rw-r--r--fs/cifs/inode.c282
-rw-r--r--fs/cifs/netmisc.c24
-rw-r--r--fs/cifs/readdir.c162
-rw-r--r--fs/coda/inode.c3
-rw-r--r--fs/compat.c224
-rw-r--r--fs/compat_ioctl.c1025
-rw-r--r--fs/configfs/file.c33
-rw-r--r--fs/configfs/mount.c2
-rw-r--r--fs/cramfs/inode.c3
-rw-r--r--fs/dcache.c144
-rw-r--r--fs/debugfs/inode.c2
-rw-r--r--fs/devpts/inode.c5
-rw-r--r--fs/direct-io.c10
-rw-r--r--fs/dlm/Kconfig31
-rw-r--r--fs/dlm/Makefile6
-rw-r--r--fs/dlm/ast.c1
-rw-r--r--fs/dlm/config.c10
-rw-r--r--fs/dlm/config.h3
-rw-r--r--fs/dlm/dlm_internal.h11
-rw-r--r--fs/dlm/lock.c955
-rw-r--r--fs/dlm/lock.h2
-rw-r--r--fs/dlm/lockspace.c6
-rw-r--r--fs/dlm/lowcomms-sctp.c1210
-rw-r--r--fs/dlm/lowcomms.c (renamed from fs/dlm/lowcomms-tcp.c)788
-rw-r--r--fs/dlm/user.c163
-rw-r--r--fs/dquot.c10
-rw-r--r--fs/ecryptfs/file.c1
-rw-r--r--fs/ecryptfs/main.c15
-rw-r--r--fs/ecryptfs/mmap.c11
-rw-r--r--fs/efs/super.c3
-rw-r--r--fs/eventpoll.c238
-rw-r--r--fs/exec.c51
-rw-r--r--fs/exportfs/expfs.c1
-rw-r--r--fs/ext2/dir.c4
-rw-r--r--fs/ext2/ext2.h1
-rw-r--r--fs/ext2/fsync.c1
-rw-r--r--fs/ext2/inode.c26
-rw-r--r--fs/ext2/ioctl.c1
-rw-r--r--fs/ext2/super.c3
-rw-r--r--fs/ext2/xattr_security.c1
-rw-r--r--fs/ext2/xattr_trusted.c1
-rw-r--r--fs/ext3/dir.c1
-rw-r--r--fs/ext3/inode.c39
-rw-r--r--fs/ext3/ioctl.c1
-rw-r--r--fs/ext3/namei.c27
-rw-r--r--fs/ext3/resize.c1
-rw-r--r--fs/ext3/super.c7
-rw-r--r--fs/ext3/xattr_security.c1
-rw-r--r--fs/ext3/xattr_trusted.c1
-rw-r--r--fs/ext3/xattr_user.c1
-rw-r--r--fs/ext4/dir.c1
-rw-r--r--fs/ext4/extents.c1
-rw-r--r--fs/ext4/inode.c7
-rw-r--r--fs/ext4/namei.c27
-rw-r--r--fs/ext4/resize.c1
-rw-r--r--fs/ext4/super.c7
-rw-r--r--fs/ext4/xattr_security.c1
-rw-r--r--fs/ext4/xattr_trusted.c1
-rw-r--r--fs/ext4/xattr_user.c1
-rw-r--r--fs/fat/cache.c3
-rw-r--r--fs/fat/dir.c199
-rw-r--r--fs/fat/inode.c24
-rw-r--r--fs/fifo.c1
-rw-r--r--fs/file_table.c1
-rw-r--r--fs/filesystems.c21
-rw-r--r--fs/freevxfs/vxfs_bmap.c2
-rw-r--r--fs/freevxfs/vxfs_inode.c2
-rw-r--r--fs/freevxfs/vxfs_subr.c3
-rw-r--r--fs/fuse/file.c3
-rw-r--r--fs/fuse/inode.c9
-rw-r--r--fs/gfs2/dir.c38
-rw-r--r--fs/gfs2/glock.c619
-rw-r--r--fs/gfs2/glock.h8
-rw-r--r--fs/gfs2/glops.c5
-rw-r--r--fs/gfs2/incore.h14
-rw-r--r--fs/gfs2/locking/dlm/lock.c14
-rw-r--r--fs/gfs2/locking/dlm/lock_dlm.h3
-rw-r--r--fs/gfs2/locking/dlm/plock.c109
-rw-r--r--fs/gfs2/locking/dlm/sysfs.c2
-rw-r--r--fs/gfs2/locking/nolock/main.c9
-rw-r--r--fs/gfs2/lops.c20
-rw-r--r--fs/gfs2/main.c10
-rw-r--r--fs/gfs2/mount.c239
-rw-r--r--fs/gfs2/ops_address.c21
-rw-r--r--fs/gfs2/ops_dentry.c1
-rw-r--r--fs/gfs2/ops_file.c13
-rw-r--r--fs/gfs2/ops_fstype.c4
-rw-r--r--fs/gfs2/ops_super.c28
-rw-r--r--fs/gfs2/rgrp.c12
-rw-r--r--fs/gfs2/sys.c2
-rw-r--r--fs/hfs/btree.c3
-rw-r--r--fs/hfs/super.c2
-rw-r--r--fs/hfsplus/btree.c3
-rw-r--r--fs/hfsplus/super.c2
-rw-r--r--fs/hostfs/hostfs.h15
-rw-r--r--fs/hostfs/hostfs_kern.c192
-rw-r--r--fs/hostfs/hostfs_user.c229
-rw-r--r--fs/hpfs/super.c3
-rw-r--r--fs/hugetlbfs/inode.c20
-rw-r--r--fs/inode.c47
-rw-r--r--fs/inotify.c2
-rw-r--r--fs/internal.h10
-rw-r--r--fs/ioctl.c2
-rw-r--r--fs/isofs/inode.c3
-rw-r--r--fs/jbd/checkpoint.c2
-rw-r--r--fs/jbd/commit.c1
-rw-r--r--fs/jbd/journal.c14
-rw-r--r--fs/jbd/recovery.c2
-rw-r--r--fs/jbd/revoke.c3
-rw-r--r--fs/jbd/transaction.c3
-rw-r--r--fs/jbd2/checkpoint.c2
-rw-r--r--fs/jbd2/commit.c1
-rw-r--r--fs/jbd2/journal.c14
-rw-r--r--fs/jbd2/recovery.c2
-rw-r--r--fs/jbd2/revoke.c3
-rw-r--r--fs/jbd2/transaction.c3
-rw-r--r--fs/jffs2/super.c3
-rw-r--r--fs/jfs/inode.c1
-rw-r--r--fs/jfs/ioctl.c2
-rw-r--r--fs/jfs/jfs_dmap.c2
-rw-r--r--fs/jfs/jfs_imap.c6
-rw-r--r--fs/jfs/jfs_inode.c18
-rw-r--r--fs/jfs/jfs_inode.h1
-rw-r--r--fs/jfs/jfs_lock.h2
-rw-r--r--fs/jfs/jfs_logmgr.c10
-rw-r--r--fs/jfs/jfs_metapage.c3
-rw-r--r--fs/jfs/jfs_txnmgr.c7
-rw-r--r--fs/jfs/super.c3
-rw-r--r--fs/libfs.c28
-rw-r--r--fs/lockd/clntproc.c1
-rw-r--r--fs/lockd/mon.c10
-rw-r--r--fs/lockd/svc4proc.c6
-rw-r--r--fs/lockd/svclock.c275
-rw-r--r--fs/lockd/svcproc.c7
-rw-r--r--fs/lockd/svcsubs.c2
-rw-r--r--fs/lockd/xdr.c20
-rw-r--r--fs/lockd/xdr4.c24
-rw-r--r--fs/locks.c267
-rw-r--r--fs/minix/dir.c1
-rw-r--r--fs/minix/inode.c3
-rw-r--r--fs/mpage.c31
-rw-r--r--fs/namei.c32
-rw-r--r--fs/namespace.c41
-rw-r--r--fs/ncpfs/file.c1
-rw-r--r--fs/ncpfs/inode.c3
-rw-r--r--fs/nfs/client.c4
-rw-r--r--fs/nfs/dir.c25
-rw-r--r--fs/nfs/direct.c6
-rw-r--r--fs/nfs/file.c7
-rw-r--r--fs/nfs/getroot.c1
-rw-r--r--fs/nfs/inode.c3
-rw-r--r--fs/nfs/internal.h12
-rw-r--r--fs/nfs/mount_clnt.c7
-rw-r--r--fs/nfs/nfs2xdr.c7
-rw-r--r--fs/nfs/nfs3proc.c1
-rw-r--r--fs/nfs/nfs3xdr.c13
-rw-r--r--fs/nfs/nfs4proc.c4
-rw-r--r--fs/nfs/nfs4renewd.c1
-rw-r--r--fs/nfs/nfs4xdr.c7
-rw-r--r--fs/nfs/nfsroot.c2
-rw-r--r--fs/nfs/pagelist.c242
-rw-r--r--fs/nfs/proc.c1
-rw-r--r--fs/nfs/read.c92
-rw-r--r--fs/nfs/super.c10
-rw-r--r--fs/nfs/symlink.c7
-rw-r--r--fs/nfs/write.c263
-rw-r--r--fs/nfsd/Makefile1
-rw-r--r--fs/nfsd/export.c14
-rw-r--r--fs/nfsd/nfs3proc.c2
-rw-r--r--fs/nfsd/nfs3xdr.c71
-rw-r--r--fs/nfsd/nfs4acl.c17
-rw-r--r--fs/nfsd/nfs4callback.c7
-rw-r--r--fs/nfsd/nfs4idmap.c1
-rw-r--r--fs/nfsd/nfs4state.c32
-rw-r--r--fs/nfsd/nfs4xdr.c1
-rw-r--r--fs/nfsd/nfsfh.c57
-rw-r--r--fs/nfsd/nfsproc.c2
-rw-r--r--fs/nfsd/nfsxdr.c53
-rw-r--r--fs/ntfs/aops.h3
-rw-r--r--fs/ntfs/attrib.c18
-rw-r--r--fs/ntfs/dir.c1
-rw-r--r--fs/ntfs/file.c24
-rw-r--r--fs/ntfs/inode.c1
-rw-r--r--fs/ntfs/super.c33
-rw-r--r--fs/ocfs2/alloc.c6
-rw-r--r--fs/ocfs2/aops.c11
-rw-r--r--fs/ocfs2/cluster/heartbeat.c2
-rw-r--r--fs/ocfs2/cluster/masklog.c4
-rw-r--r--fs/ocfs2/cluster/masklog.h2
-rw-r--r--fs/ocfs2/cluster/sys.c7
-rw-r--r--fs/ocfs2/cluster/tcp.c10
-rw-r--r--fs/ocfs2/dir.c7
-rw-r--r--fs/ocfs2/dlm/dlmast.c12
-rw-r--r--fs/ocfs2/dlm/dlmfs.c4
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c4
-rw-r--r--fs/ocfs2/dlm/dlmthread.c2
-rw-r--r--fs/ocfs2/dlmglue.c55
-rw-r--r--fs/ocfs2/dlmglue.h7
-rw-r--r--fs/ocfs2/export.c6
-rw-r--r--fs/ocfs2/file.c17
-rw-r--r--fs/ocfs2/file.h5
-rw-r--r--fs/ocfs2/inode.c36
-rw-r--r--fs/ocfs2/inode.h1
-rw-r--r--fs/ocfs2/ioctl.c24
-rw-r--r--fs/ocfs2/ioctl.h1
-rw-r--r--fs/ocfs2/journal.c7
-rw-r--r--fs/ocfs2/namei.c5
-rw-r--r--fs/ocfs2/ocfs2.h12
-rw-r--r--fs/ocfs2/ocfs2_fs.h2
-rw-r--r--fs/ocfs2/slot_map.c1
-rw-r--r--fs/ocfs2/suballoc.c10
-rw-r--r--fs/ocfs2/super.c5
-rw-r--r--fs/ocfs2/symlink.c7
-rw-r--r--fs/ocfs2/vote.c1
-rw-r--r--fs/open.c4
-rw-r--r--fs/openpromfs/inode.c3
-rw-r--r--fs/partitions/Kconfig9
-rw-r--r--fs/partitions/Makefile1
-rw-r--r--fs/partitions/acorn.c2
-rw-r--r--fs/partitions/check.c13
-rw-r--r--fs/partitions/sysv68.c92
-rw-r--r--fs/partitions/sysv68.h1
-rw-r--r--fs/pipe.c18
-rw-r--r--fs/pnode.c2
-rw-r--r--fs/proc/array.c4
-rw-r--r--fs/proc/base.c304
-rw-r--r--fs/proc/generic.c13
-rw-r--r--fs/proc/inode.c17
-rw-r--r--fs/proc/internal.h2
-rw-r--r--fs/proc/proc_devtree.c2
-rw-r--r--fs/proc/proc_misc.c12
-rw-r--r--fs/proc/proc_sysctl.c7
-rw-r--r--fs/proc/proc_tty.c3
-rw-r--r--fs/proc/task_mmu.c151
-rw-r--r--fs/proc/task_nommu.c7
-rw-r--r--fs/proc/vmcore.c2
-rw-r--r--fs/qnx4/inode.c3
-rw-r--r--fs/quota.c1
-rw-r--r--fs/ramfs/file-nommu.c1
-rw-r--r--fs/ramfs/inode.c1
-rw-r--r--fs/read_write.c16
-rw-r--r--fs/readdir.c9
-rw-r--r--fs/reiserfs/dir.c1
-rw-r--r--fs/reiserfs/file.c40
-rw-r--r--fs/reiserfs/inode.c13
-rw-r--r--fs/reiserfs/journal.c6
-rw-r--r--fs/reiserfs/namei.c1
-rw-r--r--fs/reiserfs/procfs.c3
-rw-r--r--fs/reiserfs/resize.c4
-rw-r--r--fs/reiserfs/stree.c1
-rw-r--r--fs/reiserfs/super.c10
-rw-r--r--fs/reiserfs/xattr.c6
-rw-r--r--fs/romfs/inode.c3
-rw-r--r--fs/select.c13
-rw-r--r--fs/smbfs/inode.c3
-rw-r--r--fs/smbfs/request.c7
-rw-r--r--fs/smbfs/smbiod.c3
-rw-r--r--fs/smbfs/sock.c1
-rw-r--r--fs/smbfs/symlink.c1
-rw-r--r--fs/splice.c17
-rw-r--r--fs/stat.c1
-rw-r--r--fs/super.c27
-rw-r--r--fs/sync.c2
-rw-r--r--fs/sysfs/bin.c2
-rw-r--r--fs/sysfs/file.c44
-rw-r--r--fs/sysv/dir.c10
-rw-r--r--fs/sysv/inode.c3
-rw-r--r--fs/sysv/namei.c1
-rw-r--r--fs/udf/balloc.c177
-rw-r--r--fs/udf/dir.c39
-rw-r--r--fs/udf/directory.c30
-rw-r--r--fs/udf/fsync.c1
-rw-r--r--fs/udf/inode.c581
-rw-r--r--fs/udf/misc.c6
-rw-r--r--fs/udf/namei.c226
-rw-r--r--fs/udf/partition.c2
-rw-r--r--fs/udf/super.c79
-rw-r--r--fs/udf/symlink.c2
-rw-r--r--fs/udf/truncate.c206
-rw-r--r--fs/udf/udf_sb.h2
-rw-r--r--fs/udf/udfdecl.h25
-rw-r--r--fs/ufs/dir.c7
-rw-r--r--fs/ufs/super.c3
-rw-r--r--fs/ufs/util.c6
-rw-r--r--fs/utimes.c162
-rw-r--r--fs/xattr.c1
-rw-r--r--fs/xfs/linux-2.6/mrlock.h12
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c89
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c10
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h3
-rw-r--r--fs/xfs/linux-2.6/xfs_fs_subr.c21
-rw-r--r--fs/xfs/linux-2.6/xfs_fs_subr.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c185
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h2
-rw-r--r--fs/xfs/quota/xfs_dquot.c3
-rw-r--r--fs/xfs/quota/xfs_qm.c16
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c19
-rw-r--r--fs/xfs/quota/xfs_trans_dquot.c4
-rw-r--r--fs/xfs/support/debug.c17
-rw-r--r--fs/xfs/support/debug.h2
-rw-r--r--fs/xfs/xfs_alloc.c2
-rw-r--r--fs/xfs/xfs_attr.c12
-rw-r--r--fs/xfs/xfs_attr_leaf.c2
-rw-r--r--fs/xfs/xfs_bmap.c28
-rw-r--r--fs/xfs/xfs_dfrag.c6
-rw-r--r--fs/xfs/xfs_dir2_block.c14
-rw-r--r--fs/xfs/xfs_dir2_data.c7
-rw-r--r--fs/xfs/xfs_dir2_data.h2
-rw-r--r--fs/xfs/xfs_dir2_leaf.c7
-rw-r--r--fs/xfs/xfs_dir2_node.c4
-rw-r--r--fs/xfs/xfs_error.c2
-rw-r--r--fs/xfs/xfs_fsops.c4
-rw-r--r--fs/xfs/xfs_iget.c15
-rw-r--r--fs/xfs/xfs_inode.c58
-rw-r--r--fs/xfs/xfs_inode.h65
-rw-r--r--fs/xfs/xfs_iocore.c2
-rw-r--r--fs/xfs/xfs_iomap.c15
-rw-r--r--fs/xfs/xfs_iomap.h1
-rw-r--r--fs/xfs/xfs_itable.c2
-rw-r--r--fs/xfs/xfs_log_recover.c15
-rw-r--r--fs/xfs/xfs_mount.c5
-rw-r--r--fs/xfs/xfs_qmops.c2
-rw-r--r--fs/xfs/xfs_quota.h3
-rw-r--r--fs/xfs/xfs_rename.c2
-rw-r--r--fs/xfs/xfs_rtalloc.c6
-rw-r--r--fs/xfs/xfs_rw.c4
-rw-r--r--fs/xfs/xfs_trans.c6
-rw-r--r--fs/xfs/xfs_trans.h4
-rw-r--r--fs/xfs/xfs_utils.c11
-rw-r--r--fs/xfs/xfs_vfsops.c6
-rw-r--r--fs/xfs/xfs_vnodeops.c125
-rw-r--r--include/acpi/acpi_bus.h5
-rw-r--r--include/acpi/actbl.h1
-rw-r--r--include/asm-alpha/atomic.h64
-rw-r--r--include/asm-alpha/kdebug.h1
-rw-r--r--include/asm-alpha/local.h126
-rw-r--r--include/asm-alpha/mmu_context.h1
-rw-r--r--include/asm-alpha/percpu.h14
-rw-r--r--include/asm-alpha/pgtable.h4
-rw-r--r--include/asm-alpha/scatterlist.h1
-rw-r--r--include/asm-alpha/smp.h1
-rw-r--r--include/asm-alpha/system.h226
-rw-r--r--include/asm-alpha/thread_info.h22
-rw-r--r--include/asm-arm/arch-at91/at91_adc.h61
-rw-r--r--include/asm-arm/arch-at91/at91rm9200.h181
-rw-r--r--include/asm-arm/arch-at91/at91sam9260.h9
-rw-r--r--include/asm-arm/arch-at91/at91sam9261.h191
-rw-r--r--include/asm-arm/arch-at91/at91sam9263.h8
-rw-r--r--include/asm-arm/arch-at91/board.h12
-rw-r--r--include/asm-arm/arch-at91/cpu.h6
-rw-r--r--include/asm-arm/arch-ebsa110/io.h8
-rw-r--r--include/asm-arm/arch-imx/imx-regs.h120
-rw-r--r--include/asm-arm/arch-imx/mmc.h2
-rw-r--r--include/asm-arm/arch-integrator/platform.h2
-rw-r--r--include/asm-arm/arch-iop13xx/io.h1
-rw-r--r--include/asm-arm/arch-iop13xx/iop13xx.h24
-rw-r--r--include/asm-arm/arch-iop13xx/time.h56
-rw-r--r--include/asm-arm/arch-iop32x/glantank.h2
-rw-r--r--include/asm-arm/arch-iop32x/io.h1
-rw-r--r--include/asm-arm/arch-iop32x/iop32x.h9
-rw-r--r--include/asm-arm/arch-iop32x/memory.h4
-rw-r--r--include/asm-arm/arch-iop32x/n2100.h2
-rw-r--r--include/asm-arm/arch-iop33x/io.h1
-rw-r--r--include/asm-arm/arch-iop33x/iop33x.h10
-rw-r--r--include/asm-arm/arch-iop33x/memory.h4
-rw-r--r--include/asm-arm/arch-ixp23xx/io.h4
-rw-r--r--include/asm-arm/arch-ixp4xx/cpu.h31
-rw-r--r--include/asm-arm/arch-ixp4xx/dma.h1
-rw-r--r--include/asm-arm/arch-ixp4xx/dsmg600.h57
-rw-r--r--include/asm-arm/arch-ixp4xx/entry-macro.S4
-rw-r--r--include/asm-arm/arch-ixp4xx/gpio.h73
-rw-r--r--include/asm-arm/arch-ixp4xx/hardware.h12
-rw-r--r--include/asm-arm/arch-ixp4xx/io.h6
-rw-r--r--include/asm-arm/arch-ixp4xx/irqs.h16
-rw-r--r--include/asm-arm/arch-ixp4xx/ixp4xx-regs.h15
-rw-r--r--include/asm-arm/arch-netx/netx-regs.h4
-rw-r--r--include/asm-arm/arch-ns9xxx/board.h2
-rw-r--r--include/asm-arm/arch-ns9xxx/clock.h34
-rw-r--r--include/asm-arm/arch-ns9xxx/hardware.h5
-rw-r--r--include/asm-arm/arch-ns9xxx/processor.h3
-rw-r--r--include/asm-arm/arch-ns9xxx/regs-sys.h6
-rw-r--r--include/asm-arm/arch-omap/aic23.h4
-rw-r--r--include/asm-arm/arch-omap/board-apollon.h9
-rw-r--r--include/asm-arm/arch-omap/board-h4.h3
-rw-r--r--include/asm-arm/arch-omap/board.h43
-rw-r--r--include/asm-arm/arch-omap/dma.h2
-rw-r--r--include/asm-arm/arch-omap/dsp.h250
-rw-r--r--include/asm-arm/arch-omap/dsp_common.h32
-rw-r--r--include/asm-arm/arch-omap/gpio-switch.h54
-rw-r--r--include/asm-arm/arch-omap/gpio.h2
-rw-r--r--include/asm-arm/arch-omap/gpmc.h2
-rw-r--r--include/asm-arm/arch-omap/hardware.h9
-rw-r--r--include/asm-arm/arch-omap/hwa742.h12
-rw-r--r--include/asm-arm/arch-omap/io.h11
-rw-r--r--include/asm-arm/arch-omap/irqs.h20
-rw-r--r--include/asm-arm/arch-omap/lcd_lph8923.h14
-rw-r--r--include/asm-arm/arch-omap/lcd_mipid.h24
-rw-r--r--include/asm-arm/arch-omap/led.h24
-rw-r--r--include/asm-arm/arch-omap/mailbox.h73
-rw-r--r--include/asm-arm/arch-omap/mcspi.h1
-rw-r--r--include/asm-arm/arch-omap/memory.h13
-rw-r--r--include/asm-arm/arch-omap/menelaus.h17
-rw-r--r--include/asm-arm/arch-omap/omap16xx.h12
-rw-r--r--include/asm-arm/arch-omap/omap24xx.h9
-rw-r--r--include/asm-arm/arch-omap/omapfb.h188
-rw-r--r--include/asm-arm/arch-omap/sram.h3
-rw-r--r--include/asm-arm/arch-omap/usb.h40
-rw-r--r--include/asm-arm/arch-pxa/i2c.h1
-rw-r--r--include/asm-arm/arch-pxa/mmc.h2
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h58
-rw-r--r--include/asm-arm/arch-pxa/pxa27x_keyboard.h13
-rw-r--r--include/asm-arm/arch-s3c2410/regs-ac97.h56
-rw-r--r--include/asm-arm/arch-s3c2410/regs-power.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-udc.h6
-rw-r--r--include/asm-arm/arch-s3c2410/regs-watchdog.h2
-rw-r--r--include/asm-arm/arch-s3c2410/udc.h2
-rw-r--r--include/asm-arm/atomic.h1
-rw-r--r--include/asm-arm/cacheflush.h40
-rw-r--r--include/asm-arm/dma-mapping.h2
-rw-r--r--include/asm-arm/ecard.h52
-rw-r--r--include/asm-arm/glue.h9
-rw-r--r--include/asm-arm/hardware/iop3xx.h24
-rw-r--r--include/asm-arm/io.h33
-rw-r--r--include/asm-arm/kdebug.h1
-rw-r--r--include/asm-arm/kexec.h2
-rw-r--r--include/asm-arm/mach/map.h21
-rw-r--r--include/asm-arm/mach/mmc.h2
-rw-r--r--include/asm-arm/mmu_context.h9
-rw-r--r--include/asm-arm/pgtable-nommu.h4
-rw-r--r--include/asm-arm/pgtable.h4
-rw-r--r--include/asm-arm/plat-s3c24xx/clock.h1
-rw-r--r--include/asm-arm/plat-s3c24xx/cpu.h16
-rw-r--r--include/asm-arm/proc-fns.h8
-rw-r--r--include/asm-arm/ptrace.h10
-rw-r--r--include/asm-arm/system.h13
-rw-r--r--include/asm-arm/thread_info.h1
-rw-r--r--include/asm-arm26/atomic.h1
-rw-r--r--include/asm-arm26/io.h2
-rw-r--r--include/asm-arm26/kdebug.h1
-rw-r--r--include/asm-arm26/memory.h4
-rw-r--r--include/asm-arm26/mmu_context.h2
-rw-r--r--include/asm-arm26/pgtable.h4
-rw-r--r--include/asm-arm26/setup.h2
-rw-r--r--include/asm-arm26/system.h2
-rw-r--r--include/asm-avr32/arch-at32ap/cpu.h33
-rw-r--r--include/asm-avr32/kdebug.h25
-rw-r--r--include/asm-avr32/mmu_context.h1
-rw-r--r--include/asm-avr32/pgtable.h4
-rw-r--r--include/asm-avr32/scatterlist.h2
-rw-r--r--include/asm-avr32/setup.h2
-rw-r--r--include/asm-avr32/unistd.h4
-rw-r--r--include/asm-blackfin/Kbuild1
-rw-r--r--include/asm-blackfin/a.out.h25
-rw-r--r--include/asm-blackfin/atomic.h144
-rw-r--r--include/asm-blackfin/auxvec.h4
-rw-r--r--include/asm-blackfin/bf5xx_timers.h209
-rw-r--r--include/asm-blackfin/bfin-global.h120
-rw-r--r--include/asm-blackfin/bfin5xx_spi.h170
-rw-r--r--include/asm-blackfin/bfin_simple_timer.h13
-rw-r--r--include/asm-blackfin/bfin_sport.h175
-rw-r--r--include/asm-blackfin/bitops.h213
-rw-r--r--include/asm-blackfin/blackfin.h81
-rw-r--r--include/asm-blackfin/bug.h4
-rw-r--r--include/asm-blackfin/bugs.h16
-rw-r--r--include/asm-blackfin/byteorder.h48
-rw-r--r--include/asm-blackfin/cache.h29
-rw-r--r--include/asm-blackfin/cacheflush.h90
-rw-r--r--include/asm-blackfin/checksum.h101
-rw-r--r--include/asm-blackfin/cplb.h51
-rw-r--r--include/asm-blackfin/cplbinit.h203
-rw-r--r--include/asm-blackfin/cpumask.h6
-rw-r--r--include/asm-blackfin/cputime.h6
-rw-r--r--include/asm-blackfin/current.h23
-rw-r--r--include/asm-blackfin/delay.h44
-rw-r--r--include/asm-blackfin/device.h7
-rw-r--r--include/asm-blackfin/div64.h1
-rw-r--r--include/asm-blackfin/dma-mapping.h66
-rw-r--r--include/asm-blackfin/dma.h188
-rw-r--r--include/asm-blackfin/dpmc.h70
-rw-r--r--include/asm-blackfin/elf.h127
-rw-r--r--include/asm-blackfin/emergency-restart.h6
-rw-r--r--include/asm-blackfin/entry.h56
-rw-r--r--include/asm-blackfin/errno.h6
-rw-r--r--include/asm-blackfin/fcntl.h13
-rw-r--r--include/asm-blackfin/flat.h58
-rw-r--r--include/asm-blackfin/futex.h6
-rw-r--r--include/asm-blackfin/gpio.h367
-rw-r--r--include/asm-blackfin/hardirq.h41
-rw-r--r--include/asm-blackfin/hw_irq.h6
-rw-r--r--include/asm-blackfin/ide.h32
-rw-r--r--include/asm-blackfin/io.h207
-rw-r--r--include/asm-blackfin/ioctl.h1
-rw-r--r--include/asm-blackfin/ioctls.h82
-rw-r--r--include/asm-blackfin/ipc.h1
-rw-r--r--include/asm-blackfin/ipcbuf.h30
-rw-r--r--include/asm-blackfin/irq.h70
-rw-r--r--include/asm-blackfin/irq_handler.h22
-rw-r--r--include/asm-blackfin/irq_regs.h1
-rw-r--r--include/asm-blackfin/kdebug.h1
-rw-r--r--include/asm-blackfin/kmap_types.h21
-rw-r--r--include/asm-blackfin/l1layout.h31
-rw-r--r--include/asm-blackfin/linkage.h7
-rw-r--r--include/asm-blackfin/local.h6
-rw-r--r--include/asm-blackfin/mach-bf533/anomaly.h175
-rw-r--r--include/asm-blackfin/mach-bf533/bf533.h306
-rw-r--r--include/asm-blackfin/mach-bf533/bfin_serial_5xx.h108
-rw-r--r--include/asm-blackfin/mach-bf533/blackfin.h45
-rw-r--r--include/asm-blackfin/mach-bf533/cdefBF532.h706
-rw-r--r--include/asm-blackfin/mach-bf533/defBF532.h1175
-rw-r--r--include/asm-blackfin/mach-bf533/dma.h54
-rw-r--r--include/asm-blackfin/mach-bf533/irq.h177
-rw-r--r--include/asm-blackfin/mach-bf533/mem_init.h316
-rw-r--r--include/asm-blackfin/mach-bf533/mem_map.h168
-rw-r--r--include/asm-blackfin/mach-bf537/anomaly.h120
-rw-r--r--include/asm-blackfin/mach-bf537/bf537.h287
-rw-r--r--include/asm-blackfin/mach-bf537/bfin_serial_5xx.h147
-rw-r--r--include/asm-blackfin/mach-bf537/blackfin.h430
-rw-r--r--include/asm-blackfin/mach-bf537/cdefBF534.h1823
-rw-r--r--include/asm-blackfin/mach-bf537/cdefBF537.h209
-rw-r--r--include/asm-blackfin/mach-bf537/defBF534.h2501
-rw-r--r--include/asm-blackfin/mach-bf537/defBF537.h404
-rw-r--r--include/asm-blackfin/mach-bf537/dma.h55
-rw-r--r--include/asm-blackfin/mach-bf537/irq.h219
-rw-r--r--include/asm-blackfin/mach-bf537/mem_init.h330
-rw-r--r--include/asm-blackfin/mach-bf537/mem_map.h175
-rw-r--r--include/asm-blackfin/mach-bf561/anomaly.h184
-rw-r--r--include/asm-blackfin/mach-bf561/bf561.h408
-rw-r--r--include/asm-blackfin/mach-bf561/bfin_serial_5xx.h108
-rw-r--r--include/asm-blackfin/mach-bf561/blackfin.h52
-rw-r--r--include/asm-blackfin/mach-bf561/cdefBF561.h1543
-rw-r--r--include/asm-blackfin/mach-bf561/defBF561.h1717
-rw-r--r--include/asm-blackfin/mach-bf561/dma.h35
-rw-r--r--include/asm-blackfin/mach-bf561/irq.h450
-rw-r--r--include/asm-blackfin/mach-bf561/mem_init.h322
-rw-r--r--include/asm-blackfin/mach-bf561/mem_map.h75
-rw-r--r--include/asm-blackfin/mach-common/cdef_LPBlackfin.h471
-rw-r--r--include/asm-blackfin/mach-common/context.S350
-rw-r--r--include/asm-blackfin/mach-common/def_LPBlackfin.h691
-rw-r--r--include/asm-blackfin/macros.h95
-rw-r--r--include/asm-blackfin/mem_map.h12
-rw-r--r--include/asm-blackfin/mman.h45
-rw-r--r--include/asm-blackfin/mmu.h30
-rw-r--r--include/asm-blackfin/mmu_context.h129
-rw-r--r--include/asm-blackfin/module.h19
-rw-r--r--include/asm-blackfin/msgbuf.h31
-rw-r--r--include/asm-blackfin/mutex.h9
-rw-r--r--include/asm-blackfin/namei.h19
-rw-r--r--include/asm-blackfin/page.h89
-rw-r--r--include/asm-blackfin/page_offset.h6
-rw-r--r--include/asm-blackfin/param.h22
-rw-r--r--include/asm-blackfin/pci.h148
-rw-r--r--include/asm-blackfin/percpu.h6
-rw-r--r--include/asm-blackfin/pgalloc.h8
-rw-r--r--include/asm-blackfin/pgtable.h96
-rw-r--r--include/asm-blackfin/poll.h24
-rw-r--r--include/asm-blackfin/posix_types.h65
-rw-r--r--include/asm-blackfin/processor.h130
-rw-r--r--include/asm-blackfin/ptrace.h166
-rw-r--r--include/asm-blackfin/resource.h6
-rw-r--r--include/asm-blackfin/scatterlist.h26
-rw-r--r--include/asm-blackfin/sections.h7
-rw-r--r--include/asm-blackfin/segment.h7
-rw-r--r--include/asm-blackfin/semaphore-helper.h82
-rw-r--r--include/asm-blackfin/semaphore.h106
-rw-r--r--include/asm-blackfin/sembuf.h25
-rw-r--r--include/asm-blackfin/setup.h17
-rw-r--r--include/asm-blackfin/shmbuf.h42
-rw-r--r--include/asm-blackfin/shmparam.h6
-rw-r--r--include/asm-blackfin/sigcontext.h55
-rw-r--r--include/asm-blackfin/siginfo.h35
-rw-r--r--include/asm-blackfin/signal.h160
-rw-r--r--include/asm-blackfin/socket.h53
-rw-r--r--include/asm-blackfin/sockios.h13
-rw-r--r--include/asm-blackfin/spinlock.h6
-rw-r--r--include/asm-blackfin/stat.h63
-rw-r--r--include/asm-blackfin/statfs.h6
-rw-r--r--include/asm-blackfin/string.h104
-rw-r--r--include/asm-blackfin/system.h249
-rw-r--r--include/asm-blackfin/termbits.h184
-rw-r--r--include/asm-blackfin/termios.h106
-rw-r--r--include/asm-blackfin/thread_info.h143
-rw-r--r--include/asm-blackfin/timex.h18
-rw-r--r--include/asm-blackfin/tlb.h16
-rw-r--r--include/asm-blackfin/tlbflush.h62
-rw-r--r--include/asm-blackfin/topology.h6
-rw-r--r--include/asm-blackfin/traps.h75
-rw-r--r--include/asm-blackfin/types.h66
-rw-r--r--include/asm-blackfin/uaccess.h271
-rw-r--r--include/asm-blackfin/ucontext.h17
-rw-r--r--include/asm-blackfin/unaligned.h6
-rw-r--r--include/asm-blackfin/unistd.h382
-rw-r--r--include/asm-blackfin/user.h89
-rw-r--r--include/asm-cris/kdebug.h1
-rw-r--r--include/asm-cris/mmu_context.h2
-rw-r--r--include/asm-frv/atomic.h91
-rw-r--r--include/asm-frv/kdebug.h1
-rw-r--r--include/asm-frv/mmu_context.h1
-rw-r--r--include/asm-frv/pgtable.h4
-rw-r--r--include/asm-frv/scatterlist.h2
-rw-r--r--include/asm-frv/semaphore.h14
-rw-r--r--include/asm-frv/system.h70
-rw-r--r--include/asm-frv/tlb.h4
-rw-r--r--include/asm-frv/unistd.h16
-rw-r--r--include/asm-generic/atomic.h140
-rw-r--r--include/asm-generic/bitops/atomic.h2
-rw-r--r--include/asm-generic/kdebug.h8
-rw-r--r--include/asm-generic/local.h33
-rw-r--r--include/asm-generic/mm_hooks.h18
-rw-r--r--include/asm-generic/percpu.h1
-rw-r--r--include/asm-generic/vmlinux.lds.h2
-rw-r--r--include/asm-h8300/irq.h1
-rw-r--r--include/asm-h8300/irq_regs.h1
-rw-r--r--include/asm-h8300/kdebug.h1
-rw-r--r--include/asm-h8300/mmu_context.h1
-rw-r--r--include/asm-h8300/pgtable.h5
-rw-r--r--include/asm-h8300/scatterlist.h2
-rw-r--r--include/asm-h8300/system.h1
-rw-r--r--include/asm-i386/Kbuild2
-rw-r--r--include/asm-i386/agp.h6
-rw-r--r--include/asm-i386/alternative.h34
-rw-r--r--include/asm-i386/apic.h9
-rw-r--r--include/asm-i386/atomic.h45
-rw-r--r--include/asm-i386/bitops.h2
-rw-r--r--include/asm-i386/boot.h2
-rw-r--r--include/asm-i386/bugs.h194
-rw-r--r--include/asm-i386/cmpxchg.h293
-rw-r--r--include/asm-i386/cpufeature.h13
-rw-r--r--include/asm-i386/current.h5
-rw-r--r--include/asm-i386/desc.h95
-rw-r--r--include/asm-i386/e820.h1
-rw-r--r--include/asm-i386/elf.h30
-rw-r--r--include/asm-i386/fixmap.h11
-rw-r--r--include/asm-i386/genapic.h6
-rw-r--r--include/asm-i386/highmem.h6
-rw-r--r--include/asm-i386/hpet.h2
-rw-r--r--include/asm-i386/i387.h17
-rw-r--r--include/asm-i386/io.h15
-rw-r--r--include/asm-i386/ioctls.h4
-rw-r--r--include/asm-i386/irq.h2
-rw-r--r--include/asm-i386/irq_regs.h12
-rw-r--r--include/asm-i386/irqflags.h64
-rw-r--r--include/asm-i386/kdebug.h25
-rw-r--r--include/asm-i386/kexec.h8
-rw-r--r--include/asm-i386/local.h205
-rw-r--r--include/asm-i386/mach-bigsmp/mach_apic.h2
-rw-r--r--include/asm-i386/mach-default/mach_apic.h2
-rw-r--r--include/asm-i386/mach-es7000/mach_apic.h9
-rw-r--r--include/asm-i386/mach-es7000/mach_mpparse.h32
-rw-r--r--include/asm-i386/mach-generic/mach_apic.h2
-rw-r--r--include/asm-i386/mach-numaq/mach_apic.h2
-rw-r--r--include/asm-i386/mach-summit/mach_apic.h2
-rw-r--r--include/asm-i386/mach-summit/mach_mpparse.h4
-rw-r--r--include/asm-i386/mach-visws/mach_apic.h2
-rw-r--r--include/asm-i386/mmu_context.h17
-rw-r--r--include/asm-i386/mmzone.h6
-rw-r--r--include/asm-i386/module.h2
-rw-r--r--include/asm-i386/msr-index.h278
-rw-r--r--include/asm-i386/msr.h410
-rw-r--r--include/asm-i386/mtrr.h4
-rw-r--r--include/asm-i386/nmi.h8
-rw-r--r--include/asm-i386/page.h81
-rw-r--r--include/asm-i386/paravirt.h954
-rw-r--r--include/asm-i386/pda.h100
-rw-r--r--include/asm-i386/percpu.h136
-rw-r--r--include/asm-i386/pgalloc.h1
-rw-r--r--include/asm-i386/pgtable-2level-defs.h2
-rw-r--r--include/asm-i386/pgtable-2level.h37
-rw-r--r--include/asm-i386/pgtable-3level-defs.h6
-rw-r--r--include/asm-i386/pgtable-3level.h69
-rw-r--r--include/asm-i386/pgtable.h99
-rw-r--r--include/asm-i386/processor-flags.h91
-rw-r--r--include/asm-i386/processor.h187
-rw-r--r--include/asm-i386/reboot.h20
-rw-r--r--include/asm-i386/reboot_fixups.h (renamed from include/linux/reboot_fixups.h)4
-rw-r--r--include/asm-i386/required-features.h34
-rw-r--r--include/asm-i386/scatterlist.h2
-rw-r--r--include/asm-i386/segment.h10
-rw-r--r--include/asm-i386/serial.h16
-rw-r--r--include/asm-i386/smp.h101
-rw-r--r--include/asm-i386/sync_bitops.h2
-rw-r--r--include/asm-i386/system.h347
-rw-r--r--include/asm-i386/termbits.h14
-rw-r--r--include/asm-i386/termios.h6
-rw-r--r--include/asm-i386/thread_info.h10
-rw-r--r--include/asm-i386/timer.h2
-rw-r--r--include/asm-i386/tlbflush.h19
-rw-r--r--include/asm-i386/tsc.h15
-rw-r--r--include/asm-i386/uaccess.h14
-rw-r--r--include/asm-i386/unistd.h3
-rw-r--r--include/asm-i386/vmi_time.h18
-rw-r--r--include/asm-i386/voyager.h6
-rw-r--r--include/asm-ia64/asmmacro.h10
-rw-r--r--include/asm-ia64/atomic.h53
-rw-r--r--include/asm-ia64/io.h6
-rw-r--r--include/asm-ia64/kdebug.h27
-rw-r--r--include/asm-ia64/kexec.h2
-rw-r--r--include/asm-ia64/kregs.h3
-rw-r--r--include/asm-ia64/local.h51
-rw-r--r--include/asm-ia64/mmu_context.h1
-rw-r--r--include/asm-ia64/pal.h33
-rw-r--r--include/asm-ia64/patch.h1
-rw-r--r--include/asm-ia64/pgtable.h4
-rw-r--r--include/asm-ia64/processor.h1
-rw-r--r--include/asm-ia64/scatterlist.h2
-rw-r--r--include/asm-ia64/sections.h1
-rw-r--r--include/asm-ia64/smp.h6
-rw-r--r--include/asm-ia64/thread_info.h2
-rw-r--r--include/asm-m32r/atomic.h23
-rw-r--r--include/asm-m32r/kdebug.h1
-rw-r--r--include/asm-m32r/mmu_context.h1
-rw-r--r--include/asm-m32r/pgtable.h4
-rw-r--r--include/asm-m32r/scatterlist.h2
-rw-r--r--include/asm-m32r/smp.h6
-rw-r--r--include/asm-m32r/system.h4
-rw-r--r--include/asm-m68k/adb.h75
-rw-r--r--include/asm-m68k/atarihw.h2
-rw-r--r--include/asm-m68k/atariints.h2
-rw-r--r--include/asm-m68k/atarikb.h6
-rw-r--r--include/asm-m68k/atomic.h31
-rw-r--r--include/asm-m68k/kdebug.h1
-rw-r--r--include/asm-m68k/mmu_context.h1
-rw-r--r--include/asm-m68k/pgtable.h4
-rw-r--r--include/asm-m68k/scatterlist.h2
-rw-r--r--include/asm-m68k/system.h1
-rw-r--r--include/asm-m68k/thread_info.h6
-rw-r--r--include/asm-m68knommu/atomic.h25
-rw-r--r--include/asm-m68knommu/kdebug.h1
-rw-r--r--include/asm-m68knommu/mmu_context.h1
-rw-r--r--include/asm-m68knommu/pgtable.h4
-rw-r--r--include/asm-m68knommu/scatterlist.h1
-rw-r--r--include/asm-m68knommu/system.h1
-rw-r--r--include/asm-mips/atomic.h57
-rw-r--r--include/asm-mips/bootinfo.h2
-rw-r--r--include/asm-mips/kdebug.h1
-rw-r--r--include/asm-mips/kexec.h2
-rw-r--r--include/asm-mips/local.h304
-rw-r--r--include/asm-mips/mach-au1x00/au1550_spi.h16
-rw-r--r--include/asm-mips/mmu_context.h1
-rw-r--r--include/asm-mips/pgtable.h4
-rw-r--r--include/asm-mips/scatterlist.h2
-rw-r--r--include/asm-mips/system.h128
-rw-r--r--include/asm-parisc/atomic.h56
-rw-r--r--include/asm-parisc/compat.h2
-rw-r--r--include/asm-parisc/kdebug.h1
-rw-r--r--include/asm-parisc/local.h41
-rw-r--r--include/asm-parisc/mmu_context.h1
-rw-r--r--include/asm-parisc/pgtable.h4
-rw-r--r--include/asm-parisc/scatterlist.h1
-rw-r--r--include/asm-powerpc/asm-compat.h10
-rw-r--r--include/asm-powerpc/atomic.h7
-rw-r--r--include/asm-powerpc/bitops.h1
-rw-r--r--include/asm-powerpc/cacheflush.h6
-rw-r--r--include/asm-powerpc/cell-pmu.h5
-rw-r--r--include/asm-powerpc/cputable.h11
-rw-r--r--include/asm-powerpc/current.h1
-rw-r--r--include/asm-powerpc/edac.h40
-rw-r--r--include/asm-powerpc/eeh_event.h6
-rw-r--r--include/asm-powerpc/ibmebus.h44
-rw-r--r--include/asm-powerpc/immap_86xx.h75
-rw-r--r--include/asm-powerpc/io.h7
-rw-r--r--include/asm-powerpc/iommu.h14
-rw-r--r--include/asm-powerpc/kdebug.h34
-rw-r--r--include/asm-powerpc/kexec.h2
-rw-r--r--include/asm-powerpc/kprobes.h12
-rw-r--r--include/asm-powerpc/local.h201
-rw-r--r--include/asm-powerpc/machdep.h22
-rw-r--r--include/asm-powerpc/mmu-44x.h78
-rw-r--r--include/asm-powerpc/mmu-hash64.h403
-rw-r--r--include/asm-powerpc/mmu.h408
-rw-r--r--include/asm-powerpc/mmu_context.h1
-rw-r--r--include/asm-powerpc/mpc52xx.h11
-rw-r--r--include/asm-powerpc/mpic.h32
-rw-r--r--include/asm-powerpc/of_device.h5
-rw-r--r--include/asm-powerpc/oprofile_impl.h2
-rw-r--r--include/asm-powerpc/paca.h6
-rw-r--r--include/asm-powerpc/page.h10
-rw-r--r--include/asm-powerpc/page_32.h2
-rw-r--r--include/asm-powerpc/page_64.h86
-rw-r--r--include/asm-powerpc/parport.h11
-rw-r--r--include/asm-powerpc/pci.h14
-rw-r--r--include/asm-powerpc/pgalloc-32.h41
-rw-r--r--include/asm-powerpc/pgalloc-64.h147
-rw-r--r--include/asm-powerpc/pgalloc.h154
-rw-r--r--include/asm-powerpc/pgtable-4k.h12
-rw-r--r--include/asm-powerpc/pgtable-64k.h17
-rw-r--r--include/asm-powerpc/pgtable-ppc32.h813
-rw-r--r--include/asm-powerpc/pgtable-ppc64.h492
-rw-r--r--include/asm-powerpc/pgtable.h521
-rw-r--r--include/asm-powerpc/pmac_feature.h2
-rw-r--r--include/asm-powerpc/pmc.h1
-rw-r--r--include/asm-powerpc/ppc-pci.h14
-rw-r--r--include/asm-powerpc/processor.h1
-rw-r--r--include/asm-powerpc/prom.h46
-rw-r--r--include/asm-powerpc/ps3.h33
-rw-r--r--include/asm-powerpc/ps3av.h22
-rw-r--r--include/asm-powerpc/reg.h68
-rw-r--r--include/asm-powerpc/smp.h1
-rw-r--r--include/asm-powerpc/spu_csa.h11
-rw-r--r--include/asm-powerpc/suspend.h9
-rw-r--r--include/asm-powerpc/system.h131
-rw-r--r--include/asm-powerpc/tlb.h1
-rw-r--r--include/asm-powerpc/tlbflush.h172
-rw-r--r--include/asm-powerpc/tsi108.h12
-rw-r--r--include/asm-powerpc/tsi108_pci.h45
-rw-r--r--include/asm-powerpc/uaccess.h28
-rw-r--r--include/asm-powerpc/ucc_fast.h3
-rw-r--r--include/asm-powerpc/udbg.h1
-rw-r--r--include/asm-powerpc/uic.h23
-rw-r--r--include/asm-ppc/hydra.h2
-rw-r--r--include/asm-ppc/ibm4xx.h8
-rw-r--r--include/asm-ppc/kdebug.h1
-rw-r--r--include/asm-ppc/mmu_context.h1
-rw-r--r--include/asm-ppc/pgtable.h4
-rw-r--r--include/asm-ppc/ppc_sys.h2
-rw-r--r--include/asm-ppc/prom.h3
-rw-r--r--include/asm-ppc/system.h2
-rw-r--r--include/asm-s390/ccwdev.h6
-rw-r--r--include/asm-s390/dma-mapping.h2
-rw-r--r--include/asm-s390/elf.h7
-rw-r--r--include/asm-s390/kdebug.h42
-rw-r--r--include/asm-s390/kexec.h2
-rw-r--r--include/asm-s390/kprobes.h16
-rw-r--r--include/asm-s390/lowcore.h10
-rw-r--r--include/asm-s390/mmu_context.h2
-rw-r--r--include/asm-s390/qdio.h1
-rw-r--r--include/asm-s390/smp.h1
-rw-r--r--include/asm-sh/bug.h96
-rw-r--r--include/asm-sh/clock.h32
-rw-r--r--include/asm-sh/cpu-features.h1
-rw-r--r--include/asm-sh/cpu-sh3/dma.h2
-rw-r--r--include/asm-sh/cpu-sh3/mmu_context.h1
-rw-r--r--include/asm-sh/cpu-sh4/dma-sh7780.h2
-rw-r--r--include/asm-sh/cpu-sh4/dma.h2
-rw-r--r--include/asm-sh/cpu-sh4/freq.h8
-rw-r--r--include/asm-sh/dmabrg.h23
-rw-r--r--include/asm-sh/edosk7705.h2
-rw-r--r--include/asm-sh/irq.h91
-rw-r--r--include/asm-sh/kdebug.h15
-rw-r--r--include/asm-sh/kexec.h44
-rw-r--r--include/asm-sh/kgdb.h51
-rw-r--r--include/asm-sh/lboxre2.h27
-rw-r--r--include/asm-sh/mmu_context.h7
-rw-r--r--include/asm-sh/page.h10
-rw-r--r--include/asm-sh/param.h2
-rw-r--r--include/asm-sh/pci.h2
-rw-r--r--include/asm-sh/pgalloc.h44
-rw-r--r--include/asm-sh/pgtable.h4
-rw-r--r--include/asm-sh/processor.h2
-rw-r--r--include/asm-sh/r7780rp.h76
-rw-r--r--include/asm-sh/scatterlist.h2
-rw-r--r--include/asm-sh/se.h4
-rw-r--r--include/asm-sh/se7722.h118
-rw-r--r--include/asm-sh/se7751.h2
-rw-r--r--include/asm-sh/se7780.h108
-rw-r--r--include/asm-sh/snapgear.h2
-rw-r--r--include/asm-sh/stat.h19
-rw-r--r--include/asm-sh/system.h22
-rw-r--r--include/asm-sh/timer.h25
-rw-r--r--include/asm-sh/unistd.h5
-rw-r--r--include/asm-sh64/kdebug.h1
-rw-r--r--include/asm-sh64/mmu_context.h2
-rw-r--r--include/asm-sh64/pgtable.h4
-rw-r--r--include/asm-sh64/scatterlist.h2
-rw-r--r--include/asm-sh64/system.h2
-rw-r--r--include/asm-sparc/kdebug.h4
-rw-r--r--include/asm-sparc/mmu_context.h2
-rw-r--r--include/asm-sparc/smp.h1
-rw-r--r--include/asm-sparc/system.h1
-rw-r--r--include/asm-sparc/unistd.h3
-rw-r--r--include/asm-sparc64/Kbuild1
-rw-r--r--include/asm-sparc64/atomic.h53
-rw-r--r--include/asm-sparc64/iommu.h1
-rw-r--r--include/asm-sparc64/kdebug.h39
-rw-r--r--include/asm-sparc64/kprobes.h1
-rw-r--r--include/asm-sparc64/local.h41
-rw-r--r--include/asm-sparc64/lsu.h2
-rw-r--r--include/asm-sparc64/mmu.h2
-rw-r--r--include/asm-sparc64/mmu_context.h1
-rw-r--r--include/asm-sparc64/page.h2
-rw-r--r--include/asm-sparc64/pbm.h152
-rw-r--r--include/asm-sparc64/percpu.h10
-rw-r--r--include/asm-sparc64/pgalloc.h26
-rw-r--r--include/asm-sparc64/pgtable.h2
-rw-r--r--include/asm-sparc64/pstate.h2
-rw-r--r--include/asm-sparc64/scatterlist.h1
-rw-r--r--include/asm-sparc64/sfafsr.h2
-rw-r--r--include/asm-sparc64/smp.h1
-rw-r--r--include/asm-sparc64/system.h1
-rw-r--r--include/asm-sparc64/unistd.h3
-rw-r--r--include/asm-um/cmpxchg.h6
-rw-r--r--include/asm-um/kdebug.h1
-rw-r--r--include/asm-um/mmu_context.h2
-rw-r--r--include/asm-um/page.h3
-rw-r--r--include/asm-um/required-features.h9
-rw-r--r--include/asm-um/smp.h4
-rw-r--r--include/asm-um/tlbflush.h24
-rw-r--r--include/asm-v850/kdebug.h1
-rw-r--r--include/asm-v850/mmu_context.h2
-rw-r--r--include/asm-v850/scatterlist.h2
-rw-r--r--include/asm-v850/system.h1
-rw-r--r--include/asm-x86_64/Kbuild3
-rw-r--r--include/asm-x86_64/agp.h6
-rw-r--r--include/asm-x86_64/alternative.h5
-rw-r--r--include/asm-x86_64/apic.h10
-rw-r--r--include/asm-x86_64/atomic.h65
-rw-r--r--include/asm-x86_64/bugs.h30
-rw-r--r--include/asm-x86_64/cmpxchg.h134
-rw-r--r--include/asm-x86_64/desc.h21
-rw-r--r--include/asm-x86_64/dma-mapping.h2
-rw-r--r--include/asm-x86_64/fixmap.h1
-rw-r--r--include/asm-x86_64/genapic.h4
-rw-r--r--include/asm-x86_64/ipi.h61
-rw-r--r--include/asm-x86_64/irqflags.h9
-rw-r--r--include/asm-x86_64/kdebug.h25
-rw-r--r--include/asm-x86_64/kexec.h2
-rw-r--r--include/asm-x86_64/local.h196
-rw-r--r--include/asm-x86_64/mmu_context.h1
-rw-r--r--include/asm-x86_64/mmzone.h2
-rw-r--r--include/asm-x86_64/msr-index.h1
-rw-r--r--include/asm-x86_64/msr.h285
-rw-r--r--include/asm-x86_64/mtrr.h12
-rw-r--r--include/asm-x86_64/nmi.h9
-rw-r--r--include/asm-x86_64/page.h50
-rw-r--r--include/asm-x86_64/percpu.h10
-rw-r--r--include/asm-x86_64/pgalloc.h15
-rw-r--r--include/asm-x86_64/pgtable.h43
-rw-r--r--include/asm-x86_64/processor-flags.h1
-rw-r--r--include/asm-x86_64/processor.h55
-rw-r--r--include/asm-x86_64/proto.h15
-rw-r--r--include/asm-x86_64/scatterlist.h2
-rw-r--r--include/asm-x86_64/segment.h2
-rw-r--r--include/asm-x86_64/serial.h16
-rw-r--r--include/asm-x86_64/smp.h18
-rw-r--r--include/asm-x86_64/suspend.h13
-rw-r--r--include/asm-x86_64/system.h105
-rw-r--r--include/asm-x86_64/termbits.h2
-rw-r--r--include/asm-x86_64/thread_info.h2
-rw-r--r--include/asm-x86_64/timex.h2
-rw-r--r--include/asm-x86_64/tlbflush.h33
-rw-r--r--include/asm-x86_64/unistd.h5
-rw-r--r--include/asm-xtensa/atomic.h23
-rw-r--r--include/asm-xtensa/kdebug.h1
-rw-r--r--include/asm-xtensa/mmu_context.h1
-rw-r--r--include/asm-xtensa/platform-iss/simcall.h2
-rw-r--r--include/asm-xtensa/scatterlist.h2
-rw-r--r--include/asm-xtensa/system.h2
-rw-r--r--include/crypto/algapi.h84
-rw-r--r--include/linux/Kbuild8
-rw-r--r--include/linux/aio.h3
-rw-r--r--include/linux/ata.h10
-rw-r--r--include/linux/awe_voice.h525
-rw-r--r--include/linux/bio.h2
-rw-r--r--include/linux/blkdev.h3
-rw-r--r--include/linux/bootmem.h4
-rw-r--r--include/linux/buffer_head.h5
-rw-r--r--include/linux/byteorder/generic.h25
-rw-r--r--include/linux/byteorder/swab.h108
-rw-r--r--include/linux/clockchips.h10
-rw-r--r--include/linux/clocksource.h18
-rw-r--r--include/linux/compat.h3
-rw-r--r--include/linux/compat_ioctl.h830
-rw-r--r--include/linux/compiler-gcc.h4
-rw-r--r--include/linux/compiler-gcc3.h12
-rw-r--r--include/linux/compiler-gcc4.h9
-rw-r--r--include/linux/compiler-intel.h5
-rw-r--r--include/linux/compiler.h21
-rw-r--r--include/linux/console.h7
-rw-r--r--include/linux/console_struct.h3
-rw-r--r--include/linux/const.h (renamed from include/asm-sparc64/const.h)12
-rw-r--r--include/linux/cpu.h3
-rw-r--r--include/linux/cpufreq.h20
-rw-r--r--include/linux/crash_dump.h8
-rw-r--r--include/linux/crypto.h236
-rw-r--r--include/linux/cyclades.h229
-rw-r--r--include/linux/dcache.h6
-rw-r--r--include/linux/device.h13
-rw-r--r--include/linux/display.h61
-rw-r--r--include/linux/dlm_device.h9
-rw-r--r--include/linux/ds1wm.h11
-rw-r--r--include/linux/efi.h1
-rw-r--r--include/linux/elf-em.h1
-rw-r--r--include/linux/elf.h17
-rw-r--r--include/linux/elfnote.h4
-rw-r--r--include/linux/etherdevice.h12
-rw-r--r--include/linux/ethtool.h2
-rw-r--r--include/linux/ext3_fs.h1
-rw-r--r--include/linux/ext3_fs_i.h2
-rw-r--r--include/linux/ext4_fs_i.h2
-rw-r--r--include/linux/fb.h59
-rw-r--r--include/linux/fcntl.h4
-rw-r--r--include/linux/font.h3
-rw-r--r--include/linux/fs.h29
-rw-r--r--include/linux/fsl_devices.h39
-rw-r--r--include/linux/futex.h65
-rw-r--r--include/linux/generic_acl.h2
-rw-r--r--include/linux/genhd.h1
-rw-r--r--include/linux/gfp.h9
-rw-r--r--include/linux/gpio_keys.h3
-rw-r--r--include/linux/hdlc.h3
-rw-r--r--include/linux/hid.h14
-rw-r--r--include/linux/highmem.h42
-rw-r--r--include/linux/hp_sdc.h1
-rw-r--r--include/linux/hugetlb.h6
-rw-r--r--include/linux/i2c-algo-bit.h9
-rw-r--r--include/linux/i2c-algo-pcf.h2
-rw-r--r--include/linux/i2c-gpio.h38
-rw-r--r--include/linux/i2c-id.h3
-rw-r--r--include/linux/i2c.h123
-rw-r--r--include/linux/ide.h1
-rw-r--r--include/linux/ieee80211.h342
-rw-r--r--include/linux/init.h12
-rw-r--r--include/linux/init_task.h4
-rw-r--r--include/linux/input-polldev.h46
-rw-r--r--include/linux/input.h57
-rw-r--r--include/linux/interrupt.h44
-rw-r--r--include/linux/ioctl32.h17
-rw-r--r--include/linux/ioport.h1
-rw-r--r--include/linux/ipc.h11
-rw-r--r--include/linux/irda.h2
-rw-r--r--include/linux/irq.h4
-rw-r--r--include/linux/isdn/capiutil.h1
-rw-r--r--include/linux/isdn_divertif.h5
-rw-r--r--include/linux/kallsyms.h26
-rw-r--r--include/linux/kdebug.h20
-rw-r--r--include/linux/kernel.h4
-rw-r--r--include/linux/kexec.h17
-rw-r--r--include/linux/kobject.h58
-rw-r--r--include/linux/kprobes.h22
-rw-r--r--include/linux/kthread.h3
-rw-r--r--include/linux/ktime.h6
-rw-r--r--include/linux/kvm.h133
-rw-r--r--include/linux/libata.h118
-rw-r--r--include/linux/list.h11
-rw-r--r--include/linux/lockd/lockd.h16
-rw-r--r--include/linux/loop.h2
-rw-r--r--include/linux/mc146818rtc.h7
-rw-r--r--include/linux/mca.h2
-rw-r--r--include/linux/meye.h2
-rw-r--r--include/linux/migrate.h15
-rw-r--r--include/linux/miscdevice.h1
-rw-r--r--include/linux/mm.h55
-rw-r--r--include/linux/mm_types.h17
-rw-r--r--include/linux/mmc/card.h32
-rw-r--r--include/linux/mmc/core.h112
-rw-r--r--include/linux/mmc/host.h59
-rw-r--r--include/linux/mmc/mmc.h322
-rw-r--r--include/linux/mmc/protocol.h327
-rw-r--r--include/linux/mmc/sd.h83
-rw-r--r--include/linux/mmzone.h15
-rw-r--r--include/linux/mnt_namespace.h5
-rw-r--r--include/linux/mod_devicetable.h1
-rw-r--r--include/linux/module.h35
-rw-r--r--include/linux/mount.h2
-rw-r--r--include/linux/msdos_fs.h3
-rw-r--r--include/linux/msi.h11
-rw-r--r--include/linux/mutex.h5
-rw-r--r--include/linux/netdevice.h36
-rw-r--r--include/linux/netfilter/nf_conntrack_proto_gre.h18
-rw-r--r--include/linux/netfilter_bridge.h25
-rw-r--r--include/linux/netlink.h4
-rw-r--r--include/linux/nfs4_acl.h1
-rw-r--r--include/linux/nfs_fs.h4
-rw-r--r--include/linux/nfs_fs_sb.h2
-rw-r--r--include/linux/nfs_mount.h1
-rw-r--r--include/linux/nfs_page.h33
-rw-r--r--include/linux/notifier.h66
-rw-r--r--include/linux/nsproxy.h3
-rw-r--r--include/linux/nubus.h126
-rw-r--r--include/linux/page-flags.h41
-rw-r--r--include/linux/pagemap.h22
-rw-r--r--include/linux/parport.h8
-rw-r--r--include/linux/parport_pc.h3
-rw-r--r--include/linux/parser.h6
-rw-r--r--include/linux/pci.h28
-rw-r--r--include/linux/pci_hotplug.h2
-rw-r--r--include/linux/pci_ids.h6
-rw-r--r--include/linux/percpu.h9
-rw-r--r--include/linux/phantom.h42
-rw-r--r--include/linux/phy.h1
-rw-r--r--include/linux/pid_namespace.h2
-rw-r--r--include/linux/pm.h39
-rw-r--r--include/linux/pmu.h20
-rw-r--r--include/linux/pnp.h3
-rw-r--r--include/linux/poison.h10
-rw-r--r--include/linux/proc_fs.h4
-rw-r--r--include/linux/quicklist.h94
-rw-r--r--include/linux/quota.h4
-rw-r--r--include/linux/quotaops.h3
-rw-r--r--include/linux/radix-tree.h4
-rw-r--r--include/linux/raid/md_k.h1
-rw-r--r--include/linux/reiserfs_fs_sb.h3
-rw-r--r--include/linux/relay.h3
-rw-r--r--include/linux/rfkill.h89
-rw-r--r--include/linux/rtc.h39
-rw-r--r--include/linux/sched.h44
-rw-r--r--include/linux/security.h2
-rw-r--r--include/linux/serial_core.h10
-rw-r--r--include/linux/serial_reg.h2
-rw-r--r--include/linux/signal.h125
-rw-r--r--include/linux/skbuff.h7
-rw-r--r--include/linux/slab.h36
-rw-r--r--include/linux/slub_def.h206
-rw-r--r--include/linux/smp.h1
-rw-r--r--include/linux/snmp.h2
-rw-r--r--include/linux/sony-laptop.h34
-rw-r--r--include/linux/sonypi.h2
-rw-r--r--include/linux/spi/Kbuild1
-rw-r--r--include/linux/spi/ad7877.h24
-rw-r--r--include/linux/spi/spi.h82
-rw-r--r--include/linux/spi/spidev.h124
-rw-r--r--include/linux/spinlock_types.h6
-rw-r--r--include/linux/stacktrace.h6
-rw-r--r--include/linux/stat.h3
-rw-r--r--include/linux/sunrpc/clnt.h9
-rw-r--r--include/linux/sunrpc/debug.h2
-rw-r--r--include/linux/sunrpc/msg_prot.h4
-rw-r--r--include/linux/sunrpc/sched.h2
-rw-r--r--include/linux/sunrpc/svc.h19
-rw-r--r--include/linux/sunrpc/svcsock.h3
-rw-r--r--include/linux/sunrpc/xprt.h7
-rw-r--r--include/linux/suspend.h68
-rw-r--r--include/linux/svga.h3
-rw-r--r--include/linux/syscalls.h2
-rw-r--r--include/linux/sysdev.h1
-rw-r--r--include/linux/tifm.h118
-rw-r--r--include/linux/time.h3
-rw-r--r--include/linux/timer.h1
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/uinput.h2
-rw-r--r--include/linux/usb.h2
-rw-r--r--include/linux/usb_sl811.h26
-rw-r--r--include/linux/utsname.h19
-rw-r--r--include/linux/vmalloc.h1
-rw-r--r--include/linux/vmstat.h3
-rw-r--r--include/linux/vt_kern.h3
-rw-r--r--include/linux/wireless.h2
-rw-r--r--include/linux/workqueue.h95
-rw-r--r--include/linux/writeback.h2
-rw-r--r--include/linux/xfrm.h49
-rw-r--r--include/math-emu/extended.h396
-rw-r--r--include/media/ovcamchip.h1
-rw-r--r--include/media/tuner.h1
-rw-r--r--include/net/flow.h6
-rw-r--r--include/net/ieee80211.h4
-rw-r--r--include/net/ieee80211_crypt.h4
-rw-r--r--include/net/ieee80211_radiotap.h77
-rw-r--r--include/net/ipv6.h15
-rw-r--r--include/net/irda/af_irda.h2
-rw-r--r--include/net/irda/irda.h2
-rw-r--r--include/net/irda/iriap.h2
-rw-r--r--include/net/irda/iriap_event.h2
-rw-r--r--include/net/irda/irias_object.h2
-rw-r--r--include/net/irda/irlan_client.h2
-rw-r--r--include/net/irda/irlan_common.h2
-rw-r--r--include/net/irda/irlan_eth.h2
-rw-r--r--include/net/irda/irlan_event.h2
-rw-r--r--include/net/irda/irlan_filter.h2
-rw-r--r--include/net/irda/irlan_provider.h2
-rw-r--r--include/net/irda/irlap.h2
-rw-r--r--include/net/irda/irlmp.h2
-rw-r--r--include/net/irda/irlmp_event.h2
-rw-r--r--include/net/irda/irlmp_frame.h2
-rw-r--r--include/net/irda/irmod.h2
-rw-r--r--include/net/irda/irqueue.h2
-rw-r--r--include/net/irda/irttp.h2
-rw-r--r--include/net/irda/parameters.h2
-rw-r--r--include/net/irda/timer.h2
-rw-r--r--include/net/irda/wrapper.h2
-rw-r--r--include/net/iucv/af_iucv.h2
-rw-r--r--include/net/iucv/iucv.h2
-rw-r--r--include/net/mac80211.h1045
-rw-r--r--include/net/sctp/command.h2
-rw-r--r--include/net/sctp/sctp.h4
-rw-r--r--include/net/sctp/structs.h1
-rw-r--r--include/net/sock.h9
-rw-r--r--include/net/tcp.h10
-rw-r--r--include/net/wext.h2
-rw-r--r--include/net/xfrm.h38
-rw-r--r--include/pcmcia/ds.h6
-rw-r--r--include/rdma/ib_mad.h2
-rw-r--r--include/rdma/ib_verbs.h47
-rw-r--r--include/scsi/iscsi_proto.h12
-rw-r--r--include/scsi/libsas.h3
-rw-r--r--include/scsi/scsi.h1
-rw-r--r--include/scsi/scsi_cmnd.h3
-rw-r--r--include/scsi/scsi_dbg.h10
-rw-r--r--include/scsi/scsi_device.h14
-rw-r--r--include/scsi/scsi_host.h32
-rw-r--r--include/scsi/scsi_tgt_if.h6
-rw-r--r--include/scsi/scsi_transport_fc.h2
-rw-r--r--include/scsi/sd.h72
-rw-r--r--include/video/mach64.h1
-rw-r--r--include/video/permedia2.h4
-rw-r--r--include/video/tgafb.h47
-rw-r--r--init/Kconfig102
-rw-r--r--init/do_mounts.c8
-rw-r--r--init/do_mounts_initrd.c5
-rw-r--r--init/main.c42
-rw-r--r--ipc/compat.c4
-rw-r--r--ipc/mqueue.c3
-rw-r--r--ipc/sem.c1
-rw-r--r--ipc/util.c54
-rw-r--r--kernel/Kconfig.preempt4
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/audit.c8
-rw-r--r--kernel/configs.c15
-rw-r--r--kernel/cpu.c66
-rw-r--r--kernel/cpuset.c74
-rw-r--r--kernel/delayacct.c6
-rw-r--r--kernel/die_notifier.c38
-rw-r--r--kernel/exit.c36
-rw-r--r--kernel/fork.c95
-rw-r--r--kernel/futex.c1036
-rw-r--r--kernel/futex_compat.c22
-rw-r--r--kernel/hrtimer.c5
-rw-r--r--kernel/irq/chip.c3
-rw-r--r--kernel/irq/handle.c5
-rw-r--r--kernel/irq/manage.c10
-rw-r--r--kernel/irq/proc.c15
-rw-r--r--kernel/irq/spurious.c4
-rw-r--r--kernel/itimer.c60
-rw-r--r--kernel/kallsyms.c104
-rw-r--r--kernel/kexec.c4
-rw-r--r--kernel/kmod.c13
-rw-r--r--kernel/kprobes.c293
-rw-r--r--kernel/ksysfs.c12
-rw-r--r--kernel/kthread.c113
-rw-r--r--kernel/lockdep.c51
-rw-r--r--kernel/module.c107
-rw-r--r--kernel/mutex.c8
-rw-r--r--kernel/nsproxy.c139
-rw-r--r--kernel/params.c4
-rw-r--r--kernel/pid.c15
-rw-r--r--kernel/posix-cpu-timers.c14
-rw-r--r--kernel/posix-timers.c1
-rw-r--r--kernel/power/Kconfig15
-rw-r--r--kernel/power/disk.c271
-rw-r--r--kernel/power/main.c70
-rw-r--r--kernel/power/power.h54
-rw-r--r--kernel/power/process.c12
-rw-r--r--kernel/power/snapshot.c318
-rw-r--r--kernel/power/swap.c61
-rw-r--r--kernel/power/swsusp.c139
-rw-r--r--kernel/power/user.c52
-rw-r--r--kernel/printk.c27
-rw-r--r--kernel/profile.c4
-rw-r--r--kernel/rcupdate.c2
-rw-r--r--kernel/rcutorture.c45
-rw-r--r--kernel/relay.c37
-rw-r--r--kernel/resource.c21
-rw-r--r--kernel/rtmutex.c41
-rw-r--r--kernel/rtmutex_common.h34
-rw-r--r--kernel/rwsem.c2
-rw-r--r--kernel/sched.c377
-rw-r--r--kernel/signal.c147
-rw-r--r--kernel/softirq.c4
-rw-r--r--kernel/softlockup.c52
-rw-r--r--kernel/stop_machine.c8
-rw-r--r--kernel/sys.c117
-rw-r--r--kernel/sysctl.c23
-rw-r--r--kernel/taskstats.c4
-rw-r--r--kernel/time.c61
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/clocksource.c51
-rw-r--r--kernel/time/tick-common.c8
-rw-r--r--kernel/time/tick-internal.h1
-rw-r--r--kernel/time/tick-sched.c51
-rw-r--r--kernel/time/timekeeping.c476
-rw-r--r--kernel/time/timer_list.c40
-rw-r--r--kernel/time/timer_stats.c14
-rw-r--r--kernel/timer.c532
-rw-r--r--kernel/uid16.c1
-rw-r--r--kernel/utsname.c41
-rw-r--r--kernel/wait.c2
-rw-r--r--kernel/workqueue.c783
-rw-r--r--lib/Kconfig5
-rw-r--r--lib/Kconfig.debug34
-rw-r--r--lib/cpumask.c3
-rw-r--r--lib/devres.c26
-rw-r--r--lib/fault-inject.c3
-rw-r--r--lib/inflate.c129
-rw-r--r--lib/iomap.c27
-rw-r--r--lib/kobject.c69
-rw-r--r--lib/parser.c10
-rw-r--r--lib/radix-tree.c2
-rw-r--r--lib/swiotlb.c1
-rw-r--r--lib/vsprintf.c37
-rw-r--r--lib/zlib_inflate/inflate.c8
-rw-r--r--mm/Kconfig5
-rw-r--r--mm/Makefile3
-rw-r--r--mm/filemap.c181
-rw-r--r--mm/filemap_xip.c7
-rw-r--r--mm/highmem.c9
-rw-r--r--mm/hugetlb.c33
-rw-r--r--mm/internal.h2
-rw-r--r--mm/madvise.c33
-rw-r--r--mm/memory.c106
-rw-r--r--mm/mmap.c50
-rw-r--r--mm/nommu.c8
-rw-r--r--mm/oom_kill.c17
-rw-r--r--mm/page-writeback.c57
-rw-r--r--mm/page_alloc.c128
-rw-r--r--mm/quicklist.c88
-rw-r--r--mm/readahead.c29
-rw-r--r--mm/rmap.c4
-rw-r--r--mm/shmem.c3
-rw-r--r--mm/slab.c291
-rw-r--r--mm/slob.c57
-rw-r--r--mm/slub.c3588
-rw-r--r--mm/sparse.c14
-rw-r--r--mm/swap.c4
-rw-r--r--mm/swapfile.c3
-rw-r--r--mm/truncate.c3
-rw-r--r--mm/vmalloc.c21
-rw-r--r--mm/vmscan.c23
-rw-r--r--mm/vmstat.c95
-rw-r--r--net/8021q/vlan.c3
-rw-r--r--net/8021q/vlanproc.c36
-rw-r--r--net/Kconfig3
-rw-r--r--net/Makefile5
-rw-r--r--net/appletalk/ddp.c26
-rw-r--r--net/ax25/af_ax25.c1
-rw-r--r--net/bluetooth/bnep/core.c1
-rw-r--r--net/bluetooth/hci_sock.c9
-rw-r--r--net/bluetooth/hci_sysfs.c9
-rw-r--r--net/bluetooth/l2cap.c6
-rw-r--r--net/bluetooth/rfcomm/core.c29
-rw-r--r--net/bluetooth/rfcomm/tty.c11
-rw-r--r--net/bridge/br_if.c4
-rw-r--r--net/bridge/br_ioctl.c4
-rw-r--r--net/bridge/br_netfilter.c138
-rw-r--r--net/bridge/br_netlink.c3
-rw-r--r--net/bridge/br_stp.c1
-rw-r--r--net/bridge/br_stp_if.c1
-rw-r--r--net/bridge/br_stp_timer.c1
-rw-r--r--net/core/datagram.c50
-rw-r--r--net/core/dev.c150
-rw-r--r--net/core/dev_mcast.c5
-rw-r--r--net/core/flow.c2
-rw-r--r--net/core/netpoll.c1
-rw-r--r--net/core/pktgen.c1
-rw-r--r--net/core/rtnetlink.c7
-rw-r--r--net/core/skbuff.c122
-rw-r--r--net/core/user_dma.c25
-rw-r--r--net/decnet/af_decnet.c13
-rw-r--r--net/decnet/dn_dev.c85
-rw-r--r--net/decnet/dn_fib.c2
-rw-r--r--net/decnet/dn_route.c14
-rw-r--r--net/ieee80211/ieee80211_crypt.c2
-rw-r--r--net/ieee80211/ieee80211_crypt_ccmp.c4
-rw-r--r--net/ieee80211/ieee80211_crypt_tkip.c6
-rw-r--r--net/ieee80211/ieee80211_crypt_wep.c2
-rw-r--r--net/ieee80211/ieee80211_module.c5
-rw-r--r--net/ieee80211/ieee80211_rx.c4
-rw-r--r--net/ieee80211/ieee80211_wx.c4
-rw-r--r--net/ipv4/Kconfig4
-rw-r--r--net/ipv4/af_inet.c1
-rw-r--r--net/ipv4/cipso_ipv4.c2
-rw-r--r--net/ipv4/devinet.c17
-rw-r--r--net/ipv4/igmp.c15
-rw-r--r--net/ipv4/ip_input.c14
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv4/ipconfig.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c1
-rw-r--r--net/ipv4/ipvs/ip_vs_sed.c2
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c20
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c26
-rw-r--r--net/ipv4/tcp.c18
-rw-r--r--net/ipv4/tcp_highspeed.c24
-rw-r--r--net/ipv4/tcp_input.c30
-rw-r--r--net/ipv4/tcp_output.c9
-rw-r--r--net/ipv4/tcp_yeah.h7
-rw-r--r--net/ipv4/udp.c206
-rw-r--r--net/ipv6/addrconf.c34
-rw-r--r--net/ipv6/af_inet6.c1
-rw-r--r--net/ipv6/anycast.c17
-rw-r--r--net/ipv6/mcast.c15
-rw-r--r--net/ipv6/netfilter/Kconfig4
-rw-r--r--net/ipv6/proc.c1
-rw-r--r--net/ipv6/xfrm6_tunnel.c2
-rw-r--r--net/ipx/af_ipx.c1
-rw-r--r--net/irda/af_irda.c1
-rw-r--r--net/iucv/af_iucv.c193
-rw-r--r--net/iucv/iucv.c260
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/llc/llc_core.c10
-rw-r--r--net/mac80211/Kconfig78
-rw-r--r--net/mac80211/Makefile20
-rw-r--r--net/mac80211/aes_ccm.c155
-rw-r--r--net/mac80211/aes_ccm.h26
-rw-r--r--net/mac80211/debugfs.c433
-rw-r--r--net/mac80211/debugfs.h16
-rw-r--r--net/mac80211/debugfs_key.c252
-rw-r--r--net/mac80211/debugfs_key.h34
-rw-r--r--net/mac80211/debugfs_netdev.c440
-rw-r--r--net/mac80211/debugfs_netdev.h30
-rw-r--r--net/mac80211/debugfs_sta.c246
-rw-r--r--net/mac80211/debugfs_sta.h12
-rw-r--r--net/mac80211/hostapd_ioctl.h108
-rw-r--r--net/mac80211/ieee80211.c4984
-rw-r--r--net/mac80211/ieee80211_cfg.c66
-rw-r--r--net/mac80211/ieee80211_cfg.h9
-rw-r--r--net/mac80211/ieee80211_common.h98
-rw-r--r--net/mac80211/ieee80211_i.h798
-rw-r--r--net/mac80211/ieee80211_iface.c352
-rw-r--r--net/mac80211/ieee80211_ioctl.c1822
-rw-r--r--net/mac80211/ieee80211_key.h106
-rw-r--r--net/mac80211/ieee80211_led.c91
-rw-r--r--net/mac80211/ieee80211_led.h32
-rw-r--r--net/mac80211/ieee80211_rate.c140
-rw-r--r--net/mac80211/ieee80211_rate.h144
-rw-r--r--net/mac80211/ieee80211_sta.c3060
-rw-r--r--net/mac80211/michael.c104
-rw-r--r--net/mac80211/michael.h20
-rw-r--r--net/mac80211/rc80211_simple.c432
-rw-r--r--net/mac80211/sta_info.c470
-rw-r--r--net/mac80211/sta_info.h164
-rw-r--r--net/mac80211/tkip.c341
-rw-r--r--net/mac80211/tkip.h36
-rw-r--r--net/mac80211/wep.c328
-rw-r--r--net/mac80211/wep.h40
-rw-r--r--net/mac80211/wme.c678
-rw-r--r--net/mac80211/wme.h57
-rw-r--r--net/mac80211/wpa.c660
-rw-r--r--net/mac80211/wpa.h31
-rw-r--r--net/netfilter/Kconfig26
-rw-r--r--net/netfilter/nf_conntrack_expect.c2
-rw-r--r--net/netlink/af_netlink.c35
-rw-r--r--net/netrom/nr_route.c5
-rw-r--r--net/rfkill/Kconfig24
-rw-r--r--net/rfkill/Makefile6
-rw-r--r--net/rfkill/rfkill-input.c174
-rw-r--r--net/rfkill/rfkill.c407
-rw-r--r--net/rose/rose_route.c8
-rw-r--r--net/rxrpc/Kconfig8
-rw-r--r--net/rxrpc/ar-ack.c80
-rw-r--r--net/rxrpc/ar-error.c2
-rw-r--r--net/rxrpc/ar-output.c2
-rw-r--r--net/rxrpc/ar-peer.c45
-rw-r--r--net/rxrpc/rxkad.c1
-rw-r--r--net/sched/sch_api.c7
-rw-r--r--net/sctp/associola.c29
-rw-r--r--net/sctp/chunk.c2
-rw-r--r--net/sctp/ipv6.c49
-rw-r--r--net/sctp/protocol.c81
-rw-r--r--net/sctp/sm_make_chunk.c15
-rw-r--r--net/sctp/sm_sideeffect.c35
-rw-r--r--net/sctp/sm_statefuns.c29
-rw-r--r--net/sctp/socket.c140
-rw-r--r--net/socket.c23
-rw-r--r--net/sunrpc/Makefile2
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_seal.c13
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c15
-rw-r--r--net/sunrpc/clnt.c69
-rw-r--r--net/sunrpc/pmap_clnt.c383
-rw-r--r--net/sunrpc/rpc_pipe.c12
-rw-r--r--net/sunrpc/rpcb_clnt.c625
-rw-r--r--net/sunrpc/sched.c65
-rw-r--r--net/sunrpc/sunrpc_syms.c6
-rw-r--r--net/sunrpc/svc.c4
-rw-r--r--net/sunrpc/svcauth.c2
-rw-r--r--net/sunrpc/svcauth_unix.c10
-rw-r--r--net/sunrpc/svcsock.c34
-rw-r--r--net/sunrpc/xprt.c4
-rw-r--r--net/sunrpc/xprtsock.c4
-rw-r--r--net/tipc/Kconfig2
-rw-r--r--net/tipc/eth_media.c12
-rw-r--r--net/unix/af_unix.c1
-rw-r--r--net/x25/af_x25.c1
-rw-r--r--net/xfrm/xfrm_algo.c22
-rw-r--r--net/xfrm/xfrm_policy.c71
-rw-r--r--net/xfrm/xfrm_state.c2
-rw-r--r--net/xfrm/xfrm_user.c80
-rw-r--r--scripts/Makefile.build19
-rw-r--r--scripts/Makefile.host14
-rw-r--r--scripts/Makefile.modpost8
-rw-r--r--scripts/basic/docproc.c2
-rw-r--r--scripts/basic/fixdep.c2
-rwxr-xr-xscripts/checksyscalls.sh118
-rwxr-xr-xscripts/cleanfile126
-rwxr-xr-xscripts/cleanpatch206
-rw-r--r--scripts/gen_initramfs_list.sh12
-rw-r--r--scripts/genksyms/genksyms.c3
-rw-r--r--scripts/kconfig/Makefile5
-rw-r--r--scripts/kconfig/conf.c1
-rw-r--r--scripts/kconfig/lex.zconf.c_shipped2
-rw-r--r--scripts/kconfig/lkc.h1
-rw-r--r--scripts/kconfig/lxdialog/dialog.h1
-rw-r--r--scripts/kconfig/lxdialog/util.c9
-rw-r--r--scripts/kconfig/mconf.c43
-rw-r--r--scripts/kconfig/menu.c2
-rw-r--r--scripts/kconfig/qconf.cc5
-rw-r--r--scripts/kconfig/qconf.h2
-rw-r--r--scripts/kconfig/symbol.c13
-rw-r--r--scripts/kconfig/zconf.l2
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped6
-rw-r--r--scripts/kconfig/zconf.y6
-rwxr-xr-xscripts/kernel-doc141
-rwxr-xr-xscripts/mkcompile_h27
-rwxr-xr-xscripts/mkuboot.sh2
-rw-r--r--scripts/mod/file2alias.c21
-rw-r--r--scripts/mod/mk_elfconfig.c3
-rw-r--r--scripts/mod/modpost.c168
-rw-r--r--scripts/mod/modpost.h1
-rw-r--r--scripts/mod/sumversion.c5
-rw-r--r--security/capability.c1
-rw-r--r--security/commoncap.c1
-rw-r--r--security/inode.c2
-rw-r--r--security/selinux/Kconfig2
-rw-r--r--security/selinux/hooks.c8
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.c8
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-tas.c11
-rw-r--r--sound/aoa/core/snd-aoa-gpio-feature.c8
-rw-r--r--sound/aoa/fabrics/snd-aoa-fabric-layout.c8
-rw-r--r--sound/aoa/soundbus/core.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c12
-rw-r--r--sound/arm/pxa2xx-ac97.c12
-rw-r--r--sound/core/Kconfig2
-rw-r--r--sound/core/control.c1
-rw-r--r--sound/core/hwdep.c1
-rw-r--r--sound/core/init.c1
-rw-r--r--sound/core/oss/mixer_oss.c1
-rw-r--r--sound/core/oss/pcm_oss.c1
-rw-r--r--sound/core/pcm_native.c1
-rw-r--r--sound/core/rawmidi.c1
-rw-r--r--sound/core/seq/oss/seq_oss.c1
-rw-r--r--sound/core/seq/seq_clientmgr.c1
-rw-r--r--sound/core/timer.c1
-rw-r--r--sound/oss/Kconfig30
-rw-r--r--sound/oss/au1550_ac97.c1
-rw-r--r--sound/oss/btaudio.c2
-rw-r--r--sound/oss/dmasound/Kconfig14
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c137
-rw-r--r--sound/oss/dmasound/tas_common.c9
-rw-r--r--sound/oss/dmasound/tas_ioctl.h1
-rw-r--r--sound/oss/es1371.c2
-rw-r--r--sound/oss/pas2_pcm.c2
-rw-r--r--sound/oss/sh_dac_audio.c2
-rw-r--r--sound/oss/soundcard.c1
-rw-r--r--sound/oss/swarm_cs4297a.c1
-rw-r--r--sound/oss/trident.c5
-rw-r--r--sound/oss/via82cxxx_audio.c1
-rw-r--r--sound/pci/ac97/ac97_codec.c2
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c2
-rw-r--r--sound/pci/ca0106/ca0106_proc.c2
-rw-r--r--sound/pci/cs46xx/dsp_spos.c1
-rw-r--r--sound/pci/cs46xx/dsp_spos_scb_lib.c1
-rw-r--r--sound/pci/hda/hda_generic.c1
-rw-r--r--sound/pci/hda/hda_proc.c1
-rw-r--r--sound/pci/hda/patch_atihdmi.c1
-rw-r--r--sound/pci/hda/patch_si3054.c1
-rw-r--r--sound/pci/hda/patch_via.c1
-rw-r--r--sound/pci/ice1712/delta.h4
-rw-r--r--sound/pci/mixart/mixart.c2
-rw-r--r--sound/ppc/pmac.c55
-rw-r--r--sound/ppc/tumbler.c57
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c12
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.h2
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c4
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.h2
-rw-r--r--sound/sparc/dbri.c2
-rw-r--r--usr/Kconfig2
4592 files changed, 260465 insertions, 101495 deletions
diff --git a/CREDITS b/CREDITS
index d7140309e06..6829e91a88d 100644
--- a/CREDITS
+++ b/CREDITS
@@ -380,7 +380,7 @@ S: FutureTV Labs Ltd
S: Brunswick House, 61-69 Newmarket Rd, Cambridge CB5 8EG
S: United Kingdom
-N: Thomas Bogendörfer
+N: Thomas Bogendörfer
E: tsbogend@alpha.franken.de
D: PCnet32 driver, SONIC driver, JAZZ_ESP driver
D: newport abscon driver, g364 framebuffer driver
@@ -400,7 +400,7 @@ W: http://math-www.uni-paderborn.de/~axel/
D: Configuration help text support
D: Linux CD and Support Giveaway List
-N: Erik Inge Bolsø
+N: Erik Inge Bolsø
E: knan@mo.himolde.no
D: Misc kernel hacks
@@ -428,7 +428,7 @@ D: Various fixes (mostly networking)
S: Montreal, Quebec
S: Canada
-N: Zoltán Böszörményi
+N: Zoltán Böszörményi
E: zboszor@mail.externet.hu
D: MTRR emulation with Cyrix style ARR registers, Athlon MTRR support
@@ -661,7 +661,7 @@ N: Kees Cook
E: kees@outflux.net
W: http://outflux.net/
P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D
-D: Minor updates to SCSI code for the Communications type
+D: Minor updates to SCSI types, added /proc/pid/maps protection
S: (ask for current address)
S: USA
@@ -1029,11 +1029,11 @@ D: Future Domain TMC-16x0 SCSI driver (author)
D: APM driver (early port)
D: DRM drivers (author of several)
-N: János Farkas
+N: János Farkas
E: chexum@shadow.banki.hu
D: romfs, various (mostly networking) fixes
P: 1024/F81FB2E1 41 B7 E4 E6 3E D4 A6 71 6D 9C F3 9F F2 BF DF 6E
-S: Madarász Viktor utca 25
+S: Madarász Viktor utca 25
S: 1131 Budapest
S: Hungary
@@ -1044,10 +1044,10 @@ D: UDF filesystem
S: (ask for current address)
S: USA
-N: Jürgen Fischer
-E: fischer@norbit.de (=?iso-8859-1?q?J=FCrgen?= Fischer)
+N: Jürgen Fischer
+E: fischer@norbit.de
D: Author of Adaptec AHA-152x SCSI driver
-S: Schulstraße 18
+S: Schulstraße 18
S: 26506 Norden
S: Germany
@@ -1113,7 +1113,7 @@ E: fuganti@netbank.com.br
D: random kernel hacker, ZF MachZ Watchdog driver
S: Conectiva S.A.
S: R. Tocantins, 89 - Cristo Rei
-S: 80050-430 - Curitiba - Paraná
+S: 80050-430 - Curitiba - Paraná
S: Brazil
N: Kumar Gala
@@ -1258,12 +1258,12 @@ S: 44 St. Joseph Street, Suite 506
S: Toronto, Ontario, M4Y 2W4
S: Canada
-N: Richard Günther
+N: Richard Günther
E: rguenth@tat.physik.uni-tuebingen.de
W: http://www.tat.physik.uni-tuebingen.de/~rguenth
P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2 93 7A 32 42 45 37 23 57
D: binfmt_misc
-S: 72074 Tübingen
+S: 72074 Tübingen
S: Germany
N: Justin Guyett
@@ -1287,7 +1287,7 @@ N: Bruno Haible
E: haible@ma2s2.mathematik.uni-karlsruhe.de
D: SysV FS, shm swapping, memory management fixes
S: 17 rue Danton
-S: F - 94270 Le Kremlin-Bicêtre
+S: F - 94270 Le Kremlin-Bicêtre
S: France
N: Greg Hankins
@@ -1701,7 +1701,7 @@ S: Czech Republic
N: Jakob Kemi
E: jakob.kemi@telia.com
D: V4L W9966 Webcam driver
-S: Forsbyvägen 33
+S: Forsbyvägen 33
S: 74143 Knivsta
S: Sweden
@@ -1745,8 +1745,9 @@ S: D-64295
S: Germany
N: Andi Kleen
-E: ak@muc.de
-D: network hacker, syncookies
+E: andi@firstfloor.org
+U: http://www.halobates.de
+D: network, x86, NUMA, various hacks
S: Schwalbenstr. 96
S: 85551 Ottobrunn
S: Germany
@@ -2064,7 +2065,7 @@ D: misc. kernel hacking and debugging
S: Cambridge, MA 02139
S: USA
-N: Martin von Löwis
+N: Martin von Löwis
E: loewis@informatik.hu-berlin.de
D: script binary format
D: NTFS driver
@@ -2141,7 +2142,7 @@ S: PO BOX 220, HFX. CENTRAL
S: Halifax, Nova Scotia
S: Canada B3J 3C8
-N: Kai Mäkisara
+N: Kai Mäkisara
E: Kai.Makisara@kolumbus.fi
D: SCSI Tape Driver
@@ -2579,10 +2580,9 @@ S: Australia
N: Miguel Ojeda Sandonis
E: maxextreme@gmail.com
-D: Author: Auxiliary LCD Controller driver (ks0108)
-D: Author: Auxiliary LCD driver (cfag12864b)
-D: Author: Auxiliary LCD framebuffer driver (cfag12864bfb)
-D: Maintainer: Auxiliary display drivers tree (drivers/auxdisplay/*)
+W: http://maxextreme.googlepages.com/
+D: Author of the ks0108, cfag12864b and cfag12864bfb auxiliary display drivers.
+D: Maintainer of the auxiliary display drivers tree (drivers/auxdisplay/*)
S: C/ Mieses 20, 9-B
S: Valladolid 47009
S: Spain
@@ -2785,10 +2785,10 @@ N: Juan Quintela
E: quintela@fi.udc.es
D: Memory Management hacking
S: LFCIA
-S: Departamento de Computación
-S: Universidade da Coruña
+S: Departamento de Computación
+S: Universidade da Coruña
S: E-15071
-S: A Coruña
+S: A Coruña
S: Spain
N: Augusto Cesar Radtke
@@ -2939,7 +2939,7 @@ E: aris@cathedrallabs.org
D: Support for EtherExpress 10 ISA (i82595) in eepro driver
D: User level driver support for input
S: R. Jose Serrato, 130 - Santa Candida
-S: 82640-320 - Curitiba - Paraná
+S: 82640-320 - Curitiba - Paraná
S: Brazil
N: Alessandro Rubini
@@ -3345,15 +3345,15 @@ P: 1024D/D0FE7AFB B24A 65C9 1D71 2AC2 DE87 CA26 189B 9946 D0FE 7AFB
D: rcutorture maintainer
D: lock annotations, finding and fixing lock bugs
-N: Winfried Trümper
+N: Winfried Trümper
E: winni@xpilot.org
W: http://www.shop.de/~winni/
D: German HOWTO, Crash-Kurs Linux (German, 100 comprehensive pages)
D: CD-Writing HOWTO, various mini-HOWTOs
D: One-week tutorials on Linux twice a year (free of charge)
-D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
+D: Linux-Workshop Köln (aka LUG Cologne, Germany), Installfests
S: Tacitusstr. 6
-S: D-50968 Köln
+S: D-50968 Köln
N: Tsu-Sheng Tsao
E: tsusheng@scf.usc.edu
diff --git a/Documentation/ABI/removed/devfs b/Documentation/ABI/removed/devfs
index 8195c4e0d0a..8ffd28bf659 100644
--- a/Documentation/ABI/removed/devfs
+++ b/Documentation/ABI/removed/devfs
@@ -6,7 +6,7 @@ Description:
races, contains a naming policy within the kernel that is
against the LSB, and can be replaced by using udev.
The files fs/devfs/*, include/linux/devfs_fs*.h were removed,
- along with the the assorted devfs function calls throughout the
+ along with the assorted devfs function calls throughout the
kernel tree.
Users:
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 9069189e78e..afc28677589 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -160,6 +160,21 @@ supply of new-lines on your screen is not a renewable resource (think
25-line terminal screens here), you have more empty lines to put
comments on.
+Do not unnecessarily use braces where a single statement will do.
+
+if (condition)
+ action();
+
+This does not apply if one branch of a conditional statement is a single
+statement. Use braces in both branches.
+
+if (condition) {
+ do_this();
+ do_that();
+} else {
+ otherwise();
+}
+
3.1: Spaces
Linux kernel style for use of spaces depends (mostly) on
@@ -625,7 +640,7 @@ language.
There appears to be a common misperception that gcc has a magic "make me
faster" speedup option called "inline". While the use of inlines can be
-appropriate (for example as a means of replacing macros, see Chapter 11), it
+appropriate (for example as a means of replacing macros, see Chapter 12), it
very often is not. Abundant use of the inline keyword leads to a much bigger
kernel, which in turn slows the system as a whole down, due to a bigger
icache footprint for the CPU and simply because there is less memory
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 867608ab3ca..6fd1646d320 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -41,8 +41,9 @@ psdocs: $(PS)
PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
pdfdocs: $(PDF)
-HTML := $(patsubst %.xml, %.html, $(BOOKS))
+HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
htmldocs: $(HTML)
+ $(call build_main_index)
MAN := $(patsubst %.xml, %.9, $(BOOKS))
mandocs: $(MAN)
@@ -132,10 +133,17 @@ quiet_cmd_db2pdf = PDF $@
%.pdf : %.xml
$(call cmd,db2pdf)
+
+main_idx = Documentation/DocBook/index.html
+build_main_index = rm -rf $(main_idx) && \
+ echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
+ echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
+ cat $(HTML) >> $(main_idx)
+
quiet_cmd_db2html = HTML $@
cmd_db2html = xmlto xhtml $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
- Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
+ $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
%.html: %.xml
@(which xmlto > /dev/null 2>&1) || \
@@ -152,6 +160,7 @@ quiet_cmd_db2man = MAN $@
@(which xmlto > /dev/null 2>&1) || \
(echo "*** You need to install xmlto ***"; \
exit 1)
+ $(Q)mkdir -p $(obj)/man
$(call cmd,db2man)
@touch $@
@@ -212,11 +221,7 @@ clean-files := $(DOCBOOKS) \
$(patsubst %.xml, %.9, $(DOCBOOKS)) \
$(C-procfs-example)
-clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS))
-
-#man put files in man subdir - traverse down
-subdir- := man/
-
+clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
# Declare the contents of the .PHONY variable as phony. We keep that
# information in a variable se we can use it in if_changed and friends.
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 0bb90237e23..38f88b6ae40 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -84,6 +84,10 @@ X!Iinclude/linux/kobject.h
!Ekernel/rcupdate.c
</sect1>
+ <sect1><title>Device Resource Management</title>
+!Edrivers/base/devres.c
+ </sect1>
+
</chapter>
<chapter id="adt">
@@ -236,6 +240,12 @@ X!Ilib/string.c
!Enet/core/dev.c
!Enet/ethernet/eth.c
!Iinclude/linux/etherdevice.h
+!Edrivers/net/phy/phy.c
+!Idrivers/net/phy/phy.c
+!Edrivers/net/phy/phy_device.c
+!Idrivers/net/phy/phy_device.c
+!Edrivers/net/phy/mdio_bus.c
+!Idrivers/net/phy/mdio_bus.c
<!-- FIXME: Removed for now since no structured comments in source
X!Enet/core/wireless.c
-->
@@ -570,4 +580,67 @@ X!Idrivers/video/console/fonts.c
!Edrivers/input/ff-core.c
!Edrivers/input/ff-memless.c
</chapter>
+
+ <chapter id="spi">
+ <title>Serial Peripheral Interface (SPI)</title>
+ <para>
+ SPI is the "Serial Peripheral Interface", widely used with
+ embedded systems because it is a simple and efficient
+ interface: basically a multiplexed shift register.
+ Its three signal wires hold a clock (SCK, often in the range
+ of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
+ a "Master In, Slave Out" (MISO) data line.
+ SPI is a full duplex protocol; for each bit shifted out the
+ MOSI line (one per clock) another is shifted in on the MISO line.
+ Those bits are assembled into words of various sizes on the
+ way to and from system memory.
+ An additional chipselect line is usually active-low (nCS);
+ four signals are normally used for each peripheral, plus
+ sometimes an interrupt.
+ </para>
+ <para>
+ The SPI bus facilities listed here provide a generalized
+ interface to declare SPI busses and devices, manage them
+ according to the standard Linux driver model, and perform
+ input/output operations.
+ At this time, only "master" side interfaces are supported,
+ where Linux talks to SPI peripherals and does not implement
+ such a peripheral itself.
+ (Interfaces to support implementing SPI slaves would
+ necessarily look different.)
+ </para>
+ <para>
+ The programming interface is structured around two kinds of driver,
+ and two kinds of device.
+ A "Controller Driver" abstracts the controller hardware, which may
+ be as simple as a set of GPIO pins or as complex as a pair of FIFOs
+ connected to dual DMA engines on the other side of the SPI shift
+ register (maximizing throughput). Such drivers bridge between
+ whatever bus they sit on (often the platform bus) and SPI, and
+ expose the SPI side of their device as a
+ <structname>struct spi_master</structname>.
+ SPI devices are children of that master, represented as a
+ <structname>struct spi_device</structname> and manufactured from
+ <structname>struct spi_board_info</structname> descriptors which
+ are usually provided by board-specific initialization code.
+ A <structname>struct spi_driver</structname> is called a
+ "Protocol Driver", and is bound to a spi_device using normal
+ driver model calls.
+ </para>
+ <para>
+ The I/O model is a set of queued messages. Protocol drivers
+ submit one or more <structname>struct spi_message</structname>
+ objects, which are processed and completed asynchronously.
+ (There are synchronous wrappers, however.) Messages are
+ built from one or more <structname>struct spi_transfer</structname>
+ objects, each of which wraps a full duplex SPI transfer.
+ A variety of protocol tweaking options are needed, because
+ different chips adopt very different policies for how they
+ use the bits transferred with SPI.
+ </para>
+!Iinclude/linux/spi/spi.h
+!Fdrivers/spi/spi.c spi_register_board_info
+!Edrivers/spi/spi.c
+ </chapter>
+
</book>
diff --git a/Documentation/DocBook/librs.tmpl b/Documentation/DocBook/librs.tmpl
index 3ff39bafc00..94f21361e0e 100644
--- a/Documentation/DocBook/librs.tmpl
+++ b/Documentation/DocBook/librs.tmpl
@@ -79,12 +79,12 @@
<chapter id="usage">
<title>Usage</title>
<para>
- This chapter provides examples how to use the library.
+ This chapter provides examples of how to use the library.
</para>
<sect1>
<title>Initializing</title>
<para>
- The init function init_rs returns a pointer to a
+ The init function init_rs returns a pointer to an
rs decoder structure, which holds the necessary
information for encoding, decoding and error correction
with the given polynomial. It either uses an existing
@@ -98,10 +98,10 @@
static struct rs_control *rs_decoder;
/* Symbolsize is 10 (bits)
- * Primitve polynomial is x^10+x^3+1
+ * Primitive polynomial is x^10+x^3+1
* first consecutive root is 0
- * primitve element to generate roots = 1
- * generator polinomial degree (number of roots) = 6
+ * primitive element to generate roots = 1
+ * generator polynomial degree (number of roots) = 6
*/
rs_decoder = init_rs (10, 0x409, 0, 1, 6);
</programlisting>
@@ -116,12 +116,12 @@ rs_decoder = init_rs (10, 0x409, 0, 1, 6);
</para>
<para>
The expanded data can be inverted on the fly by
- providing a non zero inversion mask. The expanded data is
+ providing a non-zero inversion mask. The expanded data is
XOR'ed with the mask. This is used e.g. for FLASH
ECC, where the all 0xFF is inverted to an all 0x00.
The Reed-Solomon code for all 0x00 is all 0x00. The
code is inverted before storing to FLASH so it is 0xFF
- too. This prevent's that reading from an erased FLASH
+ too. This prevents that reading from an erased FLASH
results in ECC errors.
</para>
<para>
@@ -273,7 +273,7 @@ free_rs(rs_decoder);
May be used under the terms of the GNU General Public License (GPL)
</programlisting>
<para>
- The wrapper functions and interfaces are written by Thomas Gleixner
+ The wrapper functions and interfaces are written by Thomas Gleixner.
</para>
<para>
Many users have provided bugfixes, improvements and helping hands for testing.
diff --git a/Documentation/DocBook/man/Makefile b/Documentation/DocBook/man/Makefile
deleted file mode 100644
index 4fb7ea0f7ac..00000000000
--- a/Documentation/DocBook/man/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# Rules are put in Documentation/DocBook
-
-clean-files := *.9.gz *.sgml manpage.links manpage.refs
diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt
index d389388c733..0d8240774fc 100644
--- a/Documentation/MSI-HOWTO.txt
+++ b/Documentation/MSI-HOWTO.txt
@@ -480,8 +480,8 @@ The PCI stack provides 3 possible levels of MSI disabling:
6.1. Disabling MSI on a single device
-Under some circumstances, it might be required to disable MSI on a
-single device, It may be achived by either not calling pci_enable_msi()
+Under some circumstances it might be required to disable MSI on a
+single device. This may be achieved by either not calling pci_enable_msi()
or all, or setting the pci_dev->no_msi flag before (most of the time
in a quirk).
@@ -492,7 +492,7 @@ being able to route MSI between busses. In this case, MSI have to be
disabled on all devices behind this bridge. It is achieves by setting
the PCI_BUS_FLAGS_NO_MSI flag in the pci_bus->bus_flags of the bridge
subordinate bus. There is no need to set the same flag on bridges that
-are below the broken brigde. When pci_enable_msi() is called to enable
+are below the broken bridge. When pci_enable_msi() is called to enable
MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
flag in all parent busses of the device.
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index bd23dc0bc0c..6491b2c45dd 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -80,3 +80,7 @@ kernel patches.
23: Tested after it has been merged into the -mm patchset to make sure
that it still works with all of the other queued patches and various
changes in the VM, VFS, and other subsystems.
+
+24: Avoid whitespace damage such as indenting with spaces or whitespace
+ at the end of lines. You can test this by feeding the patch to
+ "git apply --check --whitespace=error-all"
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index 58bead05eab..d7e26427e42 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -87,6 +87,21 @@ Clarity: It helps if anyone can see how to fix the driver. It helps
driver that intentionally obfuscates how the hardware works
it will go in the bitbucket.
+PM support: Since Linux is used on many portable and desktop systems, your
+ driver is likely to be used on such a system and therefore it
+ should support basic power management by implementing, if
+ necessary, the .suspend and .resume methods used during the
+ system-wide suspend and resume transitions. You should verify
+ that your driver correctly handles the suspend and resume, but
+ if you are unable to ensure that, please at least define the
+ .suspend method returning the -ENOSYS ("Function not
+ implemented") error. You should also try to make sure that your
+ driver uses as little power as possible when it's not doing
+ anything. For the driver testing instructions see
+ Documentation/power/drivers-testing.txt and for a relatively
+ complete overview of the power management issues related to
+ drivers see Documentation/power/devices.txt .
+
Control: In general if there is active maintainance of a driver by
the author then patches will be redirected to them unless
they are totally obvious and without need of checking.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index b0d0043f7c4..a417b25fb1a 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -363,7 +363,8 @@ area or subsystem of the kernel is being patched.
The "summary phrase" in the email's Subject should concisely
describe the patch which that email contains. The "summary
phrase" should not be a filename. Do not use the same "summary
-phrase" for every patch in a whole patch series.
+phrase" for every patch in a whole patch series (where a "patch
+series" is an ordered sequence of multiple, related patches).
Bear in mind that the "summary phrase" of your email becomes
a globally-unique identifier for that patch. It propagates
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index e9126e794ed..71acc28ed0d 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -61,8 +61,6 @@ __u64 stime, utime;
#define MAX_MSG_SIZE 1024
/* Maximum number of cpus expected to be specified in a cpumask */
#define MAX_CPUS 32
-/* Maximum length of pathname to log file */
-#define MAX_FILENAME 256
struct msgtemplate {
struct nlmsghdr n;
@@ -72,6 +70,16 @@ struct msgtemplate {
char cpumask[100+6*MAX_CPUS];
+static void usage(void)
+{
+ fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] "
+ "[-m cpumask] [-t tgid] [-p pid]\n");
+ fprintf(stderr, " -d: print delayacct stats\n");
+ fprintf(stderr, " -i: print IO accounting (works only with -p)\n");
+ fprintf(stderr, " -l: listen forever\n");
+ fprintf(stderr, " -v: debug on\n");
+}
+
/*
* Create a raw netlink socket and bind
*/
@@ -221,13 +229,13 @@ int main(int argc, char *argv[])
int count = 0;
int write_file = 0;
int maskset = 0;
- char logfile[128];
+ char *logfile = NULL;
int loop = 0;
struct msgtemplate msg;
while (1) {
- c = getopt(argc, argv, "diw:r:m:t:p:v:l");
+ c = getopt(argc, argv, "diw:r:m:t:p:vl");
if (c < 0)
break;
@@ -241,7 +249,7 @@ int main(int argc, char *argv[])
print_io_accounting = 1;
break;
case 'w':
- strncpy(logfile, optarg, MAX_FILENAME);
+ logfile = strdup(optarg);
printf("write to file %s\n", logfile);
write_file = 1;
break;
@@ -277,7 +285,7 @@ int main(int argc, char *argv[])
loop = 1;
break;
default:
- printf("Unknown option %d\n", c);
+ usage();
exit(-1);
}
}
diff --git a/Documentation/arm/Interrupts b/Documentation/arm/Interrupts
index 72c93de8cd4..0d3dbf1099b 100644
--- a/Documentation/arm/Interrupts
+++ b/Documentation/arm/Interrupts
@@ -149,7 +149,7 @@ So, what's changed?
3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
-4. Direct access to SA1111 INTPOL is depreciated. Use set_irq_type instead.
+4. Direct access to SA1111 INTPOL is deprecated. Use set_irq_type instead.
5. A handler is expected to perform any necessary acknowledgement of the
parent IRQ via the correct chip specific function. For instance, if
diff --git a/Documentation/arm/Samsung-S3C24XX/H1940.txt b/Documentation/arm/Samsung-S3C24XX/H1940.txt
index d6b1de92b11..f4a7b22c866 100644
--- a/Documentation/arm/Samsung-S3C24XX/H1940.txt
+++ b/Documentation/arm/Samsung-S3C24XX/H1940.txt
@@ -23,7 +23,7 @@ Support
http://handhelds.org/moin/moin.cgi/HpIpaqH1940
- Herbert Pötzl pages:
+ Herbert Pötzl pages:
http://vserver.13thfloor.at/H1940/
@@ -32,7 +32,7 @@ Maintainers
-----------
This project is being maintained and developed by a variety
- of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
+ of people, including Ben Dooks, Arnaud Patard, and Herbert Pötzl.
Thanks to the many others who have also provided support.
diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b
index 3572b98f45b..b714183d412 100644
--- a/Documentation/auxdisplay/cfag12864b
+++ b/Documentation/auxdisplay/cfag12864b
@@ -78,9 +78,9 @@ Select (17)------------------------------(16) Data / Instruction
Ground (18)---[GND] [+5v]---(19) LED +
Ground (19)---[GND]
Ground (20)---[GND] E A Values:
-Ground (21)---[GND] [GND]---[P1]---(18) Vee · R = Resistor = 22 ohm
-Ground (22)---[GND] | · P1 = Preset = 10 Kohm
-Ground (23)---[GND] ---- S ------( 3) V0 · P2 = Preset = 1 Kohm
+Ground (21)---[GND] [GND]---[P1]---(18) Vee - R = Resistor = 22 ohm
+Ground (22)---[GND] | - P1 = Preset = 10 Kohm
+Ground (23)---[GND] ---- S ------( 3) V0 - P2 = Preset = 1 Kohm
Ground (24)---[GND] | |
Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED -
diff --git a/Documentation/binfmt_misc.txt b/Documentation/binfmt_misc.txt
index d097f09ee15..f609ebf9c78 100644
--- a/Documentation/binfmt_misc.txt
+++ b/Documentation/binfmt_misc.txt
@@ -113,4 +113,4 @@ cause unexpected behaviour and can be a security hazard.
There is a web page about binfmt_misc at
http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html
-Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
+Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
diff --git a/Documentation/blackfin/00-INDEX b/Documentation/blackfin/00-INDEX
new file mode 100644
index 00000000000..7cb3b356b24
--- /dev/null
+++ b/Documentation/blackfin/00-INDEX
@@ -0,0 +1,11 @@
+00-INDEX
+ - This file
+
+cache-lock.txt
+ - HOWTO for blackfin cache locking.
+
+cachefeatures.txt
+ - Supported cache features.
+
+Filesystems
+ - Requirements for mounting the root file system.
diff --git a/Documentation/blackfin/Filesystems b/Documentation/blackfin/Filesystems
new file mode 100644
index 00000000000..51260a1b803
--- /dev/null
+++ b/Documentation/blackfin/Filesystems
@@ -0,0 +1,169 @@
+/*
+ * File: Documentation/blackfin/Filesystems
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Rev: $Id: Filesystems 2384 2006-11-01 04:12:43Z magicyang $
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ */
+
+ How to mount the root file system in uClinux/Blackfin
+ -----------------------------------------------------
+
+1 Mounting EXT3 File system.
+ ------------------------
+
+ Creating an EXT3 File system for uClinux/Blackfin:
+
+
+Please follow the steps to form the EXT3 File system and mount the same as root
+file system.
+
+a Make an ext3 file system as large as you want the final root file
+ system.
+
+ mkfs.ext3 /dev/ram0 <your-rootfs-size-in-1k-blocks>
+
+b Mount this Empty file system on a free directory as:
+
+ mount -t ext3 /dev/ram0 ./test
+ where ./test is the empty directory.
+
+c Copy your root fs directory that you have so carefully made over.
+
+ cp -af /tmp/my_final_rootfs_files/* ./test
+
+ (For ex: cp -af uClinux-dist/romfs/* ./test)
+
+d If you have done everything right till now you should be able to see
+ the required "root" dir's (that's etc, root, bin, lib, sbin...)
+
+e Now unmount the file system
+
+ umount ./test
+
+f Create the root file system image.
+
+ dd if=/dev/ram0 bs=1k count=<your-rootfs-size-in-1k-blocks> \
+ > ext3fs.img
+
+
+Now you have to tell the kernel that will be mounting this file system as
+rootfs.
+So do a make menuconfig under kernel and select the Ext3 journaling file system
+support under File system --> submenu.
+
+
+2. Mounting EXT2 File system.
+ -------------------------
+
+By default the ext2 file system image will be created if you invoke make from
+the top uClinux-dist directory.
+
+
+3. Mounting CRAMFS File System
+ ----------------------------
+
+To create a CRAMFS file system image execute the command
+
+ mkfs.cramfs ./test cramfs.img
+
+ where ./test is the target directory.
+
+
+4. Mounting ROMFS File System
+ --------------------------
+
+To create a ROMFS file system image execute the command
+
+ genromfs -v -V "ROMdisk" -f romfs.img -d ./test
+
+ where ./test is the target directory
+
+
+5. Mounting the JFFS2 Filesystem
+ -----------------------------
+
+To create a compressed JFFS filesystem (JFFS2), please execute the command
+
+ mkfs.jffs2 -d ./test -o jffs2.img
+
+ where ./test is the target directory.
+
+However, please make sure the following is in your kernel config.
+
+/*
+ * RAM/ROM/Flash chip drivers
+ */
+#define CONFIG_MTD_CFI 1
+#define CONFIG_MTD_ROM 1
+/*
+ * Mapping drivers for chip access
+ */
+#define CONFIG_MTD_COMPLEX_MAPPINGS 1
+#define CONFIG_MTD_BF533 1
+#undef CONFIG_MTD_UCLINUX
+
+Through the u-boot boot loader, use the jffs2.img in the corresponding
+partition made in linux-2.6.x/drivers/mtd/maps/bf533_flash.c.
+
+NOTE - Currently the Flash driver is available only for EZKIT. Watch out for a
+ STAMP driver soon.
+
+
+6. Mounting the NFS File system
+ -----------------------------
+
+ For mounting the NFS please do the following in the kernel config.
+
+ In Networking Support --> Networking options --> TCP/IP networking -->
+ IP: kernel level autoconfiguration
+
+ Enable BOOTP Support.
+
+ In Kernel hacking --> Compiled-in kernel boot parameter add the following
+
+ root=/dev/nfs rw ip=bootp
+
+ In File system --> Network File system, Enable
+
+ NFS file system support --> NFSv3 client support
+ Root File system on NFS
+
+ in uClibc menuconfig, do the following
+ In Networking Support
+ enable Remote Procedure Call (RPC) support
+ Full RPC Support
+
+ On the Host side, ensure that /etc/dhcpd.conf looks something like this
+
+ ddns-update-style ad-hoc;
+ allow bootp;
+ subnet 10.100.4.0 netmask 255.255.255.0 {
+ default-lease-time 122209600;
+ max-lease-time 31557600;
+ group {
+ host bf533 {
+ hardware ethernet 00:CF:52:49:C3:01;
+ fixed-address 10.100.4.50;
+ option root-path "/home/nfsmount";
+ }
+ }
+
+ ensure that /etc/exports looks something like this
+ /home/nfsmount *(rw,no_root_squash,no_all_squash)
+
+ run the following commands as root (may differ depending on your
+ distribution) :
+ - service nfs start
+ - service portmap start
+ - service dhcpd start
+ - /usr/sbin/exportfs
diff --git a/Documentation/blackfin/cache-lock.txt b/Documentation/blackfin/cache-lock.txt
new file mode 100644
index 00000000000..88ba1e6c31c
--- /dev/null
+++ b/Documentation/blackfin/cache-lock.txt
@@ -0,0 +1,48 @@
+/*
+ * File: Documentation/blackfin/cache-lock.txt
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Rev: $Id: cache-lock.txt 2384 2006-11-01 04:12:43Z magicyang $
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ */
+
+How to lock your code in cache in uClinux/blackfin
+--------------------------------------------------
+
+There are only a few steps required to lock your code into the cache.
+Currently you can lock the code by Way.
+
+Below are the interface provided for locking the cache.
+
+
+1. cache_grab_lock(int Ways);
+
+This function grab the lock for locking your code into the cache specified
+by Ways.
+
+
+2. cache_lock(int Ways);
+
+This function should be called after your critical code has been executed.
+Once the critical code exits, the code is now loaded into the cache. This
+function locks the code into the cache.
+
+
+So, the example sequence will be:
+
+ cache_grab_lock(WAY0_L); /* Grab the lock */
+
+ critical_code(); /* Execute the code of interest */
+
+ cache_lock(WAY0_L); /* Lock the cache */
+
+Where WAY0_L signifies WAY0 locking.
diff --git a/Documentation/blackfin/cachefeatures.txt b/Documentation/blackfin/cachefeatures.txt
new file mode 100644
index 00000000000..0fbec23becb
--- /dev/null
+++ b/Documentation/blackfin/cachefeatures.txt
@@ -0,0 +1,65 @@
+/*
+ * File: Documentation/blackfin/cachefeatures.txt
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Rev: $Id: cachefeatures.txt 2384 2006-11-01 04:12:43Z magicyang $
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ */
+
+ - Instruction and Data cache initialization.
+ icache_init();
+ dcache_init();
+
+ - Instruction and Data cache Invalidation Routines, when flushing the
+ same is not required.
+ _icache_invalidate();
+ _dcache_invalidate();
+
+ Also, for invalidating the entire instruction and data cache, the below
+ routines are provided (another method for invalidation, refer page no 267 and 287 of
+ ADSP-BF533 Hardware Reference manual)
+
+ invalidate_entire_dcache();
+ invalidate_entire_icache();
+
+ -External Flushing of Instruction and data cache routines.
+
+ flush_instruction_cache();
+ flush_data_cache();
+
+ - Internal Flushing of Instruction and Data Cache.
+
+ icplb_flush();
+ dcplb_flush();
+
+ - Locking the cache.
+
+ cache_grab_lock();
+ cache_lock();
+
+ Please refer linux-2.6.x/Documentation/blackfin/cache-lock.txt for how to
+ lock the cache.
+
+ Locking the cache is optional feature.
+
+ - Miscellaneous cache functions.
+
+ flush_cache_all();
+ flush_cache_mm();
+ invalidate_dcache_range();
+ flush_dcache_range();
+ flush_dcache_page();
+ flush_cache_range();
+ flush_cache_page();
+ invalidate_dcache_range();
+ flush_page_to_ram();
+
diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt
index 96ccf681075..1b930ef5a07 100644
--- a/Documentation/block/ioprio.txt
+++ b/Documentation/block/ioprio.txt
@@ -6,10 +6,10 @@ Intro
-----
With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
-priorities is supported for reads on files. This enables users to io nice
-processes or process groups, similar to what has been possible to cpu
-scheduling for ages. This document mainly details the current possibilites
-with cfq, other io schedulers do not support io priorities so far.
+priorities are supported for reads on files. This enables users to io nice
+processes or process groups, similar to what has been possible with cpu
+scheduling for ages. This document mainly details the current possibilities
+with cfq; other io schedulers do not support io priorities thus far.
Scheduling classes
------------------
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index f74affe5c82..e65736c6b8b 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -22,14 +22,21 @@ This driver is known to work with the following cards:
* SA E200i
* SA E500
-If nodes are not already created in the /dev/cciss directory, run as root:
+Detecting drive failures:
+-------------------------
-# cd /dev
-# ./MAKEDEV cciss
+To get the status of logical volumes and to detect physical drive
+failures, you can use the cciss_vol_status program found here:
+http://cciss.sourceforge.net/#cciss_utils
Device Naming:
--------------
+If nodes are not already created in the /dev/cciss directory, run as root:
+
+# cd /dev
+# ./MAKEDEV cciss
+
You need some entries in /dev for the cciss device. The MAKEDEV script
can make device nodes for you automatically. Currently the device setup
is as follows:
diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt
index 53d62c1e1c9..fc647492e94 100644
--- a/Documentation/cpu-freq/cpufreq-stats.txt
+++ b/Documentation/cpu-freq/cpufreq-stats.txt
@@ -17,7 +17,7 @@ Contents
1. Introduction
-cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
+cpufreq-stats is a driver that provides CPU frequency statistics for each CPU.
These statistics are provided in /sysfs as a bunch of read_only interfaces. This
interface (when configured) will appear in a separate directory under cpufreq
in /sysfs (<sysfs root>/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index cc60d29b954..b6d24c22274 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -217,14 +217,17 @@ Q: What happens when a CPU is being logically offlined?
A: The following happen, listed in no particular order :-)
- A notification is sent to in-kernel registered modules by sending an event
- CPU_DOWN_PREPARE
+ CPU_DOWN_PREPARE or CPU_DOWN_PREPARE_FROZEN, depending on whether or not the
+ CPU is being offlined while tasks are frozen due to a suspend operation in
+ progress
- All process is migrated away from this outgoing CPU to a new CPU
- All interrupts targeted to this CPU is migrated to a new CPU
- timers/bottom half/task lets are also migrated to a new CPU
- Once all services are migrated, kernel calls an arch specific routine
__cpu_disable() to perform arch specific cleanup.
- Once this is successful, an event for successful cleanup is sent by an event
- CPU_DEAD.
+ CPU_DEAD (or CPU_DEAD_FROZEN if tasks are frozen due to a suspend while the
+ CPU is being offlined).
"It is expected that each service cleans up when the CPU_DOWN_PREPARE
notifier is called, when CPU_DEAD is called its expected there is nothing
@@ -242,9 +245,11 @@ A: This is what you would need in your kernel code to receive notifications.
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
foobar_online_action(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
foobar_dead_action(cpu);
break;
}
diff --git a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
index 9b84b805ab7..a2ac6d29479 100644
--- a/Documentation/crypto/api-intro.txt
+++ b/Documentation/crypto/api-intro.txt
@@ -177,7 +177,7 @@ Portions of this API were derived from the following projects:
and;
Nettle (http://www.lysator.liu.se/~nisse/nettle/)
- Niels Möller
+ Niels Möller
Original developers of the crypto algorithms:
@@ -200,8 +200,8 @@ SHA1 algorithm contributors:
DES algorithm contributors:
Raimar Falke
- Gisle Sælensminde
- Niels Möller
+ Gisle Sælensminde
+ Niels Möller
Blowfish algorithm contributors:
Herbert Valerio Riedel
diff --git a/Documentation/device-mapper/delay.txt b/Documentation/device-mapper/delay.txt
new file mode 100644
index 00000000000..15adc55359e
--- /dev/null
+++ b/Documentation/device-mapper/delay.txt
@@ -0,0 +1,26 @@
+dm-delay
+========
+
+Device-Mapper's "delay" target delays reads and/or writes
+and maps them to different devices.
+
+Parameters:
+ <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+
+With separate write parameters, the first set is only used for reads.
+Delays are specified in milliseconds.
+
+Example scripts
+===============
+[[
+#!/bin/sh
+# Create device delaying rw operation for 500ms
+echo "0 `blockdev --getsize $1` delay $1 0 500" | dmsetup create delayed
+]]
+
+[[
+#!/bin/sh
+# Create device delaying only write operation for 500ms and
+# splitting reads and writes to different devices $1 $2
+echo "0 `blockdev --getsize $1` delay $1 0 0 $2 0 500" | dmsetup create delayed
+]]
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 63c2d0c55aa..64e9f6c4826 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -55,8 +55,8 @@ aic7*seq.h*
aicasm
aicdb.h*
asm
-asm-offsets.*
-asm_offsets.*
+asm-offsets.h
+asm_offsets.h
autoconf.h*
bbootsect
bin2c
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 5163b85308f..6c8d8f27db3 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -182,7 +182,7 @@ For example, you can do something like the following.
...
- devres_close_group(dev, my_midlayer_something);
+ devres_close_group(dev, my_midlayer_create_something);
return 0;
}
diff --git a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt
index f7c9262b2dc..19c4a6e1367 100644
--- a/Documentation/driver-model/platform.txt
+++ b/Documentation/driver-model/platform.txt
@@ -16,7 +16,7 @@ host bridges to peripheral buses, and most controllers integrated
into system-on-chip platforms. What they usually have in common
is direct addressing from a CPU bus. Rarely, a platform_device will
be connected through a segment of some other kind of bus; but its
-registers will still be directly addressible.
+registers will still be directly addressable.
Platform devices are given a name, used in driver binding, and a
list of resources such as addresses and IRQs.
@@ -125,7 +125,7 @@ three different ways to find such a match:
usually register later during booting, or by module loading.
- Registering a driver using platform_driver_probe() works just like
- using platform_driver_register(), except that the the driver won't
+ using platform_driver_register(), except that the driver won't
be probed later if another device registers. (Which is OK, since
this interface is only for use with non-hotpluggable devices.)
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index 46b78b7331c..bf2a9cdfe7b 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -228,5 +228,5 @@ Patches, comments and suggestions are very very welcome.
Ulf Hermenau for helping me out with traditional chinese.
- André Smoktun and Christian Frömmel for supporting me with
+ André Smoktun and Christian Frömmel for supporting me with
hardware and listening to my problems very patiently.
diff --git a/Documentation/dvb/contributors.txt b/Documentation/dvb/contributors.txt
index 4c33cced5f6..4865addebe1 100644
--- a/Documentation/dvb/contributors.txt
+++ b/Documentation/dvb/contributors.txt
@@ -66,7 +66,7 @@ Michael Dreher <michael@5dot1.de>
Andreas 'randy' Weinberger
for the support of the Fujitsu-Siemens Activy budget DVB-S
-Kenneth Aafløy <ke-aa@frisurf.no>
+Kenneth Aafløy <ke-aa@frisurf.no>
for adding support for Typhoon DVB-S budget card
Ernst Peinlich <e.peinlich@inode.at>
diff --git a/Documentation/fb/arkfb.txt b/Documentation/fb/arkfb.txt
new file mode 100644
index 00000000000..e8487a9d6a0
--- /dev/null
+++ b/Documentation/fb/arkfb.txt
@@ -0,0 +1,68 @@
+
+ arkfb - fbdev driver for ARK Logic chips
+ ========================================
+
+
+Supported Hardware
+==================
+
+ ARK 2000PV chip
+ ICS 5342 ramdac
+
+ - only BIOS initialized VGA devices supported
+ - probably not working on big endian
+
+
+Supported Features
+==================
+
+ * 4 bpp pseudocolor modes (with 18bit palette, two variants)
+ * 8 bpp pseudocolor mode (with 18bit palette)
+ * 16 bpp truecolor modes (RGB 555 and RGB 565)
+ * 24 bpp truecolor mode (RGB 888)
+ * 32 bpp truecolor mode (RGB 888)
+ * text mode (activated by bpp = 0)
+ * doublescan mode variant (not available in text mode)
+ * panning in both directions
+ * suspend/resume support
+
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (i got maximum about 70 MHz, it is dependent on specific
+hardware). This limitation is not enforced by driver. Text mode supports 8bit
+wide fonts only (hardware limitation) and 16bit tall fonts (driver
+limitation). Unfortunately character attributes (like color) in text mode are
+broken for unknown reason, so its usefulness is limited.
+
+There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
+packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
+with interleaved planes (1 byte interleave), MSB first. Both modes support
+8bit wide fonts only (driver limitation).
+
+Suspend/resume works on systems that initialize video card during resume and
+if device is active (for example used by fbcon).
+
+
+Missing Features
+================
+(alias TODO list)
+
+ * secondary (not initialized by BIOS) device support
+ * big endian support
+ * DPMS support
+ * MMIO support
+ * interlaced mode variant
+ * support for fontwidths != 8 in 4 bpp modes
+ * support for fontheight != 16 in text mode
+ * hardware cursor
+ * vsync synchronization
+ * feature connector support
+ * acceleration support (8514-like 2D)
+
+
+Known bugs
+==========
+
+ * character attributes (and cursor) in text mode are broken
+
+--
+Ondrej Zajicek <santiago@crfreenet.org>
diff --git a/Documentation/fb/aty128fb.txt b/Documentation/fb/aty128fb.txt
index 069262fb619..b605204fcfe 100644
--- a/Documentation/fb/aty128fb.txt
+++ b/Documentation/fb/aty128fb.txt
@@ -54,8 +54,8 @@ Accepted options:
noaccel - do not use acceleration engine. It is default.
accel - use acceleration engine. Not finished.
-vmode:x - chooses PowerMacintosh video mode <x>. Depreciated.
-cmode:x - chooses PowerMacintosh colour mode <x>. Depreciated.
+vmode:x - chooses PowerMacintosh video mode <x>. Deprecated.
+cmode:x - chooses PowerMacintosh colour mode <x>. Deprecated.
<XxX@X> - selects startup videomode. See modedb.txt for detailed
explanation. Default is 640x480x8bpp.
diff --git a/Documentation/fb/deferred_io.txt b/Documentation/fb/deferred_io.txt
new file mode 100644
index 00000000000..73cf9fb7cf6
--- /dev/null
+++ b/Documentation/fb/deferred_io.txt
@@ -0,0 +1,75 @@
+Deferred IO
+-----------
+
+Deferred IO is a way to delay and repurpose IO. It uses host memory as a
+buffer and the MMU pagefault as a pretrigger for when to perform the device
+IO. The following example may be a useful explaination of how one such setup
+works:
+
+- userspace app like Xfbdev mmaps framebuffer
+- deferred IO and driver sets up nopage and page_mkwrite handlers
+- userspace app tries to write to mmaped vaddress
+- we get pagefault and reach nopage handler
+- nopage handler finds and returns physical page
+- we get page_mkwrite where we add this page to a list
+- schedule a workqueue task to be run after a delay
+- app continues writing to that page with no additional cost. this is
+ the key benefit.
+- the workqueue task comes in and mkcleans the pages on the list, then
+ completes the work associated with updating the framebuffer. this is
+ the real work talking to the device.
+- app tries to write to the address (that has now been mkcleaned)
+- get pagefault and the above sequence occurs again
+
+As can be seen from above, one benefit is roughly to allow bursty framebuffer
+writes to occur at minimum cost. Then after some time when hopefully things
+have gone quiet, we go and really update the framebuffer which would be
+a relatively more expensive operation.
+
+For some types of nonvolatile high latency displays, the desired image is
+the final image rather than the intermediate stages which is why it's okay
+to not update for each write that is occuring.
+
+It may be the case that this is useful in other scenarios as well. Paul Mundt
+has mentioned a case where it is beneficial to use the page count to decide
+whether to coalesce and issue SG DMA or to do memory bursts.
+
+Another one may be if one has a device framebuffer that is in an usual format,
+say diagonally shifting RGB, this may then be a mechanism for you to allow
+apps to pretend to have a normal framebuffer but reswizzle for the device
+framebuffer at vsync time based on the touched pagelist.
+
+How to use it: (for applications)
+---------------------------------
+No changes needed. mmap the framebuffer like normal and just use it.
+
+How to use it: (for fbdev drivers)
+----------------------------------
+The following example may be helpful.
+
+1. Setup your structure. Eg:
+
+static struct fb_deferred_io hecubafb_defio = {
+ .delay = HZ,
+ .deferred_io = hecubafb_dpy_deferred_io,
+};
+
+The delay is the minimum delay between when the page_mkwrite trigger occurs
+and when the deferred_io callback is called. The deferred_io callback is
+explained below.
+
+2. Setup your deferred IO callback. Eg:
+static void hecubafb_dpy_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+
+The deferred_io callback is where you would perform all your IO to the display
+device. You receive the pagelist which is the list of pages that were written
+to during the delay. You must not modify this list. This callback is called
+from a workqueue.
+
+3. Call init
+ info->fbdefio = &hecubafb_defio;
+ fb_deferred_io_init(info);
+
+4. Call cleanup
+ fb_deferred_io_cleanup(info);
diff --git a/Documentation/fb/framebuffer.txt b/Documentation/fb/framebuffer.txt
index 610e7801207..b3e3a035683 100644
--- a/Documentation/fb/framebuffer.txt
+++ b/Documentation/fb/framebuffer.txt
@@ -215,11 +215,11 @@ vertical retrace time is the sum of the upper margin, the lower margin and the
vsync length.
+----------+---------------------------------------------+----------+-------+
- | | ^ | | |
+ | | ↑ | | |
| | |upper_margin | | |
- | | ¥ | | |
+ | | ↓ | | |
+----------###############################################----------+-------+
- | # ^ # | |
+ | # ↑ # | |
| # | # | |
| # | # | |
| # | # | |
@@ -238,15 +238,15 @@ vsync length.
| # | # | |
| # | # | |
| # | # | |
- | # ¥ # | |
+ | # ↓ # | |
+----------###############################################----------+-------+
- | | ^ | | |
+ | | ↑ | | |
| | |lower_margin | | |
- | | ¥ | | |
+ | | ↓ | | |
+----------+---------------------------------------------+----------+-------+
- | | ^ | | |
+ | | ↑ | | |
| | |vsync_len | | |
- | | ¥ | | |
+ | | ↓ | | |
+----------+---------------------------------------------+----------+-------+
The frame buffer device expects all horizontal timings in number of dotclocks
diff --git a/Documentation/fb/imacfb.txt b/Documentation/fb/imacfb.txt
index 759028545a7..316ec9bb7de 100644
--- a/Documentation/fb/imacfb.txt
+++ b/Documentation/fb/imacfb.txt
@@ -17,7 +17,7 @@ How to use it?
==============
Imacfb does not have any kind of autodetection of your machine.
-You have to add the fillowing kernel parameters in your elilo.conf:
+You have to add the following kernel parameters in your elilo.conf:
Macbook :
video=imacfb:macbook
MacMini :
diff --git a/Documentation/fb/s3fb.txt b/Documentation/fb/s3fb.txt
index 8a04c0da0c9..2c97770bdba 100644
--- a/Documentation/fb/s3fb.txt
+++ b/Documentation/fb/s3fb.txt
@@ -35,10 +35,12 @@ Supported Features
* suspend/resume support
* DPMS support
-Text mode is supported even in higher resolutions, but there is limitation
-to lower pixclocks (maximum between 50-60 MHz, depending on specific hardware).
-This limitation is not enforced by driver. Text mode supports 8bit wide fonts
-only (hardware limitation) and 16bit tall fonts (driver limitation).
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (maximum usually between 50-60 MHz, depending on specific
+hardware, i get best results from plain S3 Trio32 card - about 75 MHz). This
+limitation is not enforced by driver. Text mode supports 8bit wide fonts only
+(hardware limitation) and 16bit tall fonts (driver limitation). Text mode
+support is broken on S3 Trio64 V2/DX.
There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
@@ -73,6 +75,8 @@ Known bugs
==========
* cursor disable in text mode doesn't work
+ * text mode broken on S3 Trio64 V2/DX
+
--
Ondrej Zajicek <santiago@crfreenet.org>
diff --git a/Documentation/fb/sstfb.txt b/Documentation/fb/sstfb.txt
index df27f5bf15d..550ca775a4c 100644
--- a/Documentation/fb/sstfb.txt
+++ b/Documentation/fb/sstfb.txt
@@ -2,9 +2,9 @@
Introduction
This is a frame buffer device driver for 3dfx' Voodoo Graphics
- (aka voodoo 1, aka sst1) and Voodoo² (aka Voodoo 2, aka CVG) based
+ (aka voodoo 1, aka sst1) and Voodoo² (aka Voodoo 2, aka CVG) based
video boards. It's highly experimental code, but is guaranteed to work
- on my computer, with my "Maxi Gamer 3D" and "Maxi Gamer 3d²" boards,
+ on my computer, with my "Maxi Gamer 3D" and "Maxi Gamer 3d²" boards,
and with me "between chair and keyboard". Some people tested other
combinations and it seems that it works.
The main page is located at <http://sstfb.sourceforge.net>, and if
diff --git a/Documentation/fb/vt8623fb.txt b/Documentation/fb/vt8623fb.txt
new file mode 100644
index 00000000000..f654576c56b
--- /dev/null
+++ b/Documentation/fb/vt8623fb.txt
@@ -0,0 +1,64 @@
+
+ vt8623fb - fbdev driver for graphics core in VIA VT8623 chipset
+ ===============================================================
+
+
+Supported Hardware
+==================
+
+ VIA VT8623 [CLE266] chipset and its graphics core
+ (known as CastleRock or Unichrome)
+
+I tested vt8623fb on VIA EPIA ML-6000
+
+
+Supported Features
+==================
+
+ * 4 bpp pseudocolor modes (with 18bit palette, two variants)
+ * 8 bpp pseudocolor mode (with 18bit palette)
+ * 16 bpp truecolor mode (RGB 565)
+ * 32 bpp truecolor mode (RGB 888)
+ * text mode (activated by bpp = 0)
+ * doublescan mode variant (not available in text mode)
+ * panning in both directions
+ * suspend/resume support
+ * DPMS support
+
+Text mode is supported even in higher resolutions, but there is limitation to
+lower pixclocks (maximum about 100 MHz). This limitation is not enforced by
+driver. Text mode supports 8bit wide fonts only (hardware limitation) and
+16bit tall fonts (driver limitation).
+
+There are two 4 bpp modes. First mode (selected if nonstd == 0) is mode with
+packed pixels, high nibble first. Second mode (selected if nonstd == 1) is mode
+with interleaved planes (1 byte interleave), MSB first. Both modes support
+8bit wide fonts only (driver limitation).
+
+Suspend/resume works on systems that initialize video card during resume and
+if device is active (for example used by fbcon).
+
+
+Missing Features
+================
+(alias TODO list)
+
+ * secondary (not initialized by BIOS) device support
+ * MMIO support
+ * interlaced mode variant
+ * support for fontwidths != 8 in 4 bpp modes
+ * support for fontheight != 16 in text mode
+ * hardware cursor
+ * video overlay support
+ * vsync synchronization
+ * acceleration support (8514-like 2D, busmaster transfers)
+
+
+Known bugs
+==========
+
+ * cursor disable in text mode doesn't work
+
+
+--
+Ondrej Zajicek <santiago@crfreenet.org>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 5c88ba1ea26..676b7981adb 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -6,6 +6,14 @@ be removed from this file.
---------------------------
+What: MXSER
+When: December 2007
+Why: Old mxser driver is obsoleted by the mxser_new. Give it some time yet
+ and remove it.
+Who: Jiri Slaby <jirislaby@gmail.com>
+
+---------------------------
+
What: V4L2 VIDIOC_G_MPEGCOMP and VIDIOC_S_MPEGCOMP
When: October 2007
Why: Broken attempt to set MPEG compression parameters. These ioctls are
@@ -51,6 +59,15 @@ Who: Dan Dennedy <dan@dennedy.org>, Stefan Richter <stefanr@s5r6.in-berlin.de>
---------------------------
+What: old NCR53C9x driver
+When: October 2007
+Why: Replaced by the much better esp_scsi driver. Actual low-level
+ driver can ported over almost trivially.
+Who: David Miller <davem@davemloft.net>
+ Christoph Hellwig <hch@lst.de>
+
+---------------------------
+
What: Video4Linux API 1 ioctls and video_decoder.h from Video devices.
When: December 2006
Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
@@ -117,25 +134,6 @@ Who: Adrian Bunk <bunk@stusta.de>
---------------------------
-What: pci_module_init(driver)
-When: January 2007
-Why: Is replaced by pci_register_driver(pci_driver).
-Who: Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@suse.de>
-
----------------------------
-
-What: Usage of invalid timevals in setitimer
-When: March 2007
-Why: POSIX requires to validate timevals in the setitimer call. This
- was never done by Linux. The invalid (e.g. negative timevals) were
- silently converted to more or less random timeouts and intervals.
- Until the removal a per boot limited number of warnings is printed
- and the timevals are sanitized.
-
-Who: Thomas Gleixner <tglx@linutronix.de>
-
----------------------------
-
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.
@@ -163,7 +161,7 @@ Who: Greg Kroah-Hartman <gregkh@suse.de>
---------------------------
What: Interrupt only SA_* flags
-When: Januar 2007
+When: September 2007
Why: The interrupt related SA_* flags are replaced by IRQF_* to move them
out of the signal namespace.
@@ -190,18 +188,10 @@ Who: Jean Delvare <khali@linux-fr.org>
---------------------------
-What: i2c_adapter.dev
- i2c_adapter.list
+What: i2c_adapter.list
When: July 2007
-Why: Superfluous, given i2c_adapter.class_dev:
- * The "dev" was a stand-in for the physical device node that legacy
- drivers would not have; but now it's almost always present. Any
- remaining legacy drivers must upgrade (they now trigger warnings).
- * The "list" duplicates class device children.
- The delay in removing this is so upgraded lm_sensors and libsensors
- can get deployed. (Removal causes minor changes in the sysfs layout,
- notably the location of the adapter type name and parenting the i2c
- client hardware directly from their controller.)
+Why: Superfluous, this list duplicates the one maintained by the driver
+ core.
Who: Jean Delvare <khali@linux-fr.org>,
David Brownell <dbrownell@users.sourceforge.net>
@@ -314,3 +304,35 @@ Why: Code was merged, then submitter immediately disappeared leaving
Who: David S. Miller <davem@davemloft.net>
---------------------------
+
+What: read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer)
+When: December 2007
+Why: These functions are a leftover from 2.4 times. They have several
+ problems:
+ - Duplication of checks that are done in the device driver's
+ interrupt handler
+ - common I/O layer can't do device specific error recovery
+ - device driver can't be notified for conditions happening during
+ execution of the function
+ Device drivers should issue the read device characteristics and read
+ configuration data ccws and do the appropriate error handling
+ themselves.
+Who: Cornelia Huck <cornelia.huck@de.ibm.com>
+
+---------------------------
+
+What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers
+When: September 2007
+Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific
+ I2C-over-GPIO drivers.
+Who: Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
+What: drivers depending on OSS_OBSOLETE
+When: options in 2.6.23, code in 2.6.25
+Why: obsolete OSS drivers
+Who: Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 28bfea75bcf..d866551be03 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -15,6 +15,7 @@ prototypes:
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
+ char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
locking rules:
none have BKL
@@ -25,6 +26,7 @@ d_compare: no yes no no
d_delete: yes no yes no
d_release: no no no yes
d_iput: no no no yes
+d_dname: no no no no
--------------------------- inode_operations ---------------------------
prototypes:
@@ -52,7 +54,7 @@ ata *);
locking rules:
all may block, none have BKL
- i_sem(inode)
+ i_mutex(inode)
lookup: yes
create: yes
link: yes (both)
@@ -72,7 +74,7 @@ setxattr: yes
getxattr: no
listxattr: no
removexattr: yes
- Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_sem on
+ Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
victim.
cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
->truncate() is never called directly - it's a callback, not a
@@ -459,7 +461,7 @@ doesn't take the BKL.
->read on directories probably must go away - we should just enforce -EISDIR
in sys_read() and friends.
-->fsync() has i_sem on inode.
+->fsync() has i_mutex on inode.
--------------------------- dquot_operations -------------------------------
prototypes:
diff --git a/Documentation/filesystems/hpfs.txt b/Documentation/filesystems/hpfs.txt
index 38aba03efc5..fa45c3baed9 100644
--- a/Documentation/filesystems/hpfs.txt
+++ b/Documentation/filesystems/hpfs.txt
@@ -290,7 +290,7 @@ History
2.07 More fixes for Warp Server. Now it really works
2.08 Creating new files is not so slow on large disks
An attempt to sync deleted file does not generate filesystem error
-2.09 Fixed error on extremly fragmented files
+2.09 Fixed error on extremely fragmented files
vim: set textwidth=80:
diff --git a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt
index bae12866374..26ebde77e82 100644
--- a/Documentation/filesystems/jfs.txt
+++ b/Documentation/filesystems/jfs.txt
@@ -29,7 +29,13 @@ errors=continue Keep going on a filesystem error.
errors=remount-ro Default. Remount the filesystem read-only on an error.
errors=panic Panic and halt the machine if an error occurs.
-Please send bugs, comments, cards and letters to shaggy@austin.ibm.com.
+uid=value Override on-disk uid with specified value
+gid=value Override on-disk gid with specified value
+umask=value Override on-disk umask with specified octal value. For
+ directories, the execute bit will be set if the corresponding
+ read bit is set.
+
+Please send bugs, comments, cards and letters to shaggy@linux.vnet.ibm.com.
The JFS mailing list can be subscribed to by using the link labeled
"Mail list Subscribe" at our web page http://jfs.sourceforge.net/
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 81779068b09..8ee10ec8829 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -349,7 +349,7 @@ end of the line.
Note the "Should sync?" parameter "nosync" means that the two mirrors are
already in sync which will be the case on a clean shutdown of Windows. If the
mirrors are not clean, you can specify the "sync" option instead of "nosync"
-and the Device-Mapper driver will then copy the entirey of the "Source Device"
+and the Device-Mapper driver will then copy the entirety of the "Source Device"
to the "Target Device" or if you specified multipled target devices to all of
them.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 7aaf09b86a5..8756a07f4dc 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -122,21 +122,22 @@ subdirectory has the entries listed in Table 1-1.
Table 1-1: Process specific entries in /proc
..............................................................................
- File Content
- cmdline Command line arguments
- cpu Current and last cpu in which it was executed (2.4)(smp)
- cwd Link to the current working directory
- environ Values of environment variables
- exe Link to the executable of this process
- fd Directory, which contains all file descriptors
- maps Memory maps to executables and library files (2.4)
- mem Memory held by this process
- root Link to the root directory of this process
- stat Process status
- statm Process memory status information
- status Process status in human readable form
- wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan
- smaps Extension based on maps, presenting the rss size for each mapped file
+ File Content
+ clear_refs Clears page referenced bits shown in smaps output
+ cmdline Command line arguments
+ cpu Current and last cpu in which it was executed (2.4)(smp)
+ cwd Link to the current working directory
+ environ Values of environment variables
+ exe Link to the executable of this process
+ fd Directory, which contains all file descriptors
+ maps Memory maps to executables and library files (2.4)
+ mem Memory held by this process
+ root Link to the root directory of this process
+ stat Process status
+ statm Process memory status information
+ status Process status in human readable form
+ wchan If CONFIG_KALLSYMS is set, a pre-decoded wchan
+ smaps Extension based on maps, the rss size for each mapped file
..............................................................................
For example, to get the status information of a process, all you have to do is
@@ -228,7 +229,7 @@ Table 1-3: Kernel info in /proc
mounts Mounted filesystems
net Networking info (see text)
partitions Table of partitions known to the system
- pci Depreciated info of PCI bus (new way -> /proc/bus/pci/,
+ pci Deprecated info of PCI bus (new way -> /proc/bus/pci/,
decoupled by lspci (2.4)
rtc Real time clock
scsi SCSI info (see text)
@@ -1137,6 +1138,13 @@ determine whether or not they are still functioning properly.
Because the NMI watchdog shares registers with oprofile, by disabling the NMI
watchdog, oprofile may have more registers to utilize.
+maps_protect
+------------
+
+Enables/Disables the protection of the per-process proc entries "maps" and
+"smaps". When enabled, the contents of these files are visible only to
+readers that are allowed to ptrace() the given process.
+
2.4 /proc/sys/vm - The virtual memory subsystem
-----------------------------------------------
diff --git a/Documentation/filesystems/relay.txt b/Documentation/filesystems/relay.txt
index 7fbb6ffe576..18d23f9a18c 100644
--- a/Documentation/filesystems/relay.txt
+++ b/Documentation/filesystems/relay.txt
@@ -351,7 +351,7 @@ If the current buffer is full, i.e. all sub-buffers remain unconsumed,
the callback returns 0 to indicate that the buffer switch should not
occur yet, i.e. until the consumer has had a chance to read the
current set of ready sub-buffers. For the relay_buf_full() function
-to make sense, the consumer is reponsible for notifying the relay
+to make sense, the consumer is responsible for notifying the relay
interface when sub-buffers have been consumed via
relay_subbufs_consumed(). Any subsequent attempts to write into the
buffer will again invoke the subbuf_start() callback with the same
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index 069cb109430..fcc123ffa25 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -57,6 +57,13 @@ nonumtail=<bool> -- When creating 8.3 aliases, normally the alias will
currently exist in the directory, 'longfile.txt' will
be the short alias instead of 'longfi~1.txt'.
+usefree -- Use the "free clusters" value stored on FSINFO. It'll
+ be used to determine number of free clusters without
+ scanning disk. But it's not used by default, because
+ recent Windows don't update it correctly in some
+ case. If you are sure the "free clusters" on FSINFO is
+ correct, by this option you can avoid scanning disk.
+
quiet -- Stops printing certain warning messages.
check=s|r|n -- Case sensitivity checking setting.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index ea271f2d395..a47cc819f37 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -827,7 +827,7 @@ This describes how a filesystem can overload the standard dentry
operations. Dentries and the dcache are the domain of the VFS and the
individual filesystem implementations. Device drivers have no business
here. These methods may be set to NULL, as they are either optional or
-the VFS uses a default. As of kernel 2.6.13, the following members are
+the VFS uses a default. As of kernel 2.6.22, the following members are
defined:
struct dentry_operations {
@@ -837,6 +837,7 @@ struct dentry_operations {
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
+ char *(*d_dname)(struct dentry *, char *, int);
};
d_revalidate: called when the VFS needs to revalidate a dentry. This
@@ -859,6 +860,26 @@ struct dentry_operations {
VFS calls iput(). If you define this method, you must call
iput() yourself
+ d_dname: called when the pathname of a dentry should be generated.
+ Usefull for some pseudo filesystems (sockfs, pipefs, ...) to delay
+ pathname generation. (Instead of doing it when dentry is created,
+ its done only when the path is needed.). Real filesystems probably
+ dont want to use it, because their dentries are present in global
+ dcache hash, so their hash should be an invariant. As no lock is
+ held, d_dname() should not try to modify the dentry itself, unless
+ appropriate SMP safety is used. CAUTION : d_path() logic is quite
+ tricky. The correct way to return for example "Hello" is to put it
+ at the end of the buffer, and returns a pointer to the first char.
+ dynamic_dname() helper function is provided to take care of this.
+
+Example :
+
+static char *pipefs_dname(struct dentry *dent, char *buffer, int buflen)
+{
+ return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+ dentry->d_inode->i_ino);
+}
+
Each dentry has a pointer to its parent dentry, as well as a hash list
of child dentries. Child dentries are basically like files in a
directory.
diff --git a/Documentation/filesystems/xip.txt b/Documentation/filesystems/xip.txt
index 6c0cef10eb4..3cc4010521a 100644
--- a/Documentation/filesystems/xip.txt
+++ b/Documentation/filesystems/xip.txt
@@ -19,7 +19,7 @@ completely. With execute-in-place, read&write type operations are performed
directly from/to the memory backed storage device. For file mappings, the
storage device itself is mapped directly into userspace.
-This implementation was initialy written for shared memory segments between
+This implementation was initially written for shared memory segments between
different virtual machines on s390 hardware to allow multiple machines to
share the same binaries and libraries.
diff --git a/Documentation/fujitsu/frv/gdbstub.txt b/Documentation/fujitsu/frv/gdbstub.txt
index 9304fb36ae8..b92bfd902a4 100644
--- a/Documentation/fujitsu/frv/gdbstub.txt
+++ b/Documentation/fujitsu/frv/gdbstub.txt
@@ -126,5 +126,5 @@ GDB stub and the debugger:
Furthermore, the GDB stub will intercept a number of exceptions automatically
if they are caused by kernel execution. It will also intercept BUG() macro
-invokation.
+invocation.
diff --git a/Documentation/hwmon/adm1026 b/Documentation/hwmon/adm1026
index 473c689d792..f4327db2307 100644
--- a/Documentation/hwmon/adm1026
+++ b/Documentation/hwmon/adm1026
@@ -80,7 +80,7 @@ temperature sensor inputs. Both the PWM output and the DAC output can be
used to control fan speed. Usually only one of these two outputs will be
used. Write the minimum PWM or DAC value to the appropriate control
register. Then set the low temperature limit in the tmin values for each
-temperature sensor. The range of control is fixed at 20 °C, and the
+temperature sensor. The range of control is fixed at 20 °C, and the
largest difference between current and tmin of the temperature sensors sets
the control output. See the datasheet for several example circuits for
controlling fan speed with the PWM and DAC outputs. The fan speed sensors
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
new file mode 100644
index 00000000000..870cda9416e
--- /dev/null
+++ b/Documentation/hwmon/coretemp
@@ -0,0 +1,36 @@
+Kernel driver coretemp
+======================
+
+Supported chips:
+ * All Intel Core family
+ Prefix: 'coretemp'
+ CPUID: family 0x6, models 0xe, 0xf
+ Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual
+ Volume 3A: System Programming Guide
+
+Author: Rudolf Marek
+
+Description
+-----------
+
+This driver permits reading temperature sensor embedded inside Intel Core CPU.
+Temperature is measured in degrees Celsius and measurement resolution is
+1 degree C. Valid temperatures are from 0 to TjMax degrees C, because
+the actual value of temperature register is in fact a delta from TjMax.
+
+Temperature known as TjMax is the maximum junction temperature of processor.
+Intel defines this temperature as 85C or 100C. At this temperature, protection
+mechanism will perform actions to forcibly cool down the processor. Alarm
+may be raised, if the temperature grows enough (more than TjMax) to trigger
+the Out-Of-Spec bit. Following table summarizes the exported sysfs files:
+
+temp1_input - Core temperature (in millidegrees Celsius).
+temp1_crit - Maximum junction temperature (in millidegrees Celsius).
+temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
+ Correct CPU operation is no longer guaranteed.
+temp1_label - Contains string "Core X", where X is processor
+ number.
+
+The TjMax temperature is set to 85 degrees C if undocumented model specific
+register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as
+(sometimes) documented in processor datasheet.
diff --git a/Documentation/hwmon/gl518sm b/Documentation/hwmon/gl518sm
index ce0881883bc..229f8b78918 100644
--- a/Documentation/hwmon/gl518sm
+++ b/Documentation/hwmon/gl518sm
@@ -13,7 +13,7 @@ Supported chips:
Authors:
Frodo Looijaard <frodol@dds.nl>,
- Kyösti Mälkki <kmalkki@cc.hut.fi>
+ Kyösti Mälkki <kmalkki@cc.hut.fi>
Hong-Gunn Chew <hglinux@gunnet.org>
Jean Delvare <khali@linux-fr.org>
diff --git a/Documentation/hwmon/lm83 b/Documentation/hwmon/lm83
index f7aad1489cb..a04d1fe9269 100644
--- a/Documentation/hwmon/lm83
+++ b/Documentation/hwmon/lm83
@@ -45,7 +45,7 @@ Unconfirmed motherboards:
The LM82 is confirmed to have been found on most AMD Geode reference
designs and test platforms.
-The driver has been successfully tested by Magnus Forsström, who I'd
+The driver has been successfully tested by Magnus Forsström, who I'd
like to thank here. More testers will be of course welcome.
The fact that the LM83 is only scarcely used can be easily explained.
diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650
new file mode 100644
index 00000000000..8be7beb9e3e
--- /dev/null
+++ b/Documentation/hwmon/max6650
@@ -0,0 +1,53 @@
+Kernel driver max6650
+=====================
+
+Supported chips:
+ * Maxim 6650 / 6651
+ Prefix: 'max6650'
+ Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b
+ Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+
+Authors:
+ Hans J. Koch <hjk@linutronix.de>
+ John Morris <john.morris@spirentcom.com>
+ Claus Gindhart <claus.gindhart@kontron.com>
+
+Description
+-----------
+
+This driver implements support for the Maxim 6650/6651
+
+The 2 devices are very similar, but the Maxim 6550 has a reduced feature
+set, e.g. only one fan-input, instead of 4 for the 6651.
+
+The driver is not able to distinguish between the 2 devices.
+
+The driver provides the following sensor accesses in sysfs:
+
+fan1_input ro fan tachometer speed in RPM
+fan2_input ro "
+fan3_input ro "
+fan4_input ro "
+fan1_target rw desired fan speed in RPM (closed loop mode only)
+pwm1_enable rw regulator mode, 0=full on, 1=open loop, 2=closed loop
+pwm1 rw relative speed (0-255), 255=max. speed.
+ Used in open loop mode only.
+fan1_div rw sets the speed range the inputs can handle. Legal
+ values are 1, 2, 4, and 8. Use lower values for
+ faster fans.
+
+Module parameters
+-----------------
+
+If your board has a BIOS that initializes the MAX6650/6651 correctly, you can
+simply load your module without parameters. It won't touch the configuration
+registers then. If your board BIOS doesn't initialize the chip, or you want
+different settings, you can set the following parameters:
+
+voltage_12V: 5=5V fan, 12=12V fan, 0=don't change
+prescaler: Possible values are 1,2,4,8,16, or 0 for don't change
+clock: The clock frequency in Hz of the chip the driver should assume [254000]
+
+Please have a look at the MAX6650/6651 data sheet and make sure that you fully
+understand the meaning of these parameters before you attempt to change them.
+
diff --git a/Documentation/hwmon/sis5595 b/Documentation/hwmon/sis5595
index b7ae36b8cdf..4f8877a34f3 100644
--- a/Documentation/hwmon/sis5595
+++ b/Documentation/hwmon/sis5595
@@ -8,7 +8,7 @@ Supported chips:
Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
Authors:
- Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
Aurelien Jarno <aurelien@aurel32.net> 2.6 port
diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1
index 04a11124f66..42c8431b3c9 100644
--- a/Documentation/hwmon/smsc47m1
+++ b/Documentation/hwmon/smsc47m1
@@ -14,6 +14,10 @@ Supported chips:
http://www.smsc.com/main/datasheets/47m14x.pdf
http://www.smsc.com/main/tools/discontinued/47m15x.pdf
http://www.smsc.com/main/datasheets/47m192.pdf
+ * SMSC LPC47M292
+ Addresses scanned: none, address read from Super I/O config space
+ Prefix: 'smsc47m2'
+ Datasheet: Not public
* SMSC LPC47M997
Addresses scanned: none, address read from Super I/O config space
Prefix: 'smsc47m1'
@@ -32,9 +36,10 @@ Description
The Standard Microsystems Corporation (SMSC) 47M1xx Super I/O chips
contain monitoring and PWM control circuitry for two fans.
-The 47M15x and 47M192 chips contain a full 'hardware monitoring block'
-in addition to the fan monitoring and control. The hardware monitoring
-block is not supported by the driver.
+The LPC47M15x, LPC47M192 and LPC47M292 chips contain a full 'hardware
+monitoring block' in addition to the fan monitoring and control. The
+hardware monitoring block is not supported by this driver, use the
+smsc47m192 driver for that.
No documentation is available for the 47M997, but it has the same device
ID as the 47M15x and 47M192 chips and seems to be compatible.
diff --git a/Documentation/hwmon/smsc47m192 b/Documentation/hwmon/smsc47m192
index 45d6453cd43..6d54ecb7b3f 100644
--- a/Documentation/hwmon/smsc47m192
+++ b/Documentation/hwmon/smsc47m192
@@ -2,12 +2,13 @@ Kernel driver smsc47m192
========================
Supported chips:
- * SMSC LPC47M192 and LPC47M997
+ * SMSC LPC47M192, LPC47M15x, LPC47M292 and LPC47M997
Prefix: 'smsc47m192'
Addresses scanned: I2C 0x2c - 0x2d
Datasheet: The datasheet for LPC47M192 is publicly available from
http://www.smsc.com/
- The LPC47M997 is compatible for hardware monitoring.
+ The LPC47M15x, LPC47M292 and LPC47M997 are compatible for
+ hardware monitoring.
Author: Hartmut Rick <linux@rick.claranet.de>
Special thanks to Jean Delvare for careful checking
@@ -18,7 +19,7 @@ Description
-----------
This driver implements support for the hardware sensor capabilities
-of the SMSC LPC47M192 and LPC47M997 Super-I/O chips.
+of the SMSC LPC47M192 and compatible Super-I/O chips.
These chips support 3 temperature channels and 8 voltage inputs
as well as CPU voltage VID input.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index d73d2e8c753..a9a18ad0d17 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -152,6 +152,13 @@ fan[1-*]_div Fan divisor.
Note that this is actually an internal clock divisor, which
affects the measurable speed range, not the read value.
+fan[1-*]_target
+ Desired fan speed
+ Unit: revolution/min (RPM)
+ RW
+ Only makes sense if the chip supports closed-loop fan speed
+ control based on the measured fan speed.
+
Also see the Alarms section for status flags associated with fans.
diff --git a/Documentation/hwmon/via686a b/Documentation/hwmon/via686a
index a936fb3824b..d651b25f751 100644
--- a/Documentation/hwmon/via686a
+++ b/Documentation/hwmon/via686a
@@ -8,7 +8,7 @@ Supported chips:
Datasheet: On request through web form (http://www.via.com.tw/en/support/datasheets/)
Authors:
- Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>
Bob Dougherty <bobd@stanford.edu>
(Some conversion-factor data were contributed by
diff --git a/Documentation/hwmon/w83792d b/Documentation/hwmon/w83792d
index 8171c285bb5..14a668ed8aa 100644
--- a/Documentation/hwmon/w83792d
+++ b/Documentation/hwmon/w83792d
@@ -107,7 +107,7 @@ Known problems:
by CR[0x49h].
- The function of vid and vrm has not been finished, because I'm NOT
very familiar with them. Adding support is welcome.
-  - The function of chassis open detection needs more tests.
+  - The function of chassis open detection needs more tests.
- If you have ASUS server board and chip was not found: Then you will
need to upgrade to latest (or beta) BIOS. If it does not help please
contact us.
diff --git a/Documentation/i2c/busses/i2c-i810 b/Documentation/i2c/busses/i2c-i810
index 83c3b9743c3..778210ee158 100644
--- a/Documentation/i2c/busses/i2c-i810
+++ b/Documentation/i2c/busses/i2c-i810
@@ -7,7 +7,7 @@ Supported adapters:
Authors:
Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
- Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
Ralph Metzler <rjkm@thp.uni-koeln.de>,
Mark D. Studebaker <mdsxyz123@yahoo.com>
diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2
index 7f61fbc03f7..fae3495bcba 100644
--- a/Documentation/i2c/busses/i2c-nforce2
+++ b/Documentation/i2c/busses/i2c-nforce2
@@ -9,6 +9,8 @@ Supported adapters:
* nForce4 MCP-04 10de:0034
* nForce4 MCP51 10de:0264
* nForce4 MCP55 10de:0368
+ * nForce4 MCP61 10de:03EB
+ * nForce4 MCP65 10de:0446
Datasheet: not publicly available, but seems to be similar to the
AMD-8111 SMBus 2.0 adapter.
diff --git a/Documentation/i2c/busses/i2c-sis96x b/Documentation/i2c/busses/i2c-sis96x
index 08d7b2dac69..266481fd26e 100644
--- a/Documentation/i2c/busses/i2c-sis96x
+++ b/Documentation/i2c/busses/i2c-sis96x
@@ -60,7 +60,7 @@ Mark D. Studebaker <mdsxyz123@yahoo.com>
- design hints and bug fixes
Alexander Maylsh <amalysh@web.de>
- ditto, plus an important datasheet... almost the one I really wanted
-Hans-Günter Lütke Uphues <hg_lu@t-online.de>
+Hans-Günter Lütke Uphues <hg_lu@t-online.de>
- patch for SiS735
Robert Zwerus <arzie@dds.nl>
- testing for SiS645DX
diff --git a/Documentation/i2c/busses/i2c-via b/Documentation/i2c/busses/i2c-via
index 55edfe1a640..343870661ac 100644
--- a/Documentation/i2c/busses/i2c-via
+++ b/Documentation/i2c/busses/i2c-via
@@ -4,7 +4,7 @@ Supported adapters:
* VIA Technologies, InC. VT82C586B
Datasheet: Publicly available at the VIA website
-Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
+Author: Kyösti Mälkki <kmalkki@cc.hut.fi>
Description
-----------
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 775f489e86f..06b4be3ef6d 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -17,7 +17,7 @@ Supported adapters:
Datasheet: available on request and under NDA from VIA
Authors:
- Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
Jean Delvare <khali@linux-fr.org>
diff --git a/Documentation/i2c/i2c-protocol b/Documentation/i2c/i2c-protocol
index b4022c91421..579b92d5f3a 100644
--- a/Documentation/i2c/i2c-protocol
+++ b/Documentation/i2c/i2c-protocol
@@ -68,7 +68,7 @@ We have found some I2C devices that needs the following modifications:
Flags I2C_M_IGNORE_NAK
Normally message is interrupted immediately if there is [NA] from the
- client. Setting this flag treats any [NA] as [A], and all of
+ client. Setting this flag treats any [NA] as [A], and all of
message is sent.
These messages may still fail to SCL lo->hi timeout.
diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients
index ca272b263a9..7bf82c08f6c 100644
--- a/Documentation/i2c/porting-clients
+++ b/Documentation/i2c/porting-clients
@@ -1,4 +1,4 @@
-Revision 6, 2005-11-20
+Revision 7, 2007-04-19
Jean Delvare <khali@linux-fr.org>
Greg KH <greg@kroah.com>
@@ -20,6 +20,10 @@ yours for best results.
Technical changes:
+* [Driver type] Any driver that was relying on i2c-isa has to be
+ converted to a proper isa, platform or pci driver. This is not
+ covered by this guide.
+
* [Includes] Get rid of "version.h" and <linux/i2c-proc.h>.
Includes typically look like that:
#include <linux/module.h>
@@ -27,12 +31,10 @@ Technical changes:
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
- #include <linux/i2c-isa.h> /* for ISA drivers */
#include <linux/hwmon.h> /* for hardware monitoring drivers */
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h> /* if you need VRM support */
#include <linux/err.h> /* for class registration */
- #include <asm/io.h> /* if you have I/O operations */
Please respect this inclusion order. Some extra headers may be
required for a given driver (e.g. "lm75.h").
@@ -69,20 +71,16 @@ Technical changes:
sensors mailing list <lm-sensors@lm-sensors.org> by providing a
patch to the Documentation/hwmon/sysfs-interface file.
-* [Attach] For I2C drivers, the attach function should make sure
- that the adapter's class has I2C_CLASS_HWMON (or whatever class is
- suitable for your driver), using the following construct:
+* [Attach] The attach function should make sure that the adapter's
+ class has I2C_CLASS_HWMON (or whatever class is suitable for your
+ driver), using the following construct:
if (!(adapter->class & I2C_CLASS_HWMON))
return 0;
- ISA-only drivers of course don't need this.
Call i2c_probe() instead of i2c_detect().
* [Detect] As mentioned earlier, the flags parameter is gone.
The type_name and client_name strings are replaced by a single
name string, which will be filled with a lowercase, short string.
- In i2c-only drivers, drop the i2c_is_isa_adapter check, it's
- useless. Same for isa-only drivers, as the test would always be
- true. Only hybrid drivers (which are quite rare) still need it.
The labels used for error paths are reduced to the number needed.
It is advised that the labels are given descriptive names such as
exit and exit_free. Don't forget to properly set err before
diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary
index 41dde877679..aea60bf7e8f 100644
--- a/Documentation/i2c/summary
+++ b/Documentation/i2c/summary
@@ -4,17 +4,23 @@ I2C and SMBus
=============
I2C (pronounce: I squared C) is a protocol developed by Philips. It is a
-slow two-wire protocol (10-400 kHz), but it suffices for many types of
-devices.
+slow two-wire protocol (variable speed, up to 400 kHz), with a high speed
+extension (3.4 MHz). It provides an inexpensive bus for connecting many
+types of devices with infrequent or low bandwidth communications needs.
+I2C is widely used with embedded systems. Some systems use variants that
+don't meet branding requirements, and so are not advertised as being I2C.
-SMBus (System Management Bus) is a subset of the I2C protocol. Many
-modern mainboards have a System Management Bus. There are a lot of
-devices which can be connected to a SMBus; the most notable are modern
-memory chips with EEPROM memories and chips for hardware monitoring.
+SMBus (System Management Bus) is based on the I2C protocol, and is mostly
+a subset of I2C protocols and signaling. Many I2C devices will work on an
+SMBus, but some SMBus protocols add semantics beyond what is required to
+achieve I2C branding. Modern PC mainboards rely on SMBus. The most common
+devices connected through SMBus are RAM modules configured using I2C EEPROMs,
+and hardware monitoring chips.
-Because the SMBus is just a special case of the generalized I2C bus, we
-can simulate the SMBus protocol on plain I2C busses. The reverse is
-regretfully impossible.
+Because the SMBus is mostly a subset of the generalized I2C bus, we can
+use its protocols on many I2C systems. However, there are systems that don't
+meet both SMBus and I2C electrical constraints; and others which can't
+implement all the common SMBus protocol semantics or messages.
Terminology
@@ -29,6 +35,7 @@ When we talk about I2C, we use the following terms:
An Algorithm driver contains general code that can be used for a whole class
of I2C adapters. Each specific adapter driver depends on one algorithm
driver.
+
A Driver driver (yes, this sounds ridiculous, sorry) contains the general
code to access some type of device. Each detected device gets its own
data in the Client structure. Usually, Driver and Client are more closely
@@ -40,6 +47,10 @@ a separate Adapter and Algorithm driver), and drivers for your I2C devices
in this package. See the lm_sensors project http://www.lm-sensors.nu
for device drivers.
+At this time, Linux only operates I2C (or SMBus) in master mode; you can't
+use these APIs to make a Linux system behave as a slave/device, either to
+speak a custom protocol or to emulate some other device.
+
Included Bus Drivers
====================
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index fbcff96f4ca..3d8d36b0ad1 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -1,5 +1,5 @@
This is a small guide for those who want to write kernel drivers for I2C
-or SMBus devices.
+or SMBus devices, using Linux as the protocol host/master (not slave).
To set up a driver, you need to do several things. Some are optional, and
some things can be done slightly or completely different. Use this as a
@@ -29,8 +29,16 @@ static struct i2c_driver foo_driver = {
.driver = {
.name = "foo",
},
+
+ /* iff driver uses driver model ("new style") binding model: */
+ .probe = foo_probe,
+ .remove = foo_remove,
+
+ /* else, driver uses "legacy" binding model: */
.attach_adapter = foo_attach_adapter,
.detach_client = foo_detach_client,
+
+ /* these may be used regardless of the driver binding model */
.shutdown = foo_shutdown, /* optional */
.suspend = foo_suspend, /* optional */
.resume = foo_resume, /* optional */
@@ -40,7 +48,8 @@ static struct i2c_driver foo_driver = {
The name field is the driver name, and must not contain spaces. It
should match the module name (if the driver can be compiled as a module),
although you can use MODULE_ALIAS (passing "foo" in this example) to add
-another name for the module.
+another name for the module. If the driver name doesn't match the module
+name, the module won't be automatically loaded (hotplug/coldplug).
All other fields are for call-back functions which will be explained
below.
@@ -65,16 +74,13 @@ An example structure is below.
struct foo_data {
struct i2c_client client;
- struct semaphore lock; /* For ISA access in `sensors' drivers. */
- int sysctl_id; /* To keep the /proc directory entry for
- `sensors' drivers. */
enum chips type; /* To keep the chips type for `sensors' drivers. */
/* Because the i2c bus is slow, it is often useful to cache the read
information of a chip for some time (for example, 1 or 2 seconds).
It depends of course on the device whether this is really worthwhile
or even sensible. */
- struct semaphore update_lock; /* When we are reading lots of information,
+ struct mutex update_lock; /* When we are reading lots of information,
another process should not update the
below information */
char valid; /* != 0 if the following fields are valid. */
@@ -95,8 +101,7 @@ some obscure clients). But we need generic reading and writing routines.
I have found it useful to define foo_read and foo_write function for this.
For some cases, it will be easier to call the i2c functions directly,
but many chips have some kind of register-value idea that can easily
-be encapsulated. Also, some chips have both ISA and I2C interfaces, and
-it useful to abstract from this (only for `sensors' drivers).
+be encapsulated.
The below functions are simple examples, and should not be copied
literally.
@@ -119,28 +124,101 @@ literally.
return i2c_smbus_write_word_data(client,reg,value);
}
-For sensors code, you may have to cope with ISA registers too. Something
-like the below often works. Note the locking!
-
- int foo_read_value(struct i2c_client *client, u8 reg)
- {
- int res;
- if (i2c_is_isa_client(client)) {
- down(&(((struct foo_data *) (client->data)) -> lock));
- outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET);
- res = inb_p(client->addr + FOO_DATA_REG_OFFSET);
- up(&(((struct foo_data *) (client->data)) -> lock));
- return res;
- } else
- return i2c_smbus_read_byte_data(client,reg);
- }
-
-Writing is done the same way.
-
Probing and attaching
=====================
+The Linux I2C stack was originally written to support access to hardware
+monitoring chips on PC motherboards, and thus it embeds some assumptions
+that are more appropriate to SMBus (and PCs) than to I2C. One of these
+assumptions is that most adapters and devices drivers support the SMBUS_QUICK
+protocol to probe device presence. Another is that devices and their drivers
+can be sufficiently configured using only such probe primitives.
+
+As Linux and its I2C stack became more widely used in embedded systems
+and complex components such as DVB adapters, those assumptions became more
+problematic. Drivers for I2C devices that issue interrupts need more (and
+different) configuration information, as do drivers handling chip variants
+that can't be distinguished by protocol probing, or which need some board
+specific information to operate correctly.
+
+Accordingly, the I2C stack now has two models for associating I2C devices
+with their drivers: the original "legacy" model, and a newer one that's
+fully compatible with the Linux 2.6 driver model. These models do not mix,
+since the "legacy" model requires drivers to create "i2c_client" device
+objects after SMBus style probing, while the Linux driver model expects
+drivers to be given such device objects in their probe() routines.
+
+
+Standard Driver Model Binding ("New Style")
+-------------------------------------------
+
+System infrastructure, typically board-specific initialization code or
+boot firmware, reports what I2C devices exist. For example, there may be
+a table, in the kernel or from the boot loader, identifying I2C devices
+and linking them to board-specific configuration information about IRQs
+and other wiring artifacts, chip type, and so on. That could be used to
+create i2c_client objects for each I2C device.
+
+I2C device drivers using this binding model work just like any other
+kind of driver in Linux: they provide a probe() method to bind to
+those devices, and a remove() method to unbind.
+
+ static int foo_probe(struct i2c_client *client);
+ static int foo_remove(struct i2c_client *client);
+
+Remember that the i2c_driver does not create those client handles. The
+handle may be used during foo_probe(). If foo_probe() reports success
+(zero not a negative status code) it may save the handle and use it until
+foo_remove() returns. That binding model is used by most Linux drivers.
+
+Drivers match devices when i2c_client.driver_name and the driver name are
+the same; this approach is used in several other busses that don't have
+device typing support in the hardware. The driver and module name should
+match, so hotplug/coldplug mechanisms will modprobe the driver.
+
+
+Device Creation (Standard driver model)
+---------------------------------------
+
+If you know for a fact that an I2C device is connected to a given I2C bus,
+you can instantiate that device by simply filling an i2c_board_info
+structure with the device address and driver name, and calling
+i2c_new_device(). This will create the device, then the driver core will
+take care of finding the right driver and will call its probe() method.
+If a driver supports different device types, you can specify the type you
+want using the type field. You can also specify an IRQ and platform data
+if needed.
+
+Sometimes you know that a device is connected to a given I2C bus, but you
+don't know the exact address it uses. This happens on TV adapters for
+example, where the same driver supports dozens of slightly different
+models, and I2C device addresses change from one model to the next. In
+that case, you can use the i2c_new_probed_device() variant, which is
+similar to i2c_new_device(), except that it takes an additional list of
+possible I2C addresses to probe. A device is created for the first
+responsive address in the list. If you expect more than one device to be
+present in the address range, simply call i2c_new_probed_device() that
+many times.
+
+The call to i2c_new_device() or i2c_new_probed_device() typically happens
+in the I2C bus driver. You may want to save the returned i2c_client
+reference for later use.
+
+
+Device Deletion (Standard driver model)
+---------------------------------------
+
+Each I2C device which has been created using i2c_new_device() or
+i2c_new_probed_device() can be unregistered by calling
+i2c_unregister_device(). If you don't call it explicitly, it will be
+called automatically before the underlying I2C bus itself is removed, as a
+device can't survive its parent in the device driver model.
+
+
+Legacy Driver Binding Model
+---------------------------
+
Most i2c devices can be present on several i2c addresses; for some this
is determined in hardware (by soldering some chip pins to Vcc or Ground),
for others this can be changed in software (by writing to specific client
@@ -157,13 +235,9 @@ detection algorithm.
You do not have to use this parameter interface; but don't try to use
function i2c_probe() if you don't.
-NOTE: If you want to write a `sensors' driver, the interface is slightly
- different! See below.
-
-
-Probing classes
----------------
+Probing classes (Legacy model)
+------------------------------
All parameters are given as lists of unsigned 16-bit integers. Lists are
terminated by I2C_CLIENT_END.
@@ -210,8 +284,8 @@ Note that you *have* to call the defined variable `normal_i2c',
without any prefix!
-Attaching to an adapter
------------------------
+Attaching to an adapter (Legacy model)
+--------------------------------------
Whenever a new adapter is inserted, or for all adapters if the driver is
being registered, the callback attach_adapter() is called. Now is the
@@ -237,17 +311,13 @@ them (unless a `force' parameter was used). In addition, addresses that
are already in use (by some other registered client) are skipped.
-The detect client function
---------------------------
+The detect client function (Legacy model)
+-----------------------------------------
The detect client function is called by i2c_probe. The `kind' parameter
contains -1 for a probed detection, 0 for a forced detection, or a positive
number for a forced detection with a chip type forced.
-Below, some things are only needed if this is a `sensors' driver. Those
-parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
-markers.
-
Returning an error different from -ENODEV in a detect function will cause
the detection to stop: other addresses and adapters won't be scanned.
This should only be done on fatal or internal errors, such as a memory
@@ -256,64 +326,20 @@ shortage or i2c_attach_client failing.
For now, you can ignore the `flags' parameter. It is there for future use.
int foo_detect_client(struct i2c_adapter *adapter, int address,
- unsigned short flags, int kind)
+ int kind)
{
int err = 0;
int i;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct foo_data *data;
- const char *client_name = ""; /* For non-`sensors' drivers, put the real
- name here! */
+ const char *name = "";
/* Let's see whether this adapter can support what we need.
- Please substitute the things you need here!
- For `sensors' drivers, add `! is_isa &&' to the if statement */
+ Please substitute the things you need here! */
if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_WRITE_BYTE))
goto ERROR0;
- /* SENSORS ONLY START */
- const char *type_name = "";
- int is_isa = i2c_is_isa_adapter(adapter);
-
- /* Do this only if the chip can additionally be found on the ISA bus
- (hybrid chip). */
-
- if (is_isa) {
-
- /* Discard immediately if this ISA range is already used */
- /* FIXME: never use check_region(), only request_region() */
- if (check_region(address,FOO_EXTENT))
- goto ERROR0;
-
- /* Probe whether there is anything on this address.
- Some example code is below, but you will have to adapt this
- for your own driver */
-
- if (kind < 0) /* Only if no force parameter was used */ {
- /* We may need long timeouts at least for some chips. */
- #define REALLY_SLOW_IO
- i = inb_p(address + 1);
- if (inb_p(address + 2) != i)
- goto ERROR0;
- if (inb_p(address + 3) != i)
- goto ERROR0;
- if (inb_p(address + 7) != i)
- goto ERROR0;
- #undef REALLY_SLOW_IO
-
- /* Let's just hope nothing breaks here */
- i = inb_p(address + 5) & 0x7f;
- outb_p(~i & 0x7f,address+5);
- if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
- outb_p(i,address+5);
- return 0;
- }
- }
- }
-
- /* SENSORS ONLY END */
-
/* OK. For now, we presume we have a valid client. We now create the
client structure, even though we cannot fill it completely yet.
But it allows us to access several i2c functions safely */
@@ -323,13 +349,12 @@ For now, you can ignore the `flags' parameter. It is there for future use.
goto ERROR0;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
+ client = &data->client;
+ i2c_set_clientdata(client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &foo_driver;
- new_client->flags = 0;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &foo_driver;
/* Now, we do the remaining detection. If no `force' parameter is used. */
@@ -337,19 +362,17 @@ For now, you can ignore the `flags' parameter. It is there for future use.
parameter was used. */
if (kind < 0) {
/* The below is of course bogus */
- if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
+ if (foo_read(client, FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
goto ERROR1;
}
- /* SENSORS ONLY START */
-
/* Next, specific detection. This is especially important for `sensors'
devices. */
/* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter
was used. */
if (kind <= 0) {
- i = foo_read(new_client,FOO_REG_CHIPTYPE);
+ i = foo_read(client, FOO_REG_CHIPTYPE);
if (i == FOO_TYPE_1)
kind = chip1; /* As defined in the enum */
else if (i == FOO_TYPE_2)
@@ -363,63 +386,31 @@ For now, you can ignore the `flags' parameter. It is there for future use.
/* Now set the type and chip names */
if (kind == chip1) {
- type_name = "chip1"; /* For /proc entry */
- client_name = "CHIP 1";
+ name = "chip1";
} else if (kind == chip2) {
- type_name = "chip2"; /* For /proc entry */
- client_name = "CHIP 2";
+ name = "chip2";
}
- /* Reserve the ISA region */
- if (is_isa)
- request_region(address,FOO_EXTENT,type_name);
-
- /* SENSORS ONLY END */
-
/* Fill in the remaining client fields. */
- strcpy(new_client->name,client_name);
-
- /* SENSORS ONLY BEGIN */
+ strlcpy(client->name, name, I2C_NAME_SIZE);
data->type = kind;
- /* SENSORS ONLY END */
-
- data->valid = 0; /* Only if you use this field */
- init_MUTEX(&data->update_lock); /* Only if you use this field */
+ mutex_init(&data->update_lock); /* Only if you use this field */
/* Any other initializations in data must be done here too. */
- /* Tell the i2c layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto ERROR3;
-
- /* SENSORS ONLY BEGIN */
- /* Register a new directory entry with module sensors. See below for
- the `template' structure. */
- if ((i = i2c_register_entry(new_client, type_name,
- foo_dir_table_template,THIS_MODULE)) < 0) {
- err = i;
- goto ERROR4;
- }
- data->sysctl_id = i;
-
- /* SENSORS ONLY END */
-
/* This function can write default values to the client registers, if
needed. */
- foo_init_client(new_client);
+ foo_init_client(client);
+
+ /* Tell the i2c layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto ERROR1;
+
return 0;
/* OK, this is not exactly good programming practice, usually. But it is
very code-efficient in this case. */
- ERROR4:
- i2c_detach_client(new_client);
- ERROR3:
- ERROR2:
- /* SENSORS ONLY START */
- if (is_isa)
- release_region(address,FOO_EXTENT);
- /* SENSORS ONLY END */
ERROR1:
kfree(data);
ERROR0:
@@ -427,8 +418,8 @@ For now, you can ignore the `flags' parameter. It is there for future use.
}
-Removing the client
-===================
+Removing the client (Legacy model)
+==================================
The detach_client call back function is called when a client should be
removed. It may actually fail, but only when panicking. This code is
@@ -436,22 +427,12 @@ much simpler than the attachment code, fortunately!
int foo_detach_client(struct i2c_client *client)
{
- int err,i;
-
- /* SENSORS ONLY START */
- /* Deregister with the `i2c-proc' module. */
- i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
- /* SENSORS ONLY END */
+ int err;
/* Try to detach the client from i2c space */
if ((err = i2c_detach_client(client)))
return err;
- /* HYBRID SENSORS CHIP ONLY START */
- if i2c_is_isa_client(client)
- release_region(client->addr,LM78_EXTENT);
- /* HYBRID SENSORS CHIP ONLY END */
-
kfree(i2c_get_clientdata(client));
return 0;
}
@@ -464,45 +445,34 @@ When the kernel is booted, or when your foo driver module is inserted,
you have to do some initializing. Fortunately, just attaching (registering)
the driver module is usually enough.
- /* Keep track of how far we got in the initialization process. If several
- things have to initialized, and we fail halfway, only those things
- have to be cleaned up! */
- static int __initdata foo_initialized = 0;
-
static int __init foo_init(void)
{
int res;
- printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE);
if ((res = i2c_add_driver(&foo_driver))) {
printk("foo: Driver registration failed, module not inserted.\n");
- foo_cleanup();
return res;
}
- foo_initialized ++;
return 0;
}
- void foo_cleanup(void)
+ static void __exit foo_cleanup(void)
{
- if (foo_initialized == 1) {
- if ((res = i2c_del_driver(&foo_driver))) {
- printk("foo: Driver registration failed, module not removed.\n");
- return;
- }
- foo_initialized --;
- }
+ i2c_del_driver(&foo_driver);
}
/* Substitute your own name and email address */
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
+ /* a few non-GPL license types are also allowed */
+ MODULE_LICENSE("GPL");
+
module_init(foo_init);
module_exit(foo_cleanup);
Note that some functions are marked by `__init', and some data structures
-by `__init_data'. Hose functions and structures can be removed after
+by `__initdata'. These functions and structures can be removed after
kernel booting (or module loading) is completed.
@@ -632,110 +602,7 @@ General purpose routines
Below all general purpose routines are listed, that were not mentioned
before.
- /* This call returns a unique low identifier for each registered adapter,
- * or -1 if the adapter was not registered.
+ /* This call returns a unique low identifier for each registered adapter.
*/
extern int i2c_adapter_id(struct i2c_adapter *adap);
-
-The sensors sysctl/proc interface
-=================================
-
-This section only applies if you write `sensors' drivers.
-
-Each sensors driver creates a directory in /proc/sys/dev/sensors for each
-registered client. The directory is called something like foo-i2c-4-65.
-The sensors module helps you to do this as easily as possible.
-
-The template
-------------
-
-You will need to define a ctl_table template. This template will automatically
-be copied to a newly allocated structure and filled in where necessary when
-you call sensors_register_entry.
-
-First, I will give an example definition.
- static ctl_table foo_dir_table_template[] = {
- { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real,
- &i2c_sysctl_real,NULL,&foo_func },
- { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real,
- &i2c_sysctl_real,NULL,&foo_func },
- { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real,
- &i2c_sysctl_real,NULL,&foo_data },
- { 0 }
- };
-
-In the above example, three entries are defined. They can either be
-accessed through the /proc interface, in the /proc/sys/dev/sensors/*
-directories, as files named func1, func2 and data, or alternatively
-through the sysctl interface, in the appropriate table, with identifiers
-FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA.
-
-The third, sixth and ninth parameters should always be NULL, and the
-fourth should always be 0. The fifth is the mode of the /proc file;
-0644 is safe, as the file will be owned by root:root.
-
-The seventh and eighth parameters should be &i2c_proc_real and
-&i2c_sysctl_real if you want to export lists of reals (scaled
-integers). You can also use your own function for them, as usual.
-Finally, the last parameter is the call-back to gather the data
-(see below) if you use the *_proc_real functions.
-
-
-Gathering the data
-------------------
-
-The call back functions (foo_func and foo_data in the above example)
-can be called in several ways; the operation parameter determines
-what should be done:
-
- * If operation == SENSORS_PROC_REAL_INFO, you must return the
- magnitude (scaling) in nrels_mag;
- * If operation == SENSORS_PROC_REAL_READ, you must read information
- from the chip and return it in results. The number of integers
- to display should be put in nrels_mag;
- * If operation == SENSORS_PROC_REAL_WRITE, you must write the
- supplied information to the chip. nrels_mag will contain the number
- of integers, results the integers themselves.
-
-The *_proc_real functions will display the elements as reals for the
-/proc interface. If you set the magnitude to 2, and supply 345 for
-SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would
-write 45.6 to the /proc file, it would be returned as 4560 for
-SENSORS_PROC_REAL_WRITE. A magnitude may even be negative!
-
-An example function:
-
- /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and
- register values. Note the use of the read cache. */
- void foo_in(struct i2c_client *client, int operation, int ctl_name,
- int *nrels_mag, long *results)
- {
- struct foo_data *data = client->data;
- int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */
-
- if (operation == SENSORS_PROC_REAL_INFO)
- *nrels_mag = 2;
- else if (operation == SENSORS_PROC_REAL_READ) {
- /* Update the readings cache (if necessary) */
- foo_update_client(client);
- /* Get the readings from the cache */
- results[0] = FOO_FROM_REG(data->foo_func_base[nr]);
- results[1] = FOO_FROM_REG(data->foo_func_more[nr]);
- results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]);
- *nrels_mag = 2;
- } else if (operation == SENSORS_PROC_REAL_WRITE) {
- if (*nrels_mag >= 1) {
- /* Update the cache */
- data->foo_base[nr] = FOO_TO_REG(results[0]);
- /* Update the chip */
- foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]);
- }
- if (*nrels_mag >= 2) {
- /* Update the cache */
- data->foo_more[nr] = FOO_TO_REG(results[1]);
- /* Update the chip */
- foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]);
- }
- }
- }
diff --git a/Documentation/i2o/README b/Documentation/i2o/README
index 9aa6ddb446e..0ebf58c73f5 100644
--- a/Documentation/i2o/README
+++ b/Documentation/i2o/README
@@ -30,13 +30,13 @@ Juha Sievanen, University of Helsinki Finland
Bug fixes
Core code extensions
-Auvo Häkkinen, University of Helsinki Finland
+Auvo Häkkinen, University of Helsinki Finland
LAN OSM code
/Proc interface to LAN class
Bug fixes
Core code extensions
-Taneli Vähäkangas, University of Helsinki Finland
+Taneli Vähäkangas, University of Helsinki Finland
Fixes to i2o_config
CREDITS
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 38fe1f03fb1..d01b7a2a0f2 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -2,7 +2,7 @@
----------------------------
H. Peter Anvin <hpa@zytor.com>
- Last update 2007-01-26
+ Last update 2007-05-07
On the i386 platform, the Linux kernel uses a rather complicated boot
convention. This has evolved partially due to historical aspects, as
@@ -11,7 +11,7 @@ bootable image, the complicated PC memory model and due to changed
expectations in the PC industry caused by the effective demise of
real-mode DOS as a mainstream operating system.
-Currently, four versions of the Linux/i386 boot protocol exist.
+Currently, the following versions of the Linux/i386 boot protocol exist.
Old kernels: zImage/Image support only. Some very early kernels
may not even support a command line.
@@ -35,9 +35,13 @@ Protocol 2.03: (Kernel 2.4.18-pre1) Explicitly makes the highest possible
initrd address available to the bootloader.
Protocol 2.04: (Kernel 2.6.14) Extend the syssize field to four bytes.
+
Protocol 2.05: (Kernel 2.6.20) Make protected mode kernel relocatable.
Introduce relocatable_kernel and kernel_alignment fields.
+Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of
+ the boot command line
+
**** MEMORY LAYOUT
@@ -133,6 +137,8 @@ Offset Proto Name Meaning
022C/4 2.03+ initrd_addr_max Highest legal initrd address
0230/4 2.05+ kernel_alignment Physical addr alignment required for kernel
0234/1 2.05+ relocatable_kernel Whether kernel is relocatable or not
+0235/3 N/A pad2 Unused
+0238/4 2.06+ cmdline_size Maximum size of the kernel command line
(1) For backwards compatibility, if the setup_sects field contains 0, the
real value is 4.
@@ -177,9 +183,9 @@ filled out, however:
a version number. Otherwise, enter 0xFF here.
Assigned boot loader ids:
- 0 LILO
+ 0 LILO (0x00 reserved for pre-2.00 bootloader)
1 Loadlin
- 2 bootsect-loader
+ 2 bootsect-loader (0x20, all other values reserved)
3 SYSLINUX
4 EtherBoot
5 ELILO
@@ -204,6 +210,9 @@ filled out, however:
additional data (such as the kernel command line) moved in
addition to the real-mode kernel itself.
+ The unit is bytes starting with the beginning of the boot
+ sector.
+
ramdisk_image, ramdisk_size:
If your boot loader has loaded an initial ramdisk (initrd),
set ramdisk_image to the 32-bit pointer to the ramdisk data
@@ -233,6 +242,12 @@ filled out, however:
if your ramdisk is exactly 131072 bytes long and this field is
0x37FFFFFF, you can start your ramdisk at 0x37FE0000.)
+ cmdline_size:
+ The maximum size of the command line without the terminating
+ zero. This means that the command line can contain at most
+ cmdline_size characters. With protocol version 2.05 and
+ earlier, the maximum size was 255.
+
**** THE KERNEL COMMAND LINE
@@ -241,11 +256,10 @@ loader to communicate with the kernel. Some of its options are also
relevant to the boot loader itself, see "special command line options"
below.
-The kernel command line is a null-terminated string currently up to
-255 characters long, plus the final null. A string that is too long
-will be automatically truncated by the kernel, a boot loader may allow
-a longer command line to be passed to permit future kernels to extend
-this limit.
+The kernel command line is a null-terminated string. The maximum
+length can be retrieved from the field cmdline_size. Before protocol
+version 2.06, the maximum was 255 characters. A string that is too
+long will be automatically truncated by the kernel.
If the boot protocol version is 2.02 or later, the address of the
kernel command line is given by the header field cmd_line_ptr (see
@@ -267,14 +281,54 @@ command line is entered using the following protocol:
field.
+**** MEMORY LAYOUT OF THE REAL-MODE CODE
+
+The real-mode code requires a stack/heap to be set up, as well as
+memory allocated for the kernel command line. This needs to be done
+in the real-mode accessible memory in bottom megabyte.
+
+It should be noted that modern machines often have a sizable Extended
+BIOS Data Area (EBDA). As a result, it is advisable to use as little
+of the low megabyte as possible.
+
+Unfortunately, under the following circumstances the 0x90000 memory
+segment has to be used:
+
+ - When loading a zImage kernel ((loadflags & 0x01) == 0).
+ - When loading a 2.01 or earlier boot protocol kernel.
+
+ -> For the 2.00 and 2.01 boot protocols, the real-mode code
+ can be loaded at another address, but it is internally
+ relocated to 0x90000. For the "old" protocol, the
+ real-mode code must be loaded at 0x90000.
+
+When loading at 0x90000, avoid using memory above 0x9a000.
+
+For boot protocol 2.02 or higher, the command line does not have to be
+located in the same 64K segment as the real-mode setup code; it is
+thus permitted to give the stack/heap the full 64K segment and locate
+the command line above it.
+
+The kernel command line should not be located below the real-mode
+code, nor should it be located in high memory.
+
+
**** SAMPLE BOOT CONFIGURATION
As a sample configuration, assume the following layout of the real
-mode segment (this is a typical, and recommended layout):
+mode segment:
+
+ When loading below 0x90000, use the entire segment:
- 0x0000-0x7FFF Real mode kernel
- 0x8000-0x8FFF Stack and heap
- 0x9000-0x90FF Kernel command line
+ 0x0000-0x7fff Real mode kernel
+ 0x8000-0xdfff Stack and heap
+ 0xe000-0xffff Kernel command line
+
+ When loading at 0x90000 OR the protocol version is 2.01 or earlier:
+
+ 0x0000-0x7fff Real mode kernel
+ 0x8000-0x97ff Stack and heap
+ 0x9800-0x9fff Kernel command line
Such a boot loader should enter the following fields in the header:
@@ -290,22 +344,33 @@ Such a boot loader should enter the following fields in the header:
ramdisk_image = <initrd_address>;
ramdisk_size = <initrd_size>;
}
+
+ if ( protocol >= 0x0202 && loadflags & 0x01 )
+ heap_end = 0xe000;
+ else
+ heap_end = 0x9800;
+
if ( protocol >= 0x0201 ) {
- heap_end_ptr = 0x9000 - 0x200;
+ heap_end_ptr = heap_end - 0x200;
loadflags |= 0x80; /* CAN_USE_HEAP */
}
+
if ( protocol >= 0x0202 ) {
- cmd_line_ptr = base_ptr + 0x9000;
+ cmd_line_ptr = base_ptr + heap_end;
+ strcpy(cmd_line_ptr, cmdline);
} else {
cmd_line_magic = 0xA33F;
- cmd_line_offset = 0x9000;
- setup_move_size = 0x9100;
+ cmd_line_offset = heap_end;
+ setup_move_size = heap_end + strlen(cmdline)+1;
+ strcpy(base_ptr+cmd_line_offset, cmdline);
}
} else {
/* Very old kernel */
+ heap_end = 0x9800;
+
cmd_line_magic = 0xA33F;
- cmd_line_offset = 0x9000;
+ cmd_line_offset = heap_end;
/* A very old kernel MUST have its real-mode code
loaded at 0x90000 */
@@ -313,12 +378,11 @@ Such a boot loader should enter the following fields in the header:
if ( base_ptr != 0x90000 ) {
/* Copy the real-mode kernel */
memcpy(0x90000, base_ptr, (setup_sects+1)*512);
- /* Copy the command line */
- memcpy(0x99000, base_ptr+0x9000, 256);
-
base_ptr = 0x90000; /* Relocated */
}
+ strcpy(0x90000+cmd_line_offset, cmdline);
+
/* It is recommended to clear memory up to the 32K mark */
memset(0x90000 + (setup_sects+1)*512, 0,
(64-(setup_sects+1))*512);
@@ -364,10 +428,11 @@ conflict with actual kernel options now or in the future.
line is parsed.
mem=<size>
- <size> is an integer in C notation optionally followed by K, M
- or G (meaning << 10, << 20 or << 30). This specifies the end
- of memory to the kernel. This affects the possible placement
- of an initrd, since an initrd should be placed near end of
+ <size> is an integer in C notation optionally followed by
+ (case insensitive) K, M, G, T, P or E (meaning << 10, << 20,
+ << 30, << 40, << 50 or << 60). This specifies the end of
+ memory to the kernel. This affects the possible placement of
+ an initrd, since an initrd should be placed near end of
memory. Note that this is an option to *both* the kernel and
the bootloader!
@@ -417,7 +482,7 @@ In our example from above, we would do:
/* Set up the real-mode kernel stack */
_SS = seg;
- _SP = 0x9000; /* Load SP immediately after loading SS! */
+ _SP = heap_end;
_DS = _ES = _FS = _GS = seg;
jmp_far(seg+0x20, 0); /* Run the kernel */
@@ -449,8 +514,9 @@ IMPORTANT: All the hooks are required to preserve %esp, %ebp, %esi and
code32_start:
A 32-bit flat-mode routine *jumped* to immediately after the
transition to protected mode, but before the kernel is
- uncompressed. No segments, except CS, are set up; you should
- set them up to KERNEL_DS (0x18) yourself.
+ uncompressed. No segments, except CS, are guaranteed to be
+ set up (current kernels do, but older ones do not); you should
+ set them up to BOOT_DS (0x18) yourself.
After completing your hook, you should jump to the address
that was in this field before your boot loader overwrote it.
diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c
new file mode 100644
index 00000000000..3153167b41c
--- /dev/null
+++ b/Documentation/ia64/aliasing-test.c
@@ -0,0 +1,247 @@
+/*
+ * Exercise /dev/mem mmap cases that have been troublesome in the past
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int sum;
+
+int map_mem(char *path, off_t offset, size_t length, int touch)
+{
+ int fd, rc;
+ void *addr;
+ int *c;
+
+ fd = open(path, O_RDWR);
+ if (fd == -1) {
+ perror(path);
+ return -1;
+ }
+
+ addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+ if (addr == MAP_FAILED)
+ return 1;
+
+ if (touch) {
+ c = (int *) addr;
+ while (c < (int *) (offset + length))
+ sum += *c++;
+ }
+
+ rc = munmap(addr, length);
+ if (rc == -1) {
+ perror("munmap");
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch)
+{
+ struct dirent **namelist;
+ char *name, *path2;
+ int i, n, r, rc, result = 0;
+ struct stat buf;
+
+ n = scandir(path, &namelist, 0, alphasort);
+ if (n < 0) {
+ perror("scandir");
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ name = namelist[i]->d_name;
+
+ if (fnmatch(".", name, 0) == 0)
+ goto skip;
+ if (fnmatch("..", name, 0) == 0)
+ goto skip;
+
+ path2 = malloc(strlen(path) + strlen(name) + 3);
+ strcpy(path2, path);
+ strcat(path2, "/");
+ strcat(path2, name);
+
+ if (fnmatch(file, name, 0) == 0) {
+ rc = map_mem(path2, offset, length, touch);
+ if (rc == 0)
+ fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
+ else if (rc > 0)
+ fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
+ else {
+ fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
+ return rc;
+ }
+ } else {
+ r = lstat(path2, &buf);
+ if (r == 0 && S_ISDIR(buf.st_mode)) {
+ rc = scan_sysfs(path2, file, offset, length, touch);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ result |= rc;
+ free(path2);
+
+skip:
+ free(namelist[i]);
+ }
+ free(namelist);
+ return rc;
+}
+
+char buf[1024];
+
+int read_rom(char *path)
+{
+ int fd, rc;
+ size_t size = 0;
+
+ fd = open(path, O_RDWR);
+ if (fd == -1) {
+ perror(path);
+ return -1;
+ }
+
+ rc = write(fd, "1", 2);
+ if (rc <= 0) {
+ perror("write");
+ return -1;
+ }
+
+ do {
+ rc = read(fd, buf, sizeof(buf));
+ if (rc > 0)
+ size += rc;
+ } while (rc > 0);
+
+ close(fd);
+ return size;
+}
+
+int scan_rom(char *path, char *file)
+{
+ struct dirent **namelist;
+ char *name, *path2;
+ int i, n, r, rc, result = 0;
+ struct stat buf;
+
+ n = scandir(path, &namelist, 0, alphasort);
+ if (n < 0) {
+ perror("scandir");
+ return -1;
+ }
+
+ for (i = 0; i < n; i++) {
+ name = namelist[i]->d_name;
+
+ if (fnmatch(".", name, 0) == 0)
+ goto skip;
+ if (fnmatch("..", name, 0) == 0)
+ goto skip;
+
+ path2 = malloc(strlen(path) + strlen(name) + 3);
+ strcpy(path2, path);
+ strcat(path2, "/");
+ strcat(path2, name);
+
+ if (fnmatch(file, name, 0) == 0) {
+ rc = read_rom(path2);
+
+ /*
+ * It's OK if the ROM is unreadable. Maybe there
+ * is no ROM, or some other error ocurred. The
+ * important thing is that no MCA happened.
+ */
+ if (rc > 0)
+ fprintf(stderr, "PASS: %s read %ld bytes\n", path2, rc);
+ else {
+ fprintf(stderr, "PASS: %s not readable\n", path2);
+ return rc;
+ }
+ } else {
+ r = lstat(path2, &buf);
+ if (r == 0 && S_ISDIR(buf.st_mode)) {
+ rc = scan_rom(path2, file);
+ if (rc < 0)
+ return rc;
+ }
+ }
+
+ result |= rc;
+ free(path2);
+
+skip:
+ free(namelist[i]);
+ }
+ free(namelist);
+ return rc;
+}
+
+main()
+{
+ int rc;
+
+ if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
+ fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
+ else
+ fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
+
+ /*
+ * It's not safe to blindly read the VGA frame buffer. If you know
+ * how to poke the card the right way, it should respond, but it's
+ * not safe in general. Many machines, e.g., Intel chipsets, cover
+ * up a non-responding card by just returning -1, but others will
+ * report the failure as a machine check.
+ */
+ if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
+ fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
+ else
+ fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
+
+ if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
+ fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
+ else
+ fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
+
+ /*
+ * Often you can map all the individual pieces above (0-0xA0000,
+ * 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
+ * thing at once. This is because the individual pieces use different
+ * attributes, and there's no single attribute supported over the
+ * whole region.
+ */
+ rc = map_mem("/dev/mem", 0, 1024*1024, 0);
+ if (rc == 0)
+ fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
+ else if (rc > 0)
+ fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
+ else
+ fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
+
+ scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
+ scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
+ scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
+ scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
+
+ scan_rom("/sys/devices", "rom");
+}
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
index 38f9a52d182..9a431a7d0f5 100644
--- a/Documentation/ia64/aliasing.txt
+++ b/Documentation/ia64/aliasing.txt
@@ -112,16 +112,6 @@ POTENTIAL ATTRIBUTE ALIASING CASES
The /dev/mem mmap constraints apply.
- However, since this is for mapping legacy MMIO space, WB access
- does not make sense. This matters on machines without legacy
- VGA support: these machines may have WB memory for the entire
- first megabyte (or even the entire first granule).
-
- On these machines, we could mmap legacy_mem as WB, which would
- be safe in terms of attribute aliasing, but X has no way of
- knowing that it is accessing regular memory, not a frame buffer,
- so the kernel should fail the mmap rather than doing it with WB.
-
read/write of /dev/mem
This uses copy_from_user(), which implicitly uses a kernel
@@ -138,14 +128,20 @@ POTENTIAL ATTRIBUTE ALIASING CASES
ioremap()
- This returns a kernel identity mapping for use inside the
- kernel.
+ This returns a mapping for use inside the kernel.
If the region is in kern_memmap, we should use the attribute
- specified there. Otherwise, if the EFI memory map reports that
- the entire granule supports WB, we should use that (granules
- that are partially reserved or occupied by firmware do not appear
- in kern_memmap). Otherwise, we should use a UC mapping.
+ specified there.
+
+ If the EFI memory map reports that the entire granule supports
+ WB, we should use that (granules that are partially reserved
+ or occupied by firmware do not appear in kern_memmap).
+
+ If the granule contains non-WB memory, but we can cover the
+ region safely with kernel page table mappings, we can use
+ ioremap_page_range() as most other architectures do.
+
+ Failing all of the above, we have to fall back to a UC mapping.
PAST PROBLEM CASES
@@ -158,7 +154,7 @@ PAST PROBLEM CASES
succeed. It may create either WB or UC user mappings, depending
on whether the region is in kern_memmap or the EFI memory map.
- mmap of 0x0-0xA0000 /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
+ mmap of 0x0-0x9FFFF /dev/mem by "hwinfo" on HP sx1000 with VGA enabled
See https://bugzilla.novell.com/show_bug.cgi?id=140858.
@@ -171,28 +167,25 @@ PAST PROBLEM CASES
so it is safe to use WB mappings.
The kernel VGA driver may ioremap the VGA frame buffer at 0xA0000,
- which will use a granule-sized UC mapping covering 0-0xFFFFF. This
- granule covers some WB-only memory, but since UC is non-speculative,
- the processor will never generate an uncacheable reference to the
- WB-only areas unless the driver explicitly touches them.
+ which uses a granule-sized UC mapping. This granule will cover some
+ WB-only memory, but since UC is non-speculative, the processor will
+ never generate an uncacheable reference to the WB-only areas unless
+ the driver explicitly touches them.
mmap of 0x0-0xFFFFF legacy_mem by "X"
- If the EFI memory map reports this entire range as WB, there
- is no VGA MMIO hole, and the mmap should fail or be done with
- a WB mapping.
+ If the EFI memory map reports that the entire range supports the
+ same attributes, we can allow the mmap (and we will prefer WB if
+ supported, as is the case with HP sx[12]000 machines with VGA
+ disabled).
- There's no easy way for X to determine whether the 0xA0000-0xBFFFF
- region is a frame buffer or just memory, so I think it's best to
- just fail this mmap request rather than using a WB mapping. As
- far as I know, there's no need to map legacy_mem with WB
- mappings.
+ If EFI reports the range as partly WB and partly UC (as on sx[12]000
+ machines with VGA enabled), we must fail the mmap because there's no
+ safe attribute to use.
- Otherwise, a UC mapping of the entire region is probably safe.
- The VGA hole means the region will not be in kern_memmap. The
- HP sx1000 chipset doesn't support UC access to the memory surrounding
- the VGA hole, but X doesn't need that area anyway and should not
- reference it.
+ If EFI reports some of the range but not all (as on Intel firmware
+ that doesn't report the VGA frame buffer at all), we should fail the
+ mmap and force the user to map just the specific region of interest.
mmap of 0xA0000-0xBFFFF legacy_mem by "X" on HP sx1000 with VGA disabled
@@ -202,6 +195,16 @@ PAST PROBLEM CASES
This is a special case of the previous case, and the mmap should
fail for the same reason as above.
+ read of /sys/devices/.../rom
+
+ For VGA devices, this may cause an ioremap() of 0xC0000. This
+ used to be done with a UC mapping, because the VGA frame buffer
+ at 0xA0000 prevents use of a WB granule. The UC mapping causes
+ an MCA on HP sx[12]000 chipsets.
+
+ We should use WB page table mappings to avoid covering the VGA
+ frame buffer.
+
NOTES
[1] SDM rev 2.2, vol 2, sec 4.4.1.
diff --git a/Documentation/ia64/err_inject.txt b/Documentation/ia64/err_inject.txt
new file mode 100644
index 00000000000..6449a7090db
--- /dev/null
+++ b/Documentation/ia64/err_inject.txt
@@ -0,0 +1,1068 @@
+
+IPF Machine Check (MC) error inject tool
+========================================
+
+IPF Machine Check (MC) error inject tool is used to inject MC
+errors from Linux. The tool is a test bed for IPF MC work flow including
+hardware correctable error handling, OS recoverable error handling, MC
+event logging, etc.
+
+The tool includes two parts: a kernel driver and a user application
+sample. The driver provides interface to PAL to inject error
+and query error injection capabilities. The driver code is in
+arch/ia64/kernel/err_inject.c. The application sample (shown below)
+provides a combination of various errors and calls the driver's interface
+(sysfs interface) to inject errors or query error injection capabilities.
+
+The tool can be used to test Intel IPF machine MC handling capabilities.
+It's especially useful for people who can not access hardware MC injection
+tool to inject error. It's also very useful to integrate with other
+software test suits to do stressful testing on IPF.
+
+Below is a sample application as part of the whole tool. The sample
+can be used as a working test tool. Or it can be expanded to include
+more features. It also can be a integrated into a libary or other user
+application to have more thorough test.
+
+The sample application takes err.conf as error configuation input. Gcc
+compiles the code. After you install err_inject driver, you can run
+this sample application to inject errors.
+
+Errata: Itanium 2 Processors Specification Update lists some errata against
+the pal_mc_error_inject PAL procedure. The following err.conf has been tested
+on latest Montecito PAL.
+
+err.conf:
+
+#This is configuration file for err_inject_tool.
+#The format of the each line is:
+#cpu, loop, interval, err_type_info, err_struct_info, err_data_buffer
+#where
+# cpu: logical cpu number the error will be inject in.
+# loop: times the error will be injected.
+# interval: In second. every so often one error is injected.
+# err_type_info, err_struct_info: PAL parameters.
+#
+#Note: All values are hex w/o or w/ 0x prefix.
+
+
+#On cpu2, inject only total 0x10 errors, interval 5 seconds
+#corrected, data cache, hier-2, physical addr(assigned by tool code).
+#working on Montecito latest PAL.
+2, 10, 5, 4101, 95
+
+#On cpu4, inject and consume total 0x10 errors, interval 5 seconds
+#corrected, data cache, hier-2, physical addr(assigned by tool code).
+#working on Montecito latest PAL.
+4, 10, 5, 4109, 95
+
+#On cpu15, inject and consume total 0x10 errors, interval 5 seconds
+#recoverable, DTR0, hier-2.
+#working on Montecito latest PAL.
+0xf, 0x10, 5, 4249, 15
+
+The sample application source code:
+
+err_injection_tool.c:
+
+/*
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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.
+ *
+ * Copyright (C) 2006 Intel Co
+ * Fenghua Yu <fenghua.yu@intel.com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sched.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/shm.h>
+
+#define MAX_FN_SIZE 256
+#define MAX_BUF_SIZE 256
+#define DATA_BUF_SIZE 256
+#define NR_CPUS 512
+#define MAX_TASK_NUM 2048
+#define MIN_INTERVAL 5 // seconds
+#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte.
+#define PARA_FIELD_NUM 5
+#define MASK_SIZE (NR_CPUS/64)
+#define PATH_FORMAT "/sys/devices/system/cpu/cpu%d/err_inject/"
+
+int sched_setaffinity(pid_t pid, unsigned int len, unsigned long *mask);
+
+int verbose;
+#define vbprintf if (verbose) printf
+
+int log_info(int cpu, const char *fmt, ...)
+{
+ FILE *log;
+ char fn[MAX_FN_SIZE];
+ char buf[MAX_BUF_SIZE];
+ va_list args;
+
+ sprintf(fn, "%d.log", cpu);
+ log=fopen(fn, "a+");
+ if (log==NULL) {
+ perror("Error open:");
+ return -1;
+ }
+
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ memset(buf, 0, MAX_BUF_SIZE);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ fwrite(buf, sizeof(buf), 1, log);
+ fclose(log);
+
+ return 0;
+}
+
+typedef unsigned long u64;
+typedef unsigned int u32;
+
+typedef union err_type_info_u {
+ struct {
+ u64 mode : 3, /* 0-2 */
+ err_inj : 3, /* 3-5 */
+ err_sev : 2, /* 6-7 */
+ err_struct : 5, /* 8-12 */
+ struct_hier : 3, /* 13-15 */
+ reserved : 48; /* 16-63 */
+ } err_type_info_u;
+ u64 err_type_info;
+} err_type_info_t;
+
+typedef union err_struct_info_u {
+ struct {
+ u64 siv : 1, /* 0 */
+ c_t : 2, /* 1-2 */
+ cl_p : 3, /* 3-5 */
+ cl_id : 3, /* 6-8 */
+ cl_dp : 1, /* 9 */
+ reserved1 : 22, /* 10-31 */
+ tiv : 1, /* 32 */
+ trigger : 4, /* 33-36 */
+ trigger_pl : 3, /* 37-39 */
+ reserved2 : 24; /* 40-63 */
+ } err_struct_info_cache;
+ struct {
+ u64 siv : 1, /* 0 */
+ tt : 2, /* 1-2 */
+ tc_tr : 2, /* 3-4 */
+ tr_slot : 8, /* 5-12 */
+ reserved1 : 19, /* 13-31 */
+ tiv : 1, /* 32 */
+ trigger : 4, /* 33-36 */
+ trigger_pl : 3, /* 37-39 */
+ reserved2 : 24; /* 40-63 */
+ } err_struct_info_tlb;
+ struct {
+ u64 siv : 1, /* 0 */
+ regfile_id : 4, /* 1-4 */
+ reg_num : 7, /* 5-11 */
+ reserved1 : 20, /* 12-31 */
+ tiv : 1, /* 32 */
+ trigger : 4, /* 33-36 */
+ trigger_pl : 3, /* 37-39 */
+ reserved2 : 24; /* 40-63 */
+ } err_struct_info_register;
+ struct {
+ u64 reserved;
+ } err_struct_info_bus_processor_interconnect;
+ u64 err_struct_info;
+} err_struct_info_t;
+
+typedef union err_data_buffer_u {
+ struct {
+ u64 trigger_addr; /* 0-63 */
+ u64 inj_addr; /* 64-127 */
+ u64 way : 5, /* 128-132 */
+ index : 20, /* 133-152 */
+ : 39; /* 153-191 */
+ } err_data_buffer_cache;
+ struct {
+ u64 trigger_addr; /* 0-63 */
+ u64 inj_addr; /* 64-127 */
+ u64 way : 5, /* 128-132 */
+ index : 20, /* 133-152 */
+ reserved : 39; /* 153-191 */
+ } err_data_buffer_tlb;
+ struct {
+ u64 trigger_addr; /* 0-63 */
+ } err_data_buffer_register;
+ struct {
+ u64 reserved; /* 0-63 */
+ } err_data_buffer_bus_processor_interconnect;
+ u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
+} err_data_buffer_t;
+
+typedef union capabilities_u {
+ struct {
+ u64 i : 1,
+ d : 1,
+ rv : 1,
+ tag : 1,
+ data : 1,
+ mesi : 1,
+ dp : 1,
+ reserved1 : 3,
+ pa : 1,
+ va : 1,
+ wi : 1,
+ reserved2 : 20,
+ trigger : 1,
+ trigger_pl : 1,
+ reserved3 : 30;
+ } capabilities_cache;
+ struct {
+ u64 d : 1,
+ i : 1,
+ rv : 1,
+ tc : 1,
+ tr : 1,
+ reserved1 : 27,
+ trigger : 1,
+ trigger_pl : 1,
+ reserved2 : 30;
+ } capabilities_tlb;
+ struct {
+ u64 gr_b0 : 1,
+ gr_b1 : 1,
+ fr : 1,
+ br : 1,
+ pr : 1,
+ ar : 1,
+ cr : 1,
+ rr : 1,
+ pkr : 1,
+ dbr : 1,
+ ibr : 1,
+ pmc : 1,
+ pmd : 1,
+ reserved1 : 3,
+ regnum : 1,
+ reserved2 : 15,
+ trigger : 1,
+ trigger_pl : 1,
+ reserved3 : 30;
+ } capabilities_register;
+ struct {
+ u64 reserved;
+ } capabilities_bus_processor_interconnect;
+} capabilities_t;
+
+typedef struct resources_s {
+ u64 ibr0 : 1,
+ ibr2 : 1,
+ ibr4 : 1,
+ ibr6 : 1,
+ dbr0 : 1,
+ dbr2 : 1,
+ dbr4 : 1,
+ dbr6 : 1,
+ reserved : 48;
+} resources_t;
+
+
+long get_page_size(void)
+{
+ long page_size=sysconf(_SC_PAGESIZE);
+ return page_size;
+}
+
+#define PAGE_SIZE (get_page_size()==-1?0x4000:get_page_size())
+#define SHM_SIZE (2*PAGE_SIZE*NR_CPUS)
+#define SHM_VA 0x2000000100000000
+
+int shmid;
+void *shmaddr;
+
+int create_shm(void)
+{
+ key_t key;
+ char fn[MAX_FN_SIZE];
+
+ /* cpu0 is always existing */
+ sprintf(fn, PATH_FORMAT, 0);
+ if ((key = ftok(fn, 's')) == -1) {
+ perror("ftok");
+ return -1;
+ }
+
+ shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT);
+ if (shmid == -1) {
+ if (errno==EEXIST) {
+ shmid = shmget(key, SHM_SIZE, 0);
+ if (shmid == -1) {
+ perror("shmget");
+ return -1;
+ }
+ }
+ else {
+ perror("shmget");
+ return -1;
+ }
+ }
+ vbprintf("shmid=%d", shmid);
+
+ /* connect to the segment: */
+ shmaddr = shmat(shmid, (void *)SHM_VA, 0);
+ if (shmaddr == (void*)-1) {
+ perror("shmat");
+ return -1;
+ }
+
+ memset(shmaddr, 0, SHM_SIZE);
+ mlock(shmaddr, SHM_SIZE);
+
+ return 0;
+}
+
+int free_shm()
+{
+ munlock(shmaddr, SHM_SIZE);
+ shmdt(shmaddr);
+ semctl(shmid, 0, IPC_RMID);
+
+ return 0;
+}
+
+#ifdef _SEM_SEMUN_UNDEFINED
+union semun
+{
+ int val;
+ struct semid_ds *buf;
+ unsigned short int *array;
+ struct seminfo *__buf;
+};
+#endif
+
+u32 mode=1; /* 1: physical mode; 2: virtual mode. */
+int one_lock=1;
+key_t key[NR_CPUS];
+int semid[NR_CPUS];
+
+int create_sem(int cpu)
+{
+ union semun arg;
+ char fn[MAX_FN_SIZE];
+ int sid;
+
+ sprintf(fn, PATH_FORMAT, cpu);
+ sprintf(fn, "%s/%s", fn, "err_type_info");
+ if ((key[cpu] = ftok(fn, 'e')) == -1) {
+ perror("ftok");
+ return -1;
+ }
+
+ if (semid[cpu]!=0)
+ return 0;
+
+ /* clear old semaphore */
+ if ((sid = semget(key[cpu], 1, 0)) != -1)
+ semctl(sid, 0, IPC_RMID);
+
+ /* get one semaphore */
+ if ((semid[cpu] = semget(key[cpu], 1, IPC_CREAT | IPC_EXCL)) == -1) {
+ perror("semget");
+ printf("Please remove semaphore with key=0x%lx, then run the tool.\n",
+ (u64)key[cpu]);
+ return -1;
+ }
+
+ vbprintf("semid[%d]=0x%lx, key[%d]=%lx\n",cpu,(u64)semid[cpu],cpu,
+ (u64)key[cpu]);
+ /* initialize the semaphore to 1: */
+ arg.val = 1;
+ if (semctl(semid[cpu], 0, SETVAL, arg) == -1) {
+ perror("semctl");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int lock(int cpu)
+{
+ struct sembuf lock;
+
+ lock.sem_num = cpu;
+ lock.sem_op = 1;
+ semop(semid[cpu], &lock, 1);
+
+ return 0;
+}
+
+static int unlock(int cpu)
+{
+ struct sembuf unlock;
+
+ unlock.sem_num = cpu;
+ unlock.sem_op = -1;
+ semop(semid[cpu], &unlock, 1);
+
+ return 0;
+}
+
+void free_sem(int cpu)
+{
+ semctl(semid[cpu], 0, IPC_RMID);
+}
+
+int wr_multi(char *fn, unsigned long *data, int size)
+{
+ int fd;
+ char buf[MAX_BUF_SIZE];
+ int ret;
+
+ if (size==1)
+ sprintf(buf, "%lx", *data);
+ else if (size==3)
+ sprintf(buf, "%lx,%lx,%lx", data[0], data[1], data[2]);
+ else {
+ fprintf(stderr,"write to file with wrong size!\n");
+ return -1;
+ }
+
+ fd=open(fn, O_RDWR);
+ if (!fd) {
+ perror("Error:");
+ return -1;
+ }
+ ret=write(fd, buf, sizeof(buf));
+ close(fd);
+ return ret;
+}
+
+int wr(char *fn, unsigned long data)
+{
+ return wr_multi(fn, &data, 1);
+}
+
+int rd(char *fn, unsigned long *data)
+{
+ int fd;
+ char buf[MAX_BUF_SIZE];
+
+ fd=open(fn, O_RDONLY);
+ if (fd<0) {
+ perror("Error:");
+ return -1;
+ }
+ read(fd, buf, MAX_BUF_SIZE);
+ *data=strtoul(buf, NULL, 16);
+ close(fd);
+ return 0;
+}
+
+int rd_status(char *path, int *status)
+{
+ char fn[MAX_FN_SIZE];
+ sprintf(fn, "%s/status", path);
+ if (rd(fn, (u64*)status)<0) {
+ perror("status reading error.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int rd_capabilities(char *path, u64 *capabilities)
+{
+ char fn[MAX_FN_SIZE];
+ sprintf(fn, "%s/capabilities", path);
+ if (rd(fn, capabilities)<0) {
+ perror("capabilities reading error.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int rd_all(char *path)
+{
+ unsigned long err_type_info, err_struct_info, err_data_buffer;
+ int status;
+ unsigned long capabilities, resources;
+ char fn[MAX_FN_SIZE];
+
+ sprintf(fn, "%s/err_type_info", path);
+ if (rd(fn, &err_type_info)<0) {
+ perror("err_type_info reading error.\n");
+ return -1;
+ }
+ printf("err_type_info=%lx\n", err_type_info);
+
+ sprintf(fn, "%s/err_struct_info", path);
+ if (rd(fn, &err_struct_info)<0) {
+ perror("err_struct_info reading error.\n");
+ return -1;
+ }
+ printf("err_struct_info=%lx\n", err_struct_info);
+
+ sprintf(fn, "%s/err_data_buffer", path);
+ if (rd(fn, &err_data_buffer)<0) {
+ perror("err_data_buffer reading error.\n");
+ return -1;
+ }
+ printf("err_data_buffer=%lx\n", err_data_buffer);
+
+ sprintf(fn, "%s/status", path);
+ if (rd("status", (u64*)&status)<0) {
+ perror("status reading error.\n");
+ return -1;
+ }
+ printf("status=%d\n", status);
+
+ sprintf(fn, "%s/capabilities", path);
+ if (rd(fn,&capabilities)<0) {
+ perror("capabilities reading error.\n");
+ return -1;
+ }
+ printf("capabilities=%lx\n", capabilities);
+
+ sprintf(fn, "%s/resources", path);
+ if (rd(fn, &resources)<0) {
+ perror("resources reading error.\n");
+ return -1;
+ }
+ printf("resources=%lx\n", resources);
+
+ return 0;
+}
+
+int query_capabilities(char *path, err_type_info_t err_type_info,
+ u64 *capabilities)
+{
+ char fn[MAX_FN_SIZE];
+ err_struct_info_t err_struct_info;
+ err_data_buffer_t err_data_buffer;
+
+ err_struct_info.err_struct_info=0;
+ memset(err_data_buffer.err_data_buffer, -1, ERR_DATA_BUFFER_SIZE*8);
+
+ sprintf(fn, "%s/err_type_info", path);
+ wr(fn, err_type_info.err_type_info);
+ sprintf(fn, "%s/err_struct_info", path);
+ wr(fn, 0x0);
+ sprintf(fn, "%s/err_data_buffer", path);
+ wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
+
+ // Fire pal_mc_error_inject procedure.
+ sprintf(fn, "%s/call_start", path);
+ wr(fn, mode);
+
+ if (rd_capabilities(path, capabilities)<0)
+ return -1;
+
+ return 0;
+}
+
+int query_all_capabilities()
+{
+ int status;
+ err_type_info_t err_type_info;
+ int err_sev, err_struct, struct_hier;
+ int cap=0;
+ u64 capabilities;
+ char path[MAX_FN_SIZE];
+
+ err_type_info.err_type_info=0; // Initial
+ err_type_info.err_type_info_u.mode=0; // Query mode;
+ err_type_info.err_type_info_u.err_inj=0;
+
+ printf("All capabilities implemented in pal_mc_error_inject:\n");
+ sprintf(path, PATH_FORMAT ,0);
+ for (err_sev=0;err_sev<3;err_sev++)
+ for (err_struct=0;err_struct<5;err_struct++)
+ for (struct_hier=0;struct_hier<5;struct_hier++)
+ {
+ status=-1;
+ capabilities=0;
+ err_type_info.err_type_info_u.err_sev=err_sev;
+ err_type_info.err_type_info_u.err_struct=err_struct;
+ err_type_info.err_type_info_u.struct_hier=struct_hier;
+
+ if (query_capabilities(path, err_type_info, &capabilities)<0)
+ continue;
+
+ if (rd_status(path, &status)<0)
+ continue;
+
+ if (status==0) {
+ cap=1;
+ printf("For err_sev=%d, err_struct=%d, struct_hier=%d: ",
+ err_sev, err_struct, struct_hier);
+ printf("capabilities 0x%lx\n", capabilities);
+ }
+ }
+ if (!cap) {
+ printf("No capabilities supported.\n");
+ return 0;
+ }
+
+ return 0;
+}
+
+int err_inject(int cpu, char *path, err_type_info_t err_type_info,
+ err_struct_info_t err_struct_info,
+ err_data_buffer_t err_data_buffer)
+{
+ int status;
+ char fn[MAX_FN_SIZE];
+
+ log_info(cpu, "err_type_info=%lx, err_struct_info=%lx, ",
+ err_type_info.err_type_info,
+ err_struct_info.err_struct_info);
+ log_info(cpu,"err_data_buffer=[%lx,%lx,%lx]\n",
+ err_data_buffer.err_data_buffer[0],
+ err_data_buffer.err_data_buffer[1],
+ err_data_buffer.err_data_buffer[2]);
+ sprintf(fn, "%s/err_type_info", path);
+ wr(fn, err_type_info.err_type_info);
+ sprintf(fn, "%s/err_struct_info", path);
+ wr(fn, err_struct_info.err_struct_info);
+ sprintf(fn, "%s/err_data_buffer", path);
+ wr_multi(fn, err_data_buffer.err_data_buffer, ERR_DATA_BUFFER_SIZE);
+
+ // Fire pal_mc_error_inject procedure.
+ sprintf(fn, "%s/call_start", path);
+ wr(fn,mode);
+
+ if (rd_status(path, &status)<0) {
+ vbprintf("fail: read status\n");
+ return -100;
+ }
+
+ if (status!=0) {
+ log_info(cpu, "fail: status=%d\n", status);
+ return status;
+ }
+
+ return status;
+}
+
+static int construct_data_buf(char *path, err_type_info_t err_type_info,
+ err_struct_info_t err_struct_info,
+ err_data_buffer_t *err_data_buffer,
+ void *va1)
+{
+ char fn[MAX_FN_SIZE];
+ u64 virt_addr=0, phys_addr=0;
+
+ vbprintf("va1=%lx\n", (u64)va1);
+ memset(&err_data_buffer->err_data_buffer_cache, 0, ERR_DATA_BUFFER_SIZE*8);
+
+ switch (err_type_info.err_type_info_u.err_struct) {
+ case 1: // Cache
+ switch (err_struct_info.err_struct_info_cache.cl_id) {
+ case 1: //Virtual addr
+ err_data_buffer->err_data_buffer_cache.inj_addr=(u64)va1;
+ break;
+ case 2: //Phys addr
+ sprintf(fn, "%s/virtual_to_phys", path);
+ virt_addr=(u64)va1;
+ if (wr(fn,virt_addr)<0)
+ return -1;
+ rd(fn, &phys_addr);
+ err_data_buffer->err_data_buffer_cache.inj_addr=phys_addr;
+ break;
+ default:
+ printf("Not supported cl_id\n");
+ break;
+ }
+ break;
+ case 2: // TLB
+ break;
+ case 3: // Register file
+ break;
+ case 4: // Bus/system interconnect
+ default:
+ printf("Not supported err_struct\n");
+ break;
+ }
+
+ return 0;
+}
+
+typedef struct {
+ u64 cpu;
+ u64 loop;
+ u64 interval;
+ u64 err_type_info;
+ u64 err_struct_info;
+ u64 err_data_buffer[ERR_DATA_BUFFER_SIZE];
+} parameters_t;
+
+parameters_t line_para;
+int para;
+
+static int empty_data_buffer(u64 *err_data_buffer)
+{
+ int empty=1;
+ int i;
+
+ for (i=0;i<ERR_DATA_BUFFER_SIZE; i++)
+ if (err_data_buffer[i]!=-1)
+ empty=0;
+
+ return empty;
+}
+
+int err_inj()
+{
+ err_type_info_t err_type_info;
+ err_struct_info_t err_struct_info;
+ err_data_buffer_t err_data_buffer;
+ int count;
+ FILE *fp;
+ unsigned long cpu, loop, interval, err_type_info_conf, err_struct_info_conf;
+ u64 err_data_buffer_conf[ERR_DATA_BUFFER_SIZE];
+ int num;
+ int i;
+ char path[MAX_FN_SIZE];
+ parameters_t parameters[MAX_TASK_NUM]={};
+ pid_t child_pid[MAX_TASK_NUM];
+ time_t current_time;
+ int status;
+
+ if (!para) {
+ fp=fopen("err.conf", "r");
+ if (fp==NULL) {
+ perror("Error open err.conf");
+ return -1;
+ }
+
+ num=0;
+ while (!feof(fp)) {
+ char buf[256];
+ memset(buf,0,256);
+ fgets(buf, 256, fp);
+ count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+ &cpu, &loop, &interval,&err_type_info_conf,
+ &err_struct_info_conf,
+ &err_data_buffer_conf[0],
+ &err_data_buffer_conf[1],
+ &err_data_buffer_conf[2]);
+ if (count!=PARA_FIELD_NUM+3) {
+ err_data_buffer_conf[0]=-1;
+ err_data_buffer_conf[1]=-1;
+ err_data_buffer_conf[2]=-1;
+ count=sscanf(buf, "%lx, %lx, %lx, %lx, %lx\n",
+ &cpu, &loop, &interval,&err_type_info_conf,
+ &err_struct_info_conf);
+ if (count!=PARA_FIELD_NUM)
+ continue;
+ }
+
+ parameters[num].cpu=cpu;
+ parameters[num].loop=loop;
+ parameters[num].interval= interval>MIN_INTERVAL
+ ?interval:MIN_INTERVAL;
+ parameters[num].err_type_info=err_type_info_conf;
+ parameters[num].err_struct_info=err_struct_info_conf;
+ memcpy(parameters[num++].err_data_buffer,
+ err_data_buffer_conf,ERR_DATA_BUFFER_SIZE*8) ;
+
+ if (num>=MAX_TASK_NUM)
+ break;
+ }
+ }
+ else {
+ parameters[0].cpu=line_para.cpu;
+ parameters[0].loop=line_para.loop;
+ parameters[0].interval= line_para.interval>MIN_INTERVAL
+ ?line_para.interval:MIN_INTERVAL;
+ parameters[0].err_type_info=line_para.err_type_info;
+ parameters[0].err_struct_info=line_para.err_struct_info;
+ memcpy(parameters[0].err_data_buffer,
+ line_para.err_data_buffer,ERR_DATA_BUFFER_SIZE*8) ;
+
+ num=1;
+ }
+
+ /* Create semaphore: If one_lock, one semaphore for all processors.
+ Otherwise, one sempaphore for each processor. */
+ if (one_lock) {
+ if (create_sem(0)) {
+ printf("Can not create semaphore...exit\n");
+ free_sem(0);
+ return -1;
+ }
+ }
+ else {
+ for (i=0;i<num;i++) {
+ if (create_sem(parameters[i].cpu)) {
+ printf("Can not create semaphore for cpu%d...exit\n",i);
+ free_sem(parameters[num].cpu);
+ return -1;
+ }
+ }
+ }
+
+ /* Create a shm segment which will be used to inject/consume errors on.*/
+ if (create_shm()==-1) {
+ printf("Error to create shm...exit\n");
+ return -1;
+ }
+
+ for (i=0;i<num;i++) {
+ pid_t pid;
+
+ current_time=time(NULL);
+ log_info(parameters[i].cpu, "\nBegine at %s", ctime(&current_time));
+ log_info(parameters[i].cpu, "Configurations:\n");
+ log_info(parameters[i].cpu,"On cpu%ld: loop=%lx, interval=%lx(s)",
+ parameters[i].cpu,
+ parameters[i].loop,
+ parameters[i].interval);
+ log_info(parameters[i].cpu," err_type_info=%lx,err_struct_info=%lx\n",
+ parameters[i].err_type_info,
+ parameters[i].err_struct_info);
+
+ sprintf(path, PATH_FORMAT, (int)parameters[i].cpu);
+ err_type_info.err_type_info=parameters[i].err_type_info;
+ err_struct_info.err_struct_info=parameters[i].err_struct_info;
+ memcpy(err_data_buffer.err_data_buffer,
+ parameters[i].err_data_buffer,
+ ERR_DATA_BUFFER_SIZE*8);
+
+ pid=fork();
+ if (pid==0) {
+ unsigned long mask[MASK_SIZE];
+ int j, k;
+
+ void *va1, *va2;
+
+ /* Allocate two memory areas va1 and va2 in shm */
+ va1=shmaddr+parameters[i].cpu*PAGE_SIZE;
+ va2=shmaddr+parameters[i].cpu*PAGE_SIZE+PAGE_SIZE;
+
+ vbprintf("va1=%lx, va2=%lx\n", (u64)va1, (u64)va2);
+ memset(va1, 0x1, PAGE_SIZE);
+ memset(va2, 0x2, PAGE_SIZE);
+
+ if (empty_data_buffer(err_data_buffer.err_data_buffer))
+ /* If not specified yet, construct data buffer
+ * with va1
+ */
+ construct_data_buf(path, err_type_info,
+ err_struct_info, &err_data_buffer,va1);
+
+ for (j=0;j<MASK_SIZE;j++)
+ mask[j]=0;
+
+ cpu=parameters[i].cpu;
+ k = cpu%64;
+ j = cpu/64;
+ mask[j]=1<<k;
+
+ if (sched_setaffinity(0, MASK_SIZE*8, mask)==-1) {
+ perror("Error sched_setaffinity:");
+ return -1;
+ }
+
+ for (j=0; j<parameters[i].loop; j++) {
+ log_info(parameters[i].cpu,"Injection ");
+ log_info(parameters[i].cpu,"on cpu%ld: #%d/%ld ",
+
+ parameters[i].cpu,j+1, parameters[i].loop);
+
+ /* Hold the lock */
+ if (one_lock)
+ lock(0);
+ else
+ /* Hold lock on this cpu */
+ lock(parameters[i].cpu);
+
+ if ((status=err_inject(parameters[i].cpu,
+ path, err_type_info,
+ err_struct_info, err_data_buffer))
+ ==0) {
+ /* consume the error for "inject only"*/
+ memcpy(va2, va1, PAGE_SIZE);
+ memcpy(va1, va2, PAGE_SIZE);
+ log_info(parameters[i].cpu,
+ "successful\n");
+ }
+ else {
+ log_info(parameters[i].cpu,"fail:");
+ log_info(parameters[i].cpu,
+ "status=%d\n", status);
+ unlock(parameters[i].cpu);
+ break;
+ }
+ if (one_lock)
+ /* Release the lock */
+ unlock(0);
+ /* Release lock on this cpu */
+ else
+ unlock(parameters[i].cpu);
+
+ if (j < parameters[i].loop-1)
+ sleep(parameters[i].interval);
+ }
+ current_time=time(NULL);
+ log_info(parameters[i].cpu, "Done at %s", ctime(&current_time));
+ return 0;
+ }
+ else if (pid<0) {
+ perror("Error fork:");
+ continue;
+ }
+ child_pid[i]=pid;
+ }
+ for (i=0;i<num;i++)
+ waitpid(child_pid[i], NULL, 0);
+
+ if (one_lock)
+ free_sem(0);
+ else
+ for (i=0;i<num;i++)
+ free_sem(parameters[i].cpu);
+
+ printf("All done.\n");
+
+ return 0;
+}
+
+void help()
+{
+ printf("err_inject_tool:\n");
+ printf("\t-q: query all capabilities. default: off\n");
+ printf("\t-m: procedure mode. 1: physical 2: virtual. default: 1\n");
+ printf("\t-i: inject errors. default: off\n");
+ printf("\t-l: one lock per cpu. default: one lock for all\n");
+ printf("\t-e: error parameters:\n");
+ printf("\t\tcpu,loop,interval,err_type_info,err_struct_info[,err_data_buffer[0],err_data_buffer[1],err_data_buffer[2]]\n");
+ printf("\t\t cpu: logical cpu number the error will be inject in.\n");
+ printf("\t\t loop: times the error will be injected.\n");
+ printf("\t\t interval: In second. every so often one error is injected.\n");
+ printf("\t\t err_type_info, err_struct_info: PAL parameters.\n");
+ printf("\t\t err_data_buffer: PAL parameter. Optional. If not present,\n");
+ printf("\t\t it's constructed by tool automatically. Be\n");
+ printf("\t\t careful to provide err_data_buffer and make\n");
+ printf("\t\t sure it's working with the environment.\n");
+ printf("\t Note:no space between error parameters.\n");
+ printf("\t default: Take error parameters from err.conf instead of command line.\n");
+ printf("\t-v: verbose. default: off\n");
+ printf("\t-h: help\n\n");
+ printf("The tool will take err.conf file as ");
+ printf("input to inject single or multiple errors ");
+ printf("on one or multiple cpus in parallel.\n");
+}
+
+int main(int argc, char **argv)
+{
+ char c;
+ int do_err_inj=0;
+ int do_query_all=0;
+ int count;
+ u32 m;
+
+ /* Default one lock for all cpu's */
+ one_lock=1;
+ while ((c = getopt(argc, argv, "m:iqvhle:")) != EOF)
+ switch (c) {
+ case 'm': /* Procedure mode. 1: phys 2: virt */
+ count=sscanf(optarg, "%x", &m);
+ if (count!=1 || (m!=1 && m!=2)) {
+ printf("Wrong mode number.\n");
+ help();
+ return -1;
+ }
+ mode=m;
+ break;
+ case 'i': /* Inject errors */
+ do_err_inj=1;
+ break;
+ case 'q': /* Query */
+ do_query_all=1;
+ break;
+ case 'v': /* Verbose */
+ verbose=1;
+ break;
+ case 'l': /* One lock per cpu */
+ one_lock=0;
+ break;
+ case 'e': /* error arguments */
+ /* Take parameters:
+ * #cpu, loop, interval, err_type_info, err_struct_info[, err_data_buffer]
+ * err_data_buffer is optional. Recommend not to specify
+ * err_data_buffer. Better to use tool to generate it.
+ */
+ count=sscanf(optarg,
+ "%lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx\n",
+ &line_para.cpu,
+ &line_para.loop,
+ &line_para.interval,
+ &line_para.err_type_info,
+ &line_para.err_struct_info,
+ &line_para.err_data_buffer[0],
+ &line_para.err_data_buffer[1],
+ &line_para.err_data_buffer[2]);
+ if (count!=PARA_FIELD_NUM+3) {
+ line_para.err_data_buffer[0]=-1,
+ line_para.err_data_buffer[1]=-1,
+ line_para.err_data_buffer[2]=-1;
+ count=sscanf(optarg, "%lx, %lx, %lx, %lx, %lx\n",
+ &line_para.cpu,
+ &line_para.loop,
+ &line_para.interval,
+ &line_para.err_type_info,
+ &line_para.err_struct_info);
+ if (count!=PARA_FIELD_NUM) {
+ printf("Wrong error arguments.\n");
+ help();
+ return -1;
+ }
+ }
+ para=1;
+ break;
+ continue;
+ break;
+ case 'h':
+ help();
+ return 0;
+ default:
+ break;
+ }
+
+ if (do_query_all)
+ query_all_capabilities();
+ if (do_err_inj)
+ err_inj();
+
+ if (!do_query_all && !do_err_inj)
+ help();
+
+ return 0;
+}
+
diff --git a/Documentation/input/atarikbd.txt b/Documentation/input/atarikbd.txt
index 668f4d0d97d..ab050621e20 100644
--- a/Documentation/input/atarikbd.txt
+++ b/Documentation/input/atarikbd.txt
@@ -179,9 +179,9 @@ reporting mode for joystick 1, with both buttons being logically assigned to
the mouse. After any joystick command, the ikbd assumes that joysticks are
connected to both Joystick0 and Joystick1. Any mouse command (except MOUSE
DISABLE) then causes port 0 to again be scanned as if it were a mouse, and
-both buttons are logically connected to it. If a mouse diable command is
+both buttons are logically connected to it. If a mouse disable command is
received while port 0 is presumed to be a mouse, the button is logically
-assigned to Joystick1 ( until the mouse is reenabled by another mouse command).
+assigned to Joystick1 (until the mouse is reenabled by another mouse command).
9. ikbd Command Set
diff --git a/Documentation/input/input-programming.txt b/Documentation/input/input-programming.txt
index 180e0689676..d9d523099bb 100644
--- a/Documentation/input/input-programming.txt
+++ b/Documentation/input/input-programming.txt
@@ -1,5 +1,3 @@
-$Id: input-programming.txt,v 1.4 2001/05/04 09:47:14 vojtech Exp $
-
Programming input drivers
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -20,28 +18,51 @@ pressed or released a BUTTON_IRQ happens. The driver could look like:
#include <asm/irq.h>
#include <asm/io.h>
+static struct input_dev *button_dev;
+
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
- input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
- input_sync(&button_dev);
+ input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
+ input_sync(button_dev);
}
static int __init button_init(void)
{
+ int error;
+
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
return -EBUSY;
}
-
- button_dev.evbit[0] = BIT(EV_KEY);
- button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
-
- input_register_device(&button_dev);
+
+ button_dev = input_allocate_device();
+ if (!button_dev) {
+ printk(KERN_ERR "button.c: Not enough memory\n");
+ error = -ENOMEM;
+ goto err_free_irq;
+ }
+
+ button_dev->evbit[0] = BIT(EV_KEY);
+ button_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+ error = input_register_device(button_dev);
+ if (error) {
+ printk(KERN_ERR "button.c: Failed to register device\n");
+ goto err_free_dev;
+ }
+
+ return 0;
+
+ err_free_dev:
+ input_free_device(button_dev);
+ err_free_irq:
+ free_irq(BUTTON_IRQ, button_interrupt);
+ return error;
}
static void __exit button_exit(void)
{
- input_unregister_device(&button_dev);
+ input_unregister_device(button_dev);
free_irq(BUTTON_IRQ, button_interrupt);
}
@@ -58,17 +79,18 @@ In the _init function, which is called either upon module load or when
booting the kernel, it grabs the required resources (it should also check
for the presence of the device).
-Then it sets the input bitfields. This way the device driver tells the other
+Then it allocates a new input device structure with input_aloocate_device()
+and sets up input bitfields. This way the device driver tells the other
parts of the input systems what it is - what events can be generated or
-accepted by this input device. Our example device can only generate EV_KEY type
-events, and from those only BTN_0 event code. Thus we only set these two
-bits. We could have used
+accepted by this input device. Our example device can only generate EV_KEY
+type events, and from those only BTN_0 event code. Thus we only set these
+two bits. We could have used
set_bit(EV_KEY, button_dev.evbit);
set_bit(BTN_0, button_dev.keybit);
as well, but with more than single bits the first approach tends to be
-shorter.
+shorter.
Then the example driver registers the input device structure by calling
@@ -76,16 +98,15 @@ Then the example driver registers the input device structure by calling
This adds the button_dev structure to linked lists of the input driver and
calls device handler modules _connect functions to tell them a new input
-device has appeared. Because the _connect functions may call kmalloc(,
-GFP_KERNEL), which can sleep, input_register_device() must not be called
-from an interrupt or with a spinlock held.
+device has appeared. input_register_device() may sleep and therefore must
+not be called from an interrupt or with a spinlock held.
While in use, the only used function of the driver is
button_interrupt()
which upon every interrupt from the button checks its state and reports it
-via the
+via the
input_report_key()
@@ -113,16 +134,10 @@ can use the open and close callback to know when it can stop polling or
release the interrupt and when it must resume polling or grab the interrupt
again. To do that, we would add this to our example driver:
-int button_used = 0;
-
static int button_open(struct input_dev *dev)
{
- if (button_used++)
- return 0;
-
if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
- button_used--;
return -EBUSY;
}
@@ -131,20 +146,21 @@ static int button_open(struct input_dev *dev)
static void button_close(struct input_dev *dev)
{
- if (!--button_used)
- free_irq(IRQ_AMIGA_VERTB, button_interrupt);
+ free_irq(IRQ_AMIGA_VERTB, button_interrupt);
}
static int __init button_init(void)
{
...
- button_dev.open = button_open;
- button_dev.close = button_close;
+ button_dev->open = button_open;
+ button_dev->close = button_close;
...
}
-Note the button_used variable - we have to track how many times the open
-function was called to know when exactly our device stops being used.
+Note that input core keeps track of number of users for the device and
+makes sure that dev->open() is called only when the first user connects
+to the device and that dev->close() is called when the very last user
+disconnects. Calls to both callbacks are serialized.
The open() callback should return a 0 in case of success or any nonzero value
in case of failure. The close() callback (which is void) must always succeed.
@@ -175,7 +191,7 @@ set the corresponding bits and call the
input_report_rel(struct input_dev *dev, int code, int value)
-function. Events are generated only for nonzero value.
+function. Events are generated only for nonzero value.
However EV_ABS requires a little special care. Before calling
input_register_device, you have to fill additional fields in the input_dev
@@ -187,6 +203,10 @@ the ABS_X axis:
button_dev.absfuzz[ABS_X] = 4;
button_dev.absflat[ABS_X] = 8;
+Or, you can just say:
+
+ input_set_abs_params(button_dev, ABS_X, 0, 255, 4, 8);
+
This setting would be appropriate for a joystick X axis, with the minimum of
0, maximum of 255 (which the joystick *must* be able to reach, no problem if
it sometimes reports more, but it must be able to always reach the min and
@@ -197,14 +217,7 @@ If you don't need absfuzz and absflat, you can set them to zero, which mean
that the thing is precise and always returns to exactly the center position
(if it has any).
-1.4 The void *private field
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This field in the input structure can be used to point to any private data
-structures in the input device driver, in case the driver handles more than
-one device. You'll need it in the open and close callbacks.
-
-1.5 NBITS(), LONG(), BIT()
+1.4 NBITS(), LONG(), BIT()
~~~~~~~~~~~~~~~~~~~~~~~~~~
These three macros from input.h help some bitfield computations:
@@ -213,13 +226,9 @@ These three macros from input.h help some bitfield computations:
LONG(x) - returns the index in the array in longs for bit x
BIT(x) - returns the index in a long for bit x
-1.6 The number, id* and name fields
+1.5 The id* and name fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The dev->number is assigned by the input system to the input device when it
-is registered. It has no use except for identifying the device to the user
-in system messages.
-
The dev->name should be set before registering the input device by the input
device driver. It's a string like 'Generic button device' containing a
user friendly name of the device.
@@ -234,15 +243,25 @@ driver.
The id and name fields can be passed to userland via the evdev interface.
-1.7 The keycode, keycodemax, keycodesize fields
+1.6 The keycode, keycodemax, keycodesize fields
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-These two fields will be used for any input devices that report their data
-as scancodes. If not all scancodes can be known by autodetection, they may
-need to be set by userland utilities. The keycode array then is an array
-used to map from scancodes to input system keycodes. The keycode max will
-contain the size of the array and keycodesize the size of each entry in it
-(in bytes).
+These three fields should be used by input devices that have dense keymaps.
+The keycode is an array used to map from scancodes to input system keycodes.
+The keycode max should contain the size of the array and keycodesize the
+size of each entry in it (in bytes).
+
+Userspace can query and alter current scancode to keycode mappings using
+EVIOCGKEYCODE and EVIOCSKEYCODE ioctls on corresponding evdev interface.
+When a device has all 3 aforementioned fields filled in, the driver may
+rely on kernel's default implementation of setting and querying keycode
+mappings.
+
+1.7 dev->getkeycode() and dev->setkeycode()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+getkeycode() and setkeycode() callbacks allow drivers to override default
+keycode/keycodesize/keycodemax mapping mechanism provided by input core
+and implement sparse keycode maps.
1.8 Key autorepeat
~~~~~~~~~~~~~~~~~~
@@ -266,7 +285,7 @@ direction - from the system to the input device driver. If your input device
driver can handle these events, it has to set the respective bits in evbit,
*and* also the callback routine:
- button_dev.event = button_event;
+ button_dev->event = button_event;
int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
{
diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt
index 5427bdf225e..aae0d404c56 100644
--- a/Documentation/input/xpad.txt
+++ b/Documentation/input/xpad.txt
@@ -65,15 +65,15 @@ of buttons, see section 0.3 - Unknown Controllers
I've tested this with Stepmania, and it works quite well.
-0.3 Unkown Controllers
+0.3 Unknown Controllers
----------------------
-If you have an unkown xbox controller, it should work just fine with
+If you have an unknown xbox controller, it should work just fine with
the default settings.
HOWEVER if you have an unknown dance pad not listed below, it will not
work UNLESS you set "dpad_to_buttons" to 1 in the module configuration.
-PLEASE if you have an unkown controller, email Dom <binary1230@yahoo.com> with
+PLEASE, if you have an unknown controller, email Dom <binary1230@yahoo.com> with
a dump from /proc/bus/usb and a description of the pad (manufacturer, country,
whether it is a dance pad or normal controller) so that we can add your pad
to the list of supported devices, ensuring that it will work out of the
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 8f750c0efed..3de7d379cf0 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -138,7 +138,8 @@ Code Seq# Include File Comments
'm' 00-1F net/irda/irmod.h conflict!
'n' 00-7F linux/ncp_fs.h
'n' E0-FF video/matrox.h matroxfb
-'p' 00-3F linux/mc146818rtc.h
+'p' 00-0F linux/phantom.h conflict! (OpenHaptics needs this)
+'p' 00-3F linux/mc146818rtc.h conflict!
'p' 40-7F linux/nvram.h
'p' 80-9F user-space parport
<mailto:tim@cyberelk.net>
diff --git a/Documentation/isdn/CREDITS b/Documentation/isdn/CREDITS
index e1b3023efaa..7c17c837064 100644
--- a/Documentation/isdn/CREDITS
+++ b/Documentation/isdn/CREDITS
@@ -2,7 +2,7 @@
I want to thank all who contributed to this project and especially to:
(in alphabetical order)
-Thomas Bogendörfer (tsbogend@bigbug.franken.de)
+Thomas Bogendörfer (tsbogend@bigbug.franken.de)
Tester, lots of bugfixes and hints.
Alan Cox (alan@redhat.com)
@@ -11,7 +11,7 @@ Alan Cox (alan@redhat.com)
Henner Eisen (eis@baty.hanse.de)
For X.25 implementation.
-Volker Götz (volker@oops.franken.de)
+Volker Götz (volker@oops.franken.de)
For contribution of man-pages, the imontty-tool and a perfect
maintaining of the mailing-list at hub-wue.
diff --git a/Documentation/isdn/README b/Documentation/isdn/README
index 76159524393..6783437f21c 100644
--- a/Documentation/isdn/README
+++ b/Documentation/isdn/README
@@ -402,7 +402,7 @@ README for the ISDN-subsystem
the script tools/tcltk/isdnmon. You can add actions for line-status
changes. See the comments at the beginning of the script for how to
do that. There are other tty-based tools in the tools-subdirectory
- contributed by Michael Knigge (imon), Volker Götz (imontty) and
+ contributed by Michael Knigge (imon), Volker Götz (imontty) and
Andreas Kool (isdnmon).
l) For initial testing, you can set the verbose-level to 2 (default: 0).
diff --git a/Documentation/isdn/README.icn b/Documentation/isdn/README.icn
index a5f55eadb3c..13f833d4e91 100644
--- a/Documentation/isdn/README.icn
+++ b/Documentation/isdn/README.icn
@@ -3,8 +3,8 @@ $Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
You can get the ICN-ISDN-card from:
Thinking Objects Software GmbH
-Versbacher Röthe 159
-97078 Würzburg
+Versbacher Röthe 159
+97078 Würzburg
Tel: +49 931 2877950
Fax: +49 931 2877951
diff --git a/Documentation/java.txt b/Documentation/java.txt
index c768dc63b34..3cce3fbb664 100644
--- a/Documentation/java.txt
+++ b/Documentation/java.txt
@@ -390,7 +390,7 @@ the execution bit, then just do
originally by Brian A. Lantz, brian@lantz.com
-heavily edited for binfmt_misc by Richard Günther
+heavily edited for binfmt_misc by Richard Günther
new scripts by Colin J. Watson <cjw44@cam.ac.uk>
added executable Jar file support by Kurt Huwig <kurt@iku-netz.de>
diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt
index 769ee05ee4d..1d247d59ad5 100644
--- a/Documentation/kbuild/modules.txt
+++ b/Documentation/kbuild/modules.txt
@@ -249,7 +249,7 @@ following files:
--> filename: Makefile
KERNELDIR := /lib/modules/`uname -r`/build
all::
- $(MAKE) -C $KERNELDIR M=`pwd` $@
+ $(MAKE) -C $(KERNELDIR) M=`pwd` $@
# Module specific targets
genbin:
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index c68dafeda7a..d9e3b199929 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -236,7 +236,7 @@
* Title: "Design and Implementation of the Second Extended
Filesystem"
- Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
+ Author: Rémy Card, Theodore Ts'o, Stephen Tweedie.
URL: http://web.mit.edu/tytso/www/linux/ext2intro.html
Keywords: ext2, linux fs history, inode, directory, link, devices,
VFS, physical structure, performance, benchmarks, ext2fs library,
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 2017942e096..6b8ad06846c 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -64,6 +64,7 @@ parameter is applicable:
GENERIC_TIME The generic timeofday code is enabled.
NFS Appropriate NFS support is enabled.
OSS OSS sound support is enabled.
+ PV_OPS A paravirtualized kernel
PARIDE The ParIDE subsystem is enabled.
PARISC The PA-RISC architecture is enabled.
PCI PCI bus support is enabled.
@@ -181,19 +182,41 @@ and is between 256 and 4096 characters. It is defined in the file
that require a timer override, but don't have
HPET
- acpi_dbg_layer= [HW,ACPI]
+ acpi.debug_layer= [HW,ACPI]
Format: <int>
Each bit of the <int> indicates an ACPI debug layer,
1: enable, 0: disable. It is useful for boot time
debugging. After system has booted up, it can be set
- via /proc/acpi/debug_layer.
-
- acpi_dbg_level= [HW,ACPI]
+ via /sys/module/acpi/parameters/debug_layer.
+ CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
+ Available bits (add the numbers together) to enable debug output
+ for specific parts of the ACPI subsystem:
+ 0x01 utilities 0x02 hardware 0x04 events 0x08 tables
+ 0x10 namespace 0x20 parser 0x40 dispatcher
+ 0x80 executer 0x100 resources 0x200 acpica debugger
+ 0x400 os services 0x800 acpica disassembler.
+ The number can be in decimal or prefixed with 0x in hex.
+ Warning: Many of these options can produce a lot of
+ output and make your system unusable. Be very careful.
+
+ acpi.debug_level= [HW,ACPI]
Format: <int>
Each bit of the <int> indicates an ACPI debug level,
1: enable, 0: disable. It is useful for boot time
debugging. After system has booted up, it can be set
- via /proc/acpi/debug_level.
+ via /sys/module/acpi/parameters/debug_level.
+ CONFIG_ACPI_DEBUG must be enabled for this to produce any output.
+ Available bits (add the numbers together) to enable different
+ debug output levels of the ACPI subsystem:
+ 0x01 error 0x02 warn 0x04 init 0x08 debug object
+ 0x10 info 0x20 init names 0x40 parse 0x80 load
+ 0x100 dispatch 0x200 execute 0x400 names 0x800 operation region
+ 0x1000 bfield 0x2000 tables 0x4000 values 0x8000 objects
+ 0x10000 resources 0x20000 user requests 0x40000 package.
+ The number can be in decimal or prefixed with 0x in hex.
+ Warning: Many of these options can produce a lot of
+ output and make your system unusable. Be very careful.
+
acpi_fake_ecdt [HW,ACPI] Workaround failure due to BIOS lacking ECDT
@@ -473,6 +496,30 @@ and is between 256 and 4096 characters. It is defined in the file
Format: <area>[,<node>]
See also Documentation/networking/decnet.txt.
+ default_blu= [VT]
+ Format: <blue0>,<blue1>,<blue2>,...,<blue15>
+ Change the default blue palette of the console.
+ This is a 16-member array composed of values
+ ranging from 0-255.
+
+ default_grn= [VT]
+ Format: <green0>,<green1>,<green2>,...,<green15>
+ Change the default green palette of the console.
+ This is a 16-member array composed of values
+ ranging from 0-255.
+
+ default_red= [VT]
+ Format: <red0>,<red1>,<red2>,...,<red15>
+ Change the default red palette of the console.
+ This is a 16-member array composed of values
+ ranging from 0-255.
+
+ default_utf8= [VT]
+ Format=<0|1>
+ Set system-wide default UTF-8 mode for all tty's.
+ Default is 0 and by setting to 1, it enables UTF-8
+ mode for all newly opened or allocated terminals.
+
dhash_entries= [KNL]
Set number of hash buckets for dentry cache.
@@ -673,8 +720,15 @@ and is between 256 and 4096 characters. It is defined in the file
idebus= [HW] (E)IDE subsystem - VLB/PCI bus speed
See Documentation/ide.txt.
- idle= [HW]
- Format: idle=poll or idle=halt
+ idle= [X86]
+ Format: idle=poll or idle=mwait
+ Poll forces a polling idle loop that can slightly improves the performance
+ of waking up a idle CPU, but will use a lot of power and make the system
+ run hot. Not recommended.
+ idle=mwait. On systems which support MONITOR/MWAIT but the kernel chose
+ to not use it because it doesn't save as much power as a normal idle
+ loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same
+ as idle=poll.
ignore_loglevel [KNL]
Ignore loglevel setting - this will print /all/
@@ -786,6 +840,11 @@ and is between 256 and 4096 characters. It is defined in the file
lasi= [HW,SCSI] PARISC LASI driver for the 53c700 chip
Format: addr:<io>,irq:<irq>
+ legacy_serial.force [HW,IA-32,X86-64]
+ Probe for COM ports at legacy addresses even
+ if PNPBIOS or ACPI should describe them. This
+ is for working around firmware defects.
+
llsc*= [IA64] See function print_params() in
arch/ia64/sn/kernel/llsc4.c.
@@ -1135,6 +1194,11 @@ and is between 256 and 4096 characters. It is defined in the file
nomce [IA-32] Machine Check Exception
+ noreplace-paravirt [IA-32,PV_OPS] Don't patch paravirt_ops
+
+ noreplace-smp [IA-32,SMP] Don't replace SMP instructions
+ with UP alternatives
+
noresidual [PPC] Don't use residual data on PReP machines.
noresume [SWSUSP] Disables resume and restores original swap
@@ -1540,6 +1604,20 @@ and is between 256 and 4096 characters. It is defined in the file
smart2= [HW]
Format: <io1>[,<io2>[,...,<io8>]]
+ smp-alt-once [IA-32,SMP] On a hotplug CPU system, only
+ attempt to substitute SMP alternatives once at boot.
+
+ smsc-ircc2.nopnp [HW] Don't use PNP to discover SMC devices
+ smsc-ircc2.ircc_cfg= [HW] Device configuration I/O port
+ smsc-ircc2.ircc_sir= [HW] SIR base I/O port
+ smsc-ircc2.ircc_fir= [HW] FIR base I/O port
+ smsc-ircc2.ircc_irq= [HW] IRQ line
+ smsc-ircc2.ircc_dma= [HW] DMA channel
+ smsc-ircc2.ircc_transceiver= [HW] Transceiver type:
+ 0: Toshiba Satellite 1800 (GP data pin select)
+ 1: Fast pin select (default)
+ 2: ATC IRMode
+
snd-ad1816a= [HW,ALSA]
snd-ad1848= [HW,ALSA]
@@ -1798,6 +1876,7 @@ and is between 256 and 4096 characters. It is defined in the file
[USBHID] The interval which mice are to be polled at.
vdso= [IA-32,SH]
+ vdso=2: enable compat VDSO (default with COMPAT_VDSO)
vdso=1: enable VDSO (default)
vdso=0: disable VDSO mapping
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index d71fafffce9..da5404ab756 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -14,6 +14,7 @@ CONTENTS
8. Kprobes Example
9. Jprobes Example
10. Kretprobes Example
+Appendix A: The kprobes debugfs interface
1. Concepts: Kprobes, Jprobes, Return Probes
@@ -349,9 +350,12 @@ for instrumentation and error reporting.)
If the number of times a function is called does not match the number
of times it returns, registering a return probe on that function may
-produce undesirable results. We have the do_exit() case covered.
-do_execve() and do_fork() are not an issue. We're unaware of other
-specific cases where this could be a problem.
+produce undesirable results. In such a case, a line:
+kretprobe BUG!: Processing kretprobe d000000000041aa8 @ c00000000004f48c
+gets printed. With this information, one will be able to correlate the
+exact instance of the kretprobe that caused the problem. We have the
+do_exit() case covered. do_execve() and do_fork() are not an issue.
+We're unaware of other specific cases where this could be a problem.
If, upon entry to or exit from a function, the CPU is running on
a stack other than that of the current task, registering a return
@@ -614,3 +618,27 @@ http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
http://www.redhat.com/magazine/005mar05/features/kprobes/
http://www-users.cs.umn.edu/~boutcher/kprobes/
http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
+
+
+Appendix A: The kprobes debugfs interface
+
+With recent kernels (> 2.6.20) the list of registered kprobes is visible
+under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug).
+
+/debug/kprobes/list: Lists all registered probes on the system
+
+c015d71a k vfs_read+0x0
+c011a316 j do_fork+0x0
+c03dedc5 r tcp_v4_rcv+0x0
+
+The first column provides the kernel address where the probe is inserted.
+The second column identifies the type of probe (k - kprobe, r - kretprobe
+and j - jprobe), while the third column specifies the symbol+offset of
+the probe. If the probed function belongs to a module, the module name
+is also specified.
+
+/debug/kprobes/enabled: Turn kprobes ON/OFF
+
+Provides a knob to globally turn registered kprobes ON or OFF. By default,
+all kprobes are enabled. By echoing "0" to this file, all registered probes
+will be disarmed, till such time a "1" is echoed to this file.
diff --git a/Documentation/laptop-mode.txt b/Documentation/laptop-mode.txt
index 6f639e3473a..eeedee11c8c 100644
--- a/Documentation/laptop-mode.txt
+++ b/Documentation/laptop-mode.txt
@@ -33,7 +33,7 @@ or anything. Simply install all the files included in this document, and
laptop mode will automatically be started when you're on battery. For
your convenience, a tarball containing an installer can be downloaded at:
-http://www.xs4all.nl/~bsamwel/laptop_mode/tools/
+http://www.samwel.tk/laptop_mode/laptop_mode/
To configure laptop mode, you need to edit the configuration file, which is
located in /etc/default/laptop-mode on Debian-based systems, or in
diff --git a/Documentation/m68k/README.buddha b/Documentation/m68k/README.buddha
index ef484a719bb..3ea9827ba3c 100644
--- a/Documentation/m68k/README.buddha
+++ b/Documentation/m68k/README.buddha
@@ -204,7 +204,7 @@ always shows a "no IRQ here" on the Buddha, and accesses to
the third IDE port are going into data's Nirwana on the
Buddha.
- Jens Schönfeld february 19th, 1997
+ Jens Schönfeld february 19th, 1997
updated may 27th, 1997
eMail: sysop@nostlgic.tng.oche.de
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
index 0e740c812d1..bd450e79755 100644
--- a/Documentation/magic-number.txt
+++ b/Documentation/magic-number.txt
@@ -129,7 +129,7 @@ SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda include/asm-mips64/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h
-EEPROM_MAGIC_VALUE 0X5ab478d2 lanai_dev drivers/atm/lanai.c
+EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h
EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h
PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 2202f5dc8ac..5818628207b 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -178,6 +178,21 @@ All md devices contain:
The size should be at least PAGE_SIZE (4k) and should be a power
of 2. This can only be set while assembling an array
+ layout
+ The "layout" for the array for the particular level. This is
+ simply a number that is interpretted differently by different
+ levels. It can be written while assembling an array.
+
+ reshape_position
+ This is either "none" or a sector number within the devices of
+ the array where "reshape" is up to. If this is set, the three
+ attributes mentioned above (raid_disks, chunk_size, layout) can
+ potentially have 2 values, an old and a new value. If these
+ values differ, reading the attribute returns
+ new (old)
+ and writing will effect the 'new' value, leaving the 'old'
+ unchanged.
+
component_size
For arrays with data redundancy (i.e. not raid0, linear, faulty,
multipath), all components must be the same size - or at least
@@ -193,11 +208,6 @@ All md devices contain:
1.2 (newer format in varying locations) or "none" indicating that
the kernel isn't managing metadata at all.
- layout
- The "layout" for the array for the particular level. This is
- simply a number that is interpretted differently by different
- levels. It can be written while assembling an array.
-
resync_start
The point at which resync should start. If no resync is needed,
this will be a very large number. At array creation it will
@@ -259,29 +269,6 @@ All md devices contain:
like active, but no writes have been seen for a while (safe_mode_delay).
- sync_speed_min
- sync_speed_max
- This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
- however they only apply to the particular array.
- If no value has been written to these, of if the word 'system'
- is written, then the system-wide value is used. If a value,
- in kibibytes-per-second is written, then it is used.
- When the files are read, they show the currently active value
- followed by "(local)" or "(system)" depending on whether it is
- a locally set or system-wide value.
-
- sync_completed
- This shows the number of sectors that have been completed of
- whatever the current sync_action is, followed by the number of
- sectors in total that could need to be processed. The two
- numbers are separated by a '/' thus effectively showing one
- value, a fraction of the process that is complete.
-
- sync_speed
- This shows the current actual speed, in K/sec, of the current
- sync_action. It is averaged over the last 30 seconds.
-
-
As component devices are added to an md array, they appear in the 'md'
directory as new directories named
dev-XXX
@@ -412,6 +399,35 @@ also have
Note that the numbers are 'bit' numbers, not 'block' numbers.
They should be scaled by the bitmap_chunksize.
+ sync_speed_min
+ sync_speed_max
+ This are similar to /proc/sys/dev/raid/speed_limit_{min,max}
+ however they only apply to the particular array.
+ If no value has been written to these, of if the word 'system'
+ is written, then the system-wide value is used. If a value,
+ in kibibytes-per-second is written, then it is used.
+ When the files are read, they show the currently active value
+ followed by "(local)" or "(system)" depending on whether it is
+ a locally set or system-wide value.
+
+ sync_completed
+ This shows the number of sectors that have been completed of
+ whatever the current sync_action is, followed by the number of
+ sectors in total that could need to be processed. The two
+ numbers are separated by a '/' thus effectively showing one
+ value, a fraction of the process that is complete.
+
+ sync_speed
+ This shows the current actual speed, in K/sec, of the current
+ sync_action. It is averaged over the last 30 seconds.
+
+ suspend_lo
+ suspend_hi
+ The two values, given as numbers of sectors, indicate a range
+ within the array where IO will be blocked. This is currently
+ only supported for raid4/5/6.
+
+
Each active md device may also have attributes specific to the
personality module that manages it.
These are specific to the implementation of the module and could
diff --git a/Documentation/netlabel/introduction.txt b/Documentation/netlabel/introduction.txt
index a4ffba1694c..5ecd8d1dcf4 100644
--- a/Documentation/netlabel/introduction.txt
+++ b/Documentation/netlabel/introduction.txt
@@ -30,7 +30,7 @@ The communication layer exists to allow NetLabel configuration and monitoring
from user space. The NetLabel communication layer uses a message based
protocol built on top of the Generic NETLINK transport mechanism. The exact
formatting of these NetLabel messages as well as the Generic NETLINK family
-names can be found in the the 'net/netlabel/' directory as comments in the
+names can be found in the 'net/netlabel/' directory as comments in the
header files as well as in 'include/net/netlabel.h'.
* Security Module API
diff --git a/Documentation/networking/6pack.txt b/Documentation/networking/6pack.txt
index 48ed2b711bd..d0777a1200e 100644
--- a/Documentation/networking/6pack.txt
+++ b/Documentation/networking/6pack.txt
@@ -1,6 +1,6 @@
This is the 6pack-mini-HOWTO, written by
-Andreas Könsgen DG3KQ
+Andreas Könsgen DG3KQ
Internet: ajk@iehk.rwth-aachen.de
AMPR-net: dg3kq@db0pra.ampr.org
AX.25: dg3kq@db0ach.#nrw.deu.eu
diff --git a/Documentation/networking/NAPI_HOWTO.txt b/Documentation/networking/NAPI_HOWTO.txt
index fb8dc6422a5..7907435a661 100644
--- a/Documentation/networking/NAPI_HOWTO.txt
+++ b/Documentation/networking/NAPI_HOWTO.txt
@@ -160,7 +160,7 @@ on current cpu. This primitive is called by dev->poll(), when
it completes its work. The device cannot be out of poll list at this
call, if it is then clearly it is a BUG(). You'll know ;->
-All these above nethods are used below. So keep reading for clarity.
+All of the above methods are used below, so keep reading for clarity.
Device driver changes to be made when porting NAPI
==================================================
diff --git a/Documentation/networking/bcm43xx.txt b/Documentation/networking/bcm43xx.txt
index 28541d2bee1..a136721499b 100644
--- a/Documentation/networking/bcm43xx.txt
+++ b/Documentation/networking/bcm43xx.txt
@@ -2,35 +2,88 @@
BCM43xx Linux Driver Project
============================
-About this software
--------------------
+Introduction
+------------
-The goal of this project is to develop a linux driver for Broadcom
-BCM43xx chips, based on the specification at
-http://bcm-specs.sipsolutions.net/
+Many of the wireless devices found in modern notebook computers are
+based on the wireless chips produced by Broadcom. These devices have
+been a problem for Linux users as there is no open-source driver
+available. In addition, Broadcom has not released specifications
+for the device, and driver availability has been limited to the
+binary-only form used in the GPL versions of AP hardware such as the
+Linksys WRT54G, and the Windows and OS X drivers. Before this project
+began, the only way to use these devices were to use the Windows or
+OS X drivers with either the Linuxant or ndiswrapper modules. There
+is a strong penalty if this method is used as loading the binary-only
+module "taints" the kernel, and no kernel developer will help diagnose
+any kernel problems.
-The project page is http://bcm43xx.berlios.de/
+Development
+-----------
+This driver has been developed using
+a clean-room technique that is described at
+http://bcm-specs.sipsolutions.net/ReverseEngineeringProcess. For legal
+reasons, none of the clean-room crew works on the on the Linux driver,
+and none of the Linux developers sees anything but the specifications,
+which are the ultimate product of the reverse-engineering group.
-Requirements
-------------
+Software
+--------
+
+Since the release of the 2.6.17 kernel, the bcm43xx driver has been
+distributed with the kernel source, and is prebuilt in most, if not
+all, distributions. There is, however, additional software that is
+required. The firmware used by the chip is the intellectual property
+of Broadcom and they have not given the bcm43xx team redistribution
+rights to this firmware. Since we cannot legally redistribute
+the firwmare we cannot include it with the driver. Furthermore, it
+cannot be placed in the downloadable archives of any distributing
+organization; therefore, the user is responsible for obtaining the
+firmware and placing it in the appropriate location so that the driver
+can find it when initializing.
+
+To help with this process, the bcm43xx developers provide a separate
+program named bcm43xx-fwcutter to "cut" the firmware out of a
+Windows or OS X driver and write the extracted files to the proper
+location. This program is usually provided with the distribution;
+however, it may be downloaded from
+
+http://developer.berlios.de/project/showfiles.php?group_id=4547
-1) Linux Kernel 2.6.16 or later
- http://www.kernel.org/
+The firmware is available in two versions. V3 firmware is used with
+the in-kernel bcm43xx driver that uses a software MAC layer called
+SoftMAC, and will have a microcode revision of 0x127 or smaller. The
+V4 firmware is used by an out-of-kernel driver employing a variation of
+the Devicescape MAC layer known as d80211. Once bcm43xx-d80211 reaches
+a satisfactory level of development, it will replace bcm43xx-softmac
+in the kernel as it is much more flexible and powerful.
- You may want to configure your kernel with:
+A source for the latest V3 firmware is
- CONFIG_DEBUG_FS (optional):
- -> Kernel hacking
- -> Debug Filesystem
+http://downloads.openwrt.org/sources/wl_apsta-3.130.20.0.o
-2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211
- modules:
- http://softmac.sipsolutions.net/
+Once this file is downloaded, the command
+'bcm43xx-fwcutter -w <dir> <filename>'
+will extract the microcode and write it to directory
+<dir>. The correct directory will depend on your distribution;
+however, most use '/lib/firmware'. Once this step is completed,
+the bcm3xx driver should load when the system is booted. To see
+any messages relating to the driver, issue the command 'dmesg |
+grep bcm43xx' from a terminal window. If there are any problems,
+please send that output to Bcm43xx-dev@lists.berlios.de.
-3) Firmware Files
+Although the driver has been in-kernel since 2.6.17, the earliest
+version is quite limited in its capability. Patches that include
+all features of later versions are available for the stable kernel
+versions from 2.6.18. These will be needed if you use a BCM4318,
+or a PCI Express version (BCM4311 and BCM4312). In addition, if you
+have an early BCM4306 and more than 1 GB RAM, your kernel will need
+to be patched. These patches, which are being updated regularly,
+are available at ftp://lwfinger.dynalias.org/patches. Look for
+combined_2.6.YY.patch. Of course you will need kernel source downloaded
+from kernel.org, or the source from your distribution.
- Please try fwcutter. Fwcutter can extract the firmware from various
- binary driver files. It supports driver files from Windows, MacOS and
- Linux. You can get fwcutter from http://bcm43xx.berlios.de/.
- Also, fwcutter comes with a README file for further instructions.
+If you build your own kernel, please enable CONFIG_BCM43XX_DEBUG
+and CONFIG_IEEE80211_SOFTMAC_DEBUG. The log information provided is
+essential for solving any problems.
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 5a232d946be..db0cd516958 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -13,7 +13,7 @@ You can find the latest version of this document at
Please send me your comments to
- Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
+ Ulisses Alonso Camaró <uaca@i.hate.spam.alumni.uv.es>
-------------------------------------------------------------------------------
+ Why use PACKET_MMAP
diff --git a/Documentation/networking/slicecom.hun b/Documentation/networking/slicecom.hun
index 5acf1918694..bed2f045e55 100644
--- a/Documentation/networking/slicecom.hun
+++ b/Documentation/networking/slicecom.hun
@@ -1,7 +1,7 @@
SliceCOM adapter felhasznaloi dokumentacioja - 0.51 verziohoz
-Bartók István <bartoki@itc.hu>
+Bartók István <bartoki@itc.hu>
Utolso modositas: Wed Aug 29 17:26:58 CEST 2001
-----------------------------------------------------------------
diff --git a/Documentation/networking/slicecom.txt b/Documentation/networking/slicecom.txt
index 32d3b916afa..c82c0cf981b 100644
--- a/Documentation/networking/slicecom.txt
+++ b/Documentation/networking/slicecom.txt
@@ -1,9 +1,9 @@
SliceCOM adapter user's documentation - for the 0.51 driver version
-Written by Bartók István <bartoki@itc.hu>
+Written by Bartók István <bartoki@itc.hu>
-English translation: Lakatos György <gyuri@itc.hu>
+English translation: Lakatos György <gyuri@itc.hu>
Mon Dec 11 15:28:42 CET 2000
Last modified: Wed Aug 29 17:25:37 CEST 2001
diff --git a/Documentation/networking/tms380tr.txt b/Documentation/networking/tms380tr.txt
index c169a57bc92..1f73e13058d 100644
--- a/Documentation/networking/tms380tr.txt
+++ b/Documentation/networking/tms380tr.txt
@@ -71,24 +71,24 @@ Below find attached the setting for the SK NET TR 4/16 ISA adapters
CHAPTER 1 LOCATION OF DIP-SWITCH
==============================================================
-UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
-þUÄÄÄÄÄÄ¿ UÄÄÄÄÄ¿ UÄÄÄ¿ þ
-þAÄÄÄÄÄÄU W1 AÄÄÄÄÄU UÄÄÄÄ¿ þ þ þ
-þUÄÄÄÄÄÄ¿ þ þ þ þ UÄÄÅ¿
-þAÄÄÄÄÄÄU UÄÄÄÄÄÄÄÄÄÄÄ¿ AÄÄÄÄU þ þ þ þþ
-þUÄÄÄÄÄÄ¿ þ þ UÄÄÄ¿ AÄÄÄU AÄÄÅU
-þAÄÄÄÄÄÄU þ TMS380C26 þ þ þ þ
-þUÄÄÄÄÄÄ¿ þ þ AÄÄÄU AÄ¿
-þAÄÄÄÄÄÄU þ þ þ þ
-þ AÄÄÄÄÄÄÄÄÄÄÄU þ þ
-þ þ þ
-þ AÄU
-þ þ
-þ þ
-þ þ
-þ þ
-AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
- AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU
+UÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
+þUÄÄÄÄÄÄ¿ UÄÄÄÄÄ¿ UÄÄÄ¿ þ
+þAÄÄÄÄÄÄU W1 AÄÄÄÄÄU UÄÄÄÄ¿ þ þ þ
+þUÄÄÄÄÄÄ¿ þ þ þ þ UÄÄÅ¿
+þAÄÄÄÄÄÄU UÄÄÄÄÄÄÄÄÄÄÄ¿ AÄÄÄÄU þ þ þ þþ
+þUÄÄÄÄÄÄ¿ þ þ UÄÄÄ¿ AÄÄÄU AÄÄÅU
+þAÄÄÄÄÄÄU þ TMS380C26 þ þ þ þ
+þUÄÄÄÄÄÄ¿ þ þ AÄÄÄU AÄ¿
+þAÄÄÄÄÄÄU þ þ þ þ
+þ AÄÄÄÄÄÄÄÄÄÄÄU þ þ
+þ þ þ
+þ AÄU
+þ þ
+þ þ
+þ þ
+þ þ
+AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
+ AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU AÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄU
==============================================================
CHAPTER 2 DEFAULT SETTINGS
@@ -108,9 +108,9 @@ AÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄAÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄAÄÄÄÄÄÄÄÄÄU
CHAPTER 3 DIP SWITCH W1 DESCRIPTION
==============================================================
- UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄ¿ ON
- þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ
- AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU OFF
+ UÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄ¿ ON
+ þ 1 þ 2 þ 3 þ 4 þ 5 þ 6 þ 7 þ 8 þ
+ AÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄAÄÄÄU OFF
|AD | BootROM Addr. | I/O |
+-+-+-------+-------+-----+-----+
| | |
diff --git a/Documentation/networking/udplite.txt b/Documentation/networking/udplite.txt
index dd6f46b83da..6be09ba24a3 100644
--- a/Documentation/networking/udplite.txt
+++ b/Documentation/networking/udplite.txt
@@ -139,7 +139,7 @@
3) Disabling the Checksum Computation
On both sender and receiver, checksumming will always be performed
- and can not be disabled using SO_NO_CHECK. Thus
+ and cannot be disabled using SO_NO_CHECK. Thus
setsockopt(sockfd, SOL_SOCKET, SO_NO_CHECK, ... );
diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt
index 07dd6d9930a..bc2ab419a74 100644
--- a/Documentation/networking/wan-router.txt
+++ b/Documentation/networking/wan-router.txt
@@ -335,7 +335,7 @@ REVISION HISTORY
creating applications using BiSync
streaming.
-2.0.5 Aug 04, 1999 CHDLC initializatin bug fix.
+2.0.5 Aug 04, 1999 CHDLC initialization bug fix.
PPP interrupt driven driver:
Fix to the PPP line hangup problem.
New PPP firmware
@@ -372,7 +372,7 @@ REVISION HISTORY
o cfgft1 GUI csu/dsu configurator
o wancfg GUI configuration file
configurator.
- o Architectual directory changes.
+ o Architectural directory changes.
beta-2.1.4 Jul 2000 o Dynamic interface configuration:
Network interfaces reflect the state
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index ea55ea8bc8e..7d5b60dea55 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -234,9 +234,6 @@ characters, each representing a particular tainted value.
6: 'B' if a page-release function has found a bad page reference or
some unexpected page flags.
- 7: 'U' if a user specifically requested that the Tainted flag be set,
- ' ' otherwise.
-
7: 'U' if a user or user application specifically requested that the
Tainted flag be set, ' ' otherwise.
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index cdf2f3c0ab1..d38261b6790 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -124,10 +124,6 @@ initialization with a pointer to a structure describing the driver
err_handler See Documentation/pci-error-recovery.txt
- multithread_probe Enable multi-threaded probe/scan. Driver must
- provide its own locking/syncronization for init
- operations if this is enabled.
-
The ID table is an array of struct pci_device_id entries ending with an
all-zero entry. Each entry consists of:
@@ -163,9 +159,9 @@ echo "vendor device subvendor subdevice class class_mask driver_data" > \
/sys/bus/pci/drivers/{driver}/new_id
All fields are passed in as hexadecimal values (no leading 0x).
-Users need pass only as many fields as necessary:
- o vendor, device, subvendor, and subdevice fields default
- to PCI_ANY_ID (FFFFFFFF),
+The vendor and device fields are mandatory, the others are optional. Users
+need pass only as many optional fields as necessary:
+ o subvendor and subdevice fields default to PCI_ANY_ID (FFFFFFFF)
o class and classmask fields default to 0
o driver_data defaults to 0UL.
@@ -377,7 +373,7 @@ E.g. clearing pending interrupts.
3.6 Register IRQ handler
~~~~~~~~~~~~~~~~~~~~~~~~
-While calling request_irq() is the the last step described here,
+While calling request_irq() is the last step described here,
this is often just another intermediate step to initialize a device.
This step can often be deferred until the device is opened for use.
@@ -549,8 +545,6 @@ pci_find_slot() Find pci_dev corresponding to given bus and
pci_set_power_state() Set PCI Power Management state (0=D0 ... 3=D3)
pci_find_capability() Find specified capability in device's capability
list.
-pci_module_init() Inline helper function for ensuring correct
- pci_driver initialization and error handling.
pci_resource_start() Returns bus start address for a given PCI region
pci_resource_end() Returns bus end address for a given PCI region
pci_resource_len() Returns the byte length of a PCI region
diff --git a/Documentation/pcieaer-howto.txt b/Documentation/pcieaer-howto.txt
index 16c251230c8..d5da8617010 100644
--- a/Documentation/pcieaer-howto.txt
+++ b/Documentation/pcieaer-howto.txt
@@ -13,7 +13,7 @@ Reporting (AER) driver and provides information on how to use it, as
well as how to enable the drivers of endpoint devices to conform with
PCI Express AER driver.
-1.2 Copyright © Intel Corporation 2006.
+1.2 Copyright © Intel Corporation 2006.
1.3 What is the PCI Express AER Driver?
diff --git a/Documentation/pcmcia/driver.txt b/Documentation/pcmcia/driver.txt
new file mode 100644
index 00000000000..0ac16792077
--- /dev/null
+++ b/Documentation/pcmcia/driver.txt
@@ -0,0 +1,30 @@
+PCMCIA Driver
+-------------
+
+
+sysfs
+-----
+
+New PCMCIA IDs may be added to a device driver pcmcia_device_id table at
+runtime as shown below:
+
+echo "match_flags manf_id card_id func_id function device_no \
+prod_id_hash[0] prod_id_hash[1] prod_id_hash[2] prod_id_hash[3]" > \
+/sys/bus/pcmcia/drivers/{driver}/new_id
+
+All fields are passed in as hexadecimal values (no leading 0x).
+The meaning is described in the PCMCIA specification, the match_flags is
+a bitwise or-ed combination from PCMCIA_DEV_ID_MATCH_* constants
+defined in include/linux/mod_devicetable.h.
+
+Once added, the driver probe routine will be invoked for any unclaimed
+PCMCIA device listed in its (newly updated) pcmcia_device_id list.
+
+A common use-case is to add a new device according to the manufacturer ID
+and the card ID (form the manf_id and card_id file in the device tree).
+For this, just use:
+
+echo "0x3 manf_id card_id 0 0 0 0 0 0 0" > \
+ /sys/bus/pcmcia/drivers/{driver}/new_id
+
+after loading the driver.
diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
index 28037aa1846..481faf515d5 100644
--- a/Documentation/pnp.txt
+++ b/Documentation/pnp.txt
@@ -140,7 +140,7 @@ Plug and Play but it is planned to be in the near future.
Requirements for a Linux PnP protocol:
1.) the protocol must use EISA IDs
2.) the protocol must inform the PnP Layer of a devices current configuration
-- the ability to set resources is optional but prefered.
+- the ability to set resources is optional but preferred.
The following are PnP protocol related functions:
diff --git a/Documentation/power/basic-pm-debugging.txt b/Documentation/power/basic-pm-debugging.txt
new file mode 100644
index 00000000000..1a85e2b964d
--- /dev/null
+++ b/Documentation/power/basic-pm-debugging.txt
@@ -0,0 +1,106 @@
+Debugging suspend and resume
+ (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+1. Testing suspend to disk (STD)
+
+To verify that the STD works, you can try to suspend in the "reboot" mode:
+
+# echo reboot > /sys/power/disk
+# echo disk > /sys/power/state
+
+and the system should suspend, reboot, resume and get back to the command prompt
+where you have started the transition. If that happens, the STD is most likely
+to work correctly, but you need to repeat the test at least a couple of times in
+a row for confidence. This is necessary, because some problems only show up on
+a second attempt at suspending and resuming the system. You should also test
+the "platform" and "shutdown" modes of suspend:
+
+# echo platform > /sys/power/disk
+# echo disk > /sys/power/state
+
+or
+
+# echo shutdown > /sys/power/disk
+# echo disk > /sys/power/state
+
+in which cases you will have to press the power button to make the system
+resume. If that does not work, you will need to identify what goes wrong.
+
+a) Test mode of STD
+
+To verify if there are any drivers that cause problems you can run the STD
+in the test mode:
+
+# echo test > /sys/power/disk
+# echo disk > /sys/power/state
+
+in which case the system should freeze tasks, suspend devices, disable nonboot
+CPUs (if any), wait for 5 seconds, enable nonboot CPUs, resume devices, thaw
+tasks and return to your command prompt. If that fails, most likely there is
+a driver that fails to either suspend or resume (in the latter case the system
+may hang or be unstable after the test, so please take that into consideration).
+To find this driver, you can carry out a binary search according to the rules:
+- if the test fails, unload a half of the drivers currently loaded and repeat
+(that would probably involve rebooting the system, so always note what drivers
+have been loaded before the test),
+- if the test succeeds, load a half of the drivers you have unloaded most
+recently and repeat.
+
+Once you have found the failing driver (there can be more than just one of
+them), you have to unload it every time before the STD transition. In that case
+please make sure to report the problem with the driver.
+
+It is also possible that a cycle can still fail after you have unloaded
+all modules. In that case, you would want to look in your kernel configuration
+for the drivers that can be compiled as modules (testing again with them as
+modules), and possibly also try boot time options such as "noapic" or "noacpi".
+
+b) Testing minimal configuration
+
+If the test mode of STD works, you can boot the system with "init=/bin/bash"
+and attempt to suspend in the "reboot", "shutdown" and "platform" modes. If
+that does not work, there probably is a problem with a driver statically
+compiled into the kernel and you can try to compile more drivers as modules,
+so that they can be tested individually. Otherwise, there is a problem with a
+modular driver and you can find it by loading a half of the modules you normally
+use and binary searching in accordance with the algorithm:
+- if there are n modules loaded and the attempt to suspend and resume fails,
+unload n/2 of the modules and try again (that would probably involve rebooting
+the system),
+- if there are n modules loaded and the attempt to suspend and resume succeeds,
+load n/2 modules more and try again.
+
+Again, if you find the offending module(s), it(they) must be unloaded every time
+before the STD transition, and please report the problem with it(them).
+
+c) Advanced debugging
+
+In case the STD does not work on your system even in the minimal configuration
+and compiling more drivers as modules is not practical or some modules cannot
+be unloaded, you can use one of the more advanced debugging techniques to find
+the problem. First, if there is a serial port in your box, you can set the
+CONFIG_DISABLE_CONSOLE_SUSPEND kernel configuration option and try to log kernel
+messages using the serial console. This may provide you with some information
+about the reasons of the suspend (resume) failure. Alternatively, it may be
+possible to use a FireWire port for debugging with firescope
+(ftp://ftp.firstfloor.org/pub/ak/firescope/). On i386 it is also possible to
+use the PM_TRACE mechanism documented in Documentation/s2ram.txt .
+
+2. Testing suspend to RAM (STR)
+
+To verify that the STR works, it is generally more convenient to use the s2ram
+tool available from http://suspend.sf.net and documented at
+http://en.opensuse.org/s2ram . However, before doing that it is recommended to
+carry out the procedure described in section 1.
+
+Assume you have resolved the problems with the STD and you have found some
+failing drivers. These drivers are also likely to fail during the STR or
+during the resume, so it is better to unload them every time before the STR
+transition. Now, you can follow the instructions at
+http://en.opensuse.org/s2ram to test the system, but if it does not work
+"out of the box", you may need to boot it with "init=/bin/bash" and test
+s2ram in the minimal configuration. In that case, you may be able to search
+for failing drivers by following the procedure analogous to the one described in
+1b). If you find some failing drivers, you will have to unload them every time
+before the STR transition (ie. before you run s2ram), and please report the
+problems with them.
diff --git a/Documentation/power/drivers-testing.txt b/Documentation/power/drivers-testing.txt
new file mode 100644
index 00000000000..33016c2f18d
--- /dev/null
+++ b/Documentation/power/drivers-testing.txt
@@ -0,0 +1,42 @@
+Testing suspend and resume support in device drivers
+ (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+1. Preparing the test system
+
+Unfortunately, to effectively test the support for the system-wide suspend and
+resume transitions in a driver, it is necessary to suspend and resume a fully
+functional system with this driver loaded. Moreover, that should be done
+several times, preferably several times in a row, and separately for the suspend
+to disk (STD) and the suspend to RAM (STR) transitions, because each of these
+cases involves different ordering of operations and different interactions with
+the machine's BIOS.
+
+Of course, for this purpose the test system has to be known to suspend and
+resume without the driver being tested. Thus, if possible, you should first
+resolve all suspend/resume-related problems in the test system before you start
+testing the new driver. Please see Documents/power/basic-pm-debugging.txt for
+more information about the debugging of suspend/resume functionality.
+
+2. Testing the driver
+
+Once you have resolved the suspend/resume-related problems with your test system
+without the new driver, you are ready to test it:
+
+a) Build the driver as a module, load it and try the STD in the test mode (see:
+Documents/power/basic-pm-debugging.txt, 1a)).
+
+b) Load the driver and attempt to suspend to disk in the "reboot", "shutdown"
+and "platform" modes (see: Documents/power/basic-pm-debugging.txt, 1).
+
+c) Compile the driver directly into the kernel and try the STD in the test mode.
+
+d) Attempt to suspend to disk with the driver compiled directly into the kernel
+in the "reboot", "shutdown" and "platform" modes.
+
+e) Attempt to suspend to RAM using the s2ram tool with the driver loaded (see:
+Documents/power/basic-pm-debugging.txt, 2). As far as the STR tests are
+concerned, it should not matter whether or not the driver is built as a module.
+
+Each of the above tests should be repeated several times and the STD tests
+should be mixed with the STR tests. If any of them fails, the driver cannot be
+regarded as suspend/resume-safe.
diff --git a/Documentation/power/interface.txt b/Documentation/power/interface.txt
index 74311d7e0f3..fd5192a8fa8 100644
--- a/Documentation/power/interface.txt
+++ b/Documentation/power/interface.txt
@@ -18,17 +18,10 @@ states.
/sys/power/disk controls the operating mode of the suspend-to-disk
-mechanism. Suspend-to-disk can be handled in several ways. The
-greatest distinction is who writes memory to disk - the firmware or
-the kernel. If the firmware does it, we assume that it also handles
-suspending the system.
-
-If the kernel does it, then we have three options for putting the system
-to sleep - using the platform driver (e.g. ACPI or other PM
-registers), powering off the system or rebooting the system (for
-testing). The system will support either 'firmware' or 'platform', and
-that is known a priori. But, the user may choose 'shutdown' or
-'reboot' as alternatives.
+mechanism. Suspend-to-disk can be handled in several ways. We have a
+few options for putting the system to sleep - using the platform driver
+(e.g. ACPI or other pm_ops), powering off the system or rebooting the
+system (for testing).
Additionally, /sys/power/disk can be used to turn on one of the two testing
modes of the suspend-to-disk mechanism: 'testproc' or 'test'. If the
@@ -41,19 +34,19 @@ for 5 seconds, resume devices, unfreeze tasks and enable nonboot CPUs. Then,
we are able to look in the log messages and work out, for example, which code
is being slow and which device drivers are misbehaving.
-Reading from this file will display what the mode is currently set
-to. Writing to this file will accept one of
+Reading from this file will display all supported modes and the currently
+selected one in brackets, for example
- 'firmware'
- 'platform'
+ [shutdown] reboot test testproc
+
+Writing to this file will accept one of
+
+ 'platform' (only if the platform supports it)
'shutdown'
'reboot'
'testproc'
'test'
-It will only change to 'firmware' or 'platform' if the system supports
-it.
-
/sys/power/image_size controls the size of the image created by
the suspend-to-disk mechanism. It can be written a string
representing a non-negative integer that will be used as an upper
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
index b6a3cbf7e84..e00b099a4b8 100644
--- a/Documentation/power/pci.txt
+++ b/Documentation/power/pci.txt
@@ -203,7 +203,7 @@ resume
Usage:
-if (dev->driver && dev->driver->suspend)
+if (dev->driver && dev->driver->resume)
dev->driver->resume(dev)
The resume callback may be called from any power state, and is always meant to
diff --git a/Documentation/power/states.txt b/Documentation/power/states.txt
index 0931a330d36..34800cc521b 100644
--- a/Documentation/power/states.txt
+++ b/Documentation/power/states.txt
@@ -62,17 +62,18 @@ setup via another operating system for it to use. Despite the
inconvenience, this method requires minimal work by the kernel, since
the firmware will also handle restoring memory contents on resume.
-If the kernel is responsible for persistently saving state, a mechanism
-called 'swsusp' (Swap Suspend) is used to write memory contents to
-free swap space. swsusp has some restrictive requirements, but should
-work in most cases. Some, albeit outdated, documentation can be found
-in Documentation/power/swsusp.txt.
+For suspend-to-disk, a mechanism called swsusp called 'swsusp' (Swap
+Suspend) is used to write memory contents to free swap space.
+swsusp has some restrictive requirements, but should work in most
+cases. Some, albeit outdated, documentation can be found in
+Documentation/power/swsusp.txt. Alternatively, userspace can do most
+of the actual suspend to disk work, see userland-swsusp.txt.
Once memory state is written to disk, the system may either enter a
low-power state (like ACPI S4), or it may simply power down. Powering
down offers greater savings, and allows this mechanism to work on any
system. However, entering a real low-power state allows the user to
-trigger wake up events (e.g. pressing a key or opening a laptop lid).
+trigger wake up events (e.g. pressing a key or opening a laptop lid).
A transition from Suspend-to-Disk to the On state should take about 30
seconds, though it's typically a bit more with the current
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 0761ff6c57e..5b8d6953f05 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -48,7 +48,7 @@ before suspend (it is limited to 500 MB by default).
Article about goals and implementation of Software Suspend for Linux
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Author: G‚ábor Kuti
+Author: G‚ábor Kuti
Last revised: 2003-10-20 by Pavel Machek
Idea and goals to achieve
@@ -156,8 +156,7 @@ instead set the PF_NOFREEZE process flag when creating the thread (and
be very careful).
-Q: What is the difference between "platform", "shutdown" and
-"firmware" in /sys/power/disk?
+Q: What is the difference between "platform" and "shutdown"?
A:
@@ -166,11 +165,8 @@ shutdown: save state in linux, then tell bios to powerdown
platform: save state in linux, then tell bios to powerdown and blink
"suspended led"
-firmware: tell bios to save state itself [needs BIOS-specific suspend
- partition, and has very little to do with swsusp]
-
-"platform" is actually right thing to do, but "shutdown" is most
-reliable.
+"platform" is actually right thing to do where supported, but
+"shutdown" is most reliable (except on ACPI systems).
Q: I do not understand why you have such strong objections to idea of
selective suspend.
@@ -388,8 +384,8 @@ while the system is asleep, maintaining the connection, using true sleep
modes like "suspend-to-RAM" or "standby". (Don't write "disk" to the
/sys/power/state file; write "standby" or "mem".) We've not seen any
hardware that can use these modes through software suspend, although in
-theory some systems might support "platform" or "firmware" modes that
-won't break the USB connections.
+theory some systems might support "platform" modes that won't break the
+USB connections.
Remember that it's always a bad idea to unplug a disk drive containing a
mounted filesystem. That's true even when your system is asleep! The
diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 000556c932e..e00c6cf09e8 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -93,21 +93,23 @@ SNAPSHOT_S2RAM - suspend to RAM; using this call causes the kernel to
to resume the system from RAM if there's enough battery power or restore
its state on the basis of the saved suspend image otherwise)
-SNAPSHOT_PMOPS - enable the usage of the pmops->prepare, pmops->enter and
- pmops->finish methods (the in-kernel swsusp knows these as the "platform
- method") which are needed on many machines to (among others) speed up
- the resume by letting the BIOS skip some steps or to let the system
- recognise the correct state of the hardware after the resume (in
- particular on many machines this ensures that unplugged AC
- adapters get correctly detected and that kacpid does not run wild after
- the resume). The last ioctl() argument can take one of the three
- values, defined in kernel/power/power.h:
+SNAPSHOT_PMOPS - enable the usage of the hibernation_ops->prepare,
+ hibernate_ops->enter and hibernation_ops->finish methods (the in-kernel
+ swsusp knows these as the "platform method") which are needed on many
+ machines to (among others) speed up the resume by letting the BIOS skip
+ some steps or to let the system recognise the correct state of the
+ hardware after the resume (in particular on many machines this ensures
+ that unplugged AC adapters get correctly detected and that kacpid does
+ not run wild after the resume). The last ioctl() argument can take one
+ of the three values, defined in kernel/power/power.h:
PMOPS_PREPARE - make the kernel carry out the
- pm_ops->prepare(PM_SUSPEND_DISK) operation
+ hibernation_ops->prepare() operation
PMOPS_ENTER - make the kernel power off the system by calling
- pm_ops->enter(PM_SUSPEND_DISK)
+ hibernation_ops->enter()
PMOPS_FINISH - make the kernel carry out the
- pm_ops->finish(PM_SUSPEND_DISK) operation
+ hibernation_ops->finish() operation
+ Note that the actual constants are misnamed because they surface
+ internal kernel implementation details that have changed.
The device's read() operation can be used to transfer the snapshot image from
the kernel. It has the following limitations:
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index b41397d6430..b49ce169a63 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -39,7 +39,7 @@
and property data. The old style variable
alignment would make it impossible to do
"simple" insertion of properties using
- memove (thanks Milton for
+ memmove (thanks Milton for
noticing). Updated kernel patch as well
- Correct a few more alignment constraints
- Add a chapter about the device-tree
@@ -55,7 +55,7 @@
ToDo:
- Add some definitions of interrupt tree (simple/complex)
- - Add some definitions for pci host bridges
+ - Add some definitions for PCI host bridges
- Add some common address format examples
- Add definitions for standard properties and "compatible"
names for cells that are not already defined by the existing
@@ -114,7 +114,7 @@ it with special cases.
forth words isn't required), you can enter the kernel with:
r5 : OF callback pointer as defined by IEEE 1275
- bindings to powerpc. Only the 32 bit client interface
+ bindings to powerpc. Only the 32-bit client interface
is currently supported
r3, r4 : address & length of an initrd if any or 0
@@ -194,7 +194,7 @@ it with special cases.
for this is to keep kernels on embedded systems small and efficient;
part of this is due to the fact the code is already that way. In the
future, a kernel may support multiple platforms, but only if the
- platforms feature the same core architectire. A single kernel build
+ platforms feature the same core architecture. A single kernel build
cannot support both configurations with Book E and configurations
with classic Powerpc architectures.
@@ -215,7 +215,7 @@ of the boot sequences.... someone speak up if this is wrong!
enable another config option to select the specific board
supported.
-NOTE: If ben doesn't merge the setup files, may need to change this to
+NOTE: If Ben doesn't merge the setup files, may need to change this to
point to setup_32.c
@@ -256,7 +256,7 @@ struct boot_param_header {
u32 off_dt_struct; /* offset to structure */
u32 off_dt_strings; /* offset to strings */
u32 off_mem_rsvmap; /* offset to memory reserve map
-*/
+ */
u32 version; /* format version */
u32 last_comp_version; /* last compatible version */
@@ -265,6 +265,9 @@ struct boot_param_header {
booting on */
/* version 3 fields below */
u32 size_dt_strings; /* size of the strings block */
+
+ /* version 17 fields below */
+ u32 size_dt_struct; /* size of the DT structure block */
};
Along with the constants:
@@ -273,7 +276,7 @@ struct boot_param_header {
#define OF_DT_HEADER 0xd00dfeed /* 4: version,
4: total size */
#define OF_DT_BEGIN_NODE 0x1 /* Start node: full name
-*/
+ */
#define OF_DT_END_NODE 0x2 /* End node */
#define OF_DT_PROP 0x3 /* Property: name off,
size, content */
@@ -310,9 +313,8 @@ struct boot_param_header {
- off_mem_rsvmap
This is an offset from the beginning of the header to the start
- of the reserved memory map. This map is a list of pairs of 64
+ of the reserved memory map. This map is a list of pairs of 64-
bit integers. Each pair is a physical address and a size. The
-
list is terminated by an entry of size 0. This map provides the
kernel with a list of physical memory areas that are "reserved"
and thus not to be used for memory allocations, especially during
@@ -325,7 +327,7 @@ struct boot_param_header {
contain _at least_ this DT block itself (header,total_size). If
you are passing an initrd to the kernel, you should reserve it as
well. You do not need to reserve the kernel image itself. The map
- should be 64 bit aligned.
+ should be 64-bit aligned.
- version
@@ -335,10 +337,13 @@ struct boot_param_header {
to reallocate it easily at boot and free up the unused flattened
structure after expansion. Version 16 introduces a new more
"compact" format for the tree itself that is however not backward
- compatible. You should always generate a structure of the highest
- version defined at the time of your implementation. Currently
- that is version 16, unless you explicitly aim at being backward
- compatible.
+ compatible. Version 17 adds an additional field, size_dt_struct,
+ allowing it to be reallocated or moved more easily (this is
+ particularly useful for bootloaders which need to make
+ adjustments to a device tree based on probed information). You
+ should always generate a structure of the highest version defined
+ at the time of your implementation. Currently that is version 17,
+ unless you explicitly aim at being backward compatible.
- last_comp_version
@@ -347,7 +352,7 @@ struct boot_param_header {
is backward compatible with version 1 (that is, a kernel build
for version 1 will be able to boot with a version 2 format). You
should put a 1 in this field if you generate a device tree of
- version 1 to 3, or 0x10 if you generate a tree of version 0x10
+ version 1 to 3, or 16 if you generate a tree of version 16 or 17
using the new unit name format.
- boot_cpuid_phys
@@ -360,6 +365,17 @@ struct boot_param_header {
point (see further chapters for more informations on the required
device-tree contents)
+ - size_dt_strings
+
+ This field only exists on version 3 and later headers. It
+ gives the size of the "strings" section of the device tree (which
+ starts at the offset given by off_dt_strings).
+
+ - size_dt_struct
+
+ This field only exists on version 17 and later headers. It gives
+ the size of the "structure" section of the device tree (which
+ starts at the offset given by off_dt_struct).
So the typical layout of a DT block (though the various parts don't
need to be in that order) looks like this (addresses go from top to
@@ -417,7 +433,7 @@ root node who has no parent.
A node has 2 names. The actual node name is generally contained in a
property of type "name" in the node property list whose value is a
zero terminated string and is mandatory for version 1 to 3 of the
-format definition (as it is in Open Firmware). Version 0x10 makes it
+format definition (as it is in Open Firmware). Version 16 makes it
optional as it can generate it from the unit name defined below.
There is also a "unit name" that is used to differentiate nodes with
@@ -461,7 +477,7 @@ referencing another node via "phandle" is when laying out the
interrupt tree which will be described in a further version of this
document.
-This "linux, phandle" property is a 32 bit value that uniquely
+This "linux, phandle" property is a 32-bit value that uniquely
identifies a node. You are free to use whatever values or system of
values, internal pointers, or whatever to generate these, the only
requirement is that every node for which you provide that property has
@@ -471,7 +487,7 @@ Here is an example of a simple device-tree. In this example, an "o"
designates a node followed by the node unit name. Properties are
presented with their name followed by their content. "content"
represents an ASCII string (zero terminated) value, while <content>
-represents a 32 bit hexadecimal value. The various nodes in this
+represents a 32-bit hexadecimal value. The various nodes in this
example will be discussed in a later chapter. At this point, it is
only meant to give you a idea of what a device-tree looks like. I have
purposefully kept the "name" and "linux,phandle" properties which
@@ -543,15 +559,15 @@ Here's the basic structure of a single node:
* [align gap to next 4 bytes boundary]
* for each property:
* token OF_DT_PROP (that is 0x00000003)
- * 32 bit value of property value size in bytes (or 0 of no
- * value)
- * 32 bit value of offset in string block of property name
+ * 32-bit value of property value size in bytes (or 0 if no
+ value)
+ * 32-bit value of offset in string block of property name
* property value data if any
* [align gap to next 4 bytes boundary]
* [child nodes if any]
* token OF_DT_END_NODE (that is 0x00000002)
-So the node content can be summarised as a start token, a full path,
+So the node content can be summarized as a start token, a full path,
a list of properties, a list of child nodes, and an end token. Every
child node is a full node structure itself as defined above.
@@ -583,7 +599,7 @@ provide those properties yourself.
----------------------------------------------
The general rule is documented in the various Open Firmware
-documentations. If you chose to describe a bus with the device-tree
+documentations. If you choose to describe a bus with the device-tree
and there exist an OF bus binding, then you should follow the
specification. However, the kernel does not require every single
device or bus to be described by the device tree.
@@ -596,9 +612,9 @@ those properties defining addresses format for devices directly mapped
on the processor bus.
Those 2 properties define 'cells' for representing an address and a
-size. A "cell" is a 32 bit number. For example, if both contain 2
+size. A "cell" is a 32-bit number. For example, if both contain 2
like the example tree given above, then an address and a size are both
-composed of 2 cells, and each is a 64 bit number (cells are
+composed of 2 cells, and each is a 64-bit number (cells are
concatenated and expected to be in big endian format). Another example
is the way Apple firmware defines them, with 2 cells for an address
and one cell for a size. Most 32-bit implementations should define
@@ -632,7 +648,7 @@ prom_parse.c file of the recent kernels for your bus type.
The "reg" property only defines addresses and sizes (if #size-cells
is non-0) within a given bus. In order to translate addresses upward
-(that is into parent bus addresses, and possibly into cpu physical
+(that is into parent bus addresses, and possibly into CPU physical
addresses), all busses must contain a "ranges" property. If the
"ranges" property is missing at a given level, it's assumed that
translation isn't possible. The format of the "ranges" property for a
@@ -648,9 +664,9 @@ example, for a PCI host controller, that would be a CPU address. For a
PCI<->ISA bridge, that would be a PCI address. It defines the base
address in the parent bus where the beginning of that range is mapped.
-For a new 64 bit powerpc board, I recommend either the 2/2 format or
+For a new 64-bit powerpc board, I recommend either the 2/2 format or
Apple's 2/1 format which is slightly more compact since sizes usually
-fit in a single 32 bit word. New 32 bit powerpc boards should use a
+fit in a single 32-bit word. New 32-bit powerpc boards should use a
1/1 format, unless the processor supports physical addresses greater
than 32-bits, in which case a 2/1 format is recommended.
@@ -764,7 +780,7 @@ address which can extend beyond that limit.
Required properties:
- device_type : has to be "cpu"
- - reg : This is the physical cpu number, it's a single 32 bit cell
+ - reg : This is the physical CPU number, it's a single 32-bit cell
and is also used as-is as the unit number for constructing the
unit name in the full path. For example, with 2 CPUs, you would
have the full path:
@@ -785,7 +801,7 @@ address which can extend beyond that limit.
the kernel timebase/decrementer calibration based on this
value.
- clock-frequency : a cell indicating the CPU core clock frequency
- in Hz. A new property will be defined for 64 bit values, but if
+ in Hz. A new property will be defined for 64-bit values, but if
your frequency is < 4Ghz, one cell is enough. Here as well as
for the above, the common code doesn't use that property, but
you are welcome to re-use the pSeries or Maple one. A future
@@ -832,8 +848,7 @@ address which can extend beyond that limit.
This node is a bit "special". Normally, that's where open firmware
puts some variable environment information, like the arguments, or
- phandle pointers to nodes like the main interrupt controller, or the
- default input/output devices.
+ the default input/output devices.
This specification makes a few of these mandatory, but also defines
some linux-specific properties that would be normally constructed by
@@ -853,14 +868,14 @@ address which can extend beyond that limit.
that the kernel tries to find out the default console and has
knowledge of various types like 8250 serial ports. You may want
to extend this function to add your own.
- - interrupt-controller : This is one cell containing a phandle
- value that matches the "linux,phandle" property of your main
- interrupt controller node. May be used for interrupt routing.
-
Note that u-boot creates and fills in the chosen node for platforms
that use it.
+ (Note: a practice that is now obsolete was to include a property
+ under /chosen called interrupt-controller which had a phandle value
+ that pointed to the main interrupt controller)
+
f) the /soc<SOCname> node
This node is used to represent a system-on-a-chip (SOC) and must be
@@ -908,8 +923,7 @@ address which can extend beyond that limit.
The SOC node may contain child nodes for each SOC device that the
platform uses. Nodes should not be created for devices which exist
on the SOC but are not used by a particular platform. See chapter VI
- for more information on how to specify devices that are part of an
-SOC.
+ for more information on how to specify devices that are part of a SOC.
Example SOC node for the MPC8540:
@@ -972,7 +986,7 @@ The syntax of the dtc tool is
[-o output-filename] [-V output_version] input_filename
-The "output_version" defines what versio of the "blob" format will be
+The "output_version" defines what version of the "blob" format will be
generated. Supported versions are 1,2,3 and 16. The default is
currently version 3 but that may change in the future to version 16.
@@ -994,12 +1008,12 @@ supported currently at the toplevel.
*/
property2 = <1234abcd>; /* define a property containing a
- * numerical 32 bits value (hexadecimal)
+ * numerical 32-bit value (hexadecimal)
*/
property3 = <12345678 12345678 deadbeef>;
/* define a property containing 3
- * numerical 32 bits values (cells) in
+ * numerical 32-bit values (cells) in
* hexadecimal
*/
property4 = [0a 0b 0c 0d de ea ad be ef];
@@ -1068,7 +1082,7 @@ while all this has been defined and implemented.
its usage in early_init_devtree(), and the corresponding various
early_init_dt_scan_*() callbacks. That code can be re-used in a
GPL bootloader, and as the author of that code, I would be happy
- to discuss possible free licencing to any vendor who wishes to
+ to discuss possible free licensing to any vendor who wishes to
integrate all or part of this code into a non-GPL bootloader.
@@ -1077,7 +1091,7 @@ VI - System-on-a-chip devices and nodes
=======================================
Many companies are now starting to develop system-on-a-chip
-processors, where the processor core (cpu) and many peripheral devices
+processors, where the processor core (CPU) and many peripheral devices
exist on a single piece of silicon. For these SOCs, an SOC node
should be used that defines child nodes for the devices that make
up the SOC. While platforms are not required to use this model in
@@ -1109,42 +1123,7 @@ See appendix A for an example partial SOC node definition for the
MPC8540.
-2) Specifying interrupt information for SOC devices
----------------------------------------------------
-
-Each device that is part of an SOC and which generates interrupts
-should have the following properties:
-
- - interrupt-parent : contains the phandle of the interrupt
- controller which handles interrupts for this device
- - interrupts : a list of tuples representing the interrupt
- number and the interrupt sense and level for each interrupt
- for this device.
-
-This information is used by the kernel to build the interrupt table
-for the interrupt controllers in the system.
-
-Sense and level information should be encoded as follows:
-
- Devices connected to openPIC-compatible controllers should encode
- sense and polarity as follows:
-
- 0 = low to high edge sensitive type enabled
- 1 = active low level sensitive type enabled
- 2 = active high level sensitive type enabled
- 3 = high to low edge sensitive type enabled
-
- ISA PIC interrupt controllers should adhere to the ISA PIC
- encodings listed below:
-
- 0 = active low level sensitive type enabled
- 1 = active high level sensitive type enabled
- 2 = high to low edge sensitive type enabled
- 3 = low to high edge sensitive type enabled
-
-
-
-3) Representing devices without a current OF specification
+2) Representing devices without a current OF specification
----------------------------------------------------------
Currently, there are many devices on SOCs that do not have a standard
@@ -1201,6 +1180,13 @@ platforms are moved over to use the flattened-device-tree model.
- phy-handle : The phandle for the PHY connected to this ethernet
controller.
+ Recommended properties:
+
+ - linux,network-index : This is the intended "index" of this
+ network device. This is used by the bootwrapper to interpret
+ MAC addresses passed by the firmware when no information other
+ than indices is available to associate an address with a device.
+
Example:
ethernet@24000 {
@@ -1312,10 +1298,10 @@ platforms are moved over to use the flattened-device-tree model.
and additions :
Required properties :
- - compatible : Should be "fsl-usb2-mph" for multi port host usb
- controllers, or "fsl-usb2-dr" for dual role usb controllers
- - phy_type : For multi port host usb controllers, should be one of
- "ulpi", or "serial". For dual role usb controllers, should be
+ - compatible : Should be "fsl-usb2-mph" for multi port host USB
+ controllers, or "fsl-usb2-dr" for dual role USB controllers
+ - phy_type : For multi port host USB controllers, should be one of
+ "ulpi", or "serial". For dual role USB controllers, should be
one of "ulpi", "utmi", "utmi_wide", or "serial".
- reg : Offset and length of the register set for the device
- port0 : boolean; if defined, indicates port0 is connected for
@@ -1339,7 +1325,7 @@ platforms are moved over to use the flattened-device-tree model.
- interrupt-parent : the phandle for the interrupt controller that
services interrupts for this device.
- Example multi port host usb controller device node :
+ Example multi port host USB controller device node :
usb@22000 {
device_type = "usb";
compatible = "fsl-usb2-mph";
@@ -1353,7 +1339,7 @@ platforms are moved over to use the flattened-device-tree model.
port1;
};
- Example dual role usb controller device node :
+ Example dual role USB controller device node :
usb@23000 {
device_type = "usb";
compatible = "fsl-usb2-dr";
@@ -1387,7 +1373,7 @@ platforms are moved over to use the flattened-device-tree model.
- channel-fifo-len : An integer representing the number of
descriptor pointers each channel fetch fifo can hold.
- exec-units-mask : The bitmask representing what execution units
- (EUs) are available. It's a single 32 bit cell. EU information
+ (EUs) are available. It's a single 32-bit cell. EU information
should be encoded following the SEC's Descriptor Header Dword
EU_SEL0 field documentation, i.e. as follows:
@@ -1403,7 +1389,7 @@ platforms are moved over to use the flattened-device-tree model.
bits 8 through 31 are reserved for future SEC EUs.
- descriptor-types-mask : The bitmask representing what descriptors
- are available. It's a single 32 bit cell. Descriptor type
+ are available. It's a single 32-bit cell. Descriptor type
information should be encoded following the SEC's Descriptor
Header Dword DESC_TYPE field documentation, i.e. as follows:
@@ -1458,7 +1444,7 @@ platforms are moved over to use the flattened-device-tree model.
Basically, it is a bus of devices, that could act more or less
as a complete entity (UCC, USB etc ). All of them should be siblings on
the "root" qe node, using the common properties from there.
- The description below applies to the the qe of MPC8360 and
+ The description below applies to the qe of MPC8360 and
more nodes and properties would be extended in the future.
i) Root QE device
@@ -1492,7 +1478,7 @@ platforms are moved over to use the flattened-device-tree model.
Required properties:
- device_type : should be "spi".
- compatible : should be "fsl_spi".
- - mode : the spi operation mode, it can be "cpu" or "qe".
+ - mode : the SPI operation mode, it can be "cpu" or "qe".
- reg : Offset and length of the register set for the device
- interrupts : <a b> where a is the interrupt number and b is a
field that represents an encoding of the sense and level
@@ -1569,6 +1555,15 @@ platforms are moved over to use the flattened-device-tree model.
- mac-address : list of bytes representing the ethernet address.
- phy-handle : The phandle for the PHY connected to this controller.
+ Recommended properties:
+ - linux,network-index : This is the intended "index" of this
+ network device. This is used by the bootwrapper to interpret
+ MAC addresses passed by the firmware when no information other
+ than indices is available to associate an address with a device.
+ - phy-connection-type : a string naming the controller/PHY interface type,
+ i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "tbi",
+ or "rtbi".
+
Example:
ucc@2000 {
device_type = "network";
@@ -1582,6 +1577,7 @@ platforms are moved over to use the flattened-device-tree model.
rx-clock = "none";
tx-clock = "clk9";
phy-handle = <212000>;
+ phy-connection-type = "gmii";
pio-handle = <140001>;
};
@@ -1637,7 +1633,7 @@ platforms are moved over to use the flattened-device-tree model.
- assignment : function number of the pin according to the Pin Assignment
tables in User Manual. Each pin can have up to 4 possible functions in
QE and two options for CPM.
- - has_irq : indicates if the pin is used as source of exteral
+ - has_irq : indicates if the pin is used as source of external
interrupts.
Example:
@@ -1712,7 +1708,7 @@ platforms are moved over to use the flattened-device-tree model.
- partitions : Several pairs of 32-bit values where the first value is
partition's offset from the start of the device and the second one is
partition size in bytes with LSB used to signify a read only
- partition (so, the parition size should always be an even number).
+ partition (so, the partition size should always be an even number).
- partition-names : The list of concatenated zero terminated strings
representing the partition names.
- probe-type : The type of probe which should be done for the chip
@@ -1733,6 +1729,92 @@ platforms are moved over to use the flattened-device-tree model.
More devices will be defined as this spec matures.
+VII - Specifying interrupt information for devices
+===================================================
+
+The device tree represents the busses and devices of a hardware
+system in a form similar to the physical bus topology of the
+hardware.
+
+In addition, a logical 'interrupt tree' exists which represents the
+hierarchy and routing of interrupts in the hardware.
+
+The interrupt tree model is fully described in the
+document "Open Firmware Recommended Practice: Interrupt
+Mapping Version 0.9". The document is available at:
+<http://playground.sun.com/1275/practice>.
+
+1) interrupts property
+----------------------
+
+Devices that generate interrupts to a single interrupt controller
+should use the conventional OF representation described in the
+OF interrupt mapping documentation.
+
+Each device which generates interrupts must have an 'interrupt'
+property. The interrupt property value is an arbitrary number of
+of 'interrupt specifier' values which describe the interrupt or
+interrupts for the device.
+
+The encoding of an interrupt specifier is determined by the
+interrupt domain in which the device is located in the
+interrupt tree. The root of an interrupt domain specifies in
+its #interrupt-cells property the number of 32-bit cells
+required to encode an interrupt specifier. See the OF interrupt
+mapping documentation for a detailed description of domains.
+
+For example, the binding for the OpenPIC interrupt controller
+specifies an #interrupt-cells value of 2 to encode the interrupt
+number and level/sense information. All interrupt children in an
+OpenPIC interrupt domain use 2 cells per interrupt in their interrupts
+property.
+
+The PCI bus binding specifies a #interrupt-cell value of 1 to encode
+which interrupt pin (INTA,INTB,INTC,INTD) is used.
+
+2) interrupt-parent property
+----------------------------
+
+The interrupt-parent property is specified to define an explicit
+link between a device node and its interrupt parent in
+the interrupt tree. The value of interrupt-parent is the
+phandle of the parent node.
+
+If the interrupt-parent property is not defined for a node, it's
+interrupt parent is assumed to be an ancestor in the node's
+_device tree_ hierarchy.
+
+3) OpenPIC Interrupt Controllers
+--------------------------------
+
+OpenPIC interrupt controllers require 2 cells to encode
+interrupt information. The first cell defines the interrupt
+number. The second cell defines the sense and level
+information.
+
+Sense and level information should be encoded as follows:
+
+ 0 = low to high edge sensitive type enabled
+ 1 = active low level sensitive type enabled
+ 2 = active high level sensitive type enabled
+ 3 = high to low edge sensitive type enabled
+
+4) ISA Interrupt Controllers
+----------------------------
+
+ISA PIC interrupt controllers require 2 cells to encode
+interrupt information. The first cell defines the interrupt
+number. The second cell defines the sense and level
+information.
+
+ISA PIC interrupt controllers should adhere to the ISA PIC
+encodings listed below:
+
+ 0 = active low level sensitive type enabled
+ 1 = active high level sensitive type enabled
+ 2 = high to low edge sensitive type enabled
+ 3 = low to high edge sensitive type enabled
+
Appendix A - Sample SOC node for MPC8540
========================================
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 1ef6bb88cd0..7c701b88d6d 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -147,7 +147,7 @@ RTC class framework, but can't be supported by the older driver.
* RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC
is connected to an IRQ line, it can often issue an alarm IRQ up to
- 24 hours in the future.
+ 24 hours in the future. (Use RTC_WKALM_* by preference.)
* RTC_WKALM_SET, RTC_WKALM_RD ... RTCs that can issue alarms beyond
the next 24 hours use a slightly more powerful API, which supports
@@ -175,10 +175,7 @@ driver returns ENOIOCTLCMD. Some common examples:
called with appropriate values.
* RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD: the
- set_alarm/read_alarm functions will be called. To differentiate
- between the ALM and WKALM, check the larger fields of the rtc_wkalrm
- struct (like tm_year). These will be set to -1 when using ALM and
- will be set to proper values when using WKALM.
+ set_alarm/read_alarm functions will be called.
* RTC_IRQP_SET, RTC_IRQP_READ: the irq_set_freq function will be called
to set the frequency while the framework will handle the read for you
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index 0993969609c..d30a281c570 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -2209,7 +2209,7 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609.
#3 0x5167e6 in readline_internal_char () at readline.c:454
#4 0x5168ee in readline_internal_charloop () at readline.c:507
#5 0x51692c in readline_internal () at readline.c:521
-#6 0x5164fe in readline (prompt=0x7ffff810 "\177ÿøx\177ÿ÷Ø\177ÿøxÀ")
+#6 0x5164fe in readline (prompt=0x7ffff810 "\177ÂÿÂøx\177ÂÿÂ÷ÂØ\177ÂÿÂøxÂÀ")
at readline.c:349
#7 0x4d7a8a in command_line_input (prrompt=0x564420 "(gdb) ", repeat=1,
annotation_suffix=0x4d6b44 "prompt") at top.c:2091
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index dc8e44fc650..ce3cb42507b 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -37,7 +37,11 @@ Supported Cards/Chipsets
9005:0286:9005:029d Adaptec 2420SA (Intruder HP release)
9005:0286:9005:02ac Adaptec 1800 (Typhoon44)
9005:0285:9005:02b5 Adaptec 5445 (Voodoo44)
+ 9005:0285:15d9:02b5 SMC AOC-USAS-S4i
+ 9005:0285:15d9:02c9 SMC AOC-USAS-S4iR
9005:0285:9005:02b6 Adaptec 5805 (Voodoo80)
+ 9005:0285:15d9:02b6 SMC AOC-USAS-S8i
+ 9005:0285:15d9:02ca SMC AOC-USAS-S8iR
9005:0285:9005:02b7 Adaptec 5085 (Voodoo08)
9005:0285:9005:02bb Adaptec 3405 (Marauder40LP)
9005:0285:9005:02bc Adaptec 3805 (Marauder80LP)
@@ -93,6 +97,9 @@ Supported Cards/Chipsets
9005:0286:9005:02ae (Aurora Lite ARK)
9005:0285:9005:02b0 (Sunrise Lake ARK)
9005:0285:9005:02b1 Adaptec (Voodoo 8 internal 8 external)
+ 9005:0285:108e:7aac SUN STK RAID REM (Voodoo44 Coyote)
+ 9005:0285:108e:0286 SUN STK RAID INT (Cougar)
+ 9005:0285:108e:0287 SUN STK RAID EXT (Prometheus)
People
-------------------------
diff --git a/Documentation/scsi/aha152x.txt b/Documentation/scsi/aha152x.txt
index 2ce022cec9b..29ce6d87e45 100644
--- a/Documentation/scsi/aha152x.txt
+++ b/Documentation/scsi/aha152x.txt
@@ -1,7 +1,7 @@
$Id: README.aha152x,v 1.2 1999/12/25 15:32:30 fischer Exp fischer $
Adaptec AHA-1520/1522 SCSI driver for Linux (aha152x)
-Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
+Copyright 1993-1999 Jürgen Fischer <fischer@norbit.de>
TC1550 patches by Luuk van Dijk (ldz@xs4all.nl)
diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
index 9b894f116d9..5f34d2ba69b 100644
--- a/Documentation/scsi/aic7xxx.txt
+++ b/Documentation/scsi/aic7xxx.txt
@@ -40,7 +40,7 @@ The following information is available in this file:
2. Multi-function Twin Channel Device - Two controllers on one chip.
3. Command Channel Secondary DMA Engine - Allows scatter gather list
and SCB prefetch.
- 4. 64 Byte SCB Support - Allows disconnected, unttagged request table
+ 4. 64 Byte SCB Support - Allows disconnected, untagged request table
for all possible target/lun combinations.
5. Block Move Instruction Support - Doubles the speed of certain
sequencer operations.
diff --git a/Documentation/scsi/aic7xxx_old.txt b/Documentation/scsi/aic7xxx_old.txt
index 05667e7308d..7bd210ab45a 100644
--- a/Documentation/scsi/aic7xxx_old.txt
+++ b/Documentation/scsi/aic7xxx_old.txt
@@ -356,7 +356,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
or enable Tagged Command Queueing (TCQ) on specific devices. As of
driver version 5.1.11, TCQ is now either on or off by default
according to the setting you choose during the make config process.
- In order to en/disable TCQ for certian devices at boot time, a user
+ In order to en/disable TCQ for certain devices at boot time, a user
may use this boot param. The driver will then parse this message out
and en/disable the specific device entries that are present based upon
the value given. The param line is parsed in the following manner:
diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt
index caf10b15518..39d409a8efe 100644
--- a/Documentation/scsi/ncr53c8xx.txt
+++ b/Documentation/scsi/ncr53c8xx.txt
@@ -562,11 +562,6 @@ if only one has a flaw for some SCSI feature, you can disable the
support by the driver of this feature at linux start-up and enable
this feature after boot-up only for devices that support it safely.
-CONFIG_SCSI_NCR53C8XX_PROFILE_SUPPORT (default answer: n)
- This option must be set for profiling information to be gathered
- and printed out through the proc file system. This features may
- impact performances.
-
CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n)
Answer "y" if you suspect your mother board to not allow memory mapped I/O.
May slow down performance a little. This option is required by
@@ -1265,7 +1260,7 @@ then the request of the IRQ obviously will not succeed for all the drivers.
15.1 Problem tracking
Most SCSI problems are due to a non conformant SCSI bus or to buggy
-devices. If infortunately you have SCSI problems, you can check the
+devices. If unfortunately you have SCSI problems, you can check the
following things:
- SCSI bus cables
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index 3c12422f7f4..b7be95b5bd2 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -1,5 +1,5 @@
This file contains brief information about the SCSI tape driver.
-The driver is currently maintained by Kai Mäkisara (email
+The driver is currently maintained by Kai Mäkisara (email
Kai.Makisara@kolumbus.fi)
Last modified: Mon Mar 7 21:14:44 2005 by kai.makisara
diff --git a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt
index 2c1745a9df0..3d9f06bb3d0 100644
--- a/Documentation/scsi/sym53c8xx_2.txt
+++ b/Documentation/scsi/sym53c8xx_2.txt
@@ -587,7 +587,7 @@ devices, ... may cause a SCSI signal to be wrong when te driver reads it.
15.1 Problem tracking
Most SCSI problems are due to a non conformant SCSI bus or too buggy
-devices. If infortunately you have SCSI problems, you can check the
+devices. If unfortunately you have SCSI problems, you can check the
following things:
- SCSI bus cables
diff --git a/Documentation/scsi/tmscsim.txt b/Documentation/scsi/tmscsim.txt
index 8b2168aa4fc..61c0531e044 100644
--- a/Documentation/scsi/tmscsim.txt
+++ b/Documentation/scsi/tmscsim.txt
@@ -426,7 +426,7 @@ Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and
all the others for the wonderful OS and software.
Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
release and support.
-Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
+Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert
Tonneau) for intensively testing the driver (and even risking data loss
doing this during early revisions).
diff --git a/Documentation/sh/clk.txt b/Documentation/sh/clk.txt
new file mode 100644
index 00000000000..9aef710e9a4
--- /dev/null
+++ b/Documentation/sh/clk.txt
@@ -0,0 +1,32 @@
+Clock framework on SuperH architecture
+
+The framework on SH extends existing API by the function clk_set_rate_ex,
+which prototype is as follows:
+
+ clk_set_rate_ex (struct clk *clk, unsigned long rate, int algo_id)
+
+The algo_id parameter is used to specify algorithm used to recalculate clocks,
+adjanced to clock, specified as first argument. It is assumed that algo_id==0
+means no changes to adjanced clock
+
+Internally, the clk_set_rate_ex forwards request to clk->ops->set_rate method,
+if it is present in ops structure. The method should set the clock rate and adjust
+all needed clocks according to the passed algo_id.
+Exact values for algo_id are machine-dependend. For the sh7722, the following
+values are defined:
+
+ NO_CHANGE = 0,
+ IUS_N1_N1, /* I:U = N:1, U:Sh = N:1 */
+ IUS_322, /* I:U:Sh = 3:2:2 */
+ IUS_522, /* I:U:Sh = 5:2:2 */
+ IUS_N11, /* I:U:Sh = N:1:1 */
+ SB_N1, /* Sh:B = N:1 */
+ SB3_N1, /* Sh:B3 = N:1 */
+ SB3_32, /* Sh:B3 = 3:2 */
+ SB3_43, /* Sh:B3 = 4:3 */
+ SB3_54, /* Sh:B3 = 5:4 */
+ BP_N1, /* B:P = N:1 */
+ IP_N1 /* I:P = N:1 */
+
+Each of these constants means relation between clocks that can be set via the FRQCR
+register
diff --git a/Documentation/sony-laptop.txt b/Documentation/sony-laptop.txt
index dfd26df056f..7a5c1a81905 100644
--- a/Documentation/sony-laptop.txt
+++ b/Documentation/sony-laptop.txt
@@ -3,12 +3,18 @@ Sony Notebook Control Driver (SNC) Readme
Copyright (C) 2004- 2005 Stelian Pop <stelian@popies.net>
Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
-This mini-driver drives the SNC device present in the ACPI BIOS of
-the Sony Vaio laptops.
+This mini-driver drives the SNC and SPIC device present in the ACPI BIOS of the
+Sony Vaio laptops. This driver mixes both devices functions under the same
+(hopefully consistent) interface. This also means that the sonypi driver is
+obsoleted by sony-laptop now.
-It gives access to some extra laptop functionalities. In its current
-form, this driver let the user set or query the screen brightness
-through the backlight subsystem and remove/apply power to some devices.
+Fn keys (hotkeys):
+------------------
+Some models report hotkeys through the SNC or SPIC devices, such events are
+reported both through the ACPI subsystem as acpi events and through the INPUT
+subsystem. See the logs of acpid or /proc/acpi/event and
+/proc/bus/input/devices to find out what those events are and which input
+devices are created by the driver.
Backlight control:
------------------
@@ -39,6 +45,8 @@ The files are:
audiopower power on/off the internal sound card
lanpower power on/off the internal ethernet card
(only in debug mode)
+ bluetoothpower power on/off the internal bluetooth device
+ fanspeed get/set the fan speed
Note that some files may be missing if they are not supported
by your particular laptop model.
@@ -76,9 +84,9 @@ The sony-laptop driver creates, for some of those methods (the most
current ones found on several Vaio models), an entry under
/sys/devices/platform/sony-laptop, just like the 'cdpower' one.
You can create other entries corresponding to your own laptop methods by
-further editing the source (see the 'sony_acpi_values' table, and add a new
+further editing the source (see the 'sony_nc_values' table, and add a new
entry to this table with your get/set method names using the
-HANDLE_NAMES macro).
+SNC_HANDLE_NAMES macro).
Your mission, should you accept it, is to try finding out what
those entries are for, by reading/writing random values from/to those
@@ -87,6 +95,9 @@ files and find out what is the impact on your laptop.
Should you find anything interesting, please report it back to me,
I will not disavow all knowledge of your actions :)
+See also http://www.linux.it/~malattia/wiki/index.php/Sony_drivers for other
+useful info.
+
Bugs/Limitations:
-----------------
diff --git a/Documentation/sonypi.txt b/Documentation/sonypi.txt
index c1237a92550..4857acfc50f 100644
--- a/Documentation/sonypi.txt
+++ b/Documentation/sonypi.txt
@@ -1,7 +1,7 @@
Sony Programmable I/O Control Device Driver Readme
--------------------------------------------------
Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
- Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ Copyright (C) 2001-2002 Alcôve <www.alcove.com>
Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
diff --git a/Documentation/sound/oss/mwave b/Documentation/sound/oss/mwave
index 858334bb46b..5fbcb160927 100644
--- a/Documentation/sound/oss/mwave
+++ b/Documentation/sound/oss/mwave
@@ -163,7 +163,7 @@ OR the Default= line COULD be
Default=SBPRO
Reboot to Windows 95 and choose Linux. When booted, use sndconfig to configure
-the sound modules and voilà - ThinkPad sound with Linux.
+the sound modules and voilà - ThinkPad sound with Linux.
Now the gotchas - you can either have CD sound OR Mixers but not both. That's a
problem with the SB1.5 (CD sound) or SBPRO (Mixers) settings. No one knows why
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index f9717fe9bd8..215e3b8e726 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -62,7 +62,7 @@ static struct resource pxa_spi_nssp_resources[] = {
static struct pxa2xx_spi_master pxa_nssp_master_info = {
.ssp_type = PXA25x_NSSP, /* Type of SSP */
- .clock_enable = CKEN9_NSSP, /* NSSP Peripheral clock */
+ .clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
.enable_dma = 1, /* Enables NSSP DMA */
};
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index ecc7c9eb9f2..795fbb48ffa 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -8,7 +8,7 @@ What is SPI?
The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial
link used to connect microcontrollers to sensors, memory, and peripherals.
-The three signal wires hold a clock (SCLK, often on the order of 10 MHz),
+The three signal wires hold a clock (SCK, often on the order of 10 MHz),
and parallel data lines with "Master Out, Slave In" (MOSI) or "Master In,
Slave Out" (MISO) signals. (Other names are also used.) There are four
clocking modes through which data is exchanged; mode-0 and mode-3 are most
@@ -22,7 +22,7 @@ other signals, often including an interrupt to the master.
Unlike serial busses like USB or SMBUS, even low level protocols for
SPI slave functions are usually not interoperable between vendors
-(except for cases like SPI memory chips).
+(except for commodities like SPI memory chips).
- SPI may be used for request/response style device protocols, as with
touchscreen sensors and memory chips.
@@ -77,8 +77,9 @@ cards without needing a special purpose MMC/SD/SDIO controller.
How do these driver programming interfaces work?
------------------------------------------------
The <linux/spi/spi.h> header file includes kerneldoc, as does the
-main source code, and you should certainly read that. This is just
-an overview, so you get the big picture before the details.
+main source code, and you should certainly read that chapter of the
+kernel API document. This is just an overview, so you get the big
+picture before those details.
SPI requests always go into I/O queues. Requests for a given SPI device
are always executed in FIFO order, and complete asynchronously through
@@ -88,7 +89,7 @@ a command and then reading its response.
There are two types of SPI driver, here called:
- Controller drivers ... these are often built in to System-On-Chip
+ Controller drivers ... controllers may be built in to System-On-Chip
processors, and often support both Master and Slave roles.
These drivers touch hardware registers and may use DMA.
Or they can be PIO bitbangers, needing just GPIO pins.
@@ -108,18 +109,18 @@ those two types of driver. At this writing, Linux has no slave side
programming interface.
There is a minimal core of SPI programming interfaces, focussing on
-using driver model to connect controller and protocol drivers using
+using the driver model to connect controller and protocol drivers using
device tables provided by board specific initialization code. SPI
shows up in sysfs in several locations:
- /sys/devices/.../CTLR/spiB.C ... spi_device for on bus "B",
+ /sys/devices/.../CTLR/spiB.C ... spi_device on bus "B",
chipselect C, accessed through CTLR.
/sys/devices/.../CTLR/spiB.C/modalias ... identifies the driver
that should be used with this device (for hotplug/coldplug)
/sys/bus/spi/devices/spiB.C ... symlink to the physical
- spiB-C device
+ spiB.C device
/sys/bus/spi/drivers/D ... driver for one or more spi*.* devices
@@ -240,7 +241,7 @@ The board_info should provide enough information to let the system work
without the chip's driver being loaded. The most troublesome aspect of
that is likely the SPI_CS_HIGH bit in the spi_device.mode field, since
sharing a bus with a device that interprets chipselect "backwards" is
-not possible.
+not possible until the infrastructure knows how to deselect it.
Then your board initialization code would register that table with the SPI
infrastructure, so that it's available later when the SPI master controller
@@ -268,16 +269,14 @@ board info based on the board that was hotplugged. Of course, you'd later
call at least spi_unregister_device() when that board is removed.
When Linux includes support for MMC/SD/SDIO/DataFlash cards through SPI, those
-configurations will also be dynamic. Fortunately, those devices all support
-basic device identification probes, so that support should hotplug normally.
+configurations will also be dynamic. Fortunately, such devices all support
+basic device identification probes, so they should hotplug normally.
How do I write an "SPI Protocol Driver"?
----------------------------------------
-All SPI drivers are currently kernel drivers. A userspace driver API
-would just be another kernel driver, probably offering some lowlevel
-access through aio_read(), aio_write(), and ioctl() calls and using the
-standard userspace sysfs mechanisms to bind to a given SPI device.
+Most SPI drivers are currently kernel drivers, but there's also support
+for userspace drivers. Here we talk only about kernel drivers.
SPI protocol drivers somewhat resemble platform device drivers:
@@ -319,7 +318,8 @@ might look like this unless you're creating a class_device:
As soon as it enters probe(), the driver may issue I/O requests to
the SPI device using "struct spi_message". When remove() returns,
-the driver guarantees that it won't submit any more such messages.
+or after probe() fails, the driver guarantees that it won't submit
+any more such messages.
- An spi_message is a sequence of protocol operations, executed
as one atomic sequence. SPI driver controls include:
@@ -368,7 +368,8 @@ the driver guarantees that it won't submit any more such messages.
Some drivers may need to modify spi_device characteristics like the
transfer mode, wordsize, or clock rate. This is done with spi_setup(),
which would normally be called from probe() before the first I/O is
-done to the device.
+done to the device. However, that can also be called at any time
+that no message is pending for that device.
While "spi_device" would be the bottom boundary of the driver, the
upper boundaries might include sysfs (especially for sensor readings),
@@ -445,11 +446,15 @@ SPI MASTER METHODS
This sets up the device clock rate, SPI mode, and word sizes.
Drivers may change the defaults provided by board_info, and then
call spi_setup(spi) to invoke this routine. It may sleep.
+ Unless each SPI slave has its own configuration registers, don't
+ change them right away ... otherwise drivers could corrupt I/O
+ that's in progress for other SPI devices.
master->transfer(struct spi_device *spi, struct spi_message *message)
This must not sleep. Its responsibility is arrange that the
- transfer happens and its complete() callback is issued; the two
- will normally happen later, after other transfers complete.
+ transfer happens and its complete() callback is issued. The two
+ will normally happen later, after other transfers complete, and
+ if the controller is idle it will need to be kickstarted.
master->cleanup(struct spi_device *spi)
Your controller driver may use spi_device.controller_state to hold
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
new file mode 100644
index 00000000000..5c8e1b988a0
--- /dev/null
+++ b/Documentation/spi/spidev
@@ -0,0 +1,307 @@
+SPI devices have a limited userspace API, supporting basic half-duplex
+read() and write() access to SPI slave devices. Using ioctl() requests,
+full duplex transfers and device I/O configuration are also available.
+
+ #include <fcntl.h>
+ #include <unistd.h>
+ #include <sys/ioctl.h>
+ #include <linux/types.h>
+ #include <linux/spi/spidev.h>
+
+Some reasons you might want to use this programming interface include:
+
+ * Prototyping in an environment that's not crash-prone; stray pointers
+ in userspace won't normally bring down any Linux system.
+
+ * Developing simple protocols used to talk to microcontrollers acting
+ as SPI slaves, which you may need to change quite often.
+
+Of course there are drivers that can never be written in userspace, because
+they need to access kernel interfaces (such as IRQ handlers or other layers
+of the driver stack) that are not accessible to userspace.
+
+
+DEVICE CREATION, DRIVER BINDING
+===============================
+The simplest way to arrange to use this driver is to just list it in the
+spi_board_info for a device as the driver it should use: the "modalias"
+entry is "spidev", matching the name of the driver exposing this API.
+Set up the other device characteristics (bits per word, SPI clocking,
+chipselect polarity, etc) as usual, so you won't always need to override
+them later.
+
+(Sysfs also supports userspace driven binding/unbinding of drivers to
+devices. That mechanism might be supported here in the future.)
+
+When you do that, the sysfs node for the SPI device will include a child
+device node with a "dev" attribute that will be understood by udev or mdev.
+(Larger systems will have "udev". Smaller ones may configure "mdev" into
+busybox; it's less featureful, but often enough.) For a SPI device with
+chipselect C on bus B, you should see:
+
+ /dev/spidevB.C ... character special device, major number 153 with
+ a dynamically chosen minor device number. This is the node
+ that userspace programs will open, created by "udev" or "mdev".
+
+ /sys/devices/.../spiB.C ... as usual, the SPI device node will
+ be a child of its SPI master controller.
+
+ /sys/class/spidev/spidevB.C ... created when the "spidev" driver
+ binds to that device. (Directory or symlink, based on whether
+ or not you enabled the "deprecated sysfs files" Kconfig option.)
+
+Do not try to manage the /dev character device special file nodes by hand.
+That's error prone, and you'd need to pay careful attention to system
+security issues; udev/mdev should already be configured securely.
+
+If you unbind the "spidev" driver from that device, those two "spidev" nodes
+(in sysfs and in /dev) should automatically be removed (respectively by the
+kernel and by udev/mdev). You can unbind by removing the "spidev" driver
+module, which will affect all devices using this driver. You can also unbind
+by having kernel code remove the SPI device, probably by removing the driver
+for its SPI controller (so its spi_master vanishes).
+
+Since this is a standard Linux device driver -- even though it just happens
+to expose a low level API to userspace -- it can be associated with any number
+of devices at a time. Just provide one spi_board_info record for each such
+SPI device, and you'll get a /dev device node for each device.
+
+
+BASIC CHARACTER DEVICE API
+==========================
+Normal open() and close() operations on /dev/spidevB.D files work as you
+would expect.
+
+Standard read() and write() operations are obviously only half-duplex, and
+the chipselect is deactivated between those operations. Full-duplex access,
+and composite operation without chipselect de-activation, is available using
+the SPI_IOC_MESSAGE(N) request.
+
+Several ioctl() requests let your driver read or override the device's current
+settings for data transfer parameters:
+
+ SPI_IOC_RD_MODE, SPI_IOC_WR_MODE ... pass a pointer to a byte which will
+ return (RD) or assign (WR) the SPI transfer mode. Use the constants
+ SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
+ (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
+ sample on trailing edge iff this is set) flags.
+
+ SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
+ which will return (RD) or assign (WR) the bit justification used to
+ transfer SPI words. Zero indicates MSB-first; other values indicate
+ the less common LSB-first encoding. In both cases the specified value
+ is right-justified in each word, so that unused (TX) or undefined (RX)
+ bits are in the MSBs.
+
+ SPI_IOC_RD_BITS_PER_WORD, SPI_IOC_WR_BITS_PER_WORD ... pass a pointer to
+ a byte which will return (RD) or assign (WR) the number of bits in
+ each SPI transfer word. The value zero signifies eight bits.
+
+ SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ ... pass a pointer to a
+ u32 which will return (RD) or assign (WR) the maximum SPI transfer
+ speed, in Hz. The controller can't necessarily assign that specific
+ clock speed.
+
+NOTES:
+
+ - At this time there is no async I/O support; everything is purely
+ synchronous.
+
+ - There's currently no way to report the actual bit rate used to
+ shift data to/from a given device.
+
+ - From userspace, you can't currently change the chip select polarity;
+ that could corrupt transfers to other devices sharing the SPI bus.
+ Each SPI device is deselected when it's not in active use, allowing
+ other drivers to talk to other devices.
+
+ - There's a limit on the number of bytes each I/O request can transfer
+ to the SPI device. It defaults to one page, but that can be changed
+ using a module parameter.
+
+ - Because SPI has no low-level transfer acknowledgement, you usually
+ won't see any I/O errors when talking to a non-existent device.
+
+
+FULL DUPLEX CHARACTER DEVICE API
+================================
+
+See the sample program below for one example showing the use of the full
+duplex programming interface. (Although it doesn't perform a full duplex
+transfer.) The model is the same as that used in the kernel spi_sync()
+request; the individual transfers offer the same capabilities as are
+available to kernel drivers (except that it's not asynchronous).
+
+The example shows one half-duplex RPC-style request and response message.
+These requests commonly require that the chip not be deselected between
+the request and response. Several such requests could be chained into
+a single kernel request, even allowing the chip to be deselected after
+each response. (Other protocol options include changing the word size
+and bitrate for each transfer segment.)
+
+To make a full duplex request, provide both rx_buf and tx_buf for the
+same transfer. It's even OK if those are the same buffer.
+
+
+SAMPLE PROGRAM
+==============
+
+-------------------------------- CUT HERE
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+
+static int verbose;
+
+static void do_read(int fd, int len)
+{
+ unsigned char buf[32], *bp;
+ int status;
+
+ /* read at least 2 bytes, no more than 32 */
+ if (len < 2)
+ len = 2;
+ else if (len > sizeof(buf))
+ len = sizeof(buf);
+ memset(buf, 0, sizeof buf);
+
+ status = read(fd, buf, len);
+ if (status < 0) {
+ perror("read");
+ return;
+ }
+ if (status != len) {
+ fprintf(stderr, "short read\n");
+ return;
+ }
+
+ printf("read(%2d, %2d): %02x %02x,", len, status,
+ buf[0], buf[1]);
+ status -= 2;
+ bp = buf + 2;
+ while (status-- > 0)
+ printf(" %02x", *bp++);
+ printf("\n");
+}
+
+static void do_msg(int fd, int len)
+{
+ struct spi_ioc_transfer xfer[2];
+ unsigned char buf[32], *bp;
+ int status;
+
+ memset(xfer, 0, sizeof xfer);
+ memset(buf, 0, sizeof buf);
+
+ if (len > sizeof buf)
+ len = sizeof buf;
+
+ buf[0] = 0xaa;
+ xfer[0].tx_buf = (__u64) buf;
+ xfer[0].len = 1;
+
+ xfer[1].rx_buf = (__u64) buf;
+ xfer[1].len = len;
+
+ status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
+ if (status < 0) {
+ perror("SPI_IOC_MESSAGE");
+ return;
+ }
+
+ printf("response(%2d, %2d): ", len, status);
+ for (bp = buf; len; len--)
+ printf(" %02x", *bp++);
+ printf("\n");
+}
+
+static void dumpstat(const char *name, int fd)
+{
+ __u8 mode, lsb, bits;
+ __u32 speed;
+
+ if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
+ perror("SPI rd_mode");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
+ perror("SPI rd_lsb_fist");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
+ perror("SPI bits_per_word");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
+ perror("SPI max_speed_hz");
+ return;
+ }
+
+ printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
+ name, mode, bits, lsb ? "(lsb first) " : "", speed);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int readcount = 0;
+ int msglen = 0;
+ int fd;
+ const char *name;
+
+ while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
+ switch (c) {
+ case 'm':
+ msglen = atoi(optarg);
+ if (msglen < 0)
+ goto usage;
+ continue;
+ case 'r':
+ readcount = atoi(optarg);
+ if (readcount < 0)
+ goto usage;
+ continue;
+ case 'v':
+ verbose++;
+ continue;
+ case 'h':
+ case '?':
+usage:
+ fprintf(stderr,
+ "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
+ argv[0]);
+ return 1;
+ }
+ }
+
+ if ((optind + 1) != argc)
+ goto usage;
+ name = argv[optind];
+
+ fd = open(name, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ dumpstat(name, fd);
+
+ if (msglen)
+ do_msg(fd, msglen);
+
+ if (readcount)
+ do_read(fd, readcount);
+
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 5922e84d913..111fd28727e 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -221,14 +221,14 @@ Controls the kernel's behaviour when an oops or BUG is encountered.
0: try to continue operation
-1: panic immediatly. If the `panic' sysctl is also non-zero then the
+1: panic immediately. If the `panic' sysctl is also non-zero then the
machine will be rebooted.
==============================================================
pid_max:
-PID allocation wrap value. When the kenrel's next PID value
+PID allocation wrap value. When the kernel's next PID value
reaches this value, it wraps back to a minimum PID value.
PIDs of value pid_max or larger are not allocated.
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index e96a341eb7e..1d192565e18 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -197,11 +197,22 @@ and may not be fast.
panic_on_oom
-This enables or disables panic on out-of-memory feature. If this is set to 1,
-the kernel panics when out-of-memory happens. If this is set to 0, the kernel
-will kill some rogue process, called oom_killer. Usually, oom_killer can kill
-rogue processes and system will survive. If you want to panic the system
-rather than killing rogue processes, set this to 1.
+This enables or disables panic on out-of-memory feature.
-The default value is 0.
+If this is set to 0, the kernel will kill some rogue process,
+called oom_killer. Usually, oom_killer can kill rogue processes and
+system will survive.
+
+If this is set to 1, the kernel panics when out-of-memory happens.
+However, if a process limits using nodes by mempolicy/cpusets,
+and those nodes become memory exhaustion status, one process
+may be killed by oom-killer. No panic occurs in this case.
+Because other nodes' memory may be free. This means system total status
+may be not fatal yet.
+If this is set to 2, the kernel panics compulsorily even on the
+above-mentioned.
+
+The default value is 0.
+1 and 2 are for failover of clustering. Please select either
+according to your policy of failover.
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index d43aa9d3c10..ba328f25541 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -1,6 +1,6 @@
Linux Magic System Request Key Hacks
Documentation for sysrq.c
-Last update: 2007-JAN-06
+Last update: 2007-MAR-14
* What is the magic SysRq key?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -75,7 +75,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.:
'f' - Will call oom_kill to kill a memory hog process.
-'g' - Used by kgdb on ppc platforms.
+'g' - Used by kgdb on ppc and sh platforms.
'h' - Will display help (actually any other key than those listed
above will display help. but 'h' is easy to remember :-)
diff --git a/Documentation/ibm-acpi.txt b/Documentation/thinkpad-acpi.txt
index 0132d363feb..2d4803359a0 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,16 +1,22 @@
- IBM ThinkPad ACPI Extras Driver
+ ThinkPad ACPI Extras Driver
- Version 0.12
- 17 August 2005
+ Version 0.14
+ April 21st, 2007
Borislav Deianov <borislav@users.sf.net>
+ Henrique de Moraes Holschuh <hmh@hmh.eng.br>
http://ibm-acpi.sf.net/
-This is a Linux ACPI driver for the IBM ThinkPad laptops. It supports
-various features of these laptops which are accessible through the
-ACPI framework but not otherwise supported by the generic Linux ACPI
-drivers.
+This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
+supports various features of these laptops which are accessible
+through the ACPI and ACPI EC framework, but not otherwise fully
+supported by the generic Linux ACPI drivers.
+
+This driver used to be named ibm-acpi until kernel 2.6.21 and release
+0.13-20070314. It used to be in the drivers/acpi tree, but it was
+moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
+2.6.22, and release 0.14.
Status
@@ -21,7 +27,7 @@ detailed description):
- Fn key combinations
- Bluetooth enable and disable
- - video output switching, expansion control
+ - video output switching, expansion control
- ThinkLight on and off
- limited docking and undocking
- UltraBay eject
@@ -32,7 +38,7 @@ detailed description):
- Experimental: embedded controller register dump
- LCD brightness control
- Volume control
- - Experimental: fan speed, fan enable/disable
+ - Fan control and monitoring: fan speed, fan enable/disable
- Experimental: WAN enable and disable
A compatibility table by model and feature is maintained on the web
@@ -42,6 +48,8 @@ Please include the following information in your report:
- ThinkPad model name
- a copy of your DSDT, from /proc/acpi/dsdt
+ - a copy of the output of dmidecode, with serial numbers
+ and UUIDs masked off
- which driver features work and which don't
- the observed behavior of non-working features
@@ -52,25 +60,85 @@ Installation
------------
If you are compiling this driver as included in the Linux kernel
-sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
-ACPI / IBM ThinkPad Laptop Extras).
+sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally
+enable the CONFIG_THINKPAD_ACPI_BAY option if you want the
+thinkpad-specific bay functionality.
Features
--------
-The driver creates the /proc/acpi/ibm directory. There is a file under
-that directory for each feature described below. Note that while the
-driver is still in the alpha stage, the exact proc file format and
-commands supported by the various features is guaranteed to change
-frequently.
+The driver exports two different interfaces to userspace, which can be
+used to access the features it provides. One is a legacy procfs-based
+interface, which will be removed at some time in the distant future.
+The other is a new sysfs-based interface which is not complete yet.
-Driver version -- /proc/acpi/ibm/driver
----------------------------------------
+The procfs interface creates the /proc/acpi/ibm directory. There is a
+file under that directory for each feature it supports. The procfs
+interface is mostly frozen, and will change very little if at all: it
+will not be extended to add any new functionality in the driver, instead
+all new functionality will be implemented on the sysfs interface.
+
+The sysfs interface tries to blend in the generic Linux sysfs subsystems
+and classes as much as possible. Since some of these subsystems are not
+yet ready or stabilized, it is expected that this interface will change,
+and any and all userspace programs must deal with it.
+
+
+Notes about the sysfs interface:
+
+Unlike what was done with the procfs interface, correctness when talking
+to the sysfs interfaces will be enforced, as will correctness in the
+thinkpad-acpi's implementation of sysfs interfaces.
+
+Also, any bugs in the thinkpad-acpi sysfs driver code or in the
+thinkpad-acpi's implementation of the sysfs interfaces will be fixed for
+maximum correctness, even if that means changing an interface in
+non-compatible ways. As these interfaces mature both in the kernel and
+in thinkpad-acpi, such changes should become quite rare.
+
+Applications interfacing to the thinkpad-acpi sysfs interfaces must
+follow all sysfs guidelines and correctly process all errors (the sysfs
+interface makes extensive use of errors). File descriptors and open /
+close operations to the sysfs inodes must also be properly implemented.
+
+The version of thinkpad-acpi's sysfs interface is exported by the driver
+as a driver attribute (see below).
+
+Sysfs driver attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/bus/platform/drivers/thinkpad-acpi/.
+
+Sysfs device attributes are on the driver's sysfs attribute space,
+for 2.6.20 this is /sys/devices/platform/thinkpad-acpi/.
+
+Driver version
+--------------
+
+procfs: /proc/acpi/ibm/driver
+sysfs driver attribute: version
The driver name and version. No commands can be written to this file.
-Hot keys -- /proc/acpi/ibm/hotkey
----------------------------------
+Sysfs interface version
+-----------------------
+
+sysfs driver attribute: interface_version
+
+Version of the thinkpad-acpi sysfs interface, as an unsigned long
+(output in hex format: 0xAAAABBCC), where:
+ AAAA - major revision
+ BB - minor revision
+ CC - bugfix revision
+
+The sysfs interface version changelog for the driver can be found at the
+end of this document. Changes to the sysfs interface done by the kernel
+subsystems are not documented here, nor are they tracked by this
+attribute.
+
+Hot keys
+--------
+
+procfs: /proc/acpi/ibm/hotkey
+sysfs device attribute: hotkey/*
Without this driver, only the Fn-F4 key (sleep button) generates an
ACPI event. With the driver loaded, the hotkey feature enabled and the
@@ -84,15 +152,6 @@ All labeled Fn-Fx key combinations generate distinct events. In
addition, the lid microswitch and some docking station buttons may
also generate such events.
-The following commands can be written to this file:
-
- echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
- echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
- echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
- echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
- ... any other 4-hex-digit mask ...
- echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
-
The bit mask allows some control over which hot keys generate ACPI
events. Not all bits in the mask can be modified. Not all bits that
can be modified do anything. Not all hot keys can be individually
@@ -124,15 +183,77 @@ buttons do not generate ACPI events even with this driver. They *can*
be used through the "ThinkPad Buttons" utility, see
http://www.nongnu.org/tpb/
-Bluetooth -- /proc/acpi/ibm/bluetooth
--------------------------------------
+procfs notes:
+
+The following commands can be written to the /proc/acpi/ibm/hotkey file:
+
+ echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
+ echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
+ echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
+ echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+ ... any other 4-hex-digit mask ...
+ echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
+
+sysfs notes:
+
+ The hot keys attributes are in a hotkey/ subdirectory off the
+ thinkpad device.
+
+ bios_enabled:
+ Returns the status of the hot keys feature when
+ thinkpad-acpi was loaded. Upon module unload, the hot
+ key feature status will be restored to this value.
+
+ 0: hot keys were disabled
+ 1: hot keys were enabled
+
+ bios_mask:
+ Returns the hot keys mask when thinkpad-acpi was loaded.
+ Upon module unload, the hot keys mask will be restored
+ to this value.
+
+ enable:
+ Enables/disables the hot keys feature, and reports
+ current status of the hot keys feature.
+
+ 0: disables the hot keys feature / feature disabled
+ 1: enables the hot keys feature / feature enabled
+
+ mask:
+ bit mask to enable ACPI event generation for each hot
+ key (see above). Returns the current status of the hot
+ keys mask, and allows one to modify it.
+
-This feature shows the presence and current state of a Bluetooth
-device. If Bluetooth is installed, the following commands can be used:
+Bluetooth
+---------
+
+procfs: /proc/acpi/ibm/bluetooth
+sysfs device attribute: bluetooth/enable
+
+This feature shows the presence and current state of a ThinkPad
+Bluetooth device in the internal ThinkPad CDC slot.
+
+Procfs notes:
+
+If Bluetooth is installed, the following commands can be used:
echo enable > /proc/acpi/ibm/bluetooth
echo disable > /proc/acpi/ibm/bluetooth
+Sysfs notes:
+
+ If the Bluetooth CDC card is installed, it can be enabled /
+ disabled through the "bluetooth/enable" thinkpad-acpi device
+ attribute, and its current status can also be queried.
+
+ enable:
+ 0: disables Bluetooth / Bluetooth is disabled
+ 1: enables Bluetooth / Bluetooth is enabled.
+
+ Note: this interface will be probably be superseeded by the
+ generic rfkill class.
+
Video output control -- /proc/acpi/ibm/video
--------------------------------------------
@@ -209,7 +330,7 @@ hot plugging of devices in the Linux ACPI framework. If the laptop was
booted while not in the dock, the following message is shown in the
logs:
- Mar 17 01:42:34 aero kernel: ibm_acpi: dock device not present
+ Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present
In this case, no dock-related events are generated but the dock and
undock commands described below still work. They can be executed
@@ -269,7 +390,7 @@ This is due to the current lack of support for hot plugging of devices
in the Linux ACPI framework. If the laptop was booted without the
UltraBay, the following message is shown in the logs:
- Mar 17 01:42:34 aero kernel: ibm_acpi: bay device not present
+ Mar 17 01:42:34 aero kernel: thinkpad_acpi: bay device not present
In this case, no bay-related events are generated but the eject
command described below still works. It can be executed manually or
@@ -313,23 +434,19 @@ supported. Use "eject2" instead of "eject" for the second bay.
Note: the UltraBay eject support on the 600e/x, A22p and A3x is
EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
-CMOS control -- /proc/acpi/ibm/cmos
------------------------------------
+CMOS control
+------------
+
+procfs: /proc/acpi/ibm/cmos
+sysfs device attribute: cmos_command
This feature is used internally by the ACPI firmware to control the
ThinkLight on most newer ThinkPad models. It may also control LCD
brightness, sounds volume and more, but only on some models.
-The commands are non-negative integer numbers:
-
- echo 0 >/proc/acpi/ibm/cmos
- echo 1 >/proc/acpi/ibm/cmos
- echo 2 >/proc/acpi/ibm/cmos
- ...
-
-The range of valid numbers is 0 to 21, but not all have an effect and
-the behavior varies from model to model. Here is the behavior on the
-X40 (tpb is the ThinkPad Buttons utility):
+The range of valid cmos command numbers is 0 to 21, but not all have an
+effect and the behavior varies from model to model. Here is the behavior
+on the X40 (tpb is the ThinkPad Buttons utility):
0 - no effect but tpb reports "Volume down"
1 - no effect but tpb reports "Volume up"
@@ -342,6 +459,9 @@ X40 (tpb is the ThinkPad Buttons utility):
13 - ThinkLight off
14 - no effect but tpb reports ThinkLight status change
+The cmos command interface is prone to firmware split-brain problems, as
+in newer ThinkPads it is just a compatibility layer.
+
LED control -- /proc/acpi/ibm/led
---------------------------------
@@ -393,17 +513,17 @@ X40:
16 - one medium-pitched beep repeating constantly, stop with 17
17 - stop 16
-Temperature sensors -- /proc/acpi/ibm/thermal
----------------------------------------------
+Temperature sensors
+-------------------
+
+procfs: /proc/acpi/ibm/thermal
+sysfs device attributes: (hwmon) temp*_input
Most ThinkPads include six or more separate temperature sensors but
only expose the CPU temperature through the standard ACPI methods.
This feature shows readings from up to eight different sensors on older
ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads. Readings from sensors that are not available
-return -128.
-
-No commands can be written to this file.
+sensors on newer ThinkPads.
EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
implementation directly accesses hardware registers and may not work as
@@ -460,6 +580,20 @@ The A31 has a very atypical layout for the thermal sensors
8: Bay Battery: secondary sensor
+Procfs notes:
+ Readings from sensors that are not available return -128.
+ No commands can be written to this file.
+
+Sysfs notes:
+ Sensors that are not available return the ENXIO error. This
+ status may change at runtime, as there are hotplug thermal
+ sensors, like those inside the batteries and docks.
+
+ thinkpad-acpi thermal sensors are reported through the hwmon
+ subsystem, and follow all of the hwmon guidelines at
+ Documentation/hwmon.
+
+
EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
------------------------------------------------------------------------
@@ -472,7 +606,7 @@ This feature dumps the values of 256 embedded controller
registers. Values which have changed since the last time the registers
were dumped are marked with a star:
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
@@ -503,7 +637,7 @@ vary. The second ensures that the fan-related values do vary, since
the fan speed fluctuates a bit. The third will (hopefully) mark the
fan register with a star:
-[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
+[root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump
EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f
EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00
EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00
@@ -533,19 +667,59 @@ registers contain the current battery capacity, etc. If you experiment
with this, do send me your results (including some complete dumps with
a description of the conditions when they were taken.)
-LCD brightness control -- /proc/acpi/ibm/brightness
----------------------------------------------------
+LCD brightness control
+----------------------
+
+procfs: /proc/acpi/ibm/brightness
+sysfs backlight device "thinkpad_screen"
This feature allows software control of the LCD brightness on ThinkPad
-models which don't have a hardware brightness slider. The available
-commands are:
+models which don't have a hardware brightness slider.
+
+It has some limitations: the LCD backlight cannot be actually turned on or off
+by this interface, and in many ThinkPad models, the "dim while on battery"
+functionality will be enabled by the BIOS when this interface is used, and
+cannot be controlled.
+
+The backlight control has eight levels, ranging from 0 to 7. Some of the
+levels may not be distinct.
+
+Procfs notes:
+
+ The available commands are:
echo up >/proc/acpi/ibm/brightness
echo down >/proc/acpi/ibm/brightness
echo 'level <level>' >/proc/acpi/ibm/brightness
-The <level> number range is 0 to 7, although not all of them may be
-distinct. The current brightness level is shown in the file.
+Sysfs notes:
+
+The interface is implemented through the backlight sysfs class, which is poorly
+documented at this time.
+
+Locate the thinkpad_screen device under /sys/class/backlight, and inside it
+there will be the following attributes:
+
+ max_brightness:
+ Reads the maximum brightness the hardware can be set to.
+ The minimum is always zero.
+
+ actual_brightness:
+ Reads what brightness the screen is set to at this instant.
+
+ brightness:
+ Writes request the driver to change brightness to the given
+ value. Reads will tell you what brightness the driver is trying
+ to set the display to when "power" is set to zero and the display
+ has not been dimmed by a kernel power management event.
+
+ power:
+ power management mode, where 0 is "display on", and 1 to 3 will
+ dim the display backlight to brightness level 0 because
+ thinkpad-acpi cannot really turn the backlight off. Kernel
+ power management events can temporarily increase the current
+ power management level, i.e. they can dim the display.
+
Volume control -- /proc/acpi/ibm/volume
---------------------------------------
@@ -563,41 +737,42 @@ distinct. The unmute the volume after the mute command, use either the
up or down command (the level command will not unmute the volume).
The current volume level and mute state is shown in the file.
-EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan
------------------------------------------------------------------
+Fan control and monitoring: fan speed, fan enable/disable
+---------------------------------------------------------
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+procfs: /proc/acpi/ibm/fan
+sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable
+
+NOTE NOTE NOTE: fan control operations are disabled by default for
+safety reasons. To enable them, the module parameter "fan_control=1"
+must be given to thinkpad-acpi.
This feature attempts to show the current fan speed, control mode and
other fan data that might be available. The speed is read directly
from the hardware registers of the embedded controller. This is known
-to work on later R, T and X series ThinkPads but may show a bogus
+to work on later R, T, X and Z series ThinkPads but may show a bogus
value on other models.
-Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher
-the level, the higher the fan speed, although adjacent levels often map
-to the same fan speed. 7 is the highest level, where the fan reaches
-the maximum recommended speed. Level "auto" means the EC changes the
-fan level according to some internal algorithm, usually based on
-readings from the thermal sensors. Level "disengaged" means the EC
-disables the speed-locked closed-loop fan control, and drives the fan as
-fast as it can go, which might exceed hardware limits, so use this level
-with caution.
+Fan levels:
-The fan usually ramps up or down slowly from one speed to another,
-and it is normal for the EC to take several seconds to react to fan
-commands.
+Most ThinkPad fans work in "levels" at the firmware interface. Level 0
+stops the fan. The higher the level, the higher the fan speed, although
+adjacent levels often map to the same fan speed. 7 is the highest
+level, where the fan reaches the maximum recommended speed.
-The fan may be enabled or disabled with the following commands:
+Level "auto" means the EC changes the fan level according to some
+internal algorithm, usually based on readings from the thermal sensors.
- echo enable >/proc/acpi/ibm/fan
- echo disable >/proc/acpi/ibm/fan
+There is also a "full-speed" level, also known as "disengaged" level.
+In this level, the EC disables the speed-locked closed-loop fan control,
+and drives the fan as fast as it can go, which might exceed hardware
+limits, so use this level with caution.
-Placing a fan on level 0 is the same as disabling it. Enabling a fan
-will try to place it in a safe level if it is too slow or disabled.
+The fan usually ramps up or down slowly from one speed to another, and
+it is normal for the EC to take several seconds to react to fan
+commands. The full-speed level may take up to two minutes to ramp up to
+maximum speed, and in some ThinkPads, the tachometer readings go stale
+while the EC is transitioning to the full-speed level.
WARNING WARNING WARNING: do not leave the fan disabled unless you are
monitoring all of the temperature sensor readings and you are ready to
@@ -615,46 +790,146 @@ fan is turned off when the CPU temperature drops to 49 degrees and the
HDD temperature drops to 41 degrees. These thresholds cannot
currently be controlled.
+The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
+certain conditions are met. It will override any fan programming done
+through thinkpad-acpi.
+
+The thinkpad-acpi kernel driver can be programmed to revert the fan
+level to a safe setting if userspace does not issue one of the procfs
+fan commands: "enable", "disable", "level" or "watchdog", or if there
+are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
+set to 1, manual mode) within a configurable amount of time of up to
+120 seconds. This functionality is called fan safety watchdog.
+
+Note that the watchdog timer stops after it enables the fan. It will be
+rearmed again automatically (using the same interval) when one of the
+above mentioned fan commands is received. The fan watchdog is,
+therefore, not suitable to protect against fan mode changes made through
+means other than the "enable", "disable", and "level" procfs fan
+commands, or the hwmon fan control sysfs interface.
+
+Procfs notes:
+
+The fan may be enabled or disabled with the following commands:
+
+ echo enable >/proc/acpi/ibm/fan
+ echo disable >/proc/acpi/ibm/fan
+
+Placing a fan on level 0 is the same as disabling it. Enabling a fan
+will try to place it in a safe level if it is too slow or disabled.
+
The fan level can be controlled with the command:
- echo 'level <level>' > /proc/acpi/ibm/thermal
+ echo 'level <level>' > /proc/acpi/ibm/fan
-Where <level> is an integer from 0 to 7, or one of the words "auto"
-or "disengaged" (without the quotes). Not all ThinkPads support the
-"auto" and "disengaged" levels.
+Where <level> is an integer from 0 to 7, or one of the words "auto" or
+"full-speed" (without the quotes). Not all ThinkPads support the "auto"
+and "full-speed" levels. The driver accepts "disengaged" as an alias for
+"full-speed", and reports it as "disengaged" for backwards
+compatibility.
On the X31 and X40 (and ONLY on those models), the fan speed can be
-controlled to a certain degree. Once the fan is running, it can be
+controlled to a certain degree. Once the fan is running, it can be
forced to run faster or slower with the following command:
- echo 'speed <speed>' > /proc/acpi/ibm/thermal
+ echo 'speed <speed>' > /proc/acpi/ibm/fan
-The sustainable range of fan speeds on the X40 appears to be from
-about 3700 to about 7350. Values outside this range either do not have
-any effect or the fan speed eventually settles somewhere in that
-range. The fan cannot be stopped or started with this command.
+The sustainable range of fan speeds on the X40 appears to be from about
+3700 to about 7350. Values outside this range either do not have any
+effect or the fan speed eventually settles somewhere in that range. The
+fan cannot be stopped or started with this command. This functionality
+is incomplete, and not available through the sysfs interface.
-The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
-certain conditions are met. It will override any fan programming done
-through ibm-acpi.
+To program the safety watchdog, use the "watchdog" command.
-EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
----------------------------------------
+ echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
+
+If you want to disable the watchdog, use 0 as the interval.
+
+Sysfs notes:
+
+The sysfs interface follows the hwmon subsystem guidelines for the most
+part, and the exception is the fan safety watchdog.
+
+Writes to any of the sysfs attributes may return the EINVAL error if
+that operation is not supported in a given ThinkPad or if the parameter
+is out-of-bounds, and EPERM if it is forbidden. They may also return
+EINTR (interrupted system call), and EIO (I/O error while trying to talk
+to the firmware).
+
+Features not yet implemented by the driver return ENOSYS.
+
+hwmon device attribute pwm1_enable:
+ 0: PWM offline (fan is set to full-speed mode)
+ 1: Manual PWM control (use pwm1 to set fan level)
+ 2: Hardware PWM control (EC "auto" mode)
+ 3: reserved (Software PWM control, not implemented yet)
+
+ Modes 0 and 2 are not supported by all ThinkPads, and the
+ driver is not always able to detect this. If it does know a
+ mode is unsupported, it will return -EINVAL.
+
+hwmon device attribute pwm1:
+ Fan level, scaled from the firmware values of 0-7 to the hwmon
+ scale of 0-255. 0 means fan stopped, 255 means highest normal
+ speed (level 7).
+
+ This attribute only commands the fan if pmw1_enable is set to 1
+ (manual PWM control).
+
+hwmon device attribute fan1_input:
+ Fan tachometer reading, in RPM. May go stale on certain
+ ThinkPads while the EC transitions the PWM to offline mode,
+ which can take up to two minutes. May return rubbish on older
+ ThinkPads.
+
+driver attribute fan_watchdog:
+ Fan safety watchdog timer interval, in seconds. Minimum is
+ 1 second, maximum is 120 seconds. 0 disables the watchdog.
+
+To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
+
+To start the fan in a safe mode: set pwm1_enable to 2. If that fails
+with EINVAL, try to set pwm1_enable to 1 and pwm1 to at least 128 (255
+would be the safest choice, though).
+
+
+EXPERIMENTAL: WAN
+-----------------
+
+procfs: /proc/acpi/ibm/wan
+sysfs device attribute: wwan/enable
This feature is marked EXPERIMENTAL because the implementation
directly accesses hardware registers and may not work as expected. USE
WITH CAUTION! To use this feature, you need to supply the
experimental=1 parameter when loading the module.
-This feature shows the presence and current state of a WAN (Sierra
-Wireless EV-DO) device. If WAN is installed, the following commands can
-be used:
+This feature shows the presence and current state of a W-WAN (Sierra
+Wireless EV-DO) device.
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
+
+Procfs notes:
+
+If the W-WAN card is installed, the following commands can be used:
echo enable > /proc/acpi/ibm/wan
echo disable > /proc/acpi/ibm/wan
-It was tested on a Lenovo Thinkpad X60. It should probably work on other
-Thinkpad models which come with this module installed.
+Sysfs notes:
+
+ If the W-WAN card is installed, it can be enabled /
+ disabled through the "wwan/enable" thinkpad-acpi device
+ attribute, and its current status can also be queried.
+
+ enable:
+ 0: disables WWAN card / WWAN card is disabled
+ 1: enables WWAN card / WWAN card is enabled.
+
+ Note: this interface will be probably be superseeded by the
+ generic rfkill class.
Multiple Commands, Module Parameters
------------------------------------
@@ -665,64 +940,42 @@ separating them with commas, for example:
echo enable,0xffff > /proc/acpi/ibm/hotkey
echo lcd_disable,crt_enable > /proc/acpi/ibm/video
-Commands can also be specified when loading the ibm_acpi module, for
-example:
-
- modprobe ibm_acpi hotkey=enable,0xffff video=auto_disable
-
-The ibm-acpi kernel driver can be programmed to revert the fan level
-to a safe setting if userspace does not issue one of the fan commands:
-"enable", "disable", "level" or "watchdog" within a configurable
-ammount of time. To do this, use the "watchdog" command.
-
- echo 'watchdog <interval>' > /proc/acpi/ibm/fan
-
-Interval is the ammount of time in seconds to wait for one of the
-above mentioned fan commands before reseting the fan level to a safe
-one. If set to zero, the watchdog is disabled (default). When the
-watchdog timer runs out, it does the exact equivalent of the "enable"
-fan command.
-
-Note that the watchdog timer stops after it enables the fan. It will
-be rearmed again automatically (using the same interval) when one of
-the above mentioned fan commands is received. The fan watchdog is,
-therefore, not suitable to protect against fan mode changes made
-through means other than the "enable", "disable", and "level" fan
-commands.
-
-
-Example Configuration
----------------------
-
-The ACPI support in the kernel is intended to be used in conjunction
-with a user-space daemon, acpid. The configuration files for this
-daemon control what actions are taken in response to various ACPI
-events. An example set of configuration files are included in the
-config/ directory of the tarball package available on the web
-site. Note that these are provided for illustration purposes only and
-may need to be adapted to your particular setup.
-
-The following utility scripts are used by the example action
-scripts (included with ibm-acpi for completeness):
-
- /usr/local/sbin/idectl -- from the hdparm source distribution,
- see http://www.ibiblio.org/pub/Linux/system/hardware
- /usr/local/sbin/laptop_mode -- from the Linux kernel source
- distribution, see Documentation/laptop-mode.txt
- /sbin/service -- comes with Redhat/Fedora distributions
- /usr/sbin/hibernate -- from the Software Suspend 2 distribution,
- see http://softwaresuspend.berlios.de/
-
-Toan T Nguyen <ntt@physics.ucla.edu> notes that Suse uses the
-powersave program to suspend ('powersave --suspend-to-ram') or
-hibernate ('powersave --suspend-to-disk'). This means that the
-hibernate script is not needed on that distribution.
-
-Henrik Brix Andersen <brix@gentoo.org> has written a Gentoo ACPI event
-handler script for the X31. You can get the latest version from
-http://dev.gentoo.org/~brix/files/x31.sh
-
-David Schweikert <dws@ee.eth.ch> has written an alternative blank.sh
-script which works on Debian systems. This scripts has now been
-extended to also work on Fedora systems and included as the default
-blank.sh in the distribution.
+Commands can also be specified when loading the thinkpad-acpi module,
+for example:
+
+ modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
+
+Enabling debugging output
+-------------------------
+
+The module takes a debug paramater which can be used to selectively
+enable various classes of debugging output, for example:
+
+ modprobe ibm_acpi debug=0xffff
+
+will enable all debugging output classes. It takes a bitmask, so
+to enable more than one output class, just add their values.
+
+ Debug bitmask Description
+ 0x0001 Initialization and probing
+ 0x0002 Removal
+
+There is also a kernel build option to enable more debugging
+information, which may be necessary to debug driver problems.
+
+The level of debugging information output by the driver can be changed
+at runtime through sysfs, using the driver attribute debug_level. The
+attribute takes the same bitmask as the debug module parameter above.
+
+Force loading of module
+-----------------------
+
+If thinkpad-acpi refuses to detect your ThinkPad, you can try to specify
+the module parameter force_load=1. Regardless of whether this works or
+not, please contact ibm-acpi-devel@lists.sourceforge.net with a report.
+
+
+Sysfs interface changelog:
+
+0x000100: Initial sysfs support, as a single platform driver and
+ device.
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
index 5f799e612e0..048a8762cfb 100644
--- a/Documentation/tty.txt
+++ b/Documentation/tty.txt
@@ -108,7 +108,9 @@ hardware driver through the function pointers within the tty->driver
structure:
write() Write a block of characters to the tty device.
- Returns the number of characters accepted.
+ Returns the number of characters accepted. The
+ character buffer passed to this method is already
+ in kernel space.
put_char() Queues a character for writing to the tty device.
If there is no room in the queue, the character is
diff --git a/Documentation/usb/CREDITS b/Documentation/usb/CREDITS
index 27a721635f9..67c59cdc995 100644
--- a/Documentation/usb/CREDITS
+++ b/Documentation/usb/CREDITS
@@ -65,7 +65,7 @@ THANKS file in Inaky's driver):
will sell keyboards to some of the 3 million (at least)
Linux users.
- - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
+ - Many thanks to ing büro h doran [http://www.ibhdoran.com]!
It was almost impossible to get a PC backplate USB connector
for the motherboard here at Europe (mine, home-made, was
quite lousy :). Now I know where to acquire nice USB stuff!
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index d61f6e7865d..5b635ae8494 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -42,12 +42,12 @@ ConnectTech WhiteHEAT 4 port converter
http://www.connecttech.com
For any questions or problems with this driver, please contact
- Stuart MacDonald at stuartm@connecttech.com
+ Connect Tech's Support Department at support@connecttech.com
-HandSpring Visor, Palm USB, and Clié USB driver
+HandSpring Visor, Palm USB, and Clié USB driver
- This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
+ This driver works with all HandSpring USB, Palm USB, and Sony Clié USB
devices.
Only when the device tries to connect to the host, will the device show
@@ -69,7 +69,7 @@ HandSpring Visor, Palm USB, and Clié USB driver
the port to use for the HotSync transfer. The "Generic" port can be used
for other device communication, such as a PPP link.
- For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
+ For some Sony Clié devices, /dev/ttyUSB0 must be used to talk to the
device. This is true for all OS version 3.5 devices, and most devices
that have had a flash upgrade to a newer version of the OS. See the
kernel system log for information on which is the correct port to use.
diff --git a/Documentation/video4linux/README.pvrusb2 b/Documentation/video4linux/README.pvrusb2
index a4b7ae80086..a747200fe67 100644
--- a/Documentation/video4linux/README.pvrusb2
+++ b/Documentation/video4linux/README.pvrusb2
@@ -8,7 +8,7 @@ Background:
This driver is intended for the "Hauppauge WinTV PVR USB 2.0", which
is a USB 2.0 hosted TV Tuner. This driver is a work in progress.
- Its history started with the reverse-engineering effort by Björn
+ Its history started with the reverse-engineering effort by Björn
Danielsson <pvrusb2@dax.nu> whose web page can be found here:
http://pvrusb2.dax.nu/
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index 85c575ac4fb..295462b2317 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -242,7 +242,7 @@ can generate: PAL , NTSC , SECAM
Conexant bt866 TV encoder
is used in AVS6EYES, and
-can generate: NTSC/PAL, PAL­M, PAL­N
+can generate: NTSC/PAL, PAL­M, PAL­N
The adv717x, should be able to produce PAL N. But you find nothing PAL N
specific in the registers. Seem that you have to reuse a other standard
diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
index ecb34160e61..bf3af5fe558 100644
--- a/Documentation/video4linux/meye.txt
+++ b/Documentation/video4linux/meye.txt
@@ -1,14 +1,13 @@
Vaio Picturebook Motion Eye Camera Driver Readme
------------------------------------------------
Copyright (C) 2001-2004 Stelian Pop <stelian@popies.net>
- Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ Copyright (C) 2001-2002 Alcôve <www.alcove.com>
Copyright (C) 2000 Andrew Tridgell <tridge@samba.org>
This driver enable the use of video4linux compatible applications with the
-Motion Eye camera. This driver requires the "Sony Vaio Programmable I/O
-Control Device" driver (which can be found in the "Character drivers"
-section of the kernel configuration utility) to be compiled and installed
-(using its "camera=1" parameter).
+Motion Eye camera. This driver requires the "Sony Laptop Extras" driver (which
+can be found in the "Misc devices" section of the kernel configuration utility)
+to be compiled and installed (using its "camera=1" parameter).
It can do at maximum 30 fps @ 320x240 or 15 fps @ 640x480.
diff --git a/Documentation/video4linux/ov511.txt b/Documentation/video4linux/ov511.txt
index 79af610d4ba..b3326b167ad 100644
--- a/Documentation/video4linux/ov511.txt
+++ b/Documentation/video4linux/ov511.txt
@@ -195,11 +195,11 @@ MODULE PARAMETERS:
NAME: bandingfilter
TYPE: integer (Boolean)
DEFAULT: 0 (off)
- DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
+ DESC: Enables the sensor´s banding filter exposure algorithm. This reduces
or stabilizes the "banding" caused by some artificial light sources
(especially fluorescent). You might have to set lightfreq correctly for
this to work right. As an added bonus, this sometimes makes it
- possible to capture your monitor´s output.
+ possible to capture your monitor´s output.
NAME: fastset
TYPE: integer (Boolean)
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c
new file mode 100644
index 00000000000..686a8e04a4f
--- /dev/null
+++ b/Documentation/vm/slabinfo.c
@@ -0,0 +1,1221 @@
+/*
+ * Slabinfo: Tool to get reports about slabs
+ *
+ * (C) 2007 sgi, Christoph Lameter <clameter@sgi.com>
+ *
+ * Compile by:
+ *
+ * gcc -o slabinfo slabinfo.c
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <regex.h>
+#include <errno.h>
+
+#define MAX_SLABS 500
+#define MAX_ALIASES 500
+#define MAX_NODES 1024
+
+struct slabinfo {
+ char *name;
+ int alias;
+ int refs;
+ int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
+ int hwcache_align, object_size, objs_per_slab;
+ int sanity_checks, slab_size, store_user, trace;
+ int order, poison, reclaim_account, red_zone;
+ unsigned long partial, objects, slabs;
+ int numa[MAX_NODES];
+ int numa_partial[MAX_NODES];
+} slabinfo[MAX_SLABS];
+
+struct aliasinfo {
+ char *name;
+ char *ref;
+ struct slabinfo *slab;
+} aliasinfo[MAX_ALIASES];
+
+int slabs = 0;
+int actual_slabs = 0;
+int aliases = 0;
+int alias_targets = 0;
+int highest_node = 0;
+
+char buffer[4096];
+
+int show_empty = 0;
+int show_report = 0;
+int show_alias = 0;
+int show_slab = 0;
+int skip_zero = 1;
+int show_numa = 0;
+int show_track = 0;
+int show_first_alias = 0;
+int validate = 0;
+int shrink = 0;
+int show_inverted = 0;
+int show_single_ref = 0;
+int show_totals = 0;
+int sort_size = 0;
+int set_debug = 0;
+int show_ops = 0;
+
+/* Debug options */
+int sanity = 0;
+int redzone = 0;
+int poison = 0;
+int tracking = 0;
+int tracing = 0;
+
+int page_size;
+
+regex_t pattern;
+
+void fatal(const char *x, ...)
+{
+ va_list ap;
+
+ va_start(ap, x);
+ vfprintf(stderr, x, ap);
+ va_end(ap);
+ exit(1);
+}
+
+void usage(void)
+{
+ printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n"
+ "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
+ "-a|--aliases Show aliases\n"
+ "-d<options>|--debug=<options> Set/Clear Debug options\n"
+ "-e|--empty Show empty slabs\n"
+ "-f|--first-alias Show first alias\n"
+ "-h|--help Show usage information\n"
+ "-i|--inverted Inverted list\n"
+ "-l|--slabs Show slabs\n"
+ "-n|--numa Show NUMA information\n"
+ "-o|--ops Show kmem_cache_ops\n"
+ "-s|--shrink Shrink slabs\n"
+ "-r|--report Detailed report on single slabs\n"
+ "-S|--Size Sort by size\n"
+ "-t|--tracking Show alloc/free information\n"
+ "-T|--Totals Show summary information\n"
+ "-v|--validate Validate slabs\n"
+ "-z|--zero Include empty slabs\n"
+ "-1|--1ref Single reference\n"
+ "\nValid debug options (FZPUT may be combined)\n"
+ "a / A Switch on all debug options (=FZUP)\n"
+ "- Switch off all debug options\n"
+ "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
+ "z / Z Redzoning\n"
+ "p / P Poisoning\n"
+ "u / U Tracking\n"
+ "t / T Tracing\n"
+ );
+}
+
+unsigned long read_obj(char *name)
+{
+ FILE *f = fopen(name, "r");
+
+ if (!f)
+ buffer[0] = 0;
+ else {
+ if (!fgets(buffer,sizeof(buffer), f))
+ buffer[0] = 0;
+ fclose(f);
+ if (buffer[strlen(buffer)] == '\n')
+ buffer[strlen(buffer)] = 0;
+ }
+ return strlen(buffer);
+}
+
+
+/*
+ * Get the contents of an attribute
+ */
+unsigned long get_obj(char *name)
+{
+ if (!read_obj(name))
+ return 0;
+
+ return atol(buffer);
+}
+
+unsigned long get_obj_and_str(char *name, char **x)
+{
+ unsigned long result = 0;
+ char *p;
+
+ *x = NULL;
+
+ if (!read_obj(name)) {
+ x = NULL;
+ return 0;
+ }
+ result = strtoul(buffer, &p, 10);
+ while (*p == ' ')
+ p++;
+ if (*p)
+ *x = strdup(p);
+ return result;
+}
+
+void set_obj(struct slabinfo *s, char *name, int n)
+{
+ char x[100];
+ FILE *f;
+
+ sprintf(x, "%s/%s", s->name, name);
+ f = fopen(x, "w");
+ if (!f)
+ fatal("Cannot write to %s\n", x);
+
+ fprintf(f, "%d\n", n);
+ fclose(f);
+}
+
+unsigned long read_slab_obj(struct slabinfo *s, char *name)
+{
+ char x[100];
+ FILE *f;
+ int l;
+
+ sprintf(x, "%s/%s", s->name, name);
+ f = fopen(x, "r");
+ if (!f) {
+ buffer[0] = 0;
+ l = 0;
+ } else {
+ l = fread(buffer, 1, sizeof(buffer), f);
+ buffer[l] = 0;
+ fclose(f);
+ }
+ return l;
+}
+
+
+/*
+ * Put a size string together
+ */
+int store_size(char *buffer, unsigned long value)
+{
+ unsigned long divisor = 1;
+ char trailer = 0;
+ int n;
+
+ if (value > 1000000000UL) {
+ divisor = 100000000UL;
+ trailer = 'G';
+ } else if (value > 1000000UL) {
+ divisor = 100000UL;
+ trailer = 'M';
+ } else if (value > 1000UL) {
+ divisor = 100;
+ trailer = 'K';
+ }
+
+ value /= divisor;
+ n = sprintf(buffer, "%ld",value);
+ if (trailer) {
+ buffer[n] = trailer;
+ n++;
+ buffer[n] = 0;
+ }
+ if (divisor != 1) {
+ memmove(buffer + n - 2, buffer + n - 3, 4);
+ buffer[n-2] = '.';
+ n++;
+ }
+ return n;
+}
+
+void decode_numa_list(int *numa, char *t)
+{
+ int node;
+ int nr;
+
+ memset(numa, 0, MAX_NODES * sizeof(int));
+
+ while (*t == 'N') {
+ t++;
+ node = strtoul(t, &t, 10);
+ if (*t == '=') {
+ t++;
+ nr = strtoul(t, &t, 10);
+ numa[node] = nr;
+ if (node > highest_node)
+ highest_node = node;
+ }
+ while (*t == ' ')
+ t++;
+ }
+}
+
+void slab_validate(struct slabinfo *s)
+{
+ set_obj(s, "validate", 1);
+}
+
+void slab_shrink(struct slabinfo *s)
+{
+ set_obj(s, "shrink", 1);
+}
+
+int line = 0;
+
+void first_line(void)
+{
+ printf("Name Objects Objsize Space "
+ "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
+}
+
+/*
+ * Find the shortest alias of a slab
+ */
+struct aliasinfo *find_one_alias(struct slabinfo *find)
+{
+ struct aliasinfo *a;
+ struct aliasinfo *best = NULL;
+
+ for(a = aliasinfo;a < aliasinfo + aliases; a++) {
+ if (a->slab == find &&
+ (!best || strlen(best->name) < strlen(a->name))) {
+ best = a;
+ if (strncmp(a->name,"kmall", 5) == 0)
+ return best;
+ }
+ }
+ return best;
+}
+
+unsigned long slab_size(struct slabinfo *s)
+{
+ return s->slabs * (page_size << s->order);
+}
+
+void slab_numa(struct slabinfo *s, int mode)
+{
+ int node;
+
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (!highest_node) {
+ printf("\n%s: No NUMA information available.\n", s->name);
+ return;
+ }
+
+ if (skip_zero && !s->slabs)
+ return;
+
+ if (!line) {
+ printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
+ for(node = 0; node <= highest_node; node++)
+ printf(" %4d", node);
+ printf("\n----------------------");
+ for(node = 0; node <= highest_node; node++)
+ printf("-----");
+ printf("\n");
+ }
+ printf("%-21s ", mode ? "All slabs" : s->name);
+ for(node = 0; node <= highest_node; node++) {
+ char b[20];
+
+ store_size(b, s->numa[node]);
+ printf(" %4s", b);
+ }
+ printf("\n");
+ if (mode) {
+ printf("%-21s ", "Partial slabs");
+ for(node = 0; node <= highest_node; node++) {
+ char b[20];
+
+ store_size(b, s->numa_partial[node]);
+ printf(" %4s", b);
+ }
+ printf("\n");
+ }
+ line++;
+}
+
+void show_tracking(struct slabinfo *s)
+{
+ printf("\n%s: Kernel object allocation\n", s->name);
+ printf("-----------------------------------------------------------------------\n");
+ if (read_slab_obj(s, "alloc_calls"))
+ printf(buffer);
+ else
+ printf("No Data\n");
+
+ printf("\n%s: Kernel object freeing\n", s->name);
+ printf("------------------------------------------------------------------------\n");
+ if (read_slab_obj(s, "free_calls"))
+ printf(buffer);
+ else
+ printf("No Data\n");
+
+}
+
+void ops(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (read_slab_obj(s, "ops")) {
+ printf("\n%s: kmem_cache operations\n", s->name);
+ printf("--------------------------------------------\n");
+ printf(buffer);
+ } else
+ printf("\n%s has no kmem_cache operations\n", s->name);
+}
+
+const char *onoff(int x)
+{
+ if (x)
+ return "On ";
+ return "Off";
+}
+
+void report(struct slabinfo *s)
+{
+ if (strcmp(s->name, "*") == 0)
+ return;
+ printf("\nSlabcache: %-20s Aliases: %2d Order : %2d\n", s->name, s->aliases, s->order);
+ if (s->hwcache_align)
+ printf("** Hardware cacheline aligned\n");
+ if (s->cache_dma)
+ printf("** Memory is allocated in a special DMA zone\n");
+ if (s->destroy_by_rcu)
+ printf("** Slabs are destroyed via RCU\n");
+ if (s->reclaim_account)
+ printf("** Reclaim accounting active\n");
+
+ printf("\nSizes (bytes) Slabs Debug Memory\n");
+ printf("------------------------------------------------------------------------\n");
+ printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
+ s->object_size, s->slabs, onoff(s->sanity_checks),
+ s->slabs * (page_size << s->order));
+ printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n",
+ s->slab_size, s->slabs - s->partial - s->cpu_slabs,
+ onoff(s->red_zone), s->objects * s->object_size);
+ printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n",
+ page_size << s->order, s->partial, onoff(s->poison),
+ s->slabs * (page_size << s->order) - s->objects * s->object_size);
+ printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n",
+ s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
+ (s->slab_size - s->object_size) * s->objects);
+ printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
+ s->align, s->objs_per_slab, onoff(s->trace),
+ ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
+ s->slabs);
+
+ ops(s);
+ show_tracking(s);
+ slab_numa(s, 1);
+}
+
+void slabcache(struct slabinfo *s)
+{
+ char size_str[20];
+ char dist_str[40];
+ char flags[20];
+ char *p = flags;
+
+ if (strcmp(s->name, "*") == 0)
+ return;
+
+ if (actual_slabs == 1) {
+ report(s);
+ return;
+ }
+
+ if (skip_zero && !show_empty && !s->slabs)
+ return;
+
+ if (show_empty && s->slabs)
+ return;
+
+ store_size(size_str, slab_size(s));
+ sprintf(dist_str,"%lu/%lu/%d", s->slabs, s->partial, s->cpu_slabs);
+
+ if (!line++)
+ first_line();
+
+ if (s->aliases)
+ *p++ = '*';
+ if (s->cache_dma)
+ *p++ = 'd';
+ if (s->hwcache_align)
+ *p++ = 'A';
+ if (s->poison)
+ *p++ = 'P';
+ if (s->reclaim_account)
+ *p++ = 'a';
+ if (s->red_zone)
+ *p++ = 'Z';
+ if (s->sanity_checks)
+ *p++ = 'F';
+ if (s->store_user)
+ *p++ = 'U';
+ if (s->trace)
+ *p++ = 'T';
+
+ *p = 0;
+ printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
+ s->name, s->objects, s->object_size, size_str, dist_str,
+ s->objs_per_slab, s->order,
+ s->slabs ? (s->partial * 100) / s->slabs : 100,
+ s->slabs ? (s->objects * s->object_size * 100) /
+ (s->slabs * (page_size << s->order)) : 100,
+ flags);
+}
+
+/*
+ * Analyze debug options. Return false if something is amiss.
+ */
+int debug_opt_scan(char *opt)
+{
+ if (!opt || !opt[0] || strcmp(opt, "-") == 0)
+ return 1;
+
+ if (strcasecmp(opt, "a") == 0) {
+ sanity = 1;
+ poison = 1;
+ redzone = 1;
+ tracking = 1;
+ return 1;
+ }
+
+ for ( ; *opt; opt++)
+ switch (*opt) {
+ case 'F' : case 'f':
+ if (sanity)
+ return 0;
+ sanity = 1;
+ break;
+ case 'P' : case 'p':
+ if (poison)
+ return 0;
+ poison = 1;
+ break;
+
+ case 'Z' : case 'z':
+ if (redzone)
+ return 0;
+ redzone = 1;
+ break;
+
+ case 'U' : case 'u':
+ if (tracking)
+ return 0;
+ tracking = 1;
+ break;
+
+ case 'T' : case 't':
+ if (tracing)
+ return 0;
+ tracing = 1;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+int slab_empty(struct slabinfo *s)
+{
+ if (s->objects > 0)
+ return 0;
+
+ /*
+ * We may still have slabs even if there are no objects. Shrinking will
+ * remove them.
+ */
+ if (s->slabs != 0)
+ set_obj(s, "shrink", 1);
+
+ return 1;
+}
+
+void slab_debug(struct slabinfo *s)
+{
+ if (sanity && !s->sanity_checks) {
+ set_obj(s, "sanity", 1);
+ }
+ if (!sanity && s->sanity_checks) {
+ if (slab_empty(s))
+ set_obj(s, "sanity", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
+ }
+ if (redzone && !s->red_zone) {
+ if (slab_empty(s))
+ set_obj(s, "red_zone", 1);
+ else
+ fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
+ }
+ if (!redzone && s->red_zone) {
+ if (slab_empty(s))
+ set_obj(s, "red_zone", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
+ }
+ if (poison && !s->poison) {
+ if (slab_empty(s))
+ set_obj(s, "poison", 1);
+ else
+ fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
+ }
+ if (!poison && s->poison) {
+ if (slab_empty(s))
+ set_obj(s, "poison", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
+ }
+ if (tracking && !s->store_user) {
+ if (slab_empty(s))
+ set_obj(s, "store_user", 1);
+ else
+ fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
+ }
+ if (!tracking && s->store_user) {
+ if (slab_empty(s))
+ set_obj(s, "store_user", 0);
+ else
+ fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
+ }
+ if (tracing && !s->trace) {
+ if (slabs == 1)
+ set_obj(s, "trace", 1);
+ else
+ fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
+ }
+ if (!tracing && s->trace)
+ set_obj(s, "trace", 1);
+}
+
+void totals(void)
+{
+ struct slabinfo *s;
+
+ int used_slabs = 0;
+ char b1[20], b2[20], b3[20], b4[20];
+ unsigned long long max = 1ULL << 63;
+
+ /* Object size */
+ unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
+
+ /* Number of partial slabs in a slabcache */
+ unsigned long long min_partial = max, max_partial = 0,
+ avg_partial, total_partial = 0;
+
+ /* Number of slabs in a slab cache */
+ unsigned long long min_slabs = max, max_slabs = 0,
+ avg_slabs, total_slabs = 0;
+
+ /* Size of the whole slab */
+ unsigned long long min_size = max, max_size = 0,
+ avg_size, total_size = 0;
+
+ /* Bytes used for object storage in a slab */
+ unsigned long long min_used = max, max_used = 0,
+ avg_used, total_used = 0;
+
+ /* Waste: Bytes used for alignment and padding */
+ unsigned long long min_waste = max, max_waste = 0,
+ avg_waste, total_waste = 0;
+ /* Number of objects in a slab */
+ unsigned long long min_objects = max, max_objects = 0,
+ avg_objects, total_objects = 0;
+ /* Waste per object */
+ unsigned long long min_objwaste = max,
+ max_objwaste = 0, avg_objwaste,
+ total_objwaste = 0;
+
+ /* Memory per object */
+ unsigned long long min_memobj = max,
+ max_memobj = 0, avg_memobj,
+ total_objsize = 0;
+
+ /* Percentage of partial slabs per slab */
+ unsigned long min_ppart = 100, max_ppart = 0,
+ avg_ppart, total_ppart = 0;
+
+ /* Number of objects in partial slabs */
+ unsigned long min_partobj = max, max_partobj = 0,
+ avg_partobj, total_partobj = 0;
+
+ /* Percentage of partial objects of all objects in a slab */
+ unsigned long min_ppartobj = 100, max_ppartobj = 0,
+ avg_ppartobj, total_ppartobj = 0;
+
+
+ for (s = slabinfo; s < slabinfo + slabs; s++) {
+ unsigned long long size;
+ unsigned long used;
+ unsigned long long wasted;
+ unsigned long long objwaste;
+ long long objects_in_partial_slabs;
+ unsigned long percentage_partial_slabs;
+ unsigned long percentage_partial_objs;
+
+ if (!s->slabs || !s->objects)
+ continue;
+
+ used_slabs++;
+
+ size = slab_size(s);
+ used = s->objects * s->object_size;
+ wasted = size - used;
+ objwaste = s->slab_size - s->object_size;
+
+ objects_in_partial_slabs = s->objects -
+ (s->slabs - s->partial - s ->cpu_slabs) *
+ s->objs_per_slab;
+
+ if (objects_in_partial_slabs < 0)
+ objects_in_partial_slabs = 0;
+
+ percentage_partial_slabs = s->partial * 100 / s->slabs;
+ if (percentage_partial_slabs > 100)
+ percentage_partial_slabs = 100;
+
+ percentage_partial_objs = objects_in_partial_slabs * 100
+ / s->objects;
+
+ if (percentage_partial_objs > 100)
+ percentage_partial_objs = 100;
+
+ if (s->object_size < min_objsize)
+ min_objsize = s->object_size;
+ if (s->partial < min_partial)
+ min_partial = s->partial;
+ if (s->slabs < min_slabs)
+ min_slabs = s->slabs;
+ if (size < min_size)
+ min_size = size;
+ if (wasted < min_waste)
+ min_waste = wasted;
+ if (objwaste < min_objwaste)
+ min_objwaste = objwaste;
+ if (s->objects < min_objects)
+ min_objects = s->objects;
+ if (used < min_used)
+ min_used = used;
+ if (objects_in_partial_slabs < min_partobj)
+ min_partobj = objects_in_partial_slabs;
+ if (percentage_partial_slabs < min_ppart)
+ min_ppart = percentage_partial_slabs;
+ if (percentage_partial_objs < min_ppartobj)
+ min_ppartobj = percentage_partial_objs;
+ if (s->slab_size < min_memobj)
+ min_memobj = s->slab_size;
+
+ if (s->object_size > max_objsize)
+ max_objsize = s->object_size;
+ if (s->partial > max_partial)
+ max_partial = s->partial;
+ if (s->slabs > max_slabs)
+ max_slabs = s->slabs;
+ if (size > max_size)
+ max_size = size;
+ if (wasted > max_waste)
+ max_waste = wasted;
+ if (objwaste > max_objwaste)
+ max_objwaste = objwaste;
+ if (s->objects > max_objects)
+ max_objects = s->objects;
+ if (used > max_used)
+ max_used = used;
+ if (objects_in_partial_slabs > max_partobj)
+ max_partobj = objects_in_partial_slabs;
+ if (percentage_partial_slabs > max_ppart)
+ max_ppart = percentage_partial_slabs;
+ if (percentage_partial_objs > max_ppartobj)
+ max_ppartobj = percentage_partial_objs;
+ if (s->slab_size > max_memobj)
+ max_memobj = s->slab_size;
+
+ total_partial += s->partial;
+ total_slabs += s->slabs;
+ total_size += size;
+ total_waste += wasted;
+
+ total_objects += s->objects;
+ total_used += used;
+ total_partobj += objects_in_partial_slabs;
+ total_ppart += percentage_partial_slabs;
+ total_ppartobj += percentage_partial_objs;
+
+ total_objwaste += s->objects * objwaste;
+ total_objsize += s->objects * s->slab_size;
+ }
+
+ if (!total_objects) {
+ printf("No objects\n");
+ return;
+ }
+ if (!used_slabs) {
+ printf("No slabs\n");
+ return;
+ }
+
+ /* Per slab averages */
+ avg_partial = total_partial / used_slabs;
+ avg_slabs = total_slabs / used_slabs;
+ avg_size = total_size / used_slabs;
+ avg_waste = total_waste / used_slabs;
+
+ avg_objects = total_objects / used_slabs;
+ avg_used = total_used / used_slabs;
+ avg_partobj = total_partobj / used_slabs;
+ avg_ppart = total_ppart / used_slabs;
+ avg_ppartobj = total_ppartobj / used_slabs;
+
+ /* Per object object sizes */
+ avg_objsize = total_used / total_objects;
+ avg_objwaste = total_objwaste / total_objects;
+ avg_partobj = total_partobj * 100 / total_objects;
+ avg_memobj = total_objsize / total_objects;
+
+ printf("Slabcache Totals\n");
+ printf("----------------\n");
+ printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n",
+ slabs, aliases, alias_targets, used_slabs);
+
+ store_size(b1, total_size);store_size(b2, total_waste);
+ store_size(b3, total_waste * 100 / total_used);
+ printf("Memory used: %6s # Loss : %6s MRatio: %6s%%\n", b1, b2, b3);
+
+ store_size(b1, total_objects);store_size(b2, total_partobj);
+ store_size(b3, total_partobj * 100 / total_objects);
+ printf("# Objects : %6s # PartObj: %6s ORatio: %6s%%\n", b1, b2, b3);
+
+ printf("\n");
+ printf("Per Cache Average Min Max Total\n");
+ printf("---------------------------------------------------------\n");
+
+ store_size(b1, avg_objects);store_size(b2, min_objects);
+ store_size(b3, max_objects);store_size(b4, total_objects);
+ printf("#Objects %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_slabs);store_size(b2, min_slabs);
+ store_size(b3, max_slabs);store_size(b4, total_slabs);
+ printf("#Slabs %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_partial);store_size(b2, min_partial);
+ store_size(b3, max_partial);store_size(b4, total_partial);
+ printf("#PartSlab %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+ store_size(b1, avg_ppart);store_size(b2, min_ppart);
+ store_size(b3, max_ppart);
+ store_size(b4, total_partial * 100 / total_slabs);
+ printf("%%PartSlab %10s%% %10s%% %10s%% %10s%%\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_partobj);store_size(b2, min_partobj);
+ store_size(b3, max_partobj);
+ store_size(b4, total_partobj);
+ printf("PartObjs %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
+ store_size(b3, max_ppartobj);
+ store_size(b4, total_partobj * 100 / total_objects);
+ printf("%% PartObj %10s%% %10s%% %10s%% %10s%%\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_size);store_size(b2, min_size);
+ store_size(b3, max_size);store_size(b4, total_size);
+ printf("Memory %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_used);store_size(b2, min_used);
+ store_size(b3, max_used);store_size(b4, total_used);
+ printf("Used %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ store_size(b1, avg_waste);store_size(b2, min_waste);
+ store_size(b3, max_waste);store_size(b4, total_waste);
+ printf("Loss %10s %10s %10s %10s\n",
+ b1, b2, b3, b4);
+
+ printf("\n");
+ printf("Per Object Average Min Max\n");
+ printf("---------------------------------------------\n");
+
+ store_size(b1, avg_memobj);store_size(b2, min_memobj);
+ store_size(b3, max_memobj);
+ printf("Memory %10s %10s %10s\n",
+ b1, b2, b3);
+ store_size(b1, avg_objsize);store_size(b2, min_objsize);
+ store_size(b3, max_objsize);
+ printf("User %10s %10s %10s\n",
+ b1, b2, b3);
+
+ store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
+ store_size(b3, max_objwaste);
+ printf("Loss %10s %10s %10s\n",
+ b1, b2, b3);
+}
+
+void sort_slabs(void)
+{
+ struct slabinfo *s1,*s2;
+
+ for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
+ for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
+ int result;
+
+ if (sort_size)
+ result = slab_size(s1) < slab_size(s2);
+ else
+ result = strcasecmp(s1->name, s2->name);
+
+ if (show_inverted)
+ result = -result;
+
+ if (result > 0) {
+ struct slabinfo t;
+
+ memcpy(&t, s1, sizeof(struct slabinfo));
+ memcpy(s1, s2, sizeof(struct slabinfo));
+ memcpy(s2, &t, sizeof(struct slabinfo));
+ }
+ }
+ }
+}
+
+void sort_aliases(void)
+{
+ struct aliasinfo *a1,*a2;
+
+ for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
+ for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
+ char *n1, *n2;
+
+ n1 = a1->name;
+ n2 = a2->name;
+ if (show_alias && !show_inverted) {
+ n1 = a1->ref;
+ n2 = a2->ref;
+ }
+ if (strcasecmp(n1, n2) > 0) {
+ struct aliasinfo t;
+
+ memcpy(&t, a1, sizeof(struct aliasinfo));
+ memcpy(a1, a2, sizeof(struct aliasinfo));
+ memcpy(a2, &t, sizeof(struct aliasinfo));
+ }
+ }
+ }
+}
+
+void link_slabs(void)
+{
+ struct aliasinfo *a;
+ struct slabinfo *s;
+
+ for (a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+ for (s = slabinfo; s < slabinfo + slabs; s++)
+ if (strcmp(a->ref, s->name) == 0) {
+ a->slab = s;
+ s->refs++;
+ break;
+ }
+ if (s == slabinfo + slabs)
+ fatal("Unresolved alias %s\n", a->ref);
+ }
+}
+
+void alias(void)
+{
+ struct aliasinfo *a;
+ char *active = NULL;
+
+ sort_aliases();
+ link_slabs();
+
+ for(a = aliasinfo; a < aliasinfo + aliases; a++) {
+
+ if (!show_single_ref && a->slab->refs == 1)
+ continue;
+
+ if (!show_inverted) {
+ if (active) {
+ if (strcmp(a->slab->name, active) == 0) {
+ printf(" %s", a->name);
+ continue;
+ }
+ }
+ printf("\n%-12s <- %s", a->slab->name, a->name);
+ active = a->slab->name;
+ }
+ else
+ printf("%-20s -> %s\n", a->name, a->slab->name);
+ }
+ if (active)
+ printf("\n");
+}
+
+
+void rename_slabs(void)
+{
+ struct slabinfo *s;
+ struct aliasinfo *a;
+
+ for (s = slabinfo; s < slabinfo + slabs; s++) {
+ if (*s->name != ':')
+ continue;
+
+ if (s->refs > 1 && !show_first_alias)
+ continue;
+
+ a = find_one_alias(s);
+
+ if (a)
+ s->name = a->name;
+ else {
+ s->name = "*";
+ actual_slabs--;
+ }
+ }
+}
+
+int slab_mismatch(char *slab)
+{
+ return regexec(&pattern, slab, 0, NULL, 0);
+}
+
+void read_slab_dir(void)
+{
+ DIR *dir;
+ struct dirent *de;
+ struct slabinfo *slab = slabinfo;
+ struct aliasinfo *alias = aliasinfo;
+ char *p;
+ char *t;
+ int count;
+
+ if (chdir("/sys/slab"))
+ fatal("SYSFS support for SLUB not active\n");
+
+ dir = opendir(".");
+ while ((de = readdir(dir))) {
+ if (de->d_name[0] == '.' ||
+ (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
+ continue;
+ switch (de->d_type) {
+ case DT_LNK:
+ alias->name = strdup(de->d_name);
+ count = readlink(de->d_name, buffer, sizeof(buffer));
+
+ if (count < 0)
+ fatal("Cannot read symlink %s\n", de->d_name);
+
+ buffer[count] = 0;
+ p = buffer + count;
+ while (p > buffer && p[-1] != '/')
+ p--;
+ alias->ref = strdup(p);
+ alias++;
+ break;
+ case DT_DIR:
+ if (chdir(de->d_name))
+ fatal("Unable to access slab %s\n", slab->name);
+ slab->name = strdup(de->d_name);
+ slab->alias = 0;
+ slab->refs = 0;
+ slab->aliases = get_obj("aliases");
+ slab->align = get_obj("align");
+ slab->cache_dma = get_obj("cache_dma");
+ slab->cpu_slabs = get_obj("cpu_slabs");
+ slab->destroy_by_rcu = get_obj("destroy_by_rcu");
+ slab->hwcache_align = get_obj("hwcache_align");
+ slab->object_size = get_obj("object_size");
+ slab->objects = get_obj("objects");
+ slab->objs_per_slab = get_obj("objs_per_slab");
+ slab->order = get_obj("order");
+ slab->partial = get_obj("partial");
+ slab->partial = get_obj_and_str("partial", &t);
+ decode_numa_list(slab->numa_partial, t);
+ slab->poison = get_obj("poison");
+ slab->reclaim_account = get_obj("reclaim_account");
+ slab->red_zone = get_obj("red_zone");
+ slab->sanity_checks = get_obj("sanity_checks");
+ slab->slab_size = get_obj("slab_size");
+ slab->slabs = get_obj_and_str("slabs", &t);
+ decode_numa_list(slab->numa, t);
+ slab->store_user = get_obj("store_user");
+ slab->trace = get_obj("trace");
+ chdir("..");
+ if (slab->name[0] == ':')
+ alias_targets++;
+ slab++;
+ break;
+ default :
+ fatal("Unknown file type %lx\n", de->d_type);
+ }
+ }
+ closedir(dir);
+ slabs = slab - slabinfo;
+ actual_slabs = slabs;
+ aliases = alias - aliasinfo;
+ if (slabs > MAX_SLABS)
+ fatal("Too many slabs\n");
+ if (aliases > MAX_ALIASES)
+ fatal("Too many aliases\n");
+}
+
+void output_slabs(void)
+{
+ struct slabinfo *slab;
+
+ for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
+
+ if (slab->alias)
+ continue;
+
+
+ if (show_numa)
+ slab_numa(slab, 0);
+ else if (show_track)
+ show_tracking(slab);
+ else if (validate)
+ slab_validate(slab);
+ else if (shrink)
+ slab_shrink(slab);
+ else if (set_debug)
+ slab_debug(slab);
+ else if (show_ops)
+ ops(slab);
+ else if (show_slab)
+ slabcache(slab);
+ }
+}
+
+struct option opts[] = {
+ { "aliases", 0, NULL, 'a' },
+ { "debug", 2, NULL, 'd' },
+ { "empty", 0, NULL, 'e' },
+ { "first-alias", 0, NULL, 'f' },
+ { "help", 0, NULL, 'h' },
+ { "inverted", 0, NULL, 'i'},
+ { "numa", 0, NULL, 'n' },
+ { "ops", 0, NULL, 'o' },
+ { "report", 0, NULL, 'r' },
+ { "shrink", 0, NULL, 's' },
+ { "slabs", 0, NULL, 'l' },
+ { "track", 0, NULL, 't'},
+ { "validate", 0, NULL, 'v' },
+ { "zero", 0, NULL, 'z' },
+ { "1ref", 0, NULL, '1'},
+ { NULL, 0, NULL, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int err;
+ char *pattern_source;
+
+ page_size = getpagesize();
+
+ while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS",
+ opts, NULL)) != -1)
+ switch(c) {
+ case '1':
+ show_single_ref = 1;
+ break;
+ case 'a':
+ show_alias = 1;
+ break;
+ case 'd':
+ set_debug = 1;
+ if (!debug_opt_scan(optarg))
+ fatal("Invalid debug option '%s'\n", optarg);
+ break;
+ case 'e':
+ show_empty = 1;
+ break;
+ case 'f':
+ show_first_alias = 1;
+ break;
+ case 'h':
+ usage();
+ return 0;
+ case 'i':
+ show_inverted = 1;
+ break;
+ case 'n':
+ show_numa = 1;
+ break;
+ case 'o':
+ show_ops = 1;
+ break;
+ case 'r':
+ show_report = 1;
+ break;
+ case 's':
+ shrink = 1;
+ break;
+ case 'l':
+ show_slab = 1;
+ break;
+ case 't':
+ show_track = 1;
+ break;
+ case 'v':
+ validate = 1;
+ break;
+ case 'z':
+ skip_zero = 0;
+ break;
+ case 'T':
+ show_totals = 1;
+ break;
+ case 'S':
+ sort_size = 1;
+ break;
+
+ default:
+ fatal("%s: Invalid option '%c'\n", argv[0], optopt);
+
+ }
+
+ if (!show_slab && !show_alias && !show_track && !show_report
+ && !validate && !shrink && !set_debug && !show_ops)
+ show_slab = 1;
+
+ if (argc > optind)
+ pattern_source = argv[optind];
+ else
+ pattern_source = ".*";
+
+ err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
+ if (err)
+ fatal("%s: Invalid pattern '%s' code %d\n",
+ argv[0], pattern_source, err);
+ read_slab_dir();
+ if (show_alias)
+ alias();
+ else
+ if (show_totals)
+ totals();
+ else {
+ link_slabs();
+ rename_slabs();
+ sort_slabs();
+ output_slabs();
+ }
+ return 0;
+}
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
new file mode 100644
index 00000000000..727c8d81aea
--- /dev/null
+++ b/Documentation/vm/slub.txt
@@ -0,0 +1,113 @@
+Short users guide for SLUB
+--------------------------
+
+First of all slub should transparently replace SLAB. If you enable
+SLUB then everything should work the same (Note the word "should".
+There is likely not much value in that word at this point).
+
+The basic philosophy of SLUB is very different from SLAB. SLAB
+requires rebuilding the kernel to activate debug options for all
+SLABS. SLUB always includes full debugging but its off by default.
+SLUB can enable debugging only for selected slabs in order to avoid
+an impact on overall system performance which may make a bug more
+difficult to find.
+
+In order to switch debugging on one can add a option "slub_debug"
+to the kernel command line. That will enable full debugging for
+all slabs.
+
+Typically one would then use the "slabinfo" command to get statistical
+data and perform operation on the slabs. By default slabinfo only lists
+slabs that have data in them. See "slabinfo -h" for more options when
+running the command. slabinfo can be compiled with
+
+gcc -o slabinfo Documentation/vm/slabinfo.c
+
+Some of the modes of operation of slabinfo require that slub debugging
+be enabled on the command line. F.e. no tracking information will be
+available without debugging on and validation can only partially
+be performed if debugging was not switched on.
+
+Some more sophisticated uses of slub_debug:
+-------------------------------------------
+
+Parameters may be given to slub_debug. If none is specified then full
+debugging is enabled. Format:
+
+slub_debug=<Debug-Options> Enable options for all slabs
+slub_debug=<Debug-Options>,<slab name>
+ Enable options only for select slabs
+
+Possible debug options are
+ F Sanity checks on (enables SLAB_DEBUG_FREE. Sorry
+ SLAB legacy issues)
+ Z Red zoning
+ P Poisoning (object and padding)
+ U User tracking (free and alloc)
+ T Trace (please only use on single slabs)
+
+F.e. in order to boot just with sanity checks and red zoning one would specify:
+
+ slub_debug=FZ
+
+Trying to find an issue in the dentry cache? Try
+
+ slub_debug=,dentry_cache
+
+to only enable debugging on the dentry cache.
+
+Red zoning and tracking may realign the slab. We can just apply sanity checks
+to the dentry cache with
+
+ slub_debug=F,dentry_cache
+
+In case you forgot to enable debugging on the kernel command line: It is
+possible to enable debugging manually when the kernel is up. Look at the
+contents of:
+
+/sys/slab/<slab name>/
+
+Look at the writable files. Writing 1 to them will enable the
+corresponding debug option. All options can be set on a slab that does
+not contain objects. If the slab already contains objects then sanity checks
+and tracing may only be enabled. The other options may cause the realignment
+of objects.
+
+Careful with tracing: It may spew out lots of information and never stop if
+used on the wrong slab.
+
+SLAB Merging
+------------
+
+If no debugging is specified then SLUB may merge similar slabs together
+in order to reduce overhead and increase cache hotness of objects.
+slabinfo -a displays which slabs were merged together.
+
+Getting more performance
+------------------------
+
+To some degree SLUB's performance is limited by the need to take the
+list_lock once in a while to deal with partial slabs. That overhead is
+governed by the order of the allocation for each slab. The allocations
+can be influenced by kernel parameters:
+
+slub_min_objects=x (default 8)
+slub_min_order=x (default 0)
+slub_max_order=x (default 4)
+
+slub_min_objects allows to specify how many objects must at least fit
+into one slab in order for the allocation order to be acceptable.
+In general slub will be able to perform this number of allocations
+on a slab without consulting centralized resources (list_lock) where
+contention may occur.
+
+slub_min_order specifies a minim order of slabs. A similar effect like
+slub_min_objects.
+
+slub_max_order specified the order at which slub_min_objects should no
+longer be checked. This is useful to avoid SLUB trying to generate
+super large order pages to fit slub_min_objects of a slab cache with
+large object sizes into one high order page.
+
+
+Christoph Lameter, <clameter@sgi.com>, April 10, 2007
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 85f51e5a749..6177d881983 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -149,7 +149,19 @@ NUMA
numa=noacpi Don't parse the SRAT table for NUMA setup
- numa=fake=X Fake X nodes and ignore NUMA setup of the actual machine.
+ numa=fake=CMDLINE
+ If a number, fakes CMDLINE nodes and ignores NUMA setup of the
+ actual machine. Otherwise, system memory is configured
+ depending on the sizes and coefficients listed. For example:
+ numa=fake=2*512,1024,4*256,*128
+ gives two 512M nodes, a 1024M node, four 256M nodes, and the
+ rest split into 128M chunks. If the last character of CMDLINE
+ is a *, the remaining memory is divided up equally among its
+ coefficient:
+ numa=fake=2*512,2*
+ gives two 512M nodes and the rest split into two nodes.
+ Otherwise, the remaining system RAM is allocated to an
+ additional node.
numa=hotadd=percent
Only allow hotadd memory to preallocate page structures upto
diff --git a/Documentation/x86_64/fake-numa-for-cpusets b/Documentation/x86_64/fake-numa-for-cpusets
new file mode 100644
index 00000000000..d1a985c5b00
--- /dev/null
+++ b/Documentation/x86_64/fake-numa-for-cpusets
@@ -0,0 +1,66 @@
+Using numa=fake and CPUSets for Resource Management
+Written by David Rientjes <rientjes@cs.washington.edu>
+
+This document describes how the numa=fake x86_64 command-line option can be used
+in conjunction with cpusets for coarse memory management. Using this feature,
+you can create fake NUMA nodes that represent contiguous chunks of memory and
+assign them to cpusets and their attached tasks. This is a way of limiting the
+amount of system memory that are available to a certain class of tasks.
+
+For more information on the features of cpusets, see Documentation/cpusets.txt.
+There are a number of different configurations you can use for your needs. For
+more information on the numa=fake command line option and its various ways of
+configuring fake nodes, see Documentation/x86_64/boot-options.txt.
+
+For the purposes of this introduction, we'll assume a very primitive NUMA
+emulation setup of "numa=fake=4*512,". This will split our system memory into
+four equal chunks of 512M each that we can now use to assign to cpusets. As
+you become more familiar with using this combination for resource control,
+you'll determine a better setup to minimize the number of nodes you have to deal
+with.
+
+A machine may be split as follows with "numa=fake=4*512," as reported by dmesg:
+
+ Faking node 0 at 0000000000000000-0000000020000000 (512MB)
+ Faking node 1 at 0000000020000000-0000000040000000 (512MB)
+ Faking node 2 at 0000000040000000-0000000060000000 (512MB)
+ Faking node 3 at 0000000060000000-0000000080000000 (512MB)
+ ...
+ On node 0 totalpages: 130975
+ On node 1 totalpages: 131072
+ On node 2 totalpages: 131072
+ On node 3 totalpages: 131072
+
+Now following the instructions for mounting the cpusets filesystem from
+Documentation/cpusets.txt, you can assign fake nodes (i.e. contiguous memory
+address spaces) to individual cpusets:
+
+ [root@xroads /]# mkdir exampleset
+ [root@xroads /]# mount -t cpuset none exampleset
+ [root@xroads /]# mkdir exampleset/ddset
+ [root@xroads /]# cd exampleset/ddset
+ [root@xroads /exampleset/ddset]# echo 0-1 > cpus
+ [root@xroads /exampleset/ddset]# echo 0-1 > mems
+
+Now this cpuset, 'ddset', will only allowed access to fake nodes 0 and 1 for
+memory allocations (1G).
+
+You can now assign tasks to these cpusets to limit the memory resources
+available to them according to the fake nodes assigned as mems:
+
+ [root@xroads /exampleset/ddset]# echo $$ > tasks
+ [root@xroads /exampleset/ddset]# dd if=/dev/zero of=tmp bs=1024 count=1G
+ [1] 13425
+
+Notice the difference between the system memory usage as reported by
+/proc/meminfo between the restricted cpuset case above and the unrestricted
+case (i.e. running the same 'dd' command without assigning it to a fake NUMA
+cpuset):
+ Unrestricted Restricted
+ MemTotal: 3091900 kB 3091900 kB
+ MemFree: 42113 kB 1513236 kB
+
+This allows for coarse memory management for the tasks you assign to particular
+cpusets. Since cpusets can form a hierarchy, you can create some pretty
+interesting combinations of use-cases for various classes of tasks for your
+memory management needs.
diff --git a/Documentation/x86_64/machinecheck b/Documentation/x86_64/machinecheck
index 068a6d9904b..feaeaf6f6e4 100644
--- a/Documentation/x86_64/machinecheck
+++ b/Documentation/x86_64/machinecheck
@@ -36,7 +36,12 @@ between all CPUs.
check_interval
How often to poll for corrected machine check errors, in seconds
- (Note output is hexademical). Default 5 minutes.
+ (Note output is hexademical). Default 5 minutes. When the poller
+ finds MCEs it triggers an exponential speedup (poll more often) on
+ the polling interval. When the poller stops finding MCEs, it
+ triggers an exponential backoff (poll less often) on the polling
+ interval. The check_interval variable is both the initial and
+ maximum polling interval.
tolerant
Tolerance level. When a machine check exception occurs for a non
diff --git a/Kbuild b/Kbuild
index 0451f69353b..163f8cb020a 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2,6 +2,7 @@
# Kbuild for top-level directory of the kernel
# This file takes care of the following:
# 1) Generate asm-offsets.h
+# 2) Check for missing system calls
#####
# 1) Generate asm-offsets.h
@@ -46,3 +47,13 @@ $(obj)/$(offsets-file): arch/$(ARCH)/kernel/asm-offsets.s Kbuild
$(Q)mkdir -p $(dir $@)
$(call cmd,offsets)
+#####
+# 2) Check for missing system calls
+#
+
+quiet_cmd_syscalls = CALL $<
+ cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags)
+
+PHONY += missing-syscalls
+missing-syscalls: scripts/checksyscalls.sh FORCE
+ $(call cmd,syscalls)
diff --git a/MAINTAINERS b/MAINTAINERS
index 036e31f1d89..cfd26ddccd7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -382,6 +382,12 @@ L: linux-laptop@vger.kernel.org
W: http://www.canb.auug.org.au/~sfr/
S: Supported
+APPLE SMC DRIVER
+P: Nicolas Boichat
+M: nicolas@boichat.ch
+L: mactel-linux-devel@lists.sourceforge.net
+S: Maintained
+
APPLETALK NETWORK LAYER
P: Arnaldo Carvalho de Melo
M: acme@ghostprotocols.net
@@ -673,6 +679,7 @@ AUXILIARY DISPLAY DRIVERS
P: Miguel Ojeda Sandonis
M: maxextreme@gmail.com
L: linux-kernel@vger.kernel.org
+W: http://auxdisplay.googlepages.com/
S: Maintained
AVR32 ARCHITECTURE
@@ -700,6 +707,44 @@ P: Richard Purdie
M: rpurdie@rpsys.net
S: Maintained
+BLACKFIN ARCHITECTURE
+P: Aubrey Li
+M: aubrey.li@analog.com
+P: Bernd Schmidt
+M: bernd.schmidt@analog.com
+P: Bryan Wu
+M: bryan.wu@analog.com
+P: Grace Pan
+M: grace.pan@analog.com
+P: Michael Hennerich
+M: michael.hennerich@analog.com
+P: Mike Frysinger
+M: michael.frysinger@analog.com
+P: Jane Lv
+M: jane.lv@analog.com
+P: Jerry Zeng
+M: jerry.zeng@analog.com
+P: Jie Zhang
+M: jie.zhang@analog.com
+P: Robin Getz
+M: robin.getz@analog.com
+P: Roy Huang
+M: roy.huang@analog.com
+P: Sonic Zhang
+M: sonic.zhang@analog.com
+P: Yi Li
+M: yi.li@analog.com
+L: uclinux-dist-devel@blackfin.uclinux.org
+W: http://blackfin.uclinux.org
+S: Supported
+
+BLACKFIN SERIAL DRIVER
+P: Aubrey Li
+M: aubrey.li@analog.com
+L: uclinux-dist-devel@blackfin.uclinux.org
+W: http://blackfin.uclinux.org
+S: Supported
+
BAYCOM/HDLCDRV DRIVERS FOR AX.25
P: Thomas Sailer
M: t.sailer@alumni.ethz.ch
@@ -733,6 +778,13 @@ M: tigran@aivazian.fsnet.co.uk
L: linux-kernel@vger.kernel.org
S: Maintained
+BLACKFIN I2C TWI DRIVER
+P: Sonic Zhang
+M: sonic.zhang@analog.com
+L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
+W: http://blackfin.uclinux.org/
+S: Supported
+
BLOCK LAYER
P: Jens Axboe
M: axboe@kernel.dk
@@ -892,12 +944,14 @@ CFAG12864B LCD DRIVER
P: Miguel Ojeda Sandonis
M: maxextreme@gmail.com
L: linux-kernel@vger.kernel.org
+W: http://auxdisplay.googlepages.com/
S: Maintained
CFAG12864BFB LCD FRAMEBUFFER DRIVER
P: Miguel Ojeda Sandonis
M: maxextreme@gmail.com
L: linux-kernel@vger.kernel.org
+W: http://auxdisplay.googlepages.com/
S: Maintained
CFG80211 and NL80211
@@ -984,6 +1038,14 @@ S: Maintained
CONEXANT ACCESSRUNNER USB DRIVER
P: Simon Arlott
M: cxacru@fire.lp0.eu
+L: accessrunner-general@lists.sourceforge.net
+W: http://accessrunner.sourceforge.net/
+S: Maintained
+
+CORETEMP HARDWARE MONITORING DRIVER
+P: Rudolf Marek
+M: r.marek@assembler.cz
+L: lm-sensors@lm-sensors.org
S: Maintained
COSA/SRP SYNC SERIAL DRIVER
@@ -1459,6 +1521,11 @@ L: linux-scsi@vger.kernel.org
W: http://www.icp-vortex.com/
S: Supported
+GENERIC GPIO I2C DRIVER
+P: Haavard Skinnemoen
+M: hskinnemoen@atmel.com
+S: Supported
+
GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS
P: Krzysztof Halasa
M: khc@pm.waw.pl
@@ -1582,9 +1649,9 @@ S: Supported
HOST AP DRIVER
P: Jouni Malinen
-M: jkmaline@cc.hut.fi
+M: j@w1.fi
+L: hostap@shmoo.com (subscribers-only)
L: linux-wireless@vger.kernel.org
-L: hostap@shmoo.com
W: http://hostap.epitest.fi/
S: Maintained
@@ -1605,7 +1672,7 @@ S: Maintained
HPET: x86_64
P: Andi Kleen and Vojtech Pavlik
-M: ak@muc.de and vojtech@suse.cz
+M: andi@firstfloor.org and vojtech@suse.cz
S: Maintained
HPET: ACPI hpet.c
@@ -1631,6 +1698,13 @@ L: i2c@lm-sensors.org
T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/
S: Maintained
+I2C-TINY-USB DRIVER
+P: Till Harbaum
+M: till@harbaum.org
+L: i2c@lm-sensors.org
+T: http://www.harbaum.org/till/i2c_tiny_usb
+S: Maintained
+
i386 BOOT CODE
P: Riley H. Williams
M: Riley@Williams.Name
@@ -1658,15 +1732,6 @@ W: http://www.ia64-linux.org/
T: git kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
S: Maintained
-IBM ACPI EXTRAS DRIVER
-P: Henrique de Moraes Holschuh
-M: ibm-acpi@hmh.eng.br
-L: ibm-acpi-devel@lists.sourceforge.net
-W: http://ibm-acpi.sourceforge.net
-W: http://thinkwiki.org/wiki/Ibm-acpi
-T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
-S: Maintained
-
SN-IA64 (Itanium) SUB-PLATFORM
P: Jes Sorensen
M: jes@sgi.com
@@ -1820,6 +1885,7 @@ P: Jeff Kirsher
M: jeffrey.t.kirsher@intel.com
P: Auke Kok
M: auke-jan.h.kok@intel.com
+L: e1000-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/e1000/
S: Supported
@@ -1834,6 +1900,7 @@ P: Jeff Kirsher
M: jeffrey.t.kirsher@intel.com
P: Auke Kok
M: auke-jan.h.kok@intel.com
+L: e1000-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/e1000/
S: Supported
@@ -1848,6 +1915,7 @@ P: Jesse Brandeburg
M: jesse.brandeburg@intel.com
P: Auke Kok
M: auke-jan.h.kok@intel.com
+L: e1000-devel@lists.sourceforge.net
W: http://sourceforge.net/projects/e1000/
S: Supported
@@ -1970,7 +2038,7 @@ P: Vivek Goyal
M: vgoyal@in.ibm.com
P: Haren Myneni
M: hbabu@us.ibm.com
-L: fastboot@lists.linux-foundation.org
+L: kexec@lists.infradead.org
L: linux-kernel@vger.kernel.org
W: http://lse.sourceforge.net/kdump/
S: Maintained
@@ -2020,7 +2088,7 @@ P: Eric Biederman
M: ebiederm@xmission.com
W: http://www.xmission.com/~ebiederm/files/kexec/
L: linux-kernel@vger.kernel.org
-L: fastboot@lists.linux-foundation.org
+L: kexec@lists.infradead.org
S: Maintained
KPROBES
@@ -2039,6 +2107,7 @@ KS0108 LCD CONTROLLER DRIVER
P: Miguel Ojeda Sandonis
M: maxextreme@gmail.com
L: linux-kernel@vger.kernel.org
+W: http://auxdisplay.googlepages.com/
S: Maintained
LAPB module
@@ -2215,6 +2284,16 @@ M: philb@gnu.org
W: http://www.tazenda.demon.co.uk/phil/linux-hp
S: Maintained
+MAC80211
+P: Jiri Benc
+M: jbenc@suse.cz
+P: Michael Wu
+M: flamingice@sourmilk.net
+L: linux-wireless@vger.kernel.org
+W: http://linuxwireless.org/
+T: git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git
+S: Maintained
+
MARVELL YUKON / SYSKONNECT DRIVER
P: Mirko Lindner
M: mlindner@syskonnect.de
@@ -2243,6 +2322,12 @@ M: vandrove@vc.cvut.cz
L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
+MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
+P: Hans J. Koch
+M: hjk@linutronix.de
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
MEGARAID SCSI DRIVERS
P: Neela Syam Kolli
M: Neela.Kolli@engenio.com
@@ -2509,6 +2594,19 @@ M: adaplas@gmail.com
L: linux-fbdev-devel@lists.sourceforge.net (subscribers-only)
S: Maintained
+NETERION (S2IO) Xframe 10GbE DRIVER
+P: Ramkrishna Vepa
+M: ram.vepa@neterion.com
+P: Rastapur Santosh
+M: santosh.rastapur@neterion.com
+P: Sivakumar Subramani
+M: sivakumar.subramani@neterion.com
+P: Sreenivasa Honnur
+M: sreenivasa.honnur@neterion.com
+L: netdev@vger.kernel.org
+W: http://trac.neterion.com/cgi-bin/trac.cgi/wiki/TitleIndex?anonymous
+S: Supported
+
OPENCORES I2C BUS DRIVER
P: Peter Korsgaard
M: jacmet@sunsite.dk
@@ -2622,6 +2720,19 @@ T: git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
T: cvs cvs.parisc-linux.org:/var/cvs/linux-2.6
S: Maintained
+PARAVIRT_OPS INTERFACE
+P: Jeremy Fitzhardinge
+M: jeremy@xensource.com
+P: Chris Wright
+M: chrisw@sous-sol.org
+P: Zachary Amsden
+M: zach@vmware.com
+P: Rusty Russell
+M: rusty@rustcorp.com.au
+L: virtualization@lists.osdl.org
+L: linux-kernel@vger.kernel.org
+S: Supported
+
PC87360 HARDWARE MONITORING DRIVER
P: Jim Cromie
M: jim.cromie@gmail.com
@@ -2697,7 +2808,7 @@ L: linux-abi-devel@lists.sourceforge.net
S: Maintained
PHRAM MTD DRIVER
-P: Jörn Engel
+P: Jörn Engel
M: joern@wh.fh-wedel.de
L: linux-mtd@lists.infradead.org
S: Maintained
@@ -2971,7 +3082,7 @@ T: git kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
S: Maintained
SCSI TAPE DRIVER
-P: Kai Mäkisara
+P: Kai Mäkisara
M: Kai.Makisara@kolumbus.fi
L: linux-scsi@vger.kernel.org
S: Maintained
@@ -3017,6 +3128,11 @@ L: selinux@tycho.nsa.gov (subscribers-only, general discussion)
W: http://www.nsa.gov/selinux
S: Supported
+SENSABLE PHANTOM
+P: Jiri Slaby
+M: jirislaby@gmail.com
+S: Maintained
+
SERIAL ATA (SATA) SUBSYSTEM:
P: Jeff Garzik
M: jgarzik@pobox.com
@@ -3172,6 +3288,15 @@ P: Chris Zankel
M: chris@zankel.net
S: Maintained
+THINKPAD ACPI EXTRAS DRIVER
+P: Henrique de Moraes Holschuh
+M: ibm-acpi@hmh.eng.br
+L: ibm-acpi-devel@lists.sourceforge.net
+W: http://ibm-acpi.sourceforge.net
+W: http://thinkwiki.org/wiki/Ibm-acpi
+T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
+S: Maintained
+
UltraSPARC (sparc64):
P: David S. Miller
M: davem@davemloft.net
@@ -3617,8 +3742,8 @@ W: http://www.kroah.com/linux/
S: Maintained
USB SERIAL WHITEHEAT DRIVER
-P: Stuart MacDonald
-M: stuartm@connecttech.com
+P: Support Department
+M: support@connecttech.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
W: http://www.connecttech.com
@@ -3837,6 +3962,15 @@ M: eis@baty.hanse.de
L: linux-x25@vger.kernel.org
S: Maintained
+XEN HYPERVISOR INTERFACE
+P: Jeremy Fitzhardinge
+M: jeremy@xensource.com
+P: Chris Wright
+M: chrisw@sous-sol.org
+L: virtualization@lists.osdl.org
+L: xen-devel@lists.xensource.com
+S: Supported
+
XFS FILESYSTEM
P: Silicon Graphics Inc
P: Tim Shimmin, David Chatterton
diff --git a/Makefile b/Makefile
index d970cb16545..dfe559c89fe 100644
--- a/Makefile
+++ b/Makefile
@@ -491,7 +491,7 @@ endif
include $(srctree)/arch/$(ARCH)/Makefile
ifdef CONFIG_FRAME_POINTER
-CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
else
CFLAGS += -fomit-frame-pointer
endif
@@ -576,7 +576,7 @@ libs-y := $(libs-y1) $(libs-y2)
# ---------------------------------------------------------------------------
# vmlinux is built from the objects selected by $(vmlinux-init) and
# $(vmlinux-main). Most are built-in.o files from top-level directories
-# in the kernel tree, others are specified in arch/$(ARCH)Makefile.
+# in the kernel tree, others are specified in arch/$(ARCH)/Makefile.
# Ordering when linking is important, and $(vmlinux-init) must be first.
#
# vmlinux
@@ -603,6 +603,7 @@ vmlinux-init := $(head-y) $(init-y)
vmlinux-main := $(core-y) $(libs-y) $(drivers-y) $(net-y)
vmlinux-all := $(vmlinux-init) $(vmlinux-main)
vmlinux-lds := arch/$(ARCH)/kernel/vmlinux.lds
+export KBUILD_VMLINUX_OBJS := $(vmlinux-all)
# Rule to link vmlinux - also used during CONFIG_KALLSYMS
# May be overridden by arch/$(ARCH)/Makefile
@@ -855,6 +856,7 @@ archprepare: prepare1 scripts_basic
prepare0: archprepare FORCE
$(Q)$(MAKE) $(build)=.
+ $(Q)$(MAKE) $(build)=. missing-syscalls
# All the preparing..
prepare: prepare0
@@ -1277,10 +1279,7 @@ endif
ALLSOURCE_ARCHS := $(ARCH)
define find-sources
- ( find $(__srctree) $(RCS_FIND_IGNORE) \
- \( -name include -o -name arch \) -prune -o \
- -name $1 -print; \
- for ARCH in $(ALLSOURCE_ARCHS) ; do \
+ ( for ARCH in $(ALLSOURCE_ARCHS) ; do \
find $(__srctree)arch/$${ARCH} $(RCS_FIND_IGNORE) \
-name $1 -print; \
done ; \
@@ -1294,7 +1293,11 @@ define find-sources
-name $1 -print; \
done ; \
find $(__srctree)include/asm-generic $(RCS_FIND_IGNORE) \
- -name $1 -print )
+ -name $1 -print; \
+ find $(__srctree) $(RCS_FIND_IGNORE) \
+ \( -name include -o -name arch \) -prune -o \
+ -name $1 -print; \
+ )
endef
define all-sources
diff --git a/arch/alpha/Kconfig.debug b/arch/alpha/Kconfig.debug
index 36d0106c32e..f45f28cc10d 100644
--- a/arch/alpha/Kconfig.debug
+++ b/arch/alpha/Kconfig.debug
@@ -16,14 +16,6 @@ config DEBUG_RWLOCK
too many attempts. If you suspect a rwlock problem or a kernel
hacker asks for this option then say Y. Otherwise say N.
-config DEBUG_SEMAPHORE
- bool "Semaphore debugging"
- depends on DEBUG_KERNEL
- help
- If you say Y here then semaphore processing will issue lots of
- verbose debugging messages. If you suspect a semaphore problem or a
- kernel hacker asks for this option then say Y. Otherwise say N.
-
config ALPHA_LEGACY_START_ADDRESS
bool "Legacy kernel start address"
depends on ALPHA_GENERIC
diff --git a/arch/alpha/boot/bootpz.c b/arch/alpha/boot/bootpz.c
index 4307bde80a3..1036b515e20 100644
--- a/arch/alpha/boot/bootpz.c
+++ b/arch/alpha/boot/bootpz.c
@@ -467,3 +467,9 @@ start_kernel(void)
#endif
runkernel();
}
+
+ /* dummy function, should never be called. */
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ return (void *)NULL;
+}
diff --git a/arch/alpha/boot/misc.c b/arch/alpha/boot/misc.c
index 1d65adf5691..c00646b25f6 100644
--- a/arch/alpha/boot/misc.c
+++ b/arch/alpha/boot/misc.c
@@ -98,7 +98,7 @@ extern int end;
static ulg free_mem_ptr;
static ulg free_mem_ptr_end;
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
#include "../../../lib/inflate.c"
diff --git a/arch/alpha/boot/tools/objstrip.c b/arch/alpha/boot/tools/objstrip.c
index 67beb1b45e4..96154e768a2 100644
--- a/arch/alpha/boot/tools/objstrip.c
+++ b/arch/alpha/boot/tools/objstrip.c
@@ -25,7 +25,6 @@
#include <linux/a.out.h>
#include <linux/coff.h>
#include <linux/param.h>
-#include <linux/string.h>
#ifdef __ELF__
# include <linux/elf.h>
#endif
diff --git a/arch/alpha/kernel/err_common.c b/arch/alpha/kernel/err_common.c
index 687580b16b4..13d53b1c965 100644
--- a/arch/alpha/kernel/err_common.c
+++ b/arch/alpha/kernel/err_common.c
@@ -7,7 +7,6 @@
*/
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/sched.h>
#include <asm/io.h>
diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
index 69b5f4ea735..11aee012a8a 100644
--- a/arch/alpha/kernel/err_ev6.c
+++ b/arch/alpha/kernel/err_ev6.c
@@ -7,7 +7,6 @@
*/
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/sched.h>
#include <asm/io.h>
diff --git a/arch/alpha/kernel/err_ev7.c b/arch/alpha/kernel/err_ev7.c
index 95463ab1cf3..bc799f72d8c 100644
--- a/arch/alpha/kernel/err_ev7.c
+++ b/arch/alpha/kernel/err_ev7.c
@@ -7,7 +7,6 @@
*/
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/sched.h>
#include <asm/io.h>
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index be133f1f75a..ce857158c1e 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -93,7 +93,6 @@ osf_set_program_attributes(unsigned long text_start, unsigned long text_len,
* offset differences aren't the same as "d_reclen").
*/
#define NAME_OFFSET offsetof (struct osf_dirent, d_name)
-#define ROUND_UP(x) (((x)+3) & ~3)
struct osf_dirent {
unsigned int d_ino;
@@ -115,7 +114,7 @@ osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
{
struct osf_dirent __user *dirent;
struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
- unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
+ unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));
unsigned int d_ino;
buf->error = -EINVAL; /* only used if we fail */
@@ -174,7 +173,6 @@ osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent,
return error;
}
-#undef ROUND_UP
#undef NAME_OFFSET
asmlinkage unsigned long
@@ -955,15 +953,25 @@ osf_setitimer(int which, struct itimerval32 __user *in, struct itimerval32 __use
asmlinkage int
osf_utimes(char __user *filename, struct timeval32 __user *tvs)
{
- struct timeval ktvs[2];
+ struct timespec tv[2];
if (tvs) {
+ struct timeval ktvs[2];
if (get_tv32(&ktvs[0], &tvs[0]) ||
get_tv32(&ktvs[1], &tvs[1]))
return -EFAULT;
+
+ if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
+ ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
+ return -EINVAL;
+
+ tv[0].tv_sec = ktvs[0].tv_sec;
+ tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
+ tv[1].tv_sec = ktvs[1].tv_sec;
+ tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
}
- return do_utimes(AT_FDCWD, filename, tvs ? ktvs : NULL);
+ return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
}
#define MAX_SELECT_SECONDS \
@@ -1267,6 +1275,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (len > limit)
return -ENOMEM;
+ if (flags & MAP_FIXED)
+ return addr;
+
/* First, see if the given suggestion fits.
The OSF/1 loader (/sbin/loader) relies on us returning an
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index c1518639069..92b61629fe3 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index d352c2b05f1..915f26345c4 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -744,15 +744,6 @@ setup_arch(char **cmdline_p)
paging_init();
}
-void __init
-disable_early_printk(void)
-{
- if (alpha_using_srm && srmcons_output) {
- unregister_srm_console();
- srmcons_output = 0;
- }
-}
-
static char sys_unknown[] = "Unknown";
static char systype_names[][16] = {
"0",
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 741da0945dc..7f64aa767d5 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -15,7 +15,6 @@
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index d1ec4f51df1..80cfb758ee2 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -18,7 +18,6 @@
#include <linux/mm.h>
#include <linux/threads.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 75692320386..930cedc8be2 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -164,9 +164,9 @@ srmcons_get_private_struct(struct srmcons_private **ps)
int retval = 0;
if (srmconsp == NULL) {
+ srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
spin_lock_irqsave(&srmconsp_lock, flags);
- srmconsp = kmalloc(sizeof(*srmconsp), GFP_KERNEL);
if (srmconsp == NULL)
retval = -ENOMEM;
else {
@@ -300,7 +300,7 @@ static struct console srmcons = {
.write = srm_console_write,
.device = srm_console_device,
.setup = srm_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 4cc44bd33d3..cf1e6fc6c68 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -69,7 +69,7 @@ SECTIONS
. = ALIGN(8);
SECURITY_INIT
- . = ALIGN(64);
+ . = ALIGN(8192);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index 8aa9db834c1..f5862792a16 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -21,7 +21,6 @@
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e7baca29f3f..d7c0984d4a8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -29,6 +29,10 @@ config GENERIC_TIME
bool
default n
+config GENERIC_CLOCKEVENTS
+ bool
+ default n
+
config MMU
bool
default y
@@ -67,6 +71,14 @@ config GENERIC_HARDIRQS
bool
default y
+config STACKTRACE_SUPPORT
+ bool
+ default y
+
+config LOCKDEP_SUPPORT
+ bool
+ default y
+
config TRACE_IRQFLAGS_SUPPORT
bool
default y
@@ -162,6 +174,8 @@ config ARCH_VERSATILE
select ARM_AMBA
select ARM_VIC
select ICST307
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
help
This enables support for ARM Ltd Versatile board.
@@ -255,6 +269,7 @@ config ARCH_IOP13XX
depends on MMU
select PLAT_IOP
select PCI
+ select ARCH_SUPPORTS_MSI
help
Support for Intel's IOP13XX (XScale) family of processors.
@@ -262,6 +277,7 @@ config ARCH_IXP4XX
bool "IXP4xx-based"
depends on MMU
select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
help
Support for Intel's IXP4XX (XScale) family of processors.
@@ -338,6 +354,7 @@ config ARCH_SA1100
config ARCH_S3C2410
bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
select GENERIC_GPIO
+ select GENERIC_TIME
help
Samsung S3C2410X CPU based systems, such as the Simtec Electronics
BAST (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or
@@ -363,6 +380,7 @@ config ARCH_LH7A40X
config ARCH_OMAP
bool "TI OMAP"
select GENERIC_GPIO
+ select GENERIC_TIME
help
Support for TI's OMAP platform (OMAP1 and OMAP2).
@@ -513,6 +531,8 @@ endmenu
menu "Kernel Features"
+source "kernel/time/Kconfig"
+
config SMP
bool "Symmetric Multi-Processing (EXPERIMENTAL)"
depends on EXPERIMENTAL && REALVIEW_MPCORE
@@ -572,6 +592,7 @@ config PREEMPT
config NO_IDLE_HZ
bool "Dynamic tick timer"
+ depends on !GENERIC_CLOCKEVENTS
help
Select this option if you want to disable continuous timer ticks
and have them programmed to occur as required. This option saves
@@ -669,6 +690,7 @@ config LEDS_TIMER
bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
MACH_OMAP_H2 || MACH_OMAP_PERSEUS2
depends on LEDS
+ depends on !GENERIC_CLOCKEVENTS
default y if ARCH_EBSA110
help
If you say Y here, one of the system LEDs (the green one on the
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index ab9f2d4bd04..00ea4305ad5 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -47,8 +47,13 @@ comma = ,
# Note that GCC does not numerically define an architecture version
# macro, but instead defines a whole series of macros which makes
# testing for a specific architecture or later rather impossible.
+arch-$(CONFIG_CPU_32v7) :=-D__LINUX_ARM_ARCH__=7 $(call cc-option,-march=armv7a,-march=armv5t -Wa$(comma)-march=armv7a)
arch-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6,-march=armv5t -Wa$(comma)-march=armv6)
+# Only override the compiler option if ARMv6. The ARMv6K extensions are
+# always available in ARMv7
+ifeq ($(CONFIG_CPU_32v6),y)
arch-$(CONFIG_CPU_32v6K) :=-D__LINUX_ARM_ARCH__=6 $(call cc-option,-march=armv6k,-march=armv5t -Wa$(comma)-march=armv6k)
+endif
arch-$(CONFIG_CPU_32v5) :=-D__LINUX_ARM_ARCH__=5 $(call cc-option,-march=armv5te,-march=armv4t)
arch-$(CONFIG_CPU_32v4T) :=-D__LINUX_ARM_ARCH__=4 -march=armv4t
arch-$(CONFIG_CPU_32v4) :=-D__LINUX_ARM_ARCH__=4 -march=armv4
diff --git a/arch/arm/boot/compressed/head-at91rm9200.S b/arch/arm/boot/compressed/head-at91rm9200.S
index d68b9acd826..11782ccd93a 100644
--- a/arch/arm/boot/compressed/head-at91rm9200.S
+++ b/arch/arm/boot/compressed/head-at91rm9200.S
@@ -61,6 +61,12 @@
cmp r7, r3
beq 99f
+ @ picotux 200 : 963
+ mov r3, #(MACH_TYPE_PICOTUX2XX & 0xff)
+ orr r3, r3, #(MACH_TYPE_PICOTUX2XX & 0xff00)
+ cmp r7, r3
+ beq 99f
+
@ Ajeco 1ARM : 1075
mov r3, #(MACH_TYPE_ONEARM & 0xff)
orr r3, r3, #(MACH_TYPE_ONEARM & 0xff00)
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 283891c736c..9b444022cb9 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -239,7 +239,7 @@ extern int end;
static ulg free_mem_ptr;
static ulg free_mem_ptr_end;
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
#include "../../../../lib/inflate.c"
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index fe3f05901a2..798bbfccafb 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index a9bc5b52218..5972df2b9af 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -766,10 +766,10 @@ static void sharpsl_apm_get_power_status(struct apm_power_info *info)
}
static struct pm_ops sharpsl_pm_ops = {
- .pm_disk_mode = PM_DISK_FIRMWARE,
.prepare = pxa_pm_prepare,
.enter = corgi_pxa_pm_enter,
.finish = pxa_pm_finish,
+ .valid = pm_valid_only_mem,
};
static int __init sharpsl_pm_probe(struct platform_device *pdev)
diff --git a/arch/arm/common/via82c505.c b/arch/arm/common/via82c505.c
index ba2e62986a5..79a8206e62a 100644
--- a/arch/arm/common/via82c505.c
+++ b/arch/arm/common/via82c505.c
@@ -1,6 +1,5 @@
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig
index fabf74c51a8..db850a5689e 100644
--- a/arch/arm/configs/ixp4xx_defconfig
+++ b/arch/arm/configs/ixp4xx_defconfig
@@ -117,11 +117,13 @@ CONFIG_ARCH_ADI_COYOTE=y
CONFIG_ARCH_IXDP425=y
CONFIG_MACH_IXDPG425=y
CONFIG_MACH_IXDP465=y
+CONFIG_MACH_KIXRP435=y
CONFIG_ARCH_IXCDP1100=y
CONFIG_ARCH_PRPMC1100=y
CONFIG_MACH_NAS100D=y
CONFIG_ARCH_IXDP4XX=y
CONFIG_CPU_IXP46X=y
+CONFIG_CPU_IXP43X=y
# CONFIG_MACH_GTWX5715 is not set
#
diff --git a/arch/arm/configs/picotux200_defconfig b/arch/arm/configs/picotux200_defconfig
new file mode 100644
index 00000000000..339c48953a6
--- /dev/null
+++ b/arch/arm/configs/picotux200_defconfig
@@ -0,0 +1,1386 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc4
+# Wed Mar 28 16:19:50 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=m
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_AT91=y
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
+CONFIG_ARCH_AT91RM9200=y
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+# CONFIG_ARCH_AT91SAM9263 is not set
+
+#
+# AT91RM9200 Board Type
+#
+# CONFIG_MACH_ONEARM is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MACH_AT91RM9200EK is not set
+# CONFIG_MACH_CSB337 is not set
+# CONFIG_MACH_CSB637 is not set
+# CONFIG_MACH_CARMEVA is not set
+# CONFIG_MACH_ATEB9200 is not set
+# CONFIG_MACH_KB9200 is not set
+CONFIG_MACH_PICOTUX2XX=y
+# CONFIG_MACH_KAFA is not set
+
+#
+# AT91 Board Options
+#
+
+#
+# AT91 Feature Selections
+#
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4T=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_MISC=m
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x8000000
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_ARM_AT91_ETHER=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_AT91RM9200_WATCHDOG=m
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_AT91=m
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_SENSORS_DS1337=m
+CONFIG_SENSORS_DS1374=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_PCF8574=m
+CONFIG_SENSORS_PCA9539=m
+CONFIG_SENSORS_PCF8591=m
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=m
+CONFIG_HWMON_VID=m
+# CONFIG_SENSORS_ABITUGURU is not set
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM1025=m
+CONFIG_SENSORS_ADM1026=m
+CONFIG_SENSORS_ADM1029=m
+CONFIG_SENSORS_ADM1031=m
+CONFIG_SENSORS_ADM9240=m
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+CONFIG_SENSORS_DS1621=m
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_GL520SM=m
+CONFIG_SENSORS_IT87=m
+CONFIG_SENSORS_LM63=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM77=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_LM83=m
+CONFIG_SENSORS_LM85=m
+CONFIG_SENSORS_LM87=m
+CONFIG_SENSORS_LM90=m
+CONFIG_SENSORS_LM92=m
+CONFIG_SENSORS_MAX1619=m
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+CONFIG_SENSORS_SMSC47B397=m
+# CONFIG_SENSORS_VT1211 is not set
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_W83791D=m
+CONFIG_SENSORS_W83792D=m
+CONFIG_SENSORS_W83793=m
+CONFIG_SENSORS_W83L785TS=m
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=m
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_USBNET_MII=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_NET_AX8817X=m
+CONFIG_USB_NET_CDCETHER=m
+CONFIG_USB_NET_DM9601=m
+CONFIG_USB_NET_GL620A=m
+CONFIG_USB_NET_NET1080=m
+CONFIG_USB_NET_PLUSB=m
+CONFIG_USB_NET_MCS7830=m
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+CONFIG_USB_ALI_M5632=y
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_KC2190=y
+CONFIG_USB_NET_ZAURUS=m
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_AT91=m
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=m
+CONFIG_RTC_INTF_PROC=m
+CONFIG_RTC_INTF_DEV=m
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_AT91RM9200=m
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="utf-8"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=m
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index bb28087bf81..593b56509f4 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -7,8 +7,8 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
# Object file lists.
obj-y := compat.o entry-armv.o entry-common.o irq.o \
- process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \
- time.o traps.o
+ process.o ptrace.o semaphore.o setup.o signal.o \
+ sys_arm.o stacktrace.o time.o traps.o
obj-$(CONFIG_ISA_DMA_API) += dma.o
obj-$(CONFIG_ARCH_ACORN) += ecard.o
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index f1c0fb97417..bdbd7da9928 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -40,6 +40,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/kthread.h>
#include <asm/dma.h>
#include <asm/ecard.h>
@@ -50,6 +51,8 @@
#include <asm/mach/irq.h>
#include <asm/tlbflush.h>
+#include "ecard.h"
+
#ifndef CONFIG_ARCH_RPC
#define HAVE_EXPMASK
#endif
@@ -123,7 +126,7 @@ static void ecard_task_reset(struct ecard_request *req)
res = ec->slot_no == 8
? &ec->resource[ECARD_RES_MEMC]
- : ec->type == ECARD_EASI
+ : ec->easi
? &ec->resource[ECARD_RES_EASI]
: &ec->resource[ECARD_RES_IOCSYNC];
@@ -178,7 +181,7 @@ static void ecard_task_readbytes(struct ecard_request *req)
index += 1;
}
} else {
- unsigned long base = (ec->type == ECARD_EASI
+ unsigned long base = (ec->easi
? &ec->resource[ECARD_RES_EASI]
: &ec->resource[ECARD_RES_IOCSYNC])->start;
void __iomem *pbase = (void __iomem *)base;
@@ -263,8 +266,6 @@ static int ecard_init_mm(void)
static int
ecard_task(void * unused)
{
- daemonize("kecardd");
-
/*
* Allocate a mm. We're not a lazy-TLB kernel task since we need
* to set page table entries where the user space would be. Note
@@ -727,7 +728,7 @@ static int ecard_prints(char *buffer, ecard_t *ec)
char *start = buffer;
buffer += sprintf(buffer, " %d: %s ", ec->slot_no,
- ec->type == ECARD_EASI ? "EASI" : " ");
+ ec->easi ? "EASI" : " ");
if (ec->cid.id == 0) {
struct in_chunk_dir incd;
@@ -814,7 +815,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot)
}
ec->slot_no = slot;
- ec->type = type;
+ ec->easi = type == ECARD_EASI;
ec->irq = NO_IRQ;
ec->fiq = NO_IRQ;
ec->dma = NO_DMA;
@@ -825,6 +826,7 @@ static struct expansion_card *__init ecard_alloc_card(int type, int slot)
ec->dev.bus = &ecard_bus_type;
ec->dev.dma_mask = &ec->dma_mask;
ec->dma_mask = (u64)0xffffffff;
+ ec->dev.coherent_dma_mask = ec->dma_mask;
if (slot < 4) {
ec_set_resource(ec, ECARD_RES_MEMC,
@@ -907,7 +909,7 @@ static ssize_t ecard_show_device(struct device *dev, struct device_attribute *at
static ssize_t ecard_show_type(struct device *dev, struct device_attribute *attr, char *buf)
{
struct expansion_card *ec = ECARD_DEV(dev);
- return sprintf(buf, "%s\n", ec->type == ECARD_EASI ? "EASI" : "IOC");
+ return sprintf(buf, "%s\n", ec->easi ? "EASI" : "IOC");
}
static struct device_attribute ecard_dev_attrs[] = {
@@ -1058,13 +1060,14 @@ ecard_probe(int slot, card_type_t type)
*/
static int __init ecard_init(void)
{
- int slot, irqhw, ret;
-
- ret = kernel_thread(ecard_task, NULL, CLONE_KERNEL);
- if (ret < 0) {
- printk(KERN_ERR "Ecard: unable to create kernel thread: %d\n",
- ret);
- return ret;
+ struct task_struct *task;
+ int slot, irqhw;
+
+ task = kthread_run(ecard_task, NULL, "kecardd");
+ if (IS_ERR(task)) {
+ printk(KERN_ERR "Ecard: unable to create kernel thread: %ld\n",
+ PTR_ERR(task));
+ return PTR_ERR(task);
}
printk("Probing expansion cards\n");
diff --git a/arch/arm/kernel/ecard.h b/arch/arm/kernel/ecard.h
new file mode 100644
index 00000000000..d7c2dacf935
--- /dev/null
+++ b/arch/arm/kernel/ecard.h
@@ -0,0 +1,56 @@
+/*
+ * ecard.h
+ *
+ * Copyright 2007 Russell King
+ *
+ * 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.
+ */
+
+/* Definitions internal to ecard.c - for it's use only!!
+ *
+ * External expansion card header as read from the card
+ */
+struct ex_ecid {
+ unsigned char r_irq:1;
+ unsigned char r_zero:1;
+ unsigned char r_fiq:1;
+ unsigned char r_id:4;
+ unsigned char r_a:1;
+
+ unsigned char r_cd:1;
+ unsigned char r_is:1;
+ unsigned char r_w:2;
+ unsigned char r_r1:4;
+
+ unsigned char r_r2:8;
+
+ unsigned char r_prod[2];
+
+ unsigned char r_manu[2];
+
+ unsigned char r_country;
+
+ unsigned char r_fiqmask;
+ unsigned char r_fiqoff[3];
+
+ unsigned char r_irqmask;
+ unsigned char r_irqoff[3];
+};
+
+/*
+ * Chunk directory entry as read from the card
+ */
+struct ex_chunk_dir {
+ unsigned char r_id;
+ unsigned char r_len[3];
+ unsigned long r_start;
+ union {
+ char string[256];
+ char data[1];
+ } d;
+#define c_id(x) ((x)->r_id)
+#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
+#define c_start(x) ((x)->r_start)
+};
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 0119c0d5f97..5d78ffb8a9a 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -33,7 +33,7 @@
* numbers for r1.
*
*/
- __INIT
+ .section ".text.head", "ax"
.type stext, %function
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 66db0a9bf0b..41f98b4ba2e 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -73,7 +73,7 @@
* crap here - that's what the boot loader (or in extreme, well justified
* circumstances, zImage) is for.
*/
- __INIT
+ .section ".text.head", "ax"
.type stext, %function
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
@@ -257,7 +257,9 @@ __create_page_tables:
* Map some ram to cover our .data and .bss areas.
*/
orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
+ .if (KERNEL_RAM_PADDR & 0x00f00000)
orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
+ .endif
add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
ldr r6, =(_end - 1)
@@ -274,7 +276,9 @@ __create_page_tables:
*/
add r0, r4, #PAGE_OFFSET >> 18
orr r6, r7, #(PHYS_OFFSET & 0xff000000)
- orr r6, r6, #(PHYS_OFFSET & 0x00e00000)
+ .if (PHYS_OFFSET & 0x00f00000)
+ orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
+ .endif
str r6, [r0]
#ifdef CONFIG_DEBUG_LL
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index a00cca0000b..bd4ef53bc6b 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -31,7 +31,7 @@ EXPORT_SYMBOL(init_mm);
* The things we do for performance..
*/
union thread_union init_thread_union
- __attribute__((__section__(".init.task"))) =
+ __attribute__((__section__(".data.init_task"))) =
{ INIT_THREAD_INFO(init_task) };
/*
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index e101846ab7d..11dcd52e51b 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -27,7 +27,6 @@
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
@@ -109,7 +108,7 @@ static struct irq_desc bad_irq_desc = {
* come via this function. Instead, they should provide their
* own 'handler'
*/
-asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
struct irq_desc *desc = irq_desc + irq;
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 1b061583408..79b7e5cf541 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -116,8 +116,8 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
offset += sym->st_value - loc;
if (offset & 3 ||
- offset <= (s32)0xfc000000 ||
- offset >= (s32)0x04000000) {
+ offset <= (s32)0xfe000000 ||
+ offset >= (s32)0x02000000) {
printk(KERN_ERR
"%s: relocation out of range, section "
"%d reloc %d sym '%s'\n", module->name,
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 782af3cb213..5d6e6523598 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -16,7 +16,6 @@
#include <linux/mm.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
-#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/user.h>
#include <linux/a.out.h>
@@ -28,6 +27,7 @@
#include <linux/cpu.h>
#include <linux/elfcore.h>
#include <linux/pm.h>
+#include <linux/tick.h>
#include <asm/leds.h>
#include <asm/processor.h>
@@ -160,9 +160,11 @@ void cpu_idle(void)
if (!idle)
idle = default_idle;
leds_event(led_idle_start);
+ tick_nohz_stop_sched_tick();
while (!need_resched())
idle();
leds_event(led_idle_end);
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 9254ba2f46f..6f2f46c2e40 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/security.h>
@@ -457,13 +456,10 @@ void ptrace_cancel_bpt(struct task_struct *child)
/*
* Called by kernel/ptrace.c when detaching..
- *
- * Make sure the single step bit is not set.
*/
void ptrace_disable(struct task_struct *child)
{
- child->ptrace &= ~PT_SINGLESTEP;
- ptrace_cancel_bpt(child);
+ single_step_disable(child);
}
/*
@@ -712,9 +708,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
else
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
- /* make sure single-step breakpoint is gone. */
- child->ptrace &= ~PT_SINGLESTEP;
- ptrace_cancel_bpt(child);
+ single_step_disable(child);
wake_up_process(child);
ret = 0;
break;
@@ -725,9 +719,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
* exit.
*/
case PTRACE_KILL:
- /* make sure single-step breakpoint is gone. */
- child->ptrace &= ~PT_SINGLESTEP;
- ptrace_cancel_bpt(child);
+ single_step_disable(child);
if (child->exit_state != EXIT_ZOMBIE) {
child->exit_code = SIGKILL;
wake_up_process(child);
@@ -742,7 +734,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
if (!valid_signal(data))
break;
- child->ptrace |= PT_SINGLESTEP;
+ single_step_enable(child);
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
child->exit_code = data;
/* give it a chance to run. */
@@ -786,8 +778,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
case PTRACE_SET_SYSCALL:
+ task_thread_info(child)->syscall = data;
ret = 0;
- child->ptrace_message = data;
break;
#ifdef CONFIG_CRUNCH
@@ -824,7 +816,7 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
ip = regs->ARM_ip;
regs->ARM_ip = why;
- current->ptrace_message = scno;
+ current_thread_info()->syscall = scno;
/* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
@@ -841,5 +833,5 @@ asmlinkage int syscall_trace(int why, struct pt_regs *regs, int scno)
}
regs->ARM_ip = ip;
- return current->ptrace_message;
+ return current_thread_info()->syscall;
}
diff --git a/arch/arm/kernel/ptrace.h b/arch/arm/kernel/ptrace.h
index f7cad13a22e..def3b6184a7 100644
--- a/arch/arm/kernel/ptrace.h
+++ b/arch/arm/kernel/ptrace.h
@@ -7,6 +7,45 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/ptrace.h>
+
extern void ptrace_cancel_bpt(struct task_struct *);
extern void ptrace_set_bpt(struct task_struct *);
extern void ptrace_break(struct task_struct *, struct pt_regs *);
+
+/*
+ * make sure single-step breakpoint is gone.
+ */
+static inline void single_step_disable(struct task_struct *task)
+{
+ task->ptrace &= ~PT_SINGLESTEP;
+ ptrace_cancel_bpt(task);
+}
+
+static inline void single_step_enable(struct task_struct *task)
+{
+ task->ptrace |= PT_SINGLESTEP;
+}
+
+/*
+ * Send SIGTRAP if we're single-stepping
+ */
+static inline void single_step_trap(struct task_struct *task)
+{
+ if (task->ptrace & PT_SINGLESTEP) {
+ ptrace_cancel_bpt(task);
+ send_sig(SIGTRAP, task, 1);
+ }
+}
+
+static inline void single_step_clear(struct task_struct *task)
+{
+ if (task->ptrace & PT_SINGLESTEP)
+ ptrace_cancel_bpt(task);
+}
+
+static inline void single_step_set(struct task_struct *task)
+{
+ if (task->ptrace & PT_SINGLESTEP)
+ ptrace_set_bpt(task);
+}
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 3843d3bab2d..54cdf1aeefc 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -9,7 +9,6 @@
*/
#include <linux/errno.h>
#include <linux/signal.h>
-#include <linux/ptrace.h>
#include <linux/personality.h>
#include <linux/freezer.h>
@@ -285,11 +284,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs)
if (restore_sigframe(regs, frame))
goto badframe;
- /* Send SIGTRAP if we're single-stepping */
- if (current->ptrace & PT_SINGLESTEP) {
- ptrace_cancel_bpt(current);
- send_sig(SIGTRAP, current, 1);
- }
+ single_step_trap(current);
return regs->ARM_r0;
@@ -324,11 +319,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
if (do_sigaltstack(&frame->sig.uc.uc_stack, NULL, regs->ARM_sp) == -EFAULT)
goto badframe;
- /* Send SIGTRAP if we're single-stepping */
- if (current->ptrace & PT_SINGLESTEP) {
- ptrace_cancel_bpt(current);
- send_sig(SIGTRAP, current, 1);
- }
+ single_step_trap(current);
return regs->ARM_r0;
@@ -644,14 +635,12 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (try_to_freeze())
goto no_signal;
- if (current->ptrace & PT_SINGLESTEP)
- ptrace_cancel_bpt(current);
+ single_step_clear(current);
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
handle_signal(signr, &ka, &info, oldset, regs, syscall);
- if (current->ptrace & PT_SINGLESTEP)
- ptrace_set_bpt(current);
+ single_step_set(current);
return 1;
}
@@ -705,8 +694,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
restart_syscall(regs);
}
}
- if (current->ptrace & PT_SINGLESTEP)
- ptrace_set_bpt(current);
+ single_step_set(current);
return 0;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 070bcb7a630..1b76d87fa33 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -486,7 +486,7 @@ static void ipi_timer(void)
}
#ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void do_local_timer(struct pt_regs *regs)
+asmlinkage void __exception do_local_timer(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
int cpu = smp_processor_id();
@@ -551,7 +551,7 @@ static void ipi_cpu_stop(unsigned int cpu)
*
* Bit 0 - Inter-processor function call
*/
-asmlinkage void do_IPI(struct pt_regs *regs)
+asmlinkage void __exception do_IPI(struct pt_regs *regs)
{
unsigned int cpu = smp_processor_id();
struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
diff --git a/arch/arm/kernel/stacktrace.c b/arch/arm/kernel/stacktrace.c
new file mode 100644
index 00000000000..77ef35efaa8
--- /dev/null
+++ b/arch/arm/kernel/stacktrace.c
@@ -0,0 +1,73 @@
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+
+#include "stacktrace.h"
+
+int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
+ int (*fn)(struct stackframe *, void *), void *data)
+{
+ struct stackframe *frame;
+
+ do {
+ /*
+ * Check current frame pointer is within bounds
+ */
+ if ((fp - 12) < low || fp + 4 >= high)
+ break;
+
+ frame = (struct stackframe *)(fp - 12);
+
+ if (fn(frame, data))
+ break;
+
+ /*
+ * Update the low bound - the next frame must always
+ * be at a higher address than the current frame.
+ */
+ low = fp + 4;
+ fp = frame->fp;
+ } while (fp);
+
+ return 0;
+}
+
+#ifdef CONFIG_STACKTRACE
+struct stack_trace_data {
+ struct stack_trace *trace;
+ unsigned int skip;
+};
+
+static int save_trace(struct stackframe *frame, void *d)
+{
+ struct stack_trace_data *data = d;
+ struct stack_trace *trace = data->trace;
+
+ if (data->skip) {
+ data->skip--;
+ return 0;
+ }
+
+ trace->entries[trace->nr_entries++] = frame->lr;
+
+ return trace->nr_entries >= trace->max_entries;
+}
+
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+ struct stack_trace_data data;
+ unsigned long fp, base;
+
+ data.trace = trace;
+ data.skip = trace->skip;
+
+ if (task) {
+ base = (unsigned long)task_stack_page(task);
+ fp = 0; /* FIXME */
+ } else {
+ base = (unsigned long)task_stack_page(current);
+ asm("mov %0, fp" : "=r" (fp));
+ }
+
+ walk_stackframe(fp, base, base + THREAD_SIZE, save_trace, &data);
+}
+#endif
diff --git a/arch/arm/kernel/stacktrace.h b/arch/arm/kernel/stacktrace.h
new file mode 100644
index 00000000000..e9fd20cb566
--- /dev/null
+++ b/arch/arm/kernel/stacktrace.h
@@ -0,0 +1,9 @@
+struct stackframe {
+ unsigned long fp;
+ unsigned long sp;
+ unsigned long lr;
+ unsigned long pc;
+};
+
+int walk_stackframe(unsigned long fp, unsigned long low, unsigned long high,
+ int (*fn)(struct stackframe *, void *), void *data);
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index f61decb89ba..d0540e4eaf5 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -327,6 +327,7 @@ void restore_time_delta(struct timespec *delta, struct timespec *rtc)
}
EXPORT_SYMBOL(restore_time_delta);
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
/*
* Kernel system timer support.
*/
@@ -340,8 +341,9 @@ void timer_tick(void)
update_process_times(user_mode(get_irq_regs()));
#endif
}
+#endif
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
static int timer_suspend(struct sys_device *dev, pm_message_t state)
{
struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 24095601359..10ff36e4e41 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -16,7 +16,6 @@
#include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/personality.h>
-#include <linux/ptrace.h>
#include <linux/kallsyms.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -45,7 +44,18 @@ static int __init user_debug_setup(char *str)
__setup("user_debug=", user_debug_setup);
#endif
-void dump_backtrace_entry(unsigned long where, unsigned long from)
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
+
+static inline int in_exception_text(unsigned long ptr)
+{
+ extern char __exception_text_start[];
+ extern char __exception_text_end[];
+
+ return ptr >= (unsigned long)&__exception_text_start &&
+ ptr < (unsigned long)&__exception_text_end;
+}
+
+void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
{
#ifdef CONFIG_KALLSYMS
printk("[<%08lx>] ", where);
@@ -55,6 +65,9 @@ void dump_backtrace_entry(unsigned long where, unsigned long from)
#else
printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
#endif
+
+ if (in_exception_text(where))
+ dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
}
/*
@@ -232,8 +245,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
do_exit(SIGSEGV);
}
-void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
- unsigned long err, unsigned long trap)
+void arm_notify_die(const char *str, struct pt_regs *regs,
+ struct siginfo *info, unsigned long err, unsigned long trap)
{
if (user_mode(regs)) {
current->thread.error_code = err;
@@ -266,13 +279,14 @@ void unregister_undef_hook(struct undef_hook *hook)
spin_unlock_irqrestore(&undef_lock, flags);
}
-asmlinkage void do_undefinstr(struct pt_regs *regs)
+asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
unsigned int correction = thumb_mode(regs) ? 2 : 4;
unsigned int instr;
struct undef_hook *hook;
siginfo_t info;
void __user *pc;
+ unsigned long flags;
/*
* According to the ARM ARM, PC is 2 or 4 bytes ahead,
@@ -291,7 +305,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
get_user(instr, (u32 __user *)pc);
}
- spin_lock_irq(&undef_lock);
+ spin_lock_irqsave(&undef_lock, flags);
list_for_each_entry(hook, &undef_hook, node) {
if ((instr & hook->instr_mask) == hook->instr_val &&
(regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
@@ -301,7 +315,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
}
}
}
- spin_unlock_irq(&undef_lock);
+ spin_unlock_irqrestore(&undef_lock, flags);
#ifdef CONFIG_DEBUG_USER
if (user_debug & UDBG_UNDEFINED) {
@@ -316,7 +330,7 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
info.si_code = ILL_ILLOPC;
info.si_addr = pc;
- notify_die("Oops - undefined instruction", regs, &info, 0, 6);
+ arm_notify_die("Oops - undefined instruction", regs, &info, 0, 6);
}
asmlinkage void do_unexp_fiq (struct pt_regs *regs)
@@ -370,7 +384,7 @@ static int bad_syscall(int n, struct pt_regs *regs)
info.si_addr = (void __user *)instruction_pointer(regs) -
(thumb_mode(regs) ? 2 : 4);
- notify_die("Oops - bad syscall", regs, &info, n, 0);
+ arm_notify_die("Oops - bad syscall", regs, &info, n, 0);
return regs->ARM_r0;
}
@@ -414,7 +428,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
info.si_code = SEGV_MAPERR;
info.si_addr = NULL;
- notify_die("branch through zero", regs, &info, 0, 0);
+ arm_notify_die("branch through zero", regs, &info, 0, 0);
return 0;
case NR(breakpoint): /* SWI BREAK_POINT */
@@ -550,7 +564,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
info.si_addr = (void __user *)instruction_pointer(regs) -
(thumb_mode(regs) ? 2 : 4);
- notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
+ arm_notify_die("Oops - bad syscall(2)", regs, &info, no, 0);
return 0;
}
@@ -624,7 +638,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
info.si_code = ILL_ILLOPC;
info.si_addr = (void __user *)addr;
- notify_die("unknown data abort code", regs, &info, instr, 0);
+ arm_notify_die("unknown data abort code", regs, &info, instr, 0);
}
void __attribute__((noreturn)) __bug(const char *file, int line)
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ddbdad48f5b..e4156e7868c 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -23,11 +23,15 @@ SECTIONS
#else
. = PAGE_OFFSET + TEXT_OFFSET;
#endif
- .init : { /* Init code and data */
+ .text.head : {
_stext = .;
- _sinittext = .;
+ _sinittext = .;
+ *(.text.head)
+ }
+
+ .init : { /* Init code and data */
*(.init.text)
- _einittext = .;
+ _einittext = .;
__proc_info_begin = .;
*(.proc.info.init)
__proc_info_end = .;
@@ -59,7 +63,7 @@ SECTIONS
usr/built-in.o(.init.ramfs)
__initramfs_end = .;
#endif
- . = ALIGN(64);
+ . = ALIGN(4096);
__per_cpu_start = .;
*(.data.percpu)
__per_cpu_end = .;
@@ -83,6 +87,9 @@ SECTIONS
.text : { /* Real text segment */
_text = .; /* Text and read-only data */
+ __exception_text_start = .;
+ *(.exception.text)
+ __exception_text_end = .;
*(.text)
SCHED_TEXT
LOCK_TEXT
@@ -116,7 +123,7 @@ SECTIONS
* first, the init task union, aligned
* to an 8192 byte boundary.
*/
- *(.init.task)
+ *(.data.init_task)
#ifdef CONFIG_XIP_KERNEL
. = ALIGN(4096);
diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
index 74230083cbf..84dc890d2bf 100644
--- a/arch/arm/lib/backtrace.S
+++ b/arch/arm/lib/backtrace.S
@@ -17,8 +17,8 @@
@ fp is 0 or stack frame
#define frame r4
-#define next r5
-#define save r6
+#define sv_fp r5
+#define sv_pc r6
#define mask r7
#define offset r8
@@ -31,108 +31,106 @@ ENTRY(c_backtrace)
#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK)
mov pc, lr
#else
-
stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location...
- tst r1, #0x10 @ 26 or 32-bit?
- moveq mask, #0xfc000003
- movne mask, #0
- tst mask, r0
- movne r0, #0
- movs frame, r0
-1: moveq r0, #-2
- ldmeqfd sp!, {r4 - r8, pc}
-
-2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction
- ldr r0, [sp], #4
- adr r1, 2b - 4
+ movs frame, r0 @ if frame pointer is zero
+ beq no_frame @ we have no stack frames
+
+ tst r1, #0x10 @ 26 or 32-bit mode?
+ moveq mask, #0xfc000003 @ mask for 26-bit
+ movne mask, #0 @ mask for 32-bit
+
+1: stmfd sp!, {pc} @ calculate offset of PC stored
+ ldr r0, [sp], #4 @ by stmfd for this CPU
+ adr r1, 1b
sub offset, r0, r1
-3: tst frame, mask @ Check for address exceptions...
- bne 1b
+/*
+ * Stack frame layout:
+ * optionally saved caller registers (r4 - r10)
+ * saved fp
+ * saved sp
+ * saved lr
+ * frame => saved pc
+ * optionally saved arguments (r0 - r3)
+ * saved sp => <next word>
+ *
+ * Functions start with the following code sequence:
+ * mov ip, sp
+ * stmfd sp!, {r0 - r3} (optional)
+ * corrected pc => stmfd sp!, {..., fp, ip, lr, pc}
+ */
+for_each_frame: tst frame, mask @ Check for address exceptions
+ bne no_frame
+
+1001: ldr sv_pc, [frame, #0] @ get saved pc
+1002: ldr sv_fp, [frame, #-12] @ get saved fp
-1001: ldr next, [frame, #-12] @ get fp
-1002: ldr r2, [frame, #-4] @ get lr
-1003: ldr r3, [frame, #0] @ get pc
- sub save, r3, offset @ Correct PC for prefetching
- bic save, save, mask
-1004: ldr r1, [save, #0] @ get instruction at function
- mov r1, r1, lsr #10
- ldr r3, .Ldsi+4
- teq r1, r3
- subeq save, save, #4
- mov r0, save
- bic r1, r2, mask
+ sub sv_pc, sv_pc, offset @ Correct PC for prefetching
+ bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
+
+1003: ldr r2, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
+ ldr r3, .Ldsi+4 @ adjust saved 'pc' back one
+ teq r3, r2, lsr #10 @ instruction
+ subne r0, sv_pc, #4 @ allow for mov
+ subeq r0, sv_pc, #8 @ allow for mov + stmia
+
+ ldr r1, [frame, #-4] @ get saved lr
+ mov r2, frame
+ bic r1, r1, mask @ mask PC/LR for the mode
bl dump_backtrace_entry
- ldr r0, [frame, #-8] @ get sp
- sub r0, r0, #4
-1005: ldr r1, [save, #4] @ get instruction at function+4
- mov r3, r1, lsr #10
- ldr r2, .Ldsi+4
- teq r3, r2 @ Check for stmia sp!, {args}
- addeq save, save, #4 @ next instruction
- bleq .Ldumpstm
-
- sub r0, frame, #16
-1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction
- mov r3, r1, lsr #10
- ldr r2, .Ldsi
- teq r3, r2
- bleq .Ldumpstm
-
- /*
- * A zero next framepointer means we're done.
- */
- teq next, #0
- ldmeqfd sp!, {r4 - r8, pc}
-
- /*
- * The next framepointer must be above the
- * current framepointer.
- */
- cmp next, frame
- mov frame, next
- bhi 3b
- b 1007f
+ ldr r1, [sv_pc, #-4] @ if stmfd sp!, {args} exists,
+ ldr r3, .Ldsi+4
+ teq r3, r1, lsr #10
+ ldreq r0, [frame, #-8] @ get sp
+ subeq r0, r0, #4 @ point at the last arg
+ bleq .Ldumpstm @ dump saved registers
-/*
- * Fixup for LDMDB. Note that this must not be in the fixup section.
- */
-1007: ldr r0, =.Lbad
+1004: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, ip, lr, pc}
+ ldr r3, .Ldsi @ instruction exists,
+ teq r3, r1, lsr #10
+ subeq r0, frame, #16
+ bleq .Ldumpstm @ dump saved registers
+
+ teq sv_fp, #0 @ zero saved fp means
+ beq no_frame @ no further frames
+
+ cmp sv_fp, frame @ next frame must be
+ mov frame, sv_fp @ above the current frame
+ bhi for_each_frame
+
+1006: adr r0, .Lbad
mov r1, frame
bl printk
- ldmfd sp!, {r4 - r8, pc}
- .ltorg
+no_frame: ldmfd sp!, {r4 - r8, pc}
.section __ex_table,"a"
.align 3
- .long 1001b, 1007b
- .long 1002b, 1007b
- .long 1003b, 1007b
- .long 1004b, 1007b
- .long 1005b, 1007b
- .long 1006b, 1007b
+ .long 1001b, 1006b
+ .long 1002b, 1006b
+ .long 1003b, 1006b
+ .long 1004b, 1006b
.previous
#define instr r4
#define reg r5
#define stack r6
-.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, r8, lr}
+.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr}
mov stack, r0
mov instr, r1
- mov reg, #9
+ mov reg, #10
mov r7, #0
1: mov r3, #1
tst instr, r3, lsl reg
beq 2f
add r7, r7, #1
- teq r7, #4
- moveq r7, #0
- moveq r3, #'\n'
- movne r3, #' '
- ldr r2, [stack], #-4
- mov r1, reg
+ teq r7, #6
+ moveq r7, #1
+ moveq r1, #'\n'
+ movne r1, #' '
+ ldr r3, [stack], #-4
+ mov r2, reg
adr r0, .Lfp
bl printk
2: subs reg, reg, #1
@@ -140,14 +138,13 @@ ENTRY(c_backtrace)
teq r7, #0
adrne r0, .Lcr
blne printk
- mov r0, stack
- ldmfd sp!, {instr, reg, stack, r7, r8, pc}
+ ldmfd sp!, {instr, reg, stack, r7, pc}
-.Lfp: .asciz " r%d = %08X%c"
+.Lfp: .asciz "%cr%d:%08x"
.Lcr: .asciz "\n"
.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
.align
-.Ldsi: .word 0x00e92dd8 >> 2
- .word 0x00e92d00 >> 2
+.Ldsi: .word 0xe92dd800 >> 10 @ stmfd sp!, {... fp, ip, lr, pc}
+ .word 0xe92d0000 >> 10 @ stmfd sp!, {}
#endif
diff --git a/arch/arm/lib/getuser.S b/arch/arm/lib/getuser.S
index c03ea8e666b..1dd8ea4f9a9 100644
--- a/arch/arm/lib/getuser.S
+++ b/arch/arm/lib/getuser.S
@@ -26,8 +26,6 @@
* Note that ADDR_LIMIT is either 0 or 0xc0000000.
* Note also that it is intended that __get_user_bad is not global.
*/
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
#include <asm/errno.h>
.global __get_user_1
diff --git a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S
index 4593e9c07f0..8620afe54f7 100644
--- a/arch/arm/lib/putuser.S
+++ b/arch/arm/lib/putuser.S
@@ -26,8 +26,6 @@
* Note that ADDR_LIMIT is either 0 or 0xc0000000
* Note also that it is intended that __put_user_bad is not global.
*/
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
#include <asm/errno.h>
.global __put_user_1
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index a950160fcfb..0446ef2f5bd 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -142,7 +142,7 @@ aaec2000_timer_interrupt(int irq, void *dev_id)
static struct irqaction aaec2000_timer_irq = {
.name = "AAEC-2000 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = aaec2000_timer_interrupt,
};
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index bf0d96272e3..018d637f87f 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -81,6 +81,13 @@ config MACH_KB9200
Select this if you are using KwikByte's KB920x board.
<http://kwikbyte.com/KB9202_description_new.htm>
+config MACH_PICOTUX2XX
+ bool "picotux 200"
+ depends on ARCH_AT91RM9200
+ help
+ Select this if you are using a picotux 200.
+ <http://www.picotux.com/>
+
config MACH_KAFA
bool "Sperry-Sun KAFA board"
depends on ARCH_AT91RM9200
@@ -100,7 +107,7 @@ config ARCH_AT91SAM9260_SAM9XE
depends on ARCH_AT91SAM9260
help
Select this if you are using Atmel's AT91SAM9XE System-on-Chip.
- They are basicaly AT91SAM9260s with various sizes of embedded Flash.
+ They are basically AT91SAM9260s with various sizes of embedded Flash.
comment "AT91SAM9260 / AT91SAM9XE Board Type"
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 05de6cdc88f..a412ae18a42 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o
obj-$(CONFIG_MACH_KB9200) += board-kb9202.o
obj-$(CONFIG_MACH_ATEB9200) += board-eb9200.o
obj-$(CONFIG_MACH_KAFA) += board-kafa.o
+obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o
# AT91SAM9260 board-specific support
obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 2ddcdd69df7..2cad2bf864b 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -117,6 +117,21 @@ static struct clk pioD_clk = {
.pmc_mask = 1 << AT91RM9200_ID_PIOD,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk ssc0_clk = {
+ .name = "ssc0_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_SSC0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+ .name = "ssc1_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_SSC1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc2_clk = {
+ .name = "ssc2_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_SSC2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk tc0_clk = {
.name = "tc0_clk",
.pmc_mask = 1 << AT91RM9200_ID_TC0,
@@ -161,7 +176,9 @@ static struct clk *periph_clocks[] __initdata = {
&udc_clk,
&twi_clk,
&spi_clk,
- // ssc 0 .. ssc2
+ &ssc0_clk,
+ &ssc1_clk,
+ &ssc2_clk,
&tc0_clk,
&tc1_clk,
&tc2_clk,
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index 949199a244c..a6340357585 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -87,7 +87,7 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
static struct irqaction at91rm9200_timer_irq = {
.name = "at91_tick",
- .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = at91rm9200_timer_interrupt
};
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 6ea41d8266c..e47381e8aab 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -119,6 +119,11 @@ static struct clk spi1_clk = {
.pmc_mask = 1 << AT91SAM9260_ID_SPI1,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk ssc_clk = {
+ .name = "ssc_clk",
+ .pmc_mask = 1 << AT91SAM9260_ID_SSC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk tc0_clk = {
.name = "tc0_clk",
.pmc_mask = 1 << AT91SAM9260_ID_TC0,
@@ -193,7 +198,7 @@ static struct clk *periph_clocks[] __initdata = {
&twi_clk,
&spi0_clk,
&spi1_clk,
- // ssc
+ &ssc_clk,
&tc0_clk,
&tc1_clk,
&tc2_clk,
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 784d1e682d6..dfe8c39c9fb 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -97,6 +97,21 @@ static struct clk spi1_clk = {
.pmc_mask = 1 << AT91SAM9261_ID_SPI1,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk ssc0_clk = {
+ .name = "ssc0_clk",
+ .pmc_mask = 1 << AT91SAM9261_ID_SSC0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+ .name = "ssc1_clk",
+ .pmc_mask = 1 << AT91SAM9261_ID_SSC1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc2_clk = {
+ .name = "ssc2_clk",
+ .pmc_mask = 1 << AT91SAM9261_ID_SSC2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk tc0_clk = {
.name = "tc0_clk",
.pmc_mask = 1 << AT91SAM9261_ID_TC0,
@@ -135,7 +150,9 @@ static struct clk *periph_clocks[] __initdata = {
&twi_clk,
&spi0_clk,
&spi1_clk,
- // ssc 0 .. ssc2
+ &ssc0_clk,
+ &ssc1_clk,
+ &ssc2_clk,
&tc0_clk,
&tc1_clk,
&tc2_clk,
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index e1504766fd6..8e781997716 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -430,9 +430,9 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
* LCD Controller
* -------------------------------------------------------------------- */
-#if defined(CONFIG_FB_AT91) || defined(CONFIG_FB_AT91_MODULE)
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
static u64 lcdc_dmamask = 0xffffffffUL;
-static struct at91fb_info lcdc_data;
+static struct atmel_lcdfb_info lcdc_data;
static struct resource lcdc_resources[] = {
[0] = {
@@ -455,7 +455,7 @@ static struct resource lcdc_resources[] = {
};
static struct platform_device at91_lcdc_device = {
- .name = "at91-fb",
+ .name = "atmel_lcdfb",
.id = 0,
.dev = {
.dma_mask = &lcdc_dmamask,
@@ -466,7 +466,7 @@ static struct platform_device at91_lcdc_device = {
.num_resources = ARRAY_SIZE(lcdc_resources),
};
-void __init at91_add_device_lcdc(struct at91fb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
{
if (!data) {
return;
@@ -499,7 +499,7 @@ void __init at91_add_device_lcdc(struct at91fb_info *data)
platform_device_register(&at91_lcdc_device);
}
#else
-void __init at91_add_device_lcdc(struct at91fb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 0e89a7fca3f..00e27b17785 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -87,6 +87,11 @@ static struct clk mmc1_clk = {
.pmc_mask = 1 << AT91SAM9263_ID_MCI1,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk can_clk = {
+ .name = "can_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_CAN,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk twi_clk = {
.name = "twi_clk",
.pmc_mask = 1 << AT91SAM9263_ID_TWI,
@@ -102,16 +107,46 @@ static struct clk spi1_clk = {
.pmc_mask = 1 << AT91SAM9263_ID_SPI1,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk ssc0_clk = {
+ .name = "ssc0_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_SSC0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+ .name = "ssc1_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_SSC1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ac97_clk = {
+ .name = "ac97_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_AC97C,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk tcb_clk = {
.name = "tcb_clk",
.pmc_mask = 1 << AT91SAM9263_ID_TCB,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk pwmc_clk = {
+ .name = "pwmc_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_PWMC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk macb_clk = {
.name = "macb_clk",
.pmc_mask = 1 << AT91SAM9263_ID_EMAC,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk dma_clk = {
+ .name = "dma_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_DMA,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twodge_clk = {
+ .name = "2dge_clk",
+ .pmc_mask = 1 << AT91SAM9263_ID_2DGE,
+ .type = CLK_TYPE_PERIPHERAL,
+};
static struct clk udc_clk = {
.name = "udc_clk",
.pmc_mask = 1 << AT91SAM9263_ID_UDP,
@@ -142,20 +177,21 @@ static struct clk *periph_clocks[] __initdata = {
&usart2_clk,
&mmc0_clk,
&mmc1_clk,
- // can
+ &can_clk,
&twi_clk,
&spi0_clk,
&spi1_clk,
- // ssc0 .. ssc1
- // ac97
+ &ssc0_clk,
+ &ssc1_clk,
+ &ac97_clk,
&tcb_clk,
- // pwmc
+ &pwmc_clk,
&macb_clk,
- // 2dge
+ &twodge_clk,
&udc_clk,
&isi_clk,
&lcdc_clk,
- // dma
+ &dma_clk,
&ohci_clk,
// irq0 .. irq1
};
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index b77121f27f3..2b2e18a6712 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -573,6 +573,130 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
/* --------------------------------------------------------------------
+ * AC97
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
+static u64 ac97_dmamask = 0xffffffffUL;
+static struct atmel_ac97_data ac97_data;
+
+static struct resource ac97_resources[] = {
+ [0] = {
+ .start = AT91SAM9263_BASE_AC97C,
+ .end = AT91SAM9263_BASE_AC97C + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9263_ID_AC97C,
+ .end = AT91SAM9263_ID_AC97C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91sam9263_ac97_device = {
+ .name = "ac97c",
+ .id = 1,
+ .dev = {
+ .dma_mask = &ac97_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &ac97_data,
+ },
+ .resource = ac97_resources,
+ .num_resources = ARRAY_SIZE(ac97_resources),
+};
+
+void __init at91_add_device_ac97(struct atmel_ac97_data *data)
+{
+ if (!data)
+ return;
+
+ at91_set_A_periph(AT91_PIN_PB0, 0); /* AC97FS */
+ at91_set_A_periph(AT91_PIN_PB1, 0); /* AC97CK */
+ at91_set_A_periph(AT91_PIN_PB2, 0); /* AC97TX */
+ at91_set_A_periph(AT91_PIN_PB3, 0); /* AC97RX */
+
+ /* reset */
+ if (data->reset_pin)
+ at91_set_gpio_output(data->reset_pin, 0);
+
+ ac97_data = *ek_data;
+ platform_device_register(&at91sam9263_ac97_device);
+}
+#else
+void __init at91_add_device_ac97(struct atmel_ac97_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ * LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static u64 lcdc_dmamask = 0xffffffffUL;
+static struct atmel_lcdfb_info lcdc_data;
+
+static struct resource lcdc_resources[] = {
+ [0] = {
+ .start = AT91SAM9263_LCDC_BASE,
+ .end = AT91SAM9263_LCDC_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9263_ID_LCDC,
+ .end = AT91SAM9263_ID_LCDC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_lcdc_device = {
+ .name = "atmel_lcdfb",
+ .id = 0,
+ .dev = {
+ .dma_mask = &lcdc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &lcdc_data,
+ },
+ .resource = lcdc_resources,
+ .num_resources = ARRAY_SIZE(lcdc_resources),
+};
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+ if (!data)
+ return;
+
+ at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDHSYNC */
+ at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDDOTCK */
+ at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDDEN */
+ at91_set_B_periph(AT91_PIN_PB9, 0); /* LCDCC */
+ at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD2 */
+ at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD3 */
+ at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD4 */
+ at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD5 */
+ at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD6 */
+ at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD7 */
+ at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD10 */
+ at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD11 */
+ at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD12 */
+ at91_set_B_periph(AT91_PIN_PC12, 0); /* LCDD13 */
+ at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD14 */
+ at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD15 */
+ at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD18 */
+ at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD19 */
+ at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDD20 */
+ at91_set_B_periph(AT91_PIN_PC17, 0); /* LCDD21 */
+ at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDD22 */
+ at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDD23 */
+
+ lcdc_data = *data;
+ platform_device_register(&at91_lcdc_device);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
* LEDs
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c
index a4dded27fa1..5c090c9442f 100644
--- a/arch/arm/mach-at91/at91sam926x_time.c
+++ b/arch/arm/mach-at91/at91sam926x_time.c
@@ -66,7 +66,7 @@ static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id)
static struct irqaction at91sam926x_timer_irq = {
.name = "at91_tick",
- .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = at91sam926x_timer_interrupt
};
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
new file mode 100644
index 00000000000..49cfe7ab4a8
--- /dev/null
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -0,0 +1,166 @@
+/*
+ * linux/arch/arm/mach-at91/board-picotux200.c
+ *
+ * Copyright (C) 2005 SAN People
+ * Copyright (C) 2007 Kleinhenz Elektronik GmbH
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/physmap.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91rm9200_mc.h>
+
+#include "generic.h"
+
+
+/*
+ * Serial port configuration.
+ * 0 .. 3 = USART0 .. USART3
+ * 4 = DBGU
+ */
+static struct at91_uart_config __initdata picotux200_uart_config = {
+ .console_tty = 0, /* ttyS0 */
+ .nr_tty = 2,
+ .tty_map = { 4, 1, -1, -1, -1 } /* ttyS0, ..., ttyS4 */
+};
+
+static void __init picotux200_map_io(void)
+{
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_BGA);
+
+ /* Setup the serial ports and console */
+ at91_init_serial(&picotux200_uart_config);
+}
+
+static void __init picotux200_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
+static struct at91_eth_data __initdata picotux200_eth_data = {
+ .phy_irq_pin = AT91_PIN_PC4,
+ .is_rmii = 1,
+};
+
+static struct at91_usbh_data __initdata picotux200_usbh_data = {
+ .ports = 1,
+};
+
+// static struct at91_udc_data __initdata picotux200_udc_data = {
+// .vbus_pin = AT91_PIN_PD4,
+// .pullup_pin = AT91_PIN_PD5,
+// };
+
+static struct at91_mmc_data __initdata picotux200_mmc_data = {
+ .det_pin = AT91_PIN_PB27,
+ .slot_b = 0,
+ .wire4 = 1,
+ .wp_pin = AT91_PIN_PA17,
+};
+
+// static struct spi_board_info picotux200_spi_devices[] = {
+// { /* DataFlash chip */
+// .modalias = "mtd_dataflash",
+// .chip_select = 0,
+// .max_speed_hz = 15 * 1000 * 1000,
+// },
+// #ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+// { /* DataFlash card */
+// .modalias = "mtd_dataflash",
+// .chip_select = 3,
+// .max_speed_hz = 15 * 1000 * 1000,
+// },
+// #endif
+// };
+
+#define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
+#define PICOTUX200_FLASH_SIZE 0x400000
+
+static struct physmap_flash_data picotux200_flash_data = {
+ .width = 2,
+};
+
+static struct resource picotux200_flash_resource = {
+ .start = PICOTUX200_FLASH_BASE,
+ .end = PICOTUX200_FLASH_BASE + PICOTUX200_FLASH_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device picotux200_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &picotux200_flash_data,
+ },
+ .resource = &picotux200_flash_resource,
+ .num_resources = 1,
+};
+
+static void __init picotux200_board_init(void)
+{
+ /* Serial */
+ at91_add_device_serial();
+ /* Ethernet */
+ at91_add_device_eth(&picotux200_eth_data);
+ /* USB Host */
+ at91_add_device_usbh(&picotux200_usbh_data);
+ /* USB Device */
+ // at91_add_device_udc(&picotux200_udc_data);
+ // at91_set_multi_drive(picotux200_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */
+ /* I2C */
+ at91_add_device_i2c();
+ /* SPI */
+ // at91_add_device_spi(picotux200_spi_devices, ARRAY_SIZE(picotux200_spi_devices));
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+ /* DataFlash card */
+ at91_set_gpio_output(AT91_PIN_PB22, 0);
+#else
+ /* MMC */
+ at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
+ at91_add_device_mmc(0, &picotux200_mmc_data);
+#endif
+ /* NOR Flash */
+ platform_device_register(&picotux200_flash);
+}
+
+MACHINE_START(PICOTUX2XX, "picotux 200")
+ /* Maintainer: Kleinhenz Elektronik GmbH */
+ .phys_io = AT91_BASE_SYS,
+ .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+ .boot_params = AT91_SDRAM_BASE + 0x100,
+ .timer = &at91rm9200_timer,
+ .map_io = picotux200_map_io,
+ .init_irq = picotux200_init_irq,
+ .init_machine = picotux200_board_init,
+MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index 57fb4499d96..65fa532bb4a 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -104,9 +104,9 @@ static struct spi_board_info ek_spi_devices[] = {
},
#endif
#endif
-#if defined(CONFIG_SND_AT73C213)
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
{ /* AT73C213 DAC */
- .modalias = "snd_at73c213",
+ .modalias = "at73c213",
.chip_select = 0,
.max_speed_hz = 10 * 1000 * 1000,
.bus_num = 1,
@@ -118,7 +118,7 @@ static struct spi_board_info ek_spi_devices[] = {
/*
* MACB Ethernet device
*/
-static struct __initdata at91_eth_data ek_macb_data = {
+static struct at91_eth_data __initdata ek_macb_data = {
.phy_irq_pin = AT91_PIN_PA7,
.is_rmii = 1,
};
@@ -140,7 +140,7 @@ static struct mtd_partition __initdata ek_nand_partition[] = {
},
};
-static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
{
*num_partitions = ARRAY_SIZE(ek_nand_partition);
return ek_nand_partition;
@@ -188,6 +188,8 @@ static void __init ek_board_init(void)
at91_add_device_eth(&ek_macb_data);
/* MMC */
at91_add_device_mmc(0, &ek_mmc_data);
+ /* I2C */
+ at91_add_device_i2c();
}
MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index b7e772467cf..bcf71536cc6 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
#include <linux/dm9000.h>
#include <asm/hardware.h>
@@ -195,6 +196,41 @@ static struct at91_nand_data __initdata ek_nand_data = {
};
/*
+ * ADS7846 Touchscreen
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+
+static int ads7843_pendown_state(void)
+{
+ return !at91_get_gpio_value(AT91_PIN_PC2); /* Touchscreen PENIRQ */
+}
+
+static struct ads7846_platform_data ads_info = {
+ .model = 7843,
+ .x_min = 150,
+ .x_max = 3830,
+ .y_min = 190,
+ .y_max = 3830,
+ .vref_delay_usecs = 100,
+ .x_plate_ohms = 450,
+ .y_plate_ohms = 250,
+ .pressure_max = 15000,
+ .debounce_max = 1,
+ .debounce_rep = 0,
+ .debounce_tol = (~0),
+ .get_pendown_state = ads7843_pendown_state,
+};
+
+static void __init ek_add_device_ts(void)
+{
+ at91_set_B_periph(AT91_PIN_PC2, 1); /* External IRQ0, with pullup */
+ at91_set_gpio_input(AT91_PIN_PA11, 1); /* Touchscreen BUSY signal */
+}
+#else
+static void __init ek_add_device_ts(void) {}
+#endif
+
+/*
* SPI devices
*/
static struct spi_board_info ek_spi_devices[] = {
@@ -204,6 +240,16 @@ static struct spi_board_info ek_spi_devices[] = {
.max_speed_hz = 15 * 1000 * 1000,
.bus_num = 0,
},
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+ {
+ .modalias = "ads7846",
+ .chip_select = 2,
+ .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
+ .bus_num = 0,
+ .platform_data = &ads_info,
+ .irq = AT91SAM9261_ID_IRQ0,
+ },
+#endif
#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
{ /* DataFlash card - jumper (J12) configurable to CS3 or CS0 */
.modalias = "mtd_dataflash",
@@ -211,9 +257,9 @@ static struct spi_board_info ek_spi_devices[] = {
.max_speed_hz = 15 * 1000 * 1000,
.bus_num = 0,
},
-#elif defined(CONFIG_SND_AT73C213)
+#elif defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
{ /* AT73C213 DAC */
- .modalias = "snd_at73c213",
+ .modalias = "at73c213",
.chip_select = 3,
.max_speed_hz = 10 * 1000 * 1000,
.bus_num = 0,
@@ -241,6 +287,8 @@ static void __init ek_board_init(void)
#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
/* SPI */
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* Touchscreen */
+ ek_add_device_ts();
#else
/* MMC */
at91_add_device_mmc(0, &ek_mmc_data);
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 8fdce11a880..f57458559fb 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
#include <asm/hardware.h>
#include <asm/setup.h>
@@ -86,6 +87,40 @@ static struct at91_udc_data __initdata ek_udc_data = {
/*
+ * ADS7846 Touchscreen
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+static int ads7843_pendown_state(void)
+{
+ return !at91_get_gpio_value(AT91_PIN_PA15); /* Touchscreen PENIRQ */
+}
+
+static struct ads7846_platform_data ads_info = {
+ .model = 7843,
+ .x_min = 150,
+ .x_max = 3830,
+ .y_min = 190,
+ .y_max = 3830,
+ .vref_delay_usecs = 100,
+ .x_plate_ohms = 450,
+ .y_plate_ohms = 250,
+ .pressure_max = 15000,
+ .debounce_max = 1,
+ .debounce_rep = 0,
+ .debounce_tol = (~0),
+ .get_pendown_state = ads7843_pendown_state,
+};
+
+static void __init ek_add_device_ts(void)
+{
+ at91_set_B_periph(AT91_PIN_PA15, 1); /* External IRQ1, with pullup */
+ at91_set_gpio_input(AT91_PIN_PA31, 1); /* Touchscreen BUSY signal */
+}
+#else
+static void __init ek_add_device_ts(void) {}
+#endif
+
+/*
* SPI devices.
*/
static struct spi_board_info ek_spi_devices[] = {
@@ -97,6 +132,16 @@ static struct spi_board_info ek_spi_devices[] = {
.bus_num = 0,
},
#endif
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+ {
+ .modalias = "ads7846",
+ .chip_select = 3,
+ .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
+ .bus_num = 0,
+ .platform_data = &ads_info,
+ .irq = AT91SAM9263_ID_IRQ1,
+ },
+#endif
};
@@ -112,6 +157,14 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
/*
+ * MACB Ethernet device
+ */
+static struct at91_eth_data __initdata ek_macb_data = {
+ .is_rmii = 1,
+};
+
+
+/*
* NAND flash
*/
static struct mtd_partition __initdata ek_nand_partition[] = {
@@ -148,6 +201,14 @@ static struct at91_nand_data __initdata ek_nand_data = {
};
+/*
+ * AC97
+ */
+static struct atmel_ac97_data ek_ac97_data = {
+ .reset_pin = AT91_PIN_PA13,
+};
+
+
static void __init ek_board_init(void)
{
/* Serial */
@@ -157,11 +218,20 @@ static void __init ek_board_init(void)
/* USB Device */
at91_add_device_udc(&ek_udc_data);
/* SPI */
+ at91_set_gpio_output(AT91_PIN_PE20, 1); /* select spi0 clock */
at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+ /* Touchscreen */
+ ek_add_device_ts();
/* MMC */
at91_add_device_mmc(1, &ek_mmc_data);
+ /* Ethernet */
+ at91_add_device_eth(&ek_macb_data);
/* NAND */
at91_add_device_nand(&ek_nand_data);
+ /* I2C */
+ at91_add_device_i2c();
+ /* AC97 */
+ at91_add_device_ac97(&ek_ac97_data);
}
MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index b49bfda53d7..ff8db29e989 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -201,7 +201,6 @@ error:
static struct pm_ops at91_pm_ops ={
- .pm_disk_mode = 0,
.valid = at91_pm_valid_state,
.prepare = at91_pm_prepare,
.enter = at91_pm_enter,
diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
index 428493dd468..f428af7545b 100644
--- a/arch/arm/mach-clps711x/time.c
+++ b/arch/arm/mach-clps711x/time.c
@@ -58,7 +58,7 @@ p720t_timer_interrupt(int irq, void *dev_id)
static struct irqaction clps711x_timer_irq = {
.name = "CLPS711x Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = p720t_timer_interrupt,
};
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index 231b9000473..4dde34f25e6 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -316,7 +316,7 @@ clps7500_timer_interrupt(int irq, void *dev_id)
static struct irqaction clps7500_timer_irq = {
.name = "CLPS7500 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = clps7500_timer_interrupt,
};
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 8459431cfd7..8c1b5690dfe 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -199,7 +199,7 @@ ebsa110_timer_interrupt(int irq, void *dev_id)
static struct irqaction ebsa110_timer_irq = {
.name = "EBSA110 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = ebsa110_timer_interrupt,
};
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index db38afb2aa8..bbf0d332407 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -102,6 +102,26 @@ EXPORT_SYMBOL(__readb);
EXPORT_SYMBOL(__readw);
EXPORT_SYMBOL(__readl);
+void readsw(void __iomem *addr, void *data, int len)
+{
+ void __iomem *a = __isamem_convert_addr(addr);
+
+ BUG_ON((unsigned long)addr & 1);
+
+ __raw_readsw(a, data, len);
+}
+EXPORT_SYMBOL(readsw);
+
+void readsl(void __iomem *addr, void *data, int len)
+{
+ void __iomem *a = __isamem_convert_addr(addr);
+
+ BUG_ON((unsigned long)addr & 3);
+
+ __raw_readsl(a, data, len);
+}
+EXPORT_SYMBOL(readsl);
+
void __writeb(u8 val, void __iomem *addr)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -137,6 +157,26 @@ EXPORT_SYMBOL(__writeb);
EXPORT_SYMBOL(__writew);
EXPORT_SYMBOL(__writel);
+void writesw(void __iomem *addr, void *data, int len)
+{
+ void __iomem *a = __isamem_convert_addr(addr);
+
+ BUG_ON((unsigned long)addr & 1);
+
+ __raw_writesw(a, data, len);
+}
+EXPORT_SYMBOL(writesw);
+
+void writesl(void __iomem *addr, void *data, int len)
+{
+ void __iomem *a = __isamem_convert_addr(addr);
+
+ BUG_ON((unsigned long)addr & 3);
+
+ __raw_writesl(a, data, len);
+}
+EXPORT_SYMBOL(writesl);
+
#define SUPERIO_PORT(p) \
(((p) >> 3) == (0x3f8 >> 3) || \
((p) >> 3) == (0x2f8 >> 3) || \
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index f174d1a3b11..9d7515c36bf 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -27,6 +27,10 @@ struct clk {
u32 enable_mask;
};
+static struct clk clk_uart = {
+ .name = "UARTCLK",
+ .rate = 14745600,
+};
static struct clk clk_pll1 = {
.name = "pll1",
};
@@ -50,6 +54,7 @@ static struct clk clk_usb_host = {
static struct clk *clocks[] = {
+ &clk_uart,
&clk_pll1,
&clk_f,
&clk_h,
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 829aed696d9..851cc7158ca 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -116,7 +116,7 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id)
static struct irqaction ep93xx_timer_irq = {
.name = "ep93xx timer",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = ep93xx_timer_interrupt,
};
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index fa6be870c6c..3a63941d43b 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -44,7 +44,7 @@ timer1_interrupt(int irq, void *dev_id)
static struct irqaction footbridge_timer_irq = {
.name = "Timer1 timer tick",
.handler = timer1_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};
/*
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 1463330ed8e..d0dc51e8133 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -10,7 +10,6 @@
*/
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/slab.h>
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index d884a3954fb..d08d64139d0 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -73,7 +73,7 @@ isa_timer_interrupt(int irq, void *dev_id)
static struct irqaction isa_timer_irq = {
.name = "ISA timer tick",
.handler = isa_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};
static void __init isa_timer_init(void)
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
index 13f76bdb3d9..9107b8e2ad6 100644
--- a/arch/arm/mach-h720x/cpu-h7201.c
+++ b/arch/arm/mach-h720x/cpu-h7201.c
@@ -41,7 +41,7 @@ h7201_timer_interrupt(int irq, void *dev_id)
static struct irqaction h7201_timer_irq = {
.name = "h7201 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = h7201_timer_interrupt,
};
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 703870f30ad..82e420d6fd1 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -170,7 +170,7 @@ static struct irq_chip h7202_timerx_chip = {
static struct irqaction h7202_timer_irq = {
.name = "h7202 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = h7202_timer_interrupt,
};
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 2703a730baf..6960a9d0421 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -56,7 +56,7 @@ imx_timer_interrupt(int irq, void *dev_id)
static struct irqaction imx_timer_irq = {
.name = "i.MX Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = imx_timer_interrupt,
};
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 8d880cb9ba3..897c21c2fb5 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -282,7 +282,7 @@ integrator_timer_interrupt(int irq, void *dev_id)
static struct irqaction integrator_timer_irq = {
.name = "Integrator Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = integrator_timer_interrupt,
};
diff --git a/arch/arm/mach-integrator/pci.c b/arch/arm/mach-integrator/pci.c
index 394ec9261c4..af7d3ff013e 100644
--- a/arch/arm/mach-integrator/pci.c
+++ b/arch/arm/mach-integrator/pci.c
@@ -23,7 +23,6 @@
*/
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index fb8c6d97b22..af9ebccac7c 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -22,7 +22,6 @@
*/
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
diff --git a/arch/arm/mach-iop13xx/Makefile b/arch/arm/mach-iop13xx/Makefile
index 4185e0586c3..da1609dc0de 100644
--- a/arch/arm/mach-iop13xx/Makefile
+++ b/arch/arm/mach-iop13xx/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_ARCH_IOP13XX) += setup.o
obj-$(CONFIG_ARCH_IOP13XX) += irq.o
obj-$(CONFIG_ARCH_IOP13XX) += pci.o
obj-$(CONFIG_ARCH_IOP13XX) += io.o
+obj-$(CONFIG_ARCH_IOP13XX) += tpmi.o
obj-$(CONFIG_MACH_IQ81340SC) += iq81340sc.o
obj-$(CONFIG_MACH_IQ81340MC) += iq81340mc.o
diff --git a/arch/arm/mach-iop13xx/io.c b/arch/arm/mach-iop13xx/io.c
index e79a1b62600..5b22fdeca52 100644
--- a/arch/arm/mach-iop13xx/io.c
+++ b/arch/arm/mach-iop13xx/io.c
@@ -41,7 +41,7 @@ void * __iomem __iop13xx_io(unsigned long io_addr)
EXPORT_SYMBOL(__iop13xx_io);
void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
- unsigned long flags)
+ unsigned int mtype)
{
void __iomem * retval;
@@ -61,9 +61,9 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
(cookie - IOP13XX_PCIE_LOWER_MEM_RA));
break;
case IOP13XX_PBI_LOWER_MEM_RA ... IOP13XX_PBI_UPPER_MEM_RA:
- retval = __ioremap(IOP13XX_PBI_LOWER_MEM_PA +
- (cookie - IOP13XX_PBI_LOWER_MEM_RA),
- size, flags);
+ retval = __arm_ioremap(IOP13XX_PBI_LOWER_MEM_PA +
+ (cookie - IOP13XX_PBI_LOWER_MEM_RA),
+ size, mtype);
break;
case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
@@ -75,7 +75,7 @@ void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size,
retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
break;
default:
- retval = __ioremap(cookie, size, flags);
+ retval = __arm_ioremap(cookie, size, mtype);
}
return retval;
diff --git a/arch/arm/mach-iop13xx/iq81340mc.c b/arch/arm/mach-iop13xx/iq81340mc.c
index a519d707571..268a8d84999 100644
--- a/arch/arm/mach-iop13xx/iq81340mc.c
+++ b/arch/arm/mach-iop13xx/iq81340mc.c
@@ -75,11 +75,14 @@ static void __init iq81340mc_init(void)
{
iop13xx_platform_init();
iq81340mc_pci_init();
+ iop13xx_add_tpmi_devices();
}
static void __init iq81340mc_timer_init(void)
{
- iop_init_time(400000000);
+ unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio();
+ printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq);
+ iop_init_time(bus_freq);
}
static struct sys_timer iq81340mc_timer = {
diff --git a/arch/arm/mach-iop13xx/iq81340sc.c b/arch/arm/mach-iop13xx/iq81340sc.c
index 0e71fbcabe0..a51ffd2683e 100644
--- a/arch/arm/mach-iop13xx/iq81340sc.c
+++ b/arch/arm/mach-iop13xx/iq81340sc.c
@@ -77,11 +77,14 @@ static void __init iq81340sc_init(void)
{
iop13xx_platform_init();
iq81340sc_pci_init();
+ iop13xx_add_tpmi_devices();
}
static void __init iq81340sc_timer_init(void)
{
- iop_init_time(400000000);
+ unsigned long bus_freq = iop13xx_core_freq() / iop13xx_xsi_bus_ratio();
+ printk(KERN_DEBUG "%s: bus frequency: %lu\n", __FUNCTION__, bus_freq);
+ iop_init_time(bus_freq);
}
static struct sys_timer iq81340sc_timer = {
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 89ec70ea318..d1d0d32ca77 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -88,9 +88,9 @@ void iop13xx_map_pci_memory(void)
if (end) {
iop13xx_atux_mem_base =
- (u32) __ioremap_pfn(
+ (u32) __arm_ioremap_pfn(
__phys_to_pfn(IOP13XX_PCIX_LOWER_MEM_PA)
- , 0, iop13xx_atux_mem_size, 0);
+ , 0, iop13xx_atux_mem_size, MT_DEVICE);
if (!iop13xx_atux_mem_base) {
printk("%s: atux allocation "
"failed\n", __FUNCTION__);
@@ -114,9 +114,9 @@ void iop13xx_map_pci_memory(void)
if (end) {
iop13xx_atue_mem_base =
- (u32) __ioremap_pfn(
+ (u32) __arm_ioremap_pfn(
__phys_to_pfn(IOP13XX_PCIE_LOWER_MEM_PA)
- , 0, iop13xx_atue_mem_size, 0);
+ , 0, iop13xx_atue_mem_size, MT_DEVICE);
if (!iop13xx_atue_mem_base) {
printk("%s: atue allocation "
"failed\n", __FUNCTION__);
@@ -1023,7 +1023,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
<< IOP13XX_ATUX_PCIXSR_FUNC_NUM;
__raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR);
- res[0].start = IOP13XX_PCIX_LOWER_IO_PA;
+ res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET;
res[0].end = IOP13XX_PCIX_UPPER_IO_PA;
res[0].name = "IQ81340 ATUX PCI I/O Space";
res[0].flags = IORESOURCE_IO;
@@ -1033,7 +1033,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
res[1].name = "IQ81340 ATUX PCI Memory Space";
res[1].flags = IORESOURCE_MEM;
sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET;
- sys->io_offset = IOP13XX_PCIX_IO_OFFSET;
+ sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA;
break;
case IOP13XX_INIT_ATU_ATUE:
/* Note: the function number field in the PCSR is ro */
@@ -1044,7 +1044,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
__raw_writel(pcsr, IOP13XX_ATUE_PCSR);
- res[0].start = IOP13XX_PCIE_LOWER_IO_PA;
+ res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET;
res[0].end = IOP13XX_PCIE_UPPER_IO_PA;
res[0].name = "IQ81340 ATUE PCI I/O Space";
res[0].flags = IORESOURCE_IO;
@@ -1054,7 +1054,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
res[1].name = "IQ81340 ATUE PCI Memory Space";
res[1].flags = IORESOURCE_MEM;
sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET;
- sys->io_offset = IOP13XX_PCIE_IO_OFFSET;
+ sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA;
sys->map_irq = iop13xx_pcie_map_irq;
break;
default:
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index 9a46bcd5f18..bc4871553f6 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -258,15 +258,11 @@ void __init iop13xx_platform_init(void)
if (init_uart == IOP13XX_INIT_UART_DEFAULT) {
switch (iop13xx_dev_id()) {
- /* enable both uarts on iop341 and iop342 */
+ /* enable both uarts on iop341 */
case 0x3380:
case 0x3384:
case 0x3388:
case 0x338c:
- case 0x3382:
- case 0x3386:
- case 0x338a:
- case 0x338e:
init_uart |= IOP13XX_INIT_UART_0;
init_uart |= IOP13XX_INIT_UART_1;
break;
diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c
new file mode 100644
index 00000000000..d3dc278213d
--- /dev/null
+++ b/arch/arm/mach-iop13xx/tpmi.c
@@ -0,0 +1,234 @@
+/*
+ * iop13xx tpmi device resources
+ * Copyright (c) 2005-2006, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/sizes.h>
+
+/* assumes CONTROLLER_ONLY# is never asserted in the ESSR register */
+#define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12))
+#define IOP13XX_TPMI_MEM(dev) IOP13XX_REG_ADDR32_PHYS(0x60000 + (dev << 13))
+#define IOP13XX_TPMI_CTRL(dev) IOP13XX_REG_ADDR32_PHYS(0x50000 + (dev << 10))
+#define IOP13XX_TPMI_MMR_SIZE (SZ_4K - 1)
+#define IOP13XX_TPMI_MEM_SIZE (255)
+#define IOP13XX_TPMI_MEM_CTRL (SZ_1K - 1)
+#define IOP13XX_TPMI_RESOURCE_MMR 0
+#define IOP13XX_TPMI_RESOURCE_MEM 1
+#define IOP13XX_TPMI_RESOURCE_CTRL 2
+#define IOP13XX_TPMI_RESOURCE_IRQ 3
+
+static struct resource iop13xx_tpmi_0_resources[] = {
+ [IOP13XX_TPMI_RESOURCE_MMR] = {
+ .start = IOP13XX_TPMI_MMR(4), /* tpmi0 starts at dev == 4 */
+ .end = IOP13XX_TPMI_MMR(4) + IOP13XX_TPMI_MMR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_MEM] = {
+ .start = IOP13XX_TPMI_MEM(0),
+ .end = IOP13XX_TPMI_MEM(0) + IOP13XX_TPMI_MEM_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_CTRL] = {
+ .start = IOP13XX_TPMI_CTRL(0),
+ .end = IOP13XX_TPMI_CTRL(0) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_IRQ] = {
+ .start = IRQ_IOP13XX_TPMI0_OUT,
+ .end = IRQ_IOP13XX_TPMI0_OUT,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct resource iop13xx_tpmi_1_resources[] = {
+ [IOP13XX_TPMI_RESOURCE_MMR] = {
+ .start = IOP13XX_TPMI_MMR(1),
+ .end = IOP13XX_TPMI_MMR(1) + IOP13XX_TPMI_MMR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_MEM] = {
+ .start = IOP13XX_TPMI_MEM(1),
+ .end = IOP13XX_TPMI_MEM(1) + IOP13XX_TPMI_MEM_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_CTRL] = {
+ .start = IOP13XX_TPMI_CTRL(1),
+ .end = IOP13XX_TPMI_CTRL(1) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_IRQ] = {
+ .start = IRQ_IOP13XX_TPMI1_OUT,
+ .end = IRQ_IOP13XX_TPMI1_OUT,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct resource iop13xx_tpmi_2_resources[] = {
+ [IOP13XX_TPMI_RESOURCE_MMR] = {
+ .start = IOP13XX_TPMI_MMR(2),
+ .end = IOP13XX_TPMI_MMR(2) + IOP13XX_TPMI_MMR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_MEM] = {
+ .start = IOP13XX_TPMI_MEM(2),
+ .end = IOP13XX_TPMI_MEM(2) + IOP13XX_TPMI_MEM_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_CTRL] = {
+ .start = IOP13XX_TPMI_CTRL(2),
+ .end = IOP13XX_TPMI_CTRL(2) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_IRQ] = {
+ .start = IRQ_IOP13XX_TPMI2_OUT,
+ .end = IRQ_IOP13XX_TPMI2_OUT,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct resource iop13xx_tpmi_3_resources[] = {
+ [IOP13XX_TPMI_RESOURCE_MMR] = {
+ .start = IOP13XX_TPMI_MMR(3),
+ .end = IOP13XX_TPMI_MMR(3) + IOP13XX_TPMI_MMR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_MEM] = {
+ .start = IOP13XX_TPMI_MEM(3),
+ .end = IOP13XX_TPMI_MEM(3) + IOP13XX_TPMI_MEM_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_CTRL] = {
+ .start = IOP13XX_TPMI_CTRL(3),
+ .end = IOP13XX_TPMI_CTRL(3) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
+ [IOP13XX_TPMI_RESOURCE_IRQ] = {
+ .start = IRQ_IOP13XX_TPMI3_OUT,
+ .end = IRQ_IOP13XX_TPMI3_OUT,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+u64 iop13xx_tpmi_mask = DMA_64BIT_MASK;
+static struct platform_device iop13xx_tpmi_0_device = {
+ .name = "iop-tpmi",
+ .id = 0,
+ .num_resources = 4,
+ .resource = iop13xx_tpmi_0_resources,
+ .dev = {
+ .dma_mask = &iop13xx_tpmi_mask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ },
+};
+
+static struct platform_device iop13xx_tpmi_1_device = {
+ .name = "iop-tpmi",
+ .id = 1,
+ .num_resources = 4,
+ .resource = iop13xx_tpmi_1_resources,
+ .dev = {
+ .dma_mask = &iop13xx_tpmi_mask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ },
+};
+
+static struct platform_device iop13xx_tpmi_2_device = {
+ .name = "iop-tpmi",
+ .id = 2,
+ .num_resources = 4,
+ .resource = iop13xx_tpmi_2_resources,
+ .dev = {
+ .dma_mask = &iop13xx_tpmi_mask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ },
+};
+
+static struct platform_device iop13xx_tpmi_3_device = {
+ .name = "iop-tpmi",
+ .id = 3,
+ .num_resources = 4,
+ .resource = iop13xx_tpmi_3_resources,
+ .dev = {
+ .dma_mask = &iop13xx_tpmi_mask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ },
+};
+
+__init void iop13xx_add_tpmi_devices(void)
+{
+ unsigned short device_id;
+
+ /* tpmi's not present on iop341 or iop342 */
+ if (__raw_readl(IOP13XX_ESSR0) & IOP13XX_INTERFACE_SEL_PCIX)
+ /* ATUE must be present */
+ device_id = __raw_readw(IOP13XX_ATUE_DID);
+ else
+ /* ATUX must be present */
+ device_id = __raw_readw(IOP13XX_ATUX_DID);
+
+ switch (device_id) {
+ /* iop34[1|2] 0-tpmi */
+ case 0x3380:
+ case 0x3384:
+ case 0x3388:
+ case 0x338c:
+ case 0x3382:
+ case 0x3386:
+ case 0x338a:
+ case 0x338e:
+ return;
+ /* iop348 1-tpmi */
+ case 0x3310:
+ case 0x3312:
+ case 0x3314:
+ case 0x3318:
+ case 0x331a:
+ case 0x331c:
+ case 0x33c0:
+ case 0x33c2:
+ case 0x33c4:
+ case 0x33c8:
+ case 0x33ca:
+ case 0x33cc:
+ case 0x33b0:
+ case 0x33b2:
+ case 0x33b4:
+ case 0x33b8:
+ case 0x33ba:
+ case 0x33bc:
+ case 0x3320:
+ case 0x3322:
+ case 0x3324:
+ case 0x3328:
+ case 0x332a:
+ case 0x332c:
+ platform_device_register(&iop13xx_tpmi_0_device);
+ return;
+ default:
+ platform_device_register(&iop13xx_tpmi_0_device);
+ platform_device_register(&iop13xx_tpmi_1_device);
+ platform_device_register(&iop13xx_tpmi_2_device);
+ platform_device_register(&iop13xx_tpmi_3_device);
+ return;
+ }
+}
diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig
index 9dd49cff21f..9bb02b6d7ae 100644
--- a/arch/arm/mach-iop32x/Kconfig
+++ b/arch/arm/mach-iop32x/Kconfig
@@ -34,6 +34,14 @@ config MACH_N2100
Say Y here if you want to run your kernel on the Thecus n2100
NAS appliance.
+config IOP3XX_ATU
+ bool "Enable the PCI Controller"
+ default y
+ help
+ Say Y here if you want the IOP to initialize its PCI Controller.
+ Say N if the IOP is an add in card, the host system owns the PCI
+ bus in this case.
+
endmenu
endif
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
index 60e74309a45..7b21c6e13e5 100644
--- a/arch/arm/mach-iop32x/iq31244.c
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -178,9 +178,10 @@ static struct hw_pci iq31244_pci __initdata = {
static int __init iq31244_pci_init(void)
{
- if (is_ep80219())
- pci_common_init(&ep80219_pci);
- else if (machine_is_iq31244()) {
+ if (is_ep80219()) {
+ if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE)
+ pci_common_init(&ep80219_pci);
+ } else if (machine_is_iq31244()) {
if (is_80219()) {
printk("note: iq31244 board type has been selected\n");
printk("note: to select ep80219 operation:\n");
@@ -189,7 +190,9 @@ static int __init iq31244_pci_init(void)
printk("\t2/ update boot loader to pass"
" the ep80219 id: %d\n", MACH_TYPE_EP80219);
}
- pci_common_init(&iq31244_pci);
+
+ if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE)
+ pci_common_init(&iq31244_pci);
}
return 0;
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
index 361c70c0f64..bc25fb91e7b 100644
--- a/arch/arm/mach-iop32x/iq80321.c
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -113,7 +113,8 @@ static struct hw_pci iq80321_pci __initdata = {
static int __init iq80321_pci_init(void)
{
- if (machine_is_iq80321())
+ if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
+ machine_is_iq80321())
pci_common_init(&iq80321_pci);
return 0;
diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig
index 9aa016bb18f..45598e09689 100644
--- a/arch/arm/mach-iop33x/Kconfig
+++ b/arch/arm/mach-iop33x/Kconfig
@@ -16,6 +16,14 @@ config MACH_IQ80332
Say Y here if you want to run your kernel on the Intel IQ80332
evaluation kit for the IOP332 chipset.
+config IOP3XX_ATU
+ bool "Enable the PCI Controller"
+ default y
+ help
+ Say Y here if you want the IOP to initialize its PCI Controller.
+ Say N if the IOP is an add in card, the host system owns the PCI
+ bus in this case.
+
endmenu
endif
diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
index 1a9e36138d8..376c932830b 100644
--- a/arch/arm/mach-iop33x/iq80331.c
+++ b/arch/arm/mach-iop33x/iq80331.c
@@ -96,7 +96,8 @@ static struct hw_pci iq80331_pci __initdata = {
static int __init iq80331_pci_init(void)
{
- if (machine_is_iq80331())
+ if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
+ machine_is_iq80331())
pci_common_init(&iq80331_pci);
return 0;
diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
index 96d6f0f3cd2..58c81496c6f 100644
--- a/arch/arm/mach-iop33x/iq80332.c
+++ b/arch/arm/mach-iop33x/iq80332.c
@@ -96,7 +96,8 @@ static struct hw_pci iq80332_pci __initdata = {
static int __init iq80332_pci_init(void)
{
- if (machine_is_iq80332())
+ if ((iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) &&
+ machine_is_iq80332())
pci_common_init(&iq80332_pci);
return 0;
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 27b7480f4af..cb6ad211887 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -84,59 +84,59 @@ static struct map_desc ixp2000_io_desc[] __initdata = {
.virtual = IXP2000_CAP_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
.length = IXP2000_CAP_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_INTCTL_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
.length = IXP2000_INTCTL_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_PCI_CREG_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
.length = IXP2000_PCI_CREG_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_PCI_CSR_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
.length = IXP2000_PCI_CSR_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_MSF_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
.length = IXP2000_MSF_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_SCRATCH_RING_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
.length = IXP2000_SCRATCH_RING_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_SRAM0_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
.length = IXP2000_SRAM0_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_PCI_IO_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
.length = IXP2000_PCI_IO_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_PCI_CFG0_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
.length = IXP2000_PCI_CFG0_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = IXP2000_PCI_CFG1_VIRT_BASE,
.pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
.length = IXP2000_PCI_CFG1_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}
};
void __init ixp2000_map_io(void)
{
/*
- * On IXP2400 CPUs we need to use MT_IXP2000_DEVICE so that
+ * On IXP2400 CPUs we need to use MT_DEVICE_IXP2000 so that
* XCB=101 (to avoid triggering erratum #66), and given that
* this mode speeds up I/O accesses and we have write buffer
* flushes in the right places anyway, it doesn't hurt to use
@@ -224,7 +224,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id)
static struct irqaction ixp2000_timer_irq = {
.name = "IXP2000 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = ixp2000_timer_interrupt,
};
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index ac29298c5d3..500e997ba7a 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -70,17 +70,17 @@ static struct map_desc enp2611_io_desc[] __initdata = {
.virtual = ENP2611_CALEB_VIRT_BASE,
.pfn = __phys_to_pfn(ENP2611_CALEB_PHYS_BASE),
.length = ENP2611_CALEB_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = ENP2611_PM3386_0_VIRT_BASE,
.pfn = __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE),
.length = ENP2611_PM3386_0_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}, {
.virtual = ENP2611_PM3386_1_VIRT_BASE,
.pfn = __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE),
.length = ENP2611_PM3386_1_SIZE,
- .type = MT_IXP2000_DEVICE,
+ .type = MT_DEVICE_IXP2000,
}
};
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index ce6ad635a00..b644bbab7d0 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -363,7 +363,7 @@ ixp23xx_timer_interrupt(int irq, void *dev_id)
static struct irqaction ixp23xx_timer_irq = {
.name = "IXP23xx Timer Tick",
.handler = ixp23xx_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};
void __init ixp23xx_init_timer(void)
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 8a339cdfe22..9715ef506c2 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -62,6 +62,12 @@ config MACH_IXDP465
IXDP465 Development Platform (Also known as BMP).
For more information on this platform, see <file:Documentation/arm/IXP4xx>.
+config MACH_KIXRP435
+ bool "KIXRP435"
+ help
+ Say 'Y' here if you want your kernel to support Intel's
+ KIXRP435 Reference Platform.
+ For more information on this platform, see <file:Documentation/arm/IXP4xx>.
#
# IXCDP1100 is the exact same HW as IXDP425, but with a different machine
@@ -89,12 +95,21 @@ config MACH_NAS100D
NAS 100d device. For more information on this platform,
see http://www.nslu2-linux.org/wiki/NAS100d/HomePage
+config MACH_DSMG600
+ bool
+ prompt "D-Link DSM-G600 RevA"
+ select PCI
+ help
+ Say 'Y' here if you want your kernel to support D-Link's
+ DSM-G600 RevA device. For more information on this platform,
+ see http://www.nslu2-linux.org/wiki/DSMG600/HomePage
+
#
# Avila and IXDP share the same source for now. Will change in future
#
config ARCH_IXDP4XX
bool
- depends on ARCH_IXDP425 || MACH_IXDP465
+ depends on ARCH_IXDP425 || MACH_IXDP465 || MACH_KIXRP435
default y
#
@@ -105,6 +120,11 @@ config CPU_IXP46X
depends on MACH_IXDP465
default y
+config CPU_IXP43X
+ bool
+ depends on MACH_KIXRP435
+ default y
+
config MACH_GTWX5715
bool "Gemtek WX5715 (Linksys WRV54G)"
depends on ARCH_IXP4XX
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index 746e297284e..3b87c47e06c 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -12,6 +12,7 @@ obj-pci-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o
obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o
obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-pci.o
obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o
+obj-pci-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o
obj-y += common.o
@@ -22,5 +23,6 @@ obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-setup.o
obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o
obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o
obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o
+obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o
obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index 9562177b5fe..bf04121d1a3 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -374,7 +374,7 @@ void __init ixp4xx_pci_preinit(void)
* Determine which PCI read method to use.
* Rev 0 IXP425 requires workaround.
*/
- if (!(processor_id & 0xf) && !cpu_is_ixp46x()) {
+ if (!(processor_id & 0xf) && cpu_is_ixp42x()) {
printk("PCI: IXP42x A0 silicon detected - "
"PCI Non-Prefetch Workaround Enabled\n");
ixp4xx_pci_read = ixp4xx_pci_read_errata;
@@ -480,7 +480,7 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys)
res[0].flags = IORESOURCE_IO;
res[1].name = "PCI Memory Space";
- res[1].start = 0x48000000;
+ res[1].start = PCIBIOS_MIN_MEM;
#ifndef CONFIG_IXP4XX_INDIRECT_PCI
res[1].end = 0x4bffffff;
#else
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 45068c3d8dc..64685da1462 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -27,6 +27,7 @@
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/arch/udc.h>
#include <asm/hardware.h>
@@ -41,6 +42,8 @@
#include <asm/mach/time.h>
static int __init ixp4xx_clocksource_init(void);
+static int __init ixp4xx_clockevent_init(void);
+static struct clock_event_device clockevent_ixp4xx;
/*************************************************************************
* IXP4xx chipset I/O mapping
@@ -102,6 +105,29 @@ static signed char irq2gpio[32] = {
7, 8, 9, 10, 11, 12, -1, -1,
};
+int gpio_to_irq(int gpio)
+{
+ int irq;
+
+ for (irq = 0; irq < 32; irq++) {
+ if (irq2gpio[irq] == gpio)
+ return irq;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(int irq)
+{
+ int gpio = (irq < 32) ? irq2gpio[irq] : -EINVAL;
+
+ if (gpio == -1)
+ return -EINVAL;
+
+ return gpio;
+}
+EXPORT_SYMBOL(irq_to_gpio);
+
static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
{
int line = irq2gpio[irq];
@@ -169,7 +195,7 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
static void ixp4xx_irq_mask(unsigned int irq)
{
- if (cpu_is_ixp46x() && irq >= 32)
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
*IXP4XX_ICMR2 &= ~(1 << (irq - 32));
else
*IXP4XX_ICMR &= ~(1 << irq);
@@ -192,7 +218,7 @@ static void ixp4xx_irq_unmask(unsigned int irq)
if (!(ixp4xx_irq_edge & (1 << irq)))
ixp4xx_irq_ack(irq);
- if (cpu_is_ixp46x() && irq >= 32)
+ if ((cpu_is_ixp46x() || cpu_is_ixp43x()) && irq >= 32)
*IXP4XX_ICMR2 |= (1 << (irq - 32));
else
*IXP4XX_ICMR |= (1 << irq);
@@ -216,7 +242,7 @@ void __init ixp4xx_init_irq(void)
/* Disable all interrupt */
*IXP4XX_ICMR = 0x0;
- if (cpu_is_ixp46x()) {
+ if (cpu_is_ixp46x() || cpu_is_ixp43x()) {
/* Route upper 32 sources to IRQ instead of FIQ */
*IXP4XX_ICLR2 = 0x00;
@@ -239,52 +265,40 @@ void __init ixp4xx_init_irq(void)
* counter as a source of real clock ticks to account for missed jiffies.
*************************************************************************/
-static unsigned volatile last_jiffy_time;
-
-#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
-
static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
+ struct clock_event_device *evt = &clockevent_ixp4xx;
/* Clear Pending Interrupt by writing '1' to it */
*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
- /*
- * Catch up with the real idea of time
- */
- while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
- timer_tick();
- last_jiffy_time += LATCH;
- }
-
- write_sequnlock(&xtime_lock);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction ixp4xx_timer_irq = {
- .name = "IXP4xx Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .name = "timer1",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = ixp4xx_timer_interrupt,
};
static void __init ixp4xx_timer_init(void)
{
+ /* Reset/disable counter */
+ *IXP4XX_OSRT1 = 0;
+
/* Clear Pending Interrupt by writing '1' to it */
*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
- /* Setup the Timer counter value */
- *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
-
/* Reset time-stamp counter */
*IXP4XX_OSTS = 0;
- last_jiffy_time = 0;
/* Connect the interrupt handler and enable the interrupt */
setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
ixp4xx_clocksource_init();
+ ixp4xx_clockevent_init();
}
struct sys_timer ixp4xx_timer = {
@@ -384,6 +398,9 @@ void __init ixp4xx_sys_init(void)
ixp4xx_exp_bus_size >> 20);
}
+/*
+ * clocksource
+ */
cycle_t ixp4xx_get_cycles(void)
{
return *IXP4XX_OSTS;
@@ -408,3 +425,64 @@ static int __init ixp4xx_clocksource_init(void)
return 0;
}
+
+/*
+ * clockevents
+ */
+static int ixp4xx_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long opts = *IXP4XX_OSRT1 & IXP4XX_OST_RELOAD_MASK;
+
+ *IXP4XX_OSRT1 = (evt & ~IXP4XX_OST_RELOAD_MASK) | opts;
+
+ return 0;
+}
+
+static void ixp4xx_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ unsigned long opts, osrt = *IXP4XX_OSRT1 & ~IXP4XX_OST_RELOAD_MASK;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ osrt = LATCH & ~IXP4XX_OST_RELOAD_MASK;
+ opts = IXP4XX_OST_ENABLE;
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* period set by 'set next_event' */
+ osrt = 0;
+ opts = IXP4XX_OST_ENABLE | IXP4XX_OST_ONE_SHOT;
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ default:
+ osrt = opts = 0;
+ break;
+ }
+
+ *IXP4XX_OSRT1 = osrt | opts;
+}
+
+static struct clock_event_device clockevent_ixp4xx = {
+ .name = "ixp4xx timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 200,
+ .shift = 24,
+ .set_mode = ixp4xx_set_mode,
+ .set_next_event = ixp4xx_set_next_event,
+};
+
+static int __init ixp4xx_clockevent_init(void)
+{
+ clockevent_ixp4xx.mult = div_sc(FREQ, NSEC_PER_SEC,
+ clockevent_ixp4xx.shift);
+ clockevent_ixp4xx.max_delta_ns =
+ clockevent_delta2ns(0xfffffffe, &clockevent_ixp4xx);
+ clockevent_ixp4xx.min_delta_ns =
+ clockevent_delta2ns(0xf, &clockevent_ixp4xx);
+ clockevent_ixp4xx.cpumask = cpumask_of_cpu(0);
+
+ clockevents_register_device(&clockevent_ixp4xx);
+ return 0;
+}
diff --git a/arch/arm/mach-ixp4xx/dsmg600-pci.c b/arch/arm/mach-ixp4xx/dsmg600-pci.c
new file mode 100644
index 00000000000..9db7e1f4201
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/dsmg600-pci.c
@@ -0,0 +1,74 @@
+/*
+ * DSM-G600 board-level PCI initialization
+ *
+ * Copyright (C) 2006 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on ixdp425-pci.c:
+ * Copyright (C) 2002 Intel Corporation.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Maintainer: http://www.nslu2-linux.org/
+ *
+ * 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/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/mach/pci.h>
+#include <asm/mach-types.h>
+
+void __init dsmg600_pci_preinit(void)
+{
+ set_irq_type(IRQ_DSMG600_PCI_INTA, IRQT_LOW);
+ set_irq_type(IRQ_DSMG600_PCI_INTB, IRQT_LOW);
+ set_irq_type(IRQ_DSMG600_PCI_INTC, IRQT_LOW);
+ set_irq_type(IRQ_DSMG600_PCI_INTD, IRQT_LOW);
+ set_irq_type(IRQ_DSMG600_PCI_INTE, IRQT_LOW);
+ set_irq_type(IRQ_DSMG600_PCI_INTF, IRQT_LOW);
+
+ ixp4xx_pci_preinit();
+}
+
+static int __init dsmg600_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static int pci_irq_table[DSMG600_PCI_MAX_DEV][DSMG600_PCI_IRQ_LINES] =
+ {
+ { IRQ_DSMG600_PCI_INTE, -1, -1 },
+ { IRQ_DSMG600_PCI_INTA, -1, -1 },
+ { IRQ_DSMG600_PCI_INTB, IRQ_DSMG600_PCI_INTC, IRQ_DSMG600_PCI_INTD },
+ { IRQ_DSMG600_PCI_INTF, -1, -1 },
+ };
+
+ int irq = -1;
+
+ if (slot >= 1 && slot <= DSMG600_PCI_MAX_DEV &&
+ pin >= 1 && pin <= DSMG600_PCI_IRQ_LINES)
+ irq = pci_irq_table[slot-1][pin-1];
+
+ return irq;
+}
+
+struct hw_pci __initdata dsmg600_pci = {
+ .nr_controllers = 1,
+ .preinit = dsmg600_pci_preinit,
+ .swizzle = pci_std_swizzle,
+ .setup = ixp4xx_setup,
+ .scan = ixp4xx_scan_bus,
+ .map_irq = dsmg600_map_irq,
+};
+
+int __init dsmg600_pci_init(void)
+{
+ if (machine_is_dsmg600())
+ pci_common_init(&dsmg600_pci);
+
+ return 0;
+}
+
+subsys_initcall(dsmg600_pci_init);
diff --git a/arch/arm/mach-ixp4xx/dsmg600-power.c b/arch/arm/mach-ixp4xx/dsmg600-power.c
new file mode 100644
index 00000000000..34717872d07
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/dsmg600-power.c
@@ -0,0 +1,125 @@
+/*
+ * arch/arm/mach-ixp4xx/dsmg600-power.c
+ *
+ * DSM-G600 Power/Reset driver
+ * Author: Michael Westerhof <mwester@dls.net>
+ *
+ * Based on nslu2-power.c
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * which was based on nslu2-io.c
+ * Copyright (C) 2004 Karen Spearel
+ *
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * 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/module.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+
+#include <asm/mach-types.h>
+
+extern void ctrl_alt_del(void);
+
+/* This is used to make sure the power-button pusher is serious. The button
+ * must be held until the value of this counter reaches zero.
+ */
+static volatile int power_button_countdown;
+
+/* Must hold the button down for at least this many counts to be processed */
+#define PBUTTON_HOLDDOWN_COUNT 4 /* 2 secs */
+
+static void dsmg600_power_handler(unsigned long data);
+static DEFINE_TIMER(dsmg600_power_timer, dsmg600_power_handler, 0, 0);
+
+static void dsmg600_power_handler(unsigned long data)
+{
+ /* This routine is called twice per second to check the
+ * state of the power button.
+ */
+
+ if (*IXP4XX_GPIO_GPINR & DSMG600_PB_BM) {
+
+ /* IO Pin is 1 (button pushed) */
+ if (power_button_countdown == 0) {
+ /* Signal init to do the ctrlaltdel action, this will bypass
+ * init if it hasn't started and do a kernel_restart.
+ */
+ ctrl_alt_del();
+
+ /* Change the state of the power LED to "blink" */
+ gpio_line_set(DSMG600_LED_PWR_GPIO, IXP4XX_GPIO_LOW);
+ }
+ power_button_countdown--;
+
+ } else {
+ power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+ }
+
+ mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
+}
+
+static irqreturn_t dsmg600_reset_handler(int irq, void *dev_id)
+{
+ /* This is the paper-clip reset, it shuts the machine down directly. */
+ machine_power_off();
+
+ return IRQ_HANDLED;
+}
+
+static int __init dsmg600_power_init(void)
+{
+ if (!(machine_is_dsmg600()))
+ return 0;
+
+ if (request_irq(DSMG600_RB_IRQ, &dsmg600_reset_handler,
+ IRQF_DISABLED | IRQF_TRIGGER_LOW, "DSM-G600 reset button",
+ NULL) < 0) {
+
+ printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
+ DSMG600_RB_IRQ);
+
+ return -EIO;
+ }
+
+ /* The power button on the D-Link DSM-G600 is on GPIO 15, but
+ * it cannot handle interrupts on that GPIO line. So we'll
+ * have to poll it with a kernel timer.
+ */
+
+ /* Make sure that the power button GPIO is set up as an input */
+ gpio_line_config(DSMG600_PB_GPIO, IXP4XX_GPIO_IN);
+
+ /* Set the initial value for the power button IRQ handler */
+ power_button_countdown = PBUTTON_HOLDDOWN_COUNT;
+
+ mod_timer(&dsmg600_power_timer, jiffies + msecs_to_jiffies(500));
+
+ return 0;
+}
+
+static void __exit dsmg600_power_exit(void)
+{
+ if (!(machine_is_dsmg600()))
+ return;
+
+ del_timer_sync(&dsmg600_power_timer);
+
+ free_irq(DSMG600_RB_IRQ, NULL);
+}
+
+module_init(dsmg600_power_init);
+module_exit(dsmg600_power_exit);
+
+MODULE_AUTHOR("Michael Westerhof <mwester@dls.net>");
+MODULE_DESCRIPTION("DSM-G600 Power/Reset driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
new file mode 100644
index 00000000000..1caff65e22c
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -0,0 +1,175 @@
+/*
+ * DSM-G600 board-setup
+ *
+ * Copyright (C) 2006 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based ixdp425-setup.c:
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ */
+
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+static struct flash_platform_data dsmg600_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+};
+
+static struct resource dsmg600_flash_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device dsmg600_flash = {
+ .name = "IXP4XX-Flash",
+ .id = 0,
+ .dev.platform_data = &dsmg600_flash_data,
+ .num_resources = 1,
+ .resource = &dsmg600_flash_resource,
+};
+
+static struct ixp4xx_i2c_pins dsmg600_i2c_gpio_pins = {
+ .sda_pin = DSMG600_SDA_PIN,
+ .scl_pin = DSMG600_SCL_PIN,
+};
+
+static struct platform_device dsmg600_i2c_controller = {
+ .name = "IXP4XX-I2C",
+ .id = 0,
+ .dev.platform_data = &dsmg600_i2c_gpio_pins,
+};
+
+#ifdef CONFIG_LEDS_CLASS
+static struct resource dsmg600_led_resources[] = {
+ {
+ .name = "power",
+ .start = DSMG600_LED_PWR_GPIO,
+ .end = DSMG600_LED_PWR_GPIO,
+ .flags = IXP4XX_GPIO_HIGH,
+ },
+ {
+ .name = "wlan",
+ .start = DSMG600_LED_WLAN_GPIO,
+ .end = DSMG600_LED_WLAN_GPIO,
+ .flags = IXP4XX_GPIO_LOW,
+ },
+};
+
+static struct platform_device dsmg600_leds = {
+ .name = "IXP4XX-GPIO-LED",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dsmg600_led_resources),
+ .resource = dsmg600_led_resources,
+};
+#endif
+
+static struct resource dsmg600_uart_resources[] = {
+ {
+ .start = IXP4XX_UART1_BASE_PHYS,
+ .end = IXP4XX_UART1_BASE_PHYS + 0x0fff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IXP4XX_UART2_BASE_PHYS,
+ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct plat_serial8250_port dsmg600_uart_data[] = {
+ {
+ .mapbase = IXP4XX_UART1_BASE_PHYS,
+ .membase = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
+ .irq = IRQ_IXP4XX_UART1,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = IXP4XX_UART_XTAL,
+ },
+ {
+ .mapbase = IXP4XX_UART2_BASE_PHYS,
+ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+ .irq = IRQ_IXP4XX_UART2,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = IXP4XX_UART_XTAL,
+ },
+ { }
+};
+
+static struct platform_device dsmg600_uart = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev.platform_data = dsmg600_uart_data,
+ .num_resources = ARRAY_SIZE(dsmg600_uart_resources),
+ .resource = dsmg600_uart_resources,
+};
+
+static struct platform_device *dsmg600_devices[] __initdata = {
+ &dsmg600_i2c_controller,
+ &dsmg600_flash,
+};
+
+static void dsmg600_power_off(void)
+{
+ /* enable the pwr cntl gpio */
+ gpio_line_config(DSMG600_PO_GPIO, IXP4XX_GPIO_OUT);
+
+ /* poweroff */
+ gpio_line_set(DSMG600_PO_GPIO, IXP4XX_GPIO_HIGH);
+}
+
+static void __init dsmg600_init(void)
+{
+ ixp4xx_sys_init();
+
+ /* Make sure that GPIO14 and GPIO15 are not used as clocks */
+ *IXP4XX_GPIO_GPCLKR = 0;
+
+ dsmg600_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+ dsmg600_flash_resource.end =
+ IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
+
+ pm_power_off = dsmg600_power_off;
+
+ /* The UART is required on the DSM-G600 (Redboot cannot use the
+ * NIC) -- do it here so that it does *not* get removed if
+ * platform_add_devices fails!
+ */
+ (void)platform_device_register(&dsmg600_uart);
+
+ platform_add_devices(dsmg600_devices, ARRAY_SIZE(dsmg600_devices));
+
+#ifdef CONFIG_LEDS_CLASS
+ /* We don't care whether or not this works. */
+ (void)platform_device_register(&dsmg600_leds);
+#endif
+}
+
+static void __init dsmg600_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline, struct meminfo *mi)
+{
+ /* The xtal on this machine is non-standard. */
+ ixp4xx_timer_freq = DSMG600_FREQ;
+}
+
+MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
+ /* Maintainer: www.nslu2-linux.org */
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
+ .boot_params = 0x00000100,
+ .fixup = dsmg600_fixup,
+ .map_io = ixp4xx_map_io,
+ .init_irq = ixp4xx_init_irq,
+ .timer = &ixp4xx_timer,
+ .init_machine = dsmg600_init,
+MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/ixdp425-pci.c b/arch/arm/mach-ixp4xx/ixdp425-pci.c
index 99c1dc8033c..40879600481 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-pci.c
@@ -66,7 +66,7 @@ struct hw_pci ixdp425_pci __initdata = {
int __init ixdp425_pci_init(void)
{
if (machine_is_ixdp425() || machine_is_ixcdp1100() ||
- machine_is_ixdp465())
+ machine_is_ixdp465() || machine_is_kixrp435())
pci_common_init(&ixdp425_pci);
return 0;
}
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 04b1d56396a..ec4f07950ec 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -115,6 +115,11 @@ static void __init ixdp425_init(void)
ixdp425_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
+ if (cpu_is_ixp43x()) {
+ ixdp425_uart.num_resources = 1;
+ ixdp425_uart_data[1].flags = 0;
+ }
+
platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices));
}
@@ -156,3 +161,16 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
.init_machine = ixdp425_init,
MACHINE_END
#endif
+
+#ifdef CONFIG_MACH_KIXRP435
+MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixp4xx_map_io,
+ .init_irq = ixp4xx_init_irq,
+ .timer = &ixp4xx_timer,
+ .boot_params = 0x0100,
+ .init_machine = ixdp425_init,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a400.c b/arch/arm/mach-lh7a40x/irq-lh7a400.c
index 0b938e8b4d9..9472bbebd8a 100644
--- a/arch/arm/mach-lh7a40x/irq-lh7a400.c
+++ b/arch/arm/mach-lh7a40x/irq-lh7a400.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <asm/hardware.h>
#include <asm/irq.h>
diff --git a/arch/arm/mach-lh7a40x/irq-lh7a404.c b/arch/arm/mach-lh7a40x/irq-lh7a404.c
index 5760f8c53e8..9b28389035e 100644
--- a/arch/arm/mach-lh7a40x/irq-lh7a404.c
+++ b/arch/arm/mach-lh7a40x/irq-lh7a404.c
@@ -11,7 +11,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <asm/hardware.h>
#include <asm/irq.h>
diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
index 15b9577023c..66e1ed3961e 100644
--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <asm/hardware.h>
#include <asm/irq.h>
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
index bef3c4b68d3..c25316d0253 100644
--- a/arch/arm/mach-lh7a40x/time.c
+++ b/arch/arm/mach-lh7a40x/time.c
@@ -53,7 +53,7 @@ lh7a40x_timer_interrupt(int irq, void *dev_id)
static struct irqaction lh7a40x_timer_irq = {
.name = "LHA740x Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = lh7a40x_timer_interrupt,
};
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index 7e132fcccd4..4762e207b0b 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -47,7 +47,7 @@ netx_timer_interrupt(int irq, void *dev_id)
static struct irqaction netx_timer_irq = {
.name = "NetX Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = netx_timer_interrupt,
};
diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig
index 8175ba92a2f..8584ed10799 100644
--- a/arch/arm/mach-ns9xxx/Kconfig
+++ b/arch/arm/mach-ns9xxx/Kconfig
@@ -3,19 +3,30 @@ if ARCH_NS9XXX
menu "NS9xxx Implementations"
config MACH_CC9P9360DEV
- bool "Connect Core 9P 9360 on an A9M9750 Devboard"
+ bool "ConnectCore 9P 9360 on an A9M9750 Devboard"
select PROCESSOR_NS9360
select BOARD_A9M9750DEV
help
- Say Y here if you are using the Digi Connect Core 9P 9360
+ Say Y here if you are using the Digi ConnectCore 9P 9360
on an A9M9750 Development Board.
+config MACH_CC9P9360JS
+ bool "ConnectCore 9P 9360 on a JSCC9P9360 Devboard"
+ select PROCESSOR_NS9360
+ select BOARD_JSCC9P9360
+ help
+ Say Y here if you are using the Digi ConnectCore 9P 9360
+ on an JSCC9P9360 Development Board.
+
config PROCESSOR_NS9360
bool
config BOARD_A9M9750DEV
bool
+config BOARD_JSCC9P9360
+ bool
+
endmenu
endif
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile
index 91e945f5e16..53213a69f60 100644
--- a/arch/arm/mach-ns9xxx/Makefile
+++ b/arch/arm/mach-ns9xxx/Makefile
@@ -3,3 +3,4 @@ obj-y := irq.o time.o generic.o
obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o
+obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o
diff --git a/arch/arm/mach-ns9xxx/board-jscc9p9360.c b/arch/arm/mach-ns9xxx/board-jscc9p9360.c
new file mode 100644
index 00000000000..4bd3eec04bf
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/board-jscc9p9360.c
@@ -0,0 +1,17 @@
+/*
+ * arch/arm/mach-ns9xxx/board-jscc9p9360.c
+ *
+ * Copyright (C) 2006,2007 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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 "board-jscc9p9360.h"
+
+void __init board_jscc9p9360_init_machine(void)
+{
+ /* TODO: reserve GPIOs for push buttons, etc pp */
+}
+
diff --git a/arch/arm/mach-ns9xxx/board-jscc9p9360.h b/arch/arm/mach-ns9xxx/board-jscc9p9360.h
new file mode 100644
index 00000000000..1a81a074df4
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/board-jscc9p9360.h
@@ -0,0 +1,13 @@
+/*
+ * arch/arm/mach-ns9xxx/board-jscc9p9360.h
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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/init.h>
+
+void __init board_jscc9p9360_init_machine(void);
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
new file mode 100644
index 00000000000..d09d5fa5620
--- /dev/null
+++ b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-ns9xxx/mach-cc9p9360js.c
+ *
+ * Copyright (C) 2006 by Digi International Inc.
+ * All rights reserved.
+ *
+ * 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 <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include "board-jscc9p9360.h"
+#include "generic.h"
+
+static void __init mach_cc9p9360js_init_machine(void)
+{
+ ns9xxx_init_machine();
+ board_jscc9p9360_init_machine();
+}
+
+MACHINE_START(CC9P9360DEV, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
+ .map_io = ns9xxx_map_io,
+ .init_irq = ns9xxx_init_irq,
+ .init_machine = mach_cc9p9360js_init_machine,
+ .timer = &ns9xxx_timer,
+ .boot_params = 0x100,
+MACHINE_END
diff --git a/arch/arm/mach-ns9xxx/time.c b/arch/arm/mach-ns9xxx/time.c
index eec05f18714..dd257084441 100644
--- a/arch/arm/mach-ns9xxx/time.c
+++ b/arch/arm/mach-ns9xxx/time.c
@@ -53,7 +53,7 @@ static unsigned long ns9xxx_timer_gettimeoffset(void)
static struct irqaction ns9xxx_timer_irq = {
.name = "NS9xxx Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = ns9xxx_timer_interrupt,
};
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index 8781aaeb576..856c681ebbb 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -22,6 +22,7 @@ comment "OMAP Board Type"
config MACH_OMAP_INNOVATOR
bool "TI Innovator"
depends on ARCH_OMAP1 && (ARCH_OMAP15XX || ARCH_OMAP16XX)
+ select OMAP_MCBSP
help
TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
have such a board.
@@ -29,6 +30,7 @@ config MACH_OMAP_INNOVATOR
config MACH_OMAP_H2
bool "TI H2 Support"
depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ select OMAP_MCBSP
help
TI OMAP 1610/1611B H2 board support. Say Y here if you have such
a board.
@@ -36,6 +38,7 @@ config MACH_OMAP_H2
config MACH_OMAP_H3
bool "TI H3 Support"
depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ select GPIOEXPANDER_OMAP
help
TI OMAP 1710 H3 board support. Say Y here if you have such
a board.
@@ -43,7 +46,7 @@ config MACH_OMAP_H3
config MACH_OMAP_OSK
bool "TI OSK Support"
depends on ARCH_OMAP1 && ARCH_OMAP16XX
- select TPS65010
+ select OMAP_MCBSP
help
TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
if you have such a board.
@@ -84,7 +87,7 @@ config MACH_OMAP_PALMTE
Support for the Palm Tungsten E PDA. Currently only the LCD panel
is supported. To boot the kernel, you'll need a PalmOS compatible
bootloader; check out http://palmtelinux.sourceforge.net for more
- informations.
+ information.
Say Y here if you have such a PDA, say NO otherwise.
config MACH_NOKIA770
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 7165f74f78d..a8b9a00cea2 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -37,4 +37,3 @@ led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o
led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o
led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o
obj-$(CONFIG_LEDS) += $(led-y)
-
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 62e42c7a628..f65baa95986 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -246,7 +246,7 @@ static void __init fsample_init_smc91x(void)
mdelay(50);
}
-void omap_fsample_init_irq(void)
+static void __init omap_fsample_init_irq(void)
{
omap1_init_common_hw();
omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 9d2346fb68f..7b260b7c537 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -455,7 +455,7 @@ static void __init h3_init_smc91x(void)
}
}
-void h3_init_irq(void)
+static void __init h3_init_irq(void)
{
omap1_init_common_hw();
omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index cb00530ad27..7e63a41e37c 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -308,7 +308,7 @@ static void __init innovator_init_smc91x(void)
}
}
-void innovator_init_irq(void)
+static void __init innovator_init_irq(void)
{
omap1_init_common_hw();
omap_init_irq();
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index fa4be962df6..1d5c8d50972 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -246,7 +246,7 @@ static void __init perseus2_init_smc91x(void)
mdelay(50);
}
-void omap_perseus2_init_irq(void)
+static void __init omap_perseus2_init_irq(void)
{
omap1_init_common_hw();
omap_init_irq();
diff --git a/arch/arm/mach-omap1/devices.c b/arch/arm/mach-omap1/devices.c
index 6dcd10ab449..da8a3ac47e1 100644
--- a/arch/arm/mach-omap1/devices.c
+++ b/arch/arm/mach-omap1/devices.c
@@ -24,35 +24,6 @@
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
-#if defined(CONFIG_OMAP1610_IR) || defined(CONFIG_OMAP161O_IR_MODULE)
-
-static u64 irda_dmamask = 0xffffffff;
-
-static struct platform_device omap1610ir_device = {
- .name = "omap1610-ir",
- .id = -1,
- .dev = {
- .dma_mask = &irda_dmamask,
- },
-};
-
-static void omap_init_irda(void)
-{
- /* FIXME define and use a boot tag, members something like:
- * u8 uart; // uart1, or uart3
- * ... but driver only handles uart3 for now
- * s16 fir_sel; // gpio for SIR vs FIR
- * ... may prefer a callback for SIR/MIR/FIR mode select;
- * while h2 uses a GPIO, H3 uses a gpio expander
- */
- if (machine_is_omap_h2()
- || machine_is_omap_h3())
- (void) platform_device_register(&omap1610ir_device);
-}
-#else
-static inline void omap_init_irda(void) {}
-#endif
-
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
@@ -90,6 +61,45 @@ static void omap_init_rtc(void)
static inline void omap_init_rtc(void) {}
#endif
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#if defined(CONFIG_ARCH_OMAP15XX)
+# define OMAP1_MBOX_SIZE 0x23
+# define INT_DSP_MAILBOX1 INT_1510_DSP_MAILBOX1
+#elif defined(CONFIG_ARCH_OMAP16XX)
+# define OMAP1_MBOX_SIZE 0x2f
+# define INT_DSP_MAILBOX1 INT_1610_DSP_MAILBOX1
+#endif
+
+#define OMAP1_MBOX_BASE IO_ADDRESS(OMAP16XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+ {
+ .start = OMAP1_MBOX_BASE,
+ .end = OMAP1_MBOX_BASE + OMAP1_MBOX_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_DSP_MAILBOX1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mbox_device = {
+ .name = "mailbox",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mbox_resources),
+ .resource = mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+ platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
#if defined(CONFIG_OMAP_STI)
#define OMAP1_STI_BASE IO_ADDRESS(0xfffea000)
@@ -154,7 +164,8 @@ static int __init omap1_init_devices(void)
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
- omap_init_irda();
+
+ omap_init_mbox();
omap_init_rtc();
omap_init_sti();
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index fab8b0b27cf..81c4e738506 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -17,11 +17,11 @@
#include <asm/io.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
-#include <asm/arch/omapfb.h>
extern int omap1_clk_init(void);
extern void omap_check_revision(void);
extern void omap_sram_init(void);
+extern void omapfb_reserve_sdram(void);
/*
* The machine specific code may provide the extra mapping besides the
@@ -121,7 +121,7 @@ void __init omap1_map_common_io(void)
#endif
omap_sram_init();
- omapfb_reserve_mem();
+ omapfb_reserve_sdram();
}
/*
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 410d3e78dd0..0733078940f 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -40,7 +40,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <asm/hardware.h>
#include <asm/irq.h>
diff --git a/arch/arm/mach-omap1/mailbox.c b/arch/arm/mach-omap1/mailbox.c
new file mode 100644
index 00000000000..d3abf560990
--- /dev/null
+++ b/arch/arm/mach-omap1/mailbox.c
@@ -0,0 +1,206 @@
+/*
+ * Mailbox reservation modules for DSP
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/resource.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_ARM2DSP1 0x00
+#define MAILBOX_ARM2DSP1b 0x04
+#define MAILBOX_DSP2ARM1 0x08
+#define MAILBOX_DSP2ARM1b 0x0c
+#define MAILBOX_DSP2ARM2 0x10
+#define MAILBOX_DSP2ARM2b 0x14
+#define MAILBOX_ARM2DSP1_Flag 0x18
+#define MAILBOX_DSP2ARM1_Flag 0x1c
+#define MAILBOX_DSP2ARM2_Flag 0x20
+
+unsigned long mbox_base;
+
+struct omap_mbox1_fifo {
+ unsigned long cmd;
+ unsigned long data;
+ unsigned long flag;
+};
+
+struct omap_mbox1_priv {
+ struct omap_mbox1_fifo tx_fifo;
+ struct omap_mbox1_fifo rx_fifo;
+};
+
+static inline int mbox_read_reg(unsigned int reg)
+{
+ return __raw_readw(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+ __raw_writew(val, mbox_base + reg);
+}
+
+/* msg */
+static inline mbox_msg_t omap1_mbox_fifo_read(struct omap_mbox *mbox)
+{
+ struct omap_mbox1_fifo *fifo =
+ &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+ mbox_msg_t msg;
+
+ msg = mbox_read_reg(fifo->data);
+ msg |= ((mbox_msg_t) mbox_read_reg(fifo->cmd)) << 16;
+
+ return msg;
+}
+
+static inline void
+omap1_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ struct omap_mbox1_fifo *fifo =
+ &((struct omap_mbox1_priv *)mbox->priv)->tx_fifo;
+
+ mbox_write_reg(msg & 0xffff, fifo->data);
+ mbox_write_reg(msg >> 16, fifo->cmd);
+}
+
+static inline int omap1_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+ return 0;
+}
+
+static inline int omap1_mbox_fifo_full(struct omap_mbox *mbox)
+{
+ struct omap_mbox1_fifo *fifo =
+ &((struct omap_mbox1_priv *)mbox->priv)->rx_fifo;
+
+ return (mbox_read_reg(fifo->flag));
+}
+
+/* irq */
+static inline void
+omap1_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+ if (irq == IRQ_RX)
+ enable_irq(mbox->irq);
+}
+
+static inline void
+omap1_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+ if (irq == IRQ_RX)
+ disable_irq(mbox->irq);
+}
+
+static inline int
+omap1_mbox_is_irq(struct omap_mbox *mbox, omap_mbox_type_t irq)
+{
+ if (irq == IRQ_TX)
+ return 0;
+ return 1;
+}
+
+static struct omap_mbox_ops omap1_mbox_ops = {
+ .type = OMAP_MBOX_TYPE1,
+ .fifo_read = omap1_mbox_fifo_read,
+ .fifo_write = omap1_mbox_fifo_write,
+ .fifo_empty = omap1_mbox_fifo_empty,
+ .fifo_full = omap1_mbox_fifo_full,
+ .enable_irq = omap1_mbox_enable_irq,
+ .disable_irq = omap1_mbox_disable_irq,
+ .is_irq = omap1_mbox_is_irq,
+};
+
+/* FIXME: the following struct should be created automatically by the user id */
+
+/* DSP */
+static struct omap_mbox1_priv omap1_mbox_dsp_priv = {
+ .tx_fifo = {
+ .cmd = MAILBOX_ARM2DSP1b,
+ .data = MAILBOX_ARM2DSP1,
+ .flag = MAILBOX_ARM2DSP1_Flag,
+ },
+ .rx_fifo = {
+ .cmd = MAILBOX_DSP2ARM1b,
+ .data = MAILBOX_DSP2ARM1,
+ .flag = MAILBOX_DSP2ARM1_Flag,
+ },
+};
+
+struct omap_mbox mbox_dsp_info = {
+ .name = "dsp",
+ .ops = &omap1_mbox_ops,
+ .priv = &omap1_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+static int __init omap1_mbox_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret = 0;
+
+ if (pdev->num_resources != 2) {
+ dev_err(&pdev->dev, "invalid number of resources: %d\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+ /* MBOX base */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid mem resource\n");
+ return -ENODEV;
+ }
+ mbox_base = res->start;
+
+ /* DSP IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid irq resource\n");
+ return -ENODEV;
+ }
+ mbox_dsp_info.irq = res->start;
+
+ ret = omap_mbox_register(&mbox_dsp_info);
+
+ return ret;
+}
+
+static int omap1_mbox_remove(struct platform_device *pdev)
+{
+ omap_mbox_unregister(&mbox_dsp_info);
+
+ return 0;
+}
+
+static struct platform_driver omap1_mbox_driver = {
+ .probe = omap1_mbox_probe,
+ .remove = omap1_mbox_remove,
+ .driver = {
+ .name = "mailbox",
+ },
+};
+
+static int __init omap1_mbox_init(void)
+{
+ return platform_driver_register(&omap1_mbox_driver);
+}
+
+static void __exit omap1_mbox_exit(void)
+{
+ platform_driver_unregister(&omap1_mbox_driver);
+}
+
+module_init(omap1_mbox_init);
+module_exit(omap1_mbox_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index 49efe903dac..6f4ea4bda5e 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -72,12 +72,12 @@ static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
static unsigned short enable_dyn_sleep = 1;
-static ssize_t omap_pm_sleep_while_idle_show(struct subsystem * subsys, char *buf)
+static ssize_t omap_pm_sleep_while_idle_show(struct kset *kset, char *buf)
{
return sprintf(buf, "%hu\n", enable_dyn_sleep);
}
-static ssize_t omap_pm_sleep_while_idle_store(struct subsystem * subsys,
+static ssize_t omap_pm_sleep_while_idle_store(struct kset *kset,
const char * buf,
size_t n)
{
@@ -100,7 +100,7 @@ static struct subsys_attribute sleep_while_idle_attr = {
.store = omap_pm_sleep_while_idle_store,
};
-extern struct subsystem power_subsys;
+extern struct kset power_subsys;
static void (*omap_sram_idle)(void) = NULL;
static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
@@ -698,10 +698,10 @@ static struct irqaction omap_wakeup_irq = {
static struct pm_ops omap_pm_ops ={
- .pm_disk_mode = 0,
.prepare = omap_pm_prepare,
.enter = omap_pm_enter,
.finish = omap_pm_finish,
+ .valid = pm_valid_only_mem,
};
static int __init omap_pm_init(void)
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 1b7e4a506c2..3705d20c4e5 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -39,6 +39,10 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -48,13 +52,7 @@
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
-struct sys_timer omap_timer;
-/*
- * ---------------------------------------------------------------------------
- * MPU timer
- * ---------------------------------------------------------------------------
- */
#define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE
#define OMAP_MPU_TIMER_OFFSET 0x100
@@ -88,21 +86,6 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc)
return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
}
-/*
- * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs
- * will break. On P2, the timer count rate is 6.5 MHz after programming PTV
- * with 0. This divides the 13MHz input by 2, and is undocumented.
- */
-#if defined(CONFIG_MACH_OMAP_PERSEUS2) || defined(CONFIG_MACH_OMAP_FSAMPLE)
-/* REVISIT: This ifdef construct should be replaced by a query to clock
- * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz.
- */
-#define MPU_TICKS_PER_SEC (13000000 / 2)
-#else
-#define MPU_TICKS_PER_SEC (12000000 / 2)
-#endif
-
-#define MPU_TIMER_TICK_PERIOD ((MPU_TICKS_PER_SEC / HZ) - 1)
typedef struct {
u32 cntl; /* CNTL_TIMER, R/W */
@@ -120,98 +103,164 @@ static inline unsigned long omap_mpu_timer_read(int nr)
return timer->read_tim;
}
-static inline void omap_mpu_timer_start(int nr, unsigned long load_val)
+static inline void omap_mpu_set_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl | MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_remove_autoreset(int nr)
+{
+ volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+
+ timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+}
+
+static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
+ int autoreset)
{
volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+
+ if (autoreset) timerflags |= MPU_TIMER_AR;
timer->cntl = MPU_TIMER_CLOCK_ENABLE;
udelay(1);
timer->load_tim = load_val;
udelay(1);
- timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST);
+ timer->cntl = timerflags;
}
-unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks)
+/*
+ * ---------------------------------------------------------------------------
+ * MPU timer 1 ... count down to zero, interrupt, reload
+ * ---------------------------------------------------------------------------
+ */
+static int omap_mpu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
{
- unsigned long long nsec;
+ omap_mpu_timer_start(0, cycles, 0);
+ return 0;
+}
- nsec = cycles_2_ns((unsigned long long)nr_ticks);
- return (unsigned long)nsec / 1000;
+static void omap_mpu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_mpu_set_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ omap_mpu_remove_autoreset(0);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
}
-/*
- * Last processed system timer interrupt
- */
-static unsigned long omap_mpu_timer_last = 0;
+static struct clock_event_device clockevent_mpu_timer1 = {
+ .name = "mpu_timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC, CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_next_event = omap_mpu_set_next_event,
+ .set_mode = omap_mpu_set_mode,
+};
-/*
- * Returns elapsed usecs since last system timer interrupt
- */
-static unsigned long omap_mpu_timer_gettimeoffset(void)
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &clockevent_mpu_timer1;
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction omap_mpu_timer1_irq = {
+ .name = "mpu_timer1",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = omap_mpu_timer1_interrupt,
+};
+
+static __init void omap_init_mpu_timer(unsigned long rate)
{
- unsigned long now = 0 - omap_mpu_timer_read(0);
- unsigned long elapsed = now - omap_mpu_timer_last;
+ set_cyc2ns_scale(rate / 1000);
+
+ setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
+ omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
+
+ clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC,
+ clockevent_mpu_timer1.shift);
+ clockevent_mpu_timer1.max_delta_ns =
+ clockevent_delta2ns(-1, &clockevent_mpu_timer1);
+ clockevent_mpu_timer1.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_mpu_timer1);
- return omap_mpu_timer_ticks_to_usecs(elapsed);
+ clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_mpu_timer1);
}
+
/*
- * Elapsed time between interrupts is calculated using timer0.
- * Latency during the interrupt is calculated using timer1.
- * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
+ * ---------------------------------------------------------------------------
+ * MPU timer 2 ... free running 32-bit clock source and scheduler clock
+ * ---------------------------------------------------------------------------
*/
-static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id)
-{
- unsigned long now, latency;
- write_seqlock(&xtime_lock);
- now = 0 - omap_mpu_timer_read(0);
- latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
- omap_mpu_timer_last = now - latency;
- timer_tick();
- write_sequnlock(&xtime_lock);
+static unsigned long omap_mpu_timer2_overflows;
+static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id)
+{
+ omap_mpu_timer2_overflows++;
return IRQ_HANDLED;
}
-static struct irqaction omap_mpu_timer_irq = {
- .name = "mpu timer",
- .flags = IRQF_DISABLED | IRQF_TIMER,
- .handler = omap_mpu_timer_interrupt,
+static struct irqaction omap_mpu_timer2_irq = {
+ .name = "mpu_timer2",
+ .flags = IRQF_DISABLED,
+ .handler = omap_mpu_timer2_interrupt,
};
-static unsigned long omap_mpu_timer1_overflows;
-static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
+static cycle_t mpu_read(void)
{
- omap_mpu_timer1_overflows++;
- return IRQ_HANDLED;
+ return ~omap_mpu_timer_read(1);
}
-static struct irqaction omap_mpu_timer1_irq = {
- .name = "mpu timer1 overflow",
- .flags = IRQF_DISABLED,
- .handler = omap_mpu_timer1_interrupt,
+static struct clocksource clocksource_mpu = {
+ .name = "mpu_timer2",
+ .rating = 300,
+ .read = mpu_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 24,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-static __init void omap_init_mpu_timer(void)
+static void __init omap_init_clocksource(unsigned long rate)
{
- set_cyc2ns_scale(MPU_TICKS_PER_SEC / 1000);
- omap_timer.offset = omap_mpu_timer_gettimeoffset;
- setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
- setup_irq(INT_TIMER2, &omap_mpu_timer_irq);
- omap_mpu_timer_start(0, 0xffffffff);
- omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD);
+ static char err[] __initdata = KERN_ERR
+ "%s: can't register clocksource!\n";
+
+ clocksource_mpu.mult
+ = clocksource_khz2mult(rate/1000, clocksource_mpu.shift);
+
+ setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
+ omap_mpu_timer_start(1, ~0, 1);
+
+ if (clocksource_register(&clocksource_mpu))
+ printk(err, clocksource_mpu.name);
}
+
/*
* Scheduler clock - returns current time in nanosec units.
*/
unsigned long long sched_clock(void)
{
- unsigned long ticks = 0 - omap_mpu_timer_read(0);
+ unsigned long ticks = 0 - omap_mpu_timer_read(1);
unsigned long long ticks64;
- ticks64 = omap_mpu_timer1_overflows;
+ ticks64 = omap_mpu_timer2_overflows;
ticks64 <<= 32;
ticks64 |= ticks;
@@ -225,10 +274,21 @@ unsigned long long sched_clock(void)
*/
static void __init omap_timer_init(void)
{
- omap_init_mpu_timer();
+ struct clk *ck_ref = clk_get(NULL, "ck_ref");
+ unsigned long rate;
+
+ BUG_ON(IS_ERR(ck_ref));
+
+ rate = clk_get_rate(ck_ref);
+ clk_put(ck_ref);
+
+ /* PTV = 0 */
+ rate /= 2;
+
+ omap_init_mpu_timer(rate);
+ omap_init_clocksource(rate);
}
struct sys_timer omap_timer = {
.init = omap_timer_init,
- .offset = NULL, /* Initialized later */
};
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index aab97ccf1e6..7393109f5c3 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -9,6 +9,7 @@ config ARCH_OMAP2420
bool "OMAP2420 support"
depends on ARCH_OMAP24XX
select OMAP_DM_TIMER
+ select ARCH_OMAP_OTG
comment "OMAP Board Type"
depends on ARCH_OMAP2
@@ -20,6 +21,7 @@ config MACH_OMAP_GENERIC
config MACH_OMAP_H4
bool "OMAP 2420 H4 board"
depends on ARCH_OMAP2 && ARCH_OMAP24XX
+ select OMAP_DEBUG_LEDS if LEDS || LEDS_OMAP_DEBUG
config MACH_OMAP_APOLLON
bool "OMAP 2420 Apollon board"
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 1e7ed6d22ca..452193f0153 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -266,12 +266,26 @@ static struct platform_device h4_lcd_device = {
.id = -1,
};
+static struct resource h4_led_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device h4_led_device = {
+ .name = "omap_dbg_led",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(h4_led_resources),
+ .resource = h4_led_resources,
+};
+
static struct platform_device *h4_devices[] __initdata = {
&h4_smc91x_device,
&h4_flash_device,
&h4_irda_device,
&h4_kp_device,
&h4_lcd_device,
+ &h4_led_device,
};
static inline void __init h4_init_smc91x(void)
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index aa4322451e8..52ec2f2d636 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -24,7 +24,7 @@
#include <asm/arch/mux.h>
#include <asm/arch/gpio.h>
-#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
#define OMAP2_I2C_BASE2 0x48072000
#define OMAP2_I2C_INT2 57
@@ -42,8 +42,8 @@ static struct resource i2c_resources2[] = {
};
static struct platform_device omap_i2c_device2 = {
- .name = "i2c_omap",
- .id = 2,
+ .name = "i2c_omap",
+ .id = 2,
.num_resources = ARRAY_SIZE(i2c_resources2),
.resource = i2c_resources2,
};
@@ -66,6 +66,40 @@ static void omap_init_i2c(void) {}
#endif
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+#define OMAP2_MBOX_BASE IO_ADDRESS(OMAP24XX_MAILBOX_BASE)
+
+static struct resource mbox_resources[] = {
+ {
+ .start = OMAP2_MBOX_BASE,
+ .end = OMAP2_MBOX_BASE + 0x11f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_24XX_MAIL_U0_MPU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = INT_24XX_MAIL_U3_MPU,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mbox_device = {
+ .name = "mailbox",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mbox_resources),
+ .resource = mbox_resources,
+};
+
+static inline void omap_init_mbox(void)
+{
+ platform_device_register(&mbox_device);
+}
+#else
+static inline void omap_init_mbox(void) { }
+#endif
+
#if defined(CONFIG_OMAP_STI)
#define OMAP2_STI_BASE IO_ADDRESS(0x48068000)
@@ -111,29 +145,45 @@ static inline void omap_init_sti(void) {}
#define OMAP2_MCSPI1_BASE 0x48098000
#define OMAP2_MCSPI2_BASE 0x4809a000
-/* FIXME: use resources instead */
-
static struct omap2_mcspi_platform_config omap2_mcspi1_config = {
- .base = io_p2v(OMAP2_MCSPI1_BASE),
.num_cs = 4,
};
+static struct resource omap2_mcspi1_resources[] = {
+ {
+ .start = OMAP2_MCSPI1_BASE,
+ .end = OMAP2_MCSPI1_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
struct platform_device omap2_mcspi1 = {
.name = "omap2_mcspi",
.id = 1,
+ .num_resources = ARRAY_SIZE(omap2_mcspi1_resources),
+ .resource = omap2_mcspi1_resources,
.dev = {
.platform_data = &omap2_mcspi1_config,
},
};
static struct omap2_mcspi_platform_config omap2_mcspi2_config = {
- .base = io_p2v(OMAP2_MCSPI2_BASE),
.num_cs = 2,
};
+static struct resource omap2_mcspi2_resources[] = {
+ {
+ .start = OMAP2_MCSPI2_BASE,
+ .end = OMAP2_MCSPI2_BASE + 0xff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
struct platform_device omap2_mcspi2 = {
.name = "omap2_mcspi",
.id = 2,
+ .num_resources = ARRAY_SIZE(omap2_mcspi2_resources),
+ .resource = omap2_mcspi2_resources,
.dev = {
.platform_data = &omap2_mcspi2_config,
},
@@ -157,10 +207,10 @@ static int __init omap2_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
omap_init_i2c();
+ omap_init_mbox();
omap_init_mcspi();
omap_init_sti();
return 0;
}
arch_initcall(omap2_init_devices);
-
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index d8f57824423..54c836a9845 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -246,14 +246,22 @@ static int gpmc_cs_mem_enabled(int cs)
return l & (1 << 6);
}
-static void gpmc_cs_set_reserved(int cs, int reserved)
+int gpmc_cs_set_reserved(int cs, int reserved)
{
+ if (cs > GPMC_CS_NUM)
+ return -ENODEV;
+
gpmc_cs_map &= ~(1 << cs);
gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+
+ return 0;
}
-static int gpmc_cs_reserved(int cs)
+int gpmc_cs_reserved(int cs)
{
+ if (cs > GPMC_CS_NUM)
+ return -ENODEV;
+
return gpmc_cs_map & (1 << cs);
}
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index a0728c33e5d..82dc70f6b77 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -27,6 +27,7 @@ extern void omap_sram_init(void);
extern int omap2_clk_init(void);
extern void omap2_check_revision(void);
extern void gpmc_init(void);
+extern void omapfb_reserve_sdram(void);
/*
* The machine specific code may provide the extra mapping besides the
@@ -40,9 +41,21 @@ static struct map_desc omap2_io_desc[] __initdata = {
.type = MT_DEVICE
},
{
- .virtual = L4_24XX_VIRT,
- .pfn = __phys_to_pfn(L4_24XX_PHYS),
- .length = L4_24XX_SIZE,
+ .virtual = DSP_MEM_24XX_VIRT,
+ .pfn = __phys_to_pfn(DSP_MEM_24XX_PHYS),
+ .length = DSP_MEM_24XX_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = DSP_IPI_24XX_VIRT,
+ .pfn = __phys_to_pfn(DSP_IPI_24XX_PHYS),
+ .length = DSP_IPI_24XX_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = DSP_MMU_24XX_VIRT,
+ .pfn = __phys_to_pfn(DSP_MMU_24XX_PHYS),
+ .length = DSP_MMU_24XX_SIZE,
.type = MT_DEVICE
}
};
@@ -60,7 +73,7 @@ void __init omap2_map_common_io(void)
omap2_check_revision();
omap_sram_init();
- omapfb_reserve_mem();
+ omapfb_reserve_sdram();
}
void __init omap2_init_common_hw(void)
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
new file mode 100644
index 00000000000..b03cd06e055
--- /dev/null
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -0,0 +1,318 @@
+/*
+ * Mailbox reservation modules for OMAP2
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ * and Paul Mundt <paul.mundt@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <asm/arch/mailbox.h>
+#include <asm/arch/irqs.h>
+#include <asm/io.h>
+
+#define MAILBOX_REVISION 0x00
+#define MAILBOX_SYSCONFIG 0x10
+#define MAILBOX_SYSSTATUS 0x14
+#define MAILBOX_MESSAGE_0 0x40
+#define MAILBOX_MESSAGE_1 0x44
+#define MAILBOX_MESSAGE_2 0x48
+#define MAILBOX_MESSAGE_3 0x4c
+#define MAILBOX_MESSAGE_4 0x50
+#define MAILBOX_MESSAGE_5 0x54
+#define MAILBOX_FIFOSTATUS_0 0x80
+#define MAILBOX_FIFOSTATUS_1 0x84
+#define MAILBOX_FIFOSTATUS_2 0x88
+#define MAILBOX_FIFOSTATUS_3 0x8c
+#define MAILBOX_FIFOSTATUS_4 0x90
+#define MAILBOX_FIFOSTATUS_5 0x94
+#define MAILBOX_MSGSTATUS_0 0xc0
+#define MAILBOX_MSGSTATUS_1 0xc4
+#define MAILBOX_MSGSTATUS_2 0xc8
+#define MAILBOX_MSGSTATUS_3 0xcc
+#define MAILBOX_MSGSTATUS_4 0xd0
+#define MAILBOX_MSGSTATUS_5 0xd4
+#define MAILBOX_IRQSTATUS_0 0x100
+#define MAILBOX_IRQENABLE_0 0x104
+#define MAILBOX_IRQSTATUS_1 0x108
+#define MAILBOX_IRQENABLE_1 0x10c
+#define MAILBOX_IRQSTATUS_2 0x110
+#define MAILBOX_IRQENABLE_2 0x114
+#define MAILBOX_IRQSTATUS_3 0x118
+#define MAILBOX_IRQENABLE_3 0x11c
+
+static unsigned long mbox_base;
+
+#define MAILBOX_IRQ_NOTFULL(n) (1 << (2 * (n) + 1))
+#define MAILBOX_IRQ_NEWMSG(n) (1 << (2 * (n)))
+
+struct omap_mbox2_fifo {
+ unsigned long msg;
+ unsigned long fifo_stat;
+ unsigned long msg_stat;
+};
+
+struct omap_mbox2_priv {
+ struct omap_mbox2_fifo tx_fifo;
+ struct omap_mbox2_fifo rx_fifo;
+ unsigned long irqenable;
+ unsigned long irqstatus;
+ u32 newmsg_bit;
+ u32 notfull_bit;
+};
+
+static struct clk *mbox_ick_handle;
+
+static inline unsigned int mbox_read_reg(unsigned int reg)
+{
+ return __raw_readl(mbox_base + reg);
+}
+
+static inline void mbox_write_reg(unsigned int val, unsigned int reg)
+{
+ __raw_writel(val, mbox_base + reg);
+}
+
+/* Mailbox H/W preparations */
+static inline int omap2_mbox_startup(struct omap_mbox *mbox)
+{
+ unsigned int l;
+
+ mbox_ick_handle = clk_get(NULL, "mailboxes_ick");
+ if (IS_ERR(mbox_ick_handle)) {
+ printk("Could not get mailboxes_ick\n");
+ return -ENODEV;
+ }
+ clk_enable(mbox_ick_handle);
+
+ /* set smart-idle & autoidle */
+ l = mbox_read_reg(MAILBOX_SYSCONFIG);
+ l |= 0x00000011;
+ mbox_write_reg(l, MAILBOX_SYSCONFIG);
+
+ return 0;
+}
+
+static inline void omap2_mbox_shutdown(struct omap_mbox *mbox)
+{
+ clk_disable(mbox_ick_handle);
+ clk_put(mbox_ick_handle);
+}
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t omap2_mbox_fifo_read(struct omap_mbox *mbox)
+{
+ struct omap_mbox2_fifo *fifo =
+ &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+ return (mbox_msg_t) mbox_read_reg(fifo->msg);
+}
+
+static inline void omap2_mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ struct omap_mbox2_fifo *fifo =
+ &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+ mbox_write_reg(msg, fifo->msg);
+}
+
+static inline int omap2_mbox_fifo_empty(struct omap_mbox *mbox)
+{
+ struct omap_mbox2_fifo *fifo =
+ &((struct omap_mbox2_priv *)mbox->priv)->rx_fifo;
+ return (mbox_read_reg(fifo->msg_stat) == 0);
+}
+
+static inline int omap2_mbox_fifo_full(struct omap_mbox *mbox)
+{
+ struct omap_mbox2_fifo *fifo =
+ &((struct omap_mbox2_priv *)mbox->priv)->tx_fifo;
+ return (mbox_read_reg(fifo->fifo_stat));
+}
+
+/* Mailbox IRQ handle functions */
+static inline void omap2_mbox_enable_irq(struct omap_mbox *mbox,
+ omap_mbox_type_t irq)
+{
+ struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+ l = mbox_read_reg(p->irqenable);
+ l |= bit;
+ mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_disable_irq(struct omap_mbox *mbox,
+ omap_mbox_type_t irq)
+{
+ struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ u32 l, bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+ l = mbox_read_reg(p->irqenable);
+ l &= ~bit;
+ mbox_write_reg(l, p->irqenable);
+}
+
+static inline void omap2_mbox_ack_irq(struct omap_mbox *mbox,
+ omap_mbox_type_t irq)
+{
+ struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+
+ mbox_write_reg(bit, p->irqstatus);
+}
+
+static inline int omap2_mbox_is_irq(struct omap_mbox *mbox,
+ omap_mbox_type_t irq)
+{
+ struct omap_mbox2_priv *p = (struct omap_mbox2_priv *)mbox->priv;
+ u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
+ u32 enable = mbox_read_reg(p->irqenable);
+ u32 status = mbox_read_reg(p->irqstatus);
+
+ return (enable & status & bit);
+}
+
+static struct omap_mbox_ops omap2_mbox_ops = {
+ .type = OMAP_MBOX_TYPE2,
+ .startup = omap2_mbox_startup,
+ .shutdown = omap2_mbox_shutdown,
+ .fifo_read = omap2_mbox_fifo_read,
+ .fifo_write = omap2_mbox_fifo_write,
+ .fifo_empty = omap2_mbox_fifo_empty,
+ .fifo_full = omap2_mbox_fifo_full,
+ .enable_irq = omap2_mbox_enable_irq,
+ .disable_irq = omap2_mbox_disable_irq,
+ .ack_irq = omap2_mbox_ack_irq,
+ .is_irq = omap2_mbox_is_irq,
+};
+
+/*
+ * MAILBOX 0: ARM -> DSP,
+ * MAILBOX 1: ARM <- DSP.
+ * MAILBOX 2: ARM -> IVA,
+ * MAILBOX 3: ARM <- IVA.
+ */
+
+/* FIXME: the following structs should be filled automatically by the user id */
+
+/* DSP */
+static struct omap_mbox2_priv omap2_mbox_dsp_priv = {
+ .tx_fifo = {
+ .msg = MAILBOX_MESSAGE_0,
+ .fifo_stat = MAILBOX_FIFOSTATUS_0,
+ },
+ .rx_fifo = {
+ .msg = MAILBOX_MESSAGE_1,
+ .msg_stat = MAILBOX_MSGSTATUS_1,
+ },
+ .irqenable = MAILBOX_IRQENABLE_0,
+ .irqstatus = MAILBOX_IRQSTATUS_0,
+ .notfull_bit = MAILBOX_IRQ_NOTFULL(0),
+ .newmsg_bit = MAILBOX_IRQ_NEWMSG(1),
+};
+
+struct omap_mbox mbox_dsp_info = {
+ .name = "dsp",
+ .ops = &omap2_mbox_ops,
+ .priv = &omap2_mbox_dsp_priv,
+};
+EXPORT_SYMBOL(mbox_dsp_info);
+
+/* IVA */
+static struct omap_mbox2_priv omap2_mbox_iva_priv = {
+ .tx_fifo = {
+ .msg = MAILBOX_MESSAGE_2,
+ .fifo_stat = MAILBOX_FIFOSTATUS_2,
+ },
+ .rx_fifo = {
+ .msg = MAILBOX_MESSAGE_3,
+ .msg_stat = MAILBOX_MSGSTATUS_3,
+ },
+ .irqenable = MAILBOX_IRQENABLE_3,
+ .irqstatus = MAILBOX_IRQSTATUS_3,
+ .notfull_bit = MAILBOX_IRQ_NOTFULL(2),
+ .newmsg_bit = MAILBOX_IRQ_NEWMSG(3),
+};
+
+static struct omap_mbox mbox_iva_info = {
+ .name = "iva",
+ .ops = &omap2_mbox_ops,
+ .priv = &omap2_mbox_iva_priv,
+};
+
+static int __init omap2_mbox_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret = 0;
+
+ if (pdev->num_resources != 3) {
+ dev_err(&pdev->dev, "invalid number of resources: %d\n",
+ pdev->num_resources);
+ return -ENODEV;
+ }
+
+ /* MBOX base */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid mem resource\n");
+ return -ENODEV;
+ }
+ mbox_base = res->start;
+
+ /* DSP IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid irq resource\n");
+ return -ENODEV;
+ }
+ mbox_dsp_info.irq = res->start;
+
+ ret = omap_mbox_register(&mbox_dsp_info);
+
+ /* IVA IRQ */
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "invalid irq resource\n");
+ return -ENODEV;
+ }
+ mbox_iva_info.irq = res->start;
+
+ ret = omap_mbox_register(&mbox_iva_info);
+
+ return ret;
+}
+
+static int omap2_mbox_remove(struct platform_device *pdev)
+{
+ omap_mbox_unregister(&mbox_dsp_info);
+ return 0;
+}
+
+static struct platform_driver omap2_mbox_driver = {
+ .probe = omap2_mbox_probe,
+ .remove = omap2_mbox_remove,
+ .driver = {
+ .name = "mailbox",
+ },
+};
+
+static int __init omap2_mbox_init(void)
+{
+ return platform_driver_register(&omap2_mbox_driver);
+}
+
+static void __exit omap2_mbox_exit(void)
+{
+ platform_driver_unregister(&omap2_mbox_driver);
+}
+
+module_init(omap2_mbox_init);
+module_exit(omap2_mbox_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d7eee99b7e3..6f4a5436d0c 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -370,10 +370,10 @@ static int omap2_pm_finish(suspend_state_t state)
}
static struct pm_ops omap_pm_ops = {
- .pm_disk_mode = 0,
.prepare = omap2_pm_prepare,
.enter = omap2_pm_enter,
.finish = omap2_pm_finish,
+ .valid = pm_valid_only_mem,
};
int __init omap2_pm_init(void)
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 45d1aaa51b5..62e801ef9ad 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -52,7 +52,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
static struct irqaction omap2_gp_timer_irq = {
.name = "gp timer",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = omap2_gp_timer_interrupt,
};
diff --git a/arch/arm/mach-pnx4008/pm.c b/arch/arm/mach-pnx4008/pm.c
index 3649cd3dfc9..2a137f33f75 100644
--- a/arch/arm/mach-pnx4008/pm.c
+++ b/arch/arm/mach-pnx4008/pm.c
@@ -107,50 +107,19 @@ static int pnx4008_pm_enter(suspend_state_t state)
case PM_SUSPEND_MEM:
pnx4008_suspend();
break;
- case PM_SUSPEND_DISK:
- return -ENOTSUPP;
- default:
- return -EINVAL;
}
return 0;
}
-/*
- * Called after processes are frozen, but before we shut down devices.
- */
-static int pnx4008_pm_prepare(suspend_state_t state)
-{
- switch (state) {
- case PM_SUSPEND_STANDBY:
- case PM_SUSPEND_MEM:
- break;
-
- case PM_SUSPEND_DISK:
- return -ENOTSUPP;
- break;
-
- default:
- return -EINVAL;
- break;
- }
- return 0;
-}
-
-/*
- * Called after devices are re-setup, but before processes are thawed.
- */
-static int pnx4008_pm_finish(suspend_state_t state)
+static int pnx4008_pm_valid(suspend_state_t state)
{
- return 0;
+ return (state == PM_SUSPEND_STANDBY) ||
+ (state == PM_SUSPEND_MEM);
}
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
static struct pm_ops pnx4008_pm_ops = {
- .prepare = pnx4008_pm_prepare,
.enter = pnx4008_pm_enter,
- .finish = pnx4008_pm_finish,
+ .valid = pnx4008_pm_valid,
};
static int __init pnx4008_pm_init(void)
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 8621c206ac8..67e05f005a6 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -82,7 +82,7 @@ static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id)
static struct irqaction pnx4008_timer_irq = {
.name = "PNX4008 Tick Timer",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = pnx4008_timer_interrupt
};
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index b8cb79f899d..64b08b744f9 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -164,9 +164,9 @@ void pxa_set_cken(int clock, int enable)
local_irq_save(flags);
if (enable)
- CKEN |= clock;
+ CKEN |= (1 << clock);
else
- CKEN &= ~clock;
+ CKEN &= ~(1 << clock);
local_irq_restore(flags);
}
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index f815678a9d6..4619d5fe606 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <asm/hardware.h>
#include <asm/irq.h>
@@ -39,11 +38,33 @@ static void pxa_unmask_low_irq(unsigned int irq)
ICMR |= (1 << (irq + PXA_IRQ_SKIP));
}
+static int pxa_set_wake(unsigned int irq, unsigned int on)
+{
+ u32 mask;
+
+ switch (irq) {
+ case IRQ_RTCAlrm:
+ mask = PWER_RTC;
+ break;
+#ifdef CONFIG_PXA27x
+ /* REVISIT can handle USBH1, USBH2, USB, MSL, USIM, ... */
+#endif
+ default:
+ return -EINVAL;
+ }
+ if (on)
+ PWER |= mask;
+ else
+ PWER &= ~mask;
+ return 0;
+}
+
static struct irq_chip pxa_internal_chip_low = {
.name = "SC",
.ack = pxa_mask_low_irq,
.mask = pxa_mask_low_irq,
.unmask = pxa_unmask_low_irq,
+ .set_wake = pxa_set_wake,
};
#if PXA_INTERNAL_IRQS > 32
@@ -71,6 +92,26 @@ static struct irq_chip pxa_internal_chip_high = {
#endif
+/* Note that if an input/irq line ever gets changed to an output during
+ * suspend, the relevant PWER, PRER, and PFER bits should be cleared.
+ */
+#ifdef CONFIG_PXA27x
+
+/* PXA27x: Various gpios can issue wakeup events. This logic only
+ * handles the simple cases, not the WEMUX2 and WEMUX3 options
+ */
+#define PXA27x_GPIO_NOWAKE_MASK \
+ ((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 2))
+#define WAKEMASK(gpio) \
+ (((gpio) <= 15) \
+ ? ((1 << (gpio)) & ~PXA27x_GPIO_NOWAKE_MASK) \
+ : ((gpio == 35) ? (1 << 24) : 0))
+#else
+
+/* pxa 210, 250, 255, 26x: gpios 0..15 can issue wakeups */
+#define WAKEMASK(gpio) (((gpio) <= 15) ? (1 << (gpio)) : 0)
+#endif
+
/*
* PXA GPIO edge detection for IRQs:
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
@@ -84,9 +125,11 @@ static long GPIO_IRQ_mask[4];
static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
{
int gpio, idx;
+ u32 mask;
gpio = IRQ_TO_GPIO(irq);
idx = gpio >> 5;
+ mask = WAKEMASK(gpio);
if (type == IRQT_PROBE) {
/* Don't mess with enabled GPIOs using preconfigured edges or
@@ -106,14 +149,20 @@ static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
if (type & __IRQT_RISEDGE) {
/* printk("rising "); */
__set_bit (gpio, GPIO_IRQ_rising_edge);
- } else
+ PRER |= mask;
+ } else {
__clear_bit (gpio, GPIO_IRQ_rising_edge);
+ PRER &= ~mask;
+ }
if (type & __IRQT_FALEDGE) {
/* printk("falling "); */
__set_bit (gpio, GPIO_IRQ_falling_edge);
- } else
+ PFER |= mask;
+ } else {
__clear_bit (gpio, GPIO_IRQ_falling_edge);
+ PFER &= ~mask;
+ }
/* printk("edges\n"); */
@@ -131,12 +180,29 @@ static void pxa_ack_low_gpio(unsigned int irq)
GEDR0 = (1 << (irq - IRQ_GPIO0));
}
+static int pxa_set_gpio_wake(unsigned int irq, unsigned int on)
+{
+ int gpio = IRQ_TO_GPIO(irq);
+ u32 mask = WAKEMASK(gpio);
+
+ if (!mask)
+ return -EINVAL;
+
+ if (on)
+ PWER |= mask;
+ else
+ PWER &= ~mask;
+ return 0;
+}
+
+
static struct irq_chip pxa_low_gpio_chip = {
.name = "GPIO-l",
.ack = pxa_ack_low_gpio,
.mask = pxa_mask_low_irq,
.unmask = pxa_unmask_low_irq,
.set_type = pxa_gpio_irq_type,
+ .set_wake = pxa_set_gpio_wake,
};
/*
@@ -245,6 +311,7 @@ static struct irq_chip pxa_muxed_gpio_chip = {
.mask = pxa_mask_muxed_gpio,
.unmask = pxa_unmask_muxed_gpio,
.set_type = pxa_gpio_irq_type,
+ .set_wake = pxa_set_gpio_wake,
};
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 8e27a64fa9f..e3097664ffe 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -234,7 +234,7 @@ static void lpd270_backlight_power(int on)
{
if (on) {
pxa_gpio_mode(GPIO16_PWM0_MD);
- pxa_set_cken(CKEN0_PWM0, 1);
+ pxa_set_cken(CKEN_PWM0, 1);
PWM_CTRL0 = 0;
PWM_PWDUTY0 = 0x3ff;
PWM_PERVAL0 = 0x3ff;
@@ -242,7 +242,7 @@ static void lpd270_backlight_power(int on)
PWM_CTRL0 = 0;
PWM_PWDUTY0 = 0x0;
PWM_PERVAL0 = 0x3FF;
- pxa_set_cken(CKEN0_PWM0, 0);
+ pxa_set_cken(CKEN_PWM0, 0);
}
}
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 055de7f4f00..6377b2e29ff 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -220,7 +220,7 @@ static struct resource pxa_ssp_resources[] = {
static struct pxa2xx_spi_master pxa_ssp_master_info = {
.ssp_type = PXA25x_SSP,
- .clock_enable = CKEN3_SSP,
+ .clock_enable = CKEN_SSP,
.num_chipselect = 0,
};
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 56d94d88d5c..ed99a81b98f 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -266,7 +266,7 @@ static void mainstone_backlight_power(int on)
{
if (on) {
pxa_gpio_mode(GPIO16_PWM0_MD);
- pxa_set_cken(CKEN0_PWM0, 1);
+ pxa_set_cken(CKEN_PWM0, 1);
PWM_CTRL0 = 0;
PWM_PWDUTY0 = 0x3ff;
PWM_PERVAL0 = 0x3ff;
@@ -274,7 +274,7 @@ static void mainstone_backlight_power(int on)
PWM_CTRL0 = 0;
PWM_PWDUTY0 = 0x0;
PWM_PERVAL0 = 0x3FF;
- pxa_set_cken(CKEN0_PWM0, 0);
+ pxa_set_cken(CKEN_PWM0, 0);
}
}
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index b4d8276d605..6bf15ae7384 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -223,14 +223,11 @@ int pxa_pm_finish(suspend_state_t state)
EXPORT_SYMBOL_GPL(pxa_pm_finish);
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
static struct pm_ops pxa_pm_ops = {
- .pm_disk_mode = PM_DISK_FIRMWARE,
.prepare = pxa_pm_prepare,
.enter = pxa_pm_enter,
.finish = pxa_pm_finish,
+ .valid = pm_valid_only_mem,
};
static int __init pxa_pm_init(void)
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 74eeada1e2f..c64bab49efc 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -140,9 +140,9 @@ void pxa_cpu_pm_enter(suspend_state_t state)
extern void pxa_cpu_resume(void);
if (state == PM_SUSPEND_STANDBY)
- CKEN = CKEN22_MEMC | CKEN9_OSTIMER | CKEN16_LCD |CKEN0_PWM0;
+ CKEN = CKEN_MEMC | CKEN_OSTIMER | CKEN_LCD | CKEN_PWM0;
else
- CKEN = CKEN22_MEMC | CKEN9_OSTIMER;
+ CKEN = CKEN_MEMC | CKEN_OSTIMER;
/* ensure voltage-change sequencer not initiated, which hangs */
PCFR &= ~PCFR_FVC;
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 6cc202755fb..71766ac0328 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -52,13 +52,13 @@ struct ssp_info_ {
*/
static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
#if defined (CONFIG_PXA27x)
- {IRQ_SSP, CKEN23_SSP1},
- {IRQ_SSP2, CKEN3_SSP2},
- {IRQ_SSP3, CKEN4_SSP3},
+ {IRQ_SSP, CKEN_SSP1},
+ {IRQ_SSP2, CKEN_SSP2},
+ {IRQ_SSP3, CKEN_SSP3},
#else
- {IRQ_SSP, CKEN3_SSP},
- {IRQ_NSSP, CKEN9_NSSP},
- {IRQ_ASSP, CKEN10_ASSP},
+ {IRQ_SSP, CKEN_SSP},
+ {IRQ_NSSP, CKEN_NSSP},
+ {IRQ_ASSP, CKEN_ASSP},
#endif
};
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index fc3b82a740a..5248abe334d 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -97,7 +97,7 @@ pxa_timer_interrupt(int irq, void *dev_id)
static struct irqaction pxa_timer_irq = {
.name = "PXA Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = pxa_timer_interrupt,
};
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 84d3fe76e94..c7f1b44da40 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -549,7 +549,7 @@ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
static struct irqaction realview_timer_irq = {
.name = "RealView Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = realview_timer_interrupt,
};
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 208a2b5dba1..570cf937e73 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -17,6 +17,7 @@
#include <linux/sched.h>
#include <linux/device.h>
#include <linux/serial_8250.h>
+#include <linux/pata_platform.h>
#include <asm/elf.h>
#include <asm/io.h>
@@ -159,11 +160,45 @@ static struct platform_device serial_device = {
},
};
+static struct pata_platform_info pata_platform_data = {
+ .ioport_shift = 2,
+};
+
+static struct resource pata_resources[] = {
+ [0] = {
+ .start = 0x030107c0,
+ .end = 0x030107df,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x03010fd8,
+ .end = 0x03010fdb,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = IRQ_HARDDISK,
+ .end = IRQ_HARDDISK,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device pata_device = {
+ .name = "pata_platform",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(pata_resources),
+ .resource = pata_resources,
+ .dev = {
+ .platform_data = &pata_platform_data,
+ .coherent_dma_mask = ~0, /* grumble */
+ },
+};
+
static struct platform_device *devs[] __initdata = {
&iomd_device,
&kbd_device,
&serial_device,
&acornfb_device,
+ &pata_device,
};
static int __init rpc_init(void)
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index daeba427d78..76a7cb15f3b 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -24,7 +24,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 53cbdaa43ac..f5c5c53e1cc 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/plat-s3c24xx/cpu.h>
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index 72f2cc4fcd0..bc308ceb91c 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -160,17 +160,11 @@ static struct platform_device *amlm5900_devices[] __initdata = {
#endif
};
-static struct s3c24xx_board amlm5900_board __initdata = {
- .devices = amlm5900_devices,
- .devices_count = ARRAY_SIZE(amlm5900_devices)
-};
-
void __init amlm5900_map_io(void)
{
s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs));
- s3c24xx_set_board(&amlm5900_board);
}
#ifdef CONFIG_FB_S3C2410
@@ -247,6 +241,7 @@ static void __init amlm5900_init(void)
#ifdef CONFIG_FB_S3C2410
s3c24xx_fb_set_platdata(&amlm5900_lcd_info);
#endif
+ platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices));
}
MACHINE_START(AML_M5900, "AML_M5900")
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 7b81296427e..f01de807b72 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -464,13 +464,6 @@ static struct clk *bast_clocks[] = {
&s3c24xx_uclk,
};
-static struct s3c24xx_board bast_board __initdata = {
- .devices = bast_devices,
- .devices_count = ARRAY_SIZE(bast_devices),
- .clocks = bast_clocks,
- .clocks_count = ARRAY_SIZE(bast_clocks),
-};
-
static void __init bast_map_io(void)
{
/* initialise the clocks */
@@ -486,19 +479,22 @@ static void __init bast_map_io(void)
s3c24xx_uclk.parent = &s3c24xx_clkout1;
+ s3c24xx_register_clocks(bast_clocks, ARRAY_SIZE(bast_clocks));
+
s3c_device_nand.dev.platform_data = &bast_nand_info;
s3c_device_i2c.dev.platform_data = &bast_i2c_info;
s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs));
- s3c24xx_set_board(&bast_board);
+
usb_simtec_init();
}
static void __init bast_init(void)
{
s3c24xx_fb_set_platdata(&bast_lcd_info);
+ platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices));
}
MACHINE_START(BAST, "Simtec-BAST")
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index d052ab2d937..5d5f00e9c46 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -129,7 +129,6 @@ static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = {
};
-
/**
* Set lcd on or off
**/
@@ -188,17 +187,11 @@ static struct platform_device *h1940_devices[] __initdata = {
&s3c_device_leds,
};
-static struct s3c24xx_board h1940_board __initdata = {
- .devices = h1940_devices,
- .devices_count = ARRAY_SIZE(h1940_devices)
-};
-
static void __init h1940_map_io(void)
{
s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs));
- s3c24xx_set_board(&h1940_board);
/* setup PM */
@@ -232,6 +225,8 @@ static void __init h1940_init(void)
| (0x02 << S3C2410_PLLCON_PDIVSHIFT)
| (0x03 << S3C2410_PLLCON_SDIVSHIFT);
writel(tmp, S3C2410_UPLLCON);
+
+ platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
}
MACHINE_START(H1940, "IPAQ-H1940")
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 261aa4cc077..412e50c3d28 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -90,17 +90,11 @@ static struct s3c2410_platform_i2c n30_i2ccfg = {
.max_freq = 10*1000,
};
-static struct s3c24xx_board n30_board __initdata = {
- .devices = n30_devices,
- .devices_count = ARRAY_SIZE(n30_devices)
-};
-
static void __init n30_map_io(void)
{
s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
- s3c24xx_set_board(&n30_board);
}
static void __init n30_init_irq(void)
@@ -120,6 +114,8 @@ static void __init n30_init(void)
s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
S3C2410_MISCCR_USBSUSPND0 |
S3C2410_MISCCR_USBSUSPND1, 0x0);
+
+ platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices));
}
MACHINE_START(N30, "Acer-N30")
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index c78ab75b44f..1f899fa588d 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -100,20 +100,17 @@ static struct platform_device *otom11_devices[] __initdata = {
&otom_device_nor,
};
-static struct s3c24xx_board otom11_board __initdata = {
- .devices = otom11_devices,
- .devices_count = ARRAY_SIZE(otom11_devices)
-};
-
-
static void __init otom11_map_io(void)
{
s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs));
- s3c24xx_set_board(&otom11_board);
}
+static void __init otom11_init(void)
+{
+ platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices));
+}
MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
@@ -121,6 +118,7 @@ MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = otom11_map_io,
+ .init_machine = otom11_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
index c6a41593de2..9cc4253d7bb 100644
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -29,7 +29,6 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
-#include <linux/mmc/protocol.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
@@ -331,11 +330,6 @@ static struct platform_device *qt2410_devices[] __initdata = {
&qt2410_led,
};
-static struct s3c24xx_board qt2410_board __initdata = {
- .devices = qt2410_devices,
- .devices_count = ARRAY_SIZE(qt2410_devices)
-};
-
static struct mtd_partition qt2410_nand_part[] = {
[0] = {
.name = "U-Boot",
@@ -405,7 +399,6 @@ static void __init qt2410_map_io(void)
s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc));
s3c24xx_init_clocks(12*1000*1000);
s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
- s3c24xx_set_board(&qt2410_board);
}
static void __init qt2410_machine_init(void)
@@ -432,6 +425,7 @@ static void __init qt2410_machine_init(void)
s3c2410_gpio_cfgpin(S3C2410_GPB5, S3C2410_GPIO_OUTPUT);
+ platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices));
s3c2410_pm_init();
}
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 57b8a80f33d..5852d300d52 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -94,17 +94,17 @@ static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_iis,
};
-static struct s3c24xx_board smdk2410_board __initdata = {
- .devices = smdk2410_devices,
- .devices_count = ARRAY_SIZE(smdk2410_devices)
-};
-
static void __init smdk2410_map_io(void)
{
s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs));
- s3c24xx_set_board(&smdk2410_board);
+}
+
+static void __init smdk2410_init(void)
+{
+ platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
+ smdk_machine_init();
}
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
@@ -115,7 +115,7 @@ MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switc
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = smdk2410_map_io,
.init_irq = s3c24xx_init_irq,
- .init_machine = smdk_machine_init,
+ .init_machine = smdk2410_init,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index c947c75bcbf..7b624bb0049 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -384,13 +384,6 @@ static struct clk *vr1000_clocks[] = {
&s3c24xx_uclk,
};
-static struct s3c24xx_board vr1000_board __initdata = {
- .devices = vr1000_devices,
- .devices_count = ARRAY_SIZE(vr1000_devices),
- .clocks = vr1000_clocks,
- .clocks_count = ARRAY_SIZE(vr1000_clocks),
-};
-
static void vr1000_power_off(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_OUTP);
@@ -412,15 +405,19 @@ static void __init vr1000_map_io(void)
s3c24xx_uclk.parent = &s3c24xx_clkout1;
+ s3c24xx_register_clocks(vr1000_clocks, ARRAY_SIZE(vr1000_clocks));
+
pm_power_off = vr1000_power_off;
s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs));
- s3c24xx_set_board(&vr1000_board);
- usb_simtec_init();
}
+static void __init vr1000_init(void)
+{
+ platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices));
+}
MACHINE_START(VR1000, "Thorcom-VR1000")
/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
@@ -428,6 +425,7 @@ MACHINE_START(VR1000, "Thorcom-VR1000")
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = vr1000_map_io,
+ .init_machine = vr1000_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index 637aaba6539..d1eeed2ad47 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
+/* linux/arch/arm/mach-s3c2410/sleep.S
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index befc5fdbb61..d5be5d05326 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -47,6 +47,15 @@ config MACH_S3C2413
machine_is_s3c2413() will work when MACH_SMDK2413 is
selected
+config MACH_SMDK2412
+ bool "SMDK2412"
+ select MACH_SMDK2413
+ help
+ Say Y here if you are using an SMDK2412
+
+ Note, this shares support with SMDK2413, so will automatically
+ select MACH_SMDK2413.
+
config MACH_VSTMS
bool "VMSTMS"
select CPU_S3C2412
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
index e89dbdcb1b7..f0d66828f96 100644
--- a/arch/arm/mach-s3c2412/irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index b5befce6c8d..063af09f899 100644
--- a/arch/arm/mach-s3c2412/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -110,11 +110,6 @@ static struct platform_device *smdk2413_devices[] __initdata = {
&s3c_device_usbgadget,
};
-static struct s3c24xx_board smdk2413_board __initdata = {
- .devices = smdk2413_devices,
- .devices_count = ARRAY_SIZE(smdk2413_devices)
-};
-
static void __init smdk2413_fixup(struct machine_desc *desc,
struct tag *tags, char **cmdline,
struct meminfo *mi)
@@ -132,7 +127,6 @@ static void __init smdk2413_map_io(void)
s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs));
- s3c24xx_set_board(&smdk2413_board);
}
static void __init smdk2413_machine_init(void)
@@ -149,6 +143,7 @@ static void __init smdk2413_machine_init(void)
s3c24xx_udc_set_platdata(&smdk2413_udc_cfg);
+ platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices));
smdk_machine_init();
}
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index 4231b549d79..f2fbd65956a 100644
--- a/arch/arm/mach-s3c2412/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -129,11 +129,6 @@ static struct platform_device *vstms_devices[] __initdata = {
&s3c_device_nand,
};
-static struct s3c24xx_board vstms_board __initdata = {
- .devices = vstms_devices,
- .devices_count = ARRAY_SIZE(vstms_devices)
-};
-
static void __init vstms_fixup(struct machine_desc *desc,
struct tag *tags, char **cmdline,
struct meminfo *mi)
@@ -153,7 +148,11 @@ static void __init vstms_map_io(void)
s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
- s3c24xx_set_board(&vstms_board);
+}
+
+static void __init vstms_init(void)
+{
+ platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices));
}
MACHINE_START(VSTMS, "VSTMS")
@@ -163,6 +162,7 @@ MACHINE_START(VSTMS, "VSTMS")
.fixup = vstms_fixup,
.init_irq = s3c24xx_init_irq,
+ .init_machine = vstms_init,
.map_io = vstms_map_io,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/irq.c b/arch/arm/mach-s3c2440/irq.c
index 1069d13d8c5..a87608bc1a0 100644
--- a/arch/arm/mach-s3c2440/irq.c
+++ b/arch/arm/mach-s3c2440/irq.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index 3f0288eb1ed..b5d387ef37e 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -281,13 +281,6 @@ static struct clk *anubis_clocks[] = {
&s3c24xx_uclk,
};
-static struct s3c24xx_board anubis_board __initdata = {
- .devices = anubis_devices,
- .devices_count = ARRAY_SIZE(anubis_devices),
- .clocks = anubis_clocks,
- .clocks_count = ARRAY_SIZE(anubis_clocks),
-};
-
static void __init anubis_map_io(void)
{
/* initialise the clocks */
@@ -303,23 +296,31 @@ static void __init anubis_map_io(void)
s3c24xx_uclk.parent = &s3c24xx_clkout1;
+ s3c24xx_register_clocks(anubis_clocks, ARRAY_SIZE(anubis_clocks));
+
s3c_device_nand.dev.platform_data = &anubis_nand_info;
s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
- s3c24xx_set_board(&anubis_board);
/* ensure that the GPIO is setup */
s3c2410_gpio_setpin(S3C2410_GPA0, 1);
}
+static void __init anubis_init(void)
+{
+ platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices));
+}
+
+
MACHINE_START(ANUBIS, "Simtec-Anubis")
/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = anubis_map_io,
+ .init_machine = anubis_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index 6d551d88330..5e61f2166c7 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -116,12 +116,6 @@ static struct platform_device *nexcoder_devices[] __initdata = {
&nexcoder_device_nor,
};
-static struct s3c24xx_board nexcoder_board __initdata = {
- .devices = nexcoder_devices,
- .devices_count = ARRAY_SIZE(nexcoder_devices),
-};
-
-
static void __init nexcoder_sensorboard_init(void)
{
// Initialize SCCB bus
@@ -142,10 +136,14 @@ static void __init nexcoder_map_io(void)
s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs));
- s3c24xx_set_board(&nexcoder_board);
+
nexcoder_sensorboard_init();
}
+static void __init nexcoder_init(void)
+{
+ platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices));
+};
MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
@@ -153,6 +151,7 @@ MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = nexcoder_map_io,
+ .init_machine = nexcoder_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 2ed8e51f20c..324f5a23792 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -251,13 +251,6 @@ static struct clk *osiris_clocks[] = {
&s3c24xx_uclk,
};
-static struct s3c24xx_board osiris_board __initdata = {
- .devices = osiris_devices,
- .devices_count = ARRAY_SIZE(osiris_devices),
- .clocks = osiris_clocks,
- .clocks_count = ARRAY_SIZE(osiris_clocks),
-};
-
static void __init osiris_map_io(void)
{
unsigned long flags;
@@ -275,12 +268,13 @@ static void __init osiris_map_io(void)
s3c24xx_uclk.parent = &s3c24xx_clkout1;
+ s3c24xx_register_clocks(osiris_clocks, ARRAY_SIZE(osiris_clocks));
+
s3c_device_nand.dev.platform_data = &osiris_nand_info;
s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc));
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
- s3c24xx_set_board(&osiris_board);
/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
@@ -292,12 +286,18 @@ static void __init osiris_map_io(void)
s3c2410_gpio_setpin(S3C2410_GPA0, 1);
}
+static void __init osiris_init(void)
+{
+ platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices));
+};
+
MACHINE_START(OSIRIS, "Simtec-OSIRIS")
/* Maintainer: Ben Dooks <ben@simtec.co.uk> */
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = osiris_map_io,
+ .init_machine = osiris_init,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index ae1d0a81fd6..c3cc4bf158f 100644
--- a/arch/arm/mach-s3c2440/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -202,11 +202,6 @@ static struct platform_device *rx3715_devices[] __initdata = {
&s3c_device_nand,
};
-static struct s3c24xx_board rx3715_board __initdata = {
- .devices = rx3715_devices,
- .devices_count = ARRAY_SIZE(rx3715_devices)
-};
-
static void __init rx3715_map_io(void)
{
s3c_device_nand.dev.platform_data = &rx3715_nand_info;
@@ -214,7 +209,6 @@ static void __init rx3715_map_io(void)
s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc));
s3c24xx_init_clocks(16934000);
s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs));
- s3c24xx_set_board(&rx3715_board);
}
static void __init rx3715_init_irq(void)
@@ -230,9 +224,9 @@ static void __init rx3715_init_machine(void)
s3c2410_pm_init();
s3c24xx_fb_set_platdata(&rx3715_lcdcfg);
+ platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices));
}
-
MACHINE_START(RX3715, "IPAQ-RX3715")
/* Maintainer: Ben Dooks <ben@fluff.org> */
.phys_io = S3C2410_PA_UART,
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index c17eb5b1f6b..e167254e232 100644
--- a/arch/arm/mach-s3c2440/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -174,23 +174,18 @@ static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_iis,
};
-static struct s3c24xx_board smdk2440_board __initdata = {
- .devices = smdk2440_devices,
- .devices_count = ARRAY_SIZE(smdk2440_devices)
-};
-
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(16934400);
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
- s3c24xx_set_board(&smdk2440_board);
}
static void __init smdk2440_machine_init(void)
{
s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);
+ platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
smdk_machine_init();
}
diff --git a/arch/arm/mach-s3c2443/irq.c b/arch/arm/mach-s3c2443/irq.c
index 756573595b8..6cd4818f3f0 100644
--- a/arch/arm/mach-s3c2443/irq.c
+++ b/arch/arm/mach-s3c2443/irq.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
index e82aaff7dee..b71ee53c286 100644
--- a/arch/arm/mach-s3c2443/mach-smdk2443.c
+++ b/arch/arm/mach-s3c2443/mach-smdk2443.c
@@ -106,21 +106,16 @@ static struct platform_device *smdk2443_devices[] __initdata = {
&s3c_device_i2c,
};
-static struct s3c24xx_board smdk2443_board __initdata = {
- .devices = smdk2443_devices,
- .devices_count = ARRAY_SIZE(smdk2443_devices)
-};
-
static void __init smdk2443_map_io(void)
{
s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs));
- s3c24xx_set_board(&smdk2443_board);
}
static void __init smdk2443_machine_init(void)
{
+ platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices));
smdk_machine_init();
}
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
index b1e8fd766c1..fc97fe57ee6 100644
--- a/arch/arm/mach-sa1100/clock.c
+++ b/arch/arm/mach-sa1100/clock.c
@@ -9,14 +9,17 @@
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <asm/hardware.h>
-#include <asm/semaphore.h>
+/*
+ * Very simple clock implementation - we only have one clock to
+ * deal with at the moment, so we only match using the "name".
+ */
struct clk {
struct list_head node;
unsigned long rate;
- struct module *owner;
const char *name;
unsigned int enabled;
void (*enable)(void);
@@ -24,21 +27,21 @@ struct clk {
};
static LIST_HEAD(clocks);
-static DECLARE_MUTEX(clocks_sem);
+static DEFINE_MUTEX(clocks_mutex);
static DEFINE_SPINLOCK(clocks_lock);
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
- down(&clocks_sem);
+ mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, node) {
- if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ if (strcmp(id, p->name) == 0) {
clk = p;
break;
}
}
- up(&clocks_sem);
+ mutex_unlock(&clocks_mutex);
return clk;
}
@@ -46,7 +49,6 @@ EXPORT_SYMBOL(clk_get);
void clk_put(struct clk *clk)
{
- module_put(clk->owner);
}
EXPORT_SYMBOL(clk_put);
@@ -109,18 +111,18 @@ static struct clk clk_gpio27 = {
int clk_register(struct clk *clk)
{
- down(&clocks_sem);
+ mutex_lock(&clocks_mutex);
list_add(&clk->node, &clocks);
- up(&clocks_sem);
+ mutex_unlock(&clocks_mutex);
return 0;
}
EXPORT_SYMBOL(clk_register);
void clk_unregister(struct clk *clk)
{
- down(&clocks_sem);
+ mutex_lock(&clocks_mutex);
list_del(&clk->node);
- up(&clocks_sem);
+ mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clk_unregister);
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index b034ad69a32..b72fee0f253 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -740,7 +740,7 @@ static void h3800_IRQ_demux(unsigned int irq, struct irq_desc *desc)
static struct irqaction h3800_irq = {
.name = "h3800_asic",
.handler = h3800_IRQ_demux,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};
u32 kpio_int_shadow = 0;
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 5642aeca079..edf3347d9c5 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 075d4d1d63b..d7c038a0256 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -4,7 +4,6 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/ptrace.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/serial_core.h>
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
index 786c8534231..d674cf34315 100644
--- a/arch/arm/mach-sa1100/pm.c
+++ b/arch/arm/mach-sa1100/pm.c
@@ -59,9 +59,6 @@ static int sa11x0_pm_enter(suspend_state_t state)
unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE];
struct timespec delta, rtc;
- if (state != PM_SUSPEND_MEM)
- return -EINVAL;
-
/* preserve current time */
rtc.tv_sec = RCNR;
rtc.tv_nsec = 0;
@@ -134,12 +131,9 @@ unsigned long sleep_phys_sp(void *sp)
return virt_to_phys(sp);
}
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
static struct pm_ops sa11x0_pm_ops = {
- .pm_disk_mode = PM_DISK_FIRMWARE,
.enter = sa11x0_pm_enter,
+ .valid = pm_valid_only_mem,
};
static int __init sa11x0_pm_init(void)
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 29c89f9eb2c..416e277054c 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -111,7 +111,7 @@ sa1100_timer_interrupt(int irq, void *dev_id)
static struct irqaction sa1100_timer_irq = {
.name = "SA11xx Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = sa1100_timer_interrupt,
};
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 0e480fae8ec..a0545db2a34 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -90,7 +90,7 @@ shark_timer_interrupt(int irq, void *dev_id)
static struct irqaction shark_timer_irq = {
.name = "Shark Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = shark_timer_interrupt,
};
diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c
index 00a6c146686..5b0c6af44ec 100644
--- a/arch/arm/mach-shark/irq.c
+++ b/arch/arm/mach-shark/irq.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <asm/irq.h>
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index bf71507c76f..a7dd09436cb 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -26,6 +26,8 @@
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/cnt32_to_63.h>
#include <asm/system.h>
@@ -828,69 +830,101 @@ void __init versatile_init(void)
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif
-/*
- * Returns number of ms since last clock interrupt. Note that interrupts
- * will have been disabled by do_gettimeoffset()
- */
-static unsigned long versatile_gettimeoffset(void)
+static void timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *clk)
{
- unsigned long ticks1, ticks2, status;
+ unsigned long ctrl;
- /*
- * Get the current number of ticks. Note that there is a race
- * condition between us reading the timer and checking for
- * an interrupt. We get around this by ensuring that the
- * counter has not reloaded between our two reads.
- */
- ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
- do {
- ticks1 = ticks2;
- status = __raw_readl(VA_IC_BASE + VIC_RAW_STATUS);
- ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
- } while (ticks2 > ticks1);
+ switch(mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
- /*
- * Number of ticks since last interrupt.
- */
- ticks1 = TIMER_RELOAD - ticks2;
+ ctrl = TIMER_CTRL_PERIODIC;
+ ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE;
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* period set, and timer enabled in 'next_event' hook */
+ ctrl = TIMER_CTRL_ONESHOT;
+ ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE;
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ ctrl = 0;
+ }
- /*
- * Interrupt pending? If so, we've reloaded once already.
- *
- * FIXME: Need to check this is effectively timer 0 that expires
- */
- if (status & IRQMASK_TIMERINT0_1)
- ticks1 += TIMER_RELOAD;
+ writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
+}
- /*
- * Convert the ticks to usecs
- */
- return TICKS2USECS(ticks1);
+static int timer_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
+
+ writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
+
+ return 0;
}
+static struct clock_event_device timer0_clockevent = {
+ .name = "timer0",
+ .shift = 32,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = timer_set_mode,
+ .set_next_event = timer_set_next_event,
+};
+
/*
* IRQ handler for the timer
*/
static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
{
- write_seqlock(&xtime_lock);
+ struct clock_event_device *evt = &timer0_clockevent;
- // ...clear the interrupt
writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
- timer_tick();
-
- write_sequnlock(&xtime_lock);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
static struct irqaction versatile_timer_irq = {
.name = "Versatile Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = versatile_timer_interrupt,
};
+static cycle_t versatile_get_cycles(void)
+{
+ return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
+}
+
+static struct clocksource clocksource_versatile = {
+ .name = "timer3",
+ .rating = 200,
+ .read = versatile_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init versatile_clocksource_init(void)
+{
+ /* setup timer3 as free-running clocksource */
+ writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+ writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
+ writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
+ writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
+ TIMER3_VA_BASE + TIMER_CTRL);
+
+ clocksource_versatile.mult =
+ clocksource_khz2mult(1000, clocksource_versatile.shift);
+ clocksource_register(&clocksource_versatile);
+
+ return 0;
+}
+
/*
* Set up timer interrupt, and return the current time in seconds.
*/
@@ -918,18 +952,25 @@ static void __init versatile_timer_init(void)
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
writel(0, TIMER3_VA_BASE + TIMER_CTRL);
- writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
- writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
- writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
- TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
-
/*
* Make irqs happen for the system timer
*/
setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq);
+
+ versatile_clocksource_init();
+
+ timer0_clockevent.mult =
+ div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
+ timer0_clockevent.max_delta_ns =
+ clockevent_delta2ns(0xffffffff, &timer0_clockevent);
+ timer0_clockevent.min_delta_ns =
+ clockevent_delta2ns(0xf, &timer0_clockevent);
+
+ timer0_clockevent.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&timer0_clockevent);
}
struct sys_timer versatile_timer = {
.init = versatile_timer_init,
- .offset = versatile_gettimeoffset,
};
+
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 5cd0b5d9e7e..ba58223f12b 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -16,7 +16,6 @@
*/
#include <linux/kernel.h>
#include <linux/pci.h>
-#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index e684e9b3821..b81391a4e37 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -366,6 +366,19 @@ config CPU_32v6K
enabled will not boot on processors with do not support these
instructions.
+# ARMv7
+config CPU_V7
+ bool "Support ARM V7 processor"
+ depends on ARCH_INTEGRATOR
+ select CPU_32v6K
+ select CPU_32v7
+ select CPU_ABRT_EV7
+ select CPU_CACHE_V7
+ select CPU_CACHE_VIPT
+ select CPU_CP15_MMU
+ select CPU_COPY_V6 if MMU
+ select CPU_TLB_V6 if MMU
+
# Figure out what processor architecture version we should be using.
# This defines the compiler instruction set which depends on the machine type.
config CPU_32v3
@@ -391,6 +404,9 @@ config CPU_32v5
config CPU_32v6
bool
+config CPU_32v7
+ bool
+
# The abort model
config CPU_ABRT_NOMMU
bool
@@ -413,6 +429,9 @@ config CPU_ABRT_EV5TJ
config CPU_ABRT_EV6
bool
+config CPU_ABRT_EV7
+ bool
+
# The cache model
config CPU_CACHE_V3
bool
@@ -429,6 +448,9 @@ config CPU_CACHE_V4WB
config CPU_CACHE_V6
bool
+config CPU_CACHE_V7
+ bool
+
config CPU_CACHE_VIVT
bool
@@ -503,7 +525,7 @@ comment "Processor Features"
config ARM_THUMB
bool "Support Thumb user binaries"
- depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6
+ depends on CPU_ARM720T || CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_ARM1020E || CPU_ARM1022 || CPU_ARM1026 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V7
default y
help
Say Y if you want to include kernel support for running user space
@@ -578,9 +600,15 @@ config CPU_CACHE_ROUND_ROBIN
Say Y here to use the predictable round-robin cache replacement
policy. Unless you specifically require this or are unsure, say N.
+config CPU_L2CACHE_DISABLE
+ bool "Disable level 2 cache"
+ depends on CPU_V7
+ help
+ Say Y here to disable the level 2 cache. If unsure, say N.
+
config CPU_BPREDICT_DISABLE
bool "Disable branch prediction"
- depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3
+ depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7
help
Say Y here to disable branch prediction. If unsure, say N.
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 2f8b9594777..b5bd335ff14 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -24,12 +24,14 @@ obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o
obj-$(CONFIG_CPU_ABRT_EV5T) += abort-ev5t.o
obj-$(CONFIG_CPU_ABRT_EV5TJ) += abort-ev5tj.o
obj-$(CONFIG_CPU_ABRT_EV6) += abort-ev6.o
+obj-$(CONFIG_CPU_ABRT_EV7) += abort-ev7.o
obj-$(CONFIG_CPU_CACHE_V3) += cache-v3.o
obj-$(CONFIG_CPU_CACHE_V4) += cache-v4.o
obj-$(CONFIG_CPU_CACHE_V4WT) += cache-v4wt.o
obj-$(CONFIG_CPU_CACHE_V4WB) += cache-v4wb.o
obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
+obj-$(CONFIG_CPU_CACHE_V7) += cache-v7.o
obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
@@ -66,5 +68,6 @@ obj-$(CONFIG_CPU_SA1100) += proc-sa1100.o
obj-$(CONFIG_CPU_XSCALE) += proc-xscale.o
obj-$(CONFIG_CPU_XSC3) += proc-xsc3.o
obj-$(CONFIG_CPU_V6) += proc-v6.o
+obj-$(CONFIG_CPU_V7) += proc-v7.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S
new file mode 100644
index 00000000000..eb90bce38e1
--- /dev/null
+++ b/arch/arm/mm/abort-ev7.S
@@ -0,0 +1,32 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: v7_early_abort
+ *
+ * Params : r2 = address of aborted instruction
+ * : r3 = saved SPSR
+ *
+ * Returns : r0 = address of abort
+ * : r1 = FSR, bit 11 = write
+ * : r2-r8 = corrupted
+ * : r9 = preserved
+ * : sp = pointer to registers
+ *
+ * Purpose : obtain information about current aborted instruction.
+ */
+ .align 5
+ENTRY(v7_early_abort)
+ /*
+ * The effect of data aborts on on the exclusive access monitor are
+ * UNPREDICTABLE. Do a CLREX to clear the state
+ */
+ clrex
+
+ mrc p15, 0, r1, c5, c0, 0 @ get FSR
+ mrc p15, 0, r0, c6, c0, 0 @ get FAR
+
+ /*
+ * V6 code adjusts the returned DFSR.
+ * New designs should not need to patch up faults.
+ */
+ mov pc, lr
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index aa109f074dd..19ca333240e 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/ptrace.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
new file mode 100644
index 00000000000..35ffc4d9599
--- /dev/null
+++ b/arch/arm/mm/cache-v7.S
@@ -0,0 +1,253 @@
+/*
+ * linux/arch/arm/mm/cache-v7.S
+ *
+ * Copyright (C) 2001 Deep Blue Solutions Ltd.
+ * Copyright (C) 2005 ARM Ltd.
+ *
+ * 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.
+ *
+ * This is the "shell" of the ARMv7 processor support.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+
+#include "proc-macros.S"
+
+/*
+ * v7_flush_dcache_all()
+ *
+ * Flush the whole D-cache.
+ *
+ * Corrupted registers: r0-r5, r7, r9-r11
+ *
+ * - mm - mm_struct describing address space
+ */
+ENTRY(v7_flush_dcache_all)
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr
+ ands r3, r0, #0x7000000 @ extract loc from clidr
+ mov r3, r3, lsr #23 @ left align loc bit field
+ beq finished @ if loc is 0, then no need to clean
+ mov r10, #0 @ start clean at cache level 0
+loop1:
+ add r2, r10, r10, lsr #1 @ work out 3x current cache level
+ mov r1, r0, lsr r2 @ extract cache type bits from clidr
+ and r1, r1, #7 @ mask of the bits for current cache only
+ cmp r1, #2 @ see what cache we have at this level
+ blt skip @ skip if no cache, or just i-cache
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ isb @ isb to sych the new cssr&csidr
+ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
+ and r2, r1, #7 @ extract the length of the cache lines
+ add r2, r2, #4 @ add 4 (line length offset)
+ ldr r4, =0x3ff
+ ands r4, r4, r1, lsr #3 @ find maximum number on the way size
+ clz r5, r4 @ find bit position of way size increment
+ ldr r7, =0x7fff
+ ands r7, r7, r1, lsr #13 @ extract max number of the index size
+loop2:
+ mov r9, r4 @ create working copy of max way size
+loop3:
+ orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
+ orr r11, r11, r7, lsl r2 @ factor index number into r11
+ mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
+ subs r9, r9, #1 @ decrement the way
+ bge loop3
+ subs r7, r7, #1 @ decrement the index
+ bge loop2
+skip:
+ add r10, r10, #2 @ increment cache number
+ cmp r3, r10
+ bgt loop1
+finished:
+ mov r10, #0 @ swith back to cache level 0
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ isb
+ mov pc, lr
+
+/*
+ * v7_flush_cache_all()
+ *
+ * Flush the entire cache system.
+ * The data cache flush is now achieved using atomic clean / invalidates
+ * working outwards from L1 cache. This is done using Set/Way based cache
+ * maintainance instructions.
+ * The instruction cache can still be invalidated back to the point of
+ * unification in a single instruction.
+ *
+ */
+ENTRY(v7_flush_kern_cache_all)
+ stmfd sp!, {r4-r5, r7, r9-r11, lr}
+ bl v7_flush_dcache_all
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
+ ldmfd sp!, {r4-r5, r7, r9-r11, lr}
+ mov pc, lr
+
+/*
+ * v7_flush_cache_all()
+ *
+ * Flush all TLB entries in a particular address space
+ *
+ * - mm - mm_struct describing address space
+ */
+ENTRY(v7_flush_user_cache_all)
+ /*FALLTHROUGH*/
+
+/*
+ * v7_flush_cache_range(start, end, flags)
+ *
+ * Flush a range of TLB entries in the specified address space.
+ *
+ * - start - start address (may not be aligned)
+ * - end - end address (exclusive, may not be aligned)
+ * - flags - vm_area_struct flags describing address space
+ *
+ * It is assumed that:
+ * - we have a VIPT cache.
+ */
+ENTRY(v7_flush_user_cache_range)
+ mov pc, lr
+
+/*
+ * v7_coherent_kern_range(start,end)
+ *
+ * Ensure that the I and D caches are coherent within specified
+ * region. This is typically used when code has been written to
+ * a memory region, and will be executed.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ *
+ * It is assumed that:
+ * - the Icache does not read data from the write buffer
+ */
+ENTRY(v7_coherent_kern_range)
+ /* FALLTHROUGH */
+
+/*
+ * v7_coherent_user_range(start,end)
+ *
+ * Ensure that the I and D caches are coherent within specified
+ * region. This is typically used when code has been written to
+ * a memory region, and will be executed.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ *
+ * It is assumed that:
+ * - the Icache does not read data from the write buffer
+ */
+ENTRY(v7_coherent_user_range)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+1: mcr p15, 0, r0, c7, c11, 1 @ clean D line to the point of unification
+ dsb
+ mcr p15, 0, r0, c7, c5, 1 @ invalidate I line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB
+ dsb
+ isb
+ mov pc, lr
+
+/*
+ * v7_flush_kern_dcache_page(kaddr)
+ *
+ * Ensure that the data held in the page kaddr is written back
+ * to the page in question.
+ *
+ * - kaddr - kernel address (guaranteed to be page aligned)
+ */
+ENTRY(v7_flush_kern_dcache_page)
+ dcache_line_size r2, r3
+ add r1, r0, #PAGE_SZ
+1:
+ mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line / unified line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ dsb
+ mov pc, lr
+
+/*
+ * v7_dma_inv_range(start,end)
+ *
+ * Invalidate the data cache within the specified region; we will
+ * be performing a DMA operation in this region and we want to
+ * purge old data in the cache.
+ *
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_inv_range)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ tst r0, r3
+ bic r0, r0, r3
+ mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
+
+ tst r1, r3
+ bic r1, r1, r3
+ mcrne p15, 0, r1, c7, c14, 1 @ clean & invalidate D / U line
+1:
+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ dsb
+ mov pc, lr
+
+/*
+ * v7_dma_clean_range(start,end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_clean_range)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+1:
+ mcr p15, 0, r0, c7, c10, 1 @ clean D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ dsb
+ mov pc, lr
+
+/*
+ * v7_dma_flush_range(start,end)
+ * - start - virtual start address of region
+ * - end - virtual end address of region
+ */
+ENTRY(v7_dma_flush_range)
+ dcache_line_size r2, r3
+ sub r3, r2, #1
+ bic r0, r0, r3
+1:
+ mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
+ add r0, r0, r2
+ cmp r0, r1
+ blo 1b
+ dsb
+ mov pc, lr
+
+ __INITDATA
+
+ .type v7_cache_fns, #object
+ENTRY(v7_cache_fns)
+ .long v7_flush_kern_cache_all
+ .long v7_flush_user_cache_all
+ .long v7_flush_user_cache_range
+ .long v7_coherent_kern_range
+ .long v7_coherent_user_range
+ .long v7_flush_kern_dcache_page
+ .long v7_dma_inv_range
+ .long v7_dma_clean_range
+ .long v7_dma_flush_range
+ .size v7_cache_fns, . - v7_cache_fns
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 9da43a0fdcd..fc84fcc7438 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -14,7 +14,8 @@
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
-unsigned int cpu_last_asid = { 1 << ASID_BITS };
+static DEFINE_SPINLOCK(cpu_asid_lock);
+unsigned int cpu_last_asid = ASID_FIRST_VERSION;
/*
* We fork()ed a process, and we need a new context for the child
@@ -31,15 +32,16 @@ void __new_context(struct mm_struct *mm)
{
unsigned int asid;
+ spin_lock(&cpu_asid_lock);
asid = ++cpu_last_asid;
if (asid == 0)
- asid = cpu_last_asid = 1 << ASID_BITS;
+ asid = cpu_last_asid = ASID_FIRST_VERSION;
/*
* If we've used up all our ASIDs, we need
* to start a new version and flush the TLB.
*/
- if ((asid & ~ASID_MASK) == 0) {
+ if (unlikely((asid & ~ASID_MASK) == 0)) {
asid = ++cpu_last_asid;
/* set the reserved ASID before flushing the TLB */
asm("mcr p15, 0, %0, c13, c0, 1 @ set reserved context ID\n"
@@ -47,7 +49,16 @@ void __new_context(struct mm_struct *mm)
: "r" (0));
isb();
flush_tlb_all();
+ if (icache_is_vivt_asid_tagged()) {
+ asm("mcr p15, 0, %0, c7, c5, 0 @ invalidate I-cache\n"
+ "mcr p15, 0, %0, c7, c5, 6 @ flush BTAC/BTB\n"
+ :
+ : "r" (0));
+ dsb();
+ }
}
+ spin_unlock(&cpu_asid_lock);
+ mm->cpu_vm_mask = cpumask_of_cpu(smp_processor_id());
mm->context.id = asid;
}
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 9fd6d2eafb4..75d491448e4 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
#include <linux/signal.h>
-#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/init.h>
@@ -438,7 +437,7 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *)
/*
* Dispatch a data abort to the relevant handler.
*/
-asmlinkage void
+asmlinkage void __exception
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
@@ -454,10 +453,10 @@ do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
info.si_errno = 0;
info.si_code = inf->code;
info.si_addr = (void __user *)addr;
- notify_die("", regs, &info, fsr, 0);
+ arm_notify_die("", regs, &info, fsr, 0);
}
-asmlinkage void
+asmlinkage void __exception
do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
{
do_translation_fault(addr, 0, regs);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 7760193e74c..c0ad7c0fbae 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -9,7 +9,6 @@
*/
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/ptrace.h>
#include <linux/swap.h>
#include <linux/init.h>
#include <linux/bootmem.h>
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 0ac615c0f79..d6167ad4e01 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -32,6 +32,9 @@
#include <asm/tlbflush.h>
#include <asm/sizes.h>
+#include <asm/mach/map.h>
+#include "mm.h"
+
/*
* Used by ioremap() and iounmap() code to mark (super)section-mapped
* I/O regions in vm_struct->flags field.
@@ -39,8 +42,9 @@
#define VM_ARM_SECTION_MAPPING 0x80000000
static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
- unsigned long phys_addr, pgprot_t prot)
+ unsigned long phys_addr, const struct mem_type *type)
{
+ pgprot_t prot = __pgprot(type->prot_pte);
pte_t *pte;
pte = pte_alloc_kernel(pmd, addr);
@@ -51,7 +55,8 @@ static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
if (!pte_none(*pte))
goto bad;
- set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot), 0);
+ set_pte_ext(pte, pfn_pte(phys_addr >> PAGE_SHIFT, prot),
+ type->prot_pte_ext);
phys_addr += PAGE_SIZE;
} while (pte++, addr += PAGE_SIZE, addr != end);
return 0;
@@ -63,7 +68,7 @@ static int remap_area_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr,
unsigned long end, unsigned long phys_addr,
- pgprot_t prot)
+ const struct mem_type *type)
{
unsigned long next;
pmd_t *pmd;
@@ -75,7 +80,7 @@ static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr,
do {
next = pmd_addr_end(addr, end);
- ret = remap_area_pte(pmd, addr, next, phys_addr, prot);
+ ret = remap_area_pte(pmd, addr, next, phys_addr, type);
if (ret)
return ret;
phys_addr += next - addr;
@@ -84,13 +89,11 @@ static inline int remap_area_pmd(pgd_t *pgd, unsigned long addr,
}
static int remap_area_pages(unsigned long start, unsigned long pfn,
- unsigned long size, unsigned long flags)
+ size_t size, const struct mem_type *type)
{
unsigned long addr = start;
unsigned long next, end = start + size;
unsigned long phys_addr = __pfn_to_phys(pfn);
- pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
- L_PTE_DIRTY | L_PTE_WRITE | flags);
pgd_t *pgd;
int err = 0;
@@ -98,7 +101,7 @@ static int remap_area_pages(unsigned long start, unsigned long pfn,
pgd = pgd_offset_k(addr);
do {
next = pgd_addr_end(addr, end);
- err = remap_area_pmd(pgd, addr, next, phys_addr, prot);
+ err = remap_area_pmd(pgd, addr, next, phys_addr, type);
if (err)
break;
phys_addr += next - addr;
@@ -178,9 +181,9 @@ static void unmap_area_sections(unsigned long virt, unsigned long size)
static int
remap_area_sections(unsigned long virt, unsigned long pfn,
- unsigned long size, unsigned long flags)
+ size_t size, const struct mem_type *type)
{
- unsigned long prot, addr = virt, end = virt + size;
+ unsigned long addr = virt, end = virt + size;
pgd_t *pgd;
/*
@@ -189,23 +192,13 @@ remap_area_sections(unsigned long virt, unsigned long pfn,
*/
unmap_area_sections(virt, size);
- prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_DOMAIN(DOMAIN_IO) |
- (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE));
-
- /*
- * ARMv6 and above need XN set to prevent speculative prefetches
- * hitting IO.
- */
- if (cpu_architecture() >= CPU_ARCH_ARMv6)
- prot |= PMD_SECT_XN;
-
pgd = pgd_offset_k(addr);
do {
pmd_t *pmd = pmd_offset(pgd, addr);
- pmd[0] = __pmd(__pfn_to_phys(pfn) | prot);
+ pmd[0] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
pfn += SZ_1M >> PAGE_SHIFT;
- pmd[1] = __pmd(__pfn_to_phys(pfn) | prot);
+ pmd[1] = __pmd(__pfn_to_phys(pfn) | type->prot_sect);
pfn += SZ_1M >> PAGE_SHIFT;
flush_pmd_entry(pmd);
@@ -218,9 +211,9 @@ remap_area_sections(unsigned long virt, unsigned long pfn,
static int
remap_area_supersections(unsigned long virt, unsigned long pfn,
- unsigned long size, unsigned long flags)
+ size_t size, const struct mem_type *type)
{
- unsigned long prot, addr = virt, end = virt + size;
+ unsigned long addr = virt, end = virt + size;
pgd_t *pgd;
/*
@@ -229,22 +222,12 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
*/
unmap_area_sections(virt, size);
- prot = PMD_TYPE_SECT | PMD_SECT_SUPER | PMD_SECT_AP_WRITE |
- PMD_DOMAIN(DOMAIN_IO) |
- (flags & (L_PTE_CACHEABLE | L_PTE_BUFFERABLE));
-
- /*
- * ARMv6 and above need XN set to prevent speculative prefetches
- * hitting IO.
- */
- if (cpu_architecture() >= CPU_ARCH_ARMv6)
- prot |= PMD_SECT_XN;
-
pgd = pgd_offset_k(virt);
do {
unsigned long super_pmd_val, i;
- super_pmd_val = __pfn_to_phys(pfn) | prot;
+ super_pmd_val = __pfn_to_phys(pfn) | type->prot_sect |
+ PMD_SECT_SUPER;
super_pmd_val |= ((pfn >> (32 - PAGE_SHIFT)) & 0xf) << 20;
for (i = 0; i < 8; i++) {
@@ -279,9 +262,10 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
* mapping. See include/asm-arm/proc-armv/pgtable.h for more information.
*/
void __iomem *
-__ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
- unsigned long flags)
+__arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
+ unsigned int mtype)
{
+ const struct mem_type *type;
int err;
unsigned long addr;
struct vm_struct * area;
@@ -292,6 +276,10 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
return NULL;
+ type = get_mem_type(mtype);
+ if (!type)
+ return NULL;
+
size = PAGE_ALIGN(size);
area = get_vm_area(size, VM_IOREMAP);
@@ -302,16 +290,16 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
#ifndef CONFIG_SMP
if (DOMAIN_IO == 0 &&
(((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
- cpu_is_xsc3()) &&
+ cpu_is_xsc3()) && pfn >= 0x100000 &&
!((__pfn_to_phys(pfn) | size | addr) & ~SUPERSECTION_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
- err = remap_area_supersections(addr, pfn, size, flags);
+ err = remap_area_supersections(addr, pfn, size, type);
} else if (!((__pfn_to_phys(pfn) | size | addr) & ~PMD_MASK)) {
area->flags |= VM_ARM_SECTION_MAPPING;
- err = remap_area_sections(addr, pfn, size, flags);
+ err = remap_area_sections(addr, pfn, size, type);
} else
#endif
- err = remap_area_pages(addr, pfn, size, flags);
+ err = remap_area_pages(addr, pfn, size, type);
if (err) {
vunmap((void *)addr);
@@ -321,10 +309,10 @@ __ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
flush_cache_vmap(addr, addr + size);
return (void __iomem *) (offset + addr);
}
-EXPORT_SYMBOL(__ioremap_pfn);
+EXPORT_SYMBOL(__arm_ioremap_pfn);
void __iomem *
-__ioremap(unsigned long phys_addr, size_t size, unsigned long flags)
+__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
{
unsigned long last_addr;
unsigned long offset = phys_addr & ~PAGE_MASK;
@@ -342,9 +330,9 @@ __ioremap(unsigned long phys_addr, size_t size, unsigned long flags)
*/
size = PAGE_ALIGN(last_addr + 1) - phys_addr;
- return __ioremap_pfn(pfn, offset, size, flags);
+ return __arm_ioremap_pfn(pfn, offset, size, mtype);
}
-EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(__arm_ioremap);
void __iounmap(volatile void __iomem *addr)
{
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
index a44e3097063..7647c597fc5 100644
--- a/arch/arm/mm/mm.h
+++ b/arch/arm/mm/mm.h
@@ -16,6 +16,16 @@ static inline pmd_t *pmd_off_k(unsigned long virt)
return pmd_off(pgd_offset_k(virt), virt);
}
+struct mem_type {
+ unsigned int prot_pte;
+ unsigned int prot_pte_ext;
+ unsigned int prot_l1;
+ unsigned int prot_sect;
+ unsigned int domain;
+};
+
+const struct mem_type *get_mem_type(unsigned int type);
+
#endif
struct map_desc;
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index b0b5f469407..2c4c2422cd1 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -49,8 +49,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
#endif
/*
- * We should enforce the MAP_FIXED case. However, currently
- * the generic kernel code doesn't allow us to handle this.
+ * We enforce the MAP_FIXED case.
*/
if (flags & MAP_FIXED) {
if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1))
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 94fd4bf5cb9..2ba1530d1ce 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -176,28 +176,42 @@ void adjust_cr(unsigned long mask, unsigned long set)
}
#endif
-struct mem_types {
- unsigned int prot_pte;
- unsigned int prot_l1;
- unsigned int prot_sect;
- unsigned int domain;
-};
-
-static struct mem_types mem_types[] __initdata = {
- [MT_DEVICE] = {
- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
- L_PTE_WRITE,
- .prot_l1 = PMD_TYPE_TABLE,
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
- PMD_SECT_AP_WRITE,
- .domain = DOMAIN_IO,
+#define PROT_PTE_DEVICE L_PTE_PRESENT|L_PTE_YOUNG|L_PTE_DIRTY|L_PTE_WRITE
+#define PROT_SECT_DEVICE PMD_TYPE_SECT|PMD_SECT_XN|PMD_SECT_AP_WRITE
+
+static struct mem_type mem_types[] = {
+ [MT_DEVICE] = { /* Strongly ordered / ARMv6 shared device */
+ .prot_pte = PROT_PTE_DEVICE,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_UNCACHED,
+ .domain = DOMAIN_IO,
+ },
+ [MT_DEVICE_NONSHARED] = { /* ARMv6 non-shared device */
+ .prot_pte = PROT_PTE_DEVICE,
+ .prot_pte_ext = PTE_EXT_TEX(2),
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_TEX(2),
+ .domain = DOMAIN_IO,
+ },
+ [MT_DEVICE_CACHED] = { /* ioremap_cached */
+ .prot_pte = PROT_PTE_DEVICE | L_PTE_CACHEABLE | L_PTE_BUFFERABLE,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_WB,
+ .domain = DOMAIN_IO,
+ },
+ [MT_DEVICE_IXP2000] = { /* IXP2400 requires XCB=101 for on-chip I/O */
+ .prot_pte = PROT_PTE_DEVICE,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PROT_SECT_DEVICE | PMD_SECT_BUFFERABLE |
+ PMD_SECT_TEX(1),
+ .domain = DOMAIN_IO,
},
[MT_CACHECLEAN] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN,
.domain = DOMAIN_KERNEL,
},
[MT_MINICLEAN] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE,
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_XN | PMD_SECT_MINICACHE,
.domain = DOMAIN_KERNEL,
},
[MT_LOW_VECTORS] = {
@@ -213,30 +227,20 @@ static struct mem_types mem_types[] __initdata = {
.domain = DOMAIN_USER,
},
[MT_MEMORY] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE,
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
.domain = DOMAIN_KERNEL,
},
[MT_ROM] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+ .prot_sect = PMD_TYPE_SECT,
.domain = DOMAIN_KERNEL,
},
- [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
- L_PTE_WRITE,
- .prot_l1 = PMD_TYPE_TABLE,
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
- PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
- PMD_SECT_TEX(1),
- .domain = DOMAIN_IO,
- },
- [MT_NONSHARED_DEVICE] = {
- .prot_l1 = PMD_TYPE_TABLE,
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_NONSHARED_DEV |
- PMD_SECT_AP_WRITE,
- .domain = DOMAIN_IO,
- }
};
+const struct mem_type *get_mem_type(unsigned int type)
+{
+ return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
+}
+
/*
* Adjust the PMD section entries according to the CPU in use.
*/
@@ -262,20 +266,23 @@ static void __init build_mem_type_table(void)
}
/*
- * Xscale must not have PMD bit 4 set for section mappings.
+ * ARMv5 and lower, bit 4 must be set for page tables.
+ * (was: cache "update-able on write" bit on ARM610)
+ * However, Xscale cores require this bit to be cleared.
*/
- if (cpu_is_xscale())
- for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+ if (cpu_is_xscale()) {
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
mem_types[i].prot_sect &= ~PMD_BIT4;
-
- /*
- * ARMv5 and lower, excluding Xscale, bit 4 must be set for
- * page tables.
- */
- if (cpu_arch < CPU_ARCH_ARMv6 && !cpu_is_xscale())
- for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+ mem_types[i].prot_l1 &= ~PMD_BIT4;
+ }
+ } else if (cpu_arch < CPU_ARCH_ARMv6) {
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
if (mem_types[i].prot_l1)
mem_types[i].prot_l1 |= PMD_BIT4;
+ if (mem_types[i].prot_sect)
+ mem_types[i].prot_sect |= PMD_BIT4;
+ }
+ }
cp = &cache_policies[cachepolicy];
kern_pgprot = user_pgprot = cp->pte;
@@ -296,13 +303,6 @@ static void __init build_mem_type_table(void)
*/
if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
/*
- * bit 4 becomes XN which we must clear for the
- * kernel memory mapping.
- */
- mem_types[MT_MEMORY].prot_sect &= ~PMD_SECT_XN;
- mem_types[MT_ROM].prot_sect &= ~PMD_SECT_XN;
-
- /*
* Mark cache clean areas and XIP ROM read only
* from SVC mode and no access from userspace.
*/
@@ -368,64 +368,126 @@ static void __init build_mem_type_table(void)
}
printk("Memory policy: ECC %sabled, Data cache %s\n",
ecc_mask ? "en" : "dis", cp->policy);
+
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
+ struct mem_type *t = &mem_types[i];
+ if (t->prot_l1)
+ t->prot_l1 |= PMD_DOMAIN(t->domain);
+ if (t->prot_sect)
+ t->prot_sect |= PMD_DOMAIN(t->domain);
+ }
}
#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
-/*
- * Create a SECTION PGD between VIRT and PHYS in domain
- * DOMAIN with protection PROT. This operates on half-
- * pgdir entry increments.
- */
-static inline void
-alloc_init_section(unsigned long virt, unsigned long phys, int prot)
+static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
+ unsigned long end, unsigned long pfn,
+ const struct mem_type *type)
{
- pmd_t *pmdp = pmd_off_k(virt);
+ pte_t *pte;
- if (virt & (1 << 20))
- pmdp++;
+ if (pmd_none(*pmd)) {
+ pte = alloc_bootmem_low_pages(2 * PTRS_PER_PTE * sizeof(pte_t));
+ __pmd_populate(pmd, __pa(pte) | type->prot_l1);
+ }
- *pmdp = __pmd(phys | prot);
- flush_pmd_entry(pmdp);
+ pte = pte_offset_kernel(pmd, addr);
+ do {
+ set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)),
+ type->prot_pte_ext);
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
}
-/*
- * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
- */
-static inline void
-alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
+static void __init alloc_init_section(pgd_t *pgd, unsigned long addr,
+ unsigned long end, unsigned long phys,
+ const struct mem_type *type)
{
- int i;
+ pmd_t *pmd = pmd_offset(pgd, addr);
+
+ /*
+ * Try a section mapping - end, addr and phys must all be aligned
+ * to a section boundary. Note that PMDs refer to the individual
+ * L1 entries, whereas PGDs refer to a group of L1 entries making
+ * up one logical pointer to an L2 table.
+ */
+ if (((addr | end | phys) & ~SECTION_MASK) == 0) {
+ pmd_t *p = pmd;
+
+ if (addr & SECTION_SIZE)
+ pmd++;
- for (i = 0; i < 16; i += 1) {
- alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
+ do {
+ *pmd = __pmd(phys | type->prot_sect);
+ phys += SECTION_SIZE;
+ } while (pmd++, addr += SECTION_SIZE, addr != end);
- virt += (PGDIR_SIZE / 2);
+ flush_pmd_entry(p);
+ } else {
+ /*
+ * No need to loop; pte's aren't interested in the
+ * individual L1 entries.
+ */
+ alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
}
}
-/*
- * Add a PAGE mapping between VIRT and PHYS in domain
- * DOMAIN with protection PROT. Note that due to the
- * way we map the PTEs, we must allocate two PTE_SIZE'd
- * blocks - one for the Linux pte table, and one for
- * the hardware pte table.
- */
-static inline void
-alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
+static void __init create_36bit_mapping(struct map_desc *md,
+ const struct mem_type *type)
{
- pmd_t *pmdp = pmd_off_k(virt);
- pte_t *ptep;
+ unsigned long phys, addr, length, end;
+ pgd_t *pgd;
+
+ addr = md->virtual;
+ phys = (unsigned long)__pfn_to_phys(md->pfn);
+ length = PAGE_ALIGN(md->length);
+
+ if (!(cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())) {
+ printk(KERN_ERR "MM: CPU does not support supersection "
+ "mapping for 0x%08llx at 0x%08lx\n",
+ __pfn_to_phys((u64)md->pfn), addr);
+ return;
+ }
- if (pmd_none(*pmdp)) {
- ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
- sizeof(pte_t));
+ /* N.B. ARMv6 supersections are only defined to work with domain 0.
+ * Since domain assignments can in fact be arbitrary, the
+ * 'domain == 0' check below is required to insure that ARMv6
+ * supersections are only allocated for domain 0 regardless
+ * of the actual domain assignments in use.
+ */
+ if (type->domain) {
+ printk(KERN_ERR "MM: invalid domain in supersection "
+ "mapping for 0x%08llx at 0x%08lx\n",
+ __pfn_to_phys((u64)md->pfn), addr);
+ return;
+ }
- __pmd_populate(pmdp, __pa(ptep) | prot_l1);
+ if ((addr | length | __pfn_to_phys(md->pfn)) & ~SUPERSECTION_MASK) {
+ printk(KERN_ERR "MM: cannot create mapping for "
+ "0x%08llx at 0x%08lx invalid alignment\n",
+ __pfn_to_phys((u64)md->pfn), addr);
+ return;
}
- ptep = pte_offset_kernel(pmdp, virt);
- set_pte_ext(ptep, pfn_pte(phys >> PAGE_SHIFT, prot), 0);
+ /*
+ * Shift bits [35:32] of address into bits [23:20] of PMD
+ * (See ARMv6 spec).
+ */
+ phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+
+ pgd = pgd_offset_k(addr);
+ end = addr + length;
+ do {
+ pmd_t *pmd = pmd_offset(pgd, addr);
+ int i;
+
+ for (i = 0; i < 16; i++)
+ *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER);
+
+ addr += SUPERSECTION_SIZE;
+ phys += SUPERSECTION_SIZE;
+ pgd += SUPERSECTION_SIZE >> PGDIR_SHIFT;
+ } while (addr != end);
}
/*
@@ -437,10 +499,9 @@ alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pg
*/
void __init create_mapping(struct map_desc *md)
{
- unsigned long virt, length;
- int prot_sect, prot_l1, domain;
- pgprot_t prot_pte;
- unsigned long off = (u32)__pfn_to_phys(md->pfn);
+ unsigned long phys, addr, length, end;
+ const struct mem_type *type;
+ pgd_t *pgd;
if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
printk(KERN_WARNING "BUG: not creating mapping for "
@@ -456,105 +517,37 @@ void __init create_mapping(struct map_desc *md)
__pfn_to_phys((u64)md->pfn), md->virtual);
}
- domain = mem_types[md->type].domain;
- prot_pte = __pgprot(mem_types[md->type].prot_pte);
- prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
- prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
+ type = &mem_types[md->type];
/*
* Catch 36-bit addresses
*/
- if(md->pfn >= 0x100000) {
- if(domain) {
- printk(KERN_ERR "MM: invalid domain in supersection "
- "mapping for 0x%08llx at 0x%08lx\n",
- __pfn_to_phys((u64)md->pfn), md->virtual);
- return;
- }
- if((md->virtual | md->length | __pfn_to_phys(md->pfn))
- & ~SUPERSECTION_MASK) {
- printk(KERN_ERR "MM: cannot create mapping for "
- "0x%08llx at 0x%08lx invalid alignment\n",
- __pfn_to_phys((u64)md->pfn), md->virtual);
- return;
- }
-
- /*
- * Shift bits [35:32] of address into bits [23:20] of PMD
- * (See ARMv6 spec).
- */
- off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+ if (md->pfn >= 0x100000) {
+ create_36bit_mapping(md, type);
+ return;
}
- virt = md->virtual;
- off -= virt;
- length = md->length;
+ addr = md->virtual;
+ phys = (unsigned long)__pfn_to_phys(md->pfn);
+ length = PAGE_ALIGN(md->length);
- if (mem_types[md->type].prot_l1 == 0 &&
- (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
+ if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
"be mapped using pages, ignoring.\n",
- __pfn_to_phys(md->pfn), md->virtual);
+ __pfn_to_phys(md->pfn), addr);
return;
}
- while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
- alloc_init_page(virt, virt + off, prot_l1, prot_pte);
+ pgd = pgd_offset_k(addr);
+ end = addr + length;
+ do {
+ unsigned long next = pgd_addr_end(addr, end);
- virt += PAGE_SIZE;
- length -= PAGE_SIZE;
- }
-
- /* N.B. ARMv6 supersections are only defined to work with domain 0.
- * Since domain assignments can in fact be arbitrary, the
- * 'domain == 0' check below is required to insure that ARMv6
- * supersections are only allocated for domain 0 regardless
- * of the actual domain assignments in use.
- */
- if ((cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())
- && domain == 0) {
- /*
- * Align to supersection boundary if !high pages.
- * High pages have already been checked for proper
- * alignment above and they will fail the SUPSERSECTION_MASK
- * check because of the way the address is encoded into
- * offset.
- */
- if (md->pfn <= 0x100000) {
- while ((virt & ~SUPERSECTION_MASK ||
- (virt + off) & ~SUPERSECTION_MASK) &&
- length >= (PGDIR_SIZE / 2)) {
- alloc_init_section(virt, virt + off, prot_sect);
-
- virt += (PGDIR_SIZE / 2);
- length -= (PGDIR_SIZE / 2);
- }
- }
+ alloc_init_section(pgd, addr, next, phys, type);
- while (length >= SUPERSECTION_SIZE) {
- alloc_init_supersection(virt, virt + off, prot_sect);
-
- virt += SUPERSECTION_SIZE;
- length -= SUPERSECTION_SIZE;
- }
- }
-
- /*
- * A section mapping covers half a "pgdir" entry.
- */
- while (length >= (PGDIR_SIZE / 2)) {
- alloc_init_section(virt, virt + off, prot_sect);
-
- virt += (PGDIR_SIZE / 2);
- length -= (PGDIR_SIZE / 2);
- }
-
- while (length >= PAGE_SIZE) {
- alloc_init_page(virt, virt + off, prot_l1, prot_pte);
-
- virt += PAGE_SIZE;
- length -= PAGE_SIZE;
- }
+ phys += next - addr;
+ addr = next;
+ } while (pgd++, addr != end);
}
/*
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 05818fc0c70..8cd3a60954f 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -62,21 +62,21 @@ void flush_dcache_page(struct page *page)
}
EXPORT_SYMBOL(flush_dcache_page);
-void __iomem *__ioremap_pfn(unsigned long pfn, unsigned long offset,
- size_t size, unsigned long flags)
+void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset,
+ size_t size, unsigned int mtype)
{
if (pfn >= (0x100000000ULL >> PAGE_SHIFT))
return NULL;
return (void __iomem *) (offset + (pfn << PAGE_SHIFT));
}
-EXPORT_SYMBOL(__ioremap_pfn);
+EXPORT_SYMBOL(__arm_ioremap_pfn);
-void __iomem *__ioremap(unsigned long phys_addr, size_t size,
- unsigned long flags)
+void __iomem *__arm_ioremap(unsigned long phys_addr, size_t size,
+ unsigned int mtype)
{
return (void __iomem *)phys_addr;
}
-EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(__arm_ioremap);
void __iounmap(volatile void __iomem *addr)
{
diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S
index 9e2c89eb211..b13150052a7 100644
--- a/arch/arm/mm/proc-macros.S
+++ b/arch/arm/mm/proc-macros.S
@@ -59,3 +59,15 @@
.word \ucset
#endif
.endm
+
+/*
+ * cache_line_size - get the cache line size from the CSIDR register
+ * (available on ARMv7+). It assumes that the CSSR register was configured
+ * to access the L1 data cache CSIDR.
+ */
+ .macro dcache_line_size, reg, tmp
+ mrc p15, 1, \tmp, c0, c0, 0 @ read CSIDR
+ and \tmp, \tmp, #7 @ cache line size encoding
+ mov \reg, #16 @ size offset
+ mov \reg, \reg, lsl \tmp @ actual cache line size
+ .endm
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
new file mode 100644
index 00000000000..dd823dd4a37
--- /dev/null
+++ b/arch/arm/mm/proc-v7.S
@@ -0,0 +1,262 @@
+/*
+ * linux/arch/arm/mm/proc-v7.S
+ *
+ * Copyright (C) 2001 Deep Blue Solutions Ltd.
+ *
+ * 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.
+ *
+ * This is the "shell" of the ARMv7 processor support.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/elf.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+
+#include "proc-macros.S"
+
+#define TTB_C (1 << 0)
+#define TTB_S (1 << 1)
+#define TTB_RGN_OC_WT (2 << 3)
+#define TTB_RGN_OC_WB (3 << 3)
+
+ENTRY(cpu_v7_proc_init)
+ mov pc, lr
+
+ENTRY(cpu_v7_proc_fin)
+ mov pc, lr
+
+/*
+ * cpu_v7_reset(loc)
+ *
+ * Perform a soft reset of the system. Put the CPU into the
+ * same state as it would be if it had been reset, and branch
+ * to what would be the reset vector.
+ *
+ * - loc - location to jump to for soft reset
+ *
+ * It is assumed that:
+ */
+ .align 5
+ENTRY(cpu_v7_reset)
+ mov pc, r0
+
+/*
+ * cpu_v7_do_idle()
+ *
+ * Idle the processor (eg, wait for interrupt).
+ *
+ * IRQs are already disabled.
+ */
+ENTRY(cpu_v7_do_idle)
+ .long 0xe320f003 @ ARM V7 WFI instruction
+ mov pc, lr
+
+ENTRY(cpu_v7_dcache_clean_area)
+#ifndef TLB_CAN_READ_FROM_L1_CACHE
+ dcache_line_size r2, r3
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ add r0, r0, r2
+ subs r1, r1, r2
+ bhi 1b
+ dsb
+#endif
+ mov pc, lr
+
+/*
+ * cpu_v7_switch_mm(pgd_phys, tsk)
+ *
+ * Set the translation table base pointer to be pgd_phys
+ *
+ * - pgd_phys - physical address of new TTB
+ *
+ * It is assumed that:
+ * - we are not using split page tables
+ */
+ENTRY(cpu_v7_switch_mm)
+ mov r2, #0
+ ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
+ orr r0, r0, #TTB_RGN_OC_WB @ mark PTWs outer cacheable, WB
+ mcr p15, 0, r2, c13, c0, 1 @ set reserved context ID
+ isb
+1: mcr p15, 0, r0, c2, c0, 0 @ set TTB 0
+ isb
+ mcr p15, 0, r1, c13, c0, 1 @ set context ID
+ isb
+ mov pc, lr
+
+/*
+ * cpu_v7_set_pte_ext(ptep, pte)
+ *
+ * Set a level 2 translation table entry.
+ *
+ * - ptep - pointer to level 2 translation table entry
+ * (hardware version is stored at -1024 bytes)
+ * - pte - PTE value to store
+ * - ext - value for extended PTE bits
+ *
+ * Permissions:
+ * YUWD APX AP1 AP0 SVC User
+ * 0xxx 0 0 0 no acc no acc
+ * 100x 1 0 1 r/o no acc
+ * 10x0 1 0 1 r/o no acc
+ * 1011 0 0 1 r/w no acc
+ * 110x 0 1 0 r/w r/o
+ * 11x0 0 1 0 r/w r/o
+ * 1111 0 1 1 r/w r/w
+ */
+ENTRY(cpu_v7_set_pte_ext)
+ str r1, [r0], #-2048 @ linux version
+
+ bic r3, r1, #0x000003f0
+ bic r3, r3, #0x00000003
+ orr r3, r3, r2
+ orr r3, r3, #PTE_EXT_AP0 | 2
+
+ tst r1, #L_PTE_WRITE
+ tstne r1, #L_PTE_DIRTY
+ orreq r3, r3, #PTE_EXT_APX
+
+ tst r1, #L_PTE_USER
+ orrne r3, r3, #PTE_EXT_AP1
+ tstne r3, #PTE_EXT_APX
+ bicne r3, r3, #PTE_EXT_APX | PTE_EXT_AP0
+
+ tst r1, #L_PTE_YOUNG
+ biceq r3, r3, #PTE_EXT_APX | PTE_EXT_AP_MASK
+
+ tst r1, #L_PTE_EXEC
+ orreq r3, r3, #PTE_EXT_XN
+
+ tst r1, #L_PTE_PRESENT
+ moveq r3, #0
+
+ str r3, [r0]
+ mcr p15, 0, r0, c7, c10, 1 @ flush_pte
+ mov pc, lr
+
+cpu_v7_name:
+ .ascii "ARMv7 Processor"
+ .align
+
+ .section ".text.init", #alloc, #execinstr
+
+/*
+ * __v7_setup
+ *
+ * Initialise TLB, Caches, and MMU state ready to switch the MMU
+ * on. Return in r0 the new CP15 C1 control register setting.
+ *
+ * We automatically detect if we have a Harvard cache, and use the
+ * Harvard cache control instructions insead of the unified cache
+ * control instructions.
+ *
+ * This should be able to cover all ARMv7 cores.
+ *
+ * It is assumed that:
+ * - cache type register is implemented
+ */
+__v7_setup:
+ adr r12, __v7_setup_stack @ the local stack
+ stmia r12, {r0-r5, r7, r9, r11, lr}
+ bl v7_flush_dcache_all
+ ldmia r12, {r0-r5, r7, r9, r11, lr}
+ mov r10, #0
+#ifdef HARVARD_CACHE
+ mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
+#endif
+ dsb
+ mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
+ mcr p15, 0, r10, c2, c0, 2 @ TTB control register
+ orr r4, r4, #TTB_RGN_OC_WB @ mark PTWs outer cacheable, WB
+ mcr p15, 0, r4, c2, c0, 0 @ load TTB0
+ mcr p15, 0, r4, c2, c0, 1 @ load TTB1
+ mov r10, #0x1f @ domains 0, 1 = manager
+ mcr p15, 0, r10, c3, c0, 0 @ load domain access register
+#ifndef CONFIG_CPU_L2CACHE_DISABLE
+ @ L2 cache configuration in the L2 aux control register
+ mrc p15, 1, r10, c9, c0, 2
+ bic r10, r10, #(1 << 16) @ L2 outer cache
+ mcr p15, 1, r10, c9, c0, 2
+ @ L2 cache is enabled in the aux control register
+ mrc p15, 0, r10, c1, c0, 1
+ orr r10, r10, #2
+ mcr p15, 0, r10, c1, c0, 1
+#endif
+ mrc p15, 0, r0, c1, c0, 0 @ read control register
+ ldr r10, cr1_clear @ get mask for bits to clear
+ bic r0, r0, r10 @ clear bits them
+ ldr r10, cr1_set @ get mask for bits to set
+ orr r0, r0, r10 @ set them
+ mov pc, lr @ return to head.S:__ret
+
+ /*
+ * V X F I D LR
+ * .... ...E PUI. .T.T 4RVI ZFRS BLDP WCAM
+ * rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
+ * 0 110 0011 1.00 .111 1101 < we want
+ */
+ .type cr1_clear, #object
+ .type cr1_set, #object
+cr1_clear:
+ .word 0x0120c302
+cr1_set:
+ .word 0x00c0387d
+
+__v7_setup_stack:
+ .space 4 * 11 @ 11 registers
+
+ .type v7_processor_functions, #object
+ENTRY(v7_processor_functions)
+ .word v7_early_abort
+ .word cpu_v7_proc_init
+ .word cpu_v7_proc_fin
+ .word cpu_v7_reset
+ .word cpu_v7_do_idle
+ .word cpu_v7_dcache_clean_area
+ .word cpu_v7_switch_mm
+ .word cpu_v7_set_pte_ext
+ .size v7_processor_functions, . - v7_processor_functions
+
+ .type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv7"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v7"
+ .size cpu_elf_name, . - cpu_elf_name
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+
+ /*
+ * Match any ARMv7 processor core.
+ */
+ .type __v7_proc_info, #object
+__v7_proc_info:
+ .long 0x000f0000 @ Required ID value
+ .long 0x000f0000 @ Mask for ID
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_XN | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ b __v7_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+ .long cpu_v7_name
+ .long v7_processor_functions
+ .long v6wbi_tlb_fns
+ .long v6_user_fns
+ .long v7_cache_fns
+ .size __v7_proc_info, . - __v7_proc_info
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index d29fe927ee9..c156ddab9a2 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -584,6 +584,11 @@ cpu_ixp42x_name:
.asciz "XScale-IXP42x Family"
.size cpu_ixp42x_name, . - cpu_ixp42x_name
+ .type cpu_ixp43x_name, #object
+cpu_ixp43x_name:
+ .asciz "XScale-IXP43x Family"
+ .size cpu_ixp43x_name, . - cpu_ixp43x_name
+
.type cpu_ixp46x_name, #object
cpu_ixp46x_name:
.asciz "XScale-IXP46x Family"
@@ -843,6 +848,29 @@ __ixp42x_proc_info:
.long xscale_cache_fns
.size __ixp42x_proc_info, . - __ixp42x_proc_info
+ .type __ixp43x_proc_info, #object
+__ixp43x_proc_info:
+ .long 0x69054040
+ .long 0xfffffff0
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ b __xscale_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+ .long cpu_ixp43x_name
+ .long xscale_processor_functions
+ .long v4wbi_tlb_fns
+ .long xscale_mc_user_fns
+ .long xscale_cache_fns
+ .size __ixp43x_proc_info, . - __ixp43x_proc_info
+
.type __ixp46x_proc_info, #object
__ixp46x_proc_info:
.long 0x69054200
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
index 7c22c12618c..f5ebf30151f 100644
--- a/arch/arm/oprofile/backtrace.c
+++ b/arch/arm/oprofile/backtrace.c
@@ -19,6 +19,19 @@
#include <asm/ptrace.h>
#include <asm/uaccess.h>
+#include "../kernel/stacktrace.h"
+
+static int report_trace(struct stackframe *frame, void *d)
+{
+ unsigned int *depth = d;
+
+ if (*depth) {
+ oprofile_add_trace(frame->lr);
+ (*depth)--;
+ }
+
+ return *depth == 0;
+}
/*
* The registers we're interested in are at the end of the variable
@@ -32,21 +45,6 @@ struct frame_tail {
unsigned long lr;
} __attribute__((packed));
-
-#ifdef CONFIG_FRAME_POINTER
-static struct frame_tail* kernel_backtrace(struct frame_tail *tail)
-{
- oprofile_add_trace(tail->lr);
-
- /* frame pointers should strictly progress back up the stack
- * (towards higher addresses) */
- if (tail >= tail->fp)
- return NULL;
-
- return tail->fp-1;
-}
-#endif
-
static struct frame_tail* user_backtrace(struct frame_tail *tail)
{
struct frame_tail buftail[2];
@@ -67,47 +65,14 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail)
return buftail[0].fp-1;
}
-/*
- * | | /\ Higher addresses
- * | |
- * --------------- stack base (address of current_thread_info)
- * | thread info |
- * . .
- * | stack |
- * --------------- saved regs->ARM_fp value if valid (frame_tail address)
- * . .
- * --------------- struct pt_regs stored on stack (struct pt_regs *)
- * | |
- * . .
- * | |
- * --------------- %esp
- * | |
- * | | \/ Lower addresses
- *
- * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
- */
-static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs)
-{
- unsigned long tailaddr = (unsigned long)tail;
- unsigned long stack = (unsigned long)regs;
- unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
-
- return (tailaddr > stack) && (tailaddr < stack_base);
-}
-
void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
{
- struct frame_tail *tail;
-
- tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+ struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
if (!user_mode(regs)) {
-
-#ifdef CONFIG_FRAME_POINTER
- while (depth-- && tail && valid_kernel_stack(tail, regs)) {
- tail = kernel_backtrace(tail);
- }
-#endif
+ unsigned long base = ((unsigned long)regs) & ~(THREAD_SIZE - 1);
+ walk_stackframe(regs->ARM_fp, base, base + THREAD_SIZE,
+ report_trace, &depth);
return;
}
diff --git a/arch/arm/plat-iop/io.c b/arch/arm/plat-iop/io.c
index f7eccecf2e4..498675d028d 100644
--- a/arch/arm/plat-iop/io.c
+++ b/arch/arm/plat-iop/io.c
@@ -22,7 +22,7 @@
#include <asm/io.h>
void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size,
- unsigned long flags)
+ unsigned int mtype)
{
void __iomem * retval;
@@ -34,7 +34,7 @@ void * __iomem __iop3xx_ioremap(unsigned long cookie, size_t size,
retval = (void *) IOP3XX_PMMR_PHYS_TO_VIRT(cookie);
break;
default:
- retval = __ioremap(cookie, size, flags);
+ retval = __arm_ioremap(cookie, size, mtype);
}
return retval;
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
index b5f6ec35aaf..e2744b7227c 100644
--- a/arch/arm/plat-iop/pci.c
+++ b/arch/arm/plat-iop/pci.c
@@ -55,7 +55,7 @@ static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where)
* This routine checks the status of the last configuration cycle. If an error
* was detected it returns a 1, else it returns a 0. The errors being checked
* are parity, master abort, target abort (master and target). These types of
- * errors occure during a config cycle where there is no device, like during
+ * errors occur during a config cycle where there is no device, like during
* the discovery stage.
*/
static int iop3xx_pci_status(void)
@@ -223,8 +223,111 @@ struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys)
return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
}
+void __init iop3xx_atu_setup(void)
+{
+ /* BAR 0 ( Disabled ) */
+ *IOP3XX_IAUBAR0 = 0x0;
+ *IOP3XX_IABAR0 = 0x0;
+ *IOP3XX_IATVR0 = 0x0;
+ *IOP3XX_IALR0 = 0x0;
+
+ /* BAR 1 ( Disabled ) */
+ *IOP3XX_IAUBAR1 = 0x0;
+ *IOP3XX_IABAR1 = 0x0;
+ *IOP3XX_IALR1 = 0x0;
+
+ /* BAR 2 (1:1 mapping with Physical RAM) */
+ /* Set limit and enable */
+ *IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1;
+ *IOP3XX_IAUBAR2 = 0x0;
+
+ /* Align the inbound bar with the base of memory */
+ *IOP3XX_IABAR2 = PHYS_OFFSET |
+ PCI_BASE_ADDRESS_MEM_TYPE_64 |
+ PCI_BASE_ADDRESS_MEM_PREFETCH;
+
+ *IOP3XX_IATVR2 = PHYS_OFFSET;
+
+ /* Outbound window 0 */
+ *IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_PA;
+ *IOP3XX_OUMWTVR0 = 0;
+
+ /* Outbound window 1 */
+ *IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE;
+ *IOP3XX_OUMWTVR1 = 0;
+
+ /* BAR 3 ( Disabled ) */
+ *IOP3XX_IAUBAR3 = 0x0;
+ *IOP3XX_IABAR3 = 0x0;
+ *IOP3XX_IATVR3 = 0x0;
+ *IOP3XX_IALR3 = 0x0;
+
+ /* Setup the I/O Bar
+ */
+ *IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_PA;;
+
+ /* Enable inbound and outbound cycles
+ */
+ *IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+ *IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN;
+}
+
+void __init iop3xx_atu_disable(void)
+{
+ *IOP3XX_ATUCMD = 0;
+ *IOP3XX_ATUCR = 0;
+
+ /* wait for cycles to quiesce */
+ while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY |
+ IOP3XX_PCSR_IN_Q_BUSY))
+ cpu_relax();
+
+ /* BAR 0 ( Disabled ) */
+ *IOP3XX_IAUBAR0 = 0x0;
+ *IOP3XX_IABAR0 = 0x0;
+ *IOP3XX_IATVR0 = 0x0;
+ *IOP3XX_IALR0 = 0x0;
+
+ /* BAR 1 ( Disabled ) */
+ *IOP3XX_IAUBAR1 = 0x0;
+ *IOP3XX_IABAR1 = 0x0;
+ *IOP3XX_IALR1 = 0x0;
+
+ /* BAR 2 ( Disabled ) */
+ *IOP3XX_IAUBAR2 = 0x0;
+ *IOP3XX_IABAR2 = 0x0;
+ *IOP3XX_IATVR2 = 0x0;
+ *IOP3XX_IALR2 = 0x0;
+
+ /* BAR 3 ( Disabled ) */
+ *IOP3XX_IAUBAR3 = 0x0;
+ *IOP3XX_IABAR3 = 0x0;
+ *IOP3XX_IATVR3 = 0x0;
+ *IOP3XX_IALR3 = 0x0;
+
+ /* Clear the outbound windows */
+ *IOP3XX_OIOWTVR = 0;
+
+ /* Outbound window 0 */
+ *IOP3XX_OMWTVR0 = 0;
+ *IOP3XX_OUMWTVR0 = 0;
+
+ /* Outbound window 1 */
+ *IOP3XX_OMWTVR1 = 0;
+ *IOP3XX_OUMWTVR1 = 0;
+}
+
+/* Flag to determine whether the ATU is initialized and the PCI bus scanned */
+int init_atu;
+
void iop3xx_pci_preinit(void)
{
+ if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) {
+ iop3xx_atu_disable();
+ iop3xx_atu_setup();
+ }
+
DBG("PCI: Intel 803xx PCI init code.\n");
DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD);
DBG("ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x\n",
@@ -245,3 +348,38 @@ void iop3xx_pci_preinit(void)
hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort");
}
+
+/* allow init_atu to be user overridden */
+static int __init iop3xx_init_atu_setup(char *str)
+{
+ init_atu = IOP3XX_INIT_ATU_DEFAULT;
+ if (str) {
+ while (*str != '\0') {
+ switch (*str) {
+ case 'y':
+ case 'Y':
+ init_atu = IOP3XX_INIT_ATU_ENABLE;
+ break;
+ case 'n':
+ case 'N':
+ init_atu = IOP3XX_INIT_ATU_DISABLE;
+ break;
+ case ',':
+ case '=':
+ break;
+ default:
+ printk(KERN_DEBUG "\"%s\" malformed at "
+ "character: \'%c\'",
+ __FUNCTION__,
+ *str);
+ *(str + 1) = '\0';
+ }
+ str++;
+ }
+ }
+
+ return 1;
+}
+
+__setup("iop3xx_init_atu", iop3xx_init_atu_setup);
+
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 16300adfb4d..100d57ad98e 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -32,22 +32,22 @@ static unsigned long next_jiffy_time;
unsigned long iop_gettimeoffset(void)
{
- unsigned long offset, temp1, temp2;
+ unsigned long offset, temp;
/* enable cp6, if necessary, to avoid taking the overhead of an
* undefined instruction trap
*/
asm volatile (
"mrc p15, 0, %0, c15, c1, 0\n\t"
- "ands %1, %0, #(1 << 6)\n\t"
+ "tst %0, #(1 << 6)\n\t"
"orreq %0, %0, #(1 << 6)\n\t"
"mcreq p15, 0, %0, c15, c1, 0\n\t"
-#ifdef CONFIG_XSCALE
+#ifdef CONFIG_CPU_XSCALE
"mrceq p15, 0, %0, c15, c1, 0\n\t"
"moveq %0, %0\n\t"
"subeq pc, pc, #4\n\t"
#endif
- : "=r"(temp1), "=r"(temp2) : : "cc");
+ : "=r"(temp) : : "cc");
offset = next_jiffy_time - read_tcr1();
@@ -75,7 +75,7 @@ iop_timer_interrupt(int irq, void *dev_id)
static struct irqaction iop_timer_irq = {
.name = "IOP Timer Tick",
.handler = iop_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};
void __init iop_init_time(unsigned long tick_rate)
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index f2dc363de66..cfc69f3842f 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -11,6 +11,7 @@ choice
config ARCH_OMAP1
bool "TI OMAP1"
+ select GENERIC_CLOCKEVENTS
config ARCH_OMAP2
bool "TI OMAP2"
@@ -19,6 +20,11 @@ endchoice
comment "OMAP Feature Selections"
+config OMAP_DEBUG_LEDS
+ bool
+ help
+ For debug card leds on TI reference boards.
+
config OMAP_RESET_CLOCKS
bool "Reset unused clocks during boot"
depends on ARCH_OMAP
@@ -57,6 +63,14 @@ config OMAP_MUX_WARNINGS
to change the pin multiplexing setup. When there are no warnings
printed, it's safe to deselect OMAP_MUX for your product.
+config OMAP_MCBSP
+ bool "McBSP support"
+ depends on ARCH_OMAP
+ default y
+ help
+ Say Y here if you want support for the OMAP Multichannel
+ Buffered Serial Port.
+
choice
prompt "System timer"
default OMAP_MPU_TIMER
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index 2896b454641..41a3c1cf3bd 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -3,7 +3,8 @@
#
# Common support
-obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o mcbsp.o usb.o fb.o
+obj-y := common.o sram.o sram-fn.o clock.o devices.o dma.o mux.o gpio.o \
+ usb.o fb.o
obj-m :=
obj-n :=
obj- :=
@@ -16,4 +17,4 @@ obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
-
+obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index f1179ad4be1..0a603242f36 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -33,6 +33,41 @@ static DEFINE_SPINLOCK(clockfw_lock);
static struct clk_functions *arch_clock;
+#ifdef CONFIG_PM_DEBUG
+
+static void print_parents(struct clk *clk)
+{
+ struct clk *p;
+ int printed = 0;
+
+ list_for_each_entry(p, &clocks, node) {
+ if (p->parent == clk && p->usecount) {
+ if (!clk->usecount && !printed) {
+ printk("MISMATCH: %s\n", clk->name);
+ printed = 1;
+ }
+ printk("\t%-15s\n", p->name);
+ }
+ }
+}
+
+void clk_print_usecounts(void)
+{
+ unsigned long flags;
+ struct clk *p;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ list_for_each_entry(p, &clocks, node) {
+ if (p->usecount)
+ printk("%-15s: %d\n", p->name, p->usecount);
+ print_parents(p);
+
+ }
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+
+#endif
+
/*-------------------------------------------------------------------------
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
@@ -249,6 +284,8 @@ void followparent_recalc(struct clk *clk)
return;
clk->rate = clk->parent->rate;
+ if (unlikely(clk->flags & RATE_PROPAGATES))
+ propagate_rate(clk);
}
/* Propagate rate to children */
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index 57b7b93674a..dd8708ad0a7 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -93,8 +93,12 @@ static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
* in the kernel. */
for (i = 0; i < omap_board_config_size; i++) {
if (omap_board_config[i].tag == tag) {
- kinfo = &omap_board_config[i];
- break;
+ if (skip == 0) {
+ kinfo = &omap_board_config[i];
+ break;
+ } else {
+ skip--;
+ }
}
}
if (kinfo == NULL)
@@ -156,3 +160,53 @@ static int __init omap_add_serial_console(void)
return add_preferred_console("ttyS", line, opt);
}
console_initcall(omap_add_serial_console);
+
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510. Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+#define TIMER_32K_SYNCHRONIZED 0xfffbc410
+#elif defined(CONFIG_ARCH_OMAP24XX)
+#define TIMER_32K_SYNCHRONIZED 0x48004010
+#endif
+
+#ifdef TIMER_32K_SYNCHRONIZED
+
+#include <linux/clocksource.h>
+
+static cycle_t omap_32k_read(void)
+{
+ return omap_readl(TIMER_32K_SYNCHRONIZED);
+}
+
+static struct clocksource clocksource_32k = {
+ .name = "32k_counter",
+ .rating = 250,
+ .read = omap_32k_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init omap_init_clocksource_32k(void)
+{
+ static char err[] __initdata = KERN_ERR
+ "%s: can't register clocksource!\n";
+
+ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ clocksource_32k.mult = clocksource_hz2mult(32768,
+ clocksource_32k.shift);
+
+ if (clocksource_register(&clocksource_32k))
+ printk(err, clocksource_32k.name);
+ }
+ return 0;
+}
+arch_initcall(omap_init_clocksource_32k);
+
+#endif /* TIMER_32K_SYNCHRONIZED */
diff --git a/arch/arm/plat-omap/debug-leds.c b/arch/arm/plat-omap/debug-leds.c
new file mode 100644
index 00000000000..9128a80d228
--- /dev/null
+++ b/arch/arm/plat-omap/debug-leds.c
@@ -0,0 +1,314 @@
+/*
+ * linux/arch/arm/plat-omap/debug-leds.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/leds.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/gpio.h>
+
+
+/* Many OMAP development platforms reuse the same "debug board"; these
+ * platforms include H2, H3, H4, and Perseus2. There are 16 LEDs on the
+ * debug board (all green), accessed through FPGA registers.
+ *
+ * The "surfer" expansion board and H2 sample board also have two-color
+ * green+red LEDs (in parallel), used here for timer and idle indicators
+ * in preference to the ones on the debug board, for a "Disco LED" effect.
+ *
+ * This driver exports either the original ARM LED API, the new generic
+ * one, or both.
+ */
+
+static spinlock_t lock;
+static struct h2p2_dbg_fpga __iomem *fpga;
+static u16 led_state, hw_led_state;
+
+
+#ifdef CONFIG_LEDS_OMAP_DEBUG
+#define new_led_api() 1
+#else
+#define new_led_api() 0
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/* original ARM debug LED API:
+ * - timer and idle leds (some boards use non-FPGA leds here);
+ * - up to 4 generic leds, easily accessed in-kernel (any context)
+ */
+
+#define GPIO_LED_RED 3
+#define GPIO_LED_GREEN OMAP_MPUIO(4)
+
+#define LED_STATE_ENABLED 0x01
+#define LED_STATE_CLAIMED 0x02
+#define LED_TIMER_ON 0x04
+
+#define GPIO_IDLE GPIO_LED_GREEN
+#define GPIO_TIMER GPIO_LED_RED
+
+static void h2p2_dbg_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
+ goto done;
+
+ switch (evt) {
+ case led_start:
+ if (fpga)
+ led_state |= LED_STATE_ENABLED;
+ break;
+
+ case led_stop:
+ case led_halted:
+ /* all leds off during suspend or shutdown */
+
+ if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
+ omap_set_gpio_dataout(GPIO_TIMER, 0);
+ omap_set_gpio_dataout(GPIO_IDLE, 0);
+ }
+
+ __raw_writew(~0, &fpga->leds);
+ led_state &= ~LED_STATE_ENABLED;
+ goto done;
+
+ case led_claim:
+ led_state |= LED_STATE_CLAIMED;
+ hw_led_state = 0;
+ break;
+
+ case led_release:
+ led_state &= ~LED_STATE_CLAIMED;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ led_state ^= LED_TIMER_ON;
+
+ if (machine_is_omap_perseus2() || machine_is_omap_h4())
+ hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
+ else {
+ omap_set_gpio_dataout(GPIO_TIMER,
+ led_state & LED_TIMER_ON);
+ goto done;
+ }
+
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ /* LED lit iff busy */
+ case led_idle_start:
+ if (machine_is_omap_perseus2() || machine_is_omap_h4())
+ hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
+ else {
+ omap_set_gpio_dataout(GPIO_IDLE, 1);
+ goto done;
+ }
+
+ break;
+
+ case led_idle_end:
+ if (machine_is_omap_perseus2() || machine_is_omap_h4())
+ hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
+ else {
+ omap_set_gpio_dataout(GPIO_IDLE, 0);
+ goto done;
+ }
+
+ break;
+#endif
+
+ case led_green_on:
+ hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
+ break;
+ case led_green_off:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
+ break;
+
+ case led_amber_on:
+ hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
+ break;
+ case led_amber_off:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
+ break;
+
+ case led_red_on:
+ hw_led_state |= H2P2_DBG_FPGA_LED_RED;
+ break;
+ case led_red_off:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
+ break;
+
+ case led_blue_on:
+ hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
+ break;
+ case led_blue_off:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
+ break;
+
+ default:
+ break;
+ }
+
+
+ /*
+ * Actually burn the LEDs
+ */
+ if (led_state & LED_STATE_ENABLED)
+ __raw_writew(~hw_led_state, &fpga->leds);
+
+done:
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* "new" LED API
+ * - with syfs access and generic triggering
+ * - not readily accessible to in-kernel drivers
+ */
+
+struct dbg_led {
+ struct led_classdev cdev;
+ u16 mask;
+};
+
+static struct dbg_led dbg_leds[] = {
+ /* REVISIT at least H2 uses different timer & cpu leds... */
+#ifndef CONFIG_LEDS_TIMER
+ { .mask = 1 << 0, .cdev.name = "d4:green",
+ .cdev.default_trigger = "heartbeat", },
+#endif
+#ifndef CONFIG_LEDS_CPU
+ { .mask = 1 << 1, .cdev.name = "d5:green", }, /* !idle */
+#endif
+ { .mask = 1 << 2, .cdev.name = "d6:green", },
+ { .mask = 1 << 3, .cdev.name = "d7:green", },
+
+ { .mask = 1 << 4, .cdev.name = "d8:green", },
+ { .mask = 1 << 5, .cdev.name = "d9:green", },
+ { .mask = 1 << 6, .cdev.name = "d10:green", },
+ { .mask = 1 << 7, .cdev.name = "d11:green", },
+
+ { .mask = 1 << 8, .cdev.name = "d12:green", },
+ { .mask = 1 << 9, .cdev.name = "d13:green", },
+ { .mask = 1 << 10, .cdev.name = "d14:green", },
+ { .mask = 1 << 11, .cdev.name = "d15:green", },
+
+#ifndef CONFIG_LEDS
+ { .mask = 1 << 12, .cdev.name = "d16:green", },
+ { .mask = 1 << 13, .cdev.name = "d17:green", },
+ { .mask = 1 << 14, .cdev.name = "d18:green", },
+ { .mask = 1 << 15, .cdev.name = "d19:green", },
+#endif
+};
+
+static void
+fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+ struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+ if (value == LED_OFF)
+ hw_led_state &= ~led->mask;
+ else
+ hw_led_state |= led->mask;
+ __raw_writew(~hw_led_state, &fpga->leds);
+ spin_unlock_irqrestore(&lock, flags);
+}
+
+static void __init newled_init(struct device *dev)
+{
+ unsigned i;
+ struct dbg_led *led;
+ int status;
+
+ for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
+ led->cdev.brightness_set = fpga_led_set;
+ status = led_classdev_register(dev, &led->cdev);
+ if (status < 0)
+ break;
+ }
+ return;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static int /* __init */ fpga_probe(struct platform_device *pdev)
+{
+ struct resource *iomem;
+
+ spin_lock_init(&lock);
+
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem)
+ return -ENODEV;
+
+ fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
+ __raw_writew(~0, &fpga->leds);
+
+#ifdef CONFIG_LEDS
+ leds_event = h2p2_dbg_leds_event;
+ leds_event(led_start);
+#endif
+
+ if (new_led_api()) {
+ newled_init(&pdev->dev);
+ }
+
+ return 0;
+}
+
+static int fpga_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+ __raw_writew(~0, &fpga->leds);
+ return 0;
+}
+
+static int fpga_resume_early(struct platform_device *pdev)
+{
+ __raw_writew(~hw_led_state, &fpga->leds);
+ return 0;
+}
+
+
+static struct platform_driver led_driver = {
+ .driver.name = "omap_dbg_led",
+ .probe = fpga_probe,
+ .suspend_late = fpga_suspend_late,
+ .resume_early = fpga_resume_early,
+};
+
+static int __init fpga_init(void)
+{
+ if (machine_is_omap_h4()
+ || machine_is_omap_h3()
+ || machine_is_omap_h2()
+ || machine_is_omap_perseus2()
+ )
+ return platform_driver_register(&led_driver);
+ return 0;
+}
+fs_initcall(fpga_init);
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index dbc3f44e07a..c5dab1d6417 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -25,7 +25,71 @@
#include <asm/arch/gpio.h>
#include <asm/arch/menelaus.h>
-#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
+#if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
+
+#include "../plat-omap/dsp/dsp_common.h"
+
+static struct dsp_platform_data dsp_pdata = {
+ .kdev_list = LIST_HEAD_INIT(dsp_pdata.kdev_list),
+};
+
+static struct resource omap_dsp_resources[] = {
+ {
+ .name = "dsp_mmu",
+ .start = -1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device omap_dsp_device = {
+ .name = "dsp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(omap_dsp_resources),
+ .resource = omap_dsp_resources,
+ .dev = {
+ .platform_data = &dsp_pdata,
+ },
+};
+
+static inline void omap_init_dsp(void)
+{
+ struct resource *res;
+ int irq;
+
+ if (cpu_is_omap15xx())
+ irq = INT_1510_DSP_MMU;
+ else if (cpu_is_omap16xx())
+ irq = INT_1610_DSP_MMU;
+ else if (cpu_is_omap24xx())
+ irq = INT_24XX_DSP_MMU;
+
+ res = platform_get_resource_byname(&omap_dsp_device,
+ IORESOURCE_IRQ, "dsp_mmu");
+ res->start = irq;
+
+ platform_device_register(&omap_dsp_device);
+}
+
+int dsp_kfunc_device_register(struct dsp_kfunc_device *kdev)
+{
+ static DEFINE_MUTEX(dsp_pdata_lock);
+
+ mutex_init(&kdev->lock);
+
+ mutex_lock(&dsp_pdata_lock);
+ list_add_tail(&kdev->entry, &dsp_pdata.kdev_list);
+ mutex_unlock(&dsp_pdata_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(dsp_kfunc_device_register);
+
+#else
+static inline void omap_init_dsp(void) { }
+#endif /* CONFIG_OMAP_DSP */
+
+/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_I2C_OMAP) || defined(CONFIG_I2C_OMAP_MODULE)
#define OMAP1_I2C_BASE 0xfffb3800
#define OMAP2_I2C_BASE1 0x48070000
@@ -48,8 +112,8 @@ static struct resource i2c_resources1[] = {
/* DMA not used; works around erratum writing to non-empty i2c fifo */
static struct platform_device omap_i2c_device1 = {
- .name = "i2c_omap",
- .id = 1,
+ .name = "i2c_omap",
+ .id = 1,
.num_resources = ARRAY_SIZE(i2c_resources1),
.resource = i2c_resources1,
};
@@ -376,7 +440,7 @@ static inline void omap_init_wdt(void) {}
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_OMAP_RNG) || defined(CONFIG_OMAP_RNG_MODULE)
+#if defined(CONFIG_HW_RANDOM_OMAP) || defined(CONFIG_HW_RANDOM_OMAP_MODULE)
#ifdef CONFIG_ARCH_OMAP24XX
#define OMAP_RNG_BASE 0x480A0000
@@ -429,17 +493,21 @@ static inline void omap_init_rng(void) {}
*/
static int __init omap_init_devices(void)
{
+/*
+ * Need to enable relevant once for 2430 SDP
+ */
+#ifndef CONFIG_MACH_OMAP_2430SDP
/* please keep these calls, and their implementations above,
* in alphabetical order so they're easier to sort through.
*/
+ omap_init_dsp();
omap_init_i2c();
omap_init_kp();
omap_init_mmc();
omap_init_uwire();
omap_init_wdt();
omap_init_rng();
-
+#endif
return 0;
}
arch_initcall(omap_init_devices);
-
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index f3f84fbf8b8..2d86b106ff3 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -925,10 +925,17 @@ static int omap2_dma_handle_ch(int ch)
{
u32 status = OMAP_DMA_CSR_REG(ch);
- if (!status)
+ if (!status) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING "Spurious DMA IRQ for lch %d\n", ch);
return 0;
- if (unlikely(dma_chan[ch].dev_id == -1))
+ }
+ if (unlikely(dma_chan[ch].dev_id == -1)) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING "IRQ %04x for non-allocated DMA"
+ "channel %d\n", status, ch);
return 0;
+ }
if (unlikely(status & OMAP_DMA_DROP_IRQ))
printk(KERN_INFO
"DMA synchronization event drop occurred with device "
@@ -959,11 +966,15 @@ static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id)
int i;
val = omap_readl(OMAP_DMA4_IRQSTATUS_L0);
-
- for (i = 1; i <= OMAP_LOGICAL_DMA_CH_COUNT; i++) {
- int active = val & (1 << (i - 1));
- if (active)
- omap2_dma_handle_ch(i - 1);
+ if (val == 0) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING "Spurious DMA IRQ\n");
+ return IRQ_HANDLED;
+ }
+ for (i = 0; i < OMAP_LOGICAL_DMA_CH_COUNT && val != 0; i++) {
+ if (val & 1)
+ omap2_dma_handle_ch(i);
+ val >>= 1;
}
return IRQ_HANDLED;
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 45f0439bffb..36073dfaa4d 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -372,7 +372,7 @@ void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
/* When the functional clock disappears, too quick writes seem to
* cause an abort. */
- __delay(15000);
+ __delay(150000);
}
#endif
@@ -506,6 +506,8 @@ int omap_dm_timer_init(void)
BUG_ON(dm_source_clocks[i] == NULL);
}
#endif
+ if (cpu_is_omap243x())
+ dm_timers[0].phys_base = 0x49018000;
for (i = 0; i < dm_timer_count; i++) {
#ifdef CONFIG_ARCH_OMAP2
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 56acb8720f7..4493bcff517 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -1,3 +1,26 @@
+/*
+ * File: arch/arm/plat-omap/fb.c
+ *
+ * Framebuffer device registration for TI OMAP platforms
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -16,6 +39,8 @@
#if defined(CONFIG_FB_OMAP) || defined(CONFIG_FB_OMAP_MODULE)
static struct omapfb_platform_data omapfb_config;
+static int config_invalid;
+static int configured_regions;
static u64 omap_fb_dma_mask = ~(u32)0;
@@ -30,39 +55,270 @@ static struct platform_device omap_fb_device = {
.num_resources = 0,
};
-/* called from map_io */
-void omapfb_reserve_mem(void)
+static inline int ranges_overlap(unsigned long start1, unsigned long size1,
+ unsigned long start2, unsigned long size2)
{
- const struct omap_fbmem_config *fbmem_conf;
+ return (start1 >= start2 && start1 < start2 + size2) ||
+ (start2 >= start1 && start2 < start1 + size1);
+}
- omapfb_config.fbmem.fb_sram_start = omap_fb_sram_start;
- omapfb_config.fbmem.fb_sram_size = omap_fb_sram_size;
+static inline int range_included(unsigned long start1, unsigned long size1,
+ unsigned long start2, unsigned long size2)
+{
+ return start1 >= start2 && start1 + size1 <= start2 + size2;
+}
- fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
- if (fbmem_conf != NULL) {
- /* indicate that the bootloader already initialized the
- * fb device, so we'll skip that part in the fb driver
- */
- omapfb_config.fbmem.fb_sdram_start = fbmem_conf->fb_sdram_start;
- omapfb_config.fbmem.fb_sdram_size = fbmem_conf->fb_sdram_size;
- if (fbmem_conf->fb_sdram_size) {
- pr_info("Reserving %u bytes SDRAM for frame buffer\n",
- fbmem_conf->fb_sdram_size);
- reserve_bootmem(fbmem_conf->fb_sdram_start,
- fbmem_conf->fb_sdram_size);
+/* Check if there is an overlapping region. */
+static int fbmem_region_reserved(unsigned long start, size_t size)
+{
+ struct omapfb_mem_region *rg;
+ int i;
+
+ rg = &omapfb_config.mem_desc.region[0];
+ for (i = 0; i < OMAPFB_PLANE_NUM; i++, rg++) {
+ if (!rg->paddr)
+ /* Empty slot. */
+ continue;
+ if (ranges_overlap(start, size, rg->paddr, rg->size))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Get the region_idx`th region from board config/ATAG and convert it to
+ * our internal format.
+ */
+static int get_fbmem_region(int region_idx, struct omapfb_mem_region *rg)
+{
+ const struct omap_fbmem_config *conf;
+ u32 paddr;
+
+ conf = omap_get_nr_config(OMAP_TAG_FBMEM,
+ struct omap_fbmem_config, region_idx);
+ if (conf == NULL)
+ return -ENOENT;
+
+ paddr = conf->start;
+ /*
+ * Low bits encode the page allocation mode, if high bits
+ * are zero. Otherwise we need a page aligned fixed
+ * address.
+ */
+ memset(rg, 0, sizeof(*rg));
+ rg->type = paddr & ~PAGE_MASK;
+ rg->paddr = paddr & PAGE_MASK;
+ rg->size = PAGE_ALIGN(conf->size);
+ return 0;
+}
+
+static int set_fbmem_region_type(struct omapfb_mem_region *rg, int mem_type,
+ unsigned long mem_start,
+ unsigned long mem_size)
+{
+ /*
+ * Check if the configuration specifies the type explicitly.
+ * type = 0 && paddr = 0, a default don't care case maps to
+ * the SDRAM type.
+ */
+ if (rg->type || (!rg->type && !rg->paddr))
+ return 0;
+ if (ranges_overlap(rg->paddr, rg->size, mem_start, mem_size)) {
+ rg->type = mem_type;
+ return 0;
+ }
+ /* Can't determine it. */
+ return -1;
+}
+
+static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg,
+ unsigned long start_avail, unsigned size_avail)
+{
+ unsigned long paddr = rg->paddr;
+ size_t size = rg->size;
+
+ if (rg->type > OMAPFB_MEMTYPE_MAX) {
+ printk(KERN_ERR
+ "Invalid start address for FB region %d\n", region_idx);
+ return -EINVAL;
+ }
+
+ if (!rg->size) {
+ printk(KERN_ERR "Zero size for FB region %d\n", region_idx);
+ return -EINVAL;
+ }
+
+ if (!paddr)
+ /* Allocate this dynamically, leave paddr 0 for now. */
+ return 0;
+
+ /*
+ * Fixed region for the given RAM range. Check if it's already
+ * reserved by the FB code or someone else.
+ */
+ if (fbmem_region_reserved(paddr, size) ||
+ !range_included(paddr, size, start_avail, size_avail)) {
+ printk(KERN_ERR "Trying to use reserved memory "
+ "for FB region %d\n", region_idx);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Called from map_io. We need to call to this early enough so that we
+ * can reserve the fixed SDRAM regions before VM could get hold of them.
+ */
+void omapfb_reserve_sdram(void)
+{
+ struct bootmem_data *bdata;
+ unsigned long sdram_start, sdram_size;
+ unsigned long reserved;
+ int i;
+
+ if (config_invalid)
+ return;
+
+ bdata = NODE_DATA(0)->bdata;
+ sdram_start = bdata->node_boot_start;
+ sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
+ reserved = 0;
+ for (i = 0; ; i++) {
+ struct omapfb_mem_region rg;
+
+ if (get_fbmem_region(i, &rg) < 0)
+ break;
+ if (i == OMAPFB_PLANE_NUM) {
+ printk(KERN_ERR
+ "Extraneous FB mem configuration entries\n");
+ config_invalid = 1;
+ return;
}
+ /* Check if it's our memory type. */
+ if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SDRAM,
+ sdram_start, sdram_size) < 0 ||
+ (rg.type != OMAPFB_MEMTYPE_SDRAM))
+ continue;
+ BUG_ON(omapfb_config.mem_desc.region[i].size);
+ if (check_fbmem_region(i, &rg, sdram_start, sdram_size) < 0) {
+ config_invalid = 1;
+ return;
+ }
+ if (rg.paddr)
+ reserve_bootmem(rg.paddr, rg.size);
+ reserved += rg.size;
+ omapfb_config.mem_desc.region[i] = rg;
+ configured_regions++;
}
+ omapfb_config.mem_desc.region_cnt = i;
+ if (reserved)
+ pr_info("Reserving %lu bytes SDRAM for frame buffer\n",
+ reserved);
+}
+
+/*
+ * Called at sram init time, before anything is pushed to the SRAM stack.
+ * Because of the stack scheme, we will allocate everything from the
+ * start of the lowest address region to the end of SRAM. This will also
+ * include padding for page alignment and possible holes between regions.
+ *
+ * As opposed to the SDRAM case, we'll also do any dynamic allocations at
+ * this point, since the driver built as a module would have problem with
+ * freeing / reallocating the regions.
+ */
+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+ unsigned long sram_vstart,
+ unsigned long sram_size,
+ unsigned long pstart_avail,
+ unsigned long size_avail)
+{
+ struct omapfb_mem_region rg;
+ unsigned long pend_avail;
+ unsigned long reserved;
+ int i;
+
+ if (config_invalid)
+ return 0;
+
+ reserved = 0;
+ pend_avail = pstart_avail + size_avail;
+ for (i = 0; ; i++) {
+ if (get_fbmem_region(i, &rg) < 0)
+ break;
+ if (i == OMAPFB_PLANE_NUM) {
+ printk(KERN_ERR
+ "Extraneous FB mem configuration entries\n");
+ config_invalid = 1;
+ return 0;
+ }
+
+ /* Check if it's our memory type. */
+ if (set_fbmem_region_type(&rg, OMAPFB_MEMTYPE_SRAM,
+ sram_pstart, sram_size) < 0 ||
+ (rg.type != OMAPFB_MEMTYPE_SRAM))
+ continue;
+ BUG_ON(omapfb_config.mem_desc.region[i].size);
+
+ if (check_fbmem_region(i, &rg, pstart_avail, size_avail) < 0) {
+ config_invalid = 1;
+ return 0;
+ }
+
+ if (!rg.paddr) {
+ /* Dynamic allocation */
+ if ((size_avail & PAGE_MASK) < rg.size) {
+ printk("Not enough SRAM for FB region %d\n",
+ i);
+ config_invalid = 1;
+ return 0;
+ }
+ size_avail = (size_avail - rg.size) & PAGE_MASK;
+ rg.paddr = pstart_avail + size_avail;
+ }
+ /* Reserve everything above the start of the region. */
+ if (pend_avail - rg.paddr > reserved)
+ reserved = pend_avail - rg.paddr;
+ size_avail = pend_avail - reserved - pstart_avail;
+
+ /*
+ * We have a kernel mapping for this already, so the
+ * driver won't have to make one.
+ */
+ rg.vaddr = (void *)(sram_vstart + rg.paddr - sram_pstart);
+ omapfb_config.mem_desc.region[i] = rg;
+ configured_regions++;
+ }
+ omapfb_config.mem_desc.region_cnt = i;
+ if (reserved)
+ pr_info("Reserving %lu bytes SRAM for frame buffer\n",
+ reserved);
+ return reserved;
+}
+
+void omapfb_set_ctrl_platform_data(void *data)
+{
+ omapfb_config.ctrl_platform_data = data;
}
static inline int omap_init_fb(void)
{
const struct omap_lcd_config *conf;
+ if (config_invalid)
+ return 0;
+ if (configured_regions != omapfb_config.mem_desc.region_cnt) {
+ printk(KERN_ERR "Invalid FB mem configuration entries\n");
+ return 0;
+ }
conf = omap_get_config(OMAP_TAG_LCD, struct omap_lcd_config);
- if (conf == NULL)
+ if (conf == NULL) {
+ if (configured_regions)
+ /* FB mem config, but no LCD config? */
+ printk(KERN_ERR "Missing LCD configuration\n");
return 0;
-
+ }
omapfb_config.lcd = *conf;
return platform_device_register(&omap_fb_device);
@@ -72,7 +328,16 @@ arch_initcall(omap_init_fb);
#else
-void omapfb_reserve_mem(void) {}
+void omapfb_reserve_sdram(void) {}
+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+ unsigned long sram_vstart,
+ unsigned long sram_size,
+ unsigned long start_avail,
+ unsigned long size_avail)
+{
+ return 0;
+}
+
#endif
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index b8c01de208b..337455dfe64 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -13,9 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -86,10 +84,17 @@
/*
* omap24xx specific GPIO registers
*/
-#define OMAP24XX_GPIO1_BASE (void __iomem *)0x48018000
-#define OMAP24XX_GPIO2_BASE (void __iomem *)0x4801a000
-#define OMAP24XX_GPIO3_BASE (void __iomem *)0x4801c000
-#define OMAP24XX_GPIO4_BASE (void __iomem *)0x4801e000
+#define OMAP242X_GPIO1_BASE (void __iomem *)0x48018000
+#define OMAP242X_GPIO2_BASE (void __iomem *)0x4801a000
+#define OMAP242X_GPIO3_BASE (void __iomem *)0x4801c000
+#define OMAP242X_GPIO4_BASE (void __iomem *)0x4801e000
+
+#define OMAP243X_GPIO1_BASE (void __iomem *)0x4900C000
+#define OMAP243X_GPIO2_BASE (void __iomem *)0x4900E000
+#define OMAP243X_GPIO3_BASE (void __iomem *)0x49010000
+#define OMAP243X_GPIO4_BASE (void __iomem *)0x49012000
+#define OMAP243X_GPIO5_BASE (void __iomem *)0x480B6000
+
#define OMAP24XX_GPIO_REVISION 0x0000
#define OMAP24XX_GPIO_SYSCONFIG 0x0010
#define OMAP24XX_GPIO_SYSSTATUS 0x0014
@@ -118,8 +123,18 @@ struct gpio_bank {
u16 virtual_irq_start;
int method;
u32 reserved_map;
+#if defined (CONFIG_ARCH_OMAP16XX) || defined (CONFIG_ARCH_OMAP24XX)
u32 suspend_wakeup;
u32 saved_wakeup;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
+ u32 non_wakeup_gpios;
+ u32 enabled_non_wakeup_gpios;
+
+ u32 saved_datain;
+ u32 saved_fallingdetect;
+ u32 saved_risingdetect;
+#endif
spinlock_t lock;
};
@@ -159,12 +174,22 @@ static struct gpio_bank gpio_bank_730[7] = {
#endif
#ifdef CONFIG_ARCH_OMAP24XX
-static struct gpio_bank gpio_bank_24xx[4] = {
- { OMAP24XX_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
- { OMAP24XX_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
- { OMAP24XX_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
- { OMAP24XX_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
+
+static struct gpio_bank gpio_bank_242x[4] = {
+ { OMAP242X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
+ { OMAP242X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
+ { OMAP242X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
+ { OMAP242X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
+};
+
+static struct gpio_bank gpio_bank_243x[5] = {
+ { OMAP243X_GPIO1_BASE, INT_24XX_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_24XX },
+ { OMAP243X_GPIO2_BASE, INT_24XX_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_24XX },
+ { OMAP243X_GPIO3_BASE, INT_24XX_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_24XX },
+ { OMAP243X_GPIO4_BASE, INT_24XX_GPIO_BANK4, IH_GPIO_BASE + 96, METHOD_GPIO_24XX },
+ { OMAP243X_GPIO5_BASE, INT_24XX_GPIO_BANK5, IH_GPIO_BASE + 128, METHOD_GPIO_24XX },
};
+
#endif
static struct gpio_bank *gpio_bank;
@@ -258,21 +283,34 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
u32 l;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
reg += OMAP_MPUIO_IO_CNTL;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_DIR_CONTROL;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
reg += OMAP1610_GPIO_DIRECTION;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_DIR_CONTROL;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
reg += OMAP24XX_GPIO_OE;
break;
+#endif
+ default:
+ WARN_ON(1);
+ return;
}
l = __raw_readl(reg);
if (is_input)
@@ -300,6 +338,7 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
u32 l = 0;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
reg += OMAP_MPUIO_OUTPUT;
l = __raw_readl(reg);
@@ -308,6 +347,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
else
l &= ~(1 << gpio);
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_DATA_OUTPUT;
l = __raw_readl(reg);
@@ -316,6 +357,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
else
l &= ~(1 << gpio);
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
if (enable)
reg += OMAP1610_GPIO_SET_DATAOUT;
@@ -323,6 +366,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
reg += OMAP1610_GPIO_CLEAR_DATAOUT;
l = 1 << gpio;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_DATA_OUTPUT;
l = __raw_readl(reg);
@@ -331,6 +376,8 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
else
l &= ~(1 << gpio);
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
if (enable)
reg += OMAP24XX_GPIO_SETDATAOUT;
@@ -338,8 +385,9 @@ static void _set_gpio_dataout(struct gpio_bank *bank, int gpio, int enable)
reg += OMAP24XX_GPIO_CLEARDATAOUT;
l = 1 << gpio;
break;
+#endif
default:
- BUG();
+ WARN_ON(1);
return;
}
__raw_writel(l, reg);
@@ -363,28 +411,37 @@ int omap_get_gpio_datain(int gpio)
void __iomem *reg;
if (check_gpio(gpio) < 0)
- return -1;
+ return -EINVAL;
bank = get_gpio_bank(gpio);
reg = bank->base;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
reg += OMAP_MPUIO_INPUT_LATCH;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_DATA_INPUT;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
reg += OMAP1610_GPIO_DATAIN;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_DATA_INPUT;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
reg += OMAP24XX_GPIO_DATAIN;
break;
+#endif
default:
- BUG();
- return -1;
+ return -EINVAL;
}
return (__raw_readl(reg)
& (1 << get_gpio_index(gpio))) != 0;
@@ -398,8 +455,10 @@ do { \
__raw_writel(l, base + reg); \
} while(0)
-static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int trigger)
+#ifdef CONFIG_ARCH_OMAP24XX
+static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
{
+ void __iomem *base = bank->base;
u32 gpio_bit = 1 << gpio;
MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit,
@@ -410,9 +469,21 @@ static inline void set_24xx_gpio_triggering(void __iomem *base, int gpio, int tr
trigger & __IRQT_RISEDGE);
MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit,
trigger & __IRQT_FALEDGE);
+ if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
+ if (trigger != 0)
+ __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_SETWKUENA);
+ else
+ __raw_writel(1 << gpio, bank->base + OMAP24XX_GPIO_CLEARWKUENA);
+ } else {
+ if (trigger != 0)
+ bank->enabled_non_wakeup_gpios |= gpio_bit;
+ else
+ bank->enabled_non_wakeup_gpios &= ~gpio_bit;
+ }
/* FIXME: Possibly do 'set_irq_handler(j, handle_level_irq)' if only level
* triggering requested. */
}
+#endif
static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
{
@@ -420,6 +491,7 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
u32 l = 0;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_INT_EDGE;
l = __raw_readl(reg);
@@ -430,6 +502,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
else
goto bad;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_CONTROL;
l = __raw_readl(reg);
@@ -440,22 +514,28 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
else
goto bad;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
if (gpio & 0x08)
reg += OMAP1610_GPIO_EDGE_CTRL2;
else
reg += OMAP1610_GPIO_EDGE_CTRL1;
gpio &= 0x07;
- /* We allow only edge triggering, i.e. two lowest bits */
- if (trigger & (__IRQT_LOWLVL | __IRQT_HIGHLVL))
- BUG();
l = __raw_readl(reg);
l &= ~(3 << (gpio << 1));
if (trigger & __IRQT_RISEDGE)
l |= 2 << (gpio << 1);
if (trigger & __IRQT_FALEDGE)
l |= 1 << (gpio << 1);
+ if (trigger)
+ /* Enable wake-up during idle for dynamic tick */
+ __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_SET_WAKEUPENA);
+ else
+ __raw_writel(1 << gpio, bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA);
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_CONTROL;
l = __raw_readl(reg);
@@ -466,11 +546,13 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
else
goto bad;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
- set_24xx_gpio_triggering(reg, gpio, trigger);
+ set_24xx_gpio_triggering(bank, gpio, trigger);
break;
+#endif
default:
- BUG();
goto bad;
}
__raw_writel(l, reg);
@@ -485,7 +567,7 @@ static int gpio_irq_type(unsigned irq, unsigned type)
unsigned gpio;
int retval;
- if (irq > IH_MPUIO_BASE)
+ if (!cpu_is_omap24xx() && irq > IH_MPUIO_BASE)
gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
else
gpio = irq - IH_GPIO_BASE;
@@ -493,14 +575,21 @@ static int gpio_irq_type(unsigned irq, unsigned type)
if (check_gpio(gpio) < 0)
return -EINVAL;
- if (type & IRQT_PROBE)
+ if (type & ~IRQ_TYPE_SENSE_MASK)
return -EINVAL;
- if (!cpu_is_omap24xx() && (type & (__IRQT_LOWLVL|__IRQT_HIGHLVL)))
+
+ /* OMAP1 allows only only edge triggering */
+ if (!cpu_is_omap24xx()
+ && (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;
- bank = get_gpio_bank(gpio);
+ bank = get_irq_chip_data(irq);
spin_lock(&bank->lock);
retval = _set_gpio_triggering(bank, get_gpio_index(gpio), type);
+ if (retval == 0) {
+ irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
+ irq_desc[irq].status |= type;
+ }
spin_unlock(&bank->lock);
return retval;
}
@@ -510,24 +599,34 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
void __iomem *reg = bank->base;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
/* MPUIO irqstatus is reset by reading the status register,
* so do nothing here */
return;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_STATUS;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
reg += OMAP1610_GPIO_IRQSTATUS1;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_STATUS;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
reg += OMAP24XX_GPIO_IRQSTATUS1;
break;
+#endif
default:
- BUG();
+ WARN_ON(1);
return;
}
__raw_writel(gpio_mask, reg);
@@ -550,31 +649,41 @@ static u32 _get_gpio_irqbank_mask(struct gpio_bank *bank)
u32 mask;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_MASKIT;
mask = 0xffff;
inv = 1;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_MASK;
mask = 0xffff;
inv = 1;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
reg += OMAP1610_GPIO_IRQENABLE1;
mask = 0xffff;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_MASK;
mask = 0xffffffff;
inv = 1;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
reg += OMAP24XX_GPIO_IRQENABLE1;
mask = 0xffffffff;
break;
+#endif
default:
- BUG();
+ WARN_ON(1);
return 0;
}
@@ -591,6 +700,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
u32 l;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP1
case METHOD_MPUIO:
reg += OMAP_MPUIO_GPIO_MASKIT;
l = __raw_readl(reg);
@@ -599,6 +709,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
else
l |= gpio_mask;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP15XX
case METHOD_GPIO_1510:
reg += OMAP1510_GPIO_INT_MASK;
l = __raw_readl(reg);
@@ -607,6 +719,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
else
l |= gpio_mask;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
if (enable)
reg += OMAP1610_GPIO_SET_IRQENABLE1;
@@ -614,6 +728,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
reg += OMAP1610_GPIO_CLEAR_IRQENABLE1;
l = gpio_mask;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP730
case METHOD_GPIO_730:
reg += OMAP730_GPIO_INT_MASK;
l = __raw_readl(reg);
@@ -622,6 +738,8 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
else
l |= gpio_mask;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
if (enable)
reg += OMAP24XX_GPIO_SETIRQENABLE1;
@@ -629,8 +747,9 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask, int enab
reg += OMAP24XX_GPIO_CLEARIRQENABLE1;
l = gpio_mask;
break;
+#endif
default:
- BUG();
+ WARN_ON(1);
return;
}
__raw_writel(l, reg);
@@ -652,15 +771,39 @@ static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int ena
static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
{
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
+ case METHOD_MPUIO:
case METHOD_GPIO_1610:
+ spin_lock(&bank->lock);
+ if (enable) {
+ bank->suspend_wakeup |= (1 << gpio);
+ enable_irq_wake(bank->irq);
+ } else {
+ disable_irq_wake(bank->irq);
+ bank->suspend_wakeup &= ~(1 << gpio);
+ }
+ spin_unlock(&bank->lock);
+ return 0;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
+ if (bank->non_wakeup_gpios & (1 << gpio)) {
+ printk(KERN_ERR "Unable to modify wakeup on "
+ "non-wakeup GPIO%d\n",
+ (bank - gpio_bank) * 32 + gpio);
+ return -EINVAL;
+ }
spin_lock(&bank->lock);
- if (enable)
+ if (enable) {
bank->suspend_wakeup |= (1 << gpio);
- else
+ enable_irq_wake(bank->irq);
+ } else {
+ disable_irq_wake(bank->irq);
bank->suspend_wakeup &= ~(1 << gpio);
+ }
spin_unlock(&bank->lock);
return 0;
+#endif
default:
printk(KERN_ERR "Can't enable GPIO wakeup for method %i\n",
bank->method);
@@ -685,7 +828,7 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable)
if (check_gpio(gpio) < 0)
return -ENODEV;
- bank = get_gpio_bank(gpio);
+ bank = get_irq_chip_data(irq);
retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
return retval;
@@ -722,20 +865,6 @@ int omap_request_gpio(int gpio)
__raw_writel(__raw_readl(reg) | (1 << get_gpio_index(gpio)), reg);
}
#endif
-#ifdef CONFIG_ARCH_OMAP16XX
- if (bank->method == METHOD_GPIO_1610) {
- /* Enable wake-up during idle for dynamic tick */
- void __iomem *reg = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
- __raw_writel(1 << get_gpio_index(gpio), reg);
- }
-#endif
-#ifdef CONFIG_ARCH_OMAP24XX
- if (bank->method == METHOD_GPIO_24XX) {
- /* Enable wake-up during idle for dynamic tick */
- void __iomem *reg = bank->base + OMAP24XX_GPIO_SETWKUENA;
- __raw_writel(1 << get_gpio_index(gpio), reg);
- }
-#endif
spin_unlock(&bank->lock);
return 0;
@@ -795,8 +924,10 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
desc->chip->ack(irq);
bank = get_irq_data(irq);
+#ifdef CONFIG_ARCH_OMAP1
if (bank->method == METHOD_MPUIO)
isr_reg = bank->base + OMAP_MPUIO_GPIO_INT;
+#endif
#ifdef CONFIG_ARCH_OMAP15XX
if (bank->method == METHOD_GPIO_1510)
isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
@@ -912,7 +1043,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
static void gpio_irq_shutdown(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_gpio_bank(gpio);
+ struct gpio_bank *bank = get_irq_chip_data(irq);
_reset_gpio(bank, gpio);
}
@@ -920,7 +1051,7 @@ static void gpio_irq_shutdown(unsigned int irq)
static void gpio_ack_irq(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_gpio_bank(gpio);
+ struct gpio_bank *bank = get_irq_chip_data(irq);
_clear_gpio_irqstatus(bank, gpio);
}
@@ -928,7 +1059,7 @@ static void gpio_ack_irq(unsigned int irq)
static void gpio_mask_irq(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
- struct gpio_bank *bank = get_gpio_bank(gpio);
+ struct gpio_bank *bank = get_irq_chip_data(irq);
_set_gpio_irqenable(bank, gpio, 0);
}
@@ -937,11 +1068,27 @@ static void gpio_unmask_irq(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
unsigned int gpio_idx = get_gpio_index(gpio);
- struct gpio_bank *bank = get_gpio_bank(gpio);
+ struct gpio_bank *bank = get_irq_chip_data(irq);
_set_gpio_irqenable(bank, gpio_idx, 1);
}
+static struct irq_chip gpio_irq_chip = {
+ .name = "GPIO",
+ .shutdown = gpio_irq_shutdown,
+ .ack = gpio_ack_irq,
+ .mask = gpio_mask_irq,
+ .unmask = gpio_unmask_irq,
+ .set_type = gpio_irq_type,
+ .set_wake = gpio_wake_enable,
+};
+
+/*---------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP1
+
+/* MPUIO uses the always-on 32k clock */
+
static void mpuio_ack_irq(unsigned int irq)
{
/* The ISR is reset automatically, so do nothing here. */
@@ -950,7 +1097,7 @@ static void mpuio_ack_irq(unsigned int irq)
static void mpuio_mask_irq(unsigned int irq)
{
unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
- struct gpio_bank *bank = get_gpio_bank(gpio);
+ struct gpio_bank *bank = get_irq_chip_data(irq);
_set_gpio_irqenable(bank, gpio, 0);
}
@@ -958,33 +1105,108 @@ static void mpuio_mask_irq(unsigned int irq)
static void mpuio_unmask_irq(unsigned int irq)
{
unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
- struct gpio_bank *bank = get_gpio_bank(gpio);
+ struct gpio_bank *bank = get_irq_chip_data(irq);
_set_gpio_irqenable(bank, gpio, 1);
}
-static struct irq_chip gpio_irq_chip = {
- .name = "GPIO",
- .shutdown = gpio_irq_shutdown,
- .ack = gpio_ack_irq,
- .mask = gpio_mask_irq,
- .unmask = gpio_unmask_irq,
+static struct irq_chip mpuio_irq_chip = {
+ .name = "MPUIO",
+ .ack = mpuio_ack_irq,
+ .mask = mpuio_mask_irq,
+ .unmask = mpuio_unmask_irq,
.set_type = gpio_irq_type,
+#ifdef CONFIG_ARCH_OMAP16XX
+ /* REVISIT: assuming only 16xx supports MPUIO wake events */
.set_wake = gpio_wake_enable,
+#endif
};
-static struct irq_chip mpuio_irq_chip = {
- .name = "MPUIO",
- .ack = mpuio_ack_irq,
- .mask = mpuio_mask_irq,
- .unmask = mpuio_unmask_irq,
- .set_type = gpio_irq_type,
+
+#define bank_is_mpuio(bank) ((bank)->method == METHOD_MPUIO)
+
+
+#ifdef CONFIG_ARCH_OMAP16XX
+
+#include <linux/platform_device.h>
+
+static int omap_mpuio_suspend_late(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct gpio_bank *bank = platform_get_drvdata(pdev);
+ void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
+
+ spin_lock(&bank->lock);
+ bank->saved_wakeup = __raw_readl(mask_reg);
+ __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);
+ spin_unlock(&bank->lock);
+
+ return 0;
+}
+
+static int omap_mpuio_resume_early(struct platform_device *pdev)
+{
+ struct gpio_bank *bank = platform_get_drvdata(pdev);
+ void __iomem *mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
+
+ spin_lock(&bank->lock);
+ __raw_writel(bank->saved_wakeup, mask_reg);
+ spin_unlock(&bank->lock);
+
+ return 0;
+}
+
+/* use platform_driver for this, now that there's no longer any
+ * point to sys_device (other than not disturbing old code).
+ */
+static struct platform_driver omap_mpuio_driver = {
+ .suspend_late = omap_mpuio_suspend_late,
+ .resume_early = omap_mpuio_resume_early,
+ .driver = {
+ .name = "mpuio",
+ },
+};
+
+static struct platform_device omap_mpuio_device = {
+ .name = "mpuio",
+ .id = -1,
+ .dev = {
+ .driver = &omap_mpuio_driver.driver,
+ }
+ /* could list the /proc/iomem resources */
};
+static inline void mpuio_init(void)
+{
+ platform_set_drvdata(&omap_mpuio_device, &gpio_bank_1610[0]);
+
+ if (platform_driver_register(&omap_mpuio_driver) == 0)
+ (void) platform_device_register(&omap_mpuio_device);
+}
+
+#else
+static inline void mpuio_init(void) {}
+#endif /* 16xx */
+
+#else
+
+extern struct irq_chip mpuio_irq_chip;
+
+#define bank_is_mpuio(bank) 0
+static inline void mpuio_init(void) {}
+
+#endif
+
+/*---------------------------------------------------------------------*/
+
static int initialized;
static struct clk * gpio_ick;
static struct clk * gpio_fck;
+#ifdef CONFIG_ARCH_OMAP2430
+static struct clk * gpio5_ick;
+static struct clk * gpio5_fck;
+#endif
+
static int __init _omap_gpio_init(void)
{
int i;
@@ -1010,7 +1232,25 @@ static int __init _omap_gpio_init(void)
printk("Could not get gpios_fck\n");
else
clk_enable(gpio_fck);
- }
+
+ /*
+ * On 2430 GPIO 5 uses CORE L4 ICLK
+ */
+#ifdef CONFIG_ARCH_OMAP2430
+ if (cpu_is_omap2430()) {
+ gpio5_ick = clk_get(NULL, "gpio5_ick");
+ if (IS_ERR(gpio5_ick))
+ printk("Could not get gpio5_ick\n");
+ else
+ clk_enable(gpio5_ick);
+ gpio5_fck = clk_get(NULL, "gpio5_fck");
+ if (IS_ERR(gpio5_fck))
+ printk("Could not get gpio5_fck\n");
+ else
+ clk_enable(gpio5_fck);
+ }
+#endif
+}
#ifdef CONFIG_ARCH_OMAP15XX
if (cpu_is_omap15xx()) {
@@ -1037,14 +1277,24 @@ static int __init _omap_gpio_init(void)
gpio_bank = gpio_bank_730;
}
#endif
+
#ifdef CONFIG_ARCH_OMAP24XX
- if (cpu_is_omap24xx()) {
+ if (cpu_is_omap242x()) {
int rev;
gpio_bank_count = 4;
- gpio_bank = gpio_bank_24xx;
+ gpio_bank = gpio_bank_242x;
+ rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
+ printk(KERN_INFO "OMAP242x GPIO hardware version %d.%d\n",
+ (rev >> 4) & 0x0f, rev & 0x0f);
+ }
+ if (cpu_is_omap243x()) {
+ int rev;
+
+ gpio_bank_count = 5;
+ gpio_bank = gpio_bank_243x;
rev = omap_readl(gpio_bank[0].base + OMAP24XX_GPIO_REVISION);
- printk(KERN_INFO "OMAP24xx GPIO hardware version %d.%d\n",
+ printk(KERN_INFO "OMAP243x GPIO hardware version %d.%d\n",
(rev >> 4) & 0x0f, rev & 0x0f);
}
#endif
@@ -1055,9 +1305,8 @@ static int __init _omap_gpio_init(void)
bank->reserved_map = 0;
bank->base = IO_ADDRESS(bank->base);
spin_lock_init(&bank->lock);
- if (bank->method == METHOD_MPUIO) {
+ if (bank_is_mpuio(bank))
omap_writew(0xFFFF, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_MASKIT);
- }
#ifdef CONFIG_ARCH_OMAP15XX
if (bank->method == METHOD_GPIO_1510) {
__raw_writew(0xffff, bank->base + OMAP1510_GPIO_INT_MASK);
@@ -1081,15 +1330,25 @@ static int __init _omap_gpio_init(void)
#endif
#ifdef CONFIG_ARCH_OMAP24XX
if (bank->method == METHOD_GPIO_24XX) {
+ static const u32 non_wakeup_gpios[] = {
+ 0xe203ffc0, 0x08700040
+ };
+
__raw_writel(0x00000000, bank->base + OMAP24XX_GPIO_IRQENABLE1);
__raw_writel(0xffffffff, bank->base + OMAP24XX_GPIO_IRQSTATUS1);
+ __raw_writew(0x0015, bank->base + OMAP24XX_GPIO_SYSCONFIG);
+ /* Initialize interface clock ungated, module enabled */
+ __raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
+ if (i < ARRAY_SIZE(non_wakeup_gpios))
+ bank->non_wakeup_gpios = non_wakeup_gpios[i];
gpio_count = 32;
}
#endif
for (j = bank->virtual_irq_start;
j < bank->virtual_irq_start + gpio_count; j++) {
- if (bank->method == METHOD_MPUIO)
+ set_irq_chip_data(j, bank);
+ if (bank_is_mpuio(bank))
set_irq_chip(j, &mpuio_irq_chip);
else
set_irq_chip(j, &gpio_irq_chip);
@@ -1105,6 +1364,12 @@ static int __init _omap_gpio_init(void)
if (cpu_is_omap16xx())
omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
+#ifdef CONFIG_ARCH_OMAP24XX
+ /* Enable autoidle for the OCP interface */
+ if (cpu_is_omap24xx())
+ omap_writel(1 << 0, 0x48019010);
+#endif
+
return 0;
}
@@ -1123,16 +1388,20 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
void __iomem *wake_set;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
wake_status = bank->base + OMAP1610_GPIO_WAKEUPENABLE;
wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
wake_status = bank->base + OMAP24XX_GPIO_SETWKUENA;
wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
break;
+#endif
default:
continue;
}
@@ -1160,14 +1429,18 @@ static int omap_gpio_resume(struct sys_device *dev)
void __iomem *wake_set;
switch (bank->method) {
+#ifdef CONFIG_ARCH_OMAP16XX
case METHOD_GPIO_1610:
wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
break;
+#endif
+#ifdef CONFIG_ARCH_OMAP24XX
case METHOD_GPIO_24XX:
wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
break;
+#endif
default:
continue;
}
@@ -1191,13 +1464,87 @@ static struct sys_device omap_gpio_device = {
.id = 0,
.cls = &omap_gpio_sysclass,
};
+
+#endif
+
+#ifdef CONFIG_ARCH_OMAP24XX
+
+static int workaround_enabled;
+
+void omap2_gpio_prepare_for_retention(void)
+{
+ int i, c = 0;
+
+ /* Remove triggering for all non-wakeup GPIOs. Otherwise spurious
+ * IRQs will be generated. See OMAP2420 Errata item 1.101. */
+ for (i = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ u32 l1, l2;
+
+ if (!(bank->enabled_non_wakeup_gpios))
+ continue;
+ bank->saved_datain = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+ l1 = __raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ l2 = __raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
+ bank->saved_fallingdetect = l1;
+ bank->saved_risingdetect = l2;
+ l1 &= ~bank->enabled_non_wakeup_gpios;
+ l2 &= ~bank->enabled_non_wakeup_gpios;
+ __raw_writel(l1, bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ __raw_writel(l2, bank->base + OMAP24XX_GPIO_RISINGDETECT);
+ c++;
+ }
+ if (!c) {
+ workaround_enabled = 0;
+ return;
+ }
+ workaround_enabled = 1;
+}
+
+void omap2_gpio_resume_after_retention(void)
+{
+ int i;
+
+ if (!workaround_enabled)
+ return;
+ for (i = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = &gpio_bank[i];
+ u32 l;
+
+ if (!(bank->enabled_non_wakeup_gpios))
+ continue;
+ __raw_writel(bank->saved_fallingdetect,
+ bank->base + OMAP24XX_GPIO_FALLINGDETECT);
+ __raw_writel(bank->saved_risingdetect,
+ bank->base + OMAP24XX_GPIO_RISINGDETECT);
+ /* Check if any of the non-wakeup interrupt GPIOs have changed
+ * state. If so, generate an IRQ by software. This is
+ * horribly racy, but it's the best we can do to work around
+ * this silicon bug. */
+ l = __raw_readl(bank->base + OMAP24XX_GPIO_DATAIN);
+ l ^= bank->saved_datain;
+ l &= bank->non_wakeup_gpios;
+ if (l) {
+ u32 old0, old1;
+
+ old0 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ old1 = __raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+ __raw_writel(old0 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ __raw_writel(old1 | l, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+ __raw_writel(old0, bank->base + OMAP24XX_GPIO_LEVELDETECT0);
+ __raw_writel(old1, bank->base + OMAP24XX_GPIO_LEVELDETECT1);
+ }
+ }
+
+}
+
#endif
/*
* This may get called early from board specific init
* for boards that have interrupts routed via FPGA.
*/
-int omap_gpio_init(void)
+int __init omap_gpio_init(void)
{
if (!initialized)
return _omap_gpio_init();
@@ -1212,6 +1559,8 @@ static int __init omap_gpio_sysinit(void)
if (!initialized)
ret = _omap_gpio_init();
+ mpuio_init();
+
#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP24XX)
if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
if (ret == 0) {
@@ -1232,3 +1581,128 @@ EXPORT_SYMBOL(omap_set_gpio_dataout);
EXPORT_SYMBOL(omap_get_gpio_datain);
arch_initcall(omap_gpio_sysinit);
+
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int gpio_is_input(struct gpio_bank *bank, int mask)
+{
+ void __iomem *reg = bank->base;
+
+ switch (bank->method) {
+ case METHOD_MPUIO:
+ reg += OMAP_MPUIO_IO_CNTL;
+ break;
+ case METHOD_GPIO_1510:
+ reg += OMAP1510_GPIO_DIR_CONTROL;
+ break;
+ case METHOD_GPIO_1610:
+ reg += OMAP1610_GPIO_DIRECTION;
+ break;
+ case METHOD_GPIO_730:
+ reg += OMAP730_GPIO_DIR_CONTROL;
+ break;
+ case METHOD_GPIO_24XX:
+ reg += OMAP24XX_GPIO_OE;
+ break;
+ }
+ return __raw_readl(reg) & mask;
+}
+
+
+static int dbg_gpio_show(struct seq_file *s, void *unused)
+{
+ unsigned i, j, gpio;
+
+ for (i = 0, gpio = 0; i < gpio_bank_count; i++) {
+ struct gpio_bank *bank = gpio_bank + i;
+ unsigned bankwidth = 16;
+ u32 mask = 1;
+
+ if (bank_is_mpuio(bank))
+ gpio = OMAP_MPUIO(0);
+ else if (cpu_is_omap24xx() || cpu_is_omap730())
+ bankwidth = 32;
+
+ for (j = 0; j < bankwidth; j++, gpio++, mask <<= 1) {
+ unsigned irq, value, is_in, irqstat;
+
+ if (!(bank->reserved_map & mask))
+ continue;
+
+ irq = bank->virtual_irq_start + j;
+ value = omap_get_gpio_datain(gpio);
+ is_in = gpio_is_input(bank, mask);
+
+ if (bank_is_mpuio(bank))
+ seq_printf(s, "MPUIO %2d: ", j);
+ else
+ seq_printf(s, "GPIO %3d: ", gpio);
+ seq_printf(s, "%s %s",
+ is_in ? "in " : "out",
+ value ? "hi" : "lo");
+
+ irqstat = irq_desc[irq].status;
+ if (is_in && ((bank->suspend_wakeup & mask)
+ || irqstat & IRQ_TYPE_SENSE_MASK)) {
+ char *trigger = NULL;
+
+ switch (irqstat & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = "falling";
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = "rising";
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ trigger = "bothedge";
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = "low";
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = "high";
+ break;
+ case IRQ_TYPE_NONE:
+ trigger = "(unspecified)";
+ break;
+ }
+ seq_printf(s, ", irq-%d %s%s",
+ irq, trigger,
+ (bank->suspend_wakeup & mask)
+ ? " wakeup" : "");
+ }
+ seq_printf(s, "\n");
+ }
+
+ if (bank_is_mpuio(bank)) {
+ seq_printf(s, "\n");
+ gpio = 0;
+ }
+ }
+ return 0;
+}
+
+static int dbg_gpio_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_gpio_show, &inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+ .open = dbg_gpio_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init omap_gpio_debuginit(void)
+{
+ (void) debugfs_create_file("omap_gpio", S_IRUGO,
+ NULL, NULL, &debug_fops);
+ return 0;
+}
+late_initcall(omap_gpio_debuginit);
+#endif
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c
new file mode 100644
index 00000000000..de7e6ef48bd
--- /dev/null
+++ b/arch/arm/plat-omap/mailbox.c
@@ -0,0 +1,509 @@
+/*
+ * OMAP mailbox driver
+ *
+ * Copyright (C) 2006 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * Restructured by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/blkdev.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/arch/mailbox.h>
+#include "mailbox.h"
+
+static struct omap_mbox *mboxes;
+static DEFINE_RWLOCK(mboxes_lock);
+
+/* Mailbox Sequence Bit function */
+void omap_mbox_init_seq(struct omap_mbox *mbox)
+{
+ mbox_seq_init(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_init_seq);
+
+/*
+ * message sender
+ */
+static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
+{
+ int ret = 0, i = 1000;
+
+ while (mbox_fifo_full(mbox)) {
+ if (mbox->ops->type == OMAP_MBOX_TYPE2)
+ return -1;
+ if (--i == 0)
+ return -1;
+ udelay(1);
+ }
+
+ if (arg && mbox->txq->callback) {
+ ret = mbox->txq->callback(arg);
+ if (ret)
+ goto out;
+ }
+
+ mbox_seq_toggle(mbox, &msg);
+ mbox_fifo_write(mbox, msg);
+ out:
+ return ret;
+}
+
+int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
+{
+ struct request *rq;
+ struct request_queue *q = mbox->txq->queue;
+ int ret = 0;
+
+ rq = blk_get_request(q, WRITE, GFP_ATOMIC);
+ if (unlikely(!rq)) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ rq->data = (void *)msg;
+ blk_insert_request(q, rq, 0, arg);
+
+ schedule_work(&mbox->txq->work);
+ fail:
+ return ret;
+}
+EXPORT_SYMBOL(omap_mbox_msg_send);
+
+static void mbox_tx_work(struct work_struct *work)
+{
+ int ret;
+ struct request *rq;
+ struct omap_mbox_queue *mq = container_of(work,
+ struct omap_mbox_queue, work);
+ struct omap_mbox *mbox = mq->queue->queuedata;
+ struct request_queue *q = mbox->txq->queue;
+
+ while (1) {
+ spin_lock(q->queue_lock);
+ rq = elv_next_request(q);
+ spin_unlock(q->queue_lock);
+
+ if (!rq)
+ break;
+
+ ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special);
+ if (ret) {
+ enable_mbox_irq(mbox, IRQ_TX);
+ return;
+ }
+
+ spin_lock(q->queue_lock);
+ blkdev_dequeue_request(rq);
+ end_that_request_last(rq, 0);
+ spin_unlock(q->queue_lock);
+ }
+}
+
+/*
+ * Message receiver(workqueue)
+ */
+static void mbox_rx_work(struct work_struct *work)
+{
+ struct omap_mbox_queue *mq =
+ container_of(work, struct omap_mbox_queue, work);
+ struct omap_mbox *mbox = mq->queue->queuedata;
+ struct request_queue *q = mbox->rxq->queue;
+ struct request *rq;
+ mbox_msg_t msg;
+ unsigned long flags;
+
+ if (mbox->rxq->callback == NULL) {
+ sysfs_notify(&mbox->dev.kobj, NULL, "mbox");
+ return;
+ }
+
+ while (1) {
+ spin_lock_irqsave(q->queue_lock, flags);
+ rq = elv_next_request(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ if (!rq)
+ break;
+
+ msg = (mbox_msg_t) rq->data;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blkdev_dequeue_request(rq);
+ end_that_request_last(rq, 0);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ mbox->rxq->callback((void *)msg);
+ }
+}
+
+/*
+ * Mailbox interrupt handler
+ */
+static void mbox_txq_fn(request_queue_t * q)
+{
+}
+
+static void mbox_rxq_fn(request_queue_t * q)
+{
+}
+
+static void __mbox_tx_interrupt(struct omap_mbox *mbox)
+{
+ disable_mbox_irq(mbox, IRQ_TX);
+ ack_mbox_irq(mbox, IRQ_TX);
+ schedule_work(&mbox->txq->work);
+}
+
+static void __mbox_rx_interrupt(struct omap_mbox *mbox)
+{
+ struct request *rq;
+ mbox_msg_t msg;
+ request_queue_t *q = mbox->rxq->queue;
+
+ disable_mbox_irq(mbox, IRQ_RX);
+
+ while (!mbox_fifo_empty(mbox)) {
+ rq = blk_get_request(q, WRITE, GFP_ATOMIC);
+ if (unlikely(!rq))
+ goto nomem;
+
+ msg = mbox_fifo_read(mbox);
+ rq->data = (void *)msg;
+
+ if (unlikely(mbox_seq_test(mbox, msg))) {
+ pr_info("mbox: Illegal seq bit!(%08x)\n", msg);
+ if (mbox->err_notify)
+ mbox->err_notify();
+ }
+
+ blk_insert_request(q, rq, 0, NULL);
+ if (mbox->ops->type == OMAP_MBOX_TYPE1)
+ break;
+ }
+
+ /* no more messages in the fifo. clear IRQ source. */
+ ack_mbox_irq(mbox, IRQ_RX);
+ enable_mbox_irq(mbox, IRQ_RX);
+ nomem:
+ schedule_work(&mbox->rxq->work);
+}
+
+static irqreturn_t mbox_interrupt(int irq, void *p)
+{
+ struct omap_mbox *mbox = (struct omap_mbox *)p;
+
+ if (is_mbox_irq(mbox, IRQ_TX))
+ __mbox_tx_interrupt(mbox);
+
+ if (is_mbox_irq(mbox, IRQ_RX))
+ __mbox_rx_interrupt(mbox);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * sysfs files
+ */
+static ssize_t
+omap_mbox_write(struct device *dev, struct device_attribute *attr,
+ const char * buf, size_t count)
+{
+ int ret;
+ mbox_msg_t *p = (mbox_msg_t *)buf;
+ struct omap_mbox *mbox = dev_get_drvdata(dev);
+
+ for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) {
+ ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL);
+ if (ret)
+ return -EAGAIN;
+ p++;
+ }
+
+ return (size_t)((char *)p - buf);
+}
+
+static ssize_t
+omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ unsigned long flags;
+ struct request *rq;
+ mbox_msg_t *p = (mbox_msg_t *) buf;
+ struct omap_mbox *mbox = dev_get_drvdata(dev);
+ struct request_queue *q = mbox->rxq->queue;
+
+ while (1) {
+ spin_lock_irqsave(q->queue_lock, flags);
+ rq = elv_next_request(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (!rq)
+ break;
+
+ *p = (mbox_msg_t) rq->data;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blkdev_dequeue_request(rq);
+ end_that_request_last(rq, 0);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ if (unlikely(mbox_seq_test(mbox, *p))) {
+ pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
+ continue;
+ }
+ p++;
+ }
+
+ pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
+
+ return (size_t) ((char *)p - buf);
+}
+
+static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write);
+
+static ssize_t mbox_show(struct class *class, char *buf)
+{
+ return sprintf(buf, "mbox");
+}
+
+static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL);
+
+static struct class omap_mbox_class = {
+ .name = "omap_mbox",
+};
+
+static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
+ request_fn_proc * proc,
+ void (*work) (struct work_struct *))
+{
+ request_queue_t *q;
+ struct omap_mbox_queue *mq;
+
+ mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
+ if (!mq)
+ return NULL;
+
+ spin_lock_init(&mq->lock);
+
+ q = blk_init_queue(proc, &mq->lock);
+ if (!q)
+ goto error;
+ q->queuedata = mbox;
+ mq->queue = q;
+
+ INIT_WORK(&mq->work, work);
+
+ return mq;
+error:
+ kfree(mq);
+ return NULL;
+}
+
+static void mbox_queue_free(struct omap_mbox_queue *q)
+{
+ blk_cleanup_queue(q->queue);
+ kfree(q);
+}
+
+static int omap_mbox_init(struct omap_mbox *mbox)
+{
+ int ret;
+ struct omap_mbox_queue *mq;
+
+ if (likely(mbox->ops->startup)) {
+ ret = mbox->ops->startup(mbox);
+ if (unlikely(ret))
+ return ret;
+ }
+
+ mbox->dev.class = &omap_mbox_class;
+ strlcpy(mbox->dev.bus_id, mbox->name, KOBJ_NAME_LEN);
+ dev_set_drvdata(&mbox->dev, mbox);
+
+ ret = device_register(&mbox->dev);
+ if (unlikely(ret))
+ goto fail_device_reg;
+
+ ret = device_create_file(&mbox->dev, &dev_attr_mbox);
+ if (unlikely(ret)) {
+ printk(KERN_ERR
+ "device_create_file failed: %d\n", ret);
+ goto fail_create_mbox;
+ }
+
+ ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
+ mbox->name, mbox);
+ if (unlikely(ret)) {
+ printk(KERN_ERR
+ "failed to register mailbox interrupt:%d\n", ret);
+ goto fail_request_irq;
+ }
+ enable_mbox_irq(mbox, IRQ_RX);
+
+ mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
+ if (!mq) {
+ ret = -ENOMEM;
+ goto fail_alloc_txq;
+ }
+ mbox->txq = mq;
+
+ mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work);
+ if (!mq) {
+ ret = -ENOMEM;
+ goto fail_alloc_rxq;
+ }
+ mbox->rxq = mq;
+
+ return 0;
+
+ fail_alloc_rxq:
+ mbox_queue_free(mbox->txq);
+ fail_alloc_txq:
+ free_irq(mbox->irq, mbox);
+ fail_request_irq:
+ device_remove_file(&mbox->dev, &dev_attr_mbox);
+ fail_create_mbox:
+ device_unregister(&mbox->dev);
+ fail_device_reg:
+ if (unlikely(mbox->ops->shutdown))
+ mbox->ops->shutdown(mbox);
+
+ return ret;
+}
+
+static void omap_mbox_fini(struct omap_mbox *mbox)
+{
+ mbox_queue_free(mbox->txq);
+ mbox_queue_free(mbox->rxq);
+
+ free_irq(mbox->irq, mbox);
+ device_remove_file(&mbox->dev, &dev_attr_mbox);
+ class_unregister(&omap_mbox_class);
+
+ if (unlikely(mbox->ops->shutdown))
+ mbox->ops->shutdown(mbox);
+}
+
+static struct omap_mbox **find_mboxes(const char *name)
+{
+ struct omap_mbox **p;
+
+ for (p = &mboxes; *p; p = &(*p)->next) {
+ if (strcmp((*p)->name, name) == 0)
+ break;
+ }
+
+ return p;
+}
+
+struct omap_mbox *omap_mbox_get(const char *name)
+{
+ struct omap_mbox *mbox;
+ int ret;
+
+ read_lock(&mboxes_lock);
+ mbox = *(find_mboxes(name));
+ if (mbox == NULL) {
+ read_unlock(&mboxes_lock);
+ return ERR_PTR(-ENOENT);
+ }
+
+ read_unlock(&mboxes_lock);
+
+ ret = omap_mbox_init(mbox);
+ if (ret)
+ return ERR_PTR(-ENODEV);
+
+ return mbox;
+}
+EXPORT_SYMBOL(omap_mbox_get);
+
+void omap_mbox_put(struct omap_mbox *mbox)
+{
+ omap_mbox_fini(mbox);
+}
+EXPORT_SYMBOL(omap_mbox_put);
+
+int omap_mbox_register(struct omap_mbox *mbox)
+{
+ int ret = 0;
+ struct omap_mbox **tmp;
+
+ if (!mbox)
+ return -EINVAL;
+ if (mbox->next)
+ return -EBUSY;
+
+ write_lock(&mboxes_lock);
+ tmp = find_mboxes(mbox->name);
+ if (*tmp)
+ ret = -EBUSY;
+ else
+ *tmp = mbox;
+ write_unlock(&mboxes_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(omap_mbox_register);
+
+int omap_mbox_unregister(struct omap_mbox *mbox)
+{
+ struct omap_mbox **tmp;
+
+ write_lock(&mboxes_lock);
+ tmp = &mboxes;
+ while (*tmp) {
+ if (mbox == *tmp) {
+ *tmp = mbox->next;
+ mbox->next = NULL;
+ write_unlock(&mboxes_lock);
+ return 0;
+ }
+ tmp = &(*tmp)->next;
+ }
+ write_unlock(&mboxes_lock);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(omap_mbox_unregister);
+
+static int __init omap_mbox_class_init(void)
+{
+ int ret = class_register(&omap_mbox_class);
+ if (!ret)
+ ret = class_create_file(&omap_mbox_class, &class_attr_mbox);
+
+ return ret;
+}
+
+static void __exit omap_mbox_class_exit(void)
+{
+ class_remove_file(&omap_mbox_class, &class_attr_mbox);
+ class_unregister(&omap_mbox_class);
+}
+
+subsys_initcall(omap_mbox_class_init);
+module_exit(omap_mbox_class_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-omap/mailbox.h b/arch/arm/plat-omap/mailbox.h
new file mode 100644
index 00000000000..67c6740b8ad
--- /dev/null
+++ b/arch/arm/plat-omap/mailbox.h
@@ -0,0 +1,100 @@
+/*
+ * Mailbox internal functions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ * Written by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ARCH_ARM_PLAT_MAILBOX_H
+#define __ARCH_ARM_PLAT_MAILBOX_H
+
+/*
+ * Mailbox sequence bit API
+ */
+#if defined(CONFIG_ARCH_OMAP1)
+# define MBOX_USE_SEQ_BIT
+#elif defined(CONFIG_ARCH_OMAP2)
+# define MBOX_USE_SEQ_BIT
+#endif
+
+#ifdef MBOX_USE_SEQ_BIT
+/* seq_rcv should be initialized with any value other than
+ * 0 and 1 << 31, to allow either value for the first
+ * message. */
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+ /* any value other than 0 and 1 << 31 */
+ mbox->seq_rcv = 0xffffffff;
+}
+
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+ /* add seq_snd to msg */
+ *msg = (*msg & 0x7fffffff) | mbox->seq_snd;
+ /* flip seq_snd */
+ mbox->seq_snd ^= 1 << 31;
+}
+
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ mbox_msg_t seq = msg & (1 << 31);
+ if (seq == mbox->seq_rcv)
+ return -1;
+ mbox->seq_rcv = seq;
+ return 0;
+}
+#else
+static inline void mbox_seq_init(struct omap_mbox *mbox)
+{
+}
+static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg)
+{
+}
+static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ return 0;
+}
+#endif
+
+/* Mailbox FIFO handle functions */
+static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox)
+{
+ return mbox->ops->fifo_read(mbox);
+}
+static inline void mbox_fifo_write(struct omap_mbox *mbox, mbox_msg_t msg)
+{
+ mbox->ops->fifo_write(mbox, msg);
+}
+static inline int mbox_fifo_empty(struct omap_mbox *mbox)
+{
+ return mbox->ops->fifo_empty(mbox);
+}
+static inline int mbox_fifo_full(struct omap_mbox *mbox)
+{
+ return mbox->ops->fifo_full(mbox);
+}
+
+/* Mailbox IRQ handle functions */
+static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ mbox->ops->enable_irq(mbox, irq);
+}
+static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ mbox->ops->disable_irq(mbox, irq);
+}
+static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ if (mbox->ops->ack_irq)
+ mbox->ops->ack_irq(mbox, irq);
+}
+static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+{
+ return mbox->ops->is_irq(mbox, irq);
+}
+
+#endif /* __ARCH_ARM_PLAT_MAILBOX_H */
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index b8d6f17ff58..f7b9ccdaacb 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -225,11 +225,16 @@ static void omap_mcbsp_dsp_free(void)
#ifdef CONFIG_ARCH_OMAP2
static void omap2_mcbsp2_mux_setup(void)
{
- omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
- omap_cfg_reg(R14_24XX_MCBSP2_FSX);
- omap_cfg_reg(W15_24XX_MCBSP2_DR);
- omap_cfg_reg(V15_24XX_MCBSP2_DX);
- omap_cfg_reg(V14_24XX_GPIO117);
+ if (cpu_is_omap2420()) {
+ omap_cfg_reg(Y15_24XX_MCBSP2_CLKX);
+ omap_cfg_reg(R14_24XX_MCBSP2_FSX);
+ omap_cfg_reg(W15_24XX_MCBSP2_DR);
+ omap_cfg_reg(V15_24XX_MCBSP2_DX);
+ omap_cfg_reg(V14_24XX_GPIO117);
+ }
+ /*
+ * Need to add MUX settings for OMAP 2430 SDP
+ */
}
#endif
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 19014b2ff4c..bc46f33aede 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -46,14 +46,19 @@
#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
+static unsigned long omap_sram_start;
static unsigned long omap_sram_base;
static unsigned long omap_sram_size;
static unsigned long omap_sram_ceil;
-unsigned long omap_fb_sram_start;
-unsigned long omap_fb_sram_size;
+extern unsigned long omapfb_reserve_sram(unsigned long sram_pstart,
+ unsigned long sram_vstart,
+ unsigned long sram_size,
+ unsigned long pstart_avail,
+ unsigned long size_avail);
-/* Depending on the target RAMFS firewall setup, the public usable amount of
+/*
+ * Depending on the target RAMFS firewall setup, the public usable amount of
* SRAM varies. The default accessable size for all device types is 2k. A GP
* device allows ARM11 but not other initators for full size. This
* functionality seems ok until some nice security API happens.
@@ -77,32 +82,6 @@ static int is_sram_locked(void)
return 1; /* assume locked with no PPA or security driver */
}
-void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
- unsigned long *start, unsigned long *size)
-{
- const struct omap_fbmem_config *fbmem_conf;
-
- fbmem_conf = omap_get_config(OMAP_TAG_FBMEM, struct omap_fbmem_config);
- if (fbmem_conf != NULL) {
- *start = fbmem_conf->fb_sram_start;
- *size = fbmem_conf->fb_sram_size;
- } else {
- *size = 0;
- *start = 0;
- }
-
- if (*size && (
- *start < start_avail ||
- *start + *size > start_avail + size_avail)) {
- printk(KERN_ERR "invalid FB SRAM configuration\n");
- *start = start_avail;
- *size = size_avail;
- }
-
- if (*size)
- pr_info("Reserving %lu bytes SRAM for frame buffer\n", *size);
-}
-
/*
* The amount of SRAM depends on the core type.
* Note that we cannot try to test for SRAM here because writes
@@ -111,16 +90,16 @@ void get_fb_sram_conf(unsigned long start_avail, unsigned size_avail,
*/
void __init omap_detect_sram(void)
{
- unsigned long sram_start;
+ unsigned long reserved;
if (cpu_is_omap24xx()) {
if (is_sram_locked()) {
omap_sram_base = OMAP2_SRAM_PUB_VA;
- sram_start = OMAP2_SRAM_PUB_PA;
+ omap_sram_start = OMAP2_SRAM_PUB_PA;
omap_sram_size = 0x800; /* 2K */
} else {
omap_sram_base = OMAP2_SRAM_VA;
- sram_start = OMAP2_SRAM_PA;
+ omap_sram_start = OMAP2_SRAM_PA;
if (cpu_is_omap242x())
omap_sram_size = 0xa0000; /* 640K */
else if (cpu_is_omap243x())
@@ -128,7 +107,7 @@ void __init omap_detect_sram(void)
}
} else {
omap_sram_base = OMAP1_SRAM_VA;
- sram_start = OMAP1_SRAM_PA;
+ omap_sram_start = OMAP1_SRAM_PA;
if (cpu_is_omap730())
omap_sram_size = 0x32000; /* 200K */
@@ -144,12 +123,11 @@ void __init omap_detect_sram(void)
omap_sram_size = 0x4000;
}
}
- get_fb_sram_conf(sram_start + SRAM_BOOTLOADER_SZ,
- omap_sram_size - SRAM_BOOTLOADER_SZ,
- &omap_fb_sram_start, &omap_fb_sram_size);
- if (omap_fb_sram_size)
- omap_sram_size -= sram_start + omap_sram_size -
- omap_fb_sram_start;
+ reserved = omapfb_reserve_sram(omap_sram_start, omap_sram_base,
+ omap_sram_size,
+ omap_sram_start + SRAM_BOOTLOADER_SZ,
+ omap_sram_size - SRAM_BOOTLOADER_SZ);
+ omap_sram_size -= reserved;
omap_sram_ceil = omap_sram_base + omap_sram_size;
}
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index 26531060116..2feceec8ecc 100644
--- a/arch/arm/plat-omap/timer32k.c
+++ b/arch/arm/plat-omap/timer32k.c
@@ -42,6 +42,8 @@
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/system.h>
#include <asm/hardware.h>
@@ -80,13 +82,13 @@ struct sys_timer omap_timer;
#define OMAP1_32K_TIMER_TVR 0x00
#define OMAP1_32K_TIMER_TCR 0x04
-#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
+#define OMAP_32K_TICKS_PER_SEC (32768)
/*
* TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
* so with HZ = 128, TVR = 255.
*/
-#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
+#define OMAP_32K_TIMER_TICK_PERIOD ((OMAP_32K_TICKS_PER_SEC / HZ) - 1)
#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
(((nr_jiffies) * (clock_rate)) / HZ)
@@ -142,6 +144,28 @@ static inline void omap_32k_timer_ack_irq(void)
#endif
+static void omap_32k_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_PERIODIC:
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ omap_32k_timer_stop();
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_32k_timer = {
+ .name = "32k-timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .shift = 32,
+ .set_mode = omap_32k_timer_set_mode,
+};
+
/*
* The 32KHz synchronized timer is an additional timer on 16xx.
* It is always running.
@@ -171,15 +195,6 @@ omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
static unsigned long omap_32k_last_tick = 0;
/*
- * Returns elapsed usecs since last 32k timer interrupt
- */
-static unsigned long omap_32k_timer_gettimeoffset(void)
-{
- unsigned long now = omap_32k_sync_timer_read();
- return omap_32k_ticks_to_usecs(now - omap_32k_last_tick);
-}
-
-/*
* Returns current time from boot in nsecs. It's OK for this to wrap
* around for now, as it's just a relative time stamp.
*/
@@ -188,110 +203,26 @@ unsigned long long sched_clock(void)
return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
}
-/*
- * Timer interrupt for 32KHz timer. When dynamic tick is enabled, this
- * function is also called from other interrupts to remove latency
- * issues with dynamic tick. In the dynamic tick case, we need to lock
- * with irqsave.
- */
-static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
-{
- unsigned long now;
-
- omap_32k_timer_ack_irq();
- now = omap_32k_sync_timer_read();
-
- while ((signed long)(now - omap_32k_last_tick)
- >= OMAP_32K_TICKS_PER_HZ) {
- omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick();
- }
-
- /* Restart timer so we don't drift off due to modulo or dynamic tick.
- * By default we program the next timer to be continuous to avoid
- * latencies during high system load. During dynamic tick operation the
- * continuous timer can be overridden from pm_idle to be longer.
- */
- omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
-{
- return _omap_32k_timer_interrupt(irq, dev_id);
-}
-
static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long flags;
+ struct clock_event_device *evt = &clockevent_32k_timer;
+ omap_32k_timer_ack_irq();
- write_seqlock_irqsave(&xtime_lock, flags);
- _omap_32k_timer_interrupt(irq, dev_id);
- write_sequnlock_irqrestore(&xtime_lock, flags);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
-#ifdef CONFIG_NO_IDLE_HZ
-/*
- * Programs the next timer interrupt needed. Called when dynamic tick is
- * enabled, and to reprogram the ticks to skip from pm_idle. Note that
- * we can keep the timer continuous, and don't need to set it to run in
- * one-shot mode. This is because the timer will get reprogrammed again
- * after next interrupt.
- */
-void omap_32k_timer_reprogram(unsigned long next_tick)
-{
- unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1;
- unsigned long now = omap_32k_sync_timer_read();
- unsigned long idled = now - omap_32k_last_tick;
-
- if (idled + 1 < ticks)
- ticks -= idled;
- else
- ticks = 1;
- omap_32k_timer_start(ticks);
-}
-
-static struct irqaction omap_32k_timer_irq;
-extern struct timer_update_handler timer_update;
-
-static int omap_32k_timer_enable_dyn_tick(void)
-{
- /* No need to reprogram timer, just use the next interrupt */
- return 0;
-}
-
-static int omap_32k_timer_disable_dyn_tick(void)
-{
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
- return 0;
-}
-
-static struct dyn_tick_timer omap_dyn_tick_timer = {
- .enable = omap_32k_timer_enable_dyn_tick,
- .disable = omap_32k_timer_disable_dyn_tick,
- .reprogram = omap_32k_timer_reprogram,
- .handler = omap_32k_timer_handler,
-};
-#endif /* CONFIG_NO_IDLE_HZ */
-
static struct irqaction omap_32k_timer_irq = {
.name = "32KHz timer",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = omap_32k_timer_interrupt,
};
static __init void omap_init_32k_timer(void)
{
-#ifdef CONFIG_NO_IDLE_HZ
- omap_timer.dyn_tick = &omap_dyn_tick_timer;
-#endif
-
if (cpu_class_is_omap1())
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
- omap_timer.offset = omap_32k_timer_gettimeoffset;
omap_32k_last_tick = omap_32k_sync_timer_read();
#ifdef CONFIG_ARCH_OMAP2
@@ -308,7 +239,16 @@ static __init void omap_init_32k_timer(void)
}
#endif
- omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+ clockevent_32k_timer.mult = div_sc(OMAP_32K_TICKS_PER_SEC,
+ NSEC_PER_SEC,
+ clockevent_32k_timer.shift);
+ clockevent_32k_timer.max_delta_ns =
+ clockevent_delta2ns(0xfffffffe, &clockevent_32k_timer);
+ clockevent_32k_timer.min_delta_ns =
+ clockevent_delta2ns(1, &clockevent_32k_timer);
+
+ clockevent_32k_timer.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&clockevent_32k_timer);
}
/*
@@ -326,5 +266,4 @@ static void __init omap_timer_init(void)
struct sys_timer omap_timer = {
.init = omap_timer_init,
- .offset = NULL, /* Initialized later */
};
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 7e8096809be..25489aafb11 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -37,9 +37,27 @@
#include <asm/arch/usb.h>
#include <asm/arch/board.h>
+#ifdef CONFIG_ARCH_OMAP1
+
+#define INT_USB_IRQ_GEN IH2_BASE + 20
+#define INT_USB_IRQ_NISO IH2_BASE + 30
+#define INT_USB_IRQ_ISO IH2_BASE + 29
+#define INT_USB_IRQ_HGEN INT_USB_HHC_1
+#define INT_USB_IRQ_OTG IH2_BASE + 8
+
+#else
+
+#define INT_USB_IRQ_GEN INT_24XX_USB_IRQ_GEN
+#define INT_USB_IRQ_NISO INT_24XX_USB_IRQ_NISO
+#define INT_USB_IRQ_ISO INT_24XX_USB_IRQ_ISO
+#define INT_USB_IRQ_HGEN INT_24XX_USB_IRQ_HGEN
+#define INT_USB_IRQ_OTG INT_24XX_USB_IRQ_OTG
+
+#endif
+
+
/* These routines should handle the standard chip-specific modes
* for usb0/1/2 ports, covering basic mux and transceiver setup.
- * Call omap_usb_init() once, from INIT_MACHINE().
*
* Some board-*.c files will need to set up additional mux options,
* like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
@@ -96,19 +114,26 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
{
u32 syscon1 = 0;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG &= ~USBT0WRMODEI(USB_BIDIR_TLL);
+
if (nwires == 0) {
- if (!cpu_is_omap15xx()) {
+ if (cpu_class_is_omap1() && !cpu_is_omap15xx()) {
/* pulldown D+/D- */
USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
}
return 0;
}
- if (is_device)
- omap_cfg_reg(W4_USB_PUEN);
+ if (is_device) {
+ if (cpu_is_omap24xx())
+ omap_cfg_reg(J20_24XX_USB0_PUEN);
+ else
+ omap_cfg_reg(W4_USB_PUEN);
+ }
- /* internal transceiver */
- if (nwires == 2) {
+ /* internal transceiver (unavailable on 17xx, 24xx) */
+ if (!cpu_class_is_omap2() && nwires == 2) {
// omap_cfg_reg(P9_USB_DP);
// omap_cfg_reg(R8_USB_DM);
@@ -136,29 +161,50 @@ static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
return 0;
}
- omap_cfg_reg(V6_USB0_TXD);
- omap_cfg_reg(W9_USB0_TXEN);
- omap_cfg_reg(W5_USB0_SE0);
+ if (cpu_is_omap24xx()) {
+ omap_cfg_reg(K18_24XX_USB0_DAT);
+ omap_cfg_reg(K19_24XX_USB0_TXEN);
+ omap_cfg_reg(J14_24XX_USB0_SE0);
+ if (nwires != 3)
+ omap_cfg_reg(J18_24XX_USB0_RCV);
+ } else {
+ omap_cfg_reg(V6_USB0_TXD);
+ omap_cfg_reg(W9_USB0_TXEN);
+ omap_cfg_reg(W5_USB0_SE0);
+ if (nwires != 3)
+ omap_cfg_reg(Y5_USB0_RCV);
+ }
- /* NOTE: SPEED and SUSP aren't configured here */
+ /* NOTE: SPEED and SUSP aren't configured here. OTG hosts
+ * may be able to use I2C requests to set those bits along
+ * with VBUS switching and overcurrent detction.
+ */
- if (nwires != 3)
- omap_cfg_reg(Y5_USB0_RCV);
- if (nwires != 6)
+ if (cpu_class_is_omap1() && nwires != 6)
USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
switch (nwires) {
case 3:
syscon1 = 2;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
break;
case 4:
syscon1 = 1;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_BIDIR);
break;
case 6:
syscon1 = 3;
- omap_cfg_reg(AA9_USB0_VP);
- omap_cfg_reg(R9_USB0_VM);
- USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+ if (cpu_is_omap24xx()) {
+ omap_cfg_reg(J19_24XX_USB0_VP);
+ omap_cfg_reg(K20_24XX_USB0_VM);
+ CONTROL_DEVCONF_REG |= USBT0WRMODEI(USB_UNIDIR);
+ } else {
+ omap_cfg_reg(AA9_USB0_VP);
+ omap_cfg_reg(R9_USB0_VM);
+ USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+ }
break;
default:
printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
@@ -171,14 +217,22 @@ static u32 __init omap_usb1_init(unsigned nwires)
{
u32 syscon1 = 0;
- if (nwires != 6 && !cpu_is_omap15xx())
+ if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG &= ~USBT1WRMODEI(USB_BIDIR_TLL);
+
if (nwires == 0)
return 0;
/* external transceiver */
- omap_cfg_reg(USB1_TXD);
- omap_cfg_reg(USB1_TXEN);
+ if (cpu_class_is_omap1()) {
+ omap_cfg_reg(USB1_TXD);
+ omap_cfg_reg(USB1_TXEN);
+ if (nwires != 3)
+ omap_cfg_reg(USB1_RCV);
+ }
+
if (cpu_is_omap15xx()) {
omap_cfg_reg(USB1_SEO);
omap_cfg_reg(USB1_SPEED);
@@ -190,20 +244,38 @@ static u32 __init omap_usb1_init(unsigned nwires)
} else if (cpu_is_omap1710()) {
omap_cfg_reg(R13_1710_USB1_SE0);
// SUSP
+ } else if (cpu_is_omap24xx()) {
+ /* NOTE: board-specific code must set up pin muxing for usb1,
+ * since each signal could come out on either of two balls.
+ */
} else {
- pr_debug("usb unrecognized\n");
+ pr_debug("usb%d cpu unrecognized\n", 1);
+ return 0;
}
- if (nwires != 3)
- omap_cfg_reg(USB1_RCV);
switch (nwires) {
+ case 2:
+ if (!cpu_is_omap24xx())
+ goto bad;
+ /* NOTE: board-specific code must override this setting if
+ * this TLL link is not using DP/DM
+ */
+ syscon1 = 1;
+ CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR_TLL);
+ break;
case 3:
syscon1 = 2;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
break;
case 4:
syscon1 = 1;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG |= USBT1WRMODEI(USB_BIDIR);
break;
case 6:
+ if (cpu_is_omap24xx())
+ goto bad;
syscon1 = 3;
omap_cfg_reg(USB1_VP);
omap_cfg_reg(USB1_VM);
@@ -211,6 +283,7 @@ static u32 __init omap_usb1_init(unsigned nwires)
USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
break;
default:
+bad:
printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
1, nwires);
}
@@ -221,10 +294,17 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
{
u32 syscon1 = 0;
- /* NOTE erratum: must leave USB2_UNI_R set if usb0 in use */
+ if (cpu_is_omap24xx()) {
+ CONTROL_DEVCONF_REG &= ~(USBT2WRMODEI(USB_BIDIR_TLL)
+ | USBT2TLL5PI);
+ alt_pingroup = 0;
+ }
+
+ /* NOTE omap1 erratum: must leave USB2_UNI_R set if usb0 in use */
if (alt_pingroup || nwires == 0)
return 0;
- if (nwires != 6 && !cpu_is_omap15xx())
+
+ if (cpu_class_is_omap1() && !cpu_is_omap15xx() && nwires != 6)
USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
/* external transceiver */
@@ -242,19 +322,54 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
if (nwires != 3)
omap_cfg_reg(Y5_USB2_RCV);
// FIXME omap_cfg_reg(USB2_SPEED);
+ } else if (cpu_is_omap24xx()) {
+ omap_cfg_reg(Y11_24XX_USB2_DAT);
+ omap_cfg_reg(AA10_24XX_USB2_SE0);
+ if (nwires > 2)
+ omap_cfg_reg(AA12_24XX_USB2_TXEN);
+ if (nwires > 3)
+ omap_cfg_reg(AA6_24XX_USB2_RCV);
} else {
- pr_debug("usb unrecognized\n");
+ pr_debug("usb%d cpu unrecognized\n", 1);
+ return 0;
}
- // omap_cfg_reg(USB2_SUSP);
+ // if (cpu_class_is_omap1()) omap_cfg_reg(USB2_SUSP);
switch (nwires) {
+ case 2:
+ if (!cpu_is_omap24xx())
+ goto bad;
+ /* NOTE: board-specific code must override this setting if
+ * this TLL link is not using DP/DM
+ */
+ syscon1 = 1;
+ CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR_TLL);
+ break;
case 3:
syscon1 = 2;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
break;
case 4:
syscon1 = 1;
+ if (cpu_is_omap24xx())
+ CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_BIDIR);
+ break;
+ case 5:
+ if (!cpu_is_omap24xx())
+ goto bad;
+ omap_cfg_reg(AA4_24XX_USB2_TLLSE0);
+ /* NOTE: board-specific code must override this setting if
+ * this TLL link is not using DP/DM. Something must also
+ * set up OTG_SYSCON2.HMC_TLL{ATTACH,SPEED}
+ */
+ syscon1 = 3;
+ CONTROL_DEVCONF_REG |= USBT2WRMODEI(USB_UNIDIR_TLL)
+ | USBT2TLL5PI;
break;
case 6:
+ if (cpu_is_omap24xx())
+ goto bad;
syscon1 = 3;
if (cpu_is_omap15xx()) {
omap_cfg_reg(USB2_VP);
@@ -266,6 +381,7 @@ static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
}
break;
default:
+bad:
printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
2, nwires);
}
@@ -294,13 +410,13 @@ static struct resource udc_resources[] = {
.end = UDC_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, { /* general IRQ */
- .start = IH2_BASE + 20,
+ .start = INT_USB_IRQ_GEN,
.flags = IORESOURCE_IRQ,
}, { /* PIO IRQ */
- .start = IH2_BASE + 30,
+ .start = INT_USB_IRQ_NISO,
.flags = IORESOURCE_IRQ,
}, { /* SOF IRQ */
- .start = IH2_BASE + 29,
+ .start = INT_USB_IRQ_ISO,
.flags = IORESOURCE_IRQ,
},
};
@@ -329,11 +445,11 @@ static u64 ohci_dmamask = ~(u32)0;
static struct resource ohci_resources[] = {
{
.start = OMAP_OHCI_BASE,
- .end = OMAP_OHCI_BASE + 4096 - 1,
+ .end = OMAP_OHCI_BASE + 0xff,
.flags = IORESOURCE_MEM,
},
{
- .start = INT_USB_HHC_1,
+ .start = INT_USB_IRQ_HGEN,
.flags = IORESOURCE_IRQ,
},
};
@@ -361,7 +477,7 @@ static struct resource otg_resources[] = {
.end = OTG_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, {
- .start = IH2_BASE + 8,
+ .start = INT_USB_IRQ_OTG,
.flags = IORESOURCE_IRQ,
},
};
@@ -385,7 +501,7 @@ static struct platform_device otg_device = {
// FIXME correct answer depends on hmc_mode,
-// as does any nonzero value for config->otg port number
+// as does (on omap1) any nonzero value for config->otg port number
#ifdef CONFIG_USB_GADGET_OMAP
#define is_usb0_device(config) 1
#else
@@ -426,12 +542,13 @@ omap_otg_init(struct omap_usb_config *config)
if (config->otg)
syscon |= OTG_EN;
#endif
- pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
+ if (cpu_class_is_omap1())
+ pr_debug("USB_TRANSCEIVER_CTRL_REG = %03x\n", USB_TRANSCEIVER_CTRL_REG);
pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
OTG_SYSCON_2_REG = syscon;
printk("USB: hmc %d", config->hmc_mode);
- if (alt_pingroup)
+ if (!alt_pingroup)
printk(", usb2 alt %d wires", config->pins[2]);
else if (config->pins[0])
printk(", usb0 %d wires%s", config->pins[0],
@@ -444,10 +561,12 @@ omap_otg_init(struct omap_usb_config *config)
printk(", Mini-AB on usb%d", config->otg - 1);
printk("\n");
- /* leave USB clocks/controllers off until needed */
- ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
- ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
- ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+ if (cpu_class_is_omap1()) {
+ /* leave USB clocks/controllers off until needed */
+ ULPD_SOFT_REQ_REG &= ~SOFT_USB_CLK_REQ;
+ ULPD_CLOCK_CTRL_REG &= ~USB_MCLK_EN;
+ ULPD_CLOCK_CTRL_REG |= DIS_USB_PVCI_CLK;
+ }
syscon = OTG_SYSCON_1_REG;
syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
@@ -585,7 +704,7 @@ omap_usb_init(void)
}
platform_data = *config;
- if (cpu_is_omap730() || cpu_is_omap16xx())
+ if (cpu_is_omap730() || cpu_is_omap16xx() || cpu_is_omap24xx())
omap_otg_init(&platform_data);
else if (cpu_is_omap15xx())
omap_1510_usb_init(&platform_data);
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c
index d3dc03a7383..79cda0faec8 100644
--- a/arch/arm/plat-s3c24xx/clock.c
+++ b/arch/arm/plat-s3c24xx/clock.c
@@ -404,6 +404,18 @@ int s3c24xx_register_clock(struct clk *clk)
return 0;
}
+int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
+{
+ int fails = 0;
+
+ for (; nr_clks > 0; nr_clks--, clks++) {
+ if (s3c24xx_register_clock(*clks) < 0)
+ fails++;
+ }
+
+ return fails;
+}
+
/* initalise all the clocks */
int __init s3c24xx_setup_clocks(unsigned long xtal,
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 6a2d1070e5a..8ce4904d313 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -181,24 +181,6 @@ s3c_lookup_cpu(unsigned long idcode)
return NULL;
}
-/* board information */
-
-static struct s3c24xx_board *board;
-
-void s3c24xx_set_board(struct s3c24xx_board *b)
-{
- int i;
-
- board = b;
-
- if (b->clocks_count != 0) {
- struct clk **ptr = b->clocks;
-
- for (i = b->clocks_count; i > 0; i--, ptr++)
- s3c24xx_register_clock(*ptr);
- }
-}
-
/* cpu information */
static struct cpu_table *cpu;
@@ -342,26 +324,6 @@ static int __init s3c_arch_init(void)
return ret;
ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts);
- if (ret != 0)
- return ret;
-
- if (board != NULL) {
- struct platform_device **ptr = board->devices;
- int i;
-
- for (i = 0; i < board->devices_count; i++, ptr++) {
- ret = platform_device_register(*ptr);
-
- if (ret) {
- printk(KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n", (*ptr)->name, ret, *ptr);
- }
- }
-
- /* mask any error, we may not need all these board
- * devices */
- ret = 0;
- }
-
return ret;
}
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 4540a806f52..6f03c937097 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -44,7 +44,7 @@ static struct kmem_cache *dma_kmem;
static int dma_channels;
-struct s3c24xx_dma_selection dma_sel;
+static struct s3c24xx_dma_selection dma_sel;
/* dma channel state information */
struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
@@ -880,7 +880,7 @@ static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
return 0;
}
-void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
+static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan)
{
unsigned long tmp;
unsigned int timeout = 0x10000;
@@ -957,8 +957,7 @@ static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
return 0;
}
-int
-s3c2410_dma_started(struct s3c2410_dma_chan *chan)
+static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
{
unsigned long flags;
@@ -1280,7 +1279,7 @@ static void s3c2410_dma_cache_ctor(void *p, struct kmem_cache *c, unsigned long
/* initialisation code */
-int __init s3c24xx_dma_sysclass_init(void)
+static int __init s3c24xx_dma_sysclass_init(void)
{
int ret = sysdev_class_register(&dma_sysclass);
@@ -1292,7 +1291,7 @@ int __init s3c24xx_dma_sysclass_init(void)
core_initcall(s3c24xx_dma_sysclass_init);
-int __init s3c24xx_dma_sysdev_register(void)
+static int __init s3c24xx_dma_sysdev_register(void)
{
struct s3c2410_dma_chan *cp = s3c2410_chans;
int channel, ret;
@@ -1396,7 +1395,7 @@ static struct s3c24xx_dma_order *dma_order;
* channel
*/
-struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
+static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
{
struct s3c24xx_dma_order_ch *ord = NULL;
struct s3c24xx_dma_map *ch_map;
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index ce186398e3f..8fbc8847026 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -54,7 +54,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index ecf68d61190..c6b03f8ab26 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -511,11 +511,6 @@ static int s3c2410_pm_enter(suspend_state_t state)
return -EINVAL;
}
- if (state != PM_SUSPEND_MEM) {
- printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
- return -EINVAL;
- }
-
/* check if we have anything to wake-up with... bad things seem
* to happen if you suspend with no wakeup (system will often
* require a full power-cycle)
@@ -617,30 +612,9 @@ static int s3c2410_pm_enter(suspend_state_t state)
return 0;
}
-/*
- * Called after processes are frozen, but before we shut down devices.
- */
-static int s3c2410_pm_prepare(suspend_state_t state)
-{
- return 0;
-}
-
-/*
- * Called after devices are re-setup, but before processes are thawed.
- */
-static int s3c2410_pm_finish(suspend_state_t state)
-{
- return 0;
-}
-
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
static struct pm_ops s3c2410_pm_ops = {
- .pm_disk_mode = PM_DISK_FIRMWARE,
- .prepare = s3c2410_pm_prepare,
.enter = s3c2410_pm_enter,
- .finish = s3c2410_pm_finish,
+ .valid = pm_valid_only_mem,
};
/* s3c2410_pm_init
diff --git a/arch/arm/plat-s3c24xx/s3c244x-irq.c b/arch/arm/plat-s3c24xx/s3c244x-irq.c
index a0e39d89401..2dbb2606d44 100644
--- a/arch/arm/plat-s3c24xx/s3c244x-irq.c
+++ b/arch/arm/plat-s3c24xx/s3c244x-irq.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S
index 435349dc324..7b7ae790b00 100644
--- a/arch/arm/plat-s3c24xx/sleep.S
+++ b/arch/arm/plat-s3c24xx/sleep.S
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/sleep.S
+/* linux/arch/arm/plat-s3c24xx/sleep.S
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
index c523d1c9cce..b7667375bce 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -138,7 +138,7 @@ s3c2410_timer_interrupt(int irq, void *dev_id)
static struct irqaction s3c2410_timer_irq = {
.name = "S3C2410 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.handler = s3c2410_timer_interrupt,
};
diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
index e44b9ed0f81..74e89f8fb3a 100644
--- a/arch/arm/vfp/vfpdouble.c
+++ b/arch/arm/vfp/vfpdouble.c
@@ -34,7 +34,6 @@
#include <linux/bitops.h>
#include <asm/div64.h>
-#include <asm/ptrace.h>
#include <asm/vfp.h>
#include "vfpinstr.h"
diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
index 0221ba3bc79..b252631b406 100644
--- a/arch/arm/vfp/vfpsingle.c
+++ b/arch/arm/vfp/vfpsingle.c
@@ -34,7 +34,6 @@
#include <linux/bitops.h>
#include <asm/div64.h>
-#include <asm/ptrace.h>
#include <asm/vfp.h>
#include "vfpinstr.h"
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index 989113dce41..20688bc13e9 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -57,9 +57,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_BUST_SPINLOCK
- bool
-
config ZONE_DMA
bool
default y
diff --git a/arch/arm26/boot/compressed/misc.c b/arch/arm26/boot/compressed/misc.c
index f17f50e5516..0714d19c577 100644
--- a/arch/arm26/boot/compressed/misc.c
+++ b/arch/arm26/boot/compressed/misc.c
@@ -182,7 +182,7 @@ extern int end;
static ulg free_mem_ptr;
static ulg free_mem_ptr_end;
-#define HEAP_SIZE 0x2000
+#define HEAP_SIZE 0x3000
#include "../../../../lib/inflate.c"
diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
index 93293d04b30..f735d7e018e 100644
--- a/arch/arm26/kernel/armksyms.c
+++ b/arch/arm26/kernel/armksyms.c
@@ -20,7 +20,6 @@
#include <linux/pm.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <asm/byteorder.h>
diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c
index 9343889b27f..41692795672 100644
--- a/arch/arm26/kernel/ptrace.c
+++ b/arch/arm26/kernel/ptrace.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/security.h>
diff --git a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c
index 6a8ef8da6da..379b82dc645 100644
--- a/arch/arm26/kernel/signal.c
+++ b/arch/arm26/kernel/signal.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/signal.h>
diff --git a/arch/arm26/mm/memc.c b/arch/arm26/mm/memc.c
index f2901581d4d..42505541a9b 100644
--- a/arch/arm26/mm/memc.c
+++ b/arch/arm26/mm/memc.c
@@ -176,13 +176,9 @@ void __init pgtable_cache_init(void)
{
pte_cache = kmem_cache_create("pte-cache",
sizeof(pte_t) * PTRS_PER_PTE,
- 0, 0, pte_cache_ctor, NULL);
- if (!pte_cache)
- BUG();
+ 0, SLAB_PANIC, pte_cache_ctor, NULL);
pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE +
sizeof(pgd_t) * PTRS_PER_PGD,
- 0, 0, pgd_cache_ctor, NULL);
- if (!pgd_cache)
- BUG();
+ 0, SLAB_PANIC, pgd_cache_ctor, NULL);
}
diff --git a/arch/avr32/Makefile b/arch/avr32/Makefile
index 6115fc1f0cf..dc6bc01f232 100644
--- a/arch/avr32/Makefile
+++ b/arch/avr32/Makefile
@@ -16,7 +16,7 @@ AFLAGS += -mrelax -mno-pic
CFLAGS_MODULE += -mno-relax
LDFLAGS_vmlinux += --relax
-cpuflags-$(CONFIG_CPU_AP7000) += -mcpu=ap7000
+cpuflags-$(CONFIG_CPU_AT32AP7000) += -mcpu=ap7000
CFLAGS += $(cpuflags-y)
AFLAGS += $(cpuflags-y)
diff --git a/arch/avr32/kernel/kprobes.c b/arch/avr32/kernel/kprobes.c
index d0abbcaf1c1..004c94b6fc1 100644
--- a/arch/avr32/kernel/kprobes.c
+++ b/arch/avr32/kernel/kprobes.c
@@ -15,7 +15,7 @@
#include <linux/ptrace.h>
#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
#include <asm/ocd.h>
DEFINE_PER_CPU(struct kprobe *, current_kprobe);
diff --git a/arch/avr32/kernel/process.c b/arch/avr32/kernel/process.c
index 4e4181ed1c6..13f98840261 100644
--- a/arch/avr32/kernel/process.c
+++ b/arch/avr32/kernel/process.c
@@ -330,13 +330,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
{
struct pt_regs *childregs;
- childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)p->thread_info)) - 1;
+ childregs = ((struct pt_regs *)(THREAD_SIZE + (unsigned long)task_stack_page(p))) - 1;
*childregs = *regs;
if (user_mode(regs))
childregs->sp = usp;
else
- childregs->sp = (unsigned long)p->thread_info + THREAD_SIZE;
+ childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
childregs->r12 = 0; /* Set return value for child */
@@ -403,7 +403,7 @@ unsigned long get_wchan(struct task_struct *p)
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
- stack_page = (unsigned long)p->thread_info;
+ stack_page = (unsigned long)task_stack_page(p);
BUG_ON(!stack_page);
/*
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 6f4388f7c20..3c36c2d1614 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/user.h>
@@ -21,11 +20,11 @@
#include <asm/uaccess.h>
#include <asm/ocd.h>
#include <asm/mmu_context.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
static struct pt_regs *get_user_regs(struct task_struct *tsk)
{
- return (struct pt_regs *)((unsigned long) tsk->thread_info +
+ return (struct pt_regs *)((unsigned long)task_stack_page(tsk) +
THREAD_SIZE - sizeof(struct pt_regs));
}
@@ -300,7 +299,7 @@ asmlinkage void do_debug_priv(struct pt_regs *regs)
else
die_val = DIE_BREAKPOINT;
- if (notify_die(die_val, regs, 0, SIGTRAP) == NOTIFY_STOP)
+ if (notify_die(die_val, "ptrace", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
return;
if (likely(ds & DS_SSS)) {
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index 7c279586fbb..07f6a6fa340 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -291,4 +291,5 @@ sys_call_table:
.long sys_shmget /* 275 */
.long sys_shmdt
.long sys_shmctl
+ .long sys_utimensat
.long sys_ni_syscall /* r8 is saturated at nr_syscalls */
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 4f0382d8483..86d107511dd 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -20,20 +20,6 @@
#include <asm/sysreg.h>
#include <asm/traps.h>
-ATOMIC_NOTIFIER_HEAD(avr32_die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&avr32_die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&avr32_die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
static DEFINE_SPINLOCK(die_lock);
void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
@@ -137,7 +123,7 @@ asmlinkage void do_address_exception(unsigned long ecr, struct pt_regs *regs)
/* This way of handling undefined instructions is stolen from ARM */
static LIST_HEAD(undef_hook);
-static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(undef_lock);
void register_undef_hook(struct undef_hook *hook)
{
diff --git a/arch/avr32/kernel/vmlinux.lds.c b/arch/avr32/kernel/vmlinux.lds.c
index 7ad20cfb48a..e7f72c995a3 100644
--- a/arch/avr32/kernel/vmlinux.lds.c
+++ b/arch/avr32/kernel/vmlinux.lds.c
@@ -35,7 +35,7 @@ SECTIONS
_einittext = .;
. = ALIGN(4);
__tagtable_begin = .;
- *(.taglist)
+ *(.taglist.init)
__tagtable_end = .;
*(.init.data)
. = ALIGN(16);
diff --git a/arch/avr32/mach-at32ap/clock.c b/arch/avr32/mach-at32ap/clock.c
index 00c435452d7..0f8c89c9f83 100644
--- a/arch/avr32/mach-at32ap/clock.c
+++ b/arch/avr32/mach-at32ap/clock.c
@@ -18,7 +18,7 @@
#include "clock.h"
-static spinlock_t clk_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(clk_lock);
struct clk *clk_get(struct device *dev, const char *id)
{
diff --git a/arch/avr32/mm/dma-coherent.c b/arch/avr32/mm/dma-coherent.c
index b68d669f823..099212d4567 100644
--- a/arch/avr32/mm/dma-coherent.c
+++ b/arch/avr32/mm/dma-coherent.c
@@ -112,16 +112,21 @@ void dma_free_coherent(struct device *dev, size_t size,
}
EXPORT_SYMBOL(dma_free_coherent);
-#if 0
void *dma_alloc_writecombine(struct device *dev, size_t size,
dma_addr_t *handle, gfp_t gfp)
{
struct page *page;
+ dma_addr_t phys;
page = __dma_alloc(dev, size, handle, gfp);
+ if (!page)
+ return NULL;
+
+ phys = page_to_phys(page);
+ *handle = phys;
/* Now, map the page into P3 with write-combining turned on */
- return __ioremap(page_to_phys(page), size, _PAGE_BUFFER);
+ return __ioremap(phys, size, _PAGE_BUFFER);
}
EXPORT_SYMBOL(dma_alloc_writecombine);
@@ -132,8 +137,7 @@ void dma_free_writecombine(struct device *dev, size_t size,
iounmap(cpu_addr);
- page = bus_to_page(handle);
+ page = phys_to_page(handle);
__dma_free(dev, size, page, handle);
}
EXPORT_SYMBOL(dma_free_writecombine);
-#endif
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index 146ebdbdc30..88b00b15970 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/pagemap.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
#include <asm/mmu_context.h>
#include <asm/sysreg.h>
#include <asm/tlb.h>
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
new file mode 100644
index 00000000000..1a493050932
--- /dev/null
+++ b/arch/blackfin/Kconfig
@@ -0,0 +1,989 @@
+#
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/kconfig-language.txt.
+#
+
+mainmenu "uClinux/Blackfin (w/o MMU) Kernel Configuration"
+
+config MMU
+ bool
+ default n
+
+config FPU
+ bool
+ default n
+
+config RWSEM_GENERIC_SPINLOCK
+ bool
+ default y
+
+config RWSEM_XCHGADD_ALGORITHM
+ bool
+ default n
+
+config BLACKFIN
+ bool
+ default y
+
+config BFIN
+ bool
+ default y
+
+config SEMAPHORE_SLEEPERS
+ bool
+ default y
+
+config GENERIC_FIND_NEXT_BIT
+ bool
+ default y
+
+config GENERIC_HWEIGHT
+ bool
+ default y
+
+config GENERIC_HARDIRQS
+ bool
+ default y
+
+config GENERIC_IRQ_PROBE
+ bool
+ default y
+
+config GENERIC_TIME
+ bool
+ default n
+
+config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
+config FORCE_MAX_ZONEORDER
+ int
+ default "14"
+
+config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
+config IRQCHIP_DEMUX_GPIO
+ bool
+ default y
+
+source "init/Kconfig"
+source "kernel/Kconfig.preempt"
+
+menu "Blackfin Processor Options"
+
+comment "Processor and Board Settings"
+
+choice
+ prompt "CPU"
+ default BF533
+
+config BF531
+ bool "BF531"
+ help
+ BF531 Processor Support.
+
+config BF532
+ bool "BF532"
+ help
+ BF532 Processor Support.
+
+config BF533
+ bool "BF533"
+ help
+ BF533 Processor Support.
+
+config BF534
+ bool "BF534"
+ help
+ BF534 Processor Support.
+
+config BF536
+ bool "BF536"
+ help
+ BF536 Processor Support.
+
+config BF537
+ bool "BF537"
+ help
+ BF537 Processor Support.
+
+config BF561
+ bool "BF561"
+ help
+ Not Supported Yet - Work in progress - BF561 Processor Support.
+
+endchoice
+
+choice
+ prompt "Silicon Rev"
+ default BF_REV_0_2 if BF537
+ default BF_REV_0_3 if BF533
+
+config BF_REV_0_2
+ bool "0.2"
+ depends on (BF537 || BF536 || BF534)
+
+config BF_REV_0_3
+ bool "0.3"
+ depends on (BF561 || BF537 || BF536 || BF534 || BF533 || BF532 || BF531)
+
+config BF_REV_0_4
+ bool "0.4"
+ depends on (BF561 || BF533 || BF532 || BF531)
+
+config BF_REV_0_5
+ bool "0.5"
+ depends on (BF561 || BF533 || BF532 || BF531)
+
+endchoice
+
+config BFIN_DUAL_CORE
+ bool
+ depends on (BF561)
+ default y
+
+config BFIN_SINGLE_CORE
+ bool
+ depends on !BFIN_DUAL_CORE
+ default y
+
+choice
+ prompt "System type"
+ default BFIN533_STAMP
+ help
+ Do NOT change the board here. Please use the top level
+ configuration to ensure that all the other settings are
+ correct.
+
+config BFIN533_EZKIT
+ bool "BF533-EZKIT"
+ depends on (BF533 || BF532 || BF531)
+ help
+ BF533-EZKIT-LITE board Support.
+
+config BFIN533_STAMP
+ bool "BF533-STAMP"
+ depends on (BF533 || BF532 || BF531)
+ help
+ BF533-STAMP board Support.
+
+config BFIN537_STAMP
+ bool "BF537-STAMP"
+ depends on (BF537 || BF536 || BF534)
+ help
+ BF537-STAMP board Support.
+
+config BFIN533_BLUETECHNIX_CM
+ bool "Bluetechnix CM-BF533"
+ depends on (BF533)
+ help
+ CM-BF533 support for EVAL- and DEV-Board.
+
+config BFIN537_BLUETECHNIX_CM
+ bool "Bluetechnix CM-BF537"
+ depends on (BF537)
+ help
+ CM-BF537 support for EVAL- and DEV-Board.
+
+config BFIN561_BLUETECHNIX_CM
+ bool "BF561-CM"
+ depends on (BF561)
+ help
+ CM-BF561 support for EVAL- and DEV-Board.
+
+config BFIN561_EZKIT
+ bool "BF561-EZKIT"
+ depends on (BF561)
+ help
+ BF561-EZKIT-LITE board Support.
+
+config PNAV10
+ bool "PNAV 1.0 board"
+ depends on (BF537)
+ help
+ PNAV 1.0 board Support.
+
+config GENERIC_BOARD
+ bool "Custom"
+ depends on (BF537 || BF536 \
+ || BF534 || BF561 || BF535 || BF533 || BF532 || BF531)
+ help
+ GENERIC or Custom board Support.
+
+endchoice
+
+config MEM_GENERIC_BOARD
+ bool
+ depends on GENERIC_BOARD
+ default y
+
+config MEM_MT48LC64M4A2FB_7E
+ bool
+ depends on (BFIN533_STAMP)
+ default y
+
+config MEM_MT48LC16M16A2TG_75
+ bool
+ depends on (BFIN533_EZKIT || BFIN561_EZKIT \
+ || BFIN533_BLUETECHNIX_CM || BFIN537_BLUETECHNIX_CM)
+ default y
+
+config MEM_MT48LC32M8A2_75
+ bool
+ depends on (BFIN537_STAMP || PNAV10)
+ default y
+
+config MEM_MT48LC8M32B2B5_7
+ bool
+ depends on (BFIN561_BLUETECHNIX_CM)
+ default y
+
+config BFIN_SHARED_FLASH_ENET
+ bool
+ depends on (BFIN533_STAMP)
+ default y
+
+source "arch/blackfin/mach-bf533/Kconfig"
+source "arch/blackfin/mach-bf561/Kconfig"
+source "arch/blackfin/mach-bf537/Kconfig"
+
+menu "Board customizations"
+
+config CMDLINE_BOOL
+ bool "Default bootloader kernel arguments"
+
+config CMDLINE
+ string "Initial kernel command string"
+ depends on CMDLINE_BOOL
+ default "console=ttyBF0,57600"
+ help
+ If you don't have a boot loader capable of passing a command line string
+ to the kernel, you may specify one here. As a minimum, you should specify
+ the memory size and the root device (e.g., mem=8M, root=/dev/nfs).
+
+comment "Board Setup"
+
+config CLKIN_HZ
+ int "Crystal Frequency in Hz"
+ default "11059200" if BFIN533_STAMP
+ default "27000000" if BFIN533_EZKIT
+ default "25000000" if BFIN537_STAMP
+ default "30000000" if BFIN561_EZKIT
+ default "24576000" if PNAV10
+ help
+ The frequency of CLKIN crystal oscillator on the board in Hz.
+
+config MEM_SIZE
+ int "SDRAM Memory Size in MBytes"
+ default 32 if BFIN533_EZKIT
+ default 64 if BFIN537_STAMP
+ default 64 if BFIN561_EZKIT
+ default 128 if BFIN533_STAMP
+ default 64 if PNAV10
+
+config MEM_ADD_WIDTH
+ int "SDRAM Memory Address Width"
+ default 9 if BFIN533_EZKIT
+ default 9 if BFIN561_EZKIT
+ default 10 if BFIN537_STAMP
+ default 11 if BFIN533_STAMP
+ default 10 if PNAV10
+
+config ENET_FLASH_PIN
+ int "PF port/pin used for flash and ethernet sharing"
+ depends on (BFIN533_STAMP)
+ default 0
+ help
+ PF port/pin used for flash and ethernet sharing to allow other PF
+ pins to be used on other platforms without having to touch common
+ code.
+ For example: PF0 --> 0,PF1 --> 1,PF2 --> 2, etc.
+
+config BOOT_LOAD
+ hex "Kernel load address for booting"
+ default "0x1000"
+ help
+ This option allows you to set the load address of the kernel.
+ This can be useful if you are on a board which has a small amount
+ of memory or you wish to reserve some memory at the beginning of
+ the address space.
+
+ Note that you generally want to keep this value at or above 4k
+ (0x1000) as this will allow the kernel to capture NULL pointer
+ references.
+
+comment "LED Status Indicators"
+ depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+
+config BFIN_ALIVE_LED
+ bool "Enable Board Alive"
+ depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+ default n
+ help
+ Blink the LEDs you select when the kernel is running. Helps detect
+ a hung kernel.
+
+config BFIN_ALIVE_LED_NUM
+ int "LED"
+ depends on BFIN_ALIVE_LED
+ range 1 3 if BFIN533_STAMP
+ default "3" if BFIN533_STAMP
+ help
+ Select the LED (marked on the board) for you to blink.
+
+config BFIN_IDLE_LED
+ bool "Enable System Load/Idle LED"
+ depends on (BFIN533_STAMP || BFIN533_BLUETECHNIX_CM)
+ default n
+ help
+ Blinks the LED you select when to determine kernel load.
+
+config BFIN_IDLE_LED_NUM
+ int "LED"
+ depends on BFIN_IDLE_LED
+ range 1 3 if BFIN533_STAMP
+ default "2" if BFIN533_STAMP
+ help
+ Select the LED (marked on the board) for you to blink.
+
+#
+# Sorry - but you need to put the hex address here -
+#
+
+# Flag Data register
+config BFIN_ALIVE_LED_PORT
+ hex
+ default 0xFFC00700 if (BFIN533_STAMP)
+
+# Peripheral Flag Direction Register
+config BFIN_ALIVE_LED_DPORT
+ hex
+ default 0xFFC00730 if (BFIN533_STAMP)
+
+config BFIN_ALIVE_LED_PIN
+ hex
+ default 0x04 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 1)
+ default 0x08 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 2)
+ default 0x10 if (BFIN533_STAMP && BFIN_ALIVE_LED_NUM = 3)
+
+config BFIN_IDLE_LED_PORT
+ hex
+ default 0xFFC00700 if (BFIN533_STAMP)
+
+# Peripheral Flag Direction Register
+config BFIN_IDLE_LED_DPORT
+ hex
+ default 0xFFC00730 if (BFIN533_STAMP)
+
+config BFIN_IDLE_LED_PIN
+ hex
+ default 0x04 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 1)
+ default 0x08 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 2)
+ default 0x10 if (BFIN533_STAMP && BFIN_IDLE_LED_NUM = 3)
+
+comment "Console UART Setup"
+
+choice
+ prompt "Baud Rate"
+ default BAUD_57600
+config BAUD_9600
+ bool "9600"
+config BAUD_19200
+ bool "19200"
+config BAUD_38400
+ bool "38400"
+config BAUD_57600
+ bool "57600"
+config BAUD_115200
+ bool "115200"
+endchoice
+
+choice
+ prompt "Parity"
+ default BAUD_NO_PARITY
+config BAUD_NO_PARITY
+ bool "No Parity"
+config BAUD_PARITY
+ bool "Parity"
+endchoice
+
+choice
+ prompt "Stop Bits"
+ default BAUD_1_STOPBIT
+config BAUD_1_STOPBIT
+ bool "1"
+config BAUD_2_STOPBIT
+ bool "2"
+endchoice
+
+endmenu
+
+
+menu "Blackfin Kernel Optimizations"
+
+comment "Timer Tick"
+
+source kernel/Kconfig.hz
+
+comment "Memory Optimizations"
+
+config I_ENTRY_L1
+ bool "Locate interrupt entry code in L1 Memory"
+ default y
+ help
+ If enabled interrupt entry code (STORE/RESTORE CONTEXT) is linked
+ into L1 instruction memory.(less latency)
+
+config EXCPT_IRQ_SYSC_L1
+ bool "Locate entire ASM lowlevel excepetion / interrupt - Syscall and CPLB handler code in L1 Memory"
+ default y
+ help
+ If enabled entire ASM lowlevel exception and interrupt entry code (STORE/RESTORE CONTEXT) is linked
+ into L1 instruction memory.(less latency)
+
+config DO_IRQ_L1
+ bool "Locate frequently called do_irq dispatcher function in L1 Memory"
+ default y
+ help
+ If enabled frequently called do_irq dispatcher function is linked
+ into L1 instruction memory.(less latency)
+
+config CORE_TIMER_IRQ_L1
+ bool "Locate frequently called timer_interrupt() function in L1 Memory"
+ default y
+ help
+ If enabled frequently called timer_interrupt() function is linked
+ into L1 instruction memory.(less latency)
+
+config IDLE_L1
+ bool "Locate frequently idle function in L1 Memory"
+ default y
+ help
+ If enabled frequently called idle function is linked
+ into L1 instruction memory.(less latency)
+
+config SCHEDULE_L1
+ bool "Locate kernel schedule function in L1 Memory"
+ default y
+ help
+ If enabled frequently called kernel schedule is linked
+ into L1 instruction memory.(less latency)
+
+config ARITHMETIC_OPS_L1
+ bool "Locate kernel owned arithmetic functions in L1 Memory"
+ default y
+ help
+ If enabled arithmetic functions are linked
+ into L1 instruction memory.(less latency)
+
+config ACCESS_OK_L1
+ bool "Locate access_ok function in L1 Memory"
+ default y
+ help
+ If enabled access_ok function is linked
+ into L1 instruction memory.(less latency)
+
+config MEMSET_L1
+ bool "Locate memset function in L1 Memory"
+ default y
+ help
+ If enabled memset function is linked
+ into L1 instruction memory.(less latency)
+
+config MEMCPY_L1
+ bool "Locate memcpy function in L1 Memory"
+ default y
+ help
+ If enabled memcpy function is linked
+ into L1 instruction memory.(less latency)
+
+config SYS_BFIN_SPINLOCK_L1
+ bool "Locate sys_bfin_spinlock function in L1 Memory"
+ default y
+ help
+ If enabled sys_bfin_spinlock function is linked
+ into L1 instruction memory.(less latency)
+
+config IP_CHECKSUM_L1
+ bool "Locate IP Checksum function in L1 Memory"
+ default n
+ help
+ If enabled IP Checksum function is linked
+ into L1 instruction memory.(less latency)
+
+config CACHELINE_ALIGNED_L1
+ bool "Locate cacheline_aligned data to L1 Data Memory"
+ default y
+ depends on !BF531
+ help
+ If enabled cacheline_anligned data is linked
+ into L1 data memory.(less latency)
+
+config SYSCALL_TAB_L1
+ bool "Locate Syscall Table L1 Data Memory"
+ default n
+ depends on !BF531
+ help
+ If enabled the Syscall LUT is linked
+ into L1 data memory.(less latency)
+
+config CPLB_SWITCH_TAB_L1
+ bool "Locate CPLB Switch Tables L1 Data Memory"
+ default n
+ depends on !BF531
+ help
+ If enabled the CPLB Switch Tables are linked
+ into L1 data memory.(less latency)
+
+endmenu
+
+
+choice
+ prompt "Kernel executes from"
+ help
+ Choose the memory type that the kernel will be running in.
+
+config RAMKERNEL
+ bool "RAM"
+ help
+ The kernel will be resident in RAM when running.
+
+config ROMKERNEL
+ bool "ROM"
+ help
+ The kernel will be resident in FLASH/ROM when running.
+
+endchoice
+
+source "mm/Kconfig"
+
+config LARGE_ALLOCS
+ bool "Allow allocating large blocks (> 1MB) of memory"
+ help
+ Allow the slab memory allocator to keep chains for very large
+ memory sizes - upto 32MB. You may need this if your system has
+ a lot of RAM, and you need to able to allocate very large
+ contiguous chunks. If unsure, say N.
+
+config BFIN_DMA_5XX
+ bool "Enable DMA Support"
+ depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561)
+ default y
+ help
+ DMA driver for BF5xx.
+
+choice
+ prompt "Uncached SDRAM region"
+ default DMA_UNCACHED_1M
+ depends BFIN_DMA_5XX
+config DMA_UNCACHED_2M
+ bool "Enable 2M DMA region"
+config DMA_UNCACHED_1M
+ bool "Enable 1M DMA region"
+config DMA_UNCACHED_NONE
+ bool "Disable DMA region"
+endchoice
+
+
+comment "Cache Support"
+config BLKFIN_CACHE
+ bool "Enable ICACHE"
+config BLKFIN_DCACHE
+ bool "Enable DCACHE"
+config BLKFIN_DCACHE_BANKA
+ bool "Enable only 16k BankA DCACHE - BankB is SRAM"
+ depends on BLKFIN_DCACHE && !BF531
+ default n
+config BLKFIN_CACHE_LOCK
+ bool "Enable Cache Locking"
+
+choice
+ prompt "Policy"
+ depends on BLKFIN_DCACHE
+ default BLKFIN_WB
+config BLKFIN_WB
+ bool "Write back"
+ help
+ Write Back Policy:
+ Cached data will be written back to SDRAM only when needed.
+ This can give a nice increase in performance, but beware of
+ broken drivers that do not properly invalidate/flush their
+ cache.
+
+ Write Through Policy:
+ Cached data will always be written back to SDRAM when the
+ cache is updated. This is a completely safe setting, but
+ performance is worse than Write Back.
+
+ If you are unsure of the options and you want to be safe,
+ then go with Write Through.
+
+config BLKFIN_WT
+ bool "Write through"
+ help
+ Write Back Policy:
+ Cached data will be written back to SDRAM only when needed.
+ This can give a nice increase in performance, but beware of
+ broken drivers that do not properly invalidate/flush their
+ cache.
+
+ Write Through Policy:
+ Cached data will always be written back to SDRAM when the
+ cache is updated. This is a completely safe setting, but
+ performance is worse than Write Back.
+
+ If you are unsure of the options and you want to be safe,
+ then go with Write Through.
+
+endchoice
+
+config L1_MAX_PIECE
+ int "Set the max L1 SRAM pieces"
+ default 16
+ help
+ Set the max memory pieces for the L1 SRAM allocation algorithm.
+ Min value is 16. Max value is 1024.
+
+menu "Clock Settings"
+
+
+config BFIN_KERNEL_CLOCK
+ bool "Re-program Clocks while Kernel boots?"
+ default n
+ help
+ This option decides if kernel clocks are re-programed from the
+ bootloader settings. If the clocks are not set, the SDRAM settings
+ are also not changed, and the Bootloader does 100% of the hardware
+ configuration.
+
+config VCO_MULT
+ int "VCO Multiplier"
+ depends on BFIN_KERNEL_CLOCK
+ default "22" if BFIN533_EZKIT
+ default "45" if BFIN533_STAMP
+ default "20" if BFIN537_STAMP
+ default "22" if BFIN533_BLUETECHNIX_CM
+ default "20" if BFIN537_BLUETECHNIX_CM
+ default "20" if BFIN561_BLUETECHNIX_CM
+ default "20" if BFIN561_EZKIT
+
+config CCLK_DIV
+ int "Core Clock Divider"
+ depends on BFIN_KERNEL_CLOCK
+ default 1 if BFIN533_EZKIT
+ default 1 if BFIN533_STAMP
+ default 1 if BFIN537_STAMP
+ default 1 if BFIN533_BLUETECHNIX_CM
+ default 1 if BFIN537_BLUETECHNIX_CM
+ default 1 if BFIN561_BLUETECHNIX_CM
+ default 1 if BFIN561_EZKIT
+
+config SCLK_DIV
+ int "System Clock Divider"
+ depends on BFIN_KERNEL_CLOCK
+ default 5 if BFIN533_EZKIT
+ default 5 if BFIN533_STAMP
+ default 4 if BFIN537_STAMP
+ default 5 if BFIN533_BLUETECHNIX_CM
+ default 4 if BFIN537_BLUETECHNIX_CM
+ default 4 if BFIN561_BLUETECHNIX_CM
+ default 5 if BFIN561_EZKIT
+
+config CLKIN_HALF
+ bool "Half ClockIn"
+ depends on BFIN_KERNEL_CLOCK
+ default n
+
+config PLL_BYPASS
+ bool "Bypass PLL"
+ depends on BFIN_KERNEL_CLOCK
+ default n
+
+endmenu
+
+comment "Asynchonous Memory Configuration"
+
+menu "EBIU_AMBCTL Global Control"
+config C_AMCKEN
+ bool "Enable CLKOUT"
+ default y
+
+config C_CDPRIO
+ bool "DMA has priority over core for ext. accesses"
+ default n
+
+config C_B0PEN
+ depends on BF561
+ bool "Bank 0 16 bit packing enable"
+ default y
+
+config C_B1PEN
+ depends on BF561
+ bool "Bank 1 16 bit packing enable"
+ default y
+
+config C_B2PEN
+ depends on BF561
+ bool "Bank 2 16 bit packing enable"
+ default y
+
+config C_B3PEN
+ depends on BF561
+ bool "Bank 3 16 bit packing enable"
+ default n
+
+choice
+ prompt"Enable Asynchonous Memory Banks"
+ default C_AMBEN_ALL
+
+config C_AMBEN
+ bool "Disable All Banks"
+
+config C_AMBEN_B0
+ bool "Enable Bank 0"
+
+config C_AMBEN_B0_B1
+ bool "Enable Bank 0 & 1"
+
+config C_AMBEN_B0_B1_B2
+ bool "Enable Bank 0 & 1 & 2"
+
+config C_AMBEN_ALL
+ bool "Enable All Banks"
+endchoice
+endmenu
+
+menu "EBIU_AMBCTL Control"
+config BANK_0
+ hex "Bank 0"
+ default 0x7BB0
+
+config BANK_1
+ hex "Bank 1"
+ default 0x7BB0
+
+config BANK_2
+ hex "Bank 2"
+ default 0x7BB0
+
+config BANK_3
+ hex "Bank 3"
+ default 0x99B3
+endmenu
+
+endmenu
+
+#############################################################################
+menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
+
+config PCI
+ bool "PCI support"
+ help
+ Support for PCI bus.
+
+source "drivers/pci/Kconfig"
+
+config HOTPLUG
+ bool "Support for hot-pluggable device"
+ help
+ Say Y here if you want to plug devices into your computer while
+ the system is running, and be able to use them quickly. In many
+ cases, the devices can likewise be unplugged at any time too.
+
+ One well known example of this is PCMCIA- or PC-cards, credit-card
+ size devices such as network cards, modems or hard drives which are
+ plugged into slots found on all modern laptop computers. Another
+ example, used on modern desktops as well as laptops, is USB.
+
+ Enable HOTPLUG and KMOD, and build a modular kernel. Get agent
+ software (at <http://linux-hotplug.sourceforge.net/>) and install it.
+ Then your kernel will automatically call out to a user mode "policy
+ agent" (/sbin/hotplug) to load modules and set up software needed
+ to use devices as you hotplug them.
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+menu "Power management options"
+source "kernel/power/Kconfig"
+
+choice
+ prompt "Select PM Wakeup Event Source"
+ default PM_WAKEUP_GPIO_BY_SIC_IWR
+ depends on PM
+ help
+ If you have a GPIO already configured as input with the corresponding PORTx_MASK
+ bit set - "Specify Wakeup Event by SIC_IWR value"
+
+config PM_WAKEUP_GPIO_BY_SIC_IWR
+ bool "Specify Wakeup Event by SIC_IWR value"
+config PM_WAKEUP_BY_GPIO
+ bool "Cause Wakeup Event by GPIO"
+config PM_WAKEUP_GPIO_API
+ bool "Configure Wakeup Event by PM GPIO API"
+
+endchoice
+
+config PM_WAKEUP_SIC_IWR
+ hex "Wakeup Events (SIC_IWR)"
+ depends on PM_WAKEUP_GPIO_BY_SIC_IWR
+ default 0x80000000 if (BF537 || BF536 || BF534)
+ default 0x100000 if (BF533 || BF532 || BF531)
+
+config PM_WAKEUP_GPIO_NUMBER
+ int "Wakeup GPIO number"
+ range 0 47
+ depends on PM_WAKEUP_BY_GPIO
+ default 2 if BFIN537_STAMP
+
+choice
+ prompt "GPIO Polarity"
+ depends on PM_WAKEUP_BY_GPIO
+ default PM_WAKEUP_GPIO_POLAR_H
+config PM_WAKEUP_GPIO_POLAR_H
+ bool "Active High"
+config PM_WAKEUP_GPIO_POLAR_L
+ bool "Active Low"
+config PM_WAKEUP_GPIO_POLAR_EDGE_F
+ bool "Falling EDGE"
+config PM_WAKEUP_GPIO_POLAR_EDGE_R
+ bool "Rising EDGE"
+config PM_WAKEUP_GPIO_POLAR_EDGE_B
+ bool "Both EDGE"
+endchoice
+
+endmenu
+
+if (BF537 || BF533)
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ
+ bool
+ default n
+ help
+ If you want to enable this option, you should select the
+ DPMC driver from Character Devices.
+endmenu
+
+endif
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/blackfin/oprofile/Kconfig"
+
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config DEBUG_HWERR
+ bool "Hardware error interrupt debugging"
+ depends on DEBUG_KERNEL
+ help
+ When enabled, the hardware error interrupt is never disabled, and
+ will happen immediately when an error condition occurs. This comes
+ at a slight cost in code size, but is necessary if you are getting
+ hardware error interrupts and need to know where they are coming
+ from.
+
+config DEBUG_ICACHE_CHECK
+ bool "Check Instruction cache coherancy"
+ depends on DEBUG_KERNEL
+ depends on DEBUG_HWERR
+ help
+ Say Y here if you are getting wierd unexplained errors. This will
+ ensure that icache is what SDRAM says it should be, by doing a
+ byte wise comparision between SDRAM and instruction cache. This
+ also relocates the irq_panic() function to L1 memory, (which is
+ un-cached).
+
+config DEBUG_KERNEL_START
+ bool "Debug Kernel Startup"
+ depends on DEBUG_KERNEL
+ help
+ Say Y here to put in an mini-execption handler before the kernel
+ replaces the bootloader exception handler. This will stop kernels
+ from dieing at startup with no visible error messages.
+
+config DEBUG_SERIAL_EARLY_INIT
+ bool "Initialize serial driver early"
+ default n
+ depends on SERIAL_BFIN
+ help
+ Say Y here if you want to get kernel output early when kernel
+ crashes before the normal console initialization. If this option
+ is enable, console output will always go to the ttyBF0, no matter
+ what kernel boot paramters you set.
+
+config DEBUG_HUNT_FOR_ZERO
+ bool "Catch NULL pointer reads/writes"
+ default y
+ help
+ Say Y here to catch reads/writes to anywhere in the memory range
+ from 0x0000 - 0x0FFF (the first 4k) of memory. This is useful in
+ catching common programming errors such as NULL pointer dereferences.
+
+ Misbehaving applications will be killed (generate a SEGV) while the
+ kernel will trigger a panic.
+
+ Enabling this option will take up an extra entry in CPLB table.
+ Otherwise, there is no extra overhead.
+
+config DEBUG_BFIN_NO_KERN_HWTRACE
+ bool "Trace user apps (turn off hwtrace in kernel)"
+ default n
+ help
+ Some pieces of the kernel contain a lot of flow changes which can
+ quickly fill up the hardware trace buffer. When debugging crashes,
+ the hardware trace may indicate that the problem lies in kernel
+ space when in reality an application is buggy.
+
+ Say Y here to disable hardware tracing in some known "jumpy" pieces
+ of code so that the trace buffer will extend further back.
+
+config DUAL_CORE_TEST_MODULE
+ tristate "Dual Core Test Module"
+ depends on (BF561)
+ default n
+ help
+ Say Y here to build-in dual core test module for dual core test.
+
+config CPLB_INFO
+ bool "Display the CPLB information"
+ help
+ Display the CPLB information.
+
+config ACCESS_CHECK
+ bool "Check the user pointer address"
+ default y
+ help
+ Usually the pointer transfer from user space is checked to see if its
+ address is in the kernel space.
+
+ Say N here to disable that check to improve the performance.
+
+endmenu
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
new file mode 100644
index 00000000000..52d4dbdb2b1
--- /dev/null
+++ b/arch/blackfin/Makefile
@@ -0,0 +1,80 @@
+#
+# arch/blackfin/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+
+CROSS_COMPILE ?= bfin-uclinux-
+LDFLAGS_vmlinux := -X
+OBJCOPYFLAGS := -O binary -R .note -R .comment -S
+GZFLAGS := -9
+
+CFLAGS_MODULE += -mlong-calls
+KALLSYMS += --symbol-prefix=_
+
+
+# setup the machine name and the machine dependent settings
+machine-$(CONFIG_BF531) := bf533
+machine-$(CONFIG_BF532) := bf533
+machine-$(CONFIG_BF533) := bf533
+machine-$(CONFIG_BF534) := bf537
+machine-$(CONFIG_BF536) := bf537
+machine-$(CONFIG_BF537) := bf537
+machine-$(CONFIG_BF561) := bf561
+MACHINE := $(machine-y)
+export MACHINE
+
+
+head-y := arch/$(ARCH)/mach-$(MACHINE)/head.o arch/$(ARCH)/kernel/init_task.o
+
+core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ arch/$(ARCH)/mach-common/
+
+# If we have a machine-specific directory, then include it in the build.
+ifneq ($(machine-y),)
+core-y += arch/$(ARCH)/mach-$(MACHINE)/
+core-y += arch/$(ARCH)/mach-$(MACHINE)/boards/
+endif
+
+libs-y += arch/$(ARCH)/lib/
+
+drivers-$(CONFIG_OPROFILE) += arch/$(ARCH)/oprofile/
+
+
+
+# Update machine arch symlinks if something which affects
+# them changed. We use .mach to indicate when they were updated
+# last, otherwise make uses the target directory mtime.
+
+include/asm-blackfin/.mach: $(wildcard include/config/arch/*.h) include/config/auto.conf
+ @echo ' SYMLINK include/asm-$(ARCH)/mach-$(MACHINE) -> include/asm-$(ARCH)/mach'
+ifneq ($(KBUILD_SRC),)
+ $(Q)mkdir -p include/asm-$(ARCH)
+ $(Q)ln -fsn $(srctree)/include/asm-$(ARCH)/mach-$(MACHINE) include/asm-$(ARCH)/mach
+else
+ $(Q)ln -fsn mach-$(MACHINE) include/asm-$(ARCH)/mach
+endif
+ @touch $@
+
+CLEAN_FILES += \
+ include/asm-$(ARCH)/asm-offsets.h \
+ arch/$(ARCH)/kernel/asm-offsets.s \
+ include/asm-$(ARCH)/mach \
+ include/asm-$(ARCH)/.mach
+
+archprepare: include/asm-blackfin/.mach
+archclean:
+ $(Q)$(MAKE) $(clean)=$(boot)
+
+
+all: vmImage
+boot := arch/$(ARCH)/boot
+BOOT_TARGETS = vmImage
+.PHONY: $(BOOT_TARGETS)
+$(BOOT_TARGETS): vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+define archhelp
+ echo '* vmImage - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)'
+endef
diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile
new file mode 100644
index 00000000000..49e8098d4c2
--- /dev/null
+++ b/arch/blackfin/boot/Makefile
@@ -0,0 +1,27 @@
+#
+# arch/blackfin/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
+targets := vmImage
+extra-y += vmlinux.bin vmlinux.gz
+
+quiet_cmd_uimage = UIMAGE $@
+ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
+ -C gzip -a $(CONFIG_BOOT_LOAD) -e $(CONFIG_BOOT_LOAD) -n 'Linux-$(KERNELRELEASE)' \
+ -d $< $@
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+$(obj)/vmImage: $(obj)/vmlinux.gz
+ $(call if_changed,uimage)
+ @echo 'Kernel: $@ is ready'
diff --git a/arch/blackfin/defconfig b/arch/blackfin/defconfig
new file mode 100644
index 00000000000..d5904ca994c
--- /dev/null
+++ b/arch/blackfin/defconfig
@@ -0,0 +1,1314 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BFIN=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_UCLINUX=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_IRQCHIP_DEMUX_GPIO=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_LIMIT_PAGECACHE is not set
+CONFIG_BUDDY=y
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF535 is not set
+# CONFIG_BF536 is not set
+CONFIG_BF537=y
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_2=y
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+CONFIG_BLACKFIN=y
+CONFIG_BFIN_SINGLE_CORE=y
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+CONFIG_BFIN537_STAMP=y
+# CONFIG_BFIN533_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_EZKIT is not set
+# CONFIG_PNAV10 is not set
+# CONFIG_GENERIC_BOARD is not set
+CONFIG_MEM_MT48LC32M8A2_75=y
+CONFIG_IRQ_PLL_WAKEUP=7
+
+#
+# BF537 Specific Configuration
+#
+
+#
+# PORT F/G Selection
+#
+CONFIG_BF537_PORT_F=y
+# CONFIG_BF537_PORT_G is not set
+# CONFIG_BF537_PORT_H is not set
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMA_ERROR=7
+CONFIG_IRQ_ERROR=7
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_PPI=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_TWI=10
+CONFIG_IRQ_SPI=10
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+CONFIG_IRQ_CAN_RX=11
+CONFIG_IRQ_CAN_TX=11
+CONFIG_IRQ_MAC_RX=11
+CONFIG_IRQ_MAC_TX=11
+CONFIG_IRQ_TMR0=12
+CONFIG_IRQ_TMR1=12
+CONFIG_IRQ_TMR2=12
+CONFIG_IRQ_TMR3=12
+CONFIG_IRQ_TMR4=12
+CONFIG_IRQ_TMR5=12
+CONFIG_IRQ_TMR6=12
+CONFIG_IRQ_TMR7=12
+CONFIG_IRQ_PROG_INTA=12
+CONFIG_IRQ_PORTG_INTB=12
+CONFIG_IRQ_MEM_DMA0=13
+CONFIG_IRQ_MEM_DMA1=13
+CONFIG_IRQ_WATCH=13
+
+#
+# Board customizations
+#
+
+#
+# Board Setup
+#
+CONFIG_CLKIN_HZ=25000000
+CONFIG_MEM_SIZE=64
+CONFIG_MEM_ADD_WIDTH=10
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Console UART Setup
+#
+# CONFIG_BAUD_9600 is not set
+# CONFIG_BAUD_19200 is not set
+# CONFIG_BAUD_38400 is not set
+CONFIG_BAUD_57600=y
+# CONFIG_BAUD_115200 is not set
+CONFIG_BAUD_NO_PARITY=y
+# CONFIG_BAUD_PARITY is not set
+CONFIG_BAUD_1_STOPBIT=y
+# CONFIG_BAUD_2_STOPBIT is not set
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Timer Tick
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_LARGE_ALLOCS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BLKFIN_CACHE=y
+CONFIG_BLKFIN_DCACHE=y
+# CONFIG_BLKFIN_CACHE_LOCK is not set
+# CONFIG_BLKFIN_WB is not set
+CONFIG_BLKFIN_WT=y
+CONFIG_L1_MAX_PIECE=16
+
+#
+# Clock Settings
+#
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMBCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR=y
+# CONFIG_PM_WAKEUP_BY_GPIO is not set
+# CONFIG_PM_WAKEUP_GPIO_API is not set
+CONFIG_PM_WAKEUP_SIC_IWR=0x80000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+# CONFIG_IRDA_FAST_RR is not set
+# CONFIG_IRDA_DEBUG is not set
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_MW320D=m
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=m
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_BF5xx=m
+CONFIG_BFIN_FLASH_SIZE=0x400000
+CONFIG_EBIU_FLASH_BASE=0x20000000
+
+#
+# FLASH_EBIU_AMBCTL Control
+#
+CONFIG_BFIN_FLASH_BANK_0=0x7BB0
+CONFIG_BFIN_FLASH_BANK_1=0x7BB0
+CONFIG_BFIN_FLASH_BANK_2=0x7BB0
+CONFIG_BFIN_FLASH_BANK_3=0x7BB0
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_BFIN=m
+CONFIG_BFIN_NAND_BASE=0x20212000
+CONFIG_BFIN_NAND_CLE=2
+CONFIG_BFIN_NAND_ALE=1
+CONFIG_BFIN_NAND_READY=3
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+CONFIG_BFIN_MAC=y
+CONFIG_BFIN_MAC_USE_L1=y
+CONFIG_BFIN_TX_DESC_NUM=10
+CONFIG_BFIN_RX_DESC_NUM=20
+# CONFIG_BFIN_MAC_RMII is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_BF53X_PFBUTTONS is not set
+CONFIG_TWI_KEYPAD=m
+CONFIG_BFIN_TWIKEYPAD_IRQ_PFX=72
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF533_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BF5xx_TIMERS is not set
+# CONFIG_BF5xx_PPI is not set
+CONFIG_BFIN_SPORT=y
+# CONFIG_BFIN_TIMER_LATENCY is not set
+CONFIG_TWI_LCD=m
+CONFIG_TWI_LCD_SLAVE_ADDR=34
+# CONFIG_AD5304 is not set
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+CONFIG_SERIAL_BFIN_DMA=y
+# CONFIG_SERIAL_BFIN_PIO is not set
+CONFIG_SERIAL_BFIN_UART0=y
+# CONFIG_BFIN_UART0_CTSRTS is not set
+# CONFIG_SERIAL_BFIN_UART1 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+CONFIG_CAN4LINUX=y
+
+#
+# linux embedded drivers
+#
+# CONFIG_CAN_MCF5282 is not set
+# CONFIG_CAN_UNCTWINCAN is not set
+CONFIG_CAN_BLACKFIN=m
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+CONFIG_BLACKFIN_DPMC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_BFIN_GPIO is not set
+CONFIG_I2C_BFIN_TWI=m
+CONFIG_TWICLK_KHZ=50
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+CONFIG_SENSORS_AD5252=m
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_BFIN=y
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=m
+CONFIG_FB_CFB_FILLRECT=m
+CONFIG_FB_CFB_COPYAREA=m
+CONFIG_FB_CFB_IMAGEBLIT=m
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+CONFIG_FB_BFIN_7171=m
+CONFIG_FB_BFIN_7393=m
+CONFIG_NTSC=y
+# CONFIG_PAL is not set
+# CONFIG_NTSC_640x480 is not set
+# CONFIG_PAL_640x480 is not set
+# CONFIG_NTSC_YCBCR is not set
+# CONFIG_PAL_YCBCR is not set
+CONFIG_ADV7393_1XMEM=y
+# CONFIG_ADV7393_2XMEM is not set
+CONFIG_FB_BF537_LQ035=m
+CONFIG_LQ035_SLAVE_ADDR=0x58
+# CONFIG_FB_BFIN_LANDSCAPE is not set
+# CONFIG_FB_BFIN_BGR is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_SPI_MMC is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+CONFIG_RTC_DRV_BFIN=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Virtualization
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_YAFFS_FS=m
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS=10
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+# CONFIG_BOOTPARAM is not set
+# CONFIG_NO_KERNEL_MSG is not set
+CONFIG_CPLB_INFO=y
+# CONFIG_NO_ACCESS_CHECK is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
new file mode 100644
index 00000000000..f3b7d2f9d49
--- /dev/null
+++ b/arch/blackfin/kernel/Makefile
@@ -0,0 +1,14 @@
+#
+# arch/blackfin/kernel/Makefile
+#
+
+extra-y := init_task.o vmlinux.lds
+
+obj-y := \
+ entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
+ sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \
+ flat.o
+
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
+obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
new file mode 100644
index 00000000000..e455f450450
--- /dev/null
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -0,0 +1,136 @@
+/*
+ * File: arch/blackfin/kernel/asm-offsets.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: generate definitions needed by assembly language modules.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <asm/irq.h>
+#include <asm/thread_info.h>
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+int main(void)
+{
+ /* offsets into the task struct */
+ DEFINE(TASK_STATE, offsetof(struct task_struct, state));
+ DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
+ DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
+ DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+ DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+ DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
+ DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+ DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
+ DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
+
+ /* offsets into the irq_cpustat_t struct */
+ DEFINE(CPUSTAT_SOFTIRQ_PENDING,
+ offsetof(irq_cpustat_t, __softirq_pending));
+
+ /* offsets into the thread struct */
+ DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+ DEFINE(THREAD_SR, offsetof(struct thread_struct, seqstat));
+ DEFINE(PT_SR, offsetof(struct thread_struct, seqstat));
+ DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+ DEFINE(THREAD_PC, offsetof(struct thread_struct, pc));
+ DEFINE(KERNEL_STACK_SIZE, THREAD_SIZE);
+
+ /* offsets into the pt_regs */
+ DEFINE(PT_ORIG_P0, offsetof(struct pt_regs, orig_p0));
+ DEFINE(PT_ORIG_PC, offsetof(struct pt_regs, orig_pc));
+ DEFINE(PT_R0, offsetof(struct pt_regs, r0));
+ DEFINE(PT_R1, offsetof(struct pt_regs, r1));
+ DEFINE(PT_R2, offsetof(struct pt_regs, r2));
+ DEFINE(PT_R3, offsetof(struct pt_regs, r3));
+ DEFINE(PT_R4, offsetof(struct pt_regs, r4));
+ DEFINE(PT_R5, offsetof(struct pt_regs, r5));
+ DEFINE(PT_R6, offsetof(struct pt_regs, r6));
+ DEFINE(PT_R7, offsetof(struct pt_regs, r7));
+
+ DEFINE(PT_P0, offsetof(struct pt_regs, p0));
+ DEFINE(PT_P1, offsetof(struct pt_regs, p1));
+ DEFINE(PT_P2, offsetof(struct pt_regs, p2));
+ DEFINE(PT_P3, offsetof(struct pt_regs, p3));
+ DEFINE(PT_P4, offsetof(struct pt_regs, p4));
+ DEFINE(PT_P5, offsetof(struct pt_regs, p5));
+
+ DEFINE(PT_FP, offsetof(struct pt_regs, fp));
+ DEFINE(PT_USP, offsetof(struct pt_regs, usp));
+ DEFINE(PT_I0, offsetof(struct pt_regs, i0));
+ DEFINE(PT_I1, offsetof(struct pt_regs, i1));
+ DEFINE(PT_I2, offsetof(struct pt_regs, i2));
+ DEFINE(PT_I3, offsetof(struct pt_regs, i3));
+ DEFINE(PT_M0, offsetof(struct pt_regs, m0));
+ DEFINE(PT_M1, offsetof(struct pt_regs, m1));
+ DEFINE(PT_M2, offsetof(struct pt_regs, m2));
+ DEFINE(PT_M3, offsetof(struct pt_regs, m3));
+ DEFINE(PT_L0, offsetof(struct pt_regs, l0));
+ DEFINE(PT_L1, offsetof(struct pt_regs, l1));
+ DEFINE(PT_L2, offsetof(struct pt_regs, l2));
+ DEFINE(PT_L3, offsetof(struct pt_regs, l3));
+ DEFINE(PT_B0, offsetof(struct pt_regs, b0));
+ DEFINE(PT_B1, offsetof(struct pt_regs, b1));
+ DEFINE(PT_B2, offsetof(struct pt_regs, b2));
+ DEFINE(PT_B3, offsetof(struct pt_regs, b3));
+ DEFINE(PT_A0X, offsetof(struct pt_regs, a0x));
+ DEFINE(PT_A0W, offsetof(struct pt_regs, a0w));
+ DEFINE(PT_A1X, offsetof(struct pt_regs, a1x));
+ DEFINE(PT_A1W, offsetof(struct pt_regs, a1w));
+ DEFINE(PT_LC0, offsetof(struct pt_regs, lc0));
+ DEFINE(PT_LC1, offsetof(struct pt_regs, lc1));
+ DEFINE(PT_LT0, offsetof(struct pt_regs, lt0));
+ DEFINE(PT_LT1, offsetof(struct pt_regs, lt1));
+ DEFINE(PT_LB0, offsetof(struct pt_regs, lb0));
+ DEFINE(PT_LB1, offsetof(struct pt_regs, lb1));
+ DEFINE(PT_ASTAT, offsetof(struct pt_regs, astat));
+ DEFINE(PT_RESERVED, offsetof(struct pt_regs, reserved));
+ DEFINE(PT_RETS, offsetof(struct pt_regs, rets));
+ DEFINE(PT_PC, offsetof(struct pt_regs, pc));
+ DEFINE(PT_RETX, offsetof(struct pt_regs, retx));
+ DEFINE(PT_RETN, offsetof(struct pt_regs, retn));
+ DEFINE(PT_RETE, offsetof(struct pt_regs, rete));
+ DEFINE(PT_SEQSTAT, offsetof(struct pt_regs, seqstat));
+ DEFINE(PT_SYSCFG, offsetof(struct pt_regs, syscfg));
+ DEFINE(PT_IPEND, offsetof(struct pt_regs, ipend));
+ DEFINE(SIZEOF_PTREGS, sizeof(struct pt_regs));
+ DEFINE(PT_TEXT_ADDR, sizeof(struct pt_regs)); /* Needed by gdb */
+ DEFINE(PT_TEXT_END_ADDR, 4 + sizeof(struct pt_regs));/* Needed by gdb */
+ DEFINE(PT_DATA_ADDR, 8 + sizeof(struct pt_regs)); /* Needed by gdb */
+ DEFINE(PT_FDPIC_EXEC, 12 + sizeof(struct pt_regs)); /* Needed by gdb */
+ DEFINE(PT_FDPIC_INTERP, 16 + sizeof(struct pt_regs));/* Needed by gdb */
+
+ /* signal defines */
+ DEFINE(SIGSEGV, SIGSEGV);
+ DEFINE(SIGTRAP, SIGTRAP);
+
+ return 0;
+}
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
new file mode 100644
index 00000000000..8ea079ebecb
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -0,0 +1,742 @@
+/*
+ * File: arch/blackfin/kernel/bfin_dma_5xx.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+/* Remove unused code not exported by symbol or internally called */
+#define REMOVE_DEAD_CODE
+
+/**************************************************************************
+ * Global Variables
+***************************************************************************/
+
+static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL];
+#if defined (CONFIG_BF561)
+static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+ (struct dma_register *) DMA1_0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_7_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_11_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_7_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_11_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
+};
+#else
+static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+ (struct dma_register *) DMA0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA7_NEXT_DESC_PTR,
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
+ (struct dma_register *) DMA8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA11_NEXT_DESC_PTR,
+#endif
+ (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
+};
+#endif
+
+/*------------------------------------------------------------------------------
+ * Set the Buffer Clear bit in the Configuration register of specific DMA
+ * channel. This will stop the descriptor based DMA operation.
+ *-----------------------------------------------------------------------------*/
+static void clear_dma_buffer(unsigned int channel)
+{
+ dma_ch[channel].regs->cfg |= RESTART;
+ SSYNC();
+ dma_ch[channel].regs->cfg &= ~RESTART;
+ SSYNC();
+}
+
+int __init blackfin_dma_init(void)
+{
+ int i;
+
+ printk(KERN_INFO "Blackfin DMA Controller\n");
+
+ for (i = 0; i < MAX_BLACKFIN_DMA_CHANNEL; i++) {
+ dma_ch[i].chan_status = DMA_CHANNEL_FREE;
+ dma_ch[i].regs = base_addr[i];
+ mutex_init(&(dma_ch[i].dmalock));
+ }
+
+ return 0;
+}
+
+arch_initcall(blackfin_dma_init);
+
+/*
+ * Form the channel find the irq number for that channel.
+ */
+#if !defined(CONFIG_BF561)
+
+static int bf533_channel2irq(unsigned int channel)
+{
+ int ret_irq = -1;
+
+ switch (channel) {
+ case CH_PPI:
+ ret_irq = IRQ_PPI;
+ break;
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
+ case CH_EMAC_RX:
+ ret_irq = IRQ_MAC_RX;
+ break;
+
+ case CH_EMAC_TX:
+ ret_irq = IRQ_MAC_TX;
+ break;
+
+ case CH_UART1_RX:
+ ret_irq = IRQ_UART1_RX;
+ break;
+
+ case CH_UART1_TX:
+ ret_irq = IRQ_UART1_TX;
+ break;
+#endif
+
+ case CH_SPORT0_RX:
+ ret_irq = IRQ_SPORT0_RX;
+ break;
+
+ case CH_SPORT0_TX:
+ ret_irq = IRQ_SPORT0_TX;
+ break;
+
+ case CH_SPORT1_RX:
+ ret_irq = IRQ_SPORT1_RX;
+ break;
+
+ case CH_SPORT1_TX:
+ ret_irq = IRQ_SPORT1_TX;
+ break;
+
+ case CH_SPI:
+ ret_irq = IRQ_SPI;
+ break;
+
+ case CH_UART_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+
+ case CH_UART_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+
+ case CH_MEM_STREAM0_SRC:
+ case CH_MEM_STREAM0_DEST:
+ ret_irq = IRQ_MEM_DMA0;
+ break;
+
+ case CH_MEM_STREAM1_SRC:
+ case CH_MEM_STREAM1_DEST:
+ ret_irq = IRQ_MEM_DMA1;
+ break;
+ }
+ return ret_irq;
+}
+
+# define channel2irq(channel) bf533_channel2irq(channel)
+
+#else
+
+static int bf561_channel2irq(unsigned int channel)
+{
+ int ret_irq = -1;
+
+ switch (channel) {
+ case CH_PPI0:
+ ret_irq = IRQ_PPI0;
+ break;
+ case CH_PPI1:
+ ret_irq = IRQ_PPI1;
+ break;
+ case CH_SPORT0_RX:
+ ret_irq = IRQ_SPORT0_RX;
+ break;
+ case CH_SPORT0_TX:
+ ret_irq = IRQ_SPORT0_TX;
+ break;
+ case CH_SPORT1_RX:
+ ret_irq = IRQ_SPORT1_RX;
+ break;
+ case CH_SPORT1_TX:
+ ret_irq = IRQ_SPORT1_TX;
+ break;
+ case CH_SPI:
+ ret_irq = IRQ_SPI;
+ break;
+ case CH_UART_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+ case CH_UART_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+
+ case CH_MEM_STREAM0_SRC:
+ case CH_MEM_STREAM0_DEST:
+ ret_irq = IRQ_MEM_DMA0;
+ break;
+ case CH_MEM_STREAM1_SRC:
+ case CH_MEM_STREAM1_DEST:
+ ret_irq = IRQ_MEM_DMA1;
+ break;
+ case CH_MEM_STREAM2_SRC:
+ case CH_MEM_STREAM2_DEST:
+ ret_irq = IRQ_MEM_DMA2;
+ break;
+ case CH_MEM_STREAM3_SRC:
+ case CH_MEM_STREAM3_DEST:
+ ret_irq = IRQ_MEM_DMA3;
+ break;
+
+ case CH_IMEM_STREAM0_SRC:
+ case CH_IMEM_STREAM0_DEST:
+ ret_irq = IRQ_IMEM_DMA0;
+ break;
+ case CH_IMEM_STREAM1_SRC:
+ case CH_IMEM_STREAM1_DEST:
+ ret_irq = IRQ_IMEM_DMA1;
+ break;
+ }
+ return ret_irq;
+}
+
+# define channel2irq(channel) bf561_channel2irq(channel)
+
+#endif
+
+/*------------------------------------------------------------------------------
+ * Request the specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+int request_dma(unsigned int channel, char *device_id)
+{
+
+ pr_debug("request_dma() : BEGIN \n");
+ mutex_lock(&(dma_ch[channel].dmalock));
+
+ if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
+ || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
+ mutex_unlock(&(dma_ch[channel].dmalock));
+ pr_debug("DMA CHANNEL IN USE \n");
+ return -EBUSY;
+ } else {
+ dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
+ pr_debug("DMA CHANNEL IS ALLOCATED \n");
+ }
+
+ mutex_unlock(&(dma_ch[channel].dmalock));
+
+ dma_ch[channel].device_id = device_id;
+ dma_ch[channel].irq_callback = NULL;
+
+ /* This is to be enabled by putting a restriction -
+ * you have to request DMA, before doing any operations on
+ * descriptor/channel
+ */
+ pr_debug("request_dma() : END \n");
+ return channel;
+}
+EXPORT_SYMBOL(request_dma);
+
+int set_dma_callback(unsigned int channel, dma_interrupt_t callback, void *data)
+{
+ int ret_irq = 0;
+
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ if (callback != NULL) {
+ int ret_val;
+ ret_irq = channel2irq(channel);
+
+ dma_ch[channel].data = data;
+
+ ret_val =
+ request_irq(ret_irq, (void *)callback, IRQF_DISABLED,
+ dma_ch[channel].device_id, data);
+ if (ret_val) {
+ printk(KERN_NOTICE
+ "Request irq in DMA engine failed.\n");
+ return -EPERM;
+ }
+ dma_ch[channel].irq_callback = callback;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(set_dma_callback);
+
+void free_dma(unsigned int channel)
+{
+ int ret_irq;
+
+ pr_debug("freedma() : BEGIN \n");
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ /* Halt the DMA */
+ disable_dma(channel);
+ clear_dma_buffer(channel);
+
+ if (dma_ch[channel].irq_callback != NULL) {
+ ret_irq = channel2irq(channel);
+ free_irq(ret_irq, dma_ch[channel].data);
+ }
+
+ /* Clear the DMA Variable in the Channel */
+ mutex_lock(&(dma_ch[channel].dmalock));
+ dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
+ mutex_unlock(&(dma_ch[channel].dmalock));
+
+ pr_debug("freedma() : END \n");
+}
+EXPORT_SYMBOL(free_dma);
+
+void dma_enable_irq(unsigned int channel)
+{
+ int ret_irq;
+
+ pr_debug("dma_enable_irq() : BEGIN \n");
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ ret_irq = channel2irq(channel);
+ enable_irq(ret_irq);
+}
+EXPORT_SYMBOL(dma_enable_irq);
+
+void dma_disable_irq(unsigned int channel)
+{
+ int ret_irq;
+
+ pr_debug("dma_disable_irq() : BEGIN \n");
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ ret_irq = channel2irq(channel);
+ disable_irq(ret_irq);
+}
+EXPORT_SYMBOL(dma_disable_irq);
+
+int dma_channel_active(unsigned int channel)
+{
+ if (dma_ch[channel].chan_status == DMA_CHANNEL_FREE) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+EXPORT_SYMBOL(dma_channel_active);
+
+/*------------------------------------------------------------------------------
+* stop the specific DMA channel.
+*-----------------------------------------------------------------------------*/
+void disable_dma(unsigned int channel)
+{
+ pr_debug("stop_dma() : BEGIN \n");
+
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->cfg &= ~DMAEN; /* Clean the enable bit */
+ SSYNC();
+ dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
+ /* Needs to be enabled Later */
+ pr_debug("stop_dma() : END \n");
+ return;
+}
+EXPORT_SYMBOL(disable_dma);
+
+void enable_dma(unsigned int channel)
+{
+ pr_debug("enable_dma() : BEGIN \n");
+
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].chan_status = DMA_CHANNEL_ENABLED;
+ dma_ch[channel].regs->curr_x_count = 0;
+ dma_ch[channel].regs->curr_y_count = 0;
+
+ dma_ch[channel].regs->cfg |= DMAEN; /* Set the enable bit */
+ SSYNC();
+ pr_debug("enable_dma() : END \n");
+ return;
+}
+EXPORT_SYMBOL(enable_dma);
+
+/*------------------------------------------------------------------------------
+* Set the Start Address register for the specific DMA channel
+* This function can be used for register based DMA,
+* to setup the start address
+* addr: Starting address of the DMA Data to be transferred.
+*-----------------------------------------------------------------------------*/
+void set_dma_start_addr(unsigned int channel, unsigned long addr)
+{
+ pr_debug("set_dma_start_addr() : BEGIN \n");
+
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->start_addr = addr;
+ SSYNC();
+ pr_debug("set_dma_start_addr() : END\n");
+}
+EXPORT_SYMBOL(set_dma_start_addr);
+
+void set_dma_next_desc_addr(unsigned int channel, unsigned long addr)
+{
+ pr_debug("set_dma_next_desc_addr() : BEGIN \n");
+
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->next_desc_ptr = addr;
+ SSYNC();
+ pr_debug("set_dma_start_addr() : END\n");
+}
+EXPORT_SYMBOL(set_dma_next_desc_addr);
+
+void set_dma_x_count(unsigned int channel, unsigned short x_count)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->x_count = x_count;
+ SSYNC();
+}
+EXPORT_SYMBOL(set_dma_x_count);
+
+void set_dma_y_count(unsigned int channel, unsigned short y_count)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->y_count = y_count;
+ SSYNC();
+}
+EXPORT_SYMBOL(set_dma_y_count);
+
+void set_dma_x_modify(unsigned int channel, short x_modify)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->x_modify = x_modify;
+ SSYNC();
+}
+EXPORT_SYMBOL(set_dma_x_modify);
+
+void set_dma_y_modify(unsigned int channel, short y_modify)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->y_modify = y_modify;
+ SSYNC();
+}
+EXPORT_SYMBOL(set_dma_y_modify);
+
+void set_dma_config(unsigned int channel, unsigned short config)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->cfg = config;
+ SSYNC();
+}
+EXPORT_SYMBOL(set_dma_config);
+
+unsigned short
+set_bfin_dma_config(char direction, char flow_mode,
+ char intr_mode, char dma_mode, char width)
+{
+ unsigned short config;
+
+ config =
+ ((direction << 1) | (width << 2) | (dma_mode << 4) |
+ (intr_mode << 6) | (flow_mode << 12) | RESTART);
+ return config;
+}
+EXPORT_SYMBOL(set_bfin_dma_config);
+
+void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ dma_ch[channel].regs->cfg |= ((nr_sg & 0x0F) << 8);
+
+ dma_ch[channel].regs->next_desc_ptr = (unsigned int)sg;
+
+ SSYNC();
+}
+EXPORT_SYMBOL(set_dma_sg);
+
+/*------------------------------------------------------------------------------
+ * Get the DMA status of a specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+unsigned short get_dma_curr_irqstat(unsigned int channel)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ return dma_ch[channel].regs->irq_status;
+}
+EXPORT_SYMBOL(get_dma_curr_irqstat);
+
+/*------------------------------------------------------------------------------
+ * Clear the DMA_DONE bit in DMA status. Stop the DMA completion interrupt.
+ *-----------------------------------------------------------------------------*/
+void clear_dma_irqstat(unsigned int channel)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+ dma_ch[channel].regs->irq_status |= 3;
+}
+EXPORT_SYMBOL(clear_dma_irqstat);
+
+/*------------------------------------------------------------------------------
+ * Get current DMA xcount of a specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+unsigned short get_dma_curr_xcount(unsigned int channel)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ return dma_ch[channel].regs->curr_x_count;
+}
+EXPORT_SYMBOL(get_dma_curr_xcount);
+
+/*------------------------------------------------------------------------------
+ * Get current DMA ycount of a specific DMA channel from the system.
+ *-----------------------------------------------------------------------------*/
+unsigned short get_dma_curr_ycount(unsigned int channel)
+{
+ BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
+ && channel < MAX_BLACKFIN_DMA_CHANNEL));
+
+ return dma_ch[channel].regs->curr_y_count;
+}
+EXPORT_SYMBOL(get_dma_curr_ycount);
+
+void *dma_memcpy(void *dest, const void *src, size_t size)
+{
+ int direction; /* 1 - address decrease, 0 - address increase */
+ int flag_align; /* 1 - address aligned, 0 - address unaligned */
+ int flag_2D; /* 1 - 2D DMA needed, 0 - 1D DMA needed */
+
+ if (size <= 0)
+ return NULL;
+
+ if ((unsigned long)src < memory_end)
+ blackfin_dcache_flush_range((unsigned int)src,
+ (unsigned int)(src + size));
+
+ bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
+
+ if ((unsigned long)src < (unsigned long)dest)
+ direction = 1;
+ else
+ direction = 0;
+
+ if ((((unsigned long)dest % 2) == 0) && (((unsigned long)src % 2) == 0)
+ && ((size % 2) == 0))
+ flag_align = 1;
+ else
+ flag_align = 0;
+
+ if (size > 0x10000) /* size > 64K */
+ flag_2D = 1;
+ else
+ flag_2D = 0;
+
+ /* Setup destination and source start address */
+ if (direction) {
+ if (flag_align) {
+ bfin_write_MDMA_D0_START_ADDR(dest + size - 2);
+ bfin_write_MDMA_S0_START_ADDR(src + size - 2);
+ } else {
+ bfin_write_MDMA_D0_START_ADDR(dest + size - 1);
+ bfin_write_MDMA_S0_START_ADDR(src + size - 1);
+ }
+ } else {
+ bfin_write_MDMA_D0_START_ADDR(dest);
+ bfin_write_MDMA_S0_START_ADDR(src);
+ }
+
+ /* Setup destination and source xcount */
+ if (flag_2D) {
+ if (flag_align) {
+ bfin_write_MDMA_D0_X_COUNT(1024 / 2);
+ bfin_write_MDMA_S0_X_COUNT(1024 / 2);
+ } else {
+ bfin_write_MDMA_D0_X_COUNT(1024);
+ bfin_write_MDMA_S0_X_COUNT(1024);
+ }
+ bfin_write_MDMA_D0_Y_COUNT(size >> 10);
+ bfin_write_MDMA_S0_Y_COUNT(size >> 10);
+ } else {
+ if (flag_align) {
+ bfin_write_MDMA_D0_X_COUNT(size / 2);
+ bfin_write_MDMA_S0_X_COUNT(size / 2);
+ } else {
+ bfin_write_MDMA_D0_X_COUNT(size);
+ bfin_write_MDMA_S0_X_COUNT(size);
+ }
+ }
+
+ /* Setup destination and source xmodify and ymodify */
+ if (direction) {
+ if (flag_align) {
+ bfin_write_MDMA_D0_X_MODIFY(-2);
+ bfin_write_MDMA_S0_X_MODIFY(-2);
+ if (flag_2D) {
+ bfin_write_MDMA_D0_Y_MODIFY(-2);
+ bfin_write_MDMA_S0_Y_MODIFY(-2);
+ }
+ } else {
+ bfin_write_MDMA_D0_X_MODIFY(-1);
+ bfin_write_MDMA_S0_X_MODIFY(-1);
+ if (flag_2D) {
+ bfin_write_MDMA_D0_Y_MODIFY(-1);
+ bfin_write_MDMA_S0_Y_MODIFY(-1);
+ }
+ }
+ } else {
+ if (flag_align) {
+ bfin_write_MDMA_D0_X_MODIFY(2);
+ bfin_write_MDMA_S0_X_MODIFY(2);
+ if (flag_2D) {
+ bfin_write_MDMA_D0_Y_MODIFY(2);
+ bfin_write_MDMA_S0_Y_MODIFY(2);
+ }
+ } else {
+ bfin_write_MDMA_D0_X_MODIFY(1);
+ bfin_write_MDMA_S0_X_MODIFY(1);
+ if (flag_2D) {
+ bfin_write_MDMA_D0_Y_MODIFY(1);
+ bfin_write_MDMA_S0_Y_MODIFY(1);
+ }
+ }
+ }
+
+ /* Enable source DMA */
+ if (flag_2D) {
+ if (flag_align) {
+ bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D | WDSIZE_16);
+ bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D | WDSIZE_16);
+ } else {
+ bfin_write_MDMA_S0_CONFIG(DMAEN | DMA2D);
+ bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | DMA2D);
+ }
+ } else {
+ if (flag_align) {
+ bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16);
+ bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16);
+ } else {
+ bfin_write_MDMA_S0_CONFIG(DMAEN);
+ bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN);
+ }
+ }
+
+ while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE))
+ ;
+
+ bfin_write_MDMA_D0_IRQ_STATUS(bfin_read_MDMA_D0_IRQ_STATUS() |
+ (DMA_DONE | DMA_ERR));
+
+ bfin_write_MDMA_S0_CONFIG(0);
+ bfin_write_MDMA_D0_CONFIG(0);
+
+ if ((unsigned long)dest < memory_end)
+ blackfin_dcache_invalidate_range((unsigned int)dest,
+ (unsigned int)(dest + size));
+
+ return dest;
+}
+EXPORT_SYMBOL(dma_memcpy);
+
+void *safe_dma_memcpy(void *dest, const void *src, size_t size)
+{
+ int flags = 0;
+ void *addr;
+ local_irq_save(flags);
+ addr = dma_memcpy(dest, src, size);
+ local_irq_restore(flags);
+ return addr;
+}
+EXPORT_SYMBOL(safe_dma_memcpy);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
new file mode 100644
index 00000000000..e9f24a9a46b
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -0,0 +1,637 @@
+/*
+ * File: arch/blackfin/kernel/bfin_gpio.c
+ * Based on:
+ * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Created:
+ * Description: GPIO Abstraction Layer
+ *
+ * Modified:
+ * Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+* Number BF537/6/4 BF561 BF533/2/1
+*
+* GPIO_0 PF0 PF0 PF0
+* GPIO_1 PF1 PF1 PF1
+* GPIO_2 PF2 PF2 PF2
+* GPIO_3 PF3 PF3 PF3
+* GPIO_4 PF4 PF4 PF4
+* GPIO_5 PF5 PF5 PF5
+* GPIO_6 PF6 PF6 PF6
+* GPIO_7 PF7 PF7 PF7
+* GPIO_8 PF8 PF8 PF8
+* GPIO_9 PF9 PF9 PF9
+* GPIO_10 PF10 PF10 PF10
+* GPIO_11 PF11 PF11 PF11
+* GPIO_12 PF12 PF12 PF12
+* GPIO_13 PF13 PF13 PF13
+* GPIO_14 PF14 PF14 PF14
+* GPIO_15 PF15 PF15 PF15
+* GPIO_16 PG0 PF16
+* GPIO_17 PG1 PF17
+* GPIO_18 PG2 PF18
+* GPIO_19 PG3 PF19
+* GPIO_20 PG4 PF20
+* GPIO_21 PG5 PF21
+* GPIO_22 PG6 PF22
+* GPIO_23 PG7 PF23
+* GPIO_24 PG8 PF24
+* GPIO_25 PG9 PF25
+* GPIO_26 PG10 PF26
+* GPIO_27 PG11 PF27
+* GPIO_28 PG12 PF28
+* GPIO_29 PG13 PF29
+* GPIO_30 PG14 PF30
+* GPIO_31 PG15 PF31
+* GPIO_32 PH0 PF32
+* GPIO_33 PH1 PF33
+* GPIO_34 PH2 PF34
+* GPIO_35 PH3 PF35
+* GPIO_36 PH4 PF36
+* GPIO_37 PH5 PF37
+* GPIO_38 PH6 PF38
+* GPIO_39 PH7 PF39
+* GPIO_40 PH8 PF40
+* GPIO_41 PH9 PF41
+* GPIO_42 PH10 PF42
+* GPIO_43 PH11 PF43
+* GPIO_44 PH12 PF44
+* GPIO_45 PH13 PF45
+* GPIO_46 PH14 PF46
+* GPIO_47 PH15 PF47
+*/
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <linux/irq.h>
+
+#ifdef BF533_FAMILY
+static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ (struct gpio_port_t *) FIO_FLAG_D,
+};
+#endif
+
+#ifdef BF537_FAMILY
+static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ (struct gpio_port_t *) PORTFIO,
+ (struct gpio_port_t *) PORTGIO,
+ (struct gpio_port_t *) PORTHIO,
+};
+
+static unsigned short *port_fer[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ (unsigned short *) PORTF_FER,
+ (unsigned short *) PORTG_FER,
+ (unsigned short *) PORTH_FER,
+};
+
+#endif
+
+#ifdef BF561_FAMILY
+static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ (struct gpio_port_t *) FIO0_FLAG_D,
+ (struct gpio_port_t *) FIO1_FLAG_D,
+ (struct gpio_port_t *) FIO2_FLAG_D,
+};
+#endif
+
+static unsigned short reserved_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+#ifdef CONFIG_PM
+static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned char wakeup_flags_map[MAX_BLACKFIN_GPIOS];
+static struct gpio_port_s gpio_bank_saved[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+#ifdef BF533_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB};
+#endif
+
+#ifdef BF537_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX};
+#endif
+
+#ifdef BF561_FAMILY
+static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB};
+#endif
+
+#endif /* CONFIG_PM */
+
+inline int check_gpio(unsigned short gpio)
+{
+ if (gpio > MAX_BLACKFIN_GPIOS)
+ return -EINVAL;
+ return 0;
+}
+
+#ifdef BF537_FAMILY
+void port_setup(unsigned short gpio, unsigned short usage)
+{
+ if (usage == GPIO_USAGE) {
+ if (*port_fer[gpio_bank(gpio)] & gpio_bit(gpio))
+ printk(KERN_WARNING "bfin-gpio: Possible Conflict with Peripheral "
+ "usage and GPIO %d detected!\n", gpio);
+ *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+ } else
+ *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
+ SSYNC();
+}
+#else
+# define port_setup(...) do { } while (0)
+#endif
+
+
+void default_gpio(unsigned short gpio)
+{
+ unsigned short bank,bitmask;
+
+ bank = gpio_bank(gpio);
+ bitmask = gpio_bit(gpio);
+
+ gpio_bankb[bank]->maska_clear = bitmask;
+ gpio_bankb[bank]->maskb_clear = bitmask;
+ SSYNC();
+ gpio_bankb[bank]->inen &= ~bitmask;
+ gpio_bankb[bank]->dir &= ~bitmask;
+ gpio_bankb[bank]->polar &= ~bitmask;
+ gpio_bankb[bank]->both &= ~bitmask;
+ gpio_bankb[bank]->edge &= ~bitmask;
+}
+
+
+int __init bfin_gpio_init(void)
+{
+ int i;
+
+ printk(KERN_INFO "Blackfin GPIO Controller\n");
+
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE)
+ reserved_map[gpio_bank(i)] = 0;
+
+#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
+# if defined(CONFIG_BFIN_MAC_RMII)
+ reserved_map[PORT_H] = 0xC373;
+# else
+ reserved_map[PORT_H] = 0xFFFF;
+# endif
+#endif
+
+ return 0;
+}
+
+arch_initcall(bfin_gpio_init);
+
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin General Purpose Ports Access Functions
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: These functions abstract direct register access
+* to Blackfin processor General Purpose
+* Ports Regsiters
+*
+* CAUTION: These functions do not belong to the GPIO Driver API
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+/* Set a specific bit */
+
+#define SET_GPIO(name) \
+void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+ unsigned long flags; \
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ local_irq_save(flags); \
+ if (arg) \
+ gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
+ else \
+ gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
+ local_irq_restore(flags); \
+} \
+EXPORT_SYMBOL(set_gpio_ ## name);
+
+SET_GPIO(dir)
+SET_GPIO(inen)
+SET_GPIO(polar)
+SET_GPIO(edge)
+SET_GPIO(both)
+
+
+#define SET_GPIO_SC(name) \
+void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))); \
+ if (arg) \
+ gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
+ else \
+ gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
+} \
+EXPORT_SYMBOL(set_gpio_ ## name);
+
+SET_GPIO_SC(maska)
+SET_GPIO_SC(maskb)
+
+#if defined(ANOMALY_05000311)
+void set_gpio_data(unsigned short gpio, unsigned short arg)
+{
+ unsigned long flags;
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ local_irq_save(flags);
+ if (arg)
+ gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio);
+ else
+ gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio);
+ bfin_read_CHIPID();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(set_gpio_data);
+#else
+SET_GPIO_SC(data)
+#endif
+
+
+#if defined(ANOMALY_05000311)
+void set_gpio_toggle(unsigned short gpio)
+{
+ unsigned long flags;
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ local_irq_save(flags);
+ gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
+ bfin_read_CHIPID();
+ local_irq_restore(flags);
+}
+#else
+void set_gpio_toggle(unsigned short gpio)
+{
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
+}
+#endif
+EXPORT_SYMBOL(set_gpio_toggle);
+
+
+/*Set current PORT date (16-bit word)*/
+
+#define SET_GPIO_P(name) \
+void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \
+{ \
+ gpio_bankb[gpio_bank(gpio)]->name = arg; \
+} \
+EXPORT_SYMBOL(set_gpiop_ ## name);
+
+SET_GPIO_P(dir)
+SET_GPIO_P(inen)
+SET_GPIO_P(polar)
+SET_GPIO_P(edge)
+SET_GPIO_P(both)
+SET_GPIO_P(maska)
+SET_GPIO_P(maskb)
+
+
+#if defined(ANOMALY_05000311)
+void set_gpiop_data(unsigned short gpio, unsigned short arg)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ gpio_bankb[gpio_bank(gpio)]->data = arg;
+ bfin_read_CHIPID();
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(set_gpiop_data);
+#else
+SET_GPIO_P(data)
+#endif
+
+
+
+/* Get a specific bit */
+
+#define GET_GPIO(name) \
+unsigned short get_gpio_ ## name(unsigned short gpio) \
+{ \
+ return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \
+} \
+EXPORT_SYMBOL(get_gpio_ ## name);
+
+GET_GPIO(dir)
+GET_GPIO(inen)
+GET_GPIO(polar)
+GET_GPIO(edge)
+GET_GPIO(both)
+GET_GPIO(maska)
+GET_GPIO(maskb)
+
+
+#if defined(ANOMALY_05000311)
+unsigned short get_gpio_data(unsigned short gpio)
+{
+ unsigned long flags;
+ unsigned short ret;
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+ local_irq_save(flags);
+ ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio));
+ bfin_read_CHIPID();
+ local_irq_restore(flags);
+ return ret;
+}
+EXPORT_SYMBOL(get_gpio_data);
+#else
+GET_GPIO(data)
+#endif
+
+/*Get current PORT date (16-bit word)*/
+
+#define GET_GPIO_P(name) \
+unsigned short get_gpiop_ ## name(unsigned short gpio) \
+{ \
+ return (gpio_bankb[gpio_bank(gpio)]->name);\
+} \
+EXPORT_SYMBOL(get_gpiop_ ## name);
+
+GET_GPIO_P(dir)
+GET_GPIO_P(inen)
+GET_GPIO_P(polar)
+GET_GPIO_P(edge)
+GET_GPIO_P(both)
+GET_GPIO_P(maska)
+GET_GPIO_P(maskb)
+
+#if defined(ANOMALY_05000311)
+unsigned short get_gpiop_data(unsigned short gpio)
+{
+ unsigned long flags;
+ unsigned short ret;
+ local_irq_save(flags);
+ ret = gpio_bankb[gpio_bank(gpio)]->data;
+ bfin_read_CHIPID();
+ local_irq_restore(flags);
+ return ret;
+}
+EXPORT_SYMBOL(get_gpiop_data);
+#else
+GET_GPIO_P(data)
+#endif
+
+#ifdef CONFIG_PM
+/***********************************************************
+*
+* FUNCTIONS: Blackfin PM Setup API
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+* type -
+* PM_WAKE_RISING
+* PM_WAKE_FALLING
+* PM_WAKE_HIGH
+* PM_WAKE_LOW
+* PM_WAKE_BOTH_EDGES
+*
+* DESCRIPTION: Blackfin PM Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type)
+{
+ unsigned long flags;
+
+ if ((check_gpio(gpio) < 0) || !type)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+ wakeup_flags_map[gpio] = type;
+ local_irq_restore(flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_pm_wakeup_request);
+
+void gpio_pm_wakeup_free(unsigned short gpio)
+{
+ unsigned long flags;
+
+ if (check_gpio(gpio) < 0)
+ return;
+
+ local_irq_save(flags);
+
+ wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_pm_wakeup_free);
+
+static int bfin_gpio_wakeup_type(unsigned short gpio, unsigned char type)
+{
+ port_setup(gpio, GPIO_USAGE);
+ set_gpio_dir(gpio, 0);
+ set_gpio_inen(gpio, 1);
+
+ if (type & (PM_WAKE_RISING | PM_WAKE_FALLING))
+ set_gpio_edge(gpio, 1);
+ else
+ set_gpio_edge(gpio, 0);
+
+ if ((type & (PM_WAKE_BOTH_EDGES)) == (PM_WAKE_BOTH_EDGES))
+ set_gpio_both(gpio, 1);
+ else
+ set_gpio_both(gpio, 0);
+
+ if ((type & (PM_WAKE_FALLING | PM_WAKE_LOW)))
+ set_gpio_polar(gpio, 1);
+ else
+ set_gpio_polar(gpio, 0);
+
+ SSYNC();
+
+ return 0;
+}
+
+u32 gpio_pm_setup(void)
+{
+ u32 sic_iwr = 0;
+ u16 bank, mask, i, gpio;
+
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
+ mask = wakeup_map[gpio_bank(i)];
+ bank = gpio_bank(i);
+
+ gpio_bank_saved[bank].maskb = gpio_bankb[bank]->maskb;
+ gpio_bankb[bank]->maskb = 0;
+
+ if (mask) {
+#ifdef BF537_FAMILY
+ gpio_bank_saved[bank].fer = *port_fer[bank];
+#endif
+ gpio_bank_saved[bank].inen = gpio_bankb[bank]->inen;
+ gpio_bank_saved[bank].polar = gpio_bankb[bank]->polar;
+ gpio_bank_saved[bank].dir = gpio_bankb[bank]->dir;
+ gpio_bank_saved[bank].edge = gpio_bankb[bank]->edge;
+ gpio_bank_saved[bank].both = gpio_bankb[bank]->both;
+
+ gpio = i;
+
+ while (mask) {
+ if (mask & 1) {
+ bfin_gpio_wakeup_type(gpio, wakeup_flags_map[gpio]);
+ set_gpio_data(gpio, 0); /*Clear*/
+ }
+ gpio++;
+ mask >>= 1;
+ }
+
+ sic_iwr |= 1 << (sic_iwr_irqs[bank] - (IRQ_CORETMR + 1));
+ gpio_bankb[bank]->maskb_set = wakeup_map[gpio_bank(i)];
+ }
+ }
+
+ if (sic_iwr)
+ return sic_iwr;
+ else
+ return IWR_ENABLE_ALL;
+}
+
+
+void gpio_pm_restore(void)
+{
+ u16 bank, mask, i;
+
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
+ mask = wakeup_map[gpio_bank(i)];
+ bank = gpio_bank(i);
+
+ if (mask) {
+#ifdef BF537_FAMILY
+ *port_fer[bank] = gpio_bank_saved[bank].fer;
+#endif
+ gpio_bankb[bank]->inen = gpio_bank_saved[bank].inen;
+ gpio_bankb[bank]->dir = gpio_bank_saved[bank].dir;
+ gpio_bankb[bank]->polar = gpio_bank_saved[bank].polar;
+ gpio_bankb[bank]->edge = gpio_bank_saved[bank].edge;
+ gpio_bankb[bank]->both = gpio_bank_saved[bank].both;
+ }
+
+ gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb;
+ }
+}
+
+#endif
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: Blackfin GPIO Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+int gpio_request(unsigned short gpio, const char *label)
+{
+ unsigned long flags;
+
+ if (check_gpio(gpio) < 0)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (unlikely(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+ printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+ reserved_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+
+ local_irq_restore(flags);
+
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+
+void gpio_free(unsigned short gpio)
+{
+ unsigned long flags;
+
+ if (check_gpio(gpio) < 0)
+ return;
+
+ local_irq_save(flags);
+
+ if (unlikely(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+ printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
+ dump_stack();
+ local_irq_restore(flags);
+ return;
+ }
+
+ default_gpio(gpio);
+
+ reserved_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_free);
+
+
+void gpio_direction_input(unsigned short gpio)
+{
+ unsigned long flags;
+
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+ local_irq_save(flags);
+ gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio);
+ gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+void gpio_direction_output(unsigned short gpio)
+{
+ unsigned long flags;
+
+ BUG_ON(!(reserved_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+ local_irq_save(flags);
+ gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
+ gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_output);
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
new file mode 100644
index 00000000000..f64ecb638fa
--- /dev/null
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -0,0 +1,119 @@
+/*
+ * File: arch/blackfin/kernel/bfin_ksyms.c
+ * Based on: none - original work
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <asm/irq.h>
+#include <asm/checksum.h>
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+
+/* platform dependent support */
+
+EXPORT_SYMBOL(__ioremap);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(dump_thread);
+
+EXPORT_SYMBOL(ip_fast_csum);
+
+EXPORT_SYMBOL(kernel_thread);
+
+EXPORT_SYMBOL(__up);
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(is_in_rom);
+
+/* Networking helper routines. */
+EXPORT_SYMBOL(csum_partial_copy);
+
+/* The following are special because they're not called
+ * explicitly (the C compiler generates them). Fortunately,
+ * their interface isn't gonna change any time soon now, so
+ * it's OK to leave it out of version control.
+ */
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(get_wchan);
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler... (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+extern void __ashldi3(void);
+extern void __ashrdi3(void);
+extern void __smulsi3_highpart(void);
+extern void __umulsi3_highpart(void);
+extern void __divsi3(void);
+extern void __lshrdi3(void);
+extern void __modsi3(void);
+extern void __muldi3(void);
+extern void __udivsi3(void);
+extern void __umodsi3(void);
+
+/* gcc lib functions */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__umulsi3_highpart);
+EXPORT_SYMBOL(__smulsi3_highpart);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(irq_flags);
+EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(blackfin_dcache_invalidate_range);
+EXPORT_SYMBOL(blackfin_icache_dcache_flush_range);
+EXPORT_SYMBOL(blackfin_icache_flush_range);
+EXPORT_SYMBOL(blackfin_dcache_flush_range);
+EXPORT_SYMBOL(blackfin_dflush_page);
+
+EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(__init_begin);
+EXPORT_SYMBOL(__init_end);
+EXPORT_SYMBOL(_ebss_l1);
+EXPORT_SYMBOL(_stext_l1);
+EXPORT_SYMBOL(_etext_l1);
+EXPORT_SYMBOL(_sdata_l1);
+EXPORT_SYMBOL(_ebss_b_l1);
+EXPORT_SYMBOL(_sdata_b_l1);
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
new file mode 100644
index 00000000000..539eb24e062
--- /dev/null
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -0,0 +1,183 @@
+/*
+ * File: arch/blackfin/kernel/dma-mapping.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: Dynamic DMA mapping support.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+#include <asm/bfin-global.h>
+
+static spinlock_t dma_page_lock;
+static unsigned int *dma_page;
+static unsigned int dma_pages;
+static unsigned long dma_base;
+static unsigned long dma_size;
+static unsigned int dma_initialized;
+
+void dma_alloc_init(unsigned long start, unsigned long end)
+{
+ spin_lock_init(&dma_page_lock);
+ dma_initialized = 0;
+
+ dma_page = (unsigned int *)__get_free_page(GFP_KERNEL);
+ memset(dma_page, 0, PAGE_SIZE);
+ dma_base = PAGE_ALIGN(start);
+ dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start);
+ dma_pages = dma_size >> PAGE_SHIFT;
+ memset((void *)dma_base, 0, DMA_UNCACHED_REGION);
+ dma_initialized = 1;
+
+ printk(KERN_INFO "%s: dma_page @ 0x%p - %d pages at 0x%08lx\n", __FUNCTION__,
+ dma_page, dma_pages, dma_base);
+}
+
+static inline unsigned int get_pages(size_t size)
+{
+ return ((size - 1) >> PAGE_SHIFT) + 1;
+}
+
+static unsigned long __alloc_dma_pages(unsigned int pages)
+{
+ unsigned long ret = 0, flags;
+ int i, count = 0;
+
+ if (dma_initialized == 0)
+ dma_alloc_init(_ramend - DMA_UNCACHED_REGION, _ramend);
+
+ spin_lock_irqsave(&dma_page_lock, flags);
+
+ for (i = 0; i < dma_pages;) {
+ if (dma_page[i++] == 0) {
+ if (++count == pages) {
+ while (count--)
+ dma_page[--i] = 1;
+ ret = dma_base + (i << PAGE_SHIFT);
+ break;
+ }
+ } else
+ count = 0;
+ }
+ spin_unlock_irqrestore(&dma_page_lock, flags);
+ return ret;
+}
+
+static void __free_dma_pages(unsigned long addr, unsigned int pages)
+{
+ unsigned long page = (addr - dma_base) >> PAGE_SHIFT;
+ unsigned long flags;
+ int i;
+
+ if ((page + pages) > dma_pages) {
+ printk(KERN_ERR "%s: freeing outside range.\n", __FUNCTION__);
+ BUG();
+ }
+
+ spin_lock_irqsave(&dma_page_lock, flags);
+ for (i = page; i < page + pages; i++) {
+ dma_page[i] = 0;
+ }
+ spin_unlock_irqrestore(&dma_page_lock, flags);
+}
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t * dma_handle, gfp_t gfp)
+{
+ void *ret;
+
+ ret = (void *)__alloc_dma_pages(get_pages(size));
+
+ if (ret) {
+ memset(ret, 0, size);
+ *dma_handle = virt_to_phys(ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void
+dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ __free_dma_pages((unsigned long)vaddr, get_pages(size));
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+/*
+ * Dummy functions defined for some existing drivers
+ */
+
+dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+
+ invalidate_dcache_range((unsigned long)ptr,
+ (unsigned long)ptr + size);
+
+ return (dma_addr_t) ptr;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ BUG_ON(direction == DMA_NONE);
+
+ for (i = 0; i < nents; i++)
+ invalidate_dcache_range(sg_dma_address(&sg[i]),
+ sg_dma_address(&sg[i]) +
+ sg_dma_len(&sg[i]));
+
+ return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries, enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
diff --git a/arch/blackfin/kernel/dualcore_test.c b/arch/blackfin/kernel/dualcore_test.c
new file mode 100644
index 00000000000..8b89c99f9df
--- /dev/null
+++ b/arch/blackfin/kernel/dualcore_test.c
@@ -0,0 +1,49 @@
+/*
+ * File: arch/blackfin/kernel/dualcore_test.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: Small test code for CoreB on a BF561
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+
+static int *testarg = (int*)0xfeb00000;
+
+static int test_init(void)
+{
+ *testarg = 1;
+ printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
+ *testarg, testarg);
+ return 0;
+}
+
+static void test_exit(void)
+{
+ printk("Dual core test module removed: testarg = [%d]\n", *testarg);
+}
+
+module_init(test_init);
+module_exit(test_exit);
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S
new file mode 100644
index 00000000000..5880b270bd5
--- /dev/null
+++ b/arch/blackfin/kernel/entry.S
@@ -0,0 +1,94 @@
+/*
+ * File: arch/blackfin/kernel/entry.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/asm-offsets.h>
+
+#include <asm/mach-common/context.S>
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+ENTRY(_ret_from_fork)
+ SP += -12;
+ call _schedule_tail;
+ SP += 12;
+ r0 = [sp + PT_IPEND];
+ cc = bittst(r0,1);
+ if cc jump .Lin_kernel;
+ RESTORE_CONTEXT
+ rti;
+.Lin_kernel:
+ bitclr(r0,1);
+ [sp + PT_IPEND] = r0;
+ /* do a 'fake' RTI by jumping to [RETI]
+ * to avoid clearing supervisor mode in child
+ */
+ RESTORE_ALL_SYS
+ p0 = reti;
+ jump (p0);
+
+ENTRY(_sys_fork)
+ r0 = -EINVAL;
+ rts;
+
+ENTRY(_sys_vfork)
+ r0 = sp;
+ r0 += 24;
+ [--sp] = rets;
+ SP += -12;
+ call _bfin_vfork;
+ SP += 12;
+ rets = [sp++];
+ rts;
+
+ENTRY(_sys_clone)
+ r0 = sp;
+ r0 += 24;
+ [--sp] = rets;
+ SP += -12;
+ call _bfin_clone;
+ SP += 12;
+ rets = [sp++];
+ rts;
+
+ENTRY(_sys_rt_sigreturn)
+ r0 = sp;
+ r0 += 24;
+ [--sp] = rets;
+ SP += -12;
+ call _do_rt_sigreturn;
+ SP += 12;
+ rets = [sp++];
+ rts;
diff --git a/arch/blackfin/kernel/flat.c b/arch/blackfin/kernel/flat.c
new file mode 100644
index 00000000000..a92587b628b
--- /dev/null
+++ b/arch/blackfin/kernel/flat.c
@@ -0,0 +1,101 @@
+/*
+ * arch/blackfin/kernel/flat.c
+ *
+ * Copyright (C) 2007 Analog Devices, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/flat.h>
+
+#define FLAT_BFIN_RELOC_TYPE_16_BIT 0
+#define FLAT_BFIN_RELOC_TYPE_16H_BIT 1
+#define FLAT_BFIN_RELOC_TYPE_32_BIT 2
+
+unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
+ unsigned long relval,
+ unsigned long flags,
+ unsigned long *persistent)
+{
+ unsigned short *usptr = (unsigned short *)ptr;
+ int type = (relval >> 26) & 7;
+ unsigned long val;
+
+ switch (type) {
+ case FLAT_BFIN_RELOC_TYPE_16_BIT:
+ case FLAT_BFIN_RELOC_TYPE_16H_BIT:
+ usptr = (unsigned short *)ptr;
+ pr_debug("*usptr = %x", get_unaligned(usptr));
+ val = get_unaligned(usptr);
+ val += *persistent;
+ break;
+
+ case FLAT_BFIN_RELOC_TYPE_32_BIT:
+ pr_debug("*ptr = %lx", get_unaligned(ptr));
+ val = get_unaligned(ptr);
+ break;
+
+ default:
+ pr_debug("BINFMT_FLAT: Unknown relocation type %x\n",
+ type);
+
+ return 0;
+ }
+
+ /*
+ * Stack-relative relocs contain the offset into the stack, we
+ * have to add the stack's start address here and return 1 from
+ * flat_addr_absolute to prevent the normal address calculations
+ */
+ if (relval & (1 << 29))
+ return val + current->mm->context.end_brk;
+
+ if ((flags & FLAT_FLAG_GOTPIC) == 0)
+ val = htonl(val);
+ return val;
+}
+EXPORT_SYMBOL(bfin_get_addr_from_rp);
+
+/*
+ * Insert the address ADDR into the symbol reference at RP;
+ * RELVAL is the raw relocation-table entry from which RP is derived
+ */
+void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
+ unsigned long relval)
+{
+ unsigned short *usptr = (unsigned short *)ptr;
+ int type = (relval >> 26) & 7;
+
+ switch (type) {
+ case FLAT_BFIN_RELOC_TYPE_16_BIT:
+ put_unaligned(addr, usptr);
+ pr_debug("new value %x at %p", get_unaligned(usptr),
+ usptr);
+ break;
+
+ case FLAT_BFIN_RELOC_TYPE_16H_BIT:
+ put_unaligned(addr >> 16, usptr);
+ pr_debug("new value %x", get_unaligned(usptr));
+ break;
+
+ case FLAT_BFIN_RELOC_TYPE_32_BIT:
+ put_unaligned(addr, ptr);
+ pr_debug("new ptr =%lx", get_unaligned(ptr));
+ break;
+ }
+}
+EXPORT_SYMBOL(bfin_put_addr_at_rp);
diff --git a/arch/blackfin/kernel/init_task.c b/arch/blackfin/kernel/init_task.c
new file mode 100644
index 00000000000..b45188f8512
--- /dev/null
+++ b/arch/blackfin/kernel/init_task.c
@@ -0,0 +1,60 @@
+/*
+ * File: arch/blackfin/kernel/init_task.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+
+struct mm_struct init_mm = INIT_MM(init_mm);
+EXPORT_SYMBOL(init_mm);
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry.
+ */
+union thread_union init_thread_union
+ __attribute__ ((__section__(".data.init_task"))) = {
+INIT_THREAD_INFO(init_task)};
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
new file mode 100644
index 00000000000..df5bf022cf7
--- /dev/null
+++ b/arch/blackfin/kernel/irqchip.c
@@ -0,0 +1,147 @@
+/*
+ * File: arch/blackfin/kernel/irqchip.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel_stat.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/seq_file.h>
+#include <linux/kallsyms.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+static unsigned long irq_err_count;
+static spinlock_t irq_controller_lock;
+
+/*
+ * Dummy mask/unmask handler
+ */
+void dummy_mask_unmask_irq(unsigned int irq)
+{
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+ irq_err_count += 1;
+ printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq);
+}
+EXPORT_SYMBOL(ack_bad_irq);
+
+static struct irq_chip bad_chip = {
+ .ack = dummy_mask_unmask_irq,
+ .mask = dummy_mask_unmask_irq,
+ .unmask = dummy_mask_unmask_irq,
+};
+
+static struct irq_desc bad_irq_desc = {
+ .chip = &bad_chip,
+ .handle_irq = handle_bad_irq,
+ .depth = 1,
+};
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+ int i = *(loff_t *) v;
+ struct irqaction *action;
+ unsigned long flags;
+
+ if (i < NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto unlock;
+
+ seq_printf(p, "%3d: %10u ", i, kstat_irqs(i));
+ seq_printf(p, " %s", action->name);
+ for (action = action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+
+ seq_putc(p, '\n');
+ unlock:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ } else if (i == NR_IRQS) {
+ seq_printf(p, "Err: %10lu\n", irq_err_count);
+ }
+ return 0;
+}
+
+/*
+ * do_IRQ handles all hardware IRQ's. Decoded IRQs should not
+ * come via this function. Instead, they should provide their
+ * own 'handler'
+ */
+
+#ifdef CONFIG_DO_IRQ_L1
+asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text));
+#endif
+
+asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs;
+ struct irq_desc *desc = irq_desc + irq;
+ unsigned short pending, other_ints;
+
+ old_regs = set_irq_regs(regs);
+
+ /*
+ * Some hardware gives randomly wrong interrupts. Rather
+ * than crashing, do something sensible.
+ */
+ if (irq >= NR_IRQS)
+ desc = &bad_irq_desc;
+
+ irq_enter();
+
+ generic_handle_irq(irq);
+
+ /* If we're the only interrupt running (ignoring IRQ15 which is for
+ syscalls), lower our priority to IRQ14 so that softirqs run at
+ that level. If there's another, lower-level interrupt, irq_exit
+ will defer softirqs to that. */
+ CSYNC();
+ pending = bfin_read_IPEND() & ~0x8000;
+ other_ints = pending & (pending - 1);
+ if (other_ints == 0)
+ lower_to_irq14();
+ irq_exit();
+
+ set_irq_regs(old_regs);
+}
+
+void __init init_IRQ(void)
+{
+ struct irq_desc *desc;
+ int irq;
+
+ spin_lock_init(&irq_controller_lock);
+ for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) {
+ *desc = bad_irq_desc;
+ }
+
+ init_arch_irq();
+}
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
new file mode 100644
index 00000000000..372f756f1ad
--- /dev/null
+++ b/arch/blackfin/kernel/module.c
@@ -0,0 +1,429 @@
+/*
+ * File: arch/blackfin/kernel/module.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+/*
+ * handle arithmetic relocations.
+ * See binutils/bfd/elf32-bfin.c for more details
+ */
+#define RELOC_STACK_SIZE 100
+static uint32_t reloc_stack[RELOC_STACK_SIZE];
+static unsigned int reloc_stack_tos;
+
+#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
+
+static void reloc_stack_push(uint32_t value)
+{
+ reloc_stack[reloc_stack_tos++] = value;
+}
+
+static uint32_t reloc_stack_pop(void)
+{
+ return reloc_stack[--reloc_stack_tos];
+}
+
+static uint32_t reloc_stack_operate(unsigned int oper, struct module *mod)
+{
+ uint32_t value;
+
+ switch (oper) {
+ case R_add:
+ value = reloc_stack[reloc_stack_tos - 2] +
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_sub:
+ value = reloc_stack[reloc_stack_tos - 2] -
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_mult:
+ value = reloc_stack[reloc_stack_tos - 2] *
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_div:
+ value = reloc_stack[reloc_stack_tos - 2] /
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_mod:
+ value = reloc_stack[reloc_stack_tos - 2] %
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_lshift:
+ value = reloc_stack[reloc_stack_tos - 2] <<
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_rshift:
+ value = reloc_stack[reloc_stack_tos - 2] >>
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_and:
+ value = reloc_stack[reloc_stack_tos - 2] &
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_or:
+ value = reloc_stack[reloc_stack_tos - 2] |
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_xor:
+ value = reloc_stack[reloc_stack_tos - 2] ^
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_land:
+ value = reloc_stack[reloc_stack_tos - 2] &&
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_lor:
+ value = reloc_stack[reloc_stack_tos - 2] ||
+ reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 2;
+ break;
+ case R_neg:
+ value = -reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos--;
+ break;
+ case R_comp:
+ value = ~reloc_stack[reloc_stack_tos - 1];
+ reloc_stack_tos -= 1;
+ break;
+ default:
+ printk(KERN_WARNING "module %s: unhandled reloction\n",
+ mod->name);
+ return 0;
+ }
+
+ /* now push the new value back on stack */
+ reloc_stack_push(value);
+
+ return value;
+}
+
+void *module_alloc(unsigned long size)
+{
+ if (size == 0)
+ return NULL;
+ return vmalloc(size);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+ vfree(module_region);
+}
+
+/* Transfer the section to the L1 memory */
+int
+module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
+ char *secstrings, struct module *mod)
+{
+ Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+ void *dest = NULL;
+
+ for (s = sechdrs; s < sechdrs_end; ++s) {
+ if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
+ ((strcmp(".text", secstrings + s->sh_name)==0) &&
+ (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
+ mod->arch.text_l1 = s;
+ dest = l1_inst_sram_alloc(s->sh_size);
+ if (dest == NULL) {
+ printk(KERN_ERR
+ "module %s: L1 instruction memory allocation failed\n",
+ mod->name);
+ return -1;
+ }
+ dma_memcpy(dest, (void *)s->sh_addr, s->sh_size);
+ s->sh_flags &= ~SHF_ALLOC;
+ s->sh_addr = (unsigned long)dest;
+ }
+ if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
+ ((strcmp(".data", secstrings + s->sh_name)==0) &&
+ (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
+ mod->arch.data_a_l1 = s;
+ dest = l1_data_sram_alloc(s->sh_size);
+ if (dest == NULL) {
+ printk(KERN_ERR
+ "module %s: L1 data memory allocation failed\n",
+ mod->name);
+ return -1;
+ }
+ memcpy(dest, (void *)s->sh_addr, s->sh_size);
+ s->sh_flags &= ~SHF_ALLOC;
+ s->sh_addr = (unsigned long)dest;
+ }
+ if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
+ ((strcmp(".bss", secstrings + s->sh_name)==0) &&
+ (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
+ mod->arch.bss_a_l1 = s;
+ dest = l1_data_sram_alloc(s->sh_size);
+ if (dest == NULL) {
+ printk(KERN_ERR
+ "module %s: L1 data memory allocation failed\n",
+ mod->name);
+ return -1;
+ }
+ memset(dest, 0, s->sh_size);
+ s->sh_flags &= ~SHF_ALLOC;
+ s->sh_addr = (unsigned long)dest;
+ }
+ if (strcmp(".l1.data.B", secstrings + s->sh_name) == 0) {
+ mod->arch.data_b_l1 = s;
+ dest = l1_data_B_sram_alloc(s->sh_size);
+ if (dest == NULL) {
+ printk(KERN_ERR
+ "module %s: L1 data memory allocation failed\n",
+ mod->name);
+ return -1;
+ }
+ memcpy(dest, (void *)s->sh_addr, s->sh_size);
+ s->sh_flags &= ~SHF_ALLOC;
+ s->sh_addr = (unsigned long)dest;
+ }
+ if (strcmp(".l1.bss.B", secstrings + s->sh_name) == 0) {
+ mod->arch.bss_b_l1 = s;
+ dest = l1_data_B_sram_alloc(s->sh_size);
+ if (dest == NULL) {
+ printk(KERN_ERR
+ "module %s: L1 data memory allocation failed\n",
+ mod->name);
+ return -1;
+ }
+ memset(dest, 0, s->sh_size);
+ s->sh_flags &= ~SHF_ALLOC;
+ s->sh_addr = (unsigned long)dest;
+ }
+ }
+ return 0;
+}
+
+int
+apply_relocate(Elf_Shdr * sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec, struct module *me)
+{
+ printk(KERN_ERR "module %s: .rel unsupported\n", me->name);
+ return -ENOEXEC;
+}
+
+/*************************************************************************/
+/* FUNCTION : apply_relocate_add */
+/* ABSTRACT : Blackfin specific relocation handling for the loadable */
+/* modules. Modules are expected to be .o files. */
+/* Arithmetic relocations are handled. */
+/* We do not expect LSETUP to be split and hence is not */
+/* handled. */
+/* R_byte and R_byte2 are also not handled as the gas */
+/* does not generate it. */
+/*************************************************************************/
+int
+apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec,
+ struct module *mod)
+{
+ unsigned int i;
+ unsigned short tmp;
+ Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ uint32_t *location32;
+ uint16_t *location16;
+ uint32_t value;
+
+ pr_debug("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ location16 =
+ (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].sh_addr +
+ rel[i].r_offset);
+ location32 = (uint32_t *) location16;
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ sym = (Elf32_Sym *) sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rel[i].r_info);
+ if (is_reloc_stack_empty()) {
+ value = sym->st_value;
+ } else {
+ value = reloc_stack_pop();
+ }
+ value += rel[i].r_addend;
+ pr_debug("location is %x, value is %x type is %d \n",
+ (unsigned int) location32, value,
+ ELF32_R_TYPE(rel[i].r_info));
+
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+
+ case R_pcrel24:
+ case R_pcrel24_jump_l:
+ /* Add the value, subtract its postition */
+ location16 =
+ (uint16_t *) (sechdrs[sechdrs[relsec].sh_info].
+ sh_addr + rel[i].r_offset - 2);
+ location32 = (uint32_t *) location16;
+ value -= (uint32_t) location32;
+ value >>= 1;
+ pr_debug("value is %x, before %x-%x after %x-%x\n", value,
+ *location16, *(location16 + 1),
+ (*location16 & 0xff00) | (value >> 16 & 0x00ff),
+ value & 0xffff);
+ *location16 =
+ (*location16 & 0xff00) | (value >> 16 & 0x00ff);
+ *(location16 + 1) = value & 0xffff;
+ break;
+ case R_pcrel12_jump:
+ case R_pcrel12_jump_s:
+ value -= (uint32_t) location32;
+ value >>= 1;
+ *location16 = (value & 0xfff);
+ break;
+ case R_pcrel10:
+ value -= (uint32_t) location32;
+ value >>= 1;
+ *location16 = (value & 0x3ff);
+ break;
+ case R_luimm16:
+ pr_debug("before %x after %x\n", *location16,
+ (value & 0xffff));
+ tmp = (value & 0xffff);
+ if((unsigned long)location16 >= L1_CODE_START) {
+ dma_memcpy(location16, &tmp, 2);
+ } else
+ *location16 = tmp;
+ break;
+ case R_huimm16:
+ pr_debug("before %x after %x\n", *location16,
+ ((value >> 16) & 0xffff));
+ tmp = ((value >> 16) & 0xffff);
+ if((unsigned long)location16 >= L1_CODE_START) {
+ dma_memcpy(location16, &tmp, 2);
+ } else
+ *location16 = tmp;
+ break;
+ case R_rimm16:
+ *location16 = (value & 0xffff);
+ break;
+ case R_byte4_data:
+ pr_debug("before %x after %x\n", *location32, value);
+ *location32 = value;
+ break;
+ case R_push:
+ reloc_stack_push(value);
+ break;
+ case R_const:
+ reloc_stack_push(rel[i].r_addend);
+ break;
+ case R_add:
+ case R_sub:
+ case R_mult:
+ case R_div:
+ case R_mod:
+ case R_lshift:
+ case R_rshift:
+ case R_and:
+ case R_or:
+ case R_xor:
+ case R_land:
+ case R_lor:
+ case R_neg:
+ case R_comp:
+ reloc_stack_operate(ELF32_R_TYPE(rel[i].r_info), mod);
+ break;
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ mod->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+
+int
+module_finalize(const Elf_Ehdr * hdr,
+ const Elf_Shdr * sechdrs, struct module *mod)
+{
+ unsigned int i, strindex = 0, symindex = 0;
+ char *secstrings;
+
+ secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ /* Internal symbols and strings. */
+ if (sechdrs[i].sh_type == SHT_SYMTAB) {
+ symindex = i;
+ strindex = sechdrs[i].sh_link;
+ }
+ }
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ const char *strtab = (char *)sechdrs[strindex].sh_addr;
+ unsigned int info = sechdrs[i].sh_info;
+
+ /* Not a valid relocation section? */
+ if (info >= hdr->e_shnum)
+ continue;
+
+ if ((sechdrs[i].sh_type == SHT_RELA) &&
+ ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
+ ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
+ (hdr->e_flags & FLG_CODE_IN_L1)))) {
+ apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
+ symindex, i, mod);
+ }
+ }
+ return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+ if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
+ l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
+ if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
+ l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
+ if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
+ l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
+ if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
+ l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
+ if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
+ l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
+}
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
new file mode 100644
index 00000000000..3eff7439d8d
--- /dev/null
+++ b/arch/blackfin/kernel/process.c
@@ -0,0 +1,394 @@
+/*
+ * File: arch/blackfin/kernel/process.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: Blackfin architecture-dependent process handling.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/unistd.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+
+#define LED_ON 0
+#define LED_OFF 1
+
+asmlinkage void ret_from_fork(void);
+
+/* Points to the SDRAM backup memory for the stack that is currently in
+ * L1 scratchpad memory.
+ */
+void *current_l1_stack_save;
+
+/* The number of tasks currently using a L1 stack area. The SRAM is
+ * allocated/deallocated whenever this changes from/to zero.
+ */
+int nr_l1stack_tasks;
+
+/* Start and length of the area in L1 scratchpad memory which we've allocated
+ * for process stacks.
+ */
+void *l1_stack_base;
+unsigned long l1_stack_len;
+
+/*
+ * Powermanagement idle function, if any..
+ */
+void (*pm_idle)(void) = NULL;
+EXPORT_SYMBOL(pm_idle);
+
+void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
+
+/*
+ * We are using a different LED from the one used to indicate timer interrupt.
+ */
+#if defined(CONFIG_BFIN_IDLE_LED)
+static inline void leds_switch(int flag)
+{
+ unsigned short tmp = 0;
+
+ tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
+ SSYNC();
+
+ if (flag == LED_ON)
+ tmp &= ~CONFIG_BFIN_IDLE_LED_PIN; /* light on */
+ else
+ tmp |= CONFIG_BFIN_IDLE_LED_PIN; /* light off */
+
+ bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp);
+ SSYNC();
+
+}
+#else
+static inline void leds_switch(int flag)
+{
+}
+#endif
+
+/*
+ * The idle loop on BFIN
+ */
+#ifdef CONFIG_IDLE_L1
+void default_idle(void)__attribute__((l1_text));
+void cpu_idle(void)__attribute__((l1_text));
+#endif
+
+void default_idle(void)
+{
+ while (!need_resched()) {
+ leds_switch(LED_OFF);
+ local_irq_disable();
+ if (likely(!need_resched()))
+ idle_with_irq_disabled();
+ local_irq_enable();
+ leds_switch(LED_ON);
+ }
+}
+
+void (*idle)(void) = default_idle;
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+ /* endless idle loop with no priority at all */
+ while (1) {
+ idle();
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+ }
+}
+
+void machine_restart(char *__unused)
+{
+#if defined(CONFIG_BLKFIN_CACHE)
+ bfin_write_IMEM_CONTROL(0x01);
+ SSYNC();
+#endif
+ bfin_reset();
+ /* Dont do anything till the reset occurs */
+ while (1) {
+ SSYNC();
+ }
+}
+
+void machine_halt(void)
+{
+ for (;;)
+ asm volatile ("idle");
+}
+
+void machine_power_off(void)
+{
+ for (;;)
+ asm volatile ("idle");
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ printk(KERN_NOTICE "\n");
+ printk(KERN_NOTICE
+ "PC: %08lu Status: %04lu SysStatus: %04lu RETS: %08lu\n",
+ regs->pc, regs->astat, regs->seqstat, regs->rets);
+ printk(KERN_NOTICE
+ "A0.x: %08lx A0.w: %08lx A1.x: %08lx A1.w: %08lx\n",
+ regs->a0x, regs->a0w, regs->a1x, regs->a1w);
+ printk(KERN_NOTICE "P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
+ regs->p0, regs->p1, regs->p2, regs->p3);
+ printk(KERN_NOTICE "P4: %08lx P5: %08lx\n", regs->p4, regs->p5);
+ printk(KERN_NOTICE "R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
+ regs->r0, regs->r1, regs->r2, regs->r3);
+ printk(KERN_NOTICE "R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
+ regs->r4, regs->r5, regs->r6, regs->r7);
+
+ if (!(regs->ipend))
+ printk("USP: %08lx\n", rdusp());
+}
+
+/* Fill in the fpu structure for a core dump. */
+
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs)
+{
+ return 1;
+}
+
+/*
+ * This gets run with P1 containing the
+ * function to call, and R1 containing
+ * the "args". Note P0 is clobbered on the way here.
+ */
+void kernel_thread_helper(void);
+__asm__(".section .text\n"
+ ".align 4\n"
+ "_kernel_thread_helper:\n\t"
+ "\tsp += -12;\n\t"
+ "\tr0 = r1;\n\t" "\tcall (p1);\n\t" "\tcall _do_exit;\n" ".previous");
+
+/*
+ * Create a kernel thread.
+ */
+pid_t kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
+{
+ struct pt_regs regs;
+
+ memset(&regs, 0, sizeof(regs));
+
+ regs.r1 = (unsigned long)arg;
+ regs.p1 = (unsigned long)fn;
+ regs.pc = (unsigned long)kernel_thread_helper;
+ regs.orig_p0 = -1;
+ /* Set bit 2 to tell ret_from_fork we should be returning to kernel
+ mode. */
+ regs.ipend = 0x8002;
+ __asm__ __volatile__("%0 = syscfg;":"=da"(regs.syscfg):);
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,
+ NULL);
+}
+
+void flush_thread(void)
+{
+}
+
+asmlinkage int bfin_vfork(struct pt_regs *regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL,
+ NULL);
+}
+
+asmlinkage int bfin_clone(struct pt_regs *regs)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+
+ /* syscall2 puts clone_flags in r0 and usp in r1 */
+ clone_flags = regs->r0;
+ newsp = regs->r1;
+ if (!newsp)
+ newsp = rdusp();
+ else
+ newsp -= 12;
+ return do_fork(clone_flags, newsp, regs, 0, NULL, NULL);
+}
+
+int
+copy_thread(int nr, unsigned long clone_flags,
+ unsigned long usp, unsigned long topstk,
+ struct task_struct *p, struct pt_regs *regs)
+{
+ struct pt_regs *childregs;
+
+ childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;
+ *childregs = *regs;
+ childregs->r0 = 0;
+
+ p->thread.usp = usp;
+ p->thread.ksp = (unsigned long)childregs;
+ p->thread.pc = (unsigned long)ret_from_fork;
+
+ return 0;
+}
+
+/*
+ * fill in the user structure for a core dump..
+ */
+void dump_thread(struct pt_regs *regs, struct user *dump)
+{
+ dump->magic = CMAGIC;
+ dump->start_code = 0;
+ dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
+ dump->u_tsize = ((unsigned long)current->mm->end_code) >> PAGE_SHIFT;
+ dump->u_dsize = ((unsigned long)(current->mm->brk +
+ (PAGE_SIZE - 1))) >> PAGE_SHIFT;
+ dump->u_dsize -= dump->u_tsize;
+ dump->u_ssize = 0;
+
+ if (dump->start_stack < TASK_SIZE)
+ dump->u_ssize =
+ ((unsigned long)(TASK_SIZE -
+ dump->start_stack)) >> PAGE_SHIFT;
+
+ dump->u_ar0 = (struct user_regs_struct *)((int)&dump->regs - (int)dump);
+
+ dump->regs.r0 = regs->r0;
+ dump->regs.r1 = regs->r1;
+ dump->regs.r2 = regs->r2;
+ dump->regs.r3 = regs->r3;
+ dump->regs.r4 = regs->r4;
+ dump->regs.r5 = regs->r5;
+ dump->regs.r6 = regs->r6;
+ dump->regs.r7 = regs->r7;
+ dump->regs.p0 = regs->p0;
+ dump->regs.p1 = regs->p1;
+ dump->regs.p2 = regs->p2;
+ dump->regs.p3 = regs->p3;
+ dump->regs.p4 = regs->p4;
+ dump->regs.p5 = regs->p5;
+ dump->regs.orig_p0 = regs->orig_p0;
+ dump->regs.a0w = regs->a0w;
+ dump->regs.a1w = regs->a1w;
+ dump->regs.a0x = regs->a0x;
+ dump->regs.a1x = regs->a1x;
+ dump->regs.rets = regs->rets;
+ dump->regs.astat = regs->astat;
+ dump->regs.pc = regs->pc;
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+
+asmlinkage int sys_execve(char *name, char **argv, char **envp)
+{
+ int error;
+ char *filename;
+ struct pt_regs *regs = (struct pt_regs *)((&name) + 6);
+
+ lock_kernel();
+ filename = getname(name);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve(filename, argv, envp, regs);
+ putname(filename);
+ out:
+ unlock_kernel();
+ return error;
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long fp, pc;
+ unsigned long stack_page;
+ int count = 0;
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ stack_page = (unsigned long)p;
+ fp = p->thread.usp;
+ do {
+ if (fp < stack_page + sizeof(struct thread_info) ||
+ fp >= 8184 + stack_page)
+ return 0;
+ pc = ((unsigned long *)fp)[1];
+ if (!in_sched_functions(pc))
+ return pc;
+ fp = *(unsigned long *)fp;
+ }
+ while (count++ < 16);
+ return 0;
+}
+
+#if defined(CONFIG_ACCESS_CHECK)
+int _access_ok(unsigned long addr, unsigned long size)
+{
+
+ if (addr > (addr + size))
+ return 0;
+ if (segment_eq(get_fs(),KERNEL_DS))
+ return 1;
+#ifdef CONFIG_MTD_UCLINUX
+ if (addr >= memory_start && (addr + size) <= memory_end)
+ return 1;
+ if (addr >= memory_mtd_end && (addr + size) <= physical_mem_end)
+ return 1;
+#else
+ if (addr >= memory_start && (addr + size) <= physical_mem_end)
+ return 1;
+#endif
+ if (addr >= (unsigned long)__init_begin &&
+ addr + size <= (unsigned long)__init_end)
+ return 1;
+ if (addr >= L1_SCRATCH_START
+ && addr + size <= L1_SCRATCH_START + L1_SCRATCH_LENGTH)
+ return 1;
+#if L1_CODE_LENGTH != 0
+ if (addr >= L1_CODE_START + (_etext_l1 - _stext_l1)
+ && addr + size <= L1_CODE_START + L1_CODE_LENGTH)
+ return 1;
+#endif
+#if L1_DATA_A_LENGTH != 0
+ if (addr >= L1_DATA_A_START + (_ebss_l1 - _sdata_l1)
+ && addr + size <= L1_DATA_A_START + L1_DATA_A_LENGTH)
+ return 1;
+#endif
+#if L1_DATA_B_LENGTH != 0
+ if (addr >= L1_DATA_B_START
+ && addr + size <= L1_DATA_B_START + L1_DATA_B_LENGTH)
+ return 1;
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(_access_ok);
+#endif /* CONFIG_ACCESS_CHECK */
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
new file mode 100644
index 00000000000..e718bb4a1ef
--- /dev/null
+++ b/arch/blackfin/kernel/ptrace.c
@@ -0,0 +1,430 @@
+/*
+ * File: arch/blackfin/kernel/ptrace.c
+ * Based on: Taken from linux/kernel/ptrace.c
+ * Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ *
+ * Created: 1/23/92
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/signal.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+#include <asm/dma.h>
+
+#define MAX_SHARED_LIBS 3
+#define TEXT_OFFSET 0
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
+
+/* determines which bits in the SYSCFG reg the user has access to. */
+/* 1 = access 0 = no access */
+#define SYSCFG_MASK 0x0007 /* SYSCFG reg */
+/* sets the trace bits. */
+#define TRACE_BITS 0x0001
+
+/* Find the stack offset for a register, relative to thread.esp0. */
+#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg)
+
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ *
+ * Note: if a user thread is execve'd from kernel space, the
+ * kernel stack will not be empty on entry to the kernel, so
+ * ptracing these tasks will fail.
+ */
+static inline struct pt_regs *get_user_regs(struct task_struct *task)
+{
+ return (struct pt_regs *)
+ ((unsigned long)task_stack_page(task) +
+ (THREAD_SIZE - sizeof(struct pt_regs)));
+}
+
+/*
+ * Get all user integer registers.
+ */
+static inline int ptrace_getregs(struct task_struct *tsk, void __user * uregs)
+{
+ struct pt_regs *regs = get_user_regs(tsk);
+ return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
+}
+
+/* Mapping from PT_xxx to the stack offset at which the register is
+ * saved. Notice that usp has no stack-slot and needs to be treated
+ * specially (see get_reg/put_reg below).
+ */
+
+/*
+ * Get contents of register REGNO in task TASK.
+ */
+static inline long get_reg(struct task_struct *task, int regno)
+{
+ unsigned char *reg_ptr;
+
+ struct pt_regs *regs =
+ (struct pt_regs *)((unsigned long)task_stack_page(task) +
+ (THREAD_SIZE - sizeof(struct pt_regs)));
+ reg_ptr = (char *)regs;
+
+ switch (regno) {
+ case PT_USP:
+ return task->thread.usp;
+ default:
+ if (regno <= 216)
+ return *(long *)(reg_ptr + regno);
+ }
+ /* slight mystery ... never seems to come here but kernel misbehaves without this code! */
+
+ printk(KERN_WARNING "Request to get for unknown register %d\n", regno);
+ return 0;
+}
+
+/*
+ * Write contents of register REGNO in task TASK.
+ */
+static inline int
+put_reg(struct task_struct *task, int regno, unsigned long data)
+{
+ char * reg_ptr;
+
+ struct pt_regs *regs =
+ (struct pt_regs *)((unsigned long)task_stack_page(task) +
+ (THREAD_SIZE - sizeof(struct pt_regs)));
+ reg_ptr = (char *)regs;
+
+ switch (regno) {
+ case PT_PC:
+ /*********************************************************************/
+ /* At this point the kernel is most likely in exception. */
+ /* The RETX register will be used to populate the pc of the process. */
+ /*********************************************************************/
+ regs->retx = data;
+ regs->pc = data;
+ break;
+ case PT_RETX:
+ break; /* regs->retx = data; break; */
+ case PT_USP:
+ regs->usp = data;
+ task->thread.usp = data;
+ break;
+ default:
+ if (regno <= 216)
+ *(long *)(reg_ptr + regno) = data;
+ }
+ return 0;
+}
+
+/*
+ * check that an address falls within the bounds of the target process's memory mappings
+ */
+static inline int is_user_addr_valid(struct task_struct *child,
+ unsigned long start, unsigned long len)
+{
+ struct vm_list_struct *vml;
+ struct sram_list_struct *sraml;
+
+ for (vml = child->mm->context.vmlist; vml; vml = vml->next)
+ if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end)
+ return 0;
+
+ for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
+ if (start >= (unsigned long)sraml->addr
+ && start + len <= (unsigned long)sraml->addr + sraml->length)
+ return 0;
+
+ return -EIO;
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure the single step bit is not set.
+ */
+void ptrace_disable(struct task_struct *child)
+{
+ unsigned long tmp;
+ /* make sure the single step bit is not set. */
+ tmp = get_reg(child, PT_SR) & ~(TRACE_BITS << 16);
+ put_reg(child, PT_SR, tmp);
+}
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+ int ret;
+ int add = 0;
+
+ switch (request) {
+ /* when I and D space are separate, these will need to be fixed. */
+ case PTRACE_PEEKDATA:
+ pr_debug("ptrace: PEEKDATA\n");
+ add = MAX_SHARED_LIBS * 4; /* space between text and data */
+ /* fall through */
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ {
+ unsigned long tmp = 0;
+ int copied;
+
+ ret = -EIO;
+ pr_debug("ptrace: PEEKTEXT at addr 0x%08lx + add %d %ld\n", addr, add,
+ sizeof(data));
+ if (is_user_addr_valid(child, addr + add, sizeof(tmp)) < 0)
+ break;
+ pr_debug("ptrace: user address is valid\n");
+
+#if L1_CODE_LENGTH != 0
+ if (addr + add >= L1_CODE_START
+ && addr + add + sizeof(tmp) <= L1_CODE_START + L1_CODE_LENGTH) {
+ safe_dma_memcpy (&tmp, (const void *)(addr + add), sizeof(tmp));
+ copied = sizeof(tmp);
+ } else
+#endif
+ copied =
+ access_process_vm(child, addr + add, &tmp,
+ sizeof(tmp), 0);
+ pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp);
+ if (copied != sizeof(tmp))
+ break;
+ ret = put_user(tmp, (unsigned long *)data);
+ break;
+ }
+
+ /* read the word at location addr in the USER area. */
+ case PTRACE_PEEKUSR:
+ {
+ unsigned long tmp;
+ ret = -EIO;
+ tmp = 0;
+ if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
+ printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning "
+ "0 - %x sizeof(pt_regs) is %lx\n",
+ (int)addr, sizeof(struct pt_regs));
+ break;
+ }
+ if (addr == sizeof(struct pt_regs)) {
+ /* PT_TEXT_ADDR */
+ tmp = child->mm->start_code + TEXT_OFFSET;
+ } else if (addr == (sizeof(struct pt_regs) + 4)) {
+ /* PT_TEXT_END_ADDR */
+ tmp = child->mm->end_code;
+ } else if (addr == (sizeof(struct pt_regs) + 8)) {
+ /* PT_DATA_ADDR */
+ tmp = child->mm->start_data;
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+ } else if (addr == (sizeof(struct pt_regs) + 12)) {
+ tmp = child->mm->context.exec_fdpic_loadmap;
+ } else if (addr == (sizeof(struct pt_regs) + 16)) {
+ tmp = child->mm->context.interp_fdpic_loadmap;
+#endif
+ } else {
+ tmp = get_reg(child, addr);
+ }
+ ret = put_user(tmp, (unsigned long *)data);
+ break;
+ }
+
+ /* when I and D space are separate, this will have to be fixed. */
+ case PTRACE_POKEDATA:
+ printk(KERN_NOTICE "ptrace: PTRACE_PEEKDATA\n");
+ /* fall through */
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ {
+ int copied;
+
+ ret = -EIO;
+ pr_debug("ptrace: POKETEXT at addr 0x%08lx + add %d %ld bytes %lx\n",
+ addr, add, sizeof(data), data);
+ if (is_user_addr_valid(child, addr + add, sizeof(data)) < 0)
+ break;
+ pr_debug("ptrace: user address is valid\n");
+
+#if L1_CODE_LENGTH != 0
+ if (addr + add >= L1_CODE_START
+ && addr + add + sizeof(data) <= L1_CODE_START + L1_CODE_LENGTH) {
+ safe_dma_memcpy ((void *)(addr + add), &data, sizeof(data));
+ copied = sizeof(data);
+ } else
+#endif
+ copied =
+ access_process_vm(child, addr + add, &data,
+ sizeof(data), 1);
+ pr_debug("ptrace: copied size %d\n", copied);
+ if (copied != sizeof(data))
+ break;
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ ret = -EIO;
+ if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) {
+ printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n");
+ break;
+ }
+
+ if (addr >= (sizeof(struct pt_regs))) {
+ ret = 0;
+ break;
+ }
+ if (addr == PT_SYSCFG) {
+ data &= SYSCFG_MASK;
+ data |= get_reg(child, PT_SYSCFG);
+ }
+ ret = put_reg(child, addr, data);
+ break;
+
+ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
+ case PTRACE_CONT:
+ { /* restart after signal. */
+ long tmp;
+
+ pr_debug("ptrace_cont\n");
+
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+ if (request == PTRACE_SYSCALL)
+ set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ else
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+ child->exit_code = data;
+ /* make sure the single step bit is not set. */
+ tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
+ put_reg(child, PT_SYSCFG, tmp);
+ pr_debug("before wake_up_process\n");
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ /*
+ * make the child exit. Best I can do is send it a sigkill.
+ * perhaps it should be put in the status that it wants to
+ * exit.
+ */
+ case PTRACE_KILL:
+ {
+ long tmp;
+ ret = 0;
+ if (child->exit_state == EXIT_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ /* make sure the single step bit is not set. */
+ tmp = get_reg(child, PT_SYSCFG) & ~(TRACE_BITS);
+ put_reg(child, PT_SYSCFG, tmp);
+ wake_up_process(child);
+ break;
+ }
+
+ case PTRACE_SINGLESTEP:
+ { /* set the trap flag. */
+ long tmp;
+
+ pr_debug("single step\n");
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+
+ tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS);
+ put_reg(child, PT_SYSCFG, tmp);
+
+ child->exit_code = data;
+ /* give it a chance to run. */
+ wake_up_process(child);
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_DETACH:
+ { /* detach a process that was attached. */
+ ret = ptrace_detach(child, data);
+ break;
+ }
+
+ case PTRACE_GETREGS:
+ {
+
+ /* Get all gp regs from the child. */
+ ret = ptrace_getregs(child, (void __user *)data);
+ break;
+ }
+
+ case PTRACE_SETREGS:
+ {
+ printk(KERN_NOTICE
+ "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n");
+ /* Set all gp regs in the child. */
+ ret = 0;
+ break;
+ }
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
+}
+
+asmlinkage void syscall_trace(void)
+{
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return;
+
+ if (!(current->ptrace & PT_PTRACED))
+ return;
+
+ /* the 0x80 provides a way for the tracing parent to distinguish
+ * between a syscall stop and SIGTRAP delivery
+ */
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+ ? 0x80 : 0));
+
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+}
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
new file mode 100644
index 00000000000..342bb8dd56a
--- /dev/null
+++ b/arch/blackfin/kernel/setup.c
@@ -0,0 +1,902 @@
+/*
+ * File: arch/blackfin/kernel/setup.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+
+#include <linux/ext2_fs.h>
+#include <linux/cramfs_fs.h>
+#include <linux/romfs_fs.h>
+
+#include <asm/cacheflush.h>
+#include <asm/blackfin.h>
+#include <asm/cplbinit.h>
+
+unsigned long memory_start, memory_end, physical_mem_end;
+unsigned long reserved_mem_dcache_on;
+unsigned long reserved_mem_icache_on;
+EXPORT_SYMBOL(memory_start);
+EXPORT_SYMBOL(memory_end);
+EXPORT_SYMBOL(physical_mem_end);
+EXPORT_SYMBOL(_ramend);
+
+#ifdef CONFIG_MTD_UCLINUX
+unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
+unsigned long _ebss;
+EXPORT_SYMBOL(memory_mtd_end);
+EXPORT_SYMBOL(memory_mtd_start);
+EXPORT_SYMBOL(mtd_size);
+#endif
+
+char command_line[COMMAND_LINE_SIZE];
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+static void generate_cpl_tables(void);
+#endif
+
+void __init bf53x_cache_init(void)
+{
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+ generate_cpl_tables();
+#endif
+
+#ifdef CONFIG_BLKFIN_CACHE
+ bfin_icache_init();
+ printk(KERN_INFO "Instruction Cache Enabled\n");
+#endif
+
+#ifdef CONFIG_BLKFIN_DCACHE
+ bfin_dcache_init();
+ printk(KERN_INFO "Data Cache Enabled"
+# if defined CONFIG_BLKFIN_WB
+ " (write-back)"
+# elif defined CONFIG_BLKFIN_WT
+ " (write-through)"
+# endif
+ "\n");
+#endif
+}
+
+void bf53x_relocate_l1_mem(void)
+{
+ unsigned long l1_code_length;
+ unsigned long l1_data_a_length;
+ unsigned long l1_data_b_length;
+
+ l1_code_length = _etext_l1 - _stext_l1;
+ if (l1_code_length > L1_CODE_LENGTH)
+ l1_code_length = L1_CODE_LENGTH;
+ /* cannot complain as printk is not available as yet.
+ * But we can continue booting and complain later!
+ */
+
+ /* Copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
+ dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+
+ l1_data_a_length = _ebss_l1 - _sdata_l1;
+ if (l1_data_a_length > L1_DATA_A_LENGTH)
+ l1_data_a_length = L1_DATA_A_LENGTH;
+
+ /* Copy _sdata_l1 to _ebss_l1 to L1 data bank A SRAM */
+ dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
+
+ l1_data_b_length = _ebss_b_l1 - _sdata_b_l1;
+ if (l1_data_b_length > L1_DATA_B_LENGTH)
+ l1_data_b_length = L1_DATA_B_LENGTH;
+
+ /* Copy _sdata_b_l1 to _ebss_b_l1 to L1 data bank B SRAM */
+ dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
+ l1_data_a_length, l1_data_b_length);
+
+}
+
+/*
+ * Initial parsing of the command line. Currently, we support:
+ * - Controlling the linux memory size: mem=xxx[KMG]
+ * - Controlling the physical memory size: max_mem=xxx[KMG][$][#]
+ * $ -> reserved memory is dcacheable
+ * # -> reserved memory is icacheable
+ */
+static __init void parse_cmdline_early(char *cmdline_p)
+{
+ char c = ' ', *to = cmdline_p;
+ unsigned int memsize;
+ for (;;) {
+ if (c == ' ') {
+
+ if (!memcmp(to, "mem=", 4)) {
+ to += 4;
+ memsize = memparse(to, &to);
+ if (memsize)
+ _ramend = memsize;
+
+ } else if (!memcmp(to, "max_mem=", 8)) {
+ to += 8;
+ memsize = memparse(to, &to);
+ if (memsize) {
+ physical_mem_end = memsize;
+ if (*to != ' ') {
+ if (*to == '$'
+ || *(to + 1) == '$')
+ reserved_mem_dcache_on =
+ 1;
+ if (*to == '#'
+ || *(to + 1) == '#')
+ reserved_mem_icache_on =
+ 1;
+ }
+ }
+ }
+
+ }
+ c = *(to++);
+ if (!c)
+ break;
+ }
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+ int bootmap_size;
+ unsigned long l1_length, sclk, cclk;
+#ifdef CONFIG_MTD_UCLINUX
+ unsigned long mtd_phys = 0;
+#endif
+
+ cclk = get_cclk();
+ sclk = get_sclk();
+
+#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273)
+ if (cclk == sclk)
+ panic("ANOMALY 05000273, SCLK can not be same as CCLK");
+#endif
+
+#if defined(ANOMALY_05000266)
+ bfin_read_IMDMA_D0_IRQ_STATUS();
+ bfin_read_IMDMA_D1_IRQ_STATUS();
+#endif
+
+#ifdef DEBUG_SERIAL_EARLY_INIT
+ bfin_console_init(); /* early console registration */
+ /* this give a chance to get printk() working before crash. */
+#endif
+
+#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
+ /* we need to initialize the Flashrom device here since we might
+ * do things with flash early on in the boot
+ */
+ flash_probe();
+#endif
+
+#if defined(CONFIG_CMDLINE_BOOL)
+ memset(command_line, 0, sizeof(command_line));
+ strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line));
+ command_line[sizeof(command_line) - 1] = 0;
+#endif
+
+ /* Keep a copy of command line */
+ *cmdline_p = &command_line[0];
+ memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
+ boot_command_line[COMMAND_LINE_SIZE - 1] = 0;
+
+ /* setup memory defaults from the user config */
+ physical_mem_end = 0;
+ _ramend = CONFIG_MEM_SIZE * 1024 * 1024;
+
+ parse_cmdline_early(&command_line[0]);
+
+ if (physical_mem_end == 0)
+ physical_mem_end = _ramend;
+
+ /* by now the stack is part of the init task */
+ memory_end = _ramend - DMA_UNCACHED_REGION;
+
+ _ramstart = (unsigned long)__bss_stop;
+ memory_start = PAGE_ALIGN(_ramstart);
+
+#if defined(CONFIG_MTD_UCLINUX)
+ /* generic memory mapped MTD driver */
+ memory_mtd_end = memory_end;
+
+ mtd_phys = _ramstart;
+ mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 8)));
+
+# if defined(CONFIG_EXT2_FS) || defined(CONFIG_EXT3_FS)
+ if (*((unsigned short *)(mtd_phys + 0x438)) == EXT2_SUPER_MAGIC)
+ mtd_size =
+ PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x404)) << 10);
+# endif
+
+# if defined(CONFIG_CRAMFS)
+ if (*((unsigned long *)(mtd_phys)) == CRAMFS_MAGIC)
+ mtd_size = PAGE_ALIGN(*((unsigned long *)(mtd_phys + 0x4)));
+# endif
+
+# if defined(CONFIG_ROMFS_FS)
+ if (((unsigned long *)mtd_phys)[0] == ROMSB_WORD0
+ && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1)
+ mtd_size =
+ PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2]));
+# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+ /* Due to a Hardware Anomaly we need to limit the size of usable
+ * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
+ * 05000263 - Hardware loop corrupted when taking an ICPLB exception
+ */
+# if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
+ if (memory_end >= 56 * 1024 * 1024)
+ memory_end = 56 * 1024 * 1024;
+# else
+ if (memory_end >= 60 * 1024 * 1024)
+ memory_end = 60 * 1024 * 1024;
+# endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
+# endif /* ANOMALY_05000263 */
+# endif /* CONFIG_ROMFS_FS */
+
+ memory_end -= mtd_size;
+
+ if (mtd_size == 0) {
+ console_init();
+ panic("Don't boot kernel without rootfs attached.\n");
+ }
+
+ /* Relocate MTD image to the top of memory after the uncached memory area */
+ dma_memcpy((char *)memory_end, __bss_stop, mtd_size);
+
+ memory_mtd_start = memory_end;
+ _ebss = memory_mtd_start; /* define _ebss for compatible */
+#endif /* CONFIG_MTD_UCLINUX */
+
+#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+ /* Due to a Hardware Anomaly we need to limit the size of usable
+ * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on
+ * 05000263 - Hardware loop corrupted when taking an ICPLB exception
+ */
+#if (defined(CONFIG_DEBUG_HUNT_FOR_ZERO))
+ if (memory_end >= 56 * 1024 * 1024)
+ memory_end = 56 * 1024 * 1024;
+#else
+ if (memory_end >= 60 * 1024 * 1024)
+ memory_end = 60 * 1024 * 1024;
+#endif /* CONFIG_DEBUG_HUNT_FOR_ZERO */
+ printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
+#endif /* ANOMALY_05000263 */
+
+#if !defined(CONFIG_MTD_UCLINUX)
+ memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
+#endif
+ init_mm.start_code = (unsigned long)_stext;
+ init_mm.end_code = (unsigned long)_etext;
+ init_mm.end_data = (unsigned long)_edata;
+ init_mm.brk = (unsigned long)0;
+
+ init_leds();
+
+ printk(KERN_INFO "Blackfin support (C) 2004-2007 Analog Devices, Inc.\n");
+ printk(KERN_INFO "Compiled for ADSP-%s Rev 0.%d\n", CPU, bfin_compiled_revid());
+ if (bfin_revid() != bfin_compiled_revid())
+ printk(KERN_ERR "Warning: Compiled for Rev %d, but running on Rev %d\n",
+ bfin_compiled_revid(), bfin_revid());
+ if (bfin_revid() < SUPPORTED_REVID)
+ printk(KERN_ERR "Warning: Unsupported Chip Revision ADSP-%s Rev 0.%d detected\n",
+ CPU, bfin_revid());
+ printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n");
+
+ printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n",
+ cclk / 1000000, sclk / 1000000);
+
+#if defined(ANOMALY_05000273)
+ if ((cclk >> 1) <= sclk)
+ printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n");
+#endif
+
+ printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20);
+ printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20);
+
+ printk(KERN_INFO "Memory map:\n"
+ KERN_INFO " text = 0x%p-0x%p\n"
+ KERN_INFO " init = 0x%p-0x%p\n"
+ KERN_INFO " data = 0x%p-0x%p\n"
+ KERN_INFO " stack = 0x%p-0x%p\n"
+ KERN_INFO " bss = 0x%p-0x%p\n"
+ KERN_INFO " available = 0x%p-0x%p\n"
+#ifdef CONFIG_MTD_UCLINUX
+ KERN_INFO " rootfs = 0x%p-0x%p\n"
+#endif
+#if DMA_UNCACHED_REGION > 0
+ KERN_INFO " DMA Zone = 0x%p-0x%p\n"
+#endif
+ , _stext, _etext,
+ __init_begin, __init_end,
+ _sdata, _edata,
+ (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000),
+ __bss_start, __bss_stop,
+ (void*)_ramstart, (void*)memory_end
+#ifdef CONFIG_MTD_UCLINUX
+ , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size)
+#endif
+#if DMA_UNCACHED_REGION > 0
+ , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend)
+#endif
+ );
+
+ /*
+ * give all the memory to the bootmap allocator, tell it to put the
+ * boot mem_map at the start of memory
+ */
+ bootmap_size = init_bootmem_node(NODE_DATA(0), memory_start >> PAGE_SHIFT, /* map goes here */
+ PAGE_OFFSET >> PAGE_SHIFT,
+ memory_end >> PAGE_SHIFT);
+ /*
+ * free the usable memory, we have to make sure we do not free
+ * the bootmem bitmap so we then reserve it after freeing it :-)
+ */
+ free_bootmem(memory_start, memory_end - memory_start);
+
+ reserve_bootmem(memory_start, bootmap_size);
+ /*
+ * get kmalloc into gear
+ */
+ paging_init();
+
+ /* check the size of the l1 area */
+ l1_length = _etext_l1 - _stext_l1;
+ if (l1_length > L1_CODE_LENGTH)
+ panic("L1 memory overflow\n");
+
+ l1_length = _ebss_l1 - _sdata_l1;
+ if (l1_length > L1_DATA_A_LENGTH)
+ panic("L1 memory overflow\n");
+
+ bf53x_cache_init();
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+# if defined(CONFIG_BFIN_SHARED_FLASH_ENET) && defined(CONFIG_BFIN533_STAMP)
+ /* setup BF533_STAMP CPLD to route AMS3 to Ethernet MAC */
+ bfin_write_FIO_DIR(bfin_read_FIO_DIR() | (1 << CONFIG_ENET_FLASH_PIN));
+ bfin_write_FIO_FLAG_S(1 << CONFIG_ENET_FLASH_PIN);
+ SSYNC();
+# endif
+# if defined (CONFIG_BFIN561_EZKIT)
+ bfin_write_FIO0_DIR(bfin_read_FIO0_DIR() | (1 << 12));
+ SSYNC();
+# endif /* defined (CONFIG_BFIN561_EZKIT) */
+#endif
+
+ printk(KERN_INFO "Hardware Trace Enabled\n");
+ bfin_write_TBUFCTL(0x03);
+}
+
+#if defined(CONFIG_BF561)
+static struct cpu cpu[2];
+#else
+static struct cpu cpu[1];
+#endif
+static int __init topology_init(void)
+{
+#if defined (CONFIG_BF561)
+ register_cpu(&cpu[0], 0);
+ register_cpu(&cpu[1], 1);
+ return 0;
+#else
+ return register_cpu(cpu, 0);
+#endif
+}
+
+subsys_initcall(topology_init);
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+u16 lock_kernel_check(u32 start, u32 end)
+{
+ if ((start <= (u32) _stext && end >= (u32) _end)
+ || (start >= (u32) _stext && end <= (u32) _end))
+ return IN_KERNEL;
+ return 0;
+}
+
+static unsigned short __init
+fill_cplbtab(struct cplb_tab *table,
+ unsigned long start, unsigned long end,
+ unsigned long block_size, unsigned long cplb_data)
+{
+ int i;
+
+ switch (block_size) {
+ case SIZE_4M:
+ i = 3;
+ break;
+ case SIZE_1M:
+ i = 2;
+ break;
+ case SIZE_4K:
+ i = 1;
+ break;
+ case SIZE_1K:
+ default:
+ i = 0;
+ break;
+ }
+
+ cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
+
+ while ((start < end) && (table->pos < table->size)) {
+
+ table->tab[table->pos++] = start;
+
+ if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
+ table->tab[table->pos++] =
+ cplb_data | CPLB_LOCK | CPLB_DIRTY;
+ else
+ table->tab[table->pos++] = cplb_data;
+
+ start += block_size;
+ }
+ return 0;
+}
+
+static unsigned short __init
+close_cplbtab(struct cplb_tab *table)
+{
+
+ while (table->pos < table->size) {
+
+ table->tab[table->pos++] = 0;
+ table->tab[table->pos++] = 0; /* !CPLB_VALID */
+ }
+ return 0;
+}
+
+static void __init generate_cpl_tables(void)
+{
+
+ u16 i, j, process;
+ u32 a_start, a_end, as, ae, as_1m;
+
+ struct cplb_tab *t_i = NULL;
+ struct cplb_tab *t_d = NULL;
+ struct s_cplb cplb;
+
+ cplb.init_i.size = MAX_CPLBS;
+ cplb.init_d.size = MAX_CPLBS;
+ cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
+ cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
+
+ cplb.init_i.pos = 0;
+ cplb.init_d.pos = 0;
+ cplb.switch_i.pos = 0;
+ cplb.switch_d.pos = 0;
+
+ cplb.init_i.tab = icplb_table;
+ cplb.init_d.tab = dcplb_table;
+ cplb.switch_i.tab = ipdt_table;
+ cplb.switch_d.tab = dpdt_table;
+
+ cplb_data[SDRAM_KERN].end = memory_end;
+
+#ifdef CONFIG_MTD_UCLINUX
+ cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
+ cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
+ cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
+# if defined(CONFIG_ROMFS_FS)
+ cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
+
+ /*
+ * The ROMFS_FS size is often not multiple of 1MB.
+ * This can cause multiple CPLB sets covering the same memory area.
+ * This will then cause multiple CPLB hit exceptions.
+ * Workaround: We ensure a contiguous memory area by extending the kernel
+ * memory section over the mtd section.
+ * For ROMFS_FS memory must be covered with ICPLBs anyways.
+ * So there is no difference between kernel and mtd memory setup.
+ */
+
+ cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
+ cplb_data[SDRAM_RAM_MTD].valid = 0;
+
+# endif
+#else
+ cplb_data[SDRAM_RAM_MTD].valid = 0;
+#endif
+
+ cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
+ cplb_data[SDRAM_DMAZ].end = _ramend;
+
+ cplb_data[RES_MEM].start = _ramend;
+ cplb_data[RES_MEM].end = physical_mem_end;
+
+ if (reserved_mem_dcache_on)
+ cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
+ else
+ cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
+
+ if (reserved_mem_icache_on)
+ cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
+ else
+ cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
+
+ for (i = ZERO_P; i <= L2_MEM; i++) {
+
+ if (cplb_data[i].valid) {
+
+ as_1m = cplb_data[i].start % SIZE_1M;
+
+ /* We need to make sure all sections are properly 1M aligned
+ * However between Kernel Memory and the Kernel mtd section, depending on the
+ * rootfs size, there can be overlapping memory areas.
+ */
+
+ if (as_1m && i!=L1I_MEM && i!=L1D_MEM) {
+#ifdef CONFIG_MTD_UCLINUX
+ if (i == SDRAM_RAM_MTD) {
+ if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
+ cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
+ else
+ cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
+ } else
+#endif
+ printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
+ cplb_data[i].name, cplb_data[i].start);
+ }
+
+ as = cplb_data[i].start % SIZE_4M;
+ ae = cplb_data[i].end % SIZE_4M;
+
+ if (as)
+ a_start = cplb_data[i].start + (SIZE_4M - (as));
+ else
+ a_start = cplb_data[i].start;
+
+ a_end = cplb_data[i].end - ae;
+
+ for (j = INITIAL_T; j <= SWITCH_T; j++) {
+
+ switch (j) {
+ case INITIAL_T:
+ if (cplb_data[i].attr & INITIAL_T) {
+ t_i = &cplb.init_i;
+ t_d = &cplb.init_d;
+ process = 1;
+ } else
+ process = 0;
+ break;
+ case SWITCH_T:
+ if (cplb_data[i].attr & SWITCH_T) {
+ t_i = &cplb.switch_i;
+ t_d = &cplb.switch_d;
+ process = 1;
+ } else
+ process = 0;
+ break;
+ default:
+ process = 0;
+ break;
+ }
+
+ if (process) {
+ if (cplb_data[i].attr & I_CPLB) {
+
+ if (cplb_data[i].psize) {
+ fill_cplbtab(t_i,
+ cplb_data[i].start,
+ cplb_data[i].end,
+ cplb_data[i].psize,
+ cplb_data[i].i_conf);
+ } else {
+ /*icplb_table */
+#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+ if (i == SDRAM_KERN) {
+ fill_cplbtab(t_i,
+ cplb_data[i].start,
+ cplb_data[i].end,
+ SIZE_4M,
+ cplb_data[i].i_conf);
+ } else
+#endif
+ {
+ fill_cplbtab(t_i,
+ cplb_data[i].start,
+ a_start,
+ SIZE_1M,
+ cplb_data[i].i_conf);
+ fill_cplbtab(t_i,
+ a_start,
+ a_end,
+ SIZE_4M,
+ cplb_data[i].i_conf);
+ fill_cplbtab(t_i, a_end,
+ cplb_data[i].end,
+ SIZE_1M,
+ cplb_data[i].i_conf);
+ }
+ }
+
+ }
+ if (cplb_data[i].attr & D_CPLB) {
+
+ if (cplb_data[i].psize) {
+ fill_cplbtab(t_d,
+ cplb_data[i].start,
+ cplb_data[i].end,
+ cplb_data[i].psize,
+ cplb_data[i].d_conf);
+ } else {
+/*dcplb_table*/
+ fill_cplbtab(t_d,
+ cplb_data[i].start,
+ a_start, SIZE_1M,
+ cplb_data[i].d_conf);
+ fill_cplbtab(t_d, a_start,
+ a_end, SIZE_4M,
+ cplb_data[i].d_conf);
+ fill_cplbtab(t_d, a_end,
+ cplb_data[i].end,
+ SIZE_1M,
+ cplb_data[i].d_conf);
+
+ }
+
+ }
+ }
+ }
+
+ }
+ }
+
+/* close tables */
+
+ close_cplbtab(&cplb.init_i);
+ close_cplbtab(&cplb.init_d);
+
+ cplb.init_i.tab[cplb.init_i.pos] = -1;
+ cplb.init_d.tab[cplb.init_d.pos] = -1;
+ cplb.switch_i.tab[cplb.switch_i.pos] = -1;
+ cplb.switch_d.tab[cplb.switch_d.pos] = -1;
+
+}
+
+#endif
+
+static inline u_long get_vco(void)
+{
+ u_long msel;
+ u_long vco;
+
+ msel = (bfin_read_PLL_CTL() >> 9) & 0x3F;
+ if (0 == msel)
+ msel = 64;
+
+ vco = CONFIG_CLKIN_HZ;
+ vco >>= (1 & bfin_read_PLL_CTL()); /* DF bit */
+ vco = msel * vco;
+ return vco;
+}
+
+/*Get the Core clock*/
+u_long get_cclk(void)
+{
+ u_long csel, ssel;
+ if (bfin_read_PLL_STAT() & 0x1)
+ return CONFIG_CLKIN_HZ;
+
+ ssel = bfin_read_PLL_DIV();
+ csel = ((ssel >> 4) & 0x03);
+ ssel &= 0xf;
+ if (ssel && ssel < (1 << csel)) /* SCLK > CCLK */
+ return get_vco() / ssel;
+ return get_vco() >> csel;
+}
+
+EXPORT_SYMBOL(get_cclk);
+
+/* Get the System clock */
+u_long get_sclk(void)
+{
+ u_long ssel;
+
+ if (bfin_read_PLL_STAT() & 0x1)
+ return CONFIG_CLKIN_HZ;
+
+ ssel = (bfin_read_PLL_DIV() & 0xf);
+ if (0 == ssel) {
+ printk(KERN_WARNING "Invalid System Clock\n");
+ ssel = 1;
+ }
+
+ return get_vco() / ssel;
+}
+
+EXPORT_SYMBOL(get_sclk);
+
+/*
+ * Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+ char *cpu, *mmu, *fpu, *name;
+ uint32_t revid;
+
+ u_long cclk = 0, sclk = 0;
+ u_int dcache_size = 0, dsup_banks = 0;
+
+ cpu = CPU;
+ mmu = "none";
+ fpu = "none";
+ revid = bfin_revid();
+ name = bfin_board_name;
+
+ cclk = get_cclk();
+ sclk = get_sclk();
+
+ seq_printf(m, "CPU:\t\tADSP-%s Rev. 0.%d\n"
+ "MMU:\t\t%s\n"
+ "FPU:\t\t%s\n"
+ "Core Clock:\t%9lu Hz\n"
+ "System Clock:\t%9lu Hz\n"
+ "BogoMips:\t%lu.%02lu\n"
+ "Calibration:\t%lu loops\n",
+ cpu, revid, mmu, fpu,
+ cclk,
+ sclk,
+ (loops_per_jiffy * HZ) / 500000,
+ ((loops_per_jiffy * HZ) / 5000) % 100,
+ (loops_per_jiffy * HZ));
+ seq_printf(m, "Board Name:\t%s\n", name);
+ seq_printf(m, "Board Memory:\t%ld MB\n", physical_mem_end >> 20);
+ seq_printf(m, "Kernel Memory:\t%ld MB\n", (unsigned long)_ramend >> 20);
+ if (bfin_read_IMEM_CONTROL() & (ENICPLB | IMC))
+ seq_printf(m, "I-CACHE:\tON\n");
+ else
+ seq_printf(m, "I-CACHE:\tOFF\n");
+ if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE))
+ seq_printf(m, "D-CACHE:\tON"
+#if defined CONFIG_BLKFIN_WB
+ " (write-back)"
+#elif defined CONFIG_BLKFIN_WT
+ " (write-through)"
+#endif
+ "\n");
+ else
+ seq_printf(m, "D-CACHE:\tOFF\n");
+
+
+ switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
+ case ACACHE_BSRAM:
+ seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
+ dcache_size = 16;
+ dsup_banks = 1;
+ break;
+ case ACACHE_BCACHE:
+ seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
+ dcache_size = 32;
+ dsup_banks = 2;
+ break;
+ case ASRAM_BSRAM:
+ seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
+ dcache_size = 0;
+ dsup_banks = 0;
+ break;
+ default:
+ break;
+ }
+
+
+ seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024);
+ seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size);
+ seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n",
+ BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES);
+ seq_printf(m,
+ "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n",
+ dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS,
+ BLKFIN_DLINES);
+#ifdef CONFIG_BLKFIN_CACHE_LOCK
+ switch (read_iloc()) {
+ case WAY0_L:
+ seq_printf(m, "Way0 Locked-Down\n");
+ break;
+ case WAY1_L:
+ seq_printf(m, "Way1 Locked-Down\n");
+ break;
+ case WAY01_L:
+ seq_printf(m, "Way0,Way1 Locked-Down\n");
+ break;
+ case WAY2_L:
+ seq_printf(m, "Way2 Locked-Down\n");
+ break;
+ case WAY02_L:
+ seq_printf(m, "Way0,Way2 Locked-Down\n");
+ break;
+ case WAY12_L:
+ seq_printf(m, "Way1,Way2 Locked-Down\n");
+ break;
+ case WAY012_L:
+ seq_printf(m, "Way0,Way1 & Way2 Locked-Down\n");
+ break;
+ case WAY3_L:
+ seq_printf(m, "Way3 Locked-Down\n");
+ break;
+ case WAY03_L:
+ seq_printf(m, "Way0,Way3 Locked-Down\n");
+ break;
+ case WAY13_L:
+ seq_printf(m, "Way1,Way3 Locked-Down\n");
+ break;
+ case WAY013_L:
+ seq_printf(m, "Way 0,Way1,Way3 Locked-Down\n");
+ break;
+ case WAY32_L:
+ seq_printf(m, "Way3,Way2 Locked-Down\n");
+ break;
+ case WAY320_L:
+ seq_printf(m, "Way3,Way2,Way0 Locked-Down\n");
+ break;
+ case WAY321_L:
+ seq_printf(m, "Way3,Way2,Way1 Locked-Down\n");
+ break;
+ case WAYALL_L:
+ seq_printf(m, "All Ways are locked\n");
+ break;
+ default:
+ seq_printf(m, "No Ways are locked\n");
+ }
+#endif
+ return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < NR_CPUS ? ((void *)0x12345678) : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
+};
+
+void cmdline_init(unsigned long r0)
+{
+ if (r0)
+ strncpy(command_line, (char *)r0, COMMAND_LINE_SIZE);
+}
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
new file mode 100644
index 00000000000..316e65c3439
--- /dev/null
+++ b/arch/blackfin/kernel/signal.c
@@ -0,0 +1,356 @@
+/*
+ * File: arch/blackfin/kernel/signal.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/signal.h>
+#include <linux/syscalls.h>
+#include <linux/ptrace.h>
+#include <linux/tty.h>
+#include <linux/personality.h>
+#include <linux/binfmts.h>
+#include <linux/freezer.h>
+
+#include <asm/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/ucontext.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+struct fdpic_func_descriptor {
+ unsigned long text;
+ unsigned long GOT;
+};
+
+struct rt_sigframe {
+ int sig;
+ struct siginfo *pinfo;
+ void *puc;
+ char retcode[8];
+ struct siginfo info;
+ struct ucontext uc;
+};
+
+asmlinkage int sys_sigaltstack(const stack_t * uss, stack_t * uoss)
+{
+ return do_sigaltstack(uss, uoss, rdusp());
+}
+
+static inline int
+rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *pr0)
+{
+ unsigned long usp = 0;
+ int err = 0;
+
+#define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x)
+
+ /* restore passed registers */
+ RESTORE(r0); RESTORE(r1); RESTORE(r2); RESTORE(r3);
+ RESTORE(r4); RESTORE(r5); RESTORE(r6); RESTORE(r7);
+ RESTORE(p0); RESTORE(p1); RESTORE(p2); RESTORE(p3);
+ RESTORE(p4); RESTORE(p5);
+ err |= __get_user(usp, &sc->sc_usp);
+ wrusp(usp);
+ RESTORE(a0w); RESTORE(a1w);
+ RESTORE(a0x); RESTORE(a1x);
+ RESTORE(astat);
+ RESTORE(rets);
+ RESTORE(pc);
+ RESTORE(retx);
+ RESTORE(fp);
+ RESTORE(i0); RESTORE(i1); RESTORE(i2); RESTORE(i3);
+ RESTORE(m0); RESTORE(m1); RESTORE(m2); RESTORE(m3);
+ RESTORE(l0); RESTORE(l1); RESTORE(l2); RESTORE(l3);
+ RESTORE(b0); RESTORE(b1); RESTORE(b2); RESTORE(b3);
+ RESTORE(lc0); RESTORE(lc1);
+ RESTORE(lt0); RESTORE(lt1);
+ RESTORE(lb0); RESTORE(lb1);
+ RESTORE(seqstat);
+
+ regs->orig_p0 = -1; /* disable syscall checks */
+
+ *pr0 = regs->r0;
+ return err;
+}
+
+asmlinkage int do_rt_sigreturn(unsigned long __unused)
+{
+ struct pt_regs *regs = (struct pt_regs *)__unused;
+ unsigned long usp = rdusp();
+ struct rt_sigframe *frame = (struct rt_sigframe *)(usp);
+ sigset_t set;
+ int r0;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+ goto badframe;
+
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->usp) == -EFAULT)
+ goto badframe;
+
+ return r0;
+
+ badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+static inline int rt_setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs)
+{
+ int err = 0;
+
+#define SETUP(x) err |= __put_user(regs->x, &sc->sc_##x)
+
+ SETUP(r0); SETUP(r1); SETUP(r2); SETUP(r3);
+ SETUP(r4); SETUP(r5); SETUP(r6); SETUP(r7);
+ SETUP(p0); SETUP(p1); SETUP(p2); SETUP(p3);
+ SETUP(p4); SETUP(p5);
+ err |= __put_user(rdusp(), &sc->sc_usp);
+ SETUP(a0w); SETUP(a1w);
+ SETUP(a0x); SETUP(a1x);
+ SETUP(astat);
+ SETUP(rets);
+ SETUP(pc);
+ SETUP(retx);
+ SETUP(fp);
+ SETUP(i0); SETUP(i1); SETUP(i2); SETUP(i3);
+ SETUP(m0); SETUP(m1); SETUP(m2); SETUP(m3);
+ SETUP(l0); SETUP(l1); SETUP(l2); SETUP(l3);
+ SETUP(b0); SETUP(b1); SETUP(b2); SETUP(b3);
+ SETUP(lc0); SETUP(lc1);
+ SETUP(lt0); SETUP(lt1);
+ SETUP(lb0); SETUP(lb1);
+ SETUP(seqstat);
+
+ return err;
+}
+
+static inline void push_cache(unsigned long vaddr, unsigned int len)
+{
+ flush_icache_range(vaddr, vaddr + len);
+}
+
+static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long usp;
+
+ /* Default to using normal stack. */
+ usp = rdusp();
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (!on_sig_stack(usp))
+ usp = current->sas_ss_sp + current->sas_ss_size;
+ }
+ return (void *)((usp - frame_size) & -8UL);
+}
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
+ sigset_t * set, struct pt_regs *regs)
+{
+ struct rt_sigframe *frame;
+ int err = 0;
+
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+
+ err |= __put_user((current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32
+ ? current_thread_info()->exec_domain->
+ signal_invmap[sig] : 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);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |=
+ __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(rdusp()), &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= rt_setup_sigcontext(&frame->uc.uc_mcontext, regs);
+ err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Set up to return from userspace. */
+ err |= __put_user(0x28, &(frame->retcode[0]));
+ err |= __put_user(0xe1, &(frame->retcode[1]));
+ err |= __put_user(0xad, &(frame->retcode[2]));
+ err |= __put_user(0x00, &(frame->retcode[3]));
+ err |= __put_user(0xa0, &(frame->retcode[4]));
+ err |= __put_user(0x00, &(frame->retcode[5]));
+
+ if (err)
+ goto give_sigsegv;
+
+ push_cache((unsigned long)&frame->retcode, sizeof(frame->retcode));
+
+ /* Set up registers for signal handler */
+ wrusp((unsigned long)frame);
+ if (get_personality & FDPIC_FUNCPTRS) {
+ struct fdpic_func_descriptor __user *funcptr =
+ (struct fdpic_func_descriptor *) ka->sa.sa_handler;
+ __get_user(regs->pc, &funcptr->text);
+ __get_user(regs->p3, &funcptr->GOT);
+ } else
+ regs->pc = (unsigned long)ka->sa.sa_handler;
+ regs->rets = (unsigned long)(frame->retcode);
+
+ regs->r0 = frame->sig;
+ regs->r1 = (unsigned long)(&frame->info);
+ regs->r2 = (unsigned long)(&frame->uc);
+
+ return 0;
+
+ give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+ return -EFAULT;
+}
+
+static inline void
+handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
+{
+ switch (regs->r0) {
+ case -ERESTARTNOHAND:
+ if (!has_handler)
+ goto do_restart;
+ regs->r0 = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (has_handler && !(ka->sa.sa_flags & SA_RESTART)) {
+ regs->r0 = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ do_restart:
+ regs->p0 = regs->orig_p0;
+ regs->r0 = regs->orig_r0;
+ regs->pc -= 2;
+ break;
+ }
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static int
+handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
+ sigset_t *oldset, struct pt_regs *regs)
+{
+ int ret;
+
+ /* are we from a system call? to see pt_regs->orig_p0 */
+ if (regs->orig_p0 >= 0)
+ /* If so, check system call restarting.. */
+ handle_restart(regs, ka, 1);
+
+ /* set up the stack frame */
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
+
+ if (ret == 0) {
+ 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;
+}
+
+/*
+ * 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
+ * mistake.
+ *
+ * Note that we go through the signals twice: once to check the signals
+ * that the kernel can handle, and then we build all the user-level signal
+ * handling stack-frames in one go after that.
+ */
+asmlinkage void do_signal(struct pt_regs *regs)
+{
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+ sigset_t *oldset;
+
+ current->thread.esp0 = (unsigned long)regs;
+
+ if (try_to_freeze())
+ goto no_signal;
+
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
+ oldset = &current->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+ /* a signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TIF_RESTORE_SIGMASK flag */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
+
+ return;
+ }
+
+no_signal:
+ /* Did we come from a system call? */
+ if (regs->orig_p0 >= 0)
+ /* Restart the system call - no handlers present */
+ handle_restart(regs, NULL, 0);
+
+ /* if there's no signal to deliver, we just put the saved sigmask
+ * back */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+}
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
new file mode 100644
index 00000000000..f436e6743f5
--- /dev/null
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -0,0 +1,115 @@
+/*
+ * File: arch/blackfin/kernel/sys_bfin.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/bfin
+ * platform.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+#include <asm/ipc.h>
+#include <asm/dma.h>
+#include <asm/unistd.h>
+
+/*
+ * sys_pipe() is the normal C calling standard for creating
+ * a pipe. It's not the way unix traditionally does this, though.
+ */
+asmlinkage int sys_pipe(unsigned long *fildes)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ if (copy_to_user(fildes, fd, 2 * sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+/* common code for old and new mmaps */
+static inline long
+do_mmap2(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ int error = -EBADF;
+ struct file *file = NULL;
+
+ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
+ if (!(flags & MAP_ANONYMOUS)) {
+ file = fget(fd);
+ if (!file)
+ goto out;
+ }
+
+ down_write(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up_write(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+ out:
+ return error;
+}
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ return do_mmap2(addr, len, prot, flags, fd, pgoff);
+}
+
+asmlinkage int sys_getpagesize(void)
+{
+ return PAGE_SIZE;
+}
+
+asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags)
+{
+ return sram_alloc_with_lsl(size, flags);
+}
+
+asmlinkage int sys_sram_free(const void *addr)
+{
+ return sram_free_with_lsl(addr);
+}
+
+asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len)
+{
+ return safe_dma_memcpy(dest, src, len);
+}
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
new file mode 100644
index 00000000000..f578176b6d9
--- /dev/null
+++ b/arch/blackfin/kernel/time.c
@@ -0,0 +1,326 @@
+/*
+ * File: arch/blackfin/kernel/time.c
+ * Based on: none - original work
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the bfin-specific time handling details.
+ * Most of the stuff is located in the machine specific files.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/profile.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/irq.h>
+
+#include <asm/blackfin.h>
+
+/* This is an NTP setting */
+#define TICK_SIZE (tick_nsec / 1000)
+
+static void time_sched_init(irqreturn_t(*timer_routine)
+ (int, void *));
+static unsigned long gettimeoffset(void);
+static inline void do_leds(void);
+
+#if (defined(CONFIG_BFIN_ALIVE_LED) || defined(CONFIG_BFIN_IDLE_LED))
+void __init init_leds(void)
+{
+ unsigned int tmp = 0;
+
+#if defined(CONFIG_BFIN_ALIVE_LED)
+ /* config pins as output. */
+ tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_DPORT();
+ SSYNC();
+ bfin_write_CONFIG_BFIN_ALIVE_LED_DPORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN);
+ SSYNC();
+
+ /* First set led be off */
+ tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
+ SSYNC();
+ bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp | CONFIG_BFIN_ALIVE_LED_PIN); /* light off */
+ SSYNC();
+#endif
+
+#if defined(CONFIG_BFIN_IDLE_LED)
+ /* config pins as output. */
+ tmp = bfin_read_CONFIG_BFIN_IDLE_LED_DPORT();
+ SSYNC();
+ bfin_write_CONFIG_BFIN_IDLE_LED_DPORT(tmp | CONFIG_BFIN_IDLE_LED_PIN);
+ SSYNC();
+
+ /* First set led be off */
+ tmp = bfin_read_CONFIG_BFIN_IDLE_LED_PORT();
+ SSYNC();
+ bfin_write_CONFIG_BFIN_IDLE_LED_PORT(tmp | CONFIG_BFIN_IDLE_LED_PIN); /* light off */
+ SSYNC();
+#endif
+}
+#else
+void __init init_leds(void)
+{
+}
+#endif
+
+#if defined(CONFIG_BFIN_ALIVE_LED)
+static inline void do_leds(void)
+{
+ static unsigned int count = 50;
+ static int flag = 0;
+ unsigned short tmp = 0;
+
+ if (--count == 0) {
+ count = 50;
+ flag = ~flag;
+ }
+ tmp = bfin_read_CONFIG_BFIN_ALIVE_LED_PORT();
+ SSYNC();
+
+ if (flag)
+ tmp &= ~CONFIG_BFIN_ALIVE_LED_PIN; /* light on */
+ else
+ tmp |= CONFIG_BFIN_ALIVE_LED_PIN; /* light off */
+
+ bfin_write_CONFIG_BFIN_ALIVE_LED_PORT(tmp);
+ SSYNC();
+
+}
+#else
+static inline void do_leds(void)
+{
+}
+#endif
+
+static struct irqaction bfin_timer_irq = {
+ .name = "BFIN Timer Tick",
+ .flags = IRQF_DISABLED
+};
+
+/*
+ * The way that the Blackfin core timer works is:
+ * - CCLK is divided by a programmable 8-bit pre-scaler (TSCALE)
+ * - Every time TSCALE ticks, a 32bit is counted down (TCOUNT)
+ *
+ * If you take the fastest clock (1ns, or 1GHz to make the math work easier)
+ * 10ms is 10,000,000 clock ticks, which fits easy into a 32-bit counter
+ * (32 bit counter is 4,294,967,296ns or 4.2 seconds) so, we don't need
+ * to use TSCALE, and program it to zero (which is pass CCLK through).
+ * If you feel like using it, try to keep HZ * TIMESCALE to some
+ * value that divides easy (like power of 2).
+ */
+
+#define TIME_SCALE 1
+
+static void
+time_sched_init(irqreturn_t(*timer_routine) (int, void *))
+{
+ u32 tcount;
+
+ /* power up the timer, but don't enable it just yet */
+ bfin_write_TCNTL(1);
+ CSYNC();
+
+ /*
+ * the TSCALE prescaler counter.
+ */
+ bfin_write_TSCALE((TIME_SCALE - 1));
+
+ tcount = ((get_cclk() / (HZ * TIME_SCALE)) - 1);
+ bfin_write_TPERIOD(tcount);
+ bfin_write_TCOUNT(tcount);
+
+ /* now enable the timer */
+ CSYNC();
+
+ bfin_write_TCNTL(7);
+
+ bfin_timer_irq.handler = (irq_handler_t)timer_routine;
+ /* call setup_irq instead of request_irq because request_irq calls
+ * kmalloc which has not been initialized yet
+ */
+ setup_irq(IRQ_CORETMR, &bfin_timer_irq);
+}
+
+/*
+ * Should return useconds since last timer tick
+ */
+static unsigned long gettimeoffset(void)
+{
+ unsigned long offset;
+ unsigned long clocks_per_jiffy;
+
+ clocks_per_jiffy = bfin_read_TPERIOD();
+ offset =
+ (clocks_per_jiffy -
+ bfin_read_TCOUNT()) / (((clocks_per_jiffy + 1) * HZ) /
+ USEC_PER_SEC);
+
+ /* Check if we just wrapped the counters and maybe missed a tick */
+ if ((bfin_read_ILAT() & (1 << IRQ_CORETMR))
+ && (offset < (100000 / HZ / 2)))
+ offset += (USEC_PER_SEC / HZ);
+
+ return offset;
+}
+
+static inline int set_rtc_mmss(unsigned long nowtime)
+{
+ return 0;
+}
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+#ifdef CONFIG_CORE_TIMER_IRQ_L1
+irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text));
+#endif
+
+irqreturn_t timer_interrupt(int irq, void *dummy)
+{
+ /* last time the cmos clock got updated */
+ static long last_rtc_update = 0;
+
+ write_seqlock(&xtime_lock);
+
+ do_timer(1);
+ do_leds();
+
+#ifndef CONFIG_SMP
+ update_process_times(user_mode(get_irq_regs()));
+#endif
+ profile_tick(CPU_PROFILING);
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ */
+
+ if (ntp_synced() &&
+ xtime.tv_sec > last_rtc_update + 660 &&
+ (xtime.tv_nsec / NSEC_PER_USEC) >=
+ 500000 - ((unsigned)TICK_SIZE) / 2
+ && (xtime.tv_nsec / NSEC_PER_USEC) <=
+ 500000 + ((unsigned)TICK_SIZE) / 2) {
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ /* Do it again in 60s. */
+ last_rtc_update = xtime.tv_sec - 600;
+ }
+ write_sequnlock(&xtime_lock);
+ return IRQ_HANDLED;
+}
+
+void __init time_init(void)
+{
+ time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */
+
+#ifdef CONFIG_RTC_DRV_BFIN
+ /* [#2663] hack to filter junk RTC values that would cause
+ * userspace to have to deal with time values greater than
+ * 2^31 seconds (which uClibc cannot cope with yet)
+ */
+ if ((bfin_read_RTC_STAT() & 0xC0000000) == 0xC0000000) {
+ printk(KERN_NOTICE "bfin-rtc: invalid date; resetting\n");
+ bfin_write_RTC_STAT(0);
+ }
+#endif
+
+ /* Initialize xtime. From now on, xtime is updated with timer interrupts */
+ xtime.tv_sec = secs_since_1970;
+ xtime.tv_nsec = 0;
+
+ wall_to_monotonic.tv_sec = -xtime.tv_sec;
+
+ time_sched_init(timer_interrupt);
+}
+
+#ifndef CONFIG_GENERIC_TIME
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ unsigned long seq;
+ unsigned long usec, sec;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+ usec = gettimeoffset();
+ sec = xtime.tv_sec;
+ usec += (xtime.tv_nsec / NSEC_PER_USEC);
+ }
+ while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+ while (usec >= USEC_PER_SEC) {
+ usec -= USEC_PER_SEC;
+ sec++;
+ }
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+}
+EXPORT_SYMBOL(do_gettimeofday);
+
+int do_settimeofday(struct timespec *tv)
+{
+ time_t wtm_sec, sec = tv->tv_sec;
+ long wtm_nsec, nsec = tv->tv_nsec;
+
+ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+ return -EINVAL;
+
+ write_seqlock_irq(&xtime_lock);
+ /*
+ * This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ nsec -= (gettimeoffset() * NSEC_PER_USEC);
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+ set_normalized_timespec(&xtime, sec, nsec);
+ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+ ntp_clear();
+
+ write_sequnlock_irq(&xtime_lock);
+ clock_was_set();
+
+ return 0;
+}
+EXPORT_SYMBOL(do_settimeofday);
+#endif /* !CONFIG_GENERIC_TIME */
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ */
+unsigned long long sched_clock(void)
+{
+ return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ);
+}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
new file mode 100644
index 00000000000..9556b73de80
--- /dev/null
+++ b/arch/blackfin/kernel/traps.c
@@ -0,0 +1,649 @@
+/*
+ * File: arch/blackfin/kernel/traps.c
+ * Based on:
+ * Author: Hamish Macdonald
+ *
+ * Created:
+ * Description: uses S/W interrupt 15 for the system calls
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <asm/uaccess.h>
+#include <asm/traps.h>
+#include <asm/cacheflush.h>
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+#include <asm/irq_handler.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+#ifdef CONFIG_KGDB
+# include <linux/debugger.h>
+# include <linux/kgdb.h>
+#endif
+
+/* Initiate the event table handler */
+void __init trap_init(void)
+{
+ CSYNC();
+ bfin_write_EVT3(trap);
+ CSYNC();
+}
+
+asmlinkage void trap_c(struct pt_regs *fp);
+
+int kstack_depth_to_print = 48;
+
+static int printk_address(unsigned long address)
+{
+ struct vm_list_struct *vml;
+ struct task_struct *p;
+ struct mm_struct *mm;
+
+#ifdef CONFIG_KALLSYMS
+ unsigned long offset = 0, symsize;
+ const char *symname;
+ char *modname;
+ char *delim = ":";
+ char namebuf[128];
+
+ /* look up the address and see if we are in kernel space */
+ symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf);
+
+ if (symname) {
+ /* yeah! kernel space! */
+ if (!modname)
+ modname = delim = "";
+ return printk("<0x%p> { %s%s%s%s + 0x%lx }",
+ (void*)address, delim, modname, delim, symname,
+ (unsigned long)offset);
+
+ }
+#endif
+
+ /* looks like we're off in user-land, so let's walk all the
+ * mappings of all our processes and see if we can't be a whee
+ * bit more specific
+ */
+ write_lock_irq(&tasklist_lock);
+ for_each_process(p) {
+ mm = get_task_mm(p);
+ if (!mm)
+ continue;
+
+ vml = mm->context.vmlist;
+ while (vml) {
+ struct vm_area_struct *vma = vml->vma;
+
+ if (address >= vma->vm_start && address < vma->vm_end) {
+ char *name = p->comm;
+ struct file *file = vma->vm_file;
+ if (file) {
+ char _tmpbuf[256];
+ name = d_path(file->f_dentry,
+ file->f_vfsmnt,
+ _tmpbuf,
+ sizeof(_tmpbuf));
+ }
+
+ write_unlock_irq(&tasklist_lock);
+ return printk("<0x%p> [ %s + 0x%lx ]",
+ (void*)address, name,
+ (unsigned long)
+ ((address - vma->vm_start) +
+ (vma->vm_pgoff << PAGE_SHIFT)));
+ }
+
+ vml = vml->next;
+ }
+ }
+ write_unlock_irq(&tasklist_lock);
+
+ /* we were unable to find this address anywhere */
+ return printk("[<0x%p>]", (void*)address);
+}
+
+#define trace_buffer_save(x) \
+ do { \
+ (x) = bfin_read_TBUFCTL(); \
+ bfin_write_TBUFCTL((x) & ~TBUFEN); \
+ } while (0)
+#define trace_buffer_restore(x) \
+ do { \
+ bfin_write_TBUFCTL((x)); \
+ } while (0)
+
+asmlinkage void trap_c(struct pt_regs *fp)
+{
+ int j, sig = 0;
+ siginfo_t info;
+ unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
+
+#ifdef CONFIG_KGDB
+# define CHK_DEBUGGER_TRAP() do { CHK_DEBUGGER(trapnr, sig, info.si_code, fp,); } while (0)
+# define CHK_DEBUGGER_TRAP_MAYBE() do { if (kgdb_connected) CHK_DEBUGGER_TRAP(); } while (0)
+#else
+# define CHK_DEBUGGER_TRAP() do { } while (0)
+# define CHK_DEBUGGER_TRAP_MAYBE() do { } while (0)
+#endif
+
+ trace_buffer_save(j);
+
+ /* trap_c() will be called for exceptions. During exceptions
+ * processing, the pc value should be set with retx value.
+ * With this change we can cleanup some code in signal.c- TODO
+ */
+ fp->orig_pc = fp->retx;
+ /* printk("exception: 0x%x, ipend=%x, reti=%x, retx=%x\n",
+ trapnr, fp->ipend, fp->pc, fp->retx); */
+
+ /* send the appropriate signal to the user program */
+ switch (trapnr) {
+
+ /* This table works in conjuction with the one in ./mach-common/entry.S
+ * Some exceptions are handled there (in assembly, in exception space)
+ * Some are handled here, (in C, in interrupt space)
+ * Some, like CPLB, are handled in both, where the normal path is
+ * handled in assembly/exception space, and the error path is handled
+ * here
+ */
+
+ /* 0x00 - Linux Syscall, getting here is an error */
+ /* 0x01 - userspace gdb breakpoint, handled here */
+ case VEC_EXCPT01:
+ info.si_code = TRAP_ILLTRAP;
+ sig = SIGTRAP;
+ CHK_DEBUGGER_TRAP_MAYBE();
+ /* Check if this is a breakpoint in kernel space */
+ if (fp->ipend & 0xffc0)
+ return;
+ else
+ break;
+#ifdef CONFIG_KGDB
+ case VEC_EXCPT02 : /* gdb connection */
+ info.si_code = TRAP_ILLTRAP;
+ sig = SIGTRAP;
+ CHK_DEBUGGER_TRAP();
+ return;
+#else
+ /* 0x02 - User Defined, Caught by default */
+#endif
+ /* 0x03 - Atomic test and set */
+ case VEC_EXCPT03:
+ info.si_code = SEGV_STACKFLOW;
+ sig = SIGSEGV;
+ printk(KERN_EMERG EXC_0x03);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x04 - spinlock - handled by _ex_spinlock,
+ getting here is an error */
+ /* 0x05 - User Defined, Caught by default */
+ /* 0x06 - User Defined, Caught by default */
+ /* 0x07 - User Defined, Caught by default */
+ /* 0x08 - User Defined, Caught by default */
+ /* 0x09 - User Defined, Caught by default */
+ /* 0x0A - User Defined, Caught by default */
+ /* 0x0B - User Defined, Caught by default */
+ /* 0x0C - User Defined, Caught by default */
+ /* 0x0D - User Defined, Caught by default */
+ /* 0x0E - User Defined, Caught by default */
+ /* 0x0F - User Defined, Caught by default */
+ /* 0x10 HW Single step, handled here */
+ case VEC_STEP:
+ info.si_code = TRAP_STEP;
+ sig = SIGTRAP;
+ CHK_DEBUGGER_TRAP_MAYBE();
+ /* Check if this is a single step in kernel space */
+ if (fp->ipend & 0xffc0)
+ return;
+ else
+ break;
+ /* 0x11 - Trace Buffer Full, handled here */
+ case VEC_OVFLOW:
+ info.si_code = TRAP_TRACEFLOW;
+ sig = SIGTRAP;
+ printk(KERN_EMERG EXC_0x11);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x12 - Reserved, Caught by default */
+ /* 0x13 - Reserved, Caught by default */
+ /* 0x14 - Reserved, Caught by default */
+ /* 0x15 - Reserved, Caught by default */
+ /* 0x16 - Reserved, Caught by default */
+ /* 0x17 - Reserved, Caught by default */
+ /* 0x18 - Reserved, Caught by default */
+ /* 0x19 - Reserved, Caught by default */
+ /* 0x1A - Reserved, Caught by default */
+ /* 0x1B - Reserved, Caught by default */
+ /* 0x1C - Reserved, Caught by default */
+ /* 0x1D - Reserved, Caught by default */
+ /* 0x1E - Reserved, Caught by default */
+ /* 0x1F - Reserved, Caught by default */
+ /* 0x20 - Reserved, Caught by default */
+ /* 0x21 - Undefined Instruction, handled here */
+ case VEC_UNDEF_I:
+ info.si_code = ILL_ILLOPC;
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x21);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x22 - Illegal Instruction Combination, handled here */
+ case VEC_ILGAL_I:
+ info.si_code = ILL_ILLPARAOP;
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x22);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x23 - Data CPLB Protection Violation,
+ normal case is handled in _cplb_hdr */
+ case VEC_CPLB_VL:
+ info.si_code = ILL_CPLB_VI;
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x23);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x24 - Data access misaligned, handled here */
+ case VEC_MISALI_D:
+ info.si_code = BUS_ADRALN;
+ sig = SIGBUS;
+ printk(KERN_EMERG EXC_0x24);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x25 - Unrecoverable Event, handled here */
+ case VEC_UNCOV:
+ info.si_code = ILL_ILLEXCPT;
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x25);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
+ error case is handled here */
+ case VEC_CPLB_M:
+ info.si_code = BUS_ADRALN;
+ sig = SIGBUS;
+ printk(KERN_EMERG EXC_0x26);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
+ case VEC_CPLB_MHIT:
+ info.si_code = ILL_CPLB_MULHIT;
+#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
+ sig = SIGSEGV;
+ printk(KERN_EMERG "\n\nNULL pointer access (probably)\n");
+#else
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x27);
+#endif
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x28 - Emulation Watchpoint, handled here */
+ case VEC_WATCH:
+ info.si_code = TRAP_WATCHPT;
+ sig = SIGTRAP;
+ pr_debug(EXC_0x28);
+ CHK_DEBUGGER_TRAP_MAYBE();
+ /* Check if this is a watchpoint in kernel space */
+ if (fp->ipend & 0xffc0)
+ return;
+ else
+ break;
+#ifdef CONFIG_BF535
+ /* 0x29 - Instruction fetch access error (535 only) */
+ case VEC_ISTRU_VL: /* ADSP-BF535 only (MH) */
+ info.si_code = BUS_OPFETCH;
+ sig = SIGBUS;
+ printk(KERN_EMERG "BF535: VEC_ISTRU_VL\n");
+ CHK_DEBUGGER_TRAP();
+ break;
+#else
+ /* 0x29 - Reserved, Caught by default */
+#endif
+ /* 0x2A - Instruction fetch misaligned, handled here */
+ case VEC_MISALI_I:
+ info.si_code = BUS_ADRALN;
+ sig = SIGBUS;
+ printk(KERN_EMERG EXC_0x2A);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x2B - Instruction CPLB protection Violation,
+ handled in _cplb_hdr */
+ case VEC_CPLB_I_VL:
+ info.si_code = ILL_CPLB_VI;
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x2B);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
+ case VEC_CPLB_I_M:
+ info.si_code = ILL_CPLB_MISS;
+ sig = SIGBUS;
+ printk(KERN_EMERG EXC_0x2C);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x2D - Instruction CPLB Multiple Hits, handled here */
+ case VEC_CPLB_I_MHIT:
+ info.si_code = ILL_CPLB_MULHIT;
+#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
+ sig = SIGSEGV;
+ printk(KERN_EMERG "\n\nJump to address 0 - 0x0fff\n");
+#else
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x2D);
+#endif
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x2E - Illegal use of Supervisor Resource, handled here */
+ case VEC_ILL_RES:
+ info.si_code = ILL_PRVOPC;
+ sig = SIGILL;
+ printk(KERN_EMERG EXC_0x2E);
+ CHK_DEBUGGER_TRAP();
+ break;
+ /* 0x2F - Reserved, Caught by default */
+ /* 0x30 - Reserved, Caught by default */
+ /* 0x31 - Reserved, Caught by default */
+ /* 0x32 - Reserved, Caught by default */
+ /* 0x33 - Reserved, Caught by default */
+ /* 0x34 - Reserved, Caught by default */
+ /* 0x35 - Reserved, Caught by default */
+ /* 0x36 - Reserved, Caught by default */
+ /* 0x37 - Reserved, Caught by default */
+ /* 0x38 - Reserved, Caught by default */
+ /* 0x39 - Reserved, Caught by default */
+ /* 0x3A - Reserved, Caught by default */
+ /* 0x3B - Reserved, Caught by default */
+ /* 0x3C - Reserved, Caught by default */
+ /* 0x3D - Reserved, Caught by default */
+ /* 0x3E - Reserved, Caught by default */
+ /* 0x3F - Reserved, Caught by default */
+ default:
+ info.si_code = TRAP_ILLTRAP;
+ sig = SIGTRAP;
+ printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
+ (fp->seqstat & SEQSTAT_EXCAUSE));
+ CHK_DEBUGGER_TRAP();
+ break;
+ }
+
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_addr = (void *)fp->pc;
+ force_sig_info(sig, &info, current);
+ if (sig != 0 && sig != SIGTRAP) {
+ unsigned long stack;
+ dump_bfin_regs(fp, (void *)fp->retx);
+ dump_bfin_trace_buffer();
+ show_stack(current, &stack);
+ if (current->mm == NULL)
+ panic("Kernel exception");
+ }
+
+ /* if the address that we are about to return to is not valid, set it
+ * to a valid address, if we have a current application or panic
+ */
+ if (!(fp->pc <= physical_mem_end
+#if L1_CODE_LENGTH != 0
+ || (fp->pc >= L1_CODE_START &&
+ fp->pc <= (L1_CODE_START + L1_CODE_LENGTH))
+#endif
+ )) {
+ if (current->mm) {
+ fp->pc = current->mm->start_code;
+ } else {
+ printk(KERN_EMERG "I can't return to memory that doesn't exist - bad things happen\n");
+ panic("Help - I've fallen and can't get up\n");
+ }
+ }
+
+ trace_buffer_restore(j);
+ return;
+}
+
+/* Typical exception handling routines */
+
+void dump_bfin_trace_buffer(void)
+{
+ int tflags;
+ trace_buffer_save(tflags);
+
+ if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) {
+ int i;
+ printk(KERN_EMERG "Hardware Trace:\n");
+ for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) {
+ printk(KERN_EMERG "%2i Target : ", i);
+ printk_address((unsigned long)bfin_read_TBUF());
+ printk("\n" KERN_EMERG " Source : ");
+ printk_address((unsigned long)bfin_read_TBUF());
+ printk("\n");
+ }
+ }
+
+ trace_buffer_restore(tflags);
+}
+EXPORT_SYMBOL(dump_bfin_trace_buffer);
+
+static void show_trace(struct task_struct *tsk, unsigned long *sp)
+{
+ unsigned long addr;
+
+ printk("\nCall Trace:");
+#ifdef CONFIG_KALLSYMS
+ printk("\n");
+#endif
+
+ while (!kstack_end(sp)) {
+ addr = *sp++;
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (kernel_text_address(addr))
+ print_ip_sym(addr);
+ }
+
+ printk("\n");
+}
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+ unsigned long *endstack, addr;
+ int i;
+
+ /* Cannot call dump_bfin_trace_buffer() here as show_stack() is
+ * called externally in some places in the kernel.
+ */
+
+ if (!stack) {
+ if (task)
+ stack = (unsigned long *)task->thread.ksp;
+ else
+ stack = (unsigned long *)&stack;
+ }
+
+ addr = (unsigned long)stack;
+ endstack = (unsigned long *)PAGE_ALIGN(addr);
+
+ printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (stack + 1 > endstack)
+ break;
+ if (i % 8 == 0)
+ printk("\n" KERN_EMERG " ");
+ printk(" %08lx", *stack++);
+ }
+
+ show_trace(task, stack);
+}
+
+void dump_stack(void)
+{
+ unsigned long stack;
+ int tflags;
+ trace_buffer_save(tflags);
+ dump_bfin_trace_buffer();
+ show_stack(current, &stack);
+ trace_buffer_restore(tflags);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
+{
+ if (current->pid) {
+ printk("\nCURRENT PROCESS:\n\n");
+ printk("COMM=%s PID=%d\n", current->comm, current->pid);
+ } else {
+ printk
+ ("\nNo Valid pid - Either things are really messed up, or you are in the kernel\n");
+ }
+
+ if (current->mm) {
+ printk("TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
+ "BSS = 0x%p-0x%p USER-STACK = 0x%p\n\n",
+ (void*)current->mm->start_code,
+ (void*)current->mm->end_code,
+ (void*)current->mm->start_data,
+ (void*)current->mm->end_data,
+ (void*)current->mm->end_data,
+ (void*)current->mm->brk,
+ (void*)current->mm->start_stack);
+ }
+
+ printk("return address: 0x%p; contents of [PC-16...PC+8]:\n", retaddr);
+ if (retaddr != 0 && retaddr <= (void*)physical_mem_end
+#if L1_CODE_LENGTH != 0
+ /* FIXME: Copy the code out of L1 Instruction SRAM through dma
+ memcpy. */
+ && !(retaddr >= (void*)L1_CODE_START
+ && retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH))
+#endif
+ ) {
+ int i = 0;
+ unsigned short x = 0;
+ for (i = -16; i < 8; i++) {
+ if (get_user(x, (unsigned short *)retaddr + i))
+ break;
+#ifndef CONFIG_DEBUG_HWERR
+ /* If one of the last few instructions was a STI
+ * it is likily that the error occured awhile ago
+ * and we just noticed
+ */
+ if (x >= 0x0040 && x <= 0x0047 && i <= 0)
+ panic("\n\nWARNING : You should reconfigure the kernel to turn on\n"
+ " 'Hardware error interrupt debugging'\n"
+ " The rest of this error is meanless\n");
+#endif
+
+ if (i == -8)
+ printk("\n");
+ if (i == 0)
+ printk("X\n");
+ printk("%04x ", x);
+ }
+ } else
+ printk("Cannot look at the [PC] for it is in unreadable L1 SRAM - sorry\n");
+
+ printk("\n\n");
+
+ printk("RETE: %08lx RETN: %08lx RETX: %08lx RETS: %08lx\n",
+ fp->rete, fp->retn, fp->retx, fp->rets);
+ printk("IPEND: %04lx SYSCFG: %04lx\n", fp->ipend, fp->syscfg);
+ printk("SEQSTAT: %08lx SP: %08lx\n", (long)fp->seqstat, (long)fp);
+ printk("R0: %08lx R1: %08lx R2: %08lx R3: %08lx\n",
+ fp->r0, fp->r1, fp->r2, fp->r3);
+ printk("R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
+ fp->r4, fp->r5, fp->r6, fp->r7);
+ printk("P0: %08lx P1: %08lx P2: %08lx P3: %08lx\n",
+ fp->p0, fp->p1, fp->p2, fp->p3);
+ printk("P4: %08lx P5: %08lx FP: %08lx\n", fp->p4, fp->p5, fp->fp);
+ printk("A0.w: %08lx A0.x: %08lx A1.w: %08lx A1.x: %08lx\n",
+ fp->a0w, fp->a0x, fp->a1w, fp->a1x);
+
+ printk("LB0: %08lx LT0: %08lx LC0: %08lx\n", fp->lb0, fp->lt0,
+ fp->lc0);
+ printk("LB1: %08lx LT1: %08lx LC1: %08lx\n", fp->lb1, fp->lt1,
+ fp->lc1);
+ printk("B0: %08lx L0: %08lx M0: %08lx I0: %08lx\n", fp->b0, fp->l0,
+ fp->m0, fp->i0);
+ printk("B1: %08lx L1: %08lx M1: %08lx I1: %08lx\n", fp->b1, fp->l1,
+ fp->m1, fp->i1);
+ printk("B2: %08lx L2: %08lx M2: %08lx I2: %08lx\n", fp->b2, fp->l2,
+ fp->m2, fp->i2);
+ printk("B3: %08lx L3: %08lx M3: %08lx I3: %08lx\n", fp->b3, fp->l3,
+ fp->m3, fp->i3);
+
+ printk("\nUSP: %08lx ASTAT: %08lx\n", rdusp(), fp->astat);
+ if ((long)fp->seqstat & SEQSTAT_EXCAUSE) {
+ printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
+ printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
+ }
+
+ printk("\n\n");
+}
+
+#ifdef CONFIG_SYS_BFIN_SPINLOCK_L1
+asmlinkage int sys_bfin_spinlock(int *spinlock)__attribute__((l1_text));
+#endif
+
+asmlinkage int sys_bfin_spinlock(int *spinlock)
+{
+ int ret = 0;
+ int tmp = 0;
+
+ local_irq_disable();
+ ret = get_user(tmp, spinlock);
+ if (ret == 0) {
+ if (tmp)
+ ret = 1;
+ tmp = 1;
+ put_user(tmp, spinlock);
+ }
+ local_irq_enable();
+ return ret;
+}
+
+void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
+{
+ switch (cplb_panic) {
+ case CPLB_NO_UNLOCKED:
+ printk(KERN_EMERG "All CPLBs are locked\n");
+ break;
+ case CPLB_PROT_VIOL:
+ return;
+ case CPLB_NO_ADDR_MATCH:
+ return;
+ case CPLB_UNKNOWN_ERR:
+ printk(KERN_EMERG "Unknown CPLB Exception\n");
+ break;
+ }
+
+ printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
+ printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
+ dump_bfin_regs(fp, (void *)fp->retx);
+ dump_stack();
+ panic("Unrecoverable event\n");
+}
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
new file mode 100644
index 00000000000..6ae9ebbd8e5
--- /dev/null
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -0,0 +1,228 @@
+/*
+ * File: arch/blackfin/kernel/vmlinux.lds.S
+ * Based on: none - original work
+ * Author:
+ *
+ * Created: Tue Sep 21 2004
+ * Description: Master linker script for blackfin architecture
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define VMLINUX_SYMBOL(_sym_) _##_sym_
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/mem_map.h>
+
+
+OUTPUT_FORMAT("elf32-bfin")
+ENTRY(__start)
+_jiffies = _jiffies_64;
+
+MEMORY
+{
+ ram : ORIGIN = CONFIG_BOOT_LOAD, LENGTH = (CONFIG_MEM_SIZE * 1024 * 1024) - (CONFIG_BOOT_LOAD)
+ l1_data_a : ORIGIN = L1_DATA_A_START, LENGTH = L1_DATA_A_LENGTH
+ l1_data_b : ORIGIN = L1_DATA_B_START, LENGTH = L1_DATA_B_LENGTH
+ l1_code : ORIGIN = L1_CODE_START, LENGTH = L1_CODE_LENGTH
+ l1_scratch : ORIGIN = L1_SCRATCH_START, LENGTH = L1_SCRATCH_LENGTH
+}
+
+SECTIONS
+{
+ . = CONFIG_BOOT_LOAD;
+
+ .text :
+ {
+ _text = .;
+ __stext = .;
+ *(.text)
+ SCHED_TEXT
+ *(.text.lock)
+ . = ALIGN(16);
+ ___start___ex_table = .;
+ *(__ex_table)
+ ___stop___ex_table = .;
+
+ *($code)
+ *(.rodata)
+ *(.rodata.*)
+ *(__vermagic) /* Kernel version magic */
+ *(.rodata1)
+ *(.fixup)
+ *(.spinlock.text)
+
+ /* Kernel symbol table: Normal symbols */
+ . = ALIGN(4);
+ ___start___ksymtab = .;
+ *(__ksymtab)
+ ___stop___ksymtab = .;
+
+ /* Kernel symbol table: GPL-only symbols */
+ ___start___ksymtab_gpl = .;
+ *(__ksymtab_gpl)
+ ___stop___ksymtab_gpl = .;
+
+ /* Kernel symbol table: Normal unused symbols */ \
+ ___start___ksymtab_unused = .;
+ *(__ksymtab_unused)
+ ___stop___ksymtab_unused = .;
+
+ /* Kernel symbol table: GPL-only unused symbols */
+ ___start___ksymtab_unused_gpl = .;
+ *(__ksymtab_unused_gpl)
+ ___stop___ksymtab_unused_gpl = .;
+
+
+ /* Kernel symbol table: GPL-future symbols */
+ ___start___ksymtab_gpl_future = .;
+ *(__ksymtab_gpl_future)
+ ___stop___ksymtab_gpl_future = .;
+
+ /* Kernel symbol table: Normal symbols */
+ ___start___kcrctab = .;
+ *(__kcrctab)
+ ___stop___kcrctab = .;
+
+ /* Kernel symbol table: GPL-only symbols */
+ ___start___kcrctab_gpl = .;
+ *(__kcrctab_gpl)
+ ___stop___kcrctab_gpl = .;
+
+ /* Kernel symbol table: GPL-future symbols */
+ ___start___kcrctab_gpl_future = .;
+ *(__kcrctab_gpl_future)
+ ___stop___kcrctab_gpl_future = .;
+
+ /* Kernel symbol table: strings */
+ *(__ksymtab_strings)
+
+ . = ALIGN(4);
+ __etext = .;
+ } > ram
+
+ .init :
+ {
+ . = ALIGN(4096);
+ ___init_begin = .;
+ __sinittext = .;
+ *(.init.text)
+ __einittext = .;
+ *(.init.data)
+ . = ALIGN(16);
+ ___setup_start = .;
+ *(.init.setup)
+ ___setup_end = .;
+ ___start___param = .;
+ *(__param)
+ ___stop___param = .;
+ ___initcall_start = .;
+ INITCALLS
+ ___initcall_end = .;
+ ___con_initcall_start = .;
+ *(.con_initcall.init)
+ ___con_initcall_end = .;
+ ___security_initcall_start = .;
+ *(.security_initcall.init)
+ ___security_initcall_end = .;
+ . = ALIGN(4);
+ ___initramfs_start = .;
+ *(.init.ramfs)
+ ___initramfs_end = .;
+ . = ALIGN(4);
+ ___init_end = .;
+ } > ram
+
+ __l1_lma_start = .;
+
+ .text_l1 :
+ {
+ . = ALIGN(4);
+ __stext_l1 = .;
+ *(.l1.text)
+
+ . = ALIGN(4);
+ __etext_l1 = .;
+ } > l1_code AT > ram
+
+ .data_l1 :
+ {
+ . = ALIGN(4);
+ __sdata_l1 = .;
+ *(.l1.data)
+ __edata_l1 = .;
+
+ . = ALIGN(4);
+ __sbss_l1 = .;
+ *(.l1.bss)
+
+ . = ALIGN(32);
+ *(.data_l1.cacheline_aligned)
+
+ . = ALIGN(4);
+ __ebss_l1 = .;
+ } > l1_data_a AT > ram
+ .data_b_l1 :
+ {
+ . = ALIGN(4);
+ __sdata_b_l1 = .;
+ *(.l1.data.B)
+ __edata_b_l1 = .;
+
+ . = ALIGN(4);
+ __sbss_b_l1 = .;
+ *(.l1.bss.B)
+
+ . = ALIGN(4);
+ __ebss_b_l1 = .;
+ } > l1_data_b AT > ram
+
+ .data :
+ {
+ __sdata = .;
+ . = ALIGN(0x2000);
+ *(.data.init_task)
+ *(.data)
+
+ . = ALIGN(32);
+ *(.data.cacheline_aligned)
+
+ . = ALIGN(0x2000);
+ __edata = .;
+ } > ram
+
+ /DISCARD/ : { /* Exit code and data*/
+ *(.exit.text)
+ *(.exit.data)
+ *(.exitcall.exit)
+ } > ram
+
+ .bss :
+ {
+ . = ALIGN(4);
+ ___bss_start = .;
+ *(.bss)
+ *(COMMON)
+ . = ALIGN(4);
+ ___bss_stop = .;
+ __end = . ;
+ } > ram
+}
diff --git a/arch/blackfin/lib/Makefile b/arch/blackfin/lib/Makefile
new file mode 100644
index 00000000000..635288fc5f5
--- /dev/null
+++ b/arch/blackfin/lib/Makefile
@@ -0,0 +1,11 @@
+#
+# arch/blackfin/lib/Makefile
+#
+
+lib-y := \
+ ashldi3.o ashrdi3.o lshrdi3.o \
+ muldi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
+ checksum.o memcpy.o memset.o memcmp.o memchr.o memmove.o \
+ strcmp.o strcpy.o strncmp.o strncpy.o \
+ umulsi3_highpart.o smulsi3_highpart.o \
+ ins.o outs.o
diff --git a/arch/blackfin/lib/ashldi3.c b/arch/blackfin/lib/ashldi3.c
new file mode 100644
index 00000000000..a8c279e9b19
--- /dev/null
+++ b/arch/blackfin/lib/ashldi3.c
@@ -0,0 +1,58 @@
+/*
+ * File: arch/blackfin/lib/ashldi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "gcclib.h"
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __ashldi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __ashldi3(DItype u, word_type b)
+{
+ DIunion w;
+ word_type bm;
+ DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ w.s.low = 0;
+ w.s.high = (USItype) uu.s.low << -bm;
+ } else {
+ USItype carries = (USItype) uu.s.low >> bm;
+ w.s.low = (USItype) uu.s.low << b;
+ w.s.high = ((USItype) uu.s.high << b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/ashrdi3.c b/arch/blackfin/lib/ashrdi3.c
new file mode 100644
index 00000000000..a0d3419329c
--- /dev/null
+++ b/arch/blackfin/lib/ashrdi3.c
@@ -0,0 +1,59 @@
+/*
+ * File: arch/blackfin/lib/ashrdi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "gcclib.h"
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __ashrdi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __ashrdi3(DItype u, word_type b)
+{
+ DIunion w;
+ word_type bm;
+ DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ /* w.s.high = 1..1 or 0..0 */
+ w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
+ w.s.low = uu.s.high >> -bm;
+ } else {
+ USItype carries = (USItype) uu.s.high << bm;
+ w.s.high = uu.s.high >> b;
+ w.s.low = ((USItype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c
new file mode 100644
index 00000000000..42768e0c80c
--- /dev/null
+++ b/arch/blackfin/lib/checksum.c
@@ -0,0 +1,140 @@
+/*
+ * File: arch/blackfin/lib/checksum.c
+ * Based on: none - original work
+ * Author:
+ *
+ * Created:
+ * Description: An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <net/checksum.h>
+#include <asm/checksum.h>
+
+#ifdef CONFIG_IP_CHECKSUM_L1
+static unsigned short do_csum(const unsigned char *buff, int len)__attribute__((l1_text));
+#endif
+
+static unsigned short do_csum(const unsigned char *buff, int len)
+{
+ register unsigned long sum = 0;
+ int swappem = 0;
+
+ if (1 & (unsigned long)buff) {
+ sum = *buff << 8;
+ buff++;
+ len--;
+ ++swappem;
+ }
+
+ while (len > 1) {
+ sum += *(unsigned short *)buff;
+ buff += 2;
+ len -= 2;
+ }
+
+ if (len > 0)
+ sum += *buff;
+
+ /* Fold 32-bit sum to 16 bits */
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ if (swappem)
+ sum = ((sum & 0xff00) >> 8) + ((sum & 0x00ff) << 8);
+
+ return sum;
+
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl)
+{
+ return ~do_csum(iph, ihl * 4);
+}
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum)
+{
+ /*
+ * Just in case we get nasty checksum data...
+ * Like 0xffff6ec3 in the case of our IPv6 multicast header.
+ * We fold to begin with, as well as at the end.
+ */
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ sum += do_csum(buff, len);
+
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return sum;
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+unsigned short ip_compute_csum(const unsigned char *buff, int len)
+{
+ return ~do_csum(buff, len);
+}
+
+/*
+ * copy from fs while checksumming, otherwise like csum_partial
+ */
+
+unsigned int
+csum_partial_copy_from_user(const unsigned char *src, unsigned char *dst,
+ int len, int sum, int *csum_err)
+{
+ if (csum_err)
+ *csum_err = 0;
+ memcpy(dst, src, len);
+ return csum_partial(dst, len, sum);
+}
+
+/*
+ * copy from ds while checksumming, otherwise like csum_partial
+ */
+
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+ int len, int sum)
+{
+ memcpy(dst, src, len);
+ return csum_partial(dst, len, sum);
+}
diff --git a/arch/blackfin/lib/divsi3.S b/arch/blackfin/lib/divsi3.S
new file mode 100644
index 00000000000..3e29861852b
--- /dev/null
+++ b/arch/blackfin/lib/divsi3.S
@@ -0,0 +1,216 @@
+/*
+ * File: arch/blackfin/lib/divsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: 16 / 32 bit signed division.
+ * Special cases :
+ * 1) If(numerator == 0)
+ * return 0
+ * 2) If(denominator ==0)
+ * return positive max = 0x7fffffff
+ * 3) If(numerator == denominator)
+ * return 1
+ * 4) If(denominator ==1)
+ * return numerator
+ * 5) If(denominator == -1)
+ * return -numerator
+ *
+ * Operand : R0 - Numerator (i)
+ * R1 - Denominator (i)
+ * R0 - Quotient (o)
+ * Registers Used : R2-R7,P0-P2
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+.global ___divsi3;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2;
+___divsi3 :
+
+
+ R3 = R0 ^ R1;
+ R0 = ABS R0;
+
+ CC = V;
+
+ r3 = rot r3 by -1;
+ r1 = abs r1; /* now both positive, r3.30 means "negate result",
+ ** r3.31 means overflow, add one to result
+ */
+ cc = r0 < r1;
+ if cc jump .Lret_zero;
+ r2 = r1 >> 15;
+ cc = r2;
+ if cc jump .Lidents;
+ r2 = r1 << 16;
+ cc = r2 <= r0;
+ if cc jump .Lidents;
+
+ DIVS(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+ DIVQ(R0, R1);
+
+ R0 = R0.L (Z);
+ r1 = r3 >> 31; /* add overflow issue back in */
+ r0 = r0 + r1;
+ r1 = -r0;
+ cc = bittst(r3, 30);
+ if cc r0 = r1;
+ RTS;
+
+/* Can't use the primitives. Test common identities.
+** If the identity is true, return the value in R2.
+*/
+
+.Lidents:
+ CC = R1 == 0; /* check for divide by zero */
+ IF CC JUMP .Lident_return;
+
+ CC = R0 == 0; /* check for division of zero */
+ IF CC JUMP .Lzero_return;
+
+ CC = R0 == R1; /* check for identical operands */
+ IF CC JUMP .Lident_return;
+
+ CC = R1 == 1; /* check for divide by 1 */
+ IF CC JUMP .Lident_return;
+
+ R2.L = ONES R1;
+ R2 = R2.L (Z);
+ CC = R2 == 1;
+ IF CC JUMP .Lpower_of_two;
+
+ /* Identities haven't helped either.
+ ** Perform the full division process.
+ */
+
+ P1 = 31; /* Set loop counter */
+
+ [--SP] = (R7:5); /* Push registers R5-R7 */
+ R2 = -R1;
+ [--SP] = R2;
+ R2 = R0 << 1; /* R2 lsw of dividend */
+ R6 = R0 ^ R1; /* Get sign */
+ R5 = R6 >> 31; /* Shift sign to LSB */
+
+ R0 = 0 ; /* Clear msw partial remainder */
+ R2 = R2 | R5; /* Shift quotient bit */
+ R6 = R0 ^ R1; /* Get new quotient bit */
+
+ LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */
+.Llst: R7 = R2 >> 31; /* record copy of carry from R2 */
+ R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
+ R0 = R0 << 1 || R5 = [SP];
+ R0 = R0 | R7; /* and add carry */
+ CC = R6 < 0; /* Check quotient(AQ) */
+ /* we might be subtracting divisor (AQ==0) */
+ IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/
+ R0 = R0 + R5; /* do add or subtract, as indicated by AQ */
+ R6 = R0 ^ R1; /* Generate next quotient bit */
+ R5 = R6 >> 31;
+ /* Assume AQ==1, shift in zero */
+ BITTGL(R5,0); /* tweak AQ to be what we want to shift in */
+.Llend: R2 = R2 + R5; /* and then set shifted-in value to
+ ** tweaked AQ.
+ */
+ r1 = r3 >> 31;
+ r2 = r2 + r1;
+ cc = bittst(r3,30);
+ r0 = -r2;
+ if !cc r0 = r2;
+ SP += 4;
+ (R7:5)= [SP++]; /* Pop registers R6-R7 */
+ RTS;
+
+.Lident_return:
+ CC = R1 == 0; /* check for divide by zero => 0x7fffffff */
+ R2 = -1 (X);
+ R2 >>= 1;
+ IF CC JUMP .Ltrue_ident_return;
+
+ CC = R0 == R1; /* check for identical operands => 1 */
+ R2 = 1 (Z);
+ IF CC JUMP .Ltrue_ident_return;
+
+ R2 = R0; /* assume divide by 1 => numerator */
+ /*FALLTHRU*/
+
+.Ltrue_ident_return:
+ R0 = R2; /* Return an identity value */
+ R2 = -R2;
+ CC = bittst(R3,30);
+ IF CC R0 = R2;
+.Lzero_return:
+ RTS; /* ...including zero */
+
+.Lpower_of_two:
+ /* Y has a single bit set, which means it's a power of two.
+ ** That means we can perform the division just by shifting
+ ** X to the right the appropriate number of bits
+ */
+
+ /* signbits returns the number of sign bits, minus one.
+ ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+ ** to shift right n-signbits spaces. It also means 0x80000000
+ ** is a special case, because that *also* gives a signbits of 0
+ */
+
+ R2 = R0 >> 31;
+ CC = R1 < 0;
+ IF CC JUMP .Ltrue_ident_return;
+
+ R1.l = SIGNBITS R1;
+ R1 = R1.L (Z);
+ R1 += -30;
+ R0 = LSHIFT R0 by R1.L;
+ r1 = r3 >> 31;
+ r0 = r0 + r1;
+ R2 = -R0; // negate result if necessary
+ CC = bittst(R3,30);
+ IF CC R0 = R2;
+ RTS;
+
+.Lret_zero:
+ R0 = 0;
+ RTS;
diff --git a/arch/blackfin/lib/gcclib.h b/arch/blackfin/lib/gcclib.h
new file mode 100644
index 00000000000..9ccd39a135e
--- /dev/null
+++ b/arch/blackfin/lib/gcclib.h
@@ -0,0 +1,47 @@
+/*
+ * File: arch/blackfin/lib/gcclib.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITS_PER_UNIT 8
+#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT)
+
+typedef unsigned int UQItype __attribute__ ((mode(QI)));
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+typedef unsigned int UDItype __attribute__ ((mode(DI)));
+
+struct DIstruct {
+ SItype low, high;
+};
+
+typedef union {
+ struct DIstruct s;
+ DItype ll;
+} DIunion;
diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S
new file mode 100644
index 00000000000..730d2b42753
--- /dev/null
+++ b/arch/blackfin/lib/ins.S
@@ -0,0 +1,69 @@
+/*
+ * File: arch/blackfin/lib/ins.S
+ * Based on:
+ * Author: Bas Vermeulen <bas@buyways.nl>
+ *
+ * Created: Tue Mar 22 15:27:24 CEST 2005
+ * Description: Implementation of ins{bwl} for BlackFin processors using zero overhead loops.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+ENTRY(_insl)
+ P0 = R0; /* P0 = port */
+ cli R3;
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s: R0 = [P0];
+.Llong_loop_e: [P1++] = R0;
+ sti R3;
+ RTS;
+
+ENTRY(_insw)
+ P0 = R0; /* P0 = port */
+ cli R3;
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s: R0 = W[P0];
+.Lword_loop_e: W[P1++] = R0;
+ sti R3;
+ RTS;
+
+ENTRY(_insb)
+ P0 = R0; /* P0 = port */
+ cli R3;
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+ SSYNC;
+ LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s: R0 = B[P0];
+.Lbyte_loop_e: B[P1++] = R0;
+ sti R3;
+ RTS;
diff --git a/arch/blackfin/lib/lshrdi3.c b/arch/blackfin/lib/lshrdi3.c
new file mode 100644
index 00000000000..84b9c559222
--- /dev/null
+++ b/arch/blackfin/lib/lshrdi3.c
@@ -0,0 +1,72 @@
+/*
+ * File: arch/blackfin/lib/lshrdi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define BITS_PER_UNIT 8
+
+typedef int SItype __attribute__ ((mode(SI)));
+typedef unsigned int USItype __attribute__ ((mode(SI)));
+typedef int DItype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+
+struct DIstruct {
+ SItype high, low;
+};
+
+typedef union {
+ struct DIstruct s;
+ DItype ll;
+} DIunion;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+DItype __lshrdi3(DItype u, word_type b)__attribute__((l1_text));
+#endif
+
+DItype __lshrdi3(DItype u, word_type b)
+{
+ DIunion w;
+ word_type bm;
+ DIunion uu;
+
+ if (b == 0)
+ return u;
+
+ uu.ll = u;
+
+ bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
+ if (bm <= 0) {
+ w.s.high = 0;
+ w.s.low = (USItype) uu.s.high >> -bm;
+ } else {
+ USItype carries = (USItype) uu.s.high << bm;
+ w.s.high = (USItype) uu.s.high >> b;
+ w.s.low = ((USItype) uu.s.low >> b) | carries;
+ }
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/memchr.S b/arch/blackfin/lib/memchr.S
new file mode 100644
index 00000000000..498122250d0
--- /dev/null
+++ b/arch/blackfin/lib/memchr.S
@@ -0,0 +1,70 @@
+/*
+ * File: arch/blackfin/lib/memchr.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+/* void *memchr(const void *s, int c, size_t n);
+ * R0 = address (s)
+ * R1 = sought byte (c)
+ * R2 = count (n)
+ *
+ * Returns pointer to located character.
+ */
+
+.text
+
+.align 2
+
+ENTRY(_memchr)
+ P0 = R0; /* P0 = address */
+ P2 = R2; /* P2 = count */
+ R1 = R1.B(Z);
+ CC = R2 == 0;
+ IF CC JUMP .Lfailed;
+
+.Lbytes:
+ LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
+
+.Lbyte_loop_s:
+ R3 = B[P0++](Z);
+ CC = R3 == R1;
+ IF CC JUMP .Lfound;
+.Lbyte_loop_e:
+ NOP;
+
+.Lfailed:
+ R0=0;
+ RTS;
+
+.Lfound:
+ R0 = P0;
+ R0 += -1;
+ RTS;
+
+.size _memchr,.-_memchr
diff --git a/arch/blackfin/lib/memcmp.S b/arch/blackfin/lib/memcmp.S
new file mode 100644
index 00000000000..5b9502368fc
--- /dev/null
+++ b/arch/blackfin/lib/memcmp.S
@@ -0,0 +1,110 @@
+/*
+ * File: arch/blackfin/lib/memcmp.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+/* int memcmp(const void *s1, const void *s2, size_t n);
+ * R0 = First Address (s1)
+ * R1 = Second Address (s2)
+ * R2 = count (n)
+ *
+ * Favours word aligned data.
+ */
+
+.text
+
+.align 2
+
+ENTRY(_memcmp)
+ I1 = P3;
+ P0 = R0; /* P0 = s1 address */
+ P3 = R1; /* P3 = s2 Address */
+ P2 = R2 ; /* P2 = count */
+ CC = R2 <= 7(IU);
+ IF CC JUMP .Ltoo_small;
+ I0 = R1; /* s2 */
+ R1 = R1 | R0; /* OR addresses together */
+ R1 <<= 30; /* check bottom two bits */
+ CC = AZ; /* AZ set if zero. */
+ IF !CC JUMP .Lbytes ; /* Jump if addrs not aligned. */
+
+ P1 = P2 >> 2; /* count = n/4 */
+ R3 = 3;
+ R2 = R2 & R3; /* remainder */
+ P2 = R2; /* set remainder */
+
+ LSETUP (.Lquad_loop_s, .Lquad_loop_e) LC0=P1;
+.Lquad_loop_s:
+ MNOP || R0 = [P0++] || R1 = [I0++];
+ CC = R0 == R1;
+ IF !CC JUMP .Lquad_different;
+.Lquad_loop_e:
+ NOP;
+
+ P3 = I0; /* s2 */
+.Ltoo_small:
+ CC = P2 == 0; /* Check zero count*/
+ IF CC JUMP .Lfinished; /* very unlikely*/
+
+.Lbytes:
+ LSETUP (.Lbyte_loop_s, .Lbyte_loop_e) LC0=P2;
+.Lbyte_loop_s:
+ R1 = B[P3++](Z); /* *s2 */
+ R0 = B[P0++](Z); /* *s1 */
+ CC = R0 == R1;
+ IF !CC JUMP .Ldifferent;
+.Lbyte_loop_e:
+ NOP;
+
+.Ldifferent:
+ R0 = R0 - R1;
+ P3 = I1;
+ RTS;
+
+.Lquad_different:
+ /* We've read two quads which don't match.
+ * Can't just compare them, because we're
+ * a little-endian machine, so the MSBs of
+ * the regs occur at later addresses in the
+ * string.
+ * Arrange to re-read those two quads again,
+ * byte-by-byte.
+ */
+ P0 += -4; /* back up to the start of the */
+ P3 = I0; /* quads, and increase the*/
+ P2 += 4; /* remainder count*/
+ P3 += -4;
+ JUMP .Lbytes;
+
+.Lfinished:
+ R0 = 0;
+ P3 = I1;
+ RTS;
+
+.size _memcmp,.-_memcmp
diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
new file mode 100644
index 00000000000..c1e00eff541
--- /dev/null
+++ b/arch/blackfin/lib/memcpy.S
@@ -0,0 +1,142 @@
+/*
+ * File: arch/blackfin/lib/memcpy.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: internal version of memcpy(), issued by the compiler
+ * to copy blocks of data around.
+ * This is really memmove() - it has to be able to deal with
+ * possible overlaps, because that ambiguity is when the compiler
+ * gives up and calls a function. We have our own, internal version
+ * so that we get something we trust, even if the user has redefined
+ * the normal symbol.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+/* void *memcpy(void *dest, const void *src, size_t n);
+ * R0 = To Address (dest) (leave unchanged to form result)
+ * R1 = From Address (src)
+ * R2 = count
+ *
+ * Note: Favours word alignment
+ */
+
+#ifdef CONFIG_MEMCPY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2
+
+ENTRY(_memcpy)
+ CC = R2 <= 0; /* length not positive? */
+ IF CC JUMP .L_P1L2147483647; /* Nothing to do */
+
+ P0 = R0 ; /* dst*/
+ P1 = R1 ; /* src*/
+ P2 = R2 ; /* length */
+
+ /* check for overlapping data */
+ CC = R1 < R0; /* src < dst */
+ IF !CC JUMP .Lno_overlap;
+ R3 = R1 + R2;
+ CC = R0 < R3; /* and dst < src+len */
+ IF CC JUMP .Lhas_overlap;
+
+.Lno_overlap:
+ /* Check for aligned data.*/
+
+ R3 = R1 | R0;
+ R0 = 0x3;
+ R3 = R3 & R0;
+ CC = R3; /* low bits set on either address? */
+ IF CC JUMP .Lnot_aligned;
+
+ /* Both addresses are word-aligned, so we can copy
+ at least part of the data using word copies.*/
+ P2 = P2 >> 2;
+ CC = P2 <= 2;
+ IF !CC JUMP .Lmore_than_seven;
+ /* less than eight bytes... */
+ P2 = R2;
+ LSETUP(.Lthree_start, .Lthree_end) LC0=P2;
+ R0 = R1; /* setup src address for return */
+.Lthree_start:
+ R3 = B[P1++] (X);
+.Lthree_end:
+ B[P0++] = R3;
+
+ RTS;
+
+.Lmore_than_seven:
+ /* There's at least eight bytes to copy. */
+ P2 += -1; /* because we unroll one iteration */
+ LSETUP(.Lword_loop, .Lword_loop) LC0=P2;
+ R0 = R1;
+ I1 = P1;
+ R3 = [I1++];
+.Lword_loop:
+ MNOP || [P0++] = R3 || R3 = [I1++];
+
+ [P0++] = R3;
+ /* Any remaining bytes to copy? */
+ R3 = 0x3;
+ R3 = R2 & R3;
+ CC = R3 == 0;
+ P1 = I1; /* in case there's something left, */
+ IF !CC JUMP .Lbytes_left;
+ RTS;
+.Lbytes_left: P2 = R3;
+.Lnot_aligned:
+ /* From here, we're copying byte-by-byte. */
+ LSETUP (.Lbyte_start, .Lbyte_end) LC0=P2;
+ R0 = R1; /* Save src address for return */
+.Lbyte_start:
+ R1 = B[P1++] (X);
+.Lbyte_end:
+ B[P0++] = R1;
+
+.L_P1L2147483647:
+ RTS;
+
+.Lhas_overlap:
+ /* Need to reverse the copying, because the
+ * dst would clobber the src.
+ * Don't bother to work out alignment for
+ * the reverse case.
+ */
+ R0 = R1; /* save src for later. */
+ P0 = P0 + P2;
+ P0 += -1;
+ P1 = P1 + P2;
+ P1 += -1;
+ LSETUP(.Lover_start, .Lover_end) LC0=P2;
+.Lover_start:
+ R1 = B[P1--] (X);
+.Lover_end:
+ B[P0--] = R1;
+
+ RTS;
diff --git a/arch/blackfin/lib/memmove.S b/arch/blackfin/lib/memmove.S
new file mode 100644
index 00000000000..2e5fb7f8df1
--- /dev/null
+++ b/arch/blackfin/lib/memmove.S
@@ -0,0 +1,103 @@
+/*
+ * File: arch/blackfin/lib/memmove.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+/*
+ * C Library function MEMMOVE
+ * R0 = To Address (leave unchanged to form result)
+ * R1 = From Address
+ * R2 = count
+ * Data may overlap
+ */
+
+ENTRY(_memmove)
+ I1 = P3;
+ P0 = R0; /* P0 = To address */
+ P3 = R1; /* P3 = From Address */
+ P2 = R2; /* P2 = count */
+ CC = P2 == 0; /* Check zero count*/
+ IF CC JUMP .Lfinished; /* very unlikely */
+
+ CC = R1 < R0 (IU); /* From < To */
+ IF !CC JUMP .Lno_overlap;
+ R3 = R1 + R2;
+ CC = R0 <= R3 (IU); /* (From+len) >= To */
+ IF CC JUMP .Loverlap;
+.Lno_overlap:
+ R3 = 11;
+ CC = R2 <= R3;
+ IF CC JUMP .Lbytes;
+ R3 = R1 | R0; /* OR addresses together */
+ R3 <<= 30; /* check bottom two bits */
+ CC = AZ; /* AZ set if zero.*/
+ IF !CC JUMP .Lbytes; /* Jump if addrs not aligned.*/
+
+ I0 = P3;
+ P1 = P2 >> 2; /* count = n/4 */
+ P1 += -1;
+ R3 = 3;
+ R2 = R2 & R3; /* remainder */
+ P2 = R2; /* set remainder */
+ R1 = [I0++];
+
+ LSETUP (.Lquad_loop, .Lquad_loop) LC0=P1;
+.Lquad_loop: MNOP || [P0++] = R1 || R1 = [I0++];
+ [P0++] = R1;
+
+ CC = P2 == 0; /* any remaining bytes? */
+ P3 = I0; /* Ammend P3 to updated ptr. */
+ IF !CC JUMP .Lbytes;
+ P3 = I1;
+ RTS;
+
+.Lbytes: LSETUP (.Lbyte2_s, .Lbyte2_e) LC0=P2;
+.Lbyte2_s: R1 = B[P3++](Z);
+.Lbyte2_e: B[P0++] = R1;
+
+.Lfinished: P3 = I1;
+ RTS;
+
+.Loverlap:
+ P2 += -1;
+ P0 = P0 + P2;
+ P3 = P3 + P2;
+ R1 = B[P3--] (Z);
+ CC = P2 == 0;
+ IF CC JUMP .Lno_loop;
+ LSETUP (.Lol_s, .Lol_e) LC0 = P2;
+.Lol_s: B[P0--] = R1;
+.Lol_e: R1 = B[P3--] (Z);
+.Lno_loop: B[P0] = R1;
+ P3 = I1;
+ RTS;
+
+.size _memmove,.-_memmove
diff --git a/arch/blackfin/lib/memset.S b/arch/blackfin/lib/memset.S
new file mode 100644
index 00000000000..ba6d047568d
--- /dev/null
+++ b/arch/blackfin/lib/memset.S
@@ -0,0 +1,109 @@
+/*
+ * File: arch/blackfin/lib/memset.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+#ifdef CONFIG_MEMSET_L1
+.section .l1.text
+#else
+.text
+#endif
+
+/*
+ * C Library function MEMSET
+ * R0 = address (leave unchanged to form result)
+ * R1 = filler byte
+ * R2 = count
+ * Favours word aligned data.
+ */
+
+ENTRY(_memset)
+ P0 = R0 ; /* P0 = address */
+ P2 = R2 ; /* P2 = count */
+ R3 = R0 + R2; /* end */
+ CC = R2 <= 7(IU);
+ IF CC JUMP .Ltoo_small;
+ R1 = R1.B (Z); /* R1 = fill char */
+ R2 = 3;
+ R2 = R0 & R2; /* addr bottom two bits */
+ CC = R2 == 0; /* AZ set if zero. */
+ IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */
+
+.Laligned:
+ P1 = P2 >> 2; /* count = n/4 */
+ R2 = R1 << 8; /* create quad filler */
+ R2.L = R2.L + R1.L(NS);
+ R2.H = R2.L + R1.H(NS);
+ P2 = R3;
+
+ LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
+.Lquad_loop:
+ [P0++] = R2;
+
+ CC = P0 == P2;
+ IF !CC JUMP .Lbytes_left;
+ RTS;
+
+.Lbytes_left:
+ R2 = R3; /* end point */
+ R3 = P0; /* current position */
+ R2 = R2 - R3; /* bytes left */
+ P2 = R2;
+
+.Ltoo_small:
+ CC = P2 == 0; /* Check zero count */
+ IF CC JUMP .Lfinished; /* Unusual */
+
+.Lbytes:
+ LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
+.Lbyte_loop:
+ B[P0++] = R1;
+
+.Lfinished:
+ RTS;
+
+.Lforce_align:
+ CC = BITTST (R0, 0); /* odd byte */
+ R0 = 4;
+ R0 = R0 - R2;
+ P1 = R0;
+ R0 = P0; /* Recover return address */
+ IF !CC JUMP .Lskip1;
+ B[P0++] = R1;
+.Lskip1:
+ CC = R2 <= 2; /* 2 bytes */
+ P2 -= P1; /* reduce count */
+ IF !CC JUMP .Laligned;
+ B[P0++] = R1;
+ B[P0++] = R1;
+ JUMP .Laligned;
+
+.size _memset,.-_memset
diff --git a/arch/blackfin/lib/modsi3.S b/arch/blackfin/lib/modsi3.S
new file mode 100644
index 00000000000..528b8b1ccb3
--- /dev/null
+++ b/arch/blackfin/lib/modsi3.S
@@ -0,0 +1,79 @@
+/*
+ * File: arch/blackfin/lib/modsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This program computes 32 bit signed remainder. It calls div32 function
+ * for quotient estimation.
+ *
+ * Registers used :
+ * Numerator/ Denominator in R0, R1
+ * R0 - returns remainder.
+ * R2-R7
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+.global ___modsi3;
+.type ___modsi3, STT_FUNC;
+.extern ___divsi3;
+.type ___divsi3, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___modsi3:
+
+ CC=R0==0;
+ IF CC JUMP .LRETURN_R0; /* Return 0, if numerator == 0 */
+ CC=R1==0;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 0 */
+ CC=R0==R1;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if numerator == denominator */
+ CC = R1 == 1;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == 1 */
+ CC = R1 == -1;
+ IF CC JUMP .LRETURN_ZERO; /* Return 0, if denominator == -1 */
+
+ /* Valid input. Use __divsi3() to compute the quotient, and then
+ * derive the remainder from that. */
+
+ [--SP] = (R7:6); /* Push R7 and R6 */
+ [--SP] = RETS; /* and return address */
+ R7 = R0; /* Copy of R0 */
+ R6 = R1; /* Save for later */
+ SP += -12; /* Should always provide this space */
+ CALL ___divsi3; /* Compute signed quotient using ___divsi3()*/
+ SP += 12;
+ R0 *= R6; /* Quotient * divisor */
+ R0 = R7 - R0; /* Dividend - (quotient * divisor) */
+ RETS = [SP++]; /* Get back return address */
+ (R7:6) = [SP++]; /* Pop registers R7 and R4 */
+ RTS; /* Store remainder */
+
+.LRETURN_ZERO:
+ R0 = 0;
+.LRETURN_R0:
+ RTS;
diff --git a/arch/blackfin/lib/muldi3.c b/arch/blackfin/lib/muldi3.c
new file mode 100644
index 00000000000..303d0c6a6db
--- /dev/null
+++ b/arch/blackfin/lib/muldi3.c
@@ -0,0 +1,99 @@
+/*
+ * File: arch/blackfin/lib/muldi3.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SI_TYPE_SIZE
+#define SI_TYPE_SIZE 32
+#endif
+#define __ll_b (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((usitype) (t) % __ll_b)
+#define __ll_highpart(t) ((usitype) (t) / __ll_b)
+#define BITS_PER_UNIT 8
+
+#if !defined(umul_ppmm)
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ usitype __x0, __x1, __x2, __x3; \
+ usitype __ul, __vl, __uh, __vh; \
+ \
+ __ul = __ll_lowpart (u); \
+ __uh = __ll_highpart (u); \
+ __vl = __ll_lowpart (v); \
+ __vh = __ll_highpart (v); \
+ \
+ __x0 = (usitype) __ul * __vl; \
+ __x1 = (usitype) __ul * __vh; \
+ __x2 = (usitype) __uh * __vl; \
+ __x3 = (usitype) __uh * __vh; \
+ \
+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += __ll_b; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + __ll_highpart (__x1); \
+ (w0) = __ll_lowpart (__x1) * __ll_b + __ll_lowpart (__x0); \
+ } while (0)
+#endif
+
+#if !defined(__umulsidi3)
+#define __umulsidi3(u, v) \
+ ({diunion __w; \
+ umul_ppmm (__w.s.high, __w.s.low, u, v); \
+ __w.ll; })
+#endif
+
+typedef unsigned int usitype __attribute__ ((mode(SI)));
+typedef int sitype __attribute__ ((mode(SI)));
+typedef int ditype __attribute__ ((mode(DI)));
+typedef int word_type __attribute__ ((mode(__word__)));
+
+struct distruct {
+ sitype low, high;
+};
+typedef union {
+ struct distruct s;
+ ditype ll;
+} diunion;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+ditype __muldi3(ditype u, ditype v)__attribute__((l1_text));
+#endif
+
+ditype __muldi3(ditype u, ditype v)
+{
+ diunion w;
+ diunion uu, vv;
+
+ uu.ll = u, vv.ll = v;
+ w.ll = __umulsidi3(uu.s.low, vv.s.low);
+ w.s.high += ((usitype) uu.s.low * (usitype) vv.s.high
+ + (usitype) uu.s.high * (usitype) vv.s.low);
+
+ return w.ll;
+}
diff --git a/arch/blackfin/lib/outs.S b/arch/blackfin/lib/outs.S
new file mode 100644
index 00000000000..f8c876fe893
--- /dev/null
+++ b/arch/blackfin/lib/outs.S
@@ -0,0 +1,62 @@
+/*
+ * File: arch/blackfin/lib/outs.S
+ * Based on:
+ * Author: Bas Vermeulen <bas@buyways.nl>
+ *
+ * Created: Tue Mar 22 15:27:24 CEST 2005
+ * Description: Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
+ *
+ * Modified: Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+.align 2
+
+ENTRY(_outsl)
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+
+ LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2;
+.Llong_loop_s: R0 = [P1++];
+.Llong_loop_e: [P0] = R0;
+ RTS;
+
+ENTRY(_outsw)
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+
+ LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2;
+.Lword_loop_s: R0 = W[P1++];
+.Lword_loop_e: W[P0] = R0;
+ RTS;
+
+ENTRY(_outsb)
+ P0 = R0; /* P0 = port */
+ P1 = R1; /* P1 = address */
+ P2 = R2; /* P2 = count */
+
+ LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2;
+.Lbyte_loop_s: R0 = B[P1++];
+.Lbyte_loop_e: B[P0] = R0;
+ RTS;
diff --git a/arch/blackfin/lib/smulsi3_highpart.S b/arch/blackfin/lib/smulsi3_highpart.S
new file mode 100644
index 00000000000..10b8f8da576
--- /dev/null
+++ b/arch/blackfin/lib/smulsi3_highpart.S
@@ -0,0 +1,30 @@
+.align 2
+.global ___smulsi3_highpart;
+.type ___smulsi3_highpart, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___smulsi3_highpart:
+ R2 = R1.L * R0.L (FU);
+ R3 = R1.H * R0.L (IS,M);
+ R0 = R0.H * R1.H, R1 = R0.H * R1.L (IS,M);
+
+ R1.L = R2.H + R1.L;
+ cc = ac0;
+ R2 = cc;
+
+ R1.L = R1.L + R3.L;
+ cc = ac0;
+ R1 >>>= 16;
+ R3 >>>= 16;
+ R1 = R1 + R3;
+ R1 = R1 + R2;
+ R2 = cc;
+ R1 = R1 + R2;
+
+ R0 = R0 + R1;
+ RTS;
diff --git a/arch/blackfin/lib/strcmp.c b/arch/blackfin/lib/strcmp.c
new file mode 100644
index 00000000000..2ad47c4254b
--- /dev/null
+++ b/arch/blackfin/lib/strcmp.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strcmp __inline_strcmp
+#include <asm/string.h>
+#undef strcmp
+
+int strcmp(const char *dest, const char *src)
+{
+ return __inline_strcmp(dest, src);
+}
+
diff --git a/arch/blackfin/lib/strcpy.c b/arch/blackfin/lib/strcpy.c
new file mode 100644
index 00000000000..4dc835a8a19
--- /dev/null
+++ b/arch/blackfin/lib/strcpy.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strcpy __inline_strcpy
+#include <asm/string.h>
+#undef strcpy
+
+char *strcpy(char *dest, const char *src)
+{
+ return __inline_strcpy(dest, src);
+}
+
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c
new file mode 100644
index 00000000000..947bcfe3f3b
--- /dev/null
+++ b/arch/blackfin/lib/strncmp.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strncmp __inline_strncmp
+#include <asm/string.h>
+#undef strncmp
+
+int strncmp(const char *cs, const char *ct, size_t count)
+{
+ return __inline_strncmp(cs, ct, count);
+}
+
diff --git a/arch/blackfin/lib/strncpy.c b/arch/blackfin/lib/strncpy.c
new file mode 100644
index 00000000000..77a9b2e9509
--- /dev/null
+++ b/arch/blackfin/lib/strncpy.c
@@ -0,0 +1,11 @@
+#include <linux/types.h>
+
+#define strncpy __inline_strncpy
+#include <asm/string.h>
+#undef strncpy
+
+char *strncpy(char *dest, const char *src, size_t n)
+{
+ return __inline_strncpy(dest, src, n);
+}
+
diff --git a/arch/blackfin/lib/udivsi3.S b/arch/blackfin/lib/udivsi3.S
new file mode 100644
index 00000000000..d39a1291625
--- /dev/null
+++ b/arch/blackfin/lib/udivsi3.S
@@ -0,0 +1,298 @@
+/*
+ * File: arch/blackfin/lib/udivsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+
+#define CARRY AC0
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+
+ENTRY(___udivsi3)
+
+ CC = R0 < R1 (IU); /* If X < Y, always return 0 */
+ IF CC JUMP .Lreturn_ident;
+
+ R2 = R1 << 16;
+ CC = R2 <= R0 (IU);
+ IF CC JUMP .Lidents;
+
+ R2 = R0 >> 31; /* if X is a 31-bit number */
+ R3 = R1 >> 15; /* and Y is a 15-bit number */
+ R2 = R2 | R3; /* then it's okay to use the DIVQ builtins (fallthrough to fast)*/
+ CC = R2;
+ IF CC JUMP .Ly_16bit;
+
+/* METHOD 1: FAST DIVQ
+ We know we have a 31-bit dividend, and 15-bit divisor so we can use the
+ simple divq approach (first setting AQ to 0 - implying unsigned division,
+ then 16 DIVQ's).
+*/
+
+ AQ = CC; /* Clear AQ (CC==0) */
+
+/* ISR States: When dividing two integers (32.0/16.0) using divide primitives,
+ we need to shift the dividend one bit to the left.
+ We have already checked that we have a 31-bit number so we are safe to do
+ that.
+*/
+ R0 <<= 1;
+ DIVQ(R0, R1); // 1
+ DIVQ(R0, R1); // 2
+ DIVQ(R0, R1); // 3
+ DIVQ(R0, R1); // 4
+ DIVQ(R0, R1); // 5
+ DIVQ(R0, R1); // 6
+ DIVQ(R0, R1); // 7
+ DIVQ(R0, R1); // 8
+ DIVQ(R0, R1); // 9
+ DIVQ(R0, R1); // 10
+ DIVQ(R0, R1); // 11
+ DIVQ(R0, R1); // 12
+ DIVQ(R0, R1); // 13
+ DIVQ(R0, R1); // 14
+ DIVQ(R0, R1); // 15
+ DIVQ(R0, R1); // 16
+ R0 = R0.L (Z);
+ RTS;
+
+.Ly_16bit:
+ /* We know that the upper 17 bits of Y might have bits set,
+ ** or that the sign bit of X might have a bit. If Y is a
+ ** 16-bit number, but not bigger, then we can use the builtins
+ ** with a post-divide correction.
+ ** R3 currently holds Y>>15, which means R3's LSB is the
+ ** bit we're interested in.
+ */
+
+ /* According to the ISR, to use the Divide primitives for
+ ** unsigned integer divide, the useable range is 31 bits
+ */
+ CC = ! BITTST(R0, 31);
+
+ /* IF condition is true we can scale our inputs and use the divide primitives,
+ ** with some post-adjustment
+ */
+ R3 += -1; /* if so, Y is 0x00008nnn */
+ CC &= AZ;
+
+ /* If condition is true we can scale our inputs and use the divide primitives,
+ ** with some post-adjustment
+ */
+ R3 = R1 >> 1; /* Pre-scaled divisor for primitive case */
+ R2 = R0 >> 16;
+
+ R2 = R3 - R2; /* shifted divisor < upper 16 bits of dividend */
+ CC &= CARRY;
+ IF CC JUMP .Lshift_and_correct;
+
+ /* Fall through to the identities */
+
+/* METHOD 2: identities and manual calculation
+ We are not able to use the divide primites, but may still catch some special
+ cases.
+*/
+.Lidents:
+ /* Test for common identities. Value to be returned is placed in R2. */
+ CC = R0 == 0; /* 0/Y => 0 */
+ IF CC JUMP .Lreturn_r0;
+ CC = R0 == R1; /* X==Y => 1 */
+ IF CC JUMP .Lreturn_ident;
+ CC = R1 == 1; /* X/1 => X */
+ IF CC JUMP .Lreturn_ident;
+
+ R2.L = ONES R1;
+ R2 = R2.L (Z);
+ CC = R2 == 1;
+ IF CC JUMP .Lpower_of_two;
+
+ [--SP] = (R7:5); /* Push registers R5-R7 */
+
+ /* Idents don't match. Go for the full operation. */
+
+
+ R6 = 2; /* assume we'll shift two */
+ R3 = 1;
+
+ P2 = R1;
+ /* If either R0 or R1 have sign set, */
+ /* divide them by two, and note it's */
+ /* been done. */
+ CC = R1 < 0;
+ R2 = R1 >> 1;
+ IF CC R1 = R2; /* Possibly-shifted R1 */
+ IF !CC R6 = R3; /* R1 doesn't, so at most 1 shifted */
+
+ P0 = 0;
+ R3 = -R1;
+ [--SP] = R3;
+ R2 = R0 >> 1;
+ R2 = R0 >> 1;
+ CC = R0 < 0;
+ IF CC P0 = R6; /* Number of values divided */
+ IF !CC R2 = R0; /* Shifted R0 */
+
+ /* P0 is 0, 1 (NR/=2) or 2 (NR/=2, DR/=2) */
+
+ /* r2 holds Copy dividend */
+ R3 = 0; /* Clear partial remainder */
+ R7 = 0; /* Initialise quotient bit */
+
+ P1 = 32; /* Set loop counter */
+ LSETUP(.Lulst, .Lulend) LC0 = P1; /* Set loop counter */
+.Lulst: R6 = R2 >> 31; /* R6 = sign bit of R2, for carry */
+ R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */
+ R3 = R3 << 1 || R5 = [SP];
+ R3 = R3 | R6; /* Include any carry */
+ CC = R7 < 0; /* Check quotient(AQ) */
+ /* If AQ==0, we'll sub divisor */
+ IF CC R5 = R1; /* and if AQ==1, we'll add it. */
+ R3 = R3 + R5; /* Add/sub divsor to partial remainder */
+ R7 = R3 ^ R1; /* Generate next quotient bit */
+
+ R5 = R7 >> 31; /* Get AQ */
+ BITTGL(R5, 0); /* Invert it, to get what we'll shift */
+.Lulend: R2 = R2 + R5; /* and "shift" it in. */
+
+ CC = P0 == 0; /* Check how many inputs we shifted */
+ IF CC JUMP .Lno_mult; /* if none... */
+ R6 = R2 << 1;
+ CC = P0 == 1;
+ IF CC R2 = R6; /* if 1, Q = Q*2 */
+ IF !CC R1 = P2; /* if 2, restore stored divisor */
+
+ R3 = R2; /* Copy of R2 */
+ R3 *= R1; /* Q * divisor */
+ R5 = R0 - R3; /* Z = (dividend - Q * divisor) */
+ CC = R1 <= R5 (IU); /* Check if divisor <= Z? */
+ R6 = CC; /* if yes, R6 = 1 */
+ R2 = R2 + R6; /* if yes, add one to quotient(Q) */
+.Lno_mult:
+ SP += 4;
+ (R7:5) = [SP++]; /* Pop registers R5-R7 */
+ R0 = R2; /* Store quotient */
+ RTS;
+
+.Lreturn_ident:
+ CC = R0 < R1 (IU); /* If X < Y, always return 0 */
+ R2 = 0;
+ IF CC JUMP .Ltrue_return_ident;
+ R2 = -1 (X); /* X/0 => 0xFFFFFFFF */
+ CC = R1 == 0;
+ IF CC JUMP .Ltrue_return_ident;
+ R2 = -R2; /* R2 now 1 */
+ CC = R0 == R1; /* X==Y => 1 */
+ IF CC JUMP .Ltrue_return_ident;
+ R2 = R0; /* X/1 => X */
+ /*FALLTHRU*/
+
+.Ltrue_return_ident:
+ R0 = R2;
+.Lreturn_r0:
+ RTS;
+
+.Lpower_of_two:
+ /* Y has a single bit set, which means it's a power of two.
+ ** That means we can perform the division just by shifting
+ ** X to the right the appropriate number of bits
+ */
+
+ /* signbits returns the number of sign bits, minus one.
+ ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need
+ ** to shift right n-signbits spaces. It also means 0x80000000
+ ** is a special case, because that *also* gives a signbits of 0
+ */
+
+ R2 = R0 >> 31;
+ CC = R1 < 0;
+ IF CC JUMP .Ltrue_return_ident;
+
+ R1.l = SIGNBITS R1;
+ R1 = R1.L (Z);
+ R1 += -30;
+ R0 = LSHIFT R0 by R1.L;
+ RTS;
+
+/* METHOD 3: PRESCALE AND USE THE DIVIDE PRIMITIVES WITH SOME POST-CORRECTION
+ Two scaling operations are required to use the divide primitives with a
+ divisor > 0x7FFFF.
+ Firstly (as in method 1) we need to shift the dividend 1 to the left for
+ integer division.
+ Secondly we need to shift both the divisor and dividend 1 to the right so
+ both are in range for the primitives.
+ The left/right shift of the dividend does nothing so we can skip it.
+*/
+.Lshift_and_correct:
+ R2 = R0;
+ // R3 is already R1 >> 1
+ CC=!CC;
+ AQ = CC; /* Clear AQ, got here with CC = 0 */
+ DIVQ(R2, R3); // 1
+ DIVQ(R2, R3); // 2
+ DIVQ(R2, R3); // 3
+ DIVQ(R2, R3); // 4
+ DIVQ(R2, R3); // 5
+ DIVQ(R2, R3); // 6
+ DIVQ(R2, R3); // 7
+ DIVQ(R2, R3); // 8
+ DIVQ(R2, R3); // 9
+ DIVQ(R2, R3); // 10
+ DIVQ(R2, R3); // 11
+ DIVQ(R2, R3); // 12
+ DIVQ(R2, R3); // 13
+ DIVQ(R2, R3); // 14
+ DIVQ(R2, R3); // 15
+ DIVQ(R2, R3); // 16
+
+ /* According to the Instruction Set Reference:
+ To divide by a divisor > 0x7FFF,
+ 1. prescale and perform divide to obtain quotient (Q) (done above),
+ 2. multiply quotient by unscaled divisor (result M)
+ 3. subtract the product from the divident to get an error (E = X - M)
+ 4. if E < divisor (Y) subtract 1, if E > divisor (Y) add 1, else return quotient (Q)
+ */
+ R3 = R2.L (Z); /* Q = X' / Y' */
+ R2 = R3; /* Preserve Q */
+ R2 *= R1; /* M = Q * Y */
+ R2 = R0 - R2; /* E = X - M */
+ R0 = R3; /* Copy Q into result reg */
+
+/* Correction: If result of the multiply is negative, we overflowed
+ and need to correct the result by subtracting 1 from the result.*/
+ R3 = 0xFFFF (Z);
+ R2 = R2 >> 16; /* E >> 16 */
+ CC = R2 == R3;
+ R3 = 1 ;
+ R1 = R0 - R3;
+ IF CC R0 = R1;
+ RTS;
diff --git a/arch/blackfin/lib/umodsi3.S b/arch/blackfin/lib/umodsi3.S
new file mode 100644
index 00000000000..b55ce96ab89
--- /dev/null
+++ b/arch/blackfin/lib/umodsi3.S
@@ -0,0 +1,66 @@
+/*
+ * File: arch/blackfin/lib/umodsi3.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: libgcc1 routines for Blackfin 5xx
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.extern ___udivsi3;
+.globl ___umodsi3
+___umodsi3:
+
+ CC=R0==0;
+ IF CC JUMP .LRETURN_R0; /* Return 0, if NR == 0 */
+ CC= R1==0;
+ IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 0 */
+ CC=R0==R1;
+ IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if NR == DR */
+ CC = R1 == 1;
+ IF CC JUMP .LRETURN_ZERO_VAL; /* Return 0, if DR == 1 */
+ CC = R0<R1 (IU);
+ IF CC JUMP .LRETURN_R0; /* Return dividend (R0),IF NR<DR */
+
+ [--SP] = (R7:6); /* Push registers and */
+ [--SP] = RETS; /* Return address */
+ R7 = R0; /* Copy of R0 */
+ R6 = R1;
+ SP += -12; /* Should always provide this space */
+ CALL ___udivsi3; /* Compute unsigned quotient using ___udiv32()*/
+ SP += 12;
+ R0 *= R6; /* Quotient * divisor */
+ R0 = R7 - R0; /* Dividend - (quotient * divisor) */
+ RETS = [SP++]; /* Pop return address */
+ ( R7:6) = [SP++]; /* And registers */
+ RTS; /* Return remainder */
+.LRETURN_ZERO_VAL:
+ R0 = 0;
+.LRETURN_R0:
+ RTS;
diff --git a/arch/blackfin/lib/umulsi3_highpart.S b/arch/blackfin/lib/umulsi3_highpart.S
new file mode 100644
index 00000000000..aac8218fb25
--- /dev/null
+++ b/arch/blackfin/lib/umulsi3_highpart.S
@@ -0,0 +1,23 @@
+.align 2
+.global ___umulsi3_highpart;
+.type ___umulsi3_highpart, STT_FUNC;
+
+#ifdef CONFIG_ARITHMETIC_OPS_L1
+.section .l1.text
+#else
+.text
+#endif
+
+___umulsi3_highpart:
+ R2 = R1.H * R0.H, R3 = R1.L * R0.H (FU);
+ R0 = R1.L * R0.L, R1 = R1.H * R0.L (FU);
+ R0 >>= 16;
+ /* Unsigned multiplication has the nice property that we can
+ ignore carry on this first addition. */
+ R0 = R0 + R3;
+ R0 = R0 + R1;
+ cc = ac0;
+ R1 = cc;
+ R1 = PACK(R1.l,R0.h);
+ R0 = R1 + R2;
+ RTS;
diff --git a/arch/blackfin/mach-bf533/Kconfig b/arch/blackfin/mach-bf533/Kconfig
new file mode 100644
index 00000000000..14297b3ed5c
--- /dev/null
+++ b/arch/blackfin/mach-bf533/Kconfig
@@ -0,0 +1,92 @@
+if (BF533 || BF532 || BF531)
+
+menu "BF533/2/1 Specific Configuration"
+
+comment "Interrupt Priority Assignment"
+menu "Priority"
+
+config UART_ERROR
+ int "UART ERROR"
+ default 7
+config SPORT0_ERROR
+ int "SPORT0 ERROR"
+ default 7
+config SPI_ERROR
+ int "SPI ERROR"
+ default 7
+config SPORT1_ERROR
+ int "SPORT1 ERROR"
+ default 7
+config PPI_ERROR
+ int "PPI ERROR"
+ default 7
+config DMA_ERROR
+ int "DMA ERROR"
+ default 7
+config PLLWAKE_ERROR
+ int "PLL WAKEUP ERROR"
+ default 7
+
+config RTC_ERROR
+ int "RTC ERROR"
+ default 8
+config DMA0_PPI
+ int "DMA0 PPI"
+ default 8
+
+config DMA1_SPORT0RX
+ int "DMA1 (SPORT0 RX)"
+ default 9
+config DMA2_SPORT0TX
+ int "DMA2 (SPORT0 TX)"
+ default 9
+config DMA3_SPORT1RX
+ int "DMA3 (SPORT1 RX)"
+ default 9
+config DMA4_SPORT1TX
+ int "DMA4 (SPORT1 TX)"
+ default 9
+config DMA5_SPI
+ int "DMA5 (SPI)"
+ default 10
+config DMA6_UARTRX
+ int "DMA6 (UART0 RX)"
+ default 10
+config DMA7_UARTTX
+ int "DMA7 (UART0 TX)"
+ default 10
+config TIMER0
+ int "TIMER0"
+ default 11
+config TIMER1
+ int "TIMER1"
+ default 11
+config TIMER2
+ int "TIMER2"
+ default 11
+config PFA
+ int "PF Interrupt A"
+ default 12
+config PFB
+ int "PF Interrupt B"
+ default 12
+config MEMDMA0
+ int "MEMORY DMA0"
+ default 13
+config MEMDMA1
+ int "MEMORY DMA1"
+ default 13
+config WDTIMER
+ int "WATCH DOG TIMER"
+ default 13
+
+ help
+ Enter the priority numbers between 7-13 ONLY. Others are Reserved.
+ This applies to all the above. It is not recommended to assign the
+ highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf533/Makefile b/arch/blackfin/mach-bf533/Makefile
new file mode 100644
index 00000000000..76d2c2b8579
--- /dev/null
+++ b/arch/blackfin/mach-bf533/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf533/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o
+
+obj-$(CONFIG_CPU_FREQ_BF533) += cpu.o
diff --git a/arch/blackfin/mach-bf533/boards/Makefile b/arch/blackfin/mach-bf533/boards/Makefile
new file mode 100644
index 00000000000..12a631ab389
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/Makefile
@@ -0,0 +1,8 @@
+#
+# arch/blackfin/mach-bf533/boards/Makefile
+#
+
+obj-$(CONFIG_GENERIC_BOARD) += generic_board.o
+obj-$(CONFIG_BFIN533_STAMP) += stamp.o
+obj-$(CONFIG_BFIN533_EZKIT) += ezkit.o
+obj-$(CONFIG_BFIN533_BLUETECHNIX_CM) += cm_bf533.o
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
new file mode 100644
index 00000000000..23a7f607df3
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -0,0 +1,267 @@
+/*
+ * File: arch/blackfin/mach-bf533/boards/cm_bf533.c
+ * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au> Copright 2005
+ *
+ * Created: 2005
+ * Description: Board description file
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "Bluetechnix CM BF533";
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },{
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 2, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .start = 0x20200300,
+ .end = 0x20200300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF0,
+ .end = IRQ_PF0,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 1,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+ {
+ .start = 0x20308000,
+ .end = 0x20308000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20308004,
+ .end = 0x20308004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF4,
+ .end = IRQ_PF4,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+ .sel15Kres = 1,
+ .clknotstop = 0,
+ .oc_enable = 0,
+ .int_act_high = 0,
+ .int_edge_triggered = 0,
+ .remote_wakeup_connected = 0,
+ .no_power_switching = 1,
+ .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+ .name = "isp1362-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &isp1362_priv,
+ },
+ .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+ .resource = isp1362_hcd_resources,
+};
+#endif
+
+static struct platform_device *cm_bf533_devices[] __initdata = {
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+ &bfin_sport0_uart_device,
+ &bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+ &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+};
+
+static int __init cm_bf533_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(cm_bf533_devices, ARRAY_SIZE(cm_bf533_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(cm_bf533_init);
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
new file mode 100644
index 00000000000..747298ea907
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -0,0 +1,224 @@
+/*
+ * File: arch/blackfin/mach-bf533/ezkit.c
+ * Based on: Orginal Work
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created: 2005
+ * Description:
+ *
+ * Modified: Robin Getz <rgetz@blackfin.uclinux.org> - Named the boards
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF533-EZKIT";
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+/*
+ * USB-LAN EzExtender board
+ * Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x20310300,
+ .end = 0x20310300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF9,
+ .end = IRQ_PF9,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *ezkit_devices[] __initdata = {
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+};
+
+static int __init ezkit_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(ezkit_init);
diff --git a/arch/blackfin/mach-bf533/boards/generic_board.c b/arch/blackfin/mach-bf533/boards/generic_board.c
new file mode 100644
index 00000000000..c0f43ccfbfb
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/generic_board.c
@@ -0,0 +1,95 @@
+/*
+ * File: arch/blackfin/mach-bf533/generic_board.c
+ * Based on: arch/blackfin/mach-bf533/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created: 2005
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/irq.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "UNKNOWN BOARD";
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .start = 0x20300300,
+ .end = 0x20300300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PROG_INTB,
+ .end = IRQ_PROG_INTB,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },{
+ /*
+ * denotes the flag pin and is used directly if
+ * CONFIG_IRQCHIP_DEMUX_GPIO is defined.
+ */
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+static struct platform_device *generic_board_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+};
+
+static int __init generic_board_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ return platform_add_devices(generic_board_devices, ARRAY_SIZE(generic_board_devices));
+}
+
+arch_initcall(generic_board_init);
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
new file mode 100644
index 00000000000..d7b3a5d74e8
--- /dev/null
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -0,0 +1,321 @@
+/*
+ * File: arch/blackfin/mach-bf533/stamp.c
+ * Based on: arch/blackfin/mach-bf533/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created: 2005
+ * Description: Board Info File for the BF533-STAMP
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF533-STAMP";
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x20300300,
+ .end = 0x20300300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+ {
+ .start = 0x20300000,
+ .end = 0x20300000 + 0x100,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF10,
+ .end = IRQ_PF10,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device net2272_bfin_device = {
+ .name = "net2272",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(net2272_bfin_resources),
+ .resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+ .ctl_reg = 0x4, /* send zero */
+ .enable_dma = 0,
+ .bits_per_word = 8,
+ .cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+static struct bfin5xx_spi_chip ad5304_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL2*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 31250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_PBX)
+ {
+ .modalias = "fxs-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 3,
+ .controller_data= &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "fxo-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .controller_data= &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+ {
+ .modalias = "ad5304_spi",
+ .max_speed_hz = 1000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .platform_data = NULL,
+ .controller_data = &ad5304_chip_info,
+ .mode = SPI_MODE_2,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+ .name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 1,
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+ &net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+ &bfin_sport0_uart_device,
+ &bfin_sport1_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c
new file mode 100644
index 00000000000..99547c4c290
--- /dev/null
+++ b/arch/blackfin/mach-bf533/cpu.c
@@ -0,0 +1,161 @@
+/*
+ * File: arch/blackfin/mach-bf533/cpu.c
+ * Based on:
+ * Author: michael.kang@analog.com
+ *
+ * Created:
+ * Description: clock scaling for the bf533
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/dpmc.h>
+#include <linux/fs.h>
+#include <asm/bfin-global.h>
+
+/* CONFIG_CLKIN_HZ=11059200 */
+#define VCO5 (CONFIG_CLKIN_HZ*45) /*497664000 */
+#define VCO4 (CONFIG_CLKIN_HZ*36) /*398131200 */
+#define VCO3 (CONFIG_CLKIN_HZ*27) /*298598400 */
+#define VCO2 (CONFIG_CLKIN_HZ*18) /*199065600 */
+#define VCO1 (CONFIG_CLKIN_HZ*9) /*99532800 */
+#define VCO(x) VCO##x
+
+#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
+/* frequency */
+static struct cpufreq_frequency_table bf533_freq_table[] = {
+ FREQ(1),
+ FREQ(3),
+ {VCO4, VCO4 / 2}, {VCO4, VCO4},
+ FREQ(5),
+ {0, CPUFREQ_TABLE_END},
+};
+
+/*
+ * dpmc_fops->ioctl()
+ * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ */
+static int bf533_getfreq(unsigned int cpu)
+{
+ unsigned long cclk_mhz, vco_mhz;
+
+ /* The driver only support single cpu */
+ if (cpu == 0)
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
+ else
+ cclk_mhz = -1;
+ return cclk_mhz;
+}
+
+static int bf533_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ unsigned long cclk_mhz;
+ unsigned long vco_mhz;
+ unsigned long flags;
+ unsigned int index, vco_index;
+ int i;
+
+ struct cpufreq_freqs freqs;
+ if (cpufreq_frequency_table_target
+ (policy, bf533_freq_table, target_freq, relation, &index))
+ return -EINVAL;
+ cclk_mhz = bf533_freq_table[index].frequency;
+ vco_mhz = bf533_freq_table[index].index;
+
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
+ freqs.old = bf533_getfreq(0);
+ freqs.new = cclk_mhz;
+ freqs.cpu = 0;
+
+ pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
+ cclk_mhz, vco_mhz, index, target_freq, freqs.old);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ local_irq_save(flags);
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
+ local_irq_restore(flags);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ vco_mhz = get_vco();
+ cclk_mhz = get_cclk();
+ return 0;
+}
+
+/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
+ * this platform, anyway.
+ */
+static int bf533_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, &bf533_freq_table);
+}
+
+static int __init __bf533_cpu_init(struct cpufreq_policy *policy)
+{
+ int result;
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ /*Now ,only support one cpu */
+ policy->cur = bf533_getfreq(0);
+ cpufreq_frequency_table_get_attr(bf533_freq_table, policy->cpu);
+ return cpufreq_frequency_table_cpuinfo(policy, bf533_freq_table);
+}
+
+static struct freq_attr *bf533_freq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver bf533_driver = {
+ .verify = bf533_verify_speed,
+ .target = bf533_target,
+ .get = bf533_getfreq,
+ .init = __bf533_cpu_init,
+ .name = "bf533",
+ .owner = THIS_MODULE,
+ .attr = bf533_freq_attr,
+};
+
+static int __init bf533_cpu_init(void)
+{
+ return cpufreq_register_driver(&bf533_driver);
+}
+
+static void __exit bf533_cpu_exit(void)
+{
+ cpufreq_unregister_driver(&bf533_driver);
+}
+
+MODULE_AUTHOR("Mickael Kang");
+MODULE_DESCRIPTION("cpufreq driver for BF533 CPU");
+MODULE_LICENSE("GPL");
+
+module_init(bf533_cpu_init);
+module_exit(bf533_cpu_exit);
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
new file mode 100644
index 00000000000..4808edb0680
--- /dev/null
+++ b/arch/blackfin/mach-bf533/head.S
@@ -0,0 +1,774 @@
+/*
+ * File: arch/blackfin/mach-bf533/head.S
+ * Based on:
+ * Author: Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
+ *
+ * Created: 1998
+ * Description: bf533 startup file
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+#if CONFIG_DEBUG_KERNEL_START
+#include <asm/mach-common/def_LPBlackfin.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK 0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+ /* R0: argument of command line string, passed from uboot, save it */
+ R7 = R0;
+ /* Set the SYSCFG register */
+ R0 = 0x36;
+ /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+ SYSCFG = R0;
+ R0 = 0;
+
+ /*Clear Out All the data and pointer Registers*/
+ R1 = R0;
+ R2 = R0;
+ R3 = R0;
+ R4 = R0;
+ R5 = R0;
+ R6 = R0;
+
+ P0 = R0;
+ P1 = R0;
+ P2 = R0;
+ P3 = R0;
+ P4 = R0;
+ P5 = R0;
+
+ LC0 = r0;
+ LC1 = r0;
+ L0 = r0;
+ L1 = r0;
+ L2 = r0;
+ L3 = r0;
+
+ /* Clear Out All the DAG Registers*/
+ B0 = r0;
+ B1 = r0;
+ B2 = r0;
+ B3 = r0;
+
+ I0 = r0;
+ I1 = r0;
+ I2 = r0;
+ I3 = r0;
+
+ M0 = r0;
+ M1 = r0;
+ M2 = r0;
+ M3 = r0;
+
+#if CONFIG_DEBUG_KERNEL_START
+
+/*
+ * Set up a temporary Event Vector Table, so if something bad happens before
+ * the kernel is fully started, it doesn't vector off into the bootloaders
+ * table
+ */
+ P0.l = lo(EVT2);
+ P0.h = hi(EVT2);
+ P1.l = lo(EVT15);
+ P1.h = hi(EVT15);
+ P2.l = debug_kernel_start_trap;
+ P2.h = debug_kernel_start_trap;
+
+ RTS = P2;
+ RTI = P2;
+ RTX = P2;
+ RTN = P2;
+ RTE = P2;
+
+.Lfill_temp_vector_table:
+ [P0++] = P2; /* Core Event Vector Table */
+ CC = P0 == P1;
+ if !CC JUMP .Lfill_temp_vector_table
+ P0 = r0;
+ P1 = r0;
+ P2 = r0;
+
+#endif
+
+ p0.h = hi(FIO_MASKA_C);
+ p0.l = lo(FIO_MASKA_C);
+ r0 = 0xFFFF(Z);
+ w[p0] = r0.L; /* Disable all interrupts */
+ ssync;
+
+ p0.h = hi(FIO_MASKB_C);
+ p0.l = lo(FIO_MASKB_C);
+ r0 = 0xFFFF(Z);
+ w[p0] = r0.L; /* Disable all interrupts */
+ ssync;
+
+ /* Turn off the icache */
+ p0.l = (IMEM_CONTROL & 0xFFFF);
+ p0.h = (IMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENICPLB;
+ R0 = R0 & R1;
+
+ /* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+ CLI R2;
+ SSYNC;
+#endif
+ [p0] = R0;
+ SSYNC;
+#ifdef ANOMALY_05000125
+ STI R2;
+#endif
+
+ /* Turn off the dcache */
+ p0.l = (DMEM_CONTROL & 0xFFFF);
+ p0.h = (DMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENDCPLB;
+ R0 = R0 & R1;
+
+ /* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+ CLI R2;
+ SSYNC;
+#endif
+ [p0] = R0;
+ SSYNC;
+#ifdef ANOMALY_05000125
+ STI R2;
+#endif
+
+ /* Initialise UART */
+ p0.h = hi(UART_LCR);
+ p0.l = lo(UART_LCR);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable DLL writes */
+ ssync;
+
+ p0.h = hi(UART_DLL);
+ p0.l = lo(UART_DLL);
+ r0 = 0x0(Z);
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_DLH);
+ p0.l = lo(UART_DLH);
+ r0 = 0x00(Z);
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_GCTL);
+ p0.l = lo(UART_GCTL);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable UART clock */
+ ssync;
+
+ /* Initialize stack pointer */
+ sp.l = lo(INITIAL_STACK);
+ sp.h = hi(INITIAL_STACK);
+ fp = sp;
+ usp = sp;
+
+ /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+ call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+ call _start_dma_code;
+#endif
+
+ /* Code for initializing Async memory banks */
+
+ p2.h = hi(EBIU_AMBCTL1);
+ p2.l = lo(EBIU_AMBCTL1);
+ r0.h = hi(AMBCTL1VAL);
+ r0.l = lo(AMBCTL1VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMBCTL0);
+ p2.l = lo(EBIU_AMBCTL0);
+ r0.h = hi(AMBCTL0VAL);
+ r0.l = lo(AMBCTL0VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMGCTL);
+ p2.l = lo(EBIU_AMGCTL);
+ r0 = AMGCTLVAL;
+ w[p2] = r0;
+ ssync;
+
+ /* This section keeps the processor in supervisor mode
+ * during kernel boot. Switches to user mode at end of boot.
+ * See page 3-9 of Hardware Reference manual for documentation.
+ */
+
+ /* EVT15 = _real_start */
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _real_start;
+ p1.h = _real_start;
+ [p0] = p1;
+ csync;
+
+ p0.l = lo(IMASK);
+ p0.h = hi(IMASK);
+ p1.l = IMASK_IVG15;
+ p1.h = 0x0;
+ [p0] = p1;
+ csync;
+
+ raise 15;
+ p0.l = .LWAIT_HERE;
+ p0.h = .LWAIT_HERE;
+ reti = p0;
+#if defined(ANOMALY_05000281)
+ nop; nop; nop;
+#endif
+ rti;
+
+.LWAIT_HERE:
+ jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+ [ -- sp ] = reti;
+ p0.l = lo(WDOG_CTL);
+ p0.h = hi(WDOG_CTL);
+ r0 = 0xAD6(z);
+ w[p0] = r0; /* watchdog off for now */
+ ssync;
+
+ /* Code update for BSS size == 0
+ * Zero out the bss region.
+ */
+
+ p1.l = ___bss_start;
+ p1.h = ___bss_start;
+ p2.l = ___bss_stop;
+ p2.h = ___bss_stop;
+ r0 = 0;
+ p2 -= p1;
+ lsetup (.L_clear_bss, .L_clear_bss) lc0 = p2;
+.L_clear_bss:
+ B[p1++] = r0;
+
+ /* In case there is a NULL pointer reference
+ * Zero out region before stext
+ */
+
+ p1.l = 0x0;
+ p1.h = 0x0;
+ r0.l = __stext;
+ r0.h = __stext;
+ r0 = r0 >> 1;
+ p2 = r0;
+ r0 = 0;
+ lsetup (.L_clear_zero, .L_clear_zero) lc0 = p2;
+.L_clear_zero:
+ W[p1++] = r0;
+
+/* pass the uboot arguments to the global value command line */
+ R0 = R7;
+ call _cmdline_init;
+
+ p1.l = __rambase;
+ p1.h = __rambase;
+ r0.l = __sdata;
+ r0.h = __sdata;
+ [p1] = r0;
+
+ p1.l = __ramstart;
+ p1.h = __ramstart;
+ p3.l = ___bss_stop;
+ p3.h = ___bss_stop;
+
+ r1 = p3;
+ [p1] = r1;
+
+ /*
+ * load the current thread pointer and stack
+ */
+ r1.l = _init_thread_union;
+ r1.h = _init_thread_union;
+
+ r2.l = 0x2000;
+ r2.h = 0x0000;
+ r1 = r1 + r2;
+ sp = r1;
+ usp = sp;
+ fp = sp;
+ call _start_kernel;
+.L_exit:
+ jump.s .L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+ p0.h = hi(SIC_IWR);
+ p0.l = lo(SIC_IWR);
+ r0.l = 0x1;
+ r0.h = 0x0;
+ [p0] = r0;
+ SSYNC;
+
+ /*
+ * Set PLL_CTL
+ * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+ * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
+ * - [7] = output delay (add 200ps of delay to mem signals)
+ * - [6] = input delay (add 200ps of input delay to mem signals)
+ * - [5] = PDWN : 1=All Clocks off
+ * - [3] = STOPCK : 1=Core Clock off
+ * - [1] = PLL_OFF : 1=Disable Power to PLL
+ * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+ * all other bits set to zero
+ */
+
+ p0.h = hi(PLL_LOCKCNT);
+ p0.l = lo(PLL_LOCKCNT);
+ r0 = 0x300(Z);
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITSET (R0, 24);
+ [P2] = R0;
+ SSYNC;
+
+ r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
+ r0 = r0 << 9; /* Shift it over, */
+ r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
+ r0 = r1 | r0;
+ r1 = PLL_BYPASS; /* Bypass the PLL? */
+ r1 = r1 << 8; /* Shift it over */
+ r0 = r1 | r0; /* add them all together */
+
+ p0.h = hi(PLL_CTL);
+ p0.l = lo(PLL_CTL); /* Load the address */
+ cli r2; /* Disable interrupts */
+ ssync;
+ w[p0] = r0.l; /* Set the value */
+ idle; /* Wait for the PLL to stablize */
+ sti r2; /* Enable interrupts */
+
+.Lcheck_again:
+ p0.h = hi(PLL_STAT);
+ p0.l = lo(PLL_STAT);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,5);
+ if ! CC jump .Lcheck_again;
+
+ /* Configure SCLK & CCLK Dividers */
+ r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+ p0.h = hi(PLL_DIV);
+ p0.l = lo(PLL_DIV);
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = lo(EBIU_SDRRC);
+ p0.h = hi(EBIU_SDRRC);
+ r0 = mem_SDRRC;
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = (EBIU_SDBCTL & 0xFFFF);
+ p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
+ r0 = mem_SDBCTL;
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITCLR (R0, 24);
+ p0.h = hi(EBIU_SDSTAT);
+ p0.l = lo(EBIU_SDSTAT);
+ r2.l = w[p0];
+ cc = bittst(r2,3);
+ if !cc jump .Lskip;
+ NOP;
+ BITSET (R0, 23);
+.Lskip:
+ [P2] = R0;
+ SSYNC;
+
+ R0.L = lo(mem_SDGCTL);
+ R0.H = hi(mem_SDGCTL);
+ R1 = [p2];
+ R1 = R1 | R0;
+ [P2] = R1;
+ SSYNC;
+
+ p0.h = hi(SIC_IWR);
+ p0.l = lo(SIC_IWR);
+ r0.l = lo(IWR_ENABLE_ALL)
+ r0.h = hi(IWR_ENABLE_ALL)
+ [p0] = r0;
+ SSYNC;
+
+ RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+ /* No more interrupts to be handled*/
+ CLI R6;
+ SSYNC;
+
+#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
+ p0.h = hi(FIO_INEN);
+ p0.l = lo(FIO_INEN);
+ r0.l = ~(1 << CONFIG_ENET_FLASH_PIN);
+ w[p0] = r0.l;
+
+ p0.h = hi(FIO_DIR);
+ p0.l = lo(FIO_DIR);
+ r0.l = (1 << CONFIG_ENET_FLASH_PIN);
+ w[p0] = r0.l;
+
+ p0.h = hi(FIO_FLAG_C);
+ p0.l = lo(FIO_FLAG_C);
+ r0.l = (1 << CONFIG_ENET_FLASH_PIN);
+ w[p0] = r0.l;
+#endif
+
+ /* Clear the bits 13-15 in SWRST if they werent cleared */
+ p0.h = hi(SWRST);
+ p0.l = lo(SWRST);
+ csync;
+ r0.l = w[p0];
+
+ /* Clear the IMASK register */
+ p0.h = hi(IMASK);
+ p0.l = lo(IMASK);
+ r0 = 0x0;
+ [p0] = r0;
+
+ /* Clear the ILAT register */
+ p0.h = hi(ILAT);
+ p0.l = lo(ILAT);
+ r0 = [p0];
+ [p0] = r0;
+ SSYNC;
+
+ /* Disable the WDOG TIMER */
+ p0.h = hi(WDOG_CTL);
+ p0.l = lo(WDOG_CTL);
+ r0.l = 0xAD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Clear the sticky bit incase it is already set */
+ p0.h = hi(WDOG_CTL);
+ p0.l = lo(WDOG_CTL);
+ r0.l = 0x8AD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Program the count value */
+ R0.l = 0x100;
+ R0.h = 0x0;
+ P0.h = hi(WDOG_CNT);
+ P0.l = lo(WDOG_CNT);
+ [P0] = R0;
+ SSYNC;
+
+ /* Program WDOG_STAT if necessary */
+ P0.h = hi(WDOG_CTL);
+ P0.l = lo(WDOG_CTL);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,1);
+ if !CC JUMP .LWRITESTAT;
+ CC = BITTST(R0,2);
+ if !CC JUMP .LWRITESTAT;
+ JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+ /* When watch dog timer is enabled, a write to STAT will load the contents of CNT to STAT */
+ R0 = 0x0000(z);
+ P0.h = hi(WDOG_STAT);
+ P0.l = lo(WDOG_STAT)
+ [P0] = R0;
+ SSYNC;
+
+.LSKIP_WRITE:
+ /* Enable the reset event */
+ P0.h = hi(WDOG_CTL);
+ P0.l = lo(WDOG_CTL);
+ R0 = W[P0](Z);
+ BITCLR(R0,1);
+ BITCLR(R0,2);
+ W[P0] = R0.L;
+ SSYNC;
+ NOP;
+
+ /* Enable the wdog counter */
+ R0 = W[P0](Z);
+ BITCLR(R0,4);
+ W[P0] = R0.L;
+ SSYNC;
+
+ IDLE;
+
+ RTS;
+
+#if CONFIG_DEBUG_KERNEL_START
+debug_kernel_start_trap:
+ /* Set up a temp stack in L1 - SDRAM might not be working */
+ P0.L = lo(L1_DATA_A_START + 0x100);
+ P0.H = hi(L1_DATA_A_START + 0x100);
+ SP = P0;
+
+ /* Make sure the Clocks are the way I think they should be */
+ r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
+ r0 = r0 << 9; /* Shift it over, */
+ r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
+ r0 = r1 | r0;
+ r1 = PLL_BYPASS; /* Bypass the PLL? */
+ r1 = r1 << 8; /* Shift it over */
+ r0 = r1 | r0; /* add them all together */
+
+ p0.h = hi(PLL_CTL);
+ p0.l = lo(PLL_CTL); /* Load the address */
+ cli r2; /* Disable interrupts */
+ ssync;
+ w[p0] = r0.l; /* Set the value */
+ idle; /* Wait for the PLL to stablize */
+ sti r2; /* Enable interrupts */
+
+.Lcheck_again1:
+ p0.h = hi(PLL_STAT);
+ p0.l = lo(PLL_STAT);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,5);
+ if ! CC jump .Lcheck_again1;
+
+ /* Configure SCLK & CCLK Dividers */
+ r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+ p0.h = hi(PLL_DIV);
+ p0.l = lo(PLL_DIV);
+ w[p0] = r0.l;
+ ssync;
+
+ /* Make sure UART is enabled - you can never be sure */
+
+/*
+ * Setup for console. Argument comes from the menuconfig
+ */
+
+#ifdef CONFIG_BAUD_9600
+#define CONSOLE_BAUD_RATE 9600
+#elif CONFIG_BAUD_19200
+#define CONSOLE_BAUD_RATE 19200
+#elif CONFIG_BAUD_38400
+#define CONSOLE_BAUD_RATE 38400
+#elif CONFIG_BAUD_57600
+#define CONSOLE_BAUD_RATE 57600
+#elif CONFIG_BAUD_115200
+#define CONSOLE_BAUD_RATE 115200
+#endif
+
+ p0.h = hi(UART_GCTL);
+ p0.l = lo(UART_GCTL);
+ r0 = 0x00(Z);
+ w[p0] = r0.L; /* To Turn off UART clocks */
+ ssync;
+
+ p0.h = hi(UART_LCR);
+ p0.l = lo(UART_LCR);
+ r0 = 0x83(Z);
+ w[p0] = r0.L; /* To enable DLL writes */
+ ssync;
+
+ R1 = (((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT) / CONFIG_SCLK_DIV) / (CONSOLE_BAUD_RATE * 16));
+
+ p0.h = hi(UART_DLL);
+ p0.l = lo(UART_DLL);
+ r0 = 0xFF(Z);
+ r0 = R1 & R0;
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_DLH);
+ p0.l = lo(UART_DLH);
+ r1 >>= 8 ;
+ w[p0] = r1.L;
+ ssync;
+
+ p0.h = hi(UART_GCTL);
+ p0.l = lo(UART_GCTL);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable UART clock */
+ ssync;
+
+ p0.h = hi(UART_LCR);
+ p0.l = lo(UART_LCR);
+ r0 = 0x03(Z);
+ w[p0] = r0.L; /* To Turn on UART */
+ ssync;
+
+ p0.h = hi(UART_GCTL);
+ p0.l = lo(UART_GCTL);
+ r0 = 0x01(Z);
+ w[p0] = r0.L; /* To Turn on UART Clocks */
+ ssync;
+
+ P0.h = hi(UART_THR);
+ P0.l = lo(UART_THR);
+ P1.h = hi(UART_LSR);
+ P1.l = lo(UART_LSR);
+
+ R0.L = 'K';
+ call .Lwait_char;
+ R0.L='e';
+ call .Lwait_char;
+ R0.L='r';
+ call .Lwait_char;
+ R0.L='n'
+ call .Lwait_char;
+ R0.L='e'
+ call .Lwait_char;
+ R0.L='l';
+ call .Lwait_char;
+ R0.L=' ';
+ call .Lwait_char;
+ R0.L='c';
+ call .Lwait_char;
+ R0.L='r';
+ call .Lwait_char;
+ R0.L='a';
+ call .Lwait_char;
+ R0.L='s';
+ call .Lwait_char;
+ R0.L='h';
+ call .Lwait_char;
+ R0.L='\r';
+ call .Lwait_char;
+ R0.L='\n';
+ call .Lwait_char;
+
+ R0.L='S';
+ call .Lwait_char;
+ R0.L='E';
+ call .Lwait_char;
+ R0.L='Q'
+ call .Lwait_char;
+ R0.L='S'
+ call .Lwait_char;
+ R0.L='T';
+ call .Lwait_char;
+ R0.L='A';
+ call .Lwait_char;
+ R0.L='T';
+ call .Lwait_char;
+ R0.L='=';
+ call .Lwait_char;
+ R2 = SEQSTAT;
+ call .Ldump_reg;
+
+ R0.L=' ';
+ call .Lwait_char;
+ R0.L='R';
+ call .Lwait_char;
+ R0.L='E'
+ call .Lwait_char;
+ R0.L='T'
+ call .Lwait_char;
+ R0.L='X';
+ call .Lwait_char;
+ R0.L='=';
+ call .Lwait_char;
+ R2 = RETX;
+ call .Ldump_reg;
+
+ R0.L='\r';
+ call .Lwait_char;
+ R0.L='\n';
+ call .Lwait_char;
+
+.Ldebug_kernel_start_trap_done:
+ JUMP .Ldebug_kernel_start_trap_done;
+.Ldump_reg:
+ R3 = 32;
+ R4 = 0x0F;
+ R5 = ':'; /* one past 9 */
+
+.Ldump_reg2:
+ R0 = R2;
+ R3 += -4;
+ R0 >>>= R3;
+ R0 = R0 & R4;
+ R0 += 0x30;
+ CC = R0 <= R5;
+ if CC JUMP .Ldump_reg1;
+ R0 += 7;
+
+.Ldump_reg1:
+ R1.l = W[P1];
+ CC = BITTST(R1, 5);
+ if !CC JUMP .Ldump_reg1;
+ W[P0] = r0;
+
+ CC = R3 == 0;
+ if !CC JUMP .Ldump_reg2
+ RTS;
+
+.Lwait_char:
+ R1.l = W[P1];
+ CC = BITTST(R1, 5);
+ if !CC JUMP .Lwait_char;
+ W[P0] = r0;
+ RTS;
+
+#endif /* CONFIG_DEBUG_KERNEL_START */
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long 0
+__ramstart:
+.long 0
+__ramend:
+.long 0
diff --git a/arch/blackfin/mach-bf533/ints-priority.c b/arch/blackfin/mach-bf533/ints-priority.c
new file mode 100644
index 00000000000..36a69334520
--- /dev/null
+++ b/arch/blackfin/mach-bf533/ints-priority.c
@@ -0,0 +1,65 @@
+/*
+ * File: arch/blackfin/mach-bf533/ints-priority.c
+ * Based on:
+ * Author: Michael Hennerich
+ *
+ * Created: ?
+ * Description: Set up the interupt priorities
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+void program_IAR(void)
+{
+ /* Program the IAR0 Register with the configured priority */
+ bfin_write_SIC_IAR0(((CONFIG_PLLWAKE_ERROR - 7) << PLLWAKE_ERROR_POS) |
+ ((CONFIG_DMA_ERROR - 7) << DMA_ERROR_POS) |
+ ((CONFIG_PPI_ERROR - 7) << PPI_ERROR_POS) |
+ ((CONFIG_SPORT0_ERROR - 7) << SPORT0_ERROR_POS) |
+ ((CONFIG_SPI_ERROR - 7) << SPI_ERROR_POS) |
+ ((CONFIG_SPORT1_ERROR - 7) << SPORT1_ERROR_POS) |
+ ((CONFIG_UART_ERROR - 7) << UART_ERROR_POS) |
+ ((CONFIG_RTC_ERROR - 7) << RTC_ERROR_POS));
+
+ bfin_write_SIC_IAR1(((CONFIG_DMA0_PPI - 7) << DMA0_PPI_POS) |
+ ((CONFIG_DMA1_SPORT0RX - 7) << DMA1_SPORT0RX_POS) |
+ ((CONFIG_DMA2_SPORT0TX - 7) << DMA2_SPORT0TX_POS) |
+ ((CONFIG_DMA3_SPORT1RX - 7) << DMA3_SPORT1RX_POS) |
+ ((CONFIG_DMA4_SPORT1TX - 7) << DMA4_SPORT1TX_POS) |
+ ((CONFIG_DMA5_SPI - 7) << DMA5_SPI_POS) |
+ ((CONFIG_DMA6_UARTRX - 7) << DMA6_UARTRX_POS) |
+ ((CONFIG_DMA7_UARTTX - 7) << DMA7_UARTTX_POS));
+
+ bfin_write_SIC_IAR2(((CONFIG_TIMER0 - 7) << TIMER0_POS) |
+ ((CONFIG_TIMER1 - 7) << TIMER1_POS) |
+ ((CONFIG_TIMER2 - 7) << TIMER2_POS) |
+ ((CONFIG_PFA - 7) << PFA_POS) |
+ ((CONFIG_PFB - 7) << PFB_POS) |
+ ((CONFIG_MEMDMA0 - 7) << MEMDMA0_POS) |
+ ((CONFIG_MEMDMA1 - 7) << MEMDMA1_POS) |
+ ((CONFIG_WDTIMER - 7) << WDTIMER_POS));
+
+ SSYNC();
+}
diff --git a/arch/blackfin/mach-bf537/Kconfig b/arch/blackfin/mach-bf537/Kconfig
new file mode 100644
index 00000000000..cc9ae38a4dd
--- /dev/null
+++ b/arch/blackfin/mach-bf537/Kconfig
@@ -0,0 +1,141 @@
+if (BF537 || BF534 || BF536)
+
+menu "BF537 Specific Configuration"
+
+comment "PORT F/G Selection"
+choice
+ prompt "Select BF537/6/4 default GPIO PFx PORTx"
+ help
+ Quick Hack for BF537/6/4 default GPIO PFx PORTF.
+
+config BF537_PORT_F
+ bool "Select BF537/6/4 default GPIO PFx PORTF"
+ depends on (BF537 || BF536 || BF534)
+ help
+ Quick Hack for BF537/6/4 default GPIO PFx PORTF.
+
+config BF537_PORT_G
+ bool "Select BF537/6/4 default GPIO PFx PORTG"
+ depends on (BF537 || BF536 || BF534)
+ help
+ Quick Hack for BF537/6/4 default GPIO PFx PORTG.
+
+config BF537_PORT_H
+ bool "Select BF537/6/4 default GPIO PFx PORTH"
+ depends on (BF537 || BF536 || BF534)
+ help
+ Quick Hack for BF537/6/4 default GPIO PFx PORTH
+ Use only when Blackfin EMAC support is not required.
+
+endchoice
+
+comment "Interrupt Priority Assignment"
+menu "Priority"
+
+config IRQ_PLL_WAKEUP
+ int "IRQ_PLL_WAKEUP"
+ default 7
+config IRQ_DMA_ERROR
+ int "IRQ_DMA_ERROR Generic"
+ default 7
+config IRQ_ERROR
+ int "IRQ_ERROR: CAN MAC SPORT0 SPORT1 SPI UART0 UART1"
+ default 7
+config IRQ_RTC
+ int "IRQ_RTC"
+ default 8
+config IRQ_PPI
+ int "IRQ_PPI"
+ default 8
+config IRQ_SPORT0_RX
+ int "IRQ_SPORT0_RX"
+ default 9
+config IRQ_SPORT0_TX
+ int "IRQ_SPORT0_TX"
+ default 9
+config IRQ_SPORT1_RX
+ int "IRQ_SPORT1_RX"
+ default 9
+config IRQ_SPORT1_TX
+ int "IRQ_SPORT1_TX"
+ default 9
+config IRQ_TWI
+ int "IRQ_TWI"
+ default 10
+config IRQ_SPI
+ int "IRQ_SPI"
+ default 10
+config IRQ_UART0_RX
+ int "IRQ_UART0_RX"
+ default 10
+config IRQ_UART0_TX
+ int "IRQ_UART0_TX"
+ default 10
+config IRQ_UART1_RX
+ int "IRQ_UART1_RX"
+ default 10
+config IRQ_UART1_TX
+ int "IRQ_UART1_TX"
+ default 10
+config IRQ_CAN_RX
+ int "IRQ_CAN_RX"
+ default 11
+config IRQ_CAN_TX
+ int "IRQ_CAN_TX"
+ default 11
+config IRQ_MAC_RX
+ int "IRQ_MAC_RX"
+ default 11
+config IRQ_MAC_TX
+ int "IRQ_MAC_TX"
+ default 11
+config IRQ_TMR0
+ int "IRQ_TMR0"
+ default 12
+config IRQ_TMR1
+ int "IRQ_TMR1"
+ default 12
+config IRQ_TMR2
+ int "IRQ_TMR2"
+ default 12
+config IRQ_TMR3
+ int "IRQ_TMR3"
+ default 12
+config IRQ_TMR4
+ int "IRQ_TMR4"
+ default 12
+config IRQ_TMR5
+ int "IRQ_TMR5"
+ default 12
+config IRQ_TMR6
+ int "IRQ_TMR6"
+ default 12
+config IRQ_TMR7
+ int "IRQ_TMR7"
+ default 12
+config IRQ_PROG_INTA
+ int "IRQ_PROG_INTA"
+ default 12
+config IRQ_PORTG_INTB
+ int "IRQ_PORTG_INTB"
+ default 12
+config IRQ_MEM_DMA0
+ int "IRQ_MEM_DMA0"
+ default 13
+config IRQ_MEM_DMA1
+ int "IRQ_MEM_DMA1"
+ default 13
+config IRQ_WATCH
+ int "IRQ_WATCH"
+ default 13
+
+ help
+ Enter the priority numbers between 7-13 ONLY. Others are Reserved.
+ This applies to all the above. It is not recommended to assign the
+ highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf537/Makefile b/arch/blackfin/mach-bf537/Makefile
new file mode 100644
index 00000000000..f32d44215bb
--- /dev/null
+++ b/arch/blackfin/mach-bf537/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf537/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o
+
+obj-$(CONFIG_CPU_FREQ) += cpu.o
diff --git a/arch/blackfin/mach-bf537/boards/Makefile b/arch/blackfin/mach-bf537/boards/Makefile
new file mode 100644
index 00000000000..23323cacc3a
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf537/boards/Makefile
+#
+
+obj-y += eth_mac.o
+obj-$(CONFIG_GENERIC_BOARD) += generic_board.o
+obj-$(CONFIG_BFIN537_STAMP) += stamp.o led.o
+obj-$(CONFIG_BFIN537_BLUETECHNIX_CM) += cm_bf537.o
+obj-$(CONFIG_PNAV10) += pnav10.o
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
new file mode 100644
index 00000000000..6a60618a78e
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -0,0 +1,364 @@
+/*
+ * File: arch/blackfin/mach-bf537/boards/cm_bf537.c
+ * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created: 2005
+ * Description: Board description file
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "Bluetechnix CM BF537";
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+ .enable_dma = 1,
+ .bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+ {
+ .modalias = "ad9960-spi",
+ .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .controller_data = &ad9960_spi_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+ {
+ .modalias = "spi_mmc_dummy",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 7,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "spi_mmc",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .start = 0x20200300,
+ .end = 0x20200300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF14,
+ .end = IRQ_PF14,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+ {
+ .start = 0x20308000,
+ .end = 0x20308000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20308004,
+ .end = 0x20308004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PG15,
+ .end = IRQ_PG15,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+ .sel15Kres = 1,
+ .clknotstop = 0,
+ .oc_enable = 0,
+ .int_act_high = 0,
+ .int_edge_triggered = 0,
+ .remote_wakeup_connected = 0,
+ .no_power_switching = 1,
+ .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+ .name = "isp1362-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &isp1362_priv,
+ },
+ .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+ .resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+ {
+ .start = 0x20200000,
+ .end = 0x20200000 + 0x100,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device net2272_bfin_device = {
+ .name = "net2272",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(net2272_bfin_resources),
+ .resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 1,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+ .name = "bfin_mac",
+};
+#endif
+
+static struct platform_device *cm_bf537_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+ &bfin_sport0_uart_device,
+ &bfin_sport1_uart_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+ &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+ &net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+};
+
+static int __init cm_bf537_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(cm_bf537_devices, ARRAY_SIZE(cm_bf537_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(cm_bf537_init);
diff --git a/arch/blackfin/mach-bf537/boards/eth_mac.c b/arch/blackfin/mach-bf537/boards/eth_mac.c
new file mode 100644
index 00000000000..e129a08d63d
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/eth_mac.c
@@ -0,0 +1,51 @@
+/*
+ * arch/blackfin/mach-bf537/board/eth_mac.c
+ *
+ * Copyright (C) 2007 Analog Devices, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/module.h>
+#include <asm/blackfin.h>
+
+#if defined(CONFIG_GENERIC_BOARD) \
+ || defined(CONFIG_BFIN537_STAMP)
+
+/*
+ * Currently the MAC address is saved in Flash by U-Boot
+ */
+#define FLASH_MAC 0x203f0000
+
+void get_bf537_ether_addr(char *addr)
+{
+ unsigned int flash_mac = (unsigned int) FLASH_MAC;
+ *(u32 *)(&(addr[0])) = bfin_read32(flash_mac);
+ flash_mac += 4;
+ *(u16 *)(&(addr[4])) = bfin_read16(flash_mac);
+}
+
+#else
+
+/*
+ * Provide MAC address function for other specific board setting
+ */
+void get_bf537_ether_addr(char *addr)
+{
+ printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n",__FILE__);
+}
+
+#endif
+
+EXPORT_SYMBOL(get_bf537_ether_addr);
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
new file mode 100644
index 00000000000..9019c0edbe7
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -0,0 +1,445 @@
+/*
+ * File: arch/blackfin/mach-bf537/boards/generic_board.c
+ * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+#include <linux/usb_sl811.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "UNKNOWN BOARD";
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+ {
+ .start = 0x20310000, /* IO PORT */
+ .end = 0x20312000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20311000, /* Attribute Memeory */
+ .end = 0x20311FFF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PROG_INTA,
+ .end = IRQ_PROG_INTA,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },{
+ .start = IRQ_PF4,
+ .end = IRQ_PF4,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },{
+ .start = 6, /* Card Detect PF6 */
+ .end = 6,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+ .name = "bfin_cf_pcmcia",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+ .resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x20300300,
+ .end = 0x20300300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PROG_INTB,
+ .end = IRQ_PROG_INTB,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },{
+ /*
+ * denotes the flag pin and is used directly if
+ * CONFIG_IRQCHIP_DEMUX_GPIO is defined.
+ */
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+static struct resource sl811_hcd_resources[] = {
+ {
+ .start = 0x20340000,
+ .end = 0x20340000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20340004,
+ .end = 0x20340004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PROG_INTA,
+ .end = IRQ_PROG_INTA,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },{
+ .start = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
+ .end = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+void sl811_port_power(struct device *dev, int is_on)
+{
+ unsigned short mask = (1<<CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+
+ bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
+ bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
+
+ if (is_on)
+ bfin_write_FIO_FLAG_S(mask);
+ else
+ bfin_write_FIO_FLAG_C(mask);
+}
+#endif
+
+static struct sl811_platform_data sl811_priv = {
+ .potpg = 10,
+ .power = 250, /* == 500mA */
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+ .port_power = &sl811_port_power,
+#endif
+};
+
+static struct platform_device sl811_hcd_device = {
+ .name = "sl811-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &sl811_priv,
+ },
+ .num_resources = ARRAY_SIZE(sl811_hcd_resources),
+ .resource = sl811_hcd_resources,
+};
+
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+ {
+ .start = 0x20360000,
+ .end = 0x20360000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20360004,
+ .end = 0x20360004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PROG_INTA,
+ .end = IRQ_PROG_INTA,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },{
+ .start = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
+ .end = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+ .sel15Kres = 1,
+ .clknotstop = 0,
+ .oc_enable = 0,
+ .int_act_high = 0,
+ .int_edge_triggered = 0,
+ .remote_wakeup_connected = 0,
+ .no_power_switching = 1,
+ .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+ .name = "isp1362-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &isp1362_priv,
+ },
+ .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+ .resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+ .name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+ {
+ .start = 0x20300000,
+ .end = 0x20300000 + 0x100,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device net2272_bfin_device = {
+ .name = "net2272",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(net2272_bfin_resources),
+ .resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 2, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+ {
+ .modalias = "ad9960-spi",
+ .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .controller_data = &ad9960_spi_chip_info,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+ .name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+ &bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+ &sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+ &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+ &net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+ &bfin_fb_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf537/boards/led.S b/arch/blackfin/mach-bf537/boards/led.S
new file mode 100644
index 00000000000..4e9ea4283e5
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/led.S
@@ -0,0 +1,183 @@
+/****************************************************
+ * LED1 ---- PF6 LED2 ---- PF7 *
+ * LED3 ---- PF8 LED4 ---- PF9 *
+ * LED5 ---- PF10 LED6 ---- PF11 *
+ ****************************************************/
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+/* All functions in this file save the registers they uses.
+ So there is no need to save any registers before calling them. */
+
+ .text;
+
+/* Initialize LEDs. */
+
+ENTRY(_led_init)
+ LINK 12;
+ [--SP] = P0;
+ [--SP] = R0;
+ [--SP] = R1;
+ [--SP] = R2;
+ R1 = PF6|PF7|PF8|PF9|PF10|PF11 (Z);
+ R2 = ~R1;
+
+ P0.H = hi(PORTF_FER);
+ P0.L = lo(PORTF_FER);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 & R2;
+ W[P0] = R0.L;
+ SSYNC;
+
+ P0.H = hi(PORTFIO_DIR);
+ P0.L = lo(PORTFIO_DIR);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 | R1;
+ W[P0] = R0.L;
+ SSYNC;
+
+ P0.H = hi(PORTFIO_INEN);
+ P0.L = lo(PORTFIO_INEN);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 & R2;
+ W[P0] = R0.L;
+ SSYNC;
+
+ R2 = [SP++];
+ R1 = [SP++];
+ R0 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_init, .-_led_init
+
+/* Set one LED on. Leave other LEDs unchanged.
+ It expects the LED number passed through R0. */
+
+ENTRY(_led_on)
+ LINK 12;
+ [--SP] = P0;
+ [--SP] = R1;
+ CALL _led_init;
+ R1 = 1;
+ R0 += 5;
+ R1 <<= R0;
+ P0.H = hi(PORTFIO);
+ P0.L = lo(PORTFIO);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 | R1;
+ W[P0] = R0.L;
+ SSYNC;
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_on, .-_led_on
+
+/* Set one LED off. Leave other LEDs unchanged. */
+
+ENTRY(_led_off)
+ LINK 12;
+ [--SP] = P0;
+ [--SP] = R1;
+ CALL _led_init;
+ R1 = 1;
+ R0 += 5;
+ R1 <<= R0;
+ R1 = ~R1;
+ P0.H = hi(PORTFIO);
+ P0.L = lo(PORTFIO);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 & R1;
+ W[P0] = R0.L;
+ SSYNC;
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_off, .-_led_off
+
+/* Toggle one LED. Leave other LEDs unchanged. */
+
+ENTRY(_led_toggle)
+ LINK 12;
+ [--SP] = P0;
+ [--SP] = R1;
+ CALL _led_init;
+ R1 = 1;
+ R0 += 5;
+ R1 <<= R0;
+ P0.H = hi(PORTFIO);
+ P0.L = lo(PORTFIO);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 ^ R1;
+ W[P0] = R0.L;
+ SSYNC;
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_toggle, .-_led_toggle
+
+/* Display the number using LEDs in binary format. */
+
+ENTRY(_led_disp_num)
+ LINK 12;
+ [--SP] = P0;
+ [--SP] = R1;
+ [--SP] = R2;
+ CALL _led_init;
+ R1 = 0x3f(X);
+ R0 = R0 & R1;
+ R2 = 6(X);
+ R0 <<= R2;
+ R1 <<= R2;
+ P0.H = hi(PORTFIO);
+ P0.L = lo(PORTFIO);
+ R2 = W[P0](Z);
+ SSYNC;
+ R1 = ~R1;
+ R2 = R2 & R1;
+ R2 = R2 | R0;
+ W[P0] = R2.L;
+ SSYNC;
+ R2 = [SP++];
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_disp_num, .-_led_disp_num
+
+/* Toggle the number using LEDs in binary format. */
+
+ENTRY(_led_toggle_num)
+ LINK 12;
+ [--SP] = P0;
+ [--SP] = R1;
+ [--SP] = R2;
+ CALL _led_init;
+ R1 = 0x3f(X);
+ R0 = R0 & R1;
+ R1 = 6(X);
+ R0 <<= R1;
+ P0.H = hi(PORTFIO);
+ P0.L = lo(PORTFIO);
+ R1 = W[P0](Z);
+ SSYNC;
+ R1 = R1 ^ R0;
+ W[P0] = R1.L;
+ SSYNC;
+ R2 = [SP++];
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_toggle_num, .-_led_toggle_num
+
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
new file mode 100644
index 00000000000..40d3a1b70ee
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -0,0 +1,523 @@
+/*
+ * File: arch/blackfin/mach-bf537/boards/stamp.c
+ * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+#include <linux/usb_sl811.h>
+
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "PNAV-1.0";
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+ {
+ .start = 0x20310000, /* IO PORT */
+ .end = 0x20312000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20311000, /* Attribute Memeory */
+ .end = 0x20311FFF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF4,
+ .end = IRQ_PF4,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },{
+ .start = 6, /* Card Detect PF6 */
+ .end = 6,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+ .name = "bfin_cf_pcmcia",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+ .resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x20300300,
+ .end = 0x20300300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+static struct resource sl811_hcd_resources[] = {
+ {
+ .start = 0x20340000,
+ .end = 0x20340000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20340004,
+ .end = 0x20340004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = CONFIG_USB_SL811_BFIN_IRQ,
+ .end = CONFIG_USB_SL811_BFIN_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+void sl811_port_power(struct device *dev, int is_on)
+{
+ unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+
+ bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
+ bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
+
+ if (is_on)
+ bfin_write_FIO_FLAG_S(mask);
+ else
+ bfin_write_FIO_FLAG_C(mask);
+}
+#endif
+
+static struct sl811_platform_data sl811_priv = {
+ .potpg = 10,
+ .power = 250, /* == 500mA */
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+ .port_power = &sl811_port_power,
+#endif
+};
+
+static struct platform_device sl811_hcd_device = {
+ .name = "sl811-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &sl811_priv,
+ },
+ .num_resources = ARRAY_SIZE(sl811_hcd_resources),
+ .resource = sl811_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+ {
+ .start = 0x20360000,
+ .end = 0x20360000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20360004,
+ .end = 0x20360004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+ .end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+ .sel15Kres = 1,
+ .clknotstop = 0,
+ .oc_enable = 0,
+ .int_act_high = 0,
+ .int_edge_triggered = 0,
+ .remote_wakeup_connected = 0,
+ .no_power_switching = 1,
+ .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+ .name = "isp1362-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &isp1362_priv,
+ },
+ .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+ .resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+ .name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+ {
+ .start = 0x20300000,
+ .end = 0x20300000 + 0x100,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device net2272_bfin_device = {
+ .name = "net2272",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(net2272_bfin_resources),
+ .resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) \
+ || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+ .enable_dma = 1,
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+ .ctl_reg = 0x4, /* send zero */
+ .enable_dma = 0,
+ .bits_per_word = 8,
+ .cs_change_per_word = 1,
+};
+#endif
+
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+ .cs_change_per_word = 1,
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+ .model = 7877,
+ .vref_delay_usecs = 50, /* internal, no capacitor */
+ .x_plate_ohms = 419,
+ .y_plate_ohms = 486,
+ .pressure_max = 1000,
+ .pressure_min = 0,
+ .stopacq_polarity = 1,
+ .first_conversion_delay = 3,
+ .acquisition_time = 1,
+ .averaging = 1,
+ .pen_down_acc_interval = 1,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+ || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+ {
+ .modalias = "ad9960-spi",
+ .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .controller_data = &ad9960_spi_chip_info,
+ },
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+ {
+ .modalias = "spi_mmc_dummy",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 7,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "spi_mmc",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+#if defined(CONFIG_PBX)
+ {
+ .modalias = "fxs-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 3,
+ .controller_data= &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "fxo-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .controller_data= &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+{
+ .modalias = "ad7877",
+ .platform_data = &bfin_ad7877_ts_info,
+ .irq = IRQ_PF2,
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 5,
+ .controller_data = &spi_ad7877_chip_info,
+},
+#endif
+
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+ .name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+ &bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+ &sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+ &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+ &net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+ &bfin_fb_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info,
+ ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
new file mode 100644
index 00000000000..ba2f875a7f7
--- /dev/null
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -0,0 +1,615 @@
+/*
+ * File: arch/blackfin/mach-bf537/boards/stamp.c
+ * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+#include <linux/usb_isp1362.h>
+#endif
+#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/bfin5xx_spi.h>
+#include <linux/usb_sl811.h>
+
+#include <linux/spi/ad7877.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF537-STAMP";
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+
+#define ISP1761_BASE 0x203C0000
+#define ISP1761_IRQ IRQ_PF7
+
+#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
+static struct resource bfin_isp1761_resources[] = {
+ [0] = {
+ .name = "isp1761-regs",
+ .start = ISP1761_BASE + 0x00000000,
+ .end = ISP1761_BASE + 0x000fffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = ISP1761_IRQ,
+ .end = ISP1761_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_isp1761_device = {
+ .name = "isp1761",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bfin_isp1761_resources),
+ .resource = bfin_isp1761_resources,
+};
+
+static struct platform_device *bfin_isp1761_devices[] = {
+ &bfin_isp1761_device,
+};
+
+int __init bfin_isp1761_init(void)
+{
+ unsigned int num_devices=ARRAY_SIZE(bfin_isp1761_devices);
+
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
+
+ return platform_add_devices(bfin_isp1761_devices, num_devices);
+}
+
+void __exit bfin_isp1761_exit(void)
+{
+ platform_device_unregister(&bfin_isp1761_device);
+}
+
+arch_initcall(bfin_isp1761_init);
+#endif
+
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+static struct resource bfin_pcmcia_cf_resources[] = {
+ {
+ .start = 0x20310000, /* IO PORT */
+ .end = 0x20312000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20311000, /* Attribute Memeory */
+ .end = 0x20311FFF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF4,
+ .end = IRQ_PF4,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },{
+ .start = 6, /* Card Detect PF6 */
+ .end = 6,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device bfin_pcmcia_cf_device = {
+ .name = "bfin_cf_pcmcia",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(bfin_pcmcia_cf_resources),
+ .resource = bfin_pcmcia_cf_resources,
+};
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x20300300,
+ .end = 0x20300300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+static struct resource sl811_hcd_resources[] = {
+ {
+ .start = 0x20340000,
+ .end = 0x20340000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20340004,
+ .end = 0x20340004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = CONFIG_USB_SL811_BFIN_IRQ,
+ .end = CONFIG_USB_SL811_BFIN_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+void sl811_port_power(struct device *dev, int is_on)
+{
+ unsigned short mask = (1 << CONFIG_USB_SL811_BFIN_GPIO_VBUS);
+
+ bfin_write_PORT_FER(bfin_read_PORT_FER() & ~mask);
+ bfin_write_FIO_DIR(bfin_read_FIO_DIR() | mask);
+
+ if (is_on)
+ bfin_write_FIO_FLAG_S(mask);
+ else
+ bfin_write_FIO_FLAG_C(mask);
+}
+#endif
+
+static struct sl811_platform_data sl811_priv = {
+ .potpg = 10,
+ .power = 250, /* == 500mA */
+#if defined(CONFIG_USB_SL811_BFIN_USE_VBUS)
+ .port_power = &sl811_port_power,
+#endif
+};
+
+static struct platform_device sl811_hcd_device = {
+ .name = "sl811-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &sl811_priv,
+ },
+ .num_resources = ARRAY_SIZE(sl811_hcd_resources),
+ .resource = sl811_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+ {
+ .start = 0x20360000,
+ .end = 0x20360000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x20360004,
+ .end = 0x20360004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+ .end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+ .sel15Kres = 1,
+ .clknotstop = 0,
+ .oc_enable = 0,
+ .int_act_high = 0,
+ .int_edge_triggered = 0,
+ .remote_wakeup_connected = 0,
+ .no_power_switching = 1,
+ .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+ .name = "isp1362-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &isp1362_priv,
+ },
+ .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+ .resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static struct platform_device bfin_mac_device = {
+ .name = "bfin_mac",
+};
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+static struct resource net2272_bfin_resources[] = {
+ {
+ .start = 0x20300000,
+ .end = 0x20300000 + 0x100,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF7,
+ .end = IRQ_PF7,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device net2272_bfin_device = {
+ .name = "net2272",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(net2272_bfin_resources),
+ .resource = net2272_bfin_resources,
+};
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI peripherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) \
+ || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+ .enable_dma = 1,
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_PBX)
+static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
+ .ctl_reg = 0x4, /* send zero */
+ .enable_dma = 0,
+ .bits_per_word = 8,
+ .cs_change_per_word = 1,
+};
+#endif
+
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+static struct bfin5xx_spi_chip ad5304_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
+// .cs_change_per_word = 1,
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+
+static const struct ad7877_platform_data bfin_ad7877_ts_info = {
+ .model = 7877,
+ .vref_delay_usecs = 50, /* internal, no capacitor */
+ .x_plate_ohms = 419,
+ .y_plate_ohms = 486,
+ .pressure_max = 1000,
+ .pressure_min = 0,
+ .stopacq_polarity = 1,
+ .first_conversion_delay = 3,
+ .acquisition_time = 1,
+ .averaging = 1,
+ .pen_down_acc_interval = 1,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) \
+ || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) \
+ || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+ {
+ .modalias = "ad9960-spi",
+ .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .controller_data = &ad9960_spi_chip_info,
+ },
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+ {
+ .modalias = "spi_mmc_dummy",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 0,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "spi_mmc",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+#if defined(CONFIG_PBX)
+ {
+ .modalias = "fxs-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 3,
+ .controller_data= &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "fxo-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .controller_data= &spi_si3xxx_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+#if defined(CONFIG_AD5304) || defined(CONFIG_AD5304_MODULE)
+ {
+ .modalias = "ad5304_spi",
+ .max_speed_hz = 1250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .platform_data = NULL,
+ .controller_data = &ad5304_chip_info,
+ .mode = SPI_MODE_2,
+ },
+#endif
+#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
+ {
+ .modalias = "ad7877",
+ .platform_data = &bfin_ad7877_ts_info,
+ .irq = IRQ_PF6,
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .controller_data = &spi_ad7877_chip_info,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+static struct platform_device bfin_fb_device = {
+ .name = "bf537-fb",
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+static struct platform_device i2c_bfin_twi_device = {
+ .name = "i2c-bfin-twi",
+ .id = 0,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+static struct platform_device bfin_sport0_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 0,
+};
+
+static struct platform_device bfin_sport1_uart_device = {
+ .name = "bfin-sport-uart",
+ .id = 1,
+};
+#endif
+
+static struct platform_device *stamp_devices[] __initdata = {
+#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
+ &bfin_pcmcia_cf_device,
+#endif
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
+ &sl811_hcd_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+ &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ &bfin_mac_device,
+#endif
+
+#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
+ &net2272_bfin_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+
+#if defined(CONFIG_FB_BF537_LQ035) || defined(CONFIG_FB_BF537_LQ035_MODULE)
+ &bfin_fb_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_I2C_BLACKFIN_TWI) || defined(CONFIG_I2C_BLACKFIN_TWI_MODULE)
+ &i2c_bfin_twi_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+ &bfin_sport0_uart_device,
+ &bfin_sport1_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(stamp_devices, ARRAY_SIZE(stamp_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info,
+ ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf537/cpu.c b/arch/blackfin/mach-bf537/cpu.c
new file mode 100644
index 00000000000..2d83b7e3546
--- /dev/null
+++ b/arch/blackfin/mach-bf537/cpu.c
@@ -0,0 +1,161 @@
+/*
+ * File: arch/blackfin/mach-bf537/cpu.c
+ * Based on:
+ * Author: michael.kang@analog.com
+ *
+ * Created:
+ * Description: clock scaling for the bf537
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/dpmc.h>
+#include <linux/fs.h>
+#include <asm/bfin-global.h>
+
+/* CONFIG_CLKIN_HZ=11059200 */
+#define VCO5 (CONFIG_CLKIN_HZ*45) /*497664000 */
+#define VCO4 (CONFIG_CLKIN_HZ*36) /*398131200 */
+#define VCO3 (CONFIG_CLKIN_HZ*27) /*298598400 */
+#define VCO2 (CONFIG_CLKIN_HZ*18) /*199065600 */
+#define VCO1 (CONFIG_CLKIN_HZ*9) /*99532800 */
+#define VCO(x) VCO##x
+
+#define FREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
+/* frequency */
+static struct cpufreq_frequency_table bf537_freq_table[] = {
+ FREQ(1),
+ FREQ(3),
+ {VCO4, VCO4 / 2}, {VCO4, VCO4},
+ FREQ(5),
+ {0, CPUFREQ_TABLE_END},
+};
+
+/*
+ * dpmc_fops->ioctl()
+ * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ */
+static int bf537_getfreq(unsigned int cpu)
+{
+ unsigned long cclk_mhz, vco_mhz;
+
+ /* The driver only support single cpu */
+ if (cpu == 0)
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
+ else
+ cclk_mhz = -1;
+ return cclk_mhz;
+}
+
+static int bf537_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ unsigned long cclk_mhz;
+ unsigned long vco_mhz;
+ unsigned long flags;
+ unsigned int index, vco_index;
+ int i;
+
+ struct cpufreq_freqs freqs;
+ if (cpufreq_frequency_table_target
+ (policy, bf537_freq_table, target_freq, relation, &index))
+ return -EINVAL;
+ cclk_mhz = bf537_freq_table[index].frequency;
+ vco_mhz = bf537_freq_table[index].index;
+
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
+ freqs.old = bf537_getfreq(0);
+ freqs.new = cclk_mhz;
+ freqs.cpu = 0;
+
+ pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
+ cclk_mhz, vco_mhz, index, target_freq, freqs.old);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ local_irq_save(flags);
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
+ local_irq_restore(flags);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ vco_mhz = get_vco();
+ cclk_mhz = get_cclk();
+ return 0;
+}
+
+/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
+ * this platform, anyway.
+ */
+static int bf537_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, &bf537_freq_table);
+}
+
+static int __init __bf537_cpu_init(struct cpufreq_policy *policy)
+{
+ int result;
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ /*Now ,only support one cpu */
+ policy->cur = bf537_getfreq(0);
+ cpufreq_frequency_table_get_attr(bf537_freq_table, policy->cpu);
+ return cpufreq_frequency_table_cpuinfo(policy, bf537_freq_table);
+}
+
+static struct freq_attr *bf537_freq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver bf537_driver = {
+ .verify = bf537_verify_speed,
+ .target = bf537_target,
+ .get = bf537_getfreq,
+ .init = __bf537_cpu_init,
+ .name = "bf537",
+ .owner = THIS_MODULE,
+ .attr = bf537_freq_attr,
+};
+
+static int __init bf537_cpu_init(void)
+{
+ return cpufreq_register_driver(&bf537_driver);
+}
+
+static void __exit bf537_cpu_exit(void)
+{
+ cpufreq_unregister_driver(&bf537_driver);
+}
+
+MODULE_AUTHOR("Mickael Kang");
+MODULE_DESCRIPTION("cpufreq driver for BF537 CPU");
+MODULE_LICENSE("GPL");
+
+module_init(bf537_cpu_init);
+module_exit(bf537_cpu_exit);
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
new file mode 100644
index 00000000000..d104e1d8e07
--- /dev/null
+++ b/arch/blackfin/mach-bf537/head.S
@@ -0,0 +1,602 @@
+/*
+ * File: arch/blackfin/mach-bf537/head.S
+ * Based on: arch/blackfin/mach-bf533/head.S
+ * Author: Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
+ *
+ * Created: 1998
+ * Description: Startup code for Blackfin BF537
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK 0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+ /* R0: argument of command line string, passed from uboot, save it */
+ R7 = R0;
+ /* Set the SYSCFG register */
+ R0 = 0x36;
+ SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+ R0 = 0;
+
+ /* Clear Out All the data and pointer Registers*/
+ R1 = R0;
+ R2 = R0;
+ R3 = R0;
+ R4 = R0;
+ R5 = R0;
+ R6 = R0;
+
+ P0 = R0;
+ P1 = R0;
+ P2 = R0;
+ P3 = R0;
+ P4 = R0;
+ P5 = R0;
+
+ LC0 = r0;
+ LC1 = r0;
+ L0 = r0;
+ L1 = r0;
+ L2 = r0;
+ L3 = r0;
+
+ /* Clear Out All the DAG Registers*/
+ B0 = r0;
+ B1 = r0;
+ B2 = r0;
+ B3 = r0;
+
+ I0 = r0;
+ I1 = r0;
+ I2 = r0;
+ I3 = r0;
+
+ M0 = r0;
+ M1 = r0;
+ M2 = r0;
+ M3 = r0;
+
+ /* Turn off the icache */
+ p0.l = (IMEM_CONTROL & 0xFFFF);
+ p0.h = (IMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENICPLB;
+ R0 = R0 & R1;
+
+ /* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+ CLI R2;
+ SSYNC;
+#endif
+ [p0] = R0;
+ SSYNC;
+#ifdef ANOMALY_05000125
+ STI R2;
+#endif
+
+ /* Turn off the dcache */
+ p0.l = (DMEM_CONTROL & 0xFFFF);
+ p0.h = (DMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENDCPLB;
+ R0 = R0 & R1;
+
+ /* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+ CLI R2;
+ SSYNC;
+#endif
+ [p0] = R0;
+ SSYNC;
+#ifdef ANOMALY_05000125
+ STI R2;
+#endif
+
+ /* Initialise General-Purpose I/O Modules on BF537 */
+ /* Rev 0.0 Anomaly 05000212 - PORTx_FER,
+ * PORT_MUX Registers Do Not accept "writes" correctly:
+ */
+ p0.h = hi(BFIN_PORT_MUX);
+ p0.l = lo(BFIN_PORT_MUX);
+#ifdef ANOMALY_05000212
+ R0.L = W[P0]; /* Read */
+ SSYNC;
+#endif
+ R0 = (PGDE_UART | PFTE_UART)(Z);
+#ifdef ANOMALY_05000212
+ W[P0] = R0.L; /* Write */
+ SSYNC;
+#endif
+ W[P0] = R0.L; /* Enable both UARTS */
+ SSYNC;
+
+ p0.h = hi(PORTF_FER);
+ p0.l = lo(PORTF_FER);
+#ifdef ANOMALY_05000212
+ R0.L = W[P0]; /* Read */
+ SSYNC;
+#endif
+ R0 = 0x000F(Z);
+#ifdef ANOMALY_05000212
+ W[P0] = R0.L; /* Write */
+ SSYNC;
+#endif
+ /* Enable peripheral function of PORTF for UART0 and UART1 */
+ W[P0] = R0.L;
+ SSYNC;
+
+#if !defined(CONFIG_BF534)
+ p0.h = hi(EMAC_SYSTAT);
+ p0.l = lo(EMAC_SYSTAT);
+ R0.h = 0xFFFF; /* Clear EMAC Interrupt Status bits */
+ R0.l = 0xFFFF;
+ [P0] = R0;
+ SSYNC;
+#endif
+
+#ifdef CONFIG_BF537_PORT_H
+ p0.h = hi(PORTH_FER);
+ p0.l = lo(PORTH_FER);
+ R0.L = W[P0]; /* Read */
+ SSYNC;
+ R0 = 0x0000;
+ W[P0] = R0.L; /* Write */
+ SSYNC;
+ W[P0] = R0.L; /* Disable peripheral function of PORTH */
+ SSYNC;
+#endif
+
+ /*Initialise UART*/
+ p0.h = hi(UART_LCR);
+ p0.l = lo(UART_LCR);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable DLL writes */
+ ssync;
+
+ p0.h = hi(UART_DLL);
+ p0.l = lo(UART_DLL);
+ r0 = 0x00(Z);
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_DLH);
+ p0.l = lo(UART_DLH);
+ r0 = 0x00(Z);
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_GCTL);
+ p0.l = lo(UART_GCTL);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable UART clock */
+ ssync;
+
+ /* Initialize stack pointer */
+ sp.l = lo(INITIAL_STACK);
+ sp.h = hi(INITIAL_STACK);
+ fp = sp;
+ usp = sp;
+
+ /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+ call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+ call _start_dma_code;
+#endif
+ /* Code for initializing Async memory banks */
+
+ p2.h = hi(EBIU_AMBCTL1);
+ p2.l = lo(EBIU_AMBCTL1);
+ r0.h = hi(AMBCTL1VAL);
+ r0.l = lo(AMBCTL1VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMBCTL0);
+ p2.l = lo(EBIU_AMBCTL0);
+ r0.h = hi(AMBCTL0VAL);
+ r0.l = lo(AMBCTL0VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMGCTL);
+ p2.l = lo(EBIU_AMGCTL);
+ r0 = AMGCTLVAL;
+ w[p2] = r0;
+ ssync;
+
+ /* This section keeps the processor in supervisor mode
+ * during kernel boot. Switches to user mode at end of boot.
+ * See page 3-9 of Hardware Reference manual for documentation.
+ */
+
+ /* EVT15 = _real_start */
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _real_start;
+ p1.h = _real_start;
+ [p0] = p1;
+ csync;
+
+ p0.l = lo(IMASK);
+ p0.h = hi(IMASK);
+ p1.l = IMASK_IVG15;
+ p1.h = 0x0;
+ [p0] = p1;
+ csync;
+
+ raise 15;
+ p0.l = .LWAIT_HERE;
+ p0.h = .LWAIT_HERE;
+ reti = p0;
+#if defined(ANOMALY_05000281)
+ nop; nop; nop;
+#endif
+ rti;
+
+.LWAIT_HERE:
+ jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+ [ -- sp ] = reti;
+ p0.l = lo(WDOG_CTL);
+ p0.h = hi(WDOG_CTL);
+ r0 = 0xAD6(z);
+ w[p0] = r0; /* watchdog off for now */
+ ssync;
+
+ /* Code update for BSS size == 0
+ * Zero out the bss region.
+ */
+
+ p1.l = ___bss_start;
+ p1.h = ___bss_start;
+ p2.l = ___bss_stop;
+ p2.h = ___bss_stop;
+ r0 = 0;
+ p2 -= p1;
+ lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
+.L_clear_bss:
+ B[p1++] = r0;
+
+ /* In case there is a NULL pointer reference
+ * Zero out region before stext
+ */
+
+ p1.l = 0x0;
+ p1.h = 0x0;
+ r0.l = __stext;
+ r0.h = __stext;
+ r0 = r0 >> 1;
+ p2 = r0;
+ r0 = 0;
+ lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
+.L_clear_zero:
+ W[p1++] = r0;
+
+ /* pass the uboot arguments to the global value command line */
+ R0 = R7;
+ call _cmdline_init;
+
+ p1.l = __rambase;
+ p1.h = __rambase;
+ r0.l = __sdata;
+ r0.h = __sdata;
+ [p1] = r0;
+
+ p1.l = __ramstart;
+ p1.h = __ramstart;
+ p3.l = ___bss_stop;
+ p3.h = ___bss_stop;
+
+ r1 = p3;
+ [p1] = r1;
+
+
+ /*
+ * load the current thread pointer and stack
+ */
+ r1.l = _init_thread_union;
+ r1.h = _init_thread_union;
+
+ r2.l = 0x2000;
+ r2.h = 0x0000;
+ r1 = r1 + r2;
+ sp = r1;
+ usp = sp;
+ fp = sp;
+ call _start_kernel;
+.L_exit:
+ jump.s .L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+
+ /* Enable PHY CLK buffer output */
+ p0.h = hi(VR_CTL);
+ p0.l = lo(VR_CTL);
+ r0.l = w[p0];
+ bitset(r0, 14);
+ w[p0] = r0.l;
+ ssync;
+
+ p0.h = hi(SIC_IWR);
+ p0.l = lo(SIC_IWR);
+ r0.l = 0x1;
+ r0.h = 0x0;
+ [p0] = r0;
+ SSYNC;
+
+ /*
+ * Set PLL_CTL
+ * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+ * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
+ * - [7] = output delay (add 200ps of delay to mem signals)
+ * - [6] = input delay (add 200ps of input delay to mem signals)
+ * - [5] = PDWN : 1=All Clocks off
+ * - [3] = STOPCK : 1=Core Clock off
+ * - [1] = PLL_OFF : 1=Disable Power to PLL
+ * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+ * all other bits set to zero
+ */
+
+ p0.h = hi(PLL_LOCKCNT);
+ p0.l = lo(PLL_LOCKCNT);
+ r0 = 0x300(Z);
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITSET (R0, 24);
+ [P2] = R0;
+ SSYNC;
+
+ r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
+ r0 = r0 << 9; /* Shift it over, */
+ r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
+ r0 = r1 | r0;
+ r1 = PLL_BYPASS; /* Bypass the PLL? */
+ r1 = r1 << 8; /* Shift it over */
+ r0 = r1 | r0; /* add them all together */
+
+ p0.h = hi(PLL_CTL);
+ p0.l = lo(PLL_CTL); /* Load the address */
+ cli r2; /* Disable interrupts */
+ ssync;
+ w[p0] = r0.l; /* Set the value */
+ idle; /* Wait for the PLL to stablize */
+ sti r2; /* Enable interrupts */
+
+.Lcheck_again:
+ p0.h = hi(PLL_STAT);
+ p0.l = lo(PLL_STAT);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,5);
+ if ! CC jump .Lcheck_again;
+
+ /* Configure SCLK & CCLK Dividers */
+ r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+ p0.h = hi(PLL_DIV);
+ p0.l = lo(PLL_DIV);
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = lo(EBIU_SDRRC);
+ p0.h = hi(EBIU_SDRRC);
+ r0 = mem_SDRRC;
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = (EBIU_SDBCTL & 0xFFFF);
+ p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
+ r0 = mem_SDBCTL;
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITCLR (R0, 24);
+ p0.h = hi(EBIU_SDSTAT);
+ p0.l = lo(EBIU_SDSTAT);
+ r2.l = w[p0];
+ cc = bittst(r2,3);
+ if !cc jump .Lskip;
+ NOP;
+ BITSET (R0, 23);
+.Lskip:
+ [P2] = R0;
+ SSYNC;
+
+ R0.L = lo(mem_SDGCTL);
+ R0.H = hi(mem_SDGCTL);
+ R1 = [p2];
+ R1 = R1 | R0;
+ [P2] = R1;
+ SSYNC;
+
+ p0.h = hi(SIC_IWR);
+ p0.l = lo(SIC_IWR);
+ r0.l = lo(IWR_ENABLE_ALL);
+ r0.h = hi(IWR_ENABLE_ALL);
+ [p0] = r0;
+ SSYNC;
+
+ RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+ /* No more interrupts to be handled*/
+ CLI R6;
+ SSYNC;
+
+#if defined(CONFIG_MTD_M25P80)
+/*
+ * The following code fix the SPI flash reboot issue,
+ * /CS signal of the chip which is using PF10 return to GPIO mode
+ */
+ p0.h = hi(PORTF_FER);
+ p0.l = lo(PORTF_FER);
+ r0.l = 0x0000;
+ w[p0] = r0.l;
+ SSYNC;
+
+/* /CS return to high */
+ p0.h = hi(PORTFIO);
+ p0.l = lo(PORTFIO);
+ r0.l = 0xFFFF;
+ w[p0] = r0.l;
+ SSYNC;
+
+/* Delay some time, This is necessary */
+ r1.h = 0;
+ r1.l = 0x400;
+ p1 = r1;
+ lsetup (_delay_lab1,_delay_lab1_end ) lc1 = p1;
+_delay_lab1:
+ r0.h = 0;
+ r0.l = 0x8000;
+ p0 = r0;
+ lsetup (_delay_lab0,_delay_lab0_end ) lc0 = p0;
+_delay_lab0:
+ nop;
+_delay_lab0_end:
+ nop;
+_delay_lab1_end:
+ nop;
+#endif
+
+ /* Clear the bits 13-15 in SWRST if they werent cleared */
+ p0.h = hi(SWRST);
+ p0.l = lo(SWRST);
+ csync;
+ r0.l = w[p0];
+
+ /* Clear the IMASK register */
+ p0.h = hi(IMASK);
+ p0.l = lo(IMASK);
+ r0 = 0x0;
+ [p0] = r0;
+
+ /* Clear the ILAT register */
+ p0.h = hi(ILAT);
+ p0.l = lo(ILAT);
+ r0 = [p0];
+ [p0] = r0;
+ SSYNC;
+
+ /* Disable the WDOG TIMER */
+ p0.h = hi(WDOG_CTL);
+ p0.l = lo(WDOG_CTL);
+ r0.l = 0xAD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Clear the sticky bit incase it is already set */
+ p0.h = hi(WDOG_CTL);
+ p0.l = lo(WDOG_CTL);
+ r0.l = 0x8AD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Program the count value */
+ R0.l = 0x100;
+ R0.h = 0x0;
+ P0.h = hi(WDOG_CNT);
+ P0.l = lo(WDOG_CNT);
+ [P0] = R0;
+ SSYNC;
+
+ /* Program WDOG_STAT if necessary */
+ P0.h = hi(WDOG_CTL);
+ P0.l = lo(WDOG_CTL);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,1);
+ if !CC JUMP .LWRITESTAT;
+ CC = BITTST(R0,2);
+ if !CC JUMP .LWRITESTAT;
+ JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+ /* When watch dog timer is enabled,
+ * a write to STAT will load the contents of CNT to STAT
+ */
+ R0 = 0x0000(z);
+ P0.h = hi(WDOG_STAT);
+ P0.l = lo(WDOG_STAT)
+ [P0] = R0;
+ SSYNC;
+
+.LSKIP_WRITE:
+ /* Enable the reset event */
+ P0.h = hi(WDOG_CTL);
+ P0.l = lo(WDOG_CTL);
+ R0 = W[P0](Z);
+ BITCLR(R0,1);
+ BITCLR(R0,2);
+ W[P0] = R0.L;
+ SSYNC;
+ NOP;
+
+ /* Enable the wdog counter */
+ R0 = W[P0](Z);
+ BITCLR(R0,4);
+ W[P0] = R0.L;
+ SSYNC;
+
+ IDLE;
+
+ RTS;
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long 0
+__ramstart:
+.long 0
+__ramend:
+.long 0
diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c
new file mode 100644
index 00000000000..fd6308eccbe
--- /dev/null
+++ b/arch/blackfin/mach-bf537/ints-priority.c
@@ -0,0 +1,74 @@
+/*
+ * File: arch/blackfin/mach-bf537/ints-priority.c
+ * Based on: arch/blackfin/mach-bf533/ints-priority.c
+ * Author: Michael Hennerich
+ *
+ * Created:
+ * Description: Set up the interupt priorities
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+void program_IAR(void)
+{
+ /* Program the IAR0 Register with the configured priority */
+ bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+ ((CONFIG_IRQ_DMA_ERROR - 7) << IRQ_DMA_ERROR_POS) |
+ ((CONFIG_IRQ_ERROR - 7) << IRQ_ERROR_POS) |
+ ((CONFIG_IRQ_RTC - 7) << IRQ_RTC_POS) |
+ ((CONFIG_IRQ_PPI - 7) << IRQ_PPI_POS) |
+ ((CONFIG_IRQ_SPORT0_RX - 7) << IRQ_SPORT0_RX_POS) |
+ ((CONFIG_IRQ_SPORT0_TX - 7) << IRQ_SPORT0_TX_POS) |
+ ((CONFIG_IRQ_SPORT1_RX - 7) << IRQ_SPORT1_RX_POS));
+
+ bfin_write_SIC_IAR1(((CONFIG_IRQ_SPORT1_TX - 7) << IRQ_SPORT1_TX_POS) |
+ ((CONFIG_IRQ_TWI - 7) << IRQ_TWI_POS) |
+ ((CONFIG_IRQ_SPI - 7) << IRQ_SPI_POS) |
+ ((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) |
+ ((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS) |
+ ((CONFIG_IRQ_UART1_RX - 7) << IRQ_UART1_RX_POS) |
+ ((CONFIG_IRQ_UART1_TX - 7) << IRQ_UART1_TX_POS) |
+ ((CONFIG_IRQ_CAN_RX - 7) << IRQ_CAN_RX_POS));
+
+ bfin_write_SIC_IAR2(((CONFIG_IRQ_CAN_TX - 7) << IRQ_CAN_TX_POS) |
+ ((CONFIG_IRQ_MAC_RX - 7) << IRQ_MAC_RX_POS) |
+ ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) |
+ ((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) |
+ ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) |
+ ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) |
+ ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) |
+ ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS));
+
+ bfin_write_SIC_IAR3(((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) |
+ ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) |
+ ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS) |
+ ((CONFIG_IRQ_PROG_INTA - 7) << IRQ_PROG_INTA_POS) |
+ ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) |
+ ((CONFIG_IRQ_MEM_DMA0 - 7) << IRQ_MEM_DMA0_POS) |
+ ((CONFIG_IRQ_MEM_DMA1 - 7) << IRQ_MEM_DMA1_POS) |
+ ((CONFIG_IRQ_WATCH - 7) << IRQ_WATCH_POS));
+
+ SSYNC();
+}
diff --git a/arch/blackfin/mach-bf561/Kconfig b/arch/blackfin/mach-bf561/Kconfig
new file mode 100644
index 00000000000..0a17c4cf005
--- /dev/null
+++ b/arch/blackfin/mach-bf561/Kconfig
@@ -0,0 +1,222 @@
+if BF561
+
+menu "BF561 Specific Configuration"
+
+comment "Core B Support"
+
+menu "Core B Support"
+
+config BF561_COREB
+ bool "Enable Core B support"
+ default y
+
+config BF561_COREB_RESET
+ bool "Enable Core B reset support"
+ default n
+ help
+ This requires code in the application that is loaded
+ into Core B. In order to reset, the application needs
+ to install an interrupt handler for Supplemental
+ Interrupt 0, that sets RETI to 0xff600000 and writes
+ bit 11 of SICB_SYSCR when bit 5 of SICA_SYSCR is 0.
+ This causes Core B to stall when Supplemental Interrupt
+ 0 is set, and will reset PC to 0xff600000 when
+ COREB_SRAM_INIT is cleared.
+
+endmenu
+
+comment "Interrupt Priority Assignment"
+
+menu "Priority"
+
+config IRQ_PLL_WAKEUP
+ int "PLL Wakeup Interrupt"
+ default 7
+config IRQ_DMA1_ERROR
+ int "DMA1 Error (generic)"
+ default 7
+config IRQ_DMA2_ERROR
+ int "DMA2 Error (generic)"
+ default 7
+config IRQ_IMDMA_ERROR
+ int "IMDMA Error (generic)"
+ default 7
+config IRQ_PPI0_ERROR
+ int "PPI0 Error Interrupt"
+ default 7
+config IRQ_PPI1_ERROR
+ int "PPI1 Error Interrupt"
+ default 7
+config IRQ_SPORT0_ERROR
+ int "SPORT0 Error Interrupt"
+ default 7
+config IRQ_SPORT1_ERROR
+ int "SPORT1 Error Interrupt"
+ default 7
+config IRQ_SPI_ERROR
+ int "SPI Error Interrupt"
+ default 7
+config IRQ_UART_ERROR
+ int "UART Error Interrupt"
+ default 7
+config IRQ_RESERVED_ERROR
+ int "Reserved Interrupt"
+ default 7
+config IRQ_DMA1_0
+ int "DMA1 0 Interrupt(PPI1)"
+ default 8
+config IRQ_DMA1_1
+ int "DMA1 1 Interrupt(PPI2)"
+ default 8
+config IRQ_DMA1_2
+ int "DMA1 2 Interrupt"
+ default 8
+config IRQ_DMA1_3
+ int "DMA1 3 Interrupt"
+ default 8
+config IRQ_DMA1_4
+ int "DMA1 4 Interrupt"
+ default 8
+config IRQ_DMA1_5
+ int "DMA1 5 Interrupt"
+ default 8
+config IRQ_DMA1_6
+ int "DMA1 6 Interrupt"
+ default 8
+config IRQ_DMA1_7
+ int "DMA1 7 Interrupt"
+ default 8
+config IRQ_DMA1_8
+ int "DMA1 8 Interrupt"
+ default 8
+config IRQ_DMA1_9
+ int "DMA1 9 Interrupt"
+ default 8
+config IRQ_DMA1_10
+ int "DMA1 10 Interrupt"
+ default 8
+config IRQ_DMA1_11
+ int "DMA1 11 Interrupt"
+ default 8
+config IRQ_DMA2_0
+ int "DMA2 0 (SPORT0 RX)"
+ default 9
+config IRQ_DMA2_1
+ int "DMA2 1 (SPORT0 TX)"
+ default 9
+config IRQ_DMA2_2
+ int "DMA2 2 (SPORT1 RX)"
+ default 9
+config IRQ_DMA2_3
+ int "DMA2 3 (SPORT2 TX)"
+ default 9
+config IRQ_DMA2_4
+ int "DMA2 4 (SPI)"
+ default 9
+config IRQ_DMA2_5
+ int "DMA2 5 (UART RX)"
+ default 9
+config IRQ_DMA2_6
+ int "DMA2 6 (UART TX)"
+ default 9
+config IRQ_DMA2_7
+ int "DMA2 7 Interrupt"
+ default 9
+config IRQ_DMA2_8
+ int "DMA2 8 Interrupt"
+ default 9
+config IRQ_DMA2_9
+ int "DMA2 9 Interrupt"
+ default 9
+config IRQ_DMA2_10
+ int "DMA2 10 Interrupt"
+ default 9
+config IRQ_DMA2_11
+ int "DMA2 11 Interrupt"
+ default 9
+config IRQ_TIMER0
+ int "TIMER 0 Interrupt"
+ default 10
+config IRQ_TIMER1
+ int "TIMER 1 Interrupt"
+ default 10
+config IRQ_TIMER2
+ int "TIMER 2 Interrupt"
+ default 10
+config IRQ_TIMER3
+ int "TIMER 3 Interrupt"
+ default 10
+config IRQ_TIMER4
+ int "TIMER 4 Interrupt"
+ default 10
+config IRQ_TIMER5
+ int "TIMER 5 Interrupt"
+ default 10
+config IRQ_TIMER6
+ int "TIMER 6 Interrupt"
+ default 10
+config IRQ_TIMER7
+ int "TIMER 7 Interrupt"
+ default 10
+config IRQ_TIMER8
+ int "TIMER 8 Interrupt"
+ default 10
+config IRQ_TIMER9
+ int "TIMER 9 Interrupt"
+ default 10
+config IRQ_TIMER10
+ int "TIMER 10 Interrupt"
+ default 10
+config IRQ_TIMER11
+ int "TIMER 11 Interrupt"
+ default 10
+config IRQ_PROG0_INTA
+ int "Programmable Flags0 A (8)"
+ default 11
+config IRQ_PROG0_INTB
+ int "Programmable Flags0 B (8)"
+ default 11
+config IRQ_PROG1_INTA
+ int "Programmable Flags1 A (8)"
+ default 11
+config IRQ_PROG1_INTB
+ int "Programmable Flags1 B (8)"
+ default 11
+config IRQ_PROG2_INTA
+ int "Programmable Flags2 A (8)"
+ default 11
+config IRQ_PROG2_INTB
+ int "Programmable Flags2 B (8)"
+ default 11
+config IRQ_DMA1_WRRD0
+ int "MDMA1 0 write/read INT"
+ default 8
+config IRQ_DMA1_WRRD1
+ int "MDMA1 1 write/read INT"
+ default 8
+config IRQ_DMA2_WRRD0
+ int "MDMA2 0 write/read INT"
+ default 9
+config IRQ_DMA2_WRRD1
+ int "MDMA2 1 write/read INT"
+ default 9
+config IRQ_IMDMA_WRRD0
+ int "IMDMA 0 write/read INT"
+ default 12
+config IRQ_IMDMA_WRRD1
+ int "IMDMA 1 write/read INT"
+ default 12
+config IRQ_WDTIMER
+ int "Watch Dog Timer"
+ default 13
+
+ help
+ Enter the priority numbers between 7-13 ONLY. Others are Reserved.
+ This applies to all the above. It is not recommended to assign the
+ highest priority number 7 to UART or any other device.
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf561/Makefile b/arch/blackfin/mach-bf561/Makefile
new file mode 100644
index 00000000000..57f475a5516
--- /dev/null
+++ b/arch/blackfin/mach-bf561/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf561/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o
+
+obj-$(CONFIG_BF561_COREB) += coreb.o
diff --git a/arch/blackfin/mach-bf561/boards/Makefile b/arch/blackfin/mach-bf561/boards/Makefile
new file mode 100644
index 00000000000..886edc739ab
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/Makefile
@@ -0,0 +1,7 @@
+#
+# arch/blackfin/mach-bf561/boards/Makefile
+#
+
+obj-$(CONFIG_GENERIC_BOARD) += generic_board.o
+obj-$(CONFIG_BFIN561_EZKIT) += ezkit.o
+obj-$(CONFIG_BFIN561_BLUETECHNIX_CM) += cm_bf561.o
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
new file mode 100644
index 00000000000..6824e956d15
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -0,0 +1,289 @@
+/*
+ * File: arch/blackfin/mach-bf533/boards/cm_bf561.c
+ * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au> Copright 2005
+ *
+ * Created: 2006
+ * Description: Board description file
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/usb_isp1362.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "Bluetechnix CM BF561";
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+/* all SPI perpherals info goes here */
+
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+static struct mtd_partition bfin_spi_flash_partitions[] = {
+ {
+ .name = "bootloader",
+ .size = 0x00020000,
+ .offset = 0,
+ .mask_flags = MTD_CAP_ROM
+ },{
+ .name = "kernel",
+ .size = 0xe0000,
+ .offset = 0x20000
+ },{
+ .name = "file system",
+ .size = 0x700000,
+ .offset = 0x00100000,
+ }
+};
+
+static struct flash_platform_data bfin_spi_flash_data = {
+ .name = "m25p80",
+ .parts = bfin_spi_flash_partitions,
+ .nr_parts = ARRAY_SIZE(bfin_spi_flash_partitions),
+ .type = "m25p64",
+};
+
+/* SPI flash chip (m25p64) */
+static struct bfin5xx_spi_chip spi_flash_chip_info = {
+ .enable_dma = 0, /* use dma transfer with this chip*/
+ .bits_per_word = 8,
+};
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+/* SPI ADC chip */
+static struct bfin5xx_spi_chip spi_adc_chip_info = {
+ .enable_dma = 1, /* use dma transfer with this chip*/
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+static struct bfin5xx_spi_chip ad9960_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+static struct bfin5xx_spi_chip spi_mmc_chip_info = {
+ .enable_dma = 1,
+ .bits_per_word = 8,
+};
+#endif
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
+ {
+ /* the modalias must be the same as spi device driver name */
+ .modalias = "m25p80", /* Name of spi_driver for this device */
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+ .platform_data = &bfin_spi_flash_data,
+ .controller_data = &spi_flash_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+
+#if defined(CONFIG_SPI_ADC_BF533) || defined(CONFIG_SPI_ADC_BF533_MODULE)
+ {
+ .modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
+ .max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1, /* Framework bus number */
+ .chip_select = 1, /* Framework chip select. */
+ .platform_data = NULL, /* No spi_driver specific config */
+ .controller_data = &spi_adc_chip_info,
+ },
+#endif
+
+#if defined(CONFIG_SND_BLACKFIN_AD1836) || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+#if defined(CONFIG_AD9960) || defined(CONFIG_AD9960_MODULE)
+ {
+ .modalias = "ad9960-spi",
+ .max_speed_hz = 10000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 1,
+ .controller_data = &ad9960_spi_chip_info,
+ },
+#endif
+#if defined(CONFIG_SPI_MMC) || defined(CONFIG_SPI_MMC_MODULE)
+ {
+ .modalias = "spi_mmc",
+ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SPI_MMC_CS_CHAN,
+ .platform_data = NULL,
+ .controller_data = &spi_mmc_chip_info,
+ .mode = SPI_MODE_3,
+ },
+#endif
+};
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+#endif /* spi master and devices */
+
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x28000300,
+ .end = 0x28000300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF0,
+ .end = IRQ_PF0,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+static struct resource isp1362_hcd_resources[] = {
+ {
+ .start = 0x24008000,
+ .end = 0x24008000,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = 0x24008004,
+ .end = 0x24008004,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PF47,
+ .end = IRQ_PF47,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct isp1362_platform_data isp1362_priv = {
+ .sel15Kres = 1,
+ .clknotstop = 0,
+ .oc_enable = 0,
+ .int_act_high = 0,
+ .int_edge_triggered = 0,
+ .remote_wakeup_connected = 0,
+ .no_power_switching = 1,
+ .power_switching_mode = 0,
+};
+
+static struct platform_device isp1362_hcd_device = {
+ .name = "isp1362-hcd",
+ .id = 0,
+ .dev = {
+ .platform_data = &isp1362_priv,
+ },
+ .num_resources = ARRAY_SIZE(isp1362_hcd_resources),
+ .resource = isp1362_hcd_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *cm_bf561_devices[] __initdata = {
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+
+#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
+ &isp1362_hcd_device,
+#endif
+
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+
+};
+
+static int __init cm_bf561_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(cm_bf561_devices, ARRAY_SIZE(cm_bf561_devices));
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+#endif
+ return 0;
+}
+
+arch_initcall(cm_bf561_init);
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
new file mode 100644
index 00000000000..14eb4f9a68e
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -0,0 +1,147 @@
+/*
+ * File: arch/blackfin/mach-bf561/ezkit.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <asm/irq.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADDS-BF561-EZKIT";
+
+/*
+ * USB-LAN EzExtender board
+ * Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .name = "smc91x-regs",
+ .start = 0x2C010300,
+ .end = 0x2C010300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+
+ .start = IRQ_PF9,
+ .end = IRQ_PF9,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+#ifdef CONFIG_SPI_BFIN
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
+ .enable_dma = 0,
+ .bits_per_word = 16,
+};
+#endif
+#endif
+
+/* SPI controller data */
+static struct bfin5xx_spi_master spi_bfin_master_info = {
+ .num_chipselect = 8,
+ .enable_dma = 1, /* master has the ability to do dma transfer */
+};
+
+static struct platform_device spi_bfin_master_device = {
+ .name = "bfin-spi-master",
+ .id = 1, /* Bus number */
+ .dev = {
+ .platform_data = &spi_bfin_master_info, /* Passed to driver */
+ },
+};
+
+static struct spi_board_info bfin_spi_board_info[] __initdata = {
+#if defined(CONFIG_SND_BLACKFIN_AD1836) \
+ || defined(CONFIG_SND_BLACKFIN_AD1836_MODULE)
+ {
+ .modalias = "ad1836-spi",
+ .max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = CONFIG_SND_BLACKFIN_SPI_PFBIT,
+ .controller_data = &ad1836_spi_chip_info,
+ },
+#endif
+};
+
+static struct platform_device *ezkit_devices[] __initdata = {
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+#if defined(CONFIG_SPI_BFIN) || defined(CONFIG_SPI_BFIN_MODULE)
+ &spi_bfin_master_device,
+#endif
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+};
+
+static int __init ezkit_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ ret = platform_add_devices(ezkit_devices,
+ ARRAY_SIZE(ezkit_devices));
+ if (ret < 0)
+ return ret;
+ return spi_register_board_info(bfin_spi_board_info,
+ ARRAY_SIZE(bfin_spi_board_info));
+}
+
+arch_initcall(ezkit_init);
diff --git a/arch/blackfin/mach-bf561/boards/generic_board.c b/arch/blackfin/mach-bf561/boards/generic_board.c
new file mode 100644
index 00000000000..585ecdd2f6a
--- /dev/null
+++ b/arch/blackfin/mach-bf561/boards/generic_board.c
@@ -0,0 +1,82 @@
+/*
+ * File: arch/blackfin/mach-bf561/generic_board.c
+ * Based on: arch/blackfin/mach-bf533/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <asm/irq.h>
+
+char *bfin_board_name = "UNKNOWN BOARD";
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+static struct resource smc91x_resources[] = {
+ {
+ .start = 0x2C010300,
+ .end = 0x2C010300 + 16,
+ .flags = IORESOURCE_MEM,
+ },{
+ .start = IRQ_PROG_INTB,
+ .end = IRQ_PROG_INTB,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },{
+ /*
+ * denotes the flag pin and is used directly if
+ * CONFIG_IRQCHIP_DEMUX_GPIO is defined.
+ */
+ .start = IRQ_PF9,
+ .end = IRQ_PF9,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+#endif
+
+static struct platform_device *generic_board_devices[] __initdata = {
+#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
+ &smc91x_device,
+#endif
+};
+
+static int __init generic_board_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ return platform_add_devices(generic_board_devices,
+ ARRAY_SIZE(generic_board_devices));
+}
+
+arch_initcall(generic_board_init);
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
new file mode 100644
index 00000000000..b28582fe083
--- /dev/null
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -0,0 +1,402 @@
+/*
+ * File: arch/blackfin/mach-bf561/coreb.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: Handle CoreB on a BF561
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#define MODULE_VER "v0.1"
+
+static spinlock_t coreb_lock;
+static wait_queue_head_t coreb_dma_wait;
+
+#define COREB_IS_OPEN 0x00000001
+#define COREB_IS_RUNNING 0x00000010
+
+#define CMD_COREB_INDEX 1
+#define CMD_COREB_START 2
+#define CMD_COREB_STOP 3
+#define CMD_COREB_RESET 4
+
+#define COREB_MINOR 229
+
+static unsigned long coreb_status = 0;
+static unsigned long coreb_base = 0xff600000;
+static unsigned long coreb_size = 0x4000;
+int coreb_dma_done;
+
+static loff_t coreb_lseek(struct file *file, loff_t offset, int origin);
+static ssize_t coreb_read(struct file *file, char *buf, size_t count,
+ loff_t * ppos);
+static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
+ loff_t * ppos);
+static int coreb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg);
+static int coreb_open(struct inode *inode, struct file *file);
+static int coreb_release(struct inode *inode, struct file *file);
+
+static irqreturn_t coreb_dma_interrupt(int irq, void *dev_id)
+{
+ clear_dma_irqstat(CH_MEM_STREAM2_DEST);
+ coreb_dma_done = 1;
+ wake_up_interruptible(&coreb_dma_wait);
+ return IRQ_HANDLED;
+}
+
+static ssize_t coreb_write(struct file *file, const char *buf, size_t count,
+ loff_t * ppos)
+{
+ unsigned long p = *ppos;
+ ssize_t wrote = 0;
+
+ if (p + count > coreb_size)
+ return -EFAULT;
+
+ while (count > 0) {
+ int len = count;
+
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+
+ coreb_dma_done = 0;
+
+ /* Source Channel */
+ set_dma_start_addr(CH_MEM_STREAM2_SRC, (unsigned long)buf);
+ set_dma_x_count(CH_MEM_STREAM2_SRC, len);
+ set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
+ set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
+ /* Destination Channel */
+ set_dma_start_addr(CH_MEM_STREAM2_DEST, coreb_base + p);
+ set_dma_x_count(CH_MEM_STREAM2_DEST, len);
+ set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
+ set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
+
+ enable_dma(CH_MEM_STREAM2_SRC);
+ enable_dma(CH_MEM_STREAM2_DEST);
+
+ wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
+
+ disable_dma(CH_MEM_STREAM2_SRC);
+ disable_dma(CH_MEM_STREAM2_DEST);
+
+ count -= len;
+ wrote += len;
+ buf += len;
+ p += len;
+ }
+ *ppos = p;
+ return wrote;
+}
+
+static ssize_t coreb_read(struct file *file, char *buf, size_t count,
+ loff_t * ppos)
+{
+ unsigned long p = *ppos;
+ ssize_t read = 0;
+
+ if ((p + count) > coreb_size)
+ return -EFAULT;
+
+ while (count > 0) {
+ int len = count;
+
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+
+ coreb_dma_done = 0;
+
+ /* Source Channel */
+ set_dma_start_addr(CH_MEM_STREAM2_SRC, coreb_base + p);
+ set_dma_x_count(CH_MEM_STREAM2_SRC, len);
+ set_dma_x_modify(CH_MEM_STREAM2_SRC, sizeof(char));
+ set_dma_config(CH_MEM_STREAM2_SRC, RESTART);
+ /* Destination Channel */
+ set_dma_start_addr(CH_MEM_STREAM2_DEST, (unsigned long)buf);
+ set_dma_x_count(CH_MEM_STREAM2_DEST, len);
+ set_dma_x_modify(CH_MEM_STREAM2_DEST, sizeof(char));
+ set_dma_config(CH_MEM_STREAM2_DEST, WNR | RESTART | DI_EN);
+
+ enable_dma(CH_MEM_STREAM2_SRC);
+ enable_dma(CH_MEM_STREAM2_DEST);
+
+ wait_event_interruptible(coreb_dma_wait, coreb_dma_done);
+
+ disable_dma(CH_MEM_STREAM2_SRC);
+ disable_dma(CH_MEM_STREAM2_DEST);
+
+ count -= len;
+ read += len;
+ buf += len;
+ p += len;
+ }
+
+ return read;
+}
+
+static loff_t coreb_lseek(struct file *file, loff_t offset, int origin)
+{
+ loff_t ret;
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+
+ switch (origin) {
+ case 0 /* SEEK_SET */ :
+ if (offset < coreb_size) {
+ file->f_pos = offset;
+ ret = file->f_pos;
+ } else
+ ret = -EINVAL;
+ break;
+ case 1 /* SEEK_CUR */ :
+ if ((offset + file->f_pos) < coreb_size) {
+ file->f_pos += offset;
+ ret = file->f_pos;
+ } else
+ ret = -EINVAL;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ return ret;
+}
+
+static int coreb_open(struct inode *inode, struct file *file)
+{
+ spin_lock_irq(&coreb_lock);
+
+ if (coreb_status & COREB_IS_OPEN)
+ goto out_busy;
+
+ coreb_status |= COREB_IS_OPEN;
+
+ spin_unlock_irq(&coreb_lock);
+ return 0;
+
+ out_busy:
+ spin_unlock_irq(&coreb_lock);
+ return -EBUSY;
+}
+
+static int coreb_release(struct inode *inode, struct file *file)
+{
+ spin_lock_irq(&coreb_lock);
+ coreb_status &= ~COREB_IS_OPEN;
+ spin_unlock_irq(&coreb_lock);
+ return 0;
+}
+
+static int coreb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int retval = 0;
+ int coreb_index = 0;
+
+ switch (cmd) {
+ case CMD_COREB_INDEX:
+ if (copy_from_user(&coreb_index, (int *)arg, sizeof(int))) {
+ retval = -EFAULT;
+ break;
+ }
+
+ spin_lock_irq(&coreb_lock);
+ switch (coreb_index) {
+ case 0:
+ coreb_base = 0xff600000;
+ coreb_size = 0x4000;
+ break;
+ case 1:
+ coreb_base = 0xff610000;
+ coreb_size = 0x4000;
+ break;
+ case 2:
+ coreb_base = 0xff500000;
+ coreb_size = 0x8000;
+ break;
+ case 3:
+ coreb_base = 0xff400000;
+ coreb_size = 0x8000;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ spin_unlock_irq(&coreb_lock);
+
+ mutex_lock(&file->f_dentry->d_inode->i_mutex);
+ file->f_pos = 0;
+ mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+ break;
+ case CMD_COREB_START:
+ spin_lock_irq(&coreb_lock);
+ if (coreb_status & COREB_IS_RUNNING) {
+ retval = -EBUSY;
+ break;
+ }
+ printk(KERN_INFO "Starting Core B\n");
+ coreb_status |= COREB_IS_RUNNING;
+ bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() & ~0x0020);
+ SSYNC();
+ spin_lock_irq(&coreb_lock);
+ break;
+#if defined(CONFIG_BF561_COREB_RESET)
+ case CMD_COREB_STOP:
+ spin_lock_irq(&coreb_lock);
+ printk(KERN_INFO "Stopping Core B\n");
+ bfin_write_SICA_SYSCR(bfin_read_SICA_SYSCR() | 0x0020);
+ bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+ coreb_status &= ~COREB_IS_RUNNING;
+ spin_lock_irq(&coreb_lock);
+ break;
+ case CMD_COREB_RESET:
+ printk(KERN_INFO "Resetting Core B\n");
+ bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | 0x0080);
+ break;
+#endif
+ }
+
+ return retval;
+}
+
+static struct file_operations coreb_fops = {
+ .owner = THIS_MODULE,
+ .llseek = coreb_lseek,
+ .read = coreb_read,
+ .write = coreb_write,
+ .ioctl = coreb_ioctl,
+ .open = coreb_open,
+ .release = coreb_release
+};
+
+static struct miscdevice coreb_dev = {
+ COREB_MINOR,
+ "coreb",
+ &coreb_fops
+};
+
+static ssize_t coreb_show_status(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf,
+ "Base Address:\t0x%08lx\n"
+ "Core B is %s\n"
+ "SICA_SYSCR:\t%04x\n"
+ "SICB_SYSCR:\t%04x\n"
+ "\n"
+ "IRQ Status:\tCore A\t\tCore B\n"
+ "ISR0:\t\t%08x\t\t%08x\n"
+ "ISR1:\t\t%08x\t\t%08x\n"
+ "IMASK0:\t\t%08x\t\t%08x\n"
+ "IMASK1:\t\t%08x\t\t%08x\n",
+ coreb_base,
+ coreb_status & COREB_IS_RUNNING ? "running" : "stalled",
+ bfin_read_SICA_SYSCR(), bfin_read_SICB_SYSCR(),
+ bfin_read_SICA_ISR0(), bfin_read_SICB_ISR0(),
+ bfin_read_SICA_ISR1(), bfin_read_SICB_ISR0(),
+ bfin_read_SICA_IMASK0(), bfin_read_SICB_IMASK0(),
+ bfin_read_SICA_IMASK1(), bfin_read_SICB_IMASK1());
+}
+
+static DEVICE_ATTR(coreb_status, S_IRUGO, coreb_show_status, NULL);
+
+int __init bf561_coreb_init(void)
+{
+ init_waitqueue_head(&coreb_dma_wait);
+
+ spin_lock_init(&coreb_lock);
+ /* Request the core memory regions for Core B */
+ if (request_mem_region(0xff600000, 0x4000,
+ "Core B - Instruction SRAM") == NULL)
+ goto exit;
+
+ if (request_mem_region(0xFF610000, 0x4000,
+ "Core B - Instruction SRAM") == NULL)
+ goto release_instruction_a_sram;
+
+ if (request_mem_region(0xFF500000, 0x8000,
+ "Core B - Data Bank B SRAM") == NULL)
+ goto release_instruction_b_sram;
+
+ if (request_mem_region(0xff400000, 0x8000,
+ "Core B - Data Bank A SRAM") == NULL)
+ goto release_data_b_sram;
+
+ if (request_dma(CH_MEM_STREAM2_DEST, "Core B - DMA Destination") < 0)
+ goto release_data_a_sram;
+
+ if (request_dma(CH_MEM_STREAM2_SRC, "Core B - DMA Source") < 0)
+ goto release_dma_dest;
+
+ set_dma_callback(CH_MEM_STREAM2_DEST, coreb_dma_interrupt, NULL);
+
+ misc_register(&coreb_dev);
+
+ if (device_create_file(coreb_dev.this_device, &dev_attr_coreb_status))
+ goto release_dma_src;
+
+ printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
+ return 0;
+
+ release_dma_src:
+ free_dma(CH_MEM_STREAM2_SRC);
+ release_dma_dest:
+ free_dma(CH_MEM_STREAM2_DEST);
+ release_data_a_sram:
+ release_mem_region(0xff400000, 0x8000);
+ release_data_b_sram:
+ release_mem_region(0xff500000, 0x8000);
+ release_instruction_b_sram:
+ release_mem_region(0xff610000, 0x4000);
+ release_instruction_a_sram:
+ release_mem_region(0xff600000, 0x4000);
+ exit:
+ return -ENOMEM;
+}
+
+void __exit bf561_coreb_exit(void)
+{
+ device_remove_file(coreb_dev.this_device, &dev_attr_coreb_status);
+ misc_deregister(&coreb_dev);
+
+ release_mem_region(0xff610000, 0x4000);
+ release_mem_region(0xff600000, 0x4000);
+ release_mem_region(0xff500000, 0x8000);
+ release_mem_region(0xff400000, 0x8000);
+
+ free_dma(CH_MEM_STREAM2_DEST);
+ free_dma(CH_MEM_STREAM2_SRC);
+}
+
+module_init(bf561_coreb_init);
+module_exit(bf561_coreb_exit);
+
+MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
+MODULE_DESCRIPTION("BF561 Core B Support");
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
new file mode 100644
index 00000000000..7bca478526b
--- /dev/null
+++ b/arch/blackfin/mach-bf561/head.S
@@ -0,0 +1,512 @@
+/*
+ * File: arch/blackfin/mach-bf561/head.S
+ * Based on: arch/blackfin/mach-bf533/head.S
+ * Author:
+ *
+ * Created:
+ * Description: BF561 startup file
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK 0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+ /* R0: argument of command line string, passed from uboot, save it */
+ R7 = R0;
+ /* Set the SYSCFG register */
+ R0 = 0x36;
+ SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+ R0 = 0;
+
+ /*Clear Out All the data and pointer Registers*/
+ R1 = R0;
+ R2 = R0;
+ R3 = R0;
+ R4 = R0;
+ R5 = R0;
+ R6 = R0;
+
+ P0 = R0;
+ P1 = R0;
+ P2 = R0;
+ P3 = R0;
+ P4 = R0;
+ P5 = R0;
+
+ LC0 = r0;
+ LC1 = r0;
+ L0 = r0;
+ L1 = r0;
+ L2 = r0;
+ L3 = r0;
+
+ /* Clear Out All the DAG Registers*/
+ B0 = r0;
+ B1 = r0;
+ B2 = r0;
+ B3 = r0;
+
+ I0 = r0;
+ I1 = r0;
+ I2 = r0;
+ I3 = r0;
+
+ M0 = r0;
+ M1 = r0;
+ M2 = r0;
+ M3 = r0;
+
+ /* Turn off the icache */
+ p0.l = (IMEM_CONTROL & 0xFFFF);
+ p0.h = (IMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENICPLB;
+ R0 = R0 & R1;
+
+ /* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+ CLI R2;
+ SSYNC;
+#endif
+ [p0] = R0;
+ SSYNC;
+#ifdef ANOMALY_05000125
+ STI R2;
+#endif
+
+ /* Turn off the dcache */
+ p0.l = (DMEM_CONTROL & 0xFFFF);
+ p0.h = (DMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENDCPLB;
+ R0 = R0 & R1;
+
+ /* Anomaly 05000125 */
+#ifdef ANOMALY_05000125
+ CLI R2;
+ SSYNC;
+#endif
+ [p0] = R0;
+ SSYNC;
+#ifdef ANOMALY_05000125
+ STI R2;
+#endif
+
+ /* Initialise UART*/
+ p0.h = hi(UART_LCR);
+ p0.l = lo(UART_LCR);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable DLL writes */
+ ssync;
+
+ p0.h = hi(UART_DLL);
+ p0.l = lo(UART_DLL);
+ r0 = 0x0(Z);
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_DLH);
+ p0.l = lo(UART_DLH);
+ r0 = 0x00(Z);
+ w[p0] = r0.L;
+ ssync;
+
+ p0.h = hi(UART_GCTL);
+ p0.l = lo(UART_GCTL);
+ r0 = 0x0(Z);
+ w[p0] = r0.L; /* To enable UART clock */
+ ssync;
+
+ /* Initialize stack pointer */
+ sp.l = lo(INITIAL_STACK);
+ sp.h = hi(INITIAL_STACK);
+ fp = sp;
+ usp = sp;
+
+ /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+ call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+ call _start_dma_code;
+#endif
+
+ /* Code for initializing Async memory banks */
+
+ p2.h = hi(EBIU_AMBCTL1);
+ p2.l = lo(EBIU_AMBCTL1);
+ r0.h = hi(AMBCTL1VAL);
+ r0.l = lo(AMBCTL1VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMBCTL0);
+ p2.l = lo(EBIU_AMBCTL0);
+ r0.h = hi(AMBCTL0VAL);
+ r0.l = lo(AMBCTL0VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMGCTL);
+ p2.l = lo(EBIU_AMGCTL);
+ r0 = AMGCTLVAL;
+ w[p2] = r0;
+ ssync;
+
+ /* This section keeps the processor in supervisor mode
+ * during kernel boot. Switches to user mode at end of boot.
+ * See page 3-9 of Hardware Reference manual for documentation.
+ */
+
+ /* EVT15 = _real_start */
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _real_start;
+ p1.h = _real_start;
+ [p0] = p1;
+ csync;
+
+ p0.l = lo(IMASK);
+ p0.h = hi(IMASK);
+ p1.l = IMASK_IVG15;
+ p1.h = 0x0;
+ [p0] = p1;
+ csync;
+
+ raise 15;
+ p0.l = .LWAIT_HERE;
+ p0.h = .LWAIT_HERE;
+ reti = p0;
+#if defined(ANOMALY_05000281)
+ nop; nop; nop;
+#endif
+ rti;
+
+.LWAIT_HERE:
+ jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+ [ -- sp ] = reti;
+ p0.l = lo(WDOGA_CTL);
+ p0.h = hi(WDOGA_CTL);
+ r0 = 0xAD6(z);
+ w[p0] = r0; /* watchdog off for now */
+ ssync;
+
+ /* Code update for BSS size == 0
+ * Zero out the bss region.
+ */
+
+ p1.l = ___bss_start;
+ p1.h = ___bss_start;
+ p2.l = ___bss_stop;
+ p2.h = ___bss_stop;
+ r0 = 0;
+ p2 -= p1;
+ lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
+.L_clear_bss:
+ B[p1++] = r0;
+
+ /* In case there is a NULL pointer reference
+ * Zero out region before stext
+ */
+
+ p1.l = 0x0;
+ p1.h = 0x0;
+ r0.l = __stext;
+ r0.h = __stext;
+ r0 = r0 >> 1;
+ p2 = r0;
+ r0 = 0;
+ lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
+.L_clear_zero:
+ W[p1++] = r0;
+
+/* pass the uboot arguments to the global value command line */
+ R0 = R7;
+ call _cmdline_init;
+
+ p1.l = __rambase;
+ p1.h = __rambase;
+ r0.l = __sdata;
+ r0.h = __sdata;
+ [p1] = r0;
+
+ p1.l = __ramstart;
+ p1.h = __ramstart;
+ p3.l = ___bss_stop;
+ p3.h = ___bss_stop;
+
+ r1 = p3;
+ [p1] = r1;
+
+ /*
+ * load the current thread pointer and stack
+ */
+ r1.l = _init_thread_union;
+ r1.h = _init_thread_union;
+
+ r2.l = 0x2000;
+ r2.h = 0x0000;
+ r1 = r1 + r2;
+ sp = r1;
+ usp = sp;
+ fp = sp;
+ call _start_kernel;
+.L_exit:
+ jump.s .L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+ p0.h = hi(SICA_IWR0);
+ p0.l = lo(SICA_IWR0);
+ r0.l = 0x1;
+ [p0] = r0;
+ SSYNC;
+
+ /*
+ * Set PLL_CTL
+ * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+ * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
+ * - [7] = output delay (add 200ps of delay to mem signals)
+ * - [6] = input delay (add 200ps of input delay to mem signals)
+ * - [5] = PDWN : 1=All Clocks off
+ * - [3] = STOPCK : 1=Core Clock off
+ * - [1] = PLL_OFF : 1=Disable Power to PLL
+ * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+ * all other bits set to zero
+ */
+
+ p0.h = hi(PLL_LOCKCNT);
+ p0.l = lo(PLL_LOCKCNT);
+ r0 = 0x300(Z);
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITSET (R0, 24);
+ [P2] = R0;
+ SSYNC;
+
+ r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
+ r0 = r0 << 9; /* Shift it over, */
+ r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
+ r0 = r1 | r0;
+ r1 = PLL_BYPASS; /* Bypass the PLL? */
+ r1 = r1 << 8; /* Shift it over */
+ r0 = r1 | r0; /* add them all together */
+
+ p0.h = hi(PLL_CTL);
+ p0.l = lo(PLL_CTL); /* Load the address */
+ cli r2; /* Disable interrupts */
+ ssync;
+ w[p0] = r0.l; /* Set the value */
+ idle; /* Wait for the PLL to stablize */
+ sti r2; /* Enable interrupts */
+
+.Lcheck_again:
+ p0.h = hi(PLL_STAT);
+ p0.l = lo(PLL_STAT);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,5);
+ if ! CC jump .Lcheck_again;
+
+ /* Configure SCLK & CCLK Dividers */
+ r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+ p0.h = hi(PLL_DIV);
+ p0.l = lo(PLL_DIV);
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = lo(EBIU_SDRRC);
+ p0.h = hi(EBIU_SDRRC);
+ r0 = mem_SDRRC;
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = (EBIU_SDBCTL & 0xFFFF);
+ p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
+ r0 = mem_SDBCTL;
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITCLR (R0, 24);
+ p0.h = hi(EBIU_SDSTAT);
+ p0.l = lo(EBIU_SDSTAT);
+ r2.l = w[p0];
+ cc = bittst(r2,3);
+ if !cc jump .Lskip;
+ NOP;
+ BITSET (R0, 23);
+.Lskip:
+ [P2] = R0;
+ SSYNC;
+
+ R0.L = lo(mem_SDGCTL);
+ R0.H = hi(mem_SDGCTL);
+ R1 = [p2];
+ R1 = R1 | R0;
+ [P2] = R1;
+ SSYNC;
+
+ RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+ /* No more interrupts to be handled*/
+ CLI R6;
+ SSYNC;
+
+#if defined(CONFIG_BFIN_SHARED_FLASH_ENET)
+ p0.h = hi(FIO_INEN);
+ p0.l = lo(FIO_INEN);
+ r0.l = ~(PF1 | PF0);
+ w[p0] = r0.l;
+
+ p0.h = hi(FIO_DIR);
+ p0.l = lo(FIO_DIR);
+ r0.l = (PF1 | PF0);
+ w[p0] = r0.l;
+
+ p0.h = hi(FIO_FLAG_C);
+ p0.l = lo(FIO_FLAG_C);
+ r0.l = (PF1 | PF0);
+ w[p0] = r0.l;
+#endif
+
+ /* Clear the bits 13-15 in SWRST if they werent cleared */
+ p0.h = hi(SICA_SWRST);
+ p0.l = lo(SICA_SWRST);
+ csync;
+ r0.l = w[p0];
+
+ /* Clear the IMASK register */
+ p0.h = hi(IMASK);
+ p0.l = lo(IMASK);
+ r0 = 0x0;
+ [p0] = r0;
+
+ /* Clear the ILAT register */
+ p0.h = hi(ILAT);
+ p0.l = lo(ILAT);
+ r0 = [p0];
+ [p0] = r0;
+ SSYNC;
+
+ /* Disable the WDOG TIMER */
+ p0.h = hi(WDOGA_CTL);
+ p0.l = lo(WDOGA_CTL);
+ r0.l = 0xAD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Clear the sticky bit incase it is already set */
+ p0.h = hi(WDOGA_CTL);
+ p0.l = lo(WDOGA_CTL);
+ r0.l = 0x8AD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Program the count value */
+ R0.l = 0x100;
+ R0.h = 0x0;
+ P0.h = hi(WDOGA_CNT);
+ P0.l = lo(WDOGA_CNT);
+ [P0] = R0;
+ SSYNC;
+
+ /* Program WDOG_STAT if necessary */
+ P0.h = hi(WDOGA_CTL);
+ P0.l = lo(WDOGA_CTL);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,1);
+ if !CC JUMP .LWRITESTAT;
+ CC = BITTST(R0,2);
+ if !CC JUMP .LWRITESTAT;
+ JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+ /* When watch dog timer is enabled,
+ * a write to STAT will load the contents of CNT to STAT
+ */
+ R0 = 0x0000(z);
+ P0.h = hi(WDOGA_STAT);
+ P0.l = lo(WDOGA_STAT)
+ [P0] = R0;
+ SSYNC;
+
+.LSKIP_WRITE:
+ /* Enable the reset event */
+ P0.h = hi(WDOGA_CTL);
+ P0.l = lo(WDOGA_CTL);
+ R0 = W[P0](Z);
+ BITCLR(R0,1);
+ BITCLR(R0,2);
+ W[P0] = R0.L;
+ SSYNC;
+ NOP;
+
+ /* Enable the wdog counter */
+ R0 = W[P0](Z);
+ BITCLR(R0,4);
+ W[P0] = R0.L;
+ SSYNC;
+
+ IDLE;
+
+ RTS;
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long 0
+__ramstart:
+.long 0
+__ramend:
+.long 0
diff --git a/arch/blackfin/mach-bf561/ints-priority.c b/arch/blackfin/mach-bf561/ints-priority.c
new file mode 100644
index 00000000000..89c52ff95b2
--- /dev/null
+++ b/arch/blackfin/mach-bf561/ints-priority.c
@@ -0,0 +1,108 @@
+/*
+ * File: arch/blackfin/mach-bf561/ints-priority.c
+ * Based on: arch/blackfin/mach-bf537/ints-priority.c
+ * Author: Michael Hennerich
+ *
+ * Created:
+ * Description: Set up the interupt priorities
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+void program_IAR(void)
+{
+ /* Program the IAR0 Register with the configured priority */
+ bfin_write_SICA_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+ ((CONFIG_IRQ_DMA1_ERROR - 7) << IRQ_DMA1_ERROR_POS) |
+ ((CONFIG_IRQ_DMA2_ERROR - 7) << IRQ_DMA2_ERROR_POS) |
+ ((CONFIG_IRQ_IMDMA_ERROR - 7) << IRQ_IMDMA_ERROR_POS) |
+ ((CONFIG_IRQ_PPI0_ERROR - 7) << IRQ_PPI0_ERROR_POS) |
+ ((CONFIG_IRQ_PPI1_ERROR - 7) << IRQ_PPI1_ERROR_POS) |
+ ((CONFIG_IRQ_SPORT0_ERROR - 7) << IRQ_SPORT0_ERROR_POS) |
+ ((CONFIG_IRQ_SPORT1_ERROR - 7) << IRQ_SPORT1_ERROR_POS));
+
+ bfin_write_SICA_IAR1(((CONFIG_IRQ_SPI_ERROR - 7) << IRQ_SPI_ERROR_POS) |
+ ((CONFIG_IRQ_UART_ERROR - 7) << IRQ_UART_ERROR_POS) |
+ ((CONFIG_IRQ_RESERVED_ERROR - 7) << IRQ_RESERVED_ERROR_POS) |
+ ((CONFIG_IRQ_DMA1_0 - 7) << IRQ_DMA1_0_POS) |
+ ((CONFIG_IRQ_DMA1_1 - 7) << IRQ_DMA1_1_POS) |
+ ((CONFIG_IRQ_DMA1_2 - 7) << IRQ_DMA1_2_POS) |
+ ((CONFIG_IRQ_DMA1_3 - 7) << IRQ_DMA1_3_POS) |
+ ((CONFIG_IRQ_DMA1_4 - 7) << IRQ_DMA1_4_POS));
+
+ bfin_write_SICA_IAR2(((CONFIG_IRQ_DMA1_5 - 7) << IRQ_DMA1_5_POS) |
+ ((CONFIG_IRQ_DMA1_6 - 7) << IRQ_DMA1_6_POS) |
+ ((CONFIG_IRQ_DMA1_7 - 7) << IRQ_DMA1_7_POS) |
+ ((CONFIG_IRQ_DMA1_8 - 7) << IRQ_DMA1_8_POS) |
+ ((CONFIG_IRQ_DMA1_9 - 7) << IRQ_DMA1_9_POS) |
+ ((CONFIG_IRQ_DMA1_10 - 7) << IRQ_DMA1_10_POS) |
+ ((CONFIG_IRQ_DMA1_11 - 7) << IRQ_DMA1_11_POS) |
+ ((CONFIG_IRQ_DMA2_0 - 7) << IRQ_DMA2_0_POS));
+
+ bfin_write_SICA_IAR3(((CONFIG_IRQ_DMA2_1 - 7) << IRQ_DMA2_1_POS) |
+ ((CONFIG_IRQ_DMA2_2 - 7) << IRQ_DMA2_2_POS) |
+ ((CONFIG_IRQ_DMA2_3 - 7) << IRQ_DMA2_3_POS) |
+ ((CONFIG_IRQ_DMA2_4 - 7) << IRQ_DMA2_4_POS) |
+ ((CONFIG_IRQ_DMA2_5 - 7) << IRQ_DMA2_5_POS) |
+ ((CONFIG_IRQ_DMA2_6 - 7) << IRQ_DMA2_6_POS) |
+ ((CONFIG_IRQ_DMA2_7 - 7) << IRQ_DMA2_7_POS) |
+ ((CONFIG_IRQ_DMA2_8 - 7) << IRQ_DMA2_8_POS));
+
+ bfin_write_SICA_IAR4(((CONFIG_IRQ_DMA2_9 - 7) << IRQ_DMA2_9_POS) |
+ ((CONFIG_IRQ_DMA2_10 - 7) << IRQ_DMA2_10_POS) |
+ ((CONFIG_IRQ_DMA2_11 - 7) << IRQ_DMA2_11_POS) |
+ ((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) |
+ ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) |
+ ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) |
+ ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) |
+ ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS));
+
+ bfin_write_SICA_IAR5(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
+ ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) |
+ ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) |
+ ((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) |
+ ((CONFIG_IRQ_TIMER9 - 7) << IRQ_TIMER9_POS) |
+ ((CONFIG_IRQ_TIMER10 - 7) << IRQ_TIMER10_POS) |
+ ((CONFIG_IRQ_TIMER11 - 7) << IRQ_TIMER11_POS) |
+ ((CONFIG_IRQ_PROG0_INTA - 7) << IRQ_PROG0_INTA_POS));
+
+ bfin_write_SICA_IAR6(((CONFIG_IRQ_PROG0_INTB - 7) << IRQ_PROG0_INTB_POS) |
+ ((CONFIG_IRQ_PROG1_INTA - 7) << IRQ_PROG1_INTA_POS) |
+ ((CONFIG_IRQ_PROG1_INTB - 7) << IRQ_PROG1_INTB_POS) |
+ ((CONFIG_IRQ_PROG2_INTA - 7) << IRQ_PROG2_INTA_POS) |
+ ((CONFIG_IRQ_PROG2_INTB - 7) << IRQ_PROG2_INTB_POS) |
+ ((CONFIG_IRQ_DMA1_WRRD0 - 7) << IRQ_DMA1_WRRD0_POS) |
+ ((CONFIG_IRQ_DMA1_WRRD1 - 7) << IRQ_DMA1_WRRD1_POS) |
+ ((CONFIG_IRQ_DMA2_WRRD0 - 7) << IRQ_DMA2_WRRD0_POS));
+
+ bfin_write_SICA_IAR7(((CONFIG_IRQ_DMA2_WRRD1 - 7) << IRQ_DMA2_WRRD1_POS) |
+ ((CONFIG_IRQ_IMDMA_WRRD0 - 7) << IRQ_IMDMA_WRRD0_POS) |
+ ((CONFIG_IRQ_IMDMA_WRRD1 - 7) << IRQ_IMDMA_WRRD1_POS) |
+ ((CONFIG_IRQ_WDTIMER - 7) << IRQ_WDTIMER_POS) |
+ (0 << IRQ_RESERVED_1_POS) | (0 << IRQ_RESERVED_2_POS) |
+ (0 << IRQ_SUPPLE_0_POS) | (0 << IRQ_SUPPLE_1_POS));
+
+ SSYNC();
+}
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
new file mode 100644
index 00000000000..d3a49073d19
--- /dev/null
+++ b/arch/blackfin/mach-common/Makefile
@@ -0,0 +1,12 @@
+#
+# arch/blackfin/mach-common/Makefile
+#
+
+obj-y := \
+ cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
+ interrupt.o lock.o dpmc.o irqpanic.o
+
+obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
+obj-$(CONFIG_BFIN_SINGLE_CORE) += ints-priority-sc.o
+obj-$(CONFIG_BFIN_DUAL_CORE) += ints-priority-dc.o
+obj-$(CONFIG_PM) += pm.o
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
new file mode 100644
index 00000000000..bb9446ef66e
--- /dev/null
+++ b/arch/blackfin/mach-common/cache.S
@@ -0,0 +1,253 @@
+/*
+ * File: arch/blackfin/mach-common/cache.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created:
+ * Description: cache control support
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/cplb.h>
+#include <asm/entry.h>
+#include <asm/blackfin.h>
+#include <asm/cache.h>
+
+.text
+.align 2
+ENTRY(_cache_invalidate)
+
+ /*
+ * Icache or DcacheA or DcacheB Invalidation
+ * or any combination thereof
+ * R0 has bits
+ * CPLB_ENABLE_ICACHE_P,CPLB_ENABLE_DCACHE_P,CPLB_ENABLE_DCACHE2_P
+ * set as required
+ */
+ [--SP] = R7;
+
+ R7 = R0;
+ CC = BITTST(R7,CPLB_ENABLE_ICACHE_P);
+ IF !CC JUMP .Lno_icache;
+ [--SP] = RETS;
+ CALL _icache_invalidate;
+ RETS = [SP++];
+.Lno_icache:
+ CC = BITTST(R7,CPLB_ENABLE_DCACHE_P);
+ IF !CC JUMP .Lno_dcache_a;
+ R0 = 0; /* specifies bank A */
+ [--SP] = RETS;
+ CALL _dcache_invalidate;
+ RETS = [SP++];
+.Lno_dcache_a:
+ CC = BITTST(R7,CPLB_ENABLE_DCACHE2_P);
+ IF !CC JUMP .Lno_dcache_b;
+ R0 = 0;
+ BITSET(R0, 23); /* specifies bank B */
+ [--SP] = RETS;
+ CALL _dcache_invalidate;
+ RETS = [SP++];
+.Lno_dcache_b:
+ R7 = [SP++];
+ RTS;
+
+/* Invalidate the Entire Instruction cache by
+ * disabling IMC bit
+ */
+ENTRY(_icache_invalidate)
+ENTRY(_invalidate_entire_icache)
+ [--SP] = ( R7:5);
+
+ P0.L = (IMEM_CONTROL & 0xFFFF);
+ P0.H = (IMEM_CONTROL >> 16);
+ R7 = [P0];
+
+ /* Clear the IMC bit , All valid bits in the instruction
+ * cache are set to the invalid state
+ */
+ BITCLR(R7,IMC_P);
+ CLI R6;
+ SSYNC; /* SSYNC required before invalidating cache. */
+ .align 8;
+ [P0] = R7;
+ SSYNC;
+ STI R6;
+
+ /* Configures the instruction cache agian */
+ R6 = (IMC | ENICPLB);
+ R7 = R7 | R6;
+
+ CLI R6;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P0] = R7;
+ SSYNC;
+ STI R6;
+
+ ( R7:5) = [SP++];
+ RTS;
+
+/*
+ * blackfin_cache_flush_range(start, end)
+ * Invalidate all cache lines assocoiated with this
+ * area of memory.
+ *
+ * start: Start address
+ * end: End address
+ */
+ENTRY(_blackfin_icache_flush_range)
+ R2 = -L1_CACHE_BYTES;
+ R2 = R0 & R2;
+ P0 = R2;
+ P1 = R1;
+ CSYNC;
+ IFLUSH [P0];
+1:
+ IFLUSH [P0++];
+ CC = P0 < P1 (iu);
+ IF CC JUMP 1b (bp);
+ IFLUSH [P0];
+ SSYNC;
+ RTS;
+
+/*
+ * blackfin_icache_dcache_flush_range(start, end)
+ * FLUSH all cache lines assocoiated with this
+ * area of memory.
+ *
+ * start: Start address
+ * end: End address
+ */
+
+ENTRY(_blackfin_icache_dcache_flush_range)
+ R2 = -L1_CACHE_BYTES;
+ R2 = R0 & R2;
+ P0 = R2;
+ P1 = R1;
+ CSYNC;
+ IFLUSH [P0];
+1:
+ FLUSH [P0];
+ IFLUSH [P0++];
+ CC = P0 < P1 (iu);
+ IF CC JUMP 1b (bp);
+ IFLUSH [P0];
+ FLUSH [P0];
+ SSYNC;
+ RTS;
+
+/* Throw away all D-cached data in specified region without any obligation to
+ * write them back. However, we must clean the D-cached entries around the
+ * boundaries of the start and/or end address is not cache aligned.
+ *
+ * Start: start address,
+ * end : end address.
+ */
+
+ENTRY(_blackfin_dcache_invalidate_range)
+ R2 = -L1_CACHE_BYTES;
+ R2 = R0 & R2;
+ P0 = R2;
+ P1 = R1;
+ CSYNC;
+ FLUSHINV[P0];
+1:
+ FLUSHINV[P0++];
+ CC = P0 < P1 (iu);
+ IF CC JUMP 1b (bp);
+
+ /* If the data crosses a cache line, then we'll be pointing to
+ * the last cache line, but won't have flushed/invalidated it yet,
+ * so do one more.
+ */
+ FLUSHINV[P0];
+ SSYNC;
+ RTS;
+
+/* Invalidate the Entire Data cache by
+ * clearing DMC[1:0] bits
+ */
+ENTRY(_invalidate_entire_dcache)
+ENTRY(_dcache_invalidate)
+ [--SP] = ( R7:6);
+
+ P0.L = (DMEM_CONTROL & 0xFFFF);
+ P0.H = (DMEM_CONTROL >> 16);
+ R7 = [P0];
+
+ /* Clear the DMC[1:0] bits, All valid bits in the data
+ * cache are set to the invalid state
+ */
+ BITCLR(R7,DMC0_P);
+ BITCLR(R7,DMC1_P);
+ CLI R6;
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P0] = R7;
+ SSYNC;
+ STI R6;
+
+ /* Configures the data cache again */
+
+ R6 = DMEM_CNTR;
+ R7 = R7 | R6;
+
+ CLI R6;
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P0] = R7;
+ SSYNC;
+ STI R6;
+
+ ( R7:6) = [SP++];
+ RTS;
+
+ENTRY(_blackfin_dcache_flush_range)
+ R2 = -L1_CACHE_BYTES;
+ R2 = R0 & R2;
+ P0 = R2;
+ P1 = R1;
+ CSYNC;
+ FLUSH[P0];
+1:
+ FLUSH[P0++];
+ CC = P0 < P1 (iu);
+ IF CC JUMP 1b (bp);
+
+ /* If the data crosses a cache line, then we'll be pointing to
+ * the last cache line, but won't have flushed it yet, so do
+ * one more.
+ */
+ FLUSH[P0];
+ SSYNC;
+ RTS;
+
+ENTRY(_blackfin_dflush_page)
+ P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
+ P0 = R0;
+ CSYNC;
+ FLUSH[P0];
+ LSETUP (.Lfl1, .Lfl1) LC0 = P1;
+.Lfl1: FLUSH [P0++];
+ SSYNC;
+ RTS;
diff --git a/arch/blackfin/mach-common/cacheinit.S b/arch/blackfin/mach-common/cacheinit.S
new file mode 100644
index 00000000000..8c17f099e5e
--- /dev/null
+++ b/arch/blackfin/mach-common/cacheinit.S
@@ -0,0 +1,137 @@
+/*
+ * File: arch/blackfin/mach-common/cacheinit.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created: ?
+ * Description: cache initialization
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This function sets up the data and instruction cache. The
+ * tables like icplb table, dcplb table and Page Descriptor table
+ * are defined in cplbtab.h. You can configure those tables for
+ * your suitable requirements
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+.text
+
+#if defined(CONFIG_BLKFIN_CACHE)
+ENTRY(_bfin_icache_init)
+
+ /* Initialize Instruction CPLBS */
+
+ I0.L = (ICPLB_ADDR0 & 0xFFFF);
+ I0.H = (ICPLB_ADDR0 >> 16);
+
+ I1.L = (ICPLB_DATA0 & 0xFFFF);
+ I1.H = (ICPLB_DATA0 >> 16);
+
+ I2.L = _icplb_table;
+ I2.H = _icplb_table;
+
+ r1 = -1; /* end point comparison */
+ r3 = 15; /* max counter */
+
+/* read entries from table */
+
+.Lread_iaddr:
+ R0 = [I2++];
+ CC = R0 == R1;
+ IF CC JUMP .Lidone;
+ [I0++] = R0;
+
+.Lread_idata:
+ R2 = [I2++];
+ [I1++] = R2;
+ R3 = R3 + R1;
+ CC = R3 == R1;
+ IF !CC JUMP .Lread_iaddr;
+
+.Lidone:
+ /* Enable Instruction Cache */
+ P0.l = (IMEM_CONTROL & 0xFFFF);
+ P0.h = (IMEM_CONTROL >> 16);
+ R1 = [P0];
+ R0 = (IMC | ENICPLB);
+ R0 = R0 | R1;
+
+ /* Anomaly 05000125 */
+ CLI R2;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P0] = R0;
+ SSYNC;
+ STI R2;
+ RTS;
+#endif
+
+#if defined(CONFIG_BLKFIN_DCACHE)
+ENTRY(_bfin_dcache_init)
+
+ /* Initialize Data CPLBS */
+
+ I0.L = (DCPLB_ADDR0 & 0xFFFF);
+ I0.H = (DCPLB_ADDR0 >> 16);
+
+ I1.L = (DCPLB_DATA0 & 0xFFFF);
+ I1.H = (DCPLB_DATA0 >> 16);
+
+ I2.L = _dcplb_table;
+ I2.H = _dcplb_table;
+
+ R1 = -1; /* end point comparison */
+ R3 = 15; /* max counter */
+
+ /* read entries from table */
+.Lread_daddr:
+ R0 = [I2++];
+ cc = R0 == R1;
+ IF CC JUMP .Lddone;
+ [I0++] = R0;
+
+.Lread_ddata:
+ R2 = [I2++];
+ [I1++] = R2;
+ R3 = R3 + R1;
+ CC = R3 == R1;
+ IF !CC JUMP .Lread_daddr;
+.Lddone:
+ P0.L = (DMEM_CONTROL & 0xFFFF);
+ P0.H = (DMEM_CONTROL >> 16);
+ R1 = [P0];
+
+ R0 = DMEM_CNTR;
+
+ R0 = R0 | R1;
+ /* Anomaly 05000125 */
+ CLI R2;
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P0] = R0;
+ SSYNC;
+ STI R2;
+ RTS;
+#endif
diff --git a/arch/blackfin/mach-common/cplbhdlr.S b/arch/blackfin/mach-common/cplbhdlr.S
new file mode 100644
index 00000000000..b979067c49e
--- /dev/null
+++ b/arch/blackfin/mach-common/cplbhdlr.S
@@ -0,0 +1,130 @@
+/*
+ * File: arch/blackfin/mach-common/cplbhdlr.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created: ?
+ * Description: CPLB exception handler
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/cplb.h>
+#include <asm/entry.h>
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.type _cplb_mgr, STT_FUNC;
+.type _panic_cplb_error, STT_FUNC;
+
+.align 2
+
+.global __cplb_hdr;
+.type __cplb_hdr, STT_FUNC;
+ENTRY(__cplb_hdr)
+ R2 = SEQSTAT;
+
+ /* Mask the contents of SEQSTAT and leave only EXCAUSE in R2 */
+ R2 <<= 26;
+ R2 >>= 26;
+
+ R1 = 0x23; /* Data access CPLB protection violation */
+ CC = R2 == R1;
+ IF !CC JUMP .Lnot_data_write;
+ R0 = 2; /* is a write to data space*/
+ JUMP .Lis_icplb_miss;
+
+.Lnot_data_write:
+ R1 = 0x2C; /* CPLB miss on an instruction fetch */
+ CC = R2 == R1;
+ R0 = 0; /* is_data_miss == False*/
+ IF CC JUMP .Lis_icplb_miss;
+
+ R1 = 0x26;
+ CC = R2 == R1;
+ IF !CC JUMP .Lunknown;
+
+ R0 = 1; /* is_data_miss == True*/
+
+.Lis_icplb_miss:
+
+#if defined(CONFIG_BLKFIN_CACHE) || defined(CONFIG_BLKFIN_DCACHE)
+# if defined(CONFIG_BLKFIN_CACHE) && !defined(CONFIG_BLKFIN_DCACHE)
+ R1 = CPLB_ENABLE_ICACHE;
+# endif
+# if !defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
+ R1 = CPLB_ENABLE_DCACHE;
+# endif
+# if defined(CONFIG_BLKFIN_CACHE) && defined(CONFIG_BLKFIN_DCACHE)
+ R1 = CPLB_ENABLE_DCACHE | CPLB_ENABLE_ICACHE;
+# endif
+#else
+ R1 = 0;
+#endif
+
+ [--SP] = RETS;
+ CALL _cplb_mgr;
+ RETS = [SP++];
+ CC = R0 == 0;
+ IF !CC JUMP .Lnot_replaced;
+ RTS;
+
+/*
+ * Diagnostic exception handlers
+ */
+.Lunknown:
+ R0 = CPLB_UNKNOWN_ERR;
+ JUMP .Lcplb_error;
+
+.Lnot_replaced:
+ CC = R0 == CPLB_NO_UNLOCKED;
+ IF !CC JUMP .Lnext_check;
+ R0 = CPLB_NO_UNLOCKED;
+ JUMP .Lcplb_error;
+
+.Lnext_check:
+ CC = R0 == CPLB_NO_ADDR_MATCH;
+ IF !CC JUMP .Lnext_check2;
+ R0 = CPLB_NO_ADDR_MATCH;
+ JUMP .Lcplb_error;
+
+.Lnext_check2:
+ CC = R0 == CPLB_PROT_VIOL;
+ IF !CC JUMP .Lstrange_return_from_cplb_mgr;
+ R0 = CPLB_PROT_VIOL;
+ JUMP .Lcplb_error;
+
+.Lstrange_return_from_cplb_mgr:
+ IDLE;
+ CSYNC;
+ JUMP .Lstrange_return_from_cplb_mgr;
+
+.Lcplb_error:
+ R1 = sp;
+ SP += -12;
+ call _panic_cplb_error;
+ SP += 12;
+ JUMP _handle_bad_cplb;
diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/mach-common/cplbinfo.c
new file mode 100644
index 00000000000..d65fac39d1b
--- /dev/null
+++ b/arch/blackfin/mach-common/cplbinfo.c
@@ -0,0 +1,211 @@
+/*
+ * File: arch/blackfin/mach-common/cplbinfo.c
+ * Based on:
+ * Author: Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created: Jan. 2005
+ * Description: Display CPLB status
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/current.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <asm/cplb.h>
+#include <asm/blackfin.h>
+
+#define CPLB_I 1
+#define CPLB_D 2
+
+#define SYNC_SYS SSYNC()
+#define SYNC_CORE CSYNC()
+
+#define CPLB_BIT_PAGESIZE 0x30000
+
+static int page_size_table[4] = {
+ 0x00000400, /* 1K */
+ 0x00001000, /* 4K */
+ 0x00100000, /* 1M */
+ 0x00400000 /* 4M */
+};
+
+static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
+
+static int cplb_find_entry(unsigned long *cplb_addr,
+ unsigned long *cplb_data, unsigned long addr,
+ unsigned long data)
+{
+ int ii;
+
+ for (ii = 0; ii < 16; ii++)
+ if (addr >= cplb_addr[ii] && addr < cplb_addr[ii] +
+ page_size_table[(cplb_data[ii] & CPLB_BIT_PAGESIZE) >> 16]
+ && (cplb_data[ii] == data))
+ return ii;
+
+ return -1;
+}
+
+static char *cplb_print_entry(char *buf, int type)
+{
+ unsigned long *p_addr = dpdt_table;
+ unsigned long *p_data = dpdt_table + 1;
+ unsigned long *p_icount = dpdt_swapcount_table;
+ unsigned long *p_ocount = dpdt_swapcount_table + 1;
+ unsigned long *cplb_addr = (unsigned long *)DCPLB_ADDR0;
+ unsigned long *cplb_data = (unsigned long *)DCPLB_DATA0;
+ int entry = 0, used_cplb = 0;
+
+ if (type == CPLB_I) {
+ buf += sprintf(buf, "Instrction CPLB entry:\n");
+ p_addr = ipdt_table;
+ p_data = ipdt_table + 1;
+ p_icount = ipdt_swapcount_table;
+ p_ocount = ipdt_swapcount_table + 1;
+ cplb_addr = (unsigned long *)ICPLB_ADDR0;
+ cplb_data = (unsigned long *)ICPLB_DATA0;
+ } else
+ buf += sprintf(buf, "Data CPLB entry:\n");
+
+ buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\
+\tiCount\toCount\n");
+
+ while (*p_addr != 0xffffffff) {
+ entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
+ if (entry >= 0)
+ used_cplb |= 1 << entry;
+
+ buf +=
+ sprintf(buf,
+ "0x%08lx\t0x%05lx\t%s\t%c\t%c\t%2d\t%ld\t%ld\n",
+ *p_addr, *p_data,
+ page_size_string_table[(*p_data & 0x30000) >> 16],
+ (*p_data & CPLB_VALID) ? 'Y' : 'N',
+ (*p_data & CPLB_LOCK) ? 'Y' : 'N', entry, *p_icount,
+ *p_ocount);
+
+ p_addr += 2;
+ p_data += 2;
+ p_icount += 2;
+ p_ocount += 2;
+ }
+
+ if (used_cplb != 0xffff) {
+ buf += sprintf(buf, "Unused/mismatched CPLBs:\n");
+
+ for (entry = 0; entry < 16; entry++)
+ if (0 == ((1 << entry) & used_cplb)) {
+ int flags = cplb_data[entry];
+ buf +=
+ sprintf(buf,
+ "%2d: 0x%08lx\t0x%05x\t%s\t%c\t%c\n",
+ entry, cplb_addr[entry], flags,
+ page_size_string_table[(flags &
+ 0x30000) >>
+ 16],
+ (flags & CPLB_VALID) ? 'Y' : 'N',
+ (flags & CPLB_LOCK) ? 'Y' : 'N');
+ }
+ }
+
+ buf += sprintf(buf, "\n");
+
+ return buf;
+}
+
+static int cplbinfo_proc_output(char *buf)
+{
+ char *p;
+
+ p = buf;
+
+ p += sprintf(p,
+ "------------------ CPLB Information ------------------\n\n");
+
+ if (bfin_read_IMEM_CONTROL() & ENICPLB)
+ p = cplb_print_entry(p, CPLB_I);
+ else
+ p += sprintf(p, "Instruction CPLB is disabled.\n\n");
+
+ if (bfin_read_DMEM_CONTROL() & ENDCPLB)
+ p = cplb_print_entry(p, CPLB_D);
+ else
+ p += sprintf(p, "Data CPLB is disabled.\n");
+
+ return p - buf;
+}
+
+static int cplbinfo_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len;
+
+ len = cplbinfo_proc_output(page);
+ if (len <= off + count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+ return len;
+}
+
+static int cplbinfo_write_proc(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ printk(KERN_INFO "Reset the CPLB swap in/out counts.\n");
+ memset(ipdt_swapcount_table, 0, MAX_SWITCH_I_CPLBS * sizeof(unsigned long));
+ memset(dpdt_swapcount_table, 0, MAX_SWITCH_D_CPLBS * sizeof(unsigned long));
+
+ return count;
+}
+
+static int __init cplbinfo_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ if ((entry = create_proc_entry("cplbinfo", 0, NULL)) == NULL) {
+ return -ENOMEM;
+ }
+
+ entry->read_proc = cplbinfo_read_proc;
+ entry->write_proc = cplbinfo_write_proc;
+ entry->data = NULL;
+
+ return 0;
+}
+
+static void __exit cplbinfo_exit(void)
+{
+ remove_proc_entry("cplbinfo", NULL);
+}
+
+module_init(cplbinfo_init);
+module_exit(cplbinfo_exit);
diff --git a/arch/blackfin/mach-common/cplbmgr.S b/arch/blackfin/mach-common/cplbmgr.S
new file mode 100644
index 00000000000..f5efc4bc65e
--- /dev/null
+++ b/arch/blackfin/mach-common/cplbmgr.S
@@ -0,0 +1,607 @@
+/*
+ * File: arch/blackfin/mach-common/cplbmgtr.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created: ?
+ * Description: CPLB replacement routine for CPLB mismatch
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Usage: int _cplb_mgr(is_data_miss,int enable_cache)
+ * is_data_miss==2 => Mark as Dirty, write to the clean data page
+ * is_data_miss==1 => Replace a data CPLB.
+ * is_data_miss==0 => Replace an instruction CPLB.
+ *
+ * Returns:
+ * CPLB_RELOADED => Successfully updated CPLB table.
+ * CPLB_NO_UNLOCKED => All CPLBs are locked, so cannot be evicted.
+ * This indicates that the CPLBs in the configuration
+ * tablei are badly configured, as this should never
+ * occur.
+ * CPLB_NO_ADDR_MATCH => The address being accessed, that triggered the
+ * exception, is not covered by any of the CPLBs in
+ * the configuration table. The application is
+ * presumably misbehaving.
+ * CPLB_PROT_VIOL => The address being accessed, that triggered the
+ * exception, was not a first-write to a clean Write
+ * Back Data page, and so presumably is a genuine
+ * violation of the page's protection attributes.
+ * The application is misbehaving.
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 2;
+ENTRY(_cplb_mgr)
+
+ [--SP]=( R7:4,P5:3 );
+
+ CC = R0 == 2;
+ IF CC JUMP .Ldcplb_write;
+
+ CC = R0 == 0;
+ IF !CC JUMP .Ldcplb_miss_compare;
+
+ /* ICPLB Miss Exception. We need to choose one of the
+ * currently-installed CPLBs, and replace it with one
+ * from the configuration table.
+ */
+
+ P4.L = (ICPLB_FAULT_ADDR & 0xFFFF);
+ P4.H = (ICPLB_FAULT_ADDR >> 16);
+
+ P1 = 16;
+ P5.L = _page_size_table;
+ P5.H = _page_size_table;
+
+ P0.L = (ICPLB_DATA0 & 0xFFFF);
+ P0.H = (ICPLB_DATA0 >> 16);
+ R4 = [P4]; /* Get faulting address*/
+ R6 = 64; /* Advance past the fault address, which*/
+ R6 = R6 + R4; /* we'll use if we find a match*/
+ R3 = ((16 << 8) | 2); /* Extract mask, bits 16 and 17.*/
+
+ R5 = 0;
+.Lisearch:
+
+ R1 = [P0-0x100]; /* Address for this CPLB */
+
+ R0 = [P0++]; /* Info for this CPLB*/
+ CC = BITTST(R0,0); /* Is the CPLB valid?*/
+ IF !CC JUMP .Lnomatch; /* Skip it, if not.*/
+ CC = R4 < R1(IU); /* If fault address less than page start*/
+ IF CC JUMP .Lnomatch; /* then skip this one.*/
+ R2 = EXTRACT(R0,R3.L) (Z); /* Get page size*/
+ P1 = R2;
+ P1 = P5 + (P1<<2); /* index into page-size table*/
+ R2 = [P1]; /* Get the page size*/
+ R1 = R1 + R2; /* and add to page start, to get page end*/
+ CC = R4 < R1(IU); /* and see whether fault addr is in page.*/
+ IF !CC R4 = R6; /* If so, advance the address and finish loop.*/
+ IF !CC JUMP .Lisearch_done;
+.Lnomatch:
+ /* Go around again*/
+ R5 += 1;
+ CC = BITTST(R5, 4); /* i.e CC = R5 >= 16*/
+ IF !CC JUMP .Lisearch;
+
+.Lisearch_done:
+ I0 = R4; /* Fault address we'll search for*/
+
+ /* set up pointers */
+ P0.L = (ICPLB_DATA0 & 0xFFFF);
+ P0.H = (ICPLB_DATA0 >> 16);
+
+ /* The replacement procedure for ICPLBs */
+
+ P4.L = (IMEM_CONTROL & 0xFFFF);
+ P4.H = (IMEM_CONTROL >> 16);
+
+ /* disable cplbs */
+ R5 = [P4]; /* Control Register*/
+ BITCLR(R5,ENICPLB_P);
+ CLI R1;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R1;
+
+ R1 = -1; /* end point comparison */
+ R3 = 16; /* counter */
+
+ /* Search through CPLBs for first non-locked entry */
+ /* Overwrite it by moving everyone else up by 1 */
+.Licheck_lock:
+ R0 = [P0++];
+ R3 = R3 + R1;
+ CC = R3 == R1;
+ IF CC JUMP .Lall_locked;
+ CC = BITTST(R0, 0); /* an invalid entry is good */
+ IF !CC JUMP .Lifound_victim;
+ CC = BITTST(R0,1); /* but a locked entry isn't */
+ IF CC JUMP .Licheck_lock;
+
+.Lifound_victim:
+#ifdef CONFIG_CPLB_INFO
+ R7 = [P0 - 0x104];
+ P2.L = _ipdt_table;
+ P2.H = _ipdt_table;
+ P3.L = _ipdt_swapcount_table;
+ P3.H = _ipdt_swapcount_table;
+ P3 += -4;
+.Licount:
+ R2 = [P2]; /* address from config table */
+ P2 += 8;
+ P3 += 8;
+ CC = R2==-1;
+ IF CC JUMP .Licount_done;
+ CC = R7==R2;
+ IF !CC JUMP .Licount;
+ R7 = [P3];
+ R7 += 1;
+ [P3] = R7;
+ CSYNC;
+.Licount_done:
+#endif
+ LC0=R3;
+ LSETUP(.Lis_move,.Lie_move) LC0;
+.Lis_move:
+ R0 = [P0];
+ [P0 - 4] = R0;
+ R0 = [P0 - 0x100];
+ [P0-0x104] = R0;
+.Lie_move:P0+=4;
+
+ /* We've made space in the ICPLB table, so that ICPLB15
+ * is now free to be overwritten. Next, we have to determine
+ * which CPLB we need to install, from the configuration
+ * table. This is a matter of getting the start-of-page
+ * addresses and page-lengths from the config table, and
+ * determining whether the fault address falls within that
+ * range.
+ */
+
+ P2.L = _ipdt_table;
+ P2.H = _ipdt_table;
+#ifdef CONFIG_CPLB_INFO
+ P3.L = _ipdt_swapcount_table;
+ P3.H = _ipdt_swapcount_table;
+ P3 += -8;
+#endif
+ P0.L = _page_size_table;
+ P0.H = _page_size_table;
+
+ /* Retrieve our fault address (which may have been advanced
+ * because the faulting instruction crossed a page boundary).
+ */
+
+ R0 = I0;
+
+ /* An extraction pattern, to get the page-size bits from
+ * the CPLB data entry. Bits 16-17, so two bits at posn 16.
+ */
+
+ R1 = ((16<<8)|2);
+.Linext: R4 = [P2++]; /* address from config table */
+ R2 = [P2++]; /* data from config table */
+#ifdef CONFIG_CPLB_INFO
+ P3 += 8;
+#endif
+
+ CC = R4 == -1; /* End of config table*/
+ IF CC JUMP .Lno_page_in_table;
+
+ /* See if failed address > start address */
+ CC = R4 <= R0(IU);
+ IF !CC JUMP .Linext;
+
+ /* extract page size (17:16)*/
+ R3 = EXTRACT(R2, R1.L) (Z);
+
+ /* add page size to addr to get range */
+
+ P5 = R3;
+ P5 = P0 + (P5 << 2); /* scaled, for int access*/
+ R3 = [P5];
+ R3 = R3 + R4;
+
+ /* See if failed address < (start address + page size) */
+ CC = R0 < R3(IU);
+ IF !CC JUMP .Linext;
+
+ /* We've found a CPLB in the config table that covers
+ * the faulting address, so install this CPLB into the
+ * last entry of the table.
+ */
+
+ P1.L = (ICPLB_DATA15 & 0xFFFF); /* ICPLB_DATA15 */
+ P1.H = (ICPLB_DATA15 >> 16);
+ [P1] = R2;
+ [P1-0x100] = R4;
+#ifdef CONFIG_CPLB_INFO
+ R3 = [P3];
+ R3 += 1;
+ [P3] = R3;
+#endif
+
+ /* P4 points to IMEM_CONTROL, and R5 contains its old
+ * value, after we disabled ICPLBS. Re-enable them.
+ */
+
+ BITSET(R5,ENICPLB_P);
+ CLI R2;
+ SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R2;
+
+ ( R7:4,P5:3 ) = [SP++];
+ R0 = CPLB_RELOADED;
+ RTS;
+
+/* FAILED CASES*/
+.Lno_page_in_table:
+ ( R7:4,P5:3 ) = [SP++];
+ R0 = CPLB_NO_ADDR_MATCH;
+ RTS;
+.Lall_locked:
+ ( R7:4,P5:3 ) = [SP++];
+ R0 = CPLB_NO_UNLOCKED;
+ RTS;
+.Lprot_violation:
+ ( R7:4,P5:3 ) = [SP++];
+ R0 = CPLB_PROT_VIOL;
+ RTS;
+
+.Ldcplb_write:
+
+ /* if a DCPLB is marked as write-back (CPLB_WT==0), and
+ * it is clean (CPLB_DIRTY==0), then a write to the
+ * CPLB's page triggers a protection violation. We have to
+ * mark the CPLB as dirty, to indicate that there are
+ * pending writes associated with the CPLB.
+ */
+
+ P4.L = (DCPLB_STATUS & 0xFFFF);
+ P4.H = (DCPLB_STATUS >> 16);
+ P3.L = (DCPLB_DATA0 & 0xFFFF);
+ P3.H = (DCPLB_DATA0 >> 16);
+ R5 = [P4];
+
+ /* A protection violation can be caused by more than just writes
+ * to a clean WB page, so we have to ensure that:
+ * - It's a write
+ * - to a clean WB page
+ * - and is allowed in the mode the access occurred.
+ */
+
+ CC = BITTST(R5, 16); /* ensure it was a write*/
+ IF !CC JUMP .Lprot_violation;
+
+ /* to check the rest, we have to retrieve the DCPLB.*/
+
+ /* The low half of DCPLB_STATUS is a bit mask*/
+
+ R2 = R5.L (Z); /* indicating which CPLB triggered the event.*/
+ R3 = 30; /* so we can use this to determine the offset*/
+ R2.L = SIGNBITS R2;
+ R2 = R2.L (Z); /* into the DCPLB table.*/
+ R3 = R3 - R2;
+ P4 = R3;
+ P3 = P3 + (P4<<2);
+ R3 = [P3]; /* Retrieve the CPLB*/
+
+ /* Now we can check whether it's a clean WB page*/
+
+ CC = BITTST(R3, 14); /* 0==WB, 1==WT*/
+ IF CC JUMP .Lprot_violation;
+ CC = BITTST(R3, 7); /* 0 == clean, 1 == dirty*/
+ IF CC JUMP .Lprot_violation;
+
+ /* Check whether the write is allowed in the mode that was active.*/
+
+ R2 = 1<<3; /* checking write in user mode*/
+ CC = BITTST(R5, 17); /* 0==was user, 1==was super*/
+ R5 = CC;
+ R2 <<= R5; /* if was super, check write in super mode*/
+ R2 = R3 & R2;
+ CC = R2 == 0;
+ IF CC JUMP .Lprot_violation;
+
+ /* It's a genuine write-to-clean-page.*/
+
+ BITSET(R3, 7); /* mark as dirty*/
+ [P3] = R3; /* and write back.*/
+ NOP;
+ CSYNC;
+ ( R7:4,P5:3 ) = [SP++];
+ R0 = CPLB_RELOADED;
+ RTS;
+
+.Ldcplb_miss_compare:
+
+ /* Data CPLB Miss event. We need to choose a CPLB to
+ * evict, and then locate a new CPLB to install from the
+ * config table, that covers the faulting address.
+ */
+
+ P1.L = (DCPLB_DATA15 & 0xFFFF);
+ P1.H = (DCPLB_DATA15 >> 16);
+
+ P4.L = (DCPLB_FAULT_ADDR & 0xFFFF);
+ P4.H = (DCPLB_FAULT_ADDR >> 16);
+ R4 = [P4];
+ I0 = R4;
+
+ /* The replacement procedure for DCPLBs*/
+
+ R6 = R1; /* Save for later*/
+
+ /* Turn off CPLBs while we work.*/
+ P4.L = (DMEM_CONTROL & 0xFFFF);
+ P4.H = (DMEM_CONTROL >> 16);
+ R5 = [P4];
+ BITCLR(R5,ENDCPLB_P);
+ CLI R0;
+ SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R0;
+
+ /* Start looking for a CPLB to evict. Our order of preference
+ * is: invalid CPLBs, clean CPLBs, dirty CPLBs. Locked CPLBs
+ * are no good.
+ */
+
+ I1.L = (DCPLB_DATA0 & 0xFFFF);
+ I1.H = (DCPLB_DATA0 >> 16);
+ P1 = 2;
+ P2 = 16;
+ I2.L = _dcplb_preference;
+ I2.H = _dcplb_preference;
+ LSETUP(.Lsdsearch1, .Ledsearch1) LC0 = P1;
+.Lsdsearch1:
+ R0 = [I2++]; /* Get the bits we're interested in*/
+ P0 = I1; /* Go back to start of table*/
+ LSETUP (.Lsdsearch2, .Ledsearch2) LC1 = P2;
+.Lsdsearch2:
+ R1 = [P0++]; /* Fetch each installed CPLB in turn*/
+ R2 = R1 & R0; /* and test for interesting bits.*/
+ CC = R2 == 0; /* If none are set, it'll do.*/
+ IF !CC JUMP .Lskip_stack_check;
+
+ R2 = [P0 - 0x104]; /* R2 - PageStart */
+ P3.L = _page_size_table; /* retrieve end address */
+ P3.H = _page_size_table; /* retrieve end address */
+ R3 = 0x1002; /* 16th - position, 2 bits -length */
+#ifdef ANOMALY_05000209
+ nop; /* Anomaly 05000209 */
+#endif
+ R7 = EXTRACT(R1,R3.l);
+ R7 = R7 << 2; /* Page size index offset */
+ P5 = R7;
+ P3 = P3 + P5;
+ R7 = [P3]; /* page size in bytes */
+
+ R7 = R2 + R7; /* R7 - PageEnd */
+ R4 = SP; /* Test SP is in range */
+
+ CC = R7 < R4; /* if PageEnd < SP */
+ IF CC JUMP .Ldfound_victim;
+ R3 = 0x284; /* stack length from start of trap till
+ * the point.
+ * 20 stack locations for future modifications
+ */
+ R4 = R4 + R3;
+ CC = R4 < R2; /* if SP + stacklen < PageStart */
+ IF CC JUMP .Ldfound_victim;
+.Lskip_stack_check:
+
+.Ledsearch2: NOP;
+.Ledsearch1: NOP;
+
+ /* If we got here, we didn't find a DCPLB we considered
+ * replacable, which means all of them were locked.
+ */
+
+ JUMP .Lall_locked;
+.Ldfound_victim:
+
+#ifdef CONFIG_CPLB_INFO
+ R7 = [P0 - 0x104];
+ P2.L = _dpdt_table;
+ P2.H = _dpdt_table;
+ P3.L = _dpdt_swapcount_table;
+ P3.H = _dpdt_swapcount_table;
+ P3 += -4;
+.Ldicount:
+ R2 = [P2];
+ P2 += 8;
+ P3 += 8;
+ CC = R2==-1;
+ IF CC JUMP .Ldicount_done;
+ CC = R7==R2;
+ IF !CC JUMP .Ldicount;
+ R7 = [P3];
+ R7 += 1;
+ [P3] = R7;
+.Ldicount_done:
+#endif
+
+ /* Clean down the hardware loops*/
+ R2 = 0;
+ LC1 = R2;
+ LC0 = R2;
+
+ /* There's a suitable victim in [P0-4] (because we've
+ * advanced already).
+ */
+
+.LDdoverwrite:
+
+ /* [P0-4] is a suitable victim CPLB, so we want to
+ * overwrite it by moving all the following CPLBs
+ * one space closer to the start.
+ */
+
+ R1.L = (DCPLB_DATA16 & 0xFFFF); /* DCPLB_DATA15 + 4 */
+ R1.H = (DCPLB_DATA16 >> 16);
+ R0 = P0;
+
+ /* If the victim happens to be in DCPLB15,
+ * we don't need to move anything.
+ */
+
+ CC = R1 == R0;
+ IF CC JUMP .Lde_moved;
+ R1 = R1 - R0;
+ R1 >>= 2;
+ P1 = R1;
+ LSETUP(.Lds_move, .Lde_move) LC0=P1;
+.Lds_move:
+ R0 = [P0++]; /* move data */
+ [P0 - 8] = R0;
+ R0 = [P0-0x104] /* move address */
+.Lde_move: [P0-0x108] = R0;
+
+ /* We've now made space in DCPLB15 for the new CPLB to be
+ * installed. The next stage is to locate a CPLB in the
+ * config table that covers the faulting address.
+ */
+
+.Lde_moved:NOP;
+ R0 = I0; /* Our faulting address */
+
+ P2.L = _dpdt_table;
+ P2.H = _dpdt_table;
+#ifdef CONFIG_CPLB_INFO
+ P3.L = _dpdt_swapcount_table;
+ P3.H = _dpdt_swapcount_table;
+ P3 += -8;
+#endif
+
+ P1.L = _page_size_table;
+ P1.H = _page_size_table;
+
+ /* An extraction pattern, to retrieve bits 17:16.*/
+
+ R1 = (16<<8)|2;
+.Ldnext: R4 = [P2++]; /* address */
+ R2 = [P2++]; /* data */
+#ifdef CONFIG_CPLB_INFO
+ P3 += 8;
+#endif
+
+ CC = R4 == -1;
+ IF CC JUMP .Lno_page_in_table;
+
+ /* See if failed address > start address */
+ CC = R4 <= R0(IU);
+ IF !CC JUMP .Ldnext;
+
+ /* extract page size (17:16)*/
+ R3 = EXTRACT(R2, R1.L) (Z);
+
+ /* add page size to addr to get range */
+
+ P5 = R3;
+ P5 = P1 + (P5 << 2);
+ R3 = [P5];
+ R3 = R3 + R4;
+
+ /* See if failed address < (start address + page size) */
+ CC = R0 < R3(IU);
+ IF !CC JUMP .Ldnext;
+
+ /* We've found the CPLB that should be installed, so
+ * write it into CPLB15, masking off any caching bits
+ * if necessary.
+ */
+
+ P1.L = (DCPLB_DATA15 & 0xFFFF);
+ P1.H = (DCPLB_DATA15 >> 16);
+
+ /* If the DCPLB has cache bits set, but caching hasn't
+ * been enabled, then we want to mask off the cache-in-L1
+ * bit before installing. Moreover, if caching is off, we
+ * also want to ensure that the DCPLB has WT mode set, rather
+ * than WB, since WB pages still trigger first-write exceptions
+ * even when not caching is off, and the page isn't marked as
+ * cachable. Finally, we could mark the page as clean, not dirty,
+ * but we choose to leave that decision to the user; if the user
+ * chooses to have a CPLB pre-defined as dirty, then they always
+ * pay the cost of flushing during eviction, but don't pay the
+ * cost of first-write exceptions to mark the page as dirty.
+ */
+
+#ifdef CONFIG_BLKFIN_WT
+ BITSET(R6, 14); /* Set WT*/
+#endif
+
+ [P1] = R2;
+ [P1-0x100] = R4;
+#ifdef CONFIG_CPLB_INFO
+ R3 = [P3];
+ R3 += 1;
+ [P3] = R3;
+#endif
+
+ /* We've installed the CPLB, so re-enable CPLBs. P4
+ * points to DMEM_CONTROL, and R5 is the value we
+ * last wrote to it, when we were disabling CPLBs.
+ */
+
+ BITSET(R5,ENDCPLB_P);
+ CLI R2;
+ .align 8;
+ [P4] = R5;
+ SSYNC;
+ STI R2;
+
+ ( R7:4,P5:3 ) = [SP++];
+ R0 = CPLB_RELOADED;
+ RTS;
+
+.data
+.align 4;
+_page_size_table:
+.byte4 0x00000400; /* 1K */
+.byte4 0x00001000; /* 4K */
+.byte4 0x00100000; /* 1M */
+.byte4 0x00400000; /* 4M */
+
+.align 4;
+_dcplb_preference:
+.byte4 0x00000001; /* valid bit */
+.byte4 0x00000002; /* lock bit */
diff --git a/arch/blackfin/mach-common/dpmc.S b/arch/blackfin/mach-common/dpmc.S
new file mode 100644
index 00000000000..97cdcd6a00d
--- /dev/null
+++ b/arch/blackfin/mach-common/dpmc.S
@@ -0,0 +1,418 @@
+/*
+ * File: arch/blackfin/mach-common/dpmc.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created: ?
+ * Description: Watchdog Timer APIs
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/mach/irq.h>
+
+.text
+
+ENTRY(_unmask_wdog_wakeup_evt)
+ [--SP] = ( R7:0, P5:0 );
+#if defined(CONFIG_BF561)
+ P0.H = hi(SICA_IWR1);
+ P0.L = lo(SICA_IWR1);
+#else
+ P0.h = (SIC_IWR >> 16);
+ P0.l = (SIC_IWR & 0xFFFF);
+#endif
+ R7 = [P0];
+#if defined(CONFIG_BF561)
+ BITSET(R7, 27);
+#else
+ BITSET(R7,(IRQ_WATCH - IVG7));
+#endif
+ [P0] = R7;
+ SSYNC;
+
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+.LWRITE_TO_STAT:
+ /* When watch dog timer is enabled, a write to STAT will load the
+ * contents of CNT to STAT
+ */
+ R7 = 0x0000(z);
+#if defined(CONFIG_BF561)
+ P0.h = (WDOGA_STAT >> 16);
+ P0.l = (WDOGA_STAT & 0xFFFF);
+#else
+ P0.h = (WDOG_STAT >> 16);
+ P0.l = (WDOG_STAT & 0xFFFF);
+#endif
+ [P0] = R7;
+ SSYNC;
+ JUMP .LSKIP_WRITE_TO_STAT;
+
+ENTRY(_program_wdog_timer)
+ [--SP] = ( R7:0, P5:0 );
+#if defined(CONFIG_BF561)
+ P0.h = (WDOGA_CNT >> 16);
+ P0.l = (WDOGA_CNT & 0xFFFF);
+#else
+ P0.h = (WDOG_CNT >> 16);
+ P0.l = (WDOG_CNT & 0xFFFF);
+#endif
+ [P0] = R0;
+ SSYNC;
+
+#if defined(CONFIG_BF561)
+ P0.h = (WDOGA_CTL >> 16);
+ P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+ P0.h = (WDOG_CTL >> 16);
+ P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+ R7 = W[P0](Z);
+ CC = BITTST(R7,1);
+ if !CC JUMP .LWRITE_TO_STAT;
+ CC = BITTST(R7,2);
+ if !CC JUMP .LWRITE_TO_STAT;
+
+.LSKIP_WRITE_TO_STAT:
+#if defined(CONFIG_BF561)
+ P0.h = (WDOGA_CTL >> 16);
+ P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+ P0.h = (WDOG_CTL >> 16);
+ P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+ R7 = W[P0](Z);
+ BITCLR(R7,1); /* Enable GP event */
+ BITSET(R7,2);
+ W[P0] = R7.L;
+ SSYNC;
+ NOP;
+
+ R7 = W[P0](Z);
+ BITCLR(R7,4); /* Enable the wdog counter */
+ W[P0] = R7.L;
+ SSYNC;
+
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+ENTRY(_clear_wdog_wakeup_evt)
+ [--SP] = ( R7:0, P5:0 );
+
+#if defined(CONFIG_BF561)
+ P0.h = (WDOGA_CTL >> 16);
+ P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+ P0.h = (WDOG_CTL >> 16);
+ P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+ R7 = 0x0AD6(Z);
+ W[P0] = R7.L;
+ SSYNC;
+
+ R7 = W[P0](Z);
+ BITSET(R7,15);
+ W[P0] = R7.L;
+ SSYNC;
+
+ R7 = W[P0](Z);
+ BITSET(R7,1);
+ BITSET(R7,2);
+ W[P0] = R7.L;
+ SSYNC;
+
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+ENTRY(_disable_wdog_timer)
+ [--SP] = ( R7:0, P5:0 );
+#if defined(CONFIG_BF561)
+ P0.h = (WDOGA_CTL >> 16);
+ P0.l = (WDOGA_CTL & 0xFFFF);
+#else
+ P0.h = (WDOG_CTL >> 16);
+ P0.l = (WDOG_CTL & 0xFFFF);
+#endif
+ R7 = 0xAD6(Z);
+ W[P0] = R7.L;
+ SSYNC;
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+#if !defined(CONFIG_BF561)
+
+.section .l1.text
+
+ENTRY(_sleep_mode)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ call _set_sic_iwr;
+
+ R0 = 0xFFFF (Z);
+ call _set_rtc_istat
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R1 = W[P0](z);
+ BITSET (R1, 3);
+ W[P0] = R1.L;
+
+ CLI R2;
+ SSYNC;
+ IDLE;
+ STI R2;
+
+ call _test_pll_locked;
+
+ R0 = IWR_ENABLE(0);
+ call _set_sic_iwr;
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R7 = w[p0](z);
+ BITCLR (R7, 3);
+ BITCLR (R7, 5);
+ w[p0] = R7.L;
+ IDLE;
+ call _test_pll_locked;
+
+ RETS = [SP++];
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+ENTRY(_hibernate_mode)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ call _set_sic_iwr;
+
+ R0 = 0xFFFF (Z);
+ call _set_rtc_istat
+
+ P0.H = hi(VR_CTL);
+ P0.L = lo(VR_CTL);
+ R1 = W[P0](z);
+ BITSET (R1, 8);
+ BITCLR (R1, 0);
+ BITCLR (R1, 1);
+ W[P0] = R1.L;
+ SSYNC;
+
+ CLI R2;
+ IDLE;
+
+ /* Actually, adding anything may not be necessary...SDRAM contents
+ * are lost
+ */
+
+ENTRY(_deep_sleep)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ CLI R4;
+
+ call _set_sic_iwr;
+
+ call _set_sdram_srfs;
+
+ /* Clear all the interrupts,bits sticky */
+ R0 = 0xFFFF (Z);
+ call _set_rtc_istat
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R0 = W[P0](z);
+ BITSET (R0, 5);
+ W[P0] = R0.L;
+
+ call _test_pll_locked;
+
+ SSYNC;
+ IDLE;
+
+ call _unset_sdram_srfs;
+
+ call _test_pll_locked;
+
+ R0 = IWR_ENABLE(0);
+ call _set_sic_iwr;
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R0 = w[p0](z);
+ BITCLR (R0, 3);
+ BITCLR (R0, 5);
+ BITCLR (R0, 8);
+ w[p0] = R0;
+ IDLE;
+ call _test_pll_locked;
+
+ STI R4;
+
+ RETS = [SP++];
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+ENTRY(_sleep_deeper)
+ [--SP] = ( R7:0, P5:0 );
+ [--SP] = RETS;
+
+ CLI R4;
+
+ P3 = R0;
+ R0 = IWR_ENABLE(0);
+ call _set_sic_iwr;
+ call _set_sdram_srfs;
+
+ /* Clear all the interrupts,bits sticky */
+ R0 = 0xFFFF (Z);
+ call _set_rtc_istat
+
+ P0.H = hi(PLL_DIV);
+ P0.L = lo(PLL_DIV);
+ R6 = W[P0](z);
+ R0.L = 0xF;
+ W[P0] = R0.l;
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R5 = W[P0](z);
+ R0.L = (MIN_VC/CONFIG_CLKIN_HZ) << 9;
+ W[P0] = R0.l;
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ P0.H = hi(VR_CTL);
+ P0.L = lo(VR_CTL);
+ R7 = W[P0](z);
+ R1 = 0x6;
+ R1 <<= 16;
+ R2 = 0x0404(Z);
+ R1 = R1|R2;
+
+ R2 = DEPOSIT(R7, R1);
+ W[P0] = R2;
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ R0 = W[P0](z);
+ BITSET (R0, 3);
+ W[P0] = R0.L;
+
+ R0 = P3;
+ call _set_sic_iwr;
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ R0 = IWR_ENABLE(0);
+ call _set_sic_iwr;
+
+ P0.H = hi(VR_CTL);
+ P0.L = lo(VR_CTL);
+ W[P0]= R7;
+
+ SSYNC;
+ IDLE;
+
+ call _test_pll_locked;
+
+ P0.H = hi(PLL_DIV);
+ P0.L = lo(PLL_DIV);
+ W[P0]= R6;
+
+ P0.H = hi(PLL_CTL);
+ P0.L = lo(PLL_CTL);
+ w[p0] = R5;
+ IDLE;
+ call _test_pll_locked;
+
+ call _unset_sdram_srfs;
+
+ STI R4;
+
+ RETS = [SP++];
+ ( R7:0, P5:0 ) = [SP++];
+ RTS;
+
+ENTRY(_set_sdram_srfs)
+ /* set the sdram to self refresh mode */
+ P0.H = hi(EBIU_SDGCTL);
+ P0.L = lo(EBIU_SDGCTL);
+ R2 = [P0];
+ R3.H = hi(SRFS);
+ R3.L = lo(SRFS);
+ R2 = R2|R3;
+ [P0] = R2;
+ ssync;
+ RTS;
+
+ENTRY(_unset_sdram_srfs)
+ /* set the sdram out of self refresh mode */
+ P0.H = hi(EBIU_SDGCTL);
+ P0.L = lo(EBIU_SDGCTL);
+ R2 = [P0];
+ R3.H = hi(SRFS);
+ R3.L = lo(SRFS);
+ R3 = ~R3;
+ R2 = R2&R3;
+ [P0] = R2;
+ ssync;
+ RTS;
+
+ENTRY(_set_sic_iwr)
+ P0.H = hi(SIC_IWR);
+ P0.L = lo(SIC_IWR);
+ [P0] = R0;
+ SSYNC;
+ RTS;
+
+ENTRY(_set_rtc_istat)
+ P0.H = hi(RTC_ISTAT);
+ P0.L = lo(RTC_ISTAT);
+ w[P0] = R0.L;
+ SSYNC;
+ RTS;
+
+ENTRY(_test_pll_locked)
+ P0.H = hi(PLL_STAT);
+ P0.L = lo(PLL_STAT);
+1:
+ R0 = W[P0] (Z);
+ CC = BITTST(R0,5);
+ IF !CC JUMP 1b;
+ RTS;
+#endif
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
new file mode 100644
index 00000000000..8eb0a902348
--- /dev/null
+++ b/arch/blackfin/mach-common/entry.S
@@ -0,0 +1,1207 @@
+/*
+ * File: arch/blackfin/mach-common/entry.S
+ * Based on:
+ * Author: Linus Torvalds
+ *
+ * Created: ?
+ * Description: contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all
+ * interrupts and faults that can result in a task-switch.
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * 25-Dec-2004 - LG Soft India
+ * 1. Fix in return_from_int, to make sure any pending
+ * system call in ILAT for this process to get
+ * executed, otherwise in case context switch happens,
+ * system call of first process (i.e in ILAT) will be
+ * carried forward to the switched process.
+ * 2. Removed Constant references for the following
+ * a. IPEND
+ * b. EXCAUSE mask
+ * c. PAGE Mask
+ */
+
+/*
+ * NOTE: This code handles signal-recognition, which happens every time
+ * after a timer-interrupt and after each system call.
+ */
+
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/thread_info.h> /* TIF_NEED_RESCHED */
+#include <asm/asm-offsets.h>
+
+#include <asm/mach-common/context.S>
+
+#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
+ /*
+ * TODO: this should be proper save/restore, but for now
+ * we'll just cheat and use 0x1/0x13
+ */
+# define DEBUG_START_HWTRACE \
+ P5.l = LO(TBUFCTL); \
+ P5.h = HI(TBUFCTL); \
+ R7 = 0x13; \
+ [P5] = R7;
+# define DEBUG_STOP_HWTRACE \
+ P5.l = LO(TBUFCTL); \
+ P5.h = HI(TBUFCTL); \
+ R7 = 0x01; \
+ [P5] = R7;
+#else
+# define DEBUG_START_HWTRACE
+# define DEBUG_STOP_HWTRACE
+#endif
+
+#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
+.section .l1.text
+#else
+.text
+#endif
+
+/* Slightly simplified and streamlined entry point for CPLB misses.
+ * This one does not lower the level to IRQ5, and thus can be used to
+ * patch up CPLB misses on the kernel stack.
+ */
+ENTRY(_ex_dcplb)
+#if defined(ANOMALY_05000261)
+ /*
+ * Work around an anomaly: if we see a new DCPLB fault, return
+ * without doing anything. Then, if we get the same fault again,
+ * handle it.
+ */
+ p5.l = _last_cplb_fault_retx;
+ p5.h = _last_cplb_fault_retx;
+ r7 = [p5];
+ r6 = retx;
+ [p5] = r6;
+ cc = r6 == r7;
+ if !cc jump _return_from_exception;
+ /* fall through */
+#endif
+
+ENTRY(_ex_icplb)
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ SAVE_ALL_SYS
+ call __cplb_hdr;
+ DEBUG_START_HWTRACE
+ RESTORE_ALL_SYS
+ SP = RETN;
+ rtx;
+
+ENTRY(_ex_spinlock)
+ /* Transform this into a syscall - twiddle the syscall vector. */
+ p5.l = lo(EVT15);
+ p5.h = hi(EVT15);
+ r7.l = _spinlock_bh;
+ r7.h = _spinlock_bh;
+ [p5] = r7;
+ csync;
+ /* Fall through. */
+
+ENTRY(_ex_syscall)
+ DEBUG_START_HWTRACE
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ raise 15; /* invoked by TRAP #0, for sys call */
+ sp = retn;
+ rtx
+
+ENTRY(_spinlock_bh)
+ SAVE_ALL_SYS
+ /* To end up here, vector 15 was changed - so we have to change it
+ * back.
+ */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _evt_system_call;
+ p1.h = _evt_system_call;
+ [p0] = p1;
+ csync;
+ r0 = [sp + PT_R0];
+ sp += -12;
+ call _sys_bfin_spinlock;
+ sp += 12;
+ [SP + PT_R0] = R0;
+ RESTORE_ALL_SYS
+ rti;
+
+ENTRY(_ex_soft_bp)
+ r7 = retx;
+ r7 += -2;
+ retx = r7;
+ jump.s _ex_trap_c;
+
+ENTRY(_ex_single_step)
+ r7 = retx;
+ r6 = reti;
+ cc = r7 == r6;
+ if cc jump _return_from_exception
+ r7 = syscfg;
+ bitclr (r7, 0);
+ syscfg = R7;
+
+ p5.l = lo(IPEND);
+ p5.h = hi(IPEND);
+ r6 = [p5];
+ cc = bittst(r6, 5);
+ if !cc jump _ex_trap_c;
+ p4.l = lo(EVT5);
+ p4.h = hi(EVT5);
+ r6.h = _exception_to_level5;
+ r6.l = _exception_to_level5;
+ r7 = [p4];
+ cc = r6 == r7;
+ if !cc jump _ex_trap_c;
+
+_return_from_exception:
+ DEBUG_START_HWTRACE
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ sp = retn;
+ rtx;
+
+ENTRY(_handle_bad_cplb)
+ /* To get here, we just tried and failed to change a CPLB
+ * so, handle things in trap_c (C code), by lowering to
+ * IRQ5, just like we normally do. Since this is not a
+ * "normal" return path, we have a do alot of stuff to
+ * the stack to get ready so, we can fall through - we
+ * need to make a CPLB exception look like a normal exception
+ */
+
+ DEBUG_START_HWTRACE
+ RESTORE_ALL_SYS
+ [--sp] = ASTAT;
+ [--sp] = (R7:6, P5:4);
+
+ENTRY(_ex_trap_c)
+ /* Call C code (trap_c) to handle the exception, which most
+ * likely involves sending a signal to the current process.
+ * To avoid double faults, lower our priority to IRQ5 first.
+ */
+ P5.h = _exception_to_level5;
+ P5.l = _exception_to_level5;
+ p4.l = lo(EVT5);
+ p4.h = hi(EVT5);
+ [p4] = p5;
+ csync;
+
+ /* Disable all interrupts, but make sure level 5 is enabled so
+ * we can switch to that level. Save the old mask. */
+ cli r6;
+ p4.l = _excpt_saved_imask;
+ p4.h = _excpt_saved_imask;
+ [p4] = r6;
+ r6 = 0x3f;
+ sti r6;
+
+ /* Save the excause into a circular buffer, in case the instruction
+ * which caused this excecptions causes others.
+ */
+ P5.l = _in_ptr_excause;
+ P5.h = _in_ptr_excause;
+ R7 = [P5];
+ R7 += 4;
+ R6 = 0xF;
+ R7 = R7 & R6;
+ [P5] = R7;
+ R6.l = _excause_circ_buf;
+ R6.h = _excause_circ_buf;
+ R7 = R7 + R6;
+ p5 = R7;
+ R6 = SEQSTAT;
+ [P5] = R6;
+
+ DEBUG_START_HWTRACE
+ (R7:6,P5:4) = [sp++];
+ ASTAT = [sp++];
+ SP = RETN;
+ raise 5;
+ rtx;
+
+ENTRY(_exception_to_level5)
+ SAVE_ALL_SYS
+
+ /* Restore interrupt mask. We haven't pushed RETI, so this
+ * doesn't enable interrupts until we return from this handler. */
+ p4.l = _excpt_saved_imask;
+ p4.h = _excpt_saved_imask;
+ r6 = [p4];
+ sti r6;
+
+ /* Restore the hardware error vector. */
+ P5.h = _evt_ivhw;
+ P5.l = _evt_ivhw;
+ p4.l = lo(EVT5);
+ p4.h = hi(EVT5);
+ [p4] = p5;
+ csync;
+
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+ csync;
+ r0 = [p2]; /* Read current IPEND */
+ [sp + PT_IPEND] = r0; /* Store IPEND */
+
+ /* Pop the excause from the circular buffer and push it on the stack
+ * (in the right place - if you change the location of SEQSTAT, you
+ * must change this offset.
+ */
+.L_excep_to_5_again:
+ P5.l = _out_ptr_excause;
+ P5.h = _out_ptr_excause;
+ R7 = [P5];
+ R7 += 4;
+ R6 = 0xF;
+ R7 = R7 & R6;
+ [P5] = R7;
+ R6.l = _excause_circ_buf;
+ R6.h = _excause_circ_buf;
+ R7 = R7 + R6;
+ P5 = R7;
+ R1 = [P5];
+ [SP + 8] = r1;
+
+ r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
+ SP += -12;
+ call _trap_c;
+ SP += 12;
+
+ /* See if anything else is in the exception buffer
+ * if there is, process it
+ */
+ P5.l = _out_ptr_excause;
+ P5.h = _out_ptr_excause;
+ P4.l = _in_ptr_excause;
+ P4.h = _in_ptr_excause;
+ R6 = [P5];
+ R7 = [P4];
+ CC = R6 == R7;
+ if ! CC JUMP .L_excep_to_5_again
+
+ call _ret_from_exception;
+ RESTORE_ALL_SYS
+ rti;
+
+ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
+ /* Since the kernel stack can be anywhere, it's not guaranteed to be
+ * covered by a CPLB. Switch to an exception stack; use RETN as a
+ * scratch register (for want of a better option).
+ */
+ retn = sp;
+ sp.l = _exception_stack_top;
+ sp.h = _exception_stack_top;
+ /* Try to deal with syscalls quickly. */
+ [--sp] = ASTAT;
+ [--sp] = (R7:6, P5:4);
+ DEBUG_STOP_HWTRACE
+ r7 = SEQSTAT; /* reason code is in bit 5:0 */
+ r6.l = lo(SEQSTAT_EXCAUSE);
+ r6.h = hi(SEQSTAT_EXCAUSE);
+ r7 = r7 & r6;
+ p5.h = _extable;
+ p5.l = _extable;
+ p4 = r7;
+ p5 = p5 + (p4 << 2);
+ p4 = [p5];
+ jump (p4);
+
+.Lbadsys:
+ r7 = -ENOSYS; /* signextending enough */
+ [sp + PT_R0] = r7; /* return value from system call */
+ jump .Lsyscall_really_exit;
+
+ENTRY(_kernel_execve)
+ link SIZEOF_PTREGS;
+ p0 = sp;
+ r3 = SIZEOF_PTREGS / 4;
+ r4 = 0(x);
+0:
+ [p0++] = r4;
+ r3 += -1;
+ cc = r3 == 0;
+ if !cc jump 0b (bp);
+
+ p0 = sp;
+ sp += -16;
+ [sp + 12] = p0;
+ call _do_execve;
+ SP += 16;
+ cc = r0 == 0;
+ if ! cc jump 1f;
+ /* Success. Copy our temporary pt_regs to the top of the kernel
+ * stack and do a normal exception return.
+ */
+ r1 = sp;
+ r0 = (-KERNEL_STACK_SIZE) (x);
+ r1 = r1 & r0;
+ p2 = r1;
+ p3 = [p2];
+ r0 = KERNEL_STACK_SIZE - 4 (z);
+ p1 = r0;
+ p1 = p1 + p2;
+
+ p0 = fp;
+ r4 = [p0--];
+ r3 = SIZEOF_PTREGS / 4;
+0:
+ r4 = [p0--];
+ [p1--] = r4;
+ r3 += -1;
+ cc = r3 == 0;
+ if ! cc jump 0b (bp);
+
+ r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);
+ p1 = r0;
+ p1 = p1 + p2;
+ sp = p1;
+ r0 = syscfg;
+ [SP + PT_SYSCFG] = r0;
+ [p3 + (TASK_THREAD + THREAD_KSP)] = sp;
+
+ RESTORE_CONTEXT;
+ rti;
+1:
+ unlink;
+ rts;
+
+ENTRY(_system_call)
+ /* Store IPEND */
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+ csync;
+ r0 = [p2];
+ [sp + PT_IPEND] = r0;
+
+ /* Store RETS for now */
+ r0 = rets;
+ [sp + PT_RESERVED] = r0;
+ /* Set the stack for the current process */
+ r7 = sp;
+ r6.l = lo(ALIGN_PAGE_MASK);
+ r6.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r6; /* thread_info */
+ p2 = r7;
+ p2 = [p2];
+
+ [p2+(TASK_THREAD+THREAD_KSP)] = sp;
+
+ /* Check the System Call */
+ r7 = __NR_syscall;
+ /* System call number is passed in P0 */
+ r6 = p0;
+ cc = r6 < r7;
+ if ! cc jump .Lbadsys;
+
+ /* are we tracing syscalls?*/
+ r7 = sp;
+ r6.l = lo(ALIGN_PAGE_MASK);
+ r6.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r6;
+ p2 = r7;
+ r7 = [p2+TI_FLAGS];
+ CC = BITTST(r7,TIF_SYSCALL_TRACE);
+ if CC JUMP _sys_trace;
+
+ /* Execute the appropriate system call */
+
+ p4 = p0;
+ p5.l = _sys_call_table;
+ p5.h = _sys_call_table;
+ p5 = p5 + (p4 << 2);
+ r0 = [sp + PT_R0];
+ r1 = [sp + PT_R1];
+ r2 = [sp + PT_R2];
+ p5 = [p5];
+
+ [--sp] = r5;
+ [--sp] = r4;
+ [--sp] = r3;
+ SP += -12;
+ call (p5);
+ SP += 24;
+ [sp + PT_R0] = r0;
+
+.Lresume_userspace:
+ r7 = sp;
+ r4.l = lo(ALIGN_PAGE_MASK);
+ r4.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r4; /* thread_info->flags */
+ p5 = r7;
+.Lresume_userspace_1:
+ /* Disable interrupts. */
+ [--sp] = reti;
+ reti = [sp++];
+
+ r7 = [p5 + TI_FLAGS];
+ r4.l = lo(_TIF_WORK_MASK);
+ r4.h = hi(_TIF_WORK_MASK);
+ r7 = r7 & r4;
+
+.Lsyscall_resched:
+ cc = BITTST(r7, TIF_NEED_RESCHED);
+ if !cc jump .Lsyscall_sigpending;
+
+ /* Reenable interrupts. */
+ [--sp] = reti;
+ r0 = [sp++];
+
+ SP += -12;
+ call _schedule;
+ SP += 12;
+
+ jump .Lresume_userspace_1;
+
+.Lsyscall_sigpending:
+ cc = BITTST(r7, TIF_RESTORE_SIGMASK);
+ if cc jump .Lsyscall_do_signals;
+ cc = BITTST(r7, TIF_SIGPENDING);
+ if !cc jump .Lsyscall_really_exit;
+.Lsyscall_do_signals:
+ /* Reenable interrupts. */
+ [--sp] = reti;
+ r0 = [sp++];
+
+ r0 = sp;
+ SP += -12;
+ call _do_signal;
+ SP += 12;
+
+.Lsyscall_really_exit:
+ r5 = [sp + PT_RESERVED];
+ rets = r5;
+ rts;
+
+_sys_trace:
+ call _syscall_trace;
+
+ /* Execute the appropriate system call */
+
+ p4 = [SP + PT_P0];
+ p5.l = _sys_call_table;
+ p5.h = _sys_call_table;
+ p5 = p5 + (p4 << 2);
+ r0 = [sp + PT_R0];
+ r1 = [sp + PT_R1];
+ r2 = [sp + PT_R2];
+ r3 = [sp + PT_R3];
+ r4 = [sp + PT_R4];
+ r5 = [sp + PT_R5];
+ p5 = [p5];
+
+ [--sp] = r5;
+ [--sp] = r4;
+ [--sp] = r3;
+ SP += -12;
+ call (p5);
+ SP += 24;
+ [sp + PT_R0] = r0;
+
+ call _syscall_trace;
+ jump .Lresume_userspace;
+
+ENTRY(_resume)
+ /*
+ * Beware - when entering resume, prev (the current task) is
+ * in r0, next (the new task) is in r1.
+ */
+ p0 = r0;
+ p1 = r1;
+ [--sp] = rets;
+ [--sp] = fp;
+ [--sp] = (r7:4, p5:3);
+
+ /* save usp */
+ p2 = usp;
+ [p0+(TASK_THREAD+THREAD_USP)] = p2;
+
+ /* save current kernel stack pointer */
+ [p0+(TASK_THREAD+THREAD_KSP)] = sp;
+
+ /* save program counter */
+ r1.l = _new_old_task;
+ r1.h = _new_old_task;
+ [p0+(TASK_THREAD+THREAD_PC)] = r1;
+
+ /* restore the kernel stack pointer */
+ sp = [p1+(TASK_THREAD+THREAD_KSP)];
+
+ /* restore user stack pointer */
+ p0 = [p1+(TASK_THREAD+THREAD_USP)];
+ usp = p0;
+
+ /* restore pc */
+ p0 = [p1+(TASK_THREAD+THREAD_PC)];
+ jump (p0);
+
+ /*
+ * Following code actually lands up in a new (old) task.
+ */
+
+_new_old_task:
+ (r7:4, p5:3) = [sp++];
+ fp = [sp++];
+ rets = [sp++];
+
+ /*
+ * When we come out of resume, r0 carries "old" task, becuase we are
+ * in "new" task.
+ */
+ rts;
+
+ENTRY(_ret_from_exception)
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+
+ csync;
+ r0 = [p2];
+ [sp + PT_IPEND] = r0;
+
+1:
+ r1 = 0x37(Z);
+ r2 = ~r1;
+ r2.h = 0;
+ r0 = r2 & r0;
+ cc = r0 == 0;
+ if !cc jump 4f; /* if not return to user mode, get out */
+
+ /* Make sure any pending system call or deferred exception
+ * return in ILAT for this process to get executed, otherwise
+ * in case context switch happens, system call of
+ * first process (i.e in ILAT) will be carried
+ * forward to the switched process
+ */
+
+ p2.l = lo(ILAT);
+ p2.h = hi(ILAT);
+ r0 = [p2];
+ r1 = (EVT_IVG14 | EVT_IVG15) (z);
+ r0 = r0 & r1;
+ cc = r0 == 0;
+ if !cc jump 5f;
+
+ /* Set the stack for the current process */
+ r7 = sp;
+ r4.l = lo(ALIGN_PAGE_MASK);
+ r4.h = hi(ALIGN_PAGE_MASK);
+ r7 = r7 & r4; /* thread_info->flags */
+ p5 = r7;
+ r7 = [p5 + TI_FLAGS];
+ r4.l = lo(_TIF_WORK_MASK);
+ r4.h = hi(_TIF_WORK_MASK);
+ r7 = r7 & r4;
+ cc = r7 == 0;
+ if cc jump 4f;
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _schedule_and_signal;
+ p1.h = _schedule_and_signal;
+ [p0] = p1;
+ csync;
+ raise 15; /* raise evt14 to do signal or reschedule */
+4:
+ r0 = syscfg;
+ bitclr(r0, 0);
+ syscfg = r0;
+5:
+ rts;
+
+ENTRY(_return_from_int)
+ /* If someone else already raised IRQ 15, do nothing. */
+ csync;
+ p2.l = lo(ILAT);
+ p2.h = hi(ILAT);
+ r0 = [p2];
+ cc = bittst (r0, EVT_IVG15_P);
+ if cc jump 2f;
+
+ /* if not return to user mode, get out */
+ p2.l = lo(IPEND);
+ p2.h = hi(IPEND);
+ r0 = [p2];
+ r1 = 0x17(Z);
+ r2 = ~r1;
+ r2.h = 0;
+ r0 = r2 & r0;
+ r1 = 1;
+ r1 = r0 - r1;
+ r2 = r0 & r1;
+ cc = r2 == 0;
+ if !cc jump 2f;
+
+ /* Lower the interrupt level to 15. */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _schedule_and_signal_from_int;
+ p1.h = _schedule_and_signal_from_int;
+ [p0] = p1;
+ csync;
+#if defined(ANOMALY_05000281)
+ r0.l = lo(CONFIG_BOOT_LOAD);
+ r0.h = hi(CONFIG_BOOT_LOAD);
+ reti = r0;
+#endif
+ r0 = 0x801f (z);
+ STI r0;
+ raise 15; /* raise evt15 to do signal or reschedule */
+ rti;
+2:
+ rts;
+
+ENTRY(_lower_to_irq14)
+#if defined(ANOMALY_05000281)
+ r0.l = lo(CONFIG_BOOT_LOAD);
+ r0.h = hi(CONFIG_BOOT_LOAD);
+ reti = r0;
+#endif
+ r0 = 0x401f;
+ sti r0;
+ raise 14;
+ rti;
+ENTRY(_evt14_softirq)
+#ifdef CONFIG_DEBUG_HWERR
+ r0 = 0x3f;
+ sti r0;
+#else
+ cli r0;
+#endif
+ [--sp] = RETI;
+ SP += 4;
+ rts;
+
+_schedule_and_signal_from_int:
+ /* To end up here, vector 15 was changed - so we have to change it
+ * back.
+ */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _evt_system_call;
+ p1.h = _evt_system_call;
+ [p0] = p1;
+ csync;
+ p1 = rets;
+ [sp + PT_RESERVED] = p1;
+
+ p0.l = _irq_flags;
+ p0.h = _irq_flags;
+ r0 = [p0];
+ sti r0;
+
+ jump.s .Lresume_userspace;
+
+_schedule_and_signal:
+ SAVE_CONTEXT_SYSCALL
+ /* To end up here, vector 15 was changed - so we have to change it
+ * back.
+ */
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _evt_system_call;
+ p1.h = _evt_system_call;
+ [p0] = p1;
+ csync;
+ p0.l = 1f;
+ p0.h = 1f;
+ [sp + PT_RESERVED] = P0;
+ call .Lresume_userspace;
+1:
+ RESTORE_CONTEXT
+ rti;
+
+/* Make sure when we start, that the circular buffer is initialized properly
+ * R0 and P0 are call clobbered, so we can use them here.
+ */
+ENTRY(_init_exception_buff)
+ r0 = 0;
+ p0.h = _in_ptr_excause;
+ p0.l = _in_ptr_excause;
+ [p0] = r0;
+ p0.h = _out_ptr_excause;
+ p0.l = _out_ptr_excause;
+ [p0] = r0;
+ rts;
+
+/*
+ * Put these in the kernel data section - that should always be covered by
+ * a CPLB. This is needed to ensure we don't get double fault conditions
+ */
+
+#ifdef CONFIG_SYSCALL_TAB_L1
+.section .l1.data
+#else
+.data
+#endif
+ALIGN
+_extable:
+ /* entry for each EXCAUSE[5:0]
+ * This table bmust be in sync with the table in ./kernel/traps.c
+ * EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined
+ */
+ .long _ex_syscall; /* 0x00 - User Defined - Linux Syscall */
+ .long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */
+ .long _ex_trap_c /* 0x02 - User Defined */
+ .long _ex_trap_c /* 0x03 - User Defined - Atomic test and set service */
+ .long _ex_spinlock /* 0x04 - User Defined */
+ .long _ex_trap_c /* 0x05 - User Defined */
+ .long _ex_trap_c /* 0x06 - User Defined */
+ .long _ex_trap_c /* 0x07 - User Defined */
+ .long _ex_trap_c /* 0x08 - User Defined */
+ .long _ex_trap_c /* 0x09 - User Defined */
+ .long _ex_trap_c /* 0x0A - User Defined */
+ .long _ex_trap_c /* 0x0B - User Defined */
+ .long _ex_trap_c /* 0x0C - User Defined */
+ .long _ex_trap_c /* 0x0D - User Defined */
+ .long _ex_trap_c /* 0x0E - User Defined */
+ .long _ex_trap_c /* 0x0F - User Defined */
+ .long _ex_single_step /* 0x10 - HW Single step */
+ .long _ex_trap_c /* 0x11 - Trace Buffer Full */
+ .long _ex_trap_c /* 0x12 - Reserved */
+ .long _ex_trap_c /* 0x13 - Reserved */
+ .long _ex_trap_c /* 0x14 - Reserved */
+ .long _ex_trap_c /* 0x15 - Reserved */
+ .long _ex_trap_c /* 0x16 - Reserved */
+ .long _ex_trap_c /* 0x17 - Reserved */
+ .long _ex_trap_c /* 0x18 - Reserved */
+ .long _ex_trap_c /* 0x19 - Reserved */
+ .long _ex_trap_c /* 0x1A - Reserved */
+ .long _ex_trap_c /* 0x1B - Reserved */
+ .long _ex_trap_c /* 0x1C - Reserved */
+ .long _ex_trap_c /* 0x1D - Reserved */
+ .long _ex_trap_c /* 0x1E - Reserved */
+ .long _ex_trap_c /* 0x1F - Reserved */
+ .long _ex_trap_c /* 0x20 - Reserved */
+ .long _ex_trap_c /* 0x21 - Undefined Instruction */
+ .long _ex_trap_c /* 0x22 - Illegal Instruction Combination */
+ .long _ex_dcplb /* 0x23 - Data CPLB Protection Violation */
+ .long _ex_trap_c /* 0x24 - Data access misaligned */
+ .long _ex_trap_c /* 0x25 - Unrecoverable Event */
+ .long _ex_dcplb /* 0x26 - Data CPLB Miss */
+ .long _ex_trap_c /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero */
+ .long _ex_trap_c /* 0x28 - Emulation Watchpoint */
+ .long _ex_trap_c /* 0x29 - Instruction fetch access error (535 only) */
+ .long _ex_trap_c /* 0x2A - Instruction fetch misaligned */
+ .long _ex_icplb /* 0x2B - Instruction CPLB protection Violation */
+ .long _ex_icplb /* 0x2C - Instruction CPLB miss */
+ .long _ex_trap_c /* 0x2D - Instruction CPLB Multiple Hits */
+ .long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */
+ .long _ex_trap_c /* 0x2E - Illegal use of Supervisor Resource */
+ .long _ex_trap_c /* 0x2F - Reserved */
+ .long _ex_trap_c /* 0x30 - Reserved */
+ .long _ex_trap_c /* 0x31 - Reserved */
+ .long _ex_trap_c /* 0x32 - Reserved */
+ .long _ex_trap_c /* 0x33 - Reserved */
+ .long _ex_trap_c /* 0x34 - Reserved */
+ .long _ex_trap_c /* 0x35 - Reserved */
+ .long _ex_trap_c /* 0x36 - Reserved */
+ .long _ex_trap_c /* 0x37 - Reserved */
+ .long _ex_trap_c /* 0x38 - Reserved */
+ .long _ex_trap_c /* 0x39 - Reserved */
+ .long _ex_trap_c /* 0x3A - Reserved */
+ .long _ex_trap_c /* 0x3B - Reserved */
+ .long _ex_trap_c /* 0x3C - Reserved */
+ .long _ex_trap_c /* 0x3D - Reserved */
+ .long _ex_trap_c /* 0x3E - Reserved */
+ .long _ex_trap_c /* 0x3F - Reserved */
+
+ALIGN
+ENTRY(_sys_call_table)
+ .long _sys_ni_syscall /* 0 - old "setup()" system call*/
+ .long _sys_exit
+ .long _sys_fork
+ .long _sys_read
+ .long _sys_write
+ .long _sys_open /* 5 */
+ .long _sys_close
+ .long _sys_ni_syscall /* old waitpid */
+ .long _sys_creat
+ .long _sys_link
+ .long _sys_unlink /* 10 */
+ .long _sys_execve
+ .long _sys_chdir
+ .long _sys_time
+ .long _sys_mknod
+ .long _sys_chmod /* 15 */
+ .long _sys_chown /* chown16 */
+ .long _sys_ni_syscall /* old break syscall holder */
+ .long _sys_ni_syscall /* old stat */
+ .long _sys_lseek
+ .long _sys_getpid /* 20 */
+ .long _sys_mount
+ .long _sys_ni_syscall /* old umount */
+ .long _sys_setuid
+ .long _sys_getuid
+ .long _sys_stime /* 25 */
+ .long _sys_ptrace
+ .long _sys_alarm
+ .long _sys_ni_syscall /* old fstat */
+ .long _sys_pause
+ .long _sys_ni_syscall /* old utime */ /* 30 */
+ .long _sys_ni_syscall /* old stty syscall holder */
+ .long _sys_ni_syscall /* old gtty syscall holder */
+ .long _sys_access
+ .long _sys_nice
+ .long _sys_ni_syscall /* 35 */ /* old ftime syscall holder */
+ .long _sys_sync
+ .long _sys_kill
+ .long _sys_rename
+ .long _sys_mkdir
+ .long _sys_rmdir /* 40 */
+ .long _sys_dup
+ .long _sys_pipe
+ .long _sys_times
+ .long _sys_ni_syscall /* old prof syscall holder */
+ .long _sys_brk /* 45 */
+ .long _sys_setgid
+ .long _sys_getgid
+ .long _sys_ni_syscall /* old sys_signal */
+ .long _sys_geteuid /* geteuid16 */
+ .long _sys_getegid /* getegid16 */ /* 50 */
+ .long _sys_acct
+ .long _sys_umount /* recycled never used phys() */
+ .long _sys_ni_syscall /* old lock syscall holder */
+ .long _sys_ioctl
+ .long _sys_fcntl /* 55 */
+ .long _sys_ni_syscall /* old mpx syscall holder */
+ .long _sys_setpgid
+ .long _sys_ni_syscall /* old ulimit syscall holder */
+ .long _sys_ni_syscall /* old old uname */
+ .long _sys_umask /* 60 */
+ .long _sys_chroot
+ .long _sys_ustat
+ .long _sys_dup2
+ .long _sys_getppid
+ .long _sys_getpgrp /* 65 */
+ .long _sys_setsid
+ .long _sys_ni_syscall /* old sys_sigaction */
+ .long _sys_sgetmask
+ .long _sys_ssetmask
+ .long _sys_setreuid /* setreuid16 */ /* 70 */
+ .long _sys_setregid /* setregid16 */
+ .long _sys_ni_syscall /* old sys_sigsuspend */
+ .long _sys_ni_syscall /* old sys_sigpending */
+ .long _sys_sethostname
+ .long _sys_setrlimit /* 75 */
+ .long _sys_ni_syscall /* old getrlimit */
+ .long _sys_getrusage
+ .long _sys_gettimeofday
+ .long _sys_settimeofday
+ .long _sys_getgroups /* getgroups16 */ /* 80 */
+ .long _sys_setgroups /* setgroups16 */
+ .long _sys_ni_syscall /* old_select */
+ .long _sys_symlink
+ .long _sys_ni_syscall /* old lstat */
+ .long _sys_readlink /* 85 */
+ .long _sys_uselib
+ .long _sys_ni_syscall /* sys_swapon */
+ .long _sys_reboot
+ .long _sys_ni_syscall /* old_readdir */
+ .long _sys_ni_syscall /* sys_mmap */ /* 90 */
+ .long _sys_munmap
+ .long _sys_truncate
+ .long _sys_ftruncate
+ .long _sys_fchmod
+ .long _sys_fchown /* fchown16 */ /* 95 */
+ .long _sys_getpriority
+ .long _sys_setpriority
+ .long _sys_ni_syscall /* old profil syscall holder */
+ .long _sys_statfs
+ .long _sys_fstatfs /* 100 */
+ .long _sys_ni_syscall
+ .long _sys_ni_syscall /* old sys_socketcall */
+ .long _sys_syslog
+ .long _sys_setitimer
+ .long _sys_getitimer /* 105 */
+ .long _sys_newstat
+ .long _sys_newlstat
+ .long _sys_newfstat
+ .long _sys_ni_syscall /* old uname */
+ .long _sys_ni_syscall /* iopl for i386 */ /* 110 */
+ .long _sys_vhangup
+ .long _sys_ni_syscall /* obsolete idle() syscall */
+ .long _sys_ni_syscall /* vm86old for i386 */
+ .long _sys_wait4
+ .long _sys_ni_syscall /* 115 */ /* sys_swapoff */
+ .long _sys_sysinfo
+ .long _sys_ni_syscall /* old sys_ipc */
+ .long _sys_fsync
+ .long _sys_ni_syscall /* old sys_sigreturn */
+ .long _sys_clone /* 120 */
+ .long _sys_setdomainname
+ .long _sys_newuname
+ .long _sys_ni_syscall /* old sys_modify_ldt */
+ .long _sys_adjtimex
+ .long _sys_ni_syscall /* 125 */ /* sys_mprotect */
+ .long _sys_ni_syscall /* old sys_sigprocmask */
+ .long _sys_ni_syscall /* old "creat_module" */
+ .long _sys_init_module
+ .long _sys_delete_module
+ .long _sys_ni_syscall /* 130: old "get_kernel_syms" */
+ .long _sys_quotactl
+ .long _sys_getpgid
+ .long _sys_fchdir
+ .long _sys_bdflush
+ .long _sys_ni_syscall /* 135 */ /* sys_sysfs */
+ .long _sys_personality
+ .long _sys_ni_syscall /* for afs_syscall */
+ .long _sys_setfsuid /* setfsuid16 */
+ .long _sys_setfsgid /* setfsgid16 */
+ .long _sys_llseek /* 140 */
+ .long _sys_getdents
+ .long _sys_ni_syscall /* sys_select */
+ .long _sys_flock
+ .long _sys_ni_syscall /* sys_msync */
+ .long _sys_readv /* 145 */
+ .long _sys_writev
+ .long _sys_getsid
+ .long _sys_fdatasync
+ .long _sys_sysctl
+ .long _sys_ni_syscall /* 150 */ /* sys_mlock */
+ .long _sys_ni_syscall /* sys_munlock */
+ .long _sys_ni_syscall /* sys_mlockall */
+ .long _sys_ni_syscall /* sys_munlockall */
+ .long _sys_sched_setparam
+ .long _sys_sched_getparam /* 155 */
+ .long _sys_sched_setscheduler
+ .long _sys_sched_getscheduler
+ .long _sys_sched_yield
+ .long _sys_sched_get_priority_max
+ .long _sys_sched_get_priority_min /* 160 */
+ .long _sys_sched_rr_get_interval
+ .long _sys_nanosleep
+ .long _sys_ni_syscall /* sys_mremap */
+ .long _sys_setresuid /* setresuid16 */
+ .long _sys_getresuid /* getresuid16 */ /* 165 */
+ .long _sys_ni_syscall /* for vm86 */
+ .long _sys_ni_syscall /* old "query_module" */
+ .long _sys_ni_syscall /* sys_poll */
+ .long _sys_ni_syscall /* sys_nfsservctl */
+ .long _sys_setresgid /* setresgid16 */ /* 170 */
+ .long _sys_getresgid /* getresgid16 */
+ .long _sys_prctl
+ .long _sys_rt_sigreturn
+ .long _sys_rt_sigaction
+ .long _sys_rt_sigprocmask /* 175 */
+ .long _sys_rt_sigpending
+ .long _sys_rt_sigtimedwait
+ .long _sys_rt_sigqueueinfo
+ .long _sys_rt_sigsuspend
+ .long _sys_pread64 /* 180 */
+ .long _sys_pwrite64
+ .long _sys_lchown /* lchown16 */
+ .long _sys_getcwd
+ .long _sys_capget
+ .long _sys_capset /* 185 */
+ .long _sys_sigaltstack
+ .long _sys_sendfile
+ .long _sys_ni_syscall /* streams1 */
+ .long _sys_ni_syscall /* streams2 */
+ .long _sys_vfork /* 190 */
+ .long _sys_getrlimit
+ .long _sys_mmap2
+ .long _sys_truncate64
+ .long _sys_ftruncate64
+ .long _sys_stat64 /* 195 */
+ .long _sys_lstat64
+ .long _sys_fstat64
+ .long _sys_chown
+ .long _sys_getuid
+ .long _sys_getgid /* 200 */
+ .long _sys_geteuid
+ .long _sys_getegid
+ .long _sys_setreuid
+ .long _sys_setregid
+ .long _sys_getgroups /* 205 */
+ .long _sys_setgroups
+ .long _sys_fchown
+ .long _sys_setresuid
+ .long _sys_getresuid
+ .long _sys_setresgid /* 210 */
+ .long _sys_getresgid
+ .long _sys_lchown
+ .long _sys_setuid
+ .long _sys_setgid
+ .long _sys_setfsuid /* 215 */
+ .long _sys_setfsgid
+ .long _sys_pivot_root
+ .long _sys_ni_syscall /* sys_mincore */
+ .long _sys_ni_syscall /* sys_madvise */
+ .long _sys_getdents64 /* 220 */
+ .long _sys_fcntl64
+ .long _sys_ni_syscall /* reserved for TUX */
+ .long _sys_ni_syscall
+ .long _sys_gettid
+ .long _sys_ni_syscall /* 225 */ /* sys_readahead */
+ .long _sys_setxattr
+ .long _sys_lsetxattr
+ .long _sys_fsetxattr
+ .long _sys_getxattr
+ .long _sys_lgetxattr /* 230 */
+ .long _sys_fgetxattr
+ .long _sys_listxattr
+ .long _sys_llistxattr
+ .long _sys_flistxattr
+ .long _sys_removexattr /* 235 */
+ .long _sys_lremovexattr
+ .long _sys_fremovexattr
+ .long _sys_tkill
+ .long _sys_sendfile64
+ .long _sys_futex /* 240 */
+ .long _sys_sched_setaffinity
+ .long _sys_sched_getaffinity
+ .long _sys_ni_syscall /* sys_set_thread_area */
+ .long _sys_ni_syscall /* sys_get_thread_area */
+ .long _sys_io_setup /* 245 */
+ .long _sys_io_destroy
+ .long _sys_io_getevents
+ .long _sys_io_submit
+ .long _sys_io_cancel
+ .long _sys_ni_syscall /* 250 */ /* sys_alloc_hugepages */
+ .long _sys_ni_syscall /* sys_freec_hugepages */
+ .long _sys_exit_group
+ .long _sys_lookup_dcookie
+ .long _sys_bfin_spinlock
+ .long _sys_epoll_create /* 255 */
+ .long _sys_epoll_ctl
+ .long _sys_epoll_wait
+ .long _sys_ni_syscall /* remap_file_pages */
+ .long _sys_set_tid_address
+ .long _sys_timer_create /* 260 */
+ .long _sys_timer_settime
+ .long _sys_timer_gettime
+ .long _sys_timer_getoverrun
+ .long _sys_timer_delete
+ .long _sys_clock_settime /* 265 */
+ .long _sys_clock_gettime
+ .long _sys_clock_getres
+ .long _sys_clock_nanosleep
+ .long _sys_statfs64
+ .long _sys_fstatfs64 /* 270 */
+ .long _sys_tgkill
+ .long _sys_utimes
+ .long _sys_fadvise64_64
+ .long _sys_ni_syscall /* vserver */
+ .long _sys_ni_syscall /* 275, mbind */
+ .long _sys_ni_syscall /* get_mempolicy */
+ .long _sys_ni_syscall /* set_mempolicy */
+ .long _sys_mq_open
+ .long _sys_mq_unlink
+ .long _sys_mq_timedsend /* 280 */
+ .long _sys_mq_timedreceive
+ .long _sys_mq_notify
+ .long _sys_mq_getsetattr
+ .long _sys_ni_syscall /* kexec_load */
+ .long _sys_waitid /* 285 */
+ .long _sys_add_key
+ .long _sys_request_key
+ .long _sys_keyctl
+ .long _sys_ioprio_set
+ .long _sys_ioprio_get /* 290 */
+ .long _sys_inotify_init
+ .long _sys_inotify_add_watch
+ .long _sys_inotify_rm_watch
+ .long _sys_ni_syscall /* migrate_pages */
+ .long _sys_openat /* 295 */
+ .long _sys_mkdirat
+ .long _sys_mknodat
+ .long _sys_fchownat
+ .long _sys_futimesat
+ .long _sys_fstatat64 /* 300 */
+ .long _sys_unlinkat
+ .long _sys_renameat
+ .long _sys_linkat
+ .long _sys_symlinkat
+ .long _sys_readlinkat /* 305 */
+ .long _sys_fchmodat
+ .long _sys_faccessat
+ .long _sys_pselect6
+ .long _sys_ppoll
+ .long _sys_unshare /* 310 */
+ .long _sys_sram_alloc
+ .long _sys_sram_free
+ .long _sys_dma_memcpy
+ .long _sys_accept
+ .long _sys_bind /* 315 */
+ .long _sys_connect
+ .long _sys_getpeername
+ .long _sys_getsockname
+ .long _sys_getsockopt
+ .long _sys_listen /* 320 */
+ .long _sys_recv
+ .long _sys_recvfrom
+ .long _sys_recvmsg
+ .long _sys_send
+ .long _sys_sendmsg /* 325 */
+ .long _sys_sendto
+ .long _sys_setsockopt
+ .long _sys_shutdown
+ .long _sys_socket
+ .long _sys_socketpair /* 330 */
+ .long _sys_semctl
+ .long _sys_semget
+ .long _sys_semop
+ .long _sys_msgctl
+ .long _sys_msgget /* 335 */
+ .long _sys_msgrcv
+ .long _sys_msgsnd
+ .long _sys_shmat
+ .long _sys_shmctl
+ .long _sys_shmdt /* 340 */
+ .long _sys_shmget
+ .rept NR_syscalls-(.-_sys_call_table)/4
+ .long _sys_ni_syscall
+ .endr
+_excpt_saved_imask:
+ .long 0;
+
+_exception_stack:
+ .rept 1024
+ .long 0;
+ .endr
+_exception_stack_top:
+
+#if defined(ANOMALY_05000261)
+/* Used by the assembly entry point to work around an anomaly. */
+_last_cplb_fault_retx:
+ .long 0;
+#endif
+/*
+ * Single instructions can have multiple faults, which need to be
+ * handled by traps.c, in irq5. We store the exception cause to ensure
+ * we don't miss a double fault condition
+ */
+ENTRY(_in_ptr_excause)
+ .long 0;
+ENTRY(_out_ptr_excause)
+ .long 0;
+ALIGN
+ENTRY(_excause_circ_buf)
+ .rept 4
+ .long 0
+ .endr
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
new file mode 100644
index 00000000000..dd45664f0d0
--- /dev/null
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -0,0 +1,253 @@
+/*
+ * File: arch/blackfin/mach-common/interrupt.S
+ * Based on:
+ * Author: D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
+ * Kenneth Albanowski <kjahds@kjahds.com>
+ *
+ * Created: ?
+ * Description: Interrupt Entries
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <asm/blackfin.h>
+#include <asm/mach/irq.h>
+#include <linux/autoconf.h>
+#include <linux/linkage.h>
+#include <asm/entry.h>
+#include <asm/asm-offsets.h>
+
+#include <asm/mach-common/context.S>
+
+#ifdef CONFIG_I_ENTRY_L1
+.section .l1.text
+#else
+.text
+#endif
+
+.align 4 /* just in case */
+
+/*
+ * initial interrupt handlers
+ */
+
+#ifndef CONFIG_KGDB
+ /* interrupt routine for emulation - 0 */
+ /* Currently used only if GDB stub is not in - invalid */
+ /* gdb-stub set the evt itself */
+ /* save registers for post-mortem only */
+ENTRY(_evt_emulation)
+ SAVE_ALL_SYS
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+ r0 = IRQ_EMU;
+ r1 = sp;
+ SP += -12;
+ call _irq_panic;
+ SP += 12;
+ /* - GDB stub fills this in by itself (if defined) */
+ rte;
+#endif
+
+/* Common interrupt entry code. First we do CLI, then push
+ * RETI, to keep interrupts disabled, but to allow this state to be changed
+ * by local_bh_enable.
+ * R0 contains the interrupt number, while R1 may contain the value of IPEND,
+ * or garbage if IPEND won't be needed by the ISR. */
+__common_int_entry:
+ [--sp] = fp;
+ [--sp] = usp;
+
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = a0.x;
+ [--sp] = a0.w;
+ [--sp] = a1.x;
+ [--sp] = a1.w;
+
+ [--sp] = LC0;
+ [--sp] = LC1;
+ [--sp] = LT0;
+ [--sp] = LT1;
+ [--sp] = LB0;
+ [--sp] = LB1;
+
+ [--sp] = ASTAT;
+
+ [--sp] = r0; /* Skip reserved */
+ [--sp] = RETS;
+ r2 = RETI;
+ [--sp] = r2;
+ [--sp] = RETX;
+ [--sp] = RETN;
+ [--sp] = RETE;
+ [--sp] = SEQSTAT;
+ [--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */
+
+ /* Switch to other method of keeping interrupts disabled. */
+#ifdef CONFIG_DEBUG_HWERR
+ r1 = 0x3f;
+ sti r1;
+#else
+ cli r1;
+#endif
+ [--sp] = RETI; /* orig_pc */
+ /* Clear all L registers. */
+ r1 = 0 (x);
+ l0 = r1;
+ l1 = r1;
+ l2 = r1;
+ l3 = r1;
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+
+#ifdef ANOMALY_05000283
+ cc = r7 == r7;
+ p5.h = 0xffc0;
+ p5.l = 0x0014;
+ if cc jump 1f;
+ r7.l = W[p5];
+1:
+#endif
+ r1 = sp;
+ SP += -12;
+ call _do_irq;
+ SP += 12;
+ call _return_from_int;
+.Lcommon_restore_context:
+ RESTORE_CONTEXT
+ rti;
+
+/* interrupt routine for ivhw - 5 */
+ENTRY(_evt_ivhw)
+ SAVE_CONTEXT
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+#ifdef ANOMALY_05000283
+ cc = r7 == r7;
+ p5.h = 0xffc0;
+ p5.l = 0x0014;
+ if cc jump 1f;
+ r7.l = W[p5];
+1:
+#endif
+ p0.l = lo(TBUFCTL);
+ p0.h = hi(TBUFCTL);
+ r0 = 1;
+ [p0] = r0;
+ r0 = IRQ_HWERR;
+ r1 = sp;
+
+#ifdef CONFIG_HARDWARE_PM
+ r7 = SEQSTAT;
+ r7 = r7 >>> 0xe;
+ r6 = 0x1F;
+ r7 = r7 & r6;
+ r5 = 0x12;
+ cc = r7 == r5;
+ if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */
+#endif
+
+ SP += -12;
+ call _irq_panic;
+ SP += 12;
+ rti;
+#ifdef CONFIG_HARDWARE_PM
+.Lcall_do_ovf:
+
+ SP += -12;
+ call _pm_overflow;
+ SP += 12;
+
+ jump .Lcommon_restore_context;
+#endif
+
+/* interrupt routine for evt2 - 2. This is NMI. */
+ENTRY(_evt_evt2)
+ SAVE_CONTEXT
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+#ifdef ANOMALY_05000283
+ cc = r7 == r7;
+ p5.h = 0xffc0;
+ p5.l = 0x0014;
+ if cc jump 1f;
+ r7.l = W[p5];
+1:
+#endif
+ r0 = IRQ_NMI;
+ r1 = sp;
+ SP += -12;
+ call _asm_do_IRQ;
+ SP += 12;
+ RESTORE_CONTEXT
+ rtn;
+
+/* interrupt routine for core timer - 6 */
+ENTRY(_evt_timer)
+ TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P)
+
+/* interrupt routine for evt7 - 7 */
+ENTRY(_evt_evt7)
+ INTERRUPT_ENTRY(EVT_IVG7_P)
+ENTRY(_evt_evt8)
+ INTERRUPT_ENTRY(EVT_IVG8_P)
+ENTRY(_evt_evt9)
+ INTERRUPT_ENTRY(EVT_IVG9_P)
+ENTRY(_evt_evt10)
+ INTERRUPT_ENTRY(EVT_IVG10_P)
+ENTRY(_evt_evt11)
+ INTERRUPT_ENTRY(EVT_IVG11_P)
+ENTRY(_evt_evt12)
+ INTERRUPT_ENTRY(EVT_IVG12_P)
+ENTRY(_evt_evt13)
+ INTERRUPT_ENTRY(EVT_IVG13_P)
+
+
+ /* interrupt routine for system_call - 15 */
+ENTRY(_evt_system_call)
+ SAVE_CONTEXT_SYSCALL
+#ifdef CONFIG_FRAME_POINTER
+ fp = 0;
+#endif
+ call _system_call;
+ jump .Lcommon_restore_context;
diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
new file mode 100644
index 00000000000..f3cf07036c2
--- /dev/null
+++ b/arch/blackfin/mach-common/ints-priority-dc.c
@@ -0,0 +1,476 @@
+/*
+ * File: arch/blackfin/mach-common/ints-priority-dc.c
+ * Based on:
+ * Author:
+ *
+ * Created: ?
+ * Description: Set up the interupt priorities
+ *
+ * Modified:
+ * 1996 Roman Zippel
+ * 1999 D. Jeff Dionne <jeff@uclinux.org>
+ * 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
+ * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
+ * 2003 Metrowerks/Motorola
+ * 2003 Bas Vermeulen <bas@buyways.nl>
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <linux/kgdb.h>
+#endif
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/irq_handler.h>
+
+/*
+ * NOTES:
+ * - we have separated the physical Hardware interrupt from the
+ * levels that the LINUX kernel sees (see the description in irq.h)
+ * -
+ */
+
+unsigned long irq_flags = 0;
+
+/* The number of spurious interrupts */
+atomic_t num_spurious;
+
+struct ivgx {
+ /* irq number for request_irq, available in mach-bf561/irq.h */
+ int irqno;
+ /* corresponding bit in the SICA_ISR0 register */
+ int isrflag0;
+ /* corresponding bit in the SICA_ISR1 register */
+ int isrflag1;
+} ivg_table[NR_PERI_INTS];
+
+struct ivg_slice {
+ /* position of first irq in ivg_table for given ivg */
+ struct ivgx *ifirst;
+ struct ivgx *istop;
+} ivg7_13[IVG13 - IVG7 + 1];
+
+static void search_IAR(void);
+
+/*
+ * Search SIC_IAR and fill tables with the irqvalues
+ * and their positions in the SIC_ISR register.
+ */
+static void __init search_IAR(void)
+{
+ unsigned ivg, irq_pos = 0;
+ for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
+ int irqn;
+
+ ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
+
+ for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
+ int iar_shift = (irqn & 7) * 4;
+ if (ivg ==
+ (0xf &
+ bfin_read32((unsigned long *)SICA_IAR0 +
+ (irqn >> 3)) >> iar_shift)) {
+ ivg_table[irq_pos].irqno = IVG7 + irqn;
+ ivg_table[irq_pos].isrflag0 =
+ (irqn < 32 ? (1 << irqn) : 0);
+ ivg_table[irq_pos].isrflag1 =
+ (irqn < 32 ? 0 : (1 << (irqn - 32)));
+ ivg7_13[ivg].istop++;
+ irq_pos++;
+ }
+ }
+ }
+}
+
+/*
+ * This is for BF561 internal IRQs
+ */
+
+static void ack_noop(unsigned int irq)
+{
+ /* Dummy function. */
+}
+
+static void bf561_core_mask_irq(unsigned int irq)
+{
+ irq_flags &= ~(1 << irq);
+ if (!irqs_disabled())
+ local_irq_enable();
+}
+
+static void bf561_core_unmask_irq(unsigned int irq)
+{
+ irq_flags |= 1 << irq;
+ /*
+ * If interrupts are enabled, IMASK must contain the same value
+ * as irq_flags. Make sure that invariant holds. If interrupts
+ * are currently disabled we need not do anything; one of the
+ * callers will take care of setting IMASK to the proper value
+ * when reenabling interrupts.
+ * local_irq_enable just does "STI irq_flags", so it's exactly
+ * what we need.
+ */
+ if (!irqs_disabled())
+ local_irq_enable();
+ return;
+}
+
+static void bf561_internal_mask_irq(unsigned int irq)
+{
+ unsigned long irq_mask;
+ if ((irq - (IRQ_CORETMR + 1)) < 32) {
+ irq_mask = (1 << (irq - (IRQ_CORETMR + 1)));
+ bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() & ~irq_mask);
+ } else {
+ irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32));
+ bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() & ~irq_mask);
+ }
+}
+
+static void bf561_internal_unmask_irq(unsigned int irq)
+{
+ unsigned long irq_mask;
+
+ if ((irq - (IRQ_CORETMR + 1)) < 32) {
+ irq_mask = (1 << (irq - (IRQ_CORETMR + 1)));
+ bfin_write_SICA_IMASK0(bfin_read_SICA_IMASK0() | irq_mask);
+ } else {
+ irq_mask = (1 << (irq - (IRQ_CORETMR + 1) - 32));
+ bfin_write_SICA_IMASK1(bfin_read_SICA_IMASK1() | irq_mask);
+ }
+ SSYNC();
+}
+
+static struct irq_chip bf561_core_irqchip = {
+ .ack = ack_noop,
+ .mask = bf561_core_mask_irq,
+ .unmask = bf561_core_unmask_irq,
+};
+
+static struct irq_chip bf561_internal_irqchip = {
+ .ack = ack_noop,
+ .mask = bf561_internal_mask_irq,
+ .unmask = bf561_internal_unmask_irq,
+};
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+static void bf561_gpio_ack_irq(unsigned int irq)
+{
+ u16 gpionr = irq - IRQ_PF0;
+
+ if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ set_gpio_data(gpionr, 0);
+ SSYNC();
+ }
+}
+
+static void bf561_gpio_mask_ack_irq(unsigned int irq)
+{
+ u16 gpionr = irq - IRQ_PF0;
+
+ if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ set_gpio_data(gpionr, 0);
+ SSYNC();
+ }
+
+ set_gpio_maska(gpionr, 0);
+ SSYNC();
+}
+
+static void bf561_gpio_mask_irq(unsigned int irq)
+{
+ set_gpio_maska(irq - IRQ_PF0, 0);
+ SSYNC();
+}
+
+static void bf561_gpio_unmask_irq(unsigned int irq)
+{
+ set_gpio_maska(irq - IRQ_PF0, 1);
+ SSYNC();
+}
+
+static unsigned int bf561_gpio_irq_startup(unsigned int irq)
+{
+ unsigned int ret;
+ u16 gpionr = irq - IRQ_PF0;
+
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+
+ ret = gpio_request(gpionr, NULL);
+ if(ret)
+ return ret;
+
+ }
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ bf561_gpio_unmask_irq(irq);
+
+ return ret;
+
+}
+
+static void bf561_gpio_irq_shutdown(unsigned int irq)
+{
+ bf561_gpio_mask_irq(irq);
+ gpio_free(irq - IRQ_PF0);
+ gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
+}
+
+static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+
+ unsigned int ret;
+ u16 gpionr = irq - IRQ_PF0;
+
+
+ if (type == IRQ_TYPE_PROBE) {
+ /* only probe unenabled GPIO interrupt lines */
+ if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+ return 0;
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+
+ }
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+
+ ret = gpio_request(gpionr, NULL);
+ if(ret)
+ return ret;
+
+ }
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ } else {
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ return 0;
+ }
+
+
+ set_gpio_dir(gpionr, 0);
+ set_gpio_inen(gpionr, 1);
+
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+ gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ set_gpio_edge(gpionr, 1);
+ } else {
+ set_gpio_edge(gpionr, 0);
+ gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ }
+
+ if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ set_gpio_both(gpionr, 1);
+ else
+ set_gpio_both(gpionr, 0);
+
+ if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+ set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
+ else
+ set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
+
+ SSYNC();
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ set_irq_handler(irq, handle_edge_irq);
+ else
+ set_irq_handler(irq, handle_level_irq);
+
+ return 0;
+}
+
+static struct irq_chip bf561_gpio_irqchip = {
+ .ack = bf561_gpio_ack_irq,
+ .mask = bf561_gpio_mask_irq,
+ .mask_ack = bf561_gpio_mask_ack_irq,
+ .unmask = bf561_gpio_unmask_irq,
+ .set_type = bf561_gpio_irq_type,
+ .startup = bf561_gpio_irq_startup,
+ .shutdown = bf561_gpio_irq_shutdown
+};
+
+static void bf561_demux_gpio_irq(unsigned int inta_irq,
+ struct irq_desc *intb_desc)
+{
+ int irq, flag_d, mask;
+ u16 gpio;
+
+ switch (inta_irq) {
+ case IRQ_PROG0_INTA:
+ irq = IRQ_PF0;
+ break;
+ case IRQ_PROG1_INTA:
+ irq = IRQ_PF16;
+ break;
+ case IRQ_PROG2_INTA:
+ irq = IRQ_PF32;
+ break;
+ default:
+ dump_stack();
+ return;
+ }
+
+ gpio = irq - IRQ_PF0;
+
+ flag_d = get_gpiop_data(gpio);
+ mask = flag_d & (gpio_enabled[gpio_bank(gpio)] &
+ get_gpiop_maska(gpio));
+
+ do {
+ if (mask & 1) {
+ struct irq_desc *desc = irq_desc + irq;
+ desc->handle_irq(irq, desc);
+ }
+ irq++;
+ mask >>= 1;
+ } while (mask);
+
+
+}
+
+#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the BFin IRQ handling routines.
+ */
+int __init init_arch_irq(void)
+{
+ int irq;
+ unsigned long ilat = 0;
+ /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
+ bfin_write_SICA_IMASK0(SIC_UNMASK_ALL);
+ bfin_write_SICA_IMASK1(SIC_UNMASK_ALL);
+ SSYNC();
+
+ local_irq_disable();
+
+ init_exception_buff();
+
+#ifndef CONFIG_KGDB
+ bfin_write_EVT0(evt_emulation);
+#endif
+ bfin_write_EVT2(evt_evt2);
+ bfin_write_EVT3(trap);
+ bfin_write_EVT5(evt_ivhw);
+ bfin_write_EVT6(evt_timer);
+ bfin_write_EVT7(evt_evt7);
+ bfin_write_EVT8(evt_evt8);
+ bfin_write_EVT9(evt_evt9);
+ bfin_write_EVT10(evt_evt10);
+ bfin_write_EVT11(evt_evt11);
+ bfin_write_EVT12(evt_evt12);
+ bfin_write_EVT13(evt_evt13);
+ bfin_write_EVT14(evt14_softirq);
+ bfin_write_EVT15(evt_system_call);
+ CSYNC();
+
+ for (irq = 0; irq < SYS_IRQS; irq++) {
+ if (irq <= IRQ_CORETMR)
+ set_irq_chip(irq, &bf561_core_irqchip);
+ else
+ set_irq_chip(irq, &bf561_internal_irqchip);
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+ if ((irq != IRQ_PROG0_INTA) &&
+ (irq != IRQ_PROG1_INTA) && (irq != IRQ_PROG2_INTA)) {
+#endif
+ set_irq_handler(irq, handle_simple_irq);
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+ } else {
+ set_irq_chained_handler(irq, bf561_demux_gpio_irq);
+ }
+#endif
+
+ }
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+ for (irq = IRQ_PF0; irq <= IRQ_PF47; irq++) {
+ set_irq_chip(irq, &bf561_gpio_irqchip);
+ /* if configured as edge, then will be changed to do_edge_IRQ */
+ set_irq_handler(irq, handle_level_irq);
+ }
+#endif
+ bfin_write_IMASK(0);
+ CSYNC();
+ ilat = bfin_read_ILAT();
+ CSYNC();
+ bfin_write_ILAT(ilat);
+ CSYNC();
+
+ printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
+ /* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
+ * local_irq_enable()
+ */
+ program_IAR();
+ /* Therefore it's better to setup IARs before interrupts enabled */
+ search_IAR();
+
+ /* Enable interrupts IVG7-15 */
+ irq_flags = irq_flags | IMASK_IVG15 |
+ IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
+ IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
+
+ return 0;
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
+#endif
+
+void do_irq(int vec, struct pt_regs *fp)
+{
+ if (vec == EVT_IVTMR_P) {
+ vec = IRQ_CORETMR;
+ } else {
+ struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+ struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+ unsigned long sic_status0, sic_status1;
+
+ SSYNC();
+ sic_status0 = bfin_read_SICA_IMASK0() & bfin_read_SICA_ISR0();
+ sic_status1 = bfin_read_SICA_IMASK1() & bfin_read_SICA_ISR1();
+
+ for (;; ivg++) {
+ if (ivg >= ivg_stop) {
+ atomic_inc(&num_spurious);
+ return;
+ } else if ((sic_status0 & ivg->isrflag0) ||
+ (sic_status1 & ivg->isrflag1))
+ break;
+ }
+ vec = ivg->irqno;
+ }
+ asm_do_IRQ(vec, fp);
+
+#ifdef CONFIG_KGDB
+ kgdb_process_breakpoint();
+#endif
+}
diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
new file mode 100644
index 00000000000..34b62288ec3
--- /dev/null
+++ b/arch/blackfin/mach-common/ints-priority-sc.c
@@ -0,0 +1,577 @@
+/*
+ * File: arch/blackfin/mach-common/ints-priority-sc.c
+ * Based on:
+ * Author:
+ *
+ * Created: ?
+ * Description: Set up the interupt priorities
+ *
+ * Modified:
+ * 1996 Roman Zippel
+ * 1999 D. Jeff Dionne <jeff@uclinux.org>
+ * 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
+ * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
+ * 2003 Metrowerks/Motorola
+ * 2003 Bas Vermeulen <bas@buyways.nl>
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/irq.h>
+#ifdef CONFIG_KGDB
+#include <linux/kgdb.h>
+#endif
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/irq_handler.h>
+
+#ifdef BF537_FAMILY
+# define BF537_GENERIC_ERROR_INT_DEMUX
+#else
+# undef BF537_GENERIC_ERROR_INT_DEMUX
+#endif
+
+/*
+ * NOTES:
+ * - we have separated the physical Hardware interrupt from the
+ * levels that the LINUX kernel sees (see the description in irq.h)
+ * -
+ */
+
+unsigned long irq_flags = 0;
+
+/* The number of spurious interrupts */
+atomic_t num_spurious;
+
+struct ivgx {
+ /* irq number for request_irq, available in mach-bf533/irq.h */
+ int irqno;
+ /* corresponding bit in the SIC_ISR register */
+ int isrflag;
+} ivg_table[NR_PERI_INTS];
+
+struct ivg_slice {
+ /* position of first irq in ivg_table for given ivg */
+ struct ivgx *ifirst;
+ struct ivgx *istop;
+} ivg7_13[IVG13 - IVG7 + 1];
+
+static void search_IAR(void);
+
+/*
+ * Search SIC_IAR and fill tables with the irqvalues
+ * and their positions in the SIC_ISR register.
+ */
+static void __init search_IAR(void)
+{
+ unsigned ivg, irq_pos = 0;
+ for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
+ int irqn;
+
+ ivg7_13[ivg].istop = ivg7_13[ivg].ifirst =
+ &ivg_table[irq_pos];
+
+ for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
+ int iar_shift = (irqn & 7) * 4;
+ if (ivg ==
+ (0xf &
+ bfin_read32((unsigned long *) SIC_IAR0 +
+ (irqn >> 3)) >> iar_shift)) {
+ ivg_table[irq_pos].irqno = IVG7 + irqn;
+ ivg_table[irq_pos].isrflag = 1 << irqn;
+ ivg7_13[ivg].istop++;
+ irq_pos++;
+ }
+ }
+ }
+}
+
+/*
+ * This is for BF533 internal IRQs
+ */
+
+static void ack_noop(unsigned int irq)
+{
+ /* Dummy function. */
+}
+
+static void bfin_core_mask_irq(unsigned int irq)
+{
+ irq_flags &= ~(1 << irq);
+ if (!irqs_disabled())
+ local_irq_enable();
+}
+
+static void bfin_core_unmask_irq(unsigned int irq)
+{
+ irq_flags |= 1 << irq;
+ /*
+ * If interrupts are enabled, IMASK must contain the same value
+ * as irq_flags. Make sure that invariant holds. If interrupts
+ * are currently disabled we need not do anything; one of the
+ * callers will take care of setting IMASK to the proper value
+ * when reenabling interrupts.
+ * local_irq_enable just does "STI irq_flags", so it's exactly
+ * what we need.
+ */
+ if (!irqs_disabled())
+ local_irq_enable();
+ return;
+}
+
+static void bfin_internal_mask_irq(unsigned int irq)
+{
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+ ~(1 << (irq - (IRQ_CORETMR + 1))));
+ SSYNC();
+}
+
+static void bfin_internal_unmask_irq(unsigned int irq)
+{
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
+ (1 << (irq - (IRQ_CORETMR + 1))));
+ SSYNC();
+}
+
+static struct irq_chip bfin_core_irqchip = {
+ .ack = ack_noop,
+ .mask = bfin_core_mask_irq,
+ .unmask = bfin_core_unmask_irq,
+};
+
+static struct irq_chip bfin_internal_irqchip = {
+ .ack = ack_noop,
+ .mask = bfin_internal_mask_irq,
+ .unmask = bfin_internal_unmask_irq,
+};
+
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+static int error_int_mask;
+
+static void bfin_generic_error_ack_irq(unsigned int irq)
+{
+
+}
+
+static void bfin_generic_error_mask_irq(unsigned int irq)
+{
+ error_int_mask &= ~(1L << (irq - IRQ_PPI_ERROR));
+
+ if (!error_int_mask) {
+ local_irq_disable();
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+ ~(1 <<
+ (IRQ_GENERIC_ERROR -
+ (IRQ_CORETMR + 1))));
+ SSYNC();
+ local_irq_enable();
+ }
+}
+
+static void bfin_generic_error_unmask_irq(unsigned int irq)
+{
+ local_irq_disable();
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() | 1 <<
+ (IRQ_GENERIC_ERROR - (IRQ_CORETMR + 1)));
+ SSYNC();
+ local_irq_enable();
+
+ error_int_mask |= 1L << (irq - IRQ_PPI_ERROR);
+}
+
+static struct irq_chip bfin_generic_error_irqchip = {
+ .ack = bfin_generic_error_ack_irq,
+ .mask = bfin_generic_error_mask_irq,
+ .unmask = bfin_generic_error_unmask_irq,
+};
+
+static void bfin_demux_error_irq(unsigned int int_err_irq,
+ struct irq_desc *intb_desc)
+{
+ int irq = 0;
+
+ SSYNC();
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
+ irq = IRQ_MAC_ERROR;
+ else
+#endif
+ if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
+ irq = IRQ_SPORT0_ERROR;
+ else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
+ irq = IRQ_SPORT1_ERROR;
+ else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
+ irq = IRQ_PPI_ERROR;
+ else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
+ irq = IRQ_CAN_ERROR;
+ else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
+ irq = IRQ_SPI_ERROR;
+ else if ((bfin_read_UART0_IIR() & UART_ERR_MASK_STAT1) &&
+ (bfin_read_UART0_IIR() & UART_ERR_MASK_STAT0))
+ irq = IRQ_UART0_ERROR;
+ else if ((bfin_read_UART1_IIR() & UART_ERR_MASK_STAT1) &&
+ (bfin_read_UART1_IIR() & UART_ERR_MASK_STAT0))
+ irq = IRQ_UART1_ERROR;
+
+ if (irq) {
+ if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) {
+ struct irq_desc *desc = irq_desc + irq;
+ desc->handle_irq(irq, desc);
+ } else {
+
+ switch (irq) {
+ case IRQ_PPI_ERROR:
+ bfin_write_PPI_STATUS(PPI_ERR_MASK);
+ break;
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ case IRQ_MAC_ERROR:
+ bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
+ break;
+#endif
+ case IRQ_SPORT0_ERROR:
+ bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
+ break;
+
+ case IRQ_SPORT1_ERROR:
+ bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
+ break;
+
+ case IRQ_CAN_ERROR:
+ bfin_write_CAN_GIS(CAN_ERR_MASK);
+ break;
+
+ case IRQ_SPI_ERROR:
+ bfin_write_SPI_STAT(SPI_ERR_MASK);
+ break;
+
+ default:
+ break;
+ }
+
+ pr_debug("IRQ %d:"
+ " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+ irq);
+ }
+ } else
+ printk(KERN_ERR
+ "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
+ " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+ __FUNCTION__, __FILE__, __LINE__);
+
+
+}
+#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+static void bfin_gpio_ack_irq(unsigned int irq)
+{
+ u16 gpionr = irq - IRQ_PF0;
+
+ if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ set_gpio_data(gpionr, 0);
+ SSYNC();
+ }
+}
+
+static void bfin_gpio_mask_ack_irq(unsigned int irq)
+{
+ u16 gpionr = irq - IRQ_PF0;
+
+ if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ set_gpio_data(gpionr, 0);
+ SSYNC();
+ }
+
+ set_gpio_maska(gpionr, 0);
+ SSYNC();
+}
+
+static void bfin_gpio_mask_irq(unsigned int irq)
+{
+ set_gpio_maska(irq - IRQ_PF0, 0);
+ SSYNC();
+}
+
+static void bfin_gpio_unmask_irq(unsigned int irq)
+{
+ set_gpio_maska(irq - IRQ_PF0, 1);
+ SSYNC();
+}
+
+static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+{
+ unsigned int ret;
+ u16 gpionr = irq - IRQ_PF0;
+
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+ ret = gpio_request(gpionr, NULL);
+ if (ret)
+ return ret;
+ }
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ bfin_gpio_unmask_irq(irq);
+
+ return ret;
+}
+
+static void bfin_gpio_irq_shutdown(unsigned int irq)
+{
+ bfin_gpio_mask_irq(irq);
+ gpio_free(irq - IRQ_PF0);
+ gpio_enabled[gpio_bank(irq - IRQ_PF0)] &= ~gpio_bit(irq - IRQ_PF0);
+}
+
+static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+
+ unsigned int ret;
+ u16 gpionr = irq - IRQ_PF0;
+
+ if (type == IRQ_TYPE_PROBE) {
+ /* only probe unenabled GPIO interrupt lines */
+ if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+ return 0;
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
+ {
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+ ret = gpio_request(gpionr, NULL);
+ if (ret)
+ return ret;
+ }
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ } else {
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ return 0;
+ }
+
+ set_gpio_dir(gpionr, 0);
+ set_gpio_inen(gpionr, 1);
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+ gpio_edge_triggered[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ set_gpio_edge(gpionr, 1);
+ } else {
+ set_gpio_edge(gpionr, 0);
+ gpio_edge_triggered[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ }
+
+ if ((type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ == (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ set_gpio_both(gpionr, 1);
+ else
+ set_gpio_both(gpionr, 0);
+
+ if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+ set_gpio_polar(gpionr, 1); /* low or falling edge denoted by one */
+ else
+ set_gpio_polar(gpionr, 0); /* high or rising edge denoted by zero */
+
+ SSYNC();
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ set_irq_handler(irq, handle_edge_irq);
+ else
+ set_irq_handler(irq, handle_level_irq);
+
+ return 0;
+}
+
+
+static struct irq_chip bfin_gpio_irqchip = {
+ .ack = bfin_gpio_ack_irq,
+ .mask = bfin_gpio_mask_irq,
+ .mask_ack = bfin_gpio_mask_ack_irq,
+ .unmask = bfin_gpio_unmask_irq,
+ .set_type = bfin_gpio_irq_type,
+ .startup = bfin_gpio_irq_startup,
+ .shutdown = bfin_gpio_irq_shutdown
+};
+
+static void bfin_demux_gpio_irq(unsigned int intb_irq,
+ struct irq_desc *intb_desc)
+{
+ u16 i;
+
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=16) {
+ int irq = IRQ_PF0 + i;
+ int flag_d = get_gpiop_data(i);
+ int mask =
+ flag_d & (gpio_enabled[gpio_bank(i)] &
+ get_gpiop_maska(i));
+
+ while (mask) {
+ if (mask & 1) {
+ struct irq_desc *desc = irq_desc + irq;
+ desc->handle_irq(irq, desc);
+ }
+ irq++;
+ mask >>= 1;
+ }
+ }
+}
+
+#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */
+
+/*
+ * This function should be called during kernel startup to initialize
+ * the BFin IRQ handling routines.
+ */
+int __init init_arch_irq(void)
+{
+ int irq;
+ unsigned long ilat = 0;
+ /* Disable all the peripheral intrs - page 4-29 HW Ref manual */
+ bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
+ SSYNC();
+
+ local_irq_disable();
+
+#ifndef CONFIG_KGDB
+ bfin_write_EVT0(evt_emulation);
+#endif
+ bfin_write_EVT2(evt_evt2);
+ bfin_write_EVT3(trap);
+ bfin_write_EVT5(evt_ivhw);
+ bfin_write_EVT6(evt_timer);
+ bfin_write_EVT7(evt_evt7);
+ bfin_write_EVT8(evt_evt8);
+ bfin_write_EVT9(evt_evt9);
+ bfin_write_EVT10(evt_evt10);
+ bfin_write_EVT11(evt_evt11);
+ bfin_write_EVT12(evt_evt12);
+ bfin_write_EVT13(evt_evt13);
+ bfin_write_EVT14(evt14_softirq);
+ bfin_write_EVT15(evt_system_call);
+ CSYNC();
+
+ for (irq = 0; irq < SYS_IRQS; irq++) {
+ if (irq <= IRQ_CORETMR)
+ set_irq_chip(irq, &bfin_core_irqchip);
+ else
+ set_irq_chip(irq, &bfin_internal_irqchip);
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+ if (irq != IRQ_GENERIC_ERROR) {
+#endif
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+ if ((irq != IRQ_PROG_INTA) /*PORT F & G MASK_A Interrupt*/
+# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
+ && (irq != IRQ_MAC_RX) /*PORT H MASK_A Interrupt*/
+# endif
+ ) {
+#endif
+ set_irq_handler(irq, handle_simple_irq);
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+ } else {
+ set_irq_chained_handler(irq,
+ bfin_demux_gpio_irq);
+ }
+#endif
+
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+ } else {
+ set_irq_handler(irq, bfin_demux_error_irq);
+ }
+#endif
+ }
+#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+ for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++) {
+ set_irq_chip(irq, &bfin_generic_error_irqchip);
+ set_irq_handler(irq, handle_level_irq);
+ }
+#endif
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+ for (irq = IRQ_PF0; irq < NR_IRQS; irq++) {
+ set_irq_chip(irq, &bfin_gpio_irqchip);
+ /* if configured as edge, then will be changed to do_edge_IRQ */
+ set_irq_handler(irq, handle_level_irq);
+ }
+#endif
+ bfin_write_IMASK(0);
+ CSYNC();
+ ilat = bfin_read_ILAT();
+ CSYNC();
+ bfin_write_ILAT(ilat);
+ CSYNC();
+
+ printk(KERN_INFO
+ "Configuring Blackfin Priority Driven Interrupts\n");
+ /* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
+ * local_irq_enable()
+ */
+ program_IAR();
+ /* Therefore it's better to setup IARs before interrupts enabled */
+ search_IAR();
+
+ /* Enable interrupts IVG7-15 */
+ irq_flags = irq_flags | IMASK_IVG15 |
+ IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
+ IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 |
+ IMASK_IVGHW;
+
+ return 0;
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
+#endif
+
+void do_irq(int vec, struct pt_regs *fp)
+{
+ if (vec == EVT_IVTMR_P) {
+ vec = IRQ_CORETMR;
+ } else {
+ struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+ struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+ unsigned long sic_status;
+
+ SSYNC();
+ sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+
+ for (;; ivg++) {
+ if (ivg >= ivg_stop) {
+ atomic_inc(&num_spurious);
+ return;
+ } else if (sic_status & ivg->isrflag)
+ break;
+ }
+ vec = ivg->irqno;
+ }
+ asm_do_IRQ(vec, fp);
+
+#ifdef CONFIG_KGDB
+ kgdb_process_breakpoint();
+#endif
+}
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
new file mode 100644
index 00000000000..f05e3dadaf3
--- /dev/null
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -0,0 +1,194 @@
+/*
+ * File: arch/blackfin/mach-common/irqpanic.c
+ * Based on:
+ * Author:
+ *
+ * Created: ?
+ * Description: panic kernel with dump information
+ *
+ * Modified: rgetz - added cache checking code 14Feb06
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+
+#include "../oprofile/op_blackfin.h"
+
+#ifdef CONFIG_DEBUG_ICACHE_CHECK
+#define L1_ICACHE_START 0xffa10000
+#define L1_ICACHE_END 0xffa13fff
+void irq_panic(int reason, struct pt_regs *regs) __attribute__ ((l1_text));
+#endif
+
+/*
+ * irq_panic - calls panic with string setup
+ */
+asmlinkage void irq_panic(int reason, struct pt_regs *regs)
+{
+ int sig = 0;
+ siginfo_t info;
+
+#ifdef CONFIG_DEBUG_ICACHE_CHECK
+ unsigned int cmd, tag, ca, cache_hi, cache_lo, *pa;
+ unsigned short i, j, die;
+ unsigned int bad[10][6];
+
+ /* check entire cache for coherency
+ * Since printk is in cacheable memory,
+ * don't call it until you have checked everything
+ */
+
+ die = 0;
+ i = 0;
+
+ /* check icache */
+
+ for (ca = L1_ICACHE_START; ca <= L1_ICACHE_END && i < 10; ca += 32) {
+
+ /* Grab various address bits for the itest_cmd fields */
+ cmd = (((ca & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
+ ((ca & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
+ ((ca & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
+ 0); /* Access Tag, Read access */
+
+ SSYNC();
+ bfin_write_ITEST_COMMAND(cmd);
+ SSYNC();
+ tag = bfin_read_ITEST_DATA0();
+ SSYNC();
+
+ /* if tag is marked as valid, check it */
+ if (tag & 1) {
+ /* The icache is arranged in 4 groups of 64-bits */
+ for (j = 0; j < 32; j += 8) {
+ cmd = ((((ca + j) & 0x3000) << 4) | /* ca[13:12] for SBNK[1:0] */
+ (((ca + j) & 0x0c00) << 16) | /* ca[11:10] for WAYSEL[1:0] */
+ (((ca + j) & 0x3f8)) | /* ca[09:03] for SET[4:0] and DW[1:0] */
+ 4); /* Access Data, Read access */
+
+ SSYNC();
+ bfin_write_ITEST_COMMAND(cmd);
+ SSYNC();
+
+ cache_hi = bfin_read_ITEST_DATA1();
+ cache_lo = bfin_read_ITEST_DATA0();
+
+ pa = ((unsigned int *)((tag & 0xffffcc00) |
+ ((ca + j) & ~(0xffffcc00))));
+
+ /*
+ * Debugging this, enable
+ *
+ * printk("addr: %08x %08x%08x | %08x%08x\n",
+ * ((unsigned int *)((tag & 0xffffcc00) | ((ca+j) & ~(0xffffcc00)))),
+ * cache_hi, cache_lo, *(pa+1), *pa);
+ */
+
+ if (cache_hi != *(pa + 1) || cache_lo != *pa) {
+ /* Since icache is not working, stay out of it, by not printing */
+ die = 1;
+ bad[i][0] = (ca + j);
+ bad[i][1] = cache_hi;
+ bad[i][2] = cache_lo;
+ bad[i][3] = ((tag & 0xffffcc00) |
+ ((ca + j) & ~(0xffffcc00)));
+ bad[i][4] = *(pa + 1);
+ bad[i][5] = *(pa);
+ i++;
+ }
+ }
+ }
+ }
+ if (die) {
+ printk(KERN_EMERG "icache coherency error\n");
+ for (j = 0; j <= i; j++) {
+ printk(KERN_EMERG
+ "cache address : %08x cache value : %08x%08x\n",
+ bad[j][0], bad[j][1], bad[j][2]);
+ printk(KERN_EMERG
+ "physical address: %08x SDRAM value : %08x%08x\n",
+ bad[j][3], bad[j][4], bad[j][5]);
+ }
+ panic("icache coherency error");
+ } else {
+ printk(KERN_EMERG "icache checked, and OK\n");
+ }
+#endif
+
+ printk(KERN_EMERG "\n");
+ printk(KERN_EMERG "Exception: IRQ 0x%x entered\n", reason);
+ printk(KERN_EMERG " code=[0x%08lx], stack frame=0x%08lx, "
+ " bad PC=0x%08lx\n",
+ (unsigned long)regs->seqstat,
+ (unsigned long)regs,
+ (unsigned long)regs->pc);
+ if (reason == 0x5) {
+ printk(KERN_EMERG "----------- HARDWARE ERROR -----------\n");
+
+ /* There is only need to check for Hardware Errors, since other
+ * EXCEPTIONS are handled in TRAPS.c (MH)
+ */
+ switch (regs->seqstat & SEQSTAT_HWERRCAUSE) {
+ case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR): /* System MMR Error */
+ info.si_code = BUS_ADRALN;
+ sig = SIGBUS;
+ printk(KERN_EMERG HWC_x2);
+ break;
+ case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR): /* External Memory Addressing Error */
+ info.si_code = BUS_ADRERR;
+ sig = SIGBUS;
+ printk(KERN_EMERG HWC_x3);
+ break;
+ case (SEQSTAT_HWERRCAUSE_PERF_FLOW): /* Performance Monitor Overflow */
+ printk(KERN_EMERG HWC_x12);
+ break;
+ case (SEQSTAT_HWERRCAUSE_RAISE_5): /* RAISE 5 instruction */
+ printk(KERN_EMERG HWC_x18);
+ break;
+ default: /* Reserved */
+ printk(KERN_EMERG HWC_default);
+ break;
+ }
+ }
+
+ regs->ipend = bfin_read_IPEND();
+ dump_bfin_regs(regs, (void *)regs->pc);
+ if (0 == (info.si_signo = sig) || 0 == user_mode(regs)) /* in kernelspace */
+ panic("Unhandled IRQ or exceptions!\n");
+ else { /* in userspace */
+ info.si_errno = 0;
+ info.si_addr = (void *)regs->pc;
+ force_sig_info(sig, &info, current);
+ }
+}
+
+#ifdef CONFIG_HARDWARE_PM
+/*
+ * call the handler of Performance overflow
+ */
+asmlinkage void pm_overflow(int irq, struct pt_regs *regs)
+{
+ pm_overflow_handler(irq, regs);
+}
+#endif
diff --git a/arch/blackfin/mach-common/lock.S b/arch/blackfin/mach-common/lock.S
new file mode 100644
index 00000000000..2cbb15b3392
--- /dev/null
+++ b/arch/blackfin/mach-common/lock.S
@@ -0,0 +1,204 @@
+/*
+ * File: arch/blackfin/mach-common/lock.S
+ * Based on:
+ * Author: LG Soft India
+ *
+ * Created: ?
+ * Description: kernel locks
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/cplb.h>
+#include <asm/blackfin.h>
+
+.text
+
+#ifdef CONFIG_BLKFIN_CACHE_LOCK
+
+/* When you come here, it is assumed that
+ * R0 - Which way to be locked
+ */
+
+ENTRY(_cache_grab_lock)
+
+ [--SP]=( R7:0,P5:0 );
+
+ P1.H = (IMEM_CONTROL >> 16);
+ P1.L = (IMEM_CONTROL & 0xFFFF);
+ P5.H = (ICPLB_ADDR0 >> 16);
+ P5.L = (ICPLB_ADDR0 & 0xFFFF);
+ P4.H = (ICPLB_DATA0 >> 16);
+ P4.L = (ICPLB_DATA0 & 0xFFFF);
+ R7 = R0;
+
+ /* If the code of interest already resides in the cache
+ * invalidate the entire cache itself.
+ * invalidate_entire_icache;
+ */
+
+ SP += -12;
+ [--SP] = RETS;
+ CALL _invalidate_entire_icache;
+ RETS = [SP++];
+ SP += 12;
+
+ /* Disable the Interrupts*/
+
+ CLI R3;
+
+.LLOCK_WAY:
+
+ /* Way0 - 0xFFA133E0
+ * Way1 - 0xFFA137E0
+ * Way2 - 0xFFA13BE0 Total Way Size = 4K
+ * Way3 - 0xFFA13FE0
+ */
+
+ /* Procedure Ex. -Set the locks for other ways by setting ILOC[3:1]
+ * Only Way0 of the instruction cache can now be
+ * replaced by a new code
+ */
+
+ R5 = R7;
+ CC = BITTST(R7,0);
+ IF CC JUMP .LCLEAR1;
+ R7 = 0;
+ BITSET(R7,0);
+ JUMP .LDONE1;
+
+.LCLEAR1:
+ R7 = 0;
+ BITCLR(R7,0);
+.LDONE1: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+ R7 = R5;
+ CC = BITTST(R7,1);
+ IF CC JUMP .LCLEAR2;
+ R7 = 0;
+ BITSET(R7,1);
+ JUMP .LDONE2;
+
+.LCLEAR2:
+ R7 = 0;
+ BITCLR(R7,1);
+.LDONE2: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+ R7 = R5;
+ CC = BITTST(R7,2);
+ IF CC JUMP .LCLEAR3;
+ R7 = 0;
+ BITSET(R7,2);
+ JUMP .LDONE3;
+.LCLEAR3:
+ R7 = 0;
+ BITCLR(R7,2);
+.LDONE3: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+
+ R7 = R5;
+ CC = BITTST(R7,3);
+ IF CC JUMP .LCLEAR4;
+ R7 = 0;
+ BITSET(R7,3);
+ JUMP .LDONE4;
+.LCLEAR4:
+ R7 = 0;
+ BITCLR(R7,3);
+.LDONE4: R4 = R7 << 3;
+ R7 = [P1];
+ R7 = R7 | R4;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+
+ STI R3;
+
+ ( R7:0,P5:0 ) = [SP++];
+
+ RTS;
+
+/* After the execution of critical code, the code is now locked into
+ * the cache way. Now we need to set ILOC.
+ *
+ * R0 - Which way to be locked
+ */
+
+ENTRY(_cache_lock)
+
+ [--SP]=( R7:0,P5:0 );
+
+ P1.H = (IMEM_CONTROL >> 16);
+ P1.L = (IMEM_CONTROL & 0xFFFF);
+
+ /* Disable the Interrupts*/
+ CLI R3;
+
+ R7 = [P1];
+ R2 = 0xFFFFFF87 (X);
+ R7 = R7 & R2;
+ R0 = R0 << 3;
+ R7 = R0 | R7;
+ SSYNC; /* SSYNC required writing to IMEM_CONTROL. */
+ .align 8;
+ [P1] = R7;
+ SSYNC;
+ /* Renable the Interrupts */
+ STI R3;
+
+ ( R7:0,P5:0 ) = [SP++];
+ RTS;
+
+#endif /* BLKFIN_CACHE_LOCK */
+
+/* Return the ILOC bits of IMEM_CONTROL
+ */
+
+ENTRY(_read_iloc)
+
+ P1.H = (IMEM_CONTROL >> 16);
+ P1.L = (IMEM_CONTROL & 0xFFFF);
+ R1 = 0xF;
+ R0 = [P1];
+ R0 = R0 >> 3;
+ R0 = R0 & R1;
+
+ RTS;
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
new file mode 100644
index 00000000000..deb27272c65
--- /dev/null
+++ b/arch/blackfin/mach-common/pm.c
@@ -0,0 +1,181 @@
+/*
+ * File: arch/blackfin/mach-common/pm.c
+ * Based on: arm/mach-omap/pm.c
+ * Author: Cliff Brake <cbrake@accelent.com> Copyright (c) 2001
+ *
+ * Created: 2001
+ * Description: Power management for the bfin
+ *
+ * Modified: Nicolas Pitre - PXA250 support
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ * David Singleton - OMAP1510
+ * Copyright (c) 2002 Monta Vista Software, Inc.
+ * Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610
+ * Copyright 2004
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/pm.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/dpmc.h>
+#include <asm/irq.h>
+
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H
+#define WAKEUP_TYPE PM_WAKE_HIGH
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_L
+#define WAKEUP_TYPE PM_WAKE_LOW
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_F
+#define WAKEUP_TYPE PM_WAKE_FALLING
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_R
+#define WAKEUP_TYPE PM_WAKE_RISING
+#endif
+
+#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_EDGE_B
+#define WAKEUP_TYPE PM_WAKE_BOTH_EDGES
+#endif
+
+void bfin_pm_suspend_standby_enter(void)
+{
+#ifdef CONFIG_PM_WAKEUP_BY_GPIO
+ gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE);
+#endif
+
+#if defined(CONFIG_PM_WAKEUP_BY_GPIO) || defined(CONFIG_PM_WAKEUP_GPIO_API)
+ {
+ u32 flags;
+
+ local_irq_save(flags);
+
+ sleep_deeper(gpio_pm_setup()); /*Goto Sleep*/
+
+ gpio_pm_restore();
+
+ bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+
+ local_irq_restore(flags);
+ }
+#endif
+
+#if defined(CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR)
+ sleep_deeper(CONFIG_PM_WAKEUP_SIC_IWR);
+ bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+#endif /* CONFIG_PM_WAKEUP_GPIO_BY_SIC_IWR */
+}
+
+
+/*
+ * bfin_pm_prepare - Do preliminary suspend work.
+ * @state: suspend state we're entering.
+ *
+ */
+static int bfin_pm_prepare(suspend_state_t state)
+{
+ int error = 0;
+
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ break;
+ case PM_SUSPEND_MEM:
+ return -ENOTSUPP;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return error;
+}
+
+/*
+ * bfin_pm_enter - Actually enter a sleep state.
+ * @state: State we're entering.
+ *
+ */
+static int bfin_pm_enter(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ bfin_pm_suspend_standby_enter();
+ break;
+ case PM_SUSPEND_MEM:
+ return -ENOTSUPP;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * bfin_pm_finish - Finish up suspend sequence.
+ * @state: State we're coming out of.
+ *
+ * This is called after we wake back up (or if entering the sleep state
+ * failed).
+ */
+static int bfin_pm_finish(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ break;
+
+ case PM_SUSPEND_MEM:
+ return -ENOTSUPP;
+
+ case PM_SUSPEND_DISK:
+ return -ENOTSUPP;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct pm_ops bfin_pm_ops = {
+ .pm_disk_mode = PM_DISK_PLATFORM,
+ .prepare = bfin_pm_prepare,
+ .enter = bfin_pm_enter,
+ .finish = bfin_pm_finish,
+};
+
+static int __init bfin_pm_init(void)
+{
+ pm_set_ops(&bfin_pm_ops);
+ return 0;
+}
+
+__initcall(bfin_pm_init);
diff --git a/arch/blackfin/mm/Makefile b/arch/blackfin/mm/Makefile
new file mode 100644
index 00000000000..2a7202ce01f
--- /dev/null
+++ b/arch/blackfin/mm/Makefile
@@ -0,0 +1,5 @@
+#
+# arch/blackfin/mm/Makefile
+#
+
+obj-y := blackfin_sram.o init.o
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
new file mode 100644
index 00000000000..dd0c6501c42
--- /dev/null
+++ b/arch/blackfin/mm/blackfin_sram.c
@@ -0,0 +1,540 @@
+/*
+ * File: arch/blackfin/mm/blackfin_sram.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: SRAM driver for Blackfin ADSP-BF5xx
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/rtc.h>
+#include <asm/blackfin.h>
+#include "blackfin_sram.h"
+
+spinlock_t l1sram_lock, l1_data_sram_lock, l1_inst_sram_lock;
+
+#if CONFIG_L1_MAX_PIECE < 16
+#undef CONFIG_L1_MAX_PIECE
+#define CONFIG_L1_MAX_PIECE 16
+#endif
+
+#if CONFIG_L1_MAX_PIECE > 1024
+#undef CONFIG_L1_MAX_PIECE
+#define CONFIG_L1_MAX_PIECE 1024
+#endif
+
+#define SRAM_SLT_NULL 0
+#define SRAM_SLT_FREE 1
+#define SRAM_SLT_ALLOCATED 2
+
+/* the data structure for L1 scratchpad and DATA SRAM */
+struct l1_sram_piece {
+ void *paddr;
+ int size;
+ int flag;
+};
+
+static struct l1_sram_piece l1_ssram[CONFIG_L1_MAX_PIECE];
+
+#if L1_DATA_A_LENGTH != 0
+static struct l1_sram_piece l1_data_A_sram[CONFIG_L1_MAX_PIECE];
+#endif
+
+#if L1_DATA_B_LENGTH != 0
+static struct l1_sram_piece l1_data_B_sram[CONFIG_L1_MAX_PIECE];
+#endif
+
+#if L1_CODE_LENGTH != 0
+static struct l1_sram_piece l1_inst_sram[CONFIG_L1_MAX_PIECE];
+#endif
+
+/* L1 Scratchpad SRAM initialization function */
+void l1sram_init(void)
+{
+ printk(KERN_INFO "Blackfin Scratchpad data SRAM: %d KB\n",
+ L1_SCRATCH_LENGTH >> 10);
+
+ memset(&l1_ssram, 0x00, sizeof(l1_ssram));
+ l1_ssram[0].paddr = (void*)L1_SCRATCH_START;
+ l1_ssram[0].size = L1_SCRATCH_LENGTH;
+ l1_ssram[0].flag = SRAM_SLT_FREE;
+
+ /* mutex initialize */
+ spin_lock_init(&l1sram_lock);
+}
+
+void l1_data_sram_init(void)
+{
+#if L1_DATA_A_LENGTH != 0
+ printk(KERN_INFO "Blackfin DATA_A SRAM: %d KB\n",
+ L1_DATA_A_LENGTH >> 10);
+
+ memset(&l1_data_A_sram, 0x00, sizeof(l1_data_A_sram));
+ l1_data_A_sram[0].paddr = (void*)L1_DATA_A_START +
+ (_ebss_l1 - _sdata_l1);
+ l1_data_A_sram[0].size = L1_DATA_A_LENGTH - (_ebss_l1 - _sdata_l1);
+ l1_data_A_sram[0].flag = SRAM_SLT_FREE;
+#endif
+#if L1_DATA_B_LENGTH != 0
+ printk(KERN_INFO "Blackfin DATA_B SRAM: %d KB\n",
+ L1_DATA_B_LENGTH >> 10);
+
+ memset(&l1_data_B_sram, 0x00, sizeof(l1_data_B_sram));
+ l1_data_B_sram[0].paddr = (void*)L1_DATA_B_START;
+ l1_data_B_sram[0].size = L1_DATA_B_LENGTH;
+ l1_data_B_sram[0].flag = SRAM_SLT_FREE;
+#endif
+
+ /* mutex initialize */
+ spin_lock_init(&l1_data_sram_lock);
+}
+
+void l1_inst_sram_init(void)
+{
+#if L1_CODE_LENGTH != 0
+ printk(KERN_INFO "Blackfin Instruction SRAM: %d KB\n",
+ L1_CODE_LENGTH >> 10);
+
+ memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram));
+ l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1);
+ l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
+ l1_inst_sram[0].flag = SRAM_SLT_FREE;
+#endif
+
+ /* mutex initialize */
+ spin_lock_init(&l1_inst_sram_lock);
+}
+
+/* L1 memory allocate function */
+static void *_l1_sram_alloc(size_t size, struct l1_sram_piece *pfree, int count)
+{
+ int i, index = 0;
+ void *addr = NULL;
+
+ if (size <= 0)
+ return NULL;
+
+ /* Align the size */
+ size = (size + 3) & ~3;
+
+ /* not use the good method to match the best slot !!! */
+ /* search an available memeory slot */
+ for (i = 0; i < count; i++) {
+ if ((pfree[i].flag == SRAM_SLT_FREE)
+ && (pfree[i].size >= size)) {
+ addr = pfree[i].paddr;
+ pfree[i].flag = SRAM_SLT_ALLOCATED;
+ index = i;
+ break;
+ }
+ }
+ if (i >= count)
+ return NULL;
+
+ /* updated the NULL memeory slot !!! */
+ if (pfree[i].size > size) {
+ for (i = 0; i < count; i++) {
+ if (pfree[i].flag == SRAM_SLT_NULL) {
+ pfree[i].flag = SRAM_SLT_FREE;
+ pfree[i].paddr = addr + size;
+ pfree[i].size = pfree[index].size - size;
+ pfree[index].size = size;
+ break;
+ }
+ }
+ }
+
+ return addr;
+}
+
+/* Allocate the largest available block. */
+static void *_l1_sram_alloc_max(struct l1_sram_piece *pfree, int count,
+ unsigned long *psize)
+{
+ unsigned long best = 0;
+ int i, index = -1;
+ void *addr = NULL;
+
+ /* search an available memeory slot */
+ for (i = 0; i < count; i++) {
+ if (pfree[i].flag == SRAM_SLT_FREE && pfree[i].size > best) {
+ addr = pfree[i].paddr;
+ index = i;
+ best = pfree[i].size;
+ }
+ }
+ if (index < 0)
+ return NULL;
+ *psize = best;
+
+ pfree[index].flag = SRAM_SLT_ALLOCATED;
+ return addr;
+}
+
+/* L1 memory free function */
+static int _l1_sram_free(const void *addr,
+ struct l1_sram_piece *pfree, int count)
+{
+ int i, index = 0;
+
+ /* search the relevant memory slot */
+ for (i = 0; i < count; i++) {
+ if (pfree[i].paddr == addr) {
+ if (pfree[i].flag != SRAM_SLT_ALLOCATED) {
+ /* error log */
+ return -1;
+ }
+ index = i;
+ break;
+ }
+ }
+ if (i >= count)
+ return -1;
+
+ pfree[index].flag = SRAM_SLT_FREE;
+
+ /* link the next address slot */
+ for (i = 0; i < count; i++) {
+ if (((pfree[index].paddr + pfree[index].size) == pfree[i].paddr)
+ && (pfree[i].flag == SRAM_SLT_FREE)) {
+ pfree[i].flag = SRAM_SLT_NULL;
+ pfree[index].size += pfree[i].size;
+ pfree[index].flag = SRAM_SLT_FREE;
+ break;
+ }
+ }
+
+ /* link the last address slot */
+ for (i = 0; i < count; i++) {
+ if (((pfree[i].paddr + pfree[i].size) == pfree[index].paddr) &&
+ (pfree[i].flag == SRAM_SLT_FREE)) {
+ pfree[index].flag = SRAM_SLT_NULL;
+ pfree[i].size += pfree[index].size;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int sram_free(const void *addr)
+{
+ if (0) {}
+#if L1_CODE_LENGTH != 0
+ else if (addr >= (void *)L1_CODE_START
+ && addr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
+ return l1_inst_sram_free(addr);
+#endif
+#if L1_DATA_A_LENGTH != 0
+ else if (addr >= (void *)L1_DATA_A_START
+ && addr < (void *)(L1_DATA_A_START + L1_DATA_A_LENGTH))
+ return l1_data_A_sram_free(addr);
+#endif
+#if L1_DATA_B_LENGTH != 0
+ else if (addr >= (void *)L1_DATA_B_START
+ && addr < (void *)(L1_DATA_B_START + L1_DATA_B_LENGTH))
+ return l1_data_B_sram_free(addr);
+#endif
+ else
+ return -1;
+}
+EXPORT_SYMBOL(sram_free);
+
+void *l1_data_A_sram_alloc(size_t size)
+{
+ unsigned flags;
+ void *addr = NULL;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+#if L1_DATA_A_LENGTH != 0
+ addr = _l1_sram_alloc(size, l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
+#endif
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+ pr_debug("Allocated address in l1_data_A_sram_alloc is 0x%lx+0x%lx\n",
+ (long unsigned int)addr, size);
+
+ return addr;
+}
+EXPORT_SYMBOL(l1_data_A_sram_alloc);
+
+int l1_data_A_sram_free(const void *addr)
+{
+ unsigned flags;
+ int ret;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+#if L1_DATA_A_LENGTH != 0
+ ret = _l1_sram_free(addr,
+ l1_data_A_sram, ARRAY_SIZE(l1_data_A_sram));
+#else
+ ret = -1;
+#endif
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(l1_data_A_sram_free);
+
+void *l1_data_B_sram_alloc(size_t size)
+{
+#if L1_DATA_B_LENGTH != 0
+ unsigned flags;
+ void *addr;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+ addr = _l1_sram_alloc(size, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+ pr_debug("Allocated address in l1_data_B_sram_alloc is 0x%lx+0x%lx\n",
+ (long unsigned int)addr, size);
+
+ return addr;
+#else
+ return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_alloc);
+
+int l1_data_B_sram_free(const void *addr)
+{
+#if L1_DATA_B_LENGTH != 0
+ unsigned flags;
+ int ret;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1_data_sram_lock, flags);
+
+ ret = _l1_sram_free(addr, l1_data_B_sram, ARRAY_SIZE(l1_data_B_sram));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1_data_sram_lock, flags);
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_data_B_sram_free);
+
+void *l1_data_sram_alloc(size_t size)
+{
+ void *addr = l1_data_A_sram_alloc(size);
+
+ if (!addr)
+ addr = l1_data_B_sram_alloc(size);
+
+ return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_alloc);
+
+void *l1_data_sram_zalloc(size_t size)
+{
+ void *addr = l1_data_sram_alloc(size);
+
+ if (addr)
+ memset(addr, 0x00, size);
+
+ return addr;
+}
+EXPORT_SYMBOL(l1_data_sram_zalloc);
+
+int l1_data_sram_free(const void *addr)
+{
+ int ret;
+ ret = l1_data_A_sram_free(addr);
+ if (ret == -1)
+ ret = l1_data_B_sram_free(addr);
+ return ret;
+}
+EXPORT_SYMBOL(l1_data_sram_free);
+
+void *l1_inst_sram_alloc(size_t size)
+{
+#if L1_DATA_A_LENGTH != 0
+ unsigned flags;
+ void *addr;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1_inst_sram_lock, flags);
+
+ addr = _l1_sram_alloc(size, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
+
+ pr_debug("Allocated address in l1_inst_sram_alloc is 0x%lx+0x%lx\n",
+ (long unsigned int)addr, size);
+
+ return addr;
+#else
+ return NULL;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_alloc);
+
+int l1_inst_sram_free(const void *addr)
+{
+#if L1_CODE_LENGTH != 0
+ unsigned flags;
+ int ret;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1_inst_sram_lock, flags);
+
+ ret = _l1_sram_free(addr, l1_inst_sram, ARRAY_SIZE(l1_inst_sram));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1_inst_sram_lock, flags);
+
+ return ret;
+#else
+ return -1;
+#endif
+}
+EXPORT_SYMBOL(l1_inst_sram_free);
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc(size_t size)
+{
+ unsigned flags;
+ void *addr;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1sram_lock, flags);
+
+ addr = _l1_sram_alloc(size, l1_ssram, ARRAY_SIZE(l1_ssram));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1sram_lock, flags);
+
+ return addr;
+}
+
+/* L1 Scratchpad memory allocate function */
+void *l1sram_alloc_max(size_t *psize)
+{
+ unsigned flags;
+ void *addr;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1sram_lock, flags);
+
+ addr = _l1_sram_alloc_max(l1_ssram, ARRAY_SIZE(l1_ssram), psize);
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1sram_lock, flags);
+
+ return addr;
+}
+
+/* L1 Scratchpad memory free function */
+int l1sram_free(const void *addr)
+{
+ unsigned flags;
+ int ret;
+
+ /* add mutex operation */
+ spin_lock_irqsave(&l1sram_lock, flags);
+
+ ret = _l1_sram_free(addr, l1_ssram, ARRAY_SIZE(l1_ssram));
+
+ /* add mutex operation */
+ spin_unlock_irqrestore(&l1sram_lock, flags);
+
+ return ret;
+}
+
+int sram_free_with_lsl(const void *addr)
+{
+ struct sram_list_struct *lsl, **tmp;
+ struct mm_struct *mm = current->mm;
+
+ for (tmp = &mm->context.sram_list; *tmp; tmp = &(*tmp)->next)
+ if ((*tmp)->addr == addr)
+ goto found;
+ return -1;
+found:
+ lsl = *tmp;
+ sram_free(addr);
+ *tmp = lsl->next;
+ kfree(lsl);
+
+ return 0;
+}
+EXPORT_SYMBOL(sram_free_with_lsl);
+
+void *sram_alloc_with_lsl(size_t size, unsigned long flags)
+{
+ void *addr = NULL;
+ struct sram_list_struct *lsl = NULL;
+ struct mm_struct *mm = current->mm;
+
+ lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
+ if (!lsl)
+ return NULL;
+ memset(lsl, 0, sizeof(*lsl));
+
+ if (flags & L1_INST_SRAM)
+ addr = l1_inst_sram_alloc(size);
+
+ if (addr == NULL && (flags & L1_DATA_A_SRAM))
+ addr = l1_data_A_sram_alloc(size);
+
+ if (addr == NULL && (flags & L1_DATA_B_SRAM))
+ addr = l1_data_B_sram_alloc(size);
+
+ if (addr == NULL) {
+ kfree(lsl);
+ return NULL;
+ }
+ lsl->addr = addr;
+ lsl->length = size;
+ lsl->next = mm->context.sram_list;
+ mm->context.sram_list = lsl;
+ return addr;
+}
+EXPORT_SYMBOL(sram_alloc_with_lsl);
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
new file mode 100644
index 00000000000..0fb73b78dd6
--- /dev/null
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -0,0 +1,38 @@
+/*
+ * File: arch/blackfin/mm/blackfin_sram.h
+ * Based on: arch/blackfin/mm/blackfin_sram.c
+ * Author: Mike Frysinger
+ *
+ * Created: Aug 2006
+ * Description: Local prototypes meant for internal use only
+ *
+ * Modified:
+ * Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __BLACKFIN_SRAM_H__
+#define __BLACKFIN_SRAM_H__
+
+extern void l1sram_init(void);
+extern void l1_inst_sram_init(void);
+extern void l1_data_sram_init(void);
+extern void *l1sram_alloc(size_t);
+
+#endif
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
new file mode 100644
index 00000000000..73f72abed43
--- /dev/null
+++ b/arch/blackfin/mm/init.c
@@ -0,0 +1,208 @@
+/*
+ * File: arch/blackfin/mm/init.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <asm/bfin-global.h>
+#include <asm/uaccess.h>
+#include <asm/l1layout.h>
+#include "blackfin_sram.h"
+
+/*
+ * BAD_PAGE is the page that is used for page faults when linux
+ * is out-of-memory. Older versions of linux just did a
+ * do_exit(), but using this instead means there is less risk
+ * for a process dying in kernel mode, possibly leaving a inode
+ * unused etc..
+ *
+ * BAD_PAGETABLE is the accompanying page-table: it is initialized
+ * to point to BAD_PAGE entries.
+ *
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+static unsigned long empty_bad_page_table;
+
+static unsigned long empty_bad_page;
+
+unsigned long empty_zero_page;
+
+void show_mem(void)
+{
+ unsigned long i;
+ int free = 0, total = 0, reserved = 0, shared = 0;
+
+ int cached = 0;
+ printk(KERN_INFO "Mem-info:\n");
+ show_free_areas();
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map + i))
+ reserved++;
+ else if (PageSwapCache(mem_map + i))
+ cached++;
+ else if (!page_count(mem_map + i))
+ free++;
+ else
+ shared += page_count(mem_map + i) - 1;
+ }
+ printk(KERN_INFO "%d pages of RAM\n", total);
+ printk(KERN_INFO "%d free pages\n", free);
+ printk(KERN_INFO "%d reserved pages\n", reserved);
+ printk(KERN_INFO "%d pages shared\n", shared);
+ printk(KERN_INFO "%d pages swap cached\n", cached);
+}
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses of available kernel virtual memory.
+ */
+void paging_init(void)
+{
+ /*
+ * make sure start_mem is page aligned, otherwise bootmem and
+ * page_alloc get different views og the world
+ */
+ unsigned long end_mem = memory_end & PAGE_MASK;
+
+ pr_debug("start_mem is %#lx virtual_end is %#lx\n", PAGE_ALIGN(memory_start), end_mem);
+
+ /*
+ * initialize the bad page table and bad page to point
+ * to a couple of allocated pages
+ */
+ empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
+ memset((void *)empty_zero_page, 0, PAGE_SIZE);
+
+ /*
+ * Set up SFC/DFC registers (user data space)
+ */
+ set_fs(KERNEL_DS);
+
+ pr_debug("free_area_init -> start_mem is %#lx virtual_end is %#lx\n",
+ PAGE_ALIGN(memory_start), end_mem);
+
+ {
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+
+ zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+#ifdef CONFIG_HIGHMEM
+ zones_size[ZONE_HIGHMEM] = 0;
+#endif
+ free_area_init(zones_size);
+ }
+}
+
+void mem_init(void)
+{
+ unsigned int codek = 0, datak = 0, initk = 0;
+ unsigned long tmp;
+ unsigned int len = _ramend - _rambase;
+ unsigned long start_mem = memory_start;
+ unsigned long end_mem = memory_end;
+
+ end_mem &= PAGE_MASK;
+ high_memory = (void *)end_mem;
+
+ start_mem = PAGE_ALIGN(start_mem);
+ max_mapnr = num_physpages = MAP_NR(high_memory);
+ printk(KERN_INFO "Physical pages: %lx\n", num_physpages);
+
+ /* This will put all memory onto the freelists. */
+ totalram_pages = free_all_bootmem();
+
+ codek = (_etext - _stext) >> 10;
+ datak = (__bss_stop - __bss_start) >> 10;
+ initk = (__init_end - __init_begin) >> 10;
+
+ tmp = nr_free_pages() << PAGE_SHIFT;
+ printk(KERN_INFO
+ "Memory available: %luk/%uk RAM, (%uk init code, %uk kernel code, %uk data, %uk dma)\n",
+ tmp >> 10, len >> 10, initk, codek, datak, DMA_UNCACHED_REGION >> 10);
+
+ /* Initialize the blackfin L1 Memory. */
+ l1sram_init();
+ l1_data_sram_init();
+ l1_inst_sram_init();
+
+ /* Allocate this once; never free it. We assume this gives us a
+ pointer to the start of L1 scratchpad memory; panic if it
+ doesn't. */
+ tmp = (unsigned long)l1sram_alloc(sizeof(struct l1_scratch_task_info));
+ if (tmp != (unsigned long)L1_SCRATCH_TASK_INFO) {
+ printk(KERN_EMERG "mem_init(): Did not get the right address from l1sram_alloc: %08lx != %08lx\n",
+ tmp, (unsigned long)L1_SCRATCH_TASK_INFO);
+ panic("No L1, time to give up\n");
+ }
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ int pages = 0;
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ init_page_count(virt_to_page(start));
+ free_page(start);
+ totalram_pages++;
+ pages++;
+ }
+ printk(KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
+}
+#endif
+
+void free_initmem(void)
+{
+#ifdef CONFIG_RAMKERNEL
+ unsigned long addr;
+/*
+ * the following code should be cool even if these sections
+ * are not page aligned.
+ */
+ addr = PAGE_ALIGN((unsigned long)(__init_begin));
+ /* next to check that the page we free is not a partial page */
+ for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
+ addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk(KERN_NOTICE
+ "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
+ (addr - PAGE_ALIGN((long)__init_begin)) >> 10,
+ (int)(PAGE_ALIGN((unsigned long)(__init_begin))),
+ (int)(addr - PAGE_SIZE));
+#endif
+}
diff --git a/arch/blackfin/oprofile/Kconfig b/arch/blackfin/oprofile/Kconfig
new file mode 100644
index 00000000000..0a2fd999c94
--- /dev/null
+++ b/arch/blackfin/oprofile/Kconfig
@@ -0,0 +1,29 @@
+menu "Profiling support"
+depends on EXPERIMENTAL
+
+config PROFILING
+ bool "Profiling support (EXPERIMENTAL)"
+ help
+ Say Y here to enable the extended profiling support mechanisms used
+ by profilers such as OProfile.
+
+config OPROFILE
+ tristate "OProfile system profiling (EXPERIMENTAL)"
+ depends on PROFILING
+ help
+ OProfile is a profiling system capable of profiling the
+ whole system, include the kernel, kernel modules, libraries,
+ and applications.
+
+ If unsure, say N.
+
+config HARDWARE_PM
+ tristate "Hardware Performance Monitor Profiling"
+ depends on PROFILING
+ help
+ take use of hardware performance monitor to profiling the kernel
+ and application.
+
+ If unsure, say N.
+
+endmenu
diff --git a/arch/blackfin/oprofile/Makefile b/arch/blackfin/oprofile/Makefile
new file mode 100644
index 00000000000..634e300d67e
--- /dev/null
+++ b/arch/blackfin/oprofile/Makefile
@@ -0,0 +1,14 @@
+#
+# arch/blackfin/oprofile/Makefile
+#
+
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
+ oprof.o cpu_buffer.o buffer_sync.o \
+ event_buffer.o oprofile_files.o \
+ oprofilefs.o oprofile_stats.o \
+ timer_int.o )
+
+oprofile-y := $(DRIVER_OBJS) common.o
+oprofile-$(CONFIG_HARDWARE_PM) += op_model_bf533.o
diff --git a/arch/blackfin/oprofile/common.c b/arch/blackfin/oprofile/common.c
new file mode 100644
index 00000000000..009a1700c85
--- /dev/null
+++ b/arch/blackfin/oprofile/common.c
@@ -0,0 +1,168 @@
+/*
+ * File: arch/blackfin/oprofile/common.c
+ * Based on: arch/alpha/oprofile/common.c
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include "op_blackfin.h"
+
+#define BFIN_533_ID 0xE5040003
+#define BFIN_537_ID 0xE5040002
+
+static int pfmon_enabled;
+static struct mutex pfmon_lock;
+
+struct op_bfin533_model *model;
+
+struct op_counter_config ctr[OP_MAX_COUNTER];
+
+static int op_bfin_setup(void)
+{
+ int ret;
+
+ /* Pre-compute the values to stuff in the hardware registers. */
+ spin_lock(&oprofilefs_lock);
+ ret = model->reg_setup(ctr);
+ spin_unlock(&oprofilefs_lock);
+
+ return ret;
+}
+
+static void op_bfin_shutdown(void)
+{
+#if 0
+ /* what is the difference between shutdown and stop? */
+#endif
+}
+
+static int op_bfin_start(void)
+{
+ int ret = -EBUSY;
+
+ printk(KERN_INFO "KSDBG:in %s\n", __FUNCTION__);
+ mutex_lock(&pfmon_lock);
+ if (!pfmon_enabled) {
+ ret = model->start(ctr);
+ pfmon_enabled = !ret;
+ }
+ mutex_unlock(&pfmon_lock);
+
+ return ret;
+}
+
+static void op_bfin_stop(void)
+{
+ mutex_lock(&pfmon_lock);
+ if (pfmon_enabled) {
+ model->stop();
+ pfmon_enabled = 0;
+ }
+ mutex_unlock(&pfmon_lock);
+}
+
+static int op_bfin_create_files(struct super_block *sb, struct dentry *root)
+{
+ int i;
+
+ for (i = 0; i < model->num_counters; ++i) {
+ struct dentry *dir;
+ char buf[3];
+ printk(KERN_INFO "Oprofile: creating files... \n");
+
+ snprintf(buf, sizeof buf, "%d", i);
+ dir = oprofilefs_mkdir(sb, root, buf);
+
+ oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
+ oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
+ oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
+ /*
+ * We dont support per counter user/kernel selection, but
+ * we leave the entries because userspace expects them
+ */
+ oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
+ oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
+ oprofilefs_create_ulong(sb, dir, "unit_mask",
+ &ctr[i].unit_mask);
+ }
+
+ return 0;
+}
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+#ifdef CONFIG_HARDWARE_PM
+ unsigned int dspid;
+
+ mutex_init(&pfmon_lock);
+
+ dspid = bfin_read_DSPID();
+
+ printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid);
+
+ switch (dspid) {
+ case BFIN_533_ID:
+ model = &op_model_bfin533;
+ model->num_counters = 2;
+ break;
+ case BFIN_537_ID:
+ model = &op_model_bfin533;
+ model->num_counters = 2;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ ops->cpu_type = model->name;
+ ops->create_files = op_bfin_create_files;
+ ops->setup = op_bfin_setup;
+ ops->shutdown = op_bfin_shutdown;
+ ops->start = op_bfin_start;
+ ops->stop = op_bfin_stop;
+
+ printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
+ ops->cpu_type);
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+void oprofile_arch_exit(void)
+{
+}
diff --git a/arch/blackfin/oprofile/op_blackfin.h b/arch/blackfin/oprofile/op_blackfin.h
new file mode 100644
index 00000000000..f88f446c814
--- /dev/null
+++ b/arch/blackfin/oprofile/op_blackfin.h
@@ -0,0 +1,98 @@
+/*
+ * File: arch/blackfin/oprofile/op_blackfin.h
+ * Based on:
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef OP_BLACKFIN_H
+#define OP_BLACKFIN_H 1
+
+#define OP_MAX_COUNTER 2
+
+#include <asm/blackfin.h>
+
+/* Per-counter configuration as set via oprofilefs. */
+struct op_counter_config {
+ unsigned long valid;
+ unsigned long enabled;
+ unsigned long event;
+ unsigned long count;
+ unsigned long kernel;
+ unsigned long user;
+ unsigned long unit_mask;
+};
+
+/* System-wide configuration as set via oprofilefs. */
+struct op_system_config {
+ unsigned long enable_kernel;
+ unsigned long enable_user;
+};
+
+/* Per-arch configuration */
+struct op_bfin533_model {
+ int (*reg_setup) (struct op_counter_config *);
+ int (*start) (struct op_counter_config *);
+ void (*stop) (void);
+ int num_counters;
+ char *name;
+};
+
+extern struct op_bfin533_model op_model_bfin533;
+
+static inline unsigned int ctr_read(void)
+{
+ unsigned int tmp;
+
+ tmp = bfin_read_PFCTL();
+ __builtin_bfin_csync();
+
+ return tmp;
+}
+
+static inline void ctr_write(unsigned int val)
+{
+ bfin_write_PFCTL(val);
+ __builtin_bfin_csync();
+}
+
+static inline void count_read(unsigned int *count)
+{
+ count[0] = bfin_read_PFCNTR0();
+ count[1] = bfin_read_PFCNTR1();
+ __builtin_bfin_csync();
+}
+
+static inline void count_write(unsigned int *count)
+{
+ bfin_write_PFCNTR0(count[0]);
+ bfin_write_PFCNTR1(count[1]);
+ __builtin_bfin_csync();
+}
+
+extern int pm_overflow_handler(int irq, struct pt_regs *regs);
+
+#endif
diff --git a/arch/blackfin/oprofile/op_model_bf533.c b/arch/blackfin/oprofile/op_model_bf533.c
new file mode 100644
index 00000000000..b7a20a006b4
--- /dev/null
+++ b/arch/blackfin/oprofile/op_model_bf533.c
@@ -0,0 +1,161 @@
+/*
+ * File: arch/blackfin/oprofile/op_model_bf533.c
+ * Based on:
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include "op_blackfin.h"
+
+#define PM_ENABLE 0x01;
+#define PM_CTL1_ENABLE 0x18
+#define PM_CTL0_ENABLE 0xC000
+#define COUNT_EDGE_ONLY 0x3000000
+
+static int oprofile_running;
+
+static unsigned curr_pfctl, curr_count[2];
+
+static int bfin533_reg_setup(struct op_counter_config *ctr)
+{
+ unsigned int pfctl = ctr_read();
+ unsigned int count[2];
+
+ /* set Blackfin perf monitor regs with ctr */
+ if (ctr[0].enabled) {
+ pfctl |= (PM_CTL0_ENABLE | ((char)ctr[0].event << 5));
+ count[0] = 0xFFFFFFFF - ctr[0].count;
+ curr_count[0] = count[0];
+ }
+ if (ctr[1].enabled) {
+ pfctl |= (PM_CTL1_ENABLE | ((char)ctr[1].event << 16));
+ count[1] = 0xFFFFFFFF - ctr[1].count;
+ curr_count[1] = count[1];
+ }
+
+ pr_debug("ctr[0].enabled=%d,ctr[1].enabled=%d,ctr[0].event<<5=0x%x,ctr[1].event<<16=0x%x\n", ctr[0].enabled, ctr[1].enabled, ctr[0].event << 5, ctr[1].event << 16);
+ pfctl |= COUNT_EDGE_ONLY;
+ curr_pfctl = pfctl;
+
+ pr_debug("write 0x%x to pfctl\n", pfctl);
+ ctr_write(pfctl);
+ count_write(count);
+
+ return 0;
+}
+
+static int bfin533_start(struct op_counter_config *ctr)
+{
+ unsigned int pfctl = ctr_read();
+
+ pfctl |= PM_ENABLE;
+ curr_pfctl = pfctl;
+
+ ctr_write(pfctl);
+
+ oprofile_running = 1;
+ pr_debug("start oprofile counter \n");
+
+ return 0;
+}
+
+static void bfin533_stop(void)
+{
+ int pfctl;
+
+ pfctl = ctr_read();
+ pfctl &= ~PM_ENABLE;
+ /* freeze counters */
+ ctr_write(pfctl);
+
+ oprofile_running = 0;
+ pr_debug("stop oprofile counter \n");
+}
+
+static int get_kernel(void)
+{
+ int ipend, is_kernel;
+
+ ipend = bfin_read_IPEND();
+
+ /* test bit 15 */
+ is_kernel = ((ipend & 0x8000) != 0);
+
+ return is_kernel;
+}
+
+int pm_overflow_handler(int irq, struct pt_regs *regs)
+{
+ int is_kernel;
+ int i, cpu;
+ unsigned int pc, pfctl;
+ unsigned int count[2];
+
+ pr_debug("get interrupt in %s\n", __FUNCTION__);
+ if (oprofile_running == 0) {
+ pr_debug("error: entering interrupt when oprofile is stopped.\n\r");
+ return -1;
+ }
+
+ is_kernel = get_kernel();
+ cpu = smp_processor_id();
+ pc = regs->pc;
+ pfctl = ctr_read();
+
+ /* read the two event counter regs */
+ count_read(count);
+
+ /* if the counter overflows, add sample to oprofile buffer */
+ for (i = 0; i < 2; ++i) {
+ if (oprofile_running) {
+ oprofile_add_sample(regs, i);
+ }
+ }
+
+ /* reset the perfmon counter */
+ ctr_write(curr_pfctl);
+ count_write(curr_count);
+ return 0;
+}
+
+struct op_bfin533_model op_model_bfin533 = {
+ .reg_setup = bfin533_reg_setup,
+ .start = bfin533_start,
+ .stop = bfin533_stop,
+ .num_counters = 2,
+ .name = "blackfin/bf533"
+};
diff --git a/arch/blackfin/oprofile/timer_int.c b/arch/blackfin/oprofile/timer_int.c
new file mode 100644
index 00000000000..8fba16c846c
--- /dev/null
+++ b/arch/blackfin/oprofile/timer_int.c
@@ -0,0 +1,74 @@
+/*
+ * File: arch/blackfin/oprofile/timer_int.c
+ * Based on:
+ * Author: Michael Kang
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/oprofile.h>
+
+#include <asm/ptrace.h>
+
+static void enable_sys_timer0()
+{
+}
+static void disable_sys_timer0()
+{
+}
+
+static irqreturn_t sys_timer0_int_handler(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ oprofile_add_sample(regs, 0);
+ return IRQ_HANDLED;
+}
+
+static int sys_timer0_start(void)
+{
+ enable_sys_timer0();
+ return request_irq(IVG11, sys_timer0_int_handler, 0, "sys_timer0", NULL);
+}
+
+static void sys_timer0_stop(void)
+{
+ disable_sys_timer();
+}
+
+int __init sys_timer0_init(struct oprofile_operations *ops)
+{
+ extern int nmi_active;
+
+ if (nmi_active <= 0)
+ return -ENODEV;
+
+ ops->start = timer_start;
+ ops->stop = timer_stop;
+ ops->cpu_type = "timer";
+ printk(KERN_INFO "oprofile: using NMI timer interrupt.\n");
+ return 0;
+}
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index 961c0d58ded..fd2129a0458 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -6,7 +6,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 19bcad05716..41d4a5f9328 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -16,7 +16,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index f64624fc450..1d859c16931 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -603,7 +603,7 @@ config ETRAX_CARDBUS
select HOTPLUG
select PCCARD_NONSTATIC
help
- Enabled the ETRAX Carbus driver.
+ Enabled the ETRAX Cardbus driver.
config PCI
bool
diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c
index 70d3bf0c92e..832fc63504d 100644
--- a/arch/cris/arch-v32/drivers/pci/dma.c
+++ b/arch/cris/arch-v32/drivers/pci/dma.c
@@ -76,7 +76,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
{
void __iomem *mem_base;
int pages = size >> PAGE_SHIFT;
- int bitmap_size = (pages + 31)/32;
+ int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
goto out;
diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c
index 5daeb6f7f3b..79e1e4c2ca1 100644
--- a/arch/cris/arch-v32/kernel/fasttimer.c
+++ b/arch/cris/arch-v32/kernel/fasttimer.c
@@ -603,23 +603,8 @@ void schedule_usleep(unsigned long us)
#ifdef CONFIG_PROC_FS
static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- ,int *eof, void *data_unused
-#else
- ,int unused
-#endif
- );
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
+ ,int *eof, void *data_unused);
static struct proc_dir_entry *fasttimer_proc_entry;
-#else
-static struct proc_dir_entry fasttimer_proc_entry =
-{
- 0, 9, "fasttimer",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, NULL /* ops -- default to array */,
- &proc_fasttimer_read /* get_info */,
-};
-#endif
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_PROC_FS
@@ -628,12 +613,7 @@ static struct proc_dir_entry fasttimer_proc_entry =
#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300)
static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
- ,int *eof, void *data_unused
-#else
- ,int unused
-#endif
- )
+ ,int *eof, void *data_unused)
{
unsigned long flags;
int i = 0;
@@ -808,9 +788,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
memcpy(buf, bigbuf + offset, len);
*start = buf;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
*eof = 1;
-#endif
return len;
}
@@ -974,12 +952,8 @@ void fast_timer_init(void)
printk("fast_timer_init()\n");
#ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 )))
fasttimer_proc_entry->read_proc = proc_fasttimer_read;
-#else
- proc_register_dynamic(&proc_root, &fasttimer_proc_entry);
-#endif
#endif /* PROC_FS */
if(request_irq(TIMER_INTR_VECT, timer_trig_interrupt, IRQF_DISABLED,
"fast timer int", NULL))
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index 82cf2e3624a..d4d57b74133 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -6,7 +6,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S
index e124fcd766d..dfa25e1542b 100644
--- a/arch/cris/arch-v32/vmlinux.lds.S
+++ b/arch/cris/arch-v32/vmlinux.lds.S
@@ -91,6 +91,7 @@ SECTIONS
}
SECURITY_INIT
+ . = ALIGN (8192);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c
index 1f20c16ac2a..105bb5ed48f 100644
--- a/arch/cris/kernel/crisksyms.c
+++ b/arch/cris/kernel/crisksyms.c
@@ -4,7 +4,6 @@
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/pm.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c
index 4cfcae62050..aad0a9e5991 100644
--- a/arch/cris/kernel/profile.c
+++ b/arch/cris/kernel/profile.c
@@ -15,39 +15,47 @@ static int prof_running = 0;
void
cris_profile_sample(struct pt_regs* regs)
{
- if (!prof_running)
- return;
- if (user_mode(regs))
- *(unsigned int*)sample_buffer_pos = current->pid;
- else
- *(unsigned int*)sample_buffer_pos = 0;
- *(unsigned int*)(sample_buffer_pos + 4) = instruction_pointer(regs);
- sample_buffer_pos += 8;
- if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE)
- sample_buffer_pos = sample_buffer;
+ if (!prof_running)
+ return;
+
+ if (user_mode(regs))
+ *(unsigned int*)sample_buffer_pos = current->pid;
+ else
+ *(unsigned int*)sample_buffer_pos = 0;
+
+ *(unsigned int*)(sample_buffer_pos + 4) = instruction_pointer(regs);
+ sample_buffer_pos += 8;
+
+ if (sample_buffer_pos == sample_buffer + SAMPLE_BUFFER_SIZE)
+ sample_buffer_pos = sample_buffer;
}
static ssize_t
-read_cris_profile(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+read_cris_profile(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
{
- unsigned long p = *ppos;
- if (p > SAMPLE_BUFFER_SIZE)
- return 0;
- if (p + count > SAMPLE_BUFFER_SIZE)
- count = SAMPLE_BUFFER_SIZE - p;
- if (copy_to_user(buf, sample_buffer + p,count))
+ unsigned long p = *ppos;
+
+ if (p > SAMPLE_BUFFER_SIZE)
+ return 0;
+
+ if (p + count > SAMPLE_BUFFER_SIZE)
+ count = SAMPLE_BUFFER_SIZE - p;
+ if (copy_to_user(buf, sample_buffer + p,count))
return -EFAULT;
- memset(sample_buffer + p, 0, count);
- *ppos += count;
- return count;
+
+ memset(sample_buffer + p, 0, count);
+ *ppos += count;
+
+ return count;
}
static ssize_t
write_cris_profile(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
- sample_buffer_pos = sample_buffer;
- memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE);
+ sample_buffer_pos = sample_buffer;
+ memset(sample_buffer, 0, SAMPLE_BUFFER_SIZE);
}
static const struct file_operations cris_proc_profile_operations = {
@@ -58,16 +66,23 @@ static const struct file_operations cris_proc_profile_operations = {
static int
__init init_cris_profile(void)
{
- struct proc_dir_entry *entry;
- sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL);
- sample_buffer_pos = sample_buffer;
- entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL);
- if (entry) {
- entry->proc_fops = &cris_proc_profile_operations;
- entry->size = SAMPLE_BUFFER_SIZE;
- }
- prof_running = 1;
- return 0;
+ struct proc_dir_entry *entry;
+
+ sample_buffer = kmalloc(SAMPLE_BUFFER_SIZE, GFP_KERNEL);
+ if (!sample_buffer) {
+ return -ENOMEM;
+ }
+
+ sample_buffer_pos = sample_buffer;
+
+ entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL);
+ if (entry) {
+ entry->proc_fops = &cris_proc_profile_operations;
+ entry->size = SAMPLE_BUFFER_SIZE;
+ }
+ prof_running = 1;
+
+ return 0;
}
__initcall(init_cris_profile);
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c
index 2b6363cbe98..1085d037027 100644
--- a/arch/cris/kernel/ptrace.c
+++ b/arch/cris/kernel/ptrace.c
@@ -67,7 +67,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index cea237413aa..114738a4558 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -45,6 +45,10 @@ config TIME_LOW_RES
bool
default y
+config QUICKLIST
+ bool
+ default y
+
config ARCH_HAS_ILOG2_U32
bool
default y
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 940ac306e9a..43dc08ec751 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1482,6 +1482,16 @@ sys_call_table:
.long sys_faccessat
.long sys_pselect6
.long sys_ppoll
+ .long sys_unshare /* 310 */
+ .long sys_set_robust_list
+ .long sys_get_robust_list
+ .long sys_splice
+ .long sys_sync_file_range
+ .long sys_tee /* 315 */
+ .long sys_vmsplice
+ .long sys_move_pages
+ .long sys_getcpu
+ .long sys_epoll_pwait
syscall_table_size = (. - sys_call_table)
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c
index 87f360a4ea2..c7e59dcadee 100644
--- a/arch/frv/kernel/irq.c
+++ b/arch/frv/kernel/irq.c
@@ -18,7 +18,6 @@
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/irq.h>
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index 515a5cea546..9583a338e9d 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -25,12 +25,14 @@
#include <linux/elf.h>
#include <linux/reboot.h>
#include <linux/interrupt.h>
+#include <linux/pagemap.h>
#include <asm/asm-offsets.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
+#include <asm/tlb.h>
#include <asm/gdb-stub.h>
#include <asm/mb-regs.h>
@@ -88,6 +90,8 @@ void cpu_idle(void)
while (!need_resched()) {
irq_stat[cpu].idle_timestamp = jiffies;
+ check_pgt_cache();
+
if (!frv_dma_inprogress && idle)
idle();
}
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
index fcff819b434..ce88fb95ee5 100644
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/frv/kernel/semaphore.c b/arch/frv/kernel/semaphore.c
index f278cdf3a72..8e182ced1a0 100644
--- a/arch/frv/kernel/semaphore.c
+++ b/arch/frv/kernel/semaphore.c
@@ -19,7 +19,7 @@ struct sem_waiter {
struct task_struct *task;
};
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
void semtrace(struct semaphore *sem, const char *str)
{
if (sem->debug)
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index 8ea3ca2aba6..aa3c795d535 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -191,7 +191,7 @@ static struct clock_cmode __pminitdata clock_cmodes_fr555[16] = {
static const struct clock_cmode __pminitdata *clock_cmodes;
static int __pminitdata clock_doubled;
-static struct uart_port __initdata __frv_uart0 = {
+static struct uart_port __pminitdata __frv_uart0 = {
.uartclk = 0,
.membase = (char *) UART0_BASE,
.irq = IRQ_CPU_UART0,
@@ -200,7 +200,7 @@ static struct uart_port __initdata __frv_uart0 = {
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
};
-static struct uart_port __initdata __frv_uart1 = {
+static struct uart_port __pminitdata __frv_uart1 = {
.uartclk = 0,
.membase = (char *) UART1_BASE,
.irq = IRQ_CPU_UART1,
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index 85baeae9666..d64bcaff54c 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/frv/kernel/sys_frv.c b/arch/frv/kernel/sys_frv.c
index c4d4348c9e8..26b3df32b9a 100644
--- a/arch/frv/kernel/sys_frv.c
+++ b/arch/frv/kernel/sys_frv.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 97910e01682..28eae9735ad 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -57,6 +57,7 @@ SECTIONS
__alt_instructions_end = .;
.altinstr_replacement : { *(.altinstr_replacement) }
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/frv/mm/elf-fdpic.c b/arch/frv/mm/elf-fdpic.c
index 9477ccce070..385fd30b142 100644
--- a/arch/frv/mm/elf-fdpic.c
+++ b/arch/frv/mm/elf-fdpic.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/elf-fdpic.h>
+#include <asm/mman.h>
/*****************************************************************************/
/*
@@ -64,6 +65,10 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
if (len > TASK_SIZE)
return -ENOMEM;
+ /* handle MAP_FIXED */
+ if (flags & MAP_FIXED)
+ return addr;
+
/* only honour a hint if we're not going to clobber something doing so */
if (addr) {
addr = PAGE_ALIGN(addr);
diff --git a/arch/frv/mm/pgalloc.c b/arch/frv/mm/pgalloc.c
index 19b13be114a..7787c3cc52c 100644
--- a/arch/frv/mm/pgalloc.c
+++ b/arch/frv/mm/pgalloc.c
@@ -13,12 +13,12 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/highmem.h>
+#include <linux/quicklist.h>
#include <asm/pgalloc.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((aligned(PAGE_SIZE)));
-struct kmem_cache *pgd_cache;
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
{
@@ -100,7 +100,7 @@ static inline void pgd_list_del(pgd_t *pgd)
set_page_private(next, (unsigned long) pprev);
}
-void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+void pgd_ctor(void *pgd)
{
unsigned long flags;
@@ -120,7 +120,7 @@ void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
}
/* never called when PTRS_PER_PMD > 1 */
-void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+void pgd_dtor(void *pgd)
{
unsigned long flags; /* can be called from interrupt context */
@@ -133,7 +133,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
{
pgd_t *pgd;
- pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
+ pgd = quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
if (!pgd)
return pgd;
@@ -143,17 +143,15 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
void pgd_free(pgd_t *pgd)
{
/* in the non-PAE case, clear_page_tables() clears user pgd entries */
- kmem_cache_free(pgd_cache, pgd);
+ quicklist_free(0, pgd_dtor, pgd);
}
void __init pgtable_cache_init(void)
{
- pgd_cache = kmem_cache_create("pgd",
- PTRS_PER_PGD * sizeof(pgd_t),
- PTRS_PER_PGD * sizeof(pgd_t),
- 0,
- pgd_ctor,
- pgd_dtor);
- if (!pgd_cache)
- panic("pgtable_cache_init(): Cannot create pgd cache");
}
+
+void check_pgt_cache(void)
+{
+ quicklist_trim(0, pgd_dtor, 25, 16);
+}
+
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 1734d96422c..618dbad696f 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -49,10 +49,18 @@ config GENERIC_HWEIGHT
bool
default y
+config GENERIC_HARDIRQS
+ bool
+ default y
+
config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_TIME
+ bool
+ default y
+
config TIME_LOW_RES
bool
default y
diff --git a/arch/h8300/Kconfig.debug b/arch/h8300/Kconfig.debug
index e0e9bcb015a..554efe604a0 100644
--- a/arch/h8300/Kconfig.debug
+++ b/arch/h8300/Kconfig.debug
@@ -21,12 +21,12 @@ config GDB_MAGICPRINT
bool "Message Output for GDB MagicPrint service"
depends on (H8300H_SIM || H8S_SIM)
help
- kernel messages output useing MagicPrint service from GDB
+ kernel messages output using MagicPrint service from GDB
config SYSCALL_PRINT
bool "SystemCall trace print"
help
- outout history of systemcall
+ output history of systemcall
config GDB_DEBUG
bool "Use gdb stub"
diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile
index 40b3f56f366..b2d896a7e59 100644
--- a/arch/h8300/Makefile
+++ b/arch/h8300/Makefile
@@ -41,7 +41,7 @@ LDFLAGS += $(ldflags-y)
CROSS_COMPILE = h8300-elf-
LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(CFLAGS) -print-libgcc-file-name)
-head-y := arch/$(ARCH)/platform/$(platform-y)/$(board-y)/crt0_$(model-y).o
+head-y := arch/$(ARCH)/platform/$(PLATFORM)/$(BOARD)/crt0_$(MODEL).o
core-y += arch/$(ARCH)/kernel/ \
arch/$(ARCH)/mm/
diff --git a/arch/h8300/boot/Makefile b/arch/h8300/boot/Makefile
index 65086d925ca..0bb62e064ee 100644
--- a/arch/h8300/boot/Makefile
+++ b/arch/h8300/boot/Makefile
@@ -1,12 +1,22 @@
# arch/h8300/boot/Makefile
-targets := vmlinux.srec vmlinux.bin
+targets := vmlinux.srec vmlinux.bin zImage
+subdir- := compressed
OBJCOPYFLAGS_vmlinux.srec := -Osrec
OBJCOPYFLAGS_vmlinux.bin := -Obinary
+OBJCOPYFLAGS_zImage := -O binary -R .note -R .comment -R .stab -R .stabstr -S
$(obj)/vmlinux.srec $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
@echo ' Kernel: $@ is ready'
+$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
+ $(call if_changed,objcopy)
+ @echo 'Kernel: $@ is ready'
+
+$(obj)/compressed/vmlinux: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
+
CLEAN_FILES += arch/$(ARCH)/vmlinux.bin arch/$(ARCH)/vmlinux.srec
+
diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile
new file mode 100644
index 00000000000..71aac82a8ae
--- /dev/null
+++ b/arch/h8300/boot/compressed/Makefile
@@ -0,0 +1,37 @@
+#
+# linux/arch/sh/boot/compressed/Makefile
+#
+# create a compressed vmlinux image from the original vmlinux
+#
+
+targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
+EXTRA_AFLAGS := -traditional
+
+OBJECTS = $(obj)/head.o $(obj)/misc.o
+
+#
+# IMAGE_OFFSET is the load offset of the compression loader
+# Assign dummy values if these 2 variables are not defined,
+# in order to suppress error message.
+#
+CONFIG_MEMORY_START ?= 0x00400000
+CONFIG_BOOT_LINK_OFFSET ?= 0x00400000
+IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
+
+LDFLAGS_vmlinux := -T $(obj)/vmlinux.lds
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+ $(call if_changed,ld)
+ @:
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+LDFLAGS_piggy.o := -r --format binary --oformat elf32-h8300 -T
+OBJCOPYFLAGS := -O binary
+
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
+ $(call if_changed,ld)
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
new file mode 100644
index 00000000000..b8e90d12d19
--- /dev/null
+++ b/arch/h8300/boot/compressed/head.S
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/h8300/boot/compressed/head.S
+ *
+ * Copyright (C) 2006 Yoshinori Sato
+ */
+
+.h8300h
+#include <linux/linkage.h>
+
+#define SRAM_START 0xff4000
+
+ .section .text.startup
+ .global startup
+startup:
+ mov.l #SRAM_START+0x8000, sp
+ mov.l #__sbss, er0
+ mov.l #__ebss, er1
+ sub.l er0, er1
+ shlr er1
+ shlr er1
+ sub.l er2, er2
+1:
+ mov.l er2, @er0
+ adds #4, er0
+ dec.l #1, er1
+ bne 1b
+ jsr @_decompress_kernel
+ jmp @0x400000
+
+ .align 9
+fake_headers_as_bzImage:
+ .word 0
+ .ascii "HdrS" ; header signature
+ .word 0x0202 ; header version number (>= 0x0105)
+ ; or else old loadlin-1.5 will fail)
+ .word 0 ; default_switch
+ .word 0 ; SETUPSEG
+ .word 0x1000
+ .word 0 ; pointing to kernel version string
+ .byte 0 ; = 0, old one (LILO, Loadlin,
+ ; 0xTV: T=0 for LILO
+ ; V = version
+ .byte 1 ; Load flags bzImage=1
+ .word 0x8000 ; size to move, when setup is not
+ .long 0x100000 ; 0x100000 = default for big kernel
+ .long 0 ; address of loaded ramdisk image
+ .long 0 ; its size in bytes
diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c
new file mode 100644
index 00000000000..845074588af
--- /dev/null
+++ b/arch/h8300/boot/compressed/misc.c
@@ -0,0 +1,219 @@
+/*
+ * arch/h8300/boot/compressed/misc.c
+ *
+ * This is a collection of several routines from gzip-1.0.3
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ *
+ * Adapted for h8300 by Yoshinori Sato 2006
+ */
+
+#include <asm/uaccess.h>
+
+/*
+ * gzip declarations
+ */
+
+#define OF(args) args
+#define STATIC static
+
+#undef memset
+#undef memcpy
+#define memzero(s, n) memset ((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define WSIZE 0x8000 /* Window size must be at least 32k, */
+ /* and a power of two */
+
+static uch *inbuf; /* input buffer */
+static uch window[WSIZE]; /* Sliding window buffer */
+
+static unsigned insize = 0; /* valid bytes in inbuf */
+static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
+static unsigned outcnt = 0; /* bytes in output buffer */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
+#define RESERVED 0xC0 /* bit 6,7: reserved */
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond,msg) {if(!(cond)) error(msg);}
+# define Trace(x) fprintf x
+# define Tracev(x) {if (verbose) fprintf x ;}
+# define Tracevv(x) {if (verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+static int fill_inbuf(void);
+static void flush_window(void);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+extern char input_data[];
+extern int input_len;
+
+static long bytes_out = 0;
+static uch *output_data;
+static unsigned long output_ptr = 0;
+
+static void *malloc(int size);
+static void free(void *where);
+static void error(char *m);
+static void gzip_mark(void **);
+static void gzip_release(void **);
+
+int puts(const char *);
+
+extern int _text; /* Defined in vmlinux.lds.S */
+extern int _end;
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#define HEAP_SIZE 0x10000
+
+#include "../../../../lib/inflate.c"
+
+#define SCR *((volatile unsigned char *)0xffff8a)
+#define TDR *((volatile unsigned char *)0xffff8b)
+#define SSR *((volatile unsigned char *)0xffff8c)
+
+static void *malloc(int size)
+{
+ void *p;
+
+ if (size <0) error("Malloc error");
+ if (free_mem_ptr == 0) error("Memory error");
+
+ free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
+
+ p = (void *)free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_end_ptr)
+ error("Out of memory");
+
+ return p;
+}
+
+static void free(void *where)
+{ /* Don't care */
+}
+
+static void gzip_mark(void **ptr)
+{
+ *ptr = (void *) free_mem_ptr;
+}
+
+static void gzip_release(void **ptr)
+{
+ free_mem_ptr = (long) *ptr;
+}
+
+int puts(const char *s)
+{
+ return 0;
+}
+
+void* memset(void* s, int c, size_t n)
+{
+ int i;
+ char *ss = (char*)s;
+
+ for (i=0;i<n;i++) ss[i] = c;
+ return s;
+}
+
+void* memcpy(void* __dest, __const void* __src,
+ size_t __n)
+{
+ int i;
+ char *d = (char *)__dest, *s = (char *)__src;
+
+ for (i=0;i<__n;i++) d[i] = s[i];
+ return __dest;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+static int fill_inbuf(void)
+{
+ if (insize != 0) {
+ error("ran out of input data");
+ }
+
+ inbuf = input_data;
+ insize = input_len;
+ inptr = 1;
+ return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+static void flush_window(void)
+{
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, *out, ch;
+
+ in = window;
+ out = &output_data[output_ptr];
+ for (n = 0; n < outcnt; n++) {
+ ch = *out++ = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ output_ptr += (ulg)outcnt;
+ outcnt = 0;
+}
+
+static void error(char *x)
+{
+ puts("\n\n");
+ puts(x);
+ puts("\n\n -- System halted");
+
+ while(1); /* Halt */
+}
+
+#define STACK_SIZE (4096)
+long user_stack [STACK_SIZE];
+long* stack_start = &user_stack[STACK_SIZE];
+
+void decompress_kernel(void)
+{
+ output_data = 0;
+ output_ptr = (unsigned long)0x400000;
+ free_mem_ptr = (unsigned long)&_end;
+ free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
+
+ makecrc();
+ puts("Uncompressing Linux... ");
+ gunzip();
+ puts("Ok, booting the kernel.\n");
+}
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile
index 4edbc2ef6ca..ccc1a7fbf94 100644
--- a/arch/h8300/kernel/Makefile
+++ b/arch/h8300/kernel/Makefile
@@ -4,10 +4,8 @@
extra-y := vmlinux.lds
-obj-y := process.o traps.o ptrace.o ints.o \
+obj-y := process.o traps.o ptrace.o irq.o \
sys_h8300.o time.o semaphore.o signal.o \
- setup.o gpio.o init_task.o syscalls.o devres.o
-
-devres-y = ../../../kernel/irq/devres.o
+ setup.o gpio.o init_task.o syscalls.o
obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o
diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c
index b78b82ad28a..fc30b4fd091 100644
--- a/arch/h8300/kernel/asm-offsets.c
+++ b/arch/h8300/kernel/asm-offsets.c
@@ -30,7 +30,7 @@ int main(void)
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
- DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+ DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c
new file mode 100644
index 00000000000..43d21e93f41
--- /dev/null
+++ b/arch/h8300/kernel/irq.c
@@ -0,0 +1,211 @@
+/*
+ * linux/arch/h8300/kernel/irq.c
+ *
+ * Copyright 2007 Yoshinori Sato <ysato@users.sourceforge.jp>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/errno.h>
+
+/*#define DEBUG*/
+
+extern unsigned long *interrupt_redirect_table;
+extern const int h8300_saved_vectors[];
+extern const unsigned long h8300_trap_table[];
+int h8300_enable_irq_pin(unsigned int irq);
+void h8300_disable_irq_pin(unsigned int irq);
+
+#define CPU_VECTOR ((unsigned long *)0x000000)
+#define ADDR_MASK (0xffffff)
+
+static inline int is_ext_irq(unsigned int irq)
+{
+ return (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS));
+}
+
+static void h8300_enable_irq(unsigned int irq)
+{
+ if (is_ext_irq(irq))
+ IER_REGS |= 1 << (irq - EXT_IRQ0);
+}
+
+static void h8300_disable_irq(unsigned int irq)
+{
+ if (is_ext_irq(irq))
+ IER_REGS &= ~(1 << (irq - EXT_IRQ0));
+}
+
+static void h8300_end_irq(unsigned int irq)
+{
+}
+
+static unsigned int h8300_startup_irq(unsigned int irq)
+{
+ if (is_ext_irq(irq))
+ return h8300_enable_irq_pin(irq);
+ else
+ return 0;
+}
+
+static void h8300_shutdown_irq(unsigned int irq)
+{
+ if (is_ext_irq(irq))
+ h8300_disable_irq_pin(irq);
+}
+
+/*
+ * h8300 interrupt controler implementation
+ */
+struct irq_chip h8300irq_chip = {
+ .name = "H8300-INTC",
+ .startup = h8300_startup_irq,
+ .shutdown = h8300_shutdown_irq,
+ .enable = h8300_enable_irq,
+ .disable = h8300_disable_irq,
+ .ack = NULL,
+ .end = h8300_end_irq,
+};
+
+void ack_bad_irq(unsigned int irq)
+{
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+#if defined(CONFIG_RAMKERNEL)
+static unsigned long __init *get_vector_address(void)
+{
+ unsigned long *rom_vector = CPU_VECTOR;
+ unsigned long base,tmp;
+ int vec_no;
+
+ base = rom_vector[EXT_IRQ0] & ADDR_MASK;
+
+ /* check romvector format */
+ for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) {
+ if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK))
+ return NULL;
+ }
+
+ /* ramvector base address */
+ base -= EXT_IRQ0*4;
+
+ /* writerble check */
+ tmp = ~(*(volatile unsigned long *)base);
+ (*(volatile unsigned long *)base) = tmp;
+ if ((*(volatile unsigned long *)base) != tmp)
+ return NULL;
+ return (unsigned long *)base;
+}
+
+static void __init setup_vector(void)
+{
+ int i;
+ unsigned long *ramvec,*ramvec_p;
+ const unsigned long *trap_entry;
+ const int *saved_vector;
+
+ ramvec = get_vector_address();
+ if (ramvec == NULL)
+ panic("interrupt vector serup failed.");
+ else
+ printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec);
+
+ /* create redirect table */
+ ramvec_p = ramvec;
+ trap_entry = h8300_trap_table;
+ saved_vector = h8300_saved_vectors;
+ for ( i = 0; i < NR_IRQS; i++) {
+ if (i == *saved_vector) {
+ ramvec_p++;
+ saved_vector++;
+ } else {
+ if ( i < NR_TRAPS ) {
+ if (*trap_entry)
+ *ramvec_p = VECTOR(*trap_entry);
+ ramvec_p++;
+ trap_entry++;
+ } else
+ *ramvec_p++ = REDIRECT(interrupt_entry);
+ }
+ }
+ interrupt_redirect_table = ramvec;
+#ifdef DEBUG
+ ramvec_p = ramvec;
+ for (i = 0; i < NR_IRQS; i++) {
+ if ((i % 8) == 0)
+ printk(KERN_DEBUG "\n%p: ",ramvec_p);
+ printk(KERN_DEBUG "%p ",*ramvec_p);
+ ramvec_p++;
+ }
+ printk(KERN_DEBUG "\n");
+#endif
+}
+#else
+#define setup_vector() do { } while(0)
+#endif
+
+void __init init_IRQ(void)
+{
+ int c;
+
+ setup_vector();
+
+ for (c = 0; c < NR_IRQS; c++) {
+ irq_desc[c].status = IRQ_DISABLED;
+ irq_desc[c].action = NULL;
+ irq_desc[c].depth = 1;
+ irq_desc[c].chip = &h8300irq_chip;
+ }
+}
+
+asmlinkage void do_IRQ(int irq)
+{
+ irq_enter();
+ __do_IRQ(irq);
+ irq_exit();
+}
+
+#if defined(CONFIG_PROC_FS)
+int show_interrupts(struct seq_file *p, void *v)
+{
+ int i = *(loff_t *) v, j;
+ struct irqaction * action;
+ unsigned long flags;
+
+ if (i == 0)
+ seq_puts(p, " CPU0");
+
+ if (i < NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto unlock;
+ seq_printf(p, "%3d: ",i);
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ seq_printf(p, " %14s", irq_desc[i].chip->name);
+ seq_printf(p, "-%-8s", irq_desc[i].name);
+ seq_printf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+ seq_putc(p, '\n');
+unlock:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ }
+ return 0;
+}
+#endif
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index f6031373dc2..8f2411db7ea 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c
index 313cd808104..b2e86d0255e 100644
--- a/arch/h8300/kernel/setup.c
+++ b/arch/h8300/kernel/setup.c
@@ -33,10 +33,7 @@
#include <asm/setup.h>
#include <asm/irq.h>
-
-#ifdef CONFIG_BLK_DEV_INITRD
#include <asm/pgtable.h>
-#endif
#if defined(__H8300H__)
#define CPU "H8/300H"
diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c
index 302a2dfe634..11ba75a0522 100644
--- a/arch/h8300/kernel/sys_h8300.c
+++ b/arch/h8300/kernel/sys_h8300.c
@@ -10,7 +10,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
index d1ef615ba89..330638220a2 100644
--- a/arch/h8300/kernel/time.c
+++ b/arch/h8300/kernel/time.c
@@ -44,7 +44,7 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
}
void time_init(void)
@@ -66,55 +66,3 @@ void time_init(void)
platform_timer_setup(timer_interrupt);
}
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long flags;
- unsigned long usec, sec;
-
- read_lock_irqsave(&xtime_lock, flags);
- usec = 0;
- sec = xtime.tv_sec;
- usec += (xtime.tv_nsec / 1000);
- read_unlock_irqrestore(&xtime_lock, flags);
-
- while (usec >= 1000000) {
- usec -= 1000000;
- sec++;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_lock_irq(&xtime_lock);
- /* This is revolting. We need to set the xtime.tv_usec
- * correctly. However, the value in this location is
- * is value at the last tick.
- * Discover what correction gettimeofday
- * would have done, and then undo it!
- */
- while (tv->tv_nsec < 0) {
- tv->tv_nsec += NSEC_PER_SEC;
- tv->tv_sec--;
- }
-
- xtime.tv_sec = tv->tv_sec;
- xtime.tv_nsec = tv->tv_nsec;
- ntp_clear();
- write_sequnlock_irq(&xtime_lock);
- clock_was_set();
- return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
diff --git a/arch/h8300/mm/kmap.c b/arch/h8300/mm/kmap.c
index 26ab17286a5..5c7af09ae8d 100644
--- a/arch/h8300/mm/kmap.c
+++ b/arch/h8300/mm/kmap.c
@@ -24,12 +24,14 @@
#undef DEBUG
+#define VIRT_OFFSET (0x01000000)
+
/*
* Map some physical address range into the kernel address space.
*/
void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
{
- return (void *)physaddr;
+ return (void *)(physaddr + VIRT_OFFSET);
}
/*
diff --git a/arch/h8300/platform/h8300h/Makefile b/arch/h8300/platform/h8300h/Makefile
index 5d42c772f75..b24ea08aa0a 100644
--- a/arch/h8300/platform/h8300h/Makefile
+++ b/arch/h8300/platform/h8300h/Makefile
@@ -4,4 +4,4 @@
# Reuse any files we can from the H8/300H
#
-obj-y := entry.o ints_h8300h.o ptrace_h8300h.o
+obj-y := entry.o irq_pin.o ptrace_h8300h.o
diff --git a/arch/h8300/platform/h8300h/entry.S b/arch/h8300/platform/h8300h/entry.S
index d2dea2432fb..f86ac3b5d4d 100644
--- a/arch/h8300/platform/h8300h/entry.S
+++ b/arch/h8300/platform/h8300h/entry.S
@@ -30,12 +30,12 @@
mov.l er0,@-sp
stc ccr,r0l /* check kernel mode */
- orc #0x10,ccr
btst #4,r0l
bne 5f
mov.l sp,@SYMBOL_NAME(sw_usp) /* user mode */
mov.l @sp,er0
+ orc #0x10,ccr
mov.l @SYMBOL_NAME(sw_ksp),sp
sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
mov.l er0,@-sp
@@ -165,7 +165,7 @@ SYMBOL_NAME_LABEL(interrupt_entry)
dec.l #1,er0
mov.l sp,er1
subs #4,er1 /* adjust ret_pc */
- jsr @SYMBOL_NAME(process_int)
+ jsr @SYMBOL_NAME(do_IRQ)
mov.l @SYMBOL_NAME(irq_stat)+CPUSTAT_SOFTIRQ_PENDING,er0
beq 1f
jsr @SYMBOL_NAME(do_softirq)
diff --git a/arch/h8300/platform/h8300h/generic/Makefile b/arch/h8300/platform/h8300h/generic/Makefile
index b6ea7688a61..32b964a9010 100644
--- a/arch/h8300/platform/h8300h/generic/Makefile
+++ b/arch/h8300/platform/h8300h/generic/Makefile
@@ -2,5 +2,5 @@
# Makefile for the linux kernel.
#
+extra-y := crt0_$(MODEL).o
obj-y := timer.o
-extra-y = crt0_$(MODEL).o
diff --git a/arch/h8300/platform/h8300h/ints_h8300h.c b/arch/h8300/platform/h8300h/ints_h8300h.c
deleted file mode 100644
index f1777119b87..00000000000
--- a/arch/h8300/platform/h8300h/ints_h8300h.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8300h/ints_h8300h.c
- * Interrupt handling CPU variants
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- */
-
-#include <linux/init.h>
-#include <linux/errno.h>
-
-#include <asm/ptrace.h>
-#include <asm/traps.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/gpio.h>
-#include <asm/regs306x.h>
-
-/* saved vector list */
-const int __initdata h8300_saved_vectors[]={
-#if defined(CONFIG_GDB_DEBUG)
- TRAP3_VEC,
-#endif
- -1
-};
-
-/* trap entry table */
-const unsigned long __initdata h8300_trap_table[NR_TRAPS]={
- 0,0,0,0,0,0,0,0,
- (unsigned long)system_call, /* TRAPA #0 */
- 0,0,
- (unsigned long)trace_break, /* TRAPA #3 */
-};
-
-int h8300_enable_irq_pin(unsigned int irq)
-{
- int bitmask;
- if (irq < EXT_IRQ0 || irq > EXT_IRQ5)
- return 0;
-
- /* initialize IRQ pin */
- bitmask = 1 << (irq - EXT_IRQ0);
- switch(irq) {
- case EXT_IRQ0:
- case EXT_IRQ1:
- case EXT_IRQ2:
- case EXT_IRQ3:
- if (H8300_GPIO_RESERVE(H8300_GPIO_P8, bitmask) == 0)
- return -EBUSY;
- H8300_GPIO_DDR(H8300_GPIO_P8, bitmask, H8300_GPIO_INPUT);
- break;
- case EXT_IRQ4:
- case EXT_IRQ5:
- if (H8300_GPIO_RESERVE(H8300_GPIO_P9, bitmask) == 0)
- return -EBUSY;
- H8300_GPIO_DDR(H8300_GPIO_P9, bitmask, H8300_GPIO_INPUT);
- break;
- }
-
- return 0;
-}
-
-void h8300_disable_irq_pin(unsigned int irq)
-{
- int bitmask;
- if (irq < EXT_IRQ0 || irq > EXT_IRQ5)
- return;
-
- /* disable interrupt & release IRQ pin */
- bitmask = 1 << (irq - EXT_IRQ0);
- switch(irq) {
- case EXT_IRQ0:
- case EXT_IRQ1:
- case EXT_IRQ2:
- case EXT_IRQ3:
- *(volatile unsigned char *)IER &= ~bitmask;
- H8300_GPIO_FREE(H8300_GPIO_P8, bitmask);
- break ;
- case EXT_IRQ4:
- case EXT_IRQ5:
- *(volatile unsigned char *)IER &= ~bitmask;
- H8300_GPIO_FREE(H8300_GPIO_P9, bitmask);
- break;
- }
-}
diff --git a/arch/h8300/platform/h8s/entry.S b/arch/h8300/platform/h8s/entry.S
index aeb2e9faa9b..f3d6b8e8f95 100644
--- a/arch/h8300/platform/h8s/entry.S
+++ b/arch/h8300/platform/h8s/entry.S
@@ -31,12 +31,13 @@
mov.l er0,@-sp
stc ccr,r0l /* check kernel mode */
- orc #0x10,ccr
btst #4,r0l
bne 5f
- mov.l sp,@SYMBOL_NAME(sw_usp) /* user mode */
- mov.l @sp,er0
+ /* user mode */
+ mov.l sp,@SYMBOL_NAME(sw_usp)
+ mov.l @sp,er0 /* restore saved er0 */
+ orc #0x10,ccr /* switch kernel stack */
mov.l @SYMBOL_NAME(sw_ksp),sp
sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
stm.l er0-er3,@-sp
@@ -55,8 +56,9 @@
mov.l er0,@(LER0-LER3:16,sp) /* copy ER0 */
bra 6f
5:
- mov.l @sp,er0 /* kernel mode */
- subs #2,sp /* dummy ccr */
+ /* kernel mode */
+ mov.l @sp,er0 /* restore saved er0 */
+ subs #2,sp /* set dummy ccr */
stm.l er0-er3,@-sp
mov.w @(LRET-LER3:16,sp),r1 /* copy old ccr */
mov.b r1h,r1l
@@ -94,6 +96,7 @@
mov.l @sp+,er1
add.l #(LRET-LER1),sp /* remove LORIG - LRET */
mov.l sp,@SYMBOL_NAME(sw_ksp)
+ andc #0xef,ccr /* switch to user mode */
mov.l er0,sp
bra 8f
7:
@@ -173,9 +176,6 @@ SYMBOL_NAME_LABEL(interrupt_entry)
SYMBOL_NAME_LABEL(system_call)
subs #4,sp /* dummy LVEC */
SAVE_ALL
- mov.w @(LCCR:16,sp),r1
- bset #4,r1l
- ldc r1l,ccr /* restore ccr */
mov.l er0,er4
mov.l #-ENOSYS,er0
mov.l er0,@(LER0:16,sp)
@@ -198,6 +198,7 @@ SYMBOL_NAME_LABEL(system_call)
mov.l @(LER1:16,sp),er0
mov.l @(LER2:16,sp),er1
mov.l @(LER3:16,sp),er2
+ andc #0x7f,ccr
jsr @er4
mov.l er0,@(LER0:16,sp) /* save the return value */
#if defined(CONFIG_SYSCALL_PRINT)
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 53d62373a52..30944ee2e61 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -79,6 +79,10 @@ config ARCH_MAY_HAVE_PC_FDC
bool
default y
+config ARCH_USES_SLAB_PAGE_STRUCT
+ bool
+ default y
+
config DMI
bool
default y
@@ -220,7 +224,7 @@ config PARAVIRT
config VMI
bool "VMI Paravirt-ops support"
- depends on PARAVIRT && !COMPAT_VDSO
+ depends on PARAVIRT
help
VMI provides a paravirtualized interface to the VMware ESX server
(it could be used by other hypervisors in theory too, but is not
@@ -571,6 +575,9 @@ choice
bool "3G/1G user/kernel split (for full 1G low memory)"
config VMSPLIT_2G
bool "2G/2G user/kernel split"
+ config VMSPLIT_2G_OPT
+ depends on !HIGHMEM
+ bool "2G/2G user/kernel split (for full 2G low memory)"
config VMSPLIT_1G
bool "1G/3G user/kernel split"
endchoice
@@ -578,7 +585,8 @@ endchoice
config PAGE_OFFSET
hex
default 0xB0000000 if VMSPLIT_3G_OPT
- default 0x78000000 if VMSPLIT_2G
+ default 0x80000000 if VMSPLIT_2G
+ default 0x78000000 if VMSPLIT_2G_OPT
default 0x40000000 if VMSPLIT_1G
default 0xC0000000
@@ -850,9 +858,9 @@ config RELOCATABLE
bool "Build a relocatable kernel(EXPERIMENTAL)"
depends on EXPERIMENTAL
help
- This build a kernel image that retains relocation information
+ This builds a kernel image that retains relocation information
so it can be loaded someplace besides the default 1MB.
- The relocations tend to the kernel binary about 10% larger,
+ The relocations tend to make the kernel binary about 10% larger,
but are discarded at runtime.
One use is for the kexec on panic case where the recovery kernel
@@ -915,12 +923,9 @@ source kernel/power/Kconfig
source "drivers/acpi/Kconfig"
-menu "APM (Advanced Power Management) BIOS Support"
-depends on PM && !X86_VISWS
-
-config APM
+menuconfig APM
tristate "APM (Advanced Power Management) BIOS support"
- depends on PM
+ depends on PM && !X86_VISWS
---help---
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
@@ -977,9 +982,10 @@ config APM
To compile this driver as a module, choose M here: the
module will be called apm.
+if APM
+
config APM_IGNORE_USER_SUSPEND
bool "Ignore USER SUSPEND"
- depends on APM
help
This option will ignore USER SUSPEND requests. On machines with a
compliant APM BIOS, you want to say N. However, on the NEC Versa M
@@ -987,7 +993,6 @@ config APM_IGNORE_USER_SUSPEND
config APM_DO_ENABLE
bool "Enable PM at boot time"
- depends on APM
---help---
Enable APM features at boot time. From page 36 of the APM BIOS
specification: "When disabled, the APM BIOS does not automatically
@@ -1005,7 +1010,6 @@ config APM_DO_ENABLE
config APM_CPU_IDLE
bool "Make CPU Idle calls when idle"
- depends on APM
help
Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
On some machines, this can activate improved power savings, such as
@@ -1017,7 +1021,6 @@ config APM_CPU_IDLE
config APM_DISPLAY_BLANK
bool "Enable console blanking using APM"
- depends on APM
help
Enable console blanking using the APM. Some laptops can use this to
turn off the LCD backlight when the screen blanker of the Linux
@@ -1029,22 +1032,8 @@ config APM_DISPLAY_BLANK
backlight at all, or it might print a lot of errors to the console,
especially if you are using gpm.
-config APM_RTC_IS_GMT
- bool "RTC stores time in GMT"
- depends on APM
- help
- Say Y here if your RTC (Real Time Clock a.k.a. hardware clock)
- stores the time in GMT (Greenwich Mean Time). Say N if your RTC
- stores localtime.
-
- It is in fact recommended to store GMT in your RTC, because then you
- don't have to worry about daylight savings time changes. The only
- reason not to use GMT in your RTC is if you also run a broken OS
- that doesn't understand GMT.
-
config APM_ALLOW_INTS
bool "Allow interrupts during APM BIOS calls"
- depends on APM
help
Normally we disable external interrupts while we are making calls to
the APM BIOS as a measure to lessen the effects of a badly behaving
@@ -1055,13 +1044,12 @@ config APM_ALLOW_INTS
config APM_REAL_MODE_POWER_OFF
bool "Use real mode APM BIOS call to power off"
- depends on APM
help
Use real mode APM BIOS calls to switch off the computer. This is
a work-around for a number of buggy BIOSes. Switch this option on if
your computer crashes instead of powering off properly.
-endmenu
+endif # APM
source "arch/i386/kernel/cpu/cpufreq/Kconfig"
@@ -1073,6 +1061,7 @@ config PCI
bool "PCI support" if !X86_VISWS
depends on !X86_VOYAGER
default y if X86_VISWS
+ select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC)
help
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index b99c0e2a4e6..d7f6fb0b30f 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -43,6 +43,7 @@ config M386
- "Geode GX/LX" For AMD Geode GX and LX processors.
- "CyrixIII/VIA C3" for VIA Cyrix III or VIA C3.
- "VIA C3-2" for VIA C3-2 "Nehemiah" (model 9 and above).
+ - "VIA C7" for VIA C7.
If you don't know what to do, choose "386".
@@ -107,7 +108,7 @@ config MCORE2
bool "Core 2/newer Xeon"
help
Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and 53xx)
- CPUs. You can distingush newer from older Xeons by the CPU family
+ CPUs. You can distinguish newer from older Xeons by the CPU family
in /proc/cpuinfo. Newer ones have 6.
config MPENTIUM4
@@ -171,7 +172,7 @@ config MWINCHIP3D
help
Select this for an IDT Winchip-2A or 3. Linux and GCC
treat this chip as a 586TSC with some extended instructions
- and alignment reqirements. Also enable out of order memory
+ and alignment requirements. Also enable out of order memory
stores for this CPU, which can increase performance of some
operations.
@@ -203,6 +204,12 @@ config MVIAC3_2
of SSE and tells gcc to treat the CPU as a 686.
Note, this kernel will not boot on older (pre model 9) C3s.
+config MVIAC7
+ bool "VIA C7"
+ help
+ Select this for a VIA C7. Selecting this uses the correct cache
+ shift and tells gcc to treat the CPU as a 686.
+
endchoice
config X86_GENERIC
@@ -231,16 +238,21 @@ config X86_L1_CACHE_SHIFT
default "7" if MPENTIUM4 || X86_GENERIC
default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2
+ default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MVIAC7
+
+config X86_XADD
+ bool
+ depends on !M386
+ default y
config RWSEM_GENERIC_SPINLOCK
bool
- depends on M386
+ depends on !X86_XADD
default y
config RWSEM_XCHGADD_ALGORITHM
bool
- depends on !M386
+ depends on X86_XADD
default y
config ARCH_HAS_ILOG2_U32
@@ -297,7 +309,7 @@ config X86_ALIGNMENT_16
config X86_GOOD_APIC
bool
- depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2
+ depends on MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || MK8 || MEFFICEON || MCORE2 || MVIAC7
default y
config X86_INTEL_USERCOPY
@@ -322,5 +334,18 @@ config X86_OOSTORE
config X86_TSC
bool
- depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ
+ depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2) && !X86_NUMAQ
default y
+
+# this should be set for all -march=.. options where the compiler
+# generates cmov.
+config X86_CMOV
+ bool
+ depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7)
+ default y
+
+config X86_MINIMUM_CPU_MODEL
+ int
+ default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP
+ default "0"
+
diff --git a/arch/i386/Kconfig.debug b/arch/i386/Kconfig.debug
index 458bc161193..b31c0802e1c 100644
--- a/arch/i386/Kconfig.debug
+++ b/arch/i386/Kconfig.debug
@@ -85,14 +85,4 @@ config DOUBLEFAULT
option saves about 4k and might cause you much additional grey
hair.
-config DEBUG_PARAVIRT
- bool "Enable some paravirtualization debugging"
- default n
- depends on PARAVIRT && DEBUG_KERNEL
- help
- Currently deliberately clobbers regs which are allowed to be
- clobbered in inlined paravirt hooks, even in native mode.
- If turning this off solves a problem, then DISABLE_INTERRUPTS() or
- ENABLE_INTERRUPTS() is lying about what registers can be clobbered.
-
endmenu
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index bd28f9f9b4b..6dc5e5d90fe 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -34,7 +34,7 @@ CHECKFLAGS += -D__i386__
CFLAGS += -pipe -msoft-float -mregparm=3 -freg-struct-return
# prevent gcc from keeping the stack 16 byte aligned
-CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2)
+CFLAGS += -mpreferred-stack-boundary=4
# CPU-specific tuning. Anything which can be shared with UML should go here.
include $(srctree)/arch/i386/Makefile.cpu
diff --git a/arch/i386/Makefile.cpu b/arch/i386/Makefile.cpu
index a32c031c90d..e372b584e91 100644
--- a/arch/i386/Makefile.cpu
+++ b/arch/i386/Makefile.cpu
@@ -4,9 +4,9 @@
#-mtune exists since gcc 3.4
HAS_MTUNE := $(call cc-option-yn, -mtune=i386)
ifeq ($(HAS_MTUNE),y)
-tune = $(call cc-option,-mtune=$(1),)
+tune = $(call cc-option,-mtune=$(1),$(2))
else
-tune = $(call cc-option,-mcpu=$(1),)
+tune = $(call cc-option,-mcpu=$(1),$(2))
endif
align := $(cc-option-align)
@@ -32,7 +32,8 @@ cflags-$(CONFIG_MWINCHIP2) += $(call cc-option,-march=winchip2,-march=i586)
cflags-$(CONFIG_MWINCHIP3D) += $(call cc-option,-march=winchip2,-march=i586)
cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) $(align)-functions=0 $(align)-jumps=0 $(align)-loops=0
cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686)
-cflags-$(CONFIG_MCORE2) += -march=i686 $(call cc-option,-mtune=core2,$(call cc-option,-mtune=generic,-mtune=i686))
+cflags-$(CONFIG_MVIAC7) += -march=i686
+cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2)
# AMD Elan support
cflags-$(CONFIG_X86_ELAN) += -march=i486
@@ -42,5 +43,5 @@ cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx
# add at the end to overwrite eventual tuning options from earlier
# cpu entries
-cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic)
+cflags-$(CONFIG_X86_GENERIC) += $(call tune,generic,$(call tune,i686))
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index e9794662606..bfbc32098a4 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -36,9 +36,9 @@ HOSTCFLAGS_build.o := $(LINUXINCLUDE)
# ---------------------------------------------------------------------------
$(obj)/zImage: IMAGE_OFFSET := 0x1000
-$(obj)/zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK)
+$(obj)/zImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK)
$(obj)/bzImage: IMAGE_OFFSET := 0x100000
-$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
$(obj)/bzImage: BUILDFLAGS := -b
quiet_cmd_image = BUILD $@
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index 1ce7017fd62..b28505c544c 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -189,7 +189,7 @@ static void putstr(const char *);
static unsigned long free_mem_ptr;
static unsigned long free_mem_end_ptr;
-#define HEAP_SIZE 0x3000
+#define HEAP_SIZE 0x4000
static char *vidmem = (char *)0xb8000;
static int vidport;
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index 06edf1c6624..f8b3b9cda2b 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -52,6 +52,7 @@
#include <asm/boot.h>
#include <asm/e820.h>
#include <asm/page.h>
+#include <asm/setup.h>
/* Signature words to ensure LILO loaded us right */
#define SIG1 0xAA55
@@ -81,7 +82,7 @@ start:
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
.ascii "HdrS" # header signature
- .word 0x0205 # header version number (>= 0x0105)
+ .word 0x0206 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
start_sys_seg: .word SYSSEG
@@ -171,6 +172,10 @@ relocatable_kernel: .byte 0
pad2: .byte 0
pad3: .word 0
+cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
+ #added with boot protocol
+ #version 2.06
+
trampoline: call start_of_setup
.align 16
# The offset at this point is 0x240
@@ -297,7 +302,24 @@ good_sig:
loader_panic_mess: .string "Wrong loader, giving up..."
+# check minimum cpuid
+# we do this here because it is the last place we can actually
+# show a user visible error message. Later the video modus
+# might be already messed up.
loader_ok:
+ call verify_cpu
+ testl %eax,%eax
+ jz cpu_ok
+ lea cpu_panic_mess,%si
+ call prtstr
+1: jmp 1b
+
+cpu_panic_mess:
+ .asciz "PANIC: CPU too old for this kernel."
+
+#include "../kernel/verify_cpu.S"
+
+cpu_ok:
# Get memory size (extended mem, kB)
xorl %eax, %eax
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index f4efd66e1ee..9da84412a83 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Wed Mar 7 15:29:47 2007
+# Linux kernel version: 2.6.21-git3
+# Tue May 1 07:30:51 2007
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
@@ -108,9 +108,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Processor type and features
#
-# CONFIG_TICK_ONESHOT is not set
-# CONFIG_NO_HZ is not set
-# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
# CONFIG_X86_PC is not set
# CONFIG_X86_ELAN is not set
@@ -146,9 +146,11 @@ CONFIG_MPENTIUMIII=y
# CONFIG_MGEODE_LX is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
CONFIG_X86_GENERIC=y
CONFIG_X86_CMPXCHG=y
CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_XADD=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -162,6 +164,8 @@ CONFIG_X86_GOOD_APIC=y
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_TSC=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_MODEL=4
CONFIG_HPET_TIMER=y
CONFIG_HPET_EMULATE_RTC=y
CONFIG_NR_CPUS=32
@@ -248,7 +252,6 @@ CONFIG_ACPI_FAN=y
CONFIG_ACPI_PROCESSOR=y
CONFIG_ACPI_THERMAL=y
# CONFIG_ACPI_ASUS is not set
-# CONFIG_ACPI_IBM is not set
# CONFIG_ACPI_TOSHIBA is not set
CONFIG_ACPI_BLACKLIST_YEAR=2001
CONFIG_ACPI_DEBUG=y
@@ -257,10 +260,7 @@ CONFIG_ACPI_POWER=y
CONFIG_ACPI_SYSTEM=y
CONFIG_X86_PM_TIMER=y
# CONFIG_ACPI_CONTAINER is not set
-
-#
-# APM (Advanced Power Management) BIOS Support
-#
+# CONFIG_ACPI_SBS is not set
# CONFIG_APM is not set
#
@@ -277,7 +277,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
#
# CPUFreq processor drivers
@@ -349,7 +349,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -388,6 +387,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
@@ -443,6 +443,13 @@ CONFIG_IPV6_SIT=y
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
# CONFIG_IEEE80211 is not set
#
@@ -463,10 +470,6 @@ CONFIG_FW_LOADER=y
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -513,6 +516,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
# CONFIG_SONY_LAPTOP is not set
+# CONFIG_THINKPAD_ACPI is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -548,7 +552,6 @@ CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -580,7 +583,6 @@ CONFIG_BLK_DEV_PIIX=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -669,6 +671,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SRP is not set
#
@@ -692,12 +695,12 @@ CONFIG_SATA_SIL=y
CONFIG_SATA_VIA=y
# CONFIG_SATA_VITESSE is not set
# CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_INTEL_COMBINED=y
CONFIG_SATA_ACPI=y
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
@@ -763,10 +766,9 @@ CONFIG_IEEE1394=y
# Subsystem Options
#
# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
#
-# Device Drivers
+# Controllers
#
#
@@ -775,10 +777,11 @@ CONFIG_IEEE1394=y
CONFIG_IEEE1394_OHCI1394=y
#
-# Protocol Drivers
+# Protocols
#
# CONFIG_IEEE1394_VIDEO1394 is not set
# CONFIG_IEEE1394_SBP2 is not set
+# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set
# CONFIG_IEEE1394_ETH1394 is not set
# CONFIG_IEEE1394_DV1394 is not set
CONFIG_IEEE1394_RAWIO=y
@@ -821,7 +824,9 @@ CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
#
# Tulip family network device support
@@ -902,9 +907,10 @@ CONFIG_BNX2=y
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
@@ -918,7 +924,6 @@ CONFIG_BNX2=y
# CONFIG_SHAPER is not set
CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
@@ -1051,7 +1056,7 @@ CONFIG_MAX_RAW_DEVS=256
CONFIG_HPET=y
# CONFIG_HPET_RTC_IRQ is not set
CONFIG_HPET_MMAP=y
-CONFIG_HANGCHECK_TIMER=y
+# CONFIG_HANGCHECK_TIMER is not set
#
# TPM devices
@@ -1143,6 +1148,14 @@ CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1155,6 +1168,7 @@ CONFIG_USB=y
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
# CONFIG_USB_OTG is not set
@@ -1205,10 +1219,6 @@ CONFIG_USB_STORAGE=y
#
# USB Input Devices
#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_ACECAD is not set
@@ -1529,7 +1539,7 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 4ae3dcf1d2f..91cff8dc9e1 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -34,17 +34,16 @@ obj-y += sysenter.o vsyscall.o
obj-$(CONFIG_ACPI_SRAT) += srat.o
obj-$(CONFIG_EFI) += efi.o efi_stub.o
obj-$(CONFIG_DOUBLEFAULT) += doublefault.o
+obj-$(CONFIG_SERIAL_8250) += legacy_serial.o
obj-$(CONFIG_VM86) += vm86.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_HPET_TIMER) += hpet.o
obj-$(CONFIG_K8_NB) += k8.o
-obj-$(CONFIG_VMI) += vmi.o vmitime.o
+obj-$(CONFIG_VMI) += vmi.o vmiclock.o
obj-$(CONFIG_PARAVIRT) += paravirt.o
obj-y += pcspeaker.o
-EXTRA_AFLAGS := -traditional
-
obj-$(CONFIG_SCx200) += scx200.o
# vsyscall.o contains the vsyscall DSO images as __initdata.
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 9ea5b8ecc7e..280898b045b 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -874,7 +874,7 @@ static void __init acpi_process_madt(void)
acpi_ioapic = 1;
smp_found_config = 1;
- clustered_apic_check();
+ setup_apic_routing();
}
}
if (error == -EINVAL) {
diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c
index a7d22d9f3d7..23f78efc577 100644
--- a/arch/i386/kernel/acpi/earlyquirk.c
+++ b/arch/i386/kernel/acpi/earlyquirk.c
@@ -10,7 +10,6 @@
#include <asm/pci-direct.h>
#include <asm/acpi.h>
#include <asm/apic.h>
-#include <asm/irq.h>
#ifdef CONFIG_ACPI
@@ -23,10 +22,13 @@ static int __init nvidia_hpet_check(struct acpi_table_header *header)
static int __init check_bridge(int vendor, int device)
{
#ifdef CONFIG_ACPI
+ static int warned;
/* According to Nvidia all timer overrides are bogus unless HPET
is enabled. */
if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) {
- if (acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check)) {
+ if (!warned && acpi_table_parse(ACPI_SIG_HPET,
+ nvidia_hpet_check)) {
+ warned = 1;
acpi_skip_timer_override = 1;
printk(KERN_INFO "Nvidia board "
"detected. Ignoring ACPI "
@@ -45,24 +47,6 @@ static int __init check_bridge(int vendor, int device)
return 0;
}
-static void check_intel(void)
-{
- u16 vendor, device;
-
- vendor = read_pci_config_16(0, 0, 0, PCI_VENDOR_ID);
-
- if (vendor != PCI_VENDOR_ID_INTEL)
- return;
-
- device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
-#ifdef CONFIG_SMP
- if (device == PCI_DEVICE_ID_INTEL_E7320_MCH ||
- device == PCI_DEVICE_ID_INTEL_E7520_MCH ||
- device == PCI_DEVICE_ID_INTEL_E7525_MCH)
- quirk_intel_irqbalance();
-#endif
-}
-
void __init check_acpi_pci(void)
{
int num, slot, func;
@@ -74,8 +58,6 @@ void __init check_acpi_pci(void)
if (!early_pci_allowed())
return;
- check_intel();
-
/* Poor man's PCI discovery */
for (num = 0; num < 32; num++) {
for (slot = 0; slot < 32; slot++) {
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index 426f59b0106..d8cda14fff8 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -5,6 +5,7 @@
#include <asm/alternative.h>
#include <asm/sections.h>
+static int noreplace_smp = 0;
static int smp_alt_once = 0;
static int debug_alternative = 0;
@@ -13,15 +14,33 @@ static int __init bootonly(char *str)
smp_alt_once = 1;
return 1;
}
+__setup("smp-alt-boot", bootonly);
+
static int __init debug_alt(char *str)
{
debug_alternative = 1;
return 1;
}
-
-__setup("smp-alt-boot", bootonly);
__setup("debug-alternative", debug_alt);
+static int __init setup_noreplace_smp(char *str)
+{
+ noreplace_smp = 1;
+ return 1;
+}
+__setup("noreplace-smp", setup_noreplace_smp);
+
+#ifdef CONFIG_PARAVIRT
+static int noreplace_paravirt = 0;
+
+static int __init setup_noreplace_paravirt(char *str)
+{
+ noreplace_paravirt = 1;
+ return 1;
+}
+__setup("noreplace-paravirt", setup_noreplace_paravirt);
+#endif
+
#define DPRINTK(fmt, args...) if (debug_alternative) \
printk(KERN_DEBUG fmt, args)
@@ -132,11 +151,8 @@ static void nop_out(void *insns, unsigned int len)
}
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
-extern struct alt_instr __smp_alt_instructions[], __smp_alt_instructions_end[];
extern u8 *__smp_locks[], *__smp_locks_end[];
-extern u8 __smp_alt_begin[], __smp_alt_end[];
-
/* Replace instructions with better alternatives for this CPU type.
This runs before SMP is initialized to avoid SMP problems with
self modifying code. This implies that assymetric systems where
@@ -171,29 +187,6 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
#ifdef CONFIG_SMP
-static void alternatives_smp_save(struct alt_instr *start, struct alt_instr *end)
-{
- struct alt_instr *a;
-
- DPRINTK("%s: alt table %p-%p\n", __FUNCTION__, start, end);
- for (a = start; a < end; a++) {
- memcpy(a->replacement + a->replacementlen,
- a->instr,
- a->instrlen);
- }
-}
-
-static void alternatives_smp_apply(struct alt_instr *start, struct alt_instr *end)
-{
- struct alt_instr *a;
-
- for (a = start; a < end; a++) {
- memcpy(a->instr,
- a->replacement + a->replacementlen,
- a->instrlen);
- }
-}
-
static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
{
u8 **ptr;
@@ -211,6 +204,9 @@ static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end
{
u8 **ptr;
+ if (noreplace_smp)
+ return;
+
for (ptr = start; ptr < end; ptr++) {
if (*ptr < text)
continue;
@@ -245,6 +241,9 @@ void alternatives_smp_module_add(struct module *mod, char *name,
struct smp_alt_module *smp;
unsigned long flags;
+ if (noreplace_smp)
+ return;
+
if (smp_alt_once) {
if (boot_cpu_has(X86_FEATURE_UP))
alternatives_smp_unlock(locks, locks_end,
@@ -279,7 +278,7 @@ void alternatives_smp_module_del(struct module *mod)
struct smp_alt_module *item;
unsigned long flags;
- if (smp_alt_once)
+ if (smp_alt_once || noreplace_smp)
return;
spin_lock_irqsave(&smp_alt, flags);
@@ -310,7 +309,7 @@ void alternatives_smp_switch(int smp)
return;
#endif
- if (smp_alt_once)
+ if (noreplace_smp || smp_alt_once)
return;
BUG_ON(!smp && (num_online_cpus() > 1));
@@ -319,8 +318,6 @@ void alternatives_smp_switch(int smp)
printk(KERN_INFO "SMP alternatives: switching to SMP code\n");
clear_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
clear_bit(X86_FEATURE_UP, cpu_data[0].x86_capability);
- alternatives_smp_apply(__smp_alt_instructions,
- __smp_alt_instructions_end);
list_for_each_entry(mod, &smp_alt_modules, next)
alternatives_smp_lock(mod->locks, mod->locks_end,
mod->text, mod->text_end);
@@ -328,8 +325,6 @@ void alternatives_smp_switch(int smp)
printk(KERN_INFO "SMP alternatives: switching to UP code\n");
set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
set_bit(X86_FEATURE_UP, cpu_data[0].x86_capability);
- apply_alternatives(__smp_alt_instructions,
- __smp_alt_instructions_end);
list_for_each_entry(mod, &smp_alt_modules, next)
alternatives_smp_unlock(mod->locks, mod->locks_end,
mod->text, mod->text_end);
@@ -340,36 +335,31 @@ void alternatives_smp_switch(int smp)
#endif
#ifdef CONFIG_PARAVIRT
-void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
+void apply_paravirt(struct paravirt_patch_site *start,
+ struct paravirt_patch_site *end)
{
- struct paravirt_patch *p;
+ struct paravirt_patch_site *p;
+
+ if (noreplace_paravirt)
+ return;
for (p = start; p < end; p++) {
unsigned int used;
used = paravirt_ops.patch(p->instrtype, p->clobbers, p->instr,
p->len);
-#ifdef CONFIG_DEBUG_PARAVIRT
- {
- int i;
- /* Deliberately clobber regs using "not %reg" to find bugs. */
- for (i = 0; i < 3; i++) {
- if (p->len - used >= 2 && (p->clobbers & (1 << i))) {
- memcpy(p->instr + used, "\xf7\xd0", 2);
- p->instr[used+1] |= i;
- used += 2;
- }
- }
- }
-#endif
+
+ BUG_ON(used > p->len);
+
/* Pad the rest with nops */
nop_out(p->instr + used, p->len - used);
}
- /* Sync to be conservative, in case we patched following instructions */
+ /* Sync to be conservative, in case we patched following
+ * instructions */
sync_core();
}
-extern struct paravirt_patch __start_parainstructions[],
+extern struct paravirt_patch_site __start_parainstructions[],
__stop_parainstructions[];
#endif /* CONFIG_PARAVIRT */
@@ -396,23 +386,19 @@ void __init alternative_instructions(void)
printk(KERN_INFO "SMP alternatives: switching to UP code\n");
set_bit(X86_FEATURE_UP, boot_cpu_data.x86_capability);
set_bit(X86_FEATURE_UP, cpu_data[0].x86_capability);
- apply_alternatives(__smp_alt_instructions,
- __smp_alt_instructions_end);
alternatives_smp_unlock(__smp_locks, __smp_locks_end,
_text, _etext);
}
free_init_pages("SMP alternatives",
- (unsigned long)__smp_alt_begin,
- (unsigned long)__smp_alt_end);
+ (unsigned long)__smp_locks,
+ (unsigned long)__smp_locks_end);
} else {
- alternatives_smp_save(__smp_alt_instructions,
- __smp_alt_instructions_end);
alternatives_smp_module_add(NULL, "core kernel",
__smp_locks, __smp_locks_end,
_text, _etext);
alternatives_smp_switch(0);
}
#endif
- apply_paravirt(__start_parainstructions, __stop_parainstructions);
+ apply_paravirt(__parainstructions, __parainstructions_end);
local_irq_restore(flags);
}
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 93aa911646a..67824f3bb97 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h>
@@ -129,6 +128,28 @@ static int modern_apic(void)
return lapic_get_version() >= 0x14;
}
+void apic_wait_icr_idle(void)
+{
+ while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
+ cpu_relax();
+}
+
+unsigned long safe_apic_wait_icr_idle(void)
+{
+ unsigned long send_status;
+ int timeout;
+
+ timeout = 0;
+ do {
+ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+ if (!send_status)
+ break;
+ udelay(100);
+ } while (timeout++ < 1000);
+
+ return send_status;
+}
+
/**
* enable_NMI_through_LVT0 - enable NMI through local vector table 0
*/
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 064bbf2861f..4112afe712b 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -223,7 +223,6 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/dmi.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
@@ -233,11 +232,10 @@
#include <asm/desc.h>
#include <asm/i8253.h>
#include <asm/paravirt.h>
+#include <asm/reboot.h>
#include "io_ports.h"
-extern void machine_real_restart(unsigned char *, int);
-
#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)
extern int (*console_blank_hook)(int);
#endif
@@ -384,13 +382,6 @@ static int ignore_sys_suspend;
static int ignore_normal_resume;
static int bounce_interval __read_mostly = DEFAULT_BOUNCE_INTERVAL;
-#ifdef CONFIG_APM_RTC_IS_GMT
-# define clock_cmos_diff 0
-# define got_clock_diff 1
-#else
-static long clock_cmos_diff;
-static int got_clock_diff;
-#endif
static int debug __read_mostly;
static int smp __read_mostly;
static int apm_disabled = -1;
@@ -1181,7 +1172,7 @@ static void reinit_timer(void)
unsigned long flags;
spin_lock_irqsave(&i8253_lock, flags);
- /* set the clock to 100 Hz */
+ /* set the clock to HZ */
outb_p(0x34, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */
udelay(10);
outb_p(LATCH & 0xff, PIT_CH0); /* LSB */
diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
index c37535163bf..27a776c9044 100644
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -11,11 +11,11 @@
#include <linux/suspend.h>
#include <asm/ucontext.h>
#include "sigframe.h"
+#include <asm/pgtable.h>
#include <asm/fixmap.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
#include <asm/elf.h>
-#include <asm/pda.h>
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -25,6 +25,9 @@
#define OFFSET(sym, str, mem) \
DEFINE(sym, offsetof(struct str, mem));
+/* workaround for a warning with -Wmissing-prototypes */
+void foo(void);
+
void foo(void)
{
OFFSET(SIGCONTEXT_eax, sigcontext, eax);
@@ -90,17 +93,18 @@ void foo(void)
OFFSET(pbe_next, pbe, next);
/* Offset from the sysenter stack to tss.esp0 */
- DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, esp0) -
+ DEFINE(TSS_sysenter_esp0, offsetof(struct tss_struct, x86_tss.esp0) -
sizeof(struct tss_struct));
DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
- DEFINE(VDSO_PRELINK, VDSO_PRELINK);
+ DEFINE(PAGE_SHIFT_asm, PAGE_SHIFT);
+ DEFINE(PTRS_PER_PTE, PTRS_PER_PTE);
+ DEFINE(PTRS_PER_PMD, PTRS_PER_PMD);
+ DEFINE(PTRS_PER_PGD, PTRS_PER_PGD);
- OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
+ DEFINE(VDSO_PRELINK_asm, VDSO_PRELINK);
- BLANK();
- OFFSET(PDA_cpu, i386_pda, cpu_number);
- OFFSET(PDA_pcurrent, i386_pda, pcurrent);
+ OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx);
#ifdef CONFIG_PARAVIRT
BLANK();
diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
index 010aecfffbc..74f27a463db 100644
--- a/arch/i386/kernel/cpu/Makefile
+++ b/arch/i386/kernel/cpu/Makefile
@@ -2,7 +2,7 @@
# Makefile for x86-compatible CPU details and quirks
#
-obj-y := common.o proc.o
+obj-y := common.o proc.o bugs.o
obj-y += amd.o
obj-y += cyrix.o
@@ -17,3 +17,5 @@ obj-$(CONFIG_X86_MCE) += mcheck/
obj-$(CONFIG_MTRR) += mtrr/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
+
+obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 2d47db48297..4fec702afd7 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -53,6 +53,8 @@ static __cpuinit int amd_apic_timer_broken(void)
return 0;
}
+int force_mwait __cpuinitdata;
+
static void __cpuinit init_amd(struct cpuinfo_x86 *c)
{
u32 l, h;
@@ -275,6 +277,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
if (amd_apic_timer_broken())
set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
+
+ if (c->x86 == 0x10 && !force_mwait)
+ clear_bit(X86_FEATURE_MWAIT, c->x86_capability);
}
static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
@@ -314,13 +319,3 @@ int __init amd_init_cpu(void)
cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev;
return 0;
}
-
-//early_arch_initcall(amd_init_cpu);
-
-static int __init amd_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_AMD] = NULL;
- return 0;
-}
-
-late_initcall(amd_exit_cpu);
diff --git a/arch/i386/kernel/cpu/bugs.c b/arch/i386/kernel/cpu/bugs.c
new file mode 100644
index 00000000000..54428a2500f
--- /dev/null
+++ b/arch/i386/kernel/cpu/bugs.c
@@ -0,0 +1,191 @@
+/*
+ * arch/i386/cpu/bugs.c
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ *
+ * Cyrix stuff, June 1998 by:
+ * - Rafael R. Reilova (moved everything from head.S),
+ * <rreilova@ececs.uc.edu>
+ * - Channing Corn (tests & fixes),
+ * - Andrew D. Balsa (code cleanup).
+ */
+#include <linux/init.h>
+#include <linux/utsname.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/msr.h>
+#include <asm/paravirt.h>
+#include <asm/alternative.h>
+
+static int __init no_halt(char *s)
+{
+ boot_cpu_data.hlt_works_ok = 0;
+ return 1;
+}
+
+__setup("no-hlt", no_halt);
+
+static int __init mca_pentium(char *s)
+{
+ mca_pentium_flag = 1;
+ return 1;
+}
+
+__setup("mca-pentium", mca_pentium);
+
+static int __init no_387(char *s)
+{
+ boot_cpu_data.hard_math = 0;
+ write_cr0(0xE | read_cr0());
+ return 1;
+}
+
+__setup("no387", no_387);
+
+static double __initdata x = 4195835.0;
+static double __initdata y = 3145727.0;
+
+/*
+ * This used to check for exceptions..
+ * However, it turns out that to support that,
+ * the XMM trap handlers basically had to
+ * be buggy. So let's have a correct XMM trap
+ * handler, and forget about printing out
+ * some status at boot.
+ *
+ * We should really only care about bugs here
+ * anyway. Not features.
+ */
+static void __init check_fpu(void)
+{
+ if (!boot_cpu_data.hard_math) {
+#ifndef CONFIG_MATH_EMULATION
+ printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
+ printk(KERN_EMERG "Giving up.\n");
+ for (;;) ;
+#endif
+ return;
+ }
+
+/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */
+ /* Test for the divl bug.. */
+ __asm__("fninit\n\t"
+ "fldl %1\n\t"
+ "fdivl %2\n\t"
+ "fmull %2\n\t"
+ "fldl %1\n\t"
+ "fsubp %%st,%%st(1)\n\t"
+ "fistpl %0\n\t"
+ "fwait\n\t"
+ "fninit"
+ : "=m" (*&boot_cpu_data.fdiv_bug)
+ : "m" (*&x), "m" (*&y));
+ if (boot_cpu_data.fdiv_bug)
+ printk("Hmm, FPU with FDIV bug.\n");
+}
+
+static void __init check_hlt(void)
+{
+ if (paravirt_enabled())
+ return;
+
+ printk(KERN_INFO "Checking 'hlt' instruction... ");
+ if (!boot_cpu_data.hlt_works_ok) {
+ printk("disabled\n");
+ return;
+ }
+ halt();
+ halt();
+ halt();
+ halt();
+ printk("OK.\n");
+}
+
+/*
+ * Most 386 processors have a bug where a POPAD can lock the
+ * machine even from user space.
+ */
+
+static void __init check_popad(void)
+{
+#ifndef CONFIG_X86_POPAD_OK
+ int res, inp = (int) &res;
+
+ printk(KERN_INFO "Checking for popad bug... ");
+ __asm__ __volatile__(
+ "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
+ : "=&a" (res)
+ : "d" (inp)
+ : "ecx", "edi" );
+ /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
+ if (res != 12345678) printk( "Buggy.\n" );
+ else printk( "OK.\n" );
+#endif
+}
+
+/*
+ * Check whether we are able to run this kernel safely on SMP.
+ *
+ * - In order to run on a i386, we need to be compiled for i386
+ * (for due to lack of "invlpg" and working WP on a i386)
+ * - In order to run on anything without a TSC, we need to be
+ * compiled for a i486.
+ * - In order to support the local APIC on a buggy Pentium machine,
+ * we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
+ * which happens implicitly if compiled for a Pentium or lower
+ * (unless an advanced selection of CPU features is used) as an
+ * otherwise config implies a properly working local APIC without
+ * the need to do extra reads from the APIC.
+*/
+
+static void __init check_config(void)
+{
+/*
+ * We'd better not be a i386 if we're configured to use some
+ * i486+ only features! (WP works in supervisor mode and the
+ * new "invlpg" and "bswap" instructions)
+ */
+#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP)
+ if (boot_cpu_data.x86 == 3)
+ panic("Kernel requires i486+ for 'invlpg' and other features");
+#endif
+
+/*
+ * If we configured ourselves for a TSC, we'd better have one!
+ */
+#ifdef CONFIG_X86_TSC
+ if (!cpu_has_tsc && !tsc_disable)
+ panic("Kernel compiled for Pentium+, requires TSC feature!");
+#endif
+
+/*
+ * If we were told we had a good local APIC, check for buggy Pentia,
+ * i.e. all B steppings and the C2 stepping of P54C when using their
+ * integrated APIC (see 11AP erratum in "Pentium Processor
+ * Specification Update").
+ */
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
+ && cpu_has_apic
+ && boot_cpu_data.x86 == 5
+ && boot_cpu_data.x86_model == 2
+ && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
+ panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
+#endif
+}
+
+
+void __init check_bugs(void)
+{
+ identify_boot_cpu();
+#ifndef CONFIG_SMP
+ printk("CPU: ");
+ print_cpu_info(&boot_cpu_data);
+#endif
+ check_config();
+ check_fpu();
+ check_hlt();
+ check_popad();
+ init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+ alternative_instructions();
+}
diff --git a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
index 8c25047975c..473eac883c7 100644
--- a/arch/i386/kernel/cpu/centaur.c
+++ b/arch/i386/kernel/cpu/centaur.c
@@ -469,13 +469,3 @@ int __init centaur_init_cpu(void)
cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
return 0;
}
-
-//early_arch_initcall(centaur_init_cpu);
-
-static int __init centaur_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_CENTAUR] = NULL;
- return 0;
-}
-
-late_initcall(centaur_exit_cpu);
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index dcbbd0a8bfc..794d593c47e 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -18,15 +18,37 @@
#include <asm/apic.h>
#include <mach_apic.h>
#endif
-#include <asm/pda.h>
#include "cpu.h"
-DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
-EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr);
+DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = {
+ [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 },
+ [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 },
+ [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 },
+ [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 },
+ /*
+ * Segments used for calling PnP BIOS have byte granularity.
+ * They code segments and data segments have fixed 64k limits,
+ * the transfer segment sizes are set at run time.
+ */
+ [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */
+ [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */
+ [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */
+ [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */
+ [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */
+ /*
+ * The APM segments have byte granularity and their bases
+ * are set at run time. All have 64k limits.
+ */
+ [GDT_ENTRY_APMBIOS_BASE] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */
+ /* 16-bit code */
+ [GDT_ENTRY_APMBIOS_BASE+1] = { 0x0000ffff, 0x00009a00 },
+ [GDT_ENTRY_APMBIOS_BASE+2] = { 0x0000ffff, 0x00409200 }, /* data */
-struct i386_pda *_cpu_pda[NR_CPUS] __read_mostly;
-EXPORT_SYMBOL(_cpu_pda);
+ [GDT_ENTRY_ESPFIX_SS] = { 0x00000000, 0x00c09200 },
+ [GDT_ENTRY_PERCPU] = { 0x00000000, 0x00000000 },
+} };
+EXPORT_PER_CPU_SYMBOL_GPL(gdt_page);
static int cachesize_override __cpuinitdata = -1;
static int disable_x86_fxsr __cpuinitdata;
@@ -368,7 +390,7 @@ __setup("serialnumber", x86_serial_nr_setup);
/*
* This does the hard work of actually picking apart the CPU stuff...
*/
-void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
+static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
{
int i;
@@ -479,15 +501,22 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
/* Init Machine Check Exception if available. */
mcheck_init(c);
+}
- if (c == &boot_cpu_data)
- sysenter_setup();
+void __init identify_boot_cpu(void)
+{
+ identify_cpu(&boot_cpu_data);
+ sysenter_setup();
enable_sep_cpu();
+ mtrr_bp_init();
+}
- if (c == &boot_cpu_data)
- mtrr_bp_init();
- else
- mtrr_ap_init();
+void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
+{
+ BUG_ON(c == &boot_cpu_data);
+ identify_cpu(c);
+ enable_sep_cpu();
+ mtrr_ap_init();
}
#ifdef CONFIG_X86_HT
@@ -601,129 +630,36 @@ void __init early_cpu_init(void)
#endif
}
-/* Make sure %gs is initialized properly in idle threads */
+/* Make sure %fs is initialized properly in idle threads */
struct pt_regs * __devinit idle_regs(struct pt_regs *regs)
{
memset(regs, 0, sizeof(struct pt_regs));
- regs->xfs = __KERNEL_PDA;
+ regs->xfs = __KERNEL_PERCPU;
return regs;
}
-static __cpuinit int alloc_gdt(int cpu)
+/* Current gdt points %fs at the "master" per-cpu area: after this,
+ * it's on the real one. */
+void switch_to_new_gdt(void)
{
- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
- struct desc_struct *gdt;
- struct i386_pda *pda;
-
- gdt = (struct desc_struct *)cpu_gdt_descr->address;
- pda = cpu_pda(cpu);
-
- /*
- * This is a horrible hack to allocate the GDT. The problem
- * is that cpu_init() is called really early for the boot CPU
- * (and hence needs bootmem) but much later for the secondary
- * CPUs, when bootmem will have gone away
- */
- if (NODE_DATA(0)->bdata->node_bootmem_map) {
- BUG_ON(gdt != NULL || pda != NULL);
-
- gdt = alloc_bootmem_pages(PAGE_SIZE);
- pda = alloc_bootmem(sizeof(*pda));
- /* alloc_bootmem(_pages) panics on failure, so no check */
-
- memset(gdt, 0, PAGE_SIZE);
- memset(pda, 0, sizeof(*pda));
- } else {
- /* GDT and PDA might already have been allocated if
- this is a CPU hotplug re-insertion. */
- if (gdt == NULL)
- gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL);
-
- if (pda == NULL)
- pda = kmalloc_node(sizeof(*pda), GFP_KERNEL, cpu_to_node(cpu));
-
- if (unlikely(!gdt || !pda)) {
- free_pages((unsigned long)gdt, 0);
- kfree(pda);
- return 0;
- }
- }
-
- cpu_gdt_descr->address = (unsigned long)gdt;
- cpu_pda(cpu) = pda;
-
- return 1;
-}
+ struct Xgt_desc_struct gdt_descr;
-/* Initial PDA used by boot CPU */
-struct i386_pda boot_pda = {
- ._pda = &boot_pda,
- .cpu_number = 0,
- .pcurrent = &init_task,
-};
-
-static inline void set_kernel_fs(void)
-{
- /* Set %fs for this CPU's PDA. Memory clobber is to create a
- barrier with respect to any PDA operations, so the compiler
- doesn't move any before here. */
- asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_PDA) : "memory");
+ gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id());
+ gdt_descr.size = GDT_SIZE - 1;
+ load_gdt(&gdt_descr);
+ asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory");
}
-/* Initialize the CPU's GDT and PDA. The boot CPU does this for
- itself, but secondaries find this done for them. */
-__cpuinit int init_gdt(int cpu, struct task_struct *idle)
-{
- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
- struct desc_struct *gdt;
- struct i386_pda *pda;
-
- /* For non-boot CPUs, the GDT and PDA should already have been
- allocated. */
- if (!alloc_gdt(cpu)) {
- printk(KERN_CRIT "CPU%d failed to allocate GDT or PDA\n", cpu);
- return 0;
- }
-
- gdt = (struct desc_struct *)cpu_gdt_descr->address;
- pda = cpu_pda(cpu);
-
- BUG_ON(gdt == NULL || pda == NULL);
-
- /*
- * Initialize the per-CPU GDT with the boot GDT,
- * and set up the GDT descriptor:
- */
- memcpy(gdt, cpu_gdt_table, GDT_SIZE);
- cpu_gdt_descr->size = GDT_SIZE - 1;
-
- pack_descriptor((u32 *)&gdt[GDT_ENTRY_PDA].a,
- (u32 *)&gdt[GDT_ENTRY_PDA].b,
- (unsigned long)pda, sizeof(*pda) - 1,
- 0x80 | DESCTYPE_S | 0x2, 0); /* present read-write data segment */
-
- memset(pda, 0, sizeof(*pda));
- pda->_pda = pda;
- pda->cpu_number = cpu;
- pda->pcurrent = idle;
-
- return 1;
-}
-
-void __cpuinit cpu_set_gdt(int cpu)
-{
- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-
- /* Reinit these anyway, even if they've already been done (on
- the boot CPU, this will transition from the boot gdt+pda to
- the real ones). */
- load_gdt(cpu_gdt_descr);
- set_kernel_fs();
-}
-
-/* Common CPU init for both boot and secondary CPUs */
-static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+ * and IDT. We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ */
+void __cpuinit cpu_init(void)
{
+ int cpu = smp_processor_id();
+ struct task_struct *curr = current;
struct tss_struct * t = &per_cpu(init_tss, cpu);
struct thread_struct *thread = &curr->thread;
@@ -744,6 +680,7 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
}
load_idt(&idt_descr);
+ switch_to_new_gdt();
/*
* Set up and load the per-CPU TSS and LDT
@@ -783,38 +720,6 @@ static void __cpuinit _cpu_init(int cpu, struct task_struct *curr)
mxcsr_feature_mask_init();
}
-/* Entrypoint to initialize secondary CPU */
-void __cpuinit secondary_cpu_init(void)
-{
- int cpu = smp_processor_id();
- struct task_struct *curr = current;
-
- _cpu_init(cpu, curr);
-}
-
-/*
- * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
- */
-void __cpuinit cpu_init(void)
-{
- int cpu = smp_processor_id();
- struct task_struct *curr = current;
-
- /* Set up the real GDT and PDA, so we can transition from the
- boot versions. */
- if (!init_gdt(cpu, curr)) {
- /* failed to allocate something; not much we can do... */
- for (;;)
- local_irq_enable();
- }
-
- cpu_set_gdt(cpu);
- _cpu_init(cpu, curr);
-}
-
#ifdef CONFIG_HOTPLUG_CPU
void __cpuinit cpu_uninit(void)
{
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index 2b030d6ccbf..a3df9c039bd 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -590,20 +590,23 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
static int enable_arbiter_disable(void)
{
struct pci_dev *dev;
+ int status;
int reg;
u8 pci_cmd;
+ status = 1;
/* Find PLE133 host bridge */
reg = 0x78;
- dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
+ dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
+ NULL);
/* Find CLE266 host bridge */
if (dev == NULL) {
reg = 0x76;
- dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL);
+ dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_862X_0, NULL);
/* Find CN400 V-Link host bridge */
if (dev == NULL)
- dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
-
+ dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
}
if (dev != NULL) {
/* Enable access to port 0x22 */
@@ -615,10 +618,11 @@ static int enable_arbiter_disable(void)
if (!(pci_cmd & 1<<7)) {
printk(KERN_ERR PFX
"Can't enable access to port 0x22.\n");
- return 0;
+ status = 0;
}
}
- return 1;
+ pci_dev_put(dev);
+ return status;
}
return 0;
}
@@ -629,7 +633,7 @@ static int longhaul_setup_vt8235(void)
u8 pci_cmd;
/* Find VT8235 southbridge */
- dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
+ dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
if (dev != NULL) {
/* Set transition time to max */
pci_read_config_byte(dev, 0xec, &pci_cmd);
@@ -641,6 +645,7 @@ static int longhaul_setup_vt8235(void)
pci_read_config_byte(dev, 0xe5, &pci_cmd);
pci_cmd |= 1 << 7;
pci_write_config_byte(dev, 0xe5, pci_cmd);
+ pci_dev_put(dev);
return 1;
}
return 0;
@@ -678,7 +683,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
sizeof(samuel2_eblcr));
break;
case 1 ... 15:
- longhaul_version = TYPE_LONGHAUL_V2;
+ longhaul_version = TYPE_LONGHAUL_V1;
if (c->x86_mask < 8) {
cpu_model = CPU_SAMUEL2;
cpuname = "C3 'Samuel 2' [C5B]";
diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
index 4786fedca6e..4c76b511e19 100644
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
@@ -27,7 +27,6 @@
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/cpumask.h>
-#include <linux/sched.h> /* current / set_cpus_allowed() */
#include <asm/processor.h>
#include <asm/msr.h>
@@ -62,7 +61,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV))
return -EINVAL;
- rdmsr(MSR_IA32_THERM_STATUS, l, h);
+ rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
if (l & 0x01)
dprintk("CPU#%d currently thermal throttled\n", cpu);
@@ -70,10 +69,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT))
newstate = DC_38PT;
- rdmsr(MSR_IA32_THERM_CONTROL, l, h);
+ rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
if (newstate == DC_DISABLE) {
dprintk("CPU#%d disabling modulation\n", cpu);
- wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
+ wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
} else {
dprintk("CPU#%d setting duty cycle to %d%%\n",
cpu, ((125 * newstate) / 10));
@@ -84,7 +83,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
*/
l = (l & ~14);
l = l | (1<<4) | ((newstate & 0x7)<<1);
- wrmsr(MSR_IA32_THERM_CONTROL, l, h);
+ wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h);
}
return 0;
@@ -111,7 +110,6 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
{
unsigned int newstate = DC_RESV;
struct cpufreq_freqs freqs;
- cpumask_t cpus_allowed;
int i;
if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate))
@@ -132,17 +130,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy,
/* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software
* Developer's Manual, Volume 3
*/
- cpus_allowed = current->cpus_allowed;
-
- for_each_cpu_mask(i, policy->cpus) {
- cpumask_t this_cpu = cpumask_of_cpu(i);
-
- set_cpus_allowed(current, this_cpu);
- BUG_ON(smp_processor_id() != i);
-
+ for_each_cpu_mask(i, policy->cpus)
cpufreq_p4_setdc(i, p4clockmod_table[newstate].index);
- }
- set_cpus_allowed(current, cpus_allowed);
/* notifiers */
for_each_cpu_mask(i, policy->cpus) {
@@ -256,17 +245,9 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy)
static unsigned int cpufreq_p4_get(unsigned int cpu)
{
- cpumask_t cpus_allowed;
u32 l, h;
- cpus_allowed = current->cpus_allowed;
-
- set_cpus_allowed(current, cpumask_of_cpu(cpu));
- BUG_ON(smp_processor_id() != cpu);
-
- rdmsr(MSR_IA32_THERM_CONTROL, l, h);
-
- set_cpus_allowed(current, cpus_allowed);
+ rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
if (l & 0x10) {
l = l >> 1;
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index fe3b67005eb..7cf3d207b6b 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -661,7 +661,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst,
dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
data->powernow_table = powernow_table;
- print_basics(data);
+ if (first_cpu(cpu_core_map[data->cpu]) == data->cpu)
+ print_basics(data);
for (j = 0; j < data->numps; j++)
if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid))
@@ -814,7 +815,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
/* fill in data */
data->numps = data->acpi_data.state_count;
- print_basics(data);
+ if (first_cpu(cpu_core_map[data->cpu]) == data->cpu)
+ print_basics(data);
powernow_k8_acpi_pst_values(data, 0);
/* notify BIOS that we exist */
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
index 0fb2a3001ba..95be5013c98 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
@@ -215,8 +215,10 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid);
static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index);
+#ifdef CONFIG_X86_POWERNOW_K8_ACPI
static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table);
+#endif
#ifdef CONFIG_SMP
static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[])
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index f43b987f952..35489fd6885 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -720,6 +720,7 @@ static int centrino_target (struct cpufreq_policy *policy,
cpu_set(j, set_mask);
set_cpus_allowed(current, set_mask);
+ preempt_disable();
if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) {
dprintk("couldn't limit to CPUs in this domain\n");
retval = -EAGAIN;
@@ -727,6 +728,7 @@ static int centrino_target (struct cpufreq_policy *policy,
/* We haven't started the transition yet. */
goto migrate_end;
}
+ preempt_enable();
break;
}
@@ -761,10 +763,13 @@ static int centrino_target (struct cpufreq_policy *policy,
}
wrmsr(MSR_IA32_PERF_CTL, oldmsr, h);
- if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
+ if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
+ preempt_enable();
break;
+ }
cpu_set(j, covered_cpus);
+ preempt_enable();
}
for_each_cpu_mask(k, online_policy_cpus) {
@@ -796,8 +801,11 @@ static int centrino_target (struct cpufreq_policy *policy,
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
}
+ set_cpus_allowed(current, saved_mask);
+ return 0;
migrate_end:
+ preempt_enable();
set_cpus_allowed(current, saved_mask);
return 0;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
index d59277c0091..b1acc8ce316 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
@@ -13,7 +13,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <asm/msr.h>
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
index ff0d8980611..e1c509aa305 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c
@@ -17,10 +17,10 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/ist.h>
+#include <asm/io.h>
#include "speedstep-lib.h"
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index de27bd07bc9..0b8411a864f 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -279,7 +279,7 @@ static void __cpuinit init_cyrix(struct cpuinfo_x86 *c)
*/
if (vendor == PCI_VENDOR_ID_CYRIX &&
(device == PCI_DEVICE_ID_CYRIX_5510 || device == PCI_DEVICE_ID_CYRIX_5520))
- pit_latch_buggy = 1;
+ mark_tsc_unstable("cyrix 5510/5520 detected");
}
#endif
c->x86_cache_size=16; /* Yep 16K integrated cache thats it */
@@ -448,16 +448,6 @@ int __init cyrix_init_cpu(void)
return 0;
}
-//early_arch_initcall(cyrix_init_cpu);
-
-static int __init cyrix_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_CYRIX] = NULL;
- return 0;
-}
-
-late_initcall(cyrix_exit_cpu);
-
static struct cpu_dev nsc_cpu_dev __cpuinitdata = {
.c_vendor = "NSC",
.c_ident = { "Geode by NSC" },
@@ -470,12 +460,3 @@ int __init nsc_init_cpu(void)
return 0;
}
-//early_arch_initcall(nsc_init_cpu);
-
-static int __init nsc_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_NSC] = NULL;
- return 0;
-}
-
-late_initcall(nsc_exit_cpu);
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 56fe2658495..dc4e08147b1 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -188,8 +188,10 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
}
#endif
- if (c->x86 == 15)
+ if (c->x86 == 15) {
set_bit(X86_FEATURE_P4, c->x86_capability);
+ set_bit(X86_FEATURE_SYNC_RDTSC, c->x86_capability);
+ }
if (c->x86 == 6)
set_bit(X86_FEATURE_P3, c->x86_capability);
if ((c->x86 == 0xf && c->x86_model >= 0x03) ||
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index 80b4c5d421b..e5be819492e 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -733,9 +733,11 @@ static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
sys_dev = get_cpu_sysdev(cpu);
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cache_add_dev(sys_dev);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
cache_remove_dev(sys_dev);
break;
}
diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c
index b0862af595a..f9fa4142551 100644
--- a/arch/i386/kernel/cpu/mcheck/k7.c
+++ b/arch/i386/kernel/cpu/mcheck/k7.c
@@ -75,6 +75,9 @@ void amd_mcheck_init(struct cpuinfo_x86 *c)
machine_check_vector = k7_machine_check;
wmb();
+ if (!cpu_has(c, X86_FEATURE_MCE))
+ return;
+
printk (KERN_INFO "Intel machine check architecture supported.\n");
rdmsr (MSR_IA32_MCG_CAP, l, h);
if (l & (1<<8)) /* Control register present ? */
@@ -82,9 +85,13 @@ void amd_mcheck_init(struct cpuinfo_x86 *c)
nr_mce_banks = l & 0xff;
/* Clear status for MC index 0 separately, we don't touch CTL,
- * as some Athlons cause spurious MCEs when its enabled. */
- wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
- for (i=1; i<nr_mce_banks; i++) {
+ * as some K7 Athlons cause spurious MCEs when its enabled. */
+ if (boot_cpu_data.x86 == 6) {
+ wrmsr (MSR_IA32_MC0_STATUS, 0x0, 0x0);
+ i = 1;
+ } else
+ i = 0;
+ for (; i<nr_mce_banks; i++) {
wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
}
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
index 4f10c62d180..56cd485b127 100644
--- a/arch/i386/kernel/cpu/mcheck/mce.c
+++ b/arch/i386/kernel/cpu/mcheck/mce.c
@@ -38,8 +38,7 @@ void mcheck_init(struct cpuinfo_x86 *c)
switch (c->x86_vendor) {
case X86_VENDOR_AMD:
- if (c->x86==6 || c->x86==15)
- amd_mcheck_init(c);
+ amd_mcheck_init(c);
break;
case X86_VENDOR_INTEL:
diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c
index 504434a4601..1509edfb231 100644
--- a/arch/i386/kernel/cpu/mcheck/p4.c
+++ b/arch/i386/kernel/cpu/mcheck/p4.c
@@ -124,13 +124,10 @@ static void intel_init_thermal(struct cpuinfo_x86 *c)
/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
-static inline int intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+static inline void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
{
u32 h;
- if (mce_num_extended_msrs == 0)
- goto done;
-
rdmsr (MSR_IA32_MCG_EAX, r->eax, h);
rdmsr (MSR_IA32_MCG_EBX, r->ebx, h);
rdmsr (MSR_IA32_MCG_ECX, r->ecx, h);
@@ -141,12 +138,6 @@ static inline int intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
rdmsr (MSR_IA32_MCG_ESP, r->esp, h);
rdmsr (MSR_IA32_MCG_EFLAGS, r->eflags, h);
rdmsr (MSR_IA32_MCG_EIP, r->eip, h);
-
- /* can we rely on kmalloc to do a dynamic
- * allocation for the reserved registers?
- */
-done:
- return mce_num_extended_msrs;
}
static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
@@ -155,7 +146,6 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
u32 alow, ahigh, high, low;
u32 mcgstl, mcgsth;
int i;
- struct intel_mce_extended_msrs dbg;
rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
if (mcgstl & (1<<0)) /* Recoverable ? */
@@ -164,7 +154,9 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
smp_processor_id(), mcgsth, mcgstl);
- if (intel_get_extended_msrs(&dbg)) {
+ if (mce_num_extended_msrs > 0) {
+ struct intel_mce_extended_msrs dbg;
+ intel_get_extended_msrs(&dbg);
printk (KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n",
smp_processor_id(), dbg.eip, dbg.eflags);
printk (KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c
index 065005c3f16..7ba7c3abd3a 100644
--- a/arch/i386/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/i386/kerne/cpu/mcheck/therm_throt.c
+ * linux/arch/i386/kernel/cpu/mcheck/therm_throt.c
*
* Thermal throttle event support code (such as syslog messaging and rate
* limiting) that was factored out from x86_64 (mce_intel.c) and i386 (p4.c).
@@ -137,10 +137,12 @@ static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
mutex_lock(&therm_cpu_lock);
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
err = thermal_throttle_add_dev(sys_dev);
WARN_ON(err);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
thermal_throttle_remove_dev(sys_dev);
break;
}
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index f77fc53db65..5367e32e040 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -20,13 +20,25 @@ struct mtrr_state {
mtrr_type def_type;
};
+struct fixed_range_block {
+ int base_msr; /* start address of an MTRR block */
+ int ranges; /* number of MTRRs in this block */
+};
+
+static struct fixed_range_block fixed_range_blocks[] = {
+ { MTRRfix64K_00000_MSR, 1 }, /* one 64k MTRR */
+ { MTRRfix16K_80000_MSR, 2 }, /* two 16k MTRRs */
+ { MTRRfix4K_C0000_MSR, 8 }, /* eight 4k MTRRs */
+ {}
+};
+
static unsigned long smp_changes_mask;
static struct mtrr_state mtrr_state = {};
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "mtrr."
-static __initdata int mtrr_show;
+static int mtrr_show;
module_param_named(show, mtrr_show, bool, 0);
/* Get the MSR pair relating to a var range */
@@ -37,7 +49,7 @@ get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
rdmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi);
}
-static void __init
+static void
get_fixed_ranges(mtrr_type * frs)
{
unsigned int *p = (unsigned int *) frs;
@@ -51,12 +63,18 @@ get_fixed_ranges(mtrr_type * frs)
rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]);
}
-static void __init print_fixed(unsigned base, unsigned step, const mtrr_type*types)
+void mtrr_save_fixed_ranges(void *info)
+{
+ get_fixed_ranges(mtrr_state.fixed_ranges);
+}
+
+static void __cpuinit print_fixed(unsigned base, unsigned step, const mtrr_type*types)
{
unsigned i;
for (i = 0; i < 8; ++i, ++types, base += step)
- printk(KERN_INFO "MTRR %05X-%05X %s\n", base, base + step - 1, mtrr_attrib_to_str(*types));
+ printk(KERN_INFO "MTRR %05X-%05X %s\n",
+ base, base + step - 1, mtrr_attrib_to_str(*types));
}
/* Grab all of the MTRR state for this CPU into *state */
@@ -147,6 +165,44 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
smp_processor_id(), msr, a, b);
}
+/**
+ * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs
+ * see AMD publication no. 24593, chapter 3.2.1 for more information
+ */
+static inline void k8_enable_fixed_iorrs(void)
+{
+ unsigned lo, hi;
+
+ rdmsr(MSR_K8_SYSCFG, lo, hi);
+ mtrr_wrmsr(MSR_K8_SYSCFG, lo
+ | K8_MTRRFIXRANGE_DRAM_ENABLE
+ | K8_MTRRFIXRANGE_DRAM_MODIFY, hi);
+}
+
+/**
+ * Checks and updates an fixed-range MTRR if it differs from the value it
+ * should have. If K8 extenstions are wanted, update the K8 SYSCFG MSR also.
+ * see AMD publication no. 24593, chapter 7.8.1, page 233 for more information
+ * \param msr MSR address of the MTTR which should be checked and updated
+ * \param changed pointer which indicates whether the MTRR needed to be changed
+ * \param msrwords pointer to the MSR values which the MSR should have
+ */
+static void set_fixed_range(int msr, int * changed, unsigned int * msrwords)
+{
+ unsigned lo, hi;
+
+ rdmsr(msr, lo, hi);
+
+ if (lo != msrwords[0] || hi != msrwords[1]) {
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 == 15 &&
+ ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK))
+ k8_enable_fixed_iorrs();
+ mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
+ *changed = TRUE;
+ }
+}
+
int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg)
/* [SUMMARY] Get a free MTRR.
<base> The starting (base) address of the region.
@@ -196,36 +252,21 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base,
*type = base_lo & 0xff;
}
+/**
+ * Checks and updates the fixed-range MTRRs if they differ from the saved set
+ * \param frs pointer to fixed-range MTRR values, saved by get_fixed_ranges()
+ */
static int set_fixed_ranges(mtrr_type * frs)
{
- unsigned int *p = (unsigned int *) frs;
+ unsigned long long *saved = (unsigned long long *) frs;
int changed = FALSE;
- int i;
- unsigned int lo, hi;
+ int block=-1, range;
- rdmsr(MTRRfix64K_00000_MSR, lo, hi);
- if (p[0] != lo || p[1] != hi) {
- mtrr_wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
- changed = TRUE;
- }
+ while (fixed_range_blocks[++block].ranges)
+ for (range=0; range < fixed_range_blocks[block].ranges; range++)
+ set_fixed_range(fixed_range_blocks[block].base_msr + range,
+ &changed, (unsigned int *) saved++);
- for (i = 0; i < 2; i++) {
- rdmsr(MTRRfix16K_80000_MSR + i, lo, hi);
- if (p[2 + i * 2] != lo || p[3 + i * 2] != hi) {
- mtrr_wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i * 2],
- p[3 + i * 2]);
- changed = TRUE;
- }
- }
-
- for (i = 0; i < 8; i++) {
- rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi);
- if (p[6 + i * 2] != lo || p[7 + i * 2] != hi) {
- mtrr_wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2],
- p[7 + i * 2]);
- changed = TRUE;
- }
- }
return changed;
}
@@ -428,7 +469,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, unsigned i
}
}
- if (base + size < 0x100) {
+ if (base < 0x100) {
printk(KERN_WARNING "mtrr: cannot set region below 1 MiB (0x%lx000,0x%lx000)\n",
base, size);
return -EINVAL;
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 0acfb6a5a22..02a2f39e5e0 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -729,6 +729,17 @@ void mtrr_ap_init(void)
local_irq_restore(flags);
}
+/**
+ * Save current fixed-range MTRR state of the BSP
+ */
+void mtrr_save_state(void)
+{
+ if (smp_processor_id() == 0)
+ mtrr_save_fixed_ranges(NULL);
+ else
+ smp_call_function_single(0, mtrr_save_fixed_ranges, NULL, 1, 1);
+}
+
static int __init mtrr_init_finialize(void)
{
if (!mtrr_if)
diff --git a/arch/i386/kernel/cpu/nexgen.c b/arch/i386/kernel/cpu/nexgen.c
index 8bf23cc80c6..961fbe1a748 100644
--- a/arch/i386/kernel/cpu/nexgen.c
+++ b/arch/i386/kernel/cpu/nexgen.c
@@ -58,13 +58,3 @@ int __init nexgen_init_cpu(void)
cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev;
return 0;
}
-
-//early_arch_initcall(nexgen_init_cpu);
-
-static int __init nexgen_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_NEXGEN] = NULL;
- return 0;
-}
-
-late_initcall(nexgen_exit_cpu);
diff --git a/arch/i386/kernel/cpu/perfctr-watchdog.c b/arch/i386/kernel/cpu/perfctr-watchdog.c
new file mode 100644
index 00000000000..2b04c8f1db6
--- /dev/null
+++ b/arch/i386/kernel/cpu/perfctr-watchdog.c
@@ -0,0 +1,658 @@
+/* local apic based NMI watchdog for various CPUs.
+ This file also handles reservation of performance counters for coordination
+ with other users (like oprofile).
+
+ Note that these events normally don't tick when the CPU idles. This means
+ the frequency varies with CPU load.
+
+ Original code for K7/P6 written by Keith Owens */
+
+#include <linux/percpu.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/smp.h>
+#include <linux/nmi.h>
+#include <asm/apic.h>
+#include <asm/intel_arch_perfmon.h>
+
+struct nmi_watchdog_ctlblk {
+ unsigned int cccr_msr;
+ unsigned int perfctr_msr; /* the MSR to reset in NMI handler */
+ unsigned int evntsel_msr; /* the MSR to select the events to handle */
+};
+
+/* Interface defining a CPU specific perfctr watchdog */
+struct wd_ops {
+ int (*reserve)(void);
+ void (*unreserve)(void);
+ int (*setup)(unsigned nmi_hz);
+ void (*rearm)(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz);
+ void (*stop)(void *);
+ unsigned perfctr;
+ unsigned evntsel;
+ u64 checkbit;
+};
+
+static struct wd_ops *wd_ops;
+
+/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
+ * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
+ */
+#define NMI_MAX_COUNTER_BITS 66
+
+/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
+ * evtsel_nmi_owner tracks the ownership of the event selection
+ * - different performance counters/ event selection may be reserved for
+ * different subsystems this reservation system just tries to coordinate
+ * things a little
+ */
+static DECLARE_BITMAP(perfctr_nmi_owner, NMI_MAX_COUNTER_BITS);
+static DECLARE_BITMAP(evntsel_nmi_owner, NMI_MAX_COUNTER_BITS);
+
+static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+
+/* converts an msr to an appropriate reservation bit */
+static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
+{
+ return wd_ops ? msr - wd_ops->perfctr : 0;
+}
+
+/* converts an msr to an appropriate reservation bit */
+/* returns the bit offset of the event selection register */
+static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
+{
+ return wd_ops ? msr - wd_ops->evntsel : 0;
+}
+
+/* checks for a bit availability (hack for oprofile) */
+int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
+{
+ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
+
+ return (!test_bit(counter, perfctr_nmi_owner));
+}
+
+/* checks the an msr for availability */
+int avail_to_resrv_perfctr_nmi(unsigned int msr)
+{
+ unsigned int counter;
+
+ counter = nmi_perfctr_msr_to_bit(msr);
+ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
+
+ return (!test_bit(counter, perfctr_nmi_owner));
+}
+
+int reserve_perfctr_nmi(unsigned int msr)
+{
+ unsigned int counter;
+
+ counter = nmi_perfctr_msr_to_bit(msr);
+ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
+
+ if (!test_and_set_bit(counter, perfctr_nmi_owner))
+ return 1;
+ return 0;
+}
+
+void release_perfctr_nmi(unsigned int msr)
+{
+ unsigned int counter;
+
+ counter = nmi_perfctr_msr_to_bit(msr);
+ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
+
+ clear_bit(counter, perfctr_nmi_owner);
+}
+
+int reserve_evntsel_nmi(unsigned int msr)
+{
+ unsigned int counter;
+
+ counter = nmi_evntsel_msr_to_bit(msr);
+ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
+
+ if (!test_and_set_bit(counter, evntsel_nmi_owner))
+ return 1;
+ return 0;
+}
+
+void release_evntsel_nmi(unsigned int msr)
+{
+ unsigned int counter;
+
+ counter = nmi_evntsel_msr_to_bit(msr);
+ BUG_ON(counter > NMI_MAX_COUNTER_BITS);
+
+ clear_bit(counter, evntsel_nmi_owner);
+}
+
+EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
+EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
+EXPORT_SYMBOL(reserve_perfctr_nmi);
+EXPORT_SYMBOL(release_perfctr_nmi);
+EXPORT_SYMBOL(reserve_evntsel_nmi);
+EXPORT_SYMBOL(release_evntsel_nmi);
+
+void disable_lapic_nmi_watchdog(void)
+{
+ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+ if (atomic_read(&nmi_active) <= 0)
+ return;
+
+ on_each_cpu(wd_ops->stop, NULL, 0, 1);
+ wd_ops->unreserve();
+
+ BUG_ON(atomic_read(&nmi_active) != 0);
+}
+
+void enable_lapic_nmi_watchdog(void)
+{
+ BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
+
+ /* are we already enabled */
+ if (atomic_read(&nmi_active) != 0)
+ return;
+
+ /* are we lapic aware */
+ if (!wd_ops)
+ return;
+ if (!wd_ops->reserve()) {
+ printk(KERN_ERR "NMI watchdog: cannot reserve perfctrs\n");
+ return;
+ }
+
+ on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
+ touch_nmi_watchdog();
+}
+
+/*
+ * Activate the NMI watchdog via the local APIC.
+ */
+
+static unsigned int adjust_for_32bit_ctr(unsigned int hz)
+{
+ u64 counter_val;
+ unsigned int retval = hz;
+
+ /*
+ * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter
+ * are writable, with higher bits sign extending from bit 31.
+ * So, we can only program the counter with 31 bit values and
+ * 32nd bit should be 1, for 33.. to be 1.
+ * Find the appropriate nmi_hz
+ */
+ counter_val = (u64)cpu_khz * 1000;
+ do_div(counter_val, retval);
+ if (counter_val > 0x7fffffffULL) {
+ u64 count = (u64)cpu_khz * 1000;
+ do_div(count, 0x7fffffffUL);
+ retval = count + 1;
+ }
+ return retval;
+}
+
+static void
+write_watchdog_counter(unsigned int perfctr_msr, const char *descr, unsigned nmi_hz)
+{
+ u64 count = (u64)cpu_khz * 1000;
+
+ do_div(count, nmi_hz);
+ if(descr)
+ Dprintk("setting %s to -0x%08Lx\n", descr, count);
+ wrmsrl(perfctr_msr, 0 - count);
+}
+
+static void write_watchdog_counter32(unsigned int perfctr_msr,
+ const char *descr, unsigned nmi_hz)
+{
+ u64 count = (u64)cpu_khz * 1000;
+
+ do_div(count, nmi_hz);
+ if(descr)
+ Dprintk("setting %s to -0x%08Lx\n", descr, count);
+ wrmsr(perfctr_msr, (u32)(-count), 0);
+}
+
+/* AMD K7/K8/Family10h/Family11h support. AMD keeps this interface
+ nicely stable so there is not much variety */
+
+#define K7_EVNTSEL_ENABLE (1 << 22)
+#define K7_EVNTSEL_INT (1 << 20)
+#define K7_EVNTSEL_OS (1 << 17)
+#define K7_EVNTSEL_USR (1 << 16)
+#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
+#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
+
+static int setup_k7_watchdog(unsigned nmi_hz)
+{
+ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ perfctr_msr = MSR_K7_PERFCTR0;
+ evntsel_msr = MSR_K7_EVNTSEL0;
+
+ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = K7_EVNTSEL_INT
+ | K7_EVNTSEL_OS
+ | K7_EVNTSEL_USR
+ | K7_NMI_EVENT;
+
+ /* setup the timer */
+ wrmsr(evntsel_msr, evntsel, 0);
+ write_watchdog_counter(perfctr_msr, "K7_PERFCTR0",nmi_hz);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= K7_EVNTSEL_ENABLE;
+ wrmsr(evntsel_msr, evntsel, 0);
+
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = 0; //unused
+ return 1;
+}
+
+static void single_msr_stop_watchdog(void *arg)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ wrmsr(wd->evntsel_msr, 0, 0);
+}
+
+static int single_msr_reserve(void)
+{
+ if (!reserve_perfctr_nmi(wd_ops->perfctr))
+ return 0;
+
+ if (!reserve_evntsel_nmi(wd_ops->evntsel)) {
+ release_perfctr_nmi(wd_ops->perfctr);
+ return 0;
+ }
+ return 1;
+}
+
+static void single_msr_unreserve(void)
+{
+ release_evntsel_nmi(wd_ops->perfctr);
+ release_perfctr_nmi(wd_ops->evntsel);
+}
+
+static void single_msr_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+ /* start the cycle over again */
+ write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static struct wd_ops k7_wd_ops = {
+ .reserve = single_msr_reserve,
+ .unreserve = single_msr_unreserve,
+ .setup = setup_k7_watchdog,
+ .rearm = single_msr_rearm,
+ .stop = single_msr_stop_watchdog,
+ .perfctr = MSR_K7_PERFCTR0,
+ .evntsel = MSR_K7_EVNTSEL0,
+ .checkbit = 1ULL<<63,
+};
+
+/* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
+
+#define P6_EVNTSEL0_ENABLE (1 << 22)
+#define P6_EVNTSEL_INT (1 << 20)
+#define P6_EVNTSEL_OS (1 << 17)
+#define P6_EVNTSEL_USR (1 << 16)
+#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
+#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
+
+static int setup_p6_watchdog(unsigned nmi_hz)
+{
+ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ perfctr_msr = MSR_P6_PERFCTR0;
+ evntsel_msr = MSR_P6_EVNTSEL0;
+
+ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = P6_EVNTSEL_INT
+ | P6_EVNTSEL_OS
+ | P6_EVNTSEL_USR
+ | P6_NMI_EVENT;
+
+ /* setup the timer */
+ wrmsr(evntsel_msr, evntsel, 0);
+ nmi_hz = adjust_for_32bit_ctr(nmi_hz);
+ write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0",nmi_hz);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= P6_EVNTSEL0_ENABLE;
+ wrmsr(evntsel_msr, evntsel, 0);
+
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = 0; //unused
+ return 1;
+}
+
+static void p6_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+ /* P6 based Pentium M need to re-unmask
+ * the apic vector but it doesn't hurt
+ * other P6 variant.
+ * ArchPerfom/Core Duo also needs this */
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ /* P6/ARCH_PERFMON has 32 bit counter write */
+ write_watchdog_counter32(wd->perfctr_msr, NULL,nmi_hz);
+}
+
+static struct wd_ops p6_wd_ops = {
+ .reserve = single_msr_reserve,
+ .unreserve = single_msr_unreserve,
+ .setup = setup_p6_watchdog,
+ .rearm = p6_rearm,
+ .stop = single_msr_stop_watchdog,
+ .perfctr = MSR_P6_PERFCTR0,
+ .evntsel = MSR_P6_EVNTSEL0,
+ .checkbit = 1ULL<<39,
+};
+
+/* Intel P4 performance counters. By far the most complicated of all. */
+
+#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
+#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
+#define P4_ESCR_OS (1<<3)
+#define P4_ESCR_USR (1<<2)
+#define P4_CCCR_OVF_PMI0 (1<<26)
+#define P4_CCCR_OVF_PMI1 (1<<27)
+#define P4_CCCR_THRESHOLD(N) ((N)<<20)
+#define P4_CCCR_COMPLEMENT (1<<19)
+#define P4_CCCR_COMPARE (1<<18)
+#define P4_CCCR_REQUIRED (3<<16)
+#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
+#define P4_CCCR_ENABLE (1<<12)
+#define P4_CCCR_OVF (1<<31)
+
+/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
+ CRU_ESCR0 (with any non-null event selector) through a complemented
+ max threshold. [IA32-Vol3, Section 14.9.9] */
+
+static int setup_p4_watchdog(unsigned nmi_hz)
+{
+ unsigned int perfctr_msr, evntsel_msr, cccr_msr;
+ unsigned int evntsel, cccr_val;
+ unsigned int misc_enable, dummy;
+ unsigned int ht_num;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
+ if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+ return 0;
+
+#ifdef CONFIG_SMP
+ /* detect which hyperthread we are on */
+ if (smp_num_siblings == 2) {
+ unsigned int ebx, apicid;
+
+ ebx = cpuid_ebx(1);
+ apicid = (ebx >> 24) & 0xff;
+ ht_num = apicid & 1;
+ } else
+#endif
+ ht_num = 0;
+
+ /* performance counters are shared resources
+ * assign each hyperthread its own set
+ * (re-use the ESCR0 register, seems safe
+ * and keeps the cccr_val the same)
+ */
+ if (!ht_num) {
+ /* logical cpu 0 */
+ perfctr_msr = MSR_P4_IQ_PERFCTR0;
+ evntsel_msr = MSR_P4_CRU_ESCR0;
+ cccr_msr = MSR_P4_IQ_CCCR0;
+ cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
+ } else {
+ /* logical cpu 1 */
+ perfctr_msr = MSR_P4_IQ_PERFCTR1;
+ evntsel_msr = MSR_P4_CRU_ESCR0;
+ cccr_msr = MSR_P4_IQ_CCCR1;
+ cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4);
+ }
+
+ evntsel = P4_ESCR_EVENT_SELECT(0x3F)
+ | P4_ESCR_OS
+ | P4_ESCR_USR;
+
+ cccr_val |= P4_CCCR_THRESHOLD(15)
+ | P4_CCCR_COMPLEMENT
+ | P4_CCCR_COMPARE
+ | P4_CCCR_REQUIRED;
+
+ wrmsr(evntsel_msr, evntsel, 0);
+ wrmsr(cccr_msr, cccr_val, 0);
+ write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0", nmi_hz);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ cccr_val |= P4_CCCR_ENABLE;
+ wrmsr(cccr_msr, cccr_val, 0);
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = cccr_msr;
+ return 1;
+}
+
+static void stop_p4_watchdog(void *arg)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+ wrmsr(wd->cccr_msr, 0, 0);
+ wrmsr(wd->evntsel_msr, 0, 0);
+}
+
+static int p4_reserve(void)
+{
+ if (!reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR0))
+ return 0;
+#ifdef CONFIG_SMP
+ if (smp_num_siblings > 1 && !reserve_perfctr_nmi(MSR_P4_IQ_PERFCTR1))
+ goto fail1;
+#endif
+ if (!reserve_evntsel_nmi(MSR_P4_CRU_ESCR0))
+ goto fail2;
+ /* RED-PEN why is ESCR1 not reserved here? */
+ return 1;
+ fail2:
+#ifdef CONFIG_SMP
+ if (smp_num_siblings > 1)
+ release_perfctr_nmi(MSR_P4_IQ_PERFCTR1);
+ fail1:
+#endif
+ release_perfctr_nmi(MSR_P4_IQ_PERFCTR0);
+ return 0;
+}
+
+static void p4_unreserve(void)
+{
+#ifdef CONFIG_SMP
+ if (smp_num_siblings > 1)
+ release_evntsel_nmi(MSR_P4_IQ_PERFCTR1);
+#endif
+ release_evntsel_nmi(MSR_P4_IQ_PERFCTR0);
+ release_perfctr_nmi(MSR_P4_CRU_ESCR0);
+}
+
+static void p4_rearm(struct nmi_watchdog_ctlblk *wd, unsigned nmi_hz)
+{
+ unsigned dummy;
+ /*
+ * P4 quirks:
+ * - An overflown perfctr will assert its interrupt
+ * until the OVF flag in its CCCR is cleared.
+ * - LVTPC is masked on interrupt and must be
+ * unmasked by the LVTPC handler.
+ */
+ rdmsrl(wd->cccr_msr, dummy);
+ dummy &= ~P4_CCCR_OVF;
+ wrmsrl(wd->cccr_msr, dummy);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ /* start the cycle over again */
+ write_watchdog_counter(wd->perfctr_msr, NULL, nmi_hz);
+}
+
+static struct wd_ops p4_wd_ops = {
+ .reserve = p4_reserve,
+ .unreserve = p4_unreserve,
+ .setup = setup_p4_watchdog,
+ .rearm = p4_rearm,
+ .stop = stop_p4_watchdog,
+ /* RED-PEN this is wrong for the other sibling */
+ .perfctr = MSR_P4_BPU_PERFCTR0,
+ .evntsel = MSR_P4_BSU_ESCR0,
+ .checkbit = 1ULL<<39,
+};
+
+/* Watchdog using the Intel architected PerfMon. Used for Core2 and hopefully
+ all future Intel CPUs. */
+
+#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
+#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
+
+static int setup_intel_arch_watchdog(unsigned nmi_hz)
+{
+ unsigned int ebx;
+ union cpuid10_eax eax;
+ unsigned int unused;
+ unsigned int perfctr_msr, evntsel_msr;
+ unsigned int evntsel;
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+
+ /*
+ * Check whether the Architectural PerfMon supports
+ * Unhalted Core Cycles Event or not.
+ * NOTE: Corresponding bit = 0 in ebx indicates event present.
+ */
+ cpuid(10, &(eax.full), &ebx, &unused, &unused);
+ if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
+ (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
+ return 0;
+
+ perfctr_msr = MSR_ARCH_PERFMON_PERFCTR1;
+ evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL1;
+
+ wrmsrl(perfctr_msr, 0UL);
+
+ evntsel = ARCH_PERFMON_EVENTSEL_INT
+ | ARCH_PERFMON_EVENTSEL_OS
+ | ARCH_PERFMON_EVENTSEL_USR
+ | ARCH_PERFMON_NMI_EVENT_SEL
+ | ARCH_PERFMON_NMI_EVENT_UMASK;
+
+ /* setup the timer */
+ wrmsr(evntsel_msr, evntsel, 0);
+ nmi_hz = adjust_for_32bit_ctr(nmi_hz);
+ write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0", nmi_hz);
+ apic_write(APIC_LVTPC, APIC_DM_NMI);
+ evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
+ wrmsr(evntsel_msr, evntsel, 0);
+
+ wd->perfctr_msr = perfctr_msr;
+ wd->evntsel_msr = evntsel_msr;
+ wd->cccr_msr = 0; //unused
+ wd_ops->checkbit = 1ULL << (eax.split.bit_width - 1);
+ return 1;
+}
+
+static struct wd_ops intel_arch_wd_ops = {
+ .reserve = single_msr_reserve,
+ .unreserve = single_msr_unreserve,
+ .setup = setup_intel_arch_watchdog,
+ .rearm = p6_rearm,
+ .stop = single_msr_stop_watchdog,
+ .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
+ .evntsel = MSR_ARCH_PERFMON_EVENTSEL0,
+};
+
+static void probe_nmi_watchdog(void)
+{
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_AMD:
+ if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 &&
+ boot_cpu_data.x86 != 16)
+ return;
+ wd_ops = &k7_wd_ops;
+ break;
+ case X86_VENDOR_INTEL:
+ if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
+ wd_ops = &intel_arch_wd_ops;
+ break;
+ }
+ switch (boot_cpu_data.x86) {
+ case 6:
+ if (boot_cpu_data.x86_model > 0xd)
+ return;
+
+ wd_ops = &p6_wd_ops;
+ break;
+ case 15:
+ if (boot_cpu_data.x86_model > 0x4)
+ return;
+
+ wd_ops = &p4_wd_ops;
+ break;
+ default:
+ return;
+ }
+ break;
+ }
+}
+
+/* Interface to nmi.c */
+
+int lapic_watchdog_init(unsigned nmi_hz)
+{
+ if (!wd_ops) {
+ probe_nmi_watchdog();
+ if (!wd_ops)
+ return -1;
+ }
+
+ if (!(wd_ops->setup(nmi_hz))) {
+ printk(KERN_ERR "Cannot setup NMI watchdog on CPU %d\n",
+ raw_smp_processor_id());
+ return -1;
+ }
+
+ return 0;
+}
+
+void lapic_watchdog_stop(void)
+{
+ if (wd_ops)
+ wd_ops->stop(NULL);
+}
+
+unsigned lapic_adjust_nmi_hz(unsigned hz)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+ if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
+ wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR1)
+ hz = adjust_for_32bit_ctr(hz);
+ return hz;
+}
+
+int lapic_wd_event(unsigned nmi_hz)
+{
+ struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
+ u64 ctr;
+ rdmsrl(wd->perfctr_msr, ctr);
+ if (ctr & wd_ops->checkbit) { /* perfctr still running? */
+ return 0;
+ }
+ wd_ops->rearm(wd, nmi_hz);
+ return 1;
+}
+
+int lapic_watchdog_ok(void)
+{
+ return wd_ops != NULL;
+}
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
index 47e3ebbfb28..89d91e6cc97 100644
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -72,8 +72,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"stc",
"100mhzsteps",
"hwpstate",
- NULL,
- NULL, /* constant_tsc - moved to flags */
+ "", /* constant_tsc - moved to flags */
/* nothing */
};
struct cpuinfo_x86 *c = v;
diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
index 9317f741498..50076f22e90 100644
--- a/arch/i386/kernel/cpu/rise.c
+++ b/arch/i386/kernel/cpu/rise.c
@@ -50,12 +50,3 @@ int __init rise_init_cpu(void)
return 0;
}
-//early_arch_initcall(rise_init_cpu);
-
-static int __init rise_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_RISE] = NULL;
- return 0;
-}
-
-late_initcall(rise_exit_cpu);
diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
index 5678d46863c..200fb3f9ebf 100644
--- a/arch/i386/kernel/cpu/transmeta.c
+++ b/arch/i386/kernel/cpu/transmeta.c
@@ -77,8 +77,10 @@ static void __cpuinit init_transmeta(struct cpuinfo_x86 *c)
set_bit(X86_FEATURE_CONSTANT_TSC, c->x86_capability);
/* If we can run i686 user-space code, call us an i686 */
-#define USER686 (X86_FEATURE_TSC|X86_FEATURE_CX8|X86_FEATURE_CMOV)
- if ( c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686 )
+#define USER686 ((1 << X86_FEATURE_TSC)|\
+ (1 << X86_FEATURE_CX8)|\
+ (1 << X86_FEATURE_CMOV))
+ if (c->x86 == 5 && (c->x86_capability[0] & USER686) == USER686)
c->x86 = 6;
#ifdef CONFIG_SYSCTL
@@ -112,13 +114,3 @@ int __init transmeta_init_cpu(void)
cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
return 0;
}
-
-//early_arch_initcall(transmeta_init_cpu);
-
-static int __init transmeta_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_TRANSMETA] = NULL;
- return 0;
-}
-
-late_initcall(transmeta_exit_cpu);
diff --git a/arch/i386/kernel/cpu/umc.c b/arch/i386/kernel/cpu/umc.c
index 1bf3f87e9c5..a7a4e75bdcd 100644
--- a/arch/i386/kernel/cpu/umc.c
+++ b/arch/i386/kernel/cpu/umc.c
@@ -24,13 +24,3 @@ int __init umc_init_cpu(void)
cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev;
return 0;
}
-
-//early_arch_initcall(umc_init_cpu);
-
-static int __init umc_exit_cpu(void)
-{
- cpu_devs[X86_VENDOR_UMC] = NULL;
- return 0;
-}
-
-late_initcall(umc_exit_cpu);
diff --git a/arch/i386/kernel/cpuid.c b/arch/i386/kernel/cpuid.c
index eeae0d99233..5c2faa10e9f 100644
--- a/arch/i386/kernel/cpuid.c
+++ b/arch/i386/kernel/cpuid.c
@@ -169,9 +169,11 @@ static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long ac
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpuid_device_create(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
break;
}
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index a5e0e990ea9..53589d1b1a0 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -22,7 +22,7 @@
#include <asm/nmi.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
#include <asm/smp.h>
#include <mach_ipi.h>
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index b4d14c2eb34..265c5597efb 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -33,7 +33,7 @@ static void doublefault_fn(void)
printk("double fault, tss at %08lx\n", tss);
if (ptr_ok(tss)) {
- struct tss_struct *t = (struct tss_struct *)tss;
+ struct i386_hw_tss *t = (struct i386_hw_tss *)tss;
printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
@@ -49,18 +49,21 @@ static void doublefault_fn(void)
}
struct tss_struct doublefault_tss __cacheline_aligned = {
- .esp0 = STACK_START,
- .ss0 = __KERNEL_DS,
- .ldt = 0,
- .io_bitmap_base = INVALID_IO_BITMAP_OFFSET,
+ .x86_tss = {
+ .esp0 = STACK_START,
+ .ss0 = __KERNEL_DS,
+ .ldt = 0,
+ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET,
- .eip = (unsigned long) doublefault_fn,
- .eflags = X86_EFLAGS_SF | 0x2, /* 0x2 bit is always set */
- .esp = STACK_START,
- .es = __USER_DS,
- .cs = __KERNEL_CS,
- .ss = __KERNEL_DS,
- .ds = __USER_DS,
+ .eip = (unsigned long) doublefault_fn,
+ /* 0x2 bit is always set */
+ .eflags = X86_EFLAGS_SF | 0x2,
+ .esp = STACK_START,
+ .es = __USER_DS,
+ .cs = __KERNEL_CS,
+ .ss = __KERNEL_DS,
+ .ds = __USER_DS,
- .__cr3 = __pa(swapper_pg_dir)
+ .__cr3 = __pa(swapper_pg_dir)
+ }
};
diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c
index 70f39560846..9645bb51f76 100644
--- a/arch/i386/kernel/e820.c
+++ b/arch/i386/kernel/e820.c
@@ -161,26 +161,27 @@ static struct resource standard_io_resources[] = { {
static int __init romsignature(const unsigned char *rom)
{
+ const unsigned short * const ptr = (const unsigned short *)rom;
unsigned short sig;
- return probe_kernel_address((const unsigned short *)rom, sig) == 0 &&
- sig == ROMSIGNATURE;
+ return probe_kernel_address(ptr, sig) == 0 && sig == ROMSIGNATURE;
}
-static int __init romchecksum(unsigned char *rom, unsigned long length)
+static int __init romchecksum(const unsigned char *rom, unsigned long length)
{
- unsigned char sum;
+ unsigned char sum, c;
- for (sum = 0; length; length--)
- sum += *rom++;
- return sum == 0;
+ for (sum = 0; length && probe_kernel_address(rom++, c) == 0; length--)
+ sum += c;
+ return !length && !sum;
}
static void __init probe_roms(void)
{
+ const unsigned char *rom;
unsigned long start, length, upper;
- unsigned char *rom;
- int i;
+ unsigned char c;
+ int i;
/* video rom */
upper = adapter_rom_resources[0].start;
@@ -191,8 +192,11 @@ static void __init probe_roms(void)
video_rom_resource.start = start;
+ if (probe_kernel_address(rom + 2, c) != 0)
+ continue;
+
/* 0 < length <= 0x7f * 512, historically */
- length = rom[2] * 512;
+ length = c * 512;
/* if checksum okay, trust length byte */
if (length && romchecksum(rom, length))
@@ -226,8 +230,11 @@ static void __init probe_roms(void)
if (!romsignature(rom))
continue;
+ if (probe_kernel_address(rom + 2, c) != 0)
+ continue;
+
/* 0 < length <= 0x7f * 512, historically */
- length = rom[2] * 512;
+ length = c * 512;
/* but accept any length that fits if checksum okay */
if (!length || start + length > upper || !romchecksum(rom, length))
@@ -386,10 +393,8 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
____________________33__
______________________4_
*/
- printk("sanitize start\n");
/* if there's only one memory region, don't bother */
if (*pnr_map < 2) {
- printk("sanitize bail 0\n");
return -1;
}
@@ -398,7 +403,6 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
/* bail out if we find any unreasonable addresses in bios map */
for (i=0; i<old_nr; i++)
if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr) {
- printk("sanitize bail 1\n");
return -1;
}
@@ -494,7 +498,6 @@ int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
*pnr_map = new_nr;
- printk("sanitize end\n");
return 0;
}
@@ -525,7 +528,6 @@ int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
unsigned long long size = biosmap->size;
unsigned long long end = start + size;
unsigned long type = biosmap->type;
- printk("copy_e820_map() start: %016Lx size: %016Lx end: %016Lx type: %ld\n", start, size, end, type);
/* Overflow in 64 bits? Ignore the memory map. */
if (start > end)
@@ -536,17 +538,11 @@ int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
* Not right. Fix it up.
*/
if (type == E820_RAM) {
- printk("copy_e820_map() type is E820_RAM\n");
if (start < 0x100000ULL && end > 0xA0000ULL) {
- printk("copy_e820_map() lies in range...\n");
- if (start < 0xA0000ULL) {
- printk("copy_e820_map() start < 0xA0000ULL\n");
+ if (start < 0xA0000ULL)
add_memory_region(start, 0xA0000ULL-start, type);
- }
- if (end <= 0x100000ULL) {
- printk("copy_e820_map() end <= 0x100000ULL\n");
+ if (end <= 0x100000ULL)
continue;
- }
start = 0x100000ULL;
size = end - start;
}
@@ -818,6 +814,26 @@ void __init limit_regions(unsigned long long size)
print_memory_map("limit_regions endfunc");
}
+/*
+ * This function checks if any part of the range <start,end> is mapped
+ * with type.
+ */
+int
+e820_any_mapped(u64 start, u64 end, unsigned type)
+{
+ int i;
+ for (i = 0; i < e820.nr_map; i++) {
+ const struct e820entry *ei = &e820.map[i];
+ if (type && ei->type != type)
+ continue;
+ if (ei->addr >= end || ei->addr + ei->size <= start)
+ continue;
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(e820_any_mapped);
+
/*
* This function checks if the entire range <start,end> is mapped with type.
*
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index 8f9c624ace6..a1808022ea1 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -69,13 +69,11 @@ static void efi_call_phys_prelog(void) __acquires(efi_rt_lock)
{
unsigned long cr4;
unsigned long temp;
- struct Xgt_desc_struct *cpu_gdt_descr;
+ struct Xgt_desc_struct gdt_descr;
spin_lock(&efi_rt_lock);
local_irq_save(efi_rt_eflags);
- cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
-
/*
* If I don't have PSE, I should just duplicate two entries in page
* directory. If I have PSE, I just need to duplicate one entry in
@@ -105,17 +103,19 @@ static void efi_call_phys_prelog(void) __acquires(efi_rt_lock)
*/
local_flush_tlb();
- cpu_gdt_descr->address = __pa(cpu_gdt_descr->address);
- load_gdt(cpu_gdt_descr);
+ gdt_descr.address = __pa(get_cpu_gdt_table(0));
+ gdt_descr.size = GDT_SIZE - 1;
+ load_gdt(&gdt_descr);
}
static void efi_call_phys_epilog(void) __releases(efi_rt_lock)
{
unsigned long cr4;
- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
+ struct Xgt_desc_struct gdt_descr;
- cpu_gdt_descr->address = (unsigned long)__va(cpu_gdt_descr->address);
- load_gdt(cpu_gdt_descr);
+ gdt_descr.address = (unsigned long)get_cpu_gdt_table(0);
+ gdt_descr.size = GDT_SIZE - 1;
+ load_gdt(&gdt_descr);
cr4 = read_cr4();
@@ -347,14 +347,12 @@ void __init efi_init(void)
printk(KERN_ERR PFX "Woah! Couldn't map the EFI system table.\n");
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
printk(KERN_ERR PFX "Woah! EFI system table signature incorrect\n");
- if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
- printk(KERN_ERR PFX
- "Warning: EFI system table major version mismatch: "
- "got %d.%02d, expected %d.%02d\n",
+ if ((efi.systab->hdr.revision >> 16) == 0)
+ printk(KERN_ERR PFX "Warning: EFI system table version "
+ "%d.%02d, expected 1.00 or greater\n",
efi.systab->hdr.revision >> 16,
- efi.systab->hdr.revision & 0xffff,
- EFI_SYSTEM_TABLE_REVISION >> 16,
- EFI_SYSTEM_TABLE_REVISION & 0xffff);
+ efi.systab->hdr.revision & 0xffff);
+
/*
* Grab some details from the system table
*/
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 18bddcb8e9e..b1f16ee65e4 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -15,7 +15,7 @@
* I changed all the .align's to 4 (16 byte alignment), as that's faster
* on a 486.
*
- * Stack layout in 'ret_from_system_call':
+ * Stack layout in 'syscall_exit':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
* updated in fork.c:copy_process, signal.c:do_signal,
@@ -132,7 +132,7 @@ VM_MASK = 0x00020000
movl $(__USER_DS), %edx; \
movl %edx, %ds; \
movl %edx, %es; \
- movl $(__KERNEL_PDA), %edx; \
+ movl $(__KERNEL_PERCPU), %edx; \
movl %edx, %fs
#define RESTORE_INT_REGS \
@@ -305,16 +305,12 @@ sysenter_past_esp:
pushl $(__USER_CS)
CFI_ADJUST_CFA_OFFSET 4
/*CFI_REL_OFFSET cs, 0*/
-#ifndef CONFIG_COMPAT_VDSO
/*
* Push current_thread_info()->sysenter_return to the stack.
* A tiny bit of offset fixup is necessary - 4*4 means the 4 words
* pushed above; +8 corresponds to copy_thread's esp0 setting.
*/
pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
-#else
- pushl $SYSENTER_RETURN
-#endif
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET eip, 0
@@ -342,7 +338,7 @@ sysenter_past_esp:
jae syscall_badsys
call *sys_call_table(,%eax,4)
movl %eax,PT_EAX(%esp)
- DISABLE_INTERRUPTS(CLBR_ECX|CLBR_EDX)
+ DISABLE_INTERRUPTS(CLBR_ANY)
TRACE_IRQS_OFF
movl TI_flags(%ebp), %ecx
testw $_TIF_ALLWORK_MASK, %cx
@@ -560,9 +556,7 @@ END(syscall_badsys)
#define FIXUP_ESPFIX_STACK \
/* since we are on a wrong stack, we cant make it a C code :( */ \
- movl %fs:PDA_cpu, %ebx; \
- PER_CPU(cpu_gdt_descr, %ebx); \
- movl GDS_address(%ebx), %ebx; \
+ PER_CPU(gdt_page, %ebx); \
GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \
addl %esp, %eax; \
pushl $__KERNEL_DS; \
@@ -635,7 +629,7 @@ ENTRY(name) \
SAVE_ALL; \
TRACE_IRQS_OFF \
movl %esp,%eax; \
- call smp_/**/name; \
+ call smp_##name; \
jmp ret_from_intr; \
CFI_ENDPROC; \
ENDPROC(name)
@@ -643,11 +637,6 @@ ENDPROC(name)
/* The include is where all of the SMP etc. interrupts come from */
#include "entry_arch.h"
-/* This alternate entry is needed because we hijack the apic LVTT */
-#if defined(CONFIG_VMI) && defined(CONFIG_X86_LOCAL_APIC)
-BUILD_INTERRUPT(apic_vmi_timer_interrupt,LOCAL_TIMER_VECTOR)
-#endif
-
KPROBE_ENTRY(page_fault)
RING0_EC_FRAME
pushl $do_page_fault
@@ -686,7 +675,7 @@ error_code:
pushl %fs
CFI_ADJUST_CFA_OFFSET 4
/*CFI_REL_OFFSET fs, 0*/
- movl $(__KERNEL_PDA), %ecx
+ movl $(__KERNEL_PERCPU), %ecx
movl %ecx, %fs
UNWIND_ESPFIX_STACK
popl %ecx
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 3fa7f9389af..9b10af65faa 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -34,17 +34,32 @@
/*
* This is how much memory *in addition to the memory covered up to
- * and including _end* we need mapped initially. We need one bit for
- * each possible page, but only in low memory, which means
- * 2^32/4096/8 = 128K worst case (4G/4G split.)
+ * and including _end* we need mapped initially.
+ * We need:
+ * - one bit for each possible page, but only in low memory, which means
+ * 2^32/4096/8 = 128K worst case (4G/4G split.)
+ * - enough space to map all low memory, which means
+ * (2^32/4096) / 1024 pages (worst case, non PAE)
+ * (2^32/4096) / 512 + 4 pages (worst case for PAE)
+ * - a few pages for allocator use before the kernel pagetable has
+ * been set up
*
* Modulo rounding, each megabyte assigned here requires a kilobyte of
* memory, which is currently unreclaimed.
*
* This should be a multiple of a page.
*/
-#define INIT_MAP_BEYOND_END (128*1024)
+LOW_PAGES = 1<<(32-PAGE_SHIFT_asm)
+#if PTRS_PER_PMD > 1
+PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PMD) + PTRS_PER_PGD
+#else
+PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PGD)
+#endif
+BOOTBITMAP_SIZE = LOW_PAGES / 8
+ALLOCATOR_SLOP = 4
+
+INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm
/*
* 32-bit kernel entrypoint; only used by the boot CPU. On entry,
@@ -147,8 +162,7 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
/*
* Non-boot CPU entry point; entered from trampoline.S
* We can't lgdt here, because lgdt itself uses a data segment, but
- * we know the trampoline has already loaded the boot_gdt_table GDT
- * for us.
+ * we know the trampoline has already loaded the boot_gdt for us.
*
* If cpu hotplug is not supported then this code can go in init section
* which will be freed later
@@ -318,12 +332,12 @@ is386: movl $2,%ecx # set MP
movl %eax,%cr0
call check_x87
- call setup_pda
lgdt early_gdt_descr
lidt idt_descr
ljmp $(__KERNEL_CS),$1f
1: movl $(__KERNEL_DS),%eax # reload all the segment registers
movl %eax,%ss # after changing gdt.
+ movl %eax,%fs # gets reset once there's real percpu
movl $(__USER_DS),%eax # DS/ES contains default USER segment
movl %eax,%ds
@@ -333,16 +347,17 @@ is386: movl $2,%ecx # set MP
movl %eax,%gs
lldt %ax
- movl $(__KERNEL_PDA),%eax
- mov %eax,%fs
-
cld # gcc2 wants the direction flag cleared at all times
pushl $0 # fake return address for unwinder
#ifdef CONFIG_SMP
movb ready, %cl
movb $1, ready
cmpb $0,%cl # the first CPU calls start_kernel
- jne initialize_secondary # all other CPUs call initialize_secondary
+ je 1f
+ movl $(__KERNEL_PERCPU), %eax
+ movl %eax,%fs # set this cpu's percpu
+ jmp initialize_secondary # all other CPUs call initialize_secondary
+1:
#endif /* CONFIG_SMP */
jmp start_kernel
@@ -366,23 +381,6 @@ check_x87:
ret
/*
- * Point the GDT at this CPU's PDA. On boot this will be
- * cpu_gdt_table and boot_pda; for secondary CPUs, these will be
- * that CPU's GDT and PDA.
- */
-ENTRY(setup_pda)
- /* get the PDA pointer */
- movl start_pda, %eax
-
- /* slot the PDA address into the GDT */
- mov early_gdt_descr+2, %ecx
- mov %ax, (__KERNEL_PDA+0+2)(%ecx) /* base & 0x0000ffff */
- shr $16, %eax
- mov %al, (__KERNEL_PDA+4+0)(%ecx) /* base & 0x00ff0000 */
- mov %ah, (__KERNEL_PDA+4+3)(%ecx) /* base & 0xff000000 */
- ret
-
-/*
* setup_idt
*
* sets up a idt with 256 entries pointing to
@@ -554,9 +552,6 @@ ENTRY(empty_zero_page)
* This starts the data section.
*/
.data
-ENTRY(start_pda)
- .long boot_pda
-
ENTRY(stack_start)
.long init_thread_union+THREAD_SIZE
.long __BOOT_DS
@@ -588,7 +583,7 @@ fault_msg:
.word 0 # 32 bit align gdt_desc.address
boot_gdt_descr:
.word __BOOT_DS+7
- .long boot_gdt_table - __PAGE_OFFSET
+ .long boot_gdt - __PAGE_OFFSET
.word 0 # 32-bit align idt_desc.address
idt_descr:
@@ -599,67 +594,14 @@ idt_descr:
.word 0 # 32 bit align gdt_desc.address
ENTRY(early_gdt_descr)
.word GDT_ENTRIES*8-1
- .long cpu_gdt_table
+ .long per_cpu__gdt_page /* Overwritten for secondary CPUs */
/*
- * The boot_gdt_table must mirror the equivalent in setup.S and is
+ * The boot_gdt must mirror the equivalent in setup.S and is
* used only for booting.
*/
.align L1_CACHE_BYTES
-ENTRY(boot_gdt_table)
+ENTRY(boot_gdt)
.fill GDT_ENTRY_BOOT_CS,8,0
.quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */
.quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */
-
-/*
- * The Global Descriptor Table contains 28 quadwords, per-CPU.
- */
- .align L1_CACHE_BYTES
-ENTRY(cpu_gdt_table)
- .quad 0x0000000000000000 /* NULL descriptor */
- .quad 0x0000000000000000 /* 0x0b reserved */
- .quad 0x0000000000000000 /* 0x13 reserved */
- .quad 0x0000000000000000 /* 0x1b reserved */
- .quad 0x0000000000000000 /* 0x20 unused */
- .quad 0x0000000000000000 /* 0x28 unused */
- .quad 0x0000000000000000 /* 0x33 TLS entry 1 */
- .quad 0x0000000000000000 /* 0x3b TLS entry 2 */
- .quad 0x0000000000000000 /* 0x43 TLS entry 3 */
- .quad 0x0000000000000000 /* 0x4b reserved */
- .quad 0x0000000000000000 /* 0x53 reserved */
- .quad 0x0000000000000000 /* 0x5b reserved */
-
- .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */
- .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */
- .quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */
- .quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */
-
- .quad 0x0000000000000000 /* 0x80 TSS descriptor */
- .quad 0x0000000000000000 /* 0x88 LDT descriptor */
-
- /*
- * Segments used for calling PnP BIOS have byte granularity.
- * They code segments and data segments have fixed 64k limits,
- * the transfer segment sizes are set at run time.
- */
- .quad 0x00409a000000ffff /* 0x90 32-bit code */
- .quad 0x00009a000000ffff /* 0x98 16-bit code */
- .quad 0x000092000000ffff /* 0xa0 16-bit data */
- .quad 0x0000920000000000 /* 0xa8 16-bit data */
- .quad 0x0000920000000000 /* 0xb0 16-bit data */
-
- /*
- * The APM segments have byte granularity and their bases
- * are set at run time. All have 64k limits.
- */
- .quad 0x00409a000000ffff /* 0xb8 APM CS code */
- .quad 0x00009a000000ffff /* 0xc0 APM CS 16 code (16 bit) */
- .quad 0x004092000000ffff /* 0xc8 APM DS data */
-
- .quad 0x00c0920000000000 /* 0xd0 - ESPFIX SS */
- .quad 0x00cf92000000ffff /* 0xd8 - PDA */
- .quad 0x0000000000000000 /* 0xe0 - unused */
- .quad 0x0000000000000000 /* 0xe8 - unused */
- .quad 0x0000000000000000 /* 0xf0 - unused */
- .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */
-
diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
index 4afe26e8626..e3d4b73bfdb 100644
--- a/arch/i386/kernel/i386_ksyms.c
+++ b/arch/i386/kernel/i386_ksyms.c
@@ -28,5 +28,3 @@ EXPORT_SYMBOL(__read_lock_failed);
#endif
EXPORT_SYMBOL(csum_partial);
-
-EXPORT_SYMBOL(_proxy_pda);
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index 10cef5ca8a5..f8a3c4054c7 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -110,7 +110,7 @@ void __init setup_pit_timer(void)
* Start pit with the boot cpu mask and make it global after the
* IO_APIC has been initialized.
*/
- pit_clockevent.cpumask = cpumask_of_cpu(0);
+ pit_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
pit_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, 32);
pit_clockevent.max_delta_ns =
clockevent_delta2ns(0x7FFF, &pit_clockevent);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index 03abfdb1a6e..0499cbe9871 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -5,7 +5,6 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/random.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sysdev.h>
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index b3ab8ffebd2..7f8b7af2b95 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/mc146818rtc.h>
#include <linux/compiler.h>
#include <linux/acpi.h>
@@ -35,6 +34,7 @@
#include <linux/msi.h>
#include <linux/htirq.h>
#include <linux/freezer.h>
+#include <linux/kthread.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -661,8 +661,6 @@ static int balanced_irq(void *unused)
unsigned long prev_balance_time = jiffies;
long time_remaining = balanced_irq_interval;
- daemonize("kirqd");
-
/* push everything to CPU 0 to give us a starting point. */
for (i = 0 ; i < NR_IRQS ; i++) {
irq_desc[i].pending_mask = cpumask_of_cpu(0);
@@ -722,10 +720,9 @@ static int __init balanced_irq_init(void)
}
printk(KERN_INFO "Starting balanced_irq\n");
- if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0)
+ if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd")))
return 0;
- else
- printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
+ printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
failed:
for_each_possible_cpu(i) {
kfree(irq_cpu_data[i].irq_delta);
@@ -1403,10 +1400,6 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
enable_8259A_irq(0);
}
-static inline void UNEXPECTED_IO_APIC(void)
-{
-}
-
void __init print_IO_APIC(void)
{
int apic, i;
@@ -1446,34 +1439,12 @@ void __init print_IO_APIC(void)
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
- if (reg_00.bits.ID >= get_physical_broadcast())
- UNEXPECTED_IO_APIC();
- if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw);
printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
- if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */
- (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */
- (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */
- (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */
- (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
- (reg_01.bits.entries != 0x2E) &&
- (reg_01.bits.entries != 0x3F)
- )
- UNEXPECTED_IO_APIC();
printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
- if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */
- (reg_01.bits.version != 0x10) && /* oldest IO-APICs */
- (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
- (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
- (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */
- )
- UNEXPECTED_IO_APIC();
- if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
/*
* Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
@@ -1483,8 +1454,6 @@ void __init print_IO_APIC(void)
if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
- if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
}
/*
@@ -1496,8 +1465,6 @@ void __init print_IO_APIC(void)
reg_03.raw != reg_01.raw) {
printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw);
printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT);
- if (reg_03.bits.__reserved_1)
- UNEXPECTED_IO_APIC();
}
printk(KERN_DEBUG ".... IRQ redirection table:\n");
@@ -2611,19 +2578,19 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
if (irq < 0)
return irq;
- set_irq_msi(irq, desc);
ret = msi_compose_msg(dev, irq, &msg);
if (ret < 0) {
destroy_irq(irq);
return ret;
}
+ set_irq_msi(irq, desc);
write_msi_msg(irq, &msg);
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
"edge");
- return irq;
+ return 0;
}
void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
index 498e8bc197d..3d310a946d7 100644
--- a/arch/i386/kernel/ioport.c
+++ b/arch/i386/kernel/ioport.c
@@ -12,10 +12,10 @@
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/thread_info.h>
+#include <linux/syscalls.h>
/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value)
@@ -113,7 +113,7 @@ asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on)
* Reset the owner so that a process switch will not set
* tss->io_bitmap_base to IO_BITMAP_OFFSET.
*/
- tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
+ tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
tss->io_bitmap_owner = NULL;
put_cpu();
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 8db8d514c9c..d2daf672f4a 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -24,6 +24,9 @@
DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
EXPORT_PER_CPU_SYMBOL(irq_stat);
+DEFINE_PER_CPU(struct pt_regs *, irq_regs);
+EXPORT_PER_CPU_SYMBOL(irq_regs);
+
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves.
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index b545bc746fc..dde828a333c 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -31,8 +31,8 @@
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <linux/preempt.h>
+#include <linux/kdebug.h>
#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
#include <asm/desc.h>
#include <asm/uaccess.h>
@@ -226,24 +226,15 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
}
/* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)&regs->esp;
- struct kretprobe_instance *ri;
+ ri->ret_addr = (kprobe_opcode_t *) *sara;
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
- ri->ret_addr = (kprobe_opcode_t *) *sara;
-
- /* Replace the return addr with trampoline addr */
- *sara = (unsigned long) &kretprobe_trampoline;
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ /* Replace the return addr with trampoline addr */
+ *sara = (unsigned long) &kretprobe_trampoline;
}
/*
@@ -449,8 +440,7 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
break;
}
- BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
-
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
spin_unlock_irqrestore(&kretprobe_lock, flags);
hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
@@ -753,6 +743,11 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ return 0;
+}
+
int __init arch_init_kprobes(void)
{
return 0;
diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
index b410e5fb034..e0b2d17f4f1 100644
--- a/arch/i386/kernel/ldt.c
+++ b/arch/i386/kernel/ldt.c
@@ -10,7 +10,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
diff --git a/arch/i386/kernel/legacy_serial.c b/arch/i386/kernel/legacy_serial.c
new file mode 100644
index 00000000000..21510118544
--- /dev/null
+++ b/arch/i386/kernel/legacy_serial.c
@@ -0,0 +1,67 @@
+/*
+ * Legacy COM port devices for x86 platforms without PNPBIOS or ACPI.
+ * Data taken from include/asm-i386/serial.h.
+ *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.com>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/pnp.h>
+#include <linux/serial_8250.h>
+
+/* Standard COM flags (except for COM4, because of the 8514 problem) */
+#ifdef CONFIG_SERIAL_DETECT_IRQ
+#define COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ)
+#define COM4_FLAGS (UPF_BOOT_AUTOCONF | UPF_AUTO_IRQ)
+#else
+#define COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
+#define COM4_FLAGS UPF_BOOT_AUTOCONF
+#endif
+
+#define PORT(_base,_irq,_flags) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = _flags, \
+ }
+
+static struct plat_serial8250_port x86_com_data[] = {
+ PORT(0x3F8, 4, COM_FLAGS),
+ PORT(0x2F8, 3, COM_FLAGS),
+ PORT(0x3E8, 4, COM_FLAGS),
+ PORT(0x2E8, 3, COM4_FLAGS),
+ { },
+};
+
+static struct platform_device x86_com_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = x86_com_data,
+ },
+};
+
+static int force_legacy_probe;
+module_param_named(force, force_legacy_probe, bool, 0);
+MODULE_PARM_DESC(force, "Force legacy serial port probe");
+
+static int __init serial8250_x86_com_init(void)
+{
+ if (pnp_platform_devices && !force_legacy_probe)
+ return -ENODEV;
+
+ return platform_device_register(&x86_com_device);
+}
+
+module_init(serial8250_x86_com_init);
+
+MODULE_AUTHOR("Bjorn Helgaas");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 legacy probe module");
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index cbe7ec8dbb9..83f825f2e2d 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -567,7 +567,7 @@ static int cpu_request_microcode(int cpu)
return error;
}
-static int apply_microcode_on_cpu(int cpu)
+static int apply_microcode_check_cpu(int cpu)
{
struct cpuinfo_x86 *c = cpu_data + cpu;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -575,8 +575,9 @@ static int apply_microcode_on_cpu(int cpu)
unsigned int val[2];
int err = 0;
+ /* Check if the microcode is available */
if (!uci->mc)
- return -EINVAL;
+ return 0;
old = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(cpu));
@@ -614,7 +615,7 @@ static int apply_microcode_on_cpu(int cpu)
return err;
}
-static void microcode_init_cpu(int cpu)
+static void microcode_init_cpu(int cpu, int resume)
{
cpumask_t old;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
@@ -624,8 +625,7 @@ static void microcode_init_cpu(int cpu)
set_cpus_allowed(current, cpumask_of_cpu(cpu));
mutex_lock(&microcode_mutex);
collect_cpu_info(cpu);
- if (uci->valid && system_state == SYSTEM_RUNNING &&
- !suspend_cpu_hotplug)
+ if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
cpu_request_microcode(cpu);
mutex_unlock(&microcode_mutex);
set_cpus_allowed(current, old);
@@ -702,7 +702,7 @@ static struct attribute_group mc_attr_group = {
.name = "microcode",
};
-static int mc_sysdev_add(struct sys_device *sys_dev)
+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;
@@ -711,39 +711,31 @@ static int mc_sysdev_add(struct sys_device *sys_dev)
return 0;
pr_debug("Microcode:CPU %d added\n", cpu);
- /* If suspend_cpu_hotplug is set, the system is resuming and we should
- * use the data from before the suspend.
- */
- if (suspend_cpu_hotplug) {
- err = apply_microcode_on_cpu(cpu);
- if (err)
- microcode_fini_cpu(cpu);
- }
- if (!uci->valid)
- memset(uci, 0, sizeof(*uci));
+ memset(uci, 0, sizeof(*uci));
err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
if (err)
return err;
- if (!uci->valid)
- microcode_init_cpu(cpu);
+ 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);
- /* If suspend_cpu_hotplug is set, the system is suspending and we should
- * keep the microcode in memory for the resume.
- */
- if (!suspend_cpu_hotplug)
- microcode_fini_cpu(cpu);
+ microcode_fini_cpu(cpu);
sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
return 0;
}
@@ -774,13 +766,34 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
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;
}
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 4f5983c9866..13abb4ebfb7 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -18,7 +18,6 @@
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
-#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/bitops.h>
@@ -477,7 +476,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
++mpc_record;
}
- clustered_apic_check();
+ setup_apic_routing();
if (!num_processors)
printk(KERN_ERR "SMP mptable: no processors registered!\n");
return num_processors;
diff --git a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
index bcaa6e9b619..0c1069b8d63 100644
--- a/arch/i386/kernel/msr.c
+++ b/arch/i386/kernel/msr.c
@@ -45,104 +45,6 @@
static struct class *msr_class;
-static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
-{
- int err;
-
- err = wrmsr_safe(reg, eax, edx);
- if (err)
- err = -EIO;
- return err;
-}
-
-static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
-{
- int err;
-
- err = rdmsr_safe(reg, eax, edx);
- if (err)
- err = -EIO;
- return err;
-}
-
-#ifdef CONFIG_SMP
-
-struct msr_command {
- int err;
- u32 reg;
- u32 data[2];
-};
-
-static void msr_smp_wrmsr(void *cmd_block)
-{
- struct msr_command *cmd = (struct msr_command *)cmd_block;
-
- cmd->err = wrmsr_eio(cmd->reg, cmd->data[0], cmd->data[1]);
-}
-
-static void msr_smp_rdmsr(void *cmd_block)
-{
- struct msr_command *cmd = (struct msr_command *)cmd_block;
-
- cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
-}
-
-static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-{
- struct msr_command cmd;
- int ret;
-
- preempt_disable();
- if (cpu == smp_processor_id()) {
- ret = wrmsr_eio(reg, eax, edx);
- } else {
- cmd.reg = reg;
- cmd.data[0] = eax;
- cmd.data[1] = edx;
-
- smp_call_function_single(cpu, msr_smp_wrmsr, &cmd, 1, 1);
- ret = cmd.err;
- }
- preempt_enable();
- return ret;
-}
-
-static inline int do_rdmsr(int cpu, u32 reg, u32 * eax, u32 * edx)
-{
- struct msr_command cmd;
- int ret;
-
- preempt_disable();
- if (cpu == smp_processor_id()) {
- ret = rdmsr_eio(reg, eax, edx);
- } else {
- cmd.reg = reg;
-
- smp_call_function_single(cpu, msr_smp_rdmsr, &cmd, 1, 1);
-
- *eax = cmd.data[0];
- *edx = cmd.data[1];
-
- ret = cmd.err;
- }
- preempt_enable();
- return ret;
-}
-
-#else /* ! CONFIG_SMP */
-
-static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
-{
- return wrmsr_eio(reg, eax, edx);
-}
-
-static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
-{
- return rdmsr_eio(reg, eax, edx);
-}
-
-#endif /* ! CONFIG_SMP */
-
static loff_t msr_seek(struct file *file, loff_t offset, int orig)
{
loff_t ret = -EINVAL;
@@ -174,9 +76,9 @@ static ssize_t msr_read(struct file *file, char __user * buf,
return -EINVAL; /* Invalid chunk size */
for (; count; count -= 8) {
- err = do_rdmsr(cpu, reg, &data[0], &data[1]);
+ err = rdmsr_safe_on_cpu(cpu, reg, &data[0], &data[1]);
if (err)
- return err;
+ return -EIO;
if (copy_to_user(tmp, &data, 8))
return -EFAULT;
tmp += 2;
@@ -200,9 +102,9 @@ static ssize_t msr_write(struct file *file, const char __user *buf,
for (; count; count -= 8) {
if (copy_from_user(&data, tmp, 8))
return -EFAULT;
- err = do_wrmsr(cpu, reg, data[0], data[1]);
+ err = wrmsr_safe_on_cpu(cpu, reg, data[0], data[1]);
if (err)
- return err;
+ return -EIO;
tmp += 2;
}
@@ -251,9 +153,11 @@ static int msr_class_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
msr_device_create(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
break;
}
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 84c3497efb6..fba121f7973 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -20,38 +20,21 @@
#include <linux/sysdev.h>
#include <linux/sysctl.h>
#include <linux/percpu.h>
-#include <linux/dmi.h>
#include <linux/kprobes.h>
#include <linux/cpumask.h>
#include <linux/kernel_stat.h>
+#include <linux/kdebug.h>
#include <asm/smp.h>
#include <asm/nmi.h>
-#include <asm/kdebug.h>
-#include <asm/intel_arch_perfmon.h>
#include "mach_traps.h"
int unknown_nmi_panic;
int nmi_watchdog_enabled;
-/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
- * evtsel_nmi_owner tracks the ownership of the event selection
- * - different performance counters/ event selection may be reserved for
- * different subsystems this reservation system just tries to coordinate
- * things a little
- */
-
-/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
- * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
- */
-#define NMI_MAX_COUNTER_BITS 66
-#define NMI_MAX_COUNTER_LONGS BITS_TO_LONGS(NMI_MAX_COUNTER_BITS)
-
-static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-
static cpumask_t backtrace_mask = CPU_MASK_NONE;
+
/* nmi_active:
* >0: the lapic NMI watchdog is active, but can be disabled
* <0: the lapic NMI watchdog has not been set up, and cannot
@@ -63,206 +46,11 @@ atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
unsigned int nmi_watchdog = NMI_DEFAULT;
static unsigned int nmi_hz = HZ;
-struct nmi_watchdog_ctlblk {
- int enabled;
- u64 check_bit;
- unsigned int cccr_msr;
- unsigned int perfctr_msr; /* the MSR to reset in NMI handler */
- unsigned int evntsel_msr; /* the MSR to select the events to handle */
-};
-static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+static DEFINE_PER_CPU(short, wd_enabled);
/* local prototypes */
static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
-extern void show_registers(struct pt_regs *regs);
-extern int unknown_nmi_panic;
-
-/* converts an msr to an appropriate reservation bit */
-static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
-{
- /* returns the bit offset of the performance counter register */
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- return (msr - MSR_K7_PERFCTR0);
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
- return (msr - MSR_ARCH_PERFMON_PERFCTR0);
-
- switch (boot_cpu_data.x86) {
- case 6:
- return (msr - MSR_P6_PERFCTR0);
- case 15:
- return (msr - MSR_P4_BPU_PERFCTR0);
- }
- }
- return 0;
-}
-
-/* converts an msr to an appropriate reservation bit */
-static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
-{
- /* returns the bit offset of the event selection register */
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- return (msr - MSR_K7_EVNTSEL0);
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
- return (msr - MSR_ARCH_PERFMON_EVENTSEL0);
-
- switch (boot_cpu_data.x86) {
- case 6:
- return (msr - MSR_P6_EVNTSEL0);
- case 15:
- return (msr - MSR_P4_BSU_ESCR0);
- }
- }
- return 0;
-}
-
-/* checks for a bit availability (hack for oprofile) */
-int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
-{
- int cpu;
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
- for_each_possible_cpu (cpu) {
- if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]))
- return 0;
- }
- return 1;
-}
-
-/* checks the an msr for availability */
-int avail_to_resrv_perfctr_nmi(unsigned int msr)
-{
- unsigned int counter;
- int cpu;
-
- counter = nmi_perfctr_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- for_each_possible_cpu (cpu) {
- if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]))
- return 0;
- }
- return 1;
-}
-
-static int __reserve_perfctr_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_perfctr_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]))
- return 1;
- return 0;
-}
-
-static void __release_perfctr_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_perfctr_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)[0]);
-}
-
-int reserve_perfctr_nmi(unsigned int msr)
-{
- int cpu, i;
- for_each_possible_cpu (cpu) {
- if (!__reserve_perfctr_nmi(cpu, msr)) {
- for_each_possible_cpu (i) {
- if (i >= cpu)
- break;
- __release_perfctr_nmi(i, msr);
- }
- return 0;
- }
- }
- return 1;
-}
-
-void release_perfctr_nmi(unsigned int msr)
-{
- int cpu;
- for_each_possible_cpu (cpu) {
- __release_perfctr_nmi(cpu, msr);
- }
-}
-
-int __reserve_evntsel_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_evntsel_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]))
- return 1;
- return 0;
-}
-
-static void __release_evntsel_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_evntsel_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]);
-}
-
-int reserve_evntsel_nmi(unsigned int msr)
-{
- int cpu, i;
- for_each_possible_cpu (cpu) {
- if (!__reserve_evntsel_nmi(cpu, msr)) {
- for_each_possible_cpu (i) {
- if (i >= cpu)
- break;
- __release_evntsel_nmi(i, msr);
- }
- return 0;
- }
- }
- return 1;
-}
-
-void release_evntsel_nmi(unsigned int msr)
-{
- int cpu;
- for_each_possible_cpu (cpu) {
- __release_evntsel_nmi(cpu, msr);
- }
-}
-
-static __cpuinit inline int nmi_known_cpu(void)
-{
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6)
- || (boot_cpu_data.x86 == 16));
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
- return 1;
- else
- return ((boot_cpu_data.x86 == 15) || (boot_cpu_data.x86 == 6));
- }
- return 0;
-}
-
static int endflag __initdata = 0;
#ifdef CONFIG_SMP
@@ -284,28 +72,6 @@ static __init void nmi_cpu_busy(void *data)
}
#endif
-static unsigned int adjust_for_32bit_ctr(unsigned int hz)
-{
- u64 counter_val;
- unsigned int retval = hz;
-
- /*
- * On Intel CPUs with P6/ARCH_PERFMON only 32 bits in the counter
- * are writable, with higher bits sign extending from bit 31.
- * So, we can only program the counter with 31 bit values and
- * 32nd bit should be 1, for 33.. to be 1.
- * Find the appropriate nmi_hz
- */
- counter_val = (u64)cpu_khz * 1000;
- do_div(counter_val, retval);
- if (counter_val > 0x7fffffffULL) {
- u64 count = (u64)cpu_khz * 1000;
- do_div(count, 0x7fffffffUL);
- retval = count + 1;
- }
- return retval;
-}
-
static int __init check_nmi_watchdog(void)
{
unsigned int *prev_nmi_count;
@@ -338,14 +104,14 @@ static int __init check_nmi_watchdog(void)
if (!cpu_isset(cpu, cpu_callin_map))
continue;
#endif
- if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled)
+ if (!per_cpu(wd_enabled, cpu))
continue;
if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
cpu,
prev_nmi_count[cpu],
nmi_count(cpu));
- per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0;
+ per_cpu(wd_enabled, cpu) = 0;
atomic_dec(&nmi_active);
}
}
@@ -359,16 +125,8 @@ static int __init check_nmi_watchdog(void)
/* now that we know it works we can reduce NMI frequency to
something more reasonable; makes a difference in some configs */
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- nmi_hz = 1;
-
- if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
- wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
- nmi_hz = adjust_for_32bit_ctr(nmi_hz);
- }
- }
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ nmi_hz = lapic_adjust_nmi_hz(1);
kfree(prev_nmi_count);
return 0;
@@ -391,85 +149,8 @@ static int __init setup_nmi_watchdog(char *str)
__setup("nmi_watchdog=", setup_nmi_watchdog);
-static void disable_lapic_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
- if (atomic_read(&nmi_active) <= 0)
- return;
-
- on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-
- BUG_ON(atomic_read(&nmi_active) != 0);
-}
-
-static void enable_lapic_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
- /* are we already enabled */
- if (atomic_read(&nmi_active) != 0)
- return;
-
- /* are we lapic aware */
- if (nmi_known_cpu() <= 0)
- return;
- on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
- touch_nmi_watchdog();
-}
-
-void disable_timer_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
- if (atomic_read(&nmi_active) <= 0)
- return;
-
- disable_irq(0);
- on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-
- BUG_ON(atomic_read(&nmi_active) != 0);
-}
-
-void enable_timer_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
- if (atomic_read(&nmi_active) == 0) {
- touch_nmi_watchdog();
- on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
- enable_irq(0);
- }
-}
-
-static void __acpi_nmi_disable(void *__unused)
-{
- apic_write_around(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
-}
-
-/*
- * Disable timer based NMIs on all CPUs:
- */
-void acpi_nmi_disable(void)
-{
- if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
- on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
-}
-
-static void __acpi_nmi_enable(void *__unused)
-{
- apic_write_around(APIC_LVT0, APIC_DM_NMI);
-}
-
-/*
- * Enable timer based NMIs on all CPUs:
- */
-void acpi_nmi_enable(void)
-{
- if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
- on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
-}
+/* Suspend/resume support */
#ifdef CONFIG_PM
@@ -516,7 +197,7 @@ static int __init init_lapic_nmi_sysfs(void)
if (nmi_watchdog != NMI_LOCAL_APIC)
return 0;
- if ( atomic_read(&nmi_active) < 0 )
+ if (atomic_read(&nmi_active) < 0)
return 0;
error = sysdev_class_register(&nmi_sysclass);
@@ -529,433 +210,69 @@ late_initcall(init_lapic_nmi_sysfs);
#endif /* CONFIG_PM */
-/*
- * Activate the NMI watchdog via the local APIC.
- * Original code written by Keith Owens.
- */
-
-static void write_watchdog_counter(unsigned int perfctr_msr, const char *descr)
-{
- u64 count = (u64)cpu_khz * 1000;
-
- do_div(count, nmi_hz);
- if(descr)
- Dprintk("setting %s to -0x%08Lx\n", descr, count);
- wrmsrl(perfctr_msr, 0 - count);
-}
-
-static void write_watchdog_counter32(unsigned int perfctr_msr,
- const char *descr)
-{
- u64 count = (u64)cpu_khz * 1000;
-
- do_div(count, nmi_hz);
- if(descr)
- Dprintk("setting %s to -0x%08Lx\n", descr, count);
- wrmsr(perfctr_msr, (u32)(-count), 0);
-}
-
-/* Note that these events don't tick when the CPU idles. This means
- the frequency varies with CPU load. */
-
-#define K7_EVNTSEL_ENABLE (1 << 22)
-#define K7_EVNTSEL_INT (1 << 20)
-#define K7_EVNTSEL_OS (1 << 17)
-#define K7_EVNTSEL_USR (1 << 16)
-#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
-#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
-
-static int setup_k7_watchdog(void)
-{
- unsigned int perfctr_msr, evntsel_msr;
- unsigned int evntsel;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- perfctr_msr = MSR_K7_PERFCTR0;
- evntsel_msr = MSR_K7_EVNTSEL0;
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- wrmsrl(perfctr_msr, 0UL);
-
- evntsel = K7_EVNTSEL_INT
- | K7_EVNTSEL_OS
- | K7_EVNTSEL_USR
- | K7_NMI_EVENT;
-
- /* setup the timer */
- wrmsr(evntsel_msr, evntsel, 0);
- write_watchdog_counter(perfctr_msr, "K7_PERFCTR0");
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- evntsel |= K7_EVNTSEL_ENABLE;
- wrmsr(evntsel_msr, evntsel, 0);
-
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = 0; //unused
- wd->check_bit = 1ULL<<63;
- return 1;
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
-}
-
-static void stop_k7_watchdog(void)
-{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- wrmsr(wd->evntsel_msr, 0, 0);
-
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
-}
-
-#define P6_EVNTSEL0_ENABLE (1 << 22)
-#define P6_EVNTSEL_INT (1 << 20)
-#define P6_EVNTSEL_OS (1 << 17)
-#define P6_EVNTSEL_USR (1 << 16)
-#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
-#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
-
-static int setup_p6_watchdog(void)
-{
- unsigned int perfctr_msr, evntsel_msr;
- unsigned int evntsel;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- perfctr_msr = MSR_P6_PERFCTR0;
- evntsel_msr = MSR_P6_EVNTSEL0;
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- wrmsrl(perfctr_msr, 0UL);
-
- evntsel = P6_EVNTSEL_INT
- | P6_EVNTSEL_OS
- | P6_EVNTSEL_USR
- | P6_NMI_EVENT;
-
- /* setup the timer */
- wrmsr(evntsel_msr, evntsel, 0);
- nmi_hz = adjust_for_32bit_ctr(nmi_hz);
- write_watchdog_counter32(perfctr_msr, "P6_PERFCTR0");
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- evntsel |= P6_EVNTSEL0_ENABLE;
- wrmsr(evntsel_msr, evntsel, 0);
-
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = 0; //unused
- wd->check_bit = 1ULL<<39;
- return 1;
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
-}
-
-static void stop_p6_watchdog(void)
-{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- wrmsr(wd->evntsel_msr, 0, 0);
-
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
-}
-
-/* Note that these events don't tick when the CPU idles. This means
- the frequency varies with CPU load. */
-
-#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
-#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
-#define P4_ESCR_OS (1<<3)
-#define P4_ESCR_USR (1<<2)
-#define P4_CCCR_OVF_PMI0 (1<<26)
-#define P4_CCCR_OVF_PMI1 (1<<27)
-#define P4_CCCR_THRESHOLD(N) ((N)<<20)
-#define P4_CCCR_COMPLEMENT (1<<19)
-#define P4_CCCR_COMPARE (1<<18)
-#define P4_CCCR_REQUIRED (3<<16)
-#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
-#define P4_CCCR_ENABLE (1<<12)
-#define P4_CCCR_OVF (1<<31)
-/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
- CRU_ESCR0 (with any non-null event selector) through a complemented
- max threshold. [IA32-Vol3, Section 14.9.9] */
-
-static int setup_p4_watchdog(void)
+static void __acpi_nmi_enable(void *__unused)
{
- unsigned int perfctr_msr, evntsel_msr, cccr_msr;
- unsigned int evntsel, cccr_val;
- unsigned int misc_enable, dummy;
- unsigned int ht_num;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
- if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
- return 0;
-
-#ifdef CONFIG_SMP
- /* detect which hyperthread we are on */
- if (smp_num_siblings == 2) {
- unsigned int ebx, apicid;
-
- ebx = cpuid_ebx(1);
- apicid = (ebx >> 24) & 0xff;
- ht_num = apicid & 1;
- } else
-#endif
- ht_num = 0;
-
- /* performance counters are shared resources
- * assign each hyperthread its own set
- * (re-use the ESCR0 register, seems safe
- * and keeps the cccr_val the same)
- */
- if (!ht_num) {
- /* logical cpu 0 */
- perfctr_msr = MSR_P4_IQ_PERFCTR0;
- evntsel_msr = MSR_P4_CRU_ESCR0;
- cccr_msr = MSR_P4_IQ_CCCR0;
- cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
- } else {
- /* logical cpu 1 */
- perfctr_msr = MSR_P4_IQ_PERFCTR1;
- evntsel_msr = MSR_P4_CRU_ESCR0;
- cccr_msr = MSR_P4_IQ_CCCR1;
- cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4);
- }
-
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- evntsel = P4_ESCR_EVENT_SELECT(0x3F)
- | P4_ESCR_OS
- | P4_ESCR_USR;
-
- cccr_val |= P4_CCCR_THRESHOLD(15)
- | P4_CCCR_COMPLEMENT
- | P4_CCCR_COMPARE
- | P4_CCCR_REQUIRED;
-
- wrmsr(evntsel_msr, evntsel, 0);
- wrmsr(cccr_msr, cccr_val, 0);
- write_watchdog_counter(perfctr_msr, "P4_IQ_COUNTER0");
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- cccr_val |= P4_CCCR_ENABLE;
- wrmsr(cccr_msr, cccr_val, 0);
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = cccr_msr;
- wd->check_bit = 1ULL<<39;
- return 1;
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
+ apic_write_around(APIC_LVT0, APIC_DM_NMI);
}
-static void stop_p4_watchdog(void)
+/*
+ * Enable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_enable(void)
{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- wrmsr(wd->cccr_msr, 0, 0);
- wrmsr(wd->evntsel_msr, 0, 0);
-
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
+ if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+ on_each_cpu(__acpi_nmi_enable, NULL, 0, 1);
}
-#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
-#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
-
-static int setup_intel_arch_watchdog(void)
+static void __acpi_nmi_disable(void *__unused)
{
- unsigned int ebx;
- union cpuid10_eax eax;
- unsigned int unused;
- unsigned int perfctr_msr, evntsel_msr;
- unsigned int evntsel;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- /*
- * Check whether the Architectural PerfMon supports
- * Unhalted Core Cycles Event or not.
- * NOTE: Corresponding bit = 0 in ebx indicates event present.
- */
- cpuid(10, &(eax.full), &ebx, &unused, &unused);
- if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
- (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
- goto fail;
-
- perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
- evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0;
-
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- wrmsrl(perfctr_msr, 0UL);
-
- evntsel = ARCH_PERFMON_EVENTSEL_INT
- | ARCH_PERFMON_EVENTSEL_OS
- | ARCH_PERFMON_EVENTSEL_USR
- | ARCH_PERFMON_NMI_EVENT_SEL
- | ARCH_PERFMON_NMI_EVENT_UMASK;
-
- /* setup the timer */
- wrmsr(evntsel_msr, evntsel, 0);
- nmi_hz = adjust_for_32bit_ctr(nmi_hz);
- write_watchdog_counter32(perfctr_msr, "INTEL_ARCH_PERFCTR0");
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
- wrmsr(evntsel_msr, evntsel, 0);
-
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = 0; //unused
- wd->check_bit = 1ULL << (eax.split.bit_width - 1);
- return 1;
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
+ apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
}
-static void stop_intel_arch_watchdog(void)
+/*
+ * Disable timer based NMIs on all CPUs:
+ */
+void acpi_nmi_disable(void)
{
- unsigned int ebx;
- union cpuid10_eax eax;
- unsigned int unused;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- /*
- * Check whether the Architectural PerfMon supports
- * Unhalted Core Cycles Event or not.
- * NOTE: Corresponding bit = 0 in ebx indicates event present.
- */
- cpuid(10, &(eax.full), &ebx, &unused, &unused);
- if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
- (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
- return;
-
- wrmsr(wd->evntsel_msr, 0, 0);
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
+ if (atomic_read(&nmi_active) && nmi_watchdog == NMI_IO_APIC)
+ on_each_cpu(__acpi_nmi_disable, NULL, 0, 1);
}
void setup_apic_nmi_watchdog (void *unused)
{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- /* only support LOCAL and IO APICs for now */
- if ((nmi_watchdog != NMI_LOCAL_APIC) &&
- (nmi_watchdog != NMI_IO_APIC))
- return;
-
- if (wd->enabled == 1)
- return;
+ if (__get_cpu_var(wd_enabled))
+ return;
/* cheap hack to support suspend/resume */
/* if cpu0 is not active neither should the other cpus */
if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
return;
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 &&
- boot_cpu_data.x86 != 16)
- return;
- if (!setup_k7_watchdog())
- return;
- break;
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
- if (!setup_intel_arch_watchdog())
- return;
- break;
- }
- switch (boot_cpu_data.x86) {
- case 6:
- if (boot_cpu_data.x86_model > 0xd)
- return;
-
- if (!setup_p6_watchdog())
- return;
- break;
- case 15:
- if (boot_cpu_data.x86_model > 0x4)
- return;
-
- if (!setup_p4_watchdog())
- return;
- break;
- default:
- return;
- }
- break;
- default:
+ switch (nmi_watchdog) {
+ case NMI_LOCAL_APIC:
+ __get_cpu_var(wd_enabled) = 1; /* enable it before to avoid race with handler */
+ if (lapic_watchdog_init(nmi_hz) < 0) {
+ __get_cpu_var(wd_enabled) = 0;
return;
}
+ /* FALL THROUGH */
+ case NMI_IO_APIC:
+ __get_cpu_var(wd_enabled) = 1;
+ atomic_inc(&nmi_active);
}
- wd->enabled = 1;
- atomic_inc(&nmi_active);
}
void stop_apic_nmi_watchdog(void *unused)
{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
/* only support LOCAL and IO APICs for now */
if ((nmi_watchdog != NMI_LOCAL_APIC) &&
(nmi_watchdog != NMI_IO_APIC))
return;
-
- if (wd->enabled == 0)
+ if (__get_cpu_var(wd_enabled) == 0)
return;
-
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- stop_k7_watchdog();
- break;
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
- stop_intel_arch_watchdog();
- break;
- }
- switch (boot_cpu_data.x86) {
- case 6:
- if (boot_cpu_data.x86_model > 0xd)
- break;
- stop_p6_watchdog();
- break;
- case 15:
- if (boot_cpu_data.x86_model > 0x4)
- break;
- stop_p4_watchdog();
- break;
- }
- break;
- default:
- return;
- }
- }
- wd->enabled = 0;
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ lapic_watchdog_stop();
+ __get_cpu_var(wd_enabled) = 0;
atomic_dec(&nmi_active);
}
@@ -1011,8 +328,6 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
unsigned int sum;
int touched = 0;
int cpu = smp_processor_id();
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
- u64 dummy;
int rc=0;
/* check for other users first */
@@ -1055,53 +370,20 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
alert_counter[cpu] = 0;
}
/* see if the nmi watchdog went off */
- if (wd->enabled) {
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- rdmsrl(wd->perfctr_msr, dummy);
- if (dummy & wd->check_bit){
- /* this wasn't a watchdog timer interrupt */
- goto done;
- }
-
- /* only Intel P4 uses the cccr msr */
- if (wd->cccr_msr != 0) {
- /*
- * P4 quirks:
- * - An overflown perfctr will assert its interrupt
- * until the OVF flag in its CCCR is cleared.
- * - LVTPC is masked on interrupt and must be
- * unmasked by the LVTPC handler.
- */
- rdmsrl(wd->cccr_msr, dummy);
- dummy &= ~P4_CCCR_OVF;
- wrmsrl(wd->cccr_msr, dummy);
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- /* start the cycle over again */
- write_watchdog_counter(wd->perfctr_msr, NULL);
- }
- else if (wd->perfctr_msr == MSR_P6_PERFCTR0 ||
- wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
- /* P6 based Pentium M need to re-unmask
- * the apic vector but it doesn't hurt
- * other P6 variant.
- * ArchPerfom/Core Duo also needs this */
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- /* P6/ARCH_PERFMON has 32 bit counter write */
- write_watchdog_counter32(wd->perfctr_msr, NULL);
- } else {
- /* start the cycle over again */
- write_watchdog_counter(wd->perfctr_msr, NULL);
- }
- rc = 1;
- } else if (nmi_watchdog == NMI_IO_APIC) {
- /* don't know how to accurately check for this.
- * just assume it was a watchdog timer interrupt
- * This matches the old behaviour.
- */
- rc = 1;
- }
+ if (!__get_cpu_var(wd_enabled))
+ return rc;
+ switch (nmi_watchdog) {
+ case NMI_LOCAL_APIC:
+ rc |= lapic_wd_event(nmi_hz);
+ break;
+ case NMI_IO_APIC:
+ /* don't know how to accurately check for this.
+ * just assume it was a watchdog timer interrupt
+ * This matches the old behaviour.
+ */
+ rc = 1;
+ break;
}
-done:
return rc;
}
@@ -1146,7 +428,7 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
}
if (nmi_watchdog == NMI_DEFAULT) {
- if (nmi_known_cpu() > 0)
+ if (lapic_watchdog_ok())
nmi_watchdog = NMI_LOCAL_APIC;
else
nmi_watchdog = NMI_IO_APIC;
@@ -1182,11 +464,3 @@ void __trigger_all_cpu_backtrace(void)
EXPORT_SYMBOL(nmi_active);
EXPORT_SYMBOL(nmi_watchdog);
-EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
-EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
-EXPORT_SYMBOL(reserve_perfctr_nmi);
-EXPORT_SYMBOL(release_perfctr_nmi);
-EXPORT_SYMBOL(reserve_evntsel_nmi);
-EXPORT_SYMBOL(release_evntsel_nmi);
-EXPORT_SYMBOL(disable_timer_nmi_watchdog);
-EXPORT_SYMBOL(enable_timer_nmi_watchdog);
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index 2ec331e03fa..5c10f376bce 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -20,6 +20,7 @@
#include <linux/efi.h>
#include <linux/bcd.h>
#include <linux/start_kernel.h>
+#include <linux/highmem.h>
#include <asm/bug.h>
#include <asm/paravirt.h>
@@ -35,7 +36,7 @@
#include <asm/timer.h>
/* nop stub */
-static void native_nop(void)
+void _paravirt_nop(void)
{
}
@@ -54,331 +55,148 @@ char *memory_setup(void)
#define DEF_NATIVE(name, code) \
extern const char start_##name[], end_##name[]; \
asm("start_" #name ": " code "; end_" #name ":")
-DEF_NATIVE(cli, "cli");
-DEF_NATIVE(sti, "sti");
-DEF_NATIVE(popf, "push %eax; popf");
-DEF_NATIVE(pushf, "pushf; pop %eax");
-DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli");
+
+DEF_NATIVE(irq_disable, "cli");
+DEF_NATIVE(irq_enable, "sti");
+DEF_NATIVE(restore_fl, "push %eax; popf");
+DEF_NATIVE(save_fl, "pushf; pop %eax");
DEF_NATIVE(iret, "iret");
-DEF_NATIVE(sti_sysexit, "sti; sysexit");
+DEF_NATIVE(irq_enable_sysexit, "sti; sysexit");
+DEF_NATIVE(read_cr2, "mov %cr2, %eax");
+DEF_NATIVE(write_cr3, "mov %eax, %cr3");
+DEF_NATIVE(read_cr3, "mov %cr3, %eax");
+DEF_NATIVE(clts, "clts");
+DEF_NATIVE(read_tsc, "rdtsc");
-static const struct native_insns
-{
- const char *start, *end;
-} native_insns[] = {
- [PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli },
- [PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti },
- [PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf },
- [PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf },
- [PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli },
- [PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret },
- [PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit },
-};
+DEF_NATIVE(ud2a, "ud2a");
static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len)
{
- unsigned int insn_len;
-
- /* Don't touch it if we don't have a replacement */
- if (type >= ARRAY_SIZE(native_insns) || !native_insns[type].start)
- return len;
-
- insn_len = native_insns[type].end - native_insns[type].start;
-
- /* Similarly if we can't fit replacement. */
- if (len < insn_len)
- return len;
+ const unsigned char *start, *end;
+ unsigned ret;
+
+ switch(type) {
+#define SITE(x) case PARAVIRT_PATCH(x): start = start_##x; end = end_##x; goto patch_site
+ SITE(irq_disable);
+ SITE(irq_enable);
+ SITE(restore_fl);
+ SITE(save_fl);
+ SITE(iret);
+ SITE(irq_enable_sysexit);
+ SITE(read_cr2);
+ SITE(read_cr3);
+ SITE(write_cr3);
+ SITE(clts);
+ SITE(read_tsc);
+#undef SITE
+
+ patch_site:
+ ret = paravirt_patch_insns(insns, len, start, end);
+ break;
- memcpy(insns, native_insns[type].start, insn_len);
- return insn_len;
-}
+ case PARAVIRT_PATCH(make_pgd):
+ case PARAVIRT_PATCH(make_pte):
+ case PARAVIRT_PATCH(pgd_val):
+ case PARAVIRT_PATCH(pte_val):
+#ifdef CONFIG_X86_PAE
+ case PARAVIRT_PATCH(make_pmd):
+ case PARAVIRT_PATCH(pmd_val):
+#endif
+ /* These functions end up returning exactly what
+ they're passed, in the same registers. */
+ ret = paravirt_patch_nop();
+ break;
-static unsigned long native_get_debugreg(int regno)
-{
- unsigned long val = 0; /* Damn you, gcc! */
-
- switch (regno) {
- case 0:
- asm("movl %%db0, %0" :"=r" (val)); break;
- case 1:
- asm("movl %%db1, %0" :"=r" (val)); break;
- case 2:
- asm("movl %%db2, %0" :"=r" (val)); break;
- case 3:
- asm("movl %%db3, %0" :"=r" (val)); break;
- case 6:
- asm("movl %%db6, %0" :"=r" (val)); break;
- case 7:
- asm("movl %%db7, %0" :"=r" (val)); break;
default:
- BUG();
- }
- return val;
-}
-
-static void native_set_debugreg(int regno, unsigned long value)
-{
- switch (regno) {
- case 0:
- asm("movl %0,%%db0" : /* no output */ :"r" (value));
- break;
- case 1:
- asm("movl %0,%%db1" : /* no output */ :"r" (value));
- break;
- case 2:
- asm("movl %0,%%db2" : /* no output */ :"r" (value));
+ ret = paravirt_patch_default(type, clobbers, insns, len);
break;
- case 3:
- asm("movl %0,%%db3" : /* no output */ :"r" (value));
- break;
- case 6:
- asm("movl %0,%%db6" : /* no output */ :"r" (value));
- break;
- case 7:
- asm("movl %0,%%db7" : /* no output */ :"r" (value));
- break;
- default:
- BUG();
}
-}
-
-void init_IRQ(void)
-{
- paravirt_ops.init_IRQ();
-}
-
-static void native_clts(void)
-{
- asm volatile ("clts");
-}
-
-static unsigned long native_read_cr0(void)
-{
- unsigned long val;
- asm volatile("movl %%cr0,%0\n\t" :"=r" (val));
- return val;
-}
-
-static void native_write_cr0(unsigned long val)
-{
- asm volatile("movl %0,%%cr0": :"r" (val));
-}
-
-static unsigned long native_read_cr2(void)
-{
- unsigned long val;
- asm volatile("movl %%cr2,%0\n\t" :"=r" (val));
- return val;
-}
-
-static void native_write_cr2(unsigned long val)
-{
- asm volatile("movl %0,%%cr2": :"r" (val));
-}
-
-static unsigned long native_read_cr3(void)
-{
- unsigned long val;
- asm volatile("movl %%cr3,%0\n\t" :"=r" (val));
- return val;
-}
-
-static void native_write_cr3(unsigned long val)
-{
- asm volatile("movl %0,%%cr3": :"r" (val));
-}
-
-static unsigned long native_read_cr4(void)
-{
- unsigned long val;
- asm volatile("movl %%cr4,%0\n\t" :"=r" (val));
- return val;
-}
-
-static unsigned long native_read_cr4_safe(void)
-{
- unsigned long val;
- /* This could fault if %cr4 does not exist */
- asm("1: movl %%cr4, %0 \n"
- "2: \n"
- ".section __ex_table,\"a\" \n"
- ".long 1b,2b \n"
- ".previous \n"
- : "=r" (val): "0" (0));
- return val;
-}
-
-static void native_write_cr4(unsigned long val)
-{
- asm volatile("movl %0,%%cr4": :"r" (val));
-}
-
-static unsigned long native_save_fl(void)
-{
- unsigned long f;
- asm volatile("pushfl ; popl %0":"=g" (f): /* no input */);
- return f;
-}
-
-static void native_restore_fl(unsigned long f)
-{
- asm volatile("pushl %0 ; popfl": /* no output */
- :"g" (f)
- :"memory", "cc");
-}
-
-static void native_irq_disable(void)
-{
- asm volatile("cli": : :"memory");
-}
-
-static void native_irq_enable(void)
-{
- asm volatile("sti": : :"memory");
-}
-
-static void native_safe_halt(void)
-{
- asm volatile("sti; hlt": : :"memory");
-}
-static void native_halt(void)
-{
- asm volatile("hlt": : :"memory");
+ return ret;
}
-static void native_wbinvd(void)
+unsigned paravirt_patch_nop(void)
{
- asm volatile("wbinvd": : :"memory");
+ return 0;
}
-static unsigned long long native_read_msr(unsigned int msr, int *err)
+unsigned paravirt_patch_ignore(unsigned len)
{
- unsigned long long val;
-
- asm volatile("2: rdmsr ; xorl %0,%0\n"
- "1:\n\t"
- ".section .fixup,\"ax\"\n\t"
- "3: movl %3,%0 ; jmp 1b\n\t"
- ".previous\n\t"
- ".section __ex_table,\"a\"\n"
- " .align 4\n\t"
- " .long 2b,3b\n\t"
- ".previous"
- : "=r" (*err), "=A" (val)
- : "c" (msr), "i" (-EFAULT));
-
- return val;
+ return len;
}
-static int native_write_msr(unsigned int msr, unsigned long long val)
+unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
+ void *site, u16 site_clobbers,
+ unsigned len)
{
- int err;
- asm volatile("2: wrmsr ; xorl %0,%0\n"
- "1:\n\t"
- ".section .fixup,\"ax\"\n\t"
- "3: movl %4,%0 ; jmp 1b\n\t"
- ".previous\n\t"
- ".section __ex_table,\"a\"\n"
- " .align 4\n\t"
- " .long 2b,3b\n\t"
- ".previous"
- : "=a" (err)
- : "c" (msr), "0" ((u32)val), "d" ((u32)(val>>32)),
- "i" (-EFAULT));
- return err;
-}
+ unsigned char *call = site;
+ unsigned long delta = (unsigned long)target - (unsigned long)(call+5);
-static unsigned long long native_read_tsc(void)
-{
- unsigned long long val;
- asm volatile("rdtsc" : "=A" (val));
- return val;
-}
+ if (tgt_clobbers & ~site_clobbers)
+ return len; /* target would clobber too much for this site */
+ if (len < 5)
+ return len; /* call too long for patch site */
-static unsigned long long native_read_pmc(void)
-{
- unsigned long long val;
- asm volatile("rdpmc" : "=A" (val));
- return val;
-}
+ *call++ = 0xe8; /* call */
+ *(unsigned long *)call = delta;
-static void native_load_tr_desc(void)
-{
- asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
+ return 5;
}
-static void native_load_gdt(const struct Xgt_desc_struct *dtr)
+unsigned paravirt_patch_jmp(void *target, void *site, unsigned len)
{
- asm volatile("lgdt %0"::"m" (*dtr));
-}
+ unsigned char *jmp = site;
+ unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5);
-static void native_load_idt(const struct Xgt_desc_struct *dtr)
-{
- asm volatile("lidt %0"::"m" (*dtr));
-}
+ if (len < 5)
+ return len; /* call too long for patch site */
-static void native_store_gdt(struct Xgt_desc_struct *dtr)
-{
- asm ("sgdt %0":"=m" (*dtr));
-}
+ *jmp++ = 0xe9; /* jmp */
+ *(unsigned long *)jmp = delta;
-static void native_store_idt(struct Xgt_desc_struct *dtr)
-{
- asm ("sidt %0":"=m" (*dtr));
+ return 5;
}
-static unsigned long native_store_tr(void)
+unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len)
{
- unsigned long tr;
- asm ("str %0":"=r" (tr));
- return tr;
-}
+ void *opfunc = *((void **)&paravirt_ops + type);
+ unsigned ret;
-static void native_load_tls(struct thread_struct *t, unsigned int cpu)
-{
-#define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]
- C(0); C(1); C(2);
-#undef C
-}
+ if (opfunc == NULL)
+ /* If there's no function, patch it with a ud2a (BUG) */
+ ret = paravirt_patch_insns(site, len, start_ud2a, end_ud2a);
+ else if (opfunc == paravirt_nop)
+ /* If the operation is a nop, then nop the callsite */
+ ret = paravirt_patch_nop();
+ else if (type == PARAVIRT_PATCH(iret) ||
+ type == PARAVIRT_PATCH(irq_enable_sysexit))
+ /* If operation requires a jmp, then jmp */
+ ret = paravirt_patch_jmp(opfunc, site, len);
+ else
+ /* Otherwise call the function; assume target could
+ clobber any caller-save reg */
+ ret = paravirt_patch_call(opfunc, CLBR_ANY,
+ site, clobbers, len);
-static inline void native_write_dt_entry(void *dt, int entry, u32 entry_low, u32 entry_high)
-{
- u32 *lp = (u32 *)((char *)dt + entry*8);
- lp[0] = entry_low;
- lp[1] = entry_high;
+ return ret;
}
-static void native_write_ldt_entry(void *dt, int entrynum, u32 low, u32 high)
+unsigned paravirt_patch_insns(void *site, unsigned len,
+ const char *start, const char *end)
{
- native_write_dt_entry(dt, entrynum, low, high);
-}
+ unsigned insn_len = end - start;
-static void native_write_gdt_entry(void *dt, int entrynum, u32 low, u32 high)
-{
- native_write_dt_entry(dt, entrynum, low, high);
-}
-
-static void native_write_idt_entry(void *dt, int entrynum, u32 low, u32 high)
-{
- native_write_dt_entry(dt, entrynum, low, high);
-}
+ if (insn_len > len || start == NULL)
+ insn_len = len;
+ else
+ memcpy(site, start, insn_len);
-static void native_load_esp0(struct tss_struct *tss,
- struct thread_struct *thread)
-{
- tss->esp0 = thread->esp0;
-
- /* This can only happen when SEP is enabled, no need to test "SEP"arately */
- if (unlikely(tss->ss1 != thread->sysenter_cs)) {
- tss->ss1 = thread->sysenter_cs;
- wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
- }
+ return insn_len;
}
-static void native_io_delay(void)
+void init_IRQ(void)
{
- asm volatile("outb %al,$0x80");
+ paravirt_ops.init_IRQ();
}
static void native_flush_tlb(void)
@@ -395,83 +213,11 @@ static void native_flush_tlb_global(void)
__native_flush_tlb_global();
}
-static void native_flush_tlb_single(u32 addr)
+static void native_flush_tlb_single(unsigned long addr)
{
__native_flush_tlb_single(addr);
}
-#ifndef CONFIG_X86_PAE
-static void native_set_pte(pte_t *ptep, pte_t pteval)
-{
- *ptep = pteval;
-}
-
-static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval)
-{
- *ptep = pteval;
-}
-
-static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
- *pmdp = pmdval;
-}
-
-#else /* CONFIG_X86_PAE */
-
-static void native_set_pte(pte_t *ptep, pte_t pte)
-{
- ptep->pte_high = pte.pte_high;
- smp_wmb();
- ptep->pte_low = pte.pte_low;
-}
-
-static void native_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte)
-{
- ptep->pte_high = pte.pte_high;
- smp_wmb();
- ptep->pte_low = pte.pte_low;
-}
-
-static void native_set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
-{
- ptep->pte_low = 0;
- smp_wmb();
- ptep->pte_high = pte.pte_high;
- smp_wmb();
- ptep->pte_low = pte.pte_low;
-}
-
-static void native_set_pte_atomic(pte_t *ptep, pte_t pteval)
-{
- set_64bit((unsigned long long *)ptep,pte_val(pteval));
-}
-
-static void native_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
- set_64bit((unsigned long long *)pmdp,pmd_val(pmdval));
-}
-
-static void native_set_pud(pud_t *pudp, pud_t pudval)
-{
- *pudp = pudval;
-}
-
-static void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
- ptep->pte_low = 0;
- smp_wmb();
- ptep->pte_high = 0;
-}
-
-static void native_pmd_clear(pmd_t *pmd)
-{
- u32 *tmp = (u32 *)pmd;
- *tmp = 0;
- smp_wmb();
- *(tmp + 1) = 0;
-}
-#endif /* CONFIG_X86_PAE */
-
/* These are in entry.S */
extern void native_iret(void);
extern void native_irq_enable_sysexit(void);
@@ -487,10 +233,11 @@ struct paravirt_ops paravirt_ops = {
.name = "bare hardware",
.paravirt_enabled = 0,
.kernel_rpl = 0,
+ .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */
.patch = native_patch,
.banner = default_banner,
- .arch_setup = native_nop,
+ .arch_setup = paravirt_nop,
.memory_setup = machine_specific_memory_setup,
.get_wallclock = native_get_wallclock,
.set_wallclock = native_set_wallclock,
@@ -517,8 +264,8 @@ struct paravirt_ops paravirt_ops = {
.safe_halt = native_safe_halt,
.halt = native_halt,
.wbinvd = native_wbinvd,
- .read_msr = native_read_msr,
- .write_msr = native_write_msr,
+ .read_msr = native_read_msr_safe,
+ .write_msr = native_write_msr_safe,
.read_tsc = native_read_tsc,
.read_pmc = native_read_pmc,
.get_scheduled_cycles = native_read_tsc,
@@ -531,9 +278,9 @@ struct paravirt_ops paravirt_ops = {
.store_idt = native_store_idt,
.store_tr = native_store_tr,
.load_tls = native_load_tls,
- .write_ldt_entry = native_write_ldt_entry,
- .write_gdt_entry = native_write_gdt_entry,
- .write_idt_entry = native_write_idt_entry,
+ .write_ldt_entry = write_dt_entry,
+ .write_gdt_entry = write_dt_entry,
+ .write_idt_entry = write_dt_entry,
.load_esp0 = native_load_esp0,
.set_iopl_mask = native_set_iopl_mask,
@@ -545,44 +292,57 @@ struct paravirt_ops paravirt_ops = {
.apic_read = native_apic_read,
.setup_boot_clock = setup_boot_APIC_clock,
.setup_secondary_clock = setup_secondary_APIC_clock,
+ .startup_ipi_hook = paravirt_nop,
#endif
- .set_lazy_mode = (void *)native_nop,
+ .set_lazy_mode = paravirt_nop,
+
+ .pagetable_setup_start = native_pagetable_setup_start,
+ .pagetable_setup_done = native_pagetable_setup_done,
.flush_tlb_user = native_flush_tlb,
.flush_tlb_kernel = native_flush_tlb_global,
.flush_tlb_single = native_flush_tlb_single,
+ .flush_tlb_others = native_flush_tlb_others,
- .map_pt_hook = (void *)native_nop,
-
- .alloc_pt = (void *)native_nop,
- .alloc_pd = (void *)native_nop,
- .alloc_pd_clone = (void *)native_nop,
- .release_pt = (void *)native_nop,
- .release_pd = (void *)native_nop,
+ .alloc_pt = paravirt_nop,
+ .alloc_pd = paravirt_nop,
+ .alloc_pd_clone = paravirt_nop,
+ .release_pt = paravirt_nop,
+ .release_pd = paravirt_nop,
.set_pte = native_set_pte,
.set_pte_at = native_set_pte_at,
.set_pmd = native_set_pmd,
- .pte_update = (void *)native_nop,
- .pte_update_defer = (void *)native_nop,
+ .pte_update = paravirt_nop,
+ .pte_update_defer = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+ .kmap_atomic_pte = kmap_atomic,
+#endif
+
#ifdef CONFIG_X86_PAE
.set_pte_atomic = native_set_pte_atomic,
.set_pte_present = native_set_pte_present,
.set_pud = native_set_pud,
.pte_clear = native_pte_clear,
.pmd_clear = native_pmd_clear,
+
+ .pmd_val = native_pmd_val,
+ .make_pmd = native_make_pmd,
#endif
+ .pte_val = native_pte_val,
+ .pgd_val = native_pgd_val,
+
+ .make_pte = native_make_pte,
+ .make_pgd = native_make_pgd,
+
.irq_enable_sysexit = native_irq_enable_sysexit,
.iret = native_iret,
- .startup_ipi_hook = (void *)native_nop,
+ .dup_mmap = paravirt_nop,
+ .exit_mmap = paravirt_nop,
+ .activate_mm = paravirt_nop,
};
-/*
- * NOTE: CONFIG_PARAVIRT is experimental and the paravirt_ops
- * semantics are subject to change. Hence we only do this
- * internal-only export of this, until it gets sorted out and
- * all lowlevel CPU ops used by modules are separately exported.
- */
-EXPORT_SYMBOL_GPL(paravirt_ops);
+EXPORT_SYMBOL(paravirt_ops);
diff --git a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c
index 3ebcea03362..30b754f7cbe 100644
--- a/arch/i386/kernel/pci-dma.c
+++ b/arch/i386/kernel/pci-dma.c
@@ -77,7 +77,7 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
{
void __iomem *mem_base = NULL;
int pages = size >> PAGE_SHIFT;
- int bitmap_size = (pages + 31)/32;
+ int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
goto out;
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 393a67d5d94..d76d9bc33b3 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -21,7 +21,6 @@
#include <linux/mm.h>
#include <linux/elfcore.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -39,6 +38,7 @@
#include <linux/random.h>
#include <linux/personality.h>
#include <linux/tick.h>
+#include <linux/percpu.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -57,7 +57,6 @@
#include <asm/tlbflush.h>
#include <asm/cpu.h>
-#include <asm/pda.h>
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
@@ -66,6 +65,12 @@ static int hlt_counter;
unsigned long boot_option_idle_override = 0;
EXPORT_SYMBOL(boot_option_idle_override);
+DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task;
+EXPORT_PER_CPU_SYMBOL(current_task);
+
+DEFINE_PER_CPU(int, cpu_number);
+EXPORT_PER_CPU_SYMBOL(cpu_number);
+
/*
* Return saved PC of a blocked thread.
*/
@@ -272,25 +277,24 @@ void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
}
}
-static int __init idle_setup (char *str)
+static int __init idle_setup(char *str)
{
- if (!strncmp(str, "poll", 4)) {
+ if (!strcmp(str, "poll")) {
printk("using polling idle threads.\n");
pm_idle = poll_idle;
#ifdef CONFIG_X86_SMP
if (smp_num_siblings > 1)
printk("WARNING: polling idle and HT enabled, performance may degrade.\n");
#endif
- } else if (!strncmp(str, "halt", 4)) {
- printk("using halt in idle threads.\n");
- pm_idle = default_idle;
- }
+ } else if (!strcmp(str, "mwait"))
+ force_mwait = 1;
+ else
+ return -1;
boot_option_idle_override = 1;
- return 1;
+ return 0;
}
-
-__setup("idle=", idle_setup);
+early_param("idle", idle_setup);
void show_regs(struct pt_regs * regs)
{
@@ -343,7 +347,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
regs.xds = __USER_DS;
regs.xes = __USER_DS;
- regs.xfs = __KERNEL_PDA;
+ regs.xfs = __KERNEL_PERCPU;
regs.orig_eax = -1;
regs.eip = (unsigned long) kernel_thread_helper;
regs.xcs = __KERNEL_CS | get_kernel_rpl();
@@ -376,7 +380,7 @@ void exit_thread(void)
t->io_bitmap_max = 0;
tss->io_bitmap_owner = NULL;
tss->io_bitmap_max = 0;
- tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
+ tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
put_cpu();
}
}
@@ -555,7 +559,7 @@ static noinline void __switch_to_xtra(struct task_struct *next_p,
* Disable the bitmap via an invalid offset. We still cache
* the previous bitmap owner and the IO bitmap contents:
*/
- tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
+ tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
return;
}
@@ -565,7 +569,7 @@ static noinline void __switch_to_xtra(struct task_struct *next_p,
* matches the next task, we dont have to do anything but
* to set a valid offset in the TSS:
*/
- tss->io_bitmap_base = IO_BITMAP_OFFSET;
+ tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
return;
}
/*
@@ -577,7 +581,7 @@ static noinline void __switch_to_xtra(struct task_struct *next_p,
* redundant copies when the currently switched task does not
* perform any I/O during its timeslice.
*/
- tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
+ tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
}
/*
@@ -712,7 +716,7 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
if (prev->gs | next->gs)
loadsegment(gs, next->gs);
- write_pda(pcurrent, next_p);
+ x86_write_percpu(current_task, next_p);
return prev_p;
}
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 4a8f8a25972..0c0ceec5de0 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -9,7 +9,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/i386/kernel/quirks.c b/arch/i386/kernel/quirks.c
index 34874c398b4..9f6ab1789bb 100644
--- a/arch/i386/kernel/quirks.c
+++ b/arch/i386/kernel/quirks.c
@@ -3,12 +3,10 @@
*/
#include <linux/pci.h>
#include <linux/irq.h>
-#include <asm/pci-direct.h>
-#include <asm/genapic.h>
-#include <asm/cpu.h>
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
-static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev)
+
+static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
{
u8 config, rev;
u32 word;
@@ -16,12 +14,14 @@ static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev)
/* BIOS may enable hardware IRQ balancing for
* E7520/E7320/E7525(revision ID 0x9 and below)
* based platforms.
- * For those platforms, make sure that the genapic is set to 'flat'
+ * Disable SW irqbalance/affinity on those platforms.
*/
pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
if (rev > 0x9)
return;
+ printk(KERN_INFO "Intel E7520/7320/7525 detected.");
+
/* enable access to config space*/
pci_read_config_byte(dev, 0xf4, &config);
pci_write_config_byte(dev, 0xf4, config|0x2);
@@ -30,44 +30,6 @@ static void __devinit verify_quirk_intel_irqbalance(struct pci_dev *dev)
raw_pci_ops->read(0, 0, 0x40, 0x4c, 2, &word);
if (!(word & (1 << 13))) {
-#ifdef CONFIG_X86_64
- if (genapic != &apic_flat)
- panic("APIC mode must be flat on this system\n");
-#elif defined(CONFIG_X86_GENERICARCH)
- if (genapic != &apic_default)
- panic("APIC mode must be default(flat) on this system. Use apic=default\n");
-#endif
- }
-
- /* put back the original value for config space*/
- if (!(config & 0x2))
- pci_write_config_byte(dev, 0xf4, config);
-}
-
-void __init quirk_intel_irqbalance(void)
-{
- u8 config, rev;
- u32 word;
-
- /* BIOS may enable hardware IRQ balancing for
- * E7520/E7320/E7525(revision ID 0x9 and below)
- * based platforms.
- * Disable SW irqbalance/affinity on those platforms.
- */
- rev = read_pci_config_byte(0, 0, 0, PCI_CLASS_REVISION);
- if (rev > 0x9)
- return;
-
- printk(KERN_INFO "Intel E7520/7320/7525 detected.");
-
- /* enable access to config space */
- config = read_pci_config_byte(0, 0, 0, 0xf4);
- write_pci_config_byte(0, 0, 0, 0xf4, config|0x2);
-
- /* read xTPR register */
- word = read_pci_config_16(0, 0, 0x40, 0x4c);
-
- if (!(word & (1 << 13))) {
printk(KERN_INFO "Disabling irq balancing and affinity\n");
#ifdef CONFIG_IRQBALANCE
irqbalance_disable("");
@@ -76,24 +38,13 @@ void __init quirk_intel_irqbalance(void)
#ifdef CONFIG_PROC_FS
no_irq_affinity = 1;
#endif
-#ifdef CONFIG_HOTPLUG_CPU
- printk(KERN_INFO "Disabling cpu hotplug control\n");
- enable_cpu_hotplug = 0;
-#endif
-#ifdef CONFIG_X86_64
- /* force the genapic selection to flat mode so that
- * interrupts can be redirected to more than one CPU.
- */
- genapic_force = &apic_flat;
-#endif
}
- /* put back the original value for config space */
+ /* put back the original value for config space*/
if (!(config & 0x2))
- write_pci_config_byte(0, 0, 0, 0xf4, config);
+ pci_write_config_byte(dev, 0xf4, config);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, verify_quirk_intel_irqbalance);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, verify_quirk_intel_irqbalance);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, verify_quirk_intel_irqbalance);
-
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance);
#endif
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index 3514b4153f7..50dfc65319c 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -17,7 +17,8 @@
#include <asm/apic.h>
#include <asm/desc.h>
#include "mach_reboot.h"
-#include <linux/reboot_fixups.h>
+#include <asm/reboot_fixups.h>
+#include <asm/reboot.h>
/*
* Power off function, if any
@@ -197,8 +198,6 @@ static unsigned char jump_to_bios [] =
*/
void machine_real_restart(unsigned char *code, int length)
{
- unsigned long flags;
-
local_irq_disable();
/* Write zero to CMOS register number 0x0f, which the BIOS POST
@@ -211,9 +210,9 @@ void machine_real_restart(unsigned char *code, int length)
safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.)
*/
- spin_lock_irqsave(&rtc_lock, flags);
+ spin_lock(&rtc_lock);
CMOS_WRITE(0x00, 0x8f);
- spin_unlock_irqrestore(&rtc_lock, flags);
+ spin_unlock(&rtc_lock);
/* Remap the kernel at virtual address zero, as well as offset zero
from the kernel segment. This assumes the kernel segment starts at
@@ -280,7 +279,7 @@ void machine_real_restart(unsigned char *code, int length)
EXPORT_SYMBOL(machine_real_restart);
#endif
-void machine_shutdown(void)
+static void native_machine_shutdown(void)
{
#ifdef CONFIG_SMP
int reboot_cpu_id;
@@ -316,7 +315,11 @@ void machine_shutdown(void)
#endif
}
-void machine_emergency_restart(void)
+void __attribute__((weak)) mach_reboot_fixups(void)
+{
+}
+
+static void native_machine_emergency_restart(void)
{
if (!reboot_thru_bios) {
if (efi_enabled) {
@@ -340,17 +343,17 @@ void machine_emergency_restart(void)
machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
}
-void machine_restart(char * __unused)
+static void native_machine_restart(char * __unused)
{
machine_shutdown();
machine_emergency_restart();
}
-void machine_halt(void)
+static void native_machine_halt(void)
{
}
-void machine_power_off(void)
+static void native_machine_power_off(void)
{
if (pm_power_off) {
machine_shutdown();
@@ -359,3 +362,35 @@ void machine_power_off(void)
}
+struct machine_ops machine_ops = {
+ .power_off = native_machine_power_off,
+ .shutdown = native_machine_shutdown,
+ .emergency_restart = native_machine_emergency_restart,
+ .restart = native_machine_restart,
+ .halt = native_machine_halt,
+};
+
+void machine_power_off(void)
+{
+ machine_ops.power_off();
+}
+
+void machine_shutdown(void)
+{
+ machine_ops.shutdown();
+}
+
+void machine_emergency_restart(void)
+{
+ machine_ops.emergency_restart();
+}
+
+void machine_restart(char *cmd)
+{
+ machine_ops.restart(cmd);
+}
+
+void machine_halt(void)
+{
+ machine_ops.halt();
+}
diff --git a/arch/i386/kernel/reboot_fixups.c b/arch/i386/kernel/reboot_fixups.c
index 99aab41a05b..2d78d918340 100644
--- a/arch/i386/kernel/reboot_fixups.c
+++ b/arch/i386/kernel/reboot_fixups.c
@@ -10,7 +10,7 @@
#include <asm/delay.h>
#include <linux/pci.h>
-#include <linux/reboot_fixups.h>
+#include <asm/reboot_fixups.h>
static void cs5530a_warm_reset(struct pci_dev *dev)
{
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index 4f99e870c98..d574e38f0f7 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -10,7 +10,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 0e8977871b1..93f202a855f 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -13,7 +13,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/cache.h>
@@ -165,20 +164,20 @@ void fastcall send_IPI_self(int vector)
}
/*
- * This is only used on smaller machines.
+ * This is used to send an IPI with no shorthand notation (the destination is
+ * specified in bits 56 to 63 of the ICR).
*/
-void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
+static inline void __send_IPI_dest_field(unsigned long mask, int vector)
{
- unsigned long mask = cpus_addr(cpumask)[0];
unsigned long cfg;
- unsigned long flags;
- local_irq_save(flags);
- WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
/*
* Wait for idle.
*/
- apic_wait_icr_idle();
+ if (unlikely(vector == NMI_VECTOR))
+ safe_apic_wait_icr_idle();
+ else
+ apic_wait_icr_idle();
/*
* prepare target chip field
@@ -195,13 +194,25 @@ void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
* Send the IPI. The write to APIC_ICR fires this off.
*/
apic_write_around(APIC_ICR, cfg);
+}
+
+/*
+ * This is only used on smaller machines.
+ */
+void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
+{
+ unsigned long mask = cpus_addr(cpumask)[0];
+ unsigned long flags;
+ local_irq_save(flags);
+ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
+ __send_IPI_dest_field(mask, vector);
local_irq_restore(flags);
}
void send_IPI_mask_sequence(cpumask_t mask, int vector)
{
- unsigned long cfg, flags;
+ unsigned long flags;
unsigned int query_cpu;
/*
@@ -211,30 +222,10 @@ void send_IPI_mask_sequence(cpumask_t mask, int vector)
*/
local_irq_save(flags);
-
for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) {
if (cpu_isset(query_cpu, mask)) {
-
- /*
- * Wait for idle.
- */
- apic_wait_icr_idle();
-
- /*
- * prepare target chip field
- */
- cfg = __prepare_ICR2(cpu_to_logical_apicid(query_cpu));
- apic_write_around(APIC_ICR2, cfg);
-
- /*
- * program the ICR
- */
- cfg = __prepare_ICR(0, vector);
-
- /*
- * Send the IPI. The write to APIC_ICR fires this off.
- */
- apic_write_around(APIC_ICR, cfg);
+ __send_IPI_dest_field(cpu_to_logical_apicid(query_cpu),
+ vector);
}
}
local_irq_restore(flags);
@@ -256,7 +247,6 @@ static cpumask_t flush_cpumask;
static struct mm_struct * flush_mm;
static unsigned long flush_va;
static DEFINE_SPINLOCK(tlbstate_lock);
-#define FLUSH_ALL 0xffffffff
/*
* We cannot call mmdrop() because we are in interrupt context,
@@ -338,7 +328,7 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
- if (flush_va == FLUSH_ALL)
+ if (flush_va == TLB_FLUSH_ALL)
local_flush_tlb();
else
__flush_tlb_one(flush_va);
@@ -353,9 +343,11 @@ out:
put_cpu_no_resched();
}
-static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
- unsigned long va)
+void native_flush_tlb_others(const cpumask_t *cpumaskp, struct mm_struct *mm,
+ unsigned long va)
{
+ cpumask_t cpumask = *cpumaskp;
+
/*
* A couple of (to be removed) sanity checks:
*
@@ -366,10 +358,12 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
BUG_ON(cpu_isset(smp_processor_id(), cpumask));
BUG_ON(!mm);
+#ifdef CONFIG_HOTPLUG_CPU
/* If a CPU which we ran on has gone down, OK. */
cpus_and(cpumask, cpumask, cpu_online_map);
- if (cpus_empty(cpumask))
+ if (unlikely(cpus_empty(cpumask)))
return;
+#endif
/*
* i'm not happy about this global shared spinlock in the
@@ -380,17 +374,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
flush_mm = mm;
flush_va = va;
-#if NR_CPUS <= BITS_PER_LONG
- atomic_set_mask(cpumask, &flush_cpumask);
-#else
- {
- int k;
- unsigned long *flush_mask = (unsigned long *)&flush_cpumask;
- unsigned long *cpu_mask = (unsigned long *)&cpumask;
- for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k)
- atomic_set_mask(cpu_mask[k], &flush_mask[k]);
- }
-#endif
+ cpus_or(flush_cpumask, cpumask, flush_cpumask);
/*
* We have to send the IPI only to
* CPUs affected.
@@ -417,7 +401,7 @@ void flush_tlb_current_task(void)
local_flush_tlb();
if (!cpus_empty(cpu_mask))
- flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+ flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL);
preempt_enable();
}
@@ -436,7 +420,7 @@ void flush_tlb_mm (struct mm_struct * mm)
leave_mm(smp_processor_id());
}
if (!cpus_empty(cpu_mask))
- flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+ flush_tlb_others(cpu_mask, mm, TLB_FLUSH_ALL);
preempt_enable();
}
@@ -483,7 +467,7 @@ void flush_tlb_all(void)
* it goes straight through and wastes no time serializing
* anything. Worst case is that we lose a reschedule ...
*/
-void smp_send_reschedule(int cpu)
+void native_smp_send_reschedule(int cpu)
{
WARN_ON(cpu_is_offline(cpu));
send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
@@ -515,36 +499,78 @@ void unlock_ipi_call_lock(void)
static struct call_data_struct *call_data;
+static void __smp_call_function(void (*func) (void *info), void *info,
+ int nonatomic, int wait)
+{
+ struct call_data_struct data;
+ int cpus = num_online_cpus() - 1;
+
+ if (!cpus)
+ return;
+
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+ call_data = &data;
+ mb();
+
+ /* Send a message to all other CPUs and wait for them to respond */
+ send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+
+ /* Wait for response */
+ while (atomic_read(&data.started) != cpus)
+ cpu_relax();
+
+ if (wait)
+ while (atomic_read(&data.finished) != cpus)
+ cpu_relax();
+}
+
+
/**
- * smp_call_function(): Run a function on all other CPUs.
+ * smp_call_function_mask(): Run a function on a set of other CPUs.
+ * @mask: The set of cpus to run on. Must not include the current cpu.
* @func: The function to run. This must be fast and non-blocking.
* @info: An arbitrary pointer to pass to the function.
- * @nonatomic: currently unused.
* @wait: If true, wait (atomically) until function has completed on other CPUs.
*
- * Returns 0 on success, else a negative status code. Does not return until
- * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
*
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
*/
-int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
- int wait)
+int native_smp_call_function_mask(cpumask_t mask,
+ void (*func)(void *), void *info,
+ int wait)
{
struct call_data_struct data;
+ cpumask_t allbutself;
int cpus;
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
+
/* Holding any lock stops cpus from going down. */
spin_lock(&call_lock);
- cpus = num_online_cpus() - 1;
+
+ allbutself = cpu_online_map;
+ cpu_clear(smp_processor_id(), allbutself);
+
+ cpus_and(mask, mask, allbutself);
+ cpus = cpus_weight(mask);
+
if (!cpus) {
spin_unlock(&call_lock);
return 0;
}
- /* Can deadlock when called with interrupts disabled */
- WARN_ON(irqs_disabled());
-
data.func = func;
data.info = info;
atomic_set(&data.started, 0);
@@ -554,9 +580,12 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
call_data = &data;
mb();
-
- /* Send a message to all other CPUs and wait for them to respond */
- send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+
+ /* Send a message to other CPUs */
+ if (cpus_equal(mask, allbutself))
+ send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+ else
+ send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
/* Wait for response */
while (atomic_read(&data.started) != cpus)
@@ -569,15 +598,68 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
return 0;
}
+
+/**
+ * smp_call_function(): Run a function on all other CPUs.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: Unused.
+ * @wait: If true, wait (atomically) until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
+ int wait)
+{
+ return smp_call_function_mask(cpu_online_map, func, info, wait);
+}
EXPORT_SYMBOL(smp_call_function);
+/**
+ * smp_call_function_single - Run a function on another CPU
+ * @cpu: The target CPU. Cannot be the calling CPU.
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: Unused.
+ * @wait: If true, wait until function has completed on other CPUs.
+ *
+ * Returns 0 on success, else a negative status code.
+ *
+ * If @wait is true, then returns once @func has returned; otherwise
+ * it returns just before the target cpu calls @func.
+ */
+int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ int nonatomic, int wait)
+{
+ /* prevent preemption and reschedule on another processor */
+ int ret;
+ int me = get_cpu();
+ if (cpu == me) {
+ WARN_ON(1);
+ put_cpu();
+ return -EBUSY;
+ }
+
+ ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait);
+
+ put_cpu();
+ return ret;
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
static void stop_this_cpu (void * dummy)
{
+ local_irq_disable();
/*
* Remove this CPU:
*/
cpu_clear(smp_processor_id(), cpu_online_map);
- local_irq_disable();
disable_local_APIC();
if (cpu_data[smp_processor_id()].hlt_works_ok)
for(;;) halt();
@@ -588,13 +670,18 @@ static void stop_this_cpu (void * dummy)
* this function calls the 'stop' function on all other CPUs in the system.
*/
-void smp_send_stop(void)
+void native_smp_send_stop(void)
{
- smp_call_function(stop_this_cpu, NULL, 1, 0);
+ /* Don't deadlock on the call lock in panic */
+ int nolock = !spin_trylock(&call_lock);
+ unsigned long flags;
- local_irq_disable();
+ local_irq_save(flags);
+ __smp_call_function(stop_this_cpu, NULL, 0, 0);
+ if (!nolock)
+ spin_unlock(&call_lock);
disable_local_APIC();
- local_irq_enable();
+ local_irq_restore(flags);
}
/*
@@ -633,77 +720,6 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs)
}
}
-/*
- * this function sends a 'generic call function' IPI to one other CPU
- * in the system.
- *
- * cpu is a standard Linux logical CPU number.
- */
-static void
-__smp_call_function_single(int cpu, void (*func) (void *info), void *info,
- int nonatomic, int wait)
-{
- struct call_data_struct data;
- int cpus = 1;
-
- data.func = func;
- data.info = info;
- atomic_set(&data.started, 0);
- data.wait = wait;
- if (wait)
- atomic_set(&data.finished, 0);
-
- call_data = &data;
- wmb();
- /* Send a message to all other CPUs and wait for them to respond */
- send_IPI_mask(cpumask_of_cpu(cpu), CALL_FUNCTION_VECTOR);
-
- /* Wait for response */
- while (atomic_read(&data.started) != cpus)
- cpu_relax();
-
- if (!wait)
- return;
-
- while (atomic_read(&data.finished) != cpus)
- cpu_relax();
-}
-
-/*
- * smp_call_function_single - Run a function on another CPU
- * @func: The function to run. This must be fast and non-blocking.
- * @info: An arbitrary pointer to pass to the function.
- * @nonatomic: Currently unused.
- * @wait: If true, wait until function has completed on other CPUs.
- *
- * Retrurns 0 on success, else a negative status code.
- *
- * Does not return until the remote CPU is nearly ready to execute <func>
- * or is or has executed.
- */
-
-int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
- int nonatomic, int wait)
-{
- /* prevent preemption and reschedule on another processor */
- int me = get_cpu();
- if (cpu == me) {
- WARN_ON(1);
- put_cpu();
- return -EBUSY;
- }
-
- /* Can deadlock when called with interrupts disabled */
- WARN_ON(irqs_disabled());
-
- spin_lock_bh(&call_lock);
- __smp_call_function_single(cpu, func, info, nonatomic, wait);
- spin_unlock_bh(&call_lock);
- put_cpu();
- return 0;
-}
-EXPORT_SYMBOL(smp_call_function_single);
-
static int convert_apicid_to_cpu(int apic_id)
{
int i;
@@ -730,3 +746,14 @@ int safe_smp_processor_id(void)
return cpuid >= 0 ? cpuid : 0;
}
+
+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,
+ .smp_call_function_mask = native_smp_call_function_mask,
+};
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 4ff55e67557..b92cc4e8b3b 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -40,7 +40,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
#include <linux/bootmem.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
@@ -53,13 +52,12 @@
#include <asm/desc.h>
#include <asm/arch_hooks.h>
#include <asm/nmi.h>
-#include <asm/pda.h>
-#include <asm/genapic.h>
#include <mach_apic.h>
#include <mach_wakecpu.h>
#include <smpboot_hooks.h>
#include <asm/vmi.h>
+#include <asm/mtrr.h>
/* Set if we find a B stepping CPU */
static int __devinitdata smp_b_stepping;
@@ -100,6 +98,9 @@ EXPORT_SYMBOL(x86_cpu_to_apicid);
u8 apicid_2_node[MAX_APICID];
+DEFINE_PER_CPU(unsigned long, this_cpu_off);
+EXPORT_PER_CPU_SYMBOL(this_cpu_off);
+
/*
* Trampoline 80x86 program as an array.
*/
@@ -156,7 +157,7 @@ static void __cpuinit smp_store_cpu_info(int id)
*c = boot_cpu_data;
if (id!=0)
- identify_cpu(c);
+ identify_secondary_cpu(c);
/*
* Mask B, Pentium, but not Pentium MMX
*/
@@ -379,14 +380,14 @@ set_cpu_sibling_map(int cpu)
static void __cpuinit start_secondary(void *unused)
{
/*
- * Don't put *anything* before secondary_cpu_init(), SMP
- * booting is too fragile that we want to limit the
- * things done here to the most necessary things.
+ * Don't put *anything* before cpu_init(), SMP booting is too
+ * fragile that we want to limit the things done here to the
+ * most necessary things.
*/
#ifdef CONFIG_VMI
vmi_bringup();
#endif
- secondary_cpu_init();
+ cpu_init();
preempt_disable();
smp_callin();
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
@@ -441,12 +442,6 @@ static void __cpuinit start_secondary(void *unused)
void __devinit initialize_secondary(void)
{
/*
- * switch to the per CPU GDT we already set up
- * in do_boot_cpu()
- */
- cpu_set_gdt(current_thread_info()->cpu);
-
- /*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
*/
@@ -463,7 +458,6 @@ extern struct {
void * esp;
unsigned short ss;
} stack_start;
-extern struct i386_pda *start_pda;
#ifdef CONFIG_NUMA
@@ -521,12 +515,12 @@ static void unmap_cpu_to_logical_apicid(int cpu)
unmap_cpu_to_node(cpu);
}
-#if APIC_DEBUG
static inline void __inquire_remote_apic(int apicid)
{
int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
char *names[] = { "ID", "VERSION", "SPIV" };
- int timeout, status;
+ int timeout;
+ unsigned long status;
printk("Inquiring remote APIC #%d...\n", apicid);
@@ -536,7 +530,9 @@ static inline void __inquire_remote_apic(int apicid)
/*
* Wait for idle.
*/
- apic_wait_icr_idle();
+ status = safe_apic_wait_icr_idle();
+ if (status)
+ printk("a previous APIC delivery may have failed\n");
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
@@ -550,14 +546,13 @@ static inline void __inquire_remote_apic(int apicid)
switch (status) {
case APIC_ICR_RR_VALID:
status = apic_read(APIC_RRR);
- printk("%08x\n", status);
+ printk("%lx\n", status);
break;
default:
printk("failed\n");
}
}
}
-#endif
#ifdef WAKE_SECONDARY_VIA_NMI
/*
@@ -568,8 +563,8 @@ static inline void __inquire_remote_apic(int apicid)
static int __devinit
wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
{
- unsigned long send_status = 0, accept_status = 0;
- int timeout, maxlvt;
+ unsigned long send_status, accept_status = 0;
+ int maxlvt;
/* Target chip */
apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
@@ -579,12 +574,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
/*
* Give the other CPU some time to accept the IPI.
@@ -614,8 +604,8 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
static int __devinit
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
{
- unsigned long send_status = 0, accept_status = 0;
- int maxlvt, timeout, num_starts, j;
+ unsigned long send_status, accept_status = 0;
+ int maxlvt, num_starts, j;
/*
* Be paranoid about clearing APIC errors.
@@ -640,12 +630,7 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
| APIC_DM_INIT);
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
mdelay(10);
@@ -658,12 +643,7 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
atomic_set(&init_deasserted, 1);
@@ -719,12 +699,7 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
Dprintk("Startup point 1.\n");
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
/*
* Give the other CPU some time to accept the IPI.
@@ -788,6 +763,25 @@ static inline struct task_struct * alloc_idle_task(int cpu)
#define alloc_idle_task(cpu) fork_idle(cpu)
#endif
+/* Initialize the CPU's GDT. This is either the boot CPU doing itself
+ (still using the master per-cpu area), or a CPU doing it for a
+ secondary which will soon come up. */
+static __cpuinit void init_gdt(int cpu)
+{
+ struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+
+ pack_descriptor((u32 *)&gdt[GDT_ENTRY_PERCPU].a,
+ (u32 *)&gdt[GDT_ENTRY_PERCPU].b,
+ __per_cpu_offset[cpu], 0xFFFFF,
+ 0x80 | DESCTYPE_S | 0x2, 0x8);
+
+ per_cpu(this_cpu_off, cpu) = __per_cpu_offset[cpu];
+ per_cpu(cpu_number, cpu) = cpu;
+}
+
+/* Defined in head.S */
+extern struct Xgt_desc_struct early_gdt_descr;
+
static int __cpuinit do_boot_cpu(int apicid, int cpu)
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
@@ -802,6 +796,12 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
unsigned short nmi_high = 0, nmi_low = 0;
/*
+ * Save current MTRR state in case it was changed since early boot
+ * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
+ */
+ mtrr_save_state();
+
+ /*
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
@@ -809,13 +809,9 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
- /* Pre-allocate and initialize the CPU's GDT and PDA so it
- doesn't have to do any memory allocation during the
- delicate CPU-bringup phase. */
- if (!init_gdt(cpu, idle)) {
- printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
- return -1; /* ? */
- }
+ init_gdt(cpu);
+ per_cpu(current_task, cpu) = idle;
+ early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu);
idle->thread.eip = (unsigned long) start_secondary;
/* start_eip had better be page-aligned! */
@@ -941,7 +937,6 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
DECLARE_COMPLETION_ONSTACK(done);
struct warm_boot_cpu_info info;
int apicid, ret;
- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
apicid = x86_cpu_to_apicid[cpu];
if (apicid == BAD_APICID) {
@@ -949,18 +944,6 @@ static int __cpuinit __smp_prepare_cpu(int cpu)
goto exit;
}
- /*
- * the CPU isn't initialized at boot time, allocate gdt table here.
- * cpu_init will initialize it
- */
- if (!cpu_gdt_descr->address) {
- cpu_gdt_descr->address = get_zeroed_page(GFP_KERNEL);
- if (!cpu_gdt_descr->address)
- printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu);
- ret = -ENOMEM;
- goto exit;
- }
-
info.complete = &done;
info.apicid = apicid;
info.cpu = cpu;
@@ -1173,7 +1156,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
/* These are wrappers to interface to the new boot process. Someone
who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
-void __init smp_prepare_cpus(unsigned int max_cpus)
+void __init native_smp_prepare_cpus(unsigned int max_cpus)
{
smp_commenced_mask = cpumask_of_cpu(0);
cpu_callin_map = cpumask_of_cpu(0);
@@ -1181,13 +1164,18 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
smp_boot_cpus(max_cpus);
}
-void __devinit smp_prepare_boot_cpu(void)
+void __init native_smp_prepare_boot_cpu(void)
{
- cpu_set(smp_processor_id(), cpu_online_map);
- cpu_set(smp_processor_id(), cpu_callout_map);
- cpu_set(smp_processor_id(), cpu_present_map);
- cpu_set(smp_processor_id(), cpu_possible_map);
- per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+ unsigned int cpu = smp_processor_id();
+
+ init_gdt(cpu);
+ switch_to_new_gdt();
+
+ cpu_set(cpu, cpu_online_map);
+ cpu_set(cpu, cpu_callout_map);
+ cpu_set(cpu, cpu_present_map);
+ cpu_set(cpu, cpu_possible_map);
+ __get_cpu_var(cpu_state) = CPU_ONLINE;
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -1277,7 +1265,7 @@ void __cpu_die(unsigned int cpu)
}
#endif /* CONFIG_HOTPLUG_CPU */
-int __cpuinit __cpu_up(unsigned int cpu)
+int __cpuinit native_cpu_up(unsigned int cpu)
{
unsigned long flags;
#ifdef CONFIG_HOTPLUG_CPU
@@ -1319,15 +1307,10 @@ int __cpuinit __cpu_up(unsigned int cpu)
touch_nmi_watchdog();
}
-#ifdef CONFIG_X86_GENERICARCH
- if (num_online_cpus() > 8 && genapic == &apic_default)
- panic("Default flat APIC routing can't be used with > 8 cpus\n");
-#endif
-
return 0;
}
-void __init smp_cpus_done(unsigned int max_cpus)
+void __init native_smp_cpus_done(unsigned int max_cpus)
{
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
index 4048397f174..e5dcb937901 100644
--- a/arch/i386/kernel/sys_i386.c
+++ b/arch/i386/kernel/sys_i386.c
@@ -10,7 +10,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 2697e9210e9..0772678ceec 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -319,3 +319,4 @@ ENTRY(sys_call_table)
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
+ .long sys_utimensat /* 320 */
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index 13ca54a85a1..ff4ee6f3326 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -22,16 +22,26 @@
#include <asm/msr.h>
#include <asm/pgtable.h>
#include <asm/unistd.h>
+#include <asm/elf.h>
+#include <asm/tlbflush.h>
+
+enum {
+ VDSO_DISABLED = 0,
+ VDSO_ENABLED = 1,
+ VDSO_COMPAT = 2,
+};
+
+#ifdef CONFIG_COMPAT_VDSO
+#define VDSO_DEFAULT VDSO_COMPAT
+#else
+#define VDSO_DEFAULT VDSO_ENABLED
+#endif
/*
* Should the kernel map a VDSO page into processes and pass its
* address down to glibc upon exec()?
*/
-#ifdef CONFIG_PARAVIRT
-unsigned int __read_mostly vdso_enabled = 0;
-#else
-unsigned int __read_mostly vdso_enabled = 1;
-#endif
+unsigned int __read_mostly vdso_enabled = VDSO_DEFAULT;
EXPORT_SYMBOL_GPL(vdso_enabled);
@@ -46,6 +56,123 @@ __setup("vdso=", vdso_setup);
extern asmlinkage void sysenter_entry(void);
+static __init void reloc_symtab(Elf32_Ehdr *ehdr,
+ unsigned offset, unsigned size)
+{
+ Elf32_Sym *sym = (void *)ehdr + offset;
+ unsigned nsym = size / sizeof(*sym);
+ unsigned i;
+
+ for(i = 0; i < nsym; i++, sym++) {
+ if (sym->st_shndx == SHN_UNDEF ||
+ sym->st_shndx == SHN_ABS)
+ continue; /* skip */
+
+ if (sym->st_shndx > SHN_LORESERVE) {
+ printk(KERN_INFO "VDSO: unexpected st_shndx %x\n",
+ sym->st_shndx);
+ continue;
+ }
+
+ switch(ELF_ST_TYPE(sym->st_info)) {
+ case STT_OBJECT:
+ case STT_FUNC:
+ case STT_SECTION:
+ case STT_FILE:
+ sym->st_value += VDSO_HIGH_BASE;
+ }
+ }
+}
+
+static __init void reloc_dyn(Elf32_Ehdr *ehdr, unsigned offset)
+{
+ Elf32_Dyn *dyn = (void *)ehdr + offset;
+
+ for(; dyn->d_tag != DT_NULL; dyn++)
+ switch(dyn->d_tag) {
+ case DT_PLTGOT:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_RELA:
+ case DT_INIT:
+ case DT_FINI:
+ case DT_REL:
+ case DT_DEBUG:
+ case DT_JMPREL:
+ case DT_VERSYM:
+ case DT_VERDEF:
+ case DT_VERNEED:
+ case DT_ADDRRNGLO ... DT_ADDRRNGHI:
+ /* definitely pointers needing relocation */
+ dyn->d_un.d_ptr += VDSO_HIGH_BASE;
+ break;
+
+ case DT_ENCODING ... OLD_DT_LOOS-1:
+ case DT_LOOS ... DT_HIOS-1:
+ /* Tags above DT_ENCODING are pointers if
+ they're even */
+ if (dyn->d_tag >= DT_ENCODING &&
+ (dyn->d_tag & 1) == 0)
+ dyn->d_un.d_ptr += VDSO_HIGH_BASE;
+ break;
+
+ case DT_VERDEFNUM:
+ case DT_VERNEEDNUM:
+ case DT_FLAGS_1:
+ case DT_RELACOUNT:
+ case DT_RELCOUNT:
+ case DT_VALRNGLO ... DT_VALRNGHI:
+ /* definitely not pointers */
+ break;
+
+ case OLD_DT_LOOS ... DT_LOOS-1:
+ case DT_HIOS ... DT_VALRNGLO-1:
+ default:
+ if (dyn->d_tag > DT_ENCODING)
+ printk(KERN_INFO "VDSO: unexpected DT_tag %x\n",
+ dyn->d_tag);
+ break;
+ }
+}
+
+static __init void relocate_vdso(Elf32_Ehdr *ehdr)
+{
+ Elf32_Phdr *phdr;
+ Elf32_Shdr *shdr;
+ int i;
+
+ BUG_ON(memcmp(ehdr->e_ident, ELFMAG, 4) != 0 ||
+ !elf_check_arch(ehdr) ||
+ ehdr->e_type != ET_DYN);
+
+ ehdr->e_entry += VDSO_HIGH_BASE;
+
+ /* rebase phdrs */
+ phdr = (void *)ehdr + ehdr->e_phoff;
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ phdr[i].p_vaddr += VDSO_HIGH_BASE;
+
+ /* relocate dynamic stuff */
+ if (phdr[i].p_type == PT_DYNAMIC)
+ reloc_dyn(ehdr, phdr[i].p_offset);
+ }
+
+ /* rebase sections */
+ shdr = (void *)ehdr + ehdr->e_shoff;
+ for(i = 0; i < ehdr->e_shnum; i++) {
+ if (!(shdr[i].sh_flags & SHF_ALLOC))
+ continue;
+
+ shdr[i].sh_addr += VDSO_HIGH_BASE;
+
+ if (shdr[i].sh_type == SHT_SYMTAB ||
+ shdr[i].sh_type == SHT_DYNSYM)
+ reloc_symtab(ehdr, shdr[i].sh_offset,
+ shdr[i].sh_size);
+ }
+}
+
void enable_sep_cpu(void)
{
int cpu = get_cpu();
@@ -56,14 +183,33 @@ void enable_sep_cpu(void)
return;
}
- tss->ss1 = __KERNEL_CS;
- tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
+ tss->x86_tss.ss1 = __KERNEL_CS;
+ tss->x86_tss.esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
- wrmsr(MSR_IA32_SYSENTER_ESP, tss->esp1, 0);
+ wrmsr(MSR_IA32_SYSENTER_ESP, tss->x86_tss.esp1, 0);
wrmsr(MSR_IA32_SYSENTER_EIP, (unsigned long) sysenter_entry, 0);
put_cpu();
}
+static struct vm_area_struct gate_vma;
+
+static int __init gate_vma_init(void)
+{
+ gate_vma.vm_mm = NULL;
+ gate_vma.vm_start = FIXADDR_USER_START;
+ gate_vma.vm_end = FIXADDR_USER_END;
+ gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC;
+ gate_vma.vm_page_prot = __P101;
+ /*
+ * Make sure the vDSO gets into every core dump.
+ * Dumping its contents makes post-mortem fully interpretable later
+ * without matching up the same kernel and hardware config to see
+ * what PC values meant.
+ */
+ gate_vma.vm_flags |= VM_ALWAYSDUMP;
+ return 0;
+}
+
/*
* These symbols are defined by vsyscall.o to mark the bounds
* of the ELF DSO images included therein.
@@ -72,31 +218,48 @@ extern const char vsyscall_int80_start, vsyscall_int80_end;
extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
static struct page *syscall_pages[1];
+static void map_compat_vdso(int map)
+{
+ static int vdso_mapped;
+
+ if (map == vdso_mapped)
+ return;
+
+ vdso_mapped = map;
+
+ __set_fixmap(FIX_VDSO, page_to_pfn(syscall_pages[0]) << PAGE_SHIFT,
+ map ? PAGE_READONLY_EXEC : PAGE_NONE);
+
+ /* flush stray tlbs */
+ flush_tlb_all();
+}
+
int __init sysenter_setup(void)
{
void *syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ const void *vsyscall;
+ size_t vsyscall_len;
+
syscall_pages[0] = virt_to_page(syscall_page);
-#ifdef CONFIG_COMPAT_VDSO
- __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY_EXEC);
+ gate_vma_init();
+
printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
-#endif
if (!boot_cpu_has(X86_FEATURE_SEP)) {
- memcpy(syscall_page,
- &vsyscall_int80_start,
- &vsyscall_int80_end - &vsyscall_int80_start);
- return 0;
+ vsyscall = &vsyscall_int80_start;
+ vsyscall_len = &vsyscall_int80_end - &vsyscall_int80_start;
+ } else {
+ vsyscall = &vsyscall_sysenter_start;
+ vsyscall_len = &vsyscall_sysenter_end - &vsyscall_sysenter_start;
}
- memcpy(syscall_page,
- &vsyscall_sysenter_start,
- &vsyscall_sysenter_end - &vsyscall_sysenter_start);
+ memcpy(syscall_page, vsyscall, vsyscall_len);
+ relocate_vdso(syscall_page);
return 0;
}
-#ifndef CONFIG_COMPAT_VDSO
/* Defined in vsyscall-sysenter.S */
extern void SYSENTER_RETURN;
@@ -105,36 +268,52 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
{
struct mm_struct *mm = current->mm;
unsigned long addr;
- int ret;
+ int ret = 0;
+ bool compat;
down_write(&mm->mmap_sem);
- addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
- if (IS_ERR_VALUE(addr)) {
- ret = addr;
- goto up_fail;
- }
- /*
- * MAYWRITE to allow gdb to COW and set breakpoints
- *
- * Make sure the vDSO gets into every core dump.
- * Dumping its contents makes post-mortem fully interpretable later
- * without matching up the same kernel and hardware config to see
- * what PC values meant.
- */
- ret = install_special_mapping(mm, addr, PAGE_SIZE,
- VM_READ|VM_EXEC|
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
- VM_ALWAYSDUMP,
- syscall_pages);
- if (ret)
- goto up_fail;
+ /* Test compat mode once here, in case someone
+ changes it via sysctl */
+ compat = (vdso_enabled == VDSO_COMPAT);
+
+ map_compat_vdso(compat);
+
+ if (compat)
+ addr = VDSO_HIGH_BASE;
+ else {
+ addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ /*
+ * MAYWRITE to allow gdb to COW and set breakpoints
+ *
+ * Make sure the vDSO gets into every core dump.
+ * Dumping its contents makes post-mortem fully
+ * interpretable later without matching up the same
+ * kernel and hardware config to see what PC values
+ * meant.
+ */
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ syscall_pages);
+
+ if (ret)
+ goto up_fail;
+ }
current->mm->context.vdso = (void *)addr;
current_thread_info()->sysenter_return =
- (void *)VDSO_SYM(&SYSENTER_RETURN);
-up_fail:
+ (void *)VDSO_SYM(&SYSENTER_RETURN);
+
+ up_fail:
up_write(&mm->mmap_sem);
+
return ret;
}
@@ -147,6 +326,11 @@ const char *arch_vma_name(struct vm_area_struct *vma)
struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
{
+ struct mm_struct *mm = tsk->mm;
+
+ /* Check to see if this task was created in compat vdso mode */
+ if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE)
+ return &gate_vma;
return NULL;
}
@@ -159,4 +343,3 @@ int in_gate_area_no_task(unsigned long addr)
{
return 0;
}
-#endif
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 94e5cb09110..a665df61f08 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -70,8 +70,6 @@
#include <asm/i8259.h>
-int pit_latch_buggy; /* extern */
-
#include "do_timer.h"
unsigned int cpu_khz; /* Detected as we calibrate the TSC */
diff --git a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S
index 2f1814c5cfd..f62815f8d06 100644
--- a/arch/i386/kernel/trampoline.S
+++ b/arch/i386/kernel/trampoline.S
@@ -29,7 +29,7 @@
*
* TYPE VALUE
* R_386_32 startup_32_smp
- * R_386_32 boot_gdt_table
+ * R_386_32 boot_gdt
*/
#include <linux/linkage.h>
@@ -62,8 +62,8 @@ r_base = .
* to 32 bit.
*/
- lidtl boot_idt - r_base # load idt with 0, 0
- lgdtl boot_gdt - r_base # load gdt with whatever is appropriate
+ lidtl boot_idt_descr - r_base # load idt with 0, 0
+ lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate
xor %ax, %ax
inc %ax # protected mode (PE) bit
@@ -73,11 +73,11 @@ r_base = .
# These need to be in the same 64K segment as the above;
# hence we don't use the boot_gdt_descr defined in head.S
-boot_gdt:
+boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
- .long boot_gdt_table-__PAGE_OFFSET # gdt base
+ .long boot_gdt - __PAGE_OFFSET # gdt base
-boot_idt:
+boot_idt_descr:
.word 0 # idt limit = 0
.long 0 # idt base = 0L
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index af0d3f70a81..c05e7e861b2 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -52,7 +52,7 @@
#include <asm/unwind.h>
#include <asm/smp.h>
#include <asm/arch_hooks.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
#include <asm/stacktrace.h>
#include <linux/module.h>
@@ -95,20 +95,6 @@ asmlinkage void machine_check(void);
int kstack_depth_to_print = 24;
static unsigned int code_bytes = 64;
-ATOMIC_NOTIFIER_HEAD(i386die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- vmalloc_sync_all();
- return atomic_notifier_chain_register(&i386die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&i386die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */
static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
{
@@ -319,7 +305,7 @@ void show_registers(struct pt_regs *regs)
regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss);
printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)",
TASK_COMM_LEN, current->comm, current->pid,
- current_thread_info(), current, current->thread_info);
+ current_thread_info(), current, task_thread_info(current));
/*
* When in-kernel, we also print out the stack and code at the
* time of the fault..
@@ -476,8 +462,6 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
siginfo_t *info)
{
struct task_struct *tsk = current;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
if (regs->eflags & VM_MASK) {
if (vm86)
@@ -489,6 +473,18 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
goto kernel_trap;
trap_signal: {
+ /*
+ * We want error_code and trap_no set for userspace faults and
+ * kernelspace faults which result in die(), but not
+ * kernelspace faults which are fixed up. die() gives the
+ * process no chance to handle the signal and notice the
+ * kernel fault information, so that won't result in polluting
+ * the information about previously queued, but not yet
+ * delivered, faults. See also do_general_protection below.
+ */
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
+
if (info)
force_sig_info(signr, info, tsk);
else
@@ -497,8 +493,11 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86,
}
kernel_trap: {
- if (!fixup_exception(regs))
+ if (!fixup_exception(regs)) {
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
die(str, regs, error_code);
+ }
return;
}
@@ -583,7 +582,7 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
* and we set the offset field correctly. Then we let the CPU to
* restart the faulting instruction.
*/
- if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
+ if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY &&
thread->io_bitmap_ptr) {
memcpy(tss->io_bitmap, thread->io_bitmap_ptr,
thread->io_bitmap_max);
@@ -596,16 +595,13 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
thread->io_bitmap_max, 0xff,
tss->io_bitmap_max - thread->io_bitmap_max);
tss->io_bitmap_max = thread->io_bitmap_max;
- tss->io_bitmap_base = IO_BITMAP_OFFSET;
+ tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET;
tss->io_bitmap_owner = thread;
put_cpu();
return;
}
put_cpu();
- current->thread.error_code = error_code;
- current->thread.trap_no = 13;
-
if (regs->eflags & VM_MASK)
goto gp_in_vm86;
@@ -624,6 +620,8 @@ gp_in_vm86:
gp_in_kernel:
if (!fixup_exception(regs)) {
+ current->thread.error_code = error_code;
+ current->thread.trap_no = 13;
if (notify_die(DIE_GPF, "general protection fault", regs,
error_code, 13, SIGSEGV) == NOTIFY_STOP)
return;
@@ -735,6 +733,11 @@ static __kprobes void default_do_nmi(struct pt_regs * regs)
*/
if (nmi_watchdog_tick(regs, reason))
return;
+#endif
+ if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
+ == NOTIFY_STOP)
+ return;
+#ifdef CONFIG_X86_LOCAL_APIC
if (!do_nmi_callback(regs, smp_processor_id()))
#endif
unknown_nmi_error(reason, regs);
@@ -1018,9 +1021,7 @@ fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
fastcall unsigned long patch_espfix_desc(unsigned long uesp,
unsigned long kesp)
{
- int cpu = smp_processor_id();
- struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
- struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address;
+ struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt;
unsigned long base = (kesp - uesp) & -THREAD_SIZE;
unsigned long new_kesp = kesp - base;
unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index 6cb8f533673..f64b81f3033 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -200,13 +200,10 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
{
struct cpufreq_freqs *freq = data;
- if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
- write_seqlock_irq(&xtime_lock);
-
if (!ref_freq) {
if (!freq->old){
ref_freq = freq->new;
- goto end;
+ return 0;
}
ref_freq = freq->old;
loops_per_jiffy_ref = cpu_data[freq->cpu].loops_per_jiffy;
@@ -233,13 +230,10 @@ time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, void *data)
* TSC based sched_clock turns
* to junk w/ cpufreq
*/
- mark_tsc_unstable();
+ mark_tsc_unstable("cpufreq changes");
}
}
}
-end:
- if (val != CPUFREQ_RESUMECHANGE && val != CPUFREQ_SUSPENDCHANGE)
- write_sequnlock_irq(&xtime_lock);
return 0;
}
@@ -281,11 +275,12 @@ static struct clocksource clocksource_tsc = {
CLOCK_SOURCE_MUST_VERIFY,
};
-void mark_tsc_unstable(void)
+void mark_tsc_unstable(char *reason)
{
if (!tsc_unstable) {
tsc_unstable = 1;
tsc_enabled = 0;
+ printk("Marking TSC unstable due to: %s.\n", reason);
/* Can be called before registration */
if (clocksource_tsc.mult)
clocksource_change_rating(&clocksource_tsc, 0);
diff --git a/arch/i386/kernel/verify_cpu.S b/arch/i386/kernel/verify_cpu.S
new file mode 100644
index 00000000000..e51a8695d54
--- /dev/null
+++ b/arch/i386/kernel/verify_cpu.S
@@ -0,0 +1,65 @@
+/* Check if CPU has some minimum CPUID bits
+ This runs in 16bit mode so that the caller can still use the BIOS
+ to output errors on the screen */
+#include <asm/cpufeature.h>
+
+verify_cpu:
+ pushfl # Save caller passed flags
+ pushl $0 # Kill any dangerous flags
+ popfl
+
+#if CONFIG_X86_MINIMUM_CPU_MODEL >= 4
+ pushfl
+ orl $(1<<18),(%esp) # try setting AC
+ popfl
+ pushfl
+ popl %eax
+ testl $(1<<18),%eax
+ jz bad
+#endif
+#if REQUIRED_MASK1 != 0
+ pushfl # standard way to check for cpuid
+ popl %eax
+ movl %eax,%ebx
+ xorl $0x200000,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ cmpl %eax,%ebx
+ pushfl # standard way to check for cpuid
+ popl %eax
+ movl %eax,%ebx
+ xorl $0x200000,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ cmpl %eax,%ebx
+ jz bad # REQUIRED_MASK1 != 0 requires CPUID
+
+ movl $0x0,%eax # See if cpuid 1 is implemented
+ cpuid
+ cmpl $0x1,%eax
+ jb bad # no cpuid 1
+
+ movl $0x1,%eax # Does the cpu have what it takes
+ cpuid
+
+#if CONFIG_X86_MINIMUM_CPU_MODEL > 4
+#error add proper model checking here
+#endif
+
+ andl $REQUIRED_MASK1,%edx
+ xorl $REQUIRED_MASK1,%edx
+ jnz bad
+#endif /* REQUIRED_MASK1 */
+
+ popfl
+ xor %eax,%eax
+ ret
+
+bad:
+ popfl
+ movl $1,%eax
+ ret
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index d1b8f2b7aea..f2dcd1d27c0 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -39,7 +39,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/highmem.h>
#include <linux/ptrace.h>
#include <linux/audit.h>
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c
index 697a70e8c0c..c8726c424b3 100644
--- a/arch/i386/kernel/vmi.c
+++ b/arch/i386/kernel/vmi.c
@@ -26,6 +26,7 @@
#include <linux/cpu.h>
#include <linux/bootmem.h>
#include <linux/mm.h>
+#include <linux/highmem.h>
#include <asm/vmi.h>
#include <asm/io.h>
#include <asm/fixmap.h>
@@ -56,7 +57,7 @@ static int disable_noidle;
static int disable_vmi_timer;
/* Cached VMI operations */
-struct {
+static struct {
void (*cpuid)(void /* non-c */);
void (*_set_ldt)(u32 selector);
void (*set_tr)(u32 selector);
@@ -65,16 +66,15 @@ struct {
void (*release_page)(u32, u32);
void (*set_pte)(pte_t, pte_t *, unsigned);
void (*update_pte)(pte_t *, unsigned);
- void (*set_linear_mapping)(int, u32, u32, u32);
- void (*flush_tlb)(int);
+ void (*set_linear_mapping)(int, void *, u32, u32);
+ void (*_flush_tlb)(int);
void (*set_initial_ap_state)(int, int);
void (*halt)(void);
void (*set_lazy_mode)(int mode);
} vmi_ops;
-/* XXX move this to alternative.h */
-extern struct paravirt_patch __start_parainstructions[],
- __stop_parainstructions[];
+/* Cached VMI operations */
+struct vmi_timer_ops vmi_timer_ops;
/*
* VMI patching routines.
@@ -83,11 +83,6 @@ extern struct paravirt_patch __start_parainstructions[],
#define MNEM_JMP 0xe9
#define MNEM_RET 0xc3
-static char irq_save_disable_callout[] = {
- MNEM_CALL, 0, 0, 0, 0,
- MNEM_CALL, 0, 0, 0, 0,
- MNEM_RET
-};
#define IRQ_PATCH_INT_MASK 0
#define IRQ_PATCH_DISABLE 5
@@ -135,33 +130,17 @@ static unsigned patch_internal(int call, unsigned len, void *insns)
static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len)
{
switch (type) {
- case PARAVIRT_IRQ_DISABLE:
+ case PARAVIRT_PATCH(irq_disable):
return patch_internal(VMI_CALL_DisableInterrupts, len, insns);
- case PARAVIRT_IRQ_ENABLE:
+ case PARAVIRT_PATCH(irq_enable):
return patch_internal(VMI_CALL_EnableInterrupts, len, insns);
- case PARAVIRT_RESTORE_FLAGS:
+ case PARAVIRT_PATCH(restore_fl):
return patch_internal(VMI_CALL_SetInterruptMask, len, insns);
- case PARAVIRT_SAVE_FLAGS:
+ case PARAVIRT_PATCH(save_fl):
return patch_internal(VMI_CALL_GetInterruptMask, len, insns);
- case PARAVIRT_SAVE_FLAGS_IRQ_DISABLE:
- if (len >= 10) {
- patch_internal(VMI_CALL_GetInterruptMask, len, insns);
- patch_internal(VMI_CALL_DisableInterrupts, len-5, insns+5);
- return 10;
- } else {
- /*
- * You bastards didn't leave enough room to
- * patch save_flags_irq_disable inline. Patch
- * to a helper
- */
- BUG_ON(len < 5);
- *(char *)insns = MNEM_CALL;
- patch_offset(insns, irq_save_disable_callout);
- return 5;
- }
- case PARAVIRT_INTERRUPT_RETURN:
+ case PARAVIRT_PATCH(iret):
return patch_internal(VMI_CALL_IRET, len, insns);
- case PARAVIRT_STI_SYSEXIT:
+ case PARAVIRT_PATCH(irq_enable_sysexit):
return patch_internal(VMI_CALL_SYSEXIT, len, insns);
default:
break;
@@ -230,24 +209,24 @@ static void vmi_set_tr(void)
static void vmi_load_esp0(struct tss_struct *tss,
struct thread_struct *thread)
{
- tss->esp0 = thread->esp0;
+ tss->x86_tss.esp0 = thread->esp0;
/* This can only happen when SEP is enabled, no need to test "SEP"arately */
- if (unlikely(tss->ss1 != thread->sysenter_cs)) {
- tss->ss1 = thread->sysenter_cs;
+ if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
+ tss->x86_tss.ss1 = thread->sysenter_cs;
wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
}
- vmi_ops.set_kernel_stack(__KERNEL_DS, tss->esp0);
+ vmi_ops.set_kernel_stack(__KERNEL_DS, tss->x86_tss.esp0);
}
static void vmi_flush_tlb_user(void)
{
- vmi_ops.flush_tlb(VMI_FLUSH_TLB);
+ vmi_ops._flush_tlb(VMI_FLUSH_TLB);
}
static void vmi_flush_tlb_kernel(void)
{
- vmi_ops.flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL);
+ vmi_ops._flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL);
}
/* Stub to do nothing at all; used for delays and unimplemented calls */
@@ -255,18 +234,6 @@ static void vmi_nop(void)
{
}
-/* For NO_IDLE_HZ, we stop the clock when halting the kernel */
-static fastcall void vmi_safe_halt(void)
-{
- int idle = vmi_stop_hz_timer();
- vmi_ops.halt();
- if (idle) {
- local_irq_disable();
- vmi_account_time_restart_hz_timer();
- local_irq_enable();
- }
-}
-
#ifdef CONFIG_DEBUG_PAGE_TYPE
#ifdef CONFIG_X86_PAE
@@ -370,8 +337,11 @@ static void vmi_check_page_type(u32 pfn, int type)
#define vmi_check_page_type(p,t) do { } while (0)
#endif
-static void vmi_map_pt_hook(int type, pte_t *va, u32 pfn)
+#ifdef CONFIG_HIGHPTE
+static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
{
+ void *va = kmap_atomic(page, type);
+
/*
* Internally, the VMI ROM must map virtual addresses to physical
* addresses for processing MMU updates. By the time MMU updates
@@ -385,8 +355,11 @@ static void vmi_map_pt_hook(int type, pte_t *va, u32 pfn)
* args: SLOT VA COUNT PFN
*/
BUG_ON(type != KM_PTE0 && type != KM_PTE1);
- vmi_ops.set_linear_mapping((type - KM_PTE0)+1, (u32)va, 1, pfn);
+ vmi_ops.set_linear_mapping((type - KM_PTE0)+1, va, 1, page_to_pfn(page));
+
+ return va;
}
+#endif
static void vmi_allocate_pt(u32 pfn)
{
@@ -443,13 +416,13 @@ static void vmi_release_pd(u32 pfn)
((level) | (is_current_as(mm, user) ? \
(VMI_PAGE_DEFER | VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0))
-static void vmi_update_pte(struct mm_struct *mm, u32 addr, pte_t *ptep)
+static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
}
-static void vmi_update_pte_defer(struct mm_struct *mm, u32 addr, pte_t *ptep)
+static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0));
@@ -462,7 +435,7 @@ static void vmi_set_pte(pte_t *ptep, pte_t pte)
vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT);
}
-static void vmi_set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pte)
+static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
{
vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE);
vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
@@ -516,7 +489,7 @@ static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
}
-void vmi_pmd_clear(pmd_t *pmd)
+static void vmi_pmd_clear(pmd_t *pmd)
{
const pte_t pte = { 0 };
vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD);
@@ -525,8 +498,6 @@ void vmi_pmd_clear(pmd_t *pmd)
#endif
#ifdef CONFIG_SMP
-extern void setup_pda(void);
-
static void __devinit
vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
unsigned long start_esp)
@@ -551,13 +522,11 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
ap.ds = __USER_DS;
ap.es = __USER_DS;
- ap.fs = __KERNEL_PDA;
+ ap.fs = __KERNEL_PERCPU;
ap.gs = 0;
ap.eflags = 0;
- setup_pda();
-
#ifdef CONFIG_X86_PAE
/* efer should match BSP efer. */
if (cpu_has_nx) {
@@ -575,9 +544,9 @@ vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
}
#endif
-static void vmi_set_lazy_mode(int mode)
+static void vmi_set_lazy_mode(enum paravirt_lazy_mode mode)
{
- static DEFINE_PER_CPU(int, lazy_mode);
+ static DEFINE_PER_CPU(enum paravirt_lazy_mode, lazy_mode);
if (!vmi_ops.set_lazy_mode)
return;
@@ -685,7 +654,7 @@ void vmi_bringup(void)
{
/* We must establish the lowmem mapping for MMU ops to work */
if (vmi_ops.set_linear_mapping)
- vmi_ops.set_linear_mapping(0, __PAGE_OFFSET, max_low_pfn, 0);
+ vmi_ops.set_linear_mapping(0, (void *)__PAGE_OFFSET, max_low_pfn, 0);
}
/*
@@ -740,7 +709,6 @@ do { \
} \
} while (0)
-
/*
* Activate the VMI interface and switch into paravirtualized mode
*/
@@ -796,12 +764,6 @@ static inline int __init activate_vmi(void)
para_fill(irq_disable, DisableInterrupts);
para_fill(irq_enable, EnableInterrupts);
- /* irq_save_disable !!! sheer pain */
- patch_offset(&irq_save_disable_callout[IRQ_PATCH_INT_MASK],
- (char *)paravirt_ops.save_fl);
- patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE],
- (char *)paravirt_ops.irq_disable);
-
para_fill(wbinvd, WBINVD);
para_fill(read_tsc, RDTSC);
@@ -831,8 +793,8 @@ static inline int __init activate_vmi(void)
para_wrap(set_lazy_mode, vmi_set_lazy_mode, set_lazy_mode, SetLazyMode);
/* user and kernel flush are just handled with different flags to FlushTLB */
- para_wrap(flush_tlb_user, vmi_flush_tlb_user, flush_tlb, FlushTLB);
- para_wrap(flush_tlb_kernel, vmi_flush_tlb_kernel, flush_tlb, FlushTLB);
+ para_wrap(flush_tlb_user, vmi_flush_tlb_user, _flush_tlb, FlushTLB);
+ para_wrap(flush_tlb_kernel, vmi_flush_tlb_kernel, _flush_tlb, FlushTLB);
para_fill(flush_tlb_single, InvalPage);
/*
@@ -878,8 +840,13 @@ static inline int __init activate_vmi(void)
paravirt_ops.release_pt = vmi_release_pt;
paravirt_ops.release_pd = vmi_release_pd;
}
- para_wrap(map_pt_hook, vmi_map_pt_hook, set_linear_mapping,
- SetLinearMapping);
+
+ /* Set linear is needed in all cases */
+ vmi_ops.set_linear_mapping = vmi_get_function(VMI_CALL_SetLinearMapping);
+#ifdef CONFIG_HIGHPTE
+ if (vmi_ops.set_linear_mapping)
+ paravirt_ops.kmap_atomic_pte = vmi_kmap_atomic_pte;
+#endif
/*
* These MUST always be patched. Don't support indirect jumps
@@ -920,8 +887,8 @@ static inline int __init activate_vmi(void)
paravirt_ops.get_wallclock = vmi_get_wallclock;
paravirt_ops.set_wallclock = vmi_set_wallclock;
#ifdef CONFIG_X86_LOCAL_APIC
- paravirt_ops.setup_boot_clock = vmi_timer_setup_boot_alarm;
- paravirt_ops.setup_secondary_clock = vmi_timer_setup_secondary_alarm;
+ paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
+ paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
#endif
paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
paravirt_ops.get_cpu_khz = vmi_cpu_khz;
@@ -933,11 +900,7 @@ static inline int __init activate_vmi(void)
disable_vmi_timer = 1;
}
- /* No idle HZ mode only works if VMI timer and no idle is enabled */
- if (disable_noidle || disable_vmi_timer)
- para_fill(safe_halt, Halt);
- else
- para_wrap(safe_halt, vmi_safe_halt, halt, Halt);
+ para_fill(safe_halt, Halt);
/*
* Alternative instruction rewriting doesn't happen soon enough
@@ -945,7 +908,7 @@ static inline int __init activate_vmi(void)
* to do this before IRQs get reenabled. Fortunately, it is
* idempotent.
*/
- apply_paravirt(__start_parainstructions, __stop_parainstructions);
+ apply_paravirt(__parainstructions, __parainstructions_end);
vmi_bringup();
diff --git a/arch/i386/kernel/vmiclock.c b/arch/i386/kernel/vmiclock.c
new file mode 100644
index 00000000000..26a37f8a876
--- /dev/null
+++ b/arch/i386/kernel/vmiclock.c
@@ -0,0 +1,318 @@
+/*
+ * VMI paravirtual timer support routines.
+ *
+ * Copyright (C) 2007, VMware, Inc.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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/smp.h>
+#include <linux/interrupt.h>
+#include <linux/cpumask.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+#include <asm/vmi.h>
+#include <asm/vmi_time.h>
+#include <asm/arch_hooks.h>
+#include <asm/apicdef.h>
+#include <asm/apic.h>
+#include <asm/timer.h>
+
+#include <irq_vectors.h>
+#include "io_ports.h"
+
+#define VMI_ONESHOT (VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
+#define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
+
+static DEFINE_PER_CPU(struct clock_event_device, local_events);
+
+static inline u32 vmi_counter(u32 flags)
+{
+ /* Given VMI_ONESHOT or VMI_PERIODIC, return the corresponding
+ * cycle counter. */
+ return flags & VMI_ALARM_COUNTER_MASK;
+}
+
+/* paravirt_ops.get_wallclock = vmi_get_wallclock */
+unsigned long vmi_get_wallclock(void)
+{
+ unsigned long long wallclock;
+ wallclock = vmi_timer_ops.get_wallclock(); // nsec
+ (void)do_div(wallclock, 1000000000); // sec
+
+ return wallclock;
+}
+
+/* paravirt_ops.set_wallclock = vmi_set_wallclock */
+int vmi_set_wallclock(unsigned long now)
+{
+ return 0;
+}
+
+/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
+unsigned long long vmi_get_sched_cycles(void)
+{
+ return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+}
+
+/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
+unsigned long vmi_cpu_khz(void)
+{
+ unsigned long long khz;
+ khz = vmi_timer_ops.get_cycle_frequency();
+ (void)do_div(khz, 1000);
+ return khz;
+}
+
+static inline unsigned int vmi_get_timer_vector(void)
+{
+#ifdef CONFIG_X86_IO_APIC
+ return FIRST_DEVICE_VECTOR;
+#else
+ return FIRST_EXTERNAL_VECTOR;
+#endif
+}
+
+/** vmi clockchip */
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned int startup_timer_irq(unsigned int irq)
+{
+ unsigned long val = apic_read(APIC_LVTT);
+ apic_write(APIC_LVTT, vmi_get_timer_vector());
+
+ return (val & APIC_SEND_PENDING);
+}
+
+static void mask_timer_irq(unsigned int irq)
+{
+ unsigned long val = apic_read(APIC_LVTT);
+ apic_write(APIC_LVTT, val | APIC_LVT_MASKED);
+}
+
+static void unmask_timer_irq(unsigned int irq)
+{
+ unsigned long val = apic_read(APIC_LVTT);
+ apic_write(APIC_LVTT, val & ~APIC_LVT_MASKED);
+}
+
+static void ack_timer_irq(unsigned int irq)
+{
+ ack_APIC_irq();
+}
+
+static struct irq_chip vmi_chip __read_mostly = {
+ .name = "VMI-LOCAL",
+ .startup = startup_timer_irq,
+ .mask = mask_timer_irq,
+ .unmask = unmask_timer_irq,
+ .ack = ack_timer_irq
+};
+#endif
+
+/** vmi clockevent */
+#define VMI_ALARM_WIRED_IRQ0 0x00000000
+#define VMI_ALARM_WIRED_LVTT 0x00010000
+static int vmi_wiring = VMI_ALARM_WIRED_IRQ0;
+
+static inline int vmi_get_alarm_wiring(void)
+{
+ return vmi_wiring;
+}
+
+static void vmi_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ cycle_t now, cycles_per_hz;
+ BUG_ON(!irqs_disabled());
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
+ (void)do_div(cycles_per_hz, HZ);
+ now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_PERIODIC));
+ vmi_timer_ops.set_alarm(VMI_PERIODIC, now, cycles_per_hz);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ switch (evt->mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ vmi_timer_ops.cancel_alarm(VMI_ONESHOT);
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ vmi_timer_ops.cancel_alarm(VMI_PERIODIC);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static int vmi_timer_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ /* Unfortunately, set_next_event interface only passes relative
+ * expiry, but we want absolute expiry. It'd be better if were
+ * were passed an aboslute expiry, since a bunch of time may
+ * have been stolen between the time the delta is computed and
+ * when we set the alarm below. */
+ cycle_t now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_ONESHOT));
+
+ BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+ vmi_timer_ops.set_alarm(VMI_ONESHOT, now + delta, 0);
+ return 0;
+}
+
+static struct clock_event_device vmi_clockevent = {
+ .name = "vmi-timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 22,
+ .set_mode = vmi_timer_set_mode,
+ .set_next_event = vmi_timer_next_event,
+ .rating = 1000,
+ .irq = 0,
+};
+
+static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &__get_cpu_var(local_events);
+ evt->event_handler(evt);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction vmi_clock_action = {
+ .name = "vmi-timer",
+ .handler = vmi_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+ .mask = CPU_MASK_ALL,
+};
+
+static void __devinit vmi_time_init_clockevent(void)
+{
+ cycle_t cycles_per_msec;
+ struct clock_event_device *evt;
+
+ int cpu = smp_processor_id();
+ evt = &__get_cpu_var(local_events);
+
+ /* Use cycles_per_msec since div_sc params are 32-bits. */
+ cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
+ (void)do_div(cycles_per_msec, 1000);
+
+ memcpy(evt, &vmi_clockevent, sizeof(*evt));
+ /* Must pick .shift such that .mult fits in 32-bits. Choosing
+ * .shift to be 22 allows 2^(32-22) cycles per nano-seconds
+ * before overflow. */
+ evt->mult = div_sc(cycles_per_msec, NSEC_PER_MSEC, evt->shift);
+ /* Upper bound is clockevent's use of ulong for cycle deltas. */
+ evt->max_delta_ns = clockevent_delta2ns(ULONG_MAX, evt);
+ evt->min_delta_ns = clockevent_delta2ns(1, evt);
+ evt->cpumask = cpumask_of_cpu(cpu);
+
+ printk(KERN_WARNING "vmi: registering clock event %s. mult=%lu shift=%u\n",
+ evt->name, evt->mult, evt->shift);
+ clockevents_register_device(evt);
+}
+
+void __init vmi_time_init(void)
+{
+ /* Disable PIT: BIOSes start PIT CH0 with 18.2hz peridic. */
+ outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */
+
+ vmi_time_init_clockevent();
+ setup_irq(0, &vmi_clock_action);
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+void __devinit vmi_time_bsp_init(void)
+{
+ /*
+ * On APIC systems, we want local timers to fire on each cpu. We do
+ * this by programming LVTT to deliver timer events to the IRQ handler
+ * for IRQ-0, since we can't re-use the APIC local timer handler
+ * without interfering with that code.
+ */
+ clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+ local_irq_disable();
+#ifdef CONFIG_X86_SMP
+ /*
+ * XXX handle_percpu_irq only defined for SMP; we need to switch over
+ * to using it, since this is a local interrupt, which each CPU must
+ * handle individually without locking out or dropping simultaneous
+ * local timers on other CPUs. We also don't want to trigger the
+ * quirk workaround code for interrupts which gets invoked from
+ * handle_percpu_irq via eoi, so we use our own IRQ chip.
+ */
+ set_irq_chip_and_handler_name(0, &vmi_chip, handle_percpu_irq, "lvtt");
+#else
+ set_irq_chip_and_handler_name(0, &vmi_chip, handle_edge_irq, "lvtt");
+#endif
+ vmi_wiring = VMI_ALARM_WIRED_LVTT;
+ apic_write(APIC_LVTT, vmi_get_timer_vector());
+ local_irq_enable();
+ clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+}
+
+void __devinit vmi_time_ap_init(void)
+{
+ vmi_time_init_clockevent();
+ apic_write(APIC_LVTT, vmi_get_timer_vector());
+}
+#endif
+
+/** vmi clocksource */
+
+static cycle_t read_real_cycles(void)
+{
+ return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
+}
+
+static struct clocksource clocksource_vmi = {
+ .name = "vmi-timer",
+ .rating = 450,
+ .read = read_real_cycles,
+ .mask = CLOCKSOURCE_MASK(64),
+ .mult = 0, /* to be set */
+ .shift = 22,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init init_vmi_clocksource(void)
+{
+ cycle_t cycles_per_msec;
+
+ if (!vmi_timer_ops.get_cycle_frequency)
+ return 0;
+ /* Use khz2mult rather than hz2mult since hz arg is only 32-bits. */
+ cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
+ (void)do_div(cycles_per_msec, 1000);
+
+ /* Note that clocksource.{mult, shift} converts in the opposite direction
+ * as clockevents. */
+ clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
+ clocksource_vmi.shift);
+
+ printk(KERN_WARNING "vmi: registering clock source khz=%lld\n", cycles_per_msec);
+ return clocksource_register(&clocksource_vmi);
+
+}
+module_init(init_vmi_clocksource);
diff --git a/arch/i386/kernel/vmitime.c b/arch/i386/kernel/vmitime.c
deleted file mode 100644
index 9dfb17739b6..00000000000
--- a/arch/i386/kernel/vmitime.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * VMI paravirtual timer support routines.
- *
- * Copyright (C) 2005, VMware, Inc.
- *
- * 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, GOOD TITLE or
- * NON INFRINGEMENT. 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.
- *
- * Send feedback to dhecht@vmware.com
- *
- */
-
-/*
- * Portions of this code from arch/i386/kernel/timers/timer_tsc.c.
- * Portions of the CONFIG_NO_IDLE_HZ code from arch/s390/kernel/time.c.
- * See comments there for proper credits.
- */
-
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/rcupdate.h>
-#include <linux/clocksource.h>
-
-#include <asm/timer.h>
-#include <asm/io.h>
-#include <asm/apic.h>
-#include <asm/div64.h>
-#include <asm/timer.h>
-#include <asm/desc.h>
-
-#include <asm/vmi.h>
-#include <asm/vmi_time.h>
-
-#include <mach_timer.h>
-#include <io_ports.h>
-
-#ifdef CONFIG_X86_LOCAL_APIC
-#define VMI_ALARM_WIRING VMI_ALARM_WIRED_LVTT
-#else
-#define VMI_ALARM_WIRING VMI_ALARM_WIRED_IRQ0
-#endif
-
-/* Cached VMI operations */
-struct vmi_timer_ops vmi_timer_ops;
-
-#ifdef CONFIG_NO_IDLE_HZ
-
-/* /proc/sys/kernel/hz_timer state. */
-int sysctl_hz_timer;
-
-/* Some stats */
-static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_irqs);
-static DEFINE_PER_CPU(unsigned long, vmi_idle_no_hz_jiffies);
-static DEFINE_PER_CPU(unsigned long, idle_start_jiffies);
-
-#endif /* CONFIG_NO_IDLE_HZ */
-
-/* Number of alarms per second. By default this is CONFIG_VMI_ALARM_HZ. */
-static int alarm_hz = CONFIG_VMI_ALARM_HZ;
-
-/* Cache of the value get_cycle_frequency / HZ. */
-static signed long long cycles_per_jiffy;
-
-/* Cache of the value get_cycle_frequency / alarm_hz. */
-static signed long long cycles_per_alarm;
-
-/* The number of cycles accounted for by the 'jiffies'/'xtime' count.
- * Protected by xtime_lock. */
-static unsigned long long real_cycles_accounted_system;
-
-/* The number of cycles accounted for by update_process_times(), per cpu. */
-static DEFINE_PER_CPU(unsigned long long, process_times_cycles_accounted_cpu);
-
-/* The number of stolen cycles accounted, per cpu. */
-static DEFINE_PER_CPU(unsigned long long, stolen_cycles_accounted_cpu);
-
-/* Clock source. */
-static cycle_t read_real_cycles(void)
-{
- return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
-}
-
-static cycle_t read_available_cycles(void)
-{
- return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
-}
-
-#if 0
-static cycle_t read_stolen_cycles(void)
-{
- return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_STOLEN);
-}
-#endif /* 0 */
-
-static struct clocksource clocksource_vmi = {
- .name = "vmi-timer",
- .rating = 450,
- .read = read_real_cycles,
- .mask = CLOCKSOURCE_MASK(64),
- .mult = 0, /* to be set */
- .shift = 22,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-
-/* Timer interrupt handler. */
-static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id);
-
-static struct irqaction vmi_timer_irq = {
- .handler = vmi_timer_interrupt,
- .flags = IRQF_DISABLED,
- .mask = CPU_MASK_NONE,
- .name = "VMI-alarm",
-};
-
-/* Alarm rate */
-static int __init vmi_timer_alarm_rate_setup(char* str)
-{
- int alarm_rate;
- if (get_option(&str, &alarm_rate) == 1 && alarm_rate > 0) {
- alarm_hz = alarm_rate;
- printk(KERN_WARNING "VMI timer alarm HZ set to %d\n", alarm_hz);
- }
- return 1;
-}
-__setup("vmi_timer_alarm_hz=", vmi_timer_alarm_rate_setup);
-
-
-/* Initialization */
-static void vmi_get_wallclock_ts(struct timespec *ts)
-{
- unsigned long long wallclock;
- wallclock = vmi_timer_ops.get_wallclock(); // nsec units
- ts->tv_nsec = do_div(wallclock, 1000000000);
- ts->tv_sec = wallclock;
-}
-
-unsigned long vmi_get_wallclock(void)
-{
- struct timespec ts;
- vmi_get_wallclock_ts(&ts);
- return ts.tv_sec;
-}
-
-int vmi_set_wallclock(unsigned long now)
-{
- return -1;
-}
-
-unsigned long long vmi_get_sched_cycles(void)
-{
- return read_available_cycles();
-}
-
-unsigned long vmi_cpu_khz(void)
-{
- unsigned long long khz;
-
- khz = vmi_timer_ops.get_cycle_frequency();
- (void)do_div(khz, 1000);
- return khz;
-}
-
-void __init vmi_time_init(void)
-{
- unsigned long long cycles_per_sec, cycles_per_msec;
- unsigned long flags;
-
- local_irq_save(flags);
- setup_irq(0, &vmi_timer_irq);
-#ifdef CONFIG_X86_LOCAL_APIC
- set_intr_gate(LOCAL_TIMER_VECTOR, apic_vmi_timer_interrupt);
-#endif
-
- real_cycles_accounted_system = read_real_cycles();
- per_cpu(process_times_cycles_accounted_cpu, 0) = read_available_cycles();
-
- cycles_per_sec = vmi_timer_ops.get_cycle_frequency();
- cycles_per_jiffy = cycles_per_sec;
- (void)do_div(cycles_per_jiffy, HZ);
- cycles_per_alarm = cycles_per_sec;
- (void)do_div(cycles_per_alarm, alarm_hz);
- cycles_per_msec = cycles_per_sec;
- (void)do_div(cycles_per_msec, 1000);
-
- printk(KERN_WARNING "VMI timer cycles/sec = %llu ; cycles/jiffy = %llu ;"
- "cycles/alarm = %llu\n", cycles_per_sec, cycles_per_jiffy,
- cycles_per_alarm);
-
- clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
- clocksource_vmi.shift);
- if (clocksource_register(&clocksource_vmi))
- printk(KERN_WARNING "Error registering VMITIME clocksource.");
-
- /* Disable PIT. */
- outb_p(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */
-
- /* schedule the alarm. do this in phase with process_times_cycles_accounted_cpu
- * reduce the latency calling update_process_times. */
- vmi_timer_ops.set_alarm(
- VMI_ALARM_WIRED_IRQ0 | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
- per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm,
- cycles_per_alarm);
-
- local_irq_restore(flags);
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-void __init vmi_timer_setup_boot_alarm(void)
-{
- local_irq_disable();
-
- /* Route the interrupt to the correct vector. */
- apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR);
-
- /* Cancel the IRQ0 wired alarm, and setup the LVTT alarm. */
- vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE);
- vmi_timer_ops.set_alarm(
- VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
- per_cpu(process_times_cycles_accounted_cpu, 0) + cycles_per_alarm,
- cycles_per_alarm);
- local_irq_enable();
-}
-
-/* Initialize the time accounting variables for an AP on an SMP system.
- * Also, set the local alarm for the AP. */
-void __devinit vmi_timer_setup_secondary_alarm(void)
-{
- int cpu = smp_processor_id();
-
- /* Route the interrupt to the correct vector. */
- apic_write_around(APIC_LVTT, LOCAL_TIMER_VECTOR);
-
- per_cpu(process_times_cycles_accounted_cpu, cpu) = read_available_cycles();
-
- vmi_timer_ops.set_alarm(
- VMI_ALARM_WIRED_LVTT | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
- per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm,
- cycles_per_alarm);
-}
-
-#endif
-
-/* Update system wide (real) time accounting (e.g. jiffies, xtime). */
-static void vmi_account_real_cycles(unsigned long long cur_real_cycles)
-{
- long long cycles_not_accounted;
-
- write_seqlock(&xtime_lock);
-
- cycles_not_accounted = cur_real_cycles - real_cycles_accounted_system;
- while (cycles_not_accounted >= cycles_per_jiffy) {
- /* systems wide jiffies. */
- do_timer(1);
-
- cycles_not_accounted -= cycles_per_jiffy;
- real_cycles_accounted_system += cycles_per_jiffy;
- }
-
- write_sequnlock(&xtime_lock);
-}
-
-/* Update per-cpu process times. */
-static void vmi_account_process_times_cycles(struct pt_regs *regs, int cpu,
- unsigned long long cur_process_times_cycles)
-{
- long long cycles_not_accounted;
- cycles_not_accounted = cur_process_times_cycles -
- per_cpu(process_times_cycles_accounted_cpu, cpu);
-
- while (cycles_not_accounted >= cycles_per_jiffy) {
- /* Account time to the current process. This includes
- * calling into the scheduler to decrement the timeslice
- * and possibly reschedule.*/
- update_process_times(user_mode(regs));
- /* XXX handle /proc/profile multiplier. */
- profile_tick(CPU_PROFILING);
-
- cycles_not_accounted -= cycles_per_jiffy;
- per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy;
- }
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-/* Update per-cpu idle times. Used when a no-hz halt is ended. */
-static void vmi_account_no_hz_idle_cycles(int cpu,
- unsigned long long cur_process_times_cycles)
-{
- long long cycles_not_accounted;
- unsigned long no_idle_hz_jiffies = 0;
-
- cycles_not_accounted = cur_process_times_cycles -
- per_cpu(process_times_cycles_accounted_cpu, cpu);
-
- while (cycles_not_accounted >= cycles_per_jiffy) {
- no_idle_hz_jiffies++;
- cycles_not_accounted -= cycles_per_jiffy;
- per_cpu(process_times_cycles_accounted_cpu, cpu) += cycles_per_jiffy;
- }
- /* Account time to the idle process. */
- account_steal_time(idle_task(cpu), jiffies_to_cputime(no_idle_hz_jiffies));
-}
-#endif
-
-/* Update per-cpu stolen time. */
-static void vmi_account_stolen_cycles(int cpu,
- unsigned long long cur_real_cycles,
- unsigned long long cur_avail_cycles)
-{
- long long stolen_cycles_not_accounted;
- unsigned long stolen_jiffies = 0;
-
- if (cur_real_cycles < cur_avail_cycles)
- return;
-
- stolen_cycles_not_accounted = cur_real_cycles - cur_avail_cycles -
- per_cpu(stolen_cycles_accounted_cpu, cpu);
-
- while (stolen_cycles_not_accounted >= cycles_per_jiffy) {
- stolen_jiffies++;
- stolen_cycles_not_accounted -= cycles_per_jiffy;
- per_cpu(stolen_cycles_accounted_cpu, cpu) += cycles_per_jiffy;
- }
- /* HACK: pass NULL to force time onto cpustat->steal. */
- account_steal_time(NULL, jiffies_to_cputime(stolen_jiffies));
-}
-
-/* Body of either IRQ0 interrupt handler (UP no local-APIC) or
- * local-APIC LVTT interrupt handler (UP & local-APIC or SMP). */
-static void vmi_local_timer_interrupt(int cpu)
-{
- unsigned long long cur_real_cycles, cur_process_times_cycles;
-
- cur_real_cycles = read_real_cycles();
- cur_process_times_cycles = read_available_cycles();
- /* Update system wide (real) time state (xtime, jiffies). */
- vmi_account_real_cycles(cur_real_cycles);
- /* Update per-cpu process times. */
- vmi_account_process_times_cycles(get_irq_regs(), cpu, cur_process_times_cycles);
- /* Update time stolen from this cpu by the hypervisor. */
- vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles);
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-
-/* Must be called only from idle loop, with interrupts disabled. */
-int vmi_stop_hz_timer(void)
-{
- /* Note that cpu_set, cpu_clear are (SMP safe) atomic on x86. */
-
- unsigned long seq, next;
- unsigned long long real_cycles_expiry;
- int cpu = smp_processor_id();
-
- BUG_ON(!irqs_disabled());
- if (sysctl_hz_timer != 0)
- return 0;
-
- cpu_set(cpu, nohz_cpu_mask);
- smp_mb();
-
- if (rcu_needs_cpu(cpu) || local_softirq_pending() ||
- (next = next_timer_interrupt(),
- time_before_eq(next, jiffies + HZ/CONFIG_VMI_ALARM_HZ))) {
- cpu_clear(cpu, nohz_cpu_mask);
- return 0;
- }
-
- /* Convert jiffies to the real cycle counter. */
- do {
- seq = read_seqbegin(&xtime_lock);
- real_cycles_expiry = real_cycles_accounted_system +
- (long)(next - jiffies) * cycles_per_jiffy;
- } while (read_seqretry(&xtime_lock, seq));
-
- /* This cpu is going idle. Disable the periodic alarm. */
- vmi_timer_ops.cancel_alarm(VMI_CYCLES_AVAILABLE);
- per_cpu(idle_start_jiffies, cpu) = jiffies;
- /* Set the real time alarm to expire at the next event. */
- vmi_timer_ops.set_alarm(
- VMI_ALARM_WIRING | VMI_ALARM_IS_ONESHOT | VMI_CYCLES_REAL,
- real_cycles_expiry, 0);
- return 1;
-}
-
-static void vmi_reenable_hz_timer(int cpu)
-{
- /* For /proc/vmi/info idle_hz stat. */
- per_cpu(vmi_idle_no_hz_jiffies, cpu) += jiffies - per_cpu(idle_start_jiffies, cpu);
- per_cpu(vmi_idle_no_hz_irqs, cpu)++;
-
- /* Don't bother explicitly cancelling the one-shot alarm -- at
- * worse we will receive a spurious timer interrupt. */
- vmi_timer_ops.set_alarm(
- VMI_ALARM_WIRING | VMI_ALARM_IS_PERIODIC | VMI_CYCLES_AVAILABLE,
- per_cpu(process_times_cycles_accounted_cpu, cpu) + cycles_per_alarm,
- cycles_per_alarm);
- /* Indicate this cpu is no longer nohz idle. */
- cpu_clear(cpu, nohz_cpu_mask);
-}
-
-/* Called from interrupt handlers when (local) HZ timer is disabled. */
-void vmi_account_time_restart_hz_timer(void)
-{
- unsigned long long cur_real_cycles, cur_process_times_cycles;
- int cpu = smp_processor_id();
-
- BUG_ON(!irqs_disabled());
- /* Account the time during which the HZ timer was disabled. */
- cur_real_cycles = read_real_cycles();
- cur_process_times_cycles = read_available_cycles();
- /* Update system wide (real) time state (xtime, jiffies). */
- vmi_account_real_cycles(cur_real_cycles);
- /* Update per-cpu idle times. */
- vmi_account_no_hz_idle_cycles(cpu, cur_process_times_cycles);
- /* Update time stolen from this cpu by the hypervisor. */
- vmi_account_stolen_cycles(cpu, cur_real_cycles, cur_process_times_cycles);
- /* Reenable the hz timer. */
- vmi_reenable_hz_timer(cpu);
-}
-
-#endif /* CONFIG_NO_IDLE_HZ */
-
-/* UP (and no local-APIC) VMI-timer alarm interrupt handler.
- * Handler for IRQ0. Not used when SMP or X86_LOCAL_APIC after
- * APIC setup and setup_boot_vmi_alarm() is called. */
-static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
-{
- vmi_local_timer_interrupt(smp_processor_id());
- return IRQ_HANDLED;
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-
-/* SMP VMI-timer alarm interrupt handler. Handler for LVTT vector.
- * Also used in UP when CONFIG_X86_LOCAL_APIC.
- * The wrapper code is from arch/i386/kernel/apic.c#smp_apic_timer_interrupt. */
-void smp_apic_vmi_timer_interrupt(struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
- int cpu = smp_processor_id();
-
- /*
- * the NMI deadlock-detector uses this.
- */
- per_cpu(irq_stat,cpu).apic_timer_irqs++;
-
- /*
- * NOTE! We'd better ACK the irq immediately,
- * because timer handling can be slow.
- */
- ack_APIC_irq();
-
- /*
- * update_process_times() expects us to have done irq_enter().
- * Besides, if we don't timer interrupts ignore the global
- * interrupt lock, which is the WrongThing (tm) to do.
- */
- irq_enter();
- vmi_local_timer_interrupt(cpu);
- irq_exit();
- set_irq_regs(old_regs);
-}
-
-#endif /* CONFIG_X86_LOCAL_APIC */
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 6f38f818380..23e8614edee 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -26,12 +26,11 @@ OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(phys_startup_32)
jiffies = jiffies_64;
-_proxy_pda = 1;
PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(7); /* RWE */
- note PT_NOTE FLAGS(4); /* R__ */
+ note PT_NOTE FLAGS(0); /* ___ */
}
SECTIONS
{
@@ -61,8 +60,6 @@ SECTIONS
__stop___ex_table = .;
}
- RODATA
-
BUG_TABLE
. = ALIGN(4);
@@ -72,6 +69,8 @@ SECTIONS
__tracedata_end = .;
}
+ RODATA
+
/* writeable */
. = ALIGN(4096);
.data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
@@ -117,22 +116,11 @@ SECTIONS
/* might get freed after init */
. = ALIGN(4096);
- .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
- __smp_alt_begin = .;
- __smp_alt_instructions = .;
- *(.smp_altinstructions)
- __smp_alt_instructions_end = .;
- }
- . = ALIGN(4);
.smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
__smp_locks = .;
*(.smp_locks)
__smp_locks_end = .;
}
- .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
- *(.smp_altinstr_replacement)
- __smp_alt_end = .;
- }
/* will be freed after init
* Following ALIGN() is required to make sure no other data falls on the
* same page where __smp_alt_end is pointing as that page might be freed
@@ -178,9 +166,9 @@ SECTIONS
}
. = ALIGN(4);
.parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
- __start_parainstructions = .;
+ __parainstructions = .;
*(.parainstructions)
- __stop_parainstructions = .;
+ __parainstructions_end = .;
}
/* .exit.text is discard at runtime, not link time, to deal with references
from .altinstructions and .eh_frame */
@@ -194,7 +182,7 @@ SECTIONS
__initramfs_end = .;
}
#endif
- . = ALIGN(L1_CACHE_BYTES);
+ . = ALIGN(4096);
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
__per_cpu_start = .;
*(.data.percpu)
diff --git a/arch/i386/kernel/vsyscall.lds.S b/arch/i386/kernel/vsyscall.lds.S
index f66cd11adb7..4a8b0ed9b8f 100644
--- a/arch/i386/kernel/vsyscall.lds.S
+++ b/arch/i386/kernel/vsyscall.lds.S
@@ -7,7 +7,7 @@
SECTIONS
{
- . = VDSO_PRELINK + SIZEOF_HEADERS;
+ . = VDSO_PRELINK_asm + SIZEOF_HEADERS;
.hash : { *(.hash) } :text
.gnu.hash : { *(.gnu.hash) }
@@ -21,7 +21,7 @@ SECTIONS
For the layouts to match, we need to skip more than enough
space for the dynamic symbol table et al. If this amount
is insufficient, ld -shared will barf. Just increase it here. */
- . = VDSO_PRELINK + 0x400;
+ . = VDSO_PRELINK_asm + 0x400;
.text : { *(.text) } :text =0x90909090
.note : { *(.note.*) } :text :note
diff --git a/arch/i386/lib/bitops.c b/arch/i386/lib/bitops.c
index 97db3853dc8..afd0045595d 100644
--- a/arch/i386/lib/bitops.c
+++ b/arch/i386/lib/bitops.c
@@ -43,7 +43,7 @@ EXPORT_SYMBOL(find_next_bit);
*/
int find_next_zero_bit(const unsigned long *addr, int size, int offset)
{
- unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+ const unsigned long *p = addr + (offset >> 5);
int set = 0, bit = offset & 31, res;
if (bit) {
@@ -64,7 +64,7 @@ int find_next_zero_bit(const unsigned long *addr, int size, int offset)
/*
* No zero yet, search remaining full bytes for a zero
*/
- res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
+ res = find_first_zero_bit(p, size - 32 * (p - addr));
return (offset + set + res);
}
EXPORT_SYMBOL(find_next_zero_bit);
diff --git a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S
index 75ffd02654f..adbccd0bbb7 100644
--- a/arch/i386/lib/checksum.S
+++ b/arch/i386/lib/checksum.S
@@ -25,6 +25,8 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
#include <asm/errno.h>
/*
@@ -36,8 +38,6 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
*/
.text
-.align 4
-.globl csum_partial
#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
@@ -48,9 +48,14 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
* Fortunately, it is easy to convert 2-byte alignment to 4-byte
* alignment for the unrolled loop.
*/
-csum_partial:
+ENTRY(csum_partial)
+ CFI_STARTPROC
pushl %esi
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET esi, 0
pushl %ebx
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET ebx, 0
movl 20(%esp),%eax # Function arg: unsigned int sum
movl 16(%esp),%ecx # Function arg: int len
movl 12(%esp),%esi # Function arg: unsigned char *buff
@@ -128,16 +133,27 @@ csum_partial:
roll $8, %eax
8:
popl %ebx
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE ebx
popl %esi
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE esi
ret
+ CFI_ENDPROC
+ENDPROC(csum_partial)
#else
/* Version for PentiumII/PPro */
-csum_partial:
+ENTRY(csum_partial)
+ CFI_STARTPROC
pushl %esi
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET esi, 0
pushl %ebx
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET ebx, 0
movl 20(%esp),%eax # Function arg: unsigned int sum
movl 16(%esp),%ecx # Function arg: int len
movl 12(%esp),%esi # Function arg: const unsigned char *buf
@@ -245,8 +261,14 @@ csum_partial:
roll $8, %eax
90:
popl %ebx
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE ebx
popl %esi
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE esi
ret
+ CFI_ENDPROC
+ENDPROC(csum_partial)
#endif
@@ -278,19 +300,24 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
.long 9999b, 6002f ; \
.previous
-.align 4
-.globl csum_partial_copy_generic
-
#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
#define ARGBASE 16
#define FP 12
-csum_partial_copy_generic:
+ENTRY(csum_partial_copy_generic)
+ CFI_STARTPROC
subl $4,%esp
+ CFI_ADJUST_CFA_OFFSET 4
pushl %edi
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET edi, 0
pushl %esi
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET esi, 0
pushl %ebx
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET ebx, 0
movl ARGBASE+16(%esp),%eax # sum
movl ARGBASE+12(%esp),%ecx # len
movl ARGBASE+4(%esp),%esi # src
@@ -400,10 +427,19 @@ DST( movb %cl, (%edi) )
.previous
popl %ebx
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE ebx
popl %esi
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE esi
popl %edi
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE edi
popl %ecx # equivalent to addl $4,%esp
+ CFI_ADJUST_CFA_OFFSET -4
ret
+ CFI_ENDPROC
+ENDPROC(csum_partial_copy_generic)
#else
@@ -421,10 +457,17 @@ DST( movb %cl, (%edi) )
#define ARGBASE 12
-csum_partial_copy_generic:
+ENTRY(csum_partial_copy_generic)
+ CFI_STARTPROC
pushl %ebx
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET ebx, 0
pushl %edi
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET edi, 0
pushl %esi
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET esi, 0
movl ARGBASE+4(%esp),%esi #src
movl ARGBASE+8(%esp),%edi #dst
movl ARGBASE+12(%esp),%ecx #len
@@ -485,9 +528,17 @@ DST( movb %dl, (%edi) )
.previous
popl %esi
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE esi
popl %edi
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE edi
popl %ebx
+ CFI_ADJUST_CFA_OFFSET -4
+ CFI_RESTORE ebx
ret
+ CFI_ENDPROC
+ENDPROC(csum_partial_copy_generic)
#undef ROUND
#undef ROUND1
diff --git a/arch/i386/lib/getuser.S b/arch/i386/lib/getuser.S
index 62d7f178a32..6d84b53f12a 100644
--- a/arch/i386/lib/getuser.S
+++ b/arch/i386/lib/getuser.S
@@ -8,6 +8,8 @@
* return an error value in addition to the "real"
* return value.
*/
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
#include <asm/thread_info.h>
@@ -24,19 +26,19 @@
*/
.text
-.align 4
-.globl __get_user_1
-__get_user_1:
+ENTRY(__get_user_1)
+ CFI_STARTPROC
GET_THREAD_INFO(%edx)
cmpl TI_addr_limit(%edx),%eax
jae bad_get_user
1: movzbl (%eax),%edx
xorl %eax,%eax
ret
+ CFI_ENDPROC
+ENDPROC(__get_user_1)
-.align 4
-.globl __get_user_2
-__get_user_2:
+ENTRY(__get_user_2)
+ CFI_STARTPROC
addl $1,%eax
jc bad_get_user
GET_THREAD_INFO(%edx)
@@ -45,10 +47,11 @@ __get_user_2:
2: movzwl -1(%eax),%edx
xorl %eax,%eax
ret
+ CFI_ENDPROC
+ENDPROC(__get_user_2)
-.align 4
-.globl __get_user_4
-__get_user_4:
+ENTRY(__get_user_4)
+ CFI_STARTPROC
addl $3,%eax
jc bad_get_user
GET_THREAD_INFO(%edx)
@@ -57,11 +60,16 @@ __get_user_4:
3: movl -3(%eax),%edx
xorl %eax,%eax
ret
+ CFI_ENDPROC
+ENDPROC(__get_user_4)
bad_get_user:
+ CFI_STARTPROC
xorl %edx,%edx
movl $-14,%eax
ret
+ CFI_ENDPROC
+END(bad_get_user)
.section __ex_table,"a"
.long 1b,bad_get_user
diff --git a/arch/i386/lib/msr-on-cpu.c b/arch/i386/lib/msr-on-cpu.c
index 1c46bda409f..7767962f25d 100644
--- a/arch/i386/lib/msr-on-cpu.c
+++ b/arch/i386/lib/msr-on-cpu.c
@@ -6,6 +6,7 @@
struct msr_info {
u32 msr_no;
u32 l, h;
+ int err;
};
static void __rdmsr_on_cpu(void *info)
@@ -15,20 +16,38 @@ static void __rdmsr_on_cpu(void *info)
rdmsr(rv->msr_no, rv->l, rv->h);
}
-void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+static void __rdmsr_safe_on_cpu(void *info)
{
+ struct msr_info *rv = info;
+
+ rv->err = rdmsr_safe(rv->msr_no, &rv->l, &rv->h);
+}
+
+static int _rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h, int safe)
+{
+ int err = 0;
preempt_disable();
if (smp_processor_id() == cpu)
- rdmsr(msr_no, *l, *h);
+ if (safe)
+ err = rdmsr_safe(msr_no, l, h);
+ else
+ rdmsr(msr_no, *l, *h);
else {
struct msr_info rv;
rv.msr_no = msr_no;
- smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1);
+ if (safe) {
+ smp_call_function_single(cpu, __rdmsr_safe_on_cpu,
+ &rv, 0, 1);
+ err = rv.err;
+ } else {
+ smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 0, 1);
+ }
*l = rv.l;
*h = rv.h;
}
preempt_enable();
+ return err;
}
static void __wrmsr_on_cpu(void *info)
@@ -38,21 +57,63 @@ static void __wrmsr_on_cpu(void *info)
wrmsr(rv->msr_no, rv->l, rv->h);
}
-void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+static void __wrmsr_safe_on_cpu(void *info)
{
+ struct msr_info *rv = info;
+
+ rv->err = wrmsr_safe(rv->msr_no, rv->l, rv->h);
+}
+
+static int _wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h, int safe)
+{
+ int err = 0;
preempt_disable();
if (smp_processor_id() == cpu)
- wrmsr(msr_no, l, h);
+ if (safe)
+ err = wrmsr_safe(msr_no, l, h);
+ else
+ wrmsr(msr_no, l, h);
else {
struct msr_info rv;
rv.msr_no = msr_no;
rv.l = l;
rv.h = h;
- smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1);
+ if (safe) {
+ smp_call_function_single(cpu, __wrmsr_safe_on_cpu,
+ &rv, 0, 1);
+ err = rv.err;
+ } else {
+ smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 0, 1);
+ }
}
preempt_enable();
+ return err;
+}
+
+void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+ _wrmsr_on_cpu(cpu, msr_no, l, h, 0);
+}
+
+void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+ _rdmsr_on_cpu(cpu, msr_no, l, h, 0);
+}
+
+/* These "safe" variants are slower and should be used when the target MSR
+ may not actually exist. */
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+ return _wrmsr_on_cpu(cpu, msr_no, l, h, 1);
+}
+
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+ return _rdmsr_on_cpu(cpu, msr_no, l, h, 1);
}
EXPORT_SYMBOL(rdmsr_on_cpu);
EXPORT_SYMBOL(wrmsr_on_cpu);
+EXPORT_SYMBOL(rdmsr_safe_on_cpu);
+EXPORT_SYMBOL(wrmsr_safe_on_cpu);
diff --git a/arch/i386/lib/putuser.S b/arch/i386/lib/putuser.S
index a32d9f570f4..f58fba109d1 100644
--- a/arch/i386/lib/putuser.S
+++ b/arch/i386/lib/putuser.S
@@ -8,6 +8,8 @@
* return an error value in addition to the "real"
* return value.
*/
+#include <linux/linkage.h>
+#include <asm/dwarf2.h>
#include <asm/thread_info.h>
@@ -23,23 +25,28 @@
* as they get called from within inline assembly.
*/
-#define ENTER pushl %ebx ; GET_THREAD_INFO(%ebx)
-#define EXIT popl %ebx ; ret
+#define ENTER CFI_STARTPROC ; \
+ pushl %ebx ; \
+ CFI_ADJUST_CFA_OFFSET 4 ; \
+ CFI_REL_OFFSET ebx, 0 ; \
+ GET_THREAD_INFO(%ebx)
+#define EXIT popl %ebx ; \
+ CFI_ADJUST_CFA_OFFSET -4 ; \
+ CFI_RESTORE ebx ; \
+ ret ; \
+ CFI_ENDPROC
.text
-.align 4
-.globl __put_user_1
-__put_user_1:
+ENTRY(__put_user_1)
ENTER
cmpl TI_addr_limit(%ebx),%ecx
jae bad_put_user
1: movb %al,(%ecx)
xorl %eax,%eax
EXIT
+ENDPROC(__put_user_1)
-.align 4
-.globl __put_user_2
-__put_user_2:
+ENTRY(__put_user_2)
ENTER
movl TI_addr_limit(%ebx),%ebx
subl $1,%ebx
@@ -48,10 +55,9 @@ __put_user_2:
2: movw %ax,(%ecx)
xorl %eax,%eax
EXIT
+ENDPROC(__put_user_2)
-.align 4
-.globl __put_user_4
-__put_user_4:
+ENTRY(__put_user_4)
ENTER
movl TI_addr_limit(%ebx),%ebx
subl $3,%ebx
@@ -60,10 +66,9 @@ __put_user_4:
3: movl %eax,(%ecx)
xorl %eax,%eax
EXIT
+ENDPROC(__put_user_4)
-.align 4
-.globl __put_user_8
-__put_user_8:
+ENTRY(__put_user_8)
ENTER
movl TI_addr_limit(%ebx),%ebx
subl $7,%ebx
@@ -73,10 +78,16 @@ __put_user_8:
5: movl %edx,4(%ecx)
xorl %eax,%eax
EXIT
+ENDPROC(__put_user_8)
bad_put_user:
+ CFI_STARTPROC simple
+ CFI_DEF_CFA esp, 2*4
+ CFI_OFFSET eip, -1*4
+ CFI_OFFSET ebx, -2*4
movl $-14,%eax
EXIT
+END(bad_put_user)
.section __ex_table,"a"
.long 1b,bad_put_user
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index 086b3726862..9f38b12b4af 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -716,7 +716,6 @@ do { \
unsigned long __copy_to_user_ll(void __user *to, const void *from,
unsigned long n)
{
- BUG_ON((long) n < 0);
#ifndef CONFIG_X86_WP_WORKS_OK
if (unlikely(boot_cpu_data.wp_works_ok == 0) &&
((unsigned long )to) < TASK_SIZE) {
@@ -785,7 +784,6 @@ EXPORT_SYMBOL(__copy_to_user_ll);
unsigned long __copy_from_user_ll(void *to, const void __user *from,
unsigned long n)
{
- BUG_ON((long)n < 0);
if (movsl_is_ok(to, from, n))
__copy_user_zeroing(to, from, n);
else
@@ -797,7 +795,6 @@ EXPORT_SYMBOL(__copy_from_user_ll);
unsigned long __copy_from_user_ll_nozero(void *to, const void __user *from,
unsigned long n)
{
- BUG_ON((long)n < 0);
if (movsl_is_ok(to, from, n))
__copy_user(to, from, n);
else
@@ -810,7 +807,6 @@ EXPORT_SYMBOL(__copy_from_user_ll_nozero);
unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
unsigned long n)
{
- BUG_ON((long)n < 0);
#ifdef CONFIG_X86_INTEL_USERCOPY
if ( n > 64 && cpu_has_xmm2)
n = __copy_user_zeroing_intel_nocache(to, from, n);
@@ -825,7 +821,6 @@ unsigned long __copy_from_user_ll_nocache(void *to, const void __user *from,
unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *from,
unsigned long n)
{
- BUG_ON((long)n < 0);
#ifdef CONFIG_X86_INTEL_USERCOPY
if ( n > 64 && cpu_has_xmm2)
n = __copy_user_intel_nocache(to, from, n);
@@ -853,7 +848,6 @@ unsigned long __copy_from_user_ll_nocache_nozero(void *to, const void __user *fr
unsigned long
copy_to_user(void __user *to, const void *from, unsigned long n)
{
- BUG_ON((long) n < 0);
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
return n;
@@ -879,7 +873,6 @@ EXPORT_SYMBOL(copy_to_user);
unsigned long
copy_from_user(void *to, const void __user *from, unsigned long n)
{
- BUG_ON((long) n < 0);
if (access_ok(VERIFY_READ, from, n))
n = __copy_from_user(to, from, n);
else
diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
index c7881621070..7f635c7a238 100644
--- a/arch/i386/mach-default/setup.c
+++ b/arch/i386/mach-default/setup.c
@@ -81,7 +81,7 @@ void __init trap_init_hook(void)
static struct irqaction irq0 = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_NOBALANCING,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
.name = "timer"
};
diff --git a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
index 8a210fa915b..e932d3485ae 100644
--- a/arch/i386/mach-generic/bigsmp.c
+++ b/arch/i386/mach-generic/bigsmp.c
@@ -45,7 +45,7 @@ static struct dmi_system_id __initdata bigsmp_dmi_table[] = {
};
-static int probe_bigsmp(void)
+static int __init probe_bigsmp(void)
{
if (def_to_bigsmp)
dmi_bigsmp = 1;
diff --git a/arch/i386/mach-generic/es7000.c b/arch/i386/mach-generic/es7000.c
index b8963a5a3b2..b47f951c0ec 100644
--- a/arch/i386/mach-generic/es7000.c
+++ b/arch/i386/mach-generic/es7000.c
@@ -25,4 +25,45 @@ static int probe_es7000(void)
return 0;
}
+extern void es7000_sw_apic(void);
+static void __init enable_apic_mode(void)
+{
+ es7000_sw_apic();
+ return;
+}
+
+static __init int mps_oem_check(struct mp_config_table *mpc, char *oem,
+ char *productid)
+{
+ if (mpc->mpc_oemptr) {
+ struct mp_config_oemtable *oem_table =
+ (struct mp_config_oemtable *)mpc->mpc_oemptr;
+ if (!strncmp(oem, "UNISYS", 6))
+ return parse_unisys_oem((char *)oem_table);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_ACPI
+/* Hook from generic ACPI tables.c */
+static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+ unsigned long oem_addr;
+ if (!find_unisys_acpi_oem_table(&oem_addr)) {
+ if (es7000_check_dsdt())
+ return parse_unisys_oem((char *)oem_addr);
+ else {
+ setup_unisys();
+ return 1;
+ }
+ }
+ return 0;
+}
+#else
+static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+ return 0;
+}
+#endif
+
struct genapic apic_es7000 = APIC_INIT("es7000", probe_es7000);
diff --git a/arch/i386/mach-generic/probe.c b/arch/i386/mach-generic/probe.c
index a7b3999bb37..74f3da63442 100644
--- a/arch/i386/mach-generic/probe.c
+++ b/arch/i386/mach-generic/probe.c
@@ -119,9 +119,7 @@ int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
return 0;
}
-#ifdef CONFIG_SMP
int hard_smp_processor_id(void)
{
return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID));
}
-#endif
diff --git a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c
index 233ee20907b..1f81f10e03a 100644
--- a/arch/i386/mach-visws/setup.c
+++ b/arch/i386/mach-visws/setup.c
@@ -116,7 +116,7 @@ void __init pre_setup_arch_hook()
static struct irqaction irq0 = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_IRQPOLL,
.name = "timer",
};
diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c
index 38c2b13124d..710faf71a65 100644
--- a/arch/i386/mach-visws/visws_apic.c
+++ b/arch/i386/mach-visws/visws_apic.c
@@ -18,7 +18,6 @@
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/io.h>
diff --git a/arch/i386/mach-voyager/setup.c b/arch/i386/mach-voyager/setup.c
index cfa16c151c8..2b55694e640 100644
--- a/arch/i386/mach-voyager/setup.c
+++ b/arch/i386/mach-voyager/setup.c
@@ -40,10 +40,16 @@ void __init trap_init_hook(void)
{
}
-static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL};
+static struct irqaction irq0 = {
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
+ .mask = CPU_MASK_NONE,
+ .name = "timer"
+};
void __init time_init_hook(void)
{
+ irq0.mask = cpumask_of_cpu(safe_smp_processor_id());
setup_irq(0, &irq0);
}
diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c
index 8fe7e4593d5..9b77b39b71a 100644
--- a/arch/i386/mach-voyager/voyager_basic.c
+++ b/arch/i386/mach-voyager/voyager_basic.c
@@ -292,8 +292,8 @@ machine_emergency_restart(void)
void
mca_nmi_hook(void)
{
- __u8 dumpval __attribute__((unused)) = inb(0xf823);
- __u8 swnmi __attribute__((unused)) = inb(0xf813);
+ __u8 dumpval __maybe_unused = inb(0xf823);
+ __u8 swnmi __maybe_unused = inb(0xf813);
/* FIXME: assume dump switch pressed */
/* check to see if the dump switch was pressed */
diff --git a/arch/i386/mach-voyager/voyager_cat.c b/arch/i386/mach-voyager/voyager_cat.c
index 943a9473b13..26a2d4c54b6 100644
--- a/arch/i386/mach-voyager/voyager_cat.c
+++ b/arch/i386/mach-voyager/voyager_cat.c
@@ -1111,7 +1111,7 @@ voyager_cat_do_common_interrupt(void)
printk(KERN_ERR "Voyager front panel switch turned off\n");
voyager_status.switch_off = 1;
voyager_status.request_from_kernel = 1;
- up(&kvoyagerd_sem);
+ wake_up_process(voyager_thread);
}
/* Tell the hardware we're taking care of the
* shutdown, otherwise it will power the box off
@@ -1157,7 +1157,7 @@ voyager_cat_do_common_interrupt(void)
outb(VOYAGER_CAT_END, CAT_CMD);
voyager_status.power_fail = 1;
voyager_status.request_from_kernel = 1;
- up(&kvoyagerd_sem);
+ wake_up_process(voyager_thread);
}
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index 74aeedf277f..50d9c52070b 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -16,7 +16,6 @@
#include <linux/mc146818rtc.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/bootmem.h>
@@ -536,15 +535,6 @@ do_boot_cpu(__u8 cpu)
& ~( voyager_extended_vic_processors
& voyager_allowed_boot_processors);
- /* For the 486, we can't use the 4Mb page table trick, so
- * must map a region of memory */
-#ifdef CONFIG_M486
- int i;
- unsigned long *page_table_copies = (unsigned long *)
- __get_free_page(GFP_KERNEL);
-#endif
- pgd_t orig_swapper_pg_dir0;
-
/* This is an area in head.S which was used to set up the
* initial kernel stack. We need to alter this to give the
* booting CPU a new stack (taken from its idle process) */
@@ -573,6 +563,8 @@ do_boot_cpu(__u8 cpu)
hijack_source.idt.Segment = (start_phys_address >> 4) & 0xFFFF;
cpucount++;
+ alternatives_smp_switch(1);
+
idle = fork_idle(cpu);
if(IS_ERR(idle))
panic("failed fork for CPU%d", cpu);
@@ -580,39 +572,18 @@ do_boot_cpu(__u8 cpu)
/* init_tasks (in sched.c) is indexed logically */
stack_start.esp = (void *) idle->thread.esp;
- /* Pre-allocate and initialize the CPU's GDT and PDA so it
- doesn't have to do any memory allocation during the
- delicate CPU-bringup phase. */
- if (!init_gdt(cpu, idle)) {
- printk(KERN_INFO "Couldn't allocate GDT/PDA for CPU %d\n", cpu);
- cpucount--;
- return;
- }
-
+ init_gdt(cpu, idle);
irq_ctx_init(cpu);
/* Note: Don't modify initial ss override */
VDEBUG(("VOYAGER SMP: Booting CPU%d at 0x%lx[%x:%x], stack %p\n", cpu,
(unsigned long)hijack_source.val, hijack_source.idt.Segment,
hijack_source.idt.Offset, stack_start.esp));
- /* set the original swapper_pg_dir[0] to map 0 to 4Mb transparently
- * (so that the booting CPU can find start_32 */
- orig_swapper_pg_dir0 = swapper_pg_dir[0];
-#ifdef CONFIG_M486
- if(page_table_copies == NULL)
- panic("No free memory for 486 page tables\n");
- for(i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++)
- page_table_copies[i] = (i * PAGE_SIZE)
- | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-
- ((unsigned long *)swapper_pg_dir)[0] =
- ((virt_to_phys(page_table_copies)) & PAGE_MASK)
- | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-#else
- ((unsigned long *)swapper_pg_dir)[0] =
- (virt_to_phys(pg0) & PAGE_MASK)
- | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT;
-#endif
+
+ /* init lowmem identity mapping */
+ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS));
+ flush_tlb_all();
if(quad_boot) {
printk("CPU %d: non extended Quad boot\n", cpu);
@@ -655,11 +626,7 @@ do_boot_cpu(__u8 cpu)
udelay(100);
}
/* reset the page table */
- swapper_pg_dir[0] = orig_swapper_pg_dir0;
- local_flush_tlb();
-#ifdef CONFIG_M486
- free_page((unsigned long)page_table_copies);
-#endif
+ zap_low_mappings();
if (cpu_booted_map) {
VDEBUG(("CPU%d: Booted successfully, back in CPU %d\n",
@@ -773,12 +740,6 @@ initialize_secondary(void)
#endif
/*
- * switch to the per CPU GDT we already set up
- * in do_boot_cpu()
- */
- cpu_set_gdt(current_thread_info()->cpu);
-
- /*
* We don't actually need to load the full TSS,
* basically just the stack pointer and the eip.
*/
@@ -1082,20 +1043,11 @@ smp_call_function_interrupt(void)
}
}
-/* Call this function on all CPUs using the function_interrupt above
- <func> The function to run. This must be fast and non-blocking.
- <info> An arbitrary pointer to pass to the function.
- <retry> If true, keep retrying until ready.
- <wait> If true, wait until function has completed on other CPUs.
- [RETURNS] 0 on success, else a negative status code. Does not return until
- remote CPUs are nearly ready to execute <<func>> or are or have executed.
-*/
-int
-smp_call_function (void (*func) (void *info), void *info, int retry,
- int wait)
+static int
+__smp_call_function_mask (void (*func) (void *info), void *info, int retry,
+ int wait, __u32 mask)
{
struct call_data_struct data;
- __u32 mask = cpus_addr(cpu_online_map)[0];
mask &= ~(1<<smp_processor_id());
@@ -1116,7 +1068,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
call_data = &data;
wmb();
/* Send a message to all other CPUs and wait for them to respond */
- send_CPI_allbutself(VIC_CALL_FUNCTION_CPI);
+ send_CPI(mask, VIC_CALL_FUNCTION_CPI);
/* Wait for response */
while (data.started)
@@ -1130,8 +1082,48 @@ smp_call_function (void (*func) (void *info), void *info, int retry,
return 0;
}
+
+/* Call this function on all CPUs using the function_interrupt above
+ <func> The function to run. This must be fast and non-blocking.
+ <info> An arbitrary pointer to pass to the function.
+ <retry> If true, keep retrying until ready.
+ <wait> If true, wait until function has completed on other CPUs.
+ [RETURNS] 0 on success, else a negative status code. Does not return until
+ remote CPUs are nearly ready to execute <<func>> or are or have executed.
+*/
+int
+smp_call_function(void (*func) (void *info), void *info, int retry,
+ int wait)
+{
+ __u32 mask = cpus_addr(cpu_online_map)[0];
+
+ return __smp_call_function_mask(func, info, retry, wait, mask);
+}
EXPORT_SYMBOL(smp_call_function);
+/*
+ * smp_call_function_single - Run a function on another CPU
+ * @func: The function to run. This must be fast and non-blocking.
+ * @info: An arbitrary pointer to pass to the function.
+ * @nonatomic: Currently unused.
+ * @wait: If true, wait until function has completed on other CPUs.
+ *
+ * Retrurns 0 on success, else a negative status code.
+ *
+ * Does not return until the remote CPU is nearly ready to execute <func>
+ * or is or has executed.
+ */
+
+int
+smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ int nonatomic, int wait)
+{
+ __u32 mask = 1 << cpu;
+
+ return __smp_call_function_mask(func, info, nonatomic, wait, mask);
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
/* Sorry about the name. In an APIC based system, the APICs
* themselves are programmed to send a timer interrupt. This is used
* by linux to reschedule the processor. Voyager doesn't have this,
diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c
index f39887359e8..b4b24e0e45e 100644
--- a/arch/i386/mach-voyager/voyager_thread.c
+++ b/arch/i386/mach-voyager/voyager_thread.c
@@ -18,39 +18,21 @@
#include <linux/kernel_stat.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/kmod.h>
#include <linux/completion.h>
#include <linux/sched.h>
+#include <linux/kthread.h>
#include <asm/desc.h>
#include <asm/voyager.h>
#include <asm/vic.h>
#include <asm/mtrr.h>
#include <asm/msr.h>
-#define THREAD_NAME "kvoyagerd"
-/* external variables */
-int kvoyagerd_running = 0;
-DECLARE_MUTEX_LOCKED(kvoyagerd_sem);
-
-static int thread(void *);
-
-static __u8 set_timeout = 0;
-
-/* Start the machine monitor thread. Return 1 if OK, 0 if fail */
-static int __init
-voyager_thread_start(void)
-{
- if(kernel_thread(thread, NULL, CLONE_KERNEL) < 0) {
- /* This is serious, but not fatal */
- printk(KERN_ERR "Voyager: Failed to create system monitor thread!!!\n");
- return 1;
- }
- return 0;
-}
+struct task_struct *voyager_thread;
+static __u8 set_timeout;
static int
execute(const char *string)
@@ -110,31 +92,15 @@ check_continuing_condition(void)
}
}
-static void
-wakeup(unsigned long unused)
-{
- up(&kvoyagerd_sem);
-}
-
static int
thread(void *unused)
{
- struct timer_list wakeup_timer;
-
- kvoyagerd_running = 1;
-
- daemonize(THREAD_NAME);
-
- set_timeout = 0;
-
- init_timer(&wakeup_timer);
-
- sigfillset(&current->blocked);
-
printk(KERN_NOTICE "Voyager starting monitor thread\n");
- for(;;) {
- down_interruptible(&kvoyagerd_sem);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(set_timeout ? HZ : MAX_SCHEDULE_TIMEOUT);
+
VDEBUG(("Voyager Daemon awoken\n"));
if(voyager_status.request_from_kernel == 0) {
/* probably awoken from timeout */
@@ -143,20 +109,26 @@ thread(void *unused)
check_from_kernel();
voyager_status.request_from_kernel = 0;
}
- if(set_timeout) {
- del_timer(&wakeup_timer);
- wakeup_timer.expires = HZ + jiffies;
- wakeup_timer.function = wakeup;
- add_timer(&wakeup_timer);
- }
}
}
+static int __init
+voyager_thread_start(void)
+{
+ voyager_thread = kthread_run(thread, NULL, "kvoyagerd");
+ if (IS_ERR(voyager_thread)) {
+ printk(KERN_ERR "Voyager: Failed to create system monitor thread.\n");
+ return PTR_ERR(voyager_thread);
+ }
+ return 0;
+}
+
+
static void __exit
voyager_thread_stop(void)
{
- /* FIXME: do nothing at the moment */
+ kthread_stop(voyager_thread);
}
module_init(voyager_thread_start);
-//module_exit(voyager_thread_stop);
+module_exit(voyager_thread_stop);
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index b8c4e259fc8..29d7d61543a 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -14,19 +14,20 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/highmem.h>
+#include <linux/bootmem.h> /* for max_low_pfn */
+#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/desc.h>
-#include <asm/kdebug.h>
#include <asm/segment.h>
extern void die(const char *,struct pt_regs *,long);
@@ -301,7 +302,6 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
struct mm_struct *mm;
struct vm_area_struct * vma;
unsigned long address;
- unsigned long page;
int write, si_code;
/* get the address */
@@ -510,7 +510,9 @@ no_context:
bust_spinlocks(1);
if (oops_may_print()) {
- #ifdef CONFIG_X86_PAE
+ __typeof__(pte_val(__pte(0))) page;
+
+#ifdef CONFIG_X86_PAE
if (error_code & 16) {
pte_t *pte = lookup_address(address);
@@ -519,7 +521,7 @@ no_context:
"NX-protected page - exploit attempt? "
"(uid: %d)\n", current->uid);
}
- #endif
+#endif
if (address < PAGE_SIZE)
printk(KERN_ALERT "BUG: unable to handle kernel NULL "
"pointer dereference");
@@ -529,25 +531,38 @@ no_context:
printk(" at virtual address %08lx\n",address);
printk(KERN_ALERT " printing eip:\n");
printk("%08lx\n", regs->eip);
- }
- page = read_cr3();
- page = ((unsigned long *) __va(page))[address >> 22];
- if (oops_may_print())
+
+ page = read_cr3();
+ page = ((__typeof__(page) *) __va(page))[address >> PGDIR_SHIFT];
+#ifdef CONFIG_X86_PAE
+ printk(KERN_ALERT "*pdpt = %016Lx\n", page);
+ if ((page >> PAGE_SHIFT) < max_low_pfn
+ && page & _PAGE_PRESENT) {
+ page &= PAGE_MASK;
+ page = ((__typeof__(page) *) __va(page))[(address >> PMD_SHIFT)
+ & (PTRS_PER_PMD - 1)];
+ printk(KERN_ALERT "*pde = %016Lx\n", page);
+ page &= ~_PAGE_NX;
+ }
+#else
printk(KERN_ALERT "*pde = %08lx\n", page);
- /*
- * We must not directly access the pte in the highpte
- * case, the page table might be allocated in highmem.
- * And lets rather not kmap-atomic the pte, just in case
- * it's allocated already.
- */
-#ifndef CONFIG_HIGHPTE
- if ((page & 1) && oops_may_print()) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
- }
#endif
+
+ /*
+ * We must not directly access the pte in the highpte
+ * case if the page table is located in highmem.
+ * And let's rather not kmap-atomic the pte, just in case
+ * it's allocated already.
+ */
+ if ((page >> PAGE_SHIFT) < max_low_pfn
+ && (page & _PAGE_PRESENT)) {
+ page &= PAGE_MASK;
+ page = ((__typeof__(page) *) __va(page))[(address >> PAGE_SHIFT)
+ & (PTRS_PER_PTE - 1)];
+ printk(KERN_ALERT "*pte = %0*Lx\n", sizeof(page)*2, (u64)page);
+ }
+ }
+
tsk->thread.cr2 = address;
tsk->thread.trap_no = 14;
tsk->thread.error_code = error_code;
@@ -588,7 +603,6 @@ do_sigbus:
force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
}
-#ifndef CONFIG_X86_PAE
void vmalloc_sync_all(void)
{
/*
@@ -601,6 +615,9 @@ void vmalloc_sync_all(void)
static unsigned long start = TASK_SIZE;
unsigned long address;
+ if (SHARED_KERNEL_PMD)
+ return;
+
BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
if (!test_bit(pgd_index(address), insync)) {
@@ -623,4 +640,3 @@ void vmalloc_sync_all(void)
start = address + PGDIR_SIZE;
}
}
-#endif
diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
index ac70d09df7e..ad8d86cc683 100644
--- a/arch/i386/mm/highmem.c
+++ b/arch/i386/mm/highmem.c
@@ -26,7 +26,7 @@ void kunmap(struct page *page)
* However when holding an atomic kmap is is not legal to sleep, so atomic
* kmaps are appropriate for short, tight code paths only.
*/
-void *kmap_atomic(struct page *page, enum km_type type)
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
{
enum fixed_addresses idx;
unsigned long vaddr;
@@ -41,12 +41,17 @@ void *kmap_atomic(struct page *page, enum km_type type)
return page_address(page);
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
+ set_pte(kmap_pte-idx, mk_pte(page, prot));
arch_flush_lazy_mmu_mode();
return (void*) vaddr;
}
+void *kmap_atomic(struct page *page, enum km_type type)
+{
+ return kmap_atomic_prot(page, type, kmap_prot);
+}
+
void kunmap_atomic(void *kvaddr, enum km_type type)
{
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
@@ -67,6 +72,7 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
#endif
}
+ arch_flush_lazy_mmu_mode();
pagefault_enable();
}
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
index 34728e4afe4..efdf95ac803 100644
--- a/arch/i386/mm/hugetlbpage.c
+++ b/arch/i386/mm/hugetlbpage.c
@@ -9,7 +9,6 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sysctl.h>
@@ -367,6 +366,12 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
if (len > TASK_SIZE)
return -ENOMEM;
+ if (flags & MAP_FIXED) {
+ if (prepare_hugepage_range(addr, len, pgoff))
+ return -EINVAL;
+ return addr;
+ }
+
if (addr) {
addr = ALIGN(addr, HPAGE_SIZE);
vma = find_vma(mm, addr);
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index ae436882af7..c50782efa5c 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -22,6 +22,7 @@
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
+#include <linux/pfn.h>
#include <linux/poison.h>
#include <linux/bootmem.h>
#include <linux/slab.h>
@@ -42,6 +43,7 @@
#include <asm/tlb.h>
#include <asm/tlbflush.h>
#include <asm/sections.h>
+#include <asm/paravirt.h>
unsigned int __VMALLOC_RESERVE = 128 << 20;
@@ -61,17 +63,18 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
pmd_t *pmd_table;
#ifdef CONFIG_X86_PAE
- pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT);
- set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
- pud = pud_offset(pgd, 0);
- if (pmd_table != pmd_offset(pud, 0))
- BUG();
-#else
+ if (!(pgd_val(*pgd) & _PAGE_PRESENT)) {
+ pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+
+ paravirt_alloc_pd(__pa(pmd_table) >> PAGE_SHIFT);
+ set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
+ pud = pud_offset(pgd, 0);
+ if (pmd_table != pmd_offset(pud, 0))
+ BUG();
+ }
+#endif
pud = pud_offset(pgd, 0);
pmd_table = pmd_offset(pud, 0);
-#endif
-
return pmd_table;
}
@@ -81,14 +84,12 @@ static pmd_t * __init one_md_table_init(pgd_t *pgd)
*/
static pte_t * __init one_page_table_init(pmd_t *pmd)
{
- if (pmd_none(*pmd)) {
+ if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
+
paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE));
- if (page_table != pte_offset_kernel(pmd, 0))
- BUG();
-
- return page_table;
+ BUG_ON(page_table != pte_offset_kernel(pmd, 0));
}
return pte_offset_kernel(pmd, 0);
@@ -108,7 +109,6 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
static void __init page_table_range_init (unsigned long start, unsigned long end, pgd_t *pgd_base)
{
pgd_t *pgd;
- pud_t *pud;
pmd_t *pmd;
int pgd_idx, pmd_idx;
unsigned long vaddr;
@@ -119,13 +119,10 @@ static void __init page_table_range_init (unsigned long start, unsigned long end
pgd = pgd_base + pgd_idx;
for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
- if (pgd_none(*pgd))
- one_md_table_init(pgd);
- pud = pud_offset(pgd, vaddr);
- pmd = pmd_offset(pud, vaddr);
+ pmd = one_md_table_init(pgd);
+ pmd = pmd + pmd_index(vaddr);
for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) {
- if (pmd_none(*pmd))
- one_page_table_init(pmd);
+ one_page_table_init(pmd);
vaddr += PMD_SIZE;
}
@@ -167,20 +164,22 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
/* Map with big pages if possible, otherwise create normal page tables. */
if (cpu_has_pse) {
unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1;
-
if (is_kernel_text(address) || is_kernel_text(address2))
set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC));
else
set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE));
+
pfn += PTRS_PER_PTE;
} else {
pte = one_page_table_init(pmd);
- for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) {
- if (is_kernel_text(address))
- set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
- else
- set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
+ for (pte_ofs = 0;
+ pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn;
+ pte++, pfn++, pte_ofs++, address += PAGE_SIZE) {
+ if (is_kernel_text(address))
+ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
+ else
+ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL));
}
}
}
@@ -337,24 +336,78 @@ extern void __init remap_numa_kva(void);
#define remap_numa_kva() do {} while (0)
#endif
-static void __init pagetable_init (void)
+void __init native_pagetable_setup_start(pgd_t *base)
{
- unsigned long vaddr;
- pgd_t *pgd_base = swapper_pg_dir;
-
#ifdef CONFIG_X86_PAE
int i;
- /* Init entries of the first-level page table to the zero page */
- for (i = 0; i < PTRS_PER_PGD; i++)
- set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
+
+ /*
+ * Init entries of the first-level page table to the
+ * zero page, if they haven't already been set up.
+ *
+ * In a normal native boot, we'll be running on a
+ * pagetable rooted in swapper_pg_dir, but not in PAE
+ * mode, so this will end up clobbering the mappings
+ * for the lower 24Mbytes of the address space,
+ * without affecting the kernel address space.
+ */
+ for (i = 0; i < USER_PTRS_PER_PGD; i++)
+ set_pgd(&base[i],
+ __pgd(__pa(empty_zero_page) | _PAGE_PRESENT));
+
+ /* Make sure kernel address space is empty so that a pagetable
+ will be allocated for it. */
+ memset(&base[USER_PTRS_PER_PGD], 0,
+ KERNEL_PGD_PTRS * sizeof(pgd_t));
#else
paravirt_alloc_pd(__pa(swapper_pg_dir) >> PAGE_SHIFT);
#endif
+}
+
+void __init native_pagetable_setup_done(pgd_t *base)
+{
+#ifdef CONFIG_X86_PAE
+ /*
+ * Add low memory identity-mappings - SMP needs it when
+ * starting up on an AP from real-mode. In the non-PAE
+ * case we already have these mappings through head.S.
+ * All user-space mappings are explicitly cleared after
+ * SMP startup.
+ */
+ set_pgd(&base[0], base[USER_PTRS_PER_PGD]);
+#endif
+}
+
+/*
+ * Build a proper pagetable for the kernel mappings. Up until this
+ * point, we've been running on some set of pagetables constructed by
+ * the boot process.
+ *
+ * If we're booting on native hardware, this will be a pagetable
+ * constructed in arch/i386/kernel/head.S, and not running in PAE mode
+ * (even if we'll end up running in PAE). The root of the pagetable
+ * will be swapper_pg_dir.
+ *
+ * If we're booting paravirtualized under a hypervisor, then there are
+ * more options: we may already be running PAE, and the pagetable may
+ * or may not be based in swapper_pg_dir. In any case,
+ * paravirt_pagetable_setup_start() will set up swapper_pg_dir
+ * appropriately for the rest of the initialization to work.
+ *
+ * In general, pagetable_init() assumes that the pagetable may already
+ * be partially populated, and so it avoids stomping on any existing
+ * mappings.
+ */
+static void __init pagetable_init (void)
+{
+ unsigned long vaddr, end;
+ pgd_t *pgd_base = swapper_pg_dir;
+
+ paravirt_pagetable_setup_start(pgd_base);
/* Enable PSE if available */
- if (cpu_has_pse) {
+ if (cpu_has_pse)
set_in_cr4(X86_CR4_PSE);
- }
/* Enable PGE if available */
if (cpu_has_pge) {
@@ -371,20 +424,12 @@ static void __init pagetable_init (void)
* created - mappings will be set by set_fixmap():
*/
vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
- page_table_range_init(vaddr, 0, pgd_base);
+ end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
+ page_table_range_init(vaddr, end, pgd_base);
permanent_kmaps_init(pgd_base);
-#ifdef CONFIG_X86_PAE
- /*
- * Add low memory identity-mappings - SMP needs it when
- * starting up on an AP from real-mode. In the non-PAE
- * case we already have these mappings through head.S.
- * All user-space mappings are explicitly cleared after
- * SMP startup.
- */
- set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]);
-#endif
+ paravirt_pagetable_setup_done(pgd_base);
}
#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_ACPI_SLEEP)
@@ -700,24 +745,31 @@ struct kmem_cache *pmd_cache;
void __init pgtable_cache_init(void)
{
+ size_t pgd_size = PTRS_PER_PGD*sizeof(pgd_t);
+
if (PTRS_PER_PMD > 1) {
pmd_cache = kmem_cache_create("pmd",
PTRS_PER_PMD*sizeof(pmd_t),
PTRS_PER_PMD*sizeof(pmd_t),
- 0,
+ SLAB_PANIC,
pmd_ctor,
NULL);
- if (!pmd_cache)
- panic("pgtable_cache_init(): cannot create pmd cache");
+ if (!SHARED_KERNEL_PMD) {
+ /* If we're in PAE mode and have a non-shared
+ kernel pmd, then the pgd size must be a
+ page size. This is because the pgd_list
+ links through the page structure, so there
+ can only be one pgd per page for this to
+ work. */
+ pgd_size = PAGE_SIZE;
+ }
}
pgd_cache = kmem_cache_create("pgd",
- PTRS_PER_PGD*sizeof(pgd_t),
- PTRS_PER_PGD*sizeof(pgd_t),
- 0,
+ pgd_size,
+ pgd_size,
+ SLAB_PANIC,
pgd_ctor,
- PTRS_PER_PMD == 1 ? pgd_dtor : NULL);
- if (!pgd_cache)
- panic("pgtable_cache_init(): Cannot create pgd cache");
+ (!SHARED_KERNEL_PMD) ? pgd_dtor : NULL);
}
/*
@@ -751,13 +803,25 @@ static int noinline do_test_wp_bit(void)
void mark_rodata_ro(void)
{
- unsigned long addr = (unsigned long)__start_rodata;
+ unsigned long start = PFN_ALIGN(_text);
+ unsigned long size = PFN_ALIGN(_etext) - start;
- for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE)
- change_page_attr(virt_to_page(addr), 1, PAGE_KERNEL_RO);
+#ifdef CONFIG_HOTPLUG_CPU
+ /* It must still be possible to apply SMP alternatives. */
+ if (num_possible_cpus() <= 1)
+#endif
+ {
+ change_page_attr(virt_to_page(start),
+ size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+ printk("Write protecting the kernel text: %luk\n", size >> 10);
+ }
- printk("Write protecting the kernel read-only data: %uk\n",
- (__end_rodata - __start_rodata) >> 10);
+ start += size;
+ size = (unsigned long)__end_rodata - start;
+ change_page_attr(virt_to_page(start),
+ size >> PAGE_SHIFT, PAGE_KERNEL_RO);
+ printk("Write protecting the kernel read-only data: %luk\n",
+ size >> 10);
/*
* change_page_attr() requires a global_flush_tlb() call after it.
@@ -780,7 +844,7 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
free_page(addr);
totalram_pages++;
}
- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+ printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
}
void free_initmem(void)
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index 412ebbd8adb..47bd477c8ec 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -91,7 +91,7 @@ static void set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte)
unsigned long flags;
set_pte_atomic(kpte, pte); /* change init_mm */
- if (PTRS_PER_PMD > 1)
+ if (SHARED_KERNEL_PMD)
return;
spin_lock_irqsave(&pgd_lock, flags);
@@ -142,7 +142,7 @@ __change_page_attr(struct page *page, pgprot_t prot)
return -EINVAL;
kpte_page = virt_to_page(kpte);
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) {
- if ((pte_val(*kpte) & _PAGE_PSE) == 0) {
+ if (!pte_huge(*kpte)) {
set_pte_atomic(kpte, mk_pte(page, prot));
} else {
pgprot_t ref_prot;
@@ -158,7 +158,7 @@ __change_page_attr(struct page *page, pgprot_t prot)
kpte_page = split;
}
page_private(kpte_page)++;
- } else if ((pte_val(*kpte) & _PAGE_PSE) == 0) {
+ } else if (!pte_huge(*kpte)) {
set_pte_atomic(kpte, mk_pte(page, PAGE_KERNEL));
BUG_ON(page_private(kpte_page) == 0);
page_private(kpte_page)--;
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index fa0cfbd551e..9a96c164742 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -144,10 +144,8 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
}
static int fixmaps;
-#ifndef CONFIG_COMPAT_VDSO
unsigned long __FIXADDR_TOP = 0xfffff000;
EXPORT_SYMBOL(__FIXADDR_TOP);
-#endif
void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
{
@@ -173,12 +171,8 @@ void reserve_top_address(unsigned long reserve)
BUG_ON(fixmaps > 0);
printk(KERN_INFO "Reserving virtual address space above 0x%08x\n",
(int)-reserve);
-#ifdef CONFIG_COMPAT_VDSO
- BUG_ON(reserve != 0);
-#else
__FIXADDR_TOP = -reserve - PAGE_SIZE;
__VMALLOC_RESERVE += reserve;
-#endif
}
pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
@@ -238,42 +232,92 @@ static inline void pgd_list_del(pgd_t *pgd)
set_page_private(next, (unsigned long)pprev);
}
+#if (PTRS_PER_PMD == 1)
+/* Non-PAE pgd constructor */
void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
{
unsigned long flags;
- if (PTRS_PER_PMD == 1) {
- memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
- spin_lock_irqsave(&pgd_lock, flags);
- }
+ /* !PAE, no pagetable sharing */
+ memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+
+ spin_lock_irqsave(&pgd_lock, flags);
+ /* must happen under lock */
clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
swapper_pg_dir + USER_PTRS_PER_PGD,
KERNEL_PGD_PTRS);
-
- if (PTRS_PER_PMD > 1)
- return;
-
- /* must happen under lock */
paravirt_alloc_pd_clone(__pa(pgd) >> PAGE_SHIFT,
- __pa(swapper_pg_dir) >> PAGE_SHIFT,
- USER_PTRS_PER_PGD, PTRS_PER_PGD - USER_PTRS_PER_PGD);
-
+ __pa(swapper_pg_dir) >> PAGE_SHIFT,
+ USER_PTRS_PER_PGD,
+ KERNEL_PGD_PTRS);
pgd_list_add(pgd);
spin_unlock_irqrestore(&pgd_lock, flags);
}
+#else /* PTRS_PER_PMD > 1 */
+/* PAE pgd constructor */
+void pgd_ctor(void *pgd, struct kmem_cache *cache, unsigned long unused)
+{
+ /* PAE, kernel PMD may be shared */
+
+ if (SHARED_KERNEL_PMD) {
+ clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
+ KERNEL_PGD_PTRS);
+ } else {
+ unsigned long flags;
+
+ memset(pgd, 0, USER_PTRS_PER_PGD*sizeof(pgd_t));
+ spin_lock_irqsave(&pgd_lock, flags);
+ pgd_list_add(pgd);
+ spin_unlock_irqrestore(&pgd_lock, flags);
+ }
+}
+#endif /* PTRS_PER_PMD */
-/* never called when PTRS_PER_PMD > 1 */
void pgd_dtor(void *pgd, struct kmem_cache *cache, unsigned long unused)
{
unsigned long flags; /* can be called from interrupt context */
+ BUG_ON(SHARED_KERNEL_PMD);
+
paravirt_release_pd(__pa(pgd) >> PAGE_SHIFT);
spin_lock_irqsave(&pgd_lock, flags);
pgd_list_del(pgd);
spin_unlock_irqrestore(&pgd_lock, flags);
}
+#define UNSHARED_PTRS_PER_PGD \
+ (SHARED_KERNEL_PMD ? USER_PTRS_PER_PGD : PTRS_PER_PGD)
+
+/* If we allocate a pmd for part of the kernel address space, then
+ make sure its initialized with the appropriate kernel mappings.
+ Otherwise use a cached zeroed pmd. */
+static pmd_t *pmd_cache_alloc(int idx)
+{
+ pmd_t *pmd;
+
+ if (idx >= USER_PTRS_PER_PGD) {
+ pmd = (pmd_t *)__get_free_page(GFP_KERNEL);
+
+ if (pmd)
+ memcpy(pmd,
+ (void *)pgd_page_vaddr(swapper_pg_dir[idx]),
+ sizeof(pmd_t) * PTRS_PER_PMD);
+ } else
+ pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
+
+ return pmd;
+}
+
+static void pmd_cache_free(pmd_t *pmd, int idx)
+{
+ if (idx >= USER_PTRS_PER_PGD)
+ free_page((unsigned long)pmd);
+ else
+ kmem_cache_free(pmd_cache, pmd);
+}
+
pgd_t *pgd_alloc(struct mm_struct *mm)
{
int i;
@@ -282,10 +326,12 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
if (PTRS_PER_PMD == 1 || !pgd)
return pgd;
- for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
- pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
+ for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
+ pmd_t *pmd = pmd_cache_alloc(i);
+
if (!pmd)
goto out_oom;
+
paravirt_alloc_pd(__pa(pmd) >> PAGE_SHIFT);
set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
}
@@ -296,7 +342,7 @@ out_oom:
pgd_t pgdent = pgd[i];
void* pmd = (void *)__va(pgd_val(pgdent)-1);
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
- kmem_cache_free(pmd_cache, pmd);
+ pmd_cache_free(pmd, i);
}
kmem_cache_free(pgd_cache, pgd);
return NULL;
@@ -308,11 +354,11 @@ void pgd_free(pgd_t *pgd)
/* in the PAE case user pgd entries are overwritten before usage */
if (PTRS_PER_PMD > 1)
- for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
+ for (i = 0; i < UNSHARED_PTRS_PER_PGD; ++i) {
pgd_t pgdent = pgd[i];
void* pmd = (void *)__va(pgd_val(pgdent)-1);
paravirt_release_pd(__pa(pmd) >> PAGE_SHIFT);
- kmem_cache_free(pmd_cache, pmd);
+ pmd_cache_free(pmd, i);
}
/* in the non-PAE case, free_pgtables() clears user pgd entries */
kmem_cache_free(pgd_cache, pgd);
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 8fda7be9dd4..8e185208dfd 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -14,10 +14,10 @@
#include <linux/sysdev.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
+#include <linux/kdebug.h>
#include <asm/nmi.h>
#include <asm/msr.h>
#include <asm/apic.h>
-#include <asm/kdebug.h>
#include "op_counter.h"
#include "op_x86_model.h"
@@ -414,6 +414,10 @@ int __init op_nmi_init(struct oprofile_operations *ops)
user space an consistent name. */
cpu_type = "x86-64/hammer";
break;
+ case 0x10:
+ model = &op_athlon_spec;
+ cpu_type = "x86-64/family10";
+ break;
}
break;
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
index abf0ba52a63..1418e36ae7a 100644
--- a/arch/i386/oprofile/nmi_timer_int.c
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -12,12 +12,11 @@
#include <linux/errno.h>
#include <linux/oprofile.h>
#include <linux/rcupdate.h>
-
+#include <linux/kdebug.h>
#include <asm/nmi.h>
#include <asm/apic.h>
#include <asm/ptrace.h>
-#include <asm/kdebug.h>
static int profile_timer_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index 8053b17ab64..b62eafb997b 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -354,7 +354,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
}
}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
/*
* Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index 43005f04442..bcd2f94b732 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -246,8 +246,8 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
continue;
if (!r->start && r->end) {
printk(KERN_ERR "PCI: Device %s not available "
- "because of resource collisions\n",
- pci_name(dev));
+ "because of resource %d collisions\n",
+ pci_name(dev), idx);
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c
index b21b6da8ab1..3de9f9ba2da 100644
--- a/arch/i386/pci/init.c
+++ b/arch/i386/pci/init.c
@@ -6,7 +6,7 @@
in the right sequence from here. */
static __init int pci_access_init(void)
{
- int type = 0;
+ int type __maybe_unused = 0;
#ifdef CONFIG_PCI_DIRECT
type = pci_direct_probe();
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index 747d8c63b0c..c7cabeed4d7 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -60,14 +60,19 @@ static const char __init *pci_mmcfg_e7520(void)
u32 win;
pci_conf1_read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
- pci_mmcfg_config_num = 1;
- pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
- if (!pci_mmcfg_config)
- return NULL;
- pci_mmcfg_config[0].address = (win & 0xf000) << 16;
- pci_mmcfg_config[0].pci_segment = 0;
- pci_mmcfg_config[0].start_bus_number = 0;
- pci_mmcfg_config[0].end_bus_number = 255;
+ win = win & 0xf000;
+ if(win == 0x0000 || win == 0xf000)
+ pci_mmcfg_config_num = 0;
+ else {
+ pci_mmcfg_config_num = 1;
+ pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
+ if (!pci_mmcfg_config)
+ return NULL;
+ pci_mmcfg_config[0].address = win << 16;
+ pci_mmcfg_config[0].pci_segment = 0;
+ pci_mmcfg_config[0].start_bus_number = 0;
+ pci_mmcfg_config[0].end_bus_number = 255;
+ }
return "Intel Corporation E7520 Memory Controller Hub";
}
@@ -108,6 +113,10 @@ static const char __init *pci_mmcfg_intel_945(void)
if ((pciexbar & mask) & 0x0fffffffU)
pci_mmcfg_config_num = 0;
+ /* Don't hit the APIC registers and their friends */
+ if ((pciexbar & mask) >= 0xf0000000U)
+ pci_mmcfg_config_num = 0;
+
if (pci_mmcfg_config_num) {
pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL);
if (!pci_mmcfg_config)
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index 2c15500f871..998fd3ec0d6 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -21,6 +21,7 @@ unsigned long saved_context_eflags;
void __save_processor_state(struct saved_context *ctxt)
{
+ mtrr_save_fixed_ranges(NULL);
kernel_fpu_begin();
/*
diff --git a/arch/i386/power/suspend.c b/arch/i386/power/suspend.c
index db5e98d2eb7..a0020b913f3 100644
--- a/arch/i386/power/suspend.c
+++ b/arch/i386/power/suspend.c
@@ -16,6 +16,9 @@
/* Defined in arch/i386/power/swsusp.S */
extern int restore_image(void);
+/* References to section boundaries */
+extern const void __nosave_begin, __nosave_end;
+
/* Pointer to the temporary resume page tables */
pgd_t *resume_pg_dir;
@@ -156,3 +159,14 @@ int swsusp_arch_resume(void)
restore_image();
return 0;
}
+
+/*
+ * pfn_is_nosave - check if given pfn is in the 'nosave' section
+ */
+
+int pfn_is_nosave(unsigned long pfn)
+{
+ unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT;
+ unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
+ return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index e19185d2655..6e41471449c 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -14,6 +14,7 @@ config IA64
select PCI if (!IA64_HP_SIM)
select ACPI if (!IA64_HP_SIM)
select PM if (!IA64_HP_SIM)
+ select ARCH_SUPPORTS_MSI
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
@@ -438,6 +439,16 @@ config IA64_PALINFO
To use this option, you have to ensure that the "/proc file system
support" (CONFIG_PROC_FS) is enabled, too.
+config IA64_MC_ERR_INJECT
+ tristate "MC error injection support"
+ help
+ Selets whether support for MC error injection. By enabling the
+ support, kernel provide sysfs interface for user application to
+ call MC error injection PAL procedure to inject various errors.
+ This is a useful tool for MCA testing.
+
+ If you're unsure, do not select this option.
+
config SGI_SN
def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
@@ -457,7 +468,7 @@ config KEXEC
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
- but it is indepedent of the system firmware. And like a reboot
+ but it is independent of the system firmware. And like a reboot
you can start any kernel with it, not just Linux.
The name comes from the similiarity to the exec system call.
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 153bfdc0182..90bd9601cdd 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -164,6 +164,7 @@ CONFIG_COMPAT=y
CONFIG_IA64_MCA_RECOVERY=y
CONFIG_PERFMON=y
CONFIG_IA64_PALINFO=y
+# CONFIG_MC_ERR_INJECT is not set
CONFIG_SGI_SN=y
# CONFIG_IA64_ESI is not set
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 5a0a7afcfc3..300acd913d9 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -287,7 +287,7 @@ sys_fw_init (const char *args, int arglen)
memset(efi_systab, 0, sizeof(efi_systab));
efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE;
- efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION;
+ efi_systab->hdr.revision = ((1 << 16) | 00);
efi_systab->hdr.headersize = sizeof(efi_systab->hdr);
efi_systab->fw_vendor = __pa("H\0e\0w\0l\0e\0t\0t\0-\0P\0a\0c\0k\0a\0r\0d\0\0");
efi_systab->fw_revision = 1;
diff --git a/arch/ia64/ia32/ia32_ldt.c b/arch/ia64/ia32/ia32_ldt.c
index a152738c7d0..16d51c14684 100644
--- a/arch/ia64/ia32/ia32_ldt.c
+++ b/arch/ia64/ia32/ia32_ldt.c
@@ -10,7 +10,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index b3355a9ca2c..10510e58520 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -18,7 +18,6 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c
index 6af400a12ca..beea7a0b9dc 100644
--- a/arch/ia64/ia32/ia32_support.c
+++ b/arch/ia64/ia32/ia32_support.c
@@ -252,10 +252,8 @@ ia32_init (void)
extern struct kmem_cache *partial_page_cachep;
partial_page_cachep = kmem_cache_create("partial_page_cache",
- sizeof(struct partial_page), 0, 0,
- NULL, NULL);
- if (!partial_page_cachep)
- panic("Cannot create partial page SLAB cache");
+ sizeof(struct partial_page),
+ 0, SLAB_PANIC, NULL, NULL);
}
#endif
return 0;
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 098ee605bf5..33e5a598672 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_PCI_MSI) += msi_ia64.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
+obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
obj-$(CONFIG_IA64_ESI) += esi.o
ifneq ($(CONFIG_IA64_ESI),)
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index 80a94e70782..aeb79fb28f0 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -16,8 +16,8 @@
#include <linux/elfcore.h>
#include <linux/sysctl.h>
#include <linux/init.h>
+#include <linux/kdebug.h>
-#include <asm/kdebug.h>
#include <asm/mca.h>
int kdump_status[NR_CPUS];
@@ -74,7 +74,7 @@ crash_save_this_cpu(void)
buf = (u64 *) per_cpu_ptr(crash_notes, cpu);
if (!buf)
return;
- buf = append_elf_note(buf, "CORE", NT_PRSTATUS, prstatus,
+ buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, prstatus,
sizeof(*prstatus));
final_note(buf);
}
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index f45f91d38ca..75ec3478d8a 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -445,11 +445,11 @@ efi_init (void)
panic("Woah! Can't find EFI system table.\n");
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
panic("Woah! EFI system table signature incorrect\n");
- if ((efi.systab->hdr.revision ^ EFI_SYSTEM_TABLE_REVISION) >> 16 != 0)
- printk(KERN_WARNING "Warning: EFI system table major version mismatch: "
- "got %d.%02d, expected %d.%02d\n",
- efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff,
- EFI_SYSTEM_TABLE_REVISION >> 16, EFI_SYSTEM_TABLE_REVISION & 0xffff);
+ if ((efi.systab->hdr.revision >> 16) == 0)
+ printk(KERN_WARNING "Warning: EFI system table version "
+ "%d.%02d, expected 1.00 or greater\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff);
config_tables = __va(efi.systab->tables);
@@ -660,6 +660,29 @@ efi_memory_descriptor (unsigned long phys_addr)
return NULL;
}
+static int
+efi_memmap_intersects (unsigned long phys_addr, unsigned long size)
+{
+ void *efi_map_start, *efi_map_end, *p;
+ efi_memory_desc_t *md;
+ u64 efi_desc_size;
+ unsigned long end;
+
+ efi_map_start = __va(ia64_boot_param->efi_memmap);
+ efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size;
+ efi_desc_size = ia64_boot_param->efi_memdesc_size;
+
+ end = phys_addr + size;
+
+ for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
+ md = p;
+
+ if (md->phys_addr < end && efi_md_end(md) > phys_addr)
+ return 1;
+ }
+ return 0;
+}
+
u32
efi_mem_type (unsigned long phys_addr)
{
@@ -766,11 +789,28 @@ valid_phys_addr_range (unsigned long phys_addr, unsigned long size)
int
valid_mmap_phys_addr_range (unsigned long pfn, unsigned long size)
{
+ unsigned long phys_addr = pfn << PAGE_SHIFT;
+ u64 attr;
+
+ attr = efi_mem_attribute(phys_addr, size);
+
/*
- * MMIO regions are often missing from the EFI memory map.
- * We must allow mmap of them for programs like X, so we
- * currently can't do any useful validation.
+ * /dev/mem mmap uses normal user pages, so we don't need the entire
+ * granule, but the entire region we're mapping must support the same
+ * attribute.
*/
+ if (attr & EFI_MEMORY_WB || attr & EFI_MEMORY_UC)
+ return 1;
+
+ /*
+ * Intel firmware doesn't tell us about all the MMIO regions, so
+ * in general we have to allow mmap requests. But if EFI *does*
+ * tell us about anything inside this region, we should deny it.
+ * The user can always map a smaller region to avoid the overlap.
+ */
+ if (efi_memmap_intersects(phys_addr, size))
+ return 0;
+
return 1;
}
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index e7873eeae44..55fd2d5471e 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -767,7 +767,7 @@ ENTRY(ia64_leave_syscall)
ld8.fill r15=[r3] // M0|1 restore r15
mov b6=r18 // I0 restore b6
- addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 // A
+ LOAD_PHYS_STACK_REG_SIZE(r17)
mov f9=f0 // F clear f9
(pKStk) br.cond.dpnt.many skip_rbs_switch // B
@@ -775,7 +775,6 @@ ENTRY(ia64_leave_syscall)
shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition
cover // B add current frame into dirty partition & set cr.ifs
;;
-(pUStk) ld4 r17=[r17] // M0|1 r17 = cpu_data->phys_stacked_size_p8
mov r19=ar.bsp // M2 get new backing store pointer
mov f10=f0 // F clear f10
@@ -953,9 +952,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
shr.u r18=r19,16 // get byte size of existing "dirty" partition
;;
mov r16=ar.bsp // get existing backing store pointer
- addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0
- ;;
- ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8
+ LOAD_PHYS_STACK_REG_SIZE(r17)
(pKStk) br.cond.dpnt skip_rbs_switch
/*
diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
new file mode 100644
index 00000000000..6a49600cf33
--- /dev/null
+++ b/arch/ia64/kernel/err_inject.c
@@ -0,0 +1,295 @@
+/*
+ * err_inject.c -
+ * 1.) Inject errors to a processor.
+ * 2.) Query error injection capabilities.
+ * This driver along with user space code can be acting as an error
+ * injection tool.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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.
+ *
+ * Written by: Fenghua Yu <fenghua.yu@intel.com>, Intel Corporation
+ * Copyright (C) 2006, Intel Corp. All rights reserved.
+ *
+ */
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+
+#define ERR_INJ_DEBUG
+
+#define ERR_DATA_BUFFER_SIZE 3 // Three 8-byte;
+
+#define define_one_ro(name) \
+static SYSDEV_ATTR(name, 0444, show_##name, NULL)
+
+#define define_one_rw(name) \
+static SYSDEV_ATTR(name, 0644, show_##name, store_##name)
+
+static u64 call_start[NR_CPUS];
+static u64 phys_addr[NR_CPUS];
+static u64 err_type_info[NR_CPUS];
+static u64 err_struct_info[NR_CPUS];
+static struct {
+ u64 data1;
+ u64 data2;
+ u64 data3;
+} __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS];
+static s64 status[NR_CPUS];
+static u64 capabilities[NR_CPUS];
+static u64 resources[NR_CPUS];
+
+#define show(name) \
+static ssize_t \
+show_##name(struct sys_device *dev, char *buf) \
+{ \
+ u32 cpu=dev->id; \
+ return sprintf(buf, "%lx\n", name[cpu]); \
+}
+
+#define store(name) \
+static ssize_t \
+store_##name(struct sys_device *dev, const char *buf, size_t size) \
+{ \
+ unsigned int cpu=dev->id; \
+ name[cpu] = simple_strtoull(buf, NULL, 16); \
+ return size; \
+}
+
+show(call_start)
+
+/* It's user's responsibility to call the PAL procedure on a specific
+ * processor. The cpu number in driver is only used for storing data.
+ */
+static ssize_t
+store_call_start(struct sys_device *dev, const char *buf, size_t size)
+{
+ unsigned int cpu=dev->id;
+ unsigned long call_start = simple_strtoull(buf, NULL, 16);
+
+#ifdef ERR_INJ_DEBUG
+ printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
+ printk(KERN_DEBUG "err_type_info=%lx,\n", err_type_info[cpu]);
+ printk(KERN_DEBUG "err_struct_info=%lx,\n", err_struct_info[cpu]);
+ printk(KERN_DEBUG "err_data_buffer=%lx, %lx, %lx.\n",
+ err_data_buffer[cpu].data1,
+ err_data_buffer[cpu].data2,
+ err_data_buffer[cpu].data3);
+#endif
+ switch (call_start) {
+ case 0: /* Do nothing. */
+ break;
+ case 1: /* Call pal_mc_error_inject in physical mode. */
+ status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
+ err_struct_info[cpu],
+ ia64_tpa(&err_data_buffer[cpu]),
+ &capabilities[cpu],
+ &resources[cpu]);
+ break;
+ case 2: /* Call pal_mc_error_inject in virtual mode. */
+ status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
+ err_struct_info[cpu],
+ ia64_tpa(&err_data_buffer[cpu]),
+ &capabilities[cpu],
+ &resources[cpu]);
+ break;
+ default:
+ status[cpu] = -EINVAL;
+ break;
+ }
+
+#ifdef ERR_INJ_DEBUG
+ printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
+ printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
+ printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
+#endif
+ return size;
+}
+
+show(err_type_info)
+store(err_type_info)
+
+static ssize_t
+show_virtual_to_phys(struct sys_device *dev, char *buf)
+{
+ unsigned int cpu=dev->id;
+ return sprintf(buf, "%lx\n", phys_addr[cpu]);
+}
+
+static ssize_t
+store_virtual_to_phys(struct sys_device *dev, const char *buf, size_t size)
+{
+ unsigned int cpu=dev->id;
+ u64 virt_addr=simple_strtoull(buf, NULL, 16);
+ int ret;
+
+ ret = get_user_pages(current, current->mm, virt_addr,
+ 1, VM_READ, 0, NULL, NULL);
+ if (ret<=0) {
+#ifdef ERR_INJ_DEBUG
+ printk("Virtual address %lx is not existing.\n",virt_addr);
+#endif
+ return -EINVAL;
+ }
+
+ phys_addr[cpu] = ia64_tpa(virt_addr);
+ return size;
+}
+
+show(err_struct_info)
+store(err_struct_info)
+
+static ssize_t
+show_err_data_buffer(struct sys_device *dev, char *buf)
+{
+ unsigned int cpu=dev->id;
+
+ return sprintf(buf, "%lx, %lx, %lx\n",
+ err_data_buffer[cpu].data1,
+ err_data_buffer[cpu].data2,
+ err_data_buffer[cpu].data3);
+}
+
+static ssize_t
+store_err_data_buffer(struct sys_device *dev, const char *buf, size_t size)
+{
+ unsigned int cpu=dev->id;
+ int ret;
+
+#ifdef ERR_INJ_DEBUG
+ printk("write err_data_buffer=[%lx,%lx,%lx] on cpu%d\n",
+ err_data_buffer[cpu].data1,
+ err_data_buffer[cpu].data2,
+ err_data_buffer[cpu].data3,
+ cpu);
+#endif
+ ret=sscanf(buf, "%lx, %lx, %lx",
+ &err_data_buffer[cpu].data1,
+ &err_data_buffer[cpu].data2,
+ &err_data_buffer[cpu].data3);
+ if (ret!=ERR_DATA_BUFFER_SIZE)
+ return -EINVAL;
+
+ return size;
+}
+
+show(status)
+show(capabilities)
+show(resources)
+
+define_one_rw(call_start);
+define_one_rw(err_type_info);
+define_one_rw(err_struct_info);
+define_one_rw(err_data_buffer);
+define_one_rw(virtual_to_phys);
+define_one_ro(status);
+define_one_ro(capabilities);
+define_one_ro(resources);
+
+static struct attribute *default_attrs[] = {
+ &attr_call_start.attr,
+ &attr_virtual_to_phys.attr,
+ &attr_err_type_info.attr,
+ &attr_err_struct_info.attr,
+ &attr_err_data_buffer.attr,
+ &attr_status.attr,
+ &attr_capabilities.attr,
+ &attr_resources.attr,
+ NULL
+};
+
+static struct attribute_group err_inject_attr_group = {
+ .attrs = default_attrs,
+ .name = "err_inject"
+};
+/* Add/Remove err_inject interface for CPU device */
+static int __cpuinit err_inject_add_dev(struct sys_device * sys_dev)
+{
+ return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
+}
+
+static int __cpuinit err_inject_remove_dev(struct sys_device * sys_dev)
+{
+ sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
+ return 0;
+}
+static int __cpuinit err_inject_cpu_callback(struct notifier_block *nfb,
+ 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:
+ err_inject_add_dev(sys_dev);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ err_inject_remove_dev(sys_dev);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata err_inject_cpu_notifier =
+{
+ .notifier_call = err_inject_cpu_callback,
+};
+
+static int __init
+err_inject_init(void)
+{
+ int i;
+
+#ifdef ERR_INJ_DEBUG
+ printk(KERN_INFO "Enter error injection driver.\n");
+#endif
+ for_each_online_cpu(i) {
+ err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
+ (void *)(long)i);
+ }
+
+ register_hotcpu_notifier(&err_inject_cpu_notifier);
+
+ return 0;
+}
+
+static void __exit
+err_inject_exit(void)
+{
+ int i;
+ struct sys_device *sys_dev;
+
+#ifdef ERR_INJ_DEBUG
+ printk(KERN_INFO "Exit error injection driver.\n");
+#endif
+ for_each_online_cpu(i) {
+ sys_dev = get_cpu_sysdev(i);
+ sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
+ }
+ unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+}
+
+module_init(err_inject_init);
+module_exit(err_inject_exit);
+
+MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
+MODULE_DESCRIPTION("MC error injection kenrel sysfs interface");
+MODULE_LICENSE("GPL");
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index dcfbf3e7a9e..93d9ab14ba2 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -87,7 +87,6 @@
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/bootmem.h>
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 456f57b087c..1c5044a8095 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -27,7 +27,6 @@
#include <linux/random.h> /* for rand_initialize_irq() */
#include <linux/signal.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/threads.h>
#include <linux/bitops.h>
#include <linux/irq.h>
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index 6b7fcbd3f6f..34f44d8be00 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -374,6 +374,7 @@ ENTRY(alt_dtlb_miss)
movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
mov r21=cr.ipsr
mov r31=pr
+ mov r24=PERCPU_ADDR
;;
#ifdef CONFIG_DISABLE_VHPT
shr.u r22=r16,61 // get the region number into r21
@@ -386,22 +387,30 @@ ENTRY(alt_dtlb_miss)
(p8) mov r29=b0 // save b0
(p8) br.cond.dptk dtlb_fault
#endif
+ cmp.ge p10,p11=r16,r24 // access to per_cpu_data?
+ tbit.z p12,p0=r16,61 // access to region 6?
+ mov r25=PERCPU_PAGE_SHIFT << 2
+ mov r26=PERCPU_PAGE_SIZE
+ nop.m 0
+ nop.b 0
+ ;;
+(p10) mov r19=IA64_KR(PER_CPU_DATA)
+(p11) and r19=r19,r16 // clear non-ppn fields
extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
and r22=IA64_ISR_CODE_MASK,r20 // get the isr.code field
tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on?
- shr.u r18=r16,57 // move address bit 61 to bit 4
- and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
tbit.nz p9,p0=r20,IA64_ISR_NA_BIT // is non-access bit on?
;;
- andcm r18=0x10,r18 // bit 4=~address-bit(61)
+(p10) sub r19=r19,r26
+(p10) mov cr.itir=r25
cmp.ne p8,p0=r0,r23
(p9) cmp.eq.or.andcm p6,p7=IA64_ISR_CODE_LFETCH,r22 // check isr.code field
+(p12) dep r17=-1,r17,4,1 // set ma=UC for region 6 addr
(p8) br.cond.spnt page_fault
dep r21=-1,r21,IA64_PSR_ED_BIT,1
- or r19=r19,r17 // insert PTE control bits into r19
;;
- or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6
+ or r19=r19,r17 // insert PTE control bits into r19
(p6) mov cr.ipsr=r21
;;
(p7) itc.d r19 // insert the TLB entry
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 6cb56dd4056..4f5fd0960ba 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -29,9 +29,9 @@
#include <linux/slab.h>
#include <linux/preempt.h>
#include <linux/moduleloader.h>
+#include <linux/kdebug.h>
#include <asm/pgtable.h>
-#include <asm/kdebug.h>
#include <asm/sections.h>
#include <asm/uaccess.h>
@@ -444,7 +444,8 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
break;
}
- BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
+
regs->cr_iip = orig_ret_address;
reset_current_kprobe();
@@ -464,23 +465,13 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
}
/* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
- struct kretprobe_instance *ri;
-
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
- ri->ret_addr = (kprobe_opcode_t *)regs->b0;
-
- /* Replace the return addr with trampoline addr */
- regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
+ ri->ret_addr = (kprobe_opcode_t *)regs->b0;
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ /* Replace the return addr with trampoline addr */
+ regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
}
int __kprobes arch_prepare_kprobe(struct kprobe *p)
@@ -1021,3 +1012,12 @@ int __init arch_init_kprobes(void)
(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
return register_kprobe(&trampoline_p);
}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr ==
+ (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 491687f84fb..f8ae709de0b 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -63,7 +63,6 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/smp_lock.h>
#include <linux/bootmem.h>
#include <linux/acpi.h>
#include <linux/timer.h>
@@ -72,9 +71,9 @@
#include <linux/smp.h>
#include <linux/workqueue.h>
#include <linux/cpumask.h>
+#include <linux/kdebug.h>
#include <asm/delay.h>
-#include <asm/kdebug.h>
#include <asm/machvec.h>
#include <asm/meminit.h>
#include <asm/page.h>
@@ -1690,7 +1689,7 @@ format_mca_init_stack(void *mca_data, unsigned long offset,
ti->preempt_count = 1;
ti->task = p;
ti->cpu = cpu;
- p->thread_info = ti;
+ p->stack = ti;
p->state = TASK_UNINTERRUPTIBLE;
cpu_set(cpu, p->cpus_allowed);
INIT_LIST_HEAD(&p->tasks);
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index c6b607c00de..8c9c26aa6ae 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -101,14 +101,6 @@ ia64_do_tlb_purge:
;;
srlz.d
;;
- // 2. Purge DTR for PERCPU data.
- movl r16=PERCPU_ADDR
- mov r18=PERCPU_PAGE_SHIFT<<2
- ;;
- ptr.d r16,r18
- ;;
- srlz.d
- ;;
// 3. Purge ITR for PAL code.
GET_THIS_PADDR(r2, ia64_mca_pal_base)
;;
@@ -196,22 +188,6 @@ ia64_reload_tr:
srlz.i
srlz.d
;;
- // 2. Reload DTR register for PERCPU data.
- GET_THIS_PADDR(r2, ia64_mca_per_cpu_pte)
- ;;
- movl r16=PERCPU_ADDR // vaddr
- movl r18=PERCPU_PAGE_SHIFT<<2
- ;;
- mov cr.itir=r18
- mov cr.ifa=r16
- ;;
- ld8 r18=[r2] // load per-CPU PTE
- mov r16=IA64_TR_PERCPU_DATA;
- ;;
- itr.d dtr[r16]=r18
- ;;
- srlz.d
- ;;
// 3. Reload ITR for PAL code.
GET_THIS_PADDR(r2, ia64_mca_pal_pte)
;;
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index 832cf1e647e..70b8bdbb7e6 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -14,7 +14,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kallsyms.h>
-#include <linux/smp_lock.h>
#include <linux/bootmem.h>
#include <linux/acpi.h>
#include <linux/timer.h>
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index a71df9ae039..85829e27785 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -975,9 +975,11 @@ static int palinfo_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
create_palinfo_proc_entries(hotcpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
remove_palinfo_proc_entries(hotcpu);
break;
}
diff --git a/arch/ia64/kernel/patch.c b/arch/ia64/kernel/patch.c
index bc11bb096f5..e796e29f8e1 100644
--- a/arch/ia64/kernel/patch.c
+++ b/arch/ia64/kernel/patch.c
@@ -195,3 +195,23 @@ ia64_patch_gate (void)
ia64_patch_vtop(START(vtop), END(vtop));
ia64_patch_mckinley_e9(START(mckinley_e9), END(mckinley_e9));
}
+
+void ia64_patch_phys_stack_reg(unsigned long val)
+{
+ s32 * offp = (s32 *) __start___phys_stack_reg_patchlist;
+ s32 * end = (s32 *) __end___phys_stack_reg_patchlist;
+ u64 ip, mask, imm;
+
+ /* see instruction format A4: adds r1 = imm13, r3 */
+ mask = (0x3fUL << 27) | (0x7f << 13);
+ imm = (((val >> 7) & 0x3f) << 27) | (val & 0x7f) << 13;
+
+ while (offp < end) {
+ ip = (u64) offp + *offp;
+ ia64_patch(ip, mask, imm);
+ ia64_fc(ip);
+ ++offp;
+ }
+ ia64_sync_i();
+ ia64_srlz_i();
+}
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index abc7ad03588..e7191ca30b1 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -23,7 +23,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/init.h>
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index ae96d417699..8bb571a8a73 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -20,20 +20,19 @@
#include <linux/personality.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/thread_info.h>
#include <linux/unistd.h>
#include <linux/efi.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/kdebug.h>
#include <asm/cpu.h>
#include <asm/delay.h>
#include <asm/elf.h>
#include <asm/ia32.h>
#include <asm/irq.h>
-#include <asm/kdebug.h>
#include <asm/kexec.h>
#include <asm/pgalloc.h>
#include <asm/processor.h>
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index af9f8754d84..89f6b138a62 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -42,7 +42,6 @@
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/vmalloc.h>
@@ -583,6 +582,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
struct salinfo_data *data;
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
spin_lock_irqsave(&data_saved_lock, flags);
for (i = 0, data = salinfo_data;
i < ARRAY_SIZE(salinfo_data);
@@ -593,6 +593,7 @@ salinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu
spin_unlock_irqrestore(&data_saved_lock, flags);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
spin_lock_irqsave(&data_saved_lock, flags);
for (i = 0, data = salinfo_data;
i < ARRAY_SIZE(salinfo_data);
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index dc7dd7648ec..6e19da122ae 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -75,7 +75,6 @@ extern void ia64_setup_printk_clock(void);
DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);
DEFINE_PER_CPU(unsigned long, local_per_cpu_offset);
-DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8);
unsigned long ia64_cycles_per_usec;
struct ia64_boot_param *ia64_boot_param;
struct screen_info screen_info;
@@ -869,6 +868,7 @@ void __cpuinit
cpu_init (void)
{
extern void __cpuinit ia64_mmu_init (void *);
+ static unsigned long max_num_phys_stacked = IA64_NUM_PHYS_STACK_REG;
unsigned long num_phys_stacked;
pal_vm_info_2_u_t vmi;
unsigned int max_ctx;
@@ -982,7 +982,10 @@ cpu_init (void)
num_phys_stacked = 96;
}
/* size of physical stacked register partition plus 8 bytes: */
- __get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8;
+ if (num_phys_stacked > max_num_phys_stacked) {
+ ia64_patch_phys_stack_reg(num_phys_stacked*8 + 8);
+ max_num_phys_stacked = num_phys_stacked;
+ }
platform_cpu_init();
pm_idle = default_idle;
}
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 77f8b49c788..0dcd56da600 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index ff7df439da6..a44792d0f3a 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -35,7 +35,6 @@
#include <linux/mm.h>
#include <linux/notifier.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/efi.h>
#include <linux/percpu.h>
diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
index 9ef62a3fbfa..1eda194b955 100644
--- a/arch/ia64/kernel/sys_ia64.c
+++ b/arch/ia64/kernel/sys_ia64.c
@@ -13,7 +13,6 @@
#include <linux/shm.h>
#include <linux/file.h> /* doh, must come after sched.h... */
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/highuid.h>
#include <linux/hugetlb.h>
@@ -33,6 +32,13 @@ arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len
if (len > RGN_MAP_LIMIT)
return -ENOMEM;
+ /* handle fixed mapping: prevent overlap with huge pages */
+ if (flags & MAP_FIXED) {
+ if (is_hugepage_only_range(mm, addr, len))
+ return -EINVAL;
+ return addr;
+ }
+
#ifdef CONFIG_HUGETLB_PAGE
if (REGION_NUMBER(addr) == RGN_HPAGE)
addr = 0;
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 39e0cd3a088..a06667c7acc 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -235,7 +235,7 @@ ia64_init_itm (void)
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_IRQPOLL,
.name = "timer"
};
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 687500ddb4b..94ae3c87d82 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -412,9 +412,11 @@ static int __cpuinit cache_cpu_callback(struct notifier_block *nfb,
sys_dev = get_cpu_sysdev(cpu);
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cache_add_dev(sys_dev);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
cache_remove_dev(sys_dev);
break;
}
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 765cbe5ba6a..5bfb8be02b7 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -16,33 +16,17 @@
#include <linux/hardirq.h>
#include <linux/kprobes.h>
#include <linux/delay.h> /* for ssleep() */
+#include <linux/kdebug.h>
#include <asm/fpswa.h>
#include <asm/ia32.h>
#include <asm/intrinsics.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
-#include <asm/kdebug.h>
fpswa_interface_t *fpswa_interface;
EXPORT_SYMBOL(fpswa_interface);
-ATOMIC_NOTIFIER_HEAD(ia64die_chain);
-
-int
-register_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&ia64die_chain, nb);
-}
-EXPORT_SYMBOL_GPL(register_die_notifier);
-
-int
-unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&ia64die_chain, nb);
-}
-EXPORT_SYMBOL_GPL(unregister_die_notifier);
-
void __init
trap_init (void)
{
diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
index 1e357550c77..fe6aa5a9f8f 100644
--- a/arch/ia64/kernel/unaligned.c
+++ b/arch/ia64/kernel/unaligned.c
@@ -15,7 +15,6 @@
*/
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <asm/intrinsics.h>
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 25dd55e4db2..69238264211 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -78,6 +78,13 @@ SECTIONS
__stop___mca_table = .;
}
+ .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET)
+ {
+ __start___phys_stack_reg_patchlist = .;
+ *(.data.patch.phys_stack_reg)
+ __end___phys_stack_reg_patchlist = .;
+ }
+
/* Global data */
_data = .;
diff --git a/arch/ia64/lib/csum_partial_copy.c b/arch/ia64/lib/csum_partial_copy.c
index 503dfe6d145..118daf5a063 100644
--- a/arch/ia64/lib/csum_partial_copy.c
+++ b/arch/ia64/lib/csum_partial_copy.c
@@ -128,6 +128,8 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
return (__force __wsum)result;
}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
__wsum
csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
{
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 872da7a2acc..94844442812 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -693,6 +693,7 @@ void __init paging_init(void)
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
}
+#ifdef CONFIG_MEMORY_HOTPLUG
pg_data_t *arch_alloc_nodedata(int nid)
{
unsigned long size = compute_pernodesize(nid);
@@ -710,3 +711,4 @@ void arch_refresh_nodedata(int update_node, pg_data_t *update_pgdat)
pgdat_list[update_node] = update_pgdat;
scatter_node_data();
}
+#endif
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 59f3ab93761..21658e02116 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -7,15 +7,14 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kprobes.h>
+#include <linux/kdebug.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include <asm/kdebug.h>
extern void die (char *, struct pt_regs *, long);
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 0c7e94edc20..1346b7f0539 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -13,7 +13,6 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <asm/mman.h>
@@ -148,6 +147,14 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u
return -ENOMEM;
if (len & ~HPAGE_MASK)
return -EINVAL;
+
+ /* Handle MAP_FIXED */
+ if (flags & MAP_FIXED) {
+ if (prepare_hugepage_range(addr, len, pgoff))
+ return -EINVAL;
+ return addr;
+ }
+
/* This code assumes that RGN_HPAGE != 0. */
if ((REGION_NUMBER(addr) != RGN_HPAGE) || (addr & (HPAGE_SIZE - 1)))
addr = HPAGE_REGION_BASE;
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 4f36987eea7..cffb1e8325e 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -121,7 +121,7 @@ lazy_mmu_prot_update (pte_t pte)
return; /* i-cache is already coherent with d-cache */
if (PageCompound(page)) {
- order = (unsigned long) (page[1].lru.prev);
+ order = compound_order(page);
flush_icache_range(addr, addr + (1UL << order << PAGE_SHIFT));
}
else
@@ -355,7 +355,7 @@ setup_gate (void)
void __devinit
ia64_mmu_init (void *my_cpu_data)
{
- unsigned long psr, pta, impl_va_bits;
+ unsigned long pta, impl_va_bits;
extern void __devinit tlb_init (void);
#ifdef CONFIG_DISABLE_VHPT
@@ -364,15 +364,6 @@ ia64_mmu_init (void *my_cpu_data)
# define VHPT_ENABLE_BIT 1
#endif
- /* Pin mapping for percpu area into TLB */
- psr = ia64_clear_ic();
- ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR,
- pte_val(pfn_pte(__pa(my_cpu_data) >> PAGE_SHIFT, PAGE_KERNEL)),
- PERCPU_PAGE_SHIFT);
-
- ia64_set_psr(psr);
- ia64_srlz_i();
-
/*
* Check if the virtually mapped linear page table (VMLPT) overlaps with a mapped
* address space. The IA-64 architecture guarantees that at least 50 bits of
diff --git a/arch/ia64/mm/ioremap.c b/arch/ia64/mm/ioremap.c
index 4280c074d64..2a140627dfd 100644
--- a/arch/ia64/mm/ioremap.c
+++ b/arch/ia64/mm/ioremap.c
@@ -1,5 +1,5 @@
/*
- * (c) Copyright 2006 Hewlett-Packard Development Company, L.P.
+ * (c) Copyright 2006, 2007 Hewlett-Packard Development Company, L.P.
* Bjorn Helgaas <bjorn.helgaas@hp.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -10,51 +10,101 @@
#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/efi.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#include <asm/meminit.h>
static inline void __iomem *
-__ioremap (unsigned long offset, unsigned long size)
+__ioremap (unsigned long phys_addr)
{
- return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset);
+ return (void __iomem *) (__IA64_UNCACHED_OFFSET | phys_addr);
}
void __iomem *
-ioremap (unsigned long offset, unsigned long size)
+ioremap (unsigned long phys_addr, unsigned long size)
{
+ void __iomem *addr;
+ struct vm_struct *area;
+ unsigned long offset;
+ pgprot_t prot;
u64 attr;
unsigned long gran_base, gran_size;
+ unsigned long page_base;
/*
* For things in kern_memmap, we must use the same attribute
* as the rest of the kernel. For more details, see
* Documentation/ia64/aliasing.txt.
*/
- attr = kern_mem_attribute(offset, size);
+ attr = kern_mem_attribute(phys_addr, size);
if (attr & EFI_MEMORY_WB)
- return (void __iomem *) phys_to_virt(offset);
+ return (void __iomem *) phys_to_virt(phys_addr);
else if (attr & EFI_MEMORY_UC)
- return __ioremap(offset, size);
+ return __ioremap(phys_addr);
/*
* Some chipsets don't support UC access to memory. If
* WB is supported for the whole granule, we prefer that.
*/
- gran_base = GRANULEROUNDDOWN(offset);
- gran_size = GRANULEROUNDUP(offset + size) - gran_base;
+ gran_base = GRANULEROUNDDOWN(phys_addr);
+ gran_size = GRANULEROUNDUP(phys_addr + size) - gran_base;
if (efi_mem_attribute(gran_base, gran_size) & EFI_MEMORY_WB)
- return (void __iomem *) phys_to_virt(offset);
+ return (void __iomem *) phys_to_virt(phys_addr);
- return __ioremap(offset, size);
+ /*
+ * WB is not supported for the whole granule, so we can't use
+ * the region 7 identity mapping. If we can safely cover the
+ * area with kernel page table mappings, we can use those
+ * instead.
+ */
+ page_base = phys_addr & PAGE_MASK;
+ size = PAGE_ALIGN(phys_addr + size) - page_base;
+ if (efi_mem_attribute(page_base, size) & EFI_MEMORY_WB) {
+ prot = PAGE_KERNEL;
+
+ /*
+ * Mappings have to be page-aligned
+ */
+ offset = phys_addr & ~PAGE_MASK;
+ phys_addr &= PAGE_MASK;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area)
+ return NULL;
+
+ area->phys_addr = phys_addr;
+ addr = (void __iomem *) area->addr;
+ if (ioremap_page_range((unsigned long) addr,
+ (unsigned long) addr + size, phys_addr, prot)) {
+ vunmap((void __force *) addr);
+ return NULL;
+ }
+
+ return (void __iomem *) (offset + (char __iomem *)addr);
+ }
+
+ return __ioremap(phys_addr);
}
EXPORT_SYMBOL(ioremap);
void __iomem *
-ioremap_nocache (unsigned long offset, unsigned long size)
+ioremap_nocache (unsigned long phys_addr, unsigned long size)
{
- if (kern_mem_attribute(offset, size) & EFI_MEMORY_WB)
+ if (kern_mem_attribute(phys_addr, size) & EFI_MEMORY_WB)
return NULL;
- return __ioremap(offset, size);
+ return __ioremap(phys_addr);
}
EXPORT_SYMBOL(ioremap_nocache);
+
+void
+iounmap (volatile void __iomem *addr)
+{
+ if (REGION_NUMBER(addr) == RGN_GATE)
+ vunmap((void *) ((unsigned long) addr & PAGE_MASK));
+}
+EXPORT_SYMBOL(iounmap);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 0e83f3b419b..3549f3b4259 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <asm/machvec.h>
@@ -659,8 +658,6 @@ pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma)
return -EINVAL;
prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
vma->vm_page_prot);
- if (pgprot_val(prot) != pgprot_val(pgprot_noncached(vma->vm_page_prot)))
- return -EINVAL;
addr = pci_get_legacy_mem(bus);
if (IS_ERR(addr))
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index fcf7f93c4b6..2c3f9dfca78 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -8,7 +8,6 @@
#include <linux/types.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <asm/delay.h>
#include <asm/sn/sn_sal.h>
#include "ioerror.h"
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index 49873aa4a37..83f190ffe35 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -87,7 +87,6 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
if (irq < 0)
return irq;
- set_irq_msi(irq, entry);
/*
* Set up the vector plumbing. Let the prom (via sn_intr_alloc)
* decide which cpu to direct this msi at by default.
@@ -144,10 +143,11 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
*/
msg.data = 0x100 + irq;
+ set_irq_msi(irq, entry);
write_msi_msg(irq, &msg);
set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
- return irq;
+ return 0;
}
#ifdef CONFIG_SMP
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index 68355ef6f84..e336e1692a7 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -55,9 +55,9 @@
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/completion.h>
+#include <linux/kdebug.h>
#include <asm/sn/intr.h>
#include <asm/sn/sn_sal.h>
-#include <asm/kdebug.h>
#include <asm/uaccess.h>
#include <asm/sn/xpc.h>
@@ -1332,7 +1332,7 @@ xpc_init(void)
dev_warn(xpc_part, "can't register reboot notifier\n");
}
- /* add ourselves to the die_notifier list (i.e., ia64die_chain) */
+ /* add ourselves to the die_notifier list */
ret = register_die_notifier(&xpc_die_notifier);
if (ret != 0) {
dev_warn(xpc_part, "can't register die notifier\n");
diff --git a/arch/ia64/sn/kernel/xpnet.c b/arch/ia64/sn/kernel/xpnet.c
index 5419acb89a8..88fad85ceef 100644
--- a/arch/ia64/sn/kernel/xpnet.c
+++ b/arch/ia64/sn/kernel/xpnet.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/netdevice.h>
diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c
index 8cbbb0b11e0..41a4c95e06d 100644
--- a/arch/m32r/kernel/m32r_ksyms.c
+++ b/arch/m32r/kernel/m32r_ksyms.c
@@ -5,7 +5,6 @@
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <asm/semaphore.h>
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index 4b156054baa..916faf6070a 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -13,7 +13,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index 48d376f47e1..3eb30595349 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -43,7 +43,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/irq.h>
#include <linux/bootmem.h>
#include <linux/delay.h>
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
index b4e7bcb4354..bda85548de6 100644
--- a/arch/m32r/kernel/sys_m32r.c
+++ b/arch/m32r/kernel/sys_m32r.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 439cc257cd1..6c73bca3f47 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -110,7 +110,7 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(32);
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c
index 9880abac3f5..88469178ea6 100644
--- a/arch/m32r/mm/fault-nommu.c
+++ b/arch/m32r/mm/fault-nommu.c
@@ -17,7 +17,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index 037d58e82fb..f3935ba2494 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -18,7 +18,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/tty.h>
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index a8e1e604dfa..b8536c7c087 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -409,6 +409,9 @@ config STRAM_PROC
help
Say Y here to report ST-RAM usage statistics in /proc/stram.
+config ATARI_KBD_CORE
+ bool
+
config HEARTBEAT
bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40
default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300
diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile
index 34d826d10f1..c20831a7e1a 100644
--- a/arch/m68k/Makefile
+++ b/arch/m68k/Makefile
@@ -21,7 +21,7 @@ AS += -m68020
LDFLAGS := -m m68kelf
ifneq ($(COMPILE_ARCH),$(ARCH))
# prefix for cross-compiling binaries
- CROSS_COMPILE = m68k-linux-
+ CROSS_COMPILE = m68k-linux-gnu-
endif
ifdef CONFIG_SUN3
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index 28d95cfe8ac..907a5533c84 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -54,7 +54,7 @@ static irqreturn_t ami_int5(int irq, void *dev_id);
static struct irq_controller amiga_irq_controller = {
.name = "amiga",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(amiga_irq_controller.lock),
.enable = amiga_enable_irq,
.disable = amiga_disable_irq,
};
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index 7a20058eb38..c4a4ffd45bc 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -123,7 +123,7 @@ static void cia_disable_irq(unsigned int irq)
static struct irq_controller cia_irq_controller = {
.name = "cia",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cia_irq_controller.lock),
.enable = cia_enable_irq,
.disable = cia_disable_irq,
};
@@ -160,7 +160,7 @@ static void auto_disable_irq(unsigned int irq)
static struct irq_controller auto_irq_controller = {
.name = "auto",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock),
.enable = auto_enable_irq,
.disable = auto_disable_irq,
};
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 3204f412cad..35748531327 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -22,9 +22,7 @@
#include <linux/vt_kern.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#ifdef CONFIG_ZORRO
#include <linux/zorro.h>
-#endif
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -62,55 +60,51 @@ static char s_cdtv[] __initdata = "CDTV";
static char s_cd32[] __initdata = "CD32";
static char s_draco[] __initdata = "Draco";
static char *amiga_models[] __initdata = {
- [AMI_500-AMI_500] = s_a500,
- [AMI_500PLUS-AMI_500] = s_a500p,
- [AMI_600-AMI_500] = s_a600,
- [AMI_1000-AMI_500] = s_a1000,
- [AMI_1200-AMI_500] = s_a1200,
- [AMI_2000-AMI_500] = s_a2000,
- [AMI_2500-AMI_500] = s_a2500,
- [AMI_3000-AMI_500] = s_a3000,
- [AMI_3000T-AMI_500] = s_a3000t,
- [AMI_3000PLUS-AMI_500] = s_a3000p,
- [AMI_4000-AMI_500] = s_a4000,
- [AMI_4000T-AMI_500] = s_a4000t,
- [AMI_CDTV-AMI_500] = s_cdtv,
- [AMI_CD32-AMI_500] = s_cd32,
- [AMI_DRACO-AMI_500] = s_draco,
+ [AMI_500-AMI_500] = s_a500,
+ [AMI_500PLUS-AMI_500] = s_a500p,
+ [AMI_600-AMI_500] = s_a600,
+ [AMI_1000-AMI_500] = s_a1000,
+ [AMI_1200-AMI_500] = s_a1200,
+ [AMI_2000-AMI_500] = s_a2000,
+ [AMI_2500-AMI_500] = s_a2500,
+ [AMI_3000-AMI_500] = s_a3000,
+ [AMI_3000T-AMI_500] = s_a3000t,
+ [AMI_3000PLUS-AMI_500] = s_a3000p,
+ [AMI_4000-AMI_500] = s_a4000,
+ [AMI_4000T-AMI_500] = s_a4000t,
+ [AMI_CDTV-AMI_500] = s_cdtv,
+ [AMI_CD32-AMI_500] = s_cd32,
+ [AMI_DRACO-AMI_500] = s_draco,
};
static char amiga_model_name[13] = "Amiga ";
-extern char m68k_debug_device[];
-
static void amiga_sched_init(irq_handler_t handler);
/* amiga specific irq functions */
-extern void amiga_init_IRQ (void);
+extern void amiga_init_IRQ(void);
static void amiga_get_model(char *model);
static int amiga_get_hardware_list(char *buffer);
/* amiga specific timer functions */
-static unsigned long amiga_gettimeoffset (void);
-static int a3000_hwclk (int, struct rtc_time *);
-static int a2000_hwclk (int, struct rtc_time *);
-static int amiga_set_clock_mmss (unsigned long);
-static unsigned int amiga_get_ss (void);
-extern void amiga_mksound( unsigned int count, unsigned int ticks );
-static void amiga_reset (void);
+static unsigned long amiga_gettimeoffset(void);
+static int a3000_hwclk(int, struct rtc_time *);
+static int a2000_hwclk(int, struct rtc_time *);
+static int amiga_set_clock_mmss(unsigned long);
+static unsigned int amiga_get_ss(void);
+extern void amiga_mksound(unsigned int count, unsigned int ticks);
+static void amiga_reset(void);
extern void amiga_init_sound(void);
-static void amiga_savekmsg_init(void);
static void amiga_mem_console_write(struct console *co, const char *b,
unsigned int count);
void amiga_serial_console_write(struct console *co, const char *s,
unsigned int count);
-static void amiga_debug_init(void);
#ifdef CONFIG_HEARTBEAT
static void amiga_heartbeat(int on);
#endif
static struct console amiga_console_driver = {
- .name = "debug",
- .flags = CON_PRINTBUFFER,
- .index = -1,
+ .name = "debug",
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
@@ -119,24 +113,24 @@ static struct console amiga_console_driver = {
*/
static struct {
- struct resource _ciab, _ciaa, _custom, _kickstart;
+ struct resource _ciab, _ciaa, _custom, _kickstart;
} mb_resources = {
- ._ciab = {
- .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff
- },
- ._ciaa = {
- .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff
- },
- ._custom = {
- .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff
- },
- ._kickstart = {
- .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff
- }
+ ._ciab = {
+ .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff
+ },
+ ._ciaa = {
+ .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff
+ },
+ ._custom = {
+ .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff
+ },
+ ._kickstart = {
+ .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff
+ }
};
static struct resource rtc_resource = {
- .start = 0x00dc0000, .end = 0x00dcffff
+ .start = 0x00dc0000, .end = 0x00dcffff
};
static struct resource ram_resource[NUM_MEMINFO];
@@ -148,57 +142,57 @@ static struct resource ram_resource[NUM_MEMINFO];
int amiga_parse_bootinfo(const struct bi_record *record)
{
- int unknown = 0;
- const unsigned long *data = record->data;
+ int unknown = 0;
+ const unsigned long *data = record->data;
- switch (record->tag) {
+ switch (record->tag) {
case BI_AMIGA_MODEL:
- amiga_model = *data;
- break;
+ amiga_model = *data;
+ break;
case BI_AMIGA_ECLOCK:
- amiga_eclock = *data;
- break;
+ amiga_eclock = *data;
+ break;
case BI_AMIGA_CHIPSET:
- amiga_chipset = *data;
- break;
+ amiga_chipset = *data;
+ break;
case BI_AMIGA_CHIP_SIZE:
- amiga_chip_size = *(const int *)data;
- break;
+ amiga_chip_size = *(const int *)data;
+ break;
case BI_AMIGA_VBLANK:
- amiga_vblank = *(const unsigned char *)data;
- break;
+ amiga_vblank = *(const unsigned char *)data;
+ break;
case BI_AMIGA_PSFREQ:
- amiga_psfreq = *(const unsigned char *)data;
- break;
+ amiga_psfreq = *(const unsigned char *)data;
+ break;
case BI_AMIGA_AUTOCON:
#ifdef CONFIG_ZORRO
- if (zorro_num_autocon < ZORRO_NUM_AUTO) {
- const struct ConfigDev *cd = (struct ConfigDev *)data;
- struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
- dev->rom = cd->cd_Rom;
- dev->slotaddr = cd->cd_SlotAddr;
- dev->slotsize = cd->cd_SlotSize;
- dev->resource.start = (unsigned long)cd->cd_BoardAddr;
- dev->resource.end = dev->resource.start+cd->cd_BoardSize-1;
- } else
- printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
+ if (zorro_num_autocon < ZORRO_NUM_AUTO) {
+ const struct ConfigDev *cd = (struct ConfigDev *)data;
+ struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++];
+ dev->rom = cd->cd_Rom;
+ dev->slotaddr = cd->cd_SlotAddr;
+ dev->slotsize = cd->cd_SlotSize;
+ dev->resource.start = (unsigned long)cd->cd_BoardAddr;
+ dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1;
+ } else
+ printk("amiga_parse_bootinfo: too many AutoConfig devices\n");
#endif /* CONFIG_ZORRO */
- break;
+ break;
case BI_AMIGA_SERPER:
- /* serial port period: ignored here */
- break;
+ /* serial port period: ignored here */
+ break;
default:
- unknown = 1;
- }
- return(unknown);
+ unknown = 1;
+ }
+ return unknown;
}
/*
@@ -207,159 +201,159 @@ int amiga_parse_bootinfo(const struct bi_record *record)
static void __init amiga_identify(void)
{
- /* Fill in some default values, if necessary */
- if (amiga_eclock == 0)
- amiga_eclock = 709379;
-
- memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
-
- printk("Amiga hardware found: ");
- if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) {
- printk("[%s] ", amiga_models[amiga_model-AMI_500]);
- strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]);
- }
-
- switch(amiga_model) {
- case AMI_UNKNOWN:
- goto Generic;
-
- case AMI_600:
- case AMI_1200:
- AMIGAHW_SET(A1200_IDE);
- AMIGAHW_SET(PCMCIA);
- case AMI_500:
- case AMI_500PLUS:
- case AMI_1000:
- case AMI_2000:
- case AMI_2500:
- AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */
- goto Generic;
-
- case AMI_3000:
- case AMI_3000T:
- AMIGAHW_SET(AMBER_FF);
- AMIGAHW_SET(MAGIC_REKICK);
- /* fall through */
- case AMI_3000PLUS:
- AMIGAHW_SET(A3000_SCSI);
- AMIGAHW_SET(A3000_CLK);
- AMIGAHW_SET(ZORRO3);
- goto Generic;
-
- case AMI_4000T:
- AMIGAHW_SET(A4000_SCSI);
- /* fall through */
- case AMI_4000:
- AMIGAHW_SET(A4000_IDE);
- AMIGAHW_SET(A3000_CLK);
- AMIGAHW_SET(ZORRO3);
- goto Generic;
-
- case AMI_CDTV:
- case AMI_CD32:
- AMIGAHW_SET(CD_ROM);
- AMIGAHW_SET(A2000_CLK); /* Is this correct? */
- goto Generic;
-
- Generic:
- AMIGAHW_SET(AMI_VIDEO);
- AMIGAHW_SET(AMI_BLITTER);
- AMIGAHW_SET(AMI_AUDIO);
- AMIGAHW_SET(AMI_FLOPPY);
- AMIGAHW_SET(AMI_KEYBOARD);
- AMIGAHW_SET(AMI_MOUSE);
- AMIGAHW_SET(AMI_SERIAL);
- AMIGAHW_SET(AMI_PARALLEL);
- AMIGAHW_SET(CHIP_RAM);
- AMIGAHW_SET(PAULA);
-
- switch(amiga_chipset) {
- case CS_OCS:
- case CS_ECS:
- case CS_AGA:
- switch (amiga_custom.deniseid & 0xf) {
- case 0x0c:
- AMIGAHW_SET(DENISE_HR);
- break;
- case 0x08:
- AMIGAHW_SET(LISA);
- break;
- }
- break;
- default:
- AMIGAHW_SET(DENISE);
- break;
- }
- switch ((amiga_custom.vposr>>8) & 0x7f) {
- case 0x00:
- AMIGAHW_SET(AGNUS_PAL);
- break;
- case 0x10:
- AMIGAHW_SET(AGNUS_NTSC);
- break;
- case 0x20:
- case 0x21:
- AMIGAHW_SET(AGNUS_HR_PAL);
- break;
- case 0x30:
- case 0x31:
- AMIGAHW_SET(AGNUS_HR_NTSC);
- break;
- case 0x22:
- case 0x23:
- AMIGAHW_SET(ALICE_PAL);
- break;
- case 0x32:
- case 0x33:
- AMIGAHW_SET(ALICE_NTSC);
- break;
- }
- AMIGAHW_SET(ZORRO);
- break;
-
- case AMI_DRACO:
- panic("No support for Draco yet");
-
- default:
- panic("Unknown Amiga Model");
- }
+ /* Fill in some default values, if necessary */
+ if (amiga_eclock == 0)
+ amiga_eclock = 709379;
-#define AMIGAHW_ANNOUNCE(name, str) \
- if (AMIGAHW_PRESENT(name)) \
- printk(str)
-
- AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO ");
- AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER ");
- AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF ");
- AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO ");
- AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY ");
- AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI ");
- AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI ");
- AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE ");
- AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE ");
- AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM ");
- AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD ");
- AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE ");
- AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL ");
- AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL ");
- AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK ");
- AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK ");
- AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM ");
- AMIGAHW_ANNOUNCE(PAULA, "PAULA ");
- AMIGAHW_ANNOUNCE(DENISE, "DENISE ");
- AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR ");
- AMIGAHW_ANNOUNCE(LISA, "LISA ");
- AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL ");
- AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC ");
- AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL ");
- AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC ");
- AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
- AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
- AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
- AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
- if (AMIGAHW_PRESENT(ZORRO))
- printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
- printk("\n");
+ memset(&amiga_hw_present, 0, sizeof(amiga_hw_present));
+
+ printk("Amiga hardware found: ");
+ if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) {
+ printk("[%s] ", amiga_models[amiga_model-AMI_500]);
+ strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]);
+ }
+
+ switch (amiga_model) {
+ case AMI_UNKNOWN:
+ goto Generic;
+
+ case AMI_600:
+ case AMI_1200:
+ AMIGAHW_SET(A1200_IDE);
+ AMIGAHW_SET(PCMCIA);
+ case AMI_500:
+ case AMI_500PLUS:
+ case AMI_1000:
+ case AMI_2000:
+ case AMI_2500:
+ AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */
+ goto Generic;
+
+ case AMI_3000:
+ case AMI_3000T:
+ AMIGAHW_SET(AMBER_FF);
+ AMIGAHW_SET(MAGIC_REKICK);
+ /* fall through */
+ case AMI_3000PLUS:
+ AMIGAHW_SET(A3000_SCSI);
+ AMIGAHW_SET(A3000_CLK);
+ AMIGAHW_SET(ZORRO3);
+ goto Generic;
+
+ case AMI_4000T:
+ AMIGAHW_SET(A4000_SCSI);
+ /* fall through */
+ case AMI_4000:
+ AMIGAHW_SET(A4000_IDE);
+ AMIGAHW_SET(A3000_CLK);
+ AMIGAHW_SET(ZORRO3);
+ goto Generic;
+
+ case AMI_CDTV:
+ case AMI_CD32:
+ AMIGAHW_SET(CD_ROM);
+ AMIGAHW_SET(A2000_CLK); /* Is this correct? */
+ goto Generic;
+
+ Generic:
+ AMIGAHW_SET(AMI_VIDEO);
+ AMIGAHW_SET(AMI_BLITTER);
+ AMIGAHW_SET(AMI_AUDIO);
+ AMIGAHW_SET(AMI_FLOPPY);
+ AMIGAHW_SET(AMI_KEYBOARD);
+ AMIGAHW_SET(AMI_MOUSE);
+ AMIGAHW_SET(AMI_SERIAL);
+ AMIGAHW_SET(AMI_PARALLEL);
+ AMIGAHW_SET(CHIP_RAM);
+ AMIGAHW_SET(PAULA);
+
+ switch (amiga_chipset) {
+ case CS_OCS:
+ case CS_ECS:
+ case CS_AGA:
+ switch (amiga_custom.deniseid & 0xf) {
+ case 0x0c:
+ AMIGAHW_SET(DENISE_HR);
+ break;
+ case 0x08:
+ AMIGAHW_SET(LISA);
+ break;
+ }
+ break;
+ default:
+ AMIGAHW_SET(DENISE);
+ break;
+ }
+ switch ((amiga_custom.vposr>>8) & 0x7f) {
+ case 0x00:
+ AMIGAHW_SET(AGNUS_PAL);
+ break;
+ case 0x10:
+ AMIGAHW_SET(AGNUS_NTSC);
+ break;
+ case 0x20:
+ case 0x21:
+ AMIGAHW_SET(AGNUS_HR_PAL);
+ break;
+ case 0x30:
+ case 0x31:
+ AMIGAHW_SET(AGNUS_HR_NTSC);
+ break;
+ case 0x22:
+ case 0x23:
+ AMIGAHW_SET(ALICE_PAL);
+ break;
+ case 0x32:
+ case 0x33:
+ AMIGAHW_SET(ALICE_NTSC);
+ break;
+ }
+ AMIGAHW_SET(ZORRO);
+ break;
+
+ case AMI_DRACO:
+ panic("No support for Draco yet");
+
+ default:
+ panic("Unknown Amiga Model");
+ }
+
+#define AMIGAHW_ANNOUNCE(name, str) \
+ if (AMIGAHW_PRESENT(name)) \
+ printk(str)
+
+ AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO ");
+ AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER ");
+ AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF ");
+ AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO ");
+ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY ");
+ AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI ");
+ AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI ");
+ AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE ");
+ AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE ");
+ AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM ");
+ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD ");
+ AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE ");
+ AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL ");
+ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL ");
+ AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK ");
+ AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK ");
+ AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM ");
+ AMIGAHW_ANNOUNCE(PAULA, "PAULA ");
+ AMIGAHW_ANNOUNCE(DENISE, "DENISE ");
+ AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR ");
+ AMIGAHW_ANNOUNCE(LISA, "LISA ");
+ AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL ");
+ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC ");
+ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL ");
+ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC ");
+ AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL ");
+ AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC ");
+ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK ");
+ AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA ");
+ if (AMIGAHW_PRESENT(ZORRO))
+ printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : "");
+ printk("\n");
#undef AMIGAHW_ANNOUNCE
}
@@ -370,119 +364,105 @@ static void __init amiga_identify(void)
void __init config_amiga(void)
{
- int i;
-
- amiga_debug_init();
- amiga_identify();
-
- /* Yuk, we don't have PCI memory */
- iomem_resource.name = "Memory";
- for (i = 0; i < 4; i++)
- request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
-
- mach_sched_init = amiga_sched_init;
- mach_init_IRQ = amiga_init_IRQ;
- mach_get_model = amiga_get_model;
- mach_get_hardware_list = amiga_get_hardware_list;
- mach_gettimeoffset = amiga_gettimeoffset;
- if (AMIGAHW_PRESENT(A3000_CLK)){
- mach_hwclk = a3000_hwclk;
- rtc_resource.name = "A3000 RTC";
- request_resource(&iomem_resource, &rtc_resource);
- }
- else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */
- mach_hwclk = a2000_hwclk;
- rtc_resource.name = "A2000 RTC";
- request_resource(&iomem_resource, &rtc_resource);
- }
-
- mach_max_dma_address = 0xffffffff; /*
- * default MAX_DMA=0xffffffff
- * on all machines. If we don't
- * do so, the SCSI code will not
- * be able to allocate any mem
- * for transfers, unless we are
- * dealing with a Z2 mem only
- * system. /Jes
- */
-
- mach_set_clock_mmss = amiga_set_clock_mmss;
- mach_get_ss = amiga_get_ss;
- mach_reset = amiga_reset;
+ int i;
+
+ amiga_identify();
+
+ /* Yuk, we don't have PCI memory */
+ iomem_resource.name = "Memory";
+ for (i = 0; i < 4; i++)
+ request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]);
+
+ mach_sched_init = amiga_sched_init;
+ mach_init_IRQ = amiga_init_IRQ;
+ mach_get_model = amiga_get_model;
+ mach_get_hardware_list = amiga_get_hardware_list;
+ mach_gettimeoffset = amiga_gettimeoffset;
+ if (AMIGAHW_PRESENT(A3000_CLK)) {
+ mach_hwclk = a3000_hwclk;
+ rtc_resource.name = "A3000 RTC";
+ request_resource(&iomem_resource, &rtc_resource);
+ } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ {
+ mach_hwclk = a2000_hwclk;
+ rtc_resource.name = "A2000 RTC";
+ request_resource(&iomem_resource, &rtc_resource);
+ }
+
+ /*
+ * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI
+ * code will not be able to allocate any mem for transfers, unless we are
+ * dealing with a Z2 mem only system. /Jes
+ */
+ mach_max_dma_address = 0xffffffff;
+
+ mach_set_clock_mmss = amiga_set_clock_mmss;
+ mach_get_ss = amiga_get_ss;
+ mach_reset = amiga_reset;
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
- mach_beep = amiga_mksound;
+ mach_beep = amiga_mksound;
#endif
#ifdef CONFIG_HEARTBEAT
- mach_heartbeat = amiga_heartbeat;
+ mach_heartbeat = amiga_heartbeat;
#endif
- /* Fill in the clock values (based on the 700 kHz E-Clock) */
- amiga_masterclock = 40*amiga_eclock; /* 28 MHz */
- amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */
-
- /* clear all DMA bits */
- amiga_custom.dmacon = DMAF_ALL;
- /* ensure that the DMA master bit is set */
- amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
-
- /* don't use Z2 RAM as system memory on Z3 capable machines */
- if (AMIGAHW_PRESENT(ZORRO3)) {
- int i, j;
- u32 disabled_z2mem = 0;
- for (i = 0; i < m68k_num_memory; i++)
- if (m68k_memory[i].addr < 16*1024*1024) {
- if (i == 0) {
- /* don't cut off the branch we're sitting on */
- printk("Warning: kernel runs in Zorro II memory\n");
- continue;
+ /* Fill in the clock values (based on the 700 kHz E-Clock) */
+ amiga_masterclock = 40*amiga_eclock; /* 28 MHz */
+ amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */
+
+ /* clear all DMA bits */
+ amiga_custom.dmacon = DMAF_ALL;
+ /* ensure that the DMA master bit is set */
+ amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER;
+
+ /* don't use Z2 RAM as system memory on Z3 capable machines */
+ if (AMIGAHW_PRESENT(ZORRO3)) {
+ int i, j;
+ u32 disabled_z2mem = 0;
+
+ for (i = 0; i < m68k_num_memory; i++) {
+ if (m68k_memory[i].addr < 16*1024*1024) {
+ if (i == 0) {
+ /* don't cut off the branch we're sitting on */
+ printk("Warning: kernel runs in Zorro II memory\n");
+ continue;
+ }
+ disabled_z2mem += m68k_memory[i].size;
+ m68k_num_memory--;
+ for (j = i; j < m68k_num_memory; j++)
+ m68k_memory[j] = m68k_memory[j+1];
+ i--;
+ }
+ }
+ if (disabled_z2mem)
+ printk("%dK of Zorro II memory will not be used as system memory\n",
+ disabled_z2mem>>10);
}
- disabled_z2mem += m68k_memory[i].size;
- m68k_num_memory--;
- for (j = i; j < m68k_num_memory; j++)
- m68k_memory[j] = m68k_memory[j+1];
- i--;
- }
- if (disabled_z2mem)
- printk("%dK of Zorro II memory will not be used as system memory\n",
- disabled_z2mem>>10);
- }
-
- /* request all RAM */
- for (i = 0; i < m68k_num_memory; i++) {
- ram_resource[i].name =
- (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" :
- (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" :
- "16-bit Slow RAM";
- ram_resource[i].start = m68k_memory[i].addr;
- ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1;
- request_resource(&iomem_resource, &ram_resource[i]);
- }
-
- /* initialize chipram allocator */
- amiga_chip_init ();
-
- /* debugging using chipram */
- if (!strcmp( m68k_debug_device, "mem" )){
- if (!AMIGAHW_PRESENT(CHIP_RAM))
- printk("Warning: no chipram present for debugging\n");
- else {
- amiga_savekmsg_init();
- amiga_console_driver.write = amiga_mem_console_write;
- register_console(&amiga_console_driver);
- }
- }
-
- /* our beloved beeper */
- if (AMIGAHW_PRESENT(AMI_AUDIO))
- amiga_init_sound();
-
- /*
- * if it is an A3000, set the magic bit that forces
- * a hard rekick
- */
- if (AMIGAHW_PRESENT(MAGIC_REKICK))
- *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
+
+ /* request all RAM */
+ for (i = 0; i < m68k_num_memory; i++) {
+ ram_resource[i].name =
+ (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" :
+ (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" :
+ "16-bit Slow RAM";
+ ram_resource[i].start = m68k_memory[i].addr;
+ ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1;
+ request_resource(&iomem_resource, &ram_resource[i]);
+ }
+
+ /* initialize chipram allocator */
+ amiga_chip_init();
+
+ /* our beloved beeper */
+ if (AMIGAHW_PRESENT(AMI_AUDIO))
+ amiga_init_sound();
+
+ /*
+ * if it is an A3000, set the magic bit that forces
+ * a hard rekick
+ */
+ if (AMIGAHW_PRESENT(MAGIC_REKICK))
+ *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80;
}
static unsigned short jiffy_ticks;
@@ -490,12 +470,12 @@ static unsigned short jiffy_ticks;
static void __init amiga_sched_init(irq_handler_t timer_routine)
{
static struct resource sched_res = {
- .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
+ .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
};
jiffy_ticks = (amiga_eclock+HZ/2)/HZ;
if (request_resource(&mb_resources._ciab, &sched_res))
- printk("Cannot allocate ciab.ta{lo,hi}\n");
+ printk("Cannot allocate ciab.ta{lo,hi}\n");
ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */
ciab.talo = jiffy_ticks % 256;
ciab.tahi = jiffy_ticks / 256;
@@ -513,7 +493,7 @@ static void __init amiga_sched_init(irq_handler_t timer_routine)
#define TICK_SIZE 10000
/* This is always executed with interrupts disabled. */
-static unsigned long amiga_gettimeoffset (void)
+static unsigned long amiga_gettimeoffset(void)
{
unsigned short hi, lo, hi2;
unsigned long ticks, offset = 0;
@@ -585,15 +565,15 @@ static int a2000_hwclk(int op, struct rtc_time *t)
tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD;
- while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
- {
- tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
- udelay(70);
- tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
+ while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) {
+ tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
+ udelay(70);
+ tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
}
if (!cnt)
- printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1);
+ printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n",
+ tod_2000.cntrl1);
if (!op) { /* read */
t->tm_sec = tod_2000.second1 * 10 + tod_2000.second2;
@@ -606,7 +586,7 @@ static int a2000_hwclk(int op, struct rtc_time *t)
if (t->tm_year <= 69)
t->tm_year += 100;
- if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){
+ if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) {
if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12)
t->tm_hour = 0;
else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12)
@@ -642,7 +622,7 @@ static int a2000_hwclk(int op, struct rtc_time *t)
return 0;
}
-static int amiga_set_clock_mmss (unsigned long nowtime)
+static int amiga_set_clock_mmss(unsigned long nowtime)
{
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
@@ -660,8 +640,7 @@ static int amiga_set_clock_mmss (unsigned long nowtime)
tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
- while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--)
- {
+ while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) {
tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD;
udelay(70);
tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD;
@@ -681,7 +660,7 @@ static int amiga_set_clock_mmss (unsigned long nowtime)
return 0;
}
-static unsigned int amiga_get_ss( void )
+static unsigned int amiga_get_ss(void)
{
unsigned int s;
@@ -695,71 +674,72 @@ static unsigned int amiga_get_ss( void )
return s;
}
-static NORET_TYPE void amiga_reset( void )
+static NORET_TYPE void amiga_reset(void)
ATTRIB_NORET;
-static void amiga_reset (void)
+static void amiga_reset(void)
{
- unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
- unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
-
- local_irq_disable();
- if (CPU_IS_040_OR_060)
- /* Setup transparent translation registers for mapping
- * of 16 MB kernel segment before disabling translation
- */
- __asm__ __volatile__
- ("movel %0,%/d0\n\t"
- "andl #0xff000000,%/d0\n\t"
- "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
- ".chip 68040\n\t"
- "movec %%d0,%%itt0\n\t"
- "movec %%d0,%%dtt0\n\t"
- ".chip 68k\n\t"
- "jmp %0@\n\t"
- : /* no outputs */
- : "a" (jmp_addr040));
- else
- /* for 680[23]0, just disable translation and jump to the physical
- * address of the label
- */
- __asm__ __volatile__
- ("pmove %/tc,%@\n\t"
- "bclr #7,%@\n\t"
- "pmove %@,%/tc\n\t"
- "jmp %0@\n\t"
- : /* no outputs */
- : "a" (jmp_addr));
- jmp_addr_label040:
- /* disable translation on '040 now */
- __asm__ __volatile__
- ("moveq #0,%/d0\n\t"
- ".chip 68040\n\t"
- "movec %%d0,%%tc\n\t" /* disable MMU */
- ".chip 68k\n\t"
- : /* no outputs */
- : /* no inputs */
- : "d0");
-
- jmp_addr_label:
- /* pickup reset address from AmigaOS ROM, reset devices and jump
- * to reset address
- */
- __asm__ __volatile__
- ("movew #0x2700,%/sr\n\t"
- "leal 0x01000000,%/a0\n\t"
- "subl %/a0@(-0x14),%/a0\n\t"
- "movel %/a0@(4),%/a0\n\t"
- "subql #2,%/a0\n\t"
- "bra 1f\n\t"
- /* align on a longword boundary */
- __ALIGN_STR "\n"
- "1:\n\t"
- "reset\n\t"
- "jmp %/a0@" : /* Just that gcc scans it for % escapes */ );
-
- for (;;);
-
+ unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+ unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label);
+
+ local_irq_disable();
+ if (CPU_IS_040_OR_060)
+ /* Setup transparent translation registers for mapping
+ * of 16 MB kernel segment before disabling translation
+ */
+ asm volatile ("\n"
+ " move.l %0,%%d0\n"
+ " and.l #0xff000000,%%d0\n"
+ " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */
+ " .chip 68040\n"
+ " movec %%d0,%%itt0\n"
+ " movec %%d0,%%dtt0\n"
+ " .chip 68k\n"
+ " jmp %0@\n"
+ : /* no outputs */
+ : "a" (jmp_addr040)
+ : "d0");
+ else
+ /* for 680[23]0, just disable translation and jump to the physical
+ * address of the label
+ */
+ asm volatile ("\n"
+ " pmove %%tc,%@\n"
+ " bclr #7,%@\n"
+ " pmove %@,%%tc\n"
+ " jmp %0@\n"
+ : /* no outputs */
+ : "a" (jmp_addr));
+jmp_addr_label040:
+ /* disable translation on '040 now */
+ asm volatile ("\n"
+ " moveq #0,%%d0\n"
+ " .chip 68040\n"
+ " movec %%d0,%%tc\n" /* disable MMU */
+ " .chip 68k\n"
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+
+ jmp_addr_label:
+ /* pickup reset address from AmigaOS ROM, reset devices and jump
+ * to reset address
+ */
+ asm volatile ("\n"
+ " move.w #0x2700,%sr\n"
+ " lea 0x01000000,%a0\n"
+ " sub.l %a0@(-0x14),%a0\n"
+ " move.l %a0@(4),%a0\n"
+ " subq.l #2,%a0\n"
+ " jra 1f\n"
+ /* align on a longword boundary */
+ " " __ALIGN_STR "\n"
+ "1:\n"
+ " reset\n"
+ " jmp %a0@");
+
+ for (;;)
+ ;
}
@@ -773,11 +753,11 @@ static void amiga_reset (void)
#define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */
struct savekmsg {
- unsigned long magic1; /* SAVEKMSG_MAGIC1 */
- unsigned long magic2; /* SAVEKMSG_MAGIC2 */
- unsigned long magicptr; /* address of magic1 */
- unsigned long size;
- char data[0];
+ unsigned long magic1; /* SAVEKMSG_MAGIC1 */
+ unsigned long magic2; /* SAVEKMSG_MAGIC2 */
+ unsigned long magicptr; /* address of magic1 */
+ unsigned long size;
+ char data[0];
};
static struct savekmsg *savekmsg;
@@ -785,113 +765,132 @@ static struct savekmsg *savekmsg;
static void amiga_mem_console_write(struct console *co, const char *s,
unsigned int count)
{
- if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
- memcpy(savekmsg->data+savekmsg->size, s, count);
- savekmsg->size += count;
- }
+ if (savekmsg->size + count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) {
+ memcpy(savekmsg->data + savekmsg->size, s, count);
+ savekmsg->size += count;
+ }
}
-static void amiga_savekmsg_init(void)
+static int __init amiga_savekmsg_setup(char *arg)
{
- static struct resource debug_res = { .name = "Debug" };
+ static struct resource debug_res = { .name = "Debug" };
+
+ if (!MACH_IS_AMIGA || strcmp(arg, "mem"))
+ goto done;
+
+ if (!AMIGAHW_PRESENT(CHIP_RAM)) {
+ printk("Warning: no chipram present for debugging\n");
+ goto done;
+ }
- savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
- savekmsg->magic1 = SAVEKMSG_MAGIC1;
- savekmsg->magic2 = SAVEKMSG_MAGIC2;
- savekmsg->magicptr = ZTWO_PADDR(savekmsg);
- savekmsg->size = 0;
+ savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res);
+ savekmsg->magic1 = SAVEKMSG_MAGIC1;
+ savekmsg->magic2 = SAVEKMSG_MAGIC2;
+ savekmsg->magicptr = ZTWO_PADDR(savekmsg);
+ savekmsg->size = 0;
+
+ amiga_console_driver.write = amiga_mem_console_write;
+ register_console(&amiga_console_driver);
+
+done:
+ return 0;
}
+early_param("debug", amiga_savekmsg_setup);
+
static void amiga_serial_putc(char c)
{
- amiga_custom.serdat = (unsigned char)c | 0x100;
- while (!(amiga_custom.serdatr & 0x2000))
- ;
+ amiga_custom.serdat = (unsigned char)c | 0x100;
+ while (!(amiga_custom.serdatr & 0x2000))
+ ;
}
void amiga_serial_console_write(struct console *co, const char *s,
- unsigned int count)
+ unsigned int count)
{
- while (count--) {
- if (*s == '\n')
- amiga_serial_putc('\r');
- amiga_serial_putc(*s++);
- }
+ while (count--) {
+ if (*s == '\n')
+ amiga_serial_putc('\r');
+ amiga_serial_putc(*s++);
+ }
}
#ifdef CONFIG_SERIAL_CONSOLE
void amiga_serial_puts(const char *s)
{
- amiga_serial_console_write(NULL, s, strlen(s));
+ amiga_serial_console_write(NULL, s, strlen(s));
}
int amiga_serial_console_wait_key(struct console *co)
{
- int ch;
-
- while (!(amiga_custom.intreqr & IF_RBF))
- barrier();
- ch = amiga_custom.serdatr & 0xff;
- /* clear the interrupt, so that another character can be read */
- amiga_custom.intreq = IF_RBF;
- return ch;
+ int ch;
+
+ while (!(amiga_custom.intreqr & IF_RBF))
+ barrier();
+ ch = amiga_custom.serdatr & 0xff;
+ /* clear the interrupt, so that another character can be read */
+ amiga_custom.intreq = IF_RBF;
+ return ch;
}
void amiga_serial_gets(struct console *co, char *s, int len)
{
- int ch, cnt = 0;
-
- while (1) {
- ch = amiga_serial_console_wait_key(co);
-
- /* Check for backspace. */
- if (ch == 8 || ch == 127) {
- if (cnt == 0) {
- amiga_serial_putc('\007');
- continue;
- }
- cnt--;
- amiga_serial_puts("\010 \010");
- continue;
- }
+ int ch, cnt = 0;
+
+ while (1) {
+ ch = amiga_serial_console_wait_key(co);
+
+ /* Check for backspace. */
+ if (ch == 8 || ch == 127) {
+ if (cnt == 0) {
+ amiga_serial_putc('\007');
+ continue;
+ }
+ cnt--;
+ amiga_serial_puts("\010 \010");
+ continue;
+ }
- /* Check for enter. */
- if (ch == 10 || ch == 13)
- break;
+ /* Check for enter. */
+ if (ch == 10 || ch == 13)
+ break;
- /* See if line is too long. */
- if (cnt >= len + 1) {
- amiga_serial_putc(7);
- cnt--;
- continue;
- }
+ /* See if line is too long. */
+ if (cnt >= len + 1) {
+ amiga_serial_putc(7);
+ cnt--;
+ continue;
+ }
- /* Store and echo character. */
- s[cnt++] = ch;
- amiga_serial_putc(ch);
- }
- /* Print enter. */
- amiga_serial_puts("\r\n");
- s[cnt] = 0;
+ /* Store and echo character. */
+ s[cnt++] = ch;
+ amiga_serial_putc(ch);
+ }
+ /* Print enter. */
+ amiga_serial_puts("\r\n");
+ s[cnt] = 0;
}
#endif
-static void __init amiga_debug_init(void)
+static int __init amiga_debug_setup(char *arg)
{
- if (!strcmp( m68k_debug_device, "ser" )) {
+ if (MACH_IS_AMIGA && !strcmp(arg, "ser")) {
/* no initialization required (?) */
amiga_console_driver.write = amiga_serial_console_write;
register_console(&amiga_console_driver);
}
+ return 0;
}
+early_param("debug", amiga_debug_setup);
+
#ifdef CONFIG_HEARTBEAT
static void amiga_heartbeat(int on)
{
- if (on)
- ciaa.pra &= ~2;
- else
- ciaa.pra |= 2;
+ if (on)
+ ciaa.pra &= ~2;
+ else
+ ciaa.pra |= 2;
}
#endif
@@ -901,81 +900,81 @@ static void amiga_heartbeat(int on)
static void amiga_get_model(char *model)
{
- strcpy(model, amiga_model_name);
+ strcpy(model, amiga_model_name);
}
static int amiga_get_hardware_list(char *buffer)
{
- int len = 0;
-
- if (AMIGAHW_PRESENT(CHIP_RAM))
- len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10);
- len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
- amiga_psfreq, amiga_eclock);
- if (AMIGAHW_PRESENT(AMI_VIDEO)) {
- char *type;
- switch(amiga_chipset) {
- case CS_OCS:
- type = "OCS";
- break;
- case CS_ECS:
- type = "ECS";
- break;
- case CS_AGA:
- type = "AGA";
- break;
- default:
- type = "Old or Unknown";
- break;
+ int len = 0;
+
+ if (AMIGAHW_PRESENT(CHIP_RAM))
+ len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10);
+ len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n",
+ amiga_psfreq, amiga_eclock);
+ if (AMIGAHW_PRESENT(AMI_VIDEO)) {
+ char *type;
+ switch (amiga_chipset) {
+ case CS_OCS:
+ type = "OCS";
+ break;
+ case CS_ECS:
+ type = "ECS";
+ break;
+ case CS_AGA:
+ type = "AGA";
+ break;
+ default:
+ type = "Old or Unknown";
+ break;
+ }
+ len += sprintf(buffer+len, "Graphics:\t%s\n", type);
}
- len += sprintf(buffer+len, "Graphics:\t%s\n", type);
- }
#define AMIGAHW_ANNOUNCE(name, str) \
- if (AMIGAHW_PRESENT(name)) \
- len += sprintf (buffer+len, "\t%s\n", str)
-
- len += sprintf (buffer + len, "Detected hardware:\n");
-
- AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
- AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
- AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
- AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
- AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
- AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
- AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
- AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
- AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
- AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
- AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
- AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
- AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
- AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
- AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
- AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
- AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
- AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
- AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
- AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
- AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
- AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
- AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
- AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
- AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
- AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
- AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
- AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
- AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
+ if (AMIGAHW_PRESENT(name)) \
+ len += sprintf (buffer+len, "\t%s\n", str)
+
+ len += sprintf (buffer + len, "Detected hardware:\n");
+
+ AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video");
+ AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter");
+ AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer");
+ AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio");
+ AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller");
+ AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)");
+ AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)");
+ AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)");
+ AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)");
+ AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive");
+ AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard");
+ AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port");
+ AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port");
+ AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port");
+ AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)");
+ AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)");
+ AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM");
+ AMIGAHW_ANNOUNCE(PAULA, "Paula 8364");
+ AMIGAHW_ANNOUNCE(DENISE, "Denise 8362");
+ AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373");
+ AMIGAHW_ANNOUNCE(LISA, "Lisa 8375");
+ AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371");
+ AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370");
+ AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372");
+ AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372");
+ AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374");
+ AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374");
+ AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick");
+ AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot");
#ifdef CONFIG_ZORRO
- if (AMIGAHW_PRESENT(ZORRO))
- len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion "
- "Device%s\n",
- AMIGAHW_PRESENT(ZORRO3) ? "I" : "",
- zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
+ if (AMIGAHW_PRESENT(ZORRO))
+ len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion "
+ "Device%s\n",
+ AMIGAHW_PRESENT(ZORRO3) ? "I" : "",
+ zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s");
#endif /* CONFIG_ZORRO */
#undef AMIGAHW_ANNOUNCE
- return(len);
+ return len;
}
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index 4274af12599..13bd41bed28 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -31,7 +31,7 @@ void apollo_irq_shutdown(unsigned int irq)
static struct irq_controller apollo_irq_controller = {
.name = "apollo",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(apollo_irq_controller.lock),
.startup = apollo_irq_startup,
.shutdown = apollo_irq_shutdown,
};
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
index 8cb6236b39d..2cb86191f0a 100644
--- a/arch/m68k/atari/Makefile
+++ b/arch/m68k/atari/Makefile
@@ -8,3 +8,4 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \
ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_HADES) += hades-pci.o
endif
+obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index 7f812641790..b85ca22024c 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -339,7 +339,7 @@ static void atari_shutdown_irq(unsigned int irq)
static struct irq_controller atari_irq_controller = {
.name = "atari",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(atari_irq_controller.lock),
.startup = atari_startup_irq,
.shutdown = atari_shutdown_irq,
.enable = atari_enable_irq,
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
new file mode 100644
index 00000000000..1c29603b16b
--- /dev/null
+++ b/arch/m68k/atari/atakeyb.c
@@ -0,0 +1,730 @@
+/*
+ * linux/atari/atakeyb.c
+ *
+ * Atari Keyboard driver for 680x0 Linux
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ * Atari support by Robert de Vries
+ * enhanced by Bjoern Brauel and Roman Hodek
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/keyboard.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/kd.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/kbd_kern.h>
+
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/atari_joystick.h>
+#include <asm/irq.h>
+
+static void atakeyb_rep(unsigned long ignore);
+extern unsigned int keymap_count;
+
+/* Hook for MIDI serial driver */
+void (*atari_MIDI_interrupt_hook) (void);
+/* Hook for mouse driver */
+void (*atari_mouse_interrupt_hook) (char *);
+/* Hook for keyboard inputdev driver */
+void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
+/* Hook for mouse inputdev driver */
+void (*atari_input_mouse_interrupt_hook) (char *);
+
+/* variables for IKBD self test: */
+
+/* state: 0: off; >0: in progress; >1: 0xf1 received */
+static volatile int ikbd_self_test;
+/* timestamp when last received a char */
+static volatile unsigned long self_test_last_rcv;
+/* bitmap of keys reported as broken */
+static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
+
+#define BREAK_MASK (0x80)
+
+/*
+ * ++roman: The following changes were applied manually:
+ *
+ * - The Alt (= Meta) key works in combination with Shift and
+ * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
+ * Meta-Ctrl-A (0x81) ...
+ *
+ * - The parentheses on the keypad send '(' and ')' with all
+ * modifiers (as would do e.g. keypad '+'), but they cannot be used as
+ * application keys (i.e. sending Esc O c).
+ *
+ * - HELP and UNDO are mapped to be F21 and F24, resp, that send the
+ * codes "\E[M" and "\E[P". (This is better than the old mapping to
+ * F11 and F12, because these codes are on Shift+F1/2 anyway.) This
+ * way, applications that allow their own keyboard mappings
+ * (e.g. tcsh, X Windows) can be configured to use them in the way
+ * the label suggests (providing help or undoing).
+ *
+ * - Console switching is done with Alt+Fx (consoles 1..10) and
+ * Shift+Alt+Fx (consoles 11..20).
+ *
+ * - The misc. special function implemented in the kernel are mapped
+ * to the following key combinations:
+ *
+ * ClrHome -> Home/Find
+ * Shift + ClrHome -> End/Select
+ * Shift + Up -> Page Up
+ * Shift + Down -> Page Down
+ * Alt + Help -> show system status
+ * Shift + Help -> show memory info
+ * Ctrl + Help -> show registers
+ * Ctrl + Alt + Del -> Reboot
+ * Alt + Undo -> switch to last console
+ * Shift + Undo -> send interrupt
+ * Alt + Insert -> stop/start output (same as ^S/^Q)
+ * Alt + Up -> Scroll back console (if implemented)
+ * Alt + Down -> Scroll forward console (if implemented)
+ * Alt + CapsLock -> NumLock
+ *
+ * ++Andreas:
+ *
+ * - Help mapped to K_HELP
+ * - Undo mapped to K_UNDO (= K_F246)
+ * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
+ */
+
+static u_short ataplain_map[NR_KEYS] __initdata = {
+ 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
+ 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
+ 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
+ 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
+ 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
+ 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
+ 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
+ 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+ 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
+ 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
+ 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+ 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
+ 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+ 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
+};
+
+typedef enum kb_state_t {
+ KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
+} KB_STATE_T;
+
+#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb)
+
+typedef struct keyboard_state {
+ unsigned char buf[6];
+ int len;
+ KB_STATE_T state;
+} KEYBOARD_STATE;
+
+KEYBOARD_STATE kb_state;
+
+#define DEFAULT_KEYB_REP_DELAY (HZ/4)
+#define DEFAULT_KEYB_REP_RATE (HZ/25)
+
+/* These could be settable by some ioctl() in future... */
+static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
+static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
+
+static unsigned char rep_scancode;
+static struct timer_list atakeyb_rep_timer = {
+ .function = atakeyb_rep,
+};
+
+static void atakeyb_rep(unsigned long ignore)
+{
+ /* Disable keyboard for the time we call handle_scancode(), else a race
+ * in the keyboard tty queue may happen */
+ atari_disable_irq(IRQ_MFP_ACIA);
+ del_timer(&atakeyb_rep_timer);
+
+ /* A keyboard int may have come in before we disabled the irq, so
+ * double-check whether rep_scancode is still != 0 */
+ if (rep_scancode) {
+ init_timer(&atakeyb_rep_timer);
+ atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
+ add_timer(&atakeyb_rep_timer);
+
+ //handle_scancode(rep_scancode, 1);
+ if (atari_input_keyboard_interrupt_hook)
+ atari_input_keyboard_interrupt_hook(rep_scancode, 1);
+ }
+
+ atari_enable_irq(IRQ_MFP_ACIA);
+}
+
+
+/* ++roman: If a keyboard overrun happened, we can't tell in general how much
+ * bytes have been lost and in which state of the packet structure we are now.
+ * This usually causes keyboards bytes to be interpreted as mouse movements
+ * and vice versa, which is very annoying. It seems better to throw away some
+ * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
+ * introduced the RESYNC state for IKBD data. In this state, the bytes up to
+ * one that really looks like a key event (0x04..0xf2) or the start of a mouse
+ * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
+ * speeds up the resynchronization of the event structure, even if maybe a
+ * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
+ * it's really hard to decide whether they're mouse or keyboard bytes. Since
+ * overruns usually occur when moving the Atari mouse rapidly, they're seen as
+ * mouse bytes here. If this is wrong, only a make code of the keyboard gets
+ * lost, which isn't too bad. Loosing a break code would be disastrous,
+ * because then the keyboard repeat strikes...
+ */
+
+static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
+{
+ u_char acia_stat;
+ int scancode;
+ int break_flag;
+
+repeat:
+ if (acia.mid_ctrl & ACIA_IRQ)
+ if (atari_MIDI_interrupt_hook)
+ atari_MIDI_interrupt_hook();
+ acia_stat = acia.key_ctrl;
+ /* check out if the interrupt came from this ACIA */
+ if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
+ return IRQ_HANDLED;
+
+ if (acia_stat & ACIA_OVRN) {
+ /* a very fast typist or a slow system, give a warning */
+ /* ...happens often if interrupts were disabled for too long */
+ printk(KERN_DEBUG "Keyboard overrun\n");
+ scancode = acia.key_data;
+ /* Turn off autorepeating in case a break code has been lost */
+ del_timer(&atakeyb_rep_timer);
+ rep_scancode = 0;
+ if (ikbd_self_test)
+ /* During self test, don't do resyncing, just process the code */
+ goto interpret_scancode;
+ else if (IS_SYNC_CODE(scancode)) {
+ /* This code seem already to be the start of a new packet or a
+ * single scancode */
+ kb_state.state = KEYBOARD;
+ goto interpret_scancode;
+ } else {
+ /* Go to RESYNC state and skip this byte */
+ kb_state.state = RESYNC;
+ kb_state.len = 1; /* skip max. 1 another byte */
+ goto repeat;
+ }
+ }
+
+ if (acia_stat & ACIA_RDRF) {
+ /* received a character */
+ scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */
+ tasklet_schedule(&keyboard_tasklet);
+ interpret_scancode:
+ switch (kb_state.state) {
+ case KEYBOARD:
+ switch (scancode) {
+ case 0xF7:
+ kb_state.state = AMOUSE;
+ kb_state.len = 0;
+ break;
+
+ case 0xF8:
+ case 0xF9:
+ case 0xFA:
+ case 0xFB:
+ kb_state.state = RMOUSE;
+ kb_state.len = 1;
+ kb_state.buf[0] = scancode;
+ break;
+
+ case 0xFC:
+ kb_state.state = CLOCK;
+ kb_state.len = 0;
+ break;
+
+ case 0xFE:
+ case 0xFF:
+ kb_state.state = JOYSTICK;
+ kb_state.len = 1;
+ kb_state.buf[0] = scancode;
+ break;
+
+ case 0xF1:
+ /* during self-test, note that 0xf1 received */
+ if (ikbd_self_test) {
+ ++ikbd_self_test;
+ self_test_last_rcv = jiffies;
+ break;
+ }
+ /* FALL THROUGH */
+
+ default:
+ break_flag = scancode & BREAK_MASK;
+ scancode &= ~BREAK_MASK;
+ if (ikbd_self_test) {
+ /* Scancodes sent during the self-test stand for broken
+ * keys (keys being down). The code *should* be a break
+ * code, but nevertheless some AT keyboard interfaces send
+ * make codes instead. Therefore, simply ignore
+ * break_flag...
+ */
+ int keyval = plain_map[scancode], keytyp;
+
+ set_bit(scancode, broken_keys);
+ self_test_last_rcv = jiffies;
+ keyval = plain_map[scancode];
+ keytyp = KTYP(keyval) - 0xf0;
+ keyval = KVAL(keyval);
+
+ printk(KERN_WARNING "Key with scancode %d ", scancode);
+ if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
+ if (keyval < ' ')
+ printk("('^%c') ", keyval + '@');
+ else
+ printk("('%c') ", keyval);
+ }
+ printk("is broken -- will be ignored.\n");
+ break;
+ } else if (test_bit(scancode, broken_keys))
+ break;
+
+#if 0 // FIXME; hangs at boot
+ if (break_flag) {
+ del_timer(&atakeyb_rep_timer);
+ rep_scancode = 0;
+ } else {
+ del_timer(&atakeyb_rep_timer);
+ rep_scancode = scancode;
+ atakeyb_rep_timer.expires = jiffies + key_repeat_delay;
+ add_timer(&atakeyb_rep_timer);
+ }
+#endif
+
+ // handle_scancode(scancode, !break_flag);
+ if (atari_input_keyboard_interrupt_hook)
+ atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
+ break;
+ }
+ break;
+
+ case AMOUSE:
+ kb_state.buf[kb_state.len++] = scancode;
+ if (kb_state.len == 5) {
+ kb_state.state = KEYBOARD;
+ /* not yet used */
+ /* wake up someone waiting for this */
+ }
+ break;
+
+ case RMOUSE:
+ kb_state.buf[kb_state.len++] = scancode;
+ if (kb_state.len == 3) {
+ kb_state.state = KEYBOARD;
+ if (atari_mouse_interrupt_hook)
+ atari_mouse_interrupt_hook(kb_state.buf);
+ }
+ break;
+
+ case JOYSTICK:
+ kb_state.buf[1] = scancode;
+ kb_state.state = KEYBOARD;
+#ifdef FIXED_ATARI_JOYSTICK
+ atari_joystick_interrupt(kb_state.buf);
+#endif
+ break;
+
+ case CLOCK:
+ kb_state.buf[kb_state.len++] = scancode;
+ if (kb_state.len == 6) {
+ kb_state.state = KEYBOARD;
+ /* wake up someone waiting for this.
+ But will this ever be used, as Linux keeps its own time.
+ Perhaps for synchronization purposes? */
+ /* wake_up_interruptible(&clock_wait); */
+ }
+ break;
+
+ case RESYNC:
+ if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
+ kb_state.state = KEYBOARD;
+ goto interpret_scancode;
+ }
+ kb_state.len--;
+ break;
+ }
+ }
+
+#if 0
+ if (acia_stat & ACIA_CTS)
+ /* cannot happen */;
+#endif
+
+ if (acia_stat & (ACIA_FE | ACIA_PE)) {
+ printk("Error in keyboard communication\n");
+ }
+
+ /* handle_scancode() can take a lot of time, so check again if
+ * some character arrived
+ */
+ goto repeat;
+}
+
+/*
+ * I write to the keyboard without using interrupts, I poll instead.
+ * This takes for the maximum length string allowed (7) at 7812.5 baud
+ * 8 data 1 start 1 stop bit: 9.0 ms
+ * If this takes too long for normal operation, interrupt driven writing
+ * is the solution. (I made a feeble attempt in that direction but I
+ * kept it simple for now.)
+ */
+void ikbd_write(const char *str, int len)
+{
+ u_char acia_stat;
+
+ if ((len < 1) || (len > 7))
+ panic("ikbd: maximum string length exceeded");
+ while (len) {
+ acia_stat = acia.key_ctrl;
+ if (acia_stat & ACIA_TDRE) {
+ acia.key_data = *str++;
+ len--;
+ }
+ }
+}
+
+/* Reset (without touching the clock) */
+void ikbd_reset(void)
+{
+ static const char cmd[2] = { 0x80, 0x01 };
+
+ ikbd_write(cmd, 2);
+
+ /*
+ * if all's well code 0xF1 is returned, else the break codes of
+ * all keys making contact
+ */
+}
+
+/* Set mouse button action */
+void ikbd_mouse_button_action(int mode)
+{
+ char cmd[2] = { 0x07, mode };
+
+ ikbd_write(cmd, 2);
+}
+
+/* Set relative mouse position reporting */
+void ikbd_mouse_rel_pos(void)
+{
+ static const char cmd[1] = { 0x08 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Set absolute mouse position reporting */
+void ikbd_mouse_abs_pos(int xmax, int ymax)
+{
+ char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
+
+ ikbd_write(cmd, 5);
+}
+
+/* Set mouse keycode mode */
+void ikbd_mouse_kbd_mode(int dx, int dy)
+{
+ char cmd[3] = { 0x0A, dx, dy };
+
+ ikbd_write(cmd, 3);
+}
+
+/* Set mouse threshold */
+void ikbd_mouse_thresh(int x, int y)
+{
+ char cmd[3] = { 0x0B, x, y };
+
+ ikbd_write(cmd, 3);
+}
+
+/* Set mouse scale */
+void ikbd_mouse_scale(int x, int y)
+{
+ char cmd[3] = { 0x0C, x, y };
+
+ ikbd_write(cmd, 3);
+}
+
+/* Interrogate mouse position */
+void ikbd_mouse_pos_get(int *x, int *y)
+{
+ static const char cmd[1] = { 0x0D };
+
+ ikbd_write(cmd, 1);
+
+ /* wait for returning bytes */
+}
+
+/* Load mouse position */
+void ikbd_mouse_pos_set(int x, int y)
+{
+ char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
+
+ ikbd_write(cmd, 6);
+}
+
+/* Set Y=0 at bottom */
+void ikbd_mouse_y0_bot(void)
+{
+ static const char cmd[1] = { 0x0F };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Set Y=0 at top */
+void ikbd_mouse_y0_top(void)
+{
+ static const char cmd[1] = { 0x10 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Resume */
+void ikbd_resume(void)
+{
+ static const char cmd[1] = { 0x11 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Disable mouse */
+void ikbd_mouse_disable(void)
+{
+ static const char cmd[1] = { 0x12 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Pause output */
+void ikbd_pause(void)
+{
+ static const char cmd[1] = { 0x13 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Set joystick event reporting */
+void ikbd_joystick_event_on(void)
+{
+ static const char cmd[1] = { 0x14 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Set joystick interrogation mode */
+void ikbd_joystick_event_off(void)
+{
+ static const char cmd[1] = { 0x15 };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Joystick interrogation */
+void ikbd_joystick_get_state(void)
+{
+ static const char cmd[1] = { 0x16 };
+
+ ikbd_write(cmd, 1);
+}
+
+#if 0
+/* This disables all other ikbd activities !!!! */
+/* Set joystick monitoring */
+void ikbd_joystick_monitor(int rate)
+{
+ static const char cmd[2] = { 0x17, rate };
+
+ ikbd_write(cmd, 2);
+
+ kb_state.state = JOYSTICK_MONITOR;
+}
+#endif
+
+/* some joystick routines not in yet (0x18-0x19) */
+
+/* Disable joysticks */
+void ikbd_joystick_disable(void)
+{
+ static const char cmd[1] = { 0x1A };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Time-of-day clock set */
+void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
+{
+ char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
+
+ ikbd_write(cmd, 7);
+}
+
+/* Interrogate time-of-day clock */
+void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
+{
+ static const char cmd[1] = { 0x1C };
+
+ ikbd_write(cmd, 1);
+}
+
+/* Memory load */
+void ikbd_mem_write(int address, int size, char *data)
+{
+ panic("Attempt to write data into keyboard memory");
+}
+
+/* Memory read */
+void ikbd_mem_read(int address, char data[6])
+{
+ char cmd[3] = { 0x21, address>>8, address&0xFF };
+
+ ikbd_write(cmd, 3);
+
+ /* receive data and put it in data */
+}
+
+/* Controller execute */
+void ikbd_exec(int address)
+{
+ char cmd[3] = { 0x22, address>>8, address&0xFF };
+
+ ikbd_write(cmd, 3);
+}
+
+/* Status inquiries (0x87-0x9A) not yet implemented */
+
+/* Set the state of the caps lock led. */
+void atari_kbd_leds(unsigned int leds)
+{
+ char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
+
+ ikbd_write(cmd, 6);
+}
+
+/*
+ * The original code sometimes left the interrupt line of
+ * the ACIAs low forever. I hope, it is fixed now.
+ *
+ * Martin Rogge, 20 Aug 1995
+ */
+
+static int atari_keyb_done = 0;
+
+int __init atari_keyb_init(void)
+{
+ if (atari_keyb_done)
+ return 0;
+
+ /* setup key map */
+ memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
+
+ kb_state.state = KEYBOARD;
+ kb_state.len = 0;
+
+ request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW,
+ "keyboard/mouse/MIDI", atari_keyboard_interrupt);
+
+ atari_turnoff_irq(IRQ_MFP_ACIA);
+ do {
+ /* reset IKBD ACIA */
+ acia.key_ctrl = ACIA_RESET |
+ (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
+ (void)acia.key_ctrl;
+ (void)acia.key_data;
+
+ /* reset MIDI ACIA */
+ acia.mid_ctrl = ACIA_RESET |
+ (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
+ (void)acia.mid_ctrl;
+ (void)acia.mid_data;
+
+ /* divide 500kHz by 64 gives 7812.5 baud */
+ /* 8 data no parity 1 start 1 stop bit */
+ /* receive interrupt enabled */
+ /* RTS low (except if switch selected), transmit interrupt disabled */
+ acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
+ ((atari_switches & ATARI_SWITCH_IKBD) ?
+ ACIA_RHTID : ACIA_RLTID);
+
+ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
+ (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
+
+ /* make sure the interrupt line is up */
+ } while ((mfp.par_dt_reg & 0x10) == 0);
+
+ /* enable ACIA Interrupts */
+ mfp.active_edge &= ~0x10;
+ atari_turnon_irq(IRQ_MFP_ACIA);
+
+ ikbd_self_test = 1;
+ ikbd_reset();
+ /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
+ * self-test is finished */
+ self_test_last_rcv = jiffies;
+ while (time_before(jiffies, self_test_last_rcv + HZ/4))
+ barrier();
+ /* if not incremented: no 0xf1 received */
+ if (ikbd_self_test == 1)
+ printk(KERN_ERR "WARNING: keyboard self test failed!\n");
+ ikbd_self_test = 0;
+
+ ikbd_mouse_disable();
+ ikbd_joystick_disable();
+
+#ifdef FIXED_ATARI_JOYSTICK
+ atari_joystick_init();
+#endif
+
+ // flag init done
+ atari_keyb_done = 1;
+ return 0;
+}
+
+
+int atari_kbdrate(struct kbd_repeat *k)
+{
+ if (k->delay > 0) {
+ /* convert from msec to jiffies */
+ key_repeat_delay = (k->delay * HZ + 500) / 1000;
+ if (key_repeat_delay < 1)
+ key_repeat_delay = 1;
+ }
+ if (k->period > 0) {
+ key_repeat_rate = (k->period * HZ + 500) / 1000;
+ if (key_repeat_rate < 1)
+ key_repeat_rate = 1;
+ }
+
+ k->delay = key_repeat_delay * 1000 / HZ;
+ k->period = key_repeat_rate * 1000 / HZ;
+
+ return 0;
+}
+
+int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
+{
+#ifdef CONFIG_MAGIC_SYSRQ
+ /* ALT+HELP pressed? */
+ if ((keycode == 98) && ((shift_state & 0xff) == 8))
+ *keycodep = 0xff;
+ else
+#endif
+ *keycodep = keycode;
+ return 1;
+}
diff --git a/arch/m68k/atari/atasound.h b/arch/m68k/atari/atasound.h
deleted file mode 100644
index 1362762b8c0..00000000000
--- a/arch/m68k/atari/atasound.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-
-#define SND_NDEVS 256 /* Number of supported devices */
-#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- synthesizer and MIDI output) */
-#define SND_DEV_MIDIN 2 /* Raw midi access */
-#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6 /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS SND_DEV_SNDPROC
-
-#define DSP_DEFAULT_SPEED 8000
-
-#define ON 1
-#define OFF 0
-
-#define MAX_AUDIO_DEV 5
-#define MAX_MIXER_DEV 2
-#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 6
-#define MAX_TIMER_DEV 3
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index ca5cd4344e3..e40e5dcaa34 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -50,70 +50,25 @@ int atari_dont_touch_floppy_select;
int atari_rtc_year_offset;
/* local function prototypes */
-static void atari_reset( void );
+static void atari_reset(void);
static void atari_get_model(char *model);
static int atari_get_hardware_list(char *buffer);
/* atari specific irq functions */
extern void atari_init_IRQ (void);
-extern void atari_mksound( unsigned int count, unsigned int ticks );
+extern void atari_mksound(unsigned int count, unsigned int ticks);
#ifdef CONFIG_HEARTBEAT
-static void atari_heartbeat( int on );
+static void atari_heartbeat(int on);
#endif
/* atari specific timer functions (in time.c) */
-extern void atari_sched_init(irq_handler_t );
+extern void atari_sched_init(irq_handler_t);
extern unsigned long atari_gettimeoffset (void);
extern int atari_mste_hwclk (int, struct rtc_time *);
extern int atari_tt_hwclk (int, struct rtc_time *);
extern int atari_mste_set_clock_mmss (unsigned long);
extern int atari_tt_set_clock_mmss (unsigned long);
-/* atari specific debug functions (in debug.c) */
-extern void atari_debug_init(void);
-
-
-/* I've moved hwreg_present() and hwreg_present_bywrite() out into
- * mm/hwtest.c, to avoid having multiple copies of the same routine
- * in the kernel [I wanted them in hp300 and they were already used
- * in the nubus code. NB: I don't have an Atari so this might (just
- * conceivably) break something.
- * I've preserved the #if 0 version of hwreg_present_bywrite() here
- * for posterity.
- * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998
- */
-
-#if 0
-static int __init
-hwreg_present_bywrite(volatile void *regp, unsigned char val)
-{
- int ret;
- long save_sp, save_vbr;
- static long tmp_vectors[3] = { [2] = (long)&&after_test };
-
- __asm__ __volatile__
- ( "movec %/vbr,%2\n\t" /* save vbr value */
- "movec %4,%/vbr\n\t" /* set up temporary vectors */
- "movel %/sp,%1\n\t" /* save sp */
- "moveq #0,%0\n\t" /* assume not present */
- "moveb %5,%3@\n\t" /* write the hardware reg */
- "cmpb %3@,%5\n\t" /* compare it */
- "seq %0" /* comes here only if reg */
- /* is present */
- : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr)
- : "a" (regp), "r" (tmp_vectors), "d" (val)
- );
- after_test:
- __asm__ __volatile__
- ( "movel %0,%/sp\n\t" /* restore sp */
- "movec %1,%/vbr" /* restore vbr */
- : : "r" (save_sp), "r" (save_vbr) : "sp"
- );
-
- return( ret );
-}
-#endif
-
/* ++roman: This is a more elaborate test for an SCC chip, since the plain
* Medusa board generates DTACK at the SCC's standard addresses, but a SCC
@@ -123,26 +78,34 @@ hwreg_present_bywrite(volatile void *regp, unsigned char val)
* should be readable without trouble (from channel A!).
*/
-static int __init scc_test( volatile char *ctla )
+static int __init scc_test(volatile char *ctla)
{
- if (!hwreg_present( ctla ))
- return( 0 );
+ if (!hwreg_present(ctla))
+ return 0;
MFPDELAY();
- *ctla = 2; MFPDELAY();
- *ctla = 0x40; MFPDELAY();
+ *ctla = 2;
+ MFPDELAY();
+ *ctla = 0x40;
+ MFPDELAY();
- *ctla = 2; MFPDELAY();
- if (*ctla != 0x40) return( 0 );
+ *ctla = 2;
+ MFPDELAY();
+ if (*ctla != 0x40)
+ return 0;
MFPDELAY();
- *ctla = 2; MFPDELAY();
- *ctla = 0x60; MFPDELAY();
+ *ctla = 2;
+ MFPDELAY();
+ *ctla = 0x60;
+ MFPDELAY();
- *ctla = 2; MFPDELAY();
- if (*ctla != 0x60) return( 0 );
+ *ctla = 2;
+ MFPDELAY();
+ if (*ctla != 0x60)
+ return 0;
- return( 1 );
+ return 1;
}
@@ -152,61 +115,66 @@ static int __init scc_test( volatile char *ctla )
int __init atari_parse_bootinfo(const struct bi_record *record)
{
- int unknown = 0;
- const u_long *data = record->data;
+ int unknown = 0;
+ const u_long *data = record->data;
- switch (record->tag) {
+ switch (record->tag) {
case BI_ATARI_MCH_COOKIE:
- atari_mch_cookie = *data;
- break;
+ atari_mch_cookie = *data;
+ break;
case BI_ATARI_MCH_TYPE:
- atari_mch_type = *data;
- break;
+ atari_mch_type = *data;
+ break;
default:
- unknown = 1;
- }
- return(unknown);
+ unknown = 1;
+ break;
+ }
+ return unknown;
}
/* Parse the Atari-specific switches= option. */
-void __init atari_switches_setup( const char *str, unsigned len )
+static int __init atari_switches_setup(char *str)
{
- char switches[len+1];
- char *p;
- int ovsc_shift;
- char *args = switches;
-
- /* copy string to local array, strsep works destructively... */
- strlcpy( switches, str, sizeof(switches) );
- atari_switches = 0;
-
- /* parse the options */
- while ((p = strsep(&args, ",")) != NULL) {
- if (!*p) continue;
- ovsc_shift = 0;
- if (strncmp( p, "ov_", 3 ) == 0) {
- p += 3;
- ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
- }
-
- if (strcmp( p, "ikbd" ) == 0) {
- /* RTS line of IKBD ACIA */
- atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
- }
- else if (strcmp( p, "midi" ) == 0) {
- /* RTS line of MIDI ACIA */
- atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+ char switches[strlen(str) + 1];
+ char *p;
+ int ovsc_shift;
+ char *args = switches;
+
+ if (!MACH_IS_ATARI)
+ return 0;
+
+ /* copy string to local array, strsep works destructively... */
+ strcpy(switches, str);
+ atari_switches = 0;
+
+ /* parse the options */
+ while ((p = strsep(&args, ",")) != NULL) {
+ if (!*p)
+ continue;
+ ovsc_shift = 0;
+ if (strncmp(p, "ov_", 3) == 0) {
+ p += 3;
+ ovsc_shift = ATARI_SWITCH_OVSC_SHIFT;
+ }
+
+ if (strcmp(p, "ikbd") == 0) {
+ /* RTS line of IKBD ACIA */
+ atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift;
+ } else if (strcmp(p, "midi") == 0) {
+ /* RTS line of MIDI ACIA */
+ atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift;
+ } else if (strcmp(p, "snd6") == 0) {
+ atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
+ } else if (strcmp(p, "snd7") == 0) {
+ atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
+ }
}
- else if (strcmp( p, "snd6" ) == 0) {
- atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift;
- }
- else if (strcmp( p, "snd7" ) == 0) {
- atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift;
- }
- }
+ return 0;
}
+early_param("switches", atari_switches_setup);
+
/*
* Setup the Atari configuration info
@@ -214,284 +182,281 @@ void __init atari_switches_setup( const char *str, unsigned len )
void __init config_atari(void)
{
- unsigned short tos_version;
+ unsigned short tos_version;
- memset(&atari_hw_present, 0, sizeof(atari_hw_present));
+ memset(&atari_hw_present, 0, sizeof(atari_hw_present));
- atari_debug_init();
+ /* Change size of I/O space from 64KB to 4GB. */
+ ioport_resource.end = 0xFFFFFFFF;
- ioport_resource.end = 0xFFFFFFFF; /* Change size of I/O space from 64KB
- to 4GB. */
-
- mach_sched_init = atari_sched_init;
- mach_init_IRQ = atari_init_IRQ;
- mach_get_model = atari_get_model;
- mach_get_hardware_list = atari_get_hardware_list;
- mach_gettimeoffset = atari_gettimeoffset;
- mach_reset = atari_reset;
- mach_max_dma_address = 0xffffff;
+ mach_sched_init = atari_sched_init;
+ mach_init_IRQ = atari_init_IRQ;
+ mach_get_model = atari_get_model;
+ mach_get_hardware_list = atari_get_hardware_list;
+ mach_gettimeoffset = atari_gettimeoffset;
+ mach_reset = atari_reset;
+ mach_max_dma_address = 0xffffff;
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
- mach_beep = atari_mksound;
+ mach_beep = atari_mksound;
#endif
#ifdef CONFIG_HEARTBEAT
- mach_heartbeat = atari_heartbeat;
+ mach_heartbeat = atari_heartbeat;
#endif
- /* Set switches as requested by the user */
- if (atari_switches & ATARI_SWITCH_IKBD)
- acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
- if (atari_switches & ATARI_SWITCH_MIDI)
- acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
- if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
- sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel |
- ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
- ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
- }
-
- /* ++bjoern:
- * Determine hardware present
- */
+ /* Set switches as requested by the user */
+ if (atari_switches & ATARI_SWITCH_IKBD)
+ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID;
+ if (atari_switches & ATARI_SWITCH_MIDI)
+ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+ if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) {
+ sound_ym.rd_data_reg_sel = 14;
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+ ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) |
+ ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0);
+ }
- printk( "Atari hardware found: " );
- if (MACH_IS_MEDUSA || MACH_IS_HADES) {
- /* There's no Atari video hardware on the Medusa, but all the
- * addresses below generate a DTACK so no bus error occurs! */
- }
- else if (hwreg_present( f030_xreg )) {
- ATARIHW_SET(VIDEL_SHIFTER);
- printk( "VIDEL " );
- /* This is a temporary hack: If there is Falcon video
- * hardware, we assume that the ST-DMA serves SCSI instead of
- * ACSI. In the future, there should be a better method for
- * this...
- */
- ATARIHW_SET(ST_SCSI);
- printk( "STDMA-SCSI " );
- }
- else if (hwreg_present( tt_palette )) {
- ATARIHW_SET(TT_SHIFTER);
- printk( "TT_SHIFTER " );
- }
- else if (hwreg_present( &shifter.bas_hi )) {
- if (hwreg_present( &shifter.bas_lo ) &&
- (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
- ATARIHW_SET(EXTD_SHIFTER);
- printk( "EXTD_SHIFTER " );
- }
- else {
- ATARIHW_SET(STND_SHIFTER);
- printk( "STND_SHIFTER " );
- }
- }
- if (hwreg_present( &mfp.par_dt_reg )) {
- ATARIHW_SET(ST_MFP);
- printk( "ST_MFP " );
- }
- if (hwreg_present( &tt_mfp.par_dt_reg )) {
- ATARIHW_SET(TT_MFP);
- printk( "TT_MFP " );
- }
- if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) {
- ATARIHW_SET(SCSI_DMA);
- printk( "TT_SCSI_DMA " );
- }
- if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) {
- ATARIHW_SET(STND_DMA);
- printk( "STND_DMA " );
- }
- if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable
- * on all Medusas, so the test below may fail */
- (hwreg_present( &st_dma.dma_vhi ) &&
- (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
- st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
- (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
- st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
- ATARIHW_SET(EXTD_DMA);
- printk( "EXTD_DMA " );
- }
- if (hwreg_present( &tt_scsi.scsi_data )) {
- ATARIHW_SET(TT_SCSI);
- printk( "TT_SCSI " );
- }
- if (hwreg_present( &sound_ym.rd_data_reg_sel )) {
- ATARIHW_SET(YM_2149);
- printk( "YM2149 " );
- }
- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
- hwreg_present( &tt_dmasnd.ctrl )) {
- ATARIHW_SET(PCM_8BIT);
- printk( "PCM " );
- }
- if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) {
- ATARIHW_SET(CODEC);
- printk( "CODEC " );
- }
- if (hwreg_present( &dsp56k_host_interface.icr )) {
- ATARIHW_SET(DSP56K);
- printk( "DSP56K " );
- }
- if (hwreg_present( &tt_scc_dma.dma_ctrl ) &&
+ /* ++bjoern:
+ * Determine hardware present
+ */
+
+ printk("Atari hardware found: ");
+ if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+ /* There's no Atari video hardware on the Medusa, but all the
+ * addresses below generate a DTACK so no bus error occurs! */
+ } else if (hwreg_present(f030_xreg)) {
+ ATARIHW_SET(VIDEL_SHIFTER);
+ printk("VIDEL ");
+ /* This is a temporary hack: If there is Falcon video
+ * hardware, we assume that the ST-DMA serves SCSI instead of
+ * ACSI. In the future, there should be a better method for
+ * this...
+ */
+ ATARIHW_SET(ST_SCSI);
+ printk("STDMA-SCSI ");
+ } else if (hwreg_present(tt_palette)) {
+ ATARIHW_SET(TT_SHIFTER);
+ printk("TT_SHIFTER ");
+ } else if (hwreg_present(&shifter.bas_hi)) {
+ if (hwreg_present(&shifter.bas_lo) &&
+ (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) {
+ ATARIHW_SET(EXTD_SHIFTER);
+ printk("EXTD_SHIFTER ");
+ } else {
+ ATARIHW_SET(STND_SHIFTER);
+ printk("STND_SHIFTER ");
+ }
+ }
+ if (hwreg_present(&mfp.par_dt_reg)) {
+ ATARIHW_SET(ST_MFP);
+ printk("ST_MFP ");
+ }
+ if (hwreg_present(&tt_mfp.par_dt_reg)) {
+ ATARIHW_SET(TT_MFP);
+ printk("TT_MFP ");
+ }
+ if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) {
+ ATARIHW_SET(SCSI_DMA);
+ printk("TT_SCSI_DMA ");
+ }
+ if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) {
+ ATARIHW_SET(STND_DMA);
+ printk("STND_DMA ");
+ }
+ /*
+ * The ST-DMA address registers aren't readable
+ * on all Medusas, so the test below may fail
+ */
+ if (MACH_IS_MEDUSA ||
+ (hwreg_present(&st_dma.dma_vhi) &&
+ (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) &&
+ st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa &&
+ (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) &&
+ st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) {
+ ATARIHW_SET(EXTD_DMA);
+ printk("EXTD_DMA ");
+ }
+ if (hwreg_present(&tt_scsi.scsi_data)) {
+ ATARIHW_SET(TT_SCSI);
+ printk("TT_SCSI ");
+ }
+ if (hwreg_present(&sound_ym.rd_data_reg_sel)) {
+ ATARIHW_SET(YM_2149);
+ printk("YM2149 ");
+ }
+ if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+ hwreg_present(&tt_dmasnd.ctrl)) {
+ ATARIHW_SET(PCM_8BIT);
+ printk("PCM ");
+ }
+ if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) {
+ ATARIHW_SET(CODEC);
+ printk("CODEC ");
+ }
+ if (hwreg_present(&dsp56k_host_interface.icr)) {
+ ATARIHW_SET(DSP56K);
+ printk("DSP56K ");
+ }
+ if (hwreg_present(&tt_scc_dma.dma_ctrl) &&
#if 0
- /* This test sucks! Who knows some better? */
- (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
- (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
+ /* This test sucks! Who knows some better? */
+ (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
+ (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
#else
- !MACH_IS_MEDUSA && !MACH_IS_HADES
+ !MACH_IS_MEDUSA && !MACH_IS_HADES
#endif
- ) {
- ATARIHW_SET(SCC_DMA);
- printk( "SCC_DMA " );
- }
- if (scc_test( &scc.cha_a_ctrl )) {
- ATARIHW_SET(SCC);
- printk( "SCC " );
- }
- if (scc_test( &st_escc.cha_b_ctrl )) {
- ATARIHW_SET( ST_ESCC );
- printk( "ST_ESCC " );
- }
- if (MACH_IS_HADES)
- {
- ATARIHW_SET( VME );
- printk( "VME " );
- }
- else if (hwreg_present( &tt_scu.sys_mask )) {
- ATARIHW_SET(SCU);
- /* Assume a VME bus if there's a SCU */
- ATARIHW_SET( VME );
- printk( "VME SCU " );
- }
- if (hwreg_present( (void *)(0xffff9210) )) {
- ATARIHW_SET(ANALOG_JOY);
- printk( "ANALOG_JOY " );
- }
- if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) {
- ATARIHW_SET(BLITTER);
- printk( "BLITTER " );
- }
- if (hwreg_present((void *)0xfff00039)) {
- ATARIHW_SET(IDE);
- printk( "IDE " );
- }
+ ) {
+ ATARIHW_SET(SCC_DMA);
+ printk("SCC_DMA ");
+ }
+ if (scc_test(&scc.cha_a_ctrl)) {
+ ATARIHW_SET(SCC);
+ printk("SCC ");
+ }
+ if (scc_test(&st_escc.cha_b_ctrl)) {
+ ATARIHW_SET(ST_ESCC);
+ printk("ST_ESCC ");
+ }
+ if (MACH_IS_HADES) {
+ ATARIHW_SET(VME);
+ printk("VME ");
+ } else if (hwreg_present(&tt_scu.sys_mask)) {
+ ATARIHW_SET(SCU);
+ /* Assume a VME bus if there's a SCU */
+ ATARIHW_SET(VME);
+ printk("VME SCU ");
+ }
+ if (hwreg_present((void *)(0xffff9210))) {
+ ATARIHW_SET(ANALOG_JOY);
+ printk("ANALOG_JOY ");
+ }
+ if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) {
+ ATARIHW_SET(BLITTER);
+ printk("BLITTER ");
+ }
+ if (hwreg_present((void *)0xfff00039)) {
+ ATARIHW_SET(IDE);
+ printk("IDE ");
+ }
#if 1 /* This maybe wrong */
- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
- hwreg_present( &tt_microwire.data ) &&
- hwreg_present( &tt_microwire.mask ) &&
- (tt_microwire.mask = 0x7ff,
- udelay(1),
- tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
- udelay(1),
- tt_microwire.data != 0)) {
- ATARIHW_SET(MICROWIRE);
- while (tt_microwire.mask != 0x7ff) ;
- printk( "MICROWIRE " );
- }
+ if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+ hwreg_present(&tt_microwire.data) &&
+ hwreg_present(&tt_microwire.mask) &&
+ (tt_microwire.mask = 0x7ff,
+ udelay(1),
+ tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR,
+ udelay(1),
+ tt_microwire.data != 0)) {
+ ATARIHW_SET(MICROWIRE);
+ while (tt_microwire.mask != 0x7ff)
+ ;
+ printk("MICROWIRE ");
+ }
#endif
- if (hwreg_present( &tt_rtc.regsel )) {
- ATARIHW_SET(TT_CLK);
- printk( "TT_CLK " );
- mach_hwclk = atari_tt_hwclk;
- mach_set_clock_mmss = atari_tt_set_clock_mmss;
- }
- if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) {
- ATARIHW_SET(MSTE_CLK);
- printk( "MSTE_CLK ");
- mach_hwclk = atari_mste_hwclk;
- mach_set_clock_mmss = atari_mste_set_clock_mmss;
- }
- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
- hwreg_present( &dma_wd.fdc_speed ) &&
- hwreg_write( &dma_wd.fdc_speed, 0 )) {
- ATARIHW_SET(FDCSPEED);
- printk( "FDC_SPEED ");
- }
- if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
- ATARIHW_SET(ACSI);
- printk( "ACSI " );
- }
- printk("\n");
-
- if (CPU_IS_040_OR_060)
- /* Now it seems to be safe to turn of the tt0 transparent
- * translation (the one that must not be turned off in
- * head.S...)
- */
- __asm__ volatile ("moveq #0,%/d0\n\t"
- ".chip 68040\n\t"
- "movec %%d0,%%itt0\n\t"
- "movec %%d0,%%dtt0\n\t"
- ".chip 68k"
- : /* no outputs */
- : /* no inputs */
- : "d0");
-
- /* allocator for memory that must reside in st-ram */
- atari_stram_init ();
-
- /* Set up a mapping for the VMEbus address region:
- *
- * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
- * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
- * 0xfe000000 virt., because this can be done with a single
- * transparent translation. On the 68040, lots of often unused
- * page tables would be needed otherwise. On a MegaSTE or similar,
- * the highest byte is stripped off by hardware due to the 24 bit
- * design of the bus.
- */
+ if (hwreg_present(&tt_rtc.regsel)) {
+ ATARIHW_SET(TT_CLK);
+ printk("TT_CLK ");
+ mach_hwclk = atari_tt_hwclk;
+ mach_set_clock_mmss = atari_tt_set_clock_mmss;
+ }
+ if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) {
+ ATARIHW_SET(MSTE_CLK);
+ printk("MSTE_CLK ");
+ mach_hwclk = atari_mste_hwclk;
+ mach_set_clock_mmss = atari_mste_set_clock_mmss;
+ }
+ if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
+ hwreg_present(&dma_wd.fdc_speed) &&
+ hwreg_write(&dma_wd.fdc_speed, 0)) {
+ ATARIHW_SET(FDCSPEED);
+ printk("FDC_SPEED ");
+ }
+ if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
+ ATARIHW_SET(ACSI);
+ printk("ACSI ");
+ }
+ printk("\n");
+
+ if (CPU_IS_040_OR_060)
+ /* Now it seems to be safe to turn of the tt0 transparent
+ * translation (the one that must not be turned off in
+ * head.S...)
+ */
+ asm volatile ("\n"
+ " moveq #0,%%d0\n"
+ " .chip 68040\n"
+ " movec %%d0,%%itt0\n"
+ " movec %%d0,%%dtt0\n"
+ " .chip 68k"
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+
+ /* allocator for memory that must reside in st-ram */
+ atari_stram_init();
+
+ /* Set up a mapping for the VMEbus address region:
+ *
+ * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff
+ * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at
+ * 0xfe000000 virt., because this can be done with a single
+ * transparent translation. On the 68040, lots of often unused
+ * page tables would be needed otherwise. On a MegaSTE or similar,
+ * the highest byte is stripped off by hardware due to the 24 bit
+ * design of the bus.
+ */
+
+ if (CPU_IS_020_OR_030) {
+ unsigned long tt1_val;
+ tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
+ * inhibit, read and write, FDC mask = 3,
+ * FDC val = 4 -> Supervisor only */
+ asm volatile ("\n"
+ " .chip 68030\n"
+ " pmove %0@,%/tt1\n"
+ " .chip 68k"
+ : : "a" (&tt1_val));
+ } else {
+ asm volatile ("\n"
+ " .chip 68040\n"
+ " movec %0,%%itt1\n"
+ " movec %0,%%dtt1\n"
+ " .chip 68k"
+ :
+ : "d" (0xfe00a040)); /* Translate 0xfexxxxxx, enable,
+ * supervisor only, non-cacheable/
+ * serialized, writable */
+
+ }
- if (CPU_IS_020_OR_030) {
- unsigned long tt1_val;
- tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache
- * inhibit, read and write, FDC mask = 3,
- * FDC val = 4 -> Supervisor only */
- __asm__ __volatile__ ( ".chip 68030\n\t"
- "pmove %0@,%/tt1\n\t"
- ".chip 68k"
- : : "a" (&tt1_val) );
- }
- else {
- __asm__ __volatile__
- ( "movel %0,%/d0\n\t"
- ".chip 68040\n\t"
- "movec %%d0,%%itt1\n\t"
- "movec %%d0,%%dtt1\n\t"
- ".chip 68k"
- :
- : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable,
- * supervisor only, non-cacheable/
- * serialized, writable */
- : "d0" );
-
- }
-
- /* Fetch tos version at Physical 2 */
- /* We my not be able to access this address if the kernel is
- loaded to st ram, since the first page is unmapped. On the
- Medusa this is always the case and there is nothing we can do
- about this, so we just assume the smaller offset. For the TT
- we use the fact that in head.S we have set up a mapping
- 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
- in the last 16MB of the address space. */
- tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
- 0xfff : *(unsigned short *)0xff000002;
- atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
+ /* Fetch tos version at Physical 2 */
+ /*
+ * We my not be able to access this address if the kernel is
+ * loaded to st ram, since the first page is unmapped. On the
+ * Medusa this is always the case and there is nothing we can do
+ * about this, so we just assume the smaller offset. For the TT
+ * we use the fact that in head.S we have set up a mapping
+ * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
+ * in the last 16MB of the address space.
+ */
+ tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+ 0xfff : *(unsigned short *)0xff000002;
+ atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
}
#ifdef CONFIG_HEARTBEAT
-static void atari_heartbeat( int on )
+static void atari_heartbeat(int on)
{
- unsigned char tmp;
- unsigned long flags;
+ unsigned char tmp;
+ unsigned long flags;
- if (atari_dont_touch_floppy_select)
- return;
+ if (atari_dont_touch_floppy_select)
+ return;
- local_irq_save(flags);
- sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
- tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
- local_irq_restore(flags);
+ local_irq_save(flags);
+ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
+ tmp = sound_ym.rd_data_reg_sel;
+ sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02);
+ local_irq_restore(flags);
}
#endif
@@ -526,180 +491,171 @@ static void atari_heartbeat( int on )
/* ++andreas: no need for complicated code, just depend on prefetch */
-static void atari_reset (void)
+static void atari_reset(void)
{
- long tc_val = 0;
- long reset_addr;
-
- /* On the Medusa, phys. 0x4 may contain garbage because it's no
- ROM. See above for explanation why we cannot use PTOV(4). */
- reset_addr = MACH_IS_HADES ? 0x7fe00030 :
- MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
- *(unsigned long *) 0xff000004;
-
- /* reset ACIA for switch off OverScan, if it's active */
- if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
- acia.key_ctrl = ACIA_RESET;
- if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
- acia.mid_ctrl = ACIA_RESET;
-
- /* processor independent: turn off interrupts and reset the VBR;
- * the caches must be left enabled, else prefetching the final jump
- * instruction doesn't work. */
- local_irq_disable();
- __asm__ __volatile__
- ("moveq #0,%/d0\n\t"
- "movec %/d0,%/vbr"
- : : : "d0" );
-
- if (CPU_IS_040_OR_060) {
- unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
- if (CPU_IS_060) {
- /* 68060: clear PCR to turn off superscalar operation */
- __asm__ __volatile__
- ("moveq #0,%/d0\n\t"
- ".chip 68060\n\t"
- "movec %%d0,%%pcr\n\t"
- ".chip 68k"
- : : : "d0" );
- }
-
- __asm__ __volatile__
- ("movel %0,%/d0\n\t"
- "andl #0xff000000,%/d0\n\t"
- "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */
- ".chip 68040\n\t"
- "movec %%d0,%%itt0\n\t"
- "movec %%d0,%%dtt0\n\t"
- ".chip 68k\n\t"
- "jmp %0@\n\t"
- : /* no outputs */
- : "a" (jmp_addr040)
- : "d0" );
- jmp_addr_label040:
- __asm__ __volatile__
- ("moveq #0,%/d0\n\t"
- "nop\n\t"
- ".chip 68040\n\t"
- "cinva %%bc\n\t"
- "nop\n\t"
- "pflusha\n\t"
- "nop\n\t"
- "movec %%d0,%%tc\n\t"
- "nop\n\t"
- /* the following setup of transparent translations is needed on the
- * Afterburner040 to successfully reboot. Other machines shouldn't
- * care about a different tt regs setup, they also didn't care in
- * the past that the regs weren't turned off. */
- "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */
- "movec %%d0,%%itt0\n\t"
- "movec %%d0,%%itt1\n\t"
- "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */
- "movec %%d0,%%dtt0\n\t"
- "movec %%d0,%%dtt1\n\t"
- ".chip 68k\n\t"
- "jmp %0@"
- : /* no outputs */
- : "a" (reset_addr)
- : "d0");
- }
- else
- __asm__ __volatile__
- ("pmove %0@,%/tc\n\t"
- "jmp %1@"
- : /* no outputs */
- : "a" (&tc_val), "a" (reset_addr));
+ long tc_val = 0;
+ long reset_addr;
+
+ /*
+ * On the Medusa, phys. 0x4 may contain garbage because it's no
+ * ROM. See above for explanation why we cannot use PTOV(4).
+ */
+ reset_addr = MACH_IS_HADES ? 0x7fe00030 :
+ MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+ *(unsigned long *) 0xff000004;
+
+ /* reset ACIA for switch off OverScan, if it's active */
+ if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+ acia.key_ctrl = ACIA_RESET;
+ if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+ acia.mid_ctrl = ACIA_RESET;
+
+ /* processor independent: turn off interrupts and reset the VBR;
+ * the caches must be left enabled, else prefetching the final jump
+ * instruction doesn't work.
+ */
+ local_irq_disable();
+ asm volatile ("movec %0,%%vbr"
+ : : "d" (0));
+
+ if (CPU_IS_040_OR_060) {
+ unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040);
+ if (CPU_IS_060) {
+ /* 68060: clear PCR to turn off superscalar operation */
+ asm volatile ("\n"
+ " .chip 68060\n"
+ " movec %0,%%pcr\n"
+ " .chip 68k"
+ : : "d" (0));
+ }
+
+ asm volatile ("\n"
+ " move.l %0,%%d0\n"
+ " and.l #0xff000000,%%d0\n"
+ " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */
+ " .chip 68040\n"
+ " movec %%d0,%%itt0\n"
+ " movec %%d0,%%dtt0\n"
+ " .chip 68k\n"
+ " jmp %0@"
+ : : "a" (jmp_addr040)
+ : "d0");
+ jmp_addr_label040:
+ asm volatile ("\n"
+ " moveq #0,%%d0\n"
+ " nop\n"
+ " .chip 68040\n"
+ " cinva %%bc\n"
+ " nop\n"
+ " pflusha\n"
+ " nop\n"
+ " movec %%d0,%%tc\n"
+ " nop\n"
+ /* the following setup of transparent translations is needed on the
+ * Afterburner040 to successfully reboot. Other machines shouldn't
+ * care about a different tt regs setup, they also didn't care in
+ * the past that the regs weren't turned off. */
+ " move.l #0xffc000,%%d0\n" /* whole insn space cacheable */
+ " movec %%d0,%%itt0\n"
+ " movec %%d0,%%itt1\n"
+ " or.w #0x40,%/d0\n" /* whole data space non-cacheable/ser. */
+ " movec %%d0,%%dtt0\n"
+ " movec %%d0,%%dtt1\n"
+ " .chip 68k\n"
+ " jmp %0@"
+ : /* no outputs */
+ : "a" (reset_addr)
+ : "d0");
+ } else
+ asm volatile ("\n"
+ " pmove %0@,%%tc\n"
+ " jmp %1@"
+ : /* no outputs */
+ : "a" (&tc_val), "a" (reset_addr));
}
static void atari_get_model(char *model)
{
- strcpy(model, "Atari ");
- switch (atari_mch_cookie >> 16) {
+ strcpy(model, "Atari ");
+ switch (atari_mch_cookie >> 16) {
case ATARI_MCH_ST:
- if (ATARIHW_PRESENT(MSTE_CLK))
- strcat (model, "Mega ST");
- else
- strcat (model, "ST");
- break;
+ if (ATARIHW_PRESENT(MSTE_CLK))
+ strcat(model, "Mega ST");
+ else
+ strcat(model, "ST");
+ break;
case ATARI_MCH_STE:
- if (MACH_IS_MSTE)
- strcat (model, "Mega STE");
- else
- strcat (model, "STE");
- break;
+ if (MACH_IS_MSTE)
+ strcat(model, "Mega STE");
+ else
+ strcat(model, "STE");
+ break;
case ATARI_MCH_TT:
- if (MACH_IS_MEDUSA)
- /* Medusa has TT _MCH cookie */
- strcat (model, "Medusa");
- else if (MACH_IS_HADES)
- strcat(model, "Hades");
- else
- strcat (model, "TT");
- break;
+ if (MACH_IS_MEDUSA)
+ /* Medusa has TT _MCH cookie */
+ strcat(model, "Medusa");
+ else if (MACH_IS_HADES)
+ strcat(model, "Hades");
+ else
+ strcat(model, "TT");
+ break;
case ATARI_MCH_FALCON:
- strcat (model, "Falcon");
- if (MACH_IS_AB40)
- strcat (model, " (with Afterburner040)");
- break;
+ strcat(model, "Falcon");
+ if (MACH_IS_AB40)
+ strcat(model, " (with Afterburner040)");
+ break;
default:
- sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)",
- atari_mch_cookie);
- break;
- }
+ sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)",
+ atari_mch_cookie);
+ break;
+ }
}
static int atari_get_hardware_list(char *buffer)
{
- int len = 0, i;
-
- for (i = 0; i < m68k_num_memory; i++)
- len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
- m68k_memory[i].size >> 20, m68k_memory[i].addr,
- (m68k_memory[i].addr & 0xff000000 ?
- "alternate RAM" : "ST-RAM"));
-
-#define ATARIHW_ANNOUNCE(name,str) \
- if (ATARIHW_PRESENT(name)) \
- len += sprintf (buffer + len, "\t%s\n", str)
-
- len += sprintf (buffer + len, "Detected hardware:\n");
- ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
- ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
- ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
- ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
- ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
- ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
- ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
- ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
- ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
- ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
- ATARIHW_ANNOUNCE(IDE, "IDE Interface");
- ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
- ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
- ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
- ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
- ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
- ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
- ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
- ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
- ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
- ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
- ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
- ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
- ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
- ATARIHW_ANNOUNCE(SCU, "System Control Unit");
- ATARIHW_ANNOUNCE(BLITTER, "Blitter");
- ATARIHW_ANNOUNCE(VME, "VME Bus");
- ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
-
- return(len);
+ int len = 0, i;
+
+ for (i = 0; i < m68k_num_memory; i++)
+ len += sprintf(buffer+len, "\t%3ld MB at 0x%08lx (%s)\n",
+ m68k_memory[i].size >> 20, m68k_memory[i].addr,
+ (m68k_memory[i].addr & 0xff000000 ?
+ "alternate RAM" : "ST-RAM"));
+
+#define ATARIHW_ANNOUNCE(name, str) \
+ if (ATARIHW_PRESENT(name)) \
+ len += sprintf(buffer + len, "\t%s\n", str)
+
+ len += sprintf(buffer + len, "Detected hardware:\n");
+ ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter");
+ ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter");
+ ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter");
+ ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter");
+ ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator");
+ ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound");
+ ATARIHW_ANNOUNCE(CODEC, "CODEC Sound");
+ ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)");
+ ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)");
+ ATARIHW_ANNOUNCE(ACSI, "ACSI Interface");
+ ATARIHW_ANNOUNCE(IDE, "IDE Interface");
+ ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC");
+ ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901");
+ ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901");
+ ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530");
+ ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230");
+ ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface");
+ ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface");
+ ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)");
+ ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)");
+ ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380");
+ ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC");
+ ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A");
+ ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15");
+ ATARIHW_ANNOUNCE(SCU, "System Control Unit");
+ ATARIHW_ANNOUNCE(BLITTER, "Blitter");
+ ATARIHW_ANNOUNCE(VME, "VME Bus");
+ ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor");
+
+ return len;
}
-
-/*
- * Local variables:
- * c-indent-level: 4
- * tab-width: 8
- * End:
- */
diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c
index 4ae01004d8d..fbeed8c8ecb 100644
--- a/arch/m68k/atari/debug.c
+++ b/arch/m68k/atari/debug.c
@@ -19,8 +19,6 @@
#include <asm/atarihw.h>
#include <asm/atariints.h>
-extern char m68k_debug_device[];
-
/* Flag that Modem1 port is already initialized and used */
int atari_MFP_init_done;
/* Flag that Modem1 port is already initialized and used */
@@ -30,317 +28,317 @@ int atari_SCC_init_done;
int atari_SCC_reset_done;
static struct console atari_console_driver = {
- .name = "debug",
- .flags = CON_PRINTBUFFER,
- .index = -1,
+ .name = "debug",
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
-static inline void ata_mfp_out (char c)
+static inline void ata_mfp_out(char c)
{
- while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
- barrier ();
- mfp.usart_dta = c;
+ while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */
+ barrier();
+ mfp.usart_dta = c;
}
-void atari_mfp_console_write (struct console *co, const char *str,
- unsigned int count)
+void atari_mfp_console_write(struct console *co, const char *str,
+ unsigned int count)
{
- while (count--) {
- if (*str == '\n')
- ata_mfp_out( '\r' );
- ata_mfp_out( *str++ );
- }
+ while (count--) {
+ if (*str == '\n')
+ ata_mfp_out('\r');
+ ata_mfp_out(*str++);
+ }
}
-static inline void ata_scc_out (char c)
+static inline void ata_scc_out(char c)
{
- do {
+ do {
+ MFPDELAY();
+ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
MFPDELAY();
- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
- MFPDELAY();
- scc.cha_b_data = c;
+ scc.cha_b_data = c;
}
-void atari_scc_console_write (struct console *co, const char *str,
- unsigned int count)
+void atari_scc_console_write(struct console *co, const char *str,
+ unsigned int count)
{
- while (count--) {
- if (*str == '\n')
- ata_scc_out( '\r' );
- ata_scc_out( *str++ );
- }
+ while (count--) {
+ if (*str == '\n')
+ ata_scc_out('\r');
+ ata_scc_out(*str++);
+ }
}
-static inline void ata_midi_out (char c)
+static inline void ata_midi_out(char c)
{
- while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
- barrier ();
- acia.mid_data = c;
+ while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */
+ barrier();
+ acia.mid_data = c;
}
-void atari_midi_console_write (struct console *co, const char *str,
- unsigned int count)
+void atari_midi_console_write(struct console *co, const char *str,
+ unsigned int count)
{
- while (count--) {
- if (*str == '\n')
- ata_midi_out( '\r' );
- ata_midi_out( *str++ );
- }
+ while (count--) {
+ if (*str == '\n')
+ ata_midi_out('\r');
+ ata_midi_out(*str++);
+ }
}
-static int ata_par_out (char c)
+static int ata_par_out(char c)
{
- unsigned char tmp;
- /* This a some-seconds timeout in case no printer is connected */
- unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
-
- while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */
- ;
- if (!i) return( 0 );
-
- sound_ym.rd_data_reg_sel = 15; /* select port B */
- sound_ym.wd_data = c; /* put char onto port */
- sound_ym.rd_data_reg_sel = 14; /* select port A */
- tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
- MFPDELAY(); /* wait a bit */
- sound_ym.wd_data = tmp | 0x20; /* set strobe H */
- return( 1 );
+ unsigned char tmp;
+ /* This a some-seconds timeout in case no printer is connected */
+ unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
+
+ while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
+ ;
+ if (!i)
+ return 0;
+
+ sound_ym.rd_data_reg_sel = 15; /* select port B */
+ sound_ym.wd_data = c; /* put char onto port */
+ sound_ym.rd_data_reg_sel = 14; /* select port A */
+ tmp = sound_ym.rd_data_reg_sel;
+ sound_ym.wd_data = tmp & ~0x20; /* set strobe L */
+ MFPDELAY(); /* wait a bit */
+ sound_ym.wd_data = tmp | 0x20; /* set strobe H */
+ return 1;
}
-static void atari_par_console_write (struct console *co, const char *str,
- unsigned int count)
+static void atari_par_console_write(struct console *co, const char *str,
+ unsigned int count)
{
- static int printer_present = 1;
+ static int printer_present = 1;
- if (!printer_present)
- return;
-
- while (count--) {
- if (*str == '\n')
- if (!ata_par_out( '\r' )) {
- printer_present = 0;
+ if (!printer_present)
return;
- }
- if (!ata_par_out( *str++ )) {
- printer_present = 0;
- return;
+
+ while (count--) {
+ if (*str == '\n') {
+ if (!ata_par_out('\r')) {
+ printer_present = 0;
+ return;
+ }
+ }
+ if (!ata_par_out(*str++)) {
+ printer_present = 0;
+ return;
+ }
}
- }
}
#ifdef CONFIG_SERIAL_CONSOLE
int atari_mfp_console_wait_key(struct console *co)
{
- while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */
- barrier();
- return( mfp.usart_dta );
+ while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */
+ barrier();
+ return mfp.usart_dta;
}
int atari_scc_console_wait_key(struct console *co)
{
- do {
+ do {
+ MFPDELAY();
+ } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */
MFPDELAY();
- } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */
- MFPDELAY();
- return( scc.cha_b_data );
+ return scc.cha_b_data;
}
int atari_midi_console_wait_key(struct console *co)
{
- while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */
- barrier();
- return( acia.mid_data );
+ while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */
+ barrier();
+ return acia.mid_data;
}
#endif
-/* The following two functions do a quick'n'dirty initialization of the MFP or
+/*
+ * The following two functions do a quick'n'dirty initialization of the MFP or
* SCC serial ports. They're used by the debugging interface, kgdb, and the
- * serial console code. */
+ * serial console code.
+ */
#ifndef CONFIG_SERIAL_CONSOLE
-static void __init atari_init_mfp_port( int cflag )
+static void __init atari_init_mfp_port(int cflag)
#else
-void atari_init_mfp_port( int cflag )
+void atari_init_mfp_port(int cflag)
#endif
{
- /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
- * bps, resp., and work only correct if there's a RSVE or RSSPEED */
- static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
- int baud = cflag & CBAUD;
- int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
- int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
-
- if (cflag & CBAUDEX)
- baud += B38400;
- if (baud < B1200 || baud > B38400+2)
- baud = B9600; /* use default 9600bps for non-implemented rates */
- baud -= B1200; /* baud_table[] starts at 1200bps */
-
- mfp.trn_stat &= ~0x01; /* disable TX */
- mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
- mfp.tim_ct_cd &= 0x70; /* stop timer D */
- mfp.tim_dt_d = baud_table[baud];
- mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
- mfp.trn_stat |= 0x01; /* enable TX */
-
- atari_MFP_init_done = 1;
+ /*
+ * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150
+ * bps, resp., and work only correct if there's a RSVE or RSSPEED
+ */
+ static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 };
+ int baud = cflag & CBAUD;
+ int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0;
+ int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00;
+
+ if (cflag & CBAUDEX)
+ baud += B38400;
+ if (baud < B1200 || baud > B38400+2)
+ baud = B9600; /* use default 9600bps for non-implemented rates */
+ baud -= B1200; /* baud_table[] starts at 1200bps */
+
+ mfp.trn_stat &= ~0x01; /* disable TX */
+ mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
+ mfp.tim_ct_cd &= 0x70; /* stop timer D */
+ mfp.tim_dt_d = baud_table[baud];
+ mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */
+ mfp.trn_stat |= 0x01; /* enable TX */
+
+ atari_MFP_init_done = 1;
}
-#define SCC_WRITE(reg,val) \
- do { \
- scc.cha_b_ctrl = (reg); \
- MFPDELAY(); \
- scc.cha_b_ctrl = (val); \
- MFPDELAY(); \
- } while(0)
+#define SCC_WRITE(reg, val) \
+ do { \
+ scc.cha_b_ctrl = (reg); \
+ MFPDELAY(); \
+ scc.cha_b_ctrl = (val); \
+ MFPDELAY(); \
+ } while (0)
/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
* delay of ~ 60us. */
-#define LONG_DELAY() \
- do { \
- int i; \
- for( i = 100; i > 0; --i ) \
- MFPDELAY(); \
- } while(0)
+#define LONG_DELAY() \
+ do { \
+ int i; \
+ for (i = 100; i > 0; --i) \
+ MFPDELAY(); \
+ } while (0)
#ifndef CONFIG_SERIAL_CONSOLE
-static void __init atari_init_scc_port( int cflag )
+static void __init atari_init_scc_port(int cflag)
#else
-void atari_init_scc_port( int cflag )
+void atari_init_scc_port(int cflag)
#endif
{
- extern int atari_SCC_reset_done;
- static int clksrc_table[9] =
- /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
- { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
- static int brgsrc_table[9] =
- /* reg 14: 0 = RTxC, 2 = PCLK */
- { 2, 2, 2, 2, 2, 2, 0, 2, 2 };
- static int clkmode_table[9] =
- /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
- { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
- static int div_table[9] =
- /* reg12 (BRG low) */
- { 208, 138, 103, 50, 24, 11, 1, 0, 0 };
-
- int baud = cflag & CBAUD;
- int clksrc, clkmode, div, reg3, reg5;
-
- if (cflag & CBAUDEX)
- baud += B38400;
- if (baud < B1200 || baud > B38400+2)
- baud = B9600; /* use default 9600bps for non-implemented rates */
- baud -= B1200; /* tables starts at 1200bps */
-
- clksrc = clksrc_table[baud];
- clkmode = clkmode_table[baud];
- div = div_table[baud];
- if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
- /* special treatment for TT, where rates >= 38400 are done via TRxC */
- clksrc = 0x28; /* TRxC */
- clkmode = baud == 6 ? 0xc0 :
- baud == 7 ? 0x80 : /* really 76800bps */
- 0x40; /* really 153600bps */
- div = 0;
- }
-
- reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
- reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
-
- (void)scc.cha_b_ctrl; /* reset reg pointer */
- SCC_WRITE( 9, 0xc0 ); /* reset */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
- 0x04 /* 1 stopbit */ |
- clkmode );
- SCC_WRITE( 3, reg3 );
- SCC_WRITE( 5, reg5 );
- SCC_WRITE( 9, 0 ); /* no interrupts */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCC_WRITE( 10, 0 ); /* NRZ mode */
- SCC_WRITE( 11, clksrc ); /* main clock source */
- SCC_WRITE( 12, div ); /* BRG value */
- SCC_WRITE( 13, 0 ); /* BRG high byte */
- SCC_WRITE( 14, brgsrc_table[baud] );
- SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) );
- SCC_WRITE( 3, reg3 | 1 );
- SCC_WRITE( 5, reg5 | 8 );
-
- atari_SCC_reset_done = 1;
- atari_SCC_init_done = 1;
+ extern int atari_SCC_reset_done;
+ static int clksrc_table[9] =
+ /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */
+ { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 };
+ static int brgsrc_table[9] =
+ /* reg 14: 0 = RTxC, 2 = PCLK */
+ { 2, 2, 2, 2, 2, 2, 0, 2, 2 };
+ static int clkmode_table[9] =
+ /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */
+ { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 };
+ static int div_table[9] =
+ /* reg12 (BRG low) */
+ { 208, 138, 103, 50, 24, 11, 1, 0, 0 };
+
+ int baud = cflag & CBAUD;
+ int clksrc, clkmode, div, reg3, reg5;
+
+ if (cflag & CBAUDEX)
+ baud += B38400;
+ if (baud < B1200 || baud > B38400+2)
+ baud = B9600; /* use default 9600bps for non-implemented rates */
+ baud -= B1200; /* tables starts at 1200bps */
+
+ clksrc = clksrc_table[baud];
+ clkmode = clkmode_table[baud];
+ div = div_table[baud];
+ if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) {
+ /* special treatment for TT, where rates >= 38400 are done via TRxC */
+ clksrc = 0x28; /* TRxC */
+ clkmode = baud == 6 ? 0xc0 :
+ baud == 7 ? 0x80 : /* really 76800bps */
+ 0x40; /* really 153600bps */
+ div = 0;
+ }
+
+ reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40;
+ reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */;
+
+ (void)scc.cha_b_ctrl; /* reset reg pointer */
+ SCC_WRITE(9, 0xc0); /* reset */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03)
+ : 0 | 0x04 /* 1 stopbit */ | clkmode);
+ SCC_WRITE(3, reg3);
+ SCC_WRITE(5, reg5);
+ SCC_WRITE(9, 0); /* no interrupts */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCC_WRITE(10, 0); /* NRZ mode */
+ SCC_WRITE(11, clksrc); /* main clock source */
+ SCC_WRITE(12, div); /* BRG value */
+ SCC_WRITE(13, 0); /* BRG high byte */
+ SCC_WRITE(14, brgsrc_table[baud]);
+ SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0));
+ SCC_WRITE(3, reg3 | 1);
+ SCC_WRITE(5, reg5 | 8);
+
+ atari_SCC_reset_done = 1;
+ atari_SCC_init_done = 1;
}
#ifndef CONFIG_SERIAL_CONSOLE
-static void __init atari_init_midi_port( int cflag )
+static void __init atari_init_midi_port(int cflag)
#else
-void atari_init_midi_port( int cflag )
+void atari_init_midi_port(int cflag)
#endif
{
- int baud = cflag & CBAUD;
- int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
- /* warning 7N1 isn't possible! (instead 7O2 is used...) */
- int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
- int div;
-
- /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
- * default) the standard MIDI speed 31250. */
- if (cflag & CBAUDEX)
- baud += B38400;
- if (baud == B4800)
- div = ACIA_DIV64; /* really 7812.5 bps */
- else if (baud == B38400+2 /* 115200 */)
- div = ACIA_DIV1; /* really 500 kbps (does that work??) */
- else
- div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
-
- /* RTS low, ints disabled */
- acia.mid_ctrl = div | csize | parity |
+ int baud = cflag & CBAUD;
+ int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00;
+ /* warning 7N1 isn't possible! (instead 7O2 is used...) */
+ int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04;
+ int div;
+
+ /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as
+ * default) the standard MIDI speed 31250. */
+ if (cflag & CBAUDEX)
+ baud += B38400;
+ if (baud == B4800)
+ div = ACIA_DIV64; /* really 7812.5 bps */
+ else if (baud == B38400+2 /* 115200 */)
+ div = ACIA_DIV1; /* really 500 kbps (does that work??) */
+ else
+ div = ACIA_DIV16; /* 31250 bps, standard for MIDI */
+
+ /* RTS low, ints disabled */
+ acia.mid_ctrl = div | csize | parity |
((atari_switches & ATARI_SWITCH_MIDI) ?
ACIA_RHTID : ACIA_RLTID);
}
-void __init atari_debug_init(void)
+static int __init atari_debug_setup(char *arg)
{
- if (!strcmp( m68k_debug_device, "ser" )) {
- /* defaults to ser2 for a Falcon and ser1 otherwise */
- strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" );
-
- }
-
- if (!strcmp( m68k_debug_device, "ser1" )) {
- /* ST-MFP Modem1 serial port */
- atari_init_mfp_port( B9600|CS8 );
- atari_console_driver.write = atari_mfp_console_write;
- }
- else if (!strcmp( m68k_debug_device, "ser2" )) {
- /* SCC Modem2 serial port */
- atari_init_scc_port( B9600|CS8 );
- atari_console_driver.write = atari_scc_console_write;
- }
- else if (!strcmp( m68k_debug_device, "midi" )) {
- /* MIDI port */
- atari_init_midi_port( B9600|CS8 );
- atari_console_driver.write = atari_midi_console_write;
- }
- else if (!strcmp( m68k_debug_device, "par" )) {
- /* parallel printer */
- atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */
- sound_ym.rd_data_reg_sel = 7; /* select mixer control */
- sound_ym.wd_data = 0xff; /* sound off, ports are output */
- sound_ym.rd_data_reg_sel = 15; /* select port B */
- sound_ym.wd_data = 0; /* no char */
- sound_ym.rd_data_reg_sel = 14; /* select port A */
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
- atari_console_driver.write = atari_par_console_write;
- }
- if (atari_console_driver.write)
- register_console(&atari_console_driver);
+ if (!MACH_IS_ATARI)
+ return 0;
+
+ if (!strcmp(arg, "ser"))
+ /* defaults to ser2 for a Falcon and ser1 otherwise */
+ arg = MACH_IS_FALCON ? "ser2" : "ser1";
+
+ if (!strcmp(arg, "ser1")) {
+ /* ST-MFP Modem1 serial port */
+ atari_init_mfp_port(B9600|CS8);
+ atari_console_driver.write = atari_mfp_console_write;
+ } else if (!strcmp(arg, "ser2")) {
+ /* SCC Modem2 serial port */
+ atari_init_scc_port(B9600|CS8);
+ atari_console_driver.write = atari_scc_console_write;
+ } else if (!strcmp(arg, "midi")) {
+ /* MIDI port */
+ atari_init_midi_port(B9600|CS8);
+ atari_console_driver.write = atari_midi_console_write;
+ } else if (!strcmp(arg, "par")) {
+ /* parallel printer */
+ atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */
+ sound_ym.rd_data_reg_sel = 7; /* select mixer control */
+ sound_ym.wd_data = 0xff; /* sound off, ports are output */
+ sound_ym.rd_data_reg_sel = 15; /* select port B */
+ sound_ym.wd_data = 0; /* no char */
+ sound_ym.rd_data_reg_sel = 14; /* select port A */
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */
+ atari_console_driver.write = atari_par_console_write;
+ }
+ if (atari_console_driver.write)
+ register_console(&atari_console_driver);
+
+ return 0;
}
-/*
- * Local variables:
- * c-indent-level: 4
- * tab-width: 8
- * End:
- */
+early_param("debug", atari_debug_setup);
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 222ce424456..e162ee685d2 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -692,7 +692,7 @@ sys_call_table:
.long sys_tgkill /* 265 */
.long sys_utimes
.long sys_fadvise64_64
- .long sys_mbind
+ .long sys_mbind
.long sys_get_mempolicy
.long sys_set_mempolicy /* 270 */
.long sys_mq_open
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 6739e87fe82..05741f23356 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -3195,7 +3195,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1
jbra L(serial_putc_done)
3:
#endif
-
+
L(serial_putc_done):
func_return serial_putc
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index b66c97c904b..60d4d75f579 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -59,14 +59,14 @@ static int m68k_first_user_vec;
static struct irq_controller auto_irq_controller = {
.name = "auto",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(auto_irq_controller.lock),
.startup = m68k_irq_startup,
.shutdown = m68k_irq_shutdown,
};
static struct irq_controller user_irq_controller = {
.name = "user",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(user_irq_controller.lock),
.startup = m68k_irq_startup,
.shutdown = m68k_irq_shutdown,
};
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 7fd2720c384..cdba9fd6d82 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 42b8fd09ea8..61031935669 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -71,9 +71,6 @@ static struct mem_info m68k_ramdisk;
static char m68k_command_line[CL_SIZE];
-char m68k_debug_device[6] = "";
-EXPORT_SYMBOL(m68k_debug_device);
-
void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata = NULL;
@@ -133,78 +130,78 @@ extern void config_hp300(void);
extern void config_q40(void);
extern void config_sun3x(void);
-extern void mac_debugging_short (int, short);
-extern void mac_debugging_long (int, long);
-
#define MASK_256K 0xfffc0000
extern void paging_init(void);
static void __init m68k_parse_bootinfo(const struct bi_record *record)
{
- while (record->tag != BI_LAST) {
- int unknown = 0;
- const unsigned long *data = record->data;
- switch (record->tag) {
- case BI_MACHTYPE:
- case BI_CPUTYPE:
- case BI_FPUTYPE:
- case BI_MMUTYPE:
- /* Already set up by head.S */
- break;
-
- case BI_MEMCHUNK:
- if (m68k_num_memory < NUM_MEMINFO) {
- m68k_memory[m68k_num_memory].addr = data[0];
- m68k_memory[m68k_num_memory].size = data[1];
- m68k_num_memory++;
- } else
- printk("m68k_parse_bootinfo: too many memory chunks\n");
- break;
-
- case BI_RAMDISK:
- m68k_ramdisk.addr = data[0];
- m68k_ramdisk.size = data[1];
- break;
-
- case BI_COMMAND_LINE:
- strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line));
- break;
-
- default:
- if (MACH_IS_AMIGA)
- unknown = amiga_parse_bootinfo(record);
- else if (MACH_IS_ATARI)
- unknown = atari_parse_bootinfo(record);
- else if (MACH_IS_MAC)
- unknown = mac_parse_bootinfo(record);
- else if (MACH_IS_Q40)
- unknown = q40_parse_bootinfo(record);
- else if (MACH_IS_BVME6000)
- unknown = bvme6000_parse_bootinfo(record);
- else if (MACH_IS_MVME16x)
- unknown = mvme16x_parse_bootinfo(record);
- else if (MACH_IS_MVME147)
- unknown = mvme147_parse_bootinfo(record);
- else if (MACH_IS_HP300)
- unknown = hp300_parse_bootinfo(record);
- else
- unknown = 1;
+ while (record->tag != BI_LAST) {
+ int unknown = 0;
+ const unsigned long *data = record->data;
+
+ switch (record->tag) {
+ case BI_MACHTYPE:
+ case BI_CPUTYPE:
+ case BI_FPUTYPE:
+ case BI_MMUTYPE:
+ /* Already set up by head.S */
+ break;
+
+ case BI_MEMCHUNK:
+ if (m68k_num_memory < NUM_MEMINFO) {
+ m68k_memory[m68k_num_memory].addr = data[0];
+ m68k_memory[m68k_num_memory].size = data[1];
+ m68k_num_memory++;
+ } else
+ printk("m68k_parse_bootinfo: too many memory chunks\n");
+ break;
+
+ case BI_RAMDISK:
+ m68k_ramdisk.addr = data[0];
+ m68k_ramdisk.size = data[1];
+ break;
+
+ case BI_COMMAND_LINE:
+ strlcpy(m68k_command_line, (const char *)data,
+ sizeof(m68k_command_line));
+ break;
+
+ default:
+ if (MACH_IS_AMIGA)
+ unknown = amiga_parse_bootinfo(record);
+ else if (MACH_IS_ATARI)
+ unknown = atari_parse_bootinfo(record);
+ else if (MACH_IS_MAC)
+ unknown = mac_parse_bootinfo(record);
+ else if (MACH_IS_Q40)
+ unknown = q40_parse_bootinfo(record);
+ else if (MACH_IS_BVME6000)
+ unknown = bvme6000_parse_bootinfo(record);
+ else if (MACH_IS_MVME16x)
+ unknown = mvme16x_parse_bootinfo(record);
+ else if (MACH_IS_MVME147)
+ unknown = mvme147_parse_bootinfo(record);
+ else if (MACH_IS_HP300)
+ unknown = hp300_parse_bootinfo(record);
+ else
+ unknown = 1;
+ }
+ if (unknown)
+ printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
+ record->tag);
+ record = (struct bi_record *)((unsigned long)record +
+ record->size);
}
- if (unknown)
- printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n",
- record->tag);
- record = (struct bi_record *)((unsigned long)record+record->size);
- }
- m68k_realnum_memory = m68k_num_memory;
+ m68k_realnum_memory = m68k_num_memory;
#ifdef CONFIG_SINGLE_MEMORY_CHUNK
- if (m68k_num_memory > 1) {
- printk("Ignoring last %i chunks of physical memory\n",
- (m68k_num_memory - 1));
- m68k_num_memory = 1;
- }
- m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
+ if (m68k_num_memory > 1) {
+ printk("Ignoring last %i chunks of physical memory\n",
+ (m68k_num_memory - 1));
+ m68k_num_memory = 1;
+ }
+ m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET;
#endif
}
@@ -215,7 +212,6 @@ void __init setup_arch(char **cmdline_p)
unsigned long endmem, startmem;
#endif
int i;
- char *p, *q;
/* The bootinfo is located right after the kernel bss */
m68k_parse_bootinfo((const struct bi_record *)&_end);
@@ -234,7 +230,7 @@ void __init setup_arch(char **cmdline_p)
/* clear the fpu if we have one */
if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
volatile int zero = 0;
- asm __volatile__ ("frestore %0" : : "m" (zero));
+ asm volatile ("frestore %0" : : "m" (zero));
}
#endif
@@ -258,37 +254,7 @@ void __init setup_arch(char **cmdline_p)
*cmdline_p = m68k_command_line;
memcpy(boot_command_line, *cmdline_p, CL_SIZE);
- /* Parse the command line for arch-specific options.
- * For the m68k, this is currently only "debug=xxx" to enable printing
- * certain kernel messages to some machine-specific device.
- */
- for( p = *cmdline_p; p && *p; ) {
- i = 0;
- if (!strncmp( p, "debug=", 6 )) {
- strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) );
- if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0;
- i = 1;
- }
-#ifdef CONFIG_ATARI
- /* This option must be parsed very early */
- if (!strncmp( p, "switches=", 9 )) {
- extern void atari_switches_setup( const char *, int );
- atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ?
- (q - (p+9)) : strlen(p+9) );
- i = 1;
- }
-#endif
-
- if (i) {
- /* option processed, delete it */
- if ((q = strchr( p, ' ' )))
- strcpy( p, q+1 );
- else
- *p = 0;
- } else {
- if ((p = strchr( p, ' ' ))) ++p;
- }
- }
+ parse_early_param();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -296,62 +262,62 @@ void __init setup_arch(char **cmdline_p)
switch (m68k_machtype) {
#ifdef CONFIG_AMIGA
- case MACH_AMIGA:
+ case MACH_AMIGA:
config_amiga();
break;
#endif
#ifdef CONFIG_ATARI
- case MACH_ATARI:
+ case MACH_ATARI:
config_atari();
break;
#endif
#ifdef CONFIG_MAC
- case MACH_MAC:
+ case MACH_MAC:
config_mac();
break;
#endif
#ifdef CONFIG_SUN3
- case MACH_SUN3:
+ case MACH_SUN3:
config_sun3();
break;
#endif
#ifdef CONFIG_APOLLO
- case MACH_APOLLO:
+ case MACH_APOLLO:
config_apollo();
break;
#endif
#ifdef CONFIG_MVME147
- case MACH_MVME147:
+ case MACH_MVME147:
config_mvme147();
break;
#endif
#ifdef CONFIG_MVME16x
- case MACH_MVME16x:
+ case MACH_MVME16x:
config_mvme16x();
break;
#endif
#ifdef CONFIG_BVME6000
- case MACH_BVME6000:
+ case MACH_BVME6000:
config_bvme6000();
break;
#endif
#ifdef CONFIG_HP300
- case MACH_HP300:
+ case MACH_HP300:
config_hp300();
break;
#endif
#ifdef CONFIG_Q40
- case MACH_Q40:
- config_q40();
+ case MACH_Q40:
+ config_q40();
break;
#endif
#ifdef CONFIG_SUN3X
- case MACH_SUN3X:
+ case MACH_SUN3X:
config_sun3x();
break;
#endif
- default:
- panic ("No configuration setup");
+ default:
+ panic("No configuration setup");
}
#ifndef CONFIG_SUN3
@@ -380,7 +346,7 @@ void __init setup_arch(char **cmdline_p)
reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size);
initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr);
initrd_end = initrd_start + m68k_ramdisk.size;
- printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
+ printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end);
}
#endif
@@ -402,18 +368,18 @@ void __init setup_arch(char **cmdline_p)
#if defined(CONFIG_ISA) && defined(MULTI_ISA)
#if defined(CONFIG_Q40)
if (MACH_IS_Q40) {
- isa_type = Q40_ISA;
- isa_sex = 0;
+ isa_type = Q40_ISA;
+ isa_sex = 0;
}
#elif defined(CONFIG_GG2)
- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){
- isa_type = GG2_ISA;
- isa_sex = 0;
+ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) {
+ isa_type = GG2_ISA;
+ isa_sex = 0;
}
#elif defined(CONFIG_AMIGA_PCMCIA)
- if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){
- isa_type = AG_ISA;
- isa_sex = 1;
+ if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) {
+ isa_type = AG_ISA;
+ isa_sex = 1;
}
#endif
#endif
@@ -421,66 +387,66 @@ void __init setup_arch(char **cmdline_p)
static int show_cpuinfo(struct seq_file *m, void *v)
{
- const char *cpu, *mmu, *fpu;
- unsigned long clockfreq, clockfactor;
+ const char *cpu, *mmu, *fpu;
+ unsigned long clockfreq, clockfactor;
#define LOOP_CYCLES_68020 (8)
#define LOOP_CYCLES_68030 (8)
#define LOOP_CYCLES_68040 (3)
#define LOOP_CYCLES_68060 (1)
- if (CPU_IS_020) {
- cpu = "68020";
- clockfactor = LOOP_CYCLES_68020;
- } else if (CPU_IS_030) {
- cpu = "68030";
- clockfactor = LOOP_CYCLES_68030;
- } else if (CPU_IS_040) {
- cpu = "68040";
- clockfactor = LOOP_CYCLES_68040;
- } else if (CPU_IS_060) {
- cpu = "68060";
- clockfactor = LOOP_CYCLES_68060;
- } else {
- cpu = "680x0";
- clockfactor = 0;
- }
+ if (CPU_IS_020) {
+ cpu = "68020";
+ clockfactor = LOOP_CYCLES_68020;
+ } else if (CPU_IS_030) {
+ cpu = "68030";
+ clockfactor = LOOP_CYCLES_68030;
+ } else if (CPU_IS_040) {
+ cpu = "68040";
+ clockfactor = LOOP_CYCLES_68040;
+ } else if (CPU_IS_060) {
+ cpu = "68060";
+ clockfactor = LOOP_CYCLES_68060;
+ } else {
+ cpu = "680x0";
+ clockfactor = 0;
+ }
#ifdef CONFIG_M68KFPU_EMU_ONLY
- fpu="none(soft float)";
+ fpu = "none(soft float)";
#else
- if (m68k_fputype & FPU_68881)
- fpu = "68881";
- else if (m68k_fputype & FPU_68882)
- fpu = "68882";
- else if (m68k_fputype & FPU_68040)
- fpu = "68040";
- else if (m68k_fputype & FPU_68060)
- fpu = "68060";
- else if (m68k_fputype & FPU_SUNFPA)
- fpu = "Sun FPA";
- else
- fpu = "none";
+ if (m68k_fputype & FPU_68881)
+ fpu = "68881";
+ else if (m68k_fputype & FPU_68882)
+ fpu = "68882";
+ else if (m68k_fputype & FPU_68040)
+ fpu = "68040";
+ else if (m68k_fputype & FPU_68060)
+ fpu = "68060";
+ else if (m68k_fputype & FPU_SUNFPA)
+ fpu = "Sun FPA";
+ else
+ fpu = "none";
#endif
- if (m68k_mmutype & MMU_68851)
- mmu = "68851";
- else if (m68k_mmutype & MMU_68030)
- mmu = "68030";
- else if (m68k_mmutype & MMU_68040)
- mmu = "68040";
- else if (m68k_mmutype & MMU_68060)
- mmu = "68060";
- else if (m68k_mmutype & MMU_SUN3)
- mmu = "Sun-3";
- else if (m68k_mmutype & MMU_APOLLO)
- mmu = "Apollo";
- else
- mmu = "unknown";
-
- clockfreq = loops_per_jiffy*HZ*clockfactor;
-
- seq_printf(m, "CPU:\t\t%s\n"
+ if (m68k_mmutype & MMU_68851)
+ mmu = "68851";
+ else if (m68k_mmutype & MMU_68030)
+ mmu = "68030";
+ else if (m68k_mmutype & MMU_68040)
+ mmu = "68040";
+ else if (m68k_mmutype & MMU_68060)
+ mmu = "68060";
+ else if (m68k_mmutype & MMU_SUN3)
+ mmu = "Sun-3";
+ else if (m68k_mmutype & MMU_APOLLO)
+ mmu = "Apollo";
+ else
+ mmu = "unknown";
+
+ clockfreq = loops_per_jiffy * HZ * clockfactor;
+
+ seq_printf(m, "CPU:\t\t%s\n"
"MMU:\t\t%s\n"
"FPU:\t\t%s\n"
"Clocking:\t%lu.%1luMHz\n"
@@ -490,7 +456,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
clockfreq/1000000,(clockfreq/100000)%10,
loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100,
loops_per_jiffy);
- return 0;
+ return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
@@ -506,44 +472,54 @@ static void c_stop(struct seq_file *m, void *v)
{
}
struct seq_operations cpuinfo_op = {
- .start = c_start,
- .next = c_next,
- .stop = c_stop,
- .show = show_cpuinfo,
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
};
int get_hardware_list(char *buffer)
{
- int len = 0;
- char model[80];
- unsigned long mem;
- int i;
+ int len = 0;
+ char model[80];
+ unsigned long mem;
+ int i;
- if (mach_get_model)
- mach_get_model(model);
- else
- strcpy(model, "Unknown m68k");
+ if (mach_get_model)
+ mach_get_model(model);
+ else
+ strcpy(model, "Unknown m68k");
- len += sprintf(buffer+len, "Model:\t\t%s\n", model);
- for (mem = 0, i = 0; i < m68k_num_memory; i++)
- mem += m68k_memory[i].size;
- len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10);
+ len += sprintf(buffer + len, "Model:\t\t%s\n", model);
+ for (mem = 0, i = 0; i < m68k_num_memory; i++)
+ mem += m68k_memory[i].size;
+ len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10);
- if (mach_get_hardware_list)
- len += mach_get_hardware_list(buffer+len);
+ if (mach_get_hardware_list)
+ len += mach_get_hardware_list(buffer + len);
- return(len);
+ return len;
}
void check_bugs(void)
{
#ifndef CONFIG_M68KFPU_EMU
if (m68k_fputype == 0) {
- printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
- "WHICH IS REQUIRED BY LINUX/M68K ***\n" );
- printk( KERN_EMERG "Upgrade your hardware or join the FPU "
- "emulation project\n" );
- panic( "no FPU" );
+ printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, "
+ "WHICH IS REQUIRED BY LINUX/M68K ***\n");
+ printk(KERN_EMERG "Upgrade your hardware or join the FPU "
+ "emulation project\n");
+ panic("no FPU");
}
#endif /* !CONFIG_M68KFPU_EMU */
}
+
+#ifdef CONFIG_ADB
+static int __init adb_probe_sync_enable (char *str) {
+ extern int __adb_probe_sync;
+ __adb_probe_sync = 1;
+ return 1;
+}
+
+__setup("adb_sync", adb_probe_sync_enable);
+#endif /* CONFIG_ADB */
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
index aed3be29e06..cf6bb51945a 100644
--- a/arch/m68k/lib/checksum.c
+++ b/arch/m68k/lib/checksum.c
@@ -320,6 +320,9 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
return(sum);
}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
+
+
/*
* copy from kernel space while checksumming, otherwise like csum_partial
*/
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index a1c7ec70674..673a1085984 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -22,7 +22,7 @@
/* #define DEBUG_BABOON */
/* #define DEBUG_IRQS */
-int baboon_present,baboon_active;
+int baboon_present;
volatile struct baboon *baboon;
irqreturn_t baboon_irq(int, void *);
@@ -45,7 +45,6 @@ void __init baboon_init(void)
baboon = (struct baboon *) BABOON_BASE;
baboon_present = 1;
- baboon_active = 0;
printk("Baboon detected at %p\n", baboon);
}
@@ -66,26 +65,28 @@ void __init baboon_register_interrupts(void)
irqreturn_t baboon_irq(int irq, void *dev_id)
{
- int irq_bit,i;
+ int irq_bit, irq_num;
unsigned char events;
#ifdef DEBUG_IRQS
- printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n",
+ printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n",
(uint) baboon->mb_control, (uint) baboon->mb_ifr,
- (uint) baboon->mb_status, baboon_active);
+ (uint) baboon->mb_status);
#endif
if (!(events = baboon->mb_ifr & 0x07))
return IRQ_NONE;
- for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
- if (events & irq_bit/* & baboon_active*/) {
- baboon_active &= ~irq_bit;
- m68k_handle_int(IRQ_BABOON_0 + i);
- baboon_active |= irq_bit;
+ irq_num = IRQ_BABOON_0;
+ irq_bit = 1;
+ do {
+ if (events & irq_bit) {
baboon->mb_ifr &= ~irq_bit;
+ m68k_handle_int(irq_num);
}
- }
+ irq_bit <<= 1;
+ irq_num++;
+ } while(events >= irq_bit);
#if 0
if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL);
/* for now we need to smash all interrupts */
@@ -95,21 +96,18 @@ irqreturn_t baboon_irq(int irq, void *dev_id)
}
void baboon_irq_enable(int irq) {
- int irq_idx = IRQ_IDX(irq);
-
#ifdef DEBUG_IRQUSE
printk("baboon_irq_enable(%d)\n", irq);
#endif
- baboon_active |= (1 << irq_idx);
+ /* FIXME: figure out how to mask and unmask baboon interrupt sources */
+ enable_irq(IRQ_NUBUS_C);
}
void baboon_irq_disable(int irq) {
- int irq_idx = IRQ_IDX(irq);
-
#ifdef DEBUG_IRQUSE
printk("baboon_irq_disable(%d)\n", irq);
#endif
- baboon_active &= ~(1 << irq_idx);
+ disable_irq(IRQ_NUBUS_C);
}
void baboon_irq_clear(int irq) {
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 562b38d0018..5fd413246f8 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -59,15 +59,15 @@ extern struct mem_info m68k_ramdisk;
extern char m68k_command_line[CL_SIZE];
-void *mac_env; /* Loaded by the boot asm */
+void *mac_env; /* Loaded by the boot asm */
/* The phys. video addr. - might be bogus on some machines */
unsigned long mac_orig_videoaddr;
/* Mac specific timer functions */
-extern unsigned long mac_gettimeoffset (void);
-extern int mac_hwclk (int, struct rtc_time *);
-extern int mac_set_clock_mmss (unsigned long);
+extern unsigned long mac_gettimeoffset(void);
+extern int mac_hwclk(int, struct rtc_time *);
+extern int mac_set_clock_mmss(unsigned long);
extern int show_mac_interrupts(struct seq_file *, void *);
extern void iop_preinit(void);
extern void iop_init(void);
@@ -82,10 +82,6 @@ extern void mac_mksound(unsigned int, unsigned int);
extern void nubus_sweep_video(void);
-/* Mac specific debug functions (in debug.c) */
-extern void mac_debug_init(void);
-extern void mac_debugging_long(int, long);
-
static void mac_get_model(char *str);
static void mac_sched_init(irq_handler_t vector)
@@ -99,51 +95,52 @@ static void mac_sched_init(irq_handler_t vector)
int __init mac_parse_bootinfo(const struct bi_record *record)
{
- int unknown = 0;
- const u_long *data = record->data;
+ int unknown = 0;
+ const u_long *data = record->data;
- switch (record->tag) {
+ switch (record->tag) {
case BI_MAC_MODEL:
- mac_bi_data.id = *data;
- break;
+ mac_bi_data.id = *data;
+ break;
case BI_MAC_VADDR:
- mac_bi_data.videoaddr = *data;
- break;
+ mac_bi_data.videoaddr = *data;
+ break;
case BI_MAC_VDEPTH:
- mac_bi_data.videodepth = *data;
- break;
+ mac_bi_data.videodepth = *data;
+ break;
case BI_MAC_VROW:
- mac_bi_data.videorow = *data;
- break;
+ mac_bi_data.videorow = *data;
+ break;
case BI_MAC_VDIM:
- mac_bi_data.dimensions = *data;
- break;
+ mac_bi_data.dimensions = *data;
+ break;
case BI_MAC_VLOGICAL:
- mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
- mac_orig_videoaddr = *data;
- break;
+ mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK);
+ mac_orig_videoaddr = *data;
+ break;
case BI_MAC_SCCBASE:
- mac_bi_data.sccbase = *data;
- break;
+ mac_bi_data.sccbase = *data;
+ break;
case BI_MAC_BTIME:
- mac_bi_data.boottime = *data;
- break;
+ mac_bi_data.boottime = *data;
+ break;
case BI_MAC_GMTBIAS:
- mac_bi_data.gmtbias = *data;
- break;
+ mac_bi_data.gmtbias = *data;
+ break;
case BI_MAC_MEMSIZE:
- mac_bi_data.memsize = *data;
- break;
+ mac_bi_data.memsize = *data;
+ break;
case BI_MAC_CPUID:
- mac_bi_data.cpuid = *data;
- break;
- case BI_MAC_ROMBASE:
- mac_bi_data.rombase = *data;
- break;
+ mac_bi_data.cpuid = *data;
+ break;
+ case BI_MAC_ROMBASE:
+ mac_bi_data.rombase = *data;
+ break;
default:
- unknown = 1;
- }
- return(unknown);
+ unknown = 1;
+ break;
+ }
+ return unknown;
}
/*
@@ -155,6 +152,7 @@ int __init mac_parse_bootinfo(const struct bi_record *record)
static void mac_cache_card_flush(int writeback)
{
unsigned long flags;
+
local_irq_save(flags);
via_flush_cache();
local_irq_restore(flags);
@@ -162,28 +160,24 @@ static void mac_cache_card_flush(int writeback)
void __init config_mac(void)
{
- if (!MACH_IS_MAC) {
- printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
- }
+ if (!MACH_IS_MAC)
+ printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n");
- mach_sched_init = mac_sched_init;
- mach_init_IRQ = mac_init_IRQ;
- mach_get_model = mac_get_model;
- mach_gettimeoffset = mac_gettimeoffset;
+ mach_sched_init = mac_sched_init;
+ mach_init_IRQ = mac_init_IRQ;
+ mach_get_model = mac_get_model;
+ mach_gettimeoffset = mac_gettimeoffset;
#warning move to adb/via init
#if 0
- mach_hwclk = mac_hwclk;
+ mach_hwclk = mac_hwclk;
#endif
- mach_set_clock_mmss = mac_set_clock_mmss;
- mach_reset = mac_reset;
- mach_halt = mac_poweroff;
- mach_power_off = mac_poweroff;
+ mach_set_clock_mmss = mac_set_clock_mmss;
+ mach_reset = mac_reset;
+ mach_halt = mac_poweroff;
+ mach_power_off = mac_poweroff;
mach_max_dma_address = 0xffffffff;
-#if 0
- mach_debug_init = mac_debug_init;
-#endif
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
- mach_beep = mac_mksound;
+ mach_beep = mac_mksound;
#endif
#ifdef CONFIG_HEARTBEAT
#if 0
@@ -199,21 +193,22 @@ void __init config_mac(void)
mac_identify();
mac_report_hardware();
- /* AFAIK only the IIci takes a cache card. The IIfx has onboard
- cache ... someone needs to figure out how to tell if it's on or
- not. */
+ /*
+ * AFAIK only the IIci takes a cache card. The IIfx has onboard
+ * cache ... someone needs to figure out how to tell if it's on or
+ * not.
+ */
if (macintosh_config->ident == MAC_MODEL_IICI
- || macintosh_config->ident == MAC_MODEL_IIFX) {
+ || macintosh_config->ident == MAC_MODEL_IIFX)
mach_l2_flush = mac_cache_card_flush;
- }
/*
* Check for machine specific fixups.
*/
#ifdef OLD_NUBUS_CODE
- nubus_sweep_video();
+ nubus_sweep_video();
#endif
}
@@ -233,8 +228,7 @@ void __init config_mac(void)
struct mac_model *macintosh_config;
EXPORT_SYMBOL(macintosh_config);
-static struct mac_model mac_data_table[]=
-{
+static struct mac_model mac_data_table[] = {
/*
* We'll pretend to be a Macintosh II, that's pretty safe.
*/
@@ -784,12 +778,12 @@ void mac_identify(void)
if (!model) {
/* no bootinfo model id -> NetBSD booter was used! */
/* XXX FIXME: breaks for model > 31 */
- model=(mac_bi_data.cpuid>>2)&63;
- printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
+ model = (mac_bi_data.cpuid >> 2) & 63;
+ printk(KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n");
}
macintosh_config = mac_data_table;
- for (m = macintosh_config ; m->ident != -1 ; m++) {
+ for (m = macintosh_config; m->ident != -1; m++) {
if (m->ident == model) {
macintosh_config = m;
break;
@@ -801,27 +795,26 @@ void mac_identify(void)
/* the serial ports set to "Faster" mode in MacOS. */
iop_preinit();
- mac_debug_init();
- printk (KERN_INFO "Detected Macintosh model: %d \n", model);
+ printk(KERN_INFO "Detected Macintosh model: %d \n", model);
/*
* Report booter data:
*/
- printk (KERN_DEBUG " Penguin bootinfo data:\n");
- printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
+ printk(KERN_DEBUG " Penguin bootinfo data:\n");
+ printk(KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n",
mac_bi_data.videoaddr, mac_bi_data.videorow,
mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF,
mac_bi_data.dimensions >> 16);
- printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
+ printk(KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n",
mac_bi_data.videological, mac_orig_videoaddr,
mac_bi_data.sccbase);
- printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
+ printk(KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n",
mac_bi_data.boottime, mac_bi_data.gmtbias);
- printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
+ printk(KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n",
mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize);
#if 0
- printk ("Ramdisk: addr 0x%lx size 0x%lx\n",
+ printk("Ramdisk: addr 0x%lx size 0x%lx\n",
m68k_ramdisk.addr, m68k_ramdisk.size);
#endif
@@ -830,22 +823,22 @@ void mac_identify(void)
*/
switch (macintosh_config->scsi_type) {
case MAC_SCSI_OLD:
- MACHW_SET(MAC_SCSI_80);
- break;
+ MACHW_SET(MAC_SCSI_80);
+ break;
case MAC_SCSI_QUADRA:
case MAC_SCSI_QUADRA2:
case MAC_SCSI_QUADRA3:
- MACHW_SET(MAC_SCSI_96);
- if ((macintosh_config->ident == MAC_MODEL_Q900) ||
- (macintosh_config->ident == MAC_MODEL_Q950))
- MACHW_SET(MAC_SCSI_96_2);
- break;
+ MACHW_SET(MAC_SCSI_96);
+ if ((macintosh_config->ident == MAC_MODEL_Q900) ||
+ (macintosh_config->ident == MAC_MODEL_Q950))
+ MACHW_SET(MAC_SCSI_96_2);
+ break;
default:
- printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
- MACHW_SET(MAC_SCSI_80);
- break;
-
+ printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n");
+ MACHW_SET(MAC_SCSI_80);
+ break;
}
+
iop_init();
via_init();
oss_init();
@@ -860,6 +853,6 @@ void mac_report_hardware(void)
static void mac_get_model(char *str)
{
- strcpy(str,"Macintosh ");
+ strcpy(str, "Macintosh ");
strcat(str, macintosh_config->name);
}
diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c
index 4eeb09dc0e8..7a5bed5bdc5 100644
--- a/arch/m68k/mac/debug.c
+++ b/arch/m68k/mac/debug.c
@@ -27,10 +27,6 @@
#include <asm/machw.h>
#include <asm/macints.h>
-extern char m68k_debug_device[];
-
-extern struct compat_bootinfo compat_boot_info;
-
extern unsigned long mac_videobase;
extern unsigned long mac_videodepth;
extern unsigned long mac_rowbytes;
@@ -52,7 +48,7 @@ extern void mac_serial_print(const char *);
*/
#ifdef DEBUG_SCREEN
-static int peng=0, line=0;
+static int peng, line;
#endif
void mac_debugging_short(int pos, short num)
@@ -74,15 +70,14 @@ void mac_debugging_short(int pos, short num)
}
/* calculate current offset */
- pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
- +80*peng;
+ pengoffset = (unsigned char *)mac_videobase +
+ (150+line*2) * mac_rowbytes) + 80 * peng;
- pptr=pengoffset;
+ pptr = pengoffset;
- for(i=0;i<8*sizeof(short);i++) /* # of bits */
- {
+ for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */
/* value mask for bit i, reverse order */
- *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00);
+ *pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00);
}
peng++;
@@ -115,11 +110,10 @@ void mac_debugging_long(int pos, long addr)
pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes)
+80*peng;
- pptr=pengoffset;
+ pptr = pengoffset;
- for(i=0;i<8*sizeof(long);i++) /* # of bits */
- {
- *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00);
+ for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */
+ *pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00);
}
peng++;
@@ -136,16 +130,15 @@ void mac_debugging_long(int pos, long addr)
* TODO: serial debug code
*/
-struct mac_SCC
- {
- u_char cha_b_ctrl;
- u_char char_dummy1;
- u_char cha_a_ctrl;
- u_char char_dummy2;
- u_char cha_b_data;
- u_char char_dummy3;
- u_char cha_a_data;
- };
+struct mac_SCC {
+ u_char cha_b_ctrl;
+ u_char char_dummy1;
+ u_char cha_a_ctrl;
+ u_char char_dummy2;
+ u_char cha_b_data;
+ u_char char_dummy3;
+ u_char cha_a_data;
+};
# define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase))
@@ -158,9 +151,9 @@ int mac_SCC_reset_done;
static int scc_port = -1;
static struct console mac_console_driver = {
- .name = "debug",
- .flags = CON_PRINTBUFFER,
- .index = -1,
+ .name = "debug",
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
/*
@@ -178,8 +171,8 @@ static struct console mac_console_driver = {
* this driver if Mac.
*/
-void mac_debug_console_write (struct console *co, const char *str,
- unsigned int count)
+void mac_debug_console_write(struct console *co, const char *str,
+ unsigned int count)
{
mac_serial_print(str);
}
@@ -190,48 +183,50 @@ void mac_debug_console_write (struct console *co, const char *str,
#define uSEC 1
-static inline void mac_sccb_out (char c)
+static inline void mac_sccb_out(char c)
{
- int i;
- do {
- for( i = uSEC; i > 0; --i )
+ int i;
+
+ do {
+ for (i = uSEC; i > 0; --i)
+ barrier();
+ } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
+ for (i = uSEC; i > 0; --i)
barrier();
- } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */
- for( i = uSEC; i > 0; --i )
- barrier();
- scc.cha_b_data = c;
+ scc.cha_b_data = c;
}
-static inline void mac_scca_out (char c)
+static inline void mac_scca_out(char c)
{
- int i;
- do {
- for( i = uSEC; i > 0; --i )
+ int i;
+
+ do {
+ for (i = uSEC; i > 0; --i)
+ barrier();
+ } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
+ for (i = uSEC; i > 0; --i)
barrier();
- } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */
- for( i = uSEC; i > 0; --i )
- barrier();
- scc.cha_a_data = c;
+ scc.cha_a_data = c;
}
-void mac_sccb_console_write (struct console *co, const char *str,
- unsigned int count)
+void mac_sccb_console_write(struct console *co, const char *str,
+ unsigned int count)
{
- while (count--) {
- if (*str == '\n')
- mac_sccb_out( '\r' );
- mac_sccb_out( *str++ );
- }
+ while (count--) {
+ if (*str == '\n')
+ mac_sccb_out('\r');
+ mac_sccb_out(*str++);
+ }
}
-void mac_scca_console_write (struct console *co, const char *str,
- unsigned int count)
+void mac_scca_console_write(struct console *co, const char *str,
+ unsigned int count)
{
- while (count--) {
- if (*str == '\n')
- mac_scca_out( '\r' );
- mac_scca_out( *str++ );
- }
+ while (count--) {
+ if (*str == '\n')
+ mac_scca_out('\r');
+ mac_scca_out(*str++);
+ }
}
@@ -239,41 +234,41 @@ void mac_scca_console_write (struct console *co, const char *str,
* SCC serial ports. They're used by the debugging interface, kgdb, and the
* serial console code. */
#define SCCB_WRITE(reg,val) \
- do { \
- int i; \
- scc.cha_b_ctrl = (reg); \
- for( i = uSEC; i > 0; --i ) \
- barrier(); \
- scc.cha_b_ctrl = (val); \
- for( i = uSEC; i > 0; --i ) \
- barrier(); \
- } while(0)
+ do { \
+ int i; \
+ scc.cha_b_ctrl = (reg); \
+ for (i = uSEC; i > 0; --i) \
+ barrier(); \
+ scc.cha_b_ctrl = (val); \
+ for (i = uSEC; i > 0; --i) \
+ barrier(); \
+ } while(0)
#define SCCA_WRITE(reg,val) \
- do { \
- int i; \
- scc.cha_a_ctrl = (reg); \
- for( i = uSEC; i > 0; --i ) \
- barrier(); \
- scc.cha_a_ctrl = (val); \
- for( i = uSEC; i > 0; --i ) \
- barrier(); \
- } while(0)
+ do { \
+ int i; \
+ scc.cha_a_ctrl = (reg); \
+ for (i = uSEC; i > 0; --i) \
+ barrier(); \
+ scc.cha_a_ctrl = (val); \
+ for (i = uSEC; i > 0; --i) \
+ barrier(); \
+ } while(0)
/* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a
* delay of ~ 60us. */
/* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/
-#define LONG_DELAY() \
- do { \
- int i; \
- for( i = 60*uSEC; i > 0; --i ) \
- barrier(); \
- } while(0)
+#define LONG_DELAY() \
+ do { \
+ int i; \
+ for (i = 60*uSEC; i > 0; --i) \
+ barrier(); \
+ } while(0)
#ifndef CONFIG_SERIAL_CONSOLE
-static void __init mac_init_scc_port( int cflag, int port )
+static void __init mac_init_scc_port(int cflag, int port)
#else
-void mac_init_scc_port( int cflag, int port )
+void mac_init_scc_port(int cflag, int port)
#endif
{
extern int mac_SCC_reset_done;
@@ -292,106 +287,102 @@ void mac_init_scc_port( int cflag, int port )
/* reg12 (BRG low) */
{ 94, 62, 46, 22, 10, 4, 1, 0, 0 };
- int baud = cflag & CBAUD;
- int clksrc, clkmode, div, reg3, reg5;
-
- if (cflag & CBAUDEX)
- baud += B38400;
- if (baud < B1200 || baud > B38400+2)
- baud = B9600; /* use default 9600bps for non-implemented rates */
- baud -= B1200; /* tables starts at 1200bps */
-
- clksrc = clksrc_table[baud];
- clkmode = clkmode_table[baud];
- div = div_table[baud];
-
- reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
- reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
-
- if (port == 1) {
- (void)scc.cha_b_ctrl; /* reset reg pointer */
- SCCB_WRITE( 9, 0xc0 ); /* reset */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+ int baud = cflag & CBAUD;
+ int clksrc, clkmode, div, reg3, reg5;
+
+ if (cflag & CBAUDEX)
+ baud += B38400;
+ if (baud < B1200 || baud > B38400+2)
+ baud = B9600; /* use default 9600bps for non-implemented rates */
+ baud -= B1200; /* tables starts at 1200bps */
+
+ clksrc = clksrc_table[baud];
+ clkmode = clkmode_table[baud];
+ div = div_table[baud];
+
+ reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40);
+ reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */;
+
+ if (port == 1) {
+ (void)scc.cha_b_ctrl; /* reset reg pointer */
+ SCCB_WRITE(9, 0xc0); /* reset */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
+ 0x04 /* 1 stopbit */ |
+ clkmode);
+ SCCB_WRITE(3, reg3);
+ SCCB_WRITE(5, reg5);
+ SCCB_WRITE(9, 0); /* no interrupts */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCB_WRITE(10, 0); /* NRZ mode */
+ SCCB_WRITE(11, clksrc); /* main clock source */
+ SCCB_WRITE(12, div); /* BRG value */
+ SCCB_WRITE(13, 0); /* BRG high byte */
+ SCCB_WRITE(14, 1);
+ SCCB_WRITE(3, reg3 | 1);
+ SCCB_WRITE(5, reg5 | 8);
+ } else if (port == 0) {
+ (void)scc.cha_a_ctrl; /* reset reg pointer */
+ SCCA_WRITE(9, 0xc0); /* reset */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
0x04 /* 1 stopbit */ |
- clkmode );
- SCCB_WRITE( 3, reg3 );
- SCCB_WRITE( 5, reg5 );
- SCCB_WRITE( 9, 0 ); /* no interrupts */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCCB_WRITE( 10, 0 ); /* NRZ mode */
- SCCB_WRITE( 11, clksrc ); /* main clock source */
- SCCB_WRITE( 12, div ); /* BRG value */
- SCCB_WRITE( 13, 0 ); /* BRG high byte */
- SCCB_WRITE( 14, 1 );
- SCCB_WRITE( 3, reg3 | 1 );
- SCCB_WRITE( 5, reg5 | 8 );
- } else if (port == 0) {
- (void)scc.cha_a_ctrl; /* reset reg pointer */
- SCCA_WRITE( 9, 0xc0 ); /* reset */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 |
- 0x04 /* 1 stopbit */ |
- clkmode );
- SCCA_WRITE( 3, reg3 );
- SCCA_WRITE( 5, reg5 );
- SCCA_WRITE( 9, 0 ); /* no interrupts */
- LONG_DELAY(); /* extra delay after WR9 access */
- SCCA_WRITE( 10, 0 ); /* NRZ mode */
- SCCA_WRITE( 11, clksrc ); /* main clock source */
- SCCA_WRITE( 12, div ); /* BRG value */
- SCCA_WRITE( 13, 0 ); /* BRG high byte */
- SCCA_WRITE( 14, 1 );
- SCCA_WRITE( 3, reg3 | 1 );
- SCCA_WRITE( 5, reg5 | 8 );
- }
-
- mac_SCC_reset_done = 1;
- mac_SCC_init_done = 1;
+ clkmode);
+ SCCA_WRITE(3, reg3);
+ SCCA_WRITE(5, reg5);
+ SCCA_WRITE(9, 0); /* no interrupts */
+ LONG_DELAY(); /* extra delay after WR9 access */
+ SCCA_WRITE(10, 0); /* NRZ mode */
+ SCCA_WRITE(11, clksrc); /* main clock source */
+ SCCA_WRITE(12, div); /* BRG value */
+ SCCA_WRITE(13, 0); /* BRG high byte */
+ SCCA_WRITE(14, 1);
+ SCCA_WRITE(3, reg3 | 1);
+ SCCA_WRITE(5, reg5 | 8);
+ }
+
+ mac_SCC_reset_done = 1;
+ mac_SCC_init_done = 1;
}
#endif /* DEBUG_SERIAL */
-void mac_init_scca_port( int cflag )
+void mac_init_scca_port(int cflag)
{
mac_init_scc_port(cflag, 0);
}
-void mac_init_sccb_port( int cflag )
+void mac_init_sccb_port(int cflag)
{
mac_init_scc_port(cflag, 1);
}
-void __init mac_debug_init(void)
+static int __init mac_debug_setup(char *arg)
{
+ if (!MACH_IS_MAC)
+ return 0;
+
#ifdef DEBUG_SERIAL
- if ( !strcmp( m68k_debug_device, "ser" )
- || !strcmp( m68k_debug_device, "ser1" )) {
- /* Mac modem port */
- mac_init_scc_port( B9600|CS8, 0 );
- mac_console_driver.write = mac_scca_console_write;
- scc_port = 0;
- }
- else if (!strcmp( m68k_debug_device, "ser2" )) {
- /* Mac printer port */
- mac_init_scc_port( B9600|CS8, 1 );
- mac_console_driver.write = mac_sccb_console_write;
- scc_port = 1;
- }
+ if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) {
+ /* Mac modem port */
+ mac_init_scc_port(B9600|CS8, 0);
+ mac_console_driver.write = mac_scca_console_write;
+ scc_port = 0;
+ } else if (!strcmp(arg, "ser2")) {
+ /* Mac printer port */
+ mac_init_scc_port(B9600|CS8, 1);
+ mac_console_driver.write = mac_sccb_console_write;
+ scc_port = 1;
+ }
#endif
#ifdef DEBUG_HEADS
- if ( !strcmp( m68k_debug_device, "scn" )
- || !strcmp( m68k_debug_device, "con" )) {
- /* display, using head.S console routines */
- mac_console_driver.write = mac_debug_console_write;
- }
+ if (!strcmp(arg, "scn") || !strcmp(arg, "con")) {
+ /* display, using head.S console routines */
+ mac_console_driver.write = mac_debug_console_write;
+ }
#endif
- if (mac_console_driver.write)
- register_console(&mac_console_driver);
+ if (mac_console_driver.write)
+ register_console(&mac_console_driver);
+ return 0;
}
-/*
- * Local variables:
- * c-indent-level: 4
- * tab-width: 8
- * End:
- */
+early_param("debug", mac_debug_setup);
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index f6fcd754d8f..0fc72d8f786 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -219,7 +219,7 @@ static void mac_disable_irq(unsigned int irq);
static struct irq_controller mac_irq_controller = {
.name = "mac",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock),
.enable = mac_enable_irq,
.disable = mac_disable_irq,
};
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 63690819565..d7be16917ef 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -109,13 +109,11 @@ irqreturn_t oss_irq(int irq, void *dev_id)
/* FIXME: how do you clear a pending IRQ? */
if (events & OSS_IP_SOUND) {
- /* FIXME: call sound handler */
oss->irq_pending &= ~OSS_IP_SOUND;
+ /* FIXME: call sound handler */
} else if (events & OSS_IP_SCSI) {
- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
- m68k_handle_int(IRQ_MAC_SCSI);
oss->irq_pending &= ~OSS_IP_SCSI;
- oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
+ m68k_handle_int(IRQ_MAC_SCSI);
} else {
/* FIXME: error check here? */
}
@@ -143,14 +141,16 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id)
#endif
/* There are only six slots on the OSS, not seven */
- for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
+ i = 6;
+ irq_bit = 0x40;
+ do {
+ --i;
+ irq_bit >>= 1;
if (events & irq_bit) {
- oss->irq_level[i] = OSS_IRQLEV_DISABLED;
- m68k_handle_int(NUBUS_SOURCE_BASE + i);
oss->irq_pending &= ~irq_bit;
- oss->irq_level[i] = OSS_IRQLEV_NUBUS;
+ m68k_handle_int(NUBUS_SOURCE_BASE + i);
}
- }
+ } while(events & (irq_bit - 1));
return IRQ_HANDLED;
}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index 15378a5878c..d66f723b17c 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -131,11 +131,8 @@ irqreturn_t psc_irq(int irq, void *dev_id)
{
int pIFR = pIFRbase + ((int) dev_id);
int pIER = pIERbase + ((int) dev_id);
- int base_irq;
- int irq_bit,i;
- unsigned char events;
-
- base_irq = irq << 3;
+ int irq_num;
+ unsigned char irq_bit, events;
#ifdef DEBUG_IRQS
printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n",
@@ -146,14 +143,16 @@ irqreturn_t psc_irq(int irq, void *dev_id)
if (!events)
return IRQ_NONE;
- for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
- if (events & irq_bit) {
- psc_write_byte(pIER, irq_bit);
- m68k_handle_int(base_irq + i);
+ irq_num = irq << 3;
+ irq_bit = 1;
+ do {
+ if (events & irq_bit) {
psc_write_byte(pIFR, irq_bit);
- psc_write_byte(pIER, irq_bit | 0x80);
+ m68k_handle_int(irq_num);
}
- }
+ irq_num++;
+ irq_bit <<= 1;
+ } while (events >= irq_bit);
return IRQ_HANDLED;
}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index e27735be292..d5cac72eb3d 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -13,6 +13,10 @@
* for info. A full-text web search on 6522 AND VIA will probably also
* net some usefulness. <cananian@alumni.princeton.edu> 20apr1999
*
+ * Additional data is here (the SY6522 was used in the Mac II etc):
+ * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf
+ * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf
+ *
* PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b
* by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org)
*
@@ -37,7 +41,7 @@ volatile __u8 *via1, *via2;
/* See note in mac_via.h about how this is possibly not useful */
volatile long *via_memory_bogon=(long *)&via_memory_bogon;
#endif
-int rbv_present,via_alt_mapping;
+int rbv_present, via_alt_mapping;
__u8 rbv_clear;
/*
@@ -60,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB;
#define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF)
#define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8)
-static int nubus_active;
+/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set
+ * high. On RBV we just use the slot interrupt enable register. On Macs with
+ * genuine VIA chips we must use nubus_disabled to keep track of disabled slot
+ * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1
+ * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt.
+ * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble,
+ * because closing one of those drivers can mask all of the NuBus interrupts.
+ * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's
+ * possible to get interrupts from cards that MacOS or the ROM has configured
+ * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and
+ * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS.
+ */
+static u8 nubus_disabled;
void via_debug_dump(void);
irqreturn_t via1_irq(int, void *);
@@ -138,11 +154,11 @@ void __init via_init(void)
printk(KERN_INFO "VIA2 at %p is ", via2);
if (rbv_present) {
- printk(KERN_INFO "an RBV\n");
+ printk("an RBV\n");
} else if (oss_present) {
- printk(KERN_INFO "an OSS\n");
+ printk("an OSS\n");
} else {
- printk(KERN_INFO "a 6522 or clone\n");
+ printk("a 6522 or clone\n");
}
#ifdef DEBUG_VIA
@@ -163,6 +179,7 @@ void __init via_init(void)
via1[vT2CL] = 0;
via1[vT2CH] = 0;
via1[vACR] &= 0x3F;
+ via1[vACR] &= ~0x03; /* disable port A & B latches */
/*
* SE/30: disable video IRQ
@@ -193,8 +210,14 @@ void __init via_init(void)
/* that the IIfx emulates this alternate mapping using the OSS. */
switch(macintosh_config->ident) {
+ case MAC_MODEL_P475:
+ case MAC_MODEL_P475F:
+ case MAC_MODEL_P575:
+ case MAC_MODEL_Q605:
+ case MAC_MODEL_Q605_ACC:
case MAC_MODEL_C610:
case MAC_MODEL_Q610:
+ case MAC_MODEL_Q630:
case MAC_MODEL_C650:
case MAC_MODEL_Q650:
case MAC_MODEL_Q700:
@@ -228,6 +251,22 @@ void __init via_init(void)
via2[vT2CL] = 0;
via2[vT2CH] = 0;
via2[vACR] &= 0x3F;
+ via2[vACR] &= ~0x03; /* disable port A & B latches */
+ }
+
+ /*
+ * Set vPCR for SCSI interrupts (but not on RBV)
+ */
+ if (!rbv_present) {
+ if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
+ /* CB2 (IRQ) indep. input, positive edge */
+ /* CA2 (DRQ) indep. input, positive edge */
+ via2[vPCR] = 0x66;
+ } else {
+ /* CB2 (IRQ) indep. input, negative edge */
+ /* CA2 (DRQ) indep. input, negative edge */
+ via2[vPCR] = 0x22;
+ }
}
}
@@ -356,78 +395,75 @@ int via_get_cache_disable(void)
void __init via_nubus_init(void)
{
- /* don't set nubus_active = 0 here, it kills the Baboon */
- /* interrupt that we've already registered. */
-
/* unlock nubus transactions */
- if (!rbv_present) {
+ if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
+ (macintosh_config->adb_type != MAC_ADB_PB2)) {
/* set the line to be an output on non-RBV machines */
- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ if (!rbv_present)
via2[vDirB] |= 0x02;
- }
- }
- /* this seems to be an ADB bit on PMU machines */
- /* according to MkLinux. -- jmt */
-
- if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ /* this seems to be an ADB bit on PMU machines */
+ /* according to MkLinux. -- jmt */
via2[gBufB] |= 0x02;
}
- /* disable nubus slot interrupts. */
- if (rbv_present) {
+ /* Disable all the slot interrupts (where possible). */
+
+ switch (macintosh_config->via_type) {
+ case MAC_VIA_II:
+ /* Just make the port A lines inputs. */
+ switch(macintosh_config->ident) {
+ case MAC_MODEL_II:
+ case MAC_MODEL_IIX:
+ case MAC_MODEL_IICX:
+ case MAC_MODEL_SE30:
+ /* The top two bits are RAM size outputs. */
+ via2[vDirA] &= 0xC0;
+ break;
+ default:
+ via2[vDirA] &= 0x80;
+ }
+ break;
+ case MAC_VIA_IIci:
+ /* RBV. Disable all the slot interrupts. SIER works like IER. */
via2[rSIER] = 0x7F;
- via2[rSIER] = nubus_active | 0x80;
- } else {
- /* These are ADB bits on PMU */
+ break;
+ case MAC_VIA_QUADRA:
+ /* Disable the inactive slot interrupts by making those lines outputs. */
if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2)) {
- switch(macintosh_config->ident)
- {
- case MAC_MODEL_II:
- case MAC_MODEL_IIX:
- case MAC_MODEL_IICX:
- case MAC_MODEL_SE30:
- via2[vBufA] |= 0x3F;
- via2[vDirA] = ~nubus_active | 0xc0;
- break;
- default:
- via2[vBufA] = 0xFF;
- via2[vDirA] = ~nubus_active;
- }
+ (macintosh_config->adb_type != MAC_ADB_PB2)) {
+ via2[vBufA] |= 0x7F;
+ via2[vDirA] |= 0x7F;
}
+ break;
}
}
/*
* The generic VIA interrupt routines (shamelessly stolen from Alan Cox's
* via6522.c :-), disable/pending masks added.
- *
- * The new interrupt architecture in macints.c takes care of a lot of the
- * gruntwork for us, including tallying the interrupts and calling the
- * handlers on the linked list. All we need to do here is basically generate
- * the machspec interrupt number after clearing the interrupt.
*/
irqreturn_t via1_irq(int irq, void *dev_id)
{
- int irq_bit, i;
- unsigned char events, mask;
+ int irq_num;
+ unsigned char irq_bit, events;
- mask = via1[vIER] & 0x7F;
- if (!(events = via1[vIFR] & mask))
+ events = via1[vIFR] & via1[vIER] & 0x7F;
+ if (!events)
return IRQ_NONE;
- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+ irq_num = VIA1_SOURCE_BASE;
+ irq_bit = 1;
+ do {
if (events & irq_bit) {
- via1[vIER] = irq_bit;
- m68k_handle_int(VIA1_SOURCE_BASE + i);
via1[vIFR] = irq_bit;
- via1[vIER] = irq_bit | 0x80;
+ m68k_handle_int(irq_num);
}
+ ++irq_num;
+ irq_bit <<= 1;
+ } while (events >= irq_bit);
#if 0 /* freakin' pmu is doing weird stuff */
if (!oss_present) {
@@ -448,20 +484,23 @@ irqreturn_t via1_irq(int irq, void *dev_id)
irqreturn_t via2_irq(int irq, void *dev_id)
{
- int irq_bit, i;
- unsigned char events, mask;
+ int irq_num;
+ unsigned char irq_bit, events;
- mask = via2[gIER] & 0x7F;
- if (!(events = via2[gIFR] & mask))
+ events = via2[gIFR] & via2[gIER] & 0x7F;
+ if (!events)
return IRQ_NONE;
- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
+ irq_num = VIA2_SOURCE_BASE;
+ irq_bit = 1;
+ do {
if (events & irq_bit) {
- via2[gIER] = irq_bit;
via2[gIFR] = irq_bit | rbv_clear;
- m68k_handle_int(VIA2_SOURCE_BASE + i);
- via2[gIER] = irq_bit | 0x80;
+ m68k_handle_int(irq_num);
}
+ ++irq_num;
+ irq_bit <<= 1;
+ } while (events >= irq_bit);
return IRQ_HANDLED;
}
@@ -472,71 +511,75 @@ irqreturn_t via2_irq(int irq, void *dev_id)
irqreturn_t via_nubus_irq(int irq, void *dev_id)
{
- int irq_bit, i;
- unsigned char events;
-
- if (!(events = ~via2[gBufA] & nubus_active))
+ int slot_irq;
+ unsigned char slot_bit, events;
+
+ events = ~via2[gBufA] & 0x7F;
+ if (rbv_present)
+ events &= via2[rSIER];
+ else
+ events &= ~via2[vDirA];
+ if (!events)
return IRQ_NONE;
- for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
- if (events & irq_bit) {
- via_irq_disable(NUBUS_SOURCE_BASE + i);
- m68k_handle_int(NUBUS_SOURCE_BASE + i);
- via_irq_enable(NUBUS_SOURCE_BASE + i);
- }
- }
+ do {
+ slot_irq = IRQ_NUBUS_F;
+ slot_bit = 0x40;
+ do {
+ if (events & slot_bit) {
+ events &= ~slot_bit;
+ m68k_handle_int(slot_irq);
+ }
+ --slot_irq;
+ slot_bit >>= 1;
+ } while (events);
+
+ /* clear the CA1 interrupt and make certain there's no more. */
+ via2[gIFR] = 0x02 | rbv_clear;
+ events = ~via2[gBufA] & 0x7F;
+ if (rbv_present)
+ events &= via2[rSIER];
+ else
+ events &= ~via2[vDirA];
+ } while (events);
return IRQ_HANDLED;
}
void via_irq_enable(int irq) {
int irq_src = IRQ_SRC(irq);
int irq_idx = IRQ_IDX(irq);
- int irq_bit = 1 << irq_idx;
#ifdef DEBUG_IRQUSE
printk(KERN_DEBUG "via_irq_enable(%d)\n", irq);
#endif
if (irq_src == 1) {
- via1[vIER] = irq_bit | 0x80;
+ via1[vIER] = IER_SET_BIT(irq_idx);
} else if (irq_src == 2) {
- /*
- * Set vPCR for SCSI interrupts (but not on RBV)
- */
- if ((irq_idx == 0) && !rbv_present) {
- if (macintosh_config->scsi_type == MAC_SCSI_OLD) {
- /* CB2 (IRQ) indep. input, positive edge */
- /* CA2 (DRQ) indep. input, positive edge */
- via2[vPCR] = 0x66;
- } else {
- /* CB2 (IRQ) indep. input, negative edge */
- /* CA2 (DRQ) indep. input, negative edge */
- via2[vPCR] = 0x22;
- }
- }
- via2[gIER] = irq_bit | 0x80;
+ if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0)
+ via2[gIER] = IER_SET_BIT(irq_idx);
} else if (irq_src == 7) {
- nubus_active |= irq_bit;
- if (rbv_present) {
- /* enable the slot interrupt. SIER works like IER. */
+ switch (macintosh_config->via_type) {
+ case MAC_VIA_II:
+ nubus_disabled &= ~(1 << irq_idx);
+ /* Enable the CA1 interrupt when no slot is disabled. */
+ if (!nubus_disabled)
+ via2[gIER] = IER_SET_BIT(1);
+ break;
+ case MAC_VIA_IIci:
+ /* On RBV, enable the slot interrupt.
+ * SIER works like IER.
+ */
via2[rSIER] = IER_SET_BIT(irq_idx);
- } else {
- /* Make sure the bit is an input, to enable the irq */
- /* But not on PowerBooks, that's ADB... */
+ break;
+ case MAC_VIA_QUADRA:
+ /* Make the port A line an input to enable the slot irq.
+ * But not on PowerBooks, that's ADB.
+ */
if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2)) {
- switch(macintosh_config->ident)
- {
- case MAC_MODEL_II:
- case MAC_MODEL_IIX:
- case MAC_MODEL_IICX:
- case MAC_MODEL_SE30:
- via2[vDirA] &= (~irq_bit | 0xc0);
- break;
- default:
- via2[vDirA] &= ~irq_bit;
- }
- }
+ (macintosh_config->adb_type != MAC_ADB_PB2))
+ via2[vDirA] &= ~(1 << irq_idx);
+ break;
}
}
}
@@ -544,29 +587,31 @@ void via_irq_enable(int irq) {
void via_irq_disable(int irq) {
int irq_src = IRQ_SRC(irq);
int irq_idx = IRQ_IDX(irq);
- int irq_bit = 1 << irq_idx;
#ifdef DEBUG_IRQUSE
printk(KERN_DEBUG "via_irq_disable(%d)\n", irq);
#endif
if (irq_src == 1) {
- via1[vIER] = irq_bit;
+ via1[vIER] = IER_CLR_BIT(irq_idx);
} else if (irq_src == 2) {
- via2[gIER] = irq_bit;
+ via2[gIER] = IER_CLR_BIT(irq_idx);
} else if (irq_src == 7) {
- if (rbv_present) {
- /* disable the slot interrupt. SIER works like IER. */
+ switch (macintosh_config->via_type) {
+ case MAC_VIA_II:
+ nubus_disabled |= 1 << irq_idx;
+ if (nubus_disabled)
+ via2[gIER] = IER_CLR_BIT(1);
+ break;
+ case MAC_VIA_IIci:
via2[rSIER] = IER_CLR_BIT(irq_idx);
- } else {
- /* disable the nubus irq by changing dir to output */
- /* except on PMU */
+ break;
+ case MAC_VIA_QUADRA:
if ((macintosh_config->adb_type != MAC_ADB_PB1) &&
- (macintosh_config->adb_type != MAC_ADB_PB2)) {
- via2[vDirA] |= irq_bit;
- }
+ (macintosh_config->adb_type != MAC_ADB_PB2))
+ via2[vDirA] |= 1 << irq_idx;
+ break;
}
- nubus_active &= ~irq_bit;
}
}
@@ -580,7 +625,9 @@ void via_irq_clear(int irq) {
} else if (irq_src == 2) {
via2[gIFR] = irq_bit | rbv_clear;
} else if (irq_src == 7) {
- /* FIXME: hmm.. */
+ /* FIXME: There is no way to clear an individual nubus slot
+ * IRQ flag, other than getting the device to do it.
+ */
}
}
@@ -600,6 +647,7 @@ int via_irq_pending(int irq)
} else if (irq_src == 2) {
return via2[gIFR] & irq_bit;
} else if (irq_src == 7) {
+ /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */
return ~via2[gBufA] & irq_bit;
}
return 0;
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 272d47eac58..e341387787a 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
-#include <linux/smp_lock.h>
#include <linux/bcd.h>
#include <asm/mvme16xhw.h>
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 92f873cc706..476e18eca75 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -35,35 +35,35 @@
#include <asm/machdep.h>
#include <asm/q40_master.h>
-extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
-extern void q40_init_IRQ (void);
+extern irqreturn_t q40_process_int(int level, struct pt_regs *regs);
+extern void q40_init_IRQ(void);
static void q40_get_model(char *model);
static int q40_get_hardware_list(char *buffer);
extern void q40_sched_init(irq_handler_t handler);
-extern unsigned long q40_gettimeoffset (void);
-extern int q40_hwclk (int, struct rtc_time *);
-extern unsigned int q40_get_ss (void);
-extern int q40_set_clock_mmss (unsigned long);
+extern unsigned long q40_gettimeoffset(void);
+extern int q40_hwclk(int, struct rtc_time *);
+extern unsigned int q40_get_ss(void);
+extern int q40_set_clock_mmss(unsigned long);
static int q40_get_rtc_pll(struct rtc_pll_info *pll);
static int q40_set_rtc_pll(struct rtc_pll_info *pll);
-extern void q40_reset (void);
+extern void q40_reset(void);
void q40_halt(void);
extern void q40_waitbut(void);
-void q40_set_vectors (void);
+void q40_set_vectors(void);
-extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ );
+extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/);
-extern char m68k_debug_device[];
static void q40_mem_console_write(struct console *co, const char *b,
- unsigned int count);
+ unsigned int count);
extern int ql_ticks;
static struct console q40_console_driver = {
- .name = "debug",
- .flags = CON_PRINTBUFFER,
- .index = -1,
+ .name = "debug",
+ .write = q40_mem_console_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
@@ -74,150 +74,162 @@ static int _cpleft;
static void q40_mem_console_write(struct console *co, const char *s,
unsigned int count)
{
- char *p=(char *)s;
-
- if (count<_cpleft)
- while (count-- >0){
- *q40_mem_cptr=*p++;
- q40_mem_cptr+=4;
- _cpleft--;
- }
+ const char *p = s;
+
+ if (count < _cpleft) {
+ while (count-- > 0) {
+ *q40_mem_cptr = *p++;
+ q40_mem_cptr += 4;
+ _cpleft--;
+ }
+ }
+}
+
+static int __init q40_debug_setup(char *arg)
+{
+ /* useful for early debugging stages - writes kernel messages into SRAM */
+ if (MACH_IS_Q40 && !strncmp(arg, "mem", 3)) {
+ /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
+ _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4;
+ register_console(&q40_console_driver);
+ }
+ return 0;
}
+
+early_param("debug", q40_debug_setup);
+
#if 0
void printq40(char *str)
{
- int l=strlen(str);
- char *p=q40_mem_cptr;
-
- while (l-- >0 && _cpleft-- >0)
- {
- *p=*str++;
- p+=4;
- }
- q40_mem_cptr=p;
+ int l = strlen(str);
+ char *p = q40_mem_cptr;
+
+ while (l-- > 0 && _cpleft-- > 0) {
+ *p = *str++;
+ p += 4;
+ }
+ q40_mem_cptr = p;
}
#endif
-static int halted=0;
+static int halted;
#ifdef CONFIG_HEARTBEAT
static void q40_heartbeat(int on)
{
- if (halted) return;
+ if (halted)
+ return;
- if (on)
- Q40_LED_ON();
- else
- Q40_LED_OFF();
+ if (on)
+ Q40_LED_ON();
+ else
+ Q40_LED_OFF();
}
#endif
void q40_reset(void)
{
- halted=1;
- printk ("\n\n*******************************************\n"
+ halted = 1;
+ printk("\n\n*******************************************\n"
"Called q40_reset : press the RESET button!! \n"
"*******************************************\n");
Q40_LED_ON();
- while(1) ;
+ while (1)
+ ;
}
void q40_halt(void)
{
- halted=1;
- printk ("\n\n*******************\n"
- " Called q40_halt\n"
- "*******************\n");
+ halted = 1;
+ printk("\n\n*******************\n"
+ " Called q40_halt\n"
+ "*******************\n");
Q40_LED_ON();
- while(1) ;
+ while (1)
+ ;
}
static void q40_get_model(char *model)
{
- sprintf(model, "Q40");
+ sprintf(model, "Q40");
}
/* No hardware options on Q40? */
static int q40_get_hardware_list(char *buffer)
{
- *buffer = '\0';
- return 0;
+ *buffer = '\0';
+ return 0;
}
-static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0};
+static unsigned int serports[] =
+{
+ 0x3f8,0x2f8,0x3e8,0x2e8,0
+};
void q40_disable_irqs(void)
{
- unsigned i,j;
+ unsigned i, j;
- j=0;
- while((i=serports[j++])) outb(0,i+UART_IER);
- master_outb(0,EXT_ENABLE_REG);
- master_outb(0,KEY_IRQ_ENABLE_REG);
+ j = 0;
+ while ((i = serports[j++]))
+ outb(0, i + UART_IER);
+ master_outb(0, EXT_ENABLE_REG);
+ master_outb(0, KEY_IRQ_ENABLE_REG);
}
void __init config_q40(void)
{
- mach_sched_init = q40_sched_init;
+ mach_sched_init = q40_sched_init;
- mach_init_IRQ = q40_init_IRQ;
- mach_gettimeoffset = q40_gettimeoffset;
- mach_hwclk = q40_hwclk;
- mach_get_ss = q40_get_ss;
- mach_get_rtc_pll = q40_get_rtc_pll;
- mach_set_rtc_pll = q40_set_rtc_pll;
- mach_set_clock_mmss = q40_set_clock_mmss;
+ mach_init_IRQ = q40_init_IRQ;
+ mach_gettimeoffset = q40_gettimeoffset;
+ mach_hwclk = q40_hwclk;
+ mach_get_ss = q40_get_ss;
+ mach_get_rtc_pll = q40_get_rtc_pll;
+ mach_set_rtc_pll = q40_set_rtc_pll;
+ mach_set_clock_mmss = q40_set_clock_mmss;
- mach_reset = q40_reset;
- mach_get_model = q40_get_model;
- mach_get_hardware_list = q40_get_hardware_list;
+ mach_reset = q40_reset;
+ mach_get_model = q40_get_model;
+ mach_get_hardware_list = q40_get_hardware_list;
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
- mach_beep = q40_mksound;
+ mach_beep = q40_mksound;
#endif
#ifdef CONFIG_HEARTBEAT
- mach_heartbeat = q40_heartbeat;
+ mach_heartbeat = q40_heartbeat;
#endif
- mach_halt = q40_halt;
-
- /* disable a few things that SMSQ might have left enabled */
- q40_disable_irqs();
-
- /* no DMA at all, but ide-scsi requires it.. make sure
- * all physical RAM fits into the boundary - otherwise
- * allocator may play costly and useless tricks */
- mach_max_dma_address = 1024*1024*1024;
-
- /* useful for early debugging stages - writes kernel messages into SRAM */
- if (!strncmp( m68k_debug_device,"mem",3 ))
- {
- /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/
- _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4;
- q40_console_driver.write = q40_mem_console_write;
- register_console(&q40_console_driver);
- }
+ mach_halt = q40_halt;
+
+ /* disable a few things that SMSQ might have left enabled */
+ q40_disable_irqs();
+
+ /* no DMA at all, but ide-scsi requires it.. make sure
+ * all physical RAM fits into the boundary - otherwise
+ * allocator may play costly and useless tricks */
+ mach_max_dma_address = 1024*1024*1024;
}
int q40_parse_bootinfo(const struct bi_record *rec)
{
- return 1;
+ return 1;
}
-static inline unsigned char bcd2bin (unsigned char b)
+static inline unsigned char bcd2bin(unsigned char b)
{
- return ((b>>4)*10 + (b&15));
+ return (b >> 4) * 10 + (b & 15);
}
-static inline unsigned char bin2bcd (unsigned char b)
+static inline unsigned char bin2bcd(unsigned char b)
{
- return (((b/10)*16) + (b%10));
+ return (b / 10) * 16 + (b % 10);
}
-unsigned long q40_gettimeoffset (void)
+unsigned long q40_gettimeoffset(void)
{
- return 5000*(ql_ticks!=0);
+ return 5000 * (ql_ticks != 0);
}
@@ -238,9 +250,9 @@ unsigned long q40_gettimeoffset (void)
int q40_hwclk(int op, struct rtc_time *t)
{
- if (op)
- { /* Write.... */
- Q40_RTC_CTRL |= Q40_RTC_WRITE;
+ if (op) {
+ /* Write.... */
+ Q40_RTC_CTRL |= Q40_RTC_WRITE;
Q40_RTC_SECS = bin2bcd(t->tm_sec);
Q40_RTC_MINS = bin2bcd(t->tm_min);
@@ -251,25 +263,23 @@ int q40_hwclk(int op, struct rtc_time *t)
if (t->tm_wday >= 0)
Q40_RTC_DOW = bin2bcd(t->tm_wday+1);
- Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
- }
- else
- { /* Read.... */
- Q40_RTC_CTRL |= Q40_RTC_READ;
-
- t->tm_year = bcd2bin (Q40_RTC_YEAR);
- t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1;
- t->tm_mday = bcd2bin (Q40_RTC_DATE);
- t->tm_hour = bcd2bin (Q40_RTC_HOUR);
- t->tm_min = bcd2bin (Q40_RTC_MINS);
- t->tm_sec = bcd2bin (Q40_RTC_SECS);
-
- Q40_RTC_CTRL &= ~(Q40_RTC_READ);
-
- if (t->tm_year < 70)
- t->tm_year += 100;
- t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
-
+ Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
+ } else {
+ /* Read.... */
+ Q40_RTC_CTRL |= Q40_RTC_READ;
+
+ t->tm_year = bcd2bin (Q40_RTC_YEAR);
+ t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1;
+ t->tm_mday = bcd2bin (Q40_RTC_DATE);
+ t->tm_hour = bcd2bin (Q40_RTC_HOUR);
+ t->tm_min = bcd2bin (Q40_RTC_MINS);
+ t->tm_sec = bcd2bin (Q40_RTC_SECS);
+
+ Q40_RTC_CTRL &= ~(Q40_RTC_READ);
+
+ if (t->tm_year < 70)
+ t->tm_year += 100;
+ t->tm_wday = bcd2bin(Q40_RTC_DOW)-1;
}
return 0;
@@ -285,29 +295,25 @@ unsigned int q40_get_ss(void)
* clock is out by > 30 minutes. Logic lifted from atari code.
*/
-int q40_set_clock_mmss (unsigned long nowtime)
+int q40_set_clock_mmss(unsigned long nowtime)
{
int retval = 0;
short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
int rtc_minutes;
+ rtc_minutes = bcd2bin(Q40_RTC_MINS);
- rtc_minutes = bcd2bin (Q40_RTC_MINS);
-
- if ((rtc_minutes < real_minutes
- ? real_minutes - rtc_minutes
- : rtc_minutes - real_minutes) < 30)
- {
- Q40_RTC_CTRL |= Q40_RTC_WRITE;
+ if ((rtc_minutes < real_minutes ?
+ real_minutes - rtc_minutes :
+ rtc_minutes - real_minutes) < 30) {
+ Q40_RTC_CTRL |= Q40_RTC_WRITE;
Q40_RTC_MINS = bin2bcd(real_minutes);
Q40_RTC_SECS = bin2bcd(real_seconds);
Q40_RTC_CTRL &= ~(Q40_RTC_WRITE);
- }
- else
+ } else
retval = -1;
-
return retval;
}
@@ -318,21 +324,23 @@ int q40_set_clock_mmss (unsigned long nowtime)
static int q40_get_rtc_pll(struct rtc_pll_info *pll)
{
- int tmp=Q40_RTC_CTRL;
+ int tmp = Q40_RTC_CTRL;
+
pll->pll_value = tmp & Q40_RTC_PLL_MASK;
if (tmp & Q40_RTC_PLL_SIGN)
pll->pll_value = -pll->pll_value;
- pll->pll_max=31;
- pll->pll_min=-31;
- pll->pll_posmult=512;
- pll->pll_negmult=256;
- pll->pll_clock=125829120;
+ pll->pll_max = 31;
+ pll->pll_min = -31;
+ pll->pll_posmult = 512;
+ pll->pll_negmult = 256;
+ pll->pll_clock = 125829120;
+
return 0;
}
static int q40_set_rtc_pll(struct rtc_pll_info *pll)
{
- if (!pll->pll_ctrl){
+ if (!pll->pll_ctrl) {
/* the docs are a bit unclear so I am doublesetting */
/* RTC_WRITE here ... */
int tmp = (pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) |
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 31cc07d8cec..2fb25ae46a8 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -59,7 +59,7 @@ static void q40_irq_shutdown(unsigned int irq)
static struct irq_controller q40_irq_controller = {
.name = "q40",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(q40_irq_controller.lock),
.startup = q40_irq_startup,
.shutdown = q40_irq_shutdown,
.enable = q40_enable_irq,
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index baf74e8de8b..50df34bf80e 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -90,7 +90,7 @@ static void sun3_inthandle(unsigned int irq, struct pt_regs *fp)
static struct irq_controller sun3_irq_controller = {
.name = "sun3",
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(sun3_irq_controller.lock),
.startup = m68k_irq_startup,
.shutdown = m68k_irq_shutdown,
.enable = sun3_enable_irq,
@@ -103,7 +103,7 @@ void sun3_init_IRQ(void)
m68k_setup_auto_interrupt(sun3_inthandle);
m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7);
- m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+ m68k_setup_user_interrupt(VEC_USER, 128, NULL);
request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL);
request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL);
diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c
index 574cf06df9e..48f8eb7b156 100644
--- a/arch/m68k/sun3x/prom.c
+++ b/arch/m68k/sun3x/prom.c
@@ -34,100 +34,101 @@ e_vector *sun3x_prom_vbr;
/* Handle returning to the prom */
void sun3x_halt(void)
{
- unsigned long flags;
+ unsigned long flags;
- /* Disable interrupts while we mess with things */
- local_irq_save(flags);
+ /* Disable interrupts while we mess with things */
+ local_irq_save(flags);
- /* Restore prom vbr */
- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+ /* Restore prom vbr */
+ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
- /* Restore prom NMI clock */
-// sun3x_disable_intreg(5);
- sun3_enable_irq(7);
+ /* Restore prom NMI clock */
+// sun3x_disable_intreg(5);
+ sun3_enable_irq(7);
- /* Let 'er rip */
- __asm__ volatile ("trap #14" : : );
+ /* Let 'er rip */
+ asm volatile ("trap #14");
- /* Restore everything */
- sun3_disable_irq(7);
- sun3_enable_irq(5);
+ /* Restore everything */
+ sun3_disable_irq(7);
+ sun3_enable_irq(5);
- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
- local_irq_restore(flags);
+ asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors));
+ local_irq_restore(flags);
}
void sun3x_reboot(void)
{
- /* This never returns, don't bother saving things */
- local_irq_disable();
+ /* This never returns, don't bother saving things */
+ local_irq_disable();
- /* Restore prom vbr */
- __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
+ /* Restore prom vbr */
+ asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr));
- /* Restore prom NMI clock */
- sun3_disable_irq(5);
- sun3_enable_irq(7);
+ /* Restore prom NMI clock */
+ sun3_disable_irq(5);
+ sun3_enable_irq(7);
- /* Let 'er rip */
- (*romvec->pv_reboot)("vmlinux");
+ /* Let 'er rip */
+ (*romvec->pv_reboot)("vmlinux");
}
-extern char m68k_debug_device[];
-
static void sun3x_prom_write(struct console *co, const char *s,
unsigned int count)
{
- while (count--) {
- if (*s == '\n')
- sun3x_putchar('\r');
- sun3x_putchar(*s++);
- }
+ while (count--) {
+ if (*s == '\n')
+ sun3x_putchar('\r');
+ sun3x_putchar(*s++);
+ }
}
/* debug console - write-only */
static struct console sun3x_debug = {
- .name = "debug",
- .write = sun3x_prom_write,
- .flags = CON_PRINTBUFFER,
- .index = -1,
+ .name = "debug",
+ .write = sun3x_prom_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
};
void sun3x_prom_init(void)
{
- /* Read the vector table */
-
- sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
- sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
- sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET);
- sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT);
- sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
- sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT);
- romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
-
- idprom_init();
-
- if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
- printk("Warning: machine reports strange type %02x\n",
- idprom->id_machtype);
- printk("Pretending it's a 3/80, but very afraid...\n");
- idprom->id_machtype = SM_SUN3X | SM_3_80;
- }
-
- /* point trap #14 at abort.
- * XXX this is futile since we restore the vbr first - oops
- */
- vectors[VEC_TRAP14] = sun3x_prom_abort;
-
- /* If debug=prom was specified, start the debug console */
-
- if (!strcmp(m68k_debug_device, "prom"))
- register_console(&sun3x_debug);
-
+ /* Read the vector table */
+
+ sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR);
+ sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR);
+ sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET);
+ sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT);
+ sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT);
+ sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT);
+ romvec = (struct linux_romvec *)SUN3X_PROM_BASE;
+
+ idprom_init();
+
+ if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) {
+ printk("Warning: machine reports strange type %02x\n",
+ idprom->id_machtype);
+ printk("Pretending it's a 3/80, but very afraid...\n");
+ idprom->id_machtype = SM_SUN3X | SM_3_80;
+ }
+
+ /* point trap #14 at abort.
+ * XXX this is futile since we restore the vbr first - oops
+ */
+ vectors[VEC_TRAP14] = sun3x_prom_abort;
+}
+static int __init sun3x_debug_setup(char *arg)
+{
+ /* If debug=prom was specified, start the debug console */
+ if (MACH_IS_SUN3X && !strcmp(arg, "prom"))
+ register_console(&sun3x_debug);
+ return 0;
}
+early_param("debug", sun3x_debug_setup);
+
/* some prom functions to export */
int prom_getintdefault(int node, char *property, int deflt)
{
@@ -141,7 +142,6 @@ int prom_getbool (int node, char *prop)
void prom_printf(char *fmt, ...)
{
-
}
void prom_halt (void)
@@ -159,7 +159,7 @@ prom_get_idprom(char *idbuf, int num_bytes)
int i;
/* make a copy of the idprom structure */
- for(i = 0; i < num_bytes; i++)
+ for (i = 0; i < num_bytes; i++)
idbuf[i] = ((char *)SUN3X_IDPROM)[i];
return idbuf[0];
diff --git a/arch/m68knommu/Kconfig.debug b/arch/m68knommu/Kconfig.debug
index 763c9aa0b4f..9ff47bd09ae 100644
--- a/arch/m68knommu/Kconfig.debug
+++ b/arch/m68knommu/Kconfig.debug
@@ -5,7 +5,7 @@ source "lib/Kconfig.debug"
config FULLDEBUG
bool "Full Symbolic/Source Debugging support"
help
- Enable debuging symbols on kernel build.
+ Enable debugging symbols on kernel build.
config HIGHPROFILE
bool "Use fast second timer for profiling"
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index b988c7bdc6e..7cd183d346e 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -31,7 +31,7 @@ int main(void)
DEFINE(TASK_PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
- DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+ DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(TASK_MM, offsetof(struct task_struct, mm));
DEFINE(TASK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
diff --git a/arch/m68knommu/kernel/dma.c b/arch/m68knommu/kernel/dma.c
index 14b19c4161f..0a25874a2aa 100644
--- a/arch/m68knommu/kernel/dma.c
+++ b/arch/m68knommu/kernel/dma.c
@@ -8,7 +8,6 @@
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/string.h>
-#include <linux/pci.h>
#include <asm/io.h>
void *dma_alloc_coherent(struct device *dev, size_t size,
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
index 72d34962357..f54b6a3dfec 100644
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c
index 3265b2d734d..48e6b33e8b4 100644
--- a/arch/m68knommu/kernel/sys_m68k.c
+++ b/arch/m68knommu/kernel/sys_m68k.c
@@ -10,7 +10,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 130d825e543..16ecea3c081 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -784,7 +784,6 @@ config TOSHIBA_RBTX4927
select HAS_TXX9_SERIAL
select HW_HAS_PCI
select I8259
- select ISA
select SWAP_IO_SPACE
select SYS_HAS_CPU_TX49XX
select SYS_SUPPORTS_32BIT_KERNEL
@@ -806,7 +805,6 @@ config TOSHIBA_RBTX4938
select HAS_TXX9_SERIAL
select HW_HAS_PCI
select I8259
- select ISA
select SWAP_IO_SPACE
select SYS_HAS_CPU_TX49XX
select SYS_SUPPORTS_32BIT_KERNEL
@@ -958,7 +956,7 @@ choice
byte order. These modes require different kernels and a different
Linux distribution. In general there is one preferred byteorder for a
particular system but some systems are just as commonly used in the
- one or the other endianess.
+ one or the other endianness.
config CPU_BIG_ENDIAN
bool "Big endian"
@@ -1042,6 +1040,9 @@ config SOC_AU1X00
select SYS_SUPPORTS_APM_EMULATION
select SYS_SUPPORTS_KGDB
+config SERIAL_RM9000
+ bool
+
config PNX8550
bool
select SOC_PNX8550
@@ -1749,7 +1750,7 @@ config ARCH_DISCONTIGMEM_ENABLE
bool
default y if SGI_IP27
help
- Say Y to upport efficient handling of discontiguous physical memory,
+ Say Y to support efficient handling of discontiguous physical memory,
for architectures which are either NUMA (Non-Uniform Memory Access)
or have huge holes in the physical address space for other reasons.
See <file:Documentation/vm/numa> for more.
@@ -1937,7 +1938,7 @@ config KEXEC
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
- but it is indepedent of the system firmware. And like a reboot
+ but it is independent of the system firmware. And like a reboot
you can start any kernel with it, not just Linux.
The name comes from the similiarity to the exec system call.
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index f2f742df32c..4892db88a86 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -92,7 +92,7 @@ cflags-y += -ffreestanding
# when fed the toolchain default!
#
# Certain gcc versions upto gcc 4.1.1 (probably 4.2-subversion as of
-# 2006-10-10 don't properly change the the predefined symbols if -EB / -EL
+# 2006-10-10 don't properly change the predefined symbols if -EB / -EL
# are used, so we kludge that here. A bug has been filed at
# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413.
#
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index de017c11f9b..9565b2104dc 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -2,7 +2,7 @@
# Makefile for the Cobalt micro systems family specific parts of the kernel
#
-obj-y := irq.o reset.o setup.o
+obj-y := irq.o reset.o setup.o buttons.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_EARLY_PRINTK) += console.o
diff --git a/arch/mips/cobalt/buttons.c b/arch/mips/cobalt/buttons.c
new file mode 100644
index 00000000000..9e143989c7b
--- /dev/null
+++ b/arch/mips/cobalt/buttons.c
@@ -0,0 +1,54 @@
+/*
+ * Cobalt buttons platform device.
+ *
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+static struct resource cobalt_buttons_resource __initdata = {
+ .start = 0x1d000000,
+ .end = 0x1d000003,
+ .flags = IORESOURCE_MEM,
+};
+
+static __init int cobalt_add_buttons(void)
+{
+ struct platform_device *pd;
+ int error;
+
+ pd = platform_device_alloc("Cobalt buttons", -1);
+ if (!pd)
+ return -ENOMEM;
+
+ error = platform_device_add_resources(pd, &cobalt_buttons_resource, 1);
+ if (error)
+ goto err_free_device;
+
+ error = platform_device_add(pd);
+ if (error)
+ goto err_free_device;
+
+ return 0;
+
+ err_free_device:
+ platform_device_put(pd);
+ return error;
+}
+device_initcall(cobalt_add_buttons);
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index 29e0df9f4be..7d0f2174614 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -245,7 +245,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
-CONFIG_ISA=y
CONFIG_MMU=y
#
@@ -573,7 +572,6 @@ CONFIG_MTD_CFI_UTIL=y
#
# Plug and Play support
#
-# CONFIG_PNP is not set
# CONFIG_PNPACPI is not set
#
@@ -658,7 +656,6 @@ CONFIG_BLK_DEV_IT8213=m
# CONFIG_BLK_DEV_VIA82CXXX is not set
CONFIG_BLK_DEV_TC86C001=m
# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
# CONFIG_IDEDMA_AUTO is not set
@@ -677,11 +674,6 @@ CONFIG_RAID_ATTRS=m
# CONFIG_ATA is not set
#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -742,37 +734,20 @@ CONFIG_NET_ETHERNET=y
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_DM9000 is not set
-# CONFIG_NET_VENDOR_RACAL is not set
#
# Tulip family network device support
#
# CONFIG_NET_TULIP is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
# CONFIG_HP100 is not set
-CONFIG_NET_ISA=y
-# CONFIG_E2100 is not set
-# CONFIG_EWRK3 is not set
-# CONFIG_EEXPRESS is not set
-# CONFIG_EEXPRESS_PRO is not set
-# CONFIG_HPLAN_PLUS is not set
-# CONFIG_HPLAN is not set
-# CONFIG_LP486E is not set
-# CONFIG_ETH16I is not set
CONFIG_NE2000=y
-# CONFIG_SEEQ8005 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_AC3200 is not set
-# CONFIG_APRICOT is not set
# CONFIG_B44 is not set
# CONFIG_FORCEDETH is not set
-# CONFIG_CS89x0 is not set
# CONFIG_DGRS is not set
# CONFIG_EEPRO100 is not set
# CONFIG_E100 is not set
@@ -833,8 +808,6 @@ CONFIG_NET_RADIO=y
# Obsolete Wireless cards support (pre-802.11)
#
# CONFIG_STRIP is not set
-# CONFIG_ARLAN is not set
-# CONFIG_WAVELAN is not set
#
# Wireless 802.11b ISA/PCI cards support
@@ -920,9 +893,6 @@ CONFIG_KEYBOARD_ATKBD=y
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
@@ -1072,7 +1042,6 @@ CONFIG_FB_ATY_CT=y
#
CONFIG_VGA_CONSOLE=y
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
-# CONFIG_MDA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 761a779d5c4..3b27309d54b 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -82,7 +82,7 @@ void output_task_defines(void)
{
text("/* MIPS task_struct offsets. */");
offset("#define TASK_STATE ", struct task_struct, state);
- offset("#define TASK_THREAD_INFO ", struct task_struct, thread_info);
+ offset("#define TASK_THREAD_INFO ", struct task_struct, stack);
offset("#define TASK_FLAGS ", struct task_struct, flags);
offset("#define TASK_MM ", struct task_struct, mm);
offset("#define TASK_PID ", struct task_struct, pid);
diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c
index 304efdc5682..4fa54b230c0 100644
--- a/arch/mips/kernel/early_printk.c
+++ b/arch/mips/kernel/early_printk.c
@@ -33,8 +33,3 @@ void __init setup_early_printk(void)
{
register_console(&early_console);
}
-
-void __init disable_early_printk(void)
-{
- unregister_console(&early_console);
-}
diff --git a/arch/mips/kernel/irixelf.c b/arch/mips/kernel/irixelf.c
index 3cc25c05d36..403d96f99e7 100644
--- a/arch/mips/kernel/irixelf.c
+++ b/arch/mips/kernel/irixelf.c
@@ -31,7 +31,6 @@
#include <linux/shm.h>
#include <linux/personality.h>
#include <linux/elfcore.h>
-#include <linux/smp_lock.h>
#include <asm/mipsregs.h>
#include <asm/namei.h>
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
index e2863821a3d..30f9eb09db3 100644
--- a/arch/mips/kernel/irixioctl.c
+++ b/arch/mips/kernel/irixioctl.c
@@ -9,7 +9,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sockios.h>
#include <linux/syscalls.h>
#include <linux/tty.h>
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 2132485caa7..6980deb6dce 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -10,7 +10,6 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/ptrace.h>
#include <linux/resource.h>
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 201ae194d1b..b5a7b46bbc4 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -22,7 +22,6 @@
#include <linux/ptrace.h>
#include <linux/audit.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/user.h>
#include <linux/security.h>
#include <linux/signal.h>
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 07d67309451..2a08ce41bf2 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -12,7 +12,6 @@
#include <linux/mm.h>
#include <linux/personality.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index b9a014411f8..003f8152b9e 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -12,7 +12,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/syscalls.h>
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index a9202fa9598..4cf9ff24d1f 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 5dcfab6b288..b361edb83dc 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -560,7 +560,7 @@ void smtc_boot_secondary(int cpu, struct task_struct *idle)
write_tc_gpr_sp(__KSTK_TOS(idle));
/* global pointer */
- write_tc_gpr_gp((unsigned long)idle->thread_info);
+ write_tc_gpr_gp((unsigned long)task_thread_info(idle));
smtc_status |= SMTC_MTC_ACTIVE;
write_tc_c0_tchalt(0);
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
index a586aba337a..ebd9db8d1ec 100644
--- a/arch/mips/kernel/stacktrace.c
+++ b/arch/mips/kernel/stacktrace.c
@@ -31,8 +31,7 @@ static void save_raw_context_stack(struct stack_trace *trace,
}
}
-static void save_context_stack(struct stack_trace *trace,
- struct task_struct *task, struct pt_regs *regs)
+static void save_context_stack(struct stack_trace *trace, struct pt_regs *regs)
{
unsigned long sp = regs->regs[29];
#ifdef CONFIG_KALLSYMS
@@ -41,7 +40,7 @@ static void save_context_stack(struct stack_trace *trace,
if (raw_show_trace || !__kernel_text_address(pc)) {
unsigned long stack_page =
- (unsigned long)task_stack_page(task);
+ (unsigned long)task_stack_page(current);
if (stack_page && sp >= stack_page &&
sp <= stack_page + THREAD_SIZE - 32)
save_raw_context_stack(trace, sp);
@@ -54,7 +53,7 @@ static void save_context_stack(struct stack_trace *trace,
trace->entries[trace->nr_entries++] = pc;
if (trace->nr_entries >= trace->max_entries)
break;
- pc = unwind_stack(task, &sp, pc, &ra);
+ pc = unwind_stack(current, &sp, pc, &ra);
} while (pc);
#else
save_raw_context_stack(trace, sp);
@@ -64,22 +63,13 @@ static void save_context_stack(struct stack_trace *trace,
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
{
struct pt_regs dummyregs;
struct pt_regs *regs = &dummyregs;
WARN_ON(trace->nr_entries || !trace->max_entries);
- if (task && task != current) {
- regs->regs[29] = task->thread.reg29;
- regs->regs[31] = 0;
- regs->cp0_epc = task->thread.reg31;
- } else {
- if (!task)
- task = current;
- prepare_frametrace(regs);
- }
-
- save_context_stack(trace, task, regs);
+ prepare_frametrace(regs);
+ save_context_stack(trace, regs);
}
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 26e1a7e78d1..9dd5a2df8ea 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -13,7 +13,6 @@
#include <linux/linkage.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/mman.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 493cb29b8a4..ff45a4b8fba 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -16,7 +16,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/bootmem.h>
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 24b7b053cfe..a7d49ae805b 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -76,7 +76,6 @@
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <asm/asm.h>
#include <asm/branch.h>
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index c76b793310c..043f637e3d1 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -119,7 +119,7 @@ SECTIONS
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
#endif
- . = ALIGN(32);
+ . = ALIGN(_PAGE_SIZE);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/mips/lib/iomap.c b/arch/mips/lib/iomap.c
index d51d5cb0a4a..e3acb2dad33 100644
--- a/arch/mips/lib/iomap.c
+++ b/arch/mips/lib/iomap.c
@@ -6,7 +6,6 @@
* (C) Copyright 2007 MIPS Technologies, Inc.
* written by Ralf Baechle <ralf@linux-mips.org>
*/
-#include <linux/pci.h>
#include <linux/module.h>
#include <asm/io.h>
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
index 8079f3d1eca..ea6ba724848 100644
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -2,7 +2,6 @@
#include <linux/mm.h>
#include <linux/signal.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <asm/asm.h>
#include <asm/bootinfo.h>
diff --git a/arch/mips/mips-boards/sim/Makefile b/arch/mips/mips-boards/sim/Makefile
index 6aeebc9122f..dc0bfda1142 100644
--- a/arch/mips/mips-boards/sim/Makefile
+++ b/arch/mips/mips-boards/sim/Makefile
@@ -17,7 +17,8 @@
# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#
-obj-y := sim_setup.o sim_mem.o sim_time.o sim_int.o sim_cmdline.o
+obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o \
+ sim_cmdline.o
obj-$(CONFIG_EARLY_PRINTK) += sim_console.o
obj-$(CONFIG_SMP) += sim_smp.o
diff --git a/arch/mips/mips-boards/sim/sim_platform.c b/arch/mips/mips-boards/sim/sim_platform.c
new file mode 100644
index 00000000000..53210a8c5de
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_platform.c
@@ -0,0 +1,35 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 by Ralf Baechle (ralf@linux-mips.org)
+ */
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+static char mipsnet_string[] = "mipsnet";
+
+static struct platform_device eth1_device = {
+ .name = mipsnet_string,
+ .id = 0,
+};
+
+/*
+ * Create a platform device for the GPI port that receives the
+ * image data from the embedded camera.
+ */
+static int __init mipsnet_devinit(void)
+{
+ int err;
+
+ err = platform_device_register(&eth1_device);
+ if (err)
+ printk(KERN_ERR "%s: registration failed\n", mipsnet_string);
+
+ return err;
+}
+
+device_initcall(mipsnet_devinit);
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index f9c595dceba..7ebea331edb 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -16,7 +16,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/module.h>
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
index 7a7444874e8..0ad39e53f7b 100644
--- a/arch/mips/pci/fixup-sb1250.c
+++ b/arch/mips/pci/fixup-sb1250.c
@@ -14,7 +14,7 @@
#include <linux/pci.h>
/*
- * Set the the BCM1250, etc. PCI host bridge's TRDY timeout
+ * Set the BCM1250, etc. PCI host bridge's TRDY timeout
* to the finite max.
*/
static void __init quirk_sb1250_pci(struct pci_dev *dev)
@@ -35,7 +35,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_HT,
quirk_sb1250_ht);
/*
- * Set the the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
+ * Set the SP1011 HT/PCI bridge's TRDY timeout to the finite max.
*/
static void __init quirk_sp1011(struct pci_dev *dev)
{
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
new file mode 100644
index 00000000000..c41b53faa8f
--- /dev/null
+++ b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
@@ -0,0 +1,165 @@
+/*
+ * The setup file for serial related hardware on PMC-Sierra MSP processors.
+ *
+ * Copyright 2005 PMC-Sierra, Inc.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include <asm/bootinfo.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/serial.h>
+
+#include <msp_prom.h>
+#include <msp_int.h>
+#include <msp_regs.h>
+
+#ifdef CONFIG_KGDB
+/*
+ * kgdb uses serial port 1 so the console can remain on port 0.
+ * To use port 0 change the definition to read as follows:
+ * #define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART0_BASE)
+ */
+#define DEBUG_PORT_BASE KSEG1ADDR(MSP_UART1_BASE)
+
+int putDebugChar(char c)
+{
+ volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE;
+ uint32_t val = (uint32_t)c;
+
+ local_irq_disable();
+ while( !(uart[5] & 0x20) ); /* Wait for TXRDY */
+ uart[0] = val;
+ while( !(uart[5] & 0x20) ); /* Wait for TXRDY */
+ local_irq_enable();
+
+ return 1;
+}
+
+char getDebugChar(void)
+{
+ volatile uint32_t *uart = (volatile uint32_t *)DEBUG_PORT_BASE;
+ uint32_t val;
+
+ while( !(uart[5] & 0x01) ); /* Wait for RXRDY */
+ val = uart[0];
+
+ return (char)val;
+}
+
+void initDebugPort(unsigned int uartclk, unsigned int baudrate)
+{
+ unsigned int baud_divisor = (uartclk + 8 * baudrate)/(16 * baudrate);
+
+ /* Enable FIFOs */
+ writeb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_4,
+ (char *)DEBUG_PORT_BASE + (UART_FCR * 4));
+
+ /* Select brtc divisor */
+ writeb(UART_LCR_DLAB, (char *)DEBUG_PORT_BASE + (UART_LCR * 4));
+
+ /* Store divisor lsb */
+ writeb(baud_divisor, (char *)DEBUG_PORT_BASE + (UART_TX * 4));
+
+ /* Store divisor msb */
+ writeb(baud_divisor >> 8, (char *)DEBUG_PORT_BASE + (UART_IER * 4));
+
+ /* Set 8N1 mode */
+ writeb(UART_LCR_WLEN8, (char *)DEBUG_PORT_BASE + (UART_LCR * 4));
+
+ /* Disable flow control */
+ writeb(0, (char *)DEBUG_PORT_BASE + (UART_MCR * 4));
+
+ /* Disable receive interrupt(!) */
+ writeb(0, (char *)DEBUG_PORT_BASE + (UART_IER * 4));
+}
+#endif
+
+void __init msp_serial_setup(void)
+{
+ char *s;
+ char *endp;
+ struct uart_port up;
+ unsigned int uartclk;
+
+ memset(&up, 0, sizeof(up));
+
+ /* Check if clock was specified in environment */
+ s = prom_getenv("uartfreqhz");
+ if(!(s && *s && (uartclk = simple_strtoul(s, &endp, 10)) && *endp == 0))
+ uartclk = MSP_BASE_BAUD;
+ ppfinit("UART clock set to %d\n", uartclk);
+
+ /* Initialize first serial port */
+ up.mapbase = MSP_UART0_BASE;
+ up.membase = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN);
+ up.irq = MSP_INT_UART0;
+ up.uartclk = uartclk;
+ up.regshift = 2;
+ up.iotype = UPIO_DWAPB; /* UPIO_MEM like */
+ up.flags = STD_COM_FLAGS;
+ up.type = PORT_16550A;
+ up.line = 0;
+ up.private_data = (void*)UART0_STATUS_REG;
+ if (early_serial_setup(&up))
+ printk(KERN_ERR "Early serial init of port 0 failed\n");
+
+ /* Initialize the second serial port, if one exists */
+ switch (mips_machtype) {
+ case MACH_MSP4200_EVAL:
+ case MACH_MSP4200_GW:
+ case MACH_MSP4200_FPGA:
+ case MACH_MSP7120_EVAL:
+ case MACH_MSP7120_GW:
+ case MACH_MSP7120_FPGA:
+ /* Enable UART1 on MSP4200 and MSP7120 */
+ *GPIO_CFG2_REG = 0x00002299;
+
+#ifdef CONFIG_KGDB
+ /* Initialize UART1 for kgdb since PMON doesn't */
+ if( DEBUG_PORT_BASE == KSEG1ADDR(MSP_UART1_BASE) ) {
+ if( mips_machtype == MACH_MSP4200_FPGA
+ || mips_machtype == MACH_MSP7120_FPGA )
+ initDebugPort(uartclk,19200);
+ else
+ initDebugPort(uartclk,57600);
+ }
+#endif
+ break;
+
+ default:
+ return; /* No second serial port, good-bye. */
+ }
+
+ up.mapbase = MSP_UART1_BASE;
+ up.membase = ioremap_nocache(up.mapbase,MSP_UART_REG_LEN);
+ up.irq = MSP_INT_UART1;
+ up.line = 1;
+ up.private_data = (void*)UART1_STATUS_REG;
+ if (early_serial_setup(&up))
+ printk(KERN_ERR "Early serial init of port 1 failed\n");
+}
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 60ade7690e0..ba8e0794630 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -19,7 +19,6 @@
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index ad5fc471a00..9ccffdfb828 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -42,7 +42,7 @@ static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
struct irqaction sni_isa_irq = {
.handler = sni_isa_irq_handler,
.name = "ISA",
- .flags = SA_SHIRQ
+ .flags = IRQF_SHARED
};
/*
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index 0f7576dfd14..a0c11efeaee 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -1049,3 +1049,22 @@ static int __init toshiba_rbtx4927_rtc_init(void)
return IS_ERR(dev) ? PTR_ERR(dev) : 0;
}
device_initcall(toshiba_rbtx4927_rtc_init);
+
+static int __init rbtx4927_ne_init(void)
+{
+ static struct resource __initdata res[] = {
+ {
+ .start = RBTX4927_RTL_8019_BASE,
+ .end = RBTX4927_RTL_8019_BASE + 0x20 - 1,
+ .flags = IORESOURCE_IO,
+ }, {
+ .start = RBTX4927_RTL_8019_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+ struct platform_device *dev =
+ platform_device_register_simple("ne", -1,
+ res, ARRAY_SIZE(res));
+ return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+device_initcall(rbtx4927_ne_init);
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/setup.c b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
index 66163ba452c..f5d1ce739fc 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/setup.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/setup.c
@@ -20,6 +20,7 @@
#include <linux/console.h>
#include <linux/pci.h>
#include <linux/pm.h>
+#include <linux/platform_device.h>
#include <asm/wbflush.h>
#include <asm/reboot.h>
@@ -1037,3 +1038,22 @@ static int __init tx4938_spi_proc_setup(void)
__initcall(tx4938_spi_proc_setup);
#endif
+
+static int __init rbtx4938_ne_init(void)
+{
+ struct resource res[] = {
+ {
+ .start = RBTX4938_RTL_8019_BASE,
+ .end = RBTX4938_RTL_8019_BASE + 0x20 - 1,
+ .flags = IORESOURCE_IO,
+ }, {
+ .start = RBTX4938_RTL_8019_IRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+ };
+ struct platform_device *dev =
+ platform_device_register_simple("ne", -1,
+ res, ARRAY_SIZE(res));
+ return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+device_initcall(rbtx4938_ne_init);
diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
index 782906b644d..eb2f9a3d515 100644
--- a/arch/parisc/configs/c3000_defconfig
+++ b/arch/parisc/configs/c3000_defconfig
@@ -435,7 +435,6 @@ CONFIG_SCSI_SATA_SIL=m
# CONFIG_SCSI_SATA_ULI is not set
CONFIG_SCSI_SATA_VIA=m
# CONFIG_SCSI_SATA_VITESSE is not set
-CONFIG_SCSI_SATA_INTEL_COMBINED=y
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index c7a81a2c014..d86e1577677 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -24,7 +24,6 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/file.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/ptrace.h>
#include <asm/errno.h>
diff --git a/arch/parisc/hpux/ioctl.c b/arch/parisc/hpux/ioctl.c
index b34b4f3c60e..dede4765852 100644
--- a/arch/parisc/hpux/ioctl.c
+++ b/arch/parisc/hpux/ioctl.c
@@ -34,7 +34,6 @@
*/
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <asm/errno.h>
#include <asm/ioctl.h>
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index 54fdb959149..d3b7917a87c 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -54,7 +54,7 @@
int main(void)
{
- DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, thread_info));
+ DEFINE(TASK_THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(TASK_STATE, offsetof(struct task_struct, state));
DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
DEFINE(TASK_SIGPENDING, offsetof(struct task_struct, pending));
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index e9d09b020e8..c5c9125dace 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -388,7 +388,7 @@ void do_cpu_irq_mask(struct pt_regs *regs)
static struct irqaction timer_action = {
.handler = timer_interrupt,
.name = "timer",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL,
};
#ifdef CONFIG_SMP
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 0d0d617b6f2..8a0db376e91 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -10,7 +10,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 9784e405f84..fb35ebc0c4d 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -16,7 +16,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 1c1a37f7305..db94affe5c7 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/unistd.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 512642d8f70..4f589216b39 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -29,7 +29,6 @@
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/shm.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/utsname.h>
#include <linux/personality.h>
@@ -106,6 +105,11 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
{
if (len > TASK_SIZE)
return -ENOMEM;
+ /* Might want to check for cache aliasing issues for MAP_FIXED case
+ * like ARM or MIPS ??? --BenH.
+ */
+ if (flags & MAP_FIXED)
+ return addr;
if (!addr)
addr = TASK_UNMAPPED_BASE;
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 55bc1471967..745ff741490 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -20,7 +20,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index 5f75b3e6598..89c03707ecc 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -216,11 +216,8 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
/* Handle some frequent special cases.... */
{
char symname[KSYM_NAME_LEN+1];
- char *modname;
- unsigned long symsize, offset;
- kallsyms_lookup(info->ip, &symsize, &offset,
- &modname, symname);
+ kallsyms_lookup(info->ip, NULL, NULL, NULL, symname);
dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 2a8253358c6..c7458599059 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -181,7 +181,7 @@ SECTIONS
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
#endif
- . = ALIGN(32);
+ . = ALIGN(ASM_PAGE_SIZE);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6dfbd52694a..ccc5410af99 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -11,6 +11,11 @@ config PPC64
This option selects whether a 32-bit or a 64-bit kernel
will be built.
+config PPC_PM_NEEDS_RTC_LIB
+ bool
+ select RTC_LIB
+ default y if PM
+
config PPC32
bool
default y if !PPC64
@@ -89,7 +94,7 @@ config SCHED_NO_NO_OMIT_FRAME_POINTER
config ARCH_MAY_HAVE_PC_FDC
bool
- default y
+ default !PPC_PSERIES || PCI
config PPC_OF
def_bool y
@@ -112,12 +117,20 @@ config GENERIC_BUG
default y
depends on BUG
+config SYS_SUPPORTS_APM_EMULATION
+ bool
+
config DEFAULT_UIMAGE
bool
help
Used to allow a board to specify it wants a uImage built by default
default n
+config PPC64_SWSUSP
+ bool
+ depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
+ default y
+
menu "Processor support"
choice
prompt "Processor Type"
@@ -157,17 +170,20 @@ config PPC_83xx
select FSL_SOC
select 83xx
select PPC_FPU
+ select WANT_DEVICE_TREE
config PPC_85xx
bool "Freescale 85xx"
select E500
select FSL_SOC
select 85xx
+ select WANT_DEVICE_TREE
config PPC_86xx
bool "Freescale 86xx"
select 6xx
select FSL_SOC
+ select FSL_PCIE
select PPC_FPU
select ALTIVEC
help
@@ -185,7 +201,7 @@ config 40x
config 44x
bool "AMCC 44x"
select PPC_DCR_NATIVE
-
+ select WANT_DEVICE_TREE
config E200
bool "Freescale e200"
@@ -250,9 +266,14 @@ config PPC_OF_PLATFORM_PCI
depends on PPC64 # not supported on 32 bits yet
default n
+config 4xx
+ bool
+ depends on 40x || 44x
+ default y
+
config BOOKE
bool
- depends on E200 || E500
+ depends on E200 || E500 || 44x
default y
config FSL_BOOKE
@@ -318,6 +339,11 @@ config PPC_STD_MMU_32
def_bool y
depends on PPC_STD_MMU && PPC32
+config PPC_MM_SLICES
+ bool
+ default y if HUGETLB_PAGE
+ default n
+
config VIRT_CPU_ACCOUNTING
bool "Deterministic task and CPU time accounting"
depends on PPC64
@@ -367,394 +393,7 @@ endmenu
source "init/Kconfig"
-menu "Platform support"
- depends on PPC64 || CLASSIC32
-
-choice
- prompt "Machine type"
- default PPC_MULTIPLATFORM
-
-config PPC_MULTIPLATFORM
- bool "Generic desktop/server/laptop"
- help
- Select this option if configuring for an IBM pSeries or
- RS/6000 machine, an Apple machine, or a PReP, CHRP,
- Maple or Cell-based machine.
-
-config EMBEDDED6xx
- bool "Embedded 6xx/7xx/7xxx-based board"
- depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
-
-config APUS
- bool "Amiga-APUS"
- depends on PPC32 && BROKEN
- help
- Select APUS if configuring for a PowerUP Amiga.
- More information is available at:
- <http://linux-apus.sourceforge.net/>.
-endchoice
-
-config QUICC_ENGINE
- bool
- depends on PPC_MPC836x || PPC_MPC832x
- default y
- help
- The QUICC Engine (QE) is a new generation of communications
- coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
- Selecting this option means that you wish to build a kernel
- for a machine with a QE coprocessor.
-
-config PPC_PSERIES
- depends on PPC_MULTIPLATFORM && PPC64
- bool "IBM pSeries & new (POWER5-based) iSeries"
- select MPIC
- select PPC_I8259
- select PPC_RTAS
- select RTAS_ERROR_LOGGING
- select PPC_UDBG_16550
- select PPC_NATIVE
- default y
-
-config PPC_ISERIES
- bool "IBM Legacy iSeries"
- depends on PPC_MULTIPLATFORM && PPC64
- select PPC_INDIRECT_IO
-
-config PPC_CHRP
- bool "Common Hardware Reference Platform (CHRP) based machines"
- depends on PPC_MULTIPLATFORM && PPC32
- select MPIC
- select PPC_I8259
- select PPC_INDIRECT_PCI
- select PPC_RTAS
- select PPC_MPC106
- select PPC_UDBG_16550
- select PPC_NATIVE
- default y
-
-config PPC_MPC52xx
- bool
- default n
-
-config PPC_MPC5200
- bool
- select PPC_MPC52xx
- default n
-
-config PPC_MPC5200_BUGFIX
- bool "MPC5200 (L25R) bugfix support"
- depends on PPC_MPC5200
- default n
- help
- Enable workarounds for original MPC5200 errata. This is not required
- for MPC5200B based boards.
-
- It is safe to say 'Y' here
-
-config PPC_EFIKA
- bool "bPlan Efika 5k2. MPC5200B based computer"
- depends on PPC_MULTIPLATFORM && PPC32
- select PPC_RTAS
- select RTAS_PROC
- select PPC_MPC52xx
- select PPC_NATIVE
- default n
-
-config PPC_LITE5200
- bool "Freescale Lite5200 Eval Board"
- depends on PPC_MULTIPLATFORM && PPC32
- select PPC_MPC5200
- default n
-
-config PPC_PMAC
- bool "Apple PowerMac based machines"
- depends on PPC_MULTIPLATFORM
- select MPIC
- select PPC_INDIRECT_PCI if PPC32
- select PPC_MPC106 if PPC32
- select PPC_NATIVE
- default y
-
-config PPC_PMAC64
- bool
- depends on PPC_PMAC && POWER4
- select MPIC
- select U3_DART
- select MPIC_BROKEN_U3
- select GENERIC_TBSYNC
- select PPC_970_NAP
- default y
-
-config PPC_PREP
- bool "PowerPC Reference Platform (PReP) based machines"
- depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
- select MPIC
- select PPC_I8259
- select PPC_INDIRECT_PCI
- select PPC_UDBG_16550
- select PPC_NATIVE
- default n
-
-config PPC_MAPLE
- depends on PPC_MULTIPLATFORM && PPC64
- bool "Maple 970FX Evaluation Board"
- select MPIC
- select U3_DART
- select MPIC_BROKEN_U3
- select GENERIC_TBSYNC
- select PPC_UDBG_16550
- select PPC_970_NAP
- select PPC_NATIVE
- select PPC_RTAS
- select MMIO_NVRAM
- select ATA_NONSTANDARD if ATA
- default n
- help
- This option enables support for the Maple 970FX Evaluation Board.
- For more information, refer to <http://www.970eval.com>
-
-config PPC_PASEMI
- depends on PPC_MULTIPLATFORM && PPC64
- bool "PA Semi SoC-based platforms"
- default n
- select MPIC
- select PPC_UDBG_16550
- select GENERIC_TBSYNC
- select PPC_NATIVE
- help
- This option enables support for PA Semi's PWRficient line
- of SoC processors, including PA6T-1682M
-
-config PPC_CELL
- bool
- default n
-
-config PPC_CELL_NATIVE
- bool
- select PPC_CELL
- select PPC_DCR_MMIO
- select PPC_OF_PLATFORM_PCI
- select PPC_INDIRECT_IO
- select PPC_NATIVE
- select MPIC
- default n
-
-config PPC_IBM_CELL_BLADE
- bool "IBM Cell Blade"
- depends on PPC_MULTIPLATFORM && PPC64
- select PPC_CELL_NATIVE
- select PPC_RTAS
- select MMIO_NVRAM
- select PPC_UDBG_16550
- select UDBG_RTAS_CONSOLE
-
-config PPC_PS3
- bool "Sony PS3 (incomplete)"
- depends on PPC_MULTIPLATFORM && PPC64
- select PPC_CELL
- select USB_ARCH_HAS_OHCI
- select USB_OHCI_LITTLE_ENDIAN
- select USB_OHCI_BIG_ENDIAN_MMIO
- select USB_ARCH_HAS_EHCI
- select USB_EHCI_BIG_ENDIAN_MMIO
- help
- This option enables support for the Sony PS3 game console
- and other platforms using the PS3 hypervisor.
- Support for this platform is not yet complete, so
- enabling this will not result in a bootable kernel on a
- PS3 system.
-
-config PPC_CELLEB
- bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
- depends on PPC_MULTIPLATFORM && PPC64
- select PPC_CELL
- select PPC_OF_PLATFORM_PCI
- select HAS_TXX9_SERIAL
- select PPC_UDBG_BEAT
- select USB_OHCI_BIG_ENDIAN_MMIO
- select USB_EHCI_BIG_ENDIAN_MMIO
-
-config PPC_NATIVE
- bool
- depends on PPC_MULTIPLATFORM
- help
- Support for running natively on the hardware, i.e. without
- a hypervisor. This option is not user-selectable but should
- be selected by all platforms that need it.
-
-config UDBG_RTAS_CONSOLE
- bool "RTAS based debug console"
- depends on PPC_RTAS
- default n
-
-config PPC_UDBG_BEAT
- bool "BEAT based debug console"
- depends on PPC_CELLEB
- default n
-
-config XICS
- depends on PPC_PSERIES
- bool
- default y
-
-config U3_DART
- bool
- depends on PPC_MULTIPLATFORM && PPC64
- default n
-
-config PPC_RTAS
- bool
- default n
-
-config RTAS_ERROR_LOGGING
- bool
- depends on PPC_RTAS
- default n
-
-config RTAS_PROC
- bool "Proc interface to RTAS"
- depends on PPC_RTAS
- default y
-
-config RTAS_FLASH
- tristate "Firmware flash interface"
- depends on PPC64 && RTAS_PROC
-
-config PPC_PMI
- tristate "Support for PMI"
- depends PPC_IBM_CELL_BLADE
- help
- PMI (Platform Management Interrupt) is a way to
- communicate with the BMC (Baseboard Mangement Controller).
- It is used in some IBM Cell blades.
- default m
-
-config MMIO_NVRAM
- bool
- default n
-
-config MPIC_BROKEN_U3
- bool
- depends on PPC_MAPLE
- default y
-
-config IBMVIO
- depends on PPC_PSERIES || PPC_ISERIES
- bool
- default y
-
-config IBMEBUS
- depends on PPC_PSERIES
- bool "Support for GX bus based adapters"
- help
- Bus device driver for GX bus based adapters.
-
-config PPC_MPC106
- bool
- default n
-
-config PPC_970_NAP
- bool
- default n
-
-config PPC_INDIRECT_IO
- bool
- select GENERIC_IOMAP
- default n
-
-config GENERIC_IOMAP
- bool
- default n
-
-source "drivers/cpufreq/Kconfig"
-
-config CPU_FREQ_PMAC
- bool "Support for Apple PowerBooks"
- depends on CPU_FREQ && ADB_PMU && PPC32
- select CPU_FREQ_TABLE
- help
- This adds support for frequency switching on Apple PowerBooks,
- this currently includes some models of iBook & Titanium
- PowerBook.
-
-config CPU_FREQ_PMAC64
- bool "Support for some Apple G5s"
- depends on CPU_FREQ && PPC64
- select CPU_FREQ_TABLE
- help
- This adds support for frequency switching on Apple iMac G5,
- and some of the more recent desktop G5 machines as well.
-
-config PPC601_SYNC_FIX
- bool "Workarounds for PPC601 bugs"
- depends on 6xx && (PPC_PREP || PPC_PMAC)
- help
- Some versions of the PPC601 (the first PowerPC chip) have bugs which
- mean that extra synchronization instructions are required near
- certain instructions, typically those that make major changes to the
- CPU state. These extra instructions reduce performance slightly.
- If you say N here, these extra instructions will not be included,
- resulting in a kernel which will run faster but may not run at all
- on some systems with the PPC601 chip.
-
- If in doubt, say Y here.
-
-config TAU
- bool "On-chip CPU temperature sensor support"
- depends on 6xx
- help
- G3 and G4 processors have an on-chip temperature sensor called the
- 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
- temperature within 2-4 degrees Celsius. This option shows the current
- on-die temperature in /proc/cpuinfo if the cpu supports it.
-
- Unfortunately, on some chip revisions, this sensor is very inaccurate
- and in many cases, does not work at all, so don't assume the cpu
- temp is actually what /proc/cpuinfo says it is.
-
-config TAU_INT
- bool "Interrupt driven TAU driver (DANGEROUS)"
- depends on TAU
- ---help---
- The TAU supports an interrupt driven mode which causes an interrupt
- whenever the temperature goes out of range. This is the fastest way
- to get notified the temp has exceeded a range. With this option off,
- a timer is used to re-check the temperature periodically.
-
- However, on some cpus it appears that the TAU interrupt hardware
- is buggy and can cause a situation which would lead unexplained hard
- lockups.
-
- Unless you are extending the TAU driver, or enjoy kernel/hardware
- debugging, leave this option off.
-
-config TAU_AVERAGE
- bool "Average high and low temp"
- depends on TAU
- ---help---
- The TAU hardware can compare the temperature to an upper and lower
- bound. The default behavior is to show both the upper and lower
- bound in /proc/cpuinfo. If the range is large, the temperature is
- either changing a lot, or the TAU hardware is broken (likely on some
- G4's). If the range is small (around 4 degrees), the temperature is
- relatively stable. If you say Y here, a single temperature value,
- halfway between the upper and lower bounds, will be reported in
- /proc/cpuinfo.
-
- If in doubt, say N here.
-
-endmenu
-
-source arch/powerpc/platforms/embedded6xx/Kconfig
-source arch/powerpc/platforms/4xx/Kconfig
-source arch/powerpc/platforms/82xx/Kconfig
-source arch/powerpc/platforms/83xx/Kconfig
-source arch/powerpc/platforms/85xx/Kconfig
-source arch/powerpc/platforms/86xx/Kconfig
-source arch/powerpc/platforms/8xx/Kconfig
-source arch/powerpc/platforms/cell/Kconfig
-source arch/powerpc/platforms/ps3/Kconfig
-source arch/powerpc/platforms/pasemi/Kconfig
+source "arch/powerpc/platforms/Kconfig"
menu "Kernel options"
@@ -837,15 +476,6 @@ config CRASH_DUMP
Don't change this unless you know what you are doing.
-config EMBEDDEDBOOT
- bool
- depends on 8xx || 8260
- default y
-
-config PC_KEYBOARD
- bool "PC PS/2 style Keyboard"
- depends on 4xx || CPM2
-
config PPCBUG_NVRAM
bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC
default y if PPC_PREP
@@ -859,8 +489,6 @@ config IRQ_ALL_CPUS
CPU. Generally saying Y is safe, although some problems have been
reported with SMP Power Macintoshes with this option enabled.
-source "arch/powerpc/platforms/pseries/Kconfig"
-
config NUMA
bool "NUMA support"
depends on PPC64
@@ -905,15 +533,21 @@ config NODES_SPAN_OTHER_NODES
def_bool y
depends on NEED_MULTIPLE_NODES
+config PPC_HAS_HASH_64K
+ bool
+ depends on PPC64
+ default n
+
config PPC_64K_PAGES
bool "64k page size"
depends on PPC64
+ select PPC_HAS_HASH_64K
help
This option changes the kernel logical page size to 64k. On machines
- without processor support for 64k pages, the kernel will simulate
- them by loading each individual 4k page on demand transparently,
- while on hardware with such support, it will be used to map
- normal application pages.
+ without processor support for 64k pages, the kernel will simulate
+ them by loading each individual 4k page on demand transparently,
+ while on hardware with such support, it will be used to map
+ normal application pages.
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
@@ -931,8 +565,6 @@ config PROC_DEVICETREE
an image of the device tree that the kernel copies from Open
Firmware or other boot firmware. If unsure, say Y here.
-source "arch/powerpc/platforms/prep/Kconfig"
-
config CMDLINE_BOOL
bool "Default bootloader kernel arguments"
@@ -967,6 +599,29 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here.
+config WANT_DEVICE_TREE
+ bool
+ default n
+
+config DEVICE_TREE
+ string "Static device tree source file"
+ depends on WANT_DEVICE_TREE
+ help
+ This specifies the device tree source (.dts) file to be
+ compiled and included when building the bootwrapper. If a
+ relative filename is given, then it will be relative to
+ arch/powerpc/boot/dts. If you are not using the bootwrapper,
+ or do not need to build a dts into the bootwrapper, this
+ field is ignored.
+
+ For example, this is required when building a cuImage target
+ for an older U-Boot, which cannot pass a device tree itself.
+ Such a kernel will not work with a newer U-Boot that tries to
+ pass a device tree (unless you tell it not to). If your U-Boot
+ does not mention a device tree in "help bootm", then use the
+ cuImage target and specify a device tree here. Otherwise, use
+ the uImage target and leave this field blank.
+
endmenu
config ISA_DMA_API
@@ -995,24 +650,17 @@ config GENERIC_ISA_DMA
depends on PPC64 || POWER4 || 6xx && !CPM2
default y
-config MPIC
- bool
- default n
-
-config MPIC_WEIRD
- bool
- default n
-
-config PPC_I8259
- bool
- default n
-
config PPC_INDIRECT_PCI
bool
depends on PCI
default y if 40x || 44x
default n
+config PPC_INDIRECT_PCI_BE
+ bool
+ depends PPC_INDIRECT_PCI
+ default n
+
config EISA
bool
@@ -1022,17 +670,23 @@ config SBUS
config FSL_SOC
bool
+config FSL_PCIE
+ bool
+ depends on PPC_86xx
+
# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
config MCA
bool
config PCI
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
- || PPC_MPC52xx || (EMBEDDED && PPC_ISERIES) || MPC7448HPC2 || PPC_PS3
+ || PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
+ || MPC7448HPC2 || PPC_PS3 || PPC_HOLLY
default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \
&& !PPC_85xx && !PPC_86xx
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
default PCI_QSPAN if !4xx && !CPM2 && 8xx
+ select ARCH_SUPPORTS_MSI
help
Find out whether your system includes a PCI bus. PCI is the name of
a bus system, i.e. the way the CPU talks to the other stuff inside
@@ -1228,12 +882,10 @@ source "fs/Kconfig"
source "arch/powerpc/sysdev/qe_lib/Kconfig"
-source "arch/powerpc/platforms/iseries/Kconfig"
-
source "lib/Kconfig"
menu "Instrumentation Support"
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL
source "arch/powerpc/oprofile/Kconfig"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index d39d13327e6..346cd3befe1 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -18,12 +18,21 @@ config DEBUG_STACK_USAGE
This option will slow down process creation somewhat.
+config DEBUG_PAGEALLOC
+ bool "Debug page memory allocations"
+ depends on DEBUG_KERNEL && !SOFTWARE_SUSPEND
+ help
+ Unmap pages from the kernel linear mapping after free_pages().
+ This results in a large slowdown, but helps to find certain types
+ of memory corruptions.
+
+
config HCALL_STATS
bool "Hypervisor call instrumentation"
depends on PPC_PSERIES && DEBUG_FS
help
Adds code to keep track of the number of hypervisor calls made and
- the amount of time spent in hypervisor callsr. Wall time spent in
+ the amount of time spent in hypervisor calls. Wall time spent in
each call is always calculated, and if available CPU cycles spent
are also calculated. A directory named hcall_inst is added at the
root of the debugfs filesystem. Within the hcall_inst directory
@@ -130,11 +139,6 @@ config BOOTX_TEXT
Say Y here to see progress messages from the boot firmware in text
mode. Requires either BootX or Open Firmware.
-config SERIAL_TEXT_DEBUG
- bool "Support for early boot texts over serial port"
- depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
- PPC_GEN550 || PPC_MPC52xx
-
config PPC_EARLY_DEBUG
bool "Early debugging (dangerous)"
@@ -199,6 +203,24 @@ config PPC_EARLY_DEBUG_BEAT
help
Select this to enable early debugging for Celleb with Beat.
+config PPC_EARLY_DEBUG_44x
+ bool "Early serial debugging for IBM/AMCC 44x CPUs"
+ depends on 44x
+ select PPC_UDBG_16550
+ help
+ Select this to enable early debugging for IBM 44x chips via the
+ inbuilt serial port.
+
endchoice
+config PPC_EARLY_DEBUG_44x_PHYSLOW
+ hex "Low 32 bits of early debug UART physical address"
+ depends PPC_EARLY_DEBUG_44x
+ default "0x40000200"
+
+config PPC_EARLY_DEBUG_44x_PHYSHIGH
+ hex "EPRN of early debug UART physical address"
+ depends PPC_EARLY_DEBUG_44x
+ default "0x1"
+
endmenu
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index a00fe723655..81a531d84ff 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -102,9 +102,9 @@ CFLAGS += $(call cc-option,-mno-altivec)
# kernel considerably.
CFLAGS += $(call cc-option,-funit-at-a-time)
-ifndef CONFIG_FSL_BOOKE
-CFLAGS += -mstring
-endif
+# Never use string load/store instructions as they are
+# often slow when they are implemented at all
+CFLAGS += -mno-string
ifeq ($(CONFIG_6xx),y)
CFLAGS += -mcpu=powerpc
@@ -166,6 +166,9 @@ define archhelp
@echo ' *_defconfig - Select default config from arch/$(ARCH)/configs'
endef
+install:
+ $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
diff --git a/arch/powerpc/boot/.gitignore b/arch/powerpc/boot/.gitignore
index 0734b2fc1d9..eec7af7e599 100644
--- a/arch/powerpc/boot/.gitignore
+++ b/arch/powerpc/boot/.gitignore
@@ -18,6 +18,9 @@ kernel-vmlinux.strip.c
kernel-vmlinux.strip.gz
mktree
uImage
+cuImage
+cuImage.bin.gz
+cuImage.elf
zImage
zImage.chrp
zImage.coff
diff --git a/arch/powerpc/boot/44x.c b/arch/powerpc/boot/44x.c
new file mode 100644
index 00000000000..d51377d9024
--- /dev/null
+++ b/arch/powerpc/boot/44x.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * Based on earlier code:
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "reg.h"
+#include "dcr.h"
+
+/* Read the 44x memory controller to get size of system memory. */
+void ibm44x_fixup_memsize(void)
+{
+ int i;
+ unsigned long memsize, bank_config;
+
+ memsize = 0;
+ for (i = 0; i < ARRAY_SIZE(sdram_bxcr); i++) {
+ mtdcr(DCRN_SDRAM0_CFGADDR, sdram_bxcr[i]);
+ bank_config = mfdcr(DCRN_SDRAM0_CFGDATA);
+
+ if (bank_config & SDRAM_CONFIG_BANK_ENABLE)
+ memsize += SDRAM_CONFIG_BANK_SIZE(bank_config);
+ }
+
+ dt_fixup_memory(0, memsize);
+}
diff --git a/arch/powerpc/boot/44x.h b/arch/powerpc/boot/44x.h
new file mode 100644
index 00000000000..7b129ad043e
--- /dev/null
+++ b/arch/powerpc/boot/44x.h
@@ -0,0 +1,16 @@
+/*
+ * PowerPC 44x related functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * 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.
+ */
+#ifndef _PPC_BOOT_44X_H_
+#define _PPC_BOOT_44X_H_
+
+void ibm44x_fixup_memsize(void);
+void ebony_init(void *mac0, void *mac1);
+
+#endif /* _PPC_BOOT_44X_H_ */
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index dc779407de1..5c384aad118 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -37,13 +37,16 @@ zlib := inffast.c inflate.c inftrees.c
zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
zliblinuxheader := zlib.h zconf.h zutil.h
-$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
- $(addprefix $(obj)/,$(zlibheader))
+$(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
+ $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
-src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
- ns16550.c serial.c simple_alloc.c div64.S util.S $(zlib)
-src-plat := of.c
-src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
+src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
+ ns16550.c serial.c simple_alloc.c div64.S util.S \
+ gunzip_util.c elf_util.c $(zlib) devtree.c \
+ 44x.c ebony.c
+src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
+ cuboot-ebony.c treeboot-ebony.c
+src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot))
obj-boot := $(addsuffix .o, $(basename $(src-boot)))
@@ -75,7 +78,7 @@ $(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S
@cp $< $@
clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
- empty.c zImage zImage.coff.lds zImage.lds zImage.sandpoint
+ empty.c zImage.coff.lds zImage.lds
quiet_cmd_bootcc = BOOTCC $@
cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
@@ -84,23 +87,25 @@ quiet_cmd_bootas = BOOTAS $@
cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
quiet_cmd_bootar = BOOTAR $@
- cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $^; mv $@.$$$$ $@
+ cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
-$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
+$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c FORCE
$(call if_changed_dep,bootcc)
-$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
+$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S FORCE
$(call if_changed_dep,bootas)
-$(obj)/wrapper.a: $(obj-wlib)
- $(call cmd,bootar)
+$(obj)/wrapper.a: $(obj-wlib) FORCE
+ $(call if_changed,bootar)
hostprogs-y := addnote addRamDisk hack-coff mktree
-extra-y := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
+targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
+extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
$(obj)/zImage.lds $(obj)/zImage.coff.lds
wrapper :=$(srctree)/$(src)/wrapper
-wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree)
+wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) \
+ $(wrapper) FORCE
#############
# Bits for building various flavours of zImage
@@ -113,41 +118,50 @@ CROSSWRAP := -C "$(CROSS_COMPILE)"
endif
endif
+# args (to if_changed): 1 = (this rule), 2 = platform, 3 = dts 4=dtb 5=initrd
quiet_cmd_wrap = WRAP $@
- cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
-quiet_cmd_wrap_initrd = WRAP $@
- cmd_wrap_initrd =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
- -i $(obj)/ramdisk.image.gz vmlinux
+ cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
+ $(if $3, -s $3)$(if $4, -d $4)$(if $5, -i $5) vmlinux
-$(obj)/zImage.chrp: vmlinux $(wrapperbits)
- $(call cmd,wrap,chrp)
-
-$(obj)/zImage.initrd.chrp: vmlinux $(wrapperbits)
- $(call cmd,wrap_initrd,chrp)
-
-$(obj)/zImage.pseries: vmlinux $(wrapperbits)
- $(call cmd,wrap,pseries)
-
-$(obj)/zImage.initrd.pseries: vmlinux $(wrapperbits)
- $(call cmd,wrap_initrd,pseries)
+image-$(CONFIG_PPC_PSERIES) += zImage.pseries
+image-$(CONFIG_PPC_MAPLE) += zImage.pseries
+image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
+image-$(CONFIG_PPC_PS3) += zImage.ps3
+image-$(CONFIG_PPC_CELLEB) += zImage.pseries
+image-$(CONFIG_PPC_CHRP) += zImage.chrp
+image-$(CONFIG_PPC_EFIKA) += zImage.chrp
+image-$(CONFIG_PPC_PMAC) += zImage.pmac
+image-$(CONFIG_PPC_HOLLY) += zImage.holly-elf
+image-$(CONFIG_DEFAULT_UIMAGE) += uImage
-$(obj)/zImage.pmac: vmlinux $(wrapperbits)
- $(call cmd,wrap,pmac)
+ifneq ($(CONFIG_DEVICE_TREE),"")
+image-$(CONFIG_PPC_83xx) += cuImage.83xx
+image-$(CONFIG_PPC_85xx) += cuImage.85xx
+image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
+endif
-$(obj)/zImage.initrd.pmac: vmlinux $(wrapperbits)
- $(call cmd,wrap_initrd,pmac)
+# For 32-bit powermacs, build the COFF and miboot images
+# as well as the ELF images.
+ifeq ($(CONFIG_PPC32),y)
+image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
+endif
-$(obj)/zImage.coff: vmlinux $(wrapperbits)
- $(call cmd,wrap,pmaccoff)
+initrd- := $(patsubst zImage%, zImage.initrd%, $(image-n) $(image-))
+initrd-y := $(patsubst zImage%, zImage.initrd%, \
+ $(patsubst treeImage%, treeImage.initrd%, $(image-y)))
+initrd-y := $(filter-out $(image-y), $(initrd-y))
+targets += $(image-y) $(initrd-y)
-$(obj)/zImage.initrd.coff: vmlinux $(wrapperbits)
- $(call cmd,wrap_initrd,pmaccoff)
+$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
-$(obj)/zImage.miboot: vmlinux $(wrapperbits)
- $(call cmd,wrap,miboot)
+# Don't put the ramdisk on the pattern rule; when its missing make will try
+# the pattern rule with less dependencies that also matches (even with the
+# hard dependency listed).
+$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
+ $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
-$(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
- $(call cmd,wrap_initrd,miboot)
+$(obj)/zImage.%: vmlinux $(wrapperbits)
+ $(call if_changed,wrap,$*)
$(obj)/zImage.ps3: vmlinux
$(STRIP) -s -R .comment $< -o $@
@@ -155,35 +169,42 @@ $(obj)/zImage.ps3: vmlinux
$(obj)/zImage.initrd.ps3: vmlinux
@echo " WARNING zImage.initrd.ps3 not supported (yet)"
+$(obj)/zImage.holly-elf: vmlinux $(wrapperbits)
+ $(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,)
+
+$(obj)/zImage.initrd.holly-elf: vmlinux $(wrapperbits) $(obj)/ramdisk.image.gz
+ $(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,$(obj)/ramdisk.image.gz)
+
$(obj)/uImage: vmlinux $(wrapperbits)
- $(call cmd,wrap,uboot)
+ $(call if_changed,wrap,uboot)
-image-$(CONFIG_PPC_PSERIES) += zImage.pseries
-image-$(CONFIG_PPC_MAPLE) += zImage.pseries
-image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
-image-$(CONFIG_PPC_PS3) += zImage.ps3
-image-$(CONFIG_PPC_CELLEB) += zImage.pseries
-image-$(CONFIG_PPC_CHRP) += zImage.chrp
-image-$(CONFIG_PPC_EFIKA) += zImage.chrp
-image-$(CONFIG_PPC_PMAC) += zImage.pmac
-image-$(CONFIG_DEFAULT_UIMAGE) += uImage
+# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
+dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
+ ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
-# For 32-bit powermacs, build the COFF and miboot images
-# as well as the ELF images.
-ifeq ($(CONFIG_PPC32),y)
-image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
-endif
+$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
+ $(call if_changed,wrap,cuboot-$*,$(dts))
-initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y))
+$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
+ $(call if_changed,wrap,treeboot-$*,$(dts))
+
+$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
+ $(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz)
$(obj)/zImage: $(addprefix $(obj)/, $(image-y))
@rm -f $@; ln $< $@
$(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y))
@rm -f $@; ln $< $@
-install: $(CONFIGURE) $(image-y)
+install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $<
-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz)
-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz)
-clean-files += $(image-)
+# anything not in $(targets)
+clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* \
+ treeImage.*
+
+# clean up files cached by wrapper
+clean-kernel := vmlinux.strip vmlinux.bin
+clean-kernel += $(addsuffix .gz,$(clean-kernel))
+# If not absolute clean-files are relative to $(obj).
+clean-files += $(addprefix $(objtree)/, $(clean-kernel))
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index 70e65b13e03..5a4215c4b01 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -16,8 +16,11 @@
_zimage_start_opd:
.long _zimage_start, 0, 0, 0
+ .weak _zimage_start
.globl _zimage_start
_zimage_start:
+ .globl _zimage_start_lib
+_zimage_start_lib:
/* Work out the offset between the address we were linked at
and the address where we're running. */
bl 1f
@@ -44,7 +47,7 @@ _zimage_start:
addi r9,r9,4
bdnz 2b
- /* Do a cache flush for our text, in case OF didn't */
+ /* Do a cache flush for our text, in case the loader didn't */
3: lis r9,_start@ha
addi r9,r9,_start@l
add r9,r0,r9
@@ -59,6 +62,34 @@ _zimage_start:
sync
isync
- mr r6,r1
- b start
+ /* Clear the BSS */
+ lis r9,__bss_start@ha
+ addi r9,r9,__bss_start@l
+ add r9,r0,r9
+ lis r8,_end@ha
+ addi r8,r8,_end@l
+ add r8,r0,r8
+ li r10,0
+5: stw r10,0(r9)
+ addi r9,r9,4
+ cmplw cr0,r9,r8
+ blt 5b
+ /* Possibly set up a custom stack */
+.weak _platform_stack_top
+ lis r8,_platform_stack_top@ha
+ addi r8,r8,_platform_stack_top@l
+ cmpwi r8,0
+ beq 6f
+ add r8,r0,r8
+ lwz r1,0(r8)
+ add r1,r0,r1
+ li r0,0
+ stwu r0,-16(r1) /* establish a stack frame */
+6:
+
+ /* Call platform_init() */
+ bl platform_init
+
+ /* Call start */
+ b start
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
new file mode 100644
index 00000000000..6cbc20afb4d
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-83xx.c
@@ -0,0 +1,68 @@
+/*
+ * Old U-boot compatibility for 83xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * 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 "ops.h"
+#include "stdio.h"
+
+#define TARGET_83xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+ void *soc;
+
+ dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+ dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr);
+ dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 4, bd.bi_busfreq);
+
+ /* Unfortunately, the specific model number is encoded in the
+ * soc node name in existing dts files -- once that is fixed,
+ * this can do a simple path lookup.
+ */
+ soc = find_node_by_devtype(NULL, "soc");
+ if (soc) {
+ void *serial = NULL;
+
+ setprop(soc, "bus-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+
+ while ((serial = find_node_by_devtype(serial, "serial"))) {
+ if (get_parent(serial) != soc)
+ continue;
+
+ setprop(serial, "clock-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+ }
+ }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ memcpy(&bd, (bd_t *)r3, sizeof(bd));
+ loader_info.initrd_addr = r4;
+ loader_info.initrd_size = r4 ? r5 : 0;
+ loader_info.cmdline = (char *)r6;
+ loader_info.cmdline_len = r7 - r6;
+
+ simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ serial_console_init();
+ platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c
new file mode 100644
index 00000000000..f88ba00ac12
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-85xx.c
@@ -0,0 +1,69 @@
+/*
+ * Old U-boot compatibility for 85xx
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * 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 "ops.h"
+#include "stdio.h"
+
+#define TARGET_85xx
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+static void platform_fixups(void)
+{
+ void *soc;
+
+ dt_fixup_memory(bd.bi_memstart, bd.bi_memsize);
+ dt_fixup_mac_addresses(bd.bi_enetaddr, bd.bi_enet1addr,
+ bd.bi_enet2addr);
+ dt_fixup_cpu_clocks(bd.bi_intfreq, bd.bi_busfreq / 8, bd.bi_busfreq);
+
+ /* Unfortunately, the specific model number is encoded in the
+ * soc node name in existing dts files -- once that is fixed,
+ * this can do a simple path lookup.
+ */
+ soc = find_node_by_devtype(NULL, "soc");
+ if (soc) {
+ void *serial = NULL;
+
+ setprop(soc, "bus-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+
+ while ((serial = find_node_by_devtype(serial, "serial"))) {
+ if (get_parent(serial) != soc)
+ continue;
+
+ setprop(serial, "clock-frequency", &bd.bi_busfreq,
+ sizeof(bd.bi_busfreq));
+ }
+ }
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ memcpy(&bd, (bd_t *)r3, sizeof(bd));
+ loader_info.initrd_addr = r4;
+ loader_info.initrd_size = r4 ? r5 : 0;
+ loader_info.cmdline = (char *)r6;
+ loader_info.cmdline_len = r7 - r6;
+
+ simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ serial_console_init();
+ platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/cuboot-ebony.c b/arch/powerpc/boot/cuboot-ebony.c
new file mode 100644
index 00000000000..4464c5f67ac
--- /dev/null
+++ b/arch/powerpc/boot/cuboot-ebony.c
@@ -0,0 +1,42 @@
+/*
+ * Old U-boot compatibility for Ebony
+ *
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ *
+ * Copyright 2007 David Gibson, IBM Corporatio.
+ * Based on cuboot-83xx.c, which is:
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * 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 "ops.h"
+#include "stdio.h"
+#include "44x.h"
+
+#define TARGET_44x
+#include "ppcboot.h"
+
+static bd_t bd;
+extern char _end[];
+
+BSS_STACK(4096);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ memcpy(&bd, (bd_t *)r3, sizeof(bd));
+ loader_info.initrd_addr = r4;
+ loader_info.initrd_size = r4 ? r5 : 0;
+ loader_info.cmdline = (char *)r6;
+ loader_info.cmdline_len = r7 - r6;
+
+ simple_alloc_init(_end, avail_ram, 32, 64);
+
+ ebony_init(&bd.bi_enetaddr, &bd.bi_enet1addr);
+}
diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h
new file mode 100644
index 00000000000..877bc97b1e9
--- /dev/null
+++ b/arch/powerpc/boot/dcr.h
@@ -0,0 +1,87 @@
+#ifndef _PPC_BOOT_DCR_H_
+#define _PPC_BOOT_DCR_H_
+
+#define mfdcr(rn) \
+ ({ \
+ unsigned long rval; \
+ asm volatile("mfdcr %0,%1" : "=r"(rval) : "i"(rn)); \
+ rval; \
+ })
+#define mtdcr(rn, val) \
+ asm volatile("mtdcr %0,%1" : : "i"(rn), "r"(val))
+
+/* 440GP/440GX SDRAM controller DCRs */
+#define DCRN_SDRAM0_CFGADDR 0x010
+#define DCRN_SDRAM0_CFGDATA 0x011
+
+#define SDRAM0_B0CR 0x40
+#define SDRAM0_B1CR 0x44
+#define SDRAM0_B2CR 0x48
+#define SDRAM0_B3CR 0x4c
+
+static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2CR, SDRAM0_B3CR };
+
+#define SDRAM_CONFIG_BANK_ENABLE 0x00000001
+#define SDRAM_CONFIG_SIZE_MASK 0x000e0000
+#define SDRAM_CONFIG_BANK_SIZE(reg) \
+ (0x00400000 << ((reg & SDRAM_CONFIG_SIZE_MASK) >> 17))
+
+/* 440GP Clock, PM, chip control */
+#define DCRN_CPC0_SR 0x0b0
+#define DCRN_CPC0_ER 0x0b1
+#define DCRN_CPC0_FR 0x0b2
+#define DCRN_CPC0_SYS0 0x0e0
+#define CPC0_SYS0_TUNE 0xffc00000
+#define CPC0_SYS0_FBDV_MASK 0x003c0000
+#define CPC0_SYS0_FWDVA_MASK 0x00038000
+#define CPC0_SYS0_FWDVB_MASK 0x00007000
+#define CPC0_SYS0_OPDV_MASK 0x00000c00
+#define CPC0_SYS0_EPDV_MASK 0x00000300
+/* Helper macros to compute the actual clock divider values from the
+ * encodings in the CPC0 register */
+#define CPC0_SYS0_FBDV(reg) \
+ ((((((reg) & CPC0_SYS0_FBDV_MASK) >> 18) - 1) & 0xf) + 1)
+#define CPC0_SYS0_FWDVA(reg) \
+ (8 - (((reg) & CPC0_SYS0_FWDVA_MASK) >> 15))
+#define CPC0_SYS0_FWDVB(reg) \
+ (8 - (((reg) & CPC0_SYS0_FWDVB_MASK) >> 12))
+#define CPC0_SYS0_OPDV(reg) \
+ ((((reg) & CPC0_SYS0_OPDV_MASK) >> 10) + 1)
+#define CPC0_SYS0_EPDV(reg) \
+ ((((reg) & CPC0_SYS0_EPDV_MASK) >> 8) + 1)
+#define CPC0_SYS0_EXTSL 0x00000080
+#define CPC0_SYS0_RW_MASK 0x00000060
+#define CPC0_SYS0_RL 0x00000010
+#define CPC0_SYS0_ZMIISL_MASK 0x0000000c
+#define CPC0_SYS0_BYPASS 0x00000002
+#define CPC0_SYS0_NTO1 0x00000001
+#define DCRN_CPC0_SYS1 0x0e1
+#define DCRN_CPC0_CUST0 0x0e2
+#define DCRN_CPC0_CUST1 0x0e3
+#define DCRN_CPC0_STRP0 0x0e4
+#define DCRN_CPC0_STRP1 0x0e5
+#define DCRN_CPC0_STRP2 0x0e6
+#define DCRN_CPC0_STRP3 0x0e7
+#define DCRN_CPC0_GPIO 0x0e8
+#define DCRN_CPC0_PLB 0x0e9
+#define DCRN_CPC0_CR1 0x0ea
+#define DCRN_CPC0_CR0 0x0eb
+#define CPC0_CR0_SWE 0x80000000
+#define CPC0_CR0_CETE 0x40000000
+#define CPC0_CR0_U1FCS 0x20000000
+#define CPC0_CR0_U0DTE 0x10000000
+#define CPC0_CR0_U0DRE 0x08000000
+#define CPC0_CR0_U0DC 0x04000000
+#define CPC0_CR0_U1DTE 0x02000000
+#define CPC0_CR0_U1DRE 0x01000000
+#define CPC0_CR0_U1DC 0x00800000
+#define CPC0_CR0_U0EC 0x00400000
+#define CPC0_CR0_U1EC 0x00200000
+#define CPC0_CR0_UDIV_MASK 0x001f0000
+#define CPC0_CR0_UDIV(reg) \
+ ((((reg) & CPC0_CR0_UDIV_MASK) >> 16) + 1)
+#define DCRN_CPC0_MIRQ0 0x0ec
+#define DCRN_CPC0_MIRQ1 0x0ed
+#define DCRN_CPC0_JTAGID 0x0ef
+
+#endif /* _PPC_BOOT_DCR_H_ */
diff --git a/arch/powerpc/boot/devtree.c b/arch/powerpc/boot/devtree.c
new file mode 100644
index 00000000000..c9951550ed2
--- /dev/null
+++ b/arch/powerpc/boot/devtree.c
@@ -0,0 +1,307 @@
+/*
+ * devtree.c - convenience functions for device tree manipulation
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * Authors: David Gibson <david@gibson.dropbear.id.au>
+ * Scott Wood <scottwood@freescale.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.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+
+void dt_fixup_memory(u64 start, u64 size)
+{
+ void *root, *memory;
+ int naddr, nsize, i;
+ u32 memreg[4];
+
+ root = finddevice("/");
+ if (getprop(root, "#address-cells", &naddr, sizeof(naddr)) < 0)
+ naddr = 2;
+ if (naddr < 1 || naddr > 2)
+ fatal("Can't cope with #address-cells == %d in /\n\r", naddr);
+
+ if (getprop(root, "#size-cells", &nsize, sizeof(nsize)) < 0)
+ nsize = 1;
+ if (nsize < 1 || nsize > 2)
+ fatal("Can't cope with #size-cells == %d in /\n\r", nsize);
+
+ i = 0;
+ if (naddr == 2)
+ memreg[i++] = start >> 32;
+ memreg[i++] = start & 0xffffffff;
+ if (nsize == 2)
+ memreg[i++] = size >> 32;
+ memreg[i++] = size & 0xffffffff;
+
+ memory = finddevice("/memory");
+ if (! memory) {
+ memory = create_node(NULL, "memory");
+ setprop_str(memory, "device_type", "memory");
+ }
+
+ printf("Memory <- <0x%x", memreg[0]);
+ for (i = 1; i < (naddr + nsize); i++)
+ printf(" 0x%x", memreg[i]);
+ printf("> (%ldMB)\n\r", (unsigned long)(size >> 20));
+
+ setprop(memory, "reg", memreg, (naddr + nsize)*sizeof(u32));
+}
+
+#define MHZ(x) ((x + 500000) / 1000000)
+
+void dt_fixup_cpu_clocks(u32 cpu, u32 tb, u32 bus)
+{
+ void *devp = NULL;
+
+ printf("CPU clock-frequency <- 0x%x (%dMHz)\n\r", cpu, MHZ(cpu));
+ printf("CPU timebase-frequency <- 0x%x (%dMHz)\n\r", tb, MHZ(tb));
+ if (bus > 0)
+ printf("CPU bus-frequency <- 0x%x (%dMHz)\n\r", bus, MHZ(bus));
+
+ while ((devp = find_node_by_devtype(devp, "cpu"))) {
+ setprop_val(devp, "clock-frequency", cpu);
+ setprop_val(devp, "timebase-frequency", tb);
+ if (bus > 0)
+ setprop_val(devp, "bus-frequency", bus);
+ }
+}
+
+void dt_fixup_clock(const char *path, u32 freq)
+{
+ void *devp = finddevice(path);
+
+ if (devp) {
+ printf("%s: clock-frequency <- %x (%dMHz)\n\r", path, freq, MHZ(freq));
+ setprop_val(devp, "clock-frequency", freq);
+ }
+}
+
+void __dt_fixup_mac_addresses(u32 startindex, ...)
+{
+ va_list ap;
+ u32 index = startindex;
+ void *devp;
+ const u8 *addr;
+
+ va_start(ap, startindex);
+ while ((addr = va_arg(ap, const u8 *))) {
+ devp = find_node_by_prop_value(NULL, "linux,network-index",
+ (void*)&index, sizeof(index));
+
+ printf("ENET%d: local-mac-address <-"
+ " %02x:%02x:%02x:%02x:%02x:%02x\n\r", index,
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+ if (devp)
+ setprop(devp, "local-mac-address", addr, 6);
+
+ index++;
+ }
+ va_end(ap);
+}
+
+#define MAX_ADDR_CELLS 4
+#define MAX_RANGES 8
+
+static void get_reg_format(void *node, u32 *naddr, u32 *nsize)
+{
+ if (getprop(node, "#address-cells", naddr, 4) != 4)
+ *naddr = 2;
+ if (getprop(node, "#size-cells", nsize, 4) != 4)
+ *nsize = 1;
+}
+
+static void copy_val(u32 *dest, u32 *src, int naddr)
+{
+ int pad = MAX_ADDR_CELLS - naddr;
+
+ memset(dest, 0, pad * 4);
+ memcpy(dest + pad, src, naddr * 4);
+}
+
+static int sub_reg(u32 *reg, u32 *sub)
+{
+ int i, borrow = 0;
+
+ for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
+ int prev_borrow = borrow;
+ borrow = reg[i] < sub[i] + prev_borrow;
+ reg[i] -= sub[i] + prev_borrow;
+ }
+
+ return !borrow;
+}
+
+static int add_reg(u32 *reg, u32 *add, int naddr)
+{
+ int i, carry = 0;
+
+ for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
+ u64 tmp = (u64)reg[i] + add[i] + carry;
+ carry = tmp >> 32;
+ reg[i] = (u32)tmp;
+ }
+
+ return !carry;
+}
+
+/* It is assumed that if the first byte of reg fits in a
+ * range, then the whole reg block fits.
+ */
+static int compare_reg(u32 *reg, u32 *range, u32 *rangesize)
+{
+ int i;
+ u32 end;
+
+ for (i = 0; i < MAX_ADDR_CELLS; i++) {
+ if (reg[i] < range[i])
+ return 0;
+ if (reg[i] > range[i])
+ break;
+ }
+
+ for (i = 0; i < MAX_ADDR_CELLS; i++) {
+ end = range[i] + rangesize[i];
+
+ if (reg[i] < end)
+ break;
+ if (reg[i] > end)
+ return 0;
+ }
+
+ return reg[i] != end;
+}
+
+/* reg must be MAX_ADDR_CELLS */
+static int find_range(u32 *reg, u32 *ranges, int nregaddr,
+ int naddr, int nsize, int buflen)
+{
+ int nrange = nregaddr + naddr + nsize;
+ int i;
+
+ for (i = 0; i + nrange <= buflen; i += nrange) {
+ u32 range_addr[MAX_ADDR_CELLS];
+ u32 range_size[MAX_ADDR_CELLS];
+
+ copy_val(range_addr, ranges + i, naddr);
+ copy_val(range_size, ranges + i + nregaddr + naddr, nsize);
+
+ if (compare_reg(reg, range_addr, range_size))
+ return i;
+ }
+
+ return -1;
+}
+
+/* Currently only generic buses without special encodings are supported.
+ * In particular, PCI is not supported. Also, only the beginning of the
+ * reg block is tracked; size is ignored except in ranges.
+ */
+static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3];
+
+static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
+ unsigned long *size)
+{
+ u32 last_addr[MAX_ADDR_CELLS];
+ u32 this_addr[MAX_ADDR_CELLS];
+ void *parent;
+ u64 ret_addr, ret_size;
+ u32 naddr, nsize, prev_naddr;
+ int buflen, offset;
+
+ parent = get_parent(node);
+ if (!parent)
+ return 0;
+
+ get_reg_format(parent, &naddr, &nsize);
+
+ if (nsize > 2)
+ return 0;
+
+ offset = (naddr + nsize) * res;
+
+ if (reglen < offset + naddr + nsize ||
+ sizeof(dt_xlate_buf) < offset + naddr + nsize)
+ return 0;
+
+ copy_val(last_addr, dt_xlate_buf + offset, naddr);
+
+ ret_size = dt_xlate_buf[offset + naddr];
+ if (nsize == 2) {
+ ret_size <<= 32;
+ ret_size |= dt_xlate_buf[offset + naddr + 1];
+ }
+
+ while ((node = get_parent(node))) {
+ prev_naddr = naddr;
+
+ get_reg_format(node, &naddr, &nsize);
+
+ buflen = getprop(node, "ranges", dt_xlate_buf,
+ sizeof(dt_xlate_buf));
+ if (buflen < 0)
+ continue;
+ if (buflen > sizeof(dt_xlate_buf))
+ return 0;
+
+ offset = find_range(last_addr, dt_xlate_buf, prev_naddr,
+ naddr, nsize, buflen / 4);
+
+ if (offset < 0)
+ return 0;
+
+ copy_val(this_addr, dt_xlate_buf + offset, prev_naddr);
+
+ if (!sub_reg(last_addr, this_addr))
+ return 0;
+
+ copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr);
+
+ if (!add_reg(last_addr, this_addr, naddr))
+ return 0;
+ }
+
+ if (naddr > 2)
+ return 0;
+
+ ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
+
+ if (sizeof(void *) == 4 &&
+ (ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
+ ret_addr + ret_size > 0x100000000ULL))
+ return 0;
+
+ *addr = ret_addr;
+ if (size)
+ *size = ret_size;
+
+ return 1;
+}
+
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size)
+{
+ int reglen;
+
+ reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4;
+ return dt_xlate(node, res, reglen, addr, size);
+}
+
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr)
+{
+
+ if (buflen > sizeof(dt_xlate_buf))
+ return 0;
+
+ memcpy(dt_xlate_buf, buf, buflen);
+ return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
+}
diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts
new file mode 100644
index 00000000000..b67918651c4
--- /dev/null
+++ b/arch/powerpc/boot/dts/ebony.dts
@@ -0,0 +1,307 @@
+/*
+ * Device Tree Source for IBM Ebony
+ *
+ * Copyright (c) 2006, 2007 IBM Corp.
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>, David Gibson <dwg@au1.ibm.com>
+ *
+ * FIXME: Draft only!
+ *
+ * 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.
+ *
+ * To build:
+ * dtc -I dts -O asm -o ebony.S -b 0 ebony.dts
+ * dtc -I dts -O dtb -o ebony.dtb -b 0 ebony.dts
+ */
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ model = "ibm,ebony";
+ compatible = "ibm,ebony";
+ dcr-parent = <&/cpus/PowerPC,440GP@0>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,440GP@0 {
+ device_type = "cpu";
+ reg = <0>;
+ clock-frequency = <0>; // Filled in by zImage
+ timebase-frequency = <0>; // Filled in by zImage
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <0>;
+ d-cache-size = <0>;
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 0>; // Filled in by zImage
+ };
+
+ UIC0: interrupt-controller0 {
+ device_type = "ibm,uic";
+ compatible = "ibm,uic-440gp", "ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0c0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+
+ };
+
+ UIC1: interrupt-controller1 {
+ device_type = "ibm,uic";
+ compatible = "ibm,uic-440gp", "ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0d0 009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <1e 4 1f 4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ CPC0: cpc {
+ device_type = "ibm,cpc";
+ compatible = "ibm,cpc-440gp";
+ dcr-reg = <0b0 003 0e0 010>;
+ // FIXME: anything else?
+ };
+
+ plb {
+ device_type = "ibm,plb";
+ compatible = "ibm,plb-440gp", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; // Filled in by zImage
+
+ SDRAM0: sdram {
+ device_type = "memory-controller";
+ compatible = "ibm,sdram-440gp", "ibm,sdram";
+ dcr-reg = <010 2>;
+ // FIXME: anything else?
+ };
+
+ DMA0: dma {
+ // FIXME: ???
+ device_type = "ibm,dma-4xx";
+ compatible = "ibm,dma-440gp", "ibm,dma-4xx";
+ dcr-reg = <100 027>;
+ };
+
+ MAL0: mcmal {
+ device_type = "mcmal-dma";
+ compatible = "ibm,mcmal-440gp", "ibm,mcmal";
+ dcr-reg = <180 62>;
+ num-tx-chans = <4>;
+ num-rx-chans = <4>;
+ interrupt-parent = <&MAL0>;
+ interrupts = <0 1 2 3 4>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*TXEOB*/ 0 &UIC0 a 4
+ /*RXEOB*/ 1 &UIC0 b 4
+ /*SERR*/ 2 &UIC1 0 4
+ /*TXDE*/ 3 &UIC1 1 4
+ /*RXDE*/ 4 &UIC1 2 4>;
+ interrupt-map-mask = <ffffffff>;
+ };
+
+ POB0: opb {
+ device_type = "ibm,opb";
+ compatible = "ibm,opb-440gp", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* Wish there was a nicer way of specifying a full 32-bit
+ range */
+ ranges = <00000000 1 00000000 80000000
+ 80000000 1 80000000 80000000>;
+ dcr-reg = <090 00b>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <7 4>;
+ clock-frequency = <0>; // Filled in by zImage
+
+ EBC0: ebc {
+ device_type = "ibm,ebc";
+ compatible = "ibm,ebc-440gp";
+ dcr-reg = <012 2>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <0>; // Filled in by zImage
+ ranges = <0 00000000 fff00000 100000
+ 1 00000000 48000000 100000
+ 2 00000000 ff800000 400000
+ 3 00000000 48200000 100000
+ 7 00000000 48300000 100000>;
+ interrupts = <5 4>;
+ interrupt-parent = <&UIC1>;
+
+ small-flash@0,0 {
+ device_type = "rom";
+ compatible = "direct-mapped";
+ probe-type = "JEDEC";
+ bank-width = <1>;
+ partitions = <0 80000>;
+ partition-names = "OpenBIOS";
+ reg = <0 80000 80000>;
+ };
+
+ ds1743@1,0 {
+ /* NVRAM & RTC */
+ device_type = "nvram";
+ compatible = "ds1743";
+ reg = <1 0 2000>;
+ };
+
+ large-flash@2,0 {
+ device_type = "rom";
+ compatible = "direct-mapped";
+ probe-type = "JEDEC";
+ bank-width = <1>;
+ partitions = <0 380000
+ 280000 80000>;
+ partition-names = "fs", "firmware";
+ reg = <2 0 400000>;
+ };
+
+ ir@3,0 {
+ reg = <3 0 10>;
+ };
+
+ fpga@7,0 {
+ compatible = "Ebony-FPGA";
+ reg = <7 0 10>;
+ };
+ };
+
+ UART0: serial@40000200 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <40000200 8>;
+ virtual-reg = <e0000200>;
+ clock-frequency = <A8C000>;
+ current-speed = <2580>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0 4>;
+ };
+
+ UART1: serial@40000300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <40000300 8>;
+ virtual-reg = <e0000300>;
+ clock-frequency = <A8C000>;
+ current-speed = <2580>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <1 4>;
+ };
+
+ IIC0: i2c@40000400 {
+ /* FIXME */
+ device_type = "i2c";
+ compatible = "ibm,iic-440gp", "ibm,iic";
+ reg = <40000400 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <2 4>;
+ };
+ IIC1: i2c@40000500 {
+ /* FIXME */
+ device_type = "i2c";
+ compatible = "ibm,iic-440gp", "ibm,iic";
+ reg = <40000500 14>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <3 4>;
+ };
+
+ GPIO0: gpio@40000700 {
+ /* FIXME */
+ device_type = "gpio";
+ compatible = "ibm,gpio-440gp";
+ reg = <40000700 20>;
+ };
+
+ ZMII0: emac-zmii@40000780 {
+ device_type = "emac-zmii";
+ compatible = "ibm,zmii-440gp", "ibm,zmii";
+ reg = <40000780 c>;
+ };
+
+ EMAC0: ethernet@40000800 {
+ linux,network-index = <0>;
+ device_type = "network";
+ compatible = "ibm,emac-440gp", "ibm,emac";
+ interrupt-parent = <&UIC1>;
+ interrupts = <1c 4 1d 4>;
+ reg = <40000800 70>;
+ local-mac-address = [000000000000]; // Filled in by zImage
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0 1>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rmii";
+ phy-map = <00000001>;
+ zmii-device = <&ZMII0>;
+ zmii-channel = <0>;
+ };
+ EMAC1: ethernet@40000900 {
+ linux,network-index = <1>;
+ device_type = "network";
+ compatible = "ibm,emac-440gp", "ibm,emac";
+ interrupt-parent = <&UIC1>;
+ interrupts = <1e 4 1f 4>;
+ reg = <40000900 70>;
+ local-mac-address = [000000000000]; // Filled in by zImage
+ mal-device = <&MAL0>;
+ mal-tx-channel = <2 3>;
+ mal-rx-channel = <1>;
+ cell-index = <1>;
+ max-frame-size = <5dc>;
+ rx-fifo-size = <1000>;
+ tx-fifo-size = <800>;
+ phy-mode = "rmii";
+ phy-map = <00000001>;
+ zmii-device = <&ZMII0>;
+ zmii-channel = <1>;
+ };
+
+
+ GPT0: gpt@40000a00 {
+ /* FIXME */
+ reg = <40000a00 d4>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <12 4 13 4 14 4 15 4 16 4>;
+ };
+
+ };
+
+ PCIX0: pci@1234 {
+ device_type = "pci";
+ /* FIXME */
+ reg = <2 0ec00000 8
+ 2 0ec80000 f0
+ 2 0ec80100 fc>;
+ };
+ };
+
+ chosen {
+ linux,stdout-path = "/plb/opb/serial@40000200";
+// linux,initrd-start = <0>; /* FIXME */
+// linux,initrd-end = <0>;
+// bootargs = "";
+ };
+};
+
diff --git a/arch/powerpc/boot/dts/holly.dts b/arch/powerpc/boot/dts/holly.dts
new file mode 100644
index 00000000000..254499b107f
--- /dev/null
+++ b/arch/powerpc/boot/dts/holly.dts
@@ -0,0 +1,198 @@
+/*
+ * Device Tree Source for IBM Holly (PPC 750CL with TSI controller)
+ * Copyright 2007, IBM Corporation
+ *
+ * Stephen Winiecki <stevewin@us.ibm.com>
+ * Josh Boyer <jwboyer@linux.vnet.ibm.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.
+ *
+ * To build:
+ * dtc -I dts -O asm -o holly.S -b 0 holly.dts
+ * dtc -I dts -O dtb -o holly.dtb -b 0 holly.dts
+ */
+
+/ {
+ model = "41K7339";
+ compatible = "ibm,holly";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells =<0>;
+ PowerPC,750CL@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>;
+ i-cache-line-size = <20>;
+ d-cache-size = <8000>;
+ i-cache-size = <8000>;
+ d-cache-sets = <80>;
+ i-cache-sets = <80>;
+ timebase-frequency = <2faf080>;
+ clock-frequency = <23c34600>;
+ bus-frequency = <bebc200>;
+ 32-bit;
+ };
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <00000000 20000000>;
+ };
+
+ tsi109@c0000000 {
+ device_type = "tsi-bridge";
+ compatible = "tsi-bridge";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <00000000 c0000000 00010000>;
+ reg = <c0000000 00010000>;
+
+ i2c@7000 {
+ device_type = "i2c";
+ compatible = "tsi-i2c";
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupts = <e 2>;
+ reg = <7000 400>;
+ };
+
+ mdio@6000 {
+ device_type = "mdio";
+ compatible = "tsi-ethernet";
+
+ PHY1: ethernet-phy@6000 {
+ device_type = "ethernet-phy";
+ compatible = "bcm54xx";
+ reg = <6000 50>;
+ phy-id = <1>;
+ };
+
+ PHY2: ethernet-phy@6400 {
+ device_type = "ethernet-phy";
+ compatible = "bcm54xx";
+ reg = <6000 50>;
+ phy-id = <2>;
+ };
+ };
+
+ ethernet@6200 {
+ device_type = "network";
+ compatible = "tsi-ethernet";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6000 200>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupts = <10 2>;
+ phy-handle = <&PHY1>;
+ };
+
+ ethernet@6600 {
+ device_type = "network";
+ compatible = "tsi-ethernet";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <6400 200>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupts = <11 2>;
+ phy-handle = <&PHY2>;
+ };
+
+ serial@7808 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <7808 200>;
+ virtual-reg = <c0007808>;
+ clock-frequency = <3F9C6000>;
+ current-speed = <1c200>;
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupts = <c 2>;
+ };
+
+ serial@7c08 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <7c08 200>;
+ virtual-reg = <c0007c08>;
+ clock-frequency = <3F9C6000>;
+ current-speed = <1c200>;
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupts = <d 2>;
+ };
+
+ MPIC: pic@7400 {
+ device_type = "open-pic";
+ compatible = "chrp,open-pic";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <7400 400>;
+ big-endian;
+ };
+
+ pci@1000 {
+ device_type = "pci";
+ compatible = "tsi109";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <1000 1000>;
+ bus-range = <0 0>;
+ /*----------------------------------------------------+
+ | PCI memory range.
+ | 01 denotes I/O space
+ | 02 denotes 32-bit memory space
+ +----------------------------------------------------*/
+ ranges = <02000000 0 40000000 40000000 0 10000000
+ 01000000 0 00000000 7e000000 0 00010000>;
+ clock-frequency = <7f28154>;
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupts = <17 2>;
+ interrupt-map-mask = <f800 0 0 7>;
+ /*----------------------------------------------------+
+ | The INTA, INTB, INTC, INTD are shared.
+ +----------------------------------------------------*/
+ interrupt-map = <
+ 0800 0 0 1 &RT0 24 0
+ 0800 0 0 2 &RT0 25 0
+ 0800 0 0 3 &RT0 26 0
+ 0800 0 0 4 &RT0 27 0
+
+ 1000 0 0 1 &RT0 25 0
+ 1000 0 0 2 &RT0 26 0
+ 1000 0 0 3 &RT0 27 0
+ 1000 0 0 4 &RT0 24 0
+
+ 1800 0 0 1 &RT0 26 0
+ 1800 0 0 2 &RT0 27 0
+ 1800 0 0 3 &RT0 24 0
+ 1800 0 0 4 &RT0 25 0
+
+ 2000 0 0 1 &RT0 27 0
+ 2000 0 0 2 &RT0 24 0
+ 2000 0 0 3 &RT0 25 0
+ 2000 0 0 4 &RT0 26 0
+ >;
+
+ RT0: router@1180 {
+ device_type = "pic-router";
+ interrupt-controller;
+ big-endian;
+ clock-frequency = <0>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <17 2>;
+ interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ };
+ };
+ };
+
+ chosen {
+ linux,stdout-path = "/tsi109@c0000000/serial@7808";
+ bootargs = "console=ttyS0,115200";
+ };
+};
diff --git a/arch/powerpc/boot/dts/kuroboxHD.dts b/arch/powerpc/boot/dts/kuroboxHD.dts
index b89791802e8..157dc98d398 100644
--- a/arch/powerpc/boot/dts/kuroboxHD.dts
+++ b/arch/powerpc/boot/dts/kuroboxHD.dts
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts"
cpus {
linux,phandle = <2000>;
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHD.dtb -V 16 kuroboxHD.dts"
interrupt-parent = <4400>;
interrupt-map-mask = <f800 0 0 7>;
interrupt-map = <
- /* IDSEL 0x11 - IRQ0 ETH */
+ /* IDSEL 11 - IRQ0 ETH */
5800 0 0 1 4400 0 1
5800 0 0 2 4400 1 1
5800 0 0 3 4400 2 1
5800 0 0 4 4400 3 1
- /* IDSEL 0x12 - IRQ1 IDE0 */
+ /* IDSEL 12 - IRQ1 IDE0 */
6000 0 0 1 4400 1 1
6000 0 0 2 4400 2 1
6000 0 0 3 4400 3 1
6000 0 0 4 4400 0 1
- /* IDSEL 0x14 - IRQ3 USB2.0 */
+ /* IDSEL 14 - IRQ3 USB2.0 */
7000 0 0 1 4400 3 1
7000 0 0 2 4400 3 1
7000 0 0 3 4400 3 1
diff --git a/arch/powerpc/boot/dts/kuroboxHG.dts b/arch/powerpc/boot/dts/kuroboxHG.dts
index 753102752d8..919eb29097d 100644
--- a/arch/powerpc/boot/dts/kuroboxHG.dts
+++ b/arch/powerpc/boot/dts/kuroboxHG.dts
@@ -29,7 +29,6 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
cpus {
linux,phandle = <2000>;
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -126,17 +125,17 @@ build with: "dtc -f -I dts -O dtb -o kuroboxHG.dtb -V 16 kuroboxHG.dts"
interrupt-parent = <4400>;
interrupt-map-mask = <f800 0 0 7>;
interrupt-map = <
- /* IDSEL 0x11 - IRQ0 ETH */
+ /* IDSEL 11 - IRQ0 ETH */
5800 0 0 1 4400 0 1
5800 0 0 2 4400 1 1
5800 0 0 3 4400 2 1
5800 0 0 4 4400 3 1
- /* IDSEL 0x12 - IRQ1 IDE0 */
+ /* IDSEL 12 - IRQ1 IDE0 */
6000 0 0 1 4400 1 1
6000 0 0 2 4400 2 1
6000 0 0 3 4400 3 1
6000 0 0 4 4400 0 1
- /* IDSEL 0x14 - IRQ3 USB2.0 */
+ /* IDSEL 14 - IRQ3 USB2.0 */
7000 0 0 1 4400 3 1
7000 0 0 2 4400 3 1
7000 0 0 3 4400 3 1
diff --git a/arch/powerpc/boot/dts/lite5200.dts b/arch/powerpc/boot/dts/lite5200.dts
index c03103c6328..e13ac6ef05a 100644
--- a/arch/powerpc/boot/dts/lite5200.dts
+++ b/arch/powerpc/boot/dts/lite5200.dts
@@ -24,7 +24,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -49,6 +48,7 @@
soc5200@f0000000 {
model = "fsl,mpc5200";
+ compatible = "mpc5200";
revision = "" // from bootloader
#interrupt-cells = <3>;
device_type = "soc";
@@ -167,7 +167,7 @@
device_type = "mscan";
compatible = "mpc5200-mscan";
cell-index = <1>;
- interrupts = <1 12 0>;
+ interrupts = <2 12 0>;
interrupt-parent = <500>;
reg = <980 80>;
};
@@ -179,7 +179,7 @@
interrupt-parent = <500>;
};
- gpio-wkup@b00 {
+ gpio-wkup@c00 {
compatible = "mpc5200-gpio-wkup";
reg = <c00 40>;
interrupts = <1 8 0 0 3 0>;
@@ -318,20 +318,22 @@
i2c@3d00 {
device_type = "i2c";
- compatible = "mpc5200-i2c";
+ compatible = "mpc5200-i2c\0fsl-i2c";
cell-index = <0>;
reg = <3d00 40>;
interrupts = <2 f 0>;
interrupt-parent = <500>;
+ fsl5200-clocking;
};
i2c@3d40 {
device_type = "i2c";
- compatible = "mpc5200-i2c";
+ compatible = "mpc5200-i2c\0fsl-i2c";
cell-index = <1>;
reg = <3d40 40>;
interrupts = <2 10 0>;
interrupt-parent = <500>;
+ fsl5200-clocking;
};
sram@8000 {
device_type = "sram";
diff --git a/arch/powerpc/boot/dts/lite5200b.dts b/arch/powerpc/boot/dts/lite5200b.dts
index 3875ca9a9a6..00211b39a34 100644
--- a/arch/powerpc/boot/dts/lite5200b.dts
+++ b/arch/powerpc/boot/dts/lite5200b.dts
@@ -24,7 +24,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -49,6 +48,7 @@
soc5200@f0000000 {
model = "fsl,mpc5200b";
+ compatible = "mpc5200";
revision = ""; // from bootloader
#interrupt-cells = <3>;
device_type = "soc";
@@ -167,7 +167,7 @@
device_type = "mscan";
compatible = "mpc5200b-mscan\0mpc5200-mscan";
cell-index = <1>;
- interrupts = <1 12 0>;
+ interrupts = <2 12 0>;
interrupt-parent = <500>;
reg = <980 80>;
};
@@ -179,7 +179,7 @@
interrupt-parent = <500>;
};
- gpio-wkup@b00 {
+ gpio-wkup@c00 {
compatible = "mpc5200b-gpio-wkup\0mpc5200-gpio-wkup";
reg = <c00 40>;
interrupts = <1 8 0 0 3 0>;
@@ -323,20 +323,22 @@
i2c@3d00 {
device_type = "i2c";
- compatible = "mpc5200b-i2c\0mpc5200-i2c";
+ compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c";
cell-index = <0>;
reg = <3d00 40>;
interrupts = <2 f 0>;
interrupt-parent = <500>;
+ fsl5200-clocking;
};
i2c@3d40 {
device_type = "i2c";
- compatible = "mpc5200b-i2c\0mpc5200-i2c";
+ compatible = "mpc5200b-i2c\0mpc5200-i2c\0fsl-i2c";
cell-index = <1>;
reg = <3d40 40>;
interrupts = <2 10 0>;
interrupt-parent = <500>;
+ fsl5200-clocking;
};
sram@8000 {
device_type = "sram";
diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts
index 41d0720c590..6fa3754f293 100644
--- a/arch/powerpc/boot/dts/mpc7448hpc2.dts
+++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts
@@ -19,7 +19,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells =<0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 260b2e44777..423eedcf634 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -17,7 +17,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 6d721900d00..a1533cc07d0 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -16,7 +16,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 06b310698a0..93b76069601 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -16,7 +16,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -307,14 +306,12 @@
interrupts = <11 8>;
reg = <3>;
device_type = "ethernet-phy";
- interface = <3>; //ENET_100_MII
};
phy4: ethernet-phy@04 {
interrupt-parent = < &ipic >;
interrupts = <12 8>;
reg = <4>;
device_type = "ethernet-phy";
- interface = <3>;
};
};
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
new file mode 100644
index 00000000000..be4c35784e4
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -0,0 +1,289 @@
+/*
+ * MPC832x RDB Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+/ {
+ model = "MPC8323ERDB";
+ compatible = "MPC8323ERDB", "MPC832xRDB", "MPC83xxRDB";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8323@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <4000>; // L1, 16K
+ i-cache-size = <4000>; // L1, 16K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ 32-bit;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <00000000 04000000>;
+ };
+
+ soc8323@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00000200>;
+ bus-frequency = <0>;
+
+ wdt@200 {
+ device_type = "watchdog";
+ compatible = "mpc83xx_wdt";
+ reg = <200 100>;
+ };
+
+ i2c@3000 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3000 100>;
+ interrupts = <e 8>;
+ interrupt-parent = <&pic>;
+ dfsrr;
+ };
+
+ serial@4500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4500 100>;
+ clock-frequency = <0>;
+ interrupts = <9 8>;
+ interrupt-parent = <&pic>;
+ };
+
+ serial@4600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4600 100>;
+ clock-frequency = <0>;
+ interrupts = <a 8>;
+ interrupt-parent = <&pic>;
+ };
+
+ crypto@30000 {
+ device_type = "crypto";
+ model = "SEC2";
+ compatible = "talitos";
+ reg = <30000 7000>;
+ interrupts = <b 8>;
+ interrupt-parent = <&pic>;
+ /* Rev. 2.2 */
+ num-channels = <1>;
+ channel-fifo-len = <18>;
+ exec-units-mask = <0000004c>;
+ descriptor-types-mask = <0122003f>;
+ };
+
+ pci@8500 {
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x10 AD16 (USB) */
+ 8000 0 0 1 &pic 11 8
+
+ /* IDSEL 0x11 AD17 (Mini1)*/
+ 8800 0 0 1 &pic 12 8
+ 8800 0 0 2 &pic 13 8
+ 8800 0 0 3 &pic 14 8
+ 8800 0 0 4 &pic 30 8
+
+ /* IDSEL 0x12 AD18 (PCI/Mini2) */
+ 9000 0 0 1 &pic 13 8
+ 9000 0 0 2 &pic 14 8
+ 9000 0 0 3 &pic 30 8
+ 9000 0 0 4 &pic 11 8>;
+
+ interrupt-parent = <&pic>;
+ interrupts = <42 8>;
+ bus-range = <0 0>;
+ ranges = <42000000 0 80000000 80000000 0 10000000
+ 02000000 0 90000000 90000000 0 10000000
+ 01000000 0 d0000000 d0000000 0 04000000>;
+ clock-frequency = <0>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <8500 100>;
+ compatible = "83xx";
+ device_type = "pci";
+ };
+
+ pic:pic@700 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <700 100>;
+ built-in;
+ device_type = "ipic";
+ };
+
+ par_io@1400 {
+ reg = <1400 100>;
+ device_type = "par_io";
+ num-ports = <7>;
+
+ ucc2pio:ucc_pin@02 {
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 3 4 3 0 2 0 /* MDIO */
+ 3 5 1 0 2 0 /* MDC */
+ 3 15 2 0 1 0 /* RX_CLK (CLK16) */
+ 3 17 2 0 1 0 /* TX_CLK (CLK3) */
+ 0 12 1 0 1 0 /* TxD0 */
+ 0 13 1 0 1 0 /* TxD1 */
+ 0 14 1 0 1 0 /* TxD2 */
+ 0 15 1 0 1 0 /* TxD3 */
+ 0 16 2 0 1 0 /* RxD0 */
+ 0 17 2 0 1 0 /* RxD1 */
+ 0 18 2 0 1 0 /* RxD2 */
+ 0 19 2 0 1 0 /* RxD3 */
+ 0 1a 2 0 1 0 /* RX_ER */
+ 0 1b 1 0 1 0 /* TX_ER */
+ 0 1c 2 0 1 0 /* RX_DV */
+ 0 1d 2 0 1 0 /* COL */
+ 0 1e 1 0 1 0 /* TX_EN */
+ 0 1f 2 0 1 0>; /* CRS */
+ };
+ ucc3pio:ucc_pin@03 {
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0 d 2 0 1 0 /* RX_CLK (CLK9) */
+ 3 18 2 0 1 0 /* TX_CLK (CLK10) */
+ 1 0 1 0 1 0 /* TxD0 */
+ 1 1 1 0 1 0 /* TxD1 */
+ 1 2 1 0 1 0 /* TxD2 */
+ 1 3 1 0 1 0 /* TxD3 */
+ 1 4 2 0 1 0 /* RxD0 */
+ 1 5 2 0 1 0 /* RxD1 */
+ 1 6 2 0 1 0 /* RxD2 */
+ 1 7 2 0 1 0 /* RxD3 */
+ 1 8 2 0 1 0 /* RX_ER */
+ 1 9 1 0 1 0 /* TX_ER */
+ 1 a 2 0 1 0 /* RX_DV */
+ 1 b 2 0 1 0 /* COL */
+ 1 c 1 0 1 0 /* TX_EN */
+ 1 d 2 0 1 0>; /* CRS */
+ };
+ };
+ };
+
+ qe@e0100000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "qe";
+ model = "QE";
+ ranges = <0 e0100000 00100000>;
+ reg = <e0100000 480>;
+ brg-frequency = <0>;
+ bus-frequency = <BCD3D80>;
+
+ muram@10000 {
+ device_type = "muram";
+ ranges = <0 00010000 00004000>;
+
+ data-only@0 {
+ reg = <0 4000>;
+ };
+ };
+
+ spi@4c0 {
+ device_type = "spi";
+ compatible = "fsl_spi";
+ reg = <4c0 40>;
+ interrupts = <2>;
+ interrupt-parent = <&qeic>;
+ mode = "cpu";
+ };
+
+ spi@500 {
+ device_type = "spi";
+ compatible = "fsl_spi";
+ reg = <500 40>;
+ interrupts = <1>;
+ interrupt-parent = <&qeic>;
+ mode = "cpu";
+ };
+
+ ucc@3000 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <2>;
+ reg = <3000 200>;
+ interrupts = <21>;
+ interrupt-parent = <&qeic>;
+ mac-address = [ 00 04 9f ef 03 02 ];
+ rx-clock = <20>;
+ tx-clock = <13>;
+ phy-handle = <&phy00>;
+ pio-handle = <&ucc2pio>;
+ };
+
+ ucc@2200 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <3>;
+ reg = <2200 200>;
+ interrupts = <22>;
+ interrupt-parent = <&qeic>;
+ mac-address = [ 00 04 9f ef 03 01 ];
+ rx-clock = <19>;
+ tx-clock = <1a>;
+ phy-handle = <&phy04>;
+ pio-handle = <&ucc3pio>;
+ };
+
+ mdio@3120 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3120 18>;
+ device_type = "mdio";
+ compatible = "ucc_geth_phy";
+
+ phy00:ethernet-phy@00 {
+ interrupt-parent = <&pic>;
+ interrupts = <0>;
+ reg = <0>;
+ device_type = "ethernet-phy";
+ };
+ phy04:ethernet-phy@04 {
+ interrupt-parent = <&pic>;
+ interrupts = <0>;
+ reg = <4>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ qeic:qeic@80 {
+ interrupt-controller;
+ device_type = "qeic";
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <80 80>;
+ built-in;
+ big-endian;
+ interrupts = <20 8 21 8>; //high:32 low:33
+ interrupt-parent = <&pic>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 61b550bf164..db0d0030327 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -15,7 +15,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
index b2e1a5ec377..f636528a3c7 100644
--- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
@@ -15,7 +15,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index e4b43c24bc0..07bcc5194d2 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -16,7 +16,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 4fe45c02184..38c8594df3a 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -21,7 +21,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -306,6 +305,7 @@
rx-clock = <0>;
tx-clock = <19>;
phy-handle = < &phy0 >;
+ phy-connection-type = "rgmii-id";
pio-handle = < &pio1 >;
};
@@ -321,6 +321,7 @@
rx-clock = <0>;
tx-clock = <14>;
phy-handle = < &phy1 >;
+ phy-connection-type = "rgmii-id";
pio-handle = < &pio2 >;
};
@@ -336,14 +337,12 @@
interrupts = <11 8>;
reg = <0>;
device_type = "ethernet-phy";
- interface = <6>; //ENET_1000_GMII
};
phy1: ethernet-phy@01 {
interrupt-parent = < &ipic >;
interrupts = <12 8>;
reg = <1>;
device_type = "ethernet-phy";
- interface = <6>;
};
};
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index 3c0917fa791..f261d647ac8 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 2a1ae760ab3..5fdcb69554f 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
new file mode 100644
index 00000000000..6b084605bb4
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -0,0 +1,136 @@
+/*
+ * MPC8544 DS Device Tree Source
+ *
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+/ {
+ model = "MPC8544DS";
+ compatible = "MPC8544DS", "MPC85xxDS";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8544@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <8000>; // L1, 32K
+ i-cache-size = <8000>; // L1, 32K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ 32-bit;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <00000000 00000000>; // Filled by U-Boot
+ };
+
+ soc8544@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00100000>; // CCSRBAR 1M
+ bus-frequency = <0>; // Filled out by uboot.
+
+ i2c@3000 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3000 100>;
+ interrupts = <1b 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ mdio@24520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "mdio";
+ compatible = "gianfar";
+ reg = <24520 20>;
+ phy0: ethernet-phy@0 {
+ interrupt-parent = <&mpic>;
+ interrupts = <3a 1>;
+ reg = <0>;
+ device_type = "ethernet-phy";
+ };
+ phy1: ethernet-phy@1 {
+ interrupt-parent = <&mpic>;
+ interrupts = <3a 1>;
+ reg = <1>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <24000 1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <d 2 e 2 12 2>;
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy0>;
+ };
+
+ ethernet@26000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <26000 1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <f 2 10 2 11 2>;
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy1>;
+ };
+
+ serial@4500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4500 100>;
+ clock-frequency = <0>;
+ interrupts = <1a 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial@4600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4600 100>;
+ clock-frequency = <0>;
+ interrupts = <1a 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ mpic: pic@40000 {
+ clock-frequency = <0>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <40000 40000>;
+ built-in;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ big-endian;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 7eb5d81d5ee..b2b2200d042 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index 5f9c102a0ab..68a4795720d 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 10502638b0e..1f2afe9291d 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index bf49d8c997b..948a3b61bd4 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -21,7 +21,6 @@
#size-cells = <1>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
@@ -289,6 +288,7 @@
rx-clock = <0>;
tx-clock = <19>;
phy-handle = <&qe_phy0>;
+ phy-connection-type = "gmii";
pio-handle = <&pio1>;
};
@@ -304,6 +304,7 @@
rx-clock = <0>;
tx-clock = <14>;
phy-handle = <&qe_phy1>;
+ phy-connection-type = "gmii";
pio-handle = <&pio2>;
};
@@ -321,28 +322,24 @@
interrupts = <31 1>;
reg = <0>;
device_type = "ethernet-phy";
- interface = <6>; //ENET_1000_GMII
};
qe_phy1: ethernet-phy@01 {
interrupt-parent = <&mpic>;
interrupts = <32 1>;
reg = <1>;
device_type = "ethernet-phy";
- interface = <6>;
};
qe_phy2: ethernet-phy@02 {
interrupt-parent = <&mpic>;
interrupts = <31 1>;
reg = <2>;
device_type = "ethernet-phy";
- interface = <6>; //ENET_1000_GMII
};
qe_phy3: ethernet-phy@03 {
interrupt-parent = <&mpic>;
interrupts = <32 1>;
reg = <3>;
device_type = "ethernet-phy";
- interface = <6>; //ENET_1000_GMII
};
};
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 8a4995a85ba..260b264c869 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -17,7 +17,6 @@
#size-cells = <1>;
cpus {
- #cpus = <2>;
#address-cells = <1>;
#size-cells = <0>;
@@ -300,6 +299,30 @@
};
};
+
+ pci@9000 {
+ compatible = "86xx";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <9000 1000>;
+ bus-range = <0 ff>;
+ ranges = <02000000 0 a0000000 a0000000 0 20000000
+ 01000000 0 00000000 e3000000 0 00100000>;
+ clock-frequency = <1fca055>;
+ interrupt-parent = <&mpic>;
+ interrupts = <19 2>;
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 44 1
+ 0000 0 0 2 &mpic 45 1
+ 0000 0 0 3 &mpic 46 1
+ 0000 0 0 4 &mpic 47 1
+ >;
+ };
+
mpic: pic@40000 {
clock-frequency = <0>;
interrupt-controller;
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index 2b56b5df451..c0d06fd1292 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -18,7 +18,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index faecd08c54d..110bf617060 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -18,7 +18,6 @@
linux,phandle = <100>;
cpus {
- #cpus = <1>;
#address-cells = <1>;
#size-cells = <0>;
linux,phandle = <200>;
diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c
new file mode 100644
index 00000000000..b1251ee7a10
--- /dev/null
+++ b/arch/powerpc/boot/ebony.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * Based on earlier code:
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003, 2004 Zultys Technologies
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+#include "reg.h"
+#include "dcr.h"
+#include "44x.h"
+
+extern char _dtb_start[];
+extern char _dtb_end[];
+
+static u8 *ebony_mac0, *ebony_mac1;
+
+/* Calculate 440GP clocks */
+void ibm440gp_fixup_clocks(unsigned int sysclk, unsigned int ser_clk)
+{
+ u32 sys0 = mfdcr(DCRN_CPC0_SYS0);
+ u32 cr0 = mfdcr(DCRN_CPC0_CR0);
+ u32 cpu, plb, opb, ebc, tb, uart0, uart1, m;
+ u32 opdv = CPC0_SYS0_OPDV(sys0);
+ u32 epdv = CPC0_SYS0_EPDV(sys0);
+
+ if (sys0 & CPC0_SYS0_BYPASS) {
+ /* Bypass system PLL */
+ cpu = plb = sysclk;
+ } else {
+ if (sys0 & CPC0_SYS0_EXTSL)
+ /* PerClk */
+ m = CPC0_SYS0_FWDVB(sys0) * opdv * epdv;
+ else
+ /* CPU clock */
+ m = CPC0_SYS0_FBDV(sys0) * CPC0_SYS0_FWDVA(sys0);
+ cpu = sysclk * m / CPC0_SYS0_FWDVA(sys0);
+ plb = sysclk * m / CPC0_SYS0_FWDVB(sys0);
+ }
+
+ opb = plb / opdv;
+ ebc = opb / epdv;
+
+ /* FIXME: Check if this is for all 440GP, or just Ebony */
+ if ((mfpvr() & 0xf0000fff) == 0x40000440)
+ /* Rev. B 440GP, use external system clock */
+ tb = sysclk;
+ else
+ /* Rev. C 440GP, errata force us to use internal clock */
+ tb = cpu;
+
+ if (cr0 & CPC0_CR0_U0EC)
+ /* External UART clock */
+ uart0 = ser_clk;
+ else
+ /* Internal UART clock */
+ uart0 = plb / CPC0_CR0_UDIV(cr0);
+
+ if (cr0 & CPC0_CR0_U1EC)
+ /* External UART clock */
+ uart1 = ser_clk;
+ else
+ /* Internal UART clock */
+ uart1 = plb / CPC0_CR0_UDIV(cr0);
+
+ printf("PPC440GP: SysClk = %dMHz (%x)\n\r",
+ (sysclk + 500000) / 1000000, sysclk);
+
+ dt_fixup_cpu_clocks(cpu, tb, 0);
+
+ dt_fixup_clock("/plb", plb);
+ dt_fixup_clock("/plb/opb", opb);
+ dt_fixup_clock("/plb/opb/ebc", ebc);
+ dt_fixup_clock("/plb/opb/serial@40000200", uart0);
+ dt_fixup_clock("/plb/opb/serial@40000300", uart1);
+}
+
+static void ebony_fixups(void)
+{
+ // FIXME: sysclk should be derived by reading the FPGA registers
+ unsigned long sysclk = 33000000;
+
+ ibm440gp_fixup_clocks(sysclk, 6 * 1843200);
+ ibm44x_fixup_memsize();
+ dt_fixup_mac_addresses(ebony_mac0, ebony_mac1);
+}
+
+#define SPRN_DBCR0 0x134
+#define DBCR0_RST_SYSTEM 0x30000000
+
+static void ebony_exit(void)
+{
+ unsigned long tmp;
+
+ asm volatile (
+ "mfspr %0,%1\n"
+ "oris %0,%0,%2@h\n"
+ "mtspr %1,%0"
+ : "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM)
+ );
+
+}
+
+void ebony_init(void *mac0, void *mac1)
+{
+ platform_ops.fixups = ebony_fixups;
+ platform_ops.exit = ebony_exit;
+ ebony_mac0 = mac0;
+ ebony_mac1 = mac1;
+ ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
+ serial_console_init();
+}
diff --git a/arch/powerpc/boot/elf.h b/arch/powerpc/boot/elf.h
index d4828fcf1cb..1941bc50d4c 100644
--- a/arch/powerpc/boot/elf.h
+++ b/arch/powerpc/boot/elf.h
@@ -146,4 +146,12 @@ typedef struct elf64_phdr {
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
+struct elf_info {
+ unsigned long loadsize;
+ unsigned long memsize;
+ unsigned long elfoffset;
+};
+int parse_elf64(void *hdr, struct elf_info *info);
+int parse_elf32(void *hdr, struct elf_info *info);
+
#endif /* _PPC_BOOT_ELF_H_ */
diff --git a/arch/powerpc/boot/elf_util.c b/arch/powerpc/boot/elf_util.c
new file mode 100644
index 00000000000..7454aa4cc20
--- /dev/null
+++ b/arch/powerpc/boot/elf_util.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * Updates for PPC64 by Todd Inglett, Dave Engebretsen & Peter Bergner.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+
+int parse_elf64(void *hdr, struct elf_info *info)
+{
+ Elf64_Ehdr *elf64 = hdr;
+ Elf64_Phdr *elf64ph;
+ unsigned int i;
+
+ if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 &&
+ elf64->e_ident[EI_MAG1] == ELFMAG1 &&
+ elf64->e_ident[EI_MAG2] == ELFMAG2 &&
+ elf64->e_ident[EI_MAG3] == ELFMAG3 &&
+ elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
+ elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
+ elf64->e_type == ET_EXEC &&
+ elf64->e_machine == EM_PPC64))
+ return 0;
+
+ elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
+ (unsigned long)elf64->e_phoff);
+ for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
+ if (elf64ph->p_type == PT_LOAD)
+ break;
+ if (i >= (unsigned int)elf64->e_phnum)
+ return 0;
+
+ info->loadsize = (unsigned long)elf64ph->p_filesz;
+ info->memsize = (unsigned long)elf64ph->p_memsz;
+ info->elfoffset = (unsigned long)elf64ph->p_offset;
+
+ return 1;
+}
+
+int parse_elf32(void *hdr, struct elf_info *info)
+{
+ Elf32_Ehdr *elf32 = hdr;
+ Elf32_Phdr *elf32ph;
+ unsigned int i;
+
+ if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 &&
+ elf32->e_ident[EI_MAG1] == ELFMAG1 &&
+ elf32->e_ident[EI_MAG2] == ELFMAG2 &&
+ elf32->e_ident[EI_MAG3] == ELFMAG3 &&
+ elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
+ elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
+ elf32->e_type == ET_EXEC &&
+ elf32->e_machine == EM_PPC))
+ return 0;
+
+ elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
+ for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
+ if (elf32ph->p_type == PT_LOAD)
+ break;
+ if (i >= elf32->e_phnum)
+ return 0;
+
+ info->loadsize = elf32ph->p_filesz;
+ info->memsize = elf32ph->p_memsz;
+ info->elfoffset = elf32ph->p_offset;
+ return 1;
+}
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c
index c76c194715b..d00fbd92a45 100644
--- a/arch/powerpc/boot/flatdevtree.c
+++ b/arch/powerpc/boot/flatdevtree.c
@@ -29,12 +29,20 @@
#define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1))
+static char *ft_root_node(struct ft_cxt *cxt)
+{
+ return cxt->rgn[FT_STRUCT].start;
+}
+
/* Routines for keeping node ptrs returned by ft_find_device current */
/* First entry not used b/c it would return 0 and be taken as NULL/error */
-static void *ft_node_add(struct ft_cxt *cxt, char *node)
+static void *ft_get_phandle(struct ft_cxt *cxt, char *node)
{
unsigned int i;
+ if (!node)
+ return NULL;
+
for (i = 1; i < cxt->nodes_used; i++) /* already there? */
if (cxt->node_tbl[i] == node)
return (void *)i;
@@ -238,7 +246,7 @@ static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
if (rgn == FT_STRUCT)
ft_node_update_before(cxt, p, -nextra);
}
- *p -= nextra;
+ *pp -= nextra;
cxt->rgn[rgn].start -= nextra;
cxt->rgn[rgn].size += nextra;
return 1;
@@ -253,8 +261,14 @@ static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
char *str, *next;
enum ft_rgn_id r;
- if (!cxt->isordered && !ft_reorder(cxt, nextra))
- return 0;
+ if (!cxt->isordered) {
+ unsigned long rgn_off = *pp - cxt->rgn[rgn].start;
+
+ if (!ft_reorder(cxt, nextra))
+ return 0;
+
+ *pp = cxt->rgn[rgn].start + rgn_off;
+ }
if (ft_shuffle(cxt, pp, rgn, nextra))
return 1;
@@ -415,7 +429,7 @@ int ft_prop(struct ft_cxt *cxt, const char *name, const void *data,
{
int off, len;
- off = lookup_string(cxt, name);
+ off = map_string(cxt, name);
if (off == NO_STRING)
return -1;
@@ -590,7 +604,7 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size)
void ft_begin_tree(struct ft_cxt *cxt)
{
- cxt->p = cxt->rgn[FT_STRUCT].start;
+ cxt->p = ft_root_node(cxt);
}
void ft_end_tree(struct ft_cxt *cxt)
@@ -636,8 +650,21 @@ void *ft_find_device(struct ft_cxt *cxt, const char *srch_path)
/* require absolute path */
if (srch_path[0] != '/')
return NULL;
- node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path);
- return ft_node_add(cxt, node);
+ node = ft_find_descendent(cxt, ft_root_node(cxt), srch_path);
+ return ft_get_phandle(cxt, node);
+}
+
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+ const char *srch_path)
+{
+ char *node;
+
+ node = ft_node_ph2node(cxt, top);
+ if (node == NULL)
+ return NULL;
+
+ node = ft_find_descendent(cxt, node, srch_path);
+ return ft_get_phandle(cxt, node);
}
void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
@@ -701,23 +728,18 @@ void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
return NULL;
}
-void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
+void *__ft_get_parent(struct ft_cxt *cxt, void *node)
{
- void *node;
int d;
struct ft_atom atom;
char *p;
- node = ft_node_ph2node(cxt, phandle);
- if (node == NULL)
- return NULL;
-
for (d = 0; cxt->genealogy[d] != NULL; ++d)
if (cxt->genealogy[d] == node)
- return cxt->genealogy[d > 0 ? d - 1 : 0];
+ return d > 0 ? cxt->genealogy[d - 1] : NULL;
/* have to do it the hard way... */
- p = cxt->rgn[FT_STRUCT].start;
+ p = ft_root_node(cxt);
d = 0;
while ((p = ft_next(cxt, p, &atom)) != NULL) {
switch (atom.tag) {
@@ -726,7 +748,7 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
if (node == atom.data) {
/* found it */
cxt->genealogy[d + 1] = NULL;
- return d > 0 ? cxt->genealogy[d - 1] : node;
+ return d > 0 ? cxt->genealogy[d - 1] : NULL;
}
++d;
break;
@@ -738,41 +760,131 @@ void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
return NULL;
}
-int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
- void *buf, const unsigned int buflen)
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
{
- struct ft_atom atom;
- void *node;
- char *p;
- int depth;
- unsigned int size;
-
- node = ft_node_ph2node(cxt, phandle);
+ void *node = ft_node_ph2node(cxt, phandle);
if (node == NULL)
- return -1;
+ return NULL;
- depth = 0;
- p = (char *)node;
+ node = __ft_get_parent(cxt, node);
+ return ft_get_phandle(cxt, node);
+}
- while ((p = ft_next(cxt, p, &atom)) != NULL) {
+static const void *__ft_get_prop(struct ft_cxt *cxt, void *node,
+ const char *propname, unsigned int *len)
+{
+ struct ft_atom atom;
+ int depth = 0;
+
+ while ((node = ft_next(cxt, node, &atom)) != NULL) {
switch (atom.tag) {
case OF_DT_BEGIN_NODE:
++depth;
break;
+
case OF_DT_PROP:
- if ((depth != 1) || strcmp(atom.name, propname))
+ if (depth != 1 || strcmp(atom.name, propname))
break;
- size = min(atom.size, buflen);
- memcpy(buf, atom.data, size);
- return atom.size;
+
+ if (len)
+ *len = atom.size;
+
+ return atom.data;
+
case OF_DT_END_NODE:
if (--depth <= 0)
- return -1;
+ return NULL;
}
}
+
+ return NULL;
+}
+
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+ void *buf, const unsigned int buflen)
+{
+ const void *data;
+ unsigned int size;
+
+ void *node = ft_node_ph2node(cxt, phandle);
+ if (!node)
+ return -1;
+
+ data = __ft_get_prop(cxt, node, propname, &size);
+ if (data) {
+ unsigned int clipped_size = min(size, buflen);
+ memcpy(buf, data, clipped_size);
+ return size;
+ }
+
return -1;
}
+void *__ft_find_node_by_prop_value(struct ft_cxt *cxt, void *prev,
+ const char *propname, const char *propval,
+ unsigned int proplen)
+{
+ struct ft_atom atom;
+ char *p = ft_root_node(cxt);
+ char *next;
+ int past_prev = prev ? 0 : 1;
+ int depth = -1;
+
+ while ((next = ft_next(cxt, p, &atom)) != NULL) {
+ const void *data;
+ unsigned int size;
+
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ depth++;
+
+ if (prev == p) {
+ past_prev = 1;
+ break;
+ }
+
+ if (!past_prev || depth < 1)
+ break;
+
+ data = __ft_get_prop(cxt, p, propname, &size);
+ if (!data || size != proplen)
+ break;
+ if (memcmp(data, propval, size))
+ break;
+
+ return p;
+
+ case OF_DT_END_NODE:
+ if (depth-- == 0)
+ return NULL;
+
+ break;
+ }
+
+ p = next;
+ }
+
+ return NULL;
+}
+
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+ const char *propname, const char *propval,
+ int proplen)
+{
+ void *node = NULL;
+
+ if (prev) {
+ node = ft_node_ph2node(cxt, prev);
+
+ if (!node)
+ return NULL;
+ }
+
+ node = __ft_find_node_by_prop_value(cxt, node, propname,
+ propval, proplen);
+ return ft_get_phandle(cxt, node);
+}
+
int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
const void *buf, const unsigned int buflen)
{
@@ -849,19 +961,26 @@ int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname)
return -1;
}
-void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name)
{
struct ft_atom atom;
char *p, *next;
int depth = 0;
- p = cxt->rgn[FT_STRUCT].start;
+ if (parent) {
+ p = ft_node_ph2node(cxt, parent);
+ if (!p)
+ return NULL;
+ } else {
+ p = ft_root_node(cxt);
+ }
+
while ((next = ft_next(cxt, p, &atom)) != NULL) {
switch (atom.tag) {
case OF_DT_BEGIN_NODE:
++depth;
- if (depth == 1 && strcmp(atom.name, path) == 0)
- /* duplicate node path, return error */
+ if (depth == 1 && strcmp(atom.name, name) == 0)
+ /* duplicate node name, return error */
return NULL;
break;
case OF_DT_END_NODE:
@@ -870,7 +989,7 @@ void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
break;
/* end of node, insert here */
cxt->p = p;
- ft_begin_node(cxt, path);
+ ft_begin_node(cxt, name);
ft_end_node(cxt);
return p;
}
diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h
index b9cd9f61f35..cb26325d72d 100644
--- a/arch/powerpc/boot/flatdevtree.h
+++ b/arch/powerpc/boot/flatdevtree.h
@@ -97,10 +97,17 @@ int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size);
void ft_dump_blob(const void *bphp);
void ft_merge_blob(struct ft_cxt *cxt, void *blob);
void *ft_find_device(struct ft_cxt *cxt, const char *srch_path);
+void *ft_find_device_rel(struct ft_cxt *cxt, const void *top,
+ const char *srch_path);
void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path);
int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
void *buf, const unsigned int buflen);
int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
const void *buf, const unsigned int buflen);
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle);
+void *ft_find_node_by_prop_value(struct ft_cxt *cxt, const void *prev,
+ const char *propname, const char *propval,
+ int proplen);
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *name);
#endif /* FLATDEVTREE_H */
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c
index 04da38fa477..4341e6558c1 100644
--- a/arch/powerpc/boot/flatdevtree_misc.c
+++ b/arch/powerpc/boot/flatdevtree_misc.c
@@ -16,24 +16,43 @@
static struct ft_cxt cxt;
-static void *ft_finddevice(const char *name)
+static void *fdtm_finddevice(const char *name)
{
return ft_find_device(&cxt, name);
}
-static int ft_getprop(const void *phandle, const char *propname, void *buf,
- const int buflen)
+static int fdtm_getprop(const void *phandle, const char *propname,
+ void *buf, const int buflen)
{
return ft_get_prop(&cxt, phandle, propname, buf, buflen);
}
-static int ft_setprop(const void *phandle, const char *propname,
- const void *buf, const int buflen)
+static int fdtm_setprop(const void *phandle, const char *propname,
+ const void *buf, const int buflen)
{
return ft_set_prop(&cxt, phandle, propname, buf, buflen);
}
-static unsigned long ft_finalize(void)
+static void *fdtm_get_parent(const void *phandle)
+{
+ return ft_get_parent(&cxt, phandle);
+}
+
+static void *fdtm_create_node(const void *phandle, const char *name)
+{
+ return ft_create_node(&cxt, phandle, name);
+}
+
+static void *fdtm_find_node_by_prop_value(const void *prev,
+ const char *propname,
+ const char *propval,
+ int proplen)
+{
+ return ft_find_node_by_prop_value(&cxt, prev, propname,
+ propval, proplen);
+}
+
+static unsigned long fdtm_finalize(void)
{
ft_end_tree(&cxt);
return (unsigned long)cxt.bph;
@@ -41,10 +60,13 @@ static unsigned long ft_finalize(void)
int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device)
{
- dt_ops.finddevice = ft_finddevice;
- dt_ops.getprop = ft_getprop;
- dt_ops.setprop = ft_setprop;
- dt_ops.finalize = ft_finalize;
+ dt_ops.finddevice = fdtm_finddevice;
+ dt_ops.getprop = fdtm_getprop;
+ dt_ops.setprop = fdtm_setprop;
+ dt_ops.get_parent = fdtm_get_parent;
+ dt_ops.create_node = fdtm_create_node;
+ dt_ops.find_node_by_prop_value = fdtm_find_node_by_prop_value;
+ dt_ops.finalize = fdtm_finalize;
return ft_open(&cxt, dt_blob, max_size, max_find_device,
platform_ops.realloc);
diff --git a/arch/powerpc/boot/gunzip_util.c b/arch/powerpc/boot/gunzip_util.c
new file mode 100644
index 00000000000..df8ab07e9ff
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Based on earlier work, Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <stddef.h>
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define HEAD_CRC 2
+#define EXTRA_FIELD 4
+#define ORIG_NAME 8
+#define COMMENT 0x10
+#define RESERVED 0xe0
+
+/**
+ * gunzip_start - prepare to decompress gzip data
+ * @state: decompressor state structure to be initialized
+ * @src: buffer containing gzip compressed or uncompressed data
+ * @srclen: size in bytes of the buffer at src
+ *
+ * If the buffer at @src contains a gzip header, this function
+ * initializes zlib to decompress the data, storing the decompression
+ * state in @state. The other functions in this file can then be used
+ * to decompress data from the gzipped stream.
+ *
+ * If the buffer at @src does not contain a gzip header, it is assumed
+ * to contain uncompressed data. The buffer information is recorded
+ * in @state and the other functions in this file will simply copy
+ * data from the uncompressed data stream at @src.
+ *
+ * Any errors, such as bad compressed data, cause an error to be
+ * printed an the platform's exit() function to be called.
+ */
+void gunzip_start(struct gunzip_state *state, void *src, int srclen)
+{
+ char *hdr = src;
+ int hdrlen = 0;
+
+ memset(state, 0, sizeof(*state));
+
+ /* Check for gzip magic number */
+ if ((hdr[0] == 0x1f) && (hdr[1] == 0x8b)) {
+ /* gzip data, initialize zlib parameters */
+ int r, flags;
+
+ state->s.workspace = state->scratch;
+ if (zlib_inflate_workspacesize() > sizeof(state->scratch))
+ fatal("insufficient scratch space for gunzip\n\r");
+
+ /* skip header */
+ hdrlen = 10;
+ flags = hdr[3];
+ if (hdr[2] != Z_DEFLATED || (flags & RESERVED) != 0)
+ fatal("bad gzipped data\n\r");
+ if ((flags & EXTRA_FIELD) != 0)
+ hdrlen = 12 + hdr[10] + (hdr[11] << 8);
+ if ((flags & ORIG_NAME) != 0)
+ while (hdr[hdrlen++] != 0)
+ ;
+ if ((flags & COMMENT) != 0)
+ while (hdr[hdrlen++] != 0)
+ ;
+ if ((flags & HEAD_CRC) != 0)
+ hdrlen += 2;
+ if (hdrlen >= srclen)
+ fatal("gunzip_start: ran out of data in header\n\r");
+
+ r = zlib_inflateInit2(&state->s, -MAX_WBITS);
+ if (r != Z_OK)
+ fatal("inflateInit2 returned %d\n\r", r);
+ }
+
+ state->s.next_in = src + hdrlen;
+ state->s.avail_in = srclen - hdrlen;
+}
+
+/**
+ * gunzip_partial - extract bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @dst: buffer to store extracted data
+ * @dstlen: maximum number of bytes to extract
+ *
+ * This function extracts at most @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary. Exactly @dstlen bytes are extracted unless the data
+ * stream doesn't contain enough bytes, in which case the entire
+ * remainder of the stream is decompressed.
+ *
+ * Returns the actual number of bytes extracted. If any errors occur,
+ * such as a corrupted compressed stream, an error is printed an the
+ * platform's exit() function is called.
+ */
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen)
+{
+ int len;
+
+ if (state->s.workspace) {
+ /* gunzipping */
+ int r;
+
+ state->s.next_out = dst;
+ state->s.avail_out = dstlen;
+ r = zlib_inflate(&state->s, Z_FULL_FLUSH);
+ if (r != Z_OK && r != Z_STREAM_END)
+ fatal("inflate returned %d msg: %s\n\r", r, state->s.msg);
+ len = state->s.next_out - (unsigned char *)dst;
+ } else {
+ /* uncompressed image */
+ len = min(state->s.avail_in, (unsigned)dstlen);
+ memcpy(dst, state->s.next_in, len);
+ state->s.next_in += len;
+ state->s.avail_in -= len;
+ }
+ return len;
+}
+
+/**
+ * gunzip_exactly - extract a fixed number of bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @dst: buffer to store extracted data
+ * @dstlen: number of bytes to extract
+ *
+ * This function extracts exactly @dstlen bytes from the data stream
+ * previously associated with @state by gunzip_start(), decompressing
+ * if necessary.
+ *
+ * If there are less @dstlen bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_exactly(struct gunzip_state *state, void *dst, int dstlen)
+{
+ int len;
+
+ len = gunzip_partial(state, dst, dstlen);
+ if (len < dstlen)
+ fatal("\n\rgunzip_exactly: ran out of data!"
+ " Wanted %d, got %d.\n\r", dstlen, len);
+}
+
+/**
+ * gunzip_discard - discard bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @len: number of bytes to discard
+ *
+ * This function extracts, then discards exactly @len bytes from the
+ * data stream previously associated with @state by gunzip_start().
+ * Subsequent gunzip_partial(), gunzip_exactly() or gunzip_finish()
+ * calls will extract the data following the discarded bytes in the
+ * data stream.
+ *
+ * If there are less @len bytes available in the data stream, or if
+ * any other errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+void gunzip_discard(struct gunzip_state *state, int len)
+{
+ static char discard_buf[128];
+
+ while (len > sizeof(discard_buf)) {
+ gunzip_exactly(state, discard_buf, sizeof(discard_buf));
+ len -= sizeof(discard_buf);
+ }
+
+ if (len > 0)
+ gunzip_exactly(state, discard_buf, len);
+}
+
+/**
+ * gunzip_finish - extract all remaining bytes from a gzip data stream
+ * @state: gzip state structure previously initialized by gunzip_start()
+ * @dst: buffer to store extracted data
+ * @dstlen: maximum number of bytes to extract
+ *
+ * This function extracts all remaining data, or at most @dstlen
+ * bytes, from the stream previously associated with @state by
+ * gunzip_start(). zlib is then shut down, so it is an error to use
+ * any of the functions in this file on @state until it is
+ * re-initialized with another call to gunzip_start().
+ *
+ * If any errors occur, such as a corrupted compressed stream, an
+ * error is printed an the platform's exit() function is called.
+ */
+int gunzip_finish(struct gunzip_state *state, void *dst, int dstlen)
+{
+ int len;
+
+ if (state->s.workspace) {
+ len = gunzip_partial(state, dst, dstlen);
+ zlib_inflateEnd(&state->s);
+ } else {
+ /* uncompressed image */
+ len = min(state->s.avail_in, (unsigned)dstlen);
+ memcpy(dst, state->s.next_in, len);
+ }
+
+ return len;
+}
diff --git a/arch/powerpc/boot/gunzip_util.h b/arch/powerpc/boot/gunzip_util.h
new file mode 100644
index 00000000000..b3dfa6e87b3
--- /dev/null
+++ b/arch/powerpc/boot/gunzip_util.h
@@ -0,0 +1,45 @@
+/*
+ * Decompression convenience functions
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ *
+ * 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.
+ */
+#ifndef _PPC_BOOT_GUNZIP_UTIL_H_
+#define _PPC_BOOT_GUNZIP_UTIL_H_
+
+#include "zlib.h"
+
+/*
+ * These functions are designed to make life easy for decompressing
+ * kernel images, initrd images or any other gzip compressed image,
+ * particularly if its useful to decompress part of the image (e.g. to
+ * examine headers) before decompressing the remainder.
+ *
+ * To use:
+ * - declare a gunzip_state structure
+ * - use gunzip_start() to initialize the state, associating it
+ * with a stream of compressed data
+ * - use gunzip_partial(), gunzip_exactly() and gunzip_discard()
+ * in any combination to extract pieces of data from the stream
+ * - Finally use gunzip_finish() to extract the tail of the
+ * compressed stream and wind up zlib
+ */
+
+/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
+#define GUNZIP_SCRATCH_SIZE 46912
+
+struct gunzip_state {
+ z_stream s;
+ char scratch[46912];
+};
+
+void gunzip_start(struct gunzip_state *state, void *src, int srclen);
+int gunzip_partial(struct gunzip_state *state, void *dst, int dstlen);
+void gunzip_exactly(struct gunzip_state *state, void *dst, int len);
+void gunzip_discard(struct gunzip_state *state, int len);
+int gunzip_finish(struct gunzip_state *state, void *dst, int len);
+
+#endif /* _PPC_BOOT_GUNZIP_UTIL_H_ */
diff --git a/arch/powerpc/boot/holly.c b/arch/powerpc/boot/holly.c
new file mode 100644
index 00000000000..7d6539f5e22
--- /dev/null
+++ b/arch/powerpc/boot/holly.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2007 IBM Corporation
+ *
+ * Stephen Winiecki <stevewin@us.ibm.com>
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>
+ *
+ * Based on earlier code:
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+#include "io.h"
+
+extern char _start[];
+extern char _end[];
+extern char _dtb_start[];
+extern char _dtb_end[];
+
+BSS_STACK(4096);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5)
+{
+ u32 heapsize = 0x8000000 - (u32)_end; /* 128M */
+
+ simple_alloc_init(_end, heapsize, 32, 64);
+ ft_init(_dtb_start, 0, 4);
+ serial_console_init();
+}
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 6f6b50d238b..56b56a8d4b2 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -14,11 +14,10 @@
#include "page.h"
#include "string.h"
#include "stdio.h"
-#include "zlib.h"
#include "ops.h"
+#include "gunzip_util.h"
#include "flatdevtree.h"
-
-extern void flush_cache(void *, unsigned long);
+#include "reg.h"
extern char _start[];
extern char __bss_start[];
@@ -30,304 +29,173 @@ extern char _initrd_end[];
extern char _dtb_start[];
extern char _dtb_end[];
+static struct gunzip_state gzstate;
+
struct addr_range {
- unsigned long addr;
+ void *addr;
unsigned long size;
- unsigned long memsize;
};
-static struct addr_range vmlinux;
-static struct addr_range vmlinuz;
-static struct addr_range initrd;
-
-static unsigned long elfoffset;
-static int is_64bit;
-
-/* scratch space for gunzip; 46912 is from zlib_inflate_workspacesize() */
-static char scratch[46912];
-static char elfheader[256];
typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
#undef DEBUG
-#define HEAD_CRC 2
-#define EXTRA_FIELD 4
-#define ORIG_NAME 8
-#define COMMENT 0x10
-#define RESERVED 0xe0
-
-static void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+static struct addr_range prep_kernel(void)
{
- z_stream s;
- int r, i, flags;
-
- /* skip header */
- i = 10;
- flags = src[3];
- if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
- printf("bad gzipped data\n\r");
- exit();
- }
- if ((flags & EXTRA_FIELD) != 0)
- i = 12 + src[10] + (src[11] << 8);
- if ((flags & ORIG_NAME) != 0)
- while (src[i++] != 0)
- ;
- if ((flags & COMMENT) != 0)
- while (src[i++] != 0)
- ;
- if ((flags & HEAD_CRC) != 0)
- i += 2;
- if (i >= *lenp) {
- printf("gunzip: ran out of data in header\n\r");
- exit();
- }
+ char elfheader[256];
+ void *vmlinuz_addr = _vmlinux_start;
+ unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+ void *addr = 0;
+ struct elf_info ei;
+ int len;
- if (zlib_inflate_workspacesize() > sizeof(scratch)) {
- printf("gunzip needs more mem\n");
- exit();
- }
- memset(&s, 0, sizeof(s));
- s.workspace = scratch;
- r = zlib_inflateInit2(&s, -MAX_WBITS);
- if (r != Z_OK) {
- printf("inflateInit2 returned %d\n\r", r);
- exit();
- }
- s.next_in = src + i;
- s.avail_in = *lenp - i;
- s.next_out = dst;
- s.avail_out = dstlen;
- r = zlib_inflate(&s, Z_FULL_FLUSH);
- if (r != Z_OK && r != Z_STREAM_END) {
- printf("inflate returned %d msg: %s\n\r", r, s.msg);
- exit();
+ /* gunzip the ELF header of the kernel */
+ gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+ gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+ if (!parse_elf64(elfheader, &ei) && !parse_elf32(elfheader, &ei))
+ fatal("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
+
+ if (platform_ops.image_hdr)
+ platform_ops.image_hdr(elfheader);
+
+ /* We need to alloc the memsize: gzip will expand the kernel
+ * text/data, then possible rubbish we don't care about. But
+ * the kernel bss must be claimed (it will be zero'd by the
+ * kernel itself)
+ */
+ printf("Allocating 0x%lx bytes for kernel ...\n\r", ei.memsize);
+
+ if (platform_ops.vmlinux_alloc) {
+ addr = platform_ops.vmlinux_alloc(ei.memsize);
+ } else {
+ if ((unsigned long)_start < ei.memsize)
+ fatal("Insufficient memory for kernel at address 0!"
+ " (_start=%p)\n\r", _start);
}
- *lenp = s.next_out - (unsigned char *) dst;
- zlib_inflateEnd(&s);
-}
-static int is_elf64(void *hdr)
-{
- Elf64_Ehdr *elf64 = hdr;
- Elf64_Phdr *elf64ph;
- unsigned int i;
-
- if (!(elf64->e_ident[EI_MAG0] == ELFMAG0 &&
- elf64->e_ident[EI_MAG1] == ELFMAG1 &&
- elf64->e_ident[EI_MAG2] == ELFMAG2 &&
- elf64->e_ident[EI_MAG3] == ELFMAG3 &&
- elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
- elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
- elf64->e_type == ET_EXEC &&
- elf64->e_machine == EM_PPC64))
- return 0;
-
- elf64ph = (Elf64_Phdr *)((unsigned long)elf64 +
- (unsigned long)elf64->e_phoff);
- for (i = 0; i < (unsigned int)elf64->e_phnum; i++, elf64ph++)
- if (elf64ph->p_type == PT_LOAD)
- break;
- if (i >= (unsigned int)elf64->e_phnum)
- return 0;
-
- elfoffset = (unsigned long)elf64ph->p_offset;
- vmlinux.size = (unsigned long)elf64ph->p_filesz + elfoffset;
- vmlinux.memsize = (unsigned long)elf64ph->p_memsz + elfoffset;
-
- is_64bit = 1;
- return 1;
-}
+ /* Finally, gunzip the kernel */
+ printf("gunzipping (0x%p <- 0x%p:0x%p)...", addr,
+ vmlinuz_addr, vmlinuz_addr+vmlinuz_size);
+ /* discard up to the actual load data */
+ gunzip_discard(&gzstate, ei.elfoffset - sizeof(elfheader));
+ len = gunzip_finish(&gzstate, addr, ei.loadsize);
+ if (len != ei.loadsize)
+ fatal("ran out of data! only got 0x%x of 0x%lx bytes.\n\r",
+ len, ei.loadsize);
+ printf("done 0x%x bytes\n\r", len);
-static int is_elf32(void *hdr)
-{
- Elf32_Ehdr *elf32 = hdr;
- Elf32_Phdr *elf32ph;
- unsigned int i;
-
- if (!(elf32->e_ident[EI_MAG0] == ELFMAG0 &&
- elf32->e_ident[EI_MAG1] == ELFMAG1 &&
- elf32->e_ident[EI_MAG2] == ELFMAG2 &&
- elf32->e_ident[EI_MAG3] == ELFMAG3 &&
- elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
- elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
- elf32->e_type == ET_EXEC &&
- elf32->e_machine == EM_PPC))
- return 0;
-
- elf32 = (Elf32_Ehdr *)elfheader;
- elf32ph = (Elf32_Phdr *) ((unsigned long)elf32 + elf32->e_phoff);
- for (i = 0; i < elf32->e_phnum; i++, elf32ph++)
- if (elf32ph->p_type == PT_LOAD)
- break;
- if (i >= elf32->e_phnum)
- return 0;
-
- elfoffset = elf32ph->p_offset;
- vmlinux.size = elf32ph->p_filesz + elf32ph->p_offset;
- vmlinux.memsize = elf32ph->p_memsz + elf32ph->p_offset;
- return 1;
+ flush_cache(addr, ei.loadsize);
+
+ return (struct addr_range){addr, ei.memsize};
}
-static void prep_kernel(unsigned long a1, unsigned long a2)
+static struct addr_range prep_initrd(struct addr_range vmlinux, void *chosen,
+ unsigned long initrd_addr,
+ unsigned long initrd_size)
{
- int len;
-
- vmlinuz.addr = (unsigned long)_vmlinux_start;
- vmlinuz.size = (unsigned long)(_vmlinux_end - _vmlinux_start);
-
- /* gunzip the ELF header of the kernel */
- if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
- len = vmlinuz.size;
- gunzip(elfheader, sizeof(elfheader),
- (unsigned char *)vmlinuz.addr, &len);
- } else
- memcpy(elfheader, (const void *)vmlinuz.addr,
- sizeof(elfheader));
-
- if (!is_elf64(elfheader) && !is_elf32(elfheader)) {
- printf("Error: not a valid PPC32 or PPC64 ELF file!\n\r");
- exit();
+ /* If we have an image attached to us, it overrides anything
+ * supplied by the loader. */
+ if (_initrd_end > _initrd_start) {
+ printf("Attached initrd image at 0x%p-0x%p\n\r",
+ _initrd_start, _initrd_end);
+ initrd_addr = (unsigned long)_initrd_start;
+ initrd_size = _initrd_end - _initrd_start;
+ } else if (initrd_size > 0) {
+ printf("Using loader supplied ramdisk at 0x%lx-0x%lx\n\r",
+ initrd_addr, initrd_addr + initrd_size);
}
- if (platform_ops.image_hdr)
- platform_ops.image_hdr(elfheader);
- /* We need to alloc the memsize plus the file offset since gzip
- * will expand the header (file offset), then the kernel, then
- * possible rubbish we don't care about. But the kernel bss must
- * be claimed (it will be zero'd by the kernel itself)
- */
- printf("Allocating 0x%lx bytes for kernel ...\n\r", vmlinux.memsize);
- vmlinux.addr = (unsigned long)malloc(vmlinux.memsize);
- if (vmlinux.addr == 0) {
- printf("Can't allocate memory for kernel image !\n\r");
- exit();
- }
+ /* If there's no initrd at all, we're done */
+ if (! initrd_size)
+ return (struct addr_range){0, 0};
/*
- * Now find the initrd
- *
- * First see if we have an image attached to us. If so
- * allocate memory for it and copy it there.
+ * If the initrd is too low it will be clobbered when the
+ * kernel relocates to its final location. In this case,
+ * allocate a safer place and move it.
*/
- initrd.size = (unsigned long)(_initrd_end - _initrd_start);
- initrd.memsize = initrd.size;
- if (initrd.size > 0) {
+ if (initrd_addr < vmlinux.size) {
+ void *old_addr = (void *)initrd_addr;
+
printf("Allocating 0x%lx bytes for initrd ...\n\r",
- initrd.size);
- initrd.addr = (unsigned long)malloc((u32)initrd.size);
- if (initrd.addr == 0) {
- printf("Can't allocate memory for initial "
- "ramdisk !\n\r");
- exit();
- }
- printf("initial ramdisk moving 0x%lx <- 0x%lx "
- "(0x%lx bytes)\n\r", initrd.addr,
- (unsigned long)_initrd_start, initrd.size);
- memmove((void *)initrd.addr, (void *)_initrd_start,
- initrd.size);
- printf("initrd head: 0x%lx\n\r",
- *((unsigned long *)initrd.addr));
- } else if (a2 != 0) {
- /* Otherwise, see if yaboot or another loader gave us an initrd */
- initrd.addr = a1;
- initrd.memsize = initrd.size = a2;
- printf("Using loader supplied initrd at 0x%lx (0x%lx bytes)\n\r",
- initrd.addr, initrd.size);
+ initrd_size);
+ initrd_addr = (unsigned long)malloc(initrd_size);
+ if (! initrd_addr)
+ fatal("Can't allocate memory for initial "
+ "ramdisk !\n\r");
+ printf("Relocating initrd 0x%lx <- 0x%p (0x%lx bytes)\n\r",
+ initrd_addr, old_addr, initrd_size);
+ memmove((void *)initrd_addr, old_addr, initrd_size);
}
- /* Eventually gunzip the kernel */
- if (*(unsigned short *)vmlinuz.addr == 0x1f8b) {
- printf("gunzipping (0x%lx <- 0x%lx:0x%0lx)...",
- vmlinux.addr, vmlinuz.addr, vmlinuz.addr+vmlinuz.size);
- len = vmlinuz.size;
- gunzip((void *)vmlinux.addr, vmlinux.memsize,
- (unsigned char *)vmlinuz.addr, &len);
- printf("done 0x%lx bytes\n\r", len);
- } else {
- memmove((void *)vmlinux.addr,(void *)vmlinuz.addr,
- vmlinuz.size);
- }
+ printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd_addr));
- /* Skip over the ELF header */
-#ifdef DEBUG
- printf("... skipping 0x%lx bytes of ELF header\n\r",
- elfoffset);
-#endif
- vmlinux.addr += elfoffset;
+ /* Tell the kernel initrd address via device tree */
+ setprop_val(chosen, "linux,initrd-start", (u32)(initrd_addr));
+ setprop_val(chosen, "linux,initrd-end", (u32)(initrd_addr+initrd_size));
- flush_cache((void *)vmlinux.addr, vmlinux.size);
+ return (struct addr_range){(void *)initrd_addr, initrd_size};
}
/* A buffer that may be edited by tools operating on a zImage binary so as to
* edit the command line passed to vmlinux (by setting /chosen/bootargs).
* The buffer is put in it's own section so that tools may locate it easier.
*/
-static char builtin_cmdline[COMMAND_LINE_SIZE]
+static char cmdline[COMMAND_LINE_SIZE]
__attribute__((__section__("__builtin_cmdline")));
-static void get_cmdline(char *buf, int size)
+static void prep_cmdline(void *chosen)
{
- void *devp;
- int len = strlen(builtin_cmdline);
-
- buf[0] = '\0';
-
- if (len > 0) { /* builtin_cmdline overrides dt's /chosen/bootargs */
- len = min(len, size-1);
- strncpy(buf, builtin_cmdline, len);
- buf[len] = '\0';
- }
- else if ((devp = finddevice("/chosen")))
- getprop(devp, "bootargs", buf, size);
-}
+ if (cmdline[0] == '\0')
+ getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
-static void set_cmdline(char *buf)
-{
- void *devp;
+ printf("\n\rLinux/PowerPC load: %s", cmdline);
+ /* If possible, edit the command line */
+ if (console_ops.edit_cmdline)
+ console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
+ printf("\n\r");
- if ((devp = finddevice("/chosen")))
- setprop(devp, "bootargs", buf, strlen(buf) + 1);
+ /* Put the command line back into the devtree for the kernel */
+ setprop_str(chosen, "bootargs", cmdline);
}
struct platform_ops platform_ops;
struct dt_ops dt_ops;
struct console_ops console_ops;
+struct loader_info loader_info;
-void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
+void start(void)
{
+ struct addr_range vmlinux, initrd;
kernel_entry_t kentry;
- char cmdline[COMMAND_LINE_SIZE];
unsigned long ft_addr = 0;
+ void *chosen;
- memset(__bss_start, 0, _end - __bss_start);
- memset(&platform_ops, 0, sizeof(platform_ops));
- memset(&dt_ops, 0, sizeof(dt_ops));
- memset(&console_ops, 0, sizeof(console_ops));
+ /* Do this first, because malloc() could clobber the loader's
+ * command line. Only use the loader command line if a
+ * built-in command line wasn't set by an external tool */
+ if ((loader_info.cmdline_len > 0) && (cmdline[0] == '\0'))
+ memmove(cmdline, loader_info.cmdline,
+ min(loader_info.cmdline_len, COMMAND_LINE_SIZE-1));
- if (platform_init(promptr, _dtb_start, _dtb_end))
- exit();
if (console_ops.open && (console_ops.open() < 0))
exit();
if (platform_ops.fixups)
platform_ops.fixups();
printf("\n\rzImage starting: loaded at 0x%p (sp: 0x%p)\n\r",
- _start, sp);
+ _start, get_sp());
- prep_kernel(a1, a2);
+ /* Ensure that the device tree has a /chosen node */
+ chosen = finddevice("/chosen");
+ if (!chosen)
+ chosen = create_node(NULL, "chosen");
- /* If cmdline came from zimage wrapper or if we can edit the one
- * in the dt, print it out and edit it, if possible.
- */
- if ((strlen(builtin_cmdline) > 0) || console_ops.edit_cmdline) {
- get_cmdline(cmdline, COMMAND_LINE_SIZE);
- printf("\n\rLinux/PowerPC load: %s", cmdline);
- if (console_ops.edit_cmdline)
- console_ops.edit_cmdline(cmdline, COMMAND_LINE_SIZE);
- printf("\n\r");
- set_cmdline(cmdline);
- }
+ vmlinux = prep_kernel();
+ initrd = prep_initrd(vmlinux, chosen,
+ loader_info.initrd_addr, loader_info.initrd_size);
+ prep_cmdline(chosen);
printf("Finalizing device tree...");
if (dt_ops.finalize)
@@ -335,7 +203,7 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
if (ft_addr)
printf(" flat tree at 0x%lx\n\r", ft_addr);
else
- printf(" using OF tree (promptr=%p)\n\r", promptr);
+ printf(" using OF tree (promptr=%p)\n\r", loader_info.promptr);
if (console_ops.close)
console_ops.close();
@@ -344,10 +212,9 @@ void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
if (ft_addr)
kentry(ft_addr, 0, NULL);
else
- /* XXX initrd addr/size should be passed in properties */
- kentry(initrd.addr, initrd.size, promptr);
+ kentry((unsigned long)initrd.addr, initrd.size,
+ loader_info.promptr);
- /* console closed so printf below may not work */
- printf("Error: Linux kernel returned to zImage boot wrapper!\n\r");
- exit();
+ /* console closed so printf in fatal below may not work */
+ fatal("Error: Linux kernel returned to zImage boot wrapper!\n\r");
}
diff --git a/arch/powerpc/boot/mktree.c b/arch/powerpc/boot/mktree.c
index 4cb89299365..45d06a8c7cd 100644
--- a/arch/powerpc/boot/mktree.c
+++ b/arch/powerpc/boot/mktree.c
@@ -46,8 +46,8 @@ int main(int argc, char *argv[])
struct stat st;
boot_block_t bt;
- if (argc < 3) {
- fprintf(stderr, "usage: %s <zImage-file> <boot-image> [entry-point]\n",argv[0]);
+ if (argc < 5) {
+ fprintf(stderr, "usage: %s <zImage-file> <boot-image> <load address> <entry point>\n",argv[0]);
exit(1);
}
@@ -61,10 +61,8 @@ int main(int argc, char *argv[])
bt.bb_magic = htonl(0x0052504F);
/* If we have the optional entry point parameter, use it */
- if (argc == 4)
- bt.bb_dest = bt.bb_entry_point = htonl(strtoul(argv[3], NULL, 0));
- else
- bt.bb_dest = bt.bb_entry_point = htonl(0x500000);
+ bt.bb_dest = htonl(strtoul(argv[3], NULL, 0));
+ bt.bb_entry_point = htonl(strtoul(argv[4], NULL, 0));
/* We know these from the linker command.
* ...and then move it up into memory a little more so the
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c
index 1ffe72e35cd..f8f1b2f3141 100644
--- a/arch/powerpc/boot/ns16550.c
+++ b/arch/powerpc/boot/ns16550.c
@@ -55,10 +55,15 @@ static u8 ns16550_tstc(void)
int ns16550_console_init(void *devp, struct serial_console_data *scdp)
{
int n;
+ unsigned long reg_phys;
n = getprop(devp, "virtual-reg", &reg_base, sizeof(reg_base));
- if (n != sizeof(reg_base))
- return -1;
+ if (n != sizeof(reg_base)) {
+ if (!dt_xlate_reg(devp, 0, &reg_phys, NULL))
+ return -1;
+
+ reg_base = (void *)reg_phys;
+ }
n = getprop(devp, "reg-shift", &reg_shift, sizeof(reg_shift));
if (n != sizeof(reg_shift))
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
index 0182f384f3e..d16ee3e3f86 100644
--- a/arch/powerpc/boot/of.c
+++ b/arch/powerpc/boot/of.c
@@ -173,7 +173,7 @@ static void *claim(unsigned long virt, unsigned long size, unsigned long align)
return (void *) virt;
}
-static void *of_try_claim(u32 size)
+static void *of_try_claim(unsigned long size)
{
unsigned long addr = 0;
@@ -208,6 +208,16 @@ static void of_image_hdr(const void *hdr)
}
}
+static void *of_vmlinux_alloc(unsigned long size)
+{
+ void *p = malloc(size);
+
+ if (!p)
+ fatal("Can't allocate memory for kernel image!\n\r");
+
+ return p;
+}
+
static void of_exit(void)
{
call_prom("exit", 0, 0);
@@ -256,11 +266,12 @@ static void of_console_write(char *buf, int len)
call_prom("write", 3, 1, of_stdout_handle, buf, len);
}
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
+void platform_init(unsigned long a1, unsigned long a2, void *promptr)
{
platform_ops.image_hdr = of_image_hdr;
platform_ops.malloc = of_try_claim;
platform_ops.exit = of_exit;
+ platform_ops.vmlinux_alloc = of_vmlinux_alloc;
dt_ops.finddevice = of_finddevice;
dt_ops.getprop = of_getprop;
@@ -270,5 +281,9 @@ int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
console_ops.write = of_console_write;
prom = (int (*)(void *))promptr;
- return 0;
+ loader_info.promptr = promptr;
+ if (a1 && a2 && a2 != 0xdeadbeef) {
+ loader_info.initrd_addr = a1;
+ loader_info.initrd_size = a2;
+ }
}
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 8abb6516bb7..73bd47a3a07 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -11,7 +11,9 @@
#ifndef _PPC_BOOT_OPS_H_
#define _PPC_BOOT_OPS_H_
+#include <stddef.h>
#include "types.h"
+#include "string.h"
#define COMMAND_LINE_SIZE 512
#define MAX_PATH_LEN 256
@@ -21,10 +23,11 @@
struct platform_ops {
void (*fixups)(void);
void (*image_hdr)(const void *);
- void * (*malloc)(u32 size);
+ void * (*malloc)(unsigned long size);
void (*free)(void *ptr);
void * (*realloc)(void *ptr, unsigned long size);
void (*exit)(void);
+ void * (*vmlinux_alloc)(unsigned long size);
};
extern struct platform_ops platform_ops;
@@ -35,6 +38,12 @@ struct dt_ops {
const int buflen);
int (*setprop)(const void *phandle, const char *name,
const void *buf, const int buflen);
+ void *(*get_parent)(const void *phandle);
+ /* The node must not already exist. */
+ void *(*create_node)(const void *parent, const char *name);
+ void *(*find_node_by_prop_value)(const void *prev,
+ const char *propname,
+ const char *propval, int proplen);
unsigned long (*finalize)(void);
};
extern struct dt_ops dt_ops;
@@ -58,13 +67,23 @@ struct serial_console_data {
void (*close)(void);
};
-int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end);
+struct loader_info {
+ void *promptr;
+ unsigned long initrd_addr, initrd_size;
+ char *cmdline;
+ int cmdline_len;
+};
+extern struct loader_info loader_info;
+
+void start(void);
int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
int serial_console_init(void);
int ns16550_console_init(void *devp, struct serial_console_data *scdp);
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
- u32 max_allocs);
-
+void *simple_alloc_init(char *base, unsigned long heap_size,
+ unsigned long granularity, unsigned long max_allocs);
+extern void flush_cache(void *, unsigned long);
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size);
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr);
static inline void *finddevice(const char *name)
{
@@ -76,12 +95,76 @@ static inline int getprop(void *devp, const char *name, void *buf, int buflen)
return (dt_ops.getprop) ? dt_ops.getprop(devp, name, buf, buflen) : -1;
}
-static inline int setprop(void *devp, const char *name, void *buf, int buflen)
+static inline int setprop(void *devp, const char *name,
+ const void *buf, int buflen)
{
return (dt_ops.setprop) ? dt_ops.setprop(devp, name, buf, buflen) : -1;
}
+#define setprop_val(devp, name, val) \
+ do { \
+ typeof(val) x = (val); \
+ setprop((devp), (name), &x, sizeof(x)); \
+ } while (0)
+
+static inline int setprop_str(void *devp, const char *name, const char *buf)
+{
+ if (dt_ops.setprop)
+ return dt_ops.setprop(devp, name, buf, strlen(buf) + 1);
+
+ return -1;
+}
+
+static inline void *get_parent(const char *devp)
+{
+ return dt_ops.get_parent ? dt_ops.get_parent(devp) : NULL;
+}
+
+static inline void *create_node(const void *parent, const char *name)
+{
+ return dt_ops.create_node ? dt_ops.create_node(parent, name) : NULL;
+}
+
-static inline void *malloc(u32 size)
+static inline void *find_node_by_prop_value(const void *prev,
+ const char *propname,
+ const char *propval, int proplen)
+{
+ if (dt_ops.find_node_by_prop_value)
+ return dt_ops.find_node_by_prop_value(prev, propname,
+ propval, proplen);
+
+ return NULL;
+}
+
+static inline void *find_node_by_prop_value_str(const void *prev,
+ const char *propname,
+ const char *propval)
+{
+ return find_node_by_prop_value(prev, propname, propval,
+ strlen(propval) + 1);
+}
+
+static inline void *find_node_by_devtype(const void *prev,
+ const char *type)
+{
+ return find_node_by_prop_value_str(prev, "device_type", type);
+}
+
+void dt_fixup_memory(u64 start, u64 size);
+void dt_fixup_cpu_clocks(u32 cpufreq, u32 tbfreq, u32 busfreq);
+void dt_fixup_clock(const char *path, u32 freq);
+void __dt_fixup_mac_addresses(u32 startindex, ...);
+#define dt_fixup_mac_addresses(...) \
+ __dt_fixup_mac_addresses(0, __VA_ARGS__, NULL)
+
+
+static inline void *find_node_by_linuxphandle(const u32 linuxphandle)
+{
+ return find_node_by_prop_value(NULL, "linux,phandle",
+ (char *)&linuxphandle, sizeof(u32));
+}
+
+static inline void *malloc(unsigned long size)
{
return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL;
}
@@ -98,5 +181,11 @@ static inline void exit(void)
platform_ops.exit();
for(;;);
}
+#define fatal(args...) { printf(args); exit(); }
+
+
+#define BSS_STACK(size) \
+ static char _bss_stack[size]; \
+ void *_platform_stack_top = _bss_stack + sizeof(_bss_stack);
#endif /* _PPC_BOOT_OPS_H_ */
diff --git a/arch/powerpc/boot/ppcboot.h b/arch/powerpc/boot/ppcboot.h
new file mode 100644
index 00000000000..5290ff2c2b2
--- /dev/null
+++ b/arch/powerpc/boot/ppcboot.h
@@ -0,0 +1,108 @@
+/*
+ * This interface is used for compatibility with old U-boots *ONLY*.
+ * Please do not imitate or extend this.
+ */
+
+/*
+ * (C) Copyright 2000, 2001
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __PPCBOOT_H__
+#define __PPCBOOT_H__
+
+/*
+ * Board information passed to kernel from PPCBoot
+ *
+ * include/asm-ppc/ppcboot.h
+ */
+
+#include "types.h"
+
+typedef struct bd_info {
+ unsigned long bi_memstart; /* start of DRAM memory */
+ unsigned long bi_memsize; /* size of DRAM memory in bytes */
+ unsigned long bi_flashstart; /* start of FLASH memory */
+ unsigned long bi_flashsize; /* size of FLASH memory */
+ unsigned long bi_flashoffset; /* reserved area for startup monitor */
+ unsigned long bi_sramstart; /* start of SRAM memory */
+ unsigned long bi_sramsize; /* size of SRAM memory */
+#if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\
+ defined(TARGET_83xx)
+ unsigned long bi_immr_base; /* base of IMMR register */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+ unsigned long bi_mbar_base; /* base of internal registers */
+#endif
+ unsigned long bi_bootflags; /* boot / reboot flag (for LynxOS) */
+ unsigned long bi_ip_addr; /* IP Address */
+ unsigned char bi_enetaddr[6]; /* Ethernet address */
+ unsigned short bi_ethspeed; /* Ethernet speed in Mbps */
+ unsigned long bi_intfreq; /* Internal Freq, in MHz */
+ unsigned long bi_busfreq; /* Bus Freq, in MHz */
+#if defined(TARGET_CPM2)
+ unsigned long bi_cpmfreq; /* CPM_CLK Freq, in MHz */
+ unsigned long bi_brgfreq; /* BRG_CLK Freq, in MHz */
+ unsigned long bi_sccfreq; /* SCC_CLK Freq, in MHz */
+ unsigned long bi_vco; /* VCO Out from PLL, in MHz */
+#endif
+#if defined(TARGET_PPC_MPC52xx)
+ unsigned long bi_ipbfreq; /* IPB Bus Freq, in MHz */
+ unsigned long bi_pcifreq; /* PCI Bus Freq, in MHz */
+#endif
+ unsigned long bi_baudrate; /* Console Baudrate */
+#if defined(TARGET_4xx)
+ unsigned char bi_s_version[4]; /* Version of this structure */
+ unsigned char bi_r_version[32]; /* Version of the ROM (IBM) */
+ unsigned int bi_procfreq; /* CPU (Internal) Freq, in Hz */
+ unsigned int bi_plb_busfreq; /* PLB Bus speed, in Hz */
+ unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
+ unsigned char bi_pci_enetaddr[6]; /* PCI Ethernet MAC address */
+#endif
+#if defined(TARGET_HYMOD)
+ hymod_conf_t bi_hymod_conf; /* hymod configuration information */
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \
+ defined(TARGET_85xx) || defined(TARGET_83xx)
+ /* second onboard ethernet port */
+ unsigned char bi_enet1addr[6];
+#define HAVE_ENET1ADDR
+#endif
+#if defined(TARGET_EVB64260) || defined(TARGET_440GX) || defined(TARGET_85xx)
+ /* third onboard ethernet ports */
+ unsigned char bi_enet2addr[6];
+#define HAVE_ENET2ADDR
+#endif
+#if defined(TARGET_440GX)
+ /* fourth onboard ethernet ports */
+ unsigned char bi_enet3addr[6];
+#define HAVE_ENET3ADDR
+#endif
+#if defined(TARGET_4xx)
+ unsigned int bi_opbfreq; /* OB clock in Hz */
+ int bi_iic_fast[2]; /* Use fast i2c mode */
+#endif
+#if defined(TARGET_440GX)
+ int bi_phynum[4]; /* phy mapping */
+ int bi_phymode[4]; /* phy mode */
+#endif
+} bd_t;
+
+#define bi_tbfreq bi_intfreq
+
+#endif /* __PPCBOOT_H__ */
diff --git a/arch/powerpc/boot/reg.h b/arch/powerpc/boot/reg.h
new file mode 100644
index 00000000000..d3cd9ee98af
--- /dev/null
+++ b/arch/powerpc/boot/reg.h
@@ -0,0 +1,22 @@
+#ifndef _PPC_BOOT_REG_H
+#define _PPC_BOOT_REG_H
+/*
+ * Copyright 2007 Davud Gibson, IBM Corporation.
+ *
+ * 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.
+ */
+
+static inline u32 mfpvr(void)
+{
+ u32 pvr;
+ asm volatile ("mfpvr %0" : "=r"(pvr));
+ return pvr;
+}
+
+register void *__stack_pointer asm("r1");
+#define get_sp() (__stack_pointer)
+
+#endif /* _PPC_BOOT_REG_H */
diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c
index cfe3a7505ba..65ec135d015 100644
--- a/arch/powerpc/boot/simple_alloc.c
+++ b/arch/powerpc/boot/simple_alloc.c
@@ -19,24 +19,24 @@
#define ENTRY_IN_USE 0x02
static struct alloc_info {
- u32 flags;
- u32 base;
- u32 size;
+ unsigned long flags;
+ unsigned long base;
+ unsigned long size;
} *alloc_tbl;
-static u32 tbl_entries;
-static u32 alloc_min;
-static u32 next_base;
-static u32 space_left;
+static unsigned long tbl_entries;
+static unsigned long alloc_min;
+static unsigned long next_base;
+static unsigned long space_left;
/*
* First time an entry is used, its base and size are set.
* An entry can be freed and re-malloc'd but its base & size don't change.
* Should be smart enough for needs of bootwrapper.
*/
-static void *simple_malloc(u32 size)
+static void *simple_malloc(unsigned long size)
{
- u32 i;
+ unsigned long i;
struct alloc_info *p = alloc_tbl;
if (size == 0)
@@ -67,13 +67,14 @@ err_out:
static struct alloc_info *simple_find_entry(void *ptr)
{
- u32 i;
+ unsigned long i;
struct alloc_info *p = alloc_tbl;
for (i=0; i<tbl_entries; i++,p++) {
if (!(p->flags & ENTRY_BEEN_USED))
break;
- if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr))
+ if ((p->flags & ENTRY_IN_USE) &&
+ (p->base == (unsigned long)ptr))
return p;
}
return NULL;
@@ -122,10 +123,10 @@ static void *simple_realloc(void *ptr, unsigned long size)
* Returns addr of first byte after heap so caller can see if it took
* too much space. If so, change args & try again.
*/
-void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
- u32 max_allocs)
+void *simple_alloc_init(char *base, unsigned long heap_size,
+ unsigned long granularity, unsigned long max_allocs)
{
- u32 heap_base, tbl_size;
+ unsigned long heap_base, tbl_size;
heap_size = _ALIGN_UP(heap_size, granularity);
alloc_min = granularity;
@@ -136,7 +137,7 @@ void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8);
memset(alloc_tbl, 0, tbl_size);
- heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min);
+ heap_base = _ALIGN_UP((unsigned long)alloc_tbl + tbl_size, alloc_min);
next_base = heap_base;
space_left = heap_size;
diff --git a/arch/powerpc/boot/stdio.h b/arch/powerpc/boot/stdio.h
index 73b8a91bfb3..adffc58412d 100644
--- a/arch/powerpc/boot/stdio.h
+++ b/arch/powerpc/boot/stdio.h
@@ -7,11 +7,12 @@
#define EINVAL 22 /* Invalid argument */
#define ENOSPC 28 /* No space left on device */
-extern int printf(const char *fmt, ...);
+extern int printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
#define fprintf(fmt, args...) printf(args)
-extern int sprintf(char *buf, const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
extern int vsprintf(char *buf, const char *fmt, va_list args);
diff --git a/arch/powerpc/boot/treeboot-ebony.c b/arch/powerpc/boot/treeboot-ebony.c
new file mode 100644
index 00000000000..8436a9c5519
--- /dev/null
+++ b/arch/powerpc/boot/treeboot-ebony.c
@@ -0,0 +1,34 @@
+/*
+ * Old U-boot compatibility for Ebony
+ *
+ * Author: David Gibson <david@gibson.dropbear.id.au>
+ *
+ * Copyright 2007 David Gibson, IBM Corporatio.
+ * Based on cuboot-83xx.c, which is:
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * 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 "ops.h"
+#include "stdio.h"
+#include "44x.h"
+
+extern char _end[];
+
+BSS_STACK(4096);
+
+#define OPENBIOS_MAC_BASE 0xfffffe0c
+#define OPENBIOS_MAC_OFFSET 0xc
+
+void platform_init(void)
+{
+ unsigned long end_of_ram = 0x8000000;
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ simple_alloc_init(_end, avail_ram, 32, 64);
+ ebony_init((u8 *)OPENBIOS_MAC_BASE,
+ (u8 *)(OPENBIOS_MAC_BASE + OPENBIOS_MAC_OFFSET));
+}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 024e4d425c5..2ed8b8b3f0e 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -29,6 +29,7 @@ initrd=
dtb=
dts=
cacheit=
+gzip=.gz
# cross-compilation prefix
CROSS=
@@ -42,7 +43,7 @@ tmpdir=.
usage() {
echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2
echo ' [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2
- echo ' [-D datadir] [-W workingdir] [vmlinux]' >&2
+ echo ' [-D datadir] [-W workingdir] [--no-gzip] [vmlinux]' >&2
exit 1
}
@@ -91,6 +92,9 @@ while [ "$#" -gt 0 ]; do
[ "$#" -gt 0 ] || usage
tmpdir="$1"
;;
+ --no-gzip)
+ gzip=
+ ;;
-?)
usage
;;
@@ -137,31 +141,43 @@ miboot|uboot)
ksection=image
isection=initrd
;;
+cuboot*)
+ gzip=
+ ;;
esac
vmz="$tmpdir/`basename \"$kernel\"`.$ext"
-if [ -z "$cacheit" -o ! -f "$vmz.gz" -o "$vmz.gz" -ot "$kernel" ]; then
+if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then
${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
- gzip -f -9 "$vmz.$$"
+
+ if [ -n "$gzip" ]; then
+ gzip -f -9 "$vmz.$$"
+ fi
+
if [ -n "$cacheit" ]; then
- mv -f "$vmz.$$.gz" "$vmz.gz"
+ mv -f "$vmz.$$$gzip" "$vmz$gzip"
else
vmz="$vmz.$$"
fi
fi
+vmz="$vmz$gzip"
+
+# Extract kernel version information, some platforms want to include
+# it in the image header
+version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
+ cut -d' ' -f3`
+if [ -n "$version" ]; then
+ uboot_version="-n Linux-$version"
+fi
+
case "$platform" in
uboot)
rm -f "$ofile"
- version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
- cut -d' ' -f3`
- if [ -n "$version" ]; then
- version="-n Linux-$version"
- fi
mkimage -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \
- $version -d "$vmz.gz" "$ofile"
+ $uboot_version -d "$vmz" "$ofile"
if [ -z "$cacheit" ]; then
- rm -f $vmz.gz
+ rm -f "$vmz"
fi
exit 0
;;
@@ -173,9 +189,9 @@ addsec() {
--set-section-flags=$3=contents,alloc,load,readonly,data
}
-addsec $tmp "$vmz.gz" $ksection $object/empty.o
+addsec $tmp "$vmz" $ksection $object/empty.o
if [ -z "$cacheit" ]; then
- rm -f "$vmz.gz"
+ rm -f "$vmz"
fi
if [ -n "$initrd" ]; then
@@ -191,17 +207,36 @@ fi
if [ "$platform" != "miboot" ]; then
${CROSS}ld -m elf32ppc -T $lds -o "$ofile" \
- $object/crt0.o $platformo $tmp $object/wrapper.a
+ $platformo $tmp $object/wrapper.a
rm $tmp
fi
+# Some platforms need the zImage's entry point and base address
+base=0x`${CROSS}nm "$ofile" | grep ' _start$' | cut -d' ' -f1`
+entry=`${CROSS}objdump -f "$ofile" | grep '^start address ' | cut -d' ' -f3`
+
# post-processing needed for some platforms
case "$platform" in
pseries|chrp)
$object/addnote "$ofile"
;;
pmaccoff)
- ${CROSS}objcopy -O aixcoff-rs6000 --set-start 0x500000 "$ofile"
+ ${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile"
$object/hack-coff "$ofile"
;;
+cuboot*)
+ mv "$ofile" "$ofile".elf
+ ${CROSS}objcopy -O binary "$ofile".elf "$ofile".bin
+ gzip -f -9 "$ofile".bin
+ mkimage -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \
+ $uboot_version -d "$ofile".bin.gz "$ofile"
+ ;;
+treeboot*)
+ mv "$ofile" "$ofile.elf"
+ $object/mktree "$ofile.elf" "$ofile" "$base" "$entry"
+ if [ -z "$cacheit" ]; then
+ rm -f "$ofile.elf"
+ fi
+ exit 0
+ ;;
esac
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S
index a360905e542..fe87a90ce7f 100644
--- a/arch/powerpc/boot/zImage.coff.lds.S
+++ b/arch/powerpc/boot/zImage.coff.lds.S
@@ -1,5 +1,6 @@
OUTPUT_ARCH(powerpc:common)
-ENTRY(_start)
+ENTRY(_zimage_start_opd)
+EXTERN(_zimage_start_opd)
SECTIONS
{
. = (5*1024*1024);
diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
index 4be3c6414b0..f6e380fdb38 100644
--- a/arch/powerpc/boot/zImage.lds.S
+++ b/arch/powerpc/boot/zImage.lds.S
@@ -1,5 +1,6 @@
OUTPUT_ARCH(powerpc:common)
ENTRY(_zimage_start)
+EXTERN(_zimage_start)
SECTIONS
{
. = (4*1024*1024);
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index cf7e316ad4f..6061e5f7696 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Fri Mar 9 23:34:53 2007
+# Linux kernel version: 2.6.21-rc6
+# Mon Apr 23 20:46:48 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -139,11 +139,31 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
# CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELLEB=y
+CONFIG_PPC_PS3=y
+
+#
+# PS3 Platform Options
+#
+# CONFIG_PS3_ADVANCED is not set
+CONFIG_PS3_HTAB_SIZE=20
+# CONFIG_PS3_DYNAMIC_DMA is not set
+CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
+CONFIG_PS3_PS3AV=y
+CONFIG_PS3_SYS_MANAGER=y
CONFIG_PPC_CELL=y
CONFIG_PPC_CELL_NATIVE=y
CONFIG_PPC_IBM_CELL_BLADE=y
-CONFIG_PPC_PS3=y
-CONFIG_PPC_CELLEB=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=m
+CONFIG_SPU_BASE=y
+CONFIG_CBE_RAS=y
+CONFIG_CBE_THERM=m
+CONFIG_CBE_CPUFREQ=m
CONFIG_PPC_NATIVE=y
CONFIG_UDBG_RTAS_CONSOLE=y
CONFIG_PPC_UDBG_BEAT=y
@@ -175,26 +195,6 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_MPIC=y
#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=m
-CONFIG_SPU_BASE=y
-CONFIG_CBE_RAS=y
-CONFIG_CBE_THERM=m
-CONFIG_CBE_CPUFREQ=m
-
-#
-# PS3 Platform Options
-#
-# CONFIG_PS3_ADVANCED is not set
-CONFIG_PS3_HTAB_SIZE=20
-# CONFIG_PS3_DYNAMIC_DMA is not set
-CONFIG_PS3_USE_LPAR_ADDR=y
-CONFIG_PS3_VUART=y
-CONFIG_PS3_PS3AV=y
-CONFIG_PS3_SYS_MANAGER=y
-
-#
# Kernel options
#
# CONFIG_HZ_100 is not set
@@ -534,7 +534,6 @@ CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
CONFIG_BLK_DEV_AEC62XX=y
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -561,11 +560,10 @@ CONFIG_BLK_DEV_SIIMAGE=y
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_BLK_DEV_TC86C001 is not set
-CONFIG_BLK_DEV_IDE_CELLEB=y
+CONFIG_BLK_DEV_CELLEB=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -937,7 +935,7 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_HVC_DRIVER=y
CONFIG_HVC_RTAS=y
-# CONFIG_HVC_BEAT is not set
+CONFIG_HVC_BEAT=y
#
# IPMI
@@ -1482,6 +1480,8 @@ CONFIG_NLS_ISO8859_15=m
# Distributed Lock Manager
#
# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
#
# Library routines
@@ -1540,6 +1540,7 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_FAULT_INJECTION is not set
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
diff --git a/arch/powerpc/configs/ebony_defconfig b/arch/powerpc/configs/ebony_defconfig
new file mode 100644
index 00000000000..c3b96ef3c2d
--- /dev/null
+++ b/arch/powerpc/configs/ebony_defconfig
@@ -0,0 +1,905 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21
+# Fri May 4 13:47:08 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_EBONY=y
+CONFIG_440GP=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPM2 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_SECCOMP=y
+CONFIG_WANT_DEVICE_TREE=y
+CONFIG_DEVICE_TREE="ebony.dts"
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+# CONFIG_PPC_INDIRECT_PCI_BE is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x01000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=35000
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+CONFIG_IBM_NEW_EMAC_ZMII=y
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 7724847f702..3ccf19d8da3 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -143,7 +143,7 @@ CONFIG_PPC_NATIVE=y
CONFIG_U3_DART=y
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
# CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/holly_defconfig b/arch/powerpc/configs/holly_defconfig
new file mode 100644
index 00000000000..be633b9b57c
--- /dev/null
+++ b/arch/powerpc/configs/holly_defconfig
@@ -0,0 +1,1070 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21
+# Sat May 5 11:02:35 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+
+#
+# Processor support
+#
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+# CONFIG_ALTIVEC is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Platform support
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+CONFIG_EMBEDDED6xx=y
+# CONFIG_APUS is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_LINKSTATION is not set
+# CONFIG_MPC7448HPC2 is not set
+CONFIG_PPC_HOLLY=y
+CONFIG_TSI108_BRIDGE=y
+CONFIG_MPIC=y
+CONFIG_MPIC_WEIRD=y
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_CPM2 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+# CONFIG_WANT_DEVICE_TREE is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_PPC_INDIRECT_PCI is not set
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_TSI108_ETH=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+# CONFIG_KPROBES is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_DEBUGGER=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+CONFIG_XMON_DISASSEMBLY=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index de97f2f0ae9..15366f0e489 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -146,7 +146,7 @@ CONFIG_PPC_RTAS=y
CONFIG_RTAS_PROC=y
# CONFIG_RTAS_FLASH is not set
# CONFIG_MMIO_NVRAM is not set
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
# CONFIG_PPC_MPC106 is not set
CONFIG_PPC_970_NAP=y
# CONFIG_PPC_INDIRECT_IO is not set
diff --git a/arch/powerpc/configs/mpc832x_mds_defconfig b/arch/powerpc/configs/mpc832x_mds_defconfig
index e1b36de6b38..83192c0dc5b 100644
--- a/arch/powerpc/configs/mpc832x_mds_defconfig
+++ b/arch/powerpc/configs/mpc832x_mds_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc5
-# Tue Jan 30 14:27:25 2007
+# Linux kernel version: 2.6.21-rc5
+# Mon Apr 9 16:09:16 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -34,9 +34,9 @@ CONFIG_DEFAULT_UIMAGE=y
CONFIG_PPC_83xx=y
# CONFIG_PPC_85xx is not set
# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
# CONFIG_40x is not set
# CONFIG_44x is not set
-# CONFIG_8xx is not set
# CONFIG_E200 is not set
CONFIG_6xx=y
CONFIG_83xx=y
@@ -63,6 +63,7 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
@@ -71,6 +72,7 @@ CONFIG_SYSVIPC=y
# CONFIG_IKCONFIG is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
@@ -123,16 +125,17 @@ CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_QUICC_ENGINE=y
-CONFIG_PPC_GEN550=y
# CONFIG_WANT_EARLY_SERIAL is not set
#
# Platform support
#
+# CONFIG_MPC8313_RDB is not set
CONFIG_MPC832x_MDS=y
-# CONFIG_MPC834x_SYS is not set
+# CONFIG_MPC832x_RDB is not set
+# CONFIG_MPC834x_MDS is not set
# CONFIG_MPC834x_ITX is not set
-# CONFIG_MPC8360E_PB is not set
+# CONFIG_MPC836x_MDS is not set
CONFIG_PPC_MPC832x=y
# CONFIG_MPIC is not set
@@ -163,6 +166,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
# CONFIG_PM is not set
@@ -172,6 +176,7 @@ CONFIG_ISA_DMA_API=y
#
# Bus options
#
+CONFIG_ZONE_DMA=y
CONFIG_GENERIC_ISA_DMA=y
# CONFIG_MPIC_WEIRD is not set
# CONFIG_PPC_I8259 is not set
@@ -220,6 +225,7 @@ CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -324,6 +330,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -342,7 +349,6 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=32768
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -482,7 +488,21 @@ CONFIG_NETDEVICES=y
#
# PHY device support
#
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+CONFIG_DAVICOM_PHY=y
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
#
# Ethernet (10 or 100Mbit)
@@ -524,11 +544,13 @@ CONFIG_UCC_GETH=y
# CONFIG_UGETH_FILTERING is not set
# CONFIG_UGETH_TX_ON_DEMOND is not set
# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
@@ -621,6 +643,7 @@ CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -691,6 +714,7 @@ CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PASEMI is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_I2C_SIS5595 is not set
@@ -738,6 +762,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
@@ -779,6 +804,11 @@ CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -791,10 +821,9 @@ CONFIG_HWMON=y
#
# Graphics support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
# CONFIG_FB is not set
# CONFIG_FB_IBM_GXT4500 is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -805,6 +834,7 @@ CONFIG_FIRMWARE_EDID=y
# HID Devices
#
CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
#
# USB support
@@ -869,6 +899,10 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Auxiliary Display support
+#
+
+#
# Virtualization
#
@@ -995,11 +1029,7 @@ CONFIG_PARTITION_ADVANCED=y
# Distributed Lock Manager
#
# CONFIG_DLM is not set
-
-#
-# QE Options
-#
-CONFIG_UCC_SLOW=y
+# CONFIG_UCC_SLOW is not set
CONFIG_UCC_FAST=y
CONFIG_UCC=y
@@ -1012,7 +1042,8 @@ CONFIG_BITREVERSE=y
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
#
# Instrumentation Support
@@ -1032,7 +1063,6 @@ CONFIG_ENABLE_MUST_CHECK=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_BOOTX_TEXT is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
# CONFIG_PPC_EARLY_DEBUG is not set
#
@@ -1061,8 +1091,10 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
@@ -1076,6 +1108,7 @@ CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
#
diff --git a/arch/powerpc/configs/mpc832x_rdb_defconfig b/arch/powerpc/configs/mpc832x_rdb_defconfig
new file mode 100644
index 00000000000..4a4da875fa4
--- /dev/null
+++ b/arch/powerpc/configs/mpc832x_rdb_defconfig
@@ -0,0 +1,1300 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc5
+# Mon Apr 9 16:12:43 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_QUICC_ENGINE=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8313_RDB is not set
+# CONFIG_MPC832x_MDS is not set
+CONFIG_MPC832x_RDB=y
+# CONFIG_MPC834x_MDS is not set
+# CONFIG_MPC834x_ITX is not set
+# CONFIG_MPC836x_MDS is not set
+CONFIG_PPC_MPC832x=y
+# CONFIG_MPIC is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+CONFIG_ICPLUS_PHY=y
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_GIANFAR is not set
+CONFIG_UCC_GETH=y
+CONFIG_UGETH_NAPI=y
+# CONFIG_UGETH_MAGIC_PACKET is not set
+# CONFIG_UGETH_FILTERING is not set
+# CONFIG_UGETH_TX_ON_DEMOND is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_83xx_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PASEMI is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+# CONFIG_USB_OHCI_HCD_PPC_OF_LE is not set
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+CONFIG_NLS_ISO8859_8=y
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/mpc836x_mds_defconfig b/arch/powerpc/configs/mpc836x_mds_defconfig
index 8eb475cd0df..921a151dc77 100644
--- a/arch/powerpc/configs/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/mpc836x_mds_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Sat Feb 17 10:09:26 2007
+# Linux kernel version: 2.6.21-rc5
+# Mon Apr 9 16:14:05 2007
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -72,6 +72,7 @@ CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_IKCONFIG is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
@@ -124,7 +125,6 @@ CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_QUICC_ENGINE=y
-CONFIG_PPC_GEN550=y
# CONFIG_WANT_EARLY_SERIAL is not set
#
@@ -132,6 +132,7 @@ CONFIG_PPC_GEN550=y
#
# CONFIG_MPC8313_RDB is not set
# CONFIG_MPC832x_MDS is not set
+# CONFIG_MPC832x_RDB is not set
# CONFIG_MPC834x_MDS is not set
# CONFIG_MPC834x_ITX is not set
CONFIG_MPC836x_MDS=y
@@ -328,6 +329,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -346,7 +348,6 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=32768
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -486,7 +487,21 @@ CONFIG_NETDEVICES=y
#
# PHY device support
#
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_FIXED_PHY is not set
#
# Ethernet (10 or 100Mbit)
@@ -528,6 +543,7 @@ CONFIG_UCC_GETH=y
# CONFIG_UGETH_FILTERING is not set
# CONFIG_UGETH_TX_ON_DEMOND is not set
# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
#
# Ethernet (10000 Mbit)
@@ -745,6 +761,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
@@ -786,6 +803,11 @@ CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -798,10 +820,9 @@ CONFIG_HWMON=y
#
# Graphics support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
# CONFIG_FB is not set
# CONFIG_FB_IBM_GXT4500 is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -1007,11 +1028,7 @@ CONFIG_PARTITION_ADVANCED=y
# Distributed Lock Manager
#
# CONFIG_DLM is not set
-
-#
-# QE Options
-#
-CONFIG_UCC_SLOW=y
+# CONFIG_UCC_SLOW is not set
CONFIG_UCC_FAST=y
CONFIG_UCC=y
@@ -1045,7 +1062,6 @@ CONFIG_ENABLE_MUST_CHECK=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_BOOTX_TEXT is not set
-# CONFIG_SERIAL_TEXT_DEBUG is not set
# CONFIG_PPC_EARLY_DEBUG is not set
#
diff --git a/arch/powerpc/configs/mpc8544_ds_defconfig b/arch/powerpc/configs/mpc8544_ds_defconfig
new file mode 100644
index 00000000000..b563513cc96
--- /dev/null
+++ b/arch/powerpc/configs/mpc8544_ds_defconfig
@@ -0,0 +1,1077 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 19 17:18:49 2007
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+# CONFIG_SPE is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_IPC_NS=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+CONFIG_MPC8544_DS=y
+CONFIG_MPC85xx=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+CONFIG_MPIC=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_MATH_EMULATION=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="root=/dev/sda3 rw console=ttyS0,115200"
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+# CONFIG_MAC_EMUMOUSEBTN is not set
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+CONFIG_VITESSE_PHY=y
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+CONFIG_GEN_RTC_X=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+CONFIG_DVB=y
+CONFIG_DVB_CORE=m
+# CONFIG_DVB_CORE_ATTACH is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+
+#
+# DVB-T (terrestrial) frontends
+#
+
+#
+# DVB-C (cable) frontends
+#
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+
+#
+# Tuners/PLL support
+#
+
+#
+# Miscellaneous devices
+#
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+# CONFIG_FB_IBM_GXT4500 is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_ECB is not set
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index a8da0aea3b8..126b9f87df2 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -152,7 +152,7 @@ CONFIG_RTAS_ERROR_LOGGING=y
CONFIG_RTAS_PROC=y
CONFIG_RTAS_FLASH=m
CONFIG_MMIO_NVRAM=y
-CONFIG_MPIC_BROKEN_U3=y
+CONFIG_MPIC_U3_HT_IRQS=y
CONFIG_IBMVIO=y
# CONFIG_IBMEBUS is not set
# CONFIG_PPC_MPC106 is not set
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 0345a2ceec5..fd604968f9a 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc6
-# Thu Jan 25 13:35:34 2007
+# Linux kernel version: 2.6.21
+# Mon Apr 30 12:03:35 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -60,6 +60,7 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
@@ -69,6 +70,7 @@ CONFIG_SYSVIPC=y
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
@@ -131,13 +133,36 @@ CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_ISERIES is not set
# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
# CONFIG_PPC_PASEMI is not set
+# CONFIG_PPC_CELLEB is not set
+CONFIG_PPC_PS3=y
+
+#
+# PS3 Platform Options
+#
+# CONFIG_PS3_ADVANCED is not set
+CONFIG_PS3_HTAB_SIZE=20
+# CONFIG_PS3_DYNAMIC_DMA is not set
+CONFIG_PS3_USE_LPAR_ADDR=y
+CONFIG_PS3_VUART=y
+CONFIG_PS3_PS3AV=y
+CONFIG_PS3_SYS_MANAGER=y
CONFIG_PPC_CELL=y
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_IBM_CELL_BLADE is not set
-CONFIG_PPC_PS3=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=y
+CONFIG_SPU_BASE=y
+# CONFIG_PQ2ADS is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
# CONFIG_U3_DART is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
@@ -146,24 +171,7 @@ CONFIG_PPC_PS3=y
# CONFIG_PPC_INDIRECT_IO is not set
# CONFIG_GENERIC_IOMAP is not set
# CONFIG_CPU_FREQ is not set
-# CONFIG_WANT_EARLY_SERIAL is not set
-# CONFIG_MPIC is not set
-
-#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=y
-CONFIG_SPU_BASE=y
-# CONFIG_CBE_RAS is not set
-
-#
-# PS3 Platform Options
-#
-CONFIG_PS3_HTAB_SIZE=20
-# CONFIG_PS3_DYNAMIC_DMA is not set
-CONFIG_PS3_USE_LPAR_ADDR=y
-CONFIG_PS3_VUART=y
-CONFIG_PS3_PS3AV=y
+# CONFIG_CPM2 is not set
#
# Kernel options
@@ -179,10 +187,10 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_BKL is not set
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
-CONFIG_FORCE_MAX_ZONEORDER=9
+CONFIG_FORCE_MAX_ZONEORDER=13
# CONFIG_IOMMU_VMERGE is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-# CONFIG_KEXEC is not set
+CONFIG_KEXEC=y
# CONFIG_CRASH_DUMP is not set
# CONFIG_IRQ_ALL_CPUS is not set
# CONFIG_NUMA is not set
@@ -203,22 +211,22 @@ CONFIG_MEMORY_HOTPLUG=y
CONFIG_MEMORY_HOTPLUG_SPARSE=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
CONFIG_ARCH_MEMORY_PROBE=y
-CONFIG_PPC_64K_PAGES=y
+# CONFIG_PPC_64K_PAGES is not set
# CONFIG_SCHED_SMT is not set
CONFIG_PROC_DEVICETREE=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="root=/dev/sda1 ip=dhcp"
+# CONFIG_CMDLINE_BOOL is not set
# CONFIG_PM is not set
# CONFIG_SECCOMP is not set
+# CONFIG_WANT_DEVICE_TREE is not set
CONFIG_ISA_DMA_API=y
#
# Bus options
#
+CONFIG_ZONE_DMA=y
CONFIG_GENERIC_ISA_DMA=y
-# CONFIG_MPIC_WEIRD is not set
-# CONFIG_PPC_I8259 is not set
# CONFIG_PCI is not set
# CONFIG_PCI_DOMAINS is not set
@@ -240,10 +248,13 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -261,7 +272,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
@@ -270,9 +281,23 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -313,7 +338,31 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_NET_PKTGEN is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
-# CONFIG_BT is not set
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+# CONFIG_BT_RFCOMM_TTY is not set
+# CONFIG_BT_BNEP is not set
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+CONFIG_BT_HCIUSB_SCO=y
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
# CONFIG_IEEE80211 is not set
#
@@ -327,16 +376,13 @@ CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -347,24 +393,27 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
#
# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_UB is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=65535
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
#
# Misc devices
#
-# CONFIG_TIFM_CORE is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -388,7 +437,7 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_OSST is not set
CONFIG_BLK_DEV_SR=y
# CONFIG_BLK_DEV_SR_VENDOR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_SG=m
# CONFIG_CHR_DEV_SCH is not set
#
@@ -413,6 +462,7 @@ CONFIG_BLK_DEV_SR=y
#
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
@@ -460,7 +510,7 @@ CONFIG_NETDEVICES=y
# Ethernet (10 or 100Mbit)
#
# CONFIG_NET_ETHERNET is not set
-CONFIG_MII=y
+CONFIG_MII=m
#
# Ethernet (1000 Mbit)
@@ -475,9 +525,10 @@ CONFIG_MII=y
#
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
@@ -551,7 +602,8 @@ CONFIG_HW_CONSOLE=y
# Non-8250 serial port support
#
CONFIG_UNIX98_PTYS=y
-# CONFIG_LEGACY_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
#
# IPMI
@@ -598,6 +650,11 @@ CONFIG_GEN_RTC=y
# CONFIG_HWMON_VID is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -611,15 +668,22 @@ CONFIG_GEN_RTC=y
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
# CONFIG_FB_OF is not set
# CONFIG_FB_VGA16 is not set
# CONFIG_FB_S1D13XXX is not set
@@ -634,7 +698,7 @@ CONFIG_FB_PS3_DEFAULT_SIZE_M=18
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
@@ -646,17 +710,62 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
#
-# CONFIG_SOUND is not set
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA PowerMac devices
+#
+
+#
+# ALSA PowerMac requires I2C
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+
+#
+# SoC audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
#
# HID Devices
#
CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
#
# USB support
@@ -665,13 +774,13 @@ CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_USB=y
-CONFIG_USB_DEBUG=y
+# CONFIG_USB_DEBUG is not set
#
# Miscellaneous USB options
#
-# CONFIG_USB_DEVICEFS is not set
-# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
@@ -704,7 +813,7 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
#
# may also be needed; see USB_STORAGE Help for more information
#
-CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE=m
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
@@ -720,10 +829,16 @@ CONFIG_USB_STORAGE=y
#
# USB Input Devices
#
-CONFIG_USB_HID=y
+CONFIG_USB_HID=m
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_ACECAD is not set
@@ -736,6 +851,7 @@ CONFIG_USB_HID=y
# CONFIG_USB_ATI_REMOTE2 is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
#
# USB Imaging devices
@@ -748,15 +864,16 @@ CONFIG_USB_HID=y
#
# CONFIG_USB_CATC is not set
# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
+CONFIG_USB_PEGASUS=m
# CONFIG_USB_RTL8150 is not set
-CONFIG_USB_USBNET_MII=y
-CONFIG_USB_USBNET=y
-CONFIG_USB_NET_CDCETHER=y
+CONFIG_USB_USBNET_MII=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_DM9601 is not set
# CONFIG_USB_NET_GL620A is not set
# CONFIG_USB_NET_NET1080 is not set
# CONFIG_USB_NET_PLUSB is not set
-CONFIG_USB_NET_MCS7830=y
+CONFIG_USB_NET_MCS7830=m
# CONFIG_USB_NET_RNDIS_HOST is not set
# CONFIG_USB_NET_CDC_SUBSET is not set
# CONFIG_USB_NET_ZAURUS is not set
@@ -781,6 +898,7 @@ CONFIG_USB_MON=y
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
@@ -791,6 +909,8 @@ CONFIG_USB_MON=y
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
#
# USB DSL modem support
@@ -846,13 +966,19 @@ CONFIG_USB_MON=y
#
#
+# Auxiliary Display support
+#
+
+#
# Virtualization
#
#
# File systems
#
-# CONFIG_EXT2_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -871,27 +997,30 @@ CONFIG_FS_MBCACHE=y
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
+CONFIG_QUOTA=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
#
-CONFIG_ISO9660_FS=y
+CONFIG_ISO9660_FS=m
CONFIG_JOLIET=y
# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=y
+CONFIG_UDF_FS=m
CONFIG_UDF_NLS=y
#
# DOS/FAT/NT Filesystems
#
-CONFIG_FAT_FS=y
+CONFIG_FAT_FS=m
# CONFIG_MSDOS_FS is not set
-CONFIG_VFAT_FS=y
+CONFIG_VFAT_FS=m
CONFIG_FAT_DEFAULT_CODEPAGE=437
CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
# CONFIG_NTFS_FS is not set
@@ -933,7 +1062,7 @@ CONFIG_RAMFS=y
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
+CONFIG_NFS_V4=y
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
@@ -941,10 +1070,16 @@ CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -1004,6 +1139,8 @@ CONFIG_NLS_ISO8859_1=y
# Distributed Lock Manager
#
# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
#
# Library routines
@@ -1014,7 +1151,8 @@ CONFIG_BITREVERSE=y
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
#
# Instrumentation Support
@@ -1032,16 +1170,16 @@ CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
CONFIG_LOG_BUF_SHIFT=17
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-CONFIG_DEBUG_SLAB=y
-# CONFIG_DEBUG_SLAB_LEAK is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
CONFIG_DEBUG_SPINLOCK=y
CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_RWSEMS=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1051,8 +1189,10 @@ CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_LIST=y
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
# CONFIG_DEBUGGER is not set
CONFIG_IRQSTACKS=y
# CONFIG_BOOTX_TEXT is not set
@@ -1063,6 +1203,8 @@ CONFIG_PPC_EARLY_DEBUG=y
# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
+# CONFIG_PPC_EARLY_DEBUG_BEAT is not set
#
# Security options
@@ -1073,4 +1215,43 @@ CONFIG_PPC_EARLY_DEBUG=y
#
# Cryptographic options
#
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 8120d428ebf..3e779f07f21 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -25,8 +25,8 @@ obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o
procfs-$(CONFIG_PPC64) := proc_ppc64.o
obj-$(CONFIG_PROC_FS) += $(procfs-y)
-rtaspci-$(CONFIG_PPC64) := rtas_pci.o
-obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y)
+rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o
+obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y)
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
obj-$(CONFIG_RTAS_PROC) += rtas-proc.o
obj-$(CONFIG_LPARCFG) += lparcfg.o
@@ -36,7 +36,9 @@ obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
obj-$(CONFIG_TAU) += tau_6xx.o
+obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o suspend.o
obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
+obj64-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_64.o swsusp_asm64.o
obj32-$(CONFIG_MODULES) += module_32.o
ifeq ($(CONFIG_PPC_MERGE),y)
@@ -66,6 +68,7 @@ obj-$(CONFIG_MODULES) += $(module-y)
pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o
pci32-$(CONFIG_PPC32) := pci_32.o
obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
+obj-$(CONFIG_PCI_MSI) += msi.o
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
kexec-$(CONFIG_PPC32) := machine_kexec_32.o
obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o $(kexec-y)
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index 4734b5de599..5c9ff7f5c44 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -241,7 +241,7 @@ static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
return -EFAULT;
for (i = 0; i < size / sizeof(long); ++i)
- if (__put_user(0, p+i))
+ if (__put_user_inatomic(0, p+i))
return -EFAULT;
return 1;
}
@@ -288,7 +288,8 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
} else {
unsigned long pc = regs->nip ^ (swiz & 4);
- if (__get_user(instr, (unsigned int __user *)pc))
+ if (__get_user_inatomic(instr,
+ (unsigned int __user *)pc))
return -EFAULT;
if (swiz == 0 && (flags & SW))
instr = cpu_to_le32(instr);
@@ -324,27 +325,31 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
((nb0 + 3) / 4) * sizeof(unsigned long));
for (i = 0; i < nb; ++i, ++p)
- if (__get_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+ if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
if (nb0 > 0) {
rptr = &regs->gpr[0];
addr += nb;
for (i = 0; i < nb0; ++i, ++p)
- if (__get_user(REG_BYTE(rptr, i ^ bswiz),
- SWIZ_PTR(p)))
+ if (__get_user_inatomic(REG_BYTE(rptr,
+ i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
}
} else {
for (i = 0; i < nb; ++i, ++p)
- if (__put_user(REG_BYTE(rptr, i ^ bswiz), SWIZ_PTR(p)))
+ if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
if (nb0 > 0) {
rptr = &regs->gpr[0];
addr += nb;
for (i = 0; i < nb0; ++i, ++p)
- if (__put_user(REG_BYTE(rptr, i ^ bswiz),
- SWIZ_PTR(p)))
+ if (__put_user_inatomic(REG_BYTE(rptr,
+ i ^ bswiz),
+ SWIZ_PTR(p)))
return -EFAULT;
}
}
@@ -398,7 +403,8 @@ int fix_alignment(struct pt_regs *regs)
if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
pc ^= 4;
- if (unlikely(__get_user(instr, (unsigned int __user *)pc)))
+ if (unlikely(__get_user_inatomic(instr,
+ (unsigned int __user *)pc)))
return -EFAULT;
if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
instr = cpu_to_le32(instr);
@@ -474,16 +480,16 @@ int fix_alignment(struct pt_regs *regs)
p = (unsigned long) addr;
switch (nb) {
case 8:
- ret |= __get_user(data.v[0], SWIZ_PTR(p++));
- ret |= __get_user(data.v[1], SWIZ_PTR(p++));
- ret |= __get_user(data.v[2], SWIZ_PTR(p++));
- ret |= __get_user(data.v[3], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++));
case 4:
- ret |= __get_user(data.v[4], SWIZ_PTR(p++));
- ret |= __get_user(data.v[5], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++));
case 2:
- ret |= __get_user(data.v[6], SWIZ_PTR(p++));
- ret |= __get_user(data.v[7], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++));
+ ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++));
if (unlikely(ret))
return -EFAULT;
}
@@ -551,16 +557,16 @@ int fix_alignment(struct pt_regs *regs)
p = (unsigned long) addr;
switch (nb) {
case 8:
- ret |= __put_user(data.v[0], SWIZ_PTR(p++));
- ret |= __put_user(data.v[1], SWIZ_PTR(p++));
- ret |= __put_user(data.v[2], SWIZ_PTR(p++));
- ret |= __put_user(data.v[3], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++));
case 4:
- ret |= __put_user(data.v[4], SWIZ_PTR(p++));
- ret |= __put_user(data.v[5], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++));
case 2:
- ret |= __put_user(data.v[6], SWIZ_PTR(p++));
- ret |= __put_user(data.v[7], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++));
+ ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++));
}
if (unlikely(ret))
return -EFAULT;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 030d300cd71..2cb1d948779 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -21,12 +21,12 @@
#include <linux/types.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/suspend.h>
#ifdef CONFIG_PPC64
#include <linux/time.h>
#include <linux/hardirq.h>
#else
#include <linux/ptrace.h>
-#include <linux/suspend.h>
#endif
#include <asm/io.h>
@@ -58,7 +58,7 @@ int main(void)
#ifdef CONFIG_PPC64
DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
#else
- DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+ DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
#endif /* CONFIG_PPC64 */
@@ -77,7 +77,6 @@ int main(void)
DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid));
#else /* CONFIG_PPC64 */
DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
- DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0));
DEFINE(PT_PTRACED, PT_PTRACED);
@@ -123,12 +122,18 @@ int main(void)
DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr));
DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id));
- DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
DEFINE(PACAVMALLOCSLLP, offsetof(struct paca_struct, vmalloc_sllp));
-#ifdef CONFIG_HUGETLB_PAGE
- DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas));
- DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas));
-#endif /* CONFIG_HUGETLB_PAGE */
+#ifdef CONFIG_PPC_MM_SLICES
+ DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct,
+ context.low_slices_psize));
+ DEFINE(PACAHIGHSLICEPSIZE, offsetof(struct paca_struct,
+ context.high_slices_psize));
+ DEFINE(MMUPSIZEDEFSIZE, sizeof(struct mmu_psize_def));
+ DEFINE(MMUPSIZESLLP, offsetof(struct mmu_psize_def, sllp));
+#else
+ DEFINE(PACACONTEXTSLLP, offsetof(struct paca_struct, context.sllp));
+
+#endif /* CONFIG_PPC_MM_SLICES */
DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen));
DEFINE(PACA_EXMC, offsetof(struct paca_struct, exmc));
DEFINE(PACA_EXSLB, offsetof(struct paca_struct, exslb));
@@ -140,6 +145,7 @@ int main(void)
DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
DEFINE(PACA_SLBSHADOWPTR, offsetof(struct paca_struct, slb_shadow_ptr));
DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset));
+ DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
DEFINE(SLBSHADOW_STACKVSID,
offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
@@ -257,11 +263,11 @@ int main(void)
DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore));
-#ifndef CONFIG_PPC64
DEFINE(pbe_address, offsetof(struct pbe, address));
DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
DEFINE(pbe_next, offsetof(struct pbe, next));
+#ifndef CONFIG_PPC64
DEFINE(TASK_SIZE, TASK_SIZE);
DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
#endif /* ! CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index 3678997339d..e7b684689e0 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -161,33 +161,33 @@ int btext_initialize(struct device_node *np)
unsigned long address = 0;
const u32 *prop;
- prop = get_property(np, "linux,bootx-width", NULL);
+ prop = of_get_property(np, "linux,bootx-width", NULL);
if (prop == NULL)
- prop = get_property(np, "width", NULL);
+ prop = of_get_property(np, "width", NULL);
if (prop == NULL)
return -EINVAL;
width = *prop;
- prop = get_property(np, "linux,bootx-height", NULL);
+ prop = of_get_property(np, "linux,bootx-height", NULL);
if (prop == NULL)
- prop = get_property(np, "height", NULL);
+ prop = of_get_property(np, "height", NULL);
if (prop == NULL)
return -EINVAL;
height = *prop;
- prop = get_property(np, "linux,bootx-depth", NULL);
+ prop = of_get_property(np, "linux,bootx-depth", NULL);
if (prop == NULL)
- prop = get_property(np, "depth", NULL);
+ prop = of_get_property(np, "depth", NULL);
if (prop == NULL)
return -EINVAL;
depth = *prop;
pitch = width * ((depth + 7) / 8);
- prop = get_property(np, "linux,bootx-linebytes", NULL);
+ prop = of_get_property(np, "linux,bootx-linebytes", NULL);
if (prop == NULL)
- prop = get_property(np, "linebytes", NULL);
+ prop = of_get_property(np, "linebytes", NULL);
if (prop && *prop != 0xffffffffu)
pitch = *prop;
if (pitch == 1)
pitch = 0x1000;
- prop = get_property(np, "address", NULL);
+ prop = of_get_property(np, "address", NULL);
if (prop)
address = *prop;
@@ -219,7 +219,7 @@ int __init btext_find_display(int allow_nonstdout)
struct device_node *np = NULL;
int rc = -ENODEV;
- name = get_property(of_chosen, "linux,stdout-path", NULL);
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name != NULL) {
np = of_find_node_by_path(name);
if (np != NULL) {
@@ -236,7 +236,7 @@ int __init btext_find_display(int allow_nonstdout)
return rc;
for (np = NULL; (np = of_find_node_by_type(np, "display"));) {
- if (get_property(np, "linux,opened", NULL)) {
+ if (of_get_property(np, "linux,opened", NULL)) {
printk("trying %s ...\n", np->full_name);
rc = btext_initialize(np);
printk("result: %d\n", rc);
diff --git a/arch/powerpc/kernel/cpu_setup_pa6t.S b/arch/powerpc/kernel/cpu_setup_pa6t.S
index 4047be25c4d..d62cb9cae4e 100644
--- a/arch/powerpc/kernel/cpu_setup_pa6t.S
+++ b/arch/powerpc/kernel/cpu_setup_pa6t.S
@@ -34,7 +34,7 @@ _GLOBAL(__setup_cpu_pa6t)
beqlr
mfspr r0,SPRN_HID5
- ori r0,r0,0x30
+ ori r0,r0,0x38
mtspr SPRN_HID5,r0
mfspr r0,SPRN_LPCR
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index e4006dc087c..9cb24d20f0f 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -389,6 +389,8 @@ static struct cpu_spec cpu_specs[] = {
.pmc_type = PPC_PMC_PA6T,
.cpu_setup = __setup_cpu_pa6t,
.cpu_restore = __restore_cpu_pa6t,
+ .oprofile_cpu_type = "ppc64/pa6t",
+ .oprofile_type = PPC_OPROFILE_PA6T,
.platform = "pa6t",
},
{ /* default match */
@@ -558,6 +560,18 @@ static struct cpu_spec cpu_specs[] = {
.cpu_setup = __setup_cpu_750cx,
.platform = "ppc750",
},
+ { /* 750CL */
+ .pvr_mask = 0xfffff0f0,
+ .pvr_value = 0x00087010,
+ .cpu_name = "750CL",
+ .cpu_features = CPU_FTRS_750CL,
+ .cpu_user_features = COMMON_USER | PPC_FEATURE_PPC_LE,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .num_pmcs = 4,
+ .cpu_setup = __setup_cpu_750,
+ .platform = "ppc750",
+ },
{ /* 745/755 */
.pvr_mask = 0xfffff000,
.pvr_value = 0x00083000,
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index c03e829fee3..c29d1652a42 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -191,7 +191,6 @@ stack_ovf:
0:
_GLOBAL(DoSyscall)
- stw r0,THREAD+LAST_SYSCALL(r2)
stw r3,ORIG_GPR3(r1)
li r12,0
stw r12,RESULT(r1)
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index a15d4b8cce4..88695963f58 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -120,8 +120,8 @@ skpinv: addi r4,r4,1 /* Increment */
* Configure and load pinned entry into TLB slot 63.
*/
- lis r3,KERNELBASE@h /* Load the kernel virtual address */
- ori r3,r3,KERNELBASE@l
+ lis r3,PAGE_OFFSET@h
+ ori r3,r3,PAGE_OFFSET@l
/* Kernel is at the base of RAM */
li r4, 0 /* Load the kernel physical address */
@@ -172,36 +172,28 @@ skpinv: addi r4,r4,1 /* Increment */
isync
4:
-#ifdef CONFIG_SERIAL_TEXT_DEBUG
- /*
- * Add temporary UART mapping for early debug.
- * We can map UART registers wherever we want as long as they don't
- * interfere with other system mappings (e.g. with pinned entries).
- * For an example of how we handle this - see ocotea.h. --ebs
- */
+#ifdef CONFIG_PPC_EARLY_DEBUG_44x
+ /* Add UART mapping for early debug. */
+
/* pageid fields */
- lis r3,UART0_IO_BASE@h
- ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K
+ lis r3,PPC44x_EARLY_DEBUG_VIRTADDR@h
+ ori r3,r3,PPC44x_TLB_VALID|PPC44x_TLB_TS|PPC44x_TLB_64K
/* xlat fields */
- lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */
-#ifndef CONFIG_440EP
- ori r4,r4,0x0001 /* ERPN is 1 for second 4GB page */
-#endif
+ lis r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW@h
+ ori r4,r4,CONFIG_PPC_EARLY_DEBUG_44x_PHYSHIGH
/* attrib fields */
- li r5,0
- ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
+ li r5,(PPC44x_TLB_SW|PPC44x_TLB_SR|PPC44x_TLB_I|PPC44x_TLB_G)
+ li r0,62 /* TLB slot 0 */
- li r0,0 /* TLB slot 0 */
-
- tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
- tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */
- tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
+ tlbwe r3,r0,PPC44x_TLB_PAGEID
+ tlbwe r4,r0,PPC44x_TLB_XLAT
+ tlbwe r5,r0,PPC44x_TLB_ATTRIB
/* Force context change */
isync
-#endif /* CONFIG_SERIAL_TEXT_DEBUG */
+#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
/* Establish the interrupt vector offsets */
SET_IVOR(0, CriticalInput);
@@ -709,16 +701,6 @@ _GLOBAL(giveup_fpu)
blr
#endif
-/*
- * extern void abort(void)
- *
- * At present, this routine just applies a system reset.
- */
-_GLOBAL(abort)
- mfspr r13,SPRN_DBCR0
- oris r13,r13,DBCR0_RST_SYSTEM@h
- mtspr SPRN_DBCR0,r13
-
_GLOBAL(set_context)
#ifdef CONFIG_BDI_SWITCH
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 97cedcd6c9b..1111fcec767 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -278,8 +278,12 @@ exception_marker:
beq- 1f; \
ld r1,PACAKSAVE(r13); /* kernel stack to use */ \
1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \
- bge- cr1,bad_stack; /* abort if it is */ \
- std r9,_CCR(r1); /* save CR in stackframe */ \
+ bge- cr1,2f; /* abort if it is */ \
+ b 3f; \
+2: li r1,(n); /* will be reloaded later */ \
+ sth r1,PACA_TRAP_SAVE(r13); \
+ b bad_stack; \
+3: std r9,_CCR(r1); /* save CR in stackframe */ \
std r11,_NIP(r1); /* save SRR0 in stackframe */ \
std r12,_MSR(r1); /* save SRR1 in stackframe */ \
std r10,0(r1); /* make stack chain pointer */ \
@@ -940,6 +944,8 @@ bad_stack:
SAVE_2GPRS(7,r1)
SAVE_10GPRS(12,r1)
SAVE_10GPRS(22,r1)
+ lhz r12,PACA_TRAP_SAVE(r13)
+ std r12,_TRAP(r1)
addi r11,r1,INT_FRAME_SIZE
std r11,0(r1)
li r12,0
@@ -1555,7 +1561,6 @@ _GLOBAL(generic_secondary_smp_init)
/* turn on 64-bit mode */
bl .enable_64b_mode
- isync
/* Set up a paca value for this processor. Since we have the
* physical cpu id in r24, we need to search the pacas to find
@@ -1735,10 +1740,6 @@ _STATIC(__boot_from_prom)
/* We never return */
trap
-/*
- * At this point, r3 contains the physical address we are running at,
- * returned by prom_init()
- */
_STATIC(__after_prom_start)
/*
@@ -1851,7 +1852,6 @@ __secondary_start_pmac_0:
_GLOBAL(pmac_secondary_start)
/* turn on 64-bit mode */
bl .enable_64b_mode
- isync
/* Copy some CPU settings from CPU 0 */
bl .__restore_cpu_ppc970
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 82bd2f10770..9a8c9af43b2 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -2,36 +2,37 @@
* IBM PowerPC IBM eBus Infrastructure Support.
*
* Copyright (c) 2005 IBM Corporation
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Heiko J Schick <schickhj@de.ibm.com>
- *
+ *
* All rights reserved.
*
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB
- * BSD.
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
*
* OpenIB BSD License
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
*
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
* and/or other materials
- * provided with the distribution.
+ * provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
@@ -43,19 +44,19 @@
#include <asm/ibmebus.h>
#include <asm/abs_addr.h>
-static struct ibmebus_dev ibmebus_bus_device = { /* fake "parent" device */
- .name = ibmebus_bus_device.ofdev.dev.bus_id,
- .ofdev.dev.bus_id = "ibmebus",
- .ofdev.dev.bus = &ibmebus_bus_type,
+static struct device ibmebus_bus_device = { /* fake "parent" device */
+ .bus_id = "ibmebus",
};
+struct bus_type ibmebus_bus_type;
+
static void *ibmebus_alloc_coherent(struct device *dev,
size_t size,
dma_addr_t *dma_handle,
gfp_t flag)
{
void *mem;
-
+
mem = kmalloc(size, flag);
*dma_handle = (dma_addr_t)mem;
@@ -63,7 +64,7 @@ static void *ibmebus_alloc_coherent(struct device *dev,
}
static void ibmebus_free_coherent(struct device *dev,
- size_t size, void *vaddr,
+ size_t size, void *vaddr,
dma_addr_t dma_handle)
{
kfree(vaddr);
@@ -79,7 +80,7 @@ static dma_addr_t ibmebus_map_single(struct device *dev,
static void ibmebus_unmap_single(struct device *dev,
dma_addr_t dma_addr,
- size_t size,
+ size_t size,
enum dma_data_direction direction)
{
return;
@@ -90,13 +91,13 @@ static int ibmebus_map_sg(struct device *dev,
int nents, enum dma_data_direction direction)
{
int i;
-
+
for (i = 0; i < nents; i++) {
- sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ sg[i].dma_address = (dma_addr_t)page_address(sg[i].page)
+ sg[i].offset;
sg[i].dma_length = sg[i].length;
}
-
+
return nents;
}
@@ -128,15 +129,15 @@ static int ibmebus_bus_probe(struct device *dev)
struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
const struct of_device_id *id;
int error = -ENODEV;
-
+
if (!ibmebusdrv->probe)
return error;
-
+
id = of_match_device(ibmebusdrv->id_table, &ibmebusdev->ofdev);
if (id) {
error = ibmebusdrv->probe(ibmebusdev, id);
}
-
+
return error;
}
@@ -144,11 +145,11 @@ static int ibmebus_bus_remove(struct device *dev)
{
struct ibmebus_dev *ibmebusdev = to_ibmebus_dev(dev);
struct ibmebus_driver *ibmebusdrv = to_ibmebus_driver(dev->driver);
-
+
if (ibmebusdrv->remove) {
return ibmebusdrv->remove(ibmebusdev);
}
-
+
return 0;
}
@@ -158,21 +159,12 @@ static void __devinit ibmebus_dev_release(struct device *dev)
kfree(to_ibmebus_dev(dev));
}
-static ssize_t ibmebusdev_show_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%s\n", to_ibmebus_dev(dev)->name);
-}
-static DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, ibmebusdev_show_name,
- NULL);
-
-static struct ibmebus_dev* __devinit ibmebus_register_device_common(
+static int __devinit ibmebus_register_device_common(
struct ibmebus_dev *dev, const char *name)
{
int err = 0;
- dev->name = name;
- dev->ofdev.dev.parent = &ibmebus_bus_device.ofdev.dev;
+ dev->ofdev.dev.parent = &ibmebus_bus_device;
dev->ofdev.dev.bus = &ibmebus_bus_type;
dev->ofdev.dev.release = ibmebus_dev_release;
@@ -181,17 +173,15 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_common(
dev->ofdev.dev.archdata.numa_node = of_node_to_nid(dev->ofdev.node);
/* An ibmebusdev is based on a of_device. We have to change the
- * bus type to use our own DMA mapping operations.
- */
+ * bus type to use our own DMA mapping operations.
+ */
if ((err = of_device_register(&dev->ofdev)) != 0) {
printk(KERN_ERR "%s: failed to register device (%d).\n",
__FUNCTION__, err);
- return NULL;
+ return -ENODEV;
}
-
- device_create_file(&dev->ofdev.dev, &dev_attr_name);
-
- return dev;
+
+ return 0;
}
static struct ibmebus_dev* __devinit ibmebus_register_device_node(
@@ -201,35 +191,35 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
const char *loc_code;
int length;
- loc_code = get_property(dn, "ibm,loc-code", NULL);
+ loc_code = of_get_property(dn, "ibm,loc-code", NULL);
if (!loc_code) {
printk(KERN_WARNING "%s: node %s missing 'ibm,loc-code'\n",
__FUNCTION__, dn->name ? dn->name : "<unknown>");
- return NULL;
+ return ERR_PTR(-EINVAL);
}
-
+
if (strlen(loc_code) == 0) {
printk(KERN_WARNING "%s: 'ibm,loc-code' is invalid\n",
__FUNCTION__);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
dev = kzalloc(sizeof(struct ibmebus_dev), GFP_KERNEL);
if (!dev) {
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
dev->ofdev.node = of_node_get(dn);
-
+
length = strlen(loc_code);
- memcpy(dev->ofdev.dev.bus_id, loc_code
- + (length - min(length, BUS_ID_SIZE - 1)),
+ memcpy(dev->ofdev.dev.bus_id, loc_code
+ + (length - min(length, BUS_ID_SIZE - 1)),
min(length, BUS_ID_SIZE - 1));
/* Register with generic device framework. */
- if (ibmebus_register_device_common(dev, dn->name) == NULL) {
+ if (ibmebus_register_device_common(dev, dn->name) != 0) {
kfree(dev);
- return NULL;
+ return ERR_PTR(-ENODEV);
}
return dev;
@@ -238,17 +228,16 @@ static struct ibmebus_dev* __devinit ibmebus_register_device_node(
static void ibmebus_probe_of_nodes(char* name)
{
struct device_node *dn = NULL;
-
+
while ((dn = of_find_node_by_name(dn, name))) {
- if (ibmebus_register_device_node(dn) == NULL) {
+ if (IS_ERR(ibmebus_register_device_node(dn))) {
of_node_put(dn);
-
return;
}
}
-
+
of_node_put(dn);
-
+
return;
}
@@ -262,17 +251,21 @@ static void ibmebus_add_devices_by_id(struct of_device_id *idt)
return;
}
-static int ibmebus_match_helper(struct device *dev, void *data)
+static int ibmebus_match_name(struct device *dev, void *data)
{
- if (strcmp((char*)data, to_ibmebus_dev(dev)->name) == 0)
+ const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ const char *name;
+
+ name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+
+ if (name && (strcmp(data, name) == 0))
return 1;
-
+
return 0;
}
static int ibmebus_unregister_device(struct device *dev)
{
- device_remove_file(dev, &dev_attr_name);
of_device_unregister(to_of_device(dev));
return 0;
@@ -281,17 +274,16 @@ static int ibmebus_unregister_device(struct device *dev)
static void ibmebus_remove_devices_by_id(struct of_device_id *idt)
{
struct device *dev;
-
+
while (strlen(idt->name) > 0) {
- while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
+ while ((dev = bus_find_device(&ibmebus_bus_type, NULL,
(void*)idt->name,
- ibmebus_match_helper))) {
+ ibmebus_match_name))) {
ibmebus_unregister_device(dev);
}
idt++;
-
}
-
+
return;
}
@@ -307,30 +299,33 @@ int ibmebus_register_driver(struct ibmebus_driver *drv)
if ((err = driver_register(&drv->driver) != 0))
return err;
+ /* remove all supported devices first, in case someone
+ * probed them manually before registering the driver */
+ ibmebus_remove_devices_by_id(drv->id_table);
ibmebus_add_devices_by_id(drv->id_table);
-
+
return 0;
}
EXPORT_SYMBOL(ibmebus_register_driver);
void ibmebus_unregister_driver(struct ibmebus_driver *drv)
-{
+{
driver_unregister(&drv->driver);
ibmebus_remove_devices_by_id(drv->id_table);
}
EXPORT_SYMBOL(ibmebus_unregister_driver);
int ibmebus_request_irq(struct ibmebus_dev *dev,
- u32 ist,
+ u32 ist,
irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id)
{
unsigned int irq = irq_create_mapping(NULL, ist);
-
+
if (irq == NO_IRQ)
return -EINVAL;
-
+
return request_irq(irq, handler,
irq_flags, devname, dev_id);
}
@@ -339,56 +334,163 @@ EXPORT_SYMBOL(ibmebus_request_irq);
void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id)
{
unsigned int irq = irq_find_mapping(NULL, ist);
-
+
free_irq(irq, dev_id);
}
EXPORT_SYMBOL(ibmebus_free_irq);
static int ibmebus_bus_match(struct device *dev, struct device_driver *drv)
-{
+{
const struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
struct ibmebus_driver *ebus_drv = to_ibmebus_driver(drv);
const struct of_device_id *ids = ebus_drv->id_table;
const struct of_device_id *found_id;
-
+
if (!ids)
return 0;
-
+
found_id = of_match_device(ids, &ebus_dev->ofdev);
if (found_id)
return 1;
-
+
return 0;
}
+static ssize_t name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ibmebus_dev *ebus_dev = to_ibmebus_dev(dev);
+ const char *name = of_get_property(ebus_dev->ofdev.node, "name", NULL);
+ return sprintf(buf, "%s\n", name);
+}
+
+static struct device_attribute ibmebus_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_NULL
+};
+
+static int ibmebus_match_path(struct device *dev, void *data)
+{
+ int rc;
+ struct device_node *dn =
+ of_node_get(to_ibmebus_dev(dev)->ofdev.node);
+
+ rc = (dn->full_name && (strcasecmp((char*)data, dn->full_name) == 0));
+
+ of_node_put(dn);
+ return rc;
+}
+
+static char *ibmebus_chomp(const char *in, size_t count)
+{
+ char *out = (char*)kmalloc(count + 1, GFP_KERNEL);
+ if (!out)
+ return NULL;
+
+ memcpy(out, in, count);
+ out[count] = '\0';
+ if (out[count - 1] == '\n')
+ out[count - 1] = '\0';
+
+ return out;
+}
+
+static ssize_t ibmebus_store_probe(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ struct device_node *dn = NULL;
+ struct ibmebus_dev *dev;
+ char *path;
+ ssize_t rc;
+
+ path = ibmebus_chomp(buf, count);
+ if (!path)
+ return -ENOMEM;
+
+ if (bus_find_device(&ibmebus_bus_type, NULL, path,
+ ibmebus_match_path)) {
+ printk(KERN_WARNING "%s: %s has already been probed\n",
+ __FUNCTION__, path);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if ((dn = of_find_node_by_path(path))) {
+ dev = ibmebus_register_device_node(dn);
+ of_node_put(dn);
+ rc = IS_ERR(dev) ? PTR_ERR(dev) : count;
+ } else {
+ printk(KERN_WARNING "%s: no such device node: %s\n",
+ __FUNCTION__, path);
+ rc = -ENODEV;
+ }
+
+out:
+ kfree(path);
+ return rc;
+}
+
+static ssize_t ibmebus_store_remove(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ struct device *dev;
+ char *path;
+
+ path = ibmebus_chomp(buf, count);
+ if (!path)
+ return -ENOMEM;
+
+ if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,
+ ibmebus_match_path))) {
+ ibmebus_unregister_device(dev);
+
+ kfree(path);
+ return count;
+ } else {
+ printk(KERN_WARNING "%s: %s not on the bus\n",
+ __FUNCTION__, path);
+
+ kfree(path);
+ return -ENODEV;
+ }
+}
+
+static struct bus_attribute ibmebus_bus_attrs[] = {
+ __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe),
+ __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove),
+ __ATTR_NULL
+};
+
struct bus_type ibmebus_bus_type = {
- .name = "ibmebus",
- .match = ibmebus_bus_match,
+ .name = "ibmebus",
+ .match = ibmebus_bus_match,
+ .dev_attrs = ibmebus_dev_attrs,
+ .bus_attrs = ibmebus_bus_attrs
};
EXPORT_SYMBOL(ibmebus_bus_type);
static int __init ibmebus_bus_init(void)
{
int err;
-
+
printk(KERN_INFO "IBM eBus Device Driver\n");
-
+
err = bus_register(&ibmebus_bus_type);
if (err) {
printk(KERN_ERR ":%s: failed to register IBM eBus.\n",
__FUNCTION__);
return err;
}
-
- err = device_register(&ibmebus_bus_device.ofdev.dev);
+
+ err = device_register(&ibmebus_bus_device);
if (err) {
- printk(KERN_WARNING "%s: device_register returned %i\n",
+ printk(KERN_WARNING "%s: device_register returned %i\n",
__FUNCTION__, err);
bus_unregister(&ibmebus_bus_type);
return err;
}
-
+
return 0;
}
__initcall(ibmebus_bus_init);
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c
index 6e7f50967ba..a9e9cbd3297 100644
--- a/arch/powerpc/kernel/idle.c
+++ b/arch/powerpc/kernel/idle.c
@@ -33,8 +33,11 @@
#include <asm/smp.h>
#ifdef CONFIG_HOTPLUG_CPU
+/* this is used for software suspend, and that shuts down
+ * CPUs even while the system is still booting... */
#define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \
- system_state == SYSTEM_RUNNING)
+ (system_state == SYSTEM_RUNNING \
+ || system_state == SYSTEM_BOOTING))
#else
#define cpu_should_die() 0
#endif
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index ba319547860..5328709eeed 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -53,3 +53,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
isync
b 1b
+_GLOBAL(power4_cpu_offline_powersave)
+ /* Go to NAP now */
+ mfmsr r7
+ rldicl r0,r7,48,1
+ rotldi r0,r0,16
+ mtmsrd r0,1 /* hard-disable interrupts */
+ li r0,1
+ li r6,0
+ stb r0,PACAHARDIRQEN(r13) /* we'll hard-enable shortly */
+ stb r6,PACASOFTIRQEN(r13) /* soft-disable irqs */
+BEGIN_FTR_SECTION
+ DSSALL
+ sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ ori r7,r7,MSR_EE
+ oris r7,r7,MSR_POW@h
+ sync
+ isync
+ mtmsrd r7
+ isync
+ blr
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 95edad4faf2..c08ceca6277 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -47,6 +47,8 @@ static int novmerge = 0;
static int novmerge = 1;
#endif
+static int protect4gb = 1;
+
static inline unsigned long iommu_num_pages(unsigned long vaddr,
unsigned long slen)
{
@@ -58,6 +60,16 @@ static inline unsigned long iommu_num_pages(unsigned long vaddr,
return npages;
}
+static int __init setup_protect4gb(char *str)
+{
+ if (strcmp(str, "on") == 0)
+ protect4gb = 1;
+ else if (strcmp(str, "off") == 0)
+ protect4gb = 0;
+
+ return 1;
+}
+
static int __init setup_iommu(char *str)
{
if (!strcmp(str, "novmerge"))
@@ -67,6 +79,7 @@ static int __init setup_iommu(char *str)
return 1;
}
+__setup("protect4gb=", setup_protect4gb);
__setup("iommu=", setup_iommu);
static unsigned long iommu_range_alloc(struct iommu_table *tbl,
@@ -429,6 +442,9 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
{
unsigned long sz;
+ unsigned long start_index, end_index;
+ unsigned long entries_per_4g;
+ unsigned long index;
static int welcomed = 0;
struct page *page;
@@ -450,7 +466,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
#ifdef CONFIG_CRASH_DUMP
if (ppc_md.tce_get) {
- unsigned long index, tceval;
+ unsigned long tceval;
unsigned long tcecount = 0;
/*
@@ -480,6 +496,23 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size);
#endif
+ /*
+ * DMA cannot cross 4 GB boundary. Mark last entry of each 4
+ * GB chunk as reserved.
+ */
+ if (protect4gb) {
+ entries_per_4g = 0x100000000l >> IOMMU_PAGE_SHIFT;
+
+ /* Mark the last bit before a 4GB boundary as used */
+ start_index = tbl->it_offset | (entries_per_4g - 1);
+ start_index -= tbl->it_offset;
+
+ end_index = tbl->it_size;
+
+ for (index = start_index; index < end_index - 1; index += entries_per_4g)
+ __set_bit(index, tbl->it_map);
+ }
+
if (!welcomed) {
printk(KERN_INFO "IOMMU table initialized, virtual merging %s\n",
novmerge ? "disabled" : "enabled");
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 10093082685..9ed4931af16 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -67,6 +67,7 @@
#ifdef CONFIG_PPC64
#include <asm/paca.h>
#include <asm/firmware.h>
+#include <asm/lv1call.h>
#endif
int __irq_offset_value;
@@ -162,6 +163,16 @@ void local_irq_restore(unsigned long en)
local_paca->hard_enabled = en;
if ((int)mfspr(SPRN_DEC) < 0)
mtspr(SPRN_DEC, 1);
+
+ /*
+ * Force the delivery of pending soft-disabled interrupts on PS3.
+ * Any HV call will have this side effect.
+ */
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
+ u64 tmp;
+ lv1_get_version_info(&tmp);
+ }
+
hard_irq_enable();
}
#endif /* CONFIG_PPC64 */
@@ -394,7 +405,7 @@ EXPORT_SYMBOL(do_softirq);
#ifdef CONFIG_PPC_MERGE
static LIST_HEAD(irq_hosts);
-static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(irq_big_lock);
static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
static unsigned int irq_radix_writer;
struct irq_map_entry irq_map[NR_IRQS];
@@ -947,33 +958,6 @@ arch_initcall(irq_late_init);
#endif /* CONFIG_PPC_MERGE */
-#ifdef CONFIG_PCI_MSI
-int pci_enable_msi(struct pci_dev * pdev)
-{
- if (ppc_md.enable_msi)
- return ppc_md.enable_msi(pdev);
- else
- return -1;
-}
-EXPORT_SYMBOL(pci_enable_msi);
-
-void pci_disable_msi(struct pci_dev * pdev)
-{
- if (ppc_md.disable_msi)
- ppc_md.disable_msi(pdev);
-}
-EXPORT_SYMBOL(pci_disable_msi);
-
-void pci_scan_msi_device(struct pci_dev *dev) {}
-int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) {return -1;}
-void pci_disable_msix(struct pci_dev *dev) {}
-void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
-void pci_no_msi(void) {}
-EXPORT_SYMBOL(pci_enable_msix);
-EXPORT_SYMBOL(pci_disable_msix);
-
-#endif
-
#ifdef CONFIG_PPC64
static int __init setup_noirqdistrib(char *str)
{
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index dd2886f97e9..0c96611f02f 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -30,8 +30,8 @@
#include <linux/ptrace.h>
#include <linux/preempt.h>
#include <linux/module.h>
+#include <linux/kdebug.h>
#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
#include <asm/sstep.h>
#include <asm/uaccess.h>
@@ -59,12 +59,14 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
}
if (!ret) {
- memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+ memcpy(p->ainsn.insn, p->addr,
+ MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
p->opcode = *p->addr;
flush_icache_range((unsigned long)p->ainsn.insn,
(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
}
+ p->ainsn.boostable = 0;
return ret;
}
@@ -124,22 +126,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
}
/* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
- struct kretprobe_instance *ri;
-
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
- ri->ret_addr = (kprobe_opcode_t *)regs->link;
-
- /* Replace the return addr with trampoline addr */
- regs->link = (unsigned long)kretprobe_trampoline;
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ ri->ret_addr = (kprobe_opcode_t *)regs->link;
+
+ /* Replace the return addr with trampoline addr */
+ regs->link = (unsigned long)kretprobe_trampoline;
}
static int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -232,6 +225,38 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
return 1;
ss_probe:
+ if (p->ainsn.boostable >= 0) {
+ unsigned int insn = *p->ainsn.insn;
+
+ /* regs->nip is also adjusted if emulate_step returns 1 */
+ ret = emulate_step(regs, insn);
+ if (ret > 0) {
+ /*
+ * Once this instruction has been boosted
+ * successfully, set the boostable flag
+ */
+ if (unlikely(p->ainsn.boostable == 0))
+ p->ainsn.boostable = 1;
+
+ if (p->post_handler)
+ p->post_handler(p, regs, 0);
+
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ reset_current_kprobe();
+ preempt_enable_no_resched();
+ return 1;
+ } else if (ret < 0) {
+ /*
+ * We don't allow kprobes on mtmsr(d)/rfi(d), etc.
+ * So, we should never get here... but, its still
+ * good to catch them, just in case...
+ */
+ printk("Can't step on instruction %x\n", insn);
+ BUG();
+ } else if (ret == 0)
+ /* This instruction can't be boosted */
+ p->ainsn.boostable = -1;
+ }
prepare_singlestep(p, regs);
kcb->kprobe_status = KPROBE_HIT_SS;
return 1;
@@ -302,7 +327,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
break;
}
- BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
regs->nip = orig_ret_address;
reset_current_kprobe();
@@ -376,7 +401,7 @@ out:
return 1;
}
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -461,14 +486,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
if (post_kprobe_handler(args->regs))
ret = NOTIFY_STOP;
break;
- case DIE_PAGE_FAULT:
- /* kprobe_running() needs smp_processor_id() */
- preempt_disable();
- if (kprobe_running() &&
- kprobe_fault_handler(args->regs, args->trapnr))
- ret = NOTIFY_STOP;
- preempt_enable();
- break;
default:
break;
}
@@ -525,3 +542,11 @@ int __init arch_init_kprobes(void)
{
return register_kprobe(&trampoline_p);
}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index 325f490a10c..cea8045ba40 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -44,12 +44,12 @@ static int __init add_legacy_port(struct device_node *np, int want_index,
int index;
/* get clock freq. if present */
- clk = get_property(np, "clock-frequency", NULL);
+ clk = of_get_property(np, "clock-frequency", NULL);
if (clk && *clk)
clock = *clk;
/* get default speed if present */
- spd = get_property(np, "current-speed", NULL);
+ spd = of_get_property(np, "current-speed", NULL);
/* If we have a location index, then try to use it */
if (want_index >= 0 && want_index < MAX_LEGACY_SERIAL_PORTS)
@@ -115,17 +115,18 @@ static int __init add_legacy_soc_port(struct device_node *np,
{
u64 addr;
const u32 *addrp;
- upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+ upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ
+ | UPF_FIXED_PORT;
struct device_node *tsi = of_get_parent(np);
/* We only support ports that have a clock frequency properly
* encoded in the device-tree.
*/
- if (get_property(np, "clock-frequency", NULL) == NULL)
+ if (of_get_property(np, "clock-frequency", NULL) == NULL)
return -1;
/* if rtas uses this device, don't try to use it as well */
- if (get_property(np, "used-by-rtas", NULL) != NULL)
+ if (of_get_property(np, "used-by-rtas", NULL) != NULL)
return -1;
/* Get the address */
@@ -157,7 +158,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
DBG(" -> add_legacy_isa_port(%s)\n", np->full_name);
/* Get the ISA port number */
- reg = get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
if (reg == NULL)
return -1;
@@ -168,7 +169,7 @@ static int __init add_legacy_isa_port(struct device_node *np,
/* Now look for an "ibm,aix-loc" property that gives us ordering
* if any...
*/
- typep = get_property(np, "ibm,aix-loc", NULL);
+ typep = of_get_property(np, "ibm,aix-loc", NULL);
/* If we have a location index, then use it */
if (typep && *typep == 'S')
@@ -206,7 +207,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
* compatible UARTs on PCI need all sort of quirks (port offsets
* etc...) that this code doesn't know about
*/
- if (get_property(np, "clock-frequency", NULL) == NULL)
+ if (of_get_property(np, "clock-frequency", NULL) == NULL)
return -1;
/* Get the PCI address. Assume BAR 0 */
@@ -232,7 +233,7 @@ static int __init add_legacy_pci_port(struct device_node *np,
* we get to their "reg" property
*/
if (np != pci_dev) {
- const u32 *reg = get_property(np, "reg", NULL);
+ const u32 *reg = of_get_property(np, "reg", NULL);
if (reg && (*reg < 4))
index = lindex = *reg;
}
@@ -243,9 +244,9 @@ static int __init add_legacy_pci_port(struct device_node *np,
* doesn't work for these settings, you'll have to add your own special
* cases here
*/
- if (device_is_compatible(pci_dev, "pci13a8,152") ||
- device_is_compatible(pci_dev, "pci13a8,154") ||
- device_is_compatible(pci_dev, "pci13a8,158")) {
+ if (of_device_is_compatible(pci_dev, "pci13a8,152") ||
+ of_device_is_compatible(pci_dev, "pci13a8,154") ||
+ of_device_is_compatible(pci_dev, "pci13a8,158")) {
addr += 0x200 * lindex;
base += 0x200 * lindex;
} else {
@@ -296,7 +297,7 @@ void __init find_legacy_serial_ports(void)
DBG(" -> find_legacy_serial_port()\n");
/* Now find out if one of these is out firmware console */
- path = get_property(of_chosen, "linux,stdout-path", NULL);
+ path = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL) {
stdout = of_find_node_by_path(path);
if (stdout)
@@ -364,11 +365,11 @@ void __init find_legacy_serial_ports(void)
/* Check for known pciclass, and also check wether we have
* a device with child nodes for ports or not
*/
- if (device_is_compatible(np, "pciclass,0700") ||
- device_is_compatible(np, "pciclass,070002"))
+ if (of_device_is_compatible(np, "pciclass,0700") ||
+ of_device_is_compatible(np, "pciclass,070002"))
pci = np;
- else if (device_is_compatible(parent, "pciclass,0700") ||
- device_is_compatible(parent, "pciclass,070002"))
+ else if (of_device_is_compatible(parent, "pciclass,0700") ||
+ of_device_is_compatible(parent, "pciclass,070002"))
pci = parent;
else {
of_node_put(parent);
@@ -529,7 +530,7 @@ static int __init check_legacy_serial_console(void)
}
/* We are getting a weird phandle from OF ... */
/* ... So use the full path instead */
- name = get_property(of_chosen, "linux,stdout-path", NULL);
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name == NULL) {
DBG(" no linux,stdout-path !\n");
return -ENODEV;
@@ -541,12 +542,12 @@ static int __init check_legacy_serial_console(void)
}
DBG("stdout is %s\n", prom_stdout->full_name);
- name = get_property(prom_stdout, "name", NULL);
+ name = of_get_property(prom_stdout, "name", NULL);
if (!name) {
DBG(" stdout package has no name !\n");
goto not_found;
}
- spd = get_property(prom_stdout, "current-speed", NULL);
+ spd = of_get_property(prom_stdout, "current-speed", NULL);
if (spd)
speed = *spd;
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 89486b63128..c492cee90e0 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -130,30 +130,31 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v)
/*
* Methods used to fetch LPAR data when running on a pSeries platform.
*/
-/* find a better place for this function... */
static void log_plpar_hcall_return(unsigned long rc, char *tag)
{
- if (rc == 0) /* success, return */
+ switch(rc) {
+ case 0:
return;
-/* check for null tag ? */
- if (rc == H_HARDWARE)
- printk(KERN_INFO
- "plpar-hcall (%s) failed with hardware fault\n", tag);
- else if (rc == H_FUNCTION)
- printk(KERN_INFO
- "plpar-hcall (%s) failed; function not allowed\n", tag);
- else if (rc == H_AUTHORITY)
- printk(KERN_INFO
- "plpar-hcall (%s) failed; not authorized to this"
- " function\n", tag);
- else if (rc == H_PARAMETER)
- printk(KERN_INFO "plpar-hcall (%s) failed; Bad parameter(s)\n",
- tag);
- else
- printk(KERN_INFO
- "plpar-hcall (%s) failed with unexpected rc(0x%lx)\n",
- tag, rc);
-
+ case H_HARDWARE:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Hardware fault\n", tag);
+ return;
+ case H_FUNCTION:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Function not allowed\n", tag);
+ return;
+ case H_AUTHORITY:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Not authorized to this function\n", tag);
+ return;
+ case H_PARAMETER:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Bad parameter(s)\n",tag);
+ return;
+ default:
+ printk(KERN_INFO "plpar-hcall (%s) "
+ "Unexpected rc(0x%lx)\n", tag, rc);
+ }
}
/*
@@ -321,15 +322,16 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
struct device_node *rtas_node;
const int *lrdrp = NULL;
- rtas_node = find_path_device("/rtas");
+ rtas_node = of_find_node_by_path("/rtas");
if (rtas_node)
- lrdrp = get_property(rtas_node, "ibm,lrdr-capacity", NULL);
+ lrdrp = of_get_property(rtas_node, "ibm,lrdr-capacity", NULL);
if (lrdrp == NULL) {
partition_potential_processors = vdso_data->processorCount;
} else {
partition_potential_processors = *(lrdrp + 4);
}
+ of_node_put(rtas_node);
partition_active_processors = lparcfg_count_active_processors();
@@ -537,25 +539,27 @@ static int lparcfg_data(struct seq_file *m, void *v)
seq_printf(m, "%s %s \n", MODULE_NAME, MODULE_VERS);
- rootdn = find_path_device("/");
+ rootdn = of_find_node_by_path("/");
if (rootdn) {
- tmp = get_property(rootdn, "model", NULL);
+ tmp = of_get_property(rootdn, "model", NULL);
if (tmp) {
model = tmp;
/* Skip "IBM," - see platforms/iseries/dt.c */
if (firmware_has_feature(FW_FEATURE_ISERIES))
model += 4;
}
- tmp = get_property(rootdn, "system-id", NULL);
+ tmp = of_get_property(rootdn, "system-id", NULL);
if (tmp) {
system_id = tmp;
/* Skip "IBM," - see platforms/iseries/dt.c */
if (firmware_has_feature(FW_FEATURE_ISERIES))
system_id += 4;
}
- lp_index_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+ lp_index_ptr = of_get_property(rootdn, "ibm,partition-no",
+ NULL);
if (lp_index_ptr)
lp_index = *lp_index_ptr;
+ of_node_put(rootdn);
}
seq_printf(m, "serial_number=%s\n", system_id);
seq_printf(m, "system_type=%s\n", model);
diff --git a/arch/powerpc/kernel/lparmap.c b/arch/powerpc/kernel/lparmap.c
index 584d1e3c013..af11285ffbd 100644
--- a/arch/powerpc/kernel/lparmap.c
+++ b/arch/powerpc/kernel/lparmap.c
@@ -10,7 +10,8 @@
#include <asm/pgtable.h>
#include <asm/iseries/lpar_map.h>
-const struct LparMap __attribute__((__section__(".text"))) xLparMap = {
+/* The # is to stop gcc trying to make .text nonexecutable */
+const struct LparMap __attribute__((__section__(".text #"))) xLparMap = {
.xNumberEsids = HvEsidsToMap,
.xNumberRanges = HvRangesToMap,
.xSegmentTableOffs = STAB0_PAGE,
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index a24b09c2771..704375bda73 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -72,8 +72,8 @@ int default_machine_kexec_prepare(struct kimage *image)
/* We also should not overwrite the tce tables */
for (node = of_find_node_by_type(NULL, "pci"); node != NULL;
node = of_find_node_by_type(node, "pci")) {
- basep = get_property(node, "linux,tce-base", NULL);
- sizep = get_property(node, "linux,tce-size", NULL);
+ basep = of_get_property(node, "linux,tce-base", NULL);
+ sizep = of_get_property(node, "linux,tce-size", NULL);
if (basep == NULL || sizep == NULL)
continue;
@@ -294,19 +294,19 @@ static unsigned long htab_base, kernel_end;
static struct property htab_base_prop = {
.name = "linux,htab-base",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&htab_base,
+ .value = &htab_base,
};
static struct property htab_size_prop = {
.name = "linux,htab-size",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&htab_size_bytes,
+ .value = &htab_size_bytes,
};
static struct property kernel_end_prop = {
.name = "linux,kernel-end",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&kernel_end,
+ .value = &kernel_end,
};
static void __init export_htab_values(void)
@@ -335,7 +335,7 @@ static void __init export_htab_values(void)
static struct property crashk_base_prop = {
.name = "linux,crashkernel-base",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&crashk_res.start,
+ .value = &crashk_res.start,
};
static unsigned long crashk_size;
@@ -343,7 +343,7 @@ static unsigned long crashk_size;
static struct property crashk_size_prop = {
.name = "linux,crashkernel-size",
.length = sizeof(unsigned long),
- .value = (unsigned char *)&crashk_size,
+ .value = &crashk_size,
};
static void __init export_crashk_values(void)
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 412bea3cf81..98decf8ebff 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -734,10 +734,6 @@ _GLOBAL(abs)
sub r3,r3,r4
blr
-_GLOBAL(_get_SP)
- mr r3,r1 /* Close enough */
- blr
-
/*
* Create a kernel thread
* kernel_thread(fn, arg, flags)
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
new file mode 100644
index 00000000000..c62d1012c01
--- /dev/null
+++ b/arch/powerpc/kernel/msi.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/msi.h>
+
+#include <asm/machdep.h>
+
+int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
+{
+ if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) {
+ pr_debug("msi: Platform doesn't provide MSI callbacks.\n");
+ return -ENOSYS;
+ }
+
+ if (ppc_md.msi_check_device) {
+ pr_debug("msi: Using platform check routine.\n");
+ return ppc_md.msi_check_device(dev, nvec, type);
+ }
+
+ return 0;
+}
+
+int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ return ppc_md.setup_msi_irqs(dev, nvec, type);
+}
+
+void arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+ return ppc_md.teardown_msi_irqs(dev);
+}
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index e921514e655..a464d67248d 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -27,7 +27,7 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
match &= node->type
&& !strcmp(matches->type, node->type);
if (matches->compatible[0])
- match &= device_is_compatible(node,
+ match &= of_device_is_compatible(node,
matches->compatible);
if (match)
return matches;
@@ -120,6 +120,117 @@ void of_device_unregister(struct of_device *ofdev)
}
+ssize_t of_device_get_modalias(struct of_device *ofdev,
+ char *str, ssize_t len)
+{
+ const char *compat;
+ int cplen, i;
+ ssize_t tsize, csize, repend;
+
+ /* Name & Type */
+ csize = snprintf(str, len, "of:N%sT%s",
+ ofdev->node->name, ofdev->node->type);
+
+ /* Get compatible property if any */
+ compat = of_get_property(ofdev->node, "compatible", &cplen);
+ if (!compat)
+ return csize;
+
+ /* Find true end (we tolerate multiple \0 at the end */
+ for (i=(cplen-1); i>=0 && !compat[i]; i--)
+ cplen--;
+ if (!cplen)
+ return csize;
+ cplen++;
+
+ /* Check space (need cplen+1 chars including final \0) */
+ tsize = csize + cplen;
+ repend = tsize;
+
+ if (csize>=len) /* @ the limit, all is already filled */
+ return tsize;
+
+ if (tsize>=len) { /* limit compat list */
+ cplen = len-csize-1;
+ repend = len;
+ }
+
+ /* Copy and do char replacement */
+ memcpy(&str[csize+1], compat, cplen);
+ for (i=csize; i<repend; i++) {
+ char c = str[i];
+ if (c=='\0')
+ str[i] = 'C';
+ else if (c==' ')
+ str[i] = '_';
+ }
+
+ return tsize;
+}
+
+int of_device_uevent(struct device *dev,
+ char **envp, int num_envp, char *buffer, int buffer_size)
+{
+ struct of_device *ofdev;
+ const char *compat;
+ int i = 0, length = 0, seen = 0, cplen, sl;
+
+ if (!dev)
+ return -ENODEV;
+
+ ofdev = to_of_device(dev);
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "OF_NAME=%s", ofdev->node->name))
+ return -ENOMEM;
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "OF_TYPE=%s", ofdev->node->type))
+ return -ENOMEM;
+
+ /* Since the compatible field can contain pretty much anything
+ * it's not really legal to split it out with commas. We split it
+ * up using a number of environment variables instead. */
+
+ compat = of_get_property(ofdev->node, "compatible", &cplen);
+ while (compat && *compat && cplen > 0) {
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "OF_COMPATIBLE_%d=%s", seen, compat))
+ return -ENOMEM;
+
+ sl = strlen (compat) + 1;
+ compat += sl;
+ cplen -= sl;
+ seen++;
+ }
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "OF_COMPATIBLE_N=%d", seen))
+ return -ENOMEM;
+
+ /* modalias is trickier, we add it in 2 steps */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS="))
+ return -ENOMEM;
+
+ sl = of_device_get_modalias(ofdev, &buffer[length-1],
+ buffer_size-length);
+ if (sl >= (buffer_size-length))
+ return -ENOMEM;
+
+ length += sl;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+
EXPORT_SYMBOL(of_match_node);
EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_device_register);
@@ -127,3 +238,5 @@ EXPORT_SYMBOL(of_device_unregister);
EXPORT_SYMBOL(of_dev_get);
EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_release_dev);
+EXPORT_SYMBOL(of_device_uevent);
+EXPORT_SYMBOL(of_device_get_modalias);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index 9e7a4d249f0..84c34d979a8 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -29,7 +29,6 @@
#include <asm/ppc-pci.h>
#include <asm/atomic.h>
-
/*
* The list of OF IDs below is used for matching bus types in the
* system whose devices are to be exposed as of_platform_devices.
@@ -133,6 +132,7 @@ static int of_platform_device_resume(struct device * dev)
struct bus_type of_platform_bus_type = {
.name = "of_platform",
.match = of_platform_bus_match,
+ .uevent = of_device_uevent,
.probe = of_platform_device_probe,
.remove = of_platform_device_remove,
.suspend = of_platform_device_suspend,
@@ -177,7 +177,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
* and 'D' for MMIO DCRs.
*/
#ifdef CONFIG_PPC_DCR
- reg = get_property(node, "dcr-reg", NULL);
+ reg = of_get_property(node, "dcr-reg", NULL);
if (reg) {
#ifdef CONFIG_PPC_DCR_NATIVE
snprintf(name, BUS_ID_SIZE, "d%x.%s",
@@ -197,7 +197,7 @@ static void of_platform_make_bus_id(struct of_device *dev)
/*
* For MMIO, get the physical address
*/
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (reg) {
addr = of_translate_address(node, reg);
if (addr != OF_BAD_ADDR) {
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index d8ef2e10050..e66064b5093 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -637,7 +637,7 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
if (pci_bus >= pci_bus_count)
return;
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, "
"assuming it starts at 0\n", node->full_name);
@@ -649,17 +649,20 @@ make_one_node_map(struct device_node* node, u8 pci_bus)
struct pci_dev* dev;
const unsigned int *class_code, *reg;
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (!reg)
continue;
- dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff));
- if (!dev || !dev->subordinate)
+ dev = pci_get_bus_and_slot(pci_bus, ((reg[0] >> 8) & 0xff));
+ if (!dev || !dev->subordinate) {
+ pci_dev_put(dev);
continue;
+ }
make_one_node_map(node, dev->subordinate->number);
+ pci_dev_put(dev);
}
}
@@ -669,6 +672,7 @@ pcibios_make_OF_bus_map(void)
int i;
struct pci_controller* hose;
struct property *map_prop;
+ struct device_node *dn;
pci_to_OF_bus_map = kmalloc(pci_bus_count, GFP_KERNEL);
if (!pci_to_OF_bus_map) {
@@ -690,12 +694,13 @@ pcibios_make_OF_bus_map(void)
continue;
make_one_node_map(node, hose->first_busno);
}
- map_prop = of_find_property(find_path_device("/"),
- "pci-OF-bus-map", NULL);
+ dn = of_find_node_by_path("/");
+ map_prop = of_find_property(dn, "pci-OF-bus-map", NULL);
if (map_prop) {
BUG_ON(pci_bus_count > map_prop->length);
memcpy(map_prop->value, pci_to_OF_bus_map, pci_bus_count);
}
+ of_node_put(dn);
#ifdef DEBUG
printk("PCI->OF bus map:\n");
for (i=0; i<pci_bus_count; i++) {
@@ -724,7 +729,7 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void*
* a fake root for all functions of a multi-function device,
* we go down them as well.
*/
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
strcmp(node->name, "multifunc-device"))
@@ -744,7 +749,7 @@ static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
unsigned int psize;
while ((np = of_get_next_child(parent, np)) != NULL) {
- reg = get_property(np, "reg", &psize);
+ reg = of_get_property(np, "reg", &psize);
if (reg == NULL || psize < 4)
continue;
if (((reg[0] >> 8) & 0xff) == devfn)
@@ -859,7 +864,7 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
find_OF_pci_device_filter, (void *)node))
return -ENODEV;
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (!reg)
return -ENODEV;
*bus = (reg[0] >> 16) & 0xff;
@@ -895,14 +900,14 @@ pci_process_bridge_OF_ranges(struct pci_controller *hose,
int rlen = 0, orig_rlen;
int memno = 0;
struct resource *res;
- int np, na = prom_n_addr_cells(dev);
+ int np, na = of_n_addr_cells(dev);
np = na + 5;
/* First we try to merge ranges to fix a problem with some pmacs
* that can have more than 3 ranges, fortunately using contiguous
* addresses -- BenH
*/
- dt_ranges = get_property(dev, "ranges", &rlen);
+ dt_ranges = of_get_property(dev, "ranges", &rlen);
if (!dt_ranges)
return;
/* Sanity check, though hopefully that never happens */
@@ -1006,14 +1011,19 @@ void __init
pci_create_OF_bus_map(void)
{
struct property* of_prop;
-
+ struct device_node *dn;
+
of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256);
- if (of_prop && find_path_device("/")) {
+ if (!of_prop)
+ return;
+ dn = of_find_node_by_path("/");
+ if (dn) {
memset(of_prop, -1, sizeof(struct property) + 256);
of_prop->name = "pci-OF-bus-map";
of_prop->length = 256;
- of_prop->value = (unsigned char *)&of_prop[1];
- prom_add_property(find_path_device("/"), of_prop);
+ of_prop->value = &of_prop[1];
+ prom_add_property(dn, of_prop);
+ of_node_put(dn);
}
}
@@ -1648,7 +1658,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
int i;
if (page_is_ram(pfn))
- return prot;
+ return __pgprot(prot);
prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 7e97d71a5f8..6d05a1f377b 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -61,8 +61,7 @@ void iSeries_pcibios_init(void);
LIST_HEAD(hose_list);
-struct dma_mapping_ops *pci_dma_ops;
-EXPORT_SYMBOL(pci_dma_ops);
+static struct dma_mapping_ops *pci_dma_ops;
int global_phb_number; /* Global phb counter */
@@ -70,6 +69,17 @@ int global_phb_number; /* Global phb counter */
struct pci_dev *ppc64_isabridge_dev = NULL;
EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+ pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+ return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
static void fixup_broken_pcnet32(struct pci_dev* dev)
{
if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -258,7 +268,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
const u32 *prop;
int len;
- prop = get_property(np, name, &len);
+ prop = of_get_property(np, name, &len);
if (prop && len >= 4)
return *prop;
return def;
@@ -291,7 +301,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
u32 i;
int proplen;
- addrs = get_property(node, "assigned-addresses", &proplen);
+ addrs = of_get_property(node, "assigned-addresses", &proplen);
if (!addrs)
return;
DBG(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
@@ -330,10 +340,10 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
struct pci_dev *dev;
const char *type;
- dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ dev = alloc_pci_dev();
if (!dev)
return NULL;
- type = get_property(node, "device_type", NULL);
+ type = of_get_property(node, "device_type", NULL);
if (type == NULL)
type = "";
@@ -397,7 +407,7 @@ void __devinit of_scan_bus(struct device_node *node,
while ((child = of_get_next_child(node, child)) != NULL) {
DBG(" * %s\n", child->full_name);
- reg = get_property(child, "reg", &reglen);
+ reg = of_get_property(child, "reg", &reglen);
if (reg == NULL || reglen < 20)
continue;
devfn = (reg[0] >> 8) & 0xff;
@@ -430,13 +440,13 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
DBG("of_scan_pci_bridge(%s)\n", node->full_name);
/* parse bus-range property */
- busrange = get_property(node, "bus-range", &len);
+ busrange = of_get_property(node, "bus-range", &len);
if (busrange == NULL || len != 8) {
printk(KERN_DEBUG "Can't get bus-range for PCI-PCI bridge %s\n",
node->full_name);
return;
}
- ranges = get_property(node, "ranges", &len);
+ ranges = of_get_property(node, "ranges", &len);
if (ranges == NULL) {
printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
node->full_name);
@@ -900,7 +910,7 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
unsigned int size;
int rlen = 0;
- range = get_property(isa_node, "ranges", &rlen);
+ range = of_get_property(isa_node, "ranges", &rlen);
if (range == NULL || (rlen < sizeof(struct isa_range))) {
printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
"mapping 64k\n");
@@ -947,7 +957,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
int rlen = 0;
int memno = 0;
struct resource *res;
- int np, na = prom_n_addr_cells(dev);
+ int np, na = of_n_addr_cells(dev);
unsigned long pci_addr, cpu_phys_addr;
np = na + 5;
@@ -960,7 +970,7 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
* (size depending on dev->n_addr_cells)
* cells 4+5 or 5+6: the size of the range
*/
- ranges = get_property(dev, "ranges", &rlen);
+ ranges = of_get_property(dev, "ranges", &rlen);
if (ranges == NULL)
return;
hose->io_base_phys = 0;
@@ -996,8 +1006,9 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
switch ((pci_space >> 24) & 0x3) {
case 1: /* I/O space */
- hose->io_base_phys = cpu_phys_addr;
- hose->pci_io_size = size;
+ hose->io_base_phys = cpu_phys_addr - pci_addr;
+ /* handle from 0 to top of I/O window */
+ hose->pci_io_size = pci_addr + size;
res = &hose->io_resource;
res->flags = IORESOURCE_IO;
@@ -1107,8 +1118,8 @@ static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
} else {
/* Root Bus */
res = &hose->io_resource;
- *start_phys = hose->io_base_phys;
- *start_virt = (unsigned long) hose->io_base_virt;
+ *start_phys = hose->io_base_phys + res->start;
+ *start_virt = (unsigned long) hose->io_base_virt + res->start;
if (res->end > res->start)
*size = res->end - res->start + 1;
else {
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index 68df018dae0..d7d36df9c05 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -40,7 +40,8 @@
static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
{
struct pci_controller *phb = data;
- const int *type = get_property(dn, "ibm,pci-config-space-type", NULL);
+ const int *type =
+ of_get_property(dn, "ibm,pci-config-space-type", NULL);
const u32 *regs;
struct pci_dn *pdn;
@@ -54,14 +55,14 @@ static void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
dn->data = pdn;
pdn->node = dn;
pdn->phb = phb;
- regs = get_property(dn, "reg", NULL);
+ regs = of_get_property(dn, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
pdn->busno = (regs[0] >> 16) & 0xff;
pdn->devfn = (regs[0] >> 8) & 0xff;
}
if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- const u32 *busp = get_property(dn, "linux,subbus", NULL);
+ const u32 *busp = of_get_property(dn, "linux,subbus", NULL);
if (busp)
pdn->bussubno = *busp;
}
@@ -100,7 +101,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
u32 class;
nextdn = NULL;
- classp = get_property(dn, "class-code", NULL);
+ classp = of_get_property(dn, "class-code", NULL);
class = classp ? *classp : 0;
if (pre && ((ret = pre(dn, data)) != NULL))
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 2f8e9c02c92..c96fa9bd35a 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -20,7 +20,6 @@
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-#include <asm/ide.h>
#include <asm/atomic.h>
#include <asm/checksum.h>
#include <asm/pgtable.h>
@@ -67,7 +66,6 @@ EXPORT_SYMBOL(clear_pages);
EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
EXPORT_SYMBOL(DMA_MODE_READ);
EXPORT_SYMBOL(DMA_MODE_WRITE);
-EXPORT_SYMBOL(__div64_32);
EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(transfer_to_handler);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e53b2988d1b..6e2f03566b0 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
@@ -305,9 +304,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
set_dabr(new->thread.dabr);
__get_cpu_var(current_dabr) = new->thread.dabr;
}
-
- flush_tlb_pending();
-#endif
+#endif /* CONFIG_PPC64 */
new_thread = &new->thread;
old_thread = &current->thread;
@@ -402,11 +399,11 @@ static void printbits(unsigned long val, struct regbit *bits)
}
#ifdef CONFIG_PPC64
-#define REG "%016lX"
+#define REG "%016lx"
#define REGS_PER_LINE 4
#define LAST_VOLATILE 13
#else
-#define REG "%08lX"
+#define REG "%08lx"
#define REGS_PER_LINE 8
#define LAST_VOLATILE 12
#endif
@@ -421,7 +418,7 @@ void show_regs(struct pt_regs * regs)
regs, regs->trap, print_tainted(), init_utsname()->release);
printk("MSR: "REG" ", regs->msr);
printbits(regs->msr, msr_bits);
- printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer);
+ printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer);
trap = TRAP(regs);
if (trap == 0x300 || trap == 0x600)
printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr);
@@ -572,7 +569,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
kregs->nip = *((unsigned long *)ret_from_fork);
#else
kregs->nip = (unsigned long)ret_from_fork;
- p->thread.last_syscall = -1;
#endif
return 0;
@@ -823,6 +819,35 @@ out:
return error;
}
+#ifdef CONFIG_IRQSTACKS
+static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
+ unsigned long nbytes)
+{
+ unsigned long stack_page;
+ unsigned long cpu = task_cpu(p);
+
+ /*
+ * Avoid crashing if the stack has overflowed and corrupted
+ * task_cpu(p), which is in the thread_info struct.
+ */
+ if (cpu < NR_CPUS && cpu_possible(cpu)) {
+ stack_page = (unsigned long) hardirq_ctx[cpu];
+ if (sp >= stack_page + sizeof(struct thread_struct)
+ && sp <= stack_page + THREAD_SIZE - nbytes)
+ return 1;
+
+ stack_page = (unsigned long) softirq_ctx[cpu];
+ if (sp >= stack_page + sizeof(struct thread_struct)
+ && sp <= stack_page + THREAD_SIZE - nbytes)
+ return 1;
+ }
+ return 0;
+}
+
+#else
+#define valid_irq_stack(sp, p, nb) 0
+#endif /* CONFIG_IRQSTACKS */
+
int validate_sp(unsigned long sp, struct task_struct *p,
unsigned long nbytes)
{
@@ -832,19 +857,7 @@ int validate_sp(unsigned long sp, struct task_struct *p,
&& sp <= stack_page + THREAD_SIZE - nbytes)
return 1;
-#ifdef CONFIG_IRQSTACKS
- stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
- if (sp >= stack_page + sizeof(struct thread_struct)
- && sp <= stack_page + THREAD_SIZE - nbytes)
- return 1;
-
- stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
- if (sp >= stack_page + sizeof(struct thread_struct)
- && sp <= stack_page + THREAD_SIZE - nbytes)
- return 1;
-#endif
-
- return 0;
+ return valid_irq_stack(sp, p, nbytes);
}
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 8d52b23348b..caef555f2dc 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -390,18 +390,19 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
if (allnextpp) {
pp->name = "name";
pp->length = sz;
- pp->value = (unsigned char *)(pp + 1);
+ pp->value = pp + 1;
*prev_pp = pp;
prev_pp = &pp->next;
memcpy(pp->value, ps, sz - 1);
((char *)pp->value)[sz - 1] = 0;
- DBG("fixed up name for %s -> %s\n", pathp, pp->value);
+ DBG("fixed up name for %s -> %s\n", pathp,
+ (char *)pp->value);
}
}
if (allnextpp) {
*prev_pp = NULL;
- np->name = get_property(np, "name", NULL);
- np->type = get_property(np, "device_type", NULL);
+ np->name = of_get_property(np, "name", NULL);
+ np->type = of_get_property(np, "device_type", NULL);
if (!np->name)
np->name = "<NULL>";
@@ -719,6 +720,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
const char *uname, int depth, void *data)
{
unsigned long *lprop;
+ u32 *prop;
unsigned long l;
char *p;
@@ -760,6 +762,22 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
crashk_res.end = crashk_res.start + *lprop - 1;
#endif
+#ifdef CONFIG_BLK_DEV_INITRD
+ DBG("Looking for initrd properties... ");
+ prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+ if (prop) {
+ initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+ prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+ if (prop) {
+ initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
+ initrd_below_start_ok = 1;
+ } else {
+ initrd_start = 0;
+ }
+ }
+ DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
/* Retreive command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
if (p != NULL && l > 0)
@@ -926,6 +944,12 @@ static void __init early_reserve_mem(void)
self_size = initial_boot_params->totalsize;
lmb_reserve(self_base, self_size);
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* then reserve the initrd, if any */
+ if (initrd_start && (initrd_end > initrd_start))
+ lmb_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif /* CONFIG_BLK_DEV_INITRD */
+
#ifdef CONFIG_PPC32
/*
* Handle the case where we might be booting from an old kexec
@@ -954,9 +978,6 @@ static void __init early_reserve_mem(void)
size = *(reserve_map++);
if (size == 0)
break;
- /* skip if the reservation is for the blob */
- if (base == self_base && size == self_size)
- continue;
DBG("reserving: %llx -> %llx\n", base, size);
lmb_reserve(base, size);
}
@@ -1021,102 +1042,46 @@ void __init early_init_devtree(void *params)
#undef printk
-int
-prom_n_addr_cells(struct device_node* np)
+int of_n_addr_cells(struct device_node* np)
{
const int *ip;
do {
if (np->parent)
np = np->parent;
- ip = get_property(np, "#address-cells", NULL);
+ ip = of_get_property(np, "#address-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
/* No #address-cells property for the root node, default to 1 */
return 1;
}
-EXPORT_SYMBOL(prom_n_addr_cells);
+EXPORT_SYMBOL(of_n_addr_cells);
-int
-prom_n_size_cells(struct device_node* np)
+int of_n_size_cells(struct device_node* np)
{
const int* ip;
do {
if (np->parent)
np = np->parent;
- ip = get_property(np, "#size-cells", NULL);
+ ip = of_get_property(np, "#size-cells", NULL);
if (ip != NULL)
return *ip;
} while (np->parent);
/* No #size-cells property for the root node, default to 1 */
return 1;
}
-EXPORT_SYMBOL(prom_n_size_cells);
-
-/**
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *find_devices(const char *name)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (np->name != 0 && strcasecmp(np->name, name) == 0) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_devices);
-
-/**
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *find_type_devices(const char *type)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (np->type != 0 && strcasecmp(np->type, type) == 0) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_type_devices);
-
-/**
- * Returns all nodes linked together
- */
-struct device_node *find_all_nodes(void)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- *prevp = np;
- prevp = &np->next;
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_all_nodes);
+EXPORT_SYMBOL(of_n_size_cells);
/** Checks if the given "compat" string matches one of the strings in
* the device's "compatible" property
*/
-int device_is_compatible(const struct device_node *device, const char *compat)
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
{
const char* cp;
int cplen, l;
- cp = get_property(device, "compatible", &cplen);
+ cp = of_get_property(device, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -1129,7 +1094,7 @@ int device_is_compatible(const struct device_node *device, const char *compat)
return 0;
}
-EXPORT_SYMBOL(device_is_compatible);
+EXPORT_SYMBOL(of_device_is_compatible);
/**
@@ -1143,51 +1108,13 @@ int machine_is_compatible(const char *compat)
root = of_find_node_by_path("/");
if (root) {
- rc = device_is_compatible(root, compat);
+ rc = of_device_is_compatible(root, compat);
of_node_put(root);
}
return rc;
}
EXPORT_SYMBOL(machine_is_compatible);
-/**
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *find_compatible_devices(const char *type,
- const char *compat)
-{
- struct device_node *head, **prevp, *np;
-
- prevp = &head;
- for (np = allnodes; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcasecmp(np->type, type) == 0))
- continue;
- if (device_is_compatible(np, compat)) {
- *prevp = np;
- prevp = &np->next;
- }
- }
- *prevp = NULL;
- return head;
-}
-EXPORT_SYMBOL(find_compatible_devices);
-
-/**
- * Find the device_node with a given full_name.
- */
-struct device_node *find_path_device(const char *path)
-{
- struct device_node *np;
-
- for (np = allnodes; np != 0; np = np->allnext)
- if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
- return np;
- return NULL;
-}
-EXPORT_SYMBOL(find_path_device);
-
/*******
*
* New implementation of the OF "find" APIs, return a refcounted
@@ -1280,7 +1207,7 @@ struct device_node *of_find_compatible_node(struct device_node *from,
if (type != NULL
&& !(np->type != 0 && strcasecmp(np->type, type) == 0))
continue;
- if (device_is_compatible(np, compatible) && of_node_get(np))
+ if (of_device_is_compatible(np, compatible) && of_node_get(np))
break;
}
of_node_put(from);
@@ -1527,8 +1454,8 @@ static int of_finish_dynamic_node(struct device_node *node)
int err = 0;
const phandle *ibm_phandle;
- node->name = get_property(node, "name", NULL);
- node->type = get_property(node, "device_type", NULL);
+ node->name = of_get_property(node, "name", NULL);
+ node->type = of_get_property(node, "device_type", NULL);
if (!parent) {
err = -ENODEV;
@@ -1542,7 +1469,7 @@ static int of_finish_dynamic_node(struct device_node *node)
return -ENODEV;
/* fix up new node's linux_phandle field */
- if ((ibm_phandle = get_property(node, "ibm,phandle", NULL)))
+ if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL)))
node->linux_phandle = *ibm_phandle;
out:
@@ -1605,13 +1532,13 @@ EXPORT_SYMBOL(of_find_property);
* Find a property with a given name for a given node
* and return the value.
*/
-const void *get_property(const struct device_node *np, const char *name,
+const void *of_get_property(const struct device_node *np, const char *name,
int *lenp)
{
struct property *pp = of_find_property(np,name,lenp);
return pp ? pp->value : NULL;
}
-EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(of_get_property);
/*
* Add a property to a node
@@ -1742,10 +1669,10 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
/* Check for ibm,ppc-interrupt-server#s. If it doesn't exist
* fallback to "reg" property and assume no threads
*/
- intserv = get_property(np, "ibm,ppc-interrupt-server#s",
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
&plen);
if (intserv == NULL) {
- const u32 *reg = get_property(np, "reg", NULL);
+ const u32 *reg = of_get_property(np, "reg", NULL);
if (reg == NULL)
continue;
if (*reg == hardid) {
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 4fb5938ce6d..d6047c44103 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -635,6 +635,12 @@ static void __init early_cmdline_parse(void)
/* ibm,dynamic-reconfiguration-memory property supported */
#define OV5_DRCONF_MEMORY 0x20
#define OV5_LARGE_PAGES 0x10 /* large pages supported */
+/* PCIe/MSI support. Without MSI full PCIe is not supported */
+#ifdef CONFIG_PCI_MSI
+#define OV5_MSI 0x01 /* PCIe/MSI support */
+#else
+#define OV5_MSI 0x00
+#endif /* CONFIG_PCI_MSI */
/*
* The architecture vector has an array of PVR mask/value pairs,
@@ -679,7 +685,7 @@ static unsigned char ibm_architecture_vec[] = {
/* option vector 5: PAPR/OF options */
3 - 2, /* length */
0, /* don't ignore, don't halt */
- OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY,
+ OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI,
};
/* Old method - ELF header with PT_NOTE sections */
@@ -967,7 +973,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp)
* If problems seem to show up, it would be a good start to track
* them down.
*/
-static void reserve_mem(u64 base, u64 size)
+static void __init reserve_mem(u64 base, u64 size)
{
u64 top = base + size;
unsigned long cnt = RELOC(mem_reserve_cnt);
@@ -2035,39 +2041,50 @@ static void __init fixup_device_tree_maple(void)
#endif
#ifdef CONFIG_PPC_CHRP
-/* Pegasos and BriQ lacks the "ranges" property in the isa node */
+/*
+ * Pegasos and BriQ lacks the "ranges" property in the isa node
+ * Pegasos needs decimal IRQ 14/15, not hexadecimal
+ */
static void __init fixup_device_tree_chrp(void)
{
- phandle isa;
- u32 isa_ranges[6];
+ phandle ph;
+ u32 prop[6];
u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
char *name;
int rc;
name = "/pci@80000000/isa@c";
- isa = call_prom("finddevice", 1, 1, ADDR(name));
- if (!PHANDLE_VALID(isa)) {
+ ph = call_prom("finddevice", 1, 1, ADDR(name));
+ if (!PHANDLE_VALID(ph)) {
name = "/pci@ff500000/isa@6";
- isa = call_prom("finddevice", 1, 1, ADDR(name));
+ ph = call_prom("finddevice", 1, 1, ADDR(name));
rloc = 0x01003000; /* IO space; PCI device = 6 */
}
- if (!PHANDLE_VALID(isa))
- return;
-
- rc = prom_getproplen(isa, "ranges");
- if (rc != 0 && rc != PROM_ERROR)
- return;
-
- prom_printf("Fixing up missing ISA range on Pegasos...\n");
+ if (PHANDLE_VALID(ph)) {
+ rc = prom_getproplen(ph, "ranges");
+ if (rc == 0 || rc == PROM_ERROR) {
+ prom_printf("Fixing up missing ISA range on Pegasos...\n");
+
+ prop[0] = 0x1;
+ prop[1] = 0x0;
+ prop[2] = rloc;
+ prop[3] = 0x0;
+ prop[4] = 0x0;
+ prop[5] = 0x00010000;
+ prom_setprop(ph, name, "ranges", prop, sizeof(prop));
+ }
+ }
- isa_ranges[0] = 0x1;
- isa_ranges[1] = 0x0;
- isa_ranges[2] = rloc;
- isa_ranges[3] = 0x0;
- isa_ranges[4] = 0x0;
- isa_ranges[5] = 0x00010000;
- prom_setprop(isa, name, "ranges",
- isa_ranges, sizeof(isa_ranges));
+ name = "/pci@80000000/ide@C,1";
+ ph = call_prom("finddevice", 1, 1, ADDR(name));
+ if (PHANDLE_VALID(ph)) {
+ prom_printf("Fixing up IDE interrupt on Pegasos...\n");
+ prop[0] = 14;
+ prop[1] = 0x0;
+ prop[2] = 15;
+ prop[3] = 0x0;
+ prom_setprop(ph, name, "interrupts", prop, 4*sizeof(u32));
+ }
}
#else
#define fixup_device_tree_chrp()
@@ -2142,7 +2159,7 @@ static void __init fixup_device_tree_efika(void)
3,12,0, 3,13,0, 3,14,0, 3,15,0 };
struct subst_entry efika_subst_table[] = {
{ "/", "device_type", prop_cstr("efika") },
- { "/builtin", "compatible", prop_cstr("soc") },
+ { "/builtin", "device_type", prop_cstr("soc") },
{ "/builtin/ata", "compatible", prop_cstr("mpc5200b-ata\0mpc5200-ata"), },
{ "/builtin/bestcomm", "compatible", prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") },
{ "/builtin/bestcomm", "interrupts", prop_bcomm_irq, sizeof(prop_bcomm_irq) },
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 91b443c9a48..b5c96af955c 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -68,9 +68,9 @@ static void of_bus_default_count_cells(struct device_node *dev,
int *addrc, int *sizec)
{
if (addrc)
- *addrc = prom_n_addr_cells(dev);
+ *addrc = of_n_addr_cells(dev);
if (sizec)
- *sizec = prom_n_size_cells(dev);
+ *sizec = of_n_size_cells(dev);
}
static u64 of_bus_default_map(u32 *addr, const u32 *range,
@@ -196,7 +196,7 @@ const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
return NULL;
/* Get "reg" or "assigned-addresses" property */
- prop = get_property(dev, bus->addresses, &psize);
+ prop = of_get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
@@ -438,7 +438,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
* to translate addresses that aren't supposed to be translated in
* the first place. --BenH.
*/
- ranges = get_property(parent, "ranges", &rlen);
+ ranges = of_get_property(parent, "ranges", &rlen);
if (ranges == NULL || rlen == 0) {
offset = of_read_number(addr, na);
memset(addr, 0, pna * 4);
@@ -578,7 +578,7 @@ const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
return NULL;
/* Get "reg" or "assigned-addresses" property */
- prop = get_property(dev, bus->addresses, &psize);
+ prop = of_get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
@@ -650,17 +650,17 @@ void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
/* busno is always one cell */
*busno = *(dma_window++);
- prop = get_property(dn, "ibm,#dma-address-cells", NULL);
+ prop = of_get_property(dn, "ibm,#dma-address-cells", NULL);
if (!prop)
- prop = get_property(dn, "#address-cells", NULL);
+ prop = of_get_property(dn, "#address-cells", NULL);
- cells = prop ? *(u32 *)prop : prom_n_addr_cells(dn);
+ cells = prop ? *(u32 *)prop : of_n_addr_cells(dn);
*phys = of_read_number(dma_window, cells);
dma_window += cells;
- prop = get_property(dn, "ibm,#dma-size-cells", NULL);
- cells = prop ? *(u32 *)prop : prom_n_size_cells(dn);
+ prop = of_get_property(dn, "ibm,#dma-size-cells", NULL);
+ cells = prop ? *(u32 *)prop : of_n_size_cells(dn);
*size = of_read_number(dma_window, cells);
}
@@ -680,7 +680,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
return NULL;
do {
- parp = get_property(child, "interrupt-parent", NULL);
+ parp = of_get_property(child, "interrupt-parent", NULL);
if (parp == NULL)
p = of_get_parent(child);
else {
@@ -691,7 +691,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
}
of_node_put(child);
child = p;
- } while (p && get_property(p, "#interrupt-cells", NULL) == NULL);
+ } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
return p;
}
@@ -716,7 +716,7 @@ void of_irq_map_init(unsigned int flags)
struct device_node *np;
for(np = NULL; (np = of_find_all_nodes(np)) != NULL;) {
- if (get_property(np, "interrupt-controller", NULL)
+ if (of_get_property(np, "interrupt-controller", NULL)
== NULL)
continue;
/* Skip /chosen/interrupt-controller */
@@ -755,7 +755,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
* is none, we are nice and just walk up the tree
*/
do {
- tmp = get_property(ipar, "#interrupt-cells", NULL);
+ tmp = of_get_property(ipar, "#interrupt-cells", NULL);
if (tmp != NULL) {
intsize = *tmp;
break;
@@ -779,7 +779,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
*/
old = of_node_get(ipar);
do {
- tmp = get_property(old, "#address-cells", NULL);
+ tmp = of_get_property(old, "#address-cells", NULL);
tnode = of_get_parent(old);
of_node_put(old);
old = tnode;
@@ -795,7 +795,8 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
/* Now check if cursor is an interrupt-controller and if it is
* then we are done
*/
- if (get_property(ipar, "interrupt-controller", NULL) != NULL) {
+ if (of_get_property(ipar, "interrupt-controller", NULL) !=
+ NULL) {
DBG(" -> got it !\n");
memcpy(out_irq->specifier, intspec,
intsize * sizeof(u32));
@@ -806,7 +807,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
}
/* Now look for an interrupt-map */
- imap = get_property(ipar, "interrupt-map", &imaplen);
+ imap = of_get_property(ipar, "interrupt-map", &imaplen);
/* No interrupt map, check for an interrupt parent */
if (imap == NULL) {
DBG(" -> no map, getting parent\n");
@@ -816,7 +817,7 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
imaplen /= sizeof(u32);
/* Look for a mask */
- imask = get_property(ipar, "interrupt-map-mask", NULL);
+ imask = of_get_property(ipar, "interrupt-map-mask", NULL);
/* If we were passed no "reg" property and we attempt to parse
* an interrupt-map, then #address-cells must be 0.
@@ -863,15 +864,13 @@ int of_irq_map_raw(struct device_node *parent, const u32 *intspec, u32 ointsize,
/* Get #interrupt-cells and #address-cells of new
* parent
*/
- tmp = get_property(newpar, "#interrupt-cells",
- NULL);
+ tmp = of_get_property(newpar, "#interrupt-cells", NULL);
if (tmp == NULL) {
DBG(" -> parent lacks #interrupt-cells !\n");
goto fail;
}
newintsize = *tmp;
- tmp = get_property(newpar, "#address-cells",
- NULL);
+ tmp = of_get_property(newpar, "#address-cells", NULL);
newaddrsize = (tmp == NULL) ? 0 : *tmp;
DBG(" -> newintsize=%d, newaddrsize=%d\n",
@@ -928,7 +927,7 @@ static int of_irq_map_oldworld(struct device_node *device, int index,
* everything together on these)
*/
while (device) {
- ints = get_property(device, "AAPL,interrupts", &intlen);
+ ints = of_get_property(device, "AAPL,interrupts", &intlen);
if (ints != NULL)
break;
device = device->parent;
@@ -970,13 +969,13 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
return of_irq_map_oldworld(device, index, out_irq);
/* Get the interrupts property */
- intspec = get_property(device, "interrupts", &intlen);
+ intspec = of_get_property(device, "interrupts", &intlen);
if (intspec == NULL)
return -EINVAL;
intlen /= sizeof(u32);
/* Get the reg property (if any) */
- addr = get_property(device, "reg", NULL);
+ addr = of_get_property(device, "reg", NULL);
/* Look for the interrupt parent. */
p = of_irq_find_parent(device);
@@ -984,7 +983,7 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
return -EINVAL;
/* Get size of interrupt specifier */
- tmp = get_property(p, "#interrupt-cells", NULL);
+ tmp = of_get_property(p, "#interrupt-cells", NULL);
if (tmp == NULL) {
of_node_put(p);
return -EINVAL;
@@ -1043,3 +1042,28 @@ const void *of_get_mac_address(struct device_node *np)
}
EXPORT_SYMBOL(of_get_mac_address);
+int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
+{
+ int irq = irq_of_parse_and_map(dev, index);
+
+ /* Only dereference the resource if both the
+ * resource and the irq are valid. */
+ if (r && irq != NO_IRQ) {
+ r->start = r->end = irq;
+ r->flags = IORESOURCE_IRQ;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(of_irq_to_resource);
+
+void __iomem *of_iomap(struct device_node *np, int index)
+{
+ struct resource res;
+
+ if (of_address_to_resource(np, index, &res))
+ return NULL;
+
+ return ioremap(res.start, 1 + res.end - res.start);
+}
+EXPORT_SYMBOL(of_iomap);
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index cc44c7b975a..f4f391cdd8f 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -19,7 +19,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 6cbf2ae5d7a..190b7ed1dbf 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -450,7 +450,7 @@ static int ppc_rtas_sensors_show(struct seq_file *m, void *v)
int llen, offs;
sprintf (rstr, SENSOR_PREFIX"%04d", p->token);
- loc = get_property(rtas_node, rstr, &llen);
+ loc = of_get_property(rtas_node, rstr, &llen);
/* A sensor may have multiple instances */
for (j = 0, offs = 0; j <= p->quant; j++) {
@@ -477,7 +477,7 @@ static int ppc_rtas_find_all_sensors(void)
const unsigned int *utmp;
int len, i;
- utmp = get_property(rtas_node, "rtas-sensors", &len);
+ utmp = of_get_property(rtas_node, "rtas-sensors", &len);
if (utmp == NULL) {
printk (KERN_ERR "error: could not get rtas-sensors\n");
return 1;
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 9d0735a5456..21478079828 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -192,18 +192,19 @@ void rtas_progress(char *s, unsigned short hex)
if (display_width == 0) {
display_width = 0x10;
- if ((root = find_path_device("/rtas"))) {
- if ((p = get_property(root,
+ if ((root = of_find_node_by_path("/rtas"))) {
+ if ((p = of_get_property(root,
"ibm,display-line-length", NULL)))
display_width = *p;
- if ((p = get_property(root,
+ if ((p = of_get_property(root,
"ibm,form-feed", NULL)))
form_feed = *p;
- if ((p = get_property(root,
+ if ((p = of_get_property(root,
"ibm,display-number-of-lines", NULL)))
display_lines = *p;
- row_width = get_property(root,
+ row_width = of_get_property(root,
"ibm,display-truncation-length", NULL);
+ of_node_put(root);
}
display_character = rtas_token("display-character");
set_indicator = rtas_token("set-indicator");
@@ -298,7 +299,7 @@ int rtas_token(const char *service)
const int *tokp;
if (rtas.dev == NULL)
return RTAS_UNKNOWN_SERVICE;
- tokp = get_property(rtas.dev, service, NULL);
+ tokp = of_get_property(rtas.dev, service, NULL);
return tokp ? *tokp : RTAS_UNKNOWN_SERVICE;
}
EXPORT_SYMBOL(rtas_token);
@@ -832,12 +833,12 @@ void __init rtas_initialize(void)
if (rtas.dev) {
const u32 *basep, *entryp, *sizep;
- basep = get_property(rtas.dev, "linux,rtas-base", NULL);
- sizep = get_property(rtas.dev, "rtas-size", NULL);
+ basep = of_get_property(rtas.dev, "linux,rtas-base", NULL);
+ sizep = of_get_property(rtas.dev, "rtas-size", NULL);
if (basep != NULL && sizep != NULL) {
rtas.base = *basep;
rtas.size = *sizep;
- entryp = get_property(rtas.dev,
+ entryp = of_get_property(rtas.dev,
"linux,rtas-entry", NULL);
if (entryp == NULL) /* Ugh */
rtas.entry = rtas.base;
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index ace9f4c86e6..f2286822be0 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -60,7 +60,7 @@ static int of_device_available(struct device_node * dn)
{
const char *status;
- status = get_property(dn, "status", NULL);
+ status = of_get_property(dn, "status", NULL);
if (!status)
return 1;
@@ -177,7 +177,7 @@ struct pci_ops rtas_pci_ops = {
int is_python(struct device_node *dev)
{
- const char *model = get_property(dev, "model", NULL);
+ const char *model = of_get_property(dev, "model", NULL);
if (model && strstr(model, "Python"))
return 1;
@@ -247,7 +247,7 @@ static int phb_set_bus_ranges(struct device_node *dev,
const int *bus_range;
unsigned int len;
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
return 1;
}
@@ -274,7 +274,7 @@ int __devinit rtas_setup_phb(struct pci_controller *phb)
return 0;
}
-unsigned long __init find_and_init_phbs(void)
+void __init find_and_init_phbs(void)
{
struct device_node *node;
struct pci_controller *phb;
@@ -309,18 +309,16 @@ unsigned long __init find_and_init_phbs(void)
if (of_chosen) {
const int *prop;
- prop = get_property(of_chosen,
+ prop = of_get_property(of_chosen,
"linux,pci-probe-only", NULL);
if (prop)
pci_probe_only = *prop;
- prop = get_property(of_chosen,
+ prop = of_get_property(of_chosen,
"linux,pci-assign-all-buses", NULL);
if (prop)
pci_assign_all_buses = *prop;
}
-
- return 0;
}
/* RPA-specific bits for removing PHBs */
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 89cfaf49d3d..370803722e4 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -21,7 +21,6 @@
#include <linux/delay.h>
#include <linux/initrd.h>
#include <linux/platform_device.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
#include <linux/ioport.h>
#include <linux/console.h>
@@ -304,26 +303,8 @@ struct seq_operations cpuinfo_op = {
void __init check_for_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
- const unsigned int *prop;
- int len;
-
- DBG(" -> check_for_initrd()\n");
-
- if (of_chosen) {
- prop = get_property(of_chosen, "linux,initrd-start", &len);
- if (prop != NULL) {
- initrd_start = (unsigned long)
- __va(of_read_ulong(prop, len / 4));
- prop = get_property(of_chosen,
- "linux,initrd-end", &len);
- if (prop != NULL) {
- initrd_end = (unsigned long)
- __va(of_read_ulong(prop, len / 4));
- initrd_below_start_ok = 1;
- } else
- initrd_start = 0;
- }
- }
+ DBG(" -> check_for_initrd() initrd_start=0x%lx initrd_end=0x%lx\n",
+ initrd_start, initrd_end);
/* If we were passed an initrd, set the ROOT_DEV properly if the values
* look sensible. If not, clear initrd reference.
@@ -371,11 +352,12 @@ void __init smp_setup_cpu_maps(void)
const int *intserv;
int j, len = sizeof(u32), nthreads = 1;
- intserv = get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
+ &len);
if (intserv)
nthreads = len / sizeof(int);
else {
- intserv = get_property(dn, "reg", NULL);
+ intserv = of_get_property(dn, "reg", NULL);
if (!intserv)
intserv = &cpu; /* assume logical == phys */
}
@@ -398,10 +380,10 @@ void __init smp_setup_cpu_maps(void)
int num_addr_cell, num_size_cell, maxcpus;
const unsigned int *ireg;
- num_addr_cell = prom_n_addr_cells(dn);
- num_size_cell = prom_n_size_cells(dn);
+ num_addr_cell = of_n_addr_cells(dn);
+ num_size_cell = of_n_size_cells(dn);
- ireg = get_property(dn, "ibm,lrdr-capacity", NULL);
+ ireg = of_get_property(dn, "ibm,lrdr-capacity", NULL);
if (!ireg)
goto out;
@@ -496,11 +478,39 @@ void probe_machine(void)
printk(KERN_INFO "Using %s machine description\n", ppc_md.name);
}
+/* Match a class of boards, not a specific device configuration. */
int check_legacy_ioport(unsigned long base_port)
{
- if (ppc_md.check_legacy_ioport == NULL)
- return 0;
- return ppc_md.check_legacy_ioport(base_port);
+ struct device_node *parent, *np = NULL;
+ int ret = -ENODEV;
+
+ switch(base_port) {
+ case I8042_DATA_REG:
+ np = of_find_node_by_type(NULL, "8042");
+ break;
+ case FDC_BASE: /* FDC1 */
+ np = of_find_node_by_type(NULL, "fdc");
+ break;
+#ifdef CONFIG_PPC_PREP
+ case _PIDXR:
+ case _PNPWRP:
+ case PNPBIOS_BASE:
+ /* implement me */
+#endif
+ default:
+ /* ipmi is supposed to fail here */
+ break;
+ }
+ if (!np)
+ return ret;
+ parent = of_get_parent(np);
+ if (parent) {
+ if (strcmp(parent->type, "isa") == 0)
+ ret = 0;
+ of_node_put(parent);
+ }
+ of_node_put(np);
+ return ret;
}
EXPORT_SYMBOL(check_legacy_ioport);
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 44a6a3c47fe..35f8f443c14 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -92,7 +92,8 @@ unsigned long __init early_init(unsigned long dt_ptr)
/* First zero the BSS -- use memset_io, some platforms don't have
* caches on yet */
- memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
+ memset_io((void __iomem *)PTRRELOC(&__bss_start), 0,
+ __bss_stop - __bss_start);
/*
* Identify the CPU type and fix up code sections
@@ -195,18 +196,22 @@ EXPORT_SYMBOL(nvram_sync);
#endif /* CONFIG_NVRAM */
-static struct cpu cpu_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
int __init ppc_init(void)
{
- int i;
+ int cpu;
/* clear the progress line */
- if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff);
+ if (ppc_md.progress)
+ ppc_md.progress(" ", 0xffff);
/* register CPU devices */
- for_each_possible_cpu(i)
- register_cpu(&cpu_devices[i], i);
+ for_each_possible_cpu(cpu) {
+ struct cpu *c = &per_cpu(cpu_devices, cpu);
+ c->hotpluggable = 1;
+ register_cpu(c, cpu);
+ }
/* call platform init */
if (ppc_md.init != NULL) {
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 3733de30e84..6018178708a 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -20,7 +20,6 @@
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/initrd.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
#include <linux/ioport.h>
#include <linux/console.h>
@@ -110,7 +109,7 @@ static void check_smt_enabled(void)
dn = of_find_node_by_path("/options");
if (dn) {
- smt_option = get_property(dn, "ibm,smt-enabled", NULL);
+ smt_option = of_get_property(dn, "ibm,smt-enabled", NULL);
if (smt_option) {
if (!strcmp(smt_option, "on"))
@@ -305,10 +304,10 @@ static void __init initialize_cache_info(void)
size = 0;
lsize = cur_cpu_spec->dcache_bsize;
- sizep = get_property(np, "d-cache-size", NULL);
+ sizep = of_get_property(np, "d-cache-size", NULL);
if (sizep != NULL)
size = *sizep;
- lsizep = get_property(np, dc, NULL);
+ lsizep = of_get_property(np, dc, NULL);
if (lsizep != NULL)
lsize = *lsizep;
if (sizep == 0 || lsizep == 0)
@@ -322,10 +321,10 @@ static void __init initialize_cache_info(void)
size = 0;
lsize = cur_cpu_spec->icache_bsize;
- sizep = get_property(np, "i-cache-size", NULL);
+ sizep = of_get_property(np, "i-cache-size", NULL);
if (sizep != NULL)
size = *sizep;
- lsizep = get_property(np, ic, NULL);
+ lsizep = of_get_property(np, ic, NULL);
if (lsizep != NULL)
lsize = *lsizep;
if (sizep == 0 || lsizep == 0)
@@ -583,14 +582,14 @@ void __init setup_per_cpu_areas(void)
char *ptr;
/* Copy section for each CPU (we discard the original) */
- size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
+ size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
#ifdef CONFIG_MODULES
if (size < PERCPU_ENOUGH_ROOM)
size = PERCPU_ENOUGH_ROOM;
#endif
for_each_possible_cpu(i) {
- ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
+ ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
if (!ptr)
panic("Cannot allocate cpu data for CPU %d\n", i);
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 6b405a3f43f..dd1dca5bfa8 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -20,7 +20,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index f72e8e823d7..1ce0ae3f6ff 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -15,7 +15,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 924d692bc8f..22f1ef1b310 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -176,10 +176,10 @@ static struct call_data_struct {
#define SMP_CALL_TIMEOUT 8
/*
- * This function sends a 'generic call function' IPI to all other CPUs
- * in the system.
+ * These functions send a 'generic call function' IPI to other online
+ * CPUS in the system.
*
- * [SUMMARY] Run a function on all other CPUs.
+ * [SUMMARY] Run a function on other CPUs.
* <func> The function to run. This must be fast and non-blocking.
* <info> An arbitrary pointer to pass to the function.
* <nonatomic> currently unused.
@@ -190,18 +190,26 @@ static struct call_data_struct {
* You must not call this function with disabled interrupts or from a
* hardware interrupt handler or from a bottom half handler.
*/
-int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
- int wait)
-{
+int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic,
+ int wait, cpumask_t map)
+{
struct call_data_struct data;
- int ret = -1, cpus;
+ int ret = -1, num_cpus;
+ int cpu;
u64 timeout;
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
+ /* remove 'self' from the map */
+ if (cpu_isset(smp_processor_id(), map))
+ cpu_clear(smp_processor_id(), map);
+
+ /* sanity check the map, remove any non-online processors. */
+ cpus_and(map, map, cpu_online_map);
+
if (unlikely(smp_ops == NULL))
- return -1;
+ return ret;
data.func = func;
data.info = info;
@@ -213,40 +221,42 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
spin_lock(&call_lock);
/* Must grab online cpu count with preempt disabled, otherwise
* it can change. */
- cpus = num_online_cpus() - 1;
- if (!cpus) {
+ num_cpus = num_online_cpus() - 1;
+ if (!num_cpus || cpus_empty(map)) {
ret = 0;
goto out;
}
call_data = &data;
smp_wmb();
- /* Send a message to all other CPUs and wait for them to respond */
- smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_CALL_FUNCTION);
+ /* Send a message to all CPUs in the map */
+ for_each_cpu_mask(cpu, map)
+ smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec;
- /* Wait for response */
- while (atomic_read(&data.started) != cpus) {
+ /* Wait for indication that they have received the message */
+ while (atomic_read(&data.started) != num_cpus) {
HMT_low();
if (get_tb() >= timeout) {
printk("smp_call_function on cpu %d: other cpus not "
- "responding (%d)\n", smp_processor_id(),
- atomic_read(&data.started));
+ "responding (%d)\n", smp_processor_id(),
+ atomic_read(&data.started));
debugger(NULL);
goto out;
}
}
+ /* optionally wait for the CPUs to complete */
if (wait) {
- while (atomic_read(&data.finished) != cpus) {
+ while (atomic_read(&data.finished) != num_cpus) {
HMT_low();
if (get_tb() >= timeout) {
printk("smp_call_function on cpu %d: other "
- "cpus not finishing (%d/%d)\n",
- smp_processor_id(),
- atomic_read(&data.finished),
- atomic_read(&data.started));
+ "cpus not finishing (%d/%d)\n",
+ smp_processor_id(),
+ atomic_read(&data.finished),
+ atomic_read(&data.started));
debugger(NULL);
goto out;
}
@@ -262,8 +272,29 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
return ret;
}
+int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
+ int wait)
+{
+ return smp_call_function_map(func,info,nonatomic,wait,cpu_online_map);
+}
EXPORT_SYMBOL(smp_call_function);
+int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int nonatomic,
+ int wait)
+{
+ cpumask_t map=CPU_MASK_NONE;
+
+ if (!cpu_online(cpu))
+ return -EINVAL;
+
+ if (cpu == smp_processor_id())
+ return -EBUSY;
+
+ cpu_set(cpu, map);
+ return smp_call_function_map(func,info,nonatomic,wait,map);
+}
+EXPORT_SYMBOL(smp_call_function_single);
+
void smp_call_function_interrupt(void)
{
void (*func) (void *info);
@@ -428,10 +459,6 @@ void generic_mach_cpu_die(void)
smp_wmb();
while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
cpu_relax();
-
-#ifdef CONFIG_PPC64
- flush_tlb_pending();
-#endif
cpu_set(cpu, cpu_online_map);
local_irq_enable();
}
diff --git a/arch/powerpc/kernel/suspend.c b/arch/powerpc/kernel/suspend.c
new file mode 100644
index 00000000000..8cee5710754
--- /dev/null
+++ b/arch/powerpc/kernel/suspend.c
@@ -0,0 +1,24 @@
+/*
+ * Suspend support specific for power.
+ *
+ * Distribute under GPLv2
+ *
+ * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ * Copyright (c) 2001 Patrick Mochel <mochel@osdl.org>
+ */
+
+#include <asm/page.h>
+
+/* References to section boundaries */
+extern const void __nosave_begin, __nosave_end;
+
+/*
+ * pfn_is_nosave - check if given pfn is in the 'nosave' section
+ */
+
+int pfn_is_nosave(unsigned long pfn)
+{
+ unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+ unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
+ return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
new file mode 100644
index 00000000000..064a7ba4f02
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp.c
@@ -0,0 +1,43 @@
+/*
+ * Common powerpc suspend code for 32 and 64 bits
+ *
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <asm/suspend.h>
+#include <asm/system.h>
+#include <asm/current.h>
+#include <asm/mmu_context.h>
+
+void save_processor_state(void)
+{
+ /*
+ * flush out all the special registers so we don't need
+ * to save them in the snapshot
+ */
+ flush_fp_to_thread(current);
+ flush_altivec_to_thread(current);
+ flush_spe_to_thread(current);
+
+#ifdef CONFIG_PPC64
+ hard_irq_disable();
+#endif
+
+}
+
+void restore_processor_state(void)
+{
+#ifdef CONFIG_PPC32
+ set_context(current->active_mm->context.id, current->active_mm->pgd);
+#endif
+
+#ifdef CONFIG_PPC64
+ hard_irq_enable();
+#endif
+}
diff --git a/arch/powerpc/kernel/swsusp_64.c b/arch/powerpc/kernel/swsusp_64.c
new file mode 100644
index 00000000000..6f3f0697274
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_64.c
@@ -0,0 +1,24 @@
+/*
+ * PowerPC 64-bit swsusp implementation
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <asm/system.h>
+#include <asm/iommu.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+void do_after_copyback(void)
+{
+ iommu_restore();
+ touch_softlockup_watchdog();
+ mb();
+}
+
+void _iommu_save(void)
+{
+ iommu_save();
+}
diff --git a/arch/powerpc/kernel/swsusp_asm64.S b/arch/powerpc/kernel/swsusp_asm64.S
new file mode 100644
index 00000000000..e092c3cbdb9
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_asm64.S
@@ -0,0 +1,228 @@
+/*
+ * PowerPC 64-bit swsusp implementation
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_r1 0x00 /* stack pointer */
+#define SL_PC 0x08
+#define SL_MSR 0x10
+#define SL_SDR1 0x18
+#define SL_XER 0x20
+#define SL_TB 0x40
+#define SL_r2 0x48
+#define SL_CR 0x50
+#define SL_LR 0x58
+#define SL_r12 0x60
+#define SL_r13 0x68
+#define SL_r14 0x70
+#define SL_r15 0x78
+#define SL_r16 0x80
+#define SL_r17 0x88
+#define SL_r18 0x90
+#define SL_r19 0x98
+#define SL_r20 0xa0
+#define SL_r21 0xa8
+#define SL_r22 0xb0
+#define SL_r23 0xb8
+#define SL_r24 0xc0
+#define SL_r25 0xc8
+#define SL_r26 0xd0
+#define SL_r27 0xd8
+#define SL_r28 0xe0
+#define SL_r29 0xe8
+#define SL_r30 0xf0
+#define SL_r31 0xf8
+#define SL_SIZE SL_r31+8
+
+/* these macros rely on the save area being
+ * pointed to by r11 */
+#define SAVE_SPECIAL(special) \
+ mf##special r0 ;\
+ std r0, SL_##special(r11)
+#define RESTORE_SPECIAL(special) \
+ ld r0, SL_##special(r11) ;\
+ mt##special r0
+#define SAVE_REGISTER(reg) \
+ std reg, SL_##reg(r11)
+#define RESTORE_REGISTER(reg) \
+ ld reg, SL_##reg(r11)
+
+/* space for storing cpu state */
+ .section .data
+ .align 5
+swsusp_save_area:
+ .space SL_SIZE
+
+ .section ".toc","aw"
+swsusp_save_area_ptr:
+ .tc swsusp_save_area[TC],swsusp_save_area
+restore_pblist_ptr:
+ .tc restore_pblist[TC],restore_pblist
+
+ .section .text
+ .align 5
+_GLOBAL(swsusp_arch_suspend)
+ ld r11,swsusp_save_area_ptr@toc(r2)
+ SAVE_SPECIAL(LR)
+ SAVE_REGISTER(r1)
+ SAVE_SPECIAL(CR)
+ SAVE_SPECIAL(TB)
+ SAVE_REGISTER(r2)
+ SAVE_REGISTER(r12)
+ SAVE_REGISTER(r13)
+ SAVE_REGISTER(r14)
+ SAVE_REGISTER(r15)
+ SAVE_REGISTER(r16)
+ SAVE_REGISTER(r17)
+ SAVE_REGISTER(r18)
+ SAVE_REGISTER(r19)
+ SAVE_REGISTER(r20)
+ SAVE_REGISTER(r21)
+ SAVE_REGISTER(r22)
+ SAVE_REGISTER(r23)
+ SAVE_REGISTER(r24)
+ SAVE_REGISTER(r25)
+ SAVE_REGISTER(r26)
+ SAVE_REGISTER(r27)
+ SAVE_REGISTER(r28)
+ SAVE_REGISTER(r29)
+ SAVE_REGISTER(r30)
+ SAVE_REGISTER(r31)
+ SAVE_SPECIAL(MSR)
+ SAVE_SPECIAL(SDR1)
+ SAVE_SPECIAL(XER)
+
+ /* we push the stack up 128 bytes but don't store the
+ * stack pointer on the stack like a real stackframe */
+ addi r1,r1,-128
+
+ bl _iommu_save
+ bl swsusp_save
+
+ /* restore LR */
+ ld r11,swsusp_save_area_ptr@toc(r2)
+ RESTORE_SPECIAL(LR)
+ addi r1,r1,128
+
+ blr
+
+/* Resume code */
+_GLOBAL(swsusp_arch_resume)
+ /* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+ DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ sync
+
+ ld r12,restore_pblist_ptr@toc(r2)
+ ld r12,0(r12)
+
+ cmpdi r12,0
+ beq- nothing_to_copy
+ li r15,512
+copyloop:
+ ld r13,pbe_address(r12)
+ ld r14,pbe_orig_address(r12)
+
+ mtctr r15
+ li r10,0
+copy_page_loop:
+ ldx r0,r10,r13
+ stdx r0,r10,r14
+ addi r10,r10,8
+ bdnz copy_page_loop
+
+ ld r12,pbe_next(r12)
+ cmpdi r12,0
+ bne+ copyloop
+nothing_to_copy:
+
+ /* flush caches */
+ lis r3, 0x10
+ mtctr r3
+ li r3, 0
+ ori r3, r3, CONFIG_KERNEL_START>>48
+ li r0, 48
+ sld r3, r3, r0
+ li r0, 0
+1:
+ dcbf r0,r3
+ addi r3,r3,0x20
+ bdnz 1b
+
+ sync
+
+ tlbia
+
+ ld r11,swsusp_save_area_ptr@toc(r2)
+
+ RESTORE_SPECIAL(CR)
+
+ /* restore timebase */
+ /* load saved tb */
+ ld r1, SL_TB(r11)
+ /* get upper 32 bits of it */
+ srdi r2, r1, 32
+ /* clear tb lower to avoid wrap */
+ li r0, 0
+ mttbl r0
+ /* set tb upper */
+ mttbu r2
+ /* set tb lower */
+ mttbl r1
+
+ /* restore registers */
+ RESTORE_REGISTER(r1)
+ RESTORE_REGISTER(r2)
+ RESTORE_REGISTER(r12)
+ RESTORE_REGISTER(r13)
+ RESTORE_REGISTER(r14)
+ RESTORE_REGISTER(r15)
+ RESTORE_REGISTER(r16)
+ RESTORE_REGISTER(r17)
+ RESTORE_REGISTER(r18)
+ RESTORE_REGISTER(r19)
+ RESTORE_REGISTER(r20)
+ RESTORE_REGISTER(r21)
+ RESTORE_REGISTER(r22)
+ RESTORE_REGISTER(r23)
+ RESTORE_REGISTER(r24)
+ RESTORE_REGISTER(r25)
+ RESTORE_REGISTER(r26)
+ RESTORE_REGISTER(r27)
+ RESTORE_REGISTER(r28)
+ RESTORE_REGISTER(r29)
+ RESTORE_REGISTER(r30)
+ RESTORE_REGISTER(r31)
+ /* can't use RESTORE_SPECIAL(MSR) */
+ ld r0, SL_MSR(r11)
+ mtmsrd r0, 0
+ RESTORE_SPECIAL(SDR1)
+ RESTORE_SPECIAL(XER)
+
+ sync
+
+ addi r1,r1,-128
+ bl slb_flush_and_rebolt
+ bl do_after_copyback
+ addi r1,r1,128
+
+ ld r11,swsusp_save_area_ptr@toc(r2)
+ RESTORE_SPECIAL(LR)
+
+ li r3, 0
+ blr
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 673e8d9df7f..047246ad4f6 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -53,10 +53,6 @@
#include <asm/ppc-pci.h>
#include <asm/syscalls.h>
-/* readdir & getdents */
-#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
-
struct old_linux_dirent32 {
u32 d_ino;
u32 d_offset;
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index d358866b880..fc6647d332c 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -24,7 +24,6 @@
#include <linux/syscalls.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index d57818aea08..68991c2d4a1 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -66,16 +66,17 @@ static int __init smt_setup(void)
if (!cpu_has_feature(CPU_FTR_SMT))
return -ENODEV;
- options = find_path_device("/options");
+ options = of_find_node_by_path("/options");
if (!options)
return -ENODEV;
- val = get_property(options, "ibm,smt-snooze-delay", NULL);
+ val = of_get_property(options, "ibm,smt-snooze-delay", NULL);
if (!smt_snooze_cmdline && val) {
for_each_possible_cpu(cpu)
per_cpu(smt_snooze_delay, cpu) = *val;
}
+ of_node_put(options);
return 0;
}
__initcall(smt_setup);
@@ -189,12 +190,12 @@ SYSFS_PMCSETUP(purr, SPRN_PURR);
SYSFS_PMCSETUP(spurr, SPRN_SPURR);
SYSFS_PMCSETUP(dscr, SPRN_DSCR);
-SYSFS_PMCSETUP(pa6t_pmc0, PA6T_SPRN_PMC0);
-SYSFS_PMCSETUP(pa6t_pmc1, PA6T_SPRN_PMC1);
-SYSFS_PMCSETUP(pa6t_pmc2, PA6T_SPRN_PMC2);
-SYSFS_PMCSETUP(pa6t_pmc3, PA6T_SPRN_PMC3);
-SYSFS_PMCSETUP(pa6t_pmc4, PA6T_SPRN_PMC4);
-SYSFS_PMCSETUP(pa6t_pmc5, PA6T_SPRN_PMC5);
+SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
+SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
+SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
+SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
+SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
+SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
@@ -341,10 +342,12 @@ static int __cpuinit sysfs_cpu_notify(struct notifier_block *self,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
register_cpu_online(cpu);
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
unregister_cpu_online(cpu);
break;
#endif
@@ -498,4 +501,4 @@ static int __init topology_init(void)
return 0;
}
-__initcall(topology_init);
+subsys_initcall(topology_init);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f6f0c6b07c4..7cedef8f5f7 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -834,7 +834,7 @@ static int __init get_freq(char *name, int cells, unsigned long *val)
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = get_property(cpu, name, NULL);
+ fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
*val = of_read_ulong(fp, cells);
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 17724fb2067..bf6445ac9f1 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -33,8 +33,8 @@
#include <linux/kexec.h>
#include <linux/backlight.h>
#include <linux/bug.h>
+#include <linux/kdebug.h>
-#include <asm/kdebug.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -72,39 +72,15 @@ EXPORT_SYMBOL(__debugger_dabr_match);
EXPORT_SYMBOL(__debugger_fault_handler);
#endif
-ATOMIC_NOTIFIER_HEAD(powerpc_die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&powerpc_die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&powerpc_die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
/*
* Trap & Exception support
*/
-static DEFINE_SPINLOCK(die_lock);
-
-int die(const char *str, struct pt_regs *regs, long err)
-{
- static int die_counter;
-
- if (debugger(regs))
- return 1;
-
- console_verbose();
- spin_lock_irq(&die_lock);
- bust_spinlocks(1);
#ifdef CONFIG_PMAC_BACKLIGHT
+static void pmac_backlight_unblank(void)
+{
mutex_lock(&pmac_backlight_mutex);
- if (machine_is(powermac) && pmac_backlight) {
+ if (pmac_backlight) {
struct backlight_properties *props;
props = &pmac_backlight->props;
@@ -113,26 +89,67 @@ int die(const char *str, struct pt_regs *regs, long err)
backlight_update_status(pmac_backlight);
}
mutex_unlock(&pmac_backlight_mutex);
+}
+#else
+static inline void pmac_backlight_unblank(void) { }
#endif
- printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
+
+int die(const char *str, struct pt_regs *regs, long err)
+{
+ static struct {
+ spinlock_t lock;
+ u32 lock_owner;
+ int lock_owner_depth;
+ } die = {
+ .lock = __SPIN_LOCK_UNLOCKED(die.lock),
+ .lock_owner = -1,
+ .lock_owner_depth = 0
+ };
+ static int die_counter;
+ unsigned long flags;
+
+ if (debugger(regs))
+ return 1;
+
+ oops_enter();
+
+ if (die.lock_owner != raw_smp_processor_id()) {
+ console_verbose();
+ spin_lock_irqsave(&die.lock, flags);
+ die.lock_owner = smp_processor_id();
+ die.lock_owner_depth = 0;
+ bust_spinlocks(1);
+ if (machine_is(powermac))
+ pmac_backlight_unblank();
+ } else {
+ local_save_flags(flags);
+ }
+
+ if (++die.lock_owner_depth < 3) {
+ printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
#ifdef CONFIG_PREEMPT
- printk("PREEMPT ");
+ printk("PREEMPT ");
#endif
#ifdef CONFIG_SMP
- printk("SMP NR_CPUS=%d ", NR_CPUS);
+ printk("SMP NR_CPUS=%d ", NR_CPUS);
#endif
#ifdef CONFIG_DEBUG_PAGEALLOC
- printk("DEBUG_PAGEALLOC ");
+ printk("DEBUG_PAGEALLOC ");
#endif
#ifdef CONFIG_NUMA
- printk("NUMA ");
+ printk("NUMA ");
#endif
- printk("%s\n", ppc_md.name ? "" : ppc_md.name);
+ printk("%s\n", ppc_md.name ? ppc_md.name : "");
+
+ print_modules();
+ show_regs(regs);
+ } else {
+ printk("Recursive die() failure, output suppressed\n");
+ }
- print_modules();
- show_regs(regs);
bust_spinlocks(0);
- spin_unlock_irq(&die_lock);
+ die.lock_owner = -1;
+ spin_unlock_irqrestore(&die.lock, flags);
if (kexec_should_crash(current) ||
kexec_sr_activated(smp_processor_id()))
@@ -145,6 +162,7 @@ int die(const char *str, struct pt_regs *regs, long err)
if (panic_on_oops)
panic("Fatal exception");
+ oops_exit();
do_exit(err);
return 0;
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index 7e0971868fc..87703df8750 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -51,6 +51,9 @@ void __init udbg_early_init(void)
udbg_init_pas_realmode();
#elif defined(CONFIG_BOOTX_TEXT)
udbg_init_btext();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_44x)
+ /* PPC44x debug */
+ udbg_init_44x_as1();
#endif
}
@@ -142,29 +145,22 @@ static void udbg_console_write(struct console *con, const char *s,
static struct console udbg_console = {
.name = "udbg",
.write = udbg_console_write,
- .flags = CON_PRINTBUFFER | CON_ENABLED,
+ .flags = CON_PRINTBUFFER | CON_ENABLED | CON_BOOT,
.index = -1,
};
static int early_console_initialized;
-void __init disable_early_printk(void)
-{
- if (!early_console_initialized)
- return;
- if (strstr(boot_command_line, "udbg-immortal")) {
- printk(KERN_INFO "early console immortal !\n");
- return;
- }
- unregister_console(&udbg_console);
- early_console_initialized = 0;
-}
-
/* called by setup_system */
void register_early_udbg_console(void)
{
if (early_console_initialized)
return;
+
+ if (strstr(boot_command_line, "udbg-immortal")) {
+ printk(KERN_INFO "early console immortal !\n");
+ udbg_console.flags &= ~CON_BOOT;
+ }
early_console_initialized = 1;
register_console(&udbg_console);
}
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index a963f657222..7afab5bcd61 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -191,3 +191,26 @@ void udbg_init_pas_realmode(void)
udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_MAPLE */
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_44x
+#include <platforms/44x/44x.h>
+
+static void udbg_44x_as1_putc(char c)
+{
+ if (udbg_comport) {
+ while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+ /* wait for idle */;
+ as1_writeb(c, &udbg_comport->thr); eieio();
+ if (c == '\n')
+ udbg_44x_as1_putc('\r');
+ }
+}
+
+void __init udbg_init_44x_as1(void)
+{
+ udbg_comport =
+ (volatile struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR;
+
+ udbg_putc = udbg_44x_as1_putc;
+}
+#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index e46c31b3664..4245579edb4 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/slab.h>
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 2968ffeafdb..62c1bc12ea3 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -37,7 +37,7 @@
#include <asm/iseries/hv_call_xm.h>
#include <asm/iseries/iommu.h>
-extern struct subsystem devices_subsys; /* needed for vio_find_name() */
+extern struct kset devices_subsys; /* needed for vio_find_name() */
static struct vio_dev vio_bus_device = { /* fake "parent" device */
.name = vio_bus_device.dev.bus_id,
@@ -81,7 +81,7 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
struct iommu_table *tbl;
unsigned long offset, size;
- dma_window = get_property(dev->dev.archdata.of_node,
+ dma_window = of_get_property(dev->dev.archdata.of_node,
"ibm,my-dma-window", NULL);
if (!dma_window)
return NULL;
@@ -117,7 +117,7 @@ static const struct vio_device_id *vio_match_device(
{
while (ids->type[0] != '\0') {
if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) &&
- device_is_compatible(dev->dev.archdata.of_node,
+ of_device_is_compatible(dev->dev.archdata.of_node,
ids->compat))
return ids;
ids++;
@@ -226,7 +226,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
return NULL;
}
- unit_address = get_property(of_node, "reg", NULL);
+ unit_address = of_get_property(of_node, "reg", NULL);
if (unit_address == NULL) {
printk(KERN_WARNING "%s: node %s missing 'reg'\n",
__FUNCTION__,
@@ -246,7 +246,7 @@ struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
viodev->type = of_node->type;
viodev->unit_address = *unit_address;
if (firmware_has_feature(FW_FEATURE_ISERIES)) {
- unit_address = get_property(of_node,
+ unit_address = of_get_property(of_node,
"linux,unit_address", NULL);
if (unit_address != NULL)
viodev->unit_address = *unit_address;
@@ -308,7 +308,7 @@ static int __init vio_bus_init(void)
return err;
}
- node_vroot = find_devices("vdevice");
+ node_vroot = of_find_node_by_name(NULL, "vdevice");
if (node_vroot) {
struct device_node *of_node;
@@ -322,6 +322,7 @@ static int __init vio_bus_init(void)
__FUNCTION__, of_node);
vio_register_device_node(of_node);
}
+ of_node_put(node_vroot);
}
return 0;
@@ -377,7 +378,7 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
dn = dev->archdata.of_node;
if (!dn)
return -ENODEV;
- cp = get_property(dn, "compatible", &length);
+ cp = of_get_property(dn, "compatible", &length);
if (!cp)
return -ENODEV;
@@ -406,12 +407,12 @@ struct bus_type vio_bus_type = {
* @which: The property/attribute to be extracted.
* @length: Pointer to length of returned data size (unused if NULL).
*
- * Calls prom.c's get_property() to return the value of the
+ * Calls prom.c's of_get_property() to return the value of the
* attribute specified by @which
*/
const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
{
- return get_property(vdev->dev.archdata.of_node, which, length);
+ return of_get_property(vdev->dev.archdata.of_node, which, length);
}
EXPORT_SYMBOL(vio_get_attribute);
@@ -426,7 +427,7 @@ static struct vio_dev *vio_find_name(const char *kobj_name)
{
struct kobject *found;
- found = kset_find_obj(&devices_subsys.kset, kobj_name);
+ found = kset_find_obj(&devices_subsys, kobj_name);
if (!found)
return NULL;
@@ -443,7 +444,7 @@ struct vio_dev *vio_find_node(struct device_node *vnode)
char kobj_name[BUS_ID_SIZE];
/* construct the kobject name from the device node */
- unit_address = get_property(vnode, "reg", NULL);
+ unit_address = of_get_property(vnode, "reg", NULL);
if (!unit_address)
return NULL;
snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 7eefeb4a30e..13206731314 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -139,11 +139,7 @@ SECTIONS
__initramfs_end = .;
}
#endif
-#ifdef CONFIG_PPC32
- . = ALIGN(32);
-#else
- . = ALIGN(128);
-#endif
+ . = ALIGN(PAGE_SIZE);
.data.percpu : {
__per_cpu_start = .;
*(.data.percpu)
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index a6b54cb97c4..25ec5378afa 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -24,7 +24,7 @@ _GLOBAL(__copy_tofrom_user)
dcbt 0,r4
beq .Lcopy_page_4K
andi. r6,r6,7
- mtcrf 0x01,r5
+ PPC_MTOCRF 0x01,r5
blt cr1,.Lshort_copy
bne .Ldst_unaligned
.Ldst_aligned:
@@ -135,7 +135,7 @@ _GLOBAL(__copy_tofrom_user)
b .Ldo_tail
.Ldst_unaligned:
- mtcrf 0x01,r6 /* put #bytes to 8B bdry into cr7 */
+ PPC_MTOCRF 0x01,r6 /* put #bytes to 8B bdry into cr7 */
subf r5,r6,r5
li r7,0
cmpldi r1,r5,16
@@ -150,7 +150,7 @@ _GLOBAL(__copy_tofrom_user)
2: bf cr7*4+1,3f
37: lwzx r0,r7,r4
83: stwx r0,r7,r3
-3: mtcrf 0x01,r5
+3: PPC_MTOCRF 0x01,r5
add r4,r6,r4
add r3,r6,r3
b .Ldst_aligned
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c
index 48f3d13a3de..6656d47841d 100644
--- a/arch/powerpc/lib/dma-noncoherent.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -306,13 +306,15 @@ EXPORT_SYMBOL(__dma_free_coherent);
static int __init dma_alloc_init(void)
{
pgd_t *pgd;
+ pud_t *pud;
pmd_t *pmd;
pte_t *pte;
int ret = 0;
do {
pgd = pgd_offset(&init_mm, CONSISTENT_BASE);
- pmd = pmd_alloc(&init_mm, pgd, CONSISTENT_BASE);
+ pud = pud_alloc(&init_mm, pgd, CONSISTENT_BASE);
+ pmd = pmd_alloc(&init_mm, pud, CONSISTENT_BASE);
if (!pmd) {
printk(KERN_ERR "%s: no pmd tables\n", __func__);
ret = -ENOMEM;
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
index 80b482ca30d..79d0fa3a470 100644
--- a/arch/powerpc/lib/locks.c
+++ b/arch/powerpc/lib/locks.c
@@ -43,9 +43,11 @@ void __spin_yield(raw_spinlock_t *lock)
if (firmware_has_feature(FW_FEATURE_ISERIES))
HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
else
plpar_hcall_norets(H_CONFER,
get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
}
/*
@@ -72,9 +74,11 @@ void __rw_yield(raw_rwlock_t *rw)
if (firmware_has_feature(FW_FEATURE_ISERIES))
HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc,
((u64)holder_cpu << 32) | yield_count);
+#ifdef CONFIG_PPC_SPLPAR
else
plpar_hcall_norets(H_CONFER,
get_hard_smp_processor_id(holder_cpu), yield_count);
+#endif
}
#endif
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
index 68df20283ff..11ce045e21f 100644
--- a/arch/powerpc/lib/mem_64.S
+++ b/arch/powerpc/lib/mem_64.S
@@ -19,7 +19,7 @@ _GLOBAL(memset)
rlwimi r4,r4,16,0,15
cmplw cr1,r5,r0 /* do we get that far? */
rldimi r4,r4,32,0
- mtcrf 1,r0
+ PPC_MTOCRF 1,r0
mr r6,r3
blt cr1,8f
beq+ 3f /* if already 8-byte aligned */
@@ -49,7 +49,7 @@ _GLOBAL(memset)
bdnz 4b
5: srwi. r0,r5,3
clrlwi r5,r5,29
- mtcrf 1,r0
+ PPC_MTOCRF 1,r0
beq 8f
bf 29,6f
std r4,0(r6)
@@ -65,7 +65,7 @@ _GLOBAL(memset)
std r4,0(r6)
addi r6,r6,8
8: cmpwi r5,0
- mtcrf 1,r5
+ PPC_MTOCRF 1,r5
beqlr+
bf 29,9f
stw r4,0(r6)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index 7173ba98f42..3f131129d1c 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -12,7 +12,7 @@
.align 7
_GLOBAL(memcpy)
std r3,48(r1) /* save destination pointer for return value */
- mtcrf 0x01,r5
+ PPC_MTOCRF 0x01,r5
cmpldi cr1,r5,16
neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry
andi. r6,r6,7
@@ -128,7 +128,7 @@ _GLOBAL(memcpy)
b .Ldo_tail
.Ldst_unaligned:
- mtcrf 0x01,r6 # put #bytes to 8B bdry into cr7
+ PPC_MTOCRF 0x01,r6 # put #bytes to 8B bdry into cr7
subf r5,r6,r5
li r7,0
cmpldi r1,r5,16
@@ -143,7 +143,7 @@ _GLOBAL(memcpy)
2: bf cr7*4+1,3f
lwzx r0,r7,r4
stwx r0,r7,r3
-3: mtcrf 0x01,r5
+3: PPC_MTOCRF 0x01,r5
add r4,r6,r4
add r3,r6,r3
b .Ldst_aligned
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 7e8ded051b5..4aae0c38764 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -54,7 +54,7 @@ static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
*/
int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
{
- unsigned int opcode, rd;
+ unsigned int opcode, rs, rb, rd, spr;
unsigned long int imm;
opcode = instr >> 26;
@@ -152,6 +152,49 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
regs->nip &= 0xffffffffUL;
return 1;
#endif
+ case 0x26: /* mfcr */
+ regs->gpr[rd] = regs->ccr;
+ regs->gpr[rd] &= 0xffffffffUL;
+ goto mtspr_out;
+ case 0x2a6: /* mfspr */
+ spr = (instr >> 11) & 0x3ff;
+ switch (spr) {
+ case 0x20: /* mfxer */
+ regs->gpr[rd] = regs->xer;
+ regs->gpr[rd] &= 0xffffffffUL;
+ goto mtspr_out;
+ case 0x100: /* mflr */
+ regs->gpr[rd] = regs->link;
+ goto mtspr_out;
+ case 0x120: /* mfctr */
+ regs->gpr[rd] = regs->ctr;
+ goto mtspr_out;
+ }
+ break;
+ case 0x378: /* orx */
+ rs = (instr >> 21) & 0x1f;
+ rb = (instr >> 11) & 0x1f;
+ if (rs == rb) { /* mr */
+ rd = (instr >> 16) & 0x1f;
+ regs->gpr[rd] = regs->gpr[rs];
+ goto mtspr_out;
+ }
+ break;
+ case 0x3a6: /* mtspr */
+ spr = (instr >> 11) & 0x3ff;
+ switch (spr) {
+ case 0x20: /* mtxer */
+ regs->xer = (regs->gpr[rd] & 0xffffffffUL);
+ goto mtspr_out;
+ case 0x100: /* mtlr */
+ regs->link = regs->gpr[rd];
+ goto mtspr_out;
+ case 0x120: /* mtctr */
+ regs->ctr = regs->gpr[rd];
+mtspr_out:
+ regs->nip += 4;
+ return 1;
+ }
}
}
return 0;
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index 0a0a0487b33..ca4dcb07a93 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -24,73 +24,38 @@
*
*/
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/stddef.h>
-#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/highmem.h>
-
-#include <asm/pgalloc.h>
-#include <asm/prom.h>
-#include <asm/io.h>
-#include <asm/mmu_context.h>
-#include <asm/pgtable.h>
#include <asm/mmu.h>
-#include <asm/uaccess.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
-#include <asm/machdep.h>
-#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/page.h>
#include "mmu_decl.h"
-extern char etext[], _stext[];
-
/* Used by the 44x TLB replacement exception handler.
* Just needed it declared someplace.
*/
-unsigned int tlb_44x_index = 0;
-unsigned int tlb_44x_hwater = 62;
+unsigned int tlb_44x_index; /* = 0 */
+unsigned int tlb_44x_hwater = PPC44x_TLB_SIZE - 1 - PPC44x_EARLY_TLBS;
/*
* "Pins" a 256MB TLB entry in AS0 for kernel lowmem
*/
-static void __init
-ppc44x_pin_tlb(int slot, unsigned int virt, unsigned int phys)
+static void __init ppc44x_pin_tlb(unsigned int virt, unsigned int phys)
{
- unsigned long attrib = 0;
-
- __asm__ __volatile__("\
- clrrwi %2,%2,10\n\
- ori %2,%2,%4\n\
- clrrwi %1,%1,10\n\
- li %0,0\n\
- ori %0,%0,%5\n\
- tlbwe %2,%3,%6\n\
- tlbwe %1,%3,%7\n\
- tlbwe %0,%3,%8"
+ __asm__ __volatile__(
+ "tlbwe %2,%3,%4\n"
+ "tlbwe %1,%3,%5\n"
+ "tlbwe %0,%3,%6\n"
:
- : "r" (attrib), "r" (phys), "r" (virt), "r" (slot),
- "i" (PPC44x_TLB_VALID | PPC44x_TLB_256M),
- "i" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
+ : "r" (PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G),
+ "r" (phys),
+ "r" (virt | PPC44x_TLB_VALID | PPC44x_TLB_256M),
+ "r" (tlb_44x_hwater--), /* slot for this TLB entry */
"i" (PPC44x_TLB_PAGEID),
"i" (PPC44x_TLB_XLAT),
"i" (PPC44x_TLB_ATTRIB));
}
-/*
- * MMU_init_hw does the chip-specific initialization of the MMU hardware.
- */
void __init MMU_init_hw(void)
{
flush_instruction_cache();
@@ -98,22 +63,13 @@ void __init MMU_init_hw(void)
unsigned long __init mmu_mapin_ram(void)
{
- unsigned int pinned_tlbs = 1;
- int i;
-
- /* Determine number of entries necessary to cover lowmem */
- pinned_tlbs = (unsigned int)
- (_ALIGN(total_lowmem, PPC_PIN_SIZE) >> PPC44x_PIN_SHIFT);
-
- /* Write upper watermark to save location */
- tlb_44x_hwater = PPC44x_LOW_SLOT - pinned_tlbs;
+ unsigned long addr;
- /* If necessary, set additional pinned TLBs */
- if (pinned_tlbs > 1)
- for (i = (PPC44x_LOW_SLOT-(pinned_tlbs-1)); i < PPC44x_LOW_SLOT; i++) {
- unsigned int phys_addr = (PPC44x_LOW_SLOT-i) * PPC_PIN_SIZE;
- ppc44x_pin_tlb(i, phys_addr+PAGE_OFFSET, phys_addr);
- }
+ /* Pin in enough TLBs to cover any lowmem not covered by the
+ * initial 256M mapping established in head_44x.S */
+ for (addr = PPC_PIN_SIZE; addr < total_lowmem;
+ addr += PPC_PIN_SIZE)
+ ppc44x_pin_tlb(addr + PAGE_OFFSET, addr);
return total_lowmem;
}
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 38a81967ca0..4f839c6a976 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -18,4 +18,5 @@ obj-$(CONFIG_40x) += 4xx_mmu.o
obj-$(CONFIG_44x) += 44x_mmu.o
obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o
obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
+obj-$(CONFIG_PPC_MM_SLICES) += slice.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 03aeb3a4607..bfe90135314 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -28,6 +28,7 @@
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/kprobes.h>
+#include <linux/kdebug.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -36,40 +37,28 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/tlbflush.h>
-#include <asm/kdebug.h>
#include <asm/siginfo.h>
-#ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
-
-int unregister_page_fault_notifier(struct notifier_block *nb)
+#ifdef CONFIG_KPROBES
+static inline int notify_page_fault(struct pt_regs *regs)
{
- return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
+ int ret = 0;
+
+ /* kprobe_running() needs smp_processor_id() */
+ if (!user_mode(regs)) {
+ preempt_disable();
+ if (kprobe_running() && kprobe_fault_handler(regs, 11))
+ ret = 1;
+ preempt_enable();
+ }
-static inline int notify_page_fault(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
- return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+ return ret;
}
#else
-static inline int notify_page_fault(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs)
{
- return NOTIFY_DONE;
+ return 0;
}
#endif
@@ -175,8 +164,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
is_write = error_code & ESR_DST;
#endif /* CONFIG_4xx || CONFIG_BOOKE */
- if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs, error_code,
- 11, SIGSEGV) == NOTIFY_STOP)
+ if (notify_page_fault(regs))
return 0;
if (trap == 0x300) {
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index bd68df5fa78..ddceefc06ec 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -283,6 +283,7 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
#define PTEG_SIZE 64
#define LG_PTEG_SIZE 6
#define LDPTEu lwzu
+#define LDPTE lwz
#define STPTE stw
#define CMPPTE cmpw
#define PTE_H 0x40
@@ -389,13 +390,30 @@ _GLOBAL(hash_page_patch_C)
* and we know there is a definite (although small) speed
* advantage to putting the PTE in the primary PTEG, we always
* put the PTE in the primary PTEG.
+ *
+ * In addition, we skip any slot that is mapping kernel text in
+ * order to avoid a deadlock when not using BAT mappings if
+ * trying to hash in the kernel hash code itself after it has
+ * already taken the hash table lock. This works in conjunction
+ * with pre-faulting of the kernel text.
+ *
+ * If the hash table bucket is full of kernel text entries, we'll
+ * lockup here but that shouldn't happen
*/
- addis r4,r7,next_slot@ha
+
+1: addis r4,r7,next_slot@ha /* get next evict slot */
lwz r6,next_slot@l(r4)
- addi r6,r6,PTE_SIZE
+ addi r6,r6,PTE_SIZE /* search for candidate */
andi. r6,r6,7*PTE_SIZE
stw r6,next_slot@l(r4)
add r4,r3,r6
+ LDPTE r0,PTE_SIZE/2(r4) /* get PTE second word */
+ clrrwi r0,r0,12
+ lis r6,etext@h
+ ori r6,r6,etext@l /* get etext */
+ tophys(r6,r6)
+ cmpl cr0,r0,r6 /* compare and try again */
+ blt 1b
#ifndef CONFIG_SMP
/* Store PTE in PTEG */
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index 9bc0a9c2b9b..4762ff7c14d 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -445,9 +445,12 @@ END_FTR_SECTION(CPU_FTR_NOEXECUTE|CPU_FTR_COHERENT_ICACHE, CPU_FTR_NOEXECUTE)
htab_insert_pte:
/* real page number in r5, PTE RPN value + index */
- rldicl r5,r31,64-PTE_RPN_SHIFT,PTE_RPN_SHIFT
+ andis. r0,r31,_PAGE_4K_PFN@h
+ srdi r5,r31,PTE_RPN_SHIFT
+ bne- htab_special_pfn
sldi r5,r5,PAGE_SHIFT-HW_PAGE_SHIFT
add r5,r5,r25
+htab_special_pfn:
sldi r5,r5,HW_PAGE_SHIFT
/* Calculate primary group hash */
@@ -612,6 +615,9 @@ htab_pte_insert_failure:
li r3,-1
b htab_bail
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
/*****************************************************************************
* *
@@ -867,7 +873,7 @@ ht64_pte_insert_failure:
b ht64_bail
-#endif /* CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC_HAS_HASH_64K */
/*****************************************************************************
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 6f1016acdbf..7b7fe2d7b9d 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -26,6 +26,7 @@
#include <asm/tlb.h>
#include <asm/cputable.h>
#include <asm/udbg.h>
+#include <asm/kexec.h>
#ifdef DEBUG_LOW
#define DBG_LOW(fmt...) udbg_printf(fmt)
@@ -340,31 +341,70 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va,
local_irq_restore(flags);
}
-/*
- * XXX This need fixing based on page size. It's only used by
- * native_hpte_clear() for now which needs fixing too so they
- * make a good pair...
- */
-static unsigned long slot2va(unsigned long hpte_v, unsigned long slot)
-{
- unsigned long avpn = HPTE_V_AVPN_VAL(hpte_v);
- unsigned long va;
+#define LP_SHIFT 12
+#define LP_BITS 8
+#define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT)
- va = avpn << 23;
+static void hpte_decode(hpte_t *hpte, unsigned long slot,
+ int *psize, unsigned long *va)
+{
+ unsigned long hpte_r = hpte->r;
+ unsigned long hpte_v = hpte->v;
+ unsigned long avpn;
+ int i, size, shift, penc, avpnm_bits;
+
+ if (!(hpte_v & HPTE_V_LARGE))
+ size = MMU_PAGE_4K;
+ else {
+ for (i = 0; i < LP_BITS; i++) {
+ if ((hpte_r & LP_MASK(i+1)) == LP_MASK(i+1))
+ break;
+ }
+ penc = LP_MASK(i+1) >> LP_SHIFT;
+ for (size = 0; size < MMU_PAGE_COUNT; size++) {
- if (! (hpte_v & HPTE_V_LARGE)) {
- unsigned long vpi, pteg;
+ /* 4K pages are not represented by LP */
+ if (size == MMU_PAGE_4K)
+ continue;
- pteg = slot / HPTES_PER_GROUP;
- if (hpte_v & HPTE_V_SECONDARY)
- pteg = ~pteg;
+ /* valid entries have a shift value */
+ if (!mmu_psize_defs[size].shift)
+ continue;
- vpi = ((va >> 28) ^ pteg) & htab_hash_mask;
+ if (penc == mmu_psize_defs[size].penc)
+ break;
+ }
+ }
- va |= vpi << PAGE_SHIFT;
+ /*
+ * FIXME, the code below works for 16M, 64K, and 4K pages as these
+ * fall under the p<=23 rules for calculating the virtual address.
+ * In the case of 16M pages, an extra bit is stolen from the AVPN
+ * field to achieve the requisite 24 bits.
+ *
+ * Does not work for 16G pages or 1 TB segments.
+ */
+ shift = mmu_psize_defs[size].shift;
+ if (mmu_psize_defs[size].avpnm)
+ avpnm_bits = __ilog2_u64(mmu_psize_defs[size].avpnm) + 1;
+ else
+ avpnm_bits = 0;
+ if (shift - avpnm_bits <= 23) {
+ avpn = HPTE_V_AVPN_VAL(hpte_v) << 23;
+
+ if (shift < 23) {
+ unsigned long vpi, pteg;
+
+ pteg = slot / HPTES_PER_GROUP;
+ if (hpte_v & HPTE_V_SECONDARY)
+ pteg = ~pteg;
+ vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask;
+ avpn |= (vpi << mmu_psize_defs[size].shift);
+ }
}
- return va;
+ *va = avpn;
+ *psize = size;
}
/*
@@ -374,15 +414,14 @@ static unsigned long slot2va(unsigned long hpte_v, unsigned long slot)
*
* TODO: add batching support when enabled. remember, no dynamic memory here,
* athough there is the control page available...
- *
- * XXX FIXME: 4k only for now !
*/
static void native_hpte_clear(void)
{
unsigned long slot, slots, flags;
hpte_t *hptep = htab_address;
- unsigned long hpte_v;
+ unsigned long hpte_v, va;
unsigned long pteg_count;
+ int psize;
pteg_count = htab_hash_mask + 1;
@@ -408,8 +447,9 @@ static void native_hpte_clear(void)
* already hold the native_tlbie_lock.
*/
if (hpte_v & HPTE_V_VALID) {
+ hpte_decode(hptep, slot, &psize, &va);
hptep->v = 0;
- __tlbie(slot2va(hpte_v, slot), MMU_PAGE_4K);
+ __tlbie(va, psize);
}
}
@@ -505,7 +545,7 @@ static inline int tlb_batching_enabled(void)
int enabled = 1;
if (root) {
- const char *model = get_property(root, "model", NULL);
+ const char *model = of_get_property(root, "model", NULL);
if (model && !strcmp(model, "IBM,9076-N81"))
enabled = 0;
of_node_put(root);
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 3c7fe2c65b5..028ba4ed03d 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -51,6 +51,7 @@
#include <asm/cputable.h>
#include <asm/abs_addr.h>
#include <asm/sections.h>
+#include <asm/spu.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -100,6 +101,11 @@ unsigned int HPAGE_SHIFT;
#ifdef CONFIG_PPC_64K_PAGES
int mmu_ci_restrictions;
#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static u8 *linear_map_hash_slots;
+static unsigned long linear_map_hash_count;
+static DEFINE_SPINLOCK(linear_map_hash_lock);
+#endif /* CONFIG_DEBUG_PAGEALLOC */
/* There are definitions of page sizes arrays to be used when none
* is provided by the firmware.
@@ -152,11 +158,10 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
for (vaddr = vstart, paddr = pstart; vaddr < vend;
vaddr += step, paddr += step) {
- unsigned long vpn, hash, hpteg;
+ unsigned long hash, hpteg;
unsigned long vsid = get_kernel_vsid(vaddr);
unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
- vpn = va >> shift;
tmp_mode = mode;
/* Make non-kernel text non-executable */
@@ -174,6 +179,10 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
if (ret < 0)
break;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ if ((paddr >> PAGE_SHIFT) < linear_map_hash_count)
+ linear_map_hash_slots[paddr >> PAGE_SHIFT] = ret | 0x80;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
}
return ret < 0 ? ret : 0;
}
@@ -281,6 +290,7 @@ static void __init htab_init_page_sizes(void)
memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
sizeof(mmu_psize_defaults_gp));
found:
+#ifndef CONFIG_DEBUG_PAGEALLOC
/*
* Pick a size for the linear mapping. Currently, we only support
* 16M, 1M and 4K which is the default
@@ -289,6 +299,7 @@ static void __init htab_init_page_sizes(void)
mmu_linear_psize = MMU_PAGE_16M;
else if (mmu_psize_defs[MMU_PAGE_1M].shift)
mmu_linear_psize = MMU_PAGE_1M;
+#endif /* CONFIG_DEBUG_PAGEALLOC */
#ifdef CONFIG_PPC_64K_PAGES
/*
@@ -303,12 +314,14 @@ static void __init htab_init_page_sizes(void)
if (mmu_psize_defs[MMU_PAGE_64K].shift) {
mmu_virtual_psize = MMU_PAGE_64K;
mmu_vmalloc_psize = MMU_PAGE_64K;
+ if (mmu_linear_psize == MMU_PAGE_4K)
+ mmu_linear_psize = MMU_PAGE_64K;
if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE))
mmu_io_psize = MMU_PAGE_64K;
else
mmu_ci_restrictions = 1;
}
-#endif
+#endif /* CONFIG_PPC_64K_PAGES */
printk(KERN_DEBUG "Page orders: linear mapping = %d, "
"virtual = %d, io = %d\n",
@@ -407,7 +420,7 @@ static void __init htab_finish_init(void)
extern unsigned int *htab_call_hpte_remove;
extern unsigned int *htab_call_hpte_updatepp;
-#ifdef CONFIG_PPC_64K_PAGES
+#ifdef CONFIG_PPC_HAS_HASH_64K
extern unsigned int *ht64_call_hpte_insert1;
extern unsigned int *ht64_call_hpte_insert2;
extern unsigned int *ht64_call_hpte_remove;
@@ -476,6 +489,13 @@ void __init htab_initialize(void)
mode_rw = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_COHERENT | PP_RWXX;
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT;
+ linear_map_hash_slots = __va(lmb_alloc_base(linear_map_hash_count,
+ 1, lmb.rmo_size));
+ memset(linear_map_hash_slots, 0, linear_map_hash_count);
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
/* On U3 based machines, we need to reserve the DART area and
* _NOT_ map it to avoid cache paradoxes as it's remapped non
* cacheable later on
@@ -573,6 +593,28 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
return pp;
}
+/*
+ * Demote a segment to using 4k pages.
+ * For now this makes the whole process use 4k pages.
+ */
+#ifdef CONFIG_PPC_64K_PAGES
+static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
+{
+ if (mm->context.user_psize == MMU_PAGE_4K)
+ return;
+#ifdef CONFIG_PPC_MM_SLICES
+ slice_set_user_psize(mm, MMU_PAGE_4K);
+#else /* CONFIG_PPC_MM_SLICES */
+ mm->context.user_psize = MMU_PAGE_4K;
+ mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
+#endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_SPE_BASE
+ spu_flush_all_slbs(mm);
+#endif
+}
+#endif /* CONFIG_PPC_64K_PAGES */
+
/* Result code is:
* 0 - handled
* 1 - normal page fault
@@ -606,7 +648,11 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
return 1;
}
vsid = get_vsid(mm->context.id, ea);
+#ifdef CONFIG_PPC_MM_SLICES
+ psize = get_slice_psize(mm, ea);
+#else
psize = mm->context.user_psize;
+#endif
break;
case VMALLOC_REGION_ID:
mm = &init_mm;
@@ -634,11 +680,22 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
if (user_region && cpus_equal(mm->cpu_vm_mask, tmp))
local = 1;
+#ifdef CONFIG_HUGETLB_PAGE
/* Handle hugepage regions */
- if (unlikely(in_hugepage_area(mm->context, ea))) {
+ if (HPAGE_SHIFT && psize == mmu_huge_psize) {
DBG_LOW(" -> huge page !\n");
return hash_huge_page(mm, access, ea, vsid, local, trap);
}
+#endif /* CONFIG_HUGETLB_PAGE */
+
+#ifndef CONFIG_PPC_64K_PAGES
+ /* If we use 4K pages and our psize is not 4K, then we are hitting
+ * a special driver mapping, we need to align the address before
+ * we fetch the PTE
+ */
+ if (psize != MMU_PAGE_4K)
+ ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1);
+#endif /* CONFIG_PPC_64K_PAGES */
/* Get PTE and page size from page tables */
ptep = find_linux_pte(pgdir, ea);
@@ -662,50 +719,56 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
}
/* Do actual hashing */
-#ifndef CONFIG_PPC_64K_PAGES
- rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
- if (mmu_ci_restrictions) {
- /* If this PTE is non-cacheable, switch to 4k */
- if (psize == MMU_PAGE_64K &&
- (pte_val(*ptep) & _PAGE_NO_CACHE)) {
- if (user_region) {
- psize = MMU_PAGE_4K;
- mm->context.user_psize = MMU_PAGE_4K;
- mm->context.sllp = SLB_VSID_USER |
- mmu_psize_defs[MMU_PAGE_4K].sllp;
- } else if (ea < VMALLOC_END) {
- /*
- * some driver did a non-cacheable mapping
- * in vmalloc space, so switch vmalloc
- * to 4k pages
- */
- printk(KERN_ALERT "Reducing vmalloc segment "
- "to 4kB pages because of "
- "non-cacheable mapping\n");
- psize = mmu_vmalloc_psize = MMU_PAGE_4K;
- }
+#ifdef CONFIG_PPC_64K_PAGES
+ /* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
+ if (pte_val(*ptep) & _PAGE_4K_PFN) {
+ demote_segment_4k(mm, ea);
+ psize = MMU_PAGE_4K;
+ }
+
+ /* If this PTE is non-cacheable and we have restrictions on
+ * using non cacheable large pages, then we switch to 4k
+ */
+ if (mmu_ci_restrictions && psize == MMU_PAGE_64K &&
+ (pte_val(*ptep) & _PAGE_NO_CACHE)) {
+ if (user_region) {
+ demote_segment_4k(mm, ea);
+ psize = MMU_PAGE_4K;
+ } else if (ea < VMALLOC_END) {
+ /*
+ * some driver did a non-cacheable mapping
+ * in vmalloc space, so switch vmalloc
+ * to 4k pages
+ */
+ printk(KERN_ALERT "Reducing vmalloc segment "
+ "to 4kB pages because of "
+ "non-cacheable mapping\n");
+ psize = mmu_vmalloc_psize = MMU_PAGE_4K;
#ifdef CONFIG_SPE_BASE
spu_flush_all_slbs(mm);
#endif
}
- if (user_region) {
- if (psize != get_paca()->context.user_psize) {
- get_paca()->context = mm->context;
- slb_flush_and_rebolt();
- }
- } else if (get_paca()->vmalloc_sllp !=
- mmu_psize_defs[mmu_vmalloc_psize].sllp) {
- get_paca()->vmalloc_sllp =
- mmu_psize_defs[mmu_vmalloc_psize].sllp;
+ }
+ if (user_region) {
+ if (psize != get_paca()->context.user_psize) {
+ get_paca()->context.user_psize =
+ mm->context.user_psize;
slb_flush_and_rebolt();
}
+ } else if (get_paca()->vmalloc_sllp !=
+ mmu_psize_defs[mmu_vmalloc_psize].sllp) {
+ get_paca()->vmalloc_sllp =
+ mmu_psize_defs[mmu_vmalloc_psize].sllp;
+ slb_flush_and_rebolt();
}
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#ifdef CONFIG_PPC_HAS_HASH_64K
if (psize == MMU_PAGE_64K)
rc = __hash_page_64K(ea, access, vsid, ptep, trap, local);
else
+#endif /* CONFIG_PPC_HAS_HASH_64K */
rc = __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#endif /* CONFIG_PPC_64K_PAGES */
#ifndef CONFIG_PPC_64K_PAGES
DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
@@ -728,50 +791,55 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
unsigned long flags;
int local = 0;
- /* We don't want huge pages prefaulted for now
- */
- if (unlikely(in_hugepage_area(mm->context, ea)))
+ BUG_ON(REGION_ID(ea) != USER_REGION_ID);
+
+#ifdef CONFIG_PPC_MM_SLICES
+ /* We only prefault standard pages for now */
+ if (unlikely(get_slice_psize(mm, ea) != mm->context.user_psize));
return;
+#endif
DBG_LOW("hash_preload(mm=%p, mm->pgdir=%p, ea=%016lx, access=%lx,"
" trap=%lx\n", mm, mm->pgd, ea, access, trap);
- /* Get PTE, VSID, access mask */
+ /* Get Linux PTE if available */
pgdir = mm->pgd;
if (pgdir == NULL)
return;
ptep = find_linux_pte(pgdir, ea);
if (!ptep)
return;
+
+#ifdef CONFIG_PPC_64K_PAGES
+ /* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
+ * a 64K kernel), then we don't preload, hash_page() will take
+ * care of it once we actually try to access the page.
+ * That way we don't have to duplicate all of the logic for segment
+ * page size demotion here
+ */
+ if (pte_val(*ptep) & (_PAGE_4K_PFN | _PAGE_NO_CACHE))
+ return;
+#endif /* CONFIG_PPC_64K_PAGES */
+
+ /* Get VSID */
vsid = get_vsid(mm->context.id, ea);
- /* Hash it in */
+ /* Hash doesn't like irqs */
local_irq_save(flags);
+
+ /* Is that local to this CPU ? */
mask = cpumask_of_cpu(smp_processor_id());
if (cpus_equal(mm->cpu_vm_mask, mask))
local = 1;
-#ifndef CONFIG_PPC_64K_PAGES
- __hash_page_4K(ea, access, vsid, ptep, trap, local);
-#else
- if (mmu_ci_restrictions) {
- /* If this PTE is non-cacheable, switch to 4k */
- if (mm->context.user_psize == MMU_PAGE_64K &&
- (pte_val(*ptep) & _PAGE_NO_CACHE)) {
- mm->context.user_psize = MMU_PAGE_4K;
- mm->context.sllp = SLB_VSID_USER |
- mmu_psize_defs[MMU_PAGE_4K].sllp;
- get_paca()->context = mm->context;
- slb_flush_and_rebolt();
-#ifdef CONFIG_SPE_BASE
- spu_flush_all_slbs(mm);
-#endif
- }
- }
+
+ /* Hash it in */
+#ifdef CONFIG_PPC_HAS_HASH_64K
if (mm->context.user_psize == MMU_PAGE_64K)
__hash_page_64K(ea, access, vsid, ptep, trap, local);
else
- __hash_page_4K(ea, access, vsid, ptep, trap, local);
#endif /* CONFIG_PPC_64K_PAGES */
+ __hash_page_4K(ea, access, vsid, ptep, trap, local);
+
local_irq_restore(flags);
}
@@ -825,3 +893,62 @@ void low_hash_fault(struct pt_regs *regs, unsigned long address)
}
bad_page_fault(regs, address, SIGBUS);
}
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static void kernel_map_linear_page(unsigned long vaddr, unsigned long lmi)
+{
+ unsigned long hash, hpteg, vsid = get_kernel_vsid(vaddr);
+ unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+ unsigned long mode = _PAGE_ACCESSED | _PAGE_DIRTY |
+ _PAGE_COHERENT | PP_RWXX | HPTE_R_N;
+ int ret;
+
+ hash = hpt_hash(va, PAGE_SHIFT);
+ hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+
+ ret = ppc_md.hpte_insert(hpteg, va, __pa(vaddr),
+ mode, HPTE_V_BOLTED, mmu_linear_psize);
+ BUG_ON (ret < 0);
+ spin_lock(&linear_map_hash_lock);
+ BUG_ON(linear_map_hash_slots[lmi] & 0x80);
+ linear_map_hash_slots[lmi] = ret | 0x80;
+ spin_unlock(&linear_map_hash_lock);
+}
+
+static void kernel_unmap_linear_page(unsigned long vaddr, unsigned long lmi)
+{
+ unsigned long hash, hidx, slot, vsid = get_kernel_vsid(vaddr);
+ unsigned long va = (vsid << 28) | (vaddr & 0x0fffffff);
+
+ hash = hpt_hash(va, PAGE_SHIFT);
+ spin_lock(&linear_map_hash_lock);
+ BUG_ON(!(linear_map_hash_slots[lmi] & 0x80));
+ hidx = linear_map_hash_slots[lmi] & 0x7f;
+ linear_map_hash_slots[lmi] = 0;
+ spin_unlock(&linear_map_hash_lock);
+ if (hidx & _PTEIDX_SECONDARY)
+ hash = ~hash;
+ slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
+ slot += hidx & _PTEIDX_GROUP_IX;
+ ppc_md.hpte_invalidate(slot, va, mmu_linear_psize, 0);
+}
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+ unsigned long flags, vaddr, lmi;
+ int i;
+
+ local_irq_save(flags);
+ for (i = 0; i < numpages; i++, page++) {
+ vaddr = (unsigned long)page_address(page);
+ lmi = __pa(vaddr) >> PAGE_SHIFT;
+ if (lmi >= linear_map_hash_count)
+ continue;
+ if (enable)
+ kernel_map_linear_page(vaddr, lmi);
+ else
+ kernel_unmap_linear_page(vaddr, lmi);
+ }
+ local_irq_restore(flags);
+}
+#endif /* CONFIG_DEBUG_PAGEALLOC */
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f6ffaaa7a5b..92a1b16fb7e 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -12,7 +12,6 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sysctl.h>
@@ -92,7 +91,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
pgd_t *pg;
pud_t *pu;
- BUG_ON(! in_hugepage_area(mm->context, addr));
+ BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
addr &= HPAGE_MASK;
@@ -120,7 +119,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
pud_t *pu;
hugepd_t *hpdp = NULL;
- BUG_ON(! in_hugepage_area(mm->context, addr));
+ BUG_ON(get_slice_psize(mm, addr) != mmu_huge_psize);
addr &= HPAGE_MASK;
@@ -303,7 +302,7 @@ void hugetlb_free_pgd_range(struct mmu_gather **tlb,
start = addr;
pgd = pgd_offset((*tlb)->mm, addr);
do {
- BUG_ON(! in_hugepage_area((*tlb)->mm->context, addr));
+ BUG_ON(get_slice_psize((*tlb)->mm, addr) != mmu_huge_psize);
next = pgd_addr_end(addr, end);
if (pgd_none_or_clear_bad(pgd))
continue;
@@ -316,12 +315,11 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
{
if (pte_present(*ptep)) {
/* We open-code pte_clear because we need to pass the right
- * argument to hpte_update (huge / !huge)
+ * argument to hpte_need_flush (huge / !huge). Might not be
+ * necessary anymore if we make hpte_need_flush() get the
+ * page size from the slices
*/
- unsigned long old = pte_update(ptep, ~0UL);
- if (old & _PAGE_HASHPTE)
- hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1);
- flush_tlb_pending();
+ pte_update(mm, addr & HPAGE_MASK, ptep, ~0UL, 1);
}
*ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
}
@@ -329,212 +327,17 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
- unsigned long old = pte_update(ptep, ~0UL);
-
- if (old & _PAGE_HASHPTE)
- hpte_update(mm, addr & HPAGE_MASK, ptep, old, 1);
- *ptep = __pte(0);
-
+ unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1);
return __pte(old);
}
-struct slb_flush_info {
- struct mm_struct *mm;
- u16 newareas;
-};
-
-static void flush_low_segments(void *parm)
-{
- struct slb_flush_info *fi = parm;
- unsigned long i;
-
- BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_LOW_AREAS);
-
- if (current->active_mm != fi->mm)
- return;
-
- /* Only need to do anything if this CPU is working in the same
- * mm as the one which has changed */
-
- /* update the paca copy of the context struct */
- get_paca()->context = current->active_mm->context;
-
- asm volatile("isync" : : : "memory");
- for (i = 0; i < NUM_LOW_AREAS; i++) {
- if (! (fi->newareas & (1U << i)))
- continue;
- asm volatile("slbie %0"
- : : "r" ((i << SID_SHIFT) | SLBIE_C));
- }
- asm volatile("isync" : : : "memory");
-}
-
-static void flush_high_segments(void *parm)
-{
- struct slb_flush_info *fi = parm;
- unsigned long i, j;
-
-
- BUILD_BUG_ON((sizeof(fi->newareas)*8) != NUM_HIGH_AREAS);
-
- if (current->active_mm != fi->mm)
- return;
-
- /* Only need to do anything if this CPU is working in the same
- * mm as the one which has changed */
-
- /* update the paca copy of the context struct */
- get_paca()->context = current->active_mm->context;
-
- asm volatile("isync" : : : "memory");
- for (i = 0; i < NUM_HIGH_AREAS; i++) {
- if (! (fi->newareas & (1U << i)))
- continue;
- for (j = 0; j < (1UL << (HTLB_AREA_SHIFT-SID_SHIFT)); j++)
- asm volatile("slbie %0"
- :: "r" (((i << HTLB_AREA_SHIFT)
- + (j << SID_SHIFT)) | SLBIE_C));
- }
- asm volatile("isync" : : : "memory");
-}
-
-static int prepare_low_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
- unsigned long start = area << SID_SHIFT;
- unsigned long end = (area+1) << SID_SHIFT;
- struct vm_area_struct *vma;
-
- BUG_ON(area >= NUM_LOW_AREAS);
-
- /* Check no VMAs are in the region */
- vma = find_vma(mm, start);
- if (vma && (vma->vm_start < end))
- return -EBUSY;
-
- return 0;
-}
-
-static int prepare_high_area_for_htlb(struct mm_struct *mm, unsigned long area)
-{
- unsigned long start = area << HTLB_AREA_SHIFT;
- unsigned long end = (area+1) << HTLB_AREA_SHIFT;
- struct vm_area_struct *vma;
-
- BUG_ON(area >= NUM_HIGH_AREAS);
-
- /* Hack, so that each addresses is controlled by exactly one
- * of the high or low area bitmaps, the first high area starts
- * at 4GB, not 0 */
- if (start == 0)
- start = 0x100000000UL;
-
- /* Check no VMAs are in the region */
- vma = find_vma(mm, start);
- if (vma && (vma->vm_start < end))
- return -EBUSY;
-
- return 0;
-}
-
-static int open_low_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
- unsigned long i;
- struct slb_flush_info fi;
-
- BUILD_BUG_ON((sizeof(newareas)*8) != NUM_LOW_AREAS);
- BUILD_BUG_ON((sizeof(mm->context.low_htlb_areas)*8) != NUM_LOW_AREAS);
-
- newareas &= ~(mm->context.low_htlb_areas);
- if (! newareas)
- return 0; /* The segments we want are already open */
-
- for (i = 0; i < NUM_LOW_AREAS; i++)
- if ((1 << i) & newareas)
- if (prepare_low_area_for_htlb(mm, i) != 0)
- return -EBUSY;
-
- mm->context.low_htlb_areas |= newareas;
-
- /* the context change must make it to memory before the flush,
- * so that further SLB misses do the right thing. */
- mb();
-
- fi.mm = mm;
- fi.newareas = newareas;
- on_each_cpu(flush_low_segments, &fi, 0, 1);
-
- return 0;
-}
-
-static int open_high_hpage_areas(struct mm_struct *mm, u16 newareas)
-{
- struct slb_flush_info fi;
- unsigned long i;
-
- BUILD_BUG_ON((sizeof(newareas)*8) != NUM_HIGH_AREAS);
- BUILD_BUG_ON((sizeof(mm->context.high_htlb_areas)*8)
- != NUM_HIGH_AREAS);
-
- newareas &= ~(mm->context.high_htlb_areas);
- if (! newareas)
- return 0; /* The areas we want are already open */
-
- for (i = 0; i < NUM_HIGH_AREAS; i++)
- if ((1 << i) & newareas)
- if (prepare_high_area_for_htlb(mm, i) != 0)
- return -EBUSY;
-
- mm->context.high_htlb_areas |= newareas;
-
- /* the context change must make it to memory before the flush,
- * so that further SLB misses do the right thing. */
- mb();
-
- fi.mm = mm;
- fi.newareas = newareas;
- on_each_cpu(flush_high_segments, &fi, 0, 1);
-
- return 0;
-}
-
-int prepare_hugepage_range(unsigned long addr, unsigned long len, pgoff_t pgoff)
-{
- int err = 0;
-
- if (pgoff & (~HPAGE_MASK >> PAGE_SHIFT))
- return -EINVAL;
- if (len & ~HPAGE_MASK)
- return -EINVAL;
- if (addr & ~HPAGE_MASK)
- return -EINVAL;
-
- if (addr < 0x100000000UL)
- err = open_low_hpage_areas(current->mm,
- LOW_ESID_MASK(addr, len));
- if ((addr + len) > 0x100000000UL)
- err = open_high_hpage_areas(current->mm,
- HTLB_AREA_MASK(addr, len));
-#ifdef CONFIG_SPE_BASE
- spu_flush_all_slbs(current->mm);
-#endif
- if (err) {
- printk(KERN_DEBUG "prepare_hugepage_range(%lx, %lx)"
- " failed (lowmask: 0x%04hx, highmask: 0x%04hx)\n",
- addr, len,
- LOW_ESID_MASK(addr, len), HTLB_AREA_MASK(addr, len));
- return err;
- }
-
- return 0;
-}
-
struct page *
follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
{
pte_t *ptep;
struct page *page;
- if (! in_hugepage_area(mm->context, address))
+ if (get_slice_psize(mm, address) != mmu_huge_psize)
return ERR_PTR(-EINVAL);
ptep = huge_pte_offset(mm, address);
@@ -558,338 +361,13 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
return NULL;
}
-/* Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions. */
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
- unsigned long len, unsigned long pgoff,
- unsigned long flags)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- unsigned long start_addr;
-
- if (len > TASK_SIZE)
- return -ENOMEM;
-
- if (addr) {
- addr = PAGE_ALIGN(addr);
- vma = find_vma(mm, addr);
- if (((TASK_SIZE - len) >= addr)
- && (!vma || (addr+len) <= vma->vm_start)
- && !is_hugepage_only_range(mm, addr,len))
- return addr;
- }
- if (len > mm->cached_hole_size) {
- start_addr = addr = mm->free_area_cache;
- } else {
- start_addr = addr = TASK_UNMAPPED_BASE;
- mm->cached_hole_size = 0;
- }
-
-full_search:
- vma = find_vma(mm, addr);
- while (TASK_SIZE - len >= addr) {
- BUG_ON(vma && (addr >= vma->vm_end));
-
- if (touches_hugepage_low_range(mm, addr, len)) {
- addr = ALIGN(addr+1, 1<<SID_SHIFT);
- vma = find_vma(mm, addr);
- continue;
- }
- if (touches_hugepage_high_range(mm, addr, len)) {
- addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
- vma = find_vma(mm, addr);
- continue;
- }
- if (!vma || addr + len <= vma->vm_start) {
- /*
- * Remember the place where we stopped the search:
- */
- mm->free_area_cache = addr + len;
- return addr;
- }
- if (addr + mm->cached_hole_size < vma->vm_start)
- mm->cached_hole_size = vma->vm_start - addr;
- addr = vma->vm_end;
- vma = vma->vm_next;
- }
-
- /* Make sure we didn't miss any holes */
- if (start_addr != TASK_UNMAPPED_BASE) {
- start_addr = addr = TASK_UNMAPPED_BASE;
- mm->cached_hole_size = 0;
- goto full_search;
- }
- return -ENOMEM;
-}
-
-/*
- * This mmap-allocator allocates new areas top-down from below the
- * stack's low limit (the base):
- *
- * Because we have an exclusive hugepage region which lies within the
- * normal user address space, we have to take special measures to make
- * non-huge mmap()s evade the hugepage reserved regions.
- */
-unsigned long
-arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
- const unsigned long len, const unsigned long pgoff,
- const unsigned long flags)
-{
- struct vm_area_struct *vma, *prev_vma;
- struct mm_struct *mm = current->mm;
- unsigned long base = mm->mmap_base, addr = addr0;
- unsigned long largest_hole = mm->cached_hole_size;
- int first_time = 1;
-
- /* requested length too big for entire address space */
- if (len > TASK_SIZE)
- return -ENOMEM;
-
- /* dont allow allocations above current base */
- if (mm->free_area_cache > base)
- mm->free_area_cache = base;
-
- /* requesting a specific address */
- if (addr) {
- addr = PAGE_ALIGN(addr);
- vma = find_vma(mm, addr);
- if (TASK_SIZE - len >= addr &&
- (!vma || addr + len <= vma->vm_start)
- && !is_hugepage_only_range(mm, addr,len))
- return addr;
- }
-
- if (len <= largest_hole) {
- largest_hole = 0;
- mm->free_area_cache = base;
- }
-try_again:
- /* make sure it can fit in the remaining address space */
- if (mm->free_area_cache < len)
- goto fail;
-
- /* either no address requested or cant fit in requested address hole */
- addr = (mm->free_area_cache - len) & PAGE_MASK;
- do {
-hugepage_recheck:
- if (touches_hugepage_low_range(mm, addr, len)) {
- addr = (addr & ((~0) << SID_SHIFT)) - len;
- goto hugepage_recheck;
- } else if (touches_hugepage_high_range(mm, addr, len)) {
- addr = (addr & ((~0UL) << HTLB_AREA_SHIFT)) - len;
- goto hugepage_recheck;
- }
-
- /*
- * Lookup failure means no vma is above this address,
- * i.e. return with success:
- */
- if (!(vma = find_vma_prev(mm, addr, &prev_vma)))
- return addr;
-
- /*
- * new region fits between prev_vma->vm_end and
- * vma->vm_start, use it:
- */
- if (addr+len <= vma->vm_start &&
- (!prev_vma || (addr >= prev_vma->vm_end))) {
- /* remember the address as a hint for next time */
- mm->cached_hole_size = largest_hole;
- return (mm->free_area_cache = addr);
- } else {
- /* pull free_area_cache down to the first hole */
- if (mm->free_area_cache == vma->vm_end) {
- mm->free_area_cache = vma->vm_start;
- mm->cached_hole_size = largest_hole;
- }
- }
-
- /* remember the largest hole we saw so far */
- if (addr + largest_hole < vma->vm_start)
- largest_hole = vma->vm_start - addr;
-
- /* try just below the current vma->vm_start */
- addr = vma->vm_start-len;
- } while (len <= vma->vm_start);
-
-fail:
- /*
- * if hint left us with no space for the requested
- * mapping then try again:
- */
- if (first_time) {
- mm->free_area_cache = base;
- largest_hole = 0;
- first_time = 0;
- goto try_again;
- }
- /*
- * A failed mmap() very likely causes application failure,
- * so fall back to the bottom-up function here. This scenario
- * can happen with large stack limits and large mmap()
- * allocations.
- */
- mm->free_area_cache = TASK_UNMAPPED_BASE;
- mm->cached_hole_size = ~0UL;
- addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
- /*
- * Restore the topdown base:
- */
- mm->free_area_cache = base;
- mm->cached_hole_size = ~0UL;
-
- return addr;
-}
-
-static int htlb_check_hinted_area(unsigned long addr, unsigned long len)
-{
- struct vm_area_struct *vma;
-
- vma = find_vma(current->mm, addr);
- if (TASK_SIZE - len >= addr &&
- (!vma || ((addr + len) <= vma->vm_start)))
- return 0;
-
- return -ENOMEM;
-}
-
-static unsigned long htlb_get_low_area(unsigned long len, u16 segmask)
-{
- unsigned long addr = 0;
- struct vm_area_struct *vma;
-
- vma = find_vma(current->mm, addr);
- while (addr + len <= 0x100000000UL) {
- BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
- if (! __within_hugepage_low_range(addr, len, segmask)) {
- addr = ALIGN(addr+1, 1<<SID_SHIFT);
- vma = find_vma(current->mm, addr);
- continue;
- }
-
- if (!vma || (addr + len) <= vma->vm_start)
- return addr;
- addr = ALIGN(vma->vm_end, HPAGE_SIZE);
- /* Depending on segmask this might not be a confirmed
- * hugepage region, so the ALIGN could have skipped
- * some VMAs */
- vma = find_vma(current->mm, addr);
- }
-
- return -ENOMEM;
-}
-
-static unsigned long htlb_get_high_area(unsigned long len, u16 areamask)
-{
- unsigned long addr = 0x100000000UL;
- struct vm_area_struct *vma;
-
- vma = find_vma(current->mm, addr);
- while (addr + len <= TASK_SIZE_USER64) {
- BUG_ON(vma && (addr >= vma->vm_end)); /* invariant */
-
- if (! __within_hugepage_high_range(addr, len, areamask)) {
- addr = ALIGN(addr+1, 1UL<<HTLB_AREA_SHIFT);
- vma = find_vma(current->mm, addr);
- continue;
- }
-
- if (!vma || (addr + len) <= vma->vm_start)
- return addr;
- addr = ALIGN(vma->vm_end, HPAGE_SIZE);
- /* Depending on segmask this might not be a confirmed
- * hugepage region, so the ALIGN could have skipped
- * some VMAs */
- vma = find_vma(current->mm, addr);
- }
-
- return -ENOMEM;
-}
unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
unsigned long len, unsigned long pgoff,
unsigned long flags)
{
- int lastshift;
- u16 areamask, curareas;
-
- if (HPAGE_SHIFT == 0)
- return -EINVAL;
- if (len & ~HPAGE_MASK)
- return -EINVAL;
- if (len > TASK_SIZE)
- return -ENOMEM;
-
- if (!cpu_has_feature(CPU_FTR_16M_PAGE))
- return -EINVAL;
-
- /* Paranoia, caller should have dealt with this */
- BUG_ON((addr + len) < addr);
-
- if (test_thread_flag(TIF_32BIT)) {
- curareas = current->mm->context.low_htlb_areas;
-
- /* First see if we can use the hint address */
- if (addr && (htlb_check_hinted_area(addr, len) == 0)) {
- areamask = LOW_ESID_MASK(addr, len);
- if (open_low_hpage_areas(current->mm, areamask) == 0)
- return addr;
- }
-
- /* Next see if we can map in the existing low areas */
- addr = htlb_get_low_area(len, curareas);
- if (addr != -ENOMEM)
- return addr;
-
- /* Finally go looking for areas to open */
- lastshift = 0;
- for (areamask = LOW_ESID_MASK(0x100000000UL-len, len);
- ! lastshift; areamask >>=1) {
- if (areamask & 1)
- lastshift = 1;
-
- addr = htlb_get_low_area(len, curareas | areamask);
- if ((addr != -ENOMEM)
- && open_low_hpage_areas(current->mm, areamask) == 0)
- return addr;
- }
- } else {
- curareas = current->mm->context.high_htlb_areas;
-
- /* First see if we can use the hint address */
- /* We discourage 64-bit processes from doing hugepage
- * mappings below 4GB (must use MAP_FIXED) */
- if ((addr >= 0x100000000UL)
- && (htlb_check_hinted_area(addr, len) == 0)) {
- areamask = HTLB_AREA_MASK(addr, len);
- if (open_high_hpage_areas(current->mm, areamask) == 0)
- return addr;
- }
-
- /* Next see if we can map in the existing high areas */
- addr = htlb_get_high_area(len, curareas);
- if (addr != -ENOMEM)
- return addr;
-
- /* Finally go looking for areas to open */
- lastshift = 0;
- for (areamask = HTLB_AREA_MASK(TASK_SIZE_USER64-len, len);
- ! lastshift; areamask >>=1) {
- if (areamask & 1)
- lastshift = 1;
-
- addr = htlb_get_high_area(len, curareas | areamask);
- if ((addr != -ENOMEM)
- && open_high_hpage_areas(current->mm, areamask) == 0)
- return addr;
- }
- }
- printk(KERN_DEBUG "hugetlb_get_unmapped_area() unable to open"
- " enough areas\n");
- return -ENOMEM;
+ return slice_get_unmapped_area(addr, len, flags,
+ mmu_huge_psize, 1, 0);
}
/*
@@ -1063,8 +541,7 @@ static int __init hugetlbpage_init(void)
huge_pgtable_cache = kmem_cache_create("hugepte_cache",
HUGEPTE_TABLE_SIZE,
HUGEPTE_TABLE_SIZE,
- SLAB_HWCACHE_ALIGN |
- SLAB_MUST_HWCACHE_ALIGN,
+ 0,
zero_ctor, NULL);
if (! huge_pgtable_cache)
panic("hugetlbpage_init(): could not create hugepte cache\n");
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 0e53ca8f02f..5fce6ccecb8 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -115,6 +115,10 @@ void MMU_setup(void)
if (strstr(cmd_line, "noltlbs")) {
__map_without_ltlbs = 1;
}
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ __map_without_bats = 1;
+ __map_without_ltlbs = 1;
+#endif
}
/*
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index d12a87ec5ae..7312a265545 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -146,21 +146,16 @@ static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
memset(addr, 0, kmem_cache_size(cache));
}
-#ifdef CONFIG_PPC_64K_PAGES
-static const unsigned int pgtable_cache_size[3] = {
- PTE_TABLE_SIZE, PMD_TABLE_SIZE, PGD_TABLE_SIZE
-};
-static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
- "pte_pmd_cache", "pmd_cache", "pgd_cache",
-};
-#else
static const unsigned int pgtable_cache_size[2] = {
- PTE_TABLE_SIZE, PMD_TABLE_SIZE
+ PGD_TABLE_SIZE, PMD_TABLE_SIZE
};
static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = {
- "pgd_pte_cache", "pud_pmd_cache",
-};
+#ifdef CONFIG_PPC_64K_PAGES
+ "pgd_cache", "pmd_cache",
+#else
+ "pgd_cache", "pud_pmd_cache",
#endif /* CONFIG_PPC_64K_PAGES */
+};
#ifdef CONFIG_HUGETLB_PAGE
/* Hugepages need one extra cache, initialized in hugetlbpage.c. We
@@ -183,12 +178,8 @@ void pgtable_cache_init(void)
"for size: %08x...\n", name, i, size);
pgtable_cache[i] = kmem_cache_create(name,
size, size,
- SLAB_HWCACHE_ALIGN |
- SLAB_MUST_HWCACHE_ALIGN,
+ SLAB_PANIC,
zero_ctor,
NULL);
- if (! pgtable_cache[i])
- panic("pgtable_cache_init(): could not create %s!\n",
- name);
}
}
diff --git a/arch/powerpc/mm/lmb.c b/arch/powerpc/mm/lmb.c
index 716a2906a24..e3a1e8dc536 100644
--- a/arch/powerpc/mm/lmb.c
+++ b/arch/powerpc/mm/lmb.c
@@ -146,6 +146,10 @@ static long __init lmb_add_region(struct lmb_region *rgn, unsigned long base,
unsigned long rgnbase = rgn->region[i].base;
unsigned long rgnsize = rgn->region[i].size;
+ if ((rgnbase == base) && (rgnsize == size))
+ /* Already have this region, so we're done */
+ return 0;
+
adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize);
if ( adjacent > 0 ) {
rgn->region[i].base -= size;
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 52f397c108a..246eeea40ec 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -31,6 +31,7 @@
#include <linux/highmem.h>
#include <linux/initrd.h>
#include <linux/pagemap.h>
+#include <linux/suspend.h>
#include <asm/pgalloc.h>
#include <asm/prom.h>
@@ -58,9 +59,6 @@ int init_bootmem_done;
int mem_init_done;
unsigned long memory_limit;
-extern void hash_preload(struct mm_struct *mm, unsigned long ea,
- unsigned long access, unsigned long trap);
-
int page_is_ram(unsigned long pfn)
{
unsigned long paddr = (pfn << PAGE_SHIFT);
@@ -83,7 +81,6 @@ int page_is_ram(unsigned long pfn)
return 0;
#endif
}
-EXPORT_SYMBOL(page_is_ram);
pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t vma_prot)
@@ -280,6 +277,28 @@ void __init do_init_bootmem(void)
init_bootmem_done = 1;
}
+/* mark pages that don't exist as nosave */
+static int __init mark_nonram_nosave(void)
+{
+ unsigned long lmb_next_region_start_pfn,
+ lmb_region_max_pfn;
+ int i;
+
+ for (i = 0; i < lmb.memory.cnt - 1; i++) {
+ lmb_region_max_pfn =
+ (lmb.memory.region[i].base >> PAGE_SHIFT) +
+ (lmb.memory.region[i].size >> PAGE_SHIFT);
+ lmb_next_region_start_pfn =
+ lmb.memory.region[i+1].base >> PAGE_SHIFT;
+
+ if (lmb_region_max_pfn < lmb_next_region_start_pfn)
+ register_nosave_region(lmb_region_max_pfn,
+ lmb_next_region_start_pfn);
+ }
+
+ return 0;
+}
+
/*
* paging_init() sets up the page tables - in fact we've already done this.
*/
@@ -311,6 +330,8 @@ void __init paging_init(void)
max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
#endif
free_area_init_nodes(max_zone_pfns);
+
+ mark_nonram_nosave();
}
#endif /* ! CONFIG_NEED_MULTIPLE_NODES */
diff --git a/arch/powerpc/mm/mmu_context_64.c b/arch/powerpc/mm/mmu_context_64.c
index 90a06ac02d5..7a78cdc0515 100644
--- a/arch/powerpc/mm/mmu_context_64.c
+++ b/arch/powerpc/mm/mmu_context_64.c
@@ -28,6 +28,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
{
int index;
int err;
+ int new_context = (mm->context.id == 0);
again:
if (!idr_pre_get(&mmu_context_idr, GFP_KERNEL))
@@ -50,9 +51,18 @@ again:
}
mm->context.id = index;
+#ifdef CONFIG_PPC_MM_SLICES
+ /* The old code would re-promote on fork, we don't do that
+ * when using slices as it could cause problem promoting slices
+ * that have been forced down to 4K
+ */
+ if (new_context)
+ slice_set_user_psize(mm, mmu_virtual_psize);
+#else
mm->context.user_psize = mmu_virtual_psize;
mm->context.sllp = SLB_VSID_USER |
mmu_psize_defs[mmu_virtual_psize].sllp;
+#endif
return 0;
}
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index bea2d21ac6f..2558c34eeda 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -19,9 +19,14 @@
* 2 of the License, or (at your option) any later version.
*
*/
+#include <linux/mm.h>
#include <asm/tlbflush.h>
#include <asm/mmu.h>
+extern void hash_preload(struct mm_struct *mm, unsigned long ea,
+ unsigned long access, unsigned long trap);
+
+
#ifdef CONFIG_PPC32
extern void mapin_ram(void);
extern int map_page(unsigned long va, phys_addr_t pa, int flags);
@@ -35,7 +40,8 @@ extern int __map_without_bats;
extern unsigned long ioremap_base;
extern unsigned int rtas_data, rtas_size;
-extern PTE *Hash, *Hash_end;
+struct _PTE;
+extern struct _PTE *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern unsigned int num_tlbcam_entries;
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index e86c37c82cf..de45aa82d97 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -74,7 +74,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
while ((cpu_node = of_find_node_by_type(cpu_node, "cpu")) != NULL) {
/* Try interrupt server first */
- interrupt_server = get_property(cpu_node,
+ interrupt_server = of_get_property(cpu_node,
"ibm,ppc-interrupt-server#s", &len);
len = len / sizeof(u32);
@@ -85,7 +85,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
return cpu_node;
}
} else {
- reg = get_property(cpu_node, "reg", &len);
+ reg = of_get_property(cpu_node, "reg", &len);
if (reg && (len > 0) && (reg[0] == hw_cpuid))
return cpu_node;
}
@@ -97,7 +97,7 @@ static struct device_node * __cpuinit find_cpu_node(unsigned int cpu)
/* must hold reference to node during call */
static const int *of_get_associativity(struct device_node *dev)
{
- return get_property(dev, "ibm,associativity", NULL);
+ return of_get_property(dev, "ibm,associativity", NULL);
}
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
@@ -179,7 +179,7 @@ static int __init find_min_common_depth(void)
* configuration (should be all 0's) and the second is for a normal
* NUMA configuration.
*/
- ref_points = get_property(rtas_root,
+ ref_points = of_get_property(rtas_root,
"ibm,associativity-reference-points", &len);
if ((len >= 1) && ref_points) {
@@ -201,8 +201,8 @@ static void __init get_n_mem_cells(int *n_addr_cells, int *n_size_cells)
if (!memory)
panic("numa.c: No memory nodes found!");
- *n_addr_cells = prom_n_addr_cells(memory);
- *n_size_cells = prom_n_size_cells(memory);
+ *n_addr_cells = of_n_addr_cells(memory);
+ *n_size_cells = of_n_size_cells(memory);
of_node_put(memory);
}
@@ -252,12 +252,15 @@ static int __cpuinit cpu_numa_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
numa_setup_cpu(lcpu);
ret = NOTIFY_OK;
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
unmap_cpu_from_node(lcpu);
break;
ret = NOTIFY_OK;
@@ -308,9 +311,9 @@ static void __init parse_drconf_memory(struct device_node *memory)
int nid, default_nid = 0;
unsigned int start, ai, flags;
- lm = get_property(memory, "ibm,lmb-size", &ls);
- dm = get_property(memory, "ibm,dynamic-memory", &ld);
- aa = get_property(memory, "ibm,associativity-lookup-arrays", &la);
+ lm = of_get_property(memory, "ibm,lmb-size", &ls);
+ dm = of_get_property(memory, "ibm,dynamic-memory", &ld);
+ aa = of_get_property(memory, "ibm,associativity-lookup-arrays", &la);
if (!lm || !dm || !aa ||
ls < sizeof(unsigned int) || ld < sizeof(unsigned int) ||
la < 2 * sizeof(unsigned int))
@@ -404,10 +407,10 @@ static int __init parse_numa_properties(void)
const unsigned int *memcell_buf;
unsigned int len;
- memcell_buf = get_property(memory,
+ memcell_buf = of_get_property(memory,
"linux,usable-memory", &len);
if (!memcell_buf || len <= 0)
- memcell_buf = get_property(memory, "reg", &len);
+ memcell_buf = of_get_property(memory, "reg", &len);
if (!memcell_buf || len <= 0)
continue;
@@ -725,7 +728,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
const unsigned int *memcell_buf;
unsigned int len;
- memcell_buf = get_property(memory, "reg", &len);
+ memcell_buf = of_get_property(memory, "reg", &len);
if (!memcell_buf || len <= 0)
continue;
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index c284bdac994..d8232b7a08f 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -183,8 +183,8 @@ __ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
* mem_init() sets high_memory so only do the check after that.
*/
if (mem_init_done && (p < virt_to_phys(high_memory))) {
- printk("__ioremap(): phys addr "PHYS_FMT" is RAM lr %p\n", p,
- __builtin_return_address(0));
+ printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n",
+ (unsigned long long)p, __builtin_return_address(0));
return NULL;
}
@@ -261,14 +261,17 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
int err = -ENOMEM;
/* Use upper 10 bits of VA to index the first level map */
- pd = pmd_offset(pgd_offset_k(va), va);
+ pd = pmd_offset(pud_offset(pgd_offset_k(va), va), va);
/* Use middle 10 bits of VA to index the second-level map */
pg = pte_alloc_kernel(pd, va);
if (pg != 0) {
err = 0;
- set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
- if (mem_init_done)
- flush_HPTE(0, va, pmd_val(*pd));
+ /* The PTE should never be already set nor present in the
+ * hash table
+ */
+ BUG_ON(pte_val(*pg) & (_PAGE_PRESENT | _PAGE_HASHPTE));
+ set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
+ __pgprot(flags)));
}
return err;
}
@@ -279,16 +282,19 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
void __init mapin_ram(void)
{
unsigned long v, p, s, f;
+ int ktext;
s = mmu_mapin_ram();
v = KERNELBASE + s;
p = PPC_MEMSTART + s;
for (; s < total_lowmem; s += PAGE_SIZE) {
- if ((char *) v >= _stext && (char *) v < etext)
- f = _PAGE_RAM_TEXT;
- else
- f = _PAGE_RAM;
+ ktext = ((char *) v >= _stext && (char *) v < etext);
+ f = ktext ?_PAGE_RAM_TEXT : _PAGE_RAM;
map_page(v, p, f);
+#ifdef CONFIG_PPC_STD_MMU_32
+ if (ktext)
+ hash_preload(&init_mm, v, 0, 0x300);
+#endif
v += PAGE_SIZE;
p += PAGE_SIZE;
}
@@ -348,23 +354,27 @@ int
get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
{
pgd_t *pgd;
+ pud_t *pud;
pmd_t *pmd;
pte_t *pte;
int retval = 0;
pgd = pgd_offset(mm, addr & PAGE_MASK);
if (pgd) {
- pmd = pmd_offset(pgd, addr & PAGE_MASK);
- if (pmd_present(*pmd)) {
- pte = pte_offset_map(pmd, addr & PAGE_MASK);
- if (pte) {
- retval = 1;
- *ptep = pte;
- if (pmdp)
- *pmdp = pmd;
- /* XXX caller needs to do pte_unmap, yuck */
- }
- }
+ pud = pud_offset(pgd, addr & PAGE_MASK);
+ if (pud && pud_present(*pud)) {
+ pmd = pmd_offset(pud, addr & PAGE_MASK);
+ if (pmd_present(*pmd)) {
+ pte = pte_offset_map(pmd, addr & PAGE_MASK);
+ if (pte) {
+ retval = 1;
+ *ptep = pte;
+ if (pmdp)
+ *pmdp = pmd;
+ /* XXX caller needs to do pte_unmap, yuck */
+ }
+ }
+ }
}
return(retval);
}
@@ -445,3 +455,55 @@ exit:
return ret;
}
+#ifdef CONFIG_DEBUG_PAGEALLOC
+
+static int __change_page_attr(struct page *page, pgprot_t prot)
+{
+ pte_t *kpte;
+ pmd_t *kpmd;
+ unsigned long address;
+
+ BUG_ON(PageHighMem(page));
+ address = (unsigned long)page_address(page);
+
+ if (v_mapped_by_bats(address) || v_mapped_by_tlbcam(address))
+ return 0;
+ if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
+ return -EINVAL;
+ set_pte_at(&init_mm, address, kpte, mk_pte(page, prot));
+ wmb();
+ flush_HPTE(0, address, pmd_val(*kpmd));
+ pte_unmap(kpte);
+
+ return 0;
+}
+
+/*
+ * Change the page attributes of an page in the linear mapping.
+ *
+ * THIS CONFLICTS WITH BAT MAPPINGS, DEBUG USE ONLY
+ */
+static int change_page_attr(struct page *page, int numpages, pgprot_t prot)
+{
+ int i, err = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ for (i = 0; i < numpages; i++, page++) {
+ err = __change_page_attr(page, prot);
+ if (err)
+ break;
+ }
+ local_irq_restore(flags);
+ return err;
+}
+
+
+void kernel_map_pages(struct page *page, int numpages, int enable)
+{
+ if (PageHighMem(page))
+ return;
+
+ change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0));
+}
+#endif /* CONFIG_DEBUG_PAGEALLOC */
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 7cceb2c44cb..ec1421a20aa 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -85,8 +85,10 @@ unsigned long __init mmu_mapin_ram(void)
unsigned long max_size = (256<<20);
unsigned long align;
- if (__map_without_bats)
+ if (__map_without_bats) {
+ printk(KERN_DEBUG "RAM mapped without BATs\n");
return 0;
+ }
/* Set up BAT2 and if necessary BAT3 to cover RAM. */
@@ -183,7 +185,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
if (Hash == 0)
return;
- pmd = pmd_offset(pgd_offset(mm, ea), ea);
+ pmd = pmd_offset(pud_offset(pgd_offset(mm, ea), ea), ea);
if (!pmd_none(*pmd))
add_hash_page(mm->context.id, ea, pmd_val(*pmd));
}
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 224e960650a..304375a7357 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -198,12 +198,6 @@ void slb_initialize(void)
static int slb_encoding_inited;
extern unsigned int *slb_miss_kernel_load_linear;
extern unsigned int *slb_miss_kernel_load_io;
-#ifdef CONFIG_HUGETLB_PAGE
- extern unsigned int *slb_miss_user_load_huge;
- unsigned long huge_llp;
-
- huge_llp = mmu_psize_defs[mmu_huge_psize].sllp;
-#endif
/* Prepare our SLB miss handler based on our page size */
linear_llp = mmu_psize_defs[mmu_linear_psize].sllp;
@@ -220,11 +214,6 @@ void slb_initialize(void)
DBG("SLB: linear LLP = %04x\n", linear_llp);
DBG("SLB: io LLP = %04x\n", io_llp);
-#ifdef CONFIG_HUGETLB_PAGE
- patch_slb_encoding(slb_miss_user_load_huge,
- SLB_VSID_USER | huge_llp);
- DBG("SLB: huge LLP = %04x\n", huge_llp);
-#endif
}
get_paca()->stab_rr = SLB_NUM_BOLTED;
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index b10e4707d7c..cd1a93d4948 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -82,31 +82,45 @@ _GLOBAL(slb_miss_kernel_load_io)
srdi. r9,r10,USER_ESID_BITS
bne- 8f /* invalid ea bits set */
- /* Figure out if the segment contains huge pages */
-#ifdef CONFIG_HUGETLB_PAGE
-BEGIN_FTR_SECTION
- b 1f
-END_FTR_SECTION_IFCLR(CPU_FTR_16M_PAGE)
+
+ /* when using slices, we extract the psize off the slice bitmaps
+ * and then we need to get the sllp encoding off the mmu_psize_defs
+ * array.
+ *
+ * XXX This is a bit inefficient especially for the normal case,
+ * so we should try to implement a fast path for the standard page
+ * size using the old sllp value so we avoid the array. We cannot
+ * really do dynamic patching unfortunately as processes might flip
+ * between 4k and 64k standard page size
+ */
+#ifdef CONFIG_PPC_MM_SLICES
cmpldi r10,16
- lhz r9,PACALOWHTLBAREAS(r13)
- mr r11,r10
+ /* Get the slice index * 4 in r11 and matching slice size mask in r9 */
+ ld r9,PACALOWSLICESPSIZE(r13)
+ sldi r11,r10,2
blt 5f
+ ld r9,PACAHIGHSLICEPSIZE(r13)
+ srdi r11,r10,(SLICE_HIGH_SHIFT - SLICE_LOW_SHIFT - 2)
+ andi. r11,r11,0x3c
- lhz r9,PACAHIGHHTLBAREAS(r13)
- srdi r11,r10,(HTLB_AREA_SHIFT-SID_SHIFT)
-
-5: srd r9,r9,r11
- andi. r9,r9,1
- beq 1f
-_GLOBAL(slb_miss_user_load_huge)
- li r11,0
- b 2f
-1:
-#endif /* CONFIG_HUGETLB_PAGE */
+5: /* Extract the psize and multiply to get an array offset */
+ srd r9,r9,r11
+ andi. r9,r9,0xf
+ mulli r9,r9,MMUPSIZEDEFSIZE
+ /* Now get to the array and obtain the sllp
+ */
+ ld r11,PACATOC(r13)
+ ld r11,mmu_psize_defs@got(r11)
+ add r11,r11,r9
+ ld r11,MMUPSIZESLLP(r11)
+ ori r11,r11,SLB_VSID_USER
+#else
+ /* paca context sllp already contains the SLB_VSID_USER bits */
lhz r11,PACACONTEXTSLLP(r13)
-2:
+#endif /* CONFIG_PPC_MM_SLICES */
+
ld r9,PACACONTEXTID(r13)
rldimi r10,r9,USER_ESID_BITS,0
b slb_finish_load
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
new file mode 100644
index 00000000000..f833dba2a02
--- /dev/null
+++ b/arch/powerpc/mm/slice.c
@@ -0,0 +1,633 @@
+/*
+ * address space "slices" (meta-segments) support
+ *
+ * Copyright (C) 2007 Benjamin Herrenschmidt, IBM Corporation.
+ *
+ * Based on hugetlb implementation
+ *
+ * Copyright (C) 2003 David Gibson, IBM Corporation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/mman.h>
+#include <asm/mmu.h>
+#include <asm/spu.h>
+
+static spinlock_t slice_convert_lock = SPIN_LOCK_UNLOCKED;
+
+
+#ifdef DEBUG
+int _slice_debug = 1;
+
+static void slice_print_mask(const char *label, struct slice_mask mask)
+{
+ char *p, buf[16 + 3 + 16 + 1];
+ int i;
+
+ if (!_slice_debug)
+ return;
+ p = buf;
+ for (i = 0; i < SLICE_NUM_LOW; i++)
+ *(p++) = (mask.low_slices & (1 << i)) ? '1' : '0';
+ *(p++) = ' ';
+ *(p++) = '-';
+ *(p++) = ' ';
+ for (i = 0; i < SLICE_NUM_HIGH; i++)
+ *(p++) = (mask.high_slices & (1 << i)) ? '1' : '0';
+ *(p++) = 0;
+
+ printk(KERN_DEBUG "%s:%s\n", label, buf);
+}
+
+#define slice_dbg(fmt...) do { if (_slice_debug) pr_debug(fmt); } while(0)
+
+#else
+
+static void slice_print_mask(const char *label, struct slice_mask mask) {}
+#define slice_dbg(fmt...)
+
+#endif
+
+static struct slice_mask slice_range_to_mask(unsigned long start,
+ unsigned long len)
+{
+ unsigned long end = start + len - 1;
+ struct slice_mask ret = { 0, 0 };
+
+ if (start < SLICE_LOW_TOP) {
+ unsigned long mend = min(end, SLICE_LOW_TOP);
+ unsigned long mstart = min(start, SLICE_LOW_TOP);
+
+ ret.low_slices = (1u << (GET_LOW_SLICE_INDEX(mend) + 1))
+ - (1u << GET_LOW_SLICE_INDEX(mstart));
+ }
+
+ if ((start + len) > SLICE_LOW_TOP)
+ ret.high_slices = (1u << (GET_HIGH_SLICE_INDEX(end) + 1))
+ - (1u << GET_HIGH_SLICE_INDEX(start));
+
+ return ret;
+}
+
+static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
+ unsigned long len)
+{
+ struct vm_area_struct *vma;
+
+ if ((mm->task_size - len) < addr)
+ return 0;
+ vma = find_vma(mm, addr);
+ return (!vma || (addr + len) <= vma->vm_start);
+}
+
+static int slice_low_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+ return !slice_area_is_free(mm, slice << SLICE_LOW_SHIFT,
+ 1ul << SLICE_LOW_SHIFT);
+}
+
+static int slice_high_has_vma(struct mm_struct *mm, unsigned long slice)
+{
+ unsigned long start = slice << SLICE_HIGH_SHIFT;
+ unsigned long end = start + (1ul << SLICE_HIGH_SHIFT);
+
+ /* Hack, so that each addresses is controlled by exactly one
+ * of the high or low area bitmaps, the first high area starts
+ * at 4GB, not 0 */
+ if (start == 0)
+ start = SLICE_LOW_TOP;
+
+ return !slice_area_is_free(mm, start, end - start);
+}
+
+static struct slice_mask slice_mask_for_free(struct mm_struct *mm)
+{
+ struct slice_mask ret = { 0, 0 };
+ unsigned long i;
+
+ for (i = 0; i < SLICE_NUM_LOW; i++)
+ if (!slice_low_has_vma(mm, i))
+ ret.low_slices |= 1u << i;
+
+ if (mm->task_size <= SLICE_LOW_TOP)
+ return ret;
+
+ for (i = 0; i < SLICE_NUM_HIGH; i++)
+ if (!slice_high_has_vma(mm, i))
+ ret.high_slices |= 1u << i;
+
+ return ret;
+}
+
+static struct slice_mask slice_mask_for_size(struct mm_struct *mm, int psize)
+{
+ struct slice_mask ret = { 0, 0 };
+ unsigned long i;
+ u64 psizes;
+
+ psizes = mm->context.low_slices_psize;
+ for (i = 0; i < SLICE_NUM_LOW; i++)
+ if (((psizes >> (i * 4)) & 0xf) == psize)
+ ret.low_slices |= 1u << i;
+
+ psizes = mm->context.high_slices_psize;
+ for (i = 0; i < SLICE_NUM_HIGH; i++)
+ if (((psizes >> (i * 4)) & 0xf) == psize)
+ ret.high_slices |= 1u << i;
+
+ return ret;
+}
+
+static int slice_check_fit(struct slice_mask mask, struct slice_mask available)
+{
+ return (mask.low_slices & available.low_slices) == mask.low_slices &&
+ (mask.high_slices & available.high_slices) == mask.high_slices;
+}
+
+static void slice_flush_segments(void *parm)
+{
+ struct mm_struct *mm = parm;
+ unsigned long flags;
+
+ if (mm != current->active_mm)
+ return;
+
+ /* update the paca copy of the context struct */
+ get_paca()->context = current->active_mm->context;
+
+ local_irq_save(flags);
+ slb_flush_and_rebolt();
+ local_irq_restore(flags);
+}
+
+static void slice_convert(struct mm_struct *mm, struct slice_mask mask, int psize)
+{
+ /* Write the new slice psize bits */
+ u64 lpsizes, hpsizes;
+ unsigned long i, flags;
+
+ slice_dbg("slice_convert(mm=%p, psize=%d)\n", mm, psize);
+ slice_print_mask(" mask", mask);
+
+ /* We need to use a spinlock here to protect against
+ * concurrent 64k -> 4k demotion ...
+ */
+ spin_lock_irqsave(&slice_convert_lock, flags);
+
+ lpsizes = mm->context.low_slices_psize;
+ for (i = 0; i < SLICE_NUM_LOW; i++)
+ if (mask.low_slices & (1u << i))
+ lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+ (((unsigned long)psize) << (i * 4));
+
+ hpsizes = mm->context.high_slices_psize;
+ for (i = 0; i < SLICE_NUM_HIGH; i++)
+ if (mask.high_slices & (1u << i))
+ hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+ (((unsigned long)psize) << (i * 4));
+
+ mm->context.low_slices_psize = lpsizes;
+ mm->context.high_slices_psize = hpsizes;
+
+ slice_dbg(" lsps=%lx, hsps=%lx\n",
+ mm->context.low_slices_psize,
+ mm->context.high_slices_psize);
+
+ spin_unlock_irqrestore(&slice_convert_lock, flags);
+ mb();
+
+ /* XXX this is sub-optimal but will do for now */
+ on_each_cpu(slice_flush_segments, mm, 0, 1);
+#ifdef CONFIG_SPU_BASE
+ spu_flush_all_slbs(mm);
+#endif
+}
+
+static unsigned long slice_find_area_bottomup(struct mm_struct *mm,
+ unsigned long len,
+ struct slice_mask available,
+ int psize, int use_cache)
+{
+ struct vm_area_struct *vma;
+ unsigned long start_addr, addr;
+ struct slice_mask mask;
+ int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+ if (use_cache) {
+ if (len <= mm->cached_hole_size) {
+ start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ } else
+ start_addr = addr = mm->free_area_cache;
+ } else
+ start_addr = addr = TASK_UNMAPPED_BASE;
+
+full_search:
+ for (;;) {
+ addr = _ALIGN_UP(addr, 1ul << pshift);
+ if ((TASK_SIZE - len) < addr)
+ break;
+ vma = find_vma(mm, addr);
+ BUG_ON(vma && (addr >= vma->vm_end));
+
+ mask = slice_range_to_mask(addr, len);
+ if (!slice_check_fit(mask, available)) {
+ if (addr < SLICE_LOW_TOP)
+ addr = _ALIGN_UP(addr + 1, 1ul << SLICE_LOW_SHIFT);
+ else
+ addr = _ALIGN_UP(addr + 1, 1ul << SLICE_HIGH_SHIFT);
+ continue;
+ }
+ if (!vma || addr + len <= vma->vm_start) {
+ /*
+ * Remember the place where we stopped the search:
+ */
+ if (use_cache)
+ mm->free_area_cache = addr + len;
+ return addr;
+ }
+ if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+ addr = vma->vm_end;
+ }
+
+ /* Make sure we didn't miss any holes */
+ if (use_cache && start_addr != TASK_UNMAPPED_BASE) {
+ start_addr = addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ goto full_search;
+ }
+ return -ENOMEM;
+}
+
+static unsigned long slice_find_area_topdown(struct mm_struct *mm,
+ unsigned long len,
+ struct slice_mask available,
+ int psize, int use_cache)
+{
+ struct vm_area_struct *vma;
+ unsigned long addr;
+ struct slice_mask mask;
+ int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+
+ /* check if free_area_cache is useful for us */
+ if (use_cache) {
+ if (len <= mm->cached_hole_size) {
+ mm->cached_hole_size = 0;
+ mm->free_area_cache = mm->mmap_base;
+ }
+
+ /* either no address requested or can't fit in requested
+ * address hole
+ */
+ addr = mm->free_area_cache;
+
+ /* make sure it can fit in the remaining address space */
+ if (addr > len) {
+ addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+ mask = slice_range_to_mask(addr, len);
+ if (slice_check_fit(mask, available) &&
+ slice_area_is_free(mm, addr, len))
+ /* remember the address as a hint for
+ * next time
+ */
+ return (mm->free_area_cache = addr);
+ }
+ }
+
+ addr = mm->mmap_base;
+ while (addr > len) {
+ /* Go down by chunk size */
+ addr = _ALIGN_DOWN(addr - len, 1ul << pshift);
+
+ /* Check for hit with different page size */
+ mask = slice_range_to_mask(addr, len);
+ if (!slice_check_fit(mask, available)) {
+ if (addr < SLICE_LOW_TOP)
+ addr = _ALIGN_DOWN(addr, 1ul << SLICE_LOW_SHIFT);
+ else if (addr < (1ul << SLICE_HIGH_SHIFT))
+ addr = SLICE_LOW_TOP;
+ else
+ addr = _ALIGN_DOWN(addr, 1ul << SLICE_HIGH_SHIFT);
+ continue;
+ }
+
+ /*
+ * Lookup failure means no vma is above this address,
+ * else if new region fits below vma->vm_start,
+ * return with success:
+ */
+ vma = find_vma(mm, addr);
+ if (!vma || (addr + len) <= vma->vm_start) {
+ /* remember the address as a hint for next time */
+ if (use_cache)
+ mm->free_area_cache = addr;
+ return addr;
+ }
+
+ /* remember the largest hole we saw so far */
+ if (use_cache && (addr + mm->cached_hole_size) < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+
+ /* try just below the current vma->vm_start */
+ addr = vma->vm_start;
+ }
+
+ /*
+ * A failed mmap() very likely causes application failure,
+ * so fall back to the bottom-up function here. This scenario
+ * can happen with large stack limits and large mmap()
+ * allocations.
+ */
+ addr = slice_find_area_bottomup(mm, len, available, psize, 0);
+
+ /*
+ * Restore the topdown base:
+ */
+ if (use_cache) {
+ mm->free_area_cache = mm->mmap_base;
+ mm->cached_hole_size = ~0UL;
+ }
+
+ return addr;
+}
+
+
+static unsigned long slice_find_area(struct mm_struct *mm, unsigned long len,
+ struct slice_mask mask, int psize,
+ int topdown, int use_cache)
+{
+ if (topdown)
+ return slice_find_area_topdown(mm, len, mask, psize, use_cache);
+ else
+ return slice_find_area_bottomup(mm, len, mask, psize, use_cache);
+}
+
+unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
+ unsigned long flags, unsigned int psize,
+ int topdown, int use_cache)
+{
+ struct slice_mask mask;
+ struct slice_mask good_mask;
+ struct slice_mask potential_mask = {0,0} /* silence stupid warning */;
+ int pmask_set = 0;
+ int fixed = (flags & MAP_FIXED);
+ int pshift = max_t(int, mmu_psize_defs[psize].shift, PAGE_SHIFT);
+ struct mm_struct *mm = current->mm;
+
+ /* Sanity checks */
+ BUG_ON(mm->task_size == 0);
+
+ slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
+ slice_dbg(" addr=%lx, len=%lx, flags=%lx, topdown=%d, use_cache=%d\n",
+ addr, len, flags, topdown, use_cache);
+
+ if (len > mm->task_size)
+ return -ENOMEM;
+ if (fixed && (addr & ((1ul << pshift) - 1)))
+ return -EINVAL;
+ if (fixed && addr > (mm->task_size - len))
+ return -EINVAL;
+
+ /* If hint, make sure it matches our alignment restrictions */
+ if (!fixed && addr) {
+ addr = _ALIGN_UP(addr, 1ul << pshift);
+ slice_dbg(" aligned addr=%lx\n", addr);
+ }
+
+ /* First makeup a "good" mask of slices that have the right size
+ * already
+ */
+ good_mask = slice_mask_for_size(mm, psize);
+ slice_print_mask(" good_mask", good_mask);
+
+ /* First check hint if it's valid or if we have MAP_FIXED */
+ if ((addr != 0 || fixed) && (mm->task_size - len) >= addr) {
+
+ /* Don't bother with hint if it overlaps a VMA */
+ if (!fixed && !slice_area_is_free(mm, addr, len))
+ goto search;
+
+ /* Build a mask for the requested range */
+ mask = slice_range_to_mask(addr, len);
+ slice_print_mask(" mask", mask);
+
+ /* Check if we fit in the good mask. If we do, we just return,
+ * nothing else to do
+ */
+ if (slice_check_fit(mask, good_mask)) {
+ slice_dbg(" fits good !\n");
+ return addr;
+ }
+
+ /* We don't fit in the good mask, check what other slices are
+ * empty and thus can be converted
+ */
+ potential_mask = slice_mask_for_free(mm);
+ potential_mask.low_slices |= good_mask.low_slices;
+ potential_mask.high_slices |= good_mask.high_slices;
+ pmask_set = 1;
+ slice_print_mask(" potential", potential_mask);
+ if (slice_check_fit(mask, potential_mask)) {
+ slice_dbg(" fits potential !\n");
+ goto convert;
+ }
+ }
+
+ /* If we have MAP_FIXED and failed the above step, then error out */
+ if (fixed)
+ return -EBUSY;
+
+ search:
+ slice_dbg(" search...\n");
+
+ /* Now let's see if we can find something in the existing slices
+ * for that size
+ */
+ addr = slice_find_area(mm, len, good_mask, psize, topdown, use_cache);
+ if (addr != -ENOMEM) {
+ /* Found within the good mask, we don't have to setup,
+ * we thus return directly
+ */
+ slice_dbg(" found area at 0x%lx\n", addr);
+ return addr;
+ }
+
+ /* Won't fit, check what can be converted */
+ if (!pmask_set) {
+ potential_mask = slice_mask_for_free(mm);
+ potential_mask.low_slices |= good_mask.low_slices;
+ potential_mask.high_slices |= good_mask.high_slices;
+ pmask_set = 1;
+ slice_print_mask(" potential", potential_mask);
+ }
+
+ /* Now let's see if we can find something in the existing slices
+ * for that size
+ */
+ addr = slice_find_area(mm, len, potential_mask, psize, topdown,
+ use_cache);
+ if (addr == -ENOMEM)
+ return -ENOMEM;
+
+ mask = slice_range_to_mask(addr, len);
+ slice_dbg(" found potential area at 0x%lx\n", addr);
+ slice_print_mask(" mask", mask);
+
+ convert:
+ slice_convert(mm, mask, psize);
+ return addr;
+
+}
+EXPORT_SYMBOL_GPL(slice_get_unmapped_area);
+
+unsigned long arch_get_unmapped_area(struct file *filp,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ return slice_get_unmapped_area(addr, len, flags,
+ current->mm->context.user_psize,
+ 0, 1);
+}
+
+unsigned long arch_get_unmapped_area_topdown(struct file *filp,
+ const unsigned long addr0,
+ const unsigned long len,
+ const unsigned long pgoff,
+ const unsigned long flags)
+{
+ return slice_get_unmapped_area(addr0, len, flags,
+ current->mm->context.user_psize,
+ 1, 1);
+}
+
+unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
+{
+ u64 psizes;
+ int index;
+
+ if (addr < SLICE_LOW_TOP) {
+ psizes = mm->context.low_slices_psize;
+ index = GET_LOW_SLICE_INDEX(addr);
+ } else {
+ psizes = mm->context.high_slices_psize;
+ index = GET_HIGH_SLICE_INDEX(addr);
+ }
+
+ return (psizes >> (index * 4)) & 0xf;
+}
+EXPORT_SYMBOL_GPL(get_slice_psize);
+
+/*
+ * This is called by hash_page when it needs to do a lazy conversion of
+ * an address space from real 64K pages to combo 4K pages (typically
+ * when hitting a non cacheable mapping on a processor or hypervisor
+ * that won't allow them for 64K pages).
+ *
+ * This is also called in init_new_context() to change back the user
+ * psize from whatever the parent context had it set to
+ *
+ * This function will only change the content of the {low,high)_slice_psize
+ * masks, it will not flush SLBs as this shall be handled lazily by the
+ * caller.
+ */
+void slice_set_user_psize(struct mm_struct *mm, unsigned int psize)
+{
+ unsigned long flags, lpsizes, hpsizes;
+ unsigned int old_psize;
+ int i;
+
+ slice_dbg("slice_set_user_psize(mm=%p, psize=%d)\n", mm, psize);
+
+ spin_lock_irqsave(&slice_convert_lock, flags);
+
+ old_psize = mm->context.user_psize;
+ slice_dbg(" old_psize=%d\n", old_psize);
+ if (old_psize == psize)
+ goto bail;
+
+ mm->context.user_psize = psize;
+ wmb();
+
+ lpsizes = mm->context.low_slices_psize;
+ for (i = 0; i < SLICE_NUM_LOW; i++)
+ if (((lpsizes >> (i * 4)) & 0xf) == old_psize)
+ lpsizes = (lpsizes & ~(0xful << (i * 4))) |
+ (((unsigned long)psize) << (i * 4));
+
+ hpsizes = mm->context.high_slices_psize;
+ for (i = 0; i < SLICE_NUM_HIGH; i++)
+ if (((hpsizes >> (i * 4)) & 0xf) == old_psize)
+ hpsizes = (hpsizes & ~(0xful << (i * 4))) |
+ (((unsigned long)psize) << (i * 4));
+
+ mm->context.low_slices_psize = lpsizes;
+ mm->context.high_slices_psize = hpsizes;
+
+ slice_dbg(" lsps=%lx, hsps=%lx\n",
+ mm->context.low_slices_psize,
+ mm->context.high_slices_psize);
+
+ bail:
+ spin_unlock_irqrestore(&slice_convert_lock, flags);
+}
+
+/*
+ * is_hugepage_only_range() is used by generic code to verify wether
+ * a normal mmap mapping (non hugetlbfs) is valid on a given area.
+ *
+ * until the generic code provides a more generic hook and/or starts
+ * calling arch get_unmapped_area for MAP_FIXED (which our implementation
+ * here knows how to deal with), we hijack it to keep standard mappings
+ * away from us.
+ *
+ * because of that generic code limitation, MAP_FIXED mapping cannot
+ * "convert" back a slice with no VMAs to the standard page size, only
+ * get_unmapped_area() can. It would be possible to fix it here but I
+ * prefer working on fixing the generic code instead.
+ *
+ * WARNING: This will not work if hugetlbfs isn't enabled since the
+ * generic code will redefine that function as 0 in that. This is ok
+ * for now as we only use slices with hugetlbfs enabled. This should
+ * be fixed as the generic code gets fixed.
+ */
+int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
+ unsigned long len)
+{
+ struct slice_mask mask, available;
+
+ mask = slice_range_to_mask(addr, len);
+ available = slice_mask_for_size(mm, mm->context.user_psize);
+
+#if 0 /* too verbose */
+ slice_dbg("is_hugepage_only_range(mm=%p, addr=%lx, len=%lx)\n",
+ mm, addr, len);
+ slice_print_mask(" mask", mask);
+ slice_print_mask(" available", available);
+#endif
+ return !slice_check_fit(mask, available);
+}
+
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index eeeacab548e..132c6bc66ce 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -227,7 +227,7 @@ void switch_stab(struct task_struct *tsk, struct mm_struct *mm)
* the first (bolted) segment, so that do_stab_bolted won't get a
* recursive segment miss on the segment table itself.
*/
-void stabs_alloc(void)
+void __init stabs_alloc(void)
{
int cpu;
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
index 925ff70be8b..6a69417cbc0 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_32.c
@@ -111,7 +111,7 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
if (start >= end)
return;
end = (end - 1) | ~PAGE_MASK;
- pmd = pmd_offset(pgd_offset(mm, start), start);
+ pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start);
for (;;) {
pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
if (pmd_end > end)
@@ -169,7 +169,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
return;
}
mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
- pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
+ pmd = pmd_offset(pud_offset(pgd_offset(mm, vmaddr), vmaddr), vmaddr);
if (!pmd_none(*pmd))
flush_hash_pages(mm->context.id, vmaddr, pmd_val(*pmd), 1);
FINISH_FLUSH;
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index b58baa65c4a..2bfc4d7e1aa 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -120,17 +120,20 @@ void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf)
}
/*
- * Update the MMU hash table to correspond with a change to
- * a Linux PTE. If wrprot is true, it is permissible to
- * change the existing HPTE to read-only rather than removing it
- * (if we remove it we should clear the _PTE_HPTEFLAGS bits).
+ * A linux PTE was changed and the corresponding hash table entry
+ * neesd to be flushed. This function will either perform the flush
+ * immediately or will batch it up if the current CPU has an active
+ * batch on it.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
*/
-void hpte_update(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, unsigned long pte, int huge)
+void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, unsigned long pte, int huge)
{
struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
- unsigned long vsid;
+ unsigned long vsid, vaddr;
unsigned int psize;
+ real_pte_t rpte;
int i;
i = batch->index;
@@ -140,16 +143,42 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
*/
addr &= PAGE_MASK;
- /* Get page size (maybe move back to caller) */
+ /* Get page size (maybe move back to caller).
+ *
+ * NOTE: when using special 64K mappings in 4K environment like
+ * for SPEs, we obtain the page size from the slice, which thus
+ * must still exist (and thus the VMA not reused) at the time
+ * of this call
+ */
if (huge) {
#ifdef CONFIG_HUGETLB_PAGE
psize = mmu_huge_psize;
#else
BUG();
- psize = pte_pagesize_index(pte); /* shutup gcc */
+ psize = pte_pagesize_index(mm, addr, pte); /* shutup gcc */
#endif
} else
- psize = pte_pagesize_index(pte);
+ psize = pte_pagesize_index(mm, addr, pte);
+
+ /* Build full vaddr */
+ if (!is_kernel_addr(addr)) {
+ vsid = get_vsid(mm->context.id, addr);
+ WARN_ON(vsid == 0);
+ } else
+ vsid = get_kernel_vsid(addr);
+ vaddr = (vsid << 28 ) | (addr & 0x0fffffff);
+ rpte = __real_pte(__pte(pte), ptep);
+
+ /*
+ * Check if we have an active batch on this CPU. If not, just
+ * flush now and return. For now, we don global invalidates
+ * in that case, might be worth testing the mm cpu mask though
+ * and decide to use local invalidates instead...
+ */
+ if (!batch->active) {
+ flush_hash_page(vaddr, rpte, psize, 0);
+ return;
+ }
/*
* This can happen when we are in the middle of a TLB batch and
@@ -162,47 +191,42 @@ void hpte_update(struct mm_struct *mm, unsigned long addr,
* batch
*/
if (i != 0 && (mm != batch->mm || batch->psize != psize)) {
- flush_tlb_pending();
+ __flush_tlb_pending(batch);
i = 0;
}
if (i == 0) {
batch->mm = mm;
batch->psize = psize;
}
- if (!is_kernel_addr(addr)) {
- vsid = get_vsid(mm->context.id, addr);
- WARN_ON(vsid == 0);
- } else
- vsid = get_kernel_vsid(addr);
- batch->vaddr[i] = (vsid << 28 ) | (addr & 0x0fffffff);
- batch->pte[i] = __real_pte(__pte(pte), ptep);
+ batch->pte[i] = rpte;
+ batch->vaddr[i] = vaddr;
batch->index = ++i;
if (i >= PPC64_TLB_BATCH_NR)
- flush_tlb_pending();
+ __flush_tlb_pending(batch);
}
+/*
+ * This function is called when terminating an mmu batch or when a batch
+ * is full. It will perform the flush of all the entries currently stored
+ * in a batch.
+ *
+ * Must be called from within some kind of spinlock/non-preempt region...
+ */
void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
{
- int i;
- int cpu;
cpumask_t tmp;
- int local = 0;
-
- BUG_ON(in_interrupt());
+ int i, local = 0;
- cpu = get_cpu();
i = batch->index;
- tmp = cpumask_of_cpu(cpu);
+ tmp = cpumask_of_cpu(smp_processor_id());
if (cpus_equal(batch->mm->cpu_vm_mask, tmp))
local = 1;
-
if (i == 1)
flush_hash_page(batch->vaddr[0], batch->pte[0],
batch->psize, local);
else
flush_hash_range(i, local);
batch->index = 0;
- put_cpu();
}
void pte_free_finish(void)
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 4ccef2d5530..4b5f9528218 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -12,6 +12,6 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
-oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
+oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index fbd62eacfdf..1a7ef7e246d 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -160,6 +160,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
case PPC_OPROFILE_POWER4:
model = &op_model_power4;
break;
+ case PPC_OPROFILE_PA6T:
+ model = &op_model_pa6t;
+ break;
#endif
#ifdef CONFIG_6xx
case PPC_OPROFILE_G4:
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index e08e1d7b3dc..c29293befba 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -37,6 +37,7 @@
#include <asm/system.h>
#include "../platforms/cell/interrupt.h"
+#include "../platforms/cell/cbe_regs.h"
#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */
#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
@@ -130,7 +131,7 @@ static int pm_rtas_token;
static u32 reset_value[NR_PHYS_CTRS];
static int num_counters;
static int oprofile_running;
-static spinlock_t virt_cntr_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(virt_cntr_lock);
static u32 ctr_enabled;
@@ -746,7 +747,7 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
* counter value etc.) are not copied to the actual registers
* until the performance monitor is enabled. In order to get
* this to work as desired, the permormance monitor needs to
- * be disabled while writting to the latches. This is a
+ * be disabled while writing to the latches. This is a
* HW design issue.
*/
cbe_enable_pm(cpu);
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
new file mode 100644
index 00000000000..e8a56b0adad
--- /dev/null
+++ b/arch/powerpc/oprofile/op_model_pa6t.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Shashi Rao, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/oprofile/op_model_power4.c
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/percpu.h>
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include <asm/oprofile_impl.h>
+#include <asm/reg.h>
+
+static unsigned char oprofile_running;
+
+/* mmcr values are set in pa6t_reg_setup, used in pa6t_cpu_setup */
+static u64 mmcr0_val;
+static u64 mmcr1_val;
+
+/* inited in pa6t_reg_setup */
+static u64 reset_value[OP_MAX_COUNTER];
+
+static inline u64 ctr_read(unsigned int i)
+{
+ switch (i) {
+ case 0:
+ return mfspr(SPRN_PA6T_PMC0);
+ case 1:
+ return mfspr(SPRN_PA6T_PMC1);
+ case 2:
+ return mfspr(SPRN_PA6T_PMC2);
+ case 3:
+ return mfspr(SPRN_PA6T_PMC3);
+ case 4:
+ return mfspr(SPRN_PA6T_PMC4);
+ case 5:
+ return mfspr(SPRN_PA6T_PMC5);
+ default:
+ printk(KERN_ERR "ctr_read called with bad arg %u\n", i);
+ return 0;
+ }
+}
+
+static inline void ctr_write(unsigned int i, u64 val)
+{
+ switch (i) {
+ case 0:
+ mtspr(SPRN_PA6T_PMC0, val);
+ break;
+ case 1:
+ mtspr(SPRN_PA6T_PMC1, val);
+ break;
+ case 2:
+ mtspr(SPRN_PA6T_PMC2, val);
+ break;
+ case 3:
+ mtspr(SPRN_PA6T_PMC3, val);
+ break;
+ case 4:
+ mtspr(SPRN_PA6T_PMC4, val);
+ break;
+ case 5:
+ mtspr(SPRN_PA6T_PMC5, val);
+ break;
+ default:
+ printk(KERN_ERR "ctr_write called with bad arg %u\n", i);
+ break;
+ }
+}
+
+
+/* precompute the values to stuff in the hardware registers */
+static void pa6t_reg_setup(struct op_counter_config *ctr,
+ struct op_system_config *sys,
+ int num_ctrs)
+{
+ int pmc;
+
+ /*
+ * adjust the mmcr0.en[0-5] and mmcr0.inten[0-5] values obtained from the
+ * event_mappings file by turning off the counters that the user doesn't
+ * care about
+ *
+ * setup user and kernel profiling
+ */
+ for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++)
+ if (!ctr[pmc].enabled) {
+ sys->mmcr0 &= ~(0x1UL << pmc);
+ sys->mmcr0 &= ~(0x1UL << (pmc+12));
+ pr_debug("turned off counter %u\n", pmc);
+ }
+
+ if (sys->enable_kernel)
+ sys->mmcr0 |= PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN;
+ else
+ sys->mmcr0 &= ~(PA6T_MMCR0_SUPEN | PA6T_MMCR0_HYPEN);
+
+ if (sys->enable_user)
+ sys->mmcr0 |= PA6T_MMCR0_PREN;
+ else
+ sys->mmcr0 &= ~PA6T_MMCR0_PREN;
+
+ /*
+ * The performance counter event settings are given in the mmcr0 and
+ * mmcr1 values passed from the user in the op_system_config
+ * structure (sys variable).
+ */
+ mmcr0_val = sys->mmcr0;
+ mmcr1_val = sys->mmcr1;
+ pr_debug("mmcr0_val inited to %016lx\n", sys->mmcr0);
+ pr_debug("mmcr1_val inited to %016lx\n", sys->mmcr1);
+
+ for (pmc = 0; pmc < cur_cpu_spec->num_pmcs; pmc++) {
+ /* counters are 40 bit. Move to cputable at some point? */
+ reset_value[pmc] = (0x1UL << 39) - ctr[pmc].count;
+ pr_debug("reset_value for pmc%u inited to 0x%lx\n",
+ pmc, reset_value[pmc]);
+ }
+}
+
+/* configure registers on this cpu */
+static void pa6t_cpu_setup(struct op_counter_config *ctr)
+{
+ u64 mmcr0 = mmcr0_val;
+ u64 mmcr1 = mmcr1_val;
+
+ /* Default is all PMCs off */
+ mmcr0 &= ~(0x3FUL);
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+ /* program selected programmable events in */
+ mtspr(SPRN_PA6T_MMCR1, mmcr1);
+
+ pr_debug("setup on cpu %d, mmcr0 %016lx\n", smp_processor_id(),
+ mfspr(SPRN_PA6T_MMCR0));
+ pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
+ mfspr(SPRN_PA6T_MMCR1));
+}
+
+static void pa6t_start(struct op_counter_config *ctr)
+{
+ int i;
+
+ /* Hold off event counting until rfid */
+ u64 mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+
+ for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
+ if (ctr[i].enabled)
+ ctr_write(i, reset_value[i]);
+ else
+ ctr_write(i, 0UL);
+
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+ oprofile_running = 1;
+
+ pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+static void pa6t_stop(void)
+{
+ u64 mmcr0;
+
+ /* freeze counters */
+ mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+ mmcr0 |= PA6T_MMCR0_FCM0;
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+
+ oprofile_running = 0;
+
+ pr_debug("stop on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+}
+
+/* handle the perfmon overflow vector */
+static void pa6t_handle_interrupt(struct pt_regs *regs,
+ struct op_counter_config *ctr)
+{
+ unsigned long pc = mfspr(SPRN_PA6T_SIAR);
+ int is_kernel = is_kernel_addr(pc);
+ u64 val;
+ int i;
+ u64 mmcr0;
+
+ /* disable perfmon counting until rfid */
+ mmcr0 = mfspr(SPRN_PA6T_MMCR0);
+ mtspr(SPRN_PA6T_MMCR0, mmcr0 | PA6T_MMCR0_HANDDIS);
+
+ /* Record samples. We've got one global bit for whether a sample
+ * was taken, so add it for any counter that triggered overflow.
+ */
+ for (i = 0; i < cur_cpu_spec->num_pmcs; i++) {
+ val = ctr_read(i);
+ if (val & (0x1UL << 39)) { /* Overflow bit set */
+ if (oprofile_running && ctr[i].enabled) {
+ if (mmcr0 & PA6T_MMCR0_SIARLOG)
+ oprofile_add_ext_sample(pc, regs, i, is_kernel);
+ ctr_write(i, reset_value[i]);
+ } else {
+ ctr_write(i, 0UL);
+ }
+ }
+ }
+
+ /* Restore mmcr0 to a good known value since the PMI changes it */
+ mmcr0 = mmcr0_val | PA6T_MMCR0_HANDDIS;
+ mtspr(SPRN_PA6T_MMCR0, mmcr0);
+}
+
+struct op_powerpc_model op_model_pa6t = {
+ .reg_setup = pa6t_reg_setup,
+ .cpu_setup = pa6t_cpu_setup,
+ .start = pa6t_start,
+ .stop = pa6t_stop,
+ .handle_interrupt = pa6t_handle_interrupt,
+};
diff --git a/arch/powerpc/platforms/44x/44x.h b/arch/powerpc/platforms/44x/44x.h
new file mode 100644
index 00000000000..42eabf87fea
--- /dev/null
+++ b/arch/powerpc/platforms/44x/44x.h
@@ -0,0 +1,8 @@
+#ifndef __POWERPC_PLATFORMS_44X_44X_H
+#define __POWERPC_PLATFORMS_44X_44X_H
+
+extern u8 as1_readb(volatile u8 __iomem *addr);
+extern void as1_writeb(u8 data, volatile u8 __iomem *addr);
+extern void ppc44x_reset_system(char *cmd);
+
+#endif /* __POWERPC_PLATFORMS_44X_44X_H */
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
new file mode 100644
index 00000000000..8e66949e7c6
--- /dev/null
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -0,0 +1,56 @@
+#config BAMBOO
+# bool "Bamboo"
+# depends on 44x
+# default n
+# select 440EP
+# help
+# This option enables support for the IBM PPC440EP evaluation board.
+
+config EBONY
+ bool "Ebony"
+ depends on 44x
+ default y
+ select 440GP
+ help
+ This option enables support for the IBM PPC440GP evaluation board.
+
+#config LUAN
+# bool "Luan"
+# depends on 44x
+# default n
+# select 440SP
+# help
+# This option enables support for the IBM PPC440SP evaluation board.
+
+#config OCOTEA
+# bool "Ocotea"
+# depends on 44x
+# default n
+# select 440GX
+# help
+# This option enables support for the IBM PPC440GX evaluation board.
+
+# 44x specific CPU modules, selected based on the board above.
+config 440EP
+ bool
+ select PPC_FPU
+ select IBM440EP_ERR42
+
+config 440GP
+ bool
+ select IBM_NEW_EMAC_ZMII
+
+config 440GX
+ bool
+
+config 440SP
+ bool
+
+config 440A
+ bool
+ depends on 440GX
+ default y
+
+# 44x errata/workaround config symbols, selected by the CPU models above
+config IBM440EP_ERR42
+ bool
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
new file mode 100644
index 00000000000..41d0a18a0e4
--- /dev/null
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_44x) := misc_44x.o
+obj-$(CONFIG_EBONY) += ebony.o
diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c
new file mode 100644
index 00000000000..ad526eafc90
--- /dev/null
+++ b/arch/powerpc/platforms/44x/ebony.c
@@ -0,0 +1,73 @@
+/*
+ * Ebony board specific routines
+ *
+ * Matt Porter <mporter@kernel.crashing.org>
+ * Copyright 2002-2005 MontaVista Software Inc.
+ *
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ * Copyright (c) 2003-2005 Zultys Technologies
+ *
+ * Rewritten and ported to the merged powerpc tree:
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/time.h>
+#include <asm/uic.h>
+#include <asm/of_platform.h>
+
+#include "44x.h"
+
+static struct of_device_id ebony_of_bus[] = {
+ { .type = "ibm,plb", },
+ { .type = "ibm,opb", },
+ { .type = "ibm,ebc", },
+ {},
+};
+
+static int __init ebony_device_probe(void)
+{
+ if (!machine_is(ebony))
+ return 0;
+
+ of_platform_bus_probe(NULL, ebony_of_bus, NULL);
+
+ return 0;
+}
+device_initcall(ebony_device_probe);
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init ebony_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "ibm,ebony"))
+ return 0;
+
+ return 1;
+}
+
+static void __init ebony_setup_arch(void)
+{
+}
+
+define_machine(ebony) {
+ .name = "Ebony",
+ .probe = ebony_probe,
+ .setup_arch = ebony_setup_arch,
+ .progress = udbg_progress,
+ .init_IRQ = uic_init_tree,
+ .get_irq = uic_get_irq,
+ .restart = ppc44x_reset_system,
+ .calibrate_decr = generic_calibrate_decr,
+};
diff --git a/arch/powerpc/platforms/44x/misc_44x.S b/arch/powerpc/platforms/44x/misc_44x.S
new file mode 100644
index 00000000000..3bce71d5d75
--- /dev/null
+++ b/arch/powerpc/platforms/44x/misc_44x.S
@@ -0,0 +1,57 @@
+/*
+ * This file contains miscellaneous low-level functions for PPC 44x.
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+
+ .text
+
+/*
+ * Do an IO access in AS1
+ */
+_GLOBAL(as1_readb)
+ mfmsr r7
+ ori r0,r7,MSR_DS
+ sync
+ mtmsr r0
+ sync
+ isync
+ lbz r3,0(r3)
+ sync
+ mtmsr r7
+ sync
+ isync
+ blr
+
+_GLOBAL(as1_writeb)
+ mfmsr r7
+ ori r0,r7,MSR_DS
+ sync
+ mtmsr r0
+ sync
+ isync
+ stb r3,0(r4)
+ sync
+ mtmsr r7
+ sync
+ isync
+ blr
+
+/*
+ * void ppc44x_reset_system(char *cmd)
+ *
+ * At present, this routine just applies a system reset.
+ */
+_GLOBAL(ppc44x_reset_system)
+ mfspr r13,SPRN_DBCR0
+ oris r13,r13,DBCR0_RST_SYSTEM@h
+ mtspr SPRN_DBCR0,r13
+ b . /* Just in case the reset doesn't work */
diff --git a/arch/powerpc/platforms/4xx/Kconfig b/arch/powerpc/platforms/4xx/Kconfig
index 2f2a13ed766..ded357c1741 100644
--- a/arch/powerpc/platforms/4xx/Kconfig
+++ b/arch/powerpc/platforms/4xx/Kconfig
@@ -3,278 +3,206 @@ config 4xx
depends on 40x || 44x
default y
-config WANT_EARLY_SERIAL
+config BOOKE
bool
- select SERIAL_8250
- default n
-
-menu "AMCC 4xx options"
- depends on 4xx
-
-choice
- prompt "Machine Type"
- depends on 40x
- default WALNUT
-
-config BUBINGA
- bool "Bubinga"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM 405EP evaluation board.
-
-config CPCI405
- bool "CPCI405"
- help
- This option enables support for the CPCI405 board.
-
-config EP405
- bool "EP405/EP405PC"
- help
- This option enables support for the EP405/EP405PC boards.
-
-config REDWOOD_5
- bool "Redwood-5"
- help
- This option enables support for the IBM STB04 evaluation board.
-
-config REDWOOD_6
- bool "Redwood-6"
- help
- This option enables support for the IBM STBx25xx evaluation board.
-
-config SYCAMORE
- bool "Sycamore"
- help
- This option enables support for the IBM PPC405GPr evaluation board.
-
-config WALNUT
- bool "Walnut"
- help
- This option enables support for the IBM PPC405GP evaluation board.
-
-config XILINX_ML300
- bool "Xilinx-ML300"
- help
- This option enables support for the Xilinx ML300 evaluation board.
-
-endchoice
-
-choice
- prompt "Machine Type"
depends on 44x
- default EBONY
-
-config BAMBOO
- bool "Bamboo"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440EP evaluation board.
-
-config EBONY
- bool "Ebony"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440GP evaluation board.
-
-config LUAN
- bool "Luan"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440SP evaluation board.
-
-config OCOTEA
- bool "Ocotea"
- select WANT_EARLY_SERIAL
- help
- This option enables support for the IBM PPC440GX evaluation board.
+ default y
-endchoice
+menu "AMCC 40x options"
+ depends on 40x
-config EP405PC
- bool "EP405PC Support"
- depends on EP405
+#config BUBINGA
+# bool "Bubinga"
+# depends on 40x
+# default n
+# select 405EP
+# help
+# This option enables support for the IBM 405EP evaluation board.
+
+#config CPCI405
+# bool "CPCI405"
+# depends on 40x
+# default n
+# select 405GP
+# help
+# This option enables support for the CPCI405 board.
+
+#config EP405
+# bool "EP405/EP405PC"
+# depends on 40x
+# default n
+# select 405GP
+# help
+# This option enables support for the EP405/EP405PC boards.
+
+#config EP405PC
+# bool "EP405PC Support"
+# depends on EP405
+# default y
+# help
+# This option enables support for the extra features of the EP405PC board.
+
+#config REDWOOD_5
+# bool "Redwood-5"
+# depends on 40x
+# default n
+# select STB03xxx
+# help
+# This option enables support for the IBM STB04 evaluation board.
+
+#config REDWOOD_6
+# bool "Redwood-6"
+# depends on 40x
+# default n
+# select STB03xxx
+# help
+# This option enables support for the IBM STBx25xx evaluation board.
+
+#config SYCAMORE
+# bool "Sycamore"
+# depends on 40x
+# default n
+# select 405GPR
+# help
+# This option enables support for the IBM PPC405GPr evaluation board.
+
+#config WALNUT
+# bool "Walnut"
+# depends on 40x
+# default y
+# select 405GP
+# help
+# This option enables support for the IBM PPC405GP evaluation board.
+
+#config XILINX_ML300
+# bool "Xilinx-ML300"
+# depends on 40x
+# default y
+# select VIRTEX_II_PRO
+# help
+# This option enables support for the Xilinx ML300 evaluation board.
+endmenu
-# It's often necessary to know the specific 4xx processor type.
-# Fortunately, it is impled (so far) from the board type, so we
-# don't need to ask more redundant questions.
+# 40x specific CPU modules, selected based on the board above.
config NP405H
bool
- depends on ASH
- default y
+ #depends on ASH
-config 440EP
+# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
+config 403GCX
bool
- depends on BAMBOO
- select PPC_FPU
- default y
+ #depends on OAK
+ select IBM405_ERR51
-config 440GP
+config 405GP
bool
- depends on EBONY
- default y
+ select IBM405_ERR77
+ select IBM405_ERR51
-config 440GX
+config 405EP
bool
- depends on OCOTEA
- default y
-config 440SP
+config 405GPR
bool
- depends on LUAN
- default y
-config 440
+config VIRTEX_II_PRO
bool
- depends on 440GP || 440SP || 440EP
- default y
+ select IBM405_ERR77
+ select IBM405_ERR51
-config 440A
+config STB03xxx
bool
- depends on 440GX
- default y
+ select IBM405_ERR77
+ select IBM405_ERR51
-config IBM440EP_ERR42
- bool
- depends on 440EP
- default y
+# 40x errata/workaround config symbols, selected by the CPU models above
# All 405-based cores up until the 405GPR and 405EP have this errata.
config IBM405_ERR77
bool
- depends on 40x && !403GCX && !405GPR && !405EP
- default y
# All 40x-based cores, up until the 405GPR and 405EP have this errata.
config IBM405_ERR51
bool
- depends on 40x && !405GPR && !405EP
- default y
-config BOOKE
- bool
+menu "AMCC 44x options"
depends on 44x
- default y
-
-config IBM_OCP
- bool
- depends on ASH || BAMBOO || BUBINGA || CPCI405 || EBONY || EP405 || LUAN || OCOTEA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
- default y
-config XILINX_OCP
- bool
- depends on XILINX_ML300
- default y
+#config BAMBOO
+# bool "Bamboo"
+# depends on 44x
+# default n
+# select 440EP
+# help
+# This option enables support for the IBM PPC440EP evaluation board.
-config IBM_EMAC4
- bool
- depends on 440GX || 440SP
- default y
-
-config BIOS_FIXUP
- bool
- depends on BUBINGA || EP405 || SYCAMORE || WALNUT
- default y
-
-# OAK doesn't exist but wanted to keep this around for any future 403GCX boards
-config 403GCX
- bool
- depends on OAK
- default y
-
-config 405EP
- bool
- depends on BUBINGA
- default y
-
-config 405GP
- bool
- depends on CPCI405 || EP405 || WALNUT
- default y
-
-config 405GPR
- bool
- depends on SYCAMORE
+config EBONY
+ bool "Ebony"
+ depends on 44x
default y
+ select 440GP
+ help
+ This option enables support for the IBM PPC440GP evaluation board.
-config VIRTEX_II_PRO
- bool
- depends on XILINX_ML300
- default y
+#config LUAN
+# bool "Luan"
+# depends on 44x
+# default n
+# select 440SP
+# help
+# This option enables support for the IBM PPC440SP evaluation board.
+
+#config OCOTEA
+# bool "Ocotea"
+# depends on 44x
+# default n
+# select 440GX
+# help
+# This option enables support for the IBM PPC440GX evaluation board.
-config STB03xxx
- bool
- depends on REDWOOD_5 || REDWOOD_6
- default y
+endmenu
-config EMBEDDEDBOOT
+# 44x specific CPU modules, selected based on the board above.
+config 440EP
bool
- depends on EP405 || XILINX_ML300
- default y
+ select PPC_FPU
+ select IBM440EP_ERR42
-config IBM_OPENBIOS
+config 440GP
bool
- depends on ASH || BUBINGA || REDWOOD_5 || REDWOOD_6 || SYCAMORE || WALNUT
- default y
+ select IBM_NEW_EMAC_ZMII
-config PPC4xx_DMA
- bool "PPC4xx DMA controller support"
- depends on 4xx
-
-config PPC4xx_EDMA
+config 440GX
bool
- depends on !STB03xxx && PPC4xx_DMA
- default y
-config PPC_GEN550
+config 440SP
bool
- depends on 4xx
- default y
-
-choice
- prompt "TTYS0 device and default console"
- depends on 40x
- default UART0_TTYS0
-
-config UART0_TTYS0
- bool "UART0"
-config UART0_TTYS1
- bool "UART1"
-
-endchoice
-
-config SERIAL_SICC
- bool "SICC Serial port support"
- depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
+config 440A
bool
- depends on SERIAL_SICC && UART0_TTYS1
+ depends on 440GX
default y
-config SERIAL_SICC_CONSOLE
+# 44x errata/workaround config symbols, selected by the CPU models above
+config IBM440EP_ERR42
bool
- depends on SERIAL_SICC && UART0_TTYS1
- default y
-endmenu
+#config XILINX_OCP
+# bool
+# depends on XILINX_ML300
+# default y
-menu "IBM 40x options"
- depends on 40x
-
-config SERIAL_SICC
- bool "SICC Serial port"
- depends on STB03xxx
-
-config UART1_DFLT_CONSOLE
- bool
- depends on SERIAL_SICC && UART0_TTYS1
- default y
+#config BIOS_FIXUP
+# bool
+# depends on BUBINGA || EP405 || SYCAMORE || WALNUT
+# default y
-config SERIAL_SICC_CONSOLE
- bool
- depends on SERIAL_SICC && UART0_TTYS1
- default y
+#config PPC4xx_DMA
+# bool "PPC4xx DMA controller support"
+# depends on 4xx
-endmenu
+#config PPC4xx_EDMA
+# bool
+# depends on !STB03xxx && PPC4xx_DMA
+# default y
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig
new file mode 100644
index 00000000000..3ffaa066c2c
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/Kconfig
@@ -0,0 +1,36 @@
+config PPC_MPC52xx
+ bool
+ select FSL_SOC
+ default n
+
+config PPC_MPC5200
+ bool
+ select PPC_MPC52xx
+ default n
+
+config PPC_MPC5200_BUGFIX
+ bool "MPC5200 (L25R) bugfix support"
+ depends on PPC_MPC5200
+ default n
+ help
+ Enable workarounds for original MPC5200 errata. This is not required
+ for MPC5200B based boards.
+
+ It is safe to say 'Y' here
+
+config PPC_EFIKA
+ bool "bPlan Efika 5k2. MPC5200B based computer"
+ depends on PPC_MULTIPLATFORM && PPC32
+ select PPC_RTAS
+ select RTAS_PROC
+ select PPC_MPC52xx
+ select PPC_NATIVE
+ default n
+
+config PPC_LITE5200
+ bool "Freescale Lite5200 Eval Board"
+ depends on PPC_MULTIPLATFORM && PPC32
+ select PPC_MPC5200
+ default n
+
+
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index 07cdbcacf15..b91e39c84d4 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -8,3 +8,5 @@ endif
obj-$(CONFIG_PPC_EFIKA) += efika.o
obj-$(CONFIG_PPC_LITE5200) += lite5200.o
+
+obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index 8de03411668..f591a9fc19b 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -112,7 +112,7 @@ void __init efika_pcisetup(void)
return;
}
- bus_range = get_property(pcictrl, "bus-range", &len);
+ bus_range = of_get_property(pcictrl, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING EFIKA_PLATFORM_NAME
": Can't get bus-range for %s\n", pcictrl->full_name);
@@ -158,18 +158,17 @@ void __init efika_pcisetup(void)
static void efika_show_cpuinfo(struct seq_file *m)
{
struct device_node *root;
- const char *revision = NULL;
- const char *codegendescription = NULL;
- const char *codegenvendor = NULL;
+ const char *revision;
+ const char *codegendescription;
+ const char *codegenvendor;
root = of_find_node_by_path("/");
if (!root)
return;
- revision = get_property(root, "revision", NULL);
- codegendescription =
- get_property(root, "CODEGEN,description", NULL);
- codegenvendor = get_property(root, "CODEGEN,vendor", NULL);
+ revision = of_get_property(root, "revision", NULL);
+ codegendescription = of_get_property(root, "CODEGEN,description", NULL);
+ codegenvendor = of_get_property(root, "CODEGEN,vendor", NULL);
if (codegendescription)
seq_printf(m, "machine\t\t: %s\n", codegendescription);
@@ -185,6 +184,16 @@ static void efika_show_cpuinfo(struct seq_file *m)
of_node_put(root);
}
+#ifdef CONFIG_PM
+static void efika_suspend_prepare(void __iomem *mbar)
+{
+ u8 pin = 4; /* GPIO_WKUP_4 (GPIO_PSC6_0 - IRDA_RX) */
+ u8 level = 1; /* wakeup on high level */
+ /* IOW. to wake it up, short pins 1 and 3 on IRDA connector */
+ mpc52xx_set_wakeup_gpio(pin, level);
+}
+#endif
+
static void __init efika_setup_arch(void)
{
rtas_initialize();
@@ -200,6 +209,11 @@ static void __init efika_setup_arch(void)
efika_pcisetup();
+#ifdef CONFIG_PM
+ mpc52xx_suspend.board_suspend_prepare = efika_suspend_prepare;
+ mpc52xx_pm_init();
+#endif
+
if (ppc_md.progress)
ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0);
}
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index cc3b40de21d..1cfc00dfb99 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -85,6 +85,28 @@ error:
iounmap(gpio);
}
+#ifdef CONFIG_PM
+static u32 descr_a;
+static void lite5200_suspend_prepare(void __iomem *mbar)
+{
+ u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */
+ u8 level = 0; /* wakeup on low level */
+ mpc52xx_set_wakeup_gpio(pin, level);
+
+ /*
+ * power down usb port
+ * this needs to be called before of-ohci suspend code
+ */
+ descr_a = in_be32(mbar + 0x1048);
+ out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100);
+}
+
+static void lite5200_resume_finish(void __iomem *mbar)
+{
+ out_be32(mbar + 0x1048, descr_a);
+}
+#endif
+
static void __init lite5200_setup_arch(void)
{
struct device_node *np;
@@ -94,8 +116,8 @@ static void __init lite5200_setup_arch(void)
np = of_find_node_by_type(NULL, "cpu");
if (np) {
- unsigned int *fp =
- (int *)get_property(np, "clock-frequency", NULL);
+ const unsigned int *fp =
+ of_get_property(np, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
@@ -107,10 +129,18 @@ static void __init lite5200_setup_arch(void)
mpc52xx_setup_cpu(); /* Generic */
lite5200_setup_cpu(); /* Platorm specific */
+#ifdef CONFIG_PM
+ mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
+ mpc52xx_suspend.board_resume_finish = lite5200_resume_finish;
+ mpc52xx_pm_init();
+#endif
+
#ifdef CONFIG_PCI
- np = of_find_node_by_type(np, "pci");
- if (np)
+ np = of_find_node_by_type(NULL, "pci");
+ if (np) {
mpc52xx_add_bridge(np);
+ of_node_put(np);
+ }
#endif
#ifdef CONFIG_BLK_DEV_INITRD
@@ -132,7 +162,7 @@ void lite5200_show_cpuinfo(struct seq_file *m)
const char *model = NULL;
if (np)
- model = get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
seq_printf(m, "vendor\t\t: Freescale Semiconductor\n");
seq_printf(m, "machine\t\t: %s\n", model ? model : "unknown");
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index ed0cb694aea..2dd415ff55a 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -60,7 +60,7 @@ mpc52xx_find_ipb_freq(struct device_node *node)
of_node_get(node);
while (node) {
- p_ipb_freq = get_property(node, "bus-frequency", NULL);
+ p_ipb_freq = of_get_property(node, "bus-frequency", NULL);
if (p_ipb_freq)
break;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index faf161bdbc1..34d34a26d30 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -370,7 +370,7 @@ mpc52xx_add_bridge(struct device_node *node)
return -EINVAL;
}
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
node->full_name);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
new file mode 100644
index 00000000000..fd40044d16c
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
@@ -0,0 +1,191 @@
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/mpc52xx.h>
+
+#include "mpc52xx_pic.h"
+
+
+/* these are defined in mpc52xx_sleep.S, and only used here */
+extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs,
+ struct mpc52xx_cdm *, struct mpc52xx_intr *);
+extern void mpc52xx_ds_sram(void);
+extern const long mpc52xx_ds_sram_size;
+extern void mpc52xx_ds_cached(void);
+extern const long mpc52xx_ds_cached_size;
+
+static void __iomem *mbar;
+static void __iomem *sdram;
+static struct mpc52xx_cdm __iomem *cdm;
+static struct mpc52xx_intr __iomem *intr;
+static struct mpc52xx_gpio_wkup __iomem *gpiow;
+static void *sram;
+static int sram_size;
+
+struct mpc52xx_suspend mpc52xx_suspend;
+
+static int mpc52xx_pm_valid(suspend_state_t state)
+{
+ switch (state) {
+ case PM_SUSPEND_STANDBY:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+int mpc52xx_set_wakeup_gpio(u8 pin, u8 level)
+{
+ u16 tmp;
+
+ /* enable gpio */
+ out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin));
+ /* set as input */
+ out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin));
+ /* enable deep sleep interrupt */
+ out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin));
+ /* low/high level creates wakeup interrupt */
+ tmp = in_be16(&gpiow->wkup_itype);
+ tmp &= ~(0x3 << (pin * 2));
+ tmp |= (!level + 1) << (pin * 2);
+ out_be16(&gpiow->wkup_itype, tmp);
+ /* master enable */
+ out_8(&gpiow->wkup_maste, 1);
+
+ return 0;
+}
+
+int mpc52xx_pm_prepare(suspend_state_t state)
+{
+ if (state != PM_SUSPEND_STANDBY)
+ return -EINVAL;
+
+ /* map the whole register space */
+ mbar = mpc52xx_find_and_map("mpc5200");
+ if (!mbar) {
+ printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
+ return -ENOSYS;
+ }
+ /* these offsets are from mpc5200 users manual */
+ sdram = mbar + 0x100;
+ cdm = mbar + 0x200;
+ intr = mbar + 0x500;
+ gpiow = mbar + 0xc00;
+ sram = mbar + 0x8000; /* Those will be handled by the */
+ sram_size = 0x4000; /* bestcomm driver soon */
+
+ /* call board suspend code, if applicable */
+ if (mpc52xx_suspend.board_suspend_prepare)
+ mpc52xx_suspend.board_suspend_prepare(mbar);
+ else {
+ printk(KERN_ALERT "%s: %i don't know how to wake up the board\n",
+ __func__, __LINE__);
+ goto out_unmap;
+ }
+
+ return 0;
+
+ out_unmap:
+ iounmap(mbar);
+ return -ENOSYS;
+}
+
+
+char saved_sram[0x4000];
+
+int mpc52xx_pm_enter(suspend_state_t state)
+{
+ u32 clk_enables;
+ u32 msr, hid0;
+ u32 intr_main_mask;
+ void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500;
+ unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
+ char saved_0x500[mpc52xx_ds_cached_size];
+
+ /* disable all interrupts in PIC */
+ intr_main_mask = in_be32(&intr->main_mask);
+ out_be32(&intr->main_mask, intr_main_mask | 0x1ffff);
+
+ /* don't let DEC expire any time soon */
+ mtspr(SPRN_DEC, 0x7fffffff);
+
+ /* save SRAM */
+ memcpy(saved_sram, sram, sram_size);
+
+ /* copy low level suspend code to sram */
+ memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size);
+
+ out_8(&cdm->ccs_sleep_enable, 1);
+ out_8(&cdm->osc_sleep_enable, 1);
+ out_8(&cdm->ccs_qreq_test, 1);
+
+ /* disable all but SDRAM and bestcomm (SRAM) clocks */
+ clk_enables = in_be32(&cdm->clk_enables);
+ out_be32(&cdm->clk_enables, clk_enables & 0x00088000);
+
+ /* disable power management */
+ msr = mfmsr();
+ mtmsr(msr & ~MSR_POW);
+
+ /* enable sleep mode, disable others */
+ hid0 = mfspr(SPRN_HID0);
+ mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP);
+
+ /* save original, copy our irq handler, flush from dcache and invalidate icache */
+ memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size);
+ memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size);
+ flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
+
+ /* call low-level sleep code */
+ mpc52xx_deep_sleep(sram, sdram, cdm, intr);
+
+ /* restore original irq handler */
+ memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size);
+ flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
+
+ /* restore old power mode */
+ mtmsr(msr & ~MSR_POW);
+ mtspr(SPRN_HID0, hid0);
+ mtmsr(msr);
+
+ out_be32(&cdm->clk_enables, clk_enables);
+ out_8(&cdm->ccs_sleep_enable, 0);
+ out_8(&cdm->osc_sleep_enable, 0);
+
+ /* restore SRAM */
+ memcpy(sram, saved_sram, sram_size);
+
+ /* restart jiffies */
+ wakeup_decrementer();
+
+ /* reenable interrupts in PIC */
+ out_be32(&intr->main_mask, intr_main_mask);
+
+ return 0;
+}
+
+int mpc52xx_pm_finish(suspend_state_t state)
+{
+ /* call board resume code */
+ if (mpc52xx_suspend.board_resume_finish)
+ mpc52xx_suspend.board_resume_finish(mbar);
+
+ iounmap(mbar);
+
+ return 0;
+}
+
+static struct pm_ops mpc52xx_pm_ops = {
+ .valid = mpc52xx_pm_valid,
+ .prepare = mpc52xx_pm_prepare,
+ .enter = mpc52xx_pm_enter,
+ .finish = mpc52xx_pm_finish,
+};
+
+int __init mpc52xx_pm_init(void)
+{
+ pm_set_ops(&mpc52xx_pm_ops);
+ return 0;
+}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_sleep.S b/arch/powerpc/platforms/52xx/mpc52xx_sleep.S
new file mode 100644
index 00000000000..4dc170b0ae1
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_sleep.S
@@ -0,0 +1,154 @@
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+
+.text
+
+_GLOBAL(mpc52xx_deep_sleep)
+mpc52xx_deep_sleep: /* args r3-r6: SRAM, SDRAM regs, CDM regs, INTR regs */
+
+ /* enable interrupts */
+ mfmsr r7
+ ori r7, r7, 0x8000 /* EE */
+ mtmsr r7
+ sync; isync;
+
+ li r10, 0 /* flag that irq handler sets */
+
+ /* enable tmr7 (or any other) interrupt */
+ lwz r8, 0x14(r6) /* intr->main_mask */
+ ori r8, r8, 0x1
+ xori r8, r8, 0x1
+ stw r8, 0x14(r6)
+ sync
+
+ /* emulate tmr7 interrupt */
+ li r8, 0x1
+ stw r8, 0x40(r6) /* intr->main_emulate */
+ sync
+
+ /* wait for it to happen */
+1:
+ cmpi cr0, r10, 1
+ bne cr0, 1b
+
+ /* lock icache */
+ mfspr r10, SPRN_HID0
+ ori r10, r10, 0x2000
+ sync; isync;
+ mtspr SPRN_HID0, r10
+ sync; isync;
+
+
+ mflr r9 /* save LR */
+
+ /* jump to sram */
+ mtlr r3
+ blrl
+
+ mtlr r9 /* restore LR */
+
+ /* unlock icache */
+ mfspr r10, SPRN_HID0
+ ori r10, r10, 0x2000
+ xori r10, r10, 0x2000
+ sync; isync;
+ mtspr SPRN_HID0, r10
+ sync; isync;
+
+
+ /* return to C code */
+ blr
+
+
+_GLOBAL(mpc52xx_ds_sram)
+mpc52xx_ds_sram:
+ /* put SDRAM into self-refresh */
+ lwz r8, 0x4(r4) /* sdram->ctrl */
+
+ oris r8, r8, 0x8000 /* mode_en */
+ stw r8, 0x4(r4)
+ sync
+
+ ori r8, r8, 0x0002 /* soft_pre */
+ stw r8, 0x4(r4)
+ sync
+ xori r8, r8, 0x0002
+
+ xoris r8, r8, 0x8000 /* !mode_en */
+ stw r8, 0x4(r4)
+ sync
+
+ oris r8, r8, 0x5000
+ xoris r8, r8, 0x4000 /* ref_en !cke */
+ stw r8, 0x4(r4)
+ sync
+
+ /* disable SDRAM clock */
+ lwz r8, 0x14(r5) /* cdm->clkenable */
+ ori r8, r8, 0x0008
+ xori r8, r8, 0x0008
+ stw r8, 0x14(r5)
+ sync
+
+
+ /* put mpc5200 to sleep */
+ mfmsr r10
+ oris r10, r10, 0x0004 /* POW = 1 */
+ sync; isync;
+ mtmsr r10
+ sync; isync;
+
+
+ /* enable clock */
+ lwz r8, 0x14(r5)
+ ori r8, r8, 0x0008
+ stw r8, 0x14(r5)
+ sync
+
+ /* get ram out of self-refresh */
+ lwz r8, 0x4(r4)
+ oris r8, r8, 0x5000 /* cke ref_en */
+ stw r8, 0x4(r4)
+ sync
+
+ blr
+_GLOBAL(mpc52xx_ds_sram_size)
+mpc52xx_ds_sram_size:
+ .long $-mpc52xx_ds_sram
+
+
+/* ### interrupt handler for wakeup from deep-sleep ### */
+_GLOBAL(mpc52xx_ds_cached)
+mpc52xx_ds_cached:
+ mtspr SPRN_SPRG0, r7
+ mtspr SPRN_SPRG1, r8
+
+ /* disable emulated interrupt */
+ mfspr r7, 311 /* MBAR */
+ addi r7, r7, 0x540 /* intr->main_emul */
+ li r8, 0
+ stw r8, 0(r7)
+ sync
+ dcbf 0, r7
+
+ /* acknowledge wakeup, so CCS releases power pown */
+ mfspr r7, 311 /* MBAR */
+ addi r7, r7, 0x524 /* intr->enc_status */
+ lwz r8, 0(r7)
+ ori r8, r8, 0x0400
+ stw r8, 0(r7)
+ sync
+ dcbf 0, r7
+
+ /* flag - we handled the interrupt */
+ li r10, 1
+
+ mfspr r8, SPRN_SPRG1
+ mfspr r7, SPRN_SPRG0
+
+ rfi
+_GLOBAL(mpc52xx_ds_cached_size)
+mpc52xx_ds_cached_size:
+ .long $-mpc52xx_ds_cached
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
index 47d841ecf2e..de7fce9cb6e 100644
--- a/arch/powerpc/platforms/82xx/Kconfig
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -1,21 +1,36 @@
-menu "Platform support"
- depends on PPC_82xx
-
choice
- prompt "Machine Type"
- default MPC82xx_ADS
+ prompt "Machine Type"
+ depends on PPC_82xx
+ default MPC82xx_ADS
config MPC82xx_ADS
- bool "Freescale MPC82xx ADS"
- select DEFAULT_UIMAGE
- select PQ2ADS
- select 8272
- select 8260
- select CPM2
- select FSL_SOC
- help
- This option enables support for the MPC8272 ADS board
+ bool "Freescale MPC82xx ADS"
+ select DEFAULT_UIMAGE
+ select PQ2ADS
+ select 8272
+ select 8260
+ select FSL_SOC
+ help
+ This option enables support for the MPC8272 ADS board
endchoice
-endmenu
+config PQ2ADS
+ bool
+ default n
+
+config 8260
+ bool
+ depends on 6xx
+ select CPM2
+ help
+ The MPC8260 is a typical embedded CPU made by Freescale. Selecting
+ this option means that you wish to build a kernel for a machine with
+ an 8260 class CPU.
+
+config 8272
+ bool
+ select 8260
+ help
+ The MPC8272 CPM has a different internal dpram setup than other CPM2
+ devices
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
index 74e7892cdfc..cc9900d2e5e 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -55,17 +55,17 @@
static int __init get_freq(char *name, unsigned long *val)
{
struct device_node *cpu;
- unsigned int *fp;
+ const unsigned int *fp;
int found = 0;
/* The cpu node should have timebase and clock frequency properties */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = (unsigned int *)get_property(cpu, name, NULL);
+ fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
- *val = *fp++;
+ *val = *fp;
}
of_node_put(cpu);
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index 7334c1a15b9..47cb09f0805 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -456,7 +456,7 @@ void m82xx_pci_init_irq(void)
iounmap(immap);
return;
}
- irq_map = get_property(np, "interrupt-map", &size);
+ irq_map = of_get_property(np, "interrupt-map", &size);
if ((!irq_map) || (size <= 7)) {
printk(KERN_INFO "No interrupt-map property of pci node\n");
iounmap(immap);
@@ -481,7 +481,7 @@ void m82xx_pci_init_irq(void)
}
pci_pic_node = of_node_get(np);
/* PCI interrupt controller registers: status and mask */
- regs = get_property(np, "reg", &size);
+ regs = of_get_property(np, "reg", &size);
if ((!regs) || (size <= 2)) {
printk(KERN_INFO "No reg property in pci pic node\n");
iounmap(immap);
@@ -521,20 +521,20 @@ void __init add_bridge(struct device_node *np)
struct pci_controller *hose;
struct resource r;
const int *bus_range;
- const void *ptr;
+ const uint *ptr;
memset(&r, 0, sizeof(r));
if (of_address_to_resource(np, 0, &r)) {
printk(KERN_INFO "No PCI reg property in device tree\n");
return;
}
- if (!(ptr = get_property(np, "clock-frequency", NULL))) {
+ if (!(ptr = of_get_property(np, "clock-frequency", NULL))) {
printk(KERN_INFO "No clock-frequency property in PCI node");
return;
}
- pci_clk_frq = *(uint *) ptr;
+ pci_clk_frq = *ptr;
of_node_put(np);
- bus_range = get_property(np, "bus-range", &len);
+ bus_range = of_get_property(np, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", np->full_name);
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 713b31a16ce..19cafdf6df9 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform support"
- depends on PPC_83xx
-
choice
prompt "Machine Type"
+ depends on PPC_83xx
default MPC834x_MDS
config MPC8313_RDB
@@ -18,6 +16,13 @@ config MPC832x_MDS
help
This option enables support for the MPC832x MDS evaluation board.
+config MPC832x_RDB
+ bool "Freescale MPC832x RDB"
+ select DEFAULT_UIMAGE
+ select QUICC_ENGINE
+ help
+ This option enables support for the MPC8323 RDB board.
+
config MPC834x_MDS
bool "Freescale MPC834x MDS"
select DEFAULT_UIMAGE
@@ -57,7 +62,7 @@ config PPC_MPC832x
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
- default y if MPC832x_MDS
+ default y if MPC832x_MDS || MPC832x_RDB
config MPC834x
bool
@@ -70,5 +75,3 @@ config PPC_MPC836x
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
default y if MPC836x_MDS
-
-endmenu
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index dfc970d0df1..31a91b53f52 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -4,6 +4,7 @@
obj-y := misc.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o
+obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o
obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o
obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o
obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 17e3a3c6d8b..94843ed52a9 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -41,7 +41,6 @@
#include <asm/qe_ic.h>
#include "mpc83xx.h"
-#include "mpc832x_mds.h"
#undef DEBUG
#ifdef DEBUG
@@ -112,6 +111,7 @@ static struct of_device_id mpc832x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .type = "qe", },
+ { .type = "mdio", },
{},
};
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
deleted file mode 100644
index a49588904f8..00000000000
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Description:
- * MPC832x MDS board specific header.
- *
- * 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.
- *
- */
-
-#ifndef __MACH_MPC832x_MDS_H__
-#define __MACH_MPC832x_MDS_H__
-
-extern u8 *get_bcsr(void);
-
-#endif /* __MACH_MPC832x_MDS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
new file mode 100644
index 00000000000..b0b22bb29de
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -0,0 +1,139 @@
+/*
+ * arch/powerpc/platforms/83xx/mpc832x_rdb.c
+ *
+ * Copyright (C) Freescale Semiconductor, Inc. 2007. All rights reserved.
+ *
+ * Description:
+ * MPC832x RDB board specific routines.
+ * This file is based on mpc832x_mds.c and mpc8313_rdb.c
+ * Author: Michael Barkowski <michael.barkowski@freescale.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.
+ */
+
+#include <linux/pci.h>
+
+#include <asm/of_platform.h>
+#include <asm/time.h>
+#include <asm/ipic.h>
+#include <asm/udbg.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+
+#include "mpc83xx.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc832x_rdb_setup_arch(void)
+{
+ struct device_node *np;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc832x_rdb_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+
+ ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef CONFIG_QUICC_ENGINE
+ qe_reset();
+
+ if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+ par_io_init(np);
+ of_node_put(np);
+
+ for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
+ par_io_of_config(np);
+ }
+#endif /* CONFIG_QUICC_ENGINE */
+}
+
+static struct of_device_id mpc832x_ids[] = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ { .type = "qe", },
+ { .type = "mdio", },
+ {},
+};
+
+static int __init mpc832x_declare_of_platform_devices(void)
+{
+ if (!machine_is(mpc832x_rdb))
+ return 0;
+
+ /* Publish the QE devices */
+ of_platform_bus_probe(NULL, mpc832x_ids, NULL);
+
+ return 0;
+}
+device_initcall(mpc832x_declare_of_platform_devices);
+
+void __init mpc832x_rdb_init_IRQ(void)
+{
+
+ struct device_node *np;
+
+ np = of_find_node_by_type(NULL, "ipic");
+ if (!np)
+ return;
+
+ ipic_init(np, 0);
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ ipic_set_default_priority();
+ of_node_put(np);
+
+#ifdef CONFIG_QUICC_ENGINE
+ np = of_find_node_by_type(NULL, "qeic");
+ if (!np)
+ return;
+
+ qe_ic_init(np, 0);
+ of_node_put(np);
+#endif /* CONFIG_QUICC_ENGINE */
+}
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc832x_rdb_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "MPC832xRDB");
+}
+
+define_machine(mpc832x_rdb) {
+ .name = "MPC832x RDB",
+ .probe = mpc832x_rdb_probe,
+ .setup_arch = mpc832x_rdb_setup_arch,
+ .init_IRQ = mpc832x_rdb_init_IRQ,
+ .get_irq = ipic_get_irq,
+ .restart = mpc83xx_restart,
+ .time_init = mpc83xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.h b/arch/powerpc/platforms/83xx/mpc834x_itx.h
deleted file mode 100644
index 174ca4ef55f..00000000000
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/powerpc/platforms/83xx/mpc834x_itx.h
- *
- * MPC834X ITX common board definitions
- *
- * Maintainer: Kumar Gala <galak@kernel.crashing.org>
- *
- * 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.
- *
- */
-
-#ifndef __MACH_MPC83XX_ITX_H__
-#define __MACH_MPC83XX_ITX_H__
-
-#define PIRQA MPC83xx_IRQ_EXT4
-#define PIRQB MPC83xx_IRQ_EXT5
-#define PIRQC MPC83xx_IRQ_EXT6
-#define PIRQD MPC83xx_IRQ_EXT7
-
-#endif /* __MACH_MPC83XX_ITX_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index 526ed090a44..bceeff8bbfd 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -118,6 +118,7 @@ static struct of_device_id mpc836x_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .type = "qe", },
+ { .type = "mdio", },
{},
};
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 9c365055514..774457d09e9 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -60,7 +60,7 @@ int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index e764c0aced8..629926e01e9 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform support"
- depends on PPC_85xx
-
choice
prompt "Machine Type"
+ depends on PPC_85xx
default MPC8540_ADS
config MPC8540_ADS
@@ -30,6 +28,12 @@ config MPC85xx_MDS
help
This option enables support for the MPC85xx MDS board
+config MPC8544_DS
+ bool "Freescale MPC8544 DS"
+ select DEFAULT_UIMAGE
+ help
+ This option enables support for the MPC8544 DS board
+
endchoice
config MPC8540
@@ -40,33 +44,15 @@ config MPC8540
config MPC8560
bool
- select PPC_INDIRECT_PCI
+ select CPM2
default y if MPC8560_ADS
config MPC85xx
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
+ select PPC_INDIRECT_PCI_BE
+ select MPIC
select SERIAL_8250_SHARE_IRQ if SERIAL_8250
- default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS
-
-config PPC_INDIRECT_PCI_BE
- bool
- depends on PPC_85xx
- default y
-
-config MPIC
- bool
- default y
-
-config CPM2
- bool
- depends on MPC8560
- default y
- help
- The CPM2 (Communications Processor Module) is a coprocessor on
- embedded CPUs made by Motorola. Selecting this option means that
- you wish to build a kernel for a machine with a CPM2 coprocessor
- on it.
-
-endmenu
+ default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \
+ || MPC85xx_MDS || MPC8544_DS
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 4e63917ada9..4e02cbb14cf 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -5,4 +5,5 @@ obj-$(CONFIG_PPC_85xx) += misc.o pci.o
obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
+obj-$(CONFIG_MPC8544_DS) += mpc8544_ds.o
obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c
new file mode 100644
index 00000000000..bec84ffe708
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c
@@ -0,0 +1,144 @@
+/*
+ * MPC8544 DS Board Setup
+ *
+ * Author Xianghua Xiao (x.xiao@freescale.com)
+ * Copyright 2007 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/mpc85xx.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/i8259.h>
+
+#include <sysdev/fsl_soc.h>
+#include "mpc85xx.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...)
+#endif
+
+
+void __init mpc8544_ds_pic_init(void)
+{
+ struct mpic *mpic;
+ struct resource r;
+ struct device_node *np = NULL;
+#ifdef CONFIG_PPC_I8259
+ struct device_node *cascade_node = NULL;
+ int cascade_irq;
+#endif
+
+ np = of_find_node_by_type(np, "open-pic");
+
+ if (np == NULL) {
+ printk(KERN_ERR "Could not find open-pic node\n");
+ return;
+ }
+
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_ERR "Failed to map mpic register space\n");
+ of_node_put(np);
+ return;
+ }
+
+ /* Alloc mpic structure and per isu has 16 INT entries. */
+ mpic = mpic_alloc(np, r.start,
+ MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+ 16, 64, " OPENPIC ");
+ BUG_ON(mpic == NULL);
+
+ /*
+ * 48 Internal Interrupts
+ */
+ mpic_assign_isu(mpic, 0, r.start + 0x10200);
+ mpic_assign_isu(mpic, 1, r.start + 0x10400);
+ mpic_assign_isu(mpic, 2, r.start + 0x10600);
+
+ /*
+ * 16 External interrupts
+ */
+ mpic_assign_isu(mpic, 3, r.start + 0x10000);
+
+ mpic_init(mpic);
+
+#ifdef CONFIG_PPC_I8259
+ /* Initialize the i8259 controller */
+ for_each_node_by_type(np, "interrupt-controller")
+ if (of_device_is_compatible(np, "chrp,iic")) {
+ cascade_node = np;
+ break;
+ }
+
+ if (cascade_node == NULL) {
+ printk(KERN_DEBUG "Could not find i8259 PIC\n");
+ return;
+ }
+
+ cascade_irq = irq_of_parse_and_map(cascade_node, 0);
+ if (cascade_irq == NO_IRQ) {
+ printk(KERN_ERR "Failed to map cascade interrupt\n");
+ return;
+ }
+
+ DBG("mpc8544ds: cascade mapped to irq %d\n", cascade_irq);
+
+ i8259_init(cascade_node, 0);
+ of_node_put(cascade_node);
+
+ set_irq_chained_handler(cascade_irq, mpc8544_8259_cascade);
+#endif /* CONFIG_PPC_I8259 */
+}
+
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc8544_ds_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8544_ds_setup_arch()", 0);
+
+ printk("MPC8544 DS board from Freescale Semiconductor\n");
+}
+
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc8544_ds_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "MPC8544DS");
+}
+
+define_machine(mpc8544_ds) {
+ .name = "MPC8544 DS",
+ .probe = mpc8544_ds_probe,
+ .setup_arch = mpc8544_ds_setup_arch,
+ .init_IRQ = mpc8544_ds_pic_init,
+ .get_irq = mpic_get_irq,
+ .restart = mpc85xx_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 8ed034aeca5..5d27621f092 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -227,7 +227,7 @@ static void __init mpc85xx_ads_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 4232686be44..1490eb3ce0d 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -197,7 +197,7 @@ static void __init mpc85xx_cds_pic_init(void)
#ifdef CONFIG_PPC_I8259
/* Initialize the i8259 controller */
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "chrp,iic")) {
+ if (of_device_is_compatible(np, "chrp,iic")) {
cascade_node = np;
break;
}
@@ -237,7 +237,7 @@ static void __init mpc85xx_cds_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 81144d2ae45..e3dddbfe66f 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -80,7 +80,7 @@ static void __init mpc85xx_mds_setup_arch(void)
np = of_find_node_by_type(NULL, "cpu");
if (np != NULL) {
const unsigned int *fp =
- get_property(np, "clock-frequency", NULL);
+ of_get_property(np, "clock-frequency", NULL);
if (fp != NULL)
loops_per_jiffy = *fp / HZ;
else
@@ -147,6 +147,7 @@ static struct of_device_id mpc85xx_ids[] = {
{ .type = "soc", },
{ .compatible = "soc", },
{ .type = "qe", },
+ { .type = "mdio", },
{},
};
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
index 05930eeb6e7..48f17e23d77 100644
--- a/arch/powerpc/platforms/85xx/pci.c
+++ b/arch/powerpc/platforms/85xx/pci.c
@@ -51,7 +51,7 @@ int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 0c70944d0e3..d1bcff50046 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -1,8 +1,6 @@
-menu "Platform Support"
- depends on PPC_86xx
-
choice
prompt "Machine Type"
+ depends on PPC_86xx
default MPC8641_HPCN
config MPC8641_HPCN
@@ -14,20 +12,10 @@ config MPC8641_HPCN
endchoice
-
config MPC8641
bool
select PPC_INDIRECT_PCI
+ select PPC_INDIRECT_PCI_BE
select PPC_UDBG_16550
+ select MPIC
default y if MPC8641_HPCN
-
-config MPIC
- bool
- default y
-
-config PPC_INDIRECT_PCI_BE
- bool
- depends on PPC_86xx
- default y
-
-endmenu
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
index 476a6eeee71..418fd8f4d26 100644
--- a/arch/powerpc/platforms/86xx/Makefile
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_SMP) += mpc86xx_smp.o
obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o
-obj-$(CONFIG_PCI) += pci.o mpc86xx_pcie.o
+obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index f42f801cf84..90877565caa 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -102,7 +102,7 @@ mpc86xx_hpcn_init_irq(void)
#ifdef CONFIG_PCI
/* Initialize i8259 controller */
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "chrp,iic")) {
+ if (of_device_is_compatible(np, "chrp,iic")) {
cascade_node = np;
break;
}
@@ -349,7 +349,7 @@ mpc86xx_hpcn_setup_arch(void)
if (np != 0) {
const unsigned int *fp;
- fp = get_property(np, "clock-frequency", NULL);
+ fp = of_get_property(np, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
@@ -384,7 +384,7 @@ mpc86xx_hpcn_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "Machine\t\t: %s\n", model);
of_node_put(root);
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index 7ef0c685479..ba55b0ff0f7 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -15,8 +15,8 @@
#include <linux/init.h>
#include <linux/delay.h>
-#include <asm/pgtable.h>
#include <asm/page.h>
+#include <asm/pgtable.h>
#include <asm/pci-bridge.h>
#include <asm-powerpc/mpic.h>
#include <asm/mpc86xx.h>
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 481e18ed5be..8235c562661 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -22,9 +22,9 @@
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/immap_86xx.h>
#include <asm/pci-bridge.h>
#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pcie.h>
#include "mpc86xx.h"
@@ -163,7 +163,7 @@ int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index beea6834bb7..39bb8c5ebe7 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -1,6 +1,3 @@
-menu "Platform support"
- depends on PPC_8xx
-
config FADS
bool
@@ -9,6 +6,7 @@ config CPM1
choice
prompt "8xx Machine Type"
+ depends on PPC_8xx
depends on 8xx
default MPC885ADS
@@ -36,38 +34,36 @@ config MPC885ADS
endchoice
menu "Freescale Ethernet driver platform-specific options"
- depends on (FS_ENET && MPC885ADS)
-
- config MPC8xx_SECOND_ETH
- bool "Second Ethernet channel"
- depends on MPC885ADS
- default y
- help
- This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
- The latter will use SCC1, for 885ADS you can select it below.
-
- choice
- prompt "Second Ethernet channel"
- depends on MPC8xx_SECOND_ETH
- default MPC8xx_SECOND_ETH_FEC2
-
- config MPC8xx_SECOND_ETH_FEC2
- bool "FEC2"
- depends on MPC885ADS
- help
- Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
- (often 2-nd UART) will not work if this is enabled.
-
- config MPC8xx_SECOND_ETH_SCC3
- bool "SCC3"
- depends on MPC885ADS
- help
- Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
- (often 1-nd UART) will not work if this is enabled.
-
- endchoice
+ depends on (FS_ENET && MPC885ADS)
-endmenu
+ config MPC8xx_SECOND_ETH
+ bool "Second Ethernet channel"
+ depends on MPC885ADS
+ default y
+ help
+ This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
+ The latter will use SCC1, for 885ADS you can select it below.
+
+ choice
+ prompt "Second Ethernet channel"
+ depends on MPC8xx_SECOND_ETH
+ default MPC8xx_SECOND_ETH_FEC2
+
+ config MPC8xx_SECOND_ETH_FEC2
+ bool "FEC2"
+ depends on MPC885ADS
+ help
+ Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
+ (often 2-nd UART) will not work if this is enabled.
+
+ config MPC8xx_SECOND_ETH_SCC3
+ bool "SCC3"
+ depends on MPC885ADS
+ help
+ Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
+ (often 1-nd UART) will not work if this is enabled.
+
+ endchoice
endmenu
@@ -98,7 +94,7 @@ config 8xx_CPU6
require workarounds for Linux (and most other OSes to work). If you
get a BUG() very early in boot, this might fix the problem. For
more details read the document entitled "MPC860 Family Device Errata
- Reference" on Motorola's website. This option also incurs a
+ Reference" on Freescale's website. This option also incurs a
performance hit.
If in doubt, say N here.
@@ -135,4 +131,3 @@ config UCODE_PATCH
depends on !NO_UCODE_PATCH
endmenu
-
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 9ed7125f015..0901dbada35 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -85,17 +85,17 @@ init_internal_rtc(void)
static int __init get_freq(char *name, unsigned long *val)
{
struct device_node *cpu;
- unsigned int *fp;
+ const unsigned int *fp;
int found = 0;
/* The cpu node should have timebase and clock frequency properties */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu) {
- fp = (unsigned int *)get_property(cpu, name, NULL);
+ fp = of_get_property(cpu, name, NULL);
if (fp) {
found = 1;
- *val = *fp++;
+ *val = *fp;
}
of_node_put(cpu);
@@ -262,7 +262,7 @@ void mpc8xx_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "Machine\t\t: %s\n", model);
of_node_put(root);
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h
index b5d19dd0619..59bad2f9ae5 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads.h
+++ b/arch/powerpc/platforms/8xx/mpc86xads.h
@@ -37,7 +37,7 @@
#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
-#define PCMCIA_MEM_ADDR (uint)0xff020000)
+#define PCMCIA_MEM_ADDR ((uint)0xff020000)
#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
/* Bits of interest in the BCSRs.
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
index ef52ce701b0..cf0e7bc8c2e 100644
--- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc86xads-setup.c
+/*arch/powerpc/platforms/8xx/mpc86xads_setup.c
*
* Platform setup for the Freescale mpc86xads board
*
@@ -247,7 +247,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
}
}
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
{
return 0;
}
@@ -260,7 +260,7 @@ static void __init mpc86xads_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
index 30cbebfe84c..7c31aec284c 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads.h
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -37,7 +37,7 @@
#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
-#define PCMCIA_MEM_ADDR (uint)0xff020000)
+#define PCMCIA_MEM_ADDR ((uint)0xff020000)
#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
/* Bits of interest in the BCSRs.
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index c5fefdf66c0..c36e475d93d 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc885ads-setup.c
+/*arch/powerpc/platforms/8xx/mpc885ads_setup.c
*
* Platform setup for the Freescale mpc885ads board
*
@@ -322,7 +322,7 @@ void init_smc_ioports(struct fs_uart_platform_info *data)
}
}
-int platform_device_skip(char *model, int id)
+int platform_device_skip(const char *model, int id)
{
#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
const char *dev = "FEC";
@@ -346,7 +346,7 @@ static void __init mpc885ads_setup_arch(void)
if (cpu != 0) {
const unsigned int *fp;
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != 0)
loops_per_jiffy = *fp / HZ;
else
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
new file mode 100644
index 00000000000..361acfa2894
--- /dev/null
+++ b/arch/powerpc/platforms/Kconfig
@@ -0,0 +1,260 @@
+menu "Platform support"
+
+choice
+ prompt "Machine type"
+ depends on PPC64 || CLASSIC32
+ default PPC_MULTIPLATFORM
+
+config PPC_MULTIPLATFORM
+ bool "Generic desktop/server/laptop"
+ help
+ Select this option if configuring for an IBM pSeries or
+ RS/6000 machine, an Apple machine, or a PReP, CHRP,
+ Maple or Cell-based machine.
+
+config EMBEDDED6xx
+ bool "Embedded 6xx/7xx/7xxx-based board"
+ depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
+
+config APUS
+ bool "Amiga-APUS"
+ depends on PPC32 && BROKEN
+ help
+ Select APUS if configuring for a PowerUP Amiga.
+ More information is available at:
+ <http://linux-apus.sourceforge.net/>.
+endchoice
+
+source "arch/powerpc/platforms/pseries/Kconfig"
+source "arch/powerpc/platforms/iseries/Kconfig"
+source "arch/powerpc/platforms/chrp/Kconfig"
+source "arch/powerpc/platforms/52xx/Kconfig"
+source "arch/powerpc/platforms/powermac/Kconfig"
+source "arch/powerpc/platforms/prep/Kconfig"
+source "arch/powerpc/platforms/maple/Kconfig"
+source "arch/powerpc/platforms/pasemi/Kconfig"
+source "arch/powerpc/platforms/celleb/Kconfig"
+source "arch/powerpc/platforms/ps3/Kconfig"
+source "arch/powerpc/platforms/cell/Kconfig"
+source "arch/powerpc/platforms/8xx/Kconfig"
+source "arch/powerpc/platforms/82xx/Kconfig"
+source "arch/powerpc/platforms/83xx/Kconfig"
+source "arch/powerpc/platforms/85xx/Kconfig"
+source "arch/powerpc/platforms/86xx/Kconfig"
+source "arch/powerpc/platforms/embedded6xx/Kconfig"
+source "arch/powerpc/platforms/44x/Kconfig"
+#source "arch/powerpc/platforms/4xx/Kconfig
+
+config PPC_NATIVE
+ bool
+ depends on PPC_MULTIPLATFORM
+ help
+ Support for running natively on the hardware, i.e. without
+ a hypervisor. This option is not user-selectable but should
+ be selected by all platforms that need it.
+
+config UDBG_RTAS_CONSOLE
+ bool "RTAS based debug console"
+ depends on PPC_RTAS
+ default n
+
+config PPC_UDBG_BEAT
+ bool "BEAT based debug console"
+ depends on PPC_CELLEB
+ default n
+
+config XICS
+ depends on PPC_PSERIES
+ bool
+ default y
+
+config MPIC
+ bool
+ default n
+
+config MPIC_WEIRD
+ bool
+ default n
+
+config PPC_I8259
+ bool
+ default n
+
+config U3_DART
+ bool
+ depends on PPC_MULTIPLATFORM && PPC64
+ default n
+
+config PPC_RTAS
+ bool
+ default n
+
+config RTAS_ERROR_LOGGING
+ bool
+ depends on PPC_RTAS
+ default n
+
+config RTAS_PROC
+ bool "Proc interface to RTAS"
+ depends on PPC_RTAS
+ default y
+
+config RTAS_FLASH
+ tristate "Firmware flash interface"
+ depends on PPC64 && RTAS_PROC
+
+config PPC_PMI
+ tristate "Support for PMI"
+ depends PPC_IBM_CELL_BLADE
+ help
+ PMI (Platform Management Interrupt) is a way to
+ communicate with the BMC (Baseboard Mangement Controller).
+ It is used in some IBM Cell blades.
+ default m
+
+config MMIO_NVRAM
+ bool
+ default n
+
+config MPIC_U3_HT_IRQS
+ bool
+ depends on PPC_MAPLE
+ default y
+
+config IBMVIO
+ depends on PPC_PSERIES || PPC_ISERIES
+ bool
+ default y
+
+config IBMEBUS
+ depends on PPC_PSERIES
+ bool "Support for GX bus based adapters"
+ help
+ Bus device driver for GX bus based adapters.
+
+config PPC_MPC106
+ bool
+ default n
+
+config PPC_970_NAP
+ bool
+ default n
+
+config PPC_INDIRECT_IO
+ bool
+ select GENERIC_IOMAP
+ default n
+
+config GENERIC_IOMAP
+ bool
+ default n
+
+source "drivers/cpufreq/Kconfig"
+
+menu "CPU Frequency drivers"
+ depends on CPU_FREQ
+
+config CPU_FREQ_PMAC
+ bool "Support for Apple PowerBooks"
+ depends on ADB_PMU && PPC32
+ select CPU_FREQ_TABLE
+ help
+ This adds support for frequency switching on Apple PowerBooks,
+ this currently includes some models of iBook & Titanium
+ PowerBook.
+
+config CPU_FREQ_PMAC64
+ bool "Support for some Apple G5s"
+ depends on PPC_PMAC && PPC64
+ select CPU_FREQ_TABLE
+ help
+ This adds support for frequency switching on Apple iMac G5,
+ and some of the more recent desktop G5 machines as well.
+
+config PPC_PASEMI_CPUFREQ
+ bool "Support for PA Semi PWRficient"
+ depends on PPC_PASEMI
+ default y
+ select CPU_FREQ_TABLE
+ help
+ This adds the support for frequency switching on PA Semi
+ PWRficient processors.
+
+endmenu
+
+config PPC601_SYNC_FIX
+ bool "Workarounds for PPC601 bugs"
+ depends on 6xx && (PPC_PREP || PPC_PMAC)
+ help
+ Some versions of the PPC601 (the first PowerPC chip) have bugs which
+ mean that extra synchronization instructions are required near
+ certain instructions, typically those that make major changes to the
+ CPU state. These extra instructions reduce performance slightly.
+ If you say N here, these extra instructions will not be included,
+ resulting in a kernel which will run faster but may not run at all
+ on some systems with the PPC601 chip.
+
+ If in doubt, say Y here.
+
+config TAU
+ bool "On-chip CPU temperature sensor support"
+ depends on CLASSIC32
+ help
+ G3 and G4 processors have an on-chip temperature sensor called the
+ 'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
+ temperature within 2-4 degrees Celsius. This option shows the current
+ on-die temperature in /proc/cpuinfo if the cpu supports it.
+
+ Unfortunately, on some chip revisions, this sensor is very inaccurate
+ and in many cases, does not work at all, so don't assume the cpu
+ temp is actually what /proc/cpuinfo says it is.
+
+config TAU_INT
+ bool "Interrupt driven TAU driver (DANGEROUS)"
+ depends on TAU
+ ---help---
+ The TAU supports an interrupt driven mode which causes an interrupt
+ whenever the temperature goes out of range. This is the fastest way
+ to get notified the temp has exceeded a range. With this option off,
+ a timer is used to re-check the temperature periodically.
+
+ However, on some cpus it appears that the TAU interrupt hardware
+ is buggy and can cause a situation which would lead unexplained hard
+ lockups.
+
+ Unless you are extending the TAU driver, or enjoy kernel/hardware
+ debugging, leave this option off.
+
+config TAU_AVERAGE
+ bool "Average high and low temp"
+ depends on TAU
+ ---help---
+ The TAU hardware can compare the temperature to an upper and lower
+ bound. The default behavior is to show both the upper and lower
+ bound in /proc/cpuinfo. If the range is large, the temperature is
+ either changing a lot, or the TAU hardware is broken (likely on some
+ G4's). If the range is small (around 4 degrees), the temperature is
+ relatively stable. If you say Y here, a single temperature value,
+ halfway between the upper and lower bounds, will be reported in
+ /proc/cpuinfo.
+
+ If in doubt, say N here.
+
+config QUICC_ENGINE
+ bool
+ help
+ The QUICC Engine (QE) is a new generation of communications
+ coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
+ Selecting this option means that you wish to build a kernel
+ for a machine with a QE coprocessor.
+
+config CPM2
+ bool
+ default n
+ help
+ The CPM2 (Communications Processor Module) is a coprocessor on
+ embedded CPUs made by Freescale. Selecting this option means that
+ you wish to build a kernel for a machine with a CPM2 coprocessor
+ on it (826x, 827x, 8560).
+
+endmenu
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 452004283f1..d6e041a46d2 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -6,7 +6,8 @@ obj-$(CONFIG_PPC_PMAC) += powermac/
endif
endif
obj-$(CONFIG_PPC_CHRP) += chrp/
-obj-$(CONFIG_4xx) += 4xx/
+#obj-$(CONFIG_4xx) += 4xx/
+obj-$(CONFIG_44x) += 44x/
obj-$(CONFIG_PPC_MPC52xx) += 52xx/
obj-$(CONFIG_PPC_8xx) += 8xx/
obj-$(CONFIG_PPC_82xx) += 82xx/
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 06a85b70433..9b2b386ccf4 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -1,3 +1,26 @@
+config PPC_CELL
+ bool
+ default n
+
+config PPC_CELL_NATIVE
+ bool
+ select PPC_CELL
+ select PPC_DCR_MMIO
+ select PPC_OF_PLATFORM_PCI
+ select PPC_INDIRECT_IO
+ select PPC_NATIVE
+ select MPIC
+ default n
+
+config PPC_IBM_CELL_BLADE
+ bool "IBM Cell Blade"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL_NATIVE
+ select PPC_RTAS
+ select MMIO_NVRAM
+ select PPC_UDBG_16550
+ select UDBG_RTAS_CONSOLE
+
menu "Cell Broadband Engine options"
depends on PPC_CELL
@@ -12,12 +35,28 @@ config SPU_FS
Units on machines implementing the Broadband Processor
Architecture.
+config SPU_FS_64K_LS
+ bool "Use 64K pages to map SPE local store"
+ # we depend on PPC_MM_SLICES for now rather than selecting
+ # it because we depend on hugetlbfs hooks being present. We
+ # will fix that when the generic code has been improved to
+ # not require hijacking hugetlbfs hooks.
+ depends on SPU_FS && PPC_MM_SLICES && !PPC_64K_PAGES
+ default y
+ select PPC_HAS_HASH_64K
+ help
+ This option causes SPE local stores to be mapped in process
+ address spaces using 64K pages while the rest of the kernel
+ uses 4K pages. This can improve performances of applications
+ using multiple SPEs by lowering the TLB pressure on them.
+
config SPU_BASE
bool
default n
config CBE_RAS
bool "RAS features for bare metal Cell BE"
+ depends on PPC_CELL_NATIVE
default y
config CBE_THERM
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index a3850fd1e94..f9ac3fe3be9 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -25,9 +25,12 @@
#include <asm/hw_irq.h>
#include <asm/io.h>
+#include <asm/machdep.h>
#include <asm/processor.h>
#include <asm/prom.h>
#include <asm/time.h>
+#include <asm/pmi.h>
+#include <asm/of_platform.h>
#include "cbe_regs.h"
@@ -68,6 +71,38 @@ static u64 MIC_Slow_Next_Timer_table[] = {
* hardware specific functions
*/
+static struct of_device *pmi_dev;
+
+static int set_pmode_pmi(int cpu, unsigned int pmode)
+{
+ int ret;
+ pmi_message_t pmi_msg;
+#ifdef DEBUG
+ u64 time;
+#endif
+
+ pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+ pmi_msg.data1 = cbe_cpu_to_node(cpu);
+ pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+ time = (u64) get_cycles();
+#endif
+
+ pmi_send_message(pmi_dev, pmi_msg);
+ ret = pmi_msg.data2;
+
+ pr_debug("PMI returned slow mode %d\n", ret);
+
+#ifdef DEBUG
+ time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
+ time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
+ pr_debug("had to wait %lu ns for a transition\n", time);
+#endif
+ return ret;
+}
+
+
static int get_pmode(int cpu)
{
int ret;
@@ -79,7 +114,7 @@ static int get_pmode(int cpu)
return ret;
}
-static int set_pmode(int cpu, unsigned int pmode)
+static int set_pmode_reg(int cpu, unsigned int pmode)
{
struct cbe_pmd_regs __iomem *pmd_regs;
struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -120,37 +155,71 @@ static int set_pmode(int cpu, unsigned int pmode)
return 0;
}
+static int set_pmode(int cpu, unsigned int slow_mode) {
+ if (pmi_dev)
+ return set_pmode_pmi(cpu, slow_mode);
+ else
+ return set_pmode_reg(cpu, slow_mode);
+}
+
+static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
+{
+ struct cpufreq_policy policy;
+ u8 cpu;
+ u8 cbe_pmode_new;
+
+ BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+ cpu = cbe_node_to_cpu(pmi_msg.data1);
+ cbe_pmode_new = pmi_msg.data2;
+
+ cpufreq_get_policy(&policy, cpu);
+
+ policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency);
+ policy.min = min(policy.min, policy.max);
+
+ pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max);
+ cpufreq_set_policy(&policy);
+}
+
+static struct pmi_handler cbe_pmi_handler = {
+ .type = PMI_TYPE_FREQ_CHANGE,
+ .handle_pmi_message = cbe_cpufreq_handle_pmi,
+};
+
+
/*
* cpufreq functions
*/
-static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
+static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- u32 *max_freq;
+ const u32 *max_freqp;
+ u32 max_freq;
int i, cur_pmode;
struct device_node *cpu;
cpu = of_get_cpu_node(policy->cpu, NULL);
- if(!cpu)
+ if (!cpu)
return -ENODEV;
pr_debug("init cpufreq on CPU %d\n", policy->cpu);
- max_freq = (u32*) get_property(cpu, "clock-frequency", NULL);
+ max_freqp = of_get_property(cpu, "clock-frequency", NULL);
- if(!max_freq)
+ if (!max_freqp)
return -EINVAL;
- // we need the freq in kHz
- *max_freq /= 1000;
+ /* we need the freq in kHz */
+ max_freq = *max_freqp / 1000;
- pr_debug("max clock-frequency is at %u kHz\n", *max_freq);
+ pr_debug("max clock-frequency is at %u kHz\n", max_freq);
pr_debug("initializing frequency table\n");
- // initialize frequency table
+ /* initialize frequency table */
for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- cbe_freqs[i].frequency = *max_freq / cbe_freqs[i].index;
+ cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index;
pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
}
@@ -167,10 +236,10 @@ static int cbe_cpufreq_cpu_init (struct cpufreq_policy *policy)
policy->cpus = cpu_sibling_map[policy->cpu];
#endif
- cpufreq_frequency_table_get_attr (cbe_freqs, policy->cpu);
+ cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
/* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
- return cpufreq_frequency_table_cpuinfo (policy, cbe_freqs);
+ return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
}
static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
@@ -202,7 +271,7 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target
freqs.new = cbe_freqs[cbe_pmode_new].frequency;
freqs.cpu = policy->cpu;
- mutex_lock (&cbe_switch_mutex);
+ mutex_lock(&cbe_switch_mutex);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
@@ -233,11 +302,26 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
static int __init cbe_cpufreq_init(void)
{
+ struct device_node *np;
+
+ if (!machine_is(cell))
+ return -ENODEV;
+
+ np = of_find_node_by_type(NULL, "ibm,pmi");
+
+ pmi_dev = of_find_device_by_node(np);
+
+ if (pmi_dev)
+ pmi_register_handler(pmi_dev, &cbe_pmi_handler);
+
return cpufreq_register_driver(&cbe_cpufreq_driver);
}
static void __exit cbe_cpufreq_exit(void)
{
+ if (pmi_dev)
+ pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
+
cpufreq_unregister_driver(&cbe_cpufreq_driver);
}
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 9a0ee62691d..12c9674b4b1 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -14,6 +14,8 @@
#include <asm/pgtable.h>
#include <asm/prom.h>
#include <asm/ptrace.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include "cbe_regs.h"
@@ -27,6 +29,7 @@
static struct cbe_regs_map
{
struct device_node *cpu_node;
+ struct device_node *be_node;
struct cbe_pmd_regs __iomem *pmd_regs;
struct cbe_iic_regs __iomem *iic_regs;
struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -37,30 +40,43 @@ static int cbe_regs_map_count;
static struct cbe_thread_map
{
struct device_node *cpu_node;
+ struct device_node *be_node;
struct cbe_regs_map *regs;
+ unsigned int thread_id;
+ unsigned int cbe_id;
} cbe_thread_map[NR_CPUS];
+static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE };
+static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE;
+
static struct cbe_regs_map *cbe_find_map(struct device_node *np)
{
int i;
struct device_node *tmp_np;
- if (strcasecmp(np->type, "spe") == 0) {
- if (np->data == NULL) {
- /* walk up path until cpu node was found */
- tmp_np = np->parent;
- while (tmp_np != NULL && strcasecmp(tmp_np->type, "cpu") != 0)
- tmp_np = tmp_np->parent;
+ if (strcasecmp(np->type, "spe")) {
+ for (i = 0; i < cbe_regs_map_count; i++)
+ if (cbe_regs_maps[i].cpu_node == np ||
+ cbe_regs_maps[i].be_node == np)
+ return &cbe_regs_maps[i];
+ return NULL;
+ }
- np->data = cbe_find_map(tmp_np);
- }
+ if (np->data)
return np->data;
- }
- for (i = 0; i < cbe_regs_map_count; i++)
- if (cbe_regs_maps[i].cpu_node == np)
- return &cbe_regs_maps[i];
- return NULL;
+ /* walk up path until cpu or be node was found */
+ tmp_np = np;
+ do {
+ tmp_np = tmp_np->parent;
+ /* on a correct devicetree we wont get up to root */
+ BUG_ON(!tmp_np);
+ } while (strcasecmp(tmp_np->type, "cpu") &&
+ strcasecmp(tmp_np->type, "be"));
+
+ np->data = cbe_find_map(tmp_np);
+
+ return np->data;
}
struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np)
@@ -130,38 +146,105 @@ struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu)
}
EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs);
-/* FIXME
- * This is little more than a stub at the moment. It should be
- * fleshed out so that it works for both SMT and non-SMT, no
- * matter if the passed cpu is odd or even.
- * For SMT enabled, returns 0 for even-numbered cpu; otherwise 1.
- * For SMT disabled, returns 0 for all cpus.
- */
u32 cbe_get_hw_thread_id(int cpu)
{
- return (cpu & 1);
+ return cbe_thread_map[cpu].thread_id;
}
EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id);
-void __init cbe_regs_init(void)
+u32 cbe_cpu_to_node(int cpu)
{
- int i;
- struct device_node *cpu;
+ return cbe_thread_map[cpu].cbe_id;
+}
+EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
- /* Build local fast map of CPUs */
- for_each_possible_cpu(i)
- cbe_thread_map[i].cpu_node = of_get_cpu_node(i, NULL);
+u32 cbe_node_to_cpu(int node)
+{
+ return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t));
+}
+EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
- /* Find maps for each device tree CPU */
- for_each_node_by_type(cpu, "cpu") {
- struct cbe_regs_map *map = &cbe_regs_maps[cbe_regs_map_count++];
+static struct device_node *cbe_get_be_node(int cpu_id)
+{
+ struct device_node *np;
+
+ for_each_node_by_type (np, "be") {
+ int len,i;
+ const phandle *cpu_handle;
+
+ cpu_handle = of_get_property(np, "cpus", &len);
+
+ for (i=0; i<len; i++)
+ if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
+ return np;
+ }
+
+ return NULL;
+}
+
+void __init cbe_fill_regs_map(struct cbe_regs_map *map)
+{
+ if(map->be_node) {
+ struct device_node *be, *np;
+
+ be = map->be_node;
+
+ for_each_node_by_type(np, "pervasive")
+ if (of_get_parent(np) == be)
+ map->pmd_regs = of_iomap(np, 0);
+
+ for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller")
+ if (of_get_parent(np) == be)
+ map->iic_regs = of_iomap(np, 2);
+ for_each_node_by_type(np, "mic-tm")
+ if (of_get_parent(np) == be)
+ map->mic_tm_regs = of_iomap(np, 0);
+ } else {
+ struct device_node *cpu;
/* That hack must die die die ! */
const struct address_prop {
unsigned long address;
unsigned int len;
} __attribute__((packed)) *prop;
+ cpu = map->cpu_node;
+
+ prop = of_get_property(cpu, "pervasive", NULL);
+ if (prop != NULL)
+ map->pmd_regs = ioremap(prop->address, prop->len);
+
+ prop = of_get_property(cpu, "iic", NULL);
+ if (prop != NULL)
+ map->iic_regs = ioremap(prop->address, prop->len);
+
+ prop = of_get_property(cpu, "mic-tm", NULL);
+ if (prop != NULL)
+ map->mic_tm_regs = ioremap(prop->address, prop->len);
+ }
+}
+
+
+void __init cbe_regs_init(void)
+{
+ int i;
+ unsigned int thread_id;
+ struct device_node *cpu;
+
+ /* Build local fast map of CPUs */
+ for_each_possible_cpu(i) {
+ cbe_thread_map[i].cpu_node = of_get_cpu_node(i, &thread_id);
+ cbe_thread_map[i].be_node = cbe_get_be_node(i);
+ cbe_thread_map[i].thread_id = thread_id;
+ }
+
+ /* Find maps for each device tree CPU */
+ for_each_node_by_type(cpu, "cpu") {
+ struct cbe_regs_map *map;
+ unsigned int cbe_id;
+
+ cbe_id = cbe_regs_map_count++;
+ map = &cbe_regs_maps[cbe_id];
if (cbe_regs_map_count > MAX_CBE) {
printk(KERN_ERR "cbe_regs: More BE chips than supported"
@@ -170,22 +253,21 @@ void __init cbe_regs_init(void)
return;
}
map->cpu_node = cpu;
- for_each_possible_cpu(i)
- if (cbe_thread_map[i].cpu_node == cpu)
- cbe_thread_map[i].regs = map;
- prop = get_property(cpu, "pervasive", NULL);
- if (prop != NULL)
- map->pmd_regs = ioremap(prop->address, prop->len);
+ for_each_possible_cpu(i) {
+ struct cbe_thread_map *thread = &cbe_thread_map[i];
- prop = get_property(cpu, "iic", NULL);
- if (prop != NULL)
- map->iic_regs = ioremap(prop->address, prop->len);
+ if (thread->cpu_node == cpu) {
+ thread->regs = map;
+ thread->cbe_id = cbe_id;
+ map->be_node = thread->be_node;
+ cpu_set(i, cbe_local_mask[cbe_id]);
+ if(thread->thread_id == 0)
+ cpu_set(i, cbe_first_online_cpu);
+ }
+ }
- prop = (struct address_prop *)get_property(cpu, "mic-tm",
- NULL);
- if (prop != NULL)
- map->mic_tm_regs = ioremap(prop->address, prop->len);
+ cbe_fill_regs_map(map);
}
}
diff --git a/arch/powerpc/platforms/cell/cbe_regs.h b/arch/powerpc/platforms/cell/cbe_regs.h
index 440a7ecc66e..17d59714487 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.h
+++ b/arch/powerpc/platforms/cell/cbe_regs.h
@@ -255,6 +255,11 @@ struct cbe_mic_tm_regs {
extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
+/* some utility functions to deal with SMT */
+extern u32 cbe_get_hw_thread_id(int cpu);
+extern u32 cbe_cpu_to_node(int cpu);
+extern u32 cbe_node_to_cpu(int node);
+
/* Init this module early */
extern void cbe_regs_init(void);
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index 70e0d968d30..f370f0fa6f4 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -1,6 +1,31 @@
/*
* thermal support for the cell processor
*
+ * This module adds some sysfs attributes to cpu and spu nodes.
+ * Base for measurements are the digital thermal sensors (DTS)
+ * located on the chip.
+ * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
+ * The attributes can be found under
+ * /sys/devices/system/cpu/cpuX/thermal
+ * /sys/devices/system/spu/spuX/thermal
+ *
+ * The following attributes are added for each node:
+ * temperature:
+ * contains the current temperature measured by the DTS
+ * throttle_begin:
+ * throttling begins when temperature is greater or equal to
+ * throttle_begin. Setting this value to 125 prevents throttling.
+ * throttle_end:
+ * throttling is being ceased, if the temperature is lower than
+ * throttle_end. Due to a delay between applying throttling and
+ * a reduced temperature this value should be less than throttle_begin.
+ * A value equal to throttle_begin provides only a very little hysteresis.
+ * throttle_full_stop:
+ * If the temperatrue is greater or equal to throttle_full_stop,
+ * full throttling is applied to the cpu or spu. This value should be
+ * greater than throttle_begin and throttle_end. Setting this value to
+ * 65 prevents the unit from running code at all.
+ *
* (C) Copyright IBM Deutschland Entwicklung GmbH 2005
*
* Author: Christian Krafft <krafft@de.ibm.com>
@@ -31,6 +56,26 @@
#include "cbe_regs.h"
#include "spu_priv1_mmio.h"
+#define TEMP_MIN 65
+#define TEMP_MAX 125
+
+#define SYSDEV_PREFIX_ATTR(_prefix,_name,_mode) \
+struct sysdev_attribute attr_ ## _prefix ## _ ## _name = { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .show = _prefix ## _show_ ## _name, \
+ .store = _prefix ## _store_ ## _name, \
+};
+
+static inline u8 reg_to_temp(u8 reg_value)
+{
+ return ((reg_value & 0x3f) << 1) + TEMP_MIN;
+}
+
+static inline u8 temp_to_reg(u8 temp)
+{
+ return ((temp - TEMP_MIN) >> 1) & 0x3f;
+}
+
static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
{
struct spu *spu;
@@ -43,14 +88,14 @@ static struct cbe_pmd_regs __iomem *get_pmd_regs(struct sys_device *sysdev)
/* returns the value for a given spu in a given register */
static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iomem *reg)
{
- unsigned int *id;
+ const unsigned int *id;
union spe_reg value;
struct spu *spu;
/* getting the id from the reg attribute will not work on future device-tree layouts
* in future we should store the id to the spu struct and use it here */
spu = container_of(sysdev, struct spu, sysdev);
- id = (unsigned int *)get_property(spu_devnode(spu), "reg", NULL);
+ id = of_get_property(spu_devnode(spu), "reg", NULL);
value.val = in_be64(&reg->val);
return value.spe[*id];
@@ -58,20 +103,81 @@ static u8 spu_read_register_value(struct sys_device *sysdev, union spe_reg __iom
static ssize_t spu_show_temp(struct sys_device *sysdev, char *buf)
{
- int value;
+ u8 value;
struct cbe_pmd_regs __iomem *pmd_regs;
pmd_regs = get_pmd_regs(sysdev);
value = spu_read_register_value(sysdev, &pmd_regs->ts_ctsr1);
- /* clear all other bits */
+
+ return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
+{
+ u64 value;
+
+ value = in_be64(&pmd_regs->tm_tpr.val);
+ /* access the corresponding byte */
+ value >>= pos;
value &= 0x3F;
- /* temp is stored in steps of 2 degrees */
- value *= 2;
- /* base temp is 65 degrees */
- value += 65;
- return sprintf(buf, "%d\n", (int) value);
+ return sprintf(buf, "%d\n", reg_to_temp(value));
+}
+
+static ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
+{
+ u64 reg_value;
+ int temp;
+ u64 new_value;
+ int ret;
+
+ ret = sscanf(buf, "%u", &temp);
+
+ if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
+ return -EINVAL;
+
+ new_value = temp_to_reg(temp);
+
+ reg_value = in_be64(&pmd_regs->tm_tpr.val);
+
+ /* zero out bits for new value */
+ reg_value &= ~(0xffull << pos);
+ /* set bits to new value */
+ reg_value |= new_value << pos;
+
+ out_be64(&pmd_regs->tm_tpr.val, reg_value);
+ return size;
+}
+
+static ssize_t spu_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(get_pmd_regs(sysdev), buf, 0);
+}
+
+static ssize_t spu_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(get_pmd_regs(sysdev), buf, 8);
+}
+
+static ssize_t spu_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(get_pmd_regs(sysdev), buf, 16);
+}
+
+static ssize_t spu_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(get_pmd_regs(sysdev), buf, size, 0);
+}
+
+static ssize_t spu_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(get_pmd_regs(sysdev), buf, size, 8);
+}
+
+static ssize_t spu_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(get_pmd_regs(sysdev), buf, size, 16);
}
static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
@@ -82,16 +188,9 @@ static ssize_t ppe_show_temp(struct sys_device *sysdev, char *buf, int pos)
pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
value = in_be64(&pmd_regs->ts_ctsr2);
- /* access the corresponding byte */
- value >>= pos;
- /* clear all other bits */
- value &= 0x3F;
- /* temp is stored in steps of 2 degrees */
- value *= 2;
- /* base temp is 65 degrees */
- value += 65;
+ value = (value >> pos) & 0x3f;
- return sprintf(buf, "%d\n", (int) value);
+ return sprintf(buf, "%d\n", reg_to_temp(value));
}
@@ -108,13 +207,52 @@ static ssize_t ppe_show_temp1(struct sys_device *sysdev, char *buf)
return ppe_show_temp(sysdev, buf, 0);
}
+static ssize_t ppe_show_throttle_end(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 32);
+}
+
+static ssize_t ppe_show_throttle_begin(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 40);
+}
+
+static ssize_t ppe_show_throttle_full_stop(struct sys_device *sysdev, char *buf)
+{
+ return show_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, 48);
+}
+
+static ssize_t ppe_store_throttle_end(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 32);
+}
+
+static ssize_t ppe_store_throttle_begin(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 40);
+}
+
+static ssize_t ppe_store_throttle_full_stop(struct sys_device *sysdev, const char *buf, size_t size)
+{
+ return store_throttle(cbe_get_cpu_pmd_regs(sysdev->id), buf, size, 48);
+}
+
+
static struct sysdev_attribute attr_spu_temperature = {
.attr = {.name = "temperature", .mode = 0400 },
.show = spu_show_temp,
};
+static SYSDEV_PREFIX_ATTR(spu, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(spu, throttle_full_stop, 0600);
+
+
static struct attribute *spu_attributes[] = {
&attr_spu_temperature.attr,
+ &attr_spu_throttle_end.attr,
+ &attr_spu_throttle_begin.attr,
+ &attr_spu_throttle_full_stop.attr,
NULL,
};
@@ -133,9 +271,16 @@ static struct sysdev_attribute attr_ppe_temperature1 = {
.show = ppe_show_temp1,
};
+static SYSDEV_PREFIX_ATTR(ppe, throttle_end, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_begin, 0600);
+static SYSDEV_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
+
static struct attribute *ppe_attributes[] = {
&attr_ppe_temperature0.attr,
&attr_ppe_temperature1.attr,
+ &attr_ppe_throttle_end.attr,
+ &attr_ppe_throttle_begin.attr,
+ &attr_ppe_throttle_full_stop.attr,
NULL,
};
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 6666d037eb4..47264e72202 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -227,7 +227,7 @@ void iic_request_IPIs(void)
static int iic_host_match(struct irq_host *h, struct device_node *node)
{
- return device_is_compatible(node,
+ return of_device_is_compatible(node,
"IBM,CBEA-Internal-Interrupt-Controller");
}
@@ -256,12 +256,12 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
unsigned int node, ext, unit, class;
const u32 *val;
- if (!device_is_compatible(ct,
+ if (!of_device_is_compatible(ct,
"IBM,CBEA-Internal-Interrupt-Controller"))
return -ENODEV;
if (intsize != 1)
return -ENODEV;
- val = get_property(ct, "#interrupt-cells", NULL);
+ val = of_get_property(ct, "#interrupt-cells", NULL);
if (val == NULL || *val != 1)
return -ENODEV;
@@ -324,10 +324,10 @@ static int __init setup_iic(void)
for (dn = NULL;
(dn = of_find_node_by_name(dn,"interrupt-controller")) != NULL;) {
- if (!device_is_compatible(dn,
+ if (!of_device_is_compatible(dn,
"IBM,CBEA-Internal-Interrupt-Controller"))
continue;
- np = get_property(dn, "ibm,interrupt-server-ranges", NULL);
+ np = of_get_property(dn, "ibm,interrupt-server-ranges", NULL);
if (np == NULL) {
printk(KERN_WARNING "IIC: CPU association not found\n");
of_node_put(dn);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 7c73128305e..7fb92f23f38 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -74,7 +74,7 @@ static void spider_io_flush(const volatile void __iomem *addr)
/* Fast path if we have a non-0 token, it indicates which bus we
* are on.
*
- * If the token is 0, that means either the the ioremap was done
+ * If the token is 0, that means either that the ioremap was done
* before we initialized this layer, or it's a PIO operation. We
* fallback to a low path in this case. Hopefully, internal devices
* which are ioremap'ed early should use in_XX/out_XX functions
@@ -318,7 +318,7 @@ static int __init spider_pci_workaround_init(void)
*/
list_for_each_entry(phb, &hose_list, list_node) {
struct device_node *np = phb->arch_data;
- const char *model = get_property(np, "model", NULL);
+ const char *model = of_get_property(np, "model", NULL);
/* If no model property or name isn't exactly "pci", skip */
if (model == NULL || strcmp(np->name, "pci"))
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 67d617b60a2..760caa76841 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -291,9 +291,9 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base)
const unsigned int *nidp;
const unsigned long *tmp;
- nidp = get_property(np, "node-id", NULL);
+ nidp = of_get_property(np, "node-id", NULL);
if (nidp && *nidp == nid) {
- tmp = get_property(np, "ioc-translation", NULL);
+ tmp = of_get_property(np, "ioc-translation", NULL);
if (tmp) {
*base = *tmp;
of_node_put(np);
@@ -430,7 +430,7 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
struct iommu_window *window;
const unsigned int *ioid;
- ioid = get_property(np, "ioid", NULL);
+ ioid = of_get_property(np, "ioid", NULL);
if (ioid == NULL)
printk(KERN_WARNING "iommu: missing ioid for %s using 0\n",
np->full_name);
@@ -496,7 +496,7 @@ static void cell_dma_dev_setup(struct device *dev)
struct dev_archdata *archdata = &dev->archdata;
/* If we run without iommu, no need to do anything */
- if (pci_dma_ops == &dma_direct_ops)
+ if (get_pci_dma_ops() == &dma_direct_ops)
return;
/* Current implementation uses the first window available in that
@@ -530,7 +530,7 @@ static int cell_of_bus_notify(struct notifier_block *nb, unsigned long action,
return 0;
/* We use the PCI DMA ops */
- dev->archdata.dma_ops = pci_dma_ops;
+ dev->archdata.dma_ops = get_pci_dma_ops();
cell_dma_dev_setup(dev);
@@ -549,7 +549,7 @@ static int __init cell_iommu_get_window(struct device_node *np,
unsigned long index;
/* Use ibm,dma-window if available, else, hard code ! */
- dma_window = get_property(np, "ibm,dma-window", NULL);
+ dma_window = of_get_property(np, "ibm,dma-window", NULL);
if (dma_window == NULL) {
*base = 0;
*size = 0x80000000u;
@@ -646,7 +646,7 @@ static int __init cell_iommu_init_disabled(void)
unsigned long base = 0, size;
/* When no iommu is present, we use direct DMA ops */
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
/* First make sure all IOC translation is turned off */
cell_disable_iommus();
@@ -734,7 +734,7 @@ static int __init cell_iommu_init(void)
}
/* Setup default PCI iommu ops */
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
bail:
/* Register callbacks on OF platform device addition/removal
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 0984c707169..3961a085b43 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -3,11 +3,13 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/smp.h>
+#include <linux/reboot.h>
#include <asm/reg.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/machdep.h>
+#include <asm/rtas.h>
#include "ras.h"
#include "cbe_regs.h"
@@ -82,6 +84,164 @@ static int cbe_machine_check_handler(struct pt_regs *regs)
return 0;
}
+struct ptcal_area {
+ struct list_head list;
+ int nid;
+ int order;
+ struct page *pages;
+};
+
+static LIST_HEAD(ptcal_list);
+
+static int ptcal_start_tok, ptcal_stop_tok;
+
+static int __init cbe_ptcal_enable_on_node(int nid, int order)
+{
+ struct ptcal_area *area;
+ int ret = -ENOMEM;
+ unsigned long addr;
+
+#ifdef CONFIG_CRASH_DUMP
+ rtas_call(ptcal_stop_tok, 1, 1, NULL, nid);
+#endif
+
+ area = kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
+ goto out_err;
+
+ area->nid = nid;
+ area->order = order;
+ area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order);
+
+ if (!area->pages)
+ goto out_free_area;
+
+ addr = __pa(page_address(area->pages));
+
+ ret = -EIO;
+ if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid,
+ (unsigned int)(addr >> 32),
+ (unsigned int)(addr & 0xffffffff))) {
+ printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n",
+ __FUNCTION__, nid);
+ goto out_free_pages;
+ }
+
+ list_add(&area->list, &ptcal_list);
+
+ return 0;
+
+out_free_pages:
+ __free_pages(area->pages, area->order);
+out_free_area:
+ kfree(area);
+out_err:
+ return ret;
+}
+
+static int __init cbe_ptcal_enable(void)
+{
+ const u32 *size;
+ struct device_node *np;
+ int order, found_mic = 0;
+
+ np = of_find_node_by_path("/rtas");
+ if (!np)
+ return -ENODEV;
+
+ size = of_get_property(np, "ibm,cbe-ptcal-size", NULL);
+ if (!size)
+ return -ENODEV;
+
+ pr_debug("%s: enabling PTCAL, size = 0x%x\n", __FUNCTION__, *size);
+ order = get_order(*size);
+ of_node_put(np);
+
+ /* support for malta device trees, with be@/mic@ nodes */
+ for_each_node_by_type(np, "mic-tm") {
+ cbe_ptcal_enable_on_node(of_node_to_nid(np), order);
+ found_mic = 1;
+ }
+
+ if (found_mic)
+ return 0;
+
+ /* support for older device tree - use cpu nodes */
+ for_each_node_by_type(np, "cpu") {
+ const u32 *nid = of_get_property(np, "node-id", NULL);
+ if (!nid) {
+ printk(KERN_ERR "%s: node %s is missing node-id?\n",
+ __FUNCTION__, np->full_name);
+ continue;
+ }
+ cbe_ptcal_enable_on_node(*nid, order);
+ found_mic = 1;
+ }
+
+ return found_mic ? 0 : -ENODEV;
+}
+
+static int cbe_ptcal_disable(void)
+{
+ struct ptcal_area *area, *tmp;
+ int ret = 0;
+
+ pr_debug("%s: disabling PTCAL\n", __FUNCTION__);
+
+ list_for_each_entry_safe(area, tmp, &ptcal_list, list) {
+ /* disable ptcal on this node */
+ if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) {
+ printk(KERN_ERR "%s: error disabling PTCAL "
+ "on node %d!\n", __FUNCTION__,
+ area->nid);
+ ret = -EIO;
+ continue;
+ }
+
+ /* ensure we can access the PTCAL area */
+ memset(page_address(area->pages), 0,
+ 1 << (area->order + PAGE_SHIFT));
+
+ /* clean up */
+ list_del(&area->list);
+ __free_pages(area->pages, area->order);
+ kfree(area);
+ }
+
+ return ret;
+}
+
+static int cbe_ptcal_notify_reboot(struct notifier_block *nb,
+ unsigned long code, void *data)
+{
+ return cbe_ptcal_disable();
+}
+
+static struct notifier_block cbe_ptcal_reboot_notifier = {
+ .notifier_call = cbe_ptcal_notify_reboot
+};
+
+int __init cbe_ptcal_init(void)
+{
+ int ret;
+ ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal");
+ ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal");
+
+ if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE
+ || ptcal_stop_tok == RTAS_UNKNOWN_SERVICE)
+ return -ENODEV;
+
+ ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier);
+ if (ret) {
+ printk(KERN_ERR "Can't disable PTCAL, so not enabling\n");
+ return ret;
+ }
+
+ return cbe_ptcal_enable();
+}
+
+arch_initcall(cbe_ptcal_init);
+
void __init cbe_ras_init(void)
{
unsigned long hid0;
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index 36989c2eee6..db6654272e1 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -71,7 +71,7 @@ static void cell_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: CHRP %s\n", model);
of_node_put(root);
}
@@ -112,7 +112,7 @@ static void __init mpic_init_IRQ(void)
for (dn = NULL;
(dn = of_find_node_by_name(dn, "interrupt-controller"));) {
- if (!device_is_compatible(dn, "CBEA,platform-open-pic"))
+ if (!of_device_is_compatible(dn, "CBEA,platform-open-pic"))
continue;
/* The MPIC driver will get everything it needs from the
@@ -190,15 +190,6 @@ static int __init cell_probe(void)
return 1;
}
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int cell_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
define_machine(cell) {
.name = "Cell",
.probe = cell_probe,
@@ -211,7 +202,6 @@ define_machine(cell) {
.get_rtc_time = rtas_get_rtc_time,
.set_rtc_time = rtas_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
- .check_legacy_ioport = cell_check_legacy_ioport,
.progress = cell_progress,
.init_IRQ = cell_init_irq,
.pci_setup_phb = rtas_setup_phb,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 21a9ebd4978..05f4b3d3d75 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -254,25 +254,25 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
}
/* Now do the horrible hacks */
- tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
+ tmp = of_get_property(pic->of_node, "#interrupt-cells", NULL);
if (tmp == NULL)
return NO_IRQ;
intsize = *tmp;
- imap = get_property(pic->of_node, "interrupt-map", &imaplen);
+ imap = of_get_property(pic->of_node, "interrupt-map", &imaplen);
if (imap == NULL || imaplen < (intsize + 1))
return NO_IRQ;
iic = of_find_node_by_phandle(imap[intsize]);
if (iic == NULL)
return NO_IRQ;
imap += intsize + 1;
- tmp = get_property(iic, "#interrupt-cells", NULL);
+ tmp = of_get_property(iic, "#interrupt-cells", NULL);
if (tmp == NULL)
return NO_IRQ;
intsize = *tmp;
/* Assume unit is last entry of interrupt specifier */
unit = imap[intsize - 1];
/* Ok, we have a unit, now let's try to get the node */
- tmp = get_property(iic, "ibm,interrupt-server-ranges", NULL);
+ tmp = of_get_property(iic, "ibm,interrupt-server-ranges", NULL);
if (tmp == NULL) {
of_node_put(iic);
return NO_IRQ;
@@ -358,12 +358,12 @@ void __init spider_init_IRQ(void)
*/
for (dn = NULL;
(dn = of_find_node_by_name(dn, "interrupt-controller"));) {
- if (device_is_compatible(dn, "CBEA,platform-spider-pic")) {
+ if (of_device_is_compatible(dn, "CBEA,platform-spider-pic")) {
if (of_address_to_resource(dn, 0, &r)) {
printk(KERN_WARNING "spider-pic: Failed\n");
continue;
}
- } else if (device_is_compatible(dn, "sti,platform-spider-pic")
+ } else if (of_device_is_compatible(dn, "sti,platform-spider-pic")
&& (chip < 2)) {
static long hard_coded_pics[] =
{ 0x24000008000ul, 0x34000008000ul};
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index eba7a2641dc..a7f5a7653c6 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -36,12 +36,14 @@
#include <asm/xmon.h>
const struct spu_management_ops *spu_management_ops;
+EXPORT_SYMBOL_GPL(spu_management_ops);
+
const struct spu_priv1_ops *spu_priv1_ops;
static struct list_head spu_list[MAX_NUMNODES];
static LIST_HEAD(spu_full_list);
static DEFINE_MUTEX(spu_mutex);
-static spinlock_t spu_list_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(spu_list_lock);
EXPORT_SYMBOL_GPL(spu_priv1_ops);
@@ -142,12 +144,11 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
switch(REGION_ID(ea)) {
case USER_REGION_ID:
-#ifdef CONFIG_HUGETLB_PAGE
- if (in_hugepage_area(mm->context, ea))
- psize = mmu_huge_psize;
- else
+#ifdef CONFIG_PPC_MM_SLICES
+ psize = get_slice_psize(mm, ea);
+#else
+ psize = mm->context.user_psize;
#endif
- psize = mm->context.user_psize;
vsid = (get_vsid(mm->context.id, ea) << SLB_VSID_SHIFT) |
SLB_VSID_USER;
break;
@@ -290,7 +291,6 @@ spu_irq_class_1(int irq, void *data)
return stat ? IRQ_HANDLED : IRQ_NONE;
}
-EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
static irqreturn_t
spu_irq_class_2(int irq, void *data)
@@ -431,10 +431,11 @@ struct spu *spu_alloc_node(int node)
spu = list_entry(spu_list[node].next, struct spu, list);
list_del_init(&spu->list);
pr_debug("Got SPU %d %d\n", spu->number, spu->node);
- spu_init_channels(spu);
}
mutex_unlock(&spu_mutex);
+ if (spu)
+ spu_init_channels(spu);
return spu;
}
EXPORT_SYMBOL_GPL(spu_alloc_node);
@@ -461,108 +462,6 @@ void spu_free(struct spu *spu)
}
EXPORT_SYMBOL_GPL(spu_free);
-static int spu_handle_mm_fault(struct spu *spu)
-{
- struct mm_struct *mm = spu->mm;
- struct vm_area_struct *vma;
- u64 ea, dsisr, is_write;
- int ret;
-
- ea = spu->dar;
- dsisr = spu->dsisr;
-#if 0
- if (!IS_VALID_EA(ea)) {
- return -EFAULT;
- }
-#endif /* XXX */
- if (mm == NULL) {
- return -EFAULT;
- }
- if (mm->pgd == NULL) {
- return -EFAULT;
- }
-
- down_read(&mm->mmap_sem);
- vma = find_vma(mm, ea);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= ea)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
-#if 0
- if (expand_stack(vma, ea))
- goto bad_area;
-#endif /* XXX */
-good_area:
- is_write = dsisr & MFC_DSISR_ACCESS_PUT;
- if (is_write) {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- } else {
- if (dsisr & MFC_DSISR_ACCESS_DENIED)
- goto bad_area;
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto bad_area;
- }
- ret = 0;
- switch (handle_mm_fault(mm, vma, ea, is_write)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- ret = -EFAULT;
- goto bad_area;
- case VM_FAULT_OOM:
- ret = -ENOMEM;
- goto bad_area;
- default:
- BUG();
- }
- up_read(&mm->mmap_sem);
- return ret;
-
-bad_area:
- up_read(&mm->mmap_sem);
- return -EFAULT;
-}
-
-int spu_irq_class_1_bottom(struct spu *spu)
-{
- u64 ea, dsisr, access, error = 0UL;
- int ret = 0;
-
- ea = spu->dar;
- dsisr = spu->dsisr;
- if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
- u64 flags;
-
- access = (_PAGE_PRESENT | _PAGE_USER);
- access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
- local_irq_save(flags);
- if (hash_page(ea, access, 0x300) != 0)
- error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
- local_irq_restore(flags);
- }
- if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
- if ((ret = spu_handle_mm_fault(spu)) != 0)
- error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
- else
- error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;
- }
- spu->dar = 0UL;
- spu->dsisr = 0UL;
- if (!error) {
- spu_restart_dma(spu);
- } else {
- spu->dma_callback(spu, SPE_EVENT_SPE_DATA_STORAGE);
- }
- return ret;
-}
-
struct sysdev_class spu_sysdev_class = {
set_kset_name("spu")
};
@@ -636,12 +535,6 @@ static int spu_create_sysdev(struct spu *spu)
return 0;
}
-static void spu_destroy_sysdev(struct spu *spu)
-{
- sysfs_remove_device_from_node(&spu->sysdev, spu->node);
- sysdev_unregister(&spu->sysdev);
-}
-
static int __init create_spu(void *data)
{
struct spu *spu;
@@ -693,58 +586,37 @@ out:
return ret;
}
-static void destroy_spu(struct spu *spu)
-{
- list_del_init(&spu->list);
- list_del_init(&spu->full_list);
-
- spu_destroy_sysdev(spu);
- spu_free_irqs(spu);
- spu_destroy_spu(spu);
- kfree(spu);
-}
-
-static void cleanup_spu_base(void)
-{
- struct spu *spu, *tmp;
- int node;
-
- mutex_lock(&spu_mutex);
- for (node = 0; node < MAX_NUMNODES; node++) {
- list_for_each_entry_safe(spu, tmp, &spu_list[node], list)
- destroy_spu(spu);
- }
- mutex_unlock(&spu_mutex);
- sysdev_class_unregister(&spu_sysdev_class);
-}
-module_exit(cleanup_spu_base);
-
static int __init init_spu_base(void)
{
- int i, ret;
+ int i, ret = 0;
+
+ for (i = 0; i < MAX_NUMNODES; i++)
+ INIT_LIST_HEAD(&spu_list[i]);
if (!spu_management_ops)
- return 0;
+ goto out;
/* create sysdev class for spus */
ret = sysdev_class_register(&spu_sysdev_class);
if (ret)
- return ret;
-
- for (i = 0; i < MAX_NUMNODES; i++)
- INIT_LIST_HEAD(&spu_list[i]);
+ goto out;
ret = spu_enumerate_spus(create_spu);
if (ret) {
printk(KERN_WARNING "%s: Error initializing spus\n",
__FUNCTION__);
- cleanup_spu_base();
- return ret;
+ goto out_unregister_sysdev_class;
}
xmon_register_spus(&spu_full_list);
+ return 0;
+
+ out_unregister_sysdev_class:
+ sysdev_class_unregister(&spu_sysdev_class);
+ out:
+
return ret;
}
module_init(init_spu_base);
diff --git a/arch/powerpc/platforms/cell/spu_coredump.c b/arch/powerpc/platforms/cell/spu_coredump.c
index 6915b418ee7..4fd37ff1e21 100644
--- a/arch/powerpc/platforms/cell/spu_coredump.c
+++ b/arch/powerpc/platforms/cell/spu_coredump.c
@@ -26,19 +26,18 @@
#include <asm/spu.h>
-static struct spu_coredump_calls spu_coredump_calls;
+static struct spu_coredump_calls *spu_coredump_calls;
static DEFINE_MUTEX(spu_coredump_mutex);
int arch_notes_size(void)
{
long ret;
- struct module *owner = spu_coredump_calls.owner;
ret = -ENOSYS;
mutex_lock(&spu_coredump_mutex);
- if (owner && try_module_get(owner)) {
- ret = spu_coredump_calls.arch_notes_size();
- module_put(owner);
+ if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+ ret = spu_coredump_calls->arch_notes_size();
+ module_put(spu_coredump_calls->owner);
}
mutex_unlock(&spu_coredump_mutex);
return ret;
@@ -46,36 +45,35 @@ int arch_notes_size(void)
void arch_write_notes(struct file *file)
{
- struct module *owner = spu_coredump_calls.owner;
-
mutex_lock(&spu_coredump_mutex);
- if (owner && try_module_get(owner)) {
- spu_coredump_calls.arch_write_notes(file);
- module_put(owner);
+ if (spu_coredump_calls && try_module_get(spu_coredump_calls->owner)) {
+ spu_coredump_calls->arch_write_notes(file);
+ module_put(spu_coredump_calls->owner);
}
mutex_unlock(&spu_coredump_mutex);
}
int register_arch_coredump_calls(struct spu_coredump_calls *calls)
{
- if (spu_coredump_calls.owner)
- return -EBUSY;
+ int ret = 0;
+
mutex_lock(&spu_coredump_mutex);
- spu_coredump_calls.arch_notes_size = calls->arch_notes_size;
- spu_coredump_calls.arch_write_notes = calls->arch_write_notes;
- spu_coredump_calls.owner = calls->owner;
+ if (spu_coredump_calls)
+ ret = -EBUSY;
+ else
+ spu_coredump_calls = calls;
mutex_unlock(&spu_coredump_mutex);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(register_arch_coredump_calls);
void unregister_arch_coredump_calls(struct spu_coredump_calls *calls)
{
- BUG_ON(spu_coredump_calls.owner != calls->owner);
+ BUG_ON(spu_coredump_calls != calls);
mutex_lock(&spu_coredump_mutex);
- spu_coredump_calls.owner = NULL;
+ spu_coredump_calls = NULL;
mutex_unlock(&spu_coredump_mutex);
}
EXPORT_SYMBOL_GPL(unregister_arch_coredump_calls);
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
index e34599f53d2..1d4562ae463 100644
--- a/arch/powerpc/platforms/cell/spu_manage.c
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -48,11 +48,11 @@ static u64 __init find_spu_unit_number(struct device_node *spe)
{
const unsigned int *prop;
int proplen;
- prop = get_property(spe, "unit-id", &proplen);
+ prop = of_get_property(spe, "unit-id", &proplen);
if (proplen == 4)
return (u64)*prop;
- prop = get_property(spe, "reg", &proplen);
+ prop = of_get_property(spe, "reg", &proplen);
if (proplen == 4)
return (u64)*prop;
@@ -76,12 +76,12 @@ static int __init spu_map_interrupts_old(struct spu *spu,
int nid;
/* Get the interrupt source unit from the device-tree */
- tmp = get_property(np, "isrc", NULL);
+ tmp = of_get_property(np, "isrc", NULL);
if (!tmp)
return -ENODEV;
isrc = tmp[0];
- tmp = get_property(np->parent->parent, "node-id", NULL);
+ tmp = of_get_property(np->parent->parent, "node-id", NULL);
if (!tmp) {
printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
nid = spu->node;
@@ -110,7 +110,7 @@ static void __iomem * __init spu_map_prop_old(struct spu *spu,
} __attribute__((packed)) *prop;
int proplen;
- prop = get_property(n, name, &proplen);
+ prop = of_get_property(n, name, &proplen);
if (prop == NULL || proplen != sizeof (struct address_prop))
return NULL;
@@ -124,11 +124,11 @@ static int __init spu_map_device_old(struct spu *spu)
int ret;
ret = -ENODEV;
- spu->name = get_property(node, "name", NULL);
+ spu->name = of_get_property(node, "name", NULL);
if (!spu->name)
goto out;
- prop = get_property(node, "local-store", NULL);
+ prop = of_get_property(node, "local-store", NULL);
if (!prop)
goto out;
spu->local_store_phys = *(unsigned long *)prop;
@@ -139,7 +139,7 @@ static int __init spu_map_device_old(struct spu *spu)
if (!spu->local_store)
goto out;
- prop = get_property(node, "problem", NULL);
+ prop = of_get_property(node, "problem", NULL);
if (!prop)
goto out_unmap;
spu->problem_phys = *(unsigned long *)prop;
@@ -226,7 +226,7 @@ static int __init spu_map_device(struct spu *spu)
struct device_node *np = spu->devnode;
int ret = -ENODEV;
- spu->name = get_property(np, "name", NULL);
+ spu->name = of_get_property(np, "name", NULL);
if (!spu->name)
goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index 472217d19fa..328afcf8950 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -1,4 +1,4 @@
-obj-y += switch.o
+obj-y += switch.o fault.o lscsa_alloc.o
obj-$(CONFIG_SPU_FS) += spufs.o
spufs-y += inode.o file.o context.o syscalls.o coredump.o
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index 1898f0d3a8b..d32db9ffc6e 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -28,7 +28,6 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/poll.h>
@@ -350,6 +349,11 @@ static int spu_backing_send_mfc_command(struct spu_context *ctx,
return ret;
}
+static void spu_backing_restart_dma(struct spu_context *ctx)
+{
+ /* nothing to do here */
+}
+
struct spu_context_ops spu_backing_ops = {
.mbox_read = spu_backing_mbox_read,
.mbox_stat_read = spu_backing_mbox_stat_read,
@@ -376,4 +380,5 @@ struct spu_context_ops spu_backing_ops = {
.read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
.get_mfc_free_elements = spu_backing_get_mfc_free_elements,
.send_mfc_command = spu_backing_send_mfc_command,
+ .restart_dma = spu_backing_restart_dma,
};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 04ad2e364e9..8654749e317 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -36,14 +36,13 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
/* Binding to physical processor deferred
* until spu_activate().
*/
- spu_init_csa(&ctx->csa);
- if (!ctx->csa.lscsa) {
+ if (spu_init_csa(&ctx->csa))
goto out_free;
- }
spin_lock_init(&ctx->mmio_lock);
+ spin_lock_init(&ctx->mapping_lock);
kref_init(&ctx->kref);
mutex_init(&ctx->state_mutex);
- init_MUTEX(&ctx->run_sema);
+ mutex_init(&ctx->run_mutex);
init_waitqueue_head(&ctx->ibox_wq);
init_waitqueue_head(&ctx->wbox_wq);
init_waitqueue_head(&ctx->stop_wq);
@@ -51,6 +50,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
ctx->state = SPU_STATE_SAVED;
ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current);
+ INIT_LIST_HEAD(&ctx->rq);
if (gang)
spu_gang_add_ctx(gang, ctx);
ctx->rt_priority = current->rt_priority;
@@ -75,6 +75,7 @@ void destroy_spu_context(struct kref *kref)
spu_fini_csa(&ctx->csa);
if (ctx->gang)
spu_gang_remove_ctx(ctx->gang, ctx);
+ BUG_ON(!list_empty(&ctx->rq));
kfree(ctx);
}
@@ -119,46 +120,6 @@ void spu_unmap_mappings(struct spu_context *ctx)
}
/**
- * spu_acquire_exclusive - lock spu contex and protect against userspace access
- * @ctx: spu contex to lock
- *
- * Note:
- * Returns 0 and with the context locked on success
- * Returns negative error and with the context _unlocked_ on failure.
- */
-int spu_acquire_exclusive(struct spu_context *ctx)
-{
- int ret = -EINVAL;
-
- spu_acquire(ctx);
- /*
- * Context is about to be freed, so we can't acquire it anymore.
- */
- if (!ctx->owner)
- goto out_unlock;
-
- if (ctx->state == SPU_STATE_SAVED) {
- ret = spu_activate(ctx, 0);
- if (ret)
- goto out_unlock;
- } else {
- /*
- * We need to exclude userspace access to the context.
- *
- * To protect against memory access we invalidate all ptes
- * and make sure the pagefault handlers block on the mutex.
- */
- spu_unmap_mappings(ctx);
- }
-
- return 0;
-
- out_unlock:
- spu_release(ctx);
- return ret;
-}
-
-/**
* spu_acquire_runnable - lock spu contex and make sure it is in runnable state
* @ctx: spu contex to lock
*
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 725e1956115..5d9ad5a0307 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -169,12 +169,12 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
struct spu_context *ctx;
loff_t pos = 0;
int sz, dfd, rc, total = 0;
- const int bufsz = 4096;
+ const int bufsz = PAGE_SIZE;
char *name;
char fullname[80], *buf;
struct elf_note en;
- buf = kmalloc(bufsz, GFP_KERNEL);
+ buf = (void *)get_zeroed_page(GFP_KERNEL);
if (!buf)
return;
@@ -187,9 +187,8 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
sz = spufs_coredump_read[i].size;
ctx = ctx_info->ctx;
- if (!ctx) {
- return;
- }
+ if (!ctx)
+ goto out;
sprintf(fullname, "SPU/%d/%s", dfd, name);
en.n_namesz = strlen(fullname) + 1;
@@ -197,23 +196,25 @@ static void spufs_arch_write_note(struct spufs_ctx_info *ctx_info, int i,
en.n_type = NT_SPU;
if (!spufs_dump_write(file, &en, sizeof(en)))
- return;
+ goto out;
if (!spufs_dump_write(file, fullname, en.n_namesz))
- return;
+ goto out;
if (!spufs_dump_seek(file, roundup((unsigned long)file->f_pos, 4)))
- return;
+ goto out;
do {
rc = do_coredump_read(i, ctx, buf, bufsz, &pos);
if (rc > 0) {
if (!spufs_dump_write(file, buf, rc))
- return;
+ goto out;
total += rc;
}
} while (rc == bufsz && total < sz);
spufs_dump_seek(file, roundup((unsigned long)file->f_pos
- total + sz, 4));
+out:
+ free_page((unsigned long)buf);
}
static void spufs_arch_write_notes(struct file *file)
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
new file mode 100644
index 00000000000..0f75c07e29d
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -0,0 +1,211 @@
+/*
+ * Low-level SPU handling
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.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, 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/sched.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+
+#include "spufs.h"
+
+/*
+ * This ought to be kept in sync with the powerpc specific do_page_fault
+ * function. Currently, there are a few corner cases that we haven't had
+ * to handle fortunately.
+ */
+static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr)
+{
+ struct vm_area_struct *vma;
+ unsigned long is_write;
+ int ret;
+
+#if 0
+ if (!IS_VALID_EA(ea)) {
+ return -EFAULT;
+ }
+#endif /* XXX */
+ if (mm == NULL) {
+ return -EFAULT;
+ }
+ if (mm->pgd == NULL) {
+ return -EFAULT;
+ }
+
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, ea);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= ea)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, ea))
+ goto bad_area;
+good_area:
+ is_write = dsisr & MFC_DSISR_ACCESS_PUT;
+ if (is_write) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (dsisr & MFC_DSISR_ACCESS_DENIED)
+ goto bad_area;
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto bad_area;
+ }
+ ret = 0;
+ switch (handle_mm_fault(mm, vma, ea, is_write)) {
+ case VM_FAULT_MINOR:
+ current->min_flt++;
+ break;
+ case VM_FAULT_MAJOR:
+ current->maj_flt++;
+ break;
+ case VM_FAULT_SIGBUS:
+ ret = -EFAULT;
+ goto bad_area;
+ case VM_FAULT_OOM:
+ ret = -ENOMEM;
+ goto bad_area;
+ default:
+ BUG();
+ }
+ up_read(&mm->mmap_sem);
+ return ret;
+
+bad_area:
+ up_read(&mm->mmap_sem);
+ return -EFAULT;
+}
+
+static void spufs_handle_dma_error(struct spu_context *ctx,
+ unsigned long ea, int type)
+{
+ if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+ ctx->event_return |= type;
+ wake_up_all(&ctx->stop_wq);
+ } else {
+ siginfo_t info;
+ memset(&info, 0, sizeof(info));
+
+ switch (type) {
+ case SPE_EVENT_INVALID_DMA:
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_OBJERR;
+ break;
+ case SPE_EVENT_SPE_DATA_STORAGE:
+ info.si_signo = SIGBUS;
+ info.si_addr = (void __user *)ea;
+ info.si_code = BUS_ADRERR;
+ break;
+ case SPE_EVENT_DMA_ALIGNMENT:
+ info.si_signo = SIGBUS;
+ /* DAR isn't set for an alignment fault :( */
+ info.si_code = BUS_ADRALN;
+ break;
+ case SPE_EVENT_SPE_ERROR:
+ info.si_signo = SIGILL;
+ info.si_addr = (void __user *)(unsigned long)
+ ctx->ops->npc_read(ctx) - 4;
+ info.si_code = ILL_ILLOPC;
+ break;
+ }
+ if (info.si_signo)
+ force_sig_info(info.si_signo, &info, current);
+ }
+}
+
+void spufs_dma_callback(struct spu *spu, int type)
+{
+ spufs_handle_dma_error(spu->ctx, spu->dar, type);
+}
+EXPORT_SYMBOL_GPL(spufs_dma_callback);
+
+/*
+ * bottom half handler for page faults, we can't do this from
+ * interrupt context, since we might need to sleep.
+ * we also need to give up the mutex so we can get scheduled
+ * out while waiting for the backing store.
+ *
+ * TODO: try calling hash_page from the interrupt handler first
+ * in order to speed up the easy case.
+ */
+int spufs_handle_class1(struct spu_context *ctx)
+{
+ u64 ea, dsisr, access;
+ unsigned long flags;
+ int ret;
+
+ /*
+ * dar and dsisr get passed from the registers
+ * to the spu_context, to this function, but not
+ * back to the spu if it gets scheduled again.
+ *
+ * if we don't handle the fault for a saved context
+ * in time, we can still expect to get the same fault
+ * the immediately after the context restore.
+ */
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ ea = ctx->spu->dar;
+ dsisr = ctx->spu->dsisr;
+ ctx->spu->dar= ctx->spu->dsisr = 0;
+ } else {
+ ea = ctx->csa.priv1.mfc_dar_RW;
+ dsisr = ctx->csa.priv1.mfc_dsisr_RW;
+ ctx->csa.priv1.mfc_dar_RW = 0;
+ ctx->csa.priv1.mfc_dsisr_RW = 0;
+ }
+
+ if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
+ return 0;
+
+ pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
+ dsisr, ctx->state);
+
+ /* we must not hold the lock when entering spu_handle_mm_fault */
+ spu_release(ctx);
+
+ access = (_PAGE_PRESENT | _PAGE_USER);
+ access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
+ local_irq_save(flags);
+ ret = hash_page(ea, access, 0x300);
+ local_irq_restore(flags);
+
+ /* hashing failed, so try the actual fault handler */
+ if (ret)
+ ret = spu_handle_mm_fault(current->mm, ea, dsisr);
+
+ spu_acquire(ctx);
+ /*
+ * If we handled the fault successfully and are in runnable
+ * state, restart the DMA.
+ * In case of unhandled error report the problem to user space.
+ */
+ if (!ret) {
+ if (ctx->spu)
+ ctx->ops->restart_dma(ctx);
+ } else
+ spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 505266a568d..45614c73c78 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -44,9 +44,25 @@ spufs_mem_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->local_store = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->local_store = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
+static int
+spufs_mem_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->local_store = NULL;
+ spin_unlock(&ctx->mapping_lock);
return 0;
}
@@ -102,14 +118,32 @@ spufs_mem_write(struct file *file, const char __user *buffer,
static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
unsigned long address)
{
- struct spu_context *ctx = vma->vm_file->private_data;
- unsigned long pfn, offset = address - vma->vm_start;
+ struct spu_context *ctx = vma->vm_file->private_data;
+ unsigned long pfn, offset, addr0 = address;
+#ifdef CONFIG_SPU_FS_64K_LS
+ struct spu_state *csa = &ctx->csa;
+ int psize;
- offset += vma->vm_pgoff << PAGE_SHIFT;
+ /* Check what page size we are using */
+ psize = get_slice_psize(vma->vm_mm, address);
+ /* Some sanity checking */
+ BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K));
+
+ /* Wow, 64K, cool, we need to align the address though */
+ if (csa->use_big_pages) {
+ BUG_ON(vma->vm_start & 0xffff);
+ address &= ~0xfffful;
+ }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
+ offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
if (offset >= LS_SIZE)
return NOPFN_SIGBUS;
+ pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n",
+ addr0, address, offset);
+
spu_acquire(ctx);
if (ctx->state == SPU_STATE_SAVED) {
@@ -133,9 +167,24 @@ static struct vm_operations_struct spufs_mem_mmap_vmops = {
.nopfn = spufs_mem_mmap_nopfn,
};
-static int
-spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
-{
+static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_SPU_FS_64K_LS
+ struct spu_context *ctx = file->private_data;
+ struct spu_state *csa = &ctx->csa;
+
+ /* Sanity check VMA alignment */
+ if (csa->use_big_pages) {
+ pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx,"
+ " pgoff=0x%lx\n", vma->vm_start, vma->vm_end,
+ vma->vm_pgoff);
+ if (vma->vm_start & 0xffff)
+ return -EINVAL;
+ if (vma->vm_pgoff & 0xf)
+ return -EINVAL;
+ }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
@@ -147,12 +196,34 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
+#ifdef CONFIG_SPU_FS_64K_LS
+unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct spu_context *ctx = file->private_data;
+ struct spu_state *csa = &ctx->csa;
+
+ /* If not using big pages, fallback to normal MM g_u_a */
+ if (!csa->use_big_pages)
+ return current->mm->get_unmapped_area(file, addr, len,
+ pgoff, flags);
+
+ /* Else, try to obtain a 64K pages slice */
+ return slice_get_unmapped_area(addr, len, flags,
+ MMU_PAGE_64K, 1, 0);
+}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
static const struct file_operations spufs_mem_fops = {
- .open = spufs_mem_open,
- .read = spufs_mem_read,
- .write = spufs_mem_write,
- .llseek = generic_file_llseek,
- .mmap = spufs_mem_mmap,
+ .open = spufs_mem_open,
+ .read = spufs_mem_read,
+ .write = spufs_mem_write,
+ .llseek = generic_file_llseek,
+ .mmap = spufs_mem_mmap,
+#ifdef CONFIG_SPU_FS_64K_LS
+ .get_unmapped_area = spufs_get_unmapped_area,
+#endif
};
static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
@@ -238,16 +309,33 @@ static int spufs_cntl_open(struct inode *inode, struct file *file)
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->cntl = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->cntl = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return simple_attr_open(inode, file, spufs_cntl_get,
spufs_cntl_set, "0x%08lx");
}
+static int
+spufs_cntl_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ simple_attr_close(inode, file);
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->cntl = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static const struct file_operations spufs_cntl_fops = {
.open = spufs_cntl_open,
- .release = simple_attr_close,
+ .release = spufs_cntl_release,
.read = simple_attr_read,
.write = simple_attr_write,
.mmap = spufs_cntl_mmap,
@@ -723,12 +811,28 @@ static int spufs_signal1_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->signal1 = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->signal1 = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_signal1_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->signal1 = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
size_t len, loff_t *pos)
{
@@ -821,6 +925,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
static const struct file_operations spufs_signal1_fops = {
.open = spufs_signal1_open,
+ .release = spufs_signal1_release,
.read = spufs_signal1_read,
.write = spufs_signal1_write,
.mmap = spufs_signal1_mmap,
@@ -830,12 +935,28 @@ static int spufs_signal2_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->signal2 = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->signal2 = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_signal2_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->signal2 = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
size_t len, loff_t *pos)
{
@@ -932,6 +1053,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
static const struct file_operations spufs_signal2_fops = {
.open = spufs_signal2_open,
+ .release = spufs_signal2_release,
.read = spufs_signal2_read,
.write = spufs_signal2_write,
.mmap = spufs_signal2_mmap,
@@ -1031,13 +1153,30 @@ static int spufs_mss_open(struct inode *inode, struct file *file)
struct spu_context *ctx = i->i_ctx;
file->private_data = i->i_ctx;
- ctx->mss = inode->i_mapping;
- smp_wmb();
+
+ spin_lock(&ctx->mapping_lock);
+ if (!i->i_openers++)
+ ctx->mss = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_mss_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->mss = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static const struct file_operations spufs_mss_fops = {
.open = spufs_mss_open,
+ .release = spufs_mss_release,
.mmap = spufs_mss_mmap,
};
@@ -1072,14 +1211,30 @@ static int spufs_psmap_open(struct inode *inode, struct file *file)
struct spufs_inode_info *i = SPUFS_I(inode);
struct spu_context *ctx = i->i_ctx;
+ spin_lock(&ctx->mapping_lock);
file->private_data = i->i_ctx;
- ctx->psmap = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->psmap = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_psmap_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->psmap = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
static const struct file_operations spufs_psmap_fops = {
.open = spufs_psmap_open,
+ .release = spufs_psmap_release,
.mmap = spufs_psmap_mmap,
};
@@ -1126,12 +1281,27 @@ static int spufs_mfc_open(struct inode *inode, struct file *file)
if (atomic_read(&inode->i_count) != 1)
return -EBUSY;
+ spin_lock(&ctx->mapping_lock);
file->private_data = ctx;
- ctx->mfc = inode->i_mapping;
- smp_wmb();
+ if (!i->i_openers++)
+ ctx->mfc = inode->i_mapping;
+ spin_unlock(&ctx->mapping_lock);
return nonseekable_open(inode, file);
}
+static int
+spufs_mfc_release(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ spin_lock(&ctx->mapping_lock);
+ if (!--i->i_openers)
+ ctx->mfc = NULL;
+ spin_unlock(&ctx->mapping_lock);
+ return 0;
+}
+
/* interrupt-level mfc callback function. */
void spufs_mfc_callback(struct spu *spu)
{
@@ -1313,7 +1483,10 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
if (ret)
goto out;
- spu_acquire_runnable(ctx, 0);
+ ret = spu_acquire_runnable(ctx, 0);
+ if (ret)
+ goto out;
+
if (file->f_flags & O_NONBLOCK) {
ret = ctx->ops->send_mfc_command(ctx, &cmd);
} else {
@@ -1399,6 +1572,7 @@ static int spufs_mfc_fasync(int fd, struct file *file, int on)
static const struct file_operations spufs_mfc_fops = {
.open = spufs_mfc_open,
+ .release = spufs_mfc_release,
.read = spufs_mfc_read,
.write = spufs_mfc_write,
.poll = spufs_mfc_poll,
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index ae42e03b8c8..fc4ed1ffbd4 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -25,7 +25,6 @@
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
@@ -296,6 +295,14 @@ static int spu_hw_send_mfc_command(struct spu_context *ctx,
}
}
+static void spu_hw_restart_dma(struct spu_context *ctx)
+{
+ struct spu_priv2 __iomem *priv2 = ctx->spu->priv2;
+
+ if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &ctx->spu->flags))
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+}
+
struct spu_context_ops spu_hw_ops = {
.mbox_read = spu_hw_mbox_read,
.mbox_stat_read = spu_hw_mbox_stat_read,
@@ -320,4 +327,5 @@ struct spu_context_ops spu_hw_ops = {
.read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
.get_mfc_free_elements = spu_hw_get_mfc_free_elements,
.send_mfc_command = spu_hw_send_mfc_command,
+ .restart_dma = spu_hw_restart_dma,
};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 8079983ef94..a93f328a731 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -36,6 +36,7 @@
#include <asm/prom.h>
#include <asm/semaphore.h>
#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#include <asm/uaccess.h>
#include "spufs.h"
@@ -54,6 +55,7 @@ spufs_alloc_inode(struct super_block *sb)
ei->i_gang = NULL;
ei->i_ctx = NULL;
+ ei->i_openers = 0;
return &ei->vfs_inode;
}
@@ -69,8 +71,7 @@ spufs_init_once(void *p, struct kmem_cache * cachep, unsigned long flags)
{
struct spufs_inode_info *ei = p;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&ei->vfs_inode);
}
}
@@ -520,13 +521,14 @@ out:
/* File system initialization */
enum {
- Opt_uid, Opt_gid, Opt_err,
+ Opt_uid, Opt_gid, Opt_mode, Opt_err,
};
static match_table_t spufs_tokens = {
- { Opt_uid, "uid=%d" },
- { Opt_gid, "gid=%d" },
- { Opt_err, NULL },
+ { Opt_uid, "uid=%d" },
+ { Opt_gid, "gid=%d" },
+ { Opt_mode, "mode=%o" },
+ { Opt_err, NULL },
};
static int
@@ -553,6 +555,11 @@ spufs_parse_options(char *options, struct inode *root)
return 0;
root->i_gid = option;
break;
+ case Opt_mode:
+ if (match_octal(&args[0], &option))
+ return 0;
+ root->i_mode = option | S_IFDIR;
+ break;
default:
return 0;
}
@@ -560,6 +567,11 @@ spufs_parse_options(char *options, struct inode *root)
return 1;
}
+static void spufs_exit_isolated_loader(void)
+{
+ kfree(isolated_loader);
+}
+
static void
spufs_init_isolated_loader(void)
{
@@ -571,7 +583,7 @@ spufs_init_isolated_loader(void)
if (!dn)
return;
- loader = get_property(dn, "loader", &size);
+ loader = of_get_property(dn, "loader", &size);
if (!loader)
return;
@@ -653,6 +665,10 @@ static int __init spufs_init(void)
{
int ret;
+ ret = -ENODEV;
+ if (!spu_management_ops)
+ goto out;
+
ret = -ENOMEM;
spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
sizeof(struct spufs_inode_info), 0,
@@ -660,25 +676,29 @@ static int __init spufs_init(void)
if (!spufs_inode_cache)
goto out;
- if (spu_sched_init() != 0) {
- kmem_cache_destroy(spufs_inode_cache);
- goto out;
- }
- ret = register_filesystem(&spufs_type);
+ ret = spu_sched_init();
if (ret)
goto out_cache;
+ ret = register_filesystem(&spufs_type);
+ if (ret)
+ goto out_sched;
ret = register_spu_syscalls(&spufs_calls);
if (ret)
goto out_fs;
ret = register_arch_coredump_calls(&spufs_coredump_calls);
if (ret)
- goto out_fs;
+ goto out_syscalls;
spufs_init_isolated_loader();
return 0;
+
+out_syscalls:
+ unregister_spu_syscalls(&spufs_calls);
out_fs:
unregister_filesystem(&spufs_type);
+out_sched:
+ spu_sched_exit();
out_cache:
kmem_cache_destroy(spufs_inode_cache);
out:
@@ -689,6 +709,7 @@ module_init(spufs_init);
static void __exit spufs_exit(void)
{
spu_sched_exit();
+ spufs_exit_isolated_loader();
unregister_arch_coredump_calls(&spufs_coredump_calls);
unregister_spu_syscalls(&spufs_calls);
unregister_filesystem(&spufs_type);
diff --git a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c
new file mode 100644
index 00000000000..f4b3c052dab
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c
@@ -0,0 +1,181 @@
+/*
+ * SPU local store allocation routines
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * 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, 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.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+
+#include <asm/spu.h>
+#include <asm/spu_csa.h>
+#include <asm/mmu.h>
+
+static int spu_alloc_lscsa_std(struct spu_state *csa)
+{
+ struct spu_lscsa *lscsa;
+ unsigned char *p;
+
+ lscsa = vmalloc(sizeof(struct spu_lscsa));
+ if (!lscsa)
+ return -ENOMEM;
+ memset(lscsa, 0, sizeof(struct spu_lscsa));
+ csa->lscsa = lscsa;
+
+ /* Set LS pages reserved to allow for user-space mapping. */
+ for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+ SetPageReserved(vmalloc_to_page(p));
+
+ return 0;
+}
+
+static void spu_free_lscsa_std(struct spu_state *csa)
+{
+ /* Clear reserved bit before vfree. */
+ unsigned char *p;
+
+ if (csa->lscsa == NULL)
+ return;
+
+ for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+ ClearPageReserved(vmalloc_to_page(p));
+
+ vfree(csa->lscsa);
+}
+
+#ifdef CONFIG_SPU_FS_64K_LS
+
+#define SPU_64K_PAGE_SHIFT 16
+#define SPU_64K_PAGE_ORDER (SPU_64K_PAGE_SHIFT - PAGE_SHIFT)
+#define SPU_64K_PAGE_COUNT (1ul << SPU_64K_PAGE_ORDER)
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+ struct page **pgarray;
+ unsigned char *p;
+ int i, j, n_4k;
+
+ /* Check availability of 64K pages */
+ if (mmu_psize_defs[MMU_PAGE_64K].shift == 0)
+ goto fail;
+
+ csa->use_big_pages = 1;
+
+ pr_debug("spu_alloc_lscsa(csa=0x%p), trying to allocate 64K pages\n",
+ csa);
+
+ /* First try to allocate our 64K pages. We need 5 of them
+ * with the current implementation. In the future, we should try
+ * to separate the lscsa with the actual local store image, thus
+ * allowing us to require only 4 64K pages per context
+ */
+ for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++) {
+ /* XXX This is likely to fail, we should use a special pool
+ * similiar to what hugetlbfs does.
+ */
+ csa->lscsa_pages[i] = alloc_pages(GFP_KERNEL,
+ SPU_64K_PAGE_ORDER);
+ if (csa->lscsa_pages[i] == NULL)
+ goto fail;
+ }
+
+ pr_debug(" success ! creating vmap...\n");
+
+ /* Now we need to create a vmalloc mapping of these for the kernel
+ * and SPU context switch code to use. Currently, we stick to a
+ * normal kernel vmalloc mapping, which in our case will be 4K
+ */
+ n_4k = SPU_64K_PAGE_COUNT * SPU_LSCSA_NUM_BIG_PAGES;
+ pgarray = kmalloc(sizeof(struct page *) * n_4k, GFP_KERNEL);
+ if (pgarray == NULL)
+ goto fail;
+ for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+ for (j = 0; j < SPU_64K_PAGE_COUNT; j++)
+ /* We assume all the struct page's are contiguous
+ * which should be hopefully the case for an order 4
+ * allocation..
+ */
+ pgarray[i * SPU_64K_PAGE_COUNT + j] =
+ csa->lscsa_pages[i] + j;
+ csa->lscsa = vmap(pgarray, n_4k, VM_USERMAP, PAGE_KERNEL);
+ kfree(pgarray);
+ if (csa->lscsa == NULL)
+ goto fail;
+
+ memset(csa->lscsa, 0, sizeof(struct spu_lscsa));
+
+ /* Set LS pages reserved to allow for user-space mapping.
+ *
+ * XXX isn't that a bit obsolete ? I think we should just
+ * make sure the page count is high enough. Anyway, won't harm
+ * for now
+ */
+ for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+ SetPageReserved(vmalloc_to_page(p));
+
+ pr_debug(" all good !\n");
+
+ return 0;
+fail:
+ pr_debug("spufs: failed to allocate lscsa 64K pages, falling back\n");
+ spu_free_lscsa(csa);
+ return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+ unsigned char *p;
+ int i;
+
+ if (!csa->use_big_pages) {
+ spu_free_lscsa_std(csa);
+ return;
+ }
+ csa->use_big_pages = 0;
+
+ if (csa->lscsa == NULL)
+ goto free_pages;
+
+ for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
+ ClearPageReserved(vmalloc_to_page(p));
+
+ vunmap(csa->lscsa);
+ csa->lscsa = NULL;
+
+ free_pages:
+
+ for (i = 0; i < SPU_LSCSA_NUM_BIG_PAGES; i++)
+ if (csa->lscsa_pages[i])
+ __free_pages(csa->lscsa_pages[i], SPU_64K_PAGE_ORDER);
+}
+
+#else /* CONFIG_SPU_FS_64K_LS */
+
+int spu_alloc_lscsa(struct spu_state *csa)
+{
+ return spu_alloc_lscsa_std(csa);
+}
+
+void spu_free_lscsa(struct spu_state *csa)
+{
+ spu_free_lscsa_std(csa);
+}
+
+#endif /* !defined(CONFIG_SPU_FS_64K_LS) */
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index f95a611ca36..57626600b1a 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -18,27 +18,6 @@ void spufs_stop_callback(struct spu *spu)
wake_up_all(&ctx->stop_wq);
}
-void spufs_dma_callback(struct spu *spu, int type)
-{
- struct spu_context *ctx = spu->ctx;
-
- if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
- ctx->event_return |= type;
- wake_up_all(&ctx->stop_wq);
- } else {
- switch (type) {
- case SPE_EVENT_DMA_ALIGNMENT:
- case SPE_EVENT_SPE_DATA_STORAGE:
- case SPE_EVENT_INVALID_DMA:
- force_sig(SIGBUS, /* info, */ current);
- break;
- case SPE_EVENT_SPE_ERROR:
- force_sig(SIGILL, /* info */ current);
- break;
- }
- }
-}
-
static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
{
struct spu *spu;
@@ -63,13 +42,18 @@ static int spu_setup_isolated(struct spu_context *ctx)
const u32 status_loading = SPU_STATUS_RUNNING
| SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS;
+ ret = -ENODEV;
if (!isolated_loader)
- return -ENODEV;
-
- ret = spu_acquire_exclusive(ctx);
- if (ret)
goto out;
+ /*
+ * We need to exclude userspace access to the context.
+ *
+ * To protect against memory access we invalidate all ptes
+ * and make sure the pagefault handlers block on the mutex.
+ */
+ spu_unmap_mappings(ctx);
+
mfc_cntl = &ctx->spu->priv2->mfc_control_RW;
/* purge the MFC DMA queue to ensure no spurious accesses before we
@@ -82,7 +66,7 @@ static int spu_setup_isolated(struct spu_context *ctx)
printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n",
__FUNCTION__);
ret = -EIO;
- goto out_unlock;
+ goto out;
}
cond_resched();
}
@@ -119,12 +103,15 @@ static int spu_setup_isolated(struct spu_context *ctx)
pr_debug("%s: isolated LOAD failed\n", __FUNCTION__);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
ret = -EACCES;
+ goto out_drop_priv;
+ }
- } else if (!(status & SPU_STATUS_ISOLATED_STATE)) {
+ if (!(status & SPU_STATUS_ISOLATED_STATE)) {
/* This isn't allowed by the CBEA, but check anyway */
pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP);
ret = -EINVAL;
+ goto out_drop_priv;
}
out_drop_priv:
@@ -132,30 +119,19 @@ out_drop_priv:
sr1 |= MFC_STATE1_PROBLEM_STATE_MASK;
spu_mfc_sr1_set(ctx->spu, sr1);
-out_unlock:
- spu_release(ctx);
out:
return ret;
}
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 * npc)
{
- int ret;
- unsigned long runcntl = SPU_RUNCNTL_RUNNABLE;
-
- ret = spu_acquire_runnable(ctx, 0);
- if (ret)
- return ret;
-
if (ctx->flags & SPU_CREATE_ISOLATE) {
+ unsigned long runcntl;
+
if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) {
- /* Need to release ctx, because spu_setup_isolated will
- * acquire it exclusively.
- */
- spu_release(ctx);
- ret = spu_setup_isolated(ctx);
- if (!ret)
- ret = spu_acquire_runnable(ctx, 0);
+ int ret = spu_setup_isolated(ctx);
+ if (ret)
+ return ret;
}
/* if userspace has set the runcntrl register (eg, to issue an
@@ -164,16 +140,17 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
(SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE);
if (runcntl == 0)
runcntl = SPU_RUNCNTL_RUNNABLE;
+ ctx->ops->runcntl_write(ctx, runcntl);
} else {
spu_start_tick(ctx);
ctx->ops->npc_write(ctx, *npc);
+ ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
}
- ctx->ops->runcntl_write(ctx, runcntl);
- return ret;
+ return 0;
}
-static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
+static int spu_run_fini(struct spu_context *ctx, u32 * npc,
u32 * status)
{
int ret = 0;
@@ -189,19 +166,27 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
return ret;
}
-static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
+static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
u32 *status)
{
int ret;
- if ((ret = spu_run_fini(ctx, npc, status)) != 0)
+ ret = spu_run_fini(ctx, npc, status);
+ if (ret)
return ret;
- if (*status & (SPU_STATUS_STOPPED_BY_STOP |
- SPU_STATUS_STOPPED_BY_HALT)) {
+
+ if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT))
return *status;
- }
- if ((ret = spu_run_init(ctx, npc)) != 0)
+
+ ret = spu_acquire_runnable(ctx, 0);
+ if (ret)
+ return ret;
+
+ ret = spu_run_init(ctx, npc);
+ if (ret) {
+ spu_release(ctx);
return ret;
+ }
return 0;
}
@@ -253,17 +238,17 @@ int spu_process_callback(struct spu_context *ctx)
{
struct spu_syscall_block s;
u32 ls_pointer, npc;
- char *ls;
+ void __iomem *ls;
long spu_ret;
int ret;
/* get syscall block from local store */
- npc = ctx->ops->npc_read(ctx);
- ls = ctx->ops->get_ls(ctx);
- ls_pointer = *(u32*)(ls + npc);
+ npc = ctx->ops->npc_read(ctx) & ~3;
+ ls = (void __iomem *)ctx->ops->get_ls(ctx);
+ ls_pointer = in_be32(ls + npc);
if (ls_pointer > (LS_SIZE - sizeof(s)))
return -EFAULT;
- memcpy(&s, ls + ls_pointer, sizeof (s));
+ memcpy_fromio(&s, ls + ls_pointer, sizeof(s));
/* do actual syscall without pinning the spu */
ret = 0;
@@ -283,7 +268,7 @@ int spu_process_callback(struct spu_context *ctx)
}
/* write result, jump over indirect pointer */
- memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
+ memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret));
ctx->ops->npc_write(ctx, npc);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
return ret;
@@ -292,11 +277,8 @@ int spu_process_callback(struct spu_context *ctx)
static inline int spu_process_events(struct spu_context *ctx)
{
struct spu *spu = ctx->spu;
- u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
int ret = 0;
- if (spu->dsisr & pte_fault)
- ret = spu_irq_class_1_bottom(spu);
if (spu->class_0_pending)
ret = spu_irq_class_0_bottom(spu);
if (!ret && signal_pending(current))
@@ -310,14 +292,21 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
int ret;
u32 status;
- if (down_interruptible(&ctx->run_sema))
+ if (mutex_lock_interruptible(&ctx->run_mutex))
return -ERESTARTSYS;
ctx->ops->master_start(ctx);
ctx->event_return = 0;
- ret = spu_run_init(ctx, npc);
+
+ ret = spu_acquire_runnable(ctx, 0);
if (ret)
+ return ret;
+
+ ret = spu_run_init(ctx, npc);
+ if (ret) {
+ spu_release(ctx);
goto out;
+ }
do {
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
@@ -330,6 +319,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
break;
status &= ~SPU_STATUS_STOPPED_BY_STOP;
}
+ ret = spufs_handle_class1(ctx);
+ if (ret)
+ break;
+
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
ret = spu_reacquire_runnable(ctx, npc, &status);
if (ret) {
@@ -363,6 +356,6 @@ out2:
out:
*event = ctx->event_return;
- up(&ctx->run_sema);
+ mutex_unlock(&ctx->run_mutex);
return ret;
}
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 39823cec084..b6ecb30e7d5 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -30,7 +30,6 @@
#include <linux/completion.h>
#include <linux/vmalloc.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/numa.h>
@@ -71,14 +70,27 @@ static inline int node_allowed(int node)
void spu_start_tick(struct spu_context *ctx)
{
- if (ctx->policy == SCHED_RR)
+ if (ctx->policy == SCHED_RR) {
+ /*
+ * Make sure the exiting bit is cleared.
+ */
+ clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
+ mb();
queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE);
+ }
}
void spu_stop_tick(struct spu_context *ctx)
{
- if (ctx->policy == SCHED_RR)
+ if (ctx->policy == SCHED_RR) {
+ /*
+ * While the work can be rearming normally setting this flag
+ * makes sure it does not rearm itself anymore.
+ */
+ set_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
+ mb();
cancel_delayed_work(&ctx->sched_work);
+ }
}
void spu_sched_tick(struct work_struct *work)
@@ -86,7 +98,15 @@ void spu_sched_tick(struct work_struct *work)
struct spu_context *ctx =
container_of(work, struct spu_context, sched_work.work);
struct spu *spu;
- int rearm = 1;
+ int preempted = 0;
+
+ /*
+ * If this context is being stopped avoid rescheduling from the
+ * scheduler tick because we would block on the state_mutex.
+ * The caller will yield the spu later on anyway.
+ */
+ if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags))
+ return;
mutex_lock(&ctx->state_mutex);
spu = ctx->spu;
@@ -94,12 +114,19 @@ void spu_sched_tick(struct work_struct *work)
int best = sched_find_first_bit(spu_prio->bitmap);
if (best <= ctx->prio) {
spu_deactivate(ctx);
- rearm = 0;
+ preempted = 1;
}
}
mutex_unlock(&ctx->state_mutex);
- if (rearm)
+ if (preempted) {
+ /*
+ * We need to break out of the wait loop in spu_run manually
+ * to ensure this context gets put on the runqueue again
+ * ASAP.
+ */
+ wake_up(&ctx->stop_wq);
+ } else
spu_start_tick(ctx);
}
@@ -208,58 +235,40 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
* spu_add_to_rq - add a context to the runqueue
* @ctx: context to add
*/
-static void spu_add_to_rq(struct spu_context *ctx)
+static void __spu_add_to_rq(struct spu_context *ctx)
{
- spin_lock(&spu_prio->runq_lock);
- list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
- set_bit(ctx->prio, spu_prio->bitmap);
- spin_unlock(&spu_prio->runq_lock);
-}
+ int prio = ctx->prio;
-/**
- * spu_del_from_rq - remove a context from the runqueue
- * @ctx: context to remove
- */
-static void spu_del_from_rq(struct spu_context *ctx)
-{
- spin_lock(&spu_prio->runq_lock);
- list_del_init(&ctx->rq);
- if (list_empty(&spu_prio->runq[ctx->prio]))
- clear_bit(ctx->prio, spu_prio->bitmap);
- spin_unlock(&spu_prio->runq_lock);
+ list_add_tail(&ctx->rq, &spu_prio->runq[prio]);
+ set_bit(prio, spu_prio->bitmap);
}
-/**
- * spu_grab_context - remove one context from the runqueue
- * @prio: priority of the context to be removed
- *
- * This function removes one context from the runqueue for priority @prio.
- * If there is more than one context with the given priority the first
- * task on the runqueue will be taken.
- *
- * Returns the spu_context it just removed.
- *
- * Must be called with spu_prio->runq_lock held.
- */
-static struct spu_context *spu_grab_context(int prio)
+static void __spu_del_from_rq(struct spu_context *ctx)
{
- struct list_head *rq = &spu_prio->runq[prio];
+ int prio = ctx->prio;
- if (list_empty(rq))
- return NULL;
- return list_entry(rq->next, struct spu_context, rq);
+ if (!list_empty(&ctx->rq))
+ list_del_init(&ctx->rq);
+ if (list_empty(&spu_prio->runq[prio]))
+ clear_bit(prio, spu_prio->bitmap);
}
static void spu_prio_wait(struct spu_context *ctx)
{
DEFINE_WAIT(wait);
+ spin_lock(&spu_prio->runq_lock);
prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE);
if (!signal_pending(current)) {
+ __spu_add_to_rq(ctx);
+ spin_unlock(&spu_prio->runq_lock);
mutex_unlock(&ctx->state_mutex);
schedule();
mutex_lock(&ctx->state_mutex);
+ spin_lock(&spu_prio->runq_lock);
+ __spu_del_from_rq(ctx);
}
+ spin_unlock(&spu_prio->runq_lock);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&ctx->stop_wq, &wait);
}
@@ -280,9 +289,14 @@ static void spu_reschedule(struct spu *spu)
spin_lock(&spu_prio->runq_lock);
best = sched_find_first_bit(spu_prio->bitmap);
if (best < MAX_PRIO) {
- struct spu_context *ctx = spu_grab_context(best);
- if (ctx)
- wake_up(&ctx->stop_wq);
+ struct list_head *rq = &spu_prio->runq[best];
+ struct spu_context *ctx;
+
+ BUG_ON(list_empty(rq));
+
+ ctx = list_entry(rq->next, struct spu_context, rq);
+ __spu_del_from_rq(ctx);
+ wake_up(&ctx->stop_wq);
}
spin_unlock(&spu_prio->runq_lock);
}
@@ -365,6 +379,12 @@ static struct spu *find_victim(struct spu_context *ctx)
}
spu_unbind_context(spu, victim);
mutex_unlock(&victim->state_mutex);
+ /*
+ * We need to break out of the wait loop in spu_run
+ * manually to ensure this context gets put on the
+ * runqueue again ASAP.
+ */
+ wake_up(&victim->stop_wq);
return spu;
}
}
@@ -377,7 +397,7 @@ static struct spu *find_victim(struct spu_context *ctx)
* @ctx: spu context to schedule
* @flags: flags (currently ignored)
*
- * Tries to find a free spu to run @ctx. If no free spu is availble
+ * Tries to find a free spu to run @ctx. If no free spu is available
* add the context to the runqueue so it gets woken up once an spu
* is available.
*/
@@ -402,9 +422,7 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
return 0;
}
- spu_add_to_rq(ctx);
spu_prio_wait(ctx);
- spu_del_from_rq(ctx);
} while (!signal_pending(current));
return -ERESTARTSYS;
@@ -438,7 +456,6 @@ void spu_deactivate(struct spu_context *ctx)
void spu_yield(struct spu_context *ctx)
{
struct spu *spu;
- int need_yield = 0;
if (mutex_trylock(&ctx->state_mutex)) {
if ((spu = ctx->spu) != NULL) {
@@ -447,13 +464,10 @@ void spu_yield(struct spu_context *ctx)
pr_debug("%s: yielding SPU %d NODE %d\n",
__FUNCTION__, spu->number, spu->node);
spu_deactivate(ctx);
- need_yield = 1;
}
}
mutex_unlock(&ctx->state_mutex);
}
- if (unlikely(need_yield))
- yield();
}
int __init spu_sched_init(void)
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 5c4e47d69d7..0a947fd7de5 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -41,7 +41,7 @@ struct spu_gang;
/* ctx->sched_flags */
enum {
- SPU_SCHED_WAKE = 0, /* currently unused */
+ SPU_SCHED_EXITING = 0,
};
struct spu_context {
@@ -50,16 +50,17 @@ struct spu_context {
spinlock_t mmio_lock; /* protects mmio access */
struct address_space *local_store; /* local store mapping. */
struct address_space *mfc; /* 'mfc' area mappings. */
- struct address_space *cntl; /* 'control' area mappings. */
- struct address_space *signal1; /* 'signal1' area mappings. */
- struct address_space *signal2; /* 'signal2' area mappings. */
- struct address_space *mss; /* 'mss' area mappings. */
- struct address_space *psmap; /* 'psmap' area mappings. */
+ struct address_space *cntl; /* 'control' area mappings. */
+ struct address_space *signal1; /* 'signal1' area mappings. */
+ struct address_space *signal2; /* 'signal2' area mappings. */
+ struct address_space *mss; /* 'mss' area mappings. */
+ struct address_space *psmap; /* 'psmap' area mappings. */
+ spinlock_t mapping_lock;
u64 object_id; /* user space pointer for oprofile */
enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
struct mutex state_mutex;
- struct semaphore run_sema;
+ struct mutex run_mutex;
struct mm_struct *owner;
@@ -140,6 +141,7 @@ struct spu_context_ops {
struct spu_dma_info * info);
void (*proxydma_info_read) (struct spu_context * ctx,
struct spu_proxydma_info * info);
+ void (*restart_dma)(struct spu_context *ctx);
};
extern struct spu_context_ops spu_hw_ops;
@@ -149,6 +151,7 @@ struct spufs_inode_info {
struct spu_context *i_ctx;
struct spu_gang *i_gang;
struct inode vfs_inode;
+ int i_openers;
};
#define SPUFS_I(inode) \
container_of(inode, struct spufs_inode_info, vfs_inode)
@@ -170,6 +173,9 @@ int put_spu_gang(struct spu_gang *gang);
void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx);
void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
+/* fault handling */
+int spufs_handle_class1(struct spu_context *ctx);
+
/* context management */
static inline void spu_acquire(struct spu_context *ctx)
{
@@ -190,7 +196,6 @@ void spu_unmap_mappings(struct spu_context *ctx);
void spu_forget(struct spu_context *ctx);
int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
void spu_acquire_saved(struct spu_context *ctx);
-int spu_acquire_exclusive(struct spu_context *ctx);
int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
@@ -218,14 +223,13 @@ extern char *isolated_loader;
prepare_to_wait(&(wq), &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
- if (!signal_pending(current)) { \
- spu_release(ctx); \
- schedule(); \
- spu_acquire(ctx); \
- continue; \
+ if (signal_pending(current)) { \
+ __ret = -ERESTARTSYS; \
+ break; \
} \
- __ret = -ERESTARTSYS; \
- break; \
+ spu_release(ctx); \
+ schedule(); \
+ spu_acquire(ctx); \
} \
finish_wait(&(wq), &__wait); \
__ret; \
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index fd91c73de34..71a0b41adb8 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -39,7 +39,6 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
@@ -2084,6 +2083,10 @@ int spu_save(struct spu_state *prev, struct spu *spu)
int rc;
acquire_spu_lock(spu); /* Step 1. */
+ prev->dar = spu->dar;
+ prev->dsisr = spu->dsisr;
+ spu->dar = 0;
+ spu->dsisr = 0;
rc = __do_spu_save(prev, spu); /* Steps 2-53. */
release_spu_lock(spu);
if (rc != 0 && rc != 2 && rc != 6) {
@@ -2109,9 +2112,9 @@ int spu_restore(struct spu_state *new, struct spu *spu)
acquire_spu_lock(spu);
harvest(NULL, spu);
- spu->dar = 0;
- spu->dsisr = 0;
spu->slb_replace = 0;
+ new->dar = 0;
+ new->dsisr = 0;
spu->class_0_pending = 0;
rc = __do_spu_restore(new, spu);
release_spu_lock(spu);
@@ -2185,40 +2188,30 @@ static void init_priv2(struct spu_state *csa)
* as it is by far the largest of the context save regions,
* and may need to be pinned or otherwise specially aligned.
*/
-void spu_init_csa(struct spu_state *csa)
+int spu_init_csa(struct spu_state *csa)
{
- struct spu_lscsa *lscsa;
- unsigned char *p;
+ int rc;
if (!csa)
- return;
+ return -EINVAL;
memset(csa, 0, sizeof(struct spu_state));
- lscsa = vmalloc(sizeof(struct spu_lscsa));
- if (!lscsa)
- return;
+ rc = spu_alloc_lscsa(csa);
+ if (rc)
+ return rc;
- memset(lscsa, 0, sizeof(struct spu_lscsa));
- csa->lscsa = lscsa;
spin_lock_init(&csa->register_lock);
- /* Set LS pages reserved to allow for user-space mapping. */
- for (p = lscsa->ls; p < lscsa->ls + LS_SIZE; p += PAGE_SIZE)
- SetPageReserved(vmalloc_to_page(p));
-
init_prob(csa);
init_priv1(csa);
init_priv2(csa);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(spu_init_csa);
void spu_fini_csa(struct spu_state *csa)
{
- /* Clear reserved bit before vfree. */
- unsigned char *p;
- for (p = csa->lscsa->ls; p < csa->lscsa->ls + LS_SIZE; p += PAGE_SIZE)
- ClearPageReserved(vmalloc_to_page(p));
-
- vfree(csa->lscsa);
+ spu_free_lscsa(csa);
}
EXPORT_SYMBOL_GPL(spu_fini_csa);
diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig
new file mode 100644
index 00000000000..2db1e293433
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/Kconfig
@@ -0,0 +1,9 @@
+config PPC_CELLEB
+ bool "Toshiba's Cell Reference Set 'Celleb' Architecture"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL
+ select PPC_OF_PLATFORM_PCI
+ select HAS_TXX9_SERIAL
+ select PPC_UDBG_BEAT
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_EHCI_BIG_ENDIAN_MMIO
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
index f63b94c6535..755d869d855 100644
--- a/arch/powerpc/platforms/celleb/iommu.c
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -37,7 +37,7 @@ static int __init find_dma_window(u64 *io_space_id, u64 *ioid,
const unsigned long *dma_window;
for_each_node_by_type(dn, "ioif") {
- dma_window = get_property(dn, "toshiba,dma-window", NULL);
+ dma_window = of_get_property(dn, "toshiba,dma-window", NULL);
if (dma_window) {
*io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
*ioid = dma_window[0] & 0x7ffUL;
@@ -80,7 +80,7 @@ static int celleb_of_bus_notify(struct notifier_block *nb,
if (action != BUS_NOTIFY_ADD_DEVICE)
return 0;
- dev->archdata.dma_ops = pci_dma_ops;
+ dev->archdata.dma_ops = get_pci_dma_ops();
return 0;
}
@@ -95,7 +95,7 @@ static int __init celleb_init_iommu(void)
return -ENODEV;
celleb_init_direct_mapping();
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
return 0;
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
index 98de836dfed..d1adf34cd5e 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -309,13 +309,13 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
goto error;
}
- name = get_property(node, "model", &rlen);
+ name = of_get_property(node, "model", &rlen);
if (!name) {
printk(KERN_ERR "PCI: model property not found.\n");
goto error;
}
- wi4 = get_property(node, "reg", &rlen);
+ wi4 = of_get_property(node, "reg", &rlen);
if (wi4 == NULL)
goto error;
@@ -352,10 +352,10 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
}
pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
- wi0 = get_property(node, "device-id", NULL);
- wi1 = get_property(node, "vendor-id", NULL);
- wi2 = get_property(node, "class-code", NULL);
- wi3 = get_property(node, "revision-id", NULL);
+ wi0 = of_get_property(node, "device-id", NULL);
+ wi1 = of_get_property(node, "vendor-id", NULL);
+ wi2 = of_get_property(node, "class-code", NULL);
+ wi3 = of_get_property(node, "revision-id", NULL);
celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
@@ -376,7 +376,7 @@ static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
- li = get_property(node, "interrupts", &rlen);
+ li = of_get_property(node, "interrupts", &rlen);
val = li[0];
celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
@@ -424,7 +424,7 @@ static int __devinit phb_set_bus_ranges(struct device_node *dev,
const int *bus_range;
unsigned int len;
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
return 1;
@@ -451,7 +451,7 @@ int __devinit celleb_setup_phb(struct pci_controller *phb)
struct device_node *node;
unsigned int rlen;
- name = get_property(dev, "name", &rlen);
+ name = of_get_property(dev, "name", &rlen);
if (!name)
return 1;
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
index 5f4d0d93323..596ab2a788d 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -67,7 +67,7 @@ static void celleb_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
/* using "CHRP" is to trick anaconda into installing FCx into Celleb */
seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
of_node_put(root);
@@ -128,15 +128,6 @@ static int __init celleb_probe(void)
return 1;
}
-/*
- * Cell has no legacy IO; anything calling this function has to
- * fail or bad things will happen
- */
-static int celleb_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
#ifdef CONFIG_KEXEC
static void celleb_kexec_cpu_down(int crash, int secondary)
{
@@ -173,7 +164,6 @@ define_machine(celleb) {
.get_rtc_time = beat_get_rtc_time,
.set_rtc_time = beat_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
- .check_legacy_ioport = celleb_check_legacy_ioport,
.progress = celleb_progress,
.power_save = beat_power_save,
.nvram_size = beat_nvram_get_size,
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig
new file mode 100644
index 00000000000..d2c69053196
--- /dev/null
+++ b/arch/powerpc/platforms/chrp/Kconfig
@@ -0,0 +1,11 @@
+config PPC_CHRP
+ bool "Common Hardware Reference Platform (CHRP) based machines"
+ depends on PPC_MULTIPLATFORM && PPC32
+ select MPIC
+ select PPC_I8259
+ select PPC_INDIRECT_PCI
+ select PPC_RTAS
+ select PPC_MPC106
+ select PPC_UDBG_16550
+ select PPC_NATIVE
+ default y
diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c
index 0dd4a64757d..8efd4244701 100644
--- a/arch/powerpc/platforms/chrp/nvram.c
+++ b/arch/powerpc/platforms/chrp/nvram.c
@@ -74,7 +74,7 @@ void __init chrp_nvram_init(void)
if (nvram == NULL)
return;
- nbytes_p = get_property(nvram, "#bytes", &proplen);
+ nbytes_p = of_get_property(nvram, "#bytes", &proplen);
if (nbytes_p == NULL || proplen != sizeof(unsigned int))
return;
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
index ddb4a116ea8..d32fedc991d 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -7,7 +7,6 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/ide.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -137,9 +136,11 @@ hydra_init(void)
struct device_node *np;
struct resource r;
- np = find_devices("mac-io");
- if (np == NULL || of_address_to_resource(np, 0, &r))
+ np = of_find_node_by_name(NULL, "mac-io");
+ if (np == NULL || of_address_to_resource(np, 0, &r)) {
+ of_node_put(np);
return 0;
+ }
Hydra = ioremap(r.start, r.end-r.start);
printk("Hydra Mac I/O at %llx\n", (unsigned long long)r.start);
printk("Hydra Feature_Control was %x",
@@ -186,10 +187,9 @@ setup_python(struct pci_controller *hose, struct device_node *dev)
/* Marvell Discovery II based Pegasos 2 */
static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev)
{
- struct device_node *root = find_path_device("/");
+ struct device_node *root = of_find_node_by_path("/");
struct device_node *rtas;
- of_node_get(root);
rtas = of_find_node_by_name (root, "rtas");
if (rtas) {
hose->ops = &rtas_pci_ops;
@@ -199,6 +199,7 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d
" your firmware\n");
}
pci_assign_all_buses = 1;
+ /* keep the reference to the root node */
}
void __init
@@ -211,14 +212,14 @@ chrp_find_bridges(void)
const unsigned int *dma;
const char *model, *machine;
int is_longtrail = 0, is_mot = 0, is_pegasos = 0;
- struct device_node *root = find_path_device("/");
+ struct device_node *root = of_find_node_by_path("/");
struct resource r;
/*
* The PCI host bridge nodes on some machines don't have
* properties to adequately identify them, so we have to
* look at what sort of machine this is as well.
*/
- machine = get_property(root, "model", NULL);
+ machine = of_get_property(root, "model", NULL);
if (machine != NULL) {
is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0;
is_mot = strncmp(machine, "MOT", 3) == 0;
@@ -237,7 +238,7 @@ chrp_find_bridges(void)
dev->full_name);
continue;
}
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s\n",
dev->full_name);
@@ -263,10 +264,10 @@ chrp_find_bridges(void)
hose->first_busno = bus_range[0];
hose->last_busno = bus_range[1];
- model = get_property(dev, "model", NULL);
+ model = of_get_property(dev, "model", NULL);
if (model == NULL)
model = "<none>";
- if (device_is_compatible(dev, "IBM,python")) {
+ if (of_device_is_compatible(dev, "IBM,python")) {
setup_python(hose, dev);
} else if (is_mot
|| strncmp(model, "Motorola, Grackle", 17) == 0) {
@@ -285,7 +286,8 @@ chrp_find_bridges(void)
r.start + 0x000f8000,
r.start + 0x000f8010);
if (index == 0) {
- dma = get_property(dev, "system-dma-base",&len);
+ dma = of_get_property(dev, "system-dma-base",
+ &len);
if (dma && len >= sizeof(*dma)) {
dma = (unsigned int *)
(((unsigned long)dma) +
@@ -303,12 +305,13 @@ chrp_find_bridges(void)
/* check the first bridge for a property that we can
use to set pci_dram_offset */
- dma = get_property(dev, "ibm,dma-ranges", &len);
+ dma = of_get_property(dev, "ibm,dma-ranges", &len);
if (index == 0 && dma != NULL && len >= 6 * sizeof(*dma)) {
pci_dram_offset = dma[2] - dma[3];
printk("pci_dram_offset = %lx\n", pci_dram_offset);
}
}
+ of_node_put(root);
}
/* SL82C105 IDE Control/Status Register */
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 117c9a0055b..373de4c063d 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -28,7 +28,6 @@
#include <linux/adb.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/ide.h>
#include <linux/console.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
@@ -111,9 +110,9 @@ void chrp_show_cpuinfo(struct seq_file *m)
struct device_node *root;
const char *model = "";
- root = find_path_device("/");
+ root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: CHRP %s\n", model);
/* longtrail (goldengate) stuff */
@@ -161,6 +160,7 @@ void chrp_show_cpuinfo(struct seq_file *m)
gg2_cachetypes[(t>>2) & 3],
gg2_cachemodes[t & 3]);
}
+ of_node_put(root);
}
/*
@@ -205,13 +205,15 @@ static void __init sio_init(void)
{
struct device_node *root;
- if ((root = find_path_device("/")) &&
- !strncmp(get_property(root, "model", NULL), "IBM,LongTrail", 13)) {
+ if ((root = of_find_node_by_path("/")) &&
+ !strncmp(of_get_property(root, "model", NULL),
+ "IBM,LongTrail", 13)) {
/* logical device 0 (KBC/Keyboard) */
sio_fixup_irq("keyboard", 0, 1, 2);
/* select logical device 1 (KBC/Mouse) */
sio_fixup_irq("mouse", 1, 12, 2);
}
+ of_node_put(root);
}
@@ -224,12 +226,12 @@ static void __init pegasos_set_l2cr(void)
return;
/* Enable L2 cache if needed */
- np = find_type_devices("cpu");
+ np = of_find_node_by_type(NULL, "cpu");
if (np != NULL) {
- const unsigned int *l2cr = get_property(np, "l2cr", NULL);
+ const unsigned int *l2cr = of_get_property(np, "l2cr", NULL);
if (l2cr == NULL) {
printk ("Pegasos l2cr : no cpu l2cr property found\n");
- return;
+ goto out;
}
if (!((*l2cr) & 0x80000000)) {
printk ("Pegasos l2cr : L2 cache was not active, "
@@ -238,6 +240,8 @@ static void __init pegasos_set_l2cr(void)
_set_L2CR((*l2cr) | 0x80000000);
}
}
+out:
+ of_node_put(np);
}
static void briq_restart(char *cmd)
@@ -250,14 +254,14 @@ static void briq_restart(char *cmd)
void __init chrp_setup_arch(void)
{
- struct device_node *root = find_path_device ("/");
+ struct device_node *root = of_find_node_by_path("/");
const char *machine = NULL;
/* init to some ~sane value until calibrate_delay() runs */
loops_per_jiffy = 50000000/HZ;
if (root)
- machine = get_property(root, "model", NULL);
+ machine = of_get_property(root, "model", NULL);
if (machine && strncmp(machine, "Pegasos", 7) == 0) {
_chrp_type = _CHRP_Pegasos;
} else if (machine && strncmp(machine, "IBM", 3) == 0) {
@@ -273,6 +277,7 @@ void __init chrp_setup_arch(void)
/* Let's assume it is an IBM chrp if all else fails */
_chrp_type = _CHRP_IBM;
}
+ of_node_put(root);
printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]);
rtas_initialize();
@@ -361,8 +366,8 @@ static void __init chrp_find_openpic(void)
return;
root = of_find_node_by_path("/");
if (root) {
- opprop = get_property(root, "platform-open-pic", &oplen);
- na = prom_n_addr_cells(root);
+ opprop = of_get_property(root, "platform-open-pic", &oplen);
+ na = of_n_addr_cells(root);
}
if (opprop && oplen >= na * sizeof(unsigned int)) {
opaddr = opprop[na-1]; /* assume 32-bit */
@@ -378,7 +383,7 @@ static void __init chrp_find_openpic(void)
printk(KERN_INFO "OpenPIC at %lx\n", opaddr);
- iranges = get_property(np, "interrupt-ranges", &len);
+ iranges = of_get_property(np, "interrupt-ranges", &len);
if (iranges == NULL)
len = 0; /* non-distributed mpic */
else
@@ -427,7 +432,7 @@ static void __init chrp_find_openpic(void)
of_node_put(np);
}
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
static struct irqaction xmon_irqaction = {
.handler = xmon_irq,
.mask = CPU_MASK_NONE,
@@ -443,7 +448,7 @@ static void __init chrp_find_8259(void)
/* Look for cascade */
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "chrp,iic")) {
+ if (of_device_is_compatible(np, "chrp,iic")) {
pic = np;
break;
}
@@ -463,15 +468,16 @@ static void __init chrp_find_8259(void)
* Also, Pegasos-type platforms don't have a proper node to start
* from anyway
*/
- for (np = find_devices("pci"); np != NULL; np = np->next) {
- const unsigned int *addrp = get_property(np,
+ for_each_node_by_name(np, "pci") {
+ const unsigned int *addrp = of_get_property(np,
"8259-interrupt-acknowledge", NULL);
if (addrp == NULL)
continue;
- chrp_int_ack = addrp[prom_n_addr_cells(np)-1];
+ chrp_int_ack = addrp[of_n_addr_cells(np)-1];
break;
}
+ of_node_put(np);
if (np == NULL)
printk(KERN_WARNING "Cannot find PCI interrupt acknowledge"
" address, polling\n");
@@ -493,7 +499,7 @@ static void __init chrp_find_8259(void)
void __init chrp_init_IRQ(void)
{
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
struct device_node *kbd;
#endif
chrp_find_openpic();
@@ -510,13 +516,14 @@ void __init chrp_init_IRQ(void)
if (_chrp_type == _CHRP_Pegasos)
ppc_md.get_irq = i8259_irq;
-#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON)
+#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON)
/* see if there is a keyboard in the device tree
with a parent of type "adb" */
- for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
+ for_each_node_by_name(kbd, "keyboard")
if (kbd->parent && kbd->parent->type
&& strcmp(kbd->parent->type, "adb") == 0)
break;
+ of_node_put(kbd);
if (kbd)
setup_irq(HYDRA_INT_ADB_NMI, &xmon_irqaction);
#endif
@@ -542,9 +549,9 @@ chrp_init2(void)
/* Get the event scan rate for the rtas so we know how
* often it expects a heartbeat. -- Cort
*/
- device = find_devices("rtas");
+ device = of_find_node_by_name(NULL, "rtas");
if (device)
- p = get_property(device, "rtas-event-scan-rate", NULL);
+ p = of_get_property(device, "rtas-event-scan-rate", NULL);
if (p && *p) {
/*
* Arrange to call chrp_event_scan at least *p times
@@ -571,6 +578,7 @@ chrp_init2(void)
printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
*p, interval);
}
+ of_node_put(device);
if (ppc_md.progress)
ppc_md.progress(" Have fun! ", 0x7777);
diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c
index 1d2307e87c3..3ea0eb78568 100644
--- a/arch/powerpc/platforms/chrp/smp.c
+++ b/arch/powerpc/platforms/chrp/smp.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 7d788902693..96d1e4b3c49 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -39,12 +39,17 @@ long __init chrp_time_init(void)
struct resource r;
int base;
- rtcs = find_compatible_devices("rtc", "pnpPNP,b00");
+ rtcs = of_find_compatible_node(NULL, "rtc", "pnpPNP,b00");
if (rtcs == NULL)
- rtcs = find_compatible_devices("rtc", "ds1385-rtc");
- if (rtcs == NULL || of_address_to_resource(rtcs, 0, &r))
+ rtcs = of_find_compatible_node(NULL, "rtc", "ds1385-rtc");
+ if (rtcs == NULL)
+ return 0;
+ if (of_address_to_resource(rtcs, 0, &r)) {
+ of_node_put(rtcs);
return 0;
-
+ }
+ of_node_put(rtcs);
+
base = r.start;
nvram_as1 = 0;
nvram_as0 = base;
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index 3410bcbc9db..8f3c2a73e16 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -2,78 +2,6 @@ choice
prompt "Machine Type"
depends on EMBEDDED6xx
-config KATANA
- bool "Artesyn-Katana"
- help
- Select KATANA if configuring an Artesyn KATANA 750i or 3750
- cPCI board.
-
-config WILLOW
- bool "Cogent-Willow"
-
-config CPCI690
- bool "Force-CPCI690"
- help
- Select CPCI690 if configuring a Force CPCI690 cPCI board.
-
-config POWERPMC250
- bool "Force-PowerPMC250"
-
-config CHESTNUT
- bool "IBM 750FX Eval board or 750GX Eval board"
- help
- Select CHESTNUT if configuring an IBM 750FX Eval Board or a
- IBM 750GX Eval board.
-
-config SPRUCE
- bool "IBM-Spruce"
- select PPC_INDIRECT_PCI
-
-config HDPU
- bool "Sky-HDPU"
- help
- Select HDPU if configuring a Sky Computers Compute Blade.
-
-config HDPU_FEATURES
- depends on HDPU
- tristate "HDPU-Features"
- help
- Select to enable HDPU enhanced features.
-
-config EV64260
- bool "Marvell-EV64260BP"
- help
- Select EV64260 if configuring a Marvell (formerly Galileo)
- EV64260BP Evaluation platform.
-
-config LOPEC
- bool "Motorola-LoPEC"
- select PPC_I8259
-
-config MVME5100
- bool "Motorola-MVME5100"
- select PPC_INDIRECT_PCI
-
-config PPLUS
- bool "Motorola-PowerPlus"
- select PPC_I8259
- select PPC_INDIRECT_PCI
-
-config PRPMC750
- bool "Motorola-PrPMC750"
- select PPC_INDIRECT_PCI
-
-config PRPMC800
- bool "Motorola-PrPMC800"
- select PPC_INDIRECT_PCI
-
-config SANDPOINT
- bool "Motorola-Sandpoint"
- select PPC_I8259
- help
- Select SANDPOINT if configuring for a Motorola Sandpoint X3
- (any flavor).
-
config LINKSTATION
bool "Linkstation / Kurobox(HG) from Buffalo"
select MPIC
@@ -92,217 +20,37 @@ config MPC7448HPC2
select TSI108_BRIDGE
select DEFAULT_UIMAGE
select PPC_UDBG_16550
- select MPIC
- select MPIC_WEIRD
help
Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
platform
-config RADSTONE_PPC7D
- bool "Radstone Technology PPC7D board"
- select PPC_I8259
-
-config PAL4
- bool "SBS-Palomar4"
-
-config EST8260
- bool "EST8260"
- ---help---
- The EST8260 is a single-board computer manufactured by Wind River
- Systems, Inc. (formerly Embedded Support Tools Corp.) and based on
- the MPC8260. Wind River Systems has a website at
- <http://www.windriver.com/>, but the EST8260 cannot be found on it
- and has probably been discontinued or rebadged.
-
-config SBC82xx
- bool "SBC82xx"
- ---help---
- SBC PowerQUICC II, single-board computer with MPC82xx CPU
- Manufacturer: Wind River Systems, Inc.
- Date of Release: May 2003
- End of Life: -
- URL: <http://www.windriver.com/>
-
-config SBS8260
- bool "SBS8260"
-
-config RPX8260
- bool "RPXSUPER"
-
-config TQM8260
- bool "TQM8260"
- ---help---
- MPC8260 based module, little larger than credit card,
- up to 128 MB global + 64 MB local RAM, 32 MB Flash,
- 32 kB EEPROM, 256 kB L@ Cache, 10baseT + 100baseT Ethernet,
- 2 x serial ports, ...
- Manufacturer: TQ Components, www.tq-group.de
- Date of Release: June 2001
- End of Life: not yet :-)
- URL: <http://www.denx.de/PDF/TQM82xx_SPEC_Rev005.pdf>
-
-config ADS8272
- bool "ADS8272"
-
-config PQ2FADS
- bool "Freescale-PQ2FADS"
- help
- Select PQ2FADS if you wish to configure for a Freescale
- PQ2FADS board (-VR or -ZU).
-
-config EV64360
- bool "Marvell-EV64360BP"
+config PPC_HOLLY
+ bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)"
+ select TSI108_BRIDGE
+ select PPC_UDBG_16550
help
- Select EV64360 if configuring a Marvell EV64360BP Evaluation
- platform.
+ Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
+ Board with TSI108/9 bridge (Hickory/Holly)
endchoice
-config PQ2ADS
- bool
- depends on ADS8272
- default y
-
-config TQM8xxL
- bool
- depends on 8xx && (TQM823L || TQM850L || FPS850L || TQM855L || TQM860L)
- default y
-
-config 8260
- bool "CPM2 Support" if WILLOW
- depends on 6xx
- default y if TQM8260 || RPX8260 || EST8260 || SBS8260 || SBC82xx || PQ2FADS
- help
- The MPC8260 is a typical embedded CPU made by Motorola. Selecting
- this option means that you wish to build a kernel for a machine with
- an 8260 class CPU.
-
-config 8272
- bool
- depends on 6xx
- default y if ADS8272
- select 8260
- help
- The MPC8272 CPM has a different internal dpram setup than other CPM2
- devices
-
-config CPM2
- bool
- depends on 8260 || MPC8560 || MPC8555
- default y
- help
- The CPM2 (Communications Processor Module) is a coprocessor on
- embedded CPUs made by Motorola. Selecting this option means that
- you wish to build a kernel for a machine with a CPM2 coprocessor
- on it (826x, 827x, 8560).
-
-config PPC_GEN550
- bool
- depends on SANDPOINT || SPRUCE || PPLUS || \
- PRPMC750 || PRPMC800 || LOPEC || \
- (EV64260 && !SERIAL_MPSC) || CHESTNUT || RADSTONE_PPC7D || \
- 83xx || LINKSTATION
- default y
-
-config FORCE
- bool
- depends on 6xx && POWERPMC250
- default y
-
-config GT64260
- bool
- depends on EV64260 || CPCI690
- default y
-
-config MV64360 # Really MV64360 & MV64460
- bool
- depends on CHESTNUT || KATANA || RADSTONE_PPC7D || HDPU || EV64360
- default y
-
-config MV64X60
- bool
- depends on (GT64260 || MV64360)
- select PPC_INDIRECT_PCI
- default y
-
config TSI108_BRIDGE
bool
- depends on MPC7448HPC2
- default y
-
-menu "Set bridge options"
- depends on MV64X60
-
-config NOT_COHERENT_CACHE
- bool "Turn off Cache Coherency"
- default n
- help
- Some 64x60 bridges lock up when trying to enforce cache coherency.
- When this option is selected, cache coherency will be turned off.
- Note that this can cause other problems (e.g., stale data being
- speculatively loaded via a cached mapping). Use at your own risk.
-
-config MV64X60_BASE
- hex "Set bridge base used by firmware"
- default "0xf1000000"
- help
- A firmware can leave the base address of the bridge's registers at
- a non-standard location. If so, set this value to reflect the
- address of that non-standard location.
-
-config MV64X60_NEW_BASE
- hex "Set bridge base used by kernel"
- default "0xf1000000"
- help
- If the current base address of the bridge's registers is not where
- you want it, set this value to the address that you want it moved to.
-
-endmenu
-
-config NONMONARCH_SUPPORT
- bool "Enable Non-Monarch Support"
- depends on PRPMC800
-
-config HARRIER
- bool
- depends on PRPMC800
- default y
-
-config EPIC_SERIAL_MODE
- bool
- depends on 6xx && (LOPEC || SANDPOINT)
+ depends on MPC7448HPC2 || PPC_HOLLY
+ select MPIC
+ select MPIC_WEIRD
default y
config MPC10X_BRIDGE
bool
- depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
+ depends on LINKSTATION
select PPC_INDIRECT_PCI
default y
config MPC10X_OPENPIC
bool
- depends on POWERPMC250 || LOPEC || SANDPOINT || LINKSTATION
+ depends on LINKSTATION
default y
config MPC10X_STORE_GATHERING
bool "Enable MPC10x store gathering"
depends on MPC10X_BRIDGE
-
-config SANDPOINT_ENABLE_UART1
- bool "Enable DUART mode on Sandpoint"
- depends on SANDPOINT
- help
- If this option is enabled then the MPC824x processor will run
- in DUART mode instead of UART mode.
-
-config HARRIER_STORE_GATHERING
- bool "Enable Harrier store gathering"
- depends on HARRIER
-
-config MVME5100_IPMC761_PRESENT
- bool "MVME5100 configured with an IPMC761"
- depends on MVME5100
- select PPC_I8259
-
-config SPRUCE_BAUD_33M
- bool "Spruce baud clock support"
- depends on SPRUCE
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile
index d3d11a3cd65..b39fe4f470d 100644
--- a/arch/powerpc/platforms/embedded6xx/Makefile
+++ b/arch/powerpc/platforms/embedded6xx/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o
obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o
+obj-$(CONFIG_PPC_HOLLY) += holly.o
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
new file mode 100644
index 00000000000..3a0b4a01401
--- /dev/null
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -0,0 +1,317 @@
+/*
+ * Board setup routines for the IBM 750GX/CL platform w/ TSI10x bridge
+ *
+ * Copyright 2007 IBM Corporation
+ *
+ * Stephen Winiecki <stevewin@us.ibm.com>
+ * Josh Boyer <jwboyer@linux.vnet.ibm.com>
+ *
+ * Based on code from mpc7448_hpc2.c
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/ide.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/tsi108.h>
+#include <asm/pci-bridge.h>
+#include <asm/reg.h>
+#include <mm/mmu_decl.h>
+#include <asm/tsi108_irq.h>
+#include <asm/tsi108_pci.h>
+#include <asm/mpic.h>
+#include <asm/of_platform.h>
+
+#undef DEBUG
+
+#define HOLLY_PCI_CFG_PHYS 0x7c000000
+
+int holly_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static void holly_remap_bridge(void)
+{
+ u32 lut_val, lut_addr;
+ int i;
+
+ printk(KERN_INFO "Remapping PCI bridge\n");
+
+ /* Re-init the PCI bridge and LUT registers to have mappings that don't
+ * rely on PIBS
+ */
+ lut_addr = 0x900;
+ for (i = 0; i < 31; i++) {
+ tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000201);
+ lut_addr += 4;
+ tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
+ lut_addr += 4;
+ }
+
+ /* Reserve the last LUT entry for PCI I/O space */
+ tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000241);
+ lut_addr += 4;
+ tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
+
+ /* Map PCI I/O space */
+ tsi108_write_reg(TSI108_PCI_PFAB_IO_UPPER, 0x0);
+ tsi108_write_reg(TSI108_PCI_PFAB_IO, 0x1);
+
+ /* Map PCI CFG space */
+ tsi108_write_reg(TSI108_PCI_PFAB_BAR0_UPPER, 0x0);
+ tsi108_write_reg(TSI108_PCI_PFAB_BAR0, 0x7c000000 | 0x01);
+
+ /* We don't need MEM32 and PRM remapping so disable them */
+ tsi108_write_reg(TSI108_PCI_PFAB_MEM32, 0x0);
+ tsi108_write_reg(TSI108_PCI_PFAB_PFM3, 0x0);
+ tsi108_write_reg(TSI108_PCI_PFAB_PFM4, 0x0);
+
+ /* Set P2O_BAR0 */
+ tsi108_write_reg(TSI108_PCI_P2O_BAR0_UPPER, 0x0);
+ tsi108_write_reg(TSI108_PCI_P2O_BAR0, 0xc0000000);
+
+ /* Init the PCI LUTs to do no remapping */
+ lut_addr = 0x500;
+ lut_val = 0x00000002;
+
+ for (i = 0; i < 32; i++) {
+ tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, lut_val);
+ lut_addr += 4;
+ tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, 0x40000000);
+ lut_addr += 4;
+ lut_val += 0x02000000;
+ }
+ tsi108_write_reg(TSI108_PCI_P2O_PAGE_SIZES, 0x00007900);
+
+ /* Set 64-bit PCI bus address for system memory */
+ tsi108_write_reg(TSI108_PCI_P2O_BAR2_UPPER, 0x0);
+ tsi108_write_reg(TSI108_PCI_P2O_BAR2, 0x0);
+}
+
+static void __init holly_setup_arch(void)
+{
+ struct device_node *cpu;
+ struct device_node *np;
+
+ if (ppc_md.progress)
+ ppc_md.progress("holly_setup_arch():set_bridge", 0);
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (cpu) {
+ const unsigned int *fp;
+
+ fp = of_get_property(cpu, "clock-frequency", NULL);
+ if (fp)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(cpu);
+ }
+ tsi108_csr_vir_base = get_vir_csrbase();
+
+ /* setup PCI host bridge */
+ holly_remap_bridge();
+
+ np = of_find_node_by_type(NULL, "pci");
+ if (np)
+ tsi108_setup_pci(np, HOLLY_PCI_CFG_PHYS, 1);
+
+ ppc_md.pci_exclude_device = holly_exclude_device;
+ if (ppc_md.progress)
+ ppc_md.progress("tsi108: resources set", 0x100);
+
+ printk(KERN_INFO "PPC750GX/CL Platform\n");
+}
+
+/*
+ * Interrupt setup and service. Interrrupts on the holly come
+ * from the four external INT pins, PCI interrupts are routed via
+ * PCI interrupt control registers, it generates internal IRQ23
+ *
+ * Interrupt routing on the Holly Board:
+ * TSI108:PB_INT[0] -> CPU0:INT#
+ * TSI108:PB_INT[1] -> CPU0:MCP#
+ * TSI108:PB_INT[2] -> N/C
+ * TSI108:PB_INT[3] -> N/C
+ */
+static void __init holly_init_IRQ(void)
+{
+ struct mpic *mpic;
+ phys_addr_t mpic_paddr = 0;
+ struct device_node *tsi_pic;
+#ifdef CONFIG_PCI
+ unsigned int cascade_pci_irq;
+ struct device_node *tsi_pci;
+ struct device_node *cascade_node = NULL;
+#endif
+
+ tsi_pic = of_find_node_by_type(NULL, "open-pic");
+ if (tsi_pic) {
+ unsigned int size;
+ const void *prop = of_get_property(tsi_pic, "reg", &size);
+ mpic_paddr = of_translate_address(tsi_pic, prop);
+ }
+
+ if (mpic_paddr == 0) {
+ printk(KERN_ERR "%s: No tsi108 PIC found !\n", __func__);
+ return;
+ }
+
+ pr_debug("%s: tsi108 pic phys_addr = 0x%x\n", __func__, (u32) mpic_paddr);
+
+ mpic = mpic_alloc(tsi_pic, mpic_paddr,
+ MPIC_PRIMARY | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET |
+ MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
+ 24,
+ NR_IRQS-4, /* num_sources used */
+ "Tsi108_PIC");
+
+ BUG_ON(mpic == NULL);
+
+ mpic_assign_isu(mpic, 0, mpic_paddr + 0x100);
+
+ mpic_init(mpic);
+
+#ifdef CONFIG_PCI
+ tsi_pci = of_find_node_by_type(NULL, "pci");
+ if (tsi_pci == NULL) {
+ printk(KERN_ERR "%s: No tsi108 pci node found !\n", __func__);
+ return;
+ }
+
+ cascade_node = of_find_node_by_type(NULL, "pic-router");
+ if (cascade_node == NULL) {
+ printk(KERN_ERR "%s: No tsi108 pci cascade node found !\n", __func__);
+ return;
+ }
+
+ cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0);
+ pr_debug("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq);
+ tsi108_pci_int_init(cascade_node);
+ set_irq_data(cascade_pci_irq, mpic);
+ set_irq_chained_handler(cascade_pci_irq, tsi108_irq_cascade);
+#endif
+ /* Configure MPIC outputs to CPU0 */
+ tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
+ of_node_put(tsi_pic);
+}
+
+void holly_show_cpuinfo(struct seq_file *m)
+{
+ seq_printf(m, "vendor\t\t: IBM\n");
+ seq_printf(m, "machine\t\t: PPC750 GX/CL\n");
+}
+
+void holly_restart(char *cmd)
+{
+ __be32 __iomem *ocn_bar1 = NULL;
+ unsigned long bar;
+ struct device_node *bridge = NULL;
+ const void *prop;
+ int size;
+ phys_addr_t addr = 0xc0000000;
+
+ local_irq_disable();
+
+ bridge = of_find_node_by_type(NULL, "tsi-bridge");
+ if (bridge) {
+ prop = of_get_property(bridge, "reg", &size);
+ addr = of_translate_address(bridge, prop);
+ }
+ addr += (TSI108_PB_OFFSET + 0x414);
+
+ ocn_bar1 = ioremap(addr, 0x4);
+
+ /* Turn on the BOOT bit so the addresses are correctly
+ * routed to the HLP interface */
+ bar = ioread32be(ocn_bar1);
+ bar |= 2;
+ iowrite32be(bar, ocn_bar1);
+ iosync();
+
+ /* Set SRR0 to the reset vector and turn on MSR_IP */
+ mtspr(SPRN_SRR0, 0xfff00100);
+ mtspr(SPRN_SRR1, MSR_IP);
+
+ /* Do an rfi to jump back to firmware. Somewhat evil,
+ * but it works
+ */
+ __asm__ __volatile__("rfi" : : : "memory");
+
+ /* Spin until reset happens. Shouldn't really get here */
+ for (;;) ;
+}
+
+void holly_power_off(void)
+{
+ local_irq_disable();
+ /* No way to shut power off with software */
+ for (;;) ;
+}
+
+void holly_halt(void)
+{
+ holly_power_off();
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init holly_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "ibm,holly"))
+ return 0;
+ return 1;
+}
+
+static int ppc750_machine_check_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *entry;
+
+ /* Are we prepared to handle this fault */
+ if ((entry = search_exception_tables(regs->nip)) != NULL) {
+ tsi108_clear_pci_cfg_error();
+ regs->msr |= MSR_RI;
+ regs->nip = entry->fixup;
+ return 1;
+ }
+ return 0;
+}
+
+define_machine(holly){
+ .name = "PPC750 GX/CL TSI",
+ .probe = holly_probe,
+ .setup_arch = holly_setup_arch,
+ .init_IRQ = holly_init_IRQ,
+ .show_cpuinfo = holly_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = holly_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .machine_check_exception = ppc750_machine_check_exception,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c
index 3f6c4114f90..b412f006a9c 100644
--- a/arch/powerpc/platforms/embedded6xx/linkstation.c
+++ b/arch/powerpc/platforms/embedded6xx/linkstation.c
@@ -58,11 +58,11 @@ static int __init add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
- int *bus_range;
+ const int *bus_range;
printk("Adding PCI host bridge %s\n", dev->full_name);
- bus_range = (int *) get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
@@ -106,7 +106,7 @@ static void __init linkstation_init_IRQ(void)
{
struct mpic *mpic;
struct device_node *dnp;
- void *prop;
+ const u32 *prop;
int size;
phys_addr_t paddr;
@@ -114,7 +114,7 @@ static void __init linkstation_init_IRQ(void)
if (dnp == NULL)
return;
- prop = (struct device_node *)get_property(dnp, "reg", &size);
+ prop = of_get_property(dnp, "reg", &size);
paddr = (phys_addr_t)of_translate_address(dnp, prop);
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, 4, 32, " EPIC ");
diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c
index 0e837762cc5..d0bee9f19e4 100644
--- a/arch/powerpc/platforms/embedded6xx/ls_uart.c
+++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c
@@ -110,8 +110,8 @@ static int __init ls_uarts_init(void)
if (!avr)
return -EINVAL;
- avr_clock = *(u32*)get_property(avr, "clock-frequency", &len);
- phys_addr = ((u32*)get_property(avr, "reg", &len))[0];
+ avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
+ phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
if (!avr_clock || !phys_addr)
return -EINVAL;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index 3fcc85f60fb..4542e0c837c 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -25,7 +25,6 @@
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/irq.h>
-#include <linux/ide.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/serial.h>
@@ -42,6 +41,7 @@
#include <asm/reg.h>
#include <mm/mmu_decl.h>
#include "mpc7448_hpc2.h"
+#include <asm/tsi108_pci.h>
#include <asm/tsi108_irq.h>
#include <asm/mpic.h>
@@ -52,16 +52,15 @@
#define DBG(fmt...) do { } while(0)
#endif
+#define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000
+
#ifndef CONFIG_PCI
isa_io_base = MPC7448_HPC2_ISA_IO_BASE;
isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE;
pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET;
#endif
-extern int tsi108_setup_pci(struct device_node *dev);
extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
-extern void tsi108_pci_int_init(struct device_node *node);
-extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc);
int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
{
@@ -73,38 +72,16 @@ int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
static void __init mpc7448_hpc2_setup_arch(void)
{
- struct device_node *cpu;
struct device_node *np;
if (ppc_md.progress)
ppc_md.progress("mpc7448_hpc2_setup_arch():set_bridge", 0);
- cpu = of_find_node_by_type(NULL, "cpu");
- if (cpu != 0) {
- const unsigned int *fp;
-
- fp = get_property(cpu, "clock-frequency", NULL);
- if (fp != 0)
- loops_per_jiffy = *fp / HZ;
- else
- loops_per_jiffy = 50000000 / HZ;
- of_node_put(cpu);
- }
tsi108_csr_vir_base = get_vir_csrbase();
-#ifdef CONFIG_ROOT_NFS
- ROOT_DEV = Root_NFS;
-#else
- ROOT_DEV = Root_HDA1;
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = Root_RAM0;
-#endif
-
/* setup PCI host bridge */
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- tsi108_setup_pci(np);
+ tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0);
ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device;
if (ppc_md.progress)
@@ -143,7 +120,7 @@ static void __init mpc7448_hpc2_init_IRQ(void)
tsi_pic = of_find_node_by_type(NULL, "open-pic");
if (tsi_pic) {
unsigned int size;
- const void *prop = get_property(tsi_pic, "reg", &size);
+ const void *prop = of_get_property(tsi_pic, "reg", &size);
mpic_paddr = of_translate_address(tsi_pic, prop);
}
@@ -233,7 +210,6 @@ static int __init mpc7448_hpc2_probe(void)
static int mpc7448_machine_check_exception(struct pt_regs *regs)
{
- extern void tsi108_clear_pci_cfg_error(void);
const struct exception_table_entry *entry;
/* Are we prepared to handle this fault */
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index 54e6b3b6f26..761d9e971fc 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -1,9 +1,15 @@
+config PPC_ISERIES
+ bool "IBM Legacy iSeries"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_INDIRECT_IO
menu "iSeries device drivers"
depends on PPC_ISERIES
config VIOCONS
- tristate "iSeries Virtual Console Support (Obsolete)"
+ bool "iSeries Virtual Console Support (Obsolete)"
+ depends on !HVC_ISERIES
+ default n
help
This is the old virtual console driver for legacy iSeries.
You should use the iSeries Hypervisor Virtual Console
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index d7a756d5135..3b6a9666c2c 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -171,7 +171,7 @@ void iommu_devnode_init_iSeries(struct pci_dev *pdev, struct device_node *dn)
{
struct iommu_table *tbl;
struct pci_dn *pdn = PCI_DN(dn);
- const u32 *lsn = get_property(dn, "linux,logical-slot-number", NULL);
+ const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
BUG_ON(lsn == NULL);
@@ -194,5 +194,5 @@ void iommu_init_early_iSeries(void)
ppc_md.tce_build = tce_build_iSeries;
ppc_md.tce_free = tce_free_iSeries;
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
}
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 5225abfafd9..63b33675848 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -30,7 +30,6 @@
#include <linux/param.h>
#include <linux/string.h>
#include <linux/bootmem.h>
-#include <linux/ide.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
@@ -337,6 +336,8 @@ unsigned int iSeries_get_irq(void)
return irq;
}
+#ifdef CONFIG_PCI
+
static int iseries_irq_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
@@ -384,3 +385,4 @@ void __init iSeries_init_IRQ(void)
"failed with rc 0x%x\n", ret);
}
+#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 4a06d9c3498..9c974227155 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -24,7 +24,6 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/ide.h>
#include <linux/pci.h>
#include <asm/io.h>
@@ -177,7 +176,7 @@ void __init iSeries_pci_final_fixup(void)
struct pci_dn *pdn = PCI_DN(node);
const u32 *agent;
- agent = get_property(node, "linux,agent-id", NULL);
+ agent = of_get_property(node, "linux,agent-id", NULL);
if ((pdn != NULL) && (agent != NULL)) {
u8 irq = iSeries_allocate_IRQ(pdn->busno, 0,
pdn->bussubno);
@@ -755,7 +754,7 @@ void __init iSeries_pcibios_init(void)
if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
continue;
- busp = get_property(node, "bus-range", NULL);
+ busp = of_get_property(node, "bus-range", NULL);
if (busp == NULL)
continue;
bus = *busp;
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index cce7e309340..7f5dcee814d 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -628,15 +628,6 @@ static void iseries_iounmap(volatile void __iomem *token)
{
}
-/*
- * iSeries has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int iseries_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
static int __init iseries_probe(void)
{
unsigned long root = of_get_flat_dt_root();
@@ -667,7 +658,6 @@ define_machine(iseries) {
.calibrate_decr = generic_calibrate_decr,
.progress = iSeries_progress,
.probe = iseries_probe,
- .check_legacy_ioport = iseries_check_legacy_ioport,
.ioremap = iseries_ioremap,
.iounmap = iseries_iounmap,
/* XXX Implement enable_pmcs for iSeries */
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index aee5908df70..722335e32fd 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index e2100ece9c6..354b8dd2a2c 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -36,7 +36,6 @@
#include <linux/dma-mapping.h>
#include <linux/wait.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <asm/system.h>
@@ -155,7 +154,7 @@ static int proc_viopath_show(struct seq_file *m, void *v)
node = of_find_node_by_path("/");
sysid = NULL;
if (node != NULL)
- sysid = get_property(node, "system-id", NULL);
+ sysid = of_get_property(node, "system-id", NULL);
if (sysid == NULL)
seq_printf(m, "SRLNBR=<UNKNOWN>\n");
diff --git a/arch/powerpc/platforms/maple/Kconfig b/arch/powerpc/platforms/maple/Kconfig
new file mode 100644
index 00000000000..f7c95eb5d8b
--- /dev/null
+++ b/arch/powerpc/platforms/maple/Kconfig
@@ -0,0 +1,17 @@
+config PPC_MAPLE
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "Maple 970FX Evaluation Board"
+ select MPIC
+ select U3_DART
+ select MPIC_U3_HT_IRQS
+ select GENERIC_TBSYNC
+ select PPC_UDBG_16550
+ select PPC_970_NAP
+ select PPC_NATIVE
+ select PPC_RTAS
+ select MMIO_NVRAM
+ select ATA_NONSTANDARD if ATA
+ default n
+ help
+ This option enables support for the Maple 970FX Evaluation Board.
+ For more information, refer to <http://www.970eval.com>
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 73c59904697..7aaa5bbc936 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -44,11 +44,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
int len;
/* For PCI<->PCI bridges or CardBus bridges, we go down */
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range != NULL && len > 2 * sizeof(int)) {
if (bus_range[1] > higher)
higher = bus_range[1];
@@ -77,7 +77,7 @@ static void __init fixup_bus_range(struct device_node *bridge)
bridge->full_name);
return;
}
- bus_range = (int *)prop->value;
+ bus_range = prop->value;
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -454,7 +454,7 @@ static int __init add_bridge(struct device_node *dev)
DBG("Adding PCI host bridge %s\n", dev->full_name);
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
dev->full_name);
@@ -467,15 +467,15 @@ static int __init add_bridge(struct device_node *dev)
hose->last_busno = bus_range ? bus_range[1] : 0xff;
disp_name = NULL;
- if (device_is_compatible(dev, "u3-agp")) {
+ if (of_device_is_compatible(dev, "u3-agp")) {
setup_u3_agp(hose);
disp_name = "U3-AGP";
primary = 0;
- } else if (device_is_compatible(dev, "u3-ht")) {
+ } else if (of_device_is_compatible(dev, "u3-ht")) {
setup_u3_ht(hose);
disp_name = "U3-HT";
primary = 1;
- } else if (device_is_compatible(dev, "u4-pcie")) {
+ } else if (of_device_is_compatible(dev, "u4-pcie")) {
setup_u4_pcie(hose);
disp_name = "U4-PCIE";
primary = 0;
@@ -556,12 +556,12 @@ void __init maple_pci_init(void)
continue;
if (strcmp(np->type, "pci") && strcmp(np->type, "ht"))
continue;
- if ((device_is_compatible(np, "u4-pcie") ||
- device_is_compatible(np, "u3-agp")) &&
+ if ((of_device_is_compatible(np, "u4-pcie") ||
+ of_device_is_compatible(np, "u3-agp")) &&
add_bridge(np) == 0)
of_node_get(np);
- if (device_is_compatible(np, "u3-ht")) {
+ if (of_device_is_compatible(np, "u3-ht")) {
of_node_get(np);
ht = np;
}
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 82d3f9e28d7..354c0586162 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -32,7 +32,6 @@
#include <linux/initrd.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
-#include <linux/ide.h>
#include <linux/pci.h>
#include <linux/adb.h>
#include <linux/cuda.h>
@@ -114,8 +113,8 @@ static void maple_restart(char *cmd)
printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
goto fail;
}
- maple_nvram_offset = get_property(sp, "restart-addr", NULL);
- maple_nvram_command = get_property(sp, "restart-value", NULL);
+ maple_nvram_offset = of_get_property(sp, "restart-addr", NULL);
+ maple_nvram_command = of_get_property(sp, "restart-value", NULL);
of_node_put(sp);
/* send command */
@@ -141,8 +140,8 @@ static void maple_power_off(void)
printk(KERN_EMERG "Maple: Unable to find Service Processor\n");
goto fail;
}
- maple_nvram_offset = get_property(sp, "power-off-addr", NULL);
- maple_nvram_command = get_property(sp, "power-off-value", NULL);
+ maple_nvram_offset = of_get_property(sp, "power-off-addr", NULL);
+ maple_nvram_command = of_get_property(sp, "power-off-value", NULL);
of_node_put(sp);
/* send command */
@@ -232,7 +231,7 @@ static void __init maple_init_IRQ(void)
*/
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "open-pic")) {
+ if (of_device_is_compatible(np, "open-pic")) {
mpic_node = np;
break;
}
@@ -249,8 +248,8 @@ static void __init maple_init_IRQ(void)
/* Find address list in /platform-open-pic */
root = of_find_node_by_path("/");
- naddr = prom_n_addr_cells(root);
- opprop = get_property(root, "platform-open-pic", &opplen);
+ naddr = of_n_addr_cells(root);
+ opprop = of_get_property(root, "platform-open-pic", &opplen);
if (opprop != 0) {
openpic_addr = of_read_number(opprop, naddr);
has_isus = (opplen > naddr);
@@ -261,11 +260,11 @@ static void __init maple_init_IRQ(void)
BUG_ON(openpic_addr == 0);
/* Check for a big endian MPIC */
- if (get_property(np, "big-endian", NULL) != NULL)
+ if (of_get_property(np, "big-endian", NULL) != NULL)
flags |= MPIC_BIG_ENDIAN;
/* XXX Maple specific bits */
- flags |= MPIC_BROKEN_U3 | MPIC_WANTS_RESET;
+ flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET;
/* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */
flags |= MPIC_BIG_ENDIAN;
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
index 68dc529dfd2..eb4dbc705b0 100644
--- a/arch/powerpc/platforms/pasemi/Kconfig
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -1,3 +1,15 @@
+config PPC_PASEMI
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "PA Semi SoC-based platforms"
+ default n
+ select MPIC
+ select PPC_UDBG_16550
+ select GENERIC_TBSYNC
+ select PPC_NATIVE
+ help
+ This option enables support for PA Semi's PWRficient line
+ of SoC processors, including PA6T-1682M
+
menu "PA Semi PWRficient options"
depends on PPC_PASEMI
@@ -7,4 +19,11 @@ config PPC_PASEMI_IOMMU
help
IOMMU support for PA6T-1682M
+config PPC_PASEMI_MDIO
+ depends on PHYLIB
+ tristate "MDIO support via GPIO"
+ default y
+ help
+ Driver for MDIO via GPIO on PWRficient platforms
+
endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index e657ccae90a..2cd2a4f26a4 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1,2 +1,3 @@
obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o
-
+obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o
+obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
new file mode 100644
index 00000000000..3ae083851b0
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Authors: Egor Martovetsky <egor@pasemi.com>
+ * Olof Johansson <olof@lixom.net>
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on arch/powerpc/platforms/cell/cbe_cpufreq.c:
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * 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, 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/cpufreq.h>
+#include <linux/timer.h>
+
+#include <asm/hw_irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+
+#define SDCASR_REG 0x0100
+#define SDCASR_REG_STRIDE 0x1000
+#define SDCPWR_CFGA0_REG 0x0100
+#define SDCPWR_PWST0_REG 0x0000
+#define SDCPWR_GIZTIME_REG 0x0440
+
+/* SDCPWR_GIZTIME_REG fields */
+#define SDCPWR_GIZTIME_GR 0x80000000
+#define SDCPWR_GIZTIME_LONGLOCK 0x000000ff
+
+/* Offset of ASR registers from SDC base */
+#define SDCASR_OFFSET 0x120000
+
+static void __iomem *sdcpwr_mapbase;
+static void __iomem *sdcasr_mapbase;
+
+static DEFINE_MUTEX(pas_switch_mutex);
+
+/* Current astate, is used when waking up from power savings on
+ * one core, in case the other core has switched states during
+ * the idle time.
+ */
+static int current_astate;
+
+/* We support 5(A0-A4) power states excluding turbo(A5-A6) modes */
+static struct cpufreq_frequency_table pas_freqs[] = {
+ {0, 0},
+ {1, 0},
+ {2, 0},
+ {3, 0},
+ {4, 0},
+ {0, CPUFREQ_TABLE_END},
+};
+
+static struct freq_attr *pas_cpu_freqs_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+/*
+ * hardware specific functions
+ */
+
+static int get_astate_freq(int astate)
+{
+ u32 ret;
+ ret = in_le32(sdcpwr_mapbase + SDCPWR_CFGA0_REG + (astate * 0x10));
+
+ return ret & 0x3f;
+}
+
+static int get_cur_astate(int cpu)
+{
+ u32 ret;
+
+ ret = in_le32(sdcpwr_mapbase + SDCPWR_PWST0_REG);
+ ret = (ret >> (cpu * 4)) & 0x7;
+
+ return ret;
+}
+
+static int get_gizmo_latency(void)
+{
+ u32 giztime, ret;
+
+ giztime = in_le32(sdcpwr_mapbase + SDCPWR_GIZTIME_REG);
+
+ /* just provide the upper bound */
+ if (giztime & SDCPWR_GIZTIME_GR)
+ ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 128000;
+ else
+ ret = (giztime & SDCPWR_GIZTIME_LONGLOCK) * 1000;
+
+ return ret;
+}
+
+static void set_astate(int cpu, unsigned int astate)
+{
+ u64 flags;
+
+ /* Return if called before init has run */
+ if (unlikely(!sdcasr_mapbase))
+ return;
+
+ local_irq_save(flags);
+
+ out_le32(sdcasr_mapbase + SDCASR_REG + SDCASR_REG_STRIDE*cpu, astate);
+
+ local_irq_restore(flags);
+}
+
+void restore_astate(int cpu)
+{
+ set_astate(cpu, current_astate);
+}
+
+/*
+ * cpufreq functions
+ */
+
+static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ const u32 *max_freqp;
+ u32 max_freq;
+ int i, cur_astate;
+ struct resource res;
+ struct device_node *cpu, *dn;
+ int err = -ENODEV;
+
+ cpu = of_get_cpu_node(policy->cpu, NULL);
+
+ if (!cpu)
+ goto out;
+
+ dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc");
+ if (!dn)
+ goto out;
+ err = of_address_to_resource(dn, 0, &res);
+ of_node_put(dn);
+ if (err)
+ goto out;
+ sdcasr_mapbase = ioremap(res.start + SDCASR_OFFSET, 0x2000);
+ if (!sdcasr_mapbase) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo");
+ if (!dn) {
+ err = -ENODEV;
+ goto out_unmap_sdcasr;
+ }
+ err = of_address_to_resource(dn, 0, &res);
+ of_node_put(dn);
+ if (err)
+ goto out_unmap_sdcasr;
+ sdcpwr_mapbase = ioremap(res.start, 0x1000);
+ if (!sdcpwr_mapbase) {
+ err = -EINVAL;
+ goto out_unmap_sdcasr;
+ }
+
+ pr_debug("init cpufreq on CPU %d\n", policy->cpu);
+
+ max_freqp = of_get_property(cpu, "clock-frequency", NULL);
+ if (!max_freqp) {
+ err = -EINVAL;
+ goto out_unmap_sdcpwr;
+ }
+
+ /* we need the freq in kHz */
+ max_freq = *max_freqp / 1000;
+
+ pr_debug("max clock-frequency is at %u kHz\n", max_freq);
+ pr_debug("initializing frequency table\n");
+
+ /* initialize frequency table */
+ for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
+ pas_freqs[i].frequency = get_astate_freq(pas_freqs[i].index) * 100000;
+ pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
+ }
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.transition_latency = get_gizmo_latency();
+
+ cur_astate = get_cur_astate(policy->cpu);
+ pr_debug("current astate is at %d\n",cur_astate);
+
+ policy->cur = pas_freqs[cur_astate].frequency;
+ policy->cpus = cpu_online_map;
+
+ ppc_proc_freq = policy->cur * 1000ul;
+
+ cpufreq_frequency_table_get_attr(pas_freqs, policy->cpu);
+
+ /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max
+ * are set correctly
+ */
+ return cpufreq_frequency_table_cpuinfo(policy, pas_freqs);
+
+out_unmap_sdcpwr:
+ iounmap(sdcpwr_mapbase);
+
+out_unmap_sdcasr:
+ iounmap(sdcasr_mapbase);
+out:
+ return err;
+}
+
+static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ if (sdcasr_mapbase)
+ iounmap(sdcasr_mapbase);
+ if (sdcpwr_mapbase)
+ iounmap(sdcpwr_mapbase);
+
+ cpufreq_frequency_table_put_attr(policy->cpu);
+ return 0;
+}
+
+static int pas_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, pas_freqs);
+}
+
+static int pas_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ int pas_astate_new;
+ int i;
+
+ cpufreq_frequency_table_target(policy,
+ pas_freqs,
+ target_freq,
+ relation,
+ &pas_astate_new);
+
+ freqs.old = policy->cur;
+ freqs.new = pas_freqs[pas_astate_new].frequency;
+ freqs.cpu = policy->cpu;
+
+ mutex_lock(&pas_switch_mutex);
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+ policy->cpu,
+ pas_freqs[pas_astate_new].frequency,
+ pas_freqs[pas_astate_new].index);
+
+ current_astate = pas_astate_new;
+
+ for_each_online_cpu(i)
+ set_astate(i, pas_astate_new);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&pas_switch_mutex);
+
+ ppc_proc_freq = freqs.new * 1000ul;
+ return 0;
+}
+
+static struct cpufreq_driver pas_cpufreq_driver = {
+ .name = "pas-cpufreq",
+ .owner = THIS_MODULE,
+ .flags = CPUFREQ_CONST_LOOPS,
+ .init = pas_cpufreq_cpu_init,
+ .exit = pas_cpufreq_cpu_exit,
+ .verify = pas_cpufreq_verify,
+ .target = pas_cpufreq_target,
+ .attr = pas_cpu_freqs_attr,
+};
+
+/*
+ * module init and destoy
+ */
+
+static int __init pas_cpufreq_init(void)
+{
+ if (!machine_is_compatible("PA6T-1682M"))
+ return -ENODEV;
+
+ return cpufreq_register_driver(&pas_cpufreq_driver);
+}
+
+static void __exit pas_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&pas_cpufreq_driver);
+}
+
+module_init(pas_cpufreq_init);
+module_exit(pas_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c
new file mode 100644
index 00000000000..c91a33593bb
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Olof Johansson, PA Semi
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Based on drivers/net/fs_enet/mii-bitbang.c.
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+#include <asm/of_platform.h>
+
+#define DELAY 1
+
+static void __iomem *gpio_regs;
+
+struct gpio_priv {
+ int mdc_pin;
+ int mdio_pin;
+};
+
+#define MDC_PIN(bus) (((struct gpio_priv *)bus->priv)->mdc_pin)
+#define MDIO_PIN(bus) (((struct gpio_priv *)bus->priv)->mdio_pin)
+
+static inline void mdio_lo(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdio_hi(struct mii_bus *bus)
+{
+ out_le32(gpio_regs, 1 << MDIO_PIN(bus));
+}
+
+static inline void mdc_lo(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
+}
+
+static inline void mdc_hi(struct mii_bus *bus)
+{
+ out_le32(gpio_regs, 1 << MDC_PIN(bus));
+}
+
+static inline void mdio_active(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
+}
+
+static inline void mdio_tristate(struct mii_bus *bus)
+{
+ out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
+}
+
+static inline int mdio_read(struct mii_bus *bus)
+{
+ return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
+}
+
+static void clock_out(struct mii_bus *bus, int bit)
+{
+ if (bit)
+ mdio_hi(bus);
+ else
+ mdio_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+}
+
+/* Utility to send the preamble, address, and register (common to read and write). */
+static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
+{
+ int i;
+
+ /* CFE uses a really long preamble (40 bits). We'll do the same. */
+ mdio_active(bus);
+ for (i = 0; i < 40; i++) {
+ clock_out(bus, 1);
+ }
+
+ /* send the start bit (01) and the read opcode (10) or write (10) */
+ clock_out(bus, 0);
+ clock_out(bus, 1);
+
+ clock_out(bus, read);
+ clock_out(bus, !read);
+
+ /* send the PHY address */
+ for (i = 0; i < 5; i++) {
+ clock_out(bus, (addr & 0x10) != 0);
+ addr <<= 1;
+ }
+
+ /* send the register address */
+ for (i = 0; i < 5; i++) {
+ clock_out(bus, (reg & 0x10) != 0);
+ reg <<= 1;
+ }
+}
+
+static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
+{
+ u16 rdreg;
+ int ret, i;
+ u8 addr = phy_id & 0xff;
+ u8 reg = location & 0xff;
+
+ bitbang_pre(bus, 1, addr, reg);
+
+ /* tri-state our MDIO I/O pin so we can read */
+ mdio_tristate(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+
+ /* read 16 bits of register data, MSB first */
+ rdreg = 0;
+ for (i = 0; i < 16; i++) {
+ mdc_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+ udelay(DELAY);
+ rdreg <<= 1;
+ rdreg |= mdio_read(bus);
+ }
+
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+ udelay(DELAY);
+
+ ret = rdreg;
+
+ return ret;
+}
+
+static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+ int i;
+
+ u8 addr = phy_id & 0xff;
+ u8 reg = location & 0xff;
+ u16 value = val & 0xffff;
+
+ bitbang_pre(bus, 0, addr, reg);
+
+ /* send the turnaround (10) */
+ mdc_lo(bus);
+ mdio_hi(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ mdc_lo(bus);
+ mdio_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+
+ /* write 16 bits of register data, MSB first */
+ for (i = 0; i < 16; i++) {
+ mdc_lo(bus);
+ if (value & 0x8000)
+ mdio_hi(bus);
+ else
+ mdio_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ value <<= 1;
+ }
+
+ /*
+ * Tri-state the MDIO line.
+ */
+ mdio_tristate(bus);
+ mdc_lo(bus);
+ udelay(DELAY);
+ mdc_hi(bus);
+ udelay(DELAY);
+ return 0;
+}
+
+static int gpio_mdio_reset(struct mii_bus *bus)
+{
+ /*nothing here - dunno how to reset it*/
+ return 0;
+}
+
+
+static int __devinit gpio_mdio_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ struct device *dev = &ofdev->dev;
+ struct device_node *np = ofdev->node;
+ struct device_node *gpio_np;
+ struct mii_bus *new_bus;
+ struct resource res;
+ struct gpio_priv *priv;
+ const unsigned int *prop;
+ int err = 0;
+ int i;
+
+ gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio");
+
+ if (!gpio_np)
+ return -ENODEV;
+
+ err = of_address_to_resource(gpio_np, 0, &res);
+ of_node_put(gpio_np);
+
+ if (err)
+ return -EINVAL;
+
+ if (!gpio_regs)
+ gpio_regs = ioremap(res.start, 0x100);
+
+ if (!gpio_regs)
+ return -EPERM;
+
+ priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (new_bus == NULL)
+ return -ENOMEM;
+
+ new_bus->name = "pasemi gpio mdio bus",
+ new_bus->read = &gpio_mdio_read,
+ new_bus->write = &gpio_mdio_write,
+ new_bus->reset = &gpio_mdio_reset,
+
+ prop = of_get_property(np, "reg", NULL);
+ new_bus->id = *prop;
+ new_bus->priv = priv;
+
+ new_bus->phy_mask = 0;
+
+ new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ for(i = 0; i < PHY_MAX_ADDR; ++i)
+ new_bus->irq[i] = irq_create_mapping(NULL, 10);
+
+
+ prop = of_get_property(np, "mdc-pin", NULL);
+ priv->mdc_pin = *prop;
+
+ prop = of_get_property(np, "mdio-pin", NULL);
+ priv->mdio_pin = *prop;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+ printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
+ new_bus->name, err);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ kfree(new_bus);
+
+ return err;
+}
+
+
+static int gpio_mdio_remove(struct of_device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(&dev->dev);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ kfree(bus->priv);
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id gpio_mdio_match[] =
+{
+ {
+ .compatible = "gpio-mdio",
+ },
+ {},
+};
+
+static struct of_platform_driver gpio_mdio_driver =
+{
+ .name = "gpio-mdio-bitbang",
+ .match_table = gpio_mdio_match,
+ .probe = gpio_mdio_probe,
+ .remove = gpio_mdio_remove,
+};
+
+int gpio_mdio_init(void)
+{
+ return of_register_platform_driver(&gpio_mdio_driver);
+}
+
+void gpio_mdio_exit(void)
+{
+ of_unregister_platform_driver(&gpio_mdio_driver);
+}
+device_initcall(gpio_mdio_init);
+
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c
index 1ca3ff38159..5985ce0c5c4 100644
--- a/arch/powerpc/platforms/pasemi/idle.c
+++ b/arch/powerpc/platforms/pasemi/idle.c
@@ -61,6 +61,10 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
/* do system reset */
return 0;
}
+
+ /* Set higher astate since we come out of power savings at 0 */
+ restore_astate(hard_smp_processor_id());
+
/* everything handled */
regs->msr |= MSR_RI;
return 1;
@@ -68,6 +72,11 @@ static int pasemi_system_reset_exception(struct pt_regs *regs)
void __init pasemi_idle_init(void)
{
+#ifndef CONFIG_PPC_PASEMI_CPUFREQ
+ printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n");
+ current_mode = 0;
+#endif
+
ppc_md.system_reset_exception = pasemi_system_reset_exception;
ppc_md.power_save = modes[current_mode].entry;
printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
index 71dbf1a56e1..95fa6a7d15e 100644
--- a/arch/powerpc/platforms/pasemi/iommu.c
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -249,13 +249,13 @@ void iommu_init_early_pasemi(void)
iommu_off = 1;
#else
iommu_off = of_chosen &&
- get_property(of_chosen, "linux,iommu-off", NULL);
+ of_get_property(of_chosen, "linux,iommu-off", NULL);
#endif
if (iommu_off) {
/* Direct I/O, IOMMU off */
ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
return;
}
@@ -266,7 +266,7 @@ void iommu_init_early_pasemi(void)
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
ppc_md.tce_build = iobmap_build;
ppc_md.tce_free = iobmap_free;
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
}
void __init alloc_iobmap_l2(void)
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 2d3927e6edb..be849549761 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -14,6 +14,14 @@ extern void __init pasemi_idle_init(void);
extern void idle_spin(void);
extern void idle_doze(void);
+/* Restore astate to last set */
+#ifdef CONFIG_PPC_PASEMI_CPUFREQ
+extern void restore_astate(int cpu);
+#else
+static inline void restore_astate(int cpu)
+{
+}
+#endif
#endif /* _PASEMI_PASEMI_H */
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index 7ecb2ba24db..bbc6dfcfaa9 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -33,7 +33,17 @@
#define PA_PXP_CFA(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
-#define CONFIG_OFFSET_VALID(off) ((off) < 4096)
+static inline int pa_pxp_offset_valid(u8 bus, u8 devfn, int offset)
+{
+ /* Device 0 Function 0 is special: It's config space spans function 1 as
+ * well, so allow larger offset. It's really a two-function device but the
+ * second function does not probe.
+ */
+ if (bus == 0 && devfn == 0)
+ return offset < 8192;
+ else
+ return offset < 4096;
+}
static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
u8 bus, u8 devfn, int offset)
@@ -51,7 +61,7 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
if (!hose)
return PCIBIOS_DEVICE_NOT_FOUND;
- if (!CONFIG_OFFSET_VALID(offset))
+ if (!pa_pxp_offset_valid(bus->number, devfn, offset))
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
@@ -85,7 +95,7 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
if (!hose)
return PCIBIOS_DEVICE_NOT_FOUND;
- if (!CONFIG_OFFSET_VALID(offset))
+ if (!pa_pxp_offset_valid(bus->number, devfn, offset))
return PCIBIOS_BAD_REGISTER_NUMBER;
addr = pa_pxp_cfg_addr(hose, bus->number, devfn, offset);
@@ -163,19 +173,6 @@ static void __init pas_fixup_phb_resources(void)
}
-void __devinit pas_pci_irq_fixup(struct pci_dev *dev)
-{
- /* DMA is special, 84 interrupts (128 -> 211), all but 128
- * need to be mapped by hand here.
- */
- if (dev->vendor == 0x1959 && dev->device == 0xa007) {
- int i;
- for (i = 129; i < 212; i++)
- irq_create_mapping(NULL, i);
- }
-}
-
-
void __init pas_pci_init(void)
{
struct device_node *np, *root;
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 449cf1a0829..c5a3f61f8d8 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -35,6 +35,7 @@
#include <asm/mpic.h>
#include <asm/smp.h>
#include <asm/time.h>
+#include <asm/of_platform.h>
#include "pasemi.h"
@@ -101,12 +102,6 @@ void __init pas_setup_arch(void)
pasemi_idle_init();
}
-/* No legacy IO on our parts */
-static int pas_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
static __init void pas_init_IRQ(void)
{
struct device_node *np;
@@ -119,7 +114,7 @@ static __init void pas_init_IRQ(void)
mpic_node = NULL;
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "open-pic")) {
+ if (of_device_is_compatible(np, "open-pic")) {
mpic_node = np;
break;
}
@@ -136,8 +131,8 @@ static __init void pas_init_IRQ(void)
/* Find address list in /platform-open-pic */
root = of_find_node_by_path("/");
- naddr = prom_n_addr_cells(root);
- opprop = get_property(root, "platform-open-pic", &opplen);
+ naddr = of_n_addr_cells(root);
+ opprop = of_get_property(root, "platform-open-pic", &opplen);
if (!opprop) {
printk(KERN_ERR "No platform-open-pic property.\n");
of_node_put(root);
@@ -147,7 +142,7 @@ static __init void pas_init_IRQ(void)
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
mpic = mpic_alloc(mpic_node, openpic_addr,
- MPIC_PRIMARY|MPIC_LARGE_VECTORS,
+ MPIC_PRIMARY|MPIC_LARGE_VECTORS|MPIC_WANTS_RESET,
0, 0, " PAS-OPIC ");
BUG_ON(!mpic);
@@ -209,6 +204,23 @@ static void __init pas_init_early(void)
iommu_init_early_pasemi();
}
+static struct of_device_id pasemi_bus_ids[] = {
+ { .type = "sdc", },
+ {},
+};
+
+static int __init pasemi_publish_devices(void)
+{
+ if (!machine_is(pasemi))
+ return 0;
+
+ /* Publish OF platform devices for SDC and other non-PCI devices */
+ of_platform_bus_probe(NULL, pasemi_bus_ids, NULL);
+
+ return 0;
+}
+device_initcall(pasemi_publish_devices);
+
/*
* Called very early, MMU is off, device-tree isn't unflattened
@@ -237,8 +249,6 @@ define_machine(pas) {
.restart = pas_restart,
.get_boot_time = pas_get_boot_time,
.calibrate_decr = generic_calibrate_decr,
- .check_legacy_ioport = pas_check_legacy_ioport,
.progress = pas_progress,
.machine_check_exception = pas_machine_check_handler,
- .pci_irq_fixup = pas_pci_irq_fixup,
};
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
new file mode 100644
index 00000000000..5b7afe50039
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -0,0 +1,20 @@
+config PPC_PMAC
+ bool "Apple PowerMac based machines"
+ depends on PPC_MULTIPLATFORM
+ select MPIC
+ select PPC_INDIRECT_PCI if PPC32
+ select PPC_MPC106 if PPC32
+ select PPC_NATIVE
+ default y
+
+config PPC_PMAC64
+ bool
+ depends on PPC_PMAC && POWER4
+ select MPIC
+ select U3_DART
+ select MPIC_U3_HT_IRQS
+ select GENERIC_TBSYNC
+ select PPC_970_NAP
+ default y
+
+
diff --git a/arch/powerpc/platforms/powermac/backlight.c b/arch/powerpc/platforms/powermac/backlight.c
index de7440e62cc..d679964ae2a 100644
--- a/arch/powerpc/platforms/powermac/backlight.c
+++ b/arch/powerpc/platforms/powermac/backlight.c
@@ -56,13 +56,16 @@ struct backlight_device *pmac_backlight;
int pmac_has_backlight_type(const char *type)
{
- struct device_node* bk_node = find_devices("backlight");
+ struct device_node* bk_node = of_find_node_by_name(NULL, "backlight");
if (bk_node) {
- const char *prop = get_property(bk_node,
+ const char *prop = of_get_property(bk_node,
"backlight-control", NULL);
- if (prop && strncmp(prop, type, strlen(type)) == 0)
+ if (prop && strncmp(prop, type, strlen(type)) == 0) {
+ of_node_put(bk_node);
return 1;
+ }
+ of_node_put(bk_node);
}
return 0;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index c2b6b4134f6..1fe35dab0e9 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -25,7 +25,6 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
#include <linux/sysdev.h>
-#include <linux/i2c.h>
#include <linux/hardirq.h>
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -421,7 +420,7 @@ static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
static u32 read_gpio(struct device_node *np)
{
- const u32 *reg = get_property(np, "reg", NULL);
+ const u32 *reg = of_get_property(np, "reg", NULL);
u32 offset;
if (reg == NULL)
@@ -521,13 +520,14 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
int lenp, rc;
const u32 *freqs, *ratio;
- freqs = get_property(cpunode, "bus-frequencies", &lenp);
+ freqs = of_get_property(cpunode, "bus-frequencies", &lenp);
lenp /= sizeof(u32);
if (freqs == NULL || lenp != 2) {
printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
return 1;
}
- ratio = get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+ ratio = of_get_property(cpunode, "processor-to-bus-ratio*2",
+ NULL);
if (ratio == NULL) {
printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
return 1;
@@ -562,7 +562,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
/* If we use the PMU, look for the min & max frequencies in the
* device-tree
*/
- value = get_property(cpunode, "min-clock-frequency", NULL);
+ value = of_get_property(cpunode, "min-clock-frequency", NULL);
if (!value)
return 1;
low_freq = (*value) / 1000;
@@ -571,7 +571,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
if (low_freq < 100000)
low_freq *= 10;
- value = get_property(cpunode, "max-clock-frequency", NULL);
+ value = of_get_property(cpunode, "max-clock-frequency", NULL);
if (!value)
return 1;
hi_freq = (*value) / 1000;
@@ -585,7 +585,7 @@ static int pmac_cpufreq_init_7447A(struct device_node *cpunode)
{
struct device_node *volt_gpio_np;
- if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+ if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL)
return 1;
volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
@@ -614,11 +614,11 @@ static int pmac_cpufreq_init_750FX(struct device_node *cpunode)
u32 pvr;
const u32 *value;
- if (get_property(cpunode, "dynamic-power-step", NULL) == NULL)
+ if (of_get_property(cpunode, "dynamic-power-step", NULL) == NULL)
return 1;
hi_freq = cur_freq;
- value = get_property(cpunode, "reduced-clock-frequency", NULL);
+ value = of_get_property(cpunode, "reduced-clock-frequency", NULL);
if (!value)
return 1;
low_freq = (*value) / 1000;
@@ -657,19 +657,19 @@ static int __init pmac_cpufreq_setup(void)
return 0;
/* Assume only one CPU */
- cpunode = find_type_devices("cpu");
+ cpunode = of_find_node_by_type(NULL, "cpu");
if (!cpunode)
goto out;
/* Get current cpu clock freq */
- value = get_property(cpunode, "clock-frequency", NULL);
+ value = of_get_property(cpunode, "clock-frequency", NULL);
if (!value)
goto out;
cur_freq = (*value) / 1000;
/* Check for 7447A based MacRISC3 */
if (machine_is_compatible("MacRISC3") &&
- get_property(cpunode, "dynamic-power-step", NULL) &&
+ of_get_property(cpunode, "dynamic-power-step", NULL) &&
PVR_VER(mfspr(SPRN_PVR)) == 0x8003) {
pmac_cpufreq_init_7447A(cpunode);
/* Check for other MacRISC3 machines */
@@ -707,6 +707,7 @@ static int __init pmac_cpufreq_setup(void)
else if (PVR_VER(mfspr(SPRN_PVR)) == 0x7000)
pmac_cpufreq_init_750FX(cpunode);
out:
+ of_node_put(cpunode);
if (set_speed_proc == NULL)
return -ENODEV;
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 9d22361a26d..00f50298c34 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -357,13 +357,13 @@ static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- if (policy->cpu != 0)
- return -ENODEV;
-
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
- policy->cpus = cpu_possible_map;
+ /* secondary CPUs are tied to the primary one by the
+ * cpufreq core if in the secondary policy we tell it that
+ * it actually must be one policy together with all others. */
+ policy->cpus = cpu_online_map;
cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
return cpufreq_frequency_table_cpuinfo(policy,
@@ -410,7 +410,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
/* Get first CPU node */
for (cpunode = NULL;
(cpunode = of_get_next_child(cpus, cpunode)) != NULL;) {
- const u32 *reg = get_property(cpunode, "reg", NULL);
+ const u32 *reg = of_get_property(cpunode, "reg", NULL);
if (reg == NULL || (*reg) != 0)
continue;
if (!strcmp(cpunode->type, "cpu"))
@@ -422,7 +422,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
}
/* Check 970FX for now */
- valp = get_property(cpunode, "cpu-version", NULL);
+ valp = of_get_property(cpunode, "cpu-version", NULL);
if (!valp) {
DBG("No cpu-version property !\n");
goto bail_noprops;
@@ -434,7 +434,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
}
/* Look for the powertune data in the device-tree */
- g5_pmode_data = get_property(cpunode, "power-mode-data",&psize);
+ g5_pmode_data = of_get_property(cpunode, "power-mode-data",&psize);
if (!g5_pmode_data) {
DBG("No power-mode-data !\n");
goto bail_noprops;
@@ -493,7 +493,7 @@ static int __init g5_neo2_cpufreq_init(struct device_node *cpus)
* half freq in this version. So far, I haven't yet seen a machine
* supporting anything else.
*/
- valp = get_property(cpunode, "clock-frequency", NULL);
+ valp = of_get_property(cpunode, "clock-frequency", NULL);
if (!valp)
return -ENODEV;
max_freq = (*valp)/1000;
@@ -563,7 +563,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
/* Lookup the cpuid eeprom node */
cpuid = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/cpuid@a0");
if (cpuid != NULL)
- eeprom = get_property(cpuid, "cpuid", NULL);
+ eeprom = of_get_property(cpuid, "cpuid", NULL);
if (eeprom == NULL) {
printk(KERN_ERR "cpufreq: Can't find cpuid EEPROM !\n");
rc = -ENODEV;
@@ -573,13 +573,13 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
/* Lookup the i2c hwclock */
for (hwclock = NULL;
(hwclock = of_find_node_by_name(hwclock, "i2c-hwclock")) != NULL;){
- const char *loc = get_property(hwclock,
+ const char *loc = of_get_property(hwclock,
"hwctrl-location", NULL);
if (loc == NULL)
continue;
if (strcmp(loc, "CPU CLOCK"))
continue;
- if (!get_property(hwclock, "platform-get-frequency", NULL))
+ if (!of_get_property(hwclock, "platform-get-frequency", NULL))
continue;
break;
}
@@ -638,7 +638,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpus)
*/
/* Get max frequency from device-tree */
- valp = get_property(cpunode, "clock-frequency", NULL);
+ valp = of_get_property(cpunode, "clock-frequency", NULL);
if (!valp) {
printk(KERN_ERR "cpufreq: Can't find CPU frequency !\n");
rc = -ENODEV;
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index 24cc50c1774..f29705f8047 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -1044,6 +1044,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
unsigned long flags;
struct macio_chip *macio;
struct device_node *np;
+ struct device_node *cpus;
const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0,
KL_GPIO_RESET_CPU1,
KL_GPIO_RESET_CPU2,
@@ -1053,12 +1054,12 @@ core99_reset_cpu(struct device_node *node, long param, long value)
if (macio->type != macio_keylargo)
return -ENODEV;
- np = find_path_device("/cpus");
- if (np == NULL)
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == NULL)
return -ENODEV;
- for (np = np->child; np != NULL; np = np->sibling) {
- const u32 *num = get_property(np, "reg", NULL);
- const u32 *rst = get_property(np, "soft-reset", NULL);
+ for (np = cpus->child; np != NULL; np = np->sibling) {
+ const u32 *num = of_get_property(np, "reg", NULL);
+ const u32 *rst = of_get_property(np, "soft-reset", NULL);
if (num == NULL || rst == NULL)
continue;
if (param == *num) {
@@ -1066,6 +1067,7 @@ core99_reset_cpu(struct device_node *node, long param, long value)
break;
}
}
+ of_node_put(cpus);
if (np == NULL || reset_io == 0)
reset_io = dflt_reset_lines[param];
@@ -1095,7 +1097,7 @@ core99_usb_enable(struct device_node *node, long param, long value)
macio->type != macio_intrepid)
return -ENODEV;
- prop = get_property(node, "AAPL,clock-id", NULL);
+ prop = of_get_property(node, "AAPL,clock-id", NULL);
if (!prop)
return -ENODEV;
if (strncmp(prop, "usb0u048", 8) == 0)
@@ -1416,7 +1418,7 @@ static long g5_eth_phy_reset(struct device_node *node, long param, long value)
phy = of_get_next_child(node, NULL);
if (!phy)
return -ENODEV;
- need_reset = device_is_compatible(phy, "B5221");
+ need_reset = of_device_is_compatible(phy, "B5221");
of_node_put(phy);
if (!need_reset)
return 0;
@@ -1497,17 +1499,18 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
unsigned long flags;
struct macio_chip *macio;
struct device_node *np;
+ struct device_node *cpus;
macio = &macio_chips[0];
if (macio->type != macio_keylargo2 && macio->type != macio_shasta)
return -ENODEV;
- np = find_path_device("/cpus");
- if (np == NULL)
+ cpus = of_find_node_by_path("/cpus");
+ if (cpus == NULL)
return -ENODEV;
- for (np = np->child; np != NULL; np = np->sibling) {
- const u32 *num = get_property(np, "reg", NULL);
- const u32 *rst = get_property(np, "soft-reset", NULL);
+ for (np = cpus->child; np != NULL; np = np->sibling) {
+ const u32 *num = of_get_property(np, "reg", NULL);
+ const u32 *rst = of_get_property(np, "soft-reset", NULL);
if (num == NULL || rst == NULL)
continue;
if (param == *num) {
@@ -1515,6 +1518,7 @@ static long g5_reset_cpu(struct device_node *node, long param, long value)
break;
}
}
+ of_node_put(cpus);
if (np == NULL || reset_io == 0)
return -ENODEV;
@@ -2404,14 +2408,15 @@ static int __init probe_motherboard(void)
struct macio_chip *macio = &macio_chips[0];
const char *model = NULL;
struct device_node *dt;
+ int ret = 0;
/* Lookup known motherboard type in device-tree. First try an
* exact match on the "model" property, then try a "compatible"
* match is none is found.
*/
- dt = find_devices("device-tree");
+ dt = of_find_node_by_name(NULL, "device-tree");
if (dt != NULL)
- model = get_property(dt, "model", NULL);
+ model = of_get_property(dt, "model", NULL);
for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
pmac_mb = pmac_mb_defs[i];
@@ -2474,15 +2479,18 @@ static int __init probe_motherboard(void)
break;
#endif /* CONFIG_POWER4 */
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto done;
}
found:
#ifndef CONFIG_POWER4
/* Fixup Hooper vs. Comet */
if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);
- if (!mach_id_ptr)
- return -ENODEV;
+ if (!mach_id_ptr) {
+ ret = -ENODEV;
+ goto done;
+ }
/* Here, I used to disable the media-bay on comet. It
* appears this is wrong, the floppy connector is actually
* a kind of media-bay and works with the current driver.
@@ -2499,18 +2507,26 @@ found:
* that all Apple OF revs did it properly, I do it the paranoid way.
*/
while (uninorth_base && uninorth_rev > 3) {
- struct device_node *np = find_path_device("/cpus");
- if (!np || !np->child) {
+ struct device_node *cpus = of_find_node_by_path("/cpus");
+ struct device_node *np;
+
+ if (!cpus || !cpus->child) {
printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");
+ of_node_put(cpus);
break;
}
- np = np->child;
+ np = cpus->child;
/* Nap mode not supported on SMP */
- if (np->sibling)
+ if (np->sibling) {
+ of_node_put(cpus);
break;
+ }
/* Nap mode not supported if flush-on-lock property is present */
- if (get_property(np, "flush-on-lock", NULL))
+ if (of_get_property(np, "flush-on-lock", NULL)) {
+ of_node_put(cpus);
break;
+ }
+ of_node_put(cpus);
powersave_nap = 1;
printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");
break;
@@ -2532,7 +2548,9 @@ found:
printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
- return 0;
+done:
+ of_node_put(dt);
+ return ret;
}
/* Initialize the Core99 UniNorth host bridge and memory controller
@@ -2558,7 +2576,7 @@ static void __init probe_uninorth(void)
if (uninorth_node == NULL)
return;
- addrp = get_property(uninorth_node, "reg", NULL);
+ addrp = of_get_property(uninorth_node, "reg", NULL);
if (addrp == NULL)
return;
address = of_translate_address(uninorth_node, addrp);
@@ -2606,7 +2624,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {
if (!compat)
break;
- if (device_is_compatible(node, compat))
+ if (of_device_is_compatible(node, compat))
break;
}
if (!node)
@@ -2642,7 +2660,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
return;
}
if (type == macio_keylargo || type == macio_keylargo2) {
- const u32 *did = get_property(node, "device-id", NULL);
+ const u32 *did = of_get_property(node, "device-id", NULL);
if (*did == 0x00000025)
type = macio_pangea;
if (*did == 0x0000003e)
@@ -2655,7 +2673,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
macio_chips[i].base = base;
macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
macio_chips[i].name = macio_names[type];
- revp = get_property(node, "revision-id", NULL);
+ revp = of_get_property(node, "revision-id", NULL);
if (revp)
macio_chips[i].rev = *revp;
printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
@@ -2706,11 +2724,11 @@ initial_serial_shutdown(struct device_node *np)
int port_type = PMAC_SCC_ASYNC;
int modem = 0;
- slots = get_property(np, "slot-names", &len);
- conn = get_property(np, "AAPL,connector", &len);
+ slots = of_get_property(np, "slot-names", &len);
+ conn = of_get_property(np, "AAPL,connector", &len);
if (conn && (strcmp(conn, "infrared") == 0))
port_type = PMAC_SCC_IRDA;
- else if (device_is_compatible(np, "cobalt"))
+ else if (of_device_is_compatible(np, "cobalt"))
modem = 1;
else if (slots && slots->count > 0) {
if (strcmp(slots->name, "IrDA") == 0)
@@ -2735,12 +2753,14 @@ set_initial_features(void)
* differenciate them all and since that hack was there for a long
* time, I'll keep it around
*/
- if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) {
+ if (macio_chips[0].type == macio_ohare) {
struct macio_chip *macio = &macio_chips[0];
- MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
- } else if (macio_chips[0].type == macio_ohare) {
- struct macio_chip *macio = &macio_chips[0];
- MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ np = of_find_node_by_name(NULL, "via-pmu");
+ if (np)
+ MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
+ else
+ MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);
+ of_node_put(np);
} else if (macio_chips[1].type == macio_ohare) {
struct macio_chip *macio = &macio_chips[1];
MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
@@ -2767,7 +2787,7 @@ set_initial_features(void)
*/
np = of_find_node_by_name(NULL, "ethernet");
while(np) {
- if (device_is_compatible(np, "K2-GMAC"))
+ if (of_device_is_compatible(np, "K2-GMAC"))
g5_gmac_enable(np, 0, 1);
np = of_find_node_by_name(np, "ethernet");
}
@@ -2779,7 +2799,7 @@ set_initial_features(void)
*/
np = of_find_node_by_name(NULL, "firewire");
while(np) {
- if (device_is_compatible(np, "pci106b,5811")) {
+ if (of_device_is_compatible(np, "pci106b,5811")) {
macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
g5_fw_enable(np, 0, 1);
}
@@ -2797,8 +2817,8 @@ set_initial_features(void)
np = of_find_node_by_name(NULL, "ethernet");
while(np) {
if (np->parent
- && device_is_compatible(np->parent, "uni-north")
- && device_is_compatible(np, "gmac"))
+ && of_device_is_compatible(np->parent, "uni-north")
+ && of_device_is_compatible(np, "gmac"))
core99_gmac_enable(np, 0, 1);
np = of_find_node_by_name(np, "ethernet");
}
@@ -2811,10 +2831,10 @@ set_initial_features(void)
np = of_find_node_by_name(NULL, "firewire");
while(np) {
if (np->parent
- && device_is_compatible(np->parent, "uni-north")
- && (device_is_compatible(np, "pci106b,18") ||
- device_is_compatible(np, "pci106b,30") ||
- device_is_compatible(np, "pci11c1,5811"))) {
+ && of_device_is_compatible(np->parent, "uni-north")
+ && (of_device_is_compatible(np, "pci106b,18") ||
+ of_device_is_compatible(np, "pci106b,30") ||
+ of_device_is_compatible(np, "pci11c1,5811"))) {
macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
core99_firewire_enable(np, 0, 1);
}
@@ -2825,22 +2845,21 @@ set_initial_features(void)
np = of_find_node_by_name(NULL, "ata-6");
while(np) {
if (np->parent
- && device_is_compatible(np->parent, "uni-north")
- && device_is_compatible(np, "kauai-ata")) {
+ && of_device_is_compatible(np->parent, "uni-north")
+ && of_device_is_compatible(np, "kauai-ata")) {
core99_ata100_enable(np, 1);
}
np = of_find_node_by_name(np, "ata-6");
}
/* Switch airport off */
- np = find_devices("radio");
- while(np) {
+ for_each_node_by_name(np, "radio") {
if (np && np->parent == macio_chips[0].of_node) {
macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;
core99_airport_enable(np, 0, 0);
}
- np = np->next;
}
+ of_node_put(np);
}
/* On all machines that support sound PM, switch sound off */
@@ -2860,16 +2879,12 @@ set_initial_features(void)
#endif /* CONFIG_POWER4 */
/* On all machines, switch modem & serial ports off */
- np = find_devices("ch-a");
- while(np) {
+ for_each_node_by_name(np, "ch-a")
initial_serial_shutdown(np);
- np = np->next;
- }
- np = find_devices("ch-b");
- while(np) {
+ of_node_put(np);
+ for_each_node_by_name(np, "ch-b")
initial_serial_shutdown(np);
- np = np->next;
- }
+ of_node_put(np);
}
void __init
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index bfc4829162f..3f507ab9c5e 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -491,7 +491,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
* on all i2c keywest nodes so far ... we would have to fallback
* to macio parsing if that wasn't the case
*/
- addrp = get_property(np, "AAPL,address", NULL);
+ addrp = of_get_property(np, "AAPL,address", NULL);
if (addrp == NULL) {
printk(KERN_ERR "low_i2c: Can't find address for %s\n",
np->full_name);
@@ -505,13 +505,13 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
host->timeout_timer.function = kw_i2c_timeout;
host->timeout_timer.data = (unsigned long)host;
- psteps = get_property(np, "AAPL,address-step", NULL);
+ psteps = of_get_property(np, "AAPL,address-step", NULL);
steps = psteps ? (*psteps) : 0x10;
for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
steps >>= 1;
/* Select interface rate */
host->speed = KW_I2C_MODE_25KHZ;
- prate = get_property(np, "AAPL,i2c-rate", NULL);
+ prate = of_get_property(np, "AAPL,i2c-rate", NULL);
if (prate) switch(*prate) {
case 100:
host->speed = KW_I2C_MODE_100KHZ;
@@ -619,7 +619,7 @@ static void __init kw_i2c_probe(void)
} else {
for (child = NULL;
(child = of_get_next_child(np, child)) != NULL;) {
- const u32 *reg = get_property(child,
+ const u32 *reg = of_get_property(child,
"reg", NULL);
if (reg == NULL)
continue;
@@ -905,7 +905,7 @@ static void __init smu_i2c_probe(void)
if (strcmp(busnode->type, "i2c") &&
strcmp(busnode->type, "i2c-bus"))
continue;
- reg = get_property(busnode, "reg", NULL);
+ reg = of_get_property(busnode, "reg", NULL);
if (reg == NULL)
continue;
@@ -950,7 +950,8 @@ struct pmac_i2c_bus *pmac_i2c_find_bus(struct device_node *node)
if (p == bus->busnode) {
if (prev && bus->flags & pmac_i2c_multibus) {
const u32 *reg;
- reg = get_property(prev, "reg", NULL);
+ reg = of_get_property(prev, "reg",
+ NULL);
if (!reg)
continue;
if (((*reg) >> 8) != bus->channel)
@@ -971,7 +972,7 @@ EXPORT_SYMBOL_GPL(pmac_i2c_find_bus);
u8 pmac_i2c_get_dev_addr(struct device_node *device)
{
- const u32 *reg = get_property(device, "reg", NULL);
+ const u32 *reg = of_get_property(device, "reg", NULL);
if (reg == NULL)
return 0;
@@ -1206,7 +1207,7 @@ static void pmac_i2c_devscan(void (*callback)(struct device_node *dev,
if (strcmp(np->name, p->name))
continue;
if (p->compatible &&
- !device_is_compatible(np, p->compatible))
+ !of_device_is_compatible(np, p->compatible))
continue;
if (p->quirks & pmac_i2c_quirk_skip)
break;
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 692945c1491..c6f0f9e738e 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -553,7 +553,7 @@ static int __init core99_nvram_setup(struct device_node *dp, unsigned long addr)
* identify the chip using flash id commands and base ourselves on
* a list of known chips IDs
*/
- if (device_is_compatible(dp, "amd-0137")) {
+ if (of_device_is_compatible(dp, "amd-0137")) {
core99_erase_bank = amd_erase_bank;
core99_write_bank = amd_write_bank;
} else {
@@ -588,7 +588,7 @@ int __init pmac_nvram_init(void)
}
}
- is_core_99 = device_is_compatible(dp, "nvram,flash");
+ is_core_99 = of_device_is_compatible(dp, "nvram,flash");
if (is_core_99) {
err = core99_nvram_setup(dp, r1.start);
goto bail;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 6fbac308ded..c4af9e21ac9 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -70,11 +70,11 @@ static int __init fixup_one_level_bus_range(struct device_node *node, int higher
int len;
/* For PCI<->PCI bridges or CardBus bridges, we go down */
- class_code = get_property(node, "class-code", NULL);
+ class_code = of_get_property(node, "class-code", NULL);
if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
continue;
- bus_range = get_property(node, "bus-range", &len);
+ bus_range = of_get_property(node, "bus-range", &len);
if (bus_range != NULL && len > 2 * sizeof(int)) {
if (bus_range[1] > higher)
higher = bus_range[1];
@@ -100,7 +100,7 @@ static void __init fixup_bus_range(struct device_node *bridge)
if (prop == NULL || prop->length < 2 * sizeof(int))
return;
- bus_range = (int *)prop->value;
+ bus_range = prop->value;
bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
}
@@ -246,8 +246,8 @@ static int chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
if (np == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
- vendor = get_property(np, "vendor-id", NULL);
- device = get_property(np, "device-id", NULL);
+ vendor = of_get_property(np, "vendor-id", NULL);
+ device = of_get_property(np, "device-id", NULL);
if (vendor == NULL || device == NULL)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -622,13 +622,14 @@ static void __init init_p2pbridge(void)
/* XXX it would be better here to identify the specific
PCI-PCI bridge chip we have. */
- if ((p2pbridge = find_devices("pci-bridge")) == 0
+ p2pbridge = of_find_node_by_name(NULL, "pci-bridge");
+ if (p2pbridge == NULL
|| p2pbridge->parent == NULL
|| strcmp(p2pbridge->parent->name, "pci") != 0)
- return;
+ goto done;
if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
DBG("Can't find PCI infos for PCI<->PCI bridge\n");
- return;
+ goto done;
}
/* Warning: At this point, we have not yet renumbered all busses.
* So we must use OF walking to find out hose
@@ -636,16 +637,18 @@ static void __init init_p2pbridge(void)
hose = pci_find_hose_for_OF_device(p2pbridge);
if (!hose) {
DBG("Can't find hose for PCI<->PCI bridge\n");
- return;
+ goto done;
}
if (early_read_config_word(hose, bus, devfn,
PCI_BRIDGE_CONTROL, &val) < 0) {
printk(KERN_ERR "init_p2pbridge: couldn't read bridge"
" control\n");
- return;
+ goto done;
}
val &= ~PCI_BRIDGE_CTL_MASTER_ABORT;
early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
+done:
+ of_node_put(p2pbridge);
}
static void __init init_second_ohare(void)
@@ -691,17 +694,17 @@ static void __init fixup_nec_usb2(void)
const u32 *prop;
u8 bus, devfn;
- prop = get_property(nec, "vendor-id", NULL);
+ prop = of_get_property(nec, "vendor-id", NULL);
if (prop == NULL)
continue;
if (0x1033 != *prop)
continue;
- prop = get_property(nec, "device-id", NULL);
+ prop = of_get_property(nec, "device-id", NULL);
if (prop == NULL)
continue;
if (0x0035 != *prop)
continue;
- prop = get_property(nec, "reg", NULL);
+ prop = of_get_property(nec, "reg", NULL);
if (prop == NULL)
continue;
devfn = (prop[0] >> 8) & 0xff;
@@ -909,7 +912,7 @@ static int __init add_bridge(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
@@ -931,15 +934,15 @@ static int __init add_bridge(struct device_node *dev)
/* 64 bits only bridges */
#ifdef CONFIG_PPC64
- if (device_is_compatible(dev, "u3-agp")) {
+ if (of_device_is_compatible(dev, "u3-agp")) {
setup_u3_agp(hose);
disp_name = "U3-AGP";
primary = 0;
- } else if (device_is_compatible(dev, "u3-ht")) {
+ } else if (of_device_is_compatible(dev, "u3-ht")) {
setup_u3_ht(hose);
disp_name = "U3-HT";
primary = 1;
- } else if (device_is_compatible(dev, "u4-pcie")) {
+ } else if (of_device_is_compatible(dev, "u4-pcie")) {
setup_u4_pcie(hose);
disp_name = "U4-PCIE";
primary = 0;
@@ -950,7 +953,7 @@ static int __init add_bridge(struct device_node *dev)
/* 32 bits only bridges */
#ifdef CONFIG_PPC32
- if (device_is_compatible(dev, "uni-north")) {
+ if (of_device_is_compatible(dev, "uni-north")) {
primary = setup_uninorth(hose, &rsrc);
disp_name = "UniNorth";
} else if (strcmp(dev->name, "pci") == 0) {
@@ -1126,21 +1129,21 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
return 0;
uninorth_child = node->parent &&
- device_is_compatible(node->parent, "uni-north");
+ of_device_is_compatible(node->parent, "uni-north");
/* Firewire & GMAC were disabled after PCI probe, the driver is
* claiming them, we must re-enable them now.
*/
if (uninorth_child && !strcmp(node->name, "firewire") &&
- (device_is_compatible(node, "pci106b,18") ||
- device_is_compatible(node, "pci106b,30") ||
- device_is_compatible(node, "pci11c1,5811"))) {
+ (of_device_is_compatible(node, "pci106b,18") ||
+ of_device_is_compatible(node, "pci106b,30") ||
+ of_device_is_compatible(node, "pci11c1,5811"))) {
pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, node, 0, 1);
pmac_call_feature(PMAC_FTR_1394_ENABLE, node, 0, 1);
updatecfg = 1;
}
if (uninorth_child && !strcmp(node->name, "ethernet") &&
- device_is_compatible(node, "gmac")) {
+ of_device_is_compatible(node, "gmac")) {
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, node, 0, 1);
updatecfg = 1;
}
@@ -1199,24 +1202,22 @@ void __init pmac_pcibios_after_init(void)
}
#endif /* CONFIG_BLK_DEV_IDE */
- nd = find_devices("firewire");
- while (nd) {
- if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
- device_is_compatible(nd, "pci106b,30") ||
- device_is_compatible(nd, "pci11c1,5811"))
- && device_is_compatible(nd->parent, "uni-north")) {
+ for_each_node_by_name(nd, "firewire") {
+ if (nd->parent && (of_device_is_compatible(nd, "pci106b,18") ||
+ of_device_is_compatible(nd, "pci106b,30") ||
+ of_device_is_compatible(nd, "pci11c1,5811"))
+ && of_device_is_compatible(nd->parent, "uni-north")) {
pmac_call_feature(PMAC_FTR_1394_ENABLE, nd, 0, 0);
pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, nd, 0, 0);
}
- nd = nd->next;
}
- nd = find_devices("ethernet");
- while (nd) {
- if (nd->parent && device_is_compatible(nd, "gmac")
- && device_is_compatible(nd->parent, "uni-north"))
+ of_node_put(nd);
+ for_each_node_by_name(nd, "ethernet") {
+ if (nd->parent && of_device_is_compatible(nd, "gmac")
+ && of_device_is_compatible(nd->parent, "uni-north"))
pmac_call_feature(PMAC_FTR_GMAC_ENABLE, nd, 0, 0);
- nd = nd->next;
}
+ of_node_put(nd);
}
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 5c6c15c5f9a..45d54b9ad9e 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -114,7 +114,7 @@ static void macio_gpio_init_one(struct macio_chip *macio)
* we just create them all
*/
for (gp = NULL; (gp = of_get_next_child(gparent, gp)) != NULL;) {
- const u32 *reg = get_property(gp, "reg", NULL);
+ const u32 *reg = of_get_property(gp, "reg", NULL);
unsigned long offset;
if (reg == NULL)
continue;
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c
index 7651f278615..85434231ae1 100644
--- a/arch/powerpc/platforms/powermac/pfunc_core.c
+++ b/arch/powerpc/platforms/powermac/pfunc_core.c
@@ -692,8 +692,7 @@ static int pmf_add_functions(struct pmf_device *dev, void *driverdata)
name = pp->name + plen;
if (strlen(name) && pp->length >= 12)
count += pmf_add_function_prop(dev, driverdata, name,
- (u32 *)pp->value,
- pp->length);
+ pp->value, pp->length);
}
return count;
}
@@ -821,7 +820,7 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
* one, then we fallback to a direct call attempt
*/
snprintf(fname, 63, "platform-%s", name);
- prop = get_property(target, fname, NULL);
+ prop = of_get_property(target, fname, NULL);
if (prop == NULL)
goto find_it;
ph = *prop;
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 5e5c0e4add9..87cd6805171 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -364,7 +364,7 @@ static void __init pmac_pic_probe_oldstyle(void)
slave = of_find_node_by_name(master, "mac-io");
/* Check ordering of master & slave */
- if (device_is_compatible(master, "gatwick")) {
+ if (of_device_is_compatible(master, "gatwick")) {
struct device_node *tmp;
BUG_ON(slave == NULL);
tmp = master;
@@ -482,14 +482,14 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np,
pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0);
flags |= MPIC_WANTS_RESET;
- if (get_property(np, "big-endian", NULL))
+ if (of_get_property(np, "big-endian", NULL))
flags |= MPIC_BIG_ENDIAN;
/* Primary Big Endian means HT interrupts. This is quite dodgy
* but works until I find a better way
*/
if (master && (flags & MPIC_BIG_ENDIAN))
- flags |= MPIC_BROKEN_U3;
+ flags |= MPIC_U3_HT_IRQS;
mpic = mpic_alloc(np, r.start, flags, 0, 0, name);
if (mpic == NULL)
@@ -510,7 +510,7 @@ static int __init pmac_pic_probe_mpic(void)
for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
!= NULL;) {
if (master == NULL &&
- get_property(np, "interrupts", NULL) == NULL)
+ of_get_property(np, "interrupts", NULL) == NULL)
master = of_node_get(np);
else if (slave == NULL)
slave = of_node_get(np);
@@ -575,7 +575,7 @@ void __init pmac_pic_init(void)
#ifdef CONFIG_PPC32
if (!pmac_newworld)
flags |= OF_IMAP_OLDWORLD_MAC;
- if (get_property(of_chosen, "linux,bootx", NULL) != NULL)
+ if (of_get_property(of_chosen, "linux,bootx", NULL) != NULL)
flags |= OF_IMAP_NO_PHANDLE;
#endif /* CONFIG_PPC_32 */
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 651fa424ea0..a410bc76a8a 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -42,7 +42,6 @@
#include <linux/initrd.h>
#include <linux/vt_kern.h>
#include <linux/console.h>
-#include <linux/ide.h>
#include <linux/pci.h>
#include <linux/adb.h>
#include <linux/cuda.h>
@@ -135,12 +134,12 @@ static void pmac_show_cpuinfo(struct seq_file *m)
seq_printf(m, "machine\t\t: ");
np = of_find_node_by_path("/");
if (np != NULL) {
- pp = get_property(np, "model", NULL);
+ pp = of_get_property(np, "model", NULL);
if (pp != NULL)
seq_printf(m, "%s\n", pp);
else
seq_printf(m, "PowerMac\n");
- pp = get_property(np, "compatible", &plen);
+ pp = of_get_property(np, "compatible", &plen);
if (pp != NULL) {
seq_printf(m, "motherboard\t:");
while (plen > 0) {
@@ -164,11 +163,13 @@ static void pmac_show_cpuinfo(struct seq_file *m)
if (np == NULL)
np = of_find_node_by_type(NULL, "cache");
if (np != NULL) {
- const unsigned int *ic = get_property(np, "i-cache-size", NULL);
- const unsigned int *dc = get_property(np, "d-cache-size", NULL);
+ const unsigned int *ic =
+ of_get_property(np, "i-cache-size", NULL);
+ const unsigned int *dc =
+ of_get_property(np, "d-cache-size", NULL);
seq_printf(m, "L2 cache\t:");
has_l2cache = 1;
- if (get_property(np, "cache-unified", NULL) != 0 && dc) {
+ if (of_get_property(np, "cache-unified", NULL) != 0 && dc) {
seq_printf(m, " %dK unified", *dc / 1024);
} else {
if (ic)
@@ -177,7 +178,7 @@ static void pmac_show_cpuinfo(struct seq_file *m)
seq_printf(m, "%s %dK data",
(ic? " +": ""), *dc / 1024);
}
- pp = get_property(np, "ram-type", NULL);
+ pp = of_get_property(np, "ram-type", NULL);
if (pp)
seq_printf(m, " %s", pp);
seq_printf(m, "\n");
@@ -192,8 +193,11 @@ static void pmac_show_cpuinfo(struct seq_file *m)
#ifndef CONFIG_ADB_CUDA
int find_via_cuda(void)
{
- if (!find_devices("via-cuda"))
+ struct device_node *dn = of_find_node_by_name(NULL, "via-cuda");
+
+ if (!dn)
return 0;
+ of_node_put(dn);
printk("WARNING ! Your machine is CUDA-based but your kernel\n");
printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n");
return 0;
@@ -203,8 +207,11 @@ int find_via_cuda(void)
#ifndef CONFIG_ADB_PMU
int find_via_pmu(void)
{
- if (!find_devices("via-pmu"))
+ struct device_node *dn = of_find_node_by_name(NULL, "via-pmu");
+
+ if (!dn)
return 0;
+ of_node_put(dn);
printk("WARNING ! Your machine is PMU-based but your kernel\n");
printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");
return 0;
@@ -224,6 +231,8 @@ static volatile u32 *sysctrl_regs;
static void __init ohare_init(void)
{
+ struct device_node *dn;
+
/* this area has the CPU identification register
and some registers used by smp boards */
sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
@@ -233,7 +242,9 @@ static void __init ohare_init(void)
* We assume that we have a PSX memory controller iff
* we have an ohare I/O controller.
*/
- if (find_devices("ohare") != NULL) {
+ dn = of_find_node_by_name(NULL, "ohare");
+ if (dn) {
+ of_node_put(dn);
if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {
if (sysctrl_regs[4] & 0x10)
sysctrl_regs[4] |= 0x04000020;
@@ -249,18 +260,19 @@ static void __init l2cr_init(void)
{
/* Checks "l2cr-value" property in the registry */
if (cpu_has_feature(CPU_FTR_L2CR)) {
- struct device_node *np = find_devices("cpus");
+ struct device_node *np = of_find_node_by_name(NULL, "cpus");
if (np == 0)
- np = find_type_devices("cpu");
+ np = of_find_node_by_type(NULL, "cpu");
if (np != 0) {
const unsigned int *l2cr =
- get_property(np, "l2cr-value", NULL);
+ of_get_property(np, "l2cr-value", NULL);
if (l2cr != 0) {
ppc_override_l2cr = 1;
ppc_override_l2cr_value = *l2cr;
_set_L2CR(0);
_set_L2CR(ppc_override_l2cr_value);
}
+ of_node_put(np);
}
}
@@ -286,7 +298,7 @@ static void __init pmac_setup_arch(void)
loops_per_jiffy = 50000000 / HZ;
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu != NULL) {
- fp = get_property(cpu, "clock-frequency", NULL);
+ fp = of_get_property(cpu, "clock-frequency", NULL);
if (fp != NULL) {
if (pvr >= 0x30 && pvr < 0x80)
/* PPC970 etc. */
@@ -303,7 +315,7 @@ static void __init pmac_setup_arch(void)
/* See if newworld or oldworld */
for (ic = NULL; (ic = of_find_all_nodes(ic)) != NULL; )
- if (get_property(ic, "interrupt-controller", NULL))
+ if (of_get_property(ic, "interrupt-controller", NULL))
break;
if (ic) {
pmac_newworld = 1;
@@ -341,8 +353,15 @@ static void __init pmac_setup_arch(void)
#ifdef CONFIG_SMP
/* Check for Core99 */
- if (find_devices("uni-n") || find_devices("u3") || find_devices("u4"))
+ ic = of_find_node_by_name(NULL, "uni-n");
+ if (!ic)
+ ic = of_find_node_by_name(NULL, "u3");
+ if (!ic)
+ ic = of_find_node_by_name(NULL, "u4");
+ if (ic) {
+ of_node_put(ic);
smp_ops = &core99_smp_ops;
+ }
#ifdef CONFIG_PPC32
else
smp_ops = &psurge_smp_ops;
@@ -420,76 +439,14 @@ static void __init find_boot_device(void)
#endif
}
-/* TODO: Merge the suspend-to-ram with the common code !!!
- * currently, this is a stub implementation for suspend-to-disk
- * only
- */
-
-#ifdef CONFIG_SOFTWARE_SUSPEND
-
-static int pmac_pm_prepare(suspend_state_t state)
-{
- printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
- return 0;
-}
-
-static int pmac_pm_enter(suspend_state_t state)
-{
- printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
- /* Giveup the lazy FPU & vec so we don't have to back them
- * up from the low level code
- */
- enable_kernel_fp();
-
-#ifdef CONFIG_ALTIVEC
- if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC)
- enable_kernel_altivec();
-#endif /* CONFIG_ALTIVEC */
-
- return 0;
-}
-
-static int pmac_pm_finish(suspend_state_t state)
-{
- printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
-
- /* Restore userland MMU context */
- set_context(current->active_mm->context.id, current->active_mm->pgd);
-
- return 0;
-}
-
-static int pmac_pm_valid(suspend_state_t state)
-{
- switch (state) {
- case PM_SUSPEND_DISK:
- return 1;
- /* can't do any other states via generic mechanism yet */
- default:
- return 0;
- }
-}
-
-static struct pm_ops pmac_pm_ops = {
- .pm_disk_mode = PM_DISK_SHUTDOWN,
- .prepare = pmac_pm_prepare,
- .enter = pmac_pm_enter,
- .finish = pmac_pm_finish,
- .valid = pmac_pm_valid,
-};
-
-#endif /* CONFIG_SOFTWARE_SUSPEND */
-
static int initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
-#ifdef CONFIG_SOFTWARE_SUSPEND
- pm_set_ops(&pmac_pm_ops);
-#endif /* CONFIG_SOFTWARE_SUSPEND */
+ /* this is udbg (which is __init) and we can later use it during
+ * cpu hotplug (in smp_core99_kick_cpu) */
+ ppc_md.progress = NULL;
return 0;
}
@@ -616,15 +573,6 @@ static void __init pmac_init_early(void)
#endif
}
-/*
- * pmac has no legacy IO, anything calling this function has to
- * fail or bad things will happen
- */
-static int pmac_check_legacy_ioport(unsigned int baseport)
-{
- return -ENODEV;
-}
-
static int __init pmac_declare_of_platform_devices(void)
{
struct device_node *np;
@@ -711,12 +659,57 @@ static int pmac_pci_probe_mode(struct pci_bus *bus)
/* We need to use normal PCI probing for the AGP bus,
* since the device for the AGP bridge isn't in the tree.
*/
- if (bus->self == NULL && (device_is_compatible(node, "u3-agp") ||
- device_is_compatible(node, "u4-pcie")))
+ if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") ||
+ of_device_is_compatible(node, "u4-pcie")))
return PCI_PROBE_NORMAL;
return PCI_PROBE_DEVTREE;
}
-#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+/* access per cpu vars from generic smp.c */
+DECLARE_PER_CPU(int, cpu_state);
+
+static void pmac_cpu_die(void)
+{
+ /*
+ * turn off as much as possible, we'll be
+ * kicked out as this will only be invoked
+ * on core99 platforms for now ...
+ */
+
+ printk(KERN_INFO "CPU#%d offline\n", smp_processor_id());
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+ smp_wmb();
+
+ /*
+ * during the path that leads here preemption is disabled,
+ * reenable it now so that when coming up preempt count is
+ * zero correctly
+ */
+ preempt_enable();
+
+ /*
+ * hard-disable interrupts for the non-NAP case, the NAP code
+ * needs to re-enable interrupts (but soft-disables them)
+ */
+ hard_irq_disable();
+
+ while (1) {
+ /* let's not take timer interrupts too often ... */
+ set_dec(0x7fffffff);
+
+ /* should always be true at this point */
+ if (cpu_has_feature(CPU_FTR_CAN_NAP))
+ power4_cpu_offline_powersave();
+ else {
+ HMT_low();
+ HMT_very_low();
+ }
+ }
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#endif /* CONFIG_PPC64 */
define_machine(powermac) {
.name = "PowerMac",
@@ -736,7 +729,6 @@ define_machine(powermac) {
.get_rtc_time = pmac_get_rtc_time,
.calibrate_decr = pmac_calibrate_decr,
.feature_call = pmac_do_feature_call,
- .check_legacy_ioport = pmac_check_legacy_ioport,
.progress = udbg_progress,
#ifdef CONFIG_PPC64
.pci_probe_mode = pmac_pci_probe_mode,
@@ -754,6 +746,6 @@ define_machine(powermac) {
.phys_mem_access_prot = pci_phys_mem_access_prot,
#endif
#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
- .cpu_die = generic_mach_cpu_die,
+ .cpu_die = pmac_cpu_die,
#endif
};
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index d73fb73802b..686ed82bde7 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -24,7 +24,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
@@ -264,6 +263,7 @@ static void __init psurge_quad_init(void)
static int __init smp_psurge_probe(void)
{
int i, ncpus;
+ struct device_node *dn;
/* We don't do SMP on the PPC601 -- paulus */
if (PVR_VER(mfspr(SPRN_PVR)) == 1)
@@ -279,8 +279,10 @@ static int __init smp_psurge_probe(void)
* in the hammerhead memory controller in the case of the
* dual-cpu powersurge board. -- paulus.
*/
- if (find_devices("hammerhead") == NULL)
+ dn = of_find_node_by_name(NULL, "hammerhead");
+ if (dn == NULL)
return 1;
+ of_node_put(dn);
hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
@@ -559,7 +561,7 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
/* Look for the clock chip */
while ((cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL) {
p = of_get_parent(cc);
- ok = p && device_is_compatible(p, "uni-n-i2c");
+ ok = p && of_device_is_compatible(p, "uni-n-i2c");
of_node_put(p);
if (!ok)
continue;
@@ -567,16 +569,16 @@ static void __init smp_core99_setup_i2c_hwsync(int ncpus)
pmac_tb_clock_chip_host = pmac_i2c_find_bus(cc);
if (pmac_tb_clock_chip_host == NULL)
continue;
- reg = get_property(cc, "reg", NULL);
+ reg = of_get_property(cc, "reg", NULL);
if (reg == NULL)
continue;
switch (*reg) {
case 0xd2:
- if (device_is_compatible(cc,"pulsar-legacy-slewing")) {
+ if (of_device_is_compatible(cc,"pulsar-legacy-slewing")) {
pmac_tb_freeze = smp_core99_pulsar_tb_freeze;
pmac_tb_pulsar_addr = 0xd2;
name = "Pulsar";
- } else if (device_is_compatible(cc, "cy28508")) {
+ } else if (of_device_is_compatible(cc, "cy28508")) {
pmac_tb_freeze = smp_core99_cypress_tb_freeze;
name = "Cypress";
}
@@ -695,7 +697,7 @@ static void __init smp_core99_setup(int ncpus)
struct device_node *cpus =
of_find_node_by_path("/cpus");
if (cpus &&
- get_property(cpus, "platform-cpu-timebase", NULL)) {
+ of_get_property(cpus, "platform-cpu-timebase", NULL)) {
pmac_tb_freeze = smp_core99_pfunc_tb_freeze;
printk(KERN_INFO "Processor timebase sync using"
" platform function\n");
@@ -712,7 +714,7 @@ static void __init smp_core99_setup(int ncpus)
core99_tb_gpio = KL_GPIO_TB_ENABLE; /* default value */
cpu = of_find_node_by_type(NULL, "cpu");
if (cpu != NULL) {
- tbprop = get_property(cpu, "timebase-enable", NULL);
+ tbprop = of_get_property(cpu, "timebase-enable", NULL);
if (tbprop)
core99_tb_gpio = *tbprop;
of_node_put(cpu);
@@ -897,7 +899,7 @@ void smp_core99_cpu_die(unsigned int cpu)
cpu_dead[cpu] = 0;
}
-#endif
+#endif /* CONFIG_HOTPLUG_CPU && CONFIG_PP32 */
/* Core99 Macs (dual G4s and G5s) */
struct smp_ops_t core99_smp_ops = {
@@ -907,8 +909,16 @@ struct smp_ops_t core99_smp_ops = {
.setup_cpu = smp_core99_setup_cpu,
.give_timebase = smp_core99_give_timebase,
.take_timebase = smp_core99_take_timebase,
-#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC32)
+#if defined(CONFIG_HOTPLUG_CPU)
+# if defined(CONFIG_PPC32)
.cpu_disable = smp_core99_cpu_disable,
.cpu_die = smp_core99_cpu_die,
+# endif
+# if defined(CONFIG_PPC64)
+ .cpu_disable = generic_cpu_disable,
+ .cpu_die = generic_cpu_die,
+ /* intentionally do *NOT* assign cpu_enable,
+ * the generic code will use kick_cpu then! */
+# endif
#endif
};
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index a4173906e94..bf9da56942e 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -297,49 +297,11 @@ int __init via_calibrate_decr(void)
}
#endif
-#ifdef CONFIG_PM
-/*
- * Reset the time after a sleep.
- */
-static int
-time_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- static unsigned long time_diff;
- unsigned long flags;
- unsigned long seq;
- struct timespec tv;
-
- switch (when) {
- case PBOOK_SLEEP_NOW:
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- time_diff = xtime.tv_sec - pmac_get_boot_time();
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- break;
- case PBOOK_WAKE:
- tv.tv_sec = pmac_get_boot_time() + time_diff;
- tv.tv_nsec = 0;
- do_settimeofday(&tv);
- break;
- }
- return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier time_sleep_notifier = {
- time_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PM */
-
/*
* Query the OF and get the decr frequency.
*/
void __init pmac_calibrate_decr(void)
{
-#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
- /* XXX why here? */
- pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif
-
generic_calibrate_decr();
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index 379db05b008..47de4d3fc16 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -81,7 +81,7 @@ void udbg_scc_init(int force_scc)
macio = of_get_parent(escc);
if (macio == NULL)
goto bail;
- path = get_property(of_chosen, "linux,stdout-path", NULL);
+ path = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (path != NULL)
stdout = of_find_node_by_path(path);
for (ch = NULL; (ch = of_get_next_child(escc, ch)) != NULL;) {
@@ -96,13 +96,13 @@ void udbg_scc_init(int force_scc)
ch = ch_def ? ch_def : ch_a;
/* Get address within mac-io ASIC */
- reg = get_property(escc, "reg", NULL);
+ reg = of_get_property(escc, "reg", NULL);
if (reg == NULL)
goto bail;
addr = reg[0];
/* Get address of mac-io PCI itself */
- reg = get_property(macio, "assigned-addresses", NULL);
+ reg = of_get_property(macio, "assigned-addresses", NULL);
if (reg == NULL)
goto bail;
addr += reg[2];
diff --git a/arch/powerpc/platforms/prep/Kconfig b/arch/powerpc/platforms/prep/Kconfig
index 673ac47a162..29d411279b0 100644
--- a/arch/powerpc/platforms/prep/Kconfig
+++ b/arch/powerpc/platforms/prep/Kconfig
@@ -1,3 +1,12 @@
+config PPC_PREP
+ bool "PowerPC Reference Platform (PReP) based machines"
+ depends on PPC_MULTIPLATFORM && PPC32 && BROKEN
+ select MPIC
+ select PPC_I8259
+ select PPC_INDIRECT_PCI
+ select PPC_UDBG_16550
+ select PPC_NATIVE
+ default n
config PREP_RESIDUAL
bool "Support for PReP Residual Data"
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 1a481a60a88..40f0008af4d 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -1,3 +1,19 @@
+config PPC_PS3
+ bool "Sony PS3 (incomplete)"
+ depends on PPC_MULTIPLATFORM && PPC64
+ select PPC_CELL
+ select USB_ARCH_HAS_OHCI
+ select USB_OHCI_LITTLE_ENDIAN
+ select USB_OHCI_BIG_ENDIAN_MMIO
+ select USB_ARCH_HAS_EHCI
+ select USB_EHCI_BIG_ENDIAN_MMIO
+ help
+ This option enables support for the Sony PS3 game console
+ and other platforms using the PS3 hypervisor.
+ Support for this platform is not yet complete, so
+ enabling this will not result in a bootable kernel on a
+ PS3 system.
+
menu "PS3 Platform Options"
depends on PPC_PS3
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index e12e59fea13..a1409e450c7 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -39,7 +39,7 @@ static unsigned long htab_addr;
static unsigned char *bolttab;
static unsigned char *inusetab;
-static spinlock_t ps3_bolttab_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ps3_bolttab_lock);
#define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
_debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
@@ -273,7 +273,8 @@ void __init ps3_map_htab(void)
result = lv1_map_htab(0, &htab_addr);
- htab = (hpte_t *)__ioremap(htab_addr, htab_size, PAGE_READONLY_X);
+ htab = (hpte_t *)__ioremap(htab_addr, htab_size,
+ pgprot_val(PAGE_READONLY_X));
DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__,
htab_addr, (unsigned long)htab);
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 631c3009561..9da82c266ba 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -89,7 +89,18 @@ struct ps3_private {
static DEFINE_PER_CPU(struct ps3_private, ps3_private);
-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+/**
+ * ps3_virq_setup - virq related setup.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @outlet: The HV outlet from the various create outlet routines.
+ * @virq: The assigned Linux virq.
+ *
+ * Calls irq_create_mapping() to get a virq and sets the chip data to
+ * ps3_private data.
+ */
+
+int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
unsigned int *virq)
{
int result;
@@ -111,17 +122,6 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
goto fail_create;
}
- /* Binds outlet to cpu + virq. */
-
- result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
-
- if (result) {
- pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
- __func__, __LINE__, ps3_result(result));
- result = -EPERM;
- goto fail_connect;
- }
-
pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
outlet, cpu, *virq);
@@ -136,94 +136,118 @@ int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
return result;
fail_set:
- lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
-fail_connect:
irq_dispose_mapping(*virq);
fail_create:
return result;
}
-EXPORT_SYMBOL_GPL(ps3_alloc_irq);
-int ps3_free_irq(unsigned int virq)
+/**
+ * ps3_virq_destroy - virq related teardown.
+ * @virq: The assigned Linux virq.
+ *
+ * Clears chip data and calls irq_dispose_mapping() for the virq.
+ */
+
+int ps3_virq_destroy(unsigned int virq)
{
- int result;
const struct ps3_private *pd = get_irq_chip_data(virq);
pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
pd->node, pd->cpu, virq);
- result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
-
- if (result)
- pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
- __func__, __LINE__, ps3_result(result));
-
set_irq_chip_data(virq, NULL);
irq_dispose_mapping(virq);
- return result;
+
+ pr_debug("%s:%d <-\n", __func__, __LINE__);
+ return 0;
}
-EXPORT_SYMBOL_GPL(ps3_free_irq);
/**
- * ps3_alloc_io_irq - Assign a virq to a system bus device.
+ * ps3_irq_plug_setup - Generic outlet and virq related setup.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
- * @interrupt_id: The device interrupt id read from the system repository.
+ * @outlet: The HV outlet from the various create outlet routines.
* @virq: The assigned Linux virq.
*
- * An io irq represents a non-virtualized device interrupt. interrupt_id
- * coresponds to the interrupt number of the interrupt controller.
+ * Sets up virq and connects the irq plug.
*/
-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
unsigned int *virq)
{
int result;
- unsigned long outlet;
+ struct ps3_private *pd;
- result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
+ result = ps3_virq_setup(cpu, outlet, virq);
if (result) {
- pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
- __func__, __LINE__, ps3_result(result));
- return result;
+ pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
+ goto fail_setup;
}
- result = ps3_alloc_irq(cpu, outlet, virq);
- BUG_ON(result);
+ pd = get_irq_chip_data(*virq);
+
+ /* Binds outlet to cpu + virq. */
+
+ result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
+ if (result) {
+ pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ result = -EPERM;
+ goto fail_connect;
+ }
+
+ return result;
+
+fail_connect:
+ ps3_virq_destroy(*virq);
+fail_setup:
return result;
}
-EXPORT_SYMBOL_GPL(ps3_alloc_io_irq);
+EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);
+
+/**
+ * ps3_irq_plug_destroy - Generic outlet and virq related teardown.
+ * @virq: The assigned Linux virq.
+ *
+ * Disconnects the irq plug and tears down virq.
+ * Do not call for system bus event interrupts setup with
+ * ps3_sb_event_receive_port_setup().
+ */
-int ps3_free_io_irq(unsigned int virq)
+int ps3_irq_plug_destroy(unsigned int virq)
{
int result;
+ const struct ps3_private *pd = get_irq_chip_data(virq);
- result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
+ pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
+ pd->node, pd->cpu, virq);
+
+ result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
if (result)
- pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
- __func__, __LINE__, ps3_result(result));
+ pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
- ps3_free_irq(virq);
+ ps3_virq_destroy(virq);
return result;
}
-EXPORT_SYMBOL_GPL(ps3_free_io_irq);
+EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);
/**
- * ps3_alloc_event_irq - Allocate a virq for use with a system event.
+ * ps3_event_receive_port_setup - Setup an event receive port.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
* @virq: The assigned Linux virq.
*
* The virq can be used with lv1_connect_interrupt_event_receive_port() to
- * arrange to receive events, or with ps3_send_event_locally() to signal
- * events.
+ * arrange to receive interrupts from system-bus devices, or with
+ * ps3_send_event_locally() to signal events.
*/
-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
+int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
{
int result;
unsigned long outlet;
@@ -237,17 +261,27 @@ int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
return result;
}
- result = ps3_alloc_irq(cpu, outlet, virq);
+ result = ps3_irq_plug_setup(cpu, outlet, virq);
BUG_ON(result);
return result;
}
+EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);
+
+/**
+ * ps3_event_receive_port_destroy - Destroy an event receive port.
+ * @virq: The assigned Linux virq.
+ *
+ * Since ps3_event_receive_port_destroy destroys the receive port outlet,
+ * SB devices need to call disconnect_interrupt_event_receive_port() before
+ * this.
+ */
-int ps3_free_event_irq(unsigned int virq)
+int ps3_event_receive_port_destroy(unsigned int virq)
{
int result;
- pr_debug(" -> %s:%d\n", __func__, __LINE__);
+ pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq);
result = lv1_destruct_event_receive_port(virq_to_hw(virq));
@@ -255,11 +289,17 @@ int ps3_free_event_irq(unsigned int virq)
pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
__func__, __LINE__, ps3_result(result));
- ps3_free_irq(virq);
+ /* lv1_destruct_event_receive_port() destroys the IRQ plug,
+ * so don't call ps3_irq_plug_destroy() here.
+ */
+
+ result = ps3_virq_destroy(virq);
+ BUG_ON(result);
pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
}
+EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy);
int ps3_send_event_locally(unsigned int virq)
{
@@ -267,7 +307,7 @@ int ps3_send_event_locally(unsigned int virq)
}
/**
- * ps3_connect_event_irq - Assign a virq to a system bus device.
+ * ps3_sb_event_receive_port_setup - Setup a system bus event receive port.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
* @did: The HV device identifier read from the system repository.
@@ -278,13 +318,15 @@ int ps3_send_event_locally(unsigned int virq)
* coresponds to the software interrupt number.
*/
-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
+int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
const struct ps3_device_id *did, unsigned int interrupt_id,
unsigned int *virq)
{
+ /* this should go in system-bus.c */
+
int result;
- result = ps3_alloc_event_irq(cpu, virq);
+ result = ps3_event_receive_port_setup(cpu, virq);
if (result)
return result;
@@ -296,7 +338,7 @@ int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
" failed: %s\n", __func__, __LINE__,
ps3_result(result));
- ps3_free_event_irq(*virq);
+ ps3_event_receive_port_destroy(*virq);
*virq = NO_IRQ;
return result;
}
@@ -306,10 +348,13 @@ int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
return 0;
}
+EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
+int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
unsigned int interrupt_id, unsigned int virq)
{
+ /* this should go in system-bus.c */
+
int result;
pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
@@ -323,14 +368,65 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
" failed: %s\n", __func__, __LINE__,
ps3_result(result));
- ps3_free_event_irq(virq);
+ result = ps3_event_receive_port_destroy(virq);
+ BUG_ON(result);
pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
}
+EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
/**
- * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
+ * ps3_io_irq_setup - Setup a system bus io irq.
+ * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
+ * serviced on.
+ * @interrupt_id: The device interrupt id read from the system repository.
+ * @virq: The assigned Linux virq.
+ *
+ * An io irq represents a non-virtualized device interrupt. interrupt_id
+ * coresponds to the interrupt number of the interrupt controller.
+ */
+
+int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+ unsigned int *virq)
+{
+ int result;
+ unsigned long outlet;
+
+ result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
+
+ if (result) {
+ pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return result;
+ }
+
+ result = ps3_irq_plug_setup(cpu, outlet, virq);
+ BUG_ON(result);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
+
+int ps3_io_irq_destroy(unsigned int virq)
+{
+ int result;
+
+ result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
+
+ if (result)
+ pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ result = ps3_irq_plug_destroy(virq);
+ BUG_ON(result);
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
+
+/**
+ * ps3_vuart_irq_setup - Setup the system virtual uart virq.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
* @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
@@ -340,7 +436,7 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
* freeing the interrupt will return a wrong state error.
*/
-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
unsigned int *virq)
{
int result;
@@ -359,13 +455,13 @@ int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
return result;
}
- result = ps3_alloc_irq(cpu, outlet, virq);
+ result = ps3_irq_plug_setup(cpu, outlet, virq);
BUG_ON(result);
return result;
}
-int ps3_free_vuart_irq(unsigned int virq)
+int ps3_vuart_irq_destroy(unsigned int virq)
{
int result;
@@ -377,13 +473,14 @@ int ps3_free_vuart_irq(unsigned int virq)
return result;
}
- ps3_free_irq(virq);
+ result = ps3_irq_plug_destroy(virq);
+ BUG_ON(result);
return result;
}
/**
- * ps3_alloc_spe_irq - Configure an spe virq.
+ * ps3_spe_irq_setup - Setup an spe virq.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
* @spe_id: The spe_id returned from lv1_construct_logical_spe().
@@ -392,7 +489,7 @@ int ps3_free_vuart_irq(unsigned int virq)
*
*/
-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
unsigned int class, unsigned int *virq)
{
int result;
@@ -408,15 +505,16 @@ int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
return result;
}
- result = ps3_alloc_irq(cpu, outlet, virq);
+ result = ps3_irq_plug_setup(cpu, outlet, virq);
BUG_ON(result);
return result;
}
-int ps3_free_spe_irq(unsigned int virq)
+int ps3_spe_irq_destroy(unsigned int virq)
{
- ps3_free_irq(virq);
+ int result = ps3_irq_plug_destroy(virq);
+ BUG_ON(result);
return 0;
}
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 2014d2b4444..f8a3e206c58 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -826,5 +826,4 @@ void __init ps3_mm_init(void)
void ps3_mm_shutdown(void)
{
ps3_mm_region_destroy(&map.r1);
- map.total = map.rm.size;
}
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index ac5df9688dc..c9894933084 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -137,6 +137,12 @@ early_param("ps3fb", early_parse_ps3fb);
#define prealloc_ps3fb_videomemory() do { } while (0)
#endif
+static int ps3_set_dabr(u64 dabr)
+{
+ enum {DABR_USER = 1, DABR_KERNEL = 2,};
+
+ return lv1_set_dabr(dabr, DABR_KERNEL | DABR_USER) ? -1 : 0;
+}
static void __init ps3_setup_arch(void)
{
@@ -234,6 +240,7 @@ define_machine(ps3) {
.get_boot_time = ps3_get_boot_time,
.set_rtc_time = ps3_set_rtc_time,
.get_rtc_time = ps3_get_rtc_time,
+ .set_dabr = ps3_set_dabr,
.calibrate_decr = ps3_calibrate_decr,
.progress = ps3_progress,
.restart = ps3_restart,
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 6fb887961a6..8729348c060 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -110,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu)
BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
for (i = 0; i < MSG_COUNT; i++) {
- result = ps3_alloc_event_irq(cpu, &virqs[i]);
+ result = ps3_event_receive_port_setup(cpu, &virqs[i]);
if (result)
continue;
@@ -134,11 +134,13 @@ void ps3_smp_cleanup_cpu(int cpu)
int i;
DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
+
for (i = 0; i < MSG_COUNT; i++) {
- ps3_free_event_irq(virqs[i]);
free_irq(virqs[i], (void*)(long)i);
+ ps3_event_receive_port_destroy(virqs[i]);
virqs[i] = NO_IRQ;
}
+
DBG(" <- %s:%d: (%d)\n", __func__, __LINE__, cpu);
}
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index a397e4e17c1..651437cb2c1 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -184,7 +184,7 @@ static int __init setup_areas(struct spu *spu)
spu_pdata(spu)->shadow = __ioremap(
spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow),
- PAGE_READONLY | _PAGE_NO_CACHE | _PAGE_GUARDED);
+ pgprot_val(PAGE_READONLY) | _PAGE_NO_CACHE | _PAGE_GUARDED);
if (!spu_pdata(spu)->shadow) {
pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__);
goto fail_ioremap;
@@ -230,19 +230,19 @@ static int __init setup_interrupts(struct spu *spu)
{
int result;
- result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
0, &spu->irqs[0]);
if (result)
goto fail_alloc_0;
- result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
1, &spu->irqs[1]);
if (result)
goto fail_alloc_1;
- result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
+ result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
2, &spu->irqs[2]);
if (result)
@@ -251,9 +251,9 @@ static int __init setup_interrupts(struct spu *spu)
return result;
fail_alloc_2:
- ps3_free_spe_irq(spu->irqs[1]);
+ ps3_spe_irq_destroy(spu->irqs[1]);
fail_alloc_1:
- ps3_free_spe_irq(spu->irqs[0]);
+ ps3_spe_irq_destroy(spu->irqs[0]);
fail_alloc_0:
spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
return result;
@@ -301,9 +301,9 @@ static int ps3_destroy_spu(struct spu *spu)
result = lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0);
BUG_ON(result);
- ps3_free_spe_irq(spu->irqs[2]);
- ps3_free_spe_irq(spu->irqs[1]);
- ps3_free_spe_irq(spu->irqs[0]);
+ ps3_spe_irq_destroy(spu->irqs[2]);
+ ps3_spe_irq_destroy(spu->irqs[1]);
+ ps3_spe_irq_destroy(spu->irqs[0]);
spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index a57032cf6f1..16e4e401b82 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -1,3 +1,13 @@
+config PPC_PSERIES
+ depends on PPC_MULTIPLATFORM && PPC64
+ bool "IBM pSeries & new (POWER5-based) iSeries"
+ select MPIC
+ select PPC_I8259
+ select PPC_RTAS
+ select RTAS_ERROR_LOGGING
+ select PPC_UDBG_16550
+ select PPC_NATIVE
+ default y
config PPC_SPLPAR
depends on PPC_PSERIES
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 2dfd05095a2..ae1fc92dc1c 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -2,14 +2,16 @@ ifeq ($(CONFIG_PPC64),y)
EXTRA_CFLAGS += -mno-minimal-toc
endif
-obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \
- setup.o iommu.o ras.o rtasd.o pci_dlpar.o \
+obj-y := lpar.o hvCall.o nvram.o reconfig.o \
+ setup.o iommu.o ras.o rtasd.o \
firmware.o power.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
obj-$(CONFIG_KEXEC) += kexec.o
+obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
+obj-$(CONFIG_PCI_MSI) += msi.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 6cedbc002e0..093438b93bd 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -74,7 +74,10 @@
* is broken and panic. This sets the threshold for how many read
* attempts we allow before panicking.
*/
-#define EEH_MAX_FAILS 100000
+#define EEH_MAX_FAILS 2100000
+
+/* Time to wait for a PCI slot to retport status, in milliseconds */
+#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */
static int ibm_set_eeh_option;
@@ -83,6 +86,7 @@ static int ibm_read_slot_reset_state;
static int ibm_read_slot_reset_state2;
static int ibm_slot_error_detail;
static int ibm_get_config_addr_info;
+static int ibm_get_config_addr_info2;
static int ibm_configure_bridge;
int eeh_subsystem_enabled;
@@ -96,6 +100,9 @@ static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
static DEFINE_SPINLOCK(slot_errbuf_lock);
static int eeh_error_buf_size;
+#define EEH_PCI_REGS_LOG_LEN 4096
+static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
+
/* System monitoring statistics */
static unsigned long no_device;
static unsigned long no_dn;
@@ -111,7 +118,8 @@ static unsigned long slot_resets;
/* --------------------------------------------------------------- */
/* Below lies the EEH event infrastructure */
-void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
+static void rtas_slot_error_detail(struct pci_dn *pdn, int severity,
+ char *driver_log, size_t loglen)
{
int config_addr;
unsigned long flags;
@@ -129,7 +137,8 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
rc = rtas_call(ibm_slot_error_detail,
8, 1, NULL, config_addr,
BUID_HI(pdn->phb->buid),
- BUID_LO(pdn->phb->buid), NULL, 0,
+ BUID_LO(pdn->phb->buid),
+ virt_to_phys(driver_log), loglen,
virt_to_phys(slot_errbuf),
eeh_error_buf_size,
severity);
@@ -140,6 +149,84 @@ void eeh_slot_error_detail (struct pci_dn *pdn, int severity)
}
/**
+ * gather_pci_data - copy assorted PCI config space registers to buff
+ * @pdn: device to report data for
+ * @buf: point to buffer in which to log
+ * @len: amount of room in buffer
+ *
+ * This routine captures assorted PCI configuration space data,
+ * and puts them into a buffer for RTAS error logging.
+ */
+static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len)
+{
+ u32 cfg;
+ int cap, i;
+ int n = 0;
+
+ n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name);
+ printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name);
+
+ rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg);
+ n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg);
+ printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg);
+
+ rtas_read_config(pdn, PCI_COMMAND, 4, &cfg);
+ n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg);
+ printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg);
+
+ /* Dump out the PCI-X command and status regs */
+ cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_PCIX);
+ if (cap) {
+ rtas_read_config(pdn, cap, 4, &cfg);
+ n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg);
+ printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg);
+
+ rtas_read_config(pdn, cap+4, 4, &cfg);
+ n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg);
+ printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg);
+ }
+
+ /* If PCI-E capable, dump PCI-E cap 10, and the AER */
+ cap = pci_find_capability(pdn->pcidev, PCI_CAP_ID_EXP);
+ if (cap) {
+ n += scnprintf(buf+n, len-n, "pci-e cap10:\n");
+ printk(KERN_WARNING
+ "EEH: PCI-E capabilities and status follow:\n");
+
+ for (i=0; i<=8; i++) {
+ rtas_read_config(pdn, cap+4*i, 4, &cfg);
+ n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+ printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg);
+ }
+
+ cap = pci_find_ext_capability(pdn->pcidev,PCI_EXT_CAP_ID_ERR);
+ if (cap) {
+ n += scnprintf(buf+n, len-n, "pci-e AER:\n");
+ printk(KERN_WARNING
+ "EEH: PCI-E AER capability register set follows:\n");
+
+ for (i=0; i<14; i++) {
+ rtas_read_config(pdn, cap+4*i, 4, &cfg);
+ n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg);
+ printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg);
+ }
+ }
+ }
+ return n;
+}
+
+void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
+{
+ size_t loglen = 0;
+ memset(pci_regs_buf, 0, EEH_PCI_REGS_LOG_LEN);
+
+ rtas_pci_enable(pdn, EEH_THAW_MMIO);
+ loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
+
+ rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
+}
+
+/**
* read_slot_reset_state - Read the reset state of a device node's slot
* @dn: device node to read
* @rets: array to return results in
@@ -168,6 +255,55 @@ static int read_slot_reset_state(struct pci_dn *pdn, int rets[])
}
/**
+ * eeh_wait_for_slot_status - returns error status of slot
+ * @pdn pci device node
+ * @max_wait_msecs maximum number to millisecs to wait
+ *
+ * Return negative value if a permanent error, else return
+ * Partition Endpoint (PE) status value.
+ *
+ * If @max_wait_msecs is positive, then this routine will
+ * sleep until a valid status can be obtained, or until
+ * the max allowed wait time is exceeded, in which case
+ * a -2 is returned.
+ */
+int
+eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs)
+{
+ int rc;
+ int rets[3];
+ int mwait;
+
+ while (1) {
+ rc = read_slot_reset_state(pdn, rets);
+ if (rc) return rc;
+ if (rets[1] == 0) return -1; /* EEH is not supported */
+
+ if (rets[0] != 5) return rets[0]; /* return actual status */
+
+ if (rets[2] == 0) return -1; /* permanently unavailable */
+
+ if (max_wait_msecs <= 0) return -1;
+
+ mwait = rets[2];
+ if (mwait <= 0) {
+ printk (KERN_WARNING
+ "EEH: Firmware returned bad wait value=%d\n", mwait);
+ mwait = 1000;
+ } else if (mwait > 300*1000) {
+ printk (KERN_WARNING
+ "EEH: Firmware is taking too long, time=%d\n", mwait);
+ mwait = 300*1000;
+ }
+ max_wait_msecs -= mwait;
+ msleep (mwait);
+ }
+
+ printk(KERN_WARNING "EEH: Timed out waiting for slot status\n");
+ return -2;
+}
+
+/**
* eeh_token_to_phys - convert EEH address token to phys address
* @token i/o token, should be address in the form 0xA....
*/
@@ -229,7 +365,7 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag)
dn = find_device_pe (dn);
/* Back up one, since config addrs might be shared */
- if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+ if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
dn = dn->parent;
PCI_DN(dn)->eeh_mode |= mode_flag;
@@ -263,7 +399,7 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag)
dn = find_device_pe (dn);
/* Back up one, since config addrs might be shared */
- if (PCI_DN(dn) && PCI_DN(dn)->eeh_pe_config_addr)
+ if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
dn = dn->parent;
PCI_DN(dn)->eeh_mode &= ~mode_flag;
@@ -293,7 +429,6 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
int rets[3];
unsigned long flags;
struct pci_dn *pdn;
- enum pci_channel_state state;
int rc = 0;
total_mmio_ffs++;
@@ -367,25 +502,25 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
goto dn_unlock;
}
- /* If EEH is not supported on this device, punt. */
- if (rets[1] != 1) {
- printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
- ret, dn->full_name);
+ /* Note that config-io to empty slots may fail;
+ * they are empty when they don't have children. */
+ if ((rets[0] == 5) && (dn->child == NULL)) {
false_positives++;
rc = 0;
goto dn_unlock;
}
- /* If not the kind of error we know about, punt. */
- if (rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
+ /* If EEH is not supported on this device, punt. */
+ if (rets[1] != 1) {
+ printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
+ ret, dn->full_name);
false_positives++;
rc = 0;
goto dn_unlock;
}
- /* Note that config-io to empty slots may fail;
- * we recognize empty because they don't have children. */
- if ((rets[0] == 5) && (dn->child == NULL)) {
+ /* If not the kind of error we know about, punt. */
+ if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
false_positives++;
rc = 0;
goto dn_unlock;
@@ -399,17 +534,12 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
eeh_mark_slot (dn, EEH_MODE_ISOLATED);
spin_unlock_irqrestore(&confirm_error_lock, flags);
- state = pci_channel_io_normal;
- if ((rets[0] == 2) || (rets[0] == 4))
- state = pci_channel_io_frozen;
- if (rets[0] == 5)
- state = pci_channel_io_perm_failure;
- eeh_send_failure_event (dn, dev, state, rets[2]);
+ eeh_send_failure_event (dn, dev);
/* Most EEH events are due to device driver bugs. Having
* a stack trace will help the device-driver authors figure
* out what happened. So print that out. */
- if (rets[0] != 5) dump_stack();
+ dump_stack();
return 1;
dn_unlock:
@@ -458,38 +588,6 @@ EXPORT_SYMBOL(eeh_check_failure);
/* The code below deals with error recovery */
/**
- * eeh_slot_availability - returns error status of slot
- * @pdn pci device node
- *
- * Return negative value if a permanent error, else return
- * a number of milliseconds to wait until the PCI slot is
- * ready to be used.
- */
-static int
-eeh_slot_availability(struct pci_dn *pdn)
-{
- int rc;
- int rets[3];
-
- rc = read_slot_reset_state(pdn, rets);
-
- if (rc) return rc;
-
- if (rets[1] == 0) return -1; /* EEH is not supported */
- if (rets[0] == 0) return 0; /* Oll Korrect */
- if (rets[0] == 5) {
- if (rets[2] == 0) return -1; /* permanently unavailable */
- return rets[2]; /* number of millisecs to wait */
- }
- if (rets[0] == 1)
- return 250;
-
- printk (KERN_ERR "EEH: Slot unavailable: rc=%d, rets=%d %d %d\n",
- rc, rets[0], rets[1], rets[2]);
- return -2;
-}
-
-/**
* rtas_pci_enable - enable MMIO or DMA transfers for this slot
* @pdn pci device node
*/
@@ -512,9 +610,13 @@ rtas_pci_enable(struct pci_dn *pdn, int function)
function);
if (rc)
- printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n",
+ printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n",
function, rc, pdn->node->full_name);
+ rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC);
+ if ((rc == 4) && (function == EEH_THAW_MMIO))
+ return 0;
+
return rc;
}
@@ -561,6 +663,36 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state)
}
/**
+ * pcibios_set_pcie_slot_reset - Set PCI-E reset state
+ * @dev: pci device struct
+ * @state: reset state to enter
+ *
+ * Return value:
+ * 0 if success
+ **/
+int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
+{
+ struct device_node *dn = pci_device_to_OF_node(dev);
+ struct pci_dn *pdn = PCI_DN(dn);
+
+ switch (state) {
+ case pcie_deassert_reset:
+ rtas_pci_slot_reset(pdn, 0);
+ break;
+ case pcie_hot_reset:
+ rtas_pci_slot_reset(pdn, 1);
+ break;
+ case pcie_warm_reset:
+ rtas_pci_slot_reset(pdn, 3);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+/**
* rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
* @pdn: pci device node to be reset.
*
@@ -595,36 +727,24 @@ int rtas_set_slot_reset(struct pci_dn *pdn)
{
int i, rc;
- __rtas_set_slot_reset(pdn);
+ /* Take three shots at resetting the bus */
+ for (i=0; i<3; i++) {
+ __rtas_set_slot_reset(pdn);
- /* Now double check with the firmware to make sure the device is
- * ready to be used; if not, wait for recovery. */
- for (i=0; i<10; i++) {
- rc = eeh_slot_availability (pdn);
+ rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC);
if (rc == 0)
return 0;
- if (rc == -2) {
- printk (KERN_ERR "EEH: failed (%d) to reset slot %s\n",
- i, pdn->node->full_name);
- __rtas_set_slot_reset(pdn);
- continue;
- }
-
if (rc < 0) {
printk (KERN_ERR "EEH: unrecoverable slot failure %s\n",
pdn->node->full_name);
return -1;
}
-
- msleep (rc+100);
+ printk (KERN_ERR "EEH: bus reset %d failed on slot %s\n",
+ i+1, pdn->node->full_name);
}
- rc = eeh_slot_availability (pdn);
- if (rc)
- printk (KERN_ERR "EEH: timeout resetting slot %s\n", pdn->node->full_name);
-
- return rc;
+ return -1;
}
/* ------------------------------------------------------- */
@@ -744,16 +864,48 @@ struct eeh_early_enable_info {
unsigned int buid_lo;
};
+static int get_pe_addr (int config_addr,
+ struct eeh_early_enable_info *info)
+{
+ unsigned int rets[3];
+ int ret;
+
+ /* Use latest config-addr token on power6 */
+ if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) {
+ /* Make sure we have a PE in hand */
+ ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
+ config_addr, info->buid_hi, info->buid_lo, 1);
+ if (ret || (rets[0]==0))
+ return 0;
+
+ ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets,
+ config_addr, info->buid_hi, info->buid_lo, 0);
+ if (ret)
+ return 0;
+ return rets[0];
+ }
+
+ /* Use older config-addr token on power5 */
+ if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
+ ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
+ config_addr, info->buid_hi, info->buid_lo, 0);
+ if (ret)
+ return 0;
+ return rets[0];
+ }
+ return 0;
+}
+
/* Enable eeh for the given device node. */
static void *early_enable_eeh(struct device_node *dn, void *data)
{
unsigned int rets[3];
struct eeh_early_enable_info *info = data;
int ret;
- const char *status = get_property(dn, "status", NULL);
- const u32 *class_code = get_property(dn, "class-code", NULL);
- const u32 *vendor_id = get_property(dn, "vendor-id", NULL);
- const u32 *device_id = get_property(dn, "device-id", NULL);
+ const char *status = of_get_property(dn, "status", NULL);
+ const u32 *class_code = of_get_property(dn, "class-code", NULL);
+ const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
+ const u32 *device_id = of_get_property(dn, "device-id", NULL);
const u32 *regs;
int enable;
struct pci_dn *pdn = PCI_DN(dn);
@@ -796,7 +948,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
/* Ok... see if this device supports EEH. Some do, some don't,
* and the only way to find out is to check each and every one. */
- regs = get_property(dn, "reg", NULL);
+ regs = of_get_property(dn, "reg", NULL);
if (regs) {
/* First register entry is addr (00BBSS00) */
/* Try to enable eeh */
@@ -810,15 +962,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
/* If the newer, better, ibm,get-config-addr-info is supported,
* then use that instead. */
- pdn->eeh_pe_config_addr = 0;
- if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
- ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
- pdn->eeh_config_addr,
- info->buid_hi, info->buid_lo,
- 0);
- if (ret == 0)
- pdn->eeh_pe_config_addr = rets[0];
- }
+ pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info);
/* Some older systems (Power4) allow the
* ibm,set-eeh-option call to succeed even on nodes
@@ -889,6 +1033,7 @@ void __init eeh_init(void)
ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state");
ibm_slot_error_detail = rtas_token("ibm,slot-error-detail");
ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
+ ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
ibm_configure_bridge = rtas_token ("ibm,configure-bridge");
if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index a4c0bf84ef2..f07d849cfc8 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -158,7 +158,8 @@ static void eeh_report_reset(struct pci_dev *dev, void *userdata)
return;
rc = driver->err_handler->slot_reset(dev);
- if (*res == PCI_ERS_RESULT_NONE) *res = rc;
+ if ((*res == PCI_ERS_RESULT_NONE) ||
+ (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc;
if (*res == PCI_ERS_RESULT_DISCONNECT &&
rc == PCI_ERS_RESULT_NEED_RESET) *res = rc;
}
@@ -248,6 +249,7 @@ static void eeh_report_failure(struct pci_dev *dev, void *userdata)
static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
{
+ struct device_node *dn;
int cnt, rc;
/* pcibios will clear the counter; save the value */
@@ -263,23 +265,20 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
if (rc)
return rc;
- /* New-style config addrs might be shared across multiple devices,
- * Walk over all functions on this device */
- if (pe_dn->eeh_pe_config_addr) {
- struct device_node *pe = pe_dn->node;
- pe = pe->parent->child;
- while (pe) {
- struct pci_dn *ppe = PCI_DN(pe);
- if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
- rtas_configure_bridge(ppe);
- eeh_restore_bars(ppe);
- }
- pe = pe->sibling;
+ /* Walk over all functions on this device. */
+ dn = pe_dn->node;
+ if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+ dn = dn->parent->child;
+
+ while (dn) {
+ struct pci_dn *ppe = PCI_DN(dn);
+ /* On Power4, always true because eeh_pe_config_addr=0 */
+ if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) {
+ rtas_configure_bridge(ppe);
+ eeh_restore_bars(ppe);
}
- } else {
- rtas_configure_bridge(pe_dn);
- eeh_restore_bars(pe_dn);
- }
+ dn = dn->sibling;
+ }
/* Give the system 5 seconds to finish running the user-space
* hotplug shutdown scripts, e.g. ifdown for ethernet. Yes,
@@ -299,7 +298,7 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus)
/* The longest amount of time to wait for a pci device
* to come back on line, in seconds.
*/
-#define MAX_WAIT_FOR_RECOVERY 15
+#define MAX_WAIT_FOR_RECOVERY 150
struct pci_dn * handle_eeh_events (struct eeh_event *event)
{
@@ -315,14 +314,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (!frozen_dn) {
- location = get_property(event->dn, "ibm,loc-code", NULL);
+ location = of_get_property(event->dn, "ibm,loc-code", NULL);
location = location ? location : "unknown";
printk(KERN_ERR "EEH: Error: Cannot find partition endpoint "
"for location=%s pci addr=%s\n",
location, pci_name(event->dev));
return NULL;
}
- location = get_property(frozen_dn, "ibm,loc-code", NULL);
+ location = of_get_property(frozen_dn, "ibm,loc-code", NULL);
location = location ? location : "unknown";
/* There are two different styles for coming up with the PE.
@@ -341,13 +340,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
return NULL;
}
-#if 0
- /* We may get "permanent failure" messages on empty slots.
- * These are false alarms. Empty slots have no child dn. */
- if ((event->state == pci_channel_io_perm_failure) && (frozen_device == NULL))
- return;
-#endif
-
frozen_pdn = PCI_DN(frozen_dn);
frozen_pdn->eeh_freeze_count++;
@@ -362,19 +354,19 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto excess_failures;
- /* If the reset state is a '5' and the time to reset is 0 (infinity)
- * or is more then 15 seconds, then mark this as a permanent failure.
- */
- if ((event->state == pci_channel_io_perm_failure) &&
- ((event->time_unavail <= 0) ||
- (event->time_unavail > MAX_WAIT_FOR_RECOVERY*1000)))
+ /* Get the current PCI slot state. */
+ rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000);
+ if (rc < 0) {
+ printk(KERN_WARNING "EEH: Permanent failure\n");
goto hard_fail;
+ }
- eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
printk(KERN_WARNING
- "EEH: This PCI device has failed %d times since last reboot: "
- "location=%s driver=%s pci addr=%s\n",
- frozen_pdn->eeh_freeze_count, location, drv_str, pci_str);
+ "EEH: This PCI device has failed %d times in the last hour:\n",
+ frozen_pdn->eeh_freeze_count);
+ printk(KERN_WARNING
+ "EEH: location=%s driver=%s pci addr=%s\n",
+ location, drv_str, pci_str);
/* Walk the various device drivers attached to this slot through
* a reset sequence, giving each an opportunity to do what it needs
@@ -384,20 +376,29 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
*/
pci_walk_bus(frozen_bus, eeh_report_error, &result);
+ /* Since rtas may enable MMIO when posting the error log,
+ * don't post the error log until after all dev drivers
+ * have been informed. */
+ eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
+
/* If all device drivers were EEH-unaware, then shut
* down all of the device drivers, and hope they
* go down willingly, without panicing the system.
*/
if (result == PCI_ERS_RESULT_NONE) {
rc = eeh_reset_device(frozen_pdn, frozen_bus);
- if (rc)
+ if (rc) {
+ printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc);
goto hard_fail;
+ }
}
/* If all devices reported they can proceed, then re-enable MMIO */
if (result == PCI_ERS_RESULT_CAN_RECOVER) {
rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO);
+ if (rc < 0)
+ goto hard_fail;
if (rc) {
result = PCI_ERS_RESULT_NEED_RESET;
} else {
@@ -410,6 +411,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
if (result == PCI_ERS_RESULT_CAN_RECOVER) {
rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA);
+ if (rc < 0)
+ goto hard_fail;
if (rc)
result = PCI_ERS_RESULT_NEED_RESET;
else
@@ -417,21 +420,28 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
}
/* If any device has a hard failure, then shut off everything. */
- if (result == PCI_ERS_RESULT_DISCONNECT)
+ if (result == PCI_ERS_RESULT_DISCONNECT) {
+ printk(KERN_WARNING "EEH: Device driver gave up\n");
goto hard_fail;
+ }
/* If any device called out for a reset, then reset the slot */
if (result == PCI_ERS_RESULT_NEED_RESET) {
rc = eeh_reset_device(frozen_pdn, NULL);
- if (rc)
+ if (rc) {
+ printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc);
goto hard_fail;
+ }
result = PCI_ERS_RESULT_NONE;
pci_walk_bus(frozen_bus, eeh_report_reset, &result);
}
/* All devices should claim they have recovered by now. */
- if (result != PCI_ERS_RESULT_RECOVERED)
+ if ((result != PCI_ERS_RESULT_RECOVERED) &&
+ (result != PCI_ERS_RESULT_NONE)) {
+ printk(KERN_WARNING "EEH: Not recovered\n");
goto hard_fail;
+ }
/* Tell all device drivers that they can resume operations */
pci_walk_bus(frozen_bus, eeh_report_resume, NULL);
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c
index 49037edf7d3..ddb80f5d850 100644
--- a/arch/powerpc/platforms/pseries/eeh_event.c
+++ b/arch/powerpc/platforms/pseries/eeh_event.c
@@ -118,9 +118,7 @@ static void eeh_thread_launcher(struct work_struct *dummy)
* (from a workqueue).
*/
int eeh_send_failure_event (struct device_node *dn,
- struct pci_dev *dev,
- enum pci_channel_state state,
- int time_unavail)
+ struct pci_dev *dev)
{
unsigned long flags;
struct eeh_event *event;
@@ -128,7 +126,7 @@ int eeh_send_failure_event (struct device_node *dn,
if (!mem_init_done) {
printk(KERN_ERR "EEH: event during early boot not handled\n");
- location = get_property(dn, "ibm,loc-code", NULL);
+ location = of_get_property(dn, "ibm,loc-code", NULL);
printk(KERN_ERR "EEH: device node = %s\n", dn->full_name);
printk(KERN_ERR "EEH: PCI location = %s\n", location);
return 1;
@@ -144,8 +142,6 @@ int eeh_send_failure_event (struct device_node *dn,
event->dn = dn;
event->dev = dev;
- event->state = state;
- event->time_unavail = time_unavail;
/* We may or may not be called in an interrupt context */
spin_lock_irqsave(&eeh_eventlist_lock, flags);
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 90522e3c9d4..29bf83bfb1f 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -80,7 +80,7 @@ void __init fw_feature_init(void)
goto out;
}
- hypertas = get_property(dn, "ibm,hypertas-functions", &len);
+ hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
if (hypertas == NULL)
goto out;
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index f460b9cbfd4..9711eb0d549 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -143,7 +143,7 @@ static int pseries_add_processor(struct device_node *np)
int err = -ENOSPC, len, nthreads, i;
const u32 *intserv;
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return 0;
@@ -203,7 +203,7 @@ static void pseries_remove_processor(struct device_node *np)
int len, nthreads, i;
const u32 *intserv;
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s", &len);
if (!intserv)
return;
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index e6653a868b9..eec684a8e44 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -242,6 +242,7 @@ static unsigned long tce_get_pSeriesLP(struct iommu_table *tbl, long tcenum)
return tce_ret;
}
+#ifdef CONFIG_PCI
static void iommu_table_setparms(struct pci_controller *phb,
struct device_node *dn,
struct iommu_table *tbl)
@@ -252,8 +253,8 @@ static void iommu_table_setparms(struct pci_controller *phb,
node = (struct device_node *)phb->arch_data;
- basep = get_property(node, "linux,tce-base", NULL);
- sizep = get_property(node, "linux,tce-size", NULL);
+ basep = of_get_property(node, "linux,tce-base", NULL);
+ sizep = of_get_property(node, "linux,tce-size", NULL);
if (basep == NULL || sizep == NULL) {
printk(KERN_ERR "PCI_DMA: iommu_table_setparms: %s has "
"missing tce entries !\n", dn->full_name);
@@ -403,7 +404,7 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus)
/* Find nearest ibm,dma-window, walking up the device tree */
for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
- dma_window = get_property(pdn, "ibm,dma-window", NULL);
+ dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window != NULL)
break;
}
@@ -478,29 +479,6 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
pci_name(dev));
}
-static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
-{
- int err = NOTIFY_OK;
- struct device_node *np = node;
- struct pci_dn *pci = PCI_DN(np);
-
- switch (action) {
- case PSERIES_RECONFIG_REMOVE:
- if (pci && pci->iommu_table &&
- get_property(np, "ibm,dma-window", NULL))
- iommu_free_table(np);
- break;
- default:
- err = NOTIFY_DONE;
- break;
- }
- return err;
-}
-
-static struct notifier_block iommu_reconfig_nb = {
- .notifier_call = iommu_reconfig_notifier,
-};
-
static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
{
struct device_node *pdn, *dn;
@@ -521,11 +499,17 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
pdn = pdn->parent) {
- dma_window = get_property(pdn, "ibm,dma-window", NULL);
+ dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
if (dma_window)
break;
}
+ if (!pdn || !PCI_DN(pdn)) {
+ printk(KERN_WARNING "pci_dma_dev_setup_pSeriesLP: "
+ "no DMA window found for pci dev=%s dn=%s\n",
+ pci_name(dev), dn? dn->full_name : "<null>");
+ return;
+ }
DBG(" parent is %s\n", pdn->full_name);
/* Check for parent == NULL so we don't try to setup the empty EADS
@@ -554,15 +538,44 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
dev->dev.archdata.dma_data = pci->iommu_table;
}
+#else /* CONFIG_PCI */
+#define pci_dma_bus_setup_pSeries NULL
+#define pci_dma_dev_setup_pSeries NULL
+#define pci_dma_bus_setup_pSeriesLP NULL
+#define pci_dma_dev_setup_pSeriesLP NULL
+#endif /* !CONFIG_PCI */
+
+static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+{
+ int err = NOTIFY_OK;
+ struct device_node *np = node;
+ struct pci_dn *pci = PCI_DN(np);
+
+ switch (action) {
+ case PSERIES_RECONFIG_REMOVE:
+ if (pci && pci->iommu_table &&
+ of_get_property(np, "ibm,dma-window", NULL))
+ iommu_free_table(np);
+ break;
+ default:
+ err = NOTIFY_DONE;
+ break;
+ }
+ return err;
+}
+
+static struct notifier_block iommu_reconfig_nb = {
+ .notifier_call = iommu_reconfig_notifier,
+};
/* These are called very early. */
void iommu_init_early_pSeries(void)
{
- if (of_chosen && get_property(of_chosen, "linux,iommu-off", NULL)) {
+ if (of_chosen && of_get_property(of_chosen, "linux,iommu-off", NULL)) {
/* Direct I/O, IOMMU off */
ppc_md.pci_dma_dev_setup = NULL;
ppc_md.pci_dma_bus_setup = NULL;
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
return;
}
@@ -588,6 +601,6 @@ void iommu_init_early_pSeries(void)
pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
}
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 843ee964321..362dfbc260a 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -209,13 +209,13 @@ void __init find_udbg_vterm(void)
/* find the boot console from /chosen/stdout */
if (!of_chosen)
return;
- name = get_property(of_chosen, "linux,stdout-path", NULL);
+ name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (name == NULL)
return;
stdout_node = of_find_node_by_path(name);
if (!stdout_node)
return;
- name = get_property(stdout_node, "name", NULL);
+ name = of_get_property(stdout_node, "name", NULL);
if (!name) {
printk(KERN_WARNING "stdout node missing 'name' property!\n");
goto out;
@@ -226,18 +226,18 @@ void __init find_udbg_vterm(void)
/* Check if it's a virtual terminal */
if (strncmp(name, "vty", 3) != 0)
goto out;
- termno = get_property(stdout_node, "reg", NULL);
+ termno = of_get_property(stdout_node, "reg", NULL);
if (termno == NULL)
goto out;
vtermno = termno[0];
- if (device_is_compatible(stdout_node, "hvterm1")) {
+ if (of_device_is_compatible(stdout_node, "hvterm1")) {
udbg_putc = udbg_putcLP;
udbg_getc = udbg_getcLP;
udbg_getc_poll = udbg_getc_pollLP;
if (add_console)
add_preferred_console("hvc", termno[0] & 0xff, NULL);
- } else if (device_is_compatible(stdout_node, "hvterm-protocol")) {
+ } else if (of_device_is_compatible(stdout_node, "hvterm-protocol")) {
vtermno = termno[0];
udbg_putc = udbg_hvsi_putc;
udbg_getc = udbg_hvsi_getc;
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
new file mode 100644
index 00000000000..6063ea2f67a
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2006 Jake Moilanen <moilanen@austin.ibm.com>, IBM Corp.
+ * Copyright 2006-2007 Michael Ellerman, IBM Corp.
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+
+#include <asm/rtas.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+static int query_token, change_token;
+
+#define RTAS_QUERY_FN 0
+#define RTAS_CHANGE_FN 1
+#define RTAS_RESET_FN 2
+#define RTAS_CHANGE_MSI_FN 3
+#define RTAS_CHANGE_MSIX_FN 4
+
+static struct pci_dn *get_pdn(struct pci_dev *pdev)
+{
+ struct device_node *dn;
+ struct pci_dn *pdn;
+
+ dn = pci_device_to_OF_node(pdev);
+ if (!dn) {
+ dev_dbg(&pdev->dev, "rtas_msi: No OF device node\n");
+ return NULL;
+ }
+
+ pdn = PCI_DN(dn);
+ if (!pdn) {
+ dev_dbg(&pdev->dev, "rtas_msi: No PCI DN\n");
+ return NULL;
+ }
+
+ return pdn;
+}
+
+/* RTAS Helpers */
+
+static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs)
+{
+ u32 addr, seq_num, rtas_ret[3];
+ unsigned long buid;
+ int rc;
+
+ addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+ buid = pdn->phb->buid;
+
+ seq_num = 1;
+ do {
+ if (func == RTAS_CHANGE_MSI_FN || func == RTAS_CHANGE_MSIX_FN)
+ rc = rtas_call(change_token, 6, 4, rtas_ret, addr,
+ BUID_HI(buid), BUID_LO(buid),
+ func, num_irqs, seq_num);
+ else
+ rc = rtas_call(change_token, 6, 3, rtas_ret, addr,
+ BUID_HI(buid), BUID_LO(buid),
+ func, num_irqs, seq_num);
+
+ seq_num = rtas_ret[1];
+ } while (rtas_busy_delay(rc));
+
+ if (rc == 0) /* Success */
+ rc = rtas_ret[0];
+
+ pr_debug("rtas_msi: ibm,change_msi(func=%d,num=%d) = (%d)\n",
+ func, num_irqs, rc);
+
+ return rc;
+}
+
+static void rtas_disable_msi(struct pci_dev *pdev)
+{
+ struct pci_dn *pdn;
+
+ pdn = get_pdn(pdev);
+ if (!pdn)
+ return;
+
+ if (rtas_change_msi(pdn, RTAS_CHANGE_FN, 0) != 0)
+ pr_debug("rtas_msi: Setting MSIs to 0 failed!\n");
+}
+
+static int rtas_query_irq_number(struct pci_dn *pdn, int offset)
+{
+ u32 addr, rtas_ret[2];
+ unsigned long buid;
+ int rc;
+
+ addr = rtas_config_addr(pdn->busno, pdn->devfn, 0);
+ buid = pdn->phb->buid;
+
+ do {
+ rc = rtas_call(query_token, 4, 3, rtas_ret, addr,
+ BUID_HI(buid), BUID_LO(buid), offset);
+ } while (rtas_busy_delay(rc));
+
+ if (rc) {
+ pr_debug("rtas_msi: error (%d) querying source number\n", rc);
+ return rc;
+ }
+
+ return rtas_ret[0];
+}
+
+static void rtas_teardown_msi_irqs(struct pci_dev *pdev)
+{
+ struct msi_desc *entry;
+
+ list_for_each_entry(entry, &pdev->msi_list, list) {
+ if (entry->irq == NO_IRQ)
+ continue;
+
+ set_irq_msi(entry->irq, NULL);
+ irq_dispose_mapping(entry->irq);
+ }
+
+ rtas_disable_msi(pdev);
+}
+
+static int check_req_msi(struct pci_dev *pdev, int nvec)
+{
+ struct device_node *dn;
+ struct pci_dn *pdn;
+ const u32 *req_msi;
+
+ pdn = get_pdn(pdev);
+ if (!pdn)
+ return -ENODEV;
+
+ dn = pdn->node;
+
+ req_msi = of_get_property(dn, "ibm,req#msi", NULL);
+ if (!req_msi) {
+ pr_debug("rtas_msi: No ibm,req#msi on %s\n", dn->full_name);
+ return -ENOENT;
+ }
+
+ if (*req_msi < nvec) {
+ pr_debug("rtas_msi: ibm,req#msi requests < %d MSIs\n", nvec);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+ if (type == PCI_CAP_ID_MSIX)
+ pr_debug("rtas_msi: MSI-X untested, trying anyway.\n");
+
+ return check_req_msi(pdev, nvec);
+}
+
+static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+{
+ struct pci_dn *pdn;
+ int hwirq, virq, i, rc;
+ struct msi_desc *entry;
+
+ pdn = get_pdn(pdev);
+ if (!pdn)
+ return -ENODEV;
+
+ /*
+ * Try the new more explicit firmware interface, if that fails fall
+ * back to the old interface. The old interface is known to never
+ * return MSI-Xs.
+ */
+ if (type == PCI_CAP_ID_MSI) {
+ rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec);
+
+ if (rc != nvec) {
+ pr_debug("rtas_msi: trying the old firmware call.\n");
+ rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec);
+ }
+ } else
+ rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec);
+
+ if (rc != nvec) {
+ pr_debug("rtas_msi: rtas_change_msi() failed\n");
+
+ /*
+ * In case of an error it's not clear whether the device is
+ * left with MSI enabled or not, so we explicitly disable.
+ */
+ goto out_free;
+ }
+
+ i = 0;
+ list_for_each_entry(entry, &pdev->msi_list, list) {
+ hwirq = rtas_query_irq_number(pdn, i);
+ if (hwirq < 0) {
+ rc = hwirq;
+ pr_debug("rtas_msi: error (%d) getting hwirq\n", rc);
+ goto out_free;
+ }
+
+ virq = irq_create_mapping(NULL, hwirq);
+
+ if (virq == NO_IRQ) {
+ pr_debug("rtas_msi: Failed mapping hwirq %d\n", hwirq);
+ rc = -ENOSPC;
+ goto out_free;
+ }
+
+ dev_dbg(&pdev->dev, "rtas_msi: allocated virq %d\n", virq);
+ set_irq_msi(virq, entry);
+ unmask_msi_irq(virq);
+ }
+
+ return 0;
+
+ out_free:
+ rtas_teardown_msi_irqs(pdev);
+ return rc;
+}
+
+static void rtas_msi_pci_irq_fixup(struct pci_dev *pdev)
+{
+ /* No LSI -> leave MSIs (if any) configured */
+ if (pdev->irq == NO_IRQ) {
+ dev_dbg(&pdev->dev, "rtas_msi: no LSI, nothing to do.\n");
+ return;
+ }
+
+ /* No MSI -> MSIs can't have been assigned by fw, leave LSI */
+ if (check_req_msi(pdev, 1)) {
+ dev_dbg(&pdev->dev, "rtas_msi: no req#msi, nothing to do.\n");
+ return;
+ }
+
+ dev_dbg(&pdev->dev, "rtas_msi: disabling existing MSI.\n");
+ rtas_disable_msi(pdev);
+}
+
+static int rtas_msi_init(void)
+{
+ query_token = rtas_token("ibm,query-interrupt-source-number");
+ change_token = rtas_token("ibm,change-msi");
+
+ if ((query_token == RTAS_UNKNOWN_SERVICE) ||
+ (change_token == RTAS_UNKNOWN_SERVICE)) {
+ pr_debug("rtas_msi: no RTAS tokens, no MSI support.\n");
+ return -1;
+ }
+
+ pr_debug("rtas_msi: Registering RTAS MSI callbacks.\n");
+
+ WARN_ON(ppc_md.setup_msi_irqs);
+ ppc_md.setup_msi_irqs = rtas_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs;
+ ppc_md.msi_check_device = rtas_msi_check_device;
+
+ WARN_ON(ppc_md.pci_irq_fixup);
+ ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup;
+
+ return 0;
+}
+arch_initcall(rtas_msi_init);
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index 64163cecdf9..f68903e15bd 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -130,7 +130,7 @@ int __init pSeries_nvram_init(void)
if (nvram == NULL)
return -ENODEV;
- nbytes_p = get_property(nvram, "#bytes", &proplen);
+ nbytes_p = of_get_property(nvram, "#bytes", &proplen);
if (nbytes_p == NULL || proplen != sizeof(unsigned int))
return -EIO;
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index fa59124ce3f..2c6ded29f73 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/string.h>
+#include <asm/eeh.h>
#include <asm/pci-bridge.h>
#include <asm/prom.h>
#include <asm/ppc-pci.h>
@@ -39,7 +40,7 @@ void pcibios_name_device(struct pci_dev *dev)
*/
dn = pci_device_to_OF_node(dev);
if (dn) {
- char *loc_code = get_property(dn, "ibm,loc-code", 0);
+ const char *loc_code = of_get_property(dn, "ibm,loc-code", 0);
if (loc_code) {
int loc_len = strlen(loc_code);
if (loc_len < sizeof(dev->dev.name)) {
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index ac56b868913..ffaf6c5c517 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -29,6 +29,7 @@
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
#include <asm/firmware.h>
+#include <asm/eeh.h>
static struct pci_bus *
find_bus_among_children(struct pci_bus *bus,
@@ -78,6 +79,7 @@ pcibios_remove_pci_devices(struct pci_bus *bus)
pci_remove_bus_device(dev);
}
}
+EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices);
/* Must be called before pci_bus_add_devices */
void
diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c
index 2624b71df73..73e69023d90 100644
--- a/arch/powerpc/platforms/pseries/power.c
+++ b/arch/powerpc/platforms/pseries/power.c
@@ -28,13 +28,13 @@
unsigned long rtas_poweron_auto; /* default and normal state is 0 */
-static ssize_t auto_poweron_show(struct subsystem *subsys, char *buf)
+static ssize_t auto_poweron_show(struct kset *kset, char *buf)
{
return sprintf(buf, "%lu\n", rtas_poweron_auto);
}
static ssize_t
-auto_poweron_store(struct subsystem *subsys, const char *buf, size_t n)
+auto_poweron_store(struct kset *kset, const char *buf, size_t n)
{
int ret;
unsigned long ups_restart;
@@ -72,12 +72,12 @@ static int __init pm_init(void)
{
int error = subsystem_register(&power_subsys);
if (!error)
- error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+ error = sysfs_create_group(&power_subsys.kobj, &attr_group);
return error;
}
core_initcall(pm_init);
#else
-extern struct subsystem power_subsys;
+extern struct kset power_subsys;
static int __init apo_pm_init(void)
{
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index edc03887311..3a393c7f390 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -31,7 +31,6 @@
#include <linux/timex.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/random.h>
@@ -85,7 +84,7 @@ static void request_ras_irqs(struct device_node *np,
* map those interrupts using the default interrupt host and default
* trigger
*/
- opicprop = get_property(np, "open-pic-interrupt", &opicplen);
+ opicprop = of_get_property(np, "open-pic-interrupt", &opicplen);
if (opicprop) {
opicplen /= sizeof(u32);
for (i = 0; i < opicplen; i++) {
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index 77d0937d5c0..9797b10b293 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -363,7 +363,7 @@ static int get_eventscan_parms(void)
node = of_find_node_by_path("/rtas");
- ip = get_property(node, "rtas-event-scan-rate", NULL);
+ ip = of_get_property(node, "rtas-event-scan-rate", NULL);
if (ip == NULL) {
printk(KERN_ERR "rtasd: no rtas-event-scan-rate\n");
of_node_put(node);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 34aff47b1f5..470db6efaeb 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -65,6 +65,7 @@
#include <asm/udbg.h>
#include <asm/smp.h>
#include <asm/firmware.h>
+#include <asm/eeh.h>
#include "plpar_wrappers.h"
#include "pseries.h"
@@ -92,7 +93,7 @@ static void pSeries_show_cpuinfo(struct seq_file *m)
root = of_find_node_by_path("/");
if (root)
- model = get_property(root, "model", NULL);
+ model = of_get_property(root, "model", NULL);
seq_printf(m, "machine\t\t: CHRP %s\n", model);
of_node_put(root);
}
@@ -138,8 +139,8 @@ static void __init pseries_mpic_init_IRQ(void)
struct mpic *mpic;
np = of_find_node_by_path("/");
- naddr = prom_n_addr_cells(np);
- opprop = get_property(np, "platform-open-pic", &opplen);
+ naddr = of_n_addr_cells(np);
+ opprop = of_get_property(np, "platform-open-pic", &opplen);
if (opprop != 0) {
openpic_addr = of_read_number(opprop, naddr);
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
@@ -167,7 +168,7 @@ static void __init pseries_mpic_init_IRQ(void)
/* Look for cascade */
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "chrp,iic")) {
+ if (of_device_is_compatible(np, "chrp,iic")) {
cascade = np;
break;
}
@@ -188,11 +189,11 @@ static void __init pseries_mpic_init_IRQ(void)
break;
if (strcmp(np->name, "pci") != 0)
continue;
- addrp = get_property(np, "8259-interrupt-acknowledge",
+ addrp = of_get_property(np, "8259-interrupt-acknowledge",
NULL);
if (addrp == NULL)
continue;
- naddr = prom_n_addr_cells(np);
+ naddr = of_n_addr_cells(np);
intack = addrp[naddr-1];
if (naddr > 1)
intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -225,7 +226,7 @@ static void __init pseries_discover_pic(void)
for (np = NULL; (np = of_find_node_by_name(np,
"interrupt-controller"));) {
- typep = get_property(np, "compatible", NULL);
+ typep = of_get_property(np, "compatible", NULL);
if (strstr(typep, "open-pic")) {
pSeries_mpic_node = of_node_get(np);
ppc_md.init_IRQ = pseries_mpic_init_IRQ;
@@ -334,32 +335,6 @@ static void __init pSeries_init_early(void)
DBG(" <- pSeries_init_early()\n");
}
-
-static int pSeries_check_legacy_ioport(unsigned int baseport)
-{
- struct device_node *np;
-
-#define I8042_DATA_REG 0x60
-#define FDC_BASE 0x3f0
-
-
- switch(baseport) {
- case I8042_DATA_REG:
- np = of_find_node_by_type(NULL, "8042");
- if (np == NULL)
- return -ENODEV;
- of_node_put(np);
- break;
- case FDC_BASE:
- np = of_find_node_by_type(NULL, "fdc");
- if (np == NULL)
- return -ENODEV;
- of_node_put(np);
- break;
- }
- return 0;
-}
-
/*
* Called very early, MMU is off, device-tree isn't unflattened
*/
@@ -514,6 +489,10 @@ void pSeries_power_off(void)
for (;;);
}
+#ifndef CONFIG_PCI
+void pSeries_final_fixup(void) { }
+#endif
+
define_machine(pseries) {
.name = "pSeries",
.probe = pSeries_probe,
@@ -532,7 +511,6 @@ define_machine(pseries) {
.set_rtc_time = rtas_set_rtc_time,
.calibrate_decr = generic_calibrate_decr,
.progress = rtas_progress,
- .check_legacy_ioport = pSeries_check_legacy_ioport,
.system_reset_exception = pSeries_system_reset_exception,
.machine_check_exception = pSeries_machine_check_exception,
};
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 81d172d6503..b854e7f1001 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -477,7 +477,7 @@ static int xics_host_match(struct irq_host *h, struct device_node *node)
* like vdevices, events, etc... The trick we use here is to match
* everything here except the legacy 8259 which is compatible "chrp,iic"
*/
- return !device_is_compatible(node, "chrp,iic");
+ return !of_device_is_compatible(node, "chrp,iic");
}
static int xics_host_map_direct(struct irq_host *h, unsigned int virq,
@@ -576,7 +576,7 @@ static void __init xics_init_one_node(struct device_node *np,
* This happens to be the case so far but we are playing with fire...
* should be fixed one of these days. -BenH.
*/
- ireg = get_property(np, "ibm,interrupt-server-ranges", NULL);
+ ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL);
/* Do that ever happen ? we'll know soon enough... but even good'old
* f80 does have that property ..
@@ -588,7 +588,7 @@ static void __init xics_init_one_node(struct device_node *np,
*/
*indx = *ireg;
}
- ireg = get_property(np, "reg", &ilen);
+ ireg = of_get_property(np, "reg", &ilen);
if (!ireg)
panic("xics_init_IRQ: can't find interrupt reg property");
@@ -618,7 +618,7 @@ static void __init xics_setup_8259_cascade(void)
unsigned long intack = 0;
for_each_node_by_type(np, "interrupt-controller")
- if (device_is_compatible(np, "chrp,iic")) {
+ if (of_device_is_compatible(np, "chrp,iic")) {
found = np;
break;
}
@@ -640,10 +640,10 @@ static void __init xics_setup_8259_cascade(void)
break;
if (strcmp(np->name, "pci") != 0)
continue;
- addrp = get_property(np, "8259-interrupt-acknowledge", NULL);
+ addrp = of_get_property(np, "8259-interrupt-acknowledge", NULL);
if (addrp == NULL)
continue;
- naddr = prom_n_addr_cells(np);
+ naddr = of_n_addr_cells(np);
intack = addrp[naddr-1];
if (naddr > 1)
intack |= ((unsigned long)addrp[naddr-2]) << 32;
@@ -664,10 +664,11 @@ static struct device_node *cpuid_to_of_node(int cpu)
int i, len;
const u32 *intserv;
- intserv = get_property(np, "ibm,ppc-interrupt-server#s", &len);
+ intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
+ &len);
if (!intserv)
- intserv = get_property(np, "reg", &len);
+ intserv = of_get_property(np, "reg", &len);
i = len / sizeof(u32);
@@ -709,7 +710,7 @@ void __init xics_init_IRQ(void)
/* Find the server numbers for the boot cpu. */
np = cpuid_to_of_node(boot_cpuid);
BUG_ON(!np);
- ireg = get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+ ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
if (!ireg)
goto skip_gserver_check;
i = ilen / sizeof(int);
@@ -725,7 +726,7 @@ void __init xics_init_IRQ(void)
default_server = hcpuid;
default_distrib_server = ireg[j+1];
- isize = get_property(np,
+ isize = of_get_property(np,
"ibm,interrupt-server#-size", NULL);
if (isize)
interrupt_server_size = *isize;
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 26ca3ffbc1d..9ce775c38ab 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -2,7 +2,9 @@ ifeq ($(CONFIG_PPC64),y)
EXTRA_CFLAGS += -mno-minimal-toc
endif
-obj-$(CONFIG_MPIC) += mpic.o
+mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
+obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
+
obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
obj-$(CONFIG_PPC_DCR) += dcr.o
@@ -11,17 +13,21 @@ obj-$(CONFIG_PPC_PMI) += pmi.o
obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
+obj-$(CONFIG_FSL_PCIE) += fsl_pcie.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
+# contains only the suspend handler for time
+obj-$(CONFIG_PM) += timer.o
+
ifeq ($(CONFIG_PPC_MERGE),y)
obj-$(CONFIG_PPC_I8259) += i8259.o
obj-$(CONFIG_PPC_83xx) += ipic.o
+obj-$(CONFIG_4xx) += uic.o
endif
# Temporary hack until we have migrated to asm-powerpc
ifeq ($(ARCH),powerpc)
-obj-$(CONFIG_MTD) += rom.o
obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o
obj-$(CONFIG_UCODE_PATCH) += micropatch.o
diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c
index 1488535b0e1..a1d2042bb30 100644
--- a/arch/powerpc/sysdev/dart_iommu.c
+++ b/arch/powerpc/sysdev/dart_iommu.c
@@ -36,6 +36,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
+#include <linux/suspend.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/iommu.h>
@@ -54,6 +55,9 @@ static unsigned long dart_tablesize;
/* Virtual base address of the DART table */
static u32 *dart_vbase;
+#ifdef CONFIG_PM
+static u32 *dart_copy;
+#endif
/* Mapped base address for the dart */
static unsigned int __iomem *dart;
@@ -333,7 +337,7 @@ void iommu_init_early_dart(void)
ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
/* Setup pci_dma ops */
- pci_dma_ops = &dma_iommu_ops;
+ set_pci_dma_ops(&dma_iommu_ops);
return;
}
@@ -343,9 +347,51 @@ void iommu_init_early_dart(void)
ppc_md.pci_dma_bus_setup = NULL;
/* Setup pci_dma ops */
- pci_dma_ops = &dma_direct_ops;
+ set_pci_dma_ops(&dma_direct_ops);
}
+#ifdef CONFIG_PM
+static void iommu_dart_save(void)
+{
+ memcpy(dart_copy, dart_vbase, 2*1024*1024);
+}
+
+static void iommu_dart_restore(void)
+{
+ memcpy(dart_vbase, dart_copy, 2*1024*1024);
+ dart_tlb_invalidate_all();
+}
+
+static int __init iommu_init_late_dart(void)
+{
+ unsigned long tbasepfn;
+ struct page *p;
+
+ /* if no dart table exists then we won't need to save it
+ * and the area has also not been reserved */
+ if (!dart_tablebase)
+ return 0;
+
+ tbasepfn = __pa(dart_tablebase) >> PAGE_SHIFT;
+ register_nosave_region_late(tbasepfn,
+ tbasepfn + ((1<<24) >> PAGE_SHIFT));
+
+ /* For suspend we need to copy the dart contents because
+ * it is not part of the regular mapping (see above) and
+ * thus not saved automatically. The memory for this copy
+ * must be allocated early because we need 2 MB. */
+ p = alloc_pages(GFP_KERNEL, 21 - PAGE_SHIFT);
+ BUG_ON(!p);
+ dart_copy = page_address(p);
+
+ ppc_md.iommu_save = iommu_dart_save;
+ ppc_md.iommu_restore = iommu_dart_restore;
+
+ return 0;
+}
+
+late_initcall(iommu_init_late_dart);
+#endif
void __init alloc_dart_table(void)
{
diff --git a/arch/powerpc/sysdev/dcr.c b/arch/powerpc/sysdev/dcr.c
index 1fc5819e7d1..574b6ef44e0 100644
--- a/arch/powerpc/sysdev/dcr.c
+++ b/arch/powerpc/sysdev/dcr.c
@@ -26,7 +26,7 @@
unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
{
unsigned int ds;
- const u32 *dr = get_property(np, "dcr-reg", &ds);
+ const u32 *dr = of_get_property(np, "dcr-reg", &ds);
if (dr == NULL || ds & 1 || index >= (ds / 8))
return 0;
@@ -37,7 +37,7 @@ unsigned int dcr_resource_start(struct device_node *np, unsigned int index)
unsigned int dcr_resource_len(struct device_node *np, unsigned int index)
{
unsigned int ds;
- const u32 *dr = get_property(np, "dcr-reg", &ds);
+ const u32 *dr = of_get_property(np, "dcr-reg", &ds);
if (dr == NULL || ds & 1 || index >= (ds / 8))
return 0;
@@ -53,9 +53,9 @@ static struct device_node * find_dcr_parent(struct device_node * node)
const u32 *p;
for (par = of_node_get(node); par;) {
- if (get_property(par, "dcr-controller", NULL))
+ if (of_get_property(par, "dcr-controller", NULL))
break;
- p = get_property(par, "dcr-parent", NULL);
+ p = of_get_property(par, "dcr-parent", NULL);
tmp = par;
if (p == NULL)
par = of_get_parent(par);
@@ -80,13 +80,13 @@ u64 of_translate_dcr_address(struct device_node *dev,
return OF_BAD_ADDR;
/* Stride is not properly defined yet, default to 0x10 for Axon */
- p = get_property(dp, "dcr-mmio-stride", NULL);
+ p = of_get_property(dp, "dcr-mmio-stride", NULL);
stride = (p == NULL) ? 0x10 : *p;
/* XXX FIXME: Which property name is to use of the 2 following ? */
- p = get_property(dp, "dcr-mmio-range", NULL);
+ p = of_get_property(dp, "dcr-mmio-range", NULL);
if (p == NULL)
- p = get_property(dp, "dcr-mmio-space", NULL);
+ p = of_get_property(dp, "dcr-mmio-space", NULL);
if (p == NULL)
return OF_BAD_ADDR;
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
index a2f4f730213..041c07e8b66 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_pcie.c
+++ b/arch/powerpc/sysdev/fsl_pcie.c
@@ -24,8 +24,6 @@
#include <asm/pci-bridge.h>
#include <asm/machdep.h>
-#include "mpc86xx.h"
-
#define PCI_CFG_OUT out_be32
/* ERRATA PCI-Ex 14 PCIE Controller timeout */
diff --git a/arch/powerpc/sysdev/fsl_pcie.h b/arch/powerpc/sysdev/fsl_pcie.h
new file mode 100644
index 00000000000..8d9779c84be
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_pcie.h
@@ -0,0 +1,94 @@
+/*
+ * MPC85xx/86xx PCI Express structure define
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc
+ *
+ * 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.
+ *
+ */
+
+#ifdef __KERNEL__
+#ifndef __POWERPC_FSL_PCIE_H
+#define __POWERPC_FSL_PCIE_H
+
+/* PCIE Express IO block registers in 85xx/86xx */
+
+struct ccsr_pex {
+ __be32 __iomem pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */
+ __be32 __iomem pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */
+ u8 __iomem res1[4];
+ __be32 __iomem pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */
+ __be32 __iomem pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */
+ u8 __iomem res2[12];
+ __be32 __iomem pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */
+ __be32 __iomem pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */
+ __be32 __iomem pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */
+ __be32 __iomem pex_pmcr; /* 0x.02c - PCI Express power management command register */
+ u8 __iomem res3[3024];
+ __be32 __iomem pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */
+ __be32 __iomem pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/
+ u8 __iomem res4[8];
+ __be32 __iomem pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/
+ u8 __iomem res5[12];
+ __be32 __iomem pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */
+ __be32 __iomem pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/
+ __be32 __iomem pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/
+ u8 __iomem res6[4];
+ __be32 __iomem pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/
+ u8 __iomem res7[12];
+ __be32 __iomem pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */
+ __be32 __iomem pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/
+ __be32 __iomem pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/
+ u8 __iomem res8[4];
+ __be32 __iomem pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/
+ u8 __iomem res9[12];
+ __be32 __iomem pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */
+ __be32 __iomem pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/
+ __be32 __iomem pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/
+ u8 __iomem res10[4];
+ __be32 __iomem pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/
+ u8 __iomem res11[12];
+ __be32 __iomem pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */
+ __be32 __iomem pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/
+ __be32 __iomem pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/
+ u8 __iomem res12[4];
+ __be32 __iomem pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/
+ u8 __iomem res13[12];
+ u8 __iomem res14[256];
+ __be32 __iomem pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */
+ u8 __iomem res15[4];
+ __be32 __iomem pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */
+ __be32 __iomem pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */
+ __be32 __iomem pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */
+ u8 __iomem res16[12];
+ __be32 __iomem pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */
+ u8 __iomem res17[4];
+ __be32 __iomem pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */
+ __be32 __iomem pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */
+ __be32 __iomem pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */
+ u8 __iomem res18[12];
+ __be32 __iomem pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */
+ u8 __iomem res19[4];
+ __be32 __iomem pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */
+ __be32 __iomem pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */
+ __be32 __iomem pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */
+ u8 __iomem res20[12];
+ __be32 __iomem pex_err_dr; /* 0x.e00 - PCI Express error detect register */
+ u8 __iomem res21[4];
+ __be32 __iomem pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */
+ u8 __iomem res22[4];
+ __be32 __iomem pex_err_disr; /* 0x.e10 - PCI Express error disable register */
+ u8 __iomem res23[12];
+ __be32 __iomem pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */
+ u8 __iomem res24[4];
+ __be32 __iomem pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */
+ __be32 __iomem pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */
+ __be32 __iomem pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */
+ __be32 __iomem pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */
+};
+
+#endif /* __POWERPC_FSL_PCIE_H */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index d20f02927f7..cad17572435 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -52,7 +52,7 @@ phys_addr_t get_immrbase(void)
soc = of_find_node_by_type(NULL, "soc");
if (soc) {
unsigned int size;
- const void *prop = get_property(soc, "reg", &size);
+ const void *prop = of_get_property(soc, "reg", &size);
if (prop)
immrbase = of_translate_address(soc, prop);
@@ -78,8 +78,8 @@ u32 get_brgfreq(void)
node = of_find_node_by_type(NULL, "cpm");
if (node) {
unsigned int size;
- const unsigned int *prop = get_property(node, "brg-frequency",
- &size);
+ const unsigned int *prop = of_get_property(node,
+ "brg-frequency", &size);
if (prop)
brgfreq = *prop;
@@ -103,8 +103,8 @@ u32 get_baudrate(void)
node = of_find_node_by_type(NULL, "serial");
if (node) {
unsigned int size;
- const unsigned int *prop = get_property(node, "current-speed",
- &size);
+ const unsigned int *prop = of_get_property(node,
+ "current-speed", &size);
if (prop)
fs_baudrate = *prop;
@@ -153,7 +153,8 @@ static int __init gfar_mdio_of_init(void)
while ((child = of_get_next_child(np, child)) != NULL) {
int irq = irq_of_parse_and_map(child, 0);
if (irq != NO_IRQ) {
- const u32 *id = get_property(child, "reg", NULL);
+ const u32 *id = of_get_property(child,
+ "reg", NULL);
mdio_data.irq[*id] = irq;
}
}
@@ -209,7 +210,7 @@ static int __init gfar_of_init(void)
of_irq_to_resource(np, 0, &r[1]);
- model = get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
/* If we aren't the FEC we have multiple interrupts */
if (model && strcasecmp(model, "FEC")) {
@@ -253,7 +254,7 @@ static int __init gfar_of_init(void)
FSL_GIANFAR_DEV_HAS_VLAN |
FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
- ph = get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
if (phy == NULL) {
@@ -263,7 +264,7 @@ static int __init gfar_of_init(void)
mdio = of_get_parent(phy);
- id = get_property(phy, "reg", NULL);
+ id = of_get_property(phy, "reg", NULL);
ret = of_address_to_resource(mdio, 0, &res);
if (ret) {
of_node_put(phy);
@@ -325,11 +326,11 @@ static int __init fsl_i2c_of_init(void)
}
i2c_data.device_flags = 0;
- flags = get_property(np, "dfsrr", NULL);
+ flags = of_get_property(np, "dfsrr", NULL);
if (flags)
i2c_data.device_flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
- flags = get_property(np, "fsl5200-clocking", NULL);
+ flags = of_get_property(np, "fsl5200-clocking", NULL);
if (flags)
i2c_data.device_flags |= FSL_I2C_DEV_CLOCK_5200;
@@ -374,7 +375,7 @@ static int __init mpc83xx_wdt_init(void)
goto nosoc;
}
- freq = get_property(soc, "bus-frequency", NULL);
+ freq = of_get_property(soc, "bus-frequency", NULL);
if (!freq) {
ret = -ENODEV;
goto err;
@@ -466,15 +467,15 @@ static int __init fsl_usb_of_init(void)
usb_data.operating_mode = FSL_USB2_MPH_HOST;
- prop = get_property(np, "port0", NULL);
+ prop = of_get_property(np, "port0", NULL);
if (prop)
usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
- prop = get_property(np, "port1", NULL);
+ prop = of_get_property(np, "port1", NULL);
if (prop)
usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
- prop = get_property(np, "phy_type", NULL);
+ prop = of_get_property(np, "phy_type", NULL);
usb_data.phy_mode = determine_usb_phy(prop);
ret =
@@ -501,7 +502,7 @@ static int __init fsl_usb_of_init(void)
of_irq_to_resource(np, 0, &r[1]);
- prop = get_property(np, "dr_mode", NULL);
+ prop = of_get_property(np, "dr_mode", NULL);
if (!prop || !strcmp(prop, "host")) {
usb_data.operating_mode = FSL_USB2_DR_HOST;
@@ -538,7 +539,7 @@ static int __init fsl_usb_of_init(void)
goto err;
}
- prop = get_property(np, "phy_type", NULL);
+ prop = of_get_property(np, "phy_type", NULL);
usb_data.phy_mode = determine_usb_phy(prop);
if (usb_dev_dr_host) {
@@ -633,7 +634,7 @@ static int __init fs_enet_of_init(void)
goto err;
}
- model = get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
if (model == NULL) {
ret = -ENODEV;
goto unreg;
@@ -643,7 +644,7 @@ static int __init fs_enet_of_init(void)
if (mac_addr)
memcpy(fs_enet_data.macaddr, mac_addr, 6);
- ph = get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
if (phy == NULL) {
@@ -651,12 +652,12 @@ static int __init fs_enet_of_init(void)
goto unreg;
}
- phy_addr = get_property(phy, "reg", NULL);
+ phy_addr = of_get_property(phy, "reg", NULL);
fs_enet_data.phy_addr = *phy_addr;
- phy_irq = get_property(phy, "interrupts", NULL);
+ phy_irq = of_get_property(phy, "interrupts", NULL);
- id = get_property(np, "device-id", NULL);
+ id = of_get_property(np, "device-id", NULL);
fs_enet_data.fs_no = *id;
strcpy(fs_enet_data.fs_type, model);
@@ -668,8 +669,10 @@ static int __init fs_enet_of_init(void)
goto unreg;
}
- fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
- fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+ fs_enet_data.clk_rx = *((u32 *)of_get_property(np,
+ "rx-clock", NULL));
+ fs_enet_data.clk_tx = *((u32 *)of_get_property(np,
+ "tx-clock", NULL));
if (strstr(model, "FCC")) {
int fcc_index = *id - 1;
@@ -690,7 +693,7 @@ static int __init fs_enet_of_init(void)
fs_enet_data.bus_id = (char*)&bus_id[(*id)];
fs_enet_data.init_ioports = init_fcc_ioports;
- mdio_bb_prop = get_property(phy, "bitbang", NULL);
+ mdio_bb_prop = of_get_property(phy, "bitbang", NULL);
if (mdio_bb_prop) {
struct platform_device *fs_enet_mdio_bb_dev;
struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
@@ -796,10 +799,10 @@ static int __init cpm_uart_of_init(void)
goto err;
}
- id = get_property(np, "device-id", NULL);
+ id = of_get_property(np, "device-id", NULL);
cpm_uart_data.fs_no = *id;
- model = (char*)get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
strcpy(cpm_uart_data.fs_type, model);
cpm_uart_data.uart_clk = ppc_proc_freq;
@@ -808,8 +811,10 @@ static int __init cpm_uart_of_init(void)
cpm_uart_data.tx_buf_size = 32;
cpm_uart_data.rx_num_fifo = 4;
cpm_uart_data.rx_buf_size = 32;
- cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
- cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+ cpm_uart_data.clk_rx = *((u32 *)of_get_property(np,
+ "rx-clock", NULL));
+ cpm_uart_data.clk_tx = *((u32 *)of_get_property(np,
+ "tx-clock", NULL));
ret =
platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
@@ -833,7 +838,7 @@ arch_initcall(cpm_uart_of_init);
#ifdef CONFIG_8xx
extern void init_scc_ioports(struct fs_platform_info*);
-extern int platform_device_skip(char *model, int id);
+extern int platform_device_skip(const char *model, int id);
static int __init fs_enet_mdio_of_init(void)
{
@@ -900,21 +905,22 @@ static int __init fs_enet_of_init(void)
struct resource r[4];
struct device_node *phy = NULL, *mdio = NULL;
struct fs_platform_info fs_enet_data;
- unsigned int *id, *phy_addr;
- void *mac_addr;
- phandle *ph;
- char *model;
+ const unsigned int *id;
+ const unsigned int *phy_addr;
+ const void *mac_addr;
+ const phandle *ph;
+ const char *model;
memset(r, 0, sizeof(r));
memset(&fs_enet_data, 0, sizeof(fs_enet_data));
- model = (char *)get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
if (model == NULL) {
ret = -ENODEV;
goto unreg;
}
- id = (u32 *) get_property(np, "device-id", NULL);
+ id = of_get_property(np, "device-id", NULL);
fs_enet_data.fs_no = *id;
if (platform_device_skip(model, *id))
@@ -929,12 +935,12 @@ static int __init fs_enet_of_init(void)
if (mac_addr)
memcpy(fs_enet_data.macaddr, mac_addr, 6);
- ph = (phandle *) get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
if (ph != NULL)
phy = of_find_node_by_phandle(*ph);
if (phy != NULL) {
- phy_addr = (u32 *) get_property(phy, "reg", NULL);
+ phy_addr = of_get_property(phy, "reg", NULL);
fs_enet_data.phy_addr = *phy_addr;
fs_enet_data.has_phy = 1;
@@ -947,7 +953,7 @@ static int __init fs_enet_of_init(void)
}
}
- model = (char*)get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
strcpy(fs_enet_data.fs_type, model);
if (strstr(model, "FEC")) {
@@ -1038,8 +1044,8 @@ static int __init cpm_smc_uart_of_init(void)
i++) {
struct resource r[3];
struct fs_uart_platform_info cpm_uart_data;
- int *id;
- char *model;
+ const int *id;
+ const char *model;
memset(r, 0, sizeof(r));
memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
@@ -1066,10 +1072,10 @@ static int __init cpm_smc_uart_of_init(void)
goto err;
}
- model = (char*)get_property(np, "model", NULL);
+ model = of_get_property(np, "model", NULL);
strcpy(cpm_uart_data.fs_type, model);
- id = (int*)get_property(np, "device-id", NULL);
+ id = of_get_property(np, "device-id", NULL);
cpm_uart_data.fs_no = *id;
cpm_uart_data.uart_clk = ppc_proc_freq;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index bcfb900481f..4fd2bec8991 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -36,6 +36,8 @@
#include <asm/mpic.h>
#include <asm/smp.h>
+#include "mpic.h"
+
#ifdef DEBUG
#define DBG(fmt...) printk(fmt)
#else
@@ -304,7 +306,7 @@ static void __init mpic_test_broken_ipi(struct mpic *mpic)
}
}
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
/* Test if an interrupt is sourced from HyperTransport (used on broken U3s)
* to force the edge setting on the MPIC and do the ack workaround.
@@ -354,6 +356,12 @@ static void mpic_startup_ht_interrupt(struct mpic *mpic, unsigned int source,
tmp |= 0x22;
writel(tmp, fixup->base + 4);
spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+
+#ifdef CONFIG_PM
+ /* use the lowest bit inverted to the actual HW,
+ * set if this fixup was enabled, clear otherwise */
+ mpic->save_data[source].fixup_data = tmp | 1;
+#endif
}
static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
@@ -375,7 +383,57 @@ static void mpic_shutdown_ht_interrupt(struct mpic *mpic, unsigned int source,
tmp |= 1;
writel(tmp, fixup->base + 4);
spin_unlock_irqrestore(&mpic->fixup_lock, flags);
+
+#ifdef CONFIG_PM
+ /* use the lowest bit inverted to the actual HW,
+ * set if this fixup was enabled, clear otherwise */
+ mpic->save_data[source].fixup_data = tmp & ~1;
+#endif
+}
+
+#ifdef CONFIG_PCI_MSI
+static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
+ unsigned int devfn)
+{
+ u8 __iomem *base;
+ u8 pos, flags;
+ u64 addr = 0;
+
+ for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
+ pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
+ u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
+ if (id == PCI_CAP_ID_HT) {
+ id = readb(devbase + pos + 3);
+ if ((id & HT_5BIT_CAP_MASK) == HT_CAPTYPE_MSI_MAPPING)
+ break;
+ }
+ }
+
+ if (pos == 0)
+ return;
+
+ base = devbase + pos;
+
+ flags = readb(base + HT_MSI_FLAGS);
+ if (!(flags & HT_MSI_FLAGS_FIXED)) {
+ addr = readl(base + HT_MSI_ADDR_LO) & HT_MSI_ADDR_LO_MASK;
+ addr = addr | ((u64)readl(base + HT_MSI_ADDR_HI) << 32);
+ }
+
+ printk(KERN_DEBUG "mpic: - HT:%02x.%x %s MSI mapping found @ 0x%lx\n",
+ PCI_SLOT(devfn), PCI_FUNC(devfn),
+ flags & HT_MSI_FLAGS_ENABLE ? "enabled" : "disabled", addr);
+
+ if (!(flags & HT_MSI_FLAGS_ENABLE))
+ writeb(flags | HT_MSI_FLAGS_ENABLE, base + HT_MSI_FLAGS);
}
+#else
+static void __init mpic_scan_ht_msi(struct mpic *mpic, u8 __iomem *devbase,
+ unsigned int devfn)
+{
+ return;
+}
+#endif
static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
unsigned int devfn, u32 vdid)
@@ -468,6 +526,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
goto next;
mpic_scan_ht_pic(mpic, devbase, devfn, l);
+ mpic_scan_ht_msi(mpic, devbase, devfn);
next:
/* next device, if function 0 */
@@ -476,7 +535,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
}
}
-#else /* CONFIG_MPIC_BROKEN_U3 */
+#else /* CONFIG_MPIC_U3_HT_IRQS */
static inline int mpic_is_ht_interrupt(struct mpic *mpic, unsigned int source)
{
@@ -487,7 +546,7 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic)
{
}
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
#define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
@@ -559,7 +618,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
*/
-static void mpic_unmask_irq(unsigned int irq)
+void mpic_unmask_irq(unsigned int irq)
{
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq);
@@ -579,7 +638,7 @@ static void mpic_unmask_irq(unsigned int irq)
} while(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK);
}
-static void mpic_mask_irq(unsigned int irq)
+void mpic_mask_irq(unsigned int irq)
{
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq(irq);
@@ -600,7 +659,7 @@ static void mpic_mask_irq(unsigned int irq)
} while(!(mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)) & MPIC_VECPRI_MASK));
}
-static void mpic_end_irq(unsigned int irq)
+void mpic_end_irq(unsigned int irq)
{
struct mpic *mpic = mpic_from_irq(irq);
@@ -615,7 +674,7 @@ static void mpic_end_irq(unsigned int irq)
mpic_eoi(mpic);
}
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
static void mpic_unmask_ht_irq(unsigned int irq)
{
@@ -665,7 +724,7 @@ static void mpic_end_ht_irq(unsigned int irq)
mpic_ht_end_irq(mpic, src);
mpic_eoi(mpic);
}
-#endif /* !CONFIG_MPIC_BROKEN_U3 */
+#endif /* !CONFIG_MPIC_U3_HT_IRQS */
#ifdef CONFIG_SMP
@@ -733,7 +792,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
}
}
-static int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
+int mpic_set_irq_type(unsigned int virq, unsigned int flow_type)
{
struct mpic *mpic = mpic_from_irq(virq);
unsigned int src = mpic_irq_to_hw(virq);
@@ -788,7 +847,7 @@ static struct irq_chip mpic_ipi_chip = {
};
#endif /* CONFIG_SMP */
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
static struct irq_chip mpic_irq_ht_chip = {
.startup = mpic_startup_ht_irq,
.shutdown = mpic_shutdown_ht_irq,
@@ -797,7 +856,7 @@ static struct irq_chip mpic_irq_ht_chip = {
.eoi = mpic_end_ht_irq,
.set_type = mpic_set_irq_type,
};
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
static int mpic_host_match(struct irq_host *h, struct device_node *node)
@@ -834,14 +893,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
if (hw >= mpic->irq_count)
return -EINVAL;
+ mpic_msi_reserve_hwirq(mpic, hw);
+
/* Default chip */
chip = &mpic->hc_irq;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
/* Check for HT interrupts, override vecpri */
if (mpic_is_ht_interrupt(mpic, hw))
chip = &mpic->hc_ht_irq;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
DBG("mpic: mapping to irq chip @%p\n", chip);
@@ -937,12 +998,12 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->hc_irq.typename = name;
if (flags & MPIC_PRIMARY)
mpic->hc_irq.set_affinity = mpic_set_affinity;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
mpic->hc_ht_irq = mpic_irq_ht_chip;
mpic->hc_ht_irq.typename = name;
if (flags & MPIC_PRIMARY)
mpic->hc_ht_irq.set_affinity = mpic_set_affinity;
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
#ifdef CONFIG_SMP
mpic->hc_ipi = mpic_ipi_chip;
@@ -970,7 +1031,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->spurious_vec = intvec_top;
/* Check for "big-endian" in device-tree */
- if (node && get_property(node, "big-endian", NULL) != NULL)
+ if (node && of_get_property(node, "big-endian", NULL) != NULL)
mpic->flags |= MPIC_BIG_ENDIAN;
@@ -986,13 +1047,13 @@ struct mpic * __init mpic_alloc(struct device_node *node,
BUG_ON(paddr == 0 && node == NULL);
/* If no physical address passed in, check if it's dcr based */
- if (paddr == 0 && get_property(node, "dcr-reg", NULL) != NULL)
+ if (paddr == 0 && of_get_property(node, "dcr-reg", NULL) != NULL)
mpic->flags |= MPIC_USES_DCR;
#ifdef CONFIG_PPC_DCR
if (mpic->flags & MPIC_USES_DCR) {
const u32 *dbasep;
- dbasep = get_property(node, "dcr-reg", NULL);
+ dbasep = of_get_property(node, "dcr-reg", NULL);
BUG_ON(dbasep == NULL);
mpic->dcr_base = *dbasep;
mpic->reg_type = mpic_access_dcr;
@@ -1006,7 +1067,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
*/
if (paddr == 0 && !(mpic->flags & MPIC_USES_DCR)) {
const u32 *reg;
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
BUG_ON(reg == NULL);
paddr = of_translate_address(node, reg);
BUG_ON(paddr == OF_BAD_ADDR);
@@ -1142,8 +1203,10 @@ void __init mpic_init(struct mpic *mpic)
/* Do the HT PIC fixups on U3 broken mpic */
DBG("MPIC flags: %x\n", mpic->flags);
- if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY))
- mpic_scan_ht_pics(mpic);
+ if ((mpic->flags & MPIC_U3_HT_IRQS) && (mpic->flags & MPIC_PRIMARY)) {
+ mpic_scan_ht_pics(mpic);
+ mpic_u3msi_init(mpic);
+ }
for (i = 0; i < mpic->num_sources; i++) {
/* start with vector = source number, and masked */
@@ -1167,6 +1230,12 @@ void __init mpic_init(struct mpic *mpic)
/* Set current processor priority to 0 */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0);
+
+#ifdef CONFIG_PM
+ /* allocate memory to save mpic state */
+ mpic->save_data = alloc_bootmem(mpic->num_sources * sizeof(struct mpic_irq_save));
+ BUG_ON(mpic->save_data == NULL);
+#endif
}
void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)
@@ -1333,8 +1402,11 @@ unsigned int mpic_get_one_irq(struct mpic *mpic)
#ifdef DEBUG_LOW
DBG("%s: get_one_irq(): %d\n", mpic->name, src);
#endif
- if (unlikely(src == mpic->spurious_vec))
+ if (unlikely(src == mpic->spurious_vec)) {
+ if (mpic->flags & MPIC_SPV_EOI)
+ mpic_eoi(mpic);
return NO_IRQ;
+ }
return irq_linear_revmap(mpic->irqhost, src);
}
@@ -1417,3 +1489,79 @@ void __devinit smp_mpic_setup_cpu(int cpu)
mpic_setup_this_cpu();
}
#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PM
+static int mpic_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct mpic *mpic = container_of(dev, struct mpic, sysdev);
+ int i;
+
+ for (i = 0; i < mpic->num_sources; i++) {
+ mpic->save_data[i].vecprio =
+ mpic_irq_read(i, MPIC_INFO(IRQ_VECTOR_PRI));
+ mpic->save_data[i].dest =
+ mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
+ }
+
+ return 0;
+}
+
+static int mpic_resume(struct sys_device *dev)
+{
+ struct mpic *mpic = container_of(dev, struct mpic, sysdev);
+ int i;
+
+ for (i = 0; i < mpic->num_sources; i++) {
+ mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI),
+ mpic->save_data[i].vecprio);
+ mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
+ mpic->save_data[i].dest);
+
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+ {
+ struct mpic_irq_fixup *fixup = &mpic->fixups[i];
+
+ if (fixup->base) {
+ /* we use the lowest bit in an inverted meaning */
+ if ((mpic->save_data[i].fixup_data & 1) == 0)
+ continue;
+
+ /* Enable and configure */
+ writeb(0x10 + 2 * fixup->index, fixup->base + 2);
+
+ writel(mpic->save_data[i].fixup_data & ~1,
+ fixup->base + 4);
+ }
+ }
+#endif
+ } /* end for loop */
+
+ return 0;
+}
+#endif
+
+static struct sysdev_class mpic_sysclass = {
+#ifdef CONFIG_PM
+ .resume = mpic_resume,
+ .suspend = mpic_suspend,
+#endif
+ set_kset_name("mpic"),
+};
+
+static int mpic_init_sys(void)
+{
+ struct mpic *mpic = mpics;
+ int error, id = 0;
+
+ error = sysdev_class_register(&mpic_sysclass);
+
+ while (mpic && !error) {
+ mpic->sysdev.cls = &mpic_sysclass;
+ mpic->sysdev.id = id++;
+ error = sysdev_register(&mpic->sysdev);
+ mpic = mpic->next;
+ }
+ return error;
+}
+
+device_initcall(mpic_init_sys);
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
new file mode 100644
index 00000000000..3a1c3d2c594
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic.h
@@ -0,0 +1,38 @@
+#ifndef _POWERPC_SYSDEV_MPIC_H
+#define _POWERPC_SYSDEV_MPIC_H
+
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#ifdef CONFIG_PCI_MSI
+extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
+extern int mpic_msi_init_allocator(struct mpic *mpic);
+extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
+extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
+extern int mpic_u3msi_init(struct mpic *mpic);
+#else
+static inline void mpic_msi_reserve_hwirq(struct mpic *mpic,
+ irq_hw_number_t hwirq)
+{
+ return;
+}
+
+static inline int mpic_u3msi_init(struct mpic *mpic)
+{
+ return -1;
+}
+#endif
+
+extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
+extern void mpic_end_irq(unsigned int irq);
+extern void mpic_mask_irq(unsigned int irq);
+extern void mpic_unmask_irq(unsigned int irq);
+
+#endif /* _POWERPC_SYSDEV_MPIC_H */
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
new file mode 100644
index 00000000000..b076793033c
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_msi.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/bitmap.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+
+static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+ pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
+ bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
+}
+
+void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
+{
+ unsigned long flags;
+
+ /* The mpic calls this even when there is no allocator setup */
+ if (!mpic->hwirq_bitmap)
+ return;
+
+ spin_lock_irqsave(&mpic->bitmap_lock, flags);
+ __mpic_msi_reserve_hwirq(mpic, hwirq);
+ spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
+{
+ unsigned long flags;
+ int offset, order = get_count_order(num);
+
+ spin_lock_irqsave(&mpic->bitmap_lock, flags);
+ /*
+ * This is fast, but stricter than we need. We might want to add
+ * a fallback routine which does a linear search with no alignment.
+ */
+ offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count,
+ order);
+ spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+
+ pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
+ num, order, offset);
+
+ return offset;
+}
+
+void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
+{
+ unsigned long flags;
+ int order = get_count_order(num);
+
+ pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
+ num, order, offset);
+
+ spin_lock_irqsave(&mpic->bitmap_lock, flags);
+ bitmap_release_region(mpic->hwirq_bitmap, offset, order);
+ spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+}
+
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+ irq_hw_number_t hwirq;
+ struct irq_host_ops *ops = mpic->irqhost->ops;
+ struct device_node *np;
+ int flags, index, i;
+ struct of_irq oirq;
+
+ pr_debug("mpic: found U3, guessing msi allocator setup\n");
+
+ /* Reserve source numbers we know are reserved in the HW */
+ for (i = 0; i < 8; i++)
+ __mpic_msi_reserve_hwirq(mpic, i);
+
+ for (i = 42; i < 46; i++)
+ __mpic_msi_reserve_hwirq(mpic, i);
+
+ for (i = 100; i < 105; i++)
+ __mpic_msi_reserve_hwirq(mpic, i);
+
+ np = NULL;
+ while ((np = of_find_all_nodes(np))) {
+ pr_debug("mpic: mapping hwirqs for %s\n", np->full_name);
+
+ index = 0;
+ while (of_irq_map_one(np, index++, &oirq) == 0) {
+ ops->xlate(mpic->irqhost, NULL, oirq.specifier,
+ oirq.size, &hwirq, &flags);
+ __mpic_msi_reserve_hwirq(mpic, hwirq);
+ }
+ }
+
+ return 0;
+}
+#else
+static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
+{
+ return -1;
+}
+#endif
+
+static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
+{
+ int i, len;
+ const u32 *p;
+
+ p = of_get_property(mpic->of_node, "msi-available-ranges", &len);
+ if (!p) {
+ pr_debug("mpic: no msi-available-ranges property found on %s\n",
+ mpic->of_node->full_name);
+ return -ENODEV;
+ }
+
+ if (len % 8 != 0) {
+ printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
+ "property on %s\n", mpic->of_node->full_name);
+ return -EINVAL;
+ }
+
+ bitmap_allocate_region(mpic->hwirq_bitmap, 0,
+ get_count_order(mpic->irq_count));
+
+ /* Format is: (<u32 start> <u32 count>)+ */
+ len /= sizeof(u32);
+ for (i = 0; i < len / 2; i++, p += 2)
+ mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
+
+ return 0;
+}
+
+int mpic_msi_init_allocator(struct mpic *mpic)
+{
+ int rc, size;
+
+ BUG_ON(mpic->hwirq_bitmap);
+ spin_lock_init(&mpic->bitmap_lock);
+
+ size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
+ pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
+
+ if (mem_init_done)
+ mpic->hwirq_bitmap = kmalloc(size, GFP_KERNEL);
+ else
+ mpic->hwirq_bitmap = alloc_bootmem(size);
+
+ if (!mpic->hwirq_bitmap) {
+ pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
+ return -ENOMEM;
+ }
+
+ memset(mpic->hwirq_bitmap, 0, size);
+
+ rc = mpic_msi_reserve_dt_hwirqs(mpic);
+ if (rc) {
+ if (mpic->flags & MPIC_U3_HT_IRQS)
+ rc = mpic_msi_reserve_u3_hwirqs(mpic);
+
+ if (rc)
+ goto out_free;
+ }
+
+ return 0;
+
+ out_free:
+ if (mem_init_done)
+ kfree(mpic->hwirq_bitmap);
+
+ mpic->hwirq_bitmap = NULL;
+ return rc;
+}
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
new file mode 100644
index 00000000000..305b864c25d
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2006, Segher Boessenkool, IBM Corporation.
+ * Copyright 2006-2007, Michael Ellerman, IBM Corporation.
+ *
+ * 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; version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+#include <linux/msi.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+
+#include "mpic.h"
+
+/* A bit ugly, can we get this from the pci_dev somehow? */
+static struct mpic *msi_mpic;
+
+static void mpic_u3msi_mask_irq(unsigned int irq)
+{
+ mask_msi_irq(irq);
+ mpic_mask_irq(irq);
+}
+
+static void mpic_u3msi_unmask_irq(unsigned int irq)
+{
+ mpic_unmask_irq(irq);
+ unmask_msi_irq(irq);
+}
+
+static struct irq_chip mpic_u3msi_chip = {
+ .shutdown = mpic_u3msi_mask_irq,
+ .mask = mpic_u3msi_mask_irq,
+ .unmask = mpic_u3msi_unmask_irq,
+ .eoi = mpic_end_irq,
+ .set_type = mpic_set_irq_type,
+ .typename = "MPIC-U3MSI",
+};
+
+static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos)
+{
+ u8 flags;
+ u32 tmp;
+ u64 addr;
+
+ pci_read_config_byte(pdev, pos + HT_MSI_FLAGS, &flags);
+
+ if (flags & HT_MSI_FLAGS_FIXED)
+ return HT_MSI_FIXED_ADDR;
+
+ pci_read_config_dword(pdev, pos + HT_MSI_ADDR_LO, &tmp);
+ addr = tmp & HT_MSI_ADDR_LO_MASK;
+ pci_read_config_dword(pdev, pos + HT_MSI_ADDR_HI, &tmp);
+ addr = addr | ((u64)tmp << 32);
+
+ return addr;
+}
+
+static u64 find_ht_magic_addr(struct pci_dev *pdev)
+{
+ struct pci_bus *bus;
+ unsigned int pos;
+
+ for (bus = pdev->bus; bus; bus = bus->parent) {
+ pos = pci_find_ht_capability(bus->self, HT_CAPTYPE_MSI_MAPPING);
+ if (pos)
+ return read_ht_magic_addr(bus->self, pos);
+ }
+
+ return 0;
+}
+
+static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+ if (type == PCI_CAP_ID_MSIX)
+ pr_debug("u3msi: MSI-X untested, trying anyway.\n");
+
+ /* If we can't find a magic address then MSI ain't gonna work */
+ if (find_ht_magic_addr(pdev) == 0) {
+ pr_debug("u3msi: no magic address found for %s\n",
+ pci_name(pdev));
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
+{
+ struct msi_desc *entry;
+
+ list_for_each_entry(entry, &pdev->msi_list, list) {
+ if (entry->irq == NO_IRQ)
+ continue;
+
+ set_irq_msi(entry->irq, NULL);
+ mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
+ irq_dispose_mapping(entry->irq);
+ }
+
+ return;
+}
+
+static void u3msi_compose_msi_msg(struct pci_dev *pdev, int virq,
+ struct msi_msg *msg)
+{
+ u64 addr;
+
+ addr = find_ht_magic_addr(pdev);
+ msg->address_lo = addr & 0xFFFFFFFF;
+ msg->address_hi = addr >> 32;
+ msg->data = virq_to_hw(virq);
+
+ pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) at address 0x%lx\n",
+ virq, virq_to_hw(virq), addr);
+}
+
+static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
+{
+ irq_hw_number_t hwirq;
+ int rc;
+ unsigned int virq;
+ struct msi_desc *entry;
+ struct msi_msg msg;
+
+ list_for_each_entry(entry, &pdev->msi_list, list) {
+ hwirq = mpic_msi_alloc_hwirqs(msi_mpic, 1);
+ if (hwirq < 0) {
+ rc = hwirq;
+ pr_debug("u3msi: failed allocating hwirq\n");
+ goto out_free;
+ }
+
+ virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
+ if (virq == NO_IRQ) {
+ pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
+ mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
+ rc = -ENOSPC;
+ goto out_free;
+ }
+
+ set_irq_msi(virq, entry);
+ set_irq_chip(virq, &mpic_u3msi_chip);
+ set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
+
+ u3msi_compose_msi_msg(pdev, virq, &msg);
+ write_msi_msg(virq, &msg);
+
+ hwirq++;
+ }
+
+ return 0;
+
+ out_free:
+ u3msi_teardown_msi_irqs(pdev);
+ return rc;
+}
+
+int mpic_u3msi_init(struct mpic *mpic)
+{
+ int rc;
+
+ rc = mpic_msi_init_allocator(mpic);
+ if (rc) {
+ pr_debug("u3msi: Error allocating bitmap!\n");
+ return rc;
+ }
+
+ pr_debug("u3msi: Registering MPIC U3 MSI callbacks.\n");
+
+ BUG_ON(msi_mpic);
+ msi_mpic = mpic;
+
+ WARN_ON(ppc_md.setup_msi_irqs);
+ ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs;
+ ppc_md.msi_check_device = u3msi_msi_check_device;
+
+ return 0;
+}
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index a5282011d39..85a7c99c100 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -33,7 +33,7 @@
#include <asm/of_platform.h>
#include <asm/io.h>
#include <asm/pmi.h>
-
+#include <asm/prom.h>
struct pmi_data {
struct list_head handler;
@@ -49,21 +49,6 @@ struct pmi_data {
};
-
-static void __iomem *of_iomap(struct device_node *np)
-{
- struct resource res;
-
- if (of_address_to_resource(np, 0, &res))
- return NULL;
-
- pr_debug("Resource start: 0x%lx\n", res.start);
- pr_debug("Resource end: 0x%lx\n", res.end);
-
- return ioremap(res.start, 1 + res.end - res.start);
-}
-
-
static int pmi_irq_handler(int irq, void *dev_id)
{
struct pmi_data *data;
@@ -118,6 +103,7 @@ out:
static struct of_device_id pmi_match[] = {
{ .type = "ibm,pmi", .name = "ibm,pmi" },
+ { .type = "ibm,pmi" },
{},
};
@@ -153,7 +139,7 @@ static int pmi_of_probe(struct of_device *dev,
goto out;
}
- data->pmi_reg = of_iomap(np);
+ data->pmi_reg = of_iomap(np, 0);
if (!data->pmi_reg) {
printk(KERN_ERR "pmi: invalid register address.\n");
rc = -EFAULT;
@@ -279,6 +265,9 @@ void pmi_register_handler(struct of_device *device,
struct pmi_data *data;
data = device->dev.driver_data;
+ if (!data)
+ return;
+
spin_lock(&data->handler_spinlock);
list_add_tail(&handler->node, &data->handler);
spin_unlock(&data->handler_spinlock);
@@ -289,10 +278,12 @@ void pmi_unregister_handler(struct of_device *device,
struct pmi_handler *handler)
{
struct pmi_data *data;
+ data = device->dev.driver_data;
- pr_debug("pmi: unregistering handler %p\n", handler);
+ if (!data)
+ return;
- data = device->dev.driver_data;
+ pr_debug("pmi: unregistering handler %p\n", handler);
spin_lock(&data->handler_spinlock);
list_del(&handler->node);
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
index a725e80befa..887739f3bad 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -2,11 +2,8 @@
# QE Communication options
#
-menu "QE Options"
- depends on QUICC_ENGINE
-
config UCC_SLOW
- bool "UCC Slow Protocols Support"
+ bool
default n
select UCC
help
@@ -14,10 +11,9 @@ config UCC_SLOW
protocols: UART, BISYNC, QMC
config UCC_FAST
- bool "UCC Fast Protocols Support"
+ bool
default n
select UCC
- select UCC_SLOW
help
This option provides qe_lib support to UCC fast
protocols: HDLC, Ethernet, ATM, transparent
@@ -26,5 +22,3 @@ config UCC
bool
default y if UCC_FAST || UCC_SLOW
-endmenu
-
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 43f6cc9d7ea..7f4c0754396 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -71,7 +71,7 @@ phys_addr_t get_qe_base(void)
qe = of_find_node_by_type(NULL, "qe");
if (qe) {
unsigned int size;
- const void *prop = get_property(qe, "reg", &size);
+ const void *prop = of_get_property(qe, "reg", &size);
qebase = of_translate_address(qe, prop);
of_node_put(qe);
};
@@ -158,7 +158,7 @@ unsigned int get_brg_clk(void)
qe = of_find_node_by_type(NULL, "qe");
if (qe) {
unsigned int size;
- const u32 *prop = get_property(qe, "brg-frequency", &size);
+ const u32 *prop = of_get_property(qe, "brg-frequency", &size);
brg_clk = *prop;
of_node_put(qe);
};
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index 0afe6bfe371..e32b45bf9ff 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -53,7 +53,7 @@ int par_io_init(struct device_node *np)
return ret;
par_io = ioremap(res.start, res.end - res.start + 1);
- num_ports = get_property(np, "num-ports", NULL);
+ num_ports = of_get_property(np, "num-ports", NULL);
if (num_ports)
num_par_io_ports = *num_ports;
@@ -161,7 +161,7 @@ int par_io_of_config(struct device_node *np)
return -1;
}
- ph = get_property(np, "pio-handle", NULL);
+ ph = of_get_property(np, "pio-handle", NULL);
if (ph == 0) {
printk(KERN_ERR "pio-handle not available \n");
return -1;
@@ -169,7 +169,7 @@ int par_io_of_config(struct device_node *np)
pio = of_find_node_by_phandle(*ph);
- pio_map = get_property(pio, "pio-map", &pio_map_len);
+ pio_map = of_get_property(pio, "pio-map", &pio_map_len);
if (pio_map == NULL) {
printk(KERN_ERR "pio-map is not set! \n");
return -1;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index a457ac1c663..66137bf2dfb 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -210,6 +210,9 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
uf_regs = uccf->uf_regs;
uccf->p_ucce = (u32 *) & (uf_regs->ucce);
uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ uccf->p_utodr = (u16 *) & (uf_regs->utodr);
+#endif
#ifdef STATISTICS
uccf->tx_frames = 0;
uccf->rx_frames = 0;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
index 817df73ecf5..b930d686a4d 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -187,7 +187,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
/* Init Guemr register */
- if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->regs)))) {
+ if ((ret = ucc_init_guemr((struct ucc_common *) us_regs))) {
printk(KERN_ERR "%s: cannot init GUEMR", __FUNCTION__);
ucc_slow_free(uccs);
return ret;
@@ -195,7 +195,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc
/* Set UCC to slow type */
if ((ret = ucc_set_type(us_info->ucc_num,
- (struct ucc_common *) (us_info->regs),
+ (struct ucc_common *) us_regs,
UCC_SPEED_TYPE_SLOW))) {
printk(KERN_ERR "%s: cannot set UCC type", __FUNCTION__);
ucc_slow_free(uccs);
diff --git a/arch/powerpc/sysdev/rom.c b/arch/powerpc/sysdev/rom.c
deleted file mode 100644
index c855a3b298a..00000000000
--- a/arch/powerpc/sysdev/rom.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * ROM device registration
- *
- * (C) 2006 MontaVista Software, Inc. 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/kernel.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
-
-static int __init powerpc_flash_init(void)
-{
- struct device_node *node = NULL;
-
- /*
- * Register all the devices which type is "rom"
- */
- while ((node = of_find_node_by_type(node, "rom")) != NULL) {
- if (node->name == NULL) {
- printk(KERN_WARNING "powerpc_flash_init: found 'rom' "
- "device, but with no name, skipping...\n");
- continue;
- }
- of_platform_device_create(node, node->name, NULL);
- }
- return 0;
-}
-
-arch_initcall(powerpc_flash_init);
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
new file mode 100644
index 00000000000..4a01748b421
--- /dev/null
+++ b/arch/powerpc/sysdev/timer.c
@@ -0,0 +1,71 @@
+/*
+ * Common code to keep time when machine suspends.
+ *
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ */
+
+#include <linux/time.h>
+#include <linux/sysdev.h>
+#include <asm/rtc.h>
+
+static unsigned long suspend_rtc_time;
+
+/*
+ * Reset the time after a sleep.
+ */
+static int timer_resume(struct sys_device *dev)
+{
+ struct timeval tv;
+ struct timespec ts;
+ struct rtc_time cur_rtc_tm;
+ unsigned long cur_rtc_time, diff;
+
+ /* get current RTC time and convert to seconds */
+ get_rtc_time(&cur_rtc_tm);
+ rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
+
+ diff = cur_rtc_time - suspend_rtc_time;
+
+ /* adjust time of day by seconds that elapsed while
+ * we were suspended */
+ do_gettimeofday(&tv);
+ ts.tv_sec = tv.tv_sec + diff;
+ ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC;
+ do_settimeofday(&ts);
+
+ return 0;
+}
+
+static int timer_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct rtc_time suspend_rtc_tm;
+ WARN_ON(!ppc_md.get_rtc_time);
+
+ get_rtc_time(&suspend_rtc_tm);
+ rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
+
+ return 0;
+}
+
+static struct sysdev_class timer_sysclass = {
+ .resume = timer_resume,
+ .suspend = timer_suspend,
+ set_kset_name("timer"),
+};
+
+static struct sys_device device_timer = {
+ .id = 0,
+ .cls = &timer_sysclass,
+};
+
+static int time_init_device(void)
+{
+ int error = sysdev_class_register(&timer_sysclass);
+ if (!error)
+ error = sysdev_register(&device_timer);
+ return error;
+}
+
+device_initcall(time_init_device);
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index 97f37ef4bbb..7d3b09b7d54 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -48,7 +48,7 @@ phys_addr_t get_csrbase(void)
tsi = of_find_node_by_type(NULL, "tsi-bridge");
if (tsi) {
unsigned int size;
- const void *prop = get_property(tsi, "reg", &size);
+ const void *prop = of_get_property(tsi, "reg", &size);
tsi108_csr_base = of_translate_address(tsi, prop);
of_node_put(tsi);
};
@@ -77,10 +77,10 @@ static int __init tsi108_eth_of_init(void)
struct resource r[2];
struct device_node *phy;
hw_info tsi_eth_data;
- unsigned int *id;
- unsigned int *phy_id;
+ const unsigned int *id;
+ const unsigned int *phy_id;
const void *mac_addr;
- phandle *ph;
+ const phandle *ph;
memset(r, 0, sizeof(r));
memset(&tsi_eth_data, 0, sizeof(tsi_eth_data));
@@ -107,10 +107,11 @@ static int __init tsi108_eth_of_init(void)
goto err;
}
- mac_addr = get_property(np, "address", NULL);
- memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
+ mac_addr = of_get_mac_address(np);
+ if (mac_addr)
+ memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
- ph = (phandle *) get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
if (phy == NULL) {
@@ -118,8 +119,8 @@ static int __init tsi108_eth_of_init(void)
goto unreg;
}
- id = (u32 *) get_property(phy, "reg", NULL);
- phy_id = (u32 *) get_property(phy, "phy-id", NULL);
+ id = of_get_property(phy, "reg", NULL);
+ phy_id = of_get_property(phy, "phy-id", NULL);
ret = of_address_to_resource(phy, 0, &res);
if (ret) {
of_node_put(phy);
@@ -129,6 +130,8 @@ static int __init tsi108_eth_of_init(void)
tsi_eth_data.phyregs = res.start;
tsi_eth_data.phy = *phy_id;
tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0);
+ if (of_device_is_compatible(phy, "bcm54xx"))
+ tsi_eth_data.phy_type = TSI108_PHY_BCM54XX;
of_node_put(phy);
ret =
platform_device_add_data(tsi_eth_dev, &tsi_eth_data,
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index ae249c6bbbc..2153163fa59 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -35,6 +35,7 @@
#include <asm/machdep.h>
#include <asm/pci-bridge.h>
#include <asm/tsi108.h>
+#include <asm/tsi108_pci.h>
#include <asm/tsi108_irq.h>
#include <asm/prom.h>
@@ -49,6 +50,7 @@
((((bus)<<16) | ((devfunc)<<8) | (offset & 0xfc)) + tsi108_pci_cfg_base)
u32 tsi108_pci_cfg_base;
+static u32 tsi108_pci_cfg_phys;
u32 tsi108_csr_vir_base;
static struct device_node *pci_irq_node;
static struct irq_host *pci_irq_host;
@@ -185,7 +187,7 @@ tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
void tsi108_clear_pci_cfg_error(void)
{
- tsi108_clear_pci_error(TSI108_PCI_CFG_BASE_PHYS);
+ tsi108_clear_pci_error(tsi108_pci_cfg_phys);
}
static struct pci_ops tsi108_direct_pci_ops = {
@@ -193,17 +195,17 @@ static struct pci_ops tsi108_direct_pci_ops = {
tsi108_direct_write_config
};
-int __init tsi108_setup_pci(struct device_node *dev)
+int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary)
{
int len;
struct pci_controller *hose;
struct resource rsrc;
const int *bus_range;
- int primary = 0, has_address = 0;
+ int has_address = 0;
/* PCI Config mapping */
- tsi108_pci_cfg_base = (u32)ioremap(TSI108_PCI_CFG_BASE_PHYS,
- TSI108_PCI_CFG_SIZE);
+ tsi108_pci_cfg_base = (u32)ioremap(cfg_phys, TSI108_PCI_CFG_SIZE);
+ tsi108_pci_cfg_phys = cfg_phys;
DBG("TSI_PCI: %s tsi108_pci_cfg_base=0x%x\n", __FUNCTION__,
tsi108_pci_cfg_base);
@@ -211,7 +213,7 @@ int __init tsi108_setup_pci(struct device_node *dev)
has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
/* Get bus range if any */
- bus_range = get_property(dev, "bus-range", &len);
+ bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int)) {
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
new file mode 100644
index 00000000000..89059895a20
--- /dev/null
+++ b/arch/powerpc/sysdev/uic.c
@@ -0,0 +1,342 @@
+/*
+ * arch/powerpc/sysdev/uic.c
+ *
+ * IBM PowerPC 4xx Universal Interrupt Controller
+ *
+ * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sysdev.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/dcr.h>
+
+#define NR_UIC_INTS 32
+
+#define UIC_SR 0x0
+#define UIC_ER 0x2
+#define UIC_CR 0x3
+#define UIC_PR 0x4
+#define UIC_TR 0x5
+#define UIC_MSR 0x6
+#define UIC_VR 0x7
+#define UIC_VCR 0x8
+
+#define uic_irq_to_hw(virq) (irq_map[virq].hwirq)
+
+struct uic *primary_uic;
+
+struct uic {
+ int index;
+ int dcrbase;
+
+ spinlock_t lock;
+
+ /* The remapper for this UIC */
+ struct irq_host *irqhost;
+
+ /* For secondary UICs, the cascade interrupt's irqaction */
+ struct irqaction cascade;
+
+ /* The device node of the interrupt controller */
+ struct device_node *of_node;
+};
+
+static void uic_unmask_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+ u32 er;
+
+ spin_lock_irqsave(&uic->lock, flags);
+ er = mfdcr(uic->dcrbase + UIC_ER);
+ er |= 1 << (31 - src);
+ mtdcr(uic->dcrbase + UIC_ER, er);
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_mask_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+ u32 er;
+
+ spin_lock_irqsave(&uic->lock, flags);
+ er = mfdcr(uic->dcrbase + UIC_ER);
+ er &= ~(1 << (31 - src));
+ mtdcr(uic->dcrbase + UIC_ER, er);
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static void uic_ack_irq(unsigned int virq)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&uic->lock, flags);
+ mtdcr(uic->dcrbase + UIC_SR, 1 << (31-src));
+ spin_unlock_irqrestore(&uic->lock, flags);
+}
+
+static int uic_set_irq_type(unsigned int virq, unsigned int flow_type)
+{
+ struct uic *uic = get_irq_chip_data(virq);
+ unsigned int src = uic_irq_to_hw(virq);
+ struct irq_desc *desc = get_irq_desc(virq);
+ unsigned long flags;
+ int trigger, polarity;
+ u32 tr, pr, mask;
+
+ switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_NONE:
+ uic_mask_irq(virq);
+ return 0;
+
+ case IRQ_TYPE_EDGE_RISING:
+ trigger = 1; polarity = 1;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ trigger = 1; polarity = 0;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
+ trigger = 0; polarity = 1;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ trigger = 0; polarity = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ mask = ~(1 << (31 - src));
+
+ spin_lock_irqsave(&uic->lock, flags);
+ tr = mfdcr(uic->dcrbase + UIC_TR);
+ pr = mfdcr(uic->dcrbase + UIC_PR);
+ tr = (tr & mask) | (trigger << (31-src));
+ pr = (pr & mask) | (polarity << (31-src));
+
+ mtdcr(uic->dcrbase + UIC_PR, pr);
+ mtdcr(uic->dcrbase + UIC_TR, tr);
+
+ desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
+ desc->status |= flow_type & IRQ_TYPE_SENSE_MASK;
+ if (trigger)
+ desc->status |= IRQ_LEVEL;
+
+ spin_unlock_irqrestore(&uic->lock, flags);
+
+ return 0;
+}
+
+static struct irq_chip uic_irq_chip = {
+ .typename = " UIC ",
+ .unmask = uic_unmask_irq,
+ .mask = uic_mask_irq,
+/* .mask_ack = uic_mask_irq_and_ack, */
+ .ack = uic_ack_irq,
+ .set_type = uic_set_irq_type,
+};
+
+static int uic_host_match(struct irq_host *h, struct device_node *node)
+{
+ struct uic *uic = h->host_data;
+ return uic->of_node == node;
+}
+
+static int uic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct uic *uic = h->host_data;
+
+ set_irq_chip_data(virq, uic);
+ /* Despite the name, handle_level_irq() works for both level
+ * and edge irqs on UIC. FIXME: check this is correct */
+ set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq);
+
+ /* Set default irq type */
+ set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int uic_host_xlate(struct irq_host *h, struct device_node *ct,
+ u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+
+{
+ /* UIC intspecs must have 2 cells */
+ BUG_ON(intsize != 2);
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1];
+ return 0;
+}
+
+static struct irq_host_ops uic_host_ops = {
+ .match = uic_host_match,
+ .map = uic_host_map,
+ .xlate = uic_host_xlate,
+};
+
+irqreturn_t uic_cascade(int virq, void *data)
+{
+ struct uic *uic = data;
+ u32 msr;
+ int src;
+ int subvirq;
+
+ msr = mfdcr(uic->dcrbase + UIC_MSR);
+ src = 32 - ffs(msr);
+
+ subvirq = irq_linear_revmap(uic->irqhost, src);
+ generic_handle_irq(subvirq);
+
+ return IRQ_HANDLED;
+}
+
+static struct uic * __init uic_init_one(struct device_node *node)
+{
+ struct uic *uic;
+ const u32 *indexp, *dcrreg;
+ int len;
+
+ BUG_ON(! of_device_is_compatible(node, "ibm,uic"));
+
+ uic = alloc_bootmem(sizeof(*uic));
+ if (! uic)
+ return NULL; /* FIXME: panic? */
+
+ memset(uic, 0, sizeof(*uic));
+ spin_lock_init(&uic->lock);
+ uic->of_node = of_node_get(node);
+ indexp = of_get_property(node, "cell-index", &len);
+ if (!indexp || (len != sizeof(u32))) {
+ printk(KERN_ERR "uic: Device node %s has missing or invalid "
+ "cell-index property\n", node->full_name);
+ return NULL;
+ }
+ uic->index = *indexp;
+
+ dcrreg = of_get_property(node, "dcr-reg", &len);
+ if (!dcrreg || (len != 2*sizeof(u32))) {
+ printk(KERN_ERR "uic: Device node %s has missing or invalid "
+ "dcr-reg property\n", node->full_name);
+ return NULL;
+ }
+ uic->dcrbase = *dcrreg;
+
+ uic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, NR_UIC_INTS,
+ &uic_host_ops, -1);
+ if (! uic->irqhost) {
+ of_node_put(node);
+ return NULL; /* FIXME: panic? */
+ }
+
+ uic->irqhost->host_data = uic;
+
+ /* Start with all interrupts disabled, level and non-critical */
+ mtdcr(uic->dcrbase + UIC_ER, 0);
+ mtdcr(uic->dcrbase + UIC_CR, 0);
+ mtdcr(uic->dcrbase + UIC_TR, 0);
+ /* Clear any pending interrupts, in case the firmware left some */
+ mtdcr(uic->dcrbase + UIC_SR, 0xffffffff);
+
+ printk ("UIC%d (%d IRQ sources) at DCR 0x%x\n", uic->index,
+ NR_UIC_INTS, uic->dcrbase);
+
+ return uic;
+}
+
+void __init uic_init_tree(void)
+{
+ struct device_node *np;
+ struct uic *uic;
+ const u32 *interrupts;
+
+ /* First locate and initialize the top-level UIC */
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+ while (np) {
+ interrupts = of_get_property(np, "interrupts", NULL);
+ if (! interrupts)
+ break;
+
+ np = of_find_compatible_node(np, NULL, "ibm,uic");
+ }
+
+ BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the
+ * top-level interrupt controller */
+ primary_uic = uic_init_one(np);
+ if (! primary_uic)
+ panic("Unable to initialize primary UIC %s\n", np->full_name);
+
+ irq_set_default_host(primary_uic->irqhost);
+ of_node_put(np);
+
+ /* The scan again for cascaded UICs */
+ np = of_find_compatible_node(NULL, NULL, "ibm,uic");
+ while (np) {
+ interrupts = of_get_property(np, "interrupts", NULL);
+ if (interrupts) {
+ /* Secondary UIC */
+ int cascade_virq;
+ int ret;
+
+ uic = uic_init_one(np);
+ if (! uic)
+ panic("Unable to initialize a secondary UIC %s\n",
+ np->full_name);
+
+ cascade_virq = irq_of_parse_and_map(np, 0);
+
+ uic->cascade.handler = uic_cascade;
+ uic->cascade.name = "UIC cascade";
+ uic->cascade.dev_id = uic;
+
+ ret = setup_irq(cascade_virq, &uic->cascade);
+ if (ret)
+ printk(KERN_ERR "Failed to setup_irq(%d) for "
+ "UIC%d cascade\n", cascade_virq,
+ uic->index);
+
+ /* FIXME: setup critical cascade?? */
+ }
+
+ np = of_find_compatible_node(np, NULL, "ibm,uic");
+ }
+}
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int uic_get_irq(void)
+{
+ u32 msr;
+ int src;
+
+ BUG_ON(! primary_uic);
+
+ msr = mfdcr(primary_uic->dcrbase + UIC_MSR);
+ src = 32 - ffs(msr);
+
+ return irq_linear_revmap(primary_uic->irqhost, src);
+}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index bf299b66f3f..28fdf4f50c2 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -330,18 +330,17 @@ static void release_output_lock(void)
static int xmon_core(struct pt_regs *regs, int fromipi)
{
int cmd = 0;
- unsigned long msr;
struct bpt *bp;
long recurse_jmp[JMP_BUF_LEN];
unsigned long offset;
+ unsigned long flags;
#ifdef CONFIG_SMP
int cpu;
int secondary;
unsigned long timeout;
#endif
- msr = mfmsr();
- mtmsr(msr & ~MSR_EE); /* disable interrupts */
+ local_irq_save(flags);
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
@@ -516,7 +515,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
insert_cpu_bpts();
- mtmsr(msr); /* restore interrupt enable */
+ local_irq_restore(flags);
return cmd != 'X' && cmd != EOF;
}
@@ -1218,7 +1217,6 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp,
{
unsigned long size, offset;
const char *name;
- char *modname;
*startp = *endp = 0;
if (pc == 0)
@@ -1226,7 +1224,7 @@ static void get_function_bounds(unsigned long pc, unsigned long *startp,
if (setjmp(bus_error_jmp) == 0) {
catch_memory_errors = 1;
sync();
- name = kallsyms_lookup(pc, &size, &offset, &modname, tmpstr);
+ name = kallsyms_lookup(pc, &size, &offset, NULL, tmpstr);
if (name != NULL) {
*startp = pc - offset;
*endp = pc - offset + size;
@@ -1360,8 +1358,12 @@ static void print_bug_trap(struct pt_regs *regs)
if (is_warning_bug(bug))
return;
+#ifdef CONFIG_DEBUG_BUGVERBOSE
printf("kernel BUG at %s:%u!\n",
bug->file, bug->line);
+#else
+ printf("kernel BUG at %p!\n", (void *)bug->bug_addr);
+#endif
}
void excprint(struct pt_regs *fp)
diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
index 48ce84f5be9..4c0a7d732f6 100644
--- a/arch/ppc/8260_io/enet.c
+++ b/arch/ppc/8260_io/enet.c
@@ -32,7 +32,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index 9db825fe37f..cab395da25d 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -29,7 +29,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/arch/ppc/8xx_io/Kconfig b/arch/ppc/8xx_io/Kconfig
index 57dacf97853..c623e44f01a 100644
--- a/arch/ppc/8xx_io/Kconfig
+++ b/arch/ppc/8xx_io/Kconfig
@@ -74,10 +74,6 @@ config ENET_BIG_BUFFERS
Allocate large buffers for MPC8xx Ethernet. Increases throughput
and decreases the likelihood of dropped packets, but costs memory.
-config HTDMSOUND
- bool "Embedded Planet HIOX Audio"
- depends on SOUND=y
-
# This doesn't really belong here, but it is convenient to ask
# 8xx specific questions.
comment "Generic MPC8xx Options"
diff --git a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile
index d8760181fe9..1051a06df7e 100644
--- a/arch/ppc/8xx_io/Makefile
+++ b/arch/ppc/8xx_io/Makefile
@@ -7,4 +7,3 @@ obj-y := commproc.o
obj-$(CONFIG_FEC_ENET) += fec.o
obj-$(CONFIG_SCC_ENET) += enet.o
obj-$(CONFIG_UCODE_PATCH) += micropatch.o
-obj-$(CONFIG_HTDMSOUND) += cs4218_tdm.o
diff --git a/arch/ppc/8xx_io/cs4218.h b/arch/ppc/8xx_io/cs4218.h
deleted file mode 100644
index e5f943045af..00000000000
--- a/arch/ppc/8xx_io/cs4218.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef _cs4218_h_
-/*
- * Hacked version of linux/drivers/sound/dmasound/dmasound.h
- *
- *
- * Minor numbers for the sound driver.
- *
- * Unfortunately Creative called the codec chip of SB as a DSP. For this
- * reason the /dev/dsp is reserved for digitized audio use. There is a
- * device for true DSP processors but it will be called something else.
- * In v3.0 it's /dev/sndproc but this could be a temporary solution.
- */
-#define _cs4218_h_
-
-#include <linux/types.h>
-
-#define SND_NDEVS 256 /* Number of supported devices */
-#define SND_DEV_CTL 0 /* Control port /dev/mixer */
-#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM
- synthesizer and MIDI output) */
-#define SND_DEV_MIDIN 2 /* Raw midi access */
-#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */
-#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */
-#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */
-#define SND_DEV_STATUS 6 /* /dev/sndstat */
-/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
-#define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */
-#define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */
-#define SND_DEV_PSS SND_DEV_SNDPROC
-
-/* switch on various prinks */
-#define DEBUG_DMASOUND 1
-
-#define MAX_AUDIO_DEV 5
-#define MAX_MIXER_DEV 4
-#define MAX_SYNTH_DEV 3
-#define MAX_MIDI_DEV 6
-#define MAX_TIMER_DEV 3
-
-#define MAX_CATCH_RADIUS 10
-
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-
-static inline int ioctl_return(int *addr, int value)
-{
- return value < 0 ? value : put_user(value, addr);
-}
-
-#define HAS_RECORD
-
- /*
- * Initialization
- */
-
-/* description of the set-up applies to either hard or soft settings */
-
-typedef struct {
- int format; /* AFMT_* */
- int stereo; /* 0 = mono, 1 = stereo */
- int size; /* 8/16 bit*/
- int speed; /* speed */
-} SETTINGS;
-
- /*
- * Machine definitions
- */
-
-typedef struct {
- const char *name;
- const char *name2;
- void (*open)(void);
- void (*release)(void);
- void *(*dma_alloc)(unsigned int, gfp_t);
- void (*dma_free)(void *, unsigned int);
- int (*irqinit)(void);
-#ifdef MODULE
- void (*irqcleanup)(void);
-#endif
- void (*init)(void);
- void (*silence)(void);
- int (*setFormat)(int);
- int (*setVolume)(int);
- int (*setBass)(int);
- int (*setTreble)(int);
- int (*setGain)(int);
- void (*play)(void);
- void (*record)(void); /* optional */
- void (*mixer_init)(void); /* optional */
- int (*mixer_ioctl)(u_int, u_long); /* optional */
- int (*write_sq_setup)(void); /* optional */
- int (*read_sq_setup)(void); /* optional */
- int (*sq_open)(mode_t); /* optional */
- int (*state_info)(char *, size_t); /* optional */
- void (*abort_read)(void); /* optional */
- int min_dsp_speed;
- int max_dsp_speed;
- int version ;
- int hardware_afmts ; /* OSS says we only return h'ware info */
- /* when queried via SNDCTL_DSP_GETFMTS */
- int capabilities ; /* low-level reply to SNDCTL_DSP_GETCAPS */
- SETTINGS default_hard ; /* open() or init() should set something valid */
- SETTINGS default_soft ; /* you can make it look like old OSS, if you want to */
-} MACHINE;
-
- /*
- * Low level stuff
- */
-
-typedef struct {
- ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
- ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
-} TRANS;
-
-
- /*
- * Sound queue stuff, the heart of the driver
- */
-
-struct sound_queue {
- /* buffers allocated for this queue */
- int numBufs; /* real limits on what the user can have */
- int bufSize; /* in bytes */
- char **buffers;
-
- /* current parameters */
- int locked ; /* params cannot be modified when != 0 */
- int user_frags ; /* user requests this many */
- int user_frag_size ; /* of this size */
- int max_count; /* actual # fragments <= numBufs */
- int block_size; /* internal block size in bytes */
- int max_active; /* in-use fragments <= max_count */
-
- /* it shouldn't be necessary to declare any of these volatile */
- int front, rear, count;
- int rear_size;
- /*
- * The use of the playing field depends on the hardware
- *
- * Atari, PMac: The number of frames that are loaded/playing
- *
- * Amiga: Bit 0 is set: a frame is loaded
- * Bit 1 is set: a frame is playing
- */
- int active;
- wait_queue_head_t action_queue, open_queue, sync_queue;
- int open_mode;
- int busy, syncing, xruns, died;
-};
-
-#define SLEEP(queue) interruptible_sleep_on_timeout(&queue, HZ)
-#define WAKE_UP(queue) (wake_up_interruptible(&queue))
-
-#endif /* _cs4218_h_ */
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
deleted file mode 100644
index a956f28ab16..00000000000
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ /dev/null
@@ -1,2833 +0,0 @@
-
-/* This is a modified version of linux/drivers/sound/dmasound.c to
- * support the CS4218 codec on the 8xx TDM port. Thanks to everyone
- * that contributed to the dmasound software (which includes me :-).
- *
- * The CS4218 is configured in Mode 4, sub-mode 0. This provides
- * left/right data only on the TDM port, as a 32-bit word, per frame
- * pulse. The control of the CS4218 is provided by some other means,
- * like the SPI port.
- * Dan Malek (dmalek@jlc.net)
- */
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/major.h>
-#include <linux/fcntl.h>
-#include <linux/errno.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/sound.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-/* Should probably do something different with this path name.....
- * Actually, I should just stop using it...
- */
-#include "cs4218.h"
-#include <linux/soundcard.h>
-
-#include <asm/mpc8xx.h>
-#include <asm/8xx_immap.h>
-#include <asm/commproc.h>
-
-#define DMASND_CS4218 5
-
-#define MAX_CATCH_RADIUS 10
-#define MIN_BUFFERS 4
-#define MIN_BUFSIZE 4
-#define MAX_BUFSIZE 128
-
-#define HAS_8BIT_TABLES
-
-static int sq_unit = -1;
-static int mixer_unit = -1;
-static int state_unit = -1;
-static int irq_installed = 0;
-static char **sound_buffers = NULL;
-static char **sound_read_buffers = NULL;
-
-static DEFINE_SPINLOCK(cs4218_lock);
-
-/* Local copies of things we put in the control register. Output
- * volume, like most codecs is really attenuation.
- */
-static int cs4218_rate_index;
-
-/*
- * Stuff for outputting a beep. The values range from -327 to +327
- * so we can multiply by an amplitude in the range 0..100 to get a
- * signed short value to put in the output buffer.
- */
-static short beep_wform[256] = {
- 0, 40, 79, 117, 153, 187, 218, 245,
- 269, 288, 304, 316, 323, 327, 327, 324,
- 318, 310, 299, 288, 275, 262, 249, 236,
- 224, 213, 204, 196, 190, 186, 183, 182,
- 182, 183, 186, 189, 192, 196, 200, 203,
- 206, 208, 209, 209, 209, 207, 204, 201,
- 197, 193, 188, 183, 179, 174, 170, 166,
- 163, 161, 160, 159, 159, 160, 161, 162,
- 164, 166, 168, 169, 171, 171, 171, 170,
- 169, 167, 163, 159, 155, 150, 144, 139,
- 133, 128, 122, 117, 113, 110, 107, 105,
- 103, 103, 103, 103, 104, 104, 105, 105,
- 105, 103, 101, 97, 92, 86, 78, 68,
- 58, 45, 32, 18, 3, -11, -26, -41,
- -55, -68, -79, -88, -95, -100, -102, -102,
- -99, -93, -85, -75, -62, -48, -33, -16,
- 0, 16, 33, 48, 62, 75, 85, 93,
- 99, 102, 102, 100, 95, 88, 79, 68,
- 55, 41, 26, 11, -3, -18, -32, -45,
- -58, -68, -78, -86, -92, -97, -101, -103,
- -105, -105, -105, -104, -104, -103, -103, -103,
- -103, -105, -107, -110, -113, -117, -122, -128,
- -133, -139, -144, -150, -155, -159, -163, -167,
- -169, -170, -171, -171, -171, -169, -168, -166,
- -164, -162, -161, -160, -159, -159, -160, -161,
- -163, -166, -170, -174, -179, -183, -188, -193,
- -197, -201, -204, -207, -209, -209, -209, -208,
- -206, -203, -200, -196, -192, -189, -186, -183,
- -182, -182, -183, -186, -190, -196, -204, -213,
- -224, -236, -249, -262, -275, -288, -299, -310,
- -318, -324, -327, -327, -323, -316, -304, -288,
- -269, -245, -218, -187, -153, -117, -79, -40,
-};
-
-#define BEEP_SPEED 5 /* 22050 Hz sample rate */
-#define BEEP_BUFLEN 512
-#define BEEP_VOLUME 15 /* 0 - 100 */
-
-static int beep_volume = BEEP_VOLUME;
-static int beep_playing = 0;
-static int beep_state = 0;
-static short *beep_buf;
-static void (*orig_mksound)(unsigned int, unsigned int);
-
-/* This is found someplace else......I guess in the keyboard driver
- * we don't include.
- */
-static void (*kd_mksound)(unsigned int, unsigned int);
-
-static int catchRadius = 0;
-static int numBufs = 4, bufSize = 32;
-static int numReadBufs = 4, readbufSize = 32;
-
-
-/* TDM/Serial transmit and receive buffer descriptors.
-*/
-static volatile cbd_t *rx_base, *rx_cur, *tx_base, *tx_cur;
-
-module_param(catchRadius, int, 0);
-module_param(numBufs, int, 0);
-module_param(bufSize, int, 0);
-module_param(numreadBufs, int, 0);
-module_param(readbufSize, int, 0);
-
-#define arraysize(x) (sizeof(x)/sizeof(*(x)))
-#define le2be16(x) (((x)<<8 & 0xff00) | ((x)>>8 & 0x00ff))
-#define le2be16dbl(x) (((x)<<8 & 0xff00ff00) | ((x)>>8 & 0x00ff00ff))
-
-#define IOCTL_IN(arg, ret) \
- do { int error = get_user(ret, (int *)(arg)); \
- if (error) return error; \
- } while (0)
-#define IOCTL_OUT(arg, ret) ioctl_return((int *)(arg), ret)
-
-/* CS4218 serial port control in mode 4.
-*/
-#define CS_INTMASK ((uint)0x40000000)
-#define CS_DO1 ((uint)0x20000000)
-#define CS_LATTEN ((uint)0x1f000000)
-#define CS_RATTEN ((uint)0x00f80000)
-#define CS_MUTE ((uint)0x00040000)
-#define CS_ISL ((uint)0x00020000)
-#define CS_ISR ((uint)0x00010000)
-#define CS_LGAIN ((uint)0x0000f000)
-#define CS_RGAIN ((uint)0x00000f00)
-
-#define CS_LATTEN_SET(X) (((X) & 0x1f) << 24)
-#define CS_RATTEN_SET(X) (((X) & 0x1f) << 19)
-#define CS_LGAIN_SET(X) (((X) & 0x0f) << 12)
-#define CS_RGAIN_SET(X) (((X) & 0x0f) << 8)
-
-#define CS_LATTEN_GET(X) (((X) >> 24) & 0x1f)
-#define CS_RATTEN_GET(X) (((X) >> 19) & 0x1f)
-#define CS_LGAIN_GET(X) (((X) >> 12) & 0x0f)
-#define CS_RGAIN_GET(X) (((X) >> 8) & 0x0f)
-
-/* The control register is effectively write only. We have to keep a copy
- * of what we write.
- */
-static uint cs4218_control;
-
-/* A place to store expanding information.
-*/
-static int expand_bal;
-static int expand_data;
-
-/* Since I can't make the microcode patch work for the SPI, I just
- * clock the bits using software.
- */
-static void sw_spi_init(void);
-static void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt);
-static uint cs4218_ctl_write(uint ctlreg);
-
-/*** Some low level helpers **************************************************/
-
-/* 16 bit mu-law */
-
-static short ulaw2dma16[] = {
- -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
- -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
- -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
- -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316,
- -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
- -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
- -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
- -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
- -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
- -1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
- -876, -844, -812, -780, -748, -716, -684, -652,
- -620, -588, -556, -524, -492, -460, -428, -396,
- -372, -356, -340, -324, -308, -292, -276, -260,
- -244, -228, -212, -196, -180, -164, -148, -132,
- -120, -112, -104, -96, -88, -80, -72, -64,
- -56, -48, -40, -32, -24, -16, -8, 0,
- 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
- 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
- 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
- 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
- 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
- 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
- 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
- 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
- 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
- 1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
- 876, 844, 812, 780, 748, 716, 684, 652,
- 620, 588, 556, 524, 492, 460, 428, 396,
- 372, 356, 340, 324, 308, 292, 276, 260,
- 244, 228, 212, 196, 180, 164, 148, 132,
- 120, 112, 104, 96, 88, 80, 72, 64,
- 56, 48, 40, 32, 24, 16, 8, 0,
-};
-
-/* 16 bit A-law */
-
-static short alaw2dma16[] = {
- -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736,
- -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784,
- -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368,
- -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392,
- -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
- -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
- -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472,
- -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
- -344, -328, -376, -360, -280, -264, -312, -296,
- -472, -456, -504, -488, -408, -392, -440, -424,
- -88, -72, -120, -104, -24, -8, -56, -40,
- -216, -200, -248, -232, -152, -136, -184, -168,
- -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184,
- -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696,
- -688, -656, -752, -720, -560, -528, -624, -592,
- -944, -912, -1008, -976, -816, -784, -880, -848,
- 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736,
- 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784,
- 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368,
- 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392,
- 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
- 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
- 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472,
- 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
- 344, 328, 376, 360, 280, 264, 312, 296,
- 472, 456, 504, 488, 408, 392, 440, 424,
- 88, 72, 120, 104, 24, 8, 56, 40,
- 216, 200, 248, 232, 152, 136, 184, 168,
- 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184,
- 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696,
- 688, 656, 752, 720, 560, 528, 624, 592,
- 944, 912, 1008, 976, 816, 784, 880, 848,
-};
-
-
-/*** Translations ************************************************************/
-
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-
-/*** Low level stuff *********************************************************/
-
-struct cs_sound_settings {
- MACHINE mach; /* machine dependent things */
- SETTINGS hard; /* hardware settings */
- SETTINGS soft; /* software settings */
- SETTINGS dsp; /* /dev/dsp default settings */
- TRANS *trans_write; /* supported translations for playback */
- TRANS *trans_read; /* supported translations for record */
- int volume_left; /* volume (range is machine dependent) */
- int volume_right;
- int bass; /* tone (range is machine dependent) */
- int treble;
- int gain;
- int minDev; /* minor device number currently open */
-};
-
-static struct cs_sound_settings sound;
-
-static void *CS_Alloc(unsigned int size, gfp_t flags);
-static void CS_Free(void *ptr, unsigned int size);
-static int CS_IrqInit(void);
-#ifdef MODULE
-static void CS_IrqCleanup(void);
-#endif /* MODULE */
-static void CS_Silence(void);
-static void CS_Init(void);
-static void CS_Play(void);
-static void CS_Record(void);
-static int CS_SetFormat(int format);
-static int CS_SetVolume(int volume);
-static void cs4218_tdm_tx_intr(void *devid);
-static void cs4218_tdm_rx_intr(void *devid);
-static void cs4218_intr(void *devid);
-static int cs_get_volume(uint reg);
-static int cs_volume_setter(int volume, int mute);
-static int cs_get_gain(uint reg);
-static int cs_set_gain(int gain);
-static void cs_mksound(unsigned int hz, unsigned int ticks);
-static void cs_nosound(unsigned long xx);
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void);
-static void sound_init(void);
-static int sound_set_format(int format);
-static int sound_set_speed(int speed);
-static int sound_set_stereo(int stereo);
-static int sound_set_volume(int volume);
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft);
-
-
-/*
- * /dev/mixer abstraction
- */
-
-struct sound_mixer {
- int busy;
- int modify_counter;
-};
-
-static struct sound_mixer mixer;
-
-static struct sound_queue sq;
-static struct sound_queue read_sq;
-
-#define sq_block_address(i) (sq.buffers[i])
-#define SIGNAL_RECEIVED (signal_pending(current))
-#define NON_BLOCKING(open_mode) (open_mode & O_NONBLOCK)
-#define ONE_SECOND HZ /* in jiffies (100ths of a second) */
-#define NO_TIME_LIMIT 0xffffffff
-
-/*
- * /dev/sndstat
- */
-
-struct sound_state {
- int busy;
- char buf[512];
- int len, ptr;
-};
-
-static struct sound_state state;
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig);
-
-/*** Config & Setup **********************************************************/
-
-void dmasound_setup(char *str, int *ints);
-
-/*** Translations ************************************************************/
-
-
-/* ++TeSche: radically changed for new expanding purposes...
- *
- * These two routines now deal with copying/expanding/translating the samples
- * from user space into our buffer at the right frequency. They take care about
- * how much data there's actually to read, how much buffer space there is and
- * to convert samples into the right frequency/encoding. They will only work on
- * complete samples so it may happen they leave some bytes in the input stream
- * if the user didn't write a multiple of the current sample size. They both
- * return the number of bytes they've used from both streams so you may detect
- * such a situation. Luckily all programs should be able to cope with that.
- *
- * I think I've optimized anything as far as one can do in plain C, all
- * variables should fit in registers and the loops are really short. There's
- * one loop for every possible situation. Writing a more generalized and thus
- * parameterized loop would only produce slower code. Feel free to optimize
- * this in assembler if you like. :)
- *
- * I think these routines belong here because they're not yet really hardware
- * independent, especially the fact that the Falcon can play 16bit samples
- * only in stereo is hardcoded in both of them!
- *
- * ++geert: split in even more functions (one per format)
- */
-
-static ssize_t cs4218_ct_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = table[data];
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = data << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- *p++ = val;
- if (stereo) {
- if (get_user(data, userPtr++))
- return -EFAULT;
- val = (data ^ 0x80) << 8;
- }
- *p++ = val;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-/* This is the default format of the codec. Signed, 16-bit stereo
- * generated by an application shouldn't have to be copied at all.
- * We should just get the phsical address of the buffers and update
- * the TDM BDs directly.
- */
-static ssize_t cs4218_ct_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- if (get_user(data, up++))
- return -EFAULT;
- *fp++ = data;
- *fp++ = data;
- count--;
- }
- } else {
- if (copy_from_user(fp, userPtr, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- *fp++ = data;
- if (stereo) {
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- }
- *fp++ = data;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-
-static ssize_t cs4218_ctx_law(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned short *table = (unsigned short *)
- (sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16);
- unsigned int data = expand_data;
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int utotal, ftotal;
- int stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = table[c];
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + table[c];
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = c << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + (c << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_u8(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- u_char c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (c ^ 0x80) << 8;
- if (stereo) {
- if (get_user(c, userPtr++))
- return -EFAULT;
- data = (data << 16) + ((c ^ 0x80) << 8);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 2: utotal;
-}
-
-
-static ssize_t cs4218_ctx_s16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + c;
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-
-static ssize_t cs4218_ctx_u16(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- unsigned int *p = (unsigned int *) &frame[*frameUsed];
- unsigned int data = expand_data;
- unsigned short *up = (unsigned short *) userPtr;
- int bal = expand_bal;
- int hSpeed = sound.hard.speed, sSpeed = sound.soft.speed;
- int stereo = sound.soft.stereo;
- int utotal, ftotal;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- ftotal = frameLeft;
- utotal = userCount;
- while (frameLeft) {
- unsigned short c;
- if (bal < 0) {
- if (userCount == 0)
- break;
- if (get_user(data, up++))
- return -EFAULT;
- data ^= mask;
- if (stereo) {
- if (get_user(c, up++))
- return -EFAULT;
- data = (data << 16) + (c ^ mask);
- } else
- data = (data << 16) + data;
- userCount--;
- bal += hSpeed;
- }
- *p++ = data;
- frameLeft--;
- bal -= sSpeed;
- }
- expand_bal = bal;
- expand_data = data;
- *frameUsed += (ftotal - frameLeft) * 4;
- utotal -= userCount;
- return stereo? utotal * 4: utotal * 2;
-}
-
-static ssize_t cs4218_ct_s8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = val >> 8;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_u8_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- short *p = (short *) &frame[*frameUsed];
- int val, stereo = sound.soft.stereo;
-
- frameLeft >>= 2;
- if (stereo)
- userCount >>= 1;
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- u_char data;
-
- val = *p++;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- if (stereo) {
- val = *p;
- data = (val >> 8) ^ 0x80;
- if (put_user(data, (u_char *)userPtr++))
- return -EFAULT;
- }
- p++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 2: used;
-}
-
-
-static ssize_t cs4218_ct_s16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- if (!stereo) {
- short *up = (short *) userPtr;
- while (count > 0) {
- short data;
- data = *fp;
- if (put_user(data, up++))
- return -EFAULT;
- fp+=2;
- count--;
- }
- } else {
- if (copy_to_user((u_char *)userPtr, fp, count * 4))
- return -EFAULT;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static ssize_t cs4218_ct_u16_read(const u_char *userPtr, size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t count, used;
- int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
- int stereo = sound.soft.stereo;
- short *fp = (short *) &frame[*frameUsed];
- short *up = (short *) userPtr;
-
- frameLeft >>= 2;
- userCount >>= (stereo? 2: 1);
- used = count = min(userCount, frameLeft);
- while (count > 0) {
- int data;
-
- data = *fp++;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- if (stereo) {
- data = *fp;
- data ^= mask;
- if (put_user(data, up++))
- return -EFAULT;
- }
- fp++;
- count--;
- }
- *frameUsed += used * 4;
- return stereo? used * 4: used * 2;
-}
-
-static TRANS transCSNormal = {
- cs4218_ct_law, cs4218_ct_law, cs4218_ct_s8, cs4218_ct_u8,
- cs4218_ct_s16, cs4218_ct_u16, cs4218_ct_s16, cs4218_ct_u16
-};
-
-static TRANS transCSExpand = {
- cs4218_ctx_law, cs4218_ctx_law, cs4218_ctx_s8, cs4218_ctx_u8,
- cs4218_ctx_s16, cs4218_ctx_u16, cs4218_ctx_s16, cs4218_ctx_u16
-};
-
-static TRANS transCSNormalRead = {
- NULL, NULL, cs4218_ct_s8_read, cs4218_ct_u8_read,
- cs4218_ct_s16_read, cs4218_ct_u16_read,
- cs4218_ct_s16_read, cs4218_ct_u16_read
-};
-
-/*** Low level stuff *********************************************************/
-
-static void *CS_Alloc(unsigned int size, gfp_t flags)
-{
- int order;
-
- size >>= 13;
- for (order=0; order < 5; order++) {
- if (size == 0)
- break;
- size >>= 1;
- }
- return (void *)__get_free_pages(flags, order);
-}
-
-static void CS_Free(void *ptr, unsigned int size)
-{
- int order;
-
- size >>= 13;
- for (order=0; order < 5; order++) {
- if (size == 0)
- break;
- size >>= 1;
- }
- free_pages((ulong)ptr, order);
-}
-
-static int __init CS_IrqInit(void)
-{
- cpm_install_handler(CPMVEC_SMC2, cs4218_intr, NULL);
- return 1;
-}
-
-#ifdef MODULE
-static void CS_IrqCleanup(void)
-{
- volatile smc_t *sp;
- volatile cpm8xx_t *cp;
-
- /* First disable transmitter and receiver.
- */
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-
- /* And now shut down the SMC.
- */
- cp = cpmp; /* Get pointer to Communication Processor */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_STOP_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-
- /* Release the interrupt handler.
- */
- cpm_free_handler(CPMVEC_SMC2);
-
- kfree(beep_buf);
- kd_mksound = orig_mksound;
-}
-#endif /* MODULE */
-
-static void CS_Silence(void)
-{
- volatile smc_t *sp;
-
- /* Disable transmitter.
- */
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~SMCMR_TEN;
-}
-
-/* Frequencies depend upon external oscillator. There are two
- * choices, 12.288 and 11.2896 MHz. The RPCG audio supports both through
- * and external control register selection bit.
- */
-static int cs4218_freqs[] = {
- /* 12.288 11.2896 */
- 48000, 44100,
- 32000, 29400,
- 24000, 22050,
- 19200, 17640,
- 16000, 14700,
- 12000, 11025,
- 9600, 8820,
- 8000, 7350
-};
-
-static void CS_Init(void)
-{
- int i, tolerance;
-
- switch (sound.soft.format) {
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- sound.hard.format = AFMT_S16_LE;
- break;
- default:
- sound.hard.format = AFMT_S16_BE;
- break;
- }
- sound.hard.stereo = 1;
- sound.hard.size = 16;
-
- /*
- * If we have a sample rate which is within catchRadius percent
- * of the requested value, we don't have to expand the samples.
- * Otherwise choose the next higher rate.
- */
- i = (sizeof(cs4218_freqs) / sizeof(int));
- do {
- tolerance = catchRadius * cs4218_freqs[--i] / 100;
- } while (sound.soft.speed > cs4218_freqs[i] + tolerance && i > 0);
- if (sound.soft.speed >= cs4218_freqs[i] - tolerance)
- sound.trans_write = &transCSNormal;
- else
- sound.trans_write = &transCSExpand;
- sound.trans_read = &transCSNormalRead;
- sound.hard.speed = cs4218_freqs[i];
- cs4218_rate_index = i;
-
- /* The CS4218 has seven selectable clock dividers for the sample
- * clock. The HIOX then provides one of two external rates.
- * An even numbered frequency table index uses the high external
- * clock rate.
- */
- *(uint *)HIOX_CSR4_ADDR &= ~(HIOX_CSR4_AUDCLKHI | HIOX_CSR4_AUDCLKSEL);
- if ((i & 1) == 0)
- *(uint *)HIOX_CSR4_ADDR |= HIOX_CSR4_AUDCLKHI;
- i >>= 1;
- *(uint *)HIOX_CSR4_ADDR |= (i & HIOX_CSR4_AUDCLKSEL);
-
- expand_bal = -sound.soft.speed;
-}
-
-static int CS_SetFormat(int format)
-{
- int size;
-
- switch (format) {
- case AFMT_QUERY:
- return sound.soft.format;
- case AFMT_MU_LAW:
- case AFMT_A_LAW:
- case AFMT_U8:
- case AFMT_S8:
- size = 8;
- break;
- case AFMT_S16_BE:
- case AFMT_U16_BE:
- case AFMT_S16_LE:
- case AFMT_U16_LE:
- size = 16;
- break;
- default: /* :-) */
- printk(KERN_ERR "dmasound: unknown format 0x%x, using AFMT_U8\n",
- format);
- size = 8;
- format = AFMT_U8;
- }
-
- sound.soft.format = format;
- sound.soft.size = size;
- if (sound.minDev == SND_DEV_DSP) {
- sound.dsp.format = format;
- sound.dsp.size = size;
- }
-
- CS_Init();
-
- return format;
-}
-
-/* Volume is the amount of attenuation we tell the codec to impose
- * on the outputs. There are 32 levels, with 0 the "loudest".
- */
-#define CS_VOLUME_TO_MASK(x) (31 - ((((x) - 1) * 31) / 99))
-#define CS_MASK_TO_VOLUME(y) (100 - ((y) * 99 / 31))
-
-static int cs_get_volume(uint reg)
-{
- int volume;
-
- volume = CS_MASK_TO_VOLUME(CS_LATTEN_GET(reg));
- volume |= CS_MASK_TO_VOLUME(CS_RATTEN_GET(reg)) << 8;
- return volume;
-}
-
-static int cs_volume_setter(int volume, int mute)
-{
- uint tempctl;
-
- if (mute && volume == 0) {
- tempctl = cs4218_control | CS_MUTE;
- } else {
- tempctl = cs4218_control & ~CS_MUTE;
- tempctl = tempctl & ~(CS_LATTEN | CS_RATTEN);
- tempctl |= CS_LATTEN_SET(CS_VOLUME_TO_MASK(volume & 0xff));
- tempctl |= CS_RATTEN_SET(CS_VOLUME_TO_MASK((volume >> 8) & 0xff));
- volume = cs_get_volume(tempctl);
- }
- if (tempctl != cs4218_control) {
- cs4218_ctl_write(tempctl);
- }
- return volume;
-}
-
-
-/* Gain has 16 steps from 0 to 15. These are in 1.5dB increments from
- * 0 (no gain) to 22.5 dB.
- */
-#define CS_RECLEVEL_TO_GAIN(v) \
- ((v) < 0 ? 0 : (v) > 100 ? 15 : (v) * 3 / 20)
-#define CS_GAIN_TO_RECLEVEL(v) (((v) * 20 + 2) / 3)
-
-static int cs_get_gain(uint reg)
-{
- int gain;
-
- gain = CS_GAIN_TO_RECLEVEL(CS_LGAIN_GET(reg));
- gain |= CS_GAIN_TO_RECLEVEL(CS_RGAIN_GET(reg)) << 8;
- return gain;
-}
-
-static int cs_set_gain(int gain)
-{
- uint tempctl;
-
- tempctl = cs4218_control & ~(CS_LGAIN | CS_RGAIN);
- tempctl |= CS_LGAIN_SET(CS_RECLEVEL_TO_GAIN(gain & 0xff));
- tempctl |= CS_RGAIN_SET(CS_RECLEVEL_TO_GAIN((gain >> 8) & 0xff));
- gain = cs_get_gain(tempctl);
-
- if (tempctl != cs4218_control) {
- cs4218_ctl_write(tempctl);
- }
- return gain;
-}
-
-static int CS_SetVolume(int volume)
-{
- return cs_volume_setter(volume, CS_MUTE);
-}
-
-static void CS_Play(void)
-{
- int i, count;
- unsigned long flags;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
-
- /* Protect buffer */
- spin_lock_irqsave(&cs4218_lock, flags);
-#if 0
- if (awacs_beep_state) {
- /* sound takes precedence over beeps */
- out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (awacs_rate_index << 8));
- out_le32(&awacs->byteswap, sound.hard.format != AFMT_S16_BE);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(&(awacs_tx_cmds[(sq.front+sq.active) % sq.max_count])));
-
- beep_playing = 0;
- awacs_beep_state = 0;
- }
-#endif
- i = sq.front + sq.active;
- if (i >= sq.max_count)
- i -= sq.max_count;
- while (sq.active < 2 && sq.active < sq.count) {
- count = (sq.count == sq.active + 1)?sq.rear_size:sq.block_size;
- if (count < sq.block_size && !sq.syncing)
- /* last block not yet filled, and we're not syncing. */
- break;
-
- bdp = &tx_base[i];
- bdp->cbd_datlen = count;
-
- flush_dcache_range((ulong)sound_buffers[i],
- (ulong)(sound_buffers[i] + count));
-
- if (++i >= sq.max_count)
- i = 0;
-
- if (sq.active == 0) {
- /* The SMC does not load its fifo until the first
- * TDM frame pulse, so the transmit data gets shifted
- * by one word. To compensate for this, we incorrectly
- * transmit the first buffer and shorten it by one
- * word. Subsequent buffers are then aligned properly.
- */
- bdp->cbd_datlen -= 2;
-
- /* Start up the SMC Transmitter.
- */
- cp = cpmp;
- cp->cp_smc[1].smc_smcmr |= SMCMR_TEN;
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_RESTART_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
- }
-
- /* Buffer is ready now.
- */
- bdp->cbd_sc |= BD_SC_READY;
-
- ++sq.active;
- }
- spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void CS_Record(void)
-{
- unsigned long flags;
- volatile smc_t *sp;
-
- if (read_sq.active)
- return;
-
- /* Protect buffer */
- spin_lock_irqsave(&cs4218_lock, flags);
-
- /* This is all we have to do......Just start it up.
- */
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr |= SMCMR_REN;
-
- read_sq.active = 1;
-
- spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-
-static void
-cs4218_tdm_tx_intr(void *devid)
-{
- int i = sq.front;
- volatile cbd_t *bdp;
-
- while (sq.active > 0) {
- bdp = &tx_base[i];
- if (bdp->cbd_sc & BD_SC_READY)
- break; /* this frame is still going */
- --sq.count;
- --sq.active;
- if (++i >= sq.max_count)
- i = 0;
- }
- if (i != sq.front)
- WAKE_UP(sq.action_queue);
- sq.front = i;
-
- CS_Play();
-
- if (!sq.active)
- WAKE_UP(sq.sync_queue);
-}
-
-
-static void
-cs4218_tdm_rx_intr(void *devid)
-{
-
- /* We want to blow 'em off when shutting down.
- */
- if (read_sq.active == 0)
- return;
-
- /* Check multiple buffers in case we were held off from
- * interrupt processing for a long time. Geeze, I really hope
- * this doesn't happen.
- */
- while ((rx_base[read_sq.rear].cbd_sc & BD_SC_EMPTY) == 0) {
-
- /* Invalidate the data cache range for this buffer.
- */
- invalidate_dcache_range(
- (uint)(sound_read_buffers[read_sq.rear]),
- (uint)(sound_read_buffers[read_sq.rear] + read_sq.block_size));
-
- /* Make buffer available again and move on.
- */
- rx_base[read_sq.rear].cbd_sc |= BD_SC_EMPTY;
- read_sq.rear++;
-
- /* Wrap the buffer ring.
- */
- if (read_sq.rear >= read_sq.max_active)
- read_sq.rear = 0;
-
- /* If we have caught up to the front buffer, bump it.
- * This will cause weird (but not fatal) results if the
- * read loop is currently using this buffer. The user is
- * behind in this case anyway, so weird things are going
- * to happen.
- */
- if (read_sq.rear == read_sq.front) {
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
-
- WAKE_UP(read_sq.action_queue);
-}
-
-static void cs_nosound(unsigned long xx)
-{
- unsigned long flags;
-
- /* not sure if this is needed, since hardware command is #if 0'd */
- spin_lock_irqsave(&cs4218_lock, flags);
- if (beep_playing) {
-#if 0
- st_le16(&beep_dbdma_cmd->command, DBDMA_STOP);
-#endif
- beep_playing = 0;
- }
- spin_unlock_irqrestore(&cs4218_lock, flags);
-}
-
-static DEFINE_TIMER(beep_timer, cs_nosound, 0, 0);
-
-static void cs_mksound(unsigned int hz, unsigned int ticks)
-{
- unsigned long flags;
- int beep_speed = BEEP_SPEED;
- int srate = cs4218_freqs[beep_speed];
- int period, ncycles, nsamples;
- int i, j, f;
- short *p;
- static int beep_hz_cache;
- static int beep_nsamples_cache;
- static int beep_volume_cache;
-
- if (hz <= srate / BEEP_BUFLEN || hz > srate / 2) {
-#if 1
- /* this is a hack for broken X server code */
- hz = 750;
- ticks = 12;
-#else
- /* cancel beep currently playing */
- awacs_nosound(0);
- return;
-#endif
- }
- /* lock while modifying beep_timer */
- spin_lock_irqsave(&cs4218_lock, flags);
- del_timer(&beep_timer);
- if (ticks) {
- beep_timer.expires = jiffies + ticks;
- add_timer(&beep_timer);
- }
- if (beep_playing || sq.active || beep_buf == NULL) {
- spin_unlock_irqrestore(&cs4218_lock, flags);
- return; /* too hard, sorry :-( */
- }
- beep_playing = 1;
-#if 0
- st_le16(&beep_dbdma_cmd->command, OUTPUT_MORE + BR_ALWAYS);
-#endif
- spin_unlock_irqrestore(&cs4218_lock, flags);
-
- if (hz == beep_hz_cache && beep_volume == beep_volume_cache) {
- nsamples = beep_nsamples_cache;
- } else {
- period = srate * 256 / hz; /* fixed point */
- ncycles = BEEP_BUFLEN * 256 / period;
- nsamples = (period * ncycles) >> 8;
- f = ncycles * 65536 / nsamples;
- j = 0;
- p = beep_buf;
- for (i = 0; i < nsamples; ++i, p += 2) {
- p[0] = p[1] = beep_wform[j >> 8] * beep_volume;
- j = (j + f) & 0xffff;
- }
- beep_hz_cache = hz;
- beep_volume_cache = beep_volume;
- beep_nsamples_cache = nsamples;
- }
-
-#if 0
- st_le16(&beep_dbdma_cmd->req_count, nsamples*4);
- st_le16(&beep_dbdma_cmd->xfer_status, 0);
- st_le32(&beep_dbdma_cmd->cmd_dep, virt_to_bus(beep_dbdma_cmd));
- st_le32(&beep_dbdma_cmd->phy_addr, virt_to_bus(beep_buf));
- awacs_beep_state = 1;
-
- spin_lock_irqsave(&cs4218_lock, flags);
- if (beep_playing) { /* i.e. haven't been terminated already */
- out_le32(&awacs_txdma->control, (RUN|WAKE|FLUSH|PAUSE) << 16);
- out_le32(&awacs->control,
- (in_le32(&awacs->control) & ~0x1f00)
- | (beep_speed << 8));
- out_le32(&awacs->byteswap, 0);
- out_le32(&awacs_txdma->cmdptr, virt_to_bus(beep_dbdma_cmd));
- out_le32(&awacs_txdma->control, RUN | (RUN << 16));
- }
- spin_unlock_irqrestore(&cs4218_lock, flags);
-#endif
-}
-
-static MACHINE mach_cs4218 = {
- .owner = THIS_MODULE,
- .name = "HIOX CS4218",
- .name2 = "Built-in Sound",
- .dma_alloc = CS_Alloc,
- .dma_free = CS_Free,
- .irqinit = CS_IrqInit,
-#ifdef MODULE
- .irqcleanup = CS_IrqCleanup,
-#endif /* MODULE */
- .init = CS_Init,
- .silence = CS_Silence,
- .setFormat = CS_SetFormat,
- .setVolume = CS_SetVolume,
- .play = CS_Play
-};
-
-
-/*** Mid level stuff *********************************************************/
-
-
-static void sound_silence(void)
-{
- /* update hardware settings one more */
- (*sound.mach.init)();
-
- (*sound.mach.silence)();
-}
-
-
-static void sound_init(void)
-{
- (*sound.mach.init)();
-}
-
-
-static int sound_set_format(int format)
-{
- return(*sound.mach.setFormat)(format);
-}
-
-
-static int sound_set_speed(int speed)
-{
- if (speed < 0)
- return(sound.soft.speed);
-
- sound.soft.speed = speed;
- (*sound.mach.init)();
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.speed = sound.soft.speed;
-
- return(sound.soft.speed);
-}
-
-
-static int sound_set_stereo(int stereo)
-{
- if (stereo < 0)
- return(sound.soft.stereo);
-
- stereo = !!stereo; /* should be 0 or 1 now */
-
- sound.soft.stereo = stereo;
- if (sound.minDev == SND_DEV_DSP)
- sound.dsp.stereo = stereo;
- (*sound.mach.init)();
-
- return(stereo);
-}
-
-
-static int sound_set_volume(int volume)
-{
- return(*sound.mach.setVolume)(volume);
-}
-
-static ssize_t sound_copy_translate(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans_write->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans_write->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans_write->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans_write->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans_write->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans_write->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.trans_write->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.trans_write->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-
-static ssize_t sound_copy_translate_read(const u_char *userPtr,
- size_t userCount,
- u_char frame[], ssize_t *frameUsed,
- ssize_t frameLeft)
-{
- ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
-
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- ct_func = sound.trans_read->ct_ulaw;
- break;
- case AFMT_A_LAW:
- ct_func = sound.trans_read->ct_alaw;
- break;
- case AFMT_S8:
- ct_func = sound.trans_read->ct_s8;
- break;
- case AFMT_U8:
- ct_func = sound.trans_read->ct_u8;
- break;
- case AFMT_S16_BE:
- ct_func = sound.trans_read->ct_s16be;
- break;
- case AFMT_U16_BE:
- ct_func = sound.trans_read->ct_u16be;
- break;
- case AFMT_S16_LE:
- ct_func = sound.trans_read->ct_s16le;
- break;
- case AFMT_U16_LE:
- ct_func = sound.trans_read->ct_u16le;
- break;
- }
- if (ct_func)
- return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
- else
- return 0;
-}
-
-
-/*
- * /dev/mixer abstraction
- */
-
-static int mixer_open(struct inode *inode, struct file *file)
-{
- mixer.busy = 1;
- return nonseekable_open(inode, file);
-}
-
-
-static int mixer_release(struct inode *inode, struct file *file)
-{
- mixer.busy = 0;
- return 0;
-}
-
-
-static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- int data;
- uint tmpcs;
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- mixer.modify_counter++;
- if (cmd == OSS_GETVERSION)
- return IOCTL_OUT(arg, SOUND_VERSION);
- switch (cmd) {
- case SOUND_MIXER_INFO: {
- mixer_info info;
- strlcpy(info.id, "CS4218_TDM", sizeof(info.id));
- strlcpy(info.name, "CS4218_TDM", sizeof(info.name));
- info.name[sizeof(info.name)-1] = 0;
- info.modify_counter = mixer.modify_counter;
- if (copy_to_user((int *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- case SOUND_MIXER_READ_DEVMASK:
- data = SOUND_MASK_VOLUME | SOUND_MASK_LINE
- | SOUND_MASK_MIC | SOUND_MASK_RECLEV
- | SOUND_MASK_ALTPCM;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECMASK:
- data = SOUND_MASK_LINE | SOUND_MASK_MIC;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECSRC:
- if (cs4218_control & CS_DO1)
- data = SOUND_MASK_LINE;
- else
- data = SOUND_MASK_MIC;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_RECSRC:
- IOCTL_IN(arg, data);
- data &= (SOUND_MASK_LINE | SOUND_MASK_MIC);
- if (data & SOUND_MASK_LINE)
- tmpcs = cs4218_control |
- (CS_ISL | CS_ISR | CS_DO1);
- if (data & SOUND_MASK_MIC)
- tmpcs = cs4218_control &
- ~(CS_ISL | CS_ISR | CS_DO1);
- if (tmpcs != cs4218_control)
- cs4218_ctl_write(tmpcs);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_STEREODEVS:
- data = SOUND_MASK_VOLUME | SOUND_MASK_RECLEV;
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_CAPS:
- return IOCTL_OUT(arg, 0);
- case SOUND_MIXER_READ_VOLUME:
- data = (cs4218_control & CS_MUTE)? 0:
- cs_get_volume(cs4218_control);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_WRITE_VOLUME:
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_volume(data));
- case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */
- IOCTL_IN(arg, data);
- beep_volume = data & 0xff;
- /* fall through */
- case SOUND_MIXER_READ_ALTPCM:
- return IOCTL_OUT(arg, beep_volume);
- case SOUND_MIXER_WRITE_RECLEV:
- IOCTL_IN(arg, data);
- data = cs_set_gain(data);
- return IOCTL_OUT(arg, data);
- case SOUND_MIXER_READ_RECLEV:
- data = cs_get_gain(cs4218_control);
- return IOCTL_OUT(arg, data);
- }
-
- return -EINVAL;
-}
-
-
-static const struct file_operations mixer_fops =
-{
- .owner = THIS_MODULE,
- .llseek = sound_lseek,
- .ioctl = mixer_ioctl,
- .open = mixer_open,
- .release = mixer_release,
-};
-
-
-static void __init mixer_init(void)
-{
- mixer_unit = register_sound_mixer(&mixer_fops, -1);
- if (mixer_unit < 0)
- return;
-
- mixer.busy = 0;
- sound.treble = 0;
- sound.bass = 0;
-
- /* Set Line input, no gain, no attenuation.
- */
- cs4218_control = CS_ISL | CS_ISR | CS_DO1;
- cs4218_control |= CS_LGAIN_SET(0) | CS_RGAIN_SET(0);
- cs4218_control |= CS_LATTEN_SET(0) | CS_RATTEN_SET(0);
- cs4218_ctl_write(cs4218_control);
-}
-
-
-/*
- * Sound queue stuff, the heart of the driver
- */
-
-
-static int sq_allocate_buffers(void)
-{
- int i;
-
- if (sound_buffers)
- return 0;
- sound_buffers = kmalloc (numBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_buffers[i] = sound.mach.dma_alloc (bufSize << 10, GFP_KERNEL);
- if (!sound_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-
-static void sq_release_buffers(void)
-{
- int i;
-
- if (sound_buffers) {
- for (i = 0; i < numBufs; i++)
- sound.mach.dma_free (sound_buffers[i], bufSize << 10);
- kfree (sound_buffers);
- sound_buffers = 0;
- }
-}
-
-
-static int sq_allocate_read_buffers(void)
-{
- int i;
-
- if (sound_read_buffers)
- return 0;
- sound_read_buffers = kmalloc(numReadBufs * sizeof(char *), GFP_KERNEL);
- if (!sound_read_buffers)
- return -ENOMEM;
- for (i = 0; i < numBufs; i++) {
- sound_read_buffers[i] = sound.mach.dma_alloc (readbufSize<<10,
- GFP_KERNEL);
- if (!sound_read_buffers[i]) {
- while (i--)
- sound.mach.dma_free (sound_read_buffers[i],
- readbufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- return -ENOMEM;
- }
- }
- return 0;
-}
-
-static void sq_release_read_buffers(void)
-{
- int i;
-
- if (sound_read_buffers) {
- cpmp->cp_smc[1].smc_smcmr &= ~SMCMR_REN;
- for (i = 0; i < numReadBufs; i++)
- sound.mach.dma_free (sound_read_buffers[i],
- bufSize << 10);
- kfree (sound_read_buffers);
- sound_read_buffers = 0;
- }
-}
-
-
-static void sq_setup(int numBufs, int bufSize, char **write_buffers)
-{
- int i;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
- volatile smc_t *sp;
-
- /* Make sure the SMC transmit is shut down.
- */
- cp = cpmp;
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~SMCMR_TEN;
-
- sq.max_count = numBufs;
- sq.max_active = numBufs;
- sq.block_size = bufSize;
- sq.buffers = write_buffers;
-
- sq.front = sq.count = 0;
- sq.rear = -1;
- sq.syncing = 0;
- sq.active = 0;
-
- bdp = tx_base;
- for (i=0; i<numBufs; i++) {
- bdp->cbd_bufaddr = virt_to_bus(write_buffers[i]);
- bdp++;
- }
-
- /* This causes the SMC to sync up with the first buffer again.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-static void read_sq_setup(int numBufs, int bufSize, char **read_buffers)
-{
- int i;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
- volatile smc_t *sp;
-
- /* Make sure the SMC receive is shut down.
- */
- cp = cpmp;
- sp = &cpmp->cp_smc[1];
- sp->smc_smcmr &= ~SMCMR_REN;
-
- read_sq.max_count = numBufs;
- read_sq.max_active = numBufs;
- read_sq.block_size = bufSize;
- read_sq.buffers = read_buffers;
-
- read_sq.front = read_sq.count = 0;
- read_sq.rear = 0;
- read_sq.rear_size = 0;
- read_sq.syncing = 0;
- read_sq.active = 0;
-
- bdp = rx_base;
- for (i=0; i<numReadBufs; i++) {
- bdp->cbd_bufaddr = virt_to_bus(read_buffers[i]);
- bdp->cbd_datlen = read_sq.block_size;
- bdp++;
- }
-
- /* This causes the SMC to sync up with the first buffer again.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2, CPM_CR_INIT_RX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-}
-
-
-static void sq_play(void)
-{
- (*sound.mach.play)();
-}
-
-
-/* ++TeSche: radically changed this one too */
-
-static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
- loff_t *ppos)
-{
- ssize_t uWritten = 0;
- u_char *dest;
- ssize_t uUsed, bUsed, bLeft;
-
- /* ++TeSche: Is something like this necessary?
- * Hey, that's an honest question! Or does any other part of the
- * filesystem already checks this situation? I really don't know.
- */
- if (uLeft == 0)
- return 0;
-
- /* The interrupt doesn't start to play the last, incomplete frame.
- * Thus we can append to it without disabling the interrupts! (Note
- * also that sq.rear isn't affected by the interrupt.)
- */
-
- if (sq.count > 0 && (bLeft = sq.block_size-sq.rear_size) > 0) {
- dest = sq_block_address(sq.rear);
- bUsed = sq.rear_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- sq.rear_size = bUsed;
- }
-
- do {
- while (sq.count == sq.max_active) {
- sq_play();
- if (NON_BLOCKING(sq.open_mode))
- return uWritten > 0 ? uWritten : -EAGAIN;
- SLEEP(sq.action_queue);
- if (SIGNAL_RECEIVED)
- return uWritten > 0 ? uWritten : -EINTR;
- }
-
- /* Here, we can avoid disabling the interrupt by first
- * copying and translating the data, and then updating
- * the sq variables. Until this is done, the interrupt
- * won't see the new frame and we can work on it
- * undisturbed.
- */
-
- dest = sq_block_address((sq.rear+1) % sq.max_count);
- bUsed = 0;
- bLeft = sq.block_size;
- uUsed = sound_copy_translate(src, uLeft, dest, &bUsed, bLeft);
- if (uUsed <= 0)
- break;
- src += uUsed;
- uWritten += uUsed;
- uLeft -= uUsed;
- if (bUsed) {
- sq.rear = (sq.rear+1) % sq.max_count;
- sq.rear_size = bUsed;
- sq.count++;
- }
- } while (bUsed); /* uUsed may have been 0 */
-
- sq_play();
-
- return uUsed < 0? uUsed: uWritten;
-}
-
-
-/***********/
-
-/* Here is how the values are used for reading.
- * The value 'active' simply indicates the DMA is running. This is
- * done so the driver semantics are DMA starts when the first read is
- * posted. The value 'front' indicates the buffer we should next
- * send to the user. The value 'rear' indicates the buffer the DMA is
- * currently filling. When 'front' == 'rear' the buffer "ring" is
- * empty (we always have an empty available). The 'rear_size' is used
- * to track partial offsets into the current buffer. Right now, I just keep
- * The DMA running. If the reader can't keep up, the interrupt tosses
- * the oldest buffer. We could also shut down the DMA in this case.
- */
-static ssize_t sq_read(struct file *file, char *dst, size_t uLeft,
- loff_t *ppos)
-{
-
- ssize_t uRead, bLeft, bUsed, uUsed;
-
- if (uLeft == 0)
- return 0;
-
- if (!read_sq.active)
- CS_Record(); /* Kick off the record process. */
-
- uRead = 0;
-
- /* Move what the user requests, depending upon other options.
- */
- while (uLeft > 0) {
-
- /* When front == rear, the DMA is not done yet.
- */
- while (read_sq.front == read_sq.rear) {
- if (NON_BLOCKING(read_sq.open_mode)) {
- return uRead > 0 ? uRead : -EAGAIN;
- }
- SLEEP(read_sq.action_queue);
- if (SIGNAL_RECEIVED)
- return uRead > 0 ? uRead : -EINTR;
- }
-
- /* The amount we move is either what is left in the
- * current buffer or what the user wants.
- */
- bLeft = read_sq.block_size - read_sq.rear_size;
- bUsed = read_sq.rear_size;
- uUsed = sound_copy_translate_read(dst, uLeft,
- read_sq.buffers[read_sq.front], &bUsed, bLeft);
- if (uUsed <= 0)
- return uUsed;
- dst += uUsed;
- uRead += uUsed;
- uLeft -= uUsed;
- read_sq.rear_size += bUsed;
- if (read_sq.rear_size >= read_sq.block_size) {
- read_sq.rear_size = 0;
- read_sq.front++;
- if (read_sq.front >= read_sq.max_active)
- read_sq.front = 0;
- }
- }
- return uRead;
-}
-
-static int sq_open(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- if (file->f_mode & FMODE_WRITE) {
- if (sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (sq.busy) {
- SLEEP(sq.open_queue);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- }
- sq.busy = 1; /* Let's play spot-the-race-condition */
-
- if (sq_allocate_buffers()) goto err_out_nobusy;
-
- sq_setup(numBufs, bufSize<<10,sound_buffers);
- sq.open_mode = file->f_mode;
- }
-
-
- if (file->f_mode & FMODE_READ) {
- if (read_sq.busy) {
- rc = -EBUSY;
- if (NON_BLOCKING(file->f_flags))
- goto err_out;
- rc = -EINTR;
- while (read_sq.busy) {
- SLEEP(read_sq.open_queue);
- if (SIGNAL_RECEIVED)
- goto err_out;
- }
- rc = 0;
- }
- read_sq.busy = 1;
- if (sq_allocate_read_buffers()) goto err_out_nobusy;
-
- read_sq_setup(numReadBufs,readbufSize<<10, sound_read_buffers);
- read_sq.open_mode = file->f_mode;
- }
-
- /* Start up the 4218 by:
- * Reset.
- * Enable, unreset.
- */
- *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_RSTAUDIO;
- eieio();
- *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_ENAUDIO;
- mdelay(50);
- *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
-
- /* We need to send the current control word in case someone
- * opened /dev/mixer and changed things while we were shut
- * down. Chances are good the initialization that follows
- * would have done this, but it is still possible it wouldn't.
- */
- cs4218_ctl_write(cs4218_control);
-
- sound.minDev = iminor(inode) & 0x0f;
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_init();
- if ((iminor(inode) & 0x0f) == SND_DEV_AUDIO) {
- sound_set_speed(8000);
- sound_set_stereo(0);
- sound_set_format(AFMT_MU_LAW);
- }
-
- return nonseekable_open(inode, file);
-
-err_out_nobusy:
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-err_out:
- return rc;
-}
-
-
-static void sq_reset(void)
-{
- sound_silence();
- sq.active = 0;
- sq.count = 0;
- sq.front = (sq.rear+1) % sq.max_count;
-#if 0
- init_tdm_buffers();
-#endif
-}
-
-
-static int sq_fsync(struct file *filp, struct dentry *dentry)
-{
- int rc = 0;
-
- sq.syncing = 1;
- sq_play(); /* there may be an incomplete frame waiting */
-
- while (sq.active) {
- SLEEP(sq.sync_queue);
- if (SIGNAL_RECEIVED) {
- /* While waiting for audio output to drain, an
- * interrupt occurred. Stop audio output immediately
- * and clear the queue. */
- sq_reset();
- rc = -EINTR;
- break;
- }
- }
-
- sq.syncing = 0;
- return rc;
-}
-
-static int sq_release(struct inode *inode, struct file *file)
-{
- int rc = 0;
-
- if (sq.busy)
- rc = sq_fsync(file, file->f_path.dentry);
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
- sound_silence();
-
- sq_release_read_buffers();
- sq_release_buffers();
-
- if (file->f_mode & FMODE_READ) {
- read_sq.busy = 0;
- WAKE_UP(read_sq.open_queue);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- sq.busy = 0;
- WAKE_UP(sq.open_queue);
- }
-
- /* Shut down the SMC.
- */
- cpmp->cp_smc[1].smc_smcmr &= ~(SMCMR_TEN | SMCMR_REN);
-
- /* Shut down the codec.
- */
- *((volatile uint *)HIOX_CSR4_ADDR) |= HIOX_CSR4_RSTAUDIO;
- eieio();
- *((volatile uint *)HIOX_CSR4_ADDR) &= ~HIOX_CSR4_ENAUDIO;
-
- /* Wake up a process waiting for the queue being released.
- * Note: There may be several processes waiting for a call
- * to open() returning. */
-
- return rc;
-}
-
-
-static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
- u_long arg)
-{
- u_long fmt;
- int data;
-#if 0
- int size, nbufs;
-#else
- int size;
-#endif
-
- switch (cmd) {
- case SNDCTL_DSP_RESET:
- sq_reset();
- return 0;
- case SNDCTL_DSP_POST:
- case SNDCTL_DSP_SYNC:
- return sq_fsync(file, file->f_path.dentry);
-
- /* ++TeSche: before changing any of these it's
- * probably wise to wait until sound playing has
- * settled down. */
- case SNDCTL_DSP_SPEED:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_speed(data));
- case SNDCTL_DSP_STEREO:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data));
- case SOUND_PCM_WRITE_CHANNELS:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
- case SNDCTL_DSP_SETFMT:
- sq_fsync(file, file->f_path.dentry);
- IOCTL_IN(arg, data);
- return IOCTL_OUT(arg, sound_set_format(data));
- case SNDCTL_DSP_GETFMTS:
- fmt = 0;
- if (sound.trans_write) {
- if (sound.trans_write->ct_ulaw)
- fmt |= AFMT_MU_LAW;
- if (sound.trans_write->ct_alaw)
- fmt |= AFMT_A_LAW;
- if (sound.trans_write->ct_s8)
- fmt |= AFMT_S8;
- if (sound.trans_write->ct_u8)
- fmt |= AFMT_U8;
- if (sound.trans_write->ct_s16be)
- fmt |= AFMT_S16_BE;
- if (sound.trans_write->ct_u16be)
- fmt |= AFMT_U16_BE;
- if (sound.trans_write->ct_s16le)
- fmt |= AFMT_S16_LE;
- if (sound.trans_write->ct_u16le)
- fmt |= AFMT_U16_LE;
- }
- return IOCTL_OUT(arg, fmt);
- case SNDCTL_DSP_GETBLKSIZE:
- size = sq.block_size
- * sound.soft.size * (sound.soft.stereo + 1)
- / (sound.hard.size * (sound.hard.stereo + 1));
- return IOCTL_OUT(arg, size);
- case SNDCTL_DSP_SUBDIVIDE:
- break;
-#if 0 /* Sorry can't do this at the moment. The CPM allocated buffers
- * long ago that can't be changed.
- */
- case SNDCTL_DSP_SETFRAGMENT:
- if (sq.count || sq.active || sq.syncing)
- return -EINVAL;
- IOCTL_IN(arg, size);
- nbufs = size >> 16;
- if (nbufs < 2 || nbufs > numBufs)
- nbufs = numBufs;
- size &= 0xffff;
- if (size >= 8 && size <= 30) {
- size = 1 << size;
- size *= sound.hard.size * (sound.hard.stereo + 1);
- size /= sound.soft.size * (sound.soft.stereo + 1);
- if (size > (bufSize << 10))
- size = bufSize << 10;
- } else
- size = bufSize << 10;
- sq_setup(numBufs, size, sound_buffers);
- sq.max_active = nbufs;
- return 0;
-#endif
-
- default:
- return mixer_ioctl(inode, file, cmd, arg);
- }
- return -EINVAL;
-}
-
-
-
-static const struct file_operations sq_fops =
-{
- .owner = THIS_MODULE,
- .llseek = sound_lseek,
- .read = sq_read, /* sq_read */
- .write = sq_write,
- .ioctl = sq_ioctl,
- .open = sq_open,
- .release = sq_release,
-};
-
-
-static void __init sq_init(void)
-{
- sq_unit = register_sound_dsp(&sq_fops, -1);
- if (sq_unit < 0)
- return;
-
- init_waitqueue_head(&sq.action_queue);
- init_waitqueue_head(&sq.open_queue);
- init_waitqueue_head(&sq.sync_queue);
- init_waitqueue_head(&read_sq.action_queue);
- init_waitqueue_head(&read_sq.open_queue);
- init_waitqueue_head(&read_sq.sync_queue);
-
- sq.busy = 0;
- read_sq.busy = 0;
-
- /* whatever you like as startup mode for /dev/dsp,
- * (/dev/audio hasn't got a startup mode). note that
- * once changed a new open() will *not* restore these!
- */
- sound.dsp.format = AFMT_S16_BE;
- sound.dsp.stereo = 1;
- sound.dsp.size = 16;
-
- /* set minimum rate possible without expanding */
- sound.dsp.speed = 8000;
-
- /* before the first open to /dev/dsp this wouldn't be set */
- sound.soft = sound.dsp;
- sound.hard = sound.dsp;
-
- sound_silence();
-}
-
-/*
- * /dev/sndstat
- */
-
-
-/* state.buf should not overflow! */
-
-static int state_open(struct inode *inode, struct file *file)
-{
- char *buffer = state.buf, *mach = "", cs4218_buf[50];
- int len = 0;
-
- if (state.busy)
- return -EBUSY;
-
- state.ptr = 0;
- state.busy = 1;
-
- sprintf(cs4218_buf, "Crystal CS4218 on TDM, ");
- mach = cs4218_buf;
-
- len += sprintf(buffer+len, "%sDMA sound driver:\n", mach);
-
- len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
- switch (sound.soft.format) {
- case AFMT_MU_LAW:
- len += sprintf(buffer+len, " (mu-law)");
- break;
- case AFMT_A_LAW:
- len += sprintf(buffer+len, " (A-law)");
- break;
- case AFMT_U8:
- len += sprintf(buffer+len, " (unsigned 8 bit)");
- break;
- case AFMT_S8:
- len += sprintf(buffer+len, " (signed 8 bit)");
- break;
- case AFMT_S16_BE:
- len += sprintf(buffer+len, " (signed 16 bit big)");
- break;
- case AFMT_U16_BE:
- len += sprintf(buffer+len, " (unsigned 16 bit big)");
- break;
- case AFMT_S16_LE:
- len += sprintf(buffer+len, " (signed 16 bit little)");
- break;
- case AFMT_U16_LE:
- len += sprintf(buffer+len, " (unsigned 16 bit little)");
- break;
- }
- len += sprintf(buffer+len, "\n");
- len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
- sound.soft.speed, sound.hard.speed);
- len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
- sound.soft.stereo, sound.soft.stereo ? "stereo" : "mono");
- len += sprintf(buffer+len, "\tsq.block_size = %d sq.max_count = %d"
- " sq.max_active = %d\n",
- sq.block_size, sq.max_count, sq.max_active);
- len += sprintf(buffer+len, "\tsq.count = %d sq.rear_size = %d\n", sq.count,
- sq.rear_size);
- len += sprintf(buffer+len, "\tsq.active = %d sq.syncing = %d\n",
- sq.active, sq.syncing);
- state.len = len;
- return nonseekable_open(inode, file);
-}
-
-
-static int state_release(struct inode *inode, struct file *file)
-{
- state.busy = 0;
- return 0;
-}
-
-
-static ssize_t state_read(struct file *file, char *buf, size_t count,
- loff_t *ppos)
-{
- int n = state.len - state.ptr;
- if (n > count)
- n = count;
- if (n <= 0)
- return 0;
- if (copy_to_user(buf, &state.buf[state.ptr], n))
- return -EFAULT;
- state.ptr += n;
- return n;
-}
-
-
-static const struct file_operations state_fops =
-{
- .owner = THIS_MODULE,
- .llseek = sound_lseek,
- .read = state_read,
- .open = state_open,
- .release = state_release,
-};
-
-
-static void __init state_init(void)
-{
- state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
- if (state_unit < 0)
- return;
- state.busy = 0;
-}
-
-
-/*** Common stuff ********************************************************/
-
-static long long sound_lseek(struct file *file, long long offset, int orig)
-{
- return -ESPIPE;
-}
-
-
-/*** Config & Setup **********************************************************/
-
-
-int __init tdm8xx_sound_init(void)
-{
- int i, has_sound;
- uint dp_offset;
- volatile uint *sirp;
- volatile cbd_t *bdp;
- volatile cpm8xx_t *cp;
- volatile smc_t *sp;
- volatile smc_uart_t *up;
- volatile immap_t *immap;
-
- has_sound = 0;
-
- /* Program the SI/TSA to use TDMa, connected to SMC2, for 4 bytes.
- */
- cp = cpmp; /* Get pointer to Communication Processor */
- immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
-
- /* Set all TDMa control bits to zero. This enables most features
- * we want.
- */
- cp->cp_simode &= ~0x00000fff;
-
- /* Enable common receive/transmit clock pins, use IDL format.
- * Sync on falling edge, transmit rising clock, receive falling
- * clock, delay 1 bit on both Tx and Rx. Common Tx/Rx clocks and
- * sync.
- * Connect SMC2 to TSA.
- */
- cp->cp_simode |= 0x80000141;
-
- /* Configure port A pins for TDMa operation.
- * The RPX-Lite (MPC850/823) loses SMC2 when TDM is used.
- */
- immap->im_ioport.iop_papar |= 0x01c0; /* Enable TDMa functions */
- immap->im_ioport.iop_padir |= 0x00c0; /* Enable TDMa Tx/Rx */
- immap->im_ioport.iop_padir &= ~0x0100; /* Enable L1RCLKa */
-
- immap->im_ioport.iop_pcpar |= 0x0800; /* Enable L1RSYNCa */
- immap->im_ioport.iop_pcdir &= ~0x0800;
-
- /* Initialize the SI TDM routing table. We use TDMa only.
- * The receive table and transmit table each have only one
- * entry, to capture/send four bytes after each frame pulse.
- * The 16-bit ram entry is 0000 0001 1000 1111. (SMC2)
- */
- cp->cp_sigmr = 0;
- sirp = (uint *)cp->cp_siram;
-
- *sirp = 0x018f0000; /* Receive entry */
- sirp += 64;
- *sirp = 0x018f0000; /* Tramsmit entry */
-
- /* Enable single TDMa routing.
- */
- cp->cp_sigmr = 0x04;
-
- /* Initialize the SMC for transparent operation.
- */
- sp = &cpmp->cp_smc[1];
- up = (smc_uart_t *)&cp->cp_dparam[PROFF_SMC2];
-
- /* We need to allocate a transmit and receive buffer
- * descriptors from dual port ram.
- */
- dp_addr = cpm_dpalloc(sizeof(cbd_t) * numReadBufs, 8);
-
- /* Set the physical address of the host memory
- * buffers in the buffer descriptors, and the
- * virtual address for us to work with.
- */
- bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
- up->smc_rbase = dp_offset;
- rx_cur = rx_base = (cbd_t *)bdp;
-
- for (i=0; i<(numReadBufs-1); i++) {
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
- bdp++;
- }
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
- /* Now, do the same for the transmit buffers.
- */
- dp_offset = cpm_dpalloc(sizeof(cbd_t) * numBufs, 8);
-
- bdp = (cbd_t *)&cp->cp_dpmem[dp_addr];
- up->smc_tbase = dp_offset;
- tx_cur = tx_base = (cbd_t *)bdp;
-
- for (i=0; i<(numBufs-1); i++) {
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = BD_SC_INTRPT;
- bdp++;
- }
- bdp->cbd_bufaddr = 0;
- bdp->cbd_datlen = 0;
- bdp->cbd_sc = (BD_SC_WRAP | BD_SC_INTRPT);
-
- /* Set transparent SMC mode.
- * A few things are specific to our application. The codec interface
- * is MSB first, hence the REVD selection. The CD/CTS pulse are
- * used by the TSA to indicate the frame start to the SMC.
- */
- up->smc_rfcr = SCC_EB;
- up->smc_tfcr = SCC_EB;
- up->smc_mrblr = readbufSize * 1024;
-
- /* Set 16-bit reversed data, transparent mode.
- */
- sp->smc_smcmr = smcr_mk_clen(15) |
- SMCMR_SM_TRANS | SMCMR_REVD | SMCMR_BS;
-
- /* Enable and clear events.
- * Because of FIFO delays, all we need is the receive interrupt
- * and we can process both the current receive and current
- * transmit interrupt within a few microseconds of the transmit.
- */
- sp->smc_smce = 0xff;
- sp->smc_smcm = SMCM_TXE | SMCM_TX | SMCM_RX;
-
- /* Send the CPM an initialize command.
- */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
-
- sound.mach = mach_cs4218;
- has_sound = 1;
-
- /* Initialize beep stuff */
- orig_mksound = kd_mksound;
- kd_mksound = cs_mksound;
- beep_buf = kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
- if (beep_buf == NULL)
- printk(KERN_WARNING "dmasound: no memory for "
- "beep buffer\n");
-
- if (!has_sound)
- return -ENODEV;
-
- /* Initialize the software SPI.
- */
- sw_spi_init();
-
- /* Set up sound queue, /dev/audio and /dev/dsp. */
-
- /* Set default settings. */
- sq_init();
-
- /* Set up /dev/sndstat. */
- state_init();
-
- /* Set up /dev/mixer. */
- mixer_init();
-
- if (!sound.mach.irqinit()) {
- printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
- return -ENODEV;
- }
-#ifdef MODULE
- irq_installed = 1;
-#endif
-
- printk(KERN_INFO "DMA sound driver installed, using %d buffers of %dk.\n",
- numBufs, bufSize);
-
- return 0;
-}
-
-/* Due to FIFOs and bit delays, the transmit interrupt occurs a few
- * microseconds ahead of the receive interrupt.
- * When we get an interrupt, we service the transmit first, then
- * check for a receive to prevent the overhead of returning through
- * the interrupt handler only to get back here right away during
- * full duplex operation.
- */
-static void
-cs4218_intr(void *dev_id)
-{
- volatile smc_t *sp;
- volatile cpm8xx_t *cp;
-
- sp = &cpmp->cp_smc[1];
-
- if (sp->smc_smce & SCCM_TX) {
- sp->smc_smce = SCCM_TX;
- cs4218_tdm_tx_intr((void *)sp);
- }
-
- if (sp->smc_smce & SCCM_RX) {
- sp->smc_smce = SCCM_RX;
- cs4218_tdm_rx_intr((void *)sp);
- }
-
- if (sp->smc_smce & SCCM_TXE) {
- /* Transmit underrun. This happens with the application
- * didn't keep up sending buffers. We tell the SMC to
- * restart, which will cause it to poll the current (next)
- * BD. If the user supplied data since this occurred,
- * we just start running again. If they didn't, the SMC
- * will poll the descriptor until data is placed there.
- */
- sp->smc_smce = SCCM_TXE;
- cp = cpmp; /* Get pointer to Communication Processor */
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SMC2,
- CPM_CR_RESTART_TX) | CPM_CR_FLG;
- while (cp->cp_cpcr & CPM_CR_FLG);
- }
-}
-
-
-#define MAXARGS 8 /* Should be sufficient for now */
-
-void __init dmasound_setup(char *str, int *ints)
-{
- /* check the bootstrap parameter for "dmasound=" */
-
- switch (ints[0]) {
- case 3:
- if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
- else
- catchRadius = ints[3];
- /* fall through */
- case 2:
- if (ints[1] < MIN_BUFFERS)
- printk("dmasound_setup: invalid number of buffers, using default = %d\n", numBufs);
- else
- numBufs = ints[1];
- if (ints[2] < MIN_BUFSIZE || ints[2] > MAX_BUFSIZE)
- printk("dmasound_setup: invalid buffer size, using default = %d\n", bufSize);
- else
- bufSize = ints[2];
- break;
- case 0:
- break;
- default:
- printk("dmasound_setup: invalid number of arguments\n");
- }
-}
-
-/* Software SPI functions.
- * These are on Port B.
- */
-#define PB_SPICLK ((uint)0x00000002)
-#define PB_SPIMOSI ((uint)0x00000004)
-#define PB_SPIMISO ((uint)0x00000008)
-
-static
-void sw_spi_init(void)
-{
- volatile cpm8xx_t *cp;
- volatile uint *hcsr4;
-
- hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
- cp = cpmp; /* Get pointer to Communication Processor */
-
- *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */
-
- /* Make these Port B signals general purpose I/O.
- * First, make sure the clock is low.
- */
- cp->cp_pbdat &= ~PB_SPICLK;
- cp->cp_pbpar &= ~(PB_SPICLK | PB_SPIMOSI | PB_SPIMISO);
-
- /* Clock and Master Output are outputs.
- */
- cp->cp_pbdir |= (PB_SPICLK | PB_SPIMOSI);
-
- /* Master Input.
- */
- cp->cp_pbdir &= ~PB_SPIMISO;
-
-}
-
-/* Write the CS4218 control word out the SPI port. While the
- * the control word is going out, the status word is arriving.
- */
-static
-uint cs4218_ctl_write(uint ctlreg)
-{
- uint status;
-
- sw_spi_io((u_char *)&ctlreg, (u_char *)&status, 4);
-
- /* Shadow the control register.....I guess we could do
- * the same for the status, but for now we just return it
- * and let the caller decide.
- */
- cs4218_control = ctlreg;
- return status;
-}
-
-static
-void sw_spi_io(u_char *obuf, u_char *ibuf, uint bcnt)
-{
- int bits, i;
- u_char outbyte, inbyte;
- volatile cpm8xx_t *cp;
- volatile uint *hcsr4;
-
- hcsr4 = (volatile uint *)HIOX_CSR4_ADDR;
- cp = cpmp; /* Get pointer to Communication Processor */
-
- /* The timing on the bus is pretty slow. Code inefficiency
- * and eieio() is our friend here :-).
- */
- cp->cp_pbdat &= ~PB_SPICLK;
- *hcsr4 |= HIOX_CSR4_AUDSPISEL; /* Enable SPI select */
- eieio();
-
- /* Clock in/out the bytes. Data is valid on the falling edge
- * of the clock. Data is MSB first.
- */
- for (i=0; i<bcnt; i++) {
- outbyte = *obuf++;
- inbyte = 0;
- for (bits=0; bits<8; bits++) {
- eieio();
- cp->cp_pbdat |= PB_SPICLK;
- eieio();
- if (outbyte & 0x80)
- cp->cp_pbdat |= PB_SPIMOSI;
- else
- cp->cp_pbdat &= ~PB_SPIMOSI;
- eieio();
- cp->cp_pbdat &= ~PB_SPICLK;
- eieio();
- outbyte <<= 1;
- inbyte <<= 1;
- if (cp->cp_pbdat & PB_SPIMISO)
- inbyte |= 1;
- }
- *ibuf++ = inbyte;
- }
-
- *hcsr4 &= ~HIOX_CSR4_AUDSPISEL; /* Disable SPI select */
- eieio();
-}
-
-void cleanup_module(void)
-{
- if (irq_installed) {
- sound_silence();
-#ifdef MODULE
- sound.mach.irqcleanup();
-#endif
- }
-
- sq_release_read_buffers();
- sq_release_buffers();
-
- if (mixer_unit >= 0)
- unregister_sound_mixer(mixer_unit);
- if (state_unit >= 0)
- unregister_sound_special(state_unit);
- if (sq_unit >= 0)
- unregister_sound_dsp(sq_unit);
-}
-
-module_init(tdm8xx_sound_init);
-module_exit(cleanup_module);
-
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index bfa3f52996d..e58288e1436 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -30,7 +30,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c
index 8e1fccd96fc..9589969cec7 100644
--- a/arch/ppc/boot/common/misc-common.c
+++ b/arch/ppc/boot/common/misc-common.c
@@ -57,7 +57,8 @@ unsigned char *ISA_io = NULL;
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
extern unsigned long com_port;
extern int serial_tstc(unsigned long com_port);
@@ -80,7 +81,8 @@ int tstc(void)
{
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if(keyb_present)
return (CRT_tstc() || serial_tstc(com_port));
else
@@ -95,7 +97,8 @@ int getc(void)
while (1) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
if (serial_tstc(com_port))
return (serial_getc(com_port));
#endif /* serial console */
@@ -112,7 +115,8 @@ putc(const char c)
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' )
serial_putc(com_port, '\r');
@@ -161,7 +165,8 @@ void puts(const char *s)
while ( ( c = *s++ ) != '\0' ) {
#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE) \
|| defined(CONFIG_SERIAL_MPC52xx_CONSOLE) \
- || defined(CONFIG_SERIAL_MPSC_CONSOLE)
+ || defined(CONFIG_SERIAL_MPSC_CONSOLE) \
+ || defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
serial_putc(com_port, c);
if ( c == '\n' ) serial_putc(com_port, '\r');
#endif /* serial console */
diff --git a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
index bcfb6cde70c..5b877792d14 100644
--- a/arch/ppc/boot/simple/Makefile
+++ b/arch/ppc/boot/simple/Makefile
@@ -201,6 +201,7 @@ boot-$(CONFIG_8260) += m8260_tty.o
endif
boot-$(CONFIG_SERIAL_MPC52xx_CONSOLE) += mpc52xx_tty.o
boot-$(CONFIG_SERIAL_MPSC_CONSOLE) += mv64x60_tty.o
+boot-$(CONFIG_SERIAL_UARTLITE_CONSOLE) += uartlite_tty.o
LIBS := $(common)/lib.a $(bootlib)/lib.a
ifeq ($(CONFIG_PPC_PREP),y)
diff --git a/arch/ppc/boot/simple/uartlite_tty.c b/arch/ppc/boot/simple/uartlite_tty.c
new file mode 100644
index 00000000000..0eae1eab38d
--- /dev/null
+++ b/arch/ppc/boot/simple/uartlite_tty.c
@@ -0,0 +1,37 @@
+/*
+ * Xilinx UARTLITE bootloader driver
+ *
+ * Copyright (c) 2007 Secret Lab Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+
+#define UARTLITE_BASEADDR ((void*)(XPAR_UARTLITE_0_BASEADDR))
+
+void
+serial_putc(unsigned long com_port, unsigned char c)
+{
+ while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x08) != 0); /* spin */
+ out_be32(UARTLITE_BASEADDR + 0x4, c);
+}
+
+unsigned char
+serial_getc(unsigned long com_port)
+{
+ while ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) == 0); /* spin */
+ return in_be32(UARTLITE_BASEADDR);
+}
+
+int
+serial_tstc(unsigned long com_port)
+{
+ return ((in_be32(UARTLITE_BASEADDR + 0x8) & 0x01) != 0);
+}
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index 1f91eca2f3d..e8e94321b59 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -35,12 +35,11 @@ int
main(void)
{
DEFINE(THREAD, offsetof(struct task_struct, thread));
- DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info));
+ DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
DEFINE(MM, offsetof(struct task_struct, mm));
DEFINE(PTRACE, offsetof(struct task_struct, ptrace));
DEFINE(KSP, offsetof(struct thread_struct, ksp));
DEFINE(PGDIR, offsetof(struct thread_struct, pgdir));
- DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index a9d455369dc..ab64256110b 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -191,7 +191,6 @@ stack_ovf:
0:
_GLOBAL(DoSyscall)
- stw r0,THREAD+LAST_SYSCALL(r2)
stw r3,ORIG_GPR3(r1)
li r12,0
stw r12,RESULT(r1)
diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
index 0a7e42d54ea..aa07b63c0a6 100644
--- a/arch/ppc/kernel/ppc_htab.c
+++ b/arch/ppc/kernel/ppc_htab.c
@@ -18,7 +18,6 @@
#include <linux/capability.h>
#include <linux/ctype.h>
#include <linux/threads.h>
-#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/bitops.h>
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index 96a55972b98..055998575cb 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
index a0625562a44..44cd128fb71 100644
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -130,7 +130,7 @@ SECTIONS
__ftr_fixup : { *(__ftr_fixup) }
__stop___ftr_fixup = .;
- . = ALIGN(32);
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/ppc/platforms/4xx/Kconfig b/arch/ppc/platforms/4xx/Kconfig
index 705ae56016f..76551b67903 100644
--- a/arch/ppc/platforms/4xx/Kconfig
+++ b/arch/ppc/platforms/4xx/Kconfig
@@ -29,6 +29,7 @@ config CPCI405
config EP405
bool "EP405/EP405PC"
+ select EMBEDDEDBOOT
help
This option enables support for the EP405/EP405PC boards.
@@ -54,11 +55,15 @@ config WALNUT
config XILINX_ML300
bool "Xilinx-ML300"
+ select XILINX_VIRTEX_II_PRO
+ select EMBEDDEDBOOT
help
This option enables support for the Xilinx ML300 evaluation board.
config XILINX_ML403
bool "Xilinx-ML403"
+ select XILINX_VIRTEX_4_FX
+ select EMBEDDEDBOOT
help
This option enables support for the Xilinx ML403 evaluation board.
endchoice
@@ -215,18 +220,14 @@ config 405GPR
config XILINX_VIRTEX_II_PRO
bool
- depends on XILINX_ML300
- default y
+ select XILINX_VIRTEX
config XILINX_VIRTEX_4_FX
bool
- depends on XILINX_ML403
- default y
+ select XILINX_VIRTEX
config XILINX_VIRTEX
bool
- depends on XILINX_VIRTEX_II_PRO || XILINX_VIRTEX_4_FX
- default y
config STB03xxx
bool
@@ -235,8 +236,6 @@ config STB03xxx
config EMBEDDEDBOOT
bool
- depends on EP405 || XILINX_ML300 || XILINX_ML403
- default y
config IBM_OPENBIOS
bool
diff --git a/arch/ppc/platforms/4xx/Makefile b/arch/ppc/platforms/4xx/Makefile
index fa6610bccaf..723ad7985cc 100644
--- a/arch/ppc/platforms/4xx/Makefile
+++ b/arch/ppc/platforms/4xx/Makefile
@@ -28,5 +28,4 @@ obj-$(CONFIG_440SP) += ibm440sp.o
obj-$(CONFIG_440SPE) += ppc440spe.o
obj-$(CONFIG_405EP) += ibm405ep.o
obj-$(CONFIG_405GPR) += ibm405gpr.o
-obj-$(CONFIG_XILINX_VIRTEX) += virtex.o
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
index 84e999d9a7b..5e994e146ba 100644
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -178,7 +178,7 @@ ocotea_setup_pcix(void)
/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
- PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+ PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
eieio();
}
@@ -289,7 +289,7 @@ ocotea_setup_arch(void)
* from FPGA, because it can be changed by on-board switches
* --ebs
*/
- ibm440gx_get_clocks(&clocks, 33333333, 6 * 1843200);
+ ibm440gx_get_clocks(&clocks, 33300000, 6 * 1843200);
ocp_sys_info.opb_bus_freq = clocks.opb;
/* Setup TODC access */
diff --git a/arch/ppc/platforms/4xx/taishan.c b/arch/ppc/platforms/4xx/taishan.c
index bb0253eef45..5d9af8ddb15 100644
--- a/arch/ppc/platforms/4xx/taishan.c
+++ b/arch/ppc/platforms/4xx/taishan.c
@@ -235,7 +235,7 @@ taishan_setup_pcix(void)
/* Setup 2GB PCI->PLB inbound memory window at 0, enable MSIs */
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAH);
PCIX_WRITEL(0x00000000, PCIX0_PIM0LAL);
- PCIX_WRITEL(0xe0000007, PCIX0_PIM0SA);
+ PCIX_WRITEL(0x80000007, PCIX0_PIM0SA);
PCIX_WRITEL(0xffffffff, PCIX0_PIM0SAH);
iounmap(pcix_reg_base);
diff --git a/arch/ppc/platforms/4xx/virtex.c b/arch/ppc/platforms/4xx/virtex.c
deleted file mode 100644
index 133a8314719..00000000000
--- a/arch/ppc/platforms/4xx/virtex.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Virtex-II Pro & Virtex-4 FX common infrastructure
- *
- * Maintainer: Grant Likely <grant.likely@secretlab.ca>
- *
- * Copyright 2005 Secret Lab Technologies Ltd.
- * Copyright 2005 General Dynamics Canada Ltd.
- * Copyright 2005 Freescale Semiconductor Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/serial_8250.h>
-#include <asm/ppc_sys.h>
-#include <platforms/4xx/virtex.h>
-#include <platforms/4xx/xparameters/xparameters.h>
-
-#define XPAR_UART(num) { \
- .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \
- .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
- .iotype = UPIO_MEM, \
- .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
- .flags = UPF_BOOT_AUTOCONF, \
- .regshift = 2, \
- }
-
-struct plat_serial8250_port serial_platform_data[] = {
-#ifdef XPAR_UARTNS550_0_BASEADDR
- XPAR_UART(0),
-#endif
-#ifdef XPAR_UARTNS550_1_BASEADDR
- XPAR_UART(1),
-#endif
-#ifdef XPAR_UARTNS550_2_BASEADDR
- XPAR_UART(2),
-#endif
-#ifdef XPAR_UARTNS550_3_BASEADDR
- XPAR_UART(3),
-#endif
- { }, /* terminated by empty record */
-};
-
-struct platform_device ppc_sys_platform_devices[] = {
- [VIRTEX_UART] = {
- .name = "serial8250",
- .id = 0,
- .dev.platform_data = serial_platform_data,
- },
-};
-
diff --git a/arch/ppc/platforms/4xx/virtex.h b/arch/ppc/platforms/4xx/virtex.h
index c14325dfd7b..738280420be 100644
--- a/arch/ppc/platforms/4xx/virtex.h
+++ b/arch/ppc/platforms/4xx/virtex.h
@@ -1,35 +1,35 @@
/*
- * arch/ppc/platforms/4xx/virtex.h
+ * Basic Virtex platform defines, included by <asm/ibm4xx.h>
*
- * Include file that defines the Xilinx Virtex-II Pro processor
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
+ * 2002-2004 (c) MontaVista Software, Inc.
*
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc. 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.
+ * 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.
*/
#ifdef __KERNEL__
#ifndef __ASM_VIRTEX_H__
#define __ASM_VIRTEX_H__
-/* serial defines */
-
#include <asm/ibm405.h>
+#include <asm/ppcboot.h>
/* Ugly, ugly, ugly! BASE_BAUD defined here to keep 8250.c happy. */
#if !defined(BASE_BAUD)
#define BASE_BAUD (0) /* dummy value; not used */
#endif
-
-/* Device type enumeration for platform bus definitions */
+
#ifndef __ASSEMBLY__
-enum ppc_sys_devices {
- VIRTEX_UART, NUM_PPC_SYS_DEVS,
-};
-#endif
-
+extern const char* virtex_machine_name;
+#define PPC4xx_MACHINE_NAME (virtex_machine_name)
+#endif /* !__ASSEMBLY__ */
+
+/* We don't need anything mapped. Size of zero will accomplish that. */
+#define PPC4xx_ONB_IO_PADDR 0u
+#define PPC4xx_ONB_IO_VADDR 0u
+#define PPC4xx_ONB_IO_SIZE 0u
+
#endif /* __ASM_VIRTEX_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.c b/arch/ppc/platforms/4xx/xilinx_ml300.c
index fb5f0b5e13d..6e522fefc26 100644
--- a/arch/ppc/platforms/4xx/xilinx_ml300.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml300.c
@@ -18,9 +18,9 @@
#include <linux/serialP.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/ppc_sys.h>
#include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
#include <platforms/4xx/xparameters/xparameters.h>
/*
@@ -53,24 +53,9 @@
* ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
*/
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
- {
- /* Only one entry, always assume the same design */
- .ppc_sys_name = "Xilinx ML300 Reference Design",
- .mask = 0x00000000,
- .value = 0x00000000,
- .num_devices = 1,
- .device_list = (enum ppc_sys_devices[])
- {
- VIRTEX_UART,
- },
- },
-};
+const char* virtex_machine_name = "ML300 Reference Design";
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
static volatile unsigned *powerdown_base =
(volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
@@ -95,52 +80,14 @@ ml300_map_io(void)
#endif
}
-/* Early serial support functions */
-static void __init
-ml300_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
- struct uart_port serial_req;
-
- memset(&serial_req, 0, sizeof(serial_req));
- serial_req.mapbase = pdata->mapbase;
- serial_req.membase = pdata->membase;
- serial_req.irq = pdata->irq;
- serial_req.uartclk = pdata->uartclk;
- serial_req.regshift = pdata->regshift;
- serial_req.iotype = pdata->iotype;
- serial_req.flags = pdata->flags;
- gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml300_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
- struct plat_serial8250_port *pdata;
- int i = 0;
-
- pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
- while(pdata && pdata->flags)
- {
- pdata->membase = ioremap(pdata->mapbase, 0x100);
- ml300_early_serial_init(i, pdata);
- pdata++;
- i++;
- }
-#endif /* CONFIG_SERIAL_8250 */
-}
-
void __init
ml300_setup_arch(void)
{
- ml300_early_serial_map();
+ virtex_early_serial_map();
ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */
/* Identify the system */
- printk(KERN_INFO "Xilinx Virtex-II Pro port\n");
- printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
+ printk(KERN_INFO "Xilinx ML300 Reference System (Virtex-II Pro)\n");
}
/* Called after board_setup_irq from ppc4xx_init_IRQ(). */
@@ -156,8 +103,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
{
ppc4xx_init(r3, r4, r5, r6, r7);
- identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
ppc_md.setup_arch = ml300_setup_arch;
ppc_md.setup_io_mappings = ml300_map_io;
ppc_md.init_IRQ = ml300_init_irq;
@@ -167,7 +112,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#endif
#ifdef CONFIG_KGDB
- ppc_md.early_serial_map = ml300_early_serial_map;
+ ppc_md.early_serial_map = virtex_early_serial_map;
#endif
}
diff --git a/arch/ppc/platforms/4xx/xilinx_ml300.h b/arch/ppc/platforms/4xx/xilinx_ml300.h
deleted file mode 100644
index 3d57332ba82..00000000000
--- a/arch/ppc/platforms/4xx/xilinx_ml300.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Include file that defines the Xilinx ML300 evaluation board
- *
- * Author: MontaVista Software, Inc.
- * source@mvista.com
- *
- * 2002-2004 (c) MontaVista Software, Inc. 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.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML300_H__
-#define __ASM_XILINX_ML300_H__
-
-/* ML300 has a Xilinx Virtex-II Pro processor */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
- unsigned int bi_memsize; /* DRAM installed, in bytes */
- unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
- unsigned int bi_intfreq; /* Processor speed, in Hz */
- unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
- unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped. Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR 0u
-#define PPC4xx_ONB_IO_VADDR 0u
-#define PPC4xx_ONB_IO_SIZE 0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML300 Reference System"
-
-#endif /* __ASM_XILINX_ML300_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.c b/arch/ppc/platforms/4xx/xilinx_ml403.c
index cb3bf7a2bcb..bc3ace3762e 100644
--- a/arch/ppc/platforms/4xx/xilinx_ml403.c
+++ b/arch/ppc/platforms/4xx/xilinx_ml403.c
@@ -1,11 +1,9 @@
/*
- * arch/ppc/platforms/4xx/xilinx_ml403.c
- *
* Xilinx ML403 evaluation board initialization
*
* Author: Grant Likely <grant.likely@secretlab.ca>
*
- * 2005 (c) Secret Lab Technologies Ltd.
+ * 2005-2007 (c) Secret Lab Technologies Ltd.
* 2002-2004 (c) MontaVista Software, Inc.
*
* This file is licensed under the terms of the GNU General Public License
@@ -22,9 +20,9 @@
#include <linux/serialP.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/ppc_sys.h>
#include <syslib/gen550.h>
+#include <syslib/virtex_devices.h>
#include <platforms/4xx/xparameters/xparameters.h>
/*
@@ -57,24 +55,9 @@
* ppc4xx_pic_init arch/ppc/syslib/xilinx_pic.c
*/
-/* Board specifications structures */
-struct ppc_sys_spec *cur_ppc_sys_spec;
-struct ppc_sys_spec ppc_sys_specs[] = {
- {
- /* Only one entry, always assume the same design */
- .ppc_sys_name = "Xilinx ML403 Reference Design",
- .mask = 0x00000000,
- .value = 0x00000000,
- .num_devices = 1,
- .device_list = (enum ppc_sys_devices[])
- {
- VIRTEX_UART,
- },
- },
-};
+const char* virtex_machine_name = "ML403 Reference Design";
#if defined(XPAR_POWER_0_POWERDOWN_BASEADDR)
-
static volatile unsigned *powerdown_base =
(volatile unsigned *) XPAR_POWER_0_POWERDOWN_BASEADDR;
@@ -99,47 +82,10 @@ ml403_map_io(void)
#endif
}
-/* Early serial support functions */
-static void __init
-ml403_early_serial_init(int num, struct plat_serial8250_port *pdata)
-{
-#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
- struct uart_port serial_req;
-
- memset(&serial_req, 0, sizeof(serial_req));
- serial_req.mapbase = pdata->mapbase;
- serial_req.membase = pdata->membase;
- serial_req.irq = pdata->irq;
- serial_req.uartclk = pdata->uartclk;
- serial_req.regshift = pdata->regshift;
- serial_req.iotype = pdata->iotype;
- serial_req.flags = pdata->flags;
- gen550_init(num, &serial_req);
-#endif
-}
-
-void __init
-ml403_early_serial_map(void)
-{
-#ifdef CONFIG_SERIAL_8250
- struct plat_serial8250_port *pdata;
- int i = 0;
-
- pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(VIRTEX_UART);
- while(pdata && pdata->flags)
- {
- pdata->membase = ioremap(pdata->mapbase, 0x100);
- ml403_early_serial_init(i, pdata);
- pdata++;
- i++;
- }
-#endif /* CONFIG_SERIAL_8250 */
-}
-
void __init
ml403_setup_arch(void)
{
- ml403_early_serial_map();
+ virtex_early_serial_map();
ppc4xx_setup_arch(); /* calls ppc4xx_find_bridges() */
/* Identify the system */
@@ -159,8 +105,6 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
{
ppc4xx_init(r3, r4, r5, r6, r7);
- identify_ppc_sys_by_id(mfspr(SPRN_PVR));
-
ppc_md.setup_arch = ml403_setup_arch;
ppc_md.setup_io_mappings = ml403_map_io;
ppc_md.init_IRQ = ml403_init_irq;
@@ -170,7 +114,7 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
#endif
#ifdef CONFIG_KGDB
- ppc_md.early_serial_map = ml403_early_serial_map;
+ ppc_md.early_serial_map = virtex_early_serial_map;
#endif
}
diff --git a/arch/ppc/platforms/4xx/xilinx_ml403.h b/arch/ppc/platforms/4xx/xilinx_ml403.h
deleted file mode 100644
index 47359695990..00000000000
--- a/arch/ppc/platforms/4xx/xilinx_ml403.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/ppc/platforms/4xx/xilinx_ml403.h
- *
- * Include file that defines the Xilinx ML403 reference design
- *
- * Author: Grant Likely <grant.likely@secretlab.ca>
- *
- * 2005 (c) Secret Lab Technologies Ltd.
- * 2002-2004 (c) MontaVista Software, Inc.
- *
- * 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.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_XILINX_ML403_H__
-#define __ASM_XILINX_ML403_H__
-
-/* ML403 has a Xilinx Virtex-4 FPGA with a PPC405 hard core */
-#include <platforms/4xx/virtex.h>
-
-#ifndef __ASSEMBLY__
-
-#include <linux/types.h>
-
-typedef struct board_info {
- unsigned int bi_memsize; /* DRAM installed, in bytes */
- unsigned char bi_enetaddr[6]; /* Local Ethernet MAC address */
- unsigned int bi_intfreq; /* Processor speed, in Hz */
- unsigned int bi_busfreq; /* PLB Bus speed, in Hz */
- unsigned int bi_pci_busfreq; /* PCI Bus speed, in Hz */
-} bd_t;
-
-/* Some 4xx parts use a different timebase frequency from the internal clock.
-*/
-#define bi_tbfreq bi_intfreq
-
-#endif /* !__ASSEMBLY__ */
-
-/* We don't need anything mapped. Size of zero will accomplish that. */
-#define PPC4xx_ONB_IO_PADDR 0u
-#define PPC4xx_ONB_IO_VADDR 0u
-#define PPC4xx_ONB_IO_SIZE 0u
-
-#define PPC4xx_MACHINE_NAME "Xilinx ML403 Reference Design"
-
-#endif /* __ASM_XILINX_ML403_H__ */
-#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h b/arch/ppc/platforms/4xx/xparameters/xparameters.h
index 66ec5f35f30..01aa043ff38 100644
--- a/arch/ppc/platforms/4xx/xparameters/xparameters.h
+++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h
@@ -34,3 +34,63 @@
.io_type = SERIAL_IO_MEM, \
},
#endif
+
+/*
+ * A few reasonable defaults for the #defines which could be missing depending
+ * on the IP version or variant (e.g. OPB vs PLB)
+ */
+
+#ifndef XPAR_EMAC_0_CAM_EXIST
+#define XPAR_EMAC_0_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_JUMBO_EXIST
+#define XPAR_EMAC_0_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_0_TX_DRE_TYPE
+#define XPAR_EMAC_0_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_RX_DRE_TYPE
+#define XPAR_EMAC_0_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_0_TX_INCLUDE_CSUM
+#define XPAR_EMAC_0_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_0_RX_INCLUDE_CSUM
+#define XPAR_EMAC_0_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_EMAC_1_CAM_EXIST
+#define XPAR_EMAC_1_CAM_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_JUMBO_EXIST
+#define XPAR_EMAC_1_JUMBO_EXIST 0
+#endif
+#ifndef XPAR_EMAC_1_TX_DRE_TYPE
+#define XPAR_EMAC_1_TX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_RX_DRE_TYPE
+#define XPAR_EMAC_1_RX_DRE_TYPE 0
+#endif
+#ifndef XPAR_EMAC_1_TX_INCLUDE_CSUM
+#define XPAR_EMAC_1_TX_INCLUDE_CSUM 0
+#endif
+#ifndef XPAR_EMAC_1_RX_INCLUDE_CSUM
+#define XPAR_EMAC_1_RX_INCLUDE_CSUM 0
+#endif
+
+#ifndef XPAR_GPIO_0_IS_DUAL
+#define XPAR_GPIO_0_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_1_IS_DUAL
+#define XPAR_GPIO_1_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_2_IS_DUAL
+#define XPAR_GPIO_2_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_3_IS_DUAL
+#define XPAR_GPIO_3_IS_DUAL 0
+#endif
+#ifndef XPAR_GPIO_4_IS_DUAL
+#define XPAR_GPIO_4_IS_DUAL 0
+#endif
+
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
index 7ce5364fdb3..bf72204125c 100644
--- a/arch/ppc/platforms/mpc866ads_setup.c
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc866ads-setup.c
+/*arch/ppc/platforms/mpc866ads_setup.c
*
* Platform setup for the Freescale mpc866ads board
*
diff --git a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h
index 57a2a55dab8..a3c1118e5b0 100644
--- a/arch/ppc/platforms/rpxclassic.h
+++ b/arch/ppc/platforms/rpxclassic.h
@@ -69,10 +69,6 @@ extern bd_t m8xx_board_info;
#define BCSR2_QSPACESEL ((uint)0x00004000)
#define BCSR2_FETHLEDMODE ((uint)0x00000800) /* CLLF */
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
/* define IO_BASE for pcmcia, CLLF only */
#if !defined(CONFIG_PCI)
#define _IO_BASE 0x80000000
diff --git a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h
deleted file mode 100644
index c3fa5a65376..00000000000
--- a/arch/ppc/platforms/rpxhiox.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * The Embedded Planet HIOX expansion card definitions.
- * There were a few different versions of these cards, but only
- * the one that escaped real production is defined here.
- *
- * Copyright (c) 2000 Dan Malek (dmalek@jlc.net)
- */
-#ifndef __MACH_RPX_HIOX_DEFS
-#define __MACH_RPX_HIOX_DEFS
-
-#define HIOX_CSR_ADDR ((uint)0xfac00000)
-#define HIOX_CSR_SIZE ((uint)(4 * 1024))
-#define HIOX_CSR0_ADDR HIOX_CSR_ADDR
-#define HIOX_CSR4_ADDR ((uint)0xfac00004)
-
-#define HIOX_CSR0_DEFAULT ((uint)0x380f3c00)
-#define HIOX_CSR0_ENSCC2 ((uint)0x80000000)
-#define HIOX_CSR0_ENSMC2 ((uint)0x04000000)
-#define HIOX_CSR0_ENVDOCLK ((uint)0x02000000)
-#define HIOX_CSR0_VDORST_HL ((uint)0x01000000)
-#define HIOX_CSR0_RS232SEL ((uint)0x0000c000)
-#define HIOX_CSR0_SCC3SEL ((uint)0x0000c000)
-#define HIOX_CSR0_SMC1SEL ((uint)0x00008000)
-#define HIOX_CSR0_SCC1SEL ((uint)0x00004000)
-#define HIOX_CSR0_ENTOUCH ((uint)0x00000080)
-#define HIOX_CSR0_PDOWN100 ((uint)0x00000060)
-#define HIOX_CSR0_PDOWN10 ((uint)0x00000040)
-#define HIOX_CSR0_PDOWN1 ((uint)0x00000020)
-#define HIOX_CSR0_TSELSPI ((uint)0x00000010)
-#define HIOX_CSR0_TIRQSTAT ((uint)0x00000008)
-#define HIOX_CSR4_DEFAULT ((uint)0x00000000)
-#define HIOX_CSR4_ENTIRQ2 ((uint)0x20000000)
-#define HIOX_CSR4_ENTIRQ3 ((uint)0x10000000)
-#define HIOX_CSR4_ENAUDIO ((uint)0x00000080)
-#define HIOX_CSR4_RSTAUDIO ((uint)0x00000040) /* 0 == reset */
-#define HIOX_CSR4_AUDCLKHI ((uint)0x00000020)
-#define HIOX_CSR4_AUDSPISEL ((uint)0x00000010)
-#define HIOX_CSR4_AUDIRQSTAT ((uint)0x00000008)
-#define HIOX_CSR4_AUDCLKSEL ((uint)0x00000007)
-
-#endif
diff --git a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h
index 71978064627..b615501d55f 100644
--- a/arch/ppc/platforms/rpxlite.h
+++ b/arch/ppc/platforms/rpxlite.h
@@ -57,10 +57,6 @@ extern bd_t m8xx_board_info;
#define BCSR1_PCVCTL6 ((uint)0x00020000)
#define BCSR1_PCVCTL7 ((uint)0x00010000)
-#if defined(CONFIG_HTDMSOUND)
-#include <platforms/rpxhiox.h>
-#endif
-
/* define IO_BASE for pcmcia */
#define _IO_BASE 0x80000000
#define _IO_BASE_SIZE 0x1000
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 09911118c67..95694159b22 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -18,7 +18,8 @@ obj-$(CONFIG_440SP) += ibm440gx_common.o ibm440sp_common.o
obj-$(CONFIG_440SPE) += ibm440gx_common.o ibm440sp_common.o ppc440spe_pcie.o
ifeq ($(CONFIG_4xx),y)
ifeq ($(CONFIG_XILINX_VIRTEX),y)
-obj-$(CONFIG_40x) += xilinx_pic.o ppc_sys.o
+obj-$(CONFIG_40x) += xilinx_pic.o
+obj-y += virtex_devices.o
else
ifeq ($(CONFIG_403),y)
obj-$(CONFIG_40x) += ppc403_pic.o
diff --git a/arch/ppc/syslib/cpc710.h b/arch/ppc/syslib/cpc710.h
deleted file mode 100644
index 5299bf8b5d0..00000000000
--- a/arch/ppc/syslib/cpc710.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Definitions for the IBM CPC710 PCI Host Bridge
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * 2001 (c) MontaVista, Software, Inc. 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.
- */
-
-#ifndef __PPC_PLATFORMS_CPC710_H
-#define __PPC_PLATFORMS_CPC710_H
-
-/* General bridge and memory controller registers */
-#define PIDR 0xff000008
-#define CNFR 0xff00000c
-#define RSTR 0xff000010
-#define UCTL 0xff001000
-#define MPSR 0xff001010
-#define SIOC 0xff001020
-#define ABCNTL 0xff001030
-#define SRST 0xff001040
-#define ERRC 0xff001050
-#define SESR 0xff001060
-#define SEAR 0xff001070
-#define SIOC1 0xff001090
-#define PGCHP 0xff001100
-#define GPDIR 0xff001130
-#define GPOUT 0xff001150
-#define ATAS 0xff001160
-#define AVDG 0xff001170
-#define MCCR 0xff001200
-#define MESR 0xff001220
-#define MEAR 0xff001230
-#define MCER0 0xff001300
-#define MCER1 0xff001310
-#define MCER2 0xff001320
-#define MCER3 0xff001330
-#define MCER4 0xff001340
-#define MCER5 0xff001350
-#define MCER6 0xff001360
-#define MCER7 0xff001370
-
-/*
- * PCI32/64 configuration registers
- * Given as offsets from their
- * respective physical segment BAR
- */
-#define PIBAR 0x000f7800
-#define PMBAR 0x000f7810
-#define MSIZE 0x000f7f40
-#define IOSIZE 0x000f7f60
-#define SMBAR 0x000f7f80
-#define SIBAR 0x000f7fc0
-#define PSSIZE 0x000f8100
-#define PPSIZE 0x000f8110
-#define BARPS 0x000f8120
-#define BARPP 0x000f8130
-#define PSBAR 0x000f8140
-#define PPBAR 0x000f8150
-#define BPMDLK 0x000f8200 /* Bottom of Peripheral Memory Space */
-#define TPMDLK 0x000f8210 /* Top of Peripheral Memory Space */
-#define BIODLK 0x000f8220 /* Bottom of Peripheral I/O Space */
-#define TIODLK 0x000f8230 /* Top of Perioheral I/O Space */
-#define DLKCTRL 0x000f8240 /* Deadlock control */
-#define DLKDEV 0x000f8250 /* Deadlock device */
-
-/* System standard configuration registers space */
-#define DCR 0xff200000
-#define DID 0xff200004
-#define BAR 0xff200018
-
-/* Device specific configuration space */
-#define PCIENB 0xff201000
-
-/* Configuration space registers */
-#define CPC710_BUS_NUMBER 0x40
-#define CPC710_SUB_BUS_NUMBER 0x41
-
-#endif /* __PPC_PLATFORMS_CPC710_H */
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
index 10659c24b1b..9192777d0f7 100644
--- a/arch/ppc/syslib/ipic.c
+++ b/arch/ppc/syslib/ipic.c
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/ipic.c
+ * arch/ppc/syslib/ipic.c
*
* IPIC routines implementations.
*
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 01e48d88f22..9caf850c9b3 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -413,7 +413,7 @@ m8xx_map_io(void)
io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
#endif
#endif
-#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
+#if defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
#endif
#ifdef CONFIG_FADS
diff --git a/arch/ppc/syslib/ppc4xx_sgdma.c b/arch/ppc/syslib/ppc4xx_sgdma.c
index 2f83e162971..c4b369b50f9 100644
--- a/arch/ppc/syslib/ppc4xx_sgdma.c
+++ b/arch/ppc/syslib/ppc4xx_sgdma.c
@@ -23,7 +23,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <asm/system.h>
#include <asm/io.h>
diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c
new file mode 100644
index 00000000000..16546788e23
--- /dev/null
+++ b/arch/ppc/syslib/virtex_devices.c
@@ -0,0 +1,233 @@
+/*
+ * Virtex hard ppc405 core common device listing
+ *
+ * Copyright 2005-2007 Secret Lab Technologies Ltd.
+ * Copyright 2005 Freescale Semiconductor Inc.
+ * Copyright 2002-2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_8250.h>
+#include <syslib/virtex_devices.h>
+#include <platforms/4xx/xparameters/xparameters.h>
+#include <asm/io.h>
+
+/*
+ * UARTLITE: shortcut macro for single instance
+ */
+#define XPAR_UARTLITE(num) { \
+ .name = "uartlite", \
+ .id = num, \
+ .num_resources = 2, \
+ .resource = (struct resource[]) { \
+ { \
+ .start = XPAR_UARTLITE_##num##_BASEADDR + 3, \
+ .end = XPAR_UARTLITE_##num##_HIGHADDR, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ { \
+ .start = XPAR_INTC_0_UARTLITE_##num##_VEC_ID, \
+ .flags = IORESOURCE_IRQ, \
+ }, \
+ }, \
+}
+
+/*
+ * Full UART: shortcut macro for single instance + platform data structure
+ */
+#define XPAR_UART(num) { \
+ .mapbase = XPAR_UARTNS550_##num##_BASEADDR + 3, \
+ .irq = XPAR_INTC_0_UARTNS550_##num##_VEC_ID, \
+ .iotype = UPIO_MEM, \
+ .uartclk = XPAR_UARTNS550_##num##_CLOCK_FREQ_HZ, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ .regshift = 2, \
+}
+
+/*
+ * SystemACE: shortcut macro for single instance
+ */
+#define XPAR_SYSACE(num) { \
+ .name = "xsysace", \
+ .id = XPAR_SYSACE_##num##_DEVICE_ID, \
+ .num_resources = 2, \
+ .resource = (struct resource[]) { \
+ { \
+ .start = XPAR_SYSACE_##num##_BASEADDR, \
+ .end = XPAR_SYSACE_##num##_HIGHADDR, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+ { \
+ .start = XPAR_INTC_0_SYSACE_##num##_VEC_ID, \
+ .flags = IORESOURCE_IRQ, \
+ }, \
+ }, \
+}
+
+
+/* UART 8250 driver platform data table */
+struct plat_serial8250_port virtex_serial_platform_data[] = {
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+ XPAR_UART(0),
+#endif
+#if defined(XPAR_UARTNS550_1_BASEADDR)
+ XPAR_UART(1),
+#endif
+#if defined(XPAR_UARTNS550_2_BASEADDR)
+ XPAR_UART(2),
+#endif
+#if defined(XPAR_UARTNS550_3_BASEADDR)
+ XPAR_UART(3),
+#endif
+#if defined(XPAR_UARTNS550_4_BASEADDR)
+ XPAR_UART(4),
+#endif
+#if defined(XPAR_UARTNS550_5_BASEADDR)
+ XPAR_UART(5),
+#endif
+#if defined(XPAR_UARTNS550_6_BASEADDR)
+ XPAR_UART(6),
+#endif
+#if defined(XPAR_UARTNS550_7_BASEADDR)
+ XPAR_UART(7),
+#endif
+ { }, /* terminated by empty record */
+};
+
+
+struct platform_device virtex_platform_devices[] = {
+ /* UARTLITE instances */
+#if defined(XPAR_UARTLITE_0_BASEADDR)
+ XPAR_UARTLITE(0),
+#endif
+#if defined(XPAR_UARTLITE_1_BASEADDR)
+ XPAR_UARTLITE(1),
+#endif
+#if defined(XPAR_UARTLITE_2_BASEADDR)
+ XPAR_UARTLITE(2),
+#endif
+#if defined(XPAR_UARTLITE_3_BASEADDR)
+ XPAR_UARTLITE(3),
+#endif
+#if defined(XPAR_UARTLITE_4_BASEADDR)
+ XPAR_UARTLITE(4),
+#endif
+#if defined(XPAR_UARTLITE_5_BASEADDR)
+ XPAR_UARTLITE(5),
+#endif
+#if defined(XPAR_UARTLITE_6_BASEADDR)
+ XPAR_UARTLITE(6),
+#endif
+#if defined(XPAR_UARTLITE_7_BASEADDR)
+ XPAR_UARTLITE(7),
+#endif
+
+ /* Full UART instances */
+#if defined(XPAR_UARTNS550_0_BASEADDR)
+ {
+ .name = "serial8250",
+ .id = 0,
+ .dev.platform_data = virtex_serial_platform_data,
+ },
+#endif
+
+ /* SystemACE instances */
+#if defined(XPAR_SYSACE_0_BASEADDR)
+ XPAR_SYSACE(0),
+#endif
+#if defined(XPAR_SYSACE_1_BASEADDR)
+ XPAR_SYSACE(1),
+#endif
+
+ /* ML300/403 reference design framebuffer */
+#if defined(XPAR_TFT_0_BASEADDR)
+ {
+ .name = "xilinxfb",
+ .id = 0,
+ .num_resources = 1,
+ .resource = (struct resource[]) {
+ {
+ .start = XPAR_TFT_0_BASEADDR,
+ .end = XPAR_TFT_0_BASEADDR+7,
+ .flags = IORESOURCE_IO,
+ },
+ },
+ },
+#endif
+};
+
+/* Early serial support functions */
+static void __init
+virtex_early_serial_init(int num, struct plat_serial8250_port *pdata)
+{
+#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
+ struct uart_port serial_req;
+
+ memset(&serial_req, 0, sizeof(serial_req));
+ serial_req.mapbase = pdata->mapbase;
+ serial_req.membase = pdata->membase;
+ serial_req.irq = pdata->irq;
+ serial_req.uartclk = pdata->uartclk;
+ serial_req.regshift = pdata->regshift;
+ serial_req.iotype = pdata->iotype;
+ serial_req.flags = pdata->flags;
+ gen550_init(num, &serial_req);
+#endif
+}
+
+void __init
+virtex_early_serial_map(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct plat_serial8250_port *pdata;
+ int i = 0;
+
+ pdata = virtex_serial_platform_data;
+ while(pdata && pdata->flags) {
+ pdata->membase = ioremap(pdata->mapbase, 0x100);
+ virtex_early_serial_init(i, pdata);
+ pdata++;
+ i++;
+ }
+#endif /* CONFIG_SERIAL_8250 */
+}
+
+/*
+ * default fixup routine; do nothing and return success.
+ *
+ * Reimplement this routine in your custom board support file to
+ * override the default behaviour
+ */
+int __attribute__ ((weak))
+virtex_device_fixup(struct platform_device *dev)
+{
+ return 0;
+}
+
+static int __init virtex_init(void)
+{
+ struct platform_device *index = virtex_platform_devices;
+ unsigned int ret = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(virtex_platform_devices); i++, index++) {
+ if (virtex_device_fixup(index) != 0)
+ continue;
+
+ if (platform_device_register(index)) {
+ ret = 1;
+ printk(KERN_ERR "cannot register dev %s:%d\n",
+ index->name, index->id);
+ }
+ }
+ return ret;
+}
+
+subsys_initcall(virtex_init);
diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
new file mode 100644
index 00000000000..3d4be1412f6
--- /dev/null
+++ b/arch/ppc/syslib/virtex_devices.h
@@ -0,0 +1,34 @@
+/*
+ * Common support header for virtex ppc405 platforms
+ *
+ * Copyright 2007 Secret Lab Technologies Ltd.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_VIRTEX_DEVICES_H__
+#define __ASM_VIRTEX_DEVICES_H__
+
+#include <linux/platform_device.h>
+
+/* ML300/403 reference design framebuffer driver platform data struct */
+struct xilinxfb_platform_data {
+ u32 rotate_screen;
+ u32 screen_height_mm;
+ u32 screen_width_mm;
+};
+
+void __init virtex_early_serial_map(void);
+
+/* Prototype for device fixup routine. Implement this routine in the
+ * board specific fixup code and the generic setup code will call it for
+ * each device is the platform device list.
+ *
+ * If the hook returns a non-zero value, then the device will not get
+ * registered with the platform bus
+ */
+int virtex_device_fixup(struct platform_device *dev);
+
+#endif /* __ASM_VIRTEX_DEVICES_H__ */
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index e6ec418093e..1a84719be26 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -49,6 +49,9 @@ config GENERIC_BUG
config NO_IOMEM
def_bool y
+config NO_DMA
+ def_bool y
+
mainmenu "Linux Kernel Configuration"
config S390
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index ee89b33145d..81a2b92ab0c 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -567,9 +567,11 @@ appldata_cpu_notify(struct notifier_block *self,
{
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
appldata_online_cpu((long) hcpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
appldata_offline_cpu((long) hcpu);
break;
default:
diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c
index 516b3ac9a9b..2180ac105b0 100644
--- a/arch/s390/appldata/appldata_net_sum.c
+++ b/arch/s390/appldata/appldata_net_sum.c
@@ -107,11 +107,8 @@ static void appldata_get_net_sum_data(void *data)
tx_dropped = 0;
collisions = 0;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
stats = dev->get_stats(dev);
- if (stats == NULL) {
- continue;
- }
rx_packets += stats->rx_packets;
tx_packets += stats->tx_packets;
rx_bytes += stats->rx_bytes;
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
index 99ff9f08e4d..d1defbbfcd8 100644
--- a/arch/s390/crypto/Kconfig
+++ b/arch/s390/crypto/Kconfig
@@ -54,7 +54,7 @@ config S390_PRNG
default "m"
help
Select this option if you want to use the s390 pseudo random number
- generator. The PRNG is part of the cryptograhic processor functions
+ generator. The PRNG is part of the cryptographic processor functions
and uses triple-DES to generate secure random numbers like the
ANSI X9.17 standard. The PRNG is usable via the char device
/dev/prandom.
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 91636353f6f..3660ca6a330 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -119,7 +119,8 @@ static struct crypto_alg aes_alg = {
.cra_name = "aes",
.cra_driver_name = "aes-s390",
.cra_priority = CRYPT_S390_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct s390_aes_ctx),
.cra_module = THIS_MODULE,
@@ -206,7 +207,8 @@ static struct crypto_alg ecb_aes_alg = {
.cra_name = "ecb(aes)",
.cra_driver_name = "ecb-aes-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct s390_aes_ctx),
.cra_type = &crypto_blkcipher_type,
@@ -300,7 +302,8 @@ static struct crypto_alg cbc_aes_alg = {
.cra_name = "cbc(aes)",
.cra_driver_name = "cbc-aes-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct s390_aes_ctx),
.cra_type = &crypto_blkcipher_type,
@@ -333,10 +336,14 @@ static int __init aes_init(void)
return -EOPNOTSUPP;
/* z9 109 and z9 BC/EC only support 128 bit key length */
- if (keylen_flag == AES_KEYLEN_128)
+ if (keylen_flag == AES_KEYLEN_128) {
+ aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE;
+ ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
+ cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE;
printk(KERN_INFO
"aes_s390: hardware acceleration only available for"
"128 bit keys\n");
+ }
ret = crypto_register_alg(&aes_alg);
if (ret)
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index ec514fe5ccd..1375f8a4469 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -15,7 +15,7 @@
int main(void)
{
- DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
+ DEFINE(__THREAD_info, offsetof(struct task_struct, stack),);
DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
DEFINE(__THREAD_mm_segment,
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index 80a54a0149a..a5692c460ba 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index dabaf98943d..a057ebf108a 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -23,6 +23,7 @@
#include <linux/kallsyms.h>
#include <linux/reboot.h>
#include <linux/kprobes.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -33,7 +34,6 @@
#include <asm/s390_ext.h>
#include <asm/lowcore.h>
#include <asm/debug.h>
-#include <asm/kdebug.h>
#ifndef CONFIG_64BIT
#define ONELONG "%08lx: "
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 06833ac2b11..0ea048d350d 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -164,7 +164,7 @@ EXPORT_SYMBOL_GPL(diag308);
/* SYSFS */
#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
-static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
+static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \
char *page) \
{ \
return sprintf(page, _format, _value); \
@@ -173,13 +173,13 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
__ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL);
#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \
-static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
+static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \
char *page) \
{ \
return sprintf(page, _fmt_out, \
(unsigned long long) _value); \
} \
-static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \
const char *buf, size_t len) \
{ \
unsigned long long value; \
@@ -194,12 +194,12 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
sys_##_prefix##_##_name##_store);
#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
-static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
+static ssize_t sys_##_prefix##_##_name##_show(struct kset *kset, \
char *page) \
{ \
return sprintf(page, _fmt_out, _value); \
} \
-static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+static ssize_t sys_##_prefix##_##_name##_store(struct kset *kset, \
const char *buf, size_t len) \
{ \
if (sscanf(buf, _fmt_in, _value) != 1) \
@@ -272,14 +272,14 @@ void __init setup_ipl_info(void)
struct ipl_info ipl_info;
EXPORT_SYMBOL_GPL(ipl_info);
-static ssize_t ipl_type_show(struct subsystem *subsys, char *page)
+static ssize_t ipl_type_show(struct kset *kset, char *page)
{
return sprintf(page, "%s\n", ipl_type_str(ipl_info.type));
}
static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type);
-static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page)
+static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
{
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
@@ -371,7 +371,7 @@ static struct attribute_group ipl_fcp_attr_group = {
/* CCW ipl device attributes */
-static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
+static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page)
{
char loadparm[LOADPARM_LEN + 1] = {};
@@ -469,7 +469,7 @@ static void reipl_get_ascii_loadparm(char *loadparm)
strstrip(loadparm);
}
-static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
+static ssize_t reipl_ccw_loadparm_show(struct kset *kset, char *page)
{
char buf[LOADPARM_LEN + 1];
@@ -477,7 +477,7 @@ static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page)
return sprintf(page, "%s\n", buf);
}
-static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys,
+static ssize_t reipl_ccw_loadparm_store(struct kset *kset,
const char *buf, size_t len)
{
int i, lp_len;
@@ -572,12 +572,12 @@ static int reipl_set_type(enum ipl_type type)
return 0;
}
-static ssize_t reipl_type_show(struct subsystem *subsys, char *page)
+static ssize_t reipl_type_show(struct kset *kset, char *page)
{
return sprintf(page, "%s\n", ipl_type_str(reipl_type));
}
-static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
+static ssize_t reipl_type_store(struct kset *kset, const char *buf,
size_t len)
{
int rc = -EINVAL;
@@ -665,12 +665,12 @@ static int dump_set_type(enum dump_type type)
return 0;
}
-static ssize_t dump_type_show(struct subsystem *subsys, char *page)
+static ssize_t dump_type_show(struct kset *kset, char *page)
{
return sprintf(page, "%s\n", dump_type_str(dump_type));
}
-static ssize_t dump_type_store(struct subsystem *subsys, const char *buf,
+static ssize_t dump_type_store(struct kset *kset, const char *buf,
size_t len)
{
int rc = -EINVAL;
@@ -697,12 +697,12 @@ static decl_subsys(shutdown_actions, NULL, NULL);
/* on panic */
-static ssize_t on_panic_show(struct subsystem *subsys, char *page)
+static ssize_t on_panic_show(struct kset *kset, char *page)
{
return sprintf(page, "%s\n", shutdown_action_str(on_panic_action));
}
-static ssize_t on_panic_store(struct subsystem *subsys, const char *buf,
+static ssize_t on_panic_store(struct kset *kset, const char *buf,
size_t len)
{
if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0)
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 993f3538149..e39333ae0fc 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -24,8 +24,8 @@
#include <linux/ptrace.h>
#include <linux/preempt.h>
#include <linux/stop_machine.h>
+#include <linux/kdebug.h>
#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
#include <asm/sections.h>
#include <asm/uaccess.h>
#include <linux/module.h>
@@ -271,23 +271,13 @@ static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
}
/* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
- struct kretprobe_instance *ri;
+ ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14];
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
- ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14];
-
- /* Replace the return addr with trampoline addr */
- regs->gprs[14] = (unsigned long)&kretprobe_trampoline;
-
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ /* Replace the return addr with trampoline addr */
+ regs->gprs[14] = (unsigned long)&kretprobe_trampoline;
}
static int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -516,7 +506,7 @@ out:
return 1;
}
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -603,7 +593,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
ret = NOTIFY_STOP;
break;
case DIE_TRAP:
- case DIE_PAGE_FAULT:
/* kprobe_running() needs smp_processor_id() */
preempt_disable();
if (kprobe_running() &&
@@ -672,3 +661,10 @@ int __init arch_init_kprobes(void)
{
return register_kprobe(&trampoline_p);
}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr == (kprobe_opcode_t *) & kretprobe_trampoline)
+ return 1;
+ return 0;
+}
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 11d9b019762..eb43c3b3126 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 3dfd0985861..6bfb0889eb1 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -65,7 +65,7 @@ long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
* User copy operations.
*/
struct uaccess_ops uaccess;
-EXPORT_SYMBOL_GPL(uaccess);
+EXPORT_SYMBOL(uaccess);
/*
* Machine setup..
@@ -74,6 +74,8 @@ unsigned int console_mode = 0;
unsigned int console_devno = -1;
unsigned int console_irq = -1;
unsigned long machine_flags = 0;
+unsigned long elf_hwcap = 0;
+char elf_platform[ELF_PLATFORM_SIZE];
struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
@@ -749,6 +751,98 @@ setup_memory(void)
#endif
}
+static __init unsigned int stfl(void)
+{
+ asm volatile(
+ " .insn s,0xb2b10000,0(0)\n" /* stfl */
+ "0:\n"
+ EX_TABLE(0b,0b));
+ return S390_lowcore.stfl_fac_list;
+}
+
+static __init int stfle(unsigned long long *list, int doublewords)
+{
+ typedef struct { unsigned long long _[doublewords]; } addrtype;
+ register unsigned long __nr asm("0") = doublewords - 1;
+
+ asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+ : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
+ return __nr + 1;
+}
+
+/*
+ * Setup hardware capabilities.
+ */
+static void __init setup_hwcaps(void)
+{
+ static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
+ struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+ unsigned long long facility_list_extended;
+ unsigned int facility_list;
+ int i;
+
+ facility_list = stfl();
+ /*
+ * The store facility list bits numbers as found in the principles
+ * of operation are numbered with bit 1UL<<31 as number 0 to
+ * bit 1UL<<0 as number 31.
+ * Bit 0: instructions named N3, "backported" to esa-mode
+ * Bit 2: z/Architecture mode is active
+ * Bit 7: the store-facility-list-extended facility is installed
+ * Bit 17: the message-security assist is installed
+ * Bit 19: the long-displacement facility is installed
+ * Bit 21: the extended-immediate facility is installed
+ * These get translated to:
+ * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1,
+ * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3,
+ * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5.
+ */
+ for (i = 0; i < 6; i++)
+ if (facility_list & (1UL << (31 - stfl_bits[i])))
+ elf_hwcap |= 1UL << i;
+
+ /*
+ * Check for additional facilities with store-facility-list-extended.
+ * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0
+ * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information
+ * as stored by stfl, bits 32-xxx contain additional facilities.
+ * How many facility words are stored depends on the number of
+ * doublewords passed to the instruction. The additional facilites
+ * are:
+ * Bit 43: decimal floating point facility is installed
+ * translated to:
+ * HWCAP_S390_DFP bit 6.
+ */
+ if ((elf_hwcap & (1UL << 2)) &&
+ stfle(&facility_list_extended, 1) > 0) {
+ if (facility_list_extended & (1ULL << (64 - 43)))
+ elf_hwcap |= 1UL << 6;
+ }
+
+ switch (cpuinfo->cpu_id.machine) {
+ case 0x9672:
+#if !defined(CONFIG_64BIT)
+ default: /* Use "g5" as default for 31 bit kernels. */
+#endif
+ strcpy(elf_platform, "g5");
+ break;
+ case 0x2064:
+ case 0x2066:
+#if defined(CONFIG_64BIT)
+ default: /* Use "z900" as default for 64 bit kernels. */
+#endif
+ strcpy(elf_platform, "z900");
+ break;
+ case 0x2084:
+ case 0x2086:
+ strcpy(elf_platform, "z990");
+ break;
+ case 0x2094:
+ strcpy(elf_platform, "z9-109");
+ break;
+ }
+}
+
/*
* Setup function called from init/main.c just after the banner
* was printed.
@@ -805,6 +899,11 @@ setup_arch(char **cmdline_p)
smp_setup_cpu_possible_map();
/*
+ * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
+ */
+ setup_hwcaps();
+
+ /*
* Create kernel page tables and switch to virtual addressing.
*/
paging_init();
@@ -839,8 +938,12 @@ void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
static int show_cpuinfo(struct seq_file *m, void *v)
{
+ static const char *hwcap_str[7] = {
+ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp"
+ };
struct cpuinfo_S390 *cpuinfo;
unsigned long n = (unsigned long) v - 1;
+ int i;
s390_adjust_jiffies();
preempt_disable();
@@ -850,7 +953,13 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"bogomips per cpu: %lu.%02lu\n",
num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100);
+ seq_puts(m, "features\t: ");
+ for (i = 0; i < 7; i++)
+ if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
+ seq_printf(m, "%s ", hwcap_str[i]);
+ seq_puts(m, "\n");
}
+
if (cpu_online(n)) {
#ifdef CONFIG_SMP
if (smp_processor_id() == n)
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 3c41907799a..d264671c1b7 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -14,7 +14,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 3754e2031b3..09f028a3266 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -25,7 +25,6 @@
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
@@ -790,10 +789,12 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
if (sysdev_create_file(s, &attr_capability))
return NOTIFY_BAD;
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
sysdev_remove_file(s, &attr_capability);
break;
}
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index 2e5c65a1863..515ff9011dd 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -59,7 +59,7 @@ static unsigned long save_context_stack(struct stack_trace *trace,
}
}
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
{
register unsigned long sp asm ("15");
unsigned long orig_sp, new_sp;
@@ -69,20 +69,16 @@ void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
new_sp = save_context_stack(trace, &trace->skip, orig_sp,
S390_lowcore.panic_stack - PAGE_SIZE,
S390_lowcore.panic_stack);
- if ((new_sp != orig_sp) && !trace->all_contexts)
+ if (new_sp != orig_sp)
return;
new_sp = save_context_stack(trace, &trace->skip, new_sp,
S390_lowcore.async_stack - ASYNC_SIZE,
S390_lowcore.async_stack);
- if ((new_sp != orig_sp) && !trace->all_contexts)
+ if (new_sp != orig_sp)
return;
- if (task)
- save_context_stack(trace, &trace->skip, new_sp,
- (unsigned long) task_stack_page(task),
- (unsigned long) task_stack_page(task) + THREAD_SIZE);
- else
- save_context_stack(trace, &trace->skip, new_sp,
- S390_lowcore.thread_info,
- S390_lowcore.thread_info + THREAD_SIZE);
+
+ save_context_stack(trace, &trace->skip, new_sp,
+ S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE);
return;
}
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index 3a77c22cda7..1c90c7e9997 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -17,7 +17,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 711dae8da7a..9c2872a7cca 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -21,6 +21,7 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/time.h>
+#include <linux/sysdev.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/smp.h>
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 49dec830373..cbfe73034c3 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -22,11 +22,11 @@
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/kdebug.h>
#include <linux/kallsyms.h>
#include <linux/reboot.h>
#include <linux/kprobes.h>
@@ -40,7 +40,6 @@
#include <asm/s390_ext.h>
#include <asm/lowcore.h>
#include <asm/debug.h>
-#include <asm/kdebug.h>
/* Called from entry.S only */
extern void handle_per_exception(struct pt_regs *regs);
@@ -70,20 +69,6 @@ static int kstack_depth_to_print = 12;
static int kstack_depth_to_print = 20;
#endif /* CONFIG_64BIT */
-ATOMIC_NOTIFIER_HEAD(s390die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&s390die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&s390die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
-
/*
* For show_trace we have tree different stack to consider:
* - the panic stack which is used if the kernel stack has overflown
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 418f6426a94..e9d3432aba6 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -107,7 +107,7 @@ SECTIONS
. = ALIGN(2);
__initramfs_end = .;
#endif
- . = ALIGN(256);
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 2b76a879a7b..8b924b35977 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -20,6 +20,7 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
+#include <linux/kdebug.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -30,7 +31,6 @@
#include <asm/system.h>
#include <asm/pgtable.h>
-#include <asm/kdebug.h>
#include <asm/s390_ext.h>
#ifndef CONFIG_64BIT
@@ -52,38 +52,24 @@ extern int sysctl_userprocess_debug;
extern void die(const char *,struct pt_regs *,long);
#ifdef CONFIG_KPROBES
-static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-int register_page_fault_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
-
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
-
-static int __kprobes __notify_page_fault(struct pt_regs *regs, long err)
-{
- struct die_args args = { .str = "page fault",
- .trapnr = 14,
- .signr = SIGSEGV };
- args.regs = regs;
- args.err = err;
- return atomic_notifier_call_chain(&notify_page_fault_chain,
- DIE_PAGE_FAULT, &args);
-}
-
static inline int notify_page_fault(struct pt_regs *regs, long err)
{
- if (unlikely(kprobe_running()))
- return __notify_page_fault(regs, err);
- return NOTIFY_DONE;
+ int ret = 0;
+
+ /* kprobe_running() needs smp_processor_id() */
+ if (!user_mode(regs)) {
+ preempt_disable();
+ if (kprobe_running() && kprobe_fault_handler(regs, 14))
+ ret = 1;
+ preempt_enable();
+ }
+
+ return ret;
}
#else
static inline int notify_page_fault(struct pt_regs *regs, long err)
{
- return NOTIFY_DONE;
+ return 0;
}
#endif
@@ -319,7 +305,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
int space;
int si_code;
- if (notify_page_fault(regs, error_code) == NOTIFY_STOP)
+ if (notify_page_fault(regs, error_code))
return;
tsk = current;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 4d16d891707..038179ecf6a 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -22,6 +22,10 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+
config GENERIC_FIND_NEXT_BIT
bool
default y
@@ -48,6 +52,9 @@ config GENERIC_IOMAP
config GENERIC_TIME
def_bool n
+config GENERIC_CLOCKEVENTS
+ def_bool n
+
config SYS_SUPPORTS_APM_EMULATION
bool
@@ -88,6 +95,14 @@ config SH_SOLUTION_ENGINE
Select SolutionEngine if configuring for a Hitachi SH7709
or SH7750 evaluation board.
+config SH_7722_SOLUTION_ENGINE
+ bool "SolutionEngine7722"
+ select SOLUTION_ENGINE
+ select CPU_SUBTYPE_SH7722
+ help
+ Select 7722 SolutionEngine if configuring for a Hitachi SH772
+ evaluation board.
+
config SH_7751_SOLUTION_ENGINE
bool "SolutionEngine7751"
select SOLUTION_ENGINE
@@ -95,6 +110,14 @@ config SH_7751_SOLUTION_ENGINE
help
Select 7751 SolutionEngine if configuring for a Hitachi SH7751
evaluation board.
+
+config SH_7780_SOLUTION_ENGINE
+ bool "SolutionEngine7780"
+ select SOLUTION_ENGINE
+ select CPU_SUBTYPE_SH7780
+ help
+ Select 7780 SolutionEngine if configuring for a Renesas SH7780
+ evaluation board.
config SH_7300_SOLUTION_ENGINE
bool "SolutionEngine7300"
@@ -193,12 +216,8 @@ config SH_RTS7751R2D
Select RTS7751R2D if configuring for a Renesas Technology
Sales SH-Graphics board.
-config SH_R7780RP
- bool "R7780RP-1"
- select CPU_SUBTYPE_SH7780
- help
- Select R7780RP-1 if configuring for a Renesas Solutions
- HIGHLANDER board.
+config SH_HIGHLANDER
+ bool "Highlander"
config SH_EDOSK7705
bool "EDOSK7705"
@@ -243,6 +262,12 @@ config SH_7619_SOLUTION_ENGINE
help
Select 7619 SolutionEngine if configuring for a Hitachi SH7619
evaluation board.
+
+config SH_LBOX_RE2
+ bool "L-BOX RE2"
+ select CPU_SUBTYPE_SH7751R
+ help
+ Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2.
config SH_UNKNOWN
bool "BareCPU"
@@ -258,6 +283,10 @@ config SH_UNKNOWN
endchoice
+source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
+source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
+source "arch/sh/boards/renesas/r7780rp/Kconfig"
+
source "arch/sh/mm/Kconfig"
config CF_ENABLER
@@ -366,6 +395,16 @@ config SH_STORE_QUEUES
Selecting this option will enable an in-kernel API for manipulating
the store queues integrated in the SH-4 processors.
+config SPECULATIVE_EXECUTION
+ bool "Speculative subroutine return"
+ depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
+ help
+ This enables support for a speculative instruction fetch for
+ subroutine return. There are various pitfalls associated with
+ this, as outlined in the SH7780 hardware manual.
+
+ If unsure, say N.
+
config CPU_HAS_INTEVT
bool
@@ -398,12 +437,13 @@ config CPU_HAS_PTEA
endmenu
-menu "Timer support"
-depends on !GENERIC_TIME
+menu "Timer and clock configuration"
config SH_TMU
bool "TMU timer support"
depends on CPU_SH3 || CPU_SH4
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
default y
help
This enables the use of the TMU as the system timer.
@@ -422,39 +462,13 @@ config SH_MTU2
help
This enables the use of the MTU2 as the system timer.
-endmenu
-
-source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
-
-source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
-
-source "arch/sh/boards/renesas/r7780rp/Kconfig"
-
config SH_TIMER_IRQ
int
- default "28" if CPU_SUBTYPE_SH7780
+ default "28" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
default "86" if CPU_SUBTYPE_SH7619
default "140" if CPU_SUBTYPE_SH7206
default "16"
-config NO_IDLE_HZ
- bool "Dynamic tick timer"
- help
- Select this option if you want to disable continuous timer ticks
- and have them programmed to occur as required. This option saves
- power as the system can remain in idle state for longer.
-
- By default dynamic tick is disabled during the boot, and can be
- manually enabled with:
-
- echo 1 > /sys/devices/system/timer/timer0/dyn_tick
-
- Alternatively, if you want dynamic tick automatically enabled
- during boot, pass "dyntick=enable" via the kernel command string.
-
- Please note that dynamic tick may affect the accuracy of
- timekeeping on some platforms depending on the implementation.
-
config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)"
default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
@@ -462,7 +476,8 @@ config SH_PCLK_FREQ
default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
CPU_SUBTYPE_SH7206
- default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
+ default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 || \
+ CPU_SUBTYPE_SH7785
default "60000000" if CPU_SUBTYPE_SH7751
default "66000000" if CPU_SUBTYPE_SH4_202
help
@@ -477,6 +492,10 @@ config SH_CLK_MD
help
MD2 - MD0 pin setting.
+source "kernel/time/Kconfig"
+
+endmenu
+
menu "CPU Frequency scaling"
source "drivers/cpufreq/Kconfig"
@@ -495,21 +514,6 @@ config SH_CPU_FREQ
endmenu
-source "arch/sh/drivers/dma/Kconfig"
-
-source "arch/sh/cchips/Kconfig"
-
-config HEARTBEAT
- bool "Heartbeat LED"
- depends on SH_MPC1211 || SH_SH03 || \
- SOLUTION_ENGINE || \
- SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK || \
- SH_R7780RP
- help
- Use the power-on LED on your machine as a load meter. The exact
- behavior is platform-dependent, but normally the flash frequency is
- a hyperbolic function of the 5-minute load average.
-
source "arch/sh/drivers/Kconfig"
endmenu
@@ -540,6 +544,20 @@ config KEXEC
support. As of this writing the exact hardware interface is
strongly in flux, so no good recommendation can be made.
+config CRASH_DUMP
+ bool "kernel crash dumps (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ Generate crash dump after being started by kexec.
+ This should be normally only set in special crash dump kernels
+ which are loaded in the main kernel with kexec-tools into
+ a specially reserved region and then later executed after
+ a crash by kdump/kexec. The crash dump kernel must be compiled
+ to a memory address not used by the main kernel using
+ MEMORY_START.
+
+ For more details see Documentation/kdump/kdump.txt
+
config SMP
bool "Symmetric multi-processing support"
---help---
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 87902e0298e..b56307294b6 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -33,6 +33,7 @@ config EARLY_SCIF_CONSOLE_PORT
default "0xffe00000" if CPU_SUBTYPE_SH7780
default "0xfffe9800" if CPU_SUBTYPE_SH7206
default "0xf8420000" if CPU_SUBTYPE_SH7619
+ default "0xa4400000" if CPU_SUBTYPE_SH7712 || CPU_SUBTYPE_SH7705
default "0xffe80000" if CPU_SH4
config EARLY_PRINTK
@@ -77,16 +78,17 @@ config 4KSTACKS
on the VM subsystem for higher order allocations. This option
will also use IRQ stacks to compensate for the reduced stackspace.
-config KGDB
+config SH_KGDB
bool "Include KGDB kernel debugger"
select FRAME_POINTER
+ select DEBUG_INFO
help
Include in-kernel hooks for kgdb, the Linux kernel source level
debugger. See <http://kgdb.sourceforge.net/> for more information.
Unless you are intending to debug the kernel, say N here.
menu "KGDB configuration options"
- depends on KGDB
+ depends on SH_KGDB
config MORE_COMPILE_OPTIONS
bool "Add any additional compile options"
@@ -103,22 +105,16 @@ config KGDB_NMI
bool "Enter KGDB on NMI"
default n
-config KGDB_THREAD
- bool "Include KGDB thread support"
- default y
-
config SH_KGDB_CONSOLE
bool "Console messages through GDB"
+ depends on !SERIAL_SH_SCI_CONSOLE
+ select SERIAL_CORE_CONSOLE
default n
config KGDB_SYSRQ
bool "Allow SysRq 'G' to enter KGDB"
default y
-config KGDB_KERNEL_ASSERTS
- bool "Include KGDB kernel assertions"
- default n
-
comment "Serial port setup"
config KGDB_DEFPORT
@@ -131,7 +127,7 @@ config KGDB_DEFBAUD
choice
prompt "Parity"
- depends on KGDB
+ depends on SH_KGDB
default KGDB_DEFPARITY_N
config KGDB_DEFPARITY_N
@@ -147,7 +143,7 @@ endchoice
choice
prompt "Data bits"
- depends on KGDB
+ depends on SH_KGDB
default KGDB_DEFBITS_8
config KGDB_DEFBITS_8
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index bd9b1729f8b..7b112241705 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -47,7 +47,6 @@ cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding
cflags-$(CONFIG_SH_DSP) += -Wa,-dsp
-cflags-$(CONFIG_SH_KGDB) += -g
cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \
$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
@@ -89,7 +88,9 @@ core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
# Boards
machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
+machdir-$(CONFIG_SH_7722_SOLUTION_ENGINE) := se/7722
machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751
+machdir-$(CONFIG_SH_7780_SOLUTION_ENGINE) := se/7780
machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se/7300
machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343
machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180
@@ -103,7 +104,7 @@ machdir-$(CONFIG_SH_HS7751RVOIP) := renesas/hs7751rvoip
machdir-$(CONFIG_SH_RTS7751R2D) := renesas/rts7751r2d
machdir-$(CONFIG_SH_7751_SYSTEMH) := renesas/systemh
machdir-$(CONFIG_SH_EDOSK7705) := renesas/edosk7705
-machdir-$(CONFIG_SH_R7780RP) := renesas/r7780rp
+machdir-$(CONFIG_SH_HIGHLANDER) := renesas/r7780rp
machdir-$(CONFIG_SH_7710VOIPGW) := renesas/sh7710voipgw
machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev
machdir-$(CONFIG_SH_LANDISK) := landisk
@@ -111,6 +112,7 @@ machdir-$(CONFIG_SH_TITAN) := titan
machdir-$(CONFIG_SH_SHMIN) := shmin
machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) := se/7206
machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) := se/7619
+machdir-$(CONFIG_SH_LBOX_RE2) := lboxre2
machdir-$(CONFIG_SH_UNKNOWN) := unknown
incdir-y := $(notdir $(machdir-y))
diff --git a/arch/sh/boards/hp6xx/Makefile b/arch/sh/boards/hp6xx/Makefile
index ff1b7f5b4e9..b3124278247 100644
--- a/arch/sh/boards/hp6xx/Makefile
+++ b/arch/sh/boards/hp6xx/Makefile
@@ -2,6 +2,6 @@
# Makefile for the HP6xx specific parts of the kernel
#
-obj-y := setup.o
+obj-y := setup.o
obj-$(CONFIG_PM) += pm.o pm_wakeup.o
-obj-$(CONFIG_APM) += hp6xx_apm.o
+obj-$(CONFIG_APM_EMULATION) += hp6xx_apm.o
diff --git a/arch/sh/boards/hp6xx/pm.c b/arch/sh/boards/hp6xx/pm.c
index d1947732fb3..8143d1b948e 100644
--- a/arch/sh/boards/hp6xx/pm.c
+++ b/arch/sh/boards/hp6xx/pm.c
@@ -27,9 +27,6 @@ static int hp6x0_pm_enter(suspend_state_t state)
u16 hd64461_stbcr;
#endif
- if (state != PM_SUSPEND_MEM)
- return -EINVAL;
-
#ifdef CONFIG_HD64461_ENABLER
outb(0, HD64461_PCC1CSCIER);
@@ -70,12 +67,9 @@ static int hp6x0_pm_enter(suspend_state_t state)
return 0;
}
-/*
- * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
- */
static struct pm_ops hp6x0_pm_ops = {
- .pm_disk_mode = PM_DISK_FIRMWARE,
.enter = hp6x0_pm_enter,
+ .valid = pm_valid_only_mem,
};
static int __init hp6x0_pm_init(void)
diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c
index b5a96649ed2..6aeee85c978 100644
--- a/arch/sh/boards/hp6xx/setup.c
+++ b/arch/sh/boards/hp6xx/setup.c
@@ -2,6 +2,7 @@
* linux/arch/sh/boards/hp6xx/setup.c
*
* Copyright (C) 2002 Andriy Skulysh
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer_e1@hotmail.com>
*
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
@@ -10,6 +11,7 @@
*/
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <asm/hd64461.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -19,6 +21,40 @@
#define SCPCR 0xa4000116
#define SCPDR 0xa4000136
+/* CF Slot */
+static struct resource cf_ide_resources[] = {
+ [0] = {
+ .start = 0x15000000 + 0x1f0,
+ .end = 0x15000000 + 0x1f0 + 0x08 - 0x01,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x15000000 + 0x1fe,
+ .end = 0x15000000 + 0x1fe + 0x01,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = 93,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cf_ide_device = {
+ .name = "pata_platform",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cf_ide_resources),
+ .resource = cf_ide_resources,
+};
+
+static struct platform_device *hp6xx_devices[] __initdata = {
+ &cf_ide_device,
+};
+
+static int __init hp6xx_devices_setup(void)
+{
+ return platform_add_devices(hp6xx_devices, ARRAY_SIZE(hp6xx_devices));
+}
+
static void __init hp6xx_setup(char **cmdline_p)
{
u8 v8;
@@ -60,41 +96,12 @@ static void __init hp6xx_setup(char **cmdline_p)
v |= SCPCR_TS_ENABLE;
ctrl_outw(v, SCPCR);
}
+device_initcall(hp6xx_devices_setup);
-/*
- * XXX: This is stupid, we should have a generic machine vector for the cchips
- * and just wrap the platform setup code in to this, as it's the only thing
- * that ends up being different.
- */
struct sh_machine_vector mv_hp6xx __initmv = {
.mv_name = "hp6xx",
.mv_setup = hp6xx_setup,
.mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
-
- .mv_inb = hd64461_inb,
- .mv_inw = hd64461_inw,
- .mv_inl = hd64461_inl,
- .mv_outb = hd64461_outb,
- .mv_outw = hd64461_outw,
- .mv_outl = hd64461_outl,
-
- .mv_inb_p = hd64461_inb_p,
- .mv_inw_p = hd64461_inw,
- .mv_inl_p = hd64461_inl,
- .mv_outb_p = hd64461_outb_p,
- .mv_outw_p = hd64461_outw,
- .mv_outl_p = hd64461_outl,
-
- .mv_insb = hd64461_insb,
- .mv_insw = hd64461_insw,
- .mv_insl = hd64461_insl,
- .mv_outsb = hd64461_outsb,
- .mv_outsw = hd64461_outsw,
- .mv_outsl = hd64461_outsl,
-
- .mv_readw = hd64461_readw,
- .mv_writew = hd64461_writew,
-
.mv_irq_demux = hd64461_irq_demux,
};
ALIAS_MV(hp6xx)
diff --git a/arch/sh/boards/landisk/Makefile b/arch/sh/boards/landisk/Makefile
index 89e4beb2ad4..a696b4277fa 100644
--- a/arch/sh/boards/landisk/Makefile
+++ b/arch/sh/boards/landisk/Makefile
@@ -2,4 +2,4 @@
# Makefile for I-O DATA DEVICE, INC. "LANDISK Series"
#
-obj-y := setup.o io.o irq.o rtc.o landisk_pwb.o
+obj-y := setup.o irq.o psw.o gio.o
diff --git a/arch/sh/boards/landisk/gio.c b/arch/sh/boards/landisk/gio.c
new file mode 100644
index 00000000000..50d38be62f0
--- /dev/null
+++ b/arch/sh/boards/landisk/gio.c
@@ -0,0 +1,167 @@
+/*
+ * arch/sh/boards/landisk/gio.c - driver for landisk
+ *
+ * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
+ * LANDISK and USL-5P Button, LED and GIO driver drive function.
+ *
+ * Copylight (C) 2006 kogiidena
+ * Copylight (C) 2002 Atom Create Engineering Co., Ltd. *
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/landisk/gio.h>
+#include <asm/landisk/iodata_landisk.h>
+
+#define DEVCOUNT 4
+#define GIO_MINOR 2 /* GIO minor no. */
+
+static dev_t dev;
+static struct cdev *cdev_p;
+static int openCnt;
+
+static int gio_open(struct inode *inode, struct file *filp)
+{
+ int minor;
+
+ minor = MINOR(inode->i_rdev);
+ if (minor < DEVCOUNT) {
+ if (openCnt > 0) {
+ return -EALREADY;
+ } else {
+ openCnt++;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+static int gio_close(struct inode *inode, struct file *filp)
+{
+ int minor;
+
+ minor = MINOR(inode->i_rdev);
+ if (minor < DEVCOUNT) {
+ openCnt--;
+ }
+ return 0;
+}
+
+static int gio_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int data;
+ static unsigned int addr = 0;
+
+ if (cmd & 0x01) { /* write */
+ if (copy_from_user(&data, (int *)arg, sizeof(int))) {
+ return -EFAULT;
+ }
+ }
+
+ switch (cmd) {
+ case GIODRV_IOCSGIOSETADDR: /* addres set */
+ addr = data;
+ break;
+
+ case GIODRV_IOCSGIODATA1: /* write byte */
+ ctrl_outb((unsigned char)(0x0ff & data), addr);
+ break;
+
+ case GIODRV_IOCSGIODATA2: /* write word */
+ if (addr & 0x01) {
+ return -EFAULT;
+ }
+ ctrl_outw((unsigned short int)(0x0ffff & data), addr);
+ break;
+
+ case GIODRV_IOCSGIODATA4: /* write long */
+ if (addr & 0x03) {
+ return -EFAULT;
+ }
+ ctrl_outl(data, addr);
+ break;
+
+ case GIODRV_IOCGGIODATA1: /* read byte */
+ data = ctrl_inb(addr);
+ break;
+
+ case GIODRV_IOCGGIODATA2: /* read word */
+ if (addr & 0x01) {
+ return -EFAULT;
+ }
+ data = ctrl_inw(addr);
+ break;
+
+ case GIODRV_IOCGGIODATA4: /* read long */
+ if (addr & 0x03) {
+ return -EFAULT;
+ }
+ data = ctrl_inl(addr);
+ break;
+ default:
+ return -EFAULT;
+ break;
+ }
+
+ if ((cmd & 0x01) == 0) { /* read */
+ if (copy_to_user((int *)arg, &data, sizeof(int))) {
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static struct file_operations gio_fops = {
+ .owner = THIS_MODULE,
+ .open = gio_open, /* open */
+ .release = gio_close, /* release */
+ .ioctl = gio_ioctl, /* ioctl */
+};
+
+static int __init gio_init(void)
+{
+ int error;
+
+ printk(KERN_INFO "gio: driver initialized\n");
+
+ openCnt = 0;
+
+ if ((error = alloc_chrdev_region(&dev, 0, DEVCOUNT, "gio")) < 0) {
+ printk(KERN_ERR
+ "gio: Couldn't alloc_chrdev_region, error=%d\n",
+ error);
+ return 1;
+ }
+
+ cdev_p = cdev_alloc();
+ cdev_p->ops = &gio_fops;
+ error = cdev_add(cdev_p, dev, DEVCOUNT);
+ if (error) {
+ printk(KERN_ERR
+ "gio: Couldn't cdev_add, error=%d\n", error);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void __exit gio_exit(void)
+{
+ cdev_del(cdev_p);
+ unregister_chrdev_region(dev, DEVCOUNT);
+}
+
+module_init(gio_init);
+module_exit(gio_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/sh/boards/landisk/io.c b/arch/sh/boards/landisk/io.c
deleted file mode 100644
index 92498b4947d..00000000000
--- a/arch/sh/boards/landisk/io.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * arch/sh/boards/landisk/io.c
- *
- * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
- * Based largely on io_se.c.
- *
- * I/O routine for I-O Data Device, Inc. LANDISK.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_landisk.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-/*
- * modifed by kogiidena
- * 2005.03.03
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/landisk/iodata_landisk.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-extern void *area5_io_base; /* Area 5 I/O Base address */
-extern void *area6_io_base; /* Area 6 I/O Base address */
-
-static inline unsigned long port2adr(unsigned int port)
-{
- if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
- if (port == 0x3f6)
- return ((unsigned long)area5_io_base + 0x2c);
- else
- return ((unsigned long)area5_io_base + PA_PIDE_OFFSET +
- ((port - 0x1f0) << 1));
- else if ((0x170 <= port && port < 0x178) || port == 0x376)
- if (port == 0x376)
- return ((unsigned long)area6_io_base + 0x2c);
- else
- return ((unsigned long)area6_io_base + PA_SIDE_OFFSET +
- ((port - 0x170) << 1));
- else
- maybebadio((unsigned long)port);
-
- return port;
-}
-
-/*
- * General outline: remap really low stuff [eventually] to SuperIO,
- * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
- * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
- * should be way beyond the window, and is used w/o translation for
- * compatibility.
- */
-u8 landisk_inb(unsigned long port)
-{
- if (PXSEG(port))
- return ctrl_inb(port);
- else if (is_pci_ioaddr(port))
- return ctrl_inb(pci_ioaddr(port));
-
- return ctrl_inw(port2adr(port)) & 0xff;
-}
-
-u8 landisk_inb_p(unsigned long port)
-{
- u8 v;
-
- if (PXSEG(port))
- v = ctrl_inb(port);
- else if (is_pci_ioaddr(port))
- v = ctrl_inb(pci_ioaddr(port));
- else
- v = ctrl_inw(port2adr(port)) & 0xff;
-
- ctrl_delay();
-
- return v;
-}
-
-u16 landisk_inw(unsigned long port)
-{
- if (PXSEG(port))
- return ctrl_inw(port);
- else if (is_pci_ioaddr(port))
- return ctrl_inw(pci_ioaddr(port));
- else
- maybebadio(port);
-
- return 0;
-}
-
-u32 landisk_inl(unsigned long port)
-{
- if (PXSEG(port))
- return ctrl_inl(port);
- else if (is_pci_ioaddr(port))
- return ctrl_inl(pci_ioaddr(port));
- else
- maybebadio(port);
-
- return 0;
-}
-
-void landisk_outb(u8 value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outb(value, port);
- else if (is_pci_ioaddr(port))
- ctrl_outb(value, pci_ioaddr(port));
- else
- ctrl_outw(value, port2adr(port));
-}
-
-void landisk_outb_p(u8 value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outb(value, port);
- else if (is_pci_ioaddr(port))
- ctrl_outb(value, pci_ioaddr(port));
- else
- ctrl_outw(value, port2adr(port));
- ctrl_delay();
-}
-
-void landisk_outw(u16 value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outw(value, port);
- else if (is_pci_ioaddr(port))
- ctrl_outw(value, pci_ioaddr(port));
- else
- maybebadio(port);
-}
-
-void landisk_outl(u32 value, unsigned long port)
-{
- if (PXSEG(port))
- ctrl_outl(value, port);
- else if (is_pci_ioaddr(port))
- ctrl_outl(value, pci_ioaddr(port));
- else
- maybebadio(port);
-}
-
-void landisk_insb(unsigned long port, void *dst, unsigned long count)
-{
- volatile u16 *p;
- u8 *buf = dst;
-
- if (PXSEG(port)) {
- while (count--)
- *buf++ = *(volatile u8 *)port;
- } else if (is_pci_ioaddr(port)) {
- volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
-
- while (count--)
- *buf++ = *bp;
- } else {
- p = (volatile u16 *)port2adr(port);
- while (count--)
- *buf++ = *p & 0xff;
- }
-}
-
-void landisk_insw(unsigned long port, void *dst, unsigned long count)
-{
- volatile u16 *p;
- u16 *buf = dst;
-
- if (PXSEG(port))
- p = (volatile u16 *)port;
- else if (is_pci_ioaddr(port))
- p = (volatile u16 *)pci_ioaddr(port);
- else
- p = (volatile u16 *)port2adr(port);
- while (count--)
- *buf++ = *p;
-}
-
-void landisk_insl(unsigned long port, void *dst, unsigned long count)
-{
- u32 *buf = dst;
-
- if (is_pci_ioaddr(port)) {
- volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
-
- while (count--)
- *buf++ = *p;
- } else
- maybebadio(port);
-}
-
-void landisk_outsb(unsigned long port, const void *src, unsigned long count)
-{
- volatile u16 *p;
- const u8 *buf = src;
-
- if (PXSEG(port))
- while (count--)
- ctrl_outb(*buf++, port);
- else if (is_pci_ioaddr(port)) {
- volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
-
- while (count--)
- *bp = *buf++;
- } else {
- p = (volatile u16 *)port2adr(port);
- while (count--)
- *p = *buf++;
- }
-}
-
-void landisk_outsw(unsigned long port, const void *src, unsigned long count)
-{
- volatile u16 *p;
- const u16 *buf = src;
-
- if (PXSEG(port))
- p = (volatile u16 *)port;
- else if (is_pci_ioaddr(port))
- p = (volatile u16 *)pci_ioaddr(port);
- else
- p = (volatile u16 *)port2adr(port);
-
- while (count--)
- *p = *buf++;
-}
-
-void landisk_outsl(unsigned long port, const void *src, unsigned long count)
-{
- const u32 *buf = src;
-
- if (is_pci_ioaddr(port)) {
- volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
-
- while (count--)
- *p = *buf++;
- } else
- maybebadio(port);
-}
-
-void __iomem *landisk_ioport_map(unsigned long port, unsigned int size)
-{
- if (PXSEG(port))
- return (void __iomem *)port;
- else if (is_pci_ioaddr(port))
- return (void __iomem *)pci_ioaddr(port);
-
- return (void __iomem *)port2adr(port);
-}
diff --git a/arch/sh/boards/landisk/irq.c b/arch/sh/boards/landisk/irq.c
index 3eba6d086d7..258649491d4 100644
--- a/arch/sh/boards/landisk/irq.c
+++ b/arch/sh/boards/landisk/irq.c
@@ -1,18 +1,16 @@
/*
* arch/sh/boards/landisk/irq.c
*
+ * I-O DATA Device, Inc. LANDISK Support
+ *
+ * Copyright (C) 2005-2007 kogiidena
+ *
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
- * I/O routine for I-O Data Device, Inc. LANDISK.
- *
- * Initial version only to support LAN access; some
- * placeholder code from io_landisk.c left in with the
- * expectation of later SuperIO and PCMCIA access.
- */
-/*
- * modified by kogiidena
- * 2005.03.03
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*/
#include <linux/init.h>
#include <linux/irq.h>
@@ -20,71 +18,27 @@
#include <linux/io.h>
#include <asm/landisk/iodata_landisk.h>
-static void enable_landisk_irq(unsigned int irq);
-static void disable_landisk_irq(unsigned int irq);
-
-/* shutdown is same as "disable" */
-#define shutdown_landisk_irq disable_landisk_irq
-
-static void ack_landisk_irq(unsigned int irq);
-static void end_landisk_irq(unsigned int irq);
-
-static unsigned int startup_landisk_irq(unsigned int irq)
-{
- enable_landisk_irq(irq);
- return 0; /* never anything pending */
-}
-
static void disable_landisk_irq(unsigned int irq)
{
- unsigned char val;
unsigned char mask = 0xff ^ (0x01 << (irq - 5));
- /* Set the priority in IPR to 0 */
- val = ctrl_inb(PA_IMASK);
- val &= mask;
- ctrl_outb(val, PA_IMASK);
+ ctrl_outb(ctrl_inb(PA_IMASK) & mask, PA_IMASK);
}
static void enable_landisk_irq(unsigned int irq)
{
- unsigned char val;
unsigned char value = (0x01 << (irq - 5));
- /* Set priority in IPR back to original value */
- val = ctrl_inb(PA_IMASK);
- val |= value;
- ctrl_outb(val, PA_IMASK);
-}
-
-static void ack_landisk_irq(unsigned int irq)
-{
- disable_landisk_irq(irq);
-}
-
-static void end_landisk_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- enable_landisk_irq(irq);
+ ctrl_outb(ctrl_inb(PA_IMASK) | value, PA_IMASK);
}
-static struct hw_interrupt_type landisk_irq_type = {
- .typename = "LANDISK IRQ",
- .startup = startup_landisk_irq,
- .shutdown = shutdown_landisk_irq,
- .enable = enable_landisk_irq,
- .disable = disable_landisk_irq,
- .ack = ack_landisk_irq,
- .end = end_landisk_irq
+static struct irq_chip landisk_irq_chip __read_mostly = {
+ .name = "LANDISK",
+ .mask = disable_landisk_irq,
+ .unmask = enable_landisk_irq,
+ .mask_ack = disable_landisk_irq,
};
-static void make_landisk_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- irq_desc[irq].chip = &landisk_irq_type;
- disable_landisk_irq(irq);
-}
-
/*
* Initialize IRQ setting
*/
@@ -92,6 +46,11 @@ void __init init_landisk_IRQ(void)
{
int i;
- for (i = 5; i < 14; i++)
- make_landisk_irq(i);
+ for (i = 5; i < 14; i++) {
+ disable_irq_nosync(i);
+ set_irq_chip_and_handler_name(i, &landisk_irq_chip,
+ handle_level_irq, "level");
+ enable_landisk_irq(i);
+ }
+ ctrl_outb(0x00, PA_PWRINT_CLR);
}
diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c
deleted file mode 100644
index 47a63c6617e..00000000000
--- a/arch/sh/boards/landisk/landisk_pwb.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch.
- *
- * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
- *
- * LED control drive function added by kogiidena
- */
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/major.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/landisk/iodata_landisk.h>
-
-#define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */
-#define LED_MINOR 21 /* LED minor no. */
-#define BTN_MINOR 22 /* BUTTON minor no. */
-#define GIO_MINOR 40 /* GIO minor no. */
-
-static int openCnt;
-static int openCntLED;
-static int openCntGio;
-static int openCntBtn;
-static int landisk_btn;
-static int landisk_btnctrlpid;
-/*
- * Functions prototypes
- */
-
-static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
-
-static int swdrv_open(struct inode *inode, struct file *filp)
-{
- int minor;
-
- minor = MINOR(inode->i_rdev);
- filp->private_data = (void *)minor;
-
- if (minor == SHUTDOWN_BTN_MINOR) {
- if (openCnt > 0) {
- return -EALREADY;
- } else {
- openCnt++;
- return 0;
- }
- } else if (minor == LED_MINOR) {
- if (openCntLED > 0) {
- return -EALREADY;
- } else {
- openCntLED++;
- return 0;
- }
- } else if (minor == BTN_MINOR) {
- if (openCntBtn > 0) {
- return -EALREADY;
- } else {
- openCntBtn++;
- return 0;
- }
- } else if (minor == GIO_MINOR) {
- if (openCntGio > 0) {
- return -EALREADY;
- } else {
- openCntGio++;
- return 0;
- }
- }
- return -ENOENT;
-
-}
-
-static int swdrv_close(struct inode *inode, struct file *filp)
-{
- int minor;
-
- minor = MINOR(inode->i_rdev);
- if (minor == SHUTDOWN_BTN_MINOR) {
- openCnt--;
- } else if (minor == LED_MINOR) {
- openCntLED--;
- } else if (minor == BTN_MINOR) {
- openCntBtn--;
- } else if (minor == GIO_MINOR) {
- openCntGio--;
- }
- return 0;
-}
-
-static int swdrv_read(struct file *filp, char *buff, size_t count,
- loff_t * ppos)
-{
- int minor;
- minor = (int)(filp->private_data);
-
- if (!access_ok(VERIFY_WRITE, (void *)buff, count))
- return -EFAULT;
-
- if (minor == SHUTDOWN_BTN_MINOR) {
- if (landisk_btn & 0x10) {
- put_user(1, buff);
- return 1;
- } else {
- return 0;
- }
- }
- return 0;
-}
-
-static int swdrv_write(struct file *filp, const char *buff, size_t count,
- loff_t * ppos)
-{
- int minor;
- minor = (int)(filp->private_data);
-
- if (minor == SHUTDOWN_BTN_MINOR) {
- return count;
- }
- return count;
-}
-
-static irqreturn_t sw_interrupt(int irq, void *dev_id)
-{
- landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));
- disable_irq(IRQ_BUTTON);
- disable_irq(IRQ_POWER);
- ctrl_outb(0x00, PA_PWRINT_CLR);
-
- if (landisk_btnctrlpid != 0) {
- kill_proc(landisk_btnctrlpid, SIGUSR1, 1);
- landisk_btnctrlpid = 0;
- }
-
- return IRQ_HANDLED;
-}
-
-static const struct file_operations swdrv_fops = {
- .read = swdrv_read, /* read */
- .write = swdrv_write, /* write */
- .open = swdrv_open, /* open */
- .release = swdrv_close, /* release */
- .ioctl = gio_ioctl, /* ioctl */
-
-};
-
-static char banner[] __initdata =
- KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n";
-
-int __init swdrv_init(void)
-{
- int error;
-
- printk("%s", banner);
-
- openCnt = 0;
- openCntLED = 0;
- openCntBtn = 0;
- openCntGio = 0;
- landisk_btn = 0;
- landisk_btnctrlpid = 0;
-
- if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) {
- printk(KERN_ERR
- "Button, LED and GIO driver:Couldn't register driver, error=%d\n",
- error);
- return 1;
- }
-
- if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
- printk(KERN_ERR "Unable to get IRQ 11.\n");
- return 1;
- }
- if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
- printk(KERN_ERR "Unable to get IRQ 12.\n");
- return 1;
- }
- ctrl_outb(0x00, PA_PWRINT_CLR);
-
- return 0;
-}
-
-module_init(swdrv_init);
-
-/*
- * gio driver
- *
- */
-
-#include <asm/landisk/gio.h>
-
-static int gio_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- int minor;
- unsigned int data, mask;
- static unsigned int addr = 0;
-
- minor = (int)(filp->private_data);
-
- /* access control */
- if (minor == GIO_MINOR) {
- ;
- } else if (minor == LED_MINOR) {
- if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) {
- ;
- } else {
- return -EINVAL;
- }
- } else if (minor == BTN_MINOR) {
- if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) {
- ;
- } else {
- return -EINVAL;
- }
- } else {
- return -EINVAL;
- }
-
- if (cmd & 0x01) { /* write */
- if (copy_from_user(&data, (int *)arg, sizeof(int))) {
- return -EFAULT;
- }
- }
-
- switch (cmd) {
- case GIODRV_IOCSGIOSETADDR: /* addres set */
- addr = data;
- break;
-
- case GIODRV_IOCSGIODATA1: /* write byte */
- ctrl_outb((unsigned char)(0x0ff & data), addr);
- break;
-
- case GIODRV_IOCSGIODATA2: /* write word */
- if (addr & 0x01) {
- return -EFAULT;
- }
- ctrl_outw((unsigned short int)(0x0ffff & data), addr);
- break;
-
- case GIODRV_IOCSGIODATA4: /* write long */
- if (addr & 0x03) {
- return -EFAULT;
- }
- ctrl_outl(data, addr);
- break;
-
- case GIODRV_IOCGGIODATA1: /* read byte */
- data = ctrl_inb(addr);
- break;
-
- case GIODRV_IOCGGIODATA2: /* read word */
- if (addr & 0x01) {
- return -EFAULT;
- }
- data = ctrl_inw(addr);
- break;
-
- case GIODRV_IOCGGIODATA4: /* read long */
- if (addr & 0x03) {
- return -EFAULT;
- }
- data = ctrl_inl(addr);
- break;
- case GIODRV_IOCSGIO_LED: /* write */
- mask = ((data & 0x00ffffff) << 8)
- | ((data & 0x0000ffff) << 16)
- | ((data & 0x000000ff) << 24);
- landisk_ledparam = data & (~mask);
- if (landisk_arch == 0) { /* arch == landisk */
- landisk_ledparam &= 0x03030303;
- mask = (~(landisk_ledparam >> 22)) & 0x000c;
- landisk_ledparam |= mask;
- } else { /* arch == usl-5p */
- mask = (landisk_ledparam >> 24) & 0x0001;
- landisk_ledparam |= mask;
- landisk_ledparam &= 0x007f7f7f;
- }
- landisk_ledparam |= 0x80;
- break;
- case GIODRV_IOCGGIO_LED: /* read */
- data = landisk_ledparam;
- if (landisk_arch == 0) { /* arch == landisk */
- data &= 0x03030303;
- } else { /* arch == usl-5p */
- ;
- }
- data &= (~0x080);
- break;
- case GIODRV_IOCSGIO_BUZZER: /* write */
- landisk_buzzerparam = data;
- landisk_ledparam |= 0x80;
- break;
- case GIODRV_IOCGGIO_LANDISK: /* read */
- data = landisk_arch & 0x01;
- break;
- case GIODRV_IOCGGIO_BTN: /* read */
- data = (0x0ff & ctrl_inb(PA_PWRINT_CLR));
- data <<= 8;
- data |= (0x0ff & ctrl_inb(PA_IMASK));
- data <<= 8;
- data |= (0x0ff & landisk_btn);
- data <<= 8;
- data |= (0x0ff & (~ctrl_inb(PA_STATUS)));
- break;
- case GIODRV_IOCSGIO_BTNPID: /* write */
- landisk_btnctrlpid = data;
- landisk_btn = 0;
- if (irq_desc[IRQ_BUTTON].depth) {
- enable_irq(IRQ_BUTTON);
- }
- if (irq_desc[IRQ_POWER].depth) {
- enable_irq(IRQ_POWER);
- }
- break;
- case GIODRV_IOCGGIO_BTNPID: /* read */
- data = landisk_btnctrlpid;
- break;
- default:
- return -EFAULT;
- break;
- }
-
- if ((cmd & 0x01) == 0) { /* read */
- if (copy_to_user((int *)arg, &data, sizeof(int))) {
- return -EFAULT;
- }
- }
- return 0;
-}
diff --git a/arch/sh/boards/landisk/psw.c b/arch/sh/boards/landisk/psw.c
new file mode 100644
index 00000000000..5a9b70b5dec
--- /dev/null
+++ b/arch/sh/boards/landisk/psw.c
@@ -0,0 +1,143 @@
+/*
+ * arch/sh/boards/landisk/psw.c
+ *
+ * push switch support for LANDISK and USL-5P
+ *
+ * Copyright (C) 2006-2007 Paul Mundt
+ * Copyright (C) 2007 kogiidena
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/landisk/iodata_landisk.h>
+#include <asm/push-switch.h>
+
+static irqreturn_t psw_irq_handler(int irq, void *arg)
+{
+ struct platform_device *pdev = arg;
+ struct push_switch *psw = platform_get_drvdata(pdev);
+ struct push_switch_platform_info *psw_info = pdev->dev.platform_data;
+ unsigned int sw_value;
+ int ret = 0;
+
+ sw_value = (0x0ff & (~ctrl_inb(PA_STATUS)));
+
+ /* Nothing to do if there's no state change */
+ if (psw->state) {
+ ret = 1;
+ goto out;
+ }
+
+ /* Figure out who raised it */
+ if (sw_value & (1 << psw_info->bit)) {
+ psw->state = 1;
+ mod_timer(&psw->debounce, jiffies + 50);
+ ret = 1;
+ }
+
+out:
+ /* Clear the switch IRQs */
+ ctrl_outb(0x00, PA_PWRINT_CLR);
+
+ return IRQ_RETVAL(ret);
+}
+
+static struct resource psw_power_resources[] = {
+ [0] = {
+ .start = IRQ_POWER,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource psw_usl5p_resources[] = {
+ [0] = {
+ .start = IRQ_BUTTON,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct push_switch_platform_info psw_power_platform_data = {
+ .name = "psw_power",
+ .bit = 4,
+ .irq_flags = IRQF_SHARED,
+ .irq_handler = psw_irq_handler,
+};
+
+static struct push_switch_platform_info psw1_platform_data = {
+ .name = "psw1",
+ .bit = 0,
+ .irq_flags = IRQF_SHARED,
+ .irq_handler = psw_irq_handler,
+};
+
+static struct push_switch_platform_info psw2_platform_data = {
+ .name = "psw2",
+ .bit = 2,
+ .irq_flags = IRQF_SHARED,
+ .irq_handler = psw_irq_handler,
+};
+
+static struct push_switch_platform_info psw3_platform_data = {
+ .name = "psw3",
+ .bit = 1,
+ .irq_flags = IRQF_SHARED,
+ .irq_handler = psw_irq_handler,
+};
+
+static struct platform_device psw_power_switch_device = {
+ .name = "push-switch",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(psw_power_resources),
+ .resource = psw_power_resources,
+ .dev = {
+ .platform_data = &psw_power_platform_data,
+ },
+};
+
+static struct platform_device psw1_switch_device = {
+ .name = "push-switch",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(psw_usl5p_resources),
+ .resource = psw_usl5p_resources,
+ .dev = {
+ .platform_data = &psw1_platform_data,
+ },
+};
+
+static struct platform_device psw2_switch_device = {
+ .name = "push-switch",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(psw_usl5p_resources),
+ .resource = psw_usl5p_resources,
+ .dev = {
+ .platform_data = &psw2_platform_data,
+ },
+};
+
+static struct platform_device psw3_switch_device = {
+ .name = "push-switch",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(psw_usl5p_resources),
+ .resource = psw_usl5p_resources,
+ .dev = {
+ .platform_data = &psw3_platform_data,
+ },
+};
+
+static struct platform_device *psw_devices[] = {
+ &psw_power_switch_device,
+ &psw1_switch_device,
+ &psw2_switch_device,
+ &psw3_switch_device,
+};
+
+static int __init psw_init(void)
+{
+ return platform_add_devices(psw_devices, ARRAY_SIZE(psw_devices));
+}
+module_init(psw_init);
diff --git a/arch/sh/boards/landisk/rtc.c b/arch/sh/boards/landisk/rtc.c
deleted file mode 100644
index 0a9a2a2ad05..00000000000
--- a/arch/sh/boards/landisk/rtc.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * arch/sh/boards/landisk/rtc.c -- RTC support
- *
- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
- */
-/*
- * modifed by kogiidena
- * 2005.09.16
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/bcd.h>
-#include <asm/rtc.h>
-
-extern spinlock_t rtc_lock;
-
-extern void
-rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon,
- unsigned int BCD_day, unsigned int BCD_hr,
- unsigned int BCD_min, unsigned int BCD_sec);
-
-extern unsigned long
-rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon,
- unsigned int *BCD_day, unsigned int *BCD_hr,
- unsigned int *BCD_min, unsigned int *BCD_sec);
-
-void landisk_rtc_gettimeofday(struct timespec *tv)
-{
- unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
- tv->tv_sec = rs5c313_get_cmos_time
- (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
- tv->tv_nsec = 0;
- spin_unlock_irqrestore(&rtc_lock, flags);
-}
-
-int landisk_rtc_settimeofday(const time_t secs)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
- unsigned long flags;
- unsigned long nowtime = secs;
- unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
-
- spin_lock_irqsave(&rtc_lock, flags);
-
- rs5c313_get_cmos_time
- (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
- cmos_minutes = BCD_min;
- BCD_TO_BIN(cmos_minutes);
-
- /*
- * 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 - cmos_minutes) + 15) / 30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr,
- real_minutes, real_seconds);
- } else {
- printk(KERN_WARNING
- "set_rtc_time: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
- }
-
- spin_unlock_irqrestore(&rtc_lock, flags);
- return retval;
-}
-
-void landisk_time_init(void)
-{
- rtc_sh_get_time = landisk_rtc_gettimeofday;
- rtc_sh_set_time = landisk_rtc_settimeofday;
-}
diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c
index 122d6996263..4058b4f50d4 100644
--- a/arch/sh/boards/landisk/setup.c
+++ b/arch/sh/boards/landisk/setup.c
@@ -1,144 +1,90 @@
/*
* arch/sh/boards/landisk/setup.c
*
- * Copyright (C) 2000 Kazumoto Kojima
- * Copyright (C) 2002 Paul Mundt
- *
* I-O DATA Device, Inc. LANDISK Support.
*
- * Modified for LANDISK by
- * Atom Create Engineering Co., Ltd. 2002.
- *
- * modifed by kogiidena
- * 2005.09.16
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2002 Paul Mundt
+ * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2005-2007 kogiidena
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pata_platform.h>
#include <linux/pm.h>
#include <linux/mm.h>
#include <asm/machvec.h>
-#include <asm/rtc.h>
#include <asm/landisk/iodata_landisk.h>
#include <asm/io.h>
-void landisk_time_init(void);
void init_landisk_IRQ(void);
-int landisk_ledparam;
-int landisk_buzzerparam;
-int landisk_arch;
-
-/* cycle the led's in the clasic knightrider/sun pattern */
-static void heartbeat_landisk(void)
-{
- static unsigned int cnt = 0, blink = 0x00, period = 25;
- volatile u8 *p = (volatile u8 *)PA_LED;
- char data;
-
- if ((landisk_ledparam & 0x080) == 0)
- return;
-
- cnt += 1;
-
- if (cnt < period)
- return;
-
- cnt = 0;
- blink++;
-
- data = (blink & 0x01) ? (landisk_ledparam >> 16) : 0;
- data |= (blink & 0x02) ? (landisk_ledparam >> 8) : 0;
- data |= landisk_ledparam;
-
- /* buzzer */
- if (landisk_buzzerparam & 0x1) {
- data |= 0x80;
- } else {
- data &= 0x7f;
- }
- *p = data;
-
- if (((landisk_ledparam & 0x007f7f00) == 0) &&
- (landisk_buzzerparam == 0))
- landisk_ledparam &= (~0x0080);
-
- landisk_buzzerparam >>= 1;
-}
-
static void landisk_power_off(void)
{
ctrl_outb(0x01, PA_SHUTDOWN);
}
-static void check_usl5p(void)
-{
- volatile u8 *p = (volatile u8 *)PA_LED;
- u8 tmp1, tmp2;
+static struct resource cf_ide_resources[3];
- tmp1 = *p;
- *p = 0x40;
- tmp2 = *p;
- *p = tmp1;
+static struct pata_platform_info pata_info = {
+ .ioport_shift = 1,
+};
- landisk_arch = (tmp2 == 0x40);
- if (landisk_arch == 1) {
- /* arch == usl-5p */
- landisk_ledparam = 0x00000380;
- landisk_ledparam |= (tmp1 & 0x07c);
- } else {
- /* arch == landisk */
- landisk_ledparam = 0x02000180;
- landisk_ledparam |= 0x04;
- }
-}
+static struct platform_device cf_ide_device = {
+ .name = "pata_platform",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cf_ide_resources),
+ .resource = cf_ide_resources,
+ .dev = {
+ .platform_data = &pata_info,
+ },
+};
-void *area5_io_base;
-void *area6_io_base;
+static struct platform_device *landisk_devices[] __initdata = {
+ &cf_ide_device,
+};
-static int __init landisk_cf_init(void)
+static int __init landisk_devices_setup(void)
{
pgprot_t prot;
- unsigned long paddrbase, psize;
+ unsigned long paddrbase;
+ void *cf_ide_base;
/* open I/O area window */
paddrbase = virt_to_phys((void *)PA_AREA5_IO);
- psize = PAGE_SIZE;
prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16);
- area5_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
- if (!area5_io_base) {
+ cf_ide_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
+ if (!cf_ide_base) {
printk("allocate_cf_area : can't open CF I/O window!\n");
return -ENOMEM;
}
- paddrbase = virt_to_phys((void *)PA_AREA6_IO);
- psize = PAGE_SIZE;
- prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
- area6_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
- if (!area6_io_base) {
- printk("allocate_cf_area : can't open HDD I/O window!\n");
- return -ENOMEM;
- }
-
- printk(KERN_INFO "Allocate Area5/6 success.\n");
-
- /* XXX : do we need attribute and common-memory area also? */
-
- return 0;
+ /* IDE cmd address : 0x1f0-0x1f7 and 0x3f6 */
+ cf_ide_resources[0].start = (unsigned long)cf_ide_base + 0x40;
+ cf_ide_resources[0].end = (unsigned long)cf_ide_base + 0x40 + 0x0f;
+ cf_ide_resources[0].flags = IORESOURCE_IO;
+ cf_ide_resources[1].start = (unsigned long)cf_ide_base + 0x2c;
+ cf_ide_resources[1].end = (unsigned long)cf_ide_base + 0x2c + 0x03;
+ cf_ide_resources[1].flags = IORESOURCE_IO;
+ cf_ide_resources[2].start = IRQ_FATA;
+ cf_ide_resources[2].flags = IORESOURCE_IRQ;
+
+ return platform_add_devices(landisk_devices,
+ ARRAY_SIZE(landisk_devices));
}
+__initcall(landisk_devices_setup);
+
static void __init landisk_setup(char **cmdline_p)
{
- device_initcall(landisk_cf_init);
-
- landisk_buzzerparam = 0;
- check_usl5p();
+ /* LED ON */
+ ctrl_outb(ctrl_inb(PA_LED) | 0x03, PA_LED);
printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n");
-
- board_time_init = landisk_time_init;
pm_power_off = landisk_power_off;
}
@@ -147,30 +93,8 @@ static void __init landisk_setup(char **cmdline_p)
*/
struct sh_machine_vector mv_landisk __initmv = {
.mv_name = "LANDISK",
- .mv_setup = landisk_setup,
.mv_nr_irqs = 72,
- .mv_inb = landisk_inb,
- .mv_inw = landisk_inw,
- .mv_inl = landisk_inl,
- .mv_outb = landisk_outb,
- .mv_outw = landisk_outw,
- .mv_outl = landisk_outl,
- .mv_inb_p = landisk_inb_p,
- .mv_inw_p = landisk_inw,
- .mv_inl_p = landisk_inl,
- .mv_outb_p = landisk_outb_p,
- .mv_outw_p = landisk_outw,
- .mv_outl_p = landisk_outl,
- .mv_insb = landisk_insb,
- .mv_insw = landisk_insw,
- .mv_insl = landisk_insl,
- .mv_outsb = landisk_outsb,
- .mv_outsw = landisk_outsw,
- .mv_outsl = landisk_outsl,
- .mv_ioport_map = landisk_ioport_map,
+ .mv_setup = landisk_setup,
.mv_init_irq = init_landisk_IRQ,
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_landisk,
-#endif
};
ALIAS_MV(landisk)
diff --git a/arch/sh/boards/lboxre2/Makefile b/arch/sh/boards/lboxre2/Makefile
new file mode 100644
index 00000000000..e9ed140c06f
--- /dev/null
+++ b/arch/sh/boards/lboxre2/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the L-BOX RE2 specific parts of the kernel
+# Copyright (c) 2007 Nobuhiro Iwamatsu
+
+obj-y := setup.o irq.o
diff --git a/arch/sh/boards/lboxre2/irq.c b/arch/sh/boards/lboxre2/irq.c
new file mode 100644
index 00000000000..5a1c3bbe7b5
--- /dev/null
+++ b/arch/sh/boards/lboxre2/irq.c
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/sh/boards/lboxre2/irq.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * NTT COMWARE L-BOX RE2 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/lboxre2.h>
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_lboxre2_IRQ(void)
+{
+ make_imask_irq(IRQ_CF1);
+ make_imask_irq(IRQ_CF0);
+ make_imask_irq(IRQ_INTD);
+ make_imask_irq(IRQ_ETH1);
+ make_imask_irq(IRQ_ETH0);
+ make_imask_irq(IRQ_INTA);
+}
diff --git a/arch/sh/boards/lboxre2/setup.c b/arch/sh/boards/lboxre2/setup.c
new file mode 100644
index 00000000000..4e20f7c63bf
--- /dev/null
+++ b/arch/sh/boards/lboxre2/setup.c
@@ -0,0 +1,85 @@
+/*
+ * linux/arch/sh/boards/lbox/setup.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * NTT COMWARE L-BOX RE2 Support
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pata_platform.h>
+#include <asm/machvec.h>
+#include <asm/addrspace.h>
+#include <asm/lboxre2.h>
+#include <asm/io.h>
+
+static struct resource cf_ide_resources[] = {
+ [0] = {
+ .start = 0x1f0,
+ .end = 0x1f0 + 8 ,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = 0x1f0 + 0x206,
+ .end = 0x1f0 +8 + 0x206 + 8,
+ .flags = IORESOURCE_IO,
+ },
+ [2] = {
+ .start = IRQ_CF0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cf_ide_device = {
+ .name = "pata_platform",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cf_ide_resources),
+ .resource = cf_ide_resources,
+};
+
+static struct platform_device *lboxre2_devices[] __initdata = {
+ &cf_ide_device,
+};
+
+static int __init lboxre2_devices_setup(void)
+{
+ u32 cf0_io_base; /* Boot CF base address */
+ pgprot_t prot;
+ unsigned long paddrbase, psize;
+
+ /* open I/O area window */
+ paddrbase = virt_to_phys((void*)PA_AREA5_IO);
+ psize = PAGE_SIZE;
+ prot = PAGE_KERNEL_PCC( 1 , _PAGE_PCC_IO16);
+ cf0_io_base = (u32)p3_ioremap(paddrbase, psize, prot.pgprot);
+ if (!cf0_io_base) {
+ printk(KERN_ERR "%s : can't open CF I/O window!\n" , __func__ );
+ return -ENOMEM;
+ }
+
+ cf_ide_resources[0].start += cf0_io_base ;
+ cf_ide_resources[0].end += cf0_io_base ;
+ cf_ide_resources[1].start += cf0_io_base ;
+ cf_ide_resources[1].end += cf0_io_base ;
+
+ return platform_add_devices(lboxre2_devices,
+ ARRAY_SIZE(lboxre2_devices));
+
+}
+device_initcall(lboxre2_devices_setup);
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_lboxre2 __initmv = {
+ .mv_name = "L-BOX RE2",
+ .mv_nr_irqs = 72,
+ .mv_init_irq = init_lboxre2_IRQ,
+};
+ALIAS_MV(lboxre2)
diff --git a/arch/sh/boards/renesas/r7780rp/Kconfig b/arch/sh/boards/renesas/r7780rp/Kconfig
index c26d9813d23..9fb11641fe1 100644
--- a/arch/sh/boards/renesas/r7780rp/Kconfig
+++ b/arch/sh/boards/renesas/r7780rp/Kconfig
@@ -1,14 +1,24 @@
-if SH_R7780RP
+if SH_HIGHLANDER
-menu "R7780RP options"
+choice
+ prompt "Highlander options"
+ default SH_R7780MP
+
+config SH_R7780RP
+ bool "R7780RP-1 board support"
+ select CPU_SUBTYPE_SH7780
config SH_R7780MP
bool "R7780MP board support"
- default y
+ select CPU_SUBTYPE_SH7780
help
Selecting this option will enable support for the mass-production
version of the R7780RP. If in doubt, say Y.
-endmenu
+config SH_R7785RP
+ bool "R7785RP board support"
+ select CPU_SUBTYPE_SH7785
+
+endchoice
endif
diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
index ed5f5a9a3b3..609e5d50dde 100644
--- a/arch/sh/boards/renesas/r7780rp/Makefile
+++ b/arch/sh/boards/renesas/r7780rp/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the R7780RP-1 specific parts of the kernel
#
-
-obj-y := setup.o irq.o
-
+irqinit-y := irq-r7780rp.o
+irqinit-$(CONFIG_SH_R7785RP) := irq-r7785rp.o
obj-$(CONFIG_PUSH_SWITCH) += psw.o
+obj-y := setup.o irq.o $(irqinit-y)
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
new file mode 100644
index 00000000000..f5f358746c9
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7780rp.c
@@ -0,0 +1,21 @@
+/*
+ * Renesas Solutions Highlander R7780RP-1 Support.
+ *
+ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/r7780rp.h>
+
+void __init highlander_init_irq(void)
+{
+ int i;
+
+ for (i = 0; i < 15; i++)
+ make_r7780rp_irq(i);
+}
diff --git a/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
new file mode 100644
index 00000000000..dd6ec4ce44d
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/irq-r7785rp.c
@@ -0,0 +1,29 @@
+/*
+ * Renesas Solutions Highlander R7780RP-1 Support.
+ *
+ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/r7780rp.h>
+
+void __init highlander_init_irq(void)
+{
+ ctrl_outw(0x0000, PA_IRLSSR1); /* FPGA IRLSSR1(CF_CD clear) */
+
+ /* Setup the FPGA IRL */
+ ctrl_outw(0x0000, PA_IRLPRA); /* FPGA IRLA */
+ ctrl_outw(0xe598, PA_IRLPRB); /* FPGA IRLB */
+ ctrl_outw(0x7060, PA_IRLPRC); /* FPGA IRLC */
+ ctrl_outw(0x0000, PA_IRLPRD); /* FPGA IRLD */
+ ctrl_outw(0x4321, PA_IRLPRE); /* FPGA IRLE */
+ ctrl_outw(0x0000, PA_IRLPRF); /* FPGA IRLF */
+
+ make_r7780rp_irq(1); /* CF card */
+ make_r7780rp_irq(10); /* On-board ethernet */
+}
diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c
index cc381e19778..e0b8eb52f37 100644
--- a/arch/sh/boards/renesas/r7780rp/irq.c
+++ b/arch/sh/boards/renesas/r7780rp/irq.c
@@ -14,10 +14,12 @@
#include <linux/io.h>
#include <asm/r7780rp.h>
-#ifdef CONFIG_SH_R7780MP
-static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
-#else
+#ifdef CONFIG_SH_R7780RP
static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0};
+#elif defined(CONFIG_SH_R7780MP)
+static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
+#elif defined(CONFIG_SH_R7785RP)
+static int mask_pos[] = {2, 11, 2, 2, 2, 2, 9, 8, 7, 5, 10, 2, 2, 2, 2, 2};
#endif
static void enable_r7780rp_irq(unsigned int irq)
@@ -40,17 +42,10 @@ static struct irq_chip r7780rp_irq_chip __read_mostly = {
.mask_ack = disable_r7780rp_irq,
};
-/*
- * Initialize IRQ setting
- */
-void __init init_r7780rp_IRQ(void)
+void make_r7780rp_irq(unsigned int irq)
{
- int i;
-
- for (i = 0; i < 15; i++) {
- disable_irq_nosync(i);
- set_irq_chip_and_handler_name(i, &r7780rp_irq_chip,
- handle_level_irq, "level");
- enable_r7780rp_irq(i);
- }
+ disable_irq_nosync(irq);
+ set_irq_chip_and_handler_name(irq, &r7780rp_irq_chip,
+ handle_level_irq, "level");
+ enable_r7780rp_irq(irq);
}
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index 2faba6679e6..0727ef92f2b 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -1,10 +1,13 @@
/*
* arch/sh/boards/renesas/r7780rp/setup.c
*
+ * Renesas Solutions Highlander Support.
+ *
* Copyright (C) 2002 Atom Create Engineering Co., Ltd.
* Copyright (C) 2005 - 2007 Paul Mundt
*
- * Renesas Solutions Highlander R7780RP-1 Support.
+ * This contains support for the R7780RP-1, R7780MP, and R7785RP
+ * Highlander modules.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -18,32 +21,6 @@
#include <asm/clock.h>
#include <asm/io.h>
-extern void init_r7780rp_IRQ(void);
-
-static struct resource m66596_usb_host_resources[] = {
- [0] = {
- .start = 0xa4800000,
- .end = 0xa4ffffff,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 6, /* irq number */
- .end = 6,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device m66596_usb_host_device = {
- .name = "m66596-hcd",
- .id = 0,
- .dev = {
- .dma_mask = NULL, /* don't use dma */
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(m66596_usb_host_resources),
- .resource = m66596_usb_host_resources,
-};
-
static struct resource cf_ide_resources[] = {
[0] = {
.start = PA_AREA5_IO + 0x1000,
@@ -56,10 +33,10 @@ static struct resource cf_ide_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
-#ifdef CONFIG_SH_R7780MP
- .start = 1,
-#else
+#ifdef CONFIG_SH_R7780RP
.start = 4,
+#else
+ .start = 1,
#endif
.flags = IORESOURCE_IRQ,
},
@@ -92,15 +69,18 @@ static struct resource heartbeat_resources[] = {
static struct platform_device heartbeat_device = {
.name = "heartbeat",
.id = -1,
+
+ /* R7785RP has a slightly more sensible FPGA.. */
+#ifndef CONFIG_SH_R7785RP
.dev = {
.platform_data = heartbeat_bit_pos,
},
+#endif
.num_resources = ARRAY_SIZE(heartbeat_resources),
.resource = heartbeat_resources,
};
static struct platform_device *r7780rp_devices[] __initdata = {
- &m66596_usb_host_device,
&cf_ide_device,
&heartbeat_device,
};
@@ -110,18 +90,19 @@ static int __init r7780rp_devices_setup(void)
return platform_add_devices(r7780rp_devices,
ARRAY_SIZE(r7780rp_devices));
}
+device_initcall(r7780rp_devices_setup);
/*
* Platform specific clocks
*/
static void ivdr_clk_enable(struct clk *clk)
{
- ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << 8), PA_IVDRCTL);
+ ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << IVDR_CK_ON), PA_IVDRCTL);
}
static void ivdr_clk_disable(struct clk *clk)
{
- ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << 8), PA_IVDRCTL);
+ ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << IVDR_CK_ON), PA_IVDRCTL);
}
static struct clk_ops ivdr_clk_ops = {
@@ -140,22 +121,22 @@ static struct clk *r7780rp_clocks[] = {
static void r7780rp_power_off(void)
{
-#ifdef CONFIG_SH_R7780MP
- ctrl_outw(0x0001, PA_POFF);
-#endif
+ if (mach_is_r7780mp() || mach_is_r7785rp())
+ ctrl_outw(0x0001, PA_POFF);
}
/*
* Initialize the board
*/
-static void __init r7780rp_setup(char **cmdline_p)
+static void __init highlander_setup(char **cmdline_p)
{
u16 ver = ctrl_inw(PA_VERREG);
int i;
- device_initcall(r7780rp_devices_setup);
-
- printk(KERN_INFO "Renesas Solutions Highlander R7780RP-1 support.\n");
+ printk(KERN_INFO "Renesas Solutions Highlander %s support.\n",
+ mach_is_r7780rp() ? "R7780RP-1" :
+ mach_is_r7780mp() ? "R7780MP" :
+ "R7785RP");
printk(KERN_INFO "Board version: %d (revision %d), "
"FPGA version: %d (revision %d)\n",
@@ -173,9 +154,10 @@ static void __init r7780rp_setup(char **cmdline_p)
}
ctrl_outw(0x0000, PA_OBLED); /* Clear LED. */
-#ifndef CONFIG_SH_R7780MP
- ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */
-#endif
+
+ if (mach_is_r7780rp())
+ ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */
+
ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x01, PA_IVDRCTL); /* Si13112 */
pm_power_off = r7780rp_power_off;
@@ -184,10 +166,10 @@ static void __init r7780rp_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_r7780rp __initmv = {
- .mv_name = "Highlander R7780RP-1",
- .mv_setup = r7780rp_setup,
+struct sh_machine_vector mv_highlander __initmv = {
+ .mv_name = "Highlander",
.mv_nr_irqs = 109,
- .mv_init_irq = init_r7780rp_IRQ,
+ .mv_setup = highlander_setup,
+ .mv_init_irq = highlander_init_irq,
};
-ALIAS_MV(r7780rp)
+ALIAS_MV(highlander)
diff --git a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c
index 9941949331a..c4550473d4c 100644
--- a/arch/sh/boards/se/770x/io.c
+++ b/arch/sh/boards/se/770x/io.c
@@ -27,6 +27,8 @@ int sh_pcic_io_dummy;
static inline volatile __u16 *
port2adr(unsigned int port)
{
+ if (port & 0xff000000)
+ return ( volatile __u16 *) port;
if (port >= 0x2000)
return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
else if (port >= 0x1000)
diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
index 307ca5da623..c8eccff77a0 100644
--- a/arch/sh/boards/se/770x/irq.c
+++ b/arch/sh/boards/se/770x/irq.c
@@ -55,23 +55,34 @@ void make_se770x_irq(struct ipr_data *table, unsigned int nr_irqs)
}
static struct ipr_data se770x_ipr_map[] = {
+ /*
+ * Super I/O (Just mimic PC):
+ * 1: keyboard
+ * 3: serial 0
+ * 4: serial 1
+ * 5: printer
+ * 6: floppy
+ * 8: rtc
+ * 12: mouse
+ * 14: ide0
+ */
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
/* This is default value */
- { 0xf-0x2, 0, 8, 0x2 , BCR_ILCRA},
- { 0xf-0xa, 0, 4, 0xa , BCR_ILCRA},
- { 0xf-0x5, 0, 0, 0x5 , BCR_ILCRB},
- { 0xf-0x8, 0, 4, 0x8 , BCR_ILCRC},
- { 0xf-0xc, 0, 0, 0xc , BCR_ILCRC},
- { 0xf-0xe, 0, 12, 0xe , BCR_ILCRD},
- { 0xf-0x3, 0, 4, 0x3 , BCR_ILCRD}, /* LAN */
- { 0xf-0xd, 0, 8, 0xd , BCR_ILCRE},
- { 0xf-0x9, 0, 4, 0x9 , BCR_ILCRE},
- { 0xf-0x1, 0, 0, 0x1 , BCR_ILCRE},
- { 0xf-0xf, 0, 12, 0xf , BCR_ILCRF},
- { 0xf-0xb, 0, 4, 0xb , BCR_ILCRF},
- { 0xf-0x7, 0, 12, 0x7 , BCR_ILCRG},
- { 0xf-0x6, 0, 8, 0x6 , BCR_ILCRG},
- { 0xf-0x4, 0, 4, 0x4 , BCR_ILCRG},
+ { 13, 0, 8, 0x0f-13 ,BCR_ILCRA},
+ { 5 , 0, 4, 0x0f- 5 ,BCR_ILCRA},
+ { 10, 0, 0, 0x0f-10, BCR_ILCRB},
+ { 7 , 0, 4, 0x0f- 7, BCR_ILCRC},
+ { 3 , 0, 0, 0x0f- 3, BCR_ILCRC},
+ { 1 , 0, 12, 0x0f- 1, BCR_ILCRD},
+ { 12, 0, 4, 0x0f-12, BCR_ILCRD}, /* LAN */
+ { 2 , 0, 8, 0x0f- 2, BCR_ILCRE}, /* PCIRQ2 */
+ { 6 , 0, 4, 0x0f- 6, BCR_ILCRE}, /* PCIRQ1 */
+ { 14, 0, 0, 0x0f-14, BCR_ILCRE}, /* PCIRQ0 */
+ { 0 , 0, 12, 0x0f , BCR_ILCRF},
+ { 4 , 0, 4, 0x0f- 4, BCR_ILCRF},
+ { 8 , 0, 12, 0x0f- 8, BCR_ILCRG},
+ { 9 , 0, 8, 0x0f- 9, BCR_ILCRG},
+ { 11, 0, 4, 0x0f-11, BCR_ILCRG},
#else
{ 14, 0, 8, 0x0f-14 ,BCR_ILCRA},
{ 12, 0, 4, 0x0f-12 ,BCR_ILCRA},
@@ -81,8 +92,10 @@ static struct ipr_data se770x_ipr_map[] = {
{ 4, 0, 4, 0x0f- 4 ,BCR_ILCRC},
{ 3, 0, 0, 0x0f- 3 ,BCR_ILCRC},
{ 1, 0, 12, 0x0f- 1 ,BCR_ILCRD},
+#if defined(CONFIG_STNIC)
/* ST NIC */
{ 10, 0, 4, 0x0f-10 ,BCR_ILCRD}, /* LAN */
+#endif
/* MRSHPC IRQs setting */
{ 0, 0, 12, 0x0f- 0 ,BCR_ILCRE}, /* PCIRQ3 */
{ 11, 0, 8, 0x0f-11 ,BCR_ILCRE}, /* PCIRQ2 */
@@ -100,18 +113,6 @@ static struct ipr_data se770x_ipr_map[] = {
*/
void __init init_se_IRQ(void)
{
- /*
- * Super I/O (Just mimic PC):
- * 1: keyboard
- * 3: serial 0
- * 4: serial 1
- * 5: printer
- * 6: floppy
- * 8: rtc
- * 12: mouse
- * 14: ide0
- */
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
/* Disable all interrupts */
ctrl_outw(0, BCR_ILCRA);
ctrl_outw(0, BCR_ILCRB);
@@ -120,6 +121,6 @@ void __init init_se_IRQ(void)
ctrl_outw(0, BCR_ILCRE);
ctrl_outw(0, BCR_ILCRF);
ctrl_outw(0, BCR_ILCRG);
-#endif
+
make_se770x_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map));
}
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
index 45cbc36b9fb..17a2631de3b 100644
--- a/arch/sh/boards/se/770x/setup.c
+++ b/arch/sh/boards/se/770x/setup.c
@@ -63,6 +63,31 @@ static void __init smsc_setup(char **cmdline_p)
outb_p(CONFIG_EXIT, CONFIG_PORT);
}
+
+static struct resource cf_ide_resources[] = {
+ [0] = {
+ .start = PA_MRSHPC_IO + 0x1f0,
+ .end = PA_MRSHPC_IO + 0x1f0 + 8,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = PA_MRSHPC_IO + 0x1f0 + 0x206,
+ .end = PA_MRSHPC_IO + 0x1f0 +8 + 0x206 + 8,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = IRQ_CFCARD,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cf_ide_device = {
+ .name = "pata_platform",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cf_ide_resources),
+ .resource = cf_ide_resources,
+};
+
static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
static struct resource heartbeat_resources[] = {
@@ -85,13 +110,14 @@ static struct platform_device heartbeat_device = {
static struct platform_device *se_devices[] __initdata = {
&heartbeat_device,
+ &cf_ide_device,
};
static int __init se_devices_setup(void)
{
return platform_add_devices(se_devices, ARRAY_SIZE(se_devices));
}
-__initcall(se_devices_setup);
+device_initcall(se_devices_setup);
/*
* The Machine Vector
@@ -107,6 +133,8 @@ struct sh_machine_vector mv_se __initmv = {
.mv_nr_irqs = 61,
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
.mv_nr_irqs = 86,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+ .mv_nr_irqs = 104,
#endif
.mv_inb = se_inb,
diff --git a/arch/sh/boards/se/7722/Makefile b/arch/sh/boards/se/7722/Makefile
new file mode 100644
index 00000000000..8694373389e
--- /dev/null
+++ b/arch/sh/boards/se/7722/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the HITACHI UL SolutionEngine 7722 specific parts of the kernel
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+#
+
+obj-y := setup.o irq.o
diff --git a/arch/sh/boards/se/7722/irq.c b/arch/sh/boards/se/7722/irq.c
new file mode 100644
index 00000000000..099e5deb77f
--- /dev/null
+++ b/arch/sh/boards/se/7722/irq.c
@@ -0,0 +1,101 @@
+/*
+ * linux/arch/sh/boards/se/7722/irq.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7722 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/se7722.h>
+
+#define INTC_INTMSK0 0xFFD00044
+#define INTC_INTMSKCLR0 0xFFD00064
+
+static void disable_se7722_irq(unsigned int irq)
+{
+ struct ipr_data *p = get_irq_chip_data(irq);
+ ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr );
+}
+
+static void enable_se7722_irq(unsigned int irq)
+{
+ struct ipr_data *p = get_irq_chip_data(irq);
+ ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr );
+}
+
+static struct irq_chip se7722_irq_chip __read_mostly = {
+ .name = "SE7722",
+ .mask = disable_se7722_irq,
+ .unmask = enable_se7722_irq,
+ .mask_ack = disable_se7722_irq,
+};
+
+static struct ipr_data ipr_irq_table[] = {
+ /* irq ,idx,sft, priority , addr */
+ { MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } ,
+ { MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } ,
+ { MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } ,
+ { MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } ,
+ { SMC_IRQ , 0 , 0 , SMC_BIT , IRQ01_MASK } ,
+ { EXT_IRQ , 0 , 0 , EXT_BIT , IRQ01_MASK } ,
+};
+
+int se7722_irq_demux(int irq)
+{
+
+ if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) {
+ volatile unsigned short intv =
+ *(volatile unsigned short *)IRQ01_STS;
+ if (irq == IRQ0_IRQ){
+ if(intv & SMC_BIT ) {
+ return SMC_IRQ;
+ } else if(intv & USB_BIT) {
+ return USB_IRQ;
+ } else {
+ printk("intv =%04x\n", intv);
+ return SMC_IRQ;
+ }
+ } else if(irq == IRQ1_IRQ){
+ if(intv & MRSHPC_BIT0) {
+ return MRSHPC_IRQ0;
+ } else if(intv & MRSHPC_BIT1) {
+ return MRSHPC_IRQ1;
+ } else if(intv & MRSHPC_BIT2) {
+ return MRSHPC_IRQ2;
+ } else if(intv & MRSHPC_BIT3) {
+ return MRSHPC_IRQ3;
+ } else {
+ printk("BIT_EXTENTION =%04x\n", intv);
+ return EXT_IRQ;
+ }
+ }
+ }
+ return irq;
+
+}
+/*
+ * Initialize IRQ setting
+ */
+void __init init_se7722_IRQ(void)
+{
+ int i = 0;
+ ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */
+ ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0); /* irq0 pri=3,irq1,pri=3 */
+ ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1); /* irq0,1 low-level irq */
+
+ for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) {
+ disable_irq_nosync(ipr_irq_table[i].irq);
+ set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip,
+ handle_level_irq, "level");
+ set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] );
+ disable_se7722_irq(ipr_irq_table[i].irq);
+ }
+}
diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c
new file mode 100644
index 00000000000..636ca6c987e
--- /dev/null
+++ b/arch/sh/boards/se/7722/setup.c
@@ -0,0 +1,148 @@
+/*
+ * linux/arch/sh/boards/se/7722/setup.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7722 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/pata_platform.h>
+#include <asm/machvec.h>
+#include <asm/se7722.h>
+#include <asm/io.h>
+
+/* Heartbeat */
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+static struct resource heartbeat_resources[] = {
+ [0] = {
+ .start = PA_LED,
+ .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .dev = {
+ .platform_data = heartbeat_bit_pos,
+ },
+ .num_resources = ARRAY_SIZE(heartbeat_resources),
+ .resource = heartbeat_resources,
+};
+
+/* SMC91x */
+static struct resource smc91x_eth_resources[] = {
+ [0] = {
+ .name = "smc91x-regs" ,
+ .start = PA_LAN + 0x300,
+ .end = PA_LAN + 0x300 + 0x10 ,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = SMC_IRQ,
+ .end = SMC_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_eth_device = {
+ .name = "smc91x",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(smc91x_eth_resources),
+ .resource = smc91x_eth_resources,
+};
+
+static struct resource cf_ide_resources[] = {
+ [0] = {
+ .start = PA_MRSHPC_IO + 0x1f0,
+ .end = PA_MRSHPC_IO + 0x1f0 + 8 ,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = PA_MRSHPC_IO + 0x1f0 + 0x206,
+ .end = PA_MRSHPC_IO + 0x1f0 +8 + 0x206 + 8,
+ .flags = IORESOURCE_IO,
+ },
+ [2] = {
+ .start = MRSHPC_IRQ0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cf_ide_device = {
+ .name = "pata_platform",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(cf_ide_resources),
+ .resource = cf_ide_resources,
+};
+
+static struct platform_device *se7722_devices[] __initdata = {
+ &heartbeat_device,
+ &smc91x_eth_device,
+ &cf_ide_device,
+};
+
+static int __init se7722_devices_setup(void)
+{
+ return platform_add_devices(se7722_devices,
+ ARRAY_SIZE(se7722_devices));
+}
+device_initcall(se7722_devices_setup);
+
+static void __init se7722_setup(char **cmdline_p)
+{
+ ctrl_outw(0x010D, FPGA_OUT); /* FPGA */
+
+ ctrl_outl(0x00051001, MSTPCR0);
+ ctrl_outl(0x00000000, MSTPCR1);
+ /* KEYSC, VOU, BEU, CEU, VEU, VPU, LCDC */
+ ctrl_outl(0xffffbfC0, MSTPCR2);
+
+ ctrl_outw(0x0000, PORT_PECR); /* PORT E 1 = IRQ5 ,E 0 = BS */
+ ctrl_outw(0x1000, PORT_PJCR); /* PORT J 1 = IRQ1,J 0 =IRQ0 */
+
+ /* LCDC I/O */
+ ctrl_outw(0x0020, PORT_PSELD);
+
+ /* SIOF1*/
+ ctrl_outw(0x0003, PORT_PSELB);
+ ctrl_outw(0xe000, PORT_PSELC);
+ ctrl_outw(0x0000, PORT_PKCR);
+
+ /* LCDC */
+ ctrl_outw(0x4020, PORT_PHCR);
+ ctrl_outw(0x0000, PORT_PLCR);
+ ctrl_outw(0x0000, PORT_PMCR);
+ ctrl_outw(0x0002, PORT_PRCR);
+ ctrl_outw(0x0000, PORT_PXCR); /* LCDC,CS6A */
+
+ /* KEYSC */
+ ctrl_outw(0x0A10, PORT_PSELA); /* BS,SHHID2 */
+ ctrl_outw(0x0000, PORT_PYCR);
+ ctrl_outw(0x0000, PORT_PZCR);
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_se7722 __initmv = {
+ .mv_name = "Solution Engine 7722" ,
+ .mv_setup = se7722_setup ,
+ .mv_nr_irqs = 109 ,
+ .mv_init_irq = init_se7722_IRQ,
+ .mv_irq_demux = se7722_irq_demux,
+
+};
+ALIAS_MV(se7722)
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
index e3feae6ec0b..52c7bfa57c2 100644
--- a/arch/sh/boards/se/7751/setup.c
+++ b/arch/sh/boards/se/7751/setup.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/setup_7751se.c
+ * linux/arch/sh/boards/se/7751/setup.c
*
* Copyright (C) 2000 Kazumoto Kojima
*
@@ -14,153 +14,6 @@
#include <asm/se7751.h>
#include <asm/io.h>
-void init_7751se_IRQ(void);
-
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-static int kgdb_uart_setup(void);
-static struct kgdb_sermap kgdb_uart_sermap =
-{ "ttyS", 0, kgdb_uart_setup, NULL };
-#endif
-
-/*
- * Initialize the board
- */
-static void __init sh7751se_setup(char **cmdline_p)
-{
- /* Call init_smsc() replacement to set up SuperIO. */
- /* XXX: RTC setting comes here */
-#ifdef CONFIG_SH_KGDB
- kgdb_register_sermap(&kgdb_uart_sermap);
-#endif
-}
-
-/*********************************************************************
- * Currently a hack (e.g. does not interact well w/serial.c, lots of *
- * hardcoded stuff) but may be useful if SCI/F needs debugging. *
- * Mostly copied from x86 code (see files asm-i386/kgdb_local.h and *
- * arch/i386/lib/kgdb_serial.c). *
- *********************************************************************/
-
-#ifdef CONFIG_SH_KGDB
-#include <linux/types.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/serial_reg.h>
-
-#define COM1_PORT 0x3f8 /* Base I/O address */
-#define COM1_IRQ 4 /* IRQ not used yet */
-#define COM2_PORT 0x2f8 /* Base I/O address */
-#define COM2_IRQ 3 /* IRQ not used yet */
-
-#define SB_CLOCK 1843200 /* Serial baud clock */
-#define SB_BASE (SB_CLOCK/16)
-#define SB_MCR UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS
-
-struct uart_port {
- int base;
-};
-#define UART_NPORTS 2
-struct uart_port uart_ports[] = {
- { COM1_PORT },
- { COM2_PORT },
-};
-struct uart_port *kgdb_uart_port;
-
-#define UART_IN(reg) inb_p(kgdb_uart_port->base + reg)
-#define UART_OUT(reg,v) outb_p((v), kgdb_uart_port->base + reg)
-
-/* Basic read/write functions for the UART */
-#define UART_LSR_RXCERR (UART_LSR_BI | UART_LSR_FE | UART_LSR_PE)
-static int kgdb_uart_getchar(void)
-{
- int lsr;
- int c = -1;
-
- while (c == -1) {
- lsr = UART_IN(UART_LSR);
- if (lsr & UART_LSR_DR)
- c = UART_IN(UART_RX);
- if ((lsr & UART_LSR_RXCERR))
- c = -1;
- }
- return c;
-}
-
-static void kgdb_uart_putchar(int c)
-{
- while ((UART_IN(UART_LSR) & UART_LSR_THRE) == 0)
- ;
- UART_OUT(UART_TX, c);
-}
-
-/*
- * Initialize UART to configured/requested values.
- * (But we don't interrupts yet, or interact w/serial.c)
- */
-static int kgdb_uart_setup(void)
-{
- int port;
- int lcr = 0;
- int bdiv = 0;
-
- if (kgdb_portnum >= UART_NPORTS) {
- KGDB_PRINTK("uart port %d invalid.\n", kgdb_portnum);
- return -1;
- }
-
- kgdb_uart_port = &uart_ports[kgdb_portnum];
-
- /* Init sequence from gdb_hook_interrupt */
- UART_IN(UART_RX);
- UART_OUT(UART_IER, 0);
-
- UART_IN(UART_RX); /* Serial driver comments say */
- UART_IN(UART_IIR); /* this clears interrupt regs */
- UART_IN(UART_MSR);
-
- /* Figure basic LCR values */
- switch (kgdb_bits) {
- case '7':
- lcr |= UART_LCR_WLEN7;
- break;
- default: case '8':
- lcr |= UART_LCR_WLEN8;
- break;
- }
- switch (kgdb_parity) {
- case 'O':
- lcr |= UART_LCR_PARITY;
- break;
- case 'E':
- lcr |= (UART_LCR_PARITY | UART_LCR_EPAR);
- break;
- default: break;
- }
-
- /* Figure the baud rate divisor */
- bdiv = (SB_BASE/kgdb_baud);
-
- /* Set the baud rate and LCR values */
- UART_OUT(UART_LCR, (lcr | UART_LCR_DLAB));
- UART_OUT(UART_DLL, (bdiv & 0xff));
- UART_OUT(UART_DLM, ((bdiv >> 8) & 0xff));
- UART_OUT(UART_LCR, lcr);
-
- /* Set the MCR */
- UART_OUT(UART_MCR, SB_MCR);
-
- /* Turn off FIFOs for now */
- UART_OUT(UART_FCR, 0);
-
- /* Setup complete: initialize function pointers */
- kgdb_getchar = kgdb_uart_getchar;
- kgdb_putchar = kgdb_uart_putchar;
-
- return 0;
-}
-#endif /* CONFIG_SH_KGDB */
-
static unsigned char heartbeat_bit_pos[] = { 8, 9, 10, 11, 12, 13, 14, 15 };
static struct resource heartbeat_resources[] = {
@@ -197,7 +50,6 @@ __initcall(se7751_devices_setup);
*/
struct sh_machine_vector mv_7751se __initmv = {
.mv_name = "7751 SolutionEngine",
- .mv_setup = sh7751se_setup,
.mv_nr_irqs = 72,
.mv_inb = sh7751se_inb,
diff --git a/arch/sh/boards/se/7780/Makefile b/arch/sh/boards/se/7780/Makefile
new file mode 100644
index 00000000000..6b88adae3ec
--- /dev/null
+++ b/arch/sh/boards/se/7780/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the HITACHI UL SolutionEngine 7780 specific parts of the kernel
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+#
+
+obj-y := setup.o irq.o
diff --git a/arch/sh/boards/se/7780/irq.c b/arch/sh/boards/se/7780/irq.c
new file mode 100644
index 00000000000..3d0625c2d07
--- /dev/null
+++ b/arch/sh/boards/se/7780/irq.c
@@ -0,0 +1,89 @@
+/*
+ * linux/arch/sh/boards/se/7780/irq.c
+ *
+ * Copyright (C) 2006,2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7780 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/se7780.h>
+
+#define INTC_INTMSK0 0xFFD00044
+#define INTC_INTMSKCLR0 0xFFD00064
+
+static void disable_se7780_irq(unsigned int irq)
+{
+ struct intc2_data *p = get_irq_chip_data(irq);
+ ctrl_outl(1 << p->msk_shift, INTC_INTMSK0 + p->msk_offset);
+}
+
+static void enable_se7780_irq(unsigned int irq)
+{
+ struct intc2_data *p = get_irq_chip_data(irq);
+ ctrl_outl(1 << p->msk_shift, INTC_INTMSKCLR0 + p->msk_offset);
+}
+
+static struct irq_chip se7780_irq_chip __read_mostly = {
+ .name = "SE7780",
+ .mask = disable_se7780_irq,
+ .unmask = enable_se7780_irq,
+ .mask_ack = disable_se7780_irq,
+};
+
+static struct intc2_data intc2_irq_table[] = {
+ { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */
+ { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */
+ { 6, 0, 29, 0, 29, 3 }, /* daughter board EXTINT3 */
+ { 8, 0, 28, 0, 28, 3 }, /* SMC 91C111 (LAN) */
+ { 10, 0, 27, 0, 27, 3 }, /* daughter board EXTINT4 */
+ { 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT5 */
+ { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT6 */
+ { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT7 */
+ { 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT8 */
+ { 0 , 0, 24, 0, 24, 3 }, /* SM501 */
+};
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_se7780_IRQ(void)
+{
+ int i ;
+
+ /* enable all interrupt at FPGA */
+ ctrl_outw(0, FPGA_INTMSK1);
+ /* mask SM501 interrupt */
+ ctrl_outw((ctrl_inw(FPGA_INTMSK1) | 0x0002), FPGA_INTMSK1);
+ /* enable all interrupt at FPGA */
+ ctrl_outw(0, FPGA_INTMSK2);
+
+ /* set FPGA INTSEL register */
+ /* FPGA + 0x06 */
+ ctrl_outw( ((IRQPIN_SM501 << IRQPOS_SM501) |
+ (IRQPIN_SMC91CX << IRQPOS_SMC91CX)), FPGA_INTSEL1);
+
+ /* FPGA + 0x08 */
+ ctrl_outw(((IRQPIN_EXTINT4 << IRQPOS_EXTINT4) |
+ (IRQPIN_EXTINT3 << IRQPOS_EXTINT3) |
+ (IRQPIN_EXTINT2 << IRQPOS_EXTINT2) |
+ (IRQPIN_EXTINT1 << IRQPOS_EXTINT1)), FPGA_INTSEL2);
+
+ /* FPGA + 0x0A */
+ ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3);
+
+ for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++) {
+ disable_irq_nosync(intc2_irq_table[i].irq);
+ set_irq_chip_and_handler_name( intc2_irq_table[i].irq, &se7780_irq_chip,
+ handle_level_irq, "level");
+ set_irq_chip_data( intc2_irq_table[i].irq, &intc2_irq_table[i] );
+ disable_se7780_irq(intc2_irq_table[i].irq);
+ }
+}
diff --git a/arch/sh/boards/se/7780/setup.c b/arch/sh/boards/se/7780/setup.c
new file mode 100644
index 00000000000..df7d08a24c9
--- /dev/null
+++ b/arch/sh/boards/se/7780/setup.c
@@ -0,0 +1,122 @@
+/*
+ * linux/arch/sh/boards/se/7780/setup.c
+ *
+ * Copyright (C) 2006,2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7780 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <asm/machvec.h>
+#include <asm/se7780.h>
+#include <asm/io.h>
+
+/* Heartbeat */
+static unsigned char heartbeat_bit_pos[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+static struct resource heartbeat_resources[] = {
+ [0] = {
+ .start = PA_LED,
+ .end = PA_LED + ARRAY_SIZE(heartbeat_bit_pos) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device heartbeat_device = {
+ .name = "heartbeat",
+ .id = -1,
+ .dev = {
+ .platform_data = heartbeat_bit_pos,
+ },
+ .num_resources = ARRAY_SIZE(heartbeat_resources),
+ .resource = heartbeat_resources,
+};
+
+/* SMC91x */
+static struct resource smc91x_eth_resources[] = {
+ [0] = {
+ .name = "smc91x-regs" ,
+ .start = PA_LAN + 0x300,
+ .end = PA_LAN + 0x300 + 0x10 ,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = SMC_IRQ,
+ .end = SMC_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_eth_device = {
+ .name = "smc91x",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(smc91x_eth_resources),
+ .resource = smc91x_eth_resources,
+};
+
+static struct platform_device *se7780_devices[] __initdata = {
+ &heartbeat_device,
+ &smc91x_eth_device,
+};
+
+static int __init se7780_devices_setup(void)
+{
+ return platform_add_devices(se7780_devices,
+ ARRAY_SIZE(se7780_devices));
+}
+device_initcall(se7780_devices_setup);
+
+#define GPIO_PHCR 0xFFEA000E
+#define GPIO_PMSELR 0xFFEA0080
+#define GPIO_PECR 0xFFEA0008
+
+static void __init se7780_setup(char **cmdline_p)
+{
+ /* "SH-Linux" on LED Display */
+ ctrl_outw( 'S' , PA_LED_DISP + (DISP_SEL0_ADDR << 1) );
+ ctrl_outw( 'H' , PA_LED_DISP + (DISP_SEL1_ADDR << 1) );
+ ctrl_outw( '-' , PA_LED_DISP + (DISP_SEL2_ADDR << 1) );
+ ctrl_outw( 'L' , PA_LED_DISP + (DISP_SEL3_ADDR << 1) );
+ ctrl_outw( 'i' , PA_LED_DISP + (DISP_SEL4_ADDR << 1) );
+ ctrl_outw( 'n' , PA_LED_DISP + (DISP_SEL5_ADDR << 1) );
+ ctrl_outw( 'u' , PA_LED_DISP + (DISP_SEL6_ADDR << 1) );
+ ctrl_outw( 'x' , PA_LED_DISP + (DISP_SEL7_ADDR << 1) );
+
+ printk(KERN_INFO "Hitachi UL Solutions Engine 7780SE03 support.\n");
+
+ /*
+ * PCI REQ/GNT setting
+ * REQ0/GNT0 -> USB
+ * REQ1/GNT1 -> PC Card
+ * REQ2/GNT2 -> Serial ATA
+ * REQ3/GNT3 -> PCI slot
+ */
+ ctrl_outw(0x0213, FPGA_REQSEL);
+
+ /* GPIO setting */
+ ctrl_outw(0x0000, GPIO_PECR);
+ ctrl_outw(ctrl_inw(GPIO_PHCR)&0xfff3, GPIO_PHCR);
+ ctrl_outw(0x0c00, GPIO_PMSELR);
+
+ /* iVDR Power ON */
+ ctrl_outw(0x0001, FPGA_IVDRPW);
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_se7780 __initmv = {
+ .mv_name = "Solution Engine 7780" ,
+ .mv_setup = se7780_setup ,
+ .mv_nr_irqs = 111 ,
+ .mv_init_irq = init_se7780_IRQ,
+};
+ALIAS_MV(se7780)
diff --git a/arch/sh/configs/lboxre2_defconfig b/arch/sh/configs/lboxre2_defconfig
new file mode 100644
index 00000000000..be86414dcc8
--- /dev/null
+++ b/arch/sh/configs/lboxre2_defconfig
@@ -0,0 +1,1271 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc4
+# Sat Mar 24 22:04:27 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_HIGHLANDER is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+CONFIG_SH_LBOX_RE2=y
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=40000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_KEXEC=y
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200 root=/dev/sda1"
+
+#
+# Bus options
+#
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+CONFIG_PCMCIA_DEBUG=y
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+CONFIG_YENTA_O2=y
+# CONFIG_YENTA_RICOH is not set
+# CONFIG_YENTA_TI is not set
+# CONFIG_YENTA_TOSHIBA is not set
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PROBE=y
+CONFIG_PCCARD_NONSTATIC=y
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PCMCIA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_QDI is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_WINBOND_VLB is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+CONFIG_NE2K_PCI=y
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+CONFIG_8139TOO_PIO=y
+CONFIG_8139TOO_TUNE_TWISTER=y
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+# CONFIG_PCMCIA_3C589 is not set
+# CONFIG_PCMCIA_3C574 is not set
+# CONFIG_PCMCIA_FMVJ18X is not set
+CONFIG_PCMCIA_PCNET=y
+# CONFIG_PCMCIA_NMCLAN is not set
+# CONFIG_PCMCIA_SMC91C92 is not set
+# CONFIG_PCMCIA_XIRC2PS is not set
+# CONFIG_PCMCIA_AXNET is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_SH is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
index 2b75b4896ba..48c6a2194c9 100644
--- a/arch/sh/configs/r7780rp_defconfig
+++ b/arch/sh/configs/r7780rp_defconfig
@@ -1,10 +1,11 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Wed Dec 6 11:59:38 2006
+# Linux kernel version: 2.6.21-rc7
+# Tue May 1 12:28:39 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
@@ -13,6 +14,8 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
# CONFIG_GENERIC_TIME is not set
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -31,6 +34,7 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
@@ -41,7 +45,7 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -99,23 +103,23 @@ CONFIG_DEFAULT_IOSCHED="noop"
# System type
#
# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7722_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7780_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
-CONFIG_SH_R7780RP=y
+CONFIG_SH_HIGHLANDER=y
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
# CONFIG_SH_LANDISK is not set
@@ -123,7 +127,11 @@ CONFIG_SH_R7780RP=y
# CONFIG_SH_SHMIN is not set
# CONFIG_SH_7206_SOLUTION_ENGINE is not set
# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
# CONFIG_SH_UNKNOWN is not set
+CONFIG_SH_R7780RP=y
+# CONFIG_SH_R7780MP is not set
+# CONFIG_SH_R7785RP is not set
#
# Processor selection
@@ -152,6 +160,7 @@ CONFIG_CPU_SH4A=y
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
#
# SH-4 Processor Support
@@ -183,6 +192,7 @@ CONFIG_CPU_SUBTYPE_SH7780=y
#
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
@@ -193,6 +203,8 @@ CONFIG_MEMORY_START=0x08000000
CONFIG_MEMORY_SIZE=0x08000000
# CONFIG_32BIT is not set
CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -210,6 +222,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
#
# Cache configuration
@@ -226,20 +239,15 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SH_FPU=y
# CONFIG_SH_DSP is not set
CONFIG_SH_STORE_QUEUES=y
+CONFIG_SPECULATIVE_EXECUTION=y
CONFIG_CPU_HAS_INTEVT=y
CONFIG_CPU_HAS_INTC2_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
-CONFIG_CPU_HAS_PTEA=y
#
-# Timer support
+# Timer and clock configuration
#
CONFIG_SH_TMU=y
-
-#
-# R7780RP options
-#
-CONFIG_SH_R7780MP=y
CONFIG_SH_TIMER_IRQ=28
CONFIG_NO_IDLE_HZ=y
CONFIG_SH_PCLK_FREQ=32000000
@@ -262,6 +270,7 @@ CONFIG_SH_PCLK_FREQ=32000000
#
# Additional SuperH Device Drivers
#
+# CONFIG_HEARTBEAT is not set
CONFIG_PUSH_SWITCH=y
#
@@ -269,9 +278,11 @@ CONFIG_PUSH_SWITCH=y
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
# CONFIG_SMP is not set
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
@@ -294,7 +305,6 @@ CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -334,6 +344,7 @@ CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -425,6 +436,7 @@ CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=m
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
#
@@ -445,6 +457,7 @@ CONFIG_FW_LOADER=m
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -461,7 +474,6 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -481,6 +493,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -500,6 +513,7 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_MULTI_LUN is not set
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
#
# SCSI Transports
@@ -544,11 +558,13 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
#
# Serial ATA (prod) and Parallel ATA (experimental) drivers
#
CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_AHCI is not set
# CONFIG_SATA_SVW is not set
# CONFIG_ATA_PIIX is not set
@@ -564,6 +580,7 @@ CONFIG_SATA_SIL=y
# CONFIG_SATA_ULI is not set
# CONFIG_SATA_VIA is not set
# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
@@ -579,6 +596,7 @@ CONFIG_SATA_SIL=y
# CONFIG_PATA_HPT3X2N is not set
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
# CONFIG_PATA_JMICRON is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_MARVELL is not set
@@ -685,6 +703,7 @@ CONFIG_8139TOO_8129=y
CONFIG_VIA_RHINE=m
CONFIG_VIA_RHINE_MMIO=y
# CONFIG_VIA_RHINE_NAPI is not set
+# CONFIG_SC92031 is not set
#
# Ethernet (1000 Mbit)
@@ -707,11 +726,13 @@ CONFIG_R8169=y
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
@@ -889,10 +910,16 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -905,9 +932,8 @@ CONFIG_HWMON=y
#
# Graphics support
#
-CONFIG_FIRMWARE_EDID=y
-# CONFIG_FB is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
#
# Sound
@@ -923,9 +949,8 @@ CONFIG_SOUND=m
# Open Sound System
#
CONFIG_SOUND_PRIME=m
-# CONFIG_OSS_OBSOLETE_DRIVER is not set
+# CONFIG_OBSOLETE_OSS is not set
# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_ES1371 is not set
# CONFIG_SOUND_ICH is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
@@ -933,6 +958,12 @@ CONFIG_SOUND_PRIME=m
# CONFIG_SOUND_VIA82CXXX is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1017,6 +1048,14 @@ CONFIG_RTC_DRV_SH=y
#
#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1175,6 +1214,11 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
CONFIG_PROFILING=y
@@ -1184,19 +1228,22 @@ CONFIG_OPROFILE=m
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
-# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_PROVE_LOCKING is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
@@ -1204,19 +1251,19 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
-CONFIG_FRAME_POINTER=y
+# CONFIG_FRAME_POINTER is not set
CONFIG_FORCED_INLINING=y
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
-# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_PRINTK=y
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_4KSTACKS is not set
-# CONFIG_KGDB is not set
+# CONFIG_SH_KGDB is not set
#
# Security options
@@ -1233,6 +1280,7 @@ CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=y
@@ -1241,9 +1289,13 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
@@ -1257,6 +1309,7 @@ CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
#
@@ -1266,7 +1319,10 @@ CONFIG_CRYPTO_DES=y
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
new file mode 100644
index 00000000000..0f5ec649daf
--- /dev/null
+++ b/arch/sh/configs/r7785rp_defconfig
@@ -0,0 +1,1334 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Mon Mar 12 14:26:33 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+CONFIG_SH_HIGHLANDER=y
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_UNKNOWN is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_R7780MP is not set
+CONFIG_SH_R7785RP=y
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX2=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+CONFIG_CPU_SUBTYPE_SH7785=y
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_32BIT=y
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+CONFIG_HUGETLB_PAGE_SIZE_1MB=y
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+CONFIG_NO_IDLE_HZ=y
+CONFIG_SH_PCLK_FREQ=50000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+CONFIG_PUSH_SWITCH=y
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_KEXEC=y
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+# CONFIG_R8169_NAPI is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frambuffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_EPSON1355 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OBSOLETE_OSS is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_SH=y
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+# CONFIG_PROVE_LOCKING is not set
+CONFIG_LOCKDEP=y
+# CONFIG_DEBUG_LOCKDEP is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_4KSTACKS is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig
index 06ebd6ec0cd..87ae5c1f862 100644
--- a/arch/sh/configs/se7705_defconfig
+++ b/arch/sh/configs/se7705_defconfig
@@ -1,15 +1,21 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct 3 12:03:04 2006
+# Linux kernel version: 2.6.21-rc5
+# Thu Apr 26 09:16:31 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -33,7 +39,9 @@ CONFIG_LOCALVERSION_AUTO=y
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
@@ -91,27 +99,30 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_SOLUTION_ENGINE=y
CONFIG_SH_SOLUTION_ENGINE=y
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7780_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7722_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_HIGHLANDER is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
# CONFIG_SH_LANDISK is not set
# CONFIG_SH_TITAN is not set
# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
# CONFIG_SH_UNKNOWN is not set
#
@@ -123,6 +134,12 @@ CONFIG_CPU_SH3=y
# SH-2 Processor Support
#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
#
# SH-3 Processor Support
@@ -134,6 +151,7 @@ CONFIG_CPU_SUBTYPE_SH7705=y
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
#
# SH-4 Processor Support
@@ -158,12 +176,14 @@ CONFIG_CPU_SUBTYPE_SH7705=y
#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
#
# SH4AL-DSP Processor Support
#
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
@@ -173,6 +193,11 @@ CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x02000000
CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -182,6 +207,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
#
# Cache configuration
@@ -190,23 +216,31 @@ CONFIG_SH7705_CACHE_32KB=y
# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
-# CONFIG_CF_ENABLER is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+# CONFIG_CF_AREA4 is not set
+CONFIG_CF_BASE_ADDR=0xb8000000
#
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
# CONFIG_SH_FPU_EMU is not set
# CONFIG_SH_DSP is not set
# CONFIG_SH_ADC is not set
CONFIG_CPU_HAS_INTEVT=y
CONFIG_CPU_HAS_PINT_IRQ=y
+CONFIG_CPU_HAS_IPR_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
#
-# Timer support
+# Timer and clock configuration
#
CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
CONFIG_SH_PCLK_FREQ=33333333
#
@@ -223,13 +257,19 @@ CONFIG_SH_PCLK_FREQ=33333333
# Companion Chips
#
# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
#
# Kernel features
#
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
# CONFIG_KEXEC is not set
@@ -287,6 +327,7 @@ CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -307,11 +348,13 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -388,6 +431,7 @@ CONFIG_MTD_PARTITIONS=y
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
@@ -461,6 +505,7 @@ CONFIG_MTD_CFI_UTIL=y
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -472,11 +517,14 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+
+#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -649,17 +697,12 @@ CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_RAW_DRIVER is not set
#
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -675,6 +718,7 @@ CONFIG_HW_RANDOM=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -683,18 +727,19 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
-# Misc devices
+# Multifunction device drivers
#
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -704,7 +749,7 @@ CONFIG_VIDEO_V4L2=y
#
# Graphics support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
# CONFIG_FB is not set
#
@@ -713,6 +758,12 @@ CONFIG_FIRMWARE_EDID=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
# USB support
#
# CONFIG_USB_ARCH_HAS_HCD is not set
@@ -773,16 +824,26 @@ CONFIG_FIRMWARE_EDID=y
#
#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
@@ -828,7 +889,6 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -878,6 +938,10 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -885,15 +949,18 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_SH_STANDARD_BIOS is not set
-# CONFIG_KGDB is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
#
# Security options
@@ -908,6 +975,7 @@ CONFIG_LOG_BUF_SHIFT=14
#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_CRC_CCITT=y
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
@@ -915,3 +983,5 @@ CONFIG_CRC32=y
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7712_defconfig b/arch/sh/configs/se7712_defconfig
new file mode 100644
index 00000000000..a5e37dbc535
--- /dev/null
+++ b/arch/sh/configs/se7712_defconfig
@@ -0,0 +1,1088 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc4
+# Wed Mar 28 10:19:02 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_SHMEM is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+CONFIG_SOLUTION_ENGINE=y
+CONFIG_SH_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_HIGHLANDER is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH3=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+CONFIG_CPU_SUBTYPE_SH7712=y
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+CONFIG_CF_BASE_ADDR=0xb8000000
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_SH_FPU_EMU is not set
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_ADC is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FIFO=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_HFSC=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_RED=y
+CONFIG_NET_SCH_SFQ=y
+CONFIG_NET_SCH_TEQL=y
+CONFIG_NET_SCH_TBF=y
+CONFIG_NET_SCH_GRED=y
+CONFIG_NET_SCH_DSMARK=y
+CONFIG_NET_SCH_NETEM=y
+CONFIG_NET_SCH_INGRESS=y
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_ROUTE4=y
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=y
+# CONFIG_NET_CLS_U32 is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_POLICE is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7722_defconfig b/arch/sh/configs/se7722_defconfig
new file mode 100644
index 00000000000..ca4c663dfa3
--- /dev/null
+++ b/arch/sh/configs/se7722_defconfig
@@ -0,0 +1,980 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc7
+# Fri Apr 27 16:30:30 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+CONFIG_SOLUTION_ENGINE=y
+# CONFIG_SH_SOLUTION_ENGINE is not set
+CONFIG_SH_7722_SOLUTION_ENGINE=y
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7780_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_HIGHLANDER is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_LBOX_RE2 is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SH4AL_DSP=y
+CONFIG_CPU_SHX2=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+CONFIG_CPU_SUBTYPE_SH7722=y
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+# CONFIG_32BIT is not set
+# CONFIG_X2TLB is not set
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+CONFIG_CF_BASE_ADDR=0xb8000000
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_NO_IDLE_HZ=y
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_SH=y
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig
new file mode 100644
index 00000000000..538661e9879
--- /dev/null
+++ b/arch/sh/configs/se7780_defconfig
@@ -0,0 +1,1309 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21-rc3
+# Thu Mar 15 14:06:20 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# System type
+#
+CONFIG_SOLUTION_ENGINE=y
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+CONFIG_SH_7780_SOLUTION_ENGINE=y
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_HIGHLANDER is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_7206_SOLUTION_ENGINE is not set
+# CONFIG_SH_7619_SOLUTION_ENGINE is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+
+#
+# SH-2A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_32BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00810000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_2 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNPACPI is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_SMC91X=y
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frambuffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_EPSON1355 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_LOGO_SUPERH_MONO is not set
+# CONFIG_LOGO_SUPERH_VGA16 is not set
+CONFIG_LOGO_SUPERH_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_OBSOLETE_OSS is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+# CONFIG_SYSFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/sh/drivers/Kconfig b/arch/sh/drivers/Kconfig
index c54c758e624..420c6b2f33a 100644
--- a/arch/sh/drivers/Kconfig
+++ b/arch/sh/drivers/Kconfig
@@ -1,5 +1,15 @@
+source "arch/sh/drivers/dma/Kconfig"
+source "arch/sh/cchips/Kconfig"
+
menu "Additional SuperH Device Drivers"
+config HEARTBEAT
+ bool "Heartbeat LED"
+ help
+ Use the power-on LED on your machine as a load meter. The exact
+ behavior is platform-dependent, but normally the flash frequency is
+ a hyperbolic function of the 5-minute load average.
+
config PUSH_SWITCH
tristate "Push switch support"
help
diff --git a/arch/sh/drivers/Makefile b/arch/sh/drivers/Makefile
index 6cb92676c5f..e13f06bebd9 100644
--- a/arch/sh/drivers/Makefile
+++ b/arch/sh/drivers/Makefile
@@ -2,8 +2,9 @@
# Makefile for the Linux SuperH-specific device drivers.
#
+obj-y += dma/
+
obj-$(CONFIG_PCI) += pci/
-obj-$(CONFIG_SH_DMA) += dma/
obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_PUSH_SWITCH) += push-switch.o
obj-$(CONFIG_HEARTBEAT) += heartbeat.o
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index defc13c37d4..99935f9daf4 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -1,12 +1,12 @@
menu "DMA support"
-config SH_DMA
- bool "DMA controller (DMAC) support"
- help
- Selecting this option will provide same API as PC's Direct Memory
- Access Controller(8237A) for SuperH DMAC.
+config SH_DMA_API
+ bool
- If unsure, say N.
+config SH_DMA
+ bool "SuperH on-chip DMA controller (DMAC) support"
+ select SH_DMA_API
+ default n
config NR_ONCHIP_DMA_CHANNELS
depends on SH_DMA
@@ -53,4 +53,12 @@ config DMA_PAGE_OPS_CHANNEL
in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
are dual-address capable.
+config SH_DMABRG
+ bool "SH7760 DMABRG support"
+ depends on CPU_SUBTYPE_SH7760
+ help
+ The DMABRG does data transfers from main memory to Audio/USB units
+ of the SH7760.
+ Say Y if you want to use Audio/USB DMA on your SH7760 board.
+
endmenu
diff --git a/arch/sh/drivers/dma/Makefile b/arch/sh/drivers/dma/Makefile
index db1295d3226..1ac812d2448 100644
--- a/arch/sh/drivers/dma/Makefile
+++ b/arch/sh/drivers/dma/Makefile
@@ -2,8 +2,8 @@
# Makefile for the SuperH DMA specific kernel interface routines under Linux.
#
-obj-y += dma-api.o
+obj-$(CONFIG_SH_DMA_API) += dma-api.o dma-sysfs.o
obj-$(CONFIG_ISA_DMA_API) += dma-isa.o
-obj-$(CONFIG_SYSFS) += dma-sysfs.o
obj-$(CONFIG_SH_DMA) += dma-sh.o
obj-$(CONFIG_SH_DREAMCAST) += dma-pvr2.o dma-g2.o
+obj-$(CONFIG_SH_DMABRG) += dmabrg.o
diff --git a/arch/sh/drivers/dma/dmabrg.c b/arch/sh/drivers/dma/dmabrg.c
new file mode 100644
index 00000000000..9d0a29370f2
--- /dev/null
+++ b/arch/sh/drivers/dma/dmabrg.c
@@ -0,0 +1,196 @@
+/*
+ * SH7760 DMABRG IRQ handling
+ *
+ * (c) 2007 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
+ * licensed under the GPLv2.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <asm/dma.h>
+#include <asm/dmabrg.h>
+#include <asm/io.h>
+
+/*
+ * The DMABRG is a special DMA unit within the SH7760. It does transfers
+ * from USB-SRAM/Audio units to main memory (and also the LCDC; but that
+ * part is sensibly placed in the LCDC registers and requires no irqs)
+ * It has 3 IRQ lines which trigger 10 events, and works independently
+ * from the traditional SH DMAC (although it blocks usage of DMAC 0)
+ *
+ * BRGIRQID | component | dir | meaning | source
+ * -----------------------------------------------------
+ * 0 | USB-DMA | ... | xfer done | DMABRGI1
+ * 1 | USB-UAE | ... | USB addr err.| DMABRGI0
+ * 2 | HAC0/SSI0 | play| all done | DMABRGI1
+ * 3 | HAC0/SSI0 | play| half done | DMABRGI2
+ * 4 | HAC0/SSI0 | rec | all done | DMABRGI1
+ * 5 | HAC0/SSI0 | rec | half done | DMABRGI2
+ * 6 | HAC1/SSI1 | play| all done | DMABRGI1
+ * 7 | HAC1/SSI1 | play| half done | DMABRGI2
+ * 8 | HAC1/SSI1 | rec | all done | DMABRGI1
+ * 9 | HAC1/SSI1 | rec | half done | DMABRGI2
+ *
+ * all can be enabled/disabled in the DMABRGCR register,
+ * as well as checked if they occured.
+ *
+ * DMABRGI0 services USB DMA Address errors, but it still must be
+ * enabled/acked in the DMABRGCR register. USB-DMA complete indicator
+ * is grouped together with the audio buffer end indicators, too bad...
+ *
+ * DMABRGCR: Bits 31-24: audio-dma ENABLE flags,
+ * Bits 23-16: audio-dma STATUS flags,
+ * Bits 9-8: USB error/xfer ENABLE,
+ * Bits 1-0: USB error/xfer STATUS.
+ * Ack an IRQ by writing 0 to the STATUS flag.
+ * Mask IRQ by writing 0 to ENABLE flag.
+ *
+ * Usage is almost like with any other IRQ:
+ * dmabrg_request_irq(BRGIRQID, handler, data)
+ * dmabrg_free_irq(BRGIRQID)
+ *
+ * handler prototype: void brgirqhandler(void *data)
+ */
+
+#define DMARSRA 0xfe090000
+#define DMAOR 0xffa00040
+#define DMACHCR0 0xffa0000c
+#define DMABRGCR 0xfe3c0000
+
+#define DMAOR_BRG 0x0000c000
+#define DMAOR_DMEN 0x00000001
+
+#define DMABRGI0 68
+#define DMABRGI1 69
+#define DMABRGI2 70
+
+struct dmabrg_handler {
+ void (*handler)(void *);
+ void *data;
+} *dmabrg_handlers;
+
+static inline void dmabrg_call_handler(int i)
+{
+ dmabrg_handlers[i].handler(dmabrg_handlers[i].data);
+}
+
+/*
+ * main DMABRG irq handler. It acks irqs and then
+ * handles every set and unmasked bit sequentially.
+ * No locking and no validity checks; it should be
+ * as fast as possible (audio!)
+ */
+static irqreturn_t dmabrg_irq(int irq, void *data)
+{
+ unsigned long dcr;
+ unsigned int i;
+
+ dcr = ctrl_inl(DMABRGCR);
+ ctrl_outl(dcr & ~0x00ff0003, DMABRGCR); /* ack all */
+ dcr &= dcr >> 8; /* ignore masked */
+
+ /* USB stuff, get it out of the way first */
+ if (dcr & 1)
+ dmabrg_call_handler(DMABRGIRQ_USBDMA);
+ if (dcr & 2)
+ dmabrg_call_handler(DMABRGIRQ_USBDMAERR);
+
+ /* Audio */
+ dcr >>= 16;
+ while (dcr) {
+ i = __ffs(dcr);
+ dcr &= dcr - 1;
+ dmabrg_call_handler(i + DMABRGIRQ_A0TXF);
+ }
+ return IRQ_HANDLED;
+}
+
+static void dmabrg_disable_irq(unsigned int dmairq)
+{
+ unsigned long dcr;
+ dcr = ctrl_inl(DMABRGCR);
+ dcr &= ~(1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
+ ctrl_outl(dcr, DMABRGCR);
+}
+
+static void dmabrg_enable_irq(unsigned int dmairq)
+{
+ unsigned long dcr;
+ dcr = ctrl_inl(DMABRGCR);
+ dcr |= (1 << ((dmairq > 1) ? dmairq + 22 : dmairq + 8));
+ ctrl_outl(dcr, DMABRGCR);
+}
+
+int dmabrg_request_irq(unsigned int dmairq, void(*handler)(void*),
+ void *data)
+{
+ if ((dmairq > 9) || !handler)
+ return -ENOENT;
+ if (dmabrg_handlers[dmairq].handler)
+ return -EBUSY;
+
+ dmabrg_handlers[dmairq].handler = handler;
+ dmabrg_handlers[dmairq].data = data;
+
+ dmabrg_enable_irq(dmairq);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dmabrg_request_irq);
+
+void dmabrg_free_irq(unsigned int dmairq)
+{
+ if (likely(dmairq < 10)) {
+ dmabrg_disable_irq(dmairq);
+ dmabrg_handlers[dmairq].handler = NULL;
+ dmabrg_handlers[dmairq].data = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(dmabrg_free_irq);
+
+static int __init dmabrg_init(void)
+{
+ unsigned long or;
+ int ret;
+
+ dmabrg_handlers = kzalloc(10 * sizeof(struct dmabrg_handler),
+ GFP_KERNEL);
+ if (!dmabrg_handlers)
+ return -ENOMEM;
+
+#ifdef CONFIG_SH_DMA
+ /* request DMAC channel 0 before anyone else can get it */
+ ret = request_dma(0, "DMAC 0 (DMABRG)");
+ if (ret < 0)
+ printk(KERN_INFO "DMABRG: DMAC ch0 not reserved!\n");
+#endif
+
+ ctrl_outl(0, DMABRGCR);
+ ctrl_outl(0, DMACHCR0);
+ ctrl_outl(0x94000000, DMARSRA); /* enable DMABRG in DMAC 0 */
+
+ /* enable DMABRG mode, enable the DMAC */
+ or = ctrl_inl(DMAOR);
+ ctrl_outl(or | DMAOR_BRG | DMAOR_DMEN, DMAOR);
+
+ ret = request_irq(DMABRGI0, dmabrg_irq, IRQF_DISABLED,
+ "DMABRG USB address error", NULL);
+ if (ret)
+ goto out0;
+
+ ret = request_irq(DMABRGI1, dmabrg_irq, IRQF_DISABLED,
+ "DMABRG Transfer End", NULL);
+ if (ret)
+ goto out1;
+
+ ret = request_irq(DMABRGI2, dmabrg_irq, IRQF_DISABLED,
+ "DMABRG Transfer Half", NULL);
+ if (ret == 0)
+ return ret;
+
+ free_irq(DMABRGI1, 0);
+out1: free_irq(DMABRGI0, 0);
+out0: kfree(dmabrg_handlers);
+ return ret;
+}
+subsys_initcall(dmabrg_init);
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c
index bc59cb6cd78..23dd6080422 100644
--- a/arch/sh/drivers/heartbeat.c
+++ b/arch/sh/drivers/heartbeat.c
@@ -40,16 +40,9 @@ static void heartbeat_timer(unsigned long data)
static unsigned bit = 0, up = 1;
ctrl_outw(1 << hd->bit_pos[bit], (unsigned long)hd->base);
- if (up)
- if (bit == (ARRAY_SIZE(hd->bit_pos) - 1)) {
- bit--;
- up = 0;
- } else
- bit++;
- else if (bit == 0)
- up = 1;
- else
- bit--;
+ bit += up;
+ if ((bit == 0) || (bit == ARRAY_SIZE(hd->bit_pos)-1))
+ up = -up;
mod_timer(&hd->timer, jiffies + (110 - ((300 << FSHIFT) /
((avenrun[0] / 5) + (3 << FSHIFT)))));
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index cc8d0d0b142..0e9b532b9fb 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -8,12 +8,15 @@ obj-$(CONFIG_PCI_AUTO) += pci-auto.o
obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7785) += pci-sh7780.o ops-sh4.o
obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \
dma-dreamcast.o
obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o
obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o
obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o
-obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o
+obj-$(CONFIG_SH_HIGHLANDER) += ops-r7780rp.o fixups-r7780rp.o
obj-$(CONFIG_SH_TITAN) += ops-titan.o
obj-$(CONFIG_SH_LANDISK) += ops-landisk.o
+obj-$(CONFIG_SH_LBOX_RE2) += ops-lboxre2.o fixups-lboxre2.o
+obj-$(CONFIG_SH_7780_SOLUTION_ENGINE) += ops-se7780.o fixups-se7780.o
diff --git a/arch/sh/drivers/pci/fixups-lboxre2.c b/arch/sh/drivers/pci/fixups-lboxre2.c
new file mode 100644
index 00000000000..40b19bdfb89
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-lboxre2.c
@@ -0,0 +1,41 @@
+/*
+ * arch/sh/drivers/pci/fixups-lboxre2.c
+ *
+ * L-BOX RE2 PCI fixups
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include "pci-sh4.h"
+
+#define PCIMCR_MRSET_OFF 0xBFFFFFFF
+#define PCIMCR_RFSH_OFF 0xFFFFFFFB
+
+int pci_fixup_pcic(void)
+{
+ unsigned long bcr1, mcr;
+
+ bcr1 = inl(SH7751_BCR1);
+ bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
+ pci_write_reg(bcr1, SH4_PCIBCR1);
+
+ /* Enable all interrupts, so we known what to fix */
+ pci_write_reg(0x0000c3ff, SH4_PCIINTM);
+ pci_write_reg(0x0000380f, SH4_PCIAINTM);
+ pci_write_reg(0xfb900047, SH7751_PCICONF1);
+ pci_write_reg(0xab000001, SH7751_PCICONF4);
+
+ mcr = inl(SH7751_MCR);
+ mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
+ pci_write_reg(mcr, SH4_PCIMCR);
+
+ pci_write_reg(0x0c000000, SH7751_PCICONF5);
+ pci_write_reg(0xd0000000, SH7751_PCICONF6);
+ pci_write_reg(0x0c000000, SH4_PCILAR0);
+ pci_write_reg(0x00000000, SH4_PCILAR1);
+
+ return 0;
+}
diff --git a/arch/sh/drivers/pci/fixups-se7780.c b/arch/sh/drivers/pci/fixups-se7780.c
new file mode 100644
index 00000000000..880cea1c0d8
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-se7780.c
@@ -0,0 +1,60 @@
+/*
+ * arch/sh/drivers/pci/fixups-se7780.c
+ *
+ * HITACHI UL Solution Engine 7780 PCI fixups
+ *
+ * Copyright (C) 2003 Lineo uSolutions, Inc.
+ * Copyright (C) 2004 - 2006 Paul Mundt
+ * Copyright (C) 2006 Nobuhiro Iwamatsu
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/pci.h>
+#include "pci-sh4.h"
+#include <asm/io.h>
+
+int pci_fixup_pcic(void)
+{
+ ctrl_outl(0x00000001, SH7780_PCI_VCR2);
+
+ /* Enable all interrupts, so we know what to fix */
+ pci_write_reg(0x0000C3FF, SH7780_PCIIMR);
+ pci_write_reg(0x0000380F, SH7780_PCIAINTM);
+
+ /* Set up standard PCI config registers */
+ ctrl_outw(0xFB00, PCI_REG(SH7780_PCISTATUS));
+ ctrl_outw(0x0047, PCI_REG(SH7780_PCICMD));
+ ctrl_outb( 0x00, PCI_REG(SH7780_PCIPIF));
+ ctrl_outb( 0x00, PCI_REG(SH7780_PCISUB));
+ ctrl_outb( 0x06, PCI_REG(SH7780_PCIBCC));
+ ctrl_outw(0x1912, PCI_REG(SH7780_PCISVID));
+ ctrl_outw(0x0001, PCI_REG(SH7780_PCISID));
+
+ pci_write_reg(0x08000000, SH7780_PCIMBAR0); /* PCI */
+ pci_write_reg(0x08000000, SH7780_PCILAR0); /* SHwy */
+ pci_write_reg(0x07F00001, SH7780_PCILSR); /* size 128M w/ MBAR */
+
+ pci_write_reg(0x00000000, SH7780_PCIMBAR1);
+ pci_write_reg(0x00000000, SH7780_PCILAR1);
+ pci_write_reg(0x00000000, SH7780_PCILSR1);
+
+ pci_write_reg(0xAB000801, SH7780_PCIIBAR);
+
+ /*
+ * Set the MBR so PCI address is one-to-one with window,
+ * meaning all calls go straight through... use ifdef to
+ * catch erroneous assumption.
+ */
+ pci_write_reg(0xFD000000 , SH7780_PCIMBR0);
+ pci_write_reg(0x00FC0000 , SH7780_PCIMBMR0); /* 16M */
+
+ /* Set IOBR for window containing area specified in pci.h */
+ pci_write_reg(PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE-1), SH7780_PCIIOBR);
+ pci_write_reg((SH7780_PCI_IO_SIZE-1) & (7 << 18), SH7780_PCIIOBMR);
+
+ pci_write_reg(0xA5000C01, SH7780_PCICR);
+
+ return 0;
+}
diff --git a/arch/sh/drivers/pci/ops-landisk.c b/arch/sh/drivers/pci/ops-landisk.c
index d06030815a9..bff09ecf341 100644
--- a/arch/sh/drivers/pci/ops-landisk.c
+++ b/arch/sh/drivers/pci/ops-landisk.c
@@ -17,8 +17,8 @@
static struct resource sh7751_io_resource = {
.name = "SH7751 IO",
- .start = 0x4000,
- .end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
+ .start = SH7751_PCI_IO_BASE,
+ .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
.flags = IORESOURCE_IO
};
diff --git a/arch/sh/drivers/pci/ops-lboxre2.c b/arch/sh/drivers/pci/ops-lboxre2.c
new file mode 100644
index 00000000000..a13cb764b0b
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-lboxre2.c
@@ -0,0 +1,63 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-lboxre2.c
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * PCI initialization for the NTT COMWARE L-BOX RE2
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <asm/lboxre2.h>
+#include "pci-sh4.h"
+
+static char lboxre2_irq_tab[] __initdata = {
+ IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ return lboxre2_irq_tab[slot];
+}
+
+static struct resource sh7751_io_resource = {
+ .name = "SH7751_IO",
+ .start = SH7751_PCI_IO_BASE ,
+ .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+ .name = "SH7751_mem",
+ .start = SH7751_PCI_MEMORY_BASE,
+ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops sh7751_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh4_pci_address_map sh7751_pci_map = {
+ .window0 = {
+ .base = SH7751_CS3_BASE_ADDR,
+ .size = 0x04000000,
+ },
+ .window1 = {
+ .base = 0x00000000, /* Unused */
+ .size = 0x00000000, /* Unused */
+ },
+ .flags = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+ return sh7751_pcic_init(&sh7751_pci_map);
+}
diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
index eeea1577e11..f2216081ab8 100644
--- a/arch/sh/drivers/pci/ops-r7780rp.c
+++ b/arch/sh/drivers/pci/ops-r7780rp.c
@@ -17,18 +17,25 @@
#include <asm/io.h>
#include "pci-sh4.h"
+static char r7780rp_irq_tab[] __initdata = {
+ 0, 1, 2, 3,
+};
+
+static char r7780mp_irq_tab[] __initdata = {
+ 65, 66, 67, 68,
+};
+
int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
- switch (slot) {
- case 0: return IRQ_PCISLOT1; /* PCI Interrupt #1 */
- case 1: return IRQ_PCISLOT2; /* PCI Interrupt #2 */
- case 2: return IRQ_PCISLOT3; /* PCI Interrupt #3 */
- case 3: return IRQ_PCISLOT4; /* PCI Interrupt E4 */
- default:
- printk(KERN_ERR "PCI: Bad IRQ mapping "
- "request for slot %d, func %d\n", slot, pin-1);
- return -1;
- }
+ if (mach_is_r7780rp())
+ return r7780rp_irq_tab[slot];
+ if (mach_is_r7780mp() || mach_is_r7785rp())
+ return r7780mp_irq_tab[slot];
+
+ printk(KERN_ERR "PCI: Bad IRQ mapping "
+ "request for slot %d, func %d\n", slot, pin-1);
+
+ return -1;
}
static struct resource sh7780_io_resource = {
diff --git a/arch/sh/drivers/pci/ops-se7780.c b/arch/sh/drivers/pci/ops-se7780.c
new file mode 100644
index 00000000000..212674df5e1
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-se7780.c
@@ -0,0 +1,96 @@
+/*
+ * linux/arch/sh/drivers/pci/ops-se7780.c
+ *
+ * Copyright (C) 2006 Nobuhiro Iwamatsu
+ *
+ * PCI initialization for the Hitachi UL Solution Engine 7780SE03
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <asm/se7780.h>
+#include <asm/io.h>
+#include "pci-sh4.h"
+
+/*
+ * IDSEL = AD16 PCI slot
+ * IDSEL = AD17 PCI slot
+ * IDSEL = AD18 Serial ATA Controller (Silicon Image SiL3512A)
+ * IDSEL = AD19 USB Host Controller (NEC uPD7210100A)
+ */
+
+/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
+static char se7780_irq_tab[4][16] __initdata = {
+ /* INTA */
+ { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ /* INTB */
+ { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ /* INTC */
+ { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ /* INTD */
+ { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+};
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ return se7780_irq_tab[pin-1][slot];
+}
+
+static struct resource se7780_io_resource = {
+ .name = "SH7780_IO",
+ .start = 0x2000,
+ .end = 0x2000 + SH7780_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource se7780_mem_resource = {
+ .name = "SH7780_mem",
+ .start = SH7780_PCI_MEMORY_BASE,
+ .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops se7780_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+ { &sh4_pci_ops, &se7780_io_resource, &se7780_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh4_pci_address_map se7780_pci_map = {
+ .window0 = {
+ .base = SH7780_CS2_BASE_ADDR,
+ .size = 0x04000000,
+ },
+ .flags = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+ printk("SH7780 PCI: Finished initialization of the PCI controller\n");
+
+ /*
+ * FPGA PCISEL register initialize
+ *
+ * CPU || SLOT1 | SLOT2 | S-ATA | USB
+ * -------------------------------------
+ * INTA || INTA | INTD | -- | INTB
+ * -------------------------------------
+ * INTB || INTB | INTA | -- | INTC
+ * -------------------------------------
+ * INTC || INTC | INTB | INTA | --
+ * -------------------------------------
+ * INTD || INTD | INTC | -- | INTA
+ * -------------------------------------
+ */
+ ctrl_outw(0x0013, FPGA_PCI_INTSEL1);
+ ctrl_outw(0xE402, FPGA_PCI_INTSEL2);
+
+ return sh7780_pcic_init(&se7780_pci_map);
+}
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
index 2d4371009a5..54232f13e40 100644
--- a/arch/sh/drivers/pci/ops-sh4.c
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -162,3 +162,9 @@ char * __init pcibios_setup(char *str)
return str;
}
+
+int __attribute__((weak)) pci_fixup_pcic(void)
+{
+ /* Nothing to do. */
+ return 0;
+}
diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h
index 5a61d6041f2..1901c33cde6 100644
--- a/arch/sh/drivers/pci/pci-sh4.h
+++ b/arch/sh/drivers/pci/pci-sh4.h
@@ -1,7 +1,7 @@
#ifndef __PCI_SH4_H
#define __PCI_SH4_H
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
#include "pci-sh7780.h"
#else
#include "pci-sh7751.h"
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
index 9ddff760d3c..1aca7fe5783 100644
--- a/arch/sh/drivers/pci/pci-sh7751.c
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -12,7 +12,6 @@
* License. See linux/COPYING for more information.
*
*/
-
#undef DEBUG
#include <linux/init.h>
@@ -28,7 +27,7 @@
* Initialization. Try all known PCI access methods. Note that we support
* using both PCI BIOS and direct access: in such cases, we use I/O ports
* to access config space.
- *
+ *
* Note that the platform specific initialization (BSC registers, and memory
* space mapping) will be called via the platform defined function
* pcibios_init_platform().
@@ -115,7 +114,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
* Wait Cycle Control + Parity Enable + Bus Master +
* Mem space enable
*/
- word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
+ word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
pci_write_reg(word, SH7751_PCICONF1);
@@ -123,10 +122,10 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
word = PCI_BASE_CLASS_BRIDGE << 24;
pci_write_reg(word, SH7751_PCICONF2);
- /* Set IO and Mem windows to local address
- * Make PCI and local address the same for easy 1 to 1 mapping
+ /* Set IO and Mem windows to local address
+ * Make PCI and local address the same for easy 1 to 1 mapping
* Window0 = map->window0.size @ non-cached area base = SDRAM
- * Window1 = map->window1.size @ cached area base = SDRAM
+ * Window1 = map->window1.size @ cached area base = SDRAM
*/
word = map->window0.size - 1;
pci_write_reg(word, SH4_PCILSR0);
@@ -175,7 +174,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
case SH7751_CS5_BASE_ADDR: word = __area_sdram_check(5); break;
case SH7751_CS6_BASE_ADDR: word = __area_sdram_check(6); break;
}
-
+
if (!word)
return 0;
@@ -194,9 +193,7 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
* DMA interrupts...
*/
-#ifdef CONFIG_SH_RTS7751R2D
pci_fixup_pcic();
-#endif
/* SH7751 init done, set central function init complete */
/* use round robin mode to stop a device starving/overruning */
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
index 602b644c35a..5508e45d483 100644
--- a/arch/sh/drivers/pci/pci-sh7780.c
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -48,7 +48,7 @@
static int __init sh7780_pci_init(void)
{
unsigned int id;
- int ret;
+ int ret, match = 0;
pr_debug("PCI: Starting intialization.\n");
@@ -56,19 +56,43 @@ static int __init sh7780_pci_init(void)
/* check for SH7780/SH7780R hardware */
id = pci_read_reg(SH7780_PCIVID);
- if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) &&
- (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) {
+ if ((id & 0xffff) == SH7780_VENDOR_ID) {
+ switch ((id >> 16) & 0xffff) {
+ case SH7780_DEVICE_ID:
+ case SH7781_DEVICE_ID:
+ case SH7785_DEVICE_ID:
+ match = 1;
+ break;
+ }
+ }
+
+ if (unlikely(!match)) {
printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id);
return -ENODEV;
}
/* Setup the INTC */
- ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */
- ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */
- ctrl_outl(0x40000000, INTC_INTMSK1); /* disable IRL4-7 Interrupt */
- ctrl_outl(0x0000fffe, INTC_INTMSK2); /* disable IRL4-7 Interrupt */
- ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */
- ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */
+ if (mach_is_7780se()) {
+ /* ICR0: IRL=use separately */
+ ctrl_outl(0x00C00020, INTC_ICR0);
+ /* ICR1: detect low level(for 2ndcut) */
+ ctrl_outl(0xAAAA0000, INTC_ICR1);
+ /* INTPRI: priority=3(all) */
+ ctrl_outl(0x33333333, INTC_INTPRI);
+ } else {
+ /* INTC SH-4 Mode */
+ ctrl_outl(0x00200000, INTC_ICR0);
+ /* enable PCIINTA - PCIINTD */
+ ctrl_outl(0x00078000, INTC_INT2MSKCR);
+ /* disable IRL4-7 Interrupt */
+ ctrl_outl(0x40000000, INTC_INTMSK1);
+ /* disable IRL4-7 Interrupt */
+ ctrl_outl(0x0000fffe, INTC_INTMSK2);
+ /* enable IRL0-3 Interrupt */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1);
+ /* enable IRL0-3 Interrupt */
+ ctrl_outl(0xfffe0000, INTC_INTMSKCLR2);
+ }
if ((ret = sh4_pci_check_direct()) != 0)
return ret;
@@ -138,9 +162,8 @@ int __init sh7780_pcic_init(struct sh4_pci_address_map *map)
* DMA interrupts...
*/
-#ifdef CONFIG_SH_R7780RP
+ /* Apply any last-minute PCIC fixups */
pci_fixup_pcic();
-#endif
/* SH7780 init done, set central function init complete */
/* use round robin mode to stop a device starving/overruning */
diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
index f02d2180a4b..00d12d0f8c1 100644
--- a/arch/sh/drivers/pci/pci-sh7780.h
+++ b/arch/sh/drivers/pci/pci-sh7780.h
@@ -14,8 +14,9 @@
/* Platform Specific Values */
#define SH7780_VENDOR_ID 0x1912
-#define SH7780_DEVICE_ID 0x0002
#define SH7781_DEVICE_ID 0x0001
+#define SH7780_DEVICE_ID 0x0002
+#define SH7785_DEVICE_ID 0x0007
/* SH7780 Control Registers */
#define SH7780_PCI_VCR0 0xFE000000
@@ -65,6 +66,22 @@
#define SH7780_PCIPMCSR_BSE 0x046
#define SH7780_PCICDD 0x047
+#define SH7780_PCICR 0x100 /* PCI Control Register */
+#define SH7780_PCILSR 0x104 /* PCI Local Space Register0 */
+#define SH7780_PCILSR1 0x108 /* PCI Local Space Register1 */
+#define SH7780_PCILAR0 0x10C /* PCI Local Address Register1 */
+#define SH7780_PCILAR1 0x110 /* PCI Local Address Register1 */
+#define SH7780_PCIIR 0x114 /* PCI Interrupt Register */
+#define SH7780_PCIIMR 0x118 /* PCI Interrupt Mask Register */
+#define SH7780_PCIAIR 0x11C /* Error Address Register */
+#define SH7780_PCICIR 0x120 /* Error Command/Data Register */
+#define SH7780_PCIAINT 0x130 /* Arbiter Interrupt Register */
+#define SH7780_PCIAINTM 0x134 /* Arbiter Int. Mask Register */
+#define SH7780_PCIBMIR 0x138 /* Error Bus Master Register */
+#define SH7780_PCIPAR 0x1C0 /* PIO Address Register */
+#define SH7780_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
+#define SH7780_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
+
#define SH7780_PCIMBR0 0x1E0
#define SH7780_PCIMBMR0 0x1E4
#define SH7780_PCIMBR2 0x1F0
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
index efecb3d5995..d67656a44b1 100644
--- a/arch/sh/drivers/pci/pci-st40.c
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index ff30d7f5804..9104b625764 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -20,5 +20,6 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
index 3e5fa1e24df..0758d48147a 100644
--- a/arch/sh/kernel/cf-enabler.c
+++ b/arch/sh/kernel/cf-enabler.c
@@ -29,7 +29,7 @@
* 0xB8001000 : Common Memory
* 0xBA000000 : I/O
*/
-#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4)
/* SH4 can't access PCMCIA interface through P2 area.
* we must remap it with appropreate attribute bit of the page set.
* this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
@@ -71,7 +71,7 @@ static int __init cf_init_default(void)
/* You must have enabled the card, and set the level interrupt
* before reaching this point. Possibly in boot ROM or boot loader.
*/
-#if defined(CONFIG_IDE) && defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4)
allocate_cf_area();
#endif
#if defined(CONFIG_SH_UNKNOWN)
@@ -84,15 +84,25 @@ static int __init cf_init_default(void)
#if defined(CONFIG_SH_SOLUTION_ENGINE)
#include <asm/se.h>
+#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+#include <asm/se7722.h>
+#endif
/*
- * SolutionEngine
+ * SolutionEngine Seriese
*
+ * about MS770xSE
* 0xB8400000 : Common Memory
* 0xB8500000 : Attribute
* 0xB8600000 : I/O
+ *
+ * about MS7722SE
+ * 0xB0400000 : Common Memory
+ * 0xB0500000 : Attribute
+ * 0xB0600000 : I/O
*/
+#if defined(CONFIG_SH_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE)
static int __init cf_init_se(void)
{
if ((ctrl_inw(MRSHPC_CSR) & 0x000c) != 0)
@@ -109,7 +119,7 @@ static int __init cf_init_se(void)
* flag == COMMON/ATTRIBUTE/IO
*/
/* common window open */
- ctrl_outw(0x8a84, MRSHPC_MW0CR1);/* window 0xb8400000 */
+ ctrl_outw(0x8a84, MRSHPC_MW0CR1);
if((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
/* common mode & bus width 16bit SWAP = 1*/
ctrl_outw(0x0b00, MRSHPC_MW0CR2);
@@ -118,7 +128,7 @@ static int __init cf_init_se(void)
ctrl_outw(0x0300, MRSHPC_MW0CR2);
/* attribute window open */
- ctrl_outw(0x8a85, MRSHPC_MW1CR1);/* window 0xb8500000 */
+ ctrl_outw(0x8a85, MRSHPC_MW1CR1);
if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
/* attribute mode & bus width 16bit SWAP = 1*/
ctrl_outw(0x0a00, MRSHPC_MW1CR2);
@@ -127,7 +137,7 @@ static int __init cf_init_se(void)
ctrl_outw(0x0200, MRSHPC_MW1CR2);
/* I/O window open */
- ctrl_outw(0x8a86, MRSHPC_IOWCR1);/* I/O window 0xb8600000 */
+ ctrl_outw(0x8a86, MRSHPC_IOWCR1);
ctrl_outw(0x0008, MRSHPC_CDCR); /* I/O card mode */
if ((ctrl_inw(MRSHPC_CSR) & 0x4000) != 0)
ctrl_outw(0x0a00, MRSHPC_IOWCR2); /* bus width 16bit SWAP = 1*/
@@ -143,10 +153,10 @@ static int __init cf_init_se(void)
int __init cf_init(void)
{
-#if defined(CONFIG_SH_SOLUTION_ENGINE)
- if (MACH_SE)
+ if( mach_is_se() || mach_is_7722se() ){
return cf_init_se();
-#endif
+ }
+
return cf_init_default();
}
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index abb586b1256..014f318f5a0 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/cpu/clock.c - SuperH clock framework
*
- * Copyright (C) 2005, 2006 Paul Mundt
+ * Copyright (C) 2005, 2006, 2007 Paul Mundt
*
* This clock framework is derived from the OMAP version by:
*
@@ -23,6 +23,7 @@
#include <linux/seq_file.h>
#include <linux/err.h>
#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
#include <asm/clock.h>
#include <asm/timer.h>
@@ -98,15 +99,17 @@ int __clk_enable(struct clk *clk)
if (clk->ops && clk->ops->init)
clk->ops->init(clk);
+ kref_get(&clk->kref);
+
if (clk->flags & CLK_ALWAYS_ENABLED)
return 0;
if (likely(clk->ops && clk->ops->enable))
clk->ops->enable(clk);
- kref_get(&clk->kref);
return 0;
}
+EXPORT_SYMBOL_GPL(__clk_enable);
int clk_enable(struct clk *clk)
{
@@ -119,6 +122,7 @@ int clk_enable(struct clk *clk)
return ret;
}
+EXPORT_SYMBOL_GPL(clk_enable);
static void clk_kref_release(struct kref *kref)
{
@@ -127,11 +131,17 @@ static void clk_kref_release(struct kref *kref)
void __clk_disable(struct clk *clk)
{
+ int count = kref_put(&clk->kref, clk_kref_release);
+
if (clk->flags & CLK_ALWAYS_ENABLED)
return;
- kref_put(&clk->kref, clk_kref_release);
+ if (!count) { /* count reaches zero, disable the clock */
+ if (likely(clk->ops && clk->ops->disable))
+ clk->ops->disable(clk);
+ }
}
+EXPORT_SYMBOL_GPL(__clk_disable);
void clk_disable(struct clk *clk)
{
@@ -141,6 +151,7 @@ void clk_disable(struct clk *clk)
__clk_disable(clk);
spin_unlock_irqrestore(&clock_lock, flags);
}
+EXPORT_SYMBOL_GPL(clk_disable);
int clk_register(struct clk *clk)
{
@@ -151,8 +162,18 @@ int clk_register(struct clk *clk)
mutex_unlock(&clock_list_sem);
+ if (clk->flags & CLK_ALWAYS_ENABLED) {
+ pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
+ if (clk->ops && clk->ops->init)
+ clk->ops->init(clk);
+ if (clk->ops && clk->ops->enable)
+ clk->ops->enable(clk);
+ pr_debug( "Enabled.");
+ }
+
return 0;
}
+EXPORT_SYMBOL_GPL(clk_register);
void clk_unregister(struct clk *clk)
{
@@ -160,21 +181,29 @@ void clk_unregister(struct clk *clk)
list_del(&clk->node);
mutex_unlock(&clock_list_sem);
}
+EXPORT_SYMBOL_GPL(clk_unregister);
-inline unsigned long clk_get_rate(struct clk *clk)
+unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
+EXPORT_SYMBOL_GPL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
+ return clk_set_rate_ex(clk, rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
+{
int ret = -EOPNOTSUPP;
if (likely(clk->ops && clk->ops->set_rate)) {
unsigned long flags;
spin_lock_irqsave(&clock_lock, flags);
- ret = clk->ops->set_rate(clk, rate);
+ ret = clk->ops->set_rate(clk, rate, algo_id);
spin_unlock_irqrestore(&clock_lock, flags);
}
@@ -183,6 +212,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
return ret;
}
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
void clk_recalc_rate(struct clk *clk)
{
@@ -197,6 +227,7 @@ void clk_recalc_rate(struct clk *clk)
if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
propagate_rate(clk);
}
+EXPORT_SYMBOL_GPL(clk_recalc_rate);
/*
* Returns a clock. Note that we first try to use device id on the bus
@@ -233,18 +264,43 @@ found:
return clk;
}
+EXPORT_SYMBOL_GPL(clk_get);
void clk_put(struct clk *clk)
{
if (clk && !IS_ERR(clk))
module_put(clk->owner);
}
+EXPORT_SYMBOL_GPL(clk_put);
void __init __attribute__ ((weak))
arch_init_clk_ops(struct clk_ops **ops, int type)
{
}
+static int show_clocks(char *buf, char **start, off_t off,
+ int len, int *eof, void *data)
+{
+ struct clk *clk;
+ char *p = buf;
+
+ list_for_each_entry_reverse(clk, &clock_list, node) {
+ unsigned long rate = clk_get_rate(clk);
+
+ /*
+ * Don't bother listing dummy clocks with no ancestry
+ * that only support enable and disable ops.
+ */
+ if (unlikely(!rate && !clk->parent))
+ continue;
+
+ p += sprintf(p, "%-12s\t: %ld.%02ldMHz\n", clk->name,
+ rate / 1000000, (rate % 1000000) / 10000);
+ }
+
+ return p - buf;
+}
+
int __init clk_init(void)
{
int i, ret = 0;
@@ -256,7 +312,6 @@ int __init clk_init(void)
arch_init_clk_ops(&clk->ops, i);
ret |= clk_register(clk);
- clk_enable(clk);
}
/* Kick the child clocks.. */
@@ -266,35 +321,14 @@ int __init clk_init(void)
return ret;
}
-int show_clocks(struct seq_file *m)
+static int __init clk_proc_init(void)
{
- struct clk *clk;
-
- list_for_each_entry_reverse(clk, &clock_list, node) {
- unsigned long rate = clk_get_rate(clk);
-
- /*
- * Don't bother listing dummy clocks with no ancestry
- * that only support enable and disable ops.
- */
- if (unlikely(!rate && !clk->parent))
- continue;
-
- seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name,
- rate / 1000000, (rate % 1000000) / 10000);
- }
+ struct proc_dir_entry *p;
+ p = create_proc_read_entry("clocks", S_IRUSR, NULL,
+ show_clocks, NULL);
+ if (unlikely(!p))
+ return -EINVAL;
return 0;
}
-
-EXPORT_SYMBOL_GPL(clk_register);
-EXPORT_SYMBOL_GPL(clk_unregister);
-EXPORT_SYMBOL_GPL(clk_get);
-EXPORT_SYMBOL_GPL(clk_put);
-EXPORT_SYMBOL_GPL(clk_enable);
-EXPORT_SYMBOL_GPL(clk_disable);
-EXPORT_SYMBOL_GPL(__clk_enable);
-EXPORT_SYMBOL_GPL(__clk_disable);
-EXPORT_SYMBOL_GPL(clk_get_rate);
-EXPORT_SYMBOL_GPL(clk_set_rate);
-EXPORT_SYMBOL_GPL(clk_recalc_rate);
+subsys_initcall(clk_proc_init);
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 726acfcb9b7..6451ad63017 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -41,6 +41,23 @@ __setup("no" __stringify(x), x##_setup);
onchip_setup(fpu);
onchip_setup(dsp);
+#ifdef CONFIG_SPECULATIVE_EXECUTION
+#define CPUOPM 0xff2f0000
+#define CPUOPM_RABD (1 << 5)
+
+static void __init speculative_execution_init(void)
+{
+ /* Clear RABD */
+ ctrl_outl(ctrl_inl(CPUOPM) & ~CPUOPM_RABD, CPUOPM);
+
+ /* Flush the update */
+ (void)ctrl_inl(CPUOPM);
+ ctrl_barrier();
+}
+#else
+#define speculative_execution_init() do { } while (0)
+#endif
+
/*
* Generic first-level cache init
*/
@@ -261,4 +278,6 @@ asmlinkage void __init sh_cpu_init(void)
*/
ubc_wakeup();
#endif
+
+ speculative_execution_init();
}
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 0049d217561..1c23308cfc2 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -4,6 +4,6 @@
obj-y += imask.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
-obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
+obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index 74defe76a05..d8e22f4ff0f 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -18,7 +18,8 @@
#define INTC2_BASE 0xfe080000
#define INTC2_INTMSK (INTC2_BASE + 0x40)
#define INTC2_INTMSKCLR (INTC2_BASE + 0x60)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
#define INTC2_BASE 0xffd40000
#define INTC2_INTMSK (INTC2_BASE + 0x38)
#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c)
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index f60007783a2..67602685df1 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -18,6 +18,58 @@
#include <asm/io.h>
#include <asm/machvec.h>
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#define INTC_INTER 0xA4000014UL
+#define INTC_IPRD 0xA4000018UL
+#define INTC_ICR2 0xA4000012UL
+
+/* PFC */
+#define PORT_PACR 0xA4000100UL
+#define PORT_PBCR 0xA4000102UL
+#define PORT_PCCR 0xA4000104UL
+#define PORT_PDCR 0xA4000106UL
+#define PORT_PECR 0xA4000108UL
+#define PORT_PFCR 0xA400010AUL
+#define PORT_PGCR 0xA400010CUL
+#define PORT_PHCR 0xA400010EUL
+#define PORT_PJCR 0xA4000110UL
+#define PORT_PKCR 0xA4000112UL
+#define PORT_PLCR 0xA4000114UL
+#define PORT_PMCR 0xA4000118UL
+#define PORT_PNCR 0xA400011AUL
+#define PORT_PECR2 0xA4050148UL
+#define PORT_PFCR2 0xA405014AUL
+#define PORT_PNCR2 0xA405015AUL
+
+/* I/O port */
+#define PORT_PADR 0xA4000120UL
+#define PORT_PBDR 0xA4000122UL
+#define PORT_PCDR 0xA4000124UL
+#define PORT_PDDR 0xA4000126UL
+#define PORT_PEDR 0xA4000128UL
+#define PORT_PFDR 0xA400012AUL
+#define PORT_PGDR 0xA400012CUL
+#define PORT_PHDR 0xA400012EUL
+#define PORT_PJDR 0xA4000130UL
+#define PORT_PKDR 0xA4000132UL
+#define PORT_PLDR 0xA4000134UL
+#define PORT_PMDR 0xA4000138UL
+#define PORT_PNDR 0xA400013AUL
+
+#define PINT0_IRQ 40
+#define PINT8_IRQ 41
+#define PINT_IRQ_BASE 86
+
+#define PINT0_IPR_ADDR INTC_IPRD
+#define PINT0_IPR_POS 3
+#define PINT0_PRIORITY 2
+
+#define PINT8_IPR_ADDR INTC_IPRD
+#define PINT8_IPR_POS 2
+#define PINT8_PRIORITY 2
+
+#endif /* CONFIG_CPU_SUBTYPE_SH7705 */
+
static unsigned char pint_map[256];
static unsigned long portcr_mask;
@@ -126,7 +178,7 @@ int ipr_irq_demux(int irq)
unsigned long creg, dreg, d, sav;
if (irq == PINT0_IRQ) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
creg = PORT_PACR;
dreg = PORT_PADR;
#else
@@ -144,7 +196,7 @@ int ipr_irq_demux(int irq)
return PINT_IRQ_BASE + pint_map[d];
} else if (irq == PINT8_IRQ) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7707)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7707)
creg = PORT_PBCR;
dreg = PORT_PBDR;
#else
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 350972ae941..965fa2572b2 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -2,9 +2,8 @@
# Makefile for the Linux/SuperH SH-2A backends.
#
-obj-y := common.o probe.o
+obj-y := common.o probe.o opcode_helper.o
-common-y += $(addprefix ../sh2/, ex.o)
-common-y += $(addprefix ../sh2/, entry.o)
+common-y += $(addprefix ../sh2/, ex.o entry.o)
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
diff --git a/arch/sh/kernel/cpu/sh2a/opcode_helper.c b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
new file mode 100644
index 00000000000..9704b7926d8
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/opcode_helper.c
@@ -0,0 +1,55 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/opcode_helper.c
+ *
+ * Helper for the SH-2A 32-bit opcodes.
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <asm/system.h>
+
+/*
+ * Instructions on SH are generally fixed at 16-bits, however, SH-2A
+ * introduces some 32-bit instructions. Since there are no real
+ * constraints on their use (and they can be mixed and matched), we need
+ * to check the instruction encoding to work out if it's a true 32-bit
+ * instruction or not.
+ *
+ * Presently, 32-bit opcodes have only slight variations in what the
+ * actual encoding looks like in the first-half of the instruction, which
+ * makes it fairly straightforward to differentiate from the 16-bit ones.
+ *
+ * First 16-bits of encoding Used by
+ *
+ * 0011nnnnmmmm0001 mov.b, mov.w, mov.l, fmov.d,
+ * fmov.s, movu.b, movu.w
+ *
+ * 0011nnnn0iii1001 bclr.b, bld.b, bset.b, bst.b, band.b,
+ * bandnot.b, bldnot.b, bor.b, bornot.b,
+ * bxor.b
+ *
+ * 0000nnnniiii0000 movi20
+ * 0000nnnniiii0001 movi20s
+ */
+unsigned int instruction_size(unsigned int insn)
+{
+ /* Look for the common cases */
+ switch ((insn & 0xf00f)) {
+ case 0x0000: /* movi20 */
+ case 0x0001: /* movi20s */
+ case 0x3001: /* 32-bit mov/fmov/movu variants */
+ return 4;
+ }
+
+ /* And the special cases.. */
+ switch ((insn & 0xf08f)) {
+ case 0x3009: /* 32-bit b*.b bit operations */
+ return 4;
+ }
+
+ return 2;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 426f6db01fc..f455c350978 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -18,6 +18,7 @@ int __init detect_cpu_and_cache_system(void)
{
/* Just SH7206 for now .. */
current_cpu_data.type = CPU_SH7206;
+ current_cpu_data.flags |= CPU_HAS_OP32;
current_cpu_data.dcache.ways = 4;
current_cpu_data.dcache.way_incr = (1 << 11);
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index 83905e4e438..09faa056cd4 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7712) += setup-sh7710.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH3) := clock-sh3.o
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index f3e827f29a4..832c0b4a1e6 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/entry.S
+ * arch/sh/kernel/cpu/sh3/entry.S
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2003 - 2006 Paul Mundt
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index ba3082d640b..2b2a9e02fb7 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/cpu/sh3/ex.S
*
- * The SH-3 exception vector table.
+ * The SH-3 and SH-4 exception vector table.
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
* Copyright (C) 2003 - 2006 Paul Mundt
@@ -9,7 +9,6 @@
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
- *
*/
#include <linux/linkage.h>
@@ -36,8 +35,12 @@ ENTRY(exception_handling_table)
.long exception_error ! address error load
.long exception_error ! address error store /* 100 */
#endif
- .long exception_error ! fpu_exception /* 120 */
- .long exception_error /* 140 */
+#if defined(CONFIG_SH_FPU)
+ .long do_fpu_error /* 120 */
+#else
+ .long exception_error /* 120 */
+#endif
+ .long exception_error /* 140 */
.long system_call ! Unconditional Trap /* 160 */
.long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
.long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
@@ -55,4 +58,4 @@ ENTRY(user_break_point_trap)
* away offsets can be manually inserted in to their appropriate
* location via set_exception_table_{evt,vec}().
*/
- .balign 4096,0,4096
+ .balign 4096,0,4096
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 821b0ab7b52..647623b22ed 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -78,6 +78,9 @@ int __init detect_cpu_and_cache_system(void)
#if defined(CONFIG_CPU_SUBTYPE_SH7710)
current_cpu_data.type = CPU_SH7710;
#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7712)
+ current_cpu_data.type = CPU_SH7712;
+#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
current_cpu_data.type = CPU_SH7705;
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index a8e41c5241f..1983fb7ad6e 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -2,6 +2,7 @@
* SH7705 Setup
*
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -14,15 +15,15 @@
static struct plat_sci_port sci_platform_data[] = {
{
- .mapbase = 0xa4400000,
+ .mapbase = 0xa4410000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 52, 53, 55, 54 },
+ .irqs = { 56, 57, 59 },
}, {
- .mapbase = 0xa4410000,
+ .mapbase = 0xa4400000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 56, 57, 59, 58 },
+ .irqs = { 52, 53, 55 },
}, {
.flags = 0,
}
@@ -46,3 +47,48 @@ static int __init sh7705_devices_setup(void)
ARRAY_SIZE(sh7705_devices));
}
__initcall(sh7705_devices_setup);
+
+static struct ipr_data sh7705_ipr_map[] = {
+ /* IRQ, IPR-idx, shift, priority */
+ { 16, 0, 12, 2 }, /* TMU0 TUNI*/
+ { 17, 0, 8, 2 }, /* TMU1 TUNI */
+ { 18, 0, 4, 2 }, /* TMU2 TUNI */
+ { 27, 1, 12, 2 }, /* WDT ITI */
+ { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
+ { 21, 0, 0, 2 }, /* RTC PRI (period) */
+ { 22, 0, 0, 2 }, /* RTC CUI (carry) */
+ { 48, 4, 12, 7 }, /* DMAC DMTE0 */
+ { 49, 4, 12, 7 }, /* DMAC DMTE1 */
+ { 50, 4, 12, 7 }, /* DMAC DMTE2 */
+ { 51, 4, 12, 7 }, /* DMAC DMTE3 */
+ { 52, 4, 8, 3 }, /* SCIF0 ERI */
+ { 53, 4, 8, 3 }, /* SCIF0 RXI */
+ { 55, 4, 8, 3 }, /* SCIF0 TXI */
+ { 56, 4, 4, 3 }, /* SCIF1 ERI */
+ { 57, 4, 4, 3 }, /* SCIF1 RXI */
+ { 59, 4, 4, 3 }, /* SCIF1 TXI */
+};
+
+static unsigned long ipr_offsets[] = {
+ 0xFFFFFEE2 /* 0: IPRA */
+, 0xFFFFFEE4 /* 1: IPRB */
+, 0xA4000016 /* 2: IPRC */
+, 0xA4000018 /* 3: IPRD */
+, 0xA400001A /* 4: IPRE */
+, 0xA4080000 /* 5: IPRF */
+, 0xA4080002 /* 6: IPRG */
+, 0xA4080004 /* 7: IPRH */
+};
+
+/* given the IPR index return the address of the IPR register */
+unsigned int map_ipridx_to_addr(int idx)
+{
+ if (idx >= ARRAY_SIZE(ipr_offsets))
+ return 0;
+ return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr()
+{
+ make_ipr_irq(sh7705_ipr_map, ARRAY_SIZE(sh7705_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
index dc9b211cf87..c7d7c35fc83 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -48,24 +48,33 @@ static struct platform_device *sh7709_devices[] __initdata = {
static int __init sh7709_devices_setup(void)
{
return platform_add_devices(sh7709_devices,
- ARRAY_SIZE(sh7709_devices));
+ ARRAY_SIZE(sh7709_devices));
}
__initcall(sh7709_devices_setup);
-#define IPRx(A,N) .addr=A, .shift=0*N*-1
+#define IPRx(A,N) .addr=A, .shift=N
#define IPRA(N) IPRx(0xfffffee2UL,N)
#define IPRB(N) IPRx(0xfffffee4UL,N)
+#define IPRC(N) IPRx(0xa4000016UL,N)
+#define IPRD(N) IPRx(0xa4000018UL,N)
#define IPRE(N) IPRx(0xa400001aUL,N)
static struct ipr_data sh7709_ipr_map[] = {
- [16] = { IPRA(15-12), 2 }, /* TMU TUNI0 */
- [17] = { IPRA(11-8), 4 }, /* TMU TUNI1 */
- [22] = { IPRA(3-0), 2 }, /* RTC CUI */
- [23 ... 26] = { IPRB(7-4), 3 }, /* SCI */
- [27] = { IPRB(15-12), 2 }, /* WDT ITI */
- [48 ... 51] = { IPRE(15-12), 7 }, /* DMA */
- [52 ... 55] = { IPRE(11-8), 3 }, /* IRDA */
- [56 ... 59] = { IPRE(7-4), 3 }, /* SCIF */
+ [16] = { IPRA(12), 2 }, /* TMU TUNI0 */
+ [17] = { IPRA(8), 4 }, /* TMU TUNI1 */
+ [18 ... 19] = { IPRA(4), 1 }, /* TMU TUNI1 */
+ [20 ... 22] = { IPRA(0), 2 }, /* RTC CUI */
+ [23 ... 26] = { IPRB(4), 3 }, /* SCI */
+ [27] = { IPRB(12), 2 }, /* WDT ITI */
+ [32] = { IPRC(0), 1 }, /* IRQ 0 */
+ [33] = { IPRC(4), 1 }, /* IRQ 1 */
+ [34] = { IPRC(8), 1 }, /* IRQ 2 APM */
+ [35] = { IPRC(12), 1 }, /* IRQ 3 TOUCHSCREEN */
+ [36] = { IPRD(0), 1 }, /* IRQ 4 */
+ [37] = { IPRD(4), 1 }, /* IRQ 5 */
+ [48 ... 51] = { IPRE(12), 7 }, /* DMA */
+ [52 ... 55] = { IPRE(8), 3 }, /* IRDA */
+ [56 ... 59] = { IPRE(4), 3 }, /* SCIF */
};
void __init init_IRQ_ipr()
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 895f99ee6a9..51760a7e7f1 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -2,6 +2,7 @@
* SH7710 Setup
*
* Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -19,6 +20,12 @@ static struct plat_sci_port sci_platform_data[] = {
.type = PORT_SCIF,
.irqs = { 52, 53, 55, 54 },
}, {
+ .mapbase = 0xa4420000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 56, 57, 59, 58 },
+ }, {
+
.flags = 0,
}
};
@@ -41,3 +48,56 @@ static int __init sh7710_devices_setup(void)
ARRAY_SIZE(sh7710_devices));
}
__initcall(sh7710_devices_setup);
+
+static struct ipr_data sh7710_ipr_map[] = {
+ /* IRQ, IPR-idx, shift, priority */
+ { 16, 0, 12, 2 }, /* TMU0 TUNI*/
+ { 17, 0, 8, 2 }, /* TMU1 TUNI */
+ { 18, 0, 4, 2 }, /* TMU2 TUNI */
+ { 27, 1, 12, 2 }, /* WDT ITI */
+ { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
+ { 21, 0, 0, 2 }, /* RTC PRI (period) */
+ { 22, 0, 0, 2 }, /* RTC CUI (carry) */
+ { 48, 4, 12, 7 }, /* DMAC DMTE0 */
+ { 49, 4, 12, 7 }, /* DMAC DMTE1 */
+ { 50, 4, 12, 7 }, /* DMAC DMTE2 */
+ { 51, 4, 12, 7 }, /* DMAC DMTE3 */
+ { 52, 4, 8, 3 }, /* SCIF0 ERI */
+ { 53, 4, 8, 3 }, /* SCIF0 RXI */
+ { 54, 4, 8, 3 }, /* SCIF0 BRI */
+ { 55, 4, 8, 3 }, /* SCIF0 TXI */
+ { 56, 4, 4, 3 }, /* SCIF1 ERI */
+ { 57, 4, 4, 3 }, /* SCIF1 RXI */
+ { 58, 4, 4, 3 }, /* SCIF1 BRI */
+ { 59, 4, 4, 3 }, /* SCIF1 TXI */
+ { 76, 5, 8, 7 }, /* DMAC DMTE4 */
+ { 77, 5, 8, 7 }, /* DMAC DMTE5 */
+ { 80, 6, 12, 5 }, /* EDMAC EINT0 */
+ { 81, 6, 8, 5 }, /* EDMAC EINT1 */
+ { 82, 6, 4, 5 }, /* EDMAC EINT2 */
+};
+
+static unsigned long ipr_offsets[] = {
+ 0xA414FEE2 /* 0: IPRA */
+, 0xA414FEE4 /* 1: IPRB */
+, 0xA4140016 /* 2: IPRC */
+, 0xA4140018 /* 3: IPRD */
+, 0xA414001A /* 4: IPRE */
+, 0xA4080000 /* 5: IPRF */
+, 0xA4080002 /* 6: IPRG */
+, 0xA4080004 /* 7: IPRH */
+, 0xA4080006 /* 8: IPRI */
+};
+
+/* given the IPR index return the address of the IPR register */
+unsigned int map_ipridx_to_addr(int idx)
+{
+ if (idx >= ARRAY_SIZE(ipr_offsets))
+ return 0;
+ return ipr_offsets[idx];
+}
+
+void __init init_IRQ_ipr()
+{
+ make_ipr_irq(sh7710_ipr_map, ARRAY_SIZE(sh7710_ipr_map));
+}
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 19ca68c7188..8add10bd826 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -2,10 +2,10 @@
# Makefile for the Linux/SuperH SH-4 backends.
#
-obj-y := ex.o probe.o common.o
-common-y += $(addprefix ../sh3/, entry.o)
+obj-y := probe.o common.o
+common-y += $(addprefix ../sh3/, entry.o ex.o)
-obj-$(CONFIG_SH_FPU) += fpu.o
+obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# CPU subtype setup
diff --git a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
index fa2019aabd7..fcb2c41bc34 100644
--- a/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/clock-sh4-202.c
@@ -82,7 +82,8 @@ static void shoc_clk_init(struct clk *clk)
for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) {
int divisor = frqcr3_divisors[i];
- if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0)
+ if (clk->ops->set_rate(clk, clk->parent->rate /
+ divisor, 0) == 0)
break;
}
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
deleted file mode 100644
index ac8ab57413c..00000000000
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * arch/sh/kernel/cpu/sh4/ex.S
- *
- * The SH-4 exception vector table.
-
- * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2003 - 2006 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- */
-#include <linux/linkage.h>
-
- .align 2
- .data
-
-ENTRY(exception_handling_table)
- .long exception_error /* 000 */
- .long exception_error
-#if defined(CONFIG_MMU)
- .long tlb_miss_load /* 040 */
- .long tlb_miss_store
- .long initial_page_write
- .long tlb_protection_violation_load
- .long tlb_protection_violation_store
- .long address_error_load
- .long address_error_store /* 100 */
-#else
- .long exception_error ! tlb miss load /* 040 */
- .long exception_error ! tlb miss store
- .long exception_error ! initial page write
- .long exception_error ! tlb prot violation load
- .long exception_error ! tlb prot violation store
- .long exception_error ! address error load
- .long exception_error ! address error store /* 100 */
-#endif
-#if defined(CONFIG_SH_FPU)
- .long do_fpu_error /* 120 */
-#else
- .long exception_error /* 120 */
-#endif
- .long exception_error /* 140 */
- .long system_call ! Unconditional Trap /* 160 */
- .long exception_error ! reserved_instruction (filled by trap_init) /* 180 */
- .long exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
-ENTRY(nmi_slot)
-#if defined (CONFIG_KGDB_NMI)
- .long debug_enter /* 1C0 */ ! Allow trap to debugger
-#else
- .long exception_none /* 1C0 */ ! Not implemented yet
-#endif
-ENTRY(user_break_point_trap)
- .long break_point_trap /* 1E0 */
-
- /*
- * Pad the remainder of the table out, exceptions residing in far
- * away offsets can be manually inserted in to their appropriate
- * location via set_exception_table_{evt,vec}().
- */
- .balign 4096,0,4096
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index 7624677f662..d61dd599169 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <asm/processor.h>
+#include <asm/system.h>
#include <asm/io.h>
/* The PR (precision) bit in the FP Status Register must be clear when
@@ -265,7 +266,7 @@ ieee_fpe_handler (struct pt_regs *regs)
nextpc = regs->pr;
finsn = *(unsigned short *) (regs->pc + 2);
} else {
- nextpc = regs->pc + 2;
+ nextpc = regs->pc + instruction_size(insn);
finsn = insn;
}
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 58950de2696..8cd04904c77 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -124,6 +124,14 @@ int __init detect_cpu_and_cache_system(void)
current_cpu_data.dcache.ways = 4;
current_cpu_data.flags |= CPU_HAS_LLSC;
break;
+ case 0x3004:
+ case 0x3007:
+ current_cpu_data.type = CPU_SH7785;
+ current_cpu_data.icache.ways = 4;
+ current_cpu_data.dcache.ways = 4;
+ current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ CPU_HAS_LLSC;
+ break;
case 0x3008:
if (prr == 0xa0) {
current_cpu_data.type = CPU_SH7722;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index a8f493f2f21..ab7422f8f82 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -5,6 +5,7 @@
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
@@ -13,7 +14,8 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o
clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
-clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7343.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh73180.c b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
index 2fa5cb2ae68..6d5ba373a75 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh73180.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/cpu/sh4/clock-sh73180.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh73180.c
*
* SH73180 support for the clock framework
*
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
index 1707a213f0c..7adc4f16e95 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7343.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/cpu/sh4/clock-sh7343.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7343.c
*
* SH7343/SH7722 support for the clock framework
*
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
new file mode 100644
index 00000000000..29090035bc5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -0,0 +1,600 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+ *
+ * SH7722 support for the clock framework
+ *
+ * Copyright (c) 2006-2007 Nomad Global Solutions Inc
+ * Based on code for sh7343 by Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+#define SH7722_PLL_FREQ (32000000/8)
+#define N (-1)
+#define NM (-2)
+#define ROUND_NEAREST 0
+#define ROUND_DOWN -1
+#define ROUND_UP +1
+
+static int adjust_algos[][3] = {
+ {}, /* NO_CHANGE */
+ { NM, N, 1 }, /* N:1, N:1 */
+ { 3, 2, 2 }, /* 3:2:2 */
+ { 5, 2, 2 }, /* 5:2:2 */
+ { N, 1, 1 }, /* N:1:1 */
+
+ { N, 1 }, /* N:1 */
+
+ { N, 1 }, /* N:1 */
+ { 3, 2 },
+ { 4, 3 },
+ { 5, 4 },
+
+ { N, 1 }
+};
+
+static unsigned long adjust_pair_of_clocks(unsigned long r1, unsigned long r2,
+ int m1, int m2, int round_flag)
+{
+ unsigned long rem, div;
+ int the_one = 0;
+
+ pr_debug( "Actual values: r1 = %ld\n", r1);
+ pr_debug( "...............r2 = %ld\n", r2);
+
+ if (m1 == m2) {
+ r2 = r1;
+ pr_debug( "setting equal rates: r2 now %ld\n", r2);
+ } else if ((m2 == N && m1 == 1) ||
+ (m2 == NM && m1 == N)) { /* N:1 or NM:N */
+ pr_debug( "Setting rates as 1:N (N:N*M)\n");
+ rem = r2 % r1;
+ pr_debug( "...remainder = %ld\n", rem);
+ if (rem) {
+ div = r2 / r1;
+ pr_debug( "...div = %ld\n", div);
+ switch (round_flag) {
+ case ROUND_NEAREST:
+ the_one = rem >= r1/2 ? 1 : 0; break;
+ case ROUND_UP:
+ the_one = 1; break;
+ case ROUND_DOWN:
+ the_one = 0; break;
+ }
+
+ r2 = r1 * (div + the_one);
+ pr_debug( "...setting r2 to %ld\n", r2);
+ }
+ } else if ((m2 == 1 && m1 == N) ||
+ (m2 == N && m1 == NM)) { /* 1:N or N:NM */
+ pr_debug( "Setting rates as N:1 (N*M:N)\n");
+ rem = r1 % r2;
+ pr_debug( "...remainder = %ld\n", rem);
+ if (rem) {
+ div = r1 / r2;
+ pr_debug( "...div = %ld\n", div);
+ switch (round_flag) {
+ case ROUND_NEAREST:
+ the_one = rem > r2/2 ? 1 : 0; break;
+ case ROUND_UP:
+ the_one = 0; break;
+ case ROUND_DOWN:
+ the_one = 1; break;
+ }
+
+ r2 = r1 / (div + the_one);
+ pr_debug( "...setting r2 to %ld\n", r2);
+ }
+ } else { /* value:value */
+ pr_debug( "Setting rates as %d:%d\n", m1, m2);
+ div = r1 / m1;
+ r2 = div * m2;
+ pr_debug( "...div = %ld\n", div);
+ pr_debug( "...setting r2 to %ld\n", r2);
+ }
+
+ return r2;
+}
+
+static void adjust_clocks(int originate, int *l, unsigned long v[],
+ int n_in_line)
+{
+ int x;
+
+ pr_debug( "Go down from %d...\n", originate);
+ /* go up recalculation clocks */
+ for (x = originate; x>0; x -- )
+ v[x-1] = adjust_pair_of_clocks(v[x], v[x-1],
+ l[x], l[x-1],
+ ROUND_UP);
+
+ pr_debug( "Go up from %d...\n", originate);
+ /* go down recalculation clocks */
+ for (x = originate; x<n_in_line - 1; x ++ )
+ v[x+1] = adjust_pair_of_clocks(v[x], v[x+1],
+ l[x], l[x+1],
+ ROUND_UP);
+}
+
+
+/*
+ * SH7722 uses a common set of multipliers and divisors, so this
+ * is quite simple..
+ */
+
+/*
+ * Instead of having two separate multipliers/divisors set, like this:
+ *
+ * static int multipliers[] = { 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ * static int divisors[] = { 1, 3, 2, 5, 3, 4, 5, 6, 8, 10, 12, 16, 20 };
+ *
+ * I created the divisors2 array, which is used to calculate rate like
+ * rate = parent * 2 / divisors2[ divisor ];
+*/
+static int divisors2[] = { 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40 };
+
+static void master_clk_init(struct clk *clk)
+{
+ clk_set_rate(clk, clk_get_rate(clk));
+}
+
+static void master_clk_recalc(struct clk *clk)
+{
+ unsigned long frqcr = ctrl_inl(FRQCR);
+
+ clk->rate = CONFIG_SH_PCLK_FREQ * (1 + (frqcr >> 24 & 0xF));
+}
+
+static int master_clk_setrate(struct clk *clk, unsigned long rate, int id)
+{
+ int div = rate / SH7722_PLL_FREQ;
+ int master_divs[] = { 2, 3, 4, 6, 8, 16 };
+ int index;
+ unsigned long frqcr;
+
+ if (rate < SH7722_PLL_FREQ * 2)
+ return -EINVAL;
+
+ for (index = 1; index < ARRAY_SIZE(master_divs); index++)
+ if (div >= master_divs[index - 1] && div < master_divs[index])
+ break;
+
+ if (index >= ARRAY_SIZE(master_divs))
+ index = ARRAY_SIZE(master_divs);
+ div = master_divs[index - 1];
+
+ frqcr = ctrl_inl(FRQCR);
+ frqcr &= ~(0xF << 24);
+ frqcr |= ( (div-1) << 24);
+ ctrl_outl(frqcr, FRQCR);
+
+ return 0;
+}
+
+static struct clk_ops sh7722_master_clk_ops = {
+ .init = master_clk_init,
+ .recalc = master_clk_recalc,
+ .set_rate = master_clk_setrate,
+};
+
+struct frqcr_context {
+ unsigned mask;
+ unsigned shift;
+};
+
+struct frqcr_context sh7722_get_clk_context(const char *name)
+{
+ struct frqcr_context ctx = { 0, };
+
+ if (!strcmp(name, "peripheral_clk")) {
+ ctx.shift = 0;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "sdram_clk")) {
+ ctx.shift = 4;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "bus_clk")) {
+ ctx.shift = 8;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "sh_clk")) {
+ ctx.shift = 12;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "umem_clk")) {
+ ctx.shift = 16;
+ ctx.mask = 0xF;
+ } else if (!strcmp(name, "cpu_clk")) {
+ ctx.shift = 20;
+ ctx.mask = 7;
+ }
+ return ctx;
+}
+
+/**
+ * sh7722_find_divisors - find divisor for setting rate
+ *
+ * All sh7722 clocks use the same set of multipliers/divisors. This function
+ * chooses correct divisor to set the rate of clock with parent clock that
+ * generates frequency of 'parent_rate'
+ *
+ * @parent_rate: rate of parent clock
+ * @rate: requested rate to be set
+ */
+static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
+{
+ unsigned div2 = parent_rate * 2 / rate;
+ int index;
+
+ if (rate > parent_rate)
+ return -EINVAL;
+
+ for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
+ if (div2 > divisors2[index] && div2 <= divisors2[index])
+ break;
+ }
+ if (index >= ARRAY_SIZE(divisors2))
+ index = ARRAY_SIZE(divisors2) - 1;
+ return divisors2[index];
+}
+
+static void sh7722_frqcr_recalc(struct clk *clk)
+{
+ struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
+ unsigned long frqcr = ctrl_inl(FRQCR);
+ int index;
+
+ index = (frqcr >> ctx.shift) & ctx.mask;
+ clk->rate = clk->parent->rate * 2 / divisors2[index];
+}
+
+static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
+ int algo_id)
+{
+ struct frqcr_context ctx = sh7722_get_clk_context(clk->name);
+ unsigned long parent_rate = clk->parent->rate;
+ int div;
+ unsigned long frqcr;
+ int err = 0;
+
+ /* pretty invalid */
+ if (parent_rate < rate)
+ return -EINVAL;
+
+ /* look for multiplier/divisor pair */
+ div = sh7722_find_divisors(parent_rate, rate);
+ if (div<0)
+ return div;
+
+ /* calculate new value of clock rate */
+ clk->rate = parent_rate * 2 / div;
+ frqcr = ctrl_inl(FRQCR);
+
+ /* FIXME: adjust as algo_id specifies */
+ if (algo_id != NO_CHANGE) {
+ int originator;
+ char *algo_group_1[] = { "cpu_clk", "umem_clk", "sh_clk" };
+ char *algo_group_2[] = { "sh_clk", "bus_clk" };
+ char *algo_group_3[] = { "sh_clk", "sdram_clk" };
+ char *algo_group_4[] = { "bus_clk", "peripheral_clk" };
+ char *algo_group_5[] = { "cpu_clk", "peripheral_clk" };
+ char **algo_current = NULL;
+ /* 3 is the maximum number of clocks in relation */
+ struct clk *ck[3];
+ unsigned long values[3]; /* the same comment as above */
+ int part_length = -1;
+ int i;
+
+ /*
+ * all the steps below only required if adjustion was
+ * requested
+ */
+ if (algo_id == IUS_N1_N1 ||
+ algo_id == IUS_322 ||
+ algo_id == IUS_522 ||
+ algo_id == IUS_N11) {
+ algo_current = algo_group_1;
+ part_length = 3;
+ }
+ if (algo_id == SB_N1) {
+ algo_current = algo_group_2;
+ part_length = 2;
+ }
+ if (algo_id == SB3_N1 ||
+ algo_id == SB3_32 ||
+ algo_id == SB3_43 ||
+ algo_id == SB3_54) {
+ algo_current = algo_group_3;
+ part_length = 2;
+ }
+ if (algo_id == BP_N1) {
+ algo_current = algo_group_4;
+ part_length = 2;
+ }
+ if (algo_id == IP_N1) {
+ algo_current = algo_group_5;
+ part_length = 2;
+ }
+ if (!algo_current)
+ goto incorrect_algo_id;
+
+ originator = -1;
+ for (i = 0; i < part_length; i ++ ) {
+ if (originator >= 0 && !strcmp(clk->name,
+ algo_current[i]))
+ originator = i;
+ ck[i] = clk_get(NULL, algo_current[i]);
+ values[i] = clk_get_rate(ck[i]);
+ }
+
+ if (originator >= 0)
+ adjust_clocks(originator, adjust_algos[algo_id],
+ values, part_length);
+
+ for (i = 0; i < part_length; i ++ ) {
+ struct frqcr_context part_ctx;
+ int part_div;
+
+ if (likely(!err)) {
+ part_div = sh7722_find_divisors(parent_rate,
+ rate);
+ if (part_div > 0) {
+ part_ctx = sh7722_get_clk_context(
+ ck[i]->name);
+ frqcr &= ~(part_ctx.mask <<
+ part_ctx.shift);
+ frqcr |= part_div << part_ctx.shift;
+ } else
+ err = part_div;
+ }
+
+ ck[i]->ops->recalc(ck[i]);
+ clk_put(ck[i]);
+ }
+ }
+
+ /* was there any error during recalculation ? If so, bail out.. */
+ if (unlikely(err!=0))
+ goto out_err;
+
+ /* clear FRQCR bits */
+ frqcr &= ~(ctx.mask << ctx.shift);
+ frqcr |= div << ctx.shift;
+
+ /* ...and perform actual change */
+ ctrl_outl(frqcr, FRQCR);
+ return 0;
+
+incorrect_algo_id:
+ return -EINVAL;
+out_err:
+ return err;
+}
+
+static struct clk_ops sh7722_frqcr_clk_ops = {
+ .recalc = sh7722_frqcr_recalc,
+ .set_rate = sh7722_frqcr_set_rate,
+};
+
+/*
+ * clock ops methods for SIU A/B and IrDA clock
+ *
+ */
+static int sh7722_siu_which(struct clk *clk)
+{
+ if (!strcmp(clk->name, "siu_a_clk"))
+ return 0;
+ if (!strcmp(clk->name, "siu_b_clk"))
+ return 1;
+ if (!strcmp(clk->name, "irda_clk"))
+ return 2;
+ return -EINVAL;
+}
+
+static unsigned long sh7722_siu_regs[] = {
+ [0] = SCLKACR,
+ [1] = SCLKBCR,
+ [2] = IrDACLKCR,
+};
+
+static int sh7722_siu_start_stop(struct clk *clk, int enable)
+{
+ int siu = sh7722_siu_which(clk);
+ unsigned long r;
+
+ if (siu < 0)
+ return siu;
+ BUG_ON(siu > 2);
+ r = ctrl_inl(sh7722_siu_regs[siu]);
+ if (enable)
+ ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]);
+ else
+ ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]);
+ return 0;
+}
+
+static void sh7722_siu_enable(struct clk *clk)
+{
+ sh7722_siu_start_stop(clk, 1);
+}
+
+static void sh7722_siu_disable(struct clk *clk)
+{
+ sh7722_siu_start_stop(clk, 0);
+}
+
+static void sh7722_video_enable(struct clk *clk)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ ctrl_outl( r & ~(1<<8), VCLKCR);
+}
+
+static void sh7722_video_disable(struct clk *clk)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ ctrl_outl( r | (1<<8), VCLKCR);
+}
+
+static int sh7722_video_set_rate(struct clk *clk, unsigned long rate,
+ int algo_id)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ r &= ~0x3F;
+ r |= ((clk->parent->rate / rate - 1) & 0x3F);
+ ctrl_outl(r, VCLKCR);
+ return 0;
+}
+
+static void sh7722_video_recalc(struct clk *clk)
+{
+ unsigned long r;
+
+ r = ctrl_inl(VCLKCR);
+ clk->rate = clk->parent->rate / ((r & 0x3F) + 1);
+}
+
+static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
+{
+ int siu = sh7722_siu_which(clk);
+ unsigned long r;
+ int div;
+
+ if (siu < 0)
+ return siu;
+ BUG_ON(siu > 2);
+ r = ctrl_inl(sh7722_siu_regs[siu]);
+ div = sh7722_find_divisors(clk->parent->rate, rate);
+ if (div < 0)
+ return div;
+ r = (r & ~0xF) | div;
+ ctrl_outl(r, sh7722_siu_regs[siu]);
+ return 0;
+}
+
+static void sh7722_siu_recalc(struct clk *clk)
+{
+ int siu = sh7722_siu_which(clk);
+ unsigned long r;
+
+ if (siu < 0)
+ return /* siu */ ;
+ BUG_ON(siu > 1);
+ r = ctrl_inl(sh7722_siu_regs[siu]);
+ clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
+}
+
+static struct clk_ops sh7722_siu_clk_ops = {
+ .recalc = sh7722_siu_recalc,
+ .set_rate = sh7722_siu_set_rate,
+ .enable = sh7722_siu_enable,
+ .disable = sh7722_siu_disable,
+};
+
+static struct clk_ops sh7722_video_clk_ops = {
+ .recalc = sh7722_video_recalc,
+ .set_rate = sh7722_video_set_rate,
+ .enable = sh7722_video_enable,
+ .disable = sh7722_video_disable,
+};
+/*
+ * and at last, clock definitions themselves
+ */
+static struct clk sh7722_umem_clock = {
+ .name = "umem_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_sh_clock = {
+ .name = "sh_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_peripheral_clock = {
+ .name = "peripheral_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+static struct clk sh7722_sdram_clock = {
+ .name = "sdram_clk",
+ .ops = &sh7722_frqcr_clk_ops,
+};
+
+/*
+ * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops
+ * methods of clk_ops determine which register they should access by
+ * examining clk->name field
+ */
+static struct clk sh7722_siu_a_clock = {
+ .name = "siu_a_clk",
+ .ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_siu_b_clock = {
+ .name = "siu_b_clk",
+ .ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_irda_clock = {
+ .name = "irda_clk",
+ .ops = &sh7722_siu_clk_ops,
+};
+
+static struct clk sh7722_video_clock = {
+ .name = "video_clk",
+ .ops = &sh7722_video_clk_ops,
+};
+
+static struct clk *sh7722_clocks[] = {
+ &sh7722_umem_clock,
+ &sh7722_sh_clock,
+ &sh7722_peripheral_clock,
+ &sh7722_sdram_clock,
+ &sh7722_siu_a_clock,
+ &sh7722_siu_b_clock,
+ &sh7722_irda_clock,
+ &sh7722_video_clock,
+};
+
+/*
+ * init in order: master, module, bus, cpu
+ */
+struct clk_ops *onchip_ops[] = {
+ &sh7722_master_clk_ops,
+ &sh7722_frqcr_clk_ops,
+ &sh7722_frqcr_clk_ops,
+ &sh7722_frqcr_clk_ops,
+};
+
+void __init
+arch_init_clk_ops(struct clk_ops **ops, int type)
+{
+ BUG_ON(type < 0 || type > ARRAY_SIZE(onchip_ops));
+ *ops = onchip_ops[type];
+}
+
+int __init sh7722_clock_init(void)
+{
+ struct clk *master;
+ int i;
+
+ master = clk_get(NULL, "master_clk");
+ for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
+ pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
+ sh7722_clocks[i]->parent = master;
+ clk_register(sh7722_clocks[i]);
+ }
+ clk_put(master);
+ return 0;
+}
+arch_initcall(sh7722_clock_init);
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
index c8694bac647..8e236062c72 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7770.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/cpu/sh4/clock-sh7770.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7770.c
*
* SH7770 support for the clock framework
*
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
index 9e6a216750c..01f3da619d3 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/cpu/sh4/clock-sh7780.c
+ * arch/sh/kernel/cpu/sh4a/clock-sh7780.c
*
* SH7780 support for the clock framework
*
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7785.c b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
new file mode 100644
index 00000000000..805535aa505
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7785.c
@@ -0,0 +1,162 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7785.c
+ *
+ * SH7785 support for the clock framework
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int ifc_divisors[] = { 1, 2, 4, 6 };
+static int ufc_divisors[] = { 1, 1, 4, 6 };
+static int sfc_divisors[] = { 1, 1, 4, 6 };
+static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18,
+ 24, 32, 36, 48, 1, 1, 1, 1 };
+static int mfc_divisors[] = { 1, 1, 4, 6 };
+static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18,
+ 24, 32, 36, 48, 1, 1, 1, 1 };
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->rate *= 36;
+}
+
+static struct clk_ops sh7785_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int idx = (ctrl_inl(FRQMR1) & 0x000f);
+ clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 16) & 0x000f);
+ clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 28) & 0x0003);
+ clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7785_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7785_clk_ops[] = {
+ &sh7785_master_clk_ops,
+ &sh7785_module_clk_ops,
+ &sh7785_bus_clk_ops,
+ &sh7785_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7785_clk_ops))
+ *ops = sh7785_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 20) & 0x0003);
+ clk->rate = clk->parent->rate / sfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_shyway_clk_ops = {
+ .recalc = shyway_clk_recalc,
+};
+
+static struct clk sh7785_shyway_clk = {
+ .name = "shyway_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7785_shyway_clk_ops,
+};
+
+static void ddr_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 12) & 0x0003);
+ clk->rate = clk->parent->rate / mfc_divisors[idx];
+}
+
+static struct clk_ops sh7785_ddr_clk_ops = {
+ .recalc = ddr_clk_recalc,
+};
+
+static struct clk sh7785_ddr_clk = {
+ .name = "ddr_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7785_ddr_clk_ops,
+};
+
+static void ram_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQMR1) >> 24) & 0x0003);
+ clk->rate = clk->parent->rate / ufc_divisors[idx];
+}
+
+static struct clk_ops sh7785_ram_clk_ops = {
+ .recalc = ram_clk_recalc,
+};
+
+static struct clk sh7785_ram_clk = {
+ .name = "ram_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &sh7785_ram_clk_ops,
+};
+
+/*
+ * Additional SH7785-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *sh7785_onchip_clocks[] = {
+ &sh7785_shyway_clk,
+ &sh7785_ddr_clk,
+ &sh7785_ram_clk,
+};
+
+static int __init sh7785_clk_init(void)
+{
+ struct clk *clk = clk_get(NULL, "master_clk");
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sh7785_onchip_clocks); i++) {
+ struct clk *clkp = sh7785_onchip_clocks[i];
+
+ clkp->parent = clk;
+ clk_register(clkp);
+ clk_enable(clkp);
+ }
+
+ /*
+ * Now that we have the rest of the clocks registered, we need to
+ * force the parent clock to propagate so that these clocks will
+ * automatically figure out their rate. We cheat by handing the
+ * parent clock its current rate and forcing child propagation.
+ */
+ clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_put(clk);
+
+ return 0;
+}
+arch_initcall(sh7785_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
new file mode 100644
index 00000000000..07b0de82cfe
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -0,0 +1,103 @@
+/*
+ * SH7785 Setup
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffea0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffeb0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 44, 45, 47, 46 },
+ },
+
+ /*
+ * The rest of these all have multiplexed IRQs
+ */
+ {
+ .mapbase = 0xffec0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 60, 60, 60, 60 },
+ }, {
+ .mapbase = 0xffed0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 61, 61, 61, 61 },
+ }, {
+ .mapbase = 0xffee0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 62, 62, 62, 62 },
+ }, {
+ .mapbase = 0xffef0000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 63, 63, 63, 63 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7785_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7785_devices_setup(void)
+{
+ return platform_add_devices(sh7785_devices,
+ ARRAY_SIZE(sh7785_devices));
+}
+__initcall(sh7785_devices_setup);
+
+static struct intc2_data intc2_irq_table[] = {
+ { 28, 0, 24, 0, 0, 2 }, /* TMU0 */
+
+ { 40, 8, 24, 0, 2, 3 }, /* SCIF0 ERI */
+ { 41, 8, 24, 0, 2, 3 }, /* SCIF0 RXI */
+ { 42, 8, 24, 0, 2, 3 }, /* SCIF0 BRI */
+ { 43, 8, 24, 0, 2, 3 }, /* SCIF0 TXI */
+
+ { 44, 8, 16, 0, 3, 3 }, /* SCIF1 ERI */
+ { 45, 8, 16, 0, 3, 3 }, /* SCIF1 RXI */
+ { 46, 8, 16, 0, 3, 3 }, /* SCIF1 BRI */
+ { 47, 8, 16, 0, 3, 3 }, /* SCIF1 TXI */
+
+ { 64, 0x14, 8, 0, 14, 2 }, /* PCIC0 */
+ { 65, 0x14, 0, 0, 15, 2 }, /* PCIC1 */
+ { 66, 0x18, 24, 0, 16, 2 }, /* PCIC2 */
+ { 67, 0x18, 16, 0, 17, 2 }, /* PCIC3 */
+ { 68, 0x18, 8, 0, 18, 2 }, /* PCIC4 */
+
+ { 60, 8, 8, 0, 4, 3 }, /* SCIF2 ERI, RXI, BRI, TXI */
+ { 60, 8, 0, 0, 5, 3 }, /* SCIF3 ERI, RXI, BRI, TXI */
+ { 60, 12, 24, 0, 6, 3 }, /* SCIF4 ERI, RXI, BRI, TXI */
+ { 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */
+};
+
+void __init init_IRQ_intc2(void)
+{
+ make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
+}
diff --git a/arch/sh/kernel/crash_dump.c b/arch/sh/kernel/crash_dump.c
new file mode 100644
index 00000000000..4a2ecbe27d8
--- /dev/null
+++ b/arch/sh/kernel/crash_dump.c
@@ -0,0 +1,46 @@
+/*
+ * crash_dump.c - Memory preserving reboot related code.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2004. All rights reserved
+ */
+
+#include <linux/errno.h>
+#include <linux/crash_dump.h>
+#include <linux/io.h>
+#include <asm/uaccess.h>
+
+/**
+ * copy_oldmem_page - copy one page from "oldmem"
+ * @pfn: page frame number to be copied
+ * @buf: target memory address for the copy; this can be in kernel address
+ * space or user address space (see @userbuf)
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page (based on pfn) to begin the copy
+ * @userbuf: if set, @buf is in user address space, use copy_to_user(),
+ * otherwise @buf is in kernel address space, use memcpy().
+ *
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+ size_t csize, unsigned long offset, int userbuf)
+{
+ void *vaddr;
+
+ if (!csize)
+ return 0;
+
+ vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+
+ if (userbuf) {
+ if (copy_to_user(buf, (vaddr + offset), csize)) {
+ iounmap(vaddr);
+ return -EFAULT;
+ }
+ } else
+ memcpy(buf, (vaddr + offset), csize);
+
+ iounmap(vaddr);
+ return csize;
+}
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 9048c0326d8..9833493d886 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -192,20 +192,14 @@ int __init setup_early_printk(char *buf)
}
#endif
- if (likely(early_console))
+ if (likely(early_console)) {
+ if (keep_early)
+ early_console->flags &= ~CON_BOOT;
+ else
+ early_console->flags |= CON_BOOT;
register_console(early_console);
+ }
return 0;
}
early_param("earlyprintk", setup_early_printk);
-
-void __init disable_early_printk(void)
-{
- if (!early_console_initialized || !early_console)
- return;
- if (!keep_early) {
- printk("disabling early console\n");
- unregister_console(early_console);
- } else
- printk("keeping early console\n");
-}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 9bdd8a00cd4..27b923c45b3 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -13,6 +13,7 @@
#include <linux/seq_file.h>
#include <linux/irq.h>
#include <asm/processor.h>
+#include <asm/machvec.h>
#include <asm/uaccess.h>
#include <asm/thread_info.h>
#include <asm/cpu/mmu_context.h>
@@ -44,7 +45,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
}
- if (i < NR_IRQS) {
+ if (i < sh_mv.mv_nr_irqs) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
if (!action)
@@ -61,7 +62,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
unlock:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
- } else if (i == NR_IRQS)
+ } else if (i == sh_mv.mv_nr_irqs)
seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
return 0;
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index d8927d85492..a5323364cbc 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -6,11 +6,11 @@
* David Grothe <dave@gcom.com>, Tigran Aivazian <tigran@sco.com>,
* Amit S. Kale <akale@veritas.com>, William Gatliff <bgat@open-widgets.com>,
* Ben Lee, Steve Chamberlain and Benoit Miller <fulg@iname.com>.
- *
+ *
* This version by Henry Bell <henry.bell@st.com>
* Minor modifications by Jeremy Siegel <jsiegel@mvista.com>
- *
- * Contains low-level support for remote debug using GDB.
+ *
+ * Contains low-level support for remote debug using GDB.
*
* To enable debugger support, two things need to happen. A call to
* set_debug_traps() is necessary in order to allow any breakpoints
@@ -48,7 +48,7 @@
* k kill (Detach GDB)
*
* d Toggle debug flag
- * D Detach GDB
+ * D Detach GDB
*
* Hct Set thread t for operations, OK or ENN
* c = 'c' (step, cont), c = 'g' (other
@@ -58,7 +58,7 @@
* qfThreadInfo Get list of current threads (first) m<id>
* qsThreadInfo " " " " " (subsequent)
* qOffsets Get section offsets Text=x;Data=y;Bss=z
- *
+ *
* TXX Find if thread XX is alive OK or ENN
* ? What was the last sigval ? SNN (signal NN)
* O Output to GDB console
@@ -74,7 +74,7 @@
* '$' or '#'. If <data> starts with two characters followed by
* ':', then the existing stubs interpret this as a sequence number.
*
- * CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ * CSUM1 and CSUM2 are ascii hex representation of an 8-bit
* checksum of <data>, the most significant nibble is sent first.
* the hex digits 0-9,a-f are used.
*
@@ -86,8 +86,8 @@
* Responses can be run-length encoded to save space. A '*' means that
* the next character is an ASCII encoding giving a repeat count which
* stands for that many repititions of the character preceding the '*'.
- * The encoding is n+29, yielding a printable character where n >=3
- * (which is where RLE starts to win). Don't use an n > 126.
+ * The encoding is n+29, yielding a printable character where n >=3
+ * (which is where RLE starts to win). Don't use an n > 126.
*
* So "0* " means the same as "0000".
*/
@@ -100,12 +100,10 @@
#include <linux/delay.h>
#include <linux/linkage.h>
#include <linux/init.h>
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
#include <linux/console.h>
-#endif
-
+#include <linux/sysrq.h>
#include <asm/system.h>
+#include <asm/cacheflush.h>
#include <asm/current.h>
#include <asm/signal.h>
#include <asm/pgtable.h>
@@ -153,7 +151,6 @@ char kgdb_in_gdb_mode;
char in_nmi; /* Set during NMI to prevent reentry */
int kgdb_nofault; /* Boolean to ignore bus errs (i.e. in GDB) */
int kgdb_enabled = 1; /* Default to enabled, cmdline can disable */
-int kgdb_halt;
/* Exposed for user access */
struct task_struct *kgdb_current;
@@ -246,14 +243,6 @@ static char out_buffer[OUTBUFMAX];
static void kgdb_to_gdb(const char *s);
-#ifdef CONFIG_KGDB_THREAD
-static struct task_struct *trapped_thread;
-static struct task_struct *current_thread;
-typedef unsigned char threadref[8];
-#define BUF_THREAD_ID_SIZE 16
-#endif
-
-
/* Convert ch to hex */
static int hex(const char ch)
{
@@ -328,7 +317,7 @@ static int hex_to_int(char **ptr, int *int_value)
}
/* Copy the binary array pointed to by buf into mem. Fix $, #,
- and 0x7d escaped with 0x7d. Return a pointer to the character
+ and 0x7d escaped with 0x7d. Return a pointer to the character
after the last byte written. */
static char *ebin_to_mem(const char *buf, char *mem, int count)
{
@@ -349,66 +338,6 @@ static char *pack_hex_byte(char *pkt, int byte)
return pkt;
}
-#ifdef CONFIG_KGDB_THREAD
-
-/* Pack a thread ID */
-static char *pack_threadid(char *pkt, threadref * id)
-{
- char *limit;
- unsigned char *altid;
-
- altid = (unsigned char *) id;
-
- limit = pkt + BUF_THREAD_ID_SIZE;
- while (pkt < limit)
- pkt = pack_hex_byte(pkt, *altid++);
- return pkt;
-}
-
-/* Convert an integer into our threadref */
-static void int_to_threadref(threadref * id, const int value)
-{
- unsigned char *scan = (unsigned char *) id;
- int i = 4;
-
- while (i--)
- *scan++ = 0;
-
- *scan++ = (value >> 24) & 0xff;
- *scan++ = (value >> 16) & 0xff;
- *scan++ = (value >> 8) & 0xff;
- *scan++ = (value & 0xff);
-}
-
-/* Return a task structure ptr for a particular pid */
-static struct task_struct *get_thread(int pid)
-{
- struct task_struct *thread;
-
- /* Use PID_MAX w/gdb for pid 0 */
- if (pid == PID_MAX) pid = 0;
-
- /* First check via PID */
- thread = find_task_by_pid(pid);
-
- if (thread)
- return thread;
-
- /* Start at the start */
- thread = init_tasks[0];
-
- /* Walk along the linked list of tasks */
- do {
- if (thread->pid == pid)
- return thread;
- thread = thread->next_task;
- } while (thread != init_tasks[0]);
-
- return NULL;
-}
-
-#endif /* CONFIG_KGDB_THREAD */
-
/* Scan for the start char '$', read the packet and check the checksum */
static void get_packet(char *buffer, int buflen)
{
@@ -452,7 +381,7 @@ static void get_packet(char *buffer, int buflen)
/* Ack successful transfer */
put_debug_char('+');
- /* If a sequence char is present, reply
+ /* If a sequence char is present, reply
the sequence ID */
if (buffer[2] == ':') {
put_debug_char(buffer[0]);
@@ -611,74 +540,6 @@ static void gdb_regs_to_kgdb_regs(const int *gdb_regs,
regs->vbr = gdb_regs[VBR];
}
-#ifdef CONFIG_KGDB_THREAD
-/* Make a local copy of registers from the specified thread */
-asmlinkage void ret_from_fork(void);
-static void thread_regs_to_gdb_regs(const struct task_struct *thread,
- int *gdb_regs)
-{
- int regno;
- int *tregs;
-
- /* Initialize to zero */
- for (regno = 0; regno < MAXREG; regno++)
- gdb_regs[regno] = 0;
-
- /* Just making sure... */
- if (thread == NULL)
- return;
-
- /* A new fork has pt_regs on the stack from a fork() call */
- if (thread->thread.pc == (unsigned long)ret_from_fork) {
-
- int vbr_val;
- struct pt_regs *kregs;
- kregs = (struct pt_regs*)thread->thread.sp;
-
- gdb_regs[R0] = kregs->regs[R0];
- gdb_regs[R1] = kregs->regs[R1];
- gdb_regs[R2] = kregs->regs[R2];
- gdb_regs[R3] = kregs->regs[R3];
- gdb_regs[R4] = kregs->regs[R4];
- gdb_regs[R5] = kregs->regs[R5];
- gdb_regs[R6] = kregs->regs[R6];
- gdb_regs[R7] = kregs->regs[R7];
- gdb_regs[R8] = kregs->regs[R8];
- gdb_regs[R9] = kregs->regs[R9];
- gdb_regs[R10] = kregs->regs[R10];
- gdb_regs[R11] = kregs->regs[R11];
- gdb_regs[R12] = kregs->regs[R12];
- gdb_regs[R13] = kregs->regs[R13];
- gdb_regs[R14] = kregs->regs[R14];
- gdb_regs[R15] = kregs->regs[R15];
- gdb_regs[PC] = kregs->pc;
- gdb_regs[PR] = kregs->pr;
- gdb_regs[GBR] = kregs->gbr;
- gdb_regs[MACH] = kregs->mach;
- gdb_regs[MACL] = kregs->macl;
- gdb_regs[SR] = kregs->sr;
-
- asm("stc vbr, %0":"=r"(vbr_val));
- gdb_regs[VBR] = vbr_val;
- return;
- }
-
- /* Otherwise, we have only some registers from switch_to() */
- tregs = (int *)thread->thread.sp;
- gdb_regs[R15] = (int)tregs;
- gdb_regs[R14] = *tregs++;
- gdb_regs[R13] = *tregs++;
- gdb_regs[R12] = *tregs++;
- gdb_regs[R11] = *tregs++;
- gdb_regs[R10] = *tregs++;
- gdb_regs[R9] = *tregs++;
- gdb_regs[R8] = *tregs++;
- gdb_regs[PR] = *tregs++;
- gdb_regs[GBR] = *tregs++;
- gdb_regs[PC] = thread->thread.pc;
-}
-#endif /* CONFIG_KGDB_THREAD */
-
/* Calculate the new address for after a step */
static short *get_step_address(void)
{
@@ -759,7 +620,7 @@ static short *get_step_address(void)
return (short *) addr;
}
-/* Set up a single-step. Replace the instruction immediately after the
+/* Set up a single-step. Replace the instruction immediately after the
current instruction (i.e. next in the expected flow of control) with a
trap instruction, so that returning will cause only a single instruction
to be executed. Note that this model is slightly broken for instructions
@@ -797,37 +658,11 @@ static void undo_single_step(void)
/* Send a signal message */
static void send_signal_msg(const int signum)
{
-#ifndef CONFIG_KGDB_THREAD
out_buffer[0] = 'S';
out_buffer[1] = highhex(signum);
out_buffer[2] = lowhex(signum);
out_buffer[3] = 0;
put_packet(out_buffer);
-#else /* CONFIG_KGDB_THREAD */
- int threadid;
- threadref thref;
- char *out = out_buffer;
- const char *tstring = "thread";
-
- *out++ = 'T';
- *out++ = highhex(signum);
- *out++ = lowhex(signum);
-
- while (*tstring) {
- *out++ = *tstring++;
- }
- *out++ = ':';
-
- threadid = trapped_thread->pid;
- if (threadid == 0) threadid = PID_MAX;
- int_to_threadref(&thref, threadid);
- pack_threadid(out, &thref);
- out += BUF_THREAD_ID_SIZE;
- *out++ = ';';
-
- *out = 0;
- put_packet(out_buffer);
-#endif /* CONFIG_KGDB_THREAD */
}
/* Reply that all was well */
@@ -962,15 +797,7 @@ static void step_with_sig_msg(void)
/* Send register contents */
static void send_regs_msg(void)
{
-#ifdef CONFIG_KGDB_THREAD
- if (!current_thread)
- kgdb_regs_to_gdb_regs(&trap_registers, registers);
- else
- thread_regs_to_gdb_regs(current_thread, registers);
-#else
kgdb_regs_to_gdb_regs(&trap_registers, registers);
-#endif
-
mem_to_hex((char *) registers, out_buffer, NUMREGBYTES);
put_packet(out_buffer);
}
@@ -978,201 +805,13 @@ static void send_regs_msg(void)
/* Set register contents - currently can't set other thread's registers */
static void set_regs_msg(void)
{
-#ifdef CONFIG_KGDB_THREAD
- if (!current_thread) {
-#endif
- kgdb_regs_to_gdb_regs(&trap_registers, registers);
- hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
- gdb_regs_to_kgdb_regs(registers, &trap_registers);
- send_ok_msg();
-#ifdef CONFIG_KGDB_THREAD
- } else
- send_err_msg();
-#endif
-}
-
-
-#ifdef CONFIG_KGDB_THREAD
-
-/* Set the status for a thread */
-void set_thread_msg(void)
-{
- int threadid;
- struct task_struct *thread = NULL;
- char *ptr;
-
- switch (in_buffer[1]) {
-
- /* To select which thread for gG etc messages, i.e. supported */
- case 'g':
-
- ptr = &in_buffer[2];
- hex_to_int(&ptr, &threadid);
- thread = get_thread(threadid);
-
- /* If we haven't found it */
- if (!thread) {
- send_err_msg();
- break;
- }
-
- /* Set current_thread (or not) */
- if (thread == trapped_thread)
- current_thread = NULL;
- else
- current_thread = thread;
- send_ok_msg();
- break;
-
- /* To select which thread for cCsS messages, i.e. unsupported */
- case 'c':
- send_ok_msg();
- break;
-
- default:
- send_empty_msg();
- break;
- }
-}
-
-/* Is a thread alive? */
-static void thread_status_msg(void)
-{
- char *ptr;
- int threadid;
- struct task_struct *thread = NULL;
-
- ptr = &in_buffer[1];
- hex_to_int(&ptr, &threadid);
- thread = get_thread(threadid);
- if (thread)
- send_ok_msg();
- else
- send_err_msg();
-}
-/* Send the current thread ID */
-static void thread_id_msg(void)
-{
- int threadid;
- threadref thref;
-
- out_buffer[0] = 'Q';
- out_buffer[1] = 'C';
-
- if (current_thread)
- threadid = current_thread->pid;
- else if (trapped_thread)
- threadid = trapped_thread->pid;
- else /* Impossible, but just in case! */
- {
- send_err_msg();
- return;
- }
-
- /* Translate pid 0 to PID_MAX for gdb */
- if (threadid == 0) threadid = PID_MAX;
-
- int_to_threadref(&thref, threadid);
- pack_threadid(out_buffer + 2, &thref);
- out_buffer[2 + BUF_THREAD_ID_SIZE] = '\0';
- put_packet(out_buffer);
-}
-
-/* Send thread info */
-static void thread_info_msg(void)
-{
- struct task_struct *thread = NULL;
- int threadid;
- char *pos;
- threadref thref;
-
- /* Start with 'm' */
- out_buffer[0] = 'm';
- pos = &out_buffer[1];
-
- /* For all possible thread IDs - this will overrun if > 44 threads! */
- /* Start at 1 and include PID_MAX (since GDB won't use pid 0...) */
- for (threadid = 1; threadid <= PID_MAX; threadid++) {
-
- read_lock(&tasklist_lock);
- thread = get_thread(threadid);
- read_unlock(&tasklist_lock);
-
- /* If it's a valid thread */
- if (thread) {
- int_to_threadref(&thref, threadid);
- pack_threadid(pos, &thref);
- pos += BUF_THREAD_ID_SIZE;
- *pos++ = ',';
- }
- }
- *--pos = 0; /* Lose final comma */
- put_packet(out_buffer);
-
-}
-
-/* Return printable info for gdb's 'info threads' command */
-static void thread_extra_info_msg(void)
-{
- int threadid;
- struct task_struct *thread = NULL;
- char buffer[20], *ptr;
- int i;
-
- /* Extract thread ID */
- ptr = &in_buffer[17];
- hex_to_int(&ptr, &threadid);
- thread = get_thread(threadid);
-
- /* If we don't recognise it, say so */
- if (thread == NULL)
- strcpy(buffer, "(unknown)");
- else
- strcpy(buffer, thread->comm);
-
- /* Construct packet */
- for (i = 0, ptr = out_buffer; buffer[i]; i++)
- ptr = pack_hex_byte(ptr, buffer[i]);
-
- if (thread->thread.pc == (unsigned long)ret_from_fork) {
- strcpy(buffer, "<new fork>");
- for (i = 0; buffer[i]; i++)
- ptr = pack_hex_byte(ptr, buffer[i]);
- }
-
- *ptr = '\0';
- put_packet(out_buffer);
-}
-
-/* Handle all qFooBarBaz messages - have to use an if statement as
- opposed to a switch because q messages can have > 1 char id. */
-static void query_msg(void)
-{
- const char *q_start = &in_buffer[1];
-
- /* qC = return current thread ID */
- if (strncmp(q_start, "C", 1) == 0)
- thread_id_msg();
-
- /* qfThreadInfo = query all threads (first) */
- else if (strncmp(q_start, "fThreadInfo", 11) == 0)
- thread_info_msg();
-
- /* qsThreadInfo = query all threads (subsequent). We know we have sent
- them all after the qfThreadInfo message, so there are no to send */
- else if (strncmp(q_start, "sThreadInfo", 11) == 0)
- put_packet("l"); /* el = last */
-
- /* qThreadExtraInfo = supply printable information per thread */
- else if (strncmp(q_start, "ThreadExtraInfo", 15) == 0)
- thread_extra_info_msg();
-
- /* Unsupported - empty message as per spec */
- else
- send_empty_msg();
+ kgdb_regs_to_gdb_regs(&trap_registers, registers);
+ hex_to_mem(&in_buffer[1], (char *) registers, NUMREGBYTES);
+ gdb_regs_to_kgdb_regs(registers, &trap_registers);
+ send_ok_msg();
}
-#endif /* CONFIG_KGDB_THREAD */
+#ifdef CONFIG_SH_KGDB_CONSOLE
/*
* Bring up the ports..
*/
@@ -1185,6 +824,9 @@ static int kgdb_serial_setup(void)
return 0;
}
+#else
+#define kgdb_serial_setup() 0
+#endif
/* The command loop, read and act on requests */
static void kgdb_command_loop(const int excep_code, const int trapa_value)
@@ -1193,7 +835,7 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
if (excep_code == NMI_VEC) {
#ifndef CONFIG_KGDB_NMI
- KGDB_PRINTK("Ignoring unexpected NMI?\n");
+ printk(KERN_NOTICE "KGDB: Ignoring unexpected NMI?\n");
return;
#else /* CONFIG_KGDB_NMI */
if (!kgdb_enabled) {
@@ -1207,19 +849,10 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
if (!kgdb_enabled)
return;
-#ifdef CONFIG_KGDB_THREAD
- /* Until GDB specifies a thread */
- current_thread = NULL;
- trapped_thread = current;
-#endif
-
/* Enter GDB mode (e.g. after detach) */
if (!kgdb_in_gdb_mode) {
/* Do serial setup, notify user, issue preemptive ack */
- kgdb_serial_setup();
- KGDB_PRINTK("Waiting for GDB (on %s%d at %d baud)\n",
- (kgdb_porttype ? kgdb_porttype->name : ""),
- kgdb_portnum, kgdb_baud);
+ printk(KERN_NOTICE "KGDB: Waiting for GDB\n");
kgdb_in_gdb_mode = 1;
put_debug_char('+');
}
@@ -1233,21 +866,18 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
will later be replaced by its original one. Do NOT do this for
trap 0xff, since that indicates a compiled-in breakpoint which
will not be replaced (and we would retake the trap forever) */
- if ((excep_code == TRAP_VEC) && (trapa_value != (0xff << 2))) {
+ if ((excep_code == TRAP_VEC) && (trapa_value != (0x3c << 2)))
trap_registers.pc -= 2;
- }
/* Undo any stepping we may have done */
undo_single_step();
while (1) {
-
out_buffer[0] = 0;
get_packet(in_buffer, BUFMAX);
/* Examine first char of buffer to see what we need to do */
switch (in_buffer[0]) {
-
case '?': /* Send which signal we've received */
send_signal_msg(sigval);
break;
@@ -1291,21 +921,6 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
step_msg();
return;
-#ifdef CONFIG_KGDB_THREAD
-
- case 'H': /* Task related */
- set_thread_msg();
- break;
-
- case 'T': /* Query thread status */
- thread_status_msg();
- break;
-
- case 'q': /* Handle query - currently thread-related */
- query_msg();
- break;
-#endif
-
case 'k': /* 'Kill the program' with a kernel ? */
break;
@@ -1323,11 +938,8 @@ static void kgdb_command_loop(const int excep_code, const int trapa_value)
}
/* There has been an exception, most likely a breakpoint. */
-asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+static void handle_exception(struct pt_regs *regs)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int excep_code, vbr_val;
int count;
int trapa_value = ctrl_inl(TRA);
@@ -1355,7 +967,7 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
kgdb_trapa_val = trapa_value;
/* Act on the exception */
- kgdb_command_loop(excep_code >> 5, trapa_value);
+ kgdb_command_loop(excep_code, trapa_value);
kgdb_current = NULL;
@@ -1373,14 +985,12 @@ asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
asm("ldc %0, vbr": :"r"(vbr_val));
}
-/* Trigger a breakpoint by function */
-void breakpoint(void)
+asmlinkage void kgdb_handle_exception(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs)
{
- if (!kgdb_enabled) {
- kgdb_enabled = 1;
- kgdb_init();
- }
- BREAKPOINT();
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
+ handle_exception(regs);
}
/* Initialise the KGDB data structures and serial configuration */
@@ -1395,24 +1005,16 @@ int kgdb_init(void)
kgdb_in_gdb_mode = 0;
if (kgdb_serial_setup() != 0) {
- KGDB_PRINTK("serial setup error\n");
+ printk(KERN_NOTICE "KGDB: serial setup error\n");
return -1;
}
/* Init ptr to exception handler */
- kgdb_debug_hook = kgdb_handle_exception;
+ kgdb_debug_hook = handle_exception;
kgdb_bus_err_hook = kgdb_handle_bus_error;
/* Enter kgdb now if requested, or just report init done */
- if (kgdb_halt) {
- kgdb_in_gdb_mode = 1;
- put_debug_char('+');
- breakpoint();
- }
- else
- {
- KGDB_PRINTK("stub is initialized.\n");
- }
+ printk(KERN_NOTICE "KGDB: stub is initialized.\n");
return 0;
}
@@ -1437,7 +1039,7 @@ static void kgdb_msg_write(const char *s, unsigned count)
/* Calculate how many this time */
wcount = (count > MAXOUT) ? MAXOUT : count;
-
+
/* Pack in hex chars */
for (i = 0; i < wcount; i++)
bufptr = pack_hex_byte(bufptr, s[i]);
@@ -1467,3 +1069,25 @@ void kgdb_console_write(struct console *co, const char *s, unsigned count)
kgdb_msg_write(s, count);
}
#endif
+
+#ifdef CONFIG_KGDB_SYSRQ
+static void sysrq_handle_gdb(int key, struct tty_struct *tty)
+{
+ printk("Entering GDB stub\n");
+ breakpoint();
+}
+
+static struct sysrq_key_op sysrq_gdb_op = {
+ .handler = sysrq_handle_gdb,
+ .help_msg = "Gdb",
+ .action_msg = "GDB",
+};
+
+static int gdb_register_sysrq(void)
+{
+ printk("Registering GDB sysrq handler\n");
+ register_sysrq_key('g', &sysrq_gdb_op);
+ return 0;
+}
+module_init(gdb_register_sysrq);
+#endif
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 08587cdb64d..790ed69b866 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -59,13 +59,13 @@ static void kexec_info(struct kimage *image)
printk(" segment[%d]: 0x%08x - 0x%08x (0x%08x)\n",
i,
(unsigned int)image->segment[i].mem,
- (unsigned int)image->segment[i].mem + image->segment[i].memsz,
+ (unsigned int)image->segment[i].mem +
+ image->segment[i].memsz,
(unsigned int)image->segment[i].memsz);
- }
+ }
printk(" start : 0x%08x\n\n", (unsigned int)image->start);
}
-
/*
* Do not allocate memory (or fail in any way) in machine_kexec().
* We are past the point of no return, committed to rebooting now.
@@ -101,6 +101,27 @@ NORET_TYPE void machine_kexec(struct kimage *image)
/* now call it */
rnk = (relocate_new_kernel_t) reboot_code_buffer;
- (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
+ (*rnk)(page_list, reboot_code_buffer, image->start, vbr_reg);
}
+/* crashkernel=size@addr specifies the location to reserve for
+ * a crash kernel. By reserving this memory we guarantee
+ * that linux never sets it up as a DMA target.
+ * Useful for holding code to do something appropriate
+ * after a kernel panic.
+ */
+static int __init parse_crashkernel(char *arg)
+{
+ unsigned long size, base;
+ size = memparse(arg, &arg);
+ if (*arg == '@') {
+ base = memparse(arg+1, &arg);
+ /* FIXME: Do I want a sanity check
+ * to validate the memory range?
+ */
+ crashk_res.start = base;
+ crashk_res.end = base + size - 1;
+ }
+ return 0;
+}
+early_param("crashkernel", parse_crashkernel);
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index e7607366ac4..6b4f5748d0b 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -7,7 +7,7 @@
*
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
* Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*/
#include <linux/module.h>
#include <linux/mm.h>
@@ -15,8 +15,12 @@
#include <linux/pm.h>
#include <linux/kallsyms.h>
#include <linux/kexec.h>
+#include <linux/kdebug.h>
+#include <linux/tick.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
#include <asm/ubc.h>
static int hlt_counter;
@@ -57,12 +61,15 @@ void cpu_idle(void)
if (!idle)
idle = default_idle;
+ tick_nohz_stop_sched_tick();
while (!need_resched())
idle();
+ tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
+ check_pgt_cache();
}
}
@@ -299,7 +306,8 @@ static void ubc_set_tracing(int asid, unsigned long pc)
ctrl_outl(0, UBC_BAMRA);
if (current_cpu_data.type == CPU_SH7729 ||
- current_cpu_data.type == CPU_SH7710) {
+ current_cpu_data.type == CPU_SH7710 ||
+ current_cpu_data.type == CPU_SH7712) {
ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
} else {
@@ -493,7 +501,11 @@ asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
/* Rewind */
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+
+ if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
force_sig(SIGTRAP, current);
}
@@ -508,7 +520,11 @@ asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
/* Rewind */
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
+
+ if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
+ SIGTRAP) == NOTIFY_STOP)
+ return;
#ifdef CONFIG_BUG
if (__kernel_text_address(instruction_pointer(regs))) {
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
index 855f7246cff..3fb5fc0b550 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -12,7 +12,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index 98802ab2821..c2772913593 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -4,7 +4,7 @@
* This file handles the architecture-dependent parts of initialization
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*/
#include <linux/screen_info.h>
#include <linux/ioport.h>
@@ -15,21 +15,22 @@
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/utsname.h>
+#include <linux/nodemask.h>
#include <linux/cpu.h>
#include <linux/pfn.h>
#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/setup.h>
#include <asm/clock.h>
+#include <asm/mmu_context.h>
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-static int kgdb_parse_options(char *options);
-#endif
extern void * __rd_start, * __rd_end;
+
/*
* Machine setup..
*/
@@ -205,53 +206,33 @@ static int __init sh_mv_setup(char **cmdline_p)
return 0;
}
-void __init setup_arch(char **cmdline_p)
+/*
+ * Register fully available low RAM pages with the bootmem allocator.
+ */
+static void __init register_bootmem_low_pages(void)
{
- unsigned long bootmap_size;
- unsigned long start_pfn, max_pfn, max_low_pfn;
-
-#ifdef CONFIG_CMDLINE_BOOL
- strcpy(COMMAND_LINE, CONFIG_CMDLINE);
-#endif
-
- ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
-
-#ifdef CONFIG_BLK_DEV_RAM
- rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
- rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
- rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
-#endif
-
- if (!MOUNT_ROOT_RDONLY)
- root_mountflags &= ~MS_RDONLY;
- init_mm.start_code = (unsigned long) _text;
- init_mm.end_code = (unsigned long) _etext;
- init_mm.end_data = (unsigned long) _edata;
- init_mm.brk = (unsigned long) _end;
-
- code_resource.start = (unsigned long)virt_to_phys(_text);
- code_resource.end = (unsigned long)virt_to_phys(_etext)-1;
- data_resource.start = (unsigned long)virt_to_phys(_etext);
- data_resource.end = (unsigned long)virt_to_phys(_edata)-1;
-
- sh_mv_setup(cmdline_p);
-
+ unsigned long curr_pfn, last_pfn, pages;
/*
- * Find the highest page frame number we have available
+ * We are rounding up the start address of usable memory:
*/
- max_pfn = PFN_DOWN(__pa(memory_end));
+ curr_pfn = PFN_UP(__MEMORY_START);
/*
- * Determine low and high memory ranges:
+ * ... and at the end of the usable range downwards:
*/
- max_low_pfn = max_pfn;
+ last_pfn = PFN_DOWN(__pa(memory_end));
- /*
- * Partially used pages are not usable - thus
- * we are rounding upwards:
- */
- start_pfn = PFN_UP(__pa(_end));
+ if (last_pfn > max_low_pfn)
+ last_pfn = max_low_pfn;
+
+ pages = last_pfn - curr_pfn;
+ free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
+}
+
+void __init setup_bootmem_allocator(unsigned long start_pfn)
+{
+ unsigned long bootmap_size;
/*
* Find a proper area for the bootmem bitmap. After this
@@ -259,31 +240,11 @@ void __init setup_arch(char **cmdline_p)
* is intact) must be done via bootmem_alloc().
*/
bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
- __MEMORY_START>>PAGE_SHIFT,
- max_low_pfn);
- /*
- * Register fully available low RAM pages with the bootmem allocator.
- */
- {
- unsigned long curr_pfn, last_pfn, pages;
-
- /*
- * We are rounding up the start address of usable memory:
- */
- curr_pfn = PFN_UP(__MEMORY_START);
- /*
- * ... and at the end of the usable range downwards:
- */
- last_pfn = PFN_DOWN(__pa(memory_end));
+ min_low_pfn, max_low_pfn);
- if (last_pfn > max_low_pfn)
- last_pfn = max_low_pfn;
-
- pages = last_pfn - curr_pfn;
- free_bootmem_node(NODE_DATA(0), PFN_PHYS(curr_pfn),
- PFN_PHYS(pages));
- }
+ register_bootmem_low_pages();
+ node_set_online(0);
/*
* Reserve the kernel text and
@@ -292,14 +253,14 @@ void __init setup_arch(char **cmdline_p)
* case of us accidentally initializing the bootmem allocator with
* an invalid RAM area.
*/
- reserve_bootmem_node(NODE_DATA(0), __MEMORY_START+PAGE_SIZE,
+ reserve_bootmem(__MEMORY_START+PAGE_SIZE,
(PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
* enabling clean reboots, SMP operation, laptop functions.
*/
- reserve_bootmem_node(NODE_DATA(0), __MEMORY_START, PAGE_SIZE);
+ reserve_bootmem(__MEMORY_START, PAGE_SIZE);
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
@@ -313,8 +274,8 @@ void __init setup_arch(char **cmdline_p)
if (LOADER_TYPE && INITRD_START) {
if (INITRD_START + INITRD_SIZE <= (max_low_pfn << PAGE_SHIFT)) {
- reserve_bootmem_node(NODE_DATA(0), INITRD_START +
- __MEMORY_START, INITRD_SIZE);
+ reserve_bootmem(INITRD_START + __MEMORY_START,
+ INITRD_SIZE);
initrd_start = INITRD_START + PAGE_OFFSET +
__MEMORY_START;
initrd_end = initrd_start + INITRD_SIZE;
@@ -327,6 +288,76 @@ void __init setup_arch(char **cmdline_p)
}
}
#endif
+#ifdef CONFIG_KEXEC
+ if (crashk_res.start != crashk_res.end)
+ reserve_bootmem(crashk_res.start,
+ crashk_res.end - crashk_res.start + 1);
+#endif
+}
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+static void __init setup_memory(void)
+{
+ unsigned long start_pfn;
+
+ /*
+ * Partially used pages are not usable - thus
+ * we are rounding upwards:
+ */
+ start_pfn = PFN_UP(__pa(_end));
+ setup_bootmem_allocator(start_pfn);
+}
+#else
+extern void __init setup_memory(void);
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+ enable_mmu();
+
+#ifdef CONFIG_CMDLINE_BOOL
+ strcpy(COMMAND_LINE, CONFIG_CMDLINE);
+#endif
+
+ ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
+
+#ifdef CONFIG_BLK_DEV_RAM
+ rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
+ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
+ rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
+#endif
+
+ if (!MOUNT_ROOT_RDONLY)
+ root_mountflags &= ~MS_RDONLY;
+ init_mm.start_code = (unsigned long) _text;
+ init_mm.end_code = (unsigned long) _etext;
+ init_mm.end_data = (unsigned long) _edata;
+ init_mm.brk = (unsigned long) _end;
+
+ code_resource.start = virt_to_phys(_text);
+ code_resource.end = virt_to_phys(_etext)-1;
+ data_resource.start = virt_to_phys(_etext);
+ data_resource.end = virt_to_phys(_edata)-1;
+
+ parse_early_param();
+
+ sh_mv_setup(cmdline_p);
+
+ /*
+ * Find the highest page frame number we have available
+ */
+ max_pfn = PFN_DOWN(__pa(memory_end));
+
+ /*
+ * Determine low and high memory ranges:
+ */
+ max_low_pfn = max_pfn;
+ min_low_pfn = __MEMORY_START >> PAGE_SHIFT;
+
+ nodes_clear(node_online_map);
+ setup_memory();
+ paging_init();
+ sparse_init();
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -335,8 +366,6 @@ void __init setup_arch(char **cmdline_p)
/* Perform the machine specific initialisation */
if (likely(sh_mv.mv_setup))
sh_mv.mv_setup(cmdline_p);
-
- paging_init();
}
struct sh_machine_vector* __init get_mv_byname(const char* name)
@@ -380,6 +409,7 @@ static const char *cpu_name[] = {
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
[CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
+ [CPU_SH7712] = "SH7712",
[CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
[CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
[CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
@@ -401,7 +431,7 @@ const char *get_cpu_subtype(struct sh_cpuinfo *c)
/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
static const char *cpu_flags[] = {
"none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
- "ptea", "llsc", "l2", NULL
+ "ptea", "llsc", "l2", "op32", NULL
};
static void show_cpuflags(struct seq_file *m, struct sh_cpuinfo *c)
@@ -477,7 +507,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
c->loops_per_jiffy/(500000/HZ),
(c->loops_per_jiffy/(5000/HZ)) % 100);
- return show_clocks(m);
+ return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
@@ -499,92 +529,3 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo,
};
#endif /* CONFIG_PROC_FS */
-
-#ifdef CONFIG_SH_KGDB
-/*
- * Parse command-line kgdb options. By default KGDB is enabled,
- * entered on error (or other action) using default serial info.
- * The command-line option can include a serial port specification
- * and an action to override default or configured behavior.
- */
-struct kgdb_sermap kgdb_sci_sermap =
-{ "ttySC", 5, kgdb_sci_setup, NULL };
-
-struct kgdb_sermap *kgdb_serlist = &kgdb_sci_sermap;
-struct kgdb_sermap *kgdb_porttype = &kgdb_sci_sermap;
-
-void kgdb_register_sermap(struct kgdb_sermap *map)
-{
- struct kgdb_sermap *last;
-
- for (last = kgdb_serlist; last->next; last = last->next)
- ;
- last->next = map;
- if (!map->namelen) {
- map->namelen = strlen(map->name);
- }
-}
-
-static int __init kgdb_parse_options(char *options)
-{
- char c;
- int baud;
-
- /* Check for port spec (or use default) */
-
- /* Determine port type and instance */
- if (!memcmp(options, "tty", 3)) {
- struct kgdb_sermap *map = kgdb_serlist;
-
- while (map && memcmp(options, map->name, map->namelen))
- map = map->next;
-
- if (!map) {
- KGDB_PRINTK("unknown port spec in %s\n", options);
- return -1;
- }
-
- kgdb_porttype = map;
- kgdb_serial_setup = map->setup_fn;
- kgdb_portnum = options[map->namelen] - '0';
- options += map->namelen + 1;
-
- options = (*options == ',') ? options+1 : options;
-
- /* Read optional parameters (baud/parity/bits) */
- baud = simple_strtoul(options, &options, 10);
- if (baud != 0) {
- kgdb_baud = baud;
-
- c = toupper(*options);
- if (c == 'E' || c == 'O' || c == 'N') {
- kgdb_parity = c;
- options++;
- }
-
- c = *options;
- if (c == '7' || c == '8') {
- kgdb_bits = c;
- options++;
- }
- options = (*options == ',') ? options+1 : options;
- }
- }
-
- /* Check for action specification */
- if (!memcmp(options, "halt", 4)) {
- kgdb_halt = 1;
- options += 4;
- } else if (!memcmp(options, "disabled", 8)) {
- kgdb_enabled = 0;
- options += 8;
- }
-
- if (*options) {
- KGDB_PRINTK("ignored unknown options: %s\n", options);
- return 0;
- }
- return 1;
-}
-__setup("kgdb=", kgdb_parse_options);
-#endif /* CONFIG_SH_KGDB */
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index 6e0d10fac4a..c1cfcb9f047 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -5,7 +5,6 @@
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/pci.h>
#include <linux/irq.h>
@@ -59,13 +58,10 @@ EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(__ndelay);
EXPORT_SYMBOL(__const_udelay);
-EXPORT_SYMBOL(__div64_32);
-
#define DECLARE_EXPORT(name) extern void name(void);EXPORT_SYMBOL(name)
/* These symbols are generated by the compiler itself */
DECLARE_EXPORT(__udivsi3);
-DECLARE_EXPORT(__udivdi3);
DECLARE_EXPORT(__sdivsi3);
DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index 9f39ef1f73d..b32c35a7c0a 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
@@ -24,7 +23,7 @@
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/freezer.h>
-
+#include <asm/system.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -501,7 +500,9 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
}
/* fallthrough */
case -ERESTARTNOINTR:
- regs->pc -= 2;
+ regs->pc -= instruction_size(
+ ctrl_inw(regs->pc - 4));
+ break;
}
} else {
/* gUSA handling */
@@ -517,7 +518,8 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
regs->regs[15] = regs->regs[1];
if (regs->pc < regs->regs[0])
/* Go to rewind point #1 */
- regs->pc = regs->regs[0] + offset - 2;
+ regs->pc = regs->regs[0] + offset -
+ instruction_size(ctrl_inw(regs->pc-4));
}
#ifdef CONFIG_PREEMPT
local_irq_restore(flags);
@@ -601,9 +603,9 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0)
regs->regs[0] == -ERESTARTSYS ||
regs->regs[0] == -ERESTARTNOINTR) {
regs->regs[0] = save_r0;
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
- regs->pc -= 2;
+ regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
regs->regs[3] = __NR_restart_syscall;
}
}
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c
index 0d5268afe80..d41e561be20 100644
--- a/arch/sh/kernel/stacktrace.c
+++ b/arch/sh/kernel/stacktrace.c
@@ -17,16 +17,9 @@
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
{
- unsigned long *sp;
-
- if (!task)
- task = current;
- if (task == current)
- sp = (unsigned long *)current_stack_pointer;
- else
- sp = (unsigned long *)task->thread.sp;
+ unsigned long *sp = (unsigned long *)current_stack_pointer;
while (!kstack_end(sp)) {
unsigned long addr = *sp++;
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index e18f183e103..76b1bc7f702 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -12,7 +12,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index 38fc8cd3ea3..4357d1a6358 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -354,3 +354,4 @@ ENTRY(sys_call_table)
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
+ .long sys_utimensat /* 320 */
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index d47e775962e..a3a67d151e5 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* Some code taken from i386 version.
@@ -15,6 +15,7 @@
#include <linux/profile.h>
#include <linux/timex.h>
#include <linux/sched.h>
+#include <linux/clockchips.h>
#include <asm/clock.h>
#include <asm/rtc.h>
#include <asm/timer.h>
@@ -38,6 +39,14 @@ static int null_rtc_set_time(const time_t secs)
return 0;
}
+/*
+ * Null high precision timer functions for systems lacking one.
+ */
+static cycle_t null_hpt_read(void)
+{
+ return 0;
+}
+
void (*rtc_sh_get_time)(struct timespec *) = null_rtc_get_time;
int (*rtc_sh_set_time)(const time_t) = null_rtc_set_time;
@@ -101,6 +110,7 @@ int do_settimeofday(struct timespec *tv)
EXPORT_SYMBOL(do_settimeofday);
#endif /* !CONFIG_GENERIC_TIME */
+#ifndef CONFIG_GENERIC_CLOCKEVENTS
/* last time the RTC clock got updated */
static long last_rtc_update;
@@ -138,6 +148,7 @@ void handle_timer_tick(void)
last_rtc_update = xtime.tv_sec - 600;
}
}
+#endif /* !CONFIG_GENERIC_CLOCKEVENTS */
#ifdef CONFIG_PM
int timer_suspend(struct sys_device *dev, pm_message_t state)
@@ -168,136 +179,58 @@ static struct sysdev_class timer_sysclass = {
.resume = timer_resume,
};
-#ifdef CONFIG_NO_IDLE_HZ
-static int timer_dyn_tick_enable(void)
+static int __init timer_init_sysfs(void)
{
- struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
- unsigned long flags;
- int ret = -ENODEV;
-
- if (dyn_tick) {
- spin_lock_irqsave(&dyn_tick->lock, flags);
- ret = 0;
- if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
- ret = dyn_tick->enable();
-
- if (ret == 0)
- dyn_tick->state |= DYN_TICK_ENABLED;
- }
- spin_unlock_irqrestore(&dyn_tick->lock, flags);
- }
+ int ret = sysdev_class_register(&timer_sysclass);
+ if (ret != 0)
+ return ret;
- return ret;
+ sys_timer->dev.cls = &timer_sysclass;
+ return sysdev_register(&sys_timer->dev);
}
+device_initcall(timer_init_sysfs);
-static int timer_dyn_tick_disable(void)
-{
- struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
- unsigned long flags;
- int ret = -ENODEV;
-
- if (dyn_tick) {
- spin_lock_irqsave(&dyn_tick->lock, flags);
- ret = 0;
- if (dyn_tick->state & DYN_TICK_ENABLED) {
- ret = dyn_tick->disable();
-
- if (ret == 0)
- dyn_tick->state &= ~DYN_TICK_ENABLED;
- }
- spin_unlock_irqrestore(&dyn_tick->lock, flags);
- }
-
- return ret;
-}
+void (*board_time_init)(void);
/*
- * Reprogram the system timer for at least the calculated time interval.
- * This function should be called from the idle thread with IRQs disabled,
- * immediately before sleeping.
+ * Shamelessly based on the MIPS and Sparc64 work.
*/
-void timer_dyn_reprogram(void)
-{
- struct dyn_tick_timer *dyn_tick = sys_timer->dyn_tick;
- unsigned long next, seq, flags;
-
- if (!dyn_tick)
- return;
-
- spin_lock_irqsave(&dyn_tick->lock, flags);
- if (dyn_tick->state & DYN_TICK_ENABLED) {
- next = next_timer_interrupt();
- do {
- seq = read_seqbegin(&xtime_lock);
- dyn_tick->reprogram(next - jiffies);
- } while (read_seqretry(&xtime_lock, seq));
- }
- spin_unlock_irqrestore(&dyn_tick->lock, flags);
-}
+static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
+unsigned long sh_hpt_frequency = 0;
+
+#define NSEC_PER_CYC_SHIFT 10
+
+struct clocksource clocksource_sh = {
+ .name = "SuperH",
+ .rating = 200,
+ .mask = CLOCKSOURCE_MASK(32),
+ .read = null_hpt_read,
+ .shift = 16,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
-static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
+static void __init init_sh_clocksource(void)
{
- return sprintf(buf, "%i\n",
- (sys_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
-}
+ if (!sh_hpt_frequency || clocksource_sh.read == null_hpt_read)
+ return;
-static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
- size_t count)
-{
- unsigned int enable = simple_strtoul(buf, NULL, 2);
+ clocksource_sh.mult = clocksource_hz2mult(sh_hpt_frequency,
+ clocksource_sh.shift);
- if (enable)
- timer_dyn_tick_enable();
- else
- timer_dyn_tick_disable();
+ timer_ticks_per_nsec_quotient =
+ clocksource_hz2mult(sh_hpt_frequency, NSEC_PER_CYC_SHIFT);
- return count;
+ clocksource_register(&clocksource_sh);
}
-static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
-/*
- * dyntick=enable|disable
- */
-static char dyntick_str[4] __initdata = "";
-
-static int __init dyntick_setup(char *str)
+#ifdef CONFIG_GENERIC_TIME
+unsigned long long sched_clock(void)
{
- if (str)
- strlcpy(dyntick_str, str, sizeof(dyntick_str));
- return 1;
+ unsigned long long ticks = clocksource_sh.read();
+ return (ticks * timer_ticks_per_nsec_quotient) >> NSEC_PER_CYC_SHIFT;
}
-
-__setup("dyntick=", dyntick_setup);
-#endif
-
-static int __init timer_init_sysfs(void)
-{
- int ret = sysdev_class_register(&timer_sysclass);
- if (ret != 0)
- return ret;
-
- sys_timer->dev.cls = &timer_sysclass;
- ret = sysdev_register(&sys_timer->dev);
-
-#ifdef CONFIG_NO_IDLE_HZ
- if (ret == 0 && sys_timer->dyn_tick) {
- ret = sysdev_create_file(&sys_timer->dev, &attr_dyn_tick);
-
- /*
- * Turn on dynamic tick after calibrate delay
- * for correct bogomips
- */
- if (ret == 0 && dyntick_str[0] == 'e')
- ret = timer_dyn_tick_enable();
- }
#endif
- return ret;
-}
-device_initcall(timer_init_sysfs);
-
-void (*board_time_init)(void);
-
void __init time_init(void)
{
if (board_time_init)
@@ -316,10 +249,15 @@ void __init time_init(void)
sys_timer = get_sys_timer();
printk(KERN_INFO "Using %s for system timer\n", sys_timer->name);
-#ifdef CONFIG_NO_IDLE_HZ
- if (sys_timer->dyn_tick)
- spin_lock_init(&sys_timer->dyn_tick->lock);
-#endif
+ if (sys_timer->ops->read)
+ clocksource_sh.read = sys_timer->ops->read;
+
+ init_sh_clocksource();
+
+ if (sh_hpt_frequency)
+ printk("Using %lu.%03lu MHz high precision timer.\n",
+ ((sh_hpt_frequency + 500) / 1000) / 1000,
+ ((sh_hpt_frequency + 500) / 1000) % 1000);
#if defined(CONFIG_SH_KGDB)
/*
diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c
index a574b93a4e7..82de6895ade 100644
--- a/arch/sh/kernel/timers/timer-cmt.c
+++ b/arch/sh/kernel/timers/timer-cmt.c
@@ -115,7 +115,7 @@ static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id)
static struct irqaction cmt_irq = {
.name = "timer",
.handler = cmt_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
};
diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c
index fffcd1c0987..b7499a2a918 100644
--- a/arch/sh/kernel/timers/timer-mtu2.c
+++ b/arch/sh/kernel/timers/timer-mtu2.c
@@ -110,7 +110,7 @@ static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id)
static struct irqaction mtu2_irq = {
.name = "timer",
.handler = mtu2_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
};
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index e060e71d078..2d997e2a5b6 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/timers/timer-tmu.c - TMU Timer Support
*
- * Copyright (C) 2005 Paul Mundt
+ * Copyright (C) 2005 - 2007 Paul Mundt
*
* TMU handling code hacked out of arch/sh/kernel/time.c
*
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/seqlock.h>
+#include <linux/clockchips.h>
#include <asm/timer.h>
#include <asm/rtc.h>
#include <asm/io.h>
@@ -25,56 +26,75 @@
#include <asm/clock.h>
#define TMU_TOCR_INIT 0x00
-#define TMU0_TCR_INIT 0x0020
-#define TMU_TSTR_INIT 1
+#define TMU_TCR_INIT 0x0020
-#define TMU0_TCR_CALIB 0x0000
+static int tmu_timer_start(void)
+{
+ ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
+ return 0;
+}
-static unsigned long tmu_timer_get_offset(void)
+static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
{
- int count;
- static int count_p = 0x7fffffff; /* for the first call after boot */
- static unsigned long jiffies_p = 0;
+ ctrl_outl(interval, TMU0_TCNT);
/*
- * cache volatile jiffies temporarily; we have IRQs turned off.
+ * TCNT reloads from TCOR on underflow, clear it if we don't
+ * intend to auto-reload
*/
- unsigned long jiffies_t;
+ if (reload)
+ ctrl_outl(interval, TMU0_TCOR);
+ else
+ ctrl_outl(0, TMU0_TCOR);
- /* timer count may underflow right here */
- count = ctrl_inl(TMU0_TCNT); /* read the latched count */
+ tmu_timer_start();
+}
- jiffies_t = jiffies;
+static int tmu_timer_stop(void)
+{
+ ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
+ return 0;
+}
- /*
- * avoiding timer inconsistencies (they are rare, but they happen)...
- * there is one kind of problem that must be avoided here:
- * 1. the timer counter underflows
- */
+static cycle_t tmu_timer_read(void)
+{
+ return ~ctrl_inl(TMU1_TCNT);
+}
+
+static int tmu_set_next_event(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ tmu0_timer_set_interval(cycles, 1);
+ return 0;
+}
- if (jiffies_t == jiffies_p) {
- if (count > count_p) {
- /* the nutcase */
- if (ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */
- count -= LATCH;
- } else {
- printk("%s (): hardware timer problem?\n",
- __FUNCTION__);
- }
- }
- } else
- jiffies_p = jiffies_t;
-
- count_p = count;
-
- count = ((LATCH-1) - count) * TICK_SIZE;
- count = (count + LATCH/2) / LATCH;
-
- return count;
+static void tmu_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ ctrl_outl(ctrl_inl(TMU0_TCNT), TMU0_TCOR);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ ctrl_outl(0, TMU0_TCOR);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ break;
+ }
}
+static struct clock_event_device tmu0_clockevent = {
+ .name = "tmu0",
+ .shift = 32,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = tmu_set_mode,
+ .set_next_event = tmu_set_next_event,
+};
+
static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
{
+ struct clock_event_device *evt = &tmu0_clockevent;
unsigned long timer_status;
/* Clear UNF bit */
@@ -82,86 +102,106 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
timer_status &= ~0x100;
ctrl_outw(timer_status, TMU0_TCR);
- /*
- * Here we are in the timer irq handler. We just have irqs locally
- * disabled but we don't know if the timer_bh is running on the other
- * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
- * the irq version of write_lock because as just said we have irq
- * locally disabled. -arca
- */
- write_seqlock(&xtime_lock);
- handle_timer_tick();
- write_sequnlock(&xtime_lock);
+ evt->event_handler(evt);
return IRQ_HANDLED;
}
-static struct irqaction tmu_irq = {
- .name = "timer",
+static struct irqaction tmu0_irq = {
+ .name = "periodic timer",
.handler = tmu_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
};
-static void tmu_clk_init(struct clk *clk)
+static void tmu0_clk_init(struct clk *clk)
{
- u8 divisor = TMU0_TCR_INIT & 0x7;
- ctrl_outw(TMU0_TCR_INIT, TMU0_TCR);
+ u8 divisor = TMU_TCR_INIT & 0x7;
+ ctrl_outw(TMU_TCR_INIT, TMU0_TCR);
clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
-static void tmu_clk_recalc(struct clk *clk)
+static void tmu0_clk_recalc(struct clk *clk)
{
u8 divisor = ctrl_inw(TMU0_TCR) & 0x7;
clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
-static struct clk_ops tmu_clk_ops = {
- .init = tmu_clk_init,
- .recalc = tmu_clk_recalc,
+static struct clk_ops tmu0_clk_ops = {
+ .init = tmu0_clk_init,
+ .recalc = tmu0_clk_recalc,
};
static struct clk tmu0_clk = {
.name = "tmu0_clk",
- .ops = &tmu_clk_ops,
+ .ops = &tmu0_clk_ops,
};
-static int tmu_timer_start(void)
+static void tmu1_clk_init(struct clk *clk)
{
- ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
- return 0;
+ u8 divisor = TMU_TCR_INIT & 0x7;
+ ctrl_outw(divisor, TMU1_TCR);
+ clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
-static int tmu_timer_stop(void)
+static void tmu1_clk_recalc(struct clk *clk)
{
- ctrl_outb(0, TMU_TSTR);
- return 0;
+ u8 divisor = ctrl_inw(TMU1_TCR) & 0x7;
+ clk->rate = clk->parent->rate / (4 << (divisor << 1));
}
+static struct clk_ops tmu1_clk_ops = {
+ .init = tmu1_clk_init,
+ .recalc = tmu1_clk_recalc,
+};
+
+static struct clk tmu1_clk = {
+ .name = "tmu1_clk",
+ .ops = &tmu1_clk_ops,
+};
+
static int tmu_timer_init(void)
{
unsigned long interval;
+ unsigned long frequency;
- setup_irq(CONFIG_SH_TIMER_IRQ, &tmu_irq);
+ setup_irq(CONFIG_SH_TIMER_IRQ, &tmu0_irq);
tmu0_clk.parent = clk_get(NULL, "module_clk");
+ tmu1_clk.parent = clk_get(NULL, "module_clk");
- /* Start TMU0 */
tmu_timer_stop();
-#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
+
+#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7760) && \
+ !defined(CONFIG_CPU_SUBTYPE_SH7785)
ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
#endif
clk_register(&tmu0_clk);
+ clk_register(&tmu1_clk);
clk_enable(&tmu0_clk);
+ clk_enable(&tmu1_clk);
- interval = (clk_get_rate(&tmu0_clk) + HZ / 2) / HZ;
- printk(KERN_INFO "Interval = %ld\n", interval);
+ frequency = clk_get_rate(&tmu0_clk);
+ interval = (frequency + HZ / 2) / HZ;
- ctrl_outl(interval, TMU0_TCOR);
- ctrl_outl(interval, TMU0_TCNT);
+ sh_hpt_frequency = clk_get_rate(&tmu1_clk);
+ ctrl_outl(~0, TMU1_TCNT);
+ ctrl_outl(~0, TMU1_TCOR);
- tmu_timer_start();
+ tmu0_timer_set_interval(interval, 1);
+
+ tmu0_clockevent.mult = div_sc(frequency, NSEC_PER_SEC,
+ tmu0_clockevent.shift);
+ tmu0_clockevent.max_delta_ns =
+ clockevent_delta2ns(-1, &tmu0_clockevent);
+ tmu0_clockevent.min_delta_ns =
+ clockevent_delta2ns(1, &tmu0_clockevent);
+
+ tmu0_clockevent.cpumask = cpumask_of_cpu(0);
+
+ clockevents_register_device(&tmu0_clockevent);
return 0;
}
@@ -170,9 +210,7 @@ struct sys_timer_ops tmu_timer_ops = {
.init = tmu_timer_init,
.start = tmu_timer_start,
.stop = tmu_timer_stop,
-#ifndef CONFIG_GENERIC_TIME
- .get_offset = tmu_timer_get_offset,
-#endif
+ .read = tmu_timer_read,
};
struct sys_timer tmu_timer = {
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index e9f168f60f9..3a197649cd8 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells
- * Copyright (C) 2002 - 2006 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -18,7 +18,9 @@
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/io.h>
+#include <linux/bug.h>
#include <linux/debug_locks.h>
+#include <linux/kdebug.h>
#include <linux/limits.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -74,7 +76,7 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
}
}
-DEFINE_SPINLOCK(die_lock);
+static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
{
@@ -130,40 +132,6 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
return -EFAULT;
}
-#ifdef CONFIG_BUG
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-static inline void do_bug_verbose(struct pt_regs *regs)
-{
- struct bug_frame f;
- long len;
-
- if (__copy_from_user(&f, (const void __user *)regs->pc,
- sizeof(struct bug_frame)))
- return;
-
- len = __strnlen_user(f.file, PATH_MAX) - 1;
- if (unlikely(len < 0 || len >= PATH_MAX))
- f.file = "<bad filename>";
- len = __strnlen_user(f.func, PATH_MAX) - 1;
- if (unlikely(len < 0 || len >= PATH_MAX))
- f.func = "<bad function>";
-
- printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n",
- f.func, f.file, f.line);
-}
-#else
-static inline void do_bug_verbose(struct pt_regs *regs)
-{
-}
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
-
-void handle_BUG(struct pt_regs *regs)
-{
- do_bug_verbose(regs);
- die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
-}
-#endif /* CONFIG_BUG */
-
/*
* handle an instruction that does an unaligned memory access by emulating the
* desired behaviour
@@ -523,7 +491,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
simple:
ret = handle_unaligned_ins(instruction,regs);
if (ret==0)
- regs->pc += 2;
+ regs->pc += instruction_size(instruction);
return ret;
}
#endif /* CONFIG_CPU_SH2A */
@@ -700,7 +668,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
err = do_fpu_inst(inst, regs);
if (!err) {
- regs->pc += 2;
+ regs->pc += instruction_size(inst);
return;
}
/* not a FPU inst. */
@@ -888,6 +856,25 @@ void __init trap_init(void)
per_cpu_trap_init();
}
+#ifdef CONFIG_BUG
+void handle_BUG(struct pt_regs *regs)
+{
+ enum bug_trap_type tt;
+ tt = report_bug(regs->pc);
+ if (tt == BUG_TRAP_TYPE_WARN) {
+ regs->pc += 2;
+ return;
+ }
+
+ die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
+}
+
+int is_valid_bugaddr(unsigned long addr)
+{
+ return addr >= PAGE_OFFSET;
+}
+#endif
+
void show_trace(struct task_struct *tsk, unsigned long *sp,
struct pt_regs *regs)
{
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 78a6c09875b..d83143cc5ca 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -34,9 +34,11 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ _etext = .; /* End of text section */
+
RODATA
- _etext = .; /* End of text section */
+ BUG_TABLE
.data : { /* Data */
*(.data)
@@ -53,8 +55,12 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
.data.page_aligned : { *(.data.page_aligned) }
+ __nosave_begin = .;
+ .data_nosave : { *(.data.nosave) }
+ . = ALIGN(PAGE_SIZE);
+ __nosave_end = .;
- . = ALIGN(L1_CACHE_BYTES);
+ . = ALIGN(PAGE_SIZE);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
@@ -110,43 +116,10 @@ SECTIONS
* it's a module.
*/
/DISCARD/ : {
- *(.exit.text)
- *(.exit.data)
*(.exitcall.exit)
}
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging section are relative to the beginning
- of the section so we begin .debug at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
- /* These must appear regardless of . */
+ STABS_DEBUG
+
+ DWARF_DEBUG
}
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
index 7b0f66f0331..e146bafcd14 100644
--- a/arch/sh/kernel/vsyscall/vsyscall.c
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/vsyscall.c
+ * arch/sh/kernel/vsyscall/vsyscall.c
*
* Copyright (C) 2006 Paul Mundt
*
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile
index 0b9cca5c7cb..e23dd1a3fcc 100644
--- a/arch/sh/lib/Makefile
+++ b/arch/sh/lib/Makefile
@@ -3,11 +3,9 @@
#
lib-y = delay.o memset.o memmove.o memchr.o \
- checksum.o strlen.o div64.o udivdi3.o \
- div64-generic.o
+ checksum.o strlen.o div64.o div64-generic.o
memcpy-y := memcpy.o
memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o
lib-y += $(memcpy-y)
-
diff --git a/arch/sh/lib/delay.c b/arch/sh/lib/delay.c
index 351714694d6..f3ddd2133e6 100644
--- a/arch/sh/lib/delay.c
+++ b/arch/sh/lib/delay.c
@@ -24,9 +24,10 @@ inline void __const_udelay(unsigned long xloops)
__asm__("dmulu.l %0, %2\n\t"
"sts mach, %0"
: "=r" (xloops)
- : "0" (xloops), "r" (cpu_data[raw_smp_processor_id()].loops_per_jiffy)
+ : "0" (xloops),
+ "r" (HZ * cpu_data[raw_smp_processor_id()].loops_per_jiffy)
: "macl", "mach");
- __delay(xloops * HZ);
+ __delay(xloops);
}
void __udelay(unsigned long usecs)
diff --git a/arch/sh/lib/udivdi3.c b/arch/sh/lib/udivdi3.c
deleted file mode 100644
index 68f038bf3c5..00000000000
--- a/arch/sh/lib/udivdi3.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Simple __udivdi3 function which doesn't use FPU.
- */
-
-#include <linux/types.h>
-
-extern u64 __xdiv64_32(u64 n, u32 d);
-extern void panic(const char * fmt, ...);
-
-u64 __udivdi3(u64 n, u64 d)
-{
- if (d & ~0xffffffff)
- panic("Need true 64-bit/64-bit division");
- return __xdiv64_32(n, (u32)d);
-}
-
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 6b0d28ac924..253346d7b31 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -67,6 +67,7 @@ config CPU_SUBTYPE_SH7300
config CPU_SUBTYPE_SH7705
bool "Support SH7705 processor"
select CPU_SH3
+ select CPU_HAS_IPR_IRQ
select CPU_HAS_PINT_IRQ
config CPU_SUBTYPE_SH7706
@@ -101,9 +102,17 @@ config CPU_SUBTYPE_SH7709
config CPU_SUBTYPE_SH7710
bool "Support SH7710 processor"
select CPU_SH3
+ select CPU_HAS_IPR_IRQ
help
Select SH7710 if you have a SH3-DSP SH7710 CPU.
+config CPU_SUBTYPE_SH7712
+ bool "Support SH7712 processor"
+ select CPU_SH3
+ select CPU_HAS_IPR_IRQ
+ help
+ Select SH7712 if you have a SH3-DSP SH7712 CPU.
+
comment "SH-4 Processor Support"
config CPU_SUBTYPE_SH7750
@@ -209,6 +218,9 @@ endmenu
menu "Memory management options"
+config QUICKLIST
+ def_bool y
+
config MMU
bool "Support for memory management hardware"
depends on !CPU_SH2
@@ -283,6 +295,21 @@ config VSYSCALL
For systems with an MMU that can afford to give up a page,
(the default value) say Y.
+config NODES_SHIFT
+ int
+ default "1"
+ depends on NEED_MULTIPLE_NODES
+
+config ARCH_FLATMEM_ENABLE
+ def_bool y
+
+config MAX_ACTIVE_REGIONS
+ int
+ default "1"
+
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
choice
prompt "Kernel page size"
default PAGE_SIZE_4KB
diff --git a/arch/sh/mm/fault-nommu.c b/arch/sh/mm/fault-nommu.c
index 34d4e0c68fb..923cb456819 100644
--- a/arch/sh/mm/fault-nommu.c
+++ b/arch/sh/mm/fault-nommu.c
@@ -19,7 +19,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <asm/system.h>
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index fa5d7f0b9f1..9207da67ff8 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -2,7 +2,7 @@
* Page fault handler for SH with an MMU.
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2003 Paul Mundt
+ * Copyright (C) 2003 - 2007 Paul Mundt
*
* Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds
@@ -15,12 +15,42 @@
#include <linux/mm.h>
#include <linux/hardirq.h>
#include <linux/kprobes.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/mmu_context.h>
#include <asm/tlbflush.h>
#include <asm/kgdb.h>
-extern void die(const char *,struct pt_regs *,long);
+#ifdef CONFIG_KPROBES
+ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+
+/* Hook to register for page fault notifications */
+int register_page_fault_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
+}
+
+int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
+}
+
+static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
+ int trap, int sig)
+{
+ struct die_args args = {
+ .regs = regs,
+ .trapnr = trap,
+ };
+ return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+}
+#else
+static inline int notify_page_fault(enum die_val val, struct pt_regs *regs,
+ int trap, int sig)
+{
+ return NOTIFY_DONE;
+}
+#endif
/*
* This routine handles page faults. It determines the address,
@@ -39,6 +69,11 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
siginfo_t info;
trace_hardirqs_on();
+
+ if (notify_page_fault(DIE_PAGE_FAULT, regs,
+ writeaccess, SIGSEGV) == NOTIFY_STOP)
+ return;
+
local_irq_enable();
#ifdef CONFIG_SH_KGDB
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index cf2c2ee35a3..ae8c321d6e2 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -13,7 +13,6 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index ae957a93237..8fe223a890e 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -1,37 +1,20 @@
-/* $Id: init.c,v 1.19 2004/02/21 04:42:16 kkojima Exp $
- *
- * linux/arch/sh/mm/init.c
+/*
+ * linux/arch/sh/mm/init.c
*
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002, 2004 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
*
* Based on linux/arch/i386/mm/init.c:
* Copyright (C) 1995 Linus Torvalds
*/
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
-#include <linux/smp.h>
#include <linux/init.h>
-#include <linux/highmem.h>
#include <linux/bootmem.h>
-#include <linux/pagemap.h>
#include <linux/proc_fs.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-#include <asm/pgalloc.h>
+#include <linux/percpu.h>
+#include <linux/io.h>
#include <asm/mmu_context.h>
-#include <asm/io.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
#include <asm/cache.h>
@@ -39,37 +22,53 @@
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];
-#ifdef CONFIG_MMU
-/* It'd be good if these lines were in the standard header file. */
-#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
-#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn)
-#endif
-
void (*copy_page)(void *from, void *to);
void (*clear_page)(void *to);
void show_mem(void)
{
- int i, total = 0, reserved = 0;
- int shared = 0, cached = 0;
+ int total = 0, reserved = 0, free = 0;
+ int shared = 0, cached = 0, slab = 0;
+ pg_data_t *pgdat;
printk("Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
- i = max_mapnr;
- while (i-- > 0) {
- total++;
- if (PageReserved(mem_map+i))
- reserved++;
- else if (PageSwapCache(mem_map+i))
- cached++;
- else if (page_count(mem_map+i))
- shared += page_count(mem_map+i) - 1;
+
+ for_each_online_pgdat(pgdat) {
+ struct page *page, *end;
+ unsigned long flags;
+
+ pgdat_resize_lock(pgdat, &flags);
+ page = pgdat->node_mem_map;
+ end = page + pgdat->node_spanned_pages;
+
+ do {
+ total++;
+ if (PageReserved(page))
+ reserved++;
+ else if (PageSwapCache(page))
+ cached++;
+ else if (PageSlab(page))
+ slab++;
+ else if (!page_count(page))
+ free++;
+ else
+ shared += page_count(page) - 1;
+ page++;
+ } while (page < end);
+
+ pgdat_resize_unlock(pgdat, &flags);
}
- printk("%d pages of RAM\n",total);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
+
+ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ printk("%d pages of RAM\n", total);
+ printk("%d free pages\n", free);
+ printk("%d reserved pages\n", reserved);
+ printk("%d slab pages\n", slab);
+ printk("%d pages shared\n", shared);
+ printk("%d pages swap cached\n", cached);
+ printk(KERN_INFO "Total of %ld pages in page table cache\n",
+ quicklist_total_size());
}
#ifdef CONFIG_MMU
@@ -147,52 +146,38 @@ extern char __init_begin, __init_end;
*/
void __init paging_init(void)
{
- unsigned long zones_size[MAX_NR_ZONES] = { 0, };
+ int nid;
- /*
- * Setup some defaults for the zone sizes.. these should be safe
- * regardless of distcontiguous memory or MMU settings.
- */
- zones_size[ZONE_NORMAL] = __MEMORY_SIZE >> PAGE_SHIFT;
-#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = 0 >> PAGE_SHIFT;
-#endif
-
-#ifdef CONFIG_MMU
- /*
- * If we have an MMU, and want to be using it .. we need to adjust
- * the zone sizes accordingly, in addition to turning it on.
- */
- {
- /* We don't need to map the kernel through the TLB, as
- * it is permanatly mapped using P1. So clear the
- * entire pgd. */
- memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
-
- /* Turn on the MMU */
- enable_mmu();
- zones_size[ZONE_NORMAL] = MAX_LOW_PFN - START_PFN;
- }
+ /* We don't need to map the kernel through the TLB, as
+ * it is permanatly mapped using P1. So clear the
+ * entire pgd. */
+ memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
/* Set an initial value for the MMU.TTB so we don't have to
* check for a null value. */
set_TTB(swapper_pg_dir);
-#elif defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
- /*
- * If we don't have CONFIG_MMU set and the processor in question
- * still has an MMU, care needs to be taken to make sure it doesn't
- * stay on.. Since the boot loader could have potentially already
- * turned it on, and we clearly don't want it, we simply turn it off.
- *
- * We don't need to do anything special for the zone sizes, since the
- * default values that were already configured up above should be
- * satisfactory.
- */
- disable_mmu();
-#endif
- NODE_DATA(0)->node_mem_map = NULL;
- free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
+ for_each_online_node(nid) {
+ pg_data_t *pgdat = NODE_DATA(nid);
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ unsigned long low, start_pfn;
+
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
+ start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT;
+ low = pgdat->bdata->node_low_pfn;
+
+ max_zone_pfns[ZONE_NORMAL] = low;
+ add_active_range(nid, start_pfn, low);
+
+ printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n",
+ nid, start_pfn, low);
+
+ free_area_init_nodes(max_zone_pfns);
+
+ printk("Node %u: mem_map starts at %p\n",
+ pgdat->node_id, pgdat->node_mem_map);
+ }
}
static struct kcore_list kcore_mem, kcore_vmalloc;
@@ -200,18 +185,33 @@ static struct kcore_list kcore_mem, kcore_vmalloc;
void __init mem_init(void)
{
int codesize, reservedpages, datasize, initsize;
- int tmp;
- extern unsigned long memory_start;
+ int nid;
-#ifdef CONFIG_MMU
- high_memory = (void *)__va(MAX_LOW_PFN * PAGE_SIZE);
-#else
- extern unsigned long memory_end;
+ reservedpages = 0;
- high_memory = (void *)(memory_end & PAGE_MASK);
-#endif
+ for_each_online_node(nid) {
+ pg_data_t *pgdat = NODE_DATA(nid);
+ unsigned long node_pages = 0;
+ void *node_high_memory;
+ int i;
+
+ num_physpages += pgdat->node_present_pages;
+
+ if (pgdat->node_spanned_pages)
+ node_pages = free_all_bootmem_node(pgdat);
+
+ totalram_pages += node_pages;
- max_mapnr = num_physpages = MAP_NR(high_memory) - MAP_NR(memory_start);
+ for (i = 0; i < node_pages; i++)
+ if (PageReserved(pgdat->node_mem_map + i))
+ reservedpages++;
+
+ node_high_memory = (void *)((pgdat->node_start_pfn +
+ pgdat->node_spanned_pages) <<
+ PAGE_SHIFT);
+ if (node_high_memory > high_memory)
+ high_memory = node_high_memory;
+ }
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
@@ -229,16 +229,6 @@ void __init mem_init(void)
clear_page = clear_page_nommu;
#endif
- /* this will put all low memory onto the freelists */
- totalram_pages += free_all_bootmem_node(NODE_DATA(0));
- reservedpages = 0;
- for (tmp = 0; tmp < num_physpages; tmp++)
- /*
- * Only count reserved RAM pages
- */
- if (PageReserved(mem_map+tmp))
- reservedpages++;
-
codesize = (unsigned long) &_etext - (unsigned long) &_text;
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
@@ -250,7 +240,7 @@ void __init mem_init(void)
printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
"%dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- max_mapnr << (PAGE_SHIFT-10),
+ totalram_pages << (PAGE_SHIFT-10),
codesize >> 10,
reservedpages << (PAGE_SHIFT-10),
datasize >> 10,
@@ -289,4 +279,3 @@ void free_initrd_mem(unsigned long start, unsigned long end)
printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
}
#endif
-
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index d0d45e2e0ab..02aae06527d 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -311,9 +311,9 @@ static int __init pmb_init(void)
BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
- pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry),
- 0, 0, pmb_cache_ctor, pmb_cache_dtor);
- BUG_ON(!pmb_cache);
+ pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
+ SLAB_PANIC, pmb_cache_ctor,
+ pmb_cache_dtor);
jump_to_P2();
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index 4fe0f94cbf4..554f801db67 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -9,6 +9,7 @@ SE SH_SOLUTION_ENGINE
7751SE SH_7751_SOLUTION_ENGINE
7300SE SH_7300_SOLUTION_ENGINE
7343SE SH_7343_SOLUTION_ENGINE
+7780SE SH_7780_SOLUTION_ENGINE
73180SE SH_73180_SOLUTION_ENGINE
7751SYSTEMH SH_7751_SYSTEMH
HP6XX SH_HP6XX
@@ -26,6 +27,7 @@ SH03 SH_SH03
LANDISK SH_LANDISK
R7780RP SH_R7780RP
R7780MP SH_R7780MP
+R7785RP SH_R7785RP
TITAN SH_TITAN
SHMIN SH_SHMIN
7710VOIPGW SH_7710VOIPGW
diff --git a/arch/sh64/kernel/early_printk.c b/arch/sh64/kernel/early_printk.c
index 8c8a76e180a..4f913112367 100644
--- a/arch/sh64/kernel/early_printk.c
+++ b/arch/sh64/kernel/early_printk.c
@@ -79,7 +79,7 @@ static struct console sh_console = {
.name = "scifcon",
.write = sh_console_write,
.setup = sh_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
@@ -97,9 +97,3 @@ void __init enable_early_printk(void)
register_console(&sh_console);
}
-
-void disable_early_printk(void)
-{
- unregister_console(&sh_console);
-}
-
diff --git a/arch/sh64/kernel/irq.c b/arch/sh64/kernel/irq.c
index e7e07f8749c..f68b4f6c9b3 100644
--- a/arch/sh64/kernel/irq.c
+++ b/arch/sh64/kernel/irq.c
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/bitops.h>
diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
index 9dae689b6a9..49862e165c0 100644
--- a/arch/sh64/kernel/pci_sh5.c
+++ b/arch/sh64/kernel/pci_sh5.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/rwsem.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/errno.h>
diff --git a/arch/sh64/kernel/sh_ksyms.c b/arch/sh64/kernel/sh_ksyms.c
index 7aa4b4f7bc5..461ea3de316 100644
--- a/arch/sh64/kernel/sh_ksyms.c
+++ b/arch/sh64/kernel/sh_ksyms.c
@@ -17,7 +17,6 @@
#include <linux/sched.h>
#include <linux/in6.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/screen_info.h>
#include <asm/semaphore.h>
diff --git a/arch/sh64/kernel/signal.c b/arch/sh64/kernel/signal.c
index 1666d3efb52..b76bdfa473d 100644
--- a/arch/sh64/kernel/signal.c
+++ b/arch/sh64/kernel/signal.c
@@ -16,7 +16,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c
index ad0fa4e003e..19126daf9f4 100644
--- a/arch/sh64/kernel/sys_sh64.c
+++ b/arch/sh64/kernel/sys_sh64.c
@@ -20,7 +20,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
diff --git a/arch/sh64/kernel/traps.c b/arch/sh64/kernel/traps.c
index c346d7ef928..9d0d58fb29f 100644
--- a/arch/sh64/kernel/traps.c
+++ b/arch/sh64/kernel/traps.c
@@ -23,7 +23,6 @@
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
diff --git a/arch/sh64/kernel/unwind.c b/arch/sh64/kernel/unwind.c
index f934f97f9f9..1214c78e358 100644
--- a/arch/sh64/kernel/unwind.c
+++ b/arch/sh64/kernel/unwind.c
@@ -46,15 +46,15 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
struct pt_regs *regs)
{
const char *sym;
- char *modname, namebuf[128];
- unsigned long offset, size;
+ char namebuf[128];
+ unsigned long offset;
unsigned long prologue = 0;
unsigned long fp_displacement = 0;
unsigned long fp_prev = 0;
unsigned long offset_r14 = 0, offset_r18 = 0;
int i, found_prologue_end = 0;
- sym = kallsyms_lookup(pc, &size, &offset, &modname, namebuf);
+ sym = kallsyms_lookup(pc, NULL, &offset, NULL, namebuf);
if (!sym)
return -EINVAL;
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index a59c5e99813..4f9616f3983 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -85,7 +85,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
.data.page_aligned : C_PHYS(.data.page_aligned) { *(.data.page_aligned) }
- . = ALIGN(L1_CACHE_BYTES);
+ . = ALIGN(PAGE_SIZE);
__per_cpu_start = .;
.data.percpu : C_PHYS(.data.percpu) { *(.data.percpu) }
__per_cpu_end = . ;
diff --git a/arch/sh64/mach-cayman/iomap.c b/arch/sh64/mach-cayman/iomap.c
index 2d06e9a5513..a5c645f02d5 100644
--- a/arch/sh64/mach-cayman/iomap.c
+++ b/arch/sh64/mach-cayman/iomap.c
@@ -9,7 +9,6 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#include <linux/pci.h>
#include <asm/io.h>
#include <asm/cayman.h>
diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
index 4f72ab33bb2..4dd8ee8f01c 100644
--- a/arch/sh64/mm/fault.c
+++ b/arch/sh64/mm/fault.c
@@ -22,7 +22,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <asm/system.h>
diff --git a/arch/sh64/mm/hugetlbpage.c b/arch/sh64/mm/hugetlbpage.c
index 4b455f61114..fa66daa2dfa 100644
--- a/arch/sh64/mm/hugetlbpage.c
+++ b/arch/sh64/mm/hugetlbpage.c
@@ -13,7 +13,6 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
diff --git a/arch/sh64/mm/tlbmiss.c b/arch/sh64/mm/tlbmiss.c
index c8615954aaa..d4c5334186d 100644
--- a/arch/sh64/mm/tlbmiss.c
+++ b/arch/sh64/mm/tlbmiss.c
@@ -32,7 +32,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <asm/system.h>
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
index 29d7cfd1c97..6773ed76e41 100644
--- a/arch/sparc/kernel/asm-offsets.c
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -28,7 +28,7 @@ int foo(void)
DEFINE(AOFF_task_gid, offsetof(struct task_struct, gid));
DEFINE(AOFF_task_euid, offsetof(struct task_struct, euid));
DEFINE(AOFF_task_egid, offsetof(struct task_struct, egid));
- /* DEFINE(THREAD_INFO, offsetof(struct task_struct, thread_info)); */
+ /* DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); */
DEFINE(ASIZ_task_uid, sizeof(current->uid));
DEFINE(ASIZ_task_gid, sizeof(current->gid));
DEFINE(ASIZ_task_euid, sizeof(current->euid));
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index 9a219e8b5dd..97da13c5256 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -19,7 +19,7 @@
#include <asm/ptrace.h>
#include <asm/psr.h>
#include <asm/page.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
#include <asm/winmacro.h>
#include <asm/thread_info.h> /* TI_UWINMASK */
#include <asm/errno.h>
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 5b4841d067c..bdbefa8a974 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -24,7 +24,6 @@
#include <linux/random.h>
#include <linux/init.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/threads.h>
#include <linux/spinlock.h>
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index fc874e63a49..2940d2c1a77 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -23,7 +23,6 @@
#include <linux/user.h>
#include <linux/a.out.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/pm.h>
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index eccd8e87f52..64c0ed98820 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -31,6 +31,7 @@
#include <linux/spinlock.h>
#include <linux/root_dev.h>
#include <linux/cpu.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -40,7 +41,6 @@
#include <asm/pgtable.h>
#include <asm/traps.h>
#include <asm/vaddrs.h>
-#include <asm/kdebug.h>
#include <asm/mbus.h>
#include <asm/idprom.h>
#include <asm/machines.h>
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c
index c9301b9143c..9994cac9507 100644
--- a/arch/sparc/kernel/signal.c
+++ b/arch/sparc/kernel/signal.c
@@ -17,7 +17,6 @@
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/binfmts.h> /* do_coredum */
#include <linux/bitops.h>
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 6b5f26b0fb7..4d9ad59031b 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/init.h>
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 0e27e226e0e..116d6a241ca 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -17,7 +17,6 @@
#include <linux/random.h>
#include <linux/init.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/seq_file.h>
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index c69de5d4863..098c94f1a32 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -12,7 +12,6 @@
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/init.h>
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index e2d9c018bd5..63ed19bfd02 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -9,7 +9,6 @@
#include <linux/sched.h>
#include <linux/threads.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/init.h>
@@ -405,7 +404,7 @@ void __init smp4m_blackbox_current(unsigned *addr)
addr[0] = 0x81580000 | rd; /* rd %tbr, reg */
addr[2] = 0x8130200a | rd | rs1; /* srl reg, 0xa, reg */
- addr[4] = 0x8008200c | rd | rs1; /* and reg, 3, reg */
+ addr[4] = 0x8008200c | rd | rs1; /* and reg, 0xc, reg */
}
void __init sun4m_init_smp(void)
diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c
index 32e8274e435..e613cc6a10b 100644
--- a/arch/sparc/kernel/sunos_ioctl.c
+++ b/arch/sparc/kernel/sunos_ioctl.c
@@ -21,7 +21,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/file.h>
diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c
index 01b07bb440f..2226a599248 100644
--- a/arch/sparc/kernel/sys_solaris.c
+++ b/arch/sparc/kernel/sys_solaris.c
@@ -12,7 +12,6 @@
#include <linux/ptrace.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
asmlinkage int
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 3a69778c836..e3f5b8ed4c5 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -80,6 +80,7 @@ sys_call_table:
/*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
/*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/ .long sys_utimensat
#ifdef CONFIG_SUNOS_EMUL
/* Now the SunOS syscall table. */
@@ -196,5 +197,6 @@ sunos_sys_table:
.long sunos_nosys, sunos_nosys, sunos_nosys
.long sunos_nosys, sunos_nosys, sunos_nosys
.long sunos_nosys
+/*310*/ .long sunos_nosys
#endif
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index 527687afc1c..dc9ffea2a4f 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -15,6 +15,7 @@
#include <linux/signal.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/kdebug.h>
#include <asm/delay.h>
#include <asm/system.h>
@@ -22,7 +23,6 @@
#include <asm/oplib.h>
#include <asm/page.h>
#include <asm/pgtable.h>
-#include <asm/kdebug.h>
#include <asm/unistd.h>
#include <asm/traps.h>
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index e5c24e0521d..f0bb6e60e62 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -65,7 +65,7 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(32);
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/sparc/lib/bitext.c b/arch/sparc/lib/bitext.c
index 2e168d16547..764b3eb7b60 100644
--- a/arch/sparc/lib/bitext.c
+++ b/arch/sparc/lib/bitext.c
@@ -9,7 +9,6 @@
* fragmentation.
*/
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/bitops.h>
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 9eeed3347df..c3483365db4 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -18,9 +18,9 @@
#include <linux/signal.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/page.h>
@@ -30,7 +30,6 @@
#include <asm/oplib.h>
#include <asm/smp.h>
#include <asm/traps.h>
-#include <asm/kdebug.h>
#include <asm/uaccess.h>
extern int prom_node_root;
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index 0df7121cef0..e5eaa8072ae 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -18,13 +18,13 @@
#include <linux/bootmem.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
+#include <linux/kdebug.h>
#include <asm/bitext.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/kdebug.h>
#include <asm/vaddrs.h>
#include <asm/traps.h>
#include <asm/smp.h>
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 590a41b864b..ad8d6b256a7 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -34,6 +34,10 @@ config MMU
bool
default y
+config QUICKLIST
+ bool
+ default y
+
config STACKTRACE_SUPPORT
bool
default y
@@ -306,6 +310,7 @@ config SUN_IO
config PCI
bool "PCI support"
+ select ARCH_SUPPORTS_MSI
help
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 120c9c33b7a..37c2d369565 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,15 +1,16 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc4
-# Sat Mar 17 14:18:44 2007
+# Linux kernel version: 2.6.21
+# Sun May 6 22:46:54 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_64BIT=y
CONFIG_MMU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_TIME_INTERPOLATION=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -108,6 +109,9 @@ CONFIG_GENERIC_HARDIRQS=y
#
# General machine setup
#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
# CONFIG_SMP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=m
@@ -140,8 +144,7 @@ CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
CONFIG_HAVE_MEMORY_PRESENT=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=0
@@ -151,6 +154,7 @@ CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_PCI_MSI=y
# CONFIG_PCI_DEBUG is not set
CONFIG_SUN_OPENPROMFS=m
@@ -178,7 +182,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
@@ -219,6 +222,7 @@ CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -292,6 +296,14 @@ CONFIG_NET_TCPPROBE=m
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
#
@@ -312,10 +324,6 @@ CONFIG_FW_LOADER=y
# Connector - unified userspace <-> kernelspace linker
#
CONFIG_CONNECTOR=m
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -383,7 +391,6 @@ CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_IDEDMA_ONLYDISK=y
# CONFIG_BLK_DEV_AEC62XX is not set
CONFIG_BLK_DEV_ALI15X3=y
@@ -413,7 +420,6 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -443,6 +449,7 @@ CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -485,6 +492,7 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SUNESP is not set
# CONFIG_SCSI_SRP is not set
@@ -628,9 +636,10 @@ CONFIG_BNX2=m
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
@@ -695,6 +704,12 @@ CONFIG_KEYBOARD_LKKBD=m
# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
CONFIG_MOUSE_SERIAL=y
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
@@ -702,6 +717,7 @@ CONFIG_MOUSE_SERIAL=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_SPARCSPKR=y
# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Hardware I/O ports
@@ -763,11 +779,8 @@ CONFIG_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_CHARDEV is not set
#
@@ -791,17 +804,17 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PASEMI is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
#
# Miscellaneous I2C Chip support
@@ -912,7 +925,7 @@ CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
#
-# Frambuffer hardware drivers
+# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
@@ -937,6 +950,8 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_XVR500 is not set
+# CONFIG_FB_XVR2500 is not set
# CONFIG_FB_PCI is not set
# CONFIG_FB_VIRTUAL is not set
@@ -1094,6 +1109,14 @@ CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1106,6 +1129,7 @@ CONFIG_USB=y
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
@@ -1156,10 +1180,6 @@ CONFIG_USB_STORAGE=m
#
# USB Input Devices
#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_ACECAD is not set
@@ -1524,6 +1544,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
+# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_BLOWFISH=m
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index eff0c01d357..6bf6fb65bc2 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -17,7 +17,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
- pci_sun4v.o pci_sun4v_asm.o
+ pci_sun4v.o pci_sun4v_asm.o pci_fire.o
obj-$(CONFIG_SMP) += smp.o trampoline.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c
index c65b2f9c98d..8230099f0d8 100644
--- a/arch/sparc64/kernel/central.c
+++ b/arch/sparc64/kernel/central.c
@@ -98,7 +98,7 @@ void apply_central_ranges(struct linux_central *central,
central->num_central_ranges);
}
-void * __init central_alloc_bootmem(unsigned long size)
+static void * __init central_alloc_bootmem(unsigned long size)
{
void *ret;
@@ -116,7 +116,7 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
return ret | (unsigned long) r->phys_addr;
}
-static void probe_other_fhcs(void)
+static void __init probe_other_fhcs(void)
{
struct device_node *dp;
const struct linux_prom64_registers *fpregs;
@@ -298,7 +298,7 @@ static void init_all_fhc_hw(void)
}
-void central_probe(void)
+void __init central_probe(void)
{
struct linux_prom_registers fpregs[6];
const struct linux_prom_registers *pr;
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 0ace17bafba..ad55a9bb50d 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -13,16 +13,17 @@
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/pci.h>
#include <asm/system.h>
#include <asm/page.h>
-#include <asm/pbm.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>
+#include <asm/io.h>
/* EBUS dma library. */
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 6241e3dbbd5..3edc18e1b81 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -279,7 +279,7 @@ static void sun4u_irq_enable(unsigned int virt_irq)
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data)) {
- unsigned long cpuid, imap;
+ unsigned long cpuid, imap, val;
unsigned int tid;
cpuid = irq_choose_cpu(virt_irq);
@@ -287,7 +287,11 @@ static void sun4u_irq_enable(unsigned int virt_irq)
tid = sun4u_compute_tid(imap, cpuid);
- upa_writel(tid | IMAP_VALID, imap);
+ val = upa_readq(imap);
+ val &= ~(IMAP_TID_UPA | IMAP_TID_JBUS |
+ IMAP_AID_SAFARI | IMAP_NID_SAFARI);
+ val |= tid | IMAP_VALID;
+ upa_writeq(val, imap);
}
}
@@ -297,10 +301,10 @@ static void sun4u_irq_disable(unsigned int virt_irq)
if (likely(data)) {
unsigned long imap = data->imap;
- u32 tmp = upa_readl(imap);
+ u32 tmp = upa_readq(imap);
tmp &= ~IMAP_VALID;
- upa_writel(tmp, imap);
+ upa_writeq(tmp, imap);
}
}
@@ -309,7 +313,7 @@ static void sun4u_irq_end(unsigned int virt_irq)
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data))
- upa_writel(ICLR_IDLE, data->iclr);
+ upa_writeq(ICLR_IDLE, data->iclr);
}
static void sun4v_irq_enable(unsigned int virt_irq)
@@ -465,7 +469,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
BUG_ON(tlb_type == hypervisor);
- ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
+ ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
bucket = &ivector_table[ino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index ae221f0d4a6..c93a15b785f 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -6,7 +6,7 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/module.h>
-#include <asm/kdebug.h>
+#include <linux/kdebug.h>
#include <asm/signal.h>
#include <asm/cacheflush.h>
#include <asm/uaccess.h>
@@ -313,7 +313,7 @@ out:
return 1;
}
-static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -403,15 +403,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
if (post_kprobe_handler(args->regs))
ret = NOTIFY_STOP;
break;
- case DIE_GPF:
- case DIE_PAGE_FAULT:
- /* kprobe_running() needs smp_processor_id() */
- preempt_disable();
- if (kprobe_running() &&
- kprobe_fault_handler(args->regs, args->trapnr))
- ret = NOTIFY_STOP;
- preempt_enable();
- break;
default:
break;
}
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 023af41ad68..d85e1ed7c3e 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -14,13 +14,12 @@
#include <linux/sched.h>
#include <linux/capability.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
+#include <linux/pci.h>
#include <linux/msi.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <asm/uaccess.h>
-#include <asm/pbm.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/ebus.h>
@@ -49,10 +48,10 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
#else
/* List of all PCI controllers found in the system. */
-struct pci_controller_info *pci_controller_root = NULL;
+struct pci_pbm_info *pci_pbm_root = NULL;
-/* Each PCI controller found gets a unique index. */
-int pci_num_controllers = 0;
+/* Each PBM found gets a unique index. */
+int pci_num_pbms = 0;
volatile int pci_poke_in_progress;
volatile int pci_poke_cpu = -1;
@@ -190,6 +189,7 @@ 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;
@@ -207,6 +207,7 @@ static struct {
{ "SUNW,tomatillo", tomatillo_init },
{ "pci108e,a801", tomatillo_init },
{ "SUNW,sun4v-pci", sun4v_pci_init },
+ { "pciex108e,80f0", fire_pci_init },
};
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0]))
@@ -290,7 +291,7 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
/* Find each controller in the system, attach and initialize
* software state structure for each and link into the
- * pci_controller_root. Setup the controller enough such
+ * pci_pbm_root. Setup the controller enough such
* that bus scanning can be done.
*/
static void __init pci_controller_probe(void)
@@ -436,6 +437,13 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
printk(" class: 0x%x device name: %s\n",
dev->class, pci_name(dev));
+ /* I have seen IDE devices which will not respond to
+ * the bmdma simplex check reads if bus mastering is
+ * disabled.
+ */
+ if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
+ pci_set_master(dev);
+
dev->current_state = 4; /* unknown power state */
dev->error_state = pci_channel_io_normal;
@@ -468,7 +476,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
return dev;
}
-static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
+static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
{
u32 idx, first, last;
@@ -497,9 +505,9 @@ static void __init pci_resource_adjust(struct resource *res,
/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
* a proper 'ranges' property.
*/
-static void __init apb_fake_ranges(struct pci_dev *dev,
- struct pci_bus *bus,
- struct pci_pbm_info *pbm)
+static void __devinit apb_fake_ranges(struct pci_dev *dev,
+ struct pci_bus *bus,
+ struct pci_pbm_info *pbm)
{
struct resource *res;
u32 first, last;
@@ -522,15 +530,15 @@ static void __init apb_fake_ranges(struct pci_dev *dev,
pci_resource_adjust(res, &pbm->mem_space);
}
-static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
- struct device_node *node,
- struct pci_bus *bus);
+static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_bus *bus);
#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
-void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
- struct device_node *node,
- struct pci_dev *dev)
+static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_dev *dev)
{
struct pci_bus *bus;
const u32 *busrange, *ranges;
@@ -629,9 +637,9 @@ simba_cont:
pci_of_scan_bus(pbm, node, bus);
}
-static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
- struct device_node *node,
- struct pci_bus *bus)
+static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
+ struct device_node *node,
+ struct pci_bus *bus)
{
struct device_node *child;
const u32 *reg;
@@ -733,9 +741,8 @@ int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
return PCIBIOS_SUCCESSFUL;
}
-struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
{
- struct pci_controller_info *p = pbm->parent;
struct device_node *node = pbm->prom_node;
struct pci_dev *host_pdev;
struct pci_bus *bus;
@@ -743,7 +750,7 @@ struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
printk("PCI: Scanning PBM %s\n", node->full_name);
/* XXX parent device? XXX */
- bus = pci_create_bus(NULL, pbm->pci_first_busno, p->pci_ops, pbm);
+ bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
if (!bus) {
printk(KERN_ERR "Failed to create bus for %s\n",
node->full_name);
@@ -768,10 +775,10 @@ struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
static void __init pci_scan_each_controller_bus(void)
{
- struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
- for (p = pci_controller_root; p; p = p->next)
- p->scan_bus(p);
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
+ pbm->scan_bus(pbm);
}
extern void power_init(void);
@@ -779,7 +786,7 @@ extern void power_init(void);
static int __init pcibios_init(void)
{
pci_controller_probe();
- if (pci_controller_root == NULL)
+ if (pci_pbm_root == NULL)
return 0;
pci_scan_each_controller_bus();
@@ -914,10 +921,8 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
enum pci_mmap_state mmap_state)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- struct pci_controller_info *p;
unsigned long space_size, user_offset, user_size;
- p = pbm->parent;
if (mmap_state == pci_mmap_io) {
space_size = (pbm->io_space.end -
pbm->io_space.start) + 1;
@@ -1070,11 +1075,7 @@ int pci_domain_nr(struct pci_bus *pbus)
if (pbm == NULL || pbm->parent == NULL) {
ret = -ENXIO;
} else {
- struct pci_controller_info *p = pbm->parent;
-
- ret = p->index;
- ret = ((ret << 1) +
- ((pbm == &pbm->parent->pbm_B) ? 1 : 0));
+ ret = pbm->index;
}
return ret;
@@ -1085,17 +1086,12 @@ 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;
- struct pci_controller_info *p = pbm->parent;
- int virt_irq, err;
+ int virt_irq;
- if (!pbm->msi_num || !p->setup_msi_irq)
+ if (!pbm->setup_msi_irq)
return -EINVAL;
- err = p->setup_msi_irq(&virt_irq, pdev, desc);
- if (err < 0)
- return err;
-
- return virt_irq;
+ return pbm->setup_msi_irq(&virt_irq, pdev, desc);
}
void arch_teardown_msi_irq(unsigned int virt_irq)
@@ -1103,12 +1099,11 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
struct msi_desc *entry = get_irq_msi(virt_irq);
struct pci_dev *pdev = entry->dev;
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
- struct pci_controller_info *p = pbm->parent;
- if (!pbm->msi_num || !p->setup_msi_irq)
+ if (!pbm->teardown_msi_irq)
return;
- return p->teardown_msi_irq(virt_irq, pdev);
+ return pbm->teardown_msi_irq(virt_irq, pdev);
}
#endif /* !(CONFIG_PCI_MSI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 1e6aeedf43c..76faaa8135d 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -9,12 +9,26 @@
#include <linux/pci.h>
#include <linux/device.h>
-#include <asm/pbm.h>
#include <asm/prom.h>
#include <asm/of_device.h>
+#include <asm/oplib.h>
#include "pci_impl.h"
+void pci_get_pbm_props(struct pci_pbm_info *pbm)
+{
+ const u32 *val = of_get_property(pbm->prom_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);
+ if (val) {
+ pbm->ino_bitmap = (((u64)val[1] << 32UL) |
+ ((u64)val[0] << 0UL));
+ }
+}
+
static void pci_register_legacy_regions(struct resource *io_res,
struct resource *mem_res)
{
@@ -149,8 +163,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
}
/* Generic helper routines for PCI error reporting. */
-void pci_scan_for_target_abort(struct pci_controller_info *p,
- struct pci_pbm_info *pbm,
+void pci_scan_for_target_abort(struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
struct pci_dev *pdev;
@@ -165,18 +178,16 @@ void pci_scan_for_target_abort(struct pci_controller_info *p,
PCI_STATUS_REC_TARGET_ABORT));
if (error_bits) {
pci_write_config_word(pdev, PCI_STATUS, error_bits);
- printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n",
- p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
- pci_name(pdev), status);
+ printk("%s: Device %s saw Target Abort [%016x]\n",
+ pbm->name, pci_name(pdev), status);
}
}
list_for_each_entry(bus, &pbus->children, node)
- pci_scan_for_target_abort(p, pbm, bus);
+ pci_scan_for_target_abort(pbm, bus);
}
-void pci_scan_for_master_abort(struct pci_controller_info *p,
- struct pci_pbm_info *pbm,
+void pci_scan_for_master_abort(struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
struct pci_dev *pdev;
@@ -190,18 +201,16 @@ void pci_scan_for_master_abort(struct pci_controller_info *p,
(status & (PCI_STATUS_REC_MASTER_ABORT));
if (error_bits) {
pci_write_config_word(pdev, PCI_STATUS, error_bits);
- printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n",
- p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
- pci_name(pdev), status);
+ printk("%s: Device %s received Master Abort [%016x]\n",
+ pbm->name, pci_name(pdev), status);
}
}
list_for_each_entry(bus, &pbus->children, node)
- pci_scan_for_master_abort(p, pbm, bus);
+ pci_scan_for_master_abort(pbm, bus);
}
-void pci_scan_for_parity_error(struct pci_controller_info *p,
- struct pci_pbm_info *pbm,
+void pci_scan_for_parity_error(struct pci_pbm_info *pbm,
struct pci_bus *pbus)
{
struct pci_dev *pdev;
@@ -216,12 +225,11 @@ void pci_scan_for_parity_error(struct pci_controller_info *p,
PCI_STATUS_DETECTED_PARITY));
if (error_bits) {
pci_write_config_word(pdev, PCI_STATUS, error_bits);
- printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n",
- p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'),
- pci_name(pdev), status);
+ printk("%s: Device %s saw Parity Error [%016x]\n",
+ pbm->name, pci_name(pdev), status);
}
}
list_for_each_entry(bus, &pbus->children, node)
- pci_scan_for_parity_error(p, pbm, bus);
+ pci_scan_for_parity_error(pbm, bus);
}
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
new file mode 100644
index 00000000000..2e0eb4ee8f7
--- /dev/null
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -0,0 +1,390 @@
+/* pci_fire.c: Sun4u platform PCI-E controller support.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+
+#include <asm/oplib.h>
+#include <asm/prom.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")
+
+/* Fire config space address format is nearly identical to
+ * that of SCHIZO and PSYCHO, except that in order to accomodate
+ * PCI-E extended config space the encoding can handle 12 bits
+ * of register address:
+ *
+ * 32 28 27 20 19 15 14 12 11 2 1 0
+ * -------------------------------------------------
+ * |0 0 0 0 0| bus | device | function | reg | 0 0 |
+ * -------------------------------------------------
+ */
+#define FIRE_CONFIG_BASE(PBM) ((PBM)->config_space)
+#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
+ (((unsigned long)(BUS) << 20) | \
+ ((unsigned long)(DEVFN) << 12) | \
+ ((unsigned long)(REG)))
+
+static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
+ unsigned char bus,
+ unsigned int devfn,
+ int where)
+{
+ if (!pbm)
+ return NULL;
+ return (void *)
+ (FIRE_CONFIG_BASE(pbm) |
+ FIRE_CONFIG_ENCODE(bus, devfn, where));
+}
+
+/* FIRE PCI configuration space accessors. */
+
+static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ struct pci_pbm_info *pbm = bus_dev->sysdata;
+ unsigned char bus = bus_dev->number;
+ u32 *addr;
+ u16 tmp16;
+ u8 tmp8;
+
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+ size, value);
+ switch (size) {
+ case 1:
+ *value = 0xff;
+ break;
+ case 2:
+ *value = 0xffff;
+ break;
+ case 4:
+ *value = 0xffffffff;
+ break;
+ }
+
+ addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ switch (size) {
+ case 1:
+ pci_config_read8((u8 *)addr, &tmp8);
+ *value = tmp8;
+ break;
+
+ case 2:
+ if (where & 0x01) {
+ printk("pci_read_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_read16((u16 *)addr, &tmp16);
+ *value = tmp16;
+ break;
+
+ case 4:
+ if (where & 0x03) {
+ printk("pci_read_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ pci_config_read32(addr, value);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct pci_pbm_info *pbm = bus_dev->sysdata;
+ unsigned char bus = bus_dev->number;
+ u32 *addr;
+
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+ size, value);
+ addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ switch (size) {
+ case 1:
+ pci_config_write8((u8 *)addr, value);
+ break;
+
+ case 2:
+ if (where & 0x01) {
+ printk("pci_write_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_write16((u16 *)addr, value);
+ break;
+
+ case 4:
+ if (where & 0x03) {
+ printk("pci_write_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ pci_config_write32(addr, value);
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops pci_fire_ops = {
+ .read = fire_read_pci_cfg,
+ .write = fire_write_pci_cfg,
+};
+
+static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
+{
+ pbm->pci_bus = pci_scan_one_pbm(pbm);
+
+ /* XXX register error interrupt handlers XXX */
+}
+
+#define FIRE_IOMMU_CONTROL 0x40000UL
+#define FIRE_IOMMU_TSBBASE 0x40008UL
+#define FIRE_IOMMU_FLUSH 0x40100UL
+#define FIRE_IOMMU_FLUSHINV 0x40100UL
+
+static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
+{
+ struct iommu *iommu = pbm->iommu;
+ u32 vdma[2], dma_mask;
+ u64 control;
+ int tsbsize;
+
+ /* No virtual-dma property on these guys, use largest size. */
+ vdma[0] = 0xc0000000; /* base */
+ vdma[1] = 0x40000000; /* size */
+ dma_mask = 0xffffffff;
+ tsbsize = 128;
+
+ /* Register addresses. */
+ iommu->iommu_control = pbm->pbm_regs + FIRE_IOMMU_CONTROL;
+ iommu->iommu_tsbbase = pbm->pbm_regs + FIRE_IOMMU_TSBBASE;
+ iommu->iommu_flush = pbm->pbm_regs + FIRE_IOMMU_FLUSH;
+ iommu->iommu_flushinv = pbm->pbm_regs + FIRE_IOMMU_FLUSHINV;
+
+ /* We use the main control/status register of FIRE as the write
+ * completion register.
+ */
+ iommu->write_complete_reg = pbm->controller_regs + 0x410000UL;
+
+ /*
+ * Invalidate TLB Entries.
+ */
+ fire_write(iommu->iommu_flushinv, ~(u64)0);
+
+ pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+
+ fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+
+ control = fire_read(iommu->iommu_control);
+ control |= (0x00000400 /* TSB cache snoop enable */ |
+ 0x00000300 /* Cache mode */ |
+ 0x00000002 /* Bypass enable */ |
+ 0x00000001 /* Translation enable */);
+ fire_write(iommu->iommu_control, control);
+}
+
+/* Based at pbm->controller_regs */
+#define FIRE_PARITY_CONTROL 0x470010UL
+#define FIRE_PARITY_ENAB 0x8000000000000000UL
+#define FIRE_FATAL_RESET_CTL 0x471028UL
+#define FIRE_FATAL_RESET_SPARE 0x0000000004000000UL
+#define FIRE_FATAL_RESET_MB 0x0000000002000000UL
+#define FIRE_FATAL_RESET_CPE 0x0000000000008000UL
+#define FIRE_FATAL_RESET_APE 0x0000000000004000UL
+#define FIRE_FATAL_RESET_PIO 0x0000000000000040UL
+#define FIRE_FATAL_RESET_JW 0x0000000000000004UL
+#define FIRE_FATAL_RESET_JI 0x0000000000000002UL
+#define FIRE_FATAL_RESET_JR 0x0000000000000001UL
+#define FIRE_CORE_INTR_ENABLE 0x471800UL
+
+/* Based at pbm->pbm_regs */
+#define FIRE_TLU_CTRL 0x80000UL
+#define FIRE_TLU_CTRL_TIM 0x00000000da000000UL
+#define FIRE_TLU_CTRL_QDET 0x0000000000000100UL
+#define FIRE_TLU_CTRL_CFG 0x0000000000000001UL
+#define FIRE_TLU_DEV_CTRL 0x90008UL
+#define FIRE_TLU_LINK_CTRL 0x90020UL
+#define FIRE_TLU_LINK_CTRL_CLK 0x0000000000000040UL
+#define FIRE_LPU_RESET 0xe2008UL
+#define FIRE_LPU_LLCFG 0xe2200UL
+#define FIRE_LPU_LLCFG_VC0 0x0000000000000100UL
+#define FIRE_LPU_FCTRL_UCTRL 0xe2240UL
+#define FIRE_LPU_FCTRL_UCTRL_N 0x0000000000000002UL
+#define FIRE_LPU_FCTRL_UCTRL_P 0x0000000000000001UL
+#define FIRE_LPU_TXL_FIFOP 0xe2430UL
+#define FIRE_LPU_LTSSM_CFG2 0xe2788UL
+#define FIRE_LPU_LTSSM_CFG3 0xe2790UL
+#define FIRE_LPU_LTSSM_CFG4 0xe2798UL
+#define FIRE_LPU_LTSSM_CFG5 0xe27a0UL
+#define FIRE_DMC_IENAB 0x31800UL
+#define FIRE_DMC_DBG_SEL_A 0x53000UL
+#define FIRE_DMC_DBG_SEL_B 0x53008UL
+#define FIRE_PEC_IENAB 0x51800UL
+
+static void pci_fire_hw_init(struct pci_pbm_info *pbm)
+{
+ u64 val;
+
+ fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
+ FIRE_PARITY_ENAB);
+
+ fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
+ (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_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+
+ val = fire_read(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);
+}
+
+static void pci_fire_pbm_init(struct pci_controller_info *p,
+ struct device_node *dp, u32 portid)
+{
+ const struct linux_prom64_registers *regs;
+ struct pci_pbm_info *pbm;
+
+ if ((portid & 1) == 0)
+ pbm = &p->pbm_A;
+ else
+ pbm = &p->pbm_B;
+
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ pbm->scan_bus = pci_fire_scan_bus;
+ pbm->pci_ops = &pci_fire_ops;
+
+ pbm->index = pci_num_pbms++;
+
+ pbm->portid = portid;
+ pbm->parent = p;
+ pbm->prom_node = dp;
+ pbm->name = dp->full_name;
+
+ regs = of_get_property(dp, "reg", NULL);
+ pbm->pbm_regs = regs[0].phys_addr;
+ pbm->controller_regs = regs[1].phys_addr - 0x410000UL;
+
+ printk("%s: SUN4U PCIE Bus Module\n", pbm->name);
+
+ pci_determine_mem_io_space(pbm);
+
+ pci_get_pbm_props(pbm);
+
+ pci_fire_hw_init(pbm);
+ pci_fire_pbm_iommu_init(pbm);
+}
+
+static inline int portid_compare(u32 x, u32 y)
+{
+ if (x == (y ^ 1))
+ return 1;
+ return 0;
+}
+
+void fire_pci_init(struct device_node *dp, const char *model_name)
+{
+ struct pci_controller_info *p;
+ u32 portid = of_getintprop_default(dp, "portid", 0xff);
+ struct iommu *iommu;
+ struct pci_pbm_info *pbm;
+
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+ if (portid_compare(pbm->portid, portid)) {
+ pci_fire_pbm_init(pbm->parent, dp, portid);
+ return;
+ }
+ }
+
+ 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;
+
+ p->pbm_A.iommu = iommu;
+
+ iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
+ if (!iommu)
+ goto fatal_memory_error;
+
+ p->pbm_B.iommu = iommu;
+
+ /* XXX MSI support XXX */
+
+ /* Like PSYCHO and SCHIZO we have a 2GB aligned area
+ * for memory space.
+ */
+ pci_memspace_mask = 0x7fffffffUL;
+
+ pci_fire_pbm_init(p, dp, portid);
+ return;
+
+fatal_memory_error:
+ prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
+ prom_halt();
+}
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 1208583fcb8..8e38023868a 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -8,15 +8,129 @@
#include <linux/types.h>
#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
#include <asm/io.h>
#include <asm/prom.h>
+#include <asm/iommu.h>
-extern struct pci_controller_info *pci_controller_root;
+/* The abstraction used here is that there are PCI controllers,
+ * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
+ * underneath. Each PCI bus module uses an IOMMU (shared by both
+ * PBMs of a controller, or per-PBM), and if a streaming buffer
+ * is present, each PCI bus module has it's own. (ie. the IOMMU
+ * might be shared between PBMs, the STC is never shared)
+ * Furthermore, each PCI bus module controls it's own autonomous
+ * PCI bus.
+ */
+
+#define PCI_STC_FLUSHFLAG_INIT(STC) \
+ (*((STC)->strbuf_flushflag) = 0UL)
+#define PCI_STC_FLUSHFLAG_SET(STC) \
+ (*((STC)->strbuf_flushflag) != 0UL)
+
+struct pci_controller_info;
+
+struct pci_pbm_info {
+ struct pci_pbm_info *next;
+ int index;
+
+ /* PCI controller we sit under. */
+ struct pci_controller_info *parent;
+
+ /* Physical address base of controller registers. */
+ unsigned long controller_regs;
+
+ /* Physical address base of PBM registers. */
+ unsigned long pbm_regs;
+
+ /* Physical address of DMA sync register, if any. */
+ unsigned long sync_reg;
+
+ /* Opaque 32-bit system bus Port ID. */
+ u32 portid;
+
+ /* Opaque 32-bit handle used for hypervisor calls. */
+ u32 devhandle;
+
+ /* Chipset version information. */
+ int chip_type;
+#define PBM_CHIP_TYPE_SABRE 1
+#define PBM_CHIP_TYPE_PSYCHO 2
+#define PBM_CHIP_TYPE_SCHIZO 3
+#define PBM_CHIP_TYPE_SCHIZO_PLUS 4
+#define PBM_CHIP_TYPE_TOMATILLO 5
+ int chip_version;
+ int chip_revision;
+
+ /* Name used for top-level resources. */
+ char *name;
+
+ /* OBP specific information. */
+ struct device_node *prom_node;
+ u64 ino_bitmap;
+
+ /* PBM I/O and Memory space resources. */
+ struct resource io_space;
+ struct resource mem_space;
+
+ /* Base of PCI Config space, can be per-PBM or shared. */
+ unsigned long config_space;
+
+ /* State of 66MHz capabilities on this PBM. */
+ int is_66mhz_capable;
+ int all_devs_66mhz;
+
+#ifdef CONFIG_PCI_MSI
+ /* MSI info. */
+ u32 msiq_num;
+ u32 msiq_ent_count;
+ u32 msiq_first;
+ u32 msiq_first_devino;
+ u32 msi_num;
+ u32 msi_first;
+ u32 msi_data_mask;
+ u32 msix_data_width;
+ u64 msi32_start;
+ u64 msi64_start;
+ u32 msi32_len;
+ u32 msi64_len;
+ void *msi_queues;
+ unsigned long *msi_bitmap;
+ int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
+ struct msi_desc *entry);
+ void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
+#endif /* !(CONFIG_PCI_MSI) */
+
+ /* This PBM's streaming buffer. */
+ struct strbuf stc;
+
+ /* IOMMU state, potentially shared by both PBM segments. */
+ struct iommu *iommu;
+
+ /* Now things for the actual PCI bus probes. */
+ 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;
+};
+
+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 unsigned long pci_memspace_mask;
-extern int pci_num_controllers;
+extern int pci_num_pbms;
/* PCI bus scanning and fixup support. */
+extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize,
+ u32 dma_offset, u32 dma_addr_mask);
+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 void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
@@ -30,9 +144,9 @@ extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
u32 value);
/* Error reporting support. */
-extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
-extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
-extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *);
+extern void pci_scan_for_parity_error(struct pci_pbm_info *, struct pci_bus *);
/* Configuration space access. */
extern void pci_config_read8(u8 *addr, u8 *ret);
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c
index 66712772f49..dfd6f9f4790 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/pci_iommu.c
@@ -8,10 +8,12 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/delay.h>
+#include <linux/pci.h>
-#include <asm/pbm.h>
+#include <asm/oplib.h>
#include "iommu_common.h"
+#include "pci_impl.h"
#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \
((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
@@ -37,17 +39,21 @@
/* Must be invoked under the IOMMU lock. */
static void __iommu_flushall(struct iommu *iommu)
{
- unsigned long tag;
- int entry;
+ if (iommu->iommu_flushinv) {
+ pci_iommu_write(iommu->iommu_flushinv, ~(u64)0);
+ } else {
+ unsigned long tag;
+ int entry;
- tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
- for (entry = 0; entry < 16; entry++) {
- pci_iommu_write(tag, 0);
- tag += 8;
- }
+ tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
+ for (entry = 0; entry < 16; entry++) {
+ pci_iommu_write(tag, 0);
+ tag += 8;
+ }
- /* Ensure completion of previous PIO writes. */
- (void) pci_iommu_read(iommu->write_complete_reg);
+ /* Ensure completion of previous PIO writes. */
+ (void) pci_iommu_read(iommu->write_complete_reg);
+ }
}
#define IOPTE_CONSISTENT(CTX) \
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 253d40ec224..2edcb1dd13c 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -12,12 +12,12 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/starfire.h>
#include <asm/prom.h>
#include <asm/of_device.h>
+#include <asm/oplib.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -98,13 +98,8 @@ static int psycho_out_of_range(struct pci_pbm_info *pbm,
unsigned char bus,
unsigned char devfn)
{
- return ((pbm->parent == 0) ||
- ((pbm == &pbm->parent->pbm_B) &&
- (bus == pbm->pci_first_busno) &&
- PCI_SLOT(devfn) > 8) ||
- ((pbm == &pbm->parent->pbm_A) &&
- (bus == pbm->pci_first_busno) &&
- PCI_SLOT(devfn) > 8));
+ return ((bus == pbm->pci_first_busno) &&
+ PCI_SLOT(devfn) > 8);
}
/* PSYCHO PCI configuration space accessors. */
@@ -265,12 +260,11 @@ 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_controller_info *p,
- struct pci_pbm_info *pbm,
+static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
int is_pbm_a)
{
struct strbuf *strbuf = &pbm->stc;
- unsigned long regbase = p->pbm_A.controller_regs;
+ unsigned long regbase = pbm->controller_regs;
unsigned long err_base, tag_base, line_base;
u64 control;
int i;
@@ -326,9 +320,8 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
unsigned long errval = stc_error_buf[j];
if (errval != 0) {
saw_error++;
- printk("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n",
- p->index,
- (is_pbm_a ? 'A' : 'B'),
+ 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);
@@ -337,18 +330,16 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
if (saw_error != 0) {
unsigned long tagval = stc_tag_buf[i];
unsigned long lineval = stc_line_buf[i];
- printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
- p->index,
- (is_pbm_a ? 'A' : 'B'),
+ 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("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
+ printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
"V(%d)FOFN(%d)]\n",
- p->index,
- (is_pbm_a ? 'A' : 'B'),
+ pbm->name,
i,
((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
@@ -362,20 +353,13 @@ static void __psycho_check_one_stc(struct pci_controller_info *p,
spin_unlock(&stc_buf_lock);
}
-static void __psycho_check_stc_error(struct pci_controller_info *p,
+static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
unsigned long afsr,
unsigned long afar,
enum psycho_error_type type)
{
- struct pci_pbm_info *pbm;
-
- pbm = &p->pbm_A;
- if (pbm->stc.strbuf_enabled)
- __psycho_check_one_stc(p, pbm, 1);
-
- pbm = &p->pbm_B;
- if (pbm->stc.strbuf_enabled)
- __psycho_check_one_stc(p, pbm, 0);
+ __psycho_check_one_stc(pbm,
+ (pbm == &pbm->parent->pbm_A));
}
/* When an Uncorrectable Error or a PCI Error happens, we
@@ -413,12 +397,12 @@ static void __psycho_check_stc_error(struct pci_controller_info *p,
#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_controller_info *p,
+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 = p->pbm_A.iommu;
+ struct iommu *iommu = pbm->iommu;
unsigned long iommu_tag[16];
unsigned long iommu_data[16];
unsigned long flags;
@@ -449,8 +433,8 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
type_string = "ECC Error";
break;
};
- printk("PSYCHO%d: IOMMU Error, type[%s]\n",
- p->index, type_string);
+ 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.
@@ -465,7 +449,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
psycho_write(iommu->iommu_control,
control | PSYCHO_IOMMU_CTRL_DENAB);
for (i = 0; i < 16; i++) {
- unsigned long base = p->pbm_A.controller_regs;
+ unsigned long base = pbm->controller_regs;
iommu_tag[i] =
psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
@@ -503,20 +487,20 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
type_string = "ECC Error";
break;
};
- printk("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
- p->index, i, type_string,
+ 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("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
- p->index, i,
+ 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(p, afsr, afar, type);
+ __psycho_check_stc_error(pbm, afsr, afar, type);
spin_unlock_irqrestore(&iommu->lock, flags);
}
@@ -541,9 +525,10 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFSR;
- unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_UE_AFAR;
+ 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;
@@ -560,22 +545,22 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
psycho_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Uncorrectable Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & PSYCHO_UEAFSR_PPIO) ?
"PIO" :
((error_bits & PSYCHO_UEAFSR_PDRD) ?
"DMA Read" :
((error_bits & PSYCHO_UEAFSR_PDWR) ?
"DMA Write" : "???")))));
- printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
- p->index,
+ printk("%s: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n",
+ pbm->name,
(afsr & PSYCHO_UEAFSR_BMSK) >> 32UL,
(afsr & PSYCHO_UEAFSR_DOFF) >> 29UL,
(afsr & PSYCHO_UEAFSR_MID) >> 24UL,
((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0));
- printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar);
- printk("PSYCHO%d: UE Secondary errors [", p->index);
+ printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: UE Secondary errors [", pbm->name);
reported = 0;
if (afsr & PSYCHO_UEAFSR_SPIO) {
reported++;
@@ -593,8 +578,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
printk("(none)");
printk("]\n");
- /* Interrogate IOMMU for error status. */
- psycho_check_iommu_error(p, afsr, afar, UE_ERR);
+ /* 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);
return IRQ_HANDLED;
}
@@ -618,9 +604,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR;
- unsigned long afar_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFAR;
+ struct pci_pbm_info *pbm = dev_id;
+ unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR;
+ unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR;
unsigned long afsr, afar, error_bits;
int reported;
@@ -637,8 +623,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
psycho_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PSYCHO%d: Correctable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Correctable Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & PSYCHO_CEAFSR_PPIO) ?
"PIO" :
((error_bits & PSYCHO_CEAFSR_PDRD) ?
@@ -649,16 +635,16 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
/* XXX Use syndrome and afar to print out module string just like
* XXX UDB CE trap handler does... -DaveM
*/
- printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+ printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
"UPA_MID[%02lx] was_block(%d)\n",
- p->index,
+ pbm->name,
(afsr & PSYCHO_CEAFSR_ESYND) >> 48UL,
(afsr & PSYCHO_CEAFSR_BMSK) >> 32UL,
(afsr & PSYCHO_CEAFSR_DOFF) >> 29UL,
(afsr & PSYCHO_CEAFSR_MID) >> 24UL,
((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0));
- printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar);
- printk("PSYCHO%d: CE Secondary errors [", p->index);
+ printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: CE Secondary errors [", pbm->name);
reported = 0;
if (afsr & PSYCHO_CEAFSR_SPIO) {
reported++;
@@ -773,8 +759,8 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
psycho_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n",
- p->index, (is_pbm_a ? 'A' : 'B'),
+ printk("%s: PCI Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & PSYCHO_PCIAFSR_PMA) ?
"Master Abort" :
((error_bits & PSYCHO_PCIAFSR_PTA) ?
@@ -783,15 +769,13 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
"Excessive Retries" :
((error_bits & PSYCHO_PCIAFSR_PPERR) ?
"Parity Error" : "???"))))));
- printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
- p->index, (is_pbm_a ? 'A' : 'B'),
+ 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("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n",
- p->index, (is_pbm_a ? 'A' : 'B'), afar);
- printk("PSYCHO%d(PBM%c): PCI Secondary errors [",
- p->index, (is_pbm_a ? 'A' : 'B'));
+ printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: PCI Secondary errors [", pbm->name);
reported = 0;
if (afsr & PSYCHO_PCIAFSR_SMA) {
reported++;
@@ -823,11 +807,11 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
* 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(p, afsr, afar, PCI_ERR);
- pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+ 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(p, pbm, pbm->pci_bus);
+ 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
@@ -837,7 +821,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
*/
if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
- pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+ pci_scan_for_parity_error(pbm, pbm->pci_bus);
return IRQ_HANDLED;
}
@@ -847,34 +831,49 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
#define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */
#define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */
#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* Enable CE INterrupts */
-static void psycho_register_error_handlers(struct pci_controller_info *p)
+static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
struct of_device *op = of_find_device_by_node(pbm->prom_node);
- unsigned long base = p->pbm_A.controller_regs;
+ unsigned long base = pbm->controller_regs;
u64 tmp;
+ int err;
if (!op)
return;
/* Psycho interrupt property order is:
- * 0: PCIERR PBM B INO
+ * 0: PCIERR INO for this PBM
* 1: UE ERR
* 2: CE ERR
* 3: POWER FAIL
* 4: SPARE HARDWARE
- * 5: PCIERR PBM A INO
+ * 5: POWER MANAGEMENT
*/
if (op->num_irqs < 6)
return;
- request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO UE", p);
- request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO CE", p);
- request_irq(op->irqs[5], psycho_pcierr_intr, IRQF_SHARED,
- "PSYCHO PCIERR-A", &p->pbm_A);
- request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED,
- "PSYCHO PCIERR-B", &p->pbm_B);
+ /* We really mean to ignore the return result here. Two
+ * PCI controller share the same interrupt numbers and
+ * drive the same front-end hardware. Whichever of the
+ * two get in here first will register the IRQ handler
+ * the second will just error out since we do not pass in
+ * IRQF_SHARED.
+ */
+ err = request_irq(op->irqs[1], psycho_ue_intr, 0,
+ "PSYCHO_UE", pbm);
+ err = request_irq(op->irqs[2], psycho_ce_intr, 0,
+ "PSYCHO_CE", pbm);
+
+ /* This one, however, ought not to fail. We can just warn
+ * about it since the system can still operate properly even
+ * if this fails.
+ */
+ err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
+ "PSYCHO_PCIERR", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register PCIERR, "
+ "err=%d\n", pbm->name, err);
/* Enable UE and CE interrupts for controller. */
psycho_write(base + PSYCHO_ECC_CTRL,
@@ -918,54 +917,45 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void pbm_scan_bus(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
+static void psycho_scan_bus(struct pci_pbm_info *pbm)
{
+ pbm_config_busmastering(pbm);
+ pbm->is_66mhz_capable = 0;
pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void psycho_scan_bus(struct pci_controller_info *p)
-{
- pbm_config_busmastering(&p->pbm_B);
- p->pbm_B.is_66mhz_capable = 0;
- pbm_config_busmastering(&p->pbm_A);
- p->pbm_A.is_66mhz_capable = 1;
- pbm_scan_bus(p, &p->pbm_B);
- pbm_scan_bus(p, &p->pbm_A);
/* After the PCI bus scan is complete, we can register
* the error interrupt handlers.
*/
- psycho_register_error_handlers(p);
+ psycho_register_error_handlers(pbm);
}
-static void psycho_iommu_init(struct pci_controller_info *p)
+static void psycho_iommu_init(struct pci_pbm_info *pbm)
{
- struct iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = pbm->iommu;
unsigned long i;
u64 control;
/* Register addresses. */
- iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
- iommu->iommu_tsbbase = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE;
- iommu->iommu_flush = p->pbm_A.controller_regs + PSYCHO_IOMMU_FLUSH;
+ 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;
/* 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 = p->pbm_A.controller_regs + PSYCHO_CONTROL;
+ iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
/*
* Invalidate TLB Entries.
*/
- control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
+ control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
control |= PSYCHO_IOMMU_CTRL_DENAB;
- psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
+ psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
for(i = 0; i < 16; i++) {
- psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
- psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
+ 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
@@ -973,17 +963,17 @@ static void psycho_iommu_init(struct pci_controller_info *p)
*/
pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
- psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE,
+ psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
__pa(iommu->page_table));
- control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL);
+ 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(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control);
+ psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
/* If necessary, hook us up for starfire IRQ translations. */
if (this_is_starfire)
- starfire_hookup(p->pbm_A.portid);
+ starfire_hookup(pbm->portid);
}
#define PSYCHO_IRQ_RETRY 0x1a00UL
@@ -998,36 +988,35 @@ static void psycho_iommu_init(struct pci_controller_info *p)
#define PSYCHO_PCIDIAG_IPAPAR 0x0000000000000002UL /* Invert PIO address parity */
#define PSYCHO_PCIDIAG_LPBACK 0x0000000000000001UL /* Enable loopback mode */
-static void psycho_controller_hwinit(struct pci_controller_info *p)
+static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
{
u64 tmp;
- psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 5);
+ psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
/* Enable arbiter for all PCI slots. */
- tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL);
+ tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
tmp |= PSYCHO_PCICTRL_AEN;
- psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL, tmp);
+ psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
- tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL);
+ tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
tmp |= PSYCHO_PCICTRL_AEN;
- psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_CTRL, tmp);
+ psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
/* Disable DMA write / PIO read synchronization on
* both PCI bus segments.
* [ U2P Erratum 1243770, STP2223BGA data sheet ]
*/
- tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG);
+ tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIA_DIAG, tmp);
+ psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
- tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG);
+ tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
tmp |= PSYCHO_PCIDIAG_DDWSYNC;
- psycho_write(p->pbm_A.controller_regs + PSYCHO_PCIB_DIAG, tmp);
+ psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
}
-static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
- struct pci_pbm_info *pbm,
+static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
int is_pbm_a)
{
unsigned long base = pbm->controller_regs;
@@ -1088,7 +1077,6 @@ static void psycho_pbm_strbuf_init(struct pci_controller_info *p,
static void psycho_pbm_init(struct pci_controller_info *p,
struct device_node *dp, int is_pbm_a)
{
- unsigned int *busrange;
struct property *prop;
struct pci_pbm_info *pbm;
@@ -1097,6 +1085,14 @@ static void psycho_pbm_init(struct pci_controller_info *p,
else
pbm = &p->pbm_B;
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ pbm->scan_bus = psycho_scan_bus;
+ pbm->pci_ops = &psycho_ops;
+
+ pbm->index = pci_num_pbms++;
+
pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
pbm->chip_version = 0;
prop = of_find_property(dp, "version#", NULL);
@@ -1117,12 +1113,9 @@ static void psycho_pbm_init(struct pci_controller_info *p,
pci_determine_mem_io_space(pbm);
- prop = of_find_property(dp, "bus-range", NULL);
- busrange = prop->value;
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
+ pci_get_pbm_props(pbm);
- psycho_pbm_strbuf_init(p, pbm, is_pbm_a);
+ psycho_pbm_strbuf_init(pbm, is_pbm_a);
}
#define PSYCHO_CONFIGSPACE 0x001000000UL
@@ -1131,6 +1124,7 @@ void psycho_init(struct device_node *dp, char *model_name)
{
struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
struct iommu *iommu;
struct property *prop;
u32 upa_portid;
@@ -1141,7 +1135,9 @@ void psycho_init(struct device_node *dp, char *model_name)
if (prop)
upa_portid = *(u32 *) prop->value;
- for(p = pci_controller_root; p; p = p->next) {
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+ struct pci_controller_info *p = pbm->parent;
+
if (p->pbm_A.portid == upa_portid) {
is_pbm_a = (p->pbm_A.prom_node == NULL);
psycho_pbm_init(p, dp, is_pbm_a);
@@ -1161,14 +1157,8 @@ void psycho_init(struct device_node *dp, char *model_name)
}
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
- p->next = pci_controller_root;
- pci_controller_root = p;
-
p->pbm_A.portid = upa_portid;
p->pbm_B.portid = upa_portid;
- p->index = pci_num_controllers++;
- p->scan_bus = psycho_scan_bus;
- p->pci_ops = &psycho_ops;
prop = of_find_property(dp, "reg", NULL);
pr_regs = prop->value;
@@ -1185,9 +1175,9 @@ void psycho_init(struct device_node *dp, char *model_name)
*/
pci_memspace_mask = 0x7fffffffUL;
- psycho_controller_hwinit(p);
+ psycho_controller_hwinit(&p->pbm_A);
- psycho_iommu_init(p);
+ psycho_iommu_init(&p->pbm_A);
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
psycho_pbm_init(p, dp, is_pbm_a);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 397862fbd9e..4cefe6e83b2 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -13,12 +13,12 @@
#include <linux/interrupt.h>
#include <asm/apb.h>
-#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/smp.h>
#include <asm/oplib.h>
#include <asm/prom.h>
+#include <asm/of_device.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -494,11 +494,11 @@ static struct pci_ops sabre_ops = {
};
/* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_controller_info *p,
+static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
unsigned long afsr,
unsigned long afar)
{
- struct iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = pbm->iommu;
unsigned long iommu_tag[16];
unsigned long iommu_data[16];
unsigned long flags;
@@ -526,8 +526,8 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
type_string = "Unknown";
break;
};
- printk("SABRE%d: IOMMU Error, type[%s]\n",
- p->index, type_string);
+ printk("%s: IOMMU Error, type[%s]\n",
+ pbm->name, type_string);
/* Enter diagnostic mode and probe for error'd
* entries in the IOTLB.
@@ -536,7 +536,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
sabre_write(iommu->iommu_control,
(control | SABRE_IOMMUCTRL_DENAB));
for (i = 0; i < 16; i++) {
- unsigned long base = p->pbm_A.controller_regs;
+ unsigned long base = pbm->controller_regs;
iommu_tag[i] =
sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
@@ -566,13 +566,13 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
type_string = "Unknown";
break;
};
- printk("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
- p->index, i, tag, type_string,
+ 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("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
- p->index, i, data,
+ 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),
@@ -584,9 +584,9 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;
- unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
+ struct pci_pbm_info *pbm = dev_id;
+ unsigned long afsr_reg = pbm->controller_regs + SABRE_UE_AFSR;
+ unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
unsigned long afsr, afar, error_bits;
int reported;
@@ -604,21 +604,21 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
sabre_write(afsr_reg, error_bits);
/* Log the error. */
- printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n",
- p->index,
+ printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
+ pbm->name,
((error_bits & SABRE_UEAFSR_PDRD) ?
"DMA Read" :
((error_bits & SABRE_UEAFSR_PDWR) ?
"DMA Write" : "???")),
((error_bits & SABRE_UEAFSR_PDTE) ?
":Translation Error" : ""));
- printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
- p->index,
+ printk("%s: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",
+ pbm->name,
(afsr & SABRE_UEAFSR_BMSK) >> 32UL,
(afsr & SABRE_UEAFSR_OFF) >> 29UL,
((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));
- printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar);
- printk("SABRE%d: UE Secondary errors [", p->index);
+ printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: UE Secondary errors [", pbm->name);
reported = 0;
if (afsr & SABRE_UEAFSR_SDRD) {
reported++;
@@ -637,16 +637,16 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
printk("]\n");
/* Interrogate IOMMU for error status. */
- sabre_check_iommu_error(p, afsr, afar);
+ sabre_check_iommu_error(pbm, afsr, afar);
return IRQ_HANDLED;
}
static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;
- unsigned long afar_reg = p->pbm_A.controller_regs + SABRE_UECE_AFAR;
+ struct pci_pbm_info *pbm = dev_id;
+ unsigned long afsr_reg = pbm->controller_regs + SABRE_CE_AFSR;
+ unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;
unsigned long afsr, afar, error_bits;
int reported;
@@ -663,8 +663,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
sabre_write(afsr_reg, error_bits);
/* Log the error. */
- printk("SABRE%d: Correctable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Correctable Error, primary error type[%s]\n",
+ pbm->name,
((error_bits & SABRE_CEAFSR_PDRD) ?
"DMA Read" :
((error_bits & SABRE_CEAFSR_PDWR) ?
@@ -673,15 +673,15 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
/* XXX Use syndrome and afar to print out module string just like
* XXX UDB CE trap handler does... -DaveM
*/
- printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
+ printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "
"was_block(%d)\n",
- p->index,
+ pbm->name,
(afsr & SABRE_CEAFSR_ESYND) >> 48UL,
(afsr & SABRE_CEAFSR_BMSK) >> 32UL,
(afsr & SABRE_CEAFSR_OFF) >> 29UL,
((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));
- printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar);
- printk("SABRE%d: CE Secondary errors [", p->index);
+ printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: CE Secondary errors [", pbm->name);
reported = 0;
if (afsr & SABRE_CEAFSR_SDRD) {
reported++;
@@ -698,13 +698,13 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
+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 = p->pbm_A.controller_regs + SABRE_PCICTRL;
+ csr_reg = pbm->controller_regs + SABRE_PCICTRL;
csr = sabre_read(csr_reg);
csr_error_bits =
csr & SABRE_PCICTRL_SERR;
@@ -714,8 +714,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
/* Log 'em. */
if (csr_error_bits & SABRE_PCICTRL_SERR)
- printk("SABRE%d: PCI SERR signal asserted.\n",
- p->index);
+ printk("%s: PCI SERR signal asserted.\n",
+ pbm->name);
ret = IRQ_HANDLED;
}
pci_bus_read_config_word(sabre_root_bus, 0,
@@ -725,8 +725,8 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
PCI_STATUS_REC_TARGET_ABORT |
PCI_STATUS_REC_MASTER_ABORT |
PCI_STATUS_SIG_SYSTEM_ERROR)) {
- printk("SABRE%d: PCI bus error, PCI_STATUS[%04x]\n",
- p->index, stat);
+ 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;
@@ -736,13 +736,13 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = 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 = p->pbm_A.controller_regs + SABRE_PIOAFSR;
- afar_reg = p->pbm_A.controller_regs + SABRE_PIOAFAR;
+ afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
+ afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
/* Latch error status. */
afar = sabre_read(afar_reg);
@@ -755,12 +755,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
if (!error_bits)
- return sabre_pcierr_intr_other(p);
+ return sabre_pcierr_intr_other(pbm);
sabre_write(afsr_reg, error_bits);
/* Log the error. */
- printk("SABRE%d: PCI Error, primary error type[%s]\n",
- p->index,
+ printk("%s: PCI Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & SABRE_PIOAFSR_PMA) ?
"Master Abort" :
((error_bits & SABRE_PIOAFSR_PTA) ?
@@ -769,12 +769,12 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
"Excessive Retries" :
((error_bits & SABRE_PIOAFSR_PPERR) ?
"Parity Error" : "???"))))));
- printk("SABRE%d: bytemask[%04lx] was_block(%d)\n",
- p->index,
+ printk("%s: bytemask[%04lx] was_block(%d)\n",
+ pbm->name,
(afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
(afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
- printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar);
- printk("SABRE%d: PCI Secondary errors [", p->index);
+ printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: PCI Secondary errors [", pbm->name);
reported = 0;
if (afsr & SABRE_PIOAFSR_SMA) {
reported++;
@@ -806,11 +806,11 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
* 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(p, afsr, afar);
- pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);
+ 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(p, &p->pbm_A, p->pbm_A.pci_bus);
+ 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
@@ -820,18 +820,18 @@ static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
*/
if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
- pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);
+ pci_scan_for_parity_error(pbm, pbm->pci_bus);
return IRQ_HANDLED;
}
-static void sabre_register_error_handlers(struct pci_controller_info *p)
+static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */
struct device_node *dp = pbm->prom_node;
struct of_device *op;
unsigned long base = pbm->controller_regs;
u64 tmp;
+ int err;
if (pbm->chip_type == PBM_CHIP_TYPE_SABRE)
dp = dp->parent;
@@ -858,22 +858,31 @@ static void sabre_register_error_handlers(struct pci_controller_info *p)
SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
- request_irq(op->irqs[1], sabre_ue_intr, IRQF_SHARED, "SABRE UE", p);
+ 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));
- request_irq(op->irqs[2], sabre_ce_intr, IRQF_SHARED, "SABRE CE", p);
- request_irq(op->irqs[0], sabre_pcierr_intr, IRQF_SHARED,
- "SABRE PCIERR", p);
+ 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,
+ "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 |= SABRE_PCICTRL_ERREN;
sabre_write(base + SABRE_PCICTRL, tmp);
}
-static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
+static void apb_init(struct pci_bus *sabre_bus)
{
struct pci_dev *pdev;
@@ -909,7 +918,7 @@ static void apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus)
}
}
-static void sabre_scan_bus(struct pci_controller_info *p)
+static void sabre_scan_bus(struct pci_pbm_info *pbm)
{
static int once;
struct pci_bus *pbus;
@@ -918,7 +927,7 @@ static void sabre_scan_bus(struct pci_controller_info *p)
* at 66Mhz, but the front side of APB runs at 33Mhz
* for both segments.
*/
- p->pbm_A.is_66mhz_capable = 0;
+ pbm->is_66mhz_capable = 0;
/* This driver has not been verified to handle
* multiple SABREs yet, so trap this.
@@ -932,41 +941,41 @@ static void sabre_scan_bus(struct pci_controller_info *p)
}
once++;
- pbus = pci_scan_one_pbm(&p->pbm_A);
+ pbus = pci_scan_one_pbm(pbm);
if (!pbus)
return;
sabre_root_bus = pbus;
- apb_init(p, pbus);
+ apb_init(pbus);
- sabre_register_error_handlers(p);
+ sabre_register_error_handlers(pbm);
}
-static void sabre_iommu_init(struct pci_controller_info *p,
+static void sabre_iommu_init(struct pci_pbm_info *pbm,
int tsbsize, unsigned long dvma_offset,
u32 dma_mask)
{
- struct iommu *iommu = p->pbm_A.iommu;
+ struct iommu *iommu = pbm->iommu;
unsigned long i;
u64 control;
/* Register addresses. */
- iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
- iommu->iommu_tsbbase = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE;
- iommu->iommu_flush = p->pbm_A.controller_regs + SABRE_IOMMU_FLUSH;
- iommu->write_complete_reg = p->pbm_A.controller_regs + SABRE_WRSYNC;
+ 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->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
/* Sabre's IOMMU lacks ctx flushing. */
iommu->iommu_ctxflush = 0;
/* Invalidate TLB Entries. */
- control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
+ control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
control |= SABRE_IOMMUCTRL_DENAB;
- sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
+ sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
for(i = 0; i < 16; i++) {
- sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
- sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
+ 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
@@ -974,10 +983,10 @@ static void sabre_iommu_init(struct pci_controller_info *p,
*/
pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask);
- sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE,
+ sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
__pa(iommu->page_table));
- control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL);
+ control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
control |= SABRE_IOMMUCTRL_ENAB;
switch(tsbsize) {
@@ -992,22 +1001,23 @@ static void sabre_iommu_init(struct pci_controller_info *p,
prom_halt();
break;
}
- sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control);
+ sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
}
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp)
+static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
{
- struct pci_pbm_info *pbm;
-
- pbm = &p->pbm_A;
pbm->name = dp->full_name;
printk("%s: SABRE PCI Bus Module\n", pbm->name);
+ pbm->scan_bus = sabre_scan_bus;
+ pbm->pci_ops = &sabre_ops;
+
+ pbm->index = pci_num_pbms++;
+
pbm->chip_type = PBM_CHIP_TYPE_SABRE;
pbm->parent = p;
pbm->prom_node = dp;
- pbm->pci_first_busno = p->pci_first_busno;
- pbm->pci_last_busno = p->pci_last_busno;
+ pci_get_pbm_props(pbm);
pci_determine_mem_io_space(pbm);
}
@@ -1016,9 +1026,9 @@ void sabre_init(struct device_node *dp, char *model_name)
{
const struct linux_prom64_registers *pr_regs;
struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
struct iommu *iommu;
int tsbsize;
- const u32 *busrange;
const u32 *vdma;
u32 upa_portid, dma_mask;
u64 clear_irq;
@@ -1053,17 +1063,15 @@ void sabre_init(struct device_node *dp, char *model_name)
prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
prom_halt();
}
- p->pbm_A.iommu = iommu;
+ pbm = &p->pbm_A;
+ pbm->iommu = iommu;
upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
- p->next = pci_controller_root;
- pci_controller_root = p;
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
- p->pbm_A.portid = upa_portid;
- p->index = pci_num_controllers++;
- p->scan_bus = sabre_scan_bus;
- p->pci_ops = &sabre_ops;
+ pbm->portid = upa_portid;
/*
* Map in SABRE register set and report the presence of this SABRE.
@@ -1074,26 +1082,26 @@ void sabre_init(struct device_node *dp, char *model_name)
/*
* First REG in property is base of entire SABRE register space.
*/
- p->pbm_A.controller_regs = pr_regs[0].phys_addr;
+ pbm->controller_regs = pr_regs[0].phys_addr;
/* Clear interrupts */
/* PCI first */
for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
- sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
+ sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
/* Then OBIO */
for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
- sabre_write(p->pbm_A.controller_regs + clear_irq, 0x0UL);
+ sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
/* Error interrupts are enabled later after the bus scan. */
- sabre_write(p->pbm_A.controller_regs + SABRE_PCICTRL,
+ sabre_write(pbm->controller_regs + SABRE_PCICTRL,
(SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR |
SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
/* Now map in PCI config space for entire SABRE. */
- p->pbm_A.config_space =
- (p->pbm_A.controller_regs + SABRE_CONFIGSPACE);
+ pbm->config_space =
+ (pbm->controller_regs + SABRE_CONFIGSPACE);
vdma = of_get_property(dp, "virtual-dma", NULL);
@@ -1117,14 +1125,10 @@ void sabre_init(struct device_node *dp, char *model_name)
prom_halt();
}
- sabre_iommu_init(p, tsbsize, vdma[0], dma_mask);
-
- busrange = of_get_property(dp, "bus-range", NULL);
- p->pci_first_busno = busrange[0];
- p->pci_last_busno = busrange[1];
+ sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, dp);
+ sabre_pbm_init(p, pbm, dp);
}
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 91a7385e5d3..e375d72b8ee 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -10,12 +10,13 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/upa.h>
#include <asm/pstate.h>
#include <asm/prom.h>
+#include <asm/of_device.h>
+#include <asm/oplib.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -238,25 +239,6 @@ static unsigned long stc_line_buf[16];
#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */
#define SCHIZO_SERR_INO 0x34 /* Safari interface error */
-struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino)
-{
- ino &= IMAP_INO;
- if (p->pbm_A.ino_bitmap & (1UL << ino))
- return &p->pbm_A;
- if (p->pbm_B.ino_bitmap & (1UL << ino))
- return &p->pbm_B;
-
- printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps "
- "PBM_A[%016lx] PBM_B[%016lx]",
- p->index, ino,
- p->pbm_A.ino_bitmap,
- p->pbm_B.ino_bitmap);
- printk("PCI%d: Using PBM_A, report this problem immediately.\n",
- p->index);
-
- return &p->pbm_A;
-}
-
#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */
#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */
#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */
@@ -522,9 +504,10 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR;
- unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR;
+ 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;
@@ -549,28 +532,28 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
schizo_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PCI%d: Uncorrectable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Uncorrectable Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & SCHIZO_UEAFSR_PPIO) ?
"PIO" :
((error_bits & SCHIZO_UEAFSR_PDRD) ?
"DMA Read" :
((error_bits & SCHIZO_UEAFSR_PDWR) ?
"DMA Write" : "???")))));
- printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
- p->index,
+ printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
(afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
(afsr & SCHIZO_UEAFSR_AID) >> 24UL);
- printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
- p->index,
+ printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
(afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
(afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
- printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar);
- printk("PCI%d: UE Secondary errors [", p->index);
+ printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: UE Secondary errors [", pbm->name);
reported = 0;
if (afsr & SCHIZO_UEAFSR_SPIO) {
reported++;
@@ -610,9 +593,9 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
- unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR;
- unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR;
+ struct pci_pbm_info *pbm = dev_id;
+ unsigned long afsr_reg = pbm->controller_regs + SCHIZO_CE_AFSR;
+ unsigned long afar_reg = pbm->controller_regs + SCHIZO_CE_AFAR;
unsigned long afsr, afar, error_bits;
int reported, limit;
@@ -637,8 +620,8 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
schizo_write(afsr_reg, error_bits);
/* Log the error. */
- printk("PCI%d: Correctable Error, primary error type[%s]\n",
- p->index,
+ printk("%s: Correctable Error, primary error type[%s]\n",
+ pbm->name,
(((error_bits & SCHIZO_CEAFSR_PPIO) ?
"PIO" :
((error_bits & SCHIZO_CEAFSR_PDRD) ?
@@ -649,20 +632,20 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
/* XXX Use syndrome and afar to print out module string just like
* XXX UDB CE trap handler does... -DaveM
*/
- printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
- p->index,
+ printk("%s: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_BMSK) >> 32UL,
(afsr & SCHIZO_UEAFSR_QOFF) >> 30UL,
(afsr & SCHIZO_UEAFSR_AID) >> 24UL);
- printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
- p->index,
+ printk("%s: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n",
+ pbm->name,
(afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0,
(afsr & SCHIZO_UEAFSR_MTAG) >> 13UL,
(afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL,
(afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL);
- printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar);
- printk("PCI%d: CE Secondary errors [", p->index);
+ printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);
+ printk("%s: CE Secondary errors [", pbm->name);
reported = 0;
if (afsr & SCHIZO_CEAFSR_SPIO) {
reported++;
@@ -881,10 +864,10 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
*/
if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
schizo_check_iommu_error(p, PCI_ERR);
- pci_scan_for_target_abort(p, pbm, pbm->pci_bus);
+ pci_scan_for_target_abort(pbm, pbm->pci_bus);
}
if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
- pci_scan_for_master_abort(p, pbm, pbm->pci_bus);
+ 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
@@ -894,7 +877,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
*/
if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR))
- pci_scan_for_parity_error(p, pbm, pbm->pci_bus);
+ pci_scan_for_parity_error(pbm, pbm->pci_bus);
return IRQ_HANDLED;
}
@@ -940,22 +923,23 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
*/
static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
{
- struct pci_controller_info *p = dev_id;
+ struct pci_pbm_info *pbm = dev_id;
+ struct pci_controller_info *p = pbm->parent;
u64 errlog;
- errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG);
- schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG,
+ errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
errlog & ~(SAFARI_ERRLOG_ERROUT));
if (!(errlog & BUS_ERROR_UNMAP)) {
- printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
- p->index, errlog);
+ printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
+ pbm->name, errlog);
return IRQ_HANDLED;
}
- printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
- p->index);
+ printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
+ pbm->name);
schizo_check_iommu_error(p, SAFARI_ERR);
return IRQ_HANDLED;
@@ -972,6 +956,16 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
#define SCHIZO_SAFARI_IRQCTRL 0x10010UL
#define SCHIZO_SAFIRQCTRL_EN 0x8000000000000000UL
+static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
+{
+ ino &= IMAP_INO;
+
+ if (pbm->ino_bitmap & (1UL << ino))
+ return 1;
+
+ return 0;
+}
+
/* How the Tomatillo IRQs are routed around is pure guesswork here.
*
* All the Tomatillo devices I see in prtconf dumps seem to have only
@@ -986,11 +980,11 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
* PCI bus units of the same Tomatillo. I still have not really
* figured this out...
*/
-static void tomatillo_register_error_handlers(struct pci_controller_info *p)
+static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct pci_pbm_info *pbm;
- struct of_device *op;
+ struct of_device *op = of_find_device_by_node(pbm->prom_node);
u64 tmp, err_mask, err_no_mask;
+ int err;
/* Tomatillo IRQ property layout is:
* 0: PCIERR
@@ -1000,44 +994,42 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
* 4: POWER FAIL?
*/
- pbm = pbm_for_ino(p, SCHIZO_UE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
- "TOMATILLO_UE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_CE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
- "TOMATILLO CE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "TOMATILLO PCIERR-A", pbm);
-
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "TOMATILLO PCIERR-B", pbm);
-
- pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
- "TOMATILLO SERR", p);
+ if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+ err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+ "TOMATILLO_UE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register UE, "
+ "err=%d\n", pbm->name, err);
+ }
+ if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+ err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+ "TOMATILLO_CE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register CE, "
+ "err=%d\n", pbm->name, err);
+ }
+ err = 0;
+ if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "TOMATILLO_PCIERR", pbm);
+ } else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "TOMATILLO_PCIERR", pbm);
+ }
+ if (err)
+ printk(KERN_WARNING "%s: Could not register PCIERR, "
+ "err=%d\n", pbm->name, err);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+ err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ "TOMATILLO_SERR", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register SERR, "
+ "err=%d\n", pbm->name, err);
+ }
/* Enable UE and CE interrupts for controller. */
- schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
- (SCHIZO_ECCCTRL_EE |
- SCHIZO_ECCCTRL_UE |
- SCHIZO_ECCCTRL_CE));
-
- schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
(SCHIZO_ECCCTRL_EE |
SCHIZO_ECCCTRL_UE |
SCHIZO_ECCCTRL_CE));
@@ -1053,15 +1045,10 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
- tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
- tmp |= err_mask;
- tmp &= ~err_no_mask;
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
- tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -1070,8 +1057,7 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
SCHIZO_PCIAFSR_STTO);
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -1083,22 +1069,18 @@ static void tomatillo_register_error_handlers(struct pci_controller_info *p)
BUS_ERROR_APERR | BUS_ERROR_UNMAP |
BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
- (SCHIZO_SAFERRCTRL_EN | err_mask));
- schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
(SCHIZO_SAFERRCTRL_EN | err_mask));
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
- (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
- schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
(SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
}
-static void schizo_register_error_handlers(struct pci_controller_info *p)
+static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
{
- struct pci_pbm_info *pbm;
- struct of_device *op;
+ struct of_device *op = of_find_device_by_node(pbm->prom_node);
u64 tmp, err_mask, err_no_mask;
+ int err;
/* Schizo IRQ property layout is:
* 0: PCIERR
@@ -1108,39 +1090,42 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
* 4: POWER FAIL?
*/
- pbm = pbm_for_ino(p, SCHIZO_UE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED,
- "SCHIZO_UE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_CE_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED,
- "SCHIZO CE", p);
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "SCHIZO PCIERR-A", pbm);
-
-
- pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED,
- "SCHIZO PCIERR-B", pbm);
-
- pbm = pbm_for_ino(p, SCHIZO_SERR_INO);
- op = of_find_device_by_node(pbm->prom_node);
- if (op)
- request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED,
- "SCHIZO SERR", p);
+ if (pbm_routes_this_ino(pbm, SCHIZO_UE_INO)) {
+ err = request_irq(op->irqs[1], schizo_ue_intr, 0,
+ "SCHIZO_UE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register UE, "
+ "err=%d\n", pbm->name, err);
+ }
+ if (pbm_routes_this_ino(pbm, SCHIZO_CE_INO)) {
+ err = request_irq(op->irqs[2], schizo_ce_intr, 0,
+ "SCHIZO_CE", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register CE, "
+ "err=%d\n", pbm->name, err);
+ }
+ err = 0;
+ if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_A_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "SCHIZO_PCIERR", pbm);
+ } else if (pbm_routes_this_ino(pbm, SCHIZO_PCIERR_B_INO)) {
+ err = request_irq(op->irqs[0], schizo_pcierr_intr, 0,
+ "SCHIZO_PCIERR", pbm);
+ }
+ if (err)
+ printk(KERN_WARNING "%s: Could not register PCIERR, "
+ "err=%d\n", pbm->name, err);
+
+ if (pbm_routes_this_ino(pbm, SCHIZO_SERR_INO)) {
+ err = request_irq(op->irqs[3], schizo_safarierr_intr, 0,
+ "SCHIZO_SERR", pbm);
+ if (err)
+ printk(KERN_WARNING "%s: Could not register SERR, "
+ "err=%d\n", pbm->name, err);
+ }
/* Enable UE and CE interrupts for controller. */
- schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
(SCHIZO_ECCCTRL_EE |
SCHIZO_ECCCTRL_UE |
SCHIZO_ECCCTRL_CE));
@@ -1159,25 +1144,12 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
/* Enable PCI Error interrupts and clear error
* bits for each PBM.
*/
- tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL);
- tmp |= err_mask;
- tmp &= ~err_no_mask;
- schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp);
-
- schizo_write(p->pbm_A.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));
-
- tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL);
+ tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
tmp |= err_mask;
tmp &= ~err_no_mask;
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
- schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR,
+ 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 |
@@ -1210,11 +1182,8 @@ static void schizo_register_error_handlers(struct pci_controller_info *p)
BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
#endif
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL,
+ schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
(SCHIZO_SAFERRCTRL_EN | err_mask));
-
- schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL,
- (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
}
static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1234,27 +1203,19 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
pci_config_write8(addr, 64);
}
-static void schizo_scan_bus(struct pci_controller_info *p)
+static void schizo_scan_bus(struct pci_pbm_info *pbm)
{
- pbm_config_busmastering(&p->pbm_B);
- p->pbm_B.is_66mhz_capable =
- (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL)
- != NULL);
- pbm_config_busmastering(&p->pbm_A);
- p->pbm_A.is_66mhz_capable =
- (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL)
+ pbm_config_busmastering(pbm);
+ pbm->is_66mhz_capable =
+ (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
!= NULL);
- p->pbm_B.pci_bus = pci_scan_one_pbm(&p->pbm_B);
- p->pbm_A.pci_bus = pci_scan_one_pbm(&p->pbm_A);
+ pbm->pci_bus = pci_scan_one_pbm(pbm);
- /* After the PCI bus scan is complete, we can register
- * the error interrupt handlers.
- */
- if (p->pbm_B.chip_type == PBM_CHIP_TYPE_TOMATILLO)
- tomatillo_register_error_handlers(p);
+ if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
+ tomatillo_register_error_handlers(pbm);
else
- schizo_register_error_handlers(p);
+ schizo_register_error_handlers(pbm);
}
#define SCHIZO_STRBUF_CONTROL (0x02800UL)
@@ -1491,10 +1452,8 @@ static void schizo_pbm_init(struct pci_controller_info *p,
int chip_type)
{
const struct linux_prom64_registers *regs;
- const unsigned int *busrange;
struct pci_pbm_info *pbm;
const char *chipset_name;
- const u32 *ino_bitmap;
int is_pbm_a;
switch (chip_type) {
@@ -1531,6 +1490,14 @@ static void schizo_pbm_init(struct pci_controller_info *p,
else
pbm = &p->pbm_B;
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ pbm->scan_bus = schizo_scan_bus;
+ pbm->pci_ops = &schizo_ops;
+
+ pbm->index = pci_num_pbms++;
+
pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = dp;
@@ -1555,13 +1522,7 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pci_determine_mem_io_space(pbm);
- ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
- pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
- ((u64)ino_bitmap[0] << 0UL));
-
- busrange = of_get_property(dp, "bus-range", NULL);
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
+ pci_get_pbm_props(pbm);
schizo_pbm_iommu_init(pbm);
schizo_pbm_strbuf_init(pbm);
@@ -1580,23 +1541,15 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
static void __schizo_init(struct device_node *dp, char *model_name, int chip_type)
{
struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
struct iommu *iommu;
u32 portid;
portid = of_getintprop_default(dp, "portid", 0xff);
- for (p = pci_controller_root; p; p = p->next) {
- struct pci_pbm_info *pbm;
-
- if (p->pbm_A.prom_node && p->pbm_B.prom_node)
- continue;
-
- pbm = (p->pbm_A.prom_node ?
- &p->pbm_A :
- &p->pbm_B);
-
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid, chip_type)) {
- schizo_pbm_init(p, dp, portid, chip_type);
+ schizo_pbm_init(pbm->parent, dp, portid, chip_type);
return;
}
}
@@ -1617,13 +1570,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
p->pbm_B.iommu = iommu;
- p->next = pci_controller_root;
- pci_controller_root = p;
-
- p->index = pci_num_controllers++;
- p->scan_bus = schizo_scan_bus;
- p->pci_ops = &schizo_ops;
-
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 94295c21932..0c76a8891a9 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -13,7 +13,6 @@
#include <linux/irq.h>
#include <linux/msi.h>
-#include <asm/pbm.h>
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/upa.h>
@@ -677,29 +676,15 @@ static struct pci_ops pci_sun4v_ops = {
};
-static void pbm_scan_bus(struct pci_controller_info *p,
- struct pci_pbm_info *pbm)
-{
- pbm->pci_bus = pci_scan_one_pbm(pbm);
-}
-
-static void pci_sun4v_scan_bus(struct pci_controller_info *p)
+static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
{
struct property *prop;
struct device_node *dp;
- if ((dp = p->pbm_A.prom_node) != NULL) {
- prop = of_find_property(dp, "66mhz-capable", NULL);
- p->pbm_A.is_66mhz_capable = (prop != NULL);
-
- pbm_scan_bus(p, &p->pbm_A);
- }
- if ((dp = p->pbm_B.prom_node) != NULL) {
- prop = of_find_property(dp, "66mhz-capable", NULL);
- p->pbm_B.is_66mhz_capable = (prop != NULL);
-
- pbm_scan_bus(p, &p->pbm_B);
- }
+ dp = pbm->prom_node;
+ prop = of_find_property(dp, "66mhz-capable", NULL);
+ pbm->is_66mhz_capable = (prop != NULL);
+ pbm->pci_bus = pci_scan_one_pbm(pbm);
/* XXX register error interrupt handlers XXX */
}
@@ -802,20 +787,6 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
pbm->name, sz);
}
-static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm)
-{
- struct property *prop;
- unsigned int *busrange;
-
- prop = of_find_property(pbm->prom_node, "bus-range", NULL);
-
- busrange = prop->value;
-
- pbm->pci_first_busno = busrange[0];
- pbm->pci_last_busno = busrange[1];
-
-}
-
#ifdef CONFIG_PCI_MSI
struct pci_sun4v_msiq_entry {
u64 version_type;
@@ -1019,114 +990,6 @@ h_error:
return -EINVAL;
}
-static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
-{
- const u32 *val;
- int len;
-
- val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
- if (!val || len != 4)
- goto no_msi;
- pbm->msiq_num = *val;
- if (pbm->msiq_num) {
- const struct msiq_prop {
- u32 first_msiq;
- u32 num_msiq;
- u32 first_devino;
- } *mqp;
- const struct msi_range_prop {
- u32 first_msi;
- u32 num_msi;
- } *mrng;
- const struct addr_range_prop {
- u32 msi32_high;
- u32 msi32_low;
- u32 msi32_len;
- u32 msi64_high;
- u32 msi64_low;
- u32 msi64_len;
- } *arng;
-
- val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
- if (!val || len != 4)
- goto no_msi;
-
- pbm->msiq_ent_count = *val;
-
- mqp = of_get_property(pbm->prom_node,
- "msi-eq-to-devino", &len);
- if (!mqp || len != sizeof(struct msiq_prop))
- goto no_msi;
-
- pbm->msiq_first = mqp->first_msiq;
- pbm->msiq_first_devino = mqp->first_devino;
-
- val = of_get_property(pbm->prom_node, "#msi", &len);
- if (!val || len != 4)
- goto no_msi;
- pbm->msi_num = *val;
-
- mrng = of_get_property(pbm->prom_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);
- if (!val || len != 4)
- goto no_msi;
- pbm->msi_data_mask = *val;
-
- val = of_get_property(pbm->prom_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",
- &len);
- if (!arng || len != sizeof(struct addr_range_prop))
- goto no_msi;
- pbm->msi32_start = ((u64)arng->msi32_high << 32) |
- (u64) arng->msi32_low;
- pbm->msi64_start = ((u64)arng->msi64_high << 32) |
- (u64) arng->msi64_low;
- pbm->msi32_len = arng->msi32_len;
- pbm->msi64_len = arng->msi64_len;
-
- if (msi_bitmap_alloc(pbm))
- goto no_msi;
-
- if (msi_queue_alloc(pbm)) {
- msi_bitmap_free(pbm);
- goto no_msi;
- }
-
- printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
- "devino[0x%x]\n",
- pbm->name,
- pbm->msiq_first, pbm->msiq_num,
- pbm->msiq_ent_count,
- pbm->msiq_first_devino);
- printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
- "width[%u]\n",
- pbm->name,
- pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
- pbm->msix_data_width);
- printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
- "addr64[0x%lx:0x%x]\n",
- pbm->name,
- pbm->msi32_start, pbm->msi32_len,
- pbm->msi64_start, pbm->msi64_len);
- printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
- pbm->name,
- pbm->msi_queues);
- }
-
- return;
-
-no_msi:
- pbm->msiq_num = 0;
- printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
-}
static int alloc_msi(struct pci_pbm_info *pbm)
{
@@ -1169,8 +1032,6 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
if (!devino)
goto out_err;
- set_irq_msi(*virt_irq_p, entry);
-
msiqid = ((devino - pbm->msiq_first_devino) +
pbm->msiq_first);
@@ -1204,6 +1065,8 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
msg.address_lo = pbm->msi32_start;
}
msg.data = msi_num;
+
+ set_irq_msi(*virt_irq_p, entry);
write_msi_msg(*virt_irq_p, &msg);
irq_install_pre_handler(*virt_irq_p,
@@ -1245,6 +1108,117 @@ static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
*/
sun4v_destroy_msi(virt_irq);
}
+
+static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
+{
+ const u32 *val;
+ int len;
+
+ val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msiq_num = *val;
+ if (pbm->msiq_num) {
+ const struct msiq_prop {
+ u32 first_msiq;
+ u32 num_msiq;
+ u32 first_devino;
+ } *mqp;
+ const struct msi_range_prop {
+ u32 first_msi;
+ u32 num_msi;
+ } *mrng;
+ const struct addr_range_prop {
+ u32 msi32_high;
+ u32 msi32_low;
+ u32 msi32_len;
+ u32 msi64_high;
+ u32 msi64_low;
+ u32 msi64_len;
+ } *arng;
+
+ val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+ if (!val || len != 4)
+ goto no_msi;
+
+ pbm->msiq_ent_count = *val;
+
+ mqp = of_get_property(pbm->prom_node,
+ "msi-eq-to-devino", &len);
+ if (!mqp || len != sizeof(struct msiq_prop))
+ goto no_msi;
+
+ pbm->msiq_first = mqp->first_msiq;
+ pbm->msiq_first_devino = mqp->first_devino;
+
+ val = of_get_property(pbm->prom_node, "#msi", &len);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msi_num = *val;
+
+ mrng = of_get_property(pbm->prom_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);
+ if (!val || len != 4)
+ goto no_msi;
+ pbm->msi_data_mask = *val;
+
+ val = of_get_property(pbm->prom_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",
+ &len);
+ if (!arng || len != sizeof(struct addr_range_prop))
+ goto no_msi;
+ pbm->msi32_start = ((u64)arng->msi32_high << 32) |
+ (u64) arng->msi32_low;
+ pbm->msi64_start = ((u64)arng->msi64_high << 32) |
+ (u64) arng->msi64_low;
+ pbm->msi32_len = arng->msi32_len;
+ pbm->msi64_len = arng->msi64_len;
+
+ if (msi_bitmap_alloc(pbm))
+ goto no_msi;
+
+ if (msi_queue_alloc(pbm)) {
+ msi_bitmap_free(pbm);
+ goto no_msi;
+ }
+
+ printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
+ "devino[0x%x]\n",
+ pbm->name,
+ pbm->msiq_first, pbm->msiq_num,
+ pbm->msiq_ent_count,
+ pbm->msiq_first_devino);
+ printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
+ "width[%u]\n",
+ pbm->name,
+ pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
+ pbm->msix_data_width);
+ printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
+ "addr64[0x%lx:0x%x]\n",
+ pbm->name,
+ pbm->msi32_start, pbm->msi32_len,
+ pbm->msi64_start, pbm->msi64_len);
+ printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
+ pbm->name,
+ pbm->msi_queues);
+ }
+ pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
+ pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
+
+ return;
+
+no_msi:
+ pbm->msiq_num = 0;
+ printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
+}
#else /* CONFIG_PCI_MSI */
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
{
@@ -1260,6 +1234,14 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
else
pbm = &p->pbm_A;
+ pbm->next = pci_pbm_root;
+ pci_pbm_root = pbm;
+
+ pbm->scan_bus = pci_sun4v_scan_bus;
+ pbm->pci_ops = &pci_sun4v_ops;
+
+ pbm->index = pci_num_pbms++;
+
pbm->parent = p;
pbm->prom_node = dp;
@@ -1271,7 +1253,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
pci_determine_mem_io_space(pbm);
- pci_sun4v_get_bus_range(pbm);
+ pci_get_pbm_props(pbm);
pci_sun4v_iommu_init(pbm);
pci_sun4v_msi_init(pbm);
}
@@ -1279,6 +1261,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
void sun4v_pci_init(struct device_node *dp, char *model_name)
{
struct pci_controller_info *p;
+ struct pci_pbm_info *pbm;
struct iommu *iommu;
struct property *prop;
struct linux_prom64_registers *regs;
@@ -1290,18 +1273,9 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
- for (p = pci_controller_root; p; p = p->next) {
- struct pci_pbm_info *pbm;
-
- if (p->pbm_A.prom_node && p->pbm_B.prom_node)
- continue;
-
- pbm = (p->pbm_A.prom_node ?
- &p->pbm_A :
- &p->pbm_B);
-
+ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (pbm->devhandle == (devhandle ^ 0x40)) {
- pci_sun4v_pbm_init(p, dp, devhandle);
+ pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
return;
}
}
@@ -1331,18 +1305,6 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
p->pbm_B.iommu = iommu;
- p->next = pci_controller_root;
- pci_controller_root = p;
-
- p->index = pci_num_controllers++;
-
- p->scan_bus = pci_sun4v_scan_bus;
-#ifdef CONFIG_PCI_MSI
- p->setup_msi_irq = pci_sun4v_setup_msi_irq;
- p->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
-#endif
- p->pci_ops = &pci_sun4v_ops;
-
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
* for memory space.
*/
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index a114151f9fb..8e3c6e43511 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -19,7 +19,6 @@
#include <linux/kallsyms.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 5e1fcd05160..c54d4d8af01 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -386,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp,
/* Now build the IRQ bucket. */
imap = controller_regs + imap_off;
- imap += 4;
iclr_off = psycho_iclr_offset(ino);
iclr = controller_regs + iclr_off;
- iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
@@ -398,7 +396,7 @@ static unsigned int psycho_irq_build(struct device_node *dp,
return build_irq(inofixup, iclr, imap);
}
-static void psycho_irq_trans_init(struct device_node *dp)
+static void __init psycho_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
@@ -613,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp,
/* Now build the IRQ bucket. */
imap = controller_regs + imap_off;
- imap += 4;
iclr_off = sabre_iclr_offset(ino);
iclr = controller_regs + iclr_off;
- iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
@@ -640,7 +636,7 @@ static unsigned int sabre_irq_build(struct device_node *dp,
return virt_irq;
}
-static void sabre_irq_trans_init(struct device_node *dp)
+static void __init sabre_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
struct sabre_irq_data *irq_data;
@@ -679,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino)
static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
unsigned int ino)
{
- return pbm_regs + schizo_iclr_offset(ino) + 4;
+
+ return pbm_regs + schizo_iclr_offset(ino);
}
static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
unsigned int ino)
{
- return pbm_regs + schizo_imap_offset(ino) + 4;
+ return pbm_regs + schizo_imap_offset(ino);
}
#define schizo_read(__reg) \
@@ -796,7 +793,8 @@ static unsigned int schizo_irq_build(struct device_node *dp,
return virt_irq;
}
-static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
+static void __init __schizo_irq_trans_init(struct device_node *dp,
+ int is_tomatillo)
{
const struct linux_prom64_registers *regs;
struct schizo_irq_data *irq_data;
@@ -818,12 +816,12 @@ static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
}
-static void schizo_irq_trans_init(struct device_node *dp)
+static void __init schizo_irq_trans_init(struct device_node *dp)
{
__schizo_irq_trans_init(dp, 0);
}
-static void tomatillo_irq_trans_init(struct device_node *dp)
+static void __init tomatillo_irq_trans_init(struct device_node *dp)
{
__schizo_irq_trans_init(dp, 1);
}
@@ -837,7 +835,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp,
return sun4v_build_irq(devhandle, devino);
}
-static void pci_sun4v_irq_trans_init(struct device_node *dp)
+static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
@@ -848,6 +846,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp)
dp->irq_trans->data = (void *) (unsigned long)
((regs->phys_addr >> 32UL) & 0x0fffffff);
}
+
+struct fire_irq_data {
+ unsigned long pbm_regs;
+ u32 portid;
+};
+
+#define FIRE_IMAP_BASE 0x001000
+#define FIRE_ICLR_BASE 0x001400
+
+static unsigned long fire_imap_offset(unsigned long ino)
+{
+ return FIRE_IMAP_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_iclr_offset(unsigned long ino)
+{
+ return FIRE_ICLR_BASE + (ino * 8UL);
+}
+
+static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
+ unsigned int ino)
+{
+ return pbm_regs + fire_iclr_offset(ino);
+}
+
+static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
+ unsigned int ino)
+{
+ return pbm_regs + fire_imap_offset(ino);
+}
+
+static unsigned int fire_irq_build(struct device_node *dp,
+ unsigned int ino,
+ void *_data)
+{
+ struct fire_irq_data *irq_data = _data;
+ unsigned long pbm_regs = irq_data->pbm_regs;
+ unsigned long imap, iclr;
+ unsigned long int_ctrlr;
+
+ ino &= 0x3f;
+
+ /* Now build the IRQ bucket. */
+ imap = fire_ino_to_imap(pbm_regs, ino);
+ iclr = fire_ino_to_iclr(pbm_regs, ino);
+
+ /* Set the interrupt controller number. */
+ int_ctrlr = 1 << 6;
+ upa_writeq(int_ctrlr, imap);
+
+ /* The interrupt map registers do not have an INO field
+ * like other chips do. They return zero in the INO
+ * field, and the interrupt controller number is controlled
+ * in bits 6 thru 9. So in order for build_irq() to get
+ * the INO right we pass it in as part of the fixup
+ * which will get added to the map register zero value
+ * read by build_irq().
+ */
+ ino |= (irq_data->portid << 6);
+ ino -= int_ctrlr;
+ return build_irq(ino, iclr, imap);
+}
+
+static void __init fire_irq_trans_init(struct device_node *dp)
+{
+ const struct linux_prom64_registers *regs;
+ struct fire_irq_data *irq_data;
+
+ dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
+ dp->irq_trans->irq_build = fire_irq_build;
+
+ irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
+
+ regs = of_get_property(dp, "reg", NULL);
+ dp->irq_trans->data = irq_data;
+
+ irq_data->pbm_regs = regs[0].phys_addr;
+ irq_data->portid = of_getintprop_default(dp, "portid", 0);
+}
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
@@ -995,7 +1072,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
return build_irq(sbus_level, iclr, imap);
}
-static void sbus_irq_trans_init(struct device_node *dp)
+static void __init sbus_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
@@ -1042,7 +1119,7 @@ static unsigned int central_build_irq(struct device_node *dp,
return build_irq(0, iclr, imap);
}
-static void central_irq_trans_init(struct device_node *dp)
+static void __init central_irq_trans_init(struct device_node *dp)
{
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = central_build_irq;
@@ -1056,7 +1133,7 @@ struct irq_trans {
};
#ifdef CONFIG_PCI
-static struct irq_trans pci_irq_trans_table[] = {
+static struct irq_trans __initdata pci_irq_trans_table[] = {
{ "SUNW,sabre", sabre_irq_trans_init },
{ "pci108e,a000", sabre_irq_trans_init },
{ "pci108e,a001", sabre_irq_trans_init },
@@ -1069,6 +1146,7 @@ static struct irq_trans pci_irq_trans_table[] = {
{ "SUNW,tomatillo", tomatillo_irq_trans_init },
{ "pci108e,a801", tomatillo_irq_trans_init },
{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
+ { "pciex108e,80f0", fire_irq_trans_init },
};
#endif
@@ -1081,7 +1159,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
return sun4v_build_irq(devhandle, devino);
}
-static void sun4v_vdev_irq_trans_init(struct device_node *dp)
+static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
@@ -1093,7 +1171,7 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
((regs->phys_addr >> 32UL) & 0x0fffffff);
}
-static void irq_trans_init(struct device_node *dp)
+static void __init irq_trans_init(struct device_node *dp)
{
#ifdef CONFIG_PCI
const char *model;
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index 3b05428cc90..91f6e2a74ad 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -1002,24 +1002,24 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
u64 control;
irq = sbus_build_irq(sbus, SYSIO_UE_INO);
- if (request_irq(irq, sysio_ue_handler,
- IRQF_SHARED, "SYSIO UE", sbus) < 0) {
+ if (request_irq(irq, sysio_ue_handler, 0,
+ "SYSIO_UE", sbus) < 0) {
prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
sbus->portid);
prom_halt();
}
irq = sbus_build_irq(sbus, SYSIO_CE_INO);
- if (request_irq(irq, sysio_ce_handler,
- IRQF_SHARED, "SYSIO CE", sbus) < 0) {
+ if (request_irq(irq, sysio_ce_handler, 0,
+ "SYSIO_CE", sbus) < 0) {
prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
sbus->portid);
prom_halt();
}
irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
- if (request_irq(irq, sysio_sbus_error_handler,
- IRQF_SHARED, "SYSIO SBUS Error", sbus) < 0) {
+ if (request_irq(irq, sysio_sbus_error_handler, 0,
+ "SYSIO_SBERR", sbus) < 0) {
prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
sbus->portid);
prom_halt();
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 96d56a8410a..203e8730100 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -20,7 +20,6 @@
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/tty.h>
-#include <linux/smp_lock.h>
#include <linux/binfmts.h>
#include <linux/bitops.h>
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index c45f21b881d..8c1c121330f 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -17,7 +17,6 @@
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/tty.h>
-#include <linux/smp_lock.h>
#include <linux/binfmts.h>
#include <linux/compat.h>
#include <linux/bitops.h>
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index d4f0a70f484..8087d67a0cf 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -10,7 +10,6 @@
#include <linux/pagemap.h>
#include <linux/threads.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/delay.h>
@@ -1343,11 +1342,11 @@ void __init setup_per_cpu_areas(void)
/* Copy section for each CPU (we discard the original) */
goal = PERCPU_ENOUGH_ROOM;
- __per_cpu_shift = 0;
- for (size = 1UL; size < goal; size <<= 1UL)
+ __per_cpu_shift = PAGE_SHIFT;
+ for (size = PAGE_SIZE; size < goal; size <<= 1UL)
__per_cpu_shift++;
- ptr = alloc_bootmem(size * NR_CPUS);
+ ptr = alloc_bootmem_pages(size * NR_CPUS);
__per_cpu_base = ptr - __per_cpu_start;
diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c
index c4d15f2762b..47f92a59be1 100644
--- a/arch/sparc64/kernel/stacktrace.c
+++ b/arch/sparc64/kernel/stacktrace.c
@@ -3,22 +3,16 @@
#include <linux/thread_info.h>
#include <asm/ptrace.h>
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
{
unsigned long ksp, fp, thread_base;
- struct thread_info *tp;
+ struct thread_info *tp = task_thread_info(current);
- if (!task)
- task = current;
- tp = task_thread_info(task);
- if (task == current) {
- flushw_all();
- __asm__ __volatile__(
- "mov %%fp, %0"
- : "=r" (ksp)
- );
- } else
- ksp = tp->ksp;
+ flushw_all();
+ __asm__ __volatile__(
+ "mov %%fp, %0"
+ : "=r" (ksp)
+ );
fp = ksp + STACK_BIAS;
thread_base = (unsigned long) tp;
diff --git a/arch/sparc64/kernel/sunos_ioctl32.c b/arch/sparc64/kernel/sunos_ioctl32.c
index a05e43d5175..75d2bad4983 100644
--- a/arch/sparc64/kernel/sunos_ioctl32.c
+++ b/arch/sparc64/kernel/sunos_ioctl32.c
@@ -22,7 +22,6 @@
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/compat.h>
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index a53d4abb4b4..d108eeb0734 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -19,7 +19,6 @@
#include <linux/mman.h>
#include <linux/utsname.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
#include <linux/ipc.h>
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 7876a022628..abd83129b2e 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -775,15 +775,25 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
asmlinkage long sys32_utimes(char __user *filename,
struct compat_timeval __user *tvs)
{
- struct timeval ktvs[2];
+ struct timespec tv[2];
if (tvs) {
+ struct timeval ktvs[2];
if (get_tv32(&ktvs[0], tvs) ||
get_tv32(&ktvs[1], 1+tvs))
return -EFAULT;
+
+ if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
+ ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
+ return -EINVAL;
+
+ tv[0].tv_sec = ktvs[0].tv_sec;
+ tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
+ tv[1].tv_sec = ktvs[1].tv_sec;
+ tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
}
- return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL));
+ return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
}
/* These are here just in case some old sparc32 binary calls it. */
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 48c36fe6dc6..5fe7f9ad4a9 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -81,6 +81,7 @@ sys_call_table32:
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
+/*310*/ .word compat_sys_utimensat
#endif /* CONFIG_COMPAT */
@@ -152,6 +153,7 @@ sys_call_table:
.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
+/*310*/ .word sys_utimensat
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -269,5 +271,6 @@ sunos_sys_table:
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys
+/*310*/ .long sunos_nosys
#endif
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index ad67784292d..d0fde36395b 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -15,10 +15,11 @@
#include <linux/kallsyms.h>
#include <linux/signal.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/kdebug.h>
+#include <asm/smp.h>
#include <asm/delay.h>
#include <asm/system.h>
#include <asm/ptrace.h>
@@ -36,26 +37,12 @@
#include <asm/psrcompat.h>
#include <asm/processor.h>
#include <asm/timer.h>
-#include <asm/kdebug.h>
#include <asm/head.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
#include <asm/prom.h>
-ATOMIC_NOTIFIER_HEAD(sparc64die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_register(&sparc64die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier);
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&sparc64die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier);
/* When an irrecoverable trap occurs at tl > 0, the trap entry
* code logs the trap state registers at every level in the trap
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index bc18d480dd1..953be816fa2 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -18,7 +18,6 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/bitops.h>
#include <linux/kallsyms.h>
#include <asm/fpumacro.h>
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 55ae802dc0a..b582024d219 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -15,11 +15,11 @@
#include <linux/signal.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kprobes.h>
#include <linux/kallsyms.h>
+#include <linux/kdebug.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -29,40 +29,26 @@
#include <asm/asi.h>
#include <asm/lsu.h>
#include <asm/sections.h>
-#include <asm/kdebug.h>
#include <asm/mmu_context.h>
#ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
-
-/* Hook to register for page fault notifications */
-int register_page_fault_notifier(struct notifier_block *nb)
+static inline int notify_page_fault(struct pt_regs *regs)
{
- return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
-}
-
-int unregister_page_fault_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&notify_page_fault_chain, nb);
-}
-
-static inline int notify_page_fault(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
- return atomic_notifier_call_chain(&notify_page_fault_chain, val, &args);
+ int ret = 0;
+
+ /* kprobe_running() needs smp_processor_id() */
+ if (!user_mode(regs)) {
+ preempt_disable();
+ if (kprobe_running() && kprobe_fault_handler(regs, 0))
+ ret = 1;
+ preempt_enable();
+ }
+ return ret;
}
#else
-static inline int notify_page_fault(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
+static inline int notify_page_fault(struct pt_regs *regs)
{
- return NOTIFY_DONE;
+ return 0;
}
#endif
@@ -121,9 +107,6 @@ static void __kprobes unhandled_fault(unsigned long address,
printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n",
(tsk->mm ? (unsigned long) tsk->mm->pgd :
(unsigned long) tsk->active_mm->pgd));
- if (notify_die(DIE_GPF, "general protection fault", regs,
- 0, 0, SIGSEGV) == NOTIFY_STOP)
- return;
die_if_kernel("Oops", regs);
}
@@ -300,8 +283,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
fault_code = get_thread_fault_code();
- if (notify_page_fault(DIE_PAGE_FAULT, "page_fault", regs,
- fault_code, 0, SIGSEGV) == NOTIFY_STOP)
+ if (notify_page_fault(regs))
return;
si_code = SEGV_MAPERR;
diff --git a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
index 00677b5e1d7..eaba9b70b18 100644
--- a/arch/sparc64/mm/hugetlbpage.c
+++ b/arch/sparc64/mm/hugetlbpage.c
@@ -10,7 +10,6 @@
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
@@ -175,6 +174,12 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
if (len > task_size)
return -ENOMEM;
+ if (flags & MAP_FIXED) {
+ if (prepare_hugepage_range(addr, len, pgoff))
+ return -EINVAL;
+ return addr;
+ }
+
if (addr) {
addr = ALIGN(addr, HPAGE_SIZE);
vma = find_vma(mm, addr);
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index cafadcbcdf3..d7004eaf1c8 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -164,30 +164,6 @@ unsigned long sparc64_kern_sec_context __read_mostly;
int bigkernel = 0;
-struct kmem_cache *pgtable_cache __read_mostly;
-
-static void zero_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
-{
- clear_page(addr);
-}
-
-extern void tsb_cache_init(void);
-
-void pgtable_cache_init(void)
-{
- pgtable_cache = kmem_cache_create("pgtable_cache",
- PAGE_SIZE, PAGE_SIZE,
- SLAB_HWCACHE_ALIGN |
- SLAB_MUST_HWCACHE_ALIGN,
- zero_ctor,
- NULL);
- if (!pgtable_cache) {
- prom_printf("Could not create pgtable_cache\n");
- prom_halt();
- }
- tsb_cache_init();
-}
-
#ifdef CONFIG_DEBUG_DCFLUSH
atomic_t dcpage_flushes = ATOMIC_INIT(0);
#ifdef CONFIG_SMP
diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c
index 236d02f41a0..8eb8a7c76ec 100644
--- a/arch/sparc64/mm/tsb.c
+++ b/arch/sparc64/mm/tsb.c
@@ -252,7 +252,7 @@ static const char *tsb_cache_names[8] = {
"tsb_1MB",
};
-void __init tsb_cache_init(void)
+void __init pgtable_cache_init(void)
{
unsigned long i;
@@ -262,8 +262,7 @@ void __init tsb_cache_init(void)
tsb_caches[i] = kmem_cache_create(name,
size, size,
- SLAB_HWCACHE_ALIGN |
- SLAB_MUST_HWCACHE_ALIGN,
+ 0,
NULL, NULL);
if (!tsb_caches[i]) {
prom_printf("Could not create %s cache\n", name);
diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c
index 330743c5b3d..18352a49862 100644
--- a/arch/sparc64/solaris/ioctl.c
+++ b/arch/sparc64/solaris/ioctl.c
@@ -686,7 +686,8 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg)
int i = 0;
read_lock_bh(&dev_base_lock);
- for (d = dev_base; d; d = d->next) i++;
+ for_each_netdev(d)
+ i++;
read_unlock_bh(&dev_base_lock);
if (put_user (i, (int __user *)A(arg)))
diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c
index 8cef5fd57b2..a531a2cdb38 100644
--- a/arch/sparc64/solaris/ipc.c
+++ b/arch/sparc64/solaris/ipc.c
@@ -6,7 +6,6 @@
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/shm.h>
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 542c808ec2c..3b67de7455f 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/utsname.h>
#include <linux/limits.h>
#include <linux/mm.h>
diff --git a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c
index 7fa2634e208..de10c9716cf 100644
--- a/arch/sparc64/solaris/signal.c
+++ b/arch/sparc64/solaris/signal.c
@@ -5,7 +5,6 @@
*/
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c
index d3a66ea74a7..cc69847cf24 100644
--- a/arch/sparc64/solaris/socket.c
+++ b/arch/sparc64/solaris/socket.c
@@ -8,7 +8,6 @@
*/
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/socket.h>
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index c2864447de8..e94f6e5d945 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/file.h>
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 354cc6b7053..b9c0f307a8f 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -320,21 +320,7 @@ source "crypto/Kconfig"
source "lib/Kconfig"
-menu "SCSI support"
-depends on BROKEN
-
-config SCSI
- tristate "SCSI support"
-
-# This gives us free_dma, which scsi.c wants.
-config GENERIC_ISA_DMA
- bool
- depends on SCSI
- default y
-
-source "arch/um/Kconfig.scsi"
-
-endmenu
+source "drivers/scsi/Kconfig"
source "drivers/md/Kconfig"
diff --git a/arch/um/Kconfig.scsi b/arch/um/Kconfig.scsi
deleted file mode 100644
index c291c942b1a..00000000000
--- a/arch/um/Kconfig.scsi
+++ /dev/null
@@ -1,58 +0,0 @@
-comment "SCSI support type (disk, tape, CD-ROM)"
- depends on SCSI
-
-config BLK_DEV_SD
- tristate "SCSI disk support"
- depends on SCSI
-
-config SD_EXTRA_DEVS
- int "Maximum number of SCSI disks that can be loaded as modules"
- depends on BLK_DEV_SD
- default "40"
-
-config CHR_DEV_ST
- tristate "SCSI tape support"
- depends on SCSI
-
-config BLK_DEV_SR
- tristate "SCSI CD-ROM support"
- depends on SCSI
-
-config BLK_DEV_SR_VENDOR
- bool "Enable vendor-specific extensions (for SCSI CDROM)"
- depends on BLK_DEV_SR
-
-config SR_EXTRA_DEVS
- int "Maximum number of CDROM devices that can be loaded as modules"
- depends on BLK_DEV_SR
- default "2"
-
-config CHR_DEV_SG
- tristate "SCSI generic support"
- depends on SCSI
-
-comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
- depends on SCSI
-
-#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-config SCSI_DEBUG_QUEUES
- bool "Enable extra checks in new queueing code"
- depends on SCSI
-
-#fi
-config SCSI_MULTI_LUN
- bool "Probe all LUNs on each SCSI device"
- depends on SCSI
-
-config SCSI_CONSTANTS
- bool "Verbose SCSI error reporting (kernel size +=12K)"
- depends on SCSI
-
-config SCSI_LOGGING
- bool "SCSI logging facility"
- depends on SCSI
-
-config SCSI_DEBUG
- tristate "SCSI debugging host simulator (EXPERIMENTAL)"
- depends on SCSI
-
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 780cc0a4a12..f938fa82214 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -41,6 +41,7 @@ CONFIG_M686=y
# CONFIG_MGEODE_LX is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
# CONFIG_X86_GENERIC is not set
CONFIG_X86_CMPXCHG=y
CONFIG_X86_XADD=y
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 9fdfad64953..3aa35161176 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -12,7 +12,6 @@
#include <linux/tty_flip.h>
#include <asm/irq.h>
#include "chan_kern.h"
-#include "user_util.h"
#include "kern.h"
#include "irq_user.h"
#include "sigio.h"
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 0cad3546cb8..13f0bf852b2 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -14,7 +14,6 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
#include "kern_util.h"
-#include "user_util.h"
#include "chan_user.h"
#include "user.h"
#include "os.h"
@@ -158,7 +157,7 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
*/
err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0);
if(err < 0){
- printk("fork of winch_thread failed - errno = %d\n", errno);
+ printk("fork of winch_thread failed - errno = %d\n", -err);
goto out_close;
}
@@ -204,14 +203,3 @@ void register_winch(int fd, struct tty_struct *tty)
}
}
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
index c6a308464ac..15453845d2b 100644
--- a/arch/um/drivers/cow_sys.h
+++ b/arch/um/drivers/cow_sys.h
@@ -2,14 +2,13 @@
#define __COW_SYS_H__
#include "kern_util.h"
-#include "user_util.h"
#include "os.h"
#include "user.h"
#include "um_malloc.h"
static inline void *cow_malloc(int size)
{
- return(um_kmalloc(size));
+ return um_kmalloc(size);
}
static inline void cow_free(void *ptr)
@@ -21,29 +20,22 @@ static inline void cow_free(void *ptr)
static inline char *cow_strdup(char *str)
{
- return(uml_strdup(str));
+ return uml_strdup(str);
}
static inline int cow_seek_file(int fd, __u64 offset)
{
- return(os_seek_file(fd, offset));
+ return os_seek_file(fd, offset);
}
static inline int cow_file_size(char *file, unsigned long long *size_out)
{
- return(os_file_size(file, size_out));
+ return os_file_size(file, size_out);
}
static inline int cow_write_file(int fd, void *buf, int size)
{
- return(os_write_file(fd, buf, size));
+ return os_write_file(fd, buf, size);
}
#endif
-
-/*
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index 021b82c7a75..b869e389968 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -14,7 +14,6 @@
#include "net_user.h"
#include "daemon.h"
#include "kern_util.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
#include "um_malloc.h"
@@ -39,11 +38,11 @@ static struct sockaddr_un *new_addr(void *name, int len)
sun = um_kmalloc(sizeof(struct sockaddr_un));
if(sun == NULL){
printk("new_addr: allocation of sockaddr_un failed\n");
- return(NULL);
+ return NULL;
}
sun->sun_family = AF_UNIX;
memcpy(sun->sun_path, name, len);
- return(sun);
+ return sun;
}
static int connect_to_switch(struct daemon_data *pri)
@@ -112,7 +111,7 @@ static int connect_to_switch(struct daemon_data *pri)
}
pri->data_addr = sun;
- return(fd);
+ return fd;
out_free:
kfree(sun);
@@ -120,10 +119,10 @@ static int connect_to_switch(struct daemon_data *pri)
os_close_file(fd);
out:
os_close_file(pri->control);
- return(err);
+ return err;
}
-static void daemon_user_init(void *data, void *dev)
+static int daemon_user_init(void *data, void *dev)
{
struct daemon_data *pri = data;
struct timeval tv;
@@ -146,13 +145,16 @@ static void daemon_user_init(void *data, void *dev)
if(pri->fd < 0){
kfree(pri->local_addr);
pri->local_addr = NULL;
+ return pri->fd;
}
+
+ return 0;
}
static int daemon_open(void *data)
{
struct daemon_data *pri = data;
- return(pri->fd);
+ return pri->fd;
}
static void daemon_remove(void *data)
@@ -176,12 +178,12 @@ int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
{
struct sockaddr_un *data_addr = pri->data_addr;
- return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+ return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
}
static int daemon_set_mtu(int mtu, void *data)
{
- return(mtu);
+ return mtu;
}
const struct net_user_info daemon_user_info = {
@@ -194,14 +196,3 @@ const struct net_user_info daemon_user_info = {
.delete_address = NULL,
.max_packet = MAX_PACKET - ETH_HEADER_OTHER
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 218aa0e9b79..7f083ec47a4 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -9,7 +9,6 @@
#include <termios.h>
#include <errno.h>
#include "user.h"
-#include "user_util.h"
#include "chan_user.h"
#include "os.h"
#include "um_malloc.h"
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
index c495ecf263b..5eeecf8917c 100644
--- a/arch/um/drivers/harddog_user.c
+++ b/arch/um/drivers/harddog_user.c
@@ -6,7 +6,6 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
-#include "user_util.h"
#include "user.h"
#include "mconsole.h"
#include "os.h"
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index f75d7b05c48..ced99106f79 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -13,7 +13,6 @@
#include "irq_user.h"
#include "line.h"
#include "kern.h"
-#include "user_util.h"
#include "kern_util.h"
#include "os.h"
#include "irq_kern.h"
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index b827e82884c..d319db16d4e 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -20,7 +20,6 @@
#include "net_user.h"
#include "mcast.h"
#include "kern_util.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
#include "um_malloc.h"
@@ -34,20 +33,21 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port)
sin = um_kmalloc(sizeof(struct sockaddr_in));
if(sin == NULL){
printk("new_addr: allocation of sockaddr_in failed\n");
- return(NULL);
+ return NULL;
}
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = in_aton(addr);
sin->sin_port = htons(port);
- return(sin);
+ return sin;
}
-static void mcast_user_init(void *data, void *dev)
+static int mcast_user_init(void *data, void *dev)
{
struct mcast_data *pri = data;
pri->mcast_addr = new_addr(pri->addr, pri->port);
pri->dev = dev;
+ return 0;
}
static void mcast_remove(void *data)
@@ -107,8 +107,8 @@ static int mcast_open(void *data)
err = -errno;
printk("mcast_open : data bind failed, errno = %d\n", errno);
goto out_close;
- }
-
+ }
+
/* subscribe to the multicast group */
mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
mreq.imr_interface.s_addr = 0;
@@ -153,12 +153,12 @@ int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
{
struct sockaddr_in *data_addr = pri->mcast_addr;
- return(net_sendto(fd, buf, len, data_addr, sizeof(*data_addr)));
+ return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
}
static int mcast_set_mtu(int mtu, void *data)
{
- return(mtu);
+ return mtu;
}
const struct net_user_info mcast_user_info = {
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 65ad2932672..542c9ef858f 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -25,7 +25,6 @@
#include "linux/console.h"
#include "asm/irq.h"
#include "asm/uaccess.h"
-#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
#include "mconsole.h"
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index f02634fbf32..62e5ad63181 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -17,7 +17,6 @@
#include "sysdep/ptrace.h"
#include "mconsole.h"
#include "os.h"
-#include "user_util.h"
static struct mconsole_command commands[] = {
/* With uts namespaces, uts information becomes process-specific, so
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index df3516e47d4..e41a08f0469 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -15,7 +15,6 @@
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
#include "mem_user.h"
-#include "user_util.h"
/* These are set in mmapper_init, which is called at boot time */
static unsigned long mmapper_size;
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 859303730b2..72773dd5442 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -21,7 +21,6 @@
#include "linux/ethtool.h"
#include "linux/platform_device.h"
#include "asm/uaccess.h"
-#include "user_util.h"
#include "kern_util.h"
#include "net_kern.h"
#include "net_user.h"
@@ -284,7 +283,7 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
-static void setup_etheraddr(char *str, unsigned char *addr)
+static void setup_etheraddr(char *str, unsigned char *addr, char *name)
{
char *end;
int i;
@@ -303,15 +302,34 @@ static void setup_etheraddr(char *str, unsigned char *addr)
}
str = end + 1;
}
- if(addr[0] & 1){
+ if (is_multicast_ether_addr(addr)) {
printk(KERN_ERR
- "Attempt to assign a broadcast ethernet address to a "
+ "Attempt to assign a multicast ethernet address to a "
"device disallowed\n");
goto random;
}
+ if (!is_valid_ether_addr(addr)) {
+ printk(KERN_ERR
+ "Attempt to assign an invalid ethernet address to a "
+ "device disallowed\n");
+ goto random;
+ }
+ if (!is_local_ether_addr(addr)) {
+ printk(KERN_WARNING
+ "Warning: attempt to assign a globally valid ethernet "
+ "address to a device\n");
+ printk(KERN_WARNING "You should better enable the 2nd "
+ "rightmost bit in the first byte of the MAC,\n");
+ printk(KERN_WARNING "i.e. %02x:%02x:%02x:%02x:%02x:%02x\n",
+ addr[0] | 0x02, addr[1], addr[2], addr[3], addr[4],
+ addr[5]);
+ goto random;
+ }
return;
random:
+ printk(KERN_INFO
+ "Choosing a random ethernet address for device %s\n", name);
random_ether_addr(addr);
}
@@ -325,31 +343,53 @@ static struct platform_driver uml_net_driver = {
};
static int driver_registered;
-static int eth_configure(int n, void *init, char *mac,
- struct transport *transport)
+static void net_device_release(struct device *dev)
+{
+ struct uml_net *device = dev->driver_data;
+ struct net_device *netdev = device->dev;
+ struct uml_net_private *lp = netdev->priv;
+
+ if(lp->remove != NULL)
+ (*lp->remove)(&lp->user);
+ list_del(&device->list);
+ kfree(device);
+ free_netdev(netdev);
+}
+
+static void eth_configure(int n, void *init, char *mac,
+ struct transport *transport)
{
struct uml_net *device;
struct net_device *dev;
struct uml_net_private *lp;
- int save, err, size;
+ int err, size;
- size = transport->private_size + sizeof(struct uml_net_private) +
- sizeof(((struct uml_net_private *) 0)->user);
+ size = transport->private_size + sizeof(struct uml_net_private);
device = kzalloc(sizeof(*device), GFP_KERNEL);
if (device == NULL) {
- printk(KERN_ERR "eth_configure failed to allocate uml_net\n");
- return(1);
+ printk(KERN_ERR "eth_configure failed to allocate struct "
+ "uml_net\n");
+ return;
+ }
+
+ dev = alloc_etherdev(size);
+ if (dev == NULL) {
+ printk(KERN_ERR "eth_configure: failed to allocate struct "
+ "net_device for eth%d\n", n);
+ goto out_free_device;
}
INIT_LIST_HEAD(&device->list);
device->index = n;
- spin_lock(&devices_lock);
- list_add(&device->list, &devices);
- spin_unlock(&devices_lock);
+ /* If this name ends up conflicting with an existing registered
+ * netdevice, that is OK, register_netdev{,ice}() will notice this
+ * and fail.
+ */
+ snprintf(dev->name, sizeof(dev->name), "eth%d", n);
- setup_etheraddr(mac, device->mac);
+ setup_etheraddr(mac, device->mac, dev->name);
printk(KERN_INFO "Netdevice %d ", n);
printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
@@ -357,11 +397,6 @@ static int eth_configure(int n, void *init, char *mac,
device->mac[2], device->mac[3],
device->mac[4], device->mac[5]);
printk(": ");
- dev = alloc_etherdev(size);
- if (dev == NULL) {
- printk(KERN_ERR "eth_configure: failed to allocate device\n");
- return 1;
- }
lp = dev->priv;
/* This points to the transport private data. It's still clear, but we
@@ -376,47 +411,20 @@ static int eth_configure(int n, void *init, char *mac,
}
device->pdev.id = n;
device->pdev.name = DRIVER_NAME;
- platform_device_register(&device->pdev);
+ device->pdev.dev.release = net_device_release;
+ device->pdev.dev.driver_data = device;
+ if(platform_device_register(&device->pdev))
+ goto out_free_netdev;
SET_NETDEV_DEV(dev,&device->pdev.dev);
- /* If this name ends up conflicting with an existing registered
- * netdevice, that is OK, register_netdev{,ice}() will notice this
- * and fail.
- */
- snprintf(dev->name, sizeof(dev->name), "eth%d", n);
device->dev = dev;
+ /*
+ * These just fill in a data structure, so there's no failure
+ * to be worried about.
+ */
(*transport->kern->init)(dev, init);
- dev->mtu = transport->user->max_packet;
- dev->open = uml_net_open;
- dev->hard_start_xmit = uml_net_start_xmit;
- dev->stop = uml_net_close;
- dev->get_stats = uml_net_get_stats;
- dev->set_multicast_list = uml_net_set_multicast_list;
- dev->tx_timeout = uml_net_tx_timeout;
- dev->set_mac_address = uml_net_set_mac;
- dev->change_mtu = uml_net_change_mtu;
- dev->ethtool_ops = &uml_net_ethtool_ops;
- dev->watchdog_timeo = (HZ >> 1);
- dev->irq = UM_ETH_IRQ;
-
- rtnl_lock();
- err = register_netdevice(dev);
- rtnl_unlock();
- if (err) {
- device->dev = NULL;
- /* XXX: should we call ->remove() here? */
- free_netdev(dev);
- return 1;
- }
-
- /* lp.user is the first four bytes of the transport data, which
- * has already been initialized. This structure assignment will
- * overwrite that, so we make sure that .user gets overwritten with
- * what it already has.
- */
- save = lp->user[0];
*lp = ((struct uml_net_private)
{ .list = LIST_HEAD_INIT(lp->list),
.dev = dev,
@@ -430,20 +438,53 @@ static int eth_configure(int n, void *init, char *mac,
.write = transport->kern->write,
.add_address = transport->user->add_address,
.delete_address = transport->user->delete_address,
- .set_mtu = transport->user->set_mtu,
- .user = { save } });
+ .set_mtu = transport->user->set_mtu });
init_timer(&lp->tl);
spin_lock_init(&lp->lock);
lp->tl.function = uml_net_user_timer_expire;
memcpy(lp->mac, device->mac, sizeof(lp->mac));
- if (transport->user->init)
- (*transport->user->init)(&lp->user, dev);
+ if ((transport->user->init != NULL) &&
+ ((*transport->user->init)(&lp->user, dev) != 0))
+ goto out_unregister;
set_ether_mac(dev, device->mac);
+ dev->mtu = transport->user->max_packet;
+ dev->open = uml_net_open;
+ dev->hard_start_xmit = uml_net_start_xmit;
+ dev->stop = uml_net_close;
+ dev->get_stats = uml_net_get_stats;
+ dev->set_multicast_list = uml_net_set_multicast_list;
+ dev->tx_timeout = uml_net_tx_timeout;
+ dev->set_mac_address = uml_net_set_mac;
+ dev->change_mtu = uml_net_change_mtu;
+ dev->ethtool_ops = &uml_net_ethtool_ops;
+ dev->watchdog_timeo = (HZ >> 1);
+ dev->irq = UM_ETH_IRQ;
- return 0;
+ rtnl_lock();
+ err = register_netdevice(dev);
+ rtnl_unlock();
+ if (err)
+ goto out_undo_user_init;
+
+ spin_lock(&devices_lock);
+ list_add(&device->list, &devices);
+ spin_unlock(&devices_lock);
+
+ return;
+
+out_undo_user_init:
+ if (transport->user->remove != NULL)
+ (*transport->user->remove)(&lp->user);
+out_unregister:
+ platform_device_unregister(&device->pdev);
+ return; /* platform_device_unregister frees dev and device */
+out_free_netdev:
+ free_netdev(dev);
+out_free_device:
+ kfree(device);
}
static struct uml_net *find_device(int n)
@@ -666,13 +707,9 @@ static int net_remove(int n, char **error_out)
lp = dev->priv;
if(lp->fd > 0)
return -EBUSY;
- if(lp->remove != NULL) (*lp->remove)(&lp->user);
unregister_netdev(dev);
platform_device_unregister(&device->pdev);
- list_del(&device->list);
- kfree(device);
- free_netdev(dev);
return 0;
}
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 0ffd7ac295d..3503cff867c 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -14,11 +14,11 @@
#include <sys/wait.h>
#include <sys/time.h>
#include "user.h"
-#include "user_util.h"
#include "kern_util.h"
#include "net_user.h"
#include "os.h"
#include "um_malloc.h"
+#include "kern_constants.h"
int tap_open_common(void *dev, char *gate_addr)
{
@@ -216,7 +216,7 @@ static void change(char *dev, char *what, unsigned char *addr,
sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1],
netmask[2], netmask[3]);
- output_len = page_size();
+ output_len = UM_KERN_PAGE_SIZE;
output = um_kmalloc(output_len);
if(output == NULL)
printk("change : failed to allocate output buffer\n");
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
index 948849343ca..c329931673d 100644
--- a/arch/um/drivers/pcap_kern.c
+++ b/arch/um/drivers/pcap_kern.c
@@ -29,21 +29,25 @@ void pcap_init(struct net_device *dev, void *data)
ppri->promisc = init->promisc;
ppri->optimize = init->optimize;
ppri->filter = init->filter;
+
+ printk("pcap backend, host interface %s\n", ppri->host_if);
}
-static int pcap_read(int fd, struct sk_buff **skb,
+static int pcap_read(int fd, struct sk_buff **skb,
struct uml_net_private *lp)
{
*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
- if(*skb == NULL) return(-ENOMEM);
- return(pcap_user_read(fd, skb_mac_header(*skb),
+ if(*skb == NULL)
+ return -ENOMEM;
+
+ return pcap_user_read(fd, skb_mac_header(*skb),
(*skb)->dev->mtu + ETH_HEADER_OTHER,
- (struct pcap_data *) &lp->user));
+ (struct pcap_data *) &lp->user);
}
static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
{
- return(-EPERM);
+ return -EPERM;
}
static const struct net_kern_info pcap_kern_info = {
@@ -65,12 +69,12 @@ int pcap_setup(char *str, char **mac_out, void *data)
.optimize = 0,
.filter = NULL });
- remain = split_if_spec(str, &host_if, &init->filter,
- &options[0], &options[1], NULL);
+ remain = split_if_spec(str, &host_if, &init->filter,
+ &options[0], &options[1], mac_out, NULL);
if(remain != NULL){
printk(KERN_ERR "pcap_setup - Extra garbage on "
"specification : '%s'\n", remain);
- return(0);
+ return 0;
}
if(host_if != NULL)
@@ -87,10 +91,13 @@ int pcap_setup(char *str, char **mac_out, void *data)
init->optimize = 1;
else if(!strcmp(options[i], "nooptimize"))
init->optimize = 0;
- else printk("pcap_setup : bad option - '%s'\n", options[i]);
+ else {
+ printk("pcap_setup : bad option - '%s'\n", options[i]);
+ return 0;
+ }
}
- return(1);
+ return 1;
}
static struct transport pcap_transport = {
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
index 11921a7baa7..483aa15222a 100644
--- a/arch/um/drivers/pcap_user.c
+++ b/arch/um/drivers/pcap_user.c
@@ -13,12 +13,13 @@
#include "pcap_user.h"
#include "user.h"
#include "um_malloc.h"
+#include "kern_constants.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
#define PCAP_FD(p) (*(int *)(p))
-static void pcap_user_init(void *data, void *dev)
+static int pcap_user_init(void *data, void *dev)
{
struct pcap_data *pri = data;
pcap_t *p;
@@ -26,13 +27,14 @@ static void pcap_user_init(void *data, void *dev)
p = pcap_open_live(pri->host_if, MAX_PACKET, pri->promisc, 0, errors);
if(p == NULL){
- printk("pcap_user_init : pcap_open_live failed - '%s'\n",
- errors);
- return;
+ printk(UM_KERN_ERR "pcap_user_init : pcap_open_live failed - "
+ "'%s'\n", errors);
+ return -EINVAL;
}
pri->dev = dev;
pri->pcap = p;
+ return 0;
}
static int pcap_open(void *data)
@@ -42,39 +44,39 @@ static int pcap_open(void *data)
int err;
if(pri->pcap == NULL)
- return(-ENODEV);
+ return -ENODEV;
if(pri->filter != NULL){
err = dev_netmask(pri->dev, &netmask);
if(err < 0){
- printk("pcap_open : dev_netmask failed\n");
- return(-EIO);
+ printk(UM_KERN_ERR "pcap_open : dev_netmask failed\n");
+ return -EIO;
}
pri->compiled = um_kmalloc(sizeof(struct bpf_program));
if(pri->compiled == NULL){
- printk("pcap_open : kmalloc failed\n");
- return(-ENOMEM);
+ printk(UM_KERN_ERR "pcap_open : kmalloc failed\n");
+ return -ENOMEM;
}
-
+
err = pcap_compile(pri->pcap,
(struct bpf_program *) pri->compiled,
pri->filter, pri->optimize, netmask);
if(err < 0){
- printk("pcap_open : pcap_compile failed - '%s'\n",
- pcap_geterr(pri->pcap));
- return(-EIO);
+ printk(UM_KERN_ERR "pcap_open : pcap_compile failed - "
+ "'%s'\n", pcap_geterr(pri->pcap));
+ return -EIO;
}
err = pcap_setfilter(pri->pcap, pri->compiled);
if(err < 0){
- printk("pcap_open : pcap_setfilter failed - '%s'\n",
- pcap_geterr(pri->pcap));
- return(-EIO);
+ printk(UM_KERN_ERR "pcap_open : pcap_setfilter "
+ "failed - '%s'\n", pcap_geterr(pri->pcap));
+ return -EIO;
}
}
-
- return(PCAP_FD(pri->pcap));
+
+ return PCAP_FD(pri->pcap);
}
static void pcap_remove(void *data)
@@ -84,7 +86,8 @@ static void pcap_remove(void *data)
if(pri->compiled != NULL)
pcap_freecode(pri->compiled);
- pcap_close(pri->pcap);
+ if(pri->pcap != NULL)
+ pcap_close(pri->pcap);
}
struct pcap_handler_data {
@@ -113,12 +116,13 @@ int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
n = pcap_dispatch(pri->pcap, 1, handler, (u_char *) &hdata);
if(n < 0){
- printk("pcap_dispatch failed - %s\n", pcap_geterr(pri->pcap));
- return(-EIO);
+ printk(UM_KERN_ERR "pcap_dispatch failed - %s\n",
+ pcap_geterr(pri->pcap));
+ return -EIO;
}
else if(n == 0)
- return(0);
- return(hdata.len);
+ return 0;
+ return hdata.len;
}
const struct net_user_info pcap_user_info = {
@@ -131,14 +135,3 @@ const struct net_user_info pcap_user_info = {
.delete_address = NULL,
.max_packet = MAX_PACKET - ETH_HEADER_OTHER
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index 80508023054..3f6357d24be 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -13,7 +13,6 @@
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "chan_user.h"
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 829a5eca8c0..df4976c9eef 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -4,13 +4,13 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
#include "chan_user.h"
#include "user.h"
-#include "user_util.h"
#include "kern_util.h"
#include "os.h"
#include "um_malloc.h"
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 7eddacc53b6..78f0e515da8 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -8,7 +8,6 @@
#include <sys/termios.h>
#include <sys/wait.h>
#include <sys/signal.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "net_user.h"
@@ -16,12 +15,14 @@
#include "slip_common.h"
#include "os.h"
#include "um_malloc.h"
+#include "kern_constants.h"
-void slip_user_init(void *data, void *dev)
+static int slip_user_init(void *data, void *dev)
{
struct slip_data *pri = data;
pri->dev = dev;
+ return 0;
}
static int set_up_tty(int fd)
@@ -89,7 +90,7 @@ static int slip_tramp(char **argv, int fd)
goto out_close;
pid = err;
- output_len = page_size();
+ output_len = UM_KERN_PAGE_SIZE;
output = um_kmalloc(output_len);
if(output == NULL){
printk("slip_tramp : failed to allocate output buffer\n");
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index ce5e85d1de3..39f889fe994 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -7,7 +7,6 @@
#include <errno.h>
#include <sys/wait.h>
#include <sys/signal.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "net_user.h"
@@ -15,11 +14,12 @@
#include "slip_common.h"
#include "os.h"
-void slirp_user_init(void *data, void *dev)
+static int slirp_user_init(void *data, void *dev)
{
struct slirp_data *pri = data;
pri->dev = dev;
+ return 0;
}
struct slirp_pre_exec_data {
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 4b382a6e710..fd09ad9e9c0 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -15,7 +15,6 @@
#include "line.h"
#include "ssl.h"
#include "chan_kern.h"
-#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
#include "init.h"
@@ -192,12 +191,12 @@ static int ssl_init(void)
ssl_driver = register_lines(&driver, &ssl_ops, serial_lines,
ARRAY_SIZE(serial_lines));
- lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
-
new_title = add_xterm_umid(opts.xterm_title);
if (new_title != NULL)
opts.xterm_title = new_title;
+ lines_init(serial_lines, ARRAY_SIZE(serial_lines), &opts);
+
ssl_init_done = 1;
register_console(&ssl_cons);
return 0;
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 76d1f1c980e..2bb4193ac1a 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -22,7 +22,6 @@
#include "stdio_console.h"
#include "line.h"
#include "chan_kern.h"
-#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
#include "mconsole_kern.h"
@@ -167,12 +166,12 @@ int stdio_init(void)
return -1;
printk(KERN_INFO "Initialized stdio console driver\n");
- lines_init(vts, ARRAY_SIZE(vts), &opts);
-
new_title = add_xterm_umid(opts.xterm_title);
if(new_title != NULL)
opts.xterm_title = new_title;
+ lines_init(vts, ARRAY_SIZE(vts), &opts);
+
con_init_done = 1;
register_console(&stdiocons);
return 0;
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index d95d64309ea..c07d0d56278 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -8,7 +8,6 @@
#include <errno.h>
#include <unistd.h>
#include "chan_user.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
#include "um_malloc.h"
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 8bd9204ac1a..70509ddaac0 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -39,7 +39,6 @@
#include "asm/irq.h"
#include "asm/types.h"
#include "asm/tlbflush.h"
-#include "user_util.h"
#include "mem_user.h"
#include "kern_util.h"
#include "kern.h"
@@ -90,7 +89,7 @@ static inline int ubd_test_bit(__u64 bit, unsigned char *data)
bits = sizeof(data[0]) * 8;
n = bit / bits;
off = bit % bits;
- return((data[n] & (1 << off)) != 0);
+ return (data[n] & (1 << off)) != 0;
}
static inline void ubd_set_bit(__u64 bit, unsigned char *data)
@@ -147,10 +146,13 @@ struct cow {
unsigned long *bitmap;
unsigned long bitmap_len;
int bitmap_offset;
- int data_offset;
+ int data_offset;
};
+#define MAX_SG 64
+
struct ubd {
+ struct list_head restart;
/* name (and fd, below) of the file opened for writing, either the
* backing or the cow file. */
char *file;
@@ -165,15 +167,17 @@ struct ubd {
struct platform_device pdev;
struct request_queue *queue;
spinlock_t lock;
- int active;
+ struct scatterlist sg[MAX_SG];
+ struct request *request;
+ int start_sg, end_sg;
};
#define DEFAULT_COW { \
.file = NULL, \
- .fd = -1, \
- .bitmap = NULL, \
+ .fd = -1, \
+ .bitmap = NULL, \
.bitmap_offset = 0, \
- .data_offset = 0, \
+ .data_offset = 0, \
}
#define DEFAULT_UBD { \
@@ -183,11 +187,13 @@ struct ubd {
.size = -1, \
.boot_openflags = OPEN_FLAGS, \
.openflags = OPEN_FLAGS, \
- .no_cow = 0, \
+ .no_cow = 0, \
.shared = 0, \
- .cow = DEFAULT_COW, \
+ .cow = DEFAULT_COW, \
.lock = SPIN_LOCK_UNLOCKED, \
- .active = 0, \
+ .request = NULL, \
+ .start_sg = 0, \
+ .end_sg = 0, \
}
/* Protected by ubd_lock */
@@ -243,7 +249,7 @@ static void make_ide_entries(char *dev_name)
static int fake_ide_setup(char *str)
{
fake_ide = 1;
- return(1);
+ return 1;
}
__setup("fake_ide", fake_ide_setup);
@@ -261,7 +267,7 @@ static int parse_unit(char **ptr)
if(isdigit(*str)) {
n = simple_strtoul(str, &end, 0);
if(end == str)
- return(-1);
+ return -1;
*ptr = end;
}
else if (('a' <= *str) && (*str <= 'z')) {
@@ -269,7 +275,7 @@ static int parse_unit(char **ptr)
str++;
*ptr = str;
}
- return(n);
+ return n;
}
/* If *index_out == -1 at exit, the passed option was a general one;
@@ -436,7 +442,7 @@ static int udb_setup(char *str)
{
printk("udb%s specified on command line is almost certainly a ubd -> "
"udb TYPO\n", str);
- return(1);
+ return 1;
}
__setup("udb", udb_setup);
@@ -467,66 +473,75 @@ static void do_ubd_request(request_queue_t * q);
/* Only changed by ubd_init, which is an initcall. */
int thread_fd = -1;
-/* call ubd_finish if you need to serialize */
-static void __ubd_finish(struct request *req, int error)
+static void ubd_end_request(struct request *req, int bytes, int uptodate)
{
- int nsect;
-
- if(error){
- end_request(req, 0);
- return;
+ if (!end_that_request_first(req, uptodate, bytes >> 9)) {
+ struct ubd *dev = req->rq_disk->private_data;
+ unsigned long flags;
+
+ add_disk_randomness(req->rq_disk);
+ spin_lock_irqsave(&dev->lock, flags);
+ end_that_request_last(req, uptodate);
+ spin_unlock_irqrestore(&dev->lock, flags);
}
- nsect = req->current_nr_sectors;
- req->sector += nsect;
- req->buffer += nsect << 9;
- req->errors = 0;
- req->nr_sectors -= nsect;
- req->current_nr_sectors = 0;
- end_request(req, 1);
}
/* Callable only from interrupt context - otherwise you need to do
* spin_lock_irq()/spin_lock_irqsave() */
-static inline void ubd_finish(struct request *req, int error)
+static inline void ubd_finish(struct request *req, int bytes)
{
- struct ubd *dev = req->rq_disk->private_data;
-
- spin_lock(&dev->lock);
- __ubd_finish(req, error);
- spin_unlock(&dev->lock);
+ if(bytes < 0){
+ ubd_end_request(req, 0, 0);
+ return;
+ }
+ ubd_end_request(req, bytes, 1);
}
+static LIST_HEAD(restart);
+
/* XXX - move this inside ubd_intr. */
/* Called without dev->lock held, and only in interrupt context. */
static void ubd_handler(void)
{
- struct io_thread_req req;
+ struct io_thread_req *req;
struct request *rq;
- struct ubd *dev;
+ struct ubd *ubd;
+ struct list_head *list, *next_ele;
+ unsigned long flags;
int n;
- n = os_read_file(thread_fd, &req, sizeof(req));
- if(n != sizeof(req)){
- printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
- "err = %d\n", os_getpid(), -n);
- return;
- }
-
- rq = req.req;
- dev = rq->rq_disk->private_data;
- dev->active = 0;
+ while(1){
+ n = os_read_file(thread_fd, &req,
+ sizeof(struct io_thread_req *));
+ if(n != sizeof(req)){
+ if(n == -EAGAIN)
+ break;
+ printk(KERN_ERR "spurious interrupt in ubd_handler, "
+ "err = %d\n", -n);
+ return;
+ }
- ubd_finish(rq, req.error);
+ rq = req->req;
+ rq->nr_sectors -= req->length >> 9;
+ if(rq->nr_sectors == 0)
+ ubd_finish(rq, rq->hard_nr_sectors << 9);
+ kfree(req);
+ }
reactivate_fd(thread_fd, UBD_IRQ);
- spin_lock(&dev->lock);
- do_ubd_request(dev->queue);
- spin_unlock(&dev->lock);
+
+ list_for_each_safe(list, next_ele, &restart){
+ ubd = container_of(list, struct ubd, restart);
+ list_del_init(&ubd->restart);
+ spin_lock_irqsave(&ubd->lock, flags);
+ do_ubd_request(ubd->queue);
+ spin_unlock_irqrestore(&ubd->lock, flags);
+ }
}
static irqreturn_t ubd_intr(int irq, void *dev)
{
ubd_handler();
- return(IRQ_HANDLED);
+ return IRQ_HANDLED;
}
/* Only changed by ubd_init, which is an initcall. */
@@ -545,7 +560,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
char *file;
file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file;
- return(os_file_size(file, size_out));
+ return os_file_size(file, size_out);
}
static void ubd_close_dev(struct ubd *ubd_dev)
@@ -617,10 +632,18 @@ static int ubd_open_dev(struct ubd *ubd_dev)
if(err < 0) goto error;
ubd_dev->cow.fd = err;
}
- return(0);
+ return 0;
error:
os_close_file(ubd_dev->fd);
- return(err);
+ return err;
+}
+
+static void ubd_device_release(struct device *dev)
+{
+ struct ubd *ubd_dev = dev->driver_data;
+
+ blk_cleanup_queue(ubd_dev->queue);
+ *ubd_dev = ((struct ubd) DEFAULT_UBD);
}
static int ubd_disk_register(int major, u64 size, int unit,
@@ -630,7 +653,7 @@ static int ubd_disk_register(int major, u64 size, int unit,
disk = alloc_disk(1 << UBD_SHIFT);
if(disk == NULL)
- return(-ENOMEM);
+ return -ENOMEM;
disk->major = major;
disk->first_minor = unit << UBD_SHIFT;
@@ -645,6 +668,8 @@ static int ubd_disk_register(int major, u64 size, int unit,
if (major == MAJOR_NR) {
ubd_devs[unit].pdev.id = unit;
ubd_devs[unit].pdev.name = DRIVER_NAME;
+ ubd_devs[unit].pdev.dev.release = ubd_device_release;
+ ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit];
platform_device_register(&ubd_devs[unit].pdev);
disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
}
@@ -675,6 +700,8 @@ static int ubd_add(int n, char **error_out)
ubd_dev->size = ROUND_BLOCK(ubd_dev->size);
+ INIT_LIST_HEAD(&ubd_dev->restart);
+
err = -ENOMEM;
ubd_dev->queue = blk_init_queue(do_ubd_request, &ubd_dev->lock);
if (ubd_dev->queue == NULL) {
@@ -683,6 +710,7 @@ static int ubd_add(int n, char **error_out)
}
ubd_dev->queue->queuedata = ubd_dev;
+ blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
if(err){
*error_out = "Failed to register device";
@@ -730,14 +758,14 @@ static int ubd_config(char *str, char **error_out)
goto err_free;
}
- mutex_lock(&ubd_lock);
+ mutex_lock(&ubd_lock);
ret = ubd_add(n, error_out);
if (ret)
ubd_devs[n].file = NULL;
- mutex_unlock(&ubd_lock);
+ mutex_unlock(&ubd_lock);
out:
- return ret;
+ return ret;
err_free:
kfree(str);
@@ -752,7 +780,7 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out)
n = parse_unit(&name);
if((n >= MAX_DEV) || (n < 0)){
*error_out = "ubd_get_config : device number out of range";
- return(-1);
+ return -1;
}
ubd_dev = &ubd_devs[n];
@@ -773,29 +801,27 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out)
out:
mutex_unlock(&ubd_lock);
- return(len);
+ return len;
}
static int ubd_id(char **str, int *start_out, int *end_out)
{
- int n;
+ int n;
n = parse_unit(str);
- *start_out = 0;
- *end_out = MAX_DEV - 1;
- return n;
+ *start_out = 0;
+ *end_out = MAX_DEV - 1;
+ return n;
}
static int ubd_remove(int n, char **error_out)
{
+ struct gendisk *disk = ubd_gendisk[n];
struct ubd *ubd_dev;
int err = -ENODEV;
mutex_lock(&ubd_lock);
- if(ubd_gendisk[n] == NULL)
- goto out;
-
ubd_dev = &ubd_devs[n];
if(ubd_dev->file == NULL)
@@ -806,9 +832,11 @@ static int ubd_remove(int n, char **error_out)
if(ubd_dev->count > 0)
goto out;
- del_gendisk(ubd_gendisk[n]);
- put_disk(ubd_gendisk[n]);
ubd_gendisk[n] = NULL;
+ if(disk != NULL){
+ del_gendisk(disk);
+ put_disk(disk);
+ }
if(fake_gendisk[n] != NULL){
del_gendisk(fake_gendisk[n]);
@@ -816,10 +844,8 @@ static int ubd_remove(int n, char **error_out)
fake_gendisk[n] = NULL;
}
- blk_cleanup_queue(ubd_dev->queue);
- platform_device_unregister(&ubd_dev->pdev);
- *ubd_dev = ((struct ubd) DEFAULT_UBD);
err = 0;
+ platform_device_unregister(&ubd_dev->pdev);
out:
mutex_unlock(&ubd_lock);
return err;
@@ -832,7 +858,7 @@ static struct mc_device ubd_mc = {
.list = LIST_HEAD_INIT(ubd_mc.list),
.name = "ubd",
.config = ubd_config,
- .get_config = ubd_get_config,
+ .get_config = ubd_get_config,
.id = ubd_id,
.remove = ubd_remove,
};
@@ -854,7 +880,7 @@ static int __init ubd0_init(void)
ubd_dev->file = "root_fs";
mutex_unlock(&ubd_lock);
- return(0);
+ return 0;
}
__initcall(ubd0_init);
@@ -882,14 +908,14 @@ static int __init ubd_init(void)
return -1;
}
platform_driver_register(&ubd_driver);
- mutex_lock(&ubd_lock);
+ mutex_lock(&ubd_lock);
for (i = 0; i < MAX_DEV; i++){
err = ubd_add(i, &error);
if(err)
printk(KERN_ERR "Failed to initialize ubd device %d :"
"%s\n", i, error);
}
- mutex_unlock(&ubd_lock);
+ mutex_unlock(&ubd_lock);
return 0;
}
@@ -913,7 +939,7 @@ static int __init ubd_driver_init(void){
"ubd : Failed to start I/O thread (errno = %d) - "
"falling back to synchronous I/O\n", -io_pid);
io_pid = -1;
- return(0);
+ return 0;
}
err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr,
IRQF_DISABLED, "ubd", ubd_devs);
@@ -948,7 +974,7 @@ static int ubd_open(struct inode *inode, struct file *filp)
err = -EROFS;
}*/
out:
- return(err);
+ return err;
}
static int ubd_release(struct inode * inode, struct file * file)
@@ -958,7 +984,7 @@ static int ubd_release(struct inode * inode, struct file * file)
if(--ubd_dev->count == 0)
ubd_close_dev(ubd_dev);
- return(0);
+ return 0;
}
static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask,
@@ -1014,7 +1040,7 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
ubd_set_bit(i, (unsigned char *)
&req->sector_mask);
- }
+ }
}
else cowify_bitmap(req->offset, req->length, &req->sector_mask,
&req->cow_offset, bitmap, bitmap_offset,
@@ -1022,26 +1048,16 @@ static void cowify_req(struct io_thread_req *req, unsigned long *bitmap,
}
/* Called with dev->lock held */
-static int prepare_request(struct request *req, struct io_thread_req *io_req)
+static void prepare_request(struct request *req, struct io_thread_req *io_req,
+ unsigned long long offset, int page_offset,
+ int len, struct page *page)
{
struct gendisk *disk = req->rq_disk;
struct ubd *ubd_dev = disk->private_data;
- __u64 offset;
- int len;
-
- /* This should be impossible now */
- if((rq_data_dir(req) == WRITE) && !ubd_dev->openflags.w){
- printk("Write attempted on readonly ubd device %s\n",
- disk->disk_name);
- end_request(req, 0);
- return(1);
- }
-
- offset = ((__u64) req->sector) << 9;
- len = req->current_nr_sectors << 9;
io_req->req = req;
- io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd : ubd_dev->fd;
+ io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
+ ubd_dev->fd;
io_req->fds[1] = ubd_dev->fd;
io_req->cow_offset = -1;
io_req->offset = offset;
@@ -1052,45 +1068,66 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
io_req->offsets[0] = 0;
io_req->offsets[1] = ubd_dev->cow.data_offset;
- io_req->buffer = req->buffer;
+ io_req->buffer = page_address(page) + page_offset;
io_req->sectorsize = 1 << 9;
if(ubd_dev->cow.file != NULL)
- cowify_req(io_req, ubd_dev->cow.bitmap, ubd_dev->cow.bitmap_offset,
- ubd_dev->cow.bitmap_len);
+ cowify_req(io_req, ubd_dev->cow.bitmap,
+ ubd_dev->cow.bitmap_offset, ubd_dev->cow.bitmap_len);
- return(0);
}
/* Called with dev->lock held */
static void do_ubd_request(request_queue_t *q)
{
- struct io_thread_req io_req;
+ struct io_thread_req *io_req;
struct request *req;
- int err, n;
-
- if(thread_fd == -1){
- while((req = elv_next_request(q)) != NULL){
- err = prepare_request(req, &io_req);
- if(!err){
- do_io(&io_req);
- __ubd_finish(req, io_req.error);
- }
- }
- }
- else {
+ int n;
+
+ while(1){
struct ubd *dev = q->queuedata;
- if(dev->active || (req = elv_next_request(q)) == NULL)
- return;
- err = prepare_request(req, &io_req);
- if(!err){
- dev->active = 1;
- n = os_write_file(thread_fd, (char *) &io_req,
- sizeof(io_req));
- if(n != sizeof(io_req))
- printk("write to io thread failed, "
- "errno = %d\n", -n);
+ if(dev->end_sg == 0){
+ struct request *req = elv_next_request(q);
+ if(req == NULL)
+ return;
+
+ dev->request = req;
+ blkdev_dequeue_request(req);
+ dev->start_sg = 0;
+ dev->end_sg = blk_rq_map_sg(q, req, dev->sg);
}
+
+ req = dev->request;
+ while(dev->start_sg < dev->end_sg){
+ struct scatterlist *sg = &dev->sg[dev->start_sg];
+
+ io_req = kmalloc(sizeof(struct io_thread_req),
+ GFP_ATOMIC);
+ if(io_req == NULL){
+ if(list_empty(&dev->restart))
+ list_add(&dev->restart, &restart);
+ return;
+ }
+ prepare_request(req, io_req,
+ (unsigned long long) req->sector << 9,
+ sg->offset, sg->length, sg->page);
+
+ n = os_write_file(thread_fd, &io_req,
+ sizeof(struct io_thread_req *));
+ if(n != sizeof(struct io_thread_req *)){
+ if(n != -EAGAIN)
+ printk("write to io thread failed, "
+ "errno = %d\n", -n);
+ else if(list_empty(&dev->restart))
+ list_add(&dev->restart, &restart);
+ return;
+ }
+
+ req->sector += sg->length >> 9;
+ dev->start_sg++;
+ }
+ dev->end_sg = 0;
+ dev->request = NULL;
}
}
@@ -1120,21 +1157,21 @@ static int ubd_ioctl(struct inode * inode, struct file * file,
ubd_id.cyls = ubd_dev->size / (128 * 32 * 512);
if(copy_to_user((char __user *) arg, (char *) &ubd_id,
sizeof(ubd_id)))
- return(-EFAULT);
- return(0);
+ return -EFAULT;
+ return 0;
case CDROMVOLREAD:
if(copy_from_user(&volume, (char __user *) arg, sizeof(volume)))
- return(-EFAULT);
+ return -EFAULT;
volume.channel0 = 255;
volume.channel1 = 255;
volume.channel2 = 255;
volume.channel3 = 255;
if(copy_to_user((char __user *) arg, &volume, sizeof(volume)))
- return(-EFAULT);
- return(0);
+ return -EFAULT;
+ return 0;
}
- return(-EINVAL);
+ return -EINVAL;
}
static int path_requires_switch(char *from_cmdline, char *from_cow, char *cow)
@@ -1176,29 +1213,29 @@ static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
if(err < 0){
printk("Failed to get modification time of backing file "
"\"%s\", err = %d\n", file, -err);
- return(err);
+ return err;
}
err = os_file_size(file, &actual);
if(err < 0){
printk("Failed to get size of backing file \"%s\", "
"err = %d\n", file, -err);
- return(err);
+ return err;
}
- if(actual != size){
+ if(actual != size){
/*__u64 can be a long on AMD64 and with %lu GCC complains; so
* the typecast.*/
printk("Size mismatch (%llu vs %llu) of COW header vs backing "
"file\n", (unsigned long long) size, actual);
- return(-EINVAL);
+ return -EINVAL;
}
if(modtime != mtime){
printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
"file\n", mtime, modtime);
- return(-EINVAL);
+ return -EINVAL;
}
- return(0);
+ return 0;
}
int read_cow_bitmap(int fd, void *buf, int offset, int len)
@@ -1207,13 +1244,13 @@ int read_cow_bitmap(int fd, void *buf, int offset, int len)
err = os_seek_file(fd, offset);
if(err < 0)
- return(err);
+ return err;
err = os_read_file(fd, buf, len);
if(err < 0)
- return(err);
+ return err;
- return(0);
+ return 0;
}
int open_ubd_file(char *file, struct openflags *openflags, int shared,
@@ -1231,14 +1268,14 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared,
if (fd < 0) {
if ((fd == -ENOENT) && (create_cow_out != NULL))
*create_cow_out = 1;
- if (!openflags->w ||
- ((fd != -EROFS) && (fd != -EACCES)))
+ if (!openflags->w ||
+ ((fd != -EROFS) && (fd != -EACCES)))
return fd;
openflags->w = 0;
fd = os_open_file(file, *openflags, mode);
if (fd < 0)
return fd;
- }
+ }
if(shared)
printk("Not locking \"%s\" on the host\n", file);
@@ -1252,7 +1289,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared,
/* Successful return case! */
if(backing_file_out == NULL)
- return(fd);
+ return fd;
err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
&size, &sectorsize, &align, bitmap_offset_out);
@@ -1262,7 +1299,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared,
goto out_close;
}
if(err)
- return(fd);
+ return fd;
asked_switch = path_requires_switch(*backing_file_out, backing_file, file);
@@ -1285,7 +1322,7 @@ int open_ubd_file(char *file, struct openflags *openflags, int shared,
cow_sizes(version, size, sectorsize, align, *bitmap_offset_out,
bitmap_len_out, data_offset_out);
- return fd;
+ return fd;
out_close:
os_close_file(fd);
return err;
@@ -1310,10 +1347,10 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
bitmap_offset_out, bitmap_len_out,
data_offset_out);
if(!err)
- return(fd);
+ return fd;
os_close_file(fd);
out:
- return(err);
+ return err;
}
static int update_bitmap(struct io_thread_req *req)
@@ -1321,23 +1358,23 @@ static int update_bitmap(struct io_thread_req *req)
int n;
if(req->cow_offset == -1)
- return(0);
+ return 0;
n = os_seek_file(req->fds[1], req->cow_offset);
if(n < 0){
printk("do_io - bitmap lseek failed : err = %d\n", -n);
- return(1);
+ return 1;
}
n = os_write_file(req->fds[1], &req->bitmap_words,
- sizeof(req->bitmap_words));
+ sizeof(req->bitmap_words));
if(n != sizeof(req->bitmap_words)){
printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
req->fds[1]);
- return(1);
+ return 1;
}
- return(0);
+ return 0;
}
void do_io(struct io_thread_req *req)
@@ -1409,13 +1446,14 @@ static int io_count = 0;
int io_thread(void *arg)
{
- struct io_thread_req req;
+ struct io_thread_req *req;
int n;
ignore_sigwinch_sig();
while(1){
- n = os_read_file(kernel_fd, &req, sizeof(req));
- if(n != sizeof(req)){
+ n = os_read_file(kernel_fd, &req,
+ sizeof(struct io_thread_req *));
+ if(n != sizeof(struct io_thread_req *)){
if(n < 0)
printk("io_thread - read failed, fd = %d, "
"err = %d\n", kernel_fd, -n);
@@ -1426,9 +1464,10 @@ int io_thread(void *arg)
continue;
}
io_count++;
- do_io(&req);
- n = os_write_file(kernel_fd, &req, sizeof(req));
- if(n != sizeof(req))
+ do_io(req);
+ n = os_write_file(kernel_fd, &req,
+ sizeof(struct io_thread_req *));
+ if(n != sizeof(struct io_thread_req *))
printk("io_thread - write failed, fd = %d, err = %d\n",
kernel_fd, -n);
}
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index b94d2bc4fe0..4707b3f14c2 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -16,7 +16,6 @@
#include <sys/mman.h>
#include <sys/param.h>
#include "asm/types.h"
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "ubd_user.h"
@@ -47,8 +46,8 @@ int start_io_thread(unsigned long sp, int *fd_out)
pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
NULL);
if(pid < 0){
- printk("start_io_thread - clone failed : errno = %d\n", errno);
err = -errno;
+ printk("start_io_thread - clone failed : errno = %d\n", errno);
goto out_close;
}
@@ -60,16 +59,5 @@ int start_io_thread(unsigned long sp, int *fd_out)
kernel_fd = -1;
*fd_out = -1;
out:
- return(err);
+ return err;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 850221d9b4c..571c2b3325d 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -14,7 +14,6 @@
#include <sys/socket.h>
#include "kern_util.h"
#include "chan_user.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
#include "xterm.h"
diff --git a/arch/um/include/arch.h b/arch/um/include/arch.h
new file mode 100644
index 00000000000..10ad52daa8c
--- /dev/null
+++ b/arch/um/include/arch.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __ARCH_H__
+#define __ARCH_H__
+
+#include "sysdep/ptrace.h"
+
+extern void arch_check_bugs(void);
+extern int arch_fixup(unsigned long address, union uml_pt_regs *regs);
+extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
+
+#endif
diff --git a/arch/um/include/as-layout.h b/arch/um/include/as-layout.h
new file mode 100644
index 00000000000..fccf187bf4e
--- /dev/null
+++ b/arch/um/include/as-layout.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __START_H__
+#define __START_H__
+
+#include "sysdep/ptrace.h"
+
+struct cpu_task {
+ int pid;
+ void *task;
+};
+
+extern struct cpu_task cpu_tasks[];
+
+extern unsigned long low_physmem;
+extern unsigned long high_physmem;
+extern unsigned long uml_physmem;
+extern unsigned long uml_reserved;
+extern unsigned long end_vm;
+extern unsigned long start_vm;
+extern unsigned long long highmem;
+
+extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
+extern unsigned long _unprotected_end;
+extern unsigned long brk_start;
+
+extern int linux_main(int argc, char **argv);
+extern void set_cmdline(char *cmd);
+
+extern void (*sig_info[])(int, union uml_pt_regs *);
+
+#endif
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 461175f8b1d..5593a802708 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -24,5 +24,7 @@ DEFINE(UM_ELF_CLASS, ELF_CLASS);
DEFINE(UM_ELFCLASS32, ELFCLASS32);
DEFINE(UM_ELFCLASS64, ELFCLASS64);
+DEFINE(UM_NR_CPUS, NR_CPUS);
+
/* For crypto assembler code. */
DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 173af029d12..50a49691e0e 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -8,6 +8,7 @@
#include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h"
+#include "uml-config.h"
typedef void (*kern_hndl)(int, union uml_pt_regs *);
@@ -23,7 +24,6 @@ struct kern_handlers {
extern const struct kern_handlers handlinfo_kern;
extern int ncpus;
-extern char *linux_prog;
extern char *gdb_init;
extern int kmalloc_ok;
extern int jail;
@@ -34,7 +34,9 @@ extern int nsyscalls;
UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1)
extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg);
+#ifdef UML_CONFIG_MODE_TT
extern unsigned long stack_sp(unsigned long page);
+#endif
extern int kernel_thread_proc(void *data);
extern void syscall_segv(int sig);
extern int current_pid(void);
@@ -42,7 +44,7 @@ extern unsigned long alloc_stack(int order, int atomic);
extern int do_signal(void);
extern int is_stack_fault(unsigned long sp);
extern unsigned long segv(struct faultinfo fi, unsigned long ip,
- int is_user, void *sc);
+ int is_user, union uml_pt_regs *regs);
extern int handle_page_fault(unsigned long address, unsigned long ip,
int is_write, int is_user, int *code_out);
extern void syscall_ready(void);
@@ -50,7 +52,6 @@ extern void set_tracing(void *t, int tracing);
extern int is_tracing(void *task);
extern int segv_syscall(void);
extern void kern_finish_exec(void *task, int new_pid, unsigned long stack);
-extern int page_size(void);
extern unsigned long page_mask(void);
extern int need_finish_fork(void);
extern void free_stack(unsigned long stack, int order);
@@ -58,7 +59,6 @@ extern void add_input_request(int op, void (*proc)(int), void *arg);
extern char *current_cmd(void);
extern void timer_handler(int sig, union uml_pt_regs *regs);
extern int set_signals(int enable);
-extern void force_sigbus(void);
extern int pid_to_processor_id(int pid);
extern void deliver_signals(void *t);
extern int next_trap_index(int max);
@@ -70,7 +70,6 @@ extern void *syscall_sp(void *t);
extern void syscall_trace(union uml_pt_regs *regs, int entryexit);
extern int hz(void);
extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
-extern int external_pid(void *t);
extern void interrupt_end(void);
extern void initial_thread_cb(void (*proc)(void *), void *arg);
extern int debugger_signal(int status, int pid);
@@ -81,7 +80,6 @@ extern int init_parent_proxy(int pid);
extern int singlestepping(void *t);
extern void check_stack_overflow(void *ptr);
extern void relay_signal(int sig, union uml_pt_regs *regs);
-extern void not_implemented(void);
extern int user_context(unsigned long sp);
extern void timer_irq(union uml_pt_regs *regs);
extern void unprotect_stack(unsigned long stack);
@@ -93,7 +91,6 @@ extern char *uml_strdup(char *string);
extern void unprotect_kernel_mem(void);
extern void protect_kernel_mem(void);
extern void uml_cleanup(void);
-extern void set_current(void *t);
extern void lock_signalled_task(void *t);
extern void IPI_handler(int cpu);
extern int jail_setup(char *line, int *add);
@@ -118,4 +115,6 @@ extern void time_init_kern(void);
extern int __cant_sleep(void);
extern void sigio_handler(int sig, union uml_pt_regs *regs);
+extern void copy_sc(union uml_pt_regs *regs, void *from);
+
#endif
diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
index 125ab42df18..9237056b910 100644
--- a/arch/um/include/net_kern.h
+++ b/arch/um/include/net_kern.h
@@ -40,7 +40,7 @@ struct uml_net_private {
void (*add_address)(unsigned char *, unsigned char *, void *);
void (*delete_address)(unsigned char *, unsigned char *, void *);
int (*set_mtu)(int mtu, void *);
- int user[1];
+ char user[0];
};
struct net_kern_info {
diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
index 19f207cd70f..cfe7c50634b 100644
--- a/arch/um/include/net_user.h
+++ b/arch/um/include/net_user.h
@@ -14,7 +14,7 @@
#define UML_NET_VERSION (4)
struct net_user_info {
- void (*init)(void *, void *);
+ int (*init)(void *, void *);
int (*open)(void *);
void (*close)(int, void *);
void (*remove)(void *);
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 5c74da41045..688d181b5f8 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -16,6 +16,8 @@
#include "sysdep/tls.h"
#include "sysdep/archsetjmp.h"
+#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
+
#define OS_TYPE_FILE 1
#define OS_TYPE_DIR 2
#define OS_TYPE_SYMLINK 3
@@ -273,8 +275,9 @@ extern void stack_protections(unsigned long address);
extern void task_protections(unsigned long address);
extern int raw(int fd);
extern void setup_machinename(char *machine_out);
-extern void setup_hostinfo(void);
+extern void setup_hostinfo(char *buf, int len);
extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
+extern void os_dump_core(void);
/* time.c */
#define BILLION (1000 * 1000 * 1000)
@@ -297,13 +300,12 @@ extern long syscall_stub_data(struct mm_id * mm_idp,
unsigned long *data, int data_count,
void **addr, void **stub_addr);
extern int map(struct mm_id * mm_idp, unsigned long virt,
- unsigned long len, int r, int w, int x, int phys_fd,
+ unsigned long len, int prot, int phys_fd,
unsigned long long offset, int done, void **data);
-extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len,
+extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
int done, void **data);
extern int protect(struct mm_id * mm_idp, unsigned long addr,
- unsigned long len, int r, int w, int x, int done,
- void **data);
+ unsigned long len, unsigned int prot, int done, void **data);
/* skas/process.c */
extern int is_skas_winch(int pid, int fd, void *data);
@@ -339,8 +341,11 @@ extern void maybe_sigio_broken(int fd, int read);
/* skas/trap */
extern void sig_handler_common_skas(int sig, void *sc_ptr);
-extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
+/* sys-x86_64/prctl.c */
extern int os_arch_prctl(int pid, int code, unsigned long *addr);
+/* tty.c */
+int get_pty(void);
+
#endif
diff --git a/arch/um/include/skas/mode_kern_skas.h b/arch/um/include/skas/mode_kern_skas.h
index 9cd9c6ec9a6..8ee6285dfac 100644
--- a/arch/um/include/skas/mode_kern_skas.h
+++ b/arch/um/include/skas/mode_kern_skas.h
@@ -33,6 +33,8 @@ extern unsigned long set_task_sizes_skas(unsigned long *task_size_out);
extern int start_uml_skas(void);
extern int external_pid_skas(struct task_struct *task);
extern int thread_pid_skas(struct task_struct *task);
+extern void flush_tlb_page_skas(struct vm_area_struct *vma,
+ unsigned long address);
#define kmem_end_skas (host_task_size - 1024 * 1024)
diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h
index 11bafab669e..0f312085ce1 100644
--- a/arch/um/include/sysdep-i386/archsetjmp.h
+++ b/arch/um/include/sysdep-i386/archsetjmp.h
@@ -1,5 +1,5 @@
/*
- * arch/i386/include/klibc/archsetjmp.h
+ * arch/um/include/sysdep-i386/archsetjmp.h
*/
#ifndef _KLIBC_ARCHSETJMP_H
diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h
index 9a5e1a6ec80..2af8f12ca16 100644
--- a/arch/um/include/sysdep-x86_64/archsetjmp.h
+++ b/arch/um/include/sysdep-x86_64/archsetjmp.h
@@ -1,5 +1,5 @@
/*
- * arch/x86_64/include/klibc/archsetjmp.h
+ * arch/um/include/sysdep-x86_64/archsetjmp.h
*/
#ifndef _KLIBC_ARCHSETJMP_H
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index 8efc1e0f1b8..bcd1a4afb84 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -14,9 +14,7 @@ struct host_vm_op {
struct {
unsigned long addr;
unsigned long len;
- unsigned int r:1;
- unsigned int w:1;
- unsigned int x:1;
+ unsigned int prot;
int fd;
__u64 offset;
} mmap;
@@ -27,9 +25,7 @@ struct host_vm_op {
struct {
unsigned long addr;
unsigned long len;
- unsigned int r:1;
- unsigned int w:1;
- unsigned int x:1;
+ unsigned int prot;
} mprotect;
} u;
};
diff --git a/arch/um/include/tt/uaccess-tt.h b/arch/um/include/tt/uaccess-tt.h
index b19645f32f2..13a64f61fcf 100644
--- a/arch/um/include/tt/uaccess-tt.h
+++ b/arch/um/include/tt/uaccess-tt.h
@@ -27,8 +27,6 @@ extern unsigned long uml_physmem;
#define access_ok_tt(type, addr, size) \
(is_stack(addr, size))
-extern unsigned long get_fault_addr(void);
-
extern int __do_copy_from_user(void *to, const void *from, int n,
void **fault_addr, void **fault_catcher);
extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h
index 0363a9b53f8..e6d7c5aa3f4 100644
--- a/arch/um/include/um_malloc.h
+++ b/arch/um/include/um_malloc.h
@@ -11,7 +11,6 @@ extern void *um_kmalloc_atomic(int size);
extern void kfree(const void *ptr);
extern void *um_vmalloc(int size);
-extern void *um_vmalloc_atomic(int size);
extern void vfree(void *ptr);
#endif /* __UM_MALLOC_H__ */
diff --git a/arch/um/include/user.h b/arch/um/include/user.h
index acadce3f271..d380e6d91a9 100644
--- a/arch/um/include/user.h
+++ b/arch/um/include/user.h
@@ -6,6 +6,19 @@
#ifndef __USER_H__
#define __USER_H__
+/*
+ * The usual definition - copied here because the kernel provides its own,
+ * fancier, type-safe, definition. Using that one would require
+ * copying too much infrastructure for my taste, so userspace files
+ * get less checking than kernel files.
+ */
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * This will provide the size_t definition in both kernel and userspace builds
+ */
+#include <linux/types.h>
+
extern void panic(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
extern int printk(const char *fmt, ...)
@@ -13,19 +26,7 @@ extern int printk(const char *fmt, ...)
extern void schedule(void);
extern int in_aton(char *str);
extern int open_gdb_chan(void);
-/* These use size_t, however unsigned long is correct on both i386 and x86_64. */
-extern unsigned long strlcpy(char *, const char *, unsigned long);
-extern unsigned long strlcat(char *, const char *, unsigned long);
+extern size_t strlcpy(char *, const char *, size_t);
+extern size_t strlcat(char *, const char *, size_t);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
deleted file mode 100644
index 023575f6734..00000000000
--- a/arch/um/include/user_util.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __USER_UTIL_H__
-#define __USER_UTIL_H__
-
-#include "sysdep/ptrace.h"
-
-/* Copied from kernel.h */
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-#define CATCH_EINTR(expr) while ((errno = 0, ((expr) < 0)) && (errno == EINTR))
-
-extern int mode_tt;
-
-extern int grantpt(int __fd);
-extern int unlockpt(int __fd);
-extern char *ptsname(int __fd);
-
-struct cpu_task {
- int pid;
- void *task;
-};
-
-extern struct cpu_task cpu_tasks[];
-
-extern void (*sig_info[])(int, union uml_pt_regs *);
-
-extern unsigned long low_physmem;
-extern unsigned long high_physmem;
-extern unsigned long uml_physmem;
-extern unsigned long uml_reserved;
-extern unsigned long end_vm;
-extern unsigned long start_vm;
-extern unsigned long long highmem;
-
-extern char host_info[];
-
-extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end;
-extern unsigned long _unprotected_end;
-extern unsigned long brk_start;
-
-extern int pty_output_sigio;
-extern int pty_close_sigio;
-
-extern void *add_signal_handler(int sig, void (*handler)(int));
-extern int linux_main(int argc, char **argv);
-extern void set_cmdline(char *cmd);
-extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
-extern int get_pty(void);
-extern int switcheroo(int fd, int prot, void *from, void *to, int size);
-extern void do_exec(int old_pid, int new_pid);
-extern void tracer_panic(char *msg, ...)
- __attribute__ ((format (printf, 1, 2)));
-extern int detach(int pid, int sig);
-extern int attach(int pid);
-extern void kill_child_dead(int pid);
-extern int cont(int pid);
-extern void check_sigio(void);
-extern void arch_check_bugs(void);
-extern int cpu_feature(char *what, char *buf, int len);
-extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
-extern int arch_fixup(unsigned long address, void *sc_ptr);
-extern void arch_init_thread(void);
-extern int raw(int fd);
-
-#endif
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index 121166400e2..356e50f5aae 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -10,8 +10,8 @@
#include "asm/pgtable.h"
#include "asm/tlbflush.h"
#include "asm/uaccess.h"
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
#include "mem_user.h"
#include "kern.h"
#include "irq_user.h"
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index 8cde431348c..cda91aa8e70 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -10,7 +10,6 @@
#include "linux/mqueue.h"
#include "asm/uaccess.h"
#include "asm/pgtable.h"
-#include "user_util.h"
#include "mem_user.h"
#include "os.h"
diff --git a/arch/um/kernel/initrd.c b/arch/um/kernel/initrd.c
index 82ecf904b09..16dc43e9d94 100644
--- a/arch/um/kernel/initrd.c
+++ b/arch/um/kernel/initrd.c
@@ -7,7 +7,6 @@
#include "linux/bootmem.h"
#include "linux/initrd.h"
#include "asm/types.h"
-#include "user_util.h"
#include "kern_util.h"
#include "initrd.h"
#include "init.h"
@@ -22,12 +21,20 @@ static int __init read_initrd(void)
long long size;
int err;
- if(initrd == NULL) return 0;
+ if(initrd == NULL)
+ return 0;
+
err = os_file_size(initrd, &size);
- if(err) return 0;
+ if(err)
+ return 0;
+
area = alloc_bootmem(size);
- if(area == NULL) return 0;
- if(load_initrd(initrd, area, size) == -1) return 0;
+ if(area == NULL)
+ return 0;
+
+ if(load_initrd(initrd, area, size) == -1)
+ return 0;
+
initrd_start = (unsigned long) area;
initrd_end = initrd_start + size;
return 0;
@@ -54,25 +61,15 @@ int load_initrd(char *filename, void *buf, int size)
fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
if(fd < 0){
printk("Opening '%s' failed - err = %d\n", filename, -fd);
- return(-1);
+ return -1;
}
n = os_read_file(fd, buf, size);
if(n != size){
printk("Read of %d bytes from '%s' failed, err = %d\n", size,
filename, -n);
- return(-1);
+ return -1;
}
os_close_file(fd);
- return(0);
+ return 0;
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index dbf2f5bc842..8f2ed369031 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -25,7 +25,6 @@
#include "asm/system.h"
#include "asm/errno.h"
#include "asm/uaccess.h"
-#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
#include "irq_kern.h"
@@ -79,6 +78,14 @@ skip:
return 0;
}
+/*
+ * This list is accessed under irq_lock, except in sigio_handler,
+ * where it is safe from being modified. IRQ handlers won't change it -
+ * if an IRQ source has vanished, it will be freed by free_irqs just
+ * before returning from sigio_handler. That will process a separate
+ * list of irqs to free, with its own locking, coming back here to
+ * remove list elements, taking the irq_lock to do so.
+ */
static struct irq_fd *active_fds = NULL;
static struct irq_fd **last_irq_ptr = &active_fds;
@@ -244,6 +251,7 @@ void free_irq_by_fd(int fd)
free_irq_by_cb(same_fd, &fd);
}
+/* Must be called with irq_lock held */
static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out)
{
struct irq_fd *irq;
@@ -309,6 +317,12 @@ void deactivate_fd(int fd, int irqnum)
ignore_sigio_fd(fd);
}
+/*
+ * Called just before shutdown in order to provide a clean exec
+ * environment in case the system is rebooting. No locking because
+ * that would cause a pointless shutdown hang if something hadn't
+ * released the lock.
+ */
int deactivate_all_fds(void)
{
struct irq_fd *irq;
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index 0e00cf93f90..7b3e53fb807 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -16,7 +16,7 @@
#include "asm/page.h"
#include "asm/tlbflush.h"
#include "kern_util.h"
-#include "user_util.h"
+#include "as-layout.h"
#include "mem_user.h"
#include "os.h"
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index df7d662b98c..72ff85693a3 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -13,8 +13,8 @@
#include "asm/page.h"
#include "asm/fixmap.h"
#include "asm/pgalloc.h"
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
#include "kern.h"
#include "mem_user.h"
#include "uml_uaccess.h"
@@ -216,7 +216,7 @@ static void __init fixaddr_user_init( void)
#endif
}
-void paging_init(void)
+void __init paging_init(void)
{
unsigned long zones_size[MAX_NR_ZONES], vaddr;
int i;
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 638f3b5f609..3ba6e4c841d 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -13,7 +13,7 @@
#include "asm/types.h"
#include "asm/pgtable.h"
#include "kern_util.h"
-#include "user_util.h"
+#include "as-layout.h"
#include "mode_kern.h"
#include "mem.h"
#include "mem_user.h"
@@ -21,229 +21,8 @@
#include "kern.h"
#include "init.h"
-struct phys_desc {
- struct rb_node rb;
- int fd;
- __u64 offset;
- void *virt;
- unsigned long phys;
- struct list_head list;
-};
-
-static struct rb_root phys_mappings = RB_ROOT;
-
-static struct rb_node **find_rb(void *virt)
-{
- struct rb_node **n = &phys_mappings.rb_node;
- struct phys_desc *d;
-
- while(*n != NULL){
- d = rb_entry(*n, struct phys_desc, rb);
- if(d->virt == virt)
- return n;
-
- if(d->virt > virt)
- n = &(*n)->rb_left;
- else
- n = &(*n)->rb_right;
- }
-
- return n;
-}
-
-static struct phys_desc *find_phys_mapping(void *virt)
-{
- struct rb_node **n = find_rb(virt);
-
- if(*n == NULL)
- return NULL;
-
- return rb_entry(*n, struct phys_desc, rb);
-}
-
-static void insert_phys_mapping(struct phys_desc *desc)
-{
- struct rb_node **n = find_rb(desc->virt);
-
- if(*n != NULL)
- panic("Physical remapping for %p already present",
- desc->virt);
-
- rb_link_node(&desc->rb, rb_parent(*n), n);
- rb_insert_color(&desc->rb, &phys_mappings);
-}
-
-LIST_HEAD(descriptor_mappings);
-
-struct desc_mapping {
- int fd;
- struct list_head list;
- struct list_head pages;
-};
-
-static struct desc_mapping *find_mapping(int fd)
-{
- struct desc_mapping *desc;
- struct list_head *ele;
-
- list_for_each(ele, &descriptor_mappings){
- desc = list_entry(ele, struct desc_mapping, list);
- if(desc->fd == fd)
- return desc;
- }
-
- return NULL;
-}
-
-static struct desc_mapping *descriptor_mapping(int fd)
-{
- struct desc_mapping *desc;
-
- desc = find_mapping(fd);
- if(desc != NULL)
- return desc;
-
- desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if(desc == NULL)
- return NULL;
-
- *desc = ((struct desc_mapping)
- { .fd = fd,
- .list = LIST_HEAD_INIT(desc->list),
- .pages = LIST_HEAD_INIT(desc->pages) });
- list_add(&desc->list, &descriptor_mappings);
-
- return desc;
-}
-
-int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
-{
- struct desc_mapping *fd_maps;
- struct phys_desc *desc;
- unsigned long phys;
- int err;
-
- fd_maps = descriptor_mapping(fd);
- if(fd_maps == NULL)
- return -ENOMEM;
-
- phys = __pa(virt);
- desc = find_phys_mapping(virt);
- if(desc != NULL)
- panic("Address 0x%p is already substituted\n", virt);
-
- err = -ENOMEM;
- desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if(desc == NULL)
- goto out;
-
- *desc = ((struct phys_desc)
- { .fd = fd,
- .offset = offset,
- .virt = virt,
- .phys = __pa(virt),
- .list = LIST_HEAD_INIT(desc->list) });
- insert_phys_mapping(desc);
-
- list_add(&desc->list, &fd_maps->pages);
-
- virt = (void *) ((unsigned long) virt & PAGE_MASK);
- err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
- if(!err)
- goto out;
-
- rb_erase(&desc->rb, &phys_mappings);
- kfree(desc);
- out:
- return err;
-}
-
static int physmem_fd = -1;
-static void remove_mapping(struct phys_desc *desc)
-{
- void *virt = desc->virt;
- int err;
-
- rb_erase(&desc->rb, &phys_mappings);
- list_del(&desc->list);
- kfree(desc);
-
- err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
- if(err)
- panic("Failed to unmap block device page from physical memory, "
- "errno = %d", -err);
-}
-
-int physmem_remove_mapping(void *virt)
-{
- struct phys_desc *desc;
-
- virt = (void *) ((unsigned long) virt & PAGE_MASK);
- desc = find_phys_mapping(virt);
- if(desc == NULL)
- return 0;
-
- remove_mapping(desc);
- return 1;
-}
-
-void physmem_forget_descriptor(int fd)
-{
- struct desc_mapping *desc;
- struct phys_desc *page;
- struct list_head *ele, *next;
- __u64 offset;
- void *addr;
- int err;
-
- desc = find_mapping(fd);
- if(desc == NULL)
- return;
-
- list_for_each_safe(ele, next, &desc->pages){
- page = list_entry(ele, struct phys_desc, list);
- offset = page->offset;
- addr = page->virt;
- remove_mapping(page);
- err = os_seek_file(fd, offset);
- if(err)
- panic("physmem_forget_descriptor - failed to seek "
- "to %lld in fd %d, error = %d\n",
- offset, fd, -err);
- err = os_read_file(fd, addr, PAGE_SIZE);
- if(err < 0)
- panic("physmem_forget_descriptor - failed to read "
- "from fd %d to 0x%p, error = %d\n",
- fd, addr, -err);
- }
-
- list_del(&desc->list);
- kfree(desc);
-}
-
-EXPORT_SYMBOL(physmem_forget_descriptor);
-EXPORT_SYMBOL(physmem_remove_mapping);
-EXPORT_SYMBOL(physmem_subst_mapping);
-
-void arch_free_page(struct page *page, int order)
-{
- void *virt;
- int i;
-
- for(i = 0; i < (1 << order); i++){
- virt = __va(page_to_phys(page + i));
- physmem_remove_mapping(virt);
- }
-}
-
-int is_remapped(void *virt)
-{
- struct phys_desc *desc = find_phys_mapping(virt);
-
- return desc != NULL;
-}
-
/* Changed during early boot */
unsigned long high_physmem;
@@ -350,14 +129,9 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
int phys_mapping(unsigned long phys, __u64 *offset_out)
{
- struct phys_desc *desc = find_phys_mapping(__va(phys & PAGE_MASK));
int fd = -1;
- if(desc != NULL){
- fd = desc->fd;
- *offset_out = desc->offset;
- }
- else if(phys < physmem_size){
+ if(phys < physmem_size){
fd = physmem_fd;
*offset_out = phys;
}
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 348b272bb76..8d2c5496532 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,8 +32,8 @@
#include "asm/tlbflush.h"
#include "asm/uaccess.h"
#include "asm/user.h"
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
#include "kern.h"
#include "signal_kern.h"
#include "init.h"
@@ -54,11 +54,9 @@
*/
struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } };
-int external_pid(void *t)
+static inline int external_pid(struct task_struct *task)
{
- struct task_struct *task = t ? t : current;
-
- return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task));
+ return CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task);
}
int pid_to_processor_id(int pid)
@@ -66,9 +64,10 @@ int pid_to_processor_id(int pid)
int i;
for(i = 0; i < ncpus; i++){
- if(cpu_tasks[i].pid == pid) return(i);
+ if(cpu_tasks[i].pid == pid)
+ return i;
}
- return(-1);
+ return -1;
}
void free_stack(unsigned long stack, int order)
@@ -85,9 +84,9 @@ unsigned long alloc_stack(int order, int atomic)
flags = GFP_ATOMIC;
page = __get_free_pages(flags, order);
if(page == 0)
- return(0);
+ return 0;
stack_protections(page);
- return(page);
+ return page;
}
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
@@ -98,15 +97,11 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
current->thread.request.u.thread.arg = arg;
pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
&current->thread.regs, 0, NULL, NULL);
- if(pid < 0)
- panic("do_fork failed in kernel_thread, errno = %d", pid);
- return(pid);
+ return pid;
}
-void set_current(void *t)
+static inline void set_current(struct task_struct *task)
{
- struct task_struct *task = t;
-
cpu_tasks[task_thread_info(task)->cpu] = ((struct cpu_task)
{ external_pid(task), task });
}
@@ -128,14 +123,16 @@ void *_switch_to(void *prev, void *next, void *last)
prev= current;
} while(current->thread.saved_task);
- return(current->thread.prev_sched);
+ return current->thread.prev_sched;
}
void interrupt_end(void)
{
- if(need_resched()) schedule();
- if(test_tsk_thread_flag(current, TIF_SIGPENDING)) do_signal();
+ if(need_resched())
+ schedule();
+ if(test_tsk_thread_flag(current, TIF_SIGPENDING))
+ do_signal();
}
void release_thread(struct task_struct *task)
@@ -150,7 +147,7 @@ void exit_thread(void)
void *get_current(void)
{
- return(current);
+ return current;
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
@@ -188,15 +185,12 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
kmalloc_ok = save_kmalloc_ok;
}
+#ifdef CONFIG_MODE_TT
unsigned long stack_sp(unsigned long page)
{
- return(page + PAGE_SIZE - sizeof(void *));
-}
-
-int current_pid(void)
-{
- return(current->pid);
+ return page + PAGE_SIZE - sizeof(void *);
}
+#endif
void default_idle(void)
{
@@ -221,11 +215,6 @@ void cpu_idle(void)
CHOOSE_MODE(init_idle_tt(), init_idle_skas());
}
-int page_size(void)
-{
- return(PAGE_SIZE);
-}
-
void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t *pte_out)
{
@@ -236,68 +225,43 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t ptent;
if(task->mm == NULL)
- return(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
pgd = pgd_offset(task->mm, addr);
if(!pgd_present(*pgd))
- return(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
pud = pud_offset(pgd, addr);
if(!pud_present(*pud))
- return(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
pmd = pmd_offset(pud, addr);
if(!pmd_present(*pmd))
- return(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
pte = pte_offset_kernel(pmd, addr);
ptent = *pte;
if(!pte_present(ptent))
- return(ERR_PTR(-EINVAL));
+ return ERR_PTR(-EINVAL);
if(pte_out != NULL)
*pte_out = ptent;
- return((void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK));
+ return (void *) (pte_val(ptent) & PAGE_MASK) + (addr & ~PAGE_MASK);
}
char *current_cmd(void)
{
#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM)
- return("(Unknown)");
+ return "(Unknown)";
#else
void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL);
return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr);
#endif
}
-void force_sigbus(void)
-{
- printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
- current->pid);
- lock_kernel();
- sigaddset(&current->pending.signal, SIGBUS);
- recalc_sigpending();
- current->flags |= PF_SIGNALED;
- do_exit(SIGBUS | 0x80);
-}
-
void dump_thread(struct pt_regs *regs, struct user *u)
{
}
-void enable_hlt(void)
-{
- panic("enable_hlt");
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
-void disable_hlt(void)
-{
- panic("disable_hlt");
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
void *um_kmalloc(int size)
{
return kmalloc(size, GFP_KERNEL);
@@ -313,36 +277,17 @@ void *um_vmalloc(int size)
return vmalloc(size);
}
-void *um_vmalloc_atomic(int size)
-{
- return __vmalloc(size, GFP_ATOMIC | __GFP_HIGHMEM, PAGE_KERNEL);
-}
-
int __cant_sleep(void) {
return in_atomic() || irqs_disabled() || in_interrupt();
/* Is in_interrupt() really needed? */
}
-unsigned long get_fault_addr(void)
-{
- return((unsigned long) current->thread.fault_addr);
-}
-
-EXPORT_SYMBOL(get_fault_addr);
-
-void not_implemented(void)
-{
- printk(KERN_DEBUG "Something isn't implemented in here\n");
-}
-
-EXPORT_SYMBOL(not_implemented);
-
int user_context(unsigned long sp)
{
unsigned long stack;
stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
- return(stack != (unsigned long) current_thread);
+ return stack != (unsigned long) current_thread;
}
extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end;
@@ -363,22 +308,22 @@ char *uml_strdup(char *string)
int copy_to_user_proc(void __user *to, void *from, int size)
{
- return(copy_to_user(to, from, size));
+ return copy_to_user(to, from, size);
}
int copy_from_user_proc(void *to, void __user *from, int size)
{
- return(copy_from_user(to, from, size));
+ return copy_from_user(to, from, size);
}
int clear_user_proc(void __user *buf, int size)
{
- return(clear_user(buf, size));
+ return clear_user(buf, size);
}
int strlen_user_proc(char __user *str)
{
- return(strlen_user(str));
+ return strlen_user(str);
}
int smp_sigio_handler(void)
@@ -387,14 +332,14 @@ int smp_sigio_handler(void)
int cpu = current_thread->cpu;
IPI_handler(cpu);
if(cpu != 0)
- return(1);
+ return 1;
#endif
- return(0);
+ return 0;
}
int cpu(void)
{
- return(current_thread->cpu);
+ return current_thread->cpu;
}
static atomic_t using_sysemu = ATOMIC_INIT(0);
@@ -443,7 +388,7 @@ int __init make_proc_sysemu(void)
if (ent == NULL)
{
printk(KERN_WARNING "Failed to register /proc/sysemu\n");
- return(0);
+ return 0;
}
ent->read_proc = proc_read_sysemu;
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index f602623644a..7e4305a1fd3 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -6,7 +6,6 @@
#include "linux/module.h"
#include "linux/sched.h"
#include "asm/smp.h"
-#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
#include "os.h"
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 3c798cdde55..c4020c3d785 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -17,7 +17,6 @@
#include "asm/signal.h"
#include "asm/uaccess.h"
#include "asm/unistd.h"
-#include "user_util.h"
#include "asm/ucontext.h"
#include "kern_util.h"
#include "signal_kern.h"
diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c
index 54b79595137..580eb646894 100644
--- a/arch/um/kernel/skas/exec.c
+++ b/arch/um/kernel/skas/exec.c
@@ -17,7 +17,17 @@
void flush_thread_skas(void)
{
- force_flush_all();
+ void *data = NULL;
+ unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+ int ret;
+
+ ret = unmap(&current->mm->context.skas.id, 0, end, 1, &data);
+ if(ret){
+ printk("flush_thread_skas - clearing address space failed, "
+ "err = %d\n", ret);
+ force_sig(SIGKILL, current);
+ }
+
switch_mm_skas(&current->mm->context.skas.id);
}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index ae4fa71d3b8..a96ae1a0610 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -13,9 +13,9 @@
#include "asm/uaccess.h"
#include "asm/atomic.h"
#include "kern_util.h"
+#include "as-layout.h"
#include "skas.h"
#include "os.h"
-#include "user_util.h"
#include "tlb.h"
#include "kern.h"
#include "mode.h"
@@ -178,20 +178,23 @@ int start_uml_skas(void)
int external_pid_skas(struct task_struct *task)
{
-#warning Need to look up userspace_pid by cpu
+ /* FIXME: Need to look up userspace_pid by cpu */
return(userspace_pid[0]);
}
int thread_pid_skas(struct task_struct *task)
{
-#warning Need to look up userspace_pid by cpu
+ /* FIXME: Need to look up userspace_pid by cpu */
return(userspace_pid[0]);
}
void kill_off_processes_skas(void)
{
if(proc_mm)
-#warning need to loop over userspace_pids in kill_off_processes_skas
+ /*
+ * FIXME: need to loop over userspace_pids in
+ * kill_off_processes_skas
+ */
os_kill_ptraced_process(userspace_pid[0], 1);
else {
struct task_struct *p;
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 27eb29ce666..c0f0693743b 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -10,7 +10,6 @@
#include "asm/page.h"
#include "asm/pgtable.h"
#include "asm/mmu.h"
-#include "user_util.h"
#include "mem_user.h"
#include "mem.h"
#include "skas.h"
@@ -28,19 +27,17 @@ static int do_ops(union mm_context *mmu, struct host_vm_op *ops, int last,
switch(op->type){
case MMAP:
ret = map(&mmu->skas.id, op->u.mmap.addr,
- op->u.mmap.len, op->u.mmap.r, op->u.mmap.w,
- op->u.mmap.x, op->u.mmap.fd,
- op->u.mmap.offset, finished, flush);
+ op->u.mmap.len, op->u.mmap.prot,
+ op->u.mmap.fd, op->u.mmap.offset, finished,
+ flush);
break;
case MUNMAP:
- ret = unmap(&mmu->skas.id,
- (void *) op->u.munmap.addr,
+ ret = unmap(&mmu->skas.id, op->u.munmap.addr,
op->u.munmap.len, finished, flush);
break;
case MPROTECT:
ret = protect(&mmu->skas.id, op->u.mprotect.addr,
- op->u.mprotect.len, op->u.mprotect.r,
- op->u.mprotect.w, op->u.mprotect.x,
+ op->u.mprotect.len, op->u.mprotect.prot,
finished, flush);
break;
default:
@@ -92,6 +89,76 @@ void flush_tlb_mm_skas(struct mm_struct *mm)
void force_flush_all_skas(void)
{
- unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
- fix_range(current->mm, 0, end, 1);
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma = mm->mmap;
+
+ while(vma != NULL) {
+ fix_range(mm, vma->vm_start, vma->vm_end, 1);
+ vma = vma->vm_next;
+ }
+}
+
+void flush_tlb_page_skas(struct vm_area_struct *vma, unsigned long address)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ struct mm_struct *mm = vma->vm_mm;
+ void *flush = NULL;
+ int r, w, x, prot, err = 0;
+ struct mm_id *mm_id;
+
+ pgd = pgd_offset(mm, address);
+ if(!pgd_present(*pgd))
+ goto kill;
+
+ pud = pud_offset(pgd, address);
+ if(!pud_present(*pud))
+ goto kill;
+
+ pmd = pmd_offset(pud, address);
+ if(!pmd_present(*pmd))
+ goto kill;
+
+ pte = pte_offset_kernel(pmd, address);
+
+ r = pte_read(*pte);
+ w = pte_write(*pte);
+ x = pte_exec(*pte);
+ if (!pte_young(*pte)) {
+ r = 0;
+ w = 0;
+ } else if (!pte_dirty(*pte)) {
+ w = 0;
+ }
+
+ mm_id = &mm->context.skas.id;
+ prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+ (x ? UM_PROT_EXEC : 0));
+ if(pte_newpage(*pte)){
+ if(pte_present(*pte)){
+ unsigned long long offset;
+ int fd;
+
+ fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
+ err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
+ 1, &flush);
+ }
+ else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
+ }
+ else if(pte_newprot(*pte))
+ err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
+
+ if(err)
+ goto kill;
+
+ *pte = pte_mkuptodate(*pte);
+
+ return;
+
+kill:
+ printk("Failed to flush page for address 0x%lx\n", address);
+ force_sig(SIGKILL, current);
}
+
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 759b0705316..e6a7778006a 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -21,7 +21,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
#include "asm/smp.h"
#include "asm/processor.h"
#include "asm/spinlock.h"
-#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
#include "irq_user.h"
@@ -90,7 +89,7 @@ static int idle_proc(void *cpup)
cpu_set(cpu, cpu_online_map);
default_idle();
- return(0);
+ return 0;
}
static struct task_struct *idle_thread(int cpu)
@@ -98,8 +97,8 @@ static struct task_struct *idle_thread(int cpu)
struct task_struct *new_task;
unsigned char c;
- current->thread.request.u.thread.proc = idle_proc;
- current->thread.request.u.thread.arg = (void *) cpu;
+ current->thread.request.u.thread.proc = idle_proc;
+ current->thread.request.u.thread.arg = (void *) cpu;
new_task = fork_idle(cpu);
if(IS_ERR(new_task))
panic("copy_process failed in idle_thread, error = %ld",
@@ -110,9 +109,9 @@ static struct task_struct *idle_thread(int cpu)
.task = new_task } );
idle_threads[cpu] = new_task;
CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
- sizeof(c)),
+ sizeof(c)),
({ panic("skas mode doesn't support SMP"); }));
- return(new_task);
+ return new_task;
}
void smp_prepare_cpus(unsigned int maxcpus)
@@ -163,13 +162,13 @@ int __cpu_up(unsigned int cpu)
cpu_set(cpu, smp_commenced_mask);
while (!cpu_isset(cpu, cpu_online_map))
mb();
- return(0);
+ return 0;
}
int setup_profiling_timer(unsigned int multiplier)
{
printk(KERN_INFO "setup_profiling_timer\n");
- return(0);
+ return 0;
}
void smp_call_function_slave(int cpu);
@@ -205,7 +204,7 @@ void IPI_handler(int cpu)
int hard_smp_processor_id(void)
{
- return(pid_to_processor_id(os_getpid()));
+ return pid_to_processor_id(os_getpid());
}
static DEFINE_SPINLOCK(call_lock);
@@ -254,14 +253,3 @@ int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic,
}
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index 2828c528322..237c4eab7cf 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -18,7 +18,6 @@
#include "asm/mman.h"
#include "asm/uaccess.h"
#include "kern_util.h"
-#include "user_util.h"
#include "sysdep/syscalls.h"
#include "mode_kern.h"
#include "choose-mode.h"
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index f9e02b31a97..93263571d81 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -10,7 +10,6 @@
#include "asm/page.h"
#include "asm/processor.h"
#include "sysrq.h"
-#include "user_util.h"
/* Catch non-i386 SUBARCH's. */
#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT)
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index b1f8b075241..259c49da7ff 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -18,7 +18,6 @@
#include "asm/param.h"
#include "asm/current.h"
#include "kern_util.h"
-#include "user_util.h"
#include "mode.h"
#include "os.h"
@@ -35,8 +34,8 @@ unsigned long long sched_clock(void)
return (unsigned long long)jiffies_64 * (1000000000 / HZ);
}
-static unsigned long long prev_nsecs[NR_CPUS];
#ifdef CONFIG_UML_REAL_TIME_CLOCK
+static unsigned long long prev_nsecs[NR_CPUS];
static long long delta[NR_CPUS]; /* Deviation per interval */
#endif
@@ -95,7 +94,12 @@ irqreturn_t um_timer(int irq, void *dev)
do_timer(1);
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
nsecs = get_time();
+#else
+ nsecs = (unsigned long long) xtime.tv_sec * BILLION + xtime.tv_nsec +
+ BILLION / HZ;
+#endif
xtime.tv_sec = nsecs / NSEC_PER_SEC;
xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
@@ -128,13 +132,18 @@ void time_init(void)
nsecs = os_nsecs();
set_normalized_timespec(&wall_to_monotonic, -nsecs / BILLION,
-nsecs % BILLION);
+ set_normalized_timespec(&xtime, nsecs / BILLION, nsecs % BILLION);
late_time_init = register_timer;
}
void do_gettimeofday(struct timeval *tv)
{
+#ifdef CONFIG_UML_REAL_TIME_CLOCK
unsigned long long nsecs = get_time();
-
+#else
+ unsigned long long nsecs = (unsigned long long) xtime.tv_sec * BILLION +
+ xtime.tv_nsec;
+#endif
tv->tv_sec = nsecs / NSEC_PER_SEC;
/* Careful about calculations here - this was originally done as
* (nsecs - tv->tv_sec * NSEC_PER_SEC) / NSEC_PER_USEC
@@ -168,6 +177,8 @@ int do_settimeofday(struct timespec *tv)
void timer_handler(int sig, union uml_pt_regs *regs)
{
+ if(current_thread->cpu == 0)
+ timer_irq(regs);
local_irq_disable();
irq_enter();
update_process_times(CHOOSE_MODE(
@@ -175,6 +186,4 @@ void timer_handler(int sig, union uml_pt_regs *regs)
(regs)->skas.is_user));
irq_exit();
local_irq_enable();
- if(current_thread->cpu == 0)
- timer_irq(regs);
}
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 54a5ff25645..8a8d5285144 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -6,17 +6,18 @@
#include "linux/mm.h"
#include "asm/page.h"
#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
#include "asm/tlbflush.h"
#include "choose-mode.h"
#include "mode_kern.h"
-#include "user_util.h"
+#include "as-layout.h"
#include "tlb.h"
#include "mem.h"
#include "mem_user.h"
#include "os.h"
static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int *index,
+ unsigned int prot, struct host_vm_op *ops, int *index,
int last_filled, union mm_context *mmu, void **flush,
int (*do_ops)(union mm_context *, struct host_vm_op *,
int, int, void **))
@@ -30,8 +31,7 @@ static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
last = &ops[*index];
if((last->type == MMAP) &&
(last->u.mmap.addr + last->u.mmap.len == virt) &&
- (last->u.mmap.r == r) && (last->u.mmap.w == w) &&
- (last->u.mmap.x == x) && (last->u.mmap.fd == fd) &&
+ (last->u.mmap.prot == prot) && (last->u.mmap.fd == fd) &&
(last->u.mmap.offset + last->u.mmap.len == offset)){
last->u.mmap.len += len;
return 0;
@@ -47,9 +47,7 @@ static int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
.u = { .mmap = {
.addr = virt,
.len = len,
- .r = r,
- .w = w,
- .x = x,
+ .prot = prot,
.fd = fd,
.offset = offset }
} });
@@ -86,8 +84,8 @@ static int add_munmap(unsigned long addr, unsigned long len,
return ret;
}
-static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
- int x, struct host_vm_op *ops, int *index,
+static int add_mprotect(unsigned long addr, unsigned long len,
+ unsigned int prot, struct host_vm_op *ops, int *index,
int last_filled, union mm_context *mmu, void **flush,
int (*do_ops)(union mm_context *, struct host_vm_op *,
int, int, void **))
@@ -99,8 +97,7 @@ static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
last = &ops[*index];
if((last->type == MPROTECT) &&
(last->u.mprotect.addr + last->u.mprotect.len == addr) &&
- (last->u.mprotect.r == r) && (last->u.mprotect.w == w) &&
- (last->u.mprotect.x == x)){
+ (last->u.mprotect.prot == prot)){
last->u.mprotect.len += len;
return 0;
}
@@ -115,114 +112,145 @@ static int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
.u = { .mprotect = {
.addr = addr,
.len = len,
- .r = r,
- .w = w,
- .x = x } } });
+ .prot = prot } } });
return ret;
}
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
+static inline int update_pte_range(pmd_t *pmd, unsigned long addr,
+ unsigned long end, struct host_vm_op *ops,
+ int last_op, int *op_index, int force,
+ union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *,
+ struct host_vm_op *, int, int,
+ void **))
+{
+ pte_t *pte;
+ int r, w, x, prot, ret = 0;
+
+ pte = pte_offset_kernel(pmd, addr);
+ do {
+ r = pte_read(*pte);
+ w = pte_write(*pte);
+ x = pte_exec(*pte);
+ if (!pte_young(*pte)) {
+ r = 0;
+ w = 0;
+ } else if (!pte_dirty(*pte)) {
+ w = 0;
+ }
+ prot = ((r ? UM_PROT_READ : 0) | (w ? UM_PROT_WRITE : 0) |
+ (x ? UM_PROT_EXEC : 0));
+ if(force || pte_newpage(*pte)){
+ if(pte_present(*pte))
+ ret = add_mmap(addr, pte_val(*pte) & PAGE_MASK,
+ PAGE_SIZE, prot, ops, op_index,
+ last_op, mmu, flush, do_ops);
+ else ret = add_munmap(addr, PAGE_SIZE, ops, op_index,
+ last_op, mmu, flush, do_ops);
+ }
+ else if(pte_newprot(*pte))
+ ret = add_mprotect(addr, PAGE_SIZE, prot, ops, op_index,
+ last_op, mmu, flush, do_ops);
+ *pte = pte_mkuptodate(*pte);
+ } while (pte++, addr += PAGE_SIZE, ((addr != end) && !ret));
+ return ret;
+}
+
+static inline int update_pmd_range(pud_t *pud, unsigned long addr,
+ unsigned long end, struct host_vm_op *ops,
+ int last_op, int *op_index, int force,
+ union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *,
+ struct host_vm_op *, int, int,
+ void **))
+{
+ pmd_t *pmd;
+ unsigned long next;
+ int ret = 0;
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ next = pmd_addr_end(addr, end);
+ if(!pmd_present(*pmd)){
+ if(force || pmd_newpage(*pmd)){
+ ret = add_munmap(addr, next - addr, ops,
+ op_index, last_op, mmu,
+ flush, do_ops);
+ pmd_mkuptodate(*pmd);
+ }
+ }
+ else ret = update_pte_range(pmd, addr, next, ops, last_op,
+ op_index, force, mmu, flush,
+ do_ops);
+ } while (pmd++, addr = next, ((addr != end) && !ret));
+ return ret;
+}
+
+static inline int update_pud_range(pgd_t *pgd, unsigned long addr,
+ unsigned long end, struct host_vm_op *ops,
+ int last_op, int *op_index, int force,
+ union mm_context *mmu, void **flush,
+ int (*do_ops)(union mm_context *,
+ struct host_vm_op *, int, int,
+ void **))
+{
+ pud_t *pud;
+ unsigned long next;
+ int ret = 0;
+
+ pud = pud_offset(pgd, addr);
+ do {
+ next = pud_addr_end(addr, end);
+ if(!pud_present(*pud)){
+ if(force || pud_newpage(*pud)){
+ ret = add_munmap(addr, next - addr, ops,
+ op_index, last_op, mmu,
+ flush, do_ops);
+ pud_mkuptodate(*pud);
+ }
+ }
+ else ret = update_pmd_range(pud, addr, next, ops, last_op,
+ op_index, force, mmu, flush,
+ do_ops);
+ } while (pud++, addr = next, ((addr != end) && !ret));
+ return ret;
+}
+
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force,
int (*do_ops)(union mm_context *, struct host_vm_op *,
int, int, void **))
{
- pgd_t *npgd;
- pud_t *npud;
- pmd_t *npmd;
- pte_t *npte;
+ pgd_t *pgd;
union mm_context *mmu = &mm->context;
- unsigned long addr, end;
- int r, w, x;
struct host_vm_op ops[1];
+ unsigned long addr = start_addr, next;
+ int ret = 0, last_op = ARRAY_SIZE(ops) - 1, op_index = -1;
void *flush = NULL;
- int op_index = -1, last_op = ARRAY_SIZE(ops) - 1;
- int ret = 0;
-
- if(mm == NULL)
- return;
ops[0].type = NONE;
- for(addr = start_addr; addr < end_addr && !ret;){
- npgd = pgd_offset(mm, addr);
- if(!pgd_present(*npgd)){
- end = ADD_ROUND(addr, PGDIR_SIZE);
- if(end > end_addr)
- end = end_addr;
- if(force || pgd_newpage(*npgd)){
- ret = add_munmap(addr, end - addr, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- pgd_mkuptodate(*npgd);
- }
- addr = end;
- continue;
- }
-
- npud = pud_offset(npgd, addr);
- if(!pud_present(*npud)){
- end = ADD_ROUND(addr, PUD_SIZE);
- if(end > end_addr)
- end = end_addr;
- if(force || pud_newpage(*npud)){
- ret = add_munmap(addr, end - addr, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- pud_mkuptodate(*npud);
- }
- addr = end;
- continue;
- }
-
- npmd = pmd_offset(npud, addr);
- if(!pmd_present(*npmd)){
- end = ADD_ROUND(addr, PMD_SIZE);
- if(end > end_addr)
- end = end_addr;
- if(force || pmd_newpage(*npmd)){
- ret = add_munmap(addr, end - addr, ops,
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end_addr);
+ if(!pgd_present(*pgd)){
+ if (force || pgd_newpage(*pgd)){
+ ret = add_munmap(addr, next - addr, ops,
&op_index, last_op, mmu,
&flush, do_ops);
- pmd_mkuptodate(*npmd);
+ pgd_mkuptodate(*pgd);
}
- addr = end;
- continue;
- }
-
- npte = pte_offset_kernel(npmd, addr);
- r = pte_read(*npte);
- w = pte_write(*npte);
- x = pte_exec(*npte);
- if (!pte_young(*npte)) {
- r = 0;
- w = 0;
- } else if (!pte_dirty(*npte)) {
- w = 0;
- }
- if(force || pte_newpage(*npte)){
- if(pte_present(*npte))
- ret = add_mmap(addr,
- pte_val(*npte) & PAGE_MASK,
- PAGE_SIZE, r, w, x, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
- else ret = add_munmap(addr, PAGE_SIZE, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
}
- else if(pte_newprot(*npte))
- ret = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
- &op_index, last_op, mmu,
- &flush, do_ops);
+ else ret = update_pud_range(pgd, addr, next, ops, last_op,
+ &op_index, force, mmu, &flush,
+ do_ops);
+ } while (pgd++, addr = next, ((addr != end_addr) && !ret));
- *npte = pte_mkuptodate(*npte);
- addr += PAGE_SIZE;
- }
if(!ret)
ret = (*do_ops)(mmu, ops, op_index, 1, &flush);
-/* This is not an else because ret is modified above */
+ /* This is not an else because ret is modified above */
if(ret) {
printk("fix_range_common: failed, killing current process\n");
force_sig(SIGKILL, current);
@@ -343,12 +371,6 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
return(pte_offset_map(pmd, addr));
}
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
-}
-
void flush_tlb_all(void)
{
flush_tlb_mm(current->mm);
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 26f15c45857..abab90c3803 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -18,8 +18,9 @@
#include "asm/current.h"
#include "asm/irq.h"
#include "sysdep/sigcontext.h"
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
+#include "arch.h"
#include "kern.h"
#include "chan_kern.h"
#include "mconsole_kern.h"
@@ -71,8 +72,8 @@ good_area:
goto out;
/* Don't require VM_READ|VM_EXEC for write faults! */
- if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto out;
+ if(!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
+ goto out;
do {
survive:
@@ -156,20 +157,23 @@ static void segv_handler(int sig, union uml_pt_regs *regs)
* the info in the regs. A pointer to the info then would
* give us bad data!
*/
-unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
+unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
+ union uml_pt_regs *regs)
{
struct siginfo si;
void *catcher;
int err;
- int is_write = FAULT_WRITE(fi);
- unsigned long address = FAULT_ADDRESS(fi);
+ int is_write = FAULT_WRITE(fi);
+ unsigned long address = FAULT_ADDRESS(fi);
- if(!is_user && (address >= start_vm) && (address < end_vm)){
- flush_tlb_kernel_vm();
- return(0);
- }
- else if(current->mm == NULL)
- panic("Segfault with no mm");
+ if(!is_user && (address >= start_vm) && (address < end_vm)){
+ flush_tlb_kernel_vm();
+ return 0;
+ }
+ else if(current->mm == NULL) {
+ show_regs(container_of(regs, struct pt_regs, regs));
+ panic("Segfault with no mm");
+ }
if (SEGV_IS_FIXABLE(&fi) || SEGV_MAYBE_FIXABLE(&fi))
err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
@@ -182,26 +186,28 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
catcher = current->thread.fault_catcher;
if(!err)
- return(0);
+ return 0;
else if(catcher != NULL){
current->thread.fault_addr = (void *) address;
do_longjmp(catcher, 1);
}
else if(current->thread.fault_addr != NULL)
panic("fault_addr set but no fault catcher");
- else if(!is_user && arch_fixup(ip, sc))
- return(0);
+ else if(!is_user && arch_fixup(ip, regs))
+ return 0;
- if(!is_user)
+ if(!is_user) {
+ show_regs(container_of(regs, struct pt_regs, regs));
panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
address, ip);
+ }
if (err == -EACCES) {
si.si_signo = SIGBUS;
si.si_errno = 0;
si.si_code = BUS_ADRERR;
si.si_addr = (void __user *)address;
- current->thread.arch.faultinfo = fi;
+ current->thread.arch.faultinfo = fi;
force_sig_info(SIGBUS, &si, current);
} else if (err == -ENOMEM) {
printk("VM: killing process %s\n", current->comm);
@@ -210,10 +216,10 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc)
BUG_ON(err != -EFAULT);
si.si_signo = SIGSEGV;
si.si_addr = (void __user *) address;
- current->thread.arch.faultinfo = fi;
+ current->thread.arch.faultinfo = fi;
force_sig_info(SIGSEGV, &si, current);
}
- return(0);
+ return 0;
}
void relay_signal(int sig, union uml_pt_regs *regs)
@@ -223,12 +229,12 @@ void relay_signal(int sig, union uml_pt_regs *regs)
if(!UPT_IS_USER(regs)){
if(sig == SIGBUS)
- printk("Bus error - the /dev/shm or /tmp mount likely "
- "just ran out of space\n");
+ printk("Bus error - the host /dev/shm or /tmp mount "
+ "likely just ran out of space\n");
panic("Kernel mode signal %d", sig);
}
- current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
+ current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
force_sig(sig, current);
}
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
index ad66df17d9d..98e21743e60 100644
--- a/arch/um/kernel/tt/exec_kern.c
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -10,7 +10,6 @@
#include "asm/uaccess.h"
#include "asm/pgalloc.h"
#include "asm/tlbflush.h"
-#include "user_util.h"
#include "kern_util.h"
#include "irq_user.h"
#include "mem_user.h"
diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c
index a92c02ff2ce..7b5f2181cf5 100644
--- a/arch/um/kernel/tt/exec_user.c
+++ b/arch/um/kernel/tt/exec_user.c
@@ -10,7 +10,6 @@
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "ptrace_user.h"
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
index 8eba8f7dca6..030e4658f36 100644
--- a/arch/um/kernel/tt/gdb.c
+++ b/arch/um/kernel/tt/gdb.c
@@ -17,7 +17,6 @@
#include "user.h"
#include "debug.h"
#include "kern_util.h"
-#include "user_util.h"
#include "tt.h"
#include "sysdep/thread.h"
#include "os.h"
@@ -115,6 +114,8 @@ struct gdb_data {
int err;
};
+extern char *linux_prog;
+
static void config_gdb_cb(void *arg)
{
struct gdb_data *data = arg;
diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h
deleted file mode 100644
index 2a35b15c5fe..00000000000
--- a/arch/um/kernel/tt/include/mode_kern-tt.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#ifndef __TT_MODE_KERN_H__
-#define __TT_MODE_KERN_H__
-
-#include "linux/sched.h"
-#include "asm/page.h"
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-
-extern void switch_to_tt(void *prev, void *next);
-extern void flush_thread_tt(void);
-extern void start_thread_tt(struct pt_regs *regs, unsigned long eip,
- unsigned long esp);
-extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
- unsigned long stack_top, struct task_struct *p,
- struct pt_regs *regs);
-extern void release_thread_tt(struct task_struct *task);
-extern void initial_thread_cb_tt(void (*proc)(void *), void *arg);
-extern void init_idle_tt(void);
-extern void flush_tlb_kernel_range_tt(unsigned long start, unsigned long end);
-extern void flush_tlb_kernel_vm_tt(void);
-extern void __flush_tlb_one_tt(unsigned long addr);
-extern void flush_tlb_range_tt(struct vm_area_struct *vma,
- unsigned long start, unsigned long end);
-extern void flush_tlb_mm_tt(struct mm_struct *mm);
-extern void force_flush_all_tt(void);
-extern long execute_syscall_tt(void *r);
-extern void before_mem_tt(unsigned long brk_start);
-extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out,
- unsigned long *task_size_out);
-extern int start_uml_tt(void);
-extern int external_pid_tt(struct task_struct *task);
-extern int thread_pid_tt(struct task_struct *task);
-
-#define kmem_end_tt (host_task_size - ABOVE_KMEM)
-
-#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
index 4d1929dfa28..d0c3c4975f2 100644
--- a/arch/um/kernel/tt/mem.c
+++ b/arch/um/kernel/tt/mem.c
@@ -8,7 +8,6 @@
#include "asm/uaccess.h"
#include "mem_user.h"
#include "kern_util.h"
-#include "user_util.h"
#include "kern.h"
#include "tt.h"
diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
index 03e58989538..9774f6360c3 100644
--- a/arch/um/kernel/tt/mem_user.c
+++ b/arch/um/kernel/tt/mem_user.c
@@ -11,7 +11,6 @@
#include <sys/mman.h>
#include "tt.h"
#include "mem_user.h"
-#include "user_util.h"
#include "os.h"
void remap_data(void *segment_start, void *segment_end, int w)
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 1e86f0bfef7..c631303cb80 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -14,7 +14,6 @@
#include "asm/tlbflush.h"
#include "irq_user.h"
#include "kern_util.h"
-#include "user_util.h"
#include "os.h"
#include "kern.h"
#include "sigcontext.h"
@@ -65,7 +64,8 @@ void switch_to_tt(void *prev, void *next)
if(from->thread.mode.tt.switch_pipe[0] == -1)
os_kill_process(os_getpid(), 0);
- err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c));
+ err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c,
+ sizeof(c));
if(err != sizeof(c))
panic("read of switch_pipe failed, errno = %d", -err);
diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
index 58800c50b10..420c23f311f 100644
--- a/arch/um/kernel/tt/ptproxy/proxy.c
+++ b/arch/um/kernel/tt/ptproxy/proxy.c
@@ -26,7 +26,6 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml
#include "sysdep.h"
#include "wait.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
#include "tempfile.h"
@@ -339,11 +338,12 @@ int start_debugger(char *prog, int startup, int stop, int *fd_out)
"err = %d\n", -fd);
exit(1);
}
- os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+ os_write_file(fd, gdb_init_string,
+ sizeof(gdb_init_string) - 1);
if(startup){
if(stop){
os_write_file(fd, "b start_kernel\n",
- strlen("b start_kernel\n"));
+ strlen("b start_kernel\n"));
}
os_write_file(fd, "c\n", strlen("c\n"));
}
diff --git a/arch/um/kernel/tt/ptproxy/ptrace.c b/arch/um/kernel/tt/ptproxy/ptrace.c
index 03774427d46..4b4f6179b21 100644
--- a/arch/um/kernel/tt/ptproxy/ptrace.c
+++ b/arch/um/kernel/tt/ptproxy/ptrace.c
@@ -16,7 +16,6 @@ Jeff Dike (jdike@karaya.com) : Modified for integration into uml
#include "ptproxy.h"
#include "debug.h"
-#include "user_util.h"
#include "kern_util.h"
#include "ptrace_user.h"
#include "tt.h"
diff --git a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
index 99f178319d0..e0e1ab0588a 100644
--- a/arch/um/kernel/tt/ptproxy/sysdep.c
+++ b/arch/um/kernel/tt/ptproxy/sysdep.c
@@ -13,7 +13,6 @@ terms and conditions.
#include <sys/types.h>
#include <linux/unistd.h>
#include "ptrace_user.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
diff --git a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
index 12f6319d8d7..bdd4af4b65f 100644
--- a/arch/um/kernel/tt/ptproxy/wait.c
+++ b/arch/um/kernel/tt/ptproxy/wait.c
@@ -13,7 +13,6 @@ terms and conditions.
#include "ptproxy.h"
#include "sysdep.h"
#include "wait.h"
-#include "user_util.h"
#include "ptrace_user.h"
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
diff --git a/arch/um/kernel/tt/syscall_user.c b/arch/um/kernel/tt/syscall_user.c
index 902987bf379..f52b47aff1d 100644
--- a/arch/um/kernel/tt/syscall_user.c
+++ b/arch/um/kernel/tt/syscall_user.c
@@ -11,7 +11,6 @@
#include "sigcontext.h"
#include "ptrace_user.h"
#include "task.h"
-#include "user_util.h"
#include "kern_util.h"
#include "syscall.h"
#include "tt.h"
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index ae6217c8613..7caa24fe05d 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -12,7 +12,6 @@
#include "asm/pgtable.h"
#include "asm/uaccess.h"
#include "asm/tlbflush.h"
-#include "user_util.h"
#include "mem_user.h"
#include "os.h"
#include "tlb.h"
diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
index b9195355075..c23588393f6 100644
--- a/arch/um/kernel/tt/tracer.c
+++ b/arch/um/kernel/tt/tracer.c
@@ -19,7 +19,6 @@
#include "sigcontext.h"
#include "sysdep/sigcontext.h"
#include "os.h"
-#include "user_util.h"
#include "mem_user.h"
#include "process.h"
#include "kern_util.h"
diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c
index b5d9d64d91e..3032eb5e246 100644
--- a/arch/um/kernel/tt/trap_user.c
+++ b/arch/um/kernel/tt/trap_user.c
@@ -8,7 +8,6 @@
#include <signal.h>
#include "sysdep/ptrace.h"
#include "sysdep/sigcontext.h"
-#include "user_util.h"
#include "kern_util.h"
#include "task.h"
#include "tt.h"
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
index ed1abcf4d05..0e5c82c5e5b 100644
--- a/arch/um/kernel/tt/uaccess_user.c
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -5,7 +5,6 @@
*/
#include <string.h>
-#include "user_util.h"
#include "uml_uaccess.h"
#include "task.h"
#include "kern_util.h"
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 89c6dba731f..1cf954a47fd 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -17,6 +17,7 @@
#include "linux/seq_file.h"
#include "linux/delay.h"
#include "linux/module.h"
+#include "linux/utsname.h"
#include "asm/page.h"
#include "asm/pgtable.h"
#include "asm/ptrace.h"
@@ -25,8 +26,9 @@
#include "asm/setup.h"
#include "ubd_user.h"
#include "asm/current.h"
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
+#include "arch.h"
#include "kern.h"
#include "mem_user.h"
#include "mem.h"
@@ -42,7 +44,7 @@
#define DEFAULT_COMMAND_LINE "root=98:0"
-/* Changed in linux_main and setup_arch, which run before SMP is started */
+/* Changed in add_arg and setup_arch, which run before SMP is started */
static char __initdata command_line[COMMAND_LINE_SIZE] = { 0 };
static void __init add_arg(char *arg)
@@ -56,17 +58,25 @@ static void __init add_arg(char *arg)
strcat(command_line, arg);
}
-struct cpuinfo_um boot_cpu_data = {
+/*
+ * These fields are initialized at boot time and not changed.
+ * XXX This structure is used only in the non-SMP case. Maybe this
+ * should be moved to smp.c.
+ */
+struct cpuinfo_um boot_cpu_data = {
.loops_per_jiffy = 0,
.ipi_pipe = { -1, -1 }
};
unsigned long thread_saved_pc(struct task_struct *task)
{
- return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
- task)));
+ return os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
+ task));
}
+/* Changed in setup_arch, which is called in early boot */
+static char host_info[(__NEW_UTS_LEN + 1) * 5];
+
static int show_cpuinfo(struct seq_file *m, void *v)
{
int index = 0;
@@ -86,7 +96,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ)) % 100);
- return(0);
+ return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
@@ -114,14 +124,12 @@ const struct seq_operations cpuinfo_op = {
/* Set in linux_main */
unsigned long host_task_size;
unsigned long task_size;
-
-unsigned long uml_start;
-
-/* Set in early boot */
unsigned long uml_physmem;
-unsigned long uml_reserved;
+unsigned long uml_reserved; /* Also modified in mem_init */
unsigned long start_vm;
unsigned long end_vm;
+
+/* Set in uml_ncpus_setup */
int ncpus = 1;
#ifdef CONFIG_CMDLINE_ON_HOST
@@ -135,6 +143,8 @@ static char *argv1_end = NULL;
/* Set in early boot */
static int have_root __initdata = 0;
+
+/* Set in uml_mem_setup and modified in linux_main */
long long physmem_size = 32 * 1024 * 1024;
void set_cmdline(char *cmd)
@@ -212,12 +222,12 @@ __uml_setup("debug", no_skas_debug_setup,
#ifdef CONFIG_SMP
static int __init uml_ncpus_setup(char *line, int *add)
{
- if (!sscanf(line, "%d", &ncpus)) {
- printf("Couldn't parse [%s]\n", line);
- return -1;
- }
+ if (!sscanf(line, "%d", &ncpus)) {
+ printf("Couldn't parse [%s]\n", line);
+ return -1;
+ }
- return 0;
+ return 0;
}
__uml_setup("ncpus=", uml_ncpus_setup,
@@ -234,7 +244,7 @@ static int force_tt = 0;
static int __init mode_tt_setup(char *line, int *add)
{
force_tt = 1;
- return(0);
+ return 0;
}
#else
@@ -245,7 +255,7 @@ static int __init mode_tt_setup(char *line, int *add)
static int __init mode_tt_setup(char *line, int *add)
{
printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
- return(0);
+ return 0;
}
#else
@@ -256,7 +266,7 @@ static int __init mode_tt_setup(char *line, int *add)
static int __init mode_tt_setup(char *line, int *add)
{
printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
- return(0);
+ return 0;
}
#endif
@@ -274,16 +284,15 @@ int mode_tt = DEFAULT_TT;
static int __init Usage(char *line, int *add)
{
- const char **p;
+ const char **p;
printf(usage_string, init_utsname()->release);
- p = &__uml_help_start;
- while (p < &__uml_help_end) {
- printf("%s", *p);
- p++;
- }
+ p = &__uml_help_start;
+ while (p < &__uml_help_end) {
+ printf("%s", *p);
+ p++;
+ }
exit(0);
-
return 0;
}
@@ -374,13 +383,12 @@ int __init linux_main(int argc, char **argv)
printf("UML running in %s mode\n", mode);
- uml_start = (unsigned long) &__binary_start;
host_task_size = CHOOSE_MODE_PROC(set_task_sizes_tt,
set_task_sizes_skas, &task_size);
/*
- * Setting up handlers to 'sig_info' struct
- */
+ * Setting up handlers to 'sig_info' struct
+ */
os_fill_handlinfo(handlinfo_kern);
brk_start = (unsigned long) sbrk(0);
@@ -396,7 +404,7 @@ int __init linux_main(int argc, char **argv)
physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
}
- uml_physmem = uml_start & PAGE_MASK;
+ uml_physmem = (unsigned long) &__binary_start & PAGE_MASK;
/* Reserve up to 4M after the current brk */
uml_reserved = ROUND_4M(brk_start) + (1 << 22);
@@ -407,7 +415,7 @@ int __init linux_main(int argc, char **argv)
argv1_begin = argv[1];
argv1_end = &argv[1][strlen(argv[1])];
#endif
-
+
highmem = 0;
iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
@@ -449,12 +457,12 @@ int __init linux_main(int argc, char **argv)
printf("Kernel virtual memory size shrunk to %lu bytes\n",
virtmem_size);
- uml_postsetup();
+ uml_postsetup();
task_protections((unsigned long) &init_thread_info);
os_flush_stdout();
- return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
+ return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
}
extern int uml_exitcode;
@@ -466,8 +474,8 @@ static int panic_exit(struct notifier_block *self, unsigned long unused1,
show_regs(&(current->thread.regs));
bust_spinlocks(0);
uml_exitcode = 1;
- machine_halt();
- return(0);
+ os_dump_core();
+ return 0;
}
static struct notifier_block panic_exit_notifier = {
@@ -482,14 +490,14 @@ void __init setup_arch(char **cmdline_p)
&panic_exit_notifier);
paging_init();
strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
- *cmdline_p = command_line;
- setup_hostinfo();
+ *cmdline_p = command_line;
+ setup_hostinfo(host_info, sizeof host_info);
}
void __init check_bugs(void)
{
arch_check_bugs();
- os_check_bugs();
+ os_check_bugs();
}
void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index 6ff12743a0b..9bf944f6a1d 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -132,10 +132,10 @@ static int aio_thread(void *arg)
{ .data = (void *) (long) event.data,
.err = event.res });
reply_fd = ((struct aio_context *) reply.data)->reply_fd;
- err = os_write_file(reply_fd, &reply, sizeof(reply));
+ err = write(reply_fd, &reply, sizeof(reply));
if(err != sizeof(reply))
printk("aio_thread - write failed, fd = %d, "
- "err = %d\n", reply_fd, -err);
+ "err = %d\n", reply_fd, errno);
}
}
return 0;
@@ -146,38 +146,31 @@ static int aio_thread(void *arg)
static int do_not_aio(struct aio_thread_req *req)
{
char c;
- int err;
+ unsigned long long actual;
+ int n;
+
+ actual = lseek64(req->io_fd, req->offset, SEEK_SET);
+ if(actual != req->offset)
+ return -errno;
switch(req->type){
case AIO_READ:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_read_file(req->io_fd, req->buf, req->len);
+ n = read(req->io_fd, req->buf, req->len);
break;
case AIO_WRITE:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_write_file(req->io_fd, req->buf, req->len);
+ n = write(req->io_fd, req->buf, req->len);
break;
case AIO_MMAP:
- err = os_seek_file(req->io_fd, req->offset);
- if(err)
- goto out;
-
- err = os_read_file(req->io_fd, &c, sizeof(c));
+ n = read(req->io_fd, &c, sizeof(c));
break;
default:
printk("do_not_aio - bad request type : %d\n", req->type);
- err = -EINVAL;
- break;
+ return -EINVAL;
}
-out:
- return err;
+ if(n < 0)
+ return -errno;
+ return 0;
}
/* These are initialized in initcalls and not changed */
@@ -193,12 +186,12 @@ static int not_aio_thread(void *arg)
signal(SIGWINCH, SIG_IGN);
while(1){
- err = os_read_file(aio_req_fd_r, &req, sizeof(req));
+ err = read(aio_req_fd_r, &req, sizeof(req));
if(err != sizeof(req)){
if(err < 0)
printk("not_aio_thread - read failed, "
"fd = %d, err = %d\n", aio_req_fd_r,
- -err);
+ errno);
else {
printk("not_aio_thread - short read, fd = %d, "
"length = %d\n", aio_req_fd_r, err);
@@ -207,11 +200,11 @@ static int not_aio_thread(void *arg)
}
err = do_not_aio(&req);
reply = ((struct aio_thread_reply) { .data = req.aio,
- .err = err });
- err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply));
+ .err = err });
+ err = write(req.aio->reply_fd, &reply, sizeof(reply));
if(err != sizeof(reply))
printk("not_aio_thread - write failed, fd = %d, "
- "err = %d\n", req.aio->reply_fd, -err);
+ "err = %d\n", req.aio->reply_fd, errno);
}
return 0;
@@ -228,6 +221,11 @@ static int init_aio_24(void)
aio_req_fd_w = fds[0];
aio_req_fd_r = fds[1];
+
+ err = os_set_fd_block(aio_req_fd_w, 0);
+ if(err)
+ goto out_close_pipe;
+
err = run_helper_thread(not_aio_thread, NULL,
CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
if(err < 0)
@@ -285,10 +283,12 @@ static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len,
if(err){
reply = ((struct aio_thread_reply) { .data = aio,
.err = err });
- err = os_write_file(aio->reply_fd, &reply, sizeof(reply));
- if(err != sizeof(reply))
+ err = write(aio->reply_fd, &reply, sizeof(reply));
+ if(err != sizeof(reply)){
+ err = -errno;
printk("submit_aio_26 - write failed, "
"fd = %d, err = %d\n", aio->reply_fd, -err);
+ }
else err = 0;
}
@@ -383,9 +383,10 @@ static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len,
};
int err;
- err = os_write_file(aio_req_fd_w, &req, sizeof(req));
+ err = write(aio_req_fd_w, &req, sizeof(req));
if(err == sizeof(req))
err = 0;
+ else err = -errno;
return err;
}
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index 863981ba146..acba3016128 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
* James Leu (jleu@mindspring.net).
* Copyright (C) 2001 by various other people who didn't put their name here.
* Licensed under the GPL.
@@ -16,19 +16,20 @@
#include <net/if.h>
#include "user.h"
#include "kern_util.h"
-#include "user_util.h"
#include "net_user.h"
#include "etap.h"
#include "os.h"
#include "um_malloc.h"
+#include "kern_constants.h"
#define MAX_PACKET ETH_MAX_PACKET
-void etap_user_init(void *data, void *dev)
+static int etap_user_init(void *data, void *dev)
{
struct ethertap_data *pri = data;
pri->dev = dev;
+ return 0;
}
struct addr_change {
@@ -47,13 +48,16 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
change.what = op;
memcpy(change.addr, addr, sizeof(change.addr));
memcpy(change.netmask, netmask, sizeof(change.netmask));
- n = os_write_file(fd, &change, sizeof(change));
- if(n != sizeof(change))
- printk("etap_change - request failed, err = %d\n", -n);
- output = um_kmalloc(page_size());
+ CATCH_EINTR(n = write(fd, &change, sizeof(change)));
+ if(n != sizeof(change)){
+ printk("etap_change - request failed, err = %d\n", errno);
+ return;
+ }
+
+ output = um_kmalloc(UM_KERN_PAGE_SIZE);
if(output == NULL)
printk("etap_change : Failed to allocate output buffer\n");
- read_output(fd, output, page_size());
+ read_output(fd, output, UM_KERN_PAGE_SIZE);
if(output != NULL){
printk("%s", output);
kfree(output);
@@ -115,13 +119,15 @@ static int etap_tramp(char *dev, char *gate, int control_me,
pe_data.data_me = data_me;
pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
- if(pid < 0) err = pid;
+ if(pid < 0)
+ err = pid;
os_close_file(data_remote);
os_close_file(control_remote);
- n = os_read_file(control_me, &c, sizeof(c));
+ CATCH_EINTR(n = read(control_me, &c, sizeof(c)));
if(n != sizeof(c)){
- printk("etap_tramp : read of status failed, err = %d\n", -n);
- return(-EINVAL);
+ err = -errno;
+ printk("etap_tramp : read of status failed, err = %d\n", -err);
+ return err;
}
if(c != 1){
printk("etap_tramp : uml_net failed\n");
@@ -132,7 +138,7 @@ static int etap_tramp(char *dev, char *gate, int control_me,
else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
printk("uml_net didn't exit with status 1\n");
}
- return(err);
+ return err;
}
static int etap_open(void *data)
@@ -142,23 +148,24 @@ static int etap_open(void *data)
int data_fds[2], control_fds[2], err, output_len;
err = tap_open_common(pri->dev, pri->gate_addr);
- if(err) return(err);
+ if(err)
+ return err;
err = os_pipe(data_fds, 0, 0);
if(err < 0){
printk("data os_pipe failed - err = %d\n", -err);
- return(err);
+ return err;
}
err = os_pipe(control_fds, 1, 0);
if(err < 0){
printk("control os_pipe failed - err = %d\n", -err);
- return(err);
+ return err;
}
-
+
err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
control_fds[1], data_fds[0], data_fds[1]);
- output_len = page_size();
+ output_len = UM_KERN_PAGE_SIZE;
output = um_kmalloc(output_len);
read_output(control_fds[0], output, output_len);
@@ -171,13 +178,13 @@ static int etap_open(void *data)
if(err < 0){
printk("etap_tramp failed - err = %d\n", -err);
- return(err);
+ return err;
}
pri->data_fd = data_fds[0];
pri->control_fd = control_fds[0];
iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
- return(data_fds[0]);
+ return data_fds[0];
}
static void etap_close(int fd, void *data)
@@ -195,7 +202,7 @@ static void etap_close(int fd, void *data)
static int etap_set_mtu(int mtu, void *data)
{
- return(mtu);
+ return mtu;
}
static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
@@ -204,7 +211,8 @@ static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
struct ethertap_data *pri = data;
tap_check_ips(pri->gate_addr, addr);
- if(pri->control_fd == -1) return;
+ if(pri->control_fd == -1)
+ return;
etap_open_addr(addr, netmask, &pri->control_fd);
}
@@ -213,7 +221,8 @@ static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
{
struct ethertap_data *pri = data;
- if(pri->control_fd == -1) return;
+ if(pri->control_fd == -1)
+ return;
etap_close_addr(addr, netmask, &pri->control_fd);
}
@@ -227,14 +236,3 @@ const struct net_user_info ethertap_user_info = {
.delete_address = etap_del_addr,
.max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index e846b23f755..11a9779dc9f 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -18,17 +18,17 @@
#include "net_user.h"
#include "tuntap.h"
#include "kern_util.h"
-#include "user_util.h"
#include "user.h"
#include "os.h"
#define MAX_PACKET ETH_MAX_PACKET
-void tuntap_user_init(void *data, void *dev)
+static int tuntap_user_init(void *data, void *dev)
{
struct tuntap_data *pri = data;
pri->dev = dev;
+ return 0;
}
static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
@@ -37,7 +37,8 @@ static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
struct tuntap_data *pri = data;
tap_check_ips(pri->gate_addr, addr);
- if((pri->fd == -1) || pri->fixed_config) return;
+ if((pri->fd == -1) || pri->fixed_config)
+ return;
open_addr(addr, netmask, pri->dev_name);
}
@@ -46,7 +47,8 @@ static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
{
struct tuntap_data *pri = data;
- if((pri->fd == -1) || pri->fixed_config) return;
+ if((pri->fd == -1) || pri->fixed_config)
+ return;
close_addr(addr, netmask, pri->dev_name);
}
@@ -58,7 +60,7 @@ struct tuntap_pre_exec_data {
static void tuntap_pre_exec(void *arg)
{
struct tuntap_pre_exec_data *data = arg;
-
+
dup2(data->stdout, 1);
os_close_file(data->close_me);
}
@@ -83,7 +85,8 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
- if(pid < 0) return(-pid);
+ if(pid < 0)
+ return -pid;
os_close_file(remote);
@@ -114,16 +117,16 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL){
printk("tuntap_open_tramp : didn't receive a message\n");
- return(-EINVAL);
+ return -EINVAL;
}
if((cmsg->cmsg_level != SOL_SOCKET) ||
(cmsg->cmsg_type != SCM_RIGHTS)){
printk("tuntap_open_tramp : didn't receive a descriptor\n");
- return(-EINVAL);
+ return -EINVAL;
}
*fd_out = ((int *) CMSG_DATA(cmsg))[0];
os_set_exec_close(*fd_out, 1);
- return(0);
+ return 0;
}
static int tuntap_open(void *data)
@@ -135,7 +138,7 @@ static int tuntap_open(void *data)
err = tap_open_common(pri->dev, pri->gate_addr);
if(err < 0)
- return(err);
+ return err;
if(pri->fixed_config){
pri->fd = os_open_file("/dev/net/tun",
@@ -143,7 +146,7 @@ static int tuntap_open(void *data)
if(pri->fd < 0){
printk("Failed to open /dev/net/tun, err = %d\n",
-pri->fd);
- return(pri->fd);
+ return pri->fd;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -160,7 +163,7 @@ static int tuntap_open(void *data)
if(err < 0){
printk("tuntap_open : os_pipe failed - err = %d\n",
-err);
- return(err);
+ return err;
}
buffer = get_output_buffer(&len);
@@ -175,7 +178,7 @@ static int tuntap_open(void *data)
printk("%s", output);
free_output_buffer(buffer);
printk("tuntap_open_tramp failed - err = %d\n", -err);
- return(err);
+ return err;
}
pri->dev_name = uml_strdup(buffer);
@@ -187,7 +190,7 @@ static int tuntap_open(void *data)
iter_addresses(pri->dev, open_addr, pri->dev_name);
}
- return(pri->fd);
+ return pri->fd;
}
static void tuntap_close(int fd, void *data)
@@ -202,7 +205,7 @@ static void tuntap_close(int fd, void *data)
static int tuntap_set_mtu(int mtu, void *data)
{
- return(mtu);
+ return mtu;
}
const struct net_user_info tuntap_user_info = {
@@ -215,14 +218,3 @@ const struct net_user_info tuntap_user_info = {
.delete_address = tuntap_del_addr,
.max_packet = MAX_PACKET
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 371b4335f46..6f92f732d25 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -18,7 +18,6 @@
#include "os.h"
#include "user.h"
#include "kern_util.h"
-#include "user_util.h"
static void copy_stat(struct uml_stat *dst, struct stat64 *src)
{
@@ -291,54 +290,22 @@ int os_seek_file(int fd, __u64 offset)
return 0;
}
-static int fault_buffer(void *start, int len,
- int (*copy_proc)(void *addr, void *buf, int len))
-{
- int page = getpagesize(), i;
- char c;
-
- for(i = 0; i < len; i += page){
- if((*copy_proc)(start + i, &c, sizeof(c)))
- return -EFAULT;
- }
- if((len % page) != 0){
- if((*copy_proc)(start + len - 1, &c, sizeof(c)))
- return -EFAULT;
- }
- return 0;
-}
-
-static int file_io(int fd, void *buf, int len,
- int (*io_proc)(int fd, void *buf, int len),
- int (*copy_user_proc)(void *addr, void *buf, int len))
+int os_read_file(int fd, void *buf, int len)
{
- int n, err;
-
- do {
- n = (*io_proc)(fd, buf, len);
- if((n < 0) && (errno == EFAULT)){
- err = fault_buffer(buf, len, copy_user_proc);
- if(err)
- return err;
- n = (*io_proc)(fd, buf, len);
- }
- } while((n < 0) && (errno == EINTR));
+ int n = read(fd, buf, len);
if(n < 0)
return -errno;
return n;
}
-int os_read_file(int fd, void *buf, int len)
-{
- return file_io(fd, buf, len, (int (*)(int, void *, int)) read,
- copy_from_user_proc);
-}
-
int os_write_file(int fd, const void *buf, int len)
{
- return file_io(fd, (void *) buf, len,
- (int (*)(int, void *, int)) write, copy_to_user_proc);
+ int n = write(fd, (void *) buf, len);
+
+ if(n < 0)
+ return -errno;
+ return n;
}
int os_file_size(char *file, unsigned long long *size_out)
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index c7ad6306e22..97bed16bf4c 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -13,9 +13,9 @@
#include <sys/wait.h>
#include "user.h"
#include "kern_util.h"
-#include "user_util.h"
#include "os.h"
#include "um_malloc.h"
+#include "kern_constants.h"
struct helper_data {
void (*pre_exec)(void*);
@@ -25,28 +25,18 @@ struct helper_data {
char *buf;
};
-/* Debugging aid, changed only from gdb */
-int helper_pause = 0;
-
-static void helper_hup(int sig)
-{
-}
-
static int helper_child(void *arg)
{
struct helper_data *data = arg;
char **argv = data->argv;
int errval;
- if (helper_pause){
- signal(SIGHUP, helper_hup);
- pause();
- }
if (data->pre_exec != NULL)
(*data->pre_exec)(data->pre_data);
errval = execvp_noalloc(data->buf, argv[0], argv);
- printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0], -errval);
- os_write_file(data->fd, &errval, sizeof(errval));
+ printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0],
+ -errval);
+ write(data->fd, &errval, sizeof(errval));
kill(os_getpid(), SIGKILL);
return 0;
}
@@ -81,7 +71,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
goto out_close;
}
- sp = stack + page_size() - sizeof(void *);
+ sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
data.pre_exec = pre_exec;
data.pre_data = pre_data;
data.argv = argv;
@@ -98,13 +88,16 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
close(fds[1]);
fds[1] = -1;
- /* Read the errno value from the child, if the exec failed, or get 0 if
- * the exec succeeded because the pipe fd was set as close-on-exec. */
- n = os_read_file(fds[0], &ret, sizeof(ret));
+ /*
+ * Read the errno value from the child, if the exec failed, or get 0 if
+ * the exec succeeded because the pipe fd was set as close-on-exec.
+ */
+ n = read(fds[0], &ret, sizeof(ret));
if (n == 0) {
ret = pid;
} else {
if (n < 0) {
+ n = -errno;
printk("run_helper : read on pipe failed, ret = %d\n",
-n);
ret = n;
@@ -135,7 +128,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
if (stack == 0)
return -ENOMEM;
- sp = stack + (page_size() << stack_order) - sizeof(void *);
+ sp = stack + (UM_KERN_PAGE_SIZE << stack_order) - sizeof(void *);
pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
if (pid < 0) {
err = -errno;
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
index d1b61d474e0..a633fa8e0a9 100644
--- a/arch/um/os-Linux/irq.c
+++ b/arch/um/os-Linux/irq.c
@@ -11,7 +11,6 @@
#include <sys/poll.h>
#include <sys/types.h>
#include <sys/time.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "process.h"
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index 685feaab65d..ea9a23696f3 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -13,8 +13,8 @@
#include <sys/mman.h>
#include <sys/user.h>
#include <asm/page.h>
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
#include "mem_user.h"
#include "irq_user.h"
#include "user.h"
@@ -25,12 +25,7 @@
#include "os.h"
#include "um_malloc.h"
-/* Set in set_stklim, which is called from main and __wrap_malloc.
- * __wrap_malloc only calls it if main hasn't started.
- */
-unsigned long stacksizelim;
-
-/* Set in main */
+/* Set in main, unchanged thereafter */
char *linux_prog;
#define PGD_BOUND (4 * 1024 * 1024)
@@ -52,7 +47,6 @@ static void set_stklim(void)
exit(1);
}
}
- stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1);
}
static __init void do_uml_initcalls(void)
@@ -126,7 +120,7 @@ extern int uml_exitcode;
extern void scan_elf_aux( char **envp);
-int main(int argc, char **argv, char **envp)
+int __init main(int argc, char **argv, char **envp)
{
char **new_argv;
int ret, i, err;
@@ -224,7 +218,7 @@ int main(int argc, char **argv, char **envp)
ret = 1;
}
printf("\n");
- return(uml_exitcode);
+ return uml_exitcode;
}
#define CAN_KMALLOC() \
@@ -237,7 +231,7 @@ void *__wrap_malloc(int size)
void *ret;
if(!CAN_KMALLOC())
- return(__real_malloc(size));
+ return __real_malloc(size);
else if(size <= PAGE_SIZE) /* finding contiguos pages can be hard*/
ret = um_kmalloc(size);
else ret = um_vmalloc(size);
@@ -248,16 +242,17 @@ void *__wrap_malloc(int size)
if(ret == NULL)
errno = ENOMEM;
- return(ret);
+ return ret;
}
void *__wrap_calloc(int n, int size)
{
void *ptr = __wrap_malloc(n * size);
- if(ptr == NULL) return(NULL);
+ if(ptr == NULL)
+ return NULL;
memset(ptr, 0, n * size);
- return(ptr);
+ return ptr;
}
extern void __real_free(void *);
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index f1ea169db85..c6378c6d10d 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -11,7 +11,6 @@
#include <sys/statfs.h>
#include "kern_util.h"
#include "user.h"
-#include "user_util.h"
#include "mem_user.h"
#include "init.h"
#include "os.h"
@@ -165,7 +164,8 @@ found:
* (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger).
* So it isn't 'static' yet.
*/
-int make_tempfile(const char *template, char **out_tempname, int do_unlink)
+int __init make_tempfile(const char *template, char **out_tempname,
+ int do_unlink)
{
char *tempname;
int fd;
@@ -206,7 +206,7 @@ out:
* This proc is used in start_up.c
* So it isn't 'static'.
*/
-int create_tmp_file(unsigned long long len)
+int __init create_tmp_file(unsigned long long len)
{
int fd, err;
char zero;
@@ -232,17 +232,16 @@ int create_tmp_file(unsigned long long len)
zero = 0;
- err = os_write_file(fd, &zero, 1);
+ err = write(fd, &zero, 1);
if(err != 1){
- errno = -err;
- perror("os_write_file");
+ perror("write");
exit(1);
}
return fd;
}
-int create_mem_file(unsigned long long len)
+int __init create_mem_file(unsigned long long len)
{
int err, fd;
@@ -257,7 +256,7 @@ int create_mem_file(unsigned long long len)
}
-void check_tmpexec(void)
+void __init check_tmpexec(void)
{
void *addr;
int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 76bdd671241..2d9d2ca3929 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -14,7 +14,6 @@
#include "ptrace_user.h"
#include "os.h"
#include "user.h"
-#include "user_util.h"
#include "process.h"
#include "irq_user.h"
#include "kern_util.h"
@@ -22,6 +21,7 @@
#include "skas_ptrace.h"
#include "kern_constants.h"
#include "uml-config.h"
+#include "init.h"
#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
@@ -40,14 +40,14 @@ unsigned long os_process_pc(int pid)
if(fd < 0){
printk("os_process_pc - couldn't open '%s', err = %d\n",
proc_stat, -fd);
- return(ARBITRARY_ADDR);
+ return ARBITRARY_ADDR;
}
- err = os_read_file(fd, buf, sizeof(buf));
+ CATCH_EINTR(err = read(fd, buf, sizeof(buf)));
if(err < 0){
printk("os_process_pc - couldn't read '%s', err = %d\n",
- proc_stat, -err);
+ proc_stat, errno);
os_close_file(fd);
- return(ARBITRARY_ADDR);
+ return ARBITRARY_ADDR;
}
os_close_file(fd);
pc = ARBITRARY_ADDR;
@@ -56,7 +56,7 @@ unsigned long os_process_pc(int pid)
"%*d %*d %*d %*d %*d %lu", &pc) != 1){
printk("os_process_pc - couldn't find pc in '%s'\n", buf);
}
- return(pc);
+ return pc;
}
int os_process_parent(int pid)
@@ -65,21 +65,22 @@ int os_process_parent(int pid)
char data[256];
int parent, n, fd;
- if(pid == -1) return(-1);
+ if(pid == -1)
+ return -1;
snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
if(fd < 0){
printk("Couldn't open '%s', err = %d\n", stat, -fd);
- return(FAILURE_PID);
+ return FAILURE_PID;
}
- n = os_read_file(fd, data, sizeof(data));
+ CATCH_EINTR(n = read(fd, data, sizeof(data)));
os_close_file(fd);
if(n < 0){
- printk("Couldn't read '%s', err = %d\n", stat, -n);
- return(FAILURE_PID);
+ printk("Couldn't read '%s', err = %d\n", stat, errno);
+ return FAILURE_PID;
}
parent = FAILURE_PID;
@@ -87,7 +88,7 @@ int os_process_parent(int pid)
if(n != 1)
printk("Failed to scan '%s'\n", data);
- return(parent);
+ return parent;
}
void os_stop_process(int pid)
@@ -145,7 +146,7 @@ void os_usr1_process(int pid)
int os_getpid(void)
{
- return(syscall(__NR_getpid));
+ return syscall(__NR_getpid);
}
int os_getpgrp(void)
@@ -165,8 +166,8 @@ int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
fd, off);
if(loc == MAP_FAILED)
- return(-errno);
- return(0);
+ return -errno;
+ return 0;
}
int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
@@ -175,8 +176,8 @@ int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
(x ? PROT_EXEC : 0));
if(mprotect(addr, len, prot) < 0)
- return(-errno);
- return(0);
+ return -errno;
+ return 0;
}
int os_unmap_memory(void *addr, int len)
@@ -185,15 +186,15 @@ int os_unmap_memory(void *addr, int len)
err = munmap(addr, len);
if(err < 0)
- return(-errno);
- return(0);
+ return -errno;
+ return 0;
}
#ifndef MADV_REMOVE
#define MADV_REMOVE KERNEL_MADV_REMOVE
#endif
-int os_drop_memory(void *addr, int length)
+int __init os_drop_memory(void *addr, int length)
{
int err;
@@ -203,7 +204,7 @@ int os_drop_memory(void *addr, int length)
return err;
}
-int can_drop_memory(void)
+int __init can_drop_memory(void)
{
void *addr;
int fd, ok = 0;
@@ -238,13 +239,14 @@ out:
return ok;
}
+#ifdef UML_CONFIG_MODE_TT
void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
{
int flags = 0, pages;
if(sig_stack != NULL){
pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
- set_sigstack(sig_stack, pages * page_size());
+ set_sigstack(sig_stack, pages * UM_KERN_PAGE_SIZE);
flags = SA_ONSTACK;
}
if(usr1_handler){
@@ -259,6 +261,7 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int))
"errno = %d\n", errno);
}
}
+#endif
void init_new_thread_signals(void)
{
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index 3fc43b33db6..8d4e0c6b8c9 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -8,6 +8,7 @@
#include <termios.h>
#include <pty.h>
#include <signal.h>
+#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sched.h>
@@ -16,10 +17,10 @@
#include "init.h"
#include "user.h"
#include "kern_util.h"
-#include "user_util.h"
#include "sigio.h"
#include "os.h"
#include "um_malloc.h"
+#include "init.h"
/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
* exitcall.
@@ -68,11 +69,12 @@ static int write_sigio_thread(void *unused)
p = &fds->poll[i];
if(p->revents == 0) continue;
if(p->fd == sigio_private[1]){
- n = os_read_file(sigio_private[1], &c, sizeof(c));
+ CATCH_EINTR(n = read(sigio_private[1], &c,
+ sizeof(c)));
if(n != sizeof(c))
printk("write_sigio_thread : "
"read on socket failed, "
- "err = %d\n", -n);
+ "err = %d\n", errno);
tmp = current_poll;
current_poll = next_poll;
next_poll = tmp;
@@ -85,10 +87,10 @@ static int write_sigio_thread(void *unused)
(fds->used - i) * sizeof(*fds->poll));
}
- n = os_write_file(respond_fd, &c, sizeof(c));
+ CATCH_EINTR(n = write(respond_fd, &c, sizeof(c)));
if(n != sizeof(c))
printk("write_sigio_thread : write on socket "
- "failed, err = %d\n", -n);
+ "failed, err = %d\n", errno);
}
}
@@ -126,15 +128,15 @@ static void update_thread(void)
char c;
flags = set_signals(0);
- n = os_write_file(sigio_private[0], &c, sizeof(c));
+ n = write(sigio_private[0], &c, sizeof(c));
if(n != sizeof(c)){
- printk("update_thread : write failed, err = %d\n", -n);
+ printk("update_thread : write failed, err = %d\n", errno);
goto fail;
}
- n = os_read_file(sigio_private[0], &c, sizeof(c));
+ CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c)));
if(n != sizeof(c)){
- printk("update_thread : read failed, err = %d\n", -n);
+ printk("update_thread : read failed, err = %d\n", errno);
goto fail;
}
@@ -320,6 +322,10 @@ out_close1:
close(l_write_sigio_fds[1]);
}
+/* Changed during early boot */
+static int pty_output_sigio = 0;
+static int pty_close_sigio = 0;
+
void maybe_sigio_broken(int fd, int read)
{
int err;
@@ -357,3 +363,143 @@ static void sigio_cleanup(void)
}
__uml_exitcall(sigio_cleanup);
+
+/* Used as a flag during SIGIO testing early in boot */
+static volatile int got_sigio = 0;
+
+static void __init handler(int sig)
+{
+ got_sigio = 1;
+}
+
+struct openpty_arg {
+ int master;
+ int slave;
+ int err;
+};
+
+static void openpty_cb(void *arg)
+{
+ struct openpty_arg *info = arg;
+
+ info->err = 0;
+ if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+ info->err = -errno;
+}
+
+static int async_pty(int master, int slave)
+{
+ int flags;
+
+ flags = fcntl(master, F_GETFL);
+ if(flags < 0)
+ return -errno;
+
+ if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+ (fcntl(master, F_SETOWN, os_getpid()) < 0))
+ return -errno;
+
+ if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+ return -errno;
+
+ return(0);
+}
+
+static void __init check_one_sigio(void (*proc)(int, int))
+{
+ struct sigaction old, new;
+ struct openpty_arg pty = { .master = -1, .slave = -1 };
+ int master, slave, err;
+
+ initial_thread_cb(openpty_cb, &pty);
+ if(pty.err){
+ printk("openpty failed, errno = %d\n", -pty.err);
+ return;
+ }
+
+ master = pty.master;
+ slave = pty.slave;
+
+ if((master == -1) || (slave == -1)){
+ printk("openpty failed to allocate a pty\n");
+ return;
+ }
+
+ /* Not now, but complain so we now where we failed. */
+ err = raw(master);
+ if (err < 0)
+ panic("check_sigio : __raw failed, errno = %d\n", -err);
+
+ err = async_pty(master, slave);
+ if(err < 0)
+ panic("tty_fds : sigio_async failed, err = %d\n", -err);
+
+ if(sigaction(SIGIO, NULL, &old) < 0)
+ panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+ new = old;
+ new.sa_handler = handler;
+ if(sigaction(SIGIO, &new, NULL) < 0)
+ panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
+
+ got_sigio = 0;
+ (*proc)(master, slave);
+
+ close(master);
+ close(slave);
+
+ if(sigaction(SIGIO, &old, NULL) < 0)
+ panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+}
+
+static void tty_output(int master, int slave)
+{
+ int n;
+ char buf[512];
+
+ printk("Checking that host ptys support output SIGIO...");
+
+ memset(buf, 0, sizeof(buf));
+
+ while(write(master, buf, sizeof(buf)) > 0) ;
+ if(errno != EAGAIN)
+ panic("tty_output : write failed, errno = %d\n", errno);
+ while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+
+ if(got_sigio){
+ printk("Yes\n");
+ pty_output_sigio = 1;
+ }
+ else if(n == -EAGAIN)
+ printk("No, enabling workaround\n");
+ else panic("tty_output : read failed, err = %d\n", n);
+}
+
+static void tty_close(int master, int slave)
+{
+ printk("Checking that host ptys support SIGIO on close...");
+
+ close(slave);
+ if(got_sigio){
+ printk("Yes\n");
+ pty_close_sigio = 1;
+ }
+ else printk("No, enabling workaround\n");
+}
+
+void __init check_sigio(void)
+{
+ if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
+ (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
+ printk("No pseudo-terminals available - skipping pty SIGIO "
+ "check\n");
+ return;
+ }
+ check_one_sigio(tty_output);
+ check_one_sigio(tty_close);
+}
+
+/* Here because it only does the SIGIO testing for now */
+void __init os_check_bugs(void)
+{
+ check_sigio();
+}
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 266768629fe..48d49341530 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -11,7 +11,6 @@
#include <stdarg.h>
#include <string.h>
#include <sys/mman.h>
-#include "user_util.h"
#include "user.h"
#include "signal_kern.h"
#include "sysdep/sigcontext.h"
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index 9383e8751ae..5c894632079 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -6,6 +6,7 @@
#include <signal.h>
#include <errno.h>
#include <string.h>
+#include <unistd.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <asm/page.h>
@@ -17,17 +18,17 @@
#include "os.h"
#include "proc_mm.h"
#include "ptrace_user.h"
-#include "user_util.h"
#include "kern_util.h"
#include "task.h"
#include "registers.h"
#include "uml-config.h"
#include "sysdep/ptrace.h"
#include "sysdep/stub.h"
+#include "init.h"
extern unsigned long batch_syscall_stub, __syscall_stub_start;
-extern void wait_stub_done(int pid, int sig, char * fname);
+extern void wait_stub_done(int pid);
static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
unsigned long *stack)
@@ -39,6 +40,19 @@ static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
return stack;
}
+static unsigned long syscall_regs[MAX_REG_NR];
+
+static int __init init_syscall_regs(void)
+{
+ get_safe_registers(syscall_regs, NULL);
+ syscall_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ ((unsigned long) &batch_syscall_stub -
+ (unsigned long) &__syscall_stub_start);
+ return 0;
+}
+
+__initcall(init_syscall_regs);
+
extern int proc_mm;
int single_count = 0;
@@ -47,34 +61,33 @@ int multi_op_count = 0;
static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
{
- unsigned long regs[MAX_REG_NR];
int n, i;
long ret, offset;
unsigned long * data;
unsigned long * syscall;
- int pid = mm_idp->u.pid;
+ int err, pid = mm_idp->u.pid;
if(proc_mm)
-#warning Need to look up userspace_pid by cpu
+ /* FIXME: Need to look up userspace_pid by cpu */
pid = userspace_pid[0];
multi_count++;
- get_safe_registers(regs, NULL);
- regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
- ((unsigned long) &batch_syscall_stub -
- (unsigned long) &__syscall_stub_start);
-
- n = ptrace_setregs(pid, regs);
+ n = ptrace_setregs(pid, syscall_regs);
if(n < 0){
printk("Registers - \n");
for(i = 0; i < MAX_REG_NR; i++)
- printk("\t%d\t0x%lx\n", i, regs[i]);
+ printk("\t%d\t0x%lx\n", i, syscall_regs[i]);
panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
-n);
}
- wait_stub_done(pid, 0, "do_syscall_stub");
+ err = ptrace(PTRACE_CONT, pid, 0, 0);
+ if(err)
+ panic("Failed to continue stub, pid = %d, errno = %d\n", pid,
+ errno);
+
+ wait_stub_done(pid);
/* When the stub stops, we find the following values on the
* beginning of the stack:
@@ -176,14 +189,10 @@ long syscall_stub_data(struct mm_id * mm_idp,
return 0;
}
-int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
- int r, int w, int x, int phys_fd, unsigned long long offset,
- int done, void **data)
+int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot,
+ int phys_fd, unsigned long long offset, int done, void **data)
{
- int prot, ret;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
+ int ret;
if(proc_mm){
struct proc_mm_op map;
@@ -200,9 +209,11 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
.fd = phys_fd,
.offset= offset
} } } );
- ret = os_write_file(fd, &map, sizeof(map));
- if(ret != sizeof(map))
+ CATCH_EINTR(ret = write(fd, &map, sizeof(map)));
+ if(ret != sizeof(map)){
+ ret = -errno;
printk("map : /proc/mm map failed, err = %d\n", -ret);
+ }
else ret = 0;
}
else {
@@ -217,8 +228,8 @@ int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
return ret;
}
-int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
- void **data)
+int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
+ int done, void **data)
{
int ret;
@@ -232,9 +243,11 @@ int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
{ .addr =
(unsigned long) addr,
.len = len } } } );
- ret = os_write_file(fd, &unmap, sizeof(unmap));
- if(ret != sizeof(unmap))
+ CATCH_EINTR(ret = write(fd, &unmap, sizeof(unmap)));
+ if(ret != sizeof(unmap)){
+ ret = -errno;
printk("unmap - proc_mm write returned %d\n", ret);
+ }
else ret = 0;
}
else {
@@ -249,13 +262,11 @@ int unmap(struct mm_id * mm_idp, void *addr, unsigned long len, int done,
}
int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
- int r, int w, int x, int done, void **data)
+ unsigned int prot, int done, void **data)
{
struct proc_mm_op protect;
- int prot, ret;
+ int ret;
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
if(proc_mm){
int fd = mm_idp->u.mm_fd;
@@ -267,9 +278,11 @@ int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
.len = len,
.prot = prot } } } );
- ret = os_write_file(fd, &protect, sizeof(protect));
- if(ret != sizeof(protect))
+ CATCH_EINTR(ret = write(fd, &protect, sizeof(protect)));
+ if(ret != sizeof(protect)){
+ ret = -errno;
printk("protect failed, err = %d", -ret);
+ }
else ret = 0;
}
else {
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 0564422c155..6a0e466d01e 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -18,7 +18,6 @@
#include <asm/types.h>
#include "user.h"
#include "sysdep/ptrace.h"
-#include "user_util.h"
#include "kern_util.h"
#include "skas.h"
#include "stub-data.h"
@@ -34,6 +33,8 @@
#include "uml-config.h"
#include "process.h"
#include "longjmp.h"
+#include "kern_constants.h"
+#include "as-layout.h"
int is_skas_winch(int pid, int fd, void *data)
{
@@ -44,45 +45,58 @@ int is_skas_winch(int pid, int fd, void *data)
return(1);
}
-void wait_stub_done(int pid, int sig, char * fname)
+static int ptrace_dump_regs(int pid)
{
- int n, status, err;
+ unsigned long regs[MAX_REG_NR];
+ int i;
+
+ if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
+ return -errno;
+ else {
+ printk("Stub registers -\n");
+ for(i = 0; i < ARRAY_SIZE(regs); i++)
+ printk("\t%d - %lx\n", i, regs[i]);
+ }
+
+ return 0;
+}
- do {
- if ( sig != -1 ) {
- err = ptrace(PTRACE_CONT, pid, 0, sig);
- if(err)
- panic("%s : continue failed, errno = %d\n",
- fname, errno);
- }
- sig = 0;
+/*
+ * Signals that are OK to receive in the stub - we'll just continue it.
+ * SIGWINCH will happen when UML is inside a detached screen.
+ */
+#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))
+
+/* Signals that the stub will finish with - anything else is an error */
+#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP))
+
+void wait_stub_done(int pid)
+{
+ int n, status, err;
+ while(1){
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
- } while((n >= 0) && WIFSTOPPED(status) &&
- ((WSTOPSIG(status) == SIGVTALRM) ||
- /* running UML inside a detached screen can cause
- * SIGWINCHes
- */
- (WSTOPSIG(status) == SIGWINCH)));
-
- if((n < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
- unsigned long regs[MAX_REG_NR];
-
- if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0)
- printk("Failed to get registers from stub, "
- "errno = %d\n", errno);
- else {
- int i;
-
- printk("Stub registers -\n");
- for(i = 0; i < ARRAY_SIZE(regs); i++)
- printk("\t%d - %lx\n", i, regs[i]);
- }
- panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
- "pid = %d, n = %d, errno = %d, status = 0x%x\n",
- fname, pid, n, errno, status);
+ if((n < 0) || !WIFSTOPPED(status))
+ goto bad_wait;
+
+ if(((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
+ break;
+
+ err = ptrace(PTRACE_CONT, pid, 0, 0);
+ if(err)
+ panic("wait_stub_done : continue failed, errno = %d\n",
+ errno);
}
+
+ if(((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
+ return;
+
+bad_wait:
+ err = ptrace_dump_regs(pid);
+ if(err)
+ printk("Failed to get registers from stub, errno = %d\n", -err);
+ panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, "
+ "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status);
}
extern unsigned long current_stub_stack(void);
@@ -104,7 +118,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi)
sizeof(struct ptrace_faultinfo));
}
else {
- wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+ err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
+ if(err)
+ panic("Failed to continue stub, pid = %d, errno = %d\n",
+ pid, errno);
+ wait_stub_done(pid);
/* faultinfo is prepared by the stub-segv-handler at start of
* the stub stack page. We just have to copy it.
@@ -142,9 +160,14 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
if((err < 0) || !WIFSTOPPED(status) ||
- (WSTOPSIG(status) != SIGTRAP + 0x80))
+ (WSTOPSIG(status) != SIGTRAP + 0x80)){
+ err = ptrace_dump_regs(pid);
+ if(err)
+ printk("Failed to get registers from process, "
+ "errno = %d\n", -err);
panic("handle_trap - failed to wait at end of syscall, "
"errno = %d, status = %d\n", errno, status);
+ }
}
handle_syscall(regs);
@@ -172,7 +195,7 @@ static int userspace_tramp(void *stack)
int fd;
__u64 offset;
fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
- addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+ addr = mmap64((void *) UML_CONFIG_STUB_CODE, UM_KERN_PAGE_SIZE,
PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
if(addr == MAP_FAILED){
printk("mapping mmap stub failed, errno = %d\n",
@@ -182,8 +205,8 @@ static int userspace_tramp(void *stack)
if(stack != NULL){
fd = phys_mapping(to_phys(stack), &offset);
- addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
- PROT_READ | PROT_WRITE,
+ addr = mmap((void *) UML_CONFIG_STUB_DATA,
+ UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, offset);
if(addr == MAP_FAILED){
printk("mapping segfault stack failed, "
@@ -199,7 +222,7 @@ static int userspace_tramp(void *stack)
(unsigned long) stub_segv_handler -
(unsigned long) &__syscall_stub_start;
- set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+ set_sigstack((void *) UML_CONFIG_STUB_DATA, UM_KERN_PAGE_SIZE);
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGIO);
sigaddset(&sa.sa_mask, SIGWINCH);
@@ -291,10 +314,13 @@ void userspace(union uml_pt_regs *regs)
UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
if(WIFSTOPPED(status)){
- switch(WSTOPSIG(status)){
+ int sig = WSTOPSIG(status);
+ switch(sig){
case SIGSEGV:
- if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
- user_signal(SIGSEGV, regs, pid);
+ if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo){
+ get_skas_faultinfo(pid, &regs->skas.faultinfo);
+ (*sig_info[SIGSEGV])(SIGSEGV, regs);
+ }
else handle_segv(pid, regs);
break;
case SIGTRAP + 0x80:
@@ -309,11 +335,13 @@ void userspace(union uml_pt_regs *regs)
case SIGBUS:
case SIGFPE:
case SIGWINCH:
- user_signal(WSTOPSIG(status), regs, pid);
+ block_signals();
+ (*sig_info[sig])(sig, regs);
+ unblock_signals();
break;
default:
printk("userspace - child stopped with signal "
- "%d\n", WSTOPSIG(status));
+ "%d\n", sig);
}
pid = userspace_pid[0];
interrupt_end();
@@ -325,11 +353,29 @@ void userspace(union uml_pt_regs *regs)
}
}
+static unsigned long thread_regs[MAX_REG_NR];
+static unsigned long thread_fp_regs[HOST_FP_SIZE];
+
+static int __init init_thread_regs(void)
+{
+ get_safe_registers(thread_regs, thread_fp_regs);
+ /* Set parent's instruction pointer to start of clone-stub */
+ thread_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_clone_handler -
+ (unsigned long) &__syscall_stub_start;
+ thread_regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+ sizeof(void *);
+#ifdef __SIGNAL_FRAMESIZE
+ thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
+#endif
+ return 0;
+}
+
+__initcall(init_thread_regs);
+
int copy_context_skas0(unsigned long new_stack, int pid)
{
int err;
- unsigned long regs[MAX_REG_NR];
- unsigned long fp_regs[HOST_FP_SIZE];
unsigned long current_stack = current_stub_stack();
struct stub_data *data = (struct stub_data *) current_stack;
struct stub_data *child_data = (struct stub_data *) new_stack;
@@ -344,23 +390,12 @@ int copy_context_skas0(unsigned long new_stack, int pid)
.timer = ((struct itimerval)
{ { 0, 1000000 / hz() },
{ 0, 1000000 / hz() }})});
- get_safe_registers(regs, fp_regs);
-
- /* Set parent's instruction pointer to start of clone-stub */
- regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
- (unsigned long) stub_clone_handler -
- (unsigned long) &__syscall_stub_start;
- regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
- sizeof(void *);
-#ifdef __SIGNAL_FRAMESIZE
- regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
-#endif
- err = ptrace_setregs(pid, regs);
+ err = ptrace_setregs(pid, thread_regs);
if(err < 0)
panic("copy_context_skas0 : PTRACE_SETREGS failed, "
"pid = %d, errno = %d\n", pid, -err);
- err = ptrace_setfpregs(pid, fp_regs);
+ err = ptrace_setfpregs(pid, thread_fp_regs);
if(err < 0)
panic("copy_context_skas0 : PTRACE_SETFPREGS failed, "
"pid = %d, errno = %d\n", pid, -err);
@@ -371,7 +406,11 @@ int copy_context_skas0(unsigned long new_stack, int pid)
/* Wait, until parent has finished its work: read child's pid from
* parent's stack, and check, if bad result.
*/
- wait_stub_done(pid, 0, "copy_context_skas0");
+ err = ptrace(PTRACE_CONT, pid, 0, 0);
+ if(err)
+ panic("Failed to continue new process, pid = %d, "
+ "errno = %d\n", pid, errno);
+ wait_stub_done(pid);
pid = data->err;
if(pid < 0)
@@ -381,7 +420,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
/* Wait, until child has finished too: read child's result from
* child's stack and check it.
*/
- wait_stub_done(pid, -1, "copy_context_skas0");
+ wait_stub_done(pid);
if (child_data->err != UML_CONFIG_STUB_DATA)
panic("copy_context_skas0 - stub-child reports error %ld\n",
child_data->err);
@@ -396,7 +435,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
/*
* This is used only, if stub pages are needed, while proc_mm is
- * availabl. Opening /proc/mm creates a new mm_context, which lacks
+ * available. Opening /proc/mm creates a new mm_context, which lacks
* the stub-pages. Thus, we map them using /proc/mm-fd
*/
void map_stub_pages(int fd, unsigned long code,
@@ -418,12 +457,13 @@ void map_stub_pages(int fd, unsigned long code,
.fd = code_fd,
.offset = code_offset
} } });
- n = os_write_file(fd, &mmop, sizeof(mmop));
+ CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
if(n != sizeof(mmop)){
+ n = errno;
printk("mmap args - addr = 0x%lx, fd = %d, offset = %llx\n",
code, code_fd, (unsigned long long) code_offset);
panic("map_stub_pages : /proc/mm map for code failed, "
- "err = %d\n", -n);
+ "err = %d\n", n);
}
if ( stack ) {
@@ -440,10 +480,10 @@ void map_stub_pages(int fd, unsigned long code,
.fd = map_fd,
.offset = map_offset
} } });
- n = os_write_file(fd, &mmop, sizeof(mmop));
+ CATCH_EINTR(n = write(fd, &mmop, sizeof(mmop)));
if(n != sizeof(mmop))
panic("map_stub_pages : /proc/mm map for data failed, "
- "err = %d\n", -n);
+ "err = %d\n", errno);
}
}
@@ -480,7 +520,15 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
SIGVTALRM, -1);
- n = UML_SETJMP(&initial_jmpbuf);
+ /*
+ * Can't use UML_SETJMP or UML_LONGJMP here because they save
+ * and restore signals, with the possible side-effect of
+ * trying to handle any signals which came when they were
+ * blocked, which can't be done on this stack.
+ * Signals must be blocked when jumping back here and restored
+ * after returning to the jumper.
+ */
+ n = setjmp(initial_jmpbuf);
switch(n){
case INIT_JMP_NEW_THREAD:
(*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
@@ -490,7 +538,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
break;
case INIT_JMP_CALLBACK:
(*cb_proc)(cb_arg);
- UML_LONGJMP(cb_back, 1);
+ longjmp(*cb_back, 1);
break;
case INIT_JMP_HALT:
kmalloc_ok = 0;
@@ -501,7 +549,7 @@ int start_idle_thread(void *stack, jmp_buf *switch_buf)
default:
panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
}
- UML_LONGJMP(switch_buf, 1);
+ longjmp(*switch_buf, 1);
}
void initial_thread_cb_skas(void (*proc)(void *), void *arg)
@@ -538,7 +586,7 @@ void switch_mm_skas(struct mm_id *mm_idp)
{
int err;
-#warning need cpu pid in switch_mm_skas
+ /* FIXME: need cpu pid in switch_mm_skas */
if(proc_mm){
err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
mm_idp->u.mm_fd);
diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c
index 9ad5fbec459..3b600c2e63b 100644
--- a/arch/um/os-Linux/skas/trap.c
+++ b/arch/um/os-Linux/skas/trap.c
@@ -5,8 +5,8 @@
#include <signal.h>
#include <errno.h>
-#include "user_util.h"
#include "kern_util.h"
+#include "as-layout.h"
#include "task.h"
#include "sigcontext.h"
#include "skas.h"
@@ -15,29 +15,39 @@
#include "sysdep/ptrace_user.h"
#include "os.h"
+static union uml_pt_regs ksig_regs[UM_NR_CPUS];
+
void sig_handler_common_skas(int sig, void *sc_ptr)
{
struct sigcontext *sc = sc_ptr;
- struct skas_regs *r;
+ union uml_pt_regs *r;
void (*handler)(int, union uml_pt_regs *);
- int save_errno = errno;
- int save_user;
+ int save_user, save_errno = errno;
/* This is done because to allow SIGSEGV to be delivered inside a SEGV
* handler. This can happen in copy_user, and if SEGV is disabled,
* the process will die.
* XXX Figure out why this is better than SA_NODEFER
*/
- if(sig == SIGSEGV)
+ if(sig == SIGSEGV) {
change_sig(SIGSEGV, 1);
+ /* For segfaults, we want the data from the
+ * sigcontext. In this case, we don't want to mangle
+ * the process registers, so use a static set of
+ * registers. For other signals, the process
+ * registers are OK.
+ */
+ r = &ksig_regs[cpu()];
+ copy_sc(r, sc_ptr);
+ }
+ else r = TASK_REGS(get_current());
- r = &TASK_REGS(get_current())->skas;
- save_user = r->is_user;
- r->is_user = 0;
+ save_user = r->skas.is_user;
+ r->skas.is_user = 0;
if ( sig == SIGFPE || sig == SIGSEGV ||
sig == SIGBUS || sig == SIGILL ||
sig == SIGTRAP ) {
- GET_FAULTINFO_FROM_SC(r->faultinfo, sc);
+ GET_FAULTINFO_FROM_SC(r->skas.faultinfo, sc);
}
change_sig(SIGUSR1, 1);
@@ -49,25 +59,8 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
sig != SIGVTALRM && sig != SIGALRM)
unblock_signals();
- handler(sig, (union uml_pt_regs *) r);
+ handler(sig, r);
errno = save_errno;
- r->is_user = save_user;
-}
-
-extern int ptrace_faultinfo;
-
-void user_signal(int sig, union uml_pt_regs *regs, int pid)
-{
- void (*handler)(int, union uml_pt_regs *);
- int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
- (sig == SIGILL) || (sig == SIGTRAP));
-
- if (segv)
- get_skas_faultinfo(pid, &regs->skas.faultinfo);
-
- handler = sig_info[sig];
- handler(sig, (union uml_pt_regs *) regs);
-
- unblock_signals();
+ r->skas.is_user = save_user;
}
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 5178eba9afa..79471f85eb8 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -17,10 +17,10 @@
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/mman.h>
+#include <sys/resource.h>
#include <asm/unistd.h>
#include <asm/page.h>
#include <sys/types.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "signal_kern.h"
@@ -329,8 +329,32 @@ static void __init check_ptrace(void)
extern void check_tmpexec(void);
-void os_early_checks(void)
+static void __init check_coredump_limit(void)
{
+ struct rlimit lim;
+ int err = getrlimit(RLIMIT_CORE, &lim);
+
+ if(err){
+ perror("Getting core dump limit");
+ return;
+ }
+
+ printf("Core dump limits :\n\tsoft - ");
+ if(lim.rlim_cur == RLIM_INFINITY)
+ printf("NONE\n");
+ else printf("%lu\n", lim.rlim_cur);
+
+ printf("\thard - ");
+ if(lim.rlim_max == RLIM_INFINITY)
+ printf("NONE\n");
+ else printf("%lu\n", lim.rlim_max);
+}
+
+void __init os_early_checks(void)
+{
+ /* Print out the core dump limits early */
+ check_coredump_limit();
+
check_ptrace();
/* Need to check this early because mmapping happens before the
@@ -528,148 +552,3 @@ int __init parse_iomem(char *str, int *add)
out:
return 1;
}
-
-
-/* Changed during early boot */
-int pty_output_sigio = 0;
-int pty_close_sigio = 0;
-
-/* Used as a flag during SIGIO testing early in boot */
-static volatile int got_sigio = 0;
-
-static void __init handler(int sig)
-{
- got_sigio = 1;
-}
-
-struct openpty_arg {
- int master;
- int slave;
- int err;
-};
-
-static void openpty_cb(void *arg)
-{
- struct openpty_arg *info = arg;
-
- info->err = 0;
- if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
- info->err = -errno;
-}
-
-static int async_pty(int master, int slave)
-{
- int flags;
-
- flags = fcntl(master, F_GETFL);
- if(flags < 0)
- return -errno;
-
- if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
- (fcntl(master, F_SETOWN, os_getpid()) < 0))
- return -errno;
-
- if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
- return -errno;
-
- return(0);
-}
-
-static void __init check_one_sigio(void (*proc)(int, int))
-{
- struct sigaction old, new;
- struct openpty_arg pty = { .master = -1, .slave = -1 };
- int master, slave, err;
-
- initial_thread_cb(openpty_cb, &pty);
- if(pty.err){
- printk("openpty failed, errno = %d\n", -pty.err);
- return;
- }
-
- master = pty.master;
- slave = pty.slave;
-
- if((master == -1) || (slave == -1)){
- printk("openpty failed to allocate a pty\n");
- return;
- }
-
- /* Not now, but complain so we now where we failed. */
- err = raw(master);
- if (err < 0)
- panic("check_sigio : __raw failed, errno = %d\n", -err);
-
- err = async_pty(master, slave);
- if(err < 0)
- panic("tty_fds : sigio_async failed, err = %d\n", -err);
-
- if(sigaction(SIGIO, NULL, &old) < 0)
- panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
- new = old;
- new.sa_handler = handler;
- if(sigaction(SIGIO, &new, NULL) < 0)
- panic("check_sigio : sigaction 2 failed, errno = %d\n", errno);
-
- got_sigio = 0;
- (*proc)(master, slave);
-
- close(master);
- close(slave);
-
- if(sigaction(SIGIO, &old, NULL) < 0)
- panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
-}
-
-static void tty_output(int master, int slave)
-{
- int n;
- char buf[512];
-
- printk("Checking that host ptys support output SIGIO...");
-
- memset(buf, 0, sizeof(buf));
-
- while(os_write_file(master, buf, sizeof(buf)) > 0) ;
- if(errno != EAGAIN)
- panic("check_sigio : write failed, errno = %d\n", errno);
- while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
-
- if(got_sigio){
- printk("Yes\n");
- pty_output_sigio = 1;
- }
- else if(n == -EAGAIN) printk("No, enabling workaround\n");
- else panic("check_sigio : read failed, err = %d\n", n);
-}
-
-static void tty_close(int master, int slave)
-{
- printk("Checking that host ptys support SIGIO on close...");
-
- close(slave);
- if(got_sigio){
- printk("Yes\n");
- pty_close_sigio = 1;
- }
- else printk("No, enabling workaround\n");
-}
-
-void __init check_sigio(void)
-{
- if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
- (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
- printk("No pseudo-terminals available - skipping pty SIGIO "
- "check\n");
- return;
- }
- check_one_sigio(tty_output);
- check_one_sigio(tty_close);
-}
-
-void os_check_bugs(void)
-{
- check_ptrace();
- check_sigio();
-}
-
diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c
index 256532034c6..32ed41ec1a3 100644
--- a/arch/um/os-Linux/sys-i386/tls.c
+++ b/arch/um/os-Linux/sys-i386/tls.c
@@ -5,7 +5,7 @@
#include <unistd.h>
#include "sysdep/tls.h"
-#include "user_util.h"
+#include "user.h"
/* Checks whether host supports TLS, and sets *tls_min according to the value
* valid on the host.
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index 2115b8beb54..5de169b168f 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -10,7 +10,6 @@
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "process.h"
diff --git a/arch/um/os-Linux/trap.c b/arch/um/os-Linux/trap.c
index d221214d2ed..295da657931 100644
--- a/arch/um/os-Linux/trap.c
+++ b/arch/um/os-Linux/trap.c
@@ -6,7 +6,6 @@
#include <stdlib.h>
#include <signal.h>
#include "kern_util.h"
-#include "user_util.h"
#include "os.h"
#include "mode.h"
#include "longjmp.h"
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
index 3dc3a02d626..bcf9359c4e9 100644
--- a/arch/um/os-Linux/tt.c
+++ b/arch/um/os-Linux/tt.c
@@ -18,7 +18,6 @@
#include <asm/ptrace.h>
#include <asm/unistd.h>
#include <asm/page.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "signal_kern.h"
@@ -32,6 +31,7 @@
#include "choose-mode.h"
#include "mode.h"
#include "tempfile.h"
+#include "kern_constants.h"
int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
int must_succeed)
@@ -143,7 +143,7 @@ int outer_tramp(void *arg)
int sig = sigkill;
t = arg;
- t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2,
+ t->pid = clone(t->tramp, (void *) t->temp_stack + UM_KERN_PAGE_SIZE/2,
t->flags, t->tramp_data);
if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL);
kill(os_getpid(), sig);
diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c
index c6ba56c1560..d11a55baa6b 100644
--- a/arch/um/os-Linux/tty_log.c
+++ b/arch/um/os-Linux/tty_log.c
@@ -53,9 +53,9 @@ int open_tty_log(void *tty, void *current_tty)
.direction = 0,
.sec = tv.tv_sec,
.usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
- os_write_file(tty_log_fd, &current_tty, data.len);
- return(tty_log_fd);
+ write(tty_log_fd, &data, sizeof(data));
+ write(tty_log_fd, &current_tty, data.len);
+ return tty_log_fd;
}
sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
@@ -67,7 +67,7 @@ int open_tty_log(void *tty, void *current_tty)
printk("open_tty_log : couldn't open '%s', errno = %d\n",
buf, -fd);
}
- return(fd);
+ return fd;
}
void close_tty_log(int fd, void *tty)
@@ -83,7 +83,7 @@ void close_tty_log(int fd, void *tty)
.direction = 0,
.sec = tv.tv_sec,
.usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
+ write(tty_log_fd, &data, sizeof(data));
return;
}
os_close_file(fd);
@@ -98,21 +98,21 @@ static int log_chunk(int fd, const char *buf, int len)
try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
missed = copy_from_user_proc(chunk, (char *) buf, try);
try -= missed;
- n = os_write_file(fd, chunk, try);
+ n = write(fd, chunk, try);
if(n != try) {
if(n < 0)
- return(n);
- return(-EIO);
+ return -errno;
+ return -EIO;
}
if(missed != 0)
- return(-EFAULT);
+ return -EFAULT;
len -= try;
total += try;
buf += try;
}
- return(total);
+ return total;
}
int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
@@ -130,10 +130,10 @@ int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
.direction = direction,
.sec = tv.tv_sec,
.usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
+ write(tty_log_fd, &data, sizeof(data));
}
- return(log_chunk(fd, buf, len));
+ return log_chunk(fd, buf, len);
}
void log_exec(char **argv, void *tty)
@@ -161,7 +161,7 @@ void log_exec(char **argv, void *tty)
.direction = 0,
.sec = tv.tv_sec,
.usec = tv.tv_usec } );
- os_write_file(tty_log_fd, &data, sizeof(data));
+ write(tty_log_fd, &data, sizeof(data));
for(ptr = argv; ; ptr++){
if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
@@ -179,7 +179,7 @@ extern void register_tty_logger(int (*opener)(void *, void *),
static int register_logger(void)
{
register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
- return(0);
+ return 0;
}
__uml_initcall(register_logger);
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 56b8a50e8bc..c307a89ed25 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -21,7 +21,6 @@
#include <sched.h>
#include <termios.h>
#include <string.h>
-#include "user_util.h"
#include "kern_util.h"
#include "user.h"
#include "mem_user.h"
@@ -30,28 +29,29 @@
#include "uml-config.h"
#include "os.h"
#include "longjmp.h"
+#include "kern_constants.h"
void stack_protections(unsigned long address)
{
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- if(mprotect((void *) address, page_size(), prot) < 0)
+ if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0)
panic("protecting stack failed, errno = %d", errno);
}
void task_protections(unsigned long address)
{
- unsigned long guard = address + page_size();
- unsigned long stack = guard + page_size();
+ unsigned long guard = address + UM_KERN_PAGE_SIZE;
+ unsigned long stack = guard + UM_KERN_PAGE_SIZE;
int prot = 0, pages;
#ifdef notdef
- if(mprotect((void *) stack, page_size(), prot) < 0)
+ if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0)
panic("protecting guard page failed, errno = %d", errno);
#endif
pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- if(mprotect((void *) stack, pages * page_size(), prot) < 0)
+ if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0)
panic("protecting stack failed, errno = %d", errno);
}
@@ -96,15 +96,13 @@ void setup_machinename(char *machine_out)
strcpy(machine_out, host.machine);
}
-char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1];
-
-void setup_hostinfo(void)
+void setup_hostinfo(char *buf, int len)
{
struct utsname host;
uname(&host);
- sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename,
- host.release, host.version, host.machine);
+ snprintf(buf, len, "%s %s %s %s %s", host.sysname, host.nodename,
+ host.release, host.version, host.machine);
}
int setjmp_wrapper(void (*proc)(void *, void *), ...)
@@ -121,3 +119,9 @@ int setjmp_wrapper(void (*proc)(void *, void *), ...)
va_end(args);
return n;
}
+
+void os_dump_core(void)
+{
+ signal(SIGSEGV, SIG_DFL);
+ abort();
+}
diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
index f1bcd399ac9..0393e44813e 100644
--- a/arch/um/sys-i386/bugs.c
+++ b/arch/um/sys-i386/bugs.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -13,7 +13,6 @@
#include "sysdep/ptrace.h"
#include "task.h"
#include "os.h"
-#include "user_util.h"
#define MAXTOKEN 64
@@ -32,21 +31,21 @@ static char token(int fd, char *buf, int len, char stop)
n = os_read_file(fd, ptr, sizeof(*ptr));
c = *ptr++;
if(n != sizeof(*ptr)){
- if(n == 0) return(0);
+ if(n == 0)
+ return 0;
printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
if(n < 0)
- return(n);
- else
- return(-EIO);
+ return n;
+ else return -EIO;
}
} while((c != '\n') && (c != stop) && (ptr < end));
if(ptr == end){
printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
- return(-1);
+ return -1;
}
*(ptr - 1) = '\0';
- return(c);
+ return c;
}
static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
@@ -58,48 +57,25 @@ static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
while(1){
c = token(fd, scratch, len - 1, ':');
if(c <= 0)
- return(0);
+ return 0;
else if(c != ':'){
printk("Failed to find ':' in /proc/cpuinfo\n");
- return(0);
+ return 0;
}
if(!strncmp(scratch, key, strlen(key)))
- return(1);
+ return 1;
do {
n = os_read_file(fd, &c, sizeof(c));
if(n != sizeof(c)){
printk("Failed to find newline in "
"/proc/cpuinfo, err = %d\n", -n);
- return(0);
+ return 0;
}
} while(c != '\n');
}
- return(0);
-}
-
-int cpu_feature(char *what, char *buf, int len)
-{
- int fd, ret = 0;
-
- fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
- if(fd < 0){
- printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
- return(0);
- }
-
- if(!find_cpuinfo_line(fd, what, buf, len)){
- printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
- goto out_close;
- }
-
- token(fd, buf, len, '\n');
- ret = 1;
-
- out_close:
- os_close_file(fd);
- return(ret);
+ return 0;
}
static int check_cpu_flag(char *feature, int *have_it)
@@ -119,7 +95,8 @@ static int check_cpu_flag(char *feature, int *have_it)
goto out;
c = token(fd, buf, len - 1, ' ');
- if(c < 0) goto out;
+ if(c < 0)
+ goto out;
else if(c != ' '){
printk("Failed to find ' ' in /proc/cpuinfo\n");
goto out;
@@ -127,7 +104,8 @@ static int check_cpu_flag(char *feature, int *have_it)
while(1){
c = token(fd, buf, len - 1, ' ');
- if(c < 0) goto out;
+ if(c < 0)
+ goto out;
else if(c == '\n') break;
if(!strcmp(buf, feature)){
@@ -136,8 +114,10 @@ static int check_cpu_flag(char *feature, int *have_it)
}
}
out:
- if(*have_it == 0) printk("No\n");
- else if(*have_it == 1) printk("Yes\n");
+ if(*have_it == 0)
+ printk("No\n");
+ else if(*have_it == 1)
+ printk("Yes\n");
os_close_file(fd);
return 1;
}
@@ -189,12 +169,13 @@ int arch_handle_signal(int sig, union uml_pt_regs *regs)
/* This is testing for a cmov (0x0f 0x4x) instruction causing a
* SIGILL in init.
*/
- if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
+ if((sig != SIGILL) || (TASK_PID(get_current()) != 1))
+ return 0;
if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
panic("SIGILL in init, could not read instructions!\n");
if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
- return(0);
+ return 0;
if(host_has_cmov == 0)
panic("SIGILL caused by cmov, which this processor doesn't "
@@ -208,16 +189,5 @@ int arch_handle_signal(int sig, union uml_pt_regs *regs)
"implements it, boot a filesystem compiled for older "
"processors");
else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
- return(0);
+ return 0;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-i386/fault.c b/arch/um/sys-i386/fault.c
index d0bbcdfdb53..745b4fd49e9 100644
--- a/arch/um/sys-i386/fault.c
+++ b/arch/um/sys-i386/fault.c
@@ -3,9 +3,7 @@
* Licensed under the GPL
*/
-#include <signal.h>
#include "sysdep/ptrace.h"
-#include "sysdep/sigcontext.h"
/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
struct exception_table_entry
@@ -17,26 +15,14 @@ struct exception_table_entry
const struct exception_table_entry *search_exception_tables(unsigned long add);
/* Compare this to arch/i386/mm/extable.c:fixup_exception() */
-int arch_fixup(unsigned long address, void *sc_ptr)
+int arch_fixup(unsigned long address, union uml_pt_regs *regs)
{
- struct sigcontext *sc = sc_ptr;
const struct exception_table_entry *fixup;
fixup = search_exception_tables(address);
if(fixup != 0){
- sc->eip = fixup->fixup;
+ UPT_IP(regs) = fixup->fixup;
return(1);
}
return(0);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
index 01212c88fcc..40ff0c831bd 100644
--- a/arch/um/sys-i386/ptrace_user.c
+++ b/arch/um/sys-i386/ptrace_user.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -15,7 +15,6 @@
#include "user.h"
#include "os.h"
#include "uml-config.h"
-#include "user_util.h"
int ptrace_getregs(long pid, unsigned long *regs_out)
{
@@ -45,7 +44,8 @@ int ptrace_setfpregs(long pid, unsigned long *regs)
return 0;
}
-/* All the below stuff is of interest for TT mode only */
+#ifdef UML_CONFIG_MODE_TT
+
static void write_debugregs(int pid, unsigned long *regs)
{
struct user *dummy;
@@ -128,13 +128,4 @@ void update_debugregs(int seq)
}
#endif
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+#endif
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 3f6acd66771..1cbf95f6858 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -18,6 +18,28 @@
#include "skas.h"
+void copy_sc(union uml_pt_regs *regs, void *from)
+{
+ struct sigcontext *sc = from;
+
+ REGS_GS(regs->skas.regs) = sc->gs;
+ REGS_FS(regs->skas.regs) = sc->fs;
+ REGS_ES(regs->skas.regs) = sc->es;
+ REGS_DS(regs->skas.regs) = sc->ds;
+ REGS_EDI(regs->skas.regs) = sc->edi;
+ REGS_ESI(regs->skas.regs) = sc->esi;
+ REGS_EBP(regs->skas.regs) = sc->ebp;
+ REGS_SP(regs->skas.regs) = sc->esp;
+ REGS_EBX(regs->skas.regs) = sc->ebx;
+ REGS_EDX(regs->skas.regs) = sc->edx;
+ REGS_ECX(regs->skas.regs) = sc->ecx;
+ REGS_EAX(regs->skas.regs) = sc->eax;
+ REGS_IP(regs->skas.regs) = sc->eip;
+ REGS_CS(regs->skas.regs) = sc->cs;
+ REGS_EFLAGS(regs->skas.regs) = sc->eflags;
+ REGS_SS(regs->skas.regs) = sc->ss;
+}
+
static int copy_sc_from_user_skas(struct pt_regs *regs,
struct sigcontext __user *from)
{
@@ -28,33 +50,18 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
err = copy_from_user(&sc, from, sizeof(sc));
err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs));
if(err)
- return(err);
-
- REGS_GS(regs->regs.skas.regs) = sc.gs;
- REGS_FS(regs->regs.skas.regs) = sc.fs;
- REGS_ES(regs->regs.skas.regs) = sc.es;
- REGS_DS(regs->regs.skas.regs) = sc.ds;
- REGS_EDI(regs->regs.skas.regs) = sc.edi;
- REGS_ESI(regs->regs.skas.regs) = sc.esi;
- REGS_EBP(regs->regs.skas.regs) = sc.ebp;
- REGS_SP(regs->regs.skas.regs) = sc.esp;
- REGS_EBX(regs->regs.skas.regs) = sc.ebx;
- REGS_EDX(regs->regs.skas.regs) = sc.edx;
- REGS_ECX(regs->regs.skas.regs) = sc.ecx;
- REGS_EAX(regs->regs.skas.regs) = sc.eax;
- REGS_IP(regs->regs.skas.regs) = sc.eip;
- REGS_CS(regs->regs.skas.regs) = sc.cs;
- REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags;
- REGS_SS(regs->regs.skas.regs) = sc.ss;
+ return err;
+
+ copy_sc(&regs->regs, &sc);
err = restore_fp_registers(userspace_pid[0], fpregs);
- if(err < 0){
+ if(err < 0) {
printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, "
- "errno = %d\n", err);
- return(1);
+ "errno = %d\n", -err);
+ return err;
}
- return(0);
+ return 0;
}
int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp,
@@ -90,16 +97,16 @@ int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *t
if(err < 0){
printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, "
"errno = %d\n", err);
- return(1);
+ return 1;
}
to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1));
sc.fpstate = to_fp;
if(err)
- return(err);
+ return err;
- return(copy_to_user(to, &sc, sizeof(sc)) ||
- copy_to_user(to_fp, fpregs, sizeof(fpregs)));
+ return copy_to_user(to, &sc, sizeof(sc)) ||
+ copy_to_user(to_fp, fpregs, sizeof(fpregs));
}
#endif
@@ -129,7 +136,7 @@ int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from,
to->fpstate = to_fp;
if(to_fp != NULL)
err |= copy_from_user(to_fp, from_fp, fpsize);
- return(err);
+ return err;
}
int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp,
@@ -164,15 +171,15 @@ static int copy_sc_from_user(struct pt_regs *to, void __user *from)
ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from,
sizeof(struct _fpstate)),
copy_sc_from_user_skas(to, from));
- return(ret);
+ return ret;
}
static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp,
struct pt_regs *from, unsigned long sp)
{
- return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
+ return CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs),
sizeof(*fp), sp),
- copy_sc_to_user_skas(to, fp, from, sp)));
+ copy_sc_to_user_skas(to, fp, from, sp));
}
static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp,
@@ -185,7 +192,7 @@ static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __u
err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size);
err |= copy_sc_to_user(&uc->uc_mcontext, fp, &current->thread.regs, sp);
err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set));
- return(err);
+ return err;
}
struct sigframe
@@ -359,7 +366,7 @@ long sys_sigreturn(struct pt_regs regs)
/* Avoid ERESTART handling */
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
- return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+ return PT_REGS_SYSCALL_RET(&current->thread.regs);
segfault:
force_sig(SIGSEGV, current);
@@ -389,20 +396,9 @@ long sys_rt_sigreturn(struct pt_regs regs)
/* Avoid ERESTART handling */
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
- return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+ return PT_REGS_SYSCALL_RET(&current->thread.regs);
segfault:
force_sig(SIGSEGV, current);
return 0;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index 643dab58572..fea8e5e15cc 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -23,9 +23,13 @@
#include "skas.h"
#endif
-/* If needed we can detect when it's uninitialized. */
+/*
+ * If needed we can detect when it's uninitialized.
+ *
+ * These are initialized in an initcall and unchanged thereafter.
+ */
static int host_supports_tls = -1;
-int host_gdt_entry_tls_min = -1;
+int host_gdt_entry_tls_min;
#ifdef CONFIG_MODE_SKAS
int do_set_thread_area_skas(struct user_desc *info)
@@ -361,7 +365,8 @@ out:
/* XXX: This part is probably common to i386 and x86-64. Don't create a common
* file for now, do that when implementing x86-64 support.*/
-static int __init __setup_host_supports_tls(void) {
+static int __init __setup_host_supports_tls(void)
+{
check_host_supports_tls(&host_supports_tls, &host_gdt_entry_tls_min);
if (host_supports_tls) {
printk(KERN_INFO "Host TLS support detected\n");
diff --git a/arch/um/sys-i386/user-offsets.c b/arch/um/sys-i386/user-offsets.c
index 447306b20ae..29118cf5ff2 100644
--- a/arch/um/sys-i386/user-offsets.c
+++ b/arch/um/sys-i386/user-offsets.c
@@ -1,9 +1,10 @@
#include <stdio.h>
+#include <stddef.h>
#include <signal.h>
+#include <sys/poll.h>
+#include <sys/mman.h>
#include <asm/ptrace.h>
#include <asm/user.h>
-#include <stddef.h>
-#include <sys/poll.h>
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -47,7 +48,6 @@ void foo(void)
OFFSET(HOST_SC_FP_ST, _fpstate, _st);
OFFSET(HOST_SC_FXSR_ENV, _fpstate, _fxsr_env);
- DEFINE(HOST_FRAME_SIZE, FRAME_SIZE);
DEFINE_LONGS(HOST_FP_SIZE, sizeof(struct user_i387_struct));
DEFINE_LONGS(HOST_XFP_SIZE, sizeof(struct user_fxsr_struct));
@@ -73,4 +73,8 @@ void foo(void)
DEFINE(UM_POLLIN, POLLIN);
DEFINE(UM_POLLPRI, POLLPRI);
DEFINE(UM_POLLOUT, POLLOUT);
+
+ DEFINE(UM_PROT_READ, PROT_READ);
+ DEFINE(UM_PROT_WRITE, PROT_WRITE);
+ DEFINE(UM_PROT_EXEC, PROT_EXEC);
}
diff --git a/arch/um/sys-ppc/sigcontext.c b/arch/um/sys-ppc/sigcontext.c
index 5d430fc994a..4bdc15c89ed 100644
--- a/arch/um/sys-ppc/sigcontext.c
+++ b/arch/um/sys-ppc/sigcontext.c
@@ -1,7 +1,6 @@
#include "asm/ptrace.h"
#include "asm/sigcontext.h"
#include "sysdep/ptrace.h"
-#include "user_util.h"
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c
index fdce7ea98ca..09547889037 100644
--- a/arch/um/sys-x86_64/bugs.c
+++ b/arch/um/sys-x86_64/bugs.c
@@ -4,12 +4,7 @@
* Licensed under the GPL
*/
-#include "linux/sched.h"
-#include "linux/errno.h"
-#include "asm/system.h"
-#include "asm/pda.h"
#include "sysdep/ptrace.h"
-#include "os.h"
void arch_init_thread(void)
{
@@ -21,102 +16,5 @@ void arch_check_bugs(void)
int arch_handle_signal(int sig, union uml_pt_regs *regs)
{
- return(0);
+ return 0;
}
-
-#define MAXTOKEN 64
-
-/* Set during early boot */
-int host_has_cmov = 1;
-int host_has_xmm = 0;
-
-static char token(int fd, char *buf, int len, char stop)
-{
- int n;
- char *ptr, *end, c;
-
- ptr = buf;
- end = &buf[len];
- do {
- n = os_read_file(fd, ptr, sizeof(*ptr));
- c = *ptr++;
- if(n != sizeof(*ptr)){
- if(n == 0) return(0);
- printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
- if(n < 0)
- return(n);
- else
- return(-EIO);
- }
- } while((c != '\n') && (c != stop) && (ptr < end));
-
- if(ptr == end){
- printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
- return(-1);
- }
- *(ptr - 1) = '\0';
- return(c);
-}
-
-static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
-{
- int n;
- char c;
-
- scratch[len - 1] = '\0';
- while(1){
- c = token(fd, scratch, len - 1, ':');
- if(c <= 0)
- return(0);
- else if(c != ':'){
- printk("Failed to find ':' in /proc/cpuinfo\n");
- return(0);
- }
-
- if(!strncmp(scratch, key, strlen(key)))
- return(1);
-
- do {
- n = os_read_file(fd, &c, sizeof(c));
- if(n != sizeof(c)){
- printk("Failed to find newline in "
- "/proc/cpuinfo, err = %d\n", -n);
- return(0);
- }
- } while(c != '\n');
- }
- return(0);
-}
-
-int cpu_feature(char *what, char *buf, int len)
-{
- int fd, ret = 0;
-
- fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
- if(fd < 0){
- printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
- return(0);
- }
-
- if(!find_cpuinfo_line(fd, what, buf, len)){
- printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
- goto out_close;
- }
-
- token(fd, buf, len, '\n');
- ret = 1;
-
- out_close:
- os_close_file(fd);
- return(ret);
-}
-
-/* Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c
index cee1513c5c3..4636b1465b6 100644
--- a/arch/um/sys-x86_64/fault.c
+++ b/arch/um/sys-x86_64/fault.c
@@ -4,20 +4,24 @@
* Licensed under the GPL
*/
-#include "user.h"
+#include "sysdep/ptrace.h"
-int arch_fixup(unsigned long address, void *sc_ptr)
+/* These two are from asm-um/uaccess.h and linux/module.h, check them. */
+struct exception_table_entry
{
- /* XXX search_exception_tables() */
+ unsigned long insn;
+ unsigned long fixup;
+};
+
+const struct exception_table_entry *search_exception_tables(unsigned long add);
+int arch_fixup(unsigned long address, union uml_pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(address);
+ if(fixup != 0){
+ UPT_IP(regs) = fixup->fixup;
+ return(1);
+ }
return(0);
}
-
-/* Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index af2f017617b..fe8ec04d35b 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -20,6 +20,36 @@
#include "skas.h"
+void copy_sc(union uml_pt_regs *regs, void *from)
+{
+ struct sigcontext *sc = from;
+
+#define GETREG(regs, regno, sc, regname) \
+ (regs)->skas.regs[(regno) / sizeof(unsigned long)] = (sc)->regname
+
+ GETREG(regs, R8, sc, r8);
+ GETREG(regs, R9, sc, r9);
+ GETREG(regs, R10, sc, r10);
+ GETREG(regs, R11, sc, r11);
+ GETREG(regs, R12, sc, r12);
+ GETREG(regs, R13, sc, r13);
+ GETREG(regs, R14, sc, r14);
+ GETREG(regs, R15, sc, r15);
+ GETREG(regs, RDI, sc, rdi);
+ GETREG(regs, RSI, sc, rsi);
+ GETREG(regs, RBP, sc, rbp);
+ GETREG(regs, RBX, sc, rbx);
+ GETREG(regs, RDX, sc, rdx);
+ GETREG(regs, RAX, sc, rax);
+ GETREG(regs, RCX, sc, rcx);
+ GETREG(regs, RSP, sc, rsp);
+ GETREG(regs, RIP, sc, rip);
+ GETREG(regs, EFLAGS, sc, eflags);
+ GETREG(regs, CS, sc, cs);
+
+#undef GETREG
+}
+
static int copy_sc_from_user_skas(struct pt_regs *regs,
struct sigcontext __user *from)
{
@@ -51,7 +81,7 @@ static int copy_sc_from_user_skas(struct pt_regs *regs,
#undef GETREG
- return(err);
+ return err;
}
int copy_sc_to_user_skas(struct sigcontext __user *to,
diff --git a/arch/um/sys-x86_64/user-offsets.c b/arch/um/sys-x86_64/user-offsets.c
index 899cebb57c3..0d5fd764c21 100644
--- a/arch/um/sys-x86_64/user-offsets.c
+++ b/arch/um/sys-x86_64/user-offsets.c
@@ -2,6 +2,7 @@
#include <stddef.h>
#include <signal.h>
#include <sys/poll.h>
+#include <sys/mman.h>
#define __FRAME_OFFSETS
#include <asm/ptrace.h>
#include <asm/types.h>
@@ -57,7 +58,6 @@ void foo(void)
OFFSET(HOST_SC_SS, sigcontext, ss);
#endif
- DEFINE_LONGS(HOST_FRAME_SIZE, FRAME_SIZE);
DEFINE(HOST_FP_SIZE, sizeof(struct _fpstate) / sizeof(unsigned long));
DEFINE(HOST_XFP_SIZE, 0);
DEFINE_LONGS(HOST_RBX, RBX);
@@ -94,4 +94,8 @@ void foo(void)
DEFINE(UM_POLLIN, POLLIN);
DEFINE(UM_POLLPRI, POLLPRI);
DEFINE(UM_POLLOUT, POLLOUT);
+
+ DEFINE(UM_PROT_READ, PROT_READ);
+ DEFINE(UM_PROT_WRITE, PROT_WRITE);
+ DEFINE(UM_PROT_EXEC, PROT_EXEC);
}
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index 50ccc7f57cd..5f54c1236c1 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -37,6 +37,10 @@ config GENERIC_IRQ_PROBE
bool
default y
+config GENERIC_TIME
+ bool
+ default y
+
config TIME_LOW_RES
bool
default y
diff --git a/arch/v850/kernel/asm-offsets.c b/arch/v850/kernel/asm-offsets.c
index 24f29136907..cee5c3142d4 100644
--- a/arch/v850/kernel/asm-offsets.c
+++ b/arch/v850/kernel/asm-offsets.c
@@ -29,7 +29,7 @@ int main (void)
DEFINE (TASK_PTRACE, offsetof (struct task_struct, ptrace));
DEFINE (TASK_BLOCKED, offsetof (struct task_struct, blocked));
DEFINE (TASK_THREAD, offsetof (struct task_struct, thread));
- DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+ DEFINE (TASK_THREAD_INFO, offsetof (struct task_struct, stack));
DEFINE (TASK_MM, offsetof (struct task_struct, mm));
DEFINE (TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
DEFINE (TASK_PID, offsetof (struct task_struct, pid));
diff --git a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S
index 8bc521ca081..e4327a8d6bc 100644
--- a/arch/v850/kernel/entry.S
+++ b/arch/v850/kernel/entry.S
@@ -523,7 +523,7 @@ END(ret_from_trap)
/* This the initial entry point for a new child thread, with an appropriate
- stack in place that makes it look the the child is in the middle of an
+ stack in place that makes it look that the child is in the middle of an
syscall. This function is actually `returned to' from switch_thread
(copy_thread makes ret_from_fork the return address in each new thread's
saved context). */
diff --git a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c
index c4f844c86e5..e4a4b8e7d5a 100644
--- a/arch/v850/kernel/process.c
+++ b/arch/v850/kernel/process.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c
index 67e05750966..a9b09343097 100644
--- a/arch/v850/kernel/ptrace.c
+++ b/arch/v850/kernel/ptrace.c
@@ -21,7 +21,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
diff --git a/arch/v850/kernel/signal.c b/arch/v850/kernel/signal.c
index 17c2d4359b0..bf166e7e762 100644
--- a/arch/v850/kernel/signal.c
+++ b/arch/v850/kernel/signal.c
@@ -17,7 +17,6 @@
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c
index d2b1fb19d24..f9f00ccf532 100644
--- a/arch/v850/kernel/syscalls.c
+++ b/arch/v850/kernel/syscalls.c
@@ -18,7 +18,6 @@
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/sem.h>
#include <linux/msg.h>
diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
index 486e3a441c8..f0905b03523 100644
--- a/arch/v850/kernel/time.c
+++ b/arch/v850/kernel/time.c
@@ -90,81 +90,6 @@ static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs)
return IRQ_HANDLED;
}
-/*
- * This version of gettimeofday has near microsecond resolution.
- */
-void do_gettimeofday (struct timeval *tv)
-{
-#if 0 /* DAVIDM later if possible */
- extern volatile unsigned long lost_ticks;
- unsigned long lost;
-#endif
- unsigned long flags;
- unsigned long usec, sec;
- unsigned long seq;
-
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
-
-#if 0
- usec = mach_gettimeoffset ? mach_gettimeoffset () : 0;
-#else
- usec = 0;
-#endif
-#if 0 /* DAVIDM later if possible */
- lost = lost_ticks;
- if (lost)
- usec += lost * (1000000/HZ);
-#endif
- sec = xtime.tv_sec;
- usec += xtime.tv_nsec / 1000;
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
- while (usec >= 1000000) {
- usec -= 1000000;
- sec++;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irq (&xtime_lock);
-
- /* This is revolting. We need to set the xtime.tv_nsec
- * correctly. However, the value in this location is
- * is value at the last tick.
- * Discover what correction gettimeofday
- * would have done, and then undo it!
- */
-#if 0
- tv->tv_nsec -= mach_gettimeoffset() * 1000;
-#endif
-
- while (tv->tv_nsec < 0) {
- tv->tv_nsec += NSEC_PER_SEC;
- tv->tv_sec--;
- }
-
- xtime.tv_sec = tv->tv_sec;
- xtime.tv_nsec = tv->tv_nsec;
-
- ntp_clear();
-
- write_sequnlock_irq (&xtime_lock);
- clock_was_set();
- return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
static int timer_dev_id;
static struct irqaction timer_irqaction = {
timer_interrupt,
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 56eb14c9847..145bb824b2a 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -415,13 +415,13 @@ config OUT_OF_LINE_PFN_TO_PAGE
depends on DISCONTIGMEM
config NR_CPUS
- int "Maximum number of CPUs (2-256)"
+ int "Maximum number of CPUs (2-255)"
range 2 255
depends on SMP
default "8"
help
This allows you to specify the maximum number of CPUs which this
- kernel will support. Current maximum is 256 CPUs due to
+ kernel will support. Current maximum is 255 CPUs due to
APIC addressing limits. Less depending on the hardware.
This is purely to save memory - each supported CPU requires
@@ -565,23 +565,56 @@ config CRASH_DUMP
PHYSICAL_START.
For more details see Documentation/kdump/kdump.txt
+config RELOCATABLE
+ bool "Build a relocatable kernel(EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ Builds a relocatable kernel. This enables loading and running
+ a kernel binary from a different physical address than it has
+ been compiled for.
+
+ One use is for the kexec on panic case where the recovery kernel
+ must live at a different physical address than the primary
+ kernel.
+
+ Note: If CONFIG_RELOCATABLE=y, then kernel run from the address
+ it has been loaded at and compile time physical address
+ (CONFIG_PHYSICAL_START) is ignored.
+
config PHYSICAL_START
hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
- default "0x1000000" if CRASH_DUMP
default "0x200000"
help
- This gives the physical address where the kernel is loaded. Normally
- for regular kernels this value is 0x200000 (2MB). But in the case
- of kexec on panic the fail safe kernel needs to run at a different
- address than the panic-ed kernel. This option is used to set the load
- address for kernels used to capture crash dump on being kexec'ed
- after panic. The default value for crash dump kernels is
- 0x1000000 (16MB). This can also be set based on the "X" value as
+ This gives the physical address where the kernel is loaded. It
+ should be aligned to 2MB boundary.
+
+ If kernel is a not relocatable (CONFIG_RELOCATABLE=n) then
+ bzImage will decompress itself to above physical address and
+ run from there. Otherwise, bzImage will run from the address where
+ it has been loaded by the boot loader and will ignore above physical
+ address.
+
+ In normal kdump cases one does not have to set/change this option
+ as now bzImage can be compiled as a completely relocatable image
+ (CONFIG_RELOCATABLE=y) and be used to load and run from a different
+ address. This option is mainly useful for the folks who don't want
+ to use a bzImage for capturing the crash dump and want to use a
+ vmlinux instead.
+
+ So if you are using bzImage for capturing the crash dump, leave
+ the value here unchanged to 0x200000 and set CONFIG_RELOCATABLE=y.
+ Otherwise if you plan to use vmlinux for capturing the crash dump
+ change this value to start of the reserved region (Typically 16MB
+ 0x1000000). In other words, it can be set based on the "X" value as
specified in the "crashkernel=YM@XM" command line boot parameter
passed to the panic-ed kernel. Typically this parameter is set as
crashkernel=64M@16M. Please take a look at
Documentation/kdump/kdump.txt for more details about crash dumps.
+ Usage of bzImage for capturing the crash dump is advantageous as
+ one does not have to build two kernels. Same kernel can be used
+ as production kernel and capture kernel.
+
Don't change this unless you know what you are doing.
config SECCOMP
@@ -627,14 +660,6 @@ config CC_STACKPROTECTOR_ALL
source kernel/Kconfig.hz
-config REORDER
- bool "Function reordering"
- default n
- help
- This option enables the toolchain to reorder functions for a more
- optimal TLB usage. If you have pretty much any version of binutils,
- this can increase your kernel build time by roughly one minute.
-
config K8_NB
def_bool y
depends on AGP_AMD64 || IOMMU || (PCI && NUMA)
@@ -676,6 +701,7 @@ menu "Bus options (PCI etc.)"
config PCI
bool "PCI support"
+ select ARCH_SUPPORTS_MSI if (X86_LOCAL_APIC && X86_IO_APIC)
# x86-64 doesn't support PCI BIOS access from long mode so always go direct.
config PCI_DIRECT
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 2941a915d4e..29617ae3926 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -40,10 +40,6 @@ cflags-y += -m64
cflags-y += -mno-red-zone
cflags-y += -mcmodel=kernel
cflags-y += -pipe
-cflags-kernel-$(CONFIG_REORDER) += -ffunction-sections
-# this makes reading assembly source easier, but produces worse code
-# actually it makes the kernel smaller too.
-cflags-y += -fno-reorder-blocks
cflags-y += -Wno-sign-compare
cflags-y += -fno-asynchronous-unwind-tables
ifneq ($(CONFIG_DEBUG_INFO),y)
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index deb063e7762..ee6f6505f95 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -36,7 +36,7 @@ subdir- := compressed/ #Let make clean descend in compressed/
# ---------------------------------------------------------------------------
$(obj)/bzImage: IMAGE_OFFSET := 0x100000
-$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
+$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
$(obj)/bzImage: BUILDFLAGS := -b
quiet_cmd_image = BUILD $@
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
index e70fa6e1da0..705a3e33d7e 100644
--- a/arch/x86_64/boot/compressed/Makefile
+++ b/arch/x86_64/boot/compressed/Makefile
@@ -8,16 +8,14 @@
targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
EXTRA_AFLAGS := -traditional
-AFLAGS := $(subst -m64,-m32,$(AFLAGS))
# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
# -m32
-CFLAGS := -m32 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing
-LDFLAGS := -m elf_i386
+CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin
+LDFLAGS := -m elf_x86_64
-LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 -m elf_i386
-
-$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
+LDFLAGS_vmlinux := -T
+$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
@@ -27,7 +25,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
-LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T
+LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
$(call if_changed,ld)
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S
index 6f55565e4d4..f9d5692a010 100644
--- a/arch/x86_64/boot/compressed/head.S
+++ b/arch/x86_64/boot/compressed/head.S
@@ -26,116 +26,279 @@
#include <linux/linkage.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/page.h>
+#include <asm/msr.h>
+.section ".text.head"
.code32
.globl startup_32
-
+
startup_32:
cld
cli
- movl $(__KERNEL_DS),%eax
- movl %eax,%ds
- movl %eax,%es
- movl %eax,%fs
- movl %eax,%gs
-
- lss stack_start,%esp
- xorl %eax,%eax
-1: incl %eax # check that A20 really IS enabled
- movl %eax,0x000000 # loop forever if it isn't
- cmpl %eax,0x100000
- je 1b
+ movl $(__KERNEL_DS), %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+/* Calculate the delta between where we were compiled to run
+ * at and where we were actually loaded at. This can only be done
+ * with a short local call on x86. Nothing else will tell us what
+ * address we are running at. The reserved chunk of the real-mode
+ * data at 0x34-0x3f are used as the stack for this calculation.
+ * Only 4 bytes are needed.
+ */
+ leal 0x40(%esi), %esp
+ call 1f
+1: popl %ebp
+ subl $1b, %ebp
+
+/* setup a stack and make sure cpu supports long mode. */
+ movl $user_stack_end, %eax
+ addl %ebp, %eax
+ movl %eax, %esp
+
+ call verify_cpu
+ testl %eax, %eax
+ jnz no_longmode
+
+/* Compute the delta between where we were compiled to run at
+ * and where the code will actually run at.
+ */
+/* %ebp contains the address we are loaded at by the boot loader and %ebx
+ * contains the address where we should move the kernel image temporarily
+ * for safe in-place decompression.
+ */
+
+#ifdef CONFIG_RELOCATABLE
+ movl %ebp, %ebx
+ addl $(LARGE_PAGE_SIZE -1), %ebx
+ andl $LARGE_PAGE_MASK, %ebx
+#else
+ movl $CONFIG_PHYSICAL_START, %ebx
+#endif
+
+ /* Replace the compressed data size with the uncompressed size */
+ subl input_len(%ebp), %ebx
+ movl output_len(%ebp), %eax
+ addl %eax, %ebx
+ /* Add 8 bytes for every 32K input block */
+ shrl $12, %eax
+ addl %eax, %ebx
+ /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
+ addl $(32768 + 18 + 4095), %ebx
+ andl $~4095, %ebx
/*
- * Initialize eflags. Some BIOS's leave bits like NT set. This would
- * confuse the debugger if this code is traced.
- * XXX - best to initialize before switching to protected mode.
+ * Prepare for entering 64 bit mode
*/
- pushl $0
- popfl
+
+ /* Load new GDT with the 64bit segments using 32bit descriptor */
+ leal gdt(%ebp), %eax
+ movl %eax, gdt+2(%ebp)
+ lgdt gdt(%ebp)
+
+ /* Enable PAE mode */
+ xorl %eax, %eax
+ orl $(1 << 5), %eax
+ movl %eax, %cr4
+
+ /*
+ * Build early 4G boot pagetable
+ */
+ /* Initialize Page tables to 0*/
+ leal pgtable(%ebx), %edi
+ xorl %eax, %eax
+ movl $((4096*6)/4), %ecx
+ rep stosl
+
+ /* Build Level 4 */
+ leal pgtable + 0(%ebx), %edi
+ leal 0x1007 (%edi), %eax
+ movl %eax, 0(%edi)
+
+ /* Build Level 3 */
+ leal pgtable + 0x1000(%ebx), %edi
+ leal 0x1007(%edi), %eax
+ movl $4, %ecx
+1: movl %eax, 0x00(%edi)
+ addl $0x00001000, %eax
+ addl $8, %edi
+ decl %ecx
+ jnz 1b
+
+ /* Build Level 2 */
+ leal pgtable + 0x2000(%ebx), %edi
+ movl $0x00000183, %eax
+ movl $2048, %ecx
+1: movl %eax, 0(%edi)
+ addl $0x00200000, %eax
+ addl $8, %edi
+ decl %ecx
+ jnz 1b
+
+ /* Enable the boot page tables */
+ leal pgtable(%ebx), %eax
+ movl %eax, %cr3
+
+ /* Enable Long mode in EFER (Extended Feature Enable Register) */
+ movl $MSR_EFER, %ecx
+ rdmsr
+ btsl $_EFER_LME, %eax
+ wrmsr
+
+ /* Setup for the jump to 64bit mode
+ *
+ * When the jump is performend we will be in long mode but
+ * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
+ * (and in turn EFER.LMA = 1). To jump into 64bit mode we use
+ * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+ * We place all of the values on our mini stack so lret can
+ * used to perform that far jump.
+ */
+ pushl $__KERNEL_CS
+ leal startup_64(%ebp), %eax
+ pushl %eax
+
+ /* Enter paged protected Mode, activating Long Mode */
+ movl $0x80000001, %eax /* Enable Paging and Protected mode */
+ movl %eax, %cr0
+
+ /* Jump from 32bit compatibility mode into 64bit mode. */
+ lret
+
+no_longmode:
+ /* This isn't an x86-64 CPU so hang */
+1:
+ hlt
+ jmp 1b
+
+#include "../../kernel/verify_cpu.S"
+
+ /* Be careful here startup_64 needs to be at a predictable
+ * address so I can export it in an ELF header. Bootloaders
+ * should look at the ELF header to find this address, as
+ * it may change in the future.
+ */
+ .code64
+ .org 0x200
+ENTRY(startup_64)
+ /* We come here either from startup_32 or directly from a
+ * 64bit bootloader. If we come here from a bootloader we depend on
+ * an identity mapped page table being provied that maps our
+ * entire text+data+bss and hopefully all of memory.
+ */
+
+ /* Setup data segments. */
+ xorl %eax, %eax
+ movl %eax, %ds
+ movl %eax, %es
+ movl %eax, %ss
+
+ /* Compute the decompressed kernel start address. It is where
+ * we were loaded at aligned to a 2M boundary. %rbp contains the
+ * decompressed kernel start address.
+ *
+ * If it is a relocatable kernel then decompress and run the kernel
+ * from load address aligned to 2MB addr, otherwise decompress and
+ * run the kernel from CONFIG_PHYSICAL_START
+ */
+
+ /* Start with the delta to where the kernel will run at. */
+#ifdef CONFIG_RELOCATABLE
+ leaq startup_32(%rip) /* - $startup_32 */, %rbp
+ addq $(LARGE_PAGE_SIZE - 1), %rbp
+ andq $LARGE_PAGE_MASK, %rbp
+ movq %rbp, %rbx
+#else
+ movq $CONFIG_PHYSICAL_START, %rbp
+ movq %rbp, %rbx
+#endif
+
+ /* Replace the compressed data size with the uncompressed size */
+ movl input_len(%rip), %eax
+ subq %rax, %rbx
+ movl output_len(%rip), %eax
+ addq %rax, %rbx
+ /* Add 8 bytes for every 32K input block */
+ shrq $12, %rax
+ addq %rax, %rbx
+ /* Add 32K + 18 bytes of extra slack and align on a 4K boundary */
+ addq $(32768 + 18 + 4095), %rbx
+ andq $~4095, %rbx
+
+/* Copy the compressed kernel to the end of our buffer
+ * where decompression in place becomes safe.
+ */
+ leaq _end(%rip), %r8
+ leaq _end(%rbx), %r9
+ movq $_end /* - $startup_32 */, %rcx
+1: subq $8, %r8
+ subq $8, %r9
+ movq 0(%r8), %rax
+ movq %rax, 0(%r9)
+ subq $8, %rcx
+ jnz 1b
+
+/*
+ * Jump to the relocated address.
+ */
+ leaq relocated(%rbx), %rax
+ jmp *%rax
+
+.section ".text"
+relocated:
+
/*
* Clear BSS
*/
- xorl %eax,%eax
- movl $_edata,%edi
- movl $_end,%ecx
- subl %edi,%ecx
+ xorq %rax, %rax
+ leaq _edata(%rbx), %rdi
+ leaq _end(%rbx), %rcx
+ subq %rdi, %rcx
cld
rep
stosb
+
+ /* Setup the stack */
+ leaq user_stack_end(%rip), %rsp
+
+ /* zero EFLAGS after setting rsp */
+ pushq $0
+ popfq
+
/*
* Do the decompression, and jump to the new kernel..
*/
- subl $16,%esp # place for structure on the stack
- movl %esp,%eax
- pushl %esi # real mode pointer as second arg
- pushl %eax # address of structure as first arg
- call decompress_kernel
- orl %eax,%eax
- jnz 3f
- addl $8,%esp
- xorl %ebx,%ebx
- ljmp $(__KERNEL_CS), $__PHYSICAL_START
+ pushq %rsi # Save the real mode argument
+ movq %rsi, %rdi # real mode address
+ leaq _heap(%rip), %rsi # _heap
+ leaq input_data(%rip), %rdx # input_data
+ movl input_len(%rip), %eax
+ movq %rax, %rcx # input_len
+ movq %rbp, %r8 # output
+ call decompress_kernel
+ popq %rsi
-/*
- * We come here, if we were loaded high.
- * We need to move the move-in-place routine down to 0x1000
- * and then start it with the buffer addresses in registers,
- * which we got from the stack.
- */
-3:
- movl %esi,%ebx
- movl $move_routine_start,%esi
- movl $0x1000,%edi
- movl $move_routine_end,%ecx
- subl %esi,%ecx
- addl $3,%ecx
- shrl $2,%ecx
- cld
- rep
- movsl
-
- popl %esi # discard the address
- addl $4,%esp # real mode pointer
- popl %esi # low_buffer_start
- popl %ecx # lcount
- popl %edx # high_buffer_start
- popl %eax # hcount
- movl $__PHYSICAL_START,%edi
- cli # make sure we don't get interrupted
- ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
/*
- * Routine (template) for moving the decompressed kernel in place,
- * if we were high loaded. This _must_ PIC-code !
+ * Jump to the decompressed kernel.
*/
-move_routine_start:
- movl %ecx,%ebp
- shrl $2,%ecx
- rep
- movsl
- movl %ebp,%ecx
- andl $3,%ecx
- rep
- movsb
- movl %edx,%esi
- movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0
- addl $3,%ecx
- shrl $2,%ecx
- rep
- movsl
- movl %ebx,%esi # Restore setup pointer
- xorl %ebx,%ebx
- ljmp $(__KERNEL_CS), $__PHYSICAL_START
-move_routine_end:
+ jmp *%rbp
-
-/* Stack for uncompression */
- .align 32
-user_stack:
+ .data
+gdt:
+ .word gdt_end - gdt
+ .long gdt
+ .word 0
+ .quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00af9a000000ffff /* __KERNEL_CS */
+ .quad 0x00cf92000000ffff /* __KERNEL_DS */
+gdt_end:
+ .bss
+/* Stack for uncompression */
+ .balign 4
+user_stack:
.fill 4096,4,0
-stack_start:
- .long user_stack+4096
- .word __KERNEL_DS
-
+user_stack_end:
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c
index 3755b2e394d..f932b0e8909 100644
--- a/arch/x86_64/boot/compressed/misc.c
+++ b/arch/x86_64/boot/compressed/misc.c
@@ -9,10 +9,95 @@
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
*/
+#define _LINUX_STRING_H_ 1
+#define __LINUX_BITMAP_H 1
+
+#include <linux/linkage.h>
#include <linux/screen_info.h>
#include <asm/io.h>
#include <asm/page.h>
+/* WARNING!!
+ * This code is compiled with -fPIC and it is relocated dynamically
+ * at run time, but no relocation processing is performed.
+ * This means that it is not safe to place pointers in static structures.
+ */
+
+/*
+ * Getting to provable safe in place decompression is hard.
+ * Worst case behaviours need to be analized.
+ * Background information:
+ *
+ * The file layout is:
+ * magic[2]
+ * method[1]
+ * flags[1]
+ * timestamp[4]
+ * extraflags[1]
+ * os[1]
+ * compressed data blocks[N]
+ * crc[4] orig_len[4]
+ *
+ * resulting in 18 bytes of non compressed data overhead.
+ *
+ * Files divided into blocks
+ * 1 bit (last block flag)
+ * 2 bits (block type)
+ *
+ * 1 block occurs every 32K -1 bytes or when there 50% compression has been achieved.
+ * The smallest block type encoding is always used.
+ *
+ * stored:
+ * 32 bits length in bytes.
+ *
+ * fixed:
+ * magic fixed tree.
+ * symbols.
+ *
+ * dynamic:
+ * dynamic tree encoding.
+ * symbols.
+ *
+ *
+ * The buffer for decompression in place is the length of the
+ * uncompressed data, plus a small amount extra to keep the algorithm safe.
+ * The compressed data is placed at the end of the buffer. The output
+ * pointer is placed at the start of the buffer and the input pointer
+ * is placed where the compressed data starts. Problems will occur
+ * when the output pointer overruns the input pointer.
+ *
+ * The output pointer can only overrun the input pointer if the input
+ * pointer is moving faster than the output pointer. A condition only
+ * triggered by data whose compressed form is larger than the uncompressed
+ * form.
+ *
+ * The worst case at the block level is a growth of the compressed data
+ * of 5 bytes per 32767 bytes.
+ *
+ * The worst case internal to a compressed block is very hard to figure.
+ * The worst case can at least be boundined by having one bit that represents
+ * 32764 bytes and then all of the rest of the bytes representing the very
+ * very last byte.
+ *
+ * All of which is enough to compute an amount of extra data that is required
+ * to be safe. To avoid problems at the block level allocating 5 extra bytes
+ * per 32767 bytes of data is sufficient. To avoind problems internal to a block
+ * adding an extra 32767 bytes (the worst case uncompressed block size) is
+ * sufficient, to ensure that in the worst case the decompressed data for
+ * block will stop the byte before the compressed data for a block begins.
+ * To avoid problems with the compressed data's meta information an extra 18
+ * bytes are needed. Leading to the formula:
+ *
+ * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
+ *
+ * Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
+ * Adding 32768 instead of 32767 just makes for round numbers.
+ * Adding the decompressor_size is necessary as it musht live after all
+ * of the data as well. Last I measured the decompressor is about 14K.
+ * 10K of actuall data and 4K of bss.
+ *
+ */
+
/*
* gzip declarations
*/
@@ -28,15 +113,20 @@ typedef unsigned char uch;
typedef unsigned short ush;
typedef unsigned long ulg;
-#define WSIZE 0x8000 /* Window size must be at least 32k, */
- /* and a power of two */
+#define WSIZE 0x80000000 /* Window size must be at least 32k,
+ * and a power of two
+ * We don't actually have a window just
+ * a huge output buffer so I report
+ * a 2G windows size, as that should
+ * always be larger than our output buffer.
+ */
-static uch *inbuf; /* input buffer */
-static uch window[WSIZE]; /* Sliding window buffer */
+static uch *inbuf; /* input buffer */
+static uch *window; /* Sliding window buffer, (and final output buffer) */
-static unsigned insize = 0; /* valid bytes in inbuf */
-static unsigned inptr = 0; /* index of next byte to be processed in inbuf */
-static unsigned outcnt = 0; /* bytes in output buffer */
+static unsigned insize; /* valid bytes in inbuf */
+static unsigned inptr; /* index of next byte to be processed in inbuf */
+static unsigned outcnt; /* bytes in output buffer */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
@@ -87,8 +177,6 @@ extern unsigned char input_data[];
extern int input_len;
static long bytes_out = 0;
-static uch *output_data;
-static unsigned long output_ptr = 0;
static void *malloc(int size);
static void free(void *where);
@@ -98,17 +186,10 @@ static void *memcpy(void *dest, const void *src, unsigned n);
static void putstr(const char *);
-extern int end;
-static long free_mem_ptr = (long)&end;
+static long free_mem_ptr;
static long free_mem_end_ptr;
-#define INPLACE_MOVE_ROUTINE 0x1000
-#define LOW_BUFFER_START 0x2000
-#define LOW_BUFFER_MAX 0x90000
-#define HEAP_SIZE 0x3000
-static unsigned int low_buffer_end, low_buffer_size;
-static int high_loaded =0;
-static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
+#define HEAP_SIZE 0x7000
static char *vidmem = (char *)0xb8000;
static int vidport;
@@ -218,58 +299,31 @@ static void* memcpy(void* dest, const void* src, unsigned n)
*/
static int fill_inbuf(void)
{
- if (insize != 0) {
- error("ran out of input data");
- }
-
- inbuf = input_data;
- insize = input_len;
- inptr = 1;
- return inbuf[0];
+ error("ran out of input data");
+ return 0;
}
/* ===========================================================================
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
-static void flush_window_low(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, *out, ch;
-
- in = window;
- out = &output_data[output_ptr];
- for (n = 0; n < outcnt; n++) {
- ch = *out++ = *in++;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- output_ptr += (ulg)outcnt;
- outcnt = 0;
-}
-
-static void flush_window_high(void)
-{
- ulg c = crc; /* temporary variable */
- unsigned n;
- uch *in, ch;
- in = window;
- for (n = 0; n < outcnt; n++) {
- ch = *output_data++ = *in++;
- if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start;
- c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
- }
- crc = c;
- bytes_out += (ulg)outcnt;
- outcnt = 0;
-}
-
static void flush_window(void)
{
- if (high_loaded) flush_window_high();
- else flush_window_low();
+ /* With my window equal to my output buffer
+ * I only need to compute the crc here.
+ */
+ ulg c = crc; /* temporary variable */
+ unsigned n;
+ uch *in, ch;
+
+ in = window;
+ for (n = 0; n < outcnt; n++) {
+ ch = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+ bytes_out += (ulg)outcnt;
+ outcnt = 0;
}
static void error(char *x)
@@ -281,57 +335,8 @@ static void error(char *x)
while(1); /* Halt */
}
-static void setup_normal_output_buffer(void)
-{
-#ifdef STANDARD_MEMORY_BIOS_CALL
- if (RM_EXT_MEM_K < 1024) error("Less than 2MB of memory");
-#else
- if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
-#endif
- output_data = (unsigned char *)__PHYSICAL_START; /* Normally Points to 1M */
- free_mem_end_ptr = (long)real_mode;
-}
-
-struct moveparams {
- uch *low_buffer_start; int lcount;
- uch *high_buffer_start; int hcount;
-};
-
-static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
-{
- high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE);
-#ifdef STANDARD_MEMORY_BIOS_CALL
- if (RM_EXT_MEM_K < (3*1024)) error("Less than 4MB of memory");
-#else
- if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory");
-#endif
- mv->low_buffer_start = output_data = (unsigned char *)LOW_BUFFER_START;
- low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX
- ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff;
- low_buffer_size = low_buffer_end - LOW_BUFFER_START;
- high_loaded = 1;
- free_mem_end_ptr = (long)high_buffer_start;
- if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
- high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
- mv->hcount = 0; /* say: we need not to move high_buffer */
- }
- else mv->hcount = -1;
- mv->high_buffer_start = high_buffer_start;
-}
-
-static void close_output_buffer_if_we_run_high(struct moveparams *mv)
-{
- if (bytes_out > low_buffer_size) {
- mv->lcount = low_buffer_size;
- if (mv->hcount)
- mv->hcount = bytes_out - low_buffer_size;
- } else {
- mv->lcount = bytes_out;
- mv->hcount = 0;
- }
-}
-
-int decompress_kernel(struct moveparams *mv, void *rmode)
+asmlinkage void decompress_kernel(void *rmode, unsigned long heap,
+ uch *input_data, unsigned long input_len, uch *output)
{
real_mode = rmode;
@@ -346,13 +351,21 @@ int decompress_kernel(struct moveparams *mv, void *rmode)
lines = RM_SCREEN_INFO.orig_video_lines;
cols = RM_SCREEN_INFO.orig_video_cols;
- if (free_mem_ptr < 0x100000) setup_normal_output_buffer();
- else setup_output_buffer_if_we_run_high(mv);
+ window = output; /* Output buffer (Normally at 1M) */
+ free_mem_ptr = heap; /* Heap */
+ free_mem_end_ptr = heap + HEAP_SIZE;
+ inbuf = input_data; /* Input buffer */
+ insize = input_len;
+ inptr = 0;
+
+ if ((ulg)output & (__KERNEL_ALIGN - 1))
+ error("Destination address not 2M aligned");
+ if ((ulg)output >= 0xffffffffffUL)
+ error("Destination address too large");
makecrc();
putstr(".\nDecompressing Linux...");
gunzip();
putstr("done.\nBooting the kernel.\n");
- if (high_loaded) close_output_buffer_if_we_run_high(mv);
- return high_loaded;
+ return;
}
diff --git a/arch/x86_64/boot/compressed/vmlinux.lds b/arch/x86_64/boot/compressed/vmlinux.lds
new file mode 100644
index 00000000000..94c13e557fb
--- /dev/null
+++ b/arch/x86_64/boot/compressed/vmlinux.lds
@@ -0,0 +1,44 @@
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(startup_64)
+SECTIONS
+{
+ /* Be careful parts of head.S assume startup_32 is at
+ * address 0.
+ */
+ . = 0;
+ .text : {
+ _head = . ;
+ *(.text.head)
+ _ehead = . ;
+ *(.text.compressed)
+ _text = .; /* Text */
+ *(.text)
+ *(.text.*)
+ _etext = . ;
+ }
+ .rodata : {
+ _rodata = . ;
+ *(.rodata) /* read-only data */
+ *(.rodata.*)
+ _erodata = . ;
+ }
+ .data : {
+ _data = . ;
+ *(.data)
+ *(.data.*)
+ _edata = . ;
+ }
+ .bss : {
+ _bss = . ;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ . = ALIGN(8);
+ _end = . ;
+ . = ALIGN(4096);
+ pgtable = . ;
+ . = . + 4096 * 6;
+ _heap = .;
+ }
+}
diff --git a/arch/x86_64/boot/compressed/vmlinux.scr b/arch/x86_64/boot/compressed/vmlinux.scr
index 1ed9d791f86..bd1429ce193 100644
--- a/arch/x86_64/boot/compressed/vmlinux.scr
+++ b/arch/x86_64/boot/compressed/vmlinux.scr
@@ -1,9 +1,10 @@
SECTIONS
{
- .data : {
+ .text.compressed : {
input_len = .;
- LONG(input_data_end - input_data) input_data = .;
- *(.data)
- input_data_end = .;
+ LONG(input_data_end - input_data) input_data = .;
+ *(.data)
+ output_len = . - 4;
+ input_data_end = .;
}
}
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
index 770940cc010..e9e33f94969 100644
--- a/arch/x86_64/boot/setup.S
+++ b/arch/x86_64/boot/setup.S
@@ -51,6 +51,7 @@
#include <asm/boot.h>
#include <asm/e820.h>
#include <asm/page.h>
+#include <asm/setup.h>
/* Signature words to ensure LILO loaded us right */
#define SIG1 0xAA55
@@ -80,7 +81,7 @@ start:
# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
.ascii "HdrS" # header signature
- .word 0x0204 # header version number (>= 0x0105)
+ .word 0x0206 # header version number (>= 0x0105)
# or else old loadlin-1.5 will fail)
realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
start_sys_seg: .word SYSSEG
@@ -155,7 +156,20 @@ cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
# low memory 0x10000 or higher.
ramdisk_max: .long 0xffffffff
-
+kernel_alignment: .long 0x200000 # physical addr alignment required for
+ # protected mode relocatable kernel
+#ifdef CONFIG_RELOCATABLE
+relocatable_kernel: .byte 1
+#else
+relocatable_kernel: .byte 0
+#endif
+pad2: .byte 0
+pad3: .word 0
+
+cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
+ #added with boot protocol
+ #version 2.06
+
trampoline: call start_of_setup
.align 16
# The offset at this point is 0x240
@@ -290,64 +304,10 @@ loader_ok:
movw %cs,%ax
movw %ax,%ds
- /* minimum CPUID flags for x86-64 */
- /* see http://www.x86-64.org/lists/discuss/msg02971.html */
-#define SSE_MASK ((1<<25)|(1<<26))
-#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\
- (1<<13)|(1<<15)|(1<<24))
-#define REQUIRED_MASK2 (1<<29)
-
- pushfl /* standard way to check for cpuid */
- popl %eax
- movl %eax,%ebx
- xorl $0x200000,%eax
- pushl %eax
- popfl
- pushfl
- popl %eax
- cmpl %eax,%ebx
- jz no_longmode /* cpu has no cpuid */
- movl $0x0,%eax
- cpuid
- cmpl $0x1,%eax
- jb no_longmode /* no cpuid 1 */
- xor %di,%di
- cmpl $0x68747541,%ebx /* AuthenticAMD */
- jnz noamd
- cmpl $0x69746e65,%edx
- jnz noamd
- cmpl $0x444d4163,%ecx
- jnz noamd
- mov $1,%di /* cpu is from AMD */
-noamd:
- movl $0x1,%eax
- cpuid
- andl $REQUIRED_MASK1,%edx
- xorl $REQUIRED_MASK1,%edx
- jnz no_longmode
- movl $0x80000000,%eax
- cpuid
- cmpl $0x80000001,%eax
- jb no_longmode /* no extended cpuid */
- movl $0x80000001,%eax
- cpuid
- andl $REQUIRED_MASK2,%edx
- xorl $REQUIRED_MASK2,%edx
- jnz no_longmode
-sse_test:
- movl $1,%eax
- cpuid
- andl $SSE_MASK,%edx
- cmpl $SSE_MASK,%edx
- je sse_ok
- test %di,%di
- jz no_longmode /* only try to force SSE on AMD */
- movl $0xc0010015,%ecx /* HWCR */
- rdmsr
- btr $15,%eax /* enable SSE */
- wrmsr
- xor %di,%di /* don't loop */
- jmp sse_test /* try again */
+ call verify_cpu
+ testl %eax,%eax
+ jz sse_ok
+
no_longmode:
call beep
lea long_mode_panic,%si
@@ -357,7 +317,8 @@ no_longmode_loop:
long_mode_panic:
.string "Your CPU does not support long mode. Use a 32bit distribution."
.byte 0
-
+
+#include "../kernel/verify_cpu.S"
sse_ok:
popw %ds
@@ -846,7 +807,7 @@ gdt_48:
# Include video setup & detection code
-#include "video.S"
+#include "../../i386/boot/video.S"
# Setup signature -- must be last
setup_sig1: .word SIG1
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
deleted file mode 100644
index 6090516c9c7..00000000000
--- a/arch/x86_64/boot/video.S
+++ /dev/null
@@ -1,2043 +0,0 @@
-/* video.S
- *
- * Display adapter & video mode setup, version 2.13 (14-May-99)
- *
- * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
- * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
- *
- * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
- *
- * For further information, look at Documentation/svga.txt.
- *
- */
-
-/* Enable autodetection of SVGA adapters and modes. */
-#undef CONFIG_VIDEO_SVGA
-
-/* Enable autodetection of VESA modes */
-#define CONFIG_VIDEO_VESA
-
-/* Enable compacting of mode table */
-#define CONFIG_VIDEO_COMPACT
-
-/* Retain screen contents when switching modes */
-#define CONFIG_VIDEO_RETAIN
-
-/* Enable local mode list */
-#undef CONFIG_VIDEO_LOCAL
-
-/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
-#undef CONFIG_VIDEO_400_HACK
-
-/* Hack that lets you force specific BIOS mode ID and specific dimensions */
-#undef CONFIG_VIDEO_GFX_HACK
-#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
-#define VIDEO_GFX_BIOS_BX 0x0102
-#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
-
-/* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- * NORMAL_VGA (-1)
- * EXTENDED_VGA (-2)
- * ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
-#define VIDEO_FIRST_MENU 0x0000
-
-/* Standard BIOS video modes (BIOS number + 0x0100) */
-#define VIDEO_FIRST_BIOS 0x0100
-
-/* VESA BIOS video modes (VESA number + 0x0200) */
-#define VIDEO_FIRST_VESA 0x0200
-
-/* Video7 special modes (BIOS number + 0x0900) */
-#define VIDEO_FIRST_V7 0x0900
-
-/* Special video modes */
-#define VIDEO_FIRST_SPECIAL 0x0f00
-#define VIDEO_80x25 0x0f00
-#define VIDEO_8POINT 0x0f01
-#define VIDEO_80x43 0x0f02
-#define VIDEO_80x28 0x0f03
-#define VIDEO_CURRENT_MODE 0x0f04
-#define VIDEO_80x30 0x0f05
-#define VIDEO_80x34 0x0f06
-#define VIDEO_80x60 0x0f07
-#define VIDEO_GFX_HACK 0x0f08
-#define VIDEO_LAST_SPECIAL 0x0f09
-
-/* Video modes given by resolution */
-#define VIDEO_FIRST_RESOLUTION 0x1000
-
-/* The "recalculate timings" flag */
-#define VIDEO_RECALC 0x8000
-
-/* Positions of various video parameters passed to the kernel */
-/* (see also include/linux/tty.h) */
-#define PARAM_CURSOR_POS 0x00
-#define PARAM_VIDEO_PAGE 0x04
-#define PARAM_VIDEO_MODE 0x06
-#define PARAM_VIDEO_COLS 0x07
-#define PARAM_VIDEO_EGA_BX 0x0a
-#define PARAM_VIDEO_LINES 0x0e
-#define PARAM_HAVE_VGA 0x0f
-#define PARAM_FONT_POINTS 0x10
-
-#define PARAM_LFB_WIDTH 0x12
-#define PARAM_LFB_HEIGHT 0x14
-#define PARAM_LFB_DEPTH 0x16
-#define PARAM_LFB_BASE 0x18
-#define PARAM_LFB_SIZE 0x1c
-#define PARAM_LFB_LINELENGTH 0x24
-#define PARAM_LFB_COLORS 0x26
-#define PARAM_VESAPM_SEG 0x2e
-#define PARAM_VESAPM_OFF 0x30
-#define PARAM_LFB_PAGES 0x32
-#define PARAM_VESA_ATTRIB 0x34
-#define PARAM_CAPABILITIES 0x36
-
-/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
-#ifdef CONFIG_VIDEO_RETAIN
-#define DO_STORE call store_screen
-#else
-#define DO_STORE
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# This is the main entry point called by setup.S
-# %ds *must* be pointing to the bootsector
-video: pushw %ds # We use different segments
- pushw %ds # FS contains original DS
- popw %fs
- pushw %cs # DS is equal to CS
- popw %ds
- pushw %cs # ES is equal to CS
- popw %es
- xorw %ax, %ax
- movw %ax, %gs # GS is zero
- cld
- call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
-#ifdef CONFIG_VIDEO_SELECT
- movw %fs:(0x01fa), %ax # User selected video mode
- cmpw $ASK_VGA, %ax # Bring up the menu
- jz vid2
-
- call mode_set # Set the mode
- jc vid1
-
- leaw badmdt, %si # Invalid mode ID
- call prtstr
-vid2: call mode_menu
-vid1:
-#ifdef CONFIG_VIDEO_RETAIN
- call restore_screen # Restore screen contents
-#endif /* CONFIG_VIDEO_RETAIN */
- call store_edid
-#endif /* CONFIG_VIDEO_SELECT */
- call mode_params # Store mode parameters
- popw %ds # Restore original DS
- ret
-
-# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
-basic_detect:
- movb $0, %fs:(PARAM_HAVE_VGA)
- movb $0x12, %ah # Check EGA/VGA
- movb $0x10, %bl
- int $0x10
- movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
- cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
- je basret
-
- incb adapter
- movw $0x1a00, %ax # Check EGA or VGA?
- int $0x10
- cmpb $0x1a, %al # 1a means VGA...
- jne basret # anything else is EGA.
-
- incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
- incb adapter
-basret: ret
-
-# Store the video mode parameters for later usage by the kernel.
-# This is done by asking the BIOS except for the rows/columns
-# parameters in the default 80x25 mode -- these are set directly,
-# because some very obscure BIOSes supply insane values.
-mode_params:
-#ifdef CONFIG_VIDEO_SELECT
- cmpb $0, graphic_mode
- jnz mopar_gr
-#endif
- movb $0x03, %ah # Read cursor position
- xorb %bh, %bh
- int $0x10
- movw %dx, %fs:(PARAM_CURSOR_POS)
- movb $0x0f, %ah # Read page/mode/width
- int $0x10
- movw %bx, %fs:(PARAM_VIDEO_PAGE)
- movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
- cmpb $0x7, %al # MDA/HGA => segment differs
- jnz mopar0
-
- movw $0xb000, video_segment
-mopar0: movw %gs:(0x485), %ax # Font size
- movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
- movw force_size, %ax # Forced size?
- orw %ax, %ax
- jz mopar1
-
- movb %ah, %fs:(PARAM_VIDEO_COLS)
- movb %al, %fs:(PARAM_VIDEO_LINES)
- ret
-
-mopar1: movb $25, %al
- cmpb $0, adapter # If we are on CGA/MDA/HGA, the
- jz mopar2 # screen must have 25 lines.
-
- movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
- incb %al # location of max lines.
-mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
- ret
-
-#ifdef CONFIG_VIDEO_SELECT
-# Fetching of VESA frame buffer parameters
-mopar_gr:
- leaw modelist+1024, %di
- movb $0x23, %fs:(PARAM_HAVE_VGA)
- movw 16(%di), %ax
- movw %ax, %fs:(PARAM_LFB_LINELENGTH)
- movw 18(%di), %ax
- movw %ax, %fs:(PARAM_LFB_WIDTH)
- movw 20(%di), %ax
- movw %ax, %fs:(PARAM_LFB_HEIGHT)
- movb 25(%di), %al
- movb $0, %ah
- movw %ax, %fs:(PARAM_LFB_DEPTH)
- movb 29(%di), %al
- movb $0, %ah
- movw %ax, %fs:(PARAM_LFB_PAGES)
- movl 40(%di), %eax
- movl %eax, %fs:(PARAM_LFB_BASE)
- movl 31(%di), %eax
- movl %eax, %fs:(PARAM_LFB_COLORS)
- movl 35(%di), %eax
- movl %eax, %fs:(PARAM_LFB_COLORS+4)
- movw 0(%di), %ax
- movw %ax, %fs:(PARAM_VESA_ATTRIB)
-
-# get video mem size
- leaw modelist+1024, %di
- movw $0x4f00, %ax
- int $0x10
- xorl %eax, %eax
- movw 18(%di), %ax
- movl %eax, %fs:(PARAM_LFB_SIZE)
-
-# store mode capabilities
- movl 10(%di), %eax
- movl %eax, %fs:(PARAM_CAPABILITIES)
-
-# switching the DAC to 8-bit is for <= 8 bpp only
- movw %fs:(PARAM_LFB_DEPTH), %ax
- cmpw $8, %ax
- jg dac_done
-
-# get DAC switching capability
- xorl %eax, %eax
- movb 10(%di), %al
- testb $1, %al
- jz dac_set
-
-# attempt to switch DAC to 8-bit
- movw $0x4f08, %ax
- movw $0x0800, %bx
- int $0x10
- cmpw $0x004f, %ax
- jne dac_set
- movb %bh, dac_size # store actual DAC size
-
-dac_set:
-# set color size to DAC size
- movb dac_size, %al
- movb %al, %fs:(PARAM_LFB_COLORS+0)
- movb %al, %fs:(PARAM_LFB_COLORS+2)
- movb %al, %fs:(PARAM_LFB_COLORS+4)
- movb %al, %fs:(PARAM_LFB_COLORS+6)
-
-# set color offsets to 0
- movb $0, %fs:(PARAM_LFB_COLORS+1)
- movb $0, %fs:(PARAM_LFB_COLORS+3)
- movb $0, %fs:(PARAM_LFB_COLORS+5)
- movb $0, %fs:(PARAM_LFB_COLORS+7)
-
-dac_done:
-# get protected mode interface informations
- movw $0x4f0a, %ax
- xorw %bx, %bx
- xorw %di, %di
- int $0x10
- cmp $0x004f, %ax
- jnz no_pm
-
- movw %es, %fs:(PARAM_VESAPM_SEG)
- movw %di, %fs:(PARAM_VESAPM_OFF)
-no_pm: ret
-
-# The video mode menu
-mode_menu:
- leaw keymsg, %si # "Return/Space/Timeout" message
- call prtstr
- call flush
-nokey: call getkt
-
- cmpb $0x0d, %al # ENTER ?
- je listm # yes - manual mode selection
-
- cmpb $0x20, %al # SPACE ?
- je defmd1 # no - repeat
-
- call beep
- jmp nokey
-
-defmd1: ret # No mode chosen? Default 80x25
-
-listm: call mode_table # List mode table
-listm0: leaw name_bann, %si # Print adapter name
- call prtstr
- movw card_name, %si
- orw %si, %si
- jnz an2
-
- movb adapter, %al
- leaw old_name, %si
- orb %al, %al
- jz an1
-
- leaw ega_name, %si
- decb %al
- jz an1
-
- leaw vga_name, %si
- jmp an1
-
-an2: call prtstr
- leaw svga_name, %si
-an1: call prtstr
- leaw listhdr, %si # Table header
- call prtstr
- movb $0x30, %dl # DL holds mode number
- leaw modelist, %si
-lm1: cmpw $ASK_VGA, (%si) # End?
- jz lm2
-
- movb %dl, %al # Menu selection number
- call prtchr
- call prtsp2
- lodsw
- call prthw # Mode ID
- call prtsp2
- movb 0x1(%si), %al
- call prtdec # Rows
- movb $0x78, %al # the letter 'x'
- call prtchr
- lodsw
- call prtdec # Columns
- movb $0x0d, %al # New line
- call prtchr
- movb $0x0a, %al
- call prtchr
- incb %dl # Next character
- cmpb $0x3a, %dl
- jnz lm1
-
- movb $0x61, %dl
- jmp lm1
-
-lm2: leaw prompt, %si # Mode prompt
- call prtstr
- leaw edit_buf, %di # Editor buffer
-lm3: call getkey
- cmpb $0x0d, %al # Enter?
- jz lment
-
- cmpb $0x08, %al # Backspace?
- jz lmbs
-
- cmpb $0x20, %al # Printable?
- jc lm3
-
- cmpw $edit_buf+4, %di # Enough space?
- jz lm3
-
- stosb
- call prtchr
- jmp lm3
-
-lmbs: cmpw $edit_buf, %di # Backspace
- jz lm3
-
- decw %di
- movb $0x08, %al
- call prtchr
- call prtspc
- movb $0x08, %al
- call prtchr
- jmp lm3
-
-lment: movb $0, (%di)
- leaw crlft, %si
- call prtstr
- leaw edit_buf, %si
- cmpb $0, (%si) # Empty string = default mode
- jz lmdef
-
- cmpb $0, 1(%si) # One character = menu selection
- jz mnusel
-
- cmpw $0x6373, (%si) # "scan" => mode scanning
- jnz lmhx
-
- cmpw $0x6e61, 2(%si)
- jz lmscan
-
-lmhx: xorw %bx, %bx # Else => mode ID in hex
-lmhex: lodsb
- orb %al, %al
- jz lmuse1
-
- subb $0x30, %al
- jc lmbad
-
- cmpb $10, %al
- jc lmhx1
-
- subb $7, %al
- andb $0xdf, %al
- cmpb $10, %al
- jc lmbad
-
- cmpb $16, %al
- jnc lmbad
-
-lmhx1: shlw $4, %bx
- orb %al, %bl
- jmp lmhex
-
-lmuse1: movw %bx, %ax
- jmp lmuse
-
-mnusel: lodsb # Menu selection
- xorb %ah, %ah
- subb $0x30, %al
- jc lmbad
-
- cmpb $10, %al
- jc lmuse
-
- cmpb $0x61-0x30, %al
- jc lmbad
-
- subb $0x61-0x30-10, %al
- cmpb $36, %al
- jnc lmbad
-
-lmuse: call mode_set
- jc lmdef
-
-lmbad: leaw unknt, %si
- call prtstr
- jmp lm2
-lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
- jz lmbad
-
- movw $0, mt_end # Scanning of modes is
- movb $1, scanning # done as new autodetection.
- call mode_table
- jmp listm0
-lmdef: ret
-
-# Additional parts of mode_set... (relative jumps, you know)
-setv7: # Video7 extended modes
- DO_STORE
- subb $VIDEO_FIRST_V7>>8, %bh
- movw $0x6f05, %ax
- int $0x10
- stc
- ret
-
-_setrec: jmp setrec # Ugly...
-_set_80x25: jmp set_80x25
-
-# Aliases for backward compatibility.
-setalias:
- movw $VIDEO_80x25, %ax
- incw %bx
- jz mode_set
-
- movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
- incw %bx
- jnz setbad # Fall-through!
-
-# Setting of user mode (AX=mode ID) => CF=success
-mode_set:
- movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
- movw %ax, %bx
- cmpb $0xff, %ah
- jz setalias
-
- testb $VIDEO_RECALC>>8, %ah
- jnz _setrec
-
- cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
- jnc setres
-
- cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
- jz setspc
-
- cmpb $VIDEO_FIRST_V7>>8, %ah
- jz setv7
-
- cmpb $VIDEO_FIRST_VESA>>8, %ah
- jnc check_vesa
-
- orb %ah, %ah
- jz setmenu
-
- decb %ah
- jz setbios
-
-setbad: clc
- movb $0, do_restore # The screen needn't be restored
- ret
-
-setvesa:
- DO_STORE
- subb $VIDEO_FIRST_VESA>>8, %bh
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz setbad # AH=0 if OK
-
- stc
- ret
-
-setbios:
- DO_STORE
- int $0x10 # Standard BIOS mode set call
- pushw %bx
- movb $0x0f, %ah # Check if really set
- int $0x10
- popw %bx
- cmpb %bl, %al
- jnz setbad
-
- stc
- ret
-
-setspc: xorb %bh, %bh # Set special mode
- cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
- jnc setbad
-
- addw %bx, %bx
- jmp *spec_inits(%bx)
-
-setmenu:
- orb %al, %al # 80x25 is an exception
- jz _set_80x25
-
- pushw %bx # Set mode chosen from menu
- call mode_table # Build the mode table
- popw %ax
- shlw $2, %ax
- addw %ax, %si
- cmpw %di, %si
- jnc setbad
-
- movw (%si), %ax # Fetch mode ID
-_m_s: jmp mode_set
-
-setres: pushw %bx # Set mode chosen by resolution
- call mode_table
- popw %bx
- xchgb %bl, %bh
-setr1: lodsw
- cmpw $ASK_VGA, %ax # End of the list?
- jz setbad
-
- lodsw
- cmpw %bx, %ax
- jnz setr1
-
- movw -4(%si), %ax # Fetch mode ID
- jmp _m_s
-
-check_vesa:
-#ifdef CONFIG_FIRMWARE_EDID
- leaw modelist+1024, %di
- movw $0x4f00, %ax
- int $0x10
- cmpw $0x004f, %ax
- jnz setbad
-
- movw 4(%di), %ax
- movw %ax, vbe_version
-#endif
- leaw modelist+1024, %di
- subb $VIDEO_FIRST_VESA>>8, %bh
- movw %bx, %cx # Get mode information structure
- movw $0x4f01, %ax
- int $0x10
- addb $VIDEO_FIRST_VESA>>8, %bh
- cmpw $0x004f, %ax
- jnz setbad
-
- movb (%di), %al # Check capabilities.
- andb $0x19, %al
- cmpb $0x09, %al
- jz setvesa # This is a text mode
-
- movb (%di), %al # Check capabilities.
- andb $0x99, %al
- cmpb $0x99, %al
- jnz _setbad # Doh! No linear frame buffer.
-
- subb $VIDEO_FIRST_VESA>>8, %bh
- orw $0x4000, %bx # Use linear frame buffer
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz _setbad # AH=0 if OK
-
- movb $1, graphic_mode # flag graphic mode
- movb $0, do_restore # no screen restore
- stc
- ret
-
-_setbad: jmp setbad # Ugly...
-
-# Recalculate vertical display end registers -- this fixes various
-# inconsistencies of extended modes on many adapters. Called when
-# the VIDEO_RECALC flag is set in the mode ID.
-
-setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
- call mode_set
- jnc rct3
-
- movw %gs:(0x485), %ax # Font size in pixels
- movb %gs:(0x484), %bl # Number of rows
- incb %bl
- mulb %bl # Number of visible
- decw %ax # scan lines - 1
- movw $0x3d4, %dx
- movw %ax, %bx
- movb $0x12, %al # Lower 8 bits
- movb %bl, %ah
- outw %ax, %dx
- movb $0x07, %al # Bits 8 and 9 in the overflow register
- call inidx
- xchgb %al, %ah
- andb $0xbd, %ah
- shrb %bh
- jnc rct1
- orb $0x02, %ah
-rct1: shrb %bh
- jnc rct2
- orb $0x40, %ah
-rct2: movb $0x07, %al
- outw %ax, %dx
- stc
-rct3: ret
-
-# Table of routines for setting of the special modes.
-spec_inits:
- .word set_80x25
- .word set_8pixel
- .word set_80x43
- .word set_80x28
- .word set_current
- .word set_80x30
- .word set_80x34
- .word set_80x60
- .word set_gfx
-
-# Set the 80x25 mode. If already set, do nothing.
-set_80x25:
- movw $0x5019, force_size # Override possibly broken BIOS
-use_80x25:
-#ifdef CONFIG_VIDEO_400_HACK
- movw $0x1202, %ax # Force 400 scan lines
- movb $0x30, %bl
- int $0x10
-#else
- movb $0x0f, %ah # Get current mode ID
- int $0x10
- cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
- jz st80 # on CGA/MDA/HGA and is also available on EGAM
-
- cmpw $0x5003, %ax # Unknown mode, force 80x25 color
- jnz force3
-
-st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
- jz set80
-
- movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
- orb %al, %al # Some buggy BIOS'es set 0 rows
- jz set80
-
- cmpb $24, %al # It's hopefully correct
- jz set80
-#endif /* CONFIG_VIDEO_400_HACK */
-force3: DO_STORE
- movw $0x0003, %ax # Forced set
- int $0x10
-set80: stc
- ret
-
-# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
-set_8pixel:
- DO_STORE
- call use_80x25 # The base is 80x25
-set_8pt:
- movw $0x1112, %ax # Use 8x8 font
- xorb %bl, %bl
- int $0x10
- movw $0x1200, %ax # Use alternate print screen
- movb $0x20, %bl
- int $0x10
- movw $0x1201, %ax # Turn off cursor emulation
- movb $0x34, %bl
- int $0x10
- movb $0x01, %ah # Define cursor scan lines 6-7
- movw $0x0607, %cx
- int $0x10
-set_current:
- stc
- ret
-
-# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
-# 80x25 mode with 14-point fonts instead of 16-point.
-set_80x28:
- DO_STORE
- call use_80x25 # The base is 80x25
-set14: movw $0x1111, %ax # Use 9x14 font
- xorb %bl, %bl
- int $0x10
- movb $0x01, %ah # Define cursor scan lines 11-12
- movw $0x0b0c, %cx
- int $0x10
- stc
- ret
-
-# Set the 80x43 mode. This mode is works on all VGA's.
-# It's a 350-scanline mode with 8-pixel font.
-set_80x43:
- DO_STORE
- movw $0x1201, %ax # Set 350 scans
- movb $0x30, %bl
- int $0x10
- movw $0x0003, %ax # Reset video mode
- int $0x10
- jmp set_8pt # Use 8-pixel font
-
-# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
-set_80x30:
- call use_80x25 # Start with real 80x25
- DO_STORE
- movw $0x3cc, %dx # Get CRTC port
- inb %dx, %al
- movb $0xd4, %dl
- rorb %al # Mono or color?
- jc set48a
-
- movb $0xb4, %dl
-set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
- call outidx
- movw $0x0b06, %ax # Vertical total
- call outidx
- movw $0x3e07, %ax # (Vertical) overflow
- call outidx
- movw $0xea10, %ax # Vertical sync start
- call outidx
- movw $0xdf12, %ax # Vertical display end
- call outidx
- movw $0xe715, %ax # Vertical blank start
- call outidx
- movw $0x0416, %ax # Vertical blank end
- call outidx
- pushw %dx
- movb $0xcc, %dl # Misc output register (read)
- inb %dx, %al
- movb $0xc2, %dl # (write)
- andb $0x0d, %al # Preserve clock select bits and color bit
- orb $0xe2, %al # Set correct sync polarity
- outb %al, %dx
- popw %dx
- movw $0x501e, force_size
- stc # That's all.
- ret
-
-# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
-set_80x34:
- call set_80x30 # Set 480 scans
- call set14 # And 14-pt font
- movw $0xdb12, %ax # VGA vertical display end
- movw $0x5022, force_size
-setvde: call outidx
- stc
- ret
-
-# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
-set_80x60:
- call set_80x30 # Set 480 scans
- call set_8pt # And 8-pt font
- movw $0xdf12, %ax # VGA vertical display end
- movw $0x503c, force_size
- jmp setvde
-
-# Special hack for ThinkPad graphics
-set_gfx:
-#ifdef CONFIG_VIDEO_GFX_HACK
- movw $VIDEO_GFX_BIOS_AX, %ax
- movw $VIDEO_GFX_BIOS_BX, %bx
- int $0x10
- movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
- stc
-#endif
- ret
-
-#ifdef CONFIG_VIDEO_RETAIN
-
-# Store screen contents to temporary buffer.
-store_screen:
- cmpb $0, do_restore # Already stored?
- jnz stsr
-
- testb $CAN_USE_HEAP, loadflags # Have we space for storing?
- jz stsr
-
- pushw %ax
- pushw %bx
- pushw force_size # Don't force specific size
- movw $0, force_size
- call mode_params # Obtain params of current mode
- popw force_size
- movb %fs:(PARAM_VIDEO_LINES), %ah
- movb %fs:(PARAM_VIDEO_COLS), %al
- movw %ax, %bx # BX=dimensions
- mulb %ah
- movw %ax, %cx # CX=number of characters
- addw %ax, %ax # Calculate image size
- addw $modelist+1024+4, %ax
- cmpw heap_end_ptr, %ax
- jnc sts1 # Unfortunately, out of memory
-
- movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
- leaw modelist+1024, %di
- stosw
- movw %bx, %ax
- stosw
- pushw %ds # Store the screen
- movw video_segment, %ds
- xorw %si, %si
- rep
- movsw
- popw %ds
- incb do_restore # Screen will be restored later
-sts1: popw %bx
- popw %ax
-stsr: ret
-
-# Restore screen contents from temporary buffer.
-restore_screen:
- cmpb $0, do_restore # Has the screen been stored?
- jz res1
-
- call mode_params # Get parameters of current mode
- movb %fs:(PARAM_VIDEO_LINES), %cl
- movb %fs:(PARAM_VIDEO_COLS), %ch
- leaw modelist+1024, %si # Screen buffer
- lodsw # Set cursor position
- movw %ax, %dx
- cmpb %cl, %dh
- jc res2
-
- movb %cl, %dh
- decb %dh
-res2: cmpb %ch, %dl
- jc res3
-
- movb %ch, %dl
- decb %dl
-res3: movb $0x02, %ah
- movb $0x00, %bh
- int $0x10
- lodsw # Display size
- movb %ah, %dl # DL=number of lines
- movb $0, %ah # BX=phys. length of orig. line
- movw %ax, %bx
- cmpb %cl, %dl # Too many?
- jc res4
-
- pushw %ax
- movb %dl, %al
- subb %cl, %al
- mulb %bl
- addw %ax, %si
- addw %ax, %si
- popw %ax
- movb %cl, %dl
-res4: cmpb %ch, %al # Too wide?
- jc res5
-
- movb %ch, %al # AX=width of src. line
-res5: movb $0, %cl
- xchgb %ch, %cl
- movw %cx, %bp # BP=width of dest. line
- pushw %es
- movw video_segment, %es
- xorw %di, %di # Move the data
- addw %bx, %bx # Convert BX and BP to _bytes_
- addw %bp, %bp
-res6: pushw %si
- pushw %di
- movw %ax, %cx
- rep
- movsw
- popw %di
- popw %si
- addw %bp, %di
- addw %bx, %si
- decb %dl
- jnz res6
-
- popw %es # Done
-res1: ret
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
-outidx: outb %al, %dx
- pushw %ax
- movb %ah, %al
- incw %dx
- outb %al, %dx
- decw %dx
- popw %ax
- ret
-
-# Build the table of video modes (stored after the setup.S code at the
-# `modelist' label. Each video mode record looks like:
-# .word MODE-ID (our special mode ID (see above))
-# .byte rows (number of rows)
-# .byte columns (number of columns)
-# Returns address of the end of the table in DI, the end is marked
-# with a ASK_VGA ID.
-mode_table:
- movw mt_end, %di # Already filled?
- orw %di, %di
- jnz mtab1x
-
- leaw modelist, %di # Store standard modes:
- movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
- stosl
- movb adapter, %al # CGA/MDA/HGA -- no more modes
- orb %al, %al
- jz mtabe
-
- decb %al
- jnz mtabv
-
- movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
- stosl
- jmp mtabe
-
-mtab1x: jmp mtab1
-
-mtabv: leaw vga_modes, %si # All modes for std VGA
- movw $vga_modes_end-vga_modes, %cx
- rep # I'm unable to use movsw as I don't know how to store a half
- movsb # of the expression above to cx without using explicit shr.
-
- cmpb $0, scanning # Mode scan requested?
- jz mscan1
-
- call mode_scan
-mscan1:
-
-#ifdef CONFIG_VIDEO_LOCAL
- call local_modes
-#endif /* CONFIG_VIDEO_LOCAL */
-
-#ifdef CONFIG_VIDEO_VESA
- call vesa_modes # Detect VESA VGA modes
-#endif /* CONFIG_VIDEO_VESA */
-
-#ifdef CONFIG_VIDEO_SVGA
- cmpb $0, scanning # Bypass when scanning
- jnz mscan2
-
- call svga_modes # Detect SVGA cards & modes
-mscan2:
-#endif /* CONFIG_VIDEO_SVGA */
-
-mtabe:
-
-#ifdef CONFIG_VIDEO_COMPACT
- leaw modelist, %si
- movw %di, %dx
- movw %si, %di
-cmt1: cmpw %dx, %si # Scan all modes
- jz cmt2
-
- leaw modelist, %bx # Find in previous entries
- movw 2(%si), %cx
-cmt3: cmpw %bx, %si
- jz cmt4
-
- cmpw 2(%bx), %cx # Found => don't copy this entry
- jz cmt5
-
- addw $4, %bx
- jmp cmt3
-
-cmt4: movsl # Copy entry
- jmp cmt1
-
-cmt5: addw $4, %si # Skip entry
- jmp cmt1
-
-cmt2:
-#endif /* CONFIG_VIDEO_COMPACT */
-
- movw $ASK_VGA, (%di) # End marker
- movw %di, mt_end
-mtab1: leaw modelist, %si # SI=mode list, DI=list end
-ret0: ret
-
-# Modes usable on all standard VGAs
-vga_modes:
- .word VIDEO_8POINT
- .word 0x5032 # 80x50
- .word VIDEO_80x43
- .word 0x502b # 80x43
- .word VIDEO_80x28
- .word 0x501c # 80x28
- .word VIDEO_80x30
- .word 0x501e # 80x30
- .word VIDEO_80x34
- .word 0x5022 # 80x34
- .word VIDEO_80x60
- .word 0x503c # 80x60
-#ifdef CONFIG_VIDEO_GFX_HACK
- .word VIDEO_GFX_HACK
- .word VIDEO_GFX_DUMMY_RESOLUTION
-#endif
-
-vga_modes_end:
-# Detect VESA modes.
-
-#ifdef CONFIG_VIDEO_VESA
-vesa_modes:
- cmpb $2, adapter # VGA only
- jnz ret0
-
- movw %di, %bp # BP=original mode table end
- addw $0x200, %di # Buffer space
- movw $0x4f00, %ax # VESA Get card info call
- int $0x10
- movw %bp, %di
- cmpw $0x004f, %ax # Successful?
- jnz ret0
-
- cmpw $0x4556, 0x200(%di)
- jnz ret0
-
- cmpw $0x4153, 0x202(%di)
- jnz ret0
-
- movw $vesa_name, card_name # Set name to "VESA VGA"
- pushw %gs
- lgsw 0x20e(%di), %si # GS:SI=mode list
- movw $128, %cx # Iteration limit
-vesa1:
-# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
-# XXX: lodsw %gs:(%si), %ax # Get next mode in the list
- gs; lodsw
- cmpw $0xffff, %ax # End of the table?
- jz vesar
-
- cmpw $0x0080, %ax # Check validity of mode ID
- jc vesa2
-
- orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
- jz vesan # Certain BIOSes report 0x80-0xff!
-
- cmpw $0x0800, %ax
- jnc vesae
-
-vesa2: pushw %cx
- movw %ax, %cx # Get mode information structure
- movw $0x4f01, %ax
- int $0x10
- movw %cx, %bx # BX=mode number
- addb $VIDEO_FIRST_VESA>>8, %bh
- popw %cx
- cmpw $0x004f, %ax
- jnz vesan # Don't report errors (buggy BIOSES)
-
- movb (%di), %al # Check capabilities. We require
- andb $0x19, %al # a color text mode.
- cmpb $0x09, %al
- jnz vesan
-
- cmpw $0xb800, 8(%di) # Standard video memory address required
- jnz vesan
-
- testb $2, (%di) # Mode characteristics supplied?
- movw %bx, (%di) # Store mode number
- jz vesa3
-
- xorw %dx, %dx
- movw 0x12(%di), %bx # Width
- orb %bh, %bh
- jnz vesan
-
- movb %bl, 0x3(%di)
- movw 0x14(%di), %ax # Height
- orb %ah, %ah
- jnz vesan
-
- movb %al, 2(%di)
- mulb %bl
- cmpw $8193, %ax # Small enough for Linux console driver?
- jnc vesan
-
- jmp vesaok
-
-vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
- jc vesan # so it must be a standard VESA mode.
-
- cmpw $5, %bx
- jnc vesan
-
- movw vesa_text_mode_table(%bx), %ax
- movw %ax, 2(%di)
-vesaok: addw $4, %di # The mode is valid. Store it.
-vesan: loop vesa1 # Next mode. Limit exceeded => error
-vesae: leaw vesaer, %si
- call prtstr
- movw %bp, %di # Discard already found modes.
-vesar: popw %gs
- ret
-
-# Dimensions of standard VESA text modes
-vesa_text_mode_table:
- .byte 60, 80 # 0108
- .byte 25, 132 # 0109
- .byte 43, 132 # 010A
- .byte 50, 132 # 010B
- .byte 60, 132 # 010C
-#endif /* CONFIG_VIDEO_VESA */
-
-# Scan for video modes. A bit dirty, but should work.
-mode_scan:
- movw $0x0100, %cx # Start with mode 0
-scm1: movb $0, %ah # Test the mode
- movb %cl, %al
- int $0x10
- movb $0x0f, %ah
- int $0x10
- cmpb %cl, %al
- jnz scm2 # Mode not set
-
- movw $0x3c0, %dx # Test if it's a text mode
- movb $0x10, %al # Mode bits
- call inidx
- andb $0x03, %al
- jnz scm2
-
- movb $0xce, %dl # Another set of mode bits
- movb $0x06, %al
- call inidx
- shrb %al
- jc scm2
-
- movb $0xd4, %dl # Cursor location
- movb $0x0f, %al
- call inidx
- orb %al, %al
- jnz scm2
-
- movw %cx, %ax # Ok, store the mode
- stosw
- movb %gs:(0x484), %al # Number of rows
- incb %al
- stosb
- movw %gs:(0x44a), %ax # Number of columns
- stosb
-scm2: incb %cl
- jns scm1
-
- movw $0x0003, %ax # Return back to mode 3
- int $0x10
- ret
-
-tstidx: outw %ax, %dx # OUT DX,AX and inidx
-inidx: outb %al, %dx # Read from indexed VGA register
- incw %dx # AL=index, DX=index reg port -> AL=data
- inb %dx, %al
- decw %dx
- ret
-
-# Try to detect type of SVGA card and supply (usually approximate) video
-# mode table for it.
-
-#ifdef CONFIG_VIDEO_SVGA
-svga_modes:
- leaw svga_table, %si # Test all known SVGA adapters
-dosvga: lodsw
- movw %ax, %bp # Default mode table
- orw %ax, %ax
- jz didsv1
-
- lodsw # Pointer to test routine
- pushw %si
- pushw %di
- pushw %es
- movw $0xc000, %bx
- movw %bx, %es
- call *%ax # Call test routine
- popw %es
- popw %di
- popw %si
- orw %bp, %bp
- jz dosvga
-
- movw %bp, %si # Found, copy the modes
- movb svga_prefix, %ah
-cpsvga: lodsb
- orb %al, %al
- jz didsv
-
- stosw
- movsw
- jmp cpsvga
-
-didsv: movw %si, card_name # Store pointer to card name
-didsv1: ret
-
-# Table of all known SVGA cards. For each card, we store a pointer to
-# a table of video modes supported by the card and a pointer to a routine
-# used for testing of presence of the card. The video mode table is always
-# followed by the name of the card or the chipset.
-svga_table:
- .word ati_md, ati_test
- .word oak_md, oak_test
- .word paradise_md, paradise_test
- .word realtek_md, realtek_test
- .word s3_md, s3_test
- .word chips_md, chips_test
- .word video7_md, video7_test
- .word cirrus5_md, cirrus5_test
- .word cirrus6_md, cirrus6_test
- .word cirrus1_md, cirrus1_test
- .word ahead_md, ahead_test
- .word everex_md, everex_test
- .word genoa_md, genoa_test
- .word trident_md, trident_test
- .word tseng_md, tseng_test
- .word 0
-
-# Test routines and mode tables:
-
-# S3 - The test algorithm was taken from the SuperProbe package
-# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
-s3_test:
- movw $0x0f35, %cx # we store some constants in cl/ch
- movw $0x03d4, %dx
- movb $0x38, %al
- call inidx
- movb %al, %bh # store current CRT-register 0x38
- movw $0x0038, %ax
- call outidx # disable writing to special regs
- movb %cl, %al # check whether we can write special reg 0x35
- call inidx
- movb %al, %bl # save the current value of CRT reg 0x35
- andb $0xf0, %al # clear bits 0-3
- movb %al, %ah
- movb %cl, %al # and write it to CRT reg 0x35
- call outidx
- call inidx # now read it back
- andb %ch, %al # clear the upper 4 bits
- jz s3_2 # the first test failed. But we have a
-
- movb %bl, %ah # second chance
- movb %cl, %al
- call outidx
- jmp s3_1 # do the other tests
-
-s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
- orb %bl, %ah # set the upper 4 bits of ah with the orig value
- call outidx # write ...
- call inidx # ... and reread
- andb %cl, %al # turn off the upper 4 bits
- pushw %ax
- movb %bl, %ah # restore old value in register 0x35
- movb %cl, %al
- call outidx
- popw %ax
- cmpb %ch, %al # setting lower 4 bits was successful => bad
- je no_s3 # writing is allowed => this is not an S3
-
-s3_1: movw $0x4838, %ax # allow writing to special regs by putting
- call outidx # magic number into CRT-register 0x38
- movb %cl, %al # check whether we can write special reg 0x35
- call inidx
- movb %al, %bl
- andb $0xf0, %al
- movb %al, %ah
- movb %cl, %al
- call outidx
- call inidx
- andb %ch, %al
- jnz no_s3 # no, we can't write => no S3
-
- movw %cx, %ax
- orb %bl, %ah
- call outidx
- call inidx
- andb %ch, %al
- pushw %ax
- movb %bl, %ah # restore old value in register 0x35
- movb %cl, %al
- call outidx
- popw %ax
- cmpb %ch, %al
- jne no_s31 # writing not possible => no S3
- movb $0x30, %al
- call inidx # now get the S3 id ...
- leaw idS3, %di
- movw $0x10, %cx
- repne
- scasb
- je no_s31
-
- movb %bh, %ah
- movb $0x38, %al
- jmp s3rest
-
-no_s3: movb $0x35, %al # restore CRT register 0x35
- movb %bl, %ah
- call outidx
-no_s31: xorw %bp, %bp # Detection failed
-s3rest: movb %bh, %ah
- movb $0x38, %al # restore old value of CRT register 0x38
- jmp outidx
-
-idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
- .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
-
-s3_md: .byte 0x54, 0x2b, 0x84
- .byte 0x55, 0x19, 0x84
- .byte 0
- .ascii "S3"
- .byte 0
-
-# ATI cards.
-ati_test:
- leaw idati, %si
- movw $0x31, %di
- movw $0x09, %cx
- repe
- cmpsb
- je atiok
-
- xorw %bp, %bp
-atiok: ret
-
-idati: .ascii "761295520"
-
-ati_md: .byte 0x23, 0x19, 0x84
- .byte 0x33, 0x2c, 0x84
- .byte 0x22, 0x1e, 0x64
- .byte 0x21, 0x19, 0x64
- .byte 0x58, 0x21, 0x50
- .byte 0x5b, 0x1e, 0x50
- .byte 0
- .ascii "ATI"
- .byte 0
-
-# AHEAD
-ahead_test:
- movw $0x200f, %ax
- movw $0x3ce, %dx
- outw %ax, %dx
- incw %dx
- inb %dx, %al
- cmpb $0x20, %al
- je isahed
-
- cmpb $0x21, %al
- je isahed
-
- xorw %bp, %bp
-isahed: ret
-
-ahead_md:
- .byte 0x22, 0x2c, 0x84
- .byte 0x23, 0x19, 0x84
- .byte 0x24, 0x1c, 0x84
- .byte 0x2f, 0x32, 0xa0
- .byte 0x32, 0x22, 0x50
- .byte 0x34, 0x42, 0x50
- .byte 0
- .ascii "Ahead"
- .byte 0
-
-# Chips & Tech.
-chips_test:
- movw $0x3c3, %dx
- inb %dx, %al
- orb $0x10, %al
- outb %al, %dx
- movw $0x104, %dx
- inb %dx, %al
- movb %al, %bl
- movw $0x3c3, %dx
- inb %dx, %al
- andb $0xef, %al
- outb %al, %dx
- cmpb $0xa5, %bl
- je cantok
-
- xorw %bp, %bp
-cantok: ret
-
-chips_md:
- .byte 0x60, 0x19, 0x84
- .byte 0x61, 0x32, 0x84
- .byte 0
- .ascii "Chips & Technologies"
- .byte 0
-
-# Cirrus Logic 5X0
-cirrus1_test:
- movw $0x3d4, %dx
- movb $0x0c, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bl
- xorb %al, %al
- outb %al, %dx
- decw %dx
- movb $0x1f, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bh
- xorb %ah, %ah
- shlb $4, %al
- movw %ax, %cx
- movb %bh, %al
- shrb $4, %al
- addw %ax, %cx
- shlw $8, %cx
- addw $6, %cx
- movw %cx, %ax
- movw $0x3c4, %dx
- outw %ax, %dx
- incw %dx
- inb %dx, %al
- andb %al, %al
- jnz nocirr
-
- movb %bh, %al
- outb %al, %dx
- inb %dx, %al
- cmpb $0x01, %al
- je iscirr
-
-nocirr: xorw %bp, %bp
-iscirr: movw $0x3d4, %dx
- movb %bl, %al
- xorb %ah, %ah
- shlw $8, %ax
- addw $0x0c, %ax
- outw %ax, %dx
- ret
-
-cirrus1_md:
- .byte 0x1f, 0x19, 0x84
- .byte 0x20, 0x2c, 0x84
- .byte 0x22, 0x1e, 0x84
- .byte 0x31, 0x25, 0x64
- .byte 0
- .ascii "Cirrus Logic 5X0"
- .byte 0
-
-# Cirrus Logic 54XX
-cirrus5_test:
- movw $0x3c4, %dx
- movb $6, %al
- call inidx
- movb %al, %bl # BL=backup
- movw $6, %ax
- call tstidx
- cmpb $0x0f, %al
- jne c5fail
-
- movw $0x1206, %ax
- call tstidx
- cmpb $0x12, %al
- jne c5fail
-
- movb $0x1e, %al
- call inidx
- movb %al, %bh
- movb %bh, %ah
- andb $0xc0, %ah
- movb $0x1e, %al
- call tstidx
- andb $0x3f, %al
- jne c5xx
-
- movb $0x1e, %al
- movb %bh, %ah
- orb $0x3f, %ah
- call tstidx
- xorb $0x3f, %al
- andb $0x3f, %al
-c5xx: pushf
- movb $0x1e, %al
- movb %bh, %ah
- outw %ax, %dx
- popf
- je c5done
-
-c5fail: xorw %bp, %bp
-c5done: movb $6, %al
- movb %bl, %ah
- outw %ax, %dx
- ret
-
-cirrus5_md:
- .byte 0x14, 0x19, 0x84
- .byte 0x54, 0x2b, 0x84
- .byte 0
- .ascii "Cirrus Logic 54XX"
- .byte 0
-
-# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
-# it's misidentified by the Ahead test.
-cirrus6_test:
- movw $0x3ce, %dx
- movb $0x0a, %al
- call inidx
- movb %al, %bl # BL=backup
- movw $0xce0a, %ax
- call tstidx
- orb %al, %al
- jne c2fail
-
- movw $0xec0a, %ax
- call tstidx
- cmpb $0x01, %al
- jne c2fail
-
- movb $0xaa, %al
- call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
- shrb $4, %al
- subb $4, %al
- jz c6done
-
- decb %al
- jz c6done
-
- subb $2, %al
- jz c6done
-
- decb %al
- jz c6done
-
-c2fail: xorw %bp, %bp
-c6done: movb $0x0a, %al
- movb %bl, %ah
- outw %ax, %dx
- ret
-
-cirrus6_md:
- .byte 0
- .ascii "Cirrus Logic 64XX"
- .byte 0
-
-# Everex / Trident
-everex_test:
- movw $0x7000, %ax
- xorw %bx, %bx
- int $0x10
- cmpb $0x70, %al
- jne noevrx
-
- shrw $4, %dx
- cmpw $0x678, %dx
- je evtrid
-
- cmpw $0x236, %dx
- jne evrxok
-
-evtrid: leaw trident_md, %bp
-evrxok: ret
-
-noevrx: xorw %bp, %bp
- ret
-
-everex_md:
- .byte 0x03, 0x22, 0x50
- .byte 0x04, 0x3c, 0x50
- .byte 0x07, 0x2b, 0x64
- .byte 0x08, 0x4b, 0x64
- .byte 0x0a, 0x19, 0x84
- .byte 0x0b, 0x2c, 0x84
- .byte 0x16, 0x1e, 0x50
- .byte 0x18, 0x1b, 0x64
- .byte 0x21, 0x40, 0xa0
- .byte 0x40, 0x1e, 0x84
- .byte 0
- .ascii "Everex/Trident"
- .byte 0
-
-# Genoa.
-genoa_test:
- leaw idgenoa, %si # Check Genoa 'clues'
- xorw %ax, %ax
- movb %es:(0x37), %al
- movw %ax, %di
- movw $0x04, %cx
- decw %si
- decw %di
-l1: incw %si
- incw %di
- movb (%si), %al
- testb %al, %al
- jz l2
-
- cmpb %es:(%di), %al
-l2: loope l1
- orw %cx, %cx
- je isgen
-
- xorw %bp, %bp
-isgen: ret
-
-idgenoa: .byte 0x77, 0x00, 0x99, 0x66
-
-genoa_md:
- .byte 0x58, 0x20, 0x50
- .byte 0x5a, 0x2a, 0x64
- .byte 0x60, 0x19, 0x84
- .byte 0x61, 0x1d, 0x84
- .byte 0x62, 0x20, 0x84
- .byte 0x63, 0x2c, 0x84
- .byte 0x64, 0x3c, 0x84
- .byte 0x6b, 0x4f, 0x64
- .byte 0x72, 0x3c, 0x50
- .byte 0x74, 0x42, 0x50
- .byte 0x78, 0x4b, 0x64
- .byte 0
- .ascii "Genoa"
- .byte 0
-
-# OAK
-oak_test:
- leaw idoakvga, %si
- movw $0x08, %di
- movw $0x08, %cx
- repe
- cmpsb
- je isoak
-
- xorw %bp, %bp
-isoak: ret
-
-idoakvga: .ascii "OAK VGA "
-
-oak_md: .byte 0x4e, 0x3c, 0x50
- .byte 0x4f, 0x3c, 0x84
- .byte 0x50, 0x19, 0x84
- .byte 0x51, 0x2b, 0x84
- .byte 0
- .ascii "OAK"
- .byte 0
-
-# WD Paradise.
-paradise_test:
- leaw idparadise, %si
- movw $0x7d, %di
- movw $0x04, %cx
- repe
- cmpsb
- je ispara
-
- xorw %bp, %bp
-ispara: ret
-
-idparadise: .ascii "VGA="
-
-paradise_md:
- .byte 0x41, 0x22, 0x50
- .byte 0x47, 0x1c, 0x84
- .byte 0x55, 0x19, 0x84
- .byte 0x54, 0x2c, 0x84
- .byte 0
- .ascii "Paradise"
- .byte 0
-
-# Trident.
-trident_test:
- movw $0x3c4, %dx
- movb $0x0e, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- xchgb %al, %ah
- xorb %al, %al
- outb %al, %dx
- inb %dx, %al
- xchgb %ah, %al
- movb %al, %bl # Strange thing ... in the book this wasn't
- andb $0x02, %bl # necessary but it worked on my card which
- jz setb2 # is a trident. Without it the screen goes
- # blurred ...
- andb $0xfd, %al
- jmp clrb2
-
-setb2: orb $0x02, %al
-clrb2: outb %al, %dx
- andb $0x0f, %ah
- cmpb $0x02, %ah
- je istrid
-
- xorw %bp, %bp
-istrid: ret
-
-trident_md:
- .byte 0x50, 0x1e, 0x50
- .byte 0x51, 0x2b, 0x50
- .byte 0x52, 0x3c, 0x50
- .byte 0x57, 0x19, 0x84
- .byte 0x58, 0x1e, 0x84
- .byte 0x59, 0x2b, 0x84
- .byte 0x5a, 0x3c, 0x84
- .byte 0
- .ascii "Trident"
- .byte 0
-
-# Tseng.
-tseng_test:
- movw $0x3cd, %dx
- inb %dx, %al # Could things be this simple ! :-)
- movb %al, %bl
- movb $0x55, %al
- outb %al, %dx
- inb %dx, %al
- movb %al, %ah
- movb %bl, %al
- outb %al, %dx
- cmpb $0x55, %ah
- je istsen
-
-isnot: xorw %bp, %bp
-istsen: ret
-
-tseng_md:
- .byte 0x26, 0x3c, 0x50
- .byte 0x2a, 0x28, 0x64
- .byte 0x23, 0x19, 0x84
- .byte 0x24, 0x1c, 0x84
- .byte 0x22, 0x2c, 0x84
- .byte 0x21, 0x3c, 0x84
- .byte 0
- .ascii "Tseng"
- .byte 0
-
-# Video7.
-video7_test:
- movw $0x3cc, %dx
- inb %dx, %al
- movw $0x3b4, %dx
- andb $0x01, %al
- jz even7
-
- movw $0x3d4, %dx
-even7: movb $0x0c, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bl
- movb $0x55, %al
- outb %al, %dx
- inb %dx, %al
- decw %dx
- movb $0x1f, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bh
- decw %dx
- movb $0x0c, %al
- outb %al, %dx
- incw %dx
- movb %bl, %al
- outb %al, %dx
- movb $0x55, %al
- xorb $0xea, %al
- cmpb %bh, %al
- jne isnot
-
- movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
- ret
-
-video7_md:
- .byte 0x40, 0x2b, 0x50
- .byte 0x43, 0x3c, 0x50
- .byte 0x44, 0x3c, 0x64
- .byte 0x41, 0x19, 0x84
- .byte 0x42, 0x2c, 0x84
- .byte 0x45, 0x1c, 0x84
- .byte 0
- .ascii "Video 7"
- .byte 0
-
-# Realtek VGA
-realtek_test:
- leaw idrtvga, %si
- movw $0x45, %di
- movw $0x0b, %cx
- repe
- cmpsb
- je isrt
-
- xorw %bp, %bp
-isrt: ret
-
-idrtvga: .ascii "REALTEK VGA"
-
-realtek_md:
- .byte 0x1a, 0x3c, 0x50
- .byte 0x1b, 0x19, 0x84
- .byte 0x1c, 0x1e, 0x84
- .byte 0x1d, 0x2b, 0x84
- .byte 0x1e, 0x3c, 0x84
- .byte 0
- .ascii "REALTEK"
- .byte 0
-
-#endif /* CONFIG_VIDEO_SVGA */
-
-# User-defined local mode table (VGA only)
-#ifdef CONFIG_VIDEO_LOCAL
-local_modes:
- leaw local_mode_table, %si
-locm1: lodsw
- orw %ax, %ax
- jz locm2
-
- stosw
- movsw
- jmp locm1
-
-locm2: ret
-
-# This is the table of local video modes which can be supplied manually
-# by the user. Each entry consists of mode ID (word) and dimensions
-# (byte for column count and another byte for row count). These modes
-# are placed before all SVGA and VESA modes and override them if table
-# compacting is enabled. The table must end with a zero word followed
-# by NUL-terminated video adapter name.
-local_mode_table:
- .word 0x0100 # Example: 40x25
- .byte 25,40
- .word 0
- .ascii "Local"
- .byte 0
-#endif /* CONFIG_VIDEO_LOCAL */
-
-# Read a key and return the ASCII code in al, scan code in ah
-getkey: xorb %ah, %ah
- int $0x16
- ret
-
-# Read a key with a timeout of 30 seconds.
-# The hardware clock is used to get the time.
-getkt: call gettime
- addb $30, %al # Wait 30 seconds
- cmpb $60, %al
- jl lminute
-
- subb $60, %al
-lminute:
- movb %al, %cl
-again: movb $0x01, %ah
- int $0x16
- jnz getkey # key pressed, so get it
-
- call gettime
- cmpb %cl, %al
- jne again
-
- movb $0x20, %al # timeout, return `space'
- ret
-
-# Flush the keyboard buffer
-flush: movb $0x01, %ah
- int $0x16
- jz empty
-
- xorb %ah, %ah
- int $0x16
- jmp flush
-
-empty: ret
-
-# Print hexadecimal number.
-prthw: pushw %ax
- movb %ah, %al
- call prthb
- popw %ax
-prthb: pushw %ax
- shrb $4, %al
- call prthn
- popw %ax
- andb $0x0f, %al
-prthn: cmpb $0x0a, %al
- jc prth1
-
- addb $0x07, %al
-prth1: addb $0x30, %al
- jmp prtchr
-
-# Print decimal number in al
-prtdec: pushw %ax
- pushw %cx
- xorb %ah, %ah
- movb $0x0a, %cl
- idivb %cl
- cmpb $0x09, %al
- jbe lt100
-
- call prtdec
- jmp skip10
-
-lt100: addb $0x30, %al
- call prtchr
-skip10: movb %ah, %al
- addb $0x30, %al
- call prtchr
- popw %cx
- popw %ax
- ret
-
-store_edid:
-#ifdef CONFIG_FIRMWARE_EDID
- pushw %es # just save all registers
- pushw %ax
- pushw %bx
- pushw %cx
- pushw %dx
- pushw %di
-
- pushw %fs
- popw %es
-
- movl $0x13131313, %eax # memset block with 0x13
- movw $32, %cx
- movw $0x140, %di
- cld
- rep
- stosl
-
- cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0
- jl no_edid
-
- pushw %es # save ES
- xorw %di, %di # Report Capability
- pushw %di
- popw %es # ES:DI must be 0:0
- movw $0x4f15, %ax
- xorw %bx, %bx
- xorw %cx, %cx
- int $0x10
- popw %es # restore ES
-
- cmpb $0x00, %ah # call successful
- jne no_edid
-
- cmpb $0x4f, %al # function supported
- jne no_edid
-
- movw $0x4f15, %ax # do VBE/DDC
- movw $0x01, %bx
- movw $0x00, %cx
- movw $0x01, %dx
- movw $0x140, %di
- int $0x10
-
-no_edid:
- popw %di # restore all registers
- popw %dx
- popw %cx
- popw %bx
- popw %ax
- popw %es
-#endif
- ret
-
-# VIDEO_SELECT-only variables
-mt_end: .word 0 # End of video mode table if built
-edit_buf: .space 6 # Line editor buffer
-card_name: .word 0 # Pointer to adapter name
-scanning: .byte 0 # Performing mode scan
-do_restore: .byte 0 # Screen contents altered during mode change
-svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
-graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
-dac_size: .byte 6 # DAC bit depth
-vbe_version: .word 0 # VBE bios version
-
-# Status messages
-keymsg: .ascii "Press <RETURN> to see video modes available, "
- .ascii "<SPACE> to continue or wait 30 secs"
- .byte 0x0d, 0x0a, 0
-
-listhdr: .byte 0x0d, 0x0a
- .ascii "Mode: COLSxROWS:"
-
-crlft: .byte 0x0d, 0x0a, 0
-
-prompt: .byte 0x0d, 0x0a
- .asciz "Enter mode number or `scan': "
-
-unknt: .asciz "Unknown mode ID. Try again."
-
-badmdt: .ascii "You passed an undefined mode number."
- .byte 0x0d, 0x0a, 0
-
-vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
- .ascii "report to <mj@ucw.cz>."
- .byte 0x0d, 0x0a, 0
-
-old_name: .asciz "CGA/MDA/HGA"
-
-ega_name: .asciz "EGA"
-
-svga_name: .ascii " "
-
-vga_name: .asciz "VGA"
-
-vesa_name: .asciz "VESA"
-
-name_bann: .asciz "Video adapter: "
-#endif /* CONFIG_VIDEO_SELECT */
-
-# Other variables:
-adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
-video_segment: .word 0xb800 # Video memory segment
-force_size: .word 0 # Use this size instead of the one in BIOS vars
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 7a1e251e333..941a7e3aa5f 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Wed Mar 7 15:29:47 2007
+# Linux kernel version: 2.6.21-git3
+# Tue May 1 07:30:48 2007
#
CONFIG_X86_64=y
CONFIG_64BIT=y
@@ -118,11 +118,11 @@ CONFIG_X86_PC=y
# CONFIG_X86_VSMP is not set
# CONFIG_MK8 is not set
# CONFIG_MPSC is not set
-# CONFIG_MCORE2 is not set
-CONFIG_GENERIC_CPU=y
-CONFIG_X86_L1_CACHE_BYTES=128
-CONFIG_X86_L1_CACHE_SHIFT=7
-CONFIG_X86_INTERNODE_CACHE_BYTES=128
+CONFIG_MCORE2=y
+# CONFIG_GENERIC_CPU is not set
+CONFIG_X86_L1_CACHE_BYTES=64
+CONFIG_X86_L1_CACHE_SHIFT=6
+CONFIG_X86_INTERNODE_CACHE_BYTES=64
CONFIG_X86_TSC=y
CONFIG_X86_GOOD_APIC=y
# CONFIG_MICROCODE is not set
@@ -174,6 +174,7 @@ CONFIG_X86_MCE_INTEL=y
CONFIG_X86_MCE_AMD=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
+# CONFIG_RELOCATABLE is not set
CONFIG_PHYSICAL_START=0x200000
CONFIG_SECCOMP=y
# CONFIG_CC_STACKPROTECTOR is not set
@@ -182,7 +183,6 @@ CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
-# CONFIG_REORDER is not set
CONFIG_K8_NB=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
@@ -218,7 +218,6 @@ CONFIG_ACPI_HOTPLUG_CPU=y
CONFIG_ACPI_THERMAL=y
CONFIG_ACPI_NUMA=y
# CONFIG_ACPI_ASUS is not set
-# CONFIG_ACPI_IBM is not set
# CONFIG_ACPI_TOSHIBA is not set
CONFIG_ACPI_BLACKLIST_YEAR=0
# CONFIG_ACPI_DEBUG is not set
@@ -243,7 +242,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
#
# CPUFreq processor drivers
@@ -299,7 +298,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -334,6 +332,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
@@ -389,6 +388,13 @@ CONFIG_IPV6_SIT=y
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
# CONFIG_IEEE80211 is not set
#
@@ -409,10 +415,6 @@ CONFIG_FW_LOADER=y
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -459,6 +461,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
# CONFIG_SONY_LAPTOP is not set
+# CONFIG_THINKPAD_ACPI is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -494,7 +497,6 @@ CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_RZ1000 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -525,7 +527,6 @@ CONFIG_BLK_DEV_PDC202XX_NEW=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -584,11 +585,9 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_ARCMSR is not set
-CONFIG_MEGARAID_NEWGEN=y
-CONFIG_MEGARAID_MM=y
-CONFIG_MEGARAID_MAILBOX=y
+# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
-CONFIG_MEGARAID_SAS=y
+# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -608,6 +607,7 @@ CONFIG_MEGARAID_SAS=y
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SRP is not set
#
@@ -631,12 +631,12 @@ CONFIG_SATA_SIL=y
CONFIG_SATA_VIA=y
# CONFIG_SATA_VITESSE is not set
# CONFIG_SATA_INIC162X is not set
-CONFIG_SATA_INTEL_COMBINED=y
CONFIG_SATA_ACPI=y
# CONFIG_PATA_ALI is not set
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
@@ -688,7 +688,7 @@ CONFIG_BLK_DEV_DM=y
CONFIG_FUSION=y
CONFIG_FUSION_SPI=y
# CONFIG_FUSION_FC is not set
-CONFIG_FUSION_SAS=y
+# CONFIG_FUSION_SAS is not set
CONFIG_FUSION_MAX_SGE=128
# CONFIG_FUSION_CTL is not set
@@ -701,19 +701,22 @@ CONFIG_IEEE1394=y
# Subsystem Options
#
# CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_EXTRA_CONFIG_ROMS is not set
#
-# Device Drivers
+# Controllers
+#
+
+#
+# Texas Instruments PCILynx requires I2C
#
-# CONFIG_IEEE1394_PCILYNX is not set
CONFIG_IEEE1394_OHCI1394=y
#
-# Protocol Drivers
+# Protocols
#
# CONFIG_IEEE1394_VIDEO1394 is not set
# CONFIG_IEEE1394_SBP2 is not set
+# CONFIG_IEEE1394_ETH1394_ROM_ENTRY is not set
# CONFIG_IEEE1394_ETH1394 is not set
# CONFIG_IEEE1394_DV1394 is not set
CONFIG_IEEE1394_RAWIO=y
@@ -776,7 +779,8 @@ CONFIG_TULIP=y
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
+CONFIG_AMD8111_ETH=y
+# CONFIG_AMD8111E_NAPI is not set
# CONFIG_ADAPTEC_STARFIRE is not set
CONFIG_B44=y
CONFIG_FORCEDETH=y
@@ -838,9 +842,10 @@ CONFIG_S2IO=m
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
@@ -854,7 +859,6 @@ CONFIG_S2IO=m
# CONFIG_SHAPER is not set
CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
@@ -988,57 +992,7 @@ CONFIG_HPET_MMAP=y
#
# I2C support
#
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_PIIX4 is not set
-CONFIG_I2C_ISA=m
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PASEMI is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_I2C is not set
#
# SPI support
@@ -1054,54 +1008,8 @@ CONFIG_I2C_ISA=m
#
# Hardware Monitoring support
#
-CONFIG_HWMON=y
+# CONFIG_HWMON is not set
# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_K8TEMP is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
-CONFIG_SENSORS_SMSC47B397=m
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_SENSORS_HDAPS is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Multifunction device drivers
@@ -1148,8 +1056,9 @@ CONFIG_SOUND=y
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-# CONFIG_OBSOLETE_OSS is not set
+CONFIG_OBSOLETE_OSS=y
# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_ES1371 is not set
CONFIG_SOUND_ICH=y
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
@@ -1164,6 +1073,14 @@ CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -1176,6 +1093,7 @@ CONFIG_USB=y
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
# CONFIG_USB_OTG is not set
@@ -1226,10 +1144,6 @@ CONFIG_USB_STORAGE=y
#
# USB Input Devices
#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_ACECAD is not set
@@ -1557,7 +1471,7 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 071100ea125..185399baaf6 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -5,6 +5,11 @@
* This tricks binfmt_elf.c into loading 32bit binaries using lots
* of ugly preprocessor tricks. Talk about very very poor man's inheritance.
*/
+#define __ASM_X86_64_ELF_H 1
+
+#undef ELF_CLASS
+#define ELF_CLASS ELFCLASS32
+
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/rwsem.h>
@@ -50,9 +55,6 @@ struct elf_phdr;
#undef ELF_ARCH
#define ELF_ARCH EM_386
-#undef ELF_CLASS
-#define ELF_CLASS ELFCLASS32
-
#define ELF_DATA ELFDATA2LSB
#define USE_ELF_CORE_DUMP 1
@@ -136,7 +138,7 @@ struct elf_prpsinfo
#define user user32
-#define __ASM_X86_64_ELF_H 1
+#undef elf_read_implies_exec
#define elf_read_implies_exec(ex, executable_stack) (executable_stack != EXSTACK_DISABLE_X)
//#include <asm/ia32.h>
#include <linux/elf.h>
diff --git a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c
index 359eacc3850..6ea19c25f90 100644
--- a/arch/x86_64/ia32/ia32_signal.c
+++ b/arch/x86_64/ia32/ia32_signal.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 796df6992f6..f2106837827 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -481,11 +481,7 @@ ia32_sys_call_table:
.quad sys_symlink
.quad sys_lstat
.quad sys_readlink /* 85 */
-#ifdef CONFIG_IA32_AOUT
.quad sys_uselib
-#else
- .quad quiet_ni_syscall
-#endif
.quad sys_swapon
.quad sys_reboot
.quad compat_sys_old_readdir
@@ -714,9 +710,10 @@ ia32_sys_call_table:
.quad compat_sys_get_robust_list
.quad sys_splice
.quad sys_sync_file_range
- .quad sys_tee
+ .quad sys_tee /* 315 */
.quad compat_sys_vmsplice
.quad compat_sys_move_pages
.quad sys_getcpu
.quad sys_epoll_pwait
+ .quad compat_sys_utimensat /* 320 */
ia32_syscall_end:
diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c
index 568ff0df89e..fc4419ff035 100644
--- a/arch/x86_64/ia32/syscall32.c
+++ b/arch/x86_64/ia32/syscall32.c
@@ -13,6 +13,7 @@
#include <asm/proto.h>
#include <asm/tlbflush.h>
#include <asm/ia32_unistd.h>
+#include <asm/vsyscall32.h>
extern unsigned char syscall32_syscall[], syscall32_syscall_end[];
extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[];
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index bb47e86f3d0..de1de8a2fd8 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -8,7 +8,8 @@ obj-y := process.o signal.o entry.o traps.o irq.o \
ptrace.o time.o ioport.o ldt.o setup.o i8259.o sys_x86_64.o \
x8664_ksyms.o i387.o syscall.o vsyscall.o \
setup64.o bootflag.o e820.o reboot.o quirks.o i8237.o \
- pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o
+ pci-dma.o pci-nommu.o alternative.o hpet.o tsc.o bugs.o \
+ perfctr-watchdog.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_X86_MCE) += mce.o therm_throt.o
@@ -21,8 +22,7 @@ obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o tsc_sync.o
obj-y += apic.o nmi.o
-obj-y += io_apic.o mpparse.o \
- genapic.o genapic_cluster.o genapic_flat.o
+obj-y += io_apic.o mpparse.o genapic.o genapic_flat.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_PM) += suspend.o
@@ -32,6 +32,7 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_IOMMU) += pci-gart.o aperture.o
obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary.o tce.o
obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o
+obj-$(CONFIG_SERIAL_8250) += legacy_serial.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_X86_PM_TIMER) += pmtimer.o
obj-$(CONFIG_X86_VSMP) += vsmp.o
@@ -49,6 +50,7 @@ CFLAGS_vsyscall.o := $(PROFILING) -g0
therm_throt-y += ../../i386/kernel/cpu/mcheck/therm_throt.o
bootflag-y += ../../i386/kernel/bootflag.o
+legacy_serial-y += ../../i386/kernel/legacy_serial.o
cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o
topology-y += ../../i386/kernel/topology.o
microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o
@@ -58,3 +60,4 @@ i8237-y += ../../i386/kernel/i8237.o
msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o
alternative-y += ../../i386/kernel/alternative.o
pcspeaker-y += ../../i386/kernel/pcspeaker.o
+perfctr-watchdog-y += ../../i386/kernel/cpu/perfctr-watchdog.o
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index e1548fbe95a..195b7034a14 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -60,19 +60,6 @@ extern char wakeup_start, wakeup_end;
extern unsigned long acpi_copy_wakeup_routine(unsigned long);
-static pgd_t low_ptr;
-
-static void init_low_mapping(void)
-{
- pgd_t *slot0 = pgd_offset(current->mm, 0UL);
- low_ptr = *slot0;
- /* FIXME: We're playing with the current task's page tables here, which
- * is potentially dangerous on SMP systems.
- */
- set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET));
- local_flush_tlb();
-}
-
/**
* acpi_save_state_mem - save kernel state
*
@@ -81,8 +68,6 @@ static void init_low_mapping(void)
*/
int acpi_save_state_mem(void)
{
- init_low_mapping();
-
memcpy((void *)acpi_wakeup_address, &wakeup_start,
&wakeup_end - &wakeup_start);
acpi_copy_wakeup_routine(acpi_wakeup_address);
@@ -95,8 +80,6 @@ int acpi_save_state_mem(void)
*/
void acpi_restore_state_mem(void)
{
- set_pgd(pgd_offset(current->mm, 0UL), low_ptr);
- local_flush_tlb();
}
/**
@@ -109,10 +92,11 @@ void acpi_restore_state_mem(void)
*/
void __init acpi_reserve_bootmem(void)
{
- acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE);
- if ((&wakeup_end - &wakeup_start) > PAGE_SIZE)
+ acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2);
+ if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2))
printk(KERN_CRIT
- "ACPI: Wakeup code way too big, will crash on attempt to suspend\n");
+ "ACPI: Wakeup code way too big, will crash on attempt"
+ " to suspend\n");
}
static int __init acpi_sleep_setup(char *str)
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index 185faa911db..8550a6ffa27 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -1,6 +1,7 @@
.text
#include <linux/linkage.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/msr.h>
@@ -30,22 +31,28 @@ wakeup_code:
cld
# setup data segment
movw %cs, %ax
- movw %ax, %ds # Make ds:0 point to wakeup_start
+ movw %ax, %ds # Make ds:0 point to wakeup_start
movw %ax, %ss
- mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
+ # Private stack is needed for ASUS board
+ mov $(wakeup_stack - wakeup_code), %sp
- pushl $0 # Kill any dangerous flags
+ pushl $0 # Kill any dangerous flags
popfl
movl real_magic - wakeup_code, %eax
cmpl $0x12345678, %eax
jne bogus_real_magic
+ call verify_cpu # Verify the cpu supports long
+ # mode
+ testl %eax, %eax
+ jnz no_longmode
+
testl $1, video_flags - wakeup_code
jz 1f
lcall $0xc000,$3
movw %cs, %ax
- movw %ax, %ds # Bios might have played with that
+ movw %ax, %ds # Bios might have played with that
movw %ax, %ss
1:
@@ -61,12 +68,15 @@ wakeup_code:
movb $0xa2, %al ; outb %al, $0x80
- lidt %ds:idt_48a - wakeup_code
- xorl %eax, %eax
- movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
- shll $4, %eax
- addl $(gdta - wakeup_code), %eax
- movl %eax, gdt_48a +2 - wakeup_code
+ mov %ds, %ax # Find 32bit wakeup_code addr
+ movzx %ax, %esi # (Convert %ds:gdt to a liner ptr)
+ shll $4, %esi
+ # Fix up the vectors
+ addl %esi, wakeup_32_vector - wakeup_code
+ addl %esi, wakeup_long64_vector - wakeup_code
+ addl %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
+
+ lidtl %ds:idt_48a - wakeup_code
lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is
# appropriate
@@ -75,86 +85,63 @@ wakeup_code:
jmp 1f
1:
- .byte 0x66, 0xea # prefix + jmpi-opcode
- .long wakeup_32 - __START_KERNEL_map
- .word __KERNEL_CS
+ ljmpl *(wakeup_32_vector - wakeup_code)
+
+ .balign 4
+wakeup_32_vector:
+ .long wakeup_32 - wakeup_code
+ .word __KERNEL32_CS, 0
.code32
wakeup_32:
# Running in this code, but at low address; paging is not yet turned on.
movb $0xa5, %al ; outb %al, $0x80
- /* Check if extended functions are implemented */
- movl $0x80000000, %eax
- cpuid
- cmpl $0x80000000, %eax
- jbe bogus_cpu
- wbinvd
- mov $0x80000001, %eax
- cpuid
- btl $29, %edx
- jnc bogus_cpu
- movl %edx,%edi
-
- movw $__KERNEL_DS, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
-
- movw $__KERNEL_DS, %ax
- movw %ax, %ss
+ movl $__KERNEL_DS, %eax
+ movl %eax, %ds
- mov $(wakeup_stack - __START_KERNEL_map), %esp
- movl saved_magic - __START_KERNEL_map, %eax
- cmpl $0x9abcdef0, %eax
- jne bogus_32_magic
+ movw $0x0e00 + 'i', %ds:(0xb8012)
+ movb $0xa8, %al ; outb %al, $0x80;
/*
* Prepare for entering 64bits mode
*/
- /* Enable PAE mode and PGE */
+ /* Enable PAE */
xorl %eax, %eax
btsl $5, %eax
- btsl $7, %eax
movl %eax, %cr4
/* Setup early boot stage 4 level pagetables */
- movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax
+ leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax
movl %eax, %cr3
- /* Setup EFER (Extended Feature Enable Register) */
- movl $MSR_EFER, %ecx
- rdmsr
- /* Fool rdmsr and reset %eax to avoid dependences */
- xorl %eax, %eax
+ /* Check if nx is implemented */
+ movl $0x80000001, %eax
+ cpuid
+ movl %edx,%edi
+
/* Enable Long Mode */
+ xorl %eax, %eax
btsl $_EFER_LME, %eax
- /* Enable System Call */
- btsl $_EFER_SCE, %eax
- /* No Execute supported? */
+ /* No Execute supported? */
btl $20,%edi
jnc 1f
btsl $_EFER_NX, %eax
-1:
/* Make changes effective */
+1: movl $MSR_EFER, %ecx
+ xorl %edx, %edx
wrmsr
- wbinvd
xorl %eax, %eax
btsl $31, %eax /* Enable paging and in turn activate Long Mode */
btsl $0, %eax /* Enable protected mode */
- btsl $1, %eax /* Enable MP */
- btsl $4, %eax /* Enable ET */
- btsl $5, %eax /* Enable NE */
- btsl $16, %eax /* Enable WP */
- btsl $18, %eax /* Enable AM */
/* Make changes effective */
movl %eax, %cr0
+
/* At this point:
CR4.PAE must be 1
CS.L must be 0
@@ -162,11 +149,6 @@ wakeup_32:
Next instruction must be a branch
This must be on identity-mapped page
*/
- jmp reach_compatibility_mode
-reach_compatibility_mode:
- movw $0x0e00 + 'i', %ds:(0xb8012)
- movb $0xa8, %al ; outb %al, $0x80;
-
/*
* At this point we're in long mode but in 32bit compatibility mode
* with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
@@ -174,24 +156,19 @@ reach_compatibility_mode:
* the new gdt/idt that has __KERNEL_CS with CS.L = 1.
*/
- movw $0x0e00 + 'n', %ds:(0xb8014)
- movb $0xa9, %al ; outb %al, $0x80
-
- /* Load new GDT with the 64bit segment using 32bit descriptor */
- movl $(pGDT32 - __START_KERNEL_map), %eax
- lgdt (%eax)
-
- movl $(wakeup_jumpvector - __START_KERNEL_map), %eax
/* Finally jump in 64bit mode */
- ljmp *(%eax)
+ ljmp *(wakeup_long64_vector - wakeup_code)(%esi)
-wakeup_jumpvector:
- .long wakeup_long64 - __START_KERNEL_map
- .word __KERNEL_CS
+ .balign 4
+wakeup_long64_vector:
+ .long wakeup_long64 - wakeup_code
+ .word __KERNEL_CS, 0
.code64
- /* Hooray, we are in Long 64-bit mode (but still running in low memory) */
+ /* Hooray, we are in Long 64-bit mode (but still running in
+ * low memory)
+ */
wakeup_long64:
/*
* We must switch to a new descriptor in kernel space for the GDT
@@ -199,7 +176,15 @@ wakeup_long64:
* addresses where we're currently running on. We have to do that here
* because in 32bit we couldn't load a 64bit linear address.
*/
- lgdt cpu_gdt_descr - __START_KERNEL_map
+ lgdt cpu_gdt_descr
+
+ movw $0x0e00 + 'n', %ds:(0xb8014)
+ movb $0xa9, %al ; outb %al, $0x80
+
+ movq saved_magic, %rax
+ movq $0x123456789abcdef0, %rdx
+ cmpq %rdx, %rax
+ jne bogus_64_magic
movw $0x0e00 + 'u', %ds:(0xb8016)
@@ -211,75 +196,58 @@ wakeup_long64:
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
- movq saved_esp, %rsp
+ movq saved_rsp, %rsp
movw $0x0e00 + 'x', %ds:(0xb8018)
- movq saved_ebx, %rbx
- movq saved_edi, %rdi
- movq saved_esi, %rsi
- movq saved_ebp, %rbp
+ movq saved_rbx, %rbx
+ movq saved_rdi, %rdi
+ movq saved_rsi, %rsi
+ movq saved_rbp, %rbp
movw $0x0e00 + '!', %ds:(0xb801a)
- movq saved_eip, %rax
+ movq saved_rip, %rax
jmp *%rax
.code32
.align 64
gdta:
+ /* Its good to keep gdt in sync with one in trampoline.S */
.word 0, 0, 0, 0 # dummy
-
- .word 0, 0, 0, 0 # unused
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9B00 # code read/exec. ??? Why I need 0x9B00 (as opposed to 0x9A00 in order for this to work?)
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9200 # data read/write
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-# this is 64bit descriptor for code
- .word 0xFFFF
- .word 0
- .word 0x9A00 # code read/exec
- .word 0x00AF # as above, but it is long mode and with D=0
+ /* ??? Why I need the accessed bit set in order for this to work? */
+ .quad 0x00cf9b000000ffff # __KERNEL32_CS
+ .quad 0x00af9b000000ffff # __KERNEL_CS
+ .quad 0x00cf93000000ffff # __KERNEL_DS
idt_48a:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
gdt_48a:
- .word 0x8000 # gdt limit=2048,
+ .word 0x800 # gdt limit=2048,
# 256 GDT entries
- .word 0, 0 # gdt base (filled in later)
-
+ .long gdta - wakeup_code # gdt base (relocated in later)
-real_save_gdt: .word 0
- .quad 0
real_magic: .quad 0
video_mode: .quad 0
video_flags: .quad 0
+.code16
bogus_real_magic:
- movb $0xba,%al ; outb %al,$0x80
+ movb $0xba,%al ; outb %al,$0x80
jmp bogus_real_magic
-bogus_32_magic:
+.code64
+bogus_64_magic:
movb $0xb3,%al ; outb %al,$0x80
- jmp bogus_32_magic
+ jmp bogus_64_magic
-bogus_31_magic:
- movb $0xb1,%al ; outb %al,$0x80
- jmp bogus_31_magic
-
-bogus_cpu:
- movb $0xbc,%al ; outb %al,$0x80
- jmp bogus_cpu
+.code16
+no_longmode:
+ movb $0xbc,%al ; outb %al,$0x80
+ jmp no_longmode
+#include "../verify_cpu.S"
/* This code uses an extended set of video mode numbers. These include:
* Aliases for standard modes
@@ -301,6 +269,7 @@ bogus_cpu:
#define VIDEO_FIRST_V7 0x0900
# Setting of user mode (AX=mode ID) => CF=success
+.code16
mode_seta:
movw %ax, %bx
#if 0
@@ -346,21 +315,18 @@ check_vesaa:
_setbada: jmp setbada
- .code64
-bogus_magic:
- movw $0x0e00 + 'B', %ds:(0xb8018)
- jmp bogus_magic
-
-bogus_magic2:
- movw $0x0e00 + '2', %ds:(0xb8018)
- jmp bogus_magic2
-
-
wakeup_stack_begin: # Stack grows down
.org 0xff0
wakeup_stack: # Just below end of page
+.org 0x1000
+ENTRY(wakeup_level4_pgt)
+ .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ .fill 510,8,0
+ /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+ .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
+
ENTRY(wakeup_end)
##
@@ -373,28 +339,11 @@ ENTRY(wakeup_end)
#
# Returned address is location of code in low memory (past data and stack)
#
+ .code64
ENTRY(acpi_copy_wakeup_routine)
pushq %rax
- pushq %rcx
pushq %rdx
- sgdt saved_gdt
- sidt saved_idt
- sldt saved_ldt
- str saved_tss
-
- movq %cr3, %rdx
- movq %rdx, saved_cr3
- movq %cr4, %rdx
- movq %rdx, saved_cr4
- movq %cr0, %rdx
- movq %rdx, saved_cr0
- sgdt real_save_gdt - wakeup_start (,%rdi)
- movl $MSR_EFER, %ecx
- rdmsr
- movl %eax, saved_efer
- movl %edx, saved_efer2
-
movl saved_video_mode, %edx
movl %edx, video_mode - wakeup_start (,%rdi)
movl acpi_video_flags, %edx
@@ -403,21 +352,13 @@ ENTRY(acpi_copy_wakeup_routine)
movq $0x123456789abcdef0, %rdx
movq %rdx, saved_magic
- movl saved_magic - __START_KERNEL_map, %eax
- cmpl $0x9abcdef0, %eax
- jne bogus_32_magic
-
- # make sure %cr4 is set correctly (features, etc)
- movl saved_cr4 - __START_KERNEL_map, %eax
- movq %rax, %cr4
+ movq saved_magic, %rax
+ movq $0x123456789abcdef0, %rdx
+ cmpq %rdx, %rax
+ jne bogus_64_magic
- movl saved_cr0 - __START_KERNEL_map, %eax
- movq %rax, %cr0
- jmp 1f # Flush pipelines
-1:
# restore the regs we used
popq %rdx
- popq %rcx
popq %rax
ENTRY(do_suspend_lowlevel_s4bios)
ret
@@ -450,13 +391,13 @@ do_suspend_lowlevel:
movq %r15, saved_context_r15(%rip)
pushfq ; popq saved_context_eflags(%rip)
- movq $.L97, saved_eip(%rip)
+ movq $.L97, saved_rip(%rip)
- movq %rsp,saved_esp
- movq %rbp,saved_ebp
- movq %rbx,saved_ebx
- movq %rdi,saved_edi
- movq %rsi,saved_esi
+ movq %rsp,saved_rsp
+ movq %rbp,saved_rbp
+ movq %rbx,saved_rbx
+ movq %rdi,saved_rdi
+ movq %rsi,saved_rsi
addq $8, %rsp
movl $3, %edi
@@ -503,25 +444,12 @@ do_suspend_lowlevel:
.data
ALIGN
-ENTRY(saved_ebp) .quad 0
-ENTRY(saved_esi) .quad 0
-ENTRY(saved_edi) .quad 0
-ENTRY(saved_ebx) .quad 0
+ENTRY(saved_rbp) .quad 0
+ENTRY(saved_rsi) .quad 0
+ENTRY(saved_rdi) .quad 0
+ENTRY(saved_rbx) .quad 0
-ENTRY(saved_eip) .quad 0
-ENTRY(saved_esp) .quad 0
+ENTRY(saved_rip) .quad 0
+ENTRY(saved_rsp) .quad 0
ENTRY(saved_magic) .quad 0
-
-ALIGN
-# saved registers
-saved_gdt: .quad 0,0
-saved_idt: .quad 0,0
-saved_ldt: .quad 0
-saved_tss: .quad 0
-
-saved_cr0: .quad 0
-saved_cr3: .quad 0
-saved_cr4: .quad 0
-saved_efer: .quad 0
-saved_efer2: .quad 0
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index b487396c4c5..a52af582059 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -51,7 +51,6 @@ static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
static u32 __init allocate_aperture(void)
{
- pg_data_t *nd0 = NODE_DATA(0);
u32 aper_size;
void *p;
@@ -65,12 +64,12 @@ static u32 __init allocate_aperture(void)
* Unfortunately we cannot move it up because that would make the
* IOMMU useless.
*/
- p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0);
+ p = __alloc_bootmem_nopanic(aper_size, aper_size, 0);
if (!p || __pa(p)+aper_size > 0xffffffff) {
printk("Cannot allocate aperture memory hole (%p,%uK)\n",
p, aper_size>>10);
if (p)
- free_bootmem_node(nd0, __pa(p), aper_size);
+ free_bootmem(__pa(p), aper_size);
return 0;
}
printk("Mapping aperture over %d KB of RAM @ %lx\n",
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index bd3e45d47c3..1b0e07bb872 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -19,7 +19,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h>
@@ -68,6 +67,28 @@ int using_apic_timer __read_mostly = 0;
static void apic_pm_activate(void);
+void apic_wait_icr_idle(void)
+{
+ while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
+ cpu_relax();
+}
+
+unsigned int safe_apic_wait_icr_idle(void)
+{
+ unsigned int send_status;
+ int timeout;
+
+ timeout = 0;
+ do {
+ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+ if (!send_status)
+ break;
+ udelay(100);
+ } while (timeout++ < 1000);
+
+ return send_status;
+}
+
void enable_NMI_through_LVT0 (void * dummy)
{
unsigned int v;
@@ -817,14 +838,15 @@ static void setup_APIC_timer(unsigned int clocks)
static int __init calibrate_APIC_clock(void)
{
- int apic, apic_start, tsc, tsc_start;
+ unsigned apic, apic_start;
+ unsigned long tsc, tsc_start;
int result;
/*
* Put whatever arbitrary (but long enough) timeout
* value into the APIC clock, we just want to get the
* counter running for calibration.
*/
- __setup_APIC_LVTT(1000000000);
+ __setup_APIC_LVTT(4000000000);
apic_start = apic_read(APIC_TMCCT);
#ifdef CONFIG_X86_PM_TIMER
@@ -835,15 +857,15 @@ static int __init calibrate_APIC_clock(void)
} else
#endif
{
- rdtscl(tsc_start);
+ rdtscll(tsc_start);
do {
apic = apic_read(APIC_TMCCT);
- rdtscl(tsc);
+ rdtscll(tsc);
} while ((tsc - tsc_start) < TICK_COUNT &&
- (apic - apic_start) < TICK_COUNT);
+ (apic_start - apic) < TICK_COUNT);
- result = (apic_start - apic) * 1000L * cpu_khz /
+ result = (apic_start - apic) * 1000L * tsc_khz /
(tsc - tsc_start);
}
printk("result %d\n", result);
diff --git a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c
index 96687e2beb2..778953bc636 100644
--- a/arch/x86_64/kernel/asm-offsets.c
+++ b/arch/x86_64/kernel/asm-offsets.c
@@ -21,6 +21,14 @@
#define BLANK() asm volatile("\n->" : : )
+#define __NO_STUBS 1
+#undef __SYSCALL
+#undef _ASM_X86_64_UNISTD_H_
+#define __SYSCALL(nr, sym) [nr] = 1,
+static char syscalls[] = {
+#include <asm/unistd.h>
+};
+
int main(void)
{
#define ENTRY(entry) DEFINE(tsk_ ## entry, offsetof(struct task_struct, entry))
@@ -71,5 +79,7 @@ int main(void)
DEFINE(TSS_ist, offsetof(struct tss_struct, ist));
BLANK();
DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+ BLANK();
+ DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
return 0;
}
diff --git a/arch/x86_64/kernel/bugs.c b/arch/x86_64/kernel/bugs.c
new file mode 100644
index 00000000000..12b585b5345
--- /dev/null
+++ b/arch/x86_64/kernel/bugs.c
@@ -0,0 +1,21 @@
+/*
+ * arch/x86_64/kernel/bugs.c
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ * Copyright (C) 2000 SuSE
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/alternative.h>
+#include <asm/processor.h>
+
+void __init check_bugs(void)
+{
+ identify_cpu(&boot_cpu_data);
+#if !defined(CONFIG_SMP)
+ printk("CPU: ");
+ print_cpu_info(&boot_cpu_data);
+#endif
+ alternative_instructions();
+}
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
index 40acb67fb88..c0749d2479f 100644
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -16,6 +16,9 @@ config X86_POWERNOW_K8
help
This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors.
+ To compile this driver as a module, choose M here: the
+ module will be called powernow-k8.
+
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
@@ -38,6 +41,9 @@ config X86_SPEEDSTEP_CENTRINO
mobile CPUs. This means Intel Pentium M (Centrino) CPUs
or 64bit enabled Intel Xeons.
+ To compile this driver as a module, choose M here: the
+ module will be called speedstep-centrino.
+
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
@@ -55,6 +61,9 @@ config X86_ACPI_CPUFREQ
Processor Performance States.
This driver also supports Intel Enhanced Speedstep.
+ To compile this driver as a module, choose M here: the
+ module will be called acpi-cpufreq.
+
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
@@ -62,7 +71,7 @@ config X86_ACPI_CPUFREQ
comment "shared options"
config X86_ACPI_CPUFREQ_PROC_INTF
- bool "/proc/acpi/processor/../performance interface (deprecated)"
+ bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on PROC_FS
depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI
help
@@ -86,16 +95,18 @@ config X86_P4_CLOCKMOD
slowdowns and noticeable latencies. Normally Speedstep should be used
instead.
+ To compile this driver as a module, choose M here: the
+ module will be called p4-clockmod.
+
For details, take a look at <file:Documentation/cpu-freq/>.
Unless you are absolutely sure say N.
config X86_SPEEDSTEP_LIB
- tristate
- default X86_P4_CLOCKMOD
+ tristate
+ default X86_P4_CLOCKMOD
endif
endmenu
-
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
index 95a7a2c1313..13432a1ae90 100644
--- a/arch/x86_64/kernel/crash.c
+++ b/arch/x86_64/kernel/crash.c
@@ -17,13 +17,13 @@
#include <linux/delay.h>
#include <linux/elf.h>
#include <linux/elfcore.h>
+#include <linux/kdebug.h>
#include <asm/processor.h>
#include <asm/hardirq.h>
#include <asm/nmi.h>
#include <asm/hw_irq.h>
#include <asm/mach_apic.h>
-#include <asm/kdebug.h>
/* This keeps a track of which one is crashing cpu. */
static int crashing_cpu;
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index a490fabfcf4..13c6c37610e 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -17,6 +17,8 @@
#include <linux/kexec.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <linux/pfn.h>
#include <asm/pgtable.h>
#include <asm/page.h>
@@ -25,7 +27,7 @@
#include <asm/bootsetup.h>
#include <asm/sections.h>
-struct e820map e820 __initdata;
+struct e820map e820;
/*
* PFN of last memory page.
@@ -98,7 +100,7 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size)
* This function checks if any part of the range <start,end> is mapped
* with type.
*/
-int __meminit
+int
e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
{
int i;
@@ -112,6 +114,7 @@ e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
}
return 0;
}
+EXPORT_SYMBOL_GPL(e820_any_mapped);
/*
* This function checks if the entire range <start,end> is mapped with type.
@@ -255,22 +258,6 @@ void __init e820_reserve_resources(void)
}
}
-/* Mark pages corresponding to given address range as nosave */
-static void __init
-e820_mark_nosave_range(unsigned long start, unsigned long end)
-{
- unsigned long pfn, max_pfn;
-
- if (start >= end)
- return;
-
- printk("Nosave address range: %016lx - %016lx\n", start, end);
- max_pfn = end >> PAGE_SHIFT;
- for (pfn = start >> PAGE_SHIFT; pfn < max_pfn; pfn++)
- if (pfn_valid(pfn))
- SetPageNosave(pfn_to_page(pfn));
-}
-
/*
* Find the ranges of physical addresses that do not correspond to
* e820 RAM areas and mark the corresponding pages as nosave for software
@@ -289,13 +276,13 @@ void __init e820_mark_nosave_regions(void)
struct e820entry *ei = &e820.map[i];
if (paddr < ei->addr)
- e820_mark_nosave_range(paddr,
- round_up(ei->addr, PAGE_SIZE));
+ register_nosave_region(PFN_DOWN(paddr),
+ PFN_UP(ei->addr));
paddr = round_down(ei->addr + ei->size, PAGE_SIZE);
if (ei->type != E820_RAM)
- e820_mark_nosave_range(round_up(ei->addr, PAGE_SIZE),
- paddr);
+ register_nosave_region(PFN_UP(ei->addr),
+ PFN_DOWN(paddr));
if (paddr >= (end_pfn << PAGE_SHIFT))
break;
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index fede55a5399..990d9c218a5 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -71,18 +71,6 @@ static void __init ati_bugs(void)
}
}
-static void intel_bugs(void)
-{
- u16 device = read_pci_config_16(0, 0, 0, PCI_DEVICE_ID);
-
-#ifdef CONFIG_SMP
- if (device == PCI_DEVICE_ID_INTEL_E7320_MCH ||
- device == PCI_DEVICE_ID_INTEL_E7520_MCH ||
- device == PCI_DEVICE_ID_INTEL_E7525_MCH)
- quirk_intel_irqbalance();
-#endif
-}
-
struct chipset {
u16 vendor;
void (*f)(void);
@@ -92,7 +80,6 @@ static struct chipset early_qrk[] __initdata = {
{ PCI_VENDOR_ID_NVIDIA, nvidia_bugs },
{ PCI_VENDOR_ID_VIA, via_bugs },
{ PCI_VENDOR_ID_ATI, ati_bugs },
- { PCI_VENDOR_ID_INTEL, intel_bugs},
{}
};
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index 47b6d90349d..56eaa259782 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -11,11 +11,10 @@
#ifdef __i386__
#include <asm/setup.h>
-#define VGABASE (__ISA_IO_base + 0xb8000)
#else
#include <asm/bootsetup.h>
-#define VGABASE ((void __iomem *)0xffffffff800b8000UL)
#endif
+#define VGABASE (__ISA_IO_base + 0xb8000)
static int max_ypos = 25, max_xpos = 80;
static int current_ypos = 25, current_xpos = 0;
@@ -176,7 +175,7 @@ static noinline long simnow(long cmd, long a, long b, long c)
return ret;
}
-void __init simnow_init(char *str)
+static void __init simnow_init(char *str)
{
char *fn = "klog";
if (*str == '=')
@@ -244,22 +243,12 @@ static int __init setup_early_printk(char *buf)
early_console = &simnow_console;
keep_early = 1;
}
+
+ if (keep_early)
+ early_console->flags &= ~CON_BOOT;
+ else
+ early_console->flags |= CON_BOOT;
register_console(early_console);
return 0;
}
-
early_param("earlyprintk", setup_early_printk);
-
-void __init disable_early_printk(void)
-{
- if (!early_console_initialized || !early_console)
- return;
- if (!keep_early) {
- printk("disabling early console\n");
- unregister_console(early_console);
- early_console_initialized = 0;
- } else {
- printk("keeping early console\n");
- }
-}
-
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index ed4350ced3d..fa984b53e7e 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -701,6 +701,7 @@ END(spurious_interrupt)
CFI_ADJUST_CFA_OFFSET 8
pushq %rax /* push real oldrax to the rdi slot */
CFI_ADJUST_CFA_OFFSET 8
+ CFI_REL_OFFSET rax,0
leaq \sym(%rip),%rax
jmp error_entry
CFI_ENDPROC
@@ -710,6 +711,7 @@ END(spurious_interrupt)
XCPT_FRAME
pushq %rax
CFI_ADJUST_CFA_OFFSET 8
+ CFI_REL_OFFSET rax,0
leaq \sym(%rip),%rax
jmp error_entry
CFI_ENDPROC
@@ -817,6 +819,7 @@ paranoid_schedule\trace:
*/
KPROBE_ENTRY(error_entry)
_frame RDI
+ CFI_REL_OFFSET rax,0
/* rdi slot contains rax, oldrax contains error code */
cld
subq $14*8,%rsp
@@ -824,6 +827,7 @@ KPROBE_ENTRY(error_entry)
movq %rsi,13*8(%rsp)
CFI_REL_OFFSET rsi,RSI
movq 14*8(%rsp),%rsi /* load rax from rdi slot */
+ CFI_REGISTER rax,rsi
movq %rdx,12*8(%rsp)
CFI_REL_OFFSET rdx,RDX
movq %rcx,11*8(%rsp)
@@ -857,6 +861,7 @@ error_swapgs:
swapgs
error_sti:
movq %rdi,RDI(%rsp)
+ CFI_REL_OFFSET rdi,RDI
movq %rsp,%rdi
movq ORIG_RAX(%rsp),%rsi /* get error code */
movq $-1,ORIG_RAX(%rsp)
diff --git a/arch/x86_64/kernel/functionlist b/arch/x86_64/kernel/functionlist
deleted file mode 100644
index 7ae18ec1245..00000000000
--- a/arch/x86_64/kernel/functionlist
+++ /dev/null
@@ -1,1284 +0,0 @@
-*(.text.flush_thread)
-*(.text.check_poison_obj)
-*(.text.copy_page)
-*(.text.__set_personality)
-*(.text.gart_map_sg)
-*(.text.kmem_cache_free)
-*(.text.find_get_page)
-*(.text._raw_spin_lock)
-*(.text.ide_outb)
-*(.text.unmap_vmas)
-*(.text.copy_page_range)
-*(.text.kprobe_handler)
-*(.text.__handle_mm_fault)
-*(.text.__d_lookup)
-*(.text.copy_user_generic)
-*(.text.__link_path_walk)
-*(.text.get_page_from_freelist)
-*(.text.kmem_cache_alloc)
-*(.text.drive_cmd_intr)
-*(.text.ia32_setup_sigcontext)
-*(.text.huge_pte_offset)
-*(.text.do_page_fault)
-*(.text.page_remove_rmap)
-*(.text.release_pages)
-*(.text.ide_end_request)
-*(.text.__mutex_lock_slowpath)
-*(.text.__find_get_block)
-*(.text.kfree)
-*(.text.vfs_read)
-*(.text._raw_spin_unlock)
-*(.text.free_hot_cold_page)
-*(.text.fget_light)
-*(.text.schedule)
-*(.text.memcmp)
-*(.text.touch_atime)
-*(.text.__might_sleep)
-*(.text.__down_read_trylock)
-*(.text.arch_pick_mmap_layout)
-*(.text.find_vma)
-*(.text.__make_request)
-*(.text.do_generic_mapping_read)
-*(.text.mutex_lock_interruptible)
-*(.text.__generic_file_aio_read)
-*(.text._atomic_dec_and_lock)
-*(.text.__wake_up_bit)
-*(.text.add_to_page_cache)
-*(.text.cache_alloc_debugcheck_after)
-*(.text.vm_normal_page)
-*(.text.mutex_debug_check_no_locks_freed)
-*(.text.net_rx_action)
-*(.text.__find_first_zero_bit)
-*(.text.put_page)
-*(.text._raw_read_lock)
-*(.text.__delay)
-*(.text.dnotify_parent)
-*(.text.do_path_lookup)
-*(.text.do_sync_read)
-*(.text.do_lookup)
-*(.text.bit_waitqueue)
-*(.text.file_read_actor)
-*(.text.strncpy_from_user)
-*(.text.__pagevec_lru_add_active)
-*(.text.fget)
-*(.text.dput)
-*(.text.__strnlen_user)
-*(.text.inotify_inode_queue_event)
-*(.text.rw_verify_area)
-*(.text.ide_intr)
-*(.text.inotify_dentry_parent_queue_event)
-*(.text.permission)
-*(.text.memscan)
-*(.text.hpet_rtc_interrupt)
-*(.text.do_mmap_pgoff)
-*(.text.current_fs_time)
-*(.text.vfs_getattr)
-*(.text.kmem_flagcheck)
-*(.text.mark_page_accessed)
-*(.text.free_pages_and_swap_cache)
-*(.text.generic_fillattr)
-*(.text.__block_prepare_write)
-*(.text.__set_page_dirty_nobuffers)
-*(.text.link_path_walk)
-*(.text.find_get_pages_tag)
-*(.text.ide_do_request)
-*(.text.__alloc_pages)
-*(.text.generic_permission)
-*(.text.mod_page_state_offset)
-*(.text.free_pgd_range)
-*(.text.generic_file_buffered_write)
-*(.text.number)
-*(.text.ide_do_rw_disk)
-*(.text.__brelse)
-*(.text.__mod_page_state_offset)
-*(.text.rotate_reclaimable_page)
-*(.text.find_vma_prepare)
-*(.text.find_vma_prev)
-*(.text.lru_cache_add_active)
-*(.text.__kmalloc_track_caller)
-*(.text.smp_invalidate_interrupt)
-*(.text.handle_IRQ_event)
-*(.text.__find_get_block_slow)
-*(.text.do_wp_page)
-*(.text.do_select)
-*(.text.set_user_nice)
-*(.text.sys_read)
-*(.text.do_munmap)
-*(.text.csum_partial)
-*(.text.__do_softirq)
-*(.text.may_open)
-*(.text.getname)
-*(.text.get_empty_filp)
-*(.text.__fput)
-*(.text.remove_mapping)
-*(.text.filp_ctor)
-*(.text.poison_obj)
-*(.text.unmap_region)
-*(.text.test_set_page_writeback)
-*(.text.__do_page_cache_readahead)
-*(.text.sock_def_readable)
-*(.text.ide_outl)
-*(.text.shrink_zone)
-*(.text.rb_insert_color)
-*(.text.get_request)
-*(.text.sys_pread64)
-*(.text.spin_bug)
-*(.text.ide_outsl)
-*(.text.mask_and_ack_8259A)
-*(.text.filemap_nopage)
-*(.text.page_add_file_rmap)
-*(.text.find_lock_page)
-*(.text.tcp_poll)
-*(.text.__mark_inode_dirty)
-*(.text.file_ra_state_init)
-*(.text.generic_file_llseek)
-*(.text.__pagevec_lru_add)
-*(.text.page_cache_readahead)
-*(.text.n_tty_receive_buf)
-*(.text.zonelist_policy)
-*(.text.vma_adjust)
-*(.text.test_clear_page_dirty)
-*(.text.sync_buffer)
-*(.text.do_exit)
-*(.text.__bitmap_weight)
-*(.text.alloc_pages_current)
-*(.text.get_unused_fd)
-*(.text.zone_watermark_ok)
-*(.text.cpuset_update_task_memory_state)
-*(.text.__bitmap_empty)
-*(.text.sys_munmap)
-*(.text.__inode_dir_notify)
-*(.text.__generic_file_aio_write_nolock)
-*(.text.__pte_alloc)
-*(.text.sys_select)
-*(.text.vm_acct_memory)
-*(.text.vfs_write)
-*(.text.__lru_add_drain)
-*(.text.prio_tree_insert)
-*(.text.generic_file_aio_read)
-*(.text.vma_merge)
-*(.text.block_write_full_page)
-*(.text.__page_set_anon_rmap)
-*(.text.apic_timer_interrupt)
-*(.text.release_console_sem)
-*(.text.sys_write)
-*(.text.sys_brk)
-*(.text.dup_mm)
-*(.text.read_current_timer)
-*(.text.ll_rw_block)
-*(.text.blk_rq_map_sg)
-*(.text.dbg_userword)
-*(.text.__block_commit_write)
-*(.text.cache_grow)
-*(.text.copy_strings)
-*(.text.release_task)
-*(.text.do_sync_write)
-*(.text.unlock_page)
-*(.text.load_elf_binary)
-*(.text.__follow_mount)
-*(.text.__getblk)
-*(.text.do_sys_open)
-*(.text.current_kernel_time)
-*(.text.call_rcu)
-*(.text.write_chan)
-*(.text.vsnprintf)
-*(.text.dummy_inode_setsecurity)
-*(.text.submit_bh)
-*(.text.poll_freewait)
-*(.text.bio_alloc_bioset)
-*(.text.skb_clone)
-*(.text.page_waitqueue)
-*(.text.__mutex_lock_interruptible_slowpath)
-*(.text.get_index)
-*(.text.csum_partial_copy_generic)
-*(.text.bad_range)
-*(.text.remove_vma)
-*(.text.cp_new_stat)
-*(.text.alloc_arraycache)
-*(.text.test_clear_page_writeback)
-*(.text.strsep)
-*(.text.open_namei)
-*(.text._raw_read_unlock)
-*(.text.get_vma_policy)
-*(.text.__down_write_trylock)
-*(.text.find_get_pages)
-*(.text.tcp_rcv_established)
-*(.text.generic_make_request)
-*(.text.__block_write_full_page)
-*(.text.cfq_set_request)
-*(.text.sys_inotify_init)
-*(.text.split_vma)
-*(.text.__mod_timer)
-*(.text.get_options)
-*(.text.vma_link)
-*(.text.mpage_writepages)
-*(.text.truncate_complete_page)
-*(.text.tcp_recvmsg)
-*(.text.sigprocmask)
-*(.text.filemap_populate)
-*(.text.sys_close)
-*(.text.inotify_dev_queue_event)
-*(.text.do_task_stat)
-*(.text.__dentry_open)
-*(.text.unlink_file_vma)
-*(.text.__pollwait)
-*(.text.packet_rcv_spkt)
-*(.text.drop_buffers)
-*(.text.free_pgtables)
-*(.text.generic_file_direct_write)
-*(.text.copy_process)
-*(.text.netif_receive_skb)
-*(.text.dnotify_flush)
-*(.text.print_bad_pte)
-*(.text.anon_vma_unlink)
-*(.text.sys_mprotect)
-*(.text.sync_sb_inodes)
-*(.text.find_inode_fast)
-*(.text.dummy_inode_readlink)
-*(.text.putname)
-*(.text.init_smp_flush)
-*(.text.dbg_redzone2)
-*(.text.sk_run_filter)
-*(.text.may_expand_vm)
-*(.text.generic_file_aio_write)
-*(.text.find_next_zero_bit)
-*(.text.file_kill)
-*(.text.audit_getname)
-*(.text.arch_unmap_area_topdown)
-*(.text.alloc_page_vma)
-*(.text.tcp_transmit_skb)
-*(.text.rb_next)
-*(.text.dbg_redzone1)
-*(.text.generic_file_mmap)
-*(.text.vfs_fstat)
-*(.text.sys_time)
-*(.text.page_lock_anon_vma)
-*(.text.get_unmapped_area)
-*(.text.remote_llseek)
-*(.text.__up_read)
-*(.text.fd_install)
-*(.text.eventpoll_init_file)
-*(.text.dma_alloc_coherent)
-*(.text.create_empty_buffers)
-*(.text.__mutex_unlock_slowpath)
-*(.text.dup_fd)
-*(.text.d_alloc)
-*(.text.tty_ldisc_try)
-*(.text.sys_stime)
-*(.text.__rb_rotate_right)
-*(.text.d_validate)
-*(.text.rb_erase)
-*(.text.path_release)
-*(.text.memmove)
-*(.text.invalidate_complete_page)
-*(.text.clear_inode)
-*(.text.cache_estimate)
-*(.text.alloc_buffer_head)
-*(.text.smp_call_function_interrupt)
-*(.text.flush_tlb_others)
-*(.text.file_move)
-*(.text.balance_dirty_pages_ratelimited)
-*(.text.vma_prio_tree_add)
-*(.text.timespec_trunc)
-*(.text.mempool_alloc)
-*(.text.iget_locked)
-*(.text.d_alloc_root)
-*(.text.cpuset_populate_dir)
-*(.text.anon_vma_prepare)
-*(.text.sys_newstat)
-*(.text.alloc_page_interleave)
-*(.text.__path_lookup_intent_open)
-*(.text.__pagevec_free)
-*(.text.inode_init_once)
-*(.text.free_vfsmnt)
-*(.text.__user_walk_fd)
-*(.text.cfq_idle_slice_timer)
-*(.text.sys_mmap)
-*(.text.sys_llseek)
-*(.text.prio_tree_remove)
-*(.text.filp_close)
-*(.text.file_permission)
-*(.text.vma_prio_tree_remove)
-*(.text.tcp_ack)
-*(.text.nameidata_to_filp)
-*(.text.sys_lseek)
-*(.text.percpu_counter_mod)
-*(.text.igrab)
-*(.text.__bread)
-*(.text.alloc_inode)
-*(.text.filldir)
-*(.text.__rb_rotate_left)
-*(.text.irq_affinity_write_proc)
-*(.text.init_request_from_bio)
-*(.text.find_or_create_page)
-*(.text.tty_poll)
-*(.text.tcp_sendmsg)
-*(.text.ide_wait_stat)
-*(.text.free_buffer_head)
-*(.text.flush_signal_handlers)
-*(.text.tcp_v4_rcv)
-*(.text.nr_blockdev_pages)
-*(.text.locks_remove_flock)
-*(.text.__iowrite32_copy)
-*(.text.do_filp_open)
-*(.text.try_to_release_page)
-*(.text.page_add_new_anon_rmap)
-*(.text.kmem_cache_size)
-*(.text.eth_type_trans)
-*(.text.try_to_free_buffers)
-*(.text.schedule_tail)
-*(.text.proc_lookup)
-*(.text.no_llseek)
-*(.text.kfree_skbmem)
-*(.text.do_wait)
-*(.text.do_mpage_readpage)
-*(.text.vfs_stat_fd)
-*(.text.tty_write)
-*(.text.705)
-*(.text.sync_page)
-*(.text.__remove_shared_vm_struct)
-*(.text.__kfree_skb)
-*(.text.sock_poll)
-*(.text.get_request_wait)
-*(.text.do_sigaction)
-*(.text.do_brk)
-*(.text.tcp_event_data_recv)
-*(.text.read_chan)
-*(.text.pipe_writev)
-*(.text.__emul_lookup_dentry)
-*(.text.rtc_get_rtc_time)
-*(.text.print_objinfo)
-*(.text.file_update_time)
-*(.text.do_signal)
-*(.text.disable_8259A_irq)
-*(.text.blk_queue_bounce)
-*(.text.__anon_vma_link)
-*(.text.__vma_link)
-*(.text.vfs_rename)
-*(.text.sys_newlstat)
-*(.text.sys_newfstat)
-*(.text.sys_mknod)
-*(.text.__show_regs)
-*(.text.iput)
-*(.text.get_signal_to_deliver)
-*(.text.flush_tlb_page)
-*(.text.debug_mutex_wake_waiter)
-*(.text.copy_thread)
-*(.text.clear_page_dirty_for_io)
-*(.text.buffer_io_error)
-*(.text.vfs_permission)
-*(.text.truncate_inode_pages_range)
-*(.text.sys_recvfrom)
-*(.text.remove_suid)
-*(.text.mark_buffer_dirty)
-*(.text.local_bh_enable)
-*(.text.get_zeroed_page)
-*(.text.get_vmalloc_info)
-*(.text.flush_old_exec)
-*(.text.dummy_inode_permission)
-*(.text.__bio_add_page)
-*(.text.prio_tree_replace)
-*(.text.notify_change)
-*(.text.mntput_no_expire)
-*(.text.fput)
-*(.text.__end_that_request_first)
-*(.text.wake_up_bit)
-*(.text.unuse_mm)
-*(.text.shrink_icache_memory)
-*(.text.sched_balance_self)
-*(.text.__pmd_alloc)
-*(.text.pipe_poll)
-*(.text.normal_poll)
-*(.text.__free_pages)
-*(.text.follow_mount)
-*(.text.cdrom_start_packet_command)
-*(.text.blk_recount_segments)
-*(.text.bio_put)
-*(.text.__alloc_skb)
-*(.text.__wake_up)
-*(.text.vm_stat_account)
-*(.text.sys_fcntl)
-*(.text.sys_fadvise64)
-*(.text._raw_write_unlock)
-*(.text.__pud_alloc)
-*(.text.alloc_page_buffers)
-*(.text.vfs_llseek)
-*(.text.sockfd_lookup)
-*(.text._raw_write_lock)
-*(.text.put_compound_page)
-*(.text.prune_dcache)
-*(.text.pipe_readv)
-*(.text.mempool_free)
-*(.text.make_ahead_window)
-*(.text.lru_add_drain)
-*(.text.constant_test_bit)
-*(.text.__clear_user)
-*(.text.arch_unmap_area)
-*(.text.anon_vma_link)
-*(.text.sys_chroot)
-*(.text.setup_arg_pages)
-*(.text.radix_tree_preload)
-*(.text.init_rwsem)
-*(.text.generic_osync_inode)
-*(.text.generic_delete_inode)
-*(.text.do_sys_poll)
-*(.text.dev_queue_xmit)
-*(.text.default_llseek)
-*(.text.__writeback_single_inode)
-*(.text.vfs_ioctl)
-*(.text.__up_write)
-*(.text.unix_poll)
-*(.text.sys_rt_sigprocmask)
-*(.text.sock_recvmsg)
-*(.text.recalc_bh_state)
-*(.text.__put_unused_fd)
-*(.text.process_backlog)
-*(.text.locks_remove_posix)
-*(.text.lease_modify)
-*(.text.expand_files)
-*(.text.end_buffer_read_nobh)
-*(.text.d_splice_alias)
-*(.text.debug_mutex_init_waiter)
-*(.text.copy_from_user)
-*(.text.cap_vm_enough_memory)
-*(.text.show_vfsmnt)
-*(.text.release_sock)
-*(.text.pfifo_fast_enqueue)
-*(.text.half_md4_transform)
-*(.text.fs_may_remount_ro)
-*(.text.do_fork)
-*(.text.copy_hugetlb_page_range)
-*(.text.cache_free_debugcheck)
-*(.text.__tcp_select_window)
-*(.text.task_handoff_register)
-*(.text.sys_open)
-*(.text.strlcpy)
-*(.text.skb_copy_datagram_iovec)
-*(.text.set_up_list3s)
-*(.text.release_open_intent)
-*(.text.qdisc_restart)
-*(.text.n_tty_chars_in_buffer)
-*(.text.inode_change_ok)
-*(.text.__downgrade_write)
-*(.text.debug_mutex_unlock)
-*(.text.add_timer_randomness)
-*(.text.sock_common_recvmsg)
-*(.text.set_bh_page)
-*(.text.printk_lock)
-*(.text.path_release_on_umount)
-*(.text.ip_output)
-*(.text.ide_build_dmatable)
-*(.text.__get_user_8)
-*(.text.end_buffer_read_sync)
-*(.text.__d_path)
-*(.text.d_move)
-*(.text.del_timer)
-*(.text.constant_test_bit)
-*(.text.blockable_page_cache_readahead)
-*(.text.tty_read)
-*(.text.sys_readlink)
-*(.text.sys_faccessat)
-*(.text.read_swap_cache_async)
-*(.text.pty_write_room)
-*(.text.page_address_in_vma)
-*(.text.kthread)
-*(.text.cfq_exit_io_context)
-*(.text.__tcp_push_pending_frames)
-*(.text.sys_pipe)
-*(.text.submit_bio)
-*(.text.pid_revalidate)
-*(.text.page_referenced_file)
-*(.text.lock_sock)
-*(.text.get_page_state_node)
-*(.text.generic_block_bmap)
-*(.text.do_setitimer)
-*(.text.dev_queue_xmit_nit)
-*(.text.copy_from_read_buf)
-*(.text.__const_udelay)
-*(.text.console_conditional_schedule)
-*(.text.wake_up_new_task)
-*(.text.wait_for_completion_interruptible)
-*(.text.tcp_rcv_rtt_update)
-*(.text.sys_mlockall)
-*(.text.set_fs_altroot)
-*(.text.schedule_timeout)
-*(.text.nr_free_pagecache_pages)
-*(.text.nf_iterate)
-*(.text.mapping_tagged)
-*(.text.ip_queue_xmit)
-*(.text.ip_local_deliver)
-*(.text.follow_page)
-*(.text.elf_map)
-*(.text.dummy_file_permission)
-*(.text.dispose_list)
-*(.text.dentry_open)
-*(.text.dentry_iput)
-*(.text.bio_alloc)
-*(.text.wait_on_page_bit)
-*(.text.vfs_readdir)
-*(.text.vfs_lstat)
-*(.text.seq_escape)
-*(.text.__posix_lock_file)
-*(.text.mm_release)
-*(.text.kref_put)
-*(.text.ip_rcv)
-*(.text.__iget)
-*(.text.free_pages)
-*(.text.find_mergeable_anon_vma)
-*(.text.find_extend_vma)
-*(.text.dummy_inode_listsecurity)
-*(.text.bio_add_page)
-*(.text.__vm_enough_memory)
-*(.text.vfs_stat)
-*(.text.tty_paranoia_check)
-*(.text.tcp_read_sock)
-*(.text.tcp_data_queue)
-*(.text.sys_uname)
-*(.text.sys_renameat)
-*(.text.__strncpy_from_user)
-*(.text.__mutex_init)
-*(.text.__lookup_hash)
-*(.text.kref_get)
-*(.text.ip_route_input)
-*(.text.__insert_inode_hash)
-*(.text.do_sock_write)
-*(.text.blk_done_softirq)
-*(.text.__wake_up_sync)
-*(.text.__vma_link_rb)
-*(.text.tty_ioctl)
-*(.text.tracesys)
-*(.text.sys_getdents)
-*(.text.sys_dup)
-*(.text.stub_execve)
-*(.text.sha_transform)
-*(.text.radix_tree_tag_clear)
-*(.text.put_unused_fd)
-*(.text.put_files_struct)
-*(.text.mpage_readpages)
-*(.text.may_delete)
-*(.text.kmem_cache_create)
-*(.text.ip_mc_output)
-*(.text.interleave_nodes)
-*(.text.groups_search)
-*(.text.generic_drop_inode)
-*(.text.generic_commit_write)
-*(.text.fcntl_setlk)
-*(.text.exit_mmap)
-*(.text.end_page_writeback)
-*(.text.__d_rehash)
-*(.text.debug_mutex_free_waiter)
-*(.text.csum_ipv6_magic)
-*(.text.count)
-*(.text.cleanup_rbuf)
-*(.text.check_spinlock_acquired_node)
-*(.text.can_vma_merge_after)
-*(.text.bio_endio)
-*(.text.alloc_pidmap)
-*(.text.write_ldt)
-*(.text.vmtruncate_range)
-*(.text.vfs_create)
-*(.text.__user_walk)
-*(.text.update_send_head)
-*(.text.unmap_underlying_metadata)
-*(.text.tty_ldisc_deref)
-*(.text.tcp_setsockopt)
-*(.text.tcp_send_ack)
-*(.text.sys_pause)
-*(.text.sys_gettimeofday)
-*(.text.sync_dirty_buffer)
-*(.text.strncmp)
-*(.text.release_posix_timer)
-*(.text.proc_file_read)
-*(.text.prepare_to_wait)
-*(.text.locks_mandatory_locked)
-*(.text.interruptible_sleep_on_timeout)
-*(.text.inode_sub_bytes)
-*(.text.in_group_p)
-*(.text.hrtimer_try_to_cancel)
-*(.text.filldir64)
-*(.text.fasync_helper)
-*(.text.dummy_sb_pivotroot)
-*(.text.d_lookup)
-*(.text.d_instantiate)
-*(.text.__d_find_alias)
-*(.text.cpu_idle_wait)
-*(.text.cond_resched_lock)
-*(.text.chown_common)
-*(.text.blk_congestion_wait)
-*(.text.activate_page)
-*(.text.unlock_buffer)
-*(.text.tty_wakeup)
-*(.text.tcp_v4_do_rcv)
-*(.text.tcp_current_mss)
-*(.text.sys_openat)
-*(.text.sys_fchdir)
-*(.text.strnlen_user)
-*(.text.strnlen)
-*(.text.strchr)
-*(.text.sock_common_getsockopt)
-*(.text.skb_checksum)
-*(.text.remove_wait_queue)
-*(.text.rb_replace_node)
-*(.text.radix_tree_node_ctor)
-*(.text.pty_chars_in_buffer)
-*(.text.profile_hit)
-*(.text.prio_tree_left)
-*(.text.pgd_clear_bad)
-*(.text.pfifo_fast_dequeue)
-*(.text.page_referenced)
-*(.text.open_exec)
-*(.text.mmput)
-*(.text.mm_init)
-*(.text.__ide_dma_off_quietly)
-*(.text.ide_dma_intr)
-*(.text.hrtimer_start)
-*(.text.get_io_context)
-*(.text.__get_free_pages)
-*(.text.find_first_zero_bit)
-*(.text.file_free_rcu)
-*(.text.dummy_socket_sendmsg)
-*(.text.do_unlinkat)
-*(.text.do_arch_prctl)
-*(.text.destroy_inode)
-*(.text.can_vma_merge_before)
-*(.text.block_sync_page)
-*(.text.block_prepare_write)
-*(.text.bio_init)
-*(.text.arch_ptrace)
-*(.text.wake_up_inode)
-*(.text.wait_on_retry_sync_kiocb)
-*(.text.vma_prio_tree_next)
-*(.text.tcp_rcv_space_adjust)
-*(.text.__tcp_ack_snd_check)
-*(.text.sys_utime)
-*(.text.sys_recvmsg)
-*(.text.sys_mremap)
-*(.text.sys_bdflush)
-*(.text.sleep_on)
-*(.text.set_page_dirty_lock)
-*(.text.seq_path)
-*(.text.schedule_timeout_interruptible)
-*(.text.sched_fork)
-*(.text.rt_run_flush)
-*(.text.profile_munmap)
-*(.text.prepare_binprm)
-*(.text.__pagevec_release_nonlru)
-*(.text.m_show)
-*(.text.lookup_mnt)
-*(.text.__lookup_mnt)
-*(.text.lock_timer_base)
-*(.text.is_subdir)
-*(.text.invalidate_bh_lru)
-*(.text.init_buffer_head)
-*(.text.ifind_fast)
-*(.text.ide_dma_start)
-*(.text.__get_page_state)
-*(.text.flock_to_posix_lock)
-*(.text.__find_symbol)
-*(.text.do_futex)
-*(.text.do_execve)
-*(.text.dirty_writeback_centisecs_handler)
-*(.text.dev_watchdog)
-*(.text.can_share_swap_page)
-*(.text.blkdev_put)
-*(.text.bio_get_nr_vecs)
-*(.text.xfrm_compile_policy)
-*(.text.vma_prio_tree_insert)
-*(.text.vfs_lstat_fd)
-*(.text.__user_path_lookup_open)
-*(.text.thread_return)
-*(.text.tcp_send_delayed_ack)
-*(.text.sock_def_error_report)
-*(.text.shrink_slab)
-*(.text.serial_out)
-*(.text.seq_read)
-*(.text.secure_ip_id)
-*(.text.search_binary_handler)
-*(.text.proc_pid_unhash)
-*(.text.pagevec_lookup)
-*(.text.new_inode)
-*(.text.memcpy_toiovec)
-*(.text.locks_free_lock)
-*(.text.__lock_page)
-*(.text.__lock_buffer)
-*(.text.load_module)
-*(.text.is_bad_inode)
-*(.text.invalidate_inode_buffers)
-*(.text.insert_vm_struct)
-*(.text.inode_setattr)
-*(.text.inode_add_bytes)
-*(.text.ide_read_24)
-*(.text.ide_get_error_location)
-*(.text.ide_do_drive_cmd)
-*(.text.get_locked_pte)
-*(.text.get_filesystem_list)
-*(.text.generic_file_open)
-*(.text.follow_down)
-*(.text.find_next_bit)
-*(.text.__find_first_bit)
-*(.text.exit_mm)
-*(.text.exec_keys)
-*(.text.end_buffer_write_sync)
-*(.text.end_bio_bh_io_sync)
-*(.text.dummy_socket_shutdown)
-*(.text.d_rehash)
-*(.text.d_path)
-*(.text.do_ioctl)
-*(.text.dget_locked)
-*(.text.copy_thread_group_keys)
-*(.text.cdrom_end_request)
-*(.text.cap_bprm_apply_creds)
-*(.text.blk_rq_bio_prep)
-*(.text.__bitmap_intersects)
-*(.text.bio_phys_segments)
-*(.text.bio_free)
-*(.text.arch_get_unmapped_area_topdown)
-*(.text.writeback_in_progress)
-*(.text.vfs_follow_link)
-*(.text.tcp_rcv_state_process)
-*(.text.tcp_check_space)
-*(.text.sys_stat)
-*(.text.sys_rt_sigreturn)
-*(.text.sys_rt_sigaction)
-*(.text.sys_remap_file_pages)
-*(.text.sys_pwrite64)
-*(.text.sys_fchownat)
-*(.text.sys_fchmodat)
-*(.text.strncat)
-*(.text.strlcat)
-*(.text.strcmp)
-*(.text.steal_locks)
-*(.text.sock_create)
-*(.text.sk_stream_rfree)
-*(.text.sk_stream_mem_schedule)
-*(.text.skip_atoi)
-*(.text.sk_alloc)
-*(.text.show_stat)
-*(.text.set_fs_pwd)
-*(.text.set_binfmt)
-*(.text.pty_unthrottle)
-*(.text.proc_symlink)
-*(.text.pipe_release)
-*(.text.pageout)
-*(.text.n_tty_write_wakeup)
-*(.text.n_tty_ioctl)
-*(.text.nr_free_zone_pages)
-*(.text.migration_thread)
-*(.text.mempool_free_slab)
-*(.text.meminfo_read_proc)
-*(.text.max_sane_readahead)
-*(.text.lru_cache_add)
-*(.text.kill_fasync)
-*(.text.kernel_read)
-*(.text.invalidate_mapping_pages)
-*(.text.inode_has_buffers)
-*(.text.init_once)
-*(.text.inet_sendmsg)
-*(.text.idedisk_issue_flush)
-*(.text.generic_file_write)
-*(.text.free_more_memory)
-*(.text.__free_fdtable)
-*(.text.filp_dtor)
-*(.text.exit_sem)
-*(.text.exit_itimers)
-*(.text.error_interrupt)
-*(.text.end_buffer_async_write)
-*(.text.eligible_child)
-*(.text.elf_map)
-*(.text.dump_task_regs)
-*(.text.dummy_task_setscheduler)
-*(.text.dummy_socket_accept)
-*(.text.dummy_file_free_security)
-*(.text.__down_read)
-*(.text.do_sock_read)
-*(.text.do_sigaltstack)
-*(.text.do_mremap)
-*(.text.current_io_context)
-*(.text.cpu_swap_callback)
-*(.text.copy_vma)
-*(.text.cap_bprm_set_security)
-*(.text.blk_insert_request)
-*(.text.bio_map_kern_endio)
-*(.text.bio_hw_segments)
-*(.text.bictcp_cong_avoid)
-*(.text.add_interrupt_randomness)
-*(.text.wait_for_completion)
-*(.text.version_read_proc)
-*(.text.unix_write_space)
-*(.text.tty_ldisc_ref_wait)
-*(.text.tty_ldisc_put)
-*(.text.try_to_wake_up)
-*(.text.tcp_v4_tw_remember_stamp)
-*(.text.tcp_try_undo_dsack)
-*(.text.tcp_may_send_now)
-*(.text.sys_waitid)
-*(.text.sys_sched_getparam)
-*(.text.sys_getppid)
-*(.text.sys_getcwd)
-*(.text.sys_dup2)
-*(.text.sys_chmod)
-*(.text.sys_chdir)
-*(.text.sprintf)
-*(.text.sock_wfree)
-*(.text.sock_aio_write)
-*(.text.skb_drop_fraglist)
-*(.text.skb_dequeue)
-*(.text.set_close_on_exec)
-*(.text.set_brk)
-*(.text.seq_puts)
-*(.text.SELECT_DRIVE)
-*(.text.sched_exec)
-*(.text.return_EIO)
-*(.text.remove_from_page_cache)
-*(.text.rcu_start_batch)
-*(.text.__put_task_struct)
-*(.text.proc_pid_readdir)
-*(.text.proc_get_inode)
-*(.text.prepare_to_wait_exclusive)
-*(.text.pipe_wait)
-*(.text.pipe_new)
-*(.text.pdflush_operation)
-*(.text.__pagevec_release)
-*(.text.pagevec_lookup_tag)
-*(.text.packet_rcv)
-*(.text.n_tty_set_room)
-*(.text.nr_free_pages)
-*(.text.__net_timestamp)
-*(.text.mpage_end_io_read)
-*(.text.mod_timer)
-*(.text.__memcpy)
-*(.text.mb_cache_shrink_fn)
-*(.text.lock_rename)
-*(.text.kstrdup)
-*(.text.is_ignored)
-*(.text.int_very_careful)
-*(.text.inotify_inode_is_dead)
-*(.text.inotify_get_cookie)
-*(.text.inode_get_bytes)
-*(.text.init_timer)
-*(.text.init_dev)
-*(.text.inet_getname)
-*(.text.ide_map_sg)
-*(.text.__ide_dma_end)
-*(.text.hrtimer_get_remaining)
-*(.text.get_task_mm)
-*(.text.get_random_int)
-*(.text.free_pipe_info)
-*(.text.filemap_write_and_wait_range)
-*(.text.exit_thread)
-*(.text.enter_idle)
-*(.text.end_that_request_first)
-*(.text.end_8259A_irq)
-*(.text.dummy_file_alloc_security)
-*(.text.do_group_exit)
-*(.text.debug_mutex_init)
-*(.text.cpuset_exit)
-*(.text.cpu_idle)
-*(.text.copy_semundo)
-*(.text.copy_files)
-*(.text.chrdev_open)
-*(.text.cdrom_transfer_packet_command)
-*(.text.cdrom_mode_sense)
-*(.text.blk_phys_contig_segment)
-*(.text.blk_get_queue)
-*(.text.bio_split)
-*(.text.audit_alloc)
-*(.text.anon_pipe_buf_release)
-*(.text.add_wait_queue_exclusive)
-*(.text.add_wait_queue)
-*(.text.acct_process)
-*(.text.account)
-*(.text.zeromap_page_range)
-*(.text.yield)
-*(.text.writeback_acquire)
-*(.text.worker_thread)
-*(.text.wait_on_page_writeback_range)
-*(.text.__wait_on_buffer)
-*(.text.vscnprintf)
-*(.text.vmalloc_to_pfn)
-*(.text.vgacon_save_screen)
-*(.text.vfs_unlink)
-*(.text.vfs_rmdir)
-*(.text.unregister_md_personality)
-*(.text.unlock_new_inode)
-*(.text.unix_stream_sendmsg)
-*(.text.unix_stream_recvmsg)
-*(.text.unhash_process)
-*(.text.udp_v4_lookup_longway)
-*(.text.tty_ldisc_flush)
-*(.text.tty_ldisc_enable)
-*(.text.tty_hung_up_p)
-*(.text.tty_buffer_free_all)
-*(.text.tso_fragment)
-*(.text.try_to_del_timer_sync)
-*(.text.tcp_v4_err)
-*(.text.tcp_unhash)
-*(.text.tcp_seq_next)
-*(.text.tcp_select_initial_window)
-*(.text.tcp_sacktag_write_queue)
-*(.text.tcp_cwnd_validate)
-*(.text.sys_vhangup)
-*(.text.sys_uselib)
-*(.text.sys_symlink)
-*(.text.sys_signal)
-*(.text.sys_poll)
-*(.text.sys_mount)
-*(.text.sys_kill)
-*(.text.sys_ioctl)
-*(.text.sys_inotify_add_watch)
-*(.text.sys_getuid)
-*(.text.sys_getrlimit)
-*(.text.sys_getitimer)
-*(.text.sys_getgroups)
-*(.text.sys_ftruncate)
-*(.text.sysfs_lookup)
-*(.text.sys_exit_group)
-*(.text.stub_fork)
-*(.text.sscanf)
-*(.text.sock_map_fd)
-*(.text.sock_get_timestamp)
-*(.text.__sock_create)
-*(.text.smp_call_function_single)
-*(.text.sk_stop_timer)
-*(.text.skb_copy_and_csum_datagram)
-*(.text.__skb_checksum_complete)
-*(.text.single_next)
-*(.text.sigqueue_alloc)
-*(.text.shrink_dcache_parent)
-*(.text.select_idle_routine)
-*(.text.run_workqueue)
-*(.text.run_local_timers)
-*(.text.remove_inode_hash)
-*(.text.remove_dquot_ref)
-*(.text.register_binfmt)
-*(.text.read_cache_pages)
-*(.text.rb_last)
-*(.text.pty_open)
-*(.text.proc_root_readdir)
-*(.text.proc_pid_flush)
-*(.text.proc_pident_lookup)
-*(.text.proc_fill_super)
-*(.text.proc_exe_link)
-*(.text.posix_locks_deadlock)
-*(.text.pipe_iov_copy_from_user)
-*(.text.opost)
-*(.text.nf_register_hook)
-*(.text.netif_rx_ni)
-*(.text.m_start)
-*(.text.mpage_writepage)
-*(.text.mm_alloc)
-*(.text.memory_open)
-*(.text.mark_buffer_async_write)
-*(.text.lru_add_drain_all)
-*(.text.locks_init_lock)
-*(.text.locks_delete_lock)
-*(.text.lock_hrtimer_base)
-*(.text.load_script)
-*(.text.__kill_fasync)
-*(.text.ip_mc_sf_allow)
-*(.text.__ioremap)
-*(.text.int_with_check)
-*(.text.int_sqrt)
-*(.text.install_thread_keyring)
-*(.text.init_page_buffers)
-*(.text.inet_sock_destruct)
-*(.text.idle_notifier_register)
-*(.text.ide_execute_command)
-*(.text.ide_end_drive_cmd)
-*(.text.__ide_dma_host_on)
-*(.text.hrtimer_run_queues)
-*(.text.hpet_mask_rtc_irq_bit)
-*(.text.__get_zone_counts)
-*(.text.get_zone_counts)
-*(.text.get_write_access)
-*(.text.get_fs_struct)
-*(.text.get_dirty_limits)
-*(.text.generic_readlink)
-*(.text.free_hot_page)
-*(.text.finish_wait)
-*(.text.find_inode)
-*(.text.find_first_bit)
-*(.text.__filemap_fdatawrite_range)
-*(.text.__filemap_copy_from_user_iovec)
-*(.text.exit_aio)
-*(.text.elv_set_request)
-*(.text.elv_former_request)
-*(.text.dup_namespace)
-*(.text.dupfd)
-*(.text.dummy_socket_getsockopt)
-*(.text.dummy_sb_post_mountroot)
-*(.text.dummy_quotactl)
-*(.text.dummy_inode_rename)
-*(.text.__do_SAK)
-*(.text.do_pipe)
-*(.text.do_fsync)
-*(.text.d_instantiate_unique)
-*(.text.d_find_alias)
-*(.text.deny_write_access)
-*(.text.dentry_unhash)
-*(.text.d_delete)
-*(.text.datagram_poll)
-*(.text.cpuset_fork)
-*(.text.cpuid_read)
-*(.text.copy_namespace)
-*(.text.cond_resched)
-*(.text.check_version)
-*(.text.__change_page_attr)
-*(.text.cfq_slab_kill)
-*(.text.cfq_completed_request)
-*(.text.cdrom_pc_intr)
-*(.text.cdrom_decode_status)
-*(.text.cap_capset_check)
-*(.text.blk_put_request)
-*(.text.bio_fs_destructor)
-*(.text.bictcp_min_cwnd)
-*(.text.alloc_chrdev_region)
-*(.text.add_element)
-*(.text.acct_update_integrals)
-*(.text.write_boundary_block)
-*(.text.writeback_release)
-*(.text.writeback_inodes)
-*(.text.wake_up_state)
-*(.text.__wake_up_locked)
-*(.text.wake_futex)
-*(.text.wait_task_inactive)
-*(.text.__wait_on_freeing_inode)
-*(.text.wait_noreap_copyout)
-*(.text.vmstat_start)
-*(.text.vgacon_do_font_op)
-*(.text.vfs_readv)
-*(.text.vfs_quota_sync)
-*(.text.update_queue)
-*(.text.unshare_files)
-*(.text.unmap_vm_area)
-*(.text.unix_socketpair)
-*(.text.unix_release_sock)
-*(.text.unix_detach_fds)
-*(.text.unix_create1)
-*(.text.unix_bind)
-*(.text.udp_sendmsg)
-*(.text.udp_rcv)
-*(.text.udp_queue_rcv_skb)
-*(.text.uart_write)
-*(.text.uart_startup)
-*(.text.uart_open)
-*(.text.tty_vhangup)
-*(.text.tty_termios_baud_rate)
-*(.text.tty_release)
-*(.text.tty_ldisc_ref)
-*(.text.throttle_vm_writeout)
-*(.text.058)
-*(.text.tcp_xmit_probe_skb)
-*(.text.tcp_v4_send_check)
-*(.text.tcp_v4_destroy_sock)
-*(.text.tcp_sync_mss)
-*(.text.tcp_snd_test)
-*(.text.tcp_slow_start)
-*(.text.tcp_send_fin)
-*(.text.tcp_rtt_estimator)
-*(.text.tcp_parse_options)
-*(.text.tcp_ioctl)
-*(.text.tcp_init_tso_segs)
-*(.text.tcp_init_cwnd)
-*(.text.tcp_getsockopt)
-*(.text.tcp_fin)
-*(.text.tcp_connect)
-*(.text.tcp_cong_avoid)
-*(.text.__tcp_checksum_complete_user)
-*(.text.task_dumpable)
-*(.text.sys_wait4)
-*(.text.sys_utimes)
-*(.text.sys_symlinkat)
-*(.text.sys_socketpair)
-*(.text.sys_rmdir)
-*(.text.sys_readahead)
-*(.text.sys_nanosleep)
-*(.text.sys_linkat)
-*(.text.sys_fstat)
-*(.text.sysfs_readdir)
-*(.text.sys_execve)
-*(.text.sysenter_tracesys)
-*(.text.sys_chown)
-*(.text.stub_clone)
-*(.text.strrchr)
-*(.text.strncpy)
-*(.text.stopmachine_set_state)
-*(.text.sock_sendmsg)
-*(.text.sock_release)
-*(.text.sock_fasync)
-*(.text.sock_close)
-*(.text.sk_stream_write_space)
-*(.text.sk_reset_timer)
-*(.text.skb_split)
-*(.text.skb_recv_datagram)
-*(.text.skb_queue_tail)
-*(.text.sk_attach_filter)
-*(.text.si_swapinfo)
-*(.text.simple_strtoll)
-*(.text.set_termios)
-*(.text.set_task_comm)
-*(.text.set_shrinker)
-*(.text.set_normalized_timespec)
-*(.text.set_brk)
-*(.text.serial_in)
-*(.text.seq_printf)
-*(.text.secure_dccp_sequence_number)
-*(.text.rwlock_bug)
-*(.text.rt_hash_code)
-*(.text.__rta_fill)
-*(.text.__request_resource)
-*(.text.relocate_new_kernel)
-*(.text.release_thread)
-*(.text.release_mem)
-*(.text.rb_prev)
-*(.text.rb_first)
-*(.text.random_poll)
-*(.text.__put_super_and_need_restart)
-*(.text.pty_write)
-*(.text.ptrace_stop)
-*(.text.proc_self_readlink)
-*(.text.proc_root_lookup)
-*(.text.proc_root_link)
-*(.text.proc_pid_make_inode)
-*(.text.proc_pid_attr_write)
-*(.text.proc_lookupfd)
-*(.text.proc_delete_inode)
-*(.text.posix_same_owner)
-*(.text.posix_block_lock)
-*(.text.poll_initwait)
-*(.text.pipe_write)
-*(.text.pipe_read_fasync)
-*(.text.pipe_ioctl)
-*(.text.pdflush)
-*(.text.pci_user_read_config_dword)
-*(.text.page_readlink)
-*(.text.null_lseek)
-*(.text.nf_hook_slow)
-*(.text.netlink_sock_destruct)
-*(.text.netlink_broadcast)
-*(.text.neigh_resolve_output)
-*(.text.name_to_int)
-*(.text.mwait_idle)
-*(.text.mutex_trylock)
-*(.text.mutex_debug_check_no_locks_held)
-*(.text.m_stop)
-*(.text.mpage_end_io_write)
-*(.text.mpage_alloc)
-*(.text.move_page_tables)
-*(.text.mounts_open)
-*(.text.__memset)
-*(.text.memcpy_fromiovec)
-*(.text.make_8259A_irq)
-*(.text.lookup_user_key_possessed)
-*(.text.lookup_create)
-*(.text.locks_insert_lock)
-*(.text.locks_alloc_lock)
-*(.text.kthread_should_stop)
-*(.text.kswapd)
-*(.text.kobject_uevent)
-*(.text.kobject_get_path)
-*(.text.kobject_get)
-*(.text.klist_children_put)
-*(.text.__ip_route_output_key)
-*(.text.ip_flush_pending_frames)
-*(.text.ip_compute_csum)
-*(.text.ip_append_data)
-*(.text.ioc_set_batching)
-*(.text.invalidate_inode_pages)
-*(.text.__invalidate_device)
-*(.text.install_arg_page)
-*(.text.in_sched_functions)
-*(.text.inotify_unmount_inodes)
-*(.text.init_once)
-*(.text.init_cdrom_command)
-*(.text.inet_stream_connect)
-*(.text.inet_sk_rebuild_header)
-*(.text.inet_csk_addr2sockaddr)
-*(.text.inet_create)
-*(.text.ifind)
-*(.text.ide_setup_dma)
-*(.text.ide_outsw)
-*(.text.ide_fixstring)
-*(.text.ide_dma_setup)
-*(.text.ide_cdrom_packet)
-*(.text.ide_cd_put)
-*(.text.ide_build_sglist)
-*(.text.i8259A_shutdown)
-*(.text.hung_up_tty_ioctl)
-*(.text.hrtimer_nanosleep)
-*(.text.hrtimer_init)
-*(.text.hrtimer_cancel)
-*(.text.hash_futex)
-*(.text.group_send_sig_info)
-*(.text.grab_cache_page_nowait)
-*(.text.get_wchan)
-*(.text.get_stack)
-*(.text.get_page_state)
-*(.text.getnstimeofday)
-*(.text.get_node)
-*(.text.get_kprobe)
-*(.text.generic_unplug_device)
-*(.text.free_task)
-*(.text.frag_show)
-*(.text.find_next_zero_string)
-*(.text.filp_open)
-*(.text.fillonedir)
-*(.text.exit_io_context)
-*(.text.exit_idle)
-*(.text.exact_lock)
-*(.text.eth_header)
-*(.text.dummy_unregister_security)
-*(.text.dummy_socket_post_create)
-*(.text.dummy_socket_listen)
-*(.text.dummy_quota_on)
-*(.text.dummy_inode_follow_link)
-*(.text.dummy_file_receive)
-*(.text.dummy_file_mprotect)
-*(.text.dummy_file_lock)
-*(.text.dummy_file_ioctl)
-*(.text.dummy_bprm_post_apply_creds)
-*(.text.do_writepages)
-*(.text.__down_interruptible)
-*(.text.do_notify_resume)
-*(.text.do_acct_process)
-*(.text.del_timer_sync)
-*(.text.default_rebuild_header)
-*(.text.d_callback)
-*(.text.dcache_readdir)
-*(.text.ctrl_dumpfamily)
-*(.text.cpuset_rmdir)
-*(.text.copy_strings_kernel)
-*(.text.con_write_room)
-*(.text.complete_all)
-*(.text.collect_sigign_sigcatch)
-*(.text.clear_user)
-*(.text.check_unthrottle)
-*(.text.cdrom_release)
-*(.text.cdrom_newpc_intr)
-*(.text.cdrom_ioctl)
-*(.text.cdrom_check_status)
-*(.text.cdev_put)
-*(.text.cdev_add)
-*(.text.cap_ptrace)
-*(.text.cap_bprm_secureexec)
-*(.text.cache_alloc_refill)
-*(.text.bmap)
-*(.text.blk_run_queue)
-*(.text.blk_queue_dma_alignment)
-*(.text.blk_ordered_req_seq)
-*(.text.blk_backing_dev_unplug)
-*(.text.__bitmap_subset)
-*(.text.__bitmap_and)
-*(.text.bio_unmap_user)
-*(.text.__bforget)
-*(.text.bd_forget)
-*(.text.bad_pipe_w)
-*(.text.bad_get_user)
-*(.text.audit_free)
-*(.text.anon_vma_ctor)
-*(.text.anon_pipe_buf_map)
-*(.text.alloc_sock_iocb)
-*(.text.alloc_fdset)
-*(.text.aio_kick_handler)
-*(.text.__add_entropy_words)
-*(.text.add_disk_randomness)
diff --git a/arch/x86_64/kernel/genapic.c b/arch/x86_64/kernel/genapic.c
index 0b3603adf56..47496a40e84 100644
--- a/arch/x86_64/kernel/genapic.c
+++ b/arch/x86_64/kernel/genapic.c
@@ -11,120 +11,54 @@
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/string.h>
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/init.h>
-#include <linux/module.h>
#include <asm/smp.h>
#include <asm/ipi.h>
+#include <asm/genapic.h>
-#if defined(CONFIG_ACPI)
+#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
/* which logical CPU number maps to which CPU (physical APIC ID) */
-u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly
+ = { [0 ... NR_CPUS-1] = BAD_APICID };
EXPORT_SYMBOL(x86_cpu_to_apicid);
-u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
-extern struct genapic apic_cluster;
-extern struct genapic apic_flat;
-extern struct genapic apic_physflat;
+u8 x86_cpu_to_log_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
-struct genapic *genapic = &apic_flat;
-struct genapic *genapic_force;
+struct genapic __read_mostly *genapic = &apic_flat;
/*
* Check the APIC IDs in bios_cpu_apicid and choose the APIC mode.
*/
-void __init clustered_apic_check(void)
+void __init setup_apic_routing(void)
{
- long i;
- u8 clusters, max_cluster;
- u8 id;
- u8 cluster_cnt[NUM_APIC_CLUSTERS];
- int max_apic = 0;
-
- /* genapic selection can be forced because of certain quirks.
- */
- if (genapic_force) {
- genapic = genapic_force;
- goto print;
- }
-
-#if defined(CONFIG_ACPI)
+#ifdef CONFIG_ACPI
/*
- * Some x86_64 machines use physical APIC mode regardless of how many
- * procs/clusters are present (x86_64 ES7000 is an example).
+ * Quirk: some x86_64 machines can only use physical APIC mode
+ * regardless of how many processors are present (x86_64 ES7000
+ * is an example).
*/
- if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID)
- if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) {
- genapic = &apic_cluster;
- goto print;
- }
-#endif
-
- memset(cluster_cnt, 0, sizeof(cluster_cnt));
- for (i = 0; i < NR_CPUS; i++) {
- id = bios_cpu_apicid[i];
- if (id == BAD_APICID)
- continue;
- if (id > max_apic)
- max_apic = id;
- cluster_cnt[APIC_CLUSTERID(id)]++;
- }
-
- /* Don't use clustered mode on AMD platforms. */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
+ if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID &&
+ (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL))
genapic = &apic_physflat;
-#ifndef CONFIG_HOTPLUG_CPU
- /* In the CPU hotplug case we cannot use broadcast mode
- because that opens a race when a CPU is removed.
- Stay at physflat mode in this case.
- It is bad to do this unconditionally though. Once
- we have ACPI platform support for CPU hotplug
- we should detect hotplug capablity from ACPI tables and
- only do this when really needed. -AK */
- if (max_apic <= 8)
- genapic = &apic_flat;
+ else
#endif
- goto print;
- }
- clusters = 0;
- max_cluster = 0;
-
- for (i = 0; i < NUM_APIC_CLUSTERS; i++) {
- if (cluster_cnt[i] > 0) {
- ++clusters;
- if (cluster_cnt[i] > max_cluster)
- max_cluster = cluster_cnt[i];
- }
- }
-
- /*
- * If we have clusters <= 1 and CPUs <= 8 in cluster 0, then flat mode,
- * else if max_cluster <= 4 and cluster_cnt[15] == 0, clustered logical
- * else physical mode.
- * (We don't use lowest priority delivery + HW APIC IRQ steering, so
- * can ignore the clustered logical case and go straight to physical.)
- */
- if (clusters <= 1 && max_cluster <= 8 && cluster_cnt[0] == max_cluster) {
-#ifdef CONFIG_HOTPLUG_CPU
- /* Don't use APIC shortcuts in CPU hotplug to avoid races */
- genapic = &apic_physflat;
-#else
+ if (cpus_weight(cpu_possible_map) <= 8)
genapic = &apic_flat;
-#endif
- } else
- genapic = &apic_cluster;
+ else
+ genapic = &apic_physflat;
-print:
printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
}
-/* Same for both flat and clustered. */
+/* Same for both flat and physical. */
void send_IPI_self(int vector)
{
diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c
deleted file mode 100644
index 73d76308b95..00000000000
--- a/arch/x86_64/kernel/genapic_cluster.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2004 James Cleverdon, IBM.
- * Subject to the GNU Public License, v.2
- *
- * Clustered APIC subarch code. Up to 255 CPUs, physical delivery.
- * (A more realistic maximum is around 230 CPUs.)
- *
- * Hacked for x86-64 by James Cleverdon from i386 architecture code by
- * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
- * James Cleverdon.
- */
-#include <linux/threads.h>
-#include <linux/cpumask.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/ctype.h>
-#include <linux/init.h>
-#include <asm/smp.h>
-#include <asm/ipi.h>
-
-
-/*
- * Set up the logical destination ID.
- *
- * Intel recommends to set DFR, LDR and TPR before enabling
- * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
- * document number 292116). So here it goes...
- */
-static void cluster_init_apic_ldr(void)
-{
- unsigned long val, id;
- long i, count;
- u8 lid;
- u8 my_id = hard_smp_processor_id();
- u8 my_cluster = APIC_CLUSTER(my_id);
-
- /* Create logical APIC IDs by counting CPUs already in cluster. */
- for (count = 0, i = NR_CPUS; --i >= 0; ) {
- lid = x86_cpu_to_log_apicid[i];
- if (lid != BAD_APICID && APIC_CLUSTER(lid) == my_cluster)
- ++count;
- }
- /*
- * We only have a 4 wide bitmap in cluster mode. There's no way
- * to get above 60 CPUs and still give each one it's own bit.
- * But, we're using physical IRQ delivery, so we don't care.
- * Use bit 3 for the 4th through Nth CPU in each cluster.
- */
- if (count >= XAPIC_DEST_CPUS_SHIFT)
- count = 3;
- id = my_cluster | (1UL << count);
- x86_cpu_to_log_apicid[smp_processor_id()] = id;
- apic_write(APIC_DFR, APIC_DFR_CLUSTER);
- val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
- val |= SET_APIC_LOGICAL_ID(id);
- apic_write(APIC_LDR, val);
-}
-
-/* Start with all IRQs pointing to boot CPU. IRQ balancing will shift them. */
-
-static cpumask_t cluster_target_cpus(void)
-{
- return cpumask_of_cpu(0);
-}
-
-static cpumask_t cluster_vector_allocation_domain(int cpu)
-{
- cpumask_t domain = CPU_MASK_NONE;
- cpu_set(cpu, domain);
- return domain;
-}
-
-static void cluster_send_IPI_mask(cpumask_t mask, int vector)
-{
- send_IPI_mask_sequence(mask, vector);
-}
-
-static void cluster_send_IPI_allbutself(int vector)
-{
- cpumask_t mask = cpu_online_map;
-
- cpu_clear(smp_processor_id(), mask);
-
- if (!cpus_empty(mask))
- cluster_send_IPI_mask(mask, vector);
-}
-
-static void cluster_send_IPI_all(int vector)
-{
- cluster_send_IPI_mask(cpu_online_map, vector);
-}
-
-static int cluster_apic_id_registered(void)
-{
- return 1;
-}
-
-static unsigned int cluster_cpu_mask_to_apicid(cpumask_t cpumask)
-{
- int cpu;
-
- /*
- * We're using fixed IRQ delivery, can only return one phys APIC ID.
- * May as well be the first.
- */
- cpu = first_cpu(cpumask);
- if ((unsigned)cpu < NR_CPUS)
- return x86_cpu_to_apicid[cpu];
- else
- return BAD_APICID;
-}
-
-/* cpuid returns the value latched in the HW at reset, not the APIC ID
- * register's value. For any box whose BIOS changes APIC IDs, like
- * clustered APIC systems, we must use hard_smp_processor_id.
- *
- * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
- */
-static unsigned int phys_pkg_id(int index_msb)
-{
- return hard_smp_processor_id() >> index_msb;
-}
-
-struct genapic apic_cluster = {
- .name = "clustered",
- .int_delivery_mode = dest_Fixed,
- .int_dest_mode = (APIC_DEST_PHYSICAL != 0),
- .target_cpus = cluster_target_cpus,
- .vector_allocation_domain = cluster_vector_allocation_domain,
- .apic_id_registered = cluster_apic_id_registered,
- .init_apic_ldr = cluster_init_apic_ldr,
- .send_IPI_all = cluster_send_IPI_all,
- .send_IPI_allbutself = cluster_send_IPI_allbutself,
- .send_IPI_mask = cluster_send_IPI_mask,
- .cpu_mask_to_apicid = cluster_cpu_mask_to_apicid,
- .phys_pkg_id = phys_pkg_id,
-};
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
index 7c01db8fa9d..ecb01eefdd2 100644
--- a/arch/x86_64/kernel/genapic_flat.c
+++ b/arch/x86_64/kernel/genapic_flat.c
@@ -8,6 +8,7 @@
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
* James Cleverdon.
*/
+#include <linux/errno.h>
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/string.h>
@@ -16,6 +17,7 @@
#include <linux/init.h>
#include <asm/smp.h>
#include <asm/ipi.h>
+#include <asm/genapic.h>
static cpumask_t flat_target_cpus(void)
{
@@ -60,31 +62,10 @@ static void flat_init_apic_ldr(void)
static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
{
unsigned long mask = cpus_addr(cpumask)[0];
- unsigned long cfg;
unsigned long flags;
local_irq_save(flags);
-
- /*
- * Wait for idle.
- */
- apic_wait_icr_idle();
-
- /*
- * prepare target chip field
- */
- cfg = __prepare_ICR2(mask);
- apic_write(APIC_ICR2, cfg);
-
- /*
- * program the ICR
- */
- cfg = __prepare_ICR(0, vector, APIC_DEST_LOGICAL);
-
- /*
- * Send the IPI. The write to APIC_ICR fires this off.
- */
- apic_write(APIC_ICR, cfg);
+ __send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
local_irq_restore(flags);
}
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 598a4d0351f..1fab487dee8 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -5,6 +5,7 @@
* Copyright (C) 2000 Pavel Machek <pavel@suse.cz>
* Copyright (C) 2000 Karsten Keil <kkeil@suse.de>
* Copyright (C) 2001,2002 Andi Kleen <ak@suse.de>
+ * Copyright (C) 2005 Eric Biederman <ebiederm@xmission.com>
*/
@@ -13,97 +14,131 @@
#include <linux/init.h>
#include <asm/desc.h>
#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/page.h>
#include <asm/msr.h>
#include <asm/cache.h>
-
+
/* we are not able to switch in one step to the final KERNEL ADRESS SPACE
- * because we need identity-mapped pages on setup so define __START_KERNEL to
- * 0x100000 for this stage
- *
+ * because we need identity-mapped pages.
+ *
*/
.text
.section .bootstrap.text
- .code32
- .globl startup_32
-/* %bx: 1 if coming from smp trampoline on secondary cpu */
-startup_32:
-
+ .code64
+ .globl startup_64
+startup_64:
+
/*
- * At this point the CPU runs in 32bit protected mode (CS.D = 1) with
- * paging disabled and the point of this file is to switch to 64bit
- * long mode with a kernel mapping for kerneland to jump into the
- * kernel virtual addresses.
- * There is no stack until we set one up.
+ * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
+ * and someone has loaded an identity mapped page table
+ * for us. These identity mapped page tables map all of the
+ * kernel pages and possibly all of memory.
+ *
+ * %esi holds a physical pointer to real_mode_data.
+ *
+ * We come here either directly from a 64bit bootloader, or from
+ * arch/x86_64/boot/compressed/head.S.
+ *
+ * We only come here initially at boot nothing else comes here.
+ *
+ * Since we may be loaded at an address different from what we were
+ * compiled to run at we first fixup the physical addresses in our page
+ * tables and then reload them.
*/
- /* Initialize the %ds segment register */
- movl $__KERNEL_DS,%eax
- movl %eax,%ds
-
- /* Load new GDT with the 64bit segments using 32bit descriptor */
- lgdt pGDT32 - __START_KERNEL_map
-
- /* If the CPU doesn't support CPUID this will double fault.
- * Unfortunately it is hard to check for CPUID without a stack.
+ /* Compute the delta between the address I am compiled to run at and the
+ * address I am actually running at.
*/
-
- /* Check if extended functions are implemented */
- movl $0x80000000, %eax
- cpuid
- cmpl $0x80000000, %eax
- jbe no_long_mode
- /* Check if long mode is implemented */
- mov $0x80000001, %eax
- cpuid
- btl $29, %edx
- jnc no_long_mode
-
- /*
- * Prepare for entering 64bits mode
+ leaq _text(%rip), %rbp
+ subq $_text - __START_KERNEL_map, %rbp
+
+ /* Is the address not 2M aligned? */
+ movq %rbp, %rax
+ andl $~LARGE_PAGE_MASK, %eax
+ testl %eax, %eax
+ jnz bad_address
+
+ /* Is the address too large? */
+ leaq _text(%rip), %rdx
+ movq $PGDIR_SIZE, %rax
+ cmpq %rax, %rdx
+ jae bad_address
+
+ /* Fixup the physical addresses in the page table
*/
+ addq %rbp, init_level4_pgt + 0(%rip)
+ addq %rbp, init_level4_pgt + (258*8)(%rip)
+ addq %rbp, init_level4_pgt + (511*8)(%rip)
+
+ addq %rbp, level3_ident_pgt + 0(%rip)
+ addq %rbp, level3_kernel_pgt + (510*8)(%rip)
+
+ /* Add an Identity mapping if I am above 1G */
+ leaq _text(%rip), %rdi
+ andq $LARGE_PAGE_MASK, %rdi
+
+ movq %rdi, %rax
+ shrq $PUD_SHIFT, %rax
+ andq $(PTRS_PER_PUD - 1), %rax
+ jz ident_complete
+
+ leaq (level2_spare_pgt - __START_KERNEL_map + _KERNPG_TABLE)(%rbp), %rdx
+ leaq level3_ident_pgt(%rip), %rbx
+ movq %rdx, 0(%rbx, %rax, 8)
+
+ movq %rdi, %rax
+ shrq $PMD_SHIFT, %rax
+ andq $(PTRS_PER_PMD - 1), %rax
+ leaq __PAGE_KERNEL_LARGE_EXEC(%rdi), %rdx
+ leaq level2_spare_pgt(%rip), %rbx
+ movq %rdx, 0(%rbx, %rax, 8)
+ident_complete:
+
+ /* Fixup the kernel text+data virtual addresses
+ */
+ leaq level2_kernel_pgt(%rip), %rdi
+ leaq 4096(%rdi), %r8
+ /* See if it is a valid page table entry */
+1: testq $1, 0(%rdi)
+ jz 2f
+ addq %rbp, 0(%rdi)
+ /* Go to the next page */
+2: addq $8, %rdi
+ cmp %r8, %rdi
+ jne 1b
+
+ /* Fixup phys_base */
+ addq %rbp, phys_base(%rip)
- /* Enable PAE mode */
- xorl %eax, %eax
- btsl $5, %eax
- movl %eax, %cr4
-
- /* Setup early boot stage 4 level pagetables */
- movl $(boot_level4_pgt - __START_KERNEL_map), %eax
- movl %eax, %cr3
-
- /* Setup EFER (Extended Feature Enable Register) */
- movl $MSR_EFER, %ecx
- rdmsr
-
- /* Enable Long Mode */
- btsl $_EFER_LME, %eax
-
- /* Make changes effective */
- wrmsr
+#ifdef CONFIG_SMP
+ addq %rbp, trampoline_level4_pgt + 0(%rip)
+ addq %rbp, trampoline_level4_pgt + (511*8)(%rip)
+#endif
+#ifdef CONFIG_ACPI_SLEEP
+ addq %rbp, wakeup_level4_pgt + 0(%rip)
+ addq %rbp, wakeup_level4_pgt + (511*8)(%rip)
+#endif
- xorl %eax, %eax
- btsl $31, %eax /* Enable paging and in turn activate Long Mode */
- btsl $0, %eax /* Enable protected mode */
- /* Make changes effective */
- movl %eax, %cr0
- /*
- * At this point we're in long mode but in 32bit compatibility mode
- * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
- * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
- * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+ /* Due to ENTRY(), sometimes the empty space gets filled with
+ * zeros. Better take a jmp than relying on empty space being
+ * filled with 0x90 (nop)
*/
- ljmp $__KERNEL_CS, $(startup_64 - __START_KERNEL_map)
-
- .code64
- .org 0x100
- .globl startup_64
-startup_64:
- /* We come here either from startup_32
- * or directly from a 64bit bootloader.
- * Since we may have come directly from a bootloader we
- * reload the page tables here.
+ jmp secondary_startup_64
+ENTRY(secondary_startup_64)
+ /*
+ * At this point the CPU runs in 64bit mode CS.L = 1 CS.D = 1,
+ * and someone has loaded a mapped page table.
+ *
+ * %esi holds a physical pointer to real_mode_data.
+ *
+ * We come here either from startup_64 (using physical addresses)
+ * or from trampoline.S (using virtual addresses).
+ *
+ * Using virtual addresses from trampoline.S removes the need
+ * to have any identity mapped pages in the kernel page table
+ * after the boot processor executes this code.
*/
/* Enable PAE mode and PGE */
@@ -113,9 +148,15 @@ startup_64:
movq %rax, %cr4
/* Setup early boot stage 4 level pagetables. */
- movq $(boot_level4_pgt - __START_KERNEL_map), %rax
+ movq $(init_level4_pgt - __START_KERNEL_map), %rax
+ addq phys_base(%rip), %rax
movq %rax, %cr3
+ /* Ensure I am executing from virtual addresses */
+ movq $1f, %rax
+ jmp *%rax
+1:
+
/* Check if nx is implemented */
movl $0x80000001, %eax
cpuid
@@ -124,17 +165,11 @@ startup_64:
/* Setup EFER (Extended Feature Enable Register) */
movl $MSR_EFER, %ecx
rdmsr
-
- /* Enable System Call */
- btsl $_EFER_SCE, %eax
-
- /* No Execute supported? */
- btl $20,%edi
+ btsl $_EFER_SCE, %eax /* Enable System Call */
+ btl $20,%edi /* No Execute supported? */
jnc 1f
btsl $_EFER_NX, %eax
-1:
- /* Make changes effective */
- wrmsr
+1: wrmsr /* Make changes effective */
/* Setup cr0 */
#define CR0_PM 1 /* protected mode */
@@ -161,7 +196,7 @@ startup_64:
* addresses where we're currently running on. We have to do that here
* because in 32bit we couldn't load a 64bit linear address.
*/
- lgdt cpu_gdt_descr
+ lgdt cpu_gdt_descr(%rip)
/* set up data segments. actually 0 would do too */
movl $__KERNEL_DS,%eax
@@ -212,6 +247,9 @@ initial_code:
init_rsp:
.quad init_thread_union+THREAD_SIZE-8
+bad_address:
+ jmp bad_address
+
ENTRY(early_idt_handler)
cmpl $2,early_recursion_flag(%rip)
jz 1f
@@ -240,110 +278,66 @@ early_idt_msg:
early_idt_ripmsg:
.asciz "RIP %s\n"
-.code32
-ENTRY(no_long_mode)
- /* This isn't an x86-64 CPU so hang */
-1:
- jmp 1b
-
-.org 0xf00
- .globl pGDT32
-pGDT32:
- .word gdt_end-cpu_gdt_table-1
- .long cpu_gdt_table-__START_KERNEL_map
-
-.org 0xf10
-ljumpvector:
- .long startup_64-__START_KERNEL_map
- .word __KERNEL_CS
+.balign PAGE_SIZE
-ENTRY(stext)
-ENTRY(_stext)
-
- $page = 0
#define NEXT_PAGE(name) \
- $page = $page + 1; \
- .org $page * 0x1000; \
- phys_/**/name = $page * 0x1000 + __PHYSICAL_START; \
+ .balign PAGE_SIZE; \
ENTRY(name)
+/* Automate the creation of 1 to 1 mapping pmd entries */
+#define PMDS(START, PERM, COUNT) \
+ i = 0 ; \
+ .rept (COUNT) ; \
+ .quad (START) + (i << 21) + (PERM) ; \
+ i = i + 1 ; \
+ .endr
+
+ /*
+ * This default setting generates an ident mapping at address 0x100000
+ * and a mapping for the kernel that precisely maps virtual address
+ * 0xffffffff80000000 to physical address 0x000000. (always using
+ * 2Mbyte large pages provided by PAE mode)
+ */
NEXT_PAGE(init_level4_pgt)
- /* This gets initialized in x86_64_start_kernel */
- .fill 512,8,0
+ .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ .fill 257,8,0
+ .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ .fill 252,8,0
+ /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
+ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE
NEXT_PAGE(level3_ident_pgt)
- .quad phys_level2_ident_pgt | 0x007
+ .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
.fill 511,8,0
NEXT_PAGE(level3_kernel_pgt)
.fill 510,8,0
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
- .quad phys_level2_kernel_pgt | 0x007
+ .quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
.fill 1,8,0
NEXT_PAGE(level2_ident_pgt)
- /* 40MB for bootup. */
- i = 0
- .rept 20
- .quad i << 21 | 0x083
- i = i + 1
- .endr
- /* Temporary mappings for the super early allocator in arch/x86_64/mm/init.c */
- .globl temp_boot_pmds
-temp_boot_pmds:
- .fill 492,8,0
-
+ /* Since I easily can, map the first 1G.
+ * Don't set NX because code runs from these pages.
+ */
+ PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC, PTRS_PER_PMD)
+
NEXT_PAGE(level2_kernel_pgt)
/* 40MB kernel mapping. The kernel code cannot be bigger than that.
When you change this change KERNEL_TEXT_SIZE in page.h too. */
/* (2^48-(2*1024*1024*1024)-((2^39)*511)-((2^30)*510)) = 0 */
- i = 0
- .rept 20
- .quad i << 21 | 0x183
- i = i + 1
- .endr
+ PMDS(0x0000000000000000, __PAGE_KERNEL_LARGE_EXEC|_PAGE_GLOBAL,
+ KERNEL_TEXT_SIZE/PMD_SIZE)
/* Module mapping starts here */
- .fill 492,8,0
+ .fill (PTRS_PER_PMD - (KERNEL_TEXT_SIZE/PMD_SIZE)),8,0
-NEXT_PAGE(level3_physmem_pgt)
- .quad phys_level2_kernel_pgt | 0x007 /* so that __va works even before pagetable_init */
- .fill 511,8,0
+NEXT_PAGE(level2_spare_pgt)
+ .fill 512,8,0
+#undef PMDS
#undef NEXT_PAGE
.data
-
-#ifdef CONFIG_ACPI_SLEEP
- .align PAGE_SIZE
-ENTRY(wakeup_level4_pgt)
- .quad phys_level3_ident_pgt | 0x007
- .fill 255,8,0
- .quad phys_level3_physmem_pgt | 0x007
- .fill 254,8,0
- /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad phys_level3_kernel_pgt | 0x007
-#endif
-
-#ifndef CONFIG_HOTPLUG_CPU
- __INITDATA
-#endif
- /*
- * This default setting generates an ident mapping at address 0x100000
- * and a mapping for the kernel that precisely maps virtual address
- * 0xffffffff80000000 to physical address 0x000000. (always using
- * 2Mbyte large pages provided by PAE mode)
- */
- .align PAGE_SIZE
-ENTRY(boot_level4_pgt)
- .quad phys_level3_ident_pgt | 0x007
- .fill 255,8,0
- .quad phys_level3_physmem_pgt | 0x007
- .fill 254,8,0
- /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad phys_level3_kernel_pgt | 0x007
-
- .data
-
.align 16
.globl cpu_gdt_descr
cpu_gdt_descr:
@@ -357,6 +351,10 @@ gdt:
.endr
#endif
+ENTRY(phys_base)
+ /* This must match the first entry in level2_kernel_pgt */
+ .quad 0x0000000000000000
+
/* We need valid kernel segments for data and code in long mode too
* IRET will check the segment types kkeil 2000/10/28
* Also sysret mandates a special GDT layout
@@ -370,13 +368,13 @@ gdt:
ENTRY(cpu_gdt_table)
.quad 0x0000000000000000 /* NULL descriptor */
+ .quad 0x00cf9b000000ffff /* __KERNEL32_CS */
+ .quad 0x00af9b000000ffff /* __KERNEL_CS */
+ .quad 0x00cf93000000ffff /* __KERNEL_DS */
+ .quad 0x00cffb000000ffff /* __USER32_CS */
+ .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */
+ .quad 0x00affb000000ffff /* __USER_CS */
.quad 0x0 /* unused */
- .quad 0x00af9a000000ffff /* __KERNEL_CS */
- .quad 0x00cf92000000ffff /* __KERNEL_DS */
- .quad 0x00cffa000000ffff /* __USER32_CS */
- .quad 0x00cff2000000ffff /* __USER_DS, __USER32_DS */
- .quad 0x00affa000000ffff /* __USER_CS */
- .quad 0x00cf9a000000ffff /* __KERNEL32_CS */
.quad 0,0 /* TSS */
.quad 0,0 /* LDT */
.quad 0,0,0 /* three TLS descriptors */
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
index 5f197b0a330..213d90e0475 100644
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -18,8 +18,16 @@
#include <asm/setup.h>
#include <asm/desc.h>
#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
#include <asm/sections.h>
+static void __init zap_identity_mappings(void)
+{
+ pgd_t *pgd = pgd_offset_k(0UL);
+ pgd_clear(pgd);
+ __flush_tlb();
+}
+
/* Don't add a printk in there. printk relies on the PDA which is not initialized
yet. */
static void __init clear_bss(void)
@@ -29,25 +37,24 @@ static void __init clear_bss(void)
}
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
-#define OLD_CL_MAGIC_ADDR 0x90020
+#define OLD_CL_MAGIC_ADDR 0x20
#define OLD_CL_MAGIC 0xA33F
-#define OLD_CL_BASE_ADDR 0x90000
-#define OLD_CL_OFFSET 0x90022
+#define OLD_CL_OFFSET 0x22
static void __init copy_bootdata(char *real_mode_data)
{
- int new_data;
+ unsigned long new_data;
char * command_line;
memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE);
- new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
+ new_data = *(u32 *) (x86_boot_params + NEW_CL_POINTER);
if (!new_data) {
- if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
+ if (OLD_CL_MAGIC != *(u16 *)(real_mode_data + OLD_CL_MAGIC_ADDR)) {
return;
}
- new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
+ new_data = __pa(real_mode_data) + *(u16 *)(real_mode_data + OLD_CL_OFFSET);
}
- command_line = (char *) ((u64)(new_data));
+ command_line = __va(new_data);
memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
}
@@ -55,26 +62,30 @@ void __init x86_64_start_kernel(char * real_mode_data)
{
int i;
+ /*
+ * Make sure kernel is aligned to 2MB address. Catching it at compile
+ * time is better. Change your config file and compile the kernel
+ * for a 2MB aligned address (CONFIG_PHYSICAL_START)
+ */
+ BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1));
+
/* clear bss before set_intr_gate with early_idt_handler */
clear_bss();
+ /* Make NULL pointers segfault */
+ zap_identity_mappings();
+
for (i = 0; i < IDT_ENTRIES; i++)
set_intr_gate(i, early_idt_handler);
asm volatile("lidt %0" :: "m" (idt_descr));
early_printk("Kernel alive\n");
- /*
- * switch to init_level4_pgt from boot_level4_pgt
- */
- memcpy(init_level4_pgt, boot_level4_pgt, PTRS_PER_PGD*sizeof(pgd_t));
- asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
-
for (i = 0; i < NR_CPUS; i++)
cpu_pda(i) = &boot_cpu_pda[i];
pda_init(0);
- copy_bootdata(real_mode_data);
+ copy_bootdata(__va(real_mode_data));
#ifdef CONFIG_SMP
cpu_set(0, cpu_online_map);
#endif
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 48942668277..4b326655b20 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -7,7 +7,6 @@
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/sysdev.h>
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index c6a5bc7e811..d8bfe315471 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/mc146818rtc.h>
#include <linux/acpi.h>
@@ -907,10 +906,6 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
enable_8259A_irq(0);
}
-void __init UNEXPECTED_IO_APIC(void)
-{
-}
-
void __apicdebuginit print_IO_APIC(void)
{
int apic, i;
@@ -946,40 +941,16 @@ void __apicdebuginit print_IO_APIC(void)
printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
- if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries);
- if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */
- (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */
- (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */
- (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */
- (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */
- (reg_01.bits.entries != 0x2E) &&
- (reg_01.bits.entries != 0x3F) &&
- (reg_01.bits.entries != 0x03)
- )
- UNEXPECTED_IO_APIC();
printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version);
- if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */
- (reg_01.bits.version != 0x02) && /* 82801BA IO-APICs (ICH2) */
- (reg_01.bits.version != 0x10) && /* oldest IO-APICs */
- (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */
- (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */
- (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */
- )
- UNEXPECTED_IO_APIC();
- if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
if (reg_01.bits.version >= 0x10) {
printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw);
printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration);
- if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2)
- UNEXPECTED_IO_APIC();
}
printk(KERN_DEBUG ".... IRQ redirection table:\n");
@@ -1407,8 +1378,7 @@ static void irq_complete_move(unsigned int irq)
vector = ~get_irq_regs()->orig_rax;
me = smp_processor_id();
- if ((vector == cfg->vector) &&
- cpu_isset(smp_processor_id(), cfg->domain)) {
+ if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
cpumask_t cleanup_mask;
cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
@@ -1443,7 +1413,7 @@ static void ack_apic_level(unsigned int irq)
/*
* We must acknowledge the irq before we move it or the acknowledge will
- * not propogate properly.
+ * not propagate properly.
*/
ack_APIC_irq();
@@ -1983,18 +1953,18 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
if (irq < 0)
return irq;
- set_irq_msi(irq, desc);
ret = msi_compose_msg(dev, irq, &msg);
if (ret < 0) {
destroy_irq(irq);
return ret;
}
+ set_irq_msi(irq, desc);
write_msi_msg(irq, &msg);
set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
- return irq;
+ return 0;
}
void arch_teardown_msi_irq(unsigned int irq)
diff --git a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c
index 745b1f0f494..653efa30b0f 100644
--- a/arch/x86_64/kernel/ioport.c
+++ b/arch/x86_64/kernel/ioport.c
@@ -12,10 +12,10 @@
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/thread_info.h>
+#include <linux/syscalls.h>
/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */
static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value)
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index 3bc30d2c13d..3eaceac3248 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -32,7 +32,7 @@ atomic_t irq_err_count;
*/
static inline void stack_overflow_check(struct pt_regs *regs)
{
- u64 curbase = (u64) current->thread_info;
+ u64 curbase = (u64)task_stack_page(current);
static unsigned long warned = -60*HZ;
if (regs->rsp >= curbase && regs->rsp <= curbase + THREAD_SIZE &&
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 209c8c0bec7..d4a0d0ac993 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -37,10 +37,10 @@
#include <linux/slab.h>
#include <linux/preempt.h>
#include <linux/module.h>
+#include <linux/kdebug.h>
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
-#include <asm/kdebug.h>
#include <asm/uaccess.h>
void jprobe_return_end(void);
@@ -266,23 +266,14 @@ static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
}
/* Called with kretprobe_lock held */
-void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)regs->rsp;
- struct kretprobe_instance *ri;
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
- ri->ret_addr = (kprobe_opcode_t *) *sara;
-
- /* Replace the return addr with trampoline addr */
- *sara = (unsigned long) &kretprobe_trampoline;
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ ri->ret_addr = (kprobe_opcode_t *) *sara;
+ /* Replace the return addr with trampoline addr */
+ *sara = (unsigned long) &kretprobe_trampoline;
}
int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -447,7 +438,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
break;
}
- BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
regs->rip = orig_ret_address;
reset_current_kprobe();
@@ -752,3 +743,11 @@ int __init arch_init_kprobes(void)
{
return register_kprobe(&trampoline_p);
}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c
index d7e5d0cf428..bc9ffd5c19c 100644
--- a/arch/x86_64/kernel/ldt.c
+++ b/arch/x86_64/kernel/ldt.c
@@ -13,7 +13,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
index 0497e3bd5bf..c3a55470367 100644
--- a/arch/x86_64/kernel/machine_kexec.c
+++ b/arch/x86_64/kernel/machine_kexec.c
@@ -189,21 +189,21 @@ NORET_TYPE void machine_kexec(struct kimage *image)
control_page = page_address(image->control_code_page) + PAGE_SIZE;
memcpy(control_page, relocate_kernel, PAGE_SIZE);
- page_list[PA_CONTROL_PAGE] = __pa(control_page);
+ page_list[PA_CONTROL_PAGE] = virt_to_phys(control_page);
page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
- page_list[PA_PGD] = __pa(kexec_pgd);
+ page_list[PA_PGD] = virt_to_phys(&kexec_pgd);
page_list[VA_PGD] = (unsigned long)kexec_pgd;
- page_list[PA_PUD_0] = __pa(kexec_pud0);
+ page_list[PA_PUD_0] = virt_to_phys(&kexec_pud0);
page_list[VA_PUD_0] = (unsigned long)kexec_pud0;
- page_list[PA_PMD_0] = __pa(kexec_pmd0);
+ page_list[PA_PMD_0] = virt_to_phys(&kexec_pmd0);
page_list[VA_PMD_0] = (unsigned long)kexec_pmd0;
- page_list[PA_PTE_0] = __pa(kexec_pte0);
+ page_list[PA_PTE_0] = virt_to_phys(&kexec_pte0);
page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
- page_list[PA_PUD_1] = __pa(kexec_pud1);
+ page_list[PA_PUD_1] = virt_to_phys(&kexec_pud1);
page_list[VA_PUD_1] = (unsigned long)kexec_pud1;
- page_list[PA_PMD_1] = __pa(kexec_pmd1);
+ page_list[PA_PMD_1] = virt_to_phys(&kexec_pmd1);
page_list[VA_PMD_1] = (unsigned long)kexec_pmd1;
- page_list[PA_PTE_1] = __pa(kexec_pte1);
+ page_list[PA_PTE_1] = virt_to_phys(&kexec_pte1);
page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
page_list[PA_TABLE_PAGE] =
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 8011a8e1c7d..a14375dd542 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -20,10 +20,10 @@
#include <linux/percpu.h>
#include <linux/ctype.h>
#include <linux/kmod.h>
+#include <linux/kdebug.h>
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/mce.h>
-#include <asm/kdebug.h>
#include <asm/uaccess.h>
#include <asm/smp.h>
@@ -323,10 +323,13 @@ void mce_log_therm_throt_event(unsigned int cpu, __u64 status)
#endif /* CONFIG_X86_MCE_INTEL */
/*
- * Periodic polling timer for "silent" machine check errors.
+ * Periodic polling timer for "silent" machine check errors. If the
+ * poller finds an MCE, poll 2x faster. When the poller finds no more
+ * errors, poll 2x slower (up to check_interval seconds).
*/
static int check_interval = 5 * 60; /* 5 minutes */
+static int next_interval; /* in jiffies */
static void mcheck_timer(struct work_struct *work);
static DECLARE_DELAYED_WORK(mcheck_work, mcheck_timer);
@@ -339,7 +342,6 @@ static void mcheck_check_cpu(void *info)
static void mcheck_timer(struct work_struct *work)
{
on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
- schedule_delayed_work(&mcheck_work, check_interval * HZ);
/*
* It's ok to read stale data here for notify_user and
@@ -349,17 +351,30 @@ static void mcheck_timer(struct work_struct *work)
* writes.
*/
if (notify_user && console_logged) {
+ static unsigned long last_print;
+ unsigned long now = jiffies;
+
+ /* if we logged an MCE, reduce the polling interval */
+ next_interval = max(next_interval/2, HZ/100);
notify_user = 0;
clear_bit(0, &console_logged);
- printk(KERN_INFO "Machine check events logged\n");
+ if (time_after_eq(now, last_print + (check_interval*HZ))) {
+ last_print = now;
+ printk(KERN_INFO "Machine check events logged\n");
+ }
+ } else {
+ next_interval = min(next_interval*2, check_interval*HZ);
}
+
+ schedule_delayed_work(&mcheck_work, next_interval);
}
static __init int periodic_mcheck_init(void)
{
- if (check_interval)
- schedule_delayed_work(&mcheck_work, check_interval*HZ);
+ next_interval = check_interval * HZ;
+ if (next_interval)
+ schedule_delayed_work(&mcheck_work, next_interval);
return 0;
}
__initcall(periodic_mcheck_init);
@@ -597,12 +612,13 @@ static int mce_resume(struct sys_device *dev)
/* Reinit MCEs after user configuration changes */
static void mce_restart(void)
{
- if (check_interval)
+ if (next_interval)
cancel_delayed_work(&mcheck_work);
/* Timer race is harmless here */
on_each_cpu(mce_init, NULL, 1, 1);
- if (check_interval)
- schedule_delayed_work(&mcheck_work, check_interval*HZ);
+ next_interval = check_interval * HZ;
+ if (next_interval)
+ schedule_delayed_work(&mcheck_work, next_interval);
}
static struct sysdev_class mce_sysclass = {
@@ -704,9 +720,11 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
mce_create_device(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
mce_remove_device(cpu);
break;
}
diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c
index d0bd5d66e10..03356e64f9c 100644
--- a/arch/x86_64/kernel/mce_amd.c
+++ b/arch/x86_64/kernel/mce_amd.c
@@ -654,9 +654,11 @@ static int threshold_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
threshold_create_device(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
threshold_remove_device(cpu);
break;
default:
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 455aa0b932f..61ae57eb9e4 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -17,7 +17,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
-#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
#include <linux/acpi.h>
@@ -300,7 +299,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
}
}
}
- clustered_apic_check();
+ setup_apic_routing();
if (!num_processors)
printk(KERN_ERR "MPTABLE: no processors registered!\n");
return num_processors;
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index dfab9f16736..931c64bad5e 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -21,34 +21,17 @@
#include <linux/sysctl.h>
#include <linux/kprobes.h>
#include <linux/cpumask.h>
+#include <linux/kdebug.h>
#include <asm/smp.h>
#include <asm/nmi.h>
#include <asm/proto.h>
-#include <asm/kdebug.h>
#include <asm/mce.h>
-#include <asm/intel_arch_perfmon.h>
int unknown_nmi_panic;
int nmi_watchdog_enabled;
int panic_on_unrecovered_nmi;
-/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
- * evtsel_nmi_owner tracks the ownership of the event selection
- * - different performance counters/ event selection may be reserved for
- * different subsystems this reservation system just tries to coordinate
- * things a little
- */
-
-/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
- * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
- */
-#define NMI_MAX_COUNTER_BITS 66
-#define NMI_MAX_COUNTER_LONGS BITS_TO_LONGS(NMI_MAX_COUNTER_BITS)
-
-static DEFINE_PER_CPU(unsigned, perfctr_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-static DEFINE_PER_CPU(unsigned, evntsel_nmi_owner[NMI_MAX_COUNTER_LONGS]);
-
static cpumask_t backtrace_mask = CPU_MASK_NONE;
/* nmi_active:
@@ -63,191 +46,11 @@ int panic_on_timeout;
unsigned int nmi_watchdog = NMI_DEFAULT;
static unsigned int nmi_hz = HZ;
-struct nmi_watchdog_ctlblk {
- int enabled;
- u64 check_bit;
- unsigned int cccr_msr;
- unsigned int perfctr_msr; /* the MSR to reset in NMI handler */
- unsigned int evntsel_msr; /* the MSR to select the events to handle */
-};
-static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk);
+static DEFINE_PER_CPU(short, wd_enabled);
/* local prototypes */
static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu);
-/* converts an msr to an appropriate reservation bit */
-static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
-{
- /* returns the bit offset of the performance counter register */
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- return (msr - MSR_K7_PERFCTR0);
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
- return (msr - MSR_ARCH_PERFMON_PERFCTR0);
- else
- return (msr - MSR_P4_BPU_PERFCTR0);
- }
- return 0;
-}
-
-/* converts an msr to an appropriate reservation bit */
-static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
-{
- /* returns the bit offset of the event selection register */
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- return (msr - MSR_K7_EVNTSEL0);
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
- return (msr - MSR_ARCH_PERFMON_EVENTSEL0);
- else
- return (msr - MSR_P4_BSU_ESCR0);
- }
- return 0;
-}
-
-/* checks for a bit availability (hack for oprofile) */
-int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
-{
- int cpu;
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
- for_each_possible_cpu (cpu) {
- if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)))
- return 0;
- }
- return 1;
-}
-
-/* checks the an msr for availability */
-int avail_to_resrv_perfctr_nmi(unsigned int msr)
-{
- unsigned int counter;
- int cpu;
-
- counter = nmi_perfctr_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- for_each_possible_cpu (cpu) {
- if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)))
- return 0;
- }
- return 1;
-}
-
-static int __reserve_perfctr_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_perfctr_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)))
- return 1;
- return 0;
-}
-
-static void __release_perfctr_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_perfctr_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu));
-}
-
-int reserve_perfctr_nmi(unsigned int msr)
-{
- int cpu, i;
- for_each_possible_cpu (cpu) {
- if (!__reserve_perfctr_nmi(cpu, msr)) {
- for_each_possible_cpu (i) {
- if (i >= cpu)
- break;
- __release_perfctr_nmi(i, msr);
- }
- return 0;
- }
- }
- return 1;
-}
-
-void release_perfctr_nmi(unsigned int msr)
-{
- int cpu;
- for_each_possible_cpu (cpu)
- __release_perfctr_nmi(cpu, msr);
-}
-
-int __reserve_evntsel_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_evntsel_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]))
- return 1;
- return 0;
-}
-
-static void __release_evntsel_nmi(int cpu, unsigned int msr)
-{
- unsigned int counter;
- if (cpu < 0)
- cpu = smp_processor_id();
-
- counter = nmi_evntsel_msr_to_bit(msr);
- BUG_ON(counter > NMI_MAX_COUNTER_BITS);
-
- clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]);
-}
-
-int reserve_evntsel_nmi(unsigned int msr)
-{
- int cpu, i;
- for_each_possible_cpu (cpu) {
- if (!__reserve_evntsel_nmi(cpu, msr)) {
- for_each_possible_cpu (i) {
- if (i >= cpu)
- break;
- __release_evntsel_nmi(i, msr);
- }
- return 0;
- }
- }
- return 1;
-}
-
-void release_evntsel_nmi(unsigned int msr)
-{
- int cpu;
- for_each_possible_cpu (cpu) {
- __release_evntsel_nmi(cpu, msr);
- }
-}
-
-static __cpuinit inline int nmi_known_cpu(void)
-{
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- return boot_cpu_data.x86 == 15 || boot_cpu_data.x86 == 16;
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
- return 1;
- else
- return (boot_cpu_data.x86 == 15);
- }
- return 0;
-}
-
/* Run after command line and cpu_init init, but before all other checks */
void nmi_watchdog_default(void)
{
@@ -277,23 +80,6 @@ static __init void nmi_cpu_busy(void *data)
}
#endif
-static unsigned int adjust_for_32bit_ctr(unsigned int hz)
-{
- unsigned int retval = hz;
-
- /*
- * On Intel CPUs with ARCH_PERFMON only 32 bits in the counter
- * are writable, with higher bits sign extending from bit 31.
- * So, we can only program the counter with 31 bit values and
- * 32nd bit should be 1, for 33.. to be 1.
- * Find the appropriate nmi_hz
- */
- if ((((u64)cpu_khz * 1000) / retval) > 0x7fffffffULL) {
- retval = ((u64)cpu_khz * 1000) / 0x7fffffffUL + 1;
- }
- return retval;
-}
-
int __init check_nmi_watchdog (void)
{
int *counts;
@@ -322,14 +108,14 @@ int __init check_nmi_watchdog (void)
mdelay((20*1000)/nmi_hz); // wait 20 ticks
for_each_online_cpu(cpu) {
- if (!per_cpu(nmi_watchdog_ctlblk, cpu).enabled)
+ if (!per_cpu(wd_enabled, cpu))
continue;
if (cpu_pda(cpu)->__nmi_count - counts[cpu] <= 5) {
printk("CPU#%d: NMI appears to be stuck (%d->%d)!\n",
cpu,
counts[cpu],
cpu_pda(cpu)->__nmi_count);
- per_cpu(nmi_watchdog_ctlblk, cpu).enabled = 0;
+ per_cpu(wd_enabled, cpu) = 0;
atomic_dec(&nmi_active);
}
}
@@ -344,13 +130,8 @@ int __init check_nmi_watchdog (void)
/* now that we know it works we can reduce NMI frequency to
something more reasonable; makes a difference in some configs */
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- nmi_hz = 1;
- if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0)
- nmi_hz = adjust_for_32bit_ctr(nmi_hz);
- }
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ nmi_hz = lapic_adjust_nmi_hz(1);
kfree(counts);
return 0;
@@ -379,57 +160,6 @@ int __init setup_nmi_watchdog(char *str)
__setup("nmi_watchdog=", setup_nmi_watchdog);
-static void disable_lapic_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
- if (atomic_read(&nmi_active) <= 0)
- return;
-
- on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-
- BUG_ON(atomic_read(&nmi_active) != 0);
-}
-
-static void enable_lapic_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
-
- /* are we already enabled */
- if (atomic_read(&nmi_active) != 0)
- return;
-
- /* are we lapic aware */
- if (nmi_known_cpu() <= 0)
- return;
-
- on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
- touch_nmi_watchdog();
-}
-
-void disable_timer_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
- if (atomic_read(&nmi_active) <= 0)
- return;
-
- disable_irq(0);
- on_each_cpu(stop_apic_nmi_watchdog, NULL, 0, 1);
-
- BUG_ON(atomic_read(&nmi_active) != 0);
-}
-
-void enable_timer_nmi_watchdog(void)
-{
- BUG_ON(nmi_watchdog != NMI_IO_APIC);
-
- if (atomic_read(&nmi_active) == 0) {
- touch_nmi_watchdog();
- on_each_cpu(setup_apic_nmi_watchdog, NULL, 0, 1);
- enable_irq(0);
- }
-}
static void __acpi_nmi_disable(void *__unused)
{
@@ -515,275 +245,9 @@ late_initcall(init_lapic_nmi_sysfs);
#endif /* CONFIG_PM */
-/*
- * Activate the NMI watchdog via the local APIC.
- * Original code written by Keith Owens.
- */
-
-/* Note that these events don't tick when the CPU idles. This means
- the frequency varies with CPU load. */
-
-#define K7_EVNTSEL_ENABLE (1 << 22)
-#define K7_EVNTSEL_INT (1 << 20)
-#define K7_EVNTSEL_OS (1 << 17)
-#define K7_EVNTSEL_USR (1 << 16)
-#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
-#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
-
-static int setup_k7_watchdog(void)
-{
- unsigned int perfctr_msr, evntsel_msr;
- unsigned int evntsel;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- perfctr_msr = MSR_K7_PERFCTR0;
- evntsel_msr = MSR_K7_EVNTSEL0;
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- /* Simulator may not support it */
- if (checking_wrmsrl(evntsel_msr, 0UL))
- goto fail2;
- wrmsrl(perfctr_msr, 0UL);
-
- evntsel = K7_EVNTSEL_INT
- | K7_EVNTSEL_OS
- | K7_EVNTSEL_USR
- | K7_NMI_EVENT;
-
- /* setup the timer */
- wrmsr(evntsel_msr, evntsel, 0);
- wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- evntsel |= K7_EVNTSEL_ENABLE;
- wrmsr(evntsel_msr, evntsel, 0);
-
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = 0; //unused
- wd->check_bit = 1ULL<<63;
- return 1;
-fail2:
- __release_evntsel_nmi(-1, evntsel_msr);
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
-}
-
-static void stop_k7_watchdog(void)
-{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- wrmsr(wd->evntsel_msr, 0, 0);
-
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
-}
-
-/* Note that these events don't tick when the CPU idles. This means
- the frequency varies with CPU load. */
-
-#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
-#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
-#define P4_ESCR_OS (1<<3)
-#define P4_ESCR_USR (1<<2)
-#define P4_CCCR_OVF_PMI0 (1<<26)
-#define P4_CCCR_OVF_PMI1 (1<<27)
-#define P4_CCCR_THRESHOLD(N) ((N)<<20)
-#define P4_CCCR_COMPLEMENT (1<<19)
-#define P4_CCCR_COMPARE (1<<18)
-#define P4_CCCR_REQUIRED (3<<16)
-#define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
-#define P4_CCCR_ENABLE (1<<12)
-#define P4_CCCR_OVF (1<<31)
-/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
- CRU_ESCR0 (with any non-null event selector) through a complemented
- max threshold. [IA32-Vol3, Section 14.9.9] */
-
-static int setup_p4_watchdog(void)
-{
- unsigned int perfctr_msr, evntsel_msr, cccr_msr;
- unsigned int evntsel, cccr_val;
- unsigned int misc_enable, dummy;
- unsigned int ht_num;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
- if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
- return 0;
-
-#ifdef CONFIG_SMP
- /* detect which hyperthread we are on */
- if (smp_num_siblings == 2) {
- unsigned int ebx, apicid;
-
- ebx = cpuid_ebx(1);
- apicid = (ebx >> 24) & 0xff;
- ht_num = apicid & 1;
- } else
-#endif
- ht_num = 0;
-
- /* performance counters are shared resources
- * assign each hyperthread its own set
- * (re-use the ESCR0 register, seems safe
- * and keeps the cccr_val the same)
- */
- if (!ht_num) {
- /* logical cpu 0 */
- perfctr_msr = MSR_P4_IQ_PERFCTR0;
- evntsel_msr = MSR_P4_CRU_ESCR0;
- cccr_msr = MSR_P4_IQ_CCCR0;
- cccr_val = P4_CCCR_OVF_PMI0 | P4_CCCR_ESCR_SELECT(4);
- } else {
- /* logical cpu 1 */
- perfctr_msr = MSR_P4_IQ_PERFCTR1;
- evntsel_msr = MSR_P4_CRU_ESCR0;
- cccr_msr = MSR_P4_IQ_CCCR1;
- cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4);
- }
-
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- evntsel = P4_ESCR_EVENT_SELECT(0x3F)
- | P4_ESCR_OS
- | P4_ESCR_USR;
-
- cccr_val |= P4_CCCR_THRESHOLD(15)
- | P4_CCCR_COMPLEMENT
- | P4_CCCR_COMPARE
- | P4_CCCR_REQUIRED;
-
- wrmsr(evntsel_msr, evntsel, 0);
- wrmsr(cccr_msr, cccr_val, 0);
- wrmsrl(perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- cccr_val |= P4_CCCR_ENABLE;
- wrmsr(cccr_msr, cccr_val, 0);
-
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = cccr_msr;
- wd->check_bit = 1ULL<<39;
- return 1;
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
-}
-
-static void stop_p4_watchdog(void)
-{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- wrmsr(wd->cccr_msr, 0, 0);
- wrmsr(wd->evntsel_msr, 0, 0);
-
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
-}
-
-#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL
-#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK
-
-static int setup_intel_arch_watchdog(void)
-{
- unsigned int ebx;
- union cpuid10_eax eax;
- unsigned int unused;
- unsigned int perfctr_msr, evntsel_msr;
- unsigned int evntsel;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- /*
- * Check whether the Architectural PerfMon supports
- * Unhalted Core Cycles Event or not.
- * NOTE: Corresponding bit = 0 in ebx indicates event present.
- */
- cpuid(10, &(eax.full), &ebx, &unused, &unused);
- if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
- (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
- goto fail;
-
- perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0;
- evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0;
-
- if (!__reserve_perfctr_nmi(-1, perfctr_msr))
- goto fail;
-
- if (!__reserve_evntsel_nmi(-1, evntsel_msr))
- goto fail1;
-
- wrmsrl(perfctr_msr, 0UL);
-
- evntsel = ARCH_PERFMON_EVENTSEL_INT
- | ARCH_PERFMON_EVENTSEL_OS
- | ARCH_PERFMON_EVENTSEL_USR
- | ARCH_PERFMON_NMI_EVENT_SEL
- | ARCH_PERFMON_NMI_EVENT_UMASK;
-
- /* setup the timer */
- wrmsr(evntsel_msr, evntsel, 0);
-
- nmi_hz = adjust_for_32bit_ctr(nmi_hz);
- wrmsr(perfctr_msr, (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
-
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- evntsel |= ARCH_PERFMON_EVENTSEL0_ENABLE;
- wrmsr(evntsel_msr, evntsel, 0);
-
- wd->perfctr_msr = perfctr_msr;
- wd->evntsel_msr = evntsel_msr;
- wd->cccr_msr = 0; //unused
- wd->check_bit = 1ULL << (eax.split.bit_width - 1);
- return 1;
-fail1:
- __release_perfctr_nmi(-1, perfctr_msr);
-fail:
- return 0;
-}
-
-static void stop_intel_arch_watchdog(void)
-{
- unsigned int ebx;
- union cpuid10_eax eax;
- unsigned int unused;
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- /*
- * Check whether the Architectural PerfMon supports
- * Unhalted Core Cycles Event or not.
- * NOTE: Corresponding bit = 0 in ebx indicates event present.
- */
- cpuid(10, &(eax.full), &ebx, &unused, &unused);
- if ((eax.split.mask_length < (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX+1)) ||
- (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
- return;
-
- wrmsr(wd->evntsel_msr, 0, 0);
-
- __release_evntsel_nmi(-1, wd->evntsel_msr);
- __release_perfctr_nmi(-1, wd->perfctr_msr);
-}
-
void setup_apic_nmi_watchdog(void *unused)
{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
- /* only support LOCAL and IO APICs for now */
- if ((nmi_watchdog != NMI_LOCAL_APIC) &&
- (nmi_watchdog != NMI_IO_APIC))
- return;
-
- if (wd->enabled == 1)
+ if (__get_cpu_var(wd_enabled) == 1)
return;
/* cheap hack to support suspend/resume */
@@ -791,62 +255,31 @@ void setup_apic_nmi_watchdog(void *unused)
if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0))
return;
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
- return;
- if (!setup_k7_watchdog())
- return;
- break;
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
- if (!setup_intel_arch_watchdog())
- return;
- break;
- }
- if (!setup_p4_watchdog())
- return;
- break;
- default:
+ switch (nmi_watchdog) {
+ case NMI_LOCAL_APIC:
+ __get_cpu_var(wd_enabled) = 1;
+ if (lapic_watchdog_init(nmi_hz) < 0) {
+ __get_cpu_var(wd_enabled) = 0;
return;
}
+ /* FALL THROUGH */
+ case NMI_IO_APIC:
+ __get_cpu_var(wd_enabled) = 1;
+ atomic_inc(&nmi_active);
}
- wd->enabled = 1;
- atomic_inc(&nmi_active);
}
void stop_apic_nmi_watchdog(void *unused)
{
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
-
/* only support LOCAL and IO APICs for now */
if ((nmi_watchdog != NMI_LOCAL_APIC) &&
(nmi_watchdog != NMI_IO_APIC))
return;
-
- if (wd->enabled == 0)
+ if (__get_cpu_var(wd_enabled) == 0)
return;
-
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_AMD:
- if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
- return;
- stop_k7_watchdog();
- break;
- case X86_VENDOR_INTEL:
- if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
- stop_intel_arch_watchdog();
- break;
- }
- stop_p4_watchdog();
- break;
- default:
- return;
- }
- }
- wd->enabled = 0;
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ lapic_watchdog_stop();
+ __get_cpu_var(wd_enabled) = 0;
atomic_dec(&nmi_active);
}
@@ -885,9 +318,7 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
int sum;
int touched = 0;
int cpu = smp_processor_id();
- struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
- u64 dummy;
- int rc=0;
+ int rc = 0;
/* check for other users first */
if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
@@ -934,55 +365,20 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
}
/* see if the nmi watchdog went off */
- if (wd->enabled) {
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- rdmsrl(wd->perfctr_msr, dummy);
- if (dummy & wd->check_bit){
- /* this wasn't a watchdog timer interrupt */
- goto done;
- }
-
- /* only Intel uses the cccr msr */
- if (wd->cccr_msr != 0) {
- /*
- * P4 quirks:
- * - An overflown perfctr will assert its interrupt
- * until the OVF flag in its CCCR is cleared.
- * - LVTPC is masked on interrupt and must be
- * unmasked by the LVTPC handler.
- */
- rdmsrl(wd->cccr_msr, dummy);
- dummy &= ~P4_CCCR_OVF;
- wrmsrl(wd->cccr_msr, dummy);
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- /* start the cycle over again */
- wrmsrl(wd->perfctr_msr,
- -((u64)cpu_khz * 1000 / nmi_hz));
- } else if (wd->perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) {
- /*
- * ArchPerfom/Core Duo needs to re-unmask
- * the apic vector
- */
- apic_write(APIC_LVTPC, APIC_DM_NMI);
- /* ARCH_PERFMON has 32 bit counter writes */
- wrmsr(wd->perfctr_msr,
- (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0);
- } else {
- /* start the cycle over again */
- wrmsrl(wd->perfctr_msr,
- -((u64)cpu_khz * 1000 / nmi_hz));
- }
- rc = 1;
- } else if (nmi_watchdog == NMI_IO_APIC) {
- /* don't know how to accurately check for this.
- * just assume it was a watchdog timer interrupt
- * This matches the old behaviour.
- */
- rc = 1;
- } else
- printk(KERN_WARNING "Unknown enabled NMI hardware?!\n");
+ if (!__get_cpu_var(wd_enabled))
+ return rc;
+ switch (nmi_watchdog) {
+ case NMI_LOCAL_APIC:
+ rc |= lapic_wd_event(nmi_hz);
+ break;
+ case NMI_IO_APIC:
+ /* don't know how to accurately check for this.
+ * just assume it was a watchdog timer interrupt
+ * This matches the old behaviour.
+ */
+ rc = 1;
+ break;
}
-done:
return rc;
}
@@ -1067,12 +463,4 @@ void __trigger_all_cpu_backtrace(void)
EXPORT_SYMBOL(nmi_active);
EXPORT_SYMBOL(nmi_watchdog);
-EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
-EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
-EXPORT_SYMBOL(reserve_perfctr_nmi);
-EXPORT_SYMBOL(release_perfctr_nmi);
-EXPORT_SYMBOL(reserve_evntsel_nmi);
-EXPORT_SYMBOL(release_evntsel_nmi);
-EXPORT_SYMBOL(disable_timer_nmi_watchdog);
-EXPORT_SYMBOL(enable_timer_nmi_watchdog);
EXPORT_SYMBOL(touch_nmi_watchdog);
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 04480c3b68f..5bd20b542c1 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -507,7 +507,7 @@ error:
return ret;
}
-static struct dma_mapping_ops calgary_dma_ops = {
+static const struct dma_mapping_ops calgary_dma_ops = {
.alloc_coherent = calgary_alloc_coherent,
.map_single = calgary_map_single,
.unmap_single = calgary_unmap_single,
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 0bae862e9a5..373ef66ca1d 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -22,13 +22,13 @@
#include <linux/topology.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
+#include <linux/kdebug.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/mtrr.h>
#include <asm/pgtable.h>
#include <asm/proto.h>
#include <asm/cacheflush.h>
-#include <asm/kdebug.h>
#include <asm/swiotlb.h>
#include <asm/dma.h>
#include <asm/k8.h>
@@ -556,7 +556,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
extern int agp_amd64_init(void);
-static struct dma_mapping_ops gart_dma_ops = {
+static const struct dma_mapping_ops gart_dma_ops = {
.mapping_error = NULL,
.map_single = gart_map_single,
.map_simple = gart_map_simple,
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index df09ab05a1b..6dade0c867c 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -79,7 +79,7 @@ void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
{
}
-struct dma_mapping_ops nommu_dma_ops = {
+const struct dma_mapping_ops nommu_dma_ops = {
.map_single = nommu_map_single,
.unmap_single = nommu_unmap_single,
.map_sg = nommu_map_sg,
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index eb18be5a656..4b4569abc60 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -12,7 +12,7 @@
int swiotlb __read_mostly;
EXPORT_SYMBOL(swiotlb);
-struct dma_mapping_ops swiotlb_dma_ops = {
+const struct dma_mapping_ops swiotlb_dma_ops = {
.mapping_error = swiotlb_dma_mapping_error,
.alloc_coherent = swiotlb_alloc_coherent,
.free_coherent = swiotlb_free_coherent,
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index d8d5ccc245c..5909039f37a 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -36,6 +36,7 @@
#include <linux/random.h>
#include <linux/notifier.h>
#include <linux/kprobes.h>
+#include <linux/kdebug.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -46,7 +47,6 @@
#include <asm/mmu_context.h>
#include <asm/pda.h>
#include <asm/prctl.h>
-#include <asm/kdebug.h>
#include <asm/desc.h>
#include <asm/proto.h>
#include <asm/ia32.h>
@@ -288,16 +288,18 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
static int __init idle_setup (char *str)
{
- if (!strncmp(str, "poll", 4)) {
+ if (!strcmp(str, "poll")) {
printk("using polling idle threads.\n");
pm_idle = poll_idle;
- }
+ } else if (!strcmp(str, "mwait"))
+ force_mwait = 1;
+ else
+ return -1;
boot_option_idle_override = 1;
- return 1;
+ return 0;
}
-
-__setup("idle=", idle_setup);
+early_param("idle", idle_setup);
/* Prints also some state that isn't saved in the pt_regs */
void __show_regs(struct pt_regs * regs)
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 4326a690a50..9409117b9f1 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/user.h>
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 2d676984745..c116b54d422 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -7,8 +7,8 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/pm.h>
+#include <linux/kdebug.h>
#include <asm/io.h>
-#include <asm/kdebug.h>
#include <asm/delay.h>
#include <asm/hw_irq.h>
#include <asm/system.h>
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 3d98b696881..db51577bda3 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -79,6 +79,8 @@ int bootloader_type;
unsigned long saved_video_mode;
+int force_mwait __cpuinitdata;
+
/*
* Early DMI memory
*/
@@ -205,10 +207,10 @@ static void discover_ebda(void)
* there is a real-mode segmented pointer pointing to the
* 4K EBDA area at 0x40E
*/
- ebda_addr = *(unsigned short *)EBDA_ADDR_POINTER;
+ ebda_addr = *(unsigned short *)__va(EBDA_ADDR_POINTER);
ebda_addr <<= 4;
- ebda_size = *(unsigned short *)(unsigned long)ebda_addr;
+ ebda_size = *(unsigned short *)__va(ebda_addr);
/* Round EBDA up to pages */
if (ebda_size == 0)
@@ -274,8 +276,6 @@ void __init setup_arch(char **cmdline_p)
dmi_scan_machine();
- zap_low_mappings(0);
-
#ifdef CONFIG_ACPI
/*
* Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
@@ -329,15 +329,8 @@ void __init setup_arch(char **cmdline_p)
#endif
#ifdef CONFIG_SMP
- /*
- * But first pinch a few for the stack/trampoline stuff
- * FIXME: Don't need the extra page at 4K, but need to fix
- * trampoline before removing it. (see the GDT stuff)
- */
- reserve_bootmem_generic(PAGE_SIZE, PAGE_SIZE);
-
/* Reserve SMP trampoline */
- reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, PAGE_SIZE);
+ reserve_bootmem_generic(SMP_TRAMPOLINE_BASE, 2*PAGE_SIZE);
#endif
#ifdef CONFIG_ACPI_SLEEP
@@ -612,6 +605,10 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
/* RDTSC can be speculated around */
clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
+
+ /* Family 10 doesn't support C states in MWAIT so don't use it */
+ if (c->x86 == 0x10 && !force_mwait)
+ clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
}
static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
@@ -987,9 +984,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"stc",
"100mhzsteps",
"hwpstate",
- NULL, /* tsc invariant mapped to constant_tsc */
- NULL,
- /* nothing */ /* constant_tsc - moved to flags */
+ "", /* tsc invariant mapped to constant_tsc */
+ /* nothing */
};
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 6a70b55f719..64379a80d76 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -103,9 +103,9 @@ void __init setup_per_cpu_areas(void)
if (!NODE_DATA(cpu_to_node(i))) {
printk("cpu with no node %d, num_online_nodes %d\n",
i, num_online_nodes());
- ptr = alloc_bootmem(size);
+ ptr = alloc_bootmem_pages(size);
} else {
- ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
+ ptr = alloc_bootmem_pages_node(NODE_DATA(cpu_to_node(i)), size);
}
if (!ptr)
panic("Cannot allocate cpu data for CPU %d\n", i);
@@ -201,7 +201,6 @@ void __cpuinit cpu_init (void)
/* CPU 0 is initialised in head64.c */
if (cpu != 0) {
pda_init(cpu);
- zap_low_mappings(cpu);
} else
estacks = boot_exception_stacks;
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 49ec324cd14..290f5d8037c 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -12,7 +12,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
@@ -141,7 +140,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
#ifdef DEBUG_SIG
- printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs.rip,regs.rsp,frame,eax);
+ printk("%d sigreturn rip:%lx rsp:%lx frame:%p rax:%lx\n",current->pid,regs->rip,regs->rsp,frame,eax);
#endif
if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->rsp) == -EFAULT)
@@ -301,7 +300,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (test_thread_flag(TIF_SINGLESTEP))
ptrace_notify(SIGTRAP);
#ifdef DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
+ printk("SIG deliver (%s:%d): sp=%p pc=%lx ra=%p\n",
current->comm, current->pid, frame, regs->rip, frame->pretcode);
#endif
@@ -463,7 +462,7 @@ void
do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
{
#ifdef DEBUG_SIG
- printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n",
+ printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%p pending:%x\n",
thread_info_flags, regs->rip, regs->rsp, __builtin_return_address(0),signal_pending(current));
#endif
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index af1ec4d23cf..2ff46859162 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -14,7 +14,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/mc146818rtc.h>
@@ -452,42 +451,34 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
}
EXPORT_SYMBOL(smp_call_function);
-void smp_stop_cpu(void)
+static void stop_this_cpu(void *dummy)
{
- unsigned long flags;
+ local_irq_disable();
/*
* Remove this CPU:
*/
cpu_clear(smp_processor_id(), cpu_online_map);
- local_irq_save(flags);
disable_local_APIC();
- local_irq_restore(flags);
-}
-
-static void smp_really_stop_cpu(void *dummy)
-{
- smp_stop_cpu();
for (;;)
halt();
}
void smp_send_stop(void)
{
- int nolock = 0;
+ int nolock;
+ unsigned long flags;
+
if (reboot_force)
return;
+
/* Don't deadlock on the call lock in panic */
- if (!spin_trylock(&call_lock)) {
- /* ignore locking because we have panicked anyways */
- nolock = 1;
- }
- __smp_call_function(smp_really_stop_cpu, NULL, 0, 0);
+ nolock = !spin_trylock(&call_lock);
+ local_irq_save(flags);
+ __smp_call_function(stop_this_cpu, NULL, 0, 0);
if (!nolock)
spin_unlock(&call_lock);
-
- local_irq_disable();
disable_local_APIC();
- local_irq_enable();
+ local_irq_restore(flags);
}
/*
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index cd4643a3702..32f50783edc 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -42,25 +42,23 @@
#include <linux/mm.h>
#include <linux/kernel_stat.h>
-#include <linux/smp_lock.h>
#include <linux/bootmem.h>
#include <linux/thread_info.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h>
#include <linux/smp.h>
+#include <linux/kdebug.h>
#include <asm/mtrr.h>
#include <asm/pgalloc.h>
#include <asm/desc.h>
-#include <asm/kdebug.h>
#include <asm/tlbflush.h>
#include <asm/proto.h>
#include <asm/nmi.h>
#include <asm/irq.h>
#include <asm/hw_irq.h>
#include <asm/numa.h>
-#include <asm/genapic.h>
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
@@ -68,7 +66,6 @@ EXPORT_SYMBOL(smp_num_siblings);
/* Last level cache ID of each logical CPU */
u8 cpu_llc_id[NR_CPUS] __cpuinitdata = {[0 ... NR_CPUS-1] = BAD_APICID};
-EXPORT_SYMBOL(cpu_llc_id);
/* Bitmask of currently online CPUs */
cpumask_t cpu_online_map __read_mostly;
@@ -392,7 +389,8 @@ static void inquire_remote_apic(int apicid)
{
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
char *names[] = { "ID", "VERSION", "SPIV" };
- int timeout, status;
+ int timeout;
+ unsigned int status;
printk(KERN_INFO "Inquiring remote APIC #%d...\n", apicid);
@@ -402,7 +400,9 @@ static void inquire_remote_apic(int apicid)
/*
* Wait for idle.
*/
- apic_wait_icr_idle();
+ status = safe_apic_wait_icr_idle();
+ if (status)
+ printk("a previous APIC delivery may have failed\n");
apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
apic_write(APIC_ICR, APIC_DM_REMRD | regs[i]);
@@ -430,8 +430,8 @@ static void inquire_remote_apic(int apicid)
*/
static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int start_rip)
{
- unsigned long send_status = 0, accept_status = 0;
- int maxlvt, timeout, num_starts, j;
+ unsigned long send_status, accept_status = 0;
+ int maxlvt, num_starts, j;
Dprintk("Asserting INIT.\n");
@@ -447,12 +447,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
| APIC_DM_INIT);
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
mdelay(10);
@@ -465,12 +460,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
apic_write(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
mb();
atomic_set(&init_deasserted, 1);
@@ -509,12 +499,7 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
Dprintk("Startup point 1.\n");
Dprintk("Waiting for send to finish...\n");
- timeout = 0;
- do {
- Dprintk("+");
- udelay(100);
- send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
- } while (send_status && (timeout++ < 1000));
+ send_status = safe_apic_wait_icr_idle();
/*
* Give the other CPU some time to accept the IPI.
@@ -945,6 +930,12 @@ int __cpuinit __cpu_up(unsigned int cpu)
return -ENOSYS;
}
+ /*
+ * Save current MTRR state in case it was changed since early boot
+ * (e.g. by the ACPI SMI) to initialize new CPUs with MTRRs in sync:
+ */
+ mtrr_save_state();
+
per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
/* Boot it! */
err = do_boot_cpu(cpu, apicid);
@@ -965,13 +956,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
while (!cpu_isset(cpu, cpu_online_map))
cpu_relax();
-
- if (num_online_cpus() > 8 && genapic == &apic_flat) {
- printk(KERN_WARNING
- "flat APIC routing can't be used with > 8 cpus\n");
- BUG();
- }
-
err = 0;
return err;
diff --git a/arch/x86_64/kernel/stacktrace.c b/arch/x86_64/kernel/stacktrace.c
index 65ac2c6b34a..cb910911358 100644
--- a/arch/x86_64/kernel/stacktrace.c
+++ b/arch/x86_64/kernel/stacktrace.c
@@ -21,8 +21,7 @@ save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
static int save_stack_stack(void *data, char *name)
{
- struct stack_trace *trace = (struct stack_trace *)data;
- return trace->all_contexts ? 0 : -1;
+ return -1;
}
static void save_stack_address(void *data, unsigned long addr)
@@ -46,11 +45,10 @@ static struct stacktrace_ops save_stack_ops = {
/*
* Save stack-backtrace addresses into a stack_trace buffer.
*/
-void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+void save_stack_trace(struct stack_trace *trace)
{
- dump_trace(task, NULL, NULL, &save_stack_ops, trace);
+ dump_trace(current, NULL, NULL, &save_stack_ops, trace);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
EXPORT_SYMBOL(save_stack_trace);
-
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index 91f7e678bae..6a5a98f2a75 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -12,6 +12,10 @@
#include <asm/proto.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mtrr.h>
+
+/* References to section boundaries */
+extern const void __nosave_begin, __nosave_end;
struct saved_context saved_context;
@@ -33,7 +37,6 @@ void __save_processor_state(struct saved_context *ctxt)
asm volatile ("str %0" : "=m" (ctxt->tr));
/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
- /* EFER should be constant for kernel version, no need to handle it. */
/*
* segment registers
*/
@@ -46,10 +49,12 @@ void __save_processor_state(struct saved_context *ctxt)
rdmsrl(MSR_FS_BASE, ctxt->fs_base);
rdmsrl(MSR_GS_BASE, ctxt->gs_base);
rdmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
+ mtrr_save_fixed_ranges(NULL);
/*
* control registers
*/
+ rdmsrl(MSR_EFER, ctxt->efer);
asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0));
asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
@@ -75,6 +80,7 @@ void __restore_processor_state(struct saved_context *ctxt)
/*
* control registers
*/
+ wrmsrl(MSR_EFER, ctxt->efer);
asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
@@ -219,4 +225,15 @@ int swsusp_arch_resume(void)
restore_image();
return 0;
}
+
+/*
+ * pfn_is_nosave - check if given pfn is in the 'nosave' section
+ */
+
+int pfn_is_nosave(unsigned long pfn)
+{
+ unsigned long nosave_begin_pfn = __pa_symbol(&__nosave_begin) >> PAGE_SHIFT;
+ unsigned long nosave_end_pfn = PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT;
+ return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
+}
#endif /* CONFIG_SOFTWARE_SUSPEND */
diff --git a/arch/x86_64/kernel/suspend_asm.S b/arch/x86_64/kernel/suspend_asm.S
index bfbe00763c6..16d183f67bc 100644
--- a/arch/x86_64/kernel/suspend_asm.S
+++ b/arch/x86_64/kernel/suspend_asm.S
@@ -71,9 +71,10 @@ loop:
jmp loop
done:
/* go back to the original page tables */
- leaq init_level4_pgt(%rip), %rax
- subq $__START_KERNEL_map, %rax
- movq %rax, %cr3
+ movq $(init_level4_pgt - __START_KERNEL_map), %rax
+ addq phys_base(%rip), %rax
+ movq %rax, %cr3
+
/* Flush TLB, including "global" things (vmalloc) */
movq mmu_cr4_features(%rip), %rax
movq %rax, %rdx
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
index 76bf7c241fe..d067d9a2ad2 100644
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -7,7 +7,6 @@
#include <linux/syscalls.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
@@ -93,6 +92,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long start_addr;
unsigned long begin, end;
+ if (flags & MAP_FIXED)
+ return addr;
+
find_start_end(flags, &begin, &end);
if (len > end)
diff --git a/arch/x86_64/kernel/syscall.c b/arch/x86_64/kernel/syscall.c
index 213fd6ab789..63d592c276c 100644
--- a/arch/x86_64/kernel/syscall.c
+++ b/arch/x86_64/kernel/syscall.c
@@ -3,6 +3,7 @@
#include <linux/linkage.h>
#include <linux/sys.h>
#include <linux/cache.h>
+#include <asm/asm-offsets.h>
#define __NO_STUBS
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 75d73a9aa9f..4a0895bacf5 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -39,13 +39,11 @@
#include <asm/proto.h>
#include <asm/hpet.h>
#include <asm/sections.h>
-#include <linux/cpufreq.h>
#include <linux/hpet.h>
#include <asm/apic.h>
#include <asm/hpet.h>
-
-extern void i8254_timer_resume(void);
-extern int using_apic_timer;
+#include <asm/mpspec.h>
+#include <asm/nmi.h>
static char *timename = NULL;
@@ -252,6 +250,51 @@ static unsigned long get_cmos_time(void)
return mktime(year, mon, day, hour, min, sec);
}
+/* calibrate_cpu is used on systems with fixed rate TSCs to determine
+ * processor frequency */
+#define TICK_COUNT 100000000
+static unsigned int __init tsc_calibrate_cpu_khz(void)
+{
+ int tsc_start, tsc_now;
+ int i, no_ctr_free;
+ unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
+ unsigned long flags;
+
+ for (i = 0; i < 4; i++)
+ if (avail_to_resrv_perfctr_nmi_bit(i))
+ break;
+ no_ctr_free = (i == 4);
+ if (no_ctr_free) {
+ i = 3;
+ rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
+ wrmsrl(MSR_K7_EVNTSEL3, 0);
+ rdmsrl(MSR_K7_PERFCTR3, pmc3);
+ } else {
+ reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+ reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+ }
+ local_irq_save(flags);
+ /* start meauring cycles, incrementing from 0 */
+ wrmsrl(MSR_K7_PERFCTR0 + i, 0);
+ wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
+ rdtscl(tsc_start);
+ do {
+ rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
+ tsc_now = get_cycles_sync();
+ } while ((tsc_now - tsc_start) < TICK_COUNT);
+
+ local_irq_restore(flags);
+ if (no_ctr_free) {
+ wrmsrl(MSR_K7_EVNTSEL3, 0);
+ wrmsrl(MSR_K7_PERFCTR3, pmc3);
+ wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
+ } else {
+ release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+ release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+ }
+
+ return pmc_now * tsc_khz / (tsc_now - tsc_start);
+}
/*
* pit_calibrate_tsc() uses the speaker output (channel 2) of
@@ -285,7 +328,7 @@ static unsigned int __init pit_calibrate_tsc(void)
#define PIT_MODE 0x43
#define PIT_CH0 0x40
-static void __init __pit_init(int val, u8 mode)
+static void __pit_init(int val, u8 mode)
{
unsigned long flags;
@@ -301,12 +344,12 @@ void __init pit_init(void)
__pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
}
-void __init pit_stop_interrupt(void)
+void pit_stop_interrupt(void)
{
__pit_init(0, 0x30); /* mode 0 */
}
-void __init stop_timer_interrupt(void)
+void stop_timer_interrupt(void)
{
char *name;
if (hpet_address) {
@@ -320,7 +363,10 @@ void __init stop_timer_interrupt(void)
}
static struct irqaction irq0 = {
- timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_IRQPOLL,
+ .mask = CPU_MASK_NONE,
+ .name = "timer"
};
void __init time_init(void)
@@ -339,23 +385,29 @@ void __init time_init(void)
if (hpet_use_timer) {
/* set tick_nsec to use the proper rate for HPET */
tick_nsec = TICK_NSEC_HPET;
- cpu_khz = hpet_calibrate_tsc();
+ tsc_khz = hpet_calibrate_tsc();
timename = "HPET";
} else {
pit_init();
- cpu_khz = pit_calibrate_tsc();
+ tsc_khz = pit_calibrate_tsc();
timename = "PIT";
}
+ cpu_khz = tsc_khz;
+ if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
+ boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_data.x86 == 16)
+ cpu_khz = tsc_calibrate_cpu_khz();
+
if (unsynchronized_tsc())
- mark_tsc_unstable();
+ mark_tsc_unstable("TSCs unsynchronized");
if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
vgetcpu_mode = VGETCPU_RDTSCP;
else
vgetcpu_mode = VGETCPU_LSL;
- set_cyc2ns_scale(cpu_khz);
+ set_cyc2ns_scale(tsc_khz);
printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
cpu_khz / 1000, cpu_khz % 1000);
init_tsc_clocksource();
diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
index c79b99a9e2f..e7e2764c461 100644
--- a/arch/x86_64/kernel/trampoline.S
+++ b/arch/x86_64/kernel/trampoline.S
@@ -3,6 +3,7 @@
* Trampoline.S Derived from Setup.S by Linus Torvalds
*
* 4 Jan 1997 Michael Chastain: changed to gnu as.
+ * 15 Sept 2005 Eric Biederman: 64bit PIC support
*
* Entry: CS:IP point to the start of our code, we are
* in real mode with no stack, but the rest of the
@@ -17,15 +18,20 @@
* and IP is zero. Thus, data addresses need to be absolute
* (no relocation) and are taken with regard to r_base.
*
+ * With the addition of trampoline_level4_pgt this code can
+ * now enter a 64bit kernel that lives at arbitrary 64bit
+ * physical addresses.
+ *
* If you work on this file, check the object module with objdump
* --full-contents --reloc to make sure there are no relocation
- * entries. For the GDT entry we do hand relocation in smpboot.c
- * because of 64bit linker limitations.
+ * entries.
*/
#include <linux/linkage.h>
-#include <asm/segment.h>
+#include <asm/pgtable.h>
#include <asm/page.h>
+#include <asm/msr.h>
+#include <asm/segment.h>
.data
@@ -33,15 +39,33 @@
ENTRY(trampoline_data)
r_base = .
+ cli # We should be safe anyway
wbinvd
mov %cs, %ax # Code and data in the same place
mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %ss
- cli # We should be safe anyway
movl $0xA5A5A5A5, trampoline_data - r_base
# write marker for master knows we're running
+ # Setup stack
+ movw $(trampoline_stack_end - r_base), %sp
+
+ call verify_cpu # Verify the cpu supports long mode
+ testl %eax, %eax # Check for return code
+ jnz no_longmode
+
+ mov %cs, %ax
+ movzx %ax, %esi # Find the 32bit trampoline location
+ shll $4, %esi
+
+ # Fixup the vectors
+ addl %esi, startup_32_vector - r_base
+ addl %esi, startup_64_vector - r_base
+ addl %esi, tgdt + 2 - r_base # Fixup the gdt pointer
+
/*
* GDT tables in non default location kernel can be beyond 16MB and
* lgdt will not be able to load the address as in real mode default
@@ -49,23 +73,94 @@ r_base = .
* to 32 bit.
*/
- lidtl idt_48 - r_base # load idt with 0, 0
- lgdtl gdt_48 - r_base # load gdt with whatever is appropriate
+ lidtl tidt - r_base # load idt with 0, 0
+ lgdtl tgdt - r_base # load gdt with whatever is appropriate
xor %ax, %ax
inc %ax # protected mode (PE) bit
lmsw %ax # into protected mode
- # flaush prefetch and jump to startup_32 in arch/x86_64/kernel/head.S
- ljmpl $__KERNEL32_CS, $(startup_32-__START_KERNEL_map)
+
+ # flush prefetch and jump to startup_32
+ ljmpl *(startup_32_vector - r_base)
+
+ .code32
+ .balign 4
+startup_32:
+ movl $__KERNEL_DS, %eax # Initialize the %ds segment register
+ movl %eax, %ds
+
+ xorl %eax, %eax
+ btsl $5, %eax # Enable PAE mode
+ movl %eax, %cr4
+
+ # Setup trampoline 4 level pagetables
+ leal (trampoline_level4_pgt - r_base)(%esi), %eax
+ movl %eax, %cr3
+
+ movl $MSR_EFER, %ecx
+ movl $(1 << _EFER_LME), %eax # Enable Long Mode
+ xorl %edx, %edx
+ wrmsr
+
+ xorl %eax, %eax
+ btsl $31, %eax # Enable paging and in turn activate Long Mode
+ btsl $0, %eax # Enable protected mode
+ movl %eax, %cr0
+
+ /*
+ * At this point we're in long mode but in 32bit compatibility mode
+ * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
+ * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use
+ * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
+ */
+ ljmp *(startup_64_vector - r_base)(%esi)
+
+ .code64
+ .balign 4
+startup_64:
+ # Now jump into the kernel using virtual addresses
+ movq $secondary_startup_64, %rax
+ jmp *%rax
+
+ .code16
+no_longmode:
+ hlt
+ jmp no_longmode
+#include "verify_cpu.S"
# Careful these need to be in the same 64K segment as the above;
-idt_48:
+tidt:
.word 0 # idt limit = 0
.word 0, 0 # idt base = 0L
-gdt_48:
- .short GDT_ENTRIES*8 - 1 # gdt limit
- .long cpu_gdt_table-__START_KERNEL_map
+ # Duplicate the global descriptor table
+ # so the kernel can live anywhere
+ .balign 4
+tgdt:
+ .short tgdt_end - tgdt # gdt limit
+ .long tgdt - r_base
+ .short 0
+ .quad 0x00cf9b000000ffff # __KERNEL32_CS
+ .quad 0x00af9b000000ffff # __KERNEL_CS
+ .quad 0x00cf93000000ffff # __KERNEL_DS
+tgdt_end:
+
+ .balign 4
+startup_32_vector:
+ .long startup_32 - r_base
+ .word __KERNEL32_CS, 0
+
+ .balign 4
+startup_64_vector:
+ .long startup_64 - r_base
+ .word __KERNEL_CS, 0
+
+trampoline_stack:
+ .org 0x1000
+trampoline_stack_end:
+ENTRY(trampoline_level4_pgt)
+ .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
+ .fill 510,8,0
+ .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
-.globl trampoline_end
-trampoline_end:
+ENTRY(trampoline_end)
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 09d2e8a10a4..8c2ac41187c 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -32,6 +32,7 @@
#include <linux/unwind.h>
#include <linux/uaccess.h>
#include <linux/bug.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -39,7 +40,6 @@
#include <asm/debugreg.h>
#include <asm/desc.h>
#include <asm/i387.h>
-#include <asm/kdebug.h>
#include <asm/processor.h>
#include <asm/unwind.h>
#include <asm/smp.h>
@@ -71,22 +71,6 @@ asmlinkage void alignment_check(void);
asmlinkage void machine_check(void);
asmlinkage void spurious_interrupt_bug(void);
-ATOMIC_NOTIFIER_HEAD(die_chain);
-EXPORT_SYMBOL(die_chain);
-
-int register_die_notifier(struct notifier_block *nb)
-{
- vmalloc_sync_all();
- return atomic_notifier_chain_register(&die_chain, nb);
-}
-EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */
-
-int unregister_die_notifier(struct notifier_block *nb)
-{
- return atomic_notifier_chain_unregister(&die_chain, nb);
-}
-EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */
-
static inline void conditional_sti(struct pt_regs *regs)
{
if (regs->eflags & X86_EFLAGS_IF)
@@ -426,8 +410,7 @@ void show_registers(struct pt_regs *regs)
const int cpu = smp_processor_id();
struct task_struct *cur = cpu_pda(cpu)->pcurrent;
- rsp = regs->rsp;
-
+ rsp = regs->rsp;
printk("CPU %d ", cpu);
__show_regs(regs);
printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
@@ -438,7 +421,6 @@ void show_registers(struct pt_regs *regs)
* time of the fault..
*/
if (in_kernel) {
-
printk("Stack: ");
_show_stack(NULL, regs, (unsigned long*)rsp);
@@ -581,10 +563,20 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
{
struct task_struct *tsk = current;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
-
if (user_mode(regs)) {
+ /*
+ * We want error_code and trap_no set for userspace
+ * faults and kernelspace faults which result in
+ * die(), but not kernelspace faults which are fixed
+ * up. die() gives the process no chance to handle
+ * the signal and notice the kernel fault information,
+ * so that won't result in polluting the information
+ * about previously queued, but not yet delivered,
+ * faults. See also do_general_protection below.
+ */
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
+
if (exception_trace && unhandled_signal(tsk, signr))
printk(KERN_INFO
"%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
@@ -605,8 +597,11 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
fixup = search_exception_tables(regs->rip);
if (fixup)
regs->rip = fixup->fixup;
- else
+ else {
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
die(str, regs, error_code);
+ }
return;
}
}
@@ -682,10 +677,10 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
conditional_sti(regs);
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = 13;
-
if (user_mode(regs)) {
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = 13;
+
if (exception_trace && unhandled_signal(tsk, SIGSEGV))
printk(KERN_INFO
"%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
@@ -704,6 +699,9 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
regs->rip = fixup->fixup;
return;
}
+
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = 13;
if (notify_die(DIE_GPF, "general protection fault", regs,
error_code, 13, SIGSEGV) == NOTIFY_STOP)
return;
@@ -778,6 +776,8 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
*/
if (nmi_watchdog_tick(regs,reason))
return;
+ if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
+ == NOTIFY_STOP)
if (!do_nmi_callback(regs,cpu))
unknown_nmi_error(reason, regs);
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c
index 1a0edbbffaa..48f9a8e6aa9 100644
--- a/arch/x86_64/kernel/tsc.c
+++ b/arch/x86_64/kernel/tsc.c
@@ -13,6 +13,8 @@ static int notsc __initdata = 0;
unsigned int cpu_khz; /* TSC clocks / usec, not used here */
EXPORT_SYMBOL(cpu_khz);
+unsigned int tsc_khz;
+EXPORT_SYMBOL(tsc_khz);
static unsigned int cyc2ns_scale __read_mostly;
@@ -77,7 +79,7 @@ static void handle_cpufreq_delayed_get(struct work_struct *v)
static unsigned int ref_freq = 0;
static unsigned long loops_per_jiffy_ref = 0;
-static unsigned long cpu_khz_ref = 0;
+static unsigned long tsc_khz_ref = 0;
static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
@@ -99,7 +101,7 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
if (!ref_freq) {
ref_freq = freq->old;
loops_per_jiffy_ref = *lpj;
- cpu_khz_ref = cpu_khz;
+ tsc_khz_ref = tsc_khz;
}
if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) ||
(val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||
@@ -107,12 +109,12 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
*lpj =
cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);
- cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);
+ tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new);
if (!(freq->flags & CPUFREQ_CONST_LOOPS))
- mark_tsc_unstable();
+ mark_tsc_unstable("cpufreq changes");
}
- set_cyc2ns_scale(cpu_khz_ref);
+ set_cyc2ns_scale(tsc_khz_ref);
return 0;
}
@@ -197,10 +199,11 @@ static struct clocksource clocksource_tsc = {
.vread = vread_tsc,
};
-void mark_tsc_unstable(void)
+void mark_tsc_unstable(char *reason)
{
if (!tsc_unstable) {
tsc_unstable = 1;
+ printk("Marking TSC unstable due to %s\n", reason);
/* Change only the rating, when not registered */
if (clocksource_tsc.mult)
clocksource_change_rating(&clocksource_tsc, 0);
@@ -213,7 +216,7 @@ EXPORT_SYMBOL_GPL(mark_tsc_unstable);
void __init init_tsc_clocksource(void)
{
if (!notsc) {
- clocksource_tsc.mult = clocksource_khz2mult(cpu_khz,
+ clocksource_tsc.mult = clocksource_khz2mult(tsc_khz,
clocksource_tsc.shift);
if (check_tsc_unstable())
clocksource_tsc.rating = 0;
diff --git a/arch/x86_64/kernel/tsc_sync.c b/arch/x86_64/kernel/tsc_sync.c
index 014f0db45df..355f5f506c8 100644
--- a/arch/x86_64/kernel/tsc_sync.c
+++ b/arch/x86_64/kernel/tsc_sync.c
@@ -50,7 +50,7 @@ static __cpuinit void check_tsc_warp(void)
/*
* The measurement runs for 20 msecs:
*/
- end = start + cpu_khz * 20ULL;
+ end = start + tsc_khz * 20ULL;
now = start;
for (i = 0; ; i++) {
@@ -138,7 +138,7 @@ void __cpuinit check_tsc_sync_source(int cpu)
printk("\n");
printk(KERN_WARNING "Measured %Ld cycles TSC warp between CPUs,"
" turning off TSC clock.\n", max_warp);
- mark_tsc_unstable();
+ mark_tsc_unstable("check_tsc_sync_source failed");
nr_warps = 0;
max_warp = 0;
last_tsc = 0;
diff --git a/arch/x86_64/kernel/verify_cpu.S b/arch/x86_64/kernel/verify_cpu.S
new file mode 100644
index 00000000000..e035f594819
--- /dev/null
+++ b/arch/x86_64/kernel/verify_cpu.S
@@ -0,0 +1,119 @@
+/*
+ *
+ * verify_cpu.S - Code for cpu long mode and SSE verification. This
+ * code has been borrowed from boot/setup.S and was introduced by
+ * Andi Kleen.
+ *
+ * Copyright (c) 2007 Andi Kleen (ak@suse.de)
+ * Copyright (c) 2007 Eric Biederman (ebiederm@xmission.com)
+ * Copyright (c) 2007 Vivek Goyal (vgoyal@in.ibm.com)
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ *
+ * This is a common code for verification whether CPU supports
+ * long mode and SSE or not. It is not called directly instead this
+ * file is included at various places and compiled in that context.
+ * Following are the current usage.
+ *
+ * This file is included by both 16bit and 32bit code.
+ *
+ * arch/x86_64/boot/setup.S : Boot cpu verification (16bit)
+ * arch/x86_64/boot/compressed/head.S: Boot cpu verification (32bit)
+ * arch/x86_64/kernel/trampoline.S: secondary processor verfication (16bit)
+ * arch/x86_64/kernel/acpi/wakeup.S:Verfication at resume (16bit)
+ *
+ * verify_cpu, returns the status of cpu check in register %eax.
+ * 0: Success 1: Failure
+ *
+ * The caller needs to check for the error code and take the action
+ * appropriately. Either display a message or halt.
+ */
+
+#include <asm/cpufeature.h>
+
+verify_cpu:
+ pushfl # Save caller passed flags
+ pushl $0 # Kill any dangerous flags
+ popfl
+
+ /* minimum CPUID flags for x86-64 as defined by AMD */
+#define M(x) (1<<(x))
+#define M2(a,b) M(a)|M(b)
+#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d)
+
+#define SSE_MASK \
+ (M2(X86_FEATURE_XMM,X86_FEATURE_XMM2))
+#define REQUIRED_MASK1 \
+ (M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\
+ M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\
+ M(X86_FEATURE_FXSR))
+#define REQUIRED_MASK2 \
+ (M(X86_FEATURE_LM - 32))
+
+ pushfl # standard way to check for cpuid
+ popl %eax
+ movl %eax,%ebx
+ xorl $0x200000,%eax
+ pushl %eax
+ popfl
+ pushfl
+ popl %eax
+ cmpl %eax,%ebx
+ jz verify_cpu_no_longmode # cpu has no cpuid
+
+ movl $0x0,%eax # See if cpuid 1 is implemented
+ cpuid
+ cmpl $0x1,%eax
+ jb verify_cpu_no_longmode # no cpuid 1
+
+ xor %di,%di
+ cmpl $0x68747541,%ebx # AuthenticAMD
+ jnz verify_cpu_noamd
+ cmpl $0x69746e65,%edx
+ jnz verify_cpu_noamd
+ cmpl $0x444d4163,%ecx
+ jnz verify_cpu_noamd
+ mov $1,%di # cpu is from AMD
+
+verify_cpu_noamd:
+ movl $0x1,%eax # Does the cpu have what it takes
+ cpuid
+ andl $REQUIRED_MASK1,%edx
+ xorl $REQUIRED_MASK1,%edx
+ jnz verify_cpu_no_longmode
+
+ movl $0x80000000,%eax # See if extended cpuid is implemented
+ cpuid
+ cmpl $0x80000001,%eax
+ jb verify_cpu_no_longmode # no extended cpuid
+
+ movl $0x80000001,%eax # Does the cpu have what it takes
+ cpuid
+ andl $REQUIRED_MASK2,%edx
+ xorl $REQUIRED_MASK2,%edx
+ jnz verify_cpu_no_longmode
+
+verify_cpu_sse_test:
+ movl $1,%eax
+ cpuid
+ andl $SSE_MASK,%edx
+ cmpl $SSE_MASK,%edx
+ je verify_cpu_sse_ok
+ test %di,%di
+ jz verify_cpu_no_longmode # only try to force SSE on AMD
+ movl $0xc0010015,%ecx # HWCR
+ rdmsr
+ btr $15,%eax # enable SSE
+ wrmsr
+ xor %di,%di # don't loop
+ jmp verify_cpu_sse_test # try again
+
+verify_cpu_no_longmode:
+ popfl # Restore caller passed flags
+ movl $1,%eax
+ ret
+verify_cpu_sse_ok:
+ popfl # Restore caller passed flags
+ xorl %eax, %eax
+ ret
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 5176ecf006e..88cfa50b424 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -29,9 +29,7 @@ SECTIONS
.text : AT(ADDR(.text) - LOAD_OFFSET) {
/* First the code that has to be first for bootstrapping */
*(.bootstrap.text)
- /* Then all the functions that are "hot" in profiles, to group them
- onto the same hugetlb entry */
- #include "functionlist"
+ _stext = .;
/* Then the rest */
*(.text)
SCHED_TEXT
@@ -50,10 +48,10 @@ SECTIONS
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
__stop___ex_table = .;
- RODATA
-
BUG_TABLE
+ RODATA
+
. = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */
/* Data */
.data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -94,6 +92,12 @@ SECTIONS
{ *(.vsyscall_gtod_data) }
vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
+
+ .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
+ { *(.vsyscall_1) }
+ .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
+ { *(.vsyscall_2) }
+
.vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
vgetcpu_mode = VVIRT(.vgetcpu_mode);
@@ -101,10 +105,6 @@ SECTIONS
.jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) }
jiffies = VVIRT(.jiffies);
- .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
- { *(.vsyscall_1) }
- .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2))
- { *(.vsyscall_2) }
.vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3))
{ *(.vsyscall_3) }
@@ -194,7 +194,7 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index b43c698cf7d..51d4c6fa88c 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -45,14 +45,34 @@
#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
#define __syscall_clobber "r11","rcx","memory"
+#define __pa_vsymbol(x) \
+ ({unsigned long v; \
+ extern char __vsyscall_0; \
+ asm("" : "=r" (v) : "0" (x)); \
+ ((v - VSYSCALL_FIRST_PAGE) + __pa_symbol(&__vsyscall_0)); })
+/*
+ * vsyscall_gtod_data contains data that is :
+ * - readonly from vsyscalls
+ * - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
+ * Try to keep this structure as small as possible to avoid cache line ping pongs
+ */
struct vsyscall_gtod_data_t {
- seqlock_t lock;
- int sysctl_enabled;
- struct timeval wall_time_tv;
+ seqlock_t lock;
+
+ /* open coded 'struct timespec' */
+ time_t wall_time_sec;
+ u32 wall_time_nsec;
+
+ int sysctl_enabled;
struct timezone sys_tz;
- cycle_t offset_base;
- struct clocksource clock;
+ struct { /* extract of a clocksource struct */
+ cycle_t (*vread)(void);
+ cycle_t cycle_last;
+ cycle_t mask;
+ u32 mult;
+ u32 shift;
+ } clock;
};
int __vgetcpu_mode __section_vgetcpu_mode;
@@ -68,9 +88,13 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
write_seqlock_irqsave(&vsyscall_gtod_data.lock, flags);
/* copy vsyscall data */
- vsyscall_gtod_data.clock = *clock;
- vsyscall_gtod_data.wall_time_tv.tv_sec = wall_time->tv_sec;
- vsyscall_gtod_data.wall_time_tv.tv_usec = wall_time->tv_nsec/1000;
+ vsyscall_gtod_data.clock.vread = clock->vread;
+ vsyscall_gtod_data.clock.cycle_last = clock->cycle_last;
+ vsyscall_gtod_data.clock.mask = clock->mask;
+ vsyscall_gtod_data.clock.mult = clock->mult;
+ vsyscall_gtod_data.clock.shift = clock->shift;
+ vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
+ vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
vsyscall_gtod_data.sys_tz = sys_tz;
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}
@@ -105,7 +129,8 @@ static __always_inline long time_syscall(long *t)
static __always_inline void do_vgettimeofday(struct timeval * tv)
{
cycle_t now, base, mask, cycle_delta;
- unsigned long seq, mult, shift, nsec_delta;
+ unsigned seq;
+ unsigned long mult, shift, nsec;
cycle_t (*vread)(void);
do {
seq = read_seqbegin(&__vsyscall_gtod_data.lock);
@@ -121,21 +146,20 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
mult = __vsyscall_gtod_data.clock.mult;
shift = __vsyscall_gtod_data.clock.shift;
- *tv = __vsyscall_gtod_data.wall_time_tv;
-
+ tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
+ nsec = __vsyscall_gtod_data.wall_time_nsec;
} while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
/* calculate interval: */
cycle_delta = (now - base) & mask;
/* convert to nsecs: */
- nsec_delta = (cycle_delta * mult) >> shift;
+ nsec += (cycle_delta * mult) >> shift;
- /* convert to usecs and add to timespec: */
- tv->tv_usec += nsec_delta / NSEC_PER_USEC;
- while (tv->tv_usec > USEC_PER_SEC) {
+ while (nsec >= NSEC_PER_SEC) {
tv->tv_sec += 1;
- tv->tv_usec -= USEC_PER_SEC;
+ nsec -= NSEC_PER_SEC;
}
+ tv->tv_usec = nsec / NSEC_PER_USEC;
}
int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
@@ -151,11 +175,13 @@ int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz)
* unlikely */
time_t __vsyscall(1) vtime(time_t *t)
{
+ time_t result;
if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
return time_syscall(t);
- else if (t)
- *t = __vsyscall_gtod_data.wall_time_tv.tv_sec;
- return __vsyscall_gtod_data.wall_time_tv.tv_sec;
+ result = __vsyscall_gtod_data.wall_time_sec;
+ if (t)
+ *t = result;
+ return result;
}
/* Fast way to get current CPU and node.
@@ -224,10 +250,10 @@ static int vsyscall_sysctl_change(ctl_table *ctl, int write, struct file * filp,
return ret;
/* gcc has some trouble with __va(__pa()), so just do it this
way. */
- map1 = ioremap(__pa_symbol(&vsysc1), 2);
+ map1 = ioremap(__pa_vsymbol(&vsysc1), 2);
if (!map1)
return -ENOMEM;
- map2 = ioremap(__pa_symbol(&vsysc2), 2);
+ map2 = ioremap(__pa_vsymbol(&vsysc2), 2);
if (!map2) {
ret = -ENOMEM;
goto out;
@@ -301,7 +327,7 @@ static int __cpuinit
cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
{
long cpu = (long)arg;
- if (action == CPU_ONLINE)
+ if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 0, 1);
return NOTIFY_DONE;
}
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 6ada7231f3a..bfb62a13d7e 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -15,22 +15,22 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/compiler.h>
+#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
+#include <linux/kdebug.h>
#include <asm/system.h>
#include <asm/pgalloc.h>
#include <asm/smp.h>
#include <asm/tlbflush.h>
#include <asm/proto.h>
-#include <asm/kdebug.h>
#include <asm-generic/sections.h>
/* Page fault error code bits */
@@ -585,7 +585,7 @@ do_sigbus:
}
DEFINE_SPINLOCK(pgd_lock);
-struct page *pgd_list;
+LIST_HEAD(pgd_list);
void vmalloc_sync_all(void)
{
@@ -605,8 +605,7 @@ void vmalloc_sync_all(void)
if (pgd_none(*pgd_ref))
continue;
spin_lock(&pgd_lock);
- for (page = pgd_list; page;
- page = (struct page *)page->index) {
+ list_for_each_entry(page, &pgd_list, lru) {
pgd_t *pgd;
pgd = (pgd_t *)page_address(page) + pgd_index(address);
if (pgd_none(*pgd))
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index ec31534eb10..1336da8bdee 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -22,10 +22,12 @@
#include <linux/bootmem.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
+#include <linux/pfn.h>
#include <linux/poison.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/memory_hotplug.h>
+#include <linux/nmi.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -46,7 +48,7 @@
#define Dprintk(x...)
#endif
-struct dma_mapping_ops* dma_ops;
+const struct dma_mapping_ops* dma_ops;
EXPORT_SYMBOL(dma_ops);
static unsigned long dma_reserve __initdata;
@@ -72,6 +74,11 @@ void show_mem(void)
for_each_online_pgdat(pgdat) {
for (i = 0; i < pgdat->node_spanned_pages; ++i) {
+ /* this loop can take a while with 256 GB and 4k pages
+ so update the NMI watchdog */
+ if (unlikely(i % MAX_ORDER_NR_PAGES == 0)) {
+ touch_nmi_watchdog();
+ }
page = pfn_to_page(pgdat->node_start_pfn + i);
total++;
if (PageReserved(page))
@@ -165,25 +172,11 @@ __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
set_pte_phys(address, phys, prot);
}
-unsigned long __initdata table_start, table_end;
+unsigned long __meminitdata table_start, table_end;
-extern pmd_t temp_boot_pmds[];
-
-static struct temp_map {
- pmd_t *pmd;
- void *address;
- int allocated;
-} temp_mappings[] __initdata = {
- { &temp_boot_pmds[0], (void *)(40UL * 1024 * 1024) },
- { &temp_boot_pmds[1], (void *)(42UL * 1024 * 1024) },
- {}
-};
-
-static __meminit void *alloc_low_page(int *index, unsigned long *phys)
+static __meminit void *alloc_low_page(unsigned long *phys)
{
- struct temp_map *ti;
- int i;
- unsigned long pfn = table_end++, paddr;
+ unsigned long pfn = table_end++;
void *adr;
if (after_bootmem) {
@@ -194,57 +187,63 @@ static __meminit void *alloc_low_page(int *index, unsigned long *phys)
if (pfn >= end_pfn)
panic("alloc_low_page: ran out of memory");
- for (i = 0; temp_mappings[i].allocated; i++) {
- if (!temp_mappings[i].pmd)
- panic("alloc_low_page: ran out of temp mappings");
- }
- ti = &temp_mappings[i];
- paddr = (pfn << PAGE_SHIFT) & PMD_MASK;
- set_pmd(ti->pmd, __pmd(paddr | _KERNPG_TABLE | _PAGE_PSE));
- ti->allocated = 1;
- __flush_tlb();
- adr = ti->address + ((pfn << PAGE_SHIFT) & ~PMD_MASK);
+
+ adr = early_ioremap(pfn * PAGE_SIZE, PAGE_SIZE);
memset(adr, 0, PAGE_SIZE);
- *index = i;
- *phys = pfn * PAGE_SIZE;
- return adr;
-}
+ *phys = pfn * PAGE_SIZE;
+ return adr;
+}
-static __meminit void unmap_low_page(int i)
+static __meminit void unmap_low_page(void *adr)
{
- struct temp_map *ti;
if (after_bootmem)
return;
- ti = &temp_mappings[i];
- set_pmd(ti->pmd, __pmd(0));
- ti->allocated = 0;
+ early_iounmap(adr, PAGE_SIZE);
}
/* Must run before zap_low_mappings */
-__init void *early_ioremap(unsigned long addr, unsigned long size)
+__meminit void *early_ioremap(unsigned long addr, unsigned long size)
{
- unsigned long map = round_down(addr, LARGE_PAGE_SIZE);
-
- /* actually usually some more */
- if (size >= LARGE_PAGE_SIZE) {
- return NULL;
+ unsigned long vaddr;
+ pmd_t *pmd, *last_pmd;
+ int i, pmds;
+
+ pmds = ((addr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
+ vaddr = __START_KERNEL_map;
+ pmd = level2_kernel_pgt;
+ last_pmd = level2_kernel_pgt + PTRS_PER_PMD - 1;
+ for (; pmd <= last_pmd; pmd++, vaddr += PMD_SIZE) {
+ for (i = 0; i < pmds; i++) {
+ if (pmd_present(pmd[i]))
+ goto next;
+ }
+ vaddr += addr & ~PMD_MASK;
+ addr &= PMD_MASK;
+ for (i = 0; i < pmds; i++, addr += PMD_SIZE)
+ set_pmd(pmd + i,__pmd(addr | _KERNPG_TABLE | _PAGE_PSE));
+ __flush_tlb();
+ return (void *)vaddr;
+ next:
+ ;
}
- set_pmd(temp_mappings[0].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE));
- map += LARGE_PAGE_SIZE;
- set_pmd(temp_mappings[1].pmd, __pmd(map | _KERNPG_TABLE | _PAGE_PSE));
- __flush_tlb();
- return temp_mappings[0].address + (addr & (LARGE_PAGE_SIZE-1));
+ printk("early_ioremap(0x%lx, %lu) failed\n", addr, size);
+ return NULL;
}
/* To avoid virtual aliases later */
-__init void early_iounmap(void *addr, unsigned long size)
+__meminit void early_iounmap(void *addr, unsigned long size)
{
- if ((void *)round_down((unsigned long)addr, LARGE_PAGE_SIZE) != temp_mappings[0].address)
- printk("early_iounmap: bad address %p\n", addr);
- set_pmd(temp_mappings[0].pmd, __pmd(0));
- set_pmd(temp_mappings[1].pmd, __pmd(0));
+ unsigned long vaddr;
+ pmd_t *pmd;
+ int i, pmds;
+
+ vaddr = (unsigned long)addr;
+ pmds = ((vaddr & ~PMD_MASK) + size + ~PMD_MASK) / PMD_SIZE;
+ pmd = level2_kernel_pgt + pmd_index(vaddr);
+ for (i = 0; i < pmds; i++)
+ pmd_clear(pmd + i);
__flush_tlb();
}
@@ -289,7 +288,6 @@ static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigne
for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE ) {
- int map;
unsigned long pmd_phys;
pud_t *pud = pud_page + pud_index(addr);
pmd_t *pmd;
@@ -307,12 +305,12 @@ static void __meminit phys_pud_init(pud_t *pud_page, unsigned long addr, unsigne
continue;
}
- pmd = alloc_low_page(&map, &pmd_phys);
+ pmd = alloc_low_page(&pmd_phys);
spin_lock(&init_mm.page_table_lock);
set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
phys_pmd_init(pmd, addr, end);
spin_unlock(&init_mm.page_table_lock);
- unmap_low_page(map);
+ unmap_low_page(pmd);
}
__flush_tlb();
}
@@ -364,7 +362,6 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end)
end = (unsigned long)__va(end);
for (; start < end; start = next) {
- int map;
unsigned long pud_phys;
pgd_t *pgd = pgd_offset_k(start);
pud_t *pud;
@@ -372,7 +369,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end)
if (after_bootmem)
pud = pud_offset(pgd, start & PGDIR_MASK);
else
- pud = alloc_low_page(&map, &pud_phys);
+ pud = alloc_low_page(&pud_phys);
next = start + PGDIR_SIZE;
if (next > end)
@@ -380,7 +377,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end)
phys_pud_init(pud, __pa(start), __pa(next));
if (!after_bootmem)
set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
- unmap_low_page(map);
+ unmap_low_page(pud);
}
if (!after_bootmem)
@@ -388,21 +385,6 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end)
__flush_tlb_all();
}
-void __cpuinit zap_low_mappings(int cpu)
-{
- if (cpu == 0) {
- pgd_t *pgd = pgd_offset_k(0UL);
- pgd_clear(pgd);
- } else {
- /*
- * For AP's, zap the low identity mappings by changing the cr3
- * to init_level4_pgt and doing local flush tlb all
- */
- asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
- }
- __flush_tlb_all();
-}
-
#ifndef CONFIG_NUMA
void __init paging_init(void)
{
@@ -579,15 +561,6 @@ void __init mem_init(void)
reservedpages << (PAGE_SHIFT-10),
datasize >> 10,
initsize >> 10);
-
-#ifdef CONFIG_SMP
- /*
- * Sync boot_level4_pgt mappings with the init_level4_pgt
- * except for the low identity mappings which are already zapped
- * in init_level4_pgt. This sync-up is essential for AP's bringup
- */
- memcpy(boot_level4_pgt+1, init_level4_pgt+1, (PTRS_PER_PGD-1)*sizeof(pgd_t));
-#endif
}
void free_init_pages(char *what, unsigned long begin, unsigned long end)
@@ -597,21 +570,23 @@ void free_init_pages(char *what, unsigned long begin, unsigned long end)
if (begin >= end)
return;
- printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+ printk(KERN_INFO "Freeing %s: %luk freed\n", what, (end - begin) >> 10);
for (addr = begin; addr < end; addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
memset((void *)(addr & ~(PAGE_SIZE-1)),
POISON_FREE_INITMEM, PAGE_SIZE);
+ if (addr >= __START_KERNEL_map)
+ change_page_attr_addr(addr, 1, __pgprot(0));
free_page(addr);
totalram_pages++;
}
+ if (addr > __START_KERNEL_map)
+ global_flush_tlb();
}
void free_initmem(void)
{
- memset(__initdata_begin, POISON_FREE_INITDATA,
- __initdata_end - __initdata_begin);
free_init_pages("unused kernel memory",
(unsigned long)(&__init_begin),
(unsigned long)(&__init_end));
@@ -621,13 +596,23 @@ void free_initmem(void)
void mark_rodata_ro(void)
{
- unsigned long addr = (unsigned long)__start_rodata;
+ unsigned long start = (unsigned long)_stext, end;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ /* It must still be possible to apply SMP alternatives. */
+ if (num_possible_cpus() > 1)
+ start = (unsigned long)_etext;
+#endif
+ end = (unsigned long)__end_rodata;
+ start = (start + PAGE_SIZE - 1) & PAGE_MASK;
+ end &= PAGE_MASK;
+ if (end <= start)
+ return;
- for (; addr < (unsigned long)__end_rodata; addr += PAGE_SIZE)
- change_page_attr_addr(addr, 1, PAGE_KERNEL_RO);
+ change_page_attr_addr(start, (end - start) >> PAGE_SHIFT, PAGE_KERNEL_RO);
- printk ("Write protecting the kernel read-only data: %luk\n",
- (__end_rodata - __start_rodata) >> 10);
+ printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n",
+ (end - start) >> 10);
/*
* change_page_attr_addr() requires a global_flush_tlb() call after it.
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
index c6e5e8d401a..6cac90aa503 100644
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -13,12 +13,21 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/io.h>
+
#include <asm/pgalloc.h>
#include <asm/fixmap.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#include <asm/proto.h>
+unsigned long __phys_addr(unsigned long x)
+{
+ if (x >= __START_KERNEL_map)
+ return x - __START_KERNEL_map + phys_base;
+ return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+
#define ISA_START_ADDRESS 0xa0000
#define ISA_END_ADDRESS 0x100000
diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
index b5b8dba28b4..f983c75825d 100644
--- a/arch/x86_64/mm/k8topology.c
+++ b/arch/x86_64/mm/k8topology.c
@@ -49,11 +49,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
int found = 0;
u32 reg;
unsigned numnodes;
- nodemask_t nodes_parsed;
unsigned dualcore = 0;
- nodes_clear(nodes_parsed);
-
if (!early_pci_allowed())
return -1;
@@ -65,6 +62,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
reg = read_pci_config(0, nb, 0, 0x60);
numnodes = ((reg >> 4) & 0xF) + 1;
+ if (numnodes <= 1)
+ return -1;
printk(KERN_INFO "Number of nodes %d\n", numnodes);
@@ -102,7 +101,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
nodeid, (base>>8)&3, (limit>>8) & 3);
return -1;
}
- if (node_isset(nodeid, nodes_parsed)) {
+ if (node_isset(nodeid, node_possible_map)) {
printk(KERN_INFO "Node %d already present. Skipping\n",
nodeid);
continue;
@@ -155,7 +154,7 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
prevbase = base;
- node_set(nodeid, nodes_parsed);
+ node_set(nodeid, node_possible_map);
}
if (!found)
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 41b8fb06992..51548947ad3 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -273,125 +273,213 @@ void __init numa_init_array(void)
#ifdef CONFIG_NUMA_EMU
/* Numa emulation */
-int numa_fake __initdata = 0;
+#define E820_ADDR_HOLE_SIZE(start, end) \
+ (e820_hole_size((start) >> PAGE_SHIFT, (end) >> PAGE_SHIFT) << \
+ PAGE_SHIFT)
+char *cmdline __initdata;
/*
- * This function is used to find out if the start and end correspond to
- * different zones.
+ * Setups up nid to range from addr to addr + size. If the end boundary is
+ * greater than max_addr, then max_addr is used instead. The return value is 0
+ * if there is additional memory left for allocation past addr and -1 otherwise.
+ * addr is adjusted to be at the end of the node.
*/
-int zone_cross_over(unsigned long start, unsigned long end)
+static int __init setup_node_range(int nid, struct bootnode *nodes, u64 *addr,
+ u64 size, u64 max_addr)
{
- if ((start < (MAX_DMA32_PFN << PAGE_SHIFT)) &&
- (end >= (MAX_DMA32_PFN << PAGE_SHIFT)))
- return 1;
- return 0;
+ int ret = 0;
+ nodes[nid].start = *addr;
+ *addr += size;
+ if (*addr >= max_addr) {
+ *addr = max_addr;
+ ret = -1;
+ }
+ nodes[nid].end = *addr;
+ node_set(nid, node_possible_map);
+ printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n", nid,
+ nodes[nid].start, nodes[nid].end,
+ (nodes[nid].end - nodes[nid].start) >> 20);
+ return ret;
}
-static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+/*
+ * Splits num_nodes nodes up equally starting at node_start. The return value
+ * is the number of nodes split up and addr is adjusted to be at the end of the
+ * last node allocated.
+ */
+static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
+ u64 max_addr, int node_start,
+ int num_nodes)
{
- int i, big;
- struct bootnode nodes[MAX_NUMNODES];
- unsigned long sz, old_sz;
- unsigned long hole_size;
- unsigned long start, end;
- unsigned long max_addr = (end_pfn << PAGE_SHIFT);
-
- start = (start_pfn << PAGE_SHIFT);
- hole_size = e820_hole_size(start, max_addr);
- sz = (max_addr - start - hole_size) / numa_fake;
-
- /* Kludge needed for the hash function */
-
- old_sz = sz;
- /*
- * Round down to the nearest FAKE_NODE_MIN_SIZE.
- */
- sz &= FAKE_NODE_MIN_HASH_MASK;
+ unsigned int big;
+ u64 size;
+ int i;
+ if (num_nodes <= 0)
+ return -1;
+ if (num_nodes > MAX_NUMNODES)
+ num_nodes = MAX_NUMNODES;
+ size = (max_addr - *addr - E820_ADDR_HOLE_SIZE(*addr, max_addr)) /
+ num_nodes;
/*
- * We ensure that each node is at least 64MB big. Smaller than this
- * size can cause VM hiccups.
+ * Calculate the number of big nodes that can be allocated as a result
+ * of consolidating the leftovers.
*/
- if (sz == 0) {
- printk(KERN_INFO "Not enough memory for %d nodes. Reducing "
- "the number of nodes\n", numa_fake);
- numa_fake = (max_addr - start - hole_size) / FAKE_NODE_MIN_SIZE;
- printk(KERN_INFO "Number of fake nodes will be = %d\n",
- numa_fake);
- sz = FAKE_NODE_MIN_SIZE;
+ big = ((size & ~FAKE_NODE_MIN_HASH_MASK) * num_nodes) /
+ FAKE_NODE_MIN_SIZE;
+
+ /* Round down to nearest FAKE_NODE_MIN_SIZE. */
+ size &= FAKE_NODE_MIN_HASH_MASK;
+ if (!size) {
+ printk(KERN_ERR "Not enough memory for each node. "
+ "NUMA emulation disabled.\n");
+ return -1;
}
- /*
- * Find out how many nodes can get an extra NODE_MIN_SIZE granule.
- * This logic ensures the extra memory gets distributed among as many
- * nodes as possible (as compared to one single node getting all that
- * extra memory.
- */
- big = ((old_sz - sz) * numa_fake) / FAKE_NODE_MIN_SIZE;
- printk(KERN_INFO "Fake node Size: %luMB hole_size: %luMB big nodes: "
- "%d\n",
- (sz >> 20), (hole_size >> 20), big);
- memset(&nodes,0,sizeof(nodes));
- end = start;
- for (i = 0; i < numa_fake; i++) {
- /*
- * In case we are not able to allocate enough memory for all
- * the nodes, we reduce the number of fake nodes.
- */
- if (end >= max_addr) {
- numa_fake = i - 1;
- break;
- }
- start = nodes[i].start = end;
- /*
- * Final node can have all the remaining memory.
- */
- if (i == numa_fake-1)
- sz = max_addr - start;
- end = nodes[i].start + sz;
- /*
- * Fir "big" number of nodes get extra granule.
- */
+
+ for (i = node_start; i < num_nodes + node_start; i++) {
+ u64 end = *addr + size;
if (i < big)
end += FAKE_NODE_MIN_SIZE;
/*
- * Iterate over the range to ensure that this node gets at
- * least sz amount of RAM (excluding holes)
+ * The final node can have the remaining system RAM. Other
+ * nodes receive roughly the same amount of available pages.
*/
- while ((end - start - e820_hole_size(start, end)) < sz) {
- end += FAKE_NODE_MIN_SIZE;
- if (end >= max_addr)
- break;
+ if (i == num_nodes + node_start - 1)
+ end = max_addr;
+ else
+ while (end - *addr - E820_ADDR_HOLE_SIZE(*addr, end) <
+ size) {
+ end += FAKE_NODE_MIN_SIZE;
+ if (end > max_addr) {
+ end = max_addr;
+ break;
+ }
+ }
+ if (setup_node_range(i, nodes, addr, end - *addr, max_addr) < 0)
+ break;
+ }
+ return i - node_start + 1;
+}
+
+/*
+ * Splits the remaining system RAM into chunks of size. The remaining memory is
+ * always assigned to a final node and can be asymmetric. Returns the number of
+ * nodes split.
+ */
+static int __init split_nodes_by_size(struct bootnode *nodes, u64 *addr,
+ u64 max_addr, int node_start, u64 size)
+{
+ int i = node_start;
+ size = (size << 20) & FAKE_NODE_MIN_HASH_MASK;
+ while (!setup_node_range(i++, nodes, addr, size, max_addr))
+ ;
+ return i - node_start;
+}
+
+/*
+ * Sets up the system RAM area from start_pfn to end_pfn according to the
+ * numa=fake command-line option.
+ */
+static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
+{
+ struct bootnode nodes[MAX_NUMNODES];
+ u64 addr = start_pfn << PAGE_SHIFT;
+ u64 max_addr = end_pfn << PAGE_SHIFT;
+ int num_nodes = 0;
+ int coeff_flag;
+ int coeff = -1;
+ int num = 0;
+ u64 size;
+ int i;
+
+ memset(&nodes, 0, sizeof(nodes));
+ /*
+ * If the numa=fake command-line is just a single number N, split the
+ * system RAM into N fake nodes.
+ */
+ if (!strchr(cmdline, '*') && !strchr(cmdline, ',')) {
+ num_nodes = split_nodes_equally(nodes, &addr, max_addr, 0,
+ simple_strtol(cmdline, NULL, 0));
+ if (num_nodes < 0)
+ return num_nodes;
+ goto out;
+ }
+
+ /* Parse the command line. */
+ for (coeff_flag = 0; ; cmdline++) {
+ if (*cmdline && isdigit(*cmdline)) {
+ num = num * 10 + *cmdline - '0';
+ continue;
}
- /*
- * Look at the next node to make sure there is some real memory
- * to map. Bad things happen when the only memory present
- * in a zone on a fake node is IO hole.
- */
- while (e820_hole_size(end, end + FAKE_NODE_MIN_SIZE) > 0) {
- if (zone_cross_over(start, end + sz)) {
- end = (MAX_DMA32_PFN << PAGE_SHIFT);
+ if (*cmdline == '*') {
+ if (num > 0)
+ coeff = num;
+ coeff_flag = 1;
+ }
+ if (!*cmdline || *cmdline == ',') {
+ if (!coeff_flag)
+ coeff = 1;
+ /*
+ * Round down to the nearest FAKE_NODE_MIN_SIZE.
+ * Command-line coefficients are in megabytes.
+ */
+ size = ((u64)num << 20) & FAKE_NODE_MIN_HASH_MASK;
+ if (size)
+ for (i = 0; i < coeff; i++, num_nodes++)
+ if (setup_node_range(num_nodes, nodes,
+ &addr, size, max_addr) < 0)
+ goto done;
+ if (!*cmdline)
break;
- }
- if (end >= max_addr)
+ coeff_flag = 0;
+ coeff = -1;
+ }
+ num = 0;
+ }
+done:
+ if (!num_nodes)
+ return -1;
+ /* Fill remainder of system RAM, if appropriate. */
+ if (addr < max_addr) {
+ if (coeff_flag && coeff < 0) {
+ /* Split remaining nodes into num-sized chunks */
+ num_nodes += split_nodes_by_size(nodes, &addr, max_addr,
+ num_nodes, num);
+ goto out;
+ }
+ switch (*(cmdline - 1)) {
+ case '*':
+ /* Split remaining nodes into coeff chunks */
+ if (coeff <= 0)
break;
- end += FAKE_NODE_MIN_SIZE;
+ num_nodes += split_nodes_equally(nodes, &addr, max_addr,
+ num_nodes, coeff);
+ break;
+ case ',':
+ /* Do not allocate remaining system RAM */
+ break;
+ default:
+ /* Give one final node */
+ setup_node_range(num_nodes, nodes, &addr,
+ max_addr - addr, max_addr);
+ num_nodes++;
}
- if (end > max_addr)
- end = max_addr;
- nodes[i].end = end;
- printk(KERN_INFO "Faking node %d at %016Lx-%016Lx (%LuMB)\n",
- i,
- nodes[i].start, nodes[i].end,
- (nodes[i].end - nodes[i].start) >> 20);
- node_set_online(i);
- }
- memnode_shift = compute_hash_shift(nodes, numa_fake);
- if (memnode_shift < 0) {
- memnode_shift = 0;
- printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n");
- return -1;
- }
- for_each_online_node(i) {
+ }
+out:
+ memnode_shift = compute_hash_shift(nodes, num_nodes);
+ if (memnode_shift < 0) {
+ memnode_shift = 0;
+ printk(KERN_ERR "No NUMA hash function found. NUMA emulation "
+ "disabled.\n");
+ return -1;
+ }
+
+ /*
+ * We need to vacate all active ranges that may have been registered by
+ * SRAT.
+ */
+ remove_all_active_ranges();
+ for_each_node_mask(i, node_possible_map) {
e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
@@ -399,26 +487,32 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
numa_init_array();
return 0;
}
-#endif
+#undef E820_ADDR_HOLE_SIZE
+#endif /* CONFIG_NUMA_EMU */
void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
{
int i;
+ nodes_clear(node_possible_map);
+
#ifdef CONFIG_NUMA_EMU
- if (numa_fake && !numa_emulation(start_pfn, end_pfn))
+ if (cmdline && !numa_emulation(start_pfn, end_pfn))
return;
+ nodes_clear(node_possible_map);
#endif
#ifdef CONFIG_ACPI_NUMA
if (!numa_off && !acpi_scan_nodes(start_pfn << PAGE_SHIFT,
end_pfn << PAGE_SHIFT))
return;
+ nodes_clear(node_possible_map);
#endif
#ifdef CONFIG_K8_NUMA
if (!numa_off && !k8_scan_nodes(start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT))
return;
+ nodes_clear(node_possible_map);
#endif
printk(KERN_INFO "%s\n",
numa_off ? "NUMA turned off" : "No NUMA configuration found");
@@ -432,6 +526,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
memnodemap[0] = 0;
nodes_clear(node_online_map);
node_set_online(0);
+ node_set(0, node_possible_map);
for (i = 0; i < NR_CPUS; i++)
numa_set_node(i, 0);
node_to_cpumask[0] = cpumask_of_cpu(0);
@@ -486,11 +581,8 @@ static __init int numa_setup(char *opt)
if (!strncmp(opt,"off",3))
numa_off = 1;
#ifdef CONFIG_NUMA_EMU
- if(!strncmp(opt, "fake=", 5)) {
- numa_fake = simple_strtoul(opt+5,NULL,0); ;
- if (numa_fake >= MAX_NUMNODES)
- numa_fake = MAX_NUMNODES;
- }
+ if (!strncmp(opt, "fake=", 5))
+ cmdline = opt + 5;
#endif
#ifdef CONFIG_ACPI_NUMA
if (!strncmp(opt,"noacpi",6))
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c
index 081409aa345..d653d0bf3df 100644
--- a/arch/x86_64/mm/pageattr.c
+++ b/arch/x86_64/mm/pageattr.c
@@ -180,16 +180,24 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
*/
int change_page_attr_addr(unsigned long address, int numpages, pgprot_t prot)
{
- int err = 0;
+ int err = 0, kernel_map = 0;
int i;
+ if (address >= __START_KERNEL_map
+ && address < __START_KERNEL_map + KERNEL_TEXT_SIZE) {
+ address = (unsigned long)__va(__pa(address));
+ kernel_map = 1;
+ }
+
down_write(&init_mm.mmap_sem);
for (i = 0; i < numpages; i++, address += PAGE_SIZE) {
unsigned long pfn = __pa(address) >> PAGE_SHIFT;
- err = __change_page_attr(address, pfn, prot, PAGE_KERNEL);
- if (err)
- break;
+ if (!kernel_map || pte_present(pfn_pte(0, prot))) {
+ err = __change_page_attr(address, pfn, prot, PAGE_KERNEL);
+ if (err)
+ break;
+ }
/* Handle kernel mapping too which aliases part of the
* lowmem */
if (__pa(address) < KERNEL_TEXT_SIZE) {
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 2efe215fc76..1e76bb0a727 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -419,19 +419,21 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
return -1;
}
+ node_possible_map = nodes_parsed;
+
/* Finally register nodes */
- for_each_node_mask(i, nodes_parsed)
+ for_each_node_mask(i, node_possible_map)
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
/* Try again in case setup_node_bootmem missed one due
to missing bootmem */
- for_each_node_mask(i, nodes_parsed)
+ for_each_node_mask(i, node_possible_map)
if (!node_online(i))
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
for (i = 0; i < NR_CPUS; i++) {
if (cpu_to_node[i] == NUMA_NO_NODE)
continue;
- if (!node_isset(cpu_to_node[i], nodes_parsed))
+ if (!node_isset(cpu_to_node[i], node_possible_map))
numa_set_node(i, NUMA_NO_NODE);
}
numa_init_array();
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index b256cfbef34..698079b3a33 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -70,7 +70,7 @@ int main(void)
DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
DEFINE(TASK_PID, offsetof (struct task_struct, pid));
DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
- DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+ DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
BLANK();
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
index ca76f071666..f5319d78c87 100644
--- a/arch/xtensa/kernel/pci-dma.c
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/pci-dma.c
+ * arch/xtensa/kernel/pci-dma.c
*
* DMA coherent memory allocation.
*
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 795bd5ac6f4..ce758bab95b 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 8b6d3d0623b..14104ff6309 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -19,7 +19,6 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/security.h>
#include <linux/signal.h>
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index c6d9880a4cd..58107672a61 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -17,7 +17,6 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index ab6370054ce..4fbd66a52a8 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -198,7 +198,7 @@ SECTIONS
__ftr_fixup : { *(__ftr_fixup) }
__stop___ftr_fixup = .;
- . = ALIGN(32);
+ . = ALIGN(4096);
__per_cpu_start = .;
.data.percpu : { *(.data.percpu) }
__per_cpu_end = .;
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index 0b4cb93db5a..cd7e6a02060 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -18,7 +18,6 @@
#include <linux/interrupt.h>
#include <asm/irq.h>
#include <linux/in6.h>
-#include <linux/pci.h>
#include <linux/ide.h>
#include <asm/uaccess.h>
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
index ab05bff4010..4bfe333be22 100644
--- a/arch/xtensa/platform-iss/network.c
+++ b/arch/xtensa/platform-iss/network.c
@@ -251,7 +251,7 @@ static int tuntap_open(struct iss_net_private *lp)
memset(&ifr, 0, sizeof ifr);
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1);
+ strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name);
if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
printk("Failed to set interface, returned %d "
diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c
index c8a42b60c57..f60c8cf6dfb 100644
--- a/arch/xtensa/platform-iss/setup.c
+++ b/arch/xtensa/platform-iss/setup.c
@@ -20,7 +20,6 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/reboot.h>
-#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/major.h>
diff --git a/block/as-iosched.c b/block/as-iosched.c
index ef126277b4b..109e91b91ff 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -569,7 +569,7 @@ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
static int as_close_req(struct as_data *ad, struct as_io_context *aic,
struct request *rq)
{
- unsigned long delay; /* milliseconds */
+ unsigned long delay; /* jiffies */
sector_t last = ad->last_sector[ad->batch_data_dir];
sector_t next = rq->sector;
sector_t delta; /* acceptable close offset (in sectors) */
@@ -578,11 +578,11 @@ static int as_close_req(struct as_data *ad, struct as_io_context *aic,
if (ad->antic_status == ANTIC_OFF || !ad->ioc_finished)
delay = 0;
else
- delay = ((jiffies - ad->antic_start) * 1000) / HZ;
+ delay = jiffies - ad->antic_start;
if (delay == 0)
delta = 8192;
- else if (delay <= 20 && delay <= ad->antic_expire)
+ else if (delay <= (20 * HZ / 1000) && delay <= ad->antic_expire)
delta = 8192 << delay;
else
return 1;
@@ -1306,7 +1306,7 @@ static void as_exit_queue(elevator_t *e)
struct as_data *ad = e->elevator_data;
del_timer_sync(&ad->antic_timer);
- kblockd_flush();
+ kblockd_flush_work(&ad->antic_work);
BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC]));
BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC]));
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f92ba2a869b..baef5fc7cff 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -9,7 +9,6 @@
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
-#include <linux/hash.h>
#include <linux/rbtree.h>
#include <linux/ioprio.h>
@@ -26,19 +25,17 @@ static int cfq_slice_async = HZ / 25;
static const int cfq_slice_async_rq = 2;
static int cfq_slice_idle = HZ / 125;
+/*
+ * grace period before allowing idle class to get disk access
+ */
#define CFQ_IDLE_GRACE (HZ / 10)
-#define CFQ_SLICE_SCALE (5)
-
-#define CFQ_KEY_ASYNC (0)
/*
- * for the hash of cfqq inside the cfqd
+ * below this threshold, we consider thinktime immediate
*/
-#define CFQ_QHASH_SHIFT 6
-#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT)
-#define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash)
+#define CFQ_MIN_TT (2)
-#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list)
+#define CFQ_SLICE_SCALE (5)
#define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private)
#define RQ_CFQQ(rq) ((rq)->elevator_private2)
@@ -56,17 +53,21 @@ static struct completion *ioc_gone;
#define ASYNC (0)
#define SYNC (1)
-#define cfq_cfqq_dispatched(cfqq) \
- ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
-
-#define cfq_cfqq_class_sync(cfqq) ((cfqq)->key != CFQ_KEY_ASYNC)
-
-#define cfq_cfqq_sync(cfqq) \
- (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
-
#define sample_valid(samples) ((samples) > 80)
/*
+ * Most of our rbtree usage is for sorting with min extraction, so
+ * if we cache the leftmost node we don't have to walk down the tree
+ * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should
+ * move this into the elevator for the rq sorting as well.
+ */
+struct cfq_rb_root {
+ struct rb_root rb;
+ struct rb_node *left;
+};
+#define CFQ_RB_ROOT (struct cfq_rb_root) { RB_ROOT, NULL, }
+
+/*
* Per block device queue structure
*/
struct cfq_data {
@@ -75,18 +76,11 @@ struct cfq_data {
/*
* rr list of queues with requests and the count of them
*/
- struct list_head rr_list[CFQ_PRIO_LISTS];
- struct list_head busy_rr;
- struct list_head cur_rr;
- struct list_head idle_rr;
+ struct cfq_rb_root service_tree;
unsigned int busy_queues;
- /*
- * cfqq lookup hash
- */
- struct hlist_head *cfq_hash;
-
int rq_in_driver;
+ int sync_flight;
int hw_tag;
/*
@@ -97,12 +91,10 @@ struct cfq_data {
struct cfq_queue *active_queue;
struct cfq_io_context *active_cic;
- int cur_prio, cur_end_prio;
- unsigned int dispatch_slice;
struct timer_list idle_class_timer;
- sector_t last_sector;
+ sector_t last_position;
unsigned long last_end_request;
/*
@@ -117,6 +109,9 @@ struct cfq_data {
unsigned int cfq_slice_idle;
struct list_head cic_list;
+
+ sector_t new_seek_mean;
+ u64 new_seek_total;
};
/*
@@ -127,12 +122,10 @@ struct cfq_queue {
atomic_t ref;
/* parent cfq_data */
struct cfq_data *cfqd;
- /* cfqq lookup hash */
- struct hlist_node cfq_hash;
- /* hash key */
- unsigned int key;
- /* member of the rr/busy/cur/idle cfqd list */
- struct list_head cfq_list;
+ /* service_tree member */
+ struct rb_node rb_node;
+ /* service_tree key */
+ unsigned long rb_key;
/* sorted list of pending requests */
struct rb_root sort_list;
/* if fifo isn't expired, next request to serve */
@@ -147,11 +140,10 @@ struct cfq_queue {
struct list_head fifo;
unsigned long slice_end;
- unsigned long service_last;
long slice_resid;
- /* number of requests that are on the dispatch list */
- int on_dispatch[2];
+ /* number of requests that are on the dispatch list or inside driver */
+ int dispatched;
/* io prio of this group */
unsigned short ioprio, org_ioprio;
@@ -159,6 +151,8 @@ struct cfq_queue {
/* various state flags, see below */
unsigned int flags;
+
+ sector_t last_request_pos;
};
enum cfqq_state_flags {
@@ -172,6 +166,7 @@ enum cfqq_state_flags {
CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */
CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */
CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */
+ CFQ_CFQQ_FLAG_sync, /* synchronous queue */
};
#define CFQ_CFQQ_FNS(name) \
@@ -198,11 +193,38 @@ CFQ_CFQQ_FNS(idle_window);
CFQ_CFQQ_FNS(prio_changed);
CFQ_CFQQ_FNS(queue_new);
CFQ_CFQQ_FNS(slice_new);
+CFQ_CFQQ_FNS(sync);
#undef CFQ_CFQQ_FNS
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
static void cfq_dispatch_insert(request_queue_t *, struct request *);
-static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
+static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
+ struct task_struct *, gfp_t);
+static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *,
+ struct io_context *);
+
+static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
+ int is_sync)
+{
+ return cic->cfqq[!!is_sync];
+}
+
+static inline void cic_set_cfqq(struct cfq_io_context *cic,
+ struct cfq_queue *cfqq, int is_sync)
+{
+ cic->cfqq[!!is_sync] = cfqq;
+}
+
+/*
+ * We regard a request as SYNC, if it's either a read or has the SYNC bit
+ * set (in which case it could also be direct WRITE).
+ */
+static inline int cfq_bio_sync(struct bio *bio)
+{
+ if (bio_data_dir(bio) == READ || bio_sync(bio))
+ return 1;
+
+ return 0;
+}
/*
* scheduler run of queue, if there are requests pending and no one in the
@@ -221,44 +243,31 @@ static int cfq_queue_empty(request_queue_t *q)
return !cfqd->busy_queues;
}
-static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync)
-{
- /*
- * Use the per-process queue, for read requests and syncronous writes
- */
- if (!(rw & REQ_RW) || is_sync)
- return task->pid;
-
- return CFQ_KEY_ASYNC;
-}
-
/*
* Scale schedule slice based on io priority. Use the sync time slice only
* if a queue is marked sync and has sync io queued. A sync queue with async
* io only, should not get full sync slice length.
*/
-static inline int
-cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static inline int cfq_prio_slice(struct cfq_data *cfqd, int sync,
+ unsigned short prio)
{
- const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+ const int base_slice = cfqd->cfq_slice[sync];
- WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+ WARN_ON(prio >= IOPRIO_BE_NR);
+
+ return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - prio));
+}
- return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio);
}
static inline void
cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
- cfqq->slice_end += cfqq->slice_resid;
-
- /*
- * Don't carry over residual for more than one slice, we only want
- * to slightly correct the fairness. Carrying over forever would
- * easily introduce oscillations.
- */
- cfqq->slice_resid = 0;
}
/*
@@ -307,7 +316,7 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
s1 = rq1->sector;
s2 = rq2->sector;
- last = cfqd->last_sector;
+ last = cfqd->last_position;
/*
* by definition, 1KiB is 2 sectors
@@ -372,6 +381,26 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
}
/*
+ * The below is leftmost cache rbtree addon
+ */
+static struct rb_node *cfq_rb_first(struct cfq_rb_root *root)
+{
+ if (!root->left)
+ root->left = rb_first(&root->rb);
+
+ return root->left;
+}
+
+static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root)
+{
+ if (root->left == n)
+ root->left = NULL;
+
+ rb_erase(n, &root->rb);
+ RB_CLEAR_NODE(n);
+}
+
+/*
* would be nice to take fifo expire time into account as well
*/
static struct request *
@@ -398,78 +427,96 @@ cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
return cfq_choose_req(cfqd, next, prev);
}
-static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
+static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
+ struct cfq_queue *cfqq)
{
- struct cfq_data *cfqd = cfqq->cfqd;
- struct list_head *list, *n;
- struct cfq_queue *__cfqq;
-
/*
- * Resorting requires the cfqq to be on the RR list already.
+ * just an approximation, should be ok.
*/
- if (!cfq_cfqq_on_rr(cfqq))
- return;
+ return (cfqd->busy_queues - 1) * (cfq_prio_slice(cfqd, 1, 0) -
+ cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio));
+}
- list_del(&cfqq->cfq_list);
+/*
+ * The cfqd->service_tree holds all pending cfq_queue's that have
+ * requests waiting to be processed. It is sorted in the order that
+ * we will service the queues.
+ */
+static void cfq_service_tree_add(struct cfq_data *cfqd,
+ struct cfq_queue *cfqq, int add_front)
+{
+ struct rb_node **p = &cfqd->service_tree.rb.rb_node;
+ struct rb_node *parent = NULL;
+ unsigned long rb_key;
+ int left;
+
+ if (!add_front) {
+ rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
+ rb_key += cfqq->slice_resid;
+ cfqq->slice_resid = 0;
+ } else
+ rb_key = 0;
- if (cfq_class_rt(cfqq))
- list = &cfqd->cur_rr;
- else if (cfq_class_idle(cfqq))
- list = &cfqd->idle_rr;
- else {
+ if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
/*
- * if cfqq has requests in flight, don't allow it to be
- * found in cfq_set_active_queue before it has finished them.
- * this is done to increase fairness between a process that
- * has lots of io pending vs one that only generates one
- * sporadically or synchronously
+ * same position, nothing more to do
*/
- if (cfq_cfqq_dispatched(cfqq))
- list = &cfqd->busy_rr;
- else
- list = &cfqd->rr_list[cfqq->ioprio];
+ if (rb_key == cfqq->rb_key)
+ return;
+
+ cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
}
- if (preempted || cfq_cfqq_queue_new(cfqq)) {
- /*
- * If this queue was preempted or is new (never been serviced),
- * let it be added first for fairness but beind other new
- * queues.
- */
- n = list;
- while (n->next != list) {
- __cfqq = list_entry_cfqq(n->next);
- if (!cfq_cfqq_queue_new(__cfqq))
- break;
+ left = 1;
+ while (*p) {
+ struct cfq_queue *__cfqq;
+ struct rb_node **n;
+
+ parent = *p;
+ __cfqq = rb_entry(parent, struct cfq_queue, rb_node);
- n = n->next;
- }
- list_add_tail(&cfqq->cfq_list, n);
- } else if (!cfq_cfqq_class_sync(cfqq)) {
- /*
- * async queue always goes to the end. this wont be overly
- * unfair to writes, as the sort of the sync queue wont be
- * allowed to pass the async queue again.
- */
- list_add_tail(&cfqq->cfq_list, list);
- } else {
/*
- * sort by last service, but don't cross a new or async
- * queue. we don't cross a new queue because it hasn't been
- * service before, and we don't cross an async queue because
- * it gets added to the end on expire.
+ * sort RT queues first, we always want to give
+ * preference to them. IDLE queues goes to the back.
+ * after that, sort on the next service time.
*/
- n = list;
- while ((n = n->prev) != list) {
- struct cfq_queue *__cfqq = list_entry_cfqq(n);
+ if (cfq_class_rt(cfqq) > cfq_class_rt(__cfqq))
+ n = &(*p)->rb_left;
+ else if (cfq_class_rt(cfqq) < cfq_class_rt(__cfqq))
+ n = &(*p)->rb_right;
+ else if (cfq_class_idle(cfqq) < cfq_class_idle(__cfqq))
+ n = &(*p)->rb_left;
+ else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq))
+ n = &(*p)->rb_right;
+ else if (rb_key < __cfqq->rb_key)
+ n = &(*p)->rb_left;
+ else
+ n = &(*p)->rb_right;
- if (!cfq_cfqq_class_sync(cfqq) || !__cfqq->service_last)
- break;
- if (time_before(__cfqq->service_last, cfqq->service_last))
- break;
- }
- list_add(&cfqq->cfq_list, n);
+ if (n == &(*p)->rb_right)
+ left = 0;
+
+ p = n;
}
+
+ if (left)
+ cfqd->service_tree.left = &cfqq->rb_node;
+
+ cfqq->rb_key = rb_key;
+ rb_link_node(&cfqq->rb_node, parent, p);
+ rb_insert_color(&cfqq->rb_node, &cfqd->service_tree.rb);
+}
+
+/*
+ * Update cfqq's position in the service tree.
+ */
+static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ /*
+ * Resorting requires the cfqq to be on the RR list already.
+ */
+ if (cfq_cfqq_on_rr(cfqq))
+ cfq_service_tree_add(cfqd, cfqq, 0);
}
/*
@@ -483,15 +530,21 @@ cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfq_mark_cfqq_on_rr(cfqq);
cfqd->busy_queues++;
- cfq_resort_rr_list(cfqq, 0);
+ cfq_resort_rr_list(cfqd, cfqq);
}
+/*
+ * Called when the cfqq no longer has requests pending, remove it from
+ * the service tree.
+ */
static inline void
cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
BUG_ON(!cfq_cfqq_on_rr(cfqq));
cfq_clear_cfqq_on_rr(cfqq);
- list_del_init(&cfqq->cfq_list);
+
+ if (!RB_EMPTY_NODE(&cfqq->rb_node))
+ cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree);
BUG_ON(!cfqd->busy_queues);
cfqd->busy_queues--;
@@ -552,10 +605,14 @@ static struct request *
cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
{
struct task_struct *tsk = current;
- pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio));
+ struct cfq_io_context *cic;
struct cfq_queue *cfqq;
- cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+ cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+ if (!cic)
+ return NULL;
+
+ cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
if (cfqq) {
sector_t sector = bio->bi_sector + bio_sectors(bio);
@@ -579,6 +636,8 @@ static void cfq_activate_request(request_queue_t *q, struct request *rq)
*/
if (!cfqd->hw_tag && cfqd->rq_in_driver > 4)
cfqd->hw_tag = 1;
+
+ cfqd->last_position = rq->hard_sector + rq->hard_nr_sectors;
}
static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
@@ -605,8 +664,7 @@ static void cfq_remove_request(struct request *rq)
}
}
-static int
-cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
+static int cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct request *__rq;
@@ -648,23 +706,24 @@ static int cfq_allow_merge(request_queue_t *q, struct request *rq,
struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- const int rw = bio_data_dir(bio);
+ struct cfq_io_context *cic;
struct cfq_queue *cfqq;
- pid_t key;
/*
* Disallow merge of a sync bio into an async request.
*/
- if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq))
+ if (cfq_bio_sync(bio) && !rq_is_sync(rq))
return 0;
/*
* Lookup the cfqq that this bio will be queued with. Allow
* merge only if rq is queued there.
*/
- key = cfq_queue_pid(current, rw, bio_sync(bio));
- cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio);
+ cic = cfq_cic_rb_lookup(cfqd, current->io_context);
+ if (!cic)
+ return 0;
+ cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
if (cfqq == RQ_CFQQ(rq))
return 1;
@@ -684,6 +743,7 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfq_clear_cfqq_must_alloc_slice(cfqq);
cfq_clear_cfqq_fifo_expire(cfqq);
cfq_mark_cfqq_slice_new(cfqq);
+ cfq_clear_cfqq_queue_new(cfqq);
}
cfqd->active_queue = cfqq;
@@ -694,23 +754,21 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
*/
static void
__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- int preempted, int timed_out)
+ int timed_out)
{
if (cfq_cfqq_wait_request(cfqq))
del_timer(&cfqd->idle_slice_timer);
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
- cfq_clear_cfqq_queue_new(cfqq);
/*
- * store what was left of this slice, if the queue idled out
- * or was preempted
+ * store what was left of this slice, if the queue idled/timed out
*/
if (timed_out && !cfq_cfqq_slice_new(cfqq))
cfqq->slice_resid = cfqq->slice_end - jiffies;
- cfq_resort_rr_list(cfqq, preempted);
+ cfq_resort_rr_list(cfqd, cfqq);
if (cfqq == cfqd->active_queue)
cfqd->active_queue = NULL;
@@ -719,163 +777,152 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
put_io_context(cfqd->active_cic->ioc);
cfqd->active_cic = NULL;
}
-
- cfqd->dispatch_slice = 0;
}
-static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted,
- int timed_out)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
{
struct cfq_queue *cfqq = cfqd->active_queue;
if (cfqq)
- __cfq_slice_expired(cfqd, cfqq, preempted, timed_out);
+ __cfq_slice_expired(cfqd, cfqq, timed_out);
}
/*
- * 0
- * 0,1
- * 0,1,2
- * 0,1,2,3
- * 0,1,2,3,4
- * 0,1,2,3,4,5
- * 0,1,2,3,4,5,6
- * 0,1,2,3,4,5,6,7
+ * Get next queue for service. Unless we have a queue preemption,
+ * we'll simply select the first cfqq in the service tree.
*/
-static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd)
{
- int prio, wrap;
+ struct cfq_queue *cfqq;
+ struct rb_node *n;
- prio = -1;
- wrap = 0;
- do {
- int p;
+ if (RB_EMPTY_ROOT(&cfqd->service_tree.rb))
+ return NULL;
- for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
- if (!list_empty(&cfqd->rr_list[p])) {
- prio = p;
- break;
- }
- }
+ n = cfq_rb_first(&cfqd->service_tree);
+ cfqq = rb_entry(n, struct cfq_queue, rb_node);
- if (prio != -1)
- break;
- cfqd->cur_prio = 0;
- if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
- cfqd->cur_end_prio = 0;
- if (wrap)
- break;
- wrap = 1;
- }
- } while (1);
+ if (cfq_class_idle(cfqq)) {
+ unsigned long end;
- if (unlikely(prio == -1))
- return -1;
+ /*
+ * if we have idle queues and no rt or be queues had
+ * pending requests, either allow immediate service if
+ * the grace period has passed or arm the idle grace
+ * timer
+ */
+ end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+ if (time_before(jiffies, end)) {
+ mod_timer(&cfqd->idle_class_timer, end);
+ cfqq = NULL;
+ }
+ }
- BUG_ON(prio >= CFQ_PRIO_LISTS);
+ return cfqq;
+}
- list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+/*
+ * Get and set a new active queue for service.
+ */
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+ struct cfq_queue *cfqq;
- cfqd->cur_prio = prio + 1;
- if (cfqd->cur_prio > cfqd->cur_end_prio) {
- cfqd->cur_end_prio = cfqd->cur_prio;
- cfqd->cur_prio = 0;
- }
- if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
- cfqd->cur_prio = 0;
- cfqd->cur_end_prio = 0;
- }
+ cfqq = cfq_get_next_queue(cfqd);
+ __cfq_set_active_queue(cfqd, cfqq);
+ return cfqq;
+}
- return prio;
+static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd,
+ struct request *rq)
+{
+ if (rq->sector >= cfqd->last_position)
+ return rq->sector - cfqd->last_position;
+ else
+ return cfqd->last_position - rq->sector;
}
-static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq)
{
- struct cfq_queue *cfqq = NULL;
+ struct cfq_io_context *cic = cfqd->active_cic;
- if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1) {
- /*
- * if current list is non-empty, grab first entry. if it is
- * empty, get next prio level and grab first entry then if any
- * are spliced
- */
- cfqq = list_entry_cfqq(cfqd->cur_rr.next);
- } else if (!list_empty(&cfqd->busy_rr)) {
- /*
- * If no new queues are available, check if the busy list has
- * some before falling back to idle io.
- */
- cfqq = list_entry_cfqq(cfqd->busy_rr.next);
- } else if (!list_empty(&cfqd->idle_rr)) {
- /*
- * if we have idle queues and no rt or be queues had pending
- * requests, either allow immediate service if the grace period
- * has passed or arm the idle grace timer
- */
- unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+ if (!sample_valid(cic->seek_samples))
+ return 0;
- if (time_after_eq(jiffies, end))
- cfqq = list_entry_cfqq(cfqd->idle_rr.next);
- else
- mod_timer(&cfqd->idle_class_timer, end);
- }
+ return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean;
+}
- __cfq_set_active_queue(cfqd, cfqq);
- return cfqq;
+static int cfq_close_cooperator(struct cfq_data *cfq_data,
+ struct cfq_queue *cfqq)
+{
+ /*
+ * We should notice if some of the queues are cooperating, eg
+ * working closely on the same area of the disk. In that case,
+ * we can group them together and don't waste time idling.
+ */
+ return 0;
}
-#define CIC_SEEKY(cic) ((cic)->seek_mean > (128 * 1024))
+#define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024))
-static int cfq_arm_slice_timer(struct cfq_data *cfqd)
+static void cfq_arm_slice_timer(struct cfq_data *cfqd)
{
struct cfq_queue *cfqq = cfqd->active_queue;
struct cfq_io_context *cic;
unsigned long sl;
WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list));
+ WARN_ON(cfq_cfqq_slice_new(cfqq));
/*
* idle is disabled, either manually or by past process history
*/
- if (!cfqd->cfq_slice_idle)
- return 0;
- if (!cfq_cfqq_idle_window(cfqq))
- return 0;
+ if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq))
+ return;
+
/*
* task has exited, don't wait
*/
cic = cfqd->active_cic;
if (!cic || !cic->ioc->task)
- return 0;
+ return;
+
+ /*
+ * See if this prio level has a good candidate
+ */
+ if (cfq_close_cooperator(cfqd, cfqq) &&
+ (sample_valid(cic->ttime_samples) && cic->ttime_mean > 2))
+ return;
cfq_mark_cfqq_must_dispatch(cfqq);
cfq_mark_cfqq_wait_request(cfqq);
- sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
-
/*
* we don't want to idle for seeks, but we do want to allow
* fair distribution of slice time for a process doing back-to-back
* seeks. so allow a little bit of time for him to submit a new rq
*/
+ sl = cfqd->cfq_slice_idle;
if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
- sl = min(sl, msecs_to_jiffies(2));
+ sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT));
mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
- return 1;
}
+/*
+ * Move request from internal lists to the request queue dispatch list.
+ */
static void cfq_dispatch_insert(request_queue_t *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_queue *cfqq = RQ_CFQQ(rq);
cfq_remove_request(rq);
- cfqq->on_dispatch[rq_is_sync(rq)]++;
+ cfqq->dispatched++;
elv_dispatch_sort(q, rq);
- rq = list_entry(q->queue_head.prev, struct request, queuelist);
- cfqd->last_sector = rq->sector + rq->nr_sectors;
+ if (cfq_cfqq_sync(cfqq))
+ cfqd->sync_flight++;
}
/*
@@ -895,13 +942,13 @@ static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq)
if (list_empty(&cfqq->fifo))
return NULL;
- fifo = cfq_cfqq_class_sync(cfqq);
+ fifo = cfq_cfqq_sync(cfqq);
rq = rq_entry_fifo(cfqq->fifo.next);
- if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
- return rq;
+ if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
+ return NULL;
- return NULL;
+ return rq;
}
static inline int
@@ -915,7 +962,8 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
}
/*
- * get next queue for service
+ * Select a queue for service. If we have a current active queue,
+ * check whether to continue servicing it, or retrieve and set a new one.
*/
static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
{
@@ -926,33 +974,41 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
goto new_queue;
/*
- * slice has expired
+ * The active queue has run out of time, expire it and select new.
*/
- if (!cfq_cfqq_must_dispatch(cfqq) && cfq_slice_used(cfqq))
+ if (cfq_slice_used(cfqq))
goto expire;
/*
- * if queue has requests, dispatch one. if not, check if
- * enough slice is left to wait for one
+ * The active queue has requests and isn't expired, allow it to
+ * dispatch.
*/
if (!RB_EMPTY_ROOT(&cfqq->sort_list))
goto keep_queue;
- else if (cfq_cfqq_slice_new(cfqq) || cfq_cfqq_dispatched(cfqq)) {
+
+ /*
+ * No requests pending. If the active queue still has requests in
+ * flight or is idling for a new request, allow either of these
+ * conditions to happen (or time out) before selecting a new queue.
+ */
+ if (timer_pending(&cfqd->idle_slice_timer) ||
+ (cfqq->dispatched && cfq_cfqq_idle_window(cfqq))) {
cfqq = NULL;
goto keep_queue;
- } else if (cfq_cfqq_class_sync(cfqq)) {
- if (cfq_arm_slice_timer(cfqd))
- return NULL;
}
expire:
- cfq_slice_expired(cfqd, 0, 0);
+ cfq_slice_expired(cfqd, 0);
new_queue:
cfqq = cfq_set_active_queue(cfqd);
keep_queue:
return cfqq;
}
+/*
+ * Dispatch some requests from cfqq, moving them to the request queue
+ * dispatch list.
+ */
static int
__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
int max_dispatch)
@@ -975,7 +1031,6 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
*/
cfq_dispatch_insert(cfqd->queue, rq);
- cfqd->dispatch_slice++;
dispatched++;
if (!cfqd->active_cic) {
@@ -993,57 +1048,54 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
* queue always expire after 1 dispatch round.
*/
if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) &&
- cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+ dispatched >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
cfq_class_idle(cfqq))) {
cfqq->slice_end = jiffies + 1;
- cfq_slice_expired(cfqd, 0, 0);
+ cfq_slice_expired(cfqd, 0);
}
return dispatched;
}
-static int
-cfq_forced_dispatch_cfqqs(struct list_head *list)
+static inline int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq)
{
- struct cfq_queue *cfqq, *next;
- int dispatched;
+ int dispatched = 0;
- dispatched = 0;
- list_for_each_entry_safe(cfqq, next, list, cfq_list) {
- while (cfqq->next_rq) {
- cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
- dispatched++;
- }
- BUG_ON(!list_empty(&cfqq->fifo));
+ while (cfqq->next_rq) {
+ cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
+ dispatched++;
}
+ BUG_ON(!list_empty(&cfqq->fifo));
return dispatched;
}
-static int
-cfq_forced_dispatch(struct cfq_data *cfqd)
+/*
+ * Drain our current requests. Used for barriers and when switching
+ * io schedulers on-the-fly.
+ */
+static int cfq_forced_dispatch(struct cfq_data *cfqd)
{
- int i, dispatched = 0;
+ int dispatched = 0;
+ struct rb_node *n;
- for (i = 0; i < CFQ_PRIO_LISTS; i++)
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->rr_list[i]);
+ while ((n = cfq_rb_first(&cfqd->service_tree)) != NULL) {
+ struct cfq_queue *cfqq = rb_entry(n, struct cfq_queue, rb_node);
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->busy_rr);
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->cur_rr);
- dispatched += cfq_forced_dispatch_cfqqs(&cfqd->idle_rr);
+ dispatched += __cfq_forced_dispatch_cfqq(cfqq);
+ }
- cfq_slice_expired(cfqd, 0, 0);
+ cfq_slice_expired(cfqd, 0);
BUG_ON(cfqd->busy_queues);
return dispatched;
}
-static int
-cfq_dispatch_requests(request_queue_t *q, int force)
+static int cfq_dispatch_requests(request_queue_t *q, int force)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq, *prev_cfqq;
+ struct cfq_queue *cfqq;
int dispatched;
if (!cfqd->busy_queues)
@@ -1053,36 +1105,28 @@ cfq_dispatch_requests(request_queue_t *q, int force)
return cfq_forced_dispatch(cfqd);
dispatched = 0;
- prev_cfqq = NULL;
while ((cfqq = cfq_select_queue(cfqd)) != NULL) {
int max_dispatch;
- if (cfqd->busy_queues > 1) {
- /*
- * Don't repeat dispatch from the previous queue.
- */
- if (prev_cfqq == cfqq)
- break;
+ max_dispatch = cfqd->cfq_quantum;
+ if (cfq_class_idle(cfqq))
+ max_dispatch = 1;
- /*
- * So we have dispatched before in this round, if the
- * next queue has idling enabled (must be sync), don't
- * allow it service until the previous have continued.
- */
- if (cfqd->rq_in_driver && cfq_cfqq_idle_window(cfqq))
+ if (cfqq->dispatched >= max_dispatch) {
+ if (cfqd->busy_queues > 1)
+ break;
+ if (cfqq->dispatched >= 4 * max_dispatch)
break;
}
+ if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
+ break;
+
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
del_timer(&cfqd->idle_slice_timer);
- max_dispatch = cfqd->cfq_quantum;
- if (cfq_class_idle(cfqq))
- max_dispatch = 1;
-
dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
- prev_cfqq = cfqq;
}
return dispatched;
@@ -1108,48 +1152,21 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
BUG_ON(cfq_cfqq_on_rr(cfqq));
if (unlikely(cfqd->active_queue == cfqq)) {
- __cfq_slice_expired(cfqd, cfqq, 0, 0);
+ __cfq_slice_expired(cfqd, cfqq, 0);
cfq_schedule_dispatch(cfqd);
}
- /*
- * it's on the empty list and still hashed
- */
- list_del(&cfqq->cfq_list);
- hlist_del(&cfqq->cfq_hash);
kmem_cache_free(cfq_pool, cfqq);
}
-static struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
- const int hashval)
-{
- struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
- struct hlist_node *entry;
- struct cfq_queue *__cfqq;
-
- hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
- const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
-
- if (__cfqq->key == key && (__p == prio || !prio))
- return __cfqq;
- }
-
- return NULL;
-}
-
-static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
-{
- return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
-}
-
static void cfq_free_io_context(struct io_context *ioc)
{
struct cfq_io_context *__cic;
struct rb_node *n;
int freed = 0;
+ ioc->ioc_data = NULL;
+
while ((n = rb_first(&ioc->cic_root)) != NULL) {
__cic = rb_entry(n, struct cfq_io_context, rb_node);
rb_erase(&__cic->rb_node, &ioc->cic_root);
@@ -1166,7 +1183,7 @@ static void cfq_free_io_context(struct io_context *ioc)
static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
if (unlikely(cfqq == cfqd->active_queue)) {
- __cfq_slice_expired(cfqd, cfqq, 0, 0);
+ __cfq_slice_expired(cfqd, cfqq, 0);
cfq_schedule_dispatch(cfqd);
}
@@ -1191,10 +1208,6 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
}
}
-
-/*
- * Called with interrupts disabled
- */
static void cfq_exit_single_io_context(struct cfq_io_context *cic)
{
struct cfq_data *cfqd = cic->key;
@@ -1208,15 +1221,20 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
}
}
+/*
+ * The process that ioc belongs to has exited, we need to clean up
+ * and put the internal structures we have that belongs to that process.
+ */
static void cfq_exit_io_context(struct io_context *ioc)
{
struct cfq_io_context *__cic;
struct rb_node *n;
+ ioc->ioc_data = NULL;
+
/*
* put the reference this task is holding to the various queues
*/
-
n = rb_first(&ioc->cic_root);
while (n != NULL) {
__cic = rb_entry(n, struct cfq_io_context, rb_node);
@@ -1284,8 +1302,6 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq)
*/
cfqq->org_ioprio = cfqq->ioprio;
cfqq->org_ioprio_class = cfqq->ioprio_class;
-
- cfq_resort_rr_list(cfqq, 0);
cfq_clear_cfqq_prio_changed(cfqq);
}
@@ -1303,7 +1319,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
cfqq = cic->cfqq[ASYNC];
if (cfqq) {
struct cfq_queue *new_cfqq;
- new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task,
+ new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task,
GFP_ATOMIC);
if (new_cfqq) {
cic->cfqq[ASYNC] = new_cfqq;
@@ -1335,16 +1351,16 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
}
static struct cfq_queue *
-cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk,
+cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
gfp_t gfp_mask)
{
- const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
struct cfq_queue *cfqq, *new_cfqq = NULL;
- unsigned short ioprio;
+ struct cfq_io_context *cic;
retry:
- ioprio = tsk->ioprio;
- cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+ cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+ /* cic always exists here */
+ cfqq = cic_to_cfqq(cic, is_sync);
if (!cfqq) {
if (new_cfqq) {
@@ -1369,20 +1385,20 @@ retry:
memset(cfqq, 0, sizeof(*cfqq));
- INIT_HLIST_NODE(&cfqq->cfq_hash);
- INIT_LIST_HEAD(&cfqq->cfq_list);
+ RB_CLEAR_NODE(&cfqq->rb_node);
INIT_LIST_HEAD(&cfqq->fifo);
- cfqq->key = key;
- hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
atomic_set(&cfqq->ref, 0);
cfqq->cfqd = cfqd;
- if (key != CFQ_KEY_ASYNC)
+ if (is_sync) {
cfq_mark_cfqq_idle_window(cfqq);
+ cfq_mark_cfqq_sync(cfqq);
+ }
cfq_mark_cfqq_prio_changed(cfqq);
cfq_mark_cfqq_queue_new(cfqq);
+
cfq_init_prio_data(cfqq);
}
@@ -1395,10 +1411,17 @@ out:
return cfqq;
}
+/*
+ * We drop cfq io contexts lazily, so we may find a dead one.
+ */
static void
cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
{
WARN_ON(!list_empty(&cic->queue_list));
+
+ if (ioc->ioc_data == cic)
+ ioc->ioc_data = NULL;
+
rb_erase(&cic->rb_node, &ioc->cic_root);
kmem_cache_free(cfq_ioc_pool, cic);
elv_ioc_count_dec(ioc_count);
@@ -1411,6 +1434,16 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
struct cfq_io_context *cic;
void *k, *key = cfqd;
+ if (unlikely(!ioc))
+ return NULL;
+
+ /*
+ * we maintain a last-hit cache, to avoid browsing over the tree
+ */
+ cic = ioc->ioc_data;
+ if (cic && cic->key == cfqd)
+ return cic;
+
restart:
n = ioc->cic_root.rb_node;
while (n) {
@@ -1426,8 +1459,10 @@ restart:
n = n->rb_left;
else if (key > k)
n = n->rb_right;
- else
+ else {
+ ioc->ioc_data = cic;
return cic;
+ }
}
return NULL;
@@ -1524,7 +1559,8 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
}
static void
-cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
+cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
+ struct request *rq)
{
sector_t sdist;
u64 total;
@@ -1534,6 +1570,11 @@ cfq_update_io_seektime(struct cfq_io_context *cic, struct request *rq)
else
sdist = cic->last_request_pos - rq->sector;
+ if (!cic->seek_samples) {
+ cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
+ cfqd->new_seek_mean = cfqd->new_seek_total / 256;
+ }
+
/*
* Don't allow the seek distance to get too large from the
* odd fragment, pagein, etc
@@ -1558,7 +1599,12 @@ static void
cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_io_context *cic)
{
- int enable_idle = cfq_cfqq_idle_window(cfqq);
+ int enable_idle;
+
+ if (!cfq_cfqq_sync(cfqq))
+ return;
+
+ enable_idle = cfq_cfqq_idle_window(cfqq);
if (!cic->ioc->task || !cfqd->cfq_slice_idle ||
(cfqd->hw_tag && CIC_SEEKY(cic)))
@@ -1584,24 +1630,28 @@ static int
cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
struct request *rq)
{
- struct cfq_queue *cfqq = cfqd->active_queue;
+ struct cfq_queue *cfqq;
- if (cfq_class_idle(new_cfqq))
+ cfqq = cfqd->active_queue;
+ if (!cfqq)
return 0;
- if (!cfqq)
+ if (cfq_slice_used(cfqq))
+ return 1;
+
+ if (cfq_class_idle(new_cfqq))
return 0;
if (cfq_class_idle(cfqq))
return 1;
- if (!cfq_cfqq_wait_request(new_cfqq))
- return 0;
+
/*
* if the new request is sync, but the currently running queue is
* not, let the sync request have priority.
*/
if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
return 1;
+
/*
* So both queues are sync. Let the new request get disk time if
* it's a metadata request and the current queue is doing regular IO.
@@ -1609,6 +1659,16 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
if (rq_is_meta(rq) && !cfqq->meta_pending)
return 1;
+ if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq))
+ return 0;
+
+ /*
+ * if this request is as-good as one we would expect from the
+ * current cfqq, let it preempt
+ */
+ if (cfq_rq_close(cfqd, rq))
+ return 1;
+
return 0;
}
@@ -1618,14 +1678,15 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
*/
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- cfq_slice_expired(cfqd, 1, 1);
+ cfq_slice_expired(cfqd, 1);
/*
* Put the new queue at the front of the of the current list,
* so we know that it will be selected next.
*/
BUG_ON(!cfq_cfqq_on_rr(cfqq));
- list_move(&cfqq->cfq_list, &cfqd->cur_rr);
+
+ cfq_service_tree_add(cfqd, cfqq, 1);
cfqq->slice_end = 0;
cfq_mark_cfqq_slice_new(cfqq);
@@ -1644,28 +1705,12 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (rq_is_meta(rq))
cfqq->meta_pending++;
- /*
- * we never wait for an async request and we don't allow preemption
- * of an async request. so just return early
- */
- if (!rq_is_sync(rq)) {
- /*
- * sync process issued an async request, if it's waiting
- * then expire it and kick rq handling.
- */
- if (cic == cfqd->active_cic &&
- del_timer(&cfqd->idle_slice_timer)) {
- cfq_slice_expired(cfqd, 0, 0);
- blk_start_queueing(cfqd->queue);
- }
- return;
- }
-
cfq_update_io_thinktime(cfqd, cic);
- cfq_update_io_seektime(cic, rq);
+ cfq_update_io_seektime(cfqd, cic, rq);
cfq_update_idle_window(cfqd, cfqq, cic);
cic->last_request_pos = rq->sector + rq->nr_sectors;
+ cfqq->last_request_pos = cic->last_request_pos;
if (cfqq == cfqd->active_queue) {
/*
@@ -1714,16 +1759,16 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
now = jiffies;
WARN_ON(!cfqd->rq_in_driver);
- WARN_ON(!cfqq->on_dispatch[sync]);
+ WARN_ON(!cfqq->dispatched);
cfqd->rq_in_driver--;
- cfqq->on_dispatch[sync]--;
- cfqq->service_last = now;
+ cfqq->dispatched--;
+
+ if (cfq_cfqq_sync(cfqq))
+ cfqd->sync_flight--;
if (!cfq_class_idle(cfqq))
cfqd->last_end_request = now;
- cfq_resort_rr_list(cfqq, 0);
-
if (sync)
RQ_CIC(rq)->last_end_request = now;
@@ -1737,12 +1782,13 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
cfq_clear_cfqq_slice_new(cfqq);
}
if (cfq_slice_used(cfqq))
- cfq_slice_expired(cfqd, 0, 1);
- else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list)) {
- if (!cfq_arm_slice_timer(cfqd))
- cfq_schedule_dispatch(cfqd);
- }
+ cfq_slice_expired(cfqd, 1);
+ else if (sync && RB_EMPTY_ROOT(&cfqq->sort_list))
+ cfq_arm_slice_timer(cfqd);
}
+
+ if (!cfqd->rq_in_driver)
+ cfq_schedule_dispatch(cfqd);
}
/*
@@ -1751,9 +1797,6 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
*/
static void cfq_prio_boost(struct cfq_queue *cfqq)
{
- const int ioprio_class = cfqq->ioprio_class;
- const int ioprio = cfqq->ioprio;
-
if (has_fs_excl()) {
/*
* boost idle prio on transactions that would lock out other
@@ -1772,12 +1815,6 @@ static void cfq_prio_boost(struct cfq_queue *cfqq)
if (cfqq->ioprio != cfqq->org_ioprio)
cfqq->ioprio = cfqq->org_ioprio;
}
-
- /*
- * refile between round-robin lists if we moved the priority class
- */
- if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio))
- cfq_resort_rr_list(cfqq, 0);
}
static inline int __cfq_may_queue(struct cfq_queue *cfqq)
@@ -1795,10 +1832,8 @@ static int cfq_may_queue(request_queue_t *q, int rw)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
+ struct cfq_io_context *cic;
struct cfq_queue *cfqq;
- unsigned int key;
-
- key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC);
/*
* don't force setup of a queue from here, as a call to may_queue
@@ -1806,7 +1841,11 @@ static int cfq_may_queue(request_queue_t *q, int rw)
* so just lookup a possibly existing queue, or return 'may queue'
* if that fails
*/
- cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
+ cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
+ if (!cic)
+ return ELV_MQUEUE_MAY;
+
+ cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC);
if (cfqq) {
cfq_init_prio_data(cfqq);
cfq_prio_boost(cfqq);
@@ -1850,7 +1889,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
const int is_sync = rq_is_sync(rq);
- pid_t key = cfq_queue_pid(tsk, rw, is_sync);
struct cfq_queue *cfqq;
unsigned long flags;
@@ -1863,14 +1901,15 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
if (!cic)
goto queue_fail;
- if (!cic->cfqq[is_sync]) {
- cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask);
+ cfqq = cic_to_cfqq(cic, is_sync);
+ if (!cfqq) {
+ cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask);
+
if (!cfqq)
goto queue_fail;
- cic->cfqq[is_sync] = cfqq;
- } else
- cfqq = cic->cfqq[is_sync];
+ cic_set_cfqq(cic, cfqq, is_sync);
+ }
cfqq->allocated[rw]++;
cfq_clear_cfqq_must_alloc(cfqq);
@@ -1940,7 +1979,7 @@ static void cfq_idle_slice_timer(unsigned long data)
}
}
expire:
- cfq_slice_expired(cfqd, 0, timed_out);
+ cfq_slice_expired(cfqd, timed_out);
out_kick:
cfq_schedule_dispatch(cfqd);
out_cont:
@@ -1986,7 +2025,7 @@ static void cfq_exit_queue(elevator_t *e)
spin_lock_irq(q->queue_lock);
if (cfqd->active_queue)
- __cfq_slice_expired(cfqd, cfqd->active_queue, 0, 0);
+ __cfq_slice_expired(cfqd, cfqd->active_queue, 0);
while (!list_empty(&cfqd->cic_list)) {
struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
@@ -2000,14 +2039,12 @@ static void cfq_exit_queue(elevator_t *e)
cfq_shutdown_timer_wq(cfqd);
- kfree(cfqd->cfq_hash);
kfree(cfqd);
}
static void *cfq_init_queue(request_queue_t *q)
{
struct cfq_data *cfqd;
- int i;
cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
if (!cfqd)
@@ -2015,21 +2052,9 @@ static void *cfq_init_queue(request_queue_t *q)
memset(cfqd, 0, sizeof(*cfqd));
- for (i = 0; i < CFQ_PRIO_LISTS; i++)
- INIT_LIST_HEAD(&cfqd->rr_list[i]);
-
- INIT_LIST_HEAD(&cfqd->busy_rr);
- INIT_LIST_HEAD(&cfqd->cur_rr);
- INIT_LIST_HEAD(&cfqd->idle_rr);
+ cfqd->service_tree = CFQ_RB_ROOT;
INIT_LIST_HEAD(&cfqd->cic_list);
- cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
- if (!cfqd->cfq_hash)
- goto out_free;
-
- for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
- INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
-
cfqd->queue = q;
init_timer(&cfqd->idle_slice_timer);
@@ -2053,9 +2078,6 @@ static void *cfq_init_queue(request_queue_t *q)
cfqd->cfq_slice_idle = cfq_slice_idle;
return cfqd;
-out_free:
- kfree(cfqd);
- return NULL;
}
static void cfq_slab_kill(void)
@@ -2068,13 +2090,11 @@ static void cfq_slab_kill(void)
static int __init cfq_slab_setup(void)
{
- cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
- NULL, NULL);
+ cfq_pool = KMEM_CACHE(cfq_queue, 0);
if (!cfq_pool)
goto fail;
- cfq_ioc_pool = kmem_cache_create("cfq_ioc_pool",
- sizeof(struct cfq_io_context), 0, 0, NULL, NULL);
+ cfq_ioc_pool = KMEM_CACHE(cfq_io_context, 0);
if (!cfq_ioc_pool)
goto fail;
@@ -2087,7 +2107,6 @@ fail:
/*
* sysfs parts below -->
*/
-
static ssize_t
cfq_var_show(unsigned int var, char *page)
{
diff --git a/block/elevator.c b/block/elevator.c
index 96a00c82274..ce866eb75f6 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -134,13 +134,13 @@ static struct elevator_type *elevator_get(const char *name)
{
struct elevator_type *e;
- spin_lock_irq(&elv_list_lock);
+ spin_lock(&elv_list_lock);
e = elevator_find(name);
if (e && !try_module_get(e->elevator_owner))
e = NULL;
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
return e;
}
@@ -965,10 +965,11 @@ void elv_unregister_queue(struct request_queue *q)
int elv_register(struct elevator_type *e)
{
char *def = "";
- spin_lock_irq(&elv_list_lock);
+
+ spin_lock(&elv_list_lock);
BUG_ON(elevator_find(e->elevator_name));
list_add_tail(&e->list, &elv_list);
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
if (!strcmp(e->elevator_name, chosen_elevator) ||
(!*chosen_elevator &&
@@ -998,9 +999,9 @@ void elv_unregister(struct elevator_type *e)
read_unlock(&tasklist_lock);
}
- spin_lock_irq(&elv_list_lock);
+ spin_lock(&elv_list_lock);
list_del_init(&e->list);
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
}
EXPORT_SYMBOL_GPL(elv_unregister);
@@ -1118,7 +1119,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
struct list_head *entry;
int len = 0;
- spin_lock_irq(&elv_list_lock);
+ spin_lock(&elv_list_lock);
list_for_each(entry, &elv_list) {
struct elevator_type *__e;
@@ -1128,7 +1129,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
else
len += sprintf(name+len, "%s ", __e->elevator_name);
}
- spin_unlock_irq(&elv_list_lock);
+ spin_unlock(&elv_list_lock);
len += sprintf(len+name, "\n");
return len;
diff --git a/block/genhd.c b/block/genhd.c
index 441432a142f..93a2cf65459 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -17,7 +17,7 @@
#include <linux/buffer_head.h>
#include <linux/mutex.h>
-struct subsystem block_subsys;
+struct kset block_subsys;
static DEFINE_MUTEX(block_subsys_lock);
/*
@@ -213,6 +213,59 @@ struct gendisk *get_gendisk(dev_t dev, int *part)
return kobj ? to_disk(kobj) : NULL;
}
+/*
+ * print a full list of all partitions - intended for places where the root
+ * filesystem can't be mounted and thus to give the victim some idea of what
+ * went wrong
+ */
+void __init printk_all_partitions(void)
+{
+ int n;
+ struct gendisk *sgp;
+
+ mutex_lock(&block_subsys_lock);
+ /* For each block device... */
+ list_for_each_entry(sgp, &block_subsys.list, kobj.entry) {
+ char buf[BDEVNAME_SIZE];
+ /*
+ * Don't show empty devices or things that have been surpressed
+ */
+ if (get_capacity(sgp) == 0 ||
+ (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO))
+ continue;
+
+ /*
+ * Note, unlike /proc/partitions, I am showing the numbers in
+ * hex - the same format as the root= option takes.
+ */
+ printk("%02x%02x %10llu %s",
+ sgp->major, sgp->first_minor,
+ (unsigned long long)get_capacity(sgp) >> 1,
+ disk_name(sgp, 0, buf));
+ if (sgp->driverfs_dev != NULL &&
+ sgp->driverfs_dev->driver != NULL)
+ printk(" driver: %s\n",
+ sgp->driverfs_dev->driver->name);
+ else
+ printk(" (driver?)\n");
+
+ /* now show the partitions */
+ for (n = 0; n < sgp->minors - 1; ++n) {
+ if (sgp->part[n] == NULL)
+ continue;
+ if (sgp->part[n]->nr_sects == 0)
+ continue;
+ printk(" %02x%02x %10llu %s\n",
+ sgp->major, n + 1 + sgp->first_minor,
+ (unsigned long long)sgp->part[n]->nr_sects >> 1,
+ disk_name(sgp, n + 1, buf));
+ } /* partition subloop */
+ } /* Block device loop */
+
+ mutex_unlock(&block_subsys_lock);
+ return;
+}
+
#ifdef CONFIG_PROC_FS
/* iterator */
static void *part_start(struct seq_file *part, loff_t *pos)
@@ -221,7 +274,7 @@ static void *part_start(struct seq_file *part, loff_t *pos)
loff_t l = *pos;
mutex_lock(&block_subsys_lock);
- list_for_each(p, &block_subsys.kset.list)
+ list_for_each(p, &block_subsys.list)
if (!l--)
return list_entry(p, struct gendisk, kobj.entry);
return NULL;
@@ -231,7 +284,7 @@ static void *part_next(struct seq_file *part, void *v, loff_t *pos)
{
struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
++*pos;
- return p==&block_subsys.kset.list ? NULL :
+ return p==&block_subsys.list ? NULL :
list_entry(p, struct gendisk, kobj.entry);
}
@@ -246,7 +299,7 @@ static int show_partition(struct seq_file *part, void *v)
int n;
char buf[BDEVNAME_SIZE];
- if (&sgp->kobj.entry == block_subsys.kset.list.next)
+ if (&sgp->kobj.entry == block_subsys.list.next)
seq_puts(part, "major minor #blocks name\n\n");
/* Don't show non-partitionable removeable devices or empty devices */
@@ -565,7 +618,7 @@ static void *diskstats_start(struct seq_file *part, loff_t *pos)
struct list_head *p;
mutex_lock(&block_subsys_lock);
- list_for_each(p, &block_subsys.kset.list)
+ list_for_each(p, &block_subsys.list)
if (!k--)
return list_entry(p, struct gendisk, kobj.entry);
return NULL;
@@ -575,7 +628,7 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
{
struct list_head *p = ((struct gendisk *)v)->kobj.entry.next;
++*pos;
- return p==&block_subsys.kset.list ? NULL :
+ return p==&block_subsys.list ? NULL :
list_entry(p, struct gendisk, kobj.entry);
}
diff --git a/block/ioctl.c b/block/ioctl.c
index e06dbe9bc85..f7e3e8abf88 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -80,7 +80,7 @@ static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user
}
/* all seems OK */
fsync_bdev(bdevp);
- invalidate_bdev(bdevp, 0);
+ invalidate_bdev(bdevp);
mutex_lock_nested(&bdev->bd_mutex, 1);
delete_partition(disk, part);
@@ -236,7 +236,7 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
lock_kernel();
fsync_bdev(bdev);
- invalidate_bdev(bdev, 0);
+ invalidate_bdev(bdev);
unlock_kernel();
return 0;
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 3de06953ac3..17e18897342 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1704,7 +1704,7 @@ EXPORT_SYMBOL(blk_stop_queue);
* on a queue, such as calling the unplug function after a timeout.
* A block device may call blk_sync_queue to ensure that any
* such activity is cancelled, thus allowing it to release resources
- * the the callbacks might use. The caller must already have made sure
+ * that the callbacks might use. The caller must already have made sure
* that its ->make_request_fn will not re-add plugging prior to calling
* this function.
*
@@ -1712,7 +1712,6 @@ EXPORT_SYMBOL(blk_stop_queue);
void blk_sync_queue(struct request_queue *q)
{
del_timer_sync(&q->unplug_timer);
- kblockd_flush();
}
EXPORT_SYMBOL(blk_sync_queue);
@@ -1925,6 +1924,8 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
+ q->sg_reserved_size = INT_MAX;
+
/*
* all done
*/
@@ -2556,6 +2557,7 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf,
bio->bi_rw |= (1 << BIO_RW);
blk_rq_bio_prep(q, rq, bio);
+ blk_queue_bounce(q, &rq->bio);
rq->buffer = rq->data = NULL;
return 0;
}
@@ -3505,7 +3507,7 @@ static int blk_cpu_notify(struct notifier_block *self, unsigned long action,
* If a CPU goes away, splice its entries to the current CPU
* and trigger a run of the softirq
*/
- if (action == CPU_DEAD) {
+ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
int cpu = (unsigned long) hcpu;
local_irq_disable();
@@ -3629,11 +3631,11 @@ int kblockd_schedule_work(struct work_struct *work)
EXPORT_SYMBOL(kblockd_schedule_work);
-void kblockd_flush(void)
+void kblockd_flush_work(struct work_struct *work)
{
- flush_workqueue(kblockd_workqueue);
+ cancel_work_sync(work);
}
-EXPORT_SYMBOL(kblockd_flush);
+EXPORT_SYMBOL(kblockd_flush_work);
int __init blk_dev_init(void)
{
@@ -3741,6 +3743,7 @@ static struct io_context *current_io_context(gfp_t gfp_flags, int node)
ret->nr_batch_requests = 0; /* because this is 0 */
ret->aic = NULL;
ret->cic_root.rb_node = NULL;
+ ret->ioc_data = NULL;
/* make sure set_task_ioprio() sees the settings above */
smp_wmb();
tsk->io_context = ret;
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index 65c6a3cba6d..e83f1dbf7c2 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -78,7 +78,9 @@ static int sg_set_timeout(request_queue_t *q, int __user *p)
static int sg_get_reserved_size(request_queue_t *q, int __user *p)
{
- return put_user(q->sg_reserved_size, p);
+ unsigned val = min(q->sg_reserved_size, q->max_sectors << 9);
+
+ return put_user(val, p);
}
static int sg_set_reserved_size(request_queue_t *q, int __user *p)
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 086fcec4472..4ca0ab3448d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -16,6 +16,10 @@ config CRYPTO_ALGAPI
help
This option provides the API for cryptographic algorithms.
+config CRYPTO_ABLKCIPHER
+ tristate
+ select CRYPTO_BLKCIPHER
+
config CRYPTO_BLKCIPHER
tristate
select CRYPTO_ALGAPI
@@ -171,6 +175,15 @@ config CRYPTO_LRW
The first 128, 192 or 256 bits in the key are used for AES and the
rest is used to tie each cipher block to its logical position.
+config CRYPTO_CRYPTD
+ tristate "Software async crypto daemon"
+ select CRYPTO_ABLKCIPHER
+ select CRYPTO_MANAGER
+ help
+ This is a generic software asynchronous crypto daemon that
+ converts an arbitrary synchronous software crypto algorithm
+ into an asynchronous algorithm that executes in a kernel thread.
+
config CRYPTO_DES
tristate "DES and Triple DES EDE cipher algorithms"
select CRYPTO_ALGAPI
@@ -258,7 +271,7 @@ config CRYPTO_SERPENT
Keys are allowed to be from 0 to 256 bits in length, in steps
of 8 bits. Also includes the 'Tnepres' algorithm, a reversed
- variant of Serpent for compatibility with old kerneli code.
+ variant of Serpent for compatibility with old kerneli.org code.
See also:
<http://www.cl.cam.ac.uk/~rja14/serpent.html>
diff --git a/crypto/Makefile b/crypto/Makefile
index 12f93f57817..cce46a1c9dc 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -8,6 +8,7 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o
crypto_algapi-objs := algapi.o $(crypto_algapi-y)
obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
+obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o
obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
crypto_hash-objs := hash.o
@@ -29,6 +30,7 @@ obj-$(CONFIG_CRYPTO_ECB) += ecb.o
obj-$(CONFIG_CRYPTO_CBC) += cbc.o
obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o
obj-$(CONFIG_CRYPTO_LRW) += lrw.o
+obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
obj-$(CONFIG_CRYPTO_DES) += des.o
obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
new file mode 100644
index 00000000000..9348ddd84a5
--- /dev/null
+++ b/crypto/ablkcipher.c
@@ -0,0 +1,83 @@
+/*
+ * Asynchronous block chaining cipher operations.
+ *
+ * This is the asynchronous version of blkcipher.c indicating completion
+ * via a callback.
+ *
+ * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+
+static int setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);
+
+ if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
+ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ return cipher->setkey(tfm, key, keylen);
+}
+
+static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type,
+ u32 mask)
+{
+ return alg->cra_ctxsize;
+}
+
+static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
+ u32 mask)
+{
+ struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher;
+ struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
+
+ if (alg->ivsize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ crt->setkey = setkey;
+ crt->encrypt = alg->encrypt;
+ crt->decrypt = alg->decrypt;
+ crt->ivsize = alg->ivsize;
+
+ return 0;
+}
+
+static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
+ __attribute__ ((unused));
+static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
+{
+ struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher;
+
+ seq_printf(m, "type : ablkcipher\n");
+ seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
+ seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize);
+ seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize);
+ seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize);
+ seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen);
+ seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen);
+}
+
+const struct crypto_type crypto_ablkcipher_type = {
+ .ctxsize = crypto_ablkcipher_ctxsize,
+ .init = crypto_init_ablkcipher_ops,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_ablkcipher_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_ablkcipher_type);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Asynchronous block chaining cipher type");
diff --git a/crypto/algapi.c b/crypto/algapi.c
index f7d2185b2c8..f137a432061 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -84,36 +84,47 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
crypto_tmpl_put(tmpl);
}
-static void crypto_remove_spawns(struct list_head *spawns,
- struct list_head *list)
+static void crypto_remove_spawn(struct crypto_spawn *spawn,
+ struct list_head *list,
+ struct list_head *secondary_spawns)
{
- struct crypto_spawn *spawn, *n;
+ struct crypto_instance *inst = spawn->inst;
+ struct crypto_template *tmpl = inst->tmpl;
- list_for_each_entry_safe(spawn, n, spawns, list) {
- struct crypto_instance *inst = spawn->inst;
- struct crypto_template *tmpl = inst->tmpl;
+ list_del_init(&spawn->list);
+ spawn->alg = NULL;
- list_del_init(&spawn->list);
- spawn->alg = NULL;
+ if (crypto_is_dead(&inst->alg))
+ return;
- if (crypto_is_dead(&inst->alg))
- continue;
+ inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
+ if (!tmpl || !crypto_tmpl_get(tmpl))
+ return;
- inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
- if (!tmpl || !crypto_tmpl_get(tmpl))
+ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
+ list_move(&inst->alg.cra_list, list);
+ hlist_del(&inst->list);
+ inst->alg.cra_destroy = crypto_destroy_instance;
+
+ list_splice(&inst->alg.cra_users, secondary_spawns);
+}
+
+static void crypto_remove_spawns(struct list_head *spawns,
+ struct list_head *list, u32 new_type)
+{
+ struct crypto_spawn *spawn, *n;
+ LIST_HEAD(secondary_spawns);
+
+ list_for_each_entry_safe(spawn, n, spawns, list) {
+ if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
continue;
- crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
- list_move(&inst->alg.cra_list, list);
- hlist_del(&inst->list);
- inst->alg.cra_destroy = crypto_destroy_instance;
+ crypto_remove_spawn(spawn, list, &secondary_spawns);
+ }
- if (!list_empty(&inst->alg.cra_users)) {
- if (&n->list == spawns)
- n = list_entry(inst->alg.cra_users.next,
- typeof(*n), list);
- __list_splice(&inst->alg.cra_users, spawns->prev);
- }
+ while (!list_empty(&secondary_spawns)) {
+ list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
+ crypto_remove_spawn(spawn, list, &secondary_spawns);
}
}
@@ -164,7 +175,7 @@ static int __crypto_register_alg(struct crypto_alg *alg,
q->cra_priority > alg->cra_priority)
continue;
- crypto_remove_spawns(&q->cra_users, list);
+ crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
}
list_add(&alg->cra_list, &crypto_alg_list);
@@ -214,7 +225,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
list_del_init(&alg->cra_list);
- crypto_remove_spawns(&alg->cra_users, list);
+ crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
return 0;
}
@@ -351,11 +362,12 @@ err:
EXPORT_SYMBOL_GPL(crypto_register_instance);
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
- struct crypto_instance *inst)
+ struct crypto_instance *inst, u32 mask)
{
int err = -EAGAIN;
spawn->inst = inst;
+ spawn->mask = mask;
down_write(&crypto_alg_sem);
if (!crypto_is_moribund(alg)) {
@@ -425,15 +437,45 @@ int crypto_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
-struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
- u32 type, u32 mask)
+struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
+{
+ struct rtattr *rta = tb[CRYPTOA_TYPE - 1];
+ struct crypto_attr_type *algt;
+
+ if (!rta)
+ return ERR_PTR(-ENOENT);
+ if (RTA_PAYLOAD(rta) < sizeof(*algt))
+ return ERR_PTR(-EINVAL);
+
+ algt = RTA_DATA(rta);
+
+ return algt;
+}
+EXPORT_SYMBOL_GPL(crypto_get_attr_type);
+
+int crypto_check_attr_type(struct rtattr **tb, u32 type)
{
- struct rtattr *rta = param;
+ struct crypto_attr_type *algt;
+
+ algt = crypto_get_attr_type(tb);
+ if (IS_ERR(algt))
+ return PTR_ERR(algt);
+
+ if ((algt->type ^ type) & algt->mask)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_check_attr_type);
+
+struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask)
+{
+ struct rtattr *rta = tb[CRYPTOA_ALG - 1];
struct crypto_attr_alg *alga;
- if (!RTA_OK(rta, len))
- return ERR_PTR(-EBADR);
- if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga))
+ if (!rta)
+ return ERR_PTR(-ENOENT);
+ if (RTA_PAYLOAD(rta) < sizeof(*alga))
return ERR_PTR(-EINVAL);
alga = RTA_DATA(rta);
@@ -464,7 +506,8 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
goto err_free_inst;
spawn = crypto_instance_ctx(inst);
- err = crypto_init_spawn(spawn, alg, inst);
+ err = crypto_init_spawn(spawn, alg, inst,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
if (err)
goto err_free_inst;
@@ -477,6 +520,68 @@ err_free_inst:
}
EXPORT_SYMBOL_GPL(crypto_alloc_instance);
+void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
+{
+ INIT_LIST_HEAD(&queue->list);
+ queue->backlog = &queue->list;
+ queue->qlen = 0;
+ queue->max_qlen = max_qlen;
+}
+EXPORT_SYMBOL_GPL(crypto_init_queue);
+
+int crypto_enqueue_request(struct crypto_queue *queue,
+ struct crypto_async_request *request)
+{
+ int err = -EINPROGRESS;
+
+ if (unlikely(queue->qlen >= queue->max_qlen)) {
+ err = -EBUSY;
+ if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+ goto out;
+ if (queue->backlog == &queue->list)
+ queue->backlog = &request->list;
+ }
+
+ queue->qlen++;
+ list_add_tail(&request->list, &queue->list);
+
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_enqueue_request);
+
+struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
+{
+ struct list_head *request;
+
+ if (unlikely(!queue->qlen))
+ return NULL;
+
+ queue->qlen--;
+
+ if (queue->backlog != &queue->list)
+ queue->backlog = queue->backlog->next;
+
+ request = queue->list.next;
+ list_del(request);
+
+ return list_entry(request, struct crypto_async_request, list);
+}
+EXPORT_SYMBOL_GPL(crypto_dequeue_request);
+
+int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
+{
+ struct crypto_async_request *req;
+
+ list_for_each_entry(req, &queue->list, list) {
+ if (req->tfm == tfm)
+ return 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
+
static int __init crypto_algapi_init(void)
{
crypto_init_proc();
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index b5befe8c3a9..8edf40c835a 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -349,13 +349,48 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key,
return cipher->setkey(tfm, key, keylen);
}
+static int async_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return setkey(crypto_ablkcipher_tfm(tfm), key, keylen);
+}
+
+static int async_encrypt(struct ablkcipher_request *req)
+{
+ struct crypto_tfm *tfm = req->base.tfm;
+ struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+ struct blkcipher_desc desc = {
+ .tfm = __crypto_blkcipher_cast(tfm),
+ .info = req->info,
+ .flags = req->base.flags,
+ };
+
+
+ return alg->encrypt(&desc, req->dst, req->src, req->nbytes);
+}
+
+static int async_decrypt(struct ablkcipher_request *req)
+{
+ struct crypto_tfm *tfm = req->base.tfm;
+ struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+ struct blkcipher_desc desc = {
+ .tfm = __crypto_blkcipher_cast(tfm),
+ .info = req->info,
+ .flags = req->base.flags,
+ };
+
+ return alg->decrypt(&desc, req->dst, req->src, req->nbytes);
+}
+
static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
u32 mask)
{
struct blkcipher_alg *cipher = &alg->cra_blkcipher;
unsigned int len = alg->cra_ctxsize;
- if (cipher->ivsize) {
+ type ^= CRYPTO_ALG_ASYNC;
+ mask &= CRYPTO_ALG_ASYNC;
+ if ((type & mask) && cipher->ivsize) {
len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1);
len += cipher->ivsize;
}
@@ -363,16 +398,26 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type,
return len;
}
-static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm)
+{
+ struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher;
+ struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+
+ crt->setkey = async_setkey;
+ crt->encrypt = async_encrypt;
+ crt->decrypt = async_decrypt;
+ crt->ivsize = alg->ivsize;
+
+ return 0;
+}
+
+static int crypto_init_blkcipher_ops_sync(struct crypto_tfm *tfm)
{
struct blkcipher_tfm *crt = &tfm->crt_blkcipher;
struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
unsigned long align = crypto_tfm_alg_alignmask(tfm) + 1;
unsigned long addr;
- if (alg->ivsize > PAGE_SIZE / 8)
- return -EINVAL;
-
crt->setkey = setkey;
crt->encrypt = alg->encrypt;
crt->decrypt = alg->decrypt;
@@ -385,8 +430,23 @@ static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
return 0;
}
+static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+ struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher;
+
+ if (alg->ivsize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ type ^= CRYPTO_ALG_ASYNC;
+ mask &= CRYPTO_ALG_ASYNC;
+ if (type & mask)
+ return crypto_init_blkcipher_ops_sync(tfm);
+ else
+ return crypto_init_blkcipher_ops_async(tfm);
+}
+
static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
- __attribute_used__;
+ __attribute__ ((unused));
static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg)
{
seq_printf(m, "type : blkcipher\n");
diff --git a/crypto/cbc.c b/crypto/cbc.c
index 136fea7e700..1f2649e13b4 100644
--- a/crypto/cbc.c
+++ b/crypto/cbc.c
@@ -275,13 +275,18 @@ static void crypto_cbc_exit_tfm(struct crypto_tfm *tfm)
crypto_free_cipher(ctx->child);
}
-static struct crypto_instance *crypto_cbc_alloc(void *param, unsigned int len)
+static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb)
{
struct crypto_instance *inst;
struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ if (err)
+ return ERR_PTR(err);
- alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
- CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
return ERR_PTR(PTR_ERR(alg));
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
new file mode 100644
index 00000000000..3ff4e1f0f03
--- /dev/null
+++ b/crypto/cryptd.c
@@ -0,0 +1,375 @@
+/*
+ * Software async crypto daemon.
+ *
+ * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define CRYPTD_MAX_QLEN 100
+
+struct cryptd_state {
+ spinlock_t lock;
+ struct mutex mutex;
+ struct crypto_queue queue;
+ struct task_struct *task;
+};
+
+struct cryptd_instance_ctx {
+ struct crypto_spawn spawn;
+ struct cryptd_state *state;
+};
+
+struct cryptd_blkcipher_ctx {
+ struct crypto_blkcipher *child;
+};
+
+struct cryptd_blkcipher_request_ctx {
+ crypto_completion_t complete;
+};
+
+
+static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm)
+{
+ struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+ struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
+ return ictx->state;
+}
+
+static int cryptd_blkcipher_setkey(struct crypto_ablkcipher *parent,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryptd_blkcipher_ctx *ctx = crypto_ablkcipher_ctx(parent);
+ struct crypto_blkcipher *child = ctx->child;
+ int err;
+
+ crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+ crypto_blkcipher_set_flags(child, crypto_ablkcipher_get_flags(parent) &
+ CRYPTO_TFM_REQ_MASK);
+ err = crypto_blkcipher_setkey(child, key, keylen);
+ crypto_ablkcipher_set_flags(parent, crypto_blkcipher_get_flags(child) &
+ CRYPTO_TFM_RES_MASK);
+ return err;
+}
+
+static void cryptd_blkcipher_crypt(struct ablkcipher_request *req,
+ struct crypto_blkcipher *child,
+ int err,
+ int (*crypt)(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int len))
+{
+ struct cryptd_blkcipher_request_ctx *rctx;
+ struct blkcipher_desc desc;
+
+ rctx = ablkcipher_request_ctx(req);
+
+ if (unlikely(err == -EINPROGRESS)) {
+ rctx->complete(&req->base, err);
+ return;
+ }
+
+ desc.tfm = child;
+ desc.info = req->info;
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ err = crypt(&desc, req->dst, req->src, req->nbytes);
+
+ req->base.complete = rctx->complete;
+
+ local_bh_disable();
+ req->base.complete(&req->base, err);
+ local_bh_enable();
+}
+
+static void cryptd_blkcipher_encrypt(struct crypto_async_request *req, int err)
+{
+ struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm);
+ struct crypto_blkcipher *child = ctx->child;
+
+ cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err,
+ crypto_blkcipher_crt(child)->encrypt);
+}
+
+static void cryptd_blkcipher_decrypt(struct crypto_async_request *req, int err)
+{
+ struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm);
+ struct crypto_blkcipher *child = ctx->child;
+
+ cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err,
+ crypto_blkcipher_crt(child)->decrypt);
+}
+
+static int cryptd_blkcipher_enqueue(struct ablkcipher_request *req,
+ crypto_completion_t complete)
+{
+ struct cryptd_blkcipher_request_ctx *rctx = ablkcipher_request_ctx(req);
+ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+ struct cryptd_state *state =
+ cryptd_get_state(crypto_ablkcipher_tfm(tfm));
+ int err;
+
+ rctx->complete = req->base.complete;
+ req->base.complete = complete;
+
+ spin_lock_bh(&state->lock);
+ err = ablkcipher_enqueue_request(crypto_ablkcipher_alg(tfm), req);
+ spin_unlock_bh(&state->lock);
+
+ wake_up_process(state->task);
+ return err;
+}
+
+static int cryptd_blkcipher_encrypt_enqueue(struct ablkcipher_request *req)
+{
+ return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_encrypt);
+}
+
+static int cryptd_blkcipher_decrypt_enqueue(struct ablkcipher_request *req)
+{
+ return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_decrypt);
+}
+
+static int cryptd_blkcipher_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+ struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
+ struct crypto_spawn *spawn = &ictx->spawn;
+ struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_blkcipher *cipher;
+
+ cipher = crypto_spawn_blkcipher(spawn);
+ if (IS_ERR(cipher))
+ return PTR_ERR(cipher);
+
+ ctx->child = cipher;
+ tfm->crt_ablkcipher.reqsize =
+ sizeof(struct cryptd_blkcipher_request_ctx);
+ return 0;
+}
+
+static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm)
+{
+ struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct cryptd_state *state = cryptd_get_state(tfm);
+ int active;
+
+ mutex_lock(&state->mutex);
+ active = ablkcipher_tfm_in_queue(__crypto_ablkcipher_cast(tfm));
+ mutex_unlock(&state->mutex);
+
+ BUG_ON(active);
+
+ crypto_free_blkcipher(ctx->child);
+}
+
+static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg,
+ struct cryptd_state *state)
+{
+ struct crypto_instance *inst;
+ struct cryptd_instance_ctx *ctx;
+ int err;
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
+ if (IS_ERR(inst))
+ goto out;
+
+ err = -ENAMETOOLONG;
+ if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+ "cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+ goto out_free_inst;
+
+ ctx = crypto_instance_ctx(inst);
+ err = crypto_init_spawn(&ctx->spawn, alg, inst,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ if (err)
+ goto out_free_inst;
+
+ ctx->state = state;
+
+ memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+
+ inst->alg.cra_priority = alg->cra_priority + 50;
+ inst->alg.cra_blocksize = alg->cra_blocksize;
+ inst->alg.cra_alignmask = alg->cra_alignmask;
+
+out:
+ return inst;
+
+out_free_inst:
+ kfree(inst);
+ inst = ERR_PTR(err);
+ goto out;
+}
+
+static struct crypto_instance *cryptd_alloc_blkcipher(
+ struct rtattr **tb, struct cryptd_state *state)
+{
+ struct crypto_instance *inst;
+ struct crypto_alg *alg;
+
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ if (IS_ERR(alg))
+ return ERR_PTR(PTR_ERR(alg));
+
+ inst = cryptd_alloc_instance(alg, state);
+ if (IS_ERR(inst))
+ goto out_put_alg;
+
+ inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC;
+ inst->alg.cra_type = &crypto_ablkcipher_type;
+
+ inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize;
+ inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize;
+ inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize;
+
+ inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx);
+
+ inst->alg.cra_init = cryptd_blkcipher_init_tfm;
+ inst->alg.cra_exit = cryptd_blkcipher_exit_tfm;
+
+ inst->alg.cra_ablkcipher.setkey = cryptd_blkcipher_setkey;
+ inst->alg.cra_ablkcipher.encrypt = cryptd_blkcipher_encrypt_enqueue;
+ inst->alg.cra_ablkcipher.decrypt = cryptd_blkcipher_decrypt_enqueue;
+
+ inst->alg.cra_ablkcipher.queue = &state->queue;
+
+out_put_alg:
+ crypto_mod_put(alg);
+ return inst;
+}
+
+static struct cryptd_state state;
+
+static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
+{
+ struct crypto_attr_type *algt;
+
+ algt = crypto_get_attr_type(tb);
+ if (IS_ERR(algt))
+ return ERR_PTR(PTR_ERR(algt));
+
+ switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
+ case CRYPTO_ALG_TYPE_BLKCIPHER:
+ return cryptd_alloc_blkcipher(tb, &state);
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static void cryptd_free(struct crypto_instance *inst)
+{
+ struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst);
+
+ crypto_drop_spawn(&ctx->spawn);
+ kfree(inst);
+}
+
+static struct crypto_template cryptd_tmpl = {
+ .name = "cryptd",
+ .alloc = cryptd_alloc,
+ .free = cryptd_free,
+ .module = THIS_MODULE,
+};
+
+static inline int cryptd_create_thread(struct cryptd_state *state,
+ int (*fn)(void *data), const char *name)
+{
+ spin_lock_init(&state->lock);
+ mutex_init(&state->mutex);
+ crypto_init_queue(&state->queue, CRYPTD_MAX_QLEN);
+
+ state->task = kthread_create(fn, state, name);
+ if (IS_ERR(state->task))
+ return PTR_ERR(state->task);
+
+ return 0;
+}
+
+static inline void cryptd_stop_thread(struct cryptd_state *state)
+{
+ BUG_ON(state->queue.qlen);
+ kthread_stop(state->task);
+}
+
+static int cryptd_thread(void *data)
+{
+ struct cryptd_state *state = data;
+ int stop;
+
+ do {
+ struct crypto_async_request *req, *backlog;
+
+ mutex_lock(&state->mutex);
+ __set_current_state(TASK_INTERRUPTIBLE);
+
+ spin_lock_bh(&state->lock);
+ backlog = crypto_get_backlog(&state->queue);
+ req = crypto_dequeue_request(&state->queue);
+ spin_unlock_bh(&state->lock);
+
+ stop = kthread_should_stop();
+
+ if (stop || req) {
+ __set_current_state(TASK_RUNNING);
+ if (req) {
+ if (backlog)
+ backlog->complete(backlog,
+ -EINPROGRESS);
+ req->complete(req, 0);
+ }
+ }
+
+ mutex_unlock(&state->mutex);
+
+ schedule();
+ } while (!stop);
+
+ return 0;
+}
+
+static int __init cryptd_init(void)
+{
+ int err;
+
+ err = cryptd_create_thread(&state, cryptd_thread, "cryptd");
+ if (err)
+ return err;
+
+ err = crypto_register_template(&cryptd_tmpl);
+ if (err)
+ kthread_stop(state.task);
+
+ return err;
+}
+
+static void __exit cryptd_exit(void)
+{
+ cryptd_stop_thread(&state);
+ crypto_unregister_template(&cryptd_tmpl);
+}
+
+module_init(cryptd_init);
+module_exit(cryptd_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Software async crypto daemon");
diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c
index 2ebffb84f1d..e5fb7cca510 100644
--- a/crypto/cryptomgr.c
+++ b/crypto/cryptomgr.c
@@ -14,17 +14,22 @@
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/init.h>
+#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/rtnetlink.h>
#include <linux/sched.h>
#include <linux/string.h>
-#include <linux/workqueue.h>
#include "internal.h"
struct cryptomgr_param {
- struct work_struct work;
+ struct rtattr *tb[CRYPTOA_MAX];
+
+ struct {
+ struct rtattr attr;
+ struct crypto_attr_type data;
+ } type;
struct {
struct rtattr attr;
@@ -32,18 +37,15 @@ struct cryptomgr_param {
} alg;
struct {
- u32 type;
- u32 mask;
char name[CRYPTO_MAX_ALG_NAME];
} larval;
char template[CRYPTO_MAX_ALG_NAME];
};
-static void cryptomgr_probe(struct work_struct *work)
+static int cryptomgr_probe(void *data)
{
- struct cryptomgr_param *param =
- container_of(work, struct cryptomgr_param, work);
+ struct cryptomgr_param *param = data;
struct crypto_template *tmpl;
struct crypto_instance *inst;
int err;
@@ -53,7 +55,7 @@ static void cryptomgr_probe(struct work_struct *work)
goto err;
do {
- inst = tmpl->alloc(&param->alg, sizeof(param->alg));
+ inst = tmpl->alloc(param->tb);
if (IS_ERR(inst))
err = PTR_ERR(inst);
else if ((err = crypto_register_instance(tmpl, inst)))
@@ -67,25 +69,29 @@ static void cryptomgr_probe(struct work_struct *work)
out:
kfree(param);
- return;
+ module_put_and_exit(0);
err:
- crypto_larval_error(param->larval.name, param->larval.type,
- param->larval.mask);
+ crypto_larval_error(param->larval.name, param->type.data.type,
+ param->type.data.mask);
goto out;
}
static int cryptomgr_schedule_probe(struct crypto_larval *larval)
{
+ struct task_struct *thread;
struct cryptomgr_param *param;
const char *name = larval->alg.cra_name;
const char *p;
unsigned int len;
- param = kmalloc(sizeof(*param), GFP_KERNEL);
- if (!param)
+ if (!try_module_get(THIS_MODULE))
goto err;
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param)
+ goto err_put_module;
+
for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
;
@@ -94,32 +100,45 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval)
goto err_free_param;
memcpy(param->template, name, len);
- param->template[len] = 0;
name = p + 1;
- for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
- ;
+ len = 0;
+ for (p = name; *p; p++) {
+ for (; isalnum(*p) || *p == '-' || *p == '_' || *p == '('; p++)
+ ;
- len = p - name;
- if (!len || *p != ')' || p[1])
+ if (*p != ')')
+ goto err_free_param;
+
+ len = p - name;
+ }
+
+ if (!len || name[len + 1])
goto err_free_param;
+ param->type.attr.rta_len = sizeof(param->type);
+ param->type.attr.rta_type = CRYPTOA_TYPE;
+ param->type.data.type = larval->alg.cra_flags;
+ param->type.data.mask = larval->mask;
+ param->tb[CRYPTOA_TYPE - 1] = &param->type.attr;
+
param->alg.attr.rta_len = sizeof(param->alg);
param->alg.attr.rta_type = CRYPTOA_ALG;
memcpy(param->alg.data.name, name, len);
- param->alg.data.name[len] = 0;
+ param->tb[CRYPTOA_ALG - 1] = &param->alg.attr;
memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
- param->larval.type = larval->alg.cra_flags;
- param->larval.mask = larval->mask;
- INIT_WORK(&param->work, cryptomgr_probe);
- schedule_work(&param->work);
+ thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
+ if (IS_ERR(thread))
+ goto err_free_param;
return NOTIFY_STOP;
err_free_param:
kfree(param);
+err_put_module:
+ module_put(THIS_MODULE);
err:
return NOTIFY_OK;
}
diff --git a/crypto/ecb.c b/crypto/ecb.c
index 839a0aed8c2..6310387a872 100644
--- a/crypto/ecb.c
+++ b/crypto/ecb.c
@@ -115,13 +115,18 @@ static void crypto_ecb_exit_tfm(struct crypto_tfm *tfm)
crypto_free_cipher(ctx->child);
}
-static struct crypto_instance *crypto_ecb_alloc(void *param, unsigned int len)
+static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb)
{
struct crypto_instance *inst;
struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ if (err)
+ return ERR_PTR(err);
- alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
- CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
return ERR_PTR(PTR_ERR(alg));
diff --git a/crypto/hash.c b/crypto/hash.c
index 12c4514f347..4ccd22deef3 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -41,7 +41,7 @@ static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
}
static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
- __attribute_used__;
+ __attribute__ ((unused));
static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
{
seq_printf(m, "type : hash\n");
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 44187c5ee59..8802fb6dd5a 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -197,13 +197,18 @@ static void hmac_free(struct crypto_instance *inst)
kfree(inst);
}
-static struct crypto_instance *hmac_alloc(void *param, unsigned int len)
+static struct crypto_instance *hmac_alloc(struct rtattr **tb)
{
struct crypto_instance *inst;
struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+ if (err)
+ return ERR_PTR(err);
- alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH,
- CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
+ CRYPTO_ALG_TYPE_HASH_MASK);
if (IS_ERR(alg))
return ERR_PTR(PTR_ERR(alg));
diff --git a/crypto/lrw.c b/crypto/lrw.c
index b4105080ac7..621095db28b 100644
--- a/crypto/lrw.c
+++ b/crypto/lrw.c
@@ -228,13 +228,18 @@ static void exit_tfm(struct crypto_tfm *tfm)
crypto_free_cipher(ctx->child);
}
-static struct crypto_instance *alloc(void *param, unsigned int len)
+static struct crypto_instance *alloc(struct rtattr **tb)
{
struct crypto_instance *inst;
struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ if (err)
+ return ERR_PTR(err);
- alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
- CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
return ERR_PTR(PTR_ERR(alg));
diff --git a/crypto/michael_mic.c b/crypto/michael_mic.c
index 094397b4884..9e917b8011b 100644
--- a/crypto/michael_mic.c
+++ b/crypto/michael_mic.c
@@ -3,7 +3,7 @@
*
* Michael MIC (IEEE 802.11i/TKIP) keyed digest
*
- * Copyright (c) 2004 Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004 Jouni Malinen <j@w1.fi>
*
* 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
@@ -173,4 +173,4 @@ module_exit(michael_mic_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Michael MIC");
-MODULE_AUTHOR("Jouni Malinen <jkmaline@cc.hut.fi>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
diff --git a/crypto/pcbc.c b/crypto/pcbc.c
index 5174d7fdad6..c3ed8a1c9f4 100644
--- a/crypto/pcbc.c
+++ b/crypto/pcbc.c
@@ -279,13 +279,18 @@ static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm)
crypto_free_cipher(ctx->child);
}
-static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len)
+static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb)
{
struct crypto_instance *inst;
struct crypto_alg *alg;
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER);
+ if (err)
+ return ERR_PTR(err);
- alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
- CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
return ERR_PTR(PTR_ERR(alg));
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 8eaa5aa210b..f0aed0106ad 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -57,6 +57,11 @@
#define ENCRYPT 1
#define DECRYPT 0
+struct tcrypt_result {
+ struct completion completion;
+ int err;
+};
+
static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };
/*
@@ -84,6 +89,17 @@ static void hexdump(unsigned char *buf, unsigned int len)
printk("\n");
}
+static void tcrypt_complete(struct crypto_async_request *req, int err)
+{
+ struct tcrypt_result *res = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ res->err = err;
+ complete(&res->completion);
+}
+
static void test_hash(char *algo, struct hash_testvec *template,
unsigned int tcount)
{
@@ -203,15 +219,14 @@ static void test_cipher(char *algo, int enc,
{
unsigned int ret, i, j, k, temp;
unsigned int tsize;
- unsigned int iv_len;
- unsigned int len;
char *q;
- struct crypto_blkcipher *tfm;
+ struct crypto_ablkcipher *tfm;
char *key;
struct cipher_testvec *cipher_tv;
- struct blkcipher_desc desc;
+ struct ablkcipher_request *req;
struct scatterlist sg[8];
const char *e;
+ struct tcrypt_result result;
if (enc == ENCRYPT)
e = "encryption";
@@ -232,15 +247,24 @@ static void test_cipher(char *algo, int enc,
memcpy(tvmem, template, tsize);
cipher_tv = (void *)tvmem;
- tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC);
+ init_completion(&result.completion);
+
+ tfm = crypto_alloc_ablkcipher(algo, 0, 0);
if (IS_ERR(tfm)) {
printk("failed to load transform for %s: %ld\n", algo,
PTR_ERR(tfm));
return;
}
- desc.tfm = tfm;
- desc.flags = 0;
+
+ req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req) {
+ printk("failed to allocate request for %s\n", algo);
+ goto out;
+ }
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ tcrypt_complete, &result);
j = 0;
for (i = 0; i < tcount; i++) {
@@ -249,17 +273,17 @@ static void test_cipher(char *algo, int enc,
printk("test %u (%d bit key):\n",
j, cipher_tv[i].klen * 8);
- crypto_blkcipher_clear_flags(tfm, ~0);
+ crypto_ablkcipher_clear_flags(tfm, ~0);
if (cipher_tv[i].wk)
- crypto_blkcipher_set_flags(
+ crypto_ablkcipher_set_flags(
tfm, CRYPTO_TFM_REQ_WEAK_KEY);
key = cipher_tv[i].key;
- ret = crypto_blkcipher_setkey(tfm, key,
- cipher_tv[i].klen);
+ ret = crypto_ablkcipher_setkey(tfm, key,
+ cipher_tv[i].klen);
if (ret) {
printk("setkey() failed flags=%x\n",
- crypto_blkcipher_get_flags(tfm));
+ crypto_ablkcipher_get_flags(tfm));
if (!cipher_tv[i].fail)
goto out;
@@ -268,19 +292,28 @@ static void test_cipher(char *algo, int enc,
sg_set_buf(&sg[0], cipher_tv[i].input,
cipher_tv[i].ilen);
- iv_len = crypto_blkcipher_ivsize(tfm);
- if (iv_len)
- crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv,
- iv_len);
+ ablkcipher_request_set_crypt(req, sg, sg,
+ cipher_tv[i].ilen,
+ cipher_tv[i].iv);
- len = cipher_tv[i].ilen;
ret = enc ?
- crypto_blkcipher_encrypt(&desc, sg, sg, len) :
- crypto_blkcipher_decrypt(&desc, sg, sg, len);
+ crypto_ablkcipher_encrypt(req) :
+ crypto_ablkcipher_decrypt(req);
- if (ret) {
- printk("%s () failed flags=%x\n", e,
- desc.flags);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret && !((ret = result.err))) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk("%s () failed err=%d\n", e, -ret);
goto out;
}
@@ -303,17 +336,17 @@ static void test_cipher(char *algo, int enc,
printk("test %u (%d bit key):\n",
j, cipher_tv[i].klen * 8);
- crypto_blkcipher_clear_flags(tfm, ~0);
+ crypto_ablkcipher_clear_flags(tfm, ~0);
if (cipher_tv[i].wk)
- crypto_blkcipher_set_flags(
+ crypto_ablkcipher_set_flags(
tfm, CRYPTO_TFM_REQ_WEAK_KEY);
key = cipher_tv[i].key;
- ret = crypto_blkcipher_setkey(tfm, key,
- cipher_tv[i].klen);
+ ret = crypto_ablkcipher_setkey(tfm, key,
+ cipher_tv[i].klen);
if (ret) {
printk("setkey() failed flags=%x\n",
- crypto_blkcipher_get_flags(tfm));
+ crypto_ablkcipher_get_flags(tfm));
if (!cipher_tv[i].fail)
goto out;
@@ -329,19 +362,28 @@ static void test_cipher(char *algo, int enc,
cipher_tv[i].tap[k]);
}
- iv_len = crypto_blkcipher_ivsize(tfm);
- if (iv_len)
- crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv,
- iv_len);
+ ablkcipher_request_set_crypt(req, sg, sg,
+ cipher_tv[i].ilen,
+ cipher_tv[i].iv);
- len = cipher_tv[i].ilen;
ret = enc ?
- crypto_blkcipher_encrypt(&desc, sg, sg, len) :
- crypto_blkcipher_decrypt(&desc, sg, sg, len);
+ crypto_ablkcipher_encrypt(req) :
+ crypto_ablkcipher_decrypt(req);
- if (ret) {
- printk("%s () failed flags=%x\n", e,
- desc.flags);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret && !((ret = result.err))) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk("%s () failed err=%d\n", e, -ret);
goto out;
}
@@ -360,7 +402,8 @@ static void test_cipher(char *algo, int enc,
}
out:
- crypto_free_blkcipher(tfm);
+ crypto_free_ablkcipher(tfm);
+ ablkcipher_request_free(req);
}
static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, char *p,
@@ -832,7 +875,7 @@ static void test_available(void)
while (*name) {
printk("alg %s ", *name);
- printk(crypto_has_alg(*name, 0, CRYPTO_ALG_ASYNC) ?
+ printk(crypto_has_alg(*name, 0, 0) ?
"found\n" : "not found\n");
name++;
}
diff --git a/crypto/xcbc.c b/crypto/xcbc.c
index 53e8ccbf0f5..9f502b86e0e 100644
--- a/crypto/xcbc.c
+++ b/crypto/xcbc.c
@@ -288,12 +288,18 @@ static void xcbc_exit_tfm(struct crypto_tfm *tfm)
crypto_free_cipher(ctx->child);
}
-static struct crypto_instance *xcbc_alloc(void *param, unsigned int len)
+static struct crypto_instance *xcbc_alloc(struct rtattr **tb)
{
struct crypto_instance *inst;
struct crypto_alg *alg;
- alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER,
- CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
+ int err;
+
+ err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
+ if (err)
+ return ERR_PTR(err);
+
+ alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
+ CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
return ERR_PTR(PTR_ERR(alg));
diff --git a/drivers/Makefile b/drivers/Makefile
index 920c975bb6d..26ca9031ea4 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -58,7 +58,7 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
-obj-$(CONFIG_I2C) += i2c/
+obj-y += i2c/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_PHONE) += telephony/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index e2ce4a9c1c9..139f41f033d 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -85,8 +85,8 @@ config ACPI_PROCFS
depends on ACPI
default y
---help---
- Procfs interface for ACPI is made optional for back-compatible.
- As the same functions are duplicated in sysfs interface
+ The Procfs interface for ACPI is made optional for backward compatibility.
+ As the same functions are duplicated in the sysfs interface
and this proc interface will be removed some time later,
it's marked as deprecated.
( /proc/acpi/debug_layer && debug_level are deprecated by
@@ -218,43 +218,6 @@ config ACPI_ASUS
NOTE: This driver is deprecated and will probably be removed soon,
use asus-laptop instead.
-config ACPI_IBM
- tristate "IBM ThinkPad Laptop Extras"
- depends on X86
- select BACKLIGHT_CLASS_DEVICE
- ---help---
- This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
- support for Fn-Fx key combinations, Bluetooth control, video
- output switching, ThinkLight control, UltraBay eject and more.
- For more information about this driver see <file:Documentation/ibm-acpi.txt>
- and <http://ibm-acpi.sf.net/> .
-
- If you have an IBM ThinkPad laptop, say Y or M here.
-
-config ACPI_IBM_DOCK
- bool "Legacy Docking Station Support"
- depends on ACPI_IBM
- depends on ACPI_DOCK=n
- default n
- ---help---
- Allows the ibm_acpi driver to handle docking station events.
- This support is obsoleted by CONFIG_HOTPLUG_PCI_ACPI. It will
- allow locking and removing the laptop from the docking station,
- but will not properly connect PCI devices.
-
- If you are not sure, say N here.
-
-config ACPI_IBM_BAY
- bool "Legacy Removable Bay Support"
- depends on ACPI_IBM
- default y
- ---help---
- Allows the ibm_acpi driver to handle removable bays. It will allow
- disabling the device in the bay, and also generate notifications when
- the bay lever is ejected or inserted.
-
- If you are not sure, say Y here.
-
config ACPI_TOSHIBA
tristate "Toshiba Laptop Extras"
depends on X86
@@ -388,11 +351,10 @@ config ACPI_HOTPLUG_MEMORY
config ACPI_SBS
tristate "Smart Battery System (EXPERIMENTAL)"
- depends on X86 && I2C
+ depends on X86
depends on EXPERIMENTAL
help
This driver adds support for the Smart Battery System.
- Depends on I2C (Device Drivers ---> I2C support)
A "Smart Battery" is quite old and quite rare compared
to today's ACPI "Control Method" battery.
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5956e9f64a8..d4336f1730e 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -1,6 +1,6 @@
#
# Makefile for the Linux ACPI interpreter
-#
+#
export ACPI_CFLAGS
@@ -32,16 +32,17 @@ obj-y += osl.o utils.o \
processor-objs += processor_core.o processor_throttling.o \
processor_idle.o processor_thermal.o
ifdef CONFIG_CPU_FREQ
-processor-objs += processor_perflib.o
+processor-objs += processor_perflib.o
endif
obj-y += sleep/
obj-y += bus.o glue.o
obj-y += scan.o
+# Keep EC driver first. Initialization of others depend on it.
+obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
-obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_BAY) += bay.o
@@ -55,8 +56,7 @@ obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
-obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-y += cm_sbs.o
-obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
+obj-$(CONFIG_ACPI_SBS) += sbs.o
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index c26172671fd..e65628a0308 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -44,11 +44,6 @@ MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
MODULE_DESCRIPTION("Hotplug Mem Driver");
MODULE_LICENSE("GPL");
-/* ACPI _STA method values */
-#define ACPI_MEMORY_STA_PRESENT (0x00000001UL)
-#define ACPI_MEMORY_STA_ENABLED (0x00000002UL)
-#define ACPI_MEMORY_STA_FUNCTIONAL (0x00000008UL)
-
/* Memory Device States */
#define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1
@@ -204,9 +199,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
* Check for device status. Device should be
* present/enabled/functioning.
*/
- if (!((current_status & ACPI_MEMORY_STA_PRESENT)
- && (current_status & ACPI_MEMORY_STA_ENABLED)
- && (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
+ if (!((current_status & ACPI_STA_DEVICE_PRESENT)
+ && (current_status & ACPI_STA_DEVICE_ENABLED)
+ && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
return -ENODEV;
return 0;
@@ -286,7 +281,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
return -ENODEV;
/* Check for device status. Device should be disabled */
- if (current_status & ACPI_MEMORY_STA_ENABLED)
+ if (current_status & ACPI_STA_DEVICE_ENABLED)
return -EINVAL;
return 0;
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index dd49ea0d0ed..e5084ececb6 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -103,7 +103,9 @@ int acpi_bus_get_status(struct acpi_device *device)
else if (device->parent)
device->status = device->parent->status;
else
- STRUCT_TO_INT(device->status) = 0x0F;
+ STRUCT_TO_INT(device->status) =
+ ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
if (device->status.functional && !device->status.present) {
printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0930d9413df..0dd3bf7c0ed 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -49,8 +49,6 @@ MODULE_AUTHOR("Anil S Keshavamurthy");
MODULE_DESCRIPTION("ACPI container driver");
MODULE_LICENSE("GPL");
-#define ACPI_STA_PRESENT (0x00000001)
-
static int acpi_container_add(struct acpi_device *device);
static int acpi_container_remove(struct acpi_device *device, int type);
@@ -75,13 +73,13 @@ static int is_device_present(acpi_handle handle)
status = acpi_get_handle(handle, "_STA", &temp);
if (ACPI_FAILURE(status))
- return 1; /* _STA not found, assmue device present */
+ return 1; /* _STA not found, assume device present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
return 0; /* Firmware error */
- return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+ return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
}
/*******************************************************************/
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 54a697f9aa1..4546bf873ae 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -29,6 +29,7 @@
#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <linux/jiffies.h>
+#include <linux/stddef.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -667,6 +668,23 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
}
DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
+/*
+ * show_dock_uid - read method for "uid" file in sysfs
+ */
+static ssize_t show_dock_uid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ unsigned long lbuf;
+ acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
+ if(ACPI_FAILURE(status)) {
+ return 0;
+ }
+ return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
+}
+DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
+
+
+
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -715,6 +733,13 @@ static int dock_add(acpi_handle handle)
kfree(dock_station);
return ret;
}
+ ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+ if (ret) {
+ printk("Error %d adding sysfs file\n", ret);
+ platform_device_unregister(&dock_device);
+ kfree(dock_station);
+ return ret;
+ }
/* Find dependent devices */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index a802962ff2b..e08cf98f504 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,6 +1,8 @@
/*
- * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $)
+ * ec.c - ACPI Embedded Controller Driver (v2.0)
*
+ * Copyright (C) 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
@@ -91,9 +93,9 @@ static struct acpi_driver acpi_ec_driver = {
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
+/* External interfaces use first EC only, so remember */
static struct acpi_ec {
acpi_handle handle;
- unsigned long uid;
unsigned long gpe;
unsigned long command_addr;
unsigned long data_addr;
@@ -101,12 +103,8 @@ static struct acpi_ec {
struct mutex lock;
atomic_t query_pending;
atomic_t event_count;
- atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
wait_queue_head_t wait;
-} *ec_ecdt;
-
-/* External interfaces use first EC only, so remember */
-static struct acpi_device *first_ec;
+} *boot_ec, *first_ec;
/* --------------------------------------------------------------------------
Transaction Management
@@ -173,56 +171,6 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
return -ETIME;
}
-#ifdef ACPI_FUTURE_USAGE
-/*
- * Note: samsung nv5000 doesn't work with ec burst mode.
- * http://bugzilla.kernel.org/show_bug.cgi?id=4980
- */
-int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
-{
- u8 tmp = 0;
- u8 status = 0;
-
- status = acpi_ec_read_status(ec);
- if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (status)
- goto end;
- acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
- tmp = acpi_ec_read_data(ec);
- if (tmp != 0x90) { /* Burst ACK byte */
- return -EINVAL;
- }
- }
-
- atomic_set(&ec->leaving_burst, 0);
- return 0;
- end:
- ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
- return -1;
-}
-
-int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
-{
- u8 status = 0;
-
- status = acpi_ec_read_status(ec);
- if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- if (status)
- goto end;
- acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
- acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
- }
- atomic_set(&ec->leaving_burst, 1);
- return 0;
- end:
- ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
- return -1;
-}
-#endif /* ACPI_FUTURE_USAGE */
-
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
const u8 * wdata, unsigned wdata_len,
u8 * rdata, unsigned rdata_len)
@@ -312,6 +260,21 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
return status;
}
+/*
+ * Note: samsung nv5000 doesn't work with ec burst mode.
+ * http://bugzilla.kernel.org/show_bug.cgi?id=4980
+ */
+int acpi_ec_burst_enable(struct acpi_ec *ec)
+{
+ u8 d;
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+}
+
+int acpi_ec_burst_disable(struct acpi_ec *ec)
+{
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+}
+
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
{
int result;
@@ -333,18 +296,33 @@ static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
+int ec_burst_enable(void)
+{
+ if (!first_ec)
+ return -ENODEV;
+ return acpi_ec_burst_enable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_enable);
+
+int ec_burst_disable(void)
+{
+ if (!first_ec)
+ return -ENODEV;
+ return acpi_ec_burst_disable(first_ec);
+}
+
+EXPORT_SYMBOL(ec_burst_disable);
+
int ec_read(u8 addr, u8 * val)
{
- struct acpi_ec *ec;
int err;
u8 temp_data;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- err = acpi_ec_read(ec, addr, &temp_data);
+ err = acpi_ec_read(first_ec, addr, &temp_data);
if (!err) {
*val = temp_data;
@@ -357,15 +335,12 @@ EXPORT_SYMBOL(ec_read);
int ec_write(u8 addr, u8 val)
{
- struct acpi_ec *ec;
int err;
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- err = acpi_ec_write(ec, addr, val);
+ err = acpi_ec_write(first_ec, addr, val);
return err;
}
@@ -376,14 +351,10 @@ int ec_transaction(u8 command,
const u8 * wdata, unsigned wdata_len,
u8 * rdata, unsigned rdata_len)
{
- struct acpi_ec *ec;
-
if (!first_ec)
return -ENODEV;
- ec = acpi_driver_data(first_ec);
-
- return acpi_ec_transaction(ec, command, wdata,
+ return acpi_ec_transaction(first_ec, command, wdata,
wdata_len, rdata, rdata_len);
}
@@ -420,7 +391,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
static void acpi_ec_gpe_query(void *ec_cxt)
{
- struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+ struct acpi_ec *ec = ec_cxt;
u8 value = 0;
char object_name[8];
@@ -438,8 +409,9 @@ static u32 acpi_ec_gpe_handler(void *data)
{
acpi_status status = AE_OK;
u8 value;
- struct acpi_ec *ec = (struct acpi_ec *)data;
+ struct acpi_ec *ec = data;
atomic_inc(&ec->event_count);
+
if (acpi_ec_mode == EC_INTR) {
wake_up(&ec->wait);
}
@@ -482,7 +454,7 @@ acpi_ec_space_handler(u32 function,
void *handler_context, void *region_context)
{
int result = 0;
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec = handler_context;
u64 temp = *value;
acpi_integer f_v = 0;
int i = 0;
@@ -494,8 +466,6 @@ acpi_ec_space_handler(u32 function,
return AE_BAD_PARAMETER;
}
- ec = (struct acpi_ec *)handler_context;
-
next_byte:
switch (function) {
case ACPI_READ:
@@ -551,18 +521,16 @@ static struct proc_dir_entry *acpi_ec_dir;
static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
- struct acpi_ec *ec = (struct acpi_ec *)seq->private;
+ struct acpi_ec *ec = seq->private;
if (!ec)
goto end;
- seq_printf(seq, "gpe: 0x%02x\n", (u32) ec->gpe);
- seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
- (u32) ec->command_addr, (u32) ec->data_addr);
- seq_printf(seq, "use global lock: %s\n",
+ seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe);
+ seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n",
+ (unsigned)ec->command_addr, (unsigned)ec->data_addr);
+ seq_printf(seq, "use global lock:\t%s\n",
ec->global_lock ? "yes" : "no");
- acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
-
end:
return 0;
}
@@ -619,154 +587,122 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
+static acpi_status
+ec_parse_io_ports(struct acpi_resource *resource, void *context);
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
+
+static struct acpi_ec *make_acpi_ec(void)
+{
+ struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec)
+ return NULL;
+
+ atomic_set(&ec->query_pending, 1);
+ atomic_set(&ec->event_count, 1);
+ mutex_init(&ec->lock);
+ init_waitqueue_head(&ec->wait);
+
+ return ec;
+}
static int acpi_ec_add(struct acpi_device *device)
{
- int result = 0;
acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
- ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec)
- return -ENOMEM;
-
- ec->handle = device->handle;
- ec->uid = -1;
- mutex_init(&ec->lock);
- atomic_set(&ec->query_pending, 0);
- atomic_set(&ec->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- atomic_set(&ec->leaving_burst, 1);
- init_waitqueue_head(&ec->wait);
- }
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
- acpi_driver_data(device) = ec;
-
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
-
- /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
- http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
- if (ec_ecdt) {
- acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler);
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
- &acpi_ec_gpe_handler);
+ ec = make_acpi_ec();
+ if (!ec)
+ return -ENOMEM;
- kfree(ec_ecdt);
+ status = ec_parse_device(device->handle, 0, ec, NULL);
+ if (status != AE_CTRL_TERMINATE) {
+ kfree(ec);
+ return -EINVAL;
}
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Obtaining GPE bit assignment"));
- result = -ENODEV;
- goto end;
- }
+ /* Check if we found the boot EC */
+ if (boot_ec) {
+ if (boot_ec->gpe == ec->gpe) {
+ /* We might have incorrect info for GL at boot time */
+ mutex_lock(&boot_ec->lock);
+ boot_ec->global_lock = ec->global_lock;
+ mutex_unlock(&boot_ec->lock);
+ kfree(ec);
+ ec = boot_ec;
+ }
+ } else
+ first_ec = ec;
+ ec->handle = device->handle;
+ acpi_driver_data(device) = ec;
- result = acpi_ec_add_fs(device);
- if (result)
- goto end;
+ acpi_ec_add_fs(device);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
acpi_device_name(device), acpi_device_bid(device),
(u32) ec->gpe));
- if (!first_ec)
- first_ec = device;
-
- end:
- if (result)
- kfree(ec);
-
- return result;
+ return 0;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
{
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
-
acpi_ec_remove_fs(device);
+ acpi_driver_data(device) = NULL;
+ if (ec == first_ec)
+ first_ec = NULL;
- kfree(ec);
-
+ /* Don't touch boot EC */
+ if (boot_ec != ec)
+ kfree(ec);
return 0;
}
static acpi_status
-acpi_ec_io_ports(struct acpi_resource *resource, void *context)
+ec_parse_io_ports(struct acpi_resource *resource, void *context)
{
- struct acpi_ec *ec = (struct acpi_ec *)context;
+ struct acpi_ec *ec = context;
- if (resource->type != ACPI_RESOURCE_TYPE_IO) {
+ if (resource->type != ACPI_RESOURCE_TYPE_IO)
return AE_OK;
- }
/*
* The first address region returned is the data port, and
* the second address region returned is the status/command
* port.
*/
- if (ec->data_addr == 0) {
+ if (ec->data_addr == 0)
ec->data_addr = resource->data.io.minimum;
- } else if (ec->command_addr == 0) {
+ else if (ec->command_addr == 0)
ec->command_addr = resource->data.io.minimum;
- } else {
+ else
return AE_CTRL_TERMINATE;
- }
return AE_OK;
}
-static int acpi_ec_start(struct acpi_device *device)
+static int ec_install_handlers(struct acpi_ec *ec)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
-
- if (!device)
- return -EINVAL;
-
- ec = acpi_driver_data(device);
-
- if (!ec)
- return -EINVAL;
-
- /*
- * Get I/O port addresses. Convert to GAS format.
- */
- status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec);
- if (ACPI_FAILURE(status) || ec->command_addr == 0) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Error getting I/O port addresses"));
- return -ENODEV;
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
- ec->gpe, ec->command_addr, ec->data_addr));
-
- /*
- * Install GPE handler
- */
+ acpi_status status;
status = acpi_install_gpe_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
- if (ACPI_FAILURE(status)) {
+ if (ACPI_FAILURE(status))
return -ENODEV;
- }
+
acpi_set_gpe_type(NULL, ec->gpe, ACPI_GPE_TYPE_RUNTIME);
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
@@ -779,18 +715,49 @@ static int acpi_ec_start(struct acpi_device *device)
return -ENODEV;
}
- return AE_OK;
+ /* EC is fully operational, allow queries */
+ atomic_set(&ec->query_pending, 0);
+
+ return 0;
+}
+
+static int acpi_ec_start(struct acpi_device *device)
+{
+ struct acpi_ec *ec;
+
+ if (!device)
+ return -EINVAL;
+
+ ec = acpi_driver_data(device);
+
+ if (!ec)
+ return -EINVAL;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+ ec->gpe, ec->command_addr, ec->data_addr));
+
+ /* Boot EC is already working */
+ if (ec == boot_ec)
+ return 0;
+
+ return ec_install_handlers(ec);
}
static int acpi_ec_stop(struct acpi_device *device, int type)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
+ if (!ec)
+ return -EINVAL;
+
+ /* Don't touch boot EC */
+ if (ec == boot_ec)
+ return 0;
status = acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
@@ -805,164 +772,67 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return 0;
}
-static acpi_status __init
-acpi_fake_ecdt_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
{
acpi_status status;
- mutex_init(&ec_ecdt->lock);
- atomic_set(&ec_ecdt->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec_ecdt->wait);
- }
+ struct acpi_ec *ec = context;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec_ecdt);
+ ec_parse_io_ports, ec);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
-
- status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe);
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->global_lock = TRUE;
- ec_ecdt->handle = handle;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
- ec_ecdt->gpe, ec_ecdt->command_addr,
- ec_ecdt->data_addr));
- return AE_CTRL_TERMINATE;
-}
-
-/*
- * Some BIOS (such as some from Gateway laptops) access EC region very early
- * such as in BAT0._INI or EC._INI before an EC device is found and
- * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
- * required, but if EC regison is accessed early, it is required.
- * The routine tries to workaround the BIOS bug by pre-scan EC device
- * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
- * op region (since _REG isn't invoked yet). The assumption is true for
- * all systems found.
- */
-static int __init acpi_ec_fake_ecdt(void)
-{
- acpi_status status;
- int ret = 0;
+ /* Use the global lock for all EC transactions? */
+ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
+ ec->handle = handle;
- ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec_ecdt) {
- ret = -ENOMEM;
- goto error;
- }
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+ ec->gpe, ec->command_addr, ec->data_addr));
- status = acpi_get_devices(ACPI_EC_HID,
- acpi_fake_ecdt_callback, NULL, NULL);
- if (ACPI_FAILURE(status)) {
- kfree(ec_ecdt);
- ec_ecdt = NULL;
- ret = -ENODEV;
- ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
- goto error;
- }
- return 0;
- error:
- return ret;
+ return AE_CTRL_TERMINATE;
}
-static int __init acpi_ec_get_real_ecdt(void)
+int __init acpi_ec_ecdt_probe(void)
{
+ int ret;
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_table(ACPI_SIG_ECDT, 1,
- (struct acpi_table_header **)&ecdt_ptr);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
-
+ boot_ec = make_acpi_ec();
+ if (!boot_ec)
+ return -ENOMEM;
/*
- * Generate a temporary ec context to use until the namespace is scanned
+ * Generate a boot ec context
*/
- ec_ecdt = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
- if (!ec_ecdt)
- return -ENOMEM;
- mutex_init(&ec_ecdt->lock);
- atomic_set(&ec_ecdt->event_count, 1);
- if (acpi_ec_mode == EC_INTR) {
- init_waitqueue_head(&ec_ecdt->wait);
- }
- ec_ecdt->command_addr = ecdt_ptr->control.address;
- ec_ecdt->data_addr = ecdt_ptr->data.address;
- ec_ecdt->gpe = ecdt_ptr->gpe;
- /* use the GL just to be safe */
- ec_ecdt->global_lock = TRUE;
- ec_ecdt->uid = ecdt_ptr->uid;
-
- status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
- if (ACPI_FAILURE(status)) {
+ status = acpi_get_table(ACPI_SIG_ECDT, 1,
+ (struct acpi_table_header **)&ecdt_ptr);
+ if (ACPI_FAILURE(status))
goto error;
- }
-
- return 0;
- error:
- ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
- kfree(ec_ecdt);
- ec_ecdt = NULL;
- return -ENODEV;
-}
-
-static int __initdata acpi_fake_ecdt_enabled;
-int __init acpi_ec_ecdt_probe(void)
-{
- acpi_status status;
- int ret;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
- ret = acpi_ec_get_real_ecdt();
- /* Try to make a fake ECDT */
- if (ret && acpi_fake_ecdt_enabled) {
- ret = acpi_ec_fake_ecdt();
- }
+ boot_ec->command_addr = ecdt_ptr->control.address;
+ boot_ec->data_addr = ecdt_ptr->data.address;
+ boot_ec->gpe = ecdt_ptr->gpe;
+ boot_ec->handle = ACPI_ROOT_OBJECT;
- if (ret)
+ ret = ec_install_handlers(boot_ec);
+ if (!ret) {
+ first_ec = boot_ec;
return 0;
-
- /*
- * Install GPE handler
- */
- status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe,
- ACPI_GPE_EDGE_TRIGGERED,
- &acpi_ec_gpe_handler, ec_ecdt);
- if (ACPI_FAILURE(status)) {
- goto error;
}
- acpi_set_gpe_type(NULL, ec_ecdt->gpe, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec_ecdt->gpe, ACPI_NOT_ISR);
-
- status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler,
- &acpi_ec_space_setup,
- ec_ecdt);
- if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec_ecdt->gpe,
- &acpi_ec_gpe_handler);
- goto error;
- }
-
- return 0;
-
error:
- ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
- kfree(ec_ecdt);
- ec_ecdt = NULL;
+ kfree(boot_ec);
+ boot_ec = NULL;
return -ENODEV;
}
@@ -1003,13 +873,6 @@ static void __exit acpi_ec_exit(void)
}
#endif /* 0 */
-static int __init acpi_fake_ecdt_setup(char *str)
-{
- acpi_fake_ecdt_enabled = 1;
- return 1;
-}
-
-__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
static int __init acpi_ec_set_intr_mode(char *str)
{
int intr;
@@ -1017,12 +880,8 @@ static int __init acpi_ec_set_intr_mode(char *str)
if (!get_option(&str, &intr))
return 0;
- if (intr) {
- acpi_ec_mode = EC_INTR;
- } else {
- acpi_ec_mode = EC_POLL;
- }
- acpi_ec_driver.ops.add = acpi_ec_add;
+ acpi_ec_mode = (intr) ? EC_INTR : EC_POLL;
+
printk(KERN_NOTICE PREFIX "%s mode.\n", intr ? "interrupt" : "polling");
return 1;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 4334c208841..41427a41f62 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -245,6 +245,35 @@ arch_initcall(init_acpi_device_notify);
#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+#ifdef CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup() do{}while(0)
+#define rtc_wake_on NULL
+#define rtc_wake_off NULL
+#endif
+
/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
* its device node and pass extra config data. This helps its driver use
* capabilities that the now-obsolete mc146818 didn't have, and informs it
@@ -283,11 +312,24 @@ static int __init acpi_rtc_init(void)
struct device *dev = get_rtc_dev();
if (dev) {
+ rtc_wake_setup();
+ rtc_info.wake_on = rtc_wake_on;
+ rtc_info.wake_off = rtc_wake_off;
+
+ /* workaround bug in some ACPI tables */
+ if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+ DBG("bogus FADT month_alarm\n");
+ acpi_gbl_FADT.month_alarm = 0;
+ }
+
rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
rtc_info.rtc_century = acpi_gbl_FADT.century;
- /* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */
+ /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
+ if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+ printk(PREFIX "RTC can wake from S4\n");
+
dev->platform_data = &rtc_info;
@@ -296,7 +338,7 @@ static int __init acpi_rtc_init(void)
put_device(dev);
} else
- pr_debug("ACPI: RTC unavailable?\n");
+ DBG("RTC unavailable?\n");
return 0;
}
/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
deleted file mode 100644
index acab4a48189..00000000000
--- a/drivers/acpi/i2c_ec.c
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
- *
- * 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 version 2.
- */
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/delay.h>
-
-#include "i2c_ec.h"
-
-#define xudelay(t) udelay(t)
-#define xmsleep(t) msleep(t)
-
-#define ACPI_EC_HC_COMPONENT 0x00080000
-#define ACPI_EC_HC_CLASS "ec_hc_smbus"
-#define ACPI_EC_HC_HID "ACPI0001"
-#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
-
-#define _COMPONENT ACPI_EC_HC_COMPONENT
-
-ACPI_MODULE_NAME("i2c_ec");
-
-static int acpi_ec_hc_add(struct acpi_device *device);
-static int acpi_ec_hc_remove(struct acpi_device *device, int type);
-
-static struct acpi_driver acpi_ec_hc_driver = {
- .name = "i2c_ec",
- .class = ACPI_EC_HC_CLASS,
- .ids = ACPI_EC_HC_HID,
- .ops = {
- .add = acpi_ec_hc_add,
- .remove = acpi_ec_hc_remove,
- },
-};
-
-/* Various bit mask for EC_SC (R) */
-#define OBF 0x01
-#define IBF 0x02
-#define CMD 0x08
-#define BURST 0x10
-#define SCI_EVT 0x20
-#define SMI_EVT 0x40
-
-/* Commands for EC_SC (W) */
-#define RD_EC 0x80
-#define WR_EC 0x81
-#define BE_EC 0x82
-#define BD_EC 0x83
-#define QR_EC 0x84
-
-/*
- * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
- */
-
-#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
-#define ACPI_EC_SMB_STS 0x01 /* status */
-#define ACPI_EC_SMB_ADDR 0x02 /* address */
-#define ACPI_EC_SMB_CMD 0x03 /* command */
-#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
-#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
-#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */
-#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
-
-#define ACPI_EC_SMB_STS_DONE 0x80
-#define ACPI_EC_SMB_STS_ALRM 0x40
-#define ACPI_EC_SMB_STS_RES 0x20
-#define ACPI_EC_SMB_STS_STATUS 0x1f
-
-#define ACPI_EC_SMB_STATUS_OK 0x00
-#define ACPI_EC_SMB_STATUS_FAIL 0x07
-#define ACPI_EC_SMB_STATUS_DNAK 0x10
-#define ACPI_EC_SMB_STATUS_DERR 0x11
-#define ACPI_EC_SMB_STATUS_CMD_DENY 0x12
-#define ACPI_EC_SMB_STATUS_UNKNOWN 0x13
-#define ACPI_EC_SMB_STATUS_ACC_DENY 0x17
-#define ACPI_EC_SMB_STATUS_TIMEOUT 0x18
-#define ACPI_EC_SMB_STATUS_NOTSUP 0x19
-#define ACPI_EC_SMB_STATUS_BUSY 0x1A
-#define ACPI_EC_SMB_STATUS_PEC 0x1F
-
-#define ACPI_EC_SMB_PRTCL_WRITE 0x00
-#define ACPI_EC_SMB_PRTCL_READ 0x01
-#define ACPI_EC_SMB_PRTCL_QUICK 0x02
-#define ACPI_EC_SMB_PRTCL_BYTE 0x04
-#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06
-#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
-#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
-#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c
-#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
-#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
-#define ACPI_EC_SMB_PRTCL_PEC 0x80
-
-/* Length of pre/post transaction sleep (msec) */
-#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
-#define ACPI_EC_SMB_ACCESS_SLEEP1 1
-#define ACPI_EC_SMB_ACCESS_SLEEP2 10
-
-static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
-{
- u8 val;
- int err;
-
- err = ec_read(smbus->base + address, &val);
- if (!err) {
- *data = val;
- }
- xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
- return (err);
-}
-
-static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
-{
- int err;
-
- err = ec_write(smbus->base + address, data);
- return (err);
-}
-
-static int
-acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
- char read_write, u8 command, int size,
- union i2c_smbus_data *data)
-{
- struct acpi_ec_smbus *smbus = adap->algo_data;
- unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
- int i;
-
- if (read_write == I2C_SMBUS_READ) {
- protocol = ACPI_EC_SMB_PRTCL_READ;
- } else {
- protocol = ACPI_EC_SMB_PRTCL_WRITE;
- }
- pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
-
- switch (size) {
-
- case I2C_SMBUS_QUICK:
- protocol |= ACPI_EC_SMB_PRTCL_QUICK;
- read_write = I2C_SMBUS_WRITE;
- break;
-
- case I2C_SMBUS_BYTE:
- if (read_write == I2C_SMBUS_WRITE) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BYTE;
- break;
-
- case I2C_SMBUS_BYTE_DATA:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
- break;
-
- case I2C_SMBUS_WORD_DATA:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
- data->word >> 8);
- }
- protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
- break;
-
- case I2C_SMBUS_BLOCK_DATA:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- if (read_write == I2C_SMBUS_WRITE) {
- len = min_t(u8, data->block[0], 32);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- }
- protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
- break;
-
- case I2C_SMBUS_I2C_BLOCK_DATA:
- len = min_t(u8, data->block[0], 32);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
- if (read_write == I2C_SMBUS_WRITE) {
- for (i = 0; i < len; i++) {
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- }
- }
- protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
- break;
-
- case I2C_SMBUS_PROC_CALL:
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
- protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
- read_write = I2C_SMBUS_READ;
- break;
-
- case I2C_SMBUS_BLOCK_PROC_CALL:
- protocol |= pec;
- len = min_t(u8, data->block[0], 31);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
- for (i = 0; i < len; i++)
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
- data->block[i + 1]);
- protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
- read_write = I2C_SMBUS_READ;
- break;
-
- default:
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
- "Unsupported transaction %d\n", size));
- return (-1);
- }
-
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
- acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
-
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
-
- if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
- xudelay(500);
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
- }
- if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
- xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
- }
- if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
- || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
- return (-1);
- }
-
- if (read_write == I2C_SMBUS_WRITE) {
- return (0);
- }
-
- switch (size) {
-
- case I2C_SMBUS_BYTE:
- case I2C_SMBUS_BYTE_DATA:
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
- break;
-
- case I2C_SMBUS_WORD_DATA:
- case I2C_SMBUS_PROC_CALL:
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
- data->word = (temp[1] << 8) | temp[0];
- break;
-
- case I2C_SMBUS_BLOCK_DATA:
- case I2C_SMBUS_BLOCK_PROC_CALL:
- len = 0;
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
- len = min_t(u8, len, 32);
- case I2C_SMBUS_I2C_BLOCK_DATA:
- for (i = 0; i < len; i++)
- acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
- data->block + i + 1);
- data->block[0] = len;
- break;
- }
-
- return (0);
-}
-
-static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
-{
-
- return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA |
- I2C_FUNC_SMBUS_PROC_CALL |
- I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
- I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
-}
-
-static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
- .smbus_xfer = acpi_ec_smb_access,
- .functionality = acpi_ec_smb_func,
-};
-
-static int acpi_ec_hc_add(struct acpi_device *device)
-{
- int status;
- unsigned long val;
- struct acpi_ec_hc *ec_hc;
- struct acpi_ec_smbus *smbus;
-
- if (!device) {
- return -EINVAL;
- }
-
- ec_hc = kzalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
- if (!ec_hc) {
- return -ENOMEM;
- }
-
- smbus = kzalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
- if (!smbus) {
- kfree(ec_hc);
- return -ENOMEM;
- }
-
- ec_hc->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
- acpi_driver_data(device) = ec_hc;
-
- status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
- kfree(ec_hc);
- kfree(smbus);
- return -EIO;
- }
-
- smbus->ec = acpi_driver_data(device->parent);
- smbus->base = (val & 0xff00ull) >> 8;
- smbus->alert = val & 0xffull;
-
- smbus->adapter.owner = THIS_MODULE;
- smbus->adapter.algo = &acpi_ec_smbus_algorithm;
- smbus->adapter.algo_data = smbus;
- smbus->adapter.dev.parent = &device->dev;
-
- if (i2c_add_adapter(&smbus->adapter)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "EC SMBus adapter: Failed to register adapter\n"));
- kfree(smbus);
- kfree(ec_hc);
- return -EIO;
- }
-
- ec_hc->smbus = smbus;
-
- printk(KERN_INFO PREFIX "%s [%s]\n",
- acpi_device_name(device), acpi_device_bid(device));
-
- return AE_OK;
-}
-
-static int acpi_ec_hc_remove(struct acpi_device *device, int type)
-{
- struct acpi_ec_hc *ec_hc;
-
- if (!device) {
- return -EINVAL;
- }
- ec_hc = acpi_driver_data(device);
-
- i2c_del_adapter(&ec_hc->smbus->adapter);
- kfree(ec_hc->smbus);
- kfree(ec_hc);
-
- return AE_OK;
-}
-
-static int __init acpi_ec_hc_init(void)
-{
- int result;
-
- result = acpi_bus_register_driver(&acpi_ec_hc_driver);
- if (result < 0) {
- return -ENODEV;
- }
- return 0;
-}
-
-static void __exit acpi_ec_hc_exit(void)
-{
- acpi_bus_unregister_driver(&acpi_ec_hc_driver);
-}
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
-{
- return acpi_driver_data(device->parent);
-}
-
-EXPORT_SYMBOL(acpi_get_ec_hc);
-
-module_init(acpi_ec_hc_init);
-module_exit(acpi_ec_hc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Ducrot Bruno");
-MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff --git a/drivers/acpi/i2c_ec.h b/drivers/acpi/i2c_ec.h
deleted file mode 100644
index 7c53fb732d6..00000000000
--- a/drivers/acpi/i2c_ec.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
- *
- * Copyright (c) 2002, 2005 Ducrot Bruno
- *
- * 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 version 2.
- */
-
-struct acpi_ec_smbus {
- struct i2c_adapter adapter;
- union acpi_ec *ec;
- int base;
- int alert;
-};
-
-struct acpi_ec_hc {
- acpi_handle handle;
- struct acpi_ec_smbus *smbus;
-};
-
-struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
deleted file mode 100644
index dc1096608f4..00000000000
--- a/drivers/acpi/ibm_acpi.c
+++ /dev/null
@@ -1,2798 +0,0 @@
-/*
- * ibm_acpi.c - IBM ThinkPad ACPI Extras
- *
- *
- * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
- * Copyright (C) 2006 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define IBM_VERSION "0.13"
-
-/*
- * Changelog:
- *
- * 2006-11-22 0.13 new maintainer
- * changelog now lives in git commit history, and will
- * not be updated further in-file.
- *
- * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
- * 2005-03-17 0.11 support for 600e, 770x
- * thanks to Jamie Lentin <lentinj@dial.pipex.com>
- * support for 770e, G41
- * G40 and G41 don't have a thinklight
- * temperatures no longer experimental
- * experimental brightness control
- * experimental volume control
- * experimental fan enable/disable
- * 2005-01-16 0.10 fix module loading on R30, R31
- * 2005-01-16 0.9 support for 570, R30, R31
- * ultrabay support on A22p, A3x
- * limit arg for cmos, led, beep, drop experimental status
- * more capable led control on A21e, A22p, T20-22, X20
- * experimental temperatures and fan speed
- * experimental embedded controller register dump
- * mark more functions as __init, drop incorrect __exit
- * use MODULE_VERSION
- * thanks to Henrik Brix Andersen <brix@gentoo.org>
- * fix parameter passing on module loading
- * thanks to Rusty Russell <rusty@rustcorp.com.au>
- * thanks to Jim Radford <radford@blackbean.org>
- * 2004-11-08 0.8 fix init error case, don't return from a macro
- * thanks to Chris Wright <chrisw@osdl.org>
- * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
- * fix led control on A21e
- * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
- * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
- * proc file format changed
- * video_switch command
- * experimental cmos control
- * experimental led control
- * experimental acpi sounds
- * 2004-09-16 0.4 support for module parameters
- * hotkey mask can be prefixed by 0x
- * video output switching
- * video expansion control
- * ultrabay eject support
- * removed lcd brightness/on/off control, didn't work
- * 2004-08-17 0.3 support for R40
- * lcd off, brightness control
- * thinklight on/off
- * 2004-08-14 0.2 support for T series, X20
- * bluetooth enable/disable
- * hotkey events disabled by default
- * removed fan control, currently useless
- * 2004-08-09 0.1 initial release, support for X series
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/string.h>
-
-#include <linux/proc_fs.h>
-#include <linux/backlight.h>
-#include <linux/fb.h>
-#include <asm/uaccess.h>
-
-#include <linux/dmi.h>
-#include <linux/jiffies.h>
-#include <linux/workqueue.h>
-
-#include <acpi/acpi_drivers.h>
-#include <acpi/acnamesp.h>
-
-#define IBM_NAME "ibm"
-#define IBM_DESC "IBM ThinkPad ACPI Extras"
-#define IBM_FILE "ibm_acpi"
-#define IBM_URL "http://ibm-acpi.sf.net/"
-
-MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
-MODULE_DESCRIPTION(IBM_DESC);
-MODULE_VERSION(IBM_VERSION);
-MODULE_LICENSE("GPL");
-
-#define IBM_DIR IBM_NAME
-
-#define IBM_LOG IBM_FILE ": "
-#define IBM_ERR KERN_ERR IBM_LOG
-#define IBM_NOTICE KERN_NOTICE IBM_LOG
-#define IBM_INFO KERN_INFO IBM_LOG
-#define IBM_DEBUG KERN_DEBUG IBM_LOG
-
-#define IBM_MAX_ACPI_ARGS 3
-
-#define __unused __attribute__ ((unused))
-
-static int experimental;
-module_param(experimental, int, 0);
-
-static acpi_handle root_handle = NULL;
-
-#define IBM_HANDLE(object, parent, paths...) \
- static acpi_handle object##_handle; \
- static acpi_handle *object##_parent = &parent##_handle; \
- static char *object##_path; \
- static char *object##_paths[] = { paths }
-
-IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
- "\\_SB.PCI.ISA.EC", /* 570 */
- "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
- "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
- "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
- "\\_SB.PCI0.ICH3.EC0", /* R31 */
- "\\_SB.PCI0.LPC.EC", /* all others */
- );
-
-IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
- "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
- "\\_SB.PCI0.VID0", /* 770e */
- "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
- "\\_SB.PCI0.AGP.VID", /* all others */
- ); /* R30, R31 */
-
-IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
-
-IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
- "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
- "\\CMS", /* R40, R40e */
- ); /* all others */
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
- "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
- "\\_SB.PCI0.PCI1.DOCK", /* all others */
- "\\_SB.PCI.ISA.SLCE", /* 570 */
- ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
- "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
- "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
- "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
- ); /* A21e, R30, R31 */
-
-IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
- "_EJ0", /* all others */
- ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
-
-IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
- "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
- ); /* all others */
-
-IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
- "_EJ0", /* 770x */
- ); /* all others */
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-/* don't list other alternatives as we install a notify handler on the 570 */
-IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
-
-IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
- "^HKEY", /* R30, R31 */
- "HKEY", /* all others */
- ); /* 570 */
-
-IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
-IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
-
-IBM_HANDLE(led, ec, "SLED", /* 570 */
- "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- "LED", /* all others */
- ); /* R30, R31 */
-
-IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
-IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
-IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
-IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
-
-IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
- "\\FSPD", /* 600e/x, 770e, 770x */
- ); /* all others */
-
-IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
- "JFNS", /* 770x-JL */
- ); /* all others */
-
-#define IBM_HKEY_HID "IBM0068"
-#define IBM_PCI_HID "PNP0A03"
-
-enum thermal_access_mode {
- IBMACPI_THERMAL_NONE = 0, /* No thermal support */
- IBMACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
- IBMACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
- IBMACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
- IBMACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
-};
-
-#define IBMACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
-struct ibm_thermal_sensors_struct {
- s32 temp[IBMACPI_MAX_THERMAL_SENSORS];
-};
-
-/*
- * FAN ACCESS MODES
- *
- * IBMACPI_FAN_RD_ACPI_GFAN:
- * ACPI GFAN method: returns fan level
- *
- * see IBMACPI_FAN_WR_ACPI_SFAN
- * EC 0x2f not available if GFAN exists
- *
- * IBMACPI_FAN_WR_ACPI_SFAN:
- * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
- *
- * EC 0x2f might be available *for reading*, but never for writing.
- *
- * IBMACPI_FAN_WR_TPEC:
- * ThinkPad EC register 0x2f (HFSP): fan control loop mode Supported
- * on almost all ThinkPads
- *
- * Fan speed changes of any sort (including those caused by the
- * disengaged mode) are usually done slowly by the firmware as the
- * maximum ammount of fan duty cycle change per second seems to be
- * limited.
- *
- * Reading is not available if GFAN exists.
- * Writing is not available if SFAN exists.
- *
- * Bits
- * 7 automatic mode engaged;
- * (default operation mode of the ThinkPad)
- * fan level is ignored in this mode.
- * 6 disengage mode (takes precedence over bit 7);
- * not available on all thinkpads. May disable
- * the tachometer, and speeds up fan to 100% duty-cycle,
- * which speeds it up far above the standard RPM
- * levels. It is not impossible that it could cause
- * hardware damage.
- * 5-3 unused in some models. Extra bits for fan level
- * in others, but still useless as all values above
- * 7 map to the same speed as level 7 in these models.
- * 2-0 fan level (0..7 usually)
- * 0x00 = stop
- * 0x07 = max (set when temperatures critical)
- * Some ThinkPads may have other levels, see
- * IBMACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
- *
- * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
- * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
- * does so, its initial value is meaningless (0x07).
- *
- * For firmware bugs, refer to:
- * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * ----
- *
- * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
- * Main fan tachometer reading (in RPM)
- *
- * This register is present on all ThinkPads with a new-style EC, and
- * it is known not to be present on the A21m/e, and T22, as there is
- * something else in offset 0x84 according to the ACPI DSDT. Other
- * ThinkPads from this same time period (and earlier) probably lack the
- * tachometer as well.
- *
- * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
- * was never fixed by IBM to report the EC firmware version string
- * probably support the tachometer (like the early X models), so
- * detecting it is quite hard. We need more data to know for sure.
- *
- * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
- * might result.
- *
- * FIRMWARE BUG: when EC 0x2f bit 6 is set (disengaged mode), this
- * register is not invalidated in ThinkPads that disable tachometer
- * readings. Thus, the tachometer readings go stale.
- *
- * For firmware bugs, refer to:
- * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
- *
- * IBMACPI_FAN_WR_ACPI_FANS:
- * ThinkPad X31, X40, X41. Not available in the X60.
- *
- * FANS ACPI handle: takes three arguments: low speed, medium speed,
- * high speed. ACPI DSDT seems to map these three speeds to levels
- * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
- * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
- *
- * The speeds are stored on handles
- * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
- *
- * There are three default speed sets, acessible as handles:
- * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
- *
- * ACPI DSDT switches which set is in use depending on various
- * factors.
- *
- * IBMACPI_FAN_WR_TPEC is also available and should be used to
- * command the fan. The X31/X40/X41 seems to have 8 fan levels,
- * but the ACPI tables just mention level 7.
- */
-
-enum fan_status_access_mode {
- IBMACPI_FAN_NONE = 0, /* No fan status or control */
- IBMACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
- IBMACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
-};
-
-enum fan_control_access_mode {
- IBMACPI_FAN_WR_NONE = 0, /* No fan control */
- IBMACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
- IBMACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
- IBMACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
-};
-
-enum fan_control_commands {
- IBMACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
- IBMACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
- IBMACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
- * and also watchdog cmd */
-};
-
-enum { /* Fan control constants */
- fan_status_offset = 0x2f, /* EC register 0x2f */
- fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
- * 0x84 must be read before 0x85 */
-
- IBMACPI_FAN_EC_DISENGAGED = 0x40, /* EC mode: tachometer
- * disengaged */
- IBMACPI_FAN_EC_AUTO = 0x80, /* EC mode: auto fan
- * control */
-};
-
-static char *ibm_thinkpad_ec_found = NULL;
-
-struct ibm_struct {
- char *name;
- char param[32];
-
- char *hid;
- struct acpi_driver *driver;
-
- int (*init) (void);
- int (*read) (char *);
- int (*write) (char *);
- void (*exit) (void);
-
- void (*notify) (struct ibm_struct *, u32);
- acpi_handle *handle;
- int type;
- struct acpi_device *device;
-
- int driver_registered;
- int proc_created;
- int init_called;
- int notify_installed;
-
- int experimental;
-};
-
-static struct proc_dir_entry *proc_dir = NULL;
-
-static struct backlight_device *ibm_backlight_device = NULL;
-
-#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
-#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
-#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
-
-static int acpi_evalf(acpi_handle handle,
- void *res, char *method, char *fmt, ...)
-{
- char *fmt0 = fmt;
- struct acpi_object_list params;
- union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
- struct acpi_buffer result, *resultp;
- union acpi_object out_obj;
- acpi_status status;
- va_list ap;
- char res_type;
- int success;
- int quiet;
-
- if (!*fmt) {
- printk(IBM_ERR "acpi_evalf() called with empty format\n");
- return 0;
- }
-
- if (*fmt == 'q') {
- quiet = 1;
- fmt++;
- } else
- quiet = 0;
-
- res_type = *(fmt++);
-
- params.count = 0;
- params.pointer = &in_objs[0];
-
- va_start(ap, fmt);
- while (*fmt) {
- char c = *(fmt++);
- switch (c) {
- case 'd': /* int */
- in_objs[params.count].integer.value = va_arg(ap, int);
- in_objs[params.count++].type = ACPI_TYPE_INTEGER;
- break;
- /* add more types as needed */
- default:
- printk(IBM_ERR "acpi_evalf() called "
- "with invalid format character '%c'\n", c);
- return 0;
- }
- }
- va_end(ap);
-
- if (res_type != 'v') {
- result.length = sizeof(out_obj);
- result.pointer = &out_obj;
- resultp = &result;
- } else
- resultp = NULL;
-
- status = acpi_evaluate_object(handle, method, &params, resultp);
-
- switch (res_type) {
- case 'd': /* int */
- if (res)
- *(int *)res = out_obj.integer.value;
- success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
- break;
- case 'v': /* void */
- success = status == AE_OK;
- break;
- /* add more types as needed */
- default:
- printk(IBM_ERR "acpi_evalf() called "
- "with invalid format character '%c'\n", res_type);
- return 0;
- }
-
- if (!success && !quiet)
- printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
- method, fmt0, status);
-
- return success;
-}
-
-static void __unused acpi_print_int(acpi_handle handle, char *method)
-{
- int i;
-
- if (acpi_evalf(handle, &i, method, "d"))
- printk(IBM_INFO "%s = 0x%x\n", method, i);
- else
- printk(IBM_ERR "error calling %s\n", method);
-}
-
-static char *next_cmd(char **cmds)
-{
- char *start = *cmds;
- char *end;
-
- while ((end = strchr(start, ',')) && end == start)
- start = end + 1;
-
- if (!end)
- return NULL;
-
- *end = 0;
- *cmds = end + 1;
- return start;
-}
-
-static int ibm_acpi_driver_init(void)
-{
- printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
- printk(IBM_INFO "%s\n", IBM_URL);
-
- if (ibm_thinkpad_ec_found)
- printk(IBM_INFO "ThinkPad EC firmware %s\n",
- ibm_thinkpad_ec_found);
-
- return 0;
-}
-
-static int driver_read(char *p)
-{
- int len = 0;
-
- len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
- len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
-
- return len;
-}
-
-static int hotkey_supported;
-static int hotkey_mask_supported;
-static int hotkey_orig_status;
-static int hotkey_orig_mask;
-
-static int hotkey_get(int *status, int *mask)
-{
- if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
- return 0;
-
- if (hotkey_mask_supported)
- if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
- return 0;
-
- return 1;
-}
-
-static int hotkey_set(int status, int mask)
-{
- int i;
-
- if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
- return 0;
-
- if (hotkey_mask_supported)
- for (i = 0; i < 32; i++) {
- int bit = ((1 << i) & mask) != 0;
- if (!acpi_evalf(hkey_handle,
- NULL, "MHKM", "vdd", i + 1, bit))
- return 0;
- }
-
- return 1;
-}
-
-static int hotkey_init(void)
-{
- /* hotkey not supported on 570 */
- hotkey_supported = hkey_handle != NULL;
-
- if (hotkey_supported) {
- /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- A30, R30, R31, T20-22, X20-21, X22-24 */
- hotkey_mask_supported =
- acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
-
- if (!hotkey_get(&hotkey_orig_status, &hotkey_orig_mask))
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int hotkey_read(char *p)
-{
- int status, mask;
- int len = 0;
-
- if (!hotkey_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- return len;
- }
-
- if (!hotkey_get(&status, &mask))
- return -EIO;
-
- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
- if (hotkey_mask_supported) {
- len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
- len += sprintf(p + len,
- "commands:\tenable, disable, reset, <mask>\n");
- } else {
- len += sprintf(p + len, "mask:\t\tnot supported\n");
- len += sprintf(p + len, "commands:\tenable, disable, reset\n");
- }
-
- return len;
-}
-
-static int hotkey_write(char *buf)
-{
- int status, mask;
- char *cmd;
- int do_cmd = 0;
-
- if (!hotkey_supported)
- return -ENODEV;
-
- if (!hotkey_get(&status, &mask))
- return -EIO;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "enable") == 0) {
- status = 1;
- } else if (strlencmp(cmd, "disable") == 0) {
- status = 0;
- } else if (strlencmp(cmd, "reset") == 0) {
- status = hotkey_orig_status;
- mask = hotkey_orig_mask;
- } else if (sscanf(cmd, "0x%x", &mask) == 1) {
- /* mask set */
- } else if (sscanf(cmd, "%x", &mask) == 1) {
- /* mask set */
- } else
- return -EINVAL;
- do_cmd = 1;
- }
-
- if (do_cmd && !hotkey_set(status, mask))
- return -EIO;
-
- return 0;
-}
-
-static void hotkey_exit(void)
-{
- if (hotkey_supported)
- hotkey_set(hotkey_orig_status, hotkey_orig_mask);
-}
-
-static void hotkey_notify(struct ibm_struct *ibm, u32 event)
-{
- int hkey;
-
- if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
- acpi_bus_generate_event(ibm->device, event, hkey);
- else {
- printk(IBM_ERR "unknown hotkey event %d\n", event);
- acpi_bus_generate_event(ibm->device, event, 0);
- }
-}
-
-static int bluetooth_supported;
-
-static int bluetooth_init(void)
-{
- /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
- bluetooth_supported = hkey_handle &&
- acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
-
- return 0;
-}
-
-static int bluetooth_status(void)
-{
- int status;
-
- if (!bluetooth_supported ||
- !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
- status = 0;
-
- return status;
-}
-
-static int bluetooth_read(char *p)
-{
- int len = 0;
- int status = bluetooth_status();
-
- if (!bluetooth_supported)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!(status & 1))
- len += sprintf(p + len, "status:\t\tnot installed\n");
- else {
- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
- len += sprintf(p + len, "commands:\tenable, disable\n");
- }
-
- return len;
-}
-
-static int bluetooth_write(char *buf)
-{
- int status = bluetooth_status();
- char *cmd;
- int do_cmd = 0;
-
- if (!bluetooth_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "enable") == 0) {
- status |= 2;
- } else if (strlencmp(cmd, "disable") == 0) {
- status &= ~2;
- } else
- return -EINVAL;
- do_cmd = 1;
- }
-
- if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
- return -EIO;
-
- return 0;
-}
-
-static int wan_supported;
-
-static int wan_init(void)
-{
- wan_supported = hkey_handle &&
- acpi_evalf(hkey_handle, NULL, "GWAN", "qv");
-
- return 0;
-}
-
-static int wan_status(void)
-{
- int status;
-
- if (!wan_supported || !acpi_evalf(hkey_handle, &status, "GWAN", "d"))
- status = 0;
-
- return status;
-}
-
-static int wan_read(char *p)
-{
- int len = 0;
- int status = wan_status();
-
- if (!wan_supported)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!(status & 1))
- len += sprintf(p + len, "status:\t\tnot installed\n");
- else {
- len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
- len += sprintf(p + len, "commands:\tenable, disable\n");
- }
-
- return len;
-}
-
-static int wan_write(char *buf)
-{
- int status = wan_status();
- char *cmd;
- int do_cmd = 0;
-
- if (!wan_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "enable") == 0) {
- status |= 2;
- } else if (strlencmp(cmd, "disable") == 0) {
- status &= ~2;
- } else
- return -EINVAL;
- do_cmd = 1;
- }
-
- if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
- return -EIO;
-
- return 0;
-}
-
-enum video_access_mode {
- IBMACPI_VIDEO_NONE = 0,
- IBMACPI_VIDEO_570, /* 570 */
- IBMACPI_VIDEO_770, /* 600e/x, 770e, 770x */
- IBMACPI_VIDEO_NEW, /* all others */
-};
-
-static enum video_access_mode video_supported;
-static int video_orig_autosw;
-
-static int video_init(void)
-{
- int ivga;
-
- if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
- /* G41, assume IVGA doesn't change */
- vid_handle = vid2_handle;
-
- if (!vid_handle)
- /* video switching not supported on R30, R31 */
- video_supported = IBMACPI_VIDEO_NONE;
- else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
- /* 570 */
- video_supported = IBMACPI_VIDEO_570;
- else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
- /* 600e/x, 770e, 770x */
- video_supported = IBMACPI_VIDEO_770;
- else
- /* all others */
- video_supported = IBMACPI_VIDEO_NEW;
-
- return 0;
-}
-
-static int video_status(void)
-{
- int status = 0;
- int i;
-
- if (video_supported == IBMACPI_VIDEO_570) {
- if (acpi_evalf(NULL, &i, "\\_SB.PHS", "dd", 0x87))
- status = i & 3;
- } else if (video_supported == IBMACPI_VIDEO_770) {
- if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
- status |= 0x01 * i;
- if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
- status |= 0x02 * i;
- } else if (video_supported == IBMACPI_VIDEO_NEW) {
- acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
- if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
- status |= 0x02 * i;
-
- acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
- if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
- status |= 0x01 * i;
- if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
- status |= 0x08 * i;
- }
-
- return status;
-}
-
-static int video_autosw(void)
-{
- int autosw = 0;
-
- if (video_supported == IBMACPI_VIDEO_570)
- acpi_evalf(vid_handle, &autosw, "SWIT", "d");
- else if (video_supported == IBMACPI_VIDEO_770 ||
- video_supported == IBMACPI_VIDEO_NEW)
- acpi_evalf(vid_handle, &autosw, "^VDEE", "d");
-
- return autosw & 1;
-}
-
-static int video_read(char *p)
-{
- int status = video_status();
- int autosw = video_autosw();
- int len = 0;
-
- if (!video_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- return len;
- }
-
- len += sprintf(p + len, "status:\t\tsupported\n");
- len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
- len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
- if (video_supported == IBMACPI_VIDEO_NEW)
- len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
- len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
- len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
- len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
- if (video_supported == IBMACPI_VIDEO_NEW)
- len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
- len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
- len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
-
- return len;
-}
-
-static int video_switch(void)
-{
- int autosw = video_autosw();
- int ret;
-
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
- return -EIO;
- ret = video_supported == IBMACPI_VIDEO_570 ?
- acpi_evalf(ec_handle, NULL, "_Q16", "v") :
- acpi_evalf(vid_handle, NULL, "VSWT", "v");
- acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
-
- return ret;
-}
-
-static int video_expand(void)
-{
- if (video_supported == IBMACPI_VIDEO_570)
- return acpi_evalf(ec_handle, NULL, "_Q17", "v");
- else if (video_supported == IBMACPI_VIDEO_770)
- return acpi_evalf(vid_handle, NULL, "VEXP", "v");
- else
- return acpi_evalf(NULL, NULL, "\\VEXP", "v");
-}
-
-static int video_switch2(int status)
-{
- int ret;
-
- if (video_supported == IBMACPI_VIDEO_570) {
- ret = acpi_evalf(NULL, NULL,
- "\\_SB.PHS2", "vdd", 0x8b, status | 0x80);
- } else if (video_supported == IBMACPI_VIDEO_770) {
- int autosw = video_autosw();
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
- return -EIO;
-
- ret = acpi_evalf(vid_handle, NULL,
- "ASWT", "vdd", status * 0x100, 0);
-
- acpi_evalf(vid_handle, NULL, "_DOS", "vd", autosw);
- } else {
- ret = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
- acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
- }
-
- return ret;
-}
-
-static int video_write(char *buf)
-{
- char *cmd;
- int enable, disable, status;
-
- if (!video_supported)
- return -ENODEV;
-
- enable = disable = 0;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "lcd_enable") == 0) {
- enable |= 0x01;
- } else if (strlencmp(cmd, "lcd_disable") == 0) {
- disable |= 0x01;
- } else if (strlencmp(cmd, "crt_enable") == 0) {
- enable |= 0x02;
- } else if (strlencmp(cmd, "crt_disable") == 0) {
- disable |= 0x02;
- } else if (video_supported == IBMACPI_VIDEO_NEW &&
- strlencmp(cmd, "dvi_enable") == 0) {
- enable |= 0x08;
- } else if (video_supported == IBMACPI_VIDEO_NEW &&
- strlencmp(cmd, "dvi_disable") == 0) {
- disable |= 0x08;
- } else if (strlencmp(cmd, "auto_enable") == 0) {
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
- return -EIO;
- } else if (strlencmp(cmd, "auto_disable") == 0) {
- if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
- return -EIO;
- } else if (strlencmp(cmd, "video_switch") == 0) {
- if (!video_switch())
- return -EIO;
- } else if (strlencmp(cmd, "expand_toggle") == 0) {
- if (!video_expand())
- return -EIO;
- } else
- return -EINVAL;
- }
-
- if (enable || disable) {
- status = (video_status() & 0x0f & ~disable) | enable;
- if (!video_switch2(status))
- return -EIO;
- }
-
- return 0;
-}
-
-static void video_exit(void)
-{
- acpi_evalf(vid_handle, NULL, "_DOS", "vd", video_orig_autosw);
-}
-
-static int light_supported;
-static int light_status_supported;
-
-static int light_init(void)
-{
- /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
- light_supported = (cmos_handle || lght_handle) && !ledb_handle;
-
- if (light_supported)
- /* light status not supported on
- 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
- light_status_supported = acpi_evalf(ec_handle, NULL,
- "KBLT", "qv");
-
- return 0;
-}
-
-static int light_read(char *p)
-{
- int len = 0;
- int status = 0;
-
- if (!light_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- } else if (!light_status_supported) {
- len += sprintf(p + len, "status:\t\tunknown\n");
- len += sprintf(p + len, "commands:\ton, off\n");
- } else {
- if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
- return -EIO;
- len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
- len += sprintf(p + len, "commands:\ton, off\n");
- }
-
- return len;
-}
-
-static int light_write(char *buf)
-{
- int cmos_cmd, lght_cmd;
- char *cmd;
- int success;
-
- if (!light_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "on") == 0) {
- cmos_cmd = 0x0c;
- lght_cmd = 1;
- } else if (strlencmp(cmd, "off") == 0) {
- cmos_cmd = 0x0d;
- lght_cmd = 0;
- } else
- return -EINVAL;
-
- success = cmos_handle ?
- acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
- acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
- if (!success)
- return -EIO;
- }
-
- return 0;
-}
-
-#if defined(CONFIG_ACPI_IBM_DOCK) || defined(CONFIG_ACPI_IBM_BAY)
-static int _sta(acpi_handle handle)
-{
- int status;
-
- if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
- status = 0;
-
- return status;
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_DOCK
-#define dock_docked() (_sta(dock_handle) & 1)
-
-static int dock_read(char *p)
-{
- int len = 0;
- int docked = dock_docked();
-
- if (!dock_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else if (!docked)
- len += sprintf(p + len, "status:\t\tundocked\n");
- else {
- len += sprintf(p + len, "status:\t\tdocked\n");
- len += sprintf(p + len, "commands:\tdock, undock\n");
- }
-
- return len;
-}
-
-static int dock_write(char *buf)
-{
- char *cmd;
-
- if (!dock_docked())
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (strlencmp(cmd, "undock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
- !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
- return -EIO;
- } else if (strlencmp(cmd, "dock") == 0) {
- if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void dock_notify(struct ibm_struct *ibm, u32 event)
-{
- int docked = dock_docked();
- int pci = ibm->hid && strstr(ibm->hid, IBM_PCI_HID);
-
- if (event == 1 && !pci) /* 570 */
- acpi_bus_generate_event(ibm->device, event, 1); /* button */
- else if (event == 1 && pci) /* 570 */
- acpi_bus_generate_event(ibm->device, event, 3); /* dock */
- else if (event == 3 && docked)
- acpi_bus_generate_event(ibm->device, event, 1); /* button */
- else if (event == 3 && !docked)
- acpi_bus_generate_event(ibm->device, event, 2); /* undock */
- else if (event == 0 && docked)
- acpi_bus_generate_event(ibm->device, event, 3); /* dock */
- else {
- printk(IBM_ERR "unknown dock event %d, status %d\n",
- event, _sta(dock_handle));
- acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
- }
-}
-#endif
-
-#ifdef CONFIG_ACPI_IBM_BAY
-static int bay_status_supported;
-static int bay_status2_supported;
-static int bay_eject_supported;
-static int bay_eject2_supported;
-
-static int bay_init(void)
-{
- bay_status_supported = bay_handle &&
- acpi_evalf(bay_handle, NULL, "_STA", "qv");
- bay_status2_supported = bay2_handle &&
- acpi_evalf(bay2_handle, NULL, "_STA", "qv");
-
- bay_eject_supported = bay_handle && bay_ej_handle &&
- (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
- bay_eject2_supported = bay2_handle && bay2_ej_handle &&
- (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
-
- return 0;
-}
-
-#define bay_occupied(b) (_sta(b##_handle) & 1)
-
-static int bay_read(char *p)
-{
- int len = 0;
- int occupied = bay_occupied(bay);
- int occupied2 = bay_occupied(bay2);
- int eject, eject2;
-
- len += sprintf(p + len, "status:\t\t%s\n", bay_status_supported ?
- (occupied ? "occupied" : "unoccupied") :
- "not supported");
- if (bay_status2_supported)
- len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
- "occupied" : "unoccupied");
-
- eject = bay_eject_supported && occupied;
- eject2 = bay_eject2_supported && occupied2;
-
- if (eject && eject2)
- len += sprintf(p + len, "commands:\teject, eject2\n");
- else if (eject)
- len += sprintf(p + len, "commands:\teject\n");
- else if (eject2)
- len += sprintf(p + len, "commands:\teject2\n");
-
- return len;
-}
-
-static int bay_write(char *buf)
-{
- char *cmd;
-
- if (!bay_eject_supported && !bay_eject2_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (bay_eject_supported && strlencmp(cmd, "eject") == 0) {
- if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else if (bay_eject2_supported &&
- strlencmp(cmd, "eject2") == 0) {
- if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void bay_notify(struct ibm_struct *ibm, u32 event)
-{
- acpi_bus_generate_event(ibm->device, event, 0);
-}
-#endif /* CONFIG_ACPI_IBM_BAY */
-
-static int cmos_read(char *p)
-{
- int len = 0;
-
- /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
- R30, R31, T20-22, X20-21 */
- if (!cmos_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else {
- len += sprintf(p + len, "status:\t\tsupported\n");
- len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
- }
-
- return len;
-}
-
-static int cmos_eval(int cmos_cmd)
-{
- if (cmos_handle)
- return acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd);
- else
- return 1;
-}
-
-static int cmos_write(char *buf)
-{
- char *cmd;
- int cmos_cmd;
-
- if (!cmos_handle)
- return -EINVAL;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
- cmos_cmd >= 0 && cmos_cmd <= 21) {
- /* cmos_cmd set */
- } else
- return -EINVAL;
-
- if (!cmos_eval(cmos_cmd))
- return -EIO;
- }
-
- return 0;
-}
-
-enum led_access_mode {
- IBMACPI_LED_NONE = 0,
- IBMACPI_LED_570, /* 570 */
- IBMACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- IBMACPI_LED_NEW, /* all others */
-};
-static enum led_access_mode led_supported;
-
-static int led_init(void)
-{
- if (!led_handle)
- /* led not supported on R30, R31 */
- led_supported = IBMACPI_LED_NONE;
- else if (strlencmp(led_path, "SLED") == 0)
- /* 570 */
- led_supported = IBMACPI_LED_570;
- else if (strlencmp(led_path, "SYSL") == 0)
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
- led_supported = IBMACPI_LED_OLD;
- else
- /* all others */
- led_supported = IBMACPI_LED_NEW;
-
- return 0;
-}
-
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
-
-static int led_read(char *p)
-{
- int len = 0;
-
- if (!led_supported) {
- len += sprintf(p + len, "status:\t\tnot supported\n");
- return len;
- }
- len += sprintf(p + len, "status:\t\tsupported\n");
-
- if (led_supported == IBMACPI_LED_570) {
- /* 570 */
- int i, status;
- for (i = 0; i < 8; i++) {
- if (!acpi_evalf(ec_handle,
- &status, "GLED", "dd", 1 << i))
- return -EIO;
- len += sprintf(p + len, "%d:\t\t%s\n",
- i, led_status(status));
- }
- }
-
- len += sprintf(p + len, "commands:\t"
- "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
-
- return len;
-}
-
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
-#define EC_HLCL 0x0c
-#define EC_HLBL 0x0d
-#define EC_HLMS 0x0e
-
-static int led_write(char *buf)
-{
- char *cmd;
- int led, ind, ret;
-
- if (!led_supported)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
- return -EINVAL;
-
- if (strstr(cmd, "off")) {
- ind = 0;
- } else if (strstr(cmd, "on")) {
- ind = 1;
- } else if (strstr(cmd, "blink")) {
- ind = 2;
- } else
- return -EINVAL;
-
- if (led_supported == IBMACPI_LED_570) {
- /* 570 */
- led = 1 << led;
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_sled_arg1[ind]))
- return -EIO;
- } else if (led_supported == IBMACPI_LED_OLD) {
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
- led = 1 << led;
- ret = ec_write(EC_HLMS, led);
- if (ret >= 0)
- ret =
- ec_write(EC_HLBL, led * led_exp_hlbl[ind]);
- if (ret >= 0)
- ret =
- ec_write(EC_HLCL, led * led_exp_hlcl[ind]);
- if (ret < 0)
- return ret;
- } else {
- /* all others */
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_led_arg1[ind]))
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int beep_read(char *p)
-{
- int len = 0;
-
- if (!beep_handle)
- len += sprintf(p + len, "status:\t\tnot supported\n");
- else {
- len += sprintf(p + len, "status:\t\tsupported\n");
- len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
- }
-
- return len;
-}
-
-static int beep_write(char *buf)
-{
- char *cmd;
- int beep_cmd;
-
- if (!beep_handle)
- return -ENODEV;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
- beep_cmd >= 0 && beep_cmd <= 17) {
- /* beep_cmd set */
- } else
- return -EINVAL;
- if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
- return -EIO;
- }
-
- return 0;
-}
-
-static int acpi_ec_read(int i, u8 * p)
-{
- int v;
-
- if (ecrd_handle) {
- if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
- return 0;
- *p = v;
- } else {
- if (ec_read(i, p) < 0)
- return 0;
- }
-
- return 1;
-}
-
-static int acpi_ec_write(int i, u8 v)
-{
- if (ecwr_handle) {
- if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
- return 0;
- } else {
- if (ec_write(i, v) < 0)
- return 0;
- }
-
- return 1;
-}
-
-static enum thermal_access_mode thermal_read_mode;
-
-static int thermal_init(void)
-{
- u8 t, ta1, ta2;
- int i;
- int acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
-
- if (ibm_thinkpad_ec_found && experimental) {
- /*
- * Direct EC access mode: sensors at registers
- * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
- * non-implemented, thermal sensors return 0x80 when
- * not available
- */
-
- ta1 = ta2 = 0;
- for (i = 0; i < 8; i++) {
- if (likely(acpi_ec_read(0x78 + i, &t))) {
- ta1 |= t;
- } else {
- ta1 = 0;
- break;
- }
- if (likely(acpi_ec_read(0xC0 + i, &t))) {
- ta2 |= t;
- } else {
- ta1 = 0;
- break;
- }
- }
- if (ta1 == 0) {
- /* This is sheer paranoia, but we handle it anyway */
- if (acpi_tmp7) {
- printk(IBM_ERR
- "ThinkPad ACPI EC access misbehaving, "
- "falling back to ACPI TMPx access mode\n");
- thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
- } else {
- printk(IBM_ERR
- "ThinkPad ACPI EC access misbehaving, "
- "disabling thermal sensors access\n");
- thermal_read_mode = IBMACPI_THERMAL_NONE;
- }
- } else {
- thermal_read_mode =
- (ta2 != 0) ?
- IBMACPI_THERMAL_TPEC_16 : IBMACPI_THERMAL_TPEC_8;
- }
- } else if (acpi_tmp7) {
- if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
- /* 600e/x, 770e, 770x */
- thermal_read_mode = IBMACPI_THERMAL_ACPI_UPDT;
- } else {
- /* Standard ACPI TMPx access, max 8 sensors */
- thermal_read_mode = IBMACPI_THERMAL_ACPI_TMP07;
- }
- } else {
- /* temperatures not supported on 570, G4x, R30, R31, R32 */
- thermal_read_mode = IBMACPI_THERMAL_NONE;
- }
-
- return 0;
-}
-
-static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
-{
- int i, t;
- s8 tmp;
- char tmpi[] = "TMPi";
-
- if (!s)
- return -EINVAL;
-
- switch (thermal_read_mode) {
-#if IBMACPI_MAX_THERMAL_SENSORS >= 16
- case IBMACPI_THERMAL_TPEC_16:
- for (i = 0; i < 8; i++) {
- if (!acpi_ec_read(0xC0 + i, &tmp))
- return -EIO;
- s->temp[i + 8] = tmp * 1000;
- }
- /* fallthrough */
-#endif
- case IBMACPI_THERMAL_TPEC_8:
- for (i = 0; i < 8; i++) {
- if (!acpi_ec_read(0x78 + i, &tmp))
- return -EIO;
- s->temp[i] = tmp * 1000;
- }
- return (thermal_read_mode == IBMACPI_THERMAL_TPEC_16) ? 16 : 8;
-
- case IBMACPI_THERMAL_ACPI_UPDT:
- if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
- return -EIO;
- for (i = 0; i < 8; i++) {
- tmpi[3] = '0' + i;
- if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
- return -EIO;
- s->temp[i] = (t - 2732) * 100;
- }
- return 8;
-
- case IBMACPI_THERMAL_ACPI_TMP07:
- for (i = 0; i < 8; i++) {
- tmpi[3] = '0' + i;
- if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
- return -EIO;
- s->temp[i] = t * 1000;
- }
- return 8;
-
- case IBMACPI_THERMAL_NONE:
- default:
- return 0;
- }
-}
-
-static int thermal_read(char *p)
-{
- int len = 0;
- int n, i;
- struct ibm_thermal_sensors_struct t;
-
- n = thermal_get_sensors(&t);
- if (unlikely(n < 0))
- return n;
-
- len += sprintf(p + len, "temperatures:\t");
-
- if (n > 0) {
- for (i = 0; i < (n - 1); i++)
- len += sprintf(p + len, "%d ", t.temp[i] / 1000);
- len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
- } else
- len += sprintf(p + len, "not supported\n");
-
- return len;
-}
-
-static u8 ecdump_regs[256];
-
-static int ecdump_read(char *p)
-{
- int len = 0;
- int i, j;
- u8 v;
-
- len += sprintf(p + len, "EC "
- " +00 +01 +02 +03 +04 +05 +06 +07"
- " +08 +09 +0a +0b +0c +0d +0e +0f\n");
- for (i = 0; i < 256; i += 16) {
- len += sprintf(p + len, "EC 0x%02x:", i);
- for (j = 0; j < 16; j++) {
- if (!acpi_ec_read(i + j, &v))
- break;
- if (v != ecdump_regs[i + j])
- len += sprintf(p + len, " *%02x", v);
- else
- len += sprintf(p + len, " %02x", v);
- ecdump_regs[i + j] = v;
- }
- len += sprintf(p + len, "\n");
- if (j != 16)
- break;
- }
-
- /* These are way too dangerous to advertise openly... */
-#if 0
- len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
- " (<offset> is 00-ff, <value> is 00-ff)\n");
- len += sprintf(p + len, "commands:\t0x<offset> <value> "
- " (<offset> is 00-ff, <value> is 0-255)\n");
-#endif
- return len;
-}
-
-static int ecdump_write(char *buf)
-{
- char *cmd;
- int i, v;
-
- while ((cmd = next_cmd(&buf))) {
- if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
- /* i and v set */
- } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
- /* i and v set */
- } else
- return -EINVAL;
- if (i >= 0 && i < 256 && v >= 0 && v < 256) {
- if (!acpi_ec_write(i, v))
- return -EIO;
- } else
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int brightness_offset = 0x31;
-
-static int brightness_get(struct backlight_device *bd)
-{
- u8 level;
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
-
- level &= 0x7;
-
- return level;
-}
-
-static int brightness_read(char *p)
-{
- int len = 0;
- int level;
-
- if ((level = brightness_get(NULL)) < 0) {
- len += sprintf(p + len, "level:\t\tunreadable\n");
- } else {
- len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
- len += sprintf(p + len, "commands:\tup, down\n");
- len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-7)\n");
- }
-
- return len;
-}
-
-#define BRIGHTNESS_UP 4
-#define BRIGHTNESS_DOWN 5
-
-static int brightness_set(int value)
-{
- int cmos_cmd, inc, i;
- int current_value = brightness_get(NULL);
-
- value &= 7;
-
- cmos_cmd = value > current_value ? BRIGHTNESS_UP : BRIGHTNESS_DOWN;
- inc = value > current_value ? 1 : -1;
- for (i = current_value; i != value; i += inc) {
- if (!cmos_eval(cmos_cmd))
- return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
- }
-
- return 0;
-}
-
-static int brightness_write(char *buf)
-{
- int level;
- int new_level;
- char *cmd;
-
- while ((cmd = next_cmd(&buf))) {
- if ((level = brightness_get(NULL)) < 0)
- return level;
- level &= 7;
-
- if (strlencmp(cmd, "up") == 0) {
- new_level = level == 7 ? 7 : level + 1;
- } else if (strlencmp(cmd, "down") == 0) {
- new_level = level == 0 ? 0 : level - 1;
- } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
- new_level >= 0 && new_level <= 7) {
- /* new_level set */
- } else
- return -EINVAL;
-
- brightness_set(new_level);
- }
-
- return 0;
-}
-
-static int brightness_update_status(struct backlight_device *bd)
-{
- return brightness_set(
- (bd->props.fb_blank == FB_BLANK_UNBLANK &&
- bd->props.power == FB_BLANK_UNBLANK) ?
- bd->props.brightness : 0);
-}
-
-static struct backlight_ops ibm_backlight_data = {
- .get_brightness = brightness_get,
- .update_status = brightness_update_status,
-};
-
-static int brightness_init(void)
-{
- int b;
-
- b = brightness_get(NULL);
- if (b < 0)
- return b;
-
- ibm_backlight_device = backlight_device_register("ibm", NULL, NULL,
- &ibm_backlight_data);
- if (IS_ERR(ibm_backlight_device)) {
- printk(IBM_ERR "Could not register backlight device\n");
- return PTR_ERR(ibm_backlight_device);
- }
-
- ibm_backlight_device->props.max_brightness = 7;
- ibm_backlight_device->props.brightness = b;
- backlight_update_status(ibm_backlight_device);
-
- return 0;
-}
-
-static void brightness_exit(void)
-{
- if (ibm_backlight_device) {
- backlight_device_unregister(ibm_backlight_device);
- ibm_backlight_device = NULL;
- }
-}
-
-static int volume_offset = 0x30;
-
-static int volume_read(char *p)
-{
- int len = 0;
- u8 level;
-
- if (!acpi_ec_read(volume_offset, &level)) {
- len += sprintf(p + len, "level:\t\tunreadable\n");
- } else {
- len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
- len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
- len += sprintf(p + len, "commands:\tup, down, mute\n");
- len += sprintf(p + len, "commands:\tlevel <level>"
- " (<level> is 0-15)\n");
- }
-
- return len;
-}
-
-#define VOLUME_DOWN 0
-#define VOLUME_UP 1
-#define VOLUME_MUTE 2
-
-static int volume_write(char *buf)
-{
- int cmos_cmd, inc, i;
- u8 level, mute;
- int new_level, new_mute;
- char *cmd;
-
- while ((cmd = next_cmd(&buf))) {
- if (!acpi_ec_read(volume_offset, &level))
- return -EIO;
- new_mute = mute = level & 0x40;
- new_level = level = level & 0xf;
-
- if (strlencmp(cmd, "up") == 0) {
- if (mute)
- new_mute = 0;
- else
- new_level = level == 15 ? 15 : level + 1;
- } else if (strlencmp(cmd, "down") == 0) {
- if (mute)
- new_mute = 0;
- else
- new_level = level == 0 ? 0 : level - 1;
- } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
- new_level >= 0 && new_level <= 15) {
- /* new_level set */
- } else if (strlencmp(cmd, "mute") == 0) {
- new_mute = 0x40;
- } else
- return -EINVAL;
-
- if (new_level != level) { /* mute doesn't change */
- cmos_cmd = new_level > level ? VOLUME_UP : VOLUME_DOWN;
- inc = new_level > level ? 1 : -1;
-
- if (mute && (!cmos_eval(cmos_cmd) ||
- !acpi_ec_write(volume_offset, level)))
- return -EIO;
-
- for (i = level; i != new_level; i += inc)
- if (!cmos_eval(cmos_cmd) ||
- !acpi_ec_write(volume_offset, i + inc))
- return -EIO;
-
- if (mute && (!cmos_eval(VOLUME_MUTE) ||
- !acpi_ec_write(volume_offset,
- new_level + mute)))
- return -EIO;
- }
-
- if (new_mute != mute) { /* level doesn't change */
- cmos_cmd = new_mute ? VOLUME_MUTE : VOLUME_UP;
-
- if (!cmos_eval(cmos_cmd) ||
- !acpi_ec_write(volume_offset, level + new_mute))
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static enum fan_status_access_mode fan_status_access_mode;
-static enum fan_control_access_mode fan_control_access_mode;
-static enum fan_control_commands fan_control_commands;
-
-static int fan_control_status_known;
-static u8 fan_control_initial_status;
-
-static void fan_watchdog_fire(struct work_struct *ignored);
-static int fan_watchdog_maxinterval;
-static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
-
-static int fan_init(void)
-{
- fan_status_access_mode = IBMACPI_FAN_NONE;
- fan_control_access_mode = IBMACPI_FAN_WR_NONE;
- fan_control_commands = 0;
- fan_control_status_known = 1;
- fan_watchdog_maxinterval = 0;
-
- if (gfan_handle) {
- /* 570, 600e/x, 770e, 770x */
- fan_status_access_mode = IBMACPI_FAN_RD_ACPI_GFAN;
- } else {
- /* all other ThinkPads: note that even old-style
- * ThinkPad ECs supports the fan control register */
- if (likely(acpi_ec_read(fan_status_offset,
- &fan_control_initial_status))) {
- fan_status_access_mode = IBMACPI_FAN_RD_TPEC;
-
- /* In some ThinkPads, neither the EC nor the ACPI
- * DSDT initialize the fan status, and it ends up
- * being set to 0x07 when it *could* be either
- * 0x07 or 0x80.
- *
- * Enable for TP-1Y (T43), TP-78 (R51e),
- * TP-76 (R52), TP-70 (T43, R52), which are known
- * to be buggy. */
- if (fan_control_initial_status == 0x07 &&
- ibm_thinkpad_ec_found &&
- ((ibm_thinkpad_ec_found[0] == '1' &&
- ibm_thinkpad_ec_found[1] == 'Y') ||
- (ibm_thinkpad_ec_found[0] == '7' &&
- (ibm_thinkpad_ec_found[1] == '6' ||
- ibm_thinkpad_ec_found[1] == '8' ||
- ibm_thinkpad_ec_found[1] == '0'))
- )) {
- printk(IBM_NOTICE
- "fan_init: initial fan status is "
- "unknown, assuming it is in auto "
- "mode\n");
- fan_control_status_known = 0;
- }
- } else {
- printk(IBM_ERR
- "ThinkPad ACPI EC access misbehaving, "
- "fan status and control unavailable\n");
- return 0;
- }
- }
-
- if (sfan_handle) {
- /* 570, 770x-JL */
- fan_control_access_mode = IBMACPI_FAN_WR_ACPI_SFAN;
- fan_control_commands |=
- IBMACPI_FAN_CMD_LEVEL | IBMACPI_FAN_CMD_ENABLE;
- } else {
- if (!gfan_handle) {
- /* gfan without sfan means no fan control */
- /* all other models implement TP EC 0x2f control */
-
- if (fans_handle) {
- /* X31, X40, X41 */
- fan_control_access_mode =
- IBMACPI_FAN_WR_ACPI_FANS;
- fan_control_commands |=
- IBMACPI_FAN_CMD_SPEED |
- IBMACPI_FAN_CMD_LEVEL |
- IBMACPI_FAN_CMD_ENABLE;
- } else {
- fan_control_access_mode = IBMACPI_FAN_WR_TPEC;
- fan_control_commands |=
- IBMACPI_FAN_CMD_LEVEL |
- IBMACPI_FAN_CMD_ENABLE;
- }
- }
- }
-
- return 0;
-}
-
-static int fan_get_status(u8 *status)
-{
- u8 s;
-
- /* TODO:
- * Add IBMACPI_FAN_RD_ACPI_FANS ? */
-
- switch (fan_status_access_mode) {
- case IBMACPI_FAN_RD_ACPI_GFAN:
- /* 570, 600e/x, 770e, 770x */
-
- if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
- return -EIO;
-
- if (likely(status))
- *status = s & 0x07;
-
- break;
-
- case IBMACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
- return -EIO;
-
- if (likely(status))
- *status = s;
-
- break;
-
- default:
- return -ENXIO;
- }
-
- return 0;
-}
-
-static int fan_get_speed(unsigned int *speed)
-{
- u8 hi, lo;
-
- switch (fan_status_access_mode) {
- case IBMACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
- !acpi_ec_read(fan_rpm_offset + 1, &hi)))
- return -EIO;
-
- if (likely(speed))
- *speed = (hi << 8) | lo;
-
- break;
-
- default:
- return -ENXIO;
- }
-
- return 0;
-}
-
-static void fan_exit(void)
-{
- cancel_delayed_work(&fan_watchdog_task);
- flush_scheduled_work();
-}
-
-static void fan_watchdog_reset(void)
-{
- static int fan_watchdog_active = 0;
-
- if (fan_watchdog_active)
- cancel_delayed_work(&fan_watchdog_task);
-
- if (fan_watchdog_maxinterval > 0) {
- fan_watchdog_active = 1;
- if (!schedule_delayed_work(&fan_watchdog_task,
- msecs_to_jiffies(fan_watchdog_maxinterval
- * 1000))) {
- printk(IBM_ERR "failed to schedule the fan watchdog, "
- "watchdog will not trigger\n");
- }
- } else
- fan_watchdog_active = 0;
-}
-
-static int fan_read(char *p)
-{
- int len = 0;
- int rc;
- u8 status;
- unsigned int speed = 0;
-
- switch (fan_status_access_mode) {
- case IBMACPI_FAN_RD_ACPI_GFAN:
- /* 570, 600e/x, 770e, 770x */
- if ((rc = fan_get_status(&status)) < 0)
- return rc;
-
- len += sprintf(p + len, "status:\t\t%s\n"
- "level:\t\t%d\n",
- (status != 0) ? "enabled" : "disabled", status);
- break;
-
- case IBMACPI_FAN_RD_TPEC:
- /* all except 570, 600e/x, 770e, 770x */
- if ((rc = fan_get_status(&status)) < 0)
- return rc;
-
- if (unlikely(!fan_control_status_known)) {
- if (status != fan_control_initial_status)
- fan_control_status_known = 1;
- else
- /* Return most likely status. In fact, it
- * might be the only possible status */
- status = IBMACPI_FAN_EC_AUTO;
- }
-
- len += sprintf(p + len, "status:\t\t%s\n",
- (status != 0) ? "enabled" : "disabled");
-
- /* No ThinkPad boots on disengaged mode, we can safely
- * assume the tachometer is online if fan control status
- * was unknown */
- if ((rc = fan_get_speed(&speed)) < 0)
- return rc;
-
- len += sprintf(p + len, "speed:\t\t%d\n", speed);
-
- if (status & IBMACPI_FAN_EC_DISENGAGED)
- /* Disengaged mode takes precedence */
- len += sprintf(p + len, "level:\t\tdisengaged\n");
- else if (status & IBMACPI_FAN_EC_AUTO)
- len += sprintf(p + len, "level:\t\tauto\n");
- else
- len += sprintf(p + len, "level:\t\t%d\n", status);
- break;
-
- case IBMACPI_FAN_NONE:
- default:
- len += sprintf(p + len, "status:\t\tnot supported\n");
- }
-
- if (fan_control_commands & IBMACPI_FAN_CMD_LEVEL) {
- len += sprintf(p + len, "commands:\tlevel <level>");
-
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_SFAN:
- len += sprintf(p + len, " (<level> is 0-7)\n");
- break;
-
- default:
- len += sprintf(p + len, " (<level> is 0-7, "
- "auto, disengaged)\n");
- break;
- }
- }
-
- if (fan_control_commands & IBMACPI_FAN_CMD_ENABLE)
- len += sprintf(p + len, "commands:\tenable, disable\n"
- "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
- "1-120 (seconds))\n");
-
- if (fan_control_commands & IBMACPI_FAN_CMD_SPEED)
- len += sprintf(p + len, "commands:\tspeed <speed>"
- " (<speed> is 0-65535)\n");
-
- return len;
-}
-
-static int fan_set_level(int level)
-{
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_SFAN:
- if (level >= 0 && level <= 7) {
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
- return -EIO;
- } else
- return -EINVAL;
- break;
-
- case IBMACPI_FAN_WR_ACPI_FANS:
- case IBMACPI_FAN_WR_TPEC:
- if ((level != IBMACPI_FAN_EC_AUTO) &&
- (level != IBMACPI_FAN_EC_DISENGAGED) &&
- ((level < 0) || (level > 7)))
- return -EINVAL;
-
- if (!acpi_ec_write(fan_status_offset, level))
- return -EIO;
- else
- fan_control_status_known = 1;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_enable(void)
-{
- u8 s;
- int rc;
-
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_FANS:
- case IBMACPI_FAN_WR_TPEC:
- if ((rc = fan_get_status(&s)) < 0)
- return rc;
-
- /* Don't go out of emergency fan mode */
- if (s != 7)
- s = IBMACPI_FAN_EC_AUTO;
-
- if (!acpi_ec_write(fan_status_offset, s))
- return -EIO;
- else
- fan_control_status_known = 1;
- break;
-
- case IBMACPI_FAN_WR_ACPI_SFAN:
- if ((rc = fan_get_status(&s)) < 0)
- return rc;
-
- s &= 0x07;
-
- /* Set fan to at least level 4 */
- if (s < 4)
- s = 4;
-
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
- return -EIO;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_disable(void)
-{
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_FANS:
- case IBMACPI_FAN_WR_TPEC:
- if (!acpi_ec_write(fan_status_offset, 0x00))
- return -EIO;
- else
- fan_control_status_known = 1;
- break;
-
- case IBMACPI_FAN_WR_ACPI_SFAN:
- if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
- return -EIO;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_set_speed(int speed)
-{
- switch (fan_control_access_mode) {
- case IBMACPI_FAN_WR_ACPI_FANS:
- if (speed >= 0 && speed <= 65535) {
- if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
- speed, speed, speed))
- return -EIO;
- } else
- return -EINVAL;
- break;
-
- default:
- return -ENXIO;
- }
- return 0;
-}
-
-static int fan_write_cmd_level(const char *cmd, int *rc)
-{
- int level;
-
- if (strlencmp(cmd, "level auto") == 0)
- level = IBMACPI_FAN_EC_AUTO;
- else if (strlencmp(cmd, "level disengaged") == 0)
- level = IBMACPI_FAN_EC_DISENGAGED;
- else if (sscanf(cmd, "level %d", &level) != 1)
- return 0;
-
- if ((*rc = fan_set_level(level)) == -ENXIO)
- printk(IBM_ERR "level command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_enable(const char *cmd, int *rc)
-{
- if (strlencmp(cmd, "enable") != 0)
- return 0;
-
- if ((*rc = fan_set_enable()) == -ENXIO)
- printk(IBM_ERR "enable command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_disable(const char *cmd, int *rc)
-{
- if (strlencmp(cmd, "disable") != 0)
- return 0;
-
- if ((*rc = fan_set_disable()) == -ENXIO)
- printk(IBM_ERR "disable command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_speed(const char *cmd, int *rc)
-{
- int speed;
-
- /* TODO:
- * Support speed <low> <medium> <high> ? */
-
- if (sscanf(cmd, "speed %d", &speed) != 1)
- return 0;
-
- if ((*rc = fan_set_speed(speed)) == -ENXIO)
- printk(IBM_ERR "speed command accepted for unsupported "
- "access mode %d", fan_control_access_mode);
-
- return 1;
-}
-
-static int fan_write_cmd_watchdog(const char *cmd, int *rc)
-{
- int interval;
-
- if (sscanf(cmd, "watchdog %d", &interval) != 1)
- return 0;
-
- if (interval < 0 || interval > 120)
- *rc = -EINVAL;
- else
- fan_watchdog_maxinterval = interval;
-
- return 1;
-}
-
-static int fan_write(char *buf)
-{
- char *cmd;
- int rc = 0;
-
- while (!rc && (cmd = next_cmd(&buf))) {
- if (!((fan_control_commands & IBMACPI_FAN_CMD_LEVEL) &&
- fan_write_cmd_level(cmd, &rc)) &&
- !((fan_control_commands & IBMACPI_FAN_CMD_ENABLE) &&
- (fan_write_cmd_enable(cmd, &rc) ||
- fan_write_cmd_disable(cmd, &rc) ||
- fan_write_cmd_watchdog(cmd, &rc))) &&
- !((fan_control_commands & IBMACPI_FAN_CMD_SPEED) &&
- fan_write_cmd_speed(cmd, &rc))
- )
- rc = -EINVAL;
- else if (!rc)
- fan_watchdog_reset();
- }
-
- return rc;
-}
-
-static void fan_watchdog_fire(struct work_struct *ignored)
-{
- printk(IBM_NOTICE "fan watchdog: enabling fan\n");
- if (fan_set_enable()) {
- printk(IBM_ERR "fan watchdog: error while enabling fan\n");
- /* reschedule for later */
- fan_watchdog_reset();
- }
-}
-
-static struct ibm_struct ibms[] = {
- {
- .name = "driver",
- .init = ibm_acpi_driver_init,
- .read = driver_read,
- },
- {
- .name = "hotkey",
- .hid = IBM_HKEY_HID,
- .init = hotkey_init,
- .read = hotkey_read,
- .write = hotkey_write,
- .exit = hotkey_exit,
- .notify = hotkey_notify,
- .handle = &hkey_handle,
- .type = ACPI_DEVICE_NOTIFY,
- },
- {
- .name = "bluetooth",
- .init = bluetooth_init,
- .read = bluetooth_read,
- .write = bluetooth_write,
- },
- {
- .name = "wan",
- .init = wan_init,
- .read = wan_read,
- .write = wan_write,
- .experimental = 1,
- },
- {
- .name = "video",
- .init = video_init,
- .read = video_read,
- .write = video_write,
- .exit = video_exit,
- },
- {
- .name = "light",
- .init = light_init,
- .read = light_read,
- .write = light_write,
- },
-#ifdef CONFIG_ACPI_IBM_DOCK
- {
- .name = "dock",
- .read = dock_read,
- .write = dock_write,
- .notify = dock_notify,
- .handle = &dock_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
- {
- .name = "dock",
- .hid = IBM_PCI_HID,
- .notify = dock_notify,
- .handle = &pci_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
- {
- .name = "bay",
- .init = bay_init,
- .read = bay_read,
- .write = bay_write,
- .notify = bay_notify,
- .handle = &bay_handle,
- .type = ACPI_SYSTEM_NOTIFY,
- },
-#endif /* CONFIG_ACPI_IBM_BAY */
- {
- .name = "cmos",
- .read = cmos_read,
- .write = cmos_write,
- },
- {
- .name = "led",
- .init = led_init,
- .read = led_read,
- .write = led_write,
- },
- {
- .name = "beep",
- .read = beep_read,
- .write = beep_write,
- },
- {
- .name = "thermal",
- .init = thermal_init,
- .read = thermal_read,
- },
- {
- .name = "ecdump",
- .read = ecdump_read,
- .write = ecdump_write,
- .experimental = 1,
- },
- {
- .name = "brightness",
- .read = brightness_read,
- .write = brightness_write,
- .init = brightness_init,
- .exit = brightness_exit,
- },
- {
- .name = "volume",
- .read = volume_read,
- .write = volume_write,
- },
- {
- .name = "fan",
- .read = fan_read,
- .write = fan_write,
- .init = fan_init,
- .exit = fan_exit,
- .experimental = 1,
- },
-};
-
-static int dispatch_read(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- struct ibm_struct *ibm = data;
- int len;
-
- if (!ibm || !ibm->read)
- return -EINVAL;
-
- len = ibm->read(page);
- if (len < 0)
- return len;
-
- if (len <= off + count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
-
- return len;
-}
-
-static int dispatch_write(struct file *file, const char __user * userbuf,
- unsigned long count, void *data)
-{
- struct ibm_struct *ibm = data;
- char *kernbuf;
- int ret;
-
- if (!ibm || !ibm->write)
- return -EINVAL;
-
- kernbuf = kmalloc(count + 2, GFP_KERNEL);
- if (!kernbuf)
- return -ENOMEM;
-
- if (copy_from_user(kernbuf, userbuf, count)) {
- kfree(kernbuf);
- return -EFAULT;
- }
-
- kernbuf[count] = 0;
- strcat(kernbuf, ",");
- ret = ibm->write(kernbuf);
- if (ret == 0)
- ret = count;
-
- kfree(kernbuf);
-
- return ret;
-}
-
-static void dispatch_notify(acpi_handle handle, u32 event, void *data)
-{
- struct ibm_struct *ibm = data;
-
- if (!ibm || !ibm->notify)
- return;
-
- ibm->notify(ibm, event);
-}
-
-static int __init setup_notify(struct ibm_struct *ibm)
-{
- acpi_status status;
- int ret;
-
- if (!*ibm->handle)
- return 0;
-
- ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
- if (ret < 0) {
- printk(IBM_ERR "%s device not present\n", ibm->name);
- return -ENODEV;
- }
-
- acpi_driver_data(ibm->device) = ibm;
- sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
-
- status = acpi_install_notify_handler(*ibm->handle, ibm->type,
- dispatch_notify, ibm);
- if (ACPI_FAILURE(status)) {
- if (status == AE_ALREADY_EXISTS) {
- printk(IBM_NOTICE "another device driver is already handling %s events\n",
- ibm->name);
- } else {
- printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
- ibm->name, status);
- }
- return -ENODEV;
- }
- ibm->notify_installed = 1;
- return 0;
-}
-
-static int __init ibm_device_add(struct acpi_device *device)
-{
- return 0;
-}
-
-static int __init register_driver(struct ibm_struct *ibm)
-{
- int ret;
-
- ibm->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
- if (!ibm->driver) {
- printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
- return -1;
- }
-
- sprintf(ibm->driver->name, "%s_%s", IBM_NAME, ibm->name);
- ibm->driver->ids = ibm->hid;
- ibm->driver->ops.add = &ibm_device_add;
-
- ret = acpi_bus_register_driver(ibm->driver);
- if (ret < 0) {
- printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
- ibm->hid, ret);
- kfree(ibm->driver);
- }
-
- return ret;
-}
-
-static void ibm_exit(struct ibm_struct *ibm);
-
-static int __init ibm_init(struct ibm_struct *ibm)
-{
- int ret;
- struct proc_dir_entry *entry;
-
- if (ibm->experimental && !experimental)
- return 0;
-
- if (ibm->hid) {
- ret = register_driver(ibm);
- if (ret < 0)
- return ret;
- ibm->driver_registered = 1;
- }
-
- if (ibm->init) {
- ret = ibm->init();
- if (ret != 0)
- return ret;
- ibm->init_called = 1;
- }
-
- if (ibm->read) {
- entry = create_proc_entry(ibm->name,
- S_IFREG | S_IRUGO | S_IWUSR,
- proc_dir);
- if (!entry) {
- printk(IBM_ERR "unable to create proc entry %s\n",
- ibm->name);
- return -ENODEV;
- }
- entry->owner = THIS_MODULE;
- entry->data = ibm;
- entry->read_proc = &dispatch_read;
- if (ibm->write)
- entry->write_proc = &dispatch_write;
- ibm->proc_created = 1;
- }
-
- if (ibm->notify) {
- ret = setup_notify(ibm);
- if (ret == -ENODEV) {
- printk(IBM_NOTICE "disabling subdriver %s\n",
- ibm->name);
- ibm_exit(ibm);
- return 0;
- }
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static void ibm_exit(struct ibm_struct *ibm)
-{
- if (ibm->notify_installed)
- acpi_remove_notify_handler(*ibm->handle, ibm->type,
- dispatch_notify);
-
- if (ibm->proc_created)
- remove_proc_entry(ibm->name, proc_dir);
-
- if (ibm->init_called && ibm->exit)
- ibm->exit();
-
- if (ibm->driver_registered) {
- acpi_bus_unregister_driver(ibm->driver);
- kfree(ibm->driver);
- }
-}
-
-static void __init ibm_handle_init(char *name,
- acpi_handle * handle, acpi_handle parent,
- char **paths, int num_paths, char **path)
-{
- int i;
- acpi_status status;
-
- for (i = 0; i < num_paths; i++) {
- status = acpi_get_handle(parent, paths[i], handle);
- if (ACPI_SUCCESS(status)) {
- *path = paths[i];
- return;
- }
- }
-
- *handle = NULL;
-}
-
-#define IBM_HANDLE_INIT(object) \
- ibm_handle_init(#object, &object##_handle, *object##_parent, \
- object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
-
-static int __init set_ibm_param(const char *val, struct kernel_param *kp)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(ibms); i++)
- if (strcmp(ibms[i].name, kp->name) == 0 && ibms[i].write) {
- if (strlen(val) > sizeof(ibms[i].param) - 2)
- return -ENOSPC;
- strcpy(ibms[i].param, val);
- strcat(ibms[i].param, ",");
- return 0;
- }
-
- return -EINVAL;
-}
-
-#define IBM_PARAM(feature) \
- module_param_call(feature, set_ibm_param, NULL, NULL, 0)
-
-IBM_PARAM(hotkey);
-IBM_PARAM(bluetooth);
-IBM_PARAM(video);
-IBM_PARAM(light);
-#ifdef CONFIG_ACPI_IBM_DOCK
-IBM_PARAM(dock);
-#endif
-#ifdef CONFIG_ACPI_IBM_BAY
-IBM_PARAM(bay);
-#endif /* CONFIG_ACPI_IBM_BAY */
-IBM_PARAM(cmos);
-IBM_PARAM(led);
-IBM_PARAM(beep);
-IBM_PARAM(ecdump);
-IBM_PARAM(brightness);
-IBM_PARAM(volume);
-IBM_PARAM(fan);
-
-static void acpi_ibm_exit(void)
-{
- int i;
-
- for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--)
- ibm_exit(&ibms[i]);
-
- if (proc_dir)
- remove_proc_entry(IBM_DIR, acpi_root_dir);
-
- if (ibm_thinkpad_ec_found)
- kfree(ibm_thinkpad_ec_found);
-}
-
-static char* __init check_dmi_for_ec(void)
-{
- struct dmi_device *dev = NULL;
- char ec_fw_string[18];
-
- /*
- * ThinkPad T23 or newer, A31 or newer, R50e or newer,
- * X32 or newer, all Z series; Some models must have an
- * up-to-date BIOS or they will not be detected.
- *
- * See http://thinkwiki.org/wiki/List_of_DMI_IDs
- */
- while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
- if (sscanf(dev->name,
- "IBM ThinkPad Embedded Controller -[%17c",
- ec_fw_string) == 1) {
- ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
- ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
- return kstrdup(ec_fw_string, GFP_KERNEL);
- }
- }
- return NULL;
-}
-
-static int __init acpi_ibm_init(void)
-{
- int ret, i;
-
- if (acpi_disabled)
- return -ENODEV;
-
- /* ec is required because many other handles are relative to it */
- IBM_HANDLE_INIT(ec);
- if (!ec_handle) {
- printk(IBM_ERR "ec object not found\n");
- return -ENODEV;
- }
-
- /* Models with newer firmware report the EC in DMI */
- ibm_thinkpad_ec_found = check_dmi_for_ec();
-
- /* these handles are not required */
- IBM_HANDLE_INIT(vid);
- IBM_HANDLE_INIT(vid2);
- IBM_HANDLE_INIT(ledb);
- IBM_HANDLE_INIT(led);
- IBM_HANDLE_INIT(hkey);
- IBM_HANDLE_INIT(lght);
- IBM_HANDLE_INIT(cmos);
-#ifdef CONFIG_ACPI_IBM_DOCK
- IBM_HANDLE_INIT(dock);
-#endif
- IBM_HANDLE_INIT(pci);
-#ifdef CONFIG_ACPI_IBM_BAY
- IBM_HANDLE_INIT(bay);
- if (bay_handle)
- IBM_HANDLE_INIT(bay_ej);
- IBM_HANDLE_INIT(bay2);
- if (bay2_handle)
- IBM_HANDLE_INIT(bay2_ej);
-#endif /* CONFIG_ACPI_IBM_BAY */
- IBM_HANDLE_INIT(beep);
- IBM_HANDLE_INIT(ecrd);
- IBM_HANDLE_INIT(ecwr);
- IBM_HANDLE_INIT(fans);
- IBM_HANDLE_INIT(gfan);
- IBM_HANDLE_INIT(sfan);
-
- proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
- if (!proc_dir) {
- printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
- acpi_ibm_exit();
- return -ENODEV;
- }
- proc_dir->owner = THIS_MODULE;
-
- for (i = 0; i < ARRAY_SIZE(ibms); i++) {
- ret = ibm_init(&ibms[i]);
- if (ret >= 0 && *ibms[i].param)
- ret = ibms[i].write(ibms[i].param);
- if (ret < 0) {
- acpi_ibm_exit();
- return ret;
- }
- }
-
- return 0;
-}
-
-module_init(acpi_ibm_init);
-module_exit(acpi_ibm_exit);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 971eca4864f..c2bed56915e 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -30,7 +30,6 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kmod.h>
#include <linux/delay.h>
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 99d1516d1e7..f7de02a6f49 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -70,8 +70,6 @@
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
-#define ACPI_STA_PRESENT 0x00000001
-
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
@@ -779,7 +777,7 @@ static int is_processor_present(acpi_handle handle)
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
- if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) {
ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
return 0;
}
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index cdf78943af4..ee5759bef94 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -51,14 +51,6 @@
#include <asm/apic.h>
#endif
-/*
- * Include the apic definitions for x86 to have the APIC timer related defines
- * available also for UP (on SMP it gets magically included via linux/smp.h).
- */
-#ifdef CONFIG_X86
-#include <asm/apic.h>
-#endif
-
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -483,7 +475,7 @@ static void acpi_processor_idle(void)
#ifdef CONFIG_GENERIC_TIME
/* TSC halts in C2, so notify users */
- mark_tsc_unstable();
+ mark_tsc_unstable("possible TSC halt in C2");
#endif
/* Re-enable interrupts */
local_irq_enable();
@@ -525,7 +517,7 @@ static void acpi_processor_idle(void)
#ifdef CONFIG_GENERIC_TIME
/* TSC halts in C3, so notify users */
- mark_tsc_unstable();
+ mark_tsc_unstable("TSC halts in C3");
#endif
/* Re-enable interrupts */
local_irq_enable();
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 2f2e7964226..c4efc0c17f8 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -433,49 +433,6 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
PDE(inode)->data);
}
-static ssize_t
-acpi_processor_write_performance(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * data)
-{
- int result = 0;
- struct seq_file *m = file->private_data;
- struct acpi_processor *pr = m->private;
- struct acpi_processor_performance *perf;
- char state_string[12] = { '\0' };
- unsigned int new_state = 0;
- struct cpufreq_policy policy;
-
-
- if (!pr || (count > sizeof(state_string) - 1))
- return -EINVAL;
-
- perf = pr->performance;
- if (!perf)
- return -EINVAL;
-
- if (copy_from_user(state_string, buffer, count))
- return -EFAULT;
-
- state_string[count] = '\0';
- new_state = simple_strtoul(state_string, NULL, 0);
-
- if (new_state >= perf->state_count)
- return -EINVAL;
-
- cpufreq_get_policy(&policy, pr->id);
-
- policy.cpu = pr->id;
- policy.min = perf->states[new_state].core_frequency * 1000;
- policy.max = perf->states[new_state].core_frequency * 1000;
-
- result = cpufreq_set_policy(&policy);
- if (result)
- return result;
-
- return count;
-}
-
static void acpi_cpufreq_add_file(struct acpi_processor *pr)
{
struct proc_dir_entry *entry = NULL;
@@ -487,10 +444,9 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr)
/* add file 'performance' [R/W] */
entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
- S_IFREG | S_IRUGO | S_IWUSR,
+ S_IFREG | S_IRUGO,
acpi_device_dir(device));
if (entry){
- acpi_processor_perf_fops.write = acpi_processor_write_performance;
entry->proc_fops = &acpi_processor_perf_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 59640d9a0ac..c1bae106833 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -30,30 +30,10 @@
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/acpi.h>
-#include <linux/i2c.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
#include <linux/delay.h>
-#include "i2c_ec.h"
-
-#define DEF_CAPACITY_UNIT 3
-#define MAH_CAPACITY_UNIT 1
-#define MWH_CAPACITY_UNIT 2
-#define CAPACITY_UNIT DEF_CAPACITY_UNIT
-
-#define REQUEST_UPDATE_MODE 1
-#define QUEUE_UPDATE_MODE 2
-
-#define DATA_TYPE_COMMON 0
-#define DATA_TYPE_INFO 1
-#define DATA_TYPE_STATE 2
-#define DATA_TYPE_ALARM 3
-#define DATA_TYPE_AC_STATE 4
-
-extern struct proc_dir_entry *acpi_lock_ac_dir(void);
-extern struct proc_dir_entry *acpi_lock_battery_dir(void);
-extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
-extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
-
#define ACPI_SBS_COMPONENT 0x00080000
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
@@ -74,39 +54,75 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
#define _COMPONENT ACPI_SBS_COMPONENT
-#define MAX_SBS_BAT 4
-#define MAX_SMBUS_ERR 1
-
ACPI_MODULE_NAME("sbs");
MODULE_AUTHOR("Rich Townsend");
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
MODULE_LICENSE("GPL");
-static struct semaphore sbs_sem;
+#define xmsleep(t) msleep(t)
+
+#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
+
+#define ACPI_EC_SMB_STS 0x01 /* status */
+#define ACPI_EC_SMB_ADDR 0x02 /* address */
+#define ACPI_EC_SMB_CMD 0x03 /* command */
+#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
+#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
-#define UPDATE_MODE QUEUE_UPDATE_MODE
-/* REQUEST_UPDATE_MODE QUEUE_UPDATE_MODE */
-#define UPDATE_INFO_MODE 0
-#define UPDATE_TIME 60
-#define UPDATE_TIME2 0
+#define ACPI_EC_SMB_STS_DONE 0x80
+#define ACPI_EC_SMB_STS_STATUS 0x1f
-static int capacity_mode = CAPACITY_UNIT;
-static int update_mode = UPDATE_MODE;
-static int update_info_mode = UPDATE_INFO_MODE;
-static int update_time = UPDATE_TIME;
-static int update_time2 = UPDATE_TIME2;
+#define ACPI_EC_SMB_PRTCL_WRITE 0x00
+#define ACPI_EC_SMB_PRTCL_READ 0x01
+#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
-module_param(capacity_mode, int, 0);
-module_param(update_mode, int, 0);
-module_param(update_info_mode, int, 0);
-module_param(update_time, int, 0);
-module_param(update_time2, int, 0);
+#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
+#define ACPI_EC_SMB_ACCESS_SLEEP1 1
+#define ACPI_EC_SMB_ACCESS_SLEEP2 10
+
+#define DEF_CAPACITY_UNIT 3
+#define MAH_CAPACITY_UNIT 1
+#define MWH_CAPACITY_UNIT 2
+#define CAPACITY_UNIT DEF_CAPACITY_UNIT
+
+#define REQUEST_UPDATE_MODE 1
+#define QUEUE_UPDATE_MODE 2
+
+#define DATA_TYPE_COMMON 0
+#define DATA_TYPE_INFO 1
+#define DATA_TYPE_STATE 2
+#define DATA_TYPE_ALARM 3
+#define DATA_TYPE_AC_STATE 4
+
+extern struct proc_dir_entry *acpi_lock_ac_dir(void);
+extern struct proc_dir_entry *acpi_lock_battery_dir(void);
+extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
+
+#define MAX_SBS_BAT 4
+#define ACPI_SBS_BLOCK_MAX 32
+
+#define ACPI_SBS_SMBUS_READ 1
+#define ACPI_SBS_SMBUS_WRITE 2
+
+#define ACPI_SBS_WORD_DATA 1
+#define ACPI_SBS_BLOCK_DATA 2
+
+#define UPDATE_DELAY 10
+
+/* 0 - every time, > 0 - by update_time */
+static unsigned int update_time = 120;
+
+static unsigned int capacity_mode = CAPACITY_UNIT;
+
+module_param(update_time, uint, 0644);
+module_param(capacity_mode, uint, 0444);
static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
-static void acpi_sbs_update_queue(void *data);
+static int acpi_sbs_resume(struct acpi_device *device);
static struct acpi_driver acpi_sbs_driver = {
.name = "sbs",
@@ -115,9 +131,14 @@ static struct acpi_driver acpi_sbs_driver = {
.ops = {
.add = acpi_sbs_add,
.remove = acpi_sbs_remove,
+ .resume = acpi_sbs_resume,
},
};
+struct acpi_ac {
+ int ac_present;
+};
+
struct acpi_battery_info {
int capacity_mode;
s16 full_charge_capacity;
@@ -126,18 +147,16 @@ struct acpi_battery_info {
int vscale;
int ipscale;
s16 serial_number;
- char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
- char device_name[I2C_SMBUS_BLOCK_MAX + 3];
- char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
+ char manufacturer_name[ACPI_SBS_BLOCK_MAX + 3];
+ char device_name[ACPI_SBS_BLOCK_MAX + 3];
+ char device_chemistry[ACPI_SBS_BLOCK_MAX + 3];
};
struct acpi_battery_state {
s16 voltage;
s16 amperage;
s16 remaining_capacity;
- s16 average_time_to_empty;
- s16 average_time_to_full;
- s16 battery_status;
+ s16 battery_state;
};
struct acpi_battery_alarm {
@@ -146,9 +165,9 @@ struct acpi_battery_alarm {
struct acpi_battery {
int alive;
- int battery_present;
int id;
int init_state;
+ int battery_present;
struct acpi_sbs *sbs;
struct acpi_battery_info info;
struct acpi_battery_state state;
@@ -158,186 +177,251 @@ struct acpi_battery {
struct acpi_sbs {
acpi_handle handle;
+ int base;
struct acpi_device *device;
struct acpi_ec_smbus *smbus;
+ struct mutex mutex;
int sbsm_present;
int sbsm_batteries_supported;
- int ac_present;
struct proc_dir_entry *ac_entry;
+ struct acpi_ac ac;
struct acpi_battery battery[MAX_SBS_BAT];
- int update_info_mode;
int zombie;
- int update_time;
- int update_time2;
struct timer_list update_timer;
+ int run_cnt;
+ int update_proc_flg;
};
-static void acpi_update_delay(struct acpi_sbs *sbs);
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type);
+static void acpi_sbs_update_time(void *data);
+
+union sbs_rw_data {
+ u16 word;
+ u8 block[ACPI_SBS_BLOCK_MAX + 2];
+};
+
+static int acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+ char read_write, u8 command, int size,
+ union sbs_rw_data *data);
/* --------------------------------------------------------------------------
SMBus Communication
-------------------------------------------------------------------------- */
-static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
+static int acpi_ec_sbs_read(struct acpi_sbs *sbs, u8 address, u8 * data)
{
- union i2c_smbus_data data;
- int result = 0;
- char *err_str;
- int err_number;
+ u8 val;
+ int err;
- data.word = 0;
+ err = ec_read(sbs->base + address, &val);
+ if (!err) {
+ *data = val;
+ }
+ xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+ return (err);
+}
- result = smbus->adapter.algo->
- smbus_xfer(&smbus->adapter,
- ACPI_SB_SMBUS_ADDR,
- 0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);
+static int acpi_ec_sbs_write(struct acpi_sbs *sbs, u8 address, u8 data)
+{
+ int err;
- err_number = (data.word & 0x000f);
+ err = ec_write(sbs->base + address, data);
+ return (err);
+}
- switch (data.word & 0x000f) {
- case 0x0000:
- err_str = "unexpected bus error";
- break;
- case 0x0001:
- err_str = "busy";
- break;
- case 0x0002:
- err_str = "reserved command";
- break;
- case 0x0003:
- err_str = "unsupported command";
- break;
- case 0x0004:
- err_str = "access denied";
+static int
+acpi_ec_sbs_access(struct acpi_sbs *sbs, u16 addr,
+ char read_write, u8 command, int size,
+ union sbs_rw_data *data)
+{
+ unsigned char protocol, len = 0, temp[2] = { 0, 0 };
+ int i;
+
+ if (read_write == ACPI_SBS_SMBUS_READ) {
+ protocol = ACPI_EC_SMB_PRTCL_READ;
+ } else {
+ protocol = ACPI_EC_SMB_PRTCL_WRITE;
+ }
+
+ switch (size) {
+
+ case ACPI_SBS_WORD_DATA:
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+ if (read_write == ACPI_SBS_SMBUS_WRITE) {
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA, data->word);
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + 1,
+ data->word >> 8);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA;
break;
- case 0x0005:
- err_str = "overflow/underflow";
+ case ACPI_SBS_BLOCK_DATA:
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_CMD, command);
+ if (read_write == ACPI_SBS_SMBUS_WRITE) {
+ len = min_t(u8, data->block[0], 32);
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_BCNT, len);
+ for (i = 0; i < len; i++)
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_DATA + i,
+ data->block[i + 1]);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA;
break;
- case 0x0006:
- err_str = "bad size";
+ default:
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "unsupported transaction %d", size));
+ return (-1);
+ }
+
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_ADDR, addr << 1);
+ acpi_ec_sbs_write(sbs, ACPI_EC_SMB_PRTCL, protocol);
+
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+
+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+ xmsleep(ACPI_EC_SMB_ACCESS_SLEEP1);
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+ }
+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+ xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_STS, temp);
+ }
+ if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
+ || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "transaction %d error", size));
+ return (-1);
+ }
+
+ if (read_write == ACPI_SBS_SMBUS_WRITE) {
+ return (0);
+ }
+
+ switch (size) {
+
+ case ACPI_SBS_WORD_DATA:
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA, temp);
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + 1, temp + 1);
+ data->word = (temp[1] << 8) | temp[0];
break;
- case 0x0007:
- err_str = "unknown error";
+
+ case ACPI_SBS_BLOCK_DATA:
+ len = 0;
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_BCNT, &len);
+ len = min_t(u8, len, 32);
+ for (i = 0; i < len; i++)
+ acpi_ec_sbs_read(sbs, ACPI_EC_SMB_DATA + i,
+ data->block + i + 1);
+ data->block[0] = len;
break;
default:
- err_str = "unrecognized error";
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "unsupported transaction %d", size));
+ return (-1);
}
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "%s: ret %i, err %i\n", err_str, result, err_number));
+
+ return (0);
}
static int
-acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
- u16 * word,
- void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_word(struct acpi_sbs *sbs, int addr, int func, u16 * word)
{
- union i2c_smbus_data data;
+ union sbs_rw_data data;
int result = 0;
- int i;
- if (err_handler == NULL) {
- err_handler = acpi_battery_smbus_err_handler;
- }
-
- for (i = 0; i < MAX_SMBUS_ERR; i++) {
- result =
- smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
- I2C_SMBUS_READ, func,
- I2C_SMBUS_WORD_DATA, &data);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
- i));
- if (err_handler) {
- err_handler(smbus);
- }
- } else {
- *word = data.word;
- break;
- }
+ result = acpi_ec_sbs_access(sbs, addr,
+ ACPI_SBS_SMBUS_READ, func,
+ ACPI_SBS_WORD_DATA, &data);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ec_sbs_access() failed"));
+ } else {
+ *word = data.word;
}
return result;
}
static int
-acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
- char *str,
- void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_read_str(struct acpi_sbs *sbs, int addr, int func, char *str)
{
- union i2c_smbus_data data;
+ union sbs_rw_data data;
int result = 0;
- int i;
-
- if (err_handler == NULL) {
- err_handler = acpi_battery_smbus_err_handler;
- }
- for (i = 0; i < MAX_SMBUS_ERR; i++) {
- result =
- smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
- I2C_SMBUS_READ, func,
- I2C_SMBUS_BLOCK_DATA,
- &data);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
- i));
- if (err_handler) {
- err_handler(smbus);
- }
- } else {
- strncpy(str, (const char *)data.block + 1,
- data.block[0]);
- str[data.block[0]] = 0;
- break;
- }
+ result = acpi_ec_sbs_access(sbs, addr,
+ ACPI_SBS_SMBUS_READ, func,
+ ACPI_SBS_BLOCK_DATA, &data);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ec_sbs_access() failed"));
+ } else {
+ strncpy(str, (const char *)data.block + 1, data.block[0]);
+ str[data.block[0]] = 0;
}
return result;
}
static int
-acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
- int word,
- void (*err_handler) (struct acpi_ec_smbus * smbus))
+acpi_sbs_write_word(struct acpi_sbs *sbs, int addr, int func, int word)
{
- union i2c_smbus_data data;
+ union sbs_rw_data data;
int result = 0;
- int i;
-
- if (err_handler == NULL) {
- err_handler = acpi_battery_smbus_err_handler;
- }
data.word = word;
- for (i = 0; i < MAX_SMBUS_ERR; i++) {
- result =
- smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
- I2C_SMBUS_WRITE, func,
- I2C_SMBUS_WORD_DATA, &data);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "try %i: smbus->adapter.algo"
- "->smbus_xfer() failed\n", i));
- if (err_handler) {
- err_handler(smbus);
- }
- } else {
- break;
- }
+ result = acpi_ec_sbs_access(sbs, addr,
+ ACPI_SBS_SMBUS_WRITE, func,
+ ACPI_SBS_WORD_DATA, &data);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ec_sbs_access() failed"));
}
return result;
}
+static int sbs_zombie(struct acpi_sbs *sbs)
+{
+ return (sbs->zombie);
+}
+
+static int sbs_mutex_lock(struct acpi_sbs *sbs)
+{
+ if (sbs_zombie(sbs)) {
+ return -ENODEV;
+ }
+ mutex_lock(&sbs->mutex);
+ return 0;
+}
+
+static void sbs_mutex_unlock(struct acpi_sbs *sbs)
+{
+ mutex_unlock(&sbs->mutex);
+}
+
/* --------------------------------------------------------------------------
Smart Battery System Management
-------------------------------------------------------------------------- */
-/* Smart Battery */
+static int acpi_check_update_proc(struct acpi_sbs *sbs)
+{
+ acpi_status status = AE_OK;
+
+ if (update_time == 0) {
+ sbs->update_proc_flg = 0;
+ return 0;
+ }
+ if (sbs->update_proc_flg == 0) {
+ status = acpi_os_execute(OSL_GPE_HANDLER,
+ acpi_sbs_update_time, sbs);
+ if (status != AE_OK) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "acpi_os_execute() failed"));
+ return 1;
+ }
+ sbs->update_proc_flg = 1;
+ }
+ return 0;
+}
static int acpi_sbs_generate_event(struct acpi_device *device,
int event, int state, char *bid, char *class)
@@ -366,12 +450,11 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
int result = 0;
int is_present = 0;
- result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
- ACPI_SBSM_SMBUS_ADDR, 0x01,
- &state, NULL);
+ result = acpi_sbs_read_word(battery->sbs,
+ ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
}
if (!result) {
is_present = (state & 0x000f) & (1 << battery->id);
@@ -381,45 +464,33 @@ static int acpi_battery_get_present(struct acpi_battery *battery)
return result;
}
-static int acpi_battery_is_present(struct acpi_battery *battery)
-{
- return (battery->battery_present);
-}
-
-static int acpi_ac_is_present(struct acpi_sbs *sbs)
-{
- return (sbs->ac_present);
-}
-
static int acpi_battery_select(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 state;
int foo;
- if (battery->sbs->sbsm_present) {
+ if (sbs->sbsm_present) {
/* Take special care not to knobble other nibbles of
* state (aka selector_state), since
* it causes charging to halt on SBSELs */
result =
- acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
- &state, NULL);
+ acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, &state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
foo = (state & 0x0fff) | (1 << (battery->id + 12));
result =
- acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
- foo, NULL);
+ acpi_sbs_write_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x01, foo);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
}
@@ -430,15 +501,14 @@ static int acpi_battery_select(struct acpi_battery *battery)
static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
{
- struct acpi_ec_smbus *smbus = sbs->smbus;
int result = 0;
s16 battery_system_info;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
- &battery_system_info, NULL);
+ result = acpi_sbs_read_word(sbs, ACPI_SBSM_SMBUS_ADDR, 0x04,
+ &battery_system_info);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -451,53 +521,50 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
static int acpi_battery_get_info(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 battery_mode;
s16 specification_info;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
- &battery->info.full_charge_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x10,
+ &battery->info.full_charge_capacity);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
- &battery->info.design_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x18,
+ &battery->info.design_capacity);
if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
- &battery->info.design_voltage,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x19,
+ &battery->info.design_voltage);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
- &specification_info,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1a,
+ &specification_info);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -529,37 +596,35 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
battery->info.ipscale = 1;
}
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
- &battery->info.serial_number,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x1c,
+ &battery->info.serial_number);
if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
- battery->info.manufacturer_name,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x20,
+ battery->info.manufacturer_name);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_str() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_str() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
- battery->info.device_name,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x21,
+ battery->info.device_name);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_str() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_str() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
- battery->info.device_chemistry,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_str(sbs, ACPI_SB_SMBUS_ADDR, 0x22,
+ battery->info.device_chemistry);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_str() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_str() failed"));
goto end;
}
@@ -567,103 +632,60 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
return result;
}
-static void acpi_update_delay(struct acpi_sbs *sbs)
-{
- if (sbs->zombie) {
- return;
- }
- if (sbs->update_time2 > 0) {
- msleep(sbs->update_time2 * 1000);
- }
-}
-
static int acpi_battery_get_state(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
- &battery->state.voltage,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x09,
+ &battery->state.voltage);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
- &battery->state.amperage,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0a,
+ &battery->state.amperage);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
- &battery->state.remaining_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x0f,
+ &battery->state.remaining_capacity);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
- &battery->state.average_time_to_empty,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x16,
+ &battery->state.battery_state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
- &battery->state.average_time_to_full,
- &acpi_battery_smbus_err_handler);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
- goto end;
- }
-
- acpi_update_delay(battery->sbs);
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
- &battery->state.battery_status,
- &acpi_battery_smbus_err_handler);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
- goto end;
- }
-
- acpi_update_delay(battery->sbs);
-
end:
return result;
}
static int acpi_battery_get_alarm(struct acpi_battery *battery)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
- &battery->alarm.remaining_capacity,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+ &battery->alarm.remaining_capacity);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- acpi_update_delay(battery->sbs);
-
end:
return result;
@@ -672,15 +694,15 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery)
static int acpi_battery_set_alarm(struct acpi_battery *battery,
unsigned long alarm)
{
- struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 battery_mode;
int foo;
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_select() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
goto end;
}
@@ -688,33 +710,29 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
if (alarm > 0) {
result =
- acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode,
- &acpi_battery_smbus_err_handler);
+ acpi_sbs_read_word(sbs, ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
result =
- acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
- battery_mode & 0xbfff,
- &acpi_battery_smbus_err_handler);
+ acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01,
+ battery_mode & 0xbfff);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
}
foo = alarm / (battery->info.capacity_mode ? 10 : 1);
- result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
- foo,
- &acpi_battery_smbus_err_handler);
+ result = acpi_sbs_write_word(sbs, ACPI_SB_SMBUS_ADDR, 0x01, foo);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
@@ -725,6 +743,7 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery,
static int acpi_battery_set_mode(struct acpi_battery *battery)
{
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
s16 battery_mode;
@@ -732,12 +751,11 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
goto end;
}
- result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
- ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode, NULL);
+ result = acpi_sbs_read_word(sbs,
+ ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -746,21 +764,19 @@ static int acpi_battery_set_mode(struct acpi_battery *battery)
} else {
battery_mode |= 0x8000;
}
- result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
- ACPI_SB_SMBUS_ADDR, 0x03,
- battery_mode, NULL);
+ result = acpi_sbs_write_word(sbs,
+ ACPI_SB_SMBUS_ADDR, 0x03, battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_write_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_write_word() failed"));
goto end;
}
- result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
- ACPI_SB_SMBUS_ADDR, 0x03,
- &battery_mode, NULL);
+ result = acpi_sbs_read_word(sbs,
+ ACPI_SB_SMBUS_ADDR, 0x03, &battery_mode);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
@@ -774,36 +790,36 @@ static int acpi_battery_init(struct acpi_battery *battery)
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_init() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
goto end;
}
result = acpi_battery_set_mode(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_set_mode() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_set_mode() failed"));
goto end;
}
result = acpi_battery_get_info(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_info() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_info() failed"));
goto end;
}
result = acpi_battery_get_state(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_state() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_state() failed"));
goto end;
}
result = acpi_battery_get_alarm(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_alarm() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_alarm() failed"));
goto end;
}
@@ -813,20 +829,19 @@ static int acpi_battery_init(struct acpi_battery *battery)
static int acpi_ac_get_present(struct acpi_sbs *sbs)
{
- struct acpi_ec_smbus *smbus = sbs->smbus;
int result = 0;
s16 charger_status;
- result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
- &charger_status, NULL);
+ result = acpi_sbs_read_word(sbs, ACPI_SBC_SMBUS_ADDR, 0x13,
+ &charger_status);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_smbus_read_word() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_read_word() failed"));
goto end;
}
- sbs->ac_present = (charger_status & 0x8000) >> 15;
+ sbs->ac.ac_present = (charger_status & 0x8000) >> 15;
end:
@@ -852,8 +867,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "proc_mkdir() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "proc_mkdir() failed"));
return -ENODEV;
}
(*dir)->owner = THIS_MODULE;
@@ -863,8 +878,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (info_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "create_proc_entry() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "create_proc_entry() failed"));
} else {
entry->proc_fops = info_fops;
entry->data = data;
@@ -876,8 +891,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (state_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "create_proc_entry() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "create_proc_entry() failed"));
} else {
entry->proc_fops = state_fops;
entry->data = data;
@@ -889,8 +904,8 @@ acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
if (alarm_fops) {
entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
if (!entry) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "create_proc_entry() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "create_proc_entry() failed"));
} else {
entry->proc_fops = alarm_fops;
entry->data = data;
@@ -923,24 +938,27 @@ static struct proc_dir_entry *acpi_battery_dir = NULL;
static int acpi_battery_read_info(struct seq_file *seq, void *offset)
{
struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
int cscale;
int result = 0;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_INFO);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
- if (acpi_battery_is_present(battery)) {
+ if (battery->battery_present) {
seq_printf(seq, "present: yes\n");
} else {
seq_printf(seq, "present: no\n");
@@ -952,13 +970,13 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
} else {
cscale = battery->info.ipscale;
}
- seq_printf(seq, "design capacity: %i%s",
+ seq_printf(seq, "design capacity: %i%s\n",
battery->info.design_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
- seq_printf(seq, "last full capacity: %i%s",
+ seq_printf(seq, "last full capacity: %i%s\n",
battery->info.full_charge_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
seq_printf(seq, "battery technology: rechargeable\n");
@@ -984,7 +1002,7 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return result;
}
@@ -996,26 +1014,29 @@ static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_state(struct seq_file *seq, void *offset)
{
- struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
int cscale;
int foo;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_STATE);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
- if (acpi_battery_is_present(battery)) {
+ if (battery->battery_present) {
seq_printf(seq, "present: yes\n");
} else {
seq_printf(seq, "present: no\n");
@@ -1028,7 +1049,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
cscale = battery->info.ipscale;
}
- if (battery->state.battery_status & 0x0010) {
+ if (battery->state.battery_state & 0x0010) {
seq_printf(seq, "capacity state: critical\n");
} else {
seq_printf(seq, "capacity state: ok\n");
@@ -1052,16 +1073,16 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
battery->info.capacity_mode ? "mW" : "mA");
}
- seq_printf(seq, "remaining capacity: %i%s",
+ seq_printf(seq, "remaining capacity: %i%s\n",
battery->state.remaining_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
seq_printf(seq, "present voltage: %i mV\n",
battery->state.voltage * battery->info.vscale);
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return result;
}
@@ -1074,24 +1095,27 @@ static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
{
struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
int result = 0;
int cscale;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, battery->id, DATA_TYPE_ALARM);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
- if (!acpi_battery_is_present(battery)) {
+ if (!battery->battery_present) {
seq_printf(seq, "present: no\n");
goto end;
}
@@ -1104,16 +1128,16 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
seq_printf(seq, "alarm: ");
if (battery->alarm.remaining_capacity) {
- seq_printf(seq, "%i%s",
+ seq_printf(seq, "%i%s\n",
battery->alarm.remaining_capacity * cscale,
- battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ battery->info.capacity_mode ? "0 mWh" : " mAh");
} else {
seq_printf(seq, "disabled\n");
}
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return result;
}
@@ -1124,16 +1148,19 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
{
struct seq_file *seq = file->private_data;
struct acpi_battery *battery = seq->private;
+ struct acpi_sbs *sbs = battery->sbs;
char alarm_string[12] = { '\0' };
int result, old_alarm, new_alarm;
- if (battery->sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
- if (!acpi_battery_is_present(battery)) {
+ if (!battery->battery_present) {
result = -ENODEV;
goto end;
}
@@ -1155,21 +1182,21 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer,
result = acpi_battery_set_alarm(battery, new_alarm);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_set_alarm() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_set_alarm() failed"));
acpi_battery_set_alarm(battery, old_alarm);
goto end;
}
result = acpi_battery_get_alarm(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_alarm() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_alarm() failed"));
acpi_battery_set_alarm(battery, old_alarm);
goto end;
}
end:
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
if (result) {
return result;
@@ -1217,24 +1244,22 @@ static int acpi_ac_read_state(struct seq_file *seq, void *offset)
struct acpi_sbs *sbs = seq->private;
int result;
- if (sbs->zombie) {
+ if (sbs_mutex_lock(sbs)) {
return -ENODEV;
}
- down(&sbs_sem);
-
- if (update_mode == REQUEST_UPDATE_MODE) {
- result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);
+ if (update_time == 0) {
+ result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_AC_STATE);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
}
seq_printf(seq, "state: %s\n",
- sbs->ac_present ? "on-line" : "off-line");
+ sbs->ac.ac_present ? "on-line" : "off-line");
- up(&sbs_sem);
+ sbs_mutex_unlock(sbs);
return 0;
}
@@ -1275,25 +1300,25 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_select() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
goto end;
}
result = acpi_battery_get_present(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_present() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_present() failed"));
goto end;
}
- is_present = acpi_battery_is_present(battery);
+ is_present = battery->battery_present;
if (is_present) {
result = acpi_battery_init(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_init() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_init() failed"));
goto end;
}
battery->init_state = 1;
@@ -1308,12 +1333,16 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
&acpi_battery_state_fops,
&acpi_battery_alarm_fops, battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generic_add_fs() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generic_add_fs() failed"));
goto end;
}
battery->alive = 1;
+ printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n",
+ ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), dir_name,
+ sbs->battery->battery_present ? "present" : "absent");
+
end:
return result;
}
@@ -1333,8 +1362,8 @@ static int acpi_ac_add(struct acpi_sbs *sbs)
result = acpi_ac_get_present(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_ac_get_present() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ac_get_present() failed"));
goto end;
}
@@ -1343,11 +1372,15 @@ static int acpi_ac_add(struct acpi_sbs *sbs)
ACPI_AC_DIR_NAME,
NULL, &acpi_ac_state_fops, NULL, sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generic_add_fs() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generic_add_fs() failed"));
goto end;
}
+ printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n",
+ ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
+ ACPI_AC_DIR_NAME, sbs->ac.ac_present ? "on-line" : "off-line");
+
end:
return result;
@@ -1361,45 +1394,85 @@ static void acpi_ac_remove(struct acpi_sbs *sbs)
}
}
-static void acpi_sbs_update_queue_run(unsigned long data)
+static void acpi_sbs_update_time_run(unsigned long data)
{
- acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);
+ acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_time, (void *)data);
}
-static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int id, int data_type)
{
struct acpi_battery *battery;
- int result = 0;
- int old_ac_present;
- int old_battery_present;
- int new_ac_present;
- int new_battery_present;
- int id;
+ int result = 0, cnt;
+ int old_ac_present = -1;
+ int old_battery_present = -1;
+ int new_ac_present = -1;
+ int new_battery_present = -1;
+ int id_min = 0, id_max = MAX_SBS_BAT - 1;
char dir_name[32];
- int do_battery_init, do_ac_init;
- s16 old_remaining_capacity;
+ int do_battery_init = 0, do_ac_init = 0;
+ int old_remaining_capacity = 0;
+ int update_ac = 1, update_battery = 1;
+ int up_tm = update_time;
- if (sbs->zombie) {
+ if (sbs_zombie(sbs)) {
goto end;
}
- old_ac_present = acpi_ac_is_present(sbs);
+ if (id >= 0) {
+ id_min = id_max = id;
+ }
+
+ if (data_type == DATA_TYPE_COMMON && up_tm > 0) {
+ cnt = up_tm / (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+ if (sbs->run_cnt % cnt != 0) {
+ update_battery = 0;
+ }
+ }
+
+ sbs->run_cnt++;
+
+ if (!update_ac && !update_battery) {
+ goto end;
+ }
+
+ old_ac_present = sbs->ac.ac_present;
result = acpi_ac_get_present(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_ac_get_present() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_ac_get_present() failed"));
}
- new_ac_present = acpi_ac_is_present(sbs);
+ new_ac_present = sbs->ac.ac_present;
do_ac_init = (old_ac_present != new_ac_present);
+ if (sbs->run_cnt == 1 && data_type == DATA_TYPE_COMMON) {
+ do_ac_init = 1;
+ }
- if (data_type == DATA_TYPE_AC_STATE) {
+ if (do_ac_init) {
+ result = acpi_sbs_generate_event(sbs->device,
+ ACPI_SBS_AC_NOTIFY_STATUS,
+ new_ac_present,
+ ACPI_AC_DIR_NAME,
+ ACPI_AC_CLASS);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generate_event() failed"));
+ }
+ }
+
+ if (data_type == DATA_TYPE_COMMON) {
+ if (!do_ac_init && !update_battery) {
+ goto end;
+ }
+ }
+
+ if (data_type == DATA_TYPE_AC_STATE && !do_ac_init) {
goto end;
}
- for (id = 0; id < MAX_SBS_BAT; id++) {
+ for (id = id_min; id <= id_max; id++) {
battery = &sbs->battery[id];
if (battery->alive == 0) {
continue;
@@ -1407,94 +1480,92 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
old_remaining_capacity = battery->state.remaining_capacity;
- old_battery_present = acpi_battery_is_present(battery);
+ old_battery_present = battery->battery_present;
result = acpi_battery_select(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_select() failed\n"));
- }
- if (sbs->zombie) {
- goto end;
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_select() failed"));
}
result = acpi_battery_get_present(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_present() failed\n"));
- }
- if (sbs->zombie) {
- goto end;
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_present() failed"));
}
- new_battery_present = acpi_battery_is_present(battery);
+ new_battery_present = battery->battery_present;
do_battery_init = ((old_battery_present != new_battery_present)
&& new_battery_present);
-
- if (sbs->zombie) {
+ if (!new_battery_present)
+ goto event;
+ if (do_ac_init || do_battery_init) {
+ result = acpi_battery_init(battery);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_init() "
+ "failed"));
+ }
+ }
+ if (sbs_zombie(sbs)) {
goto end;
}
- if (do_ac_init || do_battery_init ||
- update_info_mode || sbs->update_info_mode) {
- if (sbs->update_info_mode) {
- sbs->update_info_mode = 0;
- } else {
- sbs->update_info_mode = 1;
- }
- result = acpi_battery_init(battery);
+
+ if ((data_type == DATA_TYPE_COMMON
+ || data_type == DATA_TYPE_INFO)
+ && new_battery_present) {
+ result = acpi_battery_get_info(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_init() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_info() failed"));
}
}
if (data_type == DATA_TYPE_INFO) {
continue;
}
-
- if (sbs->zombie) {
+ if (sbs_zombie(sbs)) {
goto end;
}
- if (new_battery_present) {
- result = acpi_battery_get_alarm(battery);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_alarm() "
- "failed\n"));
- }
- if (data_type == DATA_TYPE_ALARM) {
- continue;
- }
+ if ((data_type == DATA_TYPE_COMMON
+ || data_type == DATA_TYPE_STATE)
+ && new_battery_present) {
result = acpi_battery_get_state(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_get_state() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_state() failed"));
}
}
- if (sbs->zombie) {
- goto end;
+ if (data_type == DATA_TYPE_STATE) {
+ goto event;
}
- if (data_type != DATA_TYPE_COMMON) {
- continue;
+ if (sbs_zombie(sbs)) {
+ goto end;
}
- if (old_battery_present != new_battery_present) {
- sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
- result = acpi_sbs_generate_event(sbs->device,
- ACPI_SBS_BATTERY_NOTIFY_STATUS,
- new_battery_present,
- dir_name,
- ACPI_BATTERY_CLASS);
+ if ((data_type == DATA_TYPE_COMMON
+ || data_type == DATA_TYPE_ALARM)
+ && new_battery_present) {
+ result = acpi_battery_get_alarm(battery);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generate_event() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_get_alarm() "
+ "failed"));
}
}
- if (old_remaining_capacity != battery->state.remaining_capacity) {
+ if (data_type == DATA_TYPE_ALARM) {
+ continue;
+ }
+ if (sbs_zombie(sbs)) {
+ goto end;
+ }
+
+ event:
+
+ if (old_battery_present != new_battery_present || do_ac_init ||
+ old_remaining_capacity !=
+ battery->state.remaining_capacity) {
sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
result = acpi_sbs_generate_event(sbs->device,
ACPI_SBS_BATTERY_NOTIFY_STATUS,
@@ -1502,138 +1573,120 @@ static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
dir_name,
ACPI_BATTERY_CLASS);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generate_event() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_generate_event() "
+ "failed"));
}
}
-
- }
- if (sbs->zombie) {
- goto end;
- }
- if (data_type != DATA_TYPE_COMMON) {
- goto end;
- }
-
- if (old_ac_present != new_ac_present) {
- result = acpi_sbs_generate_event(sbs->device,
- ACPI_SBS_AC_NOTIFY_STATUS,
- new_ac_present,
- ACPI_AC_DIR_NAME,
- ACPI_AC_CLASS);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_generate_event() failed\n"));
- }
}
end:
+
return result;
}
-static void acpi_sbs_update_queue(void *data)
+static void acpi_sbs_update_time(void *data)
{
struct acpi_sbs *sbs = data;
unsigned long delay = -1;
int result;
+ unsigned int up_tm = update_time;
- if (sbs->zombie) {
- goto end;
- }
+ if (sbs_mutex_lock(sbs))
+ return;
- result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);
+ result = acpi_sbs_update_run(sbs, -1, DATA_TYPE_COMMON);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_update_run() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_update_run() failed"));
}
- if (sbs->zombie) {
+ if (sbs_zombie(sbs)) {
goto end;
}
- if (update_mode == REQUEST_UPDATE_MODE) {
- goto end;
+ if (!up_tm) {
+ if (timer_pending(&sbs->update_timer))
+ del_timer(&sbs->update_timer);
+ } else {
+ delay = (up_tm > UPDATE_DELAY ? UPDATE_DELAY : up_tm);
+ delay = jiffies + HZ * delay;
+ if (timer_pending(&sbs->update_timer)) {
+ mod_timer(&sbs->update_timer, delay);
+ } else {
+ sbs->update_timer.data = (unsigned long)data;
+ sbs->update_timer.function = acpi_sbs_update_time_run;
+ sbs->update_timer.expires = delay;
+ add_timer(&sbs->update_timer);
+ }
}
- delay = jiffies + HZ * update_time;
- sbs->update_timer.data = (unsigned long)data;
- sbs->update_timer.function = acpi_sbs_update_queue_run;
- sbs->update_timer.expires = delay;
- add_timer(&sbs->update_timer);
end:
- ;
+
+ sbs_mutex_unlock(sbs);
}
static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs = NULL;
- struct acpi_ec_hc *ec_hc = NULL;
- int result, remove_result = 0;
+ int result = 0, remove_result = 0;
unsigned long sbs_obj;
- int id, cnt;
+ int id;
acpi_status status = AE_OK;
+ unsigned long val;
+
+ status =
+ acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
+ return -EIO;
+ }
sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
if (!sbs) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
- return -ENOMEM;
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "kzalloc() failed"));
+ result = -ENOMEM;
+ goto end;
}
- cnt = 0;
- while (cnt < 10) {
- cnt++;
- ec_hc = acpi_get_ec_hc(device);
- if (ec_hc) {
- break;
- }
- msleep(1000);
- }
+ mutex_init(&sbs->mutex);
- if (!ec_hc) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_get_ec_hc() failed: "
- "NO driver found for EC HC SMBus\n"));
- result = -ENODEV;
- goto end;
- }
+ sbs_mutex_lock(sbs);
+ sbs->base = (val & 0xff00ull) >> 8;
sbs->device = device;
- sbs->smbus = ec_hc->smbus;
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
acpi_driver_data(device) = sbs;
- sbs->update_time = 0;
- sbs->update_time2 = 0;
-
result = acpi_ac_add(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
goto end;
}
- result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
- if (ACPI_FAILURE(result)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_evaluate_integer() failed\n"));
+ status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
+ if (status) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "acpi_evaluate_integer() failed"));
result = -EIO;
goto end;
}
-
if (sbs_obj > 0) {
result = acpi_sbsm_get_info(sbs);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbsm_get_info() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbsm_get_info() failed"));
goto end;
}
sbs->sbsm_present = 1;
}
+
if (sbs->sbsm_present == 0) {
result = acpi_battery_add(sbs, 0);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_add() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_add() failed"));
goto end;
}
} else {
@@ -1641,9 +1694,8 @@ static int acpi_sbs_add(struct acpi_device *device)
if ((sbs->sbsm_batteries_supported & (1 << id))) {
result = acpi_battery_add(sbs, id);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_battery_add() "
- "failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_battery_add() failed"));
goto end;
}
}
@@ -1653,33 +1705,26 @@ static int acpi_sbs_add(struct acpi_device *device)
sbs->handle = device->handle;
init_timer(&sbs->update_timer);
- if (update_mode == QUEUE_UPDATE_MODE) {
- status = acpi_os_execute(OSL_GPE_HANDLER,
- acpi_sbs_update_queue, sbs);
- if (status != AE_OK) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_os_execute() failed\n"));
- }
- }
- sbs->update_time = update_time;
- sbs->update_time2 = update_time2;
-
- printk(KERN_INFO PREFIX "%s [%s]\n",
- acpi_device_name(device), acpi_device_bid(device));
+ result = acpi_check_update_proc(sbs);
+ if (result)
+ goto end;
end:
+
+ sbs_mutex_unlock(sbs);
+
if (result) {
remove_result = acpi_sbs_remove(device, 0);
if (remove_result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_sbs_remove() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_sbs_remove() failed"));
}
}
return result;
}
-int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device, int type)
{
struct acpi_sbs *sbs;
int id;
@@ -1688,15 +1733,14 @@ int acpi_sbs_remove(struct acpi_device *device, int type)
return -EINVAL;
}
- sbs = (struct acpi_sbs *)acpi_driver_data(device);
-
+ sbs = acpi_driver_data(device);
if (!sbs) {
return -EINVAL;
}
+ sbs_mutex_lock(sbs);
+
sbs->zombie = 1;
- sbs->update_time = 0;
- sbs->update_time2 = 0;
del_timer_sync(&sbs->update_timer);
acpi_os_wait_events_complete(NULL);
del_timer_sync(&sbs->update_timer);
@@ -1707,11 +1751,41 @@ int acpi_sbs_remove(struct acpi_device *device, int type)
acpi_ac_remove(sbs);
+ sbs_mutex_unlock(sbs);
+
+ mutex_destroy(&sbs->mutex);
+
kfree(sbs);
return 0;
}
+static void acpi_sbs_rmdirs(void)
+{
+ if (acpi_ac_dir) {
+ acpi_unlock_ac_dir(acpi_ac_dir);
+ acpi_ac_dir = NULL;
+ }
+ if (acpi_battery_dir) {
+ acpi_unlock_battery_dir(acpi_battery_dir);
+ acpi_battery_dir = NULL;
+ }
+}
+
+static int acpi_sbs_resume(struct acpi_device *device)
+{
+ struct acpi_sbs *sbs;
+
+ if (!device)
+ return -EINVAL;
+
+ sbs = device->driver_data;
+
+ sbs->run_cnt = 0;
+
+ return 0;
+}
+
static int __init acpi_sbs_init(void)
{
int result = 0;
@@ -1719,35 +1793,34 @@ static int __init acpi_sbs_init(void)
if (acpi_disabled)
return -ENODEV;
- init_MUTEX(&sbs_sem);
-
if (capacity_mode != DEF_CAPACITY_UNIT
&& capacity_mode != MAH_CAPACITY_UNIT
&& capacity_mode != MWH_CAPACITY_UNIT) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "
- "invalid capacity_mode = %d\n",
- capacity_mode));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "invalid capacity_mode = %d", capacity_mode));
return -EINVAL;
}
acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_lock_ac_dir() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_lock_ac_dir() failed"));
return -ENODEV;
}
acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_lock_battery_dir() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_lock_battery_dir() failed"));
+ acpi_sbs_rmdirs();
return -ENODEV;
}
result = acpi_bus_register_driver(&acpi_sbs_driver);
if (result < 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "acpi_bus_register_driver() failed\n"));
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR,
+ "acpi_bus_register_driver() failed"));
+ acpi_sbs_rmdirs();
return -ENODEV;
}
@@ -1756,13 +1829,9 @@ static int __init acpi_sbs_init(void)
static void __exit acpi_sbs_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_sbs_driver);
- acpi_unlock_ac_dir(acpi_ac_dir);
- acpi_ac_dir = NULL;
- acpi_unlock_battery_dir(acpi_battery_dir);
- acpi_battery_dir = NULL;
+ acpi_sbs_rmdirs();
return;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index bb0e0da39fb..6b3b8a52247 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -302,7 +302,7 @@ static void acpi_device_shutdown(struct device *dev)
return ;
}
-static struct bus_type acpi_bus_type = {
+struct bus_type acpi_bus_type = {
.name = "acpi",
.suspend = acpi_device_suspend,
.resume = acpi_device_resume,
@@ -1068,7 +1068,9 @@ acpi_add_single_object(struct acpi_device **child,
}
break;
default:
- STRUCT_TO_INT(device->status) = 0x0F;
+ STRUCT_TO_INT(device->status) =
+ ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED |
+ ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING;
break;
}
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 37a0930fc0a..52b23471dd6 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -29,7 +29,6 @@ static u32 acpi_suspend_states[] = {
[PM_SUSPEND_ON] = ACPI_STATE_S0,
[PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
[PM_SUSPEND_MEM] = ACPI_STATE_S3,
- [PM_SUSPEND_DISK] = ACPI_STATE_S4,
[PM_SUSPEND_MAX] = ACPI_STATE_S5
};
@@ -94,14 +93,6 @@ static int acpi_pm_enter(suspend_state_t pm_state)
do_suspend_lowlevel();
break;
- case PM_SUSPEND_DISK:
- if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
- status = acpi_enter_sleep_state(acpi_state);
- break;
- case PM_SUSPEND_MAX:
- acpi_power_off();
- break;
-
default:
return -EINVAL;
}
@@ -157,20 +148,30 @@ int acpi_suspend(u32 acpi_state)
suspend_state_t states[] = {
[1] = PM_SUSPEND_STANDBY,
[3] = PM_SUSPEND_MEM,
- [4] = PM_SUSPEND_DISK,
[5] = PM_SUSPEND_MAX
};
if (acpi_state < 6 && states[acpi_state])
return pm_suspend(states[acpi_state]);
+ if (acpi_state == 4)
+ return hibernate();
return -EINVAL;
}
static int acpi_pm_state_valid(suspend_state_t pm_state)
{
- u32 acpi_state = acpi_suspend_states[pm_state];
+ u32 acpi_state;
- return sleep_states[acpi_state];
+ switch (pm_state) {
+ case PM_SUSPEND_ON:
+ case PM_SUSPEND_STANDBY:
+ case PM_SUSPEND_MEM:
+ acpi_state = acpi_suspend_states[pm_state];
+
+ return sleep_states[acpi_state];
+ default:
+ return 0;
+ }
}
static struct pm_ops acpi_pm_ops = {
@@ -180,6 +181,49 @@ static struct pm_ops acpi_pm_ops = {
.finish = acpi_pm_finish,
};
+#ifdef CONFIG_SOFTWARE_SUSPEND
+static int acpi_hibernation_prepare(void)
+{
+ return acpi_sleep_prepare(ACPI_STATE_S4);
+}
+
+static int acpi_hibernation_enter(void)
+{
+ acpi_status status = AE_OK;
+ unsigned long flags = 0;
+
+ ACPI_FLUSH_CPU_CACHE();
+
+ local_irq_save(flags);
+ acpi_enable_wakeup_device(ACPI_STATE_S4);
+ /* This shouldn't return. If it returns, we have a problem */
+ status = acpi_enter_sleep_state(ACPI_STATE_S4);
+ local_irq_restore(flags);
+
+ return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_finish(void)
+{
+ acpi_leave_sleep_state(ACPI_STATE_S4);
+ acpi_disable_wakeup_device(ACPI_STATE_S4);
+
+ /* reset firmware waking vector */
+ acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+ if (init_8259A_after_S1) {
+ printk("Broken toshiba laptop -> kicking interrupts\n");
+ init_8259A(0);
+ }
+}
+
+static struct hibernation_ops acpi_hibernation_ops = {
+ .prepare = acpi_hibernation_prepare,
+ .enter = acpi_hibernation_enter,
+ .finish = acpi_hibernation_finish,
+};
+#endif /* CONFIG_SOFTWARE_SUSPEND */
+
/*
* Toshiba fails to preserve interrupts over S1, reinitialization
* of 8259 is needed after S1 resume.
@@ -218,14 +262,18 @@ int __init acpi_sleep_init(void)
sleep_states[i] = 1;
printk(" S%d", i);
}
- if (i == ACPI_STATE_S4) {
- if (sleep_states[i])
- acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
- }
}
printk(")\n");
pm_set_ops(&acpi_pm_ops);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+ if (sleep_states[ACPI_STATE_S4])
+ hibernation_set_ops(&acpi_hibernation_ops);
+#else
+ sleep_states[ACPI_STATE_S4] = 0;
+#endif
+
return 0;
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index ccc11b33d89..76b45f0b834 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -60,7 +60,7 @@ acpi_system_write_sleep(struct file *file,
state = simple_strtoul(str, NULL, 0);
#ifdef CONFIG_SOFTWARE_SUSPEND
if (state == 4) {
- error = software_suspend();
+ error = hibernate();
goto Done;
}
#endif
@@ -70,6 +70,14 @@ acpi_system_write_sleep(struct file *file,
}
#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+/* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
+#else
+#define HAVE_ACPI_LEGACY_ALARM
+#endif
+
+#ifdef HAVE_ACPI_LEGACY_ALARM
+
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
{
u32 sec, min, hr;
@@ -341,6 +349,8 @@ acpi_system_write_alarm(struct file *file,
end:
return_VALUE(result ? result : count);
}
+#endif /* HAVE_ACPI_LEGACY_ALARM */
+
extern struct list_head acpi_wakeup_device_list;
extern spinlock_t acpi_device_lock;
@@ -350,21 +360,31 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
{
struct list_head *node, *next;
- seq_printf(seq, "Device Sleep state Status\n");
+ seq_printf(seq, "Device\tS-state\t Status Sysfs node\n");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_wakeup_device_list) {
struct acpi_device *dev =
container_of(node, struct acpi_device, wakeup_list);
+ struct device *ldev;
if (!dev->wakeup.flags.valid)
continue;
spin_unlock(&acpi_device_lock);
- seq_printf(seq, "%4s %4d %s%8s\n",
+
+ ldev = acpi_get_physical_device(dev->handle);
+ seq_printf(seq, "%s\t S%d\t%c%-8s ",
dev->pnp.bus_id,
(u32) dev->wakeup.sleep_state,
- dev->wakeup.flags.run_wake ? "*" : "",
+ dev->wakeup.flags.run_wake ? '*' : ' ',
dev->wakeup.state.enabled ? "enabled" : "disabled");
+ if (ldev)
+ seq_printf(seq, "%s:%s",
+ ldev->bus ? ldev->bus->name : "no-bus",
+ ldev->bus_id);
+ seq_printf(seq, "\n");
+ put_device(ldev);
+
spin_lock(&acpi_device_lock);
}
spin_unlock(&acpi_device_lock);
@@ -454,6 +474,7 @@ static const struct file_operations acpi_system_sleep_fops = {
};
#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#ifdef HAVE_ACPI_LEGACY_ALARM
static const struct file_operations acpi_system_alarm_fops = {
.open = acpi_system_alarm_open_fs,
.read = seq_read,
@@ -469,8 +490,9 @@ static u32 rtc_handler(void *context)
return ACPI_INTERRUPT_HANDLED;
}
+#endif /* HAVE_ACPI_LEGACY_ALARM */
-static int acpi_sleep_proc_init(void)
+static int __init acpi_sleep_proc_init(void)
{
struct proc_dir_entry *entry = NULL;
@@ -486,6 +508,7 @@ static int acpi_sleep_proc_init(void)
entry->proc_fops = &acpi_system_sleep_fops;
#endif
+#ifdef HAVE_ACPI_LEGACY_ALARM
/* 'alarm' [R/W] */
entry =
create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
@@ -493,6 +516,9 @@ static int acpi_sleep_proc_init(void)
if (entry)
entry->proc_fops = &acpi_system_alarm_fops;
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+#endif /* HAVE_ACPI_LEGACY_ALARM */
+
/* 'wakeup device' [R/W] */
entry =
create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
@@ -500,7 +526,6 @@ static int acpi_sleep_proc_init(void)
if (entry)
entry->proc_fops = &acpi_system_wakeup_device_fops;
- acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
return 0;
}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 807c7116e94..1db833eb241 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -347,6 +347,18 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
}
+
+ /*
+ * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
+ * are indeed zero. This will workaround BIOSs that inadvertently placed
+ * values in these fields.
+ */
+ if (acpi_gbl_FADT.header.revision < 3) {
+ acpi_gbl_FADT.preferred_profile = 0;
+ acpi_gbl_FADT.pstate_control = 0;
+ acpi_gbl_FADT.cst_control = 0;
+ acpi_gbl_FADT.boot_flags = 0;
+ }
}
/******************************************************************************
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 7bdbe5a914d..c7219663f2b 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -156,11 +156,6 @@ config SATA_INIC162X
help
This option enables support for Initio 162x Serial ATA.
-config SATA_INTEL_COMBINED
- bool
- depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
- default y
-
config SATA_ACPI
bool
depends on ACPI && PCI
@@ -184,7 +179,7 @@ config PATA_ALI
If unsure, say N.
config PATA_AMD
- tristate "AMD/NVidia PATA support (Experimental)"
+ tristate "AMD/NVidia PATA support"
depends on PCI
help
This option enables support for the AMD and NVidia PATA
@@ -209,6 +204,16 @@ config PATA_ATIIXP
If unsure, say N.
+config PATA_CMD640_PCI
+ tristate "CMD640 PCI PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the CMD640 PCI IDE
+ interface chip. Only the primary channel is currently
+ supported.
+
+ If unsure, say N.
+
config PATA_CMD64X
tristate "CMD64x PATA support (Very Experimental)"
depends on PCI&& EXPERIMENTAL
@@ -273,7 +278,7 @@ config ATA_GENERIC
If unsure, say N.
config PATA_HPT366
- tristate "HPT 366/368 PATA support (Very Experimental)"
+ tristate "HPT 366/368 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the HPT 366 and 368
@@ -282,7 +287,7 @@ config PATA_HPT366
If unsure, say N.
config PATA_HPT37X
- tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
+ tristate "HPT 370/370A/371/372/374/302 PATA support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the majority of the later HPT
@@ -309,7 +314,7 @@ config PATA_HPT3X3
If unsure, say N.
config PATA_ISAPNP
- tristate "ISA Plug and Play PATA support (Very Experimental)"
+ tristate "ISA Plug and Play PATA support (Experimental)"
depends on EXPERIMENTAL && ISAPNP
help
This option enables support for ISA plug & play ATA
@@ -318,8 +323,8 @@ config PATA_ISAPNP
If unsure, say N.
config PATA_IT821X
- tristate "IT8211/2 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "IT8211/2 PATA support"
+ depends on PCI
help
This option enables support for the ITE 8211 and 8212
PATA controllers via the new ATA layer, including RAID
@@ -390,10 +395,10 @@ config PATA_MPIIX
If unsure, say N.
config PATA_OLDPIIX
- tristate "Intel PATA old PIIX support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "Intel PATA old PIIX support"
+ depends on PCI
help
- This option enables support for old(?) PIIX PATA support.
+ This option enables support for early PIIX PATA support.
If unsure, say N.
@@ -430,7 +435,7 @@ config PATA_OPTIDMA
help
This option enables DMA/PIO support for the later OPTi
controllers found on some old motherboards and in some
- latops
+ laptops.
If unsure, say N.
@@ -444,7 +449,7 @@ config PATA_PCMCIA
If unsure, say N.
config PATA_PDC_OLD
- tristate "Older Promise PATA controller support (Very Experimental)"
+ tristate "Older Promise PATA controller support (Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the Promise 20246, 20262, 20263,
@@ -459,7 +464,7 @@ config PATA_QDI
Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
config PATA_RADISYS
- tristate "RADISYS 82600 PATA support (Very experimental)"
+ tristate "RADISYS 82600 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the RADISYS 82600
@@ -477,7 +482,7 @@ config PATA_RZ1000
If unsure, say N.
config PATA_SC1200
- tristate "SC1200 PATA support (Raving Lunatic)"
+ tristate "SC1200 PATA support (Very Experimental)"
depends on PCI && EXPERIMENTAL
help
This option enables support for the NatSemi/AMD SC1200 SoC
@@ -486,8 +491,8 @@ config PATA_SC1200
If unsure, say N.
config PATA_SERVERWORKS
- tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support"
+ depends on PCI
help
This option enables support for the Serverworks OSB4/CSB5/CSB6 and
HT1000 PATA controllers, via the new ATA layer.
@@ -545,13 +550,21 @@ config PATA_WINBOND_VLB
config PATA_PLATFORM
tristate "Generic platform device PATA support"
- depends on EMBEDDED
+ depends on EMBEDDED || ARCH_RPC
help
This option enables support for generic directly connected ATA
devices commonly found on embedded systems.
If unsure, say N.
+config PATA_ICSIDE
+ tristate "Acorn ICS PATA support"
+ depends on ARM && ARCH_ACORN
+ help
+ On Acorn systems, say Y here if you wish to use the ICS PATA
+ interface card. This is not required for ICS partition support.
+ If you are unsure, say N to this.
+
config PATA_IXP4XX_CF
tristate "IXP4XX Compact Flash support"
depends on ARCH_IXP4XX
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 13d7397e000..6f42a0e2812 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_PATA_ALI) += pata_ali.o
obj-$(CONFIG_PATA_AMD) += pata_amd.o
obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
+obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
@@ -61,6 +62,7 @@ obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
+obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
# Should be last but one libata driver
obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index fd27227771b..d9617892fc2 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -170,6 +170,10 @@ enum {
AHCI_FLAG_IGN_IRQ_IF_ERR = (1 << 25), /* ignore IRQ_IF_ERR */
AHCI_FLAG_HONOR_PI = (1 << 26), /* honor PORTS_IMPL */
AHCI_FLAG_IGN_SERR_INTERNAL = (1 << 27), /* ignore SERR_INTERNAL */
+
+ AHCI_FLAG_COMMON = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ ATA_FLAG_SKIP_D2H_BSY,
};
struct ahci_cmd_hdr {
@@ -188,8 +192,10 @@ struct ahci_sg {
};
struct ahci_host_priv {
- u32 cap; /* cache of HOST_CAP register */
- u32 port_map; /* cache of HOST_PORTS_IMPL reg */
+ u32 cap; /* cap to use */
+ u32 port_map; /* port map to use */
+ u32 saved_cap; /* saved initial cap */
+ u32 saved_port_map; /* saved initial port_map */
};
struct ahci_port_priv {
@@ -209,7 +215,6 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
static void ahci_irq_clear(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
@@ -263,7 +268,6 @@ static const struct ata_port_operations ahci_ops = {
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
- .irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.irq_on = ata_dummy_irq_on,
.irq_ack = ata_dummy_irq_ack,
@@ -298,7 +302,6 @@ static const struct ata_port_operations ahci_vt8251_ops = {
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
- .irq_handler = ahci_interrupt,
.irq_clear = ahci_irq_clear,
.irq_on = ata_dummy_irq_on,
.irq_ack = ata_dummy_irq_ack,
@@ -324,58 +327,41 @@ static const struct ata_port_operations ahci_vt8251_ops = {
static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY,
+ .flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
/* board_ahci_pi */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI,
+ .flags = AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
/* board_ahci_vt8251 */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- ATA_FLAG_HRST_TO_RESUME | AHCI_FLAG_NO_NCQ,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
+ AHCI_FLAG_NO_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_vt8251_ops,
},
/* board_ahci_ign_iferr */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
- AHCI_FLAG_IGN_IRQ_IF_ERR,
+ .flags = AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
/* board_ahci_sb600 */
{
- .sht = &ahci_sht,
- .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
- ATA_FLAG_SKIP_D2H_BSY |
+ .flags = AHCI_FLAG_COMMON |
AHCI_FLAG_IGN_SERR_INTERNAL,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
-
};
static const struct pci_device_id ahci_pci_tbl[] = {
@@ -413,11 +399,11 @@ static const struct pci_device_id ahci_pci_tbl[] = {
PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci_ign_iferr },
/* ATI */
- { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 non-raid */
- { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
+ { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
+ { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
@@ -471,10 +457,100 @@ static inline int ahci_nr_ports(u32 cap)
return (cap & 0x1f) + 1;
}
-static inline void __iomem *ahci_port_base(void __iomem *base,
- unsigned int port)
+static inline void __iomem *ahci_port_base(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
+
+ return mmio + 0x100 + (ap->port_no * 0x80);
+}
+
+/**
+ * ahci_save_initial_config - Save and fixup initial config values
+ * @pdev: target PCI device
+ * @pi: associated ATA port info
+ * @hpriv: host private area to store config values
+ *
+ * Some registers containing configuration info might be setup by
+ * BIOS and might be cleared on reset. This function saves the
+ * initial values of those registers into @hpriv such that they
+ * can be restored after controller reset.
+ *
+ * If inconsistent, config values are fixed up by this function.
+ *
+ * LOCKING:
+ * None.
+ */
+static void ahci_save_initial_config(struct pci_dev *pdev,
+ const struct ata_port_info *pi,
+ struct ahci_host_priv *hpriv)
{
- return base + 0x100 + (port * 0x80);
+ void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
+ u32 cap, port_map;
+ int i;
+
+ /* Values prefixed with saved_ are written back to host after
+ * reset. Values without are used for driver operation.
+ */
+ hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
+ hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+
+ /* fixup zero port_map */
+ if (!port_map) {
+ port_map = (1 << ahci_nr_ports(hpriv->cap)) - 1;
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
+
+ /* write the fixed up value to the PI register */
+ hpriv->saved_port_map = port_map;
+ }
+
+ /* cross check port_map and cap.n_ports */
+ if (pi->flags & AHCI_FLAG_HONOR_PI) {
+ u32 tmp_port_map = port_map;
+ int n_ports = ahci_nr_ports(cap);
+
+ for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
+ if (tmp_port_map & (1 << i)) {
+ n_ports--;
+ tmp_port_map &= ~(1 << i);
+ }
+ }
+
+ /* Whine if inconsistent. No need to update cap.
+ * port_map is used to determine number of ports.
+ */
+ if (n_ports || tmp_port_map)
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "nr_ports (%u) and implemented port map "
+ "(0x%x) don't match\n",
+ ahci_nr_ports(cap), port_map);
+ } else {
+ /* fabricate port_map from cap.nr_ports */
+ port_map = (1 << ahci_nr_ports(cap)) - 1;
+ }
+
+ /* record values to use during operation */
+ hpriv->cap = cap;
+ hpriv->port_map = port_map;
+}
+
+/**
+ * ahci_restore_initial_config - Restore initial config
+ * @host: target ATA host
+ *
+ * Restore initial config stored by ahci_save_initial_config().
+ *
+ * LOCKING:
+ * None.
+ */
+static void ahci_restore_initial_config(struct ata_host *host)
+{
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+
+ writel(hpriv->saved_cap, mmio + HOST_CAP);
+ writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
+ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
@@ -511,8 +587,9 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
-static void ahci_start_engine(void __iomem *port_mmio)
+static void ahci_start_engine(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* start DMA */
@@ -522,8 +599,9 @@ static void ahci_start_engine(void __iomem *port_mmio)
readl(port_mmio + PORT_CMD); /* flush */
}
-static int ahci_stop_engine(void __iomem *port_mmio)
+static int ahci_stop_engine(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
tmp = readl(port_mmio + PORT_CMD);
@@ -545,19 +623,23 @@ static int ahci_stop_engine(void __iomem *port_mmio)
return 0;
}
-static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
- dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_start_fis_rx(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
u32 tmp;
/* set FIS registers */
- if (cap & HOST_CAP_64)
- writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
- writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+ if (hpriv->cap & HOST_CAP_64)
+ writel((pp->cmd_slot_dma >> 16) >> 16,
+ port_mmio + PORT_LST_ADDR_HI);
+ writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
- if (cap & HOST_CAP_64)
- writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
- writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+ if (hpriv->cap & HOST_CAP_64)
+ writel((pp->rx_fis_dma >> 16) >> 16,
+ port_mmio + PORT_FIS_ADDR_HI);
+ writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
/* enable FIS reception */
tmp = readl(port_mmio + PORT_CMD);
@@ -568,8 +650,9 @@ static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
readl(port_mmio + PORT_CMD);
}
-static int ahci_stop_fis_rx(void __iomem *port_mmio)
+static int ahci_stop_fis_rx(struct ata_port *ap)
{
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* disable FIS reception */
@@ -586,14 +669,16 @@ static int ahci_stop_fis_rx(void __iomem *port_mmio)
return 0;
}
-static void ahci_power_up(void __iomem *port_mmio, u32 cap)
+static void ahci_power_up(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd;
cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
/* spin up device */
- if (cap & HOST_CAP_SSS) {
+ if (hpriv->cap & HOST_CAP_SSS) {
cmd |= PORT_CMD_SPIN_UP;
writel(cmd, port_mmio + PORT_CMD);
}
@@ -603,11 +688,13 @@ static void ahci_power_up(void __iomem *port_mmio, u32 cap)
}
#ifdef CONFIG_PM
-static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+static void ahci_power_down(struct ata_port *ap)
{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 cmd, scontrol;
- if (!(cap & HOST_CAP_SSS))
+ if (!(hpriv->cap & HOST_CAP_SSS))
return;
/* put device into listen mode, first set PxSCTL.DET to 0 */
@@ -622,29 +709,28 @@ static void ahci_power_down(void __iomem *port_mmio, u32 cap)
}
#endif
-static void ahci_init_port(void __iomem *port_mmio, u32 cap,
- dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+static void ahci_init_port(struct ata_port *ap)
{
/* enable FIS reception */
- ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+ ahci_start_fis_rx(ap);
/* enable DMA */
- ahci_start_engine(port_mmio);
+ ahci_start_engine(ap);
}
-static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+static int ahci_deinit_port(struct ata_port *ap, const char **emsg)
{
int rc;
/* disable DMA */
- rc = ahci_stop_engine(port_mmio);
+ rc = ahci_stop_engine(ap);
if (rc) {
*emsg = "failed to stop engine";
return rc;
}
/* disable FIS reception */
- rc = ahci_stop_fis_rx(port_mmio);
+ rc = ahci_stop_fis_rx(ap);
if (rc) {
*emsg = "failed stop FIS RX";
return rc;
@@ -653,12 +739,11 @@ static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
return 0;
}
-static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
+static int ahci_reset_controller(struct ata_host *host)
{
- u32 cap_save, impl_save, tmp;
-
- cap_save = readl(mmio + HOST_CAP);
- impl_save = readl(mmio + HOST_PORTS_IMPL);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
+ u32 tmp;
/* global controller reset */
tmp = readl(mmio + HOST_CTL);
@@ -674,7 +759,7 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
tmp = readl(mmio + HOST_CTL);
if (tmp & HOST_RESET) {
- dev_printk(KERN_ERR, &pdev->dev,
+ dev_printk(KERN_ERR, host->dev,
"controller reset failed (0x%x)\n", tmp);
return -EIO;
}
@@ -683,18 +768,8 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
writel(HOST_AHCI_EN, mmio + HOST_CTL);
(void) readl(mmio + HOST_CTL); /* flush */
- /* These write-once registers are normally cleared on reset.
- * Restore BIOS values... which we HOPE were present before
- * reset.
- */
- if (!impl_save) {
- impl_save = (1 << ahci_nr_ports(cap_save)) - 1;
- dev_printk(KERN_WARNING, &pdev->dev,
- "PORTS_IMPL is zero, forcing 0x%x\n", impl_save);
- }
- writel(cap_save, mmio + HOST_CAP);
- writel(impl_save, mmio + HOST_PORTS_IMPL);
- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
+ /* some registers might be cleared on reset. restore initial values */
+ ahci_restore_initial_config(host);
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
u16 tmp16;
@@ -708,23 +783,23 @@ static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
return 0;
}
-static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
- int n_ports, unsigned int port_flags,
- struct ahci_host_priv *hpriv)
+static void ahci_init_controller(struct ata_host *host)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int i, rc;
u32 tmp;
- for (i = 0; i < n_ports; i++) {
- void __iomem *port_mmio = ahci_port_base(mmio, i);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port_mmio = ahci_port_base(ap);
const char *emsg = NULL;
- if ((port_flags & AHCI_FLAG_HONOR_PI) &&
- !(hpriv->port_map & (1 << i)))
+ if (ata_port_is_dummy(ap))
continue;
/* make sure port is not active */
- rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ rc = ahci_deinit_port(ap, &emsg);
if (rc)
dev_printk(KERN_WARNING, &pdev->dev,
"%s (%d)\n", emsg, rc);
@@ -752,7 +827,7 @@ static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
static unsigned int ahci_dev_classify(struct ata_port *ap)
{
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ahci_port_base(ap);
struct ata_taskfile tf;
u32 tmp;
@@ -799,11 +874,11 @@ static int ahci_clo(struct ata_port *ap)
return 0;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class)
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *port_mmio = ahci_port_base(ap);
const u32 cmd_fis_len = 5; /* five dwords */
const char *reason = NULL;
struct ata_taskfile tf;
@@ -820,7 +895,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
}
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(port_mmio);
+ rc = ahci_stop_engine(ap);
if (rc) {
reason = "failed to stop engine";
goto fail_restart;
@@ -840,7 +915,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
}
/* restart engine */
- ahci_start_engine(port_mmio);
+ ahci_start_engine(ap);
ata_tf_init(ap->device, &tf);
fis = pp->cmd_tbl;
@@ -885,47 +960,44 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
*/
msleep(150);
- *class = ATA_DEV_NONE;
- if (ata_port_online(ap)) {
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- rc = -EIO;
- reason = "device not ready";
- goto fail;
- }
- *class = ahci_dev_classify(ap);
+ rc = ata_wait_ready(ap, deadline);
+ /* link occupied, -ENODEV too is an error */
+ if (rc) {
+ reason = "device not ready";
+ goto fail;
}
+ *class = ahci_dev_classify(ap);
DPRINTK("EXIT, class=%u\n", *class);
return 0;
fail_restart:
- ahci_start_engine(port_mmio);
+ ahci_start_engine(ap);
fail:
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
+static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
DPRINTK("ENTER\n");
- ahci_stop_engine(port_mmio);
+ ahci_stop_engine(ap);
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(ap->device, &tf);
tf.command = 0x80;
ata_tf_to_fis(&tf, d2h_fis, 0);
- rc = sata_std_hardreset(ap, class);
+ rc = sata_std_hardreset(ap, class, deadline);
- ahci_start_engine(port_mmio);
+ ahci_start_engine(ap);
if (rc == 0 && ata_port_online(ap))
*class = ahci_dev_classify(ap);
@@ -936,22 +1008,22 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
return rc;
}
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
+static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
DPRINTK("ENTER\n");
- ahci_stop_engine(port_mmio);
+ ahci_stop_engine(ap);
- rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context));
+ rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+ deadline);
/* vt8251 needs SError cleared for the port to operate */
ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
- ahci_start_engine(port_mmio);
+ ahci_start_engine(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
@@ -963,7 +1035,7 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class)
static void ahci_postreset(struct ata_port *ap, unsigned int *class)
{
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 new_tmp, tmp;
ata_std_postreset(ap, class);
@@ -1131,8 +1203,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_host_intr(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ata_eh_info *ehi = &ap->eh_info;
struct ahci_port_priv *pp = ap->private_data;
u32 status, qc_active;
@@ -1283,7 +1354,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ void __iomem *port_mmio = ahci_port_base(ap);
if (qc->tf.protocol == ATA_PROT_NCQ)
writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1295,8 +1366,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
static void ahci_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *port_mmio = ahci_port_base(ap);
/* turn IRQ off */
writel(0, port_mmio + PORT_IRQ_MASK);
@@ -1305,7 +1375,7 @@ static void ahci_freeze(struct ata_port *ap)
static void ahci_thaw(struct ata_port *ap)
{
void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
/* clear IRQ */
@@ -1319,13 +1389,10 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
- ahci_stop_engine(port_mmio);
- ahci_start_engine(port_mmio);
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
}
/* perform recovery */
@@ -1335,13 +1402,10 @@ static void ahci_error_handler(struct ata_port *ap)
static void ahci_vt8251_error_handler(struct ata_port *ap)
{
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
- ahci_stop_engine(port_mmio);
- ahci_start_engine(port_mmio);
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
}
/* perform recovery */
@@ -1352,36 +1416,26 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- if (qc->flags & ATA_QCFLAG_FAILED)
- qc->err_mask |= AC_ERR_OTHER;
-
- if (qc->err_mask) {
+ if (qc->flags & ATA_QCFLAG_FAILED) {
/* make DMA engine forget about the failed command */
- ahci_stop_engine(port_mmio);
- ahci_start_engine(port_mmio);
+ ahci_stop_engine(ap);
+ ahci_start_engine(ap);
}
}
#ifdef CONFIG_PM
static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const char *emsg = NULL;
int rc;
- rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ rc = ahci_deinit_port(ap, &emsg);
if (rc == 0)
- ahci_power_down(port_mmio, hpriv->cap);
+ ahci_power_down(ap);
else {
ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
- ahci_init_port(port_mmio, hpriv->cap,
- pp->cmd_slot_dma, pp->rx_fis_dma);
+ ahci_init_port(ap);
}
return rc;
@@ -1389,13 +1443,8 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
static int ahci_port_resume(struct ata_port *ap)
{
- struct ahci_port_priv *pp = ap->private_data;
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
-
- ahci_power_up(port_mmio, hpriv->cap);
- ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+ ahci_power_up(ap);
+ ahci_init_port(ap);
return 0;
}
@@ -1423,8 +1472,6 @@ static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
static int ahci_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
- struct ahci_host_priv *hpriv = host->private_data;
- void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -1432,12 +1479,11 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = ahci_reset_controller(mmio, pdev);
+ rc = ahci_reset_controller(host);
if (rc)
return rc;
- ahci_init_controller(mmio, pdev, host->n_ports,
- host->ports[0]->flags, hpriv);
+ ahci_init_controller(host);
}
ata_host_resume(host);
@@ -1449,10 +1495,7 @@ static int ahci_pci_device_resume(struct pci_dev *pdev)
static int ahci_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
- struct ahci_host_priv *hpriv = ap->host->private_data;
struct ahci_port_priv *pp;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
void *mem;
dma_addr_t mem_dma;
int rc;
@@ -1500,85 +1543,29 @@ static int ahci_port_start(struct ata_port *ap)
ap->private_data = pp;
/* power up port */
- ahci_power_up(port_mmio, hpriv->cap);
+ ahci_power_up(ap);
/* initialize port */
- ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+ ahci_init_port(ap);
return 0;
}
static void ahci_port_stop(struct ata_port *ap)
{
- struct ahci_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const char *emsg = NULL;
int rc;
/* de-initialize port */
- rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ rc = ahci_deinit_port(ap, &emsg);
if (rc)
ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
}
-static void ahci_setup_port(struct ata_ioports *port, void __iomem *base,
- unsigned int port_idx)
-{
- VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
- base = ahci_port_base(base, port_idx);
- VPRINTK("base now==0x%lx\n", base);
-
- port->cmd_addr = base;
- port->scr_addr = base + PORT_SCR;
-
- VPRINTK("EXIT\n");
-}
-
-static int ahci_host_init(struct ata_probe_ent *probe_ent)
+static int ahci_configure_dma_masks(struct pci_dev *pdev, int using_dac)
{
- struct ahci_host_priv *hpriv = probe_ent->private_data;
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
- unsigned int i, cap_n_ports, using_dac;
int rc;
- rc = ahci_reset_controller(mmio, pdev);
- if (rc)
- return rc;
-
- hpriv->cap = readl(mmio + HOST_CAP);
- hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
- cap_n_ports = ahci_nr_ports(hpriv->cap);
-
- VPRINTK("cap 0x%x port_map 0x%x n_ports %d\n",
- hpriv->cap, hpriv->port_map, cap_n_ports);
-
- if (probe_ent->port_flags & AHCI_FLAG_HONOR_PI) {
- unsigned int n_ports = cap_n_ports;
- u32 port_map = hpriv->port_map;
- int max_port = 0;
-
- for (i = 0; i < AHCI_MAX_PORTS && n_ports; i++) {
- if (port_map & (1 << i)) {
- n_ports--;
- port_map &= ~(1 << i);
- max_port = i;
- } else
- probe_ent->dummy_port_mask |= 1 << i;
- }
-
- if (n_ports || port_map)
- dev_printk(KERN_WARNING, &pdev->dev,
- "nr_ports (%u) and implemented port map "
- "(0x%x) don't match\n",
- cap_n_ports, hpriv->port_map);
-
- probe_ent->n_ports = max_port + 1;
- } else
- probe_ent->n_ports = cap_n_ports;
-
- using_dac = hpriv->cap & HOST_CAP_64;
if (using_dac &&
!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
@@ -1604,23 +1591,14 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
return rc;
}
}
-
- for (i = 0; i < probe_ent->n_ports; i++)
- ahci_setup_port(&probe_ent->port[i], mmio, i);
-
- ahci_init_controller(mmio, pdev, probe_ent->n_ports,
- probe_ent->port_flags, hpriv);
-
- pci_set_master(pdev);
-
return 0;
}
-static void ahci_print_info(struct ata_probe_ent *probe_ent)
+static void ahci_print_info(struct ata_host *host)
{
- struct ahci_host_priv *hpriv = probe_ent->private_data;
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- void __iomem *mmio = probe_ent->iomap[AHCI_PCI_BAR];
+ struct ahci_host_priv *hpriv = host->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
u32 vers, cap, impl, speed;
const char *speed_s;
u16 cc;
@@ -1690,11 +1668,12 @@ static void ahci_print_info(struct ata_probe_ent *probe_ent)
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- unsigned int board_idx = (unsigned int) ent->driver_data;
+ struct ata_port_info pi = ahci_port_info[ent->driver_data];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
struct ahci_host_priv *hpriv;
- int rc;
+ struct ata_host *host;
+ int i, rc;
VPRINTK("ENTER\n");
@@ -1703,6 +1682,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -1716,44 +1696,49 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_enable_msi(pdev))
pci_intx(pdev, 1);
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
- probe_ent->sht = ahci_port_info[board_idx].sht;
- probe_ent->port_flags = ahci_port_info[board_idx].flags;
- probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask;
- probe_ent->port_ops = ahci_port_info[board_idx].port_ops;
+ /* save initial config */
+ ahci_save_initial_config(pdev, &pi, hpriv);
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
- probe_ent->private_data = hpriv;
+ /* prepare host */
+ if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+ pi.flags |= ATA_FLAG_NCQ;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
+ if (!host)
+ return -ENOMEM;
+ host->iomap = pcim_iomap_table(pdev);
+ host->private_data = hpriv;
+
+ for (i = 0; i < host->n_ports; i++) {
+ if (hpriv->port_map & (1 << i)) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *port_mmio = ahci_port_base(ap);
+
+ ap->ioaddr.cmd_addr = port_mmio;
+ ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
+ } else
+ host->ports[i]->ops = &ata_dummy_port_ops;
+ }
/* initialize adapter */
- rc = ahci_host_init(probe_ent);
+ rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)
return rc;
- if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
- (hpriv->cap & HOST_CAP_NCQ))
- probe_ent->port_flags |= ATA_FLAG_NCQ;
-
- ahci_print_info(probe_ent);
+ rc = ahci_reset_controller(host);
+ if (rc)
+ return rc;
- if (!ata_device_add(probe_ent))
- return -ENODEV;
+ ahci_init_controller(host);
+ ahci_print_info(host);
- devm_kfree(dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, ahci_interrupt, IRQF_SHARED,
+ &ahci_sht);
}
static int __init ahci_init(void)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index d8e79882b88..92a491ddd03 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -33,35 +33,6 @@
*/
/**
- * generic_pre_reset - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generic probe init
- */
-
-static int generic_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-
-/**
- * generic_error_handler - Probe specified port on PATA host controller
- * @ap: Port to probe
- * @classes:
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-
-static void generic_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-/**
* generic_set_mode - mode setting
* @ap: interface to set up
* @unused: returned device on error
@@ -144,8 +115,9 @@ static struct ata_port_operations generic_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = generic_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index b952c584338..4a795fdb6a0 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -93,7 +93,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "2.10ac1"
+#define DRV_VERSION "2.11"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
@@ -155,11 +155,11 @@ struct piix_host_priv {
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
static void piix_pata_error_handler(struct ata_port *ap);
-static void ich_pata_error_handler(struct ata_port *ap);
static void piix_sata_error_handler(struct ata_port *ap);
static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static int ich_pata_cable_detect(struct ata_port *ap);
static unsigned int in_module_init = 1;
@@ -305,6 +305,7 @@ static const struct ata_port_operations piix_pata_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = piix_pata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -336,8 +337,9 @@ static const struct ata_port_operations ich_pata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ich_pata_error_handler,
+ .error_handler = piix_pata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ich_pata_cable_detect,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -580,12 +582,13 @@ static const struct ich_laptop ich_laptop[] = {
/* devid, subvendor, subdev */
{ 0x27DF, 0x0005, 0x0280 }, /* ICH7 on Acer 5602WLMi */
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
+ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
/* end marker */
{ 0, }
};
/**
- * piix_pata_cbl_detect - Probe host controller cable detect info
+ * ich_pata_cable_detect - Probe host controller cable detect info
* @ap: Port for which cable detect info is desired
*
* Read 80c cable indicator from ATA PCI device's PCI config
@@ -595,23 +598,18 @@ static const struct ich_laptop ich_laptop[] = {
* None (inherited from caller).
*/
-static void ich_pata_cbl_detect(struct ata_port *ap)
+static int ich_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
const struct ich_laptop *lap = &ich_laptop[0];
u8 tmp, mask;
- /* no 80c support in host controller? */
- if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
- goto cbl40;
-
/* Check for specials - Acer Aspire 5602WLMi */
while (lap->device) {
if (lap->device == pdev->device &&
lap->subvendor == pdev->subsystem_vendor &&
lap->subdevice == pdev->subsystem_device) {
- ap->cbl = ATA_CBL_PATA40_SHORT;
- return;
+ return ATA_CBL_PATA40_SHORT;
}
lap++;
}
@@ -620,32 +618,25 @@ static void ich_pata_cbl_detect(struct ata_port *ap)
mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
if ((tmp & mask) == 0)
- goto cbl40;
-
- ap->cbl = ATA_CBL_PATA80;
- return;
-
-cbl40:
- ap->cbl = ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
}
/**
* piix_pata_prereset - prereset for PATA host controller
* @ap: Target port
- *
+ * @deadline: deadline jiffies for the operation
*
* LOCKING:
* None (inherited from caller).
*/
-static int piix_pata_prereset(struct ata_port *ap)
+static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
return -ENOENT;
-
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
static void piix_pata_error_handler(struct ata_port *ap)
@@ -654,31 +645,6 @@ static void piix_pata_error_handler(struct ata_port *ap)
ata_std_postreset);
}
-
-/**
- * ich_pata_prereset - prereset for PATA host controller
- * @ap: Target port
- *
- *
- * LOCKING:
- * None (inherited from caller).
- */
-static int ich_pata_prereset(struct ata_port *ap)
-{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
- return -ENOENT;
- ich_pata_cbl_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void ich_pata_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, ich_pata_prereset, ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
static void piix_sata_error_handler(struct ata_port *ap)
{
ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 0abd72d0dec..fef87dd70d1 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -72,7 +72,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
-static unsigned int ata_print_id = 1;
+unsigned int ata_print_id = 1;
static struct workqueue_struct *ata_wq;
struct workqueue_struct *ata_aux_wq;
@@ -89,6 +89,10 @@ int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+static int ata_ignore_hpa = 0;
+module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
+MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
+
static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
module_param(ata_probe_timeout, int, 0444);
MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
@@ -808,6 +812,205 @@ void ata_id_c_string(const u16 *id, unsigned char *s,
*p = '\0';
}
+static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
+{
+ u64 sectors = 0;
+
+ sectors |= ((u64)(tf->hob_lbah & 0xff)) << 40;
+ sectors |= ((u64)(tf->hob_lbam & 0xff)) << 32;
+ sectors |= (tf->hob_lbal & 0xff) << 24;
+ sectors |= (tf->lbah & 0xff) << 16;
+ sectors |= (tf->lbam & 0xff) << 8;
+ sectors |= (tf->lbal & 0xff);
+
+ return ++sectors;
+}
+
+static u64 ata_tf_to_lba(struct ata_taskfile *tf)
+{
+ u64 sectors = 0;
+
+ sectors |= (tf->device & 0x0f) << 24;
+ sectors |= (tf->lbah & 0xff) << 16;
+ sectors |= (tf->lbam & 0xff) << 8;
+ sectors |= (tf->lbal & 0xff);
+
+ return ++sectors;
+}
+
+/**
+ * ata_read_native_max_address_ext - LBA48 native max query
+ * @dev: Device to query
+ *
+ * Perform an LBA48 size query upon the device in question. Return the
+ * actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address_ext(struct ata_device *dev)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= 0x40;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba48(&tf);
+}
+
+/**
+ * ata_read_native_max_address - LBA28 native max query
+ * @dev: Device to query
+ *
+ * Performa an LBA28 size query upon the device in question. Return the
+ * actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_read_native_max_address(struct ata_device *dev)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_READ_NATIVE_MAX;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= 0x40;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba(&tf);
+}
+
+/**
+ * ata_set_native_max_address_ext - LBA48 native max set
+ * @dev: Device to query
+ *
+ * Perform an LBA48 size set max upon the device in question. Return the
+ * actual LBA48 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ new_sectors--;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_SET_MAX_EXT;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+ tf.device |= 0x40;
+
+ tf.lbal = (new_sectors >> 0) & 0xff;
+ tf.lbam = (new_sectors >> 8) & 0xff;
+ tf.lbah = (new_sectors >> 16) & 0xff;
+
+ tf.hob_lbal = (new_sectors >> 24) & 0xff;
+ tf.hob_lbam = (new_sectors >> 32) & 0xff;
+ tf.hob_lbah = (new_sectors >> 40) & 0xff;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba48(&tf);
+}
+
+/**
+ * ata_set_native_max_address - LBA28 native max set
+ * @dev: Device to query
+ *
+ * Perform an LBA28 size set max upon the device in question. Return the
+ * actual LBA28 size or zero if the command fails.
+ */
+
+static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
+{
+ unsigned int err;
+ struct ata_taskfile tf;
+
+ new_sectors--;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = ATA_CMD_SET_MAX;
+ tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+ tf.protocol |= ATA_PROT_NODATA;
+
+ tf.lbal = (new_sectors >> 0) & 0xff;
+ tf.lbam = (new_sectors >> 8) & 0xff;
+ tf.lbah = (new_sectors >> 16) & 0xff;
+ tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
+
+ err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err)
+ return 0;
+
+ return ata_tf_to_lba(&tf);
+}
+
+/**
+ * ata_hpa_resize - Resize a device with an HPA set
+ * @dev: Device to resize
+ *
+ * Read the size of an LBA28 or LBA48 disk with HPA features and resize
+ * it if required to the full size of the media. The caller must check
+ * the drive has the HPA feature set enabled.
+ */
+
+static u64 ata_hpa_resize(struct ata_device *dev)
+{
+ u64 sectors = dev->n_sectors;
+ u64 hpa_sectors;
+
+ if (ata_id_has_lba48(dev->id))
+ hpa_sectors = ata_read_native_max_address_ext(dev);
+ else
+ hpa_sectors = ata_read_native_max_address(dev);
+
+ /* if no hpa, both should be equal */
+ ata_dev_printk(dev, KERN_INFO, "%s 1: sectors = %lld, "
+ "hpa_sectors = %lld\n",
+ __FUNCTION__, (long long)sectors, (long long)hpa_sectors);
+
+ if (hpa_sectors > sectors) {
+ ata_dev_printk(dev, KERN_INFO,
+ "Host Protected Area detected:\n"
+ "\tcurrent size: %lld sectors\n"
+ "\tnative size: %lld sectors\n",
+ (long long)sectors, (long long)hpa_sectors);
+
+ if (ata_ignore_hpa) {
+ if (ata_id_has_lba48(dev->id))
+ hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
+ else
+ hpa_sectors = ata_set_native_max_address(dev,
+ hpa_sectors);
+
+ if (hpa_sectors) {
+ ata_dev_printk(dev, KERN_INFO, "native size "
+ "increased to %lld sectors\n",
+ (long long)hpa_sectors);
+ return hpa_sectors;
+ }
+ }
+ }
+ return sectors;
+}
+
static u64 ata_id_n_sectors(const u16 *id)
{
if (ata_id_has_lba(id)) {
@@ -1113,7 +1316,7 @@ void ata_port_flush_task(struct ata_port *ap)
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
- flush_workqueue(ata_wq);
+ cancel_work_sync(&ap->port_task.work); /* akpm: seems unneeded */
/*
* At this point, if a task is running, it's guaranteed to see
@@ -1124,7 +1327,7 @@ void ata_port_flush_task(struct ata_port *ap)
if (ata_msg_ctl(ap))
ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
__FUNCTION__);
- flush_workqueue(ata_wq);
+ cancel_work_sync(&ap->port_task.work);
}
spin_lock_irqsave(ap->lock, flags);
@@ -1270,12 +1473,16 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
if (ap->ops->post_internal_cmd)
ap->ops->post_internal_cmd(qc);
- if ((qc->flags & ATA_QCFLAG_FAILED) && !qc->err_mask) {
- if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "zero err_mask for failed "
- "internal command, assuming AC_ERR_OTHER\n");
- qc->err_mask |= AC_ERR_OTHER;
+ /* perform minimal error analysis */
+ if (qc->flags & ATA_QCFLAG_FAILED) {
+ if (qc->result_tf.command & (ATA_ERR | ATA_DF))
+ qc->err_mask |= AC_ERR_DEV;
+
+ if (!qc->err_mask)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask & ~AC_ERR_OTHER)
+ qc->err_mask &= ~AC_ERR_OTHER;
}
/* finish up */
@@ -1379,30 +1586,44 @@ unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
* Check if the current speed of the device requires IORDY. Used
* by various controllers for chip configuration.
*/
-
+
unsigned int ata_pio_need_iordy(const struct ata_device *adev)
{
- int pio;
- int speed = adev->pio_mode - XFER_PIO_0;
-
- if (speed < 2)
+ /* Controller doesn't support IORDY. Probably a pointless check
+ as the caller should know this */
+ if (adev->ap->flags & ATA_FLAG_NO_IORDY)
return 0;
- if (speed > 2)
+ /* PIO3 and higher it is mandatory */
+ if (adev->pio_mode > XFER_PIO_2)
+ return 1;
+ /* We turn it on when possible */
+ if (ata_id_has_iordy(adev->id))
return 1;
+ return 0;
+}
+/**
+ * ata_pio_mask_no_iordy - Return the non IORDY mask
+ * @adev: ATA device
+ *
+ * Compute the highest mode possible if we are not using iordy. Return
+ * -1 if no iordy mode is available.
+ */
+
+static u32 ata_pio_mask_no_iordy(const struct ata_device *adev)
+{
/* If we have no drive specific rule, then PIO 2 is non IORDY */
-
if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE */
- pio = adev->id[ATA_ID_EIDE_PIO];
+ u16 pio = adev->id[ATA_ID_EIDE_PIO];
/* Is the speed faster than the drive allows non IORDY ? */
if (pio) {
/* This is cycle times not frequency - watch the logic! */
if (pio > 240) /* PIO2 is 240nS per cycle */
- return 1;
- return 0;
+ return 3 << ATA_SHIFT_PIO;
+ return 7 << ATA_SHIFT_PIO;
}
}
- return 0;
+ return 3 << ATA_SHIFT_PIO;
}
/**
@@ -1431,13 +1652,13 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
struct ata_taskfile tf;
unsigned int err_mask = 0;
const char *reason;
+ int tried_spinup = 0;
int rc;
if (ata_msg_ctl(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
-
retry:
ata_tf_init(dev, &tf);
@@ -1494,6 +1715,32 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
goto err_out;
}
+ if (!tried_spinup && (id[2] == 0x37c8 || id[2] == 0x738c)) {
+ tried_spinup = 1;
+ /*
+ * Drive powered-up in standby mode, and requires a specific
+ * SET_FEATURES spin-up subcommand before it will accept
+ * anything other than the original IDENTIFY command.
+ */
+ ata_tf_init(dev, &tf);
+ tf.command = ATA_CMD_SET_FEATURES;
+ tf.feature = SETFEATURES_SPINUP;
+ tf.protocol = ATA_PROT_NODATA;
+ tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+ err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+ if (err_mask) {
+ rc = -EIO;
+ reason = "SPINUP failed";
+ goto err_out;
+ }
+ /*
+ * If the drive initially returned incomplete IDENTIFY info,
+ * we now must reissue the IDENTIFY command.
+ */
+ if (id[2] == 0x37c8)
+ goto retry;
+ }
+
if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
/*
* The exact sequence expected by certain pre-ATA4 drives is:
@@ -1560,20 +1807,6 @@ static void ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
-static void ata_set_port_max_cmd_len(struct ata_port *ap)
-{
- int i;
-
- if (ap->scsi_host) {
- unsigned int len = 0;
-
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- len = max(len, ap->device[i].cdb_len);
-
- ap->scsi_host->max_cmd_len = len;
- }
-}
-
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -1658,6 +1891,7 @@ int ata_dev_configure(struct ata_device *dev)
snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
dev->n_sectors = ata_id_n_sectors(id);
+ dev->n_sectors_boot = dev->n_sectors;
/* SCSI only uses 4-char revisions, dump full 8 chars from ATA */
ata_id_c_string(dev->id, fwrevbuf, ATA_ID_FW_REV,
@@ -1684,6 +1918,9 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_FLUSH_EXT;
}
+ if (ata_id_hpa_enabled(dev->id))
+ dev->n_sectors = ata_hpa_resize(dev);
+
/* config NCQ */
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
@@ -1773,8 +2010,6 @@ int ata_dev_configure(struct ata_device *dev)
}
}
- ata_set_port_max_cmd_len(ap);
-
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
if (ata_msg_drv(ap) && print_info)
@@ -1785,14 +2020,15 @@ int ata_dev_configure(struct ata_device *dev)
}
if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128)
- dev->max_sectors = min(ATA_MAX_SECTORS_128, dev->max_sectors);
+ dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
+ dev->max_sectors);
/* limit ATAPI DMA to R/W commands only */
if (ata_device_blacklisted(dev) & ATA_HORKAGE_DMA_RW_ONLY)
dev->horkage |= ATA_HORKAGE_DMA_RW_ONLY;
if (ap->ops->dev_config)
- ap->ops->dev_config(ap, dev);
+ ap->ops->dev_config(dev);
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: EXIT, drv_stat = 0x%x\n",
@@ -1807,6 +2043,56 @@ err_out_nosup:
}
/**
+ * ata_cable_40wire - return 40 wire cable type
+ * @ap: port
+ *
+ * Helper method for drivers which want to hardwire 40 wire cable
+ * detection.
+ */
+
+int ata_cable_40wire(struct ata_port *ap)
+{
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * ata_cable_80wire - return 80 wire cable type
+ * @ap: port
+ *
+ * Helper method for drivers which want to hardwire 80 wire cable
+ * detection.
+ */
+
+int ata_cable_80wire(struct ata_port *ap)
+{
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * ata_cable_unknown - return unknown PATA cable.
+ * @ap: port
+ *
+ * Helper method for drivers which have no PATA cable detection.
+ */
+
+int ata_cable_unknown(struct ata_port *ap)
+{
+ return ATA_CBL_PATA_UNK;
+}
+
+/**
+ * ata_cable_sata - return SATA cable type
+ * @ap: port
+ *
+ * Helper method for drivers which have SATA cables
+ */
+
+int ata_cable_sata(struct ata_port *ap)
+{
+ return ATA_CBL_SATA;
+}
+
+/**
* ata_bus_probe - Reset and probe ATA bus
* @ap: Bus to probe
*
@@ -1876,6 +2162,10 @@ int ata_bus_probe(struct ata_port *ap)
goto fail;
}
+ /* Now ask for the cable type as PDIAG- should have been released */
+ if (ap->ops->cable_detect)
+ ap->cbl = ap->ops->cable_detect(ap);
+
/* After the identify sequence we can now set up the devices. We do
this in the normal order so that the user doesn't get confused */
@@ -1958,7 +2248,7 @@ void ata_port_probe(struct ata_port *ap)
* LOCKING:
* None.
*/
-static void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_port *ap)
{
u32 sstatus, scontrol, tmp;
@@ -2352,6 +2642,12 @@ int ata_timing_compute(struct ata_device *adev, unsigned short speed,
t->active += (t->cycle - (t->active + t->recover)) / 2;
t->recover = t->cycle - t->active;
}
+
+ /* In a few cases quantisation may produce enough errors to
+ leave t->cycle too low for the sum of active and recovery
+ if so we must correct this */
+ if (t->active + t->recover > t->cycle)
+ t->cycle = t->active + t->recover;
return 0;
}
@@ -2481,12 +2777,13 @@ static int ata_dev_set_mode(struct ata_device *dev)
}
/**
- * ata_set_mode - Program timings and issue SET FEATURES - XFER
+ * ata_do_set_mode - Program timings and issue SET FEATURES - XFER
* @ap: port on which timings will be programmed
* @r_failed_dev: out paramter for failed device
*
- * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
- * ata_set_mode() fails, pointer to the failing device is
+ * Standard implementation of the function used to tune and set
+ * ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+ * ata_dev_set_mode() fails, pointer to the failing device is
* returned in @r_failed_dev.
*
* LOCKING:
@@ -2495,14 +2792,12 @@ static int ata_dev_set_mode(struct ata_device *dev)
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+
+int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
{
struct ata_device *dev;
int i, rc = 0, used_dma = 0, found = 0;
- /* has private set_mode? */
- if (ap->ops->set_mode)
- return ap->ops->set_mode(ap, r_failed_dev);
/* step 1: calculate xfer_mask */
for (i = 0; i < ATA_MAX_DEVICES; i++) {
@@ -2587,6 +2882,29 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
}
/**
+ * ata_set_mode - Program timings and issue SET FEATURES - XFER
+ * @ap: port on which timings will be programmed
+ * @r_failed_dev: out paramter for failed device
+ *
+ * Set ATA device disk transfer mode (PIO3, UDMA6, etc.). If
+ * ata_set_mode() fails, pointer to the failing device is
+ * returned in @r_failed_dev.
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * 0 on success, negative errno otherwise
+ */
+int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ /* has private set_mode? */
+ if (ap->ops->set_mode)
+ return ap->ops->set_mode(ap, r_failed_dev);
+ return ata_do_set_mode(ap, r_failed_dev);
+}
+
+/**
* ata_tf_to_host - issue ATA taskfile to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
@@ -2661,23 +2979,71 @@ int ata_busy_sleep(struct ata_port *ap,
return 0;
}
-static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+/**
+ * ata_wait_ready - sleep until BSY clears, or timeout
+ * @ap: port containing status register to be polled
+ * @deadline: deadline jiffies for the operation
+ *
+ * Sleep until ATA Status register bit BSY clears, or timeout
+ * occurs.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_wait_ready(struct ata_port *ap, unsigned long deadline)
+{
+ unsigned long start = jiffies;
+ int warned = 0;
+
+ while (1) {
+ u8 status = ata_chk_status(ap);
+ unsigned long now = jiffies;
+
+ if (!(status & ATA_BUSY))
+ return 0;
+ if (status == 0xff)
+ return -ENODEV;
+ if (time_after(now, deadline))
+ return -EBUSY;
+
+ if (!warned && time_after(now, start + 5 * HZ) &&
+ (deadline - now > 3 * HZ)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "port is slow to respond, please be patient "
+ "(Status 0x%x)\n", status);
+ warned = 1;
+ }
+
+ msleep(50);
+ }
+}
+
+static int ata_bus_post_reset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
- unsigned long timeout;
+ int rc, ret = 0;
/* if device 0 was found in ata_devchk, wait for its
* BSY bit to clear
*/
- if (dev0)
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ if (dev0) {
+ rc = ata_wait_ready(ap, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
+ }
/* if device 1 was found in ata_devchk, wait for
* register access, then wait for BSY to clear
*/
- timeout = jiffies + ATA_TMOUT_BOOT;
while (dev1) {
u8 nsect, lbal;
@@ -2686,14 +3052,18 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
lbal = ioread8(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1))
break;
- if (time_after(jiffies, timeout)) {
- dev1 = 0;
- break;
- }
+ if (time_after(jiffies, deadline))
+ return -EBUSY;
msleep(50); /* give drive a breather */
}
- if (dev1)
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ if (dev1) {
+ rc = ata_wait_ready(ap, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
+ }
/* is all this really necessary? */
ap->ops->dev_select(ap, 0);
@@ -2701,10 +3071,12 @@ static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
ap->ops->dev_select(ap, 1);
if (dev0)
ap->ops->dev_select(ap, 0);
+
+ return ret;
}
-static unsigned int ata_bus_softreset(struct ata_port *ap,
- unsigned int devmask)
+static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
@@ -2734,11 +3106,9 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
* pulldown resistor.
*/
if (ata_check_status(ap) == 0xFF)
- return 0;
-
- ata_bus_post_reset(ap, devmask);
+ return -ENODEV;
- return 0;
+ return ata_bus_post_reset(ap, devmask, deadline);
}
/**
@@ -2767,6 +3137,7 @@ void ata_bus_reset(struct ata_port *ap)
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
u8 err;
unsigned int dev0, dev1 = 0, devmask = 0;
+ int rc;
DPRINTK("ENTER, host %u, port %u\n", ap->print_id, ap->port_no);
@@ -2788,9 +3159,11 @@ void ata_bus_reset(struct ata_port *ap)
ap->ops->dev_select(ap, 0);
/* issue bus reset */
- if (ap->flags & ATA_FLAG_SRST)
- if (ata_bus_softreset(ap, devmask))
+ if (ap->flags & ATA_FLAG_SRST) {
+ rc = ata_bus_softreset(ap, devmask, jiffies + 40 * HZ);
+ if (rc && rc != -ENODEV)
goto err_out;
+ }
/*
* determine by signature whether we have ATA or ATAPI devices
@@ -2832,29 +3205,37 @@ err_out:
* sata_phy_debounce - debounce SATA phy status
* @ap: ATA port to debounce SATA phy status for
* @params: timing parameters { interval, duratinon, timeout } in msec
+ * @deadline: deadline jiffies for the operation
*
* Make sure SStatus of @ap reaches stable state, determined by
* holding the same value where DET is not 1 for @duration polled
* every @interval, before @timeout. Timeout constraints the
- * beginning of the stable state. Because, after hot unplugging,
- * DET gets stuck at 1 on some controllers, this functions waits
+ * beginning of the stable state. Because DET gets stuck at 1 on
+ * some controllers after hot unplugging, this functions waits
* until timeout then returns 0 if DET is stable at 1.
*
+ * @timeout is further limited by @deadline. The sooner of the
+ * two is used.
+ *
* LOCKING:
* Kernel thread context (may sleep)
*
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
+int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
+ unsigned long deadline)
{
unsigned long interval_msec = params[0];
- unsigned long duration = params[1] * HZ / 1000;
- unsigned long timeout = jiffies + params[2] * HZ / 1000;
- unsigned long last_jiffies;
+ unsigned long duration = msecs_to_jiffies(params[1]);
+ unsigned long last_jiffies, t;
u32 last, cur;
int rc;
+ t = jiffies + msecs_to_jiffies(params[2]);
+ if (time_before(t, deadline))
+ deadline = t;
+
if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
return rc;
cur &= 0xf;
@@ -2870,7 +3251,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
/* DET stable? */
if (cur == last) {
- if (cur == 1 && time_before(jiffies, timeout))
+ if (cur == 1 && time_before(jiffies, deadline))
continue;
if (time_after(jiffies, last_jiffies + duration))
return 0;
@@ -2881,8 +3262,8 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
last = cur;
last_jiffies = jiffies;
- /* check timeout */
- if (time_after(jiffies, timeout))
+ /* check deadline */
+ if (time_after(jiffies, deadline))
return -EBUSY;
}
}
@@ -2891,6 +3272,7 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
* sata_phy_resume - resume SATA phy
* @ap: ATA port to resume SATA phy for
* @params: timing parameters { interval, duratinon, timeout } in msec
+ * @deadline: deadline jiffies for the operation
*
* Resume SATA phy of @ap and debounce it.
*
@@ -2900,7 +3282,8 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params)
* RETURNS:
* 0 on success, -errno on failure.
*/
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
+int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
+ unsigned long deadline)
{
u32 scontrol;
int rc;
@@ -2918,43 +3301,19 @@ int sata_phy_resume(struct ata_port *ap, const unsigned long *params)
*/
msleep(200);
- return sata_phy_debounce(ap, params);
-}
-
-static void ata_wait_spinup(struct ata_port *ap)
-{
- struct ata_eh_context *ehc = &ap->eh_context;
- unsigned long end, secs;
- int rc;
-
- /* first, debounce phy if SATA */
- if (ap->cbl == ATA_CBL_SATA) {
- rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
-
- /* if debounced successfully and offline, no need to wait */
- if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
- return;
- }
-
- /* okay, let's give the drive time to spin up */
- end = ehc->i.hotplug_timestamp + ATA_SPINUP_WAIT * HZ / 1000;
- secs = ((end - jiffies) + HZ - 1) / HZ;
-
- if (time_after(jiffies, end))
- return;
-
- if (secs > 5)
- ata_port_printk(ap, KERN_INFO, "waiting for device to spin up "
- "(%lu secs)\n", secs);
-
- schedule_timeout_uninterruptible(end - jiffies);
+ return sata_phy_debounce(ap, params, deadline);
}
/**
* ata_std_prereset - prepare for reset
* @ap: ATA port to be reset
+ * @deadline: deadline jiffies for the operation
*
- * @ap is about to be reset. Initialize it.
+ * @ap is about to be reset. Initialize it. Failure from
+ * prereset makes libata abort whole reset sequence and give up
+ * that port, so prereset should be best-effort. It does its
+ * best to prepare for reset sequence but if things go wrong, it
+ * should just whine, not fail.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -2962,41 +3321,41 @@ static void ata_wait_spinup(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_prereset(struct ata_port *ap)
+int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
{
struct ata_eh_context *ehc = &ap->eh_context;
const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
- /* handle link resume & hotplug spinup */
+ /* handle link resume */
if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
(ap->flags & ATA_FLAG_HRST_TO_RESUME))
ehc->i.action |= ATA_EH_HARDRESET;
- if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
- (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
- ata_wait_spinup(ap);
-
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
return 0;
/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
- rc = sata_phy_resume(ap, timing);
- if (rc && rc != -EOPNOTSUPP) {
- /* phy resume failed */
+ rc = sata_phy_resume(ap, timing, deadline);
+ /* whine about phy resume failure but proceed */
+ if (rc && rc != -EOPNOTSUPP)
ata_port_printk(ap, KERN_WARNING, "failed to resume "
"link for reset (errno=%d)\n", rc);
- return rc;
- }
}
/* Wait for !BSY if the controller can wait for the first D2H
* Reg FIS and we don't know that no device is attached.
*/
- if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap))
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+ rc = ata_wait_ready(ap, deadline);
+ if (rc) {
+ ata_port_printk(ap, KERN_WARNING, "device not ready "
+ "(errno=%d), forcing hardreset\n", rc);
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+ }
return 0;
}
@@ -3005,6 +3364,7 @@ int ata_std_prereset(struct ata_port *ap)
* ata_std_softreset - reset host port via ATA SRST
* @ap: port to reset
* @classes: resulting classes of attached devices
+ * @deadline: deadline jiffies for the operation
*
* Reset host port using ATA SRST.
*
@@ -3014,10 +3374,12 @@ int ata_std_prereset(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
+int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline)
{
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
- unsigned int devmask = 0, err_mask;
+ unsigned int devmask = 0;
+ int rc;
u8 err;
DPRINTK("ENTER\n");
@@ -3038,11 +3400,11 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
/* issue bus reset */
DPRINTK("about to softreset, devmask=%x\n", devmask);
- err_mask = ata_bus_softreset(ap, devmask);
- if (err_mask) {
- ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
- err_mask);
- return -EIO;
+ rc = ata_bus_softreset(ap, devmask, deadline);
+ /* if link is occupied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
+ ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+ return rc;
}
/* determine by signature whether we have ATA or ATAPI devices */
@@ -3059,6 +3421,7 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
* sata_port_hardreset - reset port via SATA phy reset
* @ap: port to reset
* @timing: timing parameters { interval, duratinon, timeout } in msec
+ * @deadline: deadline jiffies for the operation
*
* SATA phy-reset host port using DET bits of SControl register.
*
@@ -3068,7 +3431,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
+int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+ unsigned long deadline)
{
u32 scontrol;
int rc;
@@ -3107,7 +3471,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
msleep(1);
/* bring phy back */
- rc = sata_phy_resume(ap, timing);
+ rc = sata_phy_resume(ap, timing, deadline);
out:
DPRINTK("EXIT, rc=%d\n", rc);
return rc;
@@ -3117,6 +3481,7 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
* sata_std_hardreset - reset host port via SATA phy reset
* @ap: port to reset
* @class: resulting class of attached device
+ * @deadline: deadline jiffies for the operation
*
* SATA phy-reset host port using DET bits of SControl register,
* wait for !BSY and classify the attached device.
@@ -3127,7 +3492,8 @@ int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
+int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
int rc;
@@ -3135,7 +3501,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
DPRINTK("ENTER\n");
/* do hardreset */
- rc = sata_port_hardreset(ap, timing);
+ rc = sata_port_hardreset(ap, timing, deadline);
if (rc) {
ata_port_printk(ap, KERN_ERR,
"COMRESET failed (errno=%d)\n", rc);
@@ -3152,10 +3518,12 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
/* wait a while before checking status, see SRST for more info */
msleep(150);
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+ rc = ata_wait_ready(ap, deadline);
+ /* link occupied, -ENODEV too is an error */
+ if (rc) {
ata_port_printk(ap, KERN_ERR,
- "COMRESET failed (device not ready)\n");
- return -EIO;
+ "COMRESET failed (errno=%d)\n", rc);
+ return rc;
}
ap->ops->dev_select(ap, 0); /* probably unnecessary */
@@ -3267,6 +3635,11 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
"%llu != %llu\n",
(unsigned long long)dev->n_sectors,
(unsigned long long)new_n_sectors);
+ /* Are we the boot time size - if so we appear to be the
+ same disk at this point and our HPA got reapplied */
+ if (ata_ignore_hpa && dev->n_sectors_boot == new_n_sectors
+ && ata_id_hpa_enabled(new_id))
+ return 1;
return 0;
}
@@ -3441,19 +3814,7 @@ static void ata_dev_xfermask(struct ata_device *dev)
xfer_mask = ata_pack_xfermask(ap->pio_mask,
ap->mwdma_mask, ap->udma_mask);
- /* Apply cable rule here. Don't apply it early because when
- * we handle hot plug the cable type can itself change.
- */
- if (ap->cbl == ATA_CBL_PATA40)
- xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
- /* Apply drive side cable rule. Unknown or 80 pin cables reported
- * host side are checked drive side as well. Cases where we know a
- * 40wire cable is used safely for 80 are not checked here.
- */
- if (ata_drive_40wire(dev->id) && (ap->cbl == ATA_CBL_PATA_UNK || ap->cbl == ATA_CBL_PATA80))
- xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
-
-
+ /* drive modes available */
xfer_mask &= ata_pack_xfermask(dev->pio_mask,
dev->mwdma_mask, dev->udma_mask);
xfer_mask &= ata_id_xfermask(dev->id);
@@ -3482,8 +3843,30 @@ static void ata_dev_xfermask(struct ata_device *dev)
"other device, disabling DMA\n");
}
+ if (ap->flags & ATA_FLAG_NO_IORDY)
+ xfer_mask &= ata_pio_mask_no_iordy(dev);
+
if (ap->ops->mode_filter)
- xfer_mask = ap->ops->mode_filter(ap, dev, xfer_mask);
+ xfer_mask = ap->ops->mode_filter(dev, xfer_mask);
+
+ /* Apply cable rule here. Don't apply it early because when
+ * we handle hot plug the cable type can itself change.
+ * Check this last so that we know if the transfer rate was
+ * solely limited by the cable.
+ * Unknown or 80 wire cables reported host side are checked
+ * drive side as well. Cases where we know a 40wire cable
+ * is used safely for 80 are not checked here.
+ */
+ if (xfer_mask & (0xF8 << ATA_SHIFT_UDMA))
+ /* UDMA/44 or higher would be available */
+ if((ap->cbl == ATA_CBL_PATA40) ||
+ (ata_drive_40wire(dev->id) &&
+ (ap->cbl == ATA_CBL_PATA_UNK ||
+ ap->cbl == ATA_CBL_PATA80))) {
+ ata_dev_printk(dev, KERN_WARNING,
+ "limited to UDMA/33 due to 40-wire cable\n");
+ xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
+ }
ata_unpack_xfermask(xfer_mask, &dev->pio_mask,
&dev->mwdma_mask, &dev->udma_mask);
@@ -4022,10 +4405,10 @@ void ata_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
/**
- * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data.
+ * ata_pio_sector - Transfer a sector of data.
* @qc: Command on going
*
- * Transfer ATA_SECT_SIZE of data from/to the ATA device.
+ * Transfer qc->sect_size bytes of data from/to the ATA device.
*
* LOCKING:
* Inherited from caller.
@@ -4040,7 +4423,7 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
unsigned int offset;
unsigned char *buf;
- if (qc->curbytes == qc->nbytes - ATA_SECT_SIZE)
+ if (qc->curbytes == qc->nbytes - qc->sect_size)
ap->hsm_task_state = HSM_ST_LAST;
page = sg[qc->cursg].page;
@@ -4060,17 +4443,17 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
buf = kmap_atomic(page, KM_IRQ0);
/* do the actual data transfer */
- ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+ ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
kunmap_atomic(buf, KM_IRQ0);
local_irq_restore(flags);
} else {
buf = page_address(page);
- ap->ops->data_xfer(qc->dev, buf + offset, ATA_SECT_SIZE, do_write);
+ ap->ops->data_xfer(qc->dev, buf + offset, qc->sect_size, do_write);
}
- qc->curbytes += ATA_SECT_SIZE;
- qc->cursg_ofs += ATA_SECT_SIZE;
+ qc->curbytes += qc->sect_size;
+ qc->cursg_ofs += qc->sect_size;
if (qc->cursg_ofs == (&sg[qc->cursg])->length) {
qc->cursg++;
@@ -4079,10 +4462,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
}
/**
- * ata_pio_sectors - Transfer one or many 512-byte sectors.
+ * ata_pio_sectors - Transfer one or many sectors.
* @qc: Command on going
*
- * Transfer one or many ATA_SECT_SIZE of data from/to the
+ * Transfer one or many sectors of data from/to the
* ATA device for the DRQ request.
*
* LOCKING:
@@ -4097,7 +4480,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc)
WARN_ON(qc->dev->multi_count == 0);
- nsect = min((qc->nbytes - qc->curbytes) / ATA_SECT_SIZE,
+ nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size,
qc->dev->multi_count);
while (nsect--)
ata_pio_sector(qc);
@@ -5577,42 +5960,35 @@ void ata_dev_init(struct ata_device *dev)
}
/**
- * ata_port_init - Initialize an ata_port structure
- * @ap: Structure to initialize
- * @host: Collection of hosts to which @ap belongs
- * @ent: Probe information provided by low-level driver
- * @port_no: Port number associated with this ata_port
+ * ata_port_alloc - allocate and initialize basic ATA port resources
+ * @host: ATA host this allocated port belongs to
*
- * Initialize a new ata_port structure.
+ * Allocate and initialize basic ATA port resources.
+ *
+ * RETURNS:
+ * Allocate ATA port on success, NULL on failure.
*
* LOCKING:
- * Inherited from caller.
+ * Inherited from calling layer (may sleep).
*/
-void ata_port_init(struct ata_port *ap, struct ata_host *host,
- const struct ata_probe_ent *ent, unsigned int port_no)
+struct ata_port *ata_port_alloc(struct ata_host *host)
{
+ struct ata_port *ap;
unsigned int i;
+ DPRINTK("ENTER\n");
+
+ ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+ if (!ap)
+ return NULL;
+
ap->lock = &host->lock;
ap->flags = ATA_FLAG_DISABLED;
- ap->print_id = ata_print_id++;
+ ap->print_id = -1;
ap->ctl = ATA_DEVCTL_OBS;
ap->host = host;
- ap->dev = ent->dev;
- ap->port_no = port_no;
- if (port_no == 1 && ent->pinfo2) {
- ap->pio_mask = ent->pinfo2->pio_mask;
- ap->mwdma_mask = ent->pinfo2->mwdma_mask;
- ap->udma_mask = ent->pinfo2->udma_mask;
- ap->flags |= ent->pinfo2->flags;
- ap->ops = ent->pinfo2->port_ops;
- } else {
- ap->pio_mask = ent->pio_mask;
- ap->mwdma_mask = ent->mwdma_mask;
- ap->udma_mask = ent->udma_mask;
- ap->flags |= ent->port_flags;
- ap->ops = ent->port_ops;
- }
+ ap->dev = host->dev;
+
ap->hw_sata_spd_limit = UINT_MAX;
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
@@ -5632,10 +6008,7 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
- /* set cable type */
ap->cbl = ATA_CBL_NONE;
- if (ap->flags & ATA_FLAG_SATA)
- ap->cbl = ATA_CBL_SATA;
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
@@ -5648,100 +6021,209 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
ap->stats.unhandled_irq = 1;
ap->stats.idle_irq = 1;
#endif
+ return ap;
+}
+
+static void ata_host_release(struct device *gendev, void *res)
+{
+ struct ata_host *host = dev_get_drvdata(gendev);
+ int i;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
- memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+ if (!ap)
+ continue;
+
+ if ((host->flags & ATA_HOST_STARTED) && ap->ops->port_stop)
+ ap->ops->port_stop(ap);
+ }
+
+ if ((host->flags & ATA_HOST_STARTED) && host->ops->host_stop)
+ host->ops->host_stop(host);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ if (!ap)
+ continue;
+
+ if (ap->scsi_host)
+ scsi_host_put(ap->scsi_host);
+
+ kfree(ap);
+ host->ports[i] = NULL;
+ }
+
+ dev_set_drvdata(gendev, NULL);
}
/**
- * ata_port_init_shost - Initialize SCSI host associated with ATA port
- * @ap: ATA port to initialize SCSI host for
- * @shost: SCSI host associated with @ap
+ * ata_host_alloc - allocate and init basic ATA host resources
+ * @dev: generic device this host is associated with
+ * @max_ports: maximum number of ATA ports associated with this host
+ *
+ * Allocate and initialize basic ATA host resources. LLD calls
+ * this function to allocate a host, initializes it fully and
+ * attaches it using ata_host_register().
*
- * Initialize SCSI host @shost associated with ATA port @ap.
+ * @max_ports ports are allocated and host->n_ports is
+ * initialized to @max_ports. The caller is allowed to decrease
+ * host->n_ports before calling ata_host_register(). The unused
+ * ports will be automatically freed on registration.
+ *
+ * RETURNS:
+ * Allocate ATA host on success, NULL on failure.
*
* LOCKING:
- * Inherited from caller.
+ * Inherited from calling layer (may sleep).
*/
-static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
+struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
{
- ap->scsi_host = shost;
+ struct ata_host *host;
+ size_t sz;
+ int i;
+
+ DPRINTK("ENTER\n");
+
+ if (!devres_open_group(dev, NULL, GFP_KERNEL))
+ return NULL;
- shost->unique_id = ap->print_id;
- shost->max_id = 16;
- shost->max_lun = 1;
- shost->max_channel = 1;
- shost->max_cmd_len = 12;
+ /* alloc a container for our list of ATA ports (buses) */
+ sz = sizeof(struct ata_host) + (max_ports + 1) * sizeof(void *);
+ /* alloc a container for our list of ATA ports (buses) */
+ host = devres_alloc(ata_host_release, sz, GFP_KERNEL);
+ if (!host)
+ goto err_out;
+
+ devres_add(dev, host);
+ dev_set_drvdata(dev, host);
+
+ spin_lock_init(&host->lock);
+ host->dev = dev;
+ host->n_ports = max_ports;
+
+ /* allocate ports bound to this host */
+ for (i = 0; i < max_ports; i++) {
+ struct ata_port *ap;
+
+ ap = ata_port_alloc(host);
+ if (!ap)
+ goto err_out;
+
+ ap->port_no = i;
+ host->ports[i] = ap;
+ }
+
+ devres_remove_group(dev, NULL);
+ return host;
+
+ err_out:
+ devres_release_group(dev, NULL);
+ return NULL;
}
/**
- * ata_port_add - Attach low-level ATA driver to system
- * @ent: Information provided by low-level driver
- * @host: Collections of ports to which we add
- * @port_no: Port number associated with this host
- *
- * Attach low-level ATA driver to system.
+ * ata_host_alloc_pinfo - alloc host and init with port_info array
+ * @dev: generic device this host is associated with
+ * @ppi: array of ATA port_info to initialize host with
+ * @n_ports: number of ATA ports attached to this host
*
- * LOCKING:
- * PCI/etc. bus probe sem.
+ * Allocate ATA host and initialize with info from @ppi. If NULL
+ * terminated, @ppi may contain fewer entries than @n_ports. The
+ * last entry will be used for the remaining ports.
*
* RETURNS:
- * New ata_port on success, for NULL on error.
+ * Allocate ATA host on success, NULL on failure.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
*/
-static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
- struct ata_host *host,
- unsigned int port_no)
+struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+ const struct ata_port_info * const * ppi,
+ int n_ports)
{
- struct Scsi_Host *shost;
- struct ata_port *ap;
-
- DPRINTK("ENTER\n");
+ const struct ata_port_info *pi;
+ struct ata_host *host;
+ int i, j;
- if (!ent->port_ops->error_handler &&
- !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
- printk(KERN_ERR "ata%u: no reset mechanism available\n",
- port_no);
+ host = ata_host_alloc(dev, n_ports);
+ if (!host)
return NULL;
- }
- shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
- if (!shost)
- return NULL;
+ for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
- shost->transportt = &ata_scsi_transport_template;
+ if (ppi[j])
+ pi = ppi[j++];
- ap = ata_shost_to_port(shost);
+ ap->pio_mask = pi->pio_mask;
+ ap->mwdma_mask = pi->mwdma_mask;
+ ap->udma_mask = pi->udma_mask;
+ ap->flags |= pi->flags;
+ ap->ops = pi->port_ops;
- ata_port_init(ap, host, ent, port_no);
- ata_port_init_shost(ap, shost);
+ if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
+ host->ops = pi->port_ops;
+ if (!host->private_data && pi->private_data)
+ host->private_data = pi->private_data;
+ }
- return ap;
+ return host;
}
-static void ata_host_release(struct device *gendev, void *res)
+/**
+ * ata_host_start - start and freeze ports of an ATA host
+ * @host: ATA host to start ports for
+ *
+ * Start and then freeze ports of @host. Started status is
+ * recorded in host->flags, so this function can be called
+ * multiple times. Ports are guaranteed to get started only
+ * once. If host->ops isn't initialized yet, its set to the
+ * first non-dummy port ops.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 if all ports are started successfully, -errno otherwise.
+ */
+int ata_host_start(struct ata_host *host)
{
- struct ata_host *host = dev_get_drvdata(gendev);
- int i;
+ int i, rc;
+
+ if (host->flags & ATA_HOST_STARTED)
+ return 0;
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- if (ap && ap->ops->port_stop)
- ap->ops->port_stop(ap);
+ if (!host->ops && !ata_port_is_dummy(ap))
+ host->ops = ap->ops;
+
+ if (ap->ops->port_start) {
+ rc = ap->ops->port_start(ap);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "failed to "
+ "start port (errno=%d)\n", rc);
+ goto err_out;
+ }
+ }
+
+ ata_eh_freeze_port(ap);
}
- if (host->ops->host_stop)
- host->ops->host_stop(host);
+ host->flags |= ATA_HOST_STARTED;
+ return 0;
- for (i = 0; i < host->n_ports; i++) {
+ err_out:
+ while (--i >= 0) {
struct ata_port *ap = host->ports[i];
- if (ap)
- scsi_host_put(ap->scsi_host);
-
- host->ports[i] = NULL;
+ if (ap->ops->port_stop)
+ ap->ops->port_stop(ap);
}
-
- dev_set_drvdata(gendev, NULL);
+ return rc;
}
/**
@@ -5755,7 +6237,7 @@ static void ata_host_release(struct device *gendev, void *res)
* PCI/etc. bus probe sem.
*
*/
-
+/* KILLME - the only user left is ipr */
void ata_host_init(struct ata_host *host, struct device *dev,
unsigned long flags, const struct ata_port_operations *ops)
{
@@ -5766,155 +6248,95 @@ void ata_host_init(struct ata_host *host, struct device *dev,
}
/**
- * ata_device_add - Register hardware device with ATA and SCSI layers
- * @ent: Probe information describing hardware device to be registered
- *
- * This function processes the information provided in the probe
- * information struct @ent, allocates the necessary ATA and SCSI
- * host information structures, initializes them, and registers
- * everything with requisite kernel subsystems.
+ * ata_host_register - register initialized ATA host
+ * @host: ATA host to register
+ * @sht: template for SCSI host
*
- * This function requests irqs, probes the ATA bus, and probes
- * the SCSI bus.
+ * Register initialized ATA host. @host is allocated using
+ * ata_host_alloc() and fully initialized by LLD. This function
+ * starts ports, registers @host with ATA and SCSI layers and
+ * probe registered devices.
*
* LOCKING:
- * PCI/etc. bus probe sem.
+ * Inherited from calling layer (may sleep).
*
* RETURNS:
- * Number of ports registered. Zero on error (no ports registered).
+ * 0 on success, -errno otherwise.
*/
-int ata_device_add(const struct ata_probe_ent *ent)
+int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
{
- unsigned int i;
- struct device *dev = ent->dev;
- struct ata_host *host;
- int rc;
-
- DPRINTK("ENTER\n");
+ int i, rc;
- if (ent->irq == 0) {
- dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
- return 0;
+ /* host must have been started */
+ if (!(host->flags & ATA_HOST_STARTED)) {
+ dev_printk(KERN_ERR, host->dev,
+ "BUG: trying to register unstarted host\n");
+ WARN_ON(1);
+ return -EINVAL;
}
- if (!devres_open_group(dev, ata_device_add, GFP_KERNEL))
- return 0;
+ /* Blow away unused ports. This happens when LLD can't
+ * determine the exact number of ports to allocate at
+ * allocation time.
+ */
+ for (i = host->n_ports; host->ports[i]; i++)
+ kfree(host->ports[i]);
- /* alloc a container for our list of ATA ports (buses) */
- host = devres_alloc(ata_host_release, sizeof(struct ata_host) +
- (ent->n_ports * sizeof(void *)), GFP_KERNEL);
- if (!host)
- goto err_out;
- devres_add(dev, host);
- dev_set_drvdata(dev, host);
+ /* give ports names and add SCSI hosts */
+ for (i = 0; i < host->n_ports; i++)
+ host->ports[i]->print_id = ata_print_id++;
- ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
- host->n_ports = ent->n_ports;
- host->irq = ent->irq;
- host->irq2 = ent->irq2;
- host->iomap = ent->iomap;
- host->private_data = ent->private_data;
+ rc = ata_scsi_add_hosts(host, sht);
+ if (rc)
+ return rc;
- /* register each port bound to this device */
+ /* set cable, sata_spd_limit and report */
for (i = 0; i < host->n_ports; i++) {
- struct ata_port *ap;
- unsigned long xfer_mode_mask;
- int irq_line = ent->irq;
-
- ap = ata_port_add(ent, host, i);
- host->ports[i] = ap;
- if (!ap)
- goto err_out;
+ struct ata_port *ap = host->ports[i];
+ int irq_line;
+ u32 scontrol;
+ unsigned long xfer_mask;
- /* dummy? */
- if (ent->dummy_port_mask & (1 << i)) {
- ata_port_printk(ap, KERN_INFO, "DUMMY\n");
- ap->ops = &ata_dummy_port_ops;
- continue;
- }
+ /* set SATA cable type if still unset */
+ if (ap->cbl == ATA_CBL_NONE && (ap->flags & ATA_FLAG_SATA))
+ ap->cbl = ATA_CBL_SATA;
- /* start port */
- rc = ap->ops->port_start(ap);
- if (rc) {
- host->ports[i] = NULL;
- scsi_host_put(ap->scsi_host);
- goto err_out;
+ /* init sata_spd_limit to the current value */
+ if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
+ int spd = (scontrol >> 4) & 0xf;
+ ap->hw_sata_spd_limit &= (1 << spd) - 1;
}
+ ap->sata_spd_limit = ap->hw_sata_spd_limit;
- /* Report the secondary IRQ for second channel legacy */
- if (i == 1 && ent->irq2)
- irq_line = ent->irq2;
+ /* report the secondary IRQ for second channel legacy */
+ irq_line = host->irq;
+ if (i == 1 && host->irq2)
+ irq_line = host->irq2;
- xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
- (ap->mwdma_mask << ATA_SHIFT_MWDMA) |
- (ap->pio_mask << ATA_SHIFT_PIO);
+ xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
+ ap->udma_mask);
/* print per-port info to dmesg */
- ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
- "ctl 0x%p bmdma 0x%p irq %d\n",
- ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
- ata_mode_string(xfer_mode_mask),
- ap->ioaddr.cmd_addr,
- ap->ioaddr.ctl_addr,
- ap->ioaddr.bmdma_addr,
- irq_line);
-
- /* freeze port before requesting IRQ */
- ata_eh_freeze_port(ap);
- }
-
- /* obtain irq, that may be shared between channels */
- rc = devm_request_irq(dev, ent->irq, ent->port_ops->irq_handler,
- ent->irq_flags, DRV_NAME, host);
- if (rc) {
- dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
- ent->irq, rc);
- goto err_out;
- }
-
- /* do we have a second IRQ for the other channel, eg legacy mode */
- if (ent->irq2) {
- /* We will get weird core code crashes later if this is true
- so trap it now */
- BUG_ON(ent->irq == ent->irq2);
-
- rc = devm_request_irq(dev, ent->irq2,
- ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host);
- if (rc) {
- dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
- ent->irq2, rc);
- goto err_out;
- }
+ if (!ata_port_is_dummy(ap))
+ ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
+ "ctl 0x%p bmdma 0x%p irq %d\n",
+ ap->cbl == ATA_CBL_SATA ? 'S' : 'P',
+ ata_mode_string(xfer_mask),
+ ap->ioaddr.cmd_addr,
+ ap->ioaddr.ctl_addr,
+ ap->ioaddr.bmdma_addr,
+ irq_line);
+ else
+ ata_port_printk(ap, KERN_INFO, "DUMMY\n");
}
- /* resource acquisition complete */
- devres_remove_group(dev, ata_device_add);
-
/* perform each probe synchronously */
DPRINTK("probe begin\n");
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- u32 scontrol;
int rc;
- /* init sata_spd_limit to the current value */
- if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
- int spd = (scontrol >> 4) & 0xf;
- ap->hw_sata_spd_limit &= (1 << spd) - 1;
- }
- ap->sata_spd_limit = ap->hw_sata_spd_limit;
-
- rc = scsi_add_host(ap->scsi_host, dev);
- if (rc) {
- ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
- /* FIXME: do something useful here */
- /* FIXME: handle unconditional calls to
- * scsi_scan_host and ata_host_remove, below,
- * at the very least
- */
- }
-
+ /* probe */
if (ap->ops->error_handler) {
struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
@@ -5959,16 +6381,52 @@ int ata_device_add(const struct ata_probe_ent *ent)
ata_scsi_scan_host(ap);
}
- VPRINTK("EXIT, returning %u\n", ent->n_ports);
- return ent->n_ports; /* success */
-
- err_out:
- devres_release_group(dev, ata_device_add);
- VPRINTK("EXIT, returning %d\n", rc);
return 0;
}
/**
+ * ata_host_activate - start host, request IRQ and register it
+ * @host: target ATA host
+ * @irq: IRQ to request
+ * @irq_handler: irq_handler used when requesting IRQ
+ * @irq_flags: irq_flags used when requesting IRQ
+ * @sht: scsi_host_template to use when registering the host
+ *
+ * After allocating an ATA host and initializing it, most libata
+ * LLDs perform three steps to activate the host - start host,
+ * request IRQ and register it. This helper takes necessasry
+ * arguments and performs the three steps in one go.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_host_activate(struct ata_host *host, int irq,
+ irq_handler_t irq_handler, unsigned long irq_flags,
+ struct scsi_host_template *sht)
+{
+ int rc;
+
+ rc = ata_host_start(host);
+ if (rc)
+ return rc;
+
+ rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
+ dev_driver_string(host->dev), host);
+ if (rc)
+ return rc;
+
+ rc = ata_host_register(host, sht);
+ /* if failed, just free the IRQ and leave ports alone */
+ if (rc)
+ devm_free_irq(host->dev, irq, host);
+
+ return rc;
+}
+
+/**
* ata_port_detach - Detach ATA port in prepration of device removal
* @ap: ATA port to be detached
*
@@ -6017,9 +6475,9 @@ void ata_port_detach(struct ata_port *ap)
/* Flush hotplug task. The sequence is similar to
* ata_port_flush_task().
*/
- flush_workqueue(ata_aux_wq);
+ cancel_work_sync(&ap->hotplug_task.work); /* akpm: why? */
cancel_delayed_work(&ap->hotplug_task);
- flush_workqueue(ata_aux_wq);
+ cancel_work_sync(&ap->hotplug_task.work);
skip_eh:
/* remove the associated SCSI host */
@@ -6043,32 +6501,6 @@ void ata_host_detach(struct ata_host *host)
ata_port_detach(host->ports[i]);
}
-struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
- struct ata_probe_ent *probe_ent;
-
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent) {
- printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
- kobject_name(&(dev->kobj)));
- return NULL;
- }
-
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = dev;
-
- probe_ent->sht = port->sht;
- probe_ent->port_flags = port->flags;
- probe_ent->pio_mask = port->pio_mask;
- probe_ent->mwdma_mask = port->mwdma_mask;
- probe_ent->udma_mask = port->udma_mask;
- probe_ent->port_ops = port->port_ops;
- probe_ent->private_data = port->private_data;
-
- return probe_ent;
-}
-
/**
* ata_std_ports - initialize ioaddr with standard port offsets.
* @ioaddr: IO address structure to be initialized
@@ -6334,6 +6766,10 @@ const struct ata_port_operations ata_dummy_port_ops = {
.port_stop = ata_dummy_noret,
};
+const struct ata_port_info ata_dummy_port_info = {
+ .port_ops = &ata_dummy_port_ops,
+};
+
/*
* libata is essentially a library of internal helper functions for
* low-level ATA host controller drivers. As such, the API/ABI is
@@ -6345,10 +6781,15 @@ EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
EXPORT_SYMBOL_GPL(sata_deb_timing_long);
EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
+EXPORT_SYMBOL_GPL(ata_dummy_port_info);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
EXPORT_SYMBOL_GPL(ata_host_init);
-EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_host_alloc);
+EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
+EXPORT_SYMBOL_GPL(ata_host_start);
+EXPORT_SYMBOL_GPL(ata_host_register);
+EXPORT_SYMBOL_GPL(ata_host_activate);
EXPORT_SYMBOL_GPL(ata_host_detach);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
@@ -6360,6 +6801,7 @@ EXPORT_SYMBOL_GPL(ata_tf_load);
EXPORT_SYMBOL_GPL(ata_tf_read);
EXPORT_SYMBOL_GPL(ata_noop_dev_select);
EXPORT_SYMBOL_GPL(ata_std_dev_select);
+EXPORT_SYMBOL_GPL(sata_print_link_status);
EXPORT_SYMBOL_GPL(ata_tf_to_fis);
EXPORT_SYMBOL_GPL(ata_tf_from_fis);
EXPORT_SYMBOL_GPL(ata_check_status);
@@ -6367,6 +6809,7 @@ EXPORT_SYMBOL_GPL(ata_altstatus);
EXPORT_SYMBOL_GPL(ata_exec_command);
EXPORT_SYMBOL_GPL(ata_port_start);
EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_do_set_mode);
EXPORT_SYMBOL_GPL(ata_data_xfer);
EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
EXPORT_SYMBOL_GPL(ata_qc_prep);
@@ -6400,6 +6843,7 @@ EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_wait_register);
EXPORT_SYMBOL_GPL(ata_busy_sleep);
+EXPORT_SYMBOL_GPL(ata_wait_ready);
EXPORT_SYMBOL_GPL(ata_port_queue_task);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
@@ -6429,7 +6873,8 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
#ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
+EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
#ifdef CONFIG_PM
@@ -6461,3 +6906,8 @@ EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
EXPORT_SYMBOL_GPL(ata_irq_ack);
EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
EXPORT_SYMBOL_GPL(ata_dev_try_classify);
+
+EXPORT_SYMBOL_GPL(ata_cable_40wire);
+EXPORT_SYMBOL_GPL(ata_cable_80wire);
+EXPORT_SYMBOL_GPL(ata_cable_unknown);
+EXPORT_SYMBOL_GPL(ata_cable_sata);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 39f556c0299..8256655ce7d 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -50,6 +50,28 @@ enum {
ATA_EH_SPDN_FALLBACK_TO_PIO = (1 << 2),
};
+/* Waiting in ->prereset can never be reliable. It's sometimes nice
+ * to wait there but it can't be depended upon; otherwise, we wouldn't
+ * be resetting. Just give it enough time for most drives to spin up.
+ */
+enum {
+ ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
+};
+
+/* The following table determines how we sequence resets. Each entry
+ * represents timeout for that try. The first try can be soft or
+ * hardreset. All others are hardreset if available. In most cases
+ * the first reset w/ 10sec timeout should succeed. Following entries
+ * are mostly for error handling, hotplug and retarded devices.
+ */
+static const unsigned long ata_eh_reset_timeouts[] = {
+ 10 * HZ, /* most drives spin up by 10sec */
+ 10 * HZ, /* > 99% working drives spin up before 20sec */
+ 35 * HZ, /* give > 30 secs of idleness for retarded devices */
+ 5 * HZ, /* and sweet one last chance */
+ /* > 1 min has elapsed, give up */
+};
+
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
#ifdef CONFIG_PM
@@ -1056,7 +1078,7 @@ static void ata_eh_analyze_serror(struct ata_port *ap)
}
if (serror & SERR_INTERNAL) {
err_mask |= AC_ERR_SYSTEM;
- action |= ATA_EH_SOFTRESET;
+ action |= ATA_EH_HARDRESET;
}
if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
ata_ehi_hotplugged(&ehc->i);
@@ -1151,7 +1173,9 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
return ATA_EH_SOFTRESET;
}
- if (!(qc->err_mask & AC_ERR_DEV))
+ if (stat & (ATA_ERR | ATA_DF))
+ qc->err_mask |= AC_ERR_DEV;
+ else
return 0;
switch (qc->dev->class) {
@@ -1556,14 +1580,14 @@ static void ata_eh_report(struct ata_port *ap)
}
static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
- unsigned int *classes)
+ unsigned int *classes, unsigned long deadline)
{
int i, rc;
for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_UNKNOWN;
- rc = reset(ap, classes);
+ rc = reset(ap, classes, deadline);
if (rc)
return rc;
@@ -1601,8 +1625,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
{
struct ata_eh_context *ehc = &ap->eh_context;
unsigned int *classes = ehc->classes;
- int tries = ATA_EH_RESET_TRIES;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
+ int try = 0;
+ unsigned long deadline;
unsigned int action;
ata_reset_fn_t reset;
int i, did_followup_srst, rc;
@@ -1622,7 +1647,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ehc->i.action |= ATA_EH_HARDRESET;
if (prereset) {
- rc = prereset(ap);
+ rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
if (rc) {
if (rc == -ENOENT) {
ata_port_printk(ap, KERN_DEBUG,
@@ -1663,15 +1688,20 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
}
retry:
+ deadline = jiffies + ata_eh_reset_timeouts[try++];
+
/* shut up during boot probing */
if (verbose)
ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
reset == softreset ? "soft" : "hard");
/* mark that this EH session started with reset */
- ehc->i.flags |= ATA_EHI_DID_RESET;
+ if (reset == hardreset)
+ ehc->i.flags |= ATA_EHI_DID_HARDRESET;
+ else
+ ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
- rc = ata_do_reset(ap, reset, classes);
+ rc = ata_do_reset(ap, reset, classes, deadline);
did_followup_srst = 0;
if (reset == hardreset &&
@@ -1688,7 +1718,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
}
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
- rc = ata_do_reset(ap, reset, classes);
+ rc = ata_do_reset(ap, reset, classes, deadline);
if (rc == 0 && classify &&
classes[0] == ATA_DEV_UNKNOWN) {
@@ -1698,22 +1728,21 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
}
}
- if (rc && --tries) {
- const char *type;
+ if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+ unsigned long now = jiffies;
- if (reset == softreset) {
- if (did_followup_srst)
- type = "follow-up soft";
- else
- type = "soft";
- } else
- type = "hard";
+ if (time_before(now, deadline)) {
+ unsigned long delta = deadline - jiffies;
- ata_port_printk(ap, KERN_WARNING,
- "%sreset failed, retrying in 5 secs\n", type);
- ssleep(5);
+ ata_port_printk(ap, KERN_WARNING, "reset failed "
+ "(errno=%d), retrying in %u secs\n",
+ rc, (jiffies_to_msecs(delta) + 999) / 1000);
+
+ schedule_timeout_uninterruptible(delta);
+ }
- if (reset == hardreset)
+ if (reset == hardreset &&
+ try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
sata_down_spd_limit(ap);
if (hardreset)
reset = hardreset;
@@ -1808,6 +1837,10 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
}
+ /* PDIAG- should have been released, ask cable type if post-reset */
+ if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+ ap->cbl = ap->ops->cable_detect(ap);
+
/* Configure new devices forward such that user doesn't see
* device detection messages backwards.
*/
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e9364434182..9afba2ba489 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -104,7 +104,7 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
* libata transport template. libata doesn't do real transport stuff.
* It just needs the eh_timed_out hook.
*/
-struct scsi_transport_template ata_scsi_transport_template = {
+static struct scsi_transport_template ata_scsi_transport_template = {
.eh_strategy_handler = ata_scsi_error,
.eh_timed_out = ata_scsi_timed_out,
.user_scan = ata_scsi_user_scan,
@@ -2678,6 +2678,18 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->device = qc->dev->devno ?
tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
+ /* READ/WRITE LONG use a non-standard sect_size */
+ qc->sect_size = ATA_SECT_SIZE;
+ switch (tf->command) {
+ case ATA_CMD_READ_LONG:
+ case ATA_CMD_READ_LONG_ONCE:
+ case ATA_CMD_WRITE_LONG:
+ case ATA_CMD_WRITE_LONG_ONCE:
+ if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
+ goto invalid_fld;
+ qc->sect_size = scmd->request_bufflen;
+ }
+
/*
* Filter SET_FEATURES - XFER MODE command -- otherwise,
* SET_FEATURES - XFER MODE must be preceded/succeeded
@@ -2792,8 +2804,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
{
int rc = 0;
- if (unlikely(!scmd->cmd_len)) {
- ata_dev_printk(dev, KERN_WARNING, "WARNING: zero len CDB\n");
+ if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
+ DPRINTK("bad CDB len=%u, max=%u\n",
+ scmd->cmd_len, dev->cdb_len);
scmd->result = DID_ERROR << 16;
done(scmd);
return 0;
@@ -2948,6 +2961,48 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
}
}
+int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
+{
+ int i, rc;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct Scsi_Host *shost;
+
+ rc = -ENOMEM;
+ shost = scsi_host_alloc(sht, sizeof(struct ata_port *));
+ if (!shost)
+ goto err_alloc;
+
+ *(struct ata_port **)&shost->hostdata[0] = ap;
+ ap->scsi_host = shost;
+
+ shost->transportt = &ata_scsi_transport_template;
+ shost->unique_id = ap->print_id;
+ shost->max_id = 16;
+ shost->max_lun = 1;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 16;
+
+ rc = scsi_add_host(ap->scsi_host, ap->host->dev);
+ if (rc)
+ goto err_add;
+ }
+
+ return 0;
+
+ err_add:
+ scsi_host_put(host->ports[i]->scsi_host);
+ err_alloc:
+ while (--i >= 0) {
+ struct Scsi_Host *shost = host->ports[i]->scsi_host;
+
+ scsi_remove_host(shost);
+ scsi_host_put(shost);
+ }
+ return rc;
+}
+
void ata_scsi_scan_host(struct ata_port *ap)
{
unsigned int i;
@@ -3224,21 +3279,21 @@ struct ata_port *ata_sas_port_alloc(struct ata_host *host,
struct ata_port_info *port_info,
struct Scsi_Host *shost)
{
- struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
- struct ata_probe_ent *ent;
+ struct ata_port *ap;
+ ap = ata_port_alloc(host);
if (!ap)
return NULL;
- ent = ata_probe_ent_alloc(host->dev, port_info);
- if (!ent) {
- kfree(ap);
- return NULL;
- }
-
- ata_port_init(ap, host, ent, 0);
+ ap->port_no = 0;
ap->lock = shost->host_lock;
- devm_kfree(host->dev, ent);
+ ap->pio_mask = port_info->pio_mask;
+ ap->mwdma_mask = port_info->mwdma_mask;
+ ap->udma_mask = port_info->udma_mask;
+ ap->flags |= port_info->flags;
+ ap->ops = port_info->port_ops;
+ ap->cbl = ATA_CBL_SATA;
+
return ap;
}
EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
@@ -3294,8 +3349,10 @@ int ata_sas_port_init(struct ata_port *ap)
{
int rc = ap->ops->port_start(ap);
- if (!rc)
+ if (!rc) {
+ ap->print_id = ata_print_id++;
rc = ata_bus_probe(ap);
+ }
return rc;
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2ffcca063d8..d211db6b35a 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -526,168 +526,399 @@ static int ata_resources_present(struct pci_dev *pdev, int port)
port = port * 2;
for (i = 0; i < 2; i ++) {
if (pci_resource_start(pdev, port + i) == 0 ||
- pci_resource_len(pdev, port + i) == 0)
- return 0;
+ pci_resource_len(pdev, port + i) == 0)
+ return 0;
}
return 1;
}
/**
- * ata_pci_init_native_mode - Initialize native-mode driver
- * @pdev: pci device to be initialized
- * @port: array[2] of pointers to port info structures.
- * @ports: bitmap of ports present
- *
- * Utility function which allocates and initializes an
- * ata_probe_ent structure for a standard dual-port
- * PIO-based IDE controller. The returned ata_probe_ent
- * structure can be passed to ata_device_add(). The returned
- * ata_probe_ent structure should then be freed with kfree().
- *
- * The caller need only pass the address of the primary port, the
- * secondary will be deduced automatically. If the device has non
- * standard secondary port mappings this function can be called twice,
- * once for each interface.
+ * ata_pci_init_bmdma - acquire PCI BMDMA resources and init ATA host
+ * @host: target ATA host
+ *
+ * Acquire PCI BMDMA resources and initialize @host accordingly.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
*/
+static int ata_pci_init_bmdma(struct ata_host *host)
+{
+ struct device *gdev = host->dev;
+ struct pci_dev *pdev = to_pci_dev(gdev);
+ int i, rc;
+
+ /* TODO: If we get no DMA mask we should fall back to PIO */
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ /* request and iomap DMA region */
+ rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+ if (rc) {
+ dev_printk(KERN_ERR, gdev, "failed to request/iomap BAR4\n");
+ return -ENOMEM;
+ }
+ host->iomap = pcim_iomap_table(pdev);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ void __iomem *bmdma = host->iomap[4] + 8 * i;
+
+ if (ata_port_is_dummy(ap))
+ continue;
+
+ ap->ioaddr.bmdma_addr = bmdma;
+ if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
+ (ioread8(bmdma + 2) & 0x80))
+ host->flags |= ATA_HOST_SIMPLEX;
+ }
+
+ return 0;
+}
-struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
+/**
+ * ata_pci_init_native_host - acquire native ATA resources and init host
+ * @host: target ATA host
+ * @port_mask: ports to consider
+ *
+ * Acquire native PCI ATA resources for @host and initialize
+ * @host accordoingly.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_pci_init_native_host(struct ata_host *host, unsigned int port_mask)
{
- struct ata_probe_ent *probe_ent;
- int i, p = 0;
- void __iomem * const *iomap;
-
- /* iomap BARs */
- for (i = 0; i < 4; i++) {
- if (pcim_iomap(pdev, i, 0) == NULL) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to iomap PCI BAR %d\n", i);
- return NULL;
+ struct device *gdev = host->dev;
+ struct pci_dev *pdev = to_pci_dev(gdev);
+ int i, rc;
+
+ /* Discard disabled ports. Some controllers show their unused
+ * channels this way. Disabled ports are made dummy.
+ */
+ for (i = 0; i < 2; i++) {
+ if ((port_mask & (1 << i)) && !ata_resources_present(pdev, i)) {
+ host->ports[i]->ops = &ata_dummy_port_ops;
+ port_mask &= ~(1 << i);
}
}
- pcim_iomap(pdev, 4, 0); /* may fail */
- iomap = pcim_iomap_table(pdev);
-
- /* alloc and init probe_ent */
- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- if (!probe_ent)
- return NULL;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
-
- /* Discard disabled ports. Some controllers show their
- unused channels this way */
- if (ata_resources_present(pdev, 0) == 0)
- ports &= ~ATA_PORT_PRIMARY;
- if (ata_resources_present(pdev, 1) == 0)
- ports &= ~ATA_PORT_SECONDARY;
-
- if (ports & ATA_PORT_PRIMARY) {
- probe_ent->port[p].cmd_addr = iomap[0];
- probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr = (void __iomem *)
- ((unsigned long)iomap[1] | ATA_PCI_CTL_OFS);
- if (iomap[4]) {
- if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (ioread8(iomap[4] + 2) & 0x80))
- probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = iomap[4];
- }
- ata_std_ports(&probe_ent->port[p]);
- p++;
+ if (!port_mask) {
+ dev_printk(KERN_ERR, gdev, "no available port\n");
+ return -ENODEV;
}
- if (ports & ATA_PORT_SECONDARY) {
- probe_ent->port[p].cmd_addr = iomap[2];
- probe_ent->port[p].altstatus_addr =
- probe_ent->port[p].ctl_addr = (void __iomem *)
- ((unsigned long)iomap[3] | ATA_PCI_CTL_OFS);
- if (iomap[4]) {
- if ((!(port[p]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (ioread8(iomap[4] + 10) & 0x80))
- probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- probe_ent->port[p].bmdma_addr = iomap[4] + 8;
+ /* request, iomap BARs and init port addresses accordingly */
+ for (i = 0; i < 2; i++) {
+ struct ata_port *ap = host->ports[i];
+ int base = i * 2;
+ void __iomem * const *iomap;
+
+ if (!(port_mask & (1 << i)))
+ continue;
+
+ rc = pcim_iomap_regions(pdev, 0x3 << base, DRV_NAME);
+ if (rc) {
+ dev_printk(KERN_ERR, gdev, "failed to request/iomap "
+ "BARs for port %d (errno=%d)\n", i, rc);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ return rc;
}
- ata_std_ports(&probe_ent->port[p]);
- probe_ent->pinfo2 = port[1];
- p++;
+ host->iomap = iomap = pcim_iomap_table(pdev);
+
+ ap->ioaddr.cmd_addr = iomap[base];
+ ap->ioaddr.altstatus_addr =
+ ap->ioaddr.ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
+ ata_std_ports(&ap->ioaddr);
}
- probe_ent->n_ports = p;
- return probe_ent;
+ return 0;
}
-static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
- struct ata_port_info **port, int port_mask)
+/**
+ * ata_pci_prepare_native_host - helper to prepare native PCI ATA host
+ * @pdev: target PCI device
+ * @ppi: array of port_info
+ * @n_ports: number of ports to allocate
+ * @r_host: out argument for the initialized ATA host
+ *
+ * Helper to allocate ATA host for @pdev, acquire all native PCI
+ * resources and initialize it accordingly in one go.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_pci_prepare_native_host(struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi,
+ int n_ports, struct ata_host **r_host)
+{
+ struct ata_host *host;
+ unsigned int port_mask;
+ int rc;
+
+ if (!devres_open_group(&pdev->dev, NULL, GFP_KERNEL))
+ return -ENOMEM;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to allocate ATA host\n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ port_mask = ATA_PORT_PRIMARY;
+ if (n_ports > 1)
+ port_mask |= ATA_PORT_SECONDARY;
+
+ rc = ata_pci_init_native_host(host, port_mask);
+ if (rc)
+ goto err_out;
+
+ /* init DMA related stuff */
+ rc = ata_pci_init_bmdma(host);
+ if (rc)
+ goto err_bmdma;
+
+ devres_remove_group(&pdev->dev, NULL);
+ *r_host = host;
+ return 0;
+
+ err_bmdma:
+ /* This is necessary because PCI and iomap resources are
+ * merged and releasing the top group won't release the
+ * acquired resources if some of those have been acquired
+ * before entering this function.
+ */
+ pcim_iounmap_regions(pdev, 0xf);
+ err_out:
+ devres_release_group(&pdev->dev, NULL);
+ return rc;
+}
+
+struct ata_legacy_devres {
+ unsigned int mask;
+ unsigned long cmd_port[2];
+ void __iomem * cmd_addr[2];
+ void __iomem * ctl_addr[2];
+ unsigned int irq[2];
+ void * irq_dev_id[2];
+};
+
+static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
{
- struct ata_probe_ent *probe_ent;
- void __iomem *iomap[5] = { }, *bmdma;
-
- if (port_mask & ATA_PORT_PRIMARY) {
- iomap[0] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CMD, 8);
- iomap[1] = devm_ioport_map(&pdev->dev, ATA_PRIMARY_CTL, 1);
- if (!iomap[0] || !iomap[1])
- return NULL;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (!legacy_dr->irq[i])
+ continue;
+
+ free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
+ legacy_dr->irq[i] = 0;
+ legacy_dr->irq_dev_id[i] = NULL;
}
+}
+
+static void ata_legacy_release(struct device *gdev, void *res)
+{
+ struct ata_legacy_devres *this = res;
+ int i;
- if (port_mask & ATA_PORT_SECONDARY) {
- iomap[2] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CMD, 8);
- iomap[3] = devm_ioport_map(&pdev->dev, ATA_SECONDARY_CTL, 1);
- if (!iomap[2] || !iomap[3])
- return NULL;
+ ata_legacy_free_irqs(this);
+
+ for (i = 0; i < 2; i++) {
+ if (this->cmd_addr[i])
+ ioport_unmap(this->cmd_addr[i]);
+ if (this->ctl_addr[i])
+ ioport_unmap(this->ctl_addr[i]);
+ if (this->cmd_port[i])
+ release_region(this->cmd_port[i], 8);
}
+}
- bmdma = pcim_iomap(pdev, 4, 16); /* may fail */
-
- /* alloc and init probe_ent */
- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
- if (!probe_ent)
- return NULL;
-
- probe_ent->n_ports = 2;
- probe_ent->irq_flags = IRQF_SHARED;
-
- if (port_mask & ATA_PORT_PRIMARY) {
- probe_ent->irq = ATA_PRIMARY_IRQ(pdev);
- probe_ent->port[0].cmd_addr = iomap[0];
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = iomap[1];
- if (bmdma) {
- probe_ent->port[0].bmdma_addr = bmdma;
- if ((!(port[0]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (ioread8(bmdma + 2) & 0x80))
- probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
- }
- ata_std_ports(&probe_ent->port[0]);
- } else
- probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
+static int ata_init_legacy_port(struct ata_port *ap,
+ struct ata_legacy_devres *legacy_dr)
+{
+ struct ata_host *host = ap->host;
+ int port_no = ap->port_no;
+ unsigned long cmd_port, ctl_port;
+
+ if (port_no == 0) {
+ cmd_port = ATA_PRIMARY_CMD;
+ ctl_port = ATA_PRIMARY_CTL;
+ } else {
+ cmd_port = ATA_SECONDARY_CMD;
+ ctl_port = ATA_SECONDARY_CTL;
+ }
+
+ /* request cmd_port */
+ if (request_region(cmd_port, 8, "libata"))
+ legacy_dr->cmd_port[port_no] = cmd_port;
+ else {
+ dev_printk(KERN_WARNING, host->dev,
+ "0x%0lX IDE port busy\n", cmd_port);
+ return -EBUSY;
+ }
+
+ /* iomap cmd and ctl ports */
+ legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
+ legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
+ if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no])
+ return -ENOMEM;
+
+ /* init IO addresses */
+ ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
+ ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
+ ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
+ ata_std_ports(&ap->ioaddr);
+
+ return 0;
+}
+
+/**
+ * ata_init_legacy_host - acquire legacy ATA resources and init ATA host
+ * @host: target ATA host
+ * @legacy_mask: out parameter, mask indicating ports is in legacy mode
+ * @was_busy: out parameter, indicates whether any port was busy
+ *
+ * Acquire legacy ATA resources for ports.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int ata_init_legacy_host(struct ata_host *host,
+ unsigned int *legacy_mask, int *was_busy)
+{
+ struct device *gdev = host->dev;
+ struct ata_legacy_devres *legacy_dr;
+ int i, rc;
+
+ if (!devres_open_group(gdev, NULL, GFP_KERNEL))
+ return -ENOMEM;
+
+ rc = -ENOMEM;
+ legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
+ GFP_KERNEL);
+ if (!legacy_dr)
+ goto err_out;
+ devres_add(gdev, legacy_dr);
+
+ for (i = 0; i < 2; i++) {
+ *legacy_mask &= ~(1 << i);
+ rc = ata_init_legacy_port(host->ports[i], legacy_dr);
+ if (rc == 0)
+ legacy_dr->mask |= 1 << i;
+ else if (rc == -EBUSY)
+ (*was_busy)++;
+ }
+
+ if (!legacy_dr->mask)
+ return -EBUSY;
+
+ for (i = 0; i < 2; i++)
+ if (!(legacy_dr->mask & (1 << i)))
+ host->ports[i]->ops = &ata_dummy_port_ops;
+
+ *legacy_mask |= legacy_dr->mask;
- if (port_mask & ATA_PORT_SECONDARY) {
- if (probe_ent->irq)
- probe_ent->irq2 = ATA_SECONDARY_IRQ(pdev);
+ devres_remove_group(gdev, NULL);
+ return 0;
+
+ err_out:
+ devres_release_group(gdev, NULL);
+ return rc;
+}
+
+/**
+ * ata_request_legacy_irqs - request legacy ATA IRQs
+ * @host: target ATA host
+ * @handler: array of IRQ handlers
+ * @irq_flags: array of IRQ flags
+ * @dev_id: array of IRQ dev_ids
+ *
+ * Request legacy IRQs for non-dummy legacy ports in @host. All
+ * IRQ parameters are passed as array to allow ports to have
+ * separate IRQ handlers.
+ *
+ * LOCKING:
+ * Inherited from calling layer (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int ata_request_legacy_irqs(struct ata_host *host,
+ irq_handler_t const *handler,
+ const unsigned int *irq_flags,
+ void * const *dev_id)
+{
+ struct device *gdev = host->dev;
+ struct ata_legacy_devres *legacy_dr;
+ int i, rc;
+
+ legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
+ BUG_ON(!legacy_dr);
+
+ for (i = 0; i < host->n_ports; i++) {
+ unsigned int irq;
+
+ /* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
+ if (i == 0)
+ irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
else
- probe_ent->irq = ATA_SECONDARY_IRQ(pdev);
- probe_ent->port[1].cmd_addr = iomap[2];
- probe_ent->port[1].altstatus_addr =
- probe_ent->port[1].ctl_addr = iomap[3];
- if (bmdma) {
- probe_ent->port[1].bmdma_addr = bmdma + 8;
- if ((!(port[1]->flags & ATA_FLAG_IGN_SIMPLEX)) &&
- (ioread8(bmdma + 10) & 0x80))
- probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
+
+ if (!(legacy_dr->mask & (1 << i)))
+ continue;
+
+ if (!handler[i]) {
+ dev_printk(KERN_ERR, gdev,
+ "NULL handler specified for port %d\n", i);
+ rc = -EINVAL;
+ goto err_out;
}
- ata_std_ports(&probe_ent->port[1]);
- /* FIXME: could be pointing to stack area; must copy */
- probe_ent->pinfo2 = port[1];
- } else
- probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
+ rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
+ dev_id[i]);
+ if (rc) {
+ dev_printk(KERN_ERR, gdev,
+ "irq %u request failed (errno=%d)\n", irq, rc);
+ goto err_out;
+ }
- return probe_ent;
-}
+ /* record irq allocation in legacy_dr */
+ legacy_dr->irq[i] = irq;
+ legacy_dr->irq_dev_id[i] = dev_id[i];
+
+ /* only used to print info */
+ if (i == 0)
+ host->irq = irq;
+ else
+ host->irq2 = irq;
+ }
+ return 0;
+
+ err_out:
+ ata_legacy_free_irqs(legacy_dr);
+ return rc;
+}
/**
* ata_pci_init_one - Initialize/register PCI IDE host controller
@@ -718,8 +949,8 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports)
{
struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent = NULL;
- struct ata_port_info *port[2];
+ struct ata_host *host = NULL;
+ const struct ata_port_info *port[2];
u8 mask;
unsigned int legacy_mode = 0;
int rc;
@@ -732,10 +963,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
BUG_ON(n_ports < 1 || n_ports > 2);
port[0] = port_info[0];
- if (n_ports > 1)
- port[1] = port_info[1];
- else
- port[1] = port[0];
+ port[1] = (n_ports > 1) ? port_info[1] : NULL;
/* FIXME: Really for ATA it isn't safe because the device may be
multi-purpose and we want to leave it alone if it was already
@@ -743,7 +971,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
Checking dev->is_enabled is insufficient as this is not set at
boot for the primary video which is BIOS enabled
- */
+ */
rc = pcim_enable_device(pdev);
if (rc)
@@ -769,96 +997,68 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
#endif
}
+ /* alloc and init host */
+ host = ata_host_alloc_pinfo(dev, port, n_ports);
+ if (!host) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to allocate ATA host\n");
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
if (!legacy_mode) {
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
+ unsigned int port_mask;
+
+ port_mask = ATA_PORT_PRIMARY;
+ if (n_ports > 1)
+ port_mask |= ATA_PORT_SECONDARY;
+
+ rc = ata_pci_init_native_host(host, port_mask);
+ if (rc)
goto err_out;
- }
} else {
- /* Deal with combined mode hack. This side of the logic all
- goes away once the combined mode hack is killed in 2.6.21 */
- if (!devm_request_region(dev, ATA_PRIMARY_CMD, 8, "libata")) {
- struct resource *conflict, res;
- res.start = ATA_PRIMARY_CMD;
- res.end = ATA_PRIMARY_CMD + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- while (conflict->child)
- conflict = ____request_resource(conflict, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= ATA_PORT_PRIMARY;
- else {
- pcim_pin_device(pdev);
- printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
- "ata: conflict with %s\n",
- ATA_PRIMARY_CMD,
- conflict->name);
- }
- } else
- legacy_mode |= ATA_PORT_PRIMARY;
-
- if (!devm_request_region(dev, ATA_SECONDARY_CMD, 8, "libata")) {
- struct resource *conflict, res;
- res.start = ATA_SECONDARY_CMD;
- res.end = ATA_SECONDARY_CMD + 8 - 1;
- conflict = ____request_resource(&ioport_resource, &res);
- while (conflict->child)
- conflict = ____request_resource(conflict, &res);
- if (!strcmp(conflict->name, "libata"))
- legacy_mode |= ATA_PORT_SECONDARY;
- else {
- pcim_pin_device(pdev);
- printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
- "ata: conflict with %s\n",
- ATA_SECONDARY_CMD,
- conflict->name);
- }
- } else
- legacy_mode |= ATA_PORT_SECONDARY;
-
- if (legacy_mode & ATA_PORT_PRIMARY)
- pci_request_region(pdev, 1, DRV_NAME);
- if (legacy_mode & ATA_PORT_SECONDARY)
- pci_request_region(pdev, 3, DRV_NAME);
- /* If there is a DMA resource, allocate it */
- pci_request_region(pdev, 4, DRV_NAME);
- }
+ int was_busy = 0;
- /* we have legacy mode, but all ports are unavailable */
- if (legacy_mode == (1 << 3)) {
- rc = -EBUSY;
- goto err_out;
+ rc = ata_init_legacy_host(host, &legacy_mode, &was_busy);
+ if (was_busy)
+ pcim_pin_device(pdev);
+ if (rc)
+ goto err_out;
+
+ /* request respective PCI regions, may fail */
+ rc = pci_request_region(pdev, 1, DRV_NAME);
+ rc = pci_request_region(pdev, 3, DRV_NAME);
}
- /* TODO: If we get no DMA mask we should fall back to PIO */
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- goto err_out;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ /* init BMDMA, may fail */
+ ata_pci_init_bmdma(host);
+ pci_set_master(pdev);
+
+ /* start host and request IRQ */
+ rc = ata_host_start(host);
if (rc)
goto err_out;
- if (legacy_mode) {
- probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
- } else {
- if (n_ports == 2)
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- else
- probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+ if (!legacy_mode)
+ rc = devm_request_irq(dev, pdev->irq,
+ port_info[0]->port_ops->irq_handler,
+ IRQF_SHARED, DRV_NAME, host);
+ else {
+ irq_handler_t handler[2] = { host->ops->irq_handler,
+ host->ops->irq_handler };
+ unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED };
+ void *dev_id[2] = { host, host };
+
+ rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id);
}
- if (!probe_ent) {
- rc = -ENOMEM;
+ if (rc)
goto err_out;
- }
-
- pci_set_master(pdev);
- if (!ata_device_add(probe_ent)) {
- rc = -ENODEV;
+ /* register */
+ rc = ata_host_register(host, port_info[0]->sht);
+ if (rc)
goto err_out;
- }
- devm_kfree(dev, probe_ent);
devres_remove_group(dev, NULL);
return 0;
@@ -893,12 +1093,12 @@ int ata_pci_clear_simplex(struct pci_dev *pdev)
return 0;
}
-unsigned long ata_pci_default_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long xfer_mask)
+unsigned long ata_pci_default_filter(struct ata_device *adev, unsigned long xfer_mask)
{
/* Filter out DMA modes if the device has been configured by
the BIOS as PIO only */
- if (ap->ioaddr.bmdma_addr == 0)
+ if (adev->ap->ioaddr.bmdma_addr == 0)
xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
return xfer_mask;
}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 1f1e3a51f85..5f4d40cd328 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -52,6 +52,7 @@ enum {
ATA_DNXFER_QUIET = (1 << 31),
};
+extern unsigned int ata_print_id;
extern struct workqueue_struct *ata_aux_wq;
extern int atapi_enabled;
extern int atapi_dmadir;
@@ -92,10 +93,7 @@ extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
-extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
- const struct ata_probe_ent *ent, unsigned int port_no);
-extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
- const struct ata_port_info *port);
+extern struct ata_port *ata_port_alloc(struct ata_host *host);
/* libata-acpi.c */
#ifdef CONFIG_SATA_ACPI
@@ -113,8 +111,8 @@ static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix)
#endif
/* libata-scsi.c */
-extern struct scsi_transport_template ata_scsi_transport_template;
-
+extern int ata_scsi_add_hosts(struct ata_host *host,
+ struct scsi_host_template *sht);
extern void ata_scsi_scan_host(struct ata_port *ap);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 11ea552a58c..d40edebb510 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.3"
+#define DRV_VERSION "0.7.4"
/*
* Cable special cases
@@ -90,59 +90,6 @@ static int ali_c2_cable_detect(struct ata_port *ap)
}
/**
- * ali_early_error_handler - reset for eary chip
- * @ap: ATA port
- *
- * Handle the reset callback for the later chips with cable detect
- */
-
-static int ali_c2_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ali_c2_cable_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void ali_c2_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, ali_c2_pre_reset,
- ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
-/**
- * ali_early_cable_detect - cable detection
- * @ap: ATA port
- *
- * Perform cable detection for older chipsets. This turns out to be
- * rather easy to implement
- */
-
-static int ali_early_cable_detect(struct ata_port *ap)
-{
- return ATA_CBL_PATA40;
-}
-
-/**
- * ali_early_probe_init - reset for early chip
- * @ap: ATA port
- *
- * Handle the reset callback for the early (pre cable detect) chips.
- */
-
-static int ali_early_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ali_early_cable_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void ali_early_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, ali_early_pre_reset,
- ata_std_softreset, NULL,
- ata_std_postreset);
-}
-
-/**
* ali_20_filter - filter for earlier ALI DMA
* @ap: ALi ATA port
* @adev: attached device
@@ -151,7 +98,7 @@ static void ali_early_error_handler(struct ata_port *ap)
* fix that later on. Also ensure we do not do UDMA on WDC drives
*/
-static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long ali_20_filter(struct ata_device *adev, unsigned long mask)
{
char model_num[ATA_ID_PROD_LEN + 1];
/* No DMA on anything but a disk for now */
@@ -160,7 +107,7 @@ static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strstr(model_num, "WDC"))
return mask &= ~ATA_MASK_UDMA;
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
@@ -314,7 +261,6 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
/**
* ali_lock_sectors - Keep older devices to 255 sector mode
- * @ap: ATA port
* @adev: Device
*
* Called during the bus probe for each device that is found. We use
@@ -324,7 +270,7 @@ static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* slower PIO methods
*/
-static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
+static void ali_lock_sectors(struct ata_device *adev)
{
adev->max_sectors = 255;
}
@@ -366,8 +312,9 @@ static struct ata_port_operations ali_early_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_early_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -402,8 +349,9 @@ static struct ata_port_operations ali_20_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_early_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -440,8 +388,9 @@ static struct ata_port_operations ali_c2_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_c2_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ali_c2_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -477,8 +426,9 @@ static struct ata_port_operations ali_c5_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = ali_c2_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ali_c2_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 18381762908..67c7e87dec0 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.3.8"
/**
* timing_setup - shared timing computation and load
@@ -119,34 +119,27 @@ static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offse
}
/**
- * amd_probe_init - cable detection
+ * amd_probe_init - perform reset handling
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
- * Perform cable detection. The BIOS stores this in PCI config
- * space for us.
+ * Reset sequence checking enable bits to see which ports are
+ * active.
*/
-static int amd_pre_reset(struct ata_port *ap)
+static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
{
- static const u32 bitmask[2] = {0x03, 0x0C};
static const struct pci_bits amd_enable_bits[] = {
{ 0x40, 1, 0x02, 0x02 },
{ 0x40, 1, 0x01, 0x01 }
};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 ata66;
if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
return -ENOENT;
- pci_read_config_byte(pdev, 0x42, &ata66);
- if (ata66 & bitmask[ap->port_no])
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-
+ return ata_std_prereset(ap, deadline);
}
static void amd_error_handler(struct ata_port *ap)
@@ -156,28 +149,16 @@ static void amd_error_handler(struct ata_port *ap)
ata_std_postreset);
}
-static int amd_early_pre_reset(struct ata_port *ap)
+static int amd_cable_detect(struct ata_port *ap)
{
+ static const u32 bitmask[2] = {0x03, 0x0C};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- static struct pci_bits amd_enable_bits[] = {
- { 0x40, 1, 0x02, 0x02 },
- { 0x40, 1, 0x01, 0x01 }
- };
-
- if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
- return -ENOENT;
-
- /* No host side cable detection */
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-
-}
+ u8 ata66;
-static void amd_early_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, amd_early_pre_reset,
- ata_std_softreset, NULL,
- ata_std_postreset);
+ pci_read_config_byte(pdev, 0x42, &ata66);
+ if (ata66 & bitmask[ap->port_no])
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
}
/**
@@ -246,33 +227,19 @@ static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* space for us.
*/
-static int nv_pre_reset(struct ata_port *ap) {
- static const u8 bitmask[2] = {0x03, 0x0C};
+static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+{
static const struct pci_bits nv_enable_bits[] = {
{ 0x50, 1, 0x02, 0x02 },
{ 0x50, 1, 0x01, 0x01 }
};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 ata66;
- u16 udma;
if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
return -ENOENT;
- pci_read_config_byte(pdev, 0x52, &ata66);
- if (ata66 & bitmask[ap->port_no])
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
-
- /* We now have to double check because the Nvidia boxes BIOS
- doesn't always set the cable bits but does set mode bits */
-
- pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
- if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -281,6 +248,29 @@ static void nv_error_handler(struct ata_port *ap)
ata_std_softreset, NULL,
ata_std_postreset);
}
+
+static int nv_cable_detect(struct ata_port *ap)
+{
+ static const u8 bitmask[2] = {0x03, 0x0C};
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+ u16 udma;
+ int cbl;
+
+ pci_read_config_byte(pdev, 0x52, &ata66);
+ if (ata66 & bitmask[ap->port_no])
+ cbl = ATA_CBL_PATA80;
+ else
+ cbl = ATA_CBL_PATA40;
+
+ /* We now have to double check because the Nvidia boxes BIOS
+ doesn't always set the cable bits but does set mode bits */
+ pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
+ if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
+ cbl = ATA_CBL_PATA80;
+ return cbl;
+}
+
/**
* nv100_set_piomode - set initial PIO mode data
* @ap: ATA interface
@@ -353,8 +343,9 @@ static struct ata_port_operations amd33_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = amd_early_error_handler,
+ .error_handler = amd_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -387,8 +378,9 @@ static struct ata_port_operations amd66_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = amd_early_error_handler,
+ .error_handler = amd_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -423,6 +415,7 @@ static struct ata_port_operations amd100_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = amd_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -457,6 +450,7 @@ static struct ata_port_operations amd133_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = amd_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = amd_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -491,6 +485,7 @@ static struct ata_port_operations nv100_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = nv_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -525,6 +520,7 @@ static struct ata_port_operations nv133_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = nv_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index 21c30282717..ef51940c3ad 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -39,7 +39,7 @@
static int clock = 0;
-static int artop6210_pre_reset(struct ata_port *ap)
+static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
const struct pci_bits artop_enable_bits[] = {
@@ -50,8 +50,7 @@ static int artop6210_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -72,12 +71,13 @@ static void artop6210_error_handler(struct ata_port *ap)
/**
* artop6260_pre_reset - check for 40/80 pin
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
* The ARTOP hardware reports the cable detect bits in register 0x49.
* Nothing complicated needed here.
*/
-static int artop6260_pre_reset(struct ata_port *ap)
+static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits artop_enable_bits[] = {
{ 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
@@ -85,18 +85,29 @@ static int artop6260_pre_reset(struct ata_port *ap)
};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 tmp;
/* Odd numbered device ids are the units with enable bits (the -R cards) */
if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
return -ENOENT;
+ return ata_std_prereset(ap, deadline);
+}
+
+/**
+ * artop6260_cable_detect - identify cable type
+ * @ap: Port
+ *
+ * Identify the cable type for the ARTOp interface in question
+ */
+
+static int artop6260_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
pci_read_config_byte(pdev, 0x49, &tmp);
if (tmp & (1 << ap->port_no))
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
}
/**
@@ -225,7 +236,7 @@ static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev)
/**
* artop6210_set_dmamode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
- * @adev: um
+ * @adev: Device whose timings we are configuring
*
* Set DMA mode for device, in host controller PCI config space.
*
@@ -333,6 +344,7 @@ static const struct ata_port_operations artop6210_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = artop6210_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -366,6 +378,7 @@ static const struct ata_port_operations artop6260_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = artop6260_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = artop6260_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 51d9923be02..21515381b5b 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.4"
+#define DRV_VERSION "0.4.5"
enum {
ATIIXP_IDE_PIO_TIMING = 0x40,
@@ -33,26 +33,18 @@ enum {
ATIIXP_IDE_UDMA_MODE = 0x56
};
-static int atiixp_pre_reset(struct ata_port *ap)
+static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
{
- struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits atiixp_enable_bits[] = {
{ 0x48, 1, 0x01, 0x00 },
{ 0x48, 1, 0x08, 0x00 }
};
- u8 udma;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
return -ENOENT;
- /* Hack from drivers/ide/pci. Really we want to know how to do the
- raw detection not play follow the bios mode guess */
- pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
- if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
static void atiixp_error_handler(struct ata_port *ap)
@@ -60,6 +52,19 @@ static void atiixp_error_handler(struct ata_port *ap)
ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
}
+static int atiixp_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 udma;
+
+ /* Hack from drivers/ide/pci. Really we want to know how to do the
+ raw detection not play follow the bios mode guess */
+ pci_read_config_byte(pdev, ATIIXP_IDE_UDMA_MODE + ap->port_no, &udma);
+ if ((udma & 0x07) >= 0x04 || (udma & 0x70) >= 0x40)
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
+}
+
/**
* atiixp_set_pio_timing - set initial PIO mode data
* @ap: ATA interface
@@ -245,6 +250,7 @@ static struct ata_port_operations atiixp_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = atiixp_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = atiixp_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = atiixp_bmdma_start,
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
new file mode 100644
index 00000000000..2105985a801
--- /dev/null
+++ b/drivers/ata/pata_cmd640.c
@@ -0,0 +1,312 @@
+/*
+ * pata_cmd640.c - CMD640 PCI PATA for new ATA layer
+ * (C) 2007 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based upon
+ * linux/drivers/ide/pci/cmd640.c Version 1.02 Sep 01, 1996
+ *
+ * Copyright (C) 1995-1996 Linus Torvalds & authors (see driver)
+ *
+ * This drives only the PCI version of the controller. If you have a
+ * VLB one then we have enough docs to support it but you can write
+ * your own code.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cmd640"
+#define DRV_VERSION "0.0.5"
+
+struct cmd640_reg {
+ int last;
+ u8 reg58[ATA_MAX_DEVICES];
+};
+
+enum {
+ CFR = 0x50,
+ CNTRL = 0x51,
+ CMDTIM = 0x52,
+ ARTIM0 = 0x53,
+ DRWTIM0 = 0x54,
+ ARTIM23 = 0x57,
+ DRWTIM23 = 0x58,
+ BRST = 0x59
+};
+
+/**
+ * cmd640_set_piomode - set initial PIO mode data
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup.
+ */
+
+static void cmd640_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct cmd640_reg *timing = ap->private_data;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_timing t;
+ const unsigned long T = 1000000 / 33;
+ const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 };
+ u8 reg;
+ int arttim = ARTIM0 + 2 * adev->devno;
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
+ return;
+ }
+
+ /* The second channel has shared timings and the setup timing is
+ messy to switch to merge it for worst case */
+ if (ap->port_no && pair) {
+ struct ata_timing p;
+ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP);
+ }
+
+ /* Make the timings fit */
+ if (t.recover > 16) {
+ t.active += t.recover - 16;
+ t.recover = 16;
+ }
+ if (t.active > 16)
+ t.active = 16;
+
+ /* Now convert the clocks into values we can actually stuff into
+ the chip */
+
+ if (t.recover > 1)
+ t.recover--; /* 640B only */
+ else
+ t.recover = 15;
+
+ if (t.setup > 4)
+ t.setup = 0xC0;
+ else
+ t.setup = setup_data[t.setup];
+
+ if (ap->port_no == 0) {
+ t.active &= 0x0F; /* 0 = 16 */
+
+ /* Load setup timing */
+ pci_read_config_byte(pdev, arttim, &reg);
+ reg &= 0x3F;
+ reg |= t.setup;
+ pci_write_config_byte(pdev, arttim, reg);
+
+ /* Load active/recovery */
+ pci_write_config_byte(pdev, arttim + 1, (t.active << 4) | t.recover);
+ } else {
+ /* Save the shared timings for channel, they will be loaded
+ by qc_issue_prot. Reloading the setup time is expensive
+ so we keep a merged one loaded */
+ pci_read_config_byte(pdev, ARTIM23, &reg);
+ reg &= 0x3F;
+ reg |= t.setup;
+ pci_write_config_byte(pdev, ARTIM23, reg);
+ timing->reg58[adev->devno] = (t.active << 4) | t.recover;
+ }
+}
+
+
+/**
+ * cmd640_qc_issue_prot - command preparation hook
+ * @qc: Command to be issued
+ *
+ * Channel 1 has shared timings. We must reprogram the
+ * clock each drive 2/3 switch we do.
+ */
+
+static unsigned int cmd640_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct cmd640_reg *timing = ap->private_data;
+
+ if (ap->port_no != 0 && adev->devno != timing->last) {
+ pci_write_config_byte(pdev, DRWTIM23, timing->reg58[adev->devno]);
+ timing->last = adev->devno;
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * cmd640_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * The CMD640 needs to maintain private data structures so we
+ * allocate space here.
+ */
+
+static int cmd640_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct cmd640_reg *timing;
+
+ int ret = ata_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ timing = devm_kzalloc(&pdev->dev, sizeof(struct cmd640_reg), GFP_KERNEL);
+ if (timing == NULL)
+ return -ENOMEM;
+ timing->last = -1; /* Force a load */
+ ap->private_data = timing;
+ return ret;
+}
+
+static struct scsi_host_template cmd640_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+#ifdef CONFIG_PM
+ .resume = ata_scsi_device_resume,
+ .suspend = ata_scsi_device_suspend,
+#endif
+};
+
+static struct ata_port_operations cmd640_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd640_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = cmd640_qc_issue_prot,
+
+ /* In theory this is not needed once we kill the prefetcher */
+ .data_xfer = ata_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_on = ata_irq_on,
+ .irq_ack = ata_irq_ack,
+
+ .port_start = cmd640_port_start,
+};
+
+static void cmd640_hardware_init(struct pci_dev *pdev)
+{
+ u8 r;
+ u8 ctrl;
+
+ /* CMD640 detected, commiserations */
+ pci_write_config_byte(pdev, 0x5B, 0x00);
+ /* Get version info */
+ pci_read_config_byte(pdev, CFR, &r);
+ /* PIO0 command cycles */
+ pci_write_config_byte(pdev, CMDTIM, 0);
+ /* 512 byte bursts (sector) */
+ pci_write_config_byte(pdev, BRST, 0x40);
+ /*
+ * A reporter a long time ago
+ * Had problems with the data fifo
+ * So don't run the risk
+ * Of putting crap on the disk
+ * For its better just to go slow
+ */
+ /* Do channel 0 */
+ pci_read_config_byte(pdev, CNTRL, &ctrl);
+ pci_write_config_byte(pdev, CNTRL, ctrl | 0xC0);
+ /* Ditto for channel 1 */
+ pci_read_config_byte(pdev, ARTIM23, &ctrl);
+ ctrl |= 0x0C;
+ pci_write_config_byte(pdev, ARTIM23, ctrl);
+}
+
+static int cmd640_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &cmd640_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &cmd640_port_ops
+ };
+
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ cmd640_hardware_init(pdev);
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static int cmd640_reinit_one(struct pci_dev *pdev)
+{
+ cmd640_hardware_init(pdev);
+#ifdef CONFIG_PM
+ return ata_pci_device_resume(pdev);
+#else
+ return 0;
+#endif
+}
+
+static const struct pci_device_id cmd640[] = {
+ { PCI_VDEVICE(CMD, 0x640), 0 },
+ { },
+};
+
+static struct pci_driver cmd640_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cmd640,
+ .probe = cmd640_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+#endif
+ .resume = cmd640_reinit_one,
+};
+
+static int __init cmd640_init(void)
+{
+ return pci_register_driver(&cmd640_pci_driver);
+}
+
+static void __exit cmd640_exit(void)
+{
+ pci_unregister_driver(&cmd640_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for CMD640 PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cmd640);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cmd640_init);
+module_exit(cmd640_exit);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 5b13bdd1edc..3989cc577fc 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -75,13 +75,7 @@ enum {
DTPR1 = 0x7C
};
-static int cmd64x_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static int cmd648_pre_reset(struct ata_port *ap)
+static int cmd648_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 r;
@@ -89,21 +83,8 @@ static int cmd648_pre_reset(struct ata_port *ap)
/* Check cable detect bits */
pci_read_config_byte(pdev, BMIDECSR, &r);
if (r & (1 << ap->port_no))
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
-
- return ata_std_prereset(ap);
-}
-
-static void cmd64x_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-static void cmd648_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
}
/**
@@ -304,8 +285,9 @@ static struct ata_port_operations cmd64x_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cmd64x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -338,8 +320,9 @@ static struct ata_port_operations cmd646r1_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cmd64x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -372,8 +355,9 @@ static struct ata_port_operations cmd648_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cmd648_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = cmd648_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 55cc293e748..79bef0d1fad 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -139,18 +139,6 @@ static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
cs5520_set_timings(ap, adev, adev->pio_mode);
}
-
-static int cs5520_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static void cs5520_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
static struct scsi_host_template cs5520_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -186,8 +174,9 @@ static struct ata_port_operations cs5520_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cs5520_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -197,7 +186,6 @@ static struct ata_port_operations cs5520_port_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -205,91 +193,104 @@ static struct ata_port_operations cs5520_port_ops = {
.port_start = ata_port_start,
};
-static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ struct ata_port_info pi = {
+ .flags = ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f,
+ .port_ops = &cs5520_port_ops,
+ };
+ const struct ata_port_info *ppi[2];
u8 pcicfg;
- void __iomem *iomap[5];
- static struct ata_probe_ent probe[2];
- int ports = 0;
+ void *iomap[5];
+ struct ata_host *host;
+ struct ata_ioports *ioaddr;
+ int i, rc;
/* IDE port enable bits */
- pci_read_config_byte(dev, 0x60, &pcicfg);
+ pci_read_config_byte(pdev, 0x60, &pcicfg);
/* Check if the ATA ports are enabled */
if ((pcicfg & 3) == 0)
return -ENODEV;
+ ppi[0] = ppi[1] = &ata_dummy_port_info;
+ if (pcicfg & 1)
+ ppi[0] = &pi;
+ if (pcicfg & 2)
+ ppi[1] = &pi;
+
if ((pcicfg & 0x40) == 0) {
- printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
- pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "DMA mode disabled. Enabling.\n");
+ pci_write_config_byte(pdev, 0x60, pcicfg | 0x40);
}
+ pi.mwdma_mask = id->driver_data;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host)
+ return -ENOMEM;
+
/* Perform set up for DMA */
- if (pci_enable_device_bars(dev, 1<<2)) {
+ if (pci_enable_device_bars(pdev, 1<<2)) {
printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
return -ENODEV;
}
- pci_set_master(dev);
- if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
return -ENODEV;
}
- if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
return -ENODEV;
}
- /* Map IO ports */
- iomap[0] = devm_ioport_map(&dev->dev, 0x1F0, 8);
- iomap[1] = devm_ioport_map(&dev->dev, 0x3F6, 1);
- iomap[2] = devm_ioport_map(&dev->dev, 0x170, 8);
- iomap[3] = devm_ioport_map(&dev->dev, 0x376, 1);
- iomap[4] = pcim_iomap(dev, 2, 0);
+ /* Map IO ports and initialize host accordingly */
+ iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
+ iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
+ iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
+ iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+ iomap[4] = pcim_iomap(pdev, 2, 0);
if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
return -ENOMEM;
- /* We have to do our own plumbing as the PCI setup for this
- chipset is non-standard so we can't punt to the libata code */
-
- INIT_LIST_HEAD(&probe[0].node);
- probe[0].dev = pci_dev_to_dev(dev);
- probe[0].port_ops = &cs5520_port_ops;
- probe[0].sht = &cs5520_sht;
- probe[0].pio_mask = 0x1F;
- probe[0].mwdma_mask = id->driver_data;
- probe[0].irq = 14;
- probe[0].irq_flags = 0;
- probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
- probe[0].n_ports = 1;
- probe[0].port[0].cmd_addr = iomap[0];
- probe[0].port[0].ctl_addr = iomap[1];
- probe[0].port[0].altstatus_addr = iomap[1];
- probe[0].port[0].bmdma_addr = iomap[4];
-
- /* The secondary lurks at different addresses but is otherwise
- the same beastie */
-
- probe[1] = probe[0];
- INIT_LIST_HEAD(&probe[1].node);
- probe[1].irq = 15;
- probe[1].port[0].cmd_addr = iomap[2];
- probe[1].port[0].ctl_addr = iomap[3];
- probe[1].port[0].altstatus_addr = iomap[3];
- probe[1].port[0].bmdma_addr = iomap[4] + 8;
-
- /* Let libata fill in the port details */
- ata_std_ports(&probe[0].port[0]);
- ata_std_ports(&probe[1].port[0]);
-
- /* Now add the ports that are active */
- if (pcicfg & 1)
- ports += ata_device_add(&probe[0]);
- if (pcicfg & 2)
- ports += ata_device_add(&probe[1]);
- if (ports)
- return 0;
- return -ENODEV;
+ ioaddr = &host->ports[0]->ioaddr;
+ ioaddr->cmd_addr = iomap[0];
+ ioaddr->ctl_addr = iomap[1];
+ ioaddr->altstatus_addr = iomap[1];
+ ioaddr->bmdma_addr = iomap[4];
+ ata_std_ports(ioaddr);
+
+ ioaddr = &host->ports[1]->ioaddr;
+ ioaddr->cmd_addr = iomap[2];
+ ioaddr->ctl_addr = iomap[3];
+ ioaddr->altstatus_addr = iomap[3];
+ ioaddr->bmdma_addr = iomap[4] + 8;
+ ata_std_ports(ioaddr);
+
+ /* activate the host */
+ pci_set_master(pdev);
+ rc = ata_host_start(host);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < 2; i++) {
+ static const int irq[] = { 14, 15 };
+ struct ata_port *ap = host->ports[0];
+
+ if (ata_port_is_dummy(ap))
+ continue;
+
+ rc = devm_request_irq(&pdev->dev, irq[ap->port_no],
+ ata_interrupt, 0, DRV_NAME, host);
+ if (rc)
+ return rc;
+ }
+
+ return ata_host_register(host, &cs5520_sht);
}
/**
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index db63e80e608..29642d5ee18 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -160,18 +160,6 @@ static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
-static int cs5530_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static void cs5530_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
static struct scsi_host_template cs5530_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -213,8 +201,9 @@ static struct ata_port_operations cs5530_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cs5530_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = cs5530_qc_issue_prot,
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 1572e5c9031..22006ae7194 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -70,36 +70,24 @@
#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
/**
- * cs5535_pre_reset - detect cable type
+ * cs5535_cable_detect - detect cable type
* @ap: Port to detect on
+ * @deadline: deadline jiffies for the operation
*
* Perform cable detection for ATA66 capable cable. Return a libata
* cable type.
*/
-static int cs5535_pre_reset(struct ata_port *ap)
+static int cs5535_cable_detect(struct ata_port *ap)
{
u8 cable;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable);
if (cable & 1)
- ap->cbl = ATA_CBL_PATA80;
+ return ATA_CBL_PATA80;
else
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-/**
- * cs5535_error_handler - reset/probe
- * @ap: Port to reset
- *
- * Reset and configure a port
- */
-
-static void cs5535_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, cs5535_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ return ATA_CBL_PATA40;
}
/**
@@ -205,8 +193,9 @@ static struct ata_port_operations cs5535_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cs5535_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = cs5535_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index f69dde5f706..6ec049c3b1d 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -41,17 +41,6 @@ enum {
CY82_INDEX_TIMEOUT = 0x32
};
-static int cy82c693_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-static void cy82c693_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
/**
* cy82c693_set_piomode - set initial PIO mode data
* @ap: ATA interface
@@ -156,8 +145,9 @@ static struct ata_port_operations cy82c693_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = cy82c693_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index dac7a6554f6..d0f52e03490 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -22,35 +22,29 @@
#include <linux/ata.h>
#define DRV_NAME "pata_efar"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.4.4"
/**
- * efar_pre_reset - check for 40/80 pin
+ * efar_pre_reset - Enable bits
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
* Perform cable detection for the EFAR ATA interface. This is
* different to the PIIX arrangement
*/
-static int efar_pre_reset(struct ata_port *ap)
+static int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits efar_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
{ 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
};
-
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 tmp;
if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
return -ENOENT;
- pci_read_config_byte(pdev, 0x47, &tmp);
- if (tmp & (2 >> ap->port_no))
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -67,6 +61,25 @@ static void efar_error_handler(struct ata_port *ap)
}
/**
+ * efar_cable_detect - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the EFAR ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int efar_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ pci_read_config_byte(pdev, 0x47, &tmp);
+ if (tmp & (2 >> ap->port_no))
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+/**
* efar_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
* @adev: um
@@ -256,6 +269,7 @@ static const struct ata_port_operations efar_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = efar_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = efar_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index baf35f87603..e64e05e5c7f 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -27,7 +27,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt366"
-#define DRV_VERSION "0.6.0"
+#define DRV_VERSION "0.6.1"
struct hpt_clock {
u8 xfer_speed;
@@ -169,13 +169,12 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, cons
/**
* hpt366_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
*
* Block UDMA on devices that cause trouble with this controller.
*/
-static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask)
{
if (adev->class == ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
@@ -185,7 +184,7 @@ static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device
if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
mask &= ~(0x0F << ATA_SHIFT_UDMA);
}
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
@@ -210,25 +209,29 @@ static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
return 0xffffffffU; /* silence compiler warning */
}
-static int hpt36x_pre_reset(struct ata_port *ap)
+static int hpt36x_cable_detect(struct ata_port *ap)
+{
+ u8 ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ if (ata66 & (1 << ap->port_no))
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+static int hpt36x_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits hpt36x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
{ 0x54, 1, 0x04, 0x04 }
};
-
- u8 ata66;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
if (!pci_test_config_bits(pdev, &hpt36x_enable_bits[ap->port_no]))
return -ENOENT;
- pci_read_config_byte(pdev, 0x5A, &ata66);
- if (ata66 & (1 << ap->port_no))
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -354,6 +357,7 @@ static struct ata_port_operations hpt366_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = hpt36x_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = hpt36x_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index f331eeeafa0..1614e8c822a 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -8,6 +8,7 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
+ * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
*
* TODO
* PLL mode
@@ -25,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt37x"
-#define DRV_VERSION "0.6.0"
+#define DRV_VERSION "0.6.5"
struct hpt_clock {
u8 xfer_speed;
@@ -61,201 +62,75 @@ struct hpt_chip {
* 31 FIFO enable.
*/
-/* from highpoint documentation. these are old values */
-static const struct hpt_clock hpt370_timings_33[] = {
-/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
- { XFER_UDMA_5, 0x16454e31 },
- { XFER_UDMA_4, 0x16454e31 },
- { XFER_UDMA_3, 0x166d4e31 },
- { XFER_UDMA_2, 0x16494e31 },
- { XFER_UDMA_1, 0x164d4e31 },
- { XFER_UDMA_0, 0x16514e31 },
-
- { XFER_MW_DMA_2, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57 },
- { 0, 0x06514e57 }
+static struct hpt_clock hpt37x_timings_33[] = {
+ { XFER_UDMA_6, 0x12446231 }, /* 0x12646231 ?? */
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 }
};
-static const struct hpt_clock hpt370_timings_66[] = {
- { XFER_UDMA_5, 0x14846231 },
- { XFER_UDMA_4, 0x14886231 },
- { XFER_UDMA_3, 0x148c6231 },
- { XFER_UDMA_2, 0x148c6231 },
- { XFER_UDMA_1, 0x14906231 },
- { XFER_UDMA_0, 0x14986231 },
-
- { XFER_MW_DMA_2, 0x26514e21 },
- { XFER_MW_DMA_1, 0x26514e33 },
- { XFER_MW_DMA_0, 0x26514e97 },
-
- { XFER_PIO_4, 0x06514e21 },
- { XFER_PIO_3, 0x06514e22 },
- { XFER_PIO_2, 0x06514e33 },
- { XFER_PIO_1, 0x06914e43 },
- { XFER_PIO_0, 0x06914e57 },
- { 0, 0x06514e57 }
+static struct hpt_clock hpt37x_timings_50[] = {
+ { XFER_UDMA_6, 0x12848242 },
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a }
};
-/* these are the current (4 sep 2001) timings from highpoint */
-static const struct hpt_clock hpt370a_timings_33[] = {
- { XFER_UDMA_5, 0x12446231 },
- { XFER_UDMA_4, 0x12446231 },
- { XFER_UDMA_3, 0x126c6231 },
- { XFER_UDMA_2, 0x12486231 },
- { XFER_UDMA_1, 0x124c6233 },
- { XFER_UDMA_0, 0x12506297 },
-
- { XFER_MW_DMA_2, 0x22406c31 },
- { XFER_MW_DMA_1, 0x22406c33 },
- { XFER_MW_DMA_0, 0x22406c97 },
-
- { XFER_PIO_4, 0x06414e31 },
- { XFER_PIO_3, 0x06414e42 },
- { XFER_PIO_2, 0x06414e53 },
- { XFER_PIO_1, 0x06814e93 },
- { XFER_PIO_0, 0x06814ea7 },
- { 0, 0x06814ea7 }
+static struct hpt_clock hpt37x_timings_66[] = {
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1cae9c62 }, /* 0x1c8a9c62 */
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2e },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e }
};
-/* 2x 33MHz timings */
-static const struct hpt_clock hpt370a_timings_66[] = {
- { XFER_UDMA_5, 0x1488e673 },
- { XFER_UDMA_4, 0x1488e673 },
- { XFER_UDMA_3, 0x1498e673 },
- { XFER_UDMA_2, 0x1490e673 },
- { XFER_UDMA_1, 0x1498e677 },
- { XFER_UDMA_0, 0x14a0e73f },
-
- { XFER_MW_DMA_2, 0x2480fa73 },
- { XFER_MW_DMA_1, 0x2480fa77 },
- { XFER_MW_DMA_0, 0x2480fb3f },
-
- { XFER_PIO_4, 0x0c82be73 },
- { XFER_PIO_3, 0x0c82be95 },
- { XFER_PIO_2, 0x0c82beb7 },
- { XFER_PIO_1, 0x0d02bf37 },
- { XFER_PIO_0, 0x0d02bf5f },
- { 0, 0x0d02bf5f }
-};
-
-static const struct hpt_clock hpt370a_timings_50[] = {
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x0ac1f48a }
-};
-
-static const struct hpt_clock hpt372_timings_33[] = {
- { XFER_UDMA_6, 0x1c81dc62 },
- { XFER_UDMA_5, 0x1c6ddc62 },
- { XFER_UDMA_4, 0x1c8ddc62 },
- { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
- { XFER_UDMA_2, 0x1c91dc62 },
- { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
- { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
-
- { XFER_MW_DMA_2, 0x2c829262 },
- { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
- { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
-
- { XFER_PIO_4, 0x0c829c62 },
- { XFER_PIO_3, 0x0c829c84 },
- { XFER_PIO_2, 0x0c829ca6 },
- { XFER_PIO_1, 0x0d029d26 },
- { XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d5e }
-};
-
-static const struct hpt_clock hpt372_timings_50[] = {
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x0a81f443 }
-};
-
-static const struct hpt_clock hpt372_timings_66[] = {
- { XFER_UDMA_6, 0x1c869c62 },
- { XFER_UDMA_5, 0x1cae9c62 },
- { XFER_UDMA_4, 0x1c8a9c62 },
- { XFER_UDMA_3, 0x1c8e9c62 },
- { XFER_UDMA_2, 0x1c929c62 },
- { XFER_UDMA_1, 0x1c9a9c62 },
- { XFER_UDMA_0, 0x1c829c62 },
-
- { XFER_MW_DMA_2, 0x2c829c62 },
- { XFER_MW_DMA_1, 0x2c829c66 },
- { XFER_MW_DMA_0, 0x2c829d2e },
-
- { XFER_PIO_4, 0x0c829c62 },
- { XFER_PIO_3, 0x0c829c84 },
- { XFER_PIO_2, 0x0c829ca6 },
- { XFER_PIO_1, 0x0d029d26 },
- { XFER_PIO_0, 0x0d029d5e },
- { 0, 0x0d029d26 }
-};
-
-static const struct hpt_clock hpt374_timings_33[] = {
- { XFER_UDMA_6, 0x12808242 },
- { XFER_UDMA_5, 0x12848242 },
- { XFER_UDMA_4, 0x12ac8242 },
- { XFER_UDMA_3, 0x128c8242 },
- { XFER_UDMA_2, 0x120c8242 },
- { XFER_UDMA_1, 0x12148254 },
- { XFER_UDMA_0, 0x121882ea },
-
- { XFER_MW_DMA_2, 0x22808242 },
- { XFER_MW_DMA_1, 0x22808254 },
- { XFER_MW_DMA_0, 0x228082ea },
-
- { XFER_PIO_4, 0x0a81f442 },
- { XFER_PIO_3, 0x0a81f443 },
- { XFER_PIO_2, 0x0a81f454 },
- { XFER_PIO_1, 0x0ac1f465 },
- { XFER_PIO_0, 0x0ac1f48a },
- { 0, 0x06814e93 }
-};
static const struct hpt_chip hpt370 = {
"HPT370",
48,
{
- hpt370_timings_33,
+ hpt37x_timings_33,
NULL,
NULL,
- hpt370_timings_66
+ NULL
}
};
@@ -263,10 +138,10 @@ static const struct hpt_chip hpt370a = {
"HPT370A",
48,
{
- hpt370a_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt370a_timings_50,
- hpt370a_timings_66
+ hpt37x_timings_50,
+ NULL
}
};
@@ -274,10 +149,10 @@ static const struct hpt_chip hpt372 = {
"HPT372",
55,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -285,10 +160,10 @@ static const struct hpt_chip hpt302 = {
"HPT302",
66,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -296,10 +171,10 @@ static const struct hpt_chip hpt371 = {
"HPT371",
66,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -307,10 +182,10 @@ static const struct hpt_chip hpt372a = {
"HPT372A",
66,
{
- hpt372_timings_33,
+ hpt37x_timings_33,
NULL,
- hpt372_timings_50,
- hpt372_timings_66
+ hpt37x_timings_50,
+ hpt37x_timings_66
}
};
@@ -318,7 +193,7 @@ static const struct hpt_chip hpt374 = {
"HPT374",
48,
{
- hpt374_timings_33,
+ hpt37x_timings_33,
NULL,
NULL,
NULL
@@ -397,13 +272,12 @@ static const char *bad_ata100_5[] = {
/**
* hpt370_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
*
* Block UDMA on devices that cause trouble with this controller.
*/
-static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt370_filter(struct ata_device *adev, unsigned long mask)
{
if (adev->class == ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
@@ -411,34 +285,34 @@ static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
mask &= ~(0x1F << ATA_SHIFT_UDMA);
}
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
* hpt370a_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
*
* Block UDMA on devices that cause trouble with this controller.
*/
-static unsigned long hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long hpt370a_filter(struct ata_device *adev, unsigned long mask)
{
if (adev->class != ATA_DEV_ATA) {
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
mask &= ~ (0x1F << ATA_SHIFT_UDMA);
}
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
* hpt37x_pre_reset - reset the hpt37x bus
* @ap: ATA port to reset
+ * @deadline: deadline jiffies for the operation
*
* Perform the initial reset handling for the 370/372 and 374 func 0
*/
-static int hpt37x_pre_reset(struct ata_port *ap)
+static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
{
u8 scr2, ata66;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -462,11 +336,10 @@ static int hpt37x_pre_reset(struct ata_port *ap)
ap->cbl = ATA_CBL_PATA80;
/* Reset the state machine */
- pci_write_config_byte(pdev, 0x50, 0x37);
- pci_write_config_byte(pdev, 0x54, 0x37);
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -481,7 +354,7 @@ static void hpt37x_error_handler(struct ata_port *ap)
ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
}
-static int hpt374_pre_reset(struct ata_port *ap)
+static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits hpt37x_enable_bits[] = {
{ 0x50, 1, 0x04, 0x04 },
@@ -513,11 +386,10 @@ static int hpt374_pre_reset(struct ata_port *ap)
ap->cbl = ATA_CBL_PATA80;
/* Reset the state machine */
- pci_write_config_byte(pdev, 0x50, 0x37);
- pci_write_config_byte(pdev, 0x54, 0x37);
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -1032,6 +904,24 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
.udma_mask = 0x3f,
.port_ops = &hpt370a_port_ops
};
+ /* HPT370 - UDMA100 */
+ static struct ata_port_info info_hpt370_33 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x0f,
+ .port_ops = &hpt370_port_ops
+ };
+ /* HPT370A - UDMA100 */
+ static struct ata_port_info info_hpt370a_33 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x0f,
+ .port_ops = &hpt370a_port_ops
+ };
/* HPT371, 372 and friends - UDMA133 */
static struct ata_port_info info_hpt372 = {
.sht = &hpt37x_sht,
@@ -1067,7 +957,11 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
u8 irqmask;
u32 class_rev;
+ u8 mcr1;
u32 freq;
+ int prefer_dpll = 1;
+
+ unsigned long iobase = pci_resource_start(dev, 4);
const struct hpt_chip *chip_table;
int clock_slot;
@@ -1088,10 +982,12 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
case 3:
port = &info_hpt370;
chip_table = &hpt370;
+ prefer_dpll = 0;
break;
case 4:
port = &info_hpt370a;
chip_table = &hpt370a;
+ prefer_dpll = 0;
break;
case 5:
port = &info_hpt372;
@@ -1119,8 +1015,16 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
chip_table = &hpt302;
break;
case PCI_DEVICE_ID_TTI_HPT371:
+ if (class_rev > 1)
+ return -ENODEV;
port = &info_hpt372;
chip_table = &hpt371;
+ /* Single channel device, master is not present
+ but the BIOS (or us for non x86) must mark it
+ absent */
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ mcr1 &= ~0x04;
+ pci_write_config_byte(dev, 0x50, mcr1);
break;
case PCI_DEVICE_ID_TTI_HPT374:
chip_table = &hpt374;
@@ -1150,8 +1054,18 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
*/
pci_write_config_byte(dev, 0x5b, 0x23);
+
+ /*
+ * HighPoint does this for HPT372A.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (chip_table == &hpt372a)
+ outb(0x0e, iobase + 0x9c);
- pci_read_config_dword(dev, 0x70, &freq);
+ /* Some devices do not let this value be accessed via PCI space
+ according to the old driver */
+
+ freq = inl(iobase + 0x90);
if ((freq >> 12) != 0xABCDE) {
int i;
u8 sr;
@@ -1162,7 +1076,7 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* This is the process the HPT371 BIOS is reported to use */
for(i = 0; i < 128; i++) {
pci_read_config_byte(dev, 0x78, &sr);
- total += sr;
+ total += sr & 0x1FF;
udelay(15);
}
freq = total / 128;
@@ -1173,15 +1087,27 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
* Turn the frequency check into a band and then find a timing
* table to match it.
*/
-
+
clock_slot = hpt37x_clock_slot(freq, chip_table->base);
- if (chip_table->clocks[clock_slot] == NULL) {
+ if (chip_table->clocks[clock_slot] == NULL || prefer_dpll) {
/*
* We need to try PLL mode instead
+ *
+ * For non UDMA133 capable devices we should
+ * use a 50MHz DPLL by choice
*/
- unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192;
- unsigned int f_high = f_low + 2;
+ unsigned int f_low, f_high;
int adjust;
+
+ clock_slot = 2;
+ if (port->udma_mask & 0xE0)
+ clock_slot = 3;
+
+ f_low = (MHz[clock_slot] * chip_table->base) / 192;
+ f_high = f_low + 2;
+
+ /* Select the DPLL clock. */
+ pci_write_config_byte(dev, 0x5b, 0x21);
for(adjust = 0; adjust < 8; adjust++) {
if (hpt37x_calibrate_dpll(dev))
@@ -1197,25 +1123,27 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
return -ENODEV;
}
- /* Check if this works for all cases */
- port->private_data = (void *)hpt370_timings_66;
+ if (clock_slot == 3)
+ port->private_data = (void *)hpt37x_timings_66;
+ else
+ port->private_data = (void *)hpt37x_timings_50;
printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]);
} else {
port->private_data = (void *)chip_table->clocks[clock_slot];
/*
- * Perform a final fixup. The 371 and 372 clock determines
- * if UDMA133 is available.
- */
-
- if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */
- printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n");
- if (port == &info_hpt372)
- port = &info_hpt372_50;
- else BUG();
- }
+ * Perform a final fixup. Note that we will have used the
+ * DPLL on the HPT372 which means we don't have to worry
+ * about lack of UDMA133 support on lower clocks
+ */
+
+ if (clock_slot < 2 && port == &info_hpt370)
+ port = &info_hpt370_33;
+ if (clock_slot < 2 && port == &info_hpt370a)
+ port = &info_hpt370a_33;
printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
}
+
port_info[0] = port_info[1] = port;
/* Now kick off ATA set up */
return ata_pci_init_one(dev, port_info, 2);
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 65f2e180e7f..ea1037d6786 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,10 +8,10 @@
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
* Portions Copyright (C) 2003 Red Hat Inc
+ * Portions Copyright (C) 2005-2006 MontaVista Software, Inc.
*
*
* TODO
- * 371N
* Work out best PLL policy
*/
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x2n"
-#define DRV_VERSION "0.3.2"
+#define DRV_VERSION "0.3.3"
enum {
HPT_PCI_FAST = (1 << 31),
@@ -115,14 +115,13 @@ static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
}
/**
- * hpt3x2n_pre_reset - reset the hpt3x2n bus
- * @ap: ATA port to reset
+ * hpt3x2n_cable_detect - Detect the cable type
+ * @ap: ATA port to detect on
*
- * Perform the initial reset handling for the 3x2n series controllers.
- * Reset the hardware and state machine, obtain the cable type.
+ * Return the cable type attached to this port
*/
-static int hpt3xn_pre_reset(struct ata_port *ap)
+static int hpt3x2n_cable_detect(struct ata_port *ap)
{
u8 scr2, ata66;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
@@ -135,16 +134,28 @@ static int hpt3xn_pre_reset(struct ata_port *ap)
pci_write_config_byte(pdev, 0x5B, scr2);
if (ata66 & (1 << ap->port_no))
- ap->cbl = ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
else
- ap->cbl = ATA_CBL_PATA80;
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * hpt3x2n_pre_reset - reset the hpt3x2n bus
+ * @ap: ATA port to reset
+ * @deadline: deadline jiffies for the operation
+ *
+ * Perform the initial reset handling for the 3x2n series controllers.
+ * Reset the hardware and state machine,
+ */
+static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
/* Reset the state machine */
- pci_write_config_byte(pdev, 0x50, 0x37);
- pci_write_config_byte(pdev, 0x54, 0x37);
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
udelay(100);
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -364,6 +375,7 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = hpt3x2n_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = hpt3x2n_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -422,8 +434,9 @@ static int hpt3x2n_pci_clock(struct pci_dev *pdev)
{
unsigned long freq;
u32 fcnt;
+ unsigned long iobase = pci_resource_start(pdev, 4);
- pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt);
+ fcnt = inl(iobase + 0x90); /* Not PCI readable for some chips */
if ((fcnt >> 12) != 0xABCDE) {
printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
return 33; /* Not BIOS set */
@@ -492,6 +505,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
unsigned int pci_mhz;
unsigned int f_low, f_high;
int adjust;
+ unsigned long iobase = pci_resource_start(dev, 4);
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xFF;
@@ -501,6 +515,11 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (class_rev < 6)
return -ENODEV;
break;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ if (class_rev < 2)
+ return -ENODEV;
+ /* 371N if rev > 1 */
+ break;
case PCI_DEVICE_ID_TTI_HPT372:
/* 372N if rev >= 1*/
if (class_rev == 0)
@@ -528,6 +547,19 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
irqmask &= ~0x10;
pci_write_config_byte(dev, 0x5a, irqmask);
+ /*
+ * HPT371 chips physically have only one channel, the secondary one,
+ * but the primary channel registers do exist! Go figure...
+ * So, we manually disable the non-existing channel here
+ * (if the BIOS hasn't done this already).
+ */
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT371) {
+ u8 mcr1;
+ pci_read_config_byte(dev, 0x50, &mcr1);
+ mcr1 &= ~0x04;
+ pci_write_config_byte(dev, 0x50, mcr1);
+ }
+
/* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
50 for UDMA100. Right now we always use 66 */
@@ -546,14 +578,24 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
break;
pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
}
- if (adjust == 8)
- printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n");
+ if (adjust == 8) {
+ printk(KERN_WARNING "hpt3x2n: DPLL did not stabilize.\n");
+ return -ENODEV;
+ }
/* Set our private data up. We only need a few flags so we use
it directly */
port->private_data = NULL;
- if (pci_mhz > 60)
+ if (pci_mhz > 60) {
port->private_data = (void *)PCI66;
+ /*
+ * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+ * the MISC. register to stretch the UltraDMA Tss timing.
+ * NOTE: This register is only writeable via I/O space.
+ */
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT371)
+ outb(inb(iobase + 0x9c) | 0x04, iobase + 0x9c);
+ }
/* Now kick off ATA set up */
port_info[0] = port_info[1] = port;
@@ -562,6 +604,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
static const struct pci_device_id hpt3x2n[] = {
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), },
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 813485c8526..ac28ec8c50a 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -25,25 +25,6 @@
#define DRV_NAME "pata_hpt3x3"
#define DRV_VERSION "0.4.2"
-static int hpt3x3_probe_init(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-/**
- * hpt3x3_probe_reset - reset the hpt3x3 bus
- * @ap: ATA port to reset
- *
- * Perform the housekeeping when doing an ATA bus reeset. We just
- * need to force the cable type.
- */
-
-static void hpt3x3_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset);
-}
-
/**
* hpt3x3_set_piomode - PIO setup
* @ap: ATA interface
@@ -139,8 +120,9 @@ static struct ata_port_operations hpt3x3_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = hpt3x3_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
new file mode 100644
index 00000000000..dbc8ee2adcf
--- /dev/null
+++ b/drivers/ata/pata_icside.c
@@ -0,0 +1,686 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+
+#define DRV_NAME "pata_icside"
+
+#define ICS_IDENT_OFFSET 0x2280
+
+#define ICS_ARCIN_V5_INTRSTAT 0x0000
+#define ICS_ARCIN_V5_INTROFFSET 0x0004
+
+#define ICS_ARCIN_V6_INTROFFSET_1 0x2200
+#define ICS_ARCIN_V6_INTRSTAT_1 0x2290
+#define ICS_ARCIN_V6_INTROFFSET_2 0x3200
+#define ICS_ARCIN_V6_INTRSTAT_2 0x3290
+
+struct portinfo {
+ unsigned int dataoffset;
+ unsigned int ctrloffset;
+ unsigned int stepping;
+};
+
+static const struct portinfo pata_icside_portinfo_v5 = {
+ .dataoffset = 0x2800,
+ .ctrloffset = 0x2b80,
+ .stepping = 6,
+};
+
+static const struct portinfo pata_icside_portinfo_v6_1 = {
+ .dataoffset = 0x2000,
+ .ctrloffset = 0x2380,
+ .stepping = 6,
+};
+
+static const struct portinfo pata_icside_portinfo_v6_2 = {
+ .dataoffset = 0x3000,
+ .ctrloffset = 0x3380,
+ .stepping = 6,
+};
+
+#define PATA_ICSIDE_MAX_SG 128
+
+struct pata_icside_state {
+ void __iomem *irq_port;
+ void __iomem *ioc_base;
+ unsigned int type;
+ unsigned int dma;
+ struct {
+ u8 port_sel;
+ u8 disabled;
+ unsigned int speed[ATA_MAX_DEVICES];
+ } port[2];
+ struct scatterlist sg[PATA_ICSIDE_MAX_SG];
+};
+
+#define ICS_TYPE_A3IN 0
+#define ICS_TYPE_A3USER 1
+#define ICS_TYPE_V6 3
+#define ICS_TYPE_V5 15
+#define ICS_TYPE_NOTYPE ((unsigned int)-1)
+
+/* ---------------- Version 5 PCB Support Functions --------------------- */
+/* Prototype: pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void pata_icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ struct pata_icside_state *state = ec->irq_data;
+
+ writeb(0, state->irq_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+/* Prototype: pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void pata_icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+{
+ struct pata_icside_state *state = ec->irq_data;
+
+ readb(state->irq_port + ICS_ARCIN_V5_INTROFFSET);
+}
+
+static const expansioncard_ops_t pata_icside_ops_arcin_v5 = {
+ .irqenable = pata_icside_irqenable_arcin_v5,
+ .irqdisable = pata_icside_irqdisable_arcin_v5,
+};
+
+
+/* ---------------- Version 6 PCB Support Functions --------------------- */
+/* Prototype: pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : enable interrupts from card
+ */
+static void pata_icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ struct pata_icside_state *state = ec->irq_data;
+ void __iomem *base = state->irq_port;
+
+ if (!state->port[0].disabled)
+ writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
+ if (!state->port[1].disabled)
+ writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ * Purpose : disable interrupts from card
+ */
+static void pata_icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+{
+ struct pata_icside_state *state = ec->irq_data;
+
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+}
+
+/* Prototype: pata_icside_irqprobe(struct expansion_card *ec)
+ * Purpose : detect an active interrupt from card
+ */
+static int pata_icside_irqpending_arcin_v6(struct expansion_card *ec)
+{
+ struct pata_icside_state *state = ec->irq_data;
+
+ return readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+ readb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+}
+
+static const expansioncard_ops_t pata_icside_ops_arcin_v6 = {
+ .irqenable = pata_icside_irqenable_arcin_v6,
+ .irqdisable = pata_icside_irqdisable_arcin_v6,
+ .irqpending = pata_icside_irqpending_arcin_v6,
+};
+
+
+/*
+ * SG-DMA support.
+ *
+ * Similar to the BM-DMA, but we use the RiscPCs IOMD DMA controllers.
+ * There is only one DMA controller per card, which means that only
+ * one drive can be accessed at one time. NOTE! We do not enforce that
+ * here, but we rely on the main IDE driver spotting that both
+ * interfaces use the same IRQ, which should guarantee this.
+ */
+
+/*
+ * Configure the IOMD to give the appropriate timings for the transfer
+ * mode being requested. We take the advice of the ATA standards, and
+ * calculate the cycle time based on the transfer mode, and the EIDE
+ * MW DMA specs that the drive provides in the IDENTIFY command.
+ *
+ * We have the following IOMD DMA modes to choose from:
+ *
+ * Type Active Recovery Cycle
+ * A 250 (250) 312 (550) 562 (800)
+ * B 187 (200) 250 (550) 437 (750)
+ * C 125 (125) 125 (375) 250 (500)
+ * D 62 (50) 125 (375) 187 (425)
+ *
+ * (figures in brackets are actual measured timings on DIOR/DIOW)
+ *
+ * However, we also need to take care of the read/write active and
+ * recovery timings:
+ *
+ * Read Write
+ * Mode Active -- Recovery -- Cycle IOMD type
+ * MW0 215 50 215 480 A
+ * MW1 80 50 50 150 C
+ * MW2 70 25 25 120 C
+ */
+static void pata_icside_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pata_icside_state *state = ap->host->private_data;
+ struct ata_timing t;
+ unsigned int cycle;
+ char iomd_type;
+
+ /*
+ * DMA is based on a 16MHz clock
+ */
+ if (ata_timing_compute(adev, adev->dma_mode, &t, 1000, 1))
+ return;
+
+ /*
+ * Choose the IOMD cycle timing which ensure that the interface
+ * satisfies the measured active, recovery and cycle times.
+ */
+ if (t.active <= 50 && t.recover <= 375 && t.cycle <= 425)
+ iomd_type = 'D', cycle = 187;
+ else if (t.active <= 125 && t.recover <= 375 && t.cycle <= 500)
+ iomd_type = 'C', cycle = 250;
+ else if (t.active <= 200 && t.recover <= 550 && t.cycle <= 750)
+ iomd_type = 'B', cycle = 437;
+ else
+ iomd_type = 'A', cycle = 562;
+
+ ata_dev_printk(adev, KERN_INFO, "timings: act %dns rec %dns cyc %dns (%c)\n",
+ t.active, t.recover, t.cycle, iomd_type);
+
+ state->port[ap->port_no].speed[adev->devno] = cycle;
+}
+
+static void pata_icside_bmdma_setup(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_icside_state *state = ap->host->private_data;
+ struct scatterlist *sg, *rsg = state->sg;
+ unsigned int write = qc->tf.flags & ATA_TFLAG_WRITE;
+
+ /*
+ * We are simplex; BUG if we try to fiddle with DMA
+ * while it's active.
+ */
+ BUG_ON(dma_channel_active(state->dma));
+
+ /*
+ * Copy ATAs scattered sg list into a contiguous array of sg
+ */
+ ata_for_each_sg(sg, qc) {
+ memcpy(rsg, sg, sizeof(*sg));
+ rsg++;
+ }
+
+ /*
+ * Route the DMA signals to the correct interface
+ */
+ writeb(state->port[ap->port_no].port_sel, state->ioc_base);
+
+ set_dma_speed(state->dma, state->port[ap->port_no].speed[qc->dev->devno]);
+ set_dma_sg(state->dma, state->sg, rsg - state->sg);
+ set_dma_mode(state->dma, write ? DMA_MODE_WRITE : DMA_MODE_READ);
+
+ /* issue r/w command */
+ ap->ops->exec_command(ap, &qc->tf);
+}
+
+static void pata_icside_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_icside_state *state = ap->host->private_data;
+
+ BUG_ON(dma_channel_active(state->dma));
+ enable_dma(state->dma);
+}
+
+static void pata_icside_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pata_icside_state *state = ap->host->private_data;
+
+ disable_dma(state->dma);
+
+ /* see ata_bmdma_stop */
+ ata_altstatus(ap);
+}
+
+static u8 pata_icside_bmdma_status(struct ata_port *ap)
+{
+ struct pata_icside_state *state = ap->host->private_data;
+ void __iomem *irq_port;
+
+ irq_port = state->irq_port + (ap->port_no ? ICS_ARCIN_V6_INTRSTAT_2 :
+ ICS_ARCIN_V6_INTRSTAT_1);
+
+ return readb(irq_port) & 1 ? ATA_DMA_INTR : 0;
+}
+
+static int icside_dma_init(struct ata_probe_ent *ae, struct expansion_card *ec)
+{
+ struct pata_icside_state *state = ae->private_data;
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ state->port[0].speed[i] = 480;
+ state->port[1].speed[i] = 480;
+ }
+
+ if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) {
+ state->dma = ec->dma;
+ ae->mwdma_mask = 0x07; /* MW0..2 */
+ }
+
+ return 0;
+}
+
+
+static int pata_icside_port_start(struct ata_port *ap)
+{
+ /* No PRD to alloc */
+ return ata_pad_alloc(ap, ap->dev);
+}
+
+static struct scsi_host_template pata_icside_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = PATA_ICSIDE_MAX_SG,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ~0, /* no dma boundaries */
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+/* wish this was exported from libata-core */
+static void ata_dummy_noret(struct ata_port *port)
+{
+}
+
+/*
+ * We need to shut down unused ports to prevent spurious interrupts.
+ * FIXME: the libata core doesn't call this function for PATA interfaces.
+ */
+static void pata_icside_port_disable(struct ata_port *ap)
+{
+ struct pata_icside_state *state = ap->host->private_data;
+
+ ata_port_printk(ap, KERN_ERR, "disabling icside port\n");
+
+ ata_port_disable(ap);
+
+ state->port[ap->port_no].disabled = 1;
+
+ if (state->type == ICS_TYPE_V6) {
+ /*
+ * Disable interrupts from this port, otherwise we
+ * receive spurious interrupts from the floating
+ * interrupt line.
+ */
+ void __iomem *irq_port = state->irq_port +
+ (ap->port_no ? ICS_ARCIN_V6_INTROFFSET_2 : ICS_ARCIN_V6_INTROFFSET_1);
+ readb(irq_port);
+ }
+}
+
+static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+ unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+ u8 status;
+
+ status = ata_busy_wait(ap, bits, 1000);
+ if (status & bits)
+ if (ata_msg_err(ap))
+ printk(KERN_ERR "abnormal status 0x%X\n", status);
+
+ if (ata_msg_intr(ap))
+ printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
+ __FUNCTION__, status);
+
+ return status;
+}
+
+static struct ata_port_operations pata_icside_port_ops = {
+ .port_disable = pata_icside_port_disable,
+
+ .set_dmamode = pata_icside_set_dmamode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .exec_command = ata_exec_command,
+ .check_status = ata_check_status,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = pata_icside_bmdma_setup,
+ .bmdma_start = pata_icside_bmdma_start,
+
+ .data_xfer = ata_data_xfer_noirq,
+
+ /* no need to build any PRD tables for DMA */
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = pata_icside_bmdma_stop,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_dummy_noret,
+ .irq_on = ata_irq_on,
+ .irq_ack = pata_icside_irq_ack,
+
+ .port_start = pata_icside_port_start,
+
+ .bmdma_stop = pata_icside_bmdma_stop,
+ .bmdma_status = pata_icside_bmdma_status,
+};
+
+static void
+pata_icside_add_port(struct ata_probe_ent *ae, void __iomem *base,
+ const struct portinfo *info)
+{
+ struct ata_ioports *ioaddr = &ae->port[ae->n_ports++];
+ void __iomem *cmd = base + info->dataoffset;
+
+ ioaddr->cmd_addr = cmd;
+ ioaddr->data_addr = cmd + (ATA_REG_DATA << info->stepping);
+ ioaddr->error_addr = cmd + (ATA_REG_ERR << info->stepping);
+ ioaddr->feature_addr = cmd + (ATA_REG_FEATURE << info->stepping);
+ ioaddr->nsect_addr = cmd + (ATA_REG_NSECT << info->stepping);
+ ioaddr->lbal_addr = cmd + (ATA_REG_LBAL << info->stepping);
+ ioaddr->lbam_addr = cmd + (ATA_REG_LBAM << info->stepping);
+ ioaddr->lbah_addr = cmd + (ATA_REG_LBAH << info->stepping);
+ ioaddr->device_addr = cmd + (ATA_REG_DEVICE << info->stepping);
+ ioaddr->status_addr = cmd + (ATA_REG_STATUS << info->stepping);
+ ioaddr->command_addr = cmd + (ATA_REG_CMD << info->stepping);
+
+ ioaddr->ctl_addr = base + info->ctrloffset;
+ ioaddr->altstatus_addr = ioaddr->ctl_addr;
+}
+
+static int __init
+pata_icside_register_v5(struct ata_probe_ent *ae, struct expansion_card *ec)
+{
+ struct pata_icside_state *state = ae->private_data;
+ void __iomem *base;
+
+ base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!base)
+ return -ENOMEM;
+
+ state->irq_port = base;
+
+ ec->irqaddr = base + ICS_ARCIN_V5_INTRSTAT;
+ ec->irqmask = 1;
+ ec->irq_data = state;
+ ec->ops = &pata_icside_ops_arcin_v5;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ ec->ops->irqdisable(ec, ec->irq);
+
+ pata_icside_add_port(ae, base, &pata_icside_portinfo_v5);
+
+ return 0;
+}
+
+static int __init
+pata_icside_register_v6(struct ata_probe_ent *ae, struct expansion_card *ec)
+{
+ struct pata_icside_state *state = ae->private_data;
+ void __iomem *ioc_base, *easi_base;
+ unsigned int sel = 0;
+ int ret;
+
+ ioc_base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+ ecard_resource_len(ec, ECARD_RES_IOCFAST));
+ if (!ioc_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ easi_base = ioc_base;
+
+ if (ecard_resource_flags(ec, ECARD_RES_EASI)) {
+ easi_base = ioremap(ecard_resource_start(ec, ECARD_RES_EASI),
+ ecard_resource_len(ec, ECARD_RES_EASI));
+ if (!easi_base) {
+ ret = -ENOMEM;
+ goto unmap_slot;
+ }
+
+ /*
+ * Enable access to the EASI region.
+ */
+ sel = 1 << 5;
+ }
+
+ writeb(sel, ioc_base);
+
+ ec->irq_data = state;
+ ec->ops = &pata_icside_ops_arcin_v6;
+
+ state->irq_port = easi_base;
+ state->ioc_base = ioc_base;
+ state->port[0].port_sel = sel;
+ state->port[1].port_sel = sel | 1;
+
+ /*
+ * Be on the safe side - disable interrupts
+ */
+ ec->ops->irqdisable(ec, ec->irq);
+
+ /*
+ * Find and register the interfaces.
+ */
+ pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_1);
+ pata_icside_add_port(ae, easi_base, &pata_icside_portinfo_v6_2);
+
+ /*
+ * FIXME: work around libata's aversion to calling port_disable.
+ * This permanently disables interrupts on port 0 - bad luck if
+ * you have a drive on that port.
+ */
+ state->port[0].disabled = 1;
+
+ return icside_dma_init(ae, ec);
+
+ unmap_slot:
+ iounmap(ioc_base);
+ out:
+ return ret;
+}
+
+static int __devinit
+pata_icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+ struct pata_icside_state *state;
+ struct ata_probe_ent ae;
+ void __iomem *idmem;
+ int ret;
+
+ ret = ecard_request_resources(ec);
+ if (ret)
+ goto out;
+
+ state = kzalloc(sizeof(struct pata_icside_state), GFP_KERNEL);
+ if (!state) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ state->type = ICS_TYPE_NOTYPE;
+ state->dma = NO_DMA;
+
+ idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+ ecard_resource_len(ec, ECARD_RES_IOCFAST));
+ if (idmem) {
+ unsigned int type;
+
+ type = readb(idmem + ICS_IDENT_OFFSET) & 1;
+ type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
+ type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
+ type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
+ iounmap(idmem);
+
+ state->type = type;
+ }
+
+ memset(&ae, 0, sizeof(ae));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &ec->dev;
+ ae.port_ops = &pata_icside_port_ops;
+ ae.sht = &pata_icside_sht;
+ ae.pio_mask = 0x1f;
+ ae.irq = ec->irq;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ae._host_flags = ATA_HOST_SIMPLEX;
+ ae.private_data = state;
+
+ switch (state->type) {
+ case ICS_TYPE_A3IN:
+ dev_warn(&ec->dev, "A3IN unsupported\n");
+ ret = -ENODEV;
+ break;
+
+ case ICS_TYPE_A3USER:
+ dev_warn(&ec->dev, "A3USER unsupported\n");
+ ret = -ENODEV;
+ break;
+
+ case ICS_TYPE_V5:
+ ret = pata_icside_register_v5(&ae, ec);
+ break;
+
+ case ICS_TYPE_V6:
+ ret = pata_icside_register_v6(&ae, ec);
+ break;
+
+ default:
+ dev_warn(&ec->dev, "unknown interface type\n");
+ ret = -ENODEV;
+ break;
+ }
+
+ if (ret == 0)
+ ret = ata_device_add(&ae) == 0 ? -ENODEV : 0;
+
+ if (ret == 0)
+ goto out;
+
+ kfree(state);
+ release:
+ ecard_release_resources(ec);
+ out:
+ return ret;
+}
+
+static void pata_icside_shutdown(struct expansion_card *ec)
+{
+ struct ata_host *host = ecard_get_drvdata(ec);
+ unsigned long flags;
+
+ /*
+ * Disable interrupts from this card. We need to do
+ * this before disabling EASI since we may be accessing
+ * this register via that region.
+ */
+ local_irq_save(flags);
+ if (ec->ops)
+ ec->ops->irqdisable(ec, ec->irq);
+ local_irq_restore(flags);
+
+ /*
+ * Reset the ROM pointer so that we can read the ROM
+ * after a soft reboot. This also disables access to
+ * the IDE taskfile via the EASI region.
+ */
+ if (host) {
+ struct pata_icside_state *state = host->private_data;
+ if (state->ioc_base)
+ writeb(0, state->ioc_base);
+ }
+}
+
+static void __devexit pata_icside_remove(struct expansion_card *ec)
+{
+ struct ata_host *host = ecard_get_drvdata(ec);
+ struct pata_icside_state *state = host->private_data;
+
+ ata_host_detach(host);
+
+ pata_icside_shutdown(ec);
+
+ /*
+ * don't NULL out the drvdata - devres/libata wants it
+ * to free the ata_host structure.
+ */
+ ec->ops = NULL;
+ ec->irq_data = NULL;
+
+ if (state->dma != NO_DMA)
+ free_dma(state->dma);
+ if (state->ioc_base)
+ iounmap(state->ioc_base);
+ if (state->ioc_base != state->irq_port)
+ iounmap(state->irq_port);
+
+ kfree(state);
+ ecard_release_resources(ec);
+}
+
+static const struct ecard_id pata_icside_ids[] = {
+ { MANU_ICS, PROD_ICS_IDE },
+ { MANU_ICS2, PROD_ICS2_IDE },
+ { 0xffff, 0xffff }
+};
+
+static struct ecard_driver pata_icside_driver = {
+ .probe = pata_icside_probe,
+ .remove = __devexit_p(pata_icside_remove),
+ .shutdown = pata_icside_shutdown,
+ .id_table = pata_icside_ids,
+ .drv = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init pata_icside_init(void)
+{
+ return ecard_register_driver(&pata_icside_driver);
+}
+
+static void __exit pata_icside_exit(void)
+{
+ ecard_remove_driver(&pata_icside_driver);
+}
+
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ICS PATA driver");
+
+module_init(pata_icside_init);
+module_exit(pata_icside_exit);
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 1a61cc89174..d042efdfbac 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -49,13 +49,13 @@ static struct ata_port_operations isapnp_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -74,8 +74,10 @@ static struct ata_port_operations isapnp_port_ops = {
static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
{
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
+ int rc;
if (pnp_port_valid(idev, 0) == 0)
return -ENODEV;
@@ -84,34 +86,36 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
if (pnp_irq_valid(idev, 0) == 0)
return -ENODEV;
+ /* allocate host */
+ host = ata_host_alloc(&idev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
cmd_addr = devm_ioport_map(&idev->dev, pnp_port_start(idev, 0), 8);
if (!cmd_addr)
return -ENOMEM;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &idev->dev;
- ae.port_ops = &isapnp_port_ops;
- ae.sht = &isapnp_sht;
- ae.n_ports = 1;
- ae.pio_mask = 1; /* ISA so PIO 0 cycles */
- ae.irq = pnp_irq(idev, 0);
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS;
- ae.port[0].cmd_addr = cmd_addr;
+ ap = host->ports[0];
+
+ ap->ops = &isapnp_port_ops;
+ ap->pio_mask = 1;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+
+ ap->ioaddr.cmd_addr = cmd_addr;
if (pnp_port_valid(idev, 1) == 0) {
ctl_addr = devm_ioport_map(&idev->dev,
pnp_port_start(idev, 1), 1);
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ae.port_flags |= ATA_FLAG_SRST;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
}
- ata_std_ports(&ae.port[0]);
- if (ata_device_add(&ae) == 0)
- return -ENODEV;
- return 0;
+ ata_std_ports(&ap->ioaddr);
+
+ /* activate */
+ return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
+ &isapnp_sht);
}
/**
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index ea734701555..17bf9f3ed01 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -24,33 +24,26 @@
/**
* it8213_pre_reset - check for 40/80 pin
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
- * Perform cable detection for the 8213 ATA interface. This is
- * different to the PIIX arrangement
+ * Filter out ports by the enable bits before doing the normal reset
+ * and probe.
*/
-static int it8213_pre_reset(struct ata_port *ap)
+static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits it8213_enable_bits[] = {
{ 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
};
-
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u8 tmp;
-
if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
return -ENOENT;
- pci_read_config_byte(pdev, 0x42, &tmp);
- if (tmp & 2) /* The initial docs are incorrect */
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
- * it8213_probe_reset - Probe specified port on PATA host controller
+ * it8213_error_handler - Probe specified port on PATA host controller
* @ap: Port to probe
*
* LOCKING:
@@ -63,9 +56,27 @@ static void it8213_error_handler(struct ata_port *ap)
}
/**
+ * it8213_cable_detect - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the 8213 ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int it8213_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+ pci_read_config_byte(pdev, 0x42, &tmp);
+ if (tmp & 2) /* The initial docs are incorrect */
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
+
+/**
* it8213_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
- * @adev: um
+ * @adev: Device whose timings we are configuring
*
* Set PIO mode for device, in host controller PCI config space.
*
@@ -268,6 +279,7 @@ static const struct ata_port_operations it8213_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = it8213_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = it8213_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 35ecb2ba067..f1f8cec8c22 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@
#define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.4"
+#define DRV_VERSION "0.3.6"
struct it821x_dev
{
@@ -113,31 +113,6 @@ struct it821x_dev
static int it8212_noraid;
/**
- * it821x_pre_reset - probe
- * @ap: ATA port
- *
- * Set the cable type
- */
-
-static int it821x_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-/**
- * it821x_error_handler - probe/reset
- * @ap: ATA port
- *
- * Set the cable type and trigger a probe
- */
-
-static void it821x_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-/**
* it821x_program - program the PIO/MWDMA registers
* @ap: ATA port
* @adev: Device to program
@@ -520,7 +495,6 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
/**
* it821x_dev_config - Called each device identify
- * @ap: ATA port
* @adev: Device that has just been identified
*
* Perform the initial setup needed for each device that is chip
@@ -531,7 +505,7 @@ static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused
* basically we need to filter commands for this chip.
*/
-static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void it821x_dev_config(struct ata_device *adev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -667,8 +641,9 @@ static struct ata_port_operations it821x_smart_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = it821x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -703,8 +678,9 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = it821x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = it821x_passthru_bmdma_start,
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index c6f0e192755..420c343e571 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -129,8 +129,8 @@ static struct ata_port_operations ixp4xx_port_ops = {
.qc_issue = ata_qc_issue_prot,
.eng_timeout = ata_eng_timeout,
.data_xfer = ixp4xx_mmio_data_xfer,
+ .cable_detect = ata_cable_40wire,
- .irq_handler = ata_interrupt,
.irq_clear = ixp4xx_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -173,12 +173,12 @@ static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
{
- int ret;
unsigned int irq;
struct resource *cs0, *cs1;
- struct ata_probe_ent ae;
-
+ struct ata_host *host;
+ struct ata_port *ap;
struct ixp4xx_pata_data *data = pdev->dev.platform_data;
+ int rc;
cs0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
cs1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -186,6 +186,12 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
if (!cs0 || !cs1)
return -EINVAL;
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
pdev->dev.coherent_dma_mask = DMA_32BIT_MASK;
data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
@@ -199,32 +205,22 @@ static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
*data->cs0_cfg = data->cs0_bits;
*data->cs1_cfg = data->cs1_bits;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
+ ap = host->ports[0];
- ae.dev = &pdev->dev;
- ae.port_ops = &ixp4xx_port_ops;
- ae.sht = &ixp4xx_sht;
- ae.n_ports = 1;
- ae.pio_mask = 0x1f; /* PIO4 */
- ae.irq = irq;
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY
- | ATA_FLAG_NO_ATAPI | ATA_FLAG_SRST;
+ ap->ops = &ixp4xx_port_ops;
+ ap->pio_mask = 0x1f; /* PIO4 */
+ ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
/* run in polling mode if no irq has been assigned */
if (!irq)
- ae.port_flags |= ATA_FLAG_PIO_POLLING;
+ ap->flags |= ATA_FLAG_PIO_POLLING;
- ixp4xx_setup_port(&ae.port[0], data);
+ ixp4xx_setup_port(&ap->ioaddr, data);
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
- ret = ata_device_add(&ae);
- if (ret == 0)
- return -ENODEV;
-
- return 0;
+ /* activate host */
+ return ata_host_activate(host, irq, ata_interrupt, 0, &ixp4xx_sht);
}
static __devexit int ixp4xx_pata_remove(struct platform_device *dev)
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 43763c99ea0..1daf78ac6ef 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -30,16 +30,17 @@ typedef enum {
/**
* jmicron_pre_reset - check for 40/80 pin
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
-
+ *
* On the Jmicron 361/363 there is a single PATA port that can be mapped
* either as primary or secondary (or neither). We don't do any policy
* and setup here. We assume that has been done by init_one and the
* BIOS.
*/
-static int jmicron_pre_reset(struct ata_port *ap)
+static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 control;
@@ -102,7 +103,7 @@ static int jmicron_pre_reset(struct ata_port *ap)
ap->cbl = ATA_CBL_SATA;
break;
}
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index 86fbcd6a742..707099291e0 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -162,6 +162,7 @@ static struct ata_port_operations simple_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -185,6 +186,7 @@ static struct ata_port_operations legacy_port_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .cable_detect = ata_cable_40wire,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
@@ -305,6 +307,7 @@ static struct ata_port_operations pdc20230_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -360,6 +363,7 @@ static struct ata_port_operations ht6560a_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -426,6 +430,7 @@ static struct ata_port_operations ht6560b_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -547,6 +552,7 @@ static struct ata_port_operations opti82c611a_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -680,6 +686,7 @@ static struct ata_port_operations opti82c46x_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = opti82c46x_qc_issue_prot,
@@ -709,7 +716,8 @@ static struct ata_port_operations opti82c46x_port_ops = {
static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
{
struct legacy_data *ld = &legacy_data[nr_legacy_host];
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
struct platform_device *pdev;
struct ata_port_operations *ops = &legacy_port_ops;
void __iomem *io_addr, *ctrl_addr;
@@ -791,24 +799,23 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl
if (ops == &legacy_port_ops && (autospeed & mask))
ops = &simple_port_ops;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
- ae.port_ops = ops;
- ae.sht = &legacy_sht;
- ae.n_ports = 1;
- ae.pio_mask = pio_modes;
- ae.irq = irq;
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy;
- ae.port[0].cmd_addr = io_addr;
- ae.port[0].altstatus_addr = ctrl_addr;
- ae.port[0].ctl_addr = ctrl_addr;
- ata_std_ports(&ae.port[0]);
- ae.private_data = ld;
-
- ret = -ENODEV;
- if (!ata_device_add(&ae))
+ ret = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto fail;
+ ap = host->ports[0];
+
+ ap->ops = ops;
+ ap->pio_mask = pio_modes;
+ ap->flags |= ATA_FLAG_SLAVE_POSS | iordy;
+ ap->ioaddr.cmd_addr = io_addr;
+ ap->ioaddr.altstatus_addr = ctrl_addr;
+ ap->ioaddr.ctl_addr = ctrl_addr;
+ ata_std_ports(&ap->ioaddr);
+ ap->private_data = ld;
+
+ ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
+ if (ret)
goto fail;
legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 6dd7c4ef3e6..837b7fe77dc 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -20,16 +20,17 @@
#include <linux/ata.h>
#define DRV_NAME "pata_marvell"
-#define DRV_VERSION "0.1.1"
+#define DRV_VERSION "0.1.4"
/**
* marvell_pre_reset - check for 40/80 pin
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
* Perform the PATA port setup we need.
*/
-static int marvell_pre_reset(struct ata_port *ap)
+static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 devices;
@@ -53,21 +54,24 @@ static int marvell_pre_reset(struct ata_port *ap)
(!(devices & 0x10))) /* PATA enable ? */
return -ENOENT;
+ return ata_std_prereset(ap, deadline);
+}
+
+static int marvell_cable_detect(struct ata_port *ap)
+{
/* Cable type */
switch(ap->port_no)
{
case 0:
if (ioread8(ap->ioaddr.bmdma_addr + 1) & 1)
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
- break;
-
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
case 1: /* Legacy SATA port */
- ap->cbl = ATA_CBL_SATA;
- break;
+ return ATA_CBL_SATA;
}
- return ata_std_prereset(ap);
+
+ BUG();
+ return 0; /* Our BUG macro needs the right markup */
}
/**
@@ -123,6 +127,7 @@ static const struct ata_port_operations marvell_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = marvell_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = marvell_cable_detect,
/* BMDMA handling is PCI ATA format, use helpers */
.bmdma_setup = ata_bmdma_setup,
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 882c36eaf29..9587a89f968 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -24,7 +24,7 @@
#define DRV_NAME "mpc52xx_ata"
-#define DRV_VERSION "0.1.0"
+#define DRV_VERSION "0.1.0ac2"
/* Private structures used by the driver */
@@ -297,38 +297,37 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = mpc52xx_ata_error_handler,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
.port_start = ata_port_start,
};
-static struct ata_probe_ent mpc52xx_ata_probe_ent = {
- .port_ops = &mpc52xx_ata_port_ops,
- .sht = &mpc52xx_ata_sht,
- .n_ports = 1,
- .pio_mask = 0x1f, /* Up to PIO4 */
- .mwdma_mask = 0x00, /* No MWDMA */
- .udma_mask = 0x00, /* No UDMA */
- .port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
- .irq_flags = 0,
-};
-
static int __devinit
mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
{
- struct ata_probe_ent *ae = &mpc52xx_ata_probe_ent;
- struct ata_ioports *aio = &ae->port[0];
- int rv;
-
- INIT_LIST_HEAD(&ae->node);
- ae->dev = dev;
- ae->irq = priv->ata_irq;
-
+ struct ata_host *host;
+ struct ata_port *ap;
+ struct ata_ioports *aio;
+ int rc;
+
+ host = ata_host_alloc(dev, 1);
+ if (!host)
+ return -ENOMEM;
+
+ ap = host->ports[0];
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->pio_mask = 0x1f; /* Up to PIO4 */
+ ap->mwdma_mask = 0x00; /* No MWDMA */
+ ap->udma_mask = 0x00; /* No UDMA */
+ ap->ops = &mpc52xx_ata_port_ops;
+ host->private_data = priv;
+
+ aio = &ap->ioaddr;
aio->cmd_addr = NULL; /* Don't have a classic reg block */
aio->altstatus_addr = &priv->ata_regs->tf_control;
aio->ctl_addr = &priv->ata_regs->tf_control;
@@ -343,11 +342,9 @@ mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
aio->status_addr = &priv->ata_regs->tf_command;
aio->command_addr = &priv->ata_regs->tf_command;
- ae->private_data = priv;
-
- rv = ata_device_add(ae);
-
- return rv ? 0 : -EINVAL;
+ /* activate host */
+ return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
+ &mpc52xx_ata_sht);
}
static struct mpc52xx_ata_priv *
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4abe45ac19a..3bfbd495f64 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.5"
+#define DRV_VERSION "0.7.6"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -46,15 +46,15 @@ enum {
SECONDARY = (1 << 14)
};
-static int mpiix_pre_reset(struct ata_port *ap)
+static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -185,12 +185,12 @@ static struct ata_port_operations mpiix_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = mpiix_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = mpiix_qc_issue_prot,
.data_xfer = ata_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -201,8 +201,9 @@ static struct ata_port_operations mpiix_port_ops = {
static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
/* Single threaded by the PCI probe logic */
- static struct ata_probe_ent probe;
static int printed_version;
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
u16 idetim;
int irq;
@@ -210,6 +211,10 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
if (!printed_version++)
dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+ host = ata_host_alloc(&dev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+
/* MPIIX has many functions which can be turned on or off according
to other devices present. Make sure IDE is enabled before we try
and use it */
@@ -238,27 +243,21 @@ static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
without BARs set fools the setup. #2 If you pci_disable_device
the MPIIX your box goes castors up */
- INIT_LIST_HEAD(&probe.node);
- probe.dev = pci_dev_to_dev(dev);
- probe.port_ops = &mpiix_port_ops;
- probe.sht = &mpiix_sht;
- probe.pio_mask = 0x1F;
- probe.irq_flags = IRQF_SHARED;
- probe.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- probe.n_ports = 1;
+ ap = host->ports[0];
+ ap->ops = &mpiix_port_ops;
+ ap->pio_mask = 0x1F;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
- probe.irq = irq;
- probe.port[0].cmd_addr = cmd_addr;
- probe.port[0].ctl_addr = ctl_addr;
- probe.port[0].altstatus_addr = ctl_addr;
+ ap->ioaddr.cmd_addr = cmd_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
/* Let libata fill in the port details */
- ata_std_ports(&probe.port[0]);
+ ata_std_ports(&ap->ioaddr);
- /* Now add the port that is active */
- if (ata_device_add(&probe))
- return 0;
- return -ENODEV;
+ /* activate host */
+ return ata_host_activate(host, irq, ata_interrupt, IRQF_SHARED,
+ &mpiix_sht);
}
static const struct pci_device_id mpiix[] = {
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 38f99b38a5e..dbba5b77d79 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -16,33 +16,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_netcell"
-#define DRV_VERSION "0.1.6"
-
-/**
- * netcell_probe_init - check for 40/80 pin
- * @ap: Port
- *
- * Cables are handled by the RAID controller. Report 80 pin.
- */
-
-static int netcell_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-/**
- * netcell_probe_reset - Probe specified port on PATA host controller
- * @ap: Port to probe
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void netcell_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
+#define DRV_VERSION "0.1.7"
/* No PIO or DMA methods needed for this device */
@@ -81,8 +55,9 @@ static const struct ata_port_operations netcell_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = netcell_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_80wire,
/* BMDMA handling is PCI ATA format, use helpers */
.bmdma_setup = ata_bmdma_setup,
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 9944a28daa9..ebc58a907d2 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -28,16 +28,17 @@
#include <linux/libata.h>
#define DRV_NAME "pata_ns87410"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.4.6"
/**
* ns87410_pre_reset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
- * Set up cable type and use generic probe init
+ * Check enabled ports
*/
-static int ns87410_pre_reset(struct ata_port *ap)
+static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits ns87410_enable_bits[] = {
@@ -47,8 +48,8 @@ static int ns87410_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -177,6 +178,7 @@ static struct ata_port_operations ns87410_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ns87410_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ns87410_qc_issue_prot,
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index da68cd19efd..4d75d32e582 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -25,16 +25,17 @@
#include <linux/ata.h>
#define DRV_NAME "pata_oldpiix"
-#define DRV_VERSION "0.5.4"
+#define DRV_VERSION "0.5.5"
/**
* oldpiix_pre_reset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int oldpiix_pre_reset(struct ata_port *ap)
+static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits oldpiix_enable_bits[] = {
@@ -44,8 +45,8 @@ static int oldpiix_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -65,7 +66,7 @@ static void oldpiix_pata_error_handler(struct ata_port *ap)
/**
* oldpiix_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
- * @adev: um
+ * @adev: Device whose timings we are configuring
*
* Set PIO mode for device, in host controller PCI config space.
*
@@ -255,6 +256,7 @@ static const struct ata_port_operations oldpiix_pata_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = oldpiix_pata_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 3fd3a35c224..0af8a2c77cc 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -34,7 +34,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_opti"
-#define DRV_VERSION "0.2.8"
+#define DRV_VERSION "0.2.9"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -47,11 +47,12 @@ enum {
/**
* opti_pre_reset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int opti_pre_reset(struct ata_port *ap)
+static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits opti_enable_bits[] = {
@@ -62,8 +63,7 @@ static int opti_pre_reset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -198,6 +198,7 @@ static struct ata_port_operations opti_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = opti_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 9764907e8a1..2843e480f21 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_optidma"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.3.2"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -48,11 +48,12 @@ static int pci_clock; /* 0 = 33 1 = 25 */
/**
* optidma_pre_reset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int optidma_pre_reset(struct ata_port *ap)
+static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
static const struct pci_bits optidma_enable_bits = {
@@ -62,8 +63,7 @@ static int optidma_pre_reset(struct ata_port *ap)
if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -115,7 +115,7 @@ static void optidma_lock(struct ata_port *ap)
}
/**
- * optidma_set_mode - set mode data
+ * optidma_mode_setup - set mode data
* @ap: ATA interface
* @adev: ATA device
* @mode: Mode to set
@@ -128,7 +128,7 @@ static void optidma_lock(struct ata_port *ap)
* IRQ here we depend on the host set locking to avoid catastrophe.
*/
-static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+static void optidma_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode)
{
struct ata_device *pair = ata_dev_pair(adev);
int pio = adev->pio_mode - XFER_PIO_0;
@@ -202,7 +202,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
}
/**
- * optiplus_set_mode - DMA setup for Firestar Plus
+ * optiplus_mode_setup - DMA setup for Firestar Plus
* @ap: ATA port
* @adev: device
* @mode: desired mode
@@ -213,7 +213,7 @@ static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mo
* one
*/
-static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+static void optiplus_mode_setup(struct ata_port *ap, struct ata_device *adev, u8 mode)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 udcfg;
@@ -225,7 +225,7 @@ static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 m
pci_read_config_byte(pdev, 0x44, &udcfg);
if (mode <= XFER_UDMA_0) {
udcfg &= ~(1 << unit);
- optidma_set_mode(ap, adev, adev->dma_mode);
+ optidma_mode_setup(ap, adev, adev->dma_mode);
} else {
udcfg |= (1 << unit);
if (ap->port_no) {
@@ -253,7 +253,7 @@ static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 m
static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
{
- optidma_set_mode(ap, adev, adev->pio_mode);
+ optidma_mode_setup(ap, adev, adev->pio_mode);
}
/**
@@ -268,7 +268,7 @@ static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
{
- optidma_set_mode(ap, adev, adev->dma_mode);
+ optidma_mode_setup(ap, adev, adev->dma_mode);
}
/**
@@ -283,7 +283,7 @@ static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
{
- optiplus_set_mode(ap, adev, adev->pio_mode);
+ optiplus_mode_setup(ap, adev, adev->pio_mode);
}
/**
@@ -298,7 +298,7 @@ static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
{
- optiplus_set_mode(ap, adev, adev->dma_mode);
+ optiplus_mode_setup(ap, adev, adev->dma_mode);
}
/**
@@ -322,26 +322,29 @@ static u8 optidma_make_bits43(struct ata_device *adev)
}
/**
- * optidma_post_set_mode - finalize PCI setup
+ * optidma_set_mode - mode setup
* @ap: port to set up
*
- * Finalise the configuration by writing the nibble of extra bits
- * of data into the chip.
+ * Use the standard setup to tune the chipset and then finalise the
+ * configuration by writing the nibble of extra bits of data into
+ * the chip.
*/
-static void optidma_post_set_mode(struct ata_port *ap)
+static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
{
u8 r;
int nybble = 4 * ap->port_no;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
- pci_read_config_byte(pdev, 0x43, &r);
-
- r &= (0x0F << nybble);
- r |= (optidma_make_bits43(&ap->device[0]) +
- (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
-
- pci_write_config_byte(pdev, 0x43, r);
+ int rc = ata_do_set_mode(ap, r_failed);
+ if (rc == 0) {
+ pci_read_config_byte(pdev, 0x43, &r);
+
+ r &= (0x0F << nybble);
+ r |= (optidma_make_bits43(&ap->device[0]) +
+ (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+ pci_write_config_byte(pdev, 0x43, r);
+ }
+ return rc;
}
static struct scsi_host_template optidma_sht = {
@@ -381,7 +384,8 @@ static struct ata_port_operations optidma_port_ops = {
.thaw = ata_bmdma_thaw,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.error_handler = optidma_error_handler,
- .post_set_mode = optidma_post_set_mode,
+ .set_mode = optidma_set_mode,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -416,7 +420,8 @@ static struct ata_port_operations optiplus_port_ops = {
.thaw = ata_bmdma_thaw,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.error_handler = optidma_error_handler,
- .post_set_mode = optidma_post_set_mode,
+ .set_mode = optidma_set_mode,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 103720f873c..75dc84797ff 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.0"
+#define DRV_VERSION "0.3.1"
/*
* Private data structure to glue stuff together
@@ -54,6 +54,39 @@ struct ata_pcmcia_info {
dev_node_t node;
};
+/**
+ * pcmcia_set_mode - PCMCIA specific mode setup
+ * @ap: Port
+ * @r_failed_dev: Return pointer for failed device
+ *
+ * Perform the tuning and setup of the devices and timings, which
+ * for PCMCIA is the same as any other controller. We wrap it however
+ * as we need to spot hardware with incorrect or missing master/slave
+ * decode, which alas is embarrassingly common in the PC world
+ */
+
+static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *master = &ap->device[0];
+ struct ata_device *slave = &ap->device[1];
+
+ if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
+ return ata_do_set_mode(ap, r_failed_dev);
+
+ if (memcmp(master->id + ATA_ID_FW_REV, slave->id + ATA_ID_FW_REV,
+ ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
+ {
+ /* Suspicious match, but could be two cards from
+ the same vendor - check serial */
+ if (memcmp(master->id + ATA_ID_SERNO, slave->id + ATA_ID_SERNO,
+ ATA_ID_SERNO_LEN) == 0 && master->id[ATA_ID_SERNO] >> 8) {
+ ata_dev_printk(slave, KERN_WARNING, "is a ghost device, ignoring.\n");
+ ata_dev_disable(slave);
+ }
+ }
+ return ata_do_set_mode(ap, r_failed_dev);
+}
+
static struct scsi_host_template pcmcia_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -73,6 +106,7 @@ static struct scsi_host_template pcmcia_sht = {
};
static struct ata_port_operations pcmcia_port_ops = {
+ .set_mode = pcmcia_set_mode,
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -84,13 +118,13 @@ static struct ata_port_operations pcmcia_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer_noirq,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -111,7 +145,8 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
static int pcmcia_init_one(struct pcmcia_device *pdev)
{
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
struct ata_pcmcia_info *info;
tuple_t tuple;
struct {
@@ -255,24 +290,24 @@ next_entry:
* Having done the PCMCIA plumbing the ATA side is relatively
* sane.
*/
-
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
- ae.port_ops = &pcmcia_port_ops;
- ae.sht = &pcmcia_sht;
- ae.n_ports = 1;
- ae.pio_mask = 1; /* ISA so PIO 0 cycles */
- ae.irq = pdev->irq.AssignedIRQ;
- ae.irq_flags = IRQF_SHARED;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = io_addr;
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ata_std_ports(&ae.port[0]);
-
- ret = -ENODEV;
- if (ata_device_add(&ae) == 0)
+ ret = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto failed;
+ ap = host->ports[0];
+
+ ap->ops = &pcmcia_port_ops;
+ ap->pio_mask = 1; /* ISA so PIO 0 cycles */
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->ioaddr.cmd_addr = io_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ata_std_ports(&ap->ioaddr);
+
+ /* activate */
+ ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
+ IRQF_SHARED, &pcmcia_sht);
+ if (ret)
goto failed;
info->ndev = 1;
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 93bcdadb7be..0d2cc49fde4 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc2027x"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "0.9"
#undef PDC_DEBUG
#ifdef PDC_DEBUG
@@ -66,8 +66,10 @@ static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *e
static void pdc2027x_error_handler(struct ata_port *ap);
static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
-static void pdc2027x_post_set_mode(struct ata_port *ap);
static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
+static int pdc2027x_cable_detect(struct ata_port *ap);
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
/*
* ATA Timing Tables based on 133MHz controller clock.
@@ -146,6 +148,7 @@ static struct scsi_host_template pdc2027x_sht = {
static struct ata_port_operations pdc2027x_pata100_ops = {
.port_disable = ata_port_disable,
+ .mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -166,8 +169,8 @@ static struct ata_port_operations pdc2027x_pata100_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = pdc2027x_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pdc2027x_cable_detect,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -179,7 +182,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.port_disable = ata_port_disable,
.set_piomode = pdc2027x_set_piomode,
.set_dmamode = pdc2027x_set_dmamode,
- .post_set_mode = pdc2027x_post_set_mode,
+ .set_mode = pdc2027x_set_mode,
+ .mode_filter = pdc2027x_mode_filter,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
@@ -200,8 +204,8 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = pdc2027x_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pdc2027x_cable_detect,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -212,7 +216,6 @@ static struct ata_port_operations pdc2027x_pata133_ops = {
static struct ata_port_info pdc2027x_port_info[] = {
/* PDC_UDMA_100 */
{
- .sht = &pdc2027x_sht,
.flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
ATA_FLAG_MMIO,
.pio_mask = 0x1f, /* pio0-4 */
@@ -222,7 +225,6 @@ static struct ata_port_info pdc2027x_port_info[] = {
},
/* PDC_UDMA_133 */
{
- .sht = &pdc2027x_sht,
.flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
ATA_FLAG_MMIO,
.pio_mask = 0x1f, /* pio0-4 */
@@ -261,7 +263,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade
}
/**
- * pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ * pdc2027x_pata_cable_detect - Probe host controller cable detect info
* @ap: Port for which cable detect info is desired
*
* Read 80c cable indicator from Promise extended register.
@@ -270,7 +272,7 @@ static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *ade
* LOCKING:
* None (inherited from caller).
*/
-static void pdc2027x_cbl_detect(struct ata_port *ap)
+static int pdc2027x_cable_detect(struct ata_port *ap)
{
u32 cgcr;
@@ -281,13 +283,10 @@ static void pdc2027x_cbl_detect(struct ata_port *ap)
PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
- ap->cbl = ATA_CBL_PATA80;
- return;
-
+ return ATA_CBL_PATA80;
cbl40:
printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
+ return ATA_CBL_PATA40;
}
/**
@@ -302,6 +301,7 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
/**
* pdc2027x_prereset - prereset for PATA host controller
* @ap: Target port
+ * @deadline: deadline jiffies for the operation
*
* Probeinit including cable detection.
*
@@ -309,13 +309,12 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
* None (inherited from caller).
*/
-static int pdc2027x_prereset(struct ata_port *ap)
+static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
{
/* Check whether port enabled */
if (!pdc2027x_port_enabled(ap))
return -ENOENT;
- pdc2027x_cbl_detect(ap);
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
/**
@@ -334,6 +333,32 @@ static void pdc2027x_error_handler(struct ata_port *ap)
}
/**
+ * pdc2720x_mode_filter - mode selection filter
+ * @adev: ATA device
+ * @mask: list of modes proposed
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ unsigned char model_num[ATA_ID_PROD_LEN + 1];
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (adev->class != ATA_DEV_ATA || adev->devno == 0 || pair == NULL)
+ return ata_pci_default_filter(adev, mask);
+
+ /* Check for slave of a Maxtor at UDMA6 */
+ ata_id_c_string(pair->id, model_num, ATA_ID_PROD,
+ ATA_ID_PROD_LEN + 1);
+ /* If the master is a maxtor in UDMA6 then the slave should not use UDMA 6 */
+ if(strstr(model_num, "Maxtor") == 0 && pair->dma_mode == XFER_UDMA_6)
+ mask &= ~ (1 << (6 + ATA_SHIFT_UDMA));
+
+ return ata_pci_default_filter(adev, mask);
+}
+
+/**
* pdc2027x_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port to configure
* @adev: um
@@ -444,17 +469,22 @@ static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
}
/**
- * pdc2027x_post_set_mode - Set the timing registers back to correct values.
+ * pdc2027x_set_mode - Set the timing registers back to correct values.
* @ap: Port to configure
+ * @r_failed: Returned device for failure
*
* The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
* automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
* This function overwrites the possibly incorrect values set by the hardware to be correct.
*/
-static void pdc2027x_post_set_mode(struct ata_port *ap)
+static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
{
int i;
+ i = ata_do_set_mode(ap, r_failed);
+ if (i < 0)
+ return i;
+
for (i = 0; i < ATA_MAX_DEVICES; i++) {
struct ata_device *dev = &ap->device[i];
@@ -476,6 +506,7 @@ static void pdc2027x_post_set_mode(struct ata_port *ap)
}
}
}
+ return 0;
}
/**
@@ -521,12 +552,12 @@ static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
/**
* pdc_read_counter - Read the ctr counter
- * @probe_ent: for the port address
+ * @host: target ATA host
*/
-static long pdc_read_counter(struct ata_probe_ent *probe_ent)
+static long pdc_read_counter(struct ata_host *host)
{
- void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
long counter;
int retry = 1;
u32 bccrl, bccrh, bccrlv, bccrhv;
@@ -564,12 +595,12 @@ retry:
* adjust_pll - Adjust the PLL input clock in Hz.
*
* @pdc_controller: controller specific information
- * @probe_ent: For the port address
+ * @host: target ATA host
* @pll_clock: The input of PLL in HZ
*/
-static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
+static void pdc_adjust_pll(struct ata_host *host, long pll_clock, unsigned int board_idx)
{
- void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
u16 pll_ctl;
long pll_clock_khz = pll_clock / 1000;
long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
@@ -649,19 +680,19 @@ static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsi
/**
* detect_pll_input_clock - Detect the PLL input clock in Hz.
- * @probe_ent: for the port address
+ * @host: target ATA host
* Ex. 16949000 on 33MHz PCI bus for pdc20275.
* Half of the PCI clock.
*/
-static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
+static long pdc_detect_pll_input_clock(struct ata_host *host)
{
- void __iomem *mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
u32 scr;
long start_count, end_count;
long pll_clock;
/* Read current counter value */
- start_count = pdc_read_counter(probe_ent);
+ start_count = pdc_read_counter(host);
/* Start the test mode */
scr = readl(mmio_base + PDC_SYS_CTL);
@@ -673,7 +704,7 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
mdelay(100);
/* Read the counter values again */
- end_count = pdc_read_counter(probe_ent);
+ end_count = pdc_read_counter(host);
/* Stop the test mode */
scr = readl(mmio_base + PDC_SYS_CTL);
@@ -692,11 +723,10 @@ static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
/**
* pdc_hardware_init - Initialize the hardware.
- * @pdev: instance of pci_dev found
- * @pdc_controller: controller specific information
- * @pe: for the port address
+ * @host: target ATA host
+ * @board_idx: board identifier
*/
-static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
+static int pdc_hardware_init(struct ata_host *host, unsigned int board_idx)
{
long pll_clock;
@@ -706,15 +736,15 @@ static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, uns
* Ex. 25MHz or 40MHz, we have to adjust the cycle_time.
* The pdc20275 controller employs PLL circuit to help correct timing registers setting.
*/
- pll_clock = pdc_detect_pll_input_clock(pe);
+ pll_clock = pdc_detect_pll_input_clock(host);
if (pll_clock < 0) /* counter overflow? Try again. */
- pll_clock = pdc_detect_pll_input_clock(pe);
+ pll_clock = pdc_detect_pll_input_clock(host);
- dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
+ dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
/* Adjust PLL control register */
- pdc_adjust_pll(pe, pll_clock, board_idx);
+ pdc_adjust_pll(host, pll_clock, board_idx);
return 0;
}
@@ -746,8 +776,7 @@ static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base)
* Called when an instance of PCI adapter is inserted.
* This function checks whether the hardware is supported,
* initialize hardware and register an instance of ata_host to
- * libata by providing struct ata_probe_ent and ata_device_add().
- * (implements struct pci_driver.probe() )
+ * libata. (implements struct pci_driver.probe() )
*
* @pdev: instance of pci_dev found
* @ent: matching entry in the id_tbl[]
@@ -756,14 +785,21 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
{
static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
-
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[] =
+ { &pdc2027x_port_info[board_idx], NULL };
+ struct ata_host *host;
void __iomem *mmio_base;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* alloc host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -771,6 +807,7 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
rc = pcim_iomap_regions(pdev, 1 << PDC_MMIO_BAR, DRV_NAME);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -780,46 +817,22 @@ static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_de
if (rc)
return rc;
- /* Prepare the probe entry */
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = pdc2027x_port_info[board_idx].sht;
- probe_ent->port_flags = pdc2027x_port_info[board_idx].flags;
- probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc2027x_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops;
+ mmio_base = host->iomap[PDC_MMIO_BAR];
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
+ pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
+ host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
+ pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
+ host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
- mmio_base = probe_ent->iomap[PDC_MMIO_BAR];
-
- pdc_ata_setup_port(&probe_ent->port[0], mmio_base + 0x17c0);
- probe_ent->port[0].bmdma_addr = mmio_base + 0x1000;
- pdc_ata_setup_port(&probe_ent->port[1], mmio_base + 0x15c0);
- probe_ent->port[1].bmdma_addr = mmio_base + 0x1008;
-
- probe_ent->n_ports = 2;
-
- pci_set_master(pdev);
//pci_enable_intx(pdev);
/* initialize adapter */
- if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
+ if (pdc_hardware_init(host, board_idx) != 0)
return -EIO;
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &pdc2027x_sht);
}
/**
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 0a149339891..ee636beb05e 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -22,45 +22,17 @@
#include <linux/libata.h>
#define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.0"
+#define DRV_VERSION "0.4.2"
-/**
- * pdc2024x_pre_reset - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generic probe init
- */
-
-static int pdc2024x_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-
-static void pdc2024x_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
-static int pdc2026x_pre_reset(struct ata_port *ap)
+static int pdc2026x_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u16 cis;
pci_read_config_word(pdev, 0x50, &cis);
if (cis & (1 << (10 + ap->port_no)))
- ap->cbl = ATA_CBL_PATA80;
- else
- ap->cbl = ATA_CBL_PATA40;
-
- return ata_std_prereset(ap);
-}
-
-static void pdc2026x_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
}
/**
@@ -244,7 +216,6 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
/**
* pdc2026x_dev_config - device setup hook
- * @ap: ATA port
* @adev: newly found device
*
* Perform chip specific early setup. We need to lock the transfer
@@ -252,7 +223,7 @@ static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
* barf.
*/
-static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
+static void pdc2026x_dev_config(struct ata_device *adev)
{
adev->max_sectors = 256;
}
@@ -292,8 +263,9 @@ static struct ata_port_operations pdc2024x_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = pdc2024x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -326,8 +298,9 @@ static struct ata_port_operations pdc2026x_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = pdc2026x_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = pdc2026x_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = pdc2026x_bmdma_start,
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 4b82a5435a4..a0a650c7f27 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -80,13 +80,13 @@ static struct ata_port_operations pata_platform_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_data_xfer_noirq,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -135,7 +135,8 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
static int __devinit pata_platform_probe(struct platform_device *pdev)
{
struct resource *io_res, *ctl_res;
- struct ata_probe_ent ae;
+ struct ata_host *host;
+ struct ata_port *ap;
unsigned int mmio;
/*
@@ -175,44 +176,41 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
/*
* Now that that's out of the way, wire up the port..
*/
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
- ae.port_ops = &pata_platform_port_ops;
- ae.sht = &pata_platform_sht;
- ae.n_ports = 1;
- ae.pio_mask = pio_mask;
- ae.irq = platform_get_irq(pdev, 0);
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ return -ENOMEM;
+ ap = host->ports[0];
+
+ ap->ops = &pata_platform_port_ops;
+ ap->pio_mask = pio_mask;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
/*
* Handle the MMIO case
*/
if (mmio) {
- ae.port[0].cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
+ ap->ioaddr.cmd_addr = devm_ioremap(&pdev->dev, io_res->start,
io_res->end - io_res->start + 1);
- ae.port[0].ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
+ ap->ioaddr.ctl_addr = devm_ioremap(&pdev->dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
} else {
- ae.port[0].cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
+ ap->ioaddr.cmd_addr = devm_ioport_map(&pdev->dev, io_res->start,
io_res->end - io_res->start + 1);
- ae.port[0].ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
+ ap->ioaddr.ctl_addr = devm_ioport_map(&pdev->dev, ctl_res->start,
ctl_res->end - ctl_res->start + 1);
}
- if (!ae.port[0].cmd_addr || !ae.port[0].ctl_addr) {
+ if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) {
dev_err(&pdev->dev, "failed to map IO/CTL base\n");
return -ENOMEM;
}
- ae.port[0].altstatus_addr = ae.port[0].ctl_addr;
+ ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
- pata_platform_setup_port(&ae.port[0], pdev->dev.platform_data);
+ pata_platform_setup_port(&ap->ioaddr, pdev->dev.platform_data);
- if (unlikely(ata_device_add(&ae) == 0))
- return -ENODEV;
-
- return 0;
+ /* activate */
+ return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
+ 0, &pata_platform_sht);
}
/**
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index c3810012f3f..27685ce63ce 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -183,13 +183,13 @@ static struct ata_port_operations qdi6500_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = qdi_qc_issue_prot,
.data_xfer = qdi_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -211,13 +211,13 @@ static struct ata_port_operations qdi6580_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = qdi_qc_issue_prot,
.data_xfer = qdi_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -238,8 +238,9 @@ static struct ata_port_operations qdi6580_port_ops = {
static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
{
- struct ata_probe_ent ae;
struct platform_device *pdev;
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *io_addr, *ctl_addr;
int ret;
@@ -257,34 +258,31 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
if (!io_addr || !ctl_addr)
goto fail;
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
+ ret = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto fail;
+ ap = host->ports[0];
if (type == 6580) {
- ae.port_ops = &qdi6580_port_ops;
- ae.pio_mask = 0x1F;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ap->ops = &qdi6580_port_ops;
+ ap->pio_mask = 0x1F;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
} else {
- ae.port_ops = &qdi6500_port_ops;
- ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
- ATA_FLAG_NO_IORDY;
+ ap->ops = &qdi6500_port_ops;
+ ap->pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
+ ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
}
- ae.sht = &qdi_sht;
- ae.n_ports = 1;
- ae.irq = irq;
- ae.irq_flags = 0;
- ae.port[0].cmd_addr = io_addr;
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ata_std_ports(&ae.port[0]);
+ ap->ioaddr.cmd_addr = io_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ata_std_ports(&ap->ioaddr);
/*
* Hook in a private data structure per channel
*/
- ae.private_data = &qdi_data[nr_qdi_host];
+ ap->private_data = &qdi_data[nr_qdi_host];
qdi_data[nr_qdi_host].timing = port;
qdi_data[nr_qdi_host].fast = fast;
@@ -292,8 +290,9 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i
printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
- ret = -ENODEV;
- if (!ata_device_add(&ae))
+ /* activate */
+ ret = ata_host_activate(host, irq, ata_interrupt, 0, &qdi_sht);
+ if (ret)
goto fail;
qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 9a9132c9e33..1c54673e008 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -24,40 +24,12 @@
#include <linux/ata.h>
#define DRV_NAME "pata_radisys"
-#define DRV_VERSION "0.4.1"
-
-/**
- * radisys_probe_init - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generic probe init
- */
-
-static int radisys_pre_reset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA80;
- return ata_std_prereset(ap);
-}
-
-
-/**
- * radisys_pata_error_handler - Probe specified port on PATA host controller
- * @ap: Port to probe
- * @classes:
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void radisys_pata_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
+#define DRV_VERSION "0.4.4"
/**
* radisys_set_piomode - Initialize host controller PATA PIO timings
- * @ap: Port whose timings we are configuring
- * @adev: um
+ * @ap: ATA port
+ * @adev: Device whose timings we are configuring
*
* Set PIO mode for device, in host controller PCI config space.
*
@@ -248,8 +220,9 @@ static const struct ata_port_operations radisys_pata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = radisys_pata_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_unknown,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index f522daa2a6a..85c45290eee 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -25,31 +25,6 @@
/**
- * rz1000_prereset - probe begin
- * @ap: ATA port
- *
- * Set up cable type and use generics
- */
-
-static int rz1000_prereset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
-}
-
-/**
- * rz1000_error_handler - probe reset
- * @ap: ATA port
- *
- * Perform the ATA standard reset sequence
- */
-
-static void rz1000_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-/**
* rz1000_set_mode - mode setting function
* @ap: ATA interface
* @unused: returned device on set_mode failure
@@ -122,8 +97,9 @@ static struct ata_port_operations rz1000_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = rz1000_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 93b3ed0f9e8..66e8ff467c8 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -216,6 +216,7 @@ static struct ata_port_operations sc1200_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index f3ed141fdc0..5df354d573e 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -1016,7 +1016,6 @@ static const struct ata_port_operations scc_pata_ops = {
.error_handler = scc_error_handler,
.post_internal_cmd = scc_bmdma_stop,
- .irq_handler = ata_interrupt,
.irq_clear = scc_bmdma_irq_clear,
.irq_on = scc_irq_on,
.irq_ack = scc_irq_ack,
@@ -1027,7 +1026,6 @@ static const struct ata_port_operations scc_pata_ops = {
static struct ata_port_info scc_port_info[] = {
{
- .sht = &scc_sht,
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x00,
@@ -1040,10 +1038,10 @@ static struct ata_port_info scc_port_info[] = {
* scc_reset_controller - initialize SCC PATA controller.
*/
-static int scc_reset_controller(struct ata_probe_ent *probe_ent)
+static int scc_reset_controller(struct ata_host *host)
{
- void __iomem *ctrl_base = probe_ent->iomap[SCC_CTRL_BAR];
- void __iomem *bmid_base = probe_ent->iomap[SCC_BMID_BAR];
+ void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR];
+ void __iomem *bmid_base = host->iomap[SCC_BMID_BAR];
void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
@@ -1104,17 +1102,15 @@ static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base)
ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
}
-static int scc_host_init(struct ata_probe_ent *probe_ent)
+static int scc_host_init(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
int rc;
- rc = scc_reset_controller(probe_ent);
+ rc = scc_reset_controller(host);
if (rc)
return rc;
- probe_ent->n_ports = 1;
-
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
return rc;
@@ -1122,7 +1118,7 @@ static int scc_host_init(struct ata_probe_ent *probe_ent)
if (rc)
return rc;
- scc_setup_ports(&probe_ent->port[0], probe_ent->iomap[SCC_BMID_BAR]);
+ scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]);
pci_set_master(pdev);
@@ -1145,14 +1141,18 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
unsigned int board_idx = (unsigned int) ent->driver_data;
+ const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev,
"version " DRV_VERSION "\n");
+ host = ata_port_alloc_pinfo(&pdev->dev, ppi, 1);
+ if (!host)
+ return -ENOMEM;
+
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -1162,33 +1162,14 @@ static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- return -ENOMEM;
-
- probe_ent->dev = dev;
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = scc_port_info[board_idx].sht;
- probe_ent->port_flags = scc_port_info[board_idx].flags;
- probe_ent->pio_mask = scc_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = scc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = scc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- rc = scc_host_init(probe_ent);
+ rc = scc_host_init(host);
if (rc)
return rc;
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &scc_sht);
}
static struct pci_driver scc_pci_driver = {
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 598eef810a7..b6e020383dd 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -1,5 +1,5 @@
/*
- * ata-serverworks.c - Serverworks PATA for new ATA layer
+ * pata_serverworks.c - Serverworks PATA for new ATA layer
* (C) 2005 Red Hat Inc
* Alan Cox <alan@redhat.com>
*
@@ -137,14 +137,16 @@ static struct sv_cable_table cable_detect[] = {
};
/**
- * serverworks_pre_reset - cable detection
+ * serverworks_cable_detect - cable detection
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Perform cable detection according to the device and subvendor
* identifications
*/
-static int serverworks_pre_reset(struct ata_port *ap) {
+static int serverworks_cable_detect(struct ata_port *ap)
+{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct sv_cable_table *cb = cable_detect;
@@ -152,8 +154,7 @@ static int serverworks_pre_reset(struct ata_port *ap) {
if (cb->device == pdev->device &&
(cb->subvendor == pdev->subsystem_vendor ||
cb->subvendor == PCI_ANY_ID)) {
- ap->cbl = cb->cable_detect(ap);
- return ata_std_prereset(ap);
+ return cb->cable_detect(ap);
}
cb++;
}
@@ -162,11 +163,6 @@ static int serverworks_pre_reset(struct ata_port *ap) {
return -1; /* kill compiler warning */
}
-static void serverworks_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
/**
* serverworks_is_csb - Check for CSB or OSB
* @pdev: PCI device to check
@@ -191,31 +187,31 @@ static u8 serverworks_is_csb(struct pci_dev *pdev)
/**
* serverworks_osb4_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
+ * @mask: Mask of proposed modes
*
* Filter the offered modes for the device to apply controller
* specific rules. OSB4 requires no UDMA for disks due to a FIFO
* bug we hit.
*/
-static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long serverworks_osb4_filter(struct ata_device *adev, unsigned long mask)
{
if (adev->class == ATA_DEV_ATA)
mask &= ~ATA_MASK_UDMA;
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
/**
* serverworks_csb_filter - mode selection filter
- * @ap: ATA interface
* @adev: ATA device
+ * @mask: Mask of proposed modes
*
* Check the blacklist and disable UDMA5 if matched
*/
-static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+static unsigned long serverworks_csb_filter(struct ata_device *adev, unsigned long mask)
{
const char *p;
char model_num[ATA_ID_PROD_LEN + 1];
@@ -223,7 +219,7 @@ static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct at
/* Disk, UDMA */
if (adev->class != ATA_DEV_ATA)
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
/* Actually do need to check */
ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num));
@@ -232,7 +228,7 @@ static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct at
if (!strcmp(p, model_num))
mask &= ~(0x1F << ATA_SHIFT_UDMA);
}
- return ata_pci_default_filter(ap, adev, mask);
+ return ata_pci_default_filter(adev, mask);
}
@@ -339,8 +335,9 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = serverworks_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = serverworks_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -374,8 +371,9 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = serverworks_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = serverworks_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index dab2889a556..a5886f061c0 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.4.6"
/**
* sil680_selreg - return register base
@@ -91,20 +91,16 @@ static int sil680_cable_detect(struct ata_port *ap) {
return ATA_CBL_PATA40;
}
-static int sil680_pre_reset(struct ata_port *ap)
-{
- ap->cbl = sil680_cable_detect(ap);
- return ata_std_prereset(ap);
-}
-
/**
* sil680_bus_reset - reset the SIL680 bus
* @ap: ATA port to reset
+ * @deadline: deadline jiffies for the operation
*
* Perform the SIL680 housekeeping when doing an ATA bus reset
*/
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
+static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+ unsigned long deadline)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned long addr = sil680_selreg(ap, 0);
@@ -114,12 +110,12 @@ static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
pci_write_config_byte(pdev, addr, reset | 0x03);
udelay(25);
pci_write_config_byte(pdev, addr, reset);
- return ata_std_softreset(ap, classes);
+ return ata_std_softreset(ap, classes, deadline);
}
static void sil680_error_handler(struct ata_port *ap)
{
- ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, ata_std_prereset, sil680_bus_reset, NULL, ata_std_postreset);
}
/**
@@ -257,6 +253,7 @@ static struct ata_port_operations sil680_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = sil680_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = sil680_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 8dc3bc4f586..f5838cc1172 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -35,7 +35,7 @@
#include "sis.h"
#define DRV_NAME "pata_sis"
-#define DRV_VERSION "0.5.0"
+#define DRV_VERSION "0.5.1"
struct sis_chipset {
u16 device; /* PCI host ID */
@@ -86,106 +86,58 @@ static int sis_port_base(struct ata_device *adev)
}
/**
- * sis_133_pre_reset - check for 40/80 pin
+ * sis_133_cable_detect - check for 40/80 pin
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
* Perform cable detection for the later UDMA133 capable
* SiS chipset.
*/
-static int sis_133_pre_reset(struct ata_port *ap)
+static int sis_133_cable_detect(struct ata_port *ap)
{
- static const struct pci_bits sis_enable_bits[] = {
- { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
- { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
- };
-
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u16 tmp;
- if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
- return -ENOENT;
-
/* The top bit of this register is the cable detect bit */
pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
if ((tmp & 0x8000) && !sis_short_ata40(pdev))
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
-
- return ata_std_prereset(ap);
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
}
/**
- * sis_error_handler - Probe specified port on PATA host controller
- * @ap: Port to probe
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void sis_133_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, sis_133_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
-
-
-/**
- * sis_66_pre_reset - check for 40/80 pin
+ * sis_66_cable_detect - check for 40/80 pin
* @ap: Port
+ * @deadline: deadline jiffies for the operation
*
* Perform cable detection on the UDMA66, UDMA100 and early UDMA133
* SiS IDE controllers.
*/
-static int sis_66_pre_reset(struct ata_port *ap)
+static int sis_66_cable_detect(struct ata_port *ap)
{
- static const struct pci_bits sis_enable_bits[] = {
- { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
- { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
- };
-
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 tmp;
- if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
- return 0;
- }
/* Older chips keep cable detect in bits 4/5 of reg 0x48 */
pci_read_config_byte(pdev, 0x48, &tmp);
tmp >>= ap->port_no;
if ((tmp & 0x10) && !sis_short_ata40(pdev))
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
-
- return ata_std_prereset(ap);
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
}
-/**
- * sis_66_error_handler - Probe specified port on PATA host controller
- * @ap: Port to probe
- * @classes:
- *
- * LOCKING:
- * None (inherited from caller).
- */
-
-static void sis_66_error_handler(struct ata_port *ap)
-{
- ata_bmdma_drive_eh(ap, sis_66_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
-}
/**
- * sis_old_pre_reset - probe begin
+ * sis_pre_reset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sis_old_pre_reset(struct ata_port *ap)
+static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits sis_enable_bits[] = {
{ 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
@@ -194,27 +146,24 @@ static int sis_old_pre_reset(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
- return 0;
- }
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ return ata_std_prereset(ap, deadline);
}
/**
- * sis_old_error_handler - Probe specified port on PATA host controller
+ * sis_error_handler - Probe specified port on PATA host controller
* @ap: Port to probe
*
* LOCKING:
* None (inherited from caller).
*/
-static void sis_old_error_handler(struct ata_port *ap)
+static void sis_error_handler(struct ata_port *ap)
{
- ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, sis_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
}
/**
@@ -494,7 +443,7 @@ static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *a
int drive_pci = sis_port_base(adev);
u16 timing;
- const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+ static const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
pci_read_config_word(pdev, drive_pci, &timing);
@@ -531,8 +480,8 @@ static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
u32 reg54;
/* bits 4- cycle time 8 - cvs time */
- const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
- const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
+ static const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
+ static const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
/* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
pci_read_config_dword(pdev, 0x54, &reg54);
@@ -595,8 +544,9 @@ static const struct ata_port_operations sis_133_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = sis_133_error_handler,
+ .error_handler = sis_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = sis_133_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -628,8 +578,9 @@ static const struct ata_port_operations sis_133_early_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = sis_66_error_handler,
+ .error_handler = sis_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = sis_66_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -661,9 +612,9 @@ static const struct ata_port_operations sis_100_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = sis_66_error_handler,
+ .error_handler = sis_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
-
+ .cable_detect = sis_66_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -692,10 +643,11 @@ static const struct ata_port_operations sis_66_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
+ .cable_detect = sis_66_cable_detect,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = sis_66_error_handler,
+ .error_handler = sis_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.bmdma_setup = ata_bmdma_setup,
@@ -728,8 +680,9 @@ static const struct ata_port_operations sis_old_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = sis_old_error_handler,
+ .error_handler = sis_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index b681441cfcb..9aeffdbe282 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -44,11 +44,12 @@ enum {
/**
* sl82c105_pre_reset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int sl82c105_pre_reset(struct ata_port *ap)
+static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits sl82c105_enable_bits[] = {
{ 0x40, 1, 0x01, 0x01 },
@@ -58,8 +59,7 @@ static int sl82c105_pre_reset(struct ata_port *ap)
if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
@@ -238,6 +238,7 @@ static struct ata_port_operations sl82c105_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = sl82c105_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = sl82c105_bmdma_start,
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 71418f2a0cd..349887bf5b9 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -43,16 +43,17 @@
#include <linux/libata.h>
#define DRV_NAME "pata_triflex"
-#define DRV_VERSION "0.2.7"
+#define DRV_VERSION "0.2.8"
/**
* triflex_prereset - probe begin
* @ap: ATA port
+ * @deadline: deadline jiffies for the operation
*
* Set up cable type and use generic probe init
*/
-static int triflex_prereset(struct ata_port *ap)
+static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
{
static const struct pci_bits triflex_enable_bits[] = {
{ 0x80, 1, 0x01, 0x01 },
@@ -63,8 +64,8 @@ static int triflex_prereset(struct ata_port *ap)
if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
return -ENOENT;
- ap->cbl = ATA_CBL_PATA40;
- return ata_std_prereset(ap);
+
+ return ata_std_prereset(ap, deadline);
}
@@ -214,6 +215,7 @@ static struct ata_port_operations triflex_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = triflex_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = triflex_bmdma_start,
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 946ade0e1f1..362beb2f489 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -62,7 +62,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_via"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.3.1"
/*
* The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -135,19 +135,26 @@ static const struct via_isa_bridge {
*/
static int via_cable_detect(struct ata_port *ap) {
+ const struct via_isa_bridge *config = ap->host->private_data;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 ata66;
+ /* Early chips are 40 wire */
+ if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
+ return ATA_CBL_PATA40;
+ /* UDMA 66 chips have only drive side logic */
+ else if((config->flags & VIA_UDMA) < VIA_UDMA_100)
+ return ATA_CBL_PATA_UNK;
+ /* UDMA 100 or later */
pci_read_config_dword(pdev, 0x50, &ata66);
/* Check both the drive cable reporting bits, we might not have
two drives */
if (ata66 & (0x10100000 >> (16 * ap->port_no)))
return ATA_CBL_PATA80;
- else
- return ATA_CBL_PATA40;
+ return ATA_CBL_PATA40;
}
-static int via_pre_reset(struct ata_port *ap)
+static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
{
const struct via_isa_bridge *config = ap->host->private_data;
@@ -156,23 +163,12 @@ static int via_pre_reset(struct ata_port *ap)
{ 0x40, 1, 0x02, 0x02 },
{ 0x40, 1, 0x01, 0x01 }
};
-
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-
if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no]))
return -ENOENT;
}
- if ((config->flags & VIA_UDMA) >= VIA_UDMA_100)
- ap->cbl = via_cable_detect(ap);
- /* The UDMA66 series has no cable detect so do drive side detect */
- else if ((config->flags & VIA_UDMA) < VIA_UDMA_66)
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA_UNK;
-
-
- return ata_std_prereset(ap);
+ return ata_std_prereset(ap, deadline);
}
@@ -327,6 +323,7 @@ static struct ata_port_operations via_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = via_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = via_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
@@ -362,6 +359,7 @@ static struct ata_port_operations via_port_ops_noirq = {
.thaw = ata_bmdma_thaw,
.error_handler = via_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = via_cable_detect,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 6c111035fc8..cc4ad271afb 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -8,7 +8,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -36,7 +35,7 @@ static int probe_winbond = 1;
static int probe_winbond;
#endif
-static spinlock_t winbond_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(winbond_lock);
static void winbond_writecfg(unsigned long port, u8 reg, u8 val)
{
@@ -152,13 +151,13 @@ static struct ata_port_operations winbond_port_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_40wire,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
.data_xfer = winbond_data_xfer,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -179,11 +178,9 @@ static struct ata_port_operations winbond_port_ops = {
static __init int winbond_init_one(unsigned long port)
{
- struct ata_probe_ent ae;
struct platform_device *pdev;
- int ret;
u8 reg;
- int i;
+ int i, rc;
reg = winbond_readcfg(port, 0x81);
reg |= 0x80; /* jumpered mode off */
@@ -202,58 +199,56 @@ static __init int winbond_init_one(unsigned long port)
for (i = 0; i < 2 ; i ++) {
unsigned long cmd_port = 0x1F0 - (0x80 * i);
+ struct ata_host *host;
+ struct ata_port *ap;
void __iomem *cmd_addr, *ctl_addr;
- if (reg & (1 << i)) {
- /*
- * Fill in a probe structure first of all
- */
-
- pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
- if (IS_ERR(pdev))
- return PTR_ERR(pdev);
-
- cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
- ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
- if (!cmd_addr || !ctl_addr) {
- platform_device_unregister(pdev);
- return -ENOMEM;
- }
-
- memset(&ae, 0, sizeof(struct ata_probe_ent));
- INIT_LIST_HEAD(&ae.node);
- ae.dev = &pdev->dev;
-
- ae.port_ops = &winbond_port_ops;
- ae.pio_mask = 0x1F;
-
- ae.sht = &winbond_sht;
-
- ae.n_ports = 1;
- ae.irq = 14 + i;
- ae.irq_flags = 0;
- ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
- ae.port[0].cmd_addr = cmd_addr;
- ae.port[0].altstatus_addr = ctl_addr;
- ae.port[0].ctl_addr = ctl_addr;
- ata_std_ports(&ae.port[0]);
- /*
- * Hook in a private data structure per channel
- */
- ae.private_data = &winbond_data[nr_winbond_host];
- winbond_data[nr_winbond_host].config = port;
- winbond_data[nr_winbond_host].platform_dev = pdev;
-
- ret = ata_device_add(&ae);
- if (ret == 0) {
- platform_device_unregister(pdev);
- return -ENODEV;
- }
- winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
- }
+ if (!(reg & (1 << i)))
+ continue;
+
+ pdev = platform_device_register_simple(DRV_NAME, nr_winbond_host, NULL, 0);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ rc = -ENOMEM;
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host)
+ goto err_unregister;
+
+ rc = -ENOMEM;
+ cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
+ ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+ if (!cmd_addr || !ctl_addr)
+ goto err_unregister;
+
+ ap = host->ports[0];
+ ap->ops = &winbond_port_ops;
+ ap->pio_mask = 0x1F;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->ioaddr.cmd_addr = cmd_addr;
+ ap->ioaddr.altstatus_addr = ctl_addr;
+ ap->ioaddr.ctl_addr = ctl_addr;
+ ata_std_ports(&ap->ioaddr);
+
+ /* hook in a private data structure per channel */
+ host->private_data = &winbond_data[nr_winbond_host];
+ winbond_data[nr_winbond_host].config = port;
+ winbond_data[nr_winbond_host].platform_dev = pdev;
+
+ /* activate */
+ rc = ata_host_activate(host, 14 + i, ata_interrupt, 0,
+ &winbond_sht);
+ if (rc)
+ goto err_unregister;
+
+ winbond_host[nr_winbond_host++] = dev_get_drvdata(&pdev->dev);
}
return 0;
+
+ err_unregister:
+ platform_device_unregister(pdev);
+ return rc;
}
/**
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 5dd3ca8b5f2..52b69530ab2 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -52,9 +52,9 @@
/* macro to calculate base address for ADMA regs */
#define ADMA_REGS(base,port_no) ((base) + 0x80 + ((port_no) * 0x20))
-/* macro to obtain addresses from ata_host */
-#define ADMA_HOST_REGS(host,port_no) \
- ADMA_REGS((host)->iomap[ADMA_MMIO_BAR], port_no)
+/* macro to obtain addresses from ata_port */
+#define ADMA_PORT_REGS(ap) \
+ ADMA_REGS((ap)->host->iomap[ADMA_MMIO_BAR], ap->port_no)
enum {
ADMA_MMIO_BAR = 4,
@@ -128,7 +128,6 @@ struct adma_port_priv {
static int adma_ata_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static irqreturn_t adma_intr (int irq, void *dev_instance);
static int adma_port_start(struct ata_port *ap);
static void adma_host_stop(struct ata_host *host);
static void adma_port_stop(struct ata_port *ap);
@@ -172,7 +171,6 @@ static const struct ata_port_operations adma_ata_ops = {
.qc_issue = adma_qc_issue,
.eng_timeout = adma_eng_timeout,
.data_xfer = ata_data_xfer,
- .irq_handler = adma_intr,
.irq_clear = adma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -186,7 +184,6 @@ static const struct ata_port_operations adma_ata_ops = {
static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
- .sht = &adma_ata_sht,
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
@@ -229,8 +226,10 @@ static void adma_irq_clear(struct ata_port *ap)
/* nothing */
}
-static void adma_reset_engine(void __iomem *chan)
+static void adma_reset_engine(struct ata_port *ap)
{
+ void __iomem *chan = ADMA_PORT_REGS(ap);
+
/* reset ADMA to idle state */
writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
udelay(2);
@@ -241,14 +240,14 @@ static void adma_reset_engine(void __iomem *chan)
static void adma_reinit_engine(struct ata_port *ap)
{
struct adma_port_priv *pp = ap->private_data;
- void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
/* mask/clear ATA interrupts */
writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
ata_check_status(ap);
/* reset the ADMA engine */
- adma_reset_engine(chan);
+ adma_reset_engine(ap);
/* set in-FIFO threshold to 0x100 */
writew(0x100, chan + ADMA_FIFO_IN);
@@ -268,7 +267,7 @@ static void adma_reinit_engine(struct ata_port *ap)
static inline void adma_enter_reg_mode(struct ata_port *ap)
{
- void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
writew(aPIOMD4, chan + ADMA_CONTROL);
readb(chan + ADMA_STATUS); /* flush */
@@ -415,7 +414,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
static inline void adma_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *chan = ADMA_HOST_REGS(ap->host, ap->port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
VPRINTK("ENTER, ap %p\n", ap);
@@ -453,7 +452,7 @@ static inline unsigned int adma_intr_pkt(struct ata_host *host)
struct ata_port *ap = host->ports[port_no];
struct adma_port_priv *pp;
struct ata_queued_cmd *qc;
- void __iomem *chan = ADMA_HOST_REGS(host, port_no);
+ void __iomem *chan = ADMA_PORT_REGS(ap);
u8 status = readb(chan + ADMA_STATUS);
if (status == 0)
@@ -575,7 +574,7 @@ static int adma_port_start(struct ata_port *ap)
static void adma_port_stop(struct ata_port *ap)
{
- adma_reset_engine(ADMA_HOST_REGS(ap->host, ap->port_no));
+ adma_reset_engine(ap);
}
static void adma_host_stop(struct ata_host *host)
@@ -583,21 +582,19 @@ static void adma_host_stop(struct ata_host *host)
unsigned int port_no;
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_HOST_REGS(host, port_no));
+ adma_reset_engine(host->ports[port_no]);
}
-static void adma_host_init(unsigned int chip_id,
- struct ata_probe_ent *probe_ent)
+static void adma_host_init(struct ata_host *host, unsigned int chip_id)
{
unsigned int port_no;
- void __iomem *mmio_base = probe_ent->iomap[ADMA_MMIO_BAR];
/* enable/lock aGO operation */
- writeb(7, mmio_base + ADMA_MODE_LOCK);
+ writeb(7, host->iomap[ADMA_MMIO_BAR] + ADMA_MODE_LOCK);
/* reset the ADMA logic */
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(mmio_base, port_no));
+ adma_reset_engine(host->ports[port_no]);
}
static int adma_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
@@ -623,14 +620,21 @@ static int adma_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- void __iomem *mmio_base;
unsigned int board_idx = (unsigned int) ent->driver_data;
+ const struct ata_port_info *ppi[] = { &adma_port_info[board_idx], NULL };
+ struct ata_host *host;
+ void __iomem *mmio_base;
int rc, port_no;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* alloc host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, ADMA_PORTS);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -641,46 +645,23 @@ static int adma_ata_init_one(struct pci_dev *pdev,
rc = pcim_iomap_regions(pdev, 1 << ADMA_MMIO_BAR, DRV_NAME);
if (rc)
return rc;
- mmio_base = pcim_iomap_table(pdev)[ADMA_MMIO_BAR];
+ host->iomap = pcim_iomap_table(pdev);
+ mmio_base = host->iomap[ADMA_MMIO_BAR];
rc = adma_set_dma_masks(pdev, mmio_base);
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = adma_port_info[board_idx].sht;
- probe_ent->port_flags = adma_port_info[board_idx].flags;
- probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
- probe_ent->port_ops = adma_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->n_ports = ADMA_PORTS;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
- adma_ata_setup_port(&probe_ent->port[port_no],
+ for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
+ adma_ata_setup_port(&host->ports[port_no]->ioaddr,
ADMA_ATA_REGS(mmio_base, port_no));
- }
-
- pci_set_master(pdev);
/* initialize adapter */
- adma_host_init(board_idx, probe_ent);
+ adma_host_init(host, board_idx);
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, adma_intr, IRQF_SHARED,
+ &adma_ata_sht);
}
static int __init adma_ata_init(void)
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 1e21688bfcf..b3b62e985f1 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -420,7 +420,8 @@ static void inic_thaw(struct ata_port *ap)
* SRST and SControl hardreset don't give valid signature on this
* controller. Only controller specific hardreset mechanism works.
*/
-static int inic_hardreset(struct ata_port *ap, unsigned int *class)
+static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
@@ -437,7 +438,7 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class)
msleep(1);
writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
- rc = sata_phy_resume(ap, timing);
+ rc = sata_phy_resume(ap, timing, deadline);
if (rc) {
ata_port_printk(ap, KERN_WARNING, "failed to resume "
"link after reset (errno=%d)\n", rc);
@@ -451,10 +452,12 @@ static int inic_hardreset(struct ata_port *ap, unsigned int *class)
/* wait a while before checking status */
msleep(150);
- if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
- ata_port_printk(ap, KERN_WARNING,
- "device busy after hardreset\n");
- return -EIO;
+ rc = ata_wait_ready(ap, deadline);
+ /* link occupied, -ENODEV too is an error */
+ if (rc) {
+ ata_port_printk(ap, KERN_WARNING, "device not ready "
+ "after hardreset (errno=%d)\n", rc);
+ return rc;
}
ata_tf_read(ap, &tf);
@@ -488,11 +491,11 @@ static void inic_error_handler(struct ata_port *ap)
static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
{
/* make DMA engine forget about the failed command */
- if (qc->err_mask)
+ if (qc->flags & ATA_QCFLAG_FAILED)
inic_reset_port(inic_port_base(qc->ap));
}
-static void inic_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void inic_dev_config(struct ata_device *dev)
{
/* inic can only handle upto LBA28 max sectors */
if (dev->max_sectors > ATA_MAX_SECTORS)
@@ -559,7 +562,6 @@ static struct ata_port_operations inic_port_ops = {
.bmdma_stop = inic_bmdma_stop,
.bmdma_status = inic_bmdma_status,
- .irq_handler = inic_interrupt,
.irq_clear = inic_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -580,7 +582,6 @@ static struct ata_port_operations inic_port_ops = {
};
static struct ata_port_info inic_port_info = {
- .sht = &inic_sht,
/* For some reason, ATA_PROT_ATAPI is broken on this
* controller, and no, PIO_POLLING does't fix it. It somehow
* manages to report the wrong ireason and ignoring ireason
@@ -642,7 +643,9 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
void __iomem *mmio_base = host->iomap[MMIO_BAR];
int rc;
- ata_pci_device_do_resume(pdev);
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
rc = init_controller(mmio_base, hpriv->cached_hctl);
@@ -659,8 +662,8 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_port_info *pinfo = &inic_port_info;
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[] = { &inic_port_info, NULL };
+ struct ata_host *host;
struct inic_host_priv *hpriv;
void __iomem * const *iomap;
int i, rc;
@@ -668,6 +671,15 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* alloc host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, NR_PORTS);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!host || !hpriv)
+ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -675,7 +687,22 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
if (rc)
return rc;
- iomap = pcim_iomap_table(pdev);
+ host->iomap = iomap = pcim_iomap_table(pdev);
+
+ for (i = 0; i < NR_PORTS; i++) {
+ struct ata_ioports *port = &host->ports[i]->ioaddr;
+ void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+
+ port->cmd_addr = iomap[2 * i];
+ port->altstatus_addr =
+ port->ctl_addr = (void __iomem *)
+ ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
+ port->scr_addr = port_base + PORT_SCR;
+
+ ata_std_ports(port);
+ }
+
+ hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
/* Set dma_mask. This devices doesn't support 64bit addressing. */
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
@@ -692,43 +719,6 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
- if (!probe_ent || !hpriv)
- return -ENOMEM;
-
- probe_ent->dev = &pdev->dev;
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = pinfo->sht;
- probe_ent->port_flags = pinfo->flags;
- probe_ent->pio_mask = pinfo->pio_mask;
- probe_ent->mwdma_mask = pinfo->mwdma_mask;
- probe_ent->udma_mask = pinfo->udma_mask;
- probe_ent->port_ops = pinfo->port_ops;
- probe_ent->n_ports = NR_PORTS;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
-
- probe_ent->iomap = iomap;
-
- for (i = 0; i < NR_PORTS; i++) {
- struct ata_ioports *port = &probe_ent->port[i];
- void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
-
- port->cmd_addr = iomap[2 * i];
- port->altstatus_addr =
- port->ctl_addr = (void __iomem *)
- ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
- port->scr_addr = port_base + PORT_SCR;
-
- ata_std_ports(port);
- }
-
- probe_ent->private_data = hpriv;
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
-
rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
@@ -737,13 +727,8 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
-
- return 0;
+ return ata_host_activate(host, pdev->irq, inic_interrupt, IRQF_SHARED,
+ &inic_sht);
}
static const struct pci_device_id inic_pci_tbl[] = {
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index a65ba636aaa..cb9b9ac12b4 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -253,10 +253,7 @@ enum {
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
enum {
- /* Our DMA boundary is determined by an ePRD being unable to handle
- * anything larger than 64KB
- */
- MV_DMA_BOUNDARY = 0xffffU,
+ MV_DMA_BOUNDARY = 0xffffffffU,
EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
@@ -350,7 +347,6 @@ static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t mv_interrupt(int irq, void *dev_instance);
static void mv_eng_timeout(struct ata_port *ap);
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -384,10 +380,10 @@ static struct scsi_host_template mv_sht = {
.queuecommand = ata_scsi_queuecmd,
.can_queue = MV_USE_Q_DEPTH,
.this_id = ATA_SHT_THIS_ID,
- .sg_tablesize = MV_MAX_SG_CT / 2,
+ .sg_tablesize = MV_MAX_SG_CT,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
.emulated = ATA_SHT_EMULATED,
- .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .use_clustering = 1,
.proc_name = DRV_NAME,
.dma_boundary = MV_DMA_BOUNDARY,
.slave_configure = ata_scsi_slave_config,
@@ -405,6 +401,7 @@ static const struct ata_port_operations mv5_ops = {
.dev_select = ata_std_dev_select,
.phy_reset = mv_phy_reset,
+ .cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -412,7 +409,6 @@ static const struct ata_port_operations mv5_ops = {
.eng_timeout = mv_eng_timeout,
- .irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -434,6 +430,7 @@ static const struct ata_port_operations mv6_ops = {
.dev_select = ata_std_dev_select,
.phy_reset = mv_phy_reset,
+ .cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -441,7 +438,6 @@ static const struct ata_port_operations mv6_ops = {
.eng_timeout = mv_eng_timeout,
- .irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -463,6 +459,7 @@ static const struct ata_port_operations mv_iie_ops = {
.dev_select = ata_std_dev_select,
.phy_reset = mv_phy_reset,
+ .cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep_iie,
.qc_issue = mv_qc_issue,
@@ -470,7 +467,6 @@ static const struct ata_port_operations mv_iie_ops = {
.eng_timeout = mv_eng_timeout,
- .irq_handler = mv_interrupt,
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -484,35 +480,30 @@ static const struct ata_port_operations mv_iie_ops = {
static const struct ata_port_info mv_port_info[] = {
{ /* chip_504x */
- .sht = &mv_sht,
.flags = MV_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_508x */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_5080 */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_604x */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv6_ops,
},
{ /* chip_608x */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
@@ -520,14 +511,12 @@ static const struct ata_port_info mv_port_info[] = {
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .sht = &mv_sht,
.flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
@@ -551,6 +540,9 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ PCI_VDEVICE(TTI, 0x2310), chip_7042 },
+ /* add Marvell 7042 support */
+ { PCI_VDEVICE(MARVELL, 0x7042), chip_7042 },
+
{ } /* terminate list */
};
@@ -585,6 +577,39 @@ static const struct mv_hw_ops mv6xxx_ops = {
static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+ int rc;
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
/*
* Functions
*/
@@ -798,20 +823,18 @@ static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs) {
+ if (0xffffffffU != ofs)
return readl(mv_ap_base(ap) + ofs);
- } else {
+ else
return (u32) ofs;
- }
}
static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs) {
+ if (0xffffffffU != ofs)
writelfl(val, mv_ap_base(ap) + ofs);
- }
}
static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
@@ -959,38 +982,30 @@ static void mv_port_stop(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_fill_sg(struct ata_queued_cmd *qc)
+static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
{
struct mv_port_priv *pp = qc->ap->private_data;
- unsigned int i = 0;
+ unsigned int n_sg = 0;
struct scatterlist *sg;
+ struct mv_sg *mv_sg;
+ mv_sg = pp->sg_tbl;
ata_for_each_sg(sg, qc) {
- dma_addr_t addr;
- u32 sg_len, len, offset;
-
- addr = sg_dma_address(sg);
- sg_len = sg_dma_len(sg);
-
- while (sg_len) {
- offset = addr & MV_DMA_BOUNDARY;
- len = sg_len;
- if ((offset + sg_len) > 0x10000)
- len = 0x10000 - offset;
+ dma_addr_t addr = sg_dma_address(sg);
+ u32 sg_len = sg_dma_len(sg);
- pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
- pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
- pp->sg_tbl[i].flags_size = cpu_to_le32(len & 0xffff);
+ mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
+ mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+ mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
- sg_len -= len;
- addr += len;
+ if (ata_sg_is_last(sg, qc))
+ mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
- if (!sg_len && ata_sg_is_last(sg, qc))
- pp->sg_tbl[i].flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
-
- i++;
- }
+ mv_sg++;
+ n_sg++;
}
+
+ return n_sg;
}
static inline unsigned mv_inc_q_index(unsigned index)
@@ -1320,17 +1335,15 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
int shift, port, port0, hard_port, handled;
unsigned int err_mask;
- if (hc == 0) {
+ if (hc == 0)
port0 = 0;
- } else {
+ else
port0 = MV_PORTS_PER_HC;
- }
/* we'll need the HC success int register in most cases */
hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- if (hc_irq_cause) {
+ if (hc_irq_cause)
writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
- }
VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
hc,relevant,hc_irq_cause);
@@ -1425,9 +1438,8 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
/* check the cases where we either have nothing pending or have read
* a bogus register value which can indicate HW removal or PCI fault
*/
- if (!irq_stat || (0xffffffffU == irq_stat)) {
+ if (!irq_stat || (0xffffffffU == irq_stat))
return IRQ_NONE;
- }
n_hcs = mv_get_hc_count(host->ports[0]->flags);
spin_lock(&host->lock);
@@ -1952,7 +1964,6 @@ comreset_retry:
ata_port_disable(ap);
return;
}
- ap->cbl = ATA_CBL_SATA;
/* even after SStatus reflects that device is ready,
* it seems to take a while for link to be fully
@@ -2077,9 +2088,10 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
}
-static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
- unsigned int board_idx)
+static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct mv_host_priv *hpriv = host->private_data;
u8 rev_id;
u32 hp_flags = hpriv->hp_flags;
@@ -2177,8 +2189,8 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
/**
* mv_init_host - Perform some early initialization of the host.
- * @pdev: host PCI device
- * @probe_ent: early data struct representing the host
+ * @host: ATA host to initialize
+ * @board_idx: controller index
*
* If possible, do an early global reset of the host. Then do
* our port init and clear/unmask all/relevant host interrupts.
@@ -2186,24 +2198,23 @@ static int mv_chip_id(struct pci_dev *pdev, struct mv_host_priv *hpriv,
* LOCKING:
* Inherited from caller.
*/
-static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
- unsigned int board_idx)
+static int mv_init_host(struct ata_host *host, unsigned int board_idx)
{
int rc = 0, n_hc, port, hc;
- void __iomem *mmio = probe_ent->iomap[MV_PRIMARY_BAR];
- struct mv_host_priv *hpriv = probe_ent->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
+ struct mv_host_priv *hpriv = host->private_data;
/* global interrupt mask */
writel(0, mmio + HC_MAIN_IRQ_MASK_OFS);
- rc = mv_chip_id(pdev, hpriv, board_idx);
+ rc = mv_chip_id(host, board_idx);
if (rc)
goto done;
- n_hc = mv_get_hc_count(probe_ent->port_flags);
- probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
+ n_hc = mv_get_hc_count(host->ports[0]->flags);
- for (port = 0; port < probe_ent->n_ports; port++)
+ for (port = 0; port < host->n_ports; port++)
hpriv->ops->read_preamp(hpriv, port, mmio);
rc = hpriv->ops->reset_hc(hpriv, mmio, n_hc);
@@ -2214,7 +2225,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
hpriv->ops->reset_bus(pdev, mmio);
hpriv->ops->enable_leds(hpriv, mmio);
- for (port = 0; port < probe_ent->n_ports; port++) {
+ for (port = 0; port < host->n_ports; port++) {
if (IS_60XX(hpriv)) {
void __iomem *port_mmio = mv_port_base(mmio, port);
@@ -2227,9 +2238,9 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
hpriv->ops->phy_errata(hpriv, mmio, port);
}
- for (port = 0; port < probe_ent->n_ports; port++) {
+ for (port = 0; port < host->n_ports; port++) {
void __iomem *port_mmio = mv_port_base(mmio, port);
- mv_port_init(&probe_ent->port[port], port_mmio);
+ mv_port_init(&host->ports[port]->ioaddr, port_mmio);
}
for (hc = 0; hc < n_hc; hc++) {
@@ -2268,17 +2279,17 @@ done:
/**
* mv_print_info - Dump key info to kernel log for perusal.
- * @probe_ent: early data struct representing the host
+ * @host: ATA host to print info about
*
* FIXME: complete this.
*
* LOCKING:
* Inherited from caller.
*/
-static void mv_print_info(struct ata_probe_ent *probe_ent)
+static void mv_print_info(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
- struct mv_host_priv *hpriv = probe_ent->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct mv_host_priv *hpriv = host->private_data;
u8 rev_id, scc;
const char *scc_s;
@@ -2297,7 +2308,7 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
dev_printk(KERN_INFO, &pdev->dev,
"%u slots %u ports %s mode IRQ via %s\n",
- (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports,
+ (unsigned)MV_MAX_Q_DEPTH, host->n_ports,
scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
}
@@ -2312,50 +2323,42 @@ static void mv_print_info(struct ata_probe_ent *probe_ent)
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
- struct mv_host_priv *hpriv;
unsigned int board_idx = (unsigned int)ent->driver_data;
- int rc;
+ const struct ata_port_info *ppi[] = { &mv_port_info[board_idx], NULL };
+ struct ata_host *host;
+ struct mv_host_priv *hpriv;
+ int n_ports, rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ n_ports = mv_get_hc_count(ppi[0]->flags) * MV_PORTS_PER_HC;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!host || !hpriv)
+ return -ENOMEM;
+ host->private_data = hpriv;
+
+ /* acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- pci_set_master(pdev);
rc = pcim_iomap_regions(pdev, 1 << MV_PRIMARY_BAR, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- return -ENOMEM;
-
- probe_ent->sht = mv_port_info[board_idx].sht;
- probe_ent->port_flags = mv_port_info[board_idx].flags;
- probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
- probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
- probe_ent->port_ops = mv_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
- probe_ent->private_data = hpriv;
+ rc = pci_go_64(pdev);
+ if (rc)
+ return rc;
/* initialize adapter */
- rc = mv_init_host(pdev, probe_ent, board_idx);
+ rc = mv_init_host(host, board_idx);
if (rc)
return rc;
@@ -2364,13 +2367,11 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_intx(pdev, 1);
mv_dump_pci_cfg(pdev, 0x68);
- mv_print_info(probe_ent);
+ mv_print_info(host);
- if (ata_device_add(probe_ent) == 0)
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
+ &mv_sht);
}
static int __init mv_init(void)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 9d9670a9b11..e2e795e5823 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -260,6 +260,7 @@ static int nv_adma_port_resume(struct ata_port *ap);
static void nv_adma_error_handler(struct ata_port *ap);
static void nv_adma_host_stop(struct ata_host *host);
static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc);
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
enum nv_host_type
{
@@ -368,7 +369,6 @@ static const struct ata_port_operations nv_generic_ops = {
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_generic_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -395,7 +395,6 @@ static const struct ata_port_operations nv_nf2_ops = {
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_nf2_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -422,7 +421,6 @@ static const struct ata_port_operations nv_ck804_ops = {
.error_handler = nv_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_ck804_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -435,7 +433,7 @@ static const struct ata_port_operations nv_ck804_ops = {
static const struct ata_port_operations nv_adma_ops = {
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
- .tf_read = ata_tf_read,
+ .tf_read = nv_adma_tf_read,
.check_atapi_dma = nv_adma_check_atapi_dma,
.exec_command = ata_exec_command,
.check_status = ata_check_status,
@@ -451,7 +449,6 @@ static const struct ata_port_operations nv_adma_ops = {
.error_handler = nv_adma_error_handler,
.post_internal_cmd = nv_adma_post_internal_cmd,
.data_xfer = ata_data_xfer,
- .irq_handler = nv_adma_interrupt,
.irq_clear = nv_adma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -476,6 +473,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_generic_ops,
+ .irq_handler = nv_generic_interrupt,
},
/* nforce2/3 */
{
@@ -486,6 +484,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_nf2_ops,
+ .irq_handler = nv_nf2_interrupt,
},
/* ck804 */
{
@@ -496,6 +495,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_ck804_ops,
+ .irq_handler = nv_ck804_interrupt,
},
/* ADMA */
{
@@ -507,6 +507,7 @@ static struct ata_port_info nv_port_info[] = {
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
.port_ops = &nv_adma_ops,
+ .irq_handler = nv_adma_interrupt,
},
};
@@ -667,6 +668,18 @@ static int nv_adma_check_atapi_dma(struct ata_queued_cmd *qc)
return !(pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE);
}
+static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ /* Since commands where a result TF is requested are not
+ executed in ADMA mode, the only time this function will be called
+ in ADMA mode will be if a command fails. In this case we
+ don't care about going into register mode with ADMA commands
+ pending, as the commands will all shortly be aborted anyway. */
+ nv_adma_register_mode(ap);
+
+ ata_tf_read(ap, tf);
+}
+
static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
{
unsigned int idx = 0;
@@ -738,19 +751,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
return 1;
}
- if (flags & NV_CPB_RESP_DONE) {
+ if (likely(flags & NV_CPB_RESP_DONE)) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
VPRINTK("CPB flags done, flags=0x%x\n", flags);
if (likely(qc)) {
- /* Grab the ATA port status for non-NCQ commands.
- For NCQ commands the current status may have nothing to do with
- the command just completed. */
- if (qc->tf.protocol != ATA_PROT_NCQ) {
- u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
- qc->err_mask |= ac_err_mask(ata_status);
- }
- DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
- qc->err_mask);
+ DPRINTK("Completing qc from tag %d\n",cpb_num);
ata_qc_complete(qc);
} else {
struct ata_eh_info *ehi = &ap->eh_info;
@@ -1074,14 +1079,14 @@ static int nv_adma_port_resume(struct ata_port *ap)
}
#endif
-static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int port)
+static void nv_adma_setup_port(struct ata_port *ap)
{
- void __iomem *mmio = probe_ent->iomap[NV_MMIO_BAR];
- struct ata_ioports *ioport = &probe_ent->port[port];
+ void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR];
+ struct ata_ioports *ioport = &ap->ioaddr;
VPRINTK("ENTER\n");
- mmio += NV_ADMA_PORT + port * NV_ADMA_PORT_SIZE;
+ mmio += NV_ADMA_PORT + ap->port_no * NV_ADMA_PORT_SIZE;
ioport->cmd_addr = mmio;
ioport->data_addr = mmio + (ATA_REG_DATA * 4);
@@ -1098,9 +1103,9 @@ static void nv_adma_setup_port(struct ata_probe_ent *probe_ent, unsigned int por
ioport->ctl_addr = mmio + 0x20;
}
-static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
+static int nv_adma_host_init(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
unsigned int i;
u32 tmp32;
@@ -1115,8 +1120,8 @@ static int nv_adma_host_init(struct ata_probe_ent *probe_ent)
pci_write_config_dword(pdev, NV_MCP_SATA_CFG_20, tmp32);
- for (i = 0; i < probe_ent->n_ports; i++)
- nv_adma_setup_port(probe_ent, i);
+ for (i = 0; i < host->n_ports; i++)
+ nv_adma_setup_port(host->ports[i]);
return 0;
}
@@ -1167,9 +1172,11 @@ static int nv_adma_use_reg_mode(struct ata_queued_cmd *qc)
struct nv_adma_port_priv *pp = qc->ap->private_data;
/* ADMA engine can only be used for non-ATAPI DMA commands,
- or interrupt-driven no-data commands. */
+ or interrupt-driven no-data commands, where a result taskfile
+ is not required. */
if((pp->flags & NV_ADMA_ATAPI_SETUP_COMPLETE) ||
- (qc->tf.flags & ATA_TFLAG_POLLING))
+ (qc->tf.flags & ATA_TFLAG_POLLING) ||
+ (qc->flags & ATA_QCFLAG_RESULT_TF))
return 1;
if((qc->flags & ATA_QCFLAG_DMAMAP) ||
@@ -1398,7 +1405,8 @@ static void nv_ck804_thaw(struct ata_port *ap)
writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
}
-static int nv_hardreset(struct ata_port *ap, unsigned int *class)
+static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
unsigned int dummy;
@@ -1406,7 +1414,7 @@ static int nv_hardreset(struct ata_port *ap, unsigned int *class)
* some controllers. Don't classify on hardreset. For more
* info, see http://bugme.osdl.org/show_bug.cgi?id=3352
*/
- return sata_std_hardreset(ap, &dummy);
+ return sata_std_hardreset(ap, &dummy, deadline);
}
static void nv_error_handler(struct ata_port *ap)
@@ -1473,14 +1481,13 @@ static void nv_adma_error_handler(struct ata_port *ap)
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct ata_port_info *ppi[2];
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[2];
+ struct ata_host *host;
struct nv_host_priv *hpriv;
int rc;
u32 bar;
void __iomem *base;
unsigned long type = ent->driver_data;
- int mask_set = 0;
// Make sure this is a SATA controller by counting the number of bars
// (NVIDIA SATA controllers will always have six bars). Otherwise,
@@ -1496,50 +1503,38 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
- return rc;
- }
-
- if(type >= CK804 && adma_enabled) {
+ /* determine type and allocate host */
+ if (type >= CK804 && adma_enabled) {
dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n");
type = ADMA;
- if(!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
- !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
- mask_set = 1;
- }
-
- if(!mask_set) {
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
}
- rc = -ENOMEM;
+ ppi[0] = ppi[1] = &nv_port_info[type];
+ rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+ if (rc)
+ return rc;
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ hpriv->type = type;
+ host->private_data = hpriv;
- ppi[0] = ppi[1] = &nv_port_info[type];
- probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return -ENOMEM;
-
- if (!pcim_iomap(pdev, NV_MMIO_BAR, 0))
- return -EIO;
- probe_ent->iomap = pcim_iomap_table(pdev);
+ /* set 64bit dma masks, may fail */
+ if (type == ADMA) {
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0)
+ pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ }
- probe_ent->private_data = hpriv;
- hpriv->type = type;
+ /* request and iomap NV_MMIO_BAR */
+ rc = pcim_iomap_regions(pdev, 1 << NV_MMIO_BAR, DRV_NAME);
+ if (rc)
+ return rc;
- base = probe_ent->iomap[NV_MMIO_BAR];
- probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
- probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
+ /* configure SCR access */
+ base = host->iomap[NV_MMIO_BAR];
+ host->ports[0]->ioaddr.scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
+ host->ports[1]->ioaddr.scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
/* enable SATA space for CK804 */
if (type >= CK804) {
@@ -1550,20 +1545,16 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
}
- pci_set_master(pdev);
-
+ /* init ADMA */
if (type == ADMA) {
- rc = nv_adma_host_init(probe_ent);
+ rc = nv_adma_host_init(host);
if (rc)
return rc;
}
- rc = ata_device_add(probe_ent);
- if (rc != NV_PORTS)
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, ppi[0]->irq_handler,
+ IRQF_SHARED, ppi[0]->sht);
}
static void nv_remove_one (struct pci_dev *pdev)
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 2339813ce9f..f56549b90aa 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,10 +45,11 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "2.00"
+#define DRV_VERSION "2.05"
enum {
+ PDC_MAX_PORTS = 4,
PDC_MMIO_BAR = 3,
/* register offsets */
@@ -70,14 +71,31 @@ enum {
PDC_TBG_MODE = 0x41C, /* TBG mode (not SATAII) */
PDC_SLEW_CTL = 0x470, /* slew rate control reg (not SATAII) */
- PDC_ERR_MASK = (1<<19) | (1<<20) | (1<<21) | (1<<22) |
- (1<<8) | (1<<9) | (1<<10),
+ /* PDC_GLOBAL_CTL bit definitions */
+ PDC_PH_ERR = (1 << 8), /* PCI error while loading packet */
+ PDC_SH_ERR = (1 << 9), /* PCI error while loading S/G table */
+ PDC_DH_ERR = (1 << 10), /* PCI error while loading data */
+ PDC2_HTO_ERR = (1 << 12), /* host bus timeout */
+ PDC2_ATA_HBA_ERR = (1 << 13), /* error during SATA DATA FIS transmission */
+ PDC2_ATA_DMA_CNT_ERR = (1 << 14), /* DMA DATA FIS size differs from S/G count */
+ PDC_OVERRUN_ERR = (1 << 19), /* S/G byte count larger than HD requires */
+ PDC_UNDERRUN_ERR = (1 << 20), /* S/G byte count less than HD requires */
+ PDC_DRIVE_ERR = (1 << 21), /* drive error */
+ PDC_PCI_SYS_ERR = (1 << 22), /* PCI system error */
+ PDC1_PCI_PARITY_ERR = (1 << 23), /* PCI parity error (from SATA150 driver) */
+ PDC1_ERR_MASK = PDC1_PCI_PARITY_ERR,
+ PDC2_ERR_MASK = PDC2_HTO_ERR | PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR,
+ PDC_ERR_MASK = (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC_OVERRUN_ERR
+ | PDC_UNDERRUN_ERR | PDC_DRIVE_ERR | PDC_PCI_SYS_ERR
+ | PDC1_ERR_MASK | PDC2_ERR_MASK),
board_2037x = 0, /* FastTrak S150 TX2plus */
- board_20319 = 1, /* FastTrak S150 TX4 */
- board_20619 = 2, /* FastTrak TX4000 */
- board_2057x = 3, /* SATAII150 Tx2plus */
- board_40518 = 4, /* SATAII150 Tx4 */
+ board_2037x_pata = 1, /* FastTrak S150 TX2plus PATA port */
+ board_20319 = 2, /* FastTrak S150 TX4 */
+ board_20619 = 3, /* FastTrak TX4000 */
+ board_2057x = 4, /* SATAII150 Tx2plus */
+ board_2057x_pata = 5, /* SATAII150 Tx2plus */
+ board_40518 = 6, /* SATAII150 Tx4 */
PDC_HAS_PATA = (1 << 1), /* PDC20375/20575 has PATA */
@@ -100,8 +118,10 @@ enum {
ATA_FLAG_MMIO |
ATA_FLAG_PIO_POLLING,
- /* hp->flags bits */
- PDC_FLAG_GEN_II = (1 << 0),
+ /* ap->flags bits */
+ PDC_FLAG_GEN_II = (1 << 24),
+ PDC_FLAG_SATA_PATA = (1 << 25), /* supports SATA + PATA */
+ PDC_FLAG_4_PORTS = (1 << 26), /* 4 ports */
};
@@ -110,28 +130,25 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-struct pdc_host_priv {
- unsigned long flags;
- unsigned long port_flags[ATA_MAX_PORTS];
-};
-
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
-static int pdc_port_start(struct ata_port *ap);
+static int pdc_common_port_start(struct ata_port *ap);
+static int pdc_sata_port_start(struct ata_port *ap);
static void pdc_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static int pdc_check_atapi_dma(struct ata_queued_cmd *qc);
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc);
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc);
static void pdc_irq_clear(struct ata_port *ap);
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
static void pdc_freeze(struct ata_port *ap);
static void pdc_thaw(struct ata_port *ap);
-static void pdc_error_handler(struct ata_port *ap);
+static void pdc_pata_error_handler(struct ata_port *ap);
+static void pdc_sata_error_handler(struct ata_port *ap);
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc);
-
+static int pdc_pata_cable_detect(struct ata_port *ap);
+static int pdc_sata_cable_detect(struct ata_port *ap);
static struct scsi_host_template pdc_ata_sht = {
.module = THIS_MODULE,
@@ -164,17 +181,17 @@ static const struct ata_port_operations pdc_sata_ops = {
.qc_issue = pdc_qc_issue_prot,
.freeze = pdc_freeze,
.thaw = pdc_thaw,
- .error_handler = pdc_error_handler,
+ .error_handler = pdc_sata_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
+ .cable_detect = pdc_sata_cable_detect,
.data_xfer = ata_data_xfer,
- .irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
- .port_start = pdc_port_start,
+ .port_start = pdc_sata_port_start,
};
/* First-generation chips need a more restrictive ->check_atapi_dma op */
@@ -185,23 +202,23 @@ static const struct ata_port_operations pdc_old_sata_ops = {
.check_status = ata_check_status,
.exec_command = pdc_exec_command_mmio,
.dev_select = ata_std_dev_select,
- .check_atapi_dma = pdc_old_check_atapi_dma,
+ .check_atapi_dma = pdc_old_sata_check_atapi_dma,
.qc_prep = pdc_qc_prep,
.qc_issue = pdc_qc_issue_prot,
.freeze = pdc_freeze,
.thaw = pdc_thaw,
- .error_handler = pdc_error_handler,
+ .error_handler = pdc_sata_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
+ .cable_detect = pdc_sata_cable_detect,
.data_xfer = ata_data_xfer,
- .irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
.scr_read = pdc_sata_scr_read,
.scr_write = pdc_sata_scr_write,
- .port_start = pdc_port_start,
+ .port_start = pdc_sata_port_start,
};
static const struct ata_port_operations pdc_pata_ops = {
@@ -217,32 +234,41 @@ static const struct ata_port_operations pdc_pata_ops = {
.qc_issue = pdc_qc_issue_prot,
.freeze = pdc_freeze,
.thaw = pdc_thaw,
- .error_handler = pdc_error_handler,
+ .error_handler = pdc_pata_error_handler,
.post_internal_cmd = pdc_post_internal_cmd,
+ .cable_detect = pdc_pata_cable_detect,
.data_xfer = ata_data_xfer,
- .irq_handler = pdc_interrupt,
.irq_clear = pdc_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
- .port_start = pdc_port_start,
+ .port_start = pdc_common_port_start,
};
static const struct ata_port_info pdc_port_info[] = {
/* board_2037x */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_SATA_PATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &pdc_old_sata_ops,
},
+ /* board_2037x_pata */
+ {
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_pata_ops,
+ },
+
/* board_20319 */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_4_PORTS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -251,8 +277,8 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_20619 */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS |
+ PDC_FLAG_4_PORTS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -261,18 +287,28 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_2057x */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_GEN_II | PDC_FLAG_SATA_PATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &pdc_sata_ops,
},
+ /* board_2057x_pata */
+ {
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ PDC_FLAG_GEN_II,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &pdc_pata_ops,
+ },
+
/* board_40518 */
{
- .sht = &pdc_ata_sht,
- .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA |
+ PDC_FLAG_GEN_II | PDC_FLAG_4_PORTS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -313,18 +349,12 @@ static struct pci_driver pdc_ata_pci_driver = {
};
-static int pdc_port_start(struct ata_port *ap)
+static int pdc_common_port_start(struct ata_port *ap)
{
struct device *dev = ap->host->dev;
- struct pdc_host_priv *hp = ap->host->private_data;
struct pdc_port_priv *pp;
int rc;
- /* fix up port flags and cable type for SATA+PATA chips */
- ap->flags |= hp->port_flags[ap->port_no];
- if (ap->flags & ATA_FLAG_SATA)
- ap->cbl = ATA_CBL_SATA;
-
rc = ata_port_start(ap);
if (rc)
return rc;
@@ -339,8 +369,19 @@ static int pdc_port_start(struct ata_port *ap)
ap->private_data = pp;
+ return 0;
+}
+
+static int pdc_sata_port_start(struct ata_port *ap)
+{
+ int rc;
+
+ rc = pdc_common_port_start(ap);
+ if (rc)
+ return rc;
+
/* fix up PHYMODE4 align timing */
- if ((hp->flags & PDC_FLAG_GEN_II) && sata_scr_valid(ap)) {
+ if (ap->flags & PDC_FLAG_GEN_II) {
void __iomem *mmio = (void __iomem *) ap->ioaddr.scr_addr;
unsigned int tmp;
@@ -374,23 +415,25 @@ static void pdc_reset_port(struct ata_port *ap)
readl(mmio); /* flush */
}
-static void pdc_pata_cbl_detect(struct ata_port *ap)
+static int pdc_pata_cable_detect(struct ata_port *ap)
{
u8 tmp;
void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
tmp = readb(mmio);
+ if (tmp & 0x01)
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
+}
- if (tmp & 0x01) {
- ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
- } else
- ap->cbl = ATA_CBL_PATA80;
+static int pdc_sata_cable_detect(struct ata_port *ap)
+{
+ return ATA_CBL_SATA;
}
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+ if (sc_reg > SCR_CONTROL)
return 0xffffffffU;
return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -399,7 +442,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
u32 val)
{
- if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA)
+ if (sc_reg > SCR_CONTROL)
return;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
}
@@ -555,52 +598,79 @@ static void pdc_thaw(struct ata_port *ap)
readl(mmio + PDC_CTLSTAT); /* flush */
}
-static int pdc_pre_reset(struct ata_port *ap)
-{
- if (!sata_scr_valid(ap))
- pdc_pata_cbl_detect(ap);
- return ata_std_prereset(ap);
-}
-
-static void pdc_error_handler(struct ata_port *ap)
+static void pdc_common_error_handler(struct ata_port *ap, ata_reset_fn_t hardreset)
{
- ata_reset_fn_t hardreset;
-
if (!(ap->pflags & ATA_PFLAG_FROZEN))
pdc_reset_port(ap);
- hardreset = NULL;
- if (sata_scr_valid(ap))
- hardreset = sata_std_hardreset;
-
/* perform recovery */
- ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset,
+ ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
ata_std_postreset);
}
+static void pdc_pata_error_handler(struct ata_port *ap)
+{
+ pdc_common_error_handler(ap, NULL);
+}
+
+static void pdc_sata_error_handler(struct ata_port *ap)
+{
+ pdc_common_error_handler(ap, sata_std_hardreset);
+}
+
static void pdc_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED)
- qc->err_mask |= AC_ERR_OTHER;
-
/* make DMA engine forget about the failed command */
- if (qc->err_mask)
+ if (qc->flags & ATA_QCFLAG_FAILED)
pdc_reset_port(ap);
}
+static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
+ u32 port_status, u32 err_mask)
+{
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned int ac_err_mask = 0;
+
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "port_status 0x%08x", port_status);
+ port_status &= err_mask;
+
+ if (port_status & PDC_DRIVE_ERR)
+ ac_err_mask |= AC_ERR_DEV;
+ if (port_status & (PDC_OVERRUN_ERR | PDC_UNDERRUN_ERR))
+ ac_err_mask |= AC_ERR_HSM;
+ if (port_status & (PDC2_ATA_HBA_ERR | PDC2_ATA_DMA_CNT_ERR))
+ ac_err_mask |= AC_ERR_ATA_BUS;
+ if (port_status & (PDC_PH_ERR | PDC_SH_ERR | PDC_DH_ERR | PDC2_HTO_ERR
+ | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
+ ac_err_mask |= AC_ERR_HOST_BUS;
+
+ if (sata_scr_valid(ap))
+ ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+
+ qc->err_mask |= ac_err_mask;
+
+ pdc_reset_port(ap);
+}
+
static inline unsigned int pdc_host_intr( struct ata_port *ap,
struct ata_queued_cmd *qc)
{
unsigned int handled = 0;
- u32 tmp;
- void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+ void __iomem *port_mmio = ap->ioaddr.cmd_addr;
+ u32 port_status, err_mask;
- tmp = readl(mmio);
- if (tmp & PDC_ERR_MASK) {
- qc->err_mask |= AC_ERR_DEV;
- pdc_reset_port(ap);
+ err_mask = PDC_ERR_MASK;
+ if (ap->flags & PDC_FLAG_GEN_II)
+ err_mask &= ~PDC1_ERR_MASK;
+ else
+ err_mask &= ~PDC2_ERR_MASK;
+ port_status = readl(port_mmio + PDC_GLOBAL_CTL);
+ if (unlikely(port_status & err_mask)) {
+ pdc_error_intr(ap, qc, port_status, err_mask);
+ return 1;
}
switch (qc->tf.protocol) {
@@ -767,44 +837,40 @@ static int pdc_check_atapi_dma(struct ata_queued_cmd *qc)
return pio;
}
-static int pdc_old_check_atapi_dma(struct ata_queued_cmd *qc)
+static int pdc_old_sata_check_atapi_dma(struct ata_queued_cmd *qc)
{
- struct ata_port *ap = qc->ap;
-
/* First generation chips cannot use ATAPI DMA on SATA ports */
- if (sata_scr_valid(ap))
- return 1;
- return pdc_check_atapi_dma(qc);
+ return 1;
}
-static void pdc_ata_setup_port(struct ata_ioports *port, void __iomem *base,
- void __iomem *scr_addr)
+static void pdc_ata_setup_port(struct ata_port *ap,
+ void __iomem *base, void __iomem *scr_addr)
{
- port->cmd_addr = base;
- port->data_addr = base;
- port->feature_addr =
- port->error_addr = base + 0x4;
- port->nsect_addr = base + 0x8;
- port->lbal_addr = base + 0xc;
- port->lbam_addr = base + 0x10;
- port->lbah_addr = base + 0x14;
- port->device_addr = base + 0x18;
- port->command_addr =
- port->status_addr = base + 0x1c;
- port->altstatus_addr =
- port->ctl_addr = base + 0x38;
- port->scr_addr = scr_addr;
+ ap->ioaddr.cmd_addr = base;
+ ap->ioaddr.data_addr = base;
+ ap->ioaddr.feature_addr =
+ ap->ioaddr.error_addr = base + 0x4;
+ ap->ioaddr.nsect_addr = base + 0x8;
+ ap->ioaddr.lbal_addr = base + 0xc;
+ ap->ioaddr.lbam_addr = base + 0x10;
+ ap->ioaddr.lbah_addr = base + 0x14;
+ ap->ioaddr.device_addr = base + 0x18;
+ ap->ioaddr.command_addr =
+ ap->ioaddr.status_addr = base + 0x1c;
+ ap->ioaddr.altstatus_addr =
+ ap->ioaddr.ctl_addr = base + 0x38;
+ ap->ioaddr.scr_addr = scr_addr;
}
-static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void pdc_host_init(struct ata_host *host)
{
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
- struct pdc_host_priv *hp = pe->private_data;
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ int is_gen2 = host->ports[0]->flags & PDC_FLAG_GEN_II;
int hotplug_offset;
u32 tmp;
- if (hp->flags & PDC_FLAG_GEN_II)
+ if (is_gen2)
hotplug_offset = PDC2_SATA_PLUG_CSR;
else
hotplug_offset = PDC_SATA_PLUG_CSR;
@@ -818,7 +884,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
/* enable BMR_BURST, maybe change FIFO_SHD to 8 dwords */
tmp = readl(mmio + PDC_FLASH_CTL);
tmp |= 0x02000; /* bit 13 (enable bmr burst) */
- if (!(hp->flags & PDC_FLAG_GEN_II))
+ if (!is_gen2)
tmp |= 0x10000; /* bit 16 (fifo threshold at 8 dw) */
writel(tmp, mmio + PDC_FLASH_CTL);
@@ -831,7 +897,7 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
writel(tmp | 0xff0000, mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
- if (hp->flags & PDC_FLAG_GEN_II)
+ if (is_gen2)
return;
/* reduce TBG clock to 133 Mhz. */
@@ -853,16 +919,16 @@ static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
- struct pdc_host_priv *hp;
+ const struct ata_port_info *pi = &pdc_port_info[ent->driver_data];
+ const struct ata_port_info *ppi[PDC_MAX_PORTS];
+ struct ata_host *host;
void __iomem *base;
- unsigned int board_idx = (unsigned int) ent->driver_data;
- int rc;
- u8 tmp;
+ int n_ports, i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* enable and acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -872,89 +938,49 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
pcim_pin_device(pdev);
if (rc)
return rc;
+ base = pcim_iomap_table(pdev)[PDC_MMIO_BAR];
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
-
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
+ /* determine port configuration and setup host */
+ n_ports = 2;
+ if (pi->flags & PDC_FLAG_4_PORTS)
+ n_ports = 4;
+ for (i = 0; i < n_ports; i++)
+ ppi[i] = pi;
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
+ if (pi->flags & PDC_FLAG_SATA_PATA) {
+ u8 tmp = readb(base + PDC_FLASH_CTL+1);
+ if (!(tmp & 0x80)) {
+ ppi[n_ports++] = pi + 1;
+ dev_printk(KERN_INFO, &pdev->dev, "PATA port found\n");
+ }
+ }
- hp = devm_kzalloc(&pdev->dev, sizeof(*hp), GFP_KERNEL);
- if (hp == NULL)
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
return -ENOMEM;
-
- probe_ent->private_data = hp;
-
- probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->port_flags = pdc_port_info[board_idx].flags;
- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- base = probe_ent->iomap[PDC_MMIO_BAR];
-
- pdc_ata_setup_port(&probe_ent->port[0], base + 0x200, base + 0x400);
- pdc_ata_setup_port(&probe_ent->port[1], base + 0x280, base + 0x500);
-
- /* notice 4-port boards */
- switch (board_idx) {
- case board_40518:
- hp->flags |= PDC_FLAG_GEN_II;
- /* Fall through */
- case board_20319:
- probe_ent->n_ports = 4;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, base + 0x600);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, base + 0x700);
- break;
- case board_2057x:
- hp->flags |= PDC_FLAG_GEN_II;
- /* Fall through */
- case board_2037x:
- /* TX2plus boards also have a PATA port */
- tmp = readb(base + PDC_FLASH_CTL+1);
- if (!(tmp & 0x80)) {
- probe_ent->n_ports = 3;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
- hp->port_flags[2] = ATA_FLAG_SLAVE_POSS;
- printk(KERN_INFO DRV_NAME " PATA port found\n");
- } else
- probe_ent->n_ports = 2;
- hp->port_flags[0] = ATA_FLAG_SATA;
- hp->port_flags[1] = ATA_FLAG_SATA;
- break;
- case board_20619:
- probe_ent->n_ports = 4;
- pdc_ata_setup_port(&probe_ent->port[2], base + 0x300, NULL);
- pdc_ata_setup_port(&probe_ent->port[3], base + 0x380, NULL);
- break;
- default:
- BUG();
- break;
}
+ host->iomap = pcim_iomap_table(pdev);
- pci_set_master(pdev);
+ for (i = 0; i < host->n_ports; i++)
+ pdc_ata_setup_port(host->ports[i],
+ base + 0x200 + i * 0x80,
+ base + 0x400 + i * 0x100);
/* initialize adapter */
- pdc_host_init(board_idx, probe_ent);
+ pdc_host_init(host);
- if (!ata_device_add(probe_ent))
- return -ENODEV;
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ /* start host, request IRQ and attach */
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, pdc_interrupt, IRQF_SHARED,
+ &pdc_ata_sht);
}
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 8786b45f291..f5a05de0093 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -114,7 +114,6 @@ struct qs_port_priv {
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t qs_intr (int irq, void *dev_instance);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
static void qs_phy_reset(struct ata_port *ap);
@@ -158,7 +157,6 @@ static const struct ata_port_operations qs_ata_ops = {
.qc_issue = qs_qc_issue,
.data_xfer = ata_data_xfer,
.eng_timeout = qs_eng_timeout,
- .irq_handler = qs_intr,
.irq_clear = qs_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -173,7 +171,6 @@ static const struct ata_port_operations qs_ata_ops = {
static const struct ata_port_info qs_port_info[] = {
/* board_2068_idx */
{
- .sht = &qs_ata_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
//FIXME ATA_FLAG_SRST |
@@ -530,16 +527,16 @@ static void qs_host_stop(struct ata_host *host)
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
}
-static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+static void qs_host_init(struct ata_host *host, unsigned int chip_id)
{
- void __iomem *mmio_base = pe->iomap[QS_MMIO_BAR];
+ void __iomem *mmio_base = host->iomap[QS_MMIO_BAR];
unsigned int port_no;
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
/* reset each channel in turn */
- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
u8 __iomem *chan = mmio_base + (port_no * 0x4000);
writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
@@ -547,7 +544,7 @@ static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
}
writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
- for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
u8 __iomem *chan = mmio_base + (port_no * 0x4000);
/* set FIFO depths to same settings as Windows driver */
writew(32, chan + QS_CFC_HUFT);
@@ -607,14 +604,20 @@ static int qs_ata_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
- void __iomem * const *iomap;
unsigned int board_idx = (unsigned int) ent->driver_data;
+ const struct ata_port_info *ppi[] = { &qs_port_info[board_idx], NULL };
+ struct ata_host *host;
int rc, port_no;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* alloc host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, QS_PORTS);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -625,47 +628,24 @@ static int qs_ata_init_one(struct pci_dev *pdev,
rc = pcim_iomap_regions(pdev, 1 << QS_MMIO_BAR, DRV_NAME);
if (rc)
return rc;
- iomap = pcim_iomap_table(pdev);
+ host->iomap = pcim_iomap_table(pdev);
- rc = qs_set_dma_masks(pdev, iomap[QS_MMIO_BAR]);
+ rc = qs_set_dma_masks(pdev, host->iomap[QS_MMIO_BAR]);
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = qs_port_info[board_idx].sht;
- probe_ent->port_flags = qs_port_info[board_idx].flags;
- probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
- probe_ent->port_ops = qs_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = iomap;
- probe_ent->n_ports = QS_PORTS;
-
- for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
void __iomem *chan =
- probe_ent->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
- qs_ata_setup_port(&probe_ent->port[port_no], chan);
+ host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
+ qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
}
- pci_set_master(pdev);
-
/* initialize adapter */
- qs_host_init(board_idx, probe_ent);
+ qs_host_init(host, board_idx);
- if (ata_device_add(probe_ent) != QS_PORTS)
- return -EIO;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, qs_intr, IRQF_SHARED,
+ &qs_ata_sht);
}
static int __init qs_ata_init(void)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 917b7ea4ef7..0a1e417f309 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,7 +46,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "2.1"
+#define DRV_VERSION "2.2"
enum {
SIL_MMIO_BAR = 5,
@@ -114,11 +114,10 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil_dev_config(struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static void sil_post_set_mode (struct ata_port *ap);
-static irqreturn_t sil_interrupt(int irq, void *dev_instance);
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -197,7 +196,7 @@ static const struct ata_port_operations sil_ops = {
.check_status = ata_check_status,
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .post_set_mode = sil_post_set_mode,
+ .set_mode = sil_set_mode,
.bmdma_setup = ata_bmdma_setup,
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
@@ -209,7 +208,6 @@ static const struct ata_port_operations sil_ops = {
.thaw = sil_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = sil_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -221,7 +219,6 @@ static const struct ata_port_operations sil_ops = {
static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -230,7 +227,6 @@ static const struct ata_port_info sil_port_info[] = {
},
/* sil_3112_no_sata_irq */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
SIL_FLAG_NO_SATA_IRQ,
.pio_mask = 0x1f, /* pio0-4 */
@@ -240,7 +236,6 @@ static const struct ata_port_info sil_port_info[] = {
},
/* sil_3512 */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -249,7 +244,6 @@ static const struct ata_port_info sil_port_info[] = {
},
/* sil_3114 */
{
- .sht = &sil_sht,
.flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -297,7 +291,16 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
return cache_line;
}
-static void sil_post_set_mode (struct ata_port *ap)
+/**
+ * sil_set_mode - wrap set_mode functions
+ * @ap: port to set up
+ * @r_failed: returned device when we fail
+ *
+ * Wrap the libata method for device setup as after the setup we need
+ * to inspect the results and do some configuration work
+ */
+
+static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
{
struct ata_host *host = ap->host;
struct ata_device *dev;
@@ -305,6 +308,11 @@ static void sil_post_set_mode (struct ata_port *ap)
void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
u32 tmp, dev_mode[2];
unsigned int i;
+ int rc;
+
+ rc = ata_do_set_mode(ap, r_failed);
+ if (rc)
+ return rc;
for (i = 0; i < 2; i++) {
dev = &ap->device[i];
@@ -323,6 +331,7 @@ static void sil_post_set_mode (struct ata_port *ap)
tmp |= (dev_mode[1] << 4);
writel(tmp, addr);
readl(addr); /* flush */
+ return 0;
}
static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
@@ -521,7 +530,6 @@ static void sil_thaw(struct ata_port *ap)
/**
* sil_dev_config - Apply device/host-specific errata fixups
- * @ap: Port containing device to be examined
* @dev: Device to be examined
*
* After the IDENTIFY [PACKET] DEVICE step is complete, and a
@@ -548,8 +556,9 @@ static void sil_thaw(struct ata_port *ap)
* appreciated.
* - But then again UDMA5 is hardly anything to complain about
*/
-static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil_dev_config(struct ata_device *dev)
{
+ struct ata_port *ap = dev->ap;
int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
unsigned int n, quirks = 0;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -583,10 +592,10 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
}
}
-static void sil_init_controller(struct pci_dev *pdev,
- int n_ports, unsigned long port_flags,
- void __iomem *mmio_base)
+static void sil_init_controller(struct ata_host *host)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
u8 cls;
u32 tmp;
int i;
@@ -596,7 +605,7 @@ static void sil_init_controller(struct pci_dev *pdev,
if (cls) {
cls >>= 3;
cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < n_ports; i++)
+ for (i = 0; i < host->n_ports; i++)
writew(cls << 8 | cls,
mmio_base + sil_port[i].fifo_cfg);
} else
@@ -604,10 +613,10 @@ static void sil_init_controller(struct pci_dev *pdev,
"cache line size not set. Driver may not function\n");
/* Apply R_ERR on DMA activate FIS errata workaround */
- if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {
int cnt;
- for (i = 0, cnt = 0; i < n_ports; i++) {
+ for (i = 0, cnt = 0; i < host->n_ports; i++) {
tmp = readl(mmio_base + sil_port[i].sfis_cfg);
if ((tmp & 0x3) != 0x01)
continue;
@@ -620,7 +629,7 @@ static void sil_init_controller(struct pci_dev *pdev,
}
}
- if (n_ports == 4) {
+ if (host->n_ports == 4) {
/* flip the magic "make 4 ports work" bit */
tmp = readl(mmio_base + sil_port[2].bmdma);
if ((tmp & SIL_INTR_STEERING) == 0)
@@ -632,15 +641,26 @@ static void sil_init_controller(struct pci_dev *pdev,
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
+ int board_id = ent->driver_data;
+ const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL };
+ struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int n_ports, rc;
unsigned int i;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ n_ports = 2;
+ if (board_id == sil_3114)
+ n_ports = 4;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -650,6 +670,7 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -658,45 +679,25 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
+ mmio_base = host->iomap[SIL_MMIO_BAR];
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = pci_dev_to_dev(pdev);
- probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
- probe_ent->sht = sil_port_info[ent->driver_data].sht;
- probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
- probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
- probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
- probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
-
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- mmio_base = probe_ent->iomap[SIL_MMIO_BAR];
-
- for (i = 0; i < probe_ent->n_ports; i++) {
- probe_ent->port[i].cmd_addr = mmio_base + sil_port[i].tf;
- probe_ent->port[i].altstatus_addr =
- probe_ent->port[i].ctl_addr = mmio_base + sil_port[i].ctl;
- probe_ent->port[i].bmdma_addr = mmio_base + sil_port[i].bmdma;
- probe_ent->port[i].scr_addr = mmio_base + sil_port[i].scr;
- ata_std_ports(&probe_ent->port[i]);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+
+ ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
+ ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
+ ioaddr->scr_addr = mmio_base + sil_port[i].scr;
+ ata_std_ports(ioaddr);
}
- sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
- mmio_base);
+ /* initialize and activate */
+ sil_init_controller(host);
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED,
+ &sil_sht);
}
#ifdef CONFIG_PM
@@ -709,8 +710,7 @@ static int sil_pci_device_resume(struct pci_dev *pdev)
if (rc)
return rc;
- sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- host->iomap[SIL_MMIO_BAR]);
+ sil_init_controller(host);
ata_host_resume(host);
return 0;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 5614df8c1ce..b97ee9f31ae 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -323,7 +323,7 @@ struct sil24_port_priv {
struct ata_taskfile tf; /* Cached taskfile registers */
};
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev);
+static void sil24_dev_config(struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
@@ -331,7 +331,6 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance);
static void sil24_freeze(struct ata_port *ap);
static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
@@ -401,7 +400,6 @@ static const struct ata_port_operations sil24_ops = {
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
- .irq_handler = sil24_interrupt,
.irq_clear = sil24_irq_clear,
.irq_on = ata_dummy_irq_on,
.irq_ack = ata_dummy_irq_ack,
@@ -424,10 +422,9 @@ static const struct ata_port_operations sil24_ops = {
#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
-static struct ata_port_info sil24_port_info[] = {
+static const struct ata_port_info sil24_port_info[] = {
/* sil_3124 */
{
- .sht = &sil24_sht,
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
.pio_mask = 0x1f, /* pio0-4 */
@@ -437,7 +434,6 @@ static struct ata_port_info sil24_port_info[] = {
},
/* sil_3132 */
{
- .sht = &sil24_sht,
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -446,7 +442,6 @@ static struct ata_port_info sil24_port_info[] = {
},
/* sil_3131/sil_3531 */
{
- .sht = &sil24_sht,
.flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -462,9 +457,9 @@ static int sil24_tag(int tag)
return tag;
}
-static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev)
+static void sil24_dev_config(struct ata_device *dev)
{
- void __iomem *port = ap->ioaddr.cmd_addr;
+ void __iomem *port = dev->ap->ioaddr.cmd_addr;
if (dev->cdb_len == 16)
writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -539,7 +534,8 @@ static int sil24_init_port(struct ata_port *ap)
return 0;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class)
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
@@ -571,7 +567,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
- 100, ATA_TMOUT_BOOT / HZ * 1000);
+ 100, jiffies_to_msecs(deadline - jiffies));
writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
irq_stat >>= PORT_IRQ_RAW_SHIFT;
@@ -599,7 +595,8 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class)
return -EIO;
}
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
+static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
void __iomem *port = ap->ioaddr.cmd_addr;
const char *reason;
@@ -620,7 +617,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_long);
+ rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
if (rc) {
reason = "PHY debouncing failed";
goto err;
@@ -924,11 +921,8 @@ static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED)
- qc->err_mask |= AC_ERR_OTHER;
-
/* make DMA engine forget about the failed command */
- if (qc->err_mask)
+ if (qc->flags & ATA_QCFLAG_FAILED)
sil24_init_port(ap);
}
@@ -964,11 +958,10 @@ static int sil24_port_start(struct ata_port *ap)
return 0;
}
-static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
- unsigned long port_flags,
- void __iomem *host_base,
- void __iomem *port_base)
+static void sil24_init_controller(struct ata_host *host)
{
+ void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
+ void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
u32 tmp;
int i;
@@ -979,7 +972,7 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
writel(0, host_base + HOST_CTRL);
/* init ports */
- for (i = 0; i < n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
void __iomem *port = port_base + i * PORT_REGS_SIZE;
/* Initial PHY setting */
@@ -993,12 +986,12 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
PORT_CS_PORT_RST,
PORT_CS_PORT_RST, 10, 100);
if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
+ dev_printk(KERN_ERR, host->dev,
"failed to clear port RST\n");
}
/* Configure IRQ WoC */
- if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
else
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
@@ -1026,18 +1019,17 @@ static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct device *dev = &pdev->dev;
- unsigned int board_id = (unsigned int)ent->driver_data;
- struct ata_port_info *pinfo = &sil24_port_info[board_id];
- struct ata_probe_ent *probe_ent;
- void __iomem *host_base;
- void __iomem *port_base;
+ struct ata_port_info pi = sil24_port_info[ent->driver_data];
+ const struct ata_port_info *ppi[] = { &pi, NULL };
+ void __iomem * const *iomap;
+ struct ata_host *host;
int i, rc;
u32 tmp;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* acquire resources */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -1047,33 +1039,36 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
DRV_NAME);
if (rc)
return rc;
+ iomap = pcim_iomap_table(pdev);
- /* allocate & init probe_ent */
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- return -ENOMEM;
+ /* apply workaround for completion IRQ loss on PCI-X errata */
+ if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+ tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL);
+ if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying completion IRQ loss on PCI-X "
+ "errata fix\n");
+ else
+ pi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+ }
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
+ /* allocate and fill host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi,
+ SIL24_FLAG2NPORTS(ppi[0]->flags));
+ if (!host)
+ return -ENOMEM;
+ host->iomap = iomap;
- probe_ent->sht = pinfo->sht;
- probe_ent->port_flags = pinfo->flags;
- probe_ent->pio_mask = pinfo->pio_mask;
- probe_ent->mwdma_mask = pinfo->mwdma_mask;
- probe_ent->udma_mask = pinfo->udma_mask;
- probe_ent->port_ops = pinfo->port_ops;
- probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->flags);
+ for (i = 0; i < host->n_ports; i++) {
+ void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
+ host->ports[i]->ioaddr.cmd_addr = port;
+ host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
- host_base = probe_ent->iomap[SIL24_HOST_BAR];
- port_base = probe_ent->iomap[SIL24_PORT_BAR];
+ ata_std_ports(&host->ports[i]->ioaddr);
+ }
- /*
- * Configure the device
- */
+ /* configure and activate the device */
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (rc) {
@@ -1099,36 +1094,11 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- /* Apply workaround for completion IRQ loss on PCI-X errata */
- if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
- tmp = readl(host_base + HOST_CTRL);
- if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying completion IRQ loss on PCI-X "
- "errata fix\n");
- else
- probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
- }
-
- for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
-
- probe_ent->port[i].cmd_addr = port;
- probe_ent->port[i].scr_addr = port + PORT_SCONTROL;
-
- ata_std_ports(&probe_ent->port[i]);
- }
-
- sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
- host_base, port_base);
+ sil24_init_controller(host);
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,
+ &sil24_sht);
}
#ifdef CONFIG_PM
@@ -1136,7 +1106,6 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
- void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -1146,8 +1115,7 @@ static int sil24_pci_device_resume(struct pci_dev *pdev)
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
writel(HOST_CTRL_GLOBAL_RST, host_base + HOST_CTRL);
- sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
- host_base, port_base);
+ sil24_init_controller(host);
ata_host_resume(host);
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index a787f0d4a5b..d8ee062e82f 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -121,7 +121,6 @@ static const struct ata_port_operations sis_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -131,7 +130,6 @@ static const struct ata_port_operations sis_ops = {
};
static struct ata_port_info sis_port_info = {
- .sht = &sis_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x7,
@@ -256,12 +254,13 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent = NULL;
- int rc;
+ struct ata_port_info pi = sis_port_info;
+ const struct ata_port_info *ppi[2] = { &pi, &pi };
+ struct ata_host *host;
u32 genctl, val;
- struct ata_port_info pi = sis_port_info, *ppi[2] = { &pi, &pi };
u8 pmr;
u8 port2_start = 0x20;
+ int rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -270,19 +269,6 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
- return rc;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
-
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
@@ -349,30 +335,26 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return -ENOMEM;
+ rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+ if (rc)
+ return rc;
- if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
+ if (!(pi.flags & SIS_FLAG_CFGSCR)) {
void __iomem *mmio;
- mmio = pcim_iomap(pdev, SIS_SCR_PCI_BAR, 0);
- if (!mmio)
- return -ENOMEM;
+ rc = pcim_iomap_regions(pdev, 1 << SIS_SCR_PCI_BAR, DRV_NAME);
+ if (rc)
+ return rc;
+ mmio = host->iomap[SIS_SCR_PCI_BAR];
- probe_ent->port[0].scr_addr = mmio;
- probe_ent->port[1].scr_addr = mmio + port2_start;
+ host->ports[0]->ioaddr.scr_addr = mmio;
+ host->ports[1]->ioaddr.scr_addr = mmio + port2_start;
}
pci_set_master(pdev);
pci_intx(pdev, 1);
-
- if (!ata_device_add(probe_ent))
- return -EIO;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
-
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &sis_sht);
}
static int __init sis_init(void)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index b121195cc59..17246734fe7 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -56,7 +56,9 @@
#define DRV_VERSION "2.1"
enum {
- K2_FLAG_NO_ATAPI_DMA = (1 << 29),
+ /* ap->flags bits */
+ K2_FLAG_SATA_8_PORTS = (1 << 24),
+ K2_FLAG_NO_ATAPI_DMA = (1 << 25),
/* Taskfile registers offsets */
K2_SATA_TF_CMD_OFFSET = 0x00,
@@ -90,17 +92,6 @@ enum {
board_svw8 = 1,
};
-static const struct k2_board_info {
- unsigned int n_ports;
- unsigned long port_flags;
-} k2_board_info[] = {
- /* board_svw4 */
- { 4, K2_FLAG_NO_ATAPI_DMA },
-
- /* board_svw8 */
- { 8, K2_FLAG_NO_ATAPI_DMA },
-};
-
static u8 k2_stat_check_status(struct ata_port *ap);
@@ -297,7 +288,7 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
/* Match it to a port node */
index = (ap == ap->host->ports[0]) ? 0 : 1;
for (np = np->child; np != NULL; np = np->sibling) {
- const u32 *reg = get_property(np, "reg", NULL);
+ const u32 *reg = of_get_property(np, "reg", NULL);
if (!reg)
continue;
if (index == *reg)
@@ -354,7 +345,6 @@ static const struct ata_port_operations k2_sata_ops = {
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -363,6 +353,28 @@ static const struct ata_port_operations k2_sata_ops = {
.port_start = ata_port_start,
};
+static const struct ata_port_info k2_port_info[] = {
+ /* board_svw4 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &k2_sata_ops,
+ },
+ /* board_svw8 */
+ {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | K2_FLAG_NO_ATAPI_DMA |
+ K2_FLAG_SATA_8_PORTS,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &k2_sata_ops,
+ },
+};
+
static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
{
port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET;
@@ -386,17 +398,24 @@ static void k2_sata_setup_port(struct ata_ioports *port, void __iomem *base)
static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct device *dev = &pdev->dev;
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[] =
+ { &k2_port_info[ent->driver_data], NULL };
+ struct ata_host *host;
void __iomem *mmio_base;
- const struct k2_board_info *board_info =
- &k2_board_info[ent->driver_data];
- int rc;
- int i;
+ int n_ports, i, rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ n_ports = 4;
+ if (ppi[0]->flags & K2_FLAG_SATA_8_PORTS)
+ n_ports = 8;
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
+ if (!host)
+ return -ENOMEM;
+
/*
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
@@ -404,6 +423,7 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
rc = pcim_enable_device(pdev);
if (rc)
return rc;
+
/*
* Check if we have resources mapped at all (second function may
* have been disabled by firmware)
@@ -417,6 +437,15 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
+ mmio_base = host->iomap[5];
+
+ /* different controllers have different number of ports - currently 4 or 8 */
+ /* All ports are on the same function. Multi-function device is no
+ * longer available. This should not be seen in any system. */
+ for (i = 0; i < host->n_ports; i++)
+ k2_sata_setup_port(&host->ports[i]->ioaddr,
+ mmio_base + i * K2_SATA_PORT_OFFSET);
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
@@ -425,38 +454,6 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
if (rc)
return rc;
- probe_ent = devm_kzalloc(dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = &k2_sata_sht;
- probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO | board_info->port_flags;
- probe_ent->port_ops = &k2_sata_ops;
- probe_ent->n_ports = 4;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- /* We don't care much about the PIO/UDMA masks, but the core won't like us
- * if we don't fill these
- */
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x7;
- probe_ent->udma_mask = 0x7f;
-
- mmio_base = probe_ent->iomap[5];
-
- /* different controllers have different number of ports - currently 4 or 8 */
- /* All ports are on the same function. Multi-function device is no
- * longer available. This should not be seen in any system. */
- for (i = 0; i < board_info->n_ports; i++)
- k2_sata_setup_port(&probe_ent->port[i],
- mmio_base + i * K2_SATA_PORT_OFFSET);
-
/* Clear a magic bit in SCR1 according to Darwin, those help
* some funky seagate drives (though so far, those were already
* set by the firmware on the machines I had access to)
@@ -469,12 +466,8 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &k2_sata_sht);
}
/* 0x240 is device ID for Apple K2 device
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 1a081c3a8c0..3a4f44559d0 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -151,24 +151,23 @@ struct pdc_host_priv {
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance);
static void pdc_eng_timeout(struct ata_port *ap);
static void pdc_20621_phy_reset (struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
+static unsigned int pdc20621_dimm_init(struct ata_host *host);
+static int pdc20621_detect_dimm(struct ata_host *host);
+static unsigned int pdc20621_i2c_read(struct ata_host *host,
u32 device, u32 subaddr, u32 *pdata);
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+static int pdc20621_prog_dimm0(struct ata_host *host);
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host);
#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe,
+static void pdc20621_get_from_dimm(struct ata_host *host,
void *psource, u32 offset, u32 size);
#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe,
+static void pdc20621_put_to_dimm(struct ata_host *host,
void *psource, u32 offset, u32 size);
static void pdc20621_irq_clear(struct ata_port *ap);
static unsigned int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
@@ -204,7 +203,6 @@ static const struct ata_port_operations pdc_20621_ops = {
.qc_issue = pdc20621_qc_issue_prot,
.data_xfer = ata_data_xfer,
.eng_timeout = pdc_eng_timeout,
- .irq_handler = pdc20621_interrupt,
.irq_clear = pdc20621_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -214,7 +212,6 @@ static const struct ata_port_operations pdc_20621_ops = {
static const struct ata_port_info pdc_port_info[] = {
/* board_20621 */
{
- .sht = &pdc_sata_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SRST | ATA_FLAG_MMIO |
ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
@@ -882,15 +879,15 @@ static void pdc_sata_setup_port(struct ata_ioports *port, void __iomem *base)
#ifdef ATA_VERBOSE_DEBUG
-static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_get_from_dimm(struct ata_host *host, void *psource,
u32 offset, u32 size)
{
u32 window_size;
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
- void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -937,15 +934,15 @@ static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource,
#endif
-static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
+static void pdc20621_put_to_dimm(struct ata_host *host, void *psource,
u32 offset, u32 size)
{
u32 window_size;
u16 idx;
u8 page_mask;
long dist;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
- void __iomem *dimm_mmio = pe->iomap[PDC_DIMM_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
+ void __iomem *dimm_mmio = host->iomap[PDC_DIMM_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -987,10 +984,10 @@ static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource,
}
-static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
+static unsigned int pdc20621_i2c_read(struct ata_host *host, u32 device,
u32 subaddr, u32 *pdata)
{
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
u32 i2creg = 0;
u32 status;
u32 count =0;
@@ -1023,17 +1020,17 @@ static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device,
}
-static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+static int pdc20621_detect_dimm(struct ata_host *host)
{
u32 data=0 ;
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
if (data == 100)
return 100;
} else
return 0;
- if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+ if (pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
if(data <= 0x75)
return 133;
} else
@@ -1043,13 +1040,13 @@ static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
}
-static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+static int pdc20621_prog_dimm0(struct ata_host *host)
{
u32 spd0[50];
u32 data = 0;
int size, i;
u8 bdimmsize;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
static const struct {
unsigned int reg;
unsigned int ofs;
@@ -1072,7 +1069,7 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
mmio += PDC_CHIP0_OFS;
for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
pdc_i2c_read_data[i].reg,
&spd0[pdc_i2c_read_data[i].ofs]);
@@ -1108,11 +1105,11 @@ static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
}
-static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+static unsigned int pdc20621_prog_dimm_global(struct ata_host *host)
{
u32 data, spd0;
int error, i;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1129,7 +1126,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
/* Turn on for ECC */
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
data |= (0x01 << 16);
@@ -1156,7 +1153,7 @@ static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
}
-static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+static unsigned int pdc20621_dimm_init(struct ata_host *host)
{
int speed, size, length;
u32 addr,spd0,pci_status;
@@ -1166,7 +1163,7 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
u32 ticks=0;
u32 clock=0;
u32 fparam=0;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1225,18 +1222,18 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
Read SPD of DIMM by I2C interface,
and program the DIMM Module Controller.
*/
- if (!(speed = pdc20621_detect_dimm(pe))) {
+ if (!(speed = pdc20621_detect_dimm(host))) {
printk(KERN_ERR "Detect Local DIMM Fail\n");
return 1; /* DIMM error */
}
VPRINTK("Local DIMM Speed = %d\n", speed);
/* Programming DIMM0 Module Control Register (index_CID0:80h) */
- size = pdc20621_prog_dimm0(pe);
+ size = pdc20621_prog_dimm0(host);
VPRINTK("Local DIMM Size = %dMB\n",size);
/* Programming DIMM Module Global Control Register (index_CID0:88h) */
- if (pdc20621_prog_dimm_global(pe)) {
+ if (pdc20621_prog_dimm_global(host)) {
printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
return 1;
}
@@ -1249,20 +1246,20 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
'9','8','0','3','1','6','1','2',0,0};
u8 test_parttern2[40] = {0};
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
- pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x10040, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern2, 0x40, 40);
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x10040, 40);
+ pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040,
+ pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x10040,
40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
- pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
- pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+ pdc20621_put_to_dimm(host, (void *) test_parttern1, 0x40, 40);
+ pdc20621_get_from_dimm(host, (void *) test_parttern2, 0x40, 40);
printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0],
test_parttern2[1], &(test_parttern2[2]));
}
@@ -1270,14 +1267,14 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
/* ECC initiliazation. */
- pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+ pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
PDC_DIMM_SPD_TYPE, &spd0);
if (spd0 == 0x02) {
VPRINTK("Start ECC initialization\n");
addr = 0;
length = size * 1024 * 1024;
while (addr < length) {
- pdc20621_put_to_dimm(pe, (void *) &tmp, addr,
+ pdc20621_put_to_dimm(host, (void *) &tmp, addr,
sizeof(u32));
addr += sizeof(u32);
}
@@ -1287,10 +1284,10 @@ static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
}
-static void pdc_20621_init(struct ata_probe_ent *pe)
+static void pdc_20621_init(struct ata_host *host)
{
u32 tmp;
- void __iomem *mmio = pe->iomap[PDC_MMIO_BAR];
+ void __iomem *mmio = host->iomap[PDC_MMIO_BAR];
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -1321,15 +1318,25 @@ static void pdc_20621_init(struct ata_probe_ent *pe)
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
+ const struct ata_port_info *ppi[] =
+ { &pdc_port_info[ent->driver_data], NULL };
+ struct ata_host *host;
void __iomem *base;
struct pdc_host_priv *hpriv;
- unsigned int board_idx = (unsigned int) ent->driver_data;
int rc;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+ hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
+ if (!host || !hpriv)
+ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+ /* acquire resources and fill host */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
@@ -1340,7 +1347,15 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
+
+ base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+ pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
+ pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
+ pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
+ pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
+ /* configure and activate */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
return rc;
@@ -1348,50 +1363,13 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
+ if (pdc20621_dimm_init(host))
return -ENOMEM;
-
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
- if (!hpriv)
- return -ENOMEM;
-
- probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->port_flags = pdc_port_info[board_idx].flags;
- probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
- probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
- probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
- probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
-
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- probe_ent->private_data = hpriv;
- base = probe_ent->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
-
- probe_ent->n_ports = 4;
- pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
- pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
- pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
- pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+ pdc_20621_init(host);
pci_set_master(pdev);
-
- /* initialize adapter */
- /* initialize local dimm */
- if (pdc20621_dimm_init(probe_ent))
- return -ENOMEM;
- pdc_20621_init(probe_ent);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, pdc20621_interrupt,
+ IRQF_SHARED, &pdc_sata_sht);
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index d659ace80f4..f74e383de08 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -115,7 +115,6 @@ static const struct ata_port_operations uli_ops = {
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -127,7 +126,6 @@ static const struct ata_port_operations uli_ops = {
};
static struct ata_port_info uli_port_info = {
- .sht = &uli_sht,
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_IGN_SIMPLEX,
.pio_mask = 0x1f, /* pio0-4 */
@@ -185,12 +183,13 @@ static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
- struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi[2];
- int rc;
+ const struct ata_port_info *ppi[] = { &uli_port_info, NULL };
unsigned int board_idx = (unsigned int) ent->driver_data;
+ struct ata_host *host;
struct uli_priv *hpriv;
void __iomem * const *iomap;
+ struct ata_ioports *ioaddr;
+ int n_ports, rc;
if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
@@ -199,54 +198,42 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
- return rc;
- }
-
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ n_ports = 2;
+ if (board_idx == uli_5287)
+ n_ports = 4;
+ rc = ata_pci_prepare_native_host(pdev, ppi, n_ports, &host);
if (rc)
return rc;
- ppi[0] = ppi[1] = &uli_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return -ENOMEM;
-
hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv)
return -ENOMEM;
+ host->private_data = hpriv;
- probe_ent->private_data = hpriv;
-
- iomap = pcim_iomap_table(pdev);
+ iomap = host->iomap;
switch (board_idx) {
case uli_5287:
hpriv->scr_cfg_addr[0] = ULI5287_BASE;
hpriv->scr_cfg_addr[1] = ULI5287_BASE + ULI5287_OFFS;
- probe_ent->n_ports = 4;
- probe_ent->port[2].cmd_addr = iomap[0] + 8;
- probe_ent->port[2].altstatus_addr =
- probe_ent->port[2].ctl_addr = (void __iomem *)
+ ioaddr = &host->ports[2]->ioaddr;
+ ioaddr->cmd_addr = iomap[0] + 8;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = (void __iomem *)
((unsigned long)iomap[1] | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[2].bmdma_addr = iomap[4] + 16;
+ ioaddr->bmdma_addr = iomap[4] + 16;
hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
+ ata_std_ports(ioaddr);
- probe_ent->port[3].cmd_addr = iomap[2] + 8;
- probe_ent->port[3].altstatus_addr =
- probe_ent->port[3].ctl_addr = (void __iomem *)
+ ioaddr = &host->ports[3]->ioaddr;
+ ioaddr->cmd_addr = iomap[2] + 8;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = (void __iomem *)
((unsigned long)iomap[3] | ATA_PCI_CTL_OFS) + 4;
- probe_ent->port[3].bmdma_addr = iomap[4] + 24;
+ ioaddr->bmdma_addr = iomap[4] + 24;
hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
-
- ata_std_ports(&probe_ent->port[2]);
- ata_std_ports(&probe_ent->port[3]);
+ ata_std_ports(ioaddr);
break;
case uli_5289:
@@ -266,12 +253,8 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_intx(pdev, 1);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &uli_sht);
}
static int __init uli_init(void)
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 598e6a26a48..305ab7c68ca 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -64,8 +64,6 @@ enum {
PORT0 = (1 << 1),
PORT1 = (1 << 0),
ALL_PORTS = PORT0 | PORT1,
- PATA_PORT = 2, /* PATA is port 2 */
- N_PORTS = 3,
NATIVE_MODE_ALL = (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
@@ -78,11 +76,9 @@ static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
-static void vt6421_sata_error_handler(struct ata_port *ap);
-static void vt6421_pata_error_handler(struct ata_port *ap);
+static int vt6421_pata_cable_detect(struct ata_port *ap);
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev);
static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev);
-static int vt6421_port_start(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
{ PCI_VDEVICE(VIA, 0x5337), vt6420 },
@@ -141,7 +137,6 @@ static const struct ata_port_operations vt6420_sata_ops = {
.error_handler = vt6420_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -172,15 +167,15 @@ static const struct ata_port_operations vt6421_pata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = vt6421_pata_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = vt6421_pata_cable_detect,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
- .port_start = vt6421_port_start,
+ .port_start = ata_port_start,
};
static const struct ata_port_operations vt6421_sata_ops = {
@@ -203,10 +198,10 @@ static const struct ata_port_operations vt6421_sata_ops = {
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
- .error_handler = vt6421_sata_error_handler,
+ .error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .cable_detect = ata_cable_sata,
- .irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -214,11 +209,10 @@ static const struct ata_port_operations vt6421_sata_ops = {
.scr_read = svia_scr_read,
.scr_write = svia_scr_write,
- .port_start = vt6421_port_start,
+ .port_start = ata_port_start,
};
-static struct ata_port_info vt6420_port_info = {
- .sht = &svia_sht,
+static const struct ata_port_info vt6420_port_info = {
.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
@@ -226,6 +220,22 @@ static struct ata_port_info vt6420_port_info = {
.port_ops = &vt6420_sata_ops,
};
+static struct ata_port_info vt6421_sport_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &vt6421_sata_ops,
+};
+
+static struct ata_port_info vt6421_pport_info = {
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0,
+ .udma_mask = 0x7f,
+ .port_ops = &vt6421_pata_ops,
+};
+
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
MODULE_LICENSE("GPL");
@@ -258,6 +268,7 @@ static void svia_noop_freeze(struct ata_port *ap)
/**
* vt6420_prereset - prereset for vt6420
* @ap: target ATA port
+ * @deadline: deadline jiffies for the operation
*
* SCR registers on vt6420 are pieces of shit and may hang the
* whole machine completely if accessed with the wrong timing.
@@ -274,7 +285,7 @@ static void svia_noop_freeze(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-static int vt6420_prereset(struct ata_port *ap)
+static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
{
struct ata_eh_context *ehc = &ap->eh_context;
unsigned long timeout = jiffies + (HZ * 5);
@@ -319,7 +330,7 @@ static int vt6420_prereset(struct ata_port *ap)
skip_scr:
/* wait for !BSY */
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+ ata_wait_ready(ap, deadline);
return 0;
}
@@ -330,35 +341,15 @@ static void vt6420_error_handler(struct ata_port *ap)
NULL, ata_std_postreset);
}
-static int vt6421_pata_prereset(struct ata_port *ap)
+static int vt6421_pata_cable_detect(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 tmp;
pci_read_config_byte(pdev, PATA_UDMA_TIMING, &tmp);
if (tmp & 0x10)
- ap->cbl = ATA_CBL_PATA40;
- else
- ap->cbl = ATA_CBL_PATA80;
- return 0;
-}
-
-static void vt6421_pata_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, vt6421_pata_prereset, ata_std_softreset,
- NULL, ata_std_postreset);
-}
-
-static int vt6421_sata_prereset(struct ata_port *ap)
-{
- ap->cbl = ATA_CBL_SATA;
- return 0;
-}
-
-static void vt6421_sata_error_handler(struct ata_port *ap)
-{
- return ata_bmdma_drive_eh(ap, vt6421_sata_prereset, ata_std_softreset,
- NULL, ata_std_postreset);
+ return ATA_CBL_PATA40;
+ return ATA_CBL_PATA80;
}
static void vt6421_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
@@ -375,16 +366,6 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
}
-static int vt6421_port_start(struct ata_port *ap)
-{
- if (ap->port_no == PATA_PORT) {
- ap->ops = &vt6421_pata_ops;
- ap->mwdma_mask = 0;
- ap->flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_LEGACY | ATA_FLAG_SRST;
- }
- return ata_port_start(ap);
-}
-
static const unsigned int svia_bar_sizes[] = {
8, 4, 8, 4, 16, 256
};
@@ -403,79 +384,78 @@ static void __iomem * vt6421_scr_addr(void __iomem *addr, unsigned int port)
return addr + (port * 64);
}
-static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
- void __iomem * const *iomap, unsigned int port)
+static void vt6421_init_addrs(struct ata_port *ap)
{
- void __iomem *reg_addr = iomap[port];
- void __iomem *bmdma_addr = iomap[4] + (port * 8);
-
- probe_ent->port[port].cmd_addr = reg_addr;
- probe_ent->port[port].altstatus_addr =
- probe_ent->port[port].ctl_addr = (void __iomem *)
+ void __iomem * const * iomap = ap->host->iomap;
+ void __iomem *reg_addr = iomap[ap->port_no];
+ void __iomem *bmdma_addr = iomap[4] + (ap->port_no * 8);
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ ioaddr->cmd_addr = reg_addr;
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = (void __iomem *)
((unsigned long)(reg_addr + 8) | ATA_PCI_CTL_OFS);
- probe_ent->port[port].bmdma_addr = bmdma_addr;
- probe_ent->port[port].scr_addr = vt6421_scr_addr(iomap[5], port);
+ ioaddr->bmdma_addr = bmdma_addr;
+ ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
- ata_std_ports(&probe_ent->port[port]);
+ ata_std_ports(ioaddr);
}
-static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
+static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
{
- struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi[2];
- void __iomem *bar5;
+ const struct ata_port_info *ppi[] = { &vt6420_port_info, NULL };
+ struct ata_host *host;
+ int rc;
- ppi[0] = ppi[1] = &vt6420_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
- if (!probe_ent)
- return NULL;
+ rc = ata_pci_prepare_native_host(pdev, ppi, 2, &host);
+ if (rc)
+ return rc;
+ *r_host = host;
- bar5 = pcim_iomap(pdev, 5, 0);
- if (!bar5) {
+ rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME);
+ if (rc) {
dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n");
- return NULL;
+ return rc;
}
- probe_ent->port[0].scr_addr = svia_scr_addr(bar5, 0);
- probe_ent->port[1].scr_addr = svia_scr_addr(bar5, 1);
+ host->ports[0]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 0);
+ host->ports[1]->ioaddr.scr_addr = svia_scr_addr(host->iomap[5], 1);
- return probe_ent;
+ return 0;
}
-static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
+static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
{
- struct ata_probe_ent *probe_ent;
- unsigned int i;
+ const struct ata_port_info *ppi[] =
+ { &vt6421_sport_info, &vt6421_sport_info, &vt6421_pport_info };
+ struct ata_host *host;
+ int i, rc;
+
+ *r_host = host = ata_host_alloc_pinfo(&pdev->dev, ppi, ARRAY_SIZE(ppi));
+ if (!host) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to allocate host\n");
+ return -ENOMEM;
+ }
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent)
- return NULL;
-
- memset(probe_ent, 0, sizeof(*probe_ent));
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
- probe_ent->sht = &svia_sht;
- probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
- probe_ent->port_ops = &vt6421_sata_ops;
- probe_ent->n_ports = N_PORTS;
- probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x07;
- probe_ent->udma_mask = 0x7f;
-
- for (i = 0; i < 6; i++)
- if (!pcim_iomap(pdev, i, 0)) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to iomap PCI BAR %d\n", i);
- return NULL;
- }
+ rc = pcim_iomap_regions(pdev, 0x1f, DRV_NAME);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to request/iomap "
+ "PCI BARs (errno=%d)\n", rc);
+ return rc;
+ }
+ host->iomap = pcim_iomap_table(pdev);
- for (i = 0; i < N_PORTS; i++)
- vt6421_init_addrs(probe_ent, pcim_iomap_table(pdev), i);
+ for (i = 0; i < host->n_ports; i++)
+ vt6421_init_addrs(host->ports[i]);
- return probe_ent;
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ return 0;
}
static void svia_configure(struct pci_dev *pdev)
@@ -522,7 +502,7 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
static int printed_version;
unsigned int i;
int rc;
- struct ata_probe_ent *probe_ent;
+ struct ata_host *host;
int board_id = (int) ent->driver_data;
const int *bar_sizes;
u8 tmp8;
@@ -534,12 +514,6 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc) {
- pcim_pin_device(pdev);
- return rc;
- }
-
if (board_id == vt6420) {
pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
if (tmp8 & SATA_2DEV) {
@@ -565,32 +539,18 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
- rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
- if (rc)
- return rc;
-
if (board_id == vt6420)
- probe_ent = vt6420_init_probe_ent(pdev);
+ rc = vt6420_prepare_host(pdev, &host);
else
- probe_ent = vt6421_init_probe_ent(pdev);
-
- if (!probe_ent) {
- dev_printk(KERN_ERR, &pdev->dev, "out of memory\n");
- return -ENOMEM;
- }
+ rc = vt6421_prepare_host(pdev, &host);
+ if (rc)
+ return rc;
svia_configure(pdev);
pci_set_master(pdev);
-
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &svia_sht);
}
static int __init svia_init(void)
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 170bad1b415..80126f835d3 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -333,7 +333,6 @@ static const struct ata_port_operations vsc_sata_ops = {
.thaw = vsc_thaw,
.error_handler = ata_bmdma_error_handler,
.post_internal_cmd = ata_bmdma_post_internal_cmd,
- .irq_handler = vsc_sata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
@@ -367,30 +366,50 @@ static void __devinit vsc_sata_setup_port(struct ata_ioports *port,
static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
+ static const struct ata_port_info pi = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &vsc_sata_ops,
+ };
+ const struct ata_port_info *ppi[] = { &pi, NULL };
static int printed_version;
- struct ata_probe_ent *probe_ent;
+ struct ata_host *host;
void __iomem *mmio_base;
- int rc;
+ int i, rc;
u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* allocate host */
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 4);
+ if (!host)
+ return -ENOMEM;
+
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- /*
- * Check if we have needed resource mapped.
- */
+ /* check if we have needed resource mapped */
if (pci_resource_len(pdev, 0) == 0)
return -ENODEV;
+ /* map IO regions and intialize host accordingly */
rc = pcim_iomap_regions(pdev, 1 << VSC_MMIO_BAR, DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
+ host->iomap = pcim_iomap_table(pdev);
+
+ mmio_base = host->iomap[VSC_MMIO_BAR];
+
+ for (i = 0; i < host->n_ports; i++)
+ vsc_sata_setup_port(&host->ports[i]->ioaddr,
+ mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
@@ -402,12 +421,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
if (rc)
return rc;
- probe_ent = devm_kzalloc(&pdev->dev, sizeof(*probe_ent), GFP_KERNEL);
- if (probe_ent == NULL)
- return -ENOMEM;
- probe_ent->dev = pci_dev_to_dev(pdev);
- INIT_LIST_HEAD(&probe_ent->node);
-
/*
* Due to a bug in the chip, the default cache line size can't be
* used (unless the default is non-zero).
@@ -418,33 +431,6 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
if (pci_enable_msi(pdev) == 0)
pci_intx(pdev, 0);
- else
- probe_ent->irq_flags = IRQF_SHARED;
-
- probe_ent->sht = &vsc_sata_sht;
- probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_MMIO;
- probe_ent->port_ops = &vsc_sata_ops;
- probe_ent->n_ports = 4;
- probe_ent->irq = pdev->irq;
- probe_ent->iomap = pcim_iomap_table(pdev);
-
- /* We don't care much about the PIO/UDMA masks, but the core won't like us
- * if we don't fill these
- */
- probe_ent->pio_mask = 0x1f;
- probe_ent->mwdma_mask = 0x07;
- probe_ent->udma_mask = 0x7f;
-
- mmio_base = probe_ent->iomap[VSC_MMIO_BAR];
-
- /* We have 4 ports per PCI function */
- vsc_sata_setup_port(&probe_ent->port[0], mmio_base + 1 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[1], mmio_base + 2 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[2], mmio_base + 3 * VSC_SATA_PORT_OFFSET);
- vsc_sata_setup_port(&probe_ent->port[3], mmio_base + 4 * VSC_SATA_PORT_OFFSET);
-
- pci_set_master(pdev);
/*
* Config offset 0x98 is "Extended Control and Status Register 0"
@@ -454,11 +440,9 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
*/
pci_write_config_dword(pdev, 0x98, 0);
- if (!ata_device_add(probe_ent))
- return -ENODEV;
-
- devm_kfree(&pdev->dev, probe_ent);
- return 0;
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, vsc_sata_interrupt,
+ IRQF_SHARED, &vsc_sata_sht);
}
static const struct pci_device_id vsc_sata_pci_tbl[] = {
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 8d60c4eb54f..2ebd07f2ef8 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -6,7 +6,6 @@
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
-#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index e9eb7382ac3..b39ea3f59c9 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -2,10 +2,10 @@
obj-y := core.o sys.o bus.o dd.o \
driver.o class.o platform.o \
- cpu.o firmware.o init.o map.o dmapool.o \
- dma-mapping.o devres.o \
+ cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o
obj-y += power/
+obj-$(CONFIG_HAS_DMA) += dma-mapping.o dmapool.o
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
diff --git a/drivers/base/base.h b/drivers/base/base.h
index d597f2659b2..5512d84452f 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -45,3 +45,5 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
extern char *make_class_name(const char *name, struct kobject *kobj);
extern void devres_release_all(struct device *dev);
+
+extern struct kset devices_subsys;
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 1d76e234965..dca734819e5 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -17,7 +17,7 @@
#include "power/power.h"
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
-#define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj)
+#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
/*
* sysfs bindings for drivers
@@ -123,7 +123,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
{
int error;
if (get_bus(bus)) {
- error = sysfs_create_file(&bus->subsys.kset.kobj, &attr->attr);
+ error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
put_bus(bus);
} else
error = -EINVAL;
@@ -133,7 +133,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
{
if (get_bus(bus)) {
- sysfs_remove_file(&bus->subsys.kset.kobj, &attr->attr);
+ sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
put_bus(bus);
}
}
@@ -397,7 +397,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev)
static int make_deprecated_bus_links(struct device *dev)
{
return sysfs_create_link(&dev->kobj,
- &dev->bus->subsys.kset.kobj, "bus");
+ &dev->bus->subsys.kobj, "bus");
}
static void remove_deprecated_bus_links(struct device *dev)
@@ -431,7 +431,7 @@ int bus_add_device(struct device * dev)
if (error)
goto out_id;
error = sysfs_create_link(&dev->kobj,
- &dev->bus->subsys.kset.kobj, "subsystem");
+ &dev->bus->subsys.kobj, "subsystem");
if (error)
goto out_subsys;
error = make_deprecated_bus_links(dev);
@@ -810,7 +810,7 @@ int bus_register(struct bus_type * bus)
BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
- retval = kobject_set_name(&bus->subsys.kset.kobj, "%s", bus->name);
+ retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
if (retval)
goto out;
@@ -820,13 +820,13 @@ int bus_register(struct bus_type * bus)
goto out;
kobject_set_name(&bus->devices.kobj, "devices");
- bus->devices.subsys = &bus->subsys;
+ bus->devices.kobj.parent = &bus->subsys.kobj;
retval = kset_register(&bus->devices);
if (retval)
goto bus_devices_fail;
kobject_set_name(&bus->drivers.kobj, "drivers");
- bus->drivers.subsys = &bus->subsys;
+ bus->drivers.kobj.parent = &bus->subsys.kobj;
bus->drivers.ktype = &ktype_driver;
retval = kset_register(&bus->drivers);
if (retval)
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 80bbb207463..20c4ea6eb50 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -19,10 +19,8 @@
#include <linux/slab.h>
#include "base.h"
-extern struct subsystem devices_subsys;
-
#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
-#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj)
+#define to_class(obj) container_of(obj, struct class, subsys.kobj)
static ssize_t
class_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
@@ -80,7 +78,7 @@ int class_create_file(struct class * cls, const struct class_attribute * attr)
{
int error;
if (cls) {
- error = sysfs_create_file(&cls->subsys.kset.kobj, &attr->attr);
+ error = sysfs_create_file(&cls->subsys.kobj, &attr->attr);
} else
error = -EINVAL;
return error;
@@ -89,7 +87,7 @@ int class_create_file(struct class * cls, const struct class_attribute * attr)
void class_remove_file(struct class * cls, const struct class_attribute * attr)
{
if (cls)
- sysfs_remove_file(&cls->subsys.kset.kobj, &attr->attr);
+ sysfs_remove_file(&cls->subsys.kobj, &attr->attr);
}
static struct class *class_get(struct class *cls)
@@ -147,7 +145,7 @@ int class_register(struct class * cls)
INIT_LIST_HEAD(&cls->interfaces);
kset_init(&cls->class_dirs);
init_MUTEX(&cls->sem);
- error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
+ error = kobject_set_name(&cls->subsys.kobj, "%s", cls->name);
if (error)
return error;
@@ -611,7 +609,7 @@ int class_device_add(struct class_device *class_dev)
if (parent_class_dev)
class_dev->kobj.parent = &parent_class_dev->kobj;
else
- class_dev->kobj.parent = &parent_class->subsys.kset.kobj;
+ class_dev->kobj.parent = &parent_class->subsys.kobj;
error = kobject_add(&class_dev->kobj);
if (error)
@@ -619,7 +617,7 @@ int class_device_add(struct class_device *class_dev)
/* add the needed attributes to this device */
error = sysfs_create_link(&class_dev->kobj,
- &parent_class->subsys.kset.kobj, "subsystem");
+ &parent_class->subsys.kobj, "subsystem");
if (error)
goto out3;
class_dev->uevent_attr.attr.name = "uevent";
@@ -917,8 +915,8 @@ int __init classes_init(void)
/* ick, this is ugly, the things we go through to keep from showing up
* in sysfs... */
subsystem_init(&class_obj_subsys);
- if (!class_obj_subsys.kset.subsys)
- class_obj_subsys.kset.subsys = &class_obj_subsys;
+ if (!class_obj_subsys.kobj.parent)
+ class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
return 0;
}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 8aa090da1cd..b78fc1e6826 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -252,7 +252,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
struct kobject *top_kobj;
struct kset *kset;
char *envp[32];
- char data[PAGE_SIZE];
+ char *data = NULL;
char *pos;
int i;
size_t count = 0;
@@ -276,6 +276,10 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
if (!kset->uevent_ops->filter(kset, &dev->kobj))
goto out;
+ data = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
/* let the kset specific function add its keys */
pos = data;
retval = kset->uevent_ops->uevent(kset, &dev->kobj,
@@ -290,6 +294,7 @@ static ssize_t show_uevent(struct device *dev, struct device_attribute *attr,
count += sprintf(pos, "%s\n", envp[i]);
}
out:
+ free_page((unsigned long)data);
return count;
}
@@ -560,7 +565,7 @@ static struct kobject * get_device_parent(struct device *dev,
/* Set the parent to the class, not the parent device */
/* this keeps sysfs from having a symlink to make old udevs happy */
if (dev->class)
- return &dev->class->subsys.kset.kobj;
+ return &dev->class->subsys.kobj;
else if (parent)
return &parent->kobj;
@@ -572,7 +577,7 @@ static struct kobject *virtual_device_parent(struct device *dev)
static struct kobject *virtual_dir = NULL;
if (!virtual_dir)
- virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
+ virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
return virtual_dir;
}
@@ -706,12 +711,12 @@ int device_add(struct device *dev)
}
if (dev->class) {
- sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,
+ sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
"subsystem");
/* If this is not a "fake" compatible device, then create the
* symlink from the class to the device. */
- if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
- sysfs_create_link(&dev->class->subsys.kset.kobj,
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_create_link(&dev->class->subsys.kobj,
&dev->kobj, dev->bus_id);
if (parent) {
sysfs_create_link(&dev->kobj, &dev->parent->kobj,
@@ -769,8 +774,8 @@ int device_add(struct device *dev)
sysfs_remove_link(&dev->kobj, "subsystem");
/* If this is not a "fake" compatible device, remove the
* symlink from the class to the device. */
- if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
- sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj,
dev->bus_id);
if (parent) {
#ifdef CONFIG_SYSFS_DEPRECATED
@@ -870,8 +875,8 @@ void device_del(struct device * dev)
sysfs_remove_link(&dev->kobj, "subsystem");
/* If this is not a "fake" compatible device, remove the
* symlink from the class to the device. */
- if (dev->kobj.parent != &dev->class->subsys.kset.kobj)
- sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj,
dev->bus_id);
if (parent) {
#ifdef CONFIG_SYSFS_DEPRECATED
@@ -1187,9 +1192,9 @@ int device_rename(struct device *dev, char *new_name)
#endif
if (dev->class) {
- sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ sysfs_remove_link(&dev->class->subsys.kobj,
old_symlink_name);
- sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+ sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
dev->bus_id);
}
put_device(dev);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 18dba8e78da..92428e55b0c 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -226,12 +226,10 @@ static int device_probe_drivers(void *data)
*
* Walk the list of drivers that the bus has and call
* driver_probe_device() for each pair. If a compatible
- * pair is found, break out and return. If the bus specifies
- * multithreaded probing, walking the list of drivers is done
- * on a probing thread.
+ * pair is found, break out and return.
*
* Returns 1 if the device was bound to a driver;
- * 0 if no matching device was found or multithreaded probing is done;
+ * 0 if no matching device was found;
* -ENODEV if the device is not registered.
*
* When called for a USB interface, @dev->parent->sem must be held.
@@ -239,7 +237,6 @@ static int device_probe_drivers(void *data)
int device_attach(struct device * dev)
{
int ret = 0;
- struct task_struct *probe_task = ERR_PTR(-ENOMEM);
down(&dev->sem);
if (dev->driver) {
@@ -251,12 +248,7 @@ int device_attach(struct device * dev)
ret = 0;
}
} else {
- if (dev->bus->multithread_probe)
- probe_task = kthread_run(device_probe_drivers, dev,
- "probe-%s", dev->bus_id);
- if(IS_ERR(probe_task))
- ret = bus_for_each_drv(dev->bus, NULL, dev,
- __device_attach);
+ ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
}
up(&dev->sem);
return ret;
@@ -383,33 +375,6 @@ void driver_detach(struct device_driver * drv)
}
}
-#ifdef CONFIG_PCI_MULTITHREAD_PROBE
-static int __init wait_for_probes(void)
-{
- DEFINE_WAIT(wait);
-
- printk(KERN_INFO "%s: waiting for %d threads\n", __FUNCTION__,
- atomic_read(&probe_count));
- if (!atomic_read(&probe_count))
- return 0;
- while (atomic_read(&probe_count)) {
- prepare_to_wait(&probe_waitqueue, &wait, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&probe_count))
- schedule();
- }
- finish_wait(&probe_waitqueue, &wait);
- return 0;
-}
-
-core_initcall_sync(wait_for_probes);
-postcore_initcall_sync(wait_for_probes);
-arch_initcall_sync(wait_for_probes);
-subsys_initcall_sync(wait_for_probes);
-fs_initcall_sync(wait_for_probes);
-device_initcall_sync(wait_for_probes);
-late_initcall_sync(wait_for_probes);
-#endif
-
EXPORT_SYMBOL_GPL(device_bind_driver);
EXPORT_SYMBOL_GPL(device_release_driver);
EXPORT_SYMBOL_GPL(device_attach);
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index e177c9533b6..e1c0730a3b9 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -101,19 +101,6 @@ static void add_dr(struct device *dev, struct devres_node *node)
list_add_tail(&node->entry, &dev->devres_head);
}
-/**
- * devres_alloc - Allocate device resource data
- * @release: Release function devres will be associated with
- * @size: Allocation size
- * @gfp: Allocation flags
- *
- * allocate devres of @size bytes. The allocated area is zeroed, then
- * associated with @release. The returned pointer can be passed to
- * other devres_*() functions.
- *
- * RETURNS:
- * Pointer to allocated devres on success, NULL on failure.
- */
#ifdef CONFIG_DEBUG_DEVRES
void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
const char *name)
@@ -128,6 +115,19 @@ void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
}
EXPORT_SYMBOL_GPL(__devres_alloc);
#else
+/**
+ * devres_alloc - Allocate device resource data
+ * @release: Release function devres will be associated with
+ * @size: Allocation size
+ * @gfp: Allocation flags
+ *
+ * Allocate devres of @size bytes. The allocated area is zeroed, then
+ * associated with @release. The returned pointer can be passed to
+ * other devres_*() functions.
+ *
+ * RETURNS:
+ * Pointer to allocated devres on success, NULL on failure.
+ */
void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
{
struct devres *dr;
@@ -416,7 +416,7 @@ static int release_nodes(struct device *dev, struct list_head *first,
}
/**
- * devres_release_all - Release all resources
+ * devres_release_all - Release all managed resources
* @dev: Device to release resources for
*
* Release all resources associated with @dev. This function is
@@ -600,7 +600,7 @@ static int devm_kzalloc_match(struct device *dev, void *res, void *data)
}
/**
- * devm_kzalloc - Managed kzalloc
+ * devm_kzalloc - Resource-managed kzalloc
* @dev: Device to allocate memory for
* @size: Allocation size
* @gfp: Allocation gfp flags
@@ -628,7 +628,7 @@ void * devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
EXPORT_SYMBOL_GPL(devm_kzalloc);
/**
- * devm_kfree - Managed kfree
+ * devm_kfree - Resource-managed kfree
* @dev: Device this memory belongs to
* @p: Memory to free
*
diff --git a/drivers/base/firmware.c b/drivers/base/firmware.c
index cb1b98ae0d5..90c86293216 100644
--- a/drivers/base/firmware.c
+++ b/drivers/base/firmware.c
@@ -17,13 +17,13 @@
static decl_subsys(firmware, NULL, NULL);
-int firmware_register(struct subsystem * s)
+int firmware_register(struct kset *s)
{
- kset_set_kset_s(s, firmware_subsys);
+ kobj_set_kset_s(s, firmware_subsys);
return subsystem_register(s);
}
-void firmware_unregister(struct subsystem * s)
+void firmware_unregister(struct kset *s)
{
subsystem_unregister(s);
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 30480f6f2af..869ff8c0014 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,6 +160,11 @@ static void platform_device_release(struct device *dev)
*
* Create a platform device object which can have other objects attached
* to it, and which will have attached objects freed when it is released.
+ *
+ * This device will be marked as not supporting hotpluggable drivers; no
+ * device add/remove uevents will be generated. In the unusual case that
+ * the device isn't being dynamically allocated as a legacy "probe the
+ * hardware" driver, infrastructure code should reverse this marking.
*/
struct platform_device *platform_device_alloc(const char *name, unsigned int id)
{
@@ -172,6 +177,12 @@ struct platform_device *platform_device_alloc(const char *name, unsigned int id)
pa->pdev.id = id;
device_initialize(&pa->pdev.dev);
pa->pdev.dev.release = platform_device_release;
+
+ /* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
+ * legacy probe-the-hardware drivers, which don't properly split
+ * out device enumeration logic from drivers.
+ */
+ pa->pdev.dev.uevent_suppress = 1;
}
return pa ? &pa->pdev : NULL;
@@ -292,20 +303,22 @@ EXPORT_SYMBOL_GPL(platform_device_add);
* @pdev: platform device we're removing
*
* Note that this function will also release all memory- and port-based
- * resources owned by the device (@dev->resource).
+ * resources owned by the device (@dev->resource). This function
+ * must _only_ be externally called in error cases. All other usage
+ * is a bug.
*/
void platform_device_del(struct platform_device *pdev)
{
int i;
if (pdev) {
+ device_del(&pdev->dev);
+
for (i = 0; i < pdev->num_resources; i++) {
struct resource *r = &pdev->resource[i];
if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(r);
}
-
- device_del(&pdev->dev);
}
}
EXPORT_SYMBOL_GPL(platform_device_del);
@@ -347,8 +360,15 @@ EXPORT_SYMBOL_GPL(platform_device_unregister);
* This function creates a simple platform device that requires minimal
* resource and memory management. Canned release function freeing
* memory allocated for the device allows drivers using such devices
- * to be unloaded iwithout waiting for the last reference to the device
+ * to be unloaded without waiting for the last reference to the device
* to be dropped.
+ *
+ * This interface is primarily intended for use with legacy drivers
+ * which probe hardware directly. Because such drivers create sysfs
+ * device nodes themselves, rather than letting system infrastructure
+ * handle such device enumeration tasks, they don't fully conform to
+ * the Linux driver model. In particular, when such drivers are built
+ * as modules, they can't be "hotplugged".
*/
struct platform_device *platform_device_register_simple(char *name, unsigned int id,
struct resource *res, unsigned int num)
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index 58b6f77a1b3..a47ee1b70d2 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -16,8 +16,6 @@
#define to_dev(node) container_of(node, struct device, kobj.entry)
-extern struct subsystem devices_subsys;
-
/**
* We handle system devices differently - we suspend and shut them
@@ -36,7 +34,7 @@ void device_shutdown(void)
{
struct device * dev, *devn;
- list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.kset.list,
+ list_for_each_entry_safe_reverse(dev, devn, &devices_subsys.list,
kobj.entry) {
if (dev->bus && dev->bus->shutdown) {
dev_dbg(dev, "shutdown\n");
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 04e5db445c7..29f1291966c 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -25,7 +25,7 @@
#include "base.h"
-extern struct subsystem devices_subsys;
+extern struct kset devices_subsys;
#define to_sysdev(k) container_of(k, struct sys_device, kobj)
#define to_sysdev_attr(a) container_of(a, struct sysdev_attribute, attr)
@@ -138,7 +138,7 @@ int sysdev_class_register(struct sysdev_class * cls)
pr_debug("Registering sysdev class '%s'\n",
kobject_name(&cls->kset.kobj));
INIT_LIST_HEAD(&cls->drivers);
- cls->kset.subsys = &system_subsys;
+ cls->kset.kobj.parent = &system_subsys.kobj;
kset_set_kset_s(cls, system_subsys);
return kset_register(&cls->kset);
}
@@ -309,7 +309,7 @@ void sysdev_shutdown(void)
pr_debug("Shutting Down System Devices\n");
down(&sysdev_drivers_lock);
- list_for_each_entry_reverse(cls, &system_subsys.kset.list,
+ list_for_each_entry_reverse(cls, &system_subsys.list,
kset.kobj.entry) {
struct sys_device * sysdev;
@@ -384,7 +384,7 @@ int sysdev_suspend(pm_message_t state)
pr_debug("Suspending System Devices\n");
- list_for_each_entry_reverse(cls, &system_subsys.kset.list,
+ list_for_each_entry_reverse(cls, &system_subsys.list,
kset.kobj.entry) {
pr_debug("Suspending type '%s':\n",
@@ -457,7 +457,7 @@ gbl_driver:
}
/* resume other classes */
- list_for_each_entry_continue(cls, &system_subsys.kset.list,
+ list_for_each_entry_continue(cls, &system_subsys.list,
kset.kobj.entry) {
list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
pr_debug(" %s\n", kobject_name(&err_dev->kobj));
@@ -483,7 +483,7 @@ int sysdev_resume(void)
pr_debug("Resuming System Devices\n");
- list_for_each_entry(cls, &system_subsys.kset.list, kset.kobj.entry) {
+ list_for_each_entry(cls, &system_subsys.list, kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Resuming type '%s':\n",
@@ -501,7 +501,7 @@ int sysdev_resume(void)
int __init system_bus_init(void)
{
- system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
+ system_subsys.kobj.parent = &devices_subsys.kobj;
return subsystem_register(&system_subsys);
}
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 067a9e8bc37..8d8cdfec652 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -126,10 +126,13 @@ static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
rc = topology_add_dev(cpu);
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
topology_remove_dev(cpu);
break;
}
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index e2e04329096..1d9d9b4f48c 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -65,7 +65,6 @@ not be guaranteed. There are several ways to assure this:
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <asm/pgtable.h>
#include <asm/system.h>
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 5d656217153..27a139025ce 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1480,7 +1480,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp,
break;
case FDFMTEND:
floppy_off(drive);
- invalidate_bdev(inode->i_bdev, 0);
+ invalidate_bdev(inode->i_bdev);
break;
case FDGETPRM:
memset((void *)&getprm, 0, sizeof (getprm));
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 1a6aeac5a1c..01fbdd38e3b 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -194,15 +194,15 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
sl = sl_tail = NULL;
read_lock(&dev_base_lock);
- for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
+ for_each_netdev(ifp) {
dev_hold(ifp);
if (!is_aoe_netif(ifp))
- continue;
+ goto cont;
skb = new_skb(sizeof *h + sizeof *ch);
if (skb == NULL) {
printk(KERN_INFO "aoe: skb alloc failure\n");
- continue;
+ goto cont;
}
skb_put(skb, sizeof *h + sizeof *ch);
skb->dev = ifp;
@@ -221,6 +221,8 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
skb->next = sl;
sl = skb;
+cont:
+ dev_put(ifp);
}
read_unlock(&dev_base_lock);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 65a725cd342..370dfe1c422 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -45,6 +45,10 @@
#include <linux/blkdev.h>
#include <linux/genhd.h>
#include <linux/completion.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <scsi/scsi_ioctl.h>
+#include <linux/cdrom.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
#define DRIVER_NAME "HP CISS Driver (v 3.6.14)"
@@ -1152,6 +1156,30 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
kfree(ioc);
return status;
}
+
+ /* scsi_cmd_ioctl handles these, below, though some are not */
+ /* very meaningful for cciss. SG_IO is the main one people want. */
+
+ case SG_GET_VERSION_NUM:
+ case SG_SET_TIMEOUT:
+ case SG_GET_TIMEOUT:
+ case SG_GET_RESERVED_SIZE:
+ case SG_SET_RESERVED_SIZE:
+ case SG_EMULATED_HOST:
+ case SG_IO:
+ case SCSI_IOCTL_SEND_COMMAND:
+ return scsi_cmd_ioctl(filep, disk, cmd, argp);
+
+ /* scsi_cmd_ioctl would normally handle these, below, but */
+ /* they aren't a good fit for cciss, as CD-ROMs are */
+ /* not supported, and we don't have any bus/target/lun */
+ /* which we present to the kernel. */
+
+ case CDROM_SEND_PACKET:
+ case CDROMCLOSETRAY:
+ case CDROMEJECT:
+ case SCSI_IOCTL_GET_IDLUN:
+ case SCSI_IOCTL_GET_BUS_NUMBER:
default:
return -ENOTTY;
}
@@ -1234,7 +1262,7 @@ static void cciss_softirq_done(struct request *rq)
pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
}
- complete_buffers(rq->bio, rq->errors);
+ complete_buffers(rq->bio, (rq->errors == 0));
if (blk_fs_request(rq)) {
const int rw = rq_data_dir(rq);
@@ -1248,7 +1276,7 @@ static void cciss_softirq_done(struct request *rq)
add_disk_randomness(rq->rq_disk);
spin_lock_irqsave(&h->lock, flags);
- end_that_request_last(rq, rq->errors);
+ end_that_request_last(rq, (rq->errors == 0));
cmd_free(h, cmd, 1);
cciss_check_queues(h);
spin_unlock_irqrestore(&h->lock, flags);
@@ -2336,6 +2364,44 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
start_io(h);
}
+static inline int evaluate_target_status(CommandList_struct *cmd)
+{
+ unsigned char sense_key;
+ int error_count = 1;
+
+ if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */
+ if (!blk_pc_request(cmd->rq))
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status 0x%x\n",
+ cmd, cmd->err_info->ScsiStatus);
+ return error_count;
+ }
+
+ /* check the sense key */
+ sense_key = 0xf & cmd->err_info->SenseInfo[2];
+ /* no status or recovered error */
+ if ((sense_key == 0x0) || (sense_key == 0x1))
+ error_count = 0;
+
+ if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */
+ if (error_count != 0)
+ printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION"
+ " sense key = 0x%x\n", cmd, sense_key);
+ return error_count;
+ }
+
+ /* SG_IO or similar, copy sense data back */
+ if (cmd->rq->sense) {
+ if (cmd->rq->sense_len > cmd->err_info->SenseLen)
+ cmd->rq->sense_len = cmd->err_info->SenseLen;
+ memcpy(cmd->rq->sense, cmd->err_info->SenseInfo,
+ cmd->rq->sense_len);
+ } else
+ cmd->rq->sense_len = 0;
+
+ return error_count;
+}
+
/* checks the status of the job and calls complete buffers to mark all
* buffers for the completed job. Note that this function does not need
* to hold the hba/queue lock.
@@ -2343,109 +2409,99 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
int timeout)
{
- int status = 1;
int retry_cmd = 0;
+ struct request *rq = cmd->rq;
+
+ rq->errors = 0;
if (timeout)
- status = 0;
+ rq->errors = 1;
- if (cmd->err_info->CommandStatus != 0) { /* an error has occurred */
- switch (cmd->err_info->CommandStatus) {
- unsigned char sense_key;
- case CMD_TARGET_STATUS:
- status = 0;
+ if (cmd->err_info->CommandStatus == 0) /* no error has occurred */
+ goto after_error_processing;
- if (cmd->err_info->ScsiStatus == 0x02) {
- printk(KERN_WARNING "cciss: cmd %p "
- "has CHECK CONDITION "
- " byte 2 = 0x%x\n", cmd,
- cmd->err_info->SenseInfo[2]
- );
- /* check the sense key */
- sense_key = 0xf & cmd->err_info->SenseInfo[2];
- /* no status or recovered error */
- if ((sense_key == 0x0) || (sense_key == 0x1)) {
- status = 1;
- }
- } else {
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status 0x%x\n",
- cmd, cmd->err_info->ScsiStatus);
- }
- break;
- case CMD_DATA_UNDERRUN:
+ switch (cmd->err_info->CommandStatus) {
+ case CMD_TARGET_STATUS:
+ rq->errors = evaluate_target_status(cmd);
+ break;
+ case CMD_DATA_UNDERRUN:
+ if (blk_fs_request(cmd->rq)) {
printk(KERN_WARNING "cciss: cmd %p has"
" completed with data underrun "
"reported\n", cmd);
- break;
- case CMD_DATA_OVERRUN:
+ cmd->rq->data_len = cmd->err_info->ResidualCnt;
+ }
+ break;
+ case CMD_DATA_OVERRUN:
+ if (blk_fs_request(cmd->rq))
printk(KERN_WARNING "cciss: cmd %p has"
" completed with data overrun "
"reported\n", cmd);
- break;
- case CMD_INVALID:
- printk(KERN_WARNING "cciss: cmd %p is "
- "reported invalid\n", cmd);
- status = 0;
- break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cmd %p has "
- "protocol error \n", cmd);
- status = 0;
- break;
- case CMD_HARDWARE_ERR:
- printk(KERN_WARNING "cciss: cmd %p had "
- " hardware error\n", cmd);
- status = 0;
- break;
- case CMD_CONNECTION_LOST:
- printk(KERN_WARNING "cciss: cmd %p had "
- "connection lost\n", cmd);
- status = 0;
- break;
- case CMD_ABORTED:
- printk(KERN_WARNING "cciss: cmd %p was "
- "aborted\n", cmd);
- status = 0;
- break;
- case CMD_ABORT_FAILED:
- printk(KERN_WARNING "cciss: cmd %p reports "
- "abort failed\n", cmd);
- status = 0;
- break;
- case CMD_UNSOLICITED_ABORT:
- printk(KERN_WARNING "cciss%d: unsolicited "
- "abort %p\n", h->ctlr, cmd);
- if (cmd->retry_count < MAX_CMD_RETRIES) {
- retry_cmd = 1;
- printk(KERN_WARNING
- "cciss%d: retrying %p\n", h->ctlr, cmd);
- cmd->retry_count++;
- } else
- printk(KERN_WARNING
- "cciss%d: %p retried too "
- "many times\n", h->ctlr, cmd);
- status = 0;
- break;
- case CMD_TIMEOUT:
- printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
- status = 0;
- break;
- default:
- printk(KERN_WARNING "cciss: cmd %p returned "
- "unknown status %x\n", cmd,
- cmd->err_info->CommandStatus);
- status = 0;
- }
+ break;
+ case CMD_INVALID:
+ printk(KERN_WARNING "cciss: cmd %p is "
+ "reported invalid\n", cmd);
+ rq->errors = 1;
+ break;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "protocol error \n", cmd);
+ rq->errors = 1;
+ break;
+ case CMD_HARDWARE_ERR:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ " hardware error\n", cmd);
+ rq->errors = 1;
+ break;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ "connection lost\n", cmd);
+ rq->errors = 1;
+ break;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cmd %p was "
+ "aborted\n", cmd);
+ rq->errors = 1;
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cmd %p reports "
+ "abort failed\n", cmd);
+ rq->errors = 1;
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING "cciss%d: unsolicited "
+ "abort %p\n", h->ctlr, cmd);
+ if (cmd->retry_count < MAX_CMD_RETRIES) {
+ retry_cmd = 1;
+ printk(KERN_WARNING
+ "cciss%d: retrying %p\n", h->ctlr, cmd);
+ cmd->retry_count++;
+ } else
+ printk(KERN_WARNING
+ "cciss%d: %p retried too "
+ "many times\n", h->ctlr, cmd);
+ rq->errors = 1;
+ break;
+ case CMD_TIMEOUT:
+ printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+ rq->errors = 1;
+ break;
+ default:
+ printk(KERN_WARNING "cciss: cmd %p returned "
+ "unknown status %x\n", cmd,
+ cmd->err_info->CommandStatus);
+ rq->errors = 1;
}
+
+after_error_processing:
+
/* We need to return this command */
if (retry_cmd) {
resend_cciss_cmd(h, cmd);
return;
}
-
+ cmd->rq->data_len = 0;
cmd->rq->completion_data = cmd;
- cmd->rq->errors = status;
blk_add_trace_rq(cmd->rq->q, cmd->rq, BLK_TA_COMPLETE);
blk_complete_request(cmd->rq);
}
@@ -2539,32 +2595,40 @@ static void do_cciss_request(request_queue_t *q)
#endif /* CCISS_DEBUG */
c->Header.SGList = c->Header.SGTotal = seg;
- if(h->cciss_read == CCISS_READ_10) {
- c->Request.CDB[1] = 0;
- c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
- c->Request.CDB[3] = (start_blk >> 16) & 0xff;
- c->Request.CDB[4] = (start_blk >> 8) & 0xff;
- c->Request.CDB[5] = start_blk & 0xff;
- c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
- c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
- c->Request.CDB[8] = creq->nr_sectors & 0xff;
- c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+ if (likely(blk_fs_request(creq))) {
+ if(h->cciss_read == CCISS_READ_10) {
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
+ c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+ c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+ c->Request.CDB[5] = start_blk & 0xff;
+ c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
+ c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+ c->Request.CDB[8] = creq->nr_sectors & 0xff;
+ c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+ } else {
+ c->Request.CDBLen = 16;
+ c->Request.CDB[1]= 0;
+ c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
+ c->Request.CDB[3]= (start_blk >> 48) & 0xff;
+ c->Request.CDB[4]= (start_blk >> 40) & 0xff;
+ c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+ c->Request.CDB[6]= (start_blk >> 24) & 0xff;
+ c->Request.CDB[7]= (start_blk >> 16) & 0xff;
+ c->Request.CDB[8]= (start_blk >> 8) & 0xff;
+ c->Request.CDB[9]= start_blk & 0xff;
+ c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
+ c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
+ c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
+ c->Request.CDB[13]= creq->nr_sectors & 0xff;
+ c->Request.CDB[14] = c->Request.CDB[15] = 0;
+ }
+ } else if (blk_pc_request(creq)) {
+ c->Request.CDBLen = creq->cmd_len;
+ memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB);
} else {
- c->Request.CDBLen = 16;
- c->Request.CDB[1]= 0;
- c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
- c->Request.CDB[3]= (start_blk >> 48) & 0xff;
- c->Request.CDB[4]= (start_blk >> 40) & 0xff;
- c->Request.CDB[5]= (start_blk >> 32) & 0xff;
- c->Request.CDB[6]= (start_blk >> 24) & 0xff;
- c->Request.CDB[7]= (start_blk >> 16) & 0xff;
- c->Request.CDB[8]= (start_blk >> 8) & 0xff;
- c->Request.CDB[9]= start_blk & 0xff;
- c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
- c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
- c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
- c->Request.CDB[13]= creq->nr_sectors & 0xff;
- c->Request.CDB[14] = c->Request.CDB[15] = 0;
+ printk(KERN_WARNING "cciss%d: bad request type %d\n", h->ctlr, creq->cmd_type);
+ BUG();
}
spin_lock_irq(q->queue_lock);
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index bb15051ffbe..90961a8ea89 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -35,7 +35,6 @@
#include <asm/atomic.h>
-#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 5231ed7e723..3587cb43437 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4334,7 +4334,10 @@ static int __init floppy_init(void)
if (err)
goto out_flush_work;
- device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+ err = device_create_file(&floppy_device[drive].dev,&dev_attr_cmos);
+ if (err)
+ goto out_unreg_platform_dev;
+
/* to be cleaned up... */
disks[drive]->private_data = (void *)(long)drive;
disks[drive]->queue = floppy_queue;
@@ -4345,6 +4348,8 @@ static int __init floppy_init(void)
return 0;
+out_unreg_platform_dev:
+ platform_device_unregister(&floppy_device[drive]);
out_flush_work:
flush_scheduled_work();
if (usage_count)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6b5b6420740..18cdd8c7762 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -77,9 +77,8 @@
#include <asm/uaccess.h>
-static int max_loop = 8;
-static struct loop_device *loop_dev;
-static struct gendisk **disks;
+static LIST_HEAD(loop_devices);
+static DEFINE_MUTEX(loop_devices_mutex);
/*
* Transfer functions
@@ -183,7 +182,7 @@ figure_loop_size(struct loop_device *lo)
if (unlikely((loff_t)x != size))
return -EFBIG;
- set_capacity(disks[lo->lo_number], x);
+ set_capacity(lo->lo_disk, x);
return 0;
}
@@ -244,17 +243,13 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
transfer_result = lo_do_transfer(lo, WRITE, page, offset,
bvec->bv_page, bv_offs, size, IV);
if (unlikely(transfer_result)) {
- char *kaddr;
-
/*
* The transfer failed, but we still write the data to
* keep prepare/commit calls balanced.
*/
printk(KERN_ERR "loop: transfer error block %llu\n",
(unsigned long long)index);
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, size);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, size, KM_USER0);
}
flush_dcache_page(page);
ret = aops->commit_write(file, page, offset,
@@ -812,7 +807,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
lo->lo_queue->queuedata = lo;
lo->lo_queue->unplug_fn = loop_unplug;
- set_capacity(disks[lo->lo_number], size);
+ set_capacity(lo->lo_disk, size);
bd_set_size(bdev, size << 9);
set_blocksize(bdev, lo_blocksize);
@@ -832,8 +827,8 @@ out_clr:
lo->lo_device = NULL;
lo->lo_backing_file = NULL;
lo->lo_flags = 0;
- set_capacity(disks[lo->lo_number], 0);
- invalidate_bdev(bdev, 0);
+ set_capacity(lo->lo_disk, 0);
+ invalidate_bdev(bdev);
bd_set_size(bdev, 0);
mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
lo->lo_state = Lo_unbound;
@@ -917,8 +912,8 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
- invalidate_bdev(bdev, 0);
- set_capacity(disks[lo->lo_number], 0);
+ invalidate_bdev(bdev);
+ set_capacity(lo->lo_disk, 0);
bd_set_size(bdev, 0);
mapping_set_gfp_mask(filp->f_mapping, gfp);
lo->lo_state = Lo_unbound;
@@ -1322,6 +1317,18 @@ static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a
}
#endif
+static struct loop_device *loop_find_dev(int number)
+{
+ struct loop_device *lo;
+
+ list_for_each_entry(lo, &loop_devices, lo_list) {
+ if (lo->lo_number == number)
+ return lo;
+ }
+ return NULL;
+}
+
+static struct loop_device *loop_init_one(int i);
static int lo_open(struct inode *inode, struct file *file)
{
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
@@ -1330,6 +1337,11 @@ static int lo_open(struct inode *inode, struct file *file)
lo->lo_refcnt++;
mutex_unlock(&lo->lo_ctl_mutex);
+ mutex_lock(&loop_devices_mutex);
+ if (!loop_find_dev(lo->lo_number + 1))
+ loop_init_one(lo->lo_number + 1);
+ mutex_unlock(&loop_devices_mutex);
+
return 0;
}
@@ -1357,8 +1369,9 @@ static struct block_device_operations lo_fops = {
/*
* And now the modules code and kernel interface.
*/
+static int max_loop;
module_param(max_loop, int, 0);
-MODULE_PARM_DESC(max_loop, "Maximum number of loop devices (1-256)");
+MODULE_PARM_DESC(max_loop, "obsolete, loop device is created on-demand");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
@@ -1383,7 +1396,7 @@ int loop_unregister_transfer(int number)
xfer_funcs[n] = NULL;
- for (lo = &loop_dev[0]; lo < &loop_dev[max_loop]; lo++) {
+ list_for_each_entry(lo, &loop_devices, lo_list) {
mutex_lock(&lo->lo_ctl_mutex);
if (lo->lo_encryption == xfer)
@@ -1398,91 +1411,110 @@ int loop_unregister_transfer(int number)
EXPORT_SYMBOL(loop_register_transfer);
EXPORT_SYMBOL(loop_unregister_transfer);
-static int __init loop_init(void)
+static struct loop_device *loop_init_one(int i)
{
- int i;
+ struct loop_device *lo;
+ struct gendisk *disk;
- if (max_loop < 1 || max_loop > 256) {
- printk(KERN_WARNING "loop: invalid max_loop (must be between"
- " 1 and 256), using default (8)\n");
- max_loop = 8;
- }
+ lo = kzalloc(sizeof(*lo), GFP_KERNEL);
+ if (!lo)
+ goto out;
+
+ lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
+ if (!lo->lo_queue)
+ goto out_free_dev;
+
+ disk = lo->lo_disk = alloc_disk(1);
+ if (!disk)
+ goto out_free_queue;
+
+ mutex_init(&lo->lo_ctl_mutex);
+ lo->lo_number = i;
+ lo->lo_thread = NULL;
+ init_waitqueue_head(&lo->lo_event);
+ spin_lock_init(&lo->lo_lock);
+ disk->major = LOOP_MAJOR;
+ disk->first_minor = i;
+ disk->fops = &lo_fops;
+ disk->private_data = lo;
+ disk->queue = lo->lo_queue;
+ sprintf(disk->disk_name, "loop%d", i);
+ add_disk(disk);
+ list_add_tail(&lo->lo_list, &loop_devices);
+ return lo;
+
+out_free_queue:
+ blk_cleanup_queue(lo->lo_queue);
+out_free_dev:
+ kfree(lo);
+out:
+ return ERR_PTR(-ENOMEM);
+}
+
+static void loop_del_one(struct loop_device *lo)
+{
+ del_gendisk(lo->lo_disk);
+ blk_cleanup_queue(lo->lo_queue);
+ put_disk(lo->lo_disk);
+ list_del(&lo->lo_list);
+ kfree(lo);
+}
+
+static struct kobject *loop_probe(dev_t dev, int *part, void *data)
+{
+ unsigned int number = dev & MINORMASK;
+ struct loop_device *lo;
+
+ mutex_lock(&loop_devices_mutex);
+ lo = loop_find_dev(number);
+ if (lo == NULL)
+ lo = loop_init_one(number);
+ mutex_unlock(&loop_devices_mutex);
+
+ *part = 0;
+ if (IS_ERR(lo))
+ return (void *)lo;
+ else
+ return &lo->lo_disk->kobj;
+}
+
+static int __init loop_init(void)
+{
+ struct loop_device *lo;
if (register_blkdev(LOOP_MAJOR, "loop"))
return -EIO;
+ blk_register_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS,
+ THIS_MODULE, loop_probe, NULL, NULL);
- loop_dev = kmalloc(max_loop * sizeof(struct loop_device), GFP_KERNEL);
- if (!loop_dev)
- goto out_mem1;
- memset(loop_dev, 0, max_loop * sizeof(struct loop_device));
+ lo = loop_init_one(0);
+ if (IS_ERR(lo))
+ goto out;
- disks = kmalloc(max_loop * sizeof(struct gendisk *), GFP_KERNEL);
- if (!disks)
- goto out_mem2;
+ if (max_loop) {
+ printk(KERN_INFO "loop: the max_loop option is obsolete "
+ "and will be removed in March 2008\n");
- for (i = 0; i < max_loop; i++) {
- disks[i] = alloc_disk(1);
- if (!disks[i])
- goto out_mem3;
}
-
- for (i = 0; i < max_loop; i++) {
- struct loop_device *lo = &loop_dev[i];
- struct gendisk *disk = disks[i];
-
- memset(lo, 0, sizeof(*lo));
- lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
- if (!lo->lo_queue)
- goto out_mem4;
- mutex_init(&lo->lo_ctl_mutex);
- lo->lo_number = i;
- lo->lo_thread = NULL;
- init_waitqueue_head(&lo->lo_event);
- spin_lock_init(&lo->lo_lock);
- disk->major = LOOP_MAJOR;
- disk->first_minor = i;
- disk->fops = &lo_fops;
- sprintf(disk->disk_name, "loop%d", i);
- disk->private_data = lo;
- disk->queue = lo->lo_queue;
- }
-
- /* We cannot fail after we call this, so another loop!*/
- for (i = 0; i < max_loop; i++)
- add_disk(disks[i]);
- printk(KERN_INFO "loop: loaded (max %d devices)\n", max_loop);
+ printk(KERN_INFO "loop: module loaded\n");
return 0;
-out_mem4:
- while (i--)
- blk_cleanup_queue(loop_dev[i].lo_queue);
- i = max_loop;
-out_mem3:
- while (i--)
- put_disk(disks[i]);
- kfree(disks);
-out_mem2:
- kfree(loop_dev);
-out_mem1:
+out:
unregister_blkdev(LOOP_MAJOR, "loop");
printk(KERN_ERR "loop: ran out of memory\n");
return -ENOMEM;
}
-static void loop_exit(void)
+static void __exit loop_exit(void)
{
- int i;
+ struct loop_device *lo, *next;
- for (i = 0; i < max_loop; i++) {
- del_gendisk(disks[i]);
- blk_cleanup_queue(loop_dev[i].lo_queue);
- put_disk(disks[i]);
- }
+ list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
+ loop_del_one(lo);
+
+ blk_unregister_region(MKDEV(LOOP_MAJOR, 0), 1UL << MINORBITS);
if (unregister_blkdev(LOOP_MAJOR, "loop"))
printk(KERN_WARNING "loop: cannot unregister blkdev\n");
-
- kfree(disks);
- kfree(loop_dev);
}
module_init(loop_init);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 090796bef78..069ae39a9cd 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -366,20 +366,25 @@ static struct disk_attribute pid_attr = {
.show = pid_show,
};
-static void nbd_do_it(struct nbd_device *lo)
+static int nbd_do_it(struct nbd_device *lo)
{
struct request *req;
+ int ret;
BUG_ON(lo->magic != LO_MAGIC);
lo->pid = current->pid;
- sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+ ret = sysfs_create_file(&lo->disk->kobj, &pid_attr.attr);
+ if (ret) {
+ printk(KERN_ERR "nbd: sysfs_create_file failed!");
+ return ret;
+ }
while ((req = nbd_read_stat(lo)) != NULL)
nbd_end_request(req);
sysfs_remove_file(&lo->disk->kobj, &pid_attr.attr);
- return;
+ return 0;
}
static void nbd_clear_que(struct nbd_device *lo)
@@ -569,7 +574,9 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
case NBD_DO_IT:
if (!lo->file)
return -EINVAL;
- nbd_do_it(lo);
+ error = nbd_do_it(lo);
+ if (error)
+ return error;
/* on return tidy up in case we have a signal */
/* Forcibly shutdown the socket causing all listeners
* to error
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 485aa87e9bc..a1512da3241 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -151,7 +151,7 @@ static int ramdisk_commit_write(struct file *file, struct page *page,
}
/*
- * ->writepage to the the blockdev's mapping has to redirty the page so that the
+ * ->writepage to the blockdev's mapping has to redirty the page so that the
* VM doesn't go and steal it. We return AOP_WRITEPAGE_ACTIVATE so that the VM
* won't try to (pointlessly) write the page again for a while.
*
@@ -403,7 +403,7 @@ static void __exit rd_cleanup(void)
struct block_device *bdev = rd_bdev[i];
rd_bdev[i] = NULL;
if (bdev) {
- invalidate_bdev(bdev, 1);
+ invalidate_bdev(bdev);
blkdev_put(bdev);
}
del_gendisk(rd_disks[i]);
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 5872036e8ae..6f5d6203d72 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -44,7 +44,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/slab.h>
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 406af579ac3..b0238b46dde 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -114,10 +114,16 @@ static struct usb_device_id blacklist_ids[] = {
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
+ /* Broadcom BCM2045 */
+ { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_WRONG_SCO_MTU },
+
/* IBM/Lenovo ThinkPad with Broadcom chip */
{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_WRONG_SCO_MTU },
+ /* Targus ACB10US */
+ { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET },
+
/* ANYCOM Bluetooth USB-200 and USB-250 */
{ USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index b36f44d4d1b..3625a05bc3d 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2384,7 +2384,7 @@ static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
return -EACCES;
if (!CDROM_CAN(CDC_RESET))
return -ENOSYS;
- invalidate_bdev(bdev, 0);
+ invalidate_bdev(bdev);
return cdi->ops->reset(cdi);
}
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d0c978fbc20..2df42fdcdc9 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -127,7 +127,7 @@ config ROCKETPORT
config CYCLADES
tristate "Cyclades async mux support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (PCI || ISA)
---help---
This driver supports Cyclades Z and Y multiserial boards.
You would need something like this to connect more than two modems to
@@ -631,7 +631,8 @@ config HVC_CONSOLE
config HVC_ISERIES
bool "iSeries Hypervisor Virtual Console support"
- depends on PPC_ISERIES && !VIOCONS
+ depends on PPC_ISERIES
+ default y
select HVC_DRIVER
help
iSeries machines support a hypervisor virtual console.
@@ -905,8 +906,8 @@ config SONYPI
To compile this driver as a module, choose M here: the
module will be called sonypi.
-config TANBAC_TB0219
- tristate "TANBAC TB0219 base board support"
+config GPIO_TB0219
+ tristate "TANBAC TB0219 GPIO support"
depends on TANBAC_TB022X
select GPIO_VR41XX
@@ -1071,5 +1072,11 @@ config TELCLOCK
/sys/devices/platform/telco_clock, with a number of files for
controlling the behavior of this hardware.
+config DEVPORT
+ bool
+ depends on !M68K
+ depends on ISA || PCI
+ default y
+
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index ae8567cc529..2f56ecc035a 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -91,7 +91,7 @@ obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
-obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
+obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
obj-$(CONFIG_WATCHDOG) += watchdog/
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 5b684fddcc0..4941ddb7893 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -145,6 +145,7 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
void *addr = agp_generic_alloc_page(agp_bridge);
u32 temp;
+ global_flush_tlb();
if (!addr)
return NULL;
@@ -160,6 +161,7 @@ static void ali_destroy_page(void * addr)
if (addr) {
global_cache_flush(); /* is this really needed? --hch */
agp_generic_destroy_page(addr);
+ global_flush_tlb();
}
}
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index b0acf41c0db..aa8f3a39a70 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -173,7 +173,7 @@ alpha_core_agp_setup(void)
/*
* Build a fake pci_dev struct
*/
- pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ pdev = alloc_pci_dev();
if (!pdev)
return -ENOMEM;
pdev->vendor = 0xffff;
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 485720486d6..c9f0f250d78 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -14,6 +14,7 @@
#include <linux/agp_backend.h>
#include <linux/mmzone.h>
#include <asm/page.h> /* PAGE_SIZE */
+#include <asm/e820.h>
#include <asm/k8.h>
#include "agp.h"
@@ -259,7 +260,6 @@ static const struct agp_bridge_driver amd_8151_driver = {
/* Some basic sanity checks for the aperture. */
static int __devinit aperture_valid(u64 aper, u32 size)
{
- u32 pfn, c;
if (aper == 0) {
printk(KERN_ERR PFX "No aperture\n");
return 0;
@@ -272,14 +272,9 @@ static int __devinit aperture_valid(u64 aper, u32 size)
printk(KERN_ERR PFX "Aperture out of bounds\n");
return 0;
}
- pfn = aper >> PAGE_SHIFT;
- for (c = 0; c < size/PAGE_SIZE; c++) {
- if (!pfn_valid(pfn + c))
- break;
- if (!PageReserved(pfn_to_page(pfn + c))) {
- printk(KERN_ERR PFX "Aperture pointing to RAM\n");
- return 0;
- }
+ if (e820_any_mapped(aper, aper + size, E820_RAM)) {
+ printk(KERN_ERR PFX "Aperture pointing to RAM\n");
+ return 0;
}
/* Request the Aperture. This catches cases when someone else
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index f902d71947b..45aeb917ec6 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -51,28 +51,6 @@ int agp_memory_reserved;
*/
EXPORT_SYMBOL_GPL(agp_memory_reserved);
-#if defined(CONFIG_X86)
-int map_page_into_agp(struct page *page)
-{
- int i;
- i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
- /* Caller's responsibility to call global_flush_tlb() for
- * performance reasons */
- return i;
-}
-EXPORT_SYMBOL_GPL(map_page_into_agp);
-
-int unmap_page_from_agp(struct page *page)
-{
- int i;
- i = change_page_attr(page, 1, PAGE_KERNEL);
- /* Caller's responsibility to call global_flush_tlb() for
- * performance reasons */
- return i;
-}
-EXPORT_SYMBOL_GPL(unmap_page_from_agp);
-#endif
-
/*
* Generic routines for handling agp_memory structures -
* They use the basic page allocation routines to do the brunt of the work.
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 55392a45a14..9c69f2e761f 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -186,8 +186,9 @@ static void *i8xx_alloc_pages(void)
return NULL;
if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) {
+ change_page_attr(page, 4, PAGE_KERNEL);
global_flush_tlb();
- __free_page(page);
+ __free_pages(page, 2);
return NULL;
}
global_flush_tlb();
@@ -209,7 +210,7 @@ static void i8xx_destroy_pages(void *addr)
global_flush_tlb();
put_page(page);
unlock_page(page);
- free_pages((unsigned long)addr, 2);
+ __free_pages(page, 2);
atomic_dec(&agp_bridge->current_memory_agp);
}
@@ -315,9 +316,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
struct agp_memory *new;
void *addr;
- if (pg_count != 1 && pg_count != 4)
- return NULL;
-
switch (pg_count) {
case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
global_flush_tlb();
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 0c9dab557c9..6cd7373dcdf 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -320,11 +320,11 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev,
u8 cap_ptr;
nvidia_private.dev_1 =
- pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
+ pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
nvidia_private.dev_2 =
- pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
+ pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
nvidia_private.dev_3 =
- pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
+ pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) {
printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 "
@@ -443,6 +443,9 @@ static int __init agp_nvidia_init(void)
static void __exit agp_nvidia_cleanup(void)
{
pci_unregister_driver(&agp_nvidia_pci_driver);
+ pci_dev_put(nvidia_private.dev_1);
+ pci_dev_put(nvidia_private.dev_2);
+ pci_dev_put(nvidia_private.dev_3);
}
module_init(agp_nvidia_init);
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 3d83b461cca..f4562cc2234 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -329,7 +329,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
struct agp_bridge_data *bridge;
int error = 0;
- fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ fake_bridge_dev = alloc_pci_dev();
if (!fake_bridge_dev) {
error = -ENOMEM;
goto fail;
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index ee8f50edde1..cda608c42be 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -47,9 +47,8 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
nid = info->ca_closest_node;
page = alloc_pages_node(nid, GFP_KERNEL, 0);
- if (page == NULL) {
- return 0;
- }
+ if (!page)
+ return NULL;
get_page(page);
SetPageLocked(page);
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 125f4282d95..eb1a1c73819 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -143,96 +143,6 @@ static struct agp_bridge_driver sis_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_device_ids sis_agp_device_ids[] __devinitdata =
-{
- {
- .device_id = PCI_DEVICE_ID_SI_5591_AGP,
- .chipset_name = "5591",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_530,
- .chipset_name = "530",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_540,
- .chipset_name = "540",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_550,
- .chipset_name = "550",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_620,
- .chipset_name = "620",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_630,
- .chipset_name = "630",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_635,
- .chipset_name = "635",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_645,
- .chipset_name = "645",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_646,
- .chipset_name = "646",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_648,
- .chipset_name = "648",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_650,
- .chipset_name = "650",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_651,
- .chipset_name = "651",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_655,
- .chipset_name = "655",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_661,
- .chipset_name = "661",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_730,
- .chipset_name = "730",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_735,
- .chipset_name = "735",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_740,
- .chipset_name = "740",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_741,
- .chipset_name = "741",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_745,
- .chipset_name = "745",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_746,
- .chipset_name = "746",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_760,
- .chipset_name = "760",
- },
- { }, /* dummy final entry, always present */
-};
-
-
// chipsets that require the 'delay hack'
static int sis_broken_chipsets[] __devinitdata = {
PCI_DEVICE_ID_SI_648,
@@ -269,29 +179,15 @@ static void __devinit sis_get_driver(struct agp_bridge_data *bridge)
static int __devinit agp_sis_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct agp_device_ids *devs = sis_agp_device_ids;
struct agp_bridge_data *bridge;
u8 cap_ptr;
- int j;
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
if (!cap_ptr)
return -ENODEV;
- /* probe for known chipsets */
- for (j = 0; devs[j].chipset_name; j++) {
- if (pdev->device == devs[j].device_id) {
- printk(KERN_INFO PFX "Detected SiS %s chipset\n",
- devs[j].chipset_name);
- goto found;
- }
- }
-
- printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n",
- pdev->device);
- return -ENODEV;
-found:
+ printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device);
bridge = agp_alloc_bridge();
if (!bridge)
return -ENOMEM;
@@ -320,12 +216,172 @@ static void __devexit agp_sis_remove(struct pci_dev *pdev)
static struct pci_device_id agp_sis_pci_table[] = {
{
- .class = (PCI_CLASS_BRIDGE_HOST << 8),
- .class_mask = ~0,
- .vendor = PCI_VENDOR_ID_SI,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_5591_AGP,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_530,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_540,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_550,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_620,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_630,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_635,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_645,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_646,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_648,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_650,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_651,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_655,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_661,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_730,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_735,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_740,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_741,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_745,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_746,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_760,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},
{ }
};
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 55212a3811f..551ef25063e 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -455,15 +455,6 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
u32 temp, temp2;
u8 cap_ptr = 0;
- /* Everything is on func 1 here so we are hardcoding function one */
- bridge_dev = pci_find_slot((unsigned int)pdev->bus->number,
- PCI_DEVFN(0, 1));
- if (!bridge_dev) {
- printk(KERN_INFO PFX "Detected a Serverworks chipset "
- "but could not find the secondary device.\n");
- return -ENODEV;
- }
-
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
switch (pdev->device) {
@@ -483,6 +474,15 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
return -ENODEV;
}
+ /* Everything is on func 1 here so we are hardcoding function one */
+ bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number,
+ PCI_DEVFN(0, 1));
+ if (!bridge_dev) {
+ printk(KERN_INFO PFX "Detected a Serverworks chipset "
+ "but could not find the secondary device.\n");
+ return -ENODEV;
+ }
+
serverworks_private.svrwrks_dev = bridge_dev;
serverworks_private.gart_addr_ofs = 0x10;
@@ -515,7 +515,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
bridge->driver = &sworks_driver;
bridge->dev_private_data = &serverworks_private,
- bridge->dev = pdev;
+ bridge->dev = pci_dev_get(pdev);
pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge);
@@ -525,8 +525,11 @@ static void __devexit agp_serverworks_remove(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+ pci_dev_put(bridge->dev);
agp_remove_bridge(bridge);
agp_put_bridge(bridge);
+ pci_dev_put(serverworks_private.svrwrks_dev);
+ serverworks_private.svrwrks_dev = NULL;
}
static struct pci_device_id agp_serverworks_pci_table[] = {
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 91b062126a6..42c0a600b1a 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -613,7 +613,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
uninorth_node = of_find_node_by_name(NULL, "u3");
}
if (uninorth_node) {
- const int *revprop = get_property(uninorth_node,
+ const int *revprop = of_get_property(uninorth_node,
"device-rev", NULL);
if (revprop != NULL)
uninorth_rev = *revprop & 0x3f;
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 0e2b72f2b88..4eaceabd8ce 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1574,7 +1574,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@@ -1700,7 +1700,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (extra_count)
state->count++;
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index 8dcf9d20f44..ed53f541d9e 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -202,13 +202,16 @@ static struct miscdevice briq_panel_miscdev = {
static int __init briq_panel_init(void)
{
- struct device_node *root = find_path_device("/");
+ struct device_node *root = of_find_node_by_path("/");
const char *machine;
int i;
- machine = get_property(root, "model", NULL);
- if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
+ machine = of_get_property(root, "model", NULL);
+ if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
+ of_node_put(root);
return -ENODEV;
+ }
+ of_node_put(root);
printk(KERN_INFO
"briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index b99b7561260..fd40b959afd 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -626,10 +626,10 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
/* Only 16-bit codes supported at this time */
if (ucs > 0xffff)
- ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
- else if (ucs < 0x20 || ucs >= 0xfffe)
+ return -4; /* Not found */
+ else if (ucs < 0x20)
return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+ else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
return -2; /* Zero-width space */
/*
* UNI_DIRECT_BASE indicates the start of the region in the User Zone
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index c02d9e99e05..fe6d2407bae 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -44,6 +44,7 @@ static struct pci_device_id divil_pci[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
{ } /* NULL entry */
};
+MODULE_DEVICE_TABLE(pci, divil_pci);
static struct cdev cs5535_gpio_cdev;
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 16dc5d1d3cb..c72ee97d389 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -10,15 +10,14 @@
*
* Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
* Modified and maintained by Marcio Saito <marcio@cyclades.com>.
- * Currently maintained by Cyclades team <async@cyclades.com>.
*
- * For Technical support and installation problems, please send e-mail
- * to support@cyclades.com.
+ * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* Much of the design and some of the code came from serial.c
* which was copyright (C) 1991, 1992 Linus Torvalds. It was
* extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
* and then fixed as suggested by Michael K. Johnson 12/12/92.
+ * Converted to pci probing and cleaned up by Jiri Slaby.
*
* This version supports shared IRQ's (only for PCI boards).
*
@@ -591,7 +590,7 @@
*
*/
-#define CY_VERSION "2.4"
+#define CY_VERSION "2.5"
/* If you need to install more boards than NR_CARDS, change the constant
in the definition below. No other change is necessary to support up to
@@ -624,12 +623,6 @@
#undef CY_ENABLE_MONITORING
#undef CY_PCI_DEBUG
-#if 0
-#define PAUSE __asm__("nop")
-#else
-#define PAUSE do {} while (0)
-#endif
-
/*
* Include section
*/
@@ -659,17 +652,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-#define CY_LOCK(info,flags) \
- do { \
- spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
- } while (0)
-
-#define CY_UNLOCK(info,flags) \
- do { \
- spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
- } while (0)
-
-#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -682,13 +664,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
#define IS_CYC_Z(card) ((card).num_chips == -1)
#define Z_FPGA_CHECK(card) \
- ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
+ ((readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
-#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \
+#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
Z_FPGA_CHECK(card)) && \
- (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \
+ (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
((card).base_addr+ID_ADDRESS))->signature)))
#ifndef SERIAL_XMIT_SIZE
@@ -725,8 +707,8 @@ static unsigned int cy_isa_addresses[] = {
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
#ifdef MODULE
-static long maddr[NR_CARDS] = { 0, };
-static int irq[NR_CARDS] = { 0, };
+static long maddr[NR_CARDS];
+static int irq[NR_CARDS];
module_param_array(maddr, long, NULL, 0);
module_param_array(irq, int, NULL, 0);
@@ -739,11 +721,6 @@ module_param_array(irq, int, NULL, 0);
*/
static struct cyclades_card cy_card[NR_CARDS];
-/* This is the per-channel data structure containing pointers, flags
- and variables for the port. This driver supports a maximum of NR_PORTS.
-*/
-static struct cyclades_port cy_port[NR_PORTS];
-
static int cy_next_channel; /* next minor available */
/*
@@ -825,9 +802,6 @@ static int cy_chip_offset[] = { 0x0000,
/* PCI related definitions */
-static unsigned short cy_pci_nboard;
-static unsigned short cy_isa_nboard;
-static unsigned short cy_nboard;
#ifdef CONFIG_PCI
static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */
@@ -845,7 +819,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
static void cy_start(struct tty_struct *);
static void set_line_char(struct cyclades_port *);
-static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
+static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
#endif /* CONFIG_ISA */
@@ -858,7 +832,6 @@ static void cyz_poll(unsigned long);
/* The Cyclades-Z polling cycle is defined by this variable */
static long cyz_polling_cycle = CZ_DEF_POLL;
-static int cyz_timeron = 0;
static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
#else /* CONFIG_CYZ_INTR */
@@ -871,21 +844,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
{
#ifdef SERIAL_PARANOIA_CHECK
if (!info) {
- printk("cyc Warning: null cyclades_port for (%s) in %s\n",
- name, routine);
- return 1;
- }
-
- if ((long)info < (long)(&cy_port[0]) ||
- (long)(&cy_port[NR_PORTS]) < (long)info) {
- printk("cyc Warning: cyclades_port out of range for (%s) in "
- "%s\n", name, routine);
+ printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
+ "in %s\n", name, routine);
return 1;
}
if (info->magic != CYCLADES_MAGIC) {
- printk("cyc Warning: bad magic number for serial struct (%s) "
- "in %s\n", name, routine);
+ printk(KERN_WARNING "cyc Warning: bad magic number for serial "
+ "struct (%s) in %s\n", name, routine);
return 1;
}
#endif
@@ -943,22 +909,16 @@ do_softint(struct work_struct *work)
if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
wake_up_interruptible(&info->open_wait);
#ifdef CONFIG_CYZ_INTR
- if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
- if (cyz_rx_full_timer[info->line].function == NULL) {
- cyz_rx_full_timer[info->line].expires = jiffies + 1;
- cyz_rx_full_timer[info->line].function = cyz_rx_restart;
- cyz_rx_full_timer[info->line].data =
- (unsigned long)info;
- add_timer(&cyz_rx_full_timer[info->line]);
- }
- }
+ if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) &&
+ !timer_pending(&cyz_rx_full_timer[info->line]))
+ mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1);
#endif
if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
wake_up_interruptible(&info->delta_msr_wait);
tty_wakeup(tty);
#ifdef Z_WAKE
if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
- wake_up_interruptible(&info->shutdown_wait);
+ complete(&info->shutdown_wait);
#endif
} /* do_softint */
@@ -975,11 +935,11 @@ do_softint(struct work_struct *work)
*/
static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
{
- volatile int i;
+ unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (cy_readb(base_addr + (CyCCR << index)) == 0) {
+ if (readb(base_addr + (CyCCR << index)) == 0) {
break;
}
udelay(10L);
@@ -1022,7 +982,7 @@ static unsigned detect_isa_irq(void __iomem * address)
cy_writeb(address + (CyCAR << index), 0);
cy_writeb(address + (CySRER << index),
- cy_readb(address + (CySRER << index)) | CyTxRdy);
+ readb(address + (CySRER << index)) | CyTxRdy);
local_irq_restore(flags);
/* Wait ... */
@@ -1032,11 +992,11 @@ static unsigned detect_isa_irq(void __iomem * address)
irq = probe_irq_off(irqs);
/* Clean up */
- save_xir = (u_char) cy_readb(address + (CyTIR << index));
- save_car = cy_readb(address + (CyCAR << index));
+ save_xir = (u_char) readb(address + (CyTIR << index));
+ save_car = readb(address + (CyCAR << index));
cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
cy_writeb(address + (CySRER << index),
- cy_readb(address + (CySRER << index)) & ~CyTxRdy);
+ readb(address + (CySRER << index)) & ~CyTxRdy);
cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
cy_writeb(address + (CyCAR << index), (save_car));
cy_writeb(address + (Cy_ClrIntr << index), 0);
@@ -1051,45 +1011,43 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
{
struct cyclades_port *info;
struct tty_struct *tty;
- volatile int char_count;
- int i, j, len, mdm_change, mdm_status, outch;
+ int char_count;
+ int j, len, mdm_change, mdm_status, outch;
int save_xir, channel, save_car;
char data;
if (status & CySRReceive) { /* reception interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
+ printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
#endif
/* determine the channel & change to that context */
spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr + (CyRIR << index));
+ save_xir = (u_char) readb(base_addr + (CyRIR << index));
channel = (u_short) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- info = &cy_port[i];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr + (CyCAR << index));
+ info = &cinfo->ports[channel + chip * 4];
+ save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
/* if there is nowhere to put the data, discard it */
- if (info->tty == 0) {
- j = (cy_readb(base_addr + (CyRIVR << index)) &
+ if (info->tty == NULL) {
+ j = (readb(base_addr + (CyRIVR << index)) &
CyIVRMask);
if (j == CyIVRRxEx) { /* exception */
- data = cy_readb(base_addr + (CyRDSR << index));
+ data = readb(base_addr + (CyRDSR << index));
} else { /* normal character reception */
- char_count = cy_readb(base_addr +
+ char_count = readb(base_addr +
(CyRDCR << index));
while (char_count--) {
- data = cy_readb(base_addr +
+ data = readb(base_addr +
(CyRDSR << index));
}
}
} else { /* there is an open port for this data */
tty = info->tty;
- j = (cy_readb(base_addr + (CyRIVR << index)) &
+ j = (readb(base_addr + (CyRIVR << index)) &
CyIVRMask);
if (j == CyIVRRxEx) { /* exception */
- data = cy_readb(base_addr + (CyRDSR << index));
+ data = readb(base_addr + (CyRDSR << index));
/* For statistics only */
if (data & CyBREAK)
@@ -1110,7 +1068,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
if (data & CyBREAK) {
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1123,7 +1081,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
} else if (data & CyFRAME) {
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1135,7 +1093,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
/* Pieces of seven... */
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1154,7 +1112,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
*/
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1186,7 +1144,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
}
} else { /* normal character reception */
/* load # chars available from the chip */
- char_count = cy_readb(base_addr +
+ char_count = readb(base_addr +
(CyRDCR << index));
#ifdef CY_ENABLE_MONITORING
@@ -1198,7 +1156,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
#endif
len = tty_buffer_request_room(tty, char_count);
while (len--) {
- data = cy_readb(base_addr +
+ data = readb(base_addr +
(CyRDSR << index));
tty_insert_flip_char(tty, data,
TTY_NORMAL);
@@ -1223,29 +1181,27 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
is empty, we know we can always stuff a dozen
characters. */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
+ printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
#endif
/* determine the channel & change to that context */
spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr + (CyTIR << index));
+ save_xir = (u_char) readb(base_addr + (CyTIR << index));
channel = (u_short) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- save_car = cy_readb(base_addr + (CyCAR << index));
+ save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
/* validate the port# (as configured and open) */
- if ((i < 0) || (NR_PORTS <= i)) {
+ if (channel + chip * 4 >= cinfo->nports) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) &
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txend;
}
- info = &cy_port[i];
- info->last_active = jiffies;
- if (info->tty == 0) {
+ info = &cinfo->ports[channel + chip * 4];
+ if (info->tty == NULL) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) &
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txdone;
}
@@ -1278,29 +1234,29 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
while (char_count-- > 0) {
if (!info->xmit_cnt) {
- if (cy_readb(base_addr + (CySRER << index)) &
+ if (readb(base_addr + (CySRER << index)) &
CyTxMpty) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER << index)) &
~CyTxMpty);
} else {
cy_writeb(base_addr + (CySRER << index),
- (cy_readb(base_addr +
+ (readb(base_addr +
(CySRER << index)) &
~CyTxRdy) | CyTxMpty);
}
goto txdone;
}
- if (info->xmit_buf == 0) {
+ if (info->xmit_buf == NULL) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index))&
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txdone;
}
if (info->tty->stopped || info->tty->hw_stopped) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index))&
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txdone;
}
@@ -1333,7 +1289,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
0);
info->icount.tx++;
char_count--;
- } else {
}
}
}
@@ -1353,19 +1308,16 @@ txend:
/* determine the channel & change to that context */
spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr + (CyMIR << index));
+ save_xir = (u_char) readb(base_addr + (CyMIR << index));
channel = (u_short) (save_xir & CyIRChannel);
- info = &cy_port[channel + chip * 4 + cinfo->first_line];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr + (CyCAR << index));
+ info = &cinfo->ports[channel + chip * 4];
+ save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
- mdm_change = cy_readb(base_addr + (CyMISR << index));
- mdm_status = cy_readb(base_addr + (CyMSVR1 << index));
+ mdm_change = readb(base_addr + (CyMISR << index));
+ mdm_status = readb(base_addr + (CyMSVR1 << index));
- if (info->tty == 0) { /* no place for data, ignore it */
- ;
- } else {
+ if (info->tty) {
if (mdm_change & CyANY_DELTA) {
/* For statistics only */
if (mdm_change & CyDCD)
@@ -1398,7 +1350,7 @@ txend:
info->tty->hw_stopped = 0;
cy_writeb(base_addr +
(CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER <<
index))|
CyTxRdy);
@@ -1412,17 +1364,17 @@ txend:
info->tty->hw_stopped = 1;
cy_writeb(base_addr +
(CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER <<
index)) &
~CyTxRdy);
}
}
}
- if (mdm_change & CyDSR) {
+/* if (mdm_change & CyDSR) {
}
if (mdm_change & CyRI) {
- }
+ }*/
}
/* end of service */
cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
@@ -1438,16 +1390,16 @@ txend:
static irqreturn_t cyy_interrupt(int irq, void *dev_id)
{
int status;
- struct cyclades_card *cinfo;
+ struct cyclades_card *cinfo = dev_id;
void __iomem *base_addr, *card_base_addr;
int chip;
int index;
int too_many;
int had_work;
- if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+ if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
+ printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1455,6 +1407,10 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
card_base_addr = cinfo->base_addr;
index = cinfo->bus_index;
+ /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
+ if (unlikely(card_base_addr == NULL))
+ return IRQ_HANDLED;
+
/* This loop checks all chips in the card. Make a note whenever
_any_ chip had some work to do, as this is considered an
indication that there will be more to do. Only when no chip
@@ -1466,7 +1422,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
base_addr = cinfo->base_addr +
(cy_chip_offset[chip] << index);
too_many = 0;
- while ((status = cy_readb(base_addr +
+ while ((status = readb(base_addr +
(CySVRR << index))) != 0x00) {
had_work++;
/* The purpose of the following test is to ensure that
@@ -1498,7 +1454,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
static int
cyz_fetch_msg(struct cyclades_card *cinfo,
- uclong * channel, ucchar * cmd, uclong * param)
+ __u32 * channel, __u8 * cmd, __u32 * param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -1509,16 +1465,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
if (!ISZLOADED(*cinfo)) {
return -1;
}
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
- loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
+ loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
(cinfo->ctl_addr))->loc_doorbell);
if (loc_doorbell) {
*cmd = (char)(0xff & loc_doorbell);
- *channel = cy_readl(&board_ctrl->fwcmd_channel);
- *param = (uclong) cy_readl(&board_ctrl->fwcmd_param);
+ *channel = readl(&board_ctrl->fwcmd_channel);
+ *param = (__u32) readl(&board_ctrl->fwcmd_param);
cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
loc_doorbell, 0xffffffff);
return 1;
@@ -1528,28 +1483,27 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
static int
cyz_issue_cmd(struct cyclades_card *cinfo,
- uclong channel, ucchar cmd, uclong param)
+ __u32 channel, __u8 cmd, __u32 param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
- unsigned long __iomem *pci_doorbell;
+ __u32 __iomem *pci_doorbell;
int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
return -1;
}
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
index = 0;
pci_doorbell =
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
- while ((cy_readl(pci_doorbell) & 0xff) != 0) {
+ while ((readl(pci_doorbell) & 0xff) != 0) {
if (index++ == 1000) {
- return (int)(cy_readl(pci_doorbell) & 0xff);
+ return (int)(readl(pci_doorbell) & 0xff);
}
udelay(50L);
}
@@ -1561,34 +1515,30 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
} /* cyz_issue_cmd */
static void
-cyz_handle_rx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem * ch_ctrl,
- volatile struct BUF_CTRL __iomem * buf_ctrl)
+cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+ struct BUF_CTRL __iomem *buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
+ struct cyclades_card *cinfo = info->card;
struct tty_struct *tty = info->tty;
- volatile int char_count;
+ int char_count;
int len;
#ifdef BLOCKMOVE
- int small_count;
+ unsigned char *buf;
#else
char data;
#endif
- volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
+ __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
- rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
- rx_put = cy_readl(&buf_ctrl->rx_put);
- rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
- rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
+ rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
+ rx_put = readl(&buf_ctrl->rx_put);
+ rx_bufsize = readl(&buf_ctrl->rx_bufsize);
+ rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
if (rx_put >= rx_get)
char_count = rx_put - rx_get;
else
char_count = rx_put - rx_get + rx_bufsize;
if (char_count) {
- info->last_active = jiffies;
- info->jiffies[1] = jiffies;
-
#ifdef CY_ENABLE_MONITORING
info->mon.int_count++;
info->mon.char_count += char_count;
@@ -1596,7 +1546,7 @@ cyz_handle_rx(struct cyclades_port *info,
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
- if (tty == 0) {
+ if (tty == NULL) {
/* flush received characters */
new_rx_get = (new_rx_get + char_count) &
(rx_bufsize - 1);
@@ -1606,30 +1556,28 @@ cyz_handle_rx(struct cyclades_port *info,
/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
for performance, but because of buffer boundaries, there
may be several steps to the operation */
- while (0 < (small_count = min_t(unsigned int,
- rx_bufsize - new_rx_get,
- min_t(unsigned int, TTY_FLIPBUF_SIZE -
- tty->flip.count, char_count)))){
- memcpy_fromio(tty->flip.char_buf_ptr,
- (char *)(cinfo->base_addr + rx_bufaddr +
- new_rx_get),
- small_count);
+ while (1) {
+ len = tty_prepare_flip_string(tty, &buf,
+ char_count);
+ if (!len)
+ break;
- tty->flip.char_buf_ptr += small_count;
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL,
- small_count);
- tty->flip.flag_buf_ptr += small_count;
- new_rx_get = (new_rx_get + small_count) &
+ len = min_t(unsigned int, min(len, char_count),
+ rx_bufsize - new_rx_get);
+
+ memcpy_fromio(buf, cinfo->base_addr +
+ rx_bufaddr + new_rx_get, len);
+
+ new_rx_get = (new_rx_get + len) &
(rx_bufsize - 1);
- char_count -= small_count;
- info->icount.rx += small_count;
- info->idle_stats.recv_bytes += small_count;
- tty->flip.count += small_count;
+ char_count -= len;
+ info->icount.rx += len;
+ info->idle_stats.recv_bytes += len;
}
#else
len = tty_buffer_request_room(tty, char_count);
while (len--) {
- data = cy_readb(cinfo->base_addr + rx_bufaddr +
+ data = readb(cinfo->base_addr + rx_bufaddr +
new_rx_get);
new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
tty_insert_flip_char(tty, data, TTY_NORMAL);
@@ -1640,13 +1588,12 @@ cyz_handle_rx(struct cyclades_port *info,
#ifdef CONFIG_CYZ_INTR
/* Recalculate the number of chars in the RX buffer and issue
a cmd in case it's higher than the RX high water mark */
- rx_put = cy_readl(&buf_ctrl->rx_put);
+ rx_put = readl(&buf_ctrl->rx_put);
if (rx_put >= rx_get)
char_count = rx_put - rx_get;
else
char_count = rx_put - rx_get + rx_bufsize;
- if (char_count >= (int)cy_readl(&buf_ctrl->
- rx_threshold)) {
+ if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) {
cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
}
#endif
@@ -1659,26 +1606,25 @@ cyz_handle_rx(struct cyclades_port *info,
}
static void
-cyz_handle_tx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem * ch_ctrl,
- volatile struct BUF_CTRL __iomem * buf_ctrl)
+cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+ struct BUF_CTRL __iomem *buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
+ struct cyclades_card *cinfo = info->card;
struct tty_struct *tty = info->tty;
char data;
- volatile int char_count;
+ int char_count;
#ifdef BLOCKMOVE
int small_count;
#endif
- volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
+ __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
if (info->xmit_cnt <= 0) /* Nothing to transmit */
return;
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
+ tx_get = readl(&buf_ctrl->tx_get);
+ tx_put = readl(&buf_ctrl->tx_put);
+ tx_bufsize = readl(&buf_ctrl->tx_bufsize);
+ tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
if (tx_put >= tx_get)
char_count = tx_get - tx_put - 1 + tx_bufsize;
else
@@ -1686,9 +1632,8 @@ cyz_handle_tx(struct cyclades_port *info,
if (char_count) {
- if (tty == 0) {
+ if (tty == NULL)
goto ztxdone;
- }
if (info->x_char) { /* send special char */
data = info->x_char;
@@ -1698,8 +1643,6 @@ cyz_handle_tx(struct cyclades_port *info,
info->x_char = 0;
char_count--;
info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
}
#ifdef BLOCKMOVE
while (0 < (small_count = min_t(unsigned int,
@@ -1719,8 +1662,6 @@ cyz_handle_tx(struct cyclades_port *info,
info->xmit_cnt -= small_count;
info->xmit_tail = (info->xmit_tail + small_count) &
(SERIAL_XMIT_SIZE - 1);
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
}
#else
while (info->xmit_cnt && char_count) {
@@ -1733,8 +1674,6 @@ cyz_handle_tx(struct cyclades_port *info,
tx_put = (tx_put + 1) & (tx_bufsize - 1);
char_count--;
info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
}
#endif
ztxdone:
@@ -1750,33 +1689,32 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
{
struct tty_struct *tty;
struct cyclades_port *info;
- static volatile struct FIRM_ID __iomem *firm_id;
- static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
- static volatile struct BOARD_CTRL __iomem *board_ctrl;
- static volatile struct CH_CTRL __iomem *ch_ctrl;
- static volatile struct BUF_CTRL __iomem *buf_ctrl;
- uclong channel;
- ucchar cmd;
- uclong param;
- uclong hw_ver, fw_ver;
+ static struct FIRM_ID __iomem *firm_id;
+ static struct ZFW_CTRL __iomem *zfw_ctrl;
+ static struct BOARD_CTRL __iomem *board_ctrl;
+ static struct CH_CTRL __iomem *ch_ctrl;
+ static struct BUF_CTRL __iomem *buf_ctrl;
+ __u32 channel;
+ __u8 cmd;
+ __u32 param;
+ __u32 hw_ver, fw_ver;
int special_count;
int delta_count;
firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
- fw_ver = cy_readl(&board_ctrl->fw_version);
- hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+ fw_ver = readl(&board_ctrl->fw_version);
+ hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
mail_box_0);
while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
special_count = 0;
delta_count = 0;
- info = &cy_port[channel + cinfo->first_line];
- if ((tty = info->tty) == 0) {
+ info = &cinfo->ports[channel];
+ if ((tty = info->tty) == NULL)
continue;
- }
+
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
@@ -1801,7 +1739,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
delta_count++;
if (info->flags & ASYNC_CHECK_CD) {
if ((fw_ver > 241 ? ((u_long) param) :
- cy_readl(&ch_ctrl->rs_status)) &
+ readl(&ch_ctrl->rs_status)) &
C_RS_DCD) {
cy_sched_event(info,
Cy_EVENT_OPEN_WAKEUP);
@@ -1833,8 +1771,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
case C_CM_INTBACK2:
/* Reception Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: rcvd intr, card %d, "
- "port %ld\n\r", info->card, channel);
+ printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
+ "port %ld\n", info->card, channel);
#endif
cyz_handle_rx(info, ch_ctrl, buf_ctrl);
break;
@@ -1843,8 +1781,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
case C_CM_INTBACK:
/* Transmission Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: xmit intr, card %d, "
- "port %ld\n\r", info->card, channel);
+ printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
+ "port %ld\n", info->card, channel);
#endif
cyz_handle_tx(info, ch_ctrl, buf_ctrl);
break;
@@ -1865,18 +1803,19 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
#ifdef CONFIG_CYZ_INTR
static irqreturn_t cyz_interrupt(int irq, void *dev_id)
{
- struct cyclades_card *cinfo;
+ struct cyclades_card *cinfo = dev_id;
- if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+ if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+ printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
- if (!ISZLOADED(*cinfo)) {
+ if (unlikely(!ISZLOADED(*cinfo))) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
+ printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
+ "(IRQ%d).\n", irq);
#endif
return IRQ_NONE;
}
@@ -1890,19 +1829,18 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
static void cyz_rx_restart(unsigned long arg)
{
struct cyclades_port *info = (struct cyclades_port *)arg;
+ struct cyclades_card *card = info->card;
int retval;
- int card = info->card;
- uclong channel = (info->line) - (cy_card[card].first_line);
+ __u32 channel = info->line - card->first_line;
unsigned long flags;
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
if (retval != 0) {
- printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
+ printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
info->line, retval);
}
- cyz_rx_full_timer[info->line].function = NULL;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
#else /* CONFIG_CYZ_INTR */
@@ -1912,14 +1850,14 @@ static void cyz_poll(unsigned long arg)
struct cyclades_card *cinfo;
struct cyclades_port *info;
struct tty_struct *tty;
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct BOARD_CTRL *board_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
+ static struct FIRM_ID *firm_id;
+ static struct ZFW_CTRL *zfw_ctrl;
+ static struct BOARD_CTRL *board_ctrl;
+ static struct CH_CTRL *ch_ctrl;
+ static struct BUF_CTRL *buf_ctrl;
+ unsigned long expires = jiffies + HZ;
int card, port;
- cyz_timerlist.expires = jiffies + (HZ);
for (card = 0; card < NR_CARDS; card++) {
cinfo = &cy_card[card];
@@ -1930,12 +1868,12 @@ static void cyz_poll(unsigned long arg)
firm_id = cinfo->base_addr + ID_ADDRESS;
zfw_ctrl = cinfo->base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &(zfw_ctrl->board_ctrl);
/* Skip first polling cycle to avoid racing conditions with the FW */
if (!cinfo->intr_enabled) {
- cinfo->nports = (int)cy_readl(&board_ctrl->n_channel);
+ cinfo->nports = (int)readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
continue;
}
@@ -1943,7 +1881,7 @@ static void cyz_poll(unsigned long arg)
cyz_handle_cmd(cinfo);
for (port = 0; port < cinfo->nports; port++) {
- info = &cy_port[port + cinfo->first_line];
+ info = &cinfo->ports[port];
tty = info->tty;
ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
@@ -1953,9 +1891,9 @@ static void cyz_poll(unsigned long arg)
cyz_handle_tx(info, ch_ctrl, buf_ctrl);
}
/* poll every 'cyz_polling_cycle' period */
- cyz_timerlist.expires = jiffies + cyz_polling_cycle;
+ expires = jiffies + cyz_polling_cycle;
}
- add_timer(&cyz_timerlist);
+ mod_timer(&cyz_timerlist, expires);
} /* cyz_poll */
#endif /* CONFIG_CYZ_INTR */
@@ -1968,20 +1906,21 @@ static void cyz_poll(unsigned long arg)
*/
static int startup(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
int retval = 0;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
unsigned long page;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = info->line - card->first_line;
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
@@ -2001,24 +1940,22 @@ static int startup(struct cyclades_port *info)
else
info->xmit_buf = (unsigned char *)page;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
set_line_char(info);
- if (!IS_CYC_Z(cy_card[card])) {
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc startup card %d, chip %d, channel %d, "
- "base_addr %lx\n",
- card, chip, channel, (long)base_addr);
- /**/
+ printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
+ "base_addr %p\n",
+ card, chip, channel, base_addr);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
@@ -2034,14 +1971,14 @@ static int startup(struct cyclades_port *info)
cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:startup raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) | CyRxData);
+ readb(base_addr + (CySRER << index)) | CyRxData);
info->flags |= ASYNC_INITIALIZED;
if (info->tty) {
@@ -2054,7 +1991,7 @@ static int startup(struct cyclades_port *info)
info->idle_stats.recv_idle =
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
struct FIRM_ID __iomem *firm_id;
@@ -2063,24 +2000,23 @@ static int startup(struct cyclades_port *info)
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- base_addr = cy_card[card].base_addr;
+ base_addr = card->base_addr;
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
+ if (!ISZLOADED(*card)) {
return -ENODEV;
}
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
#ifdef CY_DEBUG_OPEN
- printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);
- /**/
+ printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
+ "base_addr %p\n", card, channel, base_addr);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
@@ -2102,33 +2038,31 @@ static int startup(struct cyclades_port *info)
#endif /* CONFIG_CYZ_INTR */
#endif /* Z_WAKE */
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
if (retval != 0) {
- printk("cyc:startup(1) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
/* Flush RX buffers before raising DTR and RTS */
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX,
- 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
if (retval != 0) {
- printk("cyc:startup(2) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
/* set timeout !!! */
/* set RTS and DTR !!! */
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
+ readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
C_RS_DTR);
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
- C_CM_IOCTLM, 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:startup(3) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
#endif
/* enable send, recv, modem !!! */
@@ -2144,51 +2078,50 @@ static int startup(struct cyclades_port *info)
info->idle_stats.recv_idle =
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
#ifdef CY_DEBUG_OPEN
- printk(" cyc startup done\n");
+ printk(KERN_DEBUG "cyc startup done\n");
#endif
return 0;
errout:
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
return retval;
} /* startup */
static void start_xmit(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), channel);
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
+ readb(base_addr + (CySRER << index)) | CyTxRdy);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
#ifdef CONFIG_CYZ_INTR
int retval;
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK,
- 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
if (retval != 0) {
- printk("cyc:start_xmit retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
#else /* CONFIG_CYZ_INTR */
/* Don't have to do anything at this time */
#endif /* CONFIG_CYZ_INTR */
@@ -2201,30 +2134,30 @@ static void start_xmit(struct cyclades_port *info)
*/
static void shutdown(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
if (!(info->flags & ASYNC_INITIALIZED)) {
return;
}
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Y card %d, chip %d, channel %d, "
- "base_addr %lx\n",
- card, chip, channel, (long)base_addr);
+ printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
+ "channel %d, base_addr %p\n",
+ card, chip, channel, base_addr);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
/* Clear delta_msr_wait queue to avoid mem leaks. */
wake_up_interruptible(&info->delta_msr_wait);
@@ -2240,10 +2173,10 @@ static void shutdown(struct cyclades_port *info)
cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc shutdown dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
}
cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
@@ -2254,7 +2187,7 @@ static void shutdown(struct cyclades_port *info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->flags &= ~ASYNC_INITIALIZED;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -2262,23 +2195,23 @@ static void shutdown(struct cyclades_port *info)
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- base_addr = cy_card[card].base_addr;
+ base_addr = card->base_addr;
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);
+ printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
+ "base_addr %p\n", card, channel, base_addr);
#endif
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
+ if (!ISZLOADED(*card)) {
return;
}
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
if (info->xmit_buf) {
unsigned char *temp;
@@ -2289,16 +2222,16 @@ static void shutdown(struct cyclades_port *info)
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
cy_writel(&ch_ctrl[channel].rs_control,
- (uclong)(cy_readl(&ch_ctrl[channel].rs_control)&
+ (__u32)(readl(&ch_ctrl[channel].rs_control) &
~(C_RS_RTS | C_RS_DTR)));
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ retval = cyz_issue_cmd(info->card, channel,
C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:shutdown retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:shutdown dropping Z DTR\n");
+ printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
#endif
}
@@ -2307,11 +2240,11 @@ static void shutdown(struct cyclades_port *info)
}
info->flags &= ~ASYNC_INITIALIZED;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
#ifdef CY_DEBUG_OPEN
- printk(" cyc shutdown done\n");
+ printk(KERN_DEBUG "cyc shutdown done\n");
#endif
} /* shutdown */
@@ -2332,7 +2265,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
int retval;
void __iomem *base_addr;
- cinfo = &cy_card[info->card];
+ cinfo = info->card;
channel = info->line - cinfo->first_line;
/*
@@ -2340,9 +2273,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
* until it's done, and then try again.
*/
if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- }
+ wait_event_interruptible(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
@@ -2365,17 +2297,16 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
+ "count = %d\n", info->line, info->count);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
if (!tty_hung_up_p(filp))
info->count--;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
#ifdef CY_DEBUG_COUNT
- printk("cyc block_til_ready: (%d): decrementing count to %d\n",
- current->pid, info->count);
+ printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
+ "%d\n", current->pid, info->count);
#endif
info->blocked_open++;
@@ -2386,7 +2317,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
while (1) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
if ((tty->termios->c_cflag & CBAUD)) {
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
@@ -2395,15 +2326,14 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
cy_writeb(base_addr + (CyMSVR2 << index),
CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr +
- (CyMSVR1 << index)),
- cy_readb(base_addr +
- (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:block_til_ready raising "
+ "DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
@@ -2413,26 +2343,25 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
break;
}
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (cy_readb(base_addr +
+ (readb(base_addr +
(CyMSVR1 << index)) & CyDCD))) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
break;
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, "
- "count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc block_til_ready blocking: "
+ "ttyC%d, count = %d\n",
+ info->line, info->count);
#endif
schedule();
}
@@ -2446,31 +2375,30 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
base_addr = cinfo->base_addr;
firm_id = base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
return -EINVAL;
}
- zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
while (1) {
if ((tty->termios->c_cflag & CBAUD)) {
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) | (C_RS_RTS |
- C_RS_DTR));
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
+ readl(&ch_ctrl[channel].rs_control) |
+ C_RS_RTS | C_RS_DTR);
+ retval = cyz_issue_cmd(cinfo,
+ channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:block_til_ready retval on "
- "ttyC%d was %x\n",
+ printk(KERN_ERR "cyc:block_til_ready "
+ "retval on ttyC%d was %x\n",
info->line, retval);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:block_til_ready raising "
+ "Z DTR\n");
#endif
}
@@ -2482,7 +2410,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
break;
}
if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (cy_readl(&ch_ctrl[channel].rs_status) &
+ (readl(&ch_ctrl[channel].rs_status) &
C_RS_DCD))) {
break;
}
@@ -2491,28 +2419,26 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
break;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, "
- "count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc block_til_ready blocking: "
+ "ttyC%d, count = %d\n",
+ info->line, info->count);
#endif
schedule();
}
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)) {
info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:block_til_ready (%d): incrementing count to %d\n",
- current->pid, info->count);
+ printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
+ "count to %d\n", current->pid, info->count);
#endif
}
info->blocked_open--;
#ifdef CY_DEBUG_OPEN
- printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
+ "count = %d\n", info->line, info->count);
#endif
if (retval)
return retval;
@@ -2527,13 +2453,20 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
static int cy_open(struct tty_struct *tty, struct file *filp)
{
struct cyclades_port *info;
+ unsigned int i;
int retval, line;
line = tty->index;
if ((line < 0) || (NR_PORTS <= line)) {
return -ENODEV;
}
- info = &cy_port[line];
+ for (i = 0; i < NR_CARDS; i++)
+ if (line < cy_card[i].first_line + cy_card[i].nports &&
+ line >= cy_card[i].first_line)
+ break;
+ if (i >= NR_CARDS)
+ return -ENODEV;
+ info = &cy_card[i].ports[line - cy_card[i].first_line];
if (info->line < 0) {
return -ENODEV;
}
@@ -2542,23 +2475,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
treat it as absent from the system. This
will make the user pay attention.
*/
- if (IS_CYC_Z(cy_card[info->card])) {
- struct cyclades_card *cinfo = &cy_card[info->card];
+ if (IS_CYC_Z(*info->card)) {
+ struct cyclades_card *cinfo = info->card;
struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
- if (((ZE_V1 == cy_readl(
- &((struct RUNTIME_9060 __iomem *)
+ if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
(cinfo->ctl_addr))->mail_box_0)) &&
Z_FPGA_CHECK(*cinfo)) &&
- (ZFIRM_HLT == cy_readl(
+ (ZFIRM_HLT == readl(
&firm_id->signature))) {
- printk("cyc:Cyclades-Z Error: you need an "
- "external power supply for this number "
- "of ports.\n\rFirmware halted.\r\n");
+ printk(KERN_ERR "cyc:Cyclades-Z Error: you "
+ "need an external power supply for "
+ "this number of ports.\nFirmware "
+ "halted.\n");
} else {
- printk("cyc:Cyclades-Z firmware not yet "
- "loaded\n");
+ printk(KERN_ERR "cyc:Cyclades-Z firmware not "
+ "yet loaded\n");
}
return -ENODEV;
}
@@ -2572,24 +2505,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
struct BOARD_CTRL __iomem *board_ctrl;
zfw_ctrl = cinfo->base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ (readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
/* Enable interrupts on the PLX chip */
cy_writew(cinfo->ctl_addr + 0x68,
- cy_readw(cinfo->ctl_addr +
- 0x68) | 0x0900);
+ readw(cinfo->ctl_addr + 0x68) | 0x0900);
/* Enable interrupts on the FW */
retval = cyz_issue_cmd(cinfo, 0,
C_CM_IRQ_ENBL, 0L);
if (retval != 0) {
- printk("cyc:IRQ enable retval was %x\n",
- retval);
+ printk(KERN_ERR "cyc:IRQ enable retval "
+ "was %x\n", retval);
}
cinfo->nports =
- (int)cy_readl(&board_ctrl->n_channel);
+ (int)readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
}
}
@@ -2599,7 +2531,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
}
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_open ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
#endif
tty->driver_data = info;
info->tty = tty;
@@ -2607,12 +2539,12 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
+ info->count);
#endif
info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_open (%d): incrementing count to %d\n",
+ printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
@@ -2620,8 +2552,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
+ wait_event_interruptible(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
@@ -2636,8 +2568,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open returning after block_til_ready with %d\n",
- retval);
+ printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
+ "with %d\n", retval);
#endif
return retval;
}
@@ -2645,8 +2577,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
info->throttle = 0;
#ifdef CY_DEBUG_OPEN
- printk(" cyc:cy_open done\n");
- /**/
+ printk(KERN_DEBUG "cyc:cy_open done\n");
#endif
return 0;
} /* cy_open */
@@ -2656,9 +2587,10 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
*/
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_card *card;
+ struct cyclades_port *info = tty->driver_data;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
unsigned long orig_jiffies;
int char_time;
@@ -2697,20 +2629,19 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
if (!timeout || timeout > 2 * info->timeout)
timeout = 2 * info->timeout;
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
+ printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
+ timeout, char_time, jiffies);
#endif
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = (info->line) - (card->first_line);
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
- while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) {
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+ while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Not clean (jiff=%lu)...", jiffies);
+ printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
#endif
if (msleep_interruptible(jiffies_to_msecs(char_time)))
break;
@@ -2718,13 +2649,11 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
timeout))
break;
}
- } else {
- /* Nothing to do! */
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Clean (jiff=%lu)...done\n", jiffies);
+ printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
#endif
}
@@ -2733,25 +2662,29 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
*/
static void cy_close(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_close ttyC%d\n", info->line);
+ printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
#endif
if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
return;
}
- CY_LOCK(info, flags);
+ card = info->card;
+
+ spin_lock_irqsave(&card->card_lock, flags);
/* If the TTY is being hung up, nothing to do */
if (tty_hung_up_p(filp)) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+ printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
+ info->count);
#endif
if ((tty->count == 1) && (info->count != 1)) {
/*
@@ -2761,22 +2694,22 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk("cyc:cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
+ printk(KERN_ERR "cyc:cy_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_close at (%d): decrementing count to %d\n",
+ printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n",
current->pid, info->count - 1);
#endif
if (--info->count < 0) {
#ifdef CY_DEBUG_COUNT
- printk("cyc:cyc_close setting count to 0\n");
+ printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
#endif
info->count = 0;
}
if (info->count) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
info->flags |= ASYNC_CLOSING;
@@ -2786,81 +2719,80 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
tty_wait_until_sent(tty, info->closing_wait);
}
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
- if (!IS_CYC_Z(cy_card[info->card])) {
- int channel = info->line - cy_card[info->card].first_line;
- int index = cy_card[info->card].bus_index;
- void __iomem *base_addr = cy_card[info->card].base_addr +
+ if (!IS_CYC_Z(*card)) {
+ int channel = info->line - card->first_line;
+ int index = card->bus_index;
+ void __iomem *base_addr = card->base_addr +
(cy_chip_offset[channel >> 2] << index);
/* Stop accepting input */
channel &= 0x03;
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) & ~CyRxData);
+ readb(base_addr + (CySRER << index)) & ~CyRxData);
if (info->flags & ASYNC_INITIALIZED) {
/* Waiting for on-board buffers to be empty before closing
the port */
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
cy_wait_until_sent(tty, info->timeout);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
} else {
#ifdef Z_WAKE
/* Waiting for on-board buffers to be empty before closing the port */
- void __iomem *base_addr = cy_card[info->card].base_addr;
+ void __iomem *base_addr = card->base_addr;
struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl =
- base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
- int channel = info->line - cy_card[info->card].first_line;
+ int channel = info->line - card->first_line;
int retval;
- if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
- C_CM_IOCTLW, 0L);
+ if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
if (retval != 0) {
- printk("cyc:cy_close retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_DEBUG "cyc:cy_close retval on "
+ "ttyC%d was %x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
- interruptible_sleep_on(&info->shutdown_wait);
- CY_LOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ wait_for_completion_interruptible(&info->shutdown_wait);
+ spin_lock_irqsave(&card->card_lock, flags);
}
#endif
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
shutdown(info);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
tty->closing = 0;
info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (info->close_delay) {
msleep_interruptible(jiffies_to_msecs
(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_close done\n");
+ printk(KERN_DEBUG "cyc:cy_close done\n");
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_close */
/* This routine gets called when tty_write has put something into
@@ -2878,12 +2810,12 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
*/
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
unsigned long flags;
int c, ret = 0;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_write")) {
@@ -2893,7 +2825,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
if (!info->xmit_buf)
return 0;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
while (1) {
c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
(int)(SERIAL_XMIT_SIZE - info->xmit_head)));
@@ -2909,7 +2841,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
count -= c;
ret += c;
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
@@ -2929,11 +2861,11 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
*/
static void cy_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
unsigned long flags;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_put_char ttyC%d\n", info->line);
+ printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
@@ -2942,9 +2874,9 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
if (!info->xmit_buf)
return;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
return;
}
@@ -2953,7 +2885,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_cnt++;
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
} /* cy_put_char */
/*
@@ -2962,10 +2894,10 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
*/
static void cy_flush_chars(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
@@ -2986,11 +2918,11 @@ static void cy_flush_chars(struct tty_struct *tty)
*/
static int cy_write_room(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
int ret;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_write_room"))
@@ -3003,46 +2935,49 @@ static int cy_write_room(struct tty_struct *tty)
static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel;
+ struct cyclades_card *card;
+ struct cyclades_port *info = tty->driver_data;
+ int channel;
if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
return 0;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = (info->line) - (card->first_line);
#ifdef Z_EXT_CHARS_IN_BUFFER
if (!IS_CYC_Z(cy_card[card])) {
#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
+ printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt);
#endif
return info->xmit_cnt;
#ifdef Z_EXT_CHARS_IN_BUFFER
} else {
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
+ static struct FIRM_ID *firm_id;
+ static struct ZFW_CTRL *zfw_ctrl;
+ static struct CH_CTRL *ch_ctrl;
+ static struct BUF_CTRL *buf_ctrl;
int char_count;
- volatile uclong tx_put, tx_get, tx_bufsize;
+ __u32 tx_put, tx_get, tx_bufsize;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ firm_id = card->base_addr + ID_ADDRESS;
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ tx_get = readl(&buf_ctrl->tx_get);
+ tx_put = readl(&buf_ctrl->tx_put);
+ tx_bufsize = readl(&buf_ctrl->tx_bufsize);
if (tx_put >= tx_get)
char_count = tx_put - tx_get;
else
char_count = tx_put - tx_get + tx_bufsize;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */
+ printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt + char_count);
#endif
return info->xmit_cnt + char_count;
}
@@ -3055,10 +2990,10 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
* ------------------------------------------------------------
*/
-static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
+static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
{
int co, co_val, bpr;
- uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
+ __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
25000000);
if (baud == 0) {
@@ -3086,9 +3021,10 @@ static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
*/
static void set_line_char(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
unsigned cflag, iflag;
unsigned short chip_number;
int baud, baud_rate = 0;
@@ -3118,12 +3054,12 @@ static void set_line_char(struct cyclades_port *info)
}
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = info->line - card->first_line;
chip_number = channel / 4;
- if (!IS_CYC_Z(cy_card[card])) {
+ if (!IS_CYC_Z(*card)) {
- index = cy_card[card].bus_index;
+ index = card->bus_index;
/* baud rate */
baud = tty_get_baud_rate(info->tty);
@@ -3241,10 +3177,9 @@ static void set_line_char(struct cyclades_port *info)
chip = channel >> 2;
channel &= 0x03;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
/* tx and rx baud rate */
@@ -3276,8 +3211,7 @@ static void set_line_char(struct cyclades_port *info)
if (C_CLOCAL(info->tty)) {
/* without modem intr */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr +
- (CySRER << index)) | CyMdmCh);
+ readb(base_addr + (CySRER << index)) | CyMdmCh);
/* act on 1->0 modem transitions */
if ((cflag & CRTSCTS) && info->rflow) {
cy_writeb(base_addr + (CyMCOR1 << index),
@@ -3291,7 +3225,7 @@ static void set_line_char(struct cyclades_port *info)
} else {
/* without modem intr */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER << index)) | CyMdmCh);
/* act on 1->0 modem transitions */
if ((cflag & CRTSCTS) && info->rflow) {
@@ -3316,10 +3250,10 @@ static void set_line_char(struct cyclades_port *info)
~CyDTR);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
} else {
if (info->rtsdtr_inv) {
@@ -3330,17 +3264,17 @@ static void set_line_char(struct cyclades_port *info)
CyDTR);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
}
if (info->tty) {
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
struct FIRM_ID __iomem *firm_id;
@@ -3348,16 +3282,16 @@ static void set_line_char(struct cyclades_port *info)
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
struct BUF_CTRL __iomem *buf_ctrl;
- uclong sw_flow;
+ __u32 sw_flow;
int retval;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
+ firm_id = card->base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*card)) {
return;
}
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
@@ -3408,10 +3342,10 @@ static void set_line_char(struct cyclades_port *info)
}
if (cflag & CSTOPB) {
cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
+ readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
} else {
cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
+ readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
}
if (cflag & PARENB) {
if (cflag & PARODD) {
@@ -3426,12 +3360,10 @@ static void set_line_char(struct cyclades_port *info)
/* CTS flow control flag */
if (cflag & CRTSCTS) {
cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->
- hw_flow) | C_RS_CTS | C_RS_RTS);
+ readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
} else {
- cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->
- hw_flow) & ~(C_RS_CTS | C_RS_RTS));
+ cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
+ ~(C_RS_CTS | C_RS_RTS));
}
/* As the HW flow control is done in firmware, the driver
doesn't need to care about it */
@@ -3446,10 +3378,10 @@ static void set_line_char(struct cyclades_port *info)
}
cy_writel(&ch_ctrl->sw_flow, sw_flow);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
if (retval != 0) {
- printk("cyc:set_line_char retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
/* CD sensitivity */
@@ -3461,22 +3393,22 @@ static void set_line_char(struct cyclades_port *info)
if (baud == 0) { /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
+ readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
#endif
} else {
cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
+ readl(&ch_ctrl->rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
#endif
}
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
if (retval != 0) {
- printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
if (info->tty) {
@@ -3490,14 +3422,15 @@ get_serial_info(struct cyclades_port *info,
struct serial_struct __user * retinfo)
{
struct serial_struct tmp;
- struct cyclades_card *cinfo = &cy_card[info->card];
+ struct cyclades_card *cinfo = info->card;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = info->type;
tmp.line = info->line;
- tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
+ tmp.port = (info->card - cy_card) * 0x100 + info->line -
+ cinfo->first_line;
tmp.irq = cinfo->irq;
tmp.flags = info->flags;
tmp.close_delay = info->close_delay;
@@ -3566,25 +3499,25 @@ check_and_exit:
*/
static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
{
- int card, chip, channel, index;
+ struct cyclades_card *card;
+ int chip, channel, index;
unsigned char status;
unsigned int result;
unsigned long flags;
void __iomem *base_addr;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = (info->line) - (card->first_line);
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
- status = cy_readb(base_addr + (CySRER << index)) &
+ spin_lock_irqsave(&card->card_lock, flags);
+ status = readb(base_addr + (CySRER << index)) &
(CyTxRdy | CyTxMpty);
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
result = (status ? 0 : TIOCSER_TEMT);
} else {
/* Not supported yet */
@@ -3595,8 +3528,9 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, chip, channel, index;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int chip, channel, index;
void __iomem *base_addr;
unsigned long flags;
unsigned char status;
@@ -3611,19 +3545,18 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
return -ENODEV;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- status = cy_readb(base_addr + (CyMSVR1 << index));
- status |= cy_readb(base_addr + (CyMSVR2 << index));
- CY_UNLOCK(info, flags);
+ status = readb(base_addr + (CyMSVR1 << index));
+ status |= readb(base_addr + (CyMSVR2 << index));
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (info->rtsdtr_inv) {
result = ((status & CyRTS) ? TIOCM_DTR : 0) |
@@ -3637,19 +3570,14 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
((status & CyDSR) ? TIOCM_DSR : 0) |
((status & CyCTS) ? TIOCM_CTS : 0);
} else {
- base_addr = cy_card[card].base_addr;
-
- if (cy_card[card].num_chips != -1) {
- return -EINVAL;
- }
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ base_addr = card->base_addr;
+ firm_id = card->base_addr + ID_ADDRESS;
+ if (ISZLOADED(*card)) {
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
- lstatus = cy_readl(&ch_ctrl[channel].rs_status);
+ lstatus = readl(&ch_ctrl[channel].rs_status);
result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
@@ -3669,8 +3597,9 @@ static int
cy_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, chip, channel, index;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int chip, channel, index;
void __iomem *base_addr;
unsigned long flags;
struct FIRM_ID __iomem *firm_id;
@@ -3683,16 +3612,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
return -ENODEV;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = (info->line) - (card->first_line);
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
if (set & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3702,10 +3630,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
cy_writeb(base_addr + (CyMSVR1 << index),
CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3715,10 +3643,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
cy_writeb(base_addr + (CyMSVR1 << index),
~CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (set & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3729,15 +3657,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
CyDTR);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3749,68 +3677,69 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
} else {
- base_addr = cy_card[card].base_addr;
+ base_addr = card->base_addr;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ firm_id = card->base_addr + ID_ADDRESS;
+ if (ISZLOADED(*card)) {
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
if (set & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) | C_RS_RTS);
- CY_UNLOCK(info, flags);
+ readl(&ch_ctrl[channel].rs_control) |
+ C_RS_RTS);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) & ~C_RS_RTS);
- CY_UNLOCK(info, flags);
+ readl(&ch_ctrl[channel].rs_control) &
+ ~C_RS_RTS);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (set & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) | C_RS_DTR);
+ readl(&ch_ctrl[channel].rs_control) |
+ C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_modem_info raising "
+ "Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) & ~C_RS_DTR);
+ readl(&ch_ctrl[channel].rs_control) &
+ ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info clearing Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_modem_info clearing "
+ "Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
} else {
return -ENODEV;
}
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:set_modem_info retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
} /* cy_tiocmset */
@@ -3820,14 +3749,17 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
*/
static void cy_break(struct tty_struct *tty, int break_state)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "cy_break"))
return;
- CY_LOCK(info, flags);
- if (!IS_CYC_Z(cy_card[info->card])) {
+ card = info->card;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ if (!IS_CYC_Z(*card)) {
/* Let the transmit ISR take care of this (since it
requires stuffing characters into the output stream).
*/
@@ -3835,18 +3767,18 @@ static void cy_break(struct tty_struct *tty, int break_state)
if (!info->breakon) {
info->breakon = 1;
if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
start_xmit(info);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
}
} else {
if (!info->breakoff) {
info->breakoff = 1;
if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
start_xmit(info);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
}
}
@@ -3854,24 +3786,25 @@ static void cy_break(struct tty_struct *tty, int break_state)
int retval;
if (break_state == -1) {
- retval = cyz_issue_cmd(&cy_card[info->card],
- info->line - cy_card[info->card].first_line,
+ retval = cyz_issue_cmd(card,
+ info->line - card->first_line,
C_CM_SET_BREAK, 0L);
if (retval != 0) {
- printk("cyc:cy_break (set) retval on ttyC%d "
- "was %x\n", info->line, retval);
+ printk(KERN_ERR "cyc:cy_break (set) retval on "
+ "ttyC%d was %x\n", info->line, retval);
}
} else {
- retval = cyz_issue_cmd(&cy_card[info->card],
- info->line - cy_card[info->card].first_line,
+ retval = cyz_issue_cmd(card,
+ info->line - card->first_line,
C_CM_CLR_BREAK, 0L);
if (retval != 0) {
- printk("cyc:cy_break (clr) retval on ttyC%d "
- "was %x\n", info->line, retval);
+ printk(KERN_DEBUG "cyc:cy_break (clr) retval "
+ "on ttyC%d was %x\n", info->line,
+ retval);
}
}
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_break */
static int
@@ -3889,28 +3822,27 @@ get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
static int set_threshold(struct cyclades_port *info, unsigned long value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long flags;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
+ index = card->bus_index;
base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ card->base_addr + (cy_chip_offset[chip] << index);
info->cor3 &= ~CyREC_FIFO;
info->cor3 |= value & CyREC_FIFO;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
} /* set_threshold */
@@ -3918,25 +3850,23 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
static int
get_threshold(struct cyclades_port *info, unsigned long __user * value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long tmp;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+ tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
return put_user(tmp, value);
- } else {
- /* Nothing to do! */
- return 0;
}
+ return 0;
} /* get_threshold */
static int
@@ -3954,49 +3884,45 @@ get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
static int set_timeout(struct cyclades_port *info, unsigned long value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long flags;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
} /* set_timeout */
static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long tmp;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- tmp = cy_readb(base_addr + (CyRTPR << index));
+ tmp = readb(base_addr + (CyRTPR << index));
return put_user(tmp, value);
- } else {
- /* Nothing to do! */
- return 0;
}
+ return 0;
} /* get_timeout */
static int set_default_timeout(struct cyclades_port *info, unsigned long value)
@@ -4020,7 +3946,7 @@ static int
cy_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
struct cyclades_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
int ret_val = 0;
@@ -4031,7 +3957,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
return -ENODEV;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
+ printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+ info->line, cmd, arg);
#endif
switch (cmd) {
@@ -4076,14 +4003,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
case CYGETRTSDTR_INV:
ret_val = info->rtsdtr_inv;
break;
- case CYGETCARDINFO:
- if (copy_to_user(argp, &cy_card[info->card],
- sizeof(struct cyclades_card))) {
- ret_val = -EFAULT;
- break;
- }
- ret_val = 0;
- break;
case CYGETCD1400VER:
ret_val = info->chip_rev;
break;
@@ -4119,34 +4038,22 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
/* note the counters on entry */
- cprev = info->icount;
- CY_UNLOCK(info, flags);
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
-
- CY_LOCK(info, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
+ ret_val = wait_event_interruptible(info->delta_msr_wait, ({
+ cprev = cnow;
+ spin_lock_irqsave(&info->card->card_lock, flags);
cnow = info->icount; /* atomic copy */
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
- return -EIO; /* no change => error */
- }
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
+ ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
+ }));
+ break;
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
@@ -4155,9 +4062,9 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
* RI where only 0->1 is counted.
*/
case TIOCGICOUNT:
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
cnow = info->icount;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
p_cuser = argp;
ret_val = put_user(cnow.cts, &p_cuser->cts);
if (ret_val)
@@ -4199,7 +4106,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
}
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_ioctl done\n");
+ printk(KERN_DEBUG "cyc:cy_ioctl done\n");
#endif
return ret_val;
@@ -4213,10 +4120,10 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
*/
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_set_termios ttyC%d\n", info->line);
+ printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
#endif
if (tty->termios->c_cflag == old_termios->c_cflag &&
@@ -4248,8 +4155,9 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
*/
static void cy_send_xchar(struct tty_struct *tty, char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel;
if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
return;
@@ -4260,15 +4168,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
cy_start(tty);
card = info->card;
- channel = info->line - cy_card[card].first_line;
+ channel = info->line - card->first_line;
- if (IS_CYC_Z(cy_card[card])) {
+ if (IS_CYC_Z(*card)) {
if (ch == STOP_CHAR(tty))
- cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF,
- 0L);
+ cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
else if (ch == START_CHAR(tty))
- cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON,
- 0L);
+ cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
}
}
@@ -4278,15 +4184,16 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
*/
static void cy_throttle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
- printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
@@ -4297,22 +4204,22 @@ static void cy_throttle(struct tty_struct *tty)
card = info->card;
if (I_IXOFF(tty)) {
- if (!IS_CYC_Z(cy_card[card]))
+ if (!IS_CYC_Z(*card))
cy_send_xchar(tty, STOP_CHAR(tty));
else
info->throttle = 1;
}
if (tty->termios->c_cflag & CRTSCTS) {
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
+ index = card->bus_index;
+ base_addr = card->base_addr +
(cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -4322,7 +4229,7 @@ static void cy_throttle(struct tty_struct *tty)
cy_writeb(base_addr + (CyMSVR1 << index),
~CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 1;
}
@@ -4336,16 +4243,17 @@ static void cy_throttle(struct tty_struct *tty)
*/
static void cy_unthrottle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
- printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty), info->line);
+ printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
+ tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
@@ -4361,15 +4269,15 @@ static void cy_unthrottle(struct tty_struct *tty)
if (tty->termios->c_cflag & CRTSCTS) {
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
+ index = card->bus_index;
+ base_addr = card->base_addr +
(cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -4379,7 +4287,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_writeb(base_addr + (CyMSVR1 << index),
CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 0;
}
@@ -4392,102 +4300,96 @@ static void cy_unthrottle(struct tty_struct *tty)
static void cy_stop(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
void __iomem *base_addr;
int chip, channel, index;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_stop"))
return;
- cinfo = &cy_card[info->card];
+ cinfo = info->card;
channel = info->line - cinfo->first_line;
if (!IS_CYC_Z(*cinfo)) {
index = cinfo->bus_index;
chip = channel >> 2;
channel &= 0x03;
- base_addr = cy_card[info->card].base_addr +
- (cy_chip_offset[chip] << index);
+ base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char)(channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_stop */
static void cy_start(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
void __iomem *base_addr;
int chip, channel, index;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_start ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_start"))
return;
- cinfo = &cy_card[info->card];
+ cinfo = info->card;
channel = info->line - cinfo->first_line;
index = cinfo->bus_index;
if (!IS_CYC_Z(*cinfo)) {
chip = channel >> 2;
channel &= 0x03;
- base_addr = cy_card[info->card].base_addr +
- (cy_chip_offset[chip] << index);
+ base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ readb(base_addr + (CySRER << index)) | CyTxRdy);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
static void cy_flush_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel, retval;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel, retval;
unsigned long flags;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
return;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = info->line - card->first_line;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
- if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
+ if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
buffers as well */
- CY_LOCK(info, flags);
- retval =
- cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
if (retval != 0) {
- printk("cyc: flush_buffer retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
tty_wakeup(tty);
} /* cy_flush_buffer */
@@ -4497,10 +4399,10 @@ static void cy_flush_buffer(struct tty_struct *tty)
*/
static void cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_hangup"))
@@ -4511,7 +4413,8 @@ static void cy_hangup(struct tty_struct *tty)
info->event = 0;
info->count = 0;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
+ printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
+ current->pid);
#endif
info->tty = NULL;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -4526,10 +4429,107 @@ static void cy_hangup(struct tty_struct *tty)
* ---------------------------------------------------------------------
*/
+static int __devinit cy_init_card(struct cyclades_card *cinfo)
+{
+ struct cyclades_port *info;
+ u32 mailbox;
+ unsigned int nports;
+ unsigned short chip_number;
+ int index, port;
+
+ spin_lock_init(&cinfo->card_lock);
+
+ if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
+ mailbox = readl(&((struct RUNTIME_9060 __iomem *)
+ cinfo->ctl_addr)->mail_box_0);
+ nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+ cinfo->intr_enabled = 0;
+ cinfo->nports = 0; /* Will be correctly set later, after
+ Z FW is loaded */
+ } else {
+ index = cinfo->bus_index;
+ nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
+ }
+
+ cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
+ if (cinfo->ports == NULL) {
+ printk(KERN_ERR "Cyclades: cannot allocate ports\n");
+ cinfo->nports = 0;
+ return -ENOMEM;
+ }
+
+ for (port = cinfo->first_line; port < cinfo->first_line + nports;
+ port++) {
+ info = &cinfo->ports[port - cinfo->first_line];
+ info->magic = CYCLADES_MAGIC;
+ info->card = cinfo;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->close_delay = 5 * HZ / 10;
+
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_completion(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+
+ if (IS_CYC_Z(*cinfo)) {
+ info->type = PORT_STARTECH;
+ if (mailbox == ZO_V1)
+ info->xmit_fifo_size = CYZ_FIFO_SIZE;
+ else
+ info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
+#ifdef CONFIG_CYZ_INTR
+ setup_timer(&cyz_rx_full_timer[port],
+ cyz_rx_restart, (unsigned long)info);
+#endif
+ } else {
+ info->type = PORT_CIRRUS;
+ info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+ info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = 0x08; /* _very_ small rcv threshold */
+
+ chip_number = (port - cinfo->first_line) / 4;
+ if ((info->chip_rev = readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] <<
+ index) + (CyGFRCR << index))) >=
+ CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ info->tbpr = baud_bpr_60[13]; /* Tx BPR */
+ info->tco = baud_co_60[13]; /* Tx CO */
+ info->rbpr = baud_bpr_60[13]; /* Rx BPR */
+ info->rco = baud_co_60[13]; /* Rx CO */
+ info->rtsdtr_inv = 1;
+ } else {
+ info->tbpr = baud_bpr_25[13]; /* Tx BPR */
+ info->tco = baud_co_25[13]; /* Tx CO */
+ info->rbpr = baud_bpr_25[13]; /* Rx BPR */
+ info->rco = baud_co_25[13]; /* Rx CO */
+ info->rtsdtr_inv = 0;
+ }
+ info->read_status_mask = CyTIMEOUT | CySPECHAR |
+ CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
+ }
+
+ }
+
+#ifndef CONFIG_CYZ_INTR
+ if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
+ mod_timer(&cyz_timerlist, jiffies + 1);
+#ifdef CY_PCI_DEBUG
+ printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
+#endif
+ }
+#endif
+ return 0;
+}
+
/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
-static unsigned short __init
-cyy_init_card(void __iomem * true_base_addr, int index)
+static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
+ int index)
{
unsigned int chip_number;
void __iomem *base_addr;
@@ -4544,7 +4544,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
base_addr =
true_base_addr + (cy_chip_offset[chip_number] << index);
mdelay(1);
- if (cy_readb(base_addr + (CyCCR << index)) != 0x00) {
+ if (readb(base_addr + (CyCCR << index)) != 0x00) {
/*************
printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
chip_number, (unsigned long)base_addr);
@@ -4561,7 +4561,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
chip 4 GFRCR register appears at chip 0, there is no chip 4
and this must be a Cyclom-16Y, not a Cyclom-32Ye.
*/
- if (chip_number == 4 && cy_readb(true_base_addr +
+ if (chip_number == 4 && readb(true_base_addr +
(cy_chip_offset[0] << index) +
(CyGFRCR << index)) == 0) {
return chip_number;
@@ -4570,7 +4570,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
mdelay(1);
- if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) {
+ if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
/*
printk(" chip #%d at %#6lx is not responding ",
chip_number, (unsigned long)base_addr);
@@ -4578,7 +4578,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
*/
return chip_number;
}
- if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) !=
+ if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
0x40) {
/*
printk(" chip #%d at %#6lx is not valid (GFRCR == "
@@ -4589,7 +4589,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
return chip_number;
}
cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
- if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
+ if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
/* Impossible to reach 5ms with this chip.
Changed to 2ms instead (f = 500 Hz). */
@@ -4602,7 +4602,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
/*
printk(" chip #%d at %#6lx is rev 0x%2x\n",
chip_number, (unsigned long)base_addr,
- cy_readb(base_addr+(CyGFRCR<<index)));
+ readb(base_addr+(CyGFRCR<<index)));
*/
}
return chip_number;
@@ -4647,9 +4647,15 @@ static int __init cy_detect_isa(void)
/* probe for CD1400... */
cy_isa_address = ioremap(isa_address, CyISA_Ywin);
+ if (cy_isa_address == NULL) {
+ printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
+ "address\n");
+ continue;
+ }
cy_isa_nchan = CyPORTS_PER_CHIP *
cyy_init_card(cy_isa_address, 0);
if (cy_isa_nchan == 0) {
+ iounmap(cy_isa_address);
continue;
}
#ifdef MODULE
@@ -4660,40 +4666,42 @@ static int __init cy_detect_isa(void)
/* find out the board's irq by probing */
cy_isa_irq = detect_isa_irq(cy_isa_address);
if (cy_isa_irq == 0) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
+ "IRQ could not be detected.\n",
(unsigned long)cy_isa_address);
- printk("but the IRQ could not be detected.\n");
+ iounmap(cy_isa_address);
continue;
}
if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
+ "more channels are available. Change NR_PORTS "
+ "in cyclades.c and recompile kernel.\n",
(unsigned long)cy_isa_address);
- printk("but no more channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile "
- "kernel.\n");
+ iounmap(cy_isa_address);
return nboard;
}
/* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
+ if (cy_card[j].base_addr == NULL)
break;
}
if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/ISA found at 0x%lx ",
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
+ "more cards can be used. Change NR_CARDS in "
+ "cyclades.c and recompile kernel.\n",
(unsigned long)cy_isa_address);
- printk("but no more cards can be used .\n");
- printk("Change NR_CARDS in cyclades.c and recompile "
- "kernel.\n");
+ iounmap(cy_isa_address);
return nboard;
}
/* allocate IRQ */
if (request_irq(cy_isa_irq, cyy_interrupt,
IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long)cy_isa_address);
- printk("but could not allocate IRQ#%d.\n", cy_isa_irq);
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
+ "could not allocate IRQ#%d.\n",
+ (unsigned long)cy_isa_address, cy_isa_irq);
+ iounmap(cy_isa_address);
return nboard;
}
@@ -4704,15 +4712,23 @@ static int __init cy_detect_isa(void)
cy_card[j].bus_index = 0;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_isa_nchan / 4;
+ if (cy_init_card(&cy_card[j])) {
+ cy_card[j].base_addr = NULL;
+ free_irq(cy_isa_irq, &cy_card[j]);
+ iounmap(cy_isa_address);
+ continue;
+ }
nboard++;
- /* print message */
- printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
+ printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
+ "%d channels starting from port %d\n",
j + 1, (unsigned long)cy_isa_address,
(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
- cy_isa_irq);
- printk("%d channels starting from port %d.\n",
- cy_isa_nchan, cy_next_channel);
+ cy_isa_irq, cy_isa_nchan, cy_next_channel);
+
+ for (j = cy_next_channel;
+ j < cy_next_channel + cy_isa_nchan; j++)
+ tty_register_device(cy_serial_driver, j, NULL);
cy_next_channel += cy_isa_nchan;
}
return nboard;
@@ -4721,510 +4737,310 @@ static int __init cy_detect_isa(void)
#endif /* CONFIG_ISA */
} /* cy_detect_isa */
-static void plx_init(void __iomem * addr, uclong initctl)
+#ifdef CONFIG_PCI
+static void __devinit plx_init(void __iomem * addr, __u32 initctl)
{
/* Reset PLX */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+ cy_writel(addr + initctl, readl(addr + initctl) | 0x40000000);
udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+ cy_writel(addr + initctl, readl(addr + initctl) & ~0x40000000);
/* Reload Config. Registers from EEPROM */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+ cy_writel(addr + initctl, readl(addr + initctl) | 0x20000000);
udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+ cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000);
}
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-static int __init cy_detect_pci(void)
+static int __devinit cy_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
-#ifdef CONFIG_PCI
-
- struct pci_dev *pdev = NULL;
- unsigned char cyy_rev_id;
- unsigned char cy_pci_irq = 0;
- uclong cy_pci_phys0, cy_pci_phys2;
- void __iomem *cy_pci_addr0, *cy_pci_addr2;
- unsigned short i, j, cy_pci_nchan, plx_ver;
- unsigned short device_id, dev_index = 0;
- uclong mailbox;
- uclong ZeIndex = 0;
- void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
- uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
- unsigned char Ze_irq[NR_CARDS];
- struct pci_dev *Ze_pdev[NR_CARDS];
-
- for (i = 0; i < NR_CARDS; i++) {
- /* look for a Cyclades card by vendor and device id */
- while ((device_id = cy_pci_dev_id[dev_index].device) != 0) {
- if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
- device_id, pdev)) == NULL) {
- dev_index++; /* try next device id */
- } else {
- break; /* found a board */
- }
- }
-
- if (device_id == 0)
- break;
-
- if (pci_enable_device(pdev))
- continue;
-
- /* read PCI configuration area */
- cy_pci_irq = pdev->irq;
- cy_pci_phys0 = pci_resource_start(pdev, 0);
- cy_pci_phys2 = pci_resource_start(pdev, 2);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+ void __iomem *addr0 = NULL, *addr2 = NULL;
+ char *card_name = NULL;
+ u32 mailbox;
+ unsigned int device_id, nchan = 0, card_no, i;
+ unsigned char plx_ver;
+ int retval, irq;
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "cannot enable device\n");
+ goto err;
+ }
- device_id &= ~PCI_DEVICE_ID_MASK;
+ /* read PCI configuration area */
+ irq = pdev->irq;
+ device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
- if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
- device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
-#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+#if defined(__alpha__)
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
+ dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
+ "addresses on Alpha systems.\n");
+ retval = -EIO;
+ goto err_dis;
+ }
#endif
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
+ dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
+ "addresses\n");
+ retval = -EIO;
+ goto err_dis;
+ }
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly "
- "set. Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
+ if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+ dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
+ "it...\n");
+ pdev->resource[2].flags &= ~IORESOURCE_IO;
+ }
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve "
- "PCI resources\n");
- continue;
- }
-#if defined(__alpha__)
- if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2,
- (ulong)cy_pci_phys0);
- printk("Cyclom-Y/PCI not supported for low "
- "addresses in Alpha systems.\n");
- i--;
- continue;
- }
-#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
+ retval = pci_request_regions(pdev, "cyclades");
+ if (retval) {
+ dev_err(&pdev->dev, "failed to reserve resources\n");
+ goto err_dis;
+ }
-#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI: relocate winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
-#endif
- cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
- cyy_init_card(cy_pci_addr2, 1));
- if (cy_pci_nchan == 0) {
- printk("Cyclom-Y PCI host card with ");
- printk("no Serial-Modules at 0x%lx.\n",
- (ulong) cy_pci_phys2);
- i--;
- continue;
- }
- if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and "
- "recompile kernel.\n");
- return i;
- }
- /* fill the next cy_card structure available */
- for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
- break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and "
- "recompile kernel.\n");
- return i;
- }
+ retval = -EIO;
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+ card_name = "Cyclom-Y";
- /* allocate IRQ */
- if (request_irq(cy_pci_irq, cyy_interrupt,
- IRQF_SHARED, "Cyclom-Y", &cy_card[j])) {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return i;
- }
+ addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+ if (addr0 == NULL) {
+ dev_err(&pdev->dev, "can't remap ctl region\n");
+ goto err_reg;
+ }
+ addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+ if (addr2 == NULL) {
+ dev_err(&pdev->dev, "can't remap base region\n");
+ goto err_unmap;
+ }
- /* set cy_card */
- cy_card[j].base_phys = (ulong) cy_pci_phys2;
- cy_card[j].ctl_phys = (ulong) cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int)cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_pci_nchan / 4;
- cy_card[j].pdev = pdev;
-
- /* enable interrupts in the PCI interface */
- plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
- switch (plx_ver) {
- case PLX_9050:
-
- cy_writeb(cy_pci_addr0 + 0x4c, 0x43);
- break;
+ nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
+ if (nchan == 0) {
+ dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
+ "Serial-Modules\n");
+ return -EIO;
+ }
+ } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
+ struct RUNTIME_9060 __iomem *ctl_addr;
- case PLX_9060:
- case PLX_9080:
- default: /* Old boards, use PLX_9060 */
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent
- fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- cy_pci_irq);
-
- cy_writew(cy_pci_addr0 + 0x68,
- cy_readw(cy_pci_addr0 +
- 0x68) | 0x0900);
- break;
- }
+ ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+ if (addr0 == NULL) {
+ dev_err(&pdev->dev, "can't remap ctl region\n");
+ goto err_reg;
+ }
- /* print message */
- printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j + 1, (ulong)cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1),
- (int)cy_pci_irq);
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
-
- cy_next_channel += cy_pci_nchan;
- } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
- /* print message */
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
- printk("Cyclades-Z/PCI not supported for low "
- "addresses\n");
- break;
- } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
-#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong) cy_pci_phys2, (ulong) cy_pci_phys0);
-#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
-
- /* Disable interrupts on the PLX before resetting it */
- cy_writew(cy_pci_addr0 + 0x68,
- cy_readw(cy_pci_addr0 + 0x68) & ~0x0900);
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent
- fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- cy_pci_irq);
-
- mailbox =
- (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
-
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly "
- "set. Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
+ /* Disable interrupts on the PLX before resetting it */
+ cy_writew(addr0 + 0x68,
+ readw(addr0 + 0x68) & ~0x0900);
+
+ plx_init(addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+
+ mailbox = (u32)readl(&ctl_addr->mail_box_0);
+
+ addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
+ CyPCI_Ze_win : CyPCI_Zwin);
+ if (addr2 == NULL) {
+ dev_err(&pdev->dev, "can't remap base region\n");
+ goto err_unmap;
+ }
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve "
- "PCI resources\n");
- continue;
- }
+ if (mailbox == ZE_V1) {
+ card_name = "Cyclades-Ze";
- if (mailbox == ZE_V1) {
- cy_pci_addr2 = ioremap(cy_pci_phys2,
- CyPCI_Ze_win);
- if (ZeIndex == NR_CARDS) {
- printk("Cyclades-Ze/PCI found at "
- "0x%lx but no more cards can "
- "be used.\nChange NR_CARDS in "
- "cyclades.c and recompile "
- "kernel.\n",
- (ulong)cy_pci_phys2);
- } else {
- Ze_phys0[ZeIndex] = cy_pci_phys0;
- Ze_phys2[ZeIndex] = cy_pci_phys2;
- Ze_addr0[ZeIndex] = cy_pci_addr0;
- Ze_addr2[ZeIndex] = cy_pci_addr2;
- Ze_irq[ZeIndex] = cy_pci_irq;
- Ze_pdev[ZeIndex] = pdev;
- ZeIndex++;
- }
- i--;
- continue;
- } else {
- cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin);
- }
+ readl(&ctl_addr->mail_box_0);
+ nchan = ZE_V1_NPORTS;
+ } else {
+ card_name = "Cyclades-8Zo";
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong) cy_pci_addr2, (ulong) cy_pci_addr0);
if (mailbox == ZO_V1) {
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base,
- WIN_CREG);
- PAUSE;
- printk("Cyclades-8Zo/PCI: FPGA id %lx, ver "
- "%lx\n", (ulong) (0xff &
- cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->fpga_id)),
- (ulong)(0xff &
- cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->
- fpga_version)));
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base,
- WIN_RAM);
+ cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
+ dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
+ "id %lx, ver %lx\n", (ulong)(0xff &
+ readl(&((struct CUSTOM_REG *)addr2)->
+ fpga_id)), (ulong)(0xff &
+ readl(&((struct CUSTOM_REG *)addr2)->
+ fpga_version)));
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
} else {
- printk("Cyclades-Z/PCI: New Cyclades-Z board. "
- "FPGA not loaded\n");
+ dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
+ "Cyclades-Z board. FPGA not loaded\n");
}
#endif
/* The following clears the firmware id word. This
ensures that the driver will not attempt to talk to
the board until it has been properly initialized.
*/
- PAUSE;
if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
- cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
+ cy_writel(addr2 + ID_ADDRESS, 0L);
/* This must be a Cyclades-8Zo/PCI. The extendable
version will have a different device_id and will
be allocated its maximum number of ports. */
- cy_pci_nchan = 8;
-
- if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-8Zo/PCI found at 0x%lx but"
- "no channels are available.\nChange "
- "NR_PORTS in cyclades.c and recompile "
- "kernel.\n", (ulong)cy_pci_phys2);
- return i;
- }
-
- /* fill the next cy_card structure available */
- for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
- break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-8Zo/PCI found at 0x%lx but"
- "no more cards can be used.\nChange "
- "NR_CARDS in cyclades.c and recompile "
- "kernel.\n", (ulong)cy_pci_phys2);
- return i;
- }
-#ifdef CONFIG_CYZ_INTR
- /* allocate IRQ only if board has an IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
- if (request_irq(cy_pci_irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z",
- &cy_card[j])) {
- printk("Cyclom-8Zo/PCI found at 0x%lx "
- "but could not allocate "
- "IRQ%d.\n", (ulong)cy_pci_phys2,
- cy_pci_irq);
- return i;
- }
- }
-#endif /* CONFIG_CYZ_INTR */
-
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int)cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
- cy_card[j].pdev = pdev;
-
- /* print message */
-#ifdef CONFIG_CYZ_INTR
- /* don't report IRQ if board is no IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, "
- "IRQ%d, ", j + 1, (ulong)cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1),
- (int)cy_pci_irq);
- else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
- j + 1, (ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
-
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
- cy_next_channel += cy_pci_nchan;
+ nchan = 8;
}
}
- for (; ZeIndex != 0 && i < NR_CARDS; i++) {
- cy_pci_phys0 = Ze_phys0[0];
- cy_pci_phys2 = Ze_phys2[0];
- cy_pci_addr0 = Ze_addr0[0];
- cy_pci_addr2 = Ze_addr2[0];
- cy_pci_irq = Ze_irq[0];
- pdev = Ze_pdev[0];
- for (j = 0; j < ZeIndex - 1; j++) {
- Ze_phys0[j] = Ze_phys0[j + 1];
- Ze_phys2[j] = Ze_phys2[j + 1];
- Ze_addr0[j] = Ze_addr0[j + 1];
- Ze_addr2[j] = Ze_addr2[j + 1];
- Ze_irq[j] = Ze_irq[j + 1];
- Ze_pdev[j] = Ze_pdev[j + 1];
- }
- ZeIndex--;
- mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
-#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
- printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not "
- "loaded\n");
-#endif
- PAUSE;
- /* This must be the new Cyclades-Ze/PCI. */
- cy_pci_nchan = ZE_V1_NPORTS;
-
- if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-Ze/PCI found at 0x%lx but no channels "
- "are available.\nChange NR_PORTS in cyclades.c "
- "and recompile kernel.\n",
- (ulong) cy_pci_phys2);
- return i;
- }
+ if ((cy_next_channel + nchan) > NR_PORTS) {
+ dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
+ "channels are available. Change NR_PORTS in "
+ "cyclades.c and recompile kernel.\n");
+ goto err_unmap;
+ }
+ /* fill the next cy_card structure available */
+ for (card_no = 0; card_no < NR_CARDS; card_no++) {
+ if (cy_card[card_no].base_addr == NULL)
+ break;
+ }
+ if (card_no == NR_CARDS) { /* no more cy_cards available */
+ dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
+ "more cards can be used. Change NR_CARDS in "
+ "cyclades.c and recompile kernel.\n");
+ goto err_unmap;
+ }
- /* fill the next cy_card structure available */
- for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
- break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-Ze/PCI found at 0x%lx but no more "
- "cards can be used.\nChange NR_CARDS in "
- "cyclades.c and recompile kernel.\n",
- (ulong) cy_pci_phys2);
- return i;
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+ /* allocate IRQ */
+ retval = request_irq(irq, cyy_interrupt,
+ IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+ if (retval) {
+ dev_err(&pdev->dev, "could not allocate IRQ\n");
+ goto err_unmap;
}
+ cy_card[card_no].num_chips = nchan / 4;
+ } else {
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
- if (request_irq(cy_pci_irq, cyz_interrupt,
+ if (irq != 0 && irq != 255) {
+ retval = request_irq(irq, cyz_interrupt,
IRQF_SHARED, "Cyclades-Z",
- &cy_card[j])) {
- printk("Cyclom-Ze/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return i;
+ &cy_card[card_no]);
+ if (retval) {
+ dev_err(&pdev->dev, "could not allocate IRQ\n");
+ goto err_unmap;
}
}
#endif /* CONFIG_CYZ_INTR */
+ cy_card[card_no].num_chips = -1;
+ }
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int)cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
- cy_card[j].pdev = pdev;
+ /* set cy_card */
+ cy_card[card_no].base_addr = addr2;
+ cy_card[card_no].ctl_addr = addr0;
+ cy_card[card_no].irq = irq;
+ cy_card[card_no].bus_index = 1;
+ cy_card[card_no].first_line = cy_next_channel;
+ retval = cy_init_card(&cy_card[card_no]);
+ if (retval)
+ goto err_null;
- /* print message */
-#ifdef CONFIG_CYZ_INTR
- /* don't report IRQ if board is no IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j + 1, (ulong) cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1),
- (int)cy_pci_irq);
- else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
- j + 1, (ulong) cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1));
+ pci_set_drvdata(pdev, &cy_card[card_no]);
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
- cy_next_channel += cy_pci_nchan;
- }
- if (ZeIndex != 0) {
- printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be "
- "used.\nChange NR_CARDS in cyclades.c and recompile "
- "kernel.\n", (unsigned int)Ze_phys2[0]);
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+ /* enable interrupts in the PCI interface */
+ plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
+ switch (plx_ver) {
+ case PLX_9050:
+
+ cy_writeb(addr0 + 0x4c, 0x43);
+ break;
+
+ case PLX_9060:
+ case PLX_9080:
+ default: /* Old boards, use PLX_9060 */
+
+ plx_init(addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+
+ cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
+ break;
+ }
}
- return i;
-#else
+
+ dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
+ "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
+ for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
+ tty_register_device(cy_serial_driver, i, &pdev->dev);
+ cy_next_channel += nchan;
+
return 0;
-#endif /* ifdef CONFIG_PCI */
-} /* cy_detect_pci */
+err_null:
+ cy_card[card_no].base_addr = NULL;
+ free_irq(irq, &cy_card[card_no]);
+err_unmap:
+ pci_iounmap(pdev, addr0);
+ if (addr2)
+ pci_iounmap(pdev, addr2);
+err_reg:
+ pci_release_regions(pdev);
+err_dis:
+ pci_disable_device(pdev);
+err:
+ return retval;
+}
-/*
- * This routine prints out the appropriate serial driver version number
- * and identifies which options were configured into this driver.
- */
-static inline void show_version(void)
+static void __devexit cy_pci_remove(struct pci_dev *pdev)
{
- printk("Cyclades driver " CY_VERSION "\n");
- printk(" built %s %s\n", __DATE__, __TIME__);
-} /* show_version */
+ struct cyclades_card *cinfo = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ /* non-Z with old PLX */
+ if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
+ PLX_9050)
+ cy_writeb(cinfo->ctl_addr + 0x4c, 0);
+ else
+#ifndef CONFIG_CYZ_INTR
+ if (!IS_CYC_Z(*cinfo))
+#endif
+ cy_writew(cinfo->ctl_addr + 0x68,
+ readw(cinfo->ctl_addr + 0x68) & ~0x0900);
+
+ pci_iounmap(pdev, cinfo->base_addr);
+ if (cinfo->ctl_addr)
+ pci_iounmap(pdev, cinfo->ctl_addr);
+ if (cinfo->irq
+#ifndef CONFIG_CYZ_INTR
+ && !IS_CYC_Z(*cinfo)
+#endif /* CONFIG_CYZ_INTR */
+ )
+ free_irq(cinfo->irq, cinfo);
+ pci_release_regions(pdev);
+
+ cinfo->base_addr = NULL;
+ for (i = cinfo->first_line; i < cinfo->first_line +
+ cinfo->nports; i++)
+ tty_unregister_device(cy_serial_driver, i);
+ cinfo->nports = 0;
+ kfree(cinfo->ports);
+}
+
+static struct pci_driver cy_pci_driver = {
+ .name = "cyclades",
+ .id_table = cy_pci_dev_id,
+ .probe = cy_pci_probe,
+ .remove = __devexit_p(cy_pci_remove)
+};
+#endif
static int
cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
int *eof, void *data)
{
struct cyclades_port *info;
- int i;
+ unsigned int i, j;
int len = 0;
off_t begin = 0;
off_t pos = 0;
@@ -5238,33 +5054,34 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
len += size;
/* Output one line for each known port */
- for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
- info = &cy_port[i];
-
- if (info->count)
- size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
- "%8lu %9lu %6ld\n", info->line,
- (cur_jifs - info->idle_stats.in_use) / HZ,
- info->idle_stats.xmit_bytes,
- (cur_jifs - info->idle_stats.xmit_idle) / HZ,
- info->idle_stats.recv_bytes,
- (cur_jifs - info->idle_stats.recv_idle) / HZ,
- info->idle_stats.overruns,
- (long)info->tty->ldisc.num);
- else
- size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
- "%8lu %9lu %6ld\n",
- info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
+ for (i = 0; i < NR_CARDS; i++)
+ for (j = 0; j < cy_card[i].nports; j++) {
+ info = &cy_card[i].ports[j];
+
+ if (info->count)
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+ "%10lu %8lu %9lu %6ld\n", info->line,
+ (cur_jifs - info->idle_stats.in_use) /
+ HZ, info->idle_stats.xmit_bytes,
+ (cur_jifs - info->idle_stats.xmit_idle)/
+ HZ, info->idle_stats.recv_bytes,
+ (cur_jifs - info->idle_stats.recv_idle)/
+ HZ, info->idle_stats.overruns,
+ (long)info->tty->ldisc.num);
+ else
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+ "%10lu %8lu %9lu %6ld\n",
+ info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto done;
}
- if (pos > offset + length)
- goto done;
- }
*eof = 1;
done:
*start = buf + (offset - begin); /* Start of wanted data */
@@ -5319,18 +5136,15 @@ static const struct tty_operations cy_ops = {
static int __init cy_init(void)
{
- struct cyclades_port *info;
- struct cyclades_card *cinfo;
- int number_z_boards = 0;
- int board, port, i, index;
- unsigned long mailbox;
- unsigned short chip_number;
- int nports;
+ unsigned int nboards;
+ int retval = -ENOMEM;
cy_serial_driver = alloc_tty_driver(NR_PORTS);
if (!cy_serial_driver)
- return -ENOMEM;
- show_version();
+ goto err;
+
+ printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
+ __DATE__, __TIME__);
/* Initialize the tty_driver structure */
@@ -5344,15 +5158,13 @@ static int __init cy_init(void)
cy_serial_driver->init_termios = tty_std_termios;
cy_serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(cy_serial_driver, &cy_ops);
- if (tty_register_driver(cy_serial_driver))
- panic("Couldn't register Cyclades serial driver\n");
-
- for (i = 0; i < NR_CARDS; i++) {
- /* base_addr=0 indicates board not found */
- cy_card[i].base_addr = NULL;
+ retval = tty_register_driver(cy_serial_driver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
+ goto err_frtty;
}
/* the code below is responsible to find the boards. Each different
@@ -5363,223 +5175,68 @@ static int __init cy_init(void)
the cy_next_channel. */
/* look for isa boards */
- cy_isa_nboard = cy_detect_isa();
+ nboards = cy_detect_isa();
+#ifdef CONFIG_PCI
/* look for pci boards */
- cy_pci_nboard = cy_detect_pci();
-
- cy_nboard = cy_isa_nboard + cy_pci_nboard;
-
- /* invalidate remaining cy_card structures */
- for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr == 0) {
- cy_card[i].first_line = -1;
- cy_card[i].ctl_addr = NULL;
- cy_card[i].irq = 0;
- cy_card[i].bus_index = 0;
- cy_card[i].first_line = 0;
- cy_card[i].num_chips = 0;
- }
- }
- /* invalidate remaining cy_port structures */
- for (i = cy_next_channel; i < NR_PORTS; i++) {
- cy_port[i].line = -1;
- cy_port[i].magic = -1;
- }
-
- /* initialize per-port data structures for each valid board found */
- for (board = 0; board < cy_nboard; board++) {
- cinfo = &cy_card[board];
- if (cinfo->num_chips == -1) { /* Cyclades-Z */
- number_z_boards++;
- mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_card[board].ctl_addr)->
- mail_box_0);
- nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
- cinfo->intr_enabled = 0;
- cinfo->nports = 0; /* Will be correctly set later, after
- Z FW is loaded */
- spin_lock_init(&cinfo->card_lock);
- for (port = cinfo->first_line;
- port < cinfo->first_line + nports; port++) {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_STARTECH;
- info->card = board;
- info->line = port;
- info->chip_rev = 0;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- if (mailbox == ZO_V1)
- info->xmit_fifo_size = CYZ_FIFO_SIZE;
- else
- info->xmit_fifo_size =
- 4 * CYZ_FIFO_SIZE;
- info->cor1 = 0;
- info->cor2 = 0;
- info->cor3 = 0;
- info->cor4 = 0;
- info->cor5 = 0;
- info->tbpr = 0;
- info->tco = 0;
- info->rbpr = 0;
- info->rco = 0;
- info->custom_divisor = 0;
- info->close_delay = 5 * HZ / 10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask = 0;
- /* info->timeout */
- /* Bentson's vars */
- info->jiffies[0] = 0;
- info->jiffies[1] = 0;
- info->jiffies[2] = 0;
- info->rflush_count = 0;
-#ifdef CONFIG_CYZ_INTR
- init_timer(&cyz_rx_full_timer[port]);
- cyz_rx_full_timer[port].function = NULL;
+ retval = pci_register_driver(&cy_pci_driver);
+ if (retval && !nboards)
+ goto err_unr;
#endif
- }
- continue;
- } else { /* Cyclom-Y of some kind */
- index = cinfo->bus_index;
- spin_lock_init(&cinfo->card_lock);
- cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
- for (port = cinfo->first_line;
- port < cinfo->first_line + cinfo->nports; port++) {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = board;
- info->line = port;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- info->xmit_fifo_size = CyMAX_CHAR_FIFO;
- info->cor1 =
- CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = 0x08; /* _very_ small rcv threshold */
- info->cor4 = 0;
- info->cor5 = 0;
- info->custom_divisor = 0;
- info->close_delay = 5 * HZ / 10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev =
- cy_readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] <<
- index) + (CyGFRCR << index))) >=
- CD1400_REV_J) {
- /* It is a CD1400 rev. J or later */
- info->tbpr = baud_bpr_60[13]; /* Tx BPR */
- info->tco = baud_co_60[13]; /* Tx CO */
- info->rbpr = baud_bpr_60[13]; /* Rx BPR */
- info->rco = baud_co_60[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 1;
- } else {
- info->tbpr = baud_bpr_25[13]; /* Tx BPR */
- info->tco = baud_co_25[13]; /* Tx CO */
- info->rbpr = baud_bpr_25[13]; /* Rx BPR */
- info->rco = baud_co_25[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 0;
- }
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask =
- CyTIMEOUT | CySPECHAR | CyBREAK
- | CyPARITY | CyFRAME | CyOVERRUN;
- /* info->timeout */
- }
- }
- }
-
-#ifndef CONFIG_CYZ_INTR
- if (number_z_boards && !cyz_timeron) {
- cyz_timeron++;
- cyz_timerlist.expires = jiffies + 1;
- add_timer(&cyz_timerlist);
-#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z polling initialized\n");
-#endif
- }
-#endif /* CONFIG_CYZ_INTR */
return 0;
-
+err_unr:
+ tty_unregister_driver(cy_serial_driver);
+err_frtty:
+ put_tty_driver(cy_serial_driver);
+err:
+ return retval;
} /* cy_init */
static void __exit cy_cleanup_module(void)
{
+ struct cyclades_card *card;
int i, e1;
#ifndef CONFIG_CYZ_INTR
- if (cyz_timeron){
- cyz_timeron = 0;
- del_timer(&cyz_timerlist);
- }
+ del_timer_sync(&cyz_timerlist);
#endif /* CONFIG_CYZ_INTR */
if ((e1 = tty_unregister_driver(cy_serial_driver)))
- printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
- e1);
+ printk(KERN_ERR "failed to unregister Cyclades serial "
+ "driver(%d)\n", e1);
- put_tty_driver(cy_serial_driver);
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&cy_pci_driver);
+#endif
for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr) {
- iounmap(cy_card[i].base_addr);
- if (cy_card[i].ctl_addr)
- iounmap(cy_card[i].ctl_addr);
- if (cy_card[i].irq
+ card = &cy_card[i];
+ if (card->base_addr) {
+ /* clear interrupt */
+ cy_writeb(card->base_addr + Cy_ClrIntr, 0);
+ iounmap(card->base_addr);
+ if (card->ctl_addr)
+ iounmap(card->ctl_addr);
+ if (card->irq
#ifndef CONFIG_CYZ_INTR
- && cy_card[i].num_chips != -1 /* not a Z card */
+ && !IS_CYC_Z(*card)
#endif /* CONFIG_CYZ_INTR */
)
- free_irq(cy_card[i].irq, &cy_card[i]);
-#ifdef CONFIG_PCI
- if (cy_card[i].pdev)
- pci_release_regions(cy_card[i].pdev);
-#endif
+ free_irq(card->irq, card);
+ for (e1 = card->first_line;
+ e1 < card->first_line +
+ card->nports; e1++)
+ tty_unregister_device(cy_serial_driver, e1);
+ kfree(card->ports);
}
}
+
+ put_tty_driver(cy_serial_driver);
} /* cy_cleanup_module */
module_init(cy_init);
module_exit(cy_cleanup_module);
MODULE_LICENSE("GPL");
+MODULE_VERSION(CY_VERSION);
diff --git a/drivers/char/digi.h b/drivers/char/digi.h
deleted file mode 100644
index 19df0e879b1..00000000000
--- a/drivers/char/digi.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Definitions for DigiBoard ditty(1) command. */
-
-#if !defined(TIOCMODG)
-#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
-#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCMSET)
-#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
-#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCMBIC)
-#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
-#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCSDTR)
-#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
-#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
-#endif
-
-/************************************************************************
- * Ioctl command arguments for DIGI parameters.
- ************************************************************************/
-#define DIGI_GETA (('e'<<8) | 94) /* Read params */
-
-#define DIGI_SETA (('e'<<8) | 95) /* Set params */
-#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
-#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
-
-#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
- /* control characters */
-#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
- /* control characters */
-#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
- /* flow control chars */
-#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
- /* flow control chars */
-
-struct digiflow_struct {
- unsigned char startc; /* flow cntl start char */
- unsigned char stopc; /* flow cntl stop char */
-};
-
-typedef struct digiflow_struct digiflow_t;
-
-
-/************************************************************************
- * Values for digi_flags
- ************************************************************************/
-#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
-#define DIGI_FAST 0x0002 /* Fast baud rates */
-#define RTSPACE 0x0004 /* RTS input flow control */
-#define CTSPACE 0x0008 /* CTS output flow control */
-#define DSRPACE 0x0010 /* DSR output flow control */
-#define DCDPACE 0x0020 /* DCD output flow control */
-#define DTRPACE 0x0040 /* DTR input flow control */
-#define DIGI_FORCEDCD 0x0100 /* Force carrier */
-#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
-#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
-
-
-/************************************************************************
- * Structure used with ioctl commands for DIGI parameters.
- ************************************************************************/
-struct digi_struct {
- unsigned short digi_flags; /* Flags (see above) */
-};
-
-typedef struct digi_struct digi_t;
diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm
index 6441e01e587..af74cd79a27 100644
--- a/drivers/char/drm/README.drm
+++ b/drivers/char/drm/README.drm
@@ -1,6 +1,6 @@
************************************************************
* For the very latest on DRI development, please see: *
-* http://dri.sourceforge.net/ *
+* http://dri.freedesktop.org/ *
************************************************************
The Direct Rendering Manager (drm) is a device-independent kernel-level
@@ -26,21 +26,19 @@ ways:
Documentation on the DRI is available from:
- http://precisioninsight.com/piinsights.html
+ http://dri.freedesktop.org/wiki/Documentation
+ http://sourceforge.net/project/showfiles.php?group_id=387
+ http://dri.sourceforge.net/doc/
For specific information about kernel-level support, see:
The Direct Rendering Manager, Kernel Support for the Direct Rendering
Infrastructure
- http://precisioninsight.com/dr/drm.html
+ http://dri.sourceforge.net/doc/drm_low_level.html
Hardware Locking for the Direct Rendering Infrastructure
- http://precisioninsight.com/dr/locking.html
+ http://dri.sourceforge.net/doc/hardware_locking_low_level.html
A Security Analysis of the Direct Rendering Infrastructure
- http://precisioninsight.com/dr/security.html
+ http://dri.sourceforge.net/doc/security_low_level.html
-************************************************************
-* For the very latest on DRI development, please see: *
-* http://dri.sourceforge.net/ *
-************************************************************
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index bd7be09ea53..5b91bc04ea4 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -33,59 +33,44 @@
#include "drmP.h"
-#if PAGE_SIZE == 65536
-# define ATI_PCIGART_TABLE_ORDER 0
-# define ATI_PCIGART_TABLE_PAGES (1 << 0)
-#elif PAGE_SIZE == 16384
-# define ATI_PCIGART_TABLE_ORDER 1
-# define ATI_PCIGART_TABLE_PAGES (1 << 1)
-#elif PAGE_SIZE == 8192
-# define ATI_PCIGART_TABLE_ORDER 2
-# define ATI_PCIGART_TABLE_PAGES (1 << 2)
-#elif PAGE_SIZE == 4096
-# define ATI_PCIGART_TABLE_ORDER 3
-# define ATI_PCIGART_TABLE_PAGES (1 << 3)
-#else
-# error - PAGE_SIZE not 64K, 16K, 8K or 4K
-#endif
-
-# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
-static void *drm_ati_alloc_pcigart_table(void)
+static void *drm_ati_alloc_pcigart_table(int order)
{
unsigned long address;
struct page *page;
int i;
- DRM_DEBUG("%s\n", __FUNCTION__);
+
+ DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order);
address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
- ATI_PCIGART_TABLE_ORDER);
+ order);
if (address == 0UL) {
return NULL;
}
page = virt_to_page(address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
+ for (i = 0; i < order; i++, page++)
SetPageReserved(page);
DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
return (void *)address;
}
-static void drm_ati_free_pcigart_table(void *address)
+static void drm_ati_free_pcigart_table(void *address, int order)
{
struct page *page;
int i;
+ int num_pages = 1 << order;
DRM_DEBUG("%s\n", __FUNCTION__);
page = virt_to_page((unsigned long)address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
+ for (i = 0; i < num_pages; i++, page++)
ClearPageReserved(page);
- free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
+ free_pages((unsigned long)address, order);
}
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
drm_sg_mem_t *entry = dev->sg;
unsigned long pages;
int i;
+ int order;
+ int num_pages, max_pages;
/* we need to support large memory configurations */
if (!entry) {
@@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
return 0;
}
+ order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
+ num_pages = 1 << order;
+
if (gart_info->bus_addr) {
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
pci_unmap_single(dev->pdev, gart_info->bus_addr,
- ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+ num_pages * PAGE_SIZE,
PCI_DMA_TODEVICE);
}
- pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (entry->pages <= max_pages)
+ ? entry->pages : max_pages;
for (i = 0; i < pages; i++) {
if (!entry->busaddr[i])
@@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
&& gart_info->addr) {
- drm_ati_free_pcigart_table(gart_info->addr);
+ drm_ati_free_pcigart_table(gart_info->addr, order);
gart_info->addr = NULL;
}
return 1;
}
-
EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
unsigned long pages;
u32 *pci_gart, page_base, bus_address = 0;
int i, j, ret = 0;
+ int order;
+ int max_pages;
+ int num_pages;
if (!entry) {
DRM_ERROR("no scatter/gather memory!\n");
@@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
- address = drm_ati_alloc_pcigart_table();
+ order = drm_order((gart_info->table_size +
+ (PAGE_SIZE-1)) / PAGE_SIZE);
+ num_pages = 1 << order;
+ address = drm_ati_alloc_pcigart_table(order);
if (!address) {
DRM_ERROR("cannot allocate PCI GART page!\n");
goto done;
@@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
}
bus_address = pci_map_single(dev->pdev, address,
- ATI_PCIGART_TABLE_PAGES *
- PAGE_SIZE, PCI_DMA_TODEVICE);
+ num_pages * PAGE_SIZE,
+ PCI_DMA_TODEVICE);
if (bus_address == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
- drm_ati_free_pcigart_table(address);
+ order = drm_order((gart_info->table_size +
+ (PAGE_SIZE-1)) / PAGE_SIZE);
+ drm_ati_free_pcigart_table(address, order);
address = NULL;
goto done;
}
@@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
pci_gart = (u32 *) address;
- pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (entry->pages <= max_pages)
+ ? entry->pages : max_pages;
- memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32));
+ memset(pci_gart, 0, max_pages * sizeof(u32));
for (i = 0; i < pages; i++) {
/* we need to support large memory configurations */
@@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
page_base = (u32) entry->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
- if (gart_info->is_pcie)
+ switch(gart_info->gart_reg_if) {
+ case DRM_ATI_GART_IGP:
+ *pci_gart = cpu_to_le32((page_base) | 0xc);
+ break;
+ case DRM_ATI_GART_PCIE:
*pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
- else
+ break;
+ default:
+ case DRM_ATI_GART_PCI:
*pci_gart = cpu_to_le32(page_base);
+ break;
+ }
pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE;
}
@@ -220,5 +227,4 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
gart_info->bus_addr = bus_address;
return ret;
}
-
EXPORT_SYMBOL(drm_ati_pcigart_init);
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 8db9041e306..089198491f1 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -654,11 +654,13 @@ typedef struct drm_set_version {
/**
* Device specific ioctls should only be in their respective headers
- * The device specific ioctl range is from 0x40 to 0x79.
+ * The device specific ioctl range is from 0x40 to 0x99.
+ * Generic IOCTLS restart at 0xA0.
*
* \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
* drmCommandReadWrite().
*/
#define DRM_COMMAND_BASE 0x40
+#define DRM_COMMAND_END 0xA0
#endif
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 85d99e21e18..d494315752a 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -414,6 +414,10 @@ typedef struct drm_lock_data {
struct file *filp; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
+ spinlock_t spinlock;
+ uint32_t kernel_waiters;
+ uint32_t user_waiters;
+ int idle_has_lock;
} drm_lock_data_t;
/**
@@ -515,12 +519,17 @@ typedef struct drm_vbl_sig {
#define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB 2
+#define DRM_ATI_GART_PCI 1
+#define DRM_ATI_GART_PCIE 2
+#define DRM_ATI_GART_IGP 3
+
typedef struct ati_pcigart_info {
int gart_table_location;
- int is_pcie;
+ int gart_reg_if;
void *addr;
dma_addr_t bus_addr;
drm_local_map_t mapping;
+ int table_size;
} drm_ati_pcigart_info;
/*
@@ -590,6 +599,8 @@ struct drm_driver {
void (*reclaim_buffers) (struct drm_device * dev, struct file * filp);
void (*reclaim_buffers_locked) (struct drm_device *dev,
struct file *filp);
+ void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
+ struct file * filp);
unsigned long (*get_map_ofs) (drm_map_t * map);
unsigned long (*get_reg_ofs) (struct drm_device * dev);
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
@@ -764,7 +775,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
}
#ifdef __alpha__
-#define drm_get_pci_domain(dev) dev->hose->bus->number
+#define drm_get_pci_domain(dev) dev->hose->index
#else
#define drm_get_pci_domain(dev) 0
#endif
@@ -915,9 +926,18 @@ extern int drm_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context);
-extern int drm_lock_free(drm_device_t * dev,
- __volatile__ unsigned int *lock, unsigned int context);
+extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context);
+extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context);
+extern void drm_idlelock_take(drm_lock_data_t *lock_data);
+extern void drm_idlelock_release(drm_lock_data_t *lock_data);
+
+/*
+ * These are exported to drivers so that they can implement fencing using
+ * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
+ */
+
+extern int drm_i_have_hw_lock(struct file *filp);
+extern int drm_kernel_take_hw_lock(struct file *filp);
/* Buffer management support (drm_bufs.h) */
extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index a6828cc14e5..c11345856ff 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
list_for_each(list, &dev->maplist->head) {
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
if (entry->map && map->type == entry->map->type &&
- entry->map->offset == map->offset) {
+ ((entry->map->offset == map->offset) ||
+ (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
return entry;
}
}
@@ -180,8 +181,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
if (map->type == _DRM_REGISTERS)
map->handle = ioremap(map->offset, map->size);
break;
-
case _DRM_SHM:
+ list = drm_find_matching_map(dev, map);
+ if (list != NULL) {
+ if(list->map->size != map->size) {
+ DRM_DEBUG("Matching maps of type %d with "
+ "mismatched sizes, (%ld vs %ld)\n",
+ map->type, map->size, list->map->size);
+ list->map->size = map->size;
+ }
+
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ *maplist = list;
+ return 0;
+ }
map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
@@ -200,15 +213,45 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */
}
break;
- case _DRM_AGP:
- if (drm_core_has_AGP(dev)) {
+ case _DRM_AGP: {
+ drm_agp_mem_t *entry;
+ int valid = 0;
+
+ if (!drm_core_has_AGP(dev)) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
#ifdef __alpha__
- map->offset += dev->hose->mem_space->start;
+ map->offset += dev->hose->mem_space->start;
#endif
- map->offset += dev->agp->base;
- map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+ /* Note: dev->agp->base may actually be 0 when the DRM
+ * is not in control of AGP space. But if user space is
+ * it should already have added the AGP base itself.
+ */
+ map->offset += dev->agp->base;
+ map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+
+ /* This assumes the DRM is in total control of AGP space.
+ * It's not always the case as AGP can be in the control
+ * of user space (i.e. i810 driver). So this loop will get
+ * skipped and we double check that dev->agp->memory is
+ * actually set as well as being invalid before EPERM'ing
+ */
+ for (entry = dev->agp->memory; entry; entry = entry->next) {
+ if ((map->offset >= entry->bound) &&
+ (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
+ valid = 1;
+ break;
+ }
}
+ if (dev->agp->memory && !valid) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EPERM;
+ }
+ DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
+
break;
+ }
case _DRM_SCATTER_GATHER:
if (!dev->sg) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
@@ -267,7 +310,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
*maplist = list;
return 0;
-}
+ }
int drm_addmap(drm_device_t * dev, unsigned int offset,
unsigned int size, drm_map_type_t type,
@@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
{
drm_device_dma_t *dma = dev->dma;
drm_buf_entry_t *entry;
+ drm_agp_mem_t *agp_entry;
drm_buf_t *buf;
unsigned long offset;
unsigned long agp_offset;
@@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
int page_order;
int total;
int byte_count;
- int i;
+ int i, valid;
drm_buf_t **temp_buflist;
if (!dma)
@@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
if (dev->queue_count)
return -EBUSY; /* Not while in use */
+ /* Make sure buffers are located in AGP memory that we own */
+ valid = 0;
+ for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) {
+ if ((agp_offset >= agp_entry->bound) &&
+ (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
+ valid = 1;
+ break;
+ }
+ }
+ if (dev->agp->memory && !valid) {
+ DRM_DEBUG("zone invalid\n");
+ return -EINVAL;
+ }
spin_lock(&dev->count_lock);
if (dev->buf_use) {
spin_unlock(&dev->count_lock);
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 892db709698..32ed19c9ec1 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -65,7 +65,7 @@ int drm_dma_setup(drm_device_t * dev)
* \param dev DRM device.
*
* Free all pages associated with DMA buffers, the buffers and pages lists, and
- * finally the the drm_device::dma structure itself.
+ * finally the drm_device::dma structure itself.
*/
void drm_dma_takedown(drm_device_t * dev)
{
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index f5b9b2480c1..8e77b7ed0f4 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -15,8 +15,6 @@
* #define DRIVER_DESC "Matrox G200/G400"
* #define DRIVER_DATE "20001127"
*
- * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls )
- *
* #define drm_x mga_##x
* \endcode
*/
@@ -120,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
-#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
+#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
/**
* Take down the DRM device.
@@ -496,11 +494,14 @@ int drm_ioctl(struct inode *inode, struct file *filp,
(long)old_encode_dev(priv->head->device),
priv->authenticated);
- if (nr < DRIVER_IOCTL_COUNT)
- ioctl = &drm_ioctls[nr];
- else if ((nr >= DRM_COMMAND_BASE)
- && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
+ if ((nr >= DRM_CORE_IOCTL_COUNT) &&
+ ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
+ goto err_i1;
+ if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
+ (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+ else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
+ ioctl = &drm_ioctls[nr];
else
goto err_i1;
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 898f47dafec..3b159cab3bc 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -46,6 +46,7 @@ static int drm_setup(drm_device_t * dev)
drm_local_map_t *map;
int i;
int ret;
+ u32 sareapage;
if (dev->driver->firstopen) {
ret = dev->driver->firstopen(dev);
@@ -56,7 +57,8 @@ static int drm_setup(drm_device_t * dev)
dev->magicfree.next = NULL;
/* prebuild the SAREA */
- i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
+ sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
+ i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
if (i != 0)
return i;
@@ -84,7 +86,7 @@ static int drm_setup(drm_device_t * dev)
INIT_LIST_HEAD(&dev->ctxlist->head);
dev->vmalist = NULL;
- dev->sigdata.lock = dev->lock.hw_lock = NULL;
+ dev->sigdata.lock = NULL;
init_waitqueue_head(&dev->lock.lock_queue);
dev->queue_count = 0;
dev->queue_reserved = 0;
@@ -354,58 +356,56 @@ int drm_release(struct inode *inode, struct file *filp)
current->pid, (long)old_encode_dev(priv->head->device),
dev->open_count);
- if (priv->lock_count && dev->lock.hw_lock &&
- _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
- dev->lock.filp == filp) {
- DRM_DEBUG("File %p released, freeing lock for context %d\n",
- filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
- if (dev->driver->reclaim_buffers_locked)
+ if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
+ if (drm_i_have_hw_lock(filp)) {
dev->driver->reclaim_buffers_locked(dev, filp);
-
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
- /* FIXME: may require heavy-handed reset of
- hardware at this point, possibly
- processed via a callback to the X
- server. */
- } else if (dev->driver->reclaim_buffers_locked && priv->lock_count
- && dev->lock.hw_lock) {
- /* The lock is required to reclaim buffers */
- DECLARE_WAITQUEUE(entry, current);
-
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- if (!dev->lock.hw_lock) {
- /* Device has been unregistered */
- retcode = -EINTR;
- break;
+ } else {
+ unsigned long _end=jiffies + 3*DRM_HZ;
+ int locked = 0;
+
+ drm_idlelock_take(&dev->lock);
+
+ /*
+ * Wait for a while.
+ */
+
+ do{
+ spin_lock(&dev->lock.spinlock);
+ locked = dev->lock.idle_has_lock;
+ spin_unlock(&dev->lock.spinlock);
+ if (locked)
+ break;
+ schedule();
+ } while (!time_after_eq(jiffies, _end));
+
+ if (!locked) {
+ DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
+ "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
+ "\tI will go on reclaiming the buffers anyway.\n");
}
- if (drm_lock_take(&dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- dev->lock.filp = filp;
- dev->lock.lock_time = jiffies;
- atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
- break; /* Got lock */
- }
- /* Contention */
- schedule();
- if (signal_pending(current)) {
- retcode = -ERESTARTSYS;
- break;
- }
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- if (!retcode) {
+
dev->driver->reclaim_buffers_locked(dev, filp);
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT);
+ drm_idlelock_release(&dev->lock);
}
}
+ if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
+
+ drm_idlelock_take(&dev->lock);
+ dev->driver->reclaim_buffers_idlelocked(dev, filp);
+ drm_idlelock_release(&dev->lock);
+
+ }
+
+ if (drm_i_have_hw_lock(filp)) {
+ DRM_DEBUG("File %p released, freeing lock for context %d\n",
+ filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+ drm_lock_free(&dev->lock,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ }
+
+
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
!dev->driver->reclaim_buffers_locked) {
dev->driver->reclaim_buffers(dev, filp);
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
index a0b2d6802ae..31acb621dcc 100644
--- a/drivers/char/drm/drm_hashtab.c
+++ b/drivers/char/drm/drm_hashtab.c
@@ -43,7 +43,16 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
ht->size = 1 << order;
ht->order = order;
ht->fill = 0;
- ht->table = vmalloc(ht->size*sizeof(*ht->table));
+ ht->table = NULL;
+ ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE);
+ if (!ht->use_vmalloc) {
+ ht->table = drm_calloc(ht->size, sizeof(*ht->table),
+ DRM_MEM_HASHTAB);
+ }
+ if (!ht->table) {
+ ht->use_vmalloc = 1;
+ ht->table = vmalloc(ht->size*sizeof(*ht->table));
+ }
if (!ht->table) {
DRM_ERROR("Out of memory for hash table\n");
return -ENOMEM;
@@ -183,7 +192,11 @@ int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
void drm_ht_remove(drm_open_hash_t *ht)
{
if (ht->table) {
- vfree(ht->table);
+ if (ht->use_vmalloc)
+ vfree(ht->table);
+ else
+ drm_free(ht->table, ht->size * sizeof(*ht->table),
+ DRM_MEM_HASHTAB);
ht->table = NULL;
}
}
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
index 40afec05bff..613091c970a 100644
--- a/drivers/char/drm/drm_hashtab.h
+++ b/drivers/char/drm/drm_hashtab.h
@@ -47,6 +47,7 @@ typedef struct drm_open_hash{
unsigned int order;
unsigned int fill;
struct hlist_head *table;
+ int use_vmalloc;
} drm_open_hash_t;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 9d00c51fe2c..2e75331fd83 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -424,7 +424,7 @@ static void drm_locked_tasklet_func(unsigned long data)
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
if (!dev->locked_tasklet_func ||
- !drm_lock_take(&dev->lock.hw_lock->lock,
+ !drm_lock_take(&dev->lock,
DRM_KERNEL_CONTEXT)) {
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
return;
@@ -435,7 +435,7 @@ static void drm_locked_tasklet_func(unsigned long data)
dev->locked_tasklet_func(dev);
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ drm_lock_free(&dev->lock,
DRM_KERNEL_CONTEXT);
dev->locked_tasklet_func = NULL;
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index e9993ba461a..befd1af19df 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -35,9 +35,6 @@
#include "drmP.h"
-static int drm_lock_transfer(drm_device_t * dev,
- __volatile__ unsigned int *lock,
- unsigned int context);
static int drm_notifier(void *priv);
/**
@@ -80,6 +77,9 @@ int drm_lock(struct inode *inode, struct file *filp,
return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry);
+ spin_lock(&dev->lock.spinlock);
+ dev->lock.user_waiters++;
+ spin_unlock(&dev->lock.spinlock);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) {
@@ -87,7 +87,7 @@ int drm_lock(struct inode *inode, struct file *filp,
ret = -EINTR;
break;
}
- if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) {
+ if (drm_lock_take(&dev->lock, lock.context)) {
dev->lock.filp = filp;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
@@ -101,12 +101,14 @@ int drm_lock(struct inode *inode, struct file *filp,
break;
}
}
+ spin_lock(&dev->lock.spinlock);
+ dev->lock.user_waiters--;
+ spin_unlock(&dev->lock.spinlock);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
- DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
- if (ret)
- return ret;
+ DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
+ if (ret) return ret;
sigemptyset(&dev->sigmask);
sigaddset(&dev->sigmask, SIGSTOP);
@@ -127,14 +129,12 @@ int drm_lock(struct inode *inode, struct file *filp,
}
}
- /* dev->driver->kernel_context_switch isn't used by any of the x86
- * drivers but is used by the Sparc driver.
- */
if (dev->driver->kernel_context_switch &&
dev->last_context != lock.context) {
dev->driver->kernel_context_switch(dev, dev->last_context,
lock.context);
}
+
return 0;
}
@@ -184,12 +184,8 @@ int drm_unlock(struct inode *inode, struct file *filp,
if (dev->driver->kernel_context_switch_unlock)
dev->driver->kernel_context_switch_unlock(dev);
else {
- drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT);
-
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
+ if (drm_lock_free(&dev->lock,lock.context)) {
+ /* FIXME: Should really bail out here. */
}
}
@@ -206,18 +202,26 @@ int drm_unlock(struct inode *inode, struct file *filp,
*
* Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
*/
-int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+int drm_lock_take(drm_lock_data_t *lock_data,
+ unsigned int context)
{
unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+ spin_lock(&lock_data->spinlock);
do {
old = *lock;
if (old & _DRM_LOCK_HELD)
new = old | _DRM_LOCK_CONT;
- else
- new = context | _DRM_LOCK_HELD;
+ else {
+ new = context | _DRM_LOCK_HELD |
+ ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
+ _DRM_LOCK_CONT : 0);
+ }
prev = cmpxchg(lock, old, new);
} while (prev != old);
+ spin_unlock(&lock_data->spinlock);
+
if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) {
if (context != DRM_KERNEL_CONTEXT) {
@@ -227,7 +231,8 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
return 0;
}
}
- if (new == (context | _DRM_LOCK_HELD)) {
+
+ if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
/* Have lock */
return 1;
}
@@ -246,13 +251,13 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
* Resets the lock file pointer.
* Marks the lock as held by the given context, via the \p cmpxchg instruction.
*/
-static int drm_lock_transfer(drm_device_t * dev,
- __volatile__ unsigned int *lock,
+static int drm_lock_transfer(drm_lock_data_t *lock_data,
unsigned int context)
{
unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
- dev->lock.filp = NULL;
+ lock_data->filp = NULL;
do {
old = *lock;
new = context | _DRM_LOCK_HELD;
@@ -272,23 +277,32 @@ static int drm_lock_transfer(drm_device_t * dev,
* Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
* waiting on the lock queue.
*/
-int drm_lock_free(drm_device_t * dev,
- __volatile__ unsigned int *lock, unsigned int context)
+int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context)
{
unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ spin_lock(&lock_data->spinlock);
+ if (lock_data->kernel_waiters != 0) {
+ drm_lock_transfer(lock_data, 0);
+ lock_data->idle_has_lock = 1;
+ spin_unlock(&lock_data->spinlock);
+ return 1;
+ }
+ spin_unlock(&lock_data->spinlock);
- dev->lock.filp = NULL;
do {
old = *lock;
- new = 0;
+ new = _DRM_LOCKING_CONTEXT(old);
prev = cmpxchg(lock, old, new);
} while (prev != old);
+
if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
DRM_ERROR("%d freed heavyweight lock held by %d\n",
context, _DRM_LOCKING_CONTEXT(old));
return 1;
}
- wake_up_interruptible(&dev->lock.lock_queue);
+ wake_up_interruptible(&lock_data->lock_queue);
return 0;
}
@@ -322,3 +336,67 @@ static int drm_notifier(void *priv)
} while (prev != old);
return 0;
}
+
+/**
+ * This function returns immediately and takes the hw lock
+ * with the kernel context if it is free, otherwise it gets the highest priority when and if
+ * it is eventually released.
+ *
+ * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held
+ * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause
+ * a deadlock, which is why the "idlelock" was invented).
+ *
+ * This should be sufficient to wait for GPU idle without
+ * having to worry about starvation.
+ */
+
+void drm_idlelock_take(drm_lock_data_t *lock_data)
+{
+ int ret = 0;
+
+ spin_lock(&lock_data->spinlock);
+ lock_data->kernel_waiters++;
+ if (!lock_data->idle_has_lock) {
+
+ spin_unlock(&lock_data->spinlock);
+ ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
+ spin_lock(&lock_data->spinlock);
+
+ if (ret == 1)
+ lock_data->idle_has_lock = 1;
+ }
+ spin_unlock(&lock_data->spinlock);
+}
+EXPORT_SYMBOL(drm_idlelock_take);
+
+void drm_idlelock_release(drm_lock_data_t *lock_data)
+{
+ unsigned int old, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ spin_lock(&lock_data->spinlock);
+ if (--lock_data->kernel_waiters == 0) {
+ if (lock_data->idle_has_lock) {
+ do {
+ old = *lock;
+ prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT);
+ } while (prev != old);
+ wake_up_interruptible(&lock_data->lock_queue);
+ lock_data->idle_has_lock = 0;
+ }
+ }
+ spin_unlock(&lock_data->spinlock);
+}
+EXPORT_SYMBOL(drm_idlelock_release);
+
+
+int drm_i_have_hw_lock(struct file *filp)
+{
+ DRM_DEVICE;
+
+ return (priv->lock_count && dev->lock.hw_lock &&
+ _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
+ dev->lock.filp == filp);
+}
+
+EXPORT_SYMBOL(drm_i_have_hw_lock);
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 9b46b85027d..2ec1d9f2626 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -274,7 +274,6 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
return drm_mm_create_tail_node(mm, start, size);
}
-EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm)
{
@@ -295,4 +294,3 @@ void drm_mm_takedown(drm_mm_t * mm)
drm_free(entry, sizeof(*entry), DRM_MEM_MM);
}
-EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
index 2908b72daa6..0fe7b449792 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -70,9 +70,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#endif
-/** Task queue handler arguments */
-#define DRM_TASKQUEUE_ARGS void *arg
-
/** For data going into the kernel through the ioctl argument */
#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \
if ( copy_from_user(&arg1, arg2, arg3) ) \
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index ad54b845978..31cdde83713 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -102,6 +102,7 @@
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
@@ -230,10 +231,10 @@
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
+ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0, 0, 0}
#define i810_PCI_IDS \
@@ -296,5 +297,6 @@
{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 7fd0da71214..b204498d1a2 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -72,7 +72,7 @@ static struct drm_proc_list {
#endif
};
-#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
/**
* Initialize the DRI proc filesystem for a device.
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 120d10256fe..19408adcc77 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
spin_lock_init(&dev->count_lock);
spin_lock_init(&dev->drw_lock);
spin_lock_init(&dev->tasklet_lock);
+ spin_lock_init(&dev->lock.spinlock);
init_timer(&dev->timer);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex);
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 54a63284895..b5c5b9fa84c 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -41,6 +41,30 @@
static void drm_vm_open(struct vm_area_struct *vma);
static void drm_vm_close(struct vm_area_struct *vma);
+static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
+{
+ pgprot_t tmp = vm_get_page_prot(vma->vm_flags);
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) {
+ pgprot_val(tmp) |= _PAGE_PCD;
+ pgprot_val(tmp) &= ~_PAGE_PWT;
+ }
+#elif defined(__powerpc__)
+ pgprot_val(tmp) |= _PAGE_NO_CACHE;
+ if (map_type == _DRM_REGISTERS)
+ pgprot_val(tmp) |= _PAGE_GUARDED;
+#endif
+#if defined(__ia64__)
+ if (efi_range_is_wc(vma->vm_start, vma->vm_end -
+ vma->vm_start))
+ tmp = pgprot_writecombine(tmp);
+ else
+ tmp = pgprot_noncached(tmp);
+#endif
+ return tmp;
+}
+
/**
* \c nopage method for AGP virtual memory.
*
@@ -133,7 +157,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
* \param address access address.
* \return pointer to the page structure.
*
- * Get the the mapping, find the real physical page to map, get the page, and
+ * Get the mapping, find the real physical page to map, get the page, and
* return it.
*/
static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
@@ -151,8 +175,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
offset = address - vma->vm_start;
i = (unsigned long)map->handle + offset;
- page = (map->type == _DRM_CONSISTENT) ?
- virt_to_page((void *)i) : vmalloc_to_page((void *)i);
+ page = vmalloc_to_page((void *)i);
if (!page)
return NOPAGE_SIGBUS;
get_page(page);
@@ -389,7 +412,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {
* Create a new drm_vma_entry structure as the \p vma private data entry and
* add it to drm_device::vmalist.
*/
-static void drm_vm_open(struct vm_area_struct *vma)
+static void drm_vm_open_locked(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev;
@@ -401,15 +424,23 @@ static void drm_vm_open(struct vm_area_struct *vma)
vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) {
- mutex_lock(&dev->struct_mutex);
vma_entry->vma = vma;
vma_entry->next = dev->vmalist;
vma_entry->pid = current->pid;
dev->vmalist = vma_entry;
- mutex_unlock(&dev->struct_mutex);
}
}
+static void drm_vm_open(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->head->dev;
+
+ mutex_lock(&dev->struct_mutex);
+ drm_vm_open_locked(vma);
+ mutex_unlock(&dev->struct_mutex);
+}
+
/**
* \c close method for all virtual memory types.
*
@@ -460,7 +491,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
drm_device_dma_t *dma;
unsigned long length = vma->vm_end - vma->vm_start;
- lock_kernel();
dev = priv->head->dev;
dma = dev->dma;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -468,10 +498,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
- unlock_kernel();
return -EINVAL;
}
- unlock_kernel();
if (!capable(CAP_SYS_ADMIN) &&
(dma->flags & _DRM_DMA_USE_PCI_RO)) {
@@ -494,7 +522,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
+ drm_vm_open_locked(vma);
return 0;
}
@@ -529,7 +557,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
* according to the mapping type and remaps the pages. Finally sets the file
* pointer and calls vm_open().
*/
-int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
@@ -565,7 +593,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
return -EPERM;
/* Check for valid size. */
- if (map->size != vma->vm_end - vma->vm_start)
+ if (map->size < vma->vm_end - vma->vm_start)
return -EINVAL;
if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
@@ -600,37 +628,16 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
/* fall through to _DRM_FRAME_BUFFER... */
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
-#if defined(__i386__) || defined(__x86_64__)
- if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
- pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
- }
-#elif defined(__powerpc__)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
- if (map->type == _DRM_REGISTERS)
- pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED;
-#endif
- vma->vm_flags |= VM_IO; /* not in core dump */
-#if defined(__ia64__)
- if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
- vma->vm_page_prot =
- pgprot_writecombine(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
offset = dev->driver->get_reg_ofs(dev);
+ vma->vm_flags |= VM_IO; /* not in core dump */
+ vma->vm_page_prot = drm_io_prot(map->type, vma);
#ifdef __sparc__
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
-#else
- if (io_remap_pfn_range(vma, vma->vm_start,
- (map->offset + offset) >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
-#endif
return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n",
@@ -638,10 +645,15 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_start, vma->vm_end, map->offset + offset);
vma->vm_ops = &drm_vm_ops;
break;
- case _DRM_SHM:
case _DRM_CONSISTENT:
- /* Consistent memory is really like shared memory. It's only
- * allocate in a different way */
+ /* Consistent memory is really like shared memory. But
+ * it's allocated in a different way, so avoid nopage */
+ if (remap_pfn_range(vma, vma->vm_start,
+ page_to_pfn(virt_to_page(map->handle)),
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ /* fall through to _DRM_SHM */
+ case _DRM_SHM:
vma->vm_ops = &drm_vm_shm_ops;
vma->vm_private_data = (void *)map;
/* Don't let this area swap. Change when
@@ -659,8 +671,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
+ drm_vm_open_locked(vma);
return 0;
}
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ int ret;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_mmap_locked(filp, vma);
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
EXPORT_SYMBOL(drm_mmap);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 9354ce3b009..1ba15d9a171 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -34,7 +34,8 @@
#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
dev->pci_device == 0x2982 || \
dev->pci_device == 0x2992 || \
- dev->pci_device == 0x29A2)
+ dev->pci_device == 0x29A2 || \
+ dev->pci_device == 0x2A02)
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index db5a60450e6..1014602c43a 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -560,9 +560,10 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
if (dev_priv->is_pci) {
#endif
dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
+ dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
dev_priv->gart_info.addr = NULL;
dev_priv->gart_info.bus_addr = 0;
- dev_priv->gart_info.is_pcie = 0;
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
DRM_ERROR("failed to init PCI GART!\n");
dev->dev_private = (void *)dev_priv;
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index f1efb49de8d..9086835686d 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -383,6 +383,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
#define R128_PERFORMANCE_BOXES 0
+#define R128_PCIGART_TABLE_SIZE 32768
+
#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index a881f96c983..ecda760ae8c 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -293,7 +293,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0
# define R300_PVS_CNTL_1_POS_END_SHIFT 10
# define R300_PVS_CNTL_1_PROGRAM_END_SHIFT 20
-/* Addresses are relative the the vertex program parameters area. */
+/* Addresses are relative to the vertex program parameters area. */
#define R300_VAP_PVS_CNTL_2 0x22D4
# define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
# define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT 16
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5ed96568829..68338389d83 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -830,6 +830,15 @@ static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
return RADEON_READ(RADEON_PCIE_DATA);
}
+static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
+{
+ u32 ret;
+ RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f);
+ ret = RADEON_READ(RADEON_IGPGART_DATA);
+ RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f);
+ return ret;
+}
+
#if RADEON_FIFO_DEBUG
static void radeon_status(drm_radeon_private_t * dev_priv)
{
@@ -1267,7 +1276,44 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
}
}
-/* Enable or disable PCI-E GART on the chip */
+/* Enable or disable IGP GART on the chip */
+static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
+{
+ u32 temp, tmp;
+
+ tmp = RADEON_READ(RADEON_AIC_CNTL);
+ if (on) {
+ DRM_DEBUG("programming igpgart %08X %08lX %08X\n",
+ dev_priv->gart_vm_start,
+ (long)dev_priv->gart_info.bus_addr,
+ dev_priv->gart_size);
+
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR,
+ dev_priv->gart_info.bus_addr);
+
+ temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp);
+
+ RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
+ dev_priv->gart_size = 32*1024*1024;
+ RADEON_WRITE(RADEON_MC_AGP_LOCATION,
+ (((dev_priv->gart_vm_start - 1 +
+ dev_priv->gart_size) & 0xffff0000) |
+ (dev_priv->gart_vm_start >> 16)));
+
+ temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp);
+
+ RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1);
+ RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0);
+ }
+}
+
static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -1302,6 +1348,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp;
+ if (dev_priv->flags & RADEON_IS_IGPGART) {
+ radeon_set_igpgart(dev_priv, on);
+ return;
+ }
+
if (dev_priv->flags & RADEON_IS_PCIE) {
radeon_set_pciegart(dev_priv, on);
return;
@@ -1560,8 +1611,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
if (dev_priv->flags & RADEON_IS_AGP) {
base = dev->agp->base;
/* Check if valid */
- if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
- base < (dev_priv->fb_location + dev_priv->fb_size)) {
+ if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
+ base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
dev->agp->base);
base = 0;
@@ -1571,8 +1622,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
if (base == 0) {
base = dev_priv->fb_location + dev_priv->fb_size;
- if (((base + dev_priv->gart_size) & 0xfffffffful)
- < base)
+ if (base < dev_priv->fb_location ||
+ ((base + dev_priv->gart_size) & 0xfffffffful) < base)
base = dev_priv->fb_location
- dev_priv->gart_size;
}
@@ -1620,20 +1671,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
#endif
{
/* if we have an offset set from userspace */
- if (dev_priv->pcigart_offset) {
+ if (dev_priv->pcigart_offset_set) {
dev_priv->gart_info.bus_addr =
dev_priv->pcigart_offset + dev_priv->fb_location;
dev_priv->gart_info.mapping.offset =
dev_priv->gart_info.bus_addr;
dev_priv->gart_info.mapping.size =
- RADEON_PCIGART_TABLE_SIZE;
+ dev_priv->gart_info.table_size;
drm_core_ioremap(&dev_priv->gart_info.mapping, dev);
dev_priv->gart_info.addr =
dev_priv->gart_info.mapping.handle;
- dev_priv->gart_info.is_pcie =
- !!(dev_priv->flags & RADEON_IS_PCIE);
+ if (dev_priv->flags & RADEON_IS_PCIE)
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE;
+ else
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
dev_priv->gart_info.gart_table_location =
DRM_ATI_GART_FB;
@@ -1641,6 +1694,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
dev_priv->gart_info.addr,
dev_priv->pcigart_offset);
} else {
+ if (dev_priv->flags & RADEON_IS_IGPGART)
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP;
+ else
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
dev_priv->gart_info.gart_table_location =
DRM_ATI_GART_MAIN;
dev_priv->gart_info.addr = NULL;
@@ -1714,7 +1771,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
{
drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
- dev_priv->gart_info.addr = NULL;
+ dev_priv->gart_info.addr = 0;
}
}
/* only clear to the start of flags */
@@ -2222,6 +2279,8 @@ int radeon_driver_firstopen(struct drm_device *dev)
drm_local_map_t *map;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+
ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
drm_get_resource_len(dev, 2), _DRM_REGISTERS,
_DRM_READ_ONLY, &dev_priv->mmio);
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index 8d6350dd536..66c4b6fed04 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -707,6 +707,7 @@ typedef struct drm_radeon_setparam {
#define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */
#define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */
#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */
+#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */
/* 1.14: Clients can allocate/free a surface
*/
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 8b105f1460a..54f49ef4bef 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -95,9 +95,11 @@
* 1.24- Add general-purpose packet for manipulating scratch registers (r300)
* 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
* new packet type)
+ * 1.26- Add support for variable size PCI(E) gart aperture
+ * 1.27- Add support for IGP GART
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 25
+#define DRIVER_MINOR 27
#define DRIVER_PATCHLEVEL 0
/*
@@ -143,6 +145,7 @@ enum radeon_chip_flags {
RADEON_IS_PCIE = 0x00200000UL,
RADEON_NEW_MEMMAP = 0x00400000UL,
RADEON_IS_PCI = 0x00800000UL,
+ RADEON_IS_IGPGART = 0x01000000UL,
};
#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \
@@ -240,7 +243,6 @@ typedef struct drm_radeon_private {
int do_boxes;
int page_flipping;
- int current_page;
u32 color_fmt;
unsigned int front_offset;
@@ -280,6 +282,7 @@ typedef struct drm_radeon_private {
struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
unsigned long pcigart_offset;
+ unsigned int pcigart_offset_set;
drm_ati_pcigart_info gart_info;
u32 scratch_ages[5];
@@ -432,6 +435,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_PCIE_TX_GART_END_LO 0x16
#define RADEON_PCIE_TX_GART_END_HI 0x17
+#define RADEON_IGPGART_INDEX 0x168
+#define RADEON_IGPGART_DATA 0x16c
+#define RADEON_IGPGART_UNK_18 0x18
+#define RADEON_IGPGART_CTRL 0x2b
+#define RADEON_IGPGART_BASE_ADDR 0x2c
+#define RADEON_IGPGART_FLUSH 0x2e
+#define RADEON_IGPGART_ENABLE 0x38
+#define RADEON_IGPGART_UNK_39 0x39
+
#define RADEON_MPP_TB_CONFIG 0x01c0
#define RADEON_MEM_CNTL 0x0140
#define RADEON_MEM_SDRAM_MODE_REG 0x0158
@@ -964,6 +976,14 @@ do { \
RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \
} while (0)
+#define RADEON_WRITE_IGPGART( addr, val ) \
+do { \
+ RADEON_WRITE( RADEON_IGPGART_INDEX, \
+ ((addr) & 0x7f) | (1 << 8)); \
+ RADEON_WRITE( RADEON_IGPGART_DATA, (val) ); \
+ RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f ); \
+} while (0)
+
#define RADEON_WRITE_PCIE( addr, val ) \
do { \
RADEON_WRITE8( RADEON_PCIE_INDEX, \
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 938eccb78cc..98c5f1d3a8e 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -773,7 +773,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv,
RADEON_GMC_SRC_DATATYPE_COLOR |
RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
- if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+ if (dev_priv->sarea_priv->pfCurrentPage == 1) {
OUT_RING(dev_priv->front_pitch_offset);
} else {
OUT_RING(dev_priv->back_pitch_offset);
@@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
dev_priv->stats.clears++;
- if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+ if (dev_priv->sarea_priv->pfCurrentPage == 1) {
unsigned int tmp = flags;
flags &= ~(RADEON_FRONT | RADEON_BACK);
@@ -1382,7 +1382,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
/* Make this work even if front & back are flipped:
*/
OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
- if (dev_priv->current_page == 0) {
+ if (dev_priv->sarea_priv->pfCurrentPage == 0) {
OUT_RING(dev_priv->back_pitch_offset);
OUT_RING(dev_priv->front_pitch_offset);
} else {
@@ -1416,12 +1416,12 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
- int offset = (dev_priv->current_page == 1)
+ int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
? dev_priv->front_offset : dev_priv->back_offset;
RING_LOCALS;
- DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
+ DRM_DEBUG("%s: pfCurrentPage=%d\n",
__FUNCTION__,
- dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
+ dev_priv->sarea_priv->pfCurrentPage);
/* Do some trivial performance monitoring...
*/
@@ -1449,8 +1449,8 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev)
* performing the swapbuffer ioctl.
*/
dev_priv->sarea_priv->last_frame++;
- dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
- 1 - dev_priv->current_page;
+ dev_priv->sarea_priv->pfCurrentPage =
+ 1 - dev_priv->sarea_priv->pfCurrentPage;
BEGIN_RING(2);
@@ -2152,24 +2152,10 @@ static int radeon_do_init_pageflip(drm_device_t * dev)
ADVANCE_RING();
dev_priv->page_flipping = 1;
- dev_priv->current_page = 0;
- dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
- return 0;
-}
-
-/* Called whenever a client dies, from drm_release.
- * NOTE: Lock isn't necessarily held when this is called!
- */
-static int radeon_do_cleanup_pageflip(drm_device_t * dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- if (dev_priv->current_page != 0)
- radeon_cp_dispatch_flip(dev);
+ if (dev_priv->sarea_priv->pfCurrentPage != 1)
+ dev_priv->sarea_priv->pfCurrentPage = 0;
- dev_priv->page_flipping = 0;
return 0;
}
@@ -3145,10 +3131,16 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
break;
case RADEON_SETPARAM_PCIGART_LOCATION:
dev_priv->pcigart_offset = sp.value;
+ dev_priv->pcigart_offset_set = 1;
break;
case RADEON_SETPARAM_NEW_MEMMAP:
dev_priv->new_memmap = sp.value;
break;
+ case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
+ dev_priv->gart_info.table_size = sp.value;
+ if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
+ dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+ break;
default:
DRM_DEBUG("Invalid parameter %d\n", sp.param);
return DRM_ERR(EINVAL);
@@ -3168,9 +3160,7 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_radeon_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
- radeon_do_cleanup_pageflip(dev);
- }
+ dev_priv->page_flipping = 0;
radeon_mem_release(filp, dev_priv->gart_heap);
radeon_mem_release(filp, dev_priv->fb_heap);
radeon_surfaces_release(filp, dev_priv);
@@ -3179,6 +3169,14 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
void radeon_driver_lastclose(drm_device_t * dev)
{
+ if (dev->dev_private) {
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if (dev_priv->sarea_priv &&
+ dev_priv->sarea_priv->pfCurrentPage != 0)
+ radeon_cp_dispatch_flip(dev);
+ }
+
radeon_do_release(dev);
}
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 3d5b3218b6f..690e0af8e7c 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -71,7 +71,7 @@ static struct drm_driver driver = {
.context_dtor = NULL,
.dma_quiescent = sis_idle,
.reclaim_buffers = NULL,
- .reclaim_buffers_locked = sis_reclaim_buffers_locked,
+ .reclaim_buffers_idlelocked = sis_reclaim_buffers_locked,
.lastclose = sis_lastclose,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index c0539c6299c..13a9c5ca459 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS)
break;
case VIA_DMA_INITIALIZED:
retcode = (dev_priv->ring.virtual_start != NULL) ?
- 0 : DRM_ERR(EFAULT);
+ 0 : DRM_ERR(EFAULT);
break;
default:
retcode = DRM_ERR(EINVAL);
@@ -432,56 +432,34 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
{
int paused, count;
volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
+ uint32_t reader,ptr;
+ paused = 0;
via_flush_write_combine();
- while (!*(via_get_dma(dev_priv) - 1)) ;
- *dev_priv->last_pause_ptr = pause_addr_lo;
+ (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
+ *paused_at = pause_addr_lo;
via_flush_write_combine();
-
- /*
- * The below statement is inserted to really force the flush.
- * Not sure it is needed.
- */
-
- while (!*dev_priv->last_pause_ptr) ;
+ (void) *paused_at;
+ reader = *(dev_priv->hw_addr_ptr);
+ ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
- while (!*dev_priv->last_pause_ptr) ;
- paused = 0;
- count = 20;
-
- while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ;
- if ((count <= 8) && (count >= 0)) {
- uint32_t rgtr, ptr;
- rgtr = *(dev_priv->hw_addr_ptr);
- ptr = ((volatile char *)dev_priv->last_pause_ptr -
- dev_priv->dma_ptr) + dev_priv->dma_offset +
- (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE;
- if (rgtr <= ptr) {
- DRM_ERROR
- ("Command regulator\npaused at count %d, address %x, "
- "while current pause address is %x.\n"
- "Please mail this message to "
- "<unichrome-devel@lists.sourceforge.net>\n", count,
- rgtr, ptr);
- }
+ if ((ptr - reader) <= dev_priv->dma_diff ) {
+ count = 10000000;
+ while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
}
if (paused && !no_pci_fire) {
- uint32_t rgtr, ptr;
- uint32_t ptr_low;
+ reader = *(dev_priv->hw_addr_ptr);
+ if ((ptr - reader) == dev_priv->dma_diff) {
- count = 1000000;
- while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY)
- && count--) ;
+ /*
+ * There is a concern that these writes may stall the PCI bus
+ * if the GPU is not idle. However, idling the GPU first
+ * doesn't make a difference.
+ */
- rgtr = *(dev_priv->hw_addr_ptr);
- ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
- dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
-
- ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ?
- ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0;
- if (rgtr <= ptr && rgtr >= ptr_low) {
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
@@ -494,6 +472,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
static int via_wait_idle(drm_via_private_t * dev_priv)
{
int count = 10000000;
+
+ while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--);
+
while (count-- && (VIA_READ(VIA_REG_STATUS) &
(VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
VIA_3D_ENG_BUSY))) ;
@@ -537,6 +518,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
uint32_t end_addr, end_addr_lo;
uint32_t command;
uint32_t agp_base;
+ uint32_t ptr;
+ uint32_t reader;
+ int count;
dev_priv->dma_low = 0;
@@ -554,7 +538,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
&pause_addr_hi, &pause_addr_lo, 1) - 1;
via_flush_write_combine();
- while (!*dev_priv->last_pause_ptr) ;
+ (void) *(volatile uint32_t *)dev_priv->last_pause_ptr;
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, command);
@@ -566,6 +550,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
VIA_READ(VIA_REG_TRANSPACE);
+
+ dev_priv->dma_diff = 0;
+
+ count = 10000000;
+ while (!(VIA_READ(0x41c) & 0x80000000) && count--);
+
+ reader = *(dev_priv->hw_addr_ptr);
+ ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+
+ /*
+ * This is the difference between where we tell the
+ * command reader to pause and where it actually pauses.
+ * This differs between hw implementation so we need to
+ * detect it.
+ */
+
+ dev_priv->dma_diff = ptr - reader;
}
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
@@ -592,7 +594,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
uint32_t pause_addr_lo, pause_addr_hi;
uint32_t jump_addr_lo, jump_addr_hi;
volatile uint32_t *last_pause_ptr;
- uint32_t dma_low_save1, dma_low_save2;
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
@@ -619,31 +620,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
&pause_addr_lo, 0);
*last_pause_ptr = pause_addr_lo;
- dma_low_save1 = dev_priv->dma_low;
-
- /*
- * Now, set a trap that will pause the regulator if it tries to rerun the old
- * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
- * and reissues the jump command over PCI, while the regulator has already taken the jump
- * and actually paused at the current buffer end).
- * There appears to be no other way to detect this condition, since the hw_addr_pointer
- * does not seem to get updated immediately when a jump occurs.
- */
- last_pause_ptr =
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) - 1;
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0);
- *last_pause_ptr = pause_addr_lo;
-
- dma_low_save2 = dev_priv->dma_low;
- dev_priv->dma_low = dma_low_save1;
- via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
- dev_priv->dma_low = dma_low_save2;
- via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
+ via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
}
+
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
{
via_cmdbuf_jump(dev_priv);
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index bb9dde8b191..2d4957ab256 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -52,7 +52,8 @@ static struct drm_driver driver = {
.dma_quiescent = via_driver_dma_quiescent,
.dri_library_name = dri_library_name,
.reclaim_buffers = drm_core_reclaim_buffers,
- .reclaim_buffers_locked = via_reclaim_buffers_locked,
+ .reclaim_buffers_locked = NULL,
+ .reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
.lastclose = via_lastclose,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 8b8778d4a42..b46ca8e6306 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,11 +29,11 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20061227"
+#define DRIVER_DATE "20070202"
#define DRIVER_MAJOR 2
#define DRIVER_MINOR 11
-#define DRIVER_PATCHLEVEL 0
+#define DRIVER_PATCHLEVEL 1
#include "via_verifier.h"
@@ -93,6 +93,7 @@ typedef struct drm_via_private {
unsigned long vram_offset;
unsigned long agp_offset;
drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
+ uint32_t dma_diff;
} drm_via_private_t;
enum via_family {
diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h
deleted file mode 100644
index d57efda57c7..00000000000
--- a/drivers/char/drm/via_mm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * 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 (including the
- * next paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS 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 _via_drm_mm_h_
-#define _via_drm_mm_h_
-
-typedef struct {
- unsigned int context;
- unsigned int size;
- unsigned long offset;
- unsigned long free;
-} drm_via_mm_t;
-
-typedef struct {
- unsigned int size;
- unsigned long handle;
- void *virtual;
-} drm_via_dma_t;
-
-#endif
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 3d7efc26aad..334ad5bbe6b 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -4,7 +4,6 @@
*/
#include <linux/module.h>
#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/capability.h>
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index db984e481d4..9b8278e1f4f 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -32,7 +32,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <asm/atarihw.h>
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index d8dbdb91623..abde6ddefe6 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -62,7 +62,6 @@
#include <linux/init.h> /* for __init, module_{init,exit} */
#include <linux/poll.h> /* for POLLIN, etc. */
#include <linux/dtlk.h> /* local header file for DoubleTalk values */
-#include <linux/smp_lock.h>
#ifdef TRACING
#define TRACE_TEXT(str) printk(str);
@@ -325,16 +324,22 @@ static int dtlk_release(struct inode *inode, struct file *file)
static int __init dtlk_init(void)
{
+ int err;
+
dtlk_port_lpc = 0;
dtlk_port_tts = 0;
dtlk_busy = 0;
dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
- if (dtlk_major == 0) {
+ if (dtlk_major < 0) {
printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
- return 0;
+ return dtlk_major;
+ }
+ err = dtlk_dev_probe();
+ if (err) {
+ unregister_chrdev(dtlk_major, "dtlk");
+ return err;
}
- if (dtlk_dev_probe() == 0)
- printk(", MAJOR %d\n", dtlk_major);
+ printk(", MAJOR %d\n", dtlk_major);
init_waitqueue_head(&dtlk_process_list);
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
index 77f58ed6d59..020011495d9 100644
--- a/drivers/char/ec3104_keyb.c
+++ b/drivers/char/ec3104_keyb.c
@@ -41,7 +41,6 @@
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/kbd_kern.h>
-#include <linux/smp_lock.h>
#include <linux/bitops.h>
#include <asm/keyboard.h>
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index de5be30484a..c6c56fb8ba5 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -949,7 +949,7 @@ static int block_til_ready(struct tty_struct *tty,
} /* End forever while */
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&ch->open_wait, &wait);
if (!tty_hung_up_p(filp))
ch->count++;
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 23b25ada65e..9e1fc02967f 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -12,7 +12,7 @@
*
* This driver allows use of the real time clock (built into
* nearly all computers) from user space. It exports the /dev/rtc
- * interface supporting various ioctl() and also the /proc/dev/rtc
+ * interface supporting various ioctl() and also the /proc/driver/rtc
* pseudo-file for status information.
*
* The ioctls can be used to set the interrupt behaviour where
@@ -207,7 +207,7 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf,
sizeof(unsigned long);
}
out:
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&gen_rtc_wait, &wait);
return retval;
@@ -377,7 +377,7 @@ static int gen_rtc_release(struct inode *inode, struct file *file)
#ifdef CONFIG_PROC_FS
/*
- * Info exported via "/proc/rtc".
+ * Info exported via "/proc/driver/rtc".
*/
static int gen_rtc_proc_output(char *buf)
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index ae76a9ffe89..f0e7263dfcd 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -44,7 +44,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/reboot.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index a0a88aa23f5..322bc5f7d86 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -47,8 +47,6 @@
#define HVC_MAJOR 229
#define HVC_MINOR 0
-#define TIMEOUT (10)
-
/*
* Wait this long per iteration while trying to push buffered data to the
* hypervisor before allowing the tty to complete a close operation.
@@ -104,16 +102,16 @@ static DEFINE_SPINLOCK(hvc_structs_lock);
/*
* This value is used to assign a tty->index value to a hvc_struct based
* upon order of exposure via hvc_probe(), when we can not match it to
- * a console canidate registered with hvc_instantiate().
+ * a console candidate registered with hvc_instantiate().
*/
static int last_hvc = -1;
/*
- * Do not call this function with either the hvc_strucst_lock or the hvc_struct
+ * Do not call this function with either the hvc_structs_lock or the hvc_struct
* lock held. If successful, this function increments the kobject reference
* count against the target hvc_struct so it should be released when finished.
*/
-struct hvc_struct *hvc_get_by_index(int index)
+static struct hvc_struct *hvc_get_by_index(int index)
{
struct hvc_struct *hp;
unsigned long flags;
@@ -152,7 +150,8 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
* hvc_console_setup() finds adapters.
*/
-void hvc_console_print(struct console *co, const char *b, unsigned count)
+static void hvc_console_print(struct console *co, const char *b,
+ unsigned count)
{
char c[N_OUTBUF] __ALIGNED__;
unsigned i = 0, n = 0;
@@ -162,7 +161,7 @@ void hvc_console_print(struct console *co, const char *b, unsigned count)
if (index >= MAX_NR_HVC_CONSOLES)
return;
- /* This console adapter was removed so it is not useable. */
+ /* This console adapter was removed so it is not usable. */
if (vtermnos[index] < 0)
return;
@@ -210,7 +209,7 @@ static int __init hvc_console_setup(struct console *co, char *options)
return 0;
}
-struct console hvc_con_driver = {
+static struct console hvc_con_driver = {
.name = "hvc",
.write = hvc_console_print,
.device = hvc_console_device,
@@ -220,7 +219,7 @@ struct console hvc_con_driver = {
};
/*
- * Early console initialization. Preceeds driver initialization.
+ * Early console initialization. Precedes driver initialization.
*
* (1) we are first, and the user specified another driver
* -- index will remain -1
@@ -257,7 +256,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
if (vtermnos[index] != -1)
return -1;
- /* make sure no no tty has been registerd in this index */
+ /* make sure no no tty has been registered in this index */
hp = hvc_get_by_index(index);
if (hp) {
kobject_put(&hp->kobj);
@@ -267,7 +266,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
vtermnos[index] = vtermno;
cons_ops[index] = ops;
- /* reserve all indices upto and including this index */
+ /* reserve all indices up to and including this index */
if (last_hvc < index)
last_hvc = index;
@@ -280,7 +279,6 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
return 0;
}
-EXPORT_SYMBOL(hvc_instantiate);
/* Wake the sleeping khvcd */
static void hvc_kick(void)
@@ -528,7 +526,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
/*
* This is actually a contract between the driver and the tty layer outlining
- * how much write room the driver can guarentee will be sent OR BUFFERED. This
+ * how much write room the driver can guarantee will be sent OR BUFFERED. This
* driver MUST honor the return value.
*/
static int hvc_write_room(struct tty_struct *tty)
@@ -550,6 +548,18 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
return hp->n_outbuf;
}
+/*
+ * timeout will vary between the MIN and MAX values defined here. By default
+ * and during console activity we will use a default MIN_TIMEOUT of 10. When
+ * the console is idle, we increase the timeout value on each pass through
+ * msleep until we reach the max. This may be noticeable as a brief (average
+ * one second) delay on the console before the console responds to input when
+ * there has been no input for some time.
+ */
+#define MIN_TIMEOUT (10)
+#define MAX_TIMEOUT (2000)
+static u32 timeout = MIN_TIMEOUT;
+
#define HVC_POLL_READ 0x00000001
#define HVC_POLL_WRITE 0x00000002
@@ -642,9 +652,14 @@ static int hvc_poll(struct hvc_struct *hp)
bail:
spin_unlock_irqrestore(&hp->lock, flags);
- if (read_total)
+ if (read_total) {
+ /* Activity is occurring, so reset the polling backoff value to
+ a minimum for performance. */
+ timeout = MIN_TIMEOUT;
+
tty_flip_buffer_push(tty);
-
+ }
+
return poll_mask;
}
@@ -688,8 +703,12 @@ int khvcd(void *unused)
if (!hvc_kicked) {
if (poll_mask == 0)
schedule();
- else
- msleep_interruptible(TIMEOUT);
+ else {
+ if (timeout < MAX_TIMEOUT)
+ timeout += (timeout >> 6) + 1;
+
+ msleep_interruptible(timeout);
+ }
}
__set_current_state(TASK_RUNNING);
} while (!kthread_should_stop());
@@ -773,7 +792,6 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
return hp;
}
-EXPORT_SYMBOL(hvc_alloc);
int __devexit hvc_remove(struct hvc_struct *hp)
{
@@ -794,7 +812,7 @@ int __devexit hvc_remove(struct hvc_struct *hp)
/*
* We 'put' the instance that was grabbed when the kobject instance
- * was intialized using kobject_init(). Let the last holder of this
+ * was initialized using kobject_init(). Let the last holder of this
* kobject cause it to be removed, which will probably be the tty_hangup
* below.
*/
@@ -809,11 +827,10 @@ int __devexit hvc_remove(struct hvc_struct *hp)
tty_hangup(tty);
return 0;
}
-EXPORT_SYMBOL(hvc_remove);
/* Driver initialization. Follow console initialization. This is where the TTY
* interfaces start to become available. */
-int __init hvc_init(void)
+static int __init hvc_init(void)
{
struct tty_driver *drv;
@@ -850,7 +867,7 @@ int __init hvc_init(void)
}
module_init(hvc_init);
-/* This isn't particularily necessary due to this being a console driver
+/* This isn't particularly necessary due to this being a console driver
* but it is nice to be thorough.
*/
static void __exit hvc_exit(void)
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index f144a947bd1..b37f1d5a5be 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -575,11 +575,11 @@ static int hvc_find_vtys(void)
(num_found >= VTTY_PORTS))
break;
- vtermno = get_property(vty, "reg", NULL);
+ vtermno = of_get_property(vty, "reg", NULL);
if (!vtermno)
continue;
- if (!device_is_compatible(vty, "IBM,iSeries-vty"))
+ if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
continue;
if (num_found == 0)
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index f9c00844d2b..79711aa4b41 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -153,11 +153,11 @@ static int hvc_find_vtys(void)
if (num_found >= MAX_NR_HVC_CONSOLES)
break;
- vtermno = get_property(vty, "reg", NULL);
+ vtermno = of_get_property(vty, "reg", NULL);
if (!vtermno)
continue;
- if (device_is_compatible(vty, "hvterm1")) {
+ if (of_device_is_compatible(vty, "hvterm1")) {
hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
++num_found;
}
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index 50315d6364f..d5a752da322 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -1279,8 +1279,8 @@ static int __init hvsi_console_init(void)
struct hvsi_struct *hp;
const uint32_t *vtermno, *irq;
- vtermno = get_property(vty, "reg", NULL);
- irq = get_property(vty, "interrupts", NULL);
+ vtermno = of_get_property(vty, "reg", NULL);
+ irq = of_get_property(vty, "interrupts", NULL);
if (!vtermno || !irq)
continue;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 5f3acd8e64b..7cda04b3353 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -91,3 +91,17 @@ config HW_RANDOM_OMAP
module will be called omap-rng.
If unsure, say Y.
+
+config HW_RANDOM_PASEMI
+ tristate "PA Semi HW Random Number Generator support"
+ depends on HW_RANDOM && PPC_PASEMI
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on PA6T-1682M processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pasemi-rng.
+
+ If unsure, say Y.
+
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c41fa19454e..c8b7300e2fb 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index cc1046e6ee0..4ae9811d1a6 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -24,10 +24,11 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/hw_random.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/hw_random.h>
+#include <linux/stop_machine.h>
#include <asm/io.h>
@@ -217,30 +218,117 @@ static struct hwrng intel_rng = {
.data_read = intel_rng_data_read,
};
+struct intel_rng_hw {
+ struct pci_dev *dev;
+ void __iomem *mem;
+ u8 bios_cntl_off;
+ u8 bios_cntl_val;
+ u8 fwh_dec_en1_off;
+ u8 fwh_dec_en1_val;
+};
-#ifdef CONFIG_SMP
-static char __initdata waitflag;
+static int __init intel_rng_hw_init(void *_intel_rng_hw)
+{
+ struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
+ u8 mfc, dvc;
+
+ /* interrupts disabled in stop_machine_run call */
+
+ if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->fwh_dec_en1_off,
+ intel_rng_hw->fwh_dec_en1_val |
+ FWH_F8_EN_MASK);
+ if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->bios_cntl_off,
+ intel_rng_hw->bios_cntl_val |
+ BIOS_CNTL_WRITE_ENABLE_MASK);
+
+ writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+ writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem);
+ mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
+ dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
+ writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+
+ if (!(intel_rng_hw->bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->bios_cntl_off,
+ intel_rng_hw->bios_cntl_val);
+ if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->fwh_dec_en1_off,
+ intel_rng_hw->fwh_dec_en1_val);
-static void __init intel_init_wait(void *unused)
+ if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
+ (dvc != INTEL_FWH_DEVICE_CODE_8M &&
+ dvc != INTEL_FWH_DEVICE_CODE_4M)) {
+ printk(KERN_ERR PFX "FWH not detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
+ struct pci_dev *dev)
{
- while (waitflag)
- cpu_relax();
+ intel_rng_hw->bios_cntl_val = 0xff;
+ intel_rng_hw->fwh_dec_en1_val = 0xff;
+ intel_rng_hw->dev = dev;
+
+ /* Check for Intel 82802 */
+ if (dev->device < 0x2640) {
+ intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
+ intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD;
+ } else {
+ intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
+ intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW;
+ }
+
+ pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off,
+ &intel_rng_hw->fwh_dec_en1_val);
+ pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off,
+ &intel_rng_hw->bios_cntl_val);
+
+ if ((intel_rng_hw->bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
+ == BIOS_CNTL_LOCK_ENABLE_MASK) {
+ static __initdata /*const*/ char warning[] =
+ KERN_WARNING PFX "Firmware space is locked read-only. "
+ KERN_WARNING PFX "If you can't or\n don't want to "
+ KERN_WARNING PFX "disable this in firmware setup, and "
+ KERN_WARNING PFX "if\n you are certain that your "
+ KERN_WARNING PFX "system has a functional\n RNG, try"
+ KERN_WARNING PFX "using the 'no_fwh_detect' option.\n";
+
+ if (no_fwh_detect)
+ return -ENODEV;
+ printk(warning);
+ return -EBUSY;
+ }
+
+ intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
+ if (intel_rng_hw->mem == NULL)
+ return -EBUSY;
+
+ return 0;
}
-#endif
+
static int __init mod_init(void)
{
int err = -ENODEV;
- unsigned i;
+ int i;
struct pci_dev *dev = NULL;
- void __iomem *mem;
- unsigned long flags;
- u8 bios_cntl_off, fwh_dec_en1_off;
- u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
- u8 hw_status, mfc, dvc;
+ void __iomem *mem = mem;
+ u8 hw_status;
+ struct intel_rng_hw *intel_rng_hw;
for (i = 0; !dev && pci_tbl[i].vendor; ++i)
- dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
+ dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device,
+ NULL);
if (!dev)
goto out; /* Device not found. */
@@ -250,39 +338,18 @@ static int __init mod_init(void)
goto fwh_done;
}
- /* Check for Intel 82802 */
- if (dev->device < 0x2640) {
- fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
- bios_cntl_off = BIOS_CNTL_REG_OLD;
- } else {
- fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
- bios_cntl_off = BIOS_CNTL_REG_NEW;
- }
-
- pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
- pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
-
- if ((bios_cntl_val &
- (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
- == BIOS_CNTL_LOCK_ENABLE_MASK) {
- static __initdata /*const*/ char warning[] =
- KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
- KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
- KERN_WARNING PFX "you are certain that your system has a functional\n"
- KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
-
+ intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL);
+ if (!intel_rng_hw) {
pci_dev_put(dev);
- if (no_fwh_detect)
- goto fwh_done;
- printk(warning);
- err = -EBUSY;
goto out;
}
- mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
- if (mem == NULL) {
+ err = intel_init_hw_struct(intel_rng_hw, dev);
+ if (err) {
pci_dev_put(dev);
- err = -EBUSY;
+ kfree(intel_rng_hw);
+ if (err == -ENODEV)
+ goto fwh_done;
goto out;
}
@@ -290,59 +357,18 @@ static int __init mod_init(void)
* Since the BIOS code/data is going to disappear from its normal
* location with the Read ID command, all activity on the system
* must be stopped until the state is back to normal.
+ *
+ * Use stop_machine_run because IPIs can be blocked by disabling
+ * interrupts.
*/
-#ifdef CONFIG_SMP
- set_mb(waitflag, 1);
- if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
- set_mb(waitflag, 0);
- pci_dev_put(dev);
- printk(KERN_ERR PFX "cannot run on all processors\n");
- err = -EAGAIN;
- goto err_unmap;
- }
-#endif
- local_irq_save(flags);
-
- if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
- pci_write_config_byte(dev,
- fwh_dec_en1_off,
- fwh_dec_en1_val | FWH_F8_EN_MASK);
- if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
- pci_write_config_byte(dev,
- bios_cntl_off,
- bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
-
- writeb(INTEL_FWH_RESET_CMD, mem);
- writeb(INTEL_FWH_READ_ID_CMD, mem);
- mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
- dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
- writeb(INTEL_FWH_RESET_CMD, mem);
-
- if (!(bios_cntl_val &
- (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
- pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
- if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
- pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
-
- local_irq_restore(flags);
-#ifdef CONFIG_SMP
- /* Tell other CPUs to resume. */
- set_mb(waitflag, 0);
-#endif
-
- iounmap(mem);
+ err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS);
pci_dev_put(dev);
-
- if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
- (dvc != INTEL_FWH_DEVICE_CODE_8M &&
- dvc != INTEL_FWH_DEVICE_CODE_4M)) {
- printk(KERN_ERR PFX "FWH not detected\n");
- err = -ENODEV;
+ iounmap(intel_rng_hw->mem);
+ kfree(intel_rng_hw);
+ if (err)
goto out;
- }
fwh_done:
-
err = -ENOMEM;
mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
if (!mem)
@@ -352,22 +378,21 @@ fwh_done:
/* Check for Random Number Generator */
err = -ENODEV;
hw_status = hwstatus_get(mem);
- if ((hw_status & INTEL_RNG_PRESENT) == 0)
- goto err_unmap;
+ if ((hw_status & INTEL_RNG_PRESENT) == 0) {
+ iounmap(mem);
+ goto out;
+ }
printk(KERN_INFO "Intel 82802 RNG detected\n");
err = hwrng_register(&intel_rng);
if (err) {
printk(KERN_ERR PFX "RNG registering failed (%d)\n",
err);
- goto err_unmap;
+ iounmap(mem);
}
out:
return err;
-err_unmap:
- iounmap(mem);
- goto out;
}
static void __exit mod_exit(void)
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
new file mode 100644
index 00000000000..fa6040b6c8f
--- /dev/null
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip rng
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+
+#define SDCRNG_CTL_REG 0x00
+#define SDCRNG_CTL_FVLD_M 0x0000f000
+#define SDCRNG_CTL_FVLD_S 12
+#define SDCRNG_CTL_KSZ 0x00000800
+#define SDCRNG_CTL_RSRC_CRG 0x00000010
+#define SDCRNG_CTL_RSRC_RRG 0x00000000
+#define SDCRNG_CTL_CE 0x00000004
+#define SDCRNG_CTL_RE 0x00000002
+#define SDCRNG_CTL_DR 0x00000001
+#define SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
+#define SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
+#define SDCRNG_VAL_REG 0x20
+
+#define MODULE_NAME "pasemi_rng"
+
+static int pasemi_rng_data_present(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+
+ return (in_le32(rng_regs + SDCRNG_CTL_REG)
+ & SDCRNG_CTL_FVLD_M) ? 1 : 0;
+}
+
+static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ *data = in_le32(rng_regs + SDCRNG_VAL_REG);
+ return 4;
+}
+
+static int pasemi_rng_init(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ u32 ctl;
+
+ ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
+ out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
+ out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
+
+ return 0;
+}
+
+static void pasemi_rng_cleanup(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ u32 ctl;
+
+ ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
+ out_le32(rng_regs + SDCRNG_CTL_REG,
+ in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
+}
+
+static struct hwrng pasemi_rng = {
+ .name = MODULE_NAME,
+ .init = pasemi_rng_init,
+ .cleanup = pasemi_rng_cleanup,
+ .data_present = pasemi_rng_data_present,
+ .data_read = pasemi_rng_data_read,
+};
+
+static int __devinit rng_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ void __iomem *rng_regs;
+ struct device_node *rng_np = ofdev->node;
+ struct resource res;
+ int err = 0;
+
+ err = of_address_to_resource(rng_np, 0, &res);
+ if (err)
+ return -ENODEV;
+
+ rng_regs = ioremap(res.start, 0x100);
+
+ if (!rng_regs)
+ return -ENOMEM;
+
+ pasemi_rng.priv = (unsigned long)rng_regs;
+
+ printk(KERN_INFO "Registering PA Semi RNG\n");
+
+ err = hwrng_register(&pasemi_rng);
+
+ if (err)
+ iounmap(rng_regs);
+
+ return err;
+}
+
+static int __devexit rng_remove(struct of_device *dev)
+{
+ void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
+
+ hwrng_unregister(&pasemi_rng);
+ iounmap(rng_regs);
+
+ return 0;
+}
+
+static struct of_device_id rng_match[] = {
+ {
+ .compatible = "1682m-rng",
+ },
+ {},
+};
+
+static struct of_platform_driver rng_driver = {
+ .name = "pasemi-rng",
+ .match_table = rng_match,
+ .probe = rng_probe,
+ .remove = rng_remove,
+};
+
+static int __init rng_init(void)
+{
+ return of_register_platform_driver(&rng_driver);
+}
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+ of_unregister_platform_driver(&rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 9ebf84d1865..ec435cb25c4 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <linux/hw_random.h>
#include <asm/io.h>
#include <asm/msr.h>
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 353d9f3cf8d..0289705967d 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -22,6 +22,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/dmi.h>
+#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/io.h>
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index a48da02aad2..932264a657d 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -35,7 +35,6 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#include <asm/m48t35.h>
#include <asm/sn/ioc3.h>
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index e22146546ad..6c5d15de331 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -9,6 +9,7 @@
* source@mvista.com
*
* Copyright 2002 MontaVista Software Inc.
+ * Copyright 2006 IBM Corp., Christian Krafft <krafft@de.ibm.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
@@ -64,6 +65,11 @@
#include <linux/string.h>
#include <linux/ctype.h>
+#ifdef CONFIG_PPC_OF
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#endif
+
#define PFX "ipmi_si: "
/* Measure times between events in the driver. */
@@ -76,6 +82,12 @@
#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
short timeout */
+/* Bit for BMC global enables. */
+#define IPMI_BMC_RCV_MSG_INTR 0x01
+#define IPMI_BMC_EVT_MSG_INTR 0x02
+#define IPMI_BMC_EVT_MSG_BUFF 0x04
+#define IPMI_BMC_SYS_LOG 0x08
+
enum si_intf_state {
SI_NORMAL,
SI_GETTING_FLAGS,
@@ -84,7 +96,9 @@ enum si_intf_state {
SI_CLEARING_FLAGS_THEN_SET_IRQ,
SI_GETTING_MESSAGES,
SI_ENABLE_INTERRUPTS1,
- SI_ENABLE_INTERRUPTS2
+ SI_ENABLE_INTERRUPTS2,
+ SI_DISABLE_INTERRUPTS1,
+ SI_DISABLE_INTERRUPTS2
/* FIXME - add watchdog stuff. */
};
@@ -333,6 +347,17 @@ static void start_enable_irq(struct smi_info *smi_info)
smi_info->si_state = SI_ENABLE_INTERRUPTS1;
}
+static void start_disable_irq(struct smi_info *smi_info)
+{
+ unsigned char msg[2];
+
+ msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+ smi_info->si_state = SI_DISABLE_INTERRUPTS1;
+}
+
static void start_clear_flags(struct smi_info *smi_info)
{
unsigned char msg[3];
@@ -353,7 +378,7 @@ static void start_clear_flags(struct smi_info *smi_info)
static inline void disable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
- disable_irq_nosync(smi_info->irq);
+ start_disable_irq(smi_info);
smi_info->interrupt_disabled = 1;
}
}
@@ -361,7 +386,7 @@ static inline void disable_si_irq(struct smi_info *smi_info)
static inline void enable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
- enable_irq(smi_info->irq);
+ start_enable_irq(smi_info);
smi_info->interrupt_disabled = 0;
}
}
@@ -583,7 +608,9 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
- msg[2] = msg[3] | 1; /* enable msg queue int */
+ msg[2] = (msg[3] |
+ IPMI_BMC_RCV_MSG_INTR |
+ IPMI_BMC_EVT_MSG_INTR);
smi_info->handlers->start_transaction(
smi_info->si_sm, msg, 3);
smi_info->si_state = SI_ENABLE_INTERRUPTS2;
@@ -605,6 +632,45 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->si_state = SI_NORMAL;
break;
}
+
+ case SI_DISABLE_INTERRUPTS1:
+ {
+ unsigned char msg[4];
+
+ /* We got the flags from the SMI, now handle them. */
+ smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+ if (msg[2] != 0) {
+ printk(KERN_WARNING
+ "ipmi_si: Could not disable interrupts"
+ ", failed get.\n");
+ smi_info->si_state = SI_NORMAL;
+ } else {
+ msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+ msg[2] = (msg[3] &
+ ~(IPMI_BMC_RCV_MSG_INTR |
+ IPMI_BMC_EVT_MSG_INTR));
+ smi_info->handlers->start_transaction(
+ smi_info->si_sm, msg, 3);
+ smi_info->si_state = SI_DISABLE_INTERRUPTS2;
+ }
+ break;
+ }
+
+ case SI_DISABLE_INTERRUPTS2:
+ {
+ unsigned char msg[4];
+
+ /* We got the flags from the SMI, now handle them. */
+ smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+ if (msg[2] != 0) {
+ printk(KERN_WARNING
+ "ipmi_si: Could not disable interrupts"
+ ", failed set.\n");
+ }
+ smi_info->si_state = SI_NORMAL;
+ break;
+ }
}
}
@@ -858,9 +924,6 @@ static void smi_timeout(unsigned long data)
struct timeval t;
#endif
- if (atomic_read(&smi_info->stop_operation))
- return;
-
spin_lock_irqsave(&(smi_info->si_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
@@ -916,15 +979,11 @@ static irqreturn_t si_irq_handler(int irq, void *data)
smi_info->interrupts++;
spin_unlock(&smi_info->count_lock);
- if (atomic_read(&smi_info->stop_operation))
- goto out;
-
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
- out:
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return IRQ_HANDLED;
}
@@ -1006,6 +1065,7 @@ static DEFINE_MUTEX(smi_infos_lock);
static int smi_num; /* Used to sequence the SMIs */
#define DEFAULT_REGSPACING 1
+#define DEFAULT_REGSIZE 1
static int si_trydefaults = 1;
static char *si_type[SI_MAX_PARMS];
@@ -1111,7 +1171,7 @@ static int std_irq_setup(struct smi_info *info)
if (info->si_type == SI_BT) {
rv = request_irq(info->irq,
si_bt_irq_handler,
- IRQF_DISABLED,
+ IRQF_SHARED | IRQF_DISABLED,
DEVICE_NAME,
info);
if (!rv)
@@ -1121,7 +1181,7 @@ static int std_irq_setup(struct smi_info *info)
} else
rv = request_irq(info->irq,
si_irq_handler,
- IRQF_DISABLED,
+ IRQF_SHARED | IRQF_DISABLED,
DEVICE_NAME,
info);
if (rv) {
@@ -1701,15 +1761,11 @@ static u32 ipmi_acpi_gpe(void *context)
smi_info->interrupts++;
spin_unlock(&smi_info->count_lock);
- if (atomic_read(&smi_info->stop_operation))
- goto out;
-
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
- out:
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return ACPI_INTERRUPT_HANDLED;
@@ -2133,12 +2189,15 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
info->irq_setup = std_irq_setup;
info->dev = &pdev->dev;
+ pci_set_drvdata(pdev, info);
return try_smi_init(info);
}
static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
{
+ struct smi_info *info = pci_get_drvdata(pdev);
+ cleanup_one_si(info);
}
#ifdef CONFIG_PM
@@ -2172,6 +2231,99 @@ static struct pci_driver ipmi_pci_driver = {
#endif /* CONFIG_PCI */
+#ifdef CONFIG_PPC_OF
+static int __devinit ipmi_of_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct smi_info *info;
+ struct resource resource;
+ const int *regsize, *regspacing, *regshift;
+ struct device_node *np = dev->node;
+ int ret;
+ int proplen;
+
+ dev_info(&dev->dev, PFX "probing via device tree\n");
+
+ ret = of_address_to_resource(np, 0, &resource);
+ if (ret) {
+ dev_warn(&dev->dev, PFX "invalid address from OF\n");
+ return ret;
+ }
+
+ regsize = get_property(np, "reg-size", &proplen);
+ if (regsize && proplen != 4) {
+ dev_warn(&dev->dev, PFX "invalid regsize from OF\n");
+ return -EINVAL;
+ }
+
+ regspacing = get_property(np, "reg-spacing", &proplen);
+ if (regspacing && proplen != 4) {
+ dev_warn(&dev->dev, PFX "invalid regspacing from OF\n");
+ return -EINVAL;
+ }
+
+ regshift = get_property(np, "reg-shift", &proplen);
+ if (regshift && proplen != 4) {
+ dev_warn(&dev->dev, PFX "invalid regshift from OF\n");
+ return -EINVAL;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+ if (!info) {
+ dev_err(&dev->dev,
+ PFX "could not allocate memory for OF probe\n");
+ return -ENOMEM;
+ }
+
+ info->si_type = (enum si_type) match->data;
+ info->addr_source = "device-tree";
+ info->io_setup = mem_setup;
+ info->irq_setup = std_irq_setup;
+
+ info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+ info->io.addr_data = resource.start;
+
+ info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE;
+ info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING;
+ info->io.regshift = regshift ? *regshift : 0;
+
+ info->irq = irq_of_parse_and_map(dev->node, 0);
+ info->dev = &dev->dev;
+
+ dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n",
+ info->io.addr_data, info->io.regsize, info->io.regspacing,
+ info->irq);
+
+ dev->dev.driver_data = (void*) info;
+
+ return try_smi_init(info);
+}
+
+static int __devexit ipmi_of_remove(struct of_device *dev)
+{
+ cleanup_one_si(dev->dev.driver_data);
+ return 0;
+}
+
+static struct of_device_id ipmi_match[] =
+{
+ { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS },
+ { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC },
+ { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT },
+ {},
+};
+
+static struct of_platform_driver ipmi_of_platform_driver =
+{
+ .name = "ipmi",
+ .match_table = ipmi_match,
+ .probe = ipmi_of_probe,
+ .remove = __devexit_p(ipmi_of_remove),
+};
+#endif /* CONFIG_PPC_OF */
+
+
static int try_get_dev_id(struct smi_info *smi_info)
{
unsigned char msg[2];
@@ -2801,6 +2953,10 @@ static __devinit int init_ipmi_si(void)
}
#endif
+#ifdef CONFIG_PPC_OF
+ of_register_platform_driver(&ipmi_of_platform_driver);
+#endif
+
if (si_trydefaults) {
mutex_lock(&smi_infos_lock);
if (list_empty(&smi_infos)) {
@@ -2838,28 +2994,33 @@ static void cleanup_one_si(struct smi_info *to_clean)
list_del(&to_clean->link);
- /* Tell the timer and interrupt handlers that we are shutting
- down. */
- spin_lock_irqsave(&(to_clean->si_lock), flags);
- spin_lock(&(to_clean->msg_lock));
-
+ /* Tell the driver that we are shutting down. */
atomic_inc(&to_clean->stop_operation);
- if (to_clean->irq_cleanup)
- to_clean->irq_cleanup(to_clean);
-
- spin_unlock(&(to_clean->msg_lock));
- spin_unlock_irqrestore(&(to_clean->si_lock), flags);
-
- /* Wait until we know that we are out of any interrupt
- handlers might have been running before we freed the
- interrupt. */
- synchronize_sched();
-
+ /* Make sure the timer and thread are stopped and will not run
+ again. */
wait_for_timer_and_thread(to_clean);
- /* Interrupts and timeouts are stopped, now make sure the
- interface is in a clean state. */
+ /* Timeouts are stopped, now make sure the interrupts are off
+ for the device. A little tricky with locks to make sure
+ there are no races. */
+ spin_lock_irqsave(&to_clean->si_lock, flags);
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+ spin_unlock_irqrestore(&to_clean->si_lock, flags);
+ poll(to_clean);
+ schedule_timeout_uninterruptible(1);
+ spin_lock_irqsave(&to_clean->si_lock, flags);
+ }
+ disable_si_irq(to_clean);
+ spin_unlock_irqrestore(&to_clean->si_lock, flags);
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+ poll(to_clean);
+ schedule_timeout_uninterruptible(1);
+ }
+
+ /* Clean up interrupts and make sure that everything is done. */
+ if (to_clean->irq_cleanup)
+ to_clean->irq_cleanup(to_clean);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
schedule_timeout_uninterruptible(1);
@@ -2898,6 +3059,10 @@ static __exit void cleanup_ipmi_si(void)
pci_unregister_driver(&ipmi_pci_driver);
#endif
+#ifdef CONFIG_PPC_OF
+ of_unregister_platform_driver(&ipmi_of_platform_driver);
+#endif
+
mutex_lock(&smi_infos_lock);
list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
cleanup_one_si(e);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 6b634e8d951..147c12047cf 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -39,6 +39,7 @@
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/completion.h>
+#include <linux/kdebug.h>
#include <linux/rwsem.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
@@ -49,9 +50,18 @@
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <asm/atomic.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/apic.h>
+
+#ifdef CONFIG_X86
+/* This is ugly, but I've determined that x86 is the only architecture
+ that can reasonably support the IPMI NMI watchdog timeout at this
+ time. If another architecture adds this capability somehow, it
+ will have to be a somewhat different mechanism and I have no idea
+ how it will work. So in the unlikely event that another
+ architecture supports this, we can figure out a good generic
+ mechanism for it at that time. */
+#define HAVE_DIE_NMI_POST
#endif
#define PFX "IPMI Watchdog: "
@@ -317,6 +327,11 @@ static unsigned char ipmi_version_minor;
/* If a pretimeout occurs, this is used to allow only one panic to happen. */
static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
+#ifdef HAVE_DIE_NMI_POST
+static int testing_nmi;
+static int nmi_handler_registered;
+#endif
+
static int ipmi_heartbeat(void);
static void panic_halt_ipmi_heartbeat(void);
@@ -358,6 +373,10 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
int hbnow = 0;
+ /* These can be cleared as we are setting the timeout. */
+ ipmi_start_timer_on_heartbeat = 0;
+ pretimeout_since_last_heartbeat = 0;
+
data[0] = 0;
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
@@ -432,13 +451,12 @@ static int ipmi_set_timeout(int do_heartbeat)
wait_for_completion(&set_timeout_wait);
+ mutex_unlock(&set_timeout_lock);
+
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|| ((send_heartbeat_now)
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
- {
rv = ipmi_heartbeat();
- }
- mutex_unlock(&set_timeout_lock);
out:
return rv;
@@ -518,12 +536,10 @@ static int ipmi_heartbeat(void)
int rv;
struct ipmi_system_interface_addr addr;
- if (ipmi_ignore_heartbeat) {
+ if (ipmi_ignore_heartbeat)
return 0;
- }
if (ipmi_start_timer_on_heartbeat) {
- ipmi_start_timer_on_heartbeat = 0;
ipmi_watchdog_state = action_val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
} else if (pretimeout_since_last_heartbeat) {
@@ -531,7 +547,6 @@ static int ipmi_heartbeat(void)
We don't want to set the action, though, we want to
leave that alone (thus it can't be combined with the
above operation. */
- pretimeout_since_last_heartbeat = 0;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
}
@@ -919,6 +934,45 @@ static void ipmi_register_watchdog(int ipmi_intf)
printk(KERN_CRIT PFX "Unable to register misc device\n");
}
+#ifdef HAVE_DIE_NMI_POST
+ if (nmi_handler_registered) {
+ int old_pretimeout = pretimeout;
+ int old_timeout = timeout;
+ int old_preop_val = preop_val;
+
+ /* Set the pretimeout to go off in a second and give
+ ourselves plenty of time to stop the timer. */
+ ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+ preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */
+ pretimeout = 99;
+ timeout = 100;
+
+ testing_nmi = 1;
+
+ rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
+ if (rv) {
+ printk(KERN_WARNING PFX "Error starting timer to"
+ " test NMI: 0x%x. The NMI pretimeout will"
+ " likely not work\n", rv);
+ rv = 0;
+ goto out_restore;
+ }
+
+ msleep(1500);
+
+ if (testing_nmi != 2) {
+ printk(KERN_WARNING PFX "IPMI NMI didn't seem to"
+ " occur. The NMI pretimeout will"
+ " likely not work\n");
+ }
+ out_restore:
+ testing_nmi = 0;
+ preop_val = old_preop_val;
+ pretimeout = old_pretimeout;
+ timeout = old_timeout;
+ }
+#endif
+
out:
up_write(&register_sem);
@@ -928,6 +982,10 @@ static void ipmi_register_watchdog(int ipmi_intf)
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
printk(KERN_INFO PFX "Starting now!\n");
+ } else {
+ /* Stop the timer now. */
+ ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+ ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
}
}
@@ -964,17 +1022,28 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
up_write(&register_sem);
}
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
static int
-ipmi_nmi(void *dev_id, int cpu, int handled)
+ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
{
+ if (val != DIE_NMI_POST)
+ return NOTIFY_OK;
+
+ if (testing_nmi) {
+ testing_nmi = 2;
+ return NOTIFY_STOP;
+ }
+
/* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
- return NOTIFY_DONE;
+ return NOTIFY_OK;
+
+ if (preaction_val != WDOG_PRETIMEOUT_NMI)
+ return NOTIFY_OK;
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
- if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+ if (preop_val == WDOG_PREOP_PANIC) {
/* On some machines, the heartbeat will give
an error and not work unless we re-enable
the timer. So do so. */
@@ -983,18 +1052,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled)
panic(PFX "pre-timeout");
}
- return NOTIFY_DONE;
+ return NOTIFY_STOP;
}
-static struct nmi_handler ipmi_nmi_handler =
-{
- .link = LIST_HEAD_INIT(ipmi_nmi_handler.link),
- .dev_name = "ipmi_watchdog",
- .dev_id = NULL,
- .handler = ipmi_nmi,
- .priority = 0, /* Call us last. */
+static struct notifier_block ipmi_nmi_handler = {
+ .notifier_call = ipmi_nmi
};
-int nmi_handler_registered;
#endif
static int wdog_reboot_handler(struct notifier_block *this,
@@ -1111,7 +1174,7 @@ static int preaction_op(const char *inval, char *outval)
preaction_val = WDOG_PRETIMEOUT_NONE;
else if (strcmp(inval, "pre_smi") == 0)
preaction_val = WDOG_PRETIMEOUT_SMI;
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
else if (strcmp(inval, "pre_nmi") == 0)
preaction_val = WDOG_PRETIMEOUT_NMI;
#endif
@@ -1145,7 +1208,7 @@ static int preop_op(const char *inval, char *outval)
static void check_parms(void)
{
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
int do_nmi = 0;
int rv;
@@ -1158,20 +1221,9 @@ static void check_parms(void)
preop_op("preop_none", NULL);
do_nmi = 0;
}
-#ifdef CONFIG_X86_LOCAL_APIC
- if (nmi_watchdog == NMI_IO_APIC) {
- printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
- " mode (value is %d), that is incompatible"
- " with using NMI in the IPMI watchdog."
- " Disabling IPMI nmi pretimeout.\n",
- nmi_watchdog);
- preaction_val = WDOG_PRETIMEOUT_NONE;
- do_nmi = 0;
- }
-#endif
}
if (do_nmi && !nmi_handler_registered) {
- rv = request_nmi(&ipmi_nmi_handler);
+ rv = register_die_notifier(&ipmi_nmi_handler);
if (rv) {
printk(KERN_WARNING PFX
"Can't register nmi handler\n");
@@ -1179,7 +1231,7 @@ static void check_parms(void)
} else
nmi_handler_registered = 1;
} else if (!do_nmi && nmi_handler_registered) {
- release_nmi(&ipmi_nmi_handler);
+ unregister_die_notifier(&ipmi_nmi_handler);
nmi_handler_registered = 0;
}
#endif
@@ -1215,9 +1267,9 @@ static int __init ipmi_wdog_init(void)
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
-#ifdef HAVE_NMI_HANDLER
- if (preaction_val == WDOG_PRETIMEOUT_NMI)
- release_nmi(&ipmi_nmi_handler);
+#ifdef HAVE_DIE_NMI_POST
+ if (nmi_handler_registered)
+ unregister_die_notifier(&ipmi_nmi_handler);
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
&wdog_panic_notifier);
@@ -1236,9 +1288,9 @@ static void __exit ipmi_wdog_exit(void)
ipmi_smi_watcher_unregister(&smi_watcher);
ipmi_unregister_watchdog(watchdog_ifnum);
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
if (nmi_handler_registered)
- release_nmi(&ipmi_nmi_handler);
+ unregister_die_notifier(&ipmi_nmi_handler);
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 43ab9edc76f..761f77740d6 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -137,11 +137,10 @@
#define InterruptTheCard(base) outw(0, (base) + 0xc)
#define ClearInterrupt(base) inw((base) + 0x0a)
+#define pr_dbg(str...) pr_debug("ISICOM: " str)
#ifdef DEBUG
-#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str)
#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
#else
-#define pr_dbg(str...) do { } while (0)
#define isicom_paranoia_check(a, b, c) 0
#endif
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index cb8d691576d..1b094509b1d 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -41,7 +41,6 @@
#include <linux/input.h>
#include <linux/reboot.h>
-static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void);
/*
@@ -110,7 +109,7 @@ struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
.pid = NULL,
.sig = 0,
};
@@ -159,65 +158,41 @@ static int sysrq_alt_use;
static int sysrq_alt;
/*
- * Translation of scancodes to keycodes. We set them on only the first attached
- * keyboard - for per-keyboard setting, /dev/input/event is more useful.
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ * USB keyboards for example have two event devices: one for all "normal"
+ * keys and one for extra function keys (like "volume up", "make coffee",
+ * etc.). So this means that scancodes for the extra function keys won't
+ * be valid for the first event device, but will be for the second.
*/
int getkeycode(unsigned int scancode)
{
- struct list_head *node;
- struct input_dev *dev = NULL;
+ struct input_handle *handle;
+ int keycode;
+ int error = -ENODEV;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
- break;
- }
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+ error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
+ if (!error)
+ return keycode;
}
- if (!dev)
- return -ENODEV;
-
- if (scancode >= dev->keycodemax)
- return -EINVAL;
-
- return INPUT_KEYCODE(dev, scancode);
+ return error;
}
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- struct list_head *node;
- struct input_dev *dev = NULL;
- unsigned int i, oldkey;
+ struct input_handle *handle;
+ int error = -ENODEV;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+ error = handle->dev->setkeycode(handle->dev, scancode, keycode);
+ if (!error)
break;
- }
}
- if (!dev)
- return -ENODEV;
-
- if (scancode >= dev->keycodemax)
- return -EINVAL;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
- return -EINVAL;
-
- oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
-
- clear_bit(oldkey, dev->keybit);
- set_bit(keycode, dev->keybit);
-
- for (i = 0; i < dev->keycodemax; i++)
- if (INPUT_KEYCODE(dev,i) == oldkey)
- set_bit(oldkey, dev->keybit);
-
- return 0;
+ return error;
}
/*
@@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
*/
static void kd_nosound(unsigned long ignored)
{
- struct list_head *node;
+ struct input_handle *handle;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit))
input_inject_event(handle, EV_SND, SND_TONE, 0);
@@ -1161,7 +1135,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
if (emulate_raw(vc, keycode, !down << 7))
- if (keycode < BTN_MISC)
+ if (keycode < BTN_MISC && printk_ratelimit())
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
@@ -1285,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
* likes it, it can open it and get events from it. In this (kbd_connect)
* function, we should decide which VT to bind that keyboard to initially.
*/
-static struct input_handle *kbd_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct input_handle *handle;
+ int error;
int i;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
@@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
break;
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
- return NULL;
+ return -ENODEV;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
- return NULL;
+ return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "kbd";
- input_open_device(handle);
+ error = input_register_handle(handle);
+ if (error)
+ goto err_free_handle;
+
+ error = input_open_device(handle);
+ if (error)
+ goto err_unregister_handle;
+
+ return 0;
- return handle;
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_handle:
+ kfree(handle);
+ return error;
}
static void kbd_disconnect(struct input_handle *handle)
{
input_close_device(handle);
+ input_unregister_handle(handle);
kfree(handle);
}
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index b51d08be0bc..62051f8b091 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -118,7 +118,6 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
@@ -139,9 +138,6 @@
/* if you have more than 8 printers, remember to increase LP_NO */
#define LP_NO 8
-/* ROUND_UP macro from fs/select.c */
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
static struct lp_struct lp_table[LP_NO];
static unsigned int lp_count = 0;
@@ -652,7 +648,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
(par_timeout.tv_usec < 0)) {
return -EINVAL;
}
- to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
+ to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
to_jiffies += par_timeout.tv_sec * (long) HZ;
if (to_jiffies <= 0) {
return -EINVAL;
@@ -803,7 +799,7 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
- class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL,
+ class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
"lp%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 5f066963f17..cc9a9d0df97 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,7 +18,6 @@
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
@@ -552,7 +551,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
return virtr + wrote;
}
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
static ssize_t read_port(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
@@ -835,7 +834,7 @@ static const struct file_operations null_fops = {
.splice_write = splice_write_null,
};
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
static const struct file_operations port_fops = {
.llseek = memory_lseek,
.read = read_port,
@@ -913,7 +912,7 @@ static int memory_open(struct inode * inode, struct file * filp)
case 3:
filp->f_op = &null_fops;
break;
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
case 4:
filp->f_op = &port_fops;
break;
@@ -960,7 +959,7 @@ static const struct {
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
#endif
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 7e975f60692..4e6fb9651a1 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -41,6 +41,7 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
@@ -53,7 +54,7 @@
* Head entry for the doubly linked miscdevice list
*/
static LIST_HEAD(misc_list);
-static DECLARE_MUTEX(misc_sem);
+static DEFINE_MUTEX(misc_mtx);
/*
* Assigned numbers, used for dynamic minors
@@ -69,7 +70,7 @@ static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
struct miscdevice *p;
loff_t off = 0;
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(p, &misc_list, list) {
if (*pos == off++)
return p;
@@ -89,7 +90,7 @@ static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void misc_seq_stop(struct seq_file *seq, void *v)
{
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
}
static int misc_seq_show(struct seq_file *seq, void *v)
@@ -129,7 +130,7 @@ static int misc_open(struct inode * inode, struct file * file)
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
@@ -139,9 +140,9 @@ static int misc_open(struct inode * inode, struct file * file)
}
if (!new_fops) {
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
@@ -165,7 +166,7 @@ static int misc_open(struct inode * inode, struct file * file)
}
fops_put(old_fops);
fail:
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return err;
}
@@ -201,10 +202,10 @@ int misc_register(struct miscdevice * misc)
INIT_LIST_HEAD(&misc->list);
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == misc->minor) {
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return -EBUSY;
}
}
@@ -215,7 +216,7 @@ int misc_register(struct miscdevice * misc)
if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
break;
if (i<0) {
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return -EBUSY;
}
misc->minor = i;
@@ -238,7 +239,7 @@ int misc_register(struct miscdevice * misc)
*/
list_add(&misc->list, &misc_list);
out:
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return err;
}
@@ -259,13 +260,13 @@ int misc_deregister(struct miscdevice * misc)
if (list_empty(&misc->list))
return -EINVAL;
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_del(&misc->list);
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return 0;
}
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 7dbaee8d940..e0d35c20c04 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -1582,7 +1582,7 @@ copy:
if(copy_from_user(&dltmp, argp, sizeof(struct dl_str)))
return -EFAULT;
- if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS)
+ if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0)
return -EINVAL;
switch(cmd)
@@ -2529,6 +2529,8 @@ static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
void __iomem *baseAddr;
int i;
+ if(len < 0 || len > sizeof(moxaBuff))
+ return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
baseAddr = moxa_boards[cardno].basemem;
@@ -2576,7 +2578,7 @@ static int moxaload320b(int cardno, unsigned char __user *tmp, int len)
void __iomem *baseAddr;
int i;
- if(len > sizeof(moxaBuff))
+ if(len < 0 || len > sizeof(moxaBuff))
return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
@@ -2596,6 +2598,8 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
void __iomem *baseAddr, *ofsAddr;
int retval, port, i;
+ if(len < 0 || len > sizeof(moxaBuff))
+ return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
baseAddr = moxa_boards[cardno].basemem;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 80a01150b86..5953a45d7e9 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -54,7 +54,6 @@
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/pci.h>
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index f7603b6aeb8..6cde448cd5b 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -37,7 +37,6 @@
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/pci.h>
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 65f2d3a96b8..14557a4822c 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -1088,13 +1088,13 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
/* block until there is a message: */
add_wait_queue(&pInfo->read_wait, &wait);
repeat:
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
pMsg = remove_msg(pInfo, pClient);
if (!pMsg && !signal_pending(current)) {
schedule();
goto repeat;
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&pInfo->read_wait, &wait);
}
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index 27c1179ee52..f25facd97bb 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -21,6 +21,7 @@ config SYNCLINK_CS
config CARDMAN_4000
tristate "Omnikey Cardman 4000 support"
depends on PCMCIA
+ select BITREVERSE
help
Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
reader.
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index e91b43a014b..fee58e03dbe 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
+#include <linux/bitrev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -194,41 +195,17 @@ static inline unsigned char xinb(unsigned short port)
}
#endif
-#define b_0000 15
-#define b_0001 14
-#define b_0010 13
-#define b_0011 12
-#define b_0100 11
-#define b_0101 10
-#define b_0110 9
-#define b_0111 8
-#define b_1000 7
-#define b_1001 6
-#define b_1010 5
-#define b_1011 4
-#define b_1100 3
-#define b_1101 2
-#define b_1110 1
-#define b_1111 0
-
-static unsigned char irtab[16] = {
- b_0000, b_1000, b_0100, b_1100,
- b_0010, b_1010, b_0110, b_1110,
- b_0001, b_1001, b_0101, b_1101,
- b_0011, b_1011, b_0111, b_1111
-};
+static inline unsigned char invert_revert(unsigned char ch)
+{
+ return bitrev8(~ch);
+}
static void str_invert_revert(unsigned char *b, int len)
{
int i;
for (i = 0; i < len; i++)
- b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
-}
-
-static unsigned char invert_revert(unsigned char ch)
-{
- return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+ b[i] = invert_revert(b[i]);
}
#define ATRLENCK(dev,pos) \
@@ -1114,7 +1091,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
/*
* wait for atr to become valid.
* note: it is important to lock this code. if we dont, the monitor
- * could be run between test_bit and the the call the sleep on the
+ * could be run between test_bit and the call to sleep on the
* atr-queue. if *then* the monitor detects atr valid, it will wake up
* any process on the atr-queue, *but* since we have been interrupted,
* we do not yet sleep on this queue. this would result in a missed
@@ -1881,8 +1858,11 @@ static int cm4000_probe(struct pcmcia_device *link)
init_waitqueue_head(&dev->readq);
ret = cm4000_config(link, i);
- if (ret)
+ if (ret) {
+ dev_table[i] = NULL;
+ kfree(dev);
return ret;
+ }
class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
"cmm%d", i);
@@ -1907,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
cm4000_release(link);
dev_table[devno] = NULL;
- kfree(dev);
+ kfree(dev);
class_device_destroy(cmm_class, MKDEV(major, devno));
@@ -1956,12 +1936,14 @@ static int __init cmm_init(void)
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
+ class_destroy(cmm_class);
return major;
}
rc = pcmcia_register_driver(&cm4000_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
+ class_destroy(cmm_class);
return rc;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index f2e4ec4fd40..af88181a17f 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -636,8 +636,11 @@ static int reader_probe(struct pcmcia_device *link)
setup_timer(&dev->poll_timer, cm4040_do_poll, 0);
ret = reader_config(link, i);
- if (ret)
+ if (ret) {
+ dev_table[i] = NULL;
+ kfree(dev);
return ret;
+ }
class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
"cmx%d", i);
@@ -708,12 +711,14 @@ static int __init cm4040_init(void)
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
+ class_destroy(cmx_class);
return major;
}
rc = pcmcia_register_driver(&reader_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
+ class_destroy(cmx_class);
return rc;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 157b1d09ab5..13808f6083a 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -42,7 +42,6 @@
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 4abd1eff61d..84ac64fc48a 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -66,7 +66,6 @@
#include <linux/poll.h>
#include <linux/major.h>
#include <linux/ppdev.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <asm/uaccess.h>
@@ -752,7 +751,7 @@ static const struct file_operations pp_fops = {
static void pp_attach(struct parport *port)
{
- device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number),
+ device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number),
"parport%d", port->number);
}
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 70145254fb9..3494e3fc44b 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -980,7 +980,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
if (!tty_hung_up_p(filp))
port->count++;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 76357c855ce..61a63da420c 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -65,10 +65,6 @@
/****** Kernel includes ******/
-#ifdef MODVERSIONS
-#include <config/modversions.h>
-#endif
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
@@ -85,6 +81,7 @@
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
+#include <linux/mutex.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/wait.h>
@@ -93,7 +90,6 @@
#include <asm/atomic.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
-#include <asm/semaphore.h>
#include <linux/init.h>
/****** RocketPort includes ******/
@@ -702,7 +698,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
}
}
spin_lock_init(&info->slock);
- sema_init(&info->write_sem, 1);
+ mutex_init(&info->write_mtx);
rp_table[line] = info;
if (pci_dev)
tty_register_device(rocket_driver, line, &pci_dev->dev);
@@ -947,7 +943,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
#endif
schedule(); /* Don't hold spinlock here, will hang PC */
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
spin_lock_irqsave(&info->slock, flags);
@@ -1602,7 +1598,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
if (signal_pending(current))
break;
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
#endif
@@ -1661,8 +1657,11 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
if (rocket_paranoia_check(info, "rp_put_char"))
return;
- /* Grab the port write semaphore, locking out other processes that try to write to this port */
- down(&info->write_sem);
+ /*
+ * Grab the port write mutex, locking out other processes that try to
+ * write to this port
+ */
+ mutex_lock(&info->write_mtx);
#ifdef ROCKET_DEBUG_WRITE
printk(KERN_INFO "rp_put_char %c...", ch);
@@ -1684,12 +1683,12 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_fifo_room--;
}
spin_unlock_irqrestore(&info->slock, flags);
- up(&info->write_sem);
+ mutex_unlock(&info->write_mtx);
}
/*
* Exception handler - write routine, called when user app writes to the device.
- * A per port write semaphore is used to protect from another process writing to
+ * A per port write mutex is used to protect from another process writing to
* this port at the same time. This other process could be running on the other CPU
* or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
* Spinlocks protect the info xmit members.
@@ -1706,7 +1705,7 @@ static int rp_write(struct tty_struct *tty,
if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
return 0;
- down_interruptible(&info->write_sem);
+ mutex_lock_interruptible(&info->write_mtx);
#ifdef ROCKET_DEBUG_WRITE
printk(KERN_INFO "rp_write %d chars...", count);
@@ -1777,7 +1776,7 @@ end:
wake_up_interruptible(&tty->poll_wait);
#endif
}
- up(&info->write_sem);
+ mutex_unlock(&info->write_mtx);
return retval;
}
@@ -1852,6 +1851,12 @@ static void rp_flush_buffer(struct tty_struct *tty)
#ifdef CONFIG_PCI
+static struct pci_device_id __devinitdata rocket_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
+
/*
* Called when a PCI card is found. Retrieves and stores model information,
* init's aiopic and serial port hardware.
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 3a8bcc85bc1..89b4d7b10d1 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -15,6 +15,8 @@
#define ROCKET_TYPE_MODEMIII 3
#define ROCKET_TYPE_PC104 4
+#include <linux/mutex.h>
+
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -1171,7 +1173,7 @@ struct r_port {
struct wait_queue *close_wait;
#endif
spinlock_t slock;
- struct semaphore write_sem;
+ struct mutex write_mtx;
};
#define RPORT_MAGIC 0x525001
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index c7dac9b1335..20380a2c4de 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -388,7 +388,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
if (!retval)
retval = count;
out:
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&rtc_wait, &wait);
return retval;
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 74cff839c85..a69f094d1ed 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -299,7 +299,7 @@ int paste_selection(struct tty_struct *tty)
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
tty_ldisc_deref(ld);
return 0;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 5fd314adc1f..c585b4738f8 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1892,7 +1892,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
#endif
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)) {
info->count++;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 78237577b05..3ef593a9015 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -1,6 +1,8 @@
/*
* Sony Programmable I/O Control Device driver for VAIO
*
+ * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ *
* Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
@@ -95,6 +97,11 @@ module_param(useinput, int, 0444);
MODULE_PARM_DESC(useinput,
"set this if you would like sonypi to feed events to the input subsystem");
+static int check_ioport = 1;
+module_param(check_ioport, int, 0444);
+MODULE_PARM_DESC(check_ioport,
+ "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
+
#define SONYPI_DEVICE_MODEL_TYPE1 1
#define SONYPI_DEVICE_MODEL_TYPE2 2
#define SONYPI_DEVICE_MODEL_TYPE3 3
@@ -477,7 +484,7 @@ static struct sonypi_device {
u16 evtype_offset;
int camera_power;
int bluetooth_power;
- struct semaphore lock;
+ struct mutex lock;
struct kfifo *fifo;
spinlock_t fifo_lock;
wait_queue_head_t fifo_proc_list;
@@ -884,7 +891,7 @@ int sonypi_camera_command(int command, u8 value)
if (!camera)
return -EIO;
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
switch (command) {
case SONYPI_COMMAND_SETCAMERA:
@@ -919,7 +926,7 @@ int sonypi_camera_command(int command, u8 value)
command);
break;
}
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return 0;
}
@@ -938,20 +945,20 @@ static int sonypi_misc_fasync(int fd, struct file *filp, int on)
static int sonypi_misc_release(struct inode *inode, struct file *file)
{
sonypi_misc_fasync(-1, file, 0);
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
sonypi_device.open_count--;
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return 0;
}
static int sonypi_misc_open(struct inode *inode, struct file *file)
{
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
/* Flush input queue on first open */
if (!sonypi_device.open_count)
kfifo_reset(sonypi_device.fifo);
sonypi_device.open_count++;
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return 0;
}
@@ -1001,7 +1008,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
u8 val8;
u16 val16;
- down(&sonypi_device.lock);
+ mutex_lock(&sonypi_device.lock);
switch (cmd) {
case SONYPI_IOCGBRT:
if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
@@ -1101,7 +1108,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
default:
ret = -EINVAL;
}
- up(&sonypi_device.lock);
+ mutex_unlock(&sonypi_device.lock);
return ret;
}
@@ -1260,6 +1267,28 @@ static int __devinit sonypi_create_input_devices(void)
static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
const struct sonypi_ioport_list *ioport_list)
{
+ /* try to detect if sony-laptop is being used and thus
+ * has already requested one of the known ioports.
+ * As in the deprecated check_region this is racy has we have
+ * multiple ioports available and one of them can be requested
+ * between this check and the subsequent request. Anyway, as an
+ * attempt to be some more user-friendly as we currently are,
+ * this is enough.
+ */
+ const struct sonypi_ioport_list *check = ioport_list;
+ while (check_ioport && check->port1) {
+ if (!request_region(check->port1,
+ sonypi_device.region_size,
+ "Sony Programable I/O Device Check")) {
+ printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
+ "if not use check_ioport=0\n",
+ check->port1);
+ return -EBUSY;
+ }
+ release_region(check->port1, sonypi_device.region_size);
+ check++;
+ }
+
while (ioport_list->port1) {
if (request_region(ioport_list->port1,
@@ -1321,6 +1350,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
struct pci_dev *pcidev;
int error;
+ printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
+ "and report failures, see also "
+ "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
+
spin_lock_init(&sonypi_device.fifo_lock);
sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
&sonypi_device.fifo_lock);
@@ -1330,7 +1363,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
}
init_waitqueue_head(&sonypi_device.fifo_proc_list);
- init_MUTEX(&sonypi_device.lock);
+ mutex_init(&sonypi_device.lock);
sonypi_device.bluetooth_power = -1;
if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index ce4db6f5236..f02a0795983 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -4010,8 +4010,13 @@ static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info)
for ( i=0; i<info->num_tx_holding_buffers; ++i) {
info->tx_holding_buffers[i].buffer =
kmalloc(info->max_frame_size, GFP_KERNEL);
- if ( info->tx_holding_buffers[i].buffer == NULL )
+ if (info->tx_holding_buffers[i].buffer == NULL) {
+ for (--i; i >= 0; i--) {
+ kfree(info->tx_holding_buffers[i].buffer);
+ info->tx_holding_buffers[i].buffer = NULL;
+ }
return -ENOMEM;
+ }
}
return 0;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 0a367cd4121..2a7736b5f2f 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -3415,6 +3415,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
}
}
+
+ for (i=0; i < port_count; ++i)
+ tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
}
static int __devinit init_one(struct pci_dev *dev,
@@ -3466,6 +3469,8 @@ static void slgt_cleanup(void)
printk("unload %s %s\n", driver_name, driver_version);
if (serial_driver) {
+ for (info=slgt_device_list ; info != NULL ; info=info->next_device)
+ tty_unregister_device(serial_driver, info->line);
if ((rc = tty_unregister_driver(serial_driver)))
DBGERR(("tty_unregister_driver error=%d\n", rc));
put_tty_driver(serial_driver);
@@ -3506,23 +3511,10 @@ static int __init slgt_init(void)
printk("%s %s\n", driver_name, driver_version);
- slgt_device_count = 0;
- if ((rc = pci_register_driver(&pci_driver)) < 0) {
- printk("%s pci_register_driver error=%d\n", driver_name, rc);
- return rc;
- }
- pci_registered = 1;
-
- if (!slgt_device_list) {
- printk("%s no devices found\n",driver_name);
- pci_unregister_driver(&pci_driver);
- return -ENODEV;
- }
-
serial_driver = alloc_tty_driver(MAX_DEVICES);
if (!serial_driver) {
- rc = -ENOMEM;
- goto error;
+ printk("%s can't allocate tty driver\n", driver_name);
+ return -ENOMEM;
}
/* Initialize the tty_driver structure */
@@ -3539,7 +3531,7 @@ static int __init slgt_init(void)
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->init_termios.c_ispeed = 9600;
serial_driver->init_termios.c_ospeed = 9600;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
DBGERR(("%s can't register serial driver\n", driver_name));
@@ -3552,6 +3544,16 @@ static int __init slgt_init(void)
driver_name, driver_version,
serial_driver->major);
+ slgt_device_count = 0;
+ if ((rc = pci_register_driver(&pci_driver)) < 0) {
+ printk("%s pci_register_driver error=%d\n", driver_name, rc);
+ goto error;
+ }
+ pci_registered = 1;
+
+ if (!slgt_device_list)
+ printk("%s no devices found\n",driver_name);
+
return 0;
error:
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1d8c4ae6155..39cc318011e 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -24,7 +24,6 @@
#include <linux/sysrq.h>
#include <linux/kbd_kern.h>
#include <linux/quotaops.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/suspend.h>
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 47fb20f6969..35b40b99653 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -442,7 +442,7 @@ tipar_register(int nr, struct parport *port)
}
class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
- TIPAR_MINOR + nr), NULL, "par%d", nr);
+ TIPAR_MINOR + nr), port->dev, "par%d", nr);
/* Display informations */
pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index fe00c7dfb64..11089be0691 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -33,7 +33,7 @@ config TCG_NSC
tristate "National Semiconductor TPM Interface"
depends on TCG_TPM && PNPACPI
---help---
- If you have a TPM security chip from National Semicondutor
+ If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
compile this driver as a module, choose M here; the module
will be called tpm_nsc.
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index e5a254a434f..9bb542913b8 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -24,7 +24,9 @@
*/
#include <linux/poll.h>
+#include <linux/mutex.h>
#include <linux/spinlock.h>
+
#include "tpm.h"
enum tpm_const {
@@ -328,10 +330,10 @@ static void timeout_work(struct work_struct *work)
{
struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
- down(&chip->buffer_mutex);
+ mutex_lock(&chip->buffer_mutex);
atomic_set(&chip->data_pending, 0);
memset(chip->data_buffer, 0, TPM_BUFSIZE);
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
}
/*
@@ -380,7 +382,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
return -E2BIG;
}
- down(&chip->tpm_mutex);
+ mutex_lock(&chip->tpm_mutex);
if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
dev_err(chip->dev,
@@ -419,7 +421,7 @@ out_recv:
dev_err(chip->dev,
"tpm_transmit: tpm_recv: error %zd\n", rc);
out:
- up(&chip->tpm_mutex);
+ mutex_unlock(&chip->tpm_mutex);
return rc;
}
@@ -942,12 +944,12 @@ int tpm_release(struct inode *inode, struct file *file)
{
struct tpm_chip *chip = file->private_data;
+ flush_scheduled_work();
spin_lock(&driver_lock);
file->private_data = NULL;
- chip->num_opens--;
del_singleshot_timer_sync(&chip->user_read_timer);
- flush_scheduled_work();
atomic_set(&chip->data_pending, 0);
+ chip->num_opens--;
put_device(chip->dev);
kfree(chip->data_buffer);
spin_unlock(&driver_lock);
@@ -966,14 +968,14 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
while (atomic_read(&chip->data_pending) != 0)
msleep(TPM_TIMEOUT);
- down(&chip->buffer_mutex);
+ mutex_lock(&chip->buffer_mutex);
if (in_size > TPM_BUFSIZE)
in_size = TPM_BUFSIZE;
if (copy_from_user
(chip->data_buffer, (void __user *) buf, in_size)) {
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
return -EFAULT;
}
@@ -981,7 +983,7 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
atomic_set(&chip->data_pending, out_size);
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
/* Set a timeout by which the reader must come claim the result */
mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
@@ -1004,10 +1006,10 @@ ssize_t tpm_read(struct file *file, char __user *buf,
if (size < ret_size)
ret_size = size;
- down(&chip->buffer_mutex);
+ mutex_lock(&chip->buffer_mutex);
if (copy_to_user(buf, chip->data_buffer, ret_size))
ret_size = -EFAULT;
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
}
return ret_size;
@@ -1097,11 +1099,16 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
/* Driver specific per-device data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
+ devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+
+ if (chip == NULL || devname == NULL) {
+ kfree(chip);
+ kfree(devname);
return NULL;
+ }
- init_MUTEX(&chip->buffer_mutex);
- init_MUTEX(&chip->tpm_mutex);
+ mutex_init(&chip->buffer_mutex);
+ mutex_init(&chip->tpm_mutex);
INIT_LIST_HEAD(&chip->list);
INIT_WORK(&chip->work, timeout_work);
@@ -1124,7 +1131,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
set_bit(chip->dev_num, dev_mask);
- devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
chip->vendor.miscdev.name = devname;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index bb9a43c6cf3..b2e2b002a1b 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -19,9 +19,9 @@
*
*/
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
@@ -95,11 +95,11 @@ struct tpm_chip {
/* Data passed to and from the tpm via the read/write calls */
u8 *data_buffer;
atomic_t data_pending;
- struct semaphore buffer_mutex;
+ struct mutex buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
struct work_struct work;
- struct semaphore tpm_mutex; /* tpm is processing */
+ struct mutex tpm_mutex; /* tpm is processing */
struct tpm_vendor_specific vendor;
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index aefd683c60b..c912d8691cb 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -47,14 +47,14 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
if (!dn)
return NULL;
- if (!device_is_compatible(dn, "AT97SC3201")) {
+ if (!of_device_is_compatible(dn, "AT97SC3201")) {
of_node_put(dn);
return NULL;
}
- reg = get_property(dn, "reg", &reglen);
- naddrc = prom_n_addr_cells(dn);
- nsizec = prom_n_size_cells(dn);
+ reg = of_get_property(dn, "reg", &reglen);
+ naddrc = of_n_addr_cells(dn);
+ nsizec = of_n_size_cells(dn);
of_node_put(dn);
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 1353b5a6bae..967002a5a1e 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -30,12 +30,60 @@
#define TPM_MAX_TRIES 5000
#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
-/* These values will be filled after PnP-call */
-static int TPM_INF_DATA;
-static int TPM_INF_ADDR;
-static int TPM_INF_BASE;
-static int TPM_INF_ADDR_LEN;
-static int TPM_INF_PORT_LEN;
+#define TPM_INF_IO_PORT 0x0
+#define TPM_INF_IO_MEM 0x1
+
+#define TPM_INF_ADDR 0x0
+#define TPM_INF_DATA 0x1
+
+struct tpm_inf_dev {
+ int iotype;
+
+ void __iomem *mem_base; /* MMIO ioremap'd addr */
+ unsigned long map_base; /* phys MMIO base */
+ unsigned long map_size; /* MMIO region size */
+ unsigned int index_off; /* index register offset */
+
+ unsigned int data_regs; /* Data registers */
+ unsigned int data_size;
+
+ unsigned int config_port; /* IO Port config index reg */
+ unsigned int config_size;
+};
+
+static struct tpm_inf_dev tpm_dev;
+
+static inline void tpm_data_out(unsigned char data, unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ outb(data, tpm_dev.data_regs + offset);
+ else
+ writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
+}
+
+static inline unsigned char tpm_data_in(unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ return inb(tpm_dev.data_regs + offset);
+ else
+ return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
+}
+
+static inline void tpm_config_out(unsigned char data, unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ outb(data, tpm_dev.config_port + offset);
+ else
+ writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
+}
+
+static inline unsigned char tpm_config_in(unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ return inb(tpm_dev.config_port + offset);
+ else
+ return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
+}
/* TPM header definitions */
enum infineon_tpm_header {
@@ -105,7 +153,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
if (clear_wrfifo) {
for (i = 0; i < 4096; i++) {
- status = inb(chip->vendor.base + WRFIFO);
+ status = tpm_data_in(WRFIFO);
if (status == 0xff) {
if (check == 5)
break;
@@ -125,8 +173,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
*/
i = 0;
do {
- status = inb(chip->vendor.base + RDFIFO);
- status = inb(chip->vendor.base + STAT);
+ status = tpm_data_in(RDFIFO);
+ status = tpm_data_in(STAT);
i++;
if (i == TPM_MAX_TRIES)
return -EIO;
@@ -139,7 +187,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
int status;
int i;
for (i = 0; i < TPM_MAX_TRIES; i++) {
- status = inb(chip->vendor.base + STAT);
+ status = tpm_data_in(STAT);
/* check the status-register if wait_for_bit is set */
if (status & 1 << wait_for_bit)
break;
@@ -158,7 +206,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
{
wait(chip, STAT_XFE);
- outb(sendbyte, chip->vendor.base + WRFIFO);
+ tpm_data_out(sendbyte, WRFIFO);
}
/* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
@@ -205,7 +253,7 @@ recv_begin:
ret = wait(chip, STAT_RDA);
if (ret)
return -EIO;
- buf[i] = inb(chip->vendor.base + RDFIFO);
+ buf[i] = tpm_data_in(RDFIFO);
}
if (buf[0] != TPM_VL_VER) {
@@ -220,7 +268,7 @@ recv_begin:
for (i = 0; i < size; i++) {
wait(chip, STAT_RDA);
- buf[i] = inb(chip->vendor.base + RDFIFO);
+ buf[i] = tpm_data_in(RDFIFO);
}
if ((size == 0x6D00) && (buf[1] == 0x80)) {
@@ -269,7 +317,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
u8 count_high, count_low, count_4, count_3, count_2, count_1;
/* Disabling Reset, LP and IRQC */
- outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD);
+ tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
ret = empty_fifo(chip, 1);
if (ret) {
@@ -320,7 +368,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip)
static u8 tpm_inf_status(struct tpm_chip *chip)
{
- return inb(chip->vendor.base + STAT);
+ return tpm_data_in(STAT);
}
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
@@ -381,51 +429,88 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
/* read IO-ports through PnP */
if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
- TPM_INF_ADDR = pnp_port_start(dev, 0);
- TPM_INF_ADDR_LEN = pnp_port_len(dev, 0);
- TPM_INF_DATA = (TPM_INF_ADDR + 1);
- TPM_INF_BASE = pnp_port_start(dev, 1);
- TPM_INF_PORT_LEN = pnp_port_len(dev, 1);
- if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) {
+
+ tpm_dev.iotype = TPM_INF_IO_PORT;
+
+ tpm_dev.config_port = pnp_port_start(dev, 0);
+ tpm_dev.config_size = pnp_port_len(dev, 0);
+ tpm_dev.data_regs = pnp_port_start(dev, 1);
+ tpm_dev.data_size = pnp_port_len(dev, 1);
+ if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
rc = -EINVAL;
goto err_last;
}
dev_info(&dev->dev, "Found %s with ID %s\n",
dev->name, dev_id->id);
- if (!((TPM_INF_BASE >> 8) & 0xff)) {
+ if (!((tpm_dev.data_regs >> 8) & 0xff)) {
rc = -EINVAL;
goto err_last;
}
/* publish my base address and request region */
- if (request_region
- (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
+ if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
+ "tpm_infineon0") == NULL) {
rc = -EINVAL;
goto err_last;
}
- if (request_region
- (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) {
+ if (request_region(tpm_dev.config_port, tpm_dev.config_size,
+ "tpm_infineon0") == NULL) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
rc = -EINVAL;
goto err_last;
}
+ } else if (pnp_mem_valid(dev, 0) &&
+ !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
+
+ tpm_dev.iotype = TPM_INF_IO_MEM;
+
+ tpm_dev.map_base = pnp_mem_start(dev, 0);
+ tpm_dev.map_size = pnp_mem_len(dev, 0);
+
+ dev_info(&dev->dev, "Found %s with ID %s\n",
+ dev->name, dev_id->id);
+
+ /* publish my base address and request region */
+ if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
+ "tpm_infineon0") == NULL) {
+ rc = -EINVAL;
+ goto err_last;
+ }
+
+ tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
+ if (tpm_dev.mem_base == NULL) {
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+ rc = -EINVAL;
+ goto err_last;
+ }
+
+ /*
+ * The only known MMIO based Infineon TPM system provides
+ * a single large mem region with the device config
+ * registers at the default TPM_ADDR. The data registers
+ * seem like they could be placed anywhere within the MMIO
+ * region, but lets just put them at zero offset.
+ */
+ tpm_dev.index_off = TPM_ADDR;
+ tpm_dev.data_regs = 0x0;
} else {
rc = -EINVAL;
goto err_last;
}
/* query chip for its vendor, its version number a.s.o. */
- outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
- outb(IDVENL, TPM_INF_ADDR);
- vendorid[1] = inb(TPM_INF_DATA);
- outb(IDVENH, TPM_INF_ADDR);
- vendorid[0] = inb(TPM_INF_DATA);
- outb(IDPDL, TPM_INF_ADDR);
- productid[1] = inb(TPM_INF_DATA);
- outb(IDPDH, TPM_INF_ADDR);
- productid[0] = inb(TPM_INF_DATA);
- outb(CHIP_ID1, TPM_INF_ADDR);
- version[1] = inb(TPM_INF_DATA);
- outb(CHIP_ID2, TPM_INF_ADDR);
- version[0] = inb(TPM_INF_DATA);
+ tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
+ tpm_config_out(IDVENL, TPM_INF_ADDR);
+ vendorid[1] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IDVENH, TPM_INF_ADDR);
+ vendorid[0] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IDPDL, TPM_INF_ADDR);
+ productid[1] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IDPDH, TPM_INF_ADDR);
+ productid[0] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
+ version[1] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
+ version[0] = tpm_config_in(TPM_INF_DATA);
switch ((productid[0] << 8) | productid[1]) {
case 6:
@@ -442,51 +527,54 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
/* configure TPM with IO-ports */
- outb(IOLIMH, TPM_INF_ADDR);
- outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA);
- outb(IOLIML, TPM_INF_ADDR);
- outb((TPM_INF_BASE & 0xff), TPM_INF_DATA);
+ tpm_config_out(IOLIMH, TPM_INF_ADDR);
+ tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
+ tpm_config_out(IOLIML, TPM_INF_ADDR);
+ tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
/* control if IO-ports are set correctly */
- outb(IOLIMH, TPM_INF_ADDR);
- ioh = inb(TPM_INF_DATA);
- outb(IOLIML, TPM_INF_ADDR);
- iol = inb(TPM_INF_DATA);
+ tpm_config_out(IOLIMH, TPM_INF_ADDR);
+ ioh = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IOLIML, TPM_INF_ADDR);
+ iol = tpm_config_in(TPM_INF_DATA);
- if ((ioh << 8 | iol) != TPM_INF_BASE) {
+ if ((ioh << 8 | iol) != tpm_dev.data_regs) {
dev_err(&dev->dev,
- "Could not set IO-ports to 0x%x\n",
- TPM_INF_BASE);
+ "Could not set IO-data registers to 0x%x\n",
+ tpm_dev.data_regs);
rc = -EIO;
goto err_release_region;
}
/* activate register */
- outb(TPM_DAR, TPM_INF_ADDR);
- outb(0x01, TPM_INF_DATA);
- outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
+ tpm_config_out(TPM_DAR, TPM_INF_ADDR);
+ tpm_config_out(0x01, TPM_INF_DATA);
+ tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
/* disable RESET, LP and IRQC */
- outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD);
+ tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
/* Finally, we're done, print some infos */
dev_info(&dev->dev, "TPM found: "
- "config base 0x%x, "
- "io base 0x%x, "
+ "config base 0x%lx, "
+ "data base 0x%lx, "
"chip version 0x%02x%02x, "
"vendor id 0x%x%x (Infineon), "
"product id 0x%02x%02x"
"%s\n",
- TPM_INF_ADDR,
- TPM_INF_BASE,
+ tpm_dev.iotype == TPM_INF_IO_PORT ?
+ tpm_dev.config_port :
+ tpm_dev.map_base + tpm_dev.index_off,
+ tpm_dev.iotype == TPM_INF_IO_PORT ?
+ tpm_dev.data_regs :
+ tpm_dev.map_base + tpm_dev.data_regs,
version[0], version[1],
vendorid[0], vendorid[1],
productid[0], productid[1], chipname);
- if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) {
+ if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
goto err_release_region;
- }
- chip->vendor.base = TPM_INF_BASE;
+
return 0;
} else {
rc = -ENODEV;
@@ -494,8 +582,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
}
err_release_region:
- release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
- release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+ if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
+ release_region(tpm_dev.config_port, tpm_dev.config_size);
+ } else {
+ iounmap(tpm_dev.mem_base);
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+ }
err_last:
return rc;
@@ -506,8 +599,14 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
struct tpm_chip *chip = pnp_get_drvdata(dev);
if (chip) {
- release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
- release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+ if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
+ release_region(tpm_dev.config_port,
+ tpm_dev.config_size);
+ } else {
+ iounmap(tpm_dev.mem_base);
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+ }
tpm_remove_hardware(chip->dev);
}
}
@@ -539,5 +638,5 @@ module_exit(cleanup_inf);
MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
-MODULE_VERSION("1.8");
+MODULE_VERSION("1.9");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7a32df59490..fc662e4ce58 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -141,8 +141,6 @@ static DECLARE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
-extern void disable_early_printk(void);
-
static void initialize_tty_struct(struct tty_struct *tty);
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
@@ -155,8 +153,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(int fd, struct file * filp, int on);
static void release_tty(struct tty_struct *tty, int idx);
-static struct pid *__proc_set_tty(struct task_struct *tsk,
- struct tty_struct *tty);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
/**
* alloc_tty_struct - allocate a tty object
@@ -936,13 +934,6 @@ restart:
return -EINVAL;
/*
- * No more input please, we are switching. The new ldisc
- * will update this value in the ldisc open function
- */
-
- tty->receive_room = 0;
-
- /*
* Problem: What do we do if this blocks ?
*/
@@ -953,6 +944,13 @@ restart:
return 0;
}
+ /*
+ * No more input please, we are switching. The new ldisc
+ * will update this value in the ldisc open function
+ */
+
+ tty->receive_room = 0;
+
o_ldisc = tty->ldisc;
o_tty = tty->link;
@@ -1534,10 +1532,9 @@ void disassociate_ctty(int on_exit)
}
spin_lock_irq(&current->sighand->siglock);
- tty_pgrp = current->signal->tty_old_pgrp;
+ put_pid(current->signal->tty_old_pgrp);
current->signal->tty_old_pgrp = NULL;
spin_unlock_irq(&current->sighand->siglock);
- put_pid(tty_pgrp);
mutex_lock(&tty_mutex);
/* It is possible that do_tty_hangup has free'd this tty */
@@ -1562,13 +1559,25 @@ void disassociate_ctty(int on_exit)
unlock_kernel();
}
+/**
+ *
+ * no_tty - Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+ struct task_struct *tsk = current;
+ if (tsk->signal->leader)
+ disassociate_ctty(0);
+ proc_clear_tty(tsk);
+}
+
/**
- * stop_tty - propogate flow control
+ * stop_tty - propagate flow control
* @tty: tty to stop
*
* Perform flow control to the driver. For PTY/TTY pairs we
- * must also propogate the TIOCKPKT status. May be called
+ * must also propagate the TIOCKPKT status. May be called
* on an already stopped device and will not re-call the driver
* method.
*
@@ -1598,11 +1607,11 @@ void stop_tty(struct tty_struct *tty)
EXPORT_SYMBOL(stop_tty);
/**
- * start_tty - propogate flow control
+ * start_tty - propagate flow control
* @tty: tty to start
*
* Start a tty that has been stopped if at all possible. Perform
- * any neccessary wakeups and propogate the TIOCPKT status. If this
+ * any neccessary wakeups and propagate the TIOCPKT status. If this
* is the tty was previous stopped and is being started then the
* driver start method is invoked and the line discipline woken.
*
@@ -2508,7 +2517,6 @@ static int tty_open(struct inode * inode, struct file * filp)
int index;
dev_t device = inode->i_rdev;
unsigned short saved_flags = filp->f_flags;
- struct pid *old_pgrp;
nonseekable_open(inode, filp);
@@ -2602,17 +2610,15 @@ got_driver:
goto retry_open;
}
- old_pgrp = NULL;
mutex_lock(&tty_mutex);
spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
tty->session == NULL)
- old_pgrp = __proc_set_tty(current, tty);
+ __proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
mutex_unlock(&tty_mutex);
- put_pid(old_pgrp);
return 0;
}
@@ -3287,9 +3293,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCNOTTY:
if (current->signal->tty != tty)
return -ENOTTY;
- if (current->signal->leader)
- disassociate_ctty(0);
- proc_clear_tty(current);
+ no_tty();
return 0;
case TIOCSCTTY:
return tiocsctty(tty, arg);
@@ -3720,11 +3724,10 @@ int tty_register_driver(struct tty_driver *driver)
if (driver->flags & TTY_DRIVER_INSTALLED)
return 0;
- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
- p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+ if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+ p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memset(p, 0, driver->num * 3 * sizeof(void *));
}
if (!driver->major) {
@@ -3767,7 +3770,9 @@ int tty_register_driver(struct tty_driver *driver)
if (!driver->put_char)
driver->put_char = tty_default_put_char;
+ mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
+ mutex_unlock(&tty_mutex);
if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
for(i = 0; i < driver->num; i++)
@@ -3793,8 +3798,9 @@ int tty_unregister_driver(struct tty_driver *driver)
unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
driver->num);
-
+ mutex_lock(&tty_mutex);
list_del(&driver->tty_drivers);
+ mutex_unlock(&tty_mutex);
/*
* Free the termios and termios_locked structures because
@@ -3837,11 +3843,9 @@ void proc_clear_tty(struct task_struct *p)
p->signal->tty = NULL;
spin_unlock_irq(&p->sighand->siglock);
}
-EXPORT_SYMBOL(proc_clear_tty);
-static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
- struct pid *old_pgrp;
if (tty) {
/* We should not have a session or pgrp to here but.... */
put_pid(tty->session);
@@ -3849,21 +3853,16 @@ static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tt
tty->session = get_pid(task_session(tsk));
tty->pgrp = get_pid(task_pgrp(tsk));
}
- old_pgrp = tsk->signal->tty_old_pgrp;
+ put_pid(tsk->signal->tty_old_pgrp);
tsk->signal->tty = tty;
tsk->signal->tty_old_pgrp = NULL;
- return old_pgrp;
}
-void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
- struct pid *old_pgrp;
-
spin_lock_irq(&tsk->sighand->siglock);
- old_pgrp = __proc_set_tty(tsk, tty);
+ __proc_set_tty(tsk, tty);
spin_unlock_irq(&tsk->sighand->siglock);
-
- put_pid(old_pgrp);
}
struct tty_struct *get_current_tty(void)
@@ -3898,9 +3897,6 @@ void __init console_init(void)
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
-#ifdef CONFIG_EARLY_PRINTK
- disable_early_printk();
-#endif
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 791930320a1..83aeedda200 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -28,12 +28,13 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/kbd_kern.h>
#include <linux/console.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
+
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -70,11 +71,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
{
int size;
- down(&con_buf_sem);
+ mutex_lock(&con_buf_mtx);
size = vcs_size(file->f_path.dentry->d_inode);
switch (orig) {
default:
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return -EINVAL;
case 2:
offset += size;
@@ -85,11 +86,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
break;
}
if (offset < 0 || offset > size) {
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return -EINVAL;
}
file->f_pos = offset;
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return file->f_pos;
}
@@ -106,7 +107,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
unsigned short *org = NULL;
ssize_t ret;
- down(&con_buf_sem);
+ mutex_lock(&con_buf_mtx);
pos = *ppos;
@@ -263,7 +264,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
ret = read;
unlock_out:
release_console_sem();
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return ret;
}
@@ -280,7 +281,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
u16 *org0 = NULL, *org = NULL;
size_t ret;
- down(&con_buf_sem);
+ mutex_lock(&con_buf_mtx);
pos = *ppos;
@@ -450,7 +451,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
unlock_out:
release_console_sem();
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return ret;
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 1bbb45b937f..bbd9fc41287 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -86,6 +86,7 @@
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/tiocl.h>
@@ -157,6 +158,8 @@ static void blank_screen_t(unsigned long dummy);
static void set_palette(struct vc_data *vc);
static int printable; /* Is console ready for printing? */
+static int default_utf8;
+module_param(default_utf8, int, S_IRUGO | S_IWUSR);
/*
* ignore_poke: don't unblank the screen when things are typed. This is
@@ -348,10 +351,12 @@ void update_region(struct vc_data *vc, unsigned long start, int count)
/* Structure of attributes is hardware-dependent */
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
+ u8 _underline, u8 _reverse, u8 _italic)
{
if (vc->vc_sw->con_build_attr)
- return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse);
+ return vc->vc_sw->con_build_attr(vc, _color, _intensity,
+ _blink, _underline, _reverse, _italic);
#ifndef VT_BUF_VRAM_ONLY
/*
@@ -368,10 +373,13 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8
u8 a = vc->vc_color;
if (!vc->vc_can_do_color)
return _intensity |
+ (_italic ? 2 : 0) |
(_underline ? 4 : 0) |
(_reverse ? 8 : 0) |
(_blink ? 0x80 : 0);
- if (_underline)
+ if (_italic)
+ a = (a & 0xF0) | vc->vc_itcolor;
+ else if (_underline)
a = (a & 0xf0) | vc->vc_ulcolor;
else if (_intensity == 0)
a = (a & 0xf0) | vc->vc_ulcolor;
@@ -392,8 +400,10 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8
static void update_attr(struct vc_data *vc)
{
- vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm);
- vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' ';
+ vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
+ vc->vc_blink, vc->vc_underline,
+ vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+ vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
@@ -934,6 +944,10 @@ int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+
/*
* gotoxy() must verify all boundaries, because the arguments
* might also be negative. If the given position is out of
@@ -1132,6 +1146,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi
static void default_attr(struct vc_data *vc)
{
vc->vc_intensity = 1;
+ vc->vc_italic = 0;
vc->vc_underline = 0;
vc->vc_reverse = 0;
vc->vc_blink = 0;
@@ -1154,6 +1169,9 @@ static void csi_m(struct vc_data *vc)
case 2:
vc->vc_intensity = 0;
break;
+ case 3:
+ vc->vc_italic = 1;
+ break;
case 4:
vc->vc_underline = 1;
break;
@@ -1194,6 +1212,9 @@ static void csi_m(struct vc_data *vc)
case 22:
vc->vc_intensity = 1;
break;
+ case 23:
+ vc->vc_italic = 0;
+ break;
case 24:
vc->vc_underline = 0;
break;
@@ -1454,6 +1475,7 @@ static void save_cur(struct vc_data *vc)
vc->vc_saved_x = vc->vc_x;
vc->vc_saved_y = vc->vc_y;
vc->vc_s_intensity = vc->vc_intensity;
+ vc->vc_s_italic = vc->vc_italic;
vc->vc_s_underline = vc->vc_underline;
vc->vc_s_blink = vc->vc_blink;
vc->vc_s_reverse = vc->vc_reverse;
@@ -1468,6 +1490,7 @@ static void restore_cur(struct vc_data *vc)
{
gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
vc->vc_intensity = vc->vc_s_intensity;
+ vc->vc_italic = vc->vc_s_italic;
vc->vc_underline = vc->vc_s_underline;
vc->vc_blink = vc->vc_s_blink;
vc->vc_reverse = vc->vc_s_reverse;
@@ -1497,7 +1520,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_charset = 0;
vc->vc_need_wrap = 0;
vc->vc_report_mouse = 0;
- vc->vc_utf = 0;
+ vc->vc_utf = default_utf8;
vc->vc_utf_count = 0;
vc->vc_disp_ctrl = 0;
@@ -1930,7 +1953,47 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
* kernel memory allocation is available.
*/
char con_buf[CON_BUF_SIZE];
-DECLARE_MUTEX(con_buf_sem);
+DEFINE_MUTEX(con_buf_mtx);
+
+/* is_double_width() is based on the wcwidth() implementation by
+ * Markus Kuhn -- 2003-05-20 (Unicode 4.0)
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+struct interval {
+ uint32_t first;
+ uint32_t last;
+};
+
+static int bisearch(uint32_t ucs, const struct interval *table, int max)
+{
+ int min = 0;
+ int mid;
+
+ if (ucs < table[0].first || ucs > table[max].last)
+ return 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (ucs > table[mid].last)
+ min = mid + 1;
+ else if (ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int is_double_width(uint32_t ucs)
+{
+ static const struct interval double_width[] = {
+ { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
+ { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
+ { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, { 0xFFE0, 0xFFE6 },
+ { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
+ };
+ return bisearch(ucs, double_width,
+ sizeof(double_width) / sizeof(*double_width) - 1);
+}
/* acquires console_sem */
static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1948,6 +2011,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
unsigned int currcons;
unsigned long draw_from = 0, draw_to = 0;
struct vc_data *vc;
+ unsigned char vc_attr;
+ uint8_t rescan;
+ uint8_t inverse;
+ uint8_t width;
u16 himask, charmask;
const unsigned char *orig_buf = NULL;
int orig_count;
@@ -1983,7 +2050,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
/* At this point 'buf' is guaranteed to be a kernel buffer
* and therefore no access to userspace (and therefore sleeping)
- * will be needed. The con_buf_sem serializes all tty based
+ * will be needed. The con_buf_mtx serializes all tty based
* console rendering and vcs write/read operations. We hold
* the console spinlock during the entire write.
*/
@@ -2010,53 +2077,86 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
buf++;
n++;
count--;
+ rescan = 0;
+ inverse = 0;
+ width = 1;
/* Do no translation at all in control states */
if (vc->vc_state != ESnormal) {
tc = c;
} else if (vc->vc_utf && !vc->vc_disp_ctrl) {
- /* Combine UTF-8 into Unicode */
- /* Malformed sequences as sequences of replacement glyphs */
+ /* Combine UTF-8 into Unicode in vc_utf_char.
+ * vc_utf_count is the number of continuation bytes still
+ * expected to arrive.
+ * vc_npar is the number of continuation bytes arrived so
+ * far
+ */
rescan_last_byte:
- if(c > 0x7f) {
+ if ((c & 0xc0) == 0x80) {
+ /* Continuation byte received */
+ static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
if (vc->vc_utf_count) {
- if ((c & 0xc0) == 0x80) {
- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
- if (--vc->vc_utf_count) {
- vc->vc_npar++;
- continue;
- }
- tc = c = vc->vc_utf_char;
- } else
- goto replacement_glyph;
- } else {
- vc->vc_npar = 0;
- if ((c & 0xe0) == 0xc0) {
- vc->vc_utf_count = 1;
- vc->vc_utf_char = (c & 0x1f);
- } else if ((c & 0xf0) == 0xe0) {
- vc->vc_utf_count = 2;
- vc->vc_utf_char = (c & 0x0f);
- } else if ((c & 0xf8) == 0xf0) {
- vc->vc_utf_count = 3;
- vc->vc_utf_char = (c & 0x07);
- } else if ((c & 0xfc) == 0xf8) {
- vc->vc_utf_count = 4;
- vc->vc_utf_char = (c & 0x03);
- } else if ((c & 0xfe) == 0xfc) {
- vc->vc_utf_count = 5;
- vc->vc_utf_char = (c & 0x01);
- } else
- goto replacement_glyph;
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ vc->vc_npar++;
+ if (--vc->vc_utf_count) {
+ /* Still need some bytes */
continue;
- }
+ }
+ /* Got a whole character */
+ c = vc->vc_utf_char;
+ /* Reject overlong sequences */
+ if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+ c > utf8_length_changes[vc->vc_npar])
+ c = 0xfffd;
+ } else {
+ /* Unexpected continuation byte */
+ vc->vc_utf_count = 0;
+ c = 0xfffd;
+ }
} else {
- if (vc->vc_utf_count)
- goto replacement_glyph;
- tc = c;
+ /* Single ASCII byte or first byte of a sequence received */
+ if (vc->vc_utf_count) {
+ /* Continuation byte expected */
+ rescan = 1;
+ vc->vc_utf_count = 0;
+ c = 0xfffd;
+ } else if (c > 0x7f) {
+ /* First byte of a multibyte sequence received */
+ vc->vc_npar = 0;
+ if ((c & 0xe0) == 0xc0) {
+ vc->vc_utf_count = 1;
+ vc->vc_utf_char = (c & 0x1f);
+ } else if ((c & 0xf0) == 0xe0) {
+ vc->vc_utf_count = 2;
+ vc->vc_utf_char = (c & 0x0f);
+ } else if ((c & 0xf8) == 0xf0) {
+ vc->vc_utf_count = 3;
+ vc->vc_utf_char = (c & 0x07);
+ } else if ((c & 0xfc) == 0xf8) {
+ vc->vc_utf_count = 4;
+ vc->vc_utf_char = (c & 0x03);
+ } else if ((c & 0xfe) == 0xfc) {
+ vc->vc_utf_count = 5;
+ vc->vc_utf_char = (c & 0x01);
+ } else {
+ /* 254 and 255 are invalid */
+ c = 0xfffd;
+ }
+ if (vc->vc_utf_count) {
+ /* Still need some bytes */
+ continue;
+ }
+ }
+ /* Nothing to do if an ASCII byte was received */
}
+ /* End of UTF-8 decoding. */
+ /* c is the received character, or U+FFFD for invalid sequences. */
+ /* Replace invalid Unicode code points with U+FFFD too */
+ if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+ c = 0xfffd;
+ tc = c;
} else { /* no utf or alternate charset mode */
- tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
+ tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
/* If the original code was a control character we
@@ -2076,56 +2176,80 @@ rescan_last_byte:
&& (c != 128+27);
if (vc->vc_state == ESnormal && ok) {
+ if (vc->vc_utf && !vc->vc_disp_ctrl) {
+ if (is_double_width(c))
+ width = 2;
+ }
/* Now try to find out how to display it */
tc = conv_uni_to_pc(vc, tc);
if (tc & ~charmask) {
- if ( tc == -4 ) {
- /* If we got -4 (not found) then see if we have
- defined a replacement character (U+FFFD) */
-replacement_glyph:
- tc = conv_uni_to_pc(vc, 0xfffd);
- if (!(tc & ~charmask))
- goto display_glyph;
- } else if ( tc != -3 )
- continue; /* nothing to display */
- /* no hash table or no replacement --
- * hope for the best */
- if ( c & ~charmask )
- tc = '?';
- else
- tc = c;
+ if (tc == -1 || tc == -2) {
+ continue; /* nothing to display */
+ }
+ /* Glyph not found */
+ if (!(vc->vc_utf && !vc->vc_disp_ctrl) && !(c & ~charmask)) {
+ /* In legacy mode use the glyph we get by a 1:1 mapping.
+ This would make absolutely no sense with Unicode in mind. */
+ tc = c;
+ } else {
+ /* Display U+FFFD. If it's not found, display an inverse question mark. */
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (tc < 0) {
+ inverse = 1;
+ tc = conv_uni_to_pc(vc, '?');
+ if (tc < 0) tc = '?';
+ }
+ }
}
-display_glyph:
- if (vc->vc_need_wrap || vc->vc_decim)
- FLUSH
- if (vc->vc_need_wrap) {
- cr(vc);
- lf(vc);
- }
- if (vc->vc_decim)
- insert_char(vc, 1);
- scr_writew(himask ?
- ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
- (vc->vc_attr << 8) + tc,
- (u16 *) vc->vc_pos);
- if (DO_UPDATE(vc) && draw_x < 0) {
- draw_x = vc->vc_x;
- draw_from = vc->vc_pos;
- }
- if (vc->vc_x == vc->vc_cols - 1) {
- vc->vc_need_wrap = vc->vc_decawm;
- draw_to = vc->vc_pos + 2;
+ if (!inverse) {
+ vc_attr = vc->vc_attr;
} else {
- vc->vc_x++;
- draw_to = (vc->vc_pos += 2);
+ /* invert vc_attr */
+ if (!vc->vc_can_do_color) {
+ vc_attr = (vc->vc_attr) ^ 0x08;
+ } else if (vc->vc_hi_font_mask == 0x100) {
+ vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
+ } else {
+ vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
+ }
}
- if (vc->vc_utf_count) {
- if (vc->vc_npar) {
- vc->vc_npar--;
- goto display_glyph;
+
+ while (1) {
+ if (vc->vc_need_wrap || vc->vc_decim)
+ FLUSH
+ if (vc->vc_need_wrap) {
+ cr(vc);
+ lf(vc);
+ }
+ if (vc->vc_decim)
+ insert_char(vc, 1);
+ scr_writew(himask ?
+ ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+ (vc_attr << 8) + tc,
+ (u16 *) vc->vc_pos);
+ if (DO_UPDATE(vc) && draw_x < 0) {
+ draw_x = vc->vc_x;
+ draw_from = vc->vc_pos;
+ }
+ if (vc->vc_x == vc->vc_cols - 1) {
+ vc->vc_need_wrap = vc->vc_decawm;
+ draw_to = vc->vc_pos + 2;
+ } else {
+ vc->vc_x++;
+ draw_to = (vc->vc_pos += 2);
}
- vc->vc_utf_count = 0;
+
+ if (!--width) break;
+
+ tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
+ if (tc < 0) tc = ' ';
+ }
+
+ if (rescan) {
+ rescan = 0;
+ inverse = 0;
+ width = 1;
c = orig;
goto rescan_last_byte;
}
@@ -2581,6 +2705,11 @@ static void con_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&tty_mutex);
}
+static int default_italic_color = 2; // green (ASCII)
+static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
+module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
+
static void vc_init(struct vc_data *vc, unsigned int rows,
unsigned int cols, int do_clear)
{
@@ -2600,7 +2729,8 @@ static void vc_init(struct vc_data *vc, unsigned int rows,
vc->vc_palette[k++] = default_blu[j] ;
}
vc->vc_def_color = 0x07; /* white */
- vc->vc_ulcolor = 0x0f; /* bold white */
+ vc->vc_ulcolor = default_underline_color;
+ vc->vc_itcolor = default_italic_color;
vc->vc_halfcolor = 0x08; /* grey */
init_waitqueue_head(&vc->paste_wait);
reset_terminal(vc, do_clear);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c9f2dd620e8..c6f6f420973 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -1061,7 +1061,7 @@ int vt_waitactive(int vt)
schedule();
}
remove_wait_queue(&vt_activate_queue, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
return retval;
}
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index e812aa129e2..60198a78974 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -548,7 +548,7 @@ config MV64X60_WDT
depends on WATCHDOG && MV64X60
config BOOKE_WDT
- tristate "PowerPC Book-E Watchdog Timer"
+ bool "PowerPC Book-E Watchdog Timer"
depends on WATCHDOG && (BOOKE || 4xx)
---help---
Please see Documentation/watchdog/watchdog-api.txt for
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index 84074a697dc..b36fa8de213 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -34,7 +34,6 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 1e4a8d751a7..2f7ba7a514f 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -38,7 +38,6 @@
#include <linux/init.h>
#include <linux/pnp.h>
#include <linux/fs.h>
-#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/io.h>
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index fc0e0347f9d..d4fd0fa2f17 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -25,7 +25,7 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/fs.h>
-#include <linux/pci.h>
+#include <linux/ioport.h>
#include <linux/scx200.h>
#include <asm/uaccess.h>
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 5ac309ee7f0..5cfcff53254 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -26,7 +26,7 @@
/*
* The I/O port the PMTMR resides at.
* The location is detected during setup_arch(),
- * in arch/i386/acpi/boot.c
+ * in arch/i386/kernel/acpi/boot.c
*/
u32 pmtmr_ioport __read_mostly;
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index d155e81b5c9..993fa7b8925 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -9,6 +9,9 @@ config CPU_FREQ
clock speed, you need to either enable a dynamic cpufreq governor
(see below) after boot, or use a userspace tool.
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq.
+
For details, take a look at <file:Documentation/cpu-freq>.
If in doubt, say N.
@@ -16,7 +19,7 @@ config CPU_FREQ
if CPU_FREQ
config CPU_FREQ_TABLE
- tristate
+ tristate
config CPU_FREQ_DEBUG
bool "Enable CPUfreq debugging"
@@ -32,19 +35,26 @@ config CPU_FREQ_DEBUG
4 to activate CPUfreq governor debugging
config CPU_FREQ_STAT
- tristate "CPU frequency translation statistics"
- select CPU_FREQ_TABLE
- default y
- help
- This driver exports CPU frequency statistics information through sysfs
- file system
+ tristate "CPU frequency translation statistics"
+ select CPU_FREQ_TABLE
+ default y
+ help
+ This driver exports CPU frequency statistics information through sysfs
+ file system.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_stats.
+
+ If in doubt, say N.
config CPU_FREQ_STAT_DETAILS
- bool "CPU frequency translation statistics details"
- depends on CPU_FREQ_STAT
- help
- This will show detail CPU frequency translation table in sysfs file
- system
+ bool "CPU frequency translation statistics details"
+ depends on CPU_FREQ_STAT
+ help
+ This will show detail CPU frequency translation table in sysfs file
+ system.
+
+ If in doubt, say N.
# Note that it is not currently possible to set the other governors (such as ondemand)
# as the default, since if they fail to initialise, cpufreq will be
@@ -78,29 +88,38 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE
endchoice
config CPU_FREQ_GOV_PERFORMANCE
- tristate "'performance' governor"
- help
+ tristate "'performance' governor"
+ help
This cpufreq governor sets the frequency statically to the
highest available CPU frequency.
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_performance.
+
If in doubt, say Y.
config CPU_FREQ_GOV_POWERSAVE
- tristate "'powersave' governor"
- help
+ tristate "'powersave' governor"
+ help
This cpufreq governor sets the frequency statically to the
lowest available CPU frequency.
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_powersave.
+
If in doubt, say Y.
config CPU_FREQ_GOV_USERSPACE
- tristate "'userspace' governor for userspace frequency scaling"
- help
+ tristate "'userspace' governor for userspace frequency scaling"
+ help
Enable this cpufreq governor when you either want to set the
CPU frequency manually or when an userspace program shall
be able to set the CPU dynamically, like on LART
<http://www.lartmaker.nl/>.
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_userspace.
+
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say Y.
@@ -116,6 +135,9 @@ config CPU_FREQ_GOV_ONDEMAND
do fast frequency switching (i.e, very low latency frequency
transitions).
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_ondemand.
+
For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
@@ -136,6 +158,9 @@ config CPU_FREQ_GOV_CONSERVATIVE
step-by-step latency issues between the minimum and maximum frequency
transitions in the CPU) you will probably want to use this governor.
+ To compile this driver as a module, choose M here: the
+ module will be called cpufreq_conservative.
+
For details, take a look at linux/Documentation/cpu-freq.
If in doubt, say N.
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 3162010900c..eb37fba9b7e 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -768,6 +768,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
unlock_policy_rwsem_write(cpu);
goto err_out;
}
+ policy->user_policy.min = policy->cpuinfo.min_freq;
+ policy->user_policy.max = policy->cpuinfo.max_freq;
+ policy->user_policy.governor = policy->governor;
#ifdef CONFIG_SMP
for_each_cpu_mask(j, policy->cpus) {
@@ -858,10 +861,13 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
policy->governor = NULL; /* to assure that the starting sequence is
* run in cpufreq_set_policy */
- unlock_policy_rwsem_write(cpu);
/* set default policy */
- ret = cpufreq_set_policy(&new_policy);
+ ret = __cpufreq_set_policy(policy, &new_policy);
+ policy->user_policy.policy = policy->policy;
+
+ unlock_policy_rwsem_write(cpu);
+
if (ret) {
dprintk("setting policy failed\n");
goto err_out_unregister;
@@ -1620,43 +1626,6 @@ error_out:
}
/**
- * cpufreq_set_policy - set a new CPUFreq policy
- * @policy: policy to be set.
- *
- * Sets a new CPU frequency and voltage scaling policy.
- */
-int cpufreq_set_policy(struct cpufreq_policy *policy)
-{
- int ret = 0;
- struct cpufreq_policy *data;
-
- if (!policy)
- return -EINVAL;
-
- data = cpufreq_cpu_get(policy->cpu);
- if (!data)
- return -EINVAL;
-
- if (unlikely(lock_policy_rwsem_write(policy->cpu)))
- return -EINVAL;
-
-
- ret = __cpufreq_set_policy(data, policy);
- data->user_policy.min = data->min;
- data->user_policy.max = data->max;
- data->user_policy.policy = data->policy;
- data->user_policy.governor = data->governor;
-
- unlock_policy_rwsem_write(policy->cpu);
-
- cpufreq_cpu_put(data);
-
- return ret;
-}
-EXPORT_SYMBOL(cpufreq_set_policy);
-
-
-/**
* cpufreq_update_policy - re-evaluate an existing cpufreq policy
* @cpu: CPU which shall be re-evaluated
*
@@ -1716,9 +1685,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
if (sys_dev) {
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpufreq_add_dev(sys_dev);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
if (unlikely(lock_policy_rwsem_write(cpu)))
BUG();
@@ -1730,6 +1701,7 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
__cpufreq_remove_dev(sys_dev);
break;
case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
cpufreq_add_dev(sys_dev);
break;
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 8d053f500fc..8532bb79e5f 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -470,7 +470,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
dbs_info->enable = 1;
ondemand_powersave_bias_init();
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
- INIT_DELAYED_WORK(&dbs_info->work, do_dbs_timer);
+ INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work,
delay);
}
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d1c7cac9316..d2f0cbd8b8f 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -313,9 +313,11 @@ static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
break;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index ff8c4beaace..f4c634504d1 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -1,10 +1,10 @@
menu "Hardware crypto devices"
config CRYPTO_DEV_PADLOCK
- tristate "Support for VIA PadLock ACE"
+ bool "Support for VIA PadLock ACE"
depends on X86_32
select CRYPTO_ALGAPI
- default m
+ default y
help
Some VIA processors come with an integrated crypto engine
(so called VIA PadLock ACE, Advanced Cryptography Engine)
@@ -14,16 +14,6 @@ config CRYPTO_DEV_PADLOCK
The instructions are used only when the CPU supports them.
Otherwise software encryption is used.
- Selecting M for this option will compile a helper module
- padlock.ko that should autoload all below configured
- algorithms. Don't worry if your hardware does not support
- some or all of them. In such case padlock.ko will
- simply write a single line into the kernel log informing
- about its failure but everything will keep working fine.
-
- If you are unsure, say M. The compiled module will be
- called padlock.ko
-
config CRYPTO_DEV_PADLOCK_AES
tristate "PadLock driver for AES algorithm"
depends on CRYPTO_DEV_PADLOCK
@@ -55,13 +45,13 @@ source "arch/s390/crypto/Kconfig"
config CRYPTO_DEV_GEODE
tristate "Support for the Geode LX AES engine"
- depends on CRYPTO && X86_32 && PCI
+ depends on X86_32 && PCI
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
default m
help
Say 'Y' here to use the AMD Geode LX processor on-board AES
- engine for the CryptoAPI AES alogrithm.
+ engine for the CryptoAPI AES algorithm.
To compile this driver as a module, choose M here: the module
will be called geode-aes.
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 6059cf86941..d070030f7d7 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,4 +1,3 @@
-obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
diff --git a/drivers/crypto/padlock.c b/drivers/crypto/padlock.c
deleted file mode 100644
index d6d7dd5bb98..00000000000
--- a/drivers/crypto/padlock.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for VIA PadLock hardware crypto engine.
- *
- * Copyright (c) 2006 Michal Ludvig <michal@logix.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/crypto.h>
-#include <linux/cryptohash.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/scatterlist.h>
-#include "padlock.h"
-
-static int __init padlock_init(void)
-{
- int success = 0;
-
- if (crypto_has_cipher("aes-padlock", 0, 0))
- success++;
-
- if (crypto_has_hash("sha1-padlock", 0, 0))
- success++;
-
- if (crypto_has_hash("sha256-padlock", 0, 0))
- success++;
-
- if (!success) {
- printk(KERN_WARNING PFX "No VIA PadLock drivers have been loaded.\n");
- return -ENODEV;
- }
-
- printk(KERN_NOTICE PFX "%d drivers are available.\n", success);
-
- return 0;
-}
-
-static void __exit padlock_fini(void)
-{
-}
-
-module_init(padlock_init);
-module_exit(padlock_fini);
-
-MODULE_DESCRIPTION("Load all configured PadLock algorithms.");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michal Ludvig");
-
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 161fe09a6d3..2800b3e614a 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -261,10 +261,6 @@ static void i82875p_check(struct mem_ctl_info *mci)
i82875p_process_error_info(mci, &info, 1);
}
-#ifdef CONFIG_PROC_FS
-extern int pci_proc_attach_device(struct pci_dev *);
-#endif
-
/* Return 0 on success or 1 on failure. */
static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
@@ -287,17 +283,12 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
if (dev == NULL)
return 1;
+
+ pci_bus_add_device(dev);
}
*ovrfl_pdev = dev;
-#ifdef CONFIG_PROC_FS
- if ((dev->procent == NULL) && pci_proc_attach_device(dev)) {
- i82875p_printk(KERN_ERR, "%s(): Failed to attach overflow "
- "device\n", __func__);
- return 1;
- }
-#endif /* CONFIG_PROC_FS */
if (pci_enable_device(dev)) {
i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
"device\n", __func__);
diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c
index 9b4fcac03ad..3074879f231 100644
--- a/drivers/eisa/virtual_root.c
+++ b/drivers/eisa/virtual_root.c
@@ -47,7 +47,7 @@ static void virtual_eisa_release (struct device *dev)
/* nothing really to do here */
}
-static int virtual_eisa_root_init (void)
+static int __init virtual_eisa_root_init (void)
{
int r;
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index c6281ccd4fe..1324984a4c3 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -409,7 +409,7 @@ static struct kobj_type ktype_efivar = {
};
static ssize_t
-dummy(struct subsystem *sub, char *buf)
+dummy(struct kset *kset, char *buf)
{
return -ENODEV;
}
@@ -422,7 +422,7 @@ efivar_unregister(struct efivar_entry *var)
static ssize_t
-efivar_create(struct subsystem *sub, const char *buf, size_t count)
+efivar_create(struct kset *kset, const char *buf, size_t count)
{
struct efi_variable *new_var = (struct efi_variable *)buf;
struct efivar_entry *search_efivar, *n;
@@ -480,7 +480,7 @@ efivar_create(struct subsystem *sub, const char *buf, size_t count)
}
static ssize_t
-efivar_delete(struct subsystem *sub, const char *buf, size_t count)
+efivar_delete(struct kset *kset, const char *buf, size_t count)
{
struct efi_variable *del_var = (struct efi_variable *)buf;
struct efivar_entry *search_efivar, *n;
@@ -551,11 +551,11 @@ static struct subsys_attribute *var_subsys_attrs[] = {
* the efivars driver
*/
static ssize_t
-systab_read(struct subsystem *entry, char *buf)
+systab_read(struct kset *kset, char *buf)
{
char *str = buf;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
if (efi.mps != EFI_INVALID_TABLE_ADDR)
@@ -687,7 +687,7 @@ efivars_init(void)
goto out_free;
}
- kset_set_kset_s(&vars_subsys, efi_subsys);
+ kobj_set_kset_s(&vars_subsys, efi_subsys);
error = subsystem_register(&vars_subsys);
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 850788f4dd2..8fbe9fdac12 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -36,5 +36,7 @@ config HID_DEBUG
If unsure, say N
+source "drivers/hid/usbhid/Kconfig"
+
endmenu
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 52e97d8f3c9..68d1376a53f 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -6,3 +6,7 @@ hid-objs := hid-core.o hid-input.o
obj-$(CONFIG_HID) += hid.o
hid-$(CONFIG_HID_DEBUG) += hid-debug.o
+obj-$(CONFIG_USB_HID) += usbhid/
+obj-$(CONFIG_USB_MOUSE) += usbhid/
+obj-$(CONFIG_USB_KBD) += usbhid/
+
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1cca32f4694..6ec04e79f68 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006 Jiri Kosina
+ * Copyright (c) 2006-2007 Jiri Kosina
*/
/*
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
@@ -37,7 +36,7 @@
*/
#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -872,8 +871,13 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
unsigned count = field->report_count;
unsigned offset = field->report_offset;
unsigned size = field->report_size;
+ unsigned bitsused = offset + count * size;
unsigned n;
+ /* make sure the unused bits in the last byte are zeros */
+ if (count > 0 && size > 0 && (bitsused % 8) != 0)
+ data[(bitsused-1)/8] &= (1 << (bitsused % 8)) - 1;
+
for (n = 0; n < count; n++) {
if (field->logical_minimum < 0) /* signed values */
implement(data, offset + n * size, size, s32ton(field->value[n], size));
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index c8434023ba6..a19b65ed311 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -431,6 +431,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x000: goto ignore;
case 0x034: map_key_clear(KEY_SLEEP); break;
case 0x036: map_key_clear(BTN_MISC); break;
+ /*
+ * The next three are reported by Belkin wireless
+ * keyboard (1020:0006). These values are "reserved"
+ * in HUT 1.12.
+ */
+ case 0x03a: map_key_clear(KEY_SOUND); break;
+ case 0x03b: map_key_clear(KEY_CAMERA); break;
+ case 0x03c: map_key_clear(KEY_DOCUMENTS); break;
+
case 0x040: map_key_clear(KEY_MENU); break;
case 0x045: map_key_clear(KEY_RADIO); break;
@@ -531,10 +540,26 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x302: map_key_clear(KEY_PROG2); break;
case 0x303: map_key_clear(KEY_PROG3); break;
- /* Reported on Logitech S510 wireless keyboard */
+ /* Reported on certain Logitech wireless keyboards */
+ case 0x1001: map_key_clear(KEY_MESSENGER); break;
+ case 0x1003: map_key_clear(KEY_SOUND); break;
+ case 0x1004: map_key_clear(KEY_VIDEO); break;
+ case 0x1005: map_key_clear(KEY_AUDIO); break;
+ case 0x100a: map_key_clear(KEY_DOCUMENTS); break;
+ case 0x1011: map_key_clear(KEY_PREVIOUSSONG); break;
+ case 0x1012: map_key_clear(KEY_NEXTSONG); break;
+ case 0x1013: map_key_clear(KEY_CAMERA); break;
+ case 0x1014: map_key_clear(KEY_MESSENGER); break;
+ case 0x1015: map_key_clear(KEY_RECORD); break;
+ case 0x1016: map_key_clear(KEY_PLAYER); break;
+ case 0x1017: map_key_clear(KEY_EJECTCD); break;
+ case 0x1019: map_key_clear(KEY_PROG1); break;
+ case 0x101a: map_key_clear(KEY_PROG2); break;
+ case 0x101b: map_key_clear(KEY_PROG3); break;
case 0x101f: map_key_clear(KEY_ZOOMIN); break;
case 0x1020: map_key_clear(KEY_ZOOMOUT); break;
case 0x1021: map_key_clear(KEY_ZOOMRESET); break;
+ case 0x1023: map_key_clear(KEY_CLOSE); break;
/* this one is marked as 'Rotate' */
case 0x1028: map_key_clear(KEY_ANGLE); break;
case 0x1029: map_key_clear(KEY_SHUFFLE); break;
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
new file mode 100644
index 00000000000..7c87bdc538b
--- /dev/null
+++ b/drivers/hid/usbhid/Kconfig
@@ -0,0 +1,149 @@
+comment "USB Input Devices"
+ depends on USB
+
+config USB_HID
+ tristate "USB Human Interface Device (full HID) support"
+ default y
+ depends on USB && INPUT
+ select HID
+ ---help---
+ Say Y here if you want full HID support to connect USB keyboards,
+ mice, joysticks, graphic tablets, or any other HID based devices
+ to your computer via USB, as well as Uninterruptible Power Supply
+ (UPS) and monitor control devices.
+
+ You can't use this driver and the HIDBP (Boot Protocol) keyboard
+ and mouse drivers at the same time. More information is available:
+ <file:Documentation/input/input.txt>.
+
+ If unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbhid.
+
+comment "Input core support is needed for USB HID input layer or HIDBP support"
+ depends on USB_HID && INPUT=n
+
+config USB_HIDINPUT_POWERBOOK
+ bool "Enable support for iBook/PowerBook special keys"
+ default n
+ depends on USB_HID
+ help
+ Say Y here if you want support for the special keys (Fn, Numlock) on
+ Apple iBooks and PowerBooks.
+
+ If unsure, say N.
+
+config HID_FF
+ bool "Force feedback support (EXPERIMENTAL)"
+ depends on USB_HID && EXPERIMENTAL
+ help
+ Say Y here is you want force feedback support for a few HID devices.
+ See below for a list of supported devices.
+
+ See <file:Documentation/input/ff.txt> for a description of the force
+ feedback API.
+
+ If unsure, say N.
+
+config HID_PID
+ bool "PID device support"
+ depends on HID_FF
+ help
+ Say Y here if you have a PID-compliant device and wish to enable force
+ feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
+ devices.
+
+config LOGITECH_FF
+ bool "Logitech devices support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have one of these devices:
+ - Logitech WingMan Cordless RumblePad
+ - Logitech WingMan Cordless RumblePad 2
+ - Logitech WingMan Force 3D
+ - Logitech Formula Force EX
+ - Logitech MOMO Force wheel
+
+ and if you want to enable force feedback for them.
+ Note: if you say N here, this device will still be supported, but without
+ force feedback.
+
+config PANTHERLORD_FF
+ bool "PantherLord USB/PS2 2in1 Adapter support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+ to enable force feedback support for it.
+
+config THRUSTMASTER_FF
+ bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
+ depends on HID_FF && EXPERIMENTAL
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
+ and want to enable force feedback support for it.
+ Note: if you say N here, this device will still be supported, but without
+ force feedback.
+
+config ZEROPLUS_FF
+ bool "Zeroplus based game controller support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a Zeroplus based game controller and want to
+ enable force feedback for it.
+
+config USB_HIDDEV
+ bool "/dev/hiddev raw HID device support"
+ depends on USB_HID
+ help
+ Say Y here if you want to support HID devices (from the USB
+ specification standpoint) that aren't strictly user interface
+ devices, like monitor controls and Uninterruptable Power Supplies.
+
+ This module supports these devices separately using a separate
+ event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
+
+ If unsure, say Y.
+
+menu "USB HID Boot Protocol drivers"
+ depends on USB!=n && USB_HID!=y
+
+config USB_KBD
+ tristate "USB HIDBP Keyboard (simple Boot) support"
+ depends on USB && INPUT
+ ---help---
+ Say Y here only if you are absolutely sure that you don't want
+ to use the generic HID driver for your USB keyboard and prefer
+ to use the keyboard in its limited Boot Protocol mode instead.
+
+ This is almost certainly not what you want. This is mostly
+ useful for embedded applications or simple keyboards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbkbd.
+
+ If even remotely unsure, say N.
+
+config USB_MOUSE
+ tristate "USB HIDBP Mouse (simple Boot) support"
+ depends on USB && INPUT
+ ---help---
+ Say Y here only if you are absolutely sure that you don't want
+ to use the generic HID driver for your USB mouse and prefer
+ to use the mouse in its limited Boot Protocol mode instead.
+
+ This is almost certainly not what you want. This is mostly
+ useful for embedded applications or simple mice.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbmouse.
+
+ If even remotely unsure, say N.
+
+endmenu
+
+
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
new file mode 100644
index 00000000000..8e6ab5b164a
--- /dev/null
+++ b/drivers/hid/usbhid/Makefile
@@ -0,0 +1,35 @@
+#
+# Makefile for the USB input drivers
+#
+
+# Multipart objects.
+usbhid-objs := hid-core.o hid-quirks.o
+
+# Optional parts of multipart objects.
+
+ifeq ($(CONFIG_USB_HIDDEV),y)
+ usbhid-objs += hiddev.o
+endif
+ifeq ($(CONFIG_HID_PID),y)
+ usbhid-objs += hid-pidff.o
+endif
+ifeq ($(CONFIG_LOGITECH_FF),y)
+ usbhid-objs += hid-lgff.o
+endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+ usbhid-objs += hid-plff.o
+endif
+ifeq ($(CONFIG_THRUSTMASTER_FF),y)
+ usbhid-objs += hid-tmff.o
+endif
+ifeq ($(CONFIG_ZEROPLUS_FF),y)
+ usbhid-objs += hid-zpff.o
+endif
+ifeq ($(CONFIG_HID_FF),y)
+ usbhid-objs += hid-ff.o
+endif
+
+obj-$(CONFIG_USB_HID) += usbhid.o
+obj-$(CONFIG_USB_KBD) += usbkbd.o
+obj-$(CONFIG_USB_MOUSE) += usbmouse.o
+
diff --git a/drivers/usb/input/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 827a75a186b..91d610358d5 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -39,7 +39,7 @@
*/
#define DRIVER_VERSION "v2.6"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik, Jiri Kosina"
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
@@ -53,6 +53,13 @@ static unsigned int hid_mousepoll_interval;
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
+/* Quirks specified at module load time */
+static char *quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
+module_param_array_named(quirks, quirks_param, charp, NULL, 0444);
+MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
+ " quirks=vendorID:productID:quirks"
+ " where vendorID, productID, and quirks are all in"
+ " 0x-prefixed hex");
/*
* Input submission and I/O error handler.
*/
@@ -144,6 +151,11 @@ static void hid_io_error(struct hid_device *hid)
if (usb_get_intfdata(usbhid->intf) == NULL)
goto done;
+ /* If it has been a while since the last error, we'll assume
+ * this a brand new error and reset the retry timeout. */
+ if (time_after(jiffies, usbhid->stop_retry + HZ/2))
+ usbhid->retry_delay = 0;
+
/* When an error occurs, retry at increasing intervals */
if (usbhid->retry_delay == 0) {
usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */
@@ -508,12 +520,6 @@ void usbhid_close(struct hid_device *hid)
usb_kill_urb(usbhid->urbin);
}
-#define USB_VENDOR_ID_PANJIT 0x134c
-
-#define USB_VENDOR_ID_TURBOX 0x062a
-#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
-#define USB_VENDOR_ID_CIDC 0x1677
-
/*
* Initialize all reports
*/
@@ -545,410 +551,43 @@ void usbhid_init_reports(struct hid_device *hid)
warn("timeout initializing reports");
}
-#define USB_VENDOR_ID_GTCO 0x078c
-#define USB_DEVICE_ID_GTCO_90 0x0090
-#define USB_DEVICE_ID_GTCO_100 0x0100
-#define USB_DEVICE_ID_GTCO_101 0x0101
-#define USB_DEVICE_ID_GTCO_103 0x0103
-#define USB_DEVICE_ID_GTCO_104 0x0104
-#define USB_DEVICE_ID_GTCO_105 0x0105
-#define USB_DEVICE_ID_GTCO_106 0x0106
-#define USB_DEVICE_ID_GTCO_107 0x0107
-#define USB_DEVICE_ID_GTCO_108 0x0108
-#define USB_DEVICE_ID_GTCO_200 0x0200
-#define USB_DEVICE_ID_GTCO_201 0x0201
-#define USB_DEVICE_ID_GTCO_202 0x0202
-#define USB_DEVICE_ID_GTCO_203 0x0203
-#define USB_DEVICE_ID_GTCO_204 0x0204
-#define USB_DEVICE_ID_GTCO_205 0x0205
-#define USB_DEVICE_ID_GTCO_206 0x0206
-#define USB_DEVICE_ID_GTCO_207 0x0207
-#define USB_DEVICE_ID_GTCO_300 0x0300
-#define USB_DEVICE_ID_GTCO_301 0x0301
-#define USB_DEVICE_ID_GTCO_302 0x0302
-#define USB_DEVICE_ID_GTCO_303 0x0303
-#define USB_DEVICE_ID_GTCO_304 0x0304
-#define USB_DEVICE_ID_GTCO_305 0x0305
-#define USB_DEVICE_ID_GTCO_306 0x0306
-#define USB_DEVICE_ID_GTCO_307 0x0307
-#define USB_DEVICE_ID_GTCO_308 0x0308
-#define USB_DEVICE_ID_GTCO_309 0x0309
-#define USB_DEVICE_ID_GTCO_400 0x0400
-#define USB_DEVICE_ID_GTCO_401 0x0401
-#define USB_DEVICE_ID_GTCO_402 0x0402
-#define USB_DEVICE_ID_GTCO_403 0x0403
-#define USB_DEVICE_ID_GTCO_404 0x0404
-#define USB_DEVICE_ID_GTCO_405 0x0405
-#define USB_DEVICE_ID_GTCO_500 0x0500
-#define USB_DEVICE_ID_GTCO_501 0x0501
-#define USB_DEVICE_ID_GTCO_502 0x0502
-#define USB_DEVICE_ID_GTCO_503 0x0503
-#define USB_DEVICE_ID_GTCO_504 0x0504
-#define USB_DEVICE_ID_GTCO_1000 0x1000
-#define USB_DEVICE_ID_GTCO_1001 0x1001
-#define USB_DEVICE_ID_GTCO_1002 0x1002
-#define USB_DEVICE_ID_GTCO_1003 0x1003
-#define USB_DEVICE_ID_GTCO_1004 0x1004
-#define USB_DEVICE_ID_GTCO_1005 0x1005
-#define USB_DEVICE_ID_GTCO_1006 0x1006
-
-#define USB_VENDOR_ID_WACOM 0x056a
-
-#define USB_VENDOR_ID_ACECAD 0x0460
-#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
-#define USB_DEVICE_ID_ACECAD_302 0x0008
-
-#define USB_VENDOR_ID_KBGEAR 0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
-
-#define USB_VENDOR_ID_AIPTEK 0x08ca
-#define USB_DEVICE_ID_AIPTEK_01 0x0001
-#define USB_DEVICE_ID_AIPTEK_10 0x0010
-#define USB_DEVICE_ID_AIPTEK_20 0x0020
-#define USB_DEVICE_ID_AIPTEK_21 0x0021
-#define USB_DEVICE_ID_AIPTEK_22 0x0022
-#define USB_DEVICE_ID_AIPTEK_23 0x0023
-#define USB_DEVICE_ID_AIPTEK_24 0x0024
-
-#define USB_VENDOR_ID_GRIFFIN 0x077d
-#define USB_DEVICE_ID_POWERMATE 0x0410
-#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
-
-#define USB_VENDOR_ID_ATEN 0x0557
-#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
-#define USB_DEVICE_ID_ATEN_CS124U 0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
-
-#define USB_VENDOR_ID_TOPMAX 0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
-
-#define USB_VENDOR_ID_HAPP 0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
-#define USB_DEVICE_ID_UGCI_FLYING 0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
-
-#define USB_VENDOR_ID_MGE 0x0463
-#define USB_DEVICE_ID_MGE_UPS 0xffff
-#define USB_DEVICE_ID_MGE_UPS1 0x0001
-
-#define USB_VENDOR_ID_ONTRAK 0x0a07
-#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
-
-#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-
-#define USB_VENDOR_ID_A4TECH 0x09da
-#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
-
-#define USB_VENDOR_ID_AASHIMA 0x06d6
-#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
-#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
-
-#define USB_VENDOR_ID_CYPRESS 0x04b4
-#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
-#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
-#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
-
-#define USB_VENDOR_ID_BERKSHIRE 0x0c98
-#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
-
-#define USB_VENDOR_ID_ALPS 0x0433
-#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
-
-#define USB_VENDOR_ID_SAITEK 0x06a3
-#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
-
-#define USB_VENDOR_ID_NEC 0x073e
-#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
-
-#define USB_VENDOR_ID_CHIC 0x05fe
-#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
-
-#define USB_VENDOR_ID_GLAB 0x06c2
-#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
-#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
-#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
-#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
-#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
-#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
-#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
-#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
-
-#define USB_VENDOR_ID_WISEGROUP 0x0925
-#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
-#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
-#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
-#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
-
-#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
-#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
-
-#define USB_VENDOR_ID_CODEMERCS 0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
-
-#define USB_VENDOR_ID_DELORME 0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
-#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
-
-#define USB_VENDOR_ID_MCC 0x09db
-#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
-#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
-
-#define USB_VENDOR_ID_VERNIER 0x08f7
-#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
-#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
-#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
-#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
-
-#define USB_VENDOR_ID_LD 0x0f11
-#define USB_DEVICE_ID_LD_CASSY 0x1000
-#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
-#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
-#define USB_DEVICE_ID_LD_JWM 0x1080
-#define USB_DEVICE_ID_LD_DMMP 0x1081
-#define USB_DEVICE_ID_LD_UMIP 0x1090
-#define USB_DEVICE_ID_LD_XRAY1 0x1100
-#define USB_DEVICE_ID_LD_XRAY2 0x1101
-#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
-#define USB_DEVICE_ID_LD_COM3LAB 0x2000
-#define USB_DEVICE_ID_LD_TELEPORT 0x2010
-#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
-#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
-#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
-
-#define USB_VENDOR_ID_APPLE 0x05ac
-#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
-#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
-#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
-#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
-#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217
-#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218
-#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219
-#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a
-#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b
-#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
-#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
-#define USB_DEVICE_ID_APPLE_IR 0x8240
-
-#define USB_VENDOR_ID_CHERRY 0x046a
-#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
-
-#define USB_VENDOR_ID_YEALINK 0x6993
-#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
-
-#define USB_VENDOR_ID_ALCOR 0x058f
-#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
-
-#define USB_VENDOR_ID_SUN 0x0430
-#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
-
-#define USB_VENDOR_ID_AIRCABLE 0x16CA
-#define USB_DEVICE_ID_AIRCABLE1 0x1502
-
-#define USB_VENDOR_ID_LOGITECH 0x046d
-#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101
-#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2 0xc517
-#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
-
-#define USB_VENDOR_ID_IMATION 0x0718
-#define USB_DEVICE_ID_DISC_STAKKA 0xd000
-
-#define USB_VENDOR_ID_PANTHERLORD 0x0810
-#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
-
-#define USB_VENDOR_ID_SONY 0x054c
-#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
-
/*
- * Alphabetically sorted blacklist by quirk type.
+ * Reset LEDs which BIOS might have left on. For now, just NumLock (0x01).
*/
+static int hid_find_field_early(struct hid_device *hid, unsigned int page,
+ unsigned int hid_code, struct hid_field **pfield)
+{
+ struct hid_report *report;
+ struct hid_field *field;
+ struct hid_usage *usage;
+ int i, j;
+
+ list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) {
+ for (i = 0; i < report->maxfield; i++) {
+ field = report->field[i];
+ for (j = 0; j < field->maxusage; j++) {
+ usage = &field->usage[j];
+ if ((usage->hid & HID_USAGE_PAGE) == page &&
+ (usage->hid & 0xFFFF) == hid_code) {
+ *pfield = field;
+ return j;
+ }
+ }
+ }
+ }
+ return -1;
+}
-static const struct hid_blacklist {
- __u16 idVendor;
- __u16 idProduct;
- unsigned quirks;
-} hid_blacklist[] = {
-
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
-
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
- { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-
- { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
-
- { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
-
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
-
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER_2, HID_QUIRK_LOGITECH_S510_DESCRIPTOR },
-
- { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
-
- { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
-
- { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
-
- { 0, 0 }
-};
+static void usbhid_set_leds(struct hid_device *hid)
+{
+ struct hid_field *field;
+ int offset;
+
+ if ((offset = hid_find_field_early(hid, HID_UP_LED, 0x01, &field)) != -1) {
+ hid_set_field(field, offset, 0);
+ usbhid_submit_report(hid, field->report, USB_DIR_OUT);
+ }
+}
/*
* Traverse the supplied list of reports and find the longest
@@ -1038,16 +677,16 @@ static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
}
/*
- * Logitech S510 keyboard sends in report #3 keys which are far
+ * Certain Logitech keyboards send in report #3 keys which are far
* above the logical maximum described in descriptor. This extends
* the original value of 0x28c of logical maximum to 0x104d
*/
-static void hid_fixup_s510_descriptor(unsigned char *rdesc, int rsize)
+static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
{
if (rsize >= 90 && rdesc[83] == 0x26
&& rdesc[84] == 0x8c
&& rdesc[85] == 0x02) {
- info("Fixing up Logitech S510 report descriptor");
+ info("Fixing up Logitech keyboard report descriptor");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
@@ -1059,24 +698,14 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_descriptor *hdesc;
struct hid_device *hid;
- unsigned quirks = 0, rsize = 0;
+ u32 quirks = 0;
+ unsigned rsize = 0;
char *rdesc;
int n, len, insize = 0;
struct usbhid_device *usbhid;
- /* Ignore all Wacom devices */
- if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
- return NULL;
- /* ignore all Code Mercenaries IOWarrior devices */
- if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_CODEMERCS)
- if (le16_to_cpu(dev->descriptor.idProduct) >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
- le16_to_cpu(dev->descriptor.idProduct) <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
- return NULL;
-
- for (n = 0; hid_blacklist[n].idVendor; n++)
- if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
- (hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct)))
- quirks = hid_blacklist[n].quirks;
+ quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
/* Many keyboards and mice don't like to be polled for reports,
* so we will always set the HID_QUIRK_NOGET flag for them. */
@@ -1126,8 +755,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if ((quirks & HID_QUIRK_CYMOTION))
hid_fixup_cymotion_descriptor(rdesc, rsize);
- if (quirks & HID_QUIRK_LOGITECH_S510_DESCRIPTOR)
- hid_fixup_s510_descriptor(rdesc, rsize);
+ if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
+ hid_fixup_logitech_descriptor(rdesc, rsize);
#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
@@ -1334,6 +963,8 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
usbhid_init_reports(hid);
hid_dump_device(hid);
+ if (hid->quirks & HID_QUIRK_RESET_LEDS)
+ usbhid_set_leds(hid);
if (!hidinput_connect(hid))
hid->claimed |= HID_CLAIMED_INPUT;
@@ -1448,6 +1079,9 @@ static struct usb_driver hid_driver = {
static int __init hid_init(void)
{
int retval;
+ retval = usbhid_quirks_init(quirks_param);
+ if (retval)
+ goto usbhid_quirks_init_fail;
retval = hiddev_init();
if (retval)
goto hiddev_init_fail;
@@ -1460,6 +1094,8 @@ static int __init hid_init(void)
usb_register_fail:
hiddev_exit();
hiddev_init_fail:
+ usbhid_quirks_exit();
+usbhid_quirks_init_fail:
return retval;
}
@@ -1467,6 +1103,7 @@ static void __exit hid_exit(void)
{
usb_deregister(&hid_driver);
hiddev_exit();
+ usbhid_quirks_exit();
}
module_init(hid_init);
diff --git a/drivers/usb/input/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
index e431faaa6ab..23431fbbc3d 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/hid/usbhid/hid-ff.c
@@ -56,6 +56,7 @@ static struct hid_ff_initializer inits[] = {
{ 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
{ 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
{ 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
+ { 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */
{ 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
{ 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
{ 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
@@ -64,6 +65,7 @@ static struct hid_ff_initializer inits[] = {
{ 0x810, 0x0001, hid_plff_init },
#endif
#ifdef CONFIG_THRUSTMASTER_FF
+ { 0x44f, 0xb300, hid_tmff_init },
{ 0x44f, 0xb304, hid_tmff_init },
#endif
#ifdef CONFIG_ZEROPLUS_FF
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c
index e6f3af3e66d..92d2553f17b 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/hid/usbhid/hid-lgff.c
@@ -52,6 +52,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
{ 0x046d, 0xc283, ff_joystick },
+ { 0x046d, 0xc286, ff_joystick },
{ 0x046d, 0xc294, ff_joystick },
{ 0x046d, 0xc295, ff_joystick },
{ 0x046d, 0xca03, ff_joystick },
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index f5a90e950e6..f5a90e950e6 100644
--- a/drivers/usb/input/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
diff --git a/drivers/usb/input/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
index 76d2e6e14db..76d2e6e14db 100644
--- a/drivers/usb/input/hid-plff.c
+++ b/drivers/hid/usbhid/hid-plff.c
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
new file mode 100644
index 00000000000..17a87555e32
--- /dev/null
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -0,0 +1,681 @@
+/*
+ * USB HID quirks support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/hid.h>
+
+#define USB_VENDOR_ID_A4TECH 0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
+
+#define USB_VENDOR_ID_AASHIMA 0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
+
+#define USB_VENDOR_ID_ACECAD 0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
+#define USB_DEVICE_ID_ACECAD_302 0x0008
+
+#define USB_VENDOR_ID_AIPTEK 0x08ca
+#define USB_DEVICE_ID_AIPTEK_01 0x0001
+#define USB_DEVICE_ID_AIPTEK_10 0x0010
+#define USB_DEVICE_ID_AIPTEK_20 0x0020
+#define USB_DEVICE_ID_AIPTEK_21 0x0021
+#define USB_DEVICE_ID_AIPTEK_22 0x0022
+#define USB_DEVICE_ID_AIPTEK_23 0x0023
+#define USB_DEVICE_ID_AIPTEK_24 0x0024
+
+#define USB_VENDOR_ID_AIRCABLE 0x16CA
+#define USB_DEVICE_ID_AIRCABLE1 0x1502
+
+#define USB_VENDOR_ID_ALCOR 0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
+
+#define USB_VENDOR_ID_ALPS 0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
+
+#define USB_VENDOR_ID_APPLE 0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_IR 0x8240
+
+#define USB_VENDOR_ID_ATEN 0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
+#define USB_DEVICE_ID_ATEN_CS124U 0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
+
+#define USB_VENDOR_ID_BELKIN 0x050d
+#define USB_DEVICE_ID_FLIP_KVM 0x3201
+
+#define USB_VENDOR_ID_BERKSHIRE 0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+
+#define USB_VENDOR_ID_CHERRY 0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
+
+#define USB_VENDOR_ID_CHIC 0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
+
+#define USB_VENDOR_ID_CIDC 0x1677
+
+#define USB_VENDOR_ID_CODEMERCS 0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
+
+#define USB_VENDOR_ID_CYPRESS 0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
+
+#define USB_VENDOR_ID_DELL 0x413c
+#define USB_DEVICE_ID_DELL_W7658 0x2005
+
+#define USB_VENDOR_ID_DELORME 0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#define USB_VENDOR_ID_GLAB 0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
+#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
+#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
+
+#define USB_VENDOR_ID_GRIFFIN 0x077d
+#define USB_DEVICE_ID_POWERMATE 0x0410
+#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
+
+#define USB_VENDOR_ID_GTCO 0x078c
+#define USB_DEVICE_ID_GTCO_90 0x0090
+#define USB_DEVICE_ID_GTCO_100 0x0100
+#define USB_DEVICE_ID_GTCO_101 0x0101
+#define USB_DEVICE_ID_GTCO_103 0x0103
+#define USB_DEVICE_ID_GTCO_104 0x0104
+#define USB_DEVICE_ID_GTCO_105 0x0105
+#define USB_DEVICE_ID_GTCO_106 0x0106
+#define USB_DEVICE_ID_GTCO_107 0x0107
+#define USB_DEVICE_ID_GTCO_108 0x0108
+#define USB_DEVICE_ID_GTCO_200 0x0200
+#define USB_DEVICE_ID_GTCO_201 0x0201
+#define USB_DEVICE_ID_GTCO_202 0x0202
+#define USB_DEVICE_ID_GTCO_203 0x0203
+#define USB_DEVICE_ID_GTCO_204 0x0204
+#define USB_DEVICE_ID_GTCO_205 0x0205
+#define USB_DEVICE_ID_GTCO_206 0x0206
+#define USB_DEVICE_ID_GTCO_207 0x0207
+#define USB_DEVICE_ID_GTCO_300 0x0300
+#define USB_DEVICE_ID_GTCO_301 0x0301
+#define USB_DEVICE_ID_GTCO_302 0x0302
+#define USB_DEVICE_ID_GTCO_303 0x0303
+#define USB_DEVICE_ID_GTCO_304 0x0304
+#define USB_DEVICE_ID_GTCO_305 0x0305
+#define USB_DEVICE_ID_GTCO_306 0x0306
+#define USB_DEVICE_ID_GTCO_307 0x0307
+#define USB_DEVICE_ID_GTCO_308 0x0308
+#define USB_DEVICE_ID_GTCO_309 0x0309
+#define USB_DEVICE_ID_GTCO_400 0x0400
+#define USB_DEVICE_ID_GTCO_401 0x0401
+#define USB_DEVICE_ID_GTCO_402 0x0402
+#define USB_DEVICE_ID_GTCO_403 0x0403
+#define USB_DEVICE_ID_GTCO_404 0x0404
+#define USB_DEVICE_ID_GTCO_405 0x0405
+#define USB_DEVICE_ID_GTCO_500 0x0500
+#define USB_DEVICE_ID_GTCO_501 0x0501
+#define USB_DEVICE_ID_GTCO_502 0x0502
+#define USB_DEVICE_ID_GTCO_503 0x0503
+#define USB_DEVICE_ID_GTCO_504 0x0504
+#define USB_DEVICE_ID_GTCO_1000 0x1000
+#define USB_DEVICE_ID_GTCO_1001 0x1001
+#define USB_DEVICE_ID_GTCO_1002 0x1002
+#define USB_DEVICE_ID_GTCO_1003 0x1003
+#define USB_DEVICE_ID_GTCO_1004 0x1004
+#define USB_DEVICE_ID_GTCO_1005 0x1005
+#define USB_DEVICE_ID_GTCO_1006 0x1006
+
+#define USB_VENDOR_ID_HAPP 0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
+#define USB_DEVICE_ID_UGCI_FLYING 0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+
+#define USB_VENDOR_ID_IMATION 0x0718
+#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+
+#define USB_VENDOR_ID_KBGEAR 0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
+
+#define USB_VENDOR_ID_LD 0x0f11
+#define USB_DEVICE_ID_LD_CASSY 0x1000
+#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
+#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
+#define USB_DEVICE_ID_LD_JWM 0x1080
+#define USB_DEVICE_ID_LD_DMMP 0x1081
+#define USB_DEVICE_ID_LD_UMIP 0x1090
+#define USB_DEVICE_ID_LD_XRAY1 0x1100
+#define USB_DEVICE_ID_LD_XRAY2 0x1101
+#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
+#define USB_DEVICE_ID_LD_COM3LAB 0x2000
+#define USB_DEVICE_ID_LD_TELEPORT 0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
+
+#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
+#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
+#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
+#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
+#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
+
+#define USB_VENDOR_ID_MCC 0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
+
+#define USB_VENDOR_ID_MGE 0x0463
+#define USB_DEVICE_ID_MGE_UPS 0xffff
+#define USB_DEVICE_ID_MGE_UPS1 0x0001
+
+#define USB_VENDOR_ID_NEC 0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+
+#define USB_VENDOR_ID_ONTRAK 0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
+
+#define USB_VENDOR_ID_PANJIT 0x134c
+
+#define USB_VENDOR_ID_PANTHERLORD 0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+
+#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
+#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
+
+#define USB_VENDOR_ID_SAITEK 0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
+
+#define USB_VENDOR_ID_SONY 0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+
+#define USB_VENDOR_ID_SUN 0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
+
+#define USB_VENDOR_ID_TOPMAX 0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
+
+#define USB_VENDOR_ID_TURBOX 0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+
+#define USB_VENDOR_ID_VERNIER 0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
+
+#define USB_VENDOR_ID_WACOM 0x056a
+
+#define USB_VENDOR_ID_WISEGROUP 0x0925
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
+#define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
+#define USB_VENDOR_ID_YEALINK 0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+
+/*
+ * Alphabetically sorted blacklist by quirk type.
+ */
+
+static const struct hid_blacklist {
+ __u16 idVendor;
+ __u16 idProduct;
+ __u32 quirks;
+} hid_blacklist[] = {
+
+ { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
+ { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
+
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
+
+ { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
+ { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+
+ { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
+
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
+
+ { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
+
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
+
+ { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_LOGITECH_DESCRIPTOR },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_LOGITECH_DESCRIPTOR },
+
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
+
+ { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+ { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
+
+ { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+
+ { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+ { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+ { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
+
+ { 0, 0 }
+};
+
+/* Dynamic HID quirks list - specified at runtime */
+struct quirks_list_struct {
+ struct hid_blacklist hid_bl_item;
+ struct list_head node;
+};
+
+static LIST_HEAD(dquirks_list);
+static DECLARE_RWSEM(dquirks_rwsem);
+
+/* Runtime ("dynamic") quirks manipulation functions */
+
+/**
+ * usbhid_exists_dquirk: find any dynamic quirks for a USB HID device
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ *
+ * Description:
+ * Scans dquirks_list for a matching dynamic quirk and returns
+ * the pointer to the relevant struct hid_blacklist if found.
+ * Must be called with a read lock held on dquirks_rwsem.
+ *
+ * Returns: NULL if no quirk found, struct hid_blacklist * if found.
+ */
+static struct hid_blacklist *usbhid_exists_dquirk(const u16 idVendor,
+ const u16 idProduct)
+{
+ struct quirks_list_struct *q;
+ struct hid_blacklist *bl_entry = NULL;
+
+ list_for_each_entry(q, &dquirks_list, node) {
+ if (q->hid_bl_item.idVendor == idVendor &&
+ q->hid_bl_item.idProduct == idProduct) {
+ bl_entry = &q->hid_bl_item;
+ break;
+ }
+ }
+
+ if (bl_entry != NULL)
+ dbg("Found dynamic quirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
+ bl_entry->quirks, bl_entry->idVendor,
+ bl_entry->idProduct);
+
+ return bl_entry;
+}
+
+
+/**
+ * usbhid_modify_dquirk: add/replace a HID quirk
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ * @quirks: the u32 quirks value to add/replace
+ *
+ * Description:
+ * If an dynamic quirk exists in memory for this (idVendor,
+ * idProduct) pair, replace its quirks value with what was
+ * provided. Otherwise, add the quirk to the dynamic quirks list.
+ *
+ * Returns: 0 OK, -error on failure.
+ */
+int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct,
+ const u32 quirks)
+{
+ struct quirks_list_struct *q_new, *q;
+ int list_edited = 0;
+
+ if (!idVendor) {
+ dbg("Cannot add a quirk with idVendor = 0");
+ return -EINVAL;
+ }
+
+ q_new = kmalloc(sizeof(struct quirks_list_struct), GFP_KERNEL);
+ if (!q_new) {
+ dbg("Could not allocate quirks_list_struct");
+ return -ENOMEM;
+ }
+
+ q_new->hid_bl_item.idVendor = idVendor;
+ q_new->hid_bl_item.idProduct = idProduct;
+ q_new->hid_bl_item.quirks = quirks;
+
+ down_write(&dquirks_rwsem);
+
+ list_for_each_entry(q, &dquirks_list, node) {
+
+ if (q->hid_bl_item.idVendor == idVendor &&
+ q->hid_bl_item.idProduct == idProduct) {
+
+ list_replace(&q->node, &q_new->node);
+ kfree(q);
+ list_edited = 1;
+ break;
+
+ }
+
+ }
+
+ if (!list_edited)
+ list_add_tail(&q_new->node, &dquirks_list);
+
+ up_write(&dquirks_rwsem);
+
+ return 0;
+}
+
+
+/**
+ * usbhid_remove_all_dquirks: remove all runtime HID quirks from memory
+ *
+ * Description:
+ * Free all memory associated with dynamic quirks - called before
+ * module unload.
+ *
+ */
+static void usbhid_remove_all_dquirks(void)
+{
+ struct quirks_list_struct *q, *temp;
+
+ down_write(&dquirks_rwsem);
+ list_for_each_entry_safe(q, temp, &dquirks_list, node) {
+ list_del(&q->node);
+ kfree(q);
+ }
+ up_write(&dquirks_rwsem);
+
+}
+
+/**
+ * usbhid_quirks_init: apply USB HID quirks specified at module load time
+ */
+int usbhid_quirks_init(char **quirks_param)
+{
+ u16 idVendor, idProduct;
+ u32 quirks;
+ int n = 0, m;
+
+ for (; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
+
+ m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
+ &idVendor, &idProduct, &quirks);
+
+ if (m != 3 ||
+ usbhid_modify_dquirk(idVendor, idProduct, quirks) != 0) {
+ printk(KERN_WARNING
+ "Could not parse HID quirk module param %s\n",
+ quirks_param[n]);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * usbhid_quirks_exit: release memory associated with dynamic_quirks
+ *
+ * Description:
+ * Release all memory associated with dynamic quirks. Called upon
+ * module unload.
+ *
+ * Returns: nothing
+ */
+void usbhid_quirks_exit(void)
+{
+ usbhid_remove_all_dquirks();
+}
+
+/**
+ * usbhid_exists_squirk: return any static quirks for a USB HID device
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ *
+ * Description:
+ * Given a USB vendor ID and product ID, return a pointer to
+ * the hid_blacklist entry associated with that device.
+ *
+ * Returns: pointer if quirk found, or NULL if no quirks found.
+ */
+static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
+ const u16 idProduct)
+{
+ const struct hid_blacklist *bl_entry = NULL;
+ int n = 0;
+
+ for (; hid_blacklist[n].idVendor; n++)
+ if (hid_blacklist[n].idVendor == idVendor &&
+ hid_blacklist[n].idProduct == idProduct)
+ bl_entry = &hid_blacklist[n];
+
+ if (bl_entry != NULL)
+ dbg("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
+ bl_entry->quirks, bl_entry->idVendor,
+ bl_entry->idProduct);
+ return bl_entry;
+}
+
+/**
+ * usbhid_lookup_quirk: return any quirks associated with a USB HID device
+ * @idVendor: the 16-bit USB vendor ID, in native byteorder
+ * @idProduct: the 16-bit USB product ID, in native byteorder
+ *
+ * Description:
+ * Given a USB vendor ID and product ID, return any quirks associated
+ * with that device.
+ *
+ * Returns: a u32 quirks value.
+ */
+u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
+{
+ u32 quirks = 0;
+ const struct hid_blacklist *bl_entry = NULL;
+
+ /* Ignore all Wacom devices */
+ if (idVendor == USB_VENDOR_ID_WACOM)
+ return HID_QUIRK_IGNORE;
+
+ /* ignore all Code Mercenaries IOWarrior devices */
+ if (idVendor == USB_VENDOR_ID_CODEMERCS)
+ if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+ idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+ return HID_QUIRK_IGNORE;
+
+ down_read(&dquirks_rwsem);
+ bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
+ if (!bl_entry)
+ bl_entry = usbhid_exists_squirk(idVendor, idProduct);
+ if (bl_entry)
+ quirks = bl_entry->quirks;
+ up_read(&dquirks_rwsem);
+
+ return quirks;
+}
+
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index ab67331620d..ab67331620d 100644
--- a/drivers/usb/input/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
diff --git a/drivers/usb/input/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c
index 7bd8238ca21..7bd8238ca21 100644
--- a/drivers/usb/input/hid-zpff.c
+++ b/drivers/hid/usbhid/hid-zpff.c
diff --git a/drivers/usb/input/hiddev.c b/drivers/hid/usbhid/hiddev.c
index a8b3d66cd49..a8b3d66cd49 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
diff --git a/drivers/usb/input/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 0023f96d429..0023f96d429 100644
--- a/drivers/usb/input/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
diff --git a/drivers/usb/input/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 3749f4a235f..65aa12e8d7b 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -228,6 +228,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
struct usb_kbd *kbd;
struct input_dev *input_dev;
int i, pipe, maxp;
+ int error = -ENOMEM;
interface = iface->cur_altsetting;
@@ -306,15 +307,19 @@ static int usb_kbd_probe(struct usb_interface *iface,
kbd->led->transfer_dma = kbd->leds_dma;
kbd->led->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
- input_register_device(kbd->dev);
+ error = input_register_device(kbd->dev);
+ if (error)
+ goto fail2;
usb_set_intfdata(iface, kbd);
return 0;
-fail2: usb_kbd_free_mem(dev, kbd);
-fail1: input_free_device(input_dev);
+fail2:
+ usb_kbd_free_mem(dev, kbd);
+fail1:
+ input_free_device(input_dev);
kfree(kbd);
- return -ENOMEM;
+ return error;
}
static void usb_kbd_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/input/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 692fd608777..573776d865e 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -120,6 +120,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
struct usb_mouse *mouse;
struct input_dev *input_dev;
int pipe, maxp;
+ int error = -ENOMEM;
interface = intf->cur_altsetting;
@@ -188,15 +189,21 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
mouse->irq->transfer_dma = mouse->data_dma;
mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_register_device(mouse->dev);
+ error = input_register_device(mouse->dev);
+ if (error)
+ goto fail3;
usb_set_intfdata(intf, mouse);
return 0;
-fail2: usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
-fail1: input_free_device(input_dev);
+fail3:
+ usb_free_urb(mouse->irq);
+fail2:
+ usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
+fail1:
+ input_free_device(input_dev);
kfree(mouse);
- return -ENOMEM;
+ return error;
}
static void usb_mouse_disconnect(struct usb_interface *intf)
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6d105a1d41b..3ba3a5221c4 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -2,9 +2,7 @@
# Hardware monitoring chip drivers configuration
#
-menu "Hardware Monitoring support"
-
-config HWMON
+menuconfig HWMON
tristate "Hardware Monitoring support"
default y
help
@@ -23,13 +21,15 @@ config HWMON
This support can also be built as a module. If so, the module
will be called hwmon.
+if HWMON
+
config HWMON_VID
tristate
default n
config SENSORS_ABITUGURU
tristate "Abit uGuru"
- depends on HWMON && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get support for the Abit uGuru chips
sensor part. The voltage and frequency control parts of the Abit
@@ -39,9 +39,19 @@ config SENSORS_ABITUGURU
This driver can also be built as a module. If so, the module
will be called abituguru.
+config SENSORS_AD7418
+ tristate "Analog Devices AD7416, AD7417 and AD7418"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the Analog Devices
+ AD7416, AD7417 and AD7418 temperature monitoring chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called ad7418.
+
config SENSORS_ADM1021
tristate "Analog Devices ADM1021 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for Analog Devices ADM1021
and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
@@ -53,7 +63,7 @@ config SENSORS_ADM1021
config SENSORS_ADM1025
tristate "Analog Devices ADM1025 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1025
@@ -64,7 +74,7 @@ config SENSORS_ADM1025
config SENSORS_ADM1026
tristate "Analog Devices ADM1026 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1026
@@ -75,7 +85,7 @@ config SENSORS_ADM1026
config SENSORS_ADM1029
tristate "Analog Devices ADM1029"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for Analog Devices ADM1029
sensor chip.
@@ -86,7 +96,7 @@ config SENSORS_ADM1029
config SENSORS_ADM1031
tristate "Analog Devices ADM1031 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for Analog Devices ADM1031
and ADM1030 sensor chips.
@@ -96,7 +106,7 @@ config SENSORS_ADM1031
config SENSORS_ADM9240
tristate "Analog Devices ADM9240 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM9240,
@@ -107,7 +117,7 @@ config SENSORS_ADM9240
config SENSORS_K8TEMP
tristate "AMD Athlon64/FX or Opteron temperature sensor"
- depends on HWMON && X86 && PCI && EXPERIMENTAL
+ depends on X86 && PCI && EXPERIMENTAL
help
If you say yes here you get support for the temperature
sensor(s) inside your CPU. Supported is whole AMD K8
@@ -119,7 +129,7 @@ config SENSORS_K8TEMP
config SENSORS_AMS
tristate "Apple Motion Sensor driver"
- depends on HWMON && PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
+ depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL
help
Support for the motion sensor included in PowerBooks. Includes
implementations for PMU and I2C.
@@ -144,7 +154,7 @@ config SENSORS_AMS_I2C
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the ASB100 Bach sensor
@@ -155,7 +165,7 @@ config SENSORS_ASB100
config SENSORS_ATXP1
tristate "Attansic ATXP1 VID controller"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the Attansic ATXP1 VID
@@ -169,7 +179,7 @@ config SENSORS_ATXP1
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for Dallas Semiconductor
DS1621 and DS1625 sensor chips.
@@ -179,7 +189,7 @@ config SENSORS_DS1621
config SENSORS_F71805F
tristate "Fintek F71805F/FG and F71872F/FG"
- depends on HWMON && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get support for hardware monitoring
features of the Fintek F71805F/FG and F71872F/FG Super-I/O
@@ -190,7 +200,7 @@ config SENSORS_F71805F
config SENSORS_FSCHER
tristate "FSC Hermes"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -200,7 +210,7 @@ config SENSORS_FSCHER
config SENSORS_FSCPOS
tristate "FSC Poseidon"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -210,7 +220,7 @@ config SENSORS_FSCPOS
config SENSORS_GL518SM
tristate "Genesys Logic GL518SM"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for Genesys Logic GL518SM
sensor chips.
@@ -220,7 +230,7 @@ config SENSORS_GL518SM
config SENSORS_GL520SM
tristate "Genesys Logic GL520SM"
- depends on HWMON && I2C
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for Genesys Logic GL520SM
@@ -229,9 +239,17 @@ config SENSORS_GL520SM
This driver can also be built as a module. If so, the module
will be called gl520sm.
+config SENSORS_CORETEMP
+ tristate "Intel Core (2) Duo/Solo temperature sensor"
+ depends on X86 && EXPERIMENTAL
+ help
+ If you say yes here you get support for the temperature
+ sensor inside your CPU. Supported all are all known variants
+ of Intel Core family.
+
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
- depends on HWMON && I2C
+ depends on I2C
select I2C_ISA
select HWMON_VID
help
@@ -243,7 +261,7 @@ config SENSORS_IT87
config SENSORS_LM63
tristate "National Semiconductor LM63"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for the National Semiconductor
LM63 remote diode digital temperature sensor with integrated fan
@@ -255,7 +273,7 @@ config SENSORS_LM63
config SENSORS_LM70
tristate "National Semiconductor LM70"
- depends on HWMON && SPI_MASTER && EXPERIMENTAL
+ depends on SPI_MASTER && EXPERIMENTAL
help
If you say yes here you get support for the National Semiconductor
LM70 digital temperature sensor chip.
@@ -265,7 +283,7 @@ config SENSORS_LM70
config SENSORS_LM75
tristate "National Semiconductor LM75 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for National Semiconductor LM75
sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
@@ -280,7 +298,7 @@ config SENSORS_LM75
config SENSORS_LM77
tristate "National Semiconductor LM77"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for National Semiconductor LM77
sensor chips.
@@ -290,8 +308,7 @@ config SENSORS_LM77
config SENSORS_LM78
tristate "National Semiconductor LM78 and compatibles"
- depends on HWMON && I2C
- select I2C_ISA
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM78,
@@ -302,7 +319,7 @@ config SENSORS_LM78
config SENSORS_LM80
tristate "National Semiconductor LM80"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for National Semiconductor
LM80 sensor chips.
@@ -312,7 +329,7 @@ config SENSORS_LM80
config SENSORS_LM83
tristate "National Semiconductor LM83 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for National Semiconductor
LM82 and LM83 sensor chips.
@@ -322,7 +339,7 @@ config SENSORS_LM83
config SENSORS_LM85
tristate "National Semiconductor LM85 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM85
@@ -333,7 +350,7 @@ config SENSORS_LM85
config SENSORS_LM87
tristate "National Semiconductor LM87"
- depends on HWMON && I2C
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
@@ -344,7 +361,7 @@ config SENSORS_LM87
config SENSORS_LM90
tristate "National Semiconductor LM90 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
@@ -358,7 +375,7 @@ config SENSORS_LM90
config SENSORS_LM92
tristate "National Semiconductor LM92 and compatibles"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for National Semiconductor LM92
and Maxim MAX6635 sensor chips.
@@ -368,16 +385,26 @@ config SENSORS_LM92
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for MAX1619 sensor chip.
This driver can also be built as a module. If so, the module
will be called max1619.
+config SENSORS_MAX6650
+ tristate "Maxim MAX6650 sensor chip"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for the MAX6650 / MAX6651
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6650.
+
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select I2C_ISA
select HWMON_VID
help
@@ -392,7 +419,7 @@ config SENSORS_PC87360
config SENSORS_PC87427
tristate "National Semiconductor PC87427"
- depends on HWMON && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get access to the hardware monitoring
functions of the National Semiconductor PC87427 Super-I/O chip.
@@ -405,7 +432,7 @@ config SENSORS_PC87427
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
- depends on HWMON && I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI && EXPERIMENTAL
select I2C_ISA
help
If you say yes here you get support for the integrated sensors in
@@ -416,28 +443,28 @@ config SENSORS_SIS5595
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
- depends on HWMON && I2C
- select I2C_ISA
help
If you say yes here you get support for the integrated fan
monitoring and control capabilities of the SMSC LPC47B27x,
LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x,
- LPC47M192 and LPC47M997 chips.
+ LPC47M192, LPC47M292 and LPC47M997 chips.
- The temperature and voltage sensor features of the LPC47M192
- and LPC47M997 are supported by another driver, select also
- "SMSC LPC47M192 and compatibles" below for those.
+ The temperature and voltage sensor features of the LPC47M15x,
+ LPC47M192, LPC47M292 and LPC47M997 are supported by another
+ driver, select also "SMSC LPC47M192 and compatibles" below for
+ those.
This driver can also be built as a module. If so, the module
will be called smsc47m1.
config SENSORS_SMSC47M192
tristate "SMSC LPC47M192 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the temperature and
- voltage sensors of the SMSC LPC47M192 and LPC47M997 chips.
+ voltage sensors of the SMSC LPC47M192, LPC47M15x, LPC47M292
+ and LPC47M997 chips.
The fan monitoring and control capabilities of these chips
are supported by another driver, select
@@ -449,8 +476,7 @@ config SENSORS_SMSC47M192
config SENSORS_SMSC47B397
tristate "SMSC LPC47B397-NC"
- depends on HWMON && I2C && EXPERIMENTAL
- select I2C_ISA
+ depends on EXPERIMENTAL
help
If you say yes here you get support for the SMSC LPC47B397-NC
sensor chip.
@@ -460,7 +486,7 @@ config SENSORS_SMSC47B397
config SENSORS_VIA686A
tristate "VIA686A"
- depends on HWMON && I2C && PCI
+ depends on I2C && PCI
select I2C_ISA
help
If you say yes here you get support for the integrated sensors in
@@ -471,7 +497,7 @@ config SENSORS_VIA686A
config SENSORS_VT1211
tristate "VIA VT1211"
- depends on HWMON && EXPERIMENTAL
+ depends on EXPERIMENTAL
select HWMON_VID
help
If you say yes here then you get support for hardware monitoring
@@ -482,7 +508,7 @@ config SENSORS_VT1211
config SENSORS_VT8231
tristate "VIA VT8231"
- depends on HWMON && I2C && PCI && EXPERIMENTAL
+ depends on I2C && PCI && EXPERIMENTAL
select HWMON_VID
select I2C_ISA
help
@@ -494,8 +520,7 @@ config SENSORS_VT8231
config SENSORS_W83781D
tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
- depends on HWMON && I2C
- select I2C_ISA
+ depends on I2C
select HWMON_VID
help
If you say yes here you get support for the Winbond W8378x series
@@ -507,7 +532,7 @@ config SENSORS_W83781D
config SENSORS_W83791D
tristate "Winbond W83791D"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the Winbond W83791D chip.
@@ -517,7 +542,7 @@ config SENSORS_W83791D
config SENSORS_W83792D
tristate "Winbond W83792D"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Winbond W83792D chip.
@@ -526,7 +551,7 @@ config SENSORS_W83792D
config SENSORS_W83793
tristate "Winbond W83793"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select HWMON_VID
help
If you say yes here you get support for the Winbond W83793
@@ -537,7 +562,7 @@ config SENSORS_W83793
config SENSORS_W83L785TS
tristate "Winbond W83L785TS-S"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Winbond W83L785TS-S
sensor chip, which is used on the Asus A7N8X, among other
@@ -548,8 +573,6 @@ config SENSORS_W83L785TS
config SENSORS_W83627HF
tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF"
- depends on HWMON && I2C
- select I2C_ISA
select HWMON_VID
help
If you say yes here you get support for the Winbond W836X7 series
@@ -561,7 +584,7 @@ config SENSORS_W83627HF
config SENSORS_W83627EHF
tristate "Winbond W83627EHF"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
select I2C_ISA
help
If you say yes here you get preliminary support for the hardware
@@ -577,7 +600,7 @@ config SENSORS_W83627EHF
config SENSORS_HDAPS
tristate "IBM Hard Drive Active Protection System (hdaps)"
- depends on HWMON && INPUT && X86
+ depends on INPUT && X86
default n
help
This driver provides support for the IBM Hard Drive Active Protection
@@ -594,9 +617,32 @@ config SENSORS_HDAPS
Say Y here if you have an applicable laptop and want to experience
the awesome power of hdaps.
+config SENSORS_APPLESMC
+ tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
+ depends on HWMON && INPUT && X86
+ select NEW_LEDS
+ select LEDS_CLASS
+ default n
+ help
+ This driver provides support for the Apple System Management
+ Controller, which provides an accelerometer (Apple Sudden Motion
+ Sensor), light sensors, temperature sensors, keyboard backlight
+ control and fan control.
+
+ Only Intel-based Apple's computers are supported (MacBook Pro,
+ MacBook, MacMini).
+
+ Data from the different sensors, keyboard backlight control and fan
+ control are accessible via sysfs.
+
+ This driver also provides an absolute input class device, allowing
+ the laptop to act as a pinball machine-esque joystick.
+
+ Say Y here if you have an applicable laptop and want to experience
+ the awesome power of applesmc.
+
config HWMON_DEBUG_CHIP
bool "Hardware Monitoring Chip debugging messages"
- depends on HWMON
default n
help
Say Y here if you want the I2C chip drivers to produce a bunch of
@@ -604,4 +650,4 @@ config HWMON_DEBUG_CHIP
a problem with I2C support and want to see more of what is going
on.
-endmenu
+endif # HWMON
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4165c27a2f2..cfaf338919d 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -14,14 +14,17 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
+obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o
obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
+obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
@@ -43,6 +46,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
+obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c
new file mode 100644
index 00000000000..cc8b624a1e5
--- /dev/null
+++ b/drivers/hwmon/ad7418.c
@@ -0,0 +1,373 @@
+/*
+ * An hwmon driver for the Analog Devices AD7416/17/18
+ * Copyright (C) 2006-07 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * Based on lm75.c
+ * Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+ *
+ * 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 - version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#include "lm75.h"
+
+#define DRV_VERSION "0.3"
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END };
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418);
+
+/* AD7418 registers */
+#define AD7418_REG_TEMP_IN 0x00
+#define AD7418_REG_CONF 0x01
+#define AD7418_REG_TEMP_HYST 0x02
+#define AD7418_REG_TEMP_OS 0x03
+#define AD7418_REG_ADC 0x04
+#define AD7418_REG_CONF2 0x05
+
+#define AD7418_REG_ADC_CH(x) ((x) << 5)
+#define AD7418_CH_TEMP AD7418_REG_ADC_CH(0)
+
+static const u8 AD7418_REG_TEMP[] = { AD7418_REG_TEMP_IN,
+ AD7418_REG_TEMP_HYST,
+ AD7418_REG_TEMP_OS };
+
+struct ad7418_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct attribute_group attrs;
+ enum chips type;
+ struct mutex lock;
+ int adc_max; /* number of ADC channels */
+ char valid;
+ unsigned long last_updated; /* In jiffies */
+ s16 temp[3]; /* Register values */
+ u16 in[4];
+};
+
+static int ad7418_attach_adapter(struct i2c_adapter *adapter);
+static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ad7418_detach_client(struct i2c_client *client);
+
+static struct i2c_driver ad7418_driver = {
+ .driver = {
+ .name = "ad7418",
+ },
+ .attach_adapter = ad7418_attach_adapter,
+ .detach_client = ad7418_detach_client,
+};
+
+/* All registers are word-sized, except for the configuration registers.
+ * AD7418 uses a high-byte first convention. Do NOT use those functions to
+ * access the configuration registers CONF and CONF2, as they are byte-sized.
+ */
+static inline int ad7418_read(struct i2c_client *client, u8 reg)
+{
+ return swab16(i2c_smbus_read_word_data(client, reg));
+}
+
+static inline int ad7418_write(struct i2c_client *client, u8 reg, u16 value)
+{
+ return i2c_smbus_write_word_data(client, reg, swab16(value));
+}
+
+static void ad7418_init_client(struct i2c_client *client)
+{
+ struct ad7418_data *data = i2c_get_clientdata(client);
+
+ int reg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
+ if (reg < 0) {
+ dev_err(&client->dev, "cannot read configuration register\n");
+ } else {
+ dev_info(&client->dev, "configuring for mode 1\n");
+ i2c_smbus_write_byte_data(client, AD7418_REG_CONF, reg & 0xfe);
+
+ if (data->type == ad7417 || data->type == ad7418)
+ i2c_smbus_write_byte_data(client,
+ AD7418_REG_CONF2, 0x00);
+ }
+}
+
+static struct ad7418_data *ad7418_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ad7418_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->lock);
+
+ if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+ || !data->valid) {
+ u8 cfg;
+ int i, ch;
+
+ /* read config register and clear channel bits */
+ cfg = i2c_smbus_read_byte_data(client, AD7418_REG_CONF);
+ cfg &= 0x1F;
+
+ i2c_smbus_write_byte_data(client, AD7418_REG_CONF,
+ cfg | AD7418_CH_TEMP);
+ udelay(30);
+
+ for (i = 0; i < 3; i++) {
+ data->temp[i] = ad7418_read(client, AD7418_REG_TEMP[i]);
+ }
+
+ for (i = 0, ch = 4; i < data->adc_max; i++, ch--) {
+ i2c_smbus_write_byte_data(client,
+ AD7418_REG_CONF,
+ cfg | AD7418_REG_ADC_CH(ch));
+
+ udelay(15);
+ data->in[data->adc_max - 1 - i] =
+ ad7418_read(client, AD7418_REG_ADC);
+ }
+
+ /* restore old configuration value */
+ ad7418_write(client, AD7418_REG_CONF, cfg);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->lock);
+
+ return data;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct ad7418_data *data = ad7418_update_device(dev);
+ return sprintf(buf, "%d\n",
+ LM75_TEMP_FROM_REG(data->temp[attr->index]));
+}
+
+static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct ad7418_data *data = ad7418_update_device(dev);
+
+ return sprintf(buf, "%d\n",
+ ((data->in[attr->index] >> 6) * 2500 + 512) / 1024);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ad7418_data *data = i2c_get_clientdata(client);
+ int temp = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->lock);
+ data->temp[attr->index] = LM75_TEMP_TO_REG(temp);
+ ad7418_write(client, AD7418_REG_TEMP[attr->index], data->temp[attr->index]);
+ mutex_unlock(&data->lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ show_temp, set_temp, 2);
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 3);
+
+static int ad7418_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON))
+ return 0;
+ return i2c_probe(adapter, &addr_data, ad7418_detect);
+}
+
+static struct attribute *ad7416_attributes[] = {
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL
+};
+
+static struct attribute *ad7417_attributes[] = {
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ NULL
+};
+
+static struct attribute *ad7418_attributes[] = {
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ NULL
+};
+
+static int ad7418_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct ad7418_data *data;
+ int err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA))
+ goto exit;
+
+ if (!(data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &ad7418_driver;
+
+ i2c_set_clientdata(client, data);
+
+ mutex_init(&data->lock);
+
+ /* AD7418 has a curious behaviour on registers 6 and 7. They
+ * both always read 0xC071 and are not documented on the datasheet.
+ * We use them to detect the chip.
+ */
+ if (kind <= 0) {
+ int reg, reg6, reg7;
+
+ /* the AD7416 lies within this address range, but I have
+ * no means to check.
+ */
+ if (address >= 0x48 && address <= 0x4f) {
+ /* XXX add tests for AD7416 here */
+ /* data->type = ad7416; */
+ }
+ /* here we might have AD7417 or AD7418 */
+ else if (address >= 0x28 && address <= 0x2f) {
+ reg6 = i2c_smbus_read_word_data(client, 0x06);
+ reg7 = i2c_smbus_read_word_data(client, 0x07);
+
+ if (address == 0x28 && reg6 == 0xC071 && reg7 == 0xC071)
+ data->type = ad7418;
+
+ /* XXX add tests for AD7417 here */
+
+
+ /* both AD7417 and AD7418 have bits 0-5 of
+ * the CONF2 register at 0
+ */
+ reg = i2c_smbus_read_byte_data(client,
+ AD7418_REG_CONF2);
+ if (reg & 0x3F)
+ data->type = any_chip; /* detection failed */
+ }
+ } else {
+ dev_dbg(&adapter->dev, "detection forced\n");
+ }
+
+ if (kind > 0)
+ data->type = kind;
+ else if (kind < 0 && data->type == any_chip) {
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ switch (data->type) {
+ case any_chip:
+ case ad7416:
+ data->adc_max = 0;
+ data->attrs.attrs = ad7416_attributes;
+ strlcpy(client->name, "ad7416", I2C_NAME_SIZE);
+ break;
+
+ case ad7417:
+ data->adc_max = 4;
+ data->attrs.attrs = ad7417_attributes;
+ strlcpy(client->name, "ad7417", I2C_NAME_SIZE);
+ break;
+
+ case ad7418:
+ data->adc_max = 1;
+ data->attrs.attrs = ad7418_attributes;
+ strlcpy(client->name, "ad7418", I2C_NAME_SIZE);
+ break;
+ }
+
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ dev_info(&client->dev, "%s chip found\n", client->name);
+
+ /* Initialize the AD7418 chip */
+ ad7418_init_client(client);
+
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
+ goto exit_detach;
+
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int ad7418_detach_client(struct i2c_client *client)
+{
+ struct ad7418_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+}
+
+static int __init ad7418_init(void)
+{
+ return i2c_add_driver(&ad7418_driver);
+}
+
+static void __exit ad7418_exit(void)
+{
+ i2c_del_driver(&ad7418_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("AD7416/17/18 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ad7418_init);
+module_exit(ad7418_exit);
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index f1f0f5d0442..6db97373972 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -141,10 +141,10 @@ static void ams_worker(struct work_struct *work)
int ams_sensor_attach(void)
{
int result;
- u32 *prop;
+ const u32 *prop;
/* Get orientation */
- prop = (u32*)get_property(ams_info.of_node, "orientation", NULL);
+ prop = of_get_property(ams_info.of_node, "orientation", NULL);
if (!prop)
return -ENODEV;
ams_info.orient1 = *prop;
@@ -208,20 +208,17 @@ int __init ams_init(void)
#ifdef CONFIG_SENSORS_AMS_I2C
np = of_find_node_by_name(NULL, "accelerometer");
- if (np && device_is_compatible(np, "AAPL,accelerometer_1"))
+ if (np && of_device_is_compatible(np, "AAPL,accelerometer_1"))
/* Found I2C motion sensor */
return ams_i2c_init(np);
#endif
#ifdef CONFIG_SENSORS_AMS_PMU
np = of_find_node_by_name(NULL, "sms");
- if (np && device_is_compatible(np, "sms"))
+ if (np && of_device_is_compatible(np, "sms"))
/* Found PMU motion sensor */
return ams_pmu_init(np);
#endif
-
- printk(KERN_ERR "ams: No motion sensor found.\n");
-
return -ENODEV;
}
diff --git a/drivers/hwmon/ams/ams-i2c.c b/drivers/hwmon/ams/ams-i2c.c
index 0d24bdfea53..957760536a4 100644
--- a/drivers/hwmon/ams/ams-i2c.c
+++ b/drivers/hwmon/ams/ams-i2c.c
@@ -85,17 +85,17 @@ static int ams_i2c_write(u8 reg, u8 value)
static int ams_i2c_cmd(enum ams_i2c_cmd cmd)
{
s32 result;
- int remaining = HZ / 20;
+ int count = 3;
ams_i2c_write(AMS_COMMAND, cmd);
- mdelay(5);
+ msleep(5);
- while (remaining) {
+ while (count--) {
result = ams_i2c_read(AMS_COMMAND);
if (result == 0 || result & 0x80)
return 0;
- remaining = schedule_timeout(remaining);
+ schedule_timeout_uninterruptible(HZ / 20);
}
return -1;
@@ -263,7 +263,7 @@ int __init ams_i2c_init(struct device_node *np)
{
char *tmp_bus;
int result;
- u32 *prop;
+ const u32 *prop;
mutex_lock(&ams_info.lock);
@@ -276,7 +276,7 @@ int __init ams_i2c_init(struct device_node *np)
ams_info.bustype = BUS_I2C;
/* look for bus either using "reg" or by path */
- prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+ prop = of_get_property(ams_info.of_node, "reg", NULL);
if (!prop) {
result = -ENODEV;
diff --git a/drivers/hwmon/ams/ams-pmu.c b/drivers/hwmon/ams/ams-pmu.c
index 4636ae031a5..9463e9768f6 100644
--- a/drivers/hwmon/ams/ams-pmu.c
+++ b/drivers/hwmon/ams/ams-pmu.c
@@ -146,7 +146,7 @@ static void ams_pmu_exit(void)
int __init ams_pmu_init(struct device_node *np)
{
- u32 *prop;
+ const u32 *prop;
int result;
mutex_lock(&ams_info.lock);
@@ -160,7 +160,7 @@ int __init ams_pmu_init(struct device_node *np)
ams_info.bustype = BUS_HOST;
/* Get PMU command, should be 0x4e, but we can never know */
- prop = (u32*)get_property(ams_info.of_node, "reg", NULL);
+ prop = of_get_property(ams_info.of_node, "reg", NULL);
if (!prop) {
result = -ENODEV;
goto exit;
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
new file mode 100644
index 00000000000..b51c104a28a
--- /dev/null
+++ b/drivers/hwmon/applesmc.c
@@ -0,0 +1,1340 @@
+/*
+ * drivers/hwmon/applesmc.c - driver for Apple's SMC (accelerometer, temperature
+ * sensors, fan control, keyboard backlight control) used in Intel-based Apple
+ * computers.
+ *
+ * Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
+ *
+ * Based on hdaps.c driver:
+ * Copyright (C) 2005 Robert Love <rml@novell.com>
+ * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com>
+ *
+ * Fan control based on smcFanControl:
+ * Copyright (C) 2006 Hendrik Holtmann <holtmann@mac.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License v2 as published by the
+ * Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/dmi.h>
+#include <linux/mutex.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+#include <linux/leds.h>
+#include <linux/hwmon.h>
+#include <linux/workqueue.h>
+
+/* data port used by Apple SMC */
+#define APPLESMC_DATA_PORT 0x300
+/* command/status port used by Apple SMC */
+#define APPLESMC_CMD_PORT 0x304
+
+#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
+
+#define APPLESMC_MAX_DATA_LENGTH 32
+
+#define APPLESMC_STATUS_MASK 0x0f
+#define APPLESMC_READ_CMD 0x10
+#define APPLESMC_WRITE_CMD 0x11
+#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
+#define APPLESMC_GET_KEY_TYPE_CMD 0x13
+
+#define KEY_COUNT_KEY "#KEY" /* r-o ui32 */
+
+#define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */
+#define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */
+#define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */
+
+#define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */
+
+#define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Z_KEY "MO_Z" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_KEY "MOCN" /* r/w ui16 */
+
+#define FANS_COUNT "FNum" /* r-o ui8 */
+#define FANS_MANUAL "FS! " /* r-w ui16 */
+#define FAN_ACTUAL_SPEED "F0Ac" /* r-o fpe2 (2 bytes) */
+#define FAN_MIN_SPEED "F0Mn" /* r-o fpe2 (2 bytes) */
+#define FAN_MAX_SPEED "F0Mx" /* r-o fpe2 (2 bytes) */
+#define FAN_SAFE_SPEED "F0Sf" /* r-o fpe2 (2 bytes) */
+#define FAN_TARGET_SPEED "F0Tg" /* r-w fpe2 (2 bytes) */
+#define FAN_POSITION "F0ID" /* r-o char[16] */
+
+/*
+ * Temperature sensors keys (sp78 - 2 bytes).
+ * First set for Macbook(Pro), second for Macmini.
+ */
+static const char* temperature_sensors_sets[][13] = {
+ { "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
+ "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
+ { "TC0D", "TC0P", NULL }
+};
+
+/* List of keys used to read/write fan speeds */
+static const char* fan_speed_keys[] = {
+ FAN_ACTUAL_SPEED,
+ FAN_MIN_SPEED,
+ FAN_MAX_SPEED,
+ FAN_SAFE_SPEED,
+ FAN_TARGET_SPEED
+};
+
+#define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */
+#define INIT_WAIT_MSECS 50 /* ... in 50ms increments */
+
+#define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */
+#define APPLESMC_INPUT_FUZZ 4 /* input event threshold */
+#define APPLESMC_INPUT_FLAT 4
+
+#define SENSOR_X 0
+#define SENSOR_Y 1
+#define SENSOR_Z 2
+
+/* Structure to be passed to DMI_MATCH function */
+struct dmi_match_data {
+/* Indicates whether this computer has an accelerometer. */
+ int accelerometer;
+/* Indicates whether this computer has light sensors and keyboard backlight. */
+ int light;
+/* Indicates which temperature sensors set to use. */
+ int temperature_set;
+};
+
+static const int debug;
+static struct platform_device *pdev;
+static s16 rest_x;
+static s16 rest_y;
+static struct timer_list applesmc_timer;
+static struct input_dev *applesmc_idev;
+static struct class_device *hwmon_class_dev;
+
+/* Indicates whether this computer has an accelerometer. */
+static unsigned int applesmc_accelerometer;
+
+/* Indicates whether this computer has light sensors and keyboard backlight. */
+static unsigned int applesmc_light;
+
+/* Indicates which temperature sensors set to use. */
+static unsigned int applesmc_temperature_set;
+
+static struct mutex applesmc_lock;
+
+/*
+ * Last index written to key_at_index sysfs file, and value to use for all other
+ * key_at_index_* sysfs files.
+ */
+static unsigned int key_at_index;
+
+static struct workqueue_struct *applesmc_led_wq;
+
+/*
+ * __wait_status - Wait up to 2ms for the status port to get a certain value
+ * (masked with 0x0f), returning zero if the value is obtained. Callers must
+ * hold applesmc_lock.
+ */
+static int __wait_status(u8 val)
+{
+ unsigned int i;
+
+ val = val & APPLESMC_STATUS_MASK;
+
+ for (i = 0; i < 200; i++) {
+ if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val) {
+ if (debug)
+ printk(KERN_DEBUG
+ "Waited %d us for status %x\n",
+ i*10, val);
+ return 0;
+ }
+ udelay(10);
+ }
+
+ printk(KERN_WARNING "applesmc: wait status failed: %x != %x\n",
+ val, inb(APPLESMC_CMD_PORT));
+
+ return -EIO;
+}
+
+/*
+ * applesmc_read_key - reads len bytes from a given key, and put them in buffer.
+ * Returns zero on success or a negative error on failure. Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_read_key(const char* key, u8* buffer, u8 len)
+{
+ int i;
+
+ if (len > APPLESMC_MAX_DATA_LENGTH) {
+ printk(KERN_ERR "applesmc_read_key: cannot read more than "
+ "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
+ return -EINVAL;
+ }
+
+ outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
+ if (__wait_status(0x0c))
+ return -EIO;
+
+ for (i = 0; i < 4; i++) {
+ outb(key[i], APPLESMC_DATA_PORT);
+ if (__wait_status(0x04))
+ return -EIO;
+ }
+ if (debug)
+ printk(KERN_DEBUG "<%s", key);
+
+ outb(len, APPLESMC_DATA_PORT);
+ if (debug)
+ printk(KERN_DEBUG ">%x", len);
+
+ for (i = 0; i < len; i++) {
+ if (__wait_status(0x05))
+ return -EIO;
+ buffer[i] = inb(APPLESMC_DATA_PORT);
+ if (debug)
+ printk(KERN_DEBUG "<%x", buffer[i]);
+ }
+ if (debug)
+ printk(KERN_DEBUG "\n");
+
+ return 0;
+}
+
+/*
+ * applesmc_write_key - writes len bytes from buffer to a given key.
+ * Returns zero on success or a negative error on failure. Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_write_key(const char* key, u8* buffer, u8 len)
+{
+ int i;
+
+ if (len > APPLESMC_MAX_DATA_LENGTH) {
+ printk(KERN_ERR "applesmc_write_key: cannot write more than "
+ "%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
+ return -EINVAL;
+ }
+
+ outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
+ if (__wait_status(0x0c))
+ return -EIO;
+
+ for (i = 0; i < 4; i++) {
+ outb(key[i], APPLESMC_DATA_PORT);
+ if (__wait_status(0x04))
+ return -EIO;
+ }
+
+ outb(len, APPLESMC_DATA_PORT);
+
+ for (i = 0; i < len; i++) {
+ if (__wait_status(0x04))
+ return -EIO;
+ outb(buffer[i], APPLESMC_DATA_PORT);
+ }
+
+ return 0;
+}
+
+/*
+ * applesmc_get_key_at_index - get key at index, and put the result in key
+ * (char[6]). Returns zero on success or a negative error on failure. Callers
+ * must hold applesmc_lock.
+ */
+static int applesmc_get_key_at_index(int index, char* key)
+{
+ int i;
+ u8 readkey[4];
+ readkey[0] = index >> 24;
+ readkey[1] = index >> 16;
+ readkey[2] = index >> 8;
+ readkey[3] = index;
+
+ outb(APPLESMC_GET_KEY_BY_INDEX_CMD, APPLESMC_CMD_PORT);
+ if (__wait_status(0x0c))
+ return -EIO;
+
+ for (i = 0; i < 4; i++) {
+ outb(readkey[i], APPLESMC_DATA_PORT);
+ if (__wait_status(0x04))
+ return -EIO;
+ }
+
+ outb(4, APPLESMC_DATA_PORT);
+
+ for (i = 0; i < 4; i++) {
+ if (__wait_status(0x05))
+ return -EIO;
+ key[i] = inb(APPLESMC_DATA_PORT);
+ }
+ key[4] = 0;
+
+ return 0;
+}
+
+/*
+ * applesmc_get_key_type - get key type, and put the result in type (char[6]).
+ * Returns zero on success or a negative error on failure. Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_get_key_type(char* key, char* type)
+{
+ int i;
+
+ outb(APPLESMC_GET_KEY_TYPE_CMD, APPLESMC_CMD_PORT);
+ if (__wait_status(0x0c))
+ return -EIO;
+
+ for (i = 0; i < 4; i++) {
+ outb(key[i], APPLESMC_DATA_PORT);
+ if (__wait_status(0x04))
+ return -EIO;
+ }
+
+ outb(5, APPLESMC_DATA_PORT);
+
+ for (i = 0; i < 6; i++) {
+ if (__wait_status(0x05))
+ return -EIO;
+ type[i] = inb(APPLESMC_DATA_PORT);
+ }
+ type[5] = 0;
+
+ return 0;
+}
+
+/*
+ * applesmc_read_motion_sensor - Read motion sensor (X, Y or Z). Callers must
+ * hold applesmc_lock.
+ */
+static int applesmc_read_motion_sensor(int index, s16* value)
+{
+ u8 buffer[2];
+ int ret;
+
+ switch (index) {
+ case SENSOR_X:
+ ret = applesmc_read_key(MOTION_SENSOR_X_KEY, buffer, 2);
+ break;
+ case SENSOR_Y:
+ ret = applesmc_read_key(MOTION_SENSOR_Y_KEY, buffer, 2);
+ break;
+ case SENSOR_Z:
+ ret = applesmc_read_key(MOTION_SENSOR_Z_KEY, buffer, 2);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ *value = ((s16)buffer[0] << 8) | buffer[1];
+
+ return ret;
+}
+
+/*
+ * applesmc_device_init - initialize the accelerometer. Returns zero on success
+ * and negative error code on failure. Can sleep.
+ */
+static int applesmc_device_init(void)
+{
+ int total, ret = -ENXIO;
+ u8 buffer[2];
+
+ if (!applesmc_accelerometer)
+ return 0;
+
+ mutex_lock(&applesmc_lock);
+
+ for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) {
+ if (debug)
+ printk(KERN_DEBUG "applesmc try %d\n", total);
+ if (!applesmc_read_key(MOTION_SENSOR_KEY, buffer, 2) &&
+ (buffer[0] != 0x00 || buffer[1] != 0x00)) {
+ if (total == INIT_TIMEOUT_MSECS) {
+ printk(KERN_DEBUG "applesmc: device has"
+ " already been initialized"
+ " (0x%02x, 0x%02x).\n",
+ buffer[0], buffer[1]);
+ } else {
+ printk(KERN_DEBUG "applesmc: device"
+ " successfully initialized"
+ " (0x%02x, 0x%02x).\n",
+ buffer[0], buffer[1]);
+ }
+ ret = 0;
+ goto out;
+ }
+ buffer[0] = 0xe0;
+ buffer[1] = 0x00;
+ applesmc_write_key(MOTION_SENSOR_KEY, buffer, 2);
+ msleep(INIT_WAIT_MSECS);
+ }
+
+ printk(KERN_WARNING "applesmc: failed to init the device\n");
+
+out:
+ mutex_unlock(&applesmc_lock);
+ return ret;
+}
+
+/*
+ * applesmc_get_fan_count - get the number of fans. Callers must NOT hold
+ * applesmc_lock.
+ */
+static int applesmc_get_fan_count(void)
+{
+ int ret;
+ u8 buffer[1];
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(FANS_COUNT, buffer, 1);
+
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return buffer[0];
+}
+
+/* Device model stuff */
+static int applesmc_probe(struct platform_device *dev)
+{
+ int ret;
+
+ ret = applesmc_device_init();
+ if (ret)
+ return ret;
+
+ printk(KERN_INFO "applesmc: device successfully initialized.\n");
+ return 0;
+}
+
+static int applesmc_resume(struct platform_device *dev)
+{
+ return applesmc_device_init();
+}
+
+static struct platform_driver applesmc_driver = {
+ .probe = applesmc_probe,
+ .resume = applesmc_resume,
+ .driver = {
+ .name = "applesmc",
+ .owner = THIS_MODULE,
+ },
+};
+
+/*
+ * applesmc_calibrate - Set our "resting" values. Callers must
+ * hold applesmc_lock.
+ */
+static void applesmc_calibrate(void)
+{
+ applesmc_read_motion_sensor(SENSOR_X, &rest_x);
+ applesmc_read_motion_sensor(SENSOR_Y, &rest_y);
+ rest_x = -rest_x;
+}
+
+static int applesmc_idev_open(struct input_dev *dev)
+{
+ add_timer(&applesmc_timer);
+
+ return 0;
+}
+
+static void applesmc_idev_close(struct input_dev *dev)
+{
+ del_timer_sync(&applesmc_timer);
+}
+
+static void applesmc_idev_poll(unsigned long unused)
+{
+ s16 x, y;
+
+ /* Cannot sleep. Try nonblockingly. If we fail, try again later. */
+ if (!mutex_trylock(&applesmc_lock)) {
+ mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
+ return;
+ }
+
+ if (applesmc_read_motion_sensor(SENSOR_X, &x))
+ goto out;
+ if (applesmc_read_motion_sensor(SENSOR_Y, &y))
+ goto out;
+
+ x = -x;
+ input_report_abs(applesmc_idev, ABS_X, x - rest_x);
+ input_report_abs(applesmc_idev, ABS_Y, y - rest_y);
+ input_sync(applesmc_idev);
+
+out:
+ mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD);
+
+ mutex_unlock(&applesmc_lock);
+}
+
+/* Sysfs Files */
+
+static ssize_t applesmc_position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int ret;
+ s16 x, y, z;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_motion_sensor(SENSOR_X, &x);
+ if (ret)
+ goto out;
+ ret = applesmc_read_motion_sensor(SENSOR_Y, &y);
+ if (ret)
+ goto out;
+ ret = applesmc_read_motion_sensor(SENSOR_Z, &z);
+ if (ret)
+ goto out;
+
+out:
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
+}
+
+static ssize_t applesmc_light_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ int ret;
+ u8 left = 0, right = 0;
+ u8 buffer[6];
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(LIGHT_SENSOR_LEFT_KEY, buffer, 6);
+ left = buffer[2];
+ if (ret)
+ goto out;
+ ret = applesmc_read_key(LIGHT_SENSOR_RIGHT_KEY, buffer, 6);
+ right = buffer[2];
+
+out:
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
+}
+
+/* Displays degree Celsius * 1000 */
+static ssize_t applesmc_show_temperature(struct device *dev,
+ struct device_attribute *devattr, char *sysfsbuf)
+{
+ int ret;
+ u8 buffer[2];
+ unsigned int temp;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ const char* key =
+ temperature_sensors_sets[applesmc_temperature_set][attr->index];
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(key, buffer, 2);
+ temp = buffer[0]*1000;
+ temp += (buffer[1] >> 6) * 250;
+
+ mutex_unlock(&applesmc_lock);
+
+ if (ret)
+ return ret;
+ else
+ return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
+}
+
+static ssize_t applesmc_show_fan_speed(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ int ret;
+ unsigned int speed = 0;
+ char newkey[5];
+ u8 buffer[2];
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+
+ newkey[0] = fan_speed_keys[sensor_attr->nr][0];
+ newkey[1] = '0' + sensor_attr->index;
+ newkey[2] = fan_speed_keys[sensor_attr->nr][2];
+ newkey[3] = fan_speed_keys[sensor_attr->nr][3];
+ newkey[4] = 0;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(newkey, buffer, 2);
+ speed = ((buffer[0] << 8 | buffer[1]) >> 2);
+
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
+}
+
+static ssize_t applesmc_store_fan_speed(struct device *dev,
+ struct device_attribute *attr,
+ const char *sysfsbuf, size_t count)
+{
+ int ret;
+ u32 speed;
+ char newkey[5];
+ u8 buffer[2];
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+
+ speed = simple_strtoul(sysfsbuf, NULL, 10);
+
+ if (speed > 0x4000) /* Bigger than a 14-bit value */
+ return -EINVAL;
+
+ newkey[0] = fan_speed_keys[sensor_attr->nr][0];
+ newkey[1] = '0' + sensor_attr->index;
+ newkey[2] = fan_speed_keys[sensor_attr->nr][2];
+ newkey[3] = fan_speed_keys[sensor_attr->nr][3];
+ newkey[4] = 0;
+
+ mutex_lock(&applesmc_lock);
+
+ buffer[0] = (speed >> 6) & 0xff;
+ buffer[1] = (speed << 2) & 0xff;
+ ret = applesmc_write_key(newkey, buffer, 2);
+
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return count;
+}
+
+static ssize_t applesmc_show_fan_manual(struct device *dev,
+ struct device_attribute *devattr, char *sysfsbuf)
+{
+ int ret;
+ u16 manual = 0;
+ u8 buffer[2];
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+ manual = ((buffer[0] << 8 | buffer[1]) >> attr->index) & 0x01;
+
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
+}
+
+static ssize_t applesmc_store_fan_manual(struct device *dev,
+ struct device_attribute *devattr,
+ const char *sysfsbuf, size_t count)
+{
+ int ret;
+ u8 buffer[2];
+ u32 input;
+ u16 val;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+
+ input = simple_strtoul(sysfsbuf, NULL, 10);
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(FANS_MANUAL, buffer, 2);
+ val = (buffer[0] << 8 | buffer[1]);
+ if (ret)
+ goto out;
+
+ if (input)
+ val = val | (0x01 << attr->index);
+ else
+ val = val & ~(0x01 << attr->index);
+
+ buffer[0] = (val >> 8) & 0xFF;
+ buffer[1] = val & 0xFF;
+
+ ret = applesmc_write_key(FANS_MANUAL, buffer, 2);
+
+out:
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return count;
+}
+
+static ssize_t applesmc_show_fan_position(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ int ret;
+ char newkey[5];
+ u8 buffer[17];
+ struct sensor_device_attribute_2 *sensor_attr =
+ to_sensor_dev_attr_2(attr);
+
+ newkey[0] = FAN_POSITION[0];
+ newkey[1] = '0' + sensor_attr->index;
+ newkey[2] = FAN_POSITION[2];
+ newkey[3] = FAN_POSITION[3];
+ newkey[4] = 0;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(newkey, buffer, 16);
+ buffer[16] = 0;
+
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
+}
+
+static ssize_t applesmc_calibrate_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
+}
+
+static ssize_t applesmc_calibrate_store(struct device *dev,
+ struct device_attribute *attr, const char *sysfsbuf, size_t count)
+{
+ mutex_lock(&applesmc_lock);
+ applesmc_calibrate();
+ mutex_unlock(&applesmc_lock);
+
+ return count;
+}
+
+/* Store the next backlight value to be written by the work */
+static unsigned int backlight_value;
+
+static void applesmc_backlight_set(struct work_struct *work)
+{
+ u8 buffer[2];
+
+ mutex_lock(&applesmc_lock);
+ buffer[0] = backlight_value;
+ buffer[1] = 0x00;
+ applesmc_write_key(BACKLIGHT_KEY, buffer, 2);
+ mutex_unlock(&applesmc_lock);
+}
+static DECLARE_WORK(backlight_work, &applesmc_backlight_set);
+
+static void applesmc_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ int ret;
+
+ backlight_value = value;
+ ret = queue_work(applesmc_led_wq, &backlight_work);
+
+ if (debug && (!ret))
+ printk(KERN_DEBUG "applesmc: work was already on the queue.\n");
+}
+
+static ssize_t applesmc_key_count_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ int ret;
+ u8 buffer[4];
+ u32 count;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_read_key(KEY_COUNT_KEY, buffer, 4);
+ count = ((u32)buffer[0]<<24) + ((u32)buffer[1]<<16) +
+ ((u32)buffer[2]<<8) + buffer[3];
+
+ mutex_unlock(&applesmc_lock);
+ if (ret)
+ return ret;
+ else
+ return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", count);
+}
+
+static ssize_t applesmc_key_at_index_read_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ char key[5];
+ char info[6];
+ int ret;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_get_key_at_index(key_at_index, key);
+
+ if (ret || !key[0]) {
+ mutex_unlock(&applesmc_lock);
+
+ return -EINVAL;
+ }
+
+ ret = applesmc_get_key_type(key, info);
+
+ if (ret) {
+ mutex_unlock(&applesmc_lock);
+
+ return ret;
+ }
+
+ /*
+ * info[0] maximum value (APPLESMC_MAX_DATA_LENGTH) is much lower than
+ * PAGE_SIZE, so we don't need any checks before writing to sysfsbuf.
+ */
+ ret = applesmc_read_key(key, sysfsbuf, info[0]);
+
+ mutex_unlock(&applesmc_lock);
+
+ if (!ret) {
+ return info[0];
+ }
+ else {
+ return ret;
+ }
+}
+
+static ssize_t applesmc_key_at_index_data_length_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ char key[5];
+ char info[6];
+ int ret;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_get_key_at_index(key_at_index, key);
+
+ if (ret || !key[0]) {
+ mutex_unlock(&applesmc_lock);
+
+ return -EINVAL;
+ }
+
+ ret = applesmc_get_key_type(key, info);
+
+ mutex_unlock(&applesmc_lock);
+
+ if (!ret)
+ return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", info[0]);
+ else
+ return ret;
+}
+
+static ssize_t applesmc_key_at_index_type_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ char key[5];
+ char info[6];
+ int ret;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_get_key_at_index(key_at_index, key);
+
+ if (ret || !key[0]) {
+ mutex_unlock(&applesmc_lock);
+
+ return -EINVAL;
+ }
+
+ ret = applesmc_get_key_type(key, info);
+
+ mutex_unlock(&applesmc_lock);
+
+ if (!ret)
+ return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", info+1);
+ else
+ return ret;
+}
+
+static ssize_t applesmc_key_at_index_name_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ char key[5];
+ int ret;
+
+ mutex_lock(&applesmc_lock);
+
+ ret = applesmc_get_key_at_index(key_at_index, key);
+
+ mutex_unlock(&applesmc_lock);
+
+ if (!ret && key[0])
+ return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", key);
+ else
+ return -EINVAL;
+}
+
+static ssize_t applesmc_key_at_index_show(struct device *dev,
+ struct device_attribute *attr, char *sysfsbuf)
+{
+ return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", key_at_index);
+}
+
+static ssize_t applesmc_key_at_index_store(struct device *dev,
+ struct device_attribute *attr, const char *sysfsbuf, size_t count)
+{
+ mutex_lock(&applesmc_lock);
+
+ key_at_index = simple_strtoul(sysfsbuf, NULL, 10);
+
+ mutex_unlock(&applesmc_lock);
+
+ return count;
+}
+
+static struct led_classdev applesmc_backlight = {
+ .name = "smc:kbd_backlight",
+ .default_trigger = "nand-disk",
+ .brightness_set = applesmc_brightness_set,
+};
+
+static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
+static DEVICE_ATTR(calibrate, 0644,
+ applesmc_calibrate_show, applesmc_calibrate_store);
+
+static struct attribute *accelerometer_attributes[] = {
+ &dev_attr_position.attr,
+ &dev_attr_calibrate.attr,
+ NULL
+};
+
+static const struct attribute_group accelerometer_attributes_group =
+ { .attrs = accelerometer_attributes };
+
+static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
+
+static DEVICE_ATTR(key_count, 0444, applesmc_key_count_show, NULL);
+static DEVICE_ATTR(key_at_index, 0644,
+ applesmc_key_at_index_show, applesmc_key_at_index_store);
+static DEVICE_ATTR(key_at_index_name, 0444,
+ applesmc_key_at_index_name_show, NULL);
+static DEVICE_ATTR(key_at_index_type, 0444,
+ applesmc_key_at_index_type_show, NULL);
+static DEVICE_ATTR(key_at_index_data_length, 0444,
+ applesmc_key_at_index_data_length_show, NULL);
+static DEVICE_ATTR(key_at_index_data, 0444,
+ applesmc_key_at_index_read_show, NULL);
+
+static struct attribute *key_enumeration_attributes[] = {
+ &dev_attr_key_count.attr,
+ &dev_attr_key_at_index.attr,
+ &dev_attr_key_at_index_name.attr,
+ &dev_attr_key_at_index_type.attr,
+ &dev_attr_key_at_index_data_length.attr,
+ &dev_attr_key_at_index_data.attr,
+ NULL
+};
+
+static const struct attribute_group key_enumeration_group =
+ { .attrs = key_enumeration_attributes };
+
+/*
+ * Macro defining SENSOR_DEVICE_ATTR for a fan sysfs entries.
+ * - show actual speed
+ * - show/store minimum speed
+ * - show maximum speed
+ * - show safe speed
+ * - show/store target speed
+ * - show/store manual mode
+ */
+#define sysfs_fan_speeds_offset(offset) \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
+ applesmc_show_fan_speed, NULL, 0, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
+ applesmc_show_fan_speed, NULL, 2, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
+ applesmc_show_fan_speed, NULL, 3, offset-1); \
+\
+static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
+ applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
+\
+static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
+ applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
+\
+static SENSOR_DEVICE_ATTR(fan##offset##_label, S_IRUGO, \
+ applesmc_show_fan_position, NULL, offset-1); \
+\
+static struct attribute *fan##offset##_attributes[] = { \
+ &sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
+ &sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
+ &sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
+ &sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
+ &sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
+ &sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
+ &sensor_dev_attr_fan##offset##_label.dev_attr.attr, \
+ NULL \
+};
+
+/*
+ * Create the needed functions for each fan using the macro defined above
+ * (2 fans are supported)
+ */
+sysfs_fan_speeds_offset(1);
+sysfs_fan_speeds_offset(2);
+
+static const struct attribute_group fan_attribute_groups[] = {
+ { .attrs = fan1_attributes },
+ { .attrs = fan2_attributes }
+};
+
+/*
+ * Temperature sensors sysfs entries.
+ */
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp11_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp12_input, S_IRUGO,
+ applesmc_show_temperature, NULL, 11);
+
+static struct attribute *temperature_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp7_input.dev_attr.attr,
+ &sensor_dev_attr_temp8_input.dev_attr.attr,
+ &sensor_dev_attr_temp9_input.dev_attr.attr,
+ &sensor_dev_attr_temp10_input.dev_attr.attr,
+ &sensor_dev_attr_temp11_input.dev_attr.attr,
+ &sensor_dev_attr_temp12_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group temperature_attributes_group =
+ { .attrs = temperature_attributes };
+
+/* Module stuff */
+
+/*
+ * applesmc_dmi_match - found a match. return one, short-circuiting the hunt.
+ */
+static int applesmc_dmi_match(struct dmi_system_id *id)
+{
+ int i = 0;
+ struct dmi_match_data* dmi_data = id->driver_data;
+ printk(KERN_INFO "applesmc: %s detected:\n", id->ident);
+ applesmc_accelerometer = dmi_data->accelerometer;
+ printk(KERN_INFO "applesmc: - Model %s accelerometer\n",
+ applesmc_accelerometer ? "with" : "without");
+ applesmc_light = dmi_data->light;
+ printk(KERN_INFO "applesmc: - Model %s light sensors and backlight\n",
+ applesmc_light ? "with" : "without");
+
+ applesmc_temperature_set = dmi_data->temperature_set;
+ while (temperature_sensors_sets[applesmc_temperature_set][i] != NULL)
+ i++;
+ printk(KERN_INFO "applesmc: - Model with %d temperature sensors\n", i);
+ return 1;
+}
+
+/* Create accelerometer ressources */
+static int applesmc_create_accelerometer(void)
+{
+ int ret;
+
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &accelerometer_attributes_group);
+ if (ret)
+ goto out;
+
+ applesmc_idev = input_allocate_device();
+ if (!applesmc_idev) {
+ ret = -ENOMEM;
+ goto out_sysfs;
+ }
+
+ /* initial calibrate for the input device */
+ applesmc_calibrate();
+
+ /* initialize the input class */
+ applesmc_idev->name = "applesmc";
+ applesmc_idev->id.bustype = BUS_HOST;
+ applesmc_idev->cdev.dev = &pdev->dev;
+ applesmc_idev->evbit[0] = BIT(EV_ABS);
+ applesmc_idev->open = applesmc_idev_open;
+ applesmc_idev->close = applesmc_idev_close;
+ input_set_abs_params(applesmc_idev, ABS_X,
+ -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+ input_set_abs_params(applesmc_idev, ABS_Y,
+ -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT);
+
+ ret = input_register_device(applesmc_idev);
+ if (ret)
+ goto out_idev;
+
+ /* start up our timer for the input device */
+ init_timer(&applesmc_timer);
+ applesmc_timer.function = applesmc_idev_poll;
+ applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD;
+
+ return 0;
+
+out_idev:
+ input_free_device(applesmc_idev);
+
+out_sysfs:
+ sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+
+out:
+ printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+ return ret;
+}
+
+/* Release all ressources used by the accelerometer */
+static void applesmc_release_accelerometer(void)
+{
+ del_timer_sync(&applesmc_timer);
+ input_unregister_device(applesmc_idev);
+ sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
+}
+
+static __initdata struct dmi_match_data applesmc_dmi_data[] = {
+/* MacBook Pro: accelerometer, backlight and temperature set 0 */
+ { .accelerometer = 1, .light = 1, .temperature_set = 0 },
+/* MacBook: accelerometer and temperature set 0 */
+ { .accelerometer = 1, .light = 0, .temperature_set = 0 },
+/* MacBook: temperature set 1 */
+ { .accelerometer = 0, .light = 0, .temperature_set = 1 }
+};
+
+/* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
+ * So we need to put "Apple MacBook Pro" before "Apple MacBook". */
+static __initdata struct dmi_system_id applesmc_whitelist[] = {
+ { applesmc_dmi_match, "Apple MacBook Pro", {
+ DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") },
+ (void*)&applesmc_dmi_data[0]},
+ { applesmc_dmi_match, "Apple MacBook", {
+ DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") },
+ (void*)&applesmc_dmi_data[1]},
+ { applesmc_dmi_match, "Apple Macmini", {
+ DMI_MATCH(DMI_BOARD_VENDOR,"Apple"),
+ DMI_MATCH(DMI_PRODUCT_NAME,"Macmini") },
+ (void*)&applesmc_dmi_data[2]},
+ { .ident = NULL }
+};
+
+static int __init applesmc_init(void)
+{
+ int ret;
+ int count;
+ int i;
+
+ mutex_init(&applesmc_lock);
+
+ if (!dmi_check_system(applesmc_whitelist)) {
+ printk(KERN_WARNING "applesmc: supported laptop not found!\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (!request_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS,
+ "applesmc")) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ ret = platform_driver_register(&applesmc_driver);
+ if (ret)
+ goto out_region;
+
+ pdev = platform_device_register_simple("applesmc", APPLESMC_DATA_PORT,
+ NULL, 0);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto out_driver;
+ }
+
+ /* Create key enumeration sysfs files */
+ ret = sysfs_create_group(&pdev->dev.kobj, &key_enumeration_group);
+ if (ret)
+ goto out_device;
+
+ /* create fan files */
+ count = applesmc_get_fan_count();
+ if (count < 0) {
+ printk(KERN_ERR "applesmc: Cannot get the number of fans.\n");
+ } else {
+ printk(KERN_INFO "applesmc: %d fans found.\n", count);
+
+ switch (count) {
+ default:
+ printk(KERN_WARNING "applesmc: More than 2 fans found,"
+ " but at most 2 fans are supported"
+ " by the driver.\n");
+ case 2:
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &fan_attribute_groups[1]);
+ if (ret)
+ goto out_key_enumeration;
+ case 1:
+ ret = sysfs_create_group(&pdev->dev.kobj,
+ &fan_attribute_groups[0]);
+ if (ret)
+ goto out_fan_1;
+ case 0:
+ ;
+ }
+ }
+
+ for (i = 0;
+ temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
+ i++) {
+ if (temperature_attributes[i] == NULL) {
+ printk(KERN_ERR "applesmc: More temperature sensors "
+ "in temperature_sensors_sets (at least %i)"
+ "than available sysfs files in "
+ "temperature_attributes (%i), please report "
+ "this bug.\n", i, i-1);
+ goto out_temperature;
+ }
+ ret = sysfs_create_file(&pdev->dev.kobj,
+ temperature_attributes[i]);
+ if (ret)
+ goto out_temperature;
+ }
+
+ if (applesmc_accelerometer) {
+ ret = applesmc_create_accelerometer();
+ if (ret)
+ goto out_temperature;
+ }
+
+ if (applesmc_light) {
+ /* Add light sensor file */
+ ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_light.attr);
+ if (ret)
+ goto out_accelerometer;
+
+ /* Create the workqueue */
+ applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
+ if (!applesmc_led_wq) {
+ ret = -ENOMEM;
+ goto out_light_sysfs;
+ }
+
+ /* register as a led device */
+ ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
+ if (ret < 0)
+ goto out_light_wq;
+ }
+
+ hwmon_class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(hwmon_class_dev)) {
+ ret = PTR_ERR(hwmon_class_dev);
+ goto out_light_ledclass;
+ }
+
+ printk(KERN_INFO "applesmc: driver successfully loaded.\n");
+
+ return 0;
+
+out_light_ledclass:
+ if (applesmc_light)
+ led_classdev_unregister(&applesmc_backlight);
+out_light_wq:
+ if (applesmc_light)
+ destroy_workqueue(applesmc_led_wq);
+out_light_sysfs:
+ if (applesmc_light)
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
+out_accelerometer:
+ if (applesmc_accelerometer)
+ applesmc_release_accelerometer();
+out_temperature:
+ sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+ sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
+out_fan_1:
+ sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
+out_key_enumeration:
+ sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
+out_device:
+ platform_device_unregister(pdev);
+out_driver:
+ platform_driver_unregister(&applesmc_driver);
+out_region:
+ release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+out:
+ printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
+ return ret;
+}
+
+static void __exit applesmc_exit(void)
+{
+ hwmon_device_unregister(hwmon_class_dev);
+ if (applesmc_light) {
+ led_classdev_unregister(&applesmc_backlight);
+ destroy_workqueue(applesmc_led_wq);
+ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
+ }
+ if (applesmc_accelerometer)
+ applesmc_release_accelerometer();
+ sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+ sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
+ sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
+ sysfs_remove_group(&pdev->dev.kobj, &key_enumeration_group);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&applesmc_driver);
+ release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
+
+ printk(KERN_INFO "applesmc: driver unloaded.\n");
+}
+
+module_init(applesmc_init);
+module_exit(applesmc_exit);
+
+MODULE_AUTHOR("Nicolas Boichat");
+MODULE_DESCRIPTION("Apple SMC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
new file mode 100644
index 00000000000..75e3911810a
--- /dev/null
+++ b/drivers/hwmon/coretemp.c
@@ -0,0 +1,408 @@
+/*
+ * coretemp.c - Linux kernel module for hardware monitoring
+ *
+ * Copyright (C) 2007 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * Inspired from many hwmon drivers
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/hwmon.h>
+#include <linux/sysfs.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/cpu.h>
+#include <asm/msr.h>
+#include <asm/processor.h>
+
+#define DRVNAME "coretemp"
+
+typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_LABEL, SHOW_NAME } SHOW;
+
+/*
+ * Functions declaration
+ */
+
+static struct coretemp_data *coretemp_update_device(struct device *dev);
+
+struct coretemp_data {
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ const char *name;
+ u32 id;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+ int temp;
+ int tjmax;
+ u8 alarm;
+};
+
+static struct coretemp_data *coretemp_update_device(struct device *dev);
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ int ret;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct coretemp_data *data = dev_get_drvdata(dev);
+
+ if (attr->index == SHOW_NAME)
+ ret = sprintf(buf, "%s\n", data->name);
+ else /* show label */
+ ret = sprintf(buf, "Core %d\n", data->id);
+ return ret;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct coretemp_data *data = coretemp_update_device(dev);
+ /* read the Out-of-spec log, never clear */
+ return sprintf(buf, "%d\n", data->alarm);
+}
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct coretemp_data *data = coretemp_update_device(dev);
+ int err;
+
+ if (attr->index == SHOW_TEMP)
+ err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
+ else
+ err = sprintf(buf, "%d\n", data->tjmax);
+
+ return err;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
+ SHOW_TEMP);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
+ SHOW_TJMAX);
+static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
+
+static struct attribute *coretemp_attributes[] = {
+ &sensor_dev_attr_name.dev_attr.attr,
+ &sensor_dev_attr_temp1_label.dev_attr.attr,
+ &dev_attr_temp1_crit_alarm.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group coretemp_group = {
+ .attrs = coretemp_attributes,
+};
+
+static struct coretemp_data *coretemp_update_device(struct device *dev)
+{
+ struct coretemp_data *data = dev_get_drvdata(dev);
+
+ mutex_lock(&data->update_lock);
+
+ if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+ u32 eax, edx;
+
+ data->valid = 0;
+ rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
+ data->alarm = (eax >> 5) & 1;
+ /* update only if data has been valid */
+ if (eax & 0x80000000) {
+ data->temp = data->tjmax - (((eax >> 16)
+ & 0x7f) * 1000);
+ data->valid = 1;
+ } else {
+ dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
+ }
+ data->last_updated = jiffies;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+static int __devinit coretemp_probe(struct platform_device *pdev)
+{
+ struct coretemp_data *data;
+ struct cpuinfo_x86 *c = &(cpu_data)[pdev->id];
+ int err;
+ u32 eax, edx;
+
+ if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ dev_err(&pdev->dev, "Out of memory\n");
+ goto exit;
+ }
+
+ data->id = pdev->id;
+ data->name = "coretemp";
+ mutex_init(&data->update_lock);
+ /* Tjmax default is 100 degrees C */
+ data->tjmax = 100000;
+
+ /* test if we can access the THERM_STATUS MSR */
+ err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Unable to access THERM_STATUS MSR, giving up\n");
+ goto exit_free;
+ }
+
+ /* Some processors have Tjmax 85 following magic should detect it
+ Intel won't disclose the information without signed NDA, but
+ individuals cannot sign it. Catch(ed) 22.
+ */
+
+ if (((c->x86_model == 0xf) && (c->x86_mask > 3)) ||
+ (c->x86_model == 0xe)) {
+ err = rdmsr_safe_on_cpu(data->id, 0xee, &eax, &edx);
+ if (err) {
+ dev_warn(&pdev->dev,
+ "Unable to access MSR 0xEE, Tjmax left at %d "
+ "degrees C\n", data->tjmax/1000);
+ } else if (eax & 0x40000000) {
+ data->tjmax = 85000;
+ }
+ }
+
+ platform_set_drvdata(pdev, data);
+
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
+ goto exit_free;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n",
+ err);
+ goto exit_class;
+ }
+
+ return 0;
+
+exit_class:
+ sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __devexit coretemp_remove(struct platform_device *pdev)
+{
+ struct coretemp_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+ return 0;
+}
+
+static struct platform_driver coretemp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = coretemp_probe,
+ .remove = __devexit_p(coretemp_remove),
+};
+
+struct pdev_entry {
+ struct list_head list;
+ struct platform_device *pdev;
+ unsigned int cpu;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static int __cpuinit coretemp_device_add(unsigned int cpu)
+{
+ int err;
+ struct platform_device *pdev;
+ struct pdev_entry *pdev_entry;
+
+ pdev = platform_device_alloc(DRVNAME, cpu);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
+ if (!pdev_entry) {
+ err = -ENOMEM;
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_free;
+ }
+
+ pdev_entry->pdev = pdev;
+ pdev_entry->cpu = cpu;
+ mutex_lock(&pdev_list_mutex);
+ list_add_tail(&pdev_entry->list, &pdev_list);
+ mutex_unlock(&pdev_list_mutex);
+
+ return 0;
+
+exit_device_free:
+ kfree(pdev_entry);
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void coretemp_device_remove(unsigned int cpu)
+{
+ struct pdev_entry *p, *n;
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ if (p->cpu == cpu) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ }
+ mutex_unlock(&pdev_list_mutex);
+}
+
+static int coretemp_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long) hcpu;
+
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ coretemp_device_add(cpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ coretemp_device_remove(cpu);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata coretemp_cpu_notifier = {
+ .notifier_call = coretemp_cpu_callback,
+};
+#endif /* !CONFIG_HOTPLUG_CPU */
+
+static int __init coretemp_init(void)
+{
+ int i, err = -ENODEV;
+ struct pdev_entry *p, *n;
+
+ printk(KERN_NOTICE DRVNAME ": This driver uses undocumented features "
+ "of Core CPU. Temperature might be wrong!\n");
+
+ /* quick check if we run Intel */
+ if (cpu_data[0].x86_vendor != X86_VENDOR_INTEL)
+ goto exit;
+
+ err = platform_driver_register(&coretemp_driver);
+ if (err)
+ goto exit;
+
+ for_each_online_cpu(i) {
+ struct cpuinfo_x86 *c = &(cpu_data)[i];
+
+ /* check if family 6, models e, f */
+ if ((c->cpuid_level < 0) || (c->x86 != 0x6) ||
+ !((c->x86_model == 0xe) || (c->x86_model == 0xf))) {
+
+ /* supported CPU not found, but report the unknown
+ family 6 CPU */
+ if ((c->x86 == 0x6) && (c->x86_model > 0xf))
+ printk(KERN_WARNING DRVNAME ": Unknown CPU "
+ "model %x\n", c->x86_model);
+ continue;
+ }
+
+ err = coretemp_device_add(i);
+ if (err)
+ goto exit_devices_unreg;
+ }
+ if (list_empty(&pdev_list)) {
+ err = -ENODEV;
+ goto exit_driver_unreg;
+ }
+
+#ifdef CONFIG_HOTPLUG_CPU
+ register_hotcpu_notifier(&coretemp_cpu_notifier);
+#endif
+ return 0;
+
+exit_devices_unreg:
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ mutex_unlock(&pdev_list_mutex);
+exit_driver_unreg:
+ platform_driver_unregister(&coretemp_driver);
+exit:
+ return err;
+}
+
+static void __exit coretemp_exit(void)
+{
+ struct pdev_entry *p, *n;
+#ifdef CONFIG_HOTPLUG_CPU
+ unregister_hotcpu_notifier(&coretemp_cpu_notifier);
+#endif
+ mutex_lock(&pdev_list_mutex);
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ platform_device_unregister(p->pdev);
+ list_del(&p->list);
+ kfree(p);
+ }
+ mutex_unlock(&pdev_list_mutex);
+ platform_driver_unregister(&coretemp_driver);
+}
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
+MODULE_DESCRIPTION("Intel Core temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(coretemp_init)
+module_exit(coretemp_exit)
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index 7c297348712..cdbe309b8fc 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -35,6 +35,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/ioport.h>
#include <asm/io.h>
static struct platform_device *pdev;
@@ -1140,6 +1141,13 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start + ADDR_REG_OFFSET, 2, DRVNAME)) {
+ err = -EBUSY;
+ dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)(res->start + ADDR_REG_OFFSET),
+ (unsigned long)(res->start + ADDR_REG_OFFSET + 1));
+ goto exit_free;
+ }
data->addr = res->start;
data->name = names[sio_data->kind];
mutex_init(&data->update_lock);
@@ -1165,7 +1173,7 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
/* Register sysfs interface files */
if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
- goto exit_free;
+ goto exit_release_region;
if (data->has_in & (1 << 4)) { /* in4 */
if ((err = sysfs_create_group(&pdev->dev.kobj,
&f71805f_group_optin[0])))
@@ -1219,6 +1227,8 @@ exit_remove_files:
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+exit_release_region:
+ release_region(res->start + ADDR_REG_OFFSET, 2);
exit_free:
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -1229,6 +1239,7 @@ exit:
static int __devexit f71805f_remove(struct platform_device *pdev)
{
struct f71805f_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
int i;
platform_set_drvdata(pdev, NULL);
@@ -1239,6 +1250,9 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
kfree(data);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start + ADDR_REG_OFFSET, 2);
+
return 0;
}
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index bf759ea545a..f82fa2d23f9 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -30,10 +30,12 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/kernel.h>
+#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/dmi.h>
#include <linux/jiffies.h>
+
#include <asm/io.h>
#define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */
@@ -71,10 +73,10 @@ static u8 km_activity;
static int rest_x;
static int rest_y;
-static DECLARE_MUTEX(hdaps_sem);
+static DEFINE_MUTEX(hdaps_mtx);
/*
- * __get_latch - Get the value from a given port. Callers must hold hdaps_sem.
+ * __get_latch - Get the value from a given port. Callers must hold hdaps_mtx.
*/
static inline u8 __get_latch(u16 port)
{
@@ -83,7 +85,7 @@ static inline u8 __get_latch(u16 port)
/*
* __check_latch - Check a port latch for a given value. Returns zero if the
- * port contains the given value. Callers must hold hdaps_sem.
+ * port contains the given value. Callers must hold hdaps_mtx.
*/
static inline int __check_latch(u16 port, u8 val)
{
@@ -94,7 +96,7 @@ static inline int __check_latch(u16 port, u8 val)
/*
* __wait_latch - Wait up to 100us for a port latch to get a certain value,
- * returning zero if the value is obtained. Callers must hold hdaps_sem.
+ * returning zero if the value is obtained. Callers must hold hdaps_mtx.
*/
static int __wait_latch(u16 port, u8 val)
{
@@ -111,7 +113,7 @@ static int __wait_latch(u16 port, u8 val)
/*
* __device_refresh - request a refresh from the accelerometer. Does not wait
- * for refresh to complete. Callers must hold hdaps_sem.
+ * for refresh to complete. Callers must hold hdaps_mtx.
*/
static void __device_refresh(void)
{
@@ -125,7 +127,7 @@ static void __device_refresh(void)
/*
* __device_refresh_sync - request a synchronous refresh from the
* accelerometer. We wait for the refresh to complete. Returns zero if
- * successful and nonzero on error. Callers must hold hdaps_sem.
+ * successful and nonzero on error. Callers must hold hdaps_mtx.
*/
static int __device_refresh_sync(void)
{
@@ -135,7 +137,7 @@ static int __device_refresh_sync(void)
/*
* __device_complete - indicate to the accelerometer that we are done reading
- * data, and then initiate an async refresh. Callers must hold hdaps_sem.
+ * data, and then initiate an async refresh. Callers must hold hdaps_mtx.
*/
static inline void __device_complete(void)
{
@@ -153,7 +155,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val)
{
int ret;
- down(&hdaps_sem);
+ mutex_lock(&hdaps_mtx);
/* do a sync refresh -- we need to be sure that we read fresh data */
ret = __device_refresh_sync();
@@ -164,7 +166,7 @@ static int hdaps_readb_one(unsigned int port, u8 *val)
__device_complete();
out:
- up(&hdaps_sem);
+ mutex_unlock(&hdaps_mtx);
return ret;
}
@@ -199,9 +201,9 @@ static int hdaps_read_pair(unsigned int port1, unsigned int port2,
{
int ret;
- down(&hdaps_sem);
+ mutex_lock(&hdaps_mtx);
ret = __hdaps_read_pair(port1, port2, val1, val2);
- up(&hdaps_sem);
+ mutex_unlock(&hdaps_mtx);
return ret;
}
@@ -214,7 +216,7 @@ static int hdaps_device_init(void)
{
int total, ret = -ENXIO;
- down(&hdaps_sem);
+ mutex_lock(&hdaps_mtx);
outb(0x13, 0x1610);
outb(0x01, 0x161f);
@@ -280,7 +282,7 @@ static int hdaps_device_init(void)
}
out:
- up(&hdaps_sem);
+ mutex_unlock(&hdaps_mtx);
return ret;
}
@@ -314,7 +316,7 @@ static struct platform_driver hdaps_driver = {
};
/*
- * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem.
+ * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_mtx.
*/
static void hdaps_calibrate(void)
{
@@ -326,7 +328,7 @@ static void hdaps_mousedev_poll(unsigned long unused)
int x, y;
/* Cannot sleep. Try nonblockingly. If we fail, try again later. */
- if (down_trylock(&hdaps_sem)) {
+ if (mutex_trylock(&hdaps_mtx)) {
mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD);
return;
}
@@ -341,7 +343,7 @@ static void hdaps_mousedev_poll(unsigned long unused)
mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD);
out:
- up(&hdaps_sem);
+ mutex_unlock(&hdaps_mtx);
}
@@ -421,9 +423,9 @@ static ssize_t hdaps_calibrate_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- down(&hdaps_sem);
+ mutex_lock(&hdaps_mtx);
hdaps_calibrate();
- up(&hdaps_sem);
+ mutex_unlock(&hdaps_mtx);
return count;
}
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index b80f6ed5acf..5aab23b93e2 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -166,16 +166,16 @@ static struct vrm_model vrm_models[] = {
{X86_VENDOR_INTEL, 0x6, 0xE, ANY, 14}, /* Intel Core (65 nm) */
{X86_VENDOR_INTEL, 0x6, 0xF, ANY, 110}, /* Intel Conroe */
{X86_VENDOR_INTEL, 0x6, ANY, ANY, 82}, /* any P6 */
- {X86_VENDOR_INTEL, 0x7, ANY, ANY, 0}, /* Itanium */
{X86_VENDOR_INTEL, 0xF, 0x0, ANY, 90}, /* P4 */
{X86_VENDOR_INTEL, 0xF, 0x1, ANY, 90}, /* P4 Willamette */
{X86_VENDOR_INTEL, 0xF, 0x2, ANY, 90}, /* P4 Northwood */
{X86_VENDOR_INTEL, 0xF, ANY, ANY, 100}, /* Prescott and above assume VRD 10 */
- {X86_VENDOR_INTEL, 0x10, ANY, ANY, 0}, /* Itanium 2 */
{X86_VENDOR_CENTAUR, 0x6, 0x7, ANY, 85}, /* Eden ESP/Ezra */
{X86_VENDOR_CENTAUR, 0x6, 0x8, 0x7, 85}, /* Ezra T */
{X86_VENDOR_CENTAUR, 0x6, 0x9, 0x7, 85}, /* Nemiah */
- {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M */
+ {X86_VENDOR_CENTAUR, 0x6, 0x9, ANY, 17}, /* C3-M, Eden-N */
+ {X86_VENDOR_CENTAUR, 0x6, 0xA, 0x7, 0}, /* No information */
+ {X86_VENDOR_CENTAUR, 0x6, 0xA, ANY, 13}, /* C7, Esther */
{X86_VENDOR_UNKNOWN, ANY, ANY, ANY, 0} /* stop here */
};
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 7c65b8bb6d7..a40166ffad1 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -24,6 +24,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include "lm75.h"
@@ -39,10 +40,12 @@ I2C_CLIENT_INSMOD_1(lm75);
/* Many LM75 constants specified below */
/* The LM75 registers */
-#define LM75_REG_TEMP 0x00
#define LM75_REG_CONF 0x01
-#define LM75_REG_TEMP_HYST 0x02
-#define LM75_REG_TEMP_OS 0x03
+static const u8 LM75_REG_TEMP[3] = {
+ 0x00, /* input */
+ 0x03, /* max */
+ 0x02, /* hyst */
+};
/* Each client has this additional data */
struct lm75_data {
@@ -51,9 +54,10 @@ struct lm75_data {
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u16 temp_input; /* Register values */
- u16 temp_max;
- u16 temp_hyst;
+ u16 temp[3]; /* Register values,
+ 0 = input
+ 1 = max
+ 2 = hyst */
};
static int lm75_attach_adapter(struct i2c_adapter *adapter);
@@ -75,35 +79,36 @@ static struct i2c_driver lm75_driver = {
.detach_client = lm75_detach_client,
};
-#define show(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct lm75_data *data = lm75_update_device(dev); \
- return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct lm75_data *data = lm75_update_device(dev);
+ return sprintf(buf, "%d\n",
+ LM75_TEMP_FROM_REG(data->temp[attr->index]));
}
-show(temp_max);
-show(temp_hyst);
-show(temp_input);
-
-#define set(value, reg) \
-static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct lm75_data *data = i2c_get_clientdata(client); \
- int temp = simple_strtoul(buf, NULL, 10); \
- \
- mutex_lock(&data->update_lock); \
- data->value = LM75_TEMP_TO_REG(temp); \
- lm75_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm75_data *data = i2c_get_clientdata(client);
+ int nr = attr->index;
+ unsigned long temp = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp[nr] = LM75_TEMP_TO_REG(temp);
+ lm75_write_value(client, LM75_REG_TEMP[nr], data->temp[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
}
-set(temp_max, LM75_REG_TEMP_OS);
-set(temp_hyst, LM75_REG_TEMP_HYST);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
-static DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst);
-static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+ show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static int lm75_attach_adapter(struct i2c_adapter *adapter)
{
@@ -113,9 +118,9 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)
}
static struct attribute *lm75_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp1_max_hyst.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
NULL
};
@@ -283,11 +288,12 @@ static struct lm75_data *lm75_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
+ int i;
dev_dbg(&client->dev, "Starting lm75 update\n");
- data->temp_input = lm75_read_value(client, LM75_REG_TEMP);
- data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS);
- data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST);
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+ data->temp[i] = lm75_read_value(client,
+ LM75_REG_TEMP[i]);
data->last_updated = jiffies;
data->valid = 1;
}
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 886786c3391..9fb572f03ba 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -2,6 +2,7 @@
lm78.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+ Copyright (c) 2007 Jean Delvare <khali@linux-fr.org>
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
@@ -23,13 +24,18 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <asm/io.h>
+/* ISA device, if found */
+static struct platform_device *pdev;
+
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29,
@@ -121,12 +127,8 @@ static inline int TEMP_FROM_REG(s8 val)
a bit - except if there could be more than one SMBus. Groan. No solution
for this yet. */
-/* This module may seem overly long and complicated. In fact, it is not so
- bad. Quite a lot of bookkeeping is done. A real driver can often cut
- some corners. */
-
-/* For each registered chip, we need to keep some data in memory.
- The structure is dynamically allocated. */
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+ the driver field to differentiate between I2C and ISA chips. */
struct lm78_data {
struct i2c_client client;
struct class_device *class_dev;
@@ -152,14 +154,16 @@ struct lm78_data {
static int lm78_attach_adapter(struct i2c_adapter *adapter);
-static int lm78_isa_attach_adapter(struct i2c_adapter *adapter);
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind);
static int lm78_detach_client(struct i2c_client *client);
-static int lm78_read_value(struct i2c_client *client, u8 reg);
-static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int __devinit lm78_isa_probe(struct platform_device *pdev);
+static int __devexit lm78_isa_remove(struct platform_device *pdev);
+
+static int lm78_read_value(struct lm78_data *data, u8 reg);
+static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value);
static struct lm78_data *lm78_update_device(struct device *dev);
-static void lm78_init_client(struct i2c_client *client);
+static void lm78_init_device(struct lm78_data *data);
static struct i2c_driver lm78_driver = {
@@ -171,95 +175,78 @@ static struct i2c_driver lm78_driver = {
.detach_client = lm78_detach_client,
};
-static struct i2c_driver lm78_isa_driver = {
+static struct platform_driver lm78_isa_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "lm78-isa",
+ .name = "lm78",
},
- .attach_adapter = lm78_isa_attach_adapter,
- .detach_client = lm78_detach_client,
+ .probe = lm78_isa_probe,
+ .remove = lm78_isa_remove,
};
/* 7 Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct lm78_data *data = lm78_update_device(dev);
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index]));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct lm78_data *data = lm78_update_device(dev);
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index]));
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct lm78_data *data = lm78_update_device(dev);
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
+ return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index]));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct lm78_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
+ int nr = attr->index;
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
- lm78_write_value(client, LM78_REG_IN_MIN(nr), data->in_min[nr]);
+ lm78_write_value(data, LM78_REG_IN_MIN(nr), data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct lm78_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
+ int nr = attr->index;
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
- lm78_write_value(client, LM78_REG_IN_MAX(nr), data->in_max[nr]);
+ lm78_write_value(data, LM78_REG_IN_MAX(nr), data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_in_offset(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
- show_in##offset, NULL); \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
show_in_offset(0);
show_in_offset(1);
@@ -270,46 +257,49 @@ show_in_offset(5);
show_in_offset(6);
/* Temperature */
-static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp));
}
-static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over));
}
-static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct lm78_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over = TEMP_TO_REG(val);
- lm78_write_value(client, LM78_REG_TEMP_OVER, data->temp_over);
+ lm78_write_value(data, LM78_REG_TEMP_OVER, data->temp_over);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst));
}
-static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct lm78_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst = TEMP_TO_REG(val);
- lm78_write_value(client, LM78_REG_TEMP_HYST, data->temp_hyst);
+ lm78_write_value(data, LM78_REG_TEMP_HYST, data->temp_hyst);
mutex_unlock(&data->update_lock);
return count;
}
@@ -321,49 +311,59 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
show_temp_hyst, set_temp_hyst);
/* 3 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct lm78_data *data = lm78_update_device(dev);
+ int nr = attr->index;
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct lm78_data *data = lm78_update_device(dev);
+ int nr = attr->index;
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct lm78_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+ lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+ char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct lm78_data *data = lm78_update_device(dev);
- return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
}
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct lm78_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
unsigned long min;
u8 reg;
@@ -378,13 +378,13 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
- dev_err(&client->dev, "fan_div value %ld not "
+ dev_err(dev, "fan_div value %ld not "
"supported. Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
}
- reg = lm78_read_value(client, LM78_REG_VID_FANDIV);
+ reg = lm78_read_value(data, LM78_REG_VID_FANDIV);
switch (nr) {
case 0:
reg = (reg & 0xcf) | (data->fan_div[nr] << 4);
@@ -393,63 +393,36 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
break;
}
- lm78_write_value(client, LM78_REG_VID_FANDIV, reg);
+ lm78_write_value(data, LM78_REG_VID_FANDIV, reg);
data->fan_min[nr] =
FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- lm78_write_value(client, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
+ lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min);
-
-static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
-{
- return set_fan_div(dev, buf, count, 0) ;
-}
-
-static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
-{
- return set_fan_div(dev, buf, count, 1) ;
-}
+#define show_fan_offset(offset) \
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1);
show_fan_offset(1);
show_fan_offset(2);
show_fan_offset(3);
/* Fan 3 divisor is locked in H/W */
-static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
- show_fan_1_div, set_fan_1_div);
-static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
- show_fan_2_div, set_fan_2_div);
-static DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_3_div, NULL);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+ show_fan_div, set_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+ show_fan_div, set_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2);
/* VID */
-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_vid(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82));
@@ -457,7 +430,8 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
/* Alarms */
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct lm78_data *data = lm78_update_device(dev);
return sprintf(buf, "%u\n", data->alarms);
@@ -475,45 +449,40 @@ static int lm78_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm78_detect);
}
-static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
-{
- return lm78_detect(adapter, isa_address, -1);
-}
-
static struct attribute *lm78_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
- &dev_attr_in5_input.attr,
- &dev_attr_in5_min.attr,
- &dev_attr_in5_max.attr,
- &dev_attr_in6_input.attr,
- &dev_attr_in6_min.attr,
- &dev_attr_in6_max.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
&dev_attr_temp1_max_hyst.attr,
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
- &dev_attr_fan3_input.attr,
- &dev_attr_fan3_min.attr,
- &dev_attr_fan3_div.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
&dev_attr_alarms.attr,
&dev_attr_cpu0_vid.attr,
@@ -524,6 +493,17 @@ static const struct attribute_group lm78_group = {
.attrs = lm78_attributes,
};
+/* I2C devices get this name attribute automatically, but for ISA devices
+ we must create it by ourselves. */
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct lm78_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->client.name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
/* This function is called by i2c_probe */
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -531,54 +511,10 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
struct i2c_client *new_client;
struct lm78_data *data;
const char *client_name = "";
- int is_isa = i2c_is_isa_adapter(adapter);
- if (!is_isa &&
- !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
err = -ENODEV;
- goto ERROR0;
- }
-
- /* Reserve the ISA region */
- if (is_isa)
- if (!request_region(address, LM78_EXTENT,
- lm78_isa_driver.driver.name)) {
- err = -EBUSY;
- goto ERROR0;
- }
-
- /* Probe whether there is anything available on this address. Already
- done for SMBus clients */
- if (kind < 0) {
- if (is_isa) {
-
-#define REALLY_SLOW_IO
- /* We need the timeouts for at least some LM78-like
- chips. But only if we read 'undefined' registers. */
- i = inb_p(address + 1);
- if (inb_p(address + 2) != i) {
- err = -ENODEV;
- goto ERROR1;
- }
- if (inb_p(address + 3) != i) {
- err = -ENODEV;
- goto ERROR1;
- }
- if (inb_p(address + 7) != i) {
- err = -ENODEV;
- goto ERROR1;
- }
-#undef REALLY_SLOW_IO
-
- /* Let's just hope nothing breaks here */
- i = inb_p(address + 5) & 0x7f;
- outb_p(~i & 0x7f, address + 5);
- if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
- outb_p(i, address + 5);
- err = -ENODEV;
- goto ERROR1;
- }
- }
+ goto ERROR1;
}
/* OK. For now, we presume we have a valid client. We now create the
@@ -591,22 +527,19 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
}
new_client = &data->client;
- if (is_isa)
- mutex_init(&data->lock);
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = is_isa ? &lm78_isa_driver : &lm78_driver;
- new_client->flags = 0;
+ new_client->driver = &lm78_driver;
/* Now, we do the remaining detection. */
if (kind < 0) {
- if (lm78_read_value(new_client, LM78_REG_CONFIG) & 0x80) {
+ if (lm78_read_value(data, LM78_REG_CONFIG) & 0x80) {
err = -ENODEV;
goto ERROR2;
}
- if (!is_isa && (lm78_read_value(
- new_client, LM78_REG_I2C_ADDR) != address)) {
+ if (lm78_read_value(data, LM78_REG_I2C_ADDR) !=
+ address) {
err = -ENODEV;
goto ERROR2;
}
@@ -614,7 +547,7 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
/* Determine the chip type. */
if (kind <= 0) {
- i = lm78_read_value(new_client, LM78_REG_CHIPID);
+ i = lm78_read_value(data, LM78_REG_CHIPID);
if (i == 0x00 || i == 0x20 /* LM78 */
|| i == 0x40) /* LM78-J */
kind = lm78;
@@ -641,21 +574,12 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
data->type = kind;
- data->valid = 0;
- mutex_init(&data->update_lock);
-
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(new_client)))
goto ERROR2;
/* Initialize the LM78 chip */
- lm78_init_client(new_client);
-
- /* A few vars need to be filled upon startup */
- for (i = 0; i < 3; i++) {
- data->fan_min[i] = lm78_read_value(new_client,
- LM78_REG_FAN_MIN(i));
- }
+ lm78_init_device(data);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
@@ -676,9 +600,6 @@ ERROR3:
ERROR2:
kfree(data);
ERROR1:
- if (is_isa)
- release_region(address, LM78_EXTENT);
-ERROR0:
return err;
}
@@ -693,9 +614,77 @@ static int lm78_detach_client(struct i2c_client *client)
if ((err = i2c_detach_client(client)))
return err;
- if(i2c_is_isa_client(client))
- release_region(client->addr, LM78_EXTENT);
+ kfree(data);
+
+ return 0;
+}
+
+static int __devinit lm78_isa_probe(struct platform_device *pdev)
+{
+ int err;
+ struct lm78_data *data;
+ struct resource *res;
+ const char *name;
+
+ /* Reserve the ISA region */
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, LM78_EXTENT, "lm78")) {
+ err = -EBUSY;
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit_release_region;
+ }
+ mutex_init(&data->lock);
+ data->client.addr = res->start;
+ i2c_set_clientdata(&data->client, data);
+ platform_set_drvdata(pdev, data);
+
+ if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) {
+ data->type = lm79;
+ name = "lm79";
+ } else {
+ data->type = lm78;
+ name = "lm78";
+ }
+ strlcpy(data->client.name, name, I2C_NAME_SIZE);
+
+ /* Initialize the LM78 chip */
+ lm78_init_device(data);
+
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &lm78_group))
+ || (err = device_create_file(&pdev->dev, &dev_attr_name)))
+ goto exit_remove_files;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+ exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ kfree(data);
+ exit_release_region:
+ release_region(res->start, LM78_EXTENT);
+ exit:
+ return err;
+}
+
+static int __devexit lm78_isa_remove(struct platform_device *pdev)
+{
+ struct lm78_data *data = platform_get_drvdata(pdev);
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &lm78_group);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ release_region(data->client.addr, LM78_EXTENT);
kfree(data);
return 0;
@@ -706,11 +695,12 @@ static int lm78_detach_client(struct i2c_client *client)
separately.
We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks,
would slow down the LM78 access and should not be necessary. */
-static int lm78_read_value(struct i2c_client *client, u8 reg)
+static int lm78_read_value(struct lm78_data *data, u8 reg)
{
- int res;
- if (i2c_is_isa_client(client)) {
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct i2c_client *client = &data->client;
+
+ if (!client->driver) { /* ISA device */
+ int res;
mutex_lock(&data->lock);
outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
res = inb_p(client->addr + LM78_DATA_REG_OFFSET);
@@ -727,10 +717,11 @@ static int lm78_read_value(struct i2c_client *client, u8 reg)
would slow down the LM78 access and should not be necessary.
There are some ugly typecasts here, but the good new is - they should
nowhere else be necessary! */
-static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
+static int lm78_write_value(struct lm78_data *data, u8 reg, u8 value)
{
- if (i2c_is_isa_client(client)) {
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct i2c_client *client = &data->client;
+
+ if (!client->driver) { /* ISA device */
mutex_lock(&data->lock);
outb_p(reg, client->addr + LM78_ADDR_REG_OFFSET);
outb_p(value, client->addr + LM78_DATA_REG_OFFSET);
@@ -740,20 +731,29 @@ static int lm78_write_value(struct i2c_client *client, u8 reg, u8 value)
return i2c_smbus_write_byte_data(client, reg, value);
}
-static void lm78_init_client(struct i2c_client *client)
+static void lm78_init_device(struct lm78_data *data)
{
- u8 config = lm78_read_value(client, LM78_REG_CONFIG);
+ u8 config;
+ int i;
/* Start monitoring */
- if (!(config & 0x01))
- lm78_write_value(client, LM78_REG_CONFIG,
+ config = lm78_read_value(data, LM78_REG_CONFIG);
+ if ((config & 0x09) != 0x01)
+ lm78_write_value(data, LM78_REG_CONFIG,
(config & 0xf7) | 0x01);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 0; i < 3; i++) {
+ data->fan_min[i] = lm78_read_value(data,
+ LM78_REG_FAN_MIN(i));
+ }
+
+ mutex_init(&data->update_lock);
}
static struct lm78_data *lm78_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct lm78_data *data = i2c_get_clientdata(client);
+ struct lm78_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -761,39 +761,39 @@ static struct lm78_data *lm78_update_device(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
- dev_dbg(&client->dev, "Starting lm78 update\n");
+ dev_dbg(dev, "Starting lm78 update\n");
for (i = 0; i <= 6; i++) {
data->in[i] =
- lm78_read_value(client, LM78_REG_IN(i));
+ lm78_read_value(data, LM78_REG_IN(i));
data->in_min[i] =
- lm78_read_value(client, LM78_REG_IN_MIN(i));
+ lm78_read_value(data, LM78_REG_IN_MIN(i));
data->in_max[i] =
- lm78_read_value(client, LM78_REG_IN_MAX(i));
+ lm78_read_value(data, LM78_REG_IN_MAX(i));
}
for (i = 0; i < 3; i++) {
data->fan[i] =
- lm78_read_value(client, LM78_REG_FAN(i));
+ lm78_read_value(data, LM78_REG_FAN(i));
data->fan_min[i] =
- lm78_read_value(client, LM78_REG_FAN_MIN(i));
+ lm78_read_value(data, LM78_REG_FAN_MIN(i));
}
- data->temp = lm78_read_value(client, LM78_REG_TEMP);
+ data->temp = lm78_read_value(data, LM78_REG_TEMP);
data->temp_over =
- lm78_read_value(client, LM78_REG_TEMP_OVER);
+ lm78_read_value(data, LM78_REG_TEMP_OVER);
data->temp_hyst =
- lm78_read_value(client, LM78_REG_TEMP_HYST);
- i = lm78_read_value(client, LM78_REG_VID_FANDIV);
+ lm78_read_value(data, LM78_REG_TEMP_HYST);
+ i = lm78_read_value(data, LM78_REG_VID_FANDIV);
data->vid = i & 0x0f;
if (data->type == lm79)
data->vid |=
- (lm78_read_value(client, LM78_REG_CHIPID) &
+ (lm78_read_value(data, LM78_REG_CHIPID) &
0x01) << 4;
else
data->vid |= 0x10;
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
- data->alarms = lm78_read_value(client, LM78_REG_ALARM1) +
- (lm78_read_value(client, LM78_REG_ALARM2) << 8);
+ data->alarms = lm78_read_value(data, LM78_REG_ALARM1) +
+ (lm78_read_value(data, LM78_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
@@ -805,26 +805,154 @@ static struct lm78_data *lm78_update_device(struct device *dev)
return data;
}
+/* return 1 if a supported chip is found, 0 otherwise */
+static int __init lm78_isa_found(unsigned short address)
+{
+ int val, save, found = 0;
+
+ if (!request_region(address, LM78_EXTENT, "lm78"))
+ return 0;
+
+#define REALLY_SLOW_IO
+ /* We need the timeouts for at least some LM78-like
+ chips. But only if we read 'undefined' registers. */
+ val = inb_p(address + 1);
+ if (inb_p(address + 2) != val
+ || inb_p(address + 3) != val
+ || inb_p(address + 7) != val)
+ goto release;
+#undef REALLY_SLOW_IO
+
+ /* We should be able to change the 7 LSB of the address port. The
+ MSB (busy flag) should be clear initially, set after the write. */
+ save = inb_p(address + LM78_ADDR_REG_OFFSET);
+ if (save & 0x80)
+ goto release;
+ val = ~save & 0x7f;
+ outb_p(val, address + LM78_ADDR_REG_OFFSET);
+ if (inb_p(address + LM78_ADDR_REG_OFFSET) != (val | 0x80)) {
+ outb_p(save, address + LM78_ADDR_REG_OFFSET);
+ goto release;
+ }
+
+ /* We found a device, now see if it could be an LM78 */
+ outb_p(LM78_REG_CONFIG, address + LM78_ADDR_REG_OFFSET);
+ val = inb_p(address + LM78_DATA_REG_OFFSET);
+ if (val & 0x80)
+ goto release;
+ outb_p(LM78_REG_I2C_ADDR, address + LM78_ADDR_REG_OFFSET);
+ val = inb_p(address + LM78_DATA_REG_OFFSET);
+ if (val < 0x03 || val > 0x77) /* Not a valid I2C address */
+ goto release;
+
+ /* The busy flag should be clear again */
+ if (inb_p(address + LM78_ADDR_REG_OFFSET) & 0x80)
+ goto release;
+
+ /* Explicitly prevent the misdetection of Winbond chips */
+ outb_p(0x4f, address + LM78_ADDR_REG_OFFSET);
+ val = inb_p(address + LM78_DATA_REG_OFFSET);
+ if (val == 0xa3 || val == 0x5c)
+ goto release;
+
+ /* Explicitly prevent the misdetection of ITE chips */
+ outb_p(0x58, address + LM78_ADDR_REG_OFFSET);
+ val = inb_p(address + LM78_DATA_REG_OFFSET);
+ if (val == 0x90)
+ goto release;
+
+ /* Determine the chip type */
+ outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET);
+ val = inb_p(address + LM78_DATA_REG_OFFSET);
+ if (val == 0x00 /* LM78 */
+ || val == 0x40 /* LM78-J */
+ || (val & 0xfe) == 0xc0) /* LM79 */
+ found = 1;
+
+ if (found)
+ pr_info("lm78: Found an %s chip at %#x\n",
+ val & 0x80 ? "LM79" : "LM78", (int)address);
+
+ release:
+ release_region(address, LM78_EXTENT);
+ return found;
+}
+
+static int __init lm78_isa_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + LM78_EXTENT,
+ .name = "lm78",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("lm78", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "lm78: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "lm78: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "lm78: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+ exit_device_put:
+ platform_device_put(pdev);
+ exit:
+ pdev = NULL;
+ return err;
+}
+
static int __init sm_lm78_init(void)
{
int res;
res = i2c_add_driver(&lm78_driver);
if (res)
- return res;
+ goto exit;
- /* Don't exit if this one fails, we still want the I2C variants
- to work! */
- if (i2c_isa_add_driver(&lm78_isa_driver))
- isa_address = 0;
+ if (lm78_isa_found(isa_address)) {
+ res = platform_driver_register(&lm78_isa_driver);
+ if (res)
+ goto exit_unreg_i2c_driver;
+
+ /* Sets global pdev as a side effect */
+ res = lm78_isa_device_add(isa_address);
+ if (res)
+ goto exit_unreg_isa_driver;
+ }
return 0;
+
+ exit_unreg_isa_driver:
+ platform_driver_unregister(&lm78_isa_driver);
+ exit_unreg_i2c_driver:
+ i2c_del_driver(&lm78_driver);
+ exit:
+ return res;
}
static void __exit sm_lm78_exit(void)
{
- if (isa_address)
- i2c_isa_del_driver(&lm78_isa_driver);
+ if (pdev) {
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&lm78_isa_driver);
+ }
i2c_del_driver(&lm78_driver);
}
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index 3ce825489e3..988ae1c4aad 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -747,6 +747,7 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
}
if (!(data->channel & CHAN_NO_VID)) {
+ data->vrm = vid_which_vrm();
if ((err = device_create_file(&new_client->dev,
&dev_attr_cpu0_vid))
|| (err = device_create_file(&new_client->dev,
@@ -779,7 +780,6 @@ static void lm87_init_client(struct i2c_client *client)
u8 config;
data->channel = lm87_read_value(client, LM87_REG_CHANNEL_MODE);
- data->vrm = vid_which_vrm();
config = lm87_read_value(client, LM87_REG_CONFIG);
if (!(config & 0x01)) {
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
new file mode 100644
index 00000000000..8415664f33c
--- /dev/null
+++ b/drivers/hwmon/max6650.c
@@ -0,0 +1,693 @@
+/*
+ * max6650.c - Part of lm_sensors, Linux kernel modules for hardware
+ * monitoring.
+ *
+ * (C) 2007 by Hans J. Koch <hjk@linutronix.de>
+ *
+ * based on code written by John Morris <john.morris@spirentcom.com>
+ * Copyright (c) 2003 Spirent Communications
+ * and Claus Gindhart <claus.gindhart@kontron.com>
+ *
+ * This module has only been tested with the MAX6650 chip. It should
+ * also work with the MAX6651. It does not distinguish max6650 and max6651
+ * chips.
+ *
+ * Tha datasheet was last seen at:
+ *
+ * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+
+/*
+ * Addresses to scan. There are four disjoint possibilities, by pin config.
+ */
+
+static unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b, I2C_CLIENT_END};
+
+/*
+ * Insmod parameters
+ */
+
+/* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */
+static int fan_voltage;
+/* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */
+static int prescaler;
+/* clock: The clock frequency of the chip the driver should assume */
+static int clock = 254000;
+
+module_param(fan_voltage, int, S_IRUGO);
+module_param(prescaler, int, S_IRUGO);
+module_param(clock, int, S_IRUGO);
+
+I2C_CLIENT_INSMOD_1(max6650);
+
+/*
+ * MAX 6650/6651 registers
+ */
+
+#define MAX6650_REG_SPEED 0x00
+#define MAX6650_REG_CONFIG 0x02
+#define MAX6650_REG_GPIO_DEF 0x04
+#define MAX6650_REG_DAC 0x06
+#define MAX6650_REG_ALARM_EN 0x08
+#define MAX6650_REG_ALARM 0x0A
+#define MAX6650_REG_TACH0 0x0C
+#define MAX6650_REG_TACH1 0x0E
+#define MAX6650_REG_TACH2 0x10
+#define MAX6650_REG_TACH3 0x12
+#define MAX6650_REG_GPIO_STAT 0x14
+#define MAX6650_REG_COUNT 0x16
+
+/*
+ * Config register bits
+ */
+
+#define MAX6650_CFG_V12 0x08
+#define MAX6650_CFG_PRESCALER_MASK 0x07
+#define MAX6650_CFG_PRESCALER_2 0x01
+#define MAX6650_CFG_PRESCALER_4 0x02
+#define MAX6650_CFG_PRESCALER_8 0x03
+#define MAX6650_CFG_PRESCALER_16 0x04
+#define MAX6650_CFG_MODE_MASK 0x30
+#define MAX6650_CFG_MODE_ON 0x00
+#define MAX6650_CFG_MODE_OFF 0x10
+#define MAX6650_CFG_MODE_CLOSED_LOOP 0x20
+#define MAX6650_CFG_MODE_OPEN_LOOP 0x30
+#define MAX6650_COUNT_MASK 0x03
+
+/* Minimum and maximum values of the FAN-RPM */
+#define FAN_RPM_MIN 240
+#define FAN_RPM_MAX 30000
+
+#define DIV_FROM_REG(reg) (1 << (reg & 7))
+
+static int max6650_attach_adapter(struct i2c_adapter *adapter);
+static int max6650_detect(struct i2c_adapter *adapter, int address, int kind);
+static int max6650_init_client(struct i2c_client *client);
+static int max6650_detach_client(struct i2c_client *client);
+static struct max6650_data *max6650_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static struct i2c_driver max6650_driver = {
+ .driver = {
+ .name = "max6650",
+ },
+ .attach_adapter = max6650_attach_adapter,
+ .detach_client = max6650_detach_client,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct max6650_data
+{
+ struct i2c_client client;
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* register values */
+ u8 speed;
+ u8 config;
+ u8 tach[4];
+ u8 count;
+ u8 dac;
+};
+
+static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct max6650_data *data = max6650_update_device(dev);
+ int rpm;
+
+ /*
+ * Calculation details:
+ *
+ * Each tachometer counts over an interval given by the "count"
+ * register (0.25, 0.5, 1 or 2 seconds). This module assumes
+ * that the fans produce two pulses per revolution (this seems
+ * to be the most common).
+ */
+
+ rpm = ((data->tach[attr->index] * 120) / DIV_FROM_REG(data->count));
+ return sprintf(buf, "%d\n", rpm);
+}
+
+/*
+ * Set the fan speed to the specified RPM (or read back the RPM setting).
+ * This works in closed loop mode only. Use pwm1 for open loop speed setting.
+ *
+ * The MAX6650/1 will automatically control fan speed when in closed loop
+ * mode.
+ *
+ * Assumptions:
+ *
+ * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use
+ * the clock module parameter if you need to fine tune this.
+ *
+ * 2) The prescaler (low three bits of the config register) has already
+ * been set to an appropriate value. Use the prescaler module parameter
+ * if your BIOS doesn't initialize the chip properly.
+ *
+ * The relevant equations are given on pages 21 and 22 of the datasheet.
+ *
+ * From the datasheet, the relevant equation when in regulation is:
+ *
+ * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE
+ *
+ * where:
+ *
+ * fCLK is the oscillator frequency (either the 254kHz internal
+ * oscillator or the externally applied clock)
+ *
+ * KTACH is the value in the speed register
+ *
+ * FanSpeed is the speed of the fan in rps
+ *
+ * KSCALE is the prescaler value (1, 2, 4, 8, or 16)
+ *
+ * When reading, we need to solve for FanSpeed. When writing, we need to
+ * solve for KTACH.
+ *
+ * Note: this tachometer is completely separate from the tachometers
+ * used to measure the fan speeds. Only one fan's speed (fan1) is
+ * controlled.
+ */
+
+static ssize_t get_target(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct max6650_data *data = max6650_update_device(dev);
+ int kscale, ktach, rpm;
+
+ /*
+ * Use the datasheet equation:
+ *
+ * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]
+ *
+ * then multiply by 60 to give rpm.
+ */
+
+ kscale = DIV_FROM_REG(data->config);
+ ktach = data->speed;
+ rpm = 60 * kscale * clock / (256 * (ktach + 1));
+ return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_target(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = i2c_get_clientdata(client);
+ int rpm = simple_strtoul(buf, NULL, 10);
+ int kscale, ktach;
+
+ rpm = SENSORS_LIMIT(rpm, FAN_RPM_MIN, FAN_RPM_MAX);
+
+ /*
+ * Divide the required speed by 60 to get from rpm to rps, then
+ * use the datasheet equation:
+ *
+ * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1
+ */
+
+ mutex_lock(&data->update_lock);
+
+ kscale = DIV_FROM_REG(data->config);
+ ktach = ((clock * kscale) / (256 * rpm / 60)) - 1;
+ if (ktach < 0)
+ ktach = 0;
+ if (ktach > 255)
+ ktach = 255;
+ data->speed = ktach;
+
+ i2c_smbus_write_byte_data(client, MAX6650_REG_SPEED, data->speed);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+ * Get/set the fan speed in open loop mode using pwm1 sysfs file.
+ * Speed is given as a relative value from 0 to 255, where 255 is maximum
+ * speed. Note that this is done by writing directly to the chip's DAC,
+ * it won't change the closed loop speed set by fan1_target.
+ * Also note that due to rounding errors it is possible that you don't read
+ * back exactly the value you have set.
+ */
+
+static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ int pwm;
+ struct max6650_data *data = max6650_update_device(dev);
+
+ /* Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.
+ Lower DAC values mean higher speeds. */
+ if (data->config & MAX6650_CFG_V12)
+ pwm = 255 - (255 * (int)data->dac)/180;
+ else
+ pwm = 255 - (255 * (int)data->dac)/76;
+
+ if (pwm < 0)
+ pwm = 0;
+
+ return sprintf(buf, "%d\n", pwm);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = i2c_get_clientdata(client);
+ int pwm = simple_strtoul(buf, NULL, 10);
+
+ pwm = SENSORS_LIMIT(pwm, 0, 255);
+
+ mutex_lock(&data->update_lock);
+
+ if (data->config & MAX6650_CFG_V12)
+ data->dac = 180 - (180 * pwm)/255;
+ else
+ data->dac = 76 - (76 * pwm)/255;
+
+ i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+ * Get/Set controller mode:
+ * Possible values:
+ * 0 = Fan always on
+ * 1 = Open loop, Voltage is set according to speed, not regulated.
+ * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer
+ */
+
+static ssize_t get_enable(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct max6650_data *data = max6650_update_device(dev);
+ int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;
+ int sysfs_modes[4] = {0, 1, 2, 1};
+
+ return sprintf(buf, "%d\n", sysfs_modes[mode]);
+}
+
+static ssize_t set_enable(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = i2c_get_clientdata(client);
+ int mode = simple_strtoul(buf, NULL, 10);
+ int max6650_modes[3] = {0, 3, 2};
+
+ if ((mode < 0)||(mode > 2)) {
+ dev_err(&client->dev,
+ "illegal value for pwm1_enable (%d)\n", mode);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+
+ data->config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+ data->config = (data->config & ~MAX6650_CFG_MODE_MASK)
+ | (max6650_modes[mode] << 4);
+
+ i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, data->config);
+
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+ * Read/write functions for fan1_div sysfs file. The MAX6650 has no such
+ * divider. We handle this by converting between divider and counttime:
+ *
+ * (counttime == k) <==> (divider == 2^k), k = 0, 1, 2, or 3
+ *
+ * Lower values of k allow to connect a faster fan without the risk of
+ * counter overflow. The price is lower resolution. You can also set counttime
+ * using the module parameter. Note that the module parameter "prescaler" also
+ * influences the behaviour. Unfortunately, there's no sysfs attribute
+ * defined for that. See the data sheet for details.
+ */
+
+static ssize_t get_div(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct max6650_data *data = max6650_update_device(dev);
+
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->count));
+}
+
+static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = i2c_get_clientdata(client);
+ int div = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (div) {
+ case 1:
+ data->count = 0;
+ break;
+ case 2:
+ data->count = 1;
+ break;
+ case 4:
+ data->count = 2;
+ break;
+ case 8:
+ data->count = 3;
+ break;
+ default:
+ dev_err(&client->dev,
+ "illegal value for fan divider (%d)\n", div);
+ return -EINVAL;
+ }
+
+ i2c_smbus_write_byte_data(client, MAX6650_REG_COUNT, data->count);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3);
+static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);
+static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);
+static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);
+static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+
+
+static struct attribute *max6650_attrs[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &dev_attr_fan1_target.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm1.attr,
+ NULL
+};
+
+static struct attribute_group max6650_attr_grp = {
+ .attrs = max6650_attrs,
+};
+
+/*
+ * Real code
+ */
+
+static int max6650_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON)) {
+ dev_dbg(&adapter->dev,
+ "FATAL: max6650_attach_adapter class HWMON not set\n");
+ return 0;
+ }
+
+ return i2c_probe(adapter, &addr_data, max6650_detect);
+}
+
+/*
+ * The following function does more than just detection. If detection
+ * succeeds, it also registers the new chip.
+ */
+
+static int max6650_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct max6650_data *data;
+ int err = -ENODEV;
+
+ dev_dbg(&adapter->dev, "max6650_detect called, kind = %d\n", kind);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
+ "byte read mode, skipping.\n");
+ return 0;
+ }
+
+ if (!(data = kzalloc(sizeof(struct max6650_data), GFP_KERNEL))) {
+ dev_err(&adapter->dev, "max6650: out of memory.\n");
+ return -ENOMEM;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &max6650_driver;
+
+ /*
+ * Now we do the remaining detection. A negative kind means that
+ * the driver was loaded with no force parameter (default), so we
+ * must both detect and identify the chip (actually there is only
+ * one possible kind of chip for now, max6650). A zero kind means that
+ * the driver was loaded with the force parameter, the detection
+ * step shall be skipped. A positive kind means that the driver
+ * was loaded with the force parameter and a given kind of chip is
+ * requested, so both the detection and the identification steps
+ * are skipped.
+ *
+ * Currently I can find no way to distinguish between a MAX6650 and
+ * a MAX6651. This driver has only been tried on the former.
+ */
+
+ if ((kind < 0) &&
+ ( (i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
+ ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)
+ ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)
+ ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)
+ ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
+ dev_dbg(&adapter->dev,
+ "max6650: detection failed at 0x%02x.\n", address);
+ goto err_free;
+ }
+
+ dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
+
+ strlcpy(client->name, "max6650", I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ if ((err = i2c_attach_client(client))) {
+ dev_err(&adapter->dev, "max6650: failed to attach client.\n");
+ goto err_free;
+ }
+
+ /*
+ * Initialize the max6650 chip
+ */
+ if (max6650_init_client(client))
+ goto err_detach;
+
+ err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
+ if (err)
+ goto err_detach;
+
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (!IS_ERR(data->class_dev))
+ return 0;
+
+ err = PTR_ERR(data->class_dev);
+ dev_err(&client->dev, "error registering hwmon device.\n");
+ sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
+err_detach:
+ i2c_detach_client(client);
+err_free:
+ kfree(data);
+ return err;
+}
+
+static int max6650_detach_client(struct i2c_client *client)
+{
+ struct max6650_data *data = i2c_get_clientdata(client);
+ int err;
+
+ sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
+ hwmon_device_unregister(data->class_dev);
+ err = i2c_detach_client(client);
+ if (!err)
+ kfree(data);
+ return err;
+}
+
+static int max6650_init_client(struct i2c_client *client)
+{
+ struct max6650_data *data = i2c_get_clientdata(client);
+ int config;
+ int err = -EIO;
+
+ config = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);
+
+ if (config < 0) {
+ dev_err(&client->dev, "Error reading config, aborting.\n");
+ return err;
+ }
+
+ switch (fan_voltage) {
+ case 0:
+ break;
+ case 5:
+ config &= ~MAX6650_CFG_V12;
+ break;
+ case 12:
+ config |= MAX6650_CFG_V12;
+ break;
+ default:
+ dev_err(&client->dev,
+ "illegal value for fan_voltage (%d)\n",
+ fan_voltage);
+ }
+
+ dev_info(&client->dev, "Fan voltage is set to %dV.\n",
+ (config & MAX6650_CFG_V12) ? 12 : 5);
+
+ switch (prescaler) {
+ case 0:
+ break;
+ case 1:
+ config &= ~MAX6650_CFG_PRESCALER_MASK;
+ break;
+ case 2:
+ config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ | MAX6650_CFG_PRESCALER_2;
+ break;
+ case 4:
+ config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ | MAX6650_CFG_PRESCALER_4;
+ break;
+ case 8:
+ config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ | MAX6650_CFG_PRESCALER_8;
+ break;
+ case 16:
+ config = (config & ~MAX6650_CFG_PRESCALER_MASK)
+ | MAX6650_CFG_PRESCALER_16;
+ break;
+ default:
+ dev_err(&client->dev,
+ "illegal value for prescaler (%d)\n",
+ prescaler);
+ }
+
+ dev_info(&client->dev, "Prescaler is set to %d.\n",
+ 1 << (config & MAX6650_CFG_PRESCALER_MASK));
+
+ /* If mode is set to "full off", we change it to "open loop" and
+ * set DAC to 255, which has the same effect. We do this because
+ * there's no "full off" mode defined in hwmon specifcations.
+ */
+
+ if ((config & MAX6650_CFG_MODE_MASK) == MAX6650_CFG_MODE_OFF) {
+ dev_dbg(&client->dev, "Change mode to open loop, full off.\n");
+ config = (config & ~MAX6650_CFG_MODE_MASK)
+ | MAX6650_CFG_MODE_OPEN_LOOP;
+ if (i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, 255)) {
+ dev_err(&client->dev, "DAC write error, aborting.\n");
+ return err;
+ }
+ }
+
+ if (i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, config)) {
+ dev_err(&client->dev, "Config write error, aborting.\n");
+ return err;
+ }
+
+ data->config = config;
+ data->count = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);
+
+ return 0;
+}
+
+static const u8 tach_reg[] = {
+ MAX6650_REG_TACH0,
+ MAX6650_REG_TACH1,
+ MAX6650_REG_TACH2,
+ MAX6650_REG_TACH3,
+};
+
+static struct max6650_data *max6650_update_device(struct device *dev)
+{
+ int i;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6650_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ data->speed = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_SPEED);
+ data->config = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_CONFIG);
+ for (i = 0; i < 4; i++) {
+ data->tach[i] = i2c_smbus_read_byte_data(client,
+ tach_reg[i]);
+ }
+ data->count = i2c_smbus_read_byte_data(client,
+ MAX6650_REG_COUNT);
+ data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+static int __init sensors_max6650_init(void)
+{
+ return i2c_add_driver(&max6650_driver);
+}
+
+static void __exit sensors_max6650_exit(void)
+{
+ i2c_del_driver(&max6650_driver);
+}
+
+MODULE_AUTHOR("Hans J. Koch");
+MODULE_DESCRIPTION("MAX6650 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(sensors_max6650_init);
+module_exit(sensors_max6650_exit);
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index affa21a5ccf..29354fa26f8 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -31,6 +31,7 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
+#include <linux/ioport.h>
#include <asm/io.h>
static struct platform_device *pdev;
@@ -429,6 +430,12 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
/* This will need to be revisited when we add support for
temperature and voltage monitoring. */
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+ err = -EBUSY;
+ dev_err(&pdev->dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start, (unsigned long)res->end);
+ goto exit_kfree;
+ }
data->address[0] = res->start;
mutex_init(&data->lock);
@@ -438,7 +445,7 @@ static int __devinit pc87427_probe(struct platform_device *pdev)
/* Register sysfs hooks */
if ((err = device_create_file(&pdev->dev, &dev_attr_name)))
- goto exit_kfree;
+ goto exit_release_region;
for (i = 0; i < 8; i++) {
if (!(data->fan_enabled & (1 << i)))
continue;
@@ -462,6 +469,8 @@ exit_remove_files:
continue;
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
}
+exit_release_region:
+ release_region(res->start, res->end - res->start + 1);
exit_kfree:
platform_set_drvdata(pdev, NULL);
kfree(data);
@@ -472,6 +481,7 @@ exit:
static int __devexit pc87427_remove(struct platform_device *pdev)
{
struct pc87427_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
int i;
platform_set_drvdata(pdev, NULL);
@@ -484,6 +494,9 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
}
kfree(data);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, res->end - res->start + 1);
+
return 0;
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 72b0e2d8650..943abbd95ab 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -30,16 +30,17 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <asm/io.h>
-/* Address is autodetected, there is no default value */
-static unsigned short address;
+static struct platform_device *pdev;
+
+#define DRVNAME "smsc47b397"
/* Super-I/0 registers and commands */
@@ -91,7 +92,8 @@ static u8 smsc47b397_reg_temp[] = {0x25, 0x26, 0x27, 0x80};
#define SMSC47B397_REG_FAN_MSB(nr) (0x29 + 2 * (nr))
struct smsc47b397_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
struct class_device *class_dev;
struct mutex lock;
@@ -104,45 +106,43 @@ struct smsc47b397_data {
u8 temp[4];
};
-static int smsc47b397_read_value(struct i2c_client *client, u8 reg)
+static int smsc47b397_read_value(struct smsc47b397_data* data, u8 reg)
{
- struct smsc47b397_data *data = i2c_get_clientdata(client);
int res;
mutex_lock(&data->lock);
- outb(reg, client->addr);
- res = inb_p(client->addr + 1);
+ outb(reg, data->addr);
+ res = inb_p(data->addr + 1);
mutex_unlock(&data->lock);
return res;
}
static struct smsc47b397_data *smsc47b397_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47b397_data *data = i2c_get_clientdata(client);
+ struct smsc47b397_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
- dev_dbg(&client->dev, "starting device update...\n");
+ dev_dbg(dev, "starting device update...\n");
/* 4 temperature inputs, 4 fan inputs */
for (i = 0; i < 4; i++) {
- data->temp[i] = smsc47b397_read_value(client,
+ data->temp[i] = smsc47b397_read_value(data,
SMSC47B397_REG_TEMP(i));
/* must read LSB first */
- data->fan[i] = smsc47b397_read_value(client,
+ data->fan[i] = smsc47b397_read_value(data,
SMSC47B397_REG_FAN_LSB(i));
- data->fan[i] |= smsc47b397_read_value(client,
+ data->fan[i] |= smsc47b397_read_value(data,
SMSC47B397_REG_FAN_MSB(i)) << 8;
}
data->last_updated = jiffies;
data->valid = 1;
- dev_dbg(&client->dev, "... device update complete\n");
+ dev_dbg(dev, "... device update complete\n");
}
mutex_unlock(&data->update_lock);
@@ -157,24 +157,18 @@ static int temp_from_reg(u8 reg)
return (s8)reg * 1000;
}
-/* 0 <= nr <= 3 */
-static ssize_t show_temp(struct device *dev, char *buf, int nr)
+static ssize_t show_temp(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct smsc47b397_data *data = smsc47b397_update_device(dev);
- return sprintf(buf, "%d\n", temp_from_reg(data->temp[nr]));
+ return sprintf(buf, "%d\n", temp_from_reg(data->temp[attr->index]));
}
-#define sysfs_temp(num) \
-static ssize_t show_temp##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, num-1); \
-} \
-static DEVICE_ATTR(temp##num##_input, S_IRUGO, show_temp##num, NULL)
-
-sysfs_temp(1);
-sysfs_temp(2);
-sysfs_temp(3);
-sysfs_temp(4);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
/* FAN: 1 RPM/bit
REG: count of 90kHz pulses / revolution */
@@ -183,35 +177,37 @@ static int fan_from_reg(u16 reg)
return 90000 * 60 / reg;
}
-/* 0 <= nr <= 3 */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
- struct smsc47b397_data *data = smsc47b397_update_device(dev);
- return sprintf(buf, "%d\n", fan_from_reg(data->fan[nr]));
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct smsc47b397_data *data = smsc47b397_update_device(dev);
+ return sprintf(buf, "%d\n", fan_from_reg(data->fan[attr->index]));
}
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3);
-#define sysfs_fan(num) \
-static ssize_t show_fan##num(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, num-1); \
-} \
-static DEVICE_ATTR(fan##num##_input, S_IRUGO, show_fan##num, NULL)
-
-sysfs_fan(1);
-sysfs_fan(2);
-sysfs_fan(3);
-sysfs_fan(4);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct smsc47b397_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct attribute *smsc47b397_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp4_input.attr,
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan3_input.attr,
- &dev_attr_fan4_input.attr,
-
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+
+ &dev_attr_name.attr,
NULL
};
@@ -219,44 +215,44 @@ static const struct attribute_group smsc47b397_group = {
.attrs = smsc47b397_attributes,
};
-static int smsc47b397_detach_client(struct i2c_client *client)
+static int __devexit smsc47b397_remove(struct platform_device *pdev)
{
- struct smsc47b397_data *data = i2c_get_clientdata(client);
- int err;
+ struct smsc47b397_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, SMSC_EXTENT);
+ sysfs_remove_group(&pdev->dev.kobj, &smsc47b397_group);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, SMSC_EXTENT);
kfree(data);
return 0;
}
-static int smsc47b397_detect(struct i2c_adapter *adapter);
+static int smsc47b397_probe(struct platform_device *pdev);
-static struct i2c_driver smsc47b397_driver = {
+static struct platform_driver smsc47b397_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "smsc47b397",
+ .name = DRVNAME,
},
- .attach_adapter = smsc47b397_detect,
- .detach_client = smsc47b397_detach_client,
+ .probe = smsc47b397_probe,
+ .remove = __devexit_p(smsc47b397_remove),
};
-static int smsc47b397_detect(struct i2c_adapter *adapter)
+static int __devinit smsc47b397_probe(struct platform_device *pdev)
{
- struct i2c_client *new_client;
+ struct device *dev = &pdev->dev;
struct smsc47b397_data *data;
+ struct resource *res;
int err = 0;
- if (!request_region(address, SMSC_EXTENT,
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, SMSC_EXTENT,
smsc47b397_driver.driver.name)) {
- dev_err(&adapter->dev, "Region 0x%x already in use!\n",
- address);
+ dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+ (unsigned long)res->start,
+ (unsigned long)res->start + SMSC_EXTENT - 1);
return -EBUSY;
}
@@ -265,25 +261,16 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
goto error_release;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
+ data->addr = res->start;
+ data->name = "smsc47b397";
mutex_init(&data->lock);
- new_client->adapter = adapter;
- new_client->driver = &smsc47b397_driver;
- new_client->flags = 0;
-
- strlcpy(new_client->name, "smsc47b397", I2C_NAME_SIZE);
-
mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
- if ((err = i2c_attach_client(new_client)))
+ if ((err = sysfs_create_group(&dev->kobj, &smsc47b397_group)))
goto error_free;
- if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group)))
- goto error_detach;
-
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto error_remove;
@@ -292,13 +279,50 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
return 0;
error_remove:
- sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
-error_detach:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&dev->kobj, &smsc47b397_group);
error_free:
kfree(data);
error_release:
- release_region(address, SMSC_EXTENT);
+ release_region(res->start, SMSC_EXTENT);
+ return err;
+}
+
+static int __init smsc47b397_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + SMSC_EXTENT - 1,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
return err;
}
@@ -320,7 +344,7 @@ static int __init smsc47b397_find(unsigned short *addr)
*addr = (superio_inb(SUPERIO_REG_BASE_MSB) << 8)
| superio_inb(SUPERIO_REG_BASE_LSB);
- printk(KERN_INFO "smsc47b397: found SMSC %s "
+ printk(KERN_INFO DRVNAME ": found SMSC %s "
"(base address 0x%04x, revision %u)\n",
id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
@@ -330,17 +354,33 @@ static int __init smsc47b397_find(unsigned short *addr)
static int __init smsc47b397_init(void)
{
+ unsigned short address;
int ret;
if ((ret = smsc47b397_find(&address)))
return ret;
- return i2c_isa_add_driver(&smsc47b397_driver);
+ ret = platform_driver_register(&smsc47b397_driver);
+ if (ret)
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ ret = smsc47b397_device_add(address);
+ if (ret)
+ goto exit_driver;
+
+ return 0;
+
+exit_driver:
+ platform_driver_unregister(&smsc47b397_driver);
+exit:
+ return ret;
}
static void __exit smsc47b397_exit(void)
{
- i2c_isa_del_driver(&smsc47b397_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&smsc47b397_driver);
}
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index beb881c4b2e..1e21c8cc948 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -3,10 +3,11 @@
for hardware monitoring
Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
- LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
+ LPC47M14x, LPC47M15x, LPC47M192, LPC47M292 and LPC47M997
+ Super-I/O chips.
Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
- Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
and Jean Delvare
@@ -29,17 +30,19 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <asm/io.h>
-/* Address is autodetected, there is no default value */
-static unsigned short address;
+static struct platform_device *pdev;
+
+#define DRVNAME "smsc47m1"
+enum chips { smsc47m1, smsc47m2 };
/* Super-I/0 registers and commands */
@@ -87,10 +90,18 @@ superio_exit(void)
#define SMSC47M1_REG_ALARM 0x04
#define SMSC47M1_REG_TPIN(nr) (0x34 - (nr))
#define SMSC47M1_REG_PPIN(nr) (0x36 - (nr))
-#define SMSC47M1_REG_PWM(nr) (0x56 + (nr))
#define SMSC47M1_REG_FANDIV 0x58
-#define SMSC47M1_REG_FAN(nr) (0x59 + (nr))
-#define SMSC47M1_REG_FAN_PRELOAD(nr) (0x5B + (nr))
+
+static const u8 SMSC47M1_REG_FAN[3] = { 0x59, 0x5a, 0x6b };
+static const u8 SMSC47M1_REG_FAN_PRELOAD[3] = { 0x5b, 0x5c, 0x6c };
+static const u8 SMSC47M1_REG_PWM[3] = { 0x56, 0x57, 0x69 };
+
+#define SMSC47M2_REG_ALARM6 0x09
+#define SMSC47M2_REG_TPIN1 0x38
+#define SMSC47M2_REG_TPIN2 0x37
+#define SMSC47M2_REG_TPIN3 0x2d
+#define SMSC47M2_REG_PPIN3 0x2c
+#define SMSC47M2_REG_FANDIV3 0x6a
#define MIN_FROM_REG(reg,div) ((reg)>=192 ? 0 : \
983040/((192-(reg))*(div)))
@@ -102,45 +113,57 @@ superio_exit(void)
#define PWM_TO_REG(reg) (((reg) >> 1) & 0x7E)
struct smsc47m1_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
+ enum chips type;
struct class_device *class_dev;
- struct mutex lock;
struct mutex update_lock;
unsigned long last_updated; /* In jiffies */
- u8 fan[2]; /* Register value */
- u8 fan_preload[2]; /* Register value */
- u8 fan_div[2]; /* Register encoding, shifted right */
+ u8 fan[3]; /* Register value */
+ u8 fan_preload[3]; /* Register value */
+ u8 fan_div[3]; /* Register encoding, shifted right */
u8 alarms; /* Register encoding */
- u8 pwm[2]; /* Register value (bit 7 is enable) */
+ u8 pwm[3]; /* Register value (bit 0 is disable) */
};
+struct smsc47m1_sio_data {
+ enum chips type;
+};
-static int smsc47m1_detect(struct i2c_adapter *adapter);
-static int smsc47m1_detach_client(struct i2c_client *client);
-
-static int smsc47m1_read_value(struct i2c_client *client, u8 reg);
-static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int smsc47m1_probe(struct platform_device *pdev);
+static int smsc47m1_remove(struct platform_device *pdev);
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
int init);
+static inline int smsc47m1_read_value(struct smsc47m1_data *data, u8 reg)
+{
+ return inb_p(data->addr + reg);
+}
-static struct i2c_driver smsc47m1_driver = {
+static inline void smsc47m1_write_value(struct smsc47m1_data *data, u8 reg,
+ u8 value)
+{
+ outb_p(value, data->addr + reg);
+}
+
+static struct platform_driver smsc47m1_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "smsc47m1",
+ .name = DRVNAME,
},
- .attach_adapter = smsc47m1_detect,
- .detach_client = smsc47m1_detach_client,
+ .probe = smsc47m1_probe,
+ .remove = __devexit_p(smsc47m1_remove),
};
-/* nr is 0 or 1 in the callback functions below */
-
-static ssize_t get_fan(struct device *dev, char *buf, int nr)
+static ssize_t get_fan(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+ int nr = attr->index;
/* This chip (stupidly) stops monitoring fan speed if PWM is
enabled and duty cycle is 0%. This is fine if the monitoring
and control concern the same fan, but troublesome if they are
@@ -152,43 +175,54 @@ static ssize_t get_fan(struct device *dev, char *buf, int nr)
return sprintf(buf, "%d\n", rpm);
}
-static ssize_t get_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t get_fan_min(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
+ int nr = attr->index;
int rpm = MIN_FROM_REG(data->fan_preload[nr],
DIV_FROM_REG(data->fan_div[nr]));
return sprintf(buf, "%d\n", rpm);
}
-static ssize_t get_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t get_fan_div(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
- return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]));
+ return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index]));
}
-static ssize_t get_pwm(struct device *dev, char *buf, int nr)
+static ssize_t get_pwm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
- return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[nr]));
+ return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm[attr->index]));
}
-static ssize_t get_pwm_en(struct device *dev, char *buf, int nr)
+static ssize_t get_pwm_en(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
- return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[nr]));
+ return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index]));
}
-static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t get_alarms(struct device *dev, struct device_attribute
+ *devattr, char *buf)
{
struct smsc47m1_data *data = smsc47m1_update_device(dev, 0);
return sprintf(buf, "%d\n", data->alarms);
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47m1_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct smsc47m1_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
long rpmdiv, val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -200,7 +234,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
}
data->fan_preload[nr] = 192 - ((983040 + rpmdiv / 2) / rpmdiv);
- smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
+ smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
data->fan_preload[nr]);
mutex_unlock(&data->update_lock);
@@ -211,12 +245,12 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
determined in part by the fan clock divider. This follows the principle
of least surprise; the user doesn't expect the fan minimum to change just
because the divider changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47m1_data *data = i2c_get_clientdata(client);
-
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct smsc47m1_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
long new_div = simple_strtol(buf, NULL, 10), tmp;
u8 old_div = DIV_FROM_REG(data->fan_div[nr]);
@@ -234,27 +268,38 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
return -EINVAL;
}
- tmp = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV) & 0x0F;
- tmp |= (data->fan_div[0] << 4) | (data->fan_div[1] << 6);
- smsc47m1_write_value(client, SMSC47M1_REG_FANDIV, tmp);
+ switch (nr) {
+ case 0:
+ case 1:
+ tmp = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV)
+ & ~(0x03 << (4 + 2 * nr));
+ tmp |= data->fan_div[nr] << (4 + 2 * nr);
+ smsc47m1_write_value(data, SMSC47M1_REG_FANDIV, tmp);
+ break;
+ case 2:
+ tmp = smsc47m1_read_value(data, SMSC47M2_REG_FANDIV3) & 0xCF;
+ tmp |= data->fan_div[2] << 4;
+ smsc47m1_write_value(data, SMSC47M2_REG_FANDIV3, tmp);
+ break;
+ }
/* Preserve fan min */
tmp = 192 - (old_div * (192 - data->fan_preload[nr])
+ new_div / 2) / new_div;
data->fan_preload[nr] = SENSORS_LIMIT(tmp, 0, 191);
- smsc47m1_write_value(client, SMSC47M1_REG_FAN_PRELOAD(nr),
+ smsc47m1_write_value(data, SMSC47M1_REG_FAN_PRELOAD[nr],
data->fan_preload[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_pwm(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_pwm(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47m1_data *data = i2c_get_clientdata(client);
-
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct smsc47m1_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
long val = simple_strtol(buf, NULL, 10);
if (val < 0 || val > 255)
@@ -263,19 +308,19 @@ static ssize_t set_pwm(struct device *dev, const char *buf,
mutex_lock(&data->update_lock);
data->pwm[nr] &= 0x81; /* Preserve additional bits */
data->pwm[nr] |= PWM_TO_REG(val);
- smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
+ smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
data->pwm[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_pwm_en(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_pwm_en(struct device *dev, struct device_attribute
+ *devattr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47m1_data *data = i2c_get_clientdata(client);
-
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct smsc47m1_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
long val = simple_strtol(buf, NULL, 10);
if (val != 0 && val != 1)
@@ -284,7 +329,7 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf,
mutex_lock(&data->update_lock);
data->pwm[nr] &= 0xFE; /* preserve the other bits */
data->pwm[nr] |= !val;
- smsc47m1_write_value(client, SMSC47M1_REG_PWM(nr),
+ smsc47m1_write_value(data, SMSC47M1_REG_PWM[nr],
data->pwm[nr]);
mutex_unlock(&data->update_lock);
@@ -292,79 +337,55 @@ static ssize_t set_pwm_en(struct device *dev, const char *buf,
}
#define fan_present(offset) \
-static ssize_t get_fan##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return get_fan(dev, buf, offset - 1); \
-} \
-static ssize_t get_fan##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return get_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t get_fan##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return get_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan##offset##_div (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_div(dev, buf, count, offset - 1); \
-} \
-static ssize_t get_pwm##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return get_pwm(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm(dev, buf, count, offset - 1); \
-} \
-static ssize_t get_pwm##offset##_en (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return get_pwm_en(dev, buf, offset - 1); \
-} \
-static ssize_t set_pwm##offset##_en (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_pwm_en(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset, \
- NULL); \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- get_fan##offset##_min, set_fan##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- get_fan##offset##_div, set_fan##offset##_div); \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- get_pwm##offset, set_pwm##offset); \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
- get_pwm##offset##_en, set_pwm##offset##_en);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan, \
+ NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ get_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ get_fan_div, set_fan_div, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
+ get_pwm, set_pwm, offset - 1); \
+static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
+ get_pwm_en, set_pwm_en, offset - 1)
fan_present(1);
fan_present(2);
+fan_present(3);
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct smsc47m1_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
/* Almost all sysfs files may or may not be created depending on the chip
setup so we create them individually. It is still convenient to define a
group to remove them all at once. */
static struct attribute *smsc47m1_attributes[] = {
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
-
- &dev_attr_pwm1.attr,
- &dev_attr_pwm1_enable.attr,
- &dev_attr_pwm2.attr,
- &dev_attr_pwm2_enable.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -372,7 +393,8 @@ static const struct attribute_group smsc47m1_group = {
.attrs = smsc47m1_attributes,
};
-static int __init smsc47m1_find(unsigned short *addr)
+static int __init smsc47m1_find(unsigned short *addr,
+ struct smsc47m1_sio_data *sio_data)
{
u8 val;
@@ -386,18 +408,32 @@ static int __init smsc47m1_find(unsigned short *addr)
* can do much more besides (device id 0x60).
* The LPC47M997 is undocumented, but seems to be compatible with
* the LPC47M192, and has the same device id.
+ * The LPC47M292 (device id 0x6B) is somewhat compatible, but it
+ * supports a 3rd fan, and the pin configuration registers are
+ * unfortunately different.
*/
- if (val == 0x51)
- printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
- else if (val == 0x59)
- printk(KERN_INFO "smsc47m1: Found SMSC "
- "LPC47M10x/LPC47M112/LPC47M13x\n");
- else if (val == 0x5F)
- printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
- else if (val == 0x60)
- printk(KERN_INFO "smsc47m1: Found SMSC "
- "LPC47M15x/LPC47M192/LPC47M997\n");
- else {
+ switch (val) {
+ case 0x51:
+ pr_info(DRVNAME ": Found SMSC LPC47B27x\n");
+ sio_data->type = smsc47m1;
+ break;
+ case 0x59:
+ pr_info(DRVNAME ": Found SMSC LPC47M10x/LPC47M112/LPC47M13x\n");
+ sio_data->type = smsc47m1;
+ break;
+ case 0x5F:
+ pr_info(DRVNAME ": Found SMSC LPC47M14x\n");
+ sio_data->type = smsc47m1;
+ break;
+ case 0x60:
+ pr_info(DRVNAME ": Found SMSC LPC47M15x/LPC47M192/LPC47M997\n");
+ sio_data->type = smsc47m1;
+ break;
+ case 0x6B:
+ pr_info(DRVNAME ": Found SMSC LPC47M292\n");
+ sio_data->type = smsc47m2;
+ break;
+ default:
superio_exit();
return -ENODEV;
}
@@ -407,7 +443,7 @@ static int __init smsc47m1_find(unsigned short *addr)
| superio_inb(SUPERIO_REG_BASE + 1);
val = superio_inb(SUPERIO_REG_ACT);
if (*addr == 0 || (val & 0x01) == 0) {
- printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");
+ pr_info(DRVNAME ": Device is disabled, will not use\n");
superio_exit();
return -ENODEV;
}
@@ -416,15 +452,25 @@ static int __init smsc47m1_find(unsigned short *addr)
return 0;
}
-static int smsc47m1_detect(struct i2c_adapter *adapter)
+static int __devinit smsc47m1_probe(struct platform_device *pdev)
{
- struct i2c_client *new_client;
+ struct device *dev = &pdev->dev;
+ struct smsc47m1_sio_data *sio_data = dev->platform_data;
struct smsc47m1_data *data;
+ struct resource *res;
int err = 0;
- int fan1, fan2, pwm1, pwm2;
-
- if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.driver.name)) {
- dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);
+ int fan1, fan2, fan3, pwm1, pwm2, pwm3;
+
+ static const char *names[] = {
+ "smsc47m1",
+ "smsc47m2",
+ };
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, SMSC_EXTENT, DRVNAME)) {
+ dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+ (unsigned long)res->start,
+ (unsigned long)res->end);
return -EBUSY;
}
@@ -433,93 +479,114 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
goto error_release;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- mutex_init(&data->lock);
- new_client->adapter = adapter;
- new_client->driver = &smsc47m1_driver;
- new_client->flags = 0;
-
- strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);
+ data->addr = res->start;
+ data->type = sio_data->type;
+ data->name = names[sio_data->type];
mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
/* If no function is properly configured, there's no point in
actually registering the chip. */
- fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)
- == 0x05;
- fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)
- == 0x05;
- pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)
+ pwm1 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(0)) & 0x05)
== 0x04;
- pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
+ pwm2 = (smsc47m1_read_value(data, SMSC47M1_REG_PPIN(1)) & 0x05)
== 0x04;
- if (!(fan1 || fan2 || pwm1 || pwm2)) {
- dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
- "will not use\n", new_client->addr);
+ if (data->type == smsc47m2) {
+ fan1 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN1)
+ & 0x0d) == 0x09;
+ fan2 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN2)
+ & 0x0d) == 0x09;
+ fan3 = (smsc47m1_read_value(data, SMSC47M2_REG_TPIN3)
+ & 0x0d) == 0x0d;
+ pwm3 = (smsc47m1_read_value(data, SMSC47M2_REG_PPIN3)
+ & 0x0d) == 0x08;
+ } else {
+ fan1 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(0))
+ & 0x05) == 0x05;
+ fan2 = (smsc47m1_read_value(data, SMSC47M1_REG_TPIN(1))
+ & 0x05) == 0x05;
+ fan3 = 0;
+ pwm3 = 0;
+ }
+ if (!(fan1 || fan2 || fan3 || pwm1 || pwm2 || pwm3)) {
+ dev_warn(dev, "Device not configured, will not use\n");
err = -ENODEV;
goto error_free;
}
- if ((err = i2c_attach_client(new_client)))
- goto error_free;
-
/* Some values (fan min, clock dividers, pwm registers) may be
needed before any update is triggered, so we better read them
at least once here. We don't usually do it that way, but in
this particular case, manually reading 5 registers out of 8
doesn't make much sense and we're better using the existing
function. */
- smsc47m1_update_device(&new_client->dev, 1);
+ smsc47m1_update_device(dev, 1);
/* Register sysfs hooks */
if (fan1) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_fan1_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan1_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan1_div)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan1_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan1_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan1_div.dev_attr)))
goto error_remove_files;
} else
- dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
- "skipping\n");
+ dev_dbg(dev, "Fan 1 not enabled by hardware, skipping\n");
if (fan2) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_fan2_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan2_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan2_div)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan2_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan2_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan2_div.dev_attr)))
goto error_remove_files;
} else
- dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
- "skipping\n");
+ dev_dbg(dev, "Fan 2 not enabled by hardware, skipping\n");
+
+ if (fan3) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_fan3_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_fan3_div.dev_attr)))
+ goto error_remove_files;
+ } else
+ dev_dbg(dev, "Fan 3 not enabled by hardware, skipping\n");
if (pwm1) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_pwm1))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_pwm1_enable)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm1.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm1_enable.dev_attr)))
goto error_remove_files;
} else
- dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
- "skipping\n");
+ dev_dbg(dev, "PWM 1 not enabled by hardware, skipping\n");
+
if (pwm2) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_pwm2))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_pwm2_enable)))
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm2.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2_enable.dev_attr)))
+ goto error_remove_files;
+ } else
+ dev_dbg(dev, "PWM 2 not enabled by hardware, skipping\n");
+
+ if (pwm3) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm3.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm3_enable.dev_attr)))
goto error_remove_files;
} else
- dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
- "skipping\n");
+ dev_dbg(dev, "PWM 3 not enabled by hardware, skipping\n");
- if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
+ if ((err = device_create_file(dev, &dev_attr_alarms)))
goto error_remove_files;
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto error_remove_files;
@@ -528,78 +595,71 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
return 0;
error_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
- i2c_detach_client(new_client);
+ sysfs_remove_group(&dev->kobj, &smsc47m1_group);
error_free:
kfree(data);
error_release:
- release_region(address, SMSC_EXTENT);
+ release_region(res->start, SMSC_EXTENT);
return err;
}
-static int smsc47m1_detach_client(struct i2c_client *client)
+static int __devexit smsc47m1_remove(struct platform_device *pdev)
{
- struct smsc47m1_data *data = i2c_get_clientdata(client);
- int err;
+ struct smsc47m1_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
+ platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
-
- if ((err = i2c_detach_client(client)))
- return err;
+ sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
- release_region(client->addr, SMSC_EXTENT);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, SMSC_EXTENT);
kfree(data);
return 0;
}
-static int smsc47m1_read_value(struct i2c_client *client, u8 reg)
-{
- int res;
-
- mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
- res = inb_p(client->addr + reg);
- mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
- return res;
-}
-
-static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value)
-{
- mutex_lock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
- outb_p(value, client->addr + reg);
- mutex_unlock(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);
-}
-
static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
int init)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct smsc47m1_data *data = i2c_get_clientdata(client);
+ struct smsc47m1_data *data = dev_get_drvdata(dev);
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || init) {
- int i;
-
- for (i = 0; i < 2; i++) {
- data->fan[i] = smsc47m1_read_value(client,
- SMSC47M1_REG_FAN(i));
- data->fan_preload[i] = smsc47m1_read_value(client,
- SMSC47M1_REG_FAN_PRELOAD(i));
- data->pwm[i] = smsc47m1_read_value(client,
- SMSC47M1_REG_PWM(i));
+ int i, fan_nr;
+ fan_nr = data->type == smsc47m2 ? 3 : 2;
+
+ for (i = 0; i < fan_nr; i++) {
+ data->fan[i] = smsc47m1_read_value(data,
+ SMSC47M1_REG_FAN[i]);
+ data->fan_preload[i] = smsc47m1_read_value(data,
+ SMSC47M1_REG_FAN_PRELOAD[i]);
+ data->pwm[i] = smsc47m1_read_value(data,
+ SMSC47M1_REG_PWM[i]);
}
- i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);
+ i = smsc47m1_read_value(data, SMSC47M1_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
- data->alarms = smsc47m1_read_value(client,
+ data->alarms = smsc47m1_read_value(data,
SMSC47M1_REG_ALARM) >> 6;
/* Clear alarms if needed */
if (data->alarms)
- smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);
+ smsc47m1_write_value(data, SMSC47M1_REG_ALARM, 0xC0);
+
+ if (fan_nr >= 3) {
+ data->fan_div[2] = (smsc47m1_read_value(data,
+ SMSC47M2_REG_FANDIV3) >> 4) & 0x03;
+ data->alarms |= (smsc47m1_read_value(data,
+ SMSC47M2_REG_ALARM6) & 0x40) >> 4;
+ /* Clear alarm if needed */
+ if (data->alarms & 0x04)
+ smsc47m1_write_value(data,
+ SMSC47M2_REG_ALARM6,
+ 0x40);
+ }
data->last_updated = jiffies;
}
@@ -608,18 +668,86 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
return data;
}
+static int __init smsc47m1_device_add(unsigned short address,
+ const struct smsc47m1_sio_data *sio_data)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + SMSC_EXTENT - 1,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
+ GFP_KERNEL);
+ if (!pdev->dev.platform_data) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+ memcpy(pdev->dev.platform_data, sio_data,
+ sizeof(struct smsc47m1_sio_data));
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __init sm_smsc47m1_init(void)
{
- if (smsc47m1_find(&address)) {
+ int err;
+ unsigned short address;
+ struct smsc47m1_sio_data sio_data;
+
+ if (smsc47m1_find(&address, &sio_data))
return -ENODEV;
- }
- return i2c_isa_add_driver(&smsc47m1_driver);
+ err = platform_driver_register(&smsc47m1_driver);
+ if (err)
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ err = smsc47m1_device_add(address, &sio_data);
+ if (err)
+ goto exit_driver;
+
+ return 0;
+
+exit_driver:
+ platform_driver_unregister(&smsc47m1_driver);
+exit:
+ return err;
}
static void __exit sm_smsc47m1_exit(void)
{
- i2c_isa_del_driver(&smsc47m1_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&smsc47m1_driver);
}
MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index a6833f43739..a012f396f35 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -1,6 +1,6 @@
/*
smsc47m192.c - Support for hardware monitoring block of
- SMSC LPC47M192 and LPC47M997 Super I/O chips
+ SMSC LPC47M192 and compatible Super I/O chips
Copyright (C) 2006 Hartmut Rick <linux@rick.claranet.de>
@@ -518,7 +518,7 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
&& (i2c_smbus_read_byte_data(client,
SMSC47M192_REG_VID4) & 0xfe) == 0x80) {
dev_info(&adapter->dev,
- "found SMSC47M192 or SMSC47M997, "
+ "found SMSC47M192 or compatible, "
"version 2, stepping A%d\n", version & 0x0f);
} else {
dev_dbg(&adapter->dev,
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
index 89c23d6add7..9f3e332c5b7 100644
--- a/drivers/hwmon/vt1211.c
+++ b/drivers/hwmon/vt1211.c
@@ -31,6 +31,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/ioport.h>
#include <asm/io.h>
static int uch_config = -1;
@@ -1130,6 +1131,12 @@ static int __devinit vt1211_probe(struct platform_device *pdev)
}
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {
+ err = -EBUSY;
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start, (unsigned long)res->end);
+ goto EXIT_KFREE;
+ }
data->addr = res->start;
data->name = DRVNAME;
mutex_init(&data->update_lock);
@@ -1197,6 +1204,8 @@ EXIT_DEV_REMOVE:
dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
EXIT_DEV_REMOVE_SILENT:
vt1211_remove_sysfs(pdev);
+ release_region(res->start, res->end - res->start + 1);
+EXIT_KFREE:
platform_set_drvdata(pdev, NULL);
kfree(data);
EXIT:
@@ -1206,12 +1215,16 @@ EXIT:
static int __devexit vt1211_remove(struct platform_device *pdev)
{
struct vt1211_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
hwmon_device_unregister(data->class_dev);
vt1211_remove_sysfs(pdev);
platform_set_drvdata(pdev, NULL);
kfree(data);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, res->end - res->start + 1);
+
return 0;
}
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index d7e240635b3..a5b774b07cb 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -5,6 +5,7 @@
Philip Edelbrock <phil@netroedge.com>,
and Mark Studebaker <mdsxyz123@yahoo.com>
Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
+ Copyright (c) 2007 Jean Delvare <khali@linux-fr.org>
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
@@ -42,15 +43,20 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/ioport.h>
#include <asm/io.h>
#include "lm75.h"
+static struct platform_device *pdev;
+
+#define DRVNAME "w83627hf"
+enum chips { w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
+
static u16 force_addr;
module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
@@ -60,12 +66,6 @@ module_param(force_i2c, byte, 0);
MODULE_PARM_DESC(force_i2c,
"Initialize the i2c address of the sensors");
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
-
-/* Insmod parameters */
-enum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf, w83687thf };
-
static int reset;
module_param(reset, bool, 0);
MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
@@ -156,9 +156,9 @@ superio_exit(void)
#define WINB_REGION_OFFSET 5
#define WINB_REGION_SIZE 2
-/* Where are the sensors address/data registers relative to the base address */
-#define W83781D_ADDR_REG_OFFSET 5
-#define W83781D_DATA_REG_OFFSET 6
+/* Where are the sensors address/data registers relative to the region offset */
+#define W83781D_ADDR_REG_OFFSET 0
+#define W83781D_DATA_REG_OFFSET 1
/* The W83781D registers */
/* The W83782D registers for nr=7,8 are in bank 5 */
@@ -289,7 +289,8 @@ static inline u8 DIV_TO_REG(long val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct w83627hf_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
struct class_device *class_dev;
struct mutex lock;
enum chips type;
@@ -298,9 +299,6 @@ struct w83627hf_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- struct i2c_client *lm75; /* for secondary I2C addresses */
- /* pointer to array of 2 subclients */
-
u8 in[9]; /* Register value */
u8 in_max[9]; /* Register value */
u8 in_min[9]; /* Register value */
@@ -327,22 +325,26 @@ struct w83627hf_data {
u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
};
+struct w83627hf_sio_data {
+ enum chips type;
+};
+
-static int w83627hf_detect(struct i2c_adapter *adapter);
-static int w83627hf_detach_client(struct i2c_client *client);
+static int w83627hf_probe(struct platform_device *pdev);
+static int w83627hf_remove(struct platform_device *pdev);
-static int w83627hf_read_value(struct i2c_client *client, u16 reg);
-static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value);
+static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
+static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
static struct w83627hf_data *w83627hf_update_device(struct device *dev);
-static void w83627hf_init_client(struct i2c_client *client);
+static void w83627hf_init_device(struct platform_device *pdev);
-static struct i2c_driver w83627hf_driver = {
+static struct platform_driver w83627hf_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "w83627hf",
+ .name = DRVNAME,
},
- .attach_adapter = w83627hf_detect,
- .detach_client = w83627hf_detach_client,
+ .probe = w83627hf_probe,
+ .remove = __devexit_p(w83627hf_remove),
};
/* following are the sysfs callback functions */
@@ -360,15 +362,14 @@ show_in_reg(in_max)
static ssize_t \
store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627hf_data *data = i2c_get_clientdata(client); \
+ struct w83627hf_data *data = dev_get_drvdata(dev); \
u32 val; \
\
val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->in_##reg[nr] = IN_TO_REG(val); \
- w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \
+ w83627hf_write_value(data, W83781D_REG_IN_##REG(nr), \
data->in_##reg[nr]); \
\
mutex_unlock(&data->update_lock); \
@@ -452,8 +453,7 @@ static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *at
static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -472,7 +472,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
/* use VRM8 (standard) calculation */
data->in_min[0] = IN_TO_REG(val);
- w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);
+ w83627hf_write_value(data, W83781D_REG_IN_MIN(0), data->in_min[0]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -480,8 +480,7 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a
static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -500,7 +499,7 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a
/* use VRM8 (standard) calculation */
data->in_max[0] = IN_TO_REG(val);
- w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);
+ w83627hf_write_value(data, W83781D_REG_IN_MAX(0), data->in_max[0]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -525,8 +524,7 @@ show_fan_reg(fan_min);
static ssize_t
store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -534,7 +532,7 @@ store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
mutex_lock(&data->update_lock);
data->fan_min[nr - 1] =
FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
- w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr),
+ w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr),
data->fan_min[nr - 1]);
mutex_unlock(&data->update_lock);
@@ -587,8 +585,7 @@ show_temp_reg(temp_max_hyst);
static ssize_t \
store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627hf_data *data = i2c_get_clientdata(client); \
+ struct w83627hf_data *data = dev_get_drvdata(dev); \
u32 val; \
\
val = simple_strtoul(buf, NULL, 10); \
@@ -597,11 +594,11 @@ store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
\
if (nr >= 2) { /* TEMP2 and TEMP3 */ \
data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
- w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+ w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
data->temp_##reg##_add[nr-2]); \
} else { /* TEMP1 */ \
data->temp_##reg = TEMP_TO_REG(val); \
- w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+ w83627hf_write_value(data, W83781D_REG_TEMP_##REG(nr), \
data->temp_##reg); \
} \
\
@@ -659,8 +656,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t
store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -695,8 +691,7 @@ static ssize_t
store_beep_reg(struct device *dev, const char *buf, size_t count,
int update_mask)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val, val2;
val = simple_strtoul(buf, NULL, 10);
@@ -705,18 +700,18 @@ store_beep_reg(struct device *dev, const char *buf, size_t count,
if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
data->beep_mask = BEEP_MASK_TO_REG(val);
- w83627hf_write_value(client, W83781D_REG_BEEP_INTS1,
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS1,
data->beep_mask & 0xff);
- w83627hf_write_value(client, W83781D_REG_BEEP_INTS3,
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS3,
((data->beep_mask) >> 16) & 0xff);
val2 = (data->beep_mask >> 8) & 0x7f;
} else { /* We are storing beep_enable */
val2 =
- w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
+ w83627hf_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
data->beep_enable = BEEP_ENABLE_TO_REG(val);
}
- w83627hf_write_value(client, W83781D_REG_BEEP_INTS2,
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS2,
val2 | data->beep_enable << 7);
mutex_unlock(&data->update_lock);
@@ -754,8 +749,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr)
static ssize_t
store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
unsigned long min;
u8 reg;
unsigned long val = simple_strtoul(buf, NULL, 10);
@@ -768,19 +762,19 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
data->fan_div[nr] = DIV_TO_REG(val);
- reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+ reg = (w83627hf_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
& (nr==0 ? 0xcf : 0x3f))
| ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
- w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+ w83627hf_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
- reg = (w83627hf_read_value(client, W83781D_REG_VBAT)
+ reg = (w83627hf_read_value(data, W83781D_REG_VBAT)
& ~(1 << (5 + nr)))
| ((data->fan_div[nr] & 0x04) << (3 + nr));
- w83627hf_write_value(client, W83781D_REG_VBAT, reg);
+ w83627hf_write_value(data, W83781D_REG_VBAT, reg);
/* Restore fan_min */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+ w83627hf_write_value(data, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -814,8 +808,7 @@ show_pwm_reg(struct device *dev, char *buf, int nr)
static ssize_t
store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -825,14 +818,14 @@ store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
if (data->type == w83627thf) {
/* bits 0-3 are reserved in 627THF */
data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0;
- w83627hf_write_value(client,
+ w83627hf_write_value(data,
W836X7HF_REG_PWM(data->type, nr),
data->pwm[nr - 1] |
- (w83627hf_read_value(client,
+ (w83627hf_read_value(data,
W836X7HF_REG_PWM(data->type, nr)) & 0x0f));
} else {
data->pwm[nr - 1] = PWM_TO_REG(val);
- w83627hf_write_value(client,
+ w83627hf_write_value(data,
W836X7HF_REG_PWM(data->type, nr),
data->pwm[nr - 1]);
}
@@ -868,8 +861,7 @@ show_sensor_reg(struct device *dev, char *buf, int nr)
static ssize_t
store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
u32 val, tmp;
val = simple_strtoul(buf, NULL, 10);
@@ -878,31 +870,31 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
switch (val) {
case 1: /* PII/Celeron diode */
- tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
- w83627hf_write_value(client, W83781D_REG_SCFG1,
+ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+ w83627hf_write_value(data, W83781D_REG_SCFG1,
tmp | BIT_SCFG1[nr - 1]);
- tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
- w83627hf_write_value(client, W83781D_REG_SCFG2,
+ tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
+ w83627hf_write_value(data, W83781D_REG_SCFG2,
tmp | BIT_SCFG2[nr - 1]);
data->sens[nr - 1] = val;
break;
case 2: /* 3904 */
- tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
- w83627hf_write_value(client, W83781D_REG_SCFG1,
+ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+ w83627hf_write_value(data, W83781D_REG_SCFG1,
tmp | BIT_SCFG1[nr - 1]);
- tmp = w83627hf_read_value(client, W83781D_REG_SCFG2);
- w83627hf_write_value(client, W83781D_REG_SCFG2,
+ tmp = w83627hf_read_value(data, W83781D_REG_SCFG2);
+ w83627hf_write_value(data, W83781D_REG_SCFG2,
tmp & ~BIT_SCFG2[nr - 1]);
data->sens[nr - 1] = val;
break;
case W83781D_DEFAULT_BETA: /* thermistor */
- tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
- w83627hf_write_value(client, W83781D_REG_SCFG1,
+ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
+ w83627hf_write_value(data, W83781D_REG_SCFG1,
tmp & ~BIT_SCFG1[nr - 1]);
data->sens[nr - 1] = val;
break;
default:
- dev_err(&client->dev,
+ dev_err(dev,
"Invalid sensor type %ld; must be 1, 2, or %d\n",
(long) val, W83781D_DEFAULT_BETA);
break;
@@ -929,35 +921,85 @@ sysfs_sensor(1);
sysfs_sensor(2);
sysfs_sensor(3);
-static int __init w83627hf_find(int sioaddr, unsigned short *addr)
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static int __init w83627hf_find(int sioaddr, unsigned short *addr,
+ struct w83627hf_sio_data *sio_data)
{
+ int err = -ENODEV;
u16 val;
+ static const __initdata char *names[] = {
+ "W83627HF",
+ "W83627THF",
+ "W83697HF",
+ "W83637HF",
+ "W83687THF",
+ };
+
REG = sioaddr;
VAL = sioaddr + 1;
superio_enter();
val= superio_inb(DEVID);
- if(val != W627_DEVID &&
- val != W627THF_DEVID &&
- val != W697_DEVID &&
- val != W637_DEVID &&
- val != W687THF_DEVID) {
- superio_exit();
- return -ENODEV;
+ switch (val) {
+ case W627_DEVID:
+ sio_data->type = w83627hf;
+ break;
+ case W627THF_DEVID:
+ sio_data->type = w83627thf;
+ break;
+ case W697_DEVID:
+ sio_data->type = w83697hf;
+ break;
+ case W637_DEVID:
+ sio_data->type = w83637hf;
+ break;
+ case W687THF_DEVID:
+ sio_data->type = w83687thf;
+ break;
+ default:
+ pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n", val);
+ goto exit;
}
superio_select(W83627HF_LD_HWM);
+ force_addr &= WINB_ALIGNMENT;
+ if (force_addr) {
+ printk(KERN_WARNING DRVNAME ": Forcing address 0x%x\n",
+ force_addr);
+ superio_outb(WINB_BASE_REG, force_addr >> 8);
+ superio_outb(WINB_BASE_REG + 1, force_addr & 0xff);
+ }
val = (superio_inb(WINB_BASE_REG) << 8) |
superio_inb(WINB_BASE_REG + 1);
*addr = val & WINB_ALIGNMENT;
- if (*addr == 0 && force_addr == 0) {
- superio_exit();
- return -ENODEV;
+ if (*addr == 0) {
+ printk(KERN_WARNING DRVNAME ": Base address not set, "
+ "skipping\n");
+ goto exit;
}
+ val = superio_inb(WINB_ACT_REG);
+ if (!(val & 0x01)) {
+ printk(KERN_WARNING DRVNAME ": Enabling HWM logical device\n");
+ superio_outb(WINB_ACT_REG, val | 0x01);
+ }
+
+ err = 0;
+ pr_info(DRVNAME ": Found %s chip at %#x\n",
+ names[sio_data->type], *addr);
+
+ exit:
superio_exit();
- return 0;
+ return err;
}
static struct attribute *w83627hf_attributes[] = {
@@ -1003,6 +1045,7 @@ static struct attribute *w83627hf_attributes[] = {
&dev_attr_pwm1.attr,
&dev_attr_pwm2.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -1039,161 +1082,92 @@ static const struct attribute_group w83627hf_group_opt = {
.attrs = w83627hf_attributes_opt,
};
-static int w83627hf_detect(struct i2c_adapter *adapter)
+static int __devinit w83627hf_probe(struct platform_device *pdev)
{
- int val, kind;
- struct i2c_client *new_client;
+ struct device *dev = &pdev->dev;
+ struct w83627hf_sio_data *sio_data = dev->platform_data;
struct w83627hf_data *data;
- int err = 0;
- const char *client_name = "";
-
- if(force_addr)
- address = force_addr & WINB_ALIGNMENT;
+ struct resource *res;
+ int err;
- if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE,
- w83627hf_driver.driver.name)) {
+ static const char *names[] = {
+ "w83627hf",
+ "w83627thf",
+ "w83697hf",
+ "w83637hf",
+ "w83687thf",
+ };
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, WINB_REGION_SIZE, DRVNAME)) {
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start,
+ (unsigned long)(res->start + WINB_REGION_SIZE - 1));
err = -EBUSY;
goto ERROR0;
}
- if(force_addr) {
- printk("w83627hf.o: forcing ISA address 0x%04X\n", address);
- superio_enter();
- superio_select(W83627HF_LD_HWM);
- superio_outb(WINB_BASE_REG, address >> 8);
- superio_outb(WINB_BASE_REG+1, address & 0xff);
- superio_exit();
- }
-
- superio_enter();
- val= superio_inb(DEVID);
- if(val == W627_DEVID)
- kind = w83627hf;
- else if(val == W697_DEVID)
- kind = w83697hf;
- else if(val == W627THF_DEVID)
- kind = w83627thf;
- else if(val == W637_DEVID)
- kind = w83637hf;
- else if (val == W687THF_DEVID)
- kind = w83687thf;
- else {
- dev_info(&adapter->dev,
- "Unsupported chip (dev_id=0x%02X).\n", val);
- goto ERROR1;
- }
-
- superio_select(W83627HF_LD_HWM);
- if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)
- superio_outb(WINB_ACT_REG, 1);
- superio_exit();
-
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access w83627hf_{read,write}_value. */
-
if (!(data = kzalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {
err = -ENOMEM;
goto ERROR1;
}
-
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
+ data->addr = res->start;
+ data->type = sio_data->type;
+ data->name = names[sio_data->type];
mutex_init(&data->lock);
- new_client->adapter = adapter;
- new_client->driver = &w83627hf_driver;
- new_client->flags = 0;
-
-
- if (kind == w83627hf) {
- client_name = "w83627hf";
- } else if (kind == w83627thf) {
- client_name = "w83627thf";
- } else if (kind == w83697hf) {
- client_name = "w83697hf";
- } else if (kind == w83637hf) {
- client_name = "w83637hf";
- } else if (kind == w83687thf) {
- client_name = "w83687thf";
- }
-
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
- data->type = kind;
- data->valid = 0;
mutex_init(&data->update_lock);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto ERROR2;
-
- data->lm75 = NULL;
+ platform_set_drvdata(pdev, data);
/* Initialize the chip */
- w83627hf_init_client(new_client);
+ w83627hf_init_device(pdev);
/* A few vars need to be filled upon startup */
- data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1));
- data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
- data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
+ data->fan_min[0] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(1));
+ data->fan_min[1] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(2));
+ data->fan_min[2] = w83627hf_read_value(data, W83781D_REG_FAN_MIN(3));
/* Register common device attributes */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
+ if ((err = sysfs_create_group(&dev->kobj, &w83627hf_group)))
goto ERROR3;
/* Register chip-specific device attributes */
- if (kind == w83627hf || kind == w83697hf)
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in5_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in5_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in5_max))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in6_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in6_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in6_max)))
+ if (data->type == w83627hf || data->type == w83697hf)
+ if ((err = device_create_file(dev, &dev_attr_in5_input))
+ || (err = device_create_file(dev, &dev_attr_in5_min))
+ || (err = device_create_file(dev, &dev_attr_in5_max))
+ || (err = device_create_file(dev, &dev_attr_in6_input))
+ || (err = device_create_file(dev, &dev_attr_in6_min))
+ || (err = device_create_file(dev, &dev_attr_in6_max)))
goto ERROR4;
- if (kind != w83697hf)
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in1_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in1_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in1_max))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan3_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan3_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_fan3_div))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_temp3_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_temp3_max))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_temp3_max_hyst))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_temp3_type)))
+ if (data->type != w83697hf)
+ if ((err = device_create_file(dev, &dev_attr_in1_input))
+ || (err = device_create_file(dev, &dev_attr_in1_min))
+ || (err = device_create_file(dev, &dev_attr_in1_max))
+ || (err = device_create_file(dev, &dev_attr_fan3_input))
+ || (err = device_create_file(dev, &dev_attr_fan3_min))
+ || (err = device_create_file(dev, &dev_attr_fan3_div))
+ || (err = device_create_file(dev, &dev_attr_temp3_input))
+ || (err = device_create_file(dev, &dev_attr_temp3_max))
+ || (err = device_create_file(dev, &dev_attr_temp3_max_hyst))
+ || (err = device_create_file(dev, &dev_attr_temp3_type)))
goto ERROR4;
- if (kind != w83697hf && data->vid != 0xff)
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_cpu0_vid))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_vrm)))
+ if (data->type != w83697hf && data->vid != 0xff) {
+ /* Convert VID to voltage based on VRM */
+ data->vrm = vid_which_vrm();
+
+ if ((err = device_create_file(dev, &dev_attr_cpu0_vid))
+ || (err = device_create_file(dev, &dev_attr_vrm)))
goto ERROR4;
+ }
- if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_pwm3)))
+ if (data->type == w83627thf || data->type == w83637hf
+ || data->type == w83687thf)
+ if ((err = device_create_file(dev, &dev_attr_pwm3)))
goto ERROR4;
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto ERROR4;
@@ -1202,47 +1176,37 @@ static int w83627hf_detect(struct i2c_adapter *adapter)
return 0;
ERROR4:
- sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
- sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
+ sysfs_remove_group(&dev->kobj, &w83627hf_group);
+ sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
ERROR3:
- i2c_detach_client(new_client);
- ERROR2:
kfree(data);
ERROR1:
- release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE);
+ release_region(res->start, WINB_REGION_SIZE);
ERROR0:
return err;
}
-static int w83627hf_detach_client(struct i2c_client *client)
+static int __devexit w83627hf_remove(struct platform_device *pdev)
{
- struct w83627hf_data *data = i2c_get_clientdata(client);
- int err;
+ struct w83627hf_data *data = platform_get_drvdata(pdev);
+ struct resource *res;
+ platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
- sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE);
+ sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
kfree(data);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, WINB_REGION_SIZE);
+
return 0;
}
-/*
- ISA access must always be locked explicitly!
- We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
- would slow down the W83781D access and should not be necessary.
- There are some ugly typecasts here, but the good news is - they should
- nowhere else be necessary! */
-static int w83627hf_read_value(struct i2c_client *client, u16 reg)
+static int w83627hf_read_value(struct w83627hf_data *data, u16 reg)
{
- struct w83627hf_data *data = i2c_get_clientdata(client);
int res, word_sized;
mutex_lock(&data->lock);
@@ -1253,29 +1217,29 @@ static int w83627hf_read_value(struct i2c_client *client, u16 reg)
|| ((reg & 0x00ff) == 0x55));
if (reg & 0xff00) {
outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
+ data->addr + W83781D_ADDR_REG_OFFSET);
outb_p(reg >> 8,
- client->addr + W83781D_DATA_REG_OFFSET);
+ data->addr + W83781D_DATA_REG_OFFSET);
}
- outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
- res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);
+ outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
+ res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);
if (word_sized) {
outb_p((reg & 0xff) + 1,
- client->addr + W83781D_ADDR_REG_OFFSET);
+ data->addr + W83781D_ADDR_REG_OFFSET);
res =
- (res << 8) + inb_p(client->addr +
+ (res << 8) + inb_p(data->addr +
W83781D_DATA_REG_OFFSET);
}
if (reg & 0xff00) {
outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+ data->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
}
mutex_unlock(&data->lock);
return res;
}
-static int w83627thf_read_gpio5(struct i2c_client *client)
+static int __devinit w83627thf_read_gpio5(struct platform_device *pdev)
{
int res = 0xff, sel;
@@ -1284,7 +1248,7 @@ static int w83627thf_read_gpio5(struct i2c_client *client)
/* Make sure these GPIO pins are enabled */
if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {
- dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n");
+ dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");
goto exit;
}
@@ -1292,12 +1256,12 @@ static int w83627thf_read_gpio5(struct i2c_client *client)
There must be at least five (VRM 9), and possibly 6 (VRM 10) */
sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;
if ((sel & 0x1f) != 0x1f) {
- dev_dbg(&client->dev, "GPIO5 not configured for VID "
+ dev_dbg(&pdev->dev, "GPIO5 not configured for VID "
"function\n");
goto exit;
}
- dev_info(&client->dev, "Reading VID from GPIO5\n");
+ dev_info(&pdev->dev, "Reading VID from GPIO5\n");
res = superio_inb(W83627THF_GPIO5_DR) & sel;
exit:
@@ -1305,7 +1269,7 @@ exit:
return res;
}
-static int w83687thf_read_vid(struct i2c_client *client)
+static int __devinit w83687thf_read_vid(struct platform_device *pdev)
{
int res = 0xff;
@@ -1314,13 +1278,13 @@ static int w83687thf_read_vid(struct i2c_client *client)
/* Make sure these GPIO pins are enabled */
if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {
- dev_dbg(&client->dev, "VID disabled, no VID function\n");
+ dev_dbg(&pdev->dev, "VID disabled, no VID function\n");
goto exit;
}
/* Make sure the pins are configured for input */
if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {
- dev_dbg(&client->dev, "VID configured as output, "
+ dev_dbg(&pdev->dev, "VID configured as output, "
"no VID function\n");
goto exit;
}
@@ -1332,9 +1296,8 @@ exit:
return res;
}
-static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
+static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value)
{
- struct w83627hf_data *data = i2c_get_clientdata(client);
int word_sized;
mutex_lock(&data->lock);
@@ -1344,33 +1307,33 @@ static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value)
|| ((reg & 0x00ff) == 0x55));
if (reg & 0xff00) {
outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
+ data->addr + W83781D_ADDR_REG_OFFSET);
outb_p(reg >> 8,
- client->addr + W83781D_DATA_REG_OFFSET);
+ data->addr + W83781D_DATA_REG_OFFSET);
}
- outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);
if (word_sized) {
outb_p(value >> 8,
- client->addr + W83781D_DATA_REG_OFFSET);
+ data->addr + W83781D_DATA_REG_OFFSET);
outb_p((reg & 0xff) + 1,
- client->addr + W83781D_ADDR_REG_OFFSET);
+ data->addr + W83781D_ADDR_REG_OFFSET);
}
outb_p(value & 0xff,
- client->addr + W83781D_DATA_REG_OFFSET);
+ data->addr + W83781D_DATA_REG_OFFSET);
if (reg & 0xff00) {
outb_p(W83781D_REG_BANK,
- client->addr + W83781D_ADDR_REG_OFFSET);
- outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);
+ data->addr + W83781D_ADDR_REG_OFFSET);
+ outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);
}
mutex_unlock(&data->lock);
return 0;
}
-static void w83627hf_init_client(struct i2c_client *client)
+static void __devinit w83627hf_init_device(struct platform_device *pdev)
{
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = platform_get_drvdata(pdev);
int i;
- int type = data->type;
+ enum chips type = data->type;
u8 tmp;
if (reset) {
@@ -1379,57 +1342,53 @@ static void w83627hf_init_client(struct i2c_client *client)
speed...) so it is now optional. It might even go away if
nobody reports it as being useful, as I see very little
reason why this would be needed at all. */
- dev_info(&client->dev, "If reset=1 solved a problem you were "
+ dev_info(&pdev->dev, "If reset=1 solved a problem you were "
"having, please report!\n");
/* save this register */
- i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);
+ i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
/* Reset all except Watchdog values and last conversion values
This sets fan-divs to 2, among others */
- w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80);
+ w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
/* Restore the register and disable power-on abnormal beep.
This saves FAN 1/2/3 input/output values set by BIOS. */
- w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+ w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
/* Disable master beep-enable (reset turns it on).
Individual beeps should be reset to off but for some reason
disabling this bit helps some people not get beeped */
- w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0);
+ w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
}
/* Minimize conflicts with other winbond i2c-only clients... */
/* disable i2c subclients... how to disable main i2c client?? */
/* force i2c address to relatively uncommon address */
- w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);
- w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);
+ w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
+ w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
/* Read VID only once */
- if (w83627hf == data->type || w83637hf == data->type) {
- int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
- int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);
+ if (type == w83627hf || type == w83637hf) {
+ int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
+ int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);
data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);
- } else if (w83627thf == data->type) {
- data->vid = w83627thf_read_gpio5(client);
- } else if (w83687thf == data->type) {
- data->vid = w83687thf_read_vid(client);
+ } else if (type == w83627thf) {
+ data->vid = w83627thf_read_gpio5(pdev);
+ } else if (type == w83687thf) {
+ data->vid = w83687thf_read_vid(pdev);
}
/* Read VRM & OVT Config only once */
- if (w83627thf == data->type || w83637hf == data->type
- || w83687thf == data->type) {
+ if (type == w83627thf || type == w83637hf || type == w83687thf) {
data->vrm_ovt =
- w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);
+ w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);
}
- /* Convert VID to voltage based on VRM */
- data->vrm = vid_which_vrm();
-
- tmp = w83627hf_read_value(client, W83781D_REG_SCFG1);
+ tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {
data->sens[i - 1] = W83781D_DEFAULT_BETA;
} else {
if (w83627hf_read_value
- (client,
+ (data,
W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
data->sens[i - 1] = 1;
else
@@ -1441,38 +1400,37 @@ static void w83627hf_init_client(struct i2c_client *client)
if(init) {
/* Enable temp2 */
- tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG);
+ tmp = w83627hf_read_value(data, W83781D_REG_TEMP2_CONFIG);
if (tmp & 0x01) {
- dev_warn(&client->dev, "Enabling temp2, readings "
+ dev_warn(&pdev->dev, "Enabling temp2, readings "
"might not make sense\n");
- w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG,
+ w83627hf_write_value(data, W83781D_REG_TEMP2_CONFIG,
tmp & 0xfe);
}
/* Enable temp3 */
if (type != w83697hf) {
- tmp = w83627hf_read_value(client,
+ tmp = w83627hf_read_value(data,
W83781D_REG_TEMP3_CONFIG);
if (tmp & 0x01) {
- dev_warn(&client->dev, "Enabling temp3, "
+ dev_warn(&pdev->dev, "Enabling temp3, "
"readings might not make sense\n");
- w83627hf_write_value(client,
+ w83627hf_write_value(data,
W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
}
}
}
/* Start monitoring */
- w83627hf_write_value(client, W83781D_REG_CONFIG,
- (w83627hf_read_value(client,
+ w83627hf_write_value(data, W83781D_REG_CONFIG,
+ (w83627hf_read_value(data,
W83781D_REG_CONFIG) & 0xf7)
| 0x01);
}
static struct w83627hf_data *w83627hf_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627hf_data *data = i2c_get_clientdata(client);
+ struct w83627hf_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -1486,23 +1444,23 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
&& (i == 5 || i == 6)))
continue;
data->in[i] =
- w83627hf_read_value(client, W83781D_REG_IN(i));
+ w83627hf_read_value(data, W83781D_REG_IN(i));
data->in_min[i] =
- w83627hf_read_value(client,
+ w83627hf_read_value(data,
W83781D_REG_IN_MIN(i));
data->in_max[i] =
- w83627hf_read_value(client,
+ w83627hf_read_value(data,
W83781D_REG_IN_MAX(i));
}
for (i = 1; i <= 3; i++) {
data->fan[i - 1] =
- w83627hf_read_value(client, W83781D_REG_FAN(i));
+ w83627hf_read_value(data, W83781D_REG_FAN(i));
data->fan_min[i - 1] =
- w83627hf_read_value(client,
+ w83627hf_read_value(data,
W83781D_REG_FAN_MIN(i));
}
for (i = 1; i <= 3; i++) {
- u8 tmp = w83627hf_read_value(client,
+ u8 tmp = w83627hf_read_value(data,
W836X7HF_REG_PWM(data->type, i));
/* bits 0-3 are reserved in 627THF */
if (data->type == w83627thf)
@@ -1513,47 +1471,47 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
break;
}
- data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1));
+ data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
data->temp_max =
- w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));
+ w83627hf_read_value(data, W83781D_REG_TEMP_OVER(1));
data->temp_max_hyst =
- w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1));
+ w83627hf_read_value(data, W83781D_REG_TEMP_HYST(1));
data->temp_add[0] =
- w83627hf_read_value(client, W83781D_REG_TEMP(2));
+ w83627hf_read_value(data, W83781D_REG_TEMP(2));
data->temp_max_add[0] =
- w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2));
+ w83627hf_read_value(data, W83781D_REG_TEMP_OVER(2));
data->temp_max_hyst_add[0] =
- w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2));
+ w83627hf_read_value(data, W83781D_REG_TEMP_HYST(2));
if (data->type != w83697hf) {
data->temp_add[1] =
- w83627hf_read_value(client, W83781D_REG_TEMP(3));
+ w83627hf_read_value(data, W83781D_REG_TEMP(3));
data->temp_max_add[1] =
- w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3));
+ w83627hf_read_value(data, W83781D_REG_TEMP_OVER(3));
data->temp_max_hyst_add[1] =
- w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3));
+ w83627hf_read_value(data, W83781D_REG_TEMP_HYST(3));
}
- i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);
+ i = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = (i >> 6) & 0x03;
if (data->type != w83697hf) {
- data->fan_div[2] = (w83627hf_read_value(client,
+ data->fan_div[2] = (w83627hf_read_value(data,
W83781D_REG_PIN) >> 6) & 0x03;
}
- i = w83627hf_read_value(client, W83781D_REG_VBAT);
+ i = w83627hf_read_value(data, W83781D_REG_VBAT);
data->fan_div[0] |= (i >> 3) & 0x04;
data->fan_div[1] |= (i >> 4) & 0x04;
if (data->type != w83697hf)
data->fan_div[2] |= (i >> 5) & 0x04;
data->alarms =
- w83627hf_read_value(client, W83781D_REG_ALARM1) |
- (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |
- (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);
- i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);
+ w83627hf_read_value(data, W83781D_REG_ALARM1) |
+ (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |
+ (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);
+ i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);
data->beep_enable = i >> 7;
data->beep_mask = ((i & 0x7f) << 8) |
- w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |
- w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;
+ w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |
+ w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;
data->last_updated = jiffies;
data->valid = 1;
}
@@ -1563,19 +1521,87 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
return data;
}
+static int __init w83627hf_device_add(unsigned short address,
+ const struct w83627hf_sio_data *sio_data)
+{
+ struct resource res = {
+ .start = address + WINB_REGION_OFFSET,
+ .end = address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
+ GFP_KERNEL);
+ if (!pdev->dev.platform_data) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+ memcpy(pdev->dev.platform_data, sio_data,
+ sizeof(struct w83627hf_sio_data));
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __init sensors_w83627hf_init(void)
{
- if (w83627hf_find(0x2e, &address)
- && w83627hf_find(0x4e, &address)) {
+ int err;
+ unsigned short address;
+ struct w83627hf_sio_data sio_data;
+
+ if (w83627hf_find(0x2e, &address, &sio_data)
+ && w83627hf_find(0x4e, &address, &sio_data))
return -ENODEV;
- }
- return i2c_isa_add_driver(&w83627hf_driver);
+ err = platform_driver_register(&w83627hf_driver);
+ if (err)
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ err = w83627hf_device_add(address, &sio_data);
+ if (err)
+ goto exit_driver;
+
+ return 0;
+
+exit_driver:
+ platform_driver_unregister(&w83627hf_driver);
+exit:
+ return err;
}
static void __exit sensors_w83627hf_exit(void)
{
- i2c_isa_del_driver(&w83627hf_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&w83627hf_driver);
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index a47da3ec547..f85b48fea1c 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -2,8 +2,9 @@
w83781d.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
- and Mark Studebaker <mdsxyz123@yahoo.com>
+ Philip Edelbrock <phil@netroedge.com>,
+ and Mark Studebaker <mdsxyz123@yahoo.com>
+ Copyright (c) 2007 Jean Delvare <khali@linux-fr.org>
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
@@ -38,15 +39,20 @@
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include "lm75.h"
+/* ISA device, if found */
+static struct platform_device *pdev;
+
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
@@ -75,8 +81,8 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
#define W83781D_ADDR_REG_OFFSET 5
#define W83781D_DATA_REG_OFFSET 6
-/* The W83781D registers */
-/* The W83782D registers for nr=7,8 are in bank 5 */
+/* The device registers */
+/* in nr from 0 to 8 */
#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \
(0x554 + (((nr) - 7) * 2)))
#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \
@@ -84,12 +90,14 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \
(0x550 + (nr) - 7))
-#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))
-#define W83781D_REG_FAN(nr) (0x27 + (nr))
+/* fan nr from 0 to 2 */
+#define W83781D_REG_FAN_MIN(nr) (0x3b + (nr))
+#define W83781D_REG_FAN(nr) (0x28 + (nr))
#define W83781D_REG_BANK 0x4E
#define W83781D_REG_TEMP2_CONFIG 0x152
#define W83781D_REG_TEMP3_CONFIG 0x252
+/* temp nr from 1 to 3 */
#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \
((nr == 2) ? (0x0150) : \
(0x27)))
@@ -127,19 +135,9 @@ MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
#define W83781D_REG_VBAT 0x5D
/* PWM 782D (1-4) and 783S (1-2) only */
-#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */
- /* on which is which; */
-#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */
- /* However 782d is probably wrong. */
-#define W83781D_REG_PWM3 0x5E
-#define W83781D_REG_PWM4 0x5F
+static const u8 W83781D_REG_PWM[] = { 0x5B, 0x5A, 0x5E, 0x5F };
#define W83781D_REG_PWMCLK12 0x5C
#define W83781D_REG_PWMCLK34 0x45C
-static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2,
- W83781D_REG_PWM3, W83781D_REG_PWM4
-};
-
-#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1])
#define W83781D_REG_I2C_ADDR 0x48
#define W83781D_REG_I2C_SUBADDR 0x4A
@@ -159,12 +157,9 @@ static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };
#define W83781D_REG_RT_IDX 0x50
#define W83781D_REG_RT_VAL 0x51
-/* Conversions. Rounding and limit checking is only done on the TO_REG
- variants. Note that you should be a bit careful with which arguments
- these macros are called: arguments may be evaluated more than once.
- Fixing this is just not worth it. */
-#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
-#define IN_FROM_REG(val) (((val) * 16) / 10)
+/* Conversions */
+#define IN_TO_REG(val) SENSORS_LIMIT(((val) + 8) / 16, 0, 255)
+#define IN_FROM_REG(val) ((val) * 16)
static inline u8
FAN_TO_REG(long rpm, int div)
@@ -175,24 +170,24 @@ FAN_TO_REG(long rpm, int div)
return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254);
}
-#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \
- ((val) == 255 ? 0 : \
- 1350000 / ((val) * (div))))
+static inline long
+FAN_FROM_REG(u8 val, int div)
+{
+ if (val == 0)
+ return -1;
+ if (val == 255)
+ return 0;
+ return 1350000 / (val * div);
+}
-#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (val)+0x100*1000 \
- : (val)) / 1000, 0, 0xff))
-#define TEMP_FROM_REG(val) (((val) & 0x80 ? (val)-0x100 : (val)) * 1000)
+#define TEMP_TO_REG(val) SENSORS_LIMIT((val) / 1000, -127, 128)
+#define TEMP_FROM_REG(val) ((val) * 1000)
-#define PWM_FROM_REG(val) (val)
-#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
#define BEEP_MASK_FROM_REG(val,type) ((type) == as99127f ? \
(val) ^ 0x7fff : (val))
#define BEEP_MASK_TO_REG(val,type) ((type) == as99127f ? \
(~(val)) & 0x7fff : (val) & 0xffffff)
-#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0)
-#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0)
-
#define DIV_FROM_REG(val) (1 << (val))
static inline u8
@@ -207,7 +202,7 @@ DIV_TO_REG(long val, enum chips type)
break;
val >>= 1;
}
- return ((u8) i);
+ return i;
}
/* There are some complications in a module like this. First off, W83781D chips
@@ -221,8 +216,8 @@ DIV_TO_REG(long val, enum chips type)
a bit - except if there could be more than one SMBus. Groan. No solution
for this yet. */
-/* For each registered chip, we need to keep some data in memory.
- The structure is dynamically allocated. */
+/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
+ the driver field to differentiate between I2C and ISA chips. */
struct w83781d_data {
struct i2c_client client;
struct class_device *class_dev;
@@ -241,9 +236,9 @@ struct w83781d_data {
u8 in_min[9]; /* Register value - 8 & 9 for 782D only */
u8 fan[3]; /* Register value */
u8 fan_min[3]; /* Register value */
- u8 temp;
- u8 temp_max; /* Register value */
- u8 temp_max_hyst; /* Register value */
+ s8 temp; /* Register value */
+ s8 temp_max; /* Register value */
+ s8 temp_max_hyst; /* Register value */
u16 temp_add[2]; /* Register value */
u16 temp_max_add[2]; /* Register value */
u16 temp_max_hyst_add[2]; /* Register value */
@@ -253,7 +248,7 @@ struct w83781d_data {
u32 beep_mask; /* Register encoding, combined */
u8 beep_enable; /* Boolean */
u8 pwm[4]; /* Register value */
- u8 pwmenable[4]; /* Boolean */
+ u8 pwm2_enable; /* Boolean */
u16 sens[3]; /* 782D/783S only.
1 = pentium diode; 2 = 3904 diode;
3000-5000 = thermistor beta.
@@ -263,14 +258,16 @@ struct w83781d_data {
};
static int w83781d_attach_adapter(struct i2c_adapter *adapter);
-static int w83781d_isa_attach_adapter(struct i2c_adapter *adapter);
static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind);
static int w83781d_detach_client(struct i2c_client *client);
-static int w83781d_read_value(struct i2c_client *client, u16 reg);
-static int w83781d_write_value(struct i2c_client *client, u16 reg, u16 value);
+static int __devinit w83781d_isa_probe(struct platform_device *pdev);
+static int __devexit w83781d_isa_remove(struct platform_device *pdev);
+
+static int w83781d_read_value(struct w83781d_data *data, u16 reg);
+static int w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value);
static struct w83781d_data *w83781d_update_device(struct device *dev);
-static void w83781d_init_client(struct i2c_client *client);
+static void w83781d_init_device(struct device *dev);
static struct i2c_driver w83781d_driver = {
.driver = {
@@ -281,39 +278,44 @@ static struct i2c_driver w83781d_driver = {
.detach_client = w83781d_detach_client,
};
-static struct i2c_driver w83781d_isa_driver = {
+static struct platform_driver w83781d_isa_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "w83781d-isa",
+ .name = "w83781d",
},
- .attach_adapter = w83781d_isa_attach_adapter,
- .detach_client = w83781d_detach_client,
+ .probe = w83781d_isa_probe,
+ .remove = w83781d_isa_remove,
};
/* following are the sysfs callback functions */
#define show_in_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
+ char *buf) \
{ \
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
struct w83781d_data *data = w83781d_update_device(dev); \
- return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr] * 10)); \
+ return sprintf(buf, "%ld\n", \
+ (long)IN_FROM_REG(data->reg[attr->index])); \
}
show_in_reg(in);
show_in_reg(in_min);
show_in_reg(in_max);
#define store_in_reg(REG, reg) \
-static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+static ssize_t store_in_##reg (struct device *dev, struct device_attribute \
+ *da, const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83781d_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+ struct w83781d_data *data = dev_get_drvdata(dev); \
+ int nr = attr->index; \
u32 val; \
\
- val = simple_strtoul(buf, NULL, 10) / 10; \
+ val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->in_##reg[nr] = IN_TO_REG(val); \
- w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
+ w83781d_write_value(data, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \
\
mutex_unlock(&data->update_lock); \
return count; \
@@ -321,29 +323,13 @@ static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count
store_in_reg(MIN, min);
store_in_reg(MAX, max);
-#define sysfs_in_offset(offset) \
-static ssize_t \
-show_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);
-
-#define sysfs_in_reg_offset(reg, offset) \
-static ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_##reg (dev, buf, offset); \
-} \
-static ssize_t store_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_in_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset);
-
#define sysfs_in_offsets(offset) \
-sysfs_in_offset(offset); \
-sysfs_in_reg_offset(min, offset); \
-sysfs_in_reg_offset(max, offset);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, store_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, store_in_max, offset)
sysfs_in_offsets(0);
sysfs_in_offsets(1);
@@ -356,63 +342,56 @@ sysfs_in_offsets(7);
sysfs_in_offsets(8);
#define show_fan_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
+ char *buf) \
{ \
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
struct w83781d_data *data = w83781d_update_device(dev); \
return sprintf(buf,"%ld\n", \
- FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \
+ FAN_FROM_REG(data->reg[attr->index], \
+ DIV_FROM_REG(data->fan_div[attr->index]))); \
}
show_fan_reg(fan);
show_fan_reg(fan_min);
static ssize_t
-store_fan_min(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
u32 val;
val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->fan_min[nr - 1] =
- FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1]));
- w83781d_write_value(client, W83781D_REG_FAN_MIN(nr),
- data->fan_min[nr - 1]);
+ data->fan_min[nr] =
+ FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
+ w83781d_write_value(data, W83781D_REG_FAN_MIN(nr),
+ data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_fan_offset(offset) \
-static ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL);
-
-#define sysfs_fan_min_offset(offset) \
-static ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset); \
-} \
-static ssize_t store_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_fan_min(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset);
-
-sysfs_fan_offset(1);
-sysfs_fan_min_offset(1);
-sysfs_fan_offset(2);
-sysfs_fan_min_offset(2);
-sysfs_fan_offset(3);
-sysfs_fan_min_offset(3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+ show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+ show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+ show_fan_min, store_fan_min, 2);
#define show_temp_reg(reg) \
-static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *da, \
+ char *buf) \
{ \
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
struct w83781d_data *data = w83781d_update_device(dev); \
+ int nr = attr->index; \
if (nr >= 2) { /* TEMP2 and TEMP3 */ \
return sprintf(buf,"%d\n", \
LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \
@@ -425,10 +404,12 @@ show_temp_reg(temp_max);
show_temp_reg(temp_max_hyst);
#define store_temp_reg(REG, reg) \
-static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \
+static ssize_t store_temp_##reg (struct device *dev, \
+ struct device_attribute *da, const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83781d_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da); \
+ struct w83781d_data *data = dev_get_drvdata(dev); \
+ int nr = attr->index; \
s32 val; \
\
val = simple_strtol(buf, NULL, 10); \
@@ -437,11 +418,11 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou
\
if (nr >= 2) { /* TEMP2 and TEMP3 */ \
data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \
- w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+ w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
data->temp_##reg##_add[nr-2]); \
} else { /* TEMP1 */ \
data->temp_##reg = TEMP_TO_REG(val); \
- w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \
+ w83781d_write_value(data, W83781D_REG_TEMP_##REG(nr), \
data->temp_##reg); \
} \
\
@@ -451,29 +432,13 @@ static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t cou
store_temp_reg(OVER, max);
store_temp_reg(HYST, max_hyst);
-#define sysfs_temp_offset(offset) \
-static ssize_t \
-show_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL);
-
-#define sysfs_temp_reg_offset(reg, offset) \
-static ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_##reg (dev, buf, offset); \
-} \
-static ssize_t store_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_temp_##reg (dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset);
-
#define sysfs_temp_offsets(offset) \
-sysfs_temp_offset(offset); \
-sysfs_temp_reg_offset(max, offset); \
-sysfs_temp_reg_offset(max_hyst, offset);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_max, store_temp_max, offset); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp_max_hyst, store_temp_max_hyst, offset);
sysfs_temp_offsets(1);
sysfs_temp_offsets(2);
@@ -498,8 +463,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t
store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct w83781d_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -528,68 +492,67 @@ static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr
static ssize_t show_beep_enable (struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
- return sprintf(buf, "%ld\n",
- (long)BEEP_ENABLE_FROM_REG(data->beep_enable));
+ return sprintf(buf, "%ld\n", (long)data->beep_enable);
}
-#define BEEP_ENABLE 0 /* Store beep_enable */
-#define BEEP_MASK 1 /* Store beep_mask */
-
static ssize_t
-store_beep_reg(struct device *dev, const char *buf, size_t count,
- int update_mask)
+store_beep_mask(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
- u32 val, val2;
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ u32 val;
val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
+ data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS1,
+ data->beep_mask & 0xff);
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS2,
+ ((data->beep_mask >> 8) & 0x7f)
+ | data->beep_enable << 7);
+ if (data->type != w83781d && data->type != as99127f) {
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS3,
+ ((data->beep_mask) >> 16) & 0xff);
+ }
+ mutex_unlock(&data->update_lock);
- if (update_mask == BEEP_MASK) { /* We are storing beep_mask */
- data->beep_mask = BEEP_MASK_TO_REG(val, data->type);
- w83781d_write_value(client, W83781D_REG_BEEP_INTS1,
- data->beep_mask & 0xff);
-
- if ((data->type != w83781d) && (data->type != as99127f)) {
- w83781d_write_value(client, W83781D_REG_BEEP_INTS3,
- ((data->beep_mask) >> 16) & 0xff);
- }
+ return count;
+}
- val2 = (data->beep_mask >> 8) & 0x7f;
- } else { /* We are storing beep_enable */
- val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f;
- data->beep_enable = BEEP_ENABLE_TO_REG(val);
- }
+static ssize_t
+store_beep_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ u32 val;
- w83781d_write_value(client, W83781D_REG_BEEP_INTS2,
- val2 | data->beep_enable << 7);
+ val = simple_strtoul(buf, NULL, 10);
+ if (val != 0 && val != 1)
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ data->beep_enable = val;
+ val = w83781d_read_value(data, W83781D_REG_BEEP_INTS2) & 0x7f;
+ val |= data->beep_enable << 7;
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS2, val);
mutex_unlock(&data->update_lock);
+
return count;
}
-#define sysfs_beep(REG, reg) \
-static ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_beep_##reg(dev, attr, buf); \
-} \
-static ssize_t store_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_beep_reg(dev, buf, count, BEEP_##REG); \
-} \
-static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg);
-
-sysfs_beep(ENABLE, enable);
-sysfs_beep(MASK, mask);
+static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR,
+ show_beep_mask, store_beep_mask);
+static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR,
+ show_beep_enable, store_beep_enable);
static ssize_t
-show_fan_div_reg(struct device *dev, char *buf, int nr)
+show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct w83781d_data *data = w83781d_update_device(dev);
return sprintf(buf, "%ld\n",
- (long) DIV_FROM_REG(data->fan_div[nr - 1]));
+ (long) DIV_FROM_REG(data->fan_div[attr->index]));
}
/* Note: we save and restore the fan minimum here, because its value is
@@ -597,11 +560,13 @@ show_fan_div_reg(struct device *dev, char *buf, int nr)
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
-store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_fan_div(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct w83781d_data *data = dev_get_drvdata(dev);
unsigned long min;
+ int nr = attr->index;
u8 reg;
unsigned long val = simple_strtoul(buf, NULL, 10);
@@ -613,77 +578,72 @@ store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
data->fan_div[nr] = DIV_TO_REG(val, data->type);
- reg = (w83781d_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
+ reg = (w83781d_read_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV)
& (nr==0 ? 0xcf : 0x3f))
| ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6));
- w83781d_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
+ w83781d_write_value(data, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg);
/* w83781d and as99127f don't have extended divisor bits */
if (data->type != w83781d && data->type != as99127f) {
- reg = (w83781d_read_value(client, W83781D_REG_VBAT)
+ reg = (w83781d_read_value(data, W83781D_REG_VBAT)
& ~(1 << (5 + nr)))
| ((data->fan_div[nr] & 0x04) << (3 + nr));
- w83781d_write_value(client, W83781D_REG_VBAT, reg);
+ w83781d_write_value(data, W83781D_REG_VBAT, reg);
}
/* Restore fan_min */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- w83781d_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+ w83781d_write_value(data, W83781D_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-#define sysfs_fan_div(offset) \
-static ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_fan_div_reg(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset);
-
-sysfs_fan_div(1);
-sysfs_fan_div(2);
-sysfs_fan_div(3);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
+ show_fan_div, store_fan_div, 0);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
+ show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR,
+ show_fan_div, store_fan_div, 2);
static ssize_t
-show_pwm_reg(struct device *dev, char *buf, int nr)
+show_pwm(struct device *dev, struct device_attribute *da, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct w83781d_data *data = w83781d_update_device(dev);
- return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1]));
+ return sprintf(buf, "%d\n", (int)data->pwm[attr->index]);
}
static ssize_t
-show_pwmenable_reg(struct device *dev, char *buf, int nr)
+show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
- return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]);
+ return sprintf(buf, "%d\n", (int)data->pwm2_enable);
}
static ssize_t
-store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm(struct device *dev, struct device_attribute *da, const char *buf,
+ size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
u32 val;
val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
- data->pwm[nr - 1] = PWM_TO_REG(val);
- w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]);
+ data->pwm[nr] = SENSORS_LIMIT(val, 0, 255);
+ w83781d_write_value(data, W83781D_REG_PWM[nr], data->pwm[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t
-store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_pwm2_enable(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct w83781d_data *data = dev_get_drvdata(dev);
u32 val, reg;
val = simple_strtoul(buf, NULL, 10);
@@ -693,15 +653,15 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
switch (val) {
case 0:
case 1:
- reg = w83781d_read_value(client, W83781D_REG_PWMCLK12);
- w83781d_write_value(client, W83781D_REG_PWMCLK12,
+ reg = w83781d_read_value(data, W83781D_REG_PWMCLK12);
+ w83781d_write_value(data, W83781D_REG_PWMCLK12,
(reg & 0xf7) | (val << 3));
- reg = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
- w83781d_write_value(client, W83781D_REG_BEEP_CONFIG,
+ reg = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+ w83781d_write_value(data, W83781D_REG_BEEP_CONFIG,
(reg & 0xef) | (!val << 4));
- data->pwmenable[nr - 1] = val;
+ data->pwm2_enable = val;
break;
default:
@@ -713,50 +673,29 @@ store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define sysfs_pwm(offset) \
-static ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwm_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_pwm_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \
- show_regs_pwm_##offset, store_regs_pwm_##offset);
-
-#define sysfs_pwmenable(offset) \
-static ssize_t show_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_pwmenable_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_pwmenable_##offset (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return store_pwmenable_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \
- show_regs_pwmenable_##offset, store_regs_pwmenable_##offset);
-
-sysfs_pwm(1);
-sysfs_pwm(2);
-sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */
-sysfs_pwm(3);
-sysfs_pwm(4);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3);
+/* only PWM2 can be enabled/disabled */
+static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
+ show_pwm2_enable, store_pwm2_enable);
static ssize_t
-show_sensor_reg(struct device *dev, char *buf, int nr)
+show_sensor(struct device *dev, struct device_attribute *da, char *buf)
{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct w83781d_data *data = w83781d_update_device(dev);
- return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]);
+ return sprintf(buf, "%d\n", (int)data->sens[attr->index]);
}
static ssize_t
-store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
+store_sensor(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ int nr = attr->index;
u32 val, tmp;
val = simple_strtoul(buf, NULL, 10);
@@ -765,28 +704,28 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
switch (val) {
case 1: /* PII/Celeron diode */
- tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
- w83781d_write_value(client, W83781D_REG_SCFG1,
- tmp | BIT_SCFG1[nr - 1]);
- tmp = w83781d_read_value(client, W83781D_REG_SCFG2);
- w83781d_write_value(client, W83781D_REG_SCFG2,
- tmp | BIT_SCFG2[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+ w83781d_write_value(data, W83781D_REG_SCFG1,
+ tmp | BIT_SCFG1[nr]);
+ tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
+ w83781d_write_value(data, W83781D_REG_SCFG2,
+ tmp | BIT_SCFG2[nr]);
+ data->sens[nr] = val;
break;
case 2: /* 3904 */
- tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
- w83781d_write_value(client, W83781D_REG_SCFG1,
- tmp | BIT_SCFG1[nr - 1]);
- tmp = w83781d_read_value(client, W83781D_REG_SCFG2);
- w83781d_write_value(client, W83781D_REG_SCFG2,
- tmp & ~BIT_SCFG2[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+ w83781d_write_value(data, W83781D_REG_SCFG1,
+ tmp | BIT_SCFG1[nr]);
+ tmp = w83781d_read_value(data, W83781D_REG_SCFG2);
+ w83781d_write_value(data, W83781D_REG_SCFG2,
+ tmp & ~BIT_SCFG2[nr]);
+ data->sens[nr] = val;
break;
case W83781D_DEFAULT_BETA: /* thermistor */
- tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
- w83781d_write_value(client, W83781D_REG_SCFG1,
- tmp & ~BIT_SCFG1[nr - 1]);
- data->sens[nr - 1] = val;
+ tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
+ w83781d_write_value(data, W83781D_REG_SCFG1,
+ tmp & ~BIT_SCFG1[nr]);
+ data->sens[nr] = val;
break;
default:
dev_err(dev, "Invalid sensor type %ld; must be 1, 2, or %d\n",
@@ -798,20 +737,22 @@ store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr)
return count;
}
-#define sysfs_sensor(offset) \
-static ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_sensor_reg(dev, buf, offset); \
-} \
-static ssize_t store_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return store_sensor_reg(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset);
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
+ show_sensor, store_sensor, 0);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
+ show_sensor, store_sensor, 0);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
+ show_sensor, store_sensor, 0);
-sysfs_sensor(1);
-sysfs_sensor(2);
-sysfs_sensor(3);
+/* I2C devices get this name attribute automatically, but for ISA devices
+ we must create it by ourselves. */
+static ssize_t
+show_name(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->client.name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
/* This function is called when:
* w83781d_driver is inserted (when this module is loaded), for each
@@ -825,12 +766,6 @@ w83781d_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, w83781d_detect);
}
-static int
-w83781d_isa_attach_adapter(struct i2c_adapter *adapter)
-{
- return w83781d_detect(adapter, isa_address, -1);
-}
-
/* Assumes that adapter is of I2C, not ISA variety.
* OTHERWISE DON'T CALL THIS
*/
@@ -862,12 +797,12 @@ w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,
goto ERROR_SC_1;
}
}
- w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR,
+ w83781d_write_value(data, W83781D_REG_I2C_SUBADDR,
(force_subclients[2] & 0x07) |
((force_subclients[3] & 0x07) << 4));
data->lm75[0]->addr = force_subclients[2];
} else {
- val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR);
+ val1 = w83781d_read_value(data, W83781D_REG_I2C_SUBADDR);
data->lm75[0]->addr = 0x48 + (val1 & 0x07);
}
@@ -937,20 +872,20 @@ ERROR_SC_0:
return err;
}
-#define IN_UNIT_ATTRS(X) \
- &dev_attr_in##X##_input.attr, \
- &dev_attr_in##X##_min.attr, \
- &dev_attr_in##X##_max.attr
+#define IN_UNIT_ATTRS(X) \
+ &sensor_dev_attr_in##X##_input.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_min.dev_attr.attr, \
+ &sensor_dev_attr_in##X##_max.dev_attr.attr
-#define FAN_UNIT_ATTRS(X) \
- &dev_attr_fan##X##_input.attr, \
- &dev_attr_fan##X##_min.attr, \
- &dev_attr_fan##X##_div.attr
+#define FAN_UNIT_ATTRS(X) \
+ &sensor_dev_attr_fan##X##_input.dev_attr.attr, \
+ &sensor_dev_attr_fan##X##_min.dev_attr.attr, \
+ &sensor_dev_attr_fan##X##_div.dev_attr.attr
-#define TEMP_UNIT_ATTRS(X) \
- &dev_attr_temp##X##_input.attr, \
- &dev_attr_temp##X##_max.attr, \
- &dev_attr_temp##X##_max_hyst.attr
+#define TEMP_UNIT_ATTRS(X) \
+ &sensor_dev_attr_temp##X##_input.dev_attr.attr, \
+ &sensor_dev_attr_temp##X##_max.dev_attr.attr, \
+ &sensor_dev_attr_temp##X##_max_hyst.dev_attr.attr
static struct attribute* w83781d_attributes[] = {
IN_UNIT_ATTRS(0),
@@ -980,91 +915,115 @@ static struct attribute *w83781d_attributes_opt[] = {
IN_UNIT_ATTRS(7),
IN_UNIT_ATTRS(8),
TEMP_UNIT_ATTRS(3),
- &dev_attr_pwm1.attr,
- &dev_attr_pwm2.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm4.dev_attr.attr,
&dev_attr_pwm2_enable.attr,
- &dev_attr_pwm3.attr,
- &dev_attr_pwm4.attr,
- &dev_attr_temp1_type.attr,
- &dev_attr_temp2_type.attr,
- &dev_attr_temp3_type.attr,
+ &sensor_dev_attr_temp1_type.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
NULL
};
static const struct attribute_group w83781d_group_opt = {
.attrs = w83781d_attributes_opt,
};
+/* No clean up is done on error, it's up to the caller */
static int
-w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
+w83781d_create_files(struct device *dev, int kind, int is_isa)
{
- int i = 0, val1 = 0, val2;
- struct i2c_client *client;
- struct device *dev;
- struct w83781d_data *data;
int err;
- const char *client_name = "";
- int is_isa = i2c_is_isa_adapter(adapter);
- enum vendor { winbond, asus } vendid;
- if (!is_isa
- && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- err = -EINVAL;
- goto ERROR0;
+ if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
+ return err;
+
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_in1_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in1_max.dev_attr)))
+ return err;
+ }
+ if (kind != as99127f && kind != w83781d && kind != w83783s) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_in7_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in7_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in7_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_min.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_in8_max.dev_attr)))
+ return err;
+ }
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_temp3_input.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_max.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr)))
+ return err;
}
- /* Prevent users from forcing a kind for a bus it isn't supposed
- to possibly be on */
- if (is_isa && (kind == as99127f || kind == w83783s)) {
- dev_err(&adapter->dev,
- "Cannot force I2C-only chip for ISA address 0x%02x.\n",
- address);
- err = -EINVAL;
- goto ERROR0;
+ if (kind != w83781d && kind != as99127f) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm1.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm2.dev_attr))
+ || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
+ return err;
}
-
- if (is_isa)
- if (!request_region(address, W83781D_EXTENT,
- w83781d_isa_driver.driver.name)) {
- dev_dbg(&adapter->dev, "Request of region "
- "0x%x-0x%x for w83781d failed\n", address,
- address + W83781D_EXTENT - 1);
- err = -EBUSY;
- goto ERROR0;
+ if (kind == w83782d && !is_isa) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_pwm3.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_pwm4.dev_attr)))
+ return err;
+ }
+
+ if (kind != as99127f && kind != w83781d) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_temp1_type.dev_attr))
+ || (err = device_create_file(dev,
+ &sensor_dev_attr_temp2_type.dev_attr)))
+ return err;
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev,
+ &sensor_dev_attr_temp3_type.dev_attr)))
+ return err;
}
+ }
- /* Probe whether there is anything available on this address. Already
- done for SMBus clients */
- if (kind < 0) {
- if (is_isa) {
+ if (is_isa) {
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ return err;
+ }
-#define REALLY_SLOW_IO
- /* We need the timeouts for at least some LM78-like
- chips. But only if we read 'undefined' registers. */
- i = inb_p(address + 1);
- if (inb_p(address + 2) != i
- || inb_p(address + 3) != i
- || inb_p(address + 7) != i) {
- dev_dbg(&adapter->dev, "Detection of w83781d "
- "chip failed at step 1\n");
- err = -ENODEV;
- goto ERROR1;
- }
-#undef REALLY_SLOW_IO
+ return 0;
+}
- /* Let's just hope nothing breaks here */
- i = inb_p(address + 5) & 0x7f;
- outb_p(~i & 0x7f, address + 5);
- val2 = inb_p(address + 5) & 0x7f;
- if (val2 != (~i & 0x7f)) {
- outb_p(i, address + 5);
- dev_dbg(&adapter->dev, "Detection of w83781d "
- "chip failed at step 2 (0x%x != "
- "0x%x at 0x%x)\n", val2, ~i & 0x7f,
- address + 5);
- err = -ENODEV;
- goto ERROR1;
- }
- }
+static int
+w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ int val1 = 0, val2;
+ struct i2c_client *client;
+ struct device *dev;
+ struct w83781d_data *data;
+ int err;
+ const char *client_name = "";
+ enum vendor { winbond, asus } vendid;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ err = -EINVAL;
+ goto ERROR1;
}
/* OK. For now, we presume we have a valid client. We now create the
@@ -1081,8 +1040,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
client->addr = address;
mutex_init(&data->lock);
client->adapter = adapter;
- client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
- client->flags = 0;
+ client->driver = &w83781d_driver;
dev = &client->dev;
/* Now, we do the remaining detection. */
@@ -1092,14 +1050,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
force_*=... parameter, and the Winbond will be reset to the right
bank. */
if (kind < 0) {
- if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
+ if (w83781d_read_value(data, W83781D_REG_CONFIG) & 0x80) {
dev_dbg(&adapter->dev, "Detection of w83781d chip "
"failed at step 3\n");
err = -ENODEV;
goto ERROR2;
}
- val1 = w83781d_read_value(client, W83781D_REG_BANK);
- val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
+ val1 = w83781d_read_value(data, W83781D_REG_BANK);
+ val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
/* Check for Winbond or Asus ID if in bank 0 */
if ((!(val1 & 0x07)) &&
(((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
@@ -1111,10 +1069,10 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* If Winbond SMBus, check address at 0x48.
Asus doesn't support, except for as99127f rev.2 */
- if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
- ((val1 & 0x80) && (val2 == 0x5c)))) {
+ if ((!(val1 & 0x80) && (val2 == 0xa3)) ||
+ ((val1 & 0x80) && (val2 == 0x5c))) {
if (w83781d_read_value
- (client, W83781D_REG_I2C_ADDR) != address) {
+ (data, W83781D_REG_I2C_ADDR) != address) {
dev_dbg(&adapter->dev, "Detection of w83781d "
"chip failed at step 5\n");
err = -ENODEV;
@@ -1125,14 +1083,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
/* We have either had a force parameter, or we have already detected the
Winbond. Put it now into bank 0 and Vendor ID High Byte */
- w83781d_write_value(client, W83781D_REG_BANK,
- (w83781d_read_value(client, W83781D_REG_BANK)
+ w83781d_write_value(data, W83781D_REG_BANK,
+ (w83781d_read_value(data, W83781D_REG_BANK)
& 0x78) | 0x80);
/* Determine the chip type. */
if (kind <= 0) {
/* get vendor ID */
- val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
+ val2 = w83781d_read_value(data, W83781D_REG_CHIPMAN);
if (val2 == 0x5c)
vendid = winbond;
else if (val2 == 0x12)
@@ -1144,17 +1102,16 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
goto ERROR2;
}
- val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
+ val1 = w83781d_read_value(data, W83781D_REG_WCHIPID);
if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
kind = w83781d;
else if (val1 == 0x30 && vendid == winbond)
kind = w83782d;
- else if (val1 == 0x40 && vendid == winbond && !is_isa
- && address == 0x2d)
+ else if (val1 == 0x40 && vendid == winbond && address == 0x2d)
kind = w83783s;
else if (val1 == 0x21 && vendid == winbond)
kind = w83627hf;
- else if (val1 == 0x31 && !is_isa && address >= 0x28)
+ else if (val1 == 0x31 && address >= 0x28)
kind = as99127f;
else {
if (kind == 0)
@@ -1182,86 +1139,23 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
strlcpy(client->name, client_name, I2C_NAME_SIZE);
data->type = kind;
- data->valid = 0;
- mutex_init(&data->update_lock);
-
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(client)))
goto ERROR2;
/* attach secondary i2c lm75-like clients */
- if (!is_isa) {
- if ((err = w83781d_detect_subclients(adapter, address,
- kind, client)))
- goto ERROR3;
- } else {
- data->lm75[0] = NULL;
- data->lm75[1] = NULL;
- }
+ if ((err = w83781d_detect_subclients(adapter, address,
+ kind, client)))
+ goto ERROR3;
/* Initialize the chip */
- w83781d_init_client(client);
-
- /* A few vars need to be filled upon startup */
- for (i = 1; i <= 3; i++) {
- data->fan_min[i - 1] = w83781d_read_value(client,
- W83781D_REG_FAN_MIN(i));
- }
- if (kind != w83781d && kind != as99127f)
- for (i = 0; i < 4; i++)
- data->pwmenable[i] = 1;
+ w83781d_init_device(dev);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
+ err = w83781d_create_files(dev, kind, 0);
+ if (err)
goto ERROR4;
- if (kind != w83783s) {
- if ((err = device_create_file(dev, &dev_attr_in1_input))
- || (err = device_create_file(dev, &dev_attr_in1_min))
- || (err = device_create_file(dev, &dev_attr_in1_max)))
- goto ERROR4;
- }
- if (kind != as99127f && kind != w83781d && kind != w83783s) {
- if ((err = device_create_file(dev, &dev_attr_in7_input))
- || (err = device_create_file(dev, &dev_attr_in7_min))
- || (err = device_create_file(dev, &dev_attr_in7_max))
- || (err = device_create_file(dev, &dev_attr_in8_input))
- || (err = device_create_file(dev, &dev_attr_in8_min))
- || (err = device_create_file(dev, &dev_attr_in8_max)))
- goto ERROR4;
- }
- if (kind != w83783s) {
- if ((err = device_create_file(dev, &dev_attr_temp3_input))
- || (err = device_create_file(dev, &dev_attr_temp3_max))
- || (err = device_create_file(dev,
- &dev_attr_temp3_max_hyst)))
- goto ERROR4;
- }
-
- if (kind != w83781d && kind != as99127f) {
- if ((err = device_create_file(dev, &dev_attr_pwm1))
- || (err = device_create_file(dev, &dev_attr_pwm2))
- || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
- goto ERROR4;
- }
- if (kind == w83782d && !is_isa) {
- if ((err = device_create_file(dev, &dev_attr_pwm3))
- || (err = device_create_file(dev, &dev_attr_pwm4)))
- goto ERROR4;
- }
-
- if (kind != as99127f && kind != w83781d) {
- if ((err = device_create_file(dev, &dev_attr_temp1_type))
- || (err = device_create_file(dev,
- &dev_attr_temp2_type)))
- goto ERROR4;
- if (kind != w83783s) {
- if ((err = device_create_file(dev,
- &dev_attr_temp3_type)))
- goto ERROR4;
- }
- }
-
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
@@ -1287,9 +1181,6 @@ ERROR3:
ERROR2:
kfree(data);
ERROR1:
- if (is_isa)
- release_region(address, W83781D_EXTENT);
-ERROR0:
return err;
}
@@ -1305,8 +1196,6 @@ w83781d_detach_client(struct i2c_client *client)
sysfs_remove_group(&client->dev.kobj, &w83781d_group);
sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
}
- if (i2c_is_isa_client(client))
- release_region(client->addr, W83781D_EXTENT);
if ((err = i2c_detach_client(client)))
return err;
@@ -1322,6 +1211,88 @@ w83781d_detach_client(struct i2c_client *client)
return 0;
}
+static int __devinit
+w83781d_isa_probe(struct platform_device *pdev)
+{
+ int err, reg;
+ struct w83781d_data *data;
+ struct resource *res;
+ const char *name;
+
+ /* Reserve the ISA region */
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, W83781D_EXTENT, "w83781d")) {
+ err = -EBUSY;
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit_release_region;
+ }
+ mutex_init(&data->lock);
+ data->client.addr = res->start;
+ i2c_set_clientdata(&data->client, data);
+ platform_set_drvdata(pdev, data);
+
+ reg = w83781d_read_value(data, W83781D_REG_WCHIPID);
+ switch (reg) {
+ case 0x21:
+ data->type = w83627hf;
+ name = "w83627hf";
+ break;
+ case 0x30:
+ data->type = w83782d;
+ name = "w83782d";
+ break;
+ default:
+ data->type = w83781d;
+ name = "w83781d";
+ }
+ strlcpy(data->client.name, name, I2C_NAME_SIZE);
+
+ /* Initialize the W83781D chip */
+ w83781d_init_device(&pdev->dev);
+
+ /* Register sysfs hooks */
+ err = w83781d_create_files(&pdev->dev, data->type, 1);
+ if (err)
+ goto exit_remove_files;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+ exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ kfree(data);
+ exit_release_region:
+ release_region(res->start, W83781D_EXTENT);
+ exit:
+ return err;
+}
+
+static int __devexit
+w83781d_isa_remove(struct platform_device *pdev)
+{
+ struct w83781d_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group);
+ sysfs_remove_group(&pdev->dev.kobj, &w83781d_group_opt);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ release_region(data->client.addr, W83781D_EXTENT);
+ kfree(data);
+
+ return 0;
+}
+
/* The SMBus locks itself, usually, but nothing may access the Winbond between
bank switches. ISA access must always be locked explicitly!
We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,
@@ -1329,14 +1300,14 @@ w83781d_detach_client(struct i2c_client *client)
There are some ugly typecasts here, but the good news is - they should
nowhere else be necessary! */
static int
-w83781d_read_value(struct i2c_client *client, u16 reg)
+w83781d_read_value(struct w83781d_data *data, u16 reg)
{
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct i2c_client *client = &data->client;
int res, word_sized, bank;
struct i2c_client *cl;
mutex_lock(&data->lock);
- if (i2c_is_isa_client(client)) {
+ if (!client->driver) { /* ISA device */
word_sized = (((reg & 0xff00) == 0x100)
|| ((reg & 0xff00) == 0x200))
&& (((reg & 0x00ff) == 0x50)
@@ -1398,14 +1369,14 @@ w83781d_read_value(struct i2c_client *client, u16 reg)
}
static int
-w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
+w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value)
{
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct i2c_client *client = &data->client;
int word_sized, bank;
struct i2c_client *cl;
mutex_lock(&data->lock);
- if (i2c_is_isa_client(client)) {
+ if (!client->driver) { /* ISA device */
word_sized = (((reg & 0xff00) == 0x100)
|| ((reg & 0xff00) == 0x200))
&& (((reg & 0x00ff) == 0x53)
@@ -1462,13 +1433,18 @@ w83781d_write_value(struct i2c_client *client, u16 reg, u16 value)
}
static void
-w83781d_init_client(struct i2c_client *client)
+w83781d_init_device(struct device *dev)
{
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct w83781d_data *data = dev_get_drvdata(dev);
int i, p;
int type = data->type;
u8 tmp;
+ if (type == w83627hf)
+ dev_info(dev, "The W83627HF chip is better supported by the "
+ "w83627hf driver, support will be dropped from the "
+ "w83781d driver soon\n");
+
if (reset && type != as99127f) { /* this resets registers we don't have
documentation for on the as99127f */
/* Resetting the chip has been the default for a long time,
@@ -1477,42 +1453,42 @@ w83781d_init_client(struct i2c_client *client)
It might even go away if nobody reports it as being useful,
as I see very little reason why this would be needed at
all. */
- dev_info(&client->dev, "If reset=1 solved a problem you were "
+ dev_info(dev, "If reset=1 solved a problem you were "
"having, please report!\n");
/* save these registers */
- i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
- p = w83781d_read_value(client, W83781D_REG_PWMCLK12);
+ i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+ p = w83781d_read_value(data, W83781D_REG_PWMCLK12);
/* Reset all except Watchdog values and last conversion values
This sets fan-divs to 2, among others */
- w83781d_write_value(client, W83781D_REG_CONFIG, 0x80);
+ w83781d_write_value(data, W83781D_REG_CONFIG, 0x80);
/* Restore the registers and disable power-on abnormal beep.
This saves FAN 1/2/3 input/output values set by BIOS. */
- w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
- w83781d_write_value(client, W83781D_REG_PWMCLK12, p);
+ w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
+ w83781d_write_value(data, W83781D_REG_PWMCLK12, p);
/* Disable master beep-enable (reset turns it on).
Individual beep_mask should be reset to off but for some reason
disabling this bit helps some people not get beeped */
- w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);
+ w83781d_write_value(data, W83781D_REG_BEEP_INTS2, 0);
}
/* Disable power-on abnormal beep, as advised by the datasheet.
Already done if reset=1. */
if (init && !reset && type != as99127f) {
- i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);
- w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);
+ i = w83781d_read_value(data, W83781D_REG_BEEP_CONFIG);
+ w83781d_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
}
data->vrm = vid_which_vrm();
if ((type != w83781d) && (type != as99127f)) {
- tmp = w83781d_read_value(client, W83781D_REG_SCFG1);
+ tmp = w83781d_read_value(data, W83781D_REG_SCFG1);
for (i = 1; i <= 3; i++) {
if (!(tmp & BIT_SCFG1[i - 1])) {
data->sens[i - 1] = W83781D_DEFAULT_BETA;
} else {
if (w83781d_read_value
- (client,
+ (data,
W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])
data->sens[i - 1] = 1;
else
@@ -1525,38 +1501,46 @@ w83781d_init_client(struct i2c_client *client)
if (init && type != as99127f) {
/* Enable temp2 */
- tmp = w83781d_read_value(client, W83781D_REG_TEMP2_CONFIG);
+ tmp = w83781d_read_value(data, W83781D_REG_TEMP2_CONFIG);
if (tmp & 0x01) {
- dev_warn(&client->dev, "Enabling temp2, readings "
+ dev_warn(dev, "Enabling temp2, readings "
"might not make sense\n");
- w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG,
+ w83781d_write_value(data, W83781D_REG_TEMP2_CONFIG,
tmp & 0xfe);
}
/* Enable temp3 */
if (type != w83783s) {
- tmp = w83781d_read_value(client,
+ tmp = w83781d_read_value(data,
W83781D_REG_TEMP3_CONFIG);
if (tmp & 0x01) {
- dev_warn(&client->dev, "Enabling temp3, "
+ dev_warn(dev, "Enabling temp3, "
"readings might not make sense\n");
- w83781d_write_value(client,
+ w83781d_write_value(data,
W83781D_REG_TEMP3_CONFIG, tmp & 0xfe);
}
}
}
/* Start monitoring */
- w83781d_write_value(client, W83781D_REG_CONFIG,
- (w83781d_read_value(client,
+ w83781d_write_value(data, W83781D_REG_CONFIG,
+ (w83781d_read_value(data,
W83781D_REG_CONFIG) & 0xf7)
| 0x01);
+
+ /* A few vars need to be filled upon startup */
+ for (i = 0; i < 3; i++) {
+ data->fan_min[i] = w83781d_read_value(data,
+ W83781D_REG_FAN_MIN(i));
+ }
+
+ mutex_init(&data->update_lock);
}
static struct w83781d_data *w83781d_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83781d_data *data = i2c_get_clientdata(client);
+ struct w83781d_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = &data->client;
int i;
mutex_lock(&data->update_lock);
@@ -1569,98 +1553,97 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
if (data->type == w83783s && i == 1)
continue; /* 783S has no in1 */
data->in[i] =
- w83781d_read_value(client, W83781D_REG_IN(i));
+ w83781d_read_value(data, W83781D_REG_IN(i));
data->in_min[i] =
- w83781d_read_value(client, W83781D_REG_IN_MIN(i));
+ w83781d_read_value(data, W83781D_REG_IN_MIN(i));
data->in_max[i] =
- w83781d_read_value(client, W83781D_REG_IN_MAX(i));
+ w83781d_read_value(data, W83781D_REG_IN_MAX(i));
if ((data->type != w83782d)
&& (data->type != w83627hf) && (i == 6))
break;
}
- for (i = 1; i <= 3; i++) {
- data->fan[i - 1] =
- w83781d_read_value(client, W83781D_REG_FAN(i));
- data->fan_min[i - 1] =
- w83781d_read_value(client, W83781D_REG_FAN_MIN(i));
+ for (i = 0; i < 3; i++) {
+ data->fan[i] =
+ w83781d_read_value(data, W83781D_REG_FAN(i));
+ data->fan_min[i] =
+ w83781d_read_value(data, W83781D_REG_FAN_MIN(i));
}
if (data->type != w83781d && data->type != as99127f) {
- for (i = 1; i <= 4; i++) {
- data->pwm[i - 1] =
- w83781d_read_value(client,
- W83781D_REG_PWM(i));
- if ((data->type != w83782d
- || i2c_is_isa_client(client))
- && i == 2)
+ for (i = 0; i < 4; i++) {
+ data->pwm[i] =
+ w83781d_read_value(data,
+ W83781D_REG_PWM[i]);
+ if ((data->type != w83782d || !client->driver)
+ && i == 1)
break;
}
/* Only PWM2 can be disabled */
- data->pwmenable[1] = (w83781d_read_value(client,
+ data->pwm2_enable = (w83781d_read_value(data,
W83781D_REG_PWMCLK12) & 0x08) >> 3;
}
- data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1));
+ data->temp = w83781d_read_value(data, W83781D_REG_TEMP(1));
data->temp_max =
- w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));
+ w83781d_read_value(data, W83781D_REG_TEMP_OVER(1));
data->temp_max_hyst =
- w83781d_read_value(client, W83781D_REG_TEMP_HYST(1));
+ w83781d_read_value(data, W83781D_REG_TEMP_HYST(1));
data->temp_add[0] =
- w83781d_read_value(client, W83781D_REG_TEMP(2));
+ w83781d_read_value(data, W83781D_REG_TEMP(2));
data->temp_max_add[0] =
- w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));
+ w83781d_read_value(data, W83781D_REG_TEMP_OVER(2));
data->temp_max_hyst_add[0] =
- w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));
+ w83781d_read_value(data, W83781D_REG_TEMP_HYST(2));
if (data->type != w83783s) {
data->temp_add[1] =
- w83781d_read_value(client, W83781D_REG_TEMP(3));
+ w83781d_read_value(data, W83781D_REG_TEMP(3));
data->temp_max_add[1] =
- w83781d_read_value(client,
+ w83781d_read_value(data,
W83781D_REG_TEMP_OVER(3));
data->temp_max_hyst_add[1] =
- w83781d_read_value(client,
+ w83781d_read_value(data,
W83781D_REG_TEMP_HYST(3));
}
- i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);
+ i = w83781d_read_value(data, W83781D_REG_VID_FANDIV);
data->vid = i & 0x0f;
- data->vid |= (w83781d_read_value(client,
+ data->vid |= (w83781d_read_value(data,
W83781D_REG_CHIPID) & 0x01) << 4;
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = (i >> 6) & 0x03;
- data->fan_div[2] = (w83781d_read_value(client,
+ data->fan_div[2] = (w83781d_read_value(data,
W83781D_REG_PIN) >> 6) & 0x03;
if ((data->type != w83781d) && (data->type != as99127f)) {
- i = w83781d_read_value(client, W83781D_REG_VBAT);
+ i = w83781d_read_value(data, W83781D_REG_VBAT);
data->fan_div[0] |= (i >> 3) & 0x04;
data->fan_div[1] |= (i >> 4) & 0x04;
data->fan_div[2] |= (i >> 5) & 0x04;
}
if ((data->type == w83782d) || (data->type == w83627hf)) {
- data->alarms = w83781d_read_value(client,
+ data->alarms = w83781d_read_value(data,
W83782D_REG_ALARM1)
- | (w83781d_read_value(client,
+ | (w83781d_read_value(data,
W83782D_REG_ALARM2) << 8)
- | (w83781d_read_value(client,
+ | (w83781d_read_value(data,
W83782D_REG_ALARM3) << 16);
} else if (data->type == w83783s) {
- data->alarms = w83781d_read_value(client,
+ data->alarms = w83781d_read_value(data,
W83782D_REG_ALARM1)
- | (w83781d_read_value(client,
+ | (w83781d_read_value(data,
W83782D_REG_ALARM2) << 8);
} else {
/* No real-time status registers, fall back to
interrupt status registers */
- data->alarms = w83781d_read_value(client,
+ data->alarms = w83781d_read_value(data,
W83781D_REG_ALARM1)
- | (w83781d_read_value(client,
+ | (w83781d_read_value(data,
W83781D_REG_ALARM2) << 8);
}
- i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);
+ i = w83781d_read_value(data, W83781D_REG_BEEP_INTS2);
data->beep_enable = i >> 7;
data->beep_mask = ((i & 0x7f) << 8) +
- w83781d_read_value(client, W83781D_REG_BEEP_INTS1);
+ w83781d_read_value(data, W83781D_REG_BEEP_INTS1);
if ((data->type != w83781d) && (data->type != as99127f)) {
data->beep_mask |=
- w83781d_read_value(client,
+ w83781d_read_value(data,
W83781D_REG_BEEP_INTS3) << 16;
}
data->last_updated = jiffies;
@@ -1672,6 +1655,133 @@ static struct w83781d_data *w83781d_update_device(struct device *dev)
return data;
}
+/* return 1 if a supported chip is found, 0 otherwise */
+static int __init
+w83781d_isa_found(unsigned short address)
+{
+ int val, save, found = 0;
+
+ if (!request_region(address, W83781D_EXTENT, "w83781d"))
+ return 0;
+
+#define REALLY_SLOW_IO
+ /* We need the timeouts for at least some W83781D-like
+ chips. But only if we read 'undefined' registers. */
+ val = inb_p(address + 1);
+ if (inb_p(address + 2) != val
+ || inb_p(address + 3) != val
+ || inb_p(address + 7) != val) {
+ pr_debug("w83781d: Detection failed at step 1\n");
+ goto release;
+ }
+#undef REALLY_SLOW_IO
+
+ /* We should be able to change the 7 LSB of the address port. The
+ MSB (busy flag) should be clear initially, set after the write. */
+ save = inb_p(address + W83781D_ADDR_REG_OFFSET);
+ if (save & 0x80) {
+ pr_debug("w83781d: Detection failed at step 2\n");
+ goto release;
+ }
+ val = ~save & 0x7f;
+ outb_p(val, address + W83781D_ADDR_REG_OFFSET);
+ if (inb_p(address + W83781D_ADDR_REG_OFFSET) != (val | 0x80)) {
+ outb_p(save, address + W83781D_ADDR_REG_OFFSET);
+ pr_debug("w83781d: Detection failed at step 3\n");
+ goto release;
+ }
+
+ /* We found a device, now see if it could be a W83781D */
+ outb_p(W83781D_REG_CONFIG, address + W83781D_ADDR_REG_OFFSET);
+ val = inb_p(address + W83781D_DATA_REG_OFFSET);
+ if (val & 0x80) {
+ pr_debug("w83781d: Detection failed at step 4\n");
+ goto release;
+ }
+ outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
+ save = inb_p(address + W83781D_DATA_REG_OFFSET);
+ outb_p(W83781D_REG_CHIPMAN, address + W83781D_ADDR_REG_OFFSET);
+ val = inb_p(address + W83781D_DATA_REG_OFFSET);
+ if ((!(save & 0x80) && (val != 0xa3))
+ || ((save & 0x80) && (val != 0x5c))) {
+ pr_debug("w83781d: Detection failed at step 5\n");
+ goto release;
+ }
+ outb_p(W83781D_REG_I2C_ADDR, address + W83781D_ADDR_REG_OFFSET);
+ val = inb_p(address + W83781D_DATA_REG_OFFSET);
+ if (val < 0x03 || val > 0x77) { /* Not a valid I2C address */
+ pr_debug("w83781d: Detection failed at step 6\n");
+ goto release;
+ }
+
+ /* The busy flag should be clear again */
+ if (inb_p(address + W83781D_ADDR_REG_OFFSET) & 0x80) {
+ pr_debug("w83781d: Detection failed at step 7\n");
+ goto release;
+ }
+
+ /* Determine the chip type */
+ outb_p(W83781D_REG_BANK, address + W83781D_ADDR_REG_OFFSET);
+ save = inb_p(address + W83781D_DATA_REG_OFFSET);
+ outb_p(save & 0xf8, address + W83781D_DATA_REG_OFFSET);
+ outb_p(W83781D_REG_WCHIPID, address + W83781D_ADDR_REG_OFFSET);
+ val = inb_p(address + W83781D_DATA_REG_OFFSET);
+ if ((val & 0xfe) == 0x10 /* W83781D */
+ || val == 0x30 /* W83782D */
+ || val == 0x21) /* W83627HF */
+ found = 1;
+
+ if (found)
+ pr_info("w83781d: Found a %s chip at %#x\n",
+ val == 0x21 ? "W83627HF" :
+ val == 0x30 ? "W83782D" : "W83781D", (int)address);
+
+ release:
+ release_region(address, W83781D_EXTENT);
+ return found;
+}
+
+static int __init
+w83781d_isa_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + W83781D_EXTENT,
+ .name = "w83781d",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("w83781d", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "w83781d: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "w83781d: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "w83781d: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+ exit_device_put:
+ platform_device_put(pdev);
+ exit:
+ pdev = NULL;
+ return err;
+}
+
static int __init
sensors_w83781d_init(void)
{
@@ -1679,21 +1789,36 @@ sensors_w83781d_init(void)
res = i2c_add_driver(&w83781d_driver);
if (res)
- return res;
+ goto exit;
+
+ if (w83781d_isa_found(isa_address)) {
+ res = platform_driver_register(&w83781d_isa_driver);
+ if (res)
+ goto exit_unreg_i2c_driver;
- /* Don't exit if this one fails, we still want the I2C variants
- to work! */
- if (i2c_isa_add_driver(&w83781d_isa_driver))
- isa_address = 0;
+ /* Sets global pdev as a side effect */
+ res = w83781d_isa_device_add(isa_address);
+ if (res)
+ goto exit_unreg_isa_driver;
+ }
return 0;
+
+ exit_unreg_isa_driver:
+ platform_driver_unregister(&w83781d_isa_driver);
+ exit_unreg_i2c_driver:
+ i2c_del_driver(&w83781d_driver);
+ exit:
+ return res;
}
static void __exit
sensors_w83781d_exit(void)
{
- if (isa_address)
- i2c_isa_del_driver(&w83781d_isa_driver);
+ if (pdev) {
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&w83781d_isa_driver);
+ }
i2c_del_driver(&w83781d_driver);
}
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 11935f66fcd..434a61b415a 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -2,9 +2,7 @@
# I2C subsystem configuration
#
-menu "I2C support"
-
-config I2C
+menuconfig I2C
tristate "I2C support"
---help---
I2C (pronounce: I-square-C) is a slow serial bus protocol used in
@@ -22,9 +20,14 @@ config I2C
This I2C support can also be built as a module. If so, the module
will be called i2c-core.
+if I2C
+
+config I2C_BOARDINFO
+ boolean
+ default y
+
config I2C_CHARDEV
tristate "I2C device interface"
- depends on I2C
help
Say Y here to use i2c-* device files, usually found in the /dev
directory on your system. They make it possible to have user-space
@@ -40,7 +43,6 @@ source drivers/i2c/chips/Kconfig
config I2C_DEBUG_CORE
bool "I2C Core debugging messages"
- depends on I2C
help
Say Y here if you want the I2C core to produce a bunch of debug
messages to the system log. Select this if you are having a
@@ -48,7 +50,6 @@ config I2C_DEBUG_CORE
config I2C_DEBUG_ALGO
bool "I2C Algorithm debugging messages"
- depends on I2C
help
Say Y here if you want the I2C algorithm drivers to produce a bunch
of debug messages to the system log. Select this if you are having
@@ -57,7 +58,6 @@ config I2C_DEBUG_ALGO
config I2C_DEBUG_BUS
bool "I2C Bus debugging messages"
- depends on I2C
help
Say Y here if you want the I2C bus drivers to produce a bunch of
debug messages to the system log. Select this if you are having
@@ -66,12 +66,10 @@ config I2C_DEBUG_BUS
config I2C_DEBUG_CHIP
bool "I2C Chip debugging messages"
- depends on I2C
help
Say Y here if you want the I2C chip drivers to produce a bunch of
debug messages to the system log. Select this if you are having
a problem with I2C support and want to see more of what is going
on.
-endmenu
-
+endif # I2C
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 71c5a854ac5..ba26e6cbe74 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -2,6 +2,7 @@
# Makefile for the i2c core.
#
+obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o
obj-$(CONFIG_I2C) += i2c-core.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-y += busses/ chips/ algos/
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index af0203409dd..58899078810 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -3,11 +3,9 @@
#
menu "I2C Algorithms"
- depends on I2C
config I2C_ALGOBIT
tristate "I2C bit-banging interfaces"
- depends on I2C
help
This allows you to use a range of I2C adapters called bit-banging
adapters. Say Y if you own an I2C adapter belonging to this class
@@ -18,7 +16,6 @@ config I2C_ALGOBIT
config I2C_ALGOPCF
tristate "I2C PCF 8584 interfaces"
- depends on I2C
help
This allows you to use a range of I2C adapters called PCF adapters.
Say Y if you own an I2C adapter belonging to this class and then say
@@ -29,7 +26,6 @@ config I2C_ALGOPCF
config I2C_ALGOPCA
tristate "I2C PCA 9564 interfaces"
- depends on I2C
help
This allows you to use a range of I2C adapters called PCA adapters.
Say Y if you own an I2C adapter belonging to this class and then say
@@ -40,11 +36,11 @@ config I2C_ALGOPCA
config I2C_ALGO8XX
tristate "MPC8xx CPM I2C interface"
- depends on 8xx && I2C
+ depends on 8xx
config I2C_ALGO_SGI
tristate "I2C SGI interfaces"
- depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
+ depends on SGI_IP22 || SGI_IP32 || X86_VISWS
help
Supports the SGI interfaces like the ones found on SGI Indy VINO
or SGI O2 MACE.
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 95aa5395a5b..8a5f5825bb7 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -33,19 +33,30 @@
/* ----- global defines ----------------------------------------------- */
-#define DEB(x) if (i2c_debug>=1) x;
-#define DEB2(x) if (i2c_debug>=2) x;
-#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
-#define DEBPROTO(x) if (i2c_debug>=9) { x; }
- /* debug the protocol by showing transferred bits */
+#ifdef DEBUG
+#define bit_dbg(level, dev, format, args...) \
+ do { \
+ if (i2c_debug >= level) \
+ dev_dbg(dev, format, ##args); \
+ } while (0)
+#else
+#define bit_dbg(level, dev, format, args...) \
+ do {} while (0)
+#endif /* DEBUG */
/* ----- global variables --------------------------------------------- */
-/* module parameters:
- */
-static int i2c_debug;
static int bit_test; /* see if the line-setting functions work */
+module_param(bit_test, bool, 0);
+MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
+
+#ifdef DEBUG
+static int i2c_debug = 1;
+module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(i2c_debug,
+ "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose");
+#endif
/* --- setting states on the bus with the right timing: --------------- */
@@ -57,19 +68,19 @@ static int bit_test; /* see if the line-setting functions work */
static inline void sdalo(struct i2c_algo_bit_data *adap)
{
setsda(adap,0);
- udelay(adap->udelay);
+ udelay((adap->udelay + 1) / 2);
}
static inline void sdahi(struct i2c_algo_bit_data *adap)
{
setsda(adap,1);
- udelay(adap->udelay);
+ udelay((adap->udelay + 1) / 2);
}
static inline void scllo(struct i2c_algo_bit_data *adap)
{
setscl(adap,0);
- udelay(adap->udelay);
+ udelay(adap->udelay / 2);
}
/*
@@ -98,7 +109,11 @@ static int sclhi(struct i2c_algo_bit_data *adap)
}
cond_resched();
}
- DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
+#ifdef DEBUG
+ if (jiffies != start && i2c_debug >= 3)
+ pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go "
+ "high\n", jiffies - start);
+#endif
done:
udelay(adap->udelay);
@@ -110,30 +125,29 @@ done:
static void i2c_start(struct i2c_algo_bit_data *adap)
{
/* assert: scl, sda are high */
- DEBPROTO(printk("S "));
- sdalo(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
scllo(adap);
}
static void i2c_repstart(struct i2c_algo_bit_data *adap)
{
- /* scl, sda may not be high */
- DEBPROTO(printk(" Sr "));
- setsda(adap,1);
+ /* assert: scl is low */
+ sdahi(adap);
sclhi(adap);
-
- sdalo(adap);
+ setsda(adap, 0);
+ udelay(adap->udelay);
scllo(adap);
}
static void i2c_stop(struct i2c_algo_bit_data *adap)
{
- DEBPROTO(printk("P\n"));
/* assert: scl is low */
sdalo(adap);
sclhi(adap);
- sdahi(adap);
+ setsda(adap, 1);
+ udelay(adap->udelay);
}
@@ -145,7 +159,7 @@ static void i2c_stop(struct i2c_algo_bit_data *adap)
* 0 if the device did not ack
* -ETIMEDOUT if an error occurred (while raising the scl line)
*/
-static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
+static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c)
{
int i;
int sb;
@@ -154,34 +168,32 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
/* assert: scl is low */
for ( i=7 ; i>=0 ; i-- ) {
- sb = c & ( 1 << i );
+ sb = (c >> i) & 1;
setsda(adap,sb);
- udelay(adap->udelay);
- DEBPROTO(printk(KERN_DEBUG "%d",sb!=0));
+ udelay((adap->udelay + 1) / 2);
if (sclhi(adap)<0) { /* timed out */
- sdahi(adap); /* we don't want to block the net */
- DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i));
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at bit #%d\n", (int)c, i);
return -ETIMEDOUT;
};
/* do arbitration here:
* if ( sb && ! getsda(adap) ) -> ouch! Get out of here.
*/
- setscl(adap, 0 );
- udelay(adap->udelay);
+ scllo(adap);
}
sdahi(adap);
if (sclhi(adap)<0){ /* timeout */
- DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff));
- return -ETIMEDOUT;
+ bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, "
+ "timeout at ack\n", (int)c);
+ return -ETIMEDOUT;
};
/* read ack: SDA should be pulled down by slave */
- ack=getsda(adap); /* ack: sda is pulled low ->success. */
- DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack));
+ ack = !getsda(adap); /* ack: sda is pulled low -> success */
+ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c,
+ ack ? "A" : "NA");
- DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) );
- DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") );
scllo(adap);
- return 0==ack; /* return 1 if device acked */
+ return ack;
/* assert: scl is low (sda undef) */
}
@@ -198,19 +210,18 @@ static int i2c_inb(struct i2c_adapter *i2c_adap)
sdahi(adap);
for (i=0;i<8;i++) {
if (sclhi(adap)<0) { /* timeout */
- DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i));
+ bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit "
+ "#%d\n", 7 - i);
return -ETIMEDOUT;
};
indata *= 2;
if ( getsda(adap) )
indata |= 0x01;
- scllo(adap);
+ setscl(adap, 0);
+ udelay(i == 7 ? adap->udelay / 2 : adap->udelay);
}
/* assert: scl is low */
- DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff));
-
- DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff));
- return (int) (indata & 0xff);
+ return indata;
}
/*
@@ -221,73 +232,67 @@ static int test_bus(struct i2c_algo_bit_data *adap, char* name) {
int scl,sda;
if (adap->getscl==NULL)
- printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, "
- "SCL is not readable.\n");
+ pr_info("%s: Testing SDA only, SCL is not readable\n", name);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
- printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda);
if (!scl || !sda ) {
- printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name);
+ printk(KERN_WARNING "%s: bus seems to be busy\n", name);
goto bailout;
}
sdalo(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
- printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda);
if ( 0 != sda ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n");
+ printk(KERN_WARNING "%s: SDA stuck high!\n", name);
goto bailout;
}
if ( 0 == scl ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
- "while pulling SDA low!\n");
+ printk(KERN_WARNING "%s: SCL unexpected low "
+ "while pulling SDA low!\n", name);
goto bailout;
}
sdahi(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
- printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda);
if ( 0 == sda ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n");
+ printk(KERN_WARNING "%s: SDA stuck low!\n", name);
goto bailout;
}
if ( 0 == scl ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low "
- "while pulling SDA high!\n");
+ printk(KERN_WARNING "%s: SCL unexpected low "
+ "while pulling SDA high!\n", name);
goto bailout;
}
scllo(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?0:getscl(adap));
- printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda);
if ( 0 != scl ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n");
+ printk(KERN_WARNING "%s: SCL stuck high!\n", name);
goto bailout;
}
if ( 0 == sda ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
- "while pulling SCL low!\n");
+ printk(KERN_WARNING "%s: SDA unexpected low "
+ "while pulling SCL low!\n", name);
goto bailout;
}
sclhi(adap);
sda=getsda(adap);
scl=(adap->getscl==NULL?1:getscl(adap));
- printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda);
if ( 0 == scl ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n");
+ printk(KERN_WARNING "%s: SCL stuck low!\n", name);
goto bailout;
}
if ( 0 == sda ) {
- printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low "
- "while pulling SCL high!\n");
+ printk(KERN_WARNING "%s: SDA unexpected low "
+ "while pulling SCL high!\n", name);
goto bailout;
}
- printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name);
+ pr_info("%s: Test OK\n", name);
return 0;
bailout:
sdahi(adap);
@@ -312,44 +317,39 @@ static int try_address(struct i2c_adapter *i2c_adap,
int i,ret = -1;
for (i=0;i<=retries;i++) {
ret = i2c_outb(i2c_adap,addr);
- if (ret==1)
- break; /* success! */
- i2c_stop(adap);
- udelay(5/*adap->udelay*/);
- if (i==retries) /* no success */
+ if (ret == 1 || i == retries)
break;
- i2c_start(adap);
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
+ i2c_stop(adap);
udelay(adap->udelay);
+ yield();
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
+ i2c_start(adap);
}
- DEB2(if (i)
- printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n",
- i+1, addr & 1 ? "read" : "write", addr>>1,
- ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" )
- );
+ if (i && ret)
+ bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at "
+ "0x%02x: %s\n", i + 1,
+ addr & 1 ? "read from" : "write to", addr >> 1,
+ ret == 1 ? "success" : "failed, timeout?");
return ret;
}
static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
- struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
- char c;
- const char *temp = msg->buf;
+ const unsigned char *temp = msg->buf;
int count = msg->len;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
int retval;
int wrcount=0;
while (count > 0) {
- c = *temp;
- DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff));
- retval = i2c_outb(i2c_adap,c);
+ retval = i2c_outb(i2c_adap, *temp);
if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */
count--;
temp++;
wrcount++;
} else { /* arbitration or no acknowledge */
dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n");
- i2c_stop(adap);
return (retval<0)? retval : -EFAULT;
/* got a better one ?? */
}
@@ -362,7 +362,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
int inval;
int rdcount=0; /* counts bytes read */
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
- char *temp = msg->buf;
+ unsigned char *temp = msg->buf;
int count = msg->len;
while (count > 0) {
@@ -371,30 +371,44 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
*temp = inval;
rdcount++;
} else { /* read timed out */
- printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n");
break;
}
temp++;
count--;
- if (msg->flags & I2C_M_NO_RD_ACK)
+ if (msg->flags & I2C_M_NO_RD_ACK) {
+ bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n",
+ inval);
continue;
-
- if ( count > 0 ) { /* send ack */
- sdalo(adap);
- DEBPROTO(printk(" Am "));
- } else {
- sdahi(adap); /* neg. ack on last byte */
- DEBPROTO(printk(" NAm "));
}
+
+ /* assert: sda is high */
+ if (count) /* send ack */
+ setsda(adap, 0);
+ udelay((adap->udelay + 1) / 2);
+ bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval,
+ count ? "A" : "NA");
if (sclhi(adap)<0) { /* timeout */
- sdahi(adap);
- printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n");
+ dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n");
return -ETIMEDOUT;
};
scllo(adap);
- sdahi(adap);
+
+ /* Some SMBus transactions require that we receive the
+ transaction length as the first read byte. */
+ if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) {
+ if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&i2c_adap->dev, "readbytes: invalid "
+ "block length (%d)\n", inval);
+ return -EREMOTEIO;
+ }
+ /* The original count value accounts for the extra
+ bytes, that is, either 1 for a regular transaction,
+ or 2 for a PEC transaction. */
+ count += inval;
+ msg->len += inval;
+ }
}
return rdcount;
}
@@ -421,27 +435,31 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
if ( (flags & I2C_M_TEN) ) {
/* a ten bit address */
addr = 0xf0 | (( msg->addr >> 7) & 0x03);
- DEB2(printk(KERN_DEBUG "addr0: %d\n",addr));
+ bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr);
/* try extended address code...*/
ret = try_address(i2c_adap, addr, retries);
if ((ret != 1) && !nak_ok) {
- printk(KERN_ERR "died at extended address code.\n");
+ dev_err(&i2c_adap->dev,
+ "died at extended address code\n");
return -EREMOTEIO;
}
/* the remaining 8 bit address */
ret = i2c_outb(i2c_adap,msg->addr & 0x7f);
if ((ret != 1) && !nak_ok) {
/* the chip did not ack / xmission error occurred */
- printk(KERN_ERR "died at 2nd address code.\n");
+ dev_err(&i2c_adap->dev, "died at 2nd address code\n");
return -EREMOTEIO;
}
if ( flags & I2C_M_RD ) {
+ bit_dbg(3, &i2c_adap->dev, "emitting repeated "
+ "start condition\n");
i2c_repstart(adap);
/* okay, now switch into reading mode */
addr |= 0x01;
ret = try_address(i2c_adap, addr, retries);
if ((ret!=1) && !nak_ok) {
- printk(KERN_ERR "died at extended address code.\n");
+ dev_err(&i2c_adap->dev,
+ "died at repeated address code\n");
return -EREMOTEIO;
}
}
@@ -468,44 +486,62 @@ static int bit_xfer(struct i2c_adapter *i2c_adap,
int i,ret;
unsigned short nak_ok;
+ bit_dbg(3, &i2c_adap->dev, "emitting start condition\n");
i2c_start(adap);
for (i=0;i<num;i++) {
pmsg = &msgs[i];
nak_ok = pmsg->flags & I2C_M_IGNORE_NAK;
if (!(pmsg->flags & I2C_M_NOSTART)) {
if (i) {
+ bit_dbg(3, &i2c_adap->dev, "emitting "
+ "repeated start condition\n");
i2c_repstart(adap);
}
ret = bit_doAddress(i2c_adap, pmsg);
if ((ret != 0) && !nak_ok) {
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n"
- ,msgs[i].addr,i));
- return (ret<0) ? ret : -EREMOTEIO;
+ bit_dbg(1, &i2c_adap->dev, "NAK from "
+ "device addr 0x%02x msg #%d\n",
+ msgs[i].addr, i);
+ goto bailout;
}
}
if (pmsg->flags & I2C_M_RD ) {
/* read bytes into buffer*/
ret = readbytes(i2c_adap, pmsg);
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret));
- if (ret < pmsg->len ) {
- return (ret<0)? ret : -EREMOTEIO;
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ goto bailout;
}
} else {
/* write bytes from buffer */
ret = sendbytes(i2c_adap, pmsg);
- DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret));
- if (ret < pmsg->len ) {
- return (ret<0) ? ret : -EREMOTEIO;
+ if (ret >= 1)
+ bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n",
+ ret, ret == 1 ? "" : "s");
+ if (ret < pmsg->len) {
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ goto bailout;
}
}
}
+ ret = i;
+
+bailout:
+ bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n");
i2c_stop(adap);
- return num;
+ return ret;
}
static u32 bit_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
}
@@ -520,7 +556,7 @@ static const struct i2c_algorithm i2c_bit_algo = {
/*
* registering functions to load algorithms at runtime
*/
-int i2c_bit_add_bus(struct i2c_adapter *adap)
+static int i2c_bit_prepare_bus(struct i2c_adapter *adap)
{
struct i2c_algo_bit_data *bit_adap = adap->algo_data;
@@ -530,25 +566,39 @@ int i2c_bit_add_bus(struct i2c_adapter *adap)
return -ENODEV;
}
- DEB2(dev_dbg(&adap->dev, "hw routines registered.\n"));
-
/* register new adapter to i2c module... */
adap->algo = &i2c_bit_algo;
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
+ return 0;
+}
+
+int i2c_bit_add_bus(struct i2c_adapter *adap)
+{
+ int err;
+
+ err = i2c_bit_prepare_bus(adap);
+ if (err)
+ return err;
+
return i2c_add_adapter(adap);
}
EXPORT_SYMBOL(i2c_bit_add_bus);
+int i2c_bit_add_numbered_bus(struct i2c_adapter *adap)
+{
+ int err;
+
+ err = i2c_bit_prepare_bus(adap);
+ if (err)
+ return err;
+
+ return i2c_add_numbered_adapter(adap);
+}
+EXPORT_SYMBOL(i2c_bit_add_numbered_bus);
+
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
MODULE_LICENSE("GPL");
-
-module_param(bit_test, bool, 0);
-module_param(i2c_debug, int, S_IRUGO | S_IWUSR);
-
-MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck");
-MODULE_PARM_DESC(i2c_debug,
- "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
index ac2d5053078..6eaf145e1ad 100644
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -1,6 +1,7 @@
/*
- * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters.
- *
+ * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and
+ * MACE (SGI O2) chips.
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
@@ -162,8 +163,8 @@ static const struct i2c_algorithm sgi_algo = {
.functionality = sgi_func,
};
-/*
- * registering functions to load algorithms at runtime
+/*
+ * registering functions to load algorithms at runtime
*/
int i2c_sgi_add_bus(struct i2c_adapter *adap)
{
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index ece31d2c6c6..838dc1c19d6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -3,11 +3,10 @@
#
menu "I2C Hardware Bus support"
- depends on I2C
config I2C_ALI1535
tristate "ALI 1535"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the SMB
Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB
@@ -19,7 +18,7 @@ config I2C_ALI1535
config I2C_ALI1563
tristate "ALI 1563"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the SMB
Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
@@ -31,7 +30,7 @@ config I2C_ALI1563
config I2C_ALI15X3
tristate "ALI 15x3"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
@@ -41,7 +40,7 @@ config I2C_ALI15X3
config I2C_AMD756
tristate "AMD 756/766/768/8111 and nVidia nForce"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the AMD
756/766/768 mainboard I2C interfaces. The driver also includes
@@ -66,7 +65,7 @@ config I2C_AMD756_S4882
config I2C_AMD8111
tristate "AMD 8111"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
second (SMBus 2.0) AMD 8111 mainboard I2C interface.
@@ -76,14 +75,14 @@ config I2C_AMD8111
config I2C_AT91
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
- depends on I2C && ARCH_AT91 && EXPERIMENTAL
+ depends on ARCH_AT91 && EXPERIMENTAL
help
This supports the use of the I2C interface on Atmel AT91
processors.
config I2C_AU1550
tristate "Au1550/Au1200 SMBus interface"
- depends on I2C && (SOC_AU1550 || SOC_AU1200)
+ depends on SOC_AU1550 || SOC_AU1200
help
If you say yes to this option, support will be included for the
Au1550 and Au1200 SMBus interface.
@@ -91,9 +90,25 @@ config I2C_AU1550
This driver can also be built as a module. If so, the module
will be called i2c-au1550.
+config I2C_BLACKFIN_TWI
+ tristate "Blackfin TWI I2C support"
+ depends on BF534 || BF536 || BF537
+ help
+ This is the TWI I2C device driver for Blackfin 534/536/537.
+ This driver can also be built as a module. If so, the module
+ will be called i2c-bfin-twi.
+
+config I2C_BLACKFIN_TWI_CLK_KHZ
+ int "Blackfin TWI I2C clock (kHz)"
+ depends on I2C_BLACKFIN_TWI
+ range 10 400
+ default 50
+ help
+ The unit of the TWI clock is kHz.
+
config I2C_ELEKTOR
tristate "Elektor ISA card"
- depends on I2C && ISA && BROKEN_ON_SMP
+ depends on ISA && BROKEN_ON_SMP
select I2C_ALGOPCF
help
This supports the PCF8584 ISA bus I2C adapter. Say Y if you own
@@ -102,9 +117,17 @@ config I2C_ELEKTOR
This support is also available as a module. If so, the module
will be called i2c-elektor.
+config I2C_GPIO
+ tristate "GPIO-based bitbanging I2C"
+ depends on GENERIC_GPIO
+ select I2C_ALGOBIT
+ help
+ This is a very simple bitbanging I2C driver utilizing the
+ arch-neutral GPIO API to control the SCL and SDA lines.
+
config I2C_HYDRA
tristate "CHRP Apple Hydra Mac I/O I2C interface"
- depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL
+ depends on PCI && PPC_CHRP && EXPERIMENTAL
select I2C_ALGOBIT
help
This supports the use of the I2C interface in the Apple Hydra Mac
@@ -116,7 +139,7 @@ config I2C_HYDRA
config I2C_I801
tristate "Intel 82801 (ICH)"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
@@ -139,7 +162,7 @@ config I2C_I801
config I2C_I810
tristate "Intel 810/815"
- depends on I2C && PCI
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the Intel
@@ -156,7 +179,7 @@ config I2C_I810
config I2C_PXA
tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)"
- depends on I2C && EXPERIMENTAL && ARCH_PXA
+ depends on EXPERIMENTAL && ARCH_PXA
help
If you have devices in the PXA I2C bus, say yes to this option.
This driver can also be built as a module. If so, the module
@@ -172,7 +195,7 @@ config I2C_PXA_SLAVE
config I2C_PIIX4
tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the Intel
PIIX4 family of mainboard I2C interfaces. Specifically, the following
@@ -195,7 +218,7 @@ config I2C_PIIX4
config I2C_IBM_IIC
tristate "IBM PPC 4xx on-chip I2C interface"
- depends on IBM_OCP && I2C
+ depends on IBM_OCP
help
Say Y here if you want to use IIC peripheral found on
embedded IBM PPC 4xx based systems.
@@ -205,7 +228,7 @@ config I2C_IBM_IIC
config I2C_IOP3XX
tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
- depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
help
Say Y here if you want to use the IIC bus controller on
the Intel IOPx3xx I/O Processors or IXP4xx Network Processors.
@@ -215,11 +238,10 @@ config I2C_IOP3XX
config I2C_ISA
tristate
- depends on I2C
config I2C_IXP4XX
- tristate "IXP4xx GPIO-Based I2C Interface"
- depends on I2C && ARCH_IXP4XX
+ tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP4XX
select I2C_ALGOBIT
help
Say Y here if you have an Intel IXP4xx(420,421,422,425) based
@@ -228,9 +250,12 @@ config I2C_IXP4XX
This support is also available as a module. If so, the module
will be called i2c-ixp4xx.
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
config I2C_IXP2000
- tristate "IXP2000 GPIO-Based I2C Interface"
- depends on I2C && ARCH_IXP2000
+ tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)"
+ depends on ARCH_IXP2000
select I2C_ALGOBIT
help
Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based
@@ -239,9 +264,12 @@ config I2C_IXP2000
This support is also available as a module. If so, the module
will be called i2c-ixp2000.
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ instead.
+
config I2C_POWERMAC
tristate "Powermac I2C interface"
- depends on I2C && PPC_PMAC
+ depends on PPC_PMAC
default y
help
This exposes the various PowerMac i2c interfaces to the linux i2c
@@ -253,7 +281,7 @@ config I2C_POWERMAC
config I2C_MPC
tristate "MPC107/824x/85xx/52xx/86xx"
- depends on I2C && PPC32
+ depends on PPC32
help
If you say yes to this option, support will be included for the
built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and
@@ -265,7 +293,7 @@ config I2C_MPC
config I2C_NFORCE2
tristate "Nvidia nForce2, nForce3 and nForce4"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the Nvidia
nForce2, nForce3 and nForce4 families of mainboard I2C interfaces.
@@ -275,7 +303,7 @@ config I2C_NFORCE2
config I2C_OCORES
tristate "OpenCores I2C Controller"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes to this option, support will be included for the
OpenCores I2C controller. For details see
@@ -286,7 +314,7 @@ config I2C_OCORES
config I2C_OMAP
tristate "OMAP I2C adapter"
- depends on I2C && ARCH_OMAP
+ depends on ARCH_OMAP
default y if MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes to this option, support will be included for the
@@ -296,7 +324,7 @@ config I2C_OMAP
config I2C_PARPORT
tristate "Parallel port adapter"
- depends on I2C && PARPORT
+ depends on PARPORT
select I2C_ALGOBIT
help
This supports parallel port I2C adapters such as the ones made by
@@ -320,7 +348,6 @@ config I2C_PARPORT
config I2C_PARPORT_LIGHT
tristate "Parallel port adapter (light)"
- depends on I2C
select I2C_ALGOBIT
help
This supports parallel port I2C adapters such as the ones made by
@@ -344,13 +371,13 @@ config I2C_PARPORT_LIGHT
config I2C_PASEMI
tristate "PA Semi SMBus interface"
- depends on PPC_PASEMI && I2C && PCI
+ depends on PPC_PASEMI && PCI
help
Supports the PA Semi PWRficient on-chip SMBus interfaces.
config I2C_PROSAVAGE
tristate "S3/VIA (Pro)Savage"
- depends on I2C && PCI
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
@@ -365,19 +392,19 @@ config I2C_PROSAVAGE
config I2C_RPXLITE
tristate "Embedded Planet RPX Lite/Classic support"
- depends on (RPXLITE || RPXCLASSIC) && I2C
+ depends on RPXLITE || RPXCLASSIC
select I2C_ALGO8XX
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
- depends on I2C && ARCH_S3C2410
+ depends on ARCH_S3C2410
help
Say Y here to include support for I2C controller in the
Samsung S3C2410 based System-on-Chip devices.
config I2C_SAVAGE4
tristate "S3 Savage 4"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
@@ -388,13 +415,25 @@ config I2C_SAVAGE4
config I2C_SIBYTE
tristate "SiByte SMBus interface"
- depends on SIBYTE_SB1xxx_SOC && I2C
+ depends on SIBYTE_SB1xxx_SOC
help
Supports the SiByte SOC on-chip I2C interfaces (2 channels).
+config I2C_SIMTEC
+ tristate "Simtec Generic I2C interface"
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be inclyded for
+ the Simtec Generic I2C interface. This driver is for the
+ simple I2C bus used on newer Simtec products for general
+ I2C, such as DDC on the Simtec BBD2016A.
+
+ This driver can also be build as a module. If so, the module
+ will be called i2c-simtec.
+
config SCx200_I2C
- tristate "NatSemi SCx200 I2C using GPIO pins"
- depends on SCx200_GPIO && I2C
+ tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)"
+ depends on SCx200_GPIO
select I2C_ALGOBIT
help
Enable the use of two GPIO pins of a SCx200 processor as an I2C bus.
@@ -404,6 +443,9 @@ config SCx200_I2C
This support is also available as a module. If so, the module
will be called scx200_i2c.
+ This driver is deprecated and will be dropped soon. Use i2c-gpio
+ (or scx200_acb) instead.
+
config SCx200_I2C_SCL
int "GPIO pin used for SCL"
depends on SCx200_I2C
@@ -422,7 +464,7 @@ config SCx200_I2C_SDA
config SCx200_ACB
tristate "Geode ACCESS.bus support"
- depends on X86_32 && I2C && PCI
+ depends on X86_32 && PCI
help
Enable the use of the ACCESS.bus controllers on the Geode SCx200 and
SC1100 processors and the CS5535 and CS5536 Geode companion devices.
@@ -434,7 +476,7 @@ config SCx200_ACB
config I2C_SIS5595
tristate "SiS 5595"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
SiS5595 SMBus (a subset of I2C) interface.
@@ -444,7 +486,7 @@ config I2C_SIS5595
config I2C_SIS630
tristate "SiS 630/730"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the
SiS630 and SiS730 SMBus (a subset of I2C) interface.
@@ -454,7 +496,7 @@ config I2C_SIS630
config I2C_SIS96X
tristate "SiS 96x"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the SiS
96x SMBus (a subset of I2C) interfaces. Specifically, the following
@@ -472,7 +514,7 @@ config I2C_SIS96X
config I2C_STUB
tristate "I2C/SMBus Test Stub"
- depends on I2C && EXPERIMENTAL && 'm'
+ depends on EXPERIMENTAL && m
default 'n'
help
This module may be useful to developers of SMBus client drivers,
@@ -483,9 +525,20 @@ config I2C_STUB
If you don't know what to do here, definitely say N.
+config I2C_TINY_USB
+ tristate "I2C-Tiny-USB"
+ depends on USB
+ help
+ If you say yes to this option, support will be included for the
+ i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See
+ http://www.harbaum.org/till/i2c_tiny_usb for hardware details.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-tiny-usb.
+
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
- depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW)
+ depends on ARCH_VERSATILE || ARCH_REALVIEW
select I2C_ALGOBIT
help
Say yes if you want to support the I2C serial bus on ARMs Versatile
@@ -496,7 +549,7 @@ config I2C_VERSATILE
config I2C_ACORN
bool "Acorn IOC/IOMD I2C bus support"
- depends on I2C && ARCH_ACORN
+ depends on ARCH_ACORN
default y
select I2C_ALGOBIT
help
@@ -506,7 +559,7 @@ config I2C_ACORN
config I2C_VIA
tristate "VIA 82C586B"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the VIA
@@ -517,7 +570,7 @@ config I2C_VIA
config I2C_VIAPRO
tristate "VIA VT82C596/82C686/82xx and CX700"
- depends on I2C && PCI
+ depends on PCI
help
If you say yes to this option, support will be included for the VIA
VT82C596 and later SMBus interface. Specifically, the following
@@ -536,7 +589,7 @@ config I2C_VIAPRO
config I2C_VOODOO3
tristate "Voodoo 3"
- depends on I2C && PCI
+ depends on PCI
select I2C_ALGOBIT
help
If you say yes to this option, support will be included for the
@@ -547,7 +600,7 @@ config I2C_VOODOO3
config I2C_PCA_ISA
tristate "PCA9564 on an ISA bus"
- depends on I2C
+ depends on ISA
select I2C_ALGOPCA
default n
help
@@ -564,7 +617,7 @@ config I2C_PCA_ISA
config I2C_MV64XXX
tristate "Marvell mv64xxx I2C Controller"
- depends on I2C && MV64X60 && EXPERIMENTAL
+ depends on MV64X60 && EXPERIMENTAL
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -574,7 +627,7 @@ config I2C_MV64XXX
config I2C_PNX
tristate "I2C bus support for Philips PNX targets"
- depends on ARCH_PNX4008 && I2C
+ depends on ARCH_PNX4008
help
This driver supports the Philips IP3204 I2C IP block master and/or
slave controller
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 290b5401835..14d1432f698 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o
obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
+obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
obj-$(CONFIG_I2C_I801) += i2c-i801.o
obj-$(CONFIG_I2C_I810) += i2c-i810.o
@@ -37,10 +39,12 @@ obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
+obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_VIA) += i2c-via.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index 1e277ba5a9f..f14372ac2fc 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -497,7 +497,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_
/* set up the sysfs linkage to our parent device */
ali1535_adapter.dev.parent = &dev->dev;
- snprintf(ali1535_adapter.name, I2C_NAME_SIZE,
+ snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name),
"SMBus ALI1535 adapter at %04x", ali1535_smba);
return i2c_add_adapter(&ali1535_adapter);
}
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index e47fe01bf42..93bf87d7096 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -492,7 +492,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_
/* set up the sysfs linkage to our parent device */
ali15x3_adapter.dev.parent = &dev->dev;
- snprintf(ali15x3_adapter.name, I2C_NAME_SIZE,
+ snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
"SMBus ALI15X3 adapter at %04x", ali15x3_smba);
return i2c_add_adapter(&ali15x3_adapter);
}
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index 0c70f829334..c9fca7b4926 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -365,7 +365,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev,
}
smbus->adapter.owner = THIS_MODULE;
- snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
"SMBus2 AMD8111 adapter at %04x", smbus->base);
smbus->adapter.id = I2C_HW_SMBUS_AMD8111;
smbus->adapter.class = I2C_CLASS_HWMON;
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 67f91bdda08..f35156c5892 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -17,7 +17,6 @@
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/i2c.h>
diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c
new file mode 100644
index 00000000000..6311039dfe6
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bfin-twi.c
@@ -0,0 +1,644 @@
+/*
+ * drivers/i2c/busses/i2c-bfin-twi.c
+ *
+ * Description: Driver for Blackfin Two Wire Interface
+ *
+ * Author: sonicz <sonic.zhang@analog.com>
+ *
+ * Copyright (c) 2005-2007 Analog Devices, Inc.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <asm/blackfin.h>
+#include <asm/irq.h>
+
+#define POLL_TIMEOUT (2 * HZ)
+
+/* SMBus mode*/
+#define TWI_I2C_MODE_STANDARD 0x01
+#define TWI_I2C_MODE_STANDARDSUB 0x02
+#define TWI_I2C_MODE_COMBINED 0x04
+
+struct bfin_twi_iface {
+ struct mutex twi_lock;
+ int irq;
+ spinlock_t lock;
+ char read_write;
+ u8 command;
+ u8 *transPtr;
+ int readNum;
+ int writeNum;
+ int cur_mode;
+ int manual_stop;
+ int result;
+ int timeout_count;
+ struct timer_list timeout_timer;
+ struct i2c_adapter adap;
+ struct completion complete;
+};
+
+static struct bfin_twi_iface twi_iface;
+
+static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface)
+{
+ unsigned short twi_int_status = bfin_read_TWI_INT_STAT();
+ unsigned short mast_stat = bfin_read_TWI_MASTER_STAT();
+
+ if (twi_int_status & XMTSERV) {
+ /* Transmit next data */
+ if (iface->writeNum > 0) {
+ bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ iface->writeNum--;
+ }
+ /* start receive immediately after complete sending in
+ * combine mode.
+ */
+ else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+ | MDIR | RSTART);
+ } else if (iface->manual_stop)
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+ | STOP);
+ SSYNC();
+ /* Clear status */
+ bfin_write_TWI_INT_STAT(XMTSERV);
+ SSYNC();
+ }
+ if (twi_int_status & RCVSERV) {
+ if (iface->readNum > 0) {
+ /* Receive next data */
+ *(iface->transPtr) = bfin_read_TWI_RCV_DATA8();
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ /* Change combine mode into sub mode after
+ * read first data.
+ */
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ /* Get read number from first byte in block
+ * combine mode.
+ */
+ if (iface->readNum == 1 && iface->manual_stop)
+ iface->readNum = *iface->transPtr + 1;
+ }
+ iface->transPtr++;
+ iface->readNum--;
+ } else if (iface->manual_stop) {
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL()
+ | STOP);
+ SSYNC();
+ }
+ /* Clear interrupt source */
+ bfin_write_TWI_INT_STAT(RCVSERV);
+ SSYNC();
+ }
+ if (twi_int_status & MERR) {
+ bfin_write_TWI_INT_STAT(MERR);
+ bfin_write_TWI_INT_MASK(0);
+ bfin_write_TWI_MASTER_STAT(0x3e);
+ bfin_write_TWI_MASTER_CTL(0);
+ SSYNC();
+ iface->result = -1;
+ /* if both err and complete int stats are set, return proper
+ * results.
+ */
+ if (twi_int_status & MCOMP) {
+ bfin_write_TWI_INT_STAT(MCOMP);
+ bfin_write_TWI_INT_MASK(0);
+ bfin_write_TWI_MASTER_CTL(0);
+ SSYNC();
+ /* If it is a quick transfer, only address bug no data,
+ * not an err, return 1.
+ */
+ if (iface->writeNum == 0 && (mast_stat & BUFRDERR))
+ iface->result = 1;
+ /* If address not acknowledged return -1,
+ * else return 0.
+ */
+ else if (!(mast_stat & ANAK))
+ iface->result = 0;
+ }
+ complete(&iface->complete);
+ return;
+ }
+ if (twi_int_status & MCOMP) {
+ bfin_write_TWI_INT_STAT(MCOMP);
+ SSYNC();
+ if (iface->cur_mode == TWI_I2C_MODE_COMBINED) {
+ if (iface->readNum == 0) {
+ /* set the read number to 1 and ask for manual
+ * stop in block combine mode
+ */
+ iface->readNum = 1;
+ iface->manual_stop = 1;
+ bfin_write_TWI_MASTER_CTL(
+ bfin_read_TWI_MASTER_CTL()
+ | (0xff << 6));
+ } else {
+ /* set the readd number in other
+ * combine mode.
+ */
+ bfin_write_TWI_MASTER_CTL(
+ (bfin_read_TWI_MASTER_CTL() &
+ (~(0xff << 6))) |
+ ( iface->readNum << 6));
+ }
+ /* remove restart bit and enable master receive */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() &
+ ~RSTART);
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() |
+ MEN | MDIR);
+ SSYNC();
+ } else {
+ iface->result = 1;
+ bfin_write_TWI_INT_MASK(0);
+ bfin_write_TWI_MASTER_CTL(0);
+ SSYNC();
+ complete(&iface->complete);
+ }
+ }
+}
+
+/* Interrupt handler */
+static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
+{
+ struct bfin_twi_iface *iface = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ del_timer(&iface->timeout_timer);
+ bfin_twi_handle_interrupt(iface);
+ spin_unlock_irqrestore(&iface->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void bfin_twi_timeout(unsigned long data)
+{
+ struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iface->lock, flags);
+ bfin_twi_handle_interrupt(iface);
+ if (iface->result == 0) {
+ iface->timeout_count--;
+ if (iface->timeout_count > 0) {
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+ } else {
+ iface->result = -1;
+ complete(&iface->complete);
+ }
+ }
+ spin_unlock_irqrestore(&iface->lock, flags);
+}
+
+/*
+ * Generic i2c master transfer entrypoint
+ */
+static int bfin_twi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ struct i2c_msg *pmsg;
+ int i, ret;
+ int rc = 0;
+
+ if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+ return -ENXIO;
+
+ mutex_lock(&iface->twi_lock);
+
+ while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+ mutex_unlock(&iface->twi_lock);
+ yield();
+ mutex_lock(&iface->twi_lock);
+ }
+
+ ret = 0;
+ for (i = 0; rc >= 0 && i < num; i++) {
+ pmsg = &msgs[i];
+ if (pmsg->flags & I2C_M_TEN) {
+ dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr "
+ "not supported !\n");
+ rc = -EINVAL;
+ break;
+ }
+
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ iface->manual_stop = 0;
+ iface->transPtr = pmsg->buf;
+ iface->writeNum = iface->readNum = pmsg->len;
+ iface->result = 0;
+ iface->timeout_count = 10;
+ /* Set Transmit device address */
+ bfin_write_TWI_MASTER_ADDR(pmsg->addr);
+
+ /* FIFO Initiation. Data in FIFO should be
+ * discarded before start a new operation.
+ */
+ bfin_write_TWI_FIFO_CTL(0x3);
+ SSYNC();
+ bfin_write_TWI_FIFO_CTL(0);
+ SSYNC();
+
+ if (pmsg->flags & I2C_M_RD)
+ iface->read_write = I2C_SMBUS_READ;
+ else {
+ iface->read_write = I2C_SMBUS_WRITE;
+ /* Transmit first data */
+ if (iface->writeNum > 0) {
+ bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ iface->writeNum--;
+ SSYNC();
+ }
+ }
+
+ /* clear int stat */
+ bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+
+ /* Interrupt mask . Enable XMT, RCV interrupt */
+ bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ)?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ if (pmsg->len > 0 && pmsg->len <= 255)
+ bfin_write_TWI_MASTER_CTL(pmsg->len << 6);
+ else if (pmsg->len > 255) {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ } else
+ break;
+
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ SSYNC();
+
+ wait_for_completion(&iface->complete);
+
+ rc = iface->result;
+ if (rc == 1)
+ ret++;
+ else if (rc == -1)
+ break;
+ }
+
+ /* Release mutex */
+ mutex_unlock(&iface->twi_lock);
+
+ return ret;
+}
+
+/*
+ * SMBus type transfer entrypoint
+ */
+
+int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data *data)
+{
+ struct bfin_twi_iface *iface = adap->algo_data;
+ int rc = 0;
+
+ if (!(bfin_read_TWI_CONTROL() & TWI_ENA))
+ return -ENXIO;
+
+ mutex_lock(&iface->twi_lock);
+
+ while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) {
+ mutex_unlock(&iface->twi_lock);
+ yield();
+ mutex_lock(&iface->twi_lock);
+ }
+
+ iface->writeNum = 0;
+ iface->readNum = 0;
+
+ /* Prepare datas & select mode */
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ iface->transPtr = NULL;
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE:
+ if (data == NULL)
+ iface->transPtr = NULL;
+ else {
+ if (read_write == I2C_SMBUS_READ)
+ iface->readNum = 1;
+ else
+ iface->writeNum = 1;
+ iface->transPtr = &data->byte;
+ }
+ iface->cur_mode = TWI_I2C_MODE_STANDARD;
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = &data->byte;
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_PROC_CALL:
+ iface->writeNum = 2;
+ iface->readNum = 2;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ iface->transPtr = (u8 *)&data->word;
+ break;
+ case I2C_SMBUS_BLOCK_DATA:
+ if (read_write == I2C_SMBUS_READ) {
+ iface->readNum = 0;
+ iface->cur_mode = TWI_I2C_MODE_COMBINED;
+ } else {
+ iface->writeNum = data->block[0] + 1;
+ iface->cur_mode = TWI_I2C_MODE_STANDARDSUB;
+ }
+ iface->transPtr = data->block;
+ break;
+ default:
+ return -1;
+ }
+
+ iface->result = 0;
+ iface->manual_stop = 0;
+ iface->read_write = read_write;
+ iface->command = command;
+ iface->timeout_count = 10;
+
+ /* FIFO Initiation. Data in FIFO should be discarded before
+ * start a new operation.
+ */
+ bfin_write_TWI_FIFO_CTL(0x3);
+ SSYNC();
+ bfin_write_TWI_FIFO_CTL(0);
+
+ /* clear int stat */
+ bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV);
+
+ /* Set Transmit device address */
+ bfin_write_TWI_MASTER_ADDR(addr);
+ SSYNC();
+
+ iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+ add_timer(&iface->timeout_timer);
+
+ switch (iface->cur_mode) {
+ case TWI_I2C_MODE_STANDARDSUB:
+ bfin_write_TWI_XMT_DATA8(iface->command);
+ bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ if (iface->writeNum + 1 <= 255)
+ bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+ else {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ }
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ case TWI_I2C_MODE_COMBINED:
+ bfin_write_TWI_XMT_DATA8(iface->command);
+ bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV);
+ SSYNC();
+
+ if (iface->writeNum > 0)
+ bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6);
+ else
+ bfin_write_TWI_MASTER_CTL(0x1 << 6);
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0));
+ break;
+ default:
+ bfin_write_TWI_MASTER_CTL(0);
+ if (size != I2C_SMBUS_QUICK) {
+ /* Don't access xmit data register when this is a
+ * read operation.
+ */
+ if (iface->read_write != I2C_SMBUS_READ) {
+ if (iface->writeNum > 0) {
+ bfin_write_TWI_XMT_DATA8(*(iface->transPtr++));
+ if (iface->writeNum <= 255)
+ bfin_write_TWI_MASTER_CTL(iface->writeNum << 6);
+ else {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ }
+ iface->writeNum--;
+ } else {
+ bfin_write_TWI_XMT_DATA8(iface->command);
+ bfin_write_TWI_MASTER_CTL(1 << 6);
+ }
+ } else {
+ if (iface->readNum > 0 && iface->readNum <= 255)
+ bfin_write_TWI_MASTER_CTL(iface->readNum << 6);
+ else if (iface->readNum > 255) {
+ bfin_write_TWI_MASTER_CTL(0xff << 6);
+ iface->manual_stop = 1;
+ } else {
+ del_timer(&iface->timeout_timer);
+ break;
+ }
+ }
+ }
+ bfin_write_TWI_INT_MASK(MCOMP | MERR |
+ ((iface->read_write == I2C_SMBUS_READ) ?
+ RCVSERV : XMTSERV));
+ SSYNC();
+
+ /* Master enable */
+ bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN |
+ ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
+ ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
+ break;
+ }
+ SSYNC();
+
+ wait_for_completion(&iface->complete);
+
+ rc = (iface->result >= 0) ? 0 : -1;
+
+ /* Release mutex */
+ mutex_unlock(&iface->twi_lock);
+
+ return rc;
+}
+
+/*
+ * Return what the adapter supports
+ */
+static u32 bfin_twi_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_I2C;
+}
+
+
+static struct i2c_algorithm bfin_twi_algorithm = {
+ .master_xfer = bfin_twi_master_xfer,
+ .smbus_xfer = bfin_twi_smbus_xfer,
+ .functionality = bfin_twi_functionality,
+};
+
+
+static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state)
+{
+/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+
+ /* Disable TWI */
+ bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA);
+ SSYNC();
+
+ return 0;
+}
+
+static int i2c_bfin_twi_resume(struct platform_device *dev)
+{
+/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/
+
+ /* Enable TWI */
+ bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ SSYNC();
+
+ return 0;
+}
+
+static int i2c_bfin_twi_probe(struct platform_device *dev)
+{
+ struct bfin_twi_iface *iface = &twi_iface;
+ struct i2c_adapter *p_adap;
+ int rc;
+
+ mutex_init(&(iface->twi_lock));
+ spin_lock_init(&(iface->lock));
+ init_completion(&(iface->complete));
+ iface->irq = IRQ_TWI;
+
+ init_timer(&(iface->timeout_timer));
+ iface->timeout_timer.function = bfin_twi_timeout;
+ iface->timeout_timer.data = (unsigned long)iface;
+
+ p_adap = &iface->adap;
+ p_adap->id = I2C_HW_BLACKFIN;
+ strlcpy(p_adap->name, dev->name, sizeof(p_adap->name));
+ p_adap->algo = &bfin_twi_algorithm;
+ p_adap->algo_data = iface;
+ p_adap->class = I2C_CLASS_ALL;
+ p_adap->dev.parent = &dev->dev;
+
+ rc = request_irq(iface->irq, bfin_twi_interrupt_entry,
+ IRQF_DISABLED, dev->name, iface);
+ if (rc) {
+ dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n",
+ iface->irq);
+ return -ENODEV;
+ }
+
+ /* Set TWI internal clock as 10MHz */
+ bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F);
+
+ /* Set Twi interface clock as specified */
+ bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+ << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ )
+ & 0xFF));
+
+ /* Enable TWI */
+ bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA);
+ SSYNC();
+
+ rc = i2c_add_adapter(p_adap);
+ if (rc < 0)
+ free_irq(iface->irq, iface);
+ else
+ platform_set_drvdata(dev, iface);
+
+ return rc;
+}
+
+static int i2c_bfin_twi_remove(struct platform_device *pdev)
+{
+ struct bfin_twi_iface *iface = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&(iface->adap));
+ free_irq(iface->irq, iface);
+
+ return 0;
+}
+
+static struct platform_driver i2c_bfin_twi_driver = {
+ .probe = i2c_bfin_twi_probe,
+ .remove = i2c_bfin_twi_remove,
+ .suspend = i2c_bfin_twi_suspend,
+ .resume = i2c_bfin_twi_resume,
+ .driver = {
+ .name = "i2c-bfin-twi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init i2c_bfin_twi_init(void)
+{
+ pr_info("I2C: Blackfin I2C TWI driver\n");
+
+ return platform_driver_register(&i2c_bfin_twi_driver);
+}
+
+static void __exit i2c_bfin_twi_exit(void)
+{
+ platform_driver_unregister(&i2c_bfin_twi_driver);
+}
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI");
+MODULE_LICENSE("GPL");
+
+module_init(i2c_bfin_twi_init);
+module_exit(i2c_bfin_twi_exit);
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 83496746481..804f0a551c0 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -35,6 +35,7 @@
#include <linux/pci.h>
#include <linux/wait.h>
+#include <linux/isa.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pcf.h>
@@ -207,7 +208,7 @@ static struct i2c_adapter pcf_isa_ops = {
.name = "i2c-elektor",
};
-static int __init i2c_pcfisa_init(void)
+static int __devinit elektor_match(struct device *dev, unsigned int id)
{
#ifdef __alpha__
/* check to see we have memory mapped PCF8584 connected to the
@@ -222,9 +223,8 @@ static int __init i2c_pcfisa_init(void)
/* yeap, we've found cypress, let's check config */
if (!pci_read_config_byte(cy693_dev, 0x47, &config)) {
- pr_debug("%s: found cy82c693, config "
- "register 0x47 = 0x%02x\n",
- pcf_isa_ops.name, config);
+ dev_dbg(dev, "found cy82c693, config "
+ "register 0x47 = 0x%02x\n", config);
/* UP2000 board has this register set to 0xe1,
but the most significant bit as seems can be
@@ -244,9 +244,9 @@ static int __init i2c_pcfisa_init(void)
8.25 MHz (PCI/4) clock
(this can be read from cypress) */
clock = I2C_PCF_CLK | I2C_PCF_TRNS90;
- pr_info("%s: found API UP2000 like "
- "board, will probe PCF8584 "
- "later\n", pcf_isa_ops.name);
+ dev_info(dev, "found API UP2000 like "
+ "board, will probe PCF8584 "
+ "later\n");
}
}
pci_dev_put(cy693_dev);
@@ -256,22 +256,27 @@ static int __init i2c_pcfisa_init(void)
/* sanity checks for mmapped I/O */
if (mmapped && base < 0xc8000) {
- printk(KERN_ERR "%s: incorrect base address (%#x) specified "
- "for mmapped I/O\n", pcf_isa_ops.name, base);
- return -ENODEV;
+ dev_err(dev, "incorrect base address (%#x) specified "
+ "for mmapped I/O\n", base);
+ return 0;
}
if (base == 0) {
base = DEFAULT_BASE;
}
+ return 1;
+}
+static int __devinit elektor_probe(struct device *dev, unsigned int id)
+{
init_waitqueue_head(&pcf_wait);
if (pcf_isa_init())
return -ENODEV;
+ pcf_isa_ops.dev.parent = dev;
if (i2c_pcf_add_bus(&pcf_isa_ops) < 0)
goto fail;
- dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base);
+ dev_info(dev, "found device at %#x\n", base);
return 0;
@@ -291,7 +296,7 @@ static int __init i2c_pcfisa_init(void)
return -ENODEV;
}
-static void i2c_pcfisa_exit(void)
+static int __devexit elektor_remove(struct device *dev, unsigned int id)
{
i2c_del_adapter(&pcf_isa_ops);
@@ -307,6 +312,28 @@ static void i2c_pcfisa_exit(void)
iounmap(base_iomem);
release_mem_region(base, 2);
}
+
+ return 0;
+}
+
+static struct isa_driver i2c_elektor_driver = {
+ .match = elektor_match,
+ .probe = elektor_probe,
+ .remove = __devexit_p(elektor_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-elektor",
+ },
+};
+
+static int __init i2c_pcfisa_init(void)
+{
+ return isa_register_driver(&i2c_elektor_driver, 1);
+}
+
+static void __exit i2c_pcfisa_exit(void)
+{
+ isa_unregister_driver(&i2c_elektor_driver);
}
MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
new file mode 100644
index 00000000000..a7dd54654a9
--- /dev/null
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -0,0 +1,215 @@
+/*
+ * Bitbanging I2C bus driver using the GPIO API
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/gpio.h>
+
+/* Toggle SDA by changing the direction of the pin */
+static void i2c_gpio_setsda_dir(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ if (state)
+ gpio_direction_input(pdata->sda_pin);
+ else
+ gpio_direction_output(pdata->sda_pin, 0);
+}
+
+/*
+ * Toggle SDA by changing the output value of the pin. This is only
+ * valid for pins configured as open drain (i.e. setting the value
+ * high effectively turns off the output driver.)
+ */
+static void i2c_gpio_setsda_val(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->sda_pin, state);
+}
+
+/* Toggle SCL by changing the direction of the pin. */
+static void i2c_gpio_setscl_dir(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ if (state)
+ gpio_direction_input(pdata->scl_pin);
+ else
+ gpio_direction_output(pdata->scl_pin, 0);
+}
+
+/*
+ * Toggle SCL by changing the output value of the pin. This is used
+ * for pins that are configured as open drain and for output-only
+ * pins. The latter case will break the i2c protocol, but it will
+ * often work in practice.
+ */
+static void i2c_gpio_setscl_val(void *data, int state)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ gpio_set_value(pdata->scl_pin, state);
+}
+
+int i2c_gpio_getsda(void *data)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->sda_pin);
+}
+
+int i2c_gpio_getscl(void *data)
+{
+ struct i2c_gpio_platform_data *pdata = data;
+
+ return gpio_get_value(pdata->scl_pin);
+}
+
+static int __init i2c_gpio_probe(struct platform_device *pdev)
+{
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_algo_bit_data *bit_data;
+ struct i2c_adapter *adap;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENXIO;
+
+ ret = -ENOMEM;
+ adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
+ if (!adap)
+ goto err_alloc_adap;
+ bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL);
+ if (!bit_data)
+ goto err_alloc_bit_data;
+
+ ret = gpio_request(pdata->sda_pin, "sda");
+ if (ret)
+ goto err_request_sda;
+ ret = gpio_request(pdata->scl_pin, "scl");
+ if (ret)
+ goto err_request_scl;
+
+ if (pdata->sda_is_open_drain) {
+ gpio_direction_output(pdata->sda_pin, 1);
+ bit_data->setsda = i2c_gpio_setsda_val;
+ } else {
+ gpio_direction_input(pdata->sda_pin);
+ bit_data->setsda = i2c_gpio_setsda_dir;
+ }
+
+ if (pdata->scl_is_open_drain || pdata->scl_is_output_only) {
+ gpio_direction_output(pdata->scl_pin, 1);
+ bit_data->setscl = i2c_gpio_setscl_val;
+ } else {
+ gpio_direction_input(pdata->scl_pin);
+ bit_data->setscl = i2c_gpio_setscl_dir;
+ }
+
+ if (!pdata->scl_is_output_only)
+ bit_data->getscl = i2c_gpio_getscl;
+ bit_data->getsda = i2c_gpio_getsda;
+
+ if (pdata->udelay)
+ bit_data->udelay = pdata->udelay;
+ else if (pdata->scl_is_output_only)
+ bit_data->udelay = 50; /* 10 kHz */
+ else
+ bit_data->udelay = 5; /* 100 kHz */
+
+ if (pdata->timeout)
+ bit_data->timeout = pdata->timeout;
+ else
+ bit_data->timeout = HZ / 10; /* 100 ms */
+
+ bit_data->data = pdata;
+
+ adap->owner = THIS_MODULE;
+ snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id);
+ adap->algo_data = bit_data;
+ adap->dev.parent = &pdev->dev;
+
+ ret = i2c_bit_add_bus(adap);
+ if (ret)
+ goto err_add_bus;
+
+ platform_set_drvdata(pdev, adap);
+
+ dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n",
+ pdata->sda_pin, pdata->scl_pin,
+ pdata->scl_is_output_only
+ ? ", no clock stretching" : "");
+
+ return 0;
+
+err_add_bus:
+ gpio_free(pdata->scl_pin);
+err_request_scl:
+ gpio_free(pdata->sda_pin);
+err_request_sda:
+ kfree(bit_data);
+err_alloc_bit_data:
+ kfree(adap);
+err_alloc_adap:
+ return ret;
+}
+
+static int __exit i2c_gpio_remove(struct platform_device *pdev)
+{
+ struct i2c_gpio_platform_data *pdata;
+ struct i2c_adapter *adap;
+
+ adap = platform_get_drvdata(pdev);
+ pdata = pdev->dev.platform_data;
+
+ i2c_del_adapter(adap);
+ gpio_free(pdata->scl_pin);
+ gpio_free(pdata->sda_pin);
+ kfree(adap->algo_data);
+ kfree(adap);
+
+ return 0;
+}
+
+static struct platform_driver i2c_gpio_driver = {
+ .driver = {
+ .name = "i2c-gpio",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(i2c_gpio_remove),
+};
+
+static int __init i2c_gpio_init(void)
+{
+ int ret;
+
+ ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe);
+ if (ret)
+ printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret);
+
+ return ret;
+}
+module_init(i2c_gpio_init);
+
+static void __exit i2c_gpio_exit(void)
+{
+ platform_driver_unregister(&i2c_gpio_driver);
+}
+module_exit(i2c_gpio_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index a320e7d82c1..611b57192c9 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -527,7 +527,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
/* set up the sysfs linkage to our parent device */
i801_adapter.dev.parent = &dev->dev;
- snprintf(i801_adapter.name, I2C_NAME_SIZE,
+ snprintf(i801_adapter.name, sizeof(i801_adapter.name),
"SMBus I801 adapter at %04lx", i801_smba);
err = i2c_add_adapter(&i801_adapter);
if (err) {
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index 5f33bc9c1e0..b0e1370075d 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -41,6 +41,10 @@
#include <linux/platform_device.h>
#include <linux/completion.h>
+/* Exported by i2c-core for i2c-isa only */
+extern void i2c_adapter_dev_release(struct device *dev);
+extern struct class i2c_adapter_class;
+
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
@@ -64,16 +68,6 @@ static u32 isa_func(struct i2c_adapter *adapter)
}
-/* Copied from i2c-core */
-static ssize_t show_adapter_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
- return sprintf(buf, "%s\n", adap->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
-
-
/* We implement an interface which resembles i2c_{add,del}_driver,
but for i2c-isa drivers. We don't have to remember and handle lists
of drivers and adapters so this is much more simple, of course. */
@@ -139,41 +133,18 @@ static int __init i2c_isa_init(void)
isa_adapter.nr = ANY_I2C_ISA_BUS;
isa_adapter.dev.parent = &platform_bus;
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
- isa_adapter.dev.driver = &i2c_adapter_driver;
isa_adapter.dev.release = &i2c_adapter_dev_release;
+ isa_adapter.dev.class = &i2c_adapter_class;
err = device_register(&isa_adapter.dev);
if (err) {
printk(KERN_ERR "i2c-isa: Failed to register device\n");
goto exit;
}
- err = device_create_file(&isa_adapter.dev, &dev_attr_name);
- if (err) {
- printk(KERN_ERR "i2c-isa: Failed to create name file\n");
- goto exit_unregister;
- }
-
- /* Add this adapter to the i2c_adapter class */
- memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
- isa_adapter.class_dev.dev = &isa_adapter.dev;
- isa_adapter.class_dev.class = &i2c_adapter_class;
- strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
- BUS_ID_SIZE);
- err = class_device_register(&isa_adapter.class_dev);
- if (err) {
- printk(KERN_ERR "i2c-isa: Failed to register class device\n");
- goto exit_remove_name;
- }
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
return 0;
-exit_remove_name:
- device_remove_file(&isa_adapter.dev, &dev_attr_name);
-exit_unregister:
- init_completion(&isa_adapter.dev_released); /* Needed? */
- device_unregister(&isa_adapter.dev);
- wait_for_completion(&isa_adapter.dev_released);
exit:
return err;
}
@@ -201,15 +172,11 @@ static void __exit i2c_isa_exit(void)
/* Clean up the sysfs representation */
dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
init_completion(&isa_adapter.dev_released);
- init_completion(&isa_adapter.class_dev_released);
- class_device_unregister(&isa_adapter.class_dev);
- device_remove_file(&isa_adapter.dev, &dev_attr_name);
device_unregister(&isa_adapter.dev);
/* Wait for sysfs to drop all references */
dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
wait_for_completion(&isa_adapter.dev_released);
- wait_for_completion(&isa_adapter.class_dev_released);
dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
}
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index efa3ecc5522..6352121a282 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -118,7 +118,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
drv_data->adapter.id = I2C_HW_B_IXP2000,
strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
- I2C_NAME_SIZE);
+ sizeof(drv_data->adapter.name));
drv_data->adapter.algo_data = &drv_data->algo_data,
drv_data->adapter.dev.parent = &plat_dev->dev;
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 08e89b83984..069ed7f3b39 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -127,7 +127,7 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
drv_data->adapter.id = I2C_HW_B_IXP4XX;
drv_data->adapter.class = I2C_CLASS_HWMON;
strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
- I2C_NAME_SIZE);
+ sizeof(drv_data->adapter.name));
drv_data->adapter.algo_data = &drv_data->algo_data;
drv_data->adapter.dev.parent = &plat_dev->dev;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index ee65aa1be13..c6b6898592b 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/platform_device.h>
#include <asm/io.h>
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index a3283b907eb..a55b3335d1b 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -508,7 +508,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
}
strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter",
- I2C_NAME_SIZE);
+ sizeof(drv_data->adapter.name));
init_waitqueue_head(&drv_data->waitq);
spin_lock_init(&drv_data->lock);
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 1514ec5b77f..3cd0d63e7b5 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -33,6 +33,8 @@
nForce4 MCP-04 0034
nForce4 MCP51 0264
nForce4 MCP55 0368
+ nForce MCP61 03EB
+ nForce MCP65 0446
This driver supports the 2 SMBuses that are included in the MCP of the
nForce2/3/4/5xx chipsets.
@@ -200,6 +202,8 @@ static struct pci_device_id nforce2_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
{ 0 }
};
@@ -240,7 +244,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar,
smbus->adapter.algo = &smbus_algorithm;
smbus->adapter.algo_data = smbus;
smbus->adapter.dev.parent = &dev->dev;
- snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
"SMBus nForce2 adapter at %04x", smbus->base);
error = i2c_add_adapter(&smbus->adapter);
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index bcd8367cede..e471e3bfdc1 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -605,7 +605,8 @@ omap_i2c_probe(struct platform_device *pdev)
adap->dev.parent = &pdev->dev;
/* i2c device drivers may be active on return from add_adapter() */
- r = i2c_add_adapter(adap);
+ adap->nr = pdev->id;
+ r = i2c_add_numbered_adapter(adap);
if (r) {
dev_err(dev->dev, "failure adding adapter\n");
goto err_free_irq;
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index 4bc42810b9a..49a95e2887b 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
- * i2c-parport.c I2C bus over parallel port *
+ * i2c-parport-light.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
Based on older i2c-velleman.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
@@ -34,6 +35,9 @@
#include "i2c-parport.h"
#define DEFAULT_BASE 0x378
+#define DRVNAME "i2c-parport-light"
+
+static struct platform_device *pdev;
static u16 base;
module_param(base, ushort, 0);
@@ -106,7 +110,7 @@ static struct i2c_algo_bit_data parport_algo_data = {
.timeout = HZ,
};
-/* ----- I2c structure ---------------------------------------------------- */
+/* ----- Driver registration ---------------------------------------------- */
static struct i2c_adapter parport_adapter = {
.owner = THIS_MODULE,
@@ -116,55 +120,141 @@ static struct i2c_adapter parport_adapter = {
.name = "Parallel port adapter (light)",
};
-/* ----- Module loading, unloading and information ------------------------ */
+static int __devinit i2c_parport_probe(struct platform_device *pdev)
+{
+ int err;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
+ return -EBUSY;
+
+ /* Reset hardware to a sane state (SCL and SDA high) */
+ parport_setsda(NULL, 1);
+ parport_setscl(NULL, 1);
+ /* Other init if needed (power on...) */
+ if (adapter_parm[type].init.val)
+ line_set(1, &adapter_parm[type].init);
+
+ parport_adapter.dev.parent = &pdev->dev;
+ err = i2c_bit_add_bus(&parport_adapter);
+ if (err) {
+ dev_err(&pdev->dev, "Unable to register with I2C\n");
+ goto exit_region;
+ }
+ return 0;
+
+exit_region:
+ release_region(res->start, res->end - res->start + 1);
+ return err;
+}
+
+static int __devexit i2c_parport_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ i2c_del_adapter(&parport_adapter);
+
+ /* Un-init if needed (power off...) */
+ if (adapter_parm[type].init.val)
+ line_set(0, &adapter_parm[type].init);
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ release_region(res->start, res->end - res->start + 1);
+ return 0;
+}
+
+static struct platform_driver i2c_parport_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = i2c_parport_probe,
+ .remove = __devexit_p(i2c_parport_remove),
+};
+
+static int __init i2c_parport_device_add(u16 address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + 2,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, -1);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
static int __init i2c_parport_init(void)
{
+ int err;
+
if (type < 0) {
- printk(KERN_WARNING "i2c-parport: adapter type unspecified\n");
+ printk(KERN_ERR DRVNAME ": adapter type unspecified\n");
return -ENODEV;
}
if (type >= ARRAY_SIZE(adapter_parm)) {
- printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type);
+ printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type);
return -ENODEV;
}
if (base == 0) {
- printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE);
+ pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE);
base = DEFAULT_BASE;
}
- if (!request_region(base, 3, "i2c-parport"))
- return -ENODEV;
-
if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
- /* Reset hardware to a sane state (SCL and SDA high) */
- parport_setsda(NULL, 1);
- parport_setscl(NULL, 1);
- /* Other init if needed (power on...) */
- if (adapter_parm[type].init.val)
- line_set(1, &adapter_parm[type].init);
+ /* Sets global pdev as a side effect */
+ err = i2c_parport_device_add(base);
+ if (err)
+ goto exit;
- if (i2c_bit_add_bus(&parport_adapter) < 0) {
- printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
- release_region(base, 3);
- return -ENODEV;
- }
+ err = platform_driver_register(&i2c_parport_driver);
+ if (err)
+ goto exit_device;
return 0;
+
+exit_device:
+ platform_device_unregister(pdev);
+exit:
+ return err;
}
static void __exit i2c_parport_exit(void)
{
- /* Un-init if needed (power off...) */
- if (adapter_parm[type].init.val)
- line_set(0, &adapter_parm[type].init);
-
- i2c_del_adapter(&parport_adapter);
- release_region(base, 3);
+ platform_driver_unregister(&i2c_parport_driver);
+ platform_device_unregister(pdev);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 66696a40c7b..039a07fde90 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -1,7 +1,7 @@
/* ------------------------------------------------------------------------ *
* i2c-parport.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
- Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org>
Based on older i2c-philips-par.c driver
Copyright (C) 1995-2000 Simon G. Vogl
@@ -137,19 +137,12 @@ static struct i2c_algo_bit_data parport_algo_data = {
.setscl = parport_setscl,
.getsda = parport_getsda,
.getscl = parport_getscl,
- .udelay = 60,
+ .udelay = 10, /* ~50 kbps */
.timeout = HZ,
};
/* ----- I2c and parallel port call-back functions and structures --------- */
-static struct i2c_adapter parport_adapter = {
- .owner = THIS_MODULE,
- .class = I2C_CLASS_HWMON,
- .id = I2C_HW_B_LP,
- .name = "Parallel port adapter",
-};
-
static void i2c_parport_attach (struct parport *port)
{
struct i2c_par *adapter;
@@ -169,12 +162,20 @@ static void i2c_parport_attach (struct parport *port)
}
/* Fill the rest of the structure */
- adapter->adapter = parport_adapter;
+ adapter->adapter.owner = THIS_MODULE;
+ adapter->adapter.class = I2C_CLASS_HWMON;
+ adapter->adapter.id = I2C_HW_B_LP;
+ strlcpy(adapter->adapter.name, "Parallel port adapter",
+ sizeof(adapter->adapter.name));
adapter->algo_data = parport_algo_data;
- if (!adapter_parm[type].getscl.val)
+ /* Slow down if we can't sense SCL */
+ if (!adapter_parm[type].getscl.val) {
adapter->algo_data.getscl = NULL;
+ adapter->algo_data.udelay = 50; /* ~10 kbps */
+ }
adapter->algo_data.data = port;
adapter->adapter.algo_data = &adapter->algo_data;
+ adapter->adapter.dev.parent = port->physport->dev;
if (parport_claim_or_block(adapter->pdev) < 0) {
printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
@@ -214,11 +215,12 @@ static void i2c_parport_detach (struct parport *port)
for (prev = NULL, adapter = adapter_list; adapter;
prev = adapter, adapter = adapter->next) {
if (adapter->pdev->port == port) {
+ i2c_del_adapter(&adapter->adapter);
+
/* Un-init if needed (power off...) */
if (adapter_parm[type].init.val)
line_set(port, 0, &adapter_parm[type].init);
- i2c_del_adapter(&adapter->adapter);
parport_unregister_device(adapter->pdev);
if (prev)
prev->next = adapter->next;
diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c
index bf89eeef74e..58e32714afb 100644
--- a/drivers/i2c/busses/i2c-pasemi.c
+++ b/drivers/i2c/busses/i2c-pasemi.c
@@ -358,7 +358,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev,
}
smbus->adapter.owner = THIS_MODULE;
- snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+ snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
"PA Semi SMBus adapter at 0x%lx", smbus->base);
smbus->adapter.class = I2C_CLASS_HWMON;
smbus->adapter.algo = &smbus_algorithm;
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index cc6536a19ec..5161aaf9341 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -25,9 +25,9 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/wait.h>
+#include <linux/isa.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-pca.h>
@@ -119,27 +119,26 @@ static struct i2c_adapter pca_isa_ops = {
.name = "PCA9564 ISA Adapter",
};
-static int __init pca_isa_init(void)
+static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
{
-
init_waitqueue_head(&pca_wait);
- printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq);
+ dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
if (!request_region(base, IO_SIZE, "i2c-pca-isa")) {
- printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base);
+ dev_err(dev, "I/O address %#08lx is in use\n", base);
goto out;
}
if (irq > -1) {
if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) {
- printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq);
+ dev_err(dev, "Request irq%d failed\n", irq);
goto out_region;
}
}
if (i2c_pca_add_bus(&pca_isa_ops) < 0) {
- printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n");
+ dev_err(dev, "Failed to add i2c bus\n");
goto out_irq;
}
@@ -154,7 +153,7 @@ static int __init pca_isa_init(void)
return -ENODEV;
}
-static void pca_isa_exit(void)
+static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
{
i2c_del_adapter(&pca_isa_ops);
@@ -163,6 +162,27 @@ static void pca_isa_exit(void)
free_irq(irq, &pca_isa_ops);
}
release_region(base, IO_SIZE);
+
+ return 0;
+}
+
+static struct isa_driver pca_isa_driver = {
+ .probe = pca_isa_probe,
+ .remove = __devexit_p(pca_isa_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "i2c-pca-isa",
+ }
+};
+
+static int __init pca_isa_init(void)
+{
+ return isa_register_driver(&pca_isa_driver, 1);
+}
+
+static void __exit pca_isa_exit(void)
+{
+ isa_unregister_driver(&pca_isa_driver);
}
MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>");
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 21b18090408..5a52bf5e3fb 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -428,7 +428,7 @@ static int __devinit piix4_probe(struct pci_dev *dev,
/* set up the sysfs linkage to our parent device */
piix4_adapter.dev.parent = &dev->dev;
- snprintf(piix4_adapter.name, I2C_NAME_SIZE,
+ snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
"SMBus PIIX4 adapter at %04x", piix4_smba);
if ((retval = i2c_add_adapter(&piix4_adapter))) {
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 14e83d0aac8..873544ab598 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -539,6 +539,18 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c)
writel(icr | ICR_START | ICR_TB, _ICR(i2c));
}
+static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c)
+{
+ u32 icr;
+
+ /*
+ * Clear the STOP and ACK flags
+ */
+ icr = readl(_ICR(i2c));
+ icr &= ~(ICR_STOP | ICR_ACKNAK);
+ writel(icr, _IRC(i2c));
+}
+
/*
* We are protected by the adapter bus mutex.
*/
@@ -581,6 +593,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num)
* The rest of the processing occurs in the interrupt handler.
*/
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
+ i2c_pxa_stop_message(i2c);
/*
* We place the return code in i2c->msg_idx.
@@ -825,7 +838,7 @@ static const struct i2c_algorithm i2c_pxa_algorithm = {
};
static struct pxa_i2c i2c_pxa = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(i2c_pxa.lock),
.adap = {
.owner = THIS_MODULE,
.algo = &i2c_pxa_algorithm,
@@ -839,9 +852,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
{
struct pxa_i2c *i2c = &i2c_pxa;
struct resource *res;
-#ifdef CONFIG_I2C_PXA_SLAVE
struct i2c_pxa_platform_data *plat = dev->dev.platform_data;
-#endif
int ret;
int irq;
@@ -889,14 +900,14 @@ static int i2c_pxa_probe(struct platform_device *dev)
pxa_gpio_mode(GPIO117_I2CSCL_MD);
pxa_gpio_mode(GPIO118_I2CSDA_MD);
#endif
- pxa_set_cken(CKEN14_I2C, 1);
+ pxa_set_cken(CKEN_I2C, 1);
break;
#ifdef CONFIG_PXA27x
case 1:
local_irq_disable();
PCFR |= PCFR_PI2CEN;
local_irq_enable();
- pxa_set_cken(CKEN15_PWRI2C, 1);
+ pxa_set_cken(CKEN_PWRI2C, 1);
#endif
}
@@ -911,6 +922,10 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.algo_data = i2c;
i2c->adap.dev.parent = &dev->dev;
+ if (plat) {
+ i2c->adap.class = plat->class;
+ }
+
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n");
@@ -933,11 +948,11 @@ eadapt:
ereqirq:
switch (dev->id) {
case 0:
- pxa_set_cken(CKEN14_I2C, 0);
+ pxa_set_cken(CKEN_I2C, 0);
break;
#ifdef CONFIG_PXA27x
case 1:
- pxa_set_cken(CKEN15_PWRI2C, 0);
+ pxa_set_cken(CKEN_PWRI2C, 0);
local_irq_disable();
PCFR &= ~PCFR_PI2CEN;
local_irq_enable();
@@ -960,11 +975,11 @@ static int i2c_pxa_remove(struct platform_device *dev)
free_irq(i2c->irq, i2c);
switch (dev->id) {
case 0:
- pxa_set_cken(CKEN14_I2C, 0);
+ pxa_set_cken(CKEN_I2C, 0);
break;
#ifdef CONFIG_PXA27x
case 1:
- pxa_set_cken(CKEN15_PWRI2C, 0);
+ pxa_set_cken(CKEN_PWRI2C, 0);
local_irq_disable();
PCFR &= ~PCFR_PI2CEN;
local_irq_enable();
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 556f244aae7..e68a96f589f 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -61,6 +61,8 @@ struct s3c24xx_i2c {
unsigned int msg_idx;
unsigned int msg_ptr;
+ unsigned int tx_setup;
+
enum s3c24xx_i2c_state state;
void __iomem *regs;
@@ -199,8 +201,11 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
writeb(addr, i2c->regs + S3C2410_IICDS);
- // delay a bit and reset iiccon before setting start (per samsung)
- udelay(1);
+ /* delay here to ensure the data byte has gotten onto the bus
+ * before the transaction is started */
+
+ ndelay(i2c->tx_setup);
+
dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
writel(iiccon, i2c->regs + S3C2410_IICCON);
@@ -322,7 +327,15 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
writeb(byte, i2c->regs + S3C2410_IICDS);
-
+
+ /* delay after writing the byte to allow the
+ * data setup time on the bus, as writing the
+ * data to the register causes the first bit
+ * to appear on SDA, and SCL will change as
+ * soon as the interrupt is acknowledged */
+
+ ndelay(i2c->tx_setup);
+
} else if (!is_lastmsg(i2c)) {
/* we need to go to the next i2c message */
@@ -570,9 +583,10 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
};
static struct s3c24xx_i2c s3c24xx_i2c = {
- .lock = SPIN_LOCK_UNLOCKED,
- .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
- .adap = {
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
+ .tx_setup = 50,
+ .adap = {
.name = "s3c2410-i2c",
.owner = THIS_MODULE,
.algo = &s3c24xx_i2c_algorithm,
@@ -731,26 +745,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
return 0;
}
-static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c)
-{
- if (i2c->clk != NULL && !IS_ERR(i2c->clk)) {
- clk_disable(i2c->clk);
- clk_put(i2c->clk);
- i2c->clk = NULL;
- }
-
- if (i2c->regs != NULL) {
- iounmap(i2c->regs);
- i2c->regs = NULL;
- }
-
- if (i2c->ioarea != NULL) {
- release_resource(i2c->ioarea);
- kfree(i2c->ioarea);
- i2c->ioarea = NULL;
- }
-}
-
/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
@@ -769,7 +763,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (IS_ERR(i2c->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = -ENOENT;
- goto out;
+ goto err_noclk;
}
dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk);
@@ -782,7 +776,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IO resource\n");
ret = -ENOENT;
- goto out;
+ goto err_clk;
}
i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
@@ -791,7 +785,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (i2c->ioarea == NULL) {
dev_err(&pdev->dev, "cannot request IO\n");
ret = -ENXIO;
- goto out;
+ goto err_clk;
}
i2c->regs = ioremap(res->start, (res->end-res->start)+1);
@@ -799,7 +793,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (i2c->regs == NULL) {
dev_err(&pdev->dev, "cannot map IO\n");
ret = -ENXIO;
- goto out;
+ goto err_ioarea;
}
dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
@@ -813,7 +807,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
ret = s3c24xx_i2c_init(i2c);
if (ret != 0)
- goto out;
+ goto err_iomap;
/* find the IRQ for this unit (note, this relies on the init call to
* ensure no current IRQs pending
@@ -823,7 +817,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (res == NULL) {
dev_err(&pdev->dev, "cannot find IRQ\n");
ret = -ENOENT;
- goto out;
+ goto err_iomap;
}
ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
@@ -831,7 +825,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ\n");
- goto out;
+ goto err_iomap;
}
i2c->irq = res;
@@ -841,17 +835,29 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
- goto out;
+ goto err_irq;
}
platform_set_drvdata(pdev, i2c);
dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id);
+ return 0;
- out:
- if (ret < 0)
- s3c24xx_i2c_free(i2c);
+ err_irq:
+ free_irq(i2c->irq->start, i2c);
+
+ err_iomap:
+ iounmap(i2c->regs);
+ err_ioarea:
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
+
+ err_clk:
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ err_noclk:
return ret;
}
@@ -863,11 +869,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
static int s3c24xx_i2c_remove(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
-
- if (i2c != NULL) {
- s3c24xx_i2c_free(i2c);
- platform_set_drvdata(pdev, NULL);
- }
+
+ i2c_del_adapter(&i2c->adap);
+ free_irq(i2c->irq->start, i2c);
+
+ clk_disable(i2c->clk);
+ clk_put(i2c->clk);
+
+ iounmap(i2c->regs);
+
+ release_resource(i2c->ioarea);
+ kfree(i2c->ioarea);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c
new file mode 100644
index 00000000000..10af8d31e12
--- /dev/null
+++ b/drivers/i2c/busses/i2c-simtec.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Simtec Generic I2C Controller
+ *
+ * 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
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+struct simtec_i2c_data {
+ struct resource *ioarea;
+ void __iomem *reg;
+ struct i2c_adapter adap;
+ struct i2c_algo_bit_data bit;
+};
+
+#define CMD_SET_SDA (1<<2)
+#define CMD_SET_SCL (1<<3)
+
+#define STATE_SDA (1<<0)
+#define STATE_SCL (1<<1)
+
+/* i2c bit-bus functions */
+
+static void simtec_i2c_setsda(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
+}
+
+static void simtec_i2c_setscl(void *pw, int state)
+{
+ struct simtec_i2c_data *pd = pw;
+ writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
+}
+
+static int simtec_i2c_getsda(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SDA ? 1 : 0;
+}
+
+static int simtec_i2c_getscl(void *pw)
+{
+ struct simtec_i2c_data *pd = pw;
+ return readb(pd->reg) & STATE_SCL ? 1 : 0;
+}
+
+/* device registration */
+
+static int simtec_i2c_probe(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd;
+ struct resource *res;
+ int size;
+ int ret;
+
+ pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
+ if (pd == NULL) {
+ dev_err(&dev->dev, "cannot allocate private data\n");
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(dev, pd);
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&dev->dev, "cannot find IO resource\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ size = (res->end-res->start)+1;
+
+ pd->ioarea = request_mem_region(res->start, size, dev->name);
+ if (pd->ioarea == NULL) {
+ dev_err(&dev->dev, "cannot request IO\n");
+ ret = -ENXIO;
+ goto err;
+ }
+
+ pd->reg = ioremap(res->start, size);
+ if (pd->reg == NULL) {
+ dev_err(&dev->dev, "cannot map IO\n");
+ ret = -ENXIO;
+ goto err_res;
+ }
+
+ /* setup the private data */
+
+ pd->adap.owner = THIS_MODULE;
+ pd->adap.algo_data = &pd->bit;
+ pd->adap.dev.parent = &dev->dev;
+
+ strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
+
+ pd->bit.data = pd;
+ pd->bit.setsda = simtec_i2c_setsda;
+ pd->bit.setscl = simtec_i2c_setscl;
+ pd->bit.getsda = simtec_i2c_getsda;
+ pd->bit.getscl = simtec_i2c_getscl;
+ pd->bit.timeout = HZ;
+ pd->bit.udelay = 20;
+
+ ret = i2c_bit_add_bus(&pd->adap);
+ if (ret)
+ goto err_all;
+
+ return 0;
+
+ err_all:
+ iounmap(pd->reg);
+
+ err_res:
+ release_resource(pd->ioarea);
+ kfree(pd->ioarea);
+
+ err:
+ kfree(pd);
+ return ret;
+}
+
+static int simtec_i2c_remove(struct platform_device *dev)
+{
+ struct simtec_i2c_data *pd = platform_get_drvdata(dev);
+
+ i2c_del_adapter(&pd->adap);
+
+ iounmap(pd->reg);
+ release_resource(pd->ioarea);
+ kfree(pd->ioarea);
+ kfree(pd);
+
+ return 0;
+}
+
+
+/* device driver */
+
+static struct platform_driver simtec_i2c_driver = {
+ .driver = {
+ .name = "simtec-i2c",
+ .owner = THIS_MODULE,
+ },
+ .probe = simtec_i2c_probe,
+ .remove = simtec_i2c_remove,
+};
+
+static int __init i2c_adap_simtec_init(void)
+{
+ return platform_driver_register(&simtec_i2c_driver);
+}
+
+static void __exit i2c_adap_simtec_exit(void)
+{
+ platform_driver_unregister(&simtec_i2c_driver);
+}
+
+module_init(i2c_adap_simtec_init);
+module_exit(i2c_adap_simtec_exit);
+
+MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 4157b0cd604..dc235bb8e24 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -300,7 +300,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev,
/* set up the sysfs linkage to our parent device */
sis96x_adapter.dev.parent = &dev->dev;
- snprintf(sis96x_adapter.name, I2C_NAME_SIZE,
+ snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name),
"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
if ((retval = i2c_add_adapter(&sis96x_adapter))) {
diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c
new file mode 100644
index 00000000000..907999049d5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-tiny-usb.c
@@ -0,0 +1,277 @@
+/*
+ * driver for the i2c-tiny-usb adapter - 1.0
+ * http://www.harbaum.org/till/i2c_tiny_usb
+ *
+ * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.org)
+ *
+ * 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, version 2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+
+/* include interfaces to usb layer */
+#include <linux/usb.h>
+
+/* include interface to i2c layer */
+#include <linux/i2c.h>
+
+/* commands via USB, must match command ids in the firmware */
+#define CMD_ECHO 0
+#define CMD_GET_FUNC 1
+#define CMD_SET_DELAY 2
+#define CMD_GET_STATUS 3
+
+#define CMD_I2C_IO 4
+#define CMD_I2C_IO_BEGIN (1<<0)
+#define CMD_I2C_IO_END (1<<1)
+
+/* i2c bit delay, default is 10us -> 100kHz */
+static int delay = 10;
+module_param(delay, int, 0);
+MODULE_PARM_DESC(delay, "bit delay in microseconds, "
+ "e.g. 10 for 100kHz (default is 100kHz)");
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len);
+
+/* ----- begin of i2c layer ---------------------------------------------- */
+
+#define STATUS_IDLE 0
+#define STATUS_ADDRESS_ACK 1
+#define STATUS_ADDRESS_NAK 2
+
+static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
+{
+ unsigned char status;
+ struct i2c_msg *pmsg;
+ int i;
+
+ dev_dbg(&adapter->dev, "master xfer %d messages:\n", num);
+
+ for (i = 0 ; i < num ; i++) {
+ int cmd = CMD_I2C_IO;
+
+ if (i == 0)
+ cmd |= CMD_I2C_IO_BEGIN;
+
+ if (i == num-1)
+ cmd |= CMD_I2C_IO_END;
+
+ pmsg = &msgs[i];
+
+ dev_dbg(&adapter->dev,
+ " %d: %s (flags %d) %d bytes to 0x%02x\n",
+ i, pmsg->flags & I2C_M_RD ? "read" : "write",
+ pmsg->flags, pmsg->len, pmsg->addr);
+
+ /* and directly send the message */
+ if (pmsg->flags & I2C_M_RD) {
+ /* read data */
+ if (usb_read(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure reading data\n");
+ return -EREMOTEIO;
+ }
+ } else {
+ /* write data */
+ if (usb_write(adapter, cmd,
+ pmsg->flags, pmsg->addr,
+ pmsg->buf, pmsg->len) != pmsg->len) {
+ dev_err(&adapter->dev,
+ "failure writing data\n");
+ return -EREMOTEIO;
+ }
+ }
+
+ /* read status */
+ if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) {
+ dev_err(&adapter->dev, "failure reading status\n");
+ return -EREMOTEIO;
+ }
+
+ dev_dbg(&adapter->dev, " status = %d\n", status);
+ if (status == STATUS_ADDRESS_NAK)
+ return -EREMOTEIO;
+ }
+
+ return i;
+}
+
+static u32 usb_func(struct i2c_adapter *adapter)
+{
+ u32 func;
+
+ /* get functionality from adapter */
+ if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) !=
+ sizeof(func)) {
+ dev_err(&adapter->dev, "failure reading functionality\n");
+ return 0;
+ }
+
+ return func;
+}
+
+/* This is the actual algorithm we define */
+static const struct i2c_algorithm usb_algorithm = {
+ .master_xfer = usb_xfer,
+ .functionality = usb_func,
+};
+
+/* ----- end of i2c layer ------------------------------------------------ */
+
+/* ----- begin of usb layer ---------------------------------------------- */
+
+/* The usb i2c interface uses a vid/pid pair donated by */
+/* Future Technology Devices International Ltd. */
+static struct usb_device_id i2c_tiny_usb_table [] = {
+ { USB_DEVICE(0x0403, 0xc631) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table);
+
+/* Structure to hold all of our device specific stuff */
+struct i2c_tiny_usb {
+ struct usb_device *usb_dev; /* the usb device for this device */
+ struct usb_interface *interface; /* the interface for this device */
+ struct i2c_adapter adapter; /* i2c related things */
+};
+
+static int usb_read(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+ /* do control transfer */
+ return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE |
+ USB_DIR_IN, value, index, data, len, 2000);
+}
+
+static int usb_write(struct i2c_adapter *adapter, int cmd,
+ int value, int index, void *data, int len)
+{
+ struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data;
+
+ /* do control transfer */
+ return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0),
+ cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ value, index, data, len, 2000);
+}
+
+static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev)
+{
+ usb_put_dev(dev->usb_dev);
+ kfree(dev);
+}
+
+static int i2c_tiny_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct i2c_tiny_usb *dev;
+ int retval = -ENOMEM;
+ u16 version;
+
+ dev_dbg(&interface->dev, "probing usb device\n");
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ goto error;
+ }
+
+ dev->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dev->interface = interface;
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice);
+ dev_info(&interface->dev,
+ "version %x.%02x found at bus %03d address %03d\n",
+ version >> 8, version & 0xff,
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ /* setup i2c adapter description */
+ dev->adapter.owner = THIS_MODULE;
+ dev->adapter.class = I2C_CLASS_HWMON;
+ dev->adapter.algo = &usb_algorithm;
+ dev->adapter.algo_data = dev;
+ snprintf(dev->adapter.name, I2C_NAME_SIZE,
+ "i2c-tiny-usb at bus %03d device %03d",
+ dev->usb_dev->bus->busnum, dev->usb_dev->devnum);
+
+ if (usb_write(&dev->adapter, CMD_SET_DELAY,
+ cpu_to_le16(delay), 0, NULL, 0) != 0) {
+ dev_err(&dev->adapter.dev,
+ "failure setting delay to %dus\n", delay);
+ retval = -EIO;
+ goto error;
+ }
+
+ dev->adapter.dev.parent = &dev->interface->dev;
+
+ /* and finally attach to i2c layer */
+ i2c_add_adapter(&dev->adapter);
+
+ /* inform user about successful attachment to i2c layer */
+ dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n");
+
+ return 0;
+
+ error:
+ if (dev)
+ i2c_tiny_usb_free(dev);
+
+ return retval;
+}
+
+static void i2c_tiny_usb_disconnect(struct usb_interface *interface)
+{
+ struct i2c_tiny_usb *dev = usb_get_intfdata(interface);
+
+ i2c_del_adapter(&dev->adapter);
+ usb_set_intfdata(interface, NULL);
+ i2c_tiny_usb_free(dev);
+
+ dev_dbg(&interface->dev, "disconnected\n");
+}
+
+static struct usb_driver i2c_tiny_usb_driver = {
+ .name = "i2c-tiny-usb",
+ .probe = i2c_tiny_usb_probe,
+ .disconnect = i2c_tiny_usb_disconnect,
+ .id_table = i2c_tiny_usb_table,
+};
+
+static int __init usb_i2c_tiny_usb_init(void)
+{
+ /* register this driver with the USB subsystem */
+ return usb_register(&i2c_tiny_usb_driver);
+}
+
+static void __exit usb_i2c_tiny_usb_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&i2c_tiny_usb_driver);
+}
+
+module_init(usb_i2c_tiny_usb_init);
+module_exit(usb_i2c_tiny_usb_exit);
+
+/* ----- end of usb layer ------------------------------------------------ */
+
+MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>");
+MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 03c5fc86854..7a2bc06304f 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -404,7 +404,7 @@ found:
}
vt596_adapter.dev.parent = &pdev->dev;
- snprintf(vt596_adapter.name, I2C_NAME_SIZE,
+ snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
"SMBus Via Pro adapter at %04x", vt596_smba);
vt596_pdev = pci_dev_get(pdev);
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 0b082c5a019..0d6bd4f7b7f 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -28,7 +28,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/i2c.h>
-#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -441,7 +440,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
adapter = &iface->adapter;
i2c_set_adapdata(adapter, iface);
- snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index);
+ snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index);
adapter->owner = THIS_MODULE;
adapter->id = I2C_HW_SMBUS_SCX200;
adapter->algo = &scx200_acb_algorithm;
@@ -599,6 +598,7 @@ static __init int scx200_scan_pci(void)
else {
int i;
+ pci_dev_put(pdev);
for (i = 0; i < MAX_DEVICES; ++i) {
if (base[i] == 0)
continue;
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 87ee3ce5861..ea085a006ea 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -3,11 +3,10 @@
#
menu "Miscellaneous I2C Chip support"
- depends on I2C
config SENSORS_DS1337
tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
DS1337 and DS1339 real-time clock chips.
@@ -17,7 +16,7 @@ config SENSORS_DS1337
config SENSORS_DS1374
tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
DS1374 real-time clock chips.
@@ -27,7 +26,7 @@ config SENSORS_DS1374
config SENSORS_EEPROM
tristate "EEPROM reader"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get read-only access to the EEPROM data
available on modern memory DIMMs and Sony Vaio laptops. Such
@@ -38,7 +37,7 @@ config SENSORS_EEPROM
config SENSORS_PCF8574
tristate "Philips PCF8574 and PCF8574A"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
default n
help
If you say yes here you get support for Philips PCF8574 and
@@ -52,7 +51,7 @@ config SENSORS_PCF8574
config SENSORS_PCA9539
tristate "Philips PCA9539 16-bit I/O port"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get support for the Philips PCA9539
16-bit I/O port.
@@ -62,7 +61,7 @@ config SENSORS_PCA9539
config SENSORS_PCF8591
tristate "Philips PCF8591"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
default n
help
If you say yes here you get support for Philips PCF8591 chips.
@@ -75,7 +74,7 @@ config SENSORS_PCF8591
config ISP1301_OMAP
tristate "Philips ISP1301 with OMAP OTG"
- depends on I2C && ARCH_OMAP_OTG
+ depends on ARCH_OMAP_OTG
help
If you say yes here you get support for the Philips ISP1301
USB-On-The-Go transceiver working with the OMAP OTG controller.
@@ -90,7 +89,7 @@ config ISP1301_OMAP
# and having mostly OMAP-specific board support
config TPS65010
tristate "TPS6501x Power Management chips"
- depends on I2C && ARCH_OMAP
+ depends on ARCH_OMAP
default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
help
If you say yes here you get support for the TPS6501x series of
@@ -103,7 +102,7 @@ config TPS65010
config SENSORS_M41T00
tristate "ST M41T00 RTC chip"
- depends on I2C && PPC32
+ depends on PPC32
help
If you say yes here you get support for the ST M41T00 RTC chip.
@@ -112,7 +111,7 @@ config SENSORS_M41T00
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
- depends on I2C && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
If you say yes here you get support for the Maxim MAX6875
EEPROM-programmable, quad power-supply sequencer/supervisor.
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 214fbb1423c..3c3f2ebf3fc 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -351,8 +351,10 @@ static void tps65010_interrupt(struct tps65010 *tps)
#if 0
/* REVISIT: this might need its own workqueue
* plus tweaks including deadlock avoidance ...
+ * also needs to get error handling and probably
+ * an #ifdef CONFIG_SOFTWARE_SUSPEND
*/
- software_suspend();
+ hibernate();
#endif
poll = 1;
}
diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c
new file mode 100644
index 00000000000..ffb35f09df0
--- /dev/null
+++ b/drivers/i2c/i2c-boardinfo.c
@@ -0,0 +1,90 @@
+/*
+ * i2c-boardinfo.h - collect pre-declarations of I2C devices
+ *
+ * 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/kernel.h>
+#include <linux/i2c.h>
+
+#include "i2c-core.h"
+
+
+/* These symbols are exported ONLY FOR the i2c core.
+ * No other users will be supported.
+ */
+DEFINE_MUTEX(__i2c_board_lock);
+EXPORT_SYMBOL_GPL(__i2c_board_lock);
+
+LIST_HEAD(__i2c_board_list);
+EXPORT_SYMBOL_GPL(__i2c_board_list);
+
+int __i2c_first_dynamic_bus_num;
+EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num);
+
+
+/**
+ * i2c_register_board_info - statically declare I2C devices
+ * @busnum: identifies the bus to which these devices belong
+ * @info: vector of i2c device descriptors
+ * @len: how many descriptors in the vector; may be zero to reserve
+ * the specified bus number.
+ *
+ * Systems using the Linux I2C driver stack can declare tables of board info
+ * while they initialize. This should be done in board-specific init code
+ * near arch_initcall() time, or equivalent, before any I2C adapter driver is
+ * registered. For example, mainboard init code could define several devices,
+ * as could the init code for each daughtercard in a board stack.
+ *
+ * The I2C devices will be created later, after the adapter for the relevant
+ * bus has been registered. After that moment, standard driver model tools
+ * are used to bind "new style" I2C drivers to the devices. The bus number
+ * for any device declared using this routine is not available for dynamic
+ * allocation.
+ *
+ * The board info passed can safely be __initdata, but be careful of embedded
+ * pointers (for platform_data, functions, etc) since that won't be copied.
+ */
+int __init
+i2c_register_board_info(int busnum,
+ struct i2c_board_info const *info, unsigned len)
+{
+ int status;
+
+ mutex_lock(&__i2c_board_lock);
+
+ /* dynamic bus numbers will be assigned after the last static one */
+ if (busnum >= __i2c_first_dynamic_bus_num)
+ __i2c_first_dynamic_bus_num = busnum + 1;
+
+ for (status = 0; len; len--, info++) {
+ struct i2c_devinfo *devinfo;
+
+ devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL);
+ if (!devinfo) {
+ pr_debug("i2c-core: can't register boardinfo!\n");
+ status = -ENOMEM;
+ break;
+ }
+
+ devinfo->busnum = busnum;
+ devinfo->board_info = *info;
+ list_add_tail(&devinfo->list, &__i2c_board_list);
+ }
+
+ mutex_unlock(&__i2c_board_lock);
+
+ return status;
+}
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 21fe1406c8b..64f8e56d300 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -35,29 +35,92 @@
#include <linux/completion.h>
#include <asm/uaccess.h>
+#include "i2c-core.h"
+
static LIST_HEAD(adapters);
static LIST_HEAD(drivers);
static DEFINE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr);
+#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
/* ------------------------------------------------------------------------- */
-/* match always succeeds, as we want the probe() to tell if we really accept this match */
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
- return 1;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_driver *driver = to_i2c_driver(drv);
+
+ /* make legacy i2c drivers bypass driver model probing entirely;
+ * such drivers scan each i2c adapter/bus themselves.
+ */
+ if (!is_newstyle_driver(driver))
+ return 0;
+
+ /* new style drivers use the same kind of driver matching policy
+ * as platform devices or SPI: compare device and driver IDs.
+ */
+ return strcmp(client->driver_name, drv->name) == 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+
+/* uevent helps with hotplug: modprobe -q $(MODALIAS) */
+static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int i = 0, length = 0;
+
+ /* by definition, legacy drivers can't hotplug */
+ if (dev->driver || !client->driver_name)
+ return 0;
+
+ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=%s", client->driver_name))
+ return -ENOMEM;
+ envp[i] = NULL;
+ dev_dbg(dev, "uevent\n");
+ return 0;
}
+#else
+#define i2c_device_uevent NULL
+#endif /* CONFIG_HOTPLUG */
+
static int i2c_device_probe(struct device *dev)
{
- return -ENODEV;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_driver *driver = to_i2c_driver(dev->driver);
+
+ if (!driver->probe)
+ return -ENODEV;
+ client->driver = driver;
+ dev_dbg(dev, "probe\n");
+ return driver->probe(client);
}
static int i2c_device_remove(struct device *dev)
{
- return 0;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_driver *driver;
+ int status;
+
+ if (!dev->driver)
+ return 0;
+
+ driver = to_i2c_driver(dev->driver);
+ if (driver->remove) {
+ dev_dbg(dev, "remove\n");
+ status = driver->remove(client);
+ } else {
+ dev->driver = NULL;
+ status = 0;
+ }
+ if (status == 0)
+ client->driver = NULL;
+ return status;
}
static void i2c_device_shutdown(struct device *dev)
@@ -95,122 +158,184 @@ static int i2c_device_resume(struct device * dev)
return driver->resume(to_i2c_client(dev));
}
+static void i2c_client_release(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ complete(&client->released);
+}
+
+static void i2c_client_dev_release(struct device *dev)
+{
+ kfree(to_i2c_client(dev));
+}
+
+static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return sprintf(buf, "%s\n", client->name);
+}
+
+static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ return client->driver_name
+ ? sprintf(buf, "%s\n", client->driver_name)
+ : 0;
+}
+
+static struct device_attribute i2c_dev_attrs[] = {
+ __ATTR(name, S_IRUGO, show_client_name, NULL),
+ /* modalias helps coldplug: modprobe $(cat .../modalias) */
+ __ATTR(modalias, S_IRUGO, show_modalias, NULL),
+ { },
+};
+
struct bus_type i2c_bus_type = {
.name = "i2c",
+ .dev_attrs = i2c_dev_attrs,
.match = i2c_device_match,
+ .uevent = i2c_device_uevent,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
.suspend = i2c_device_suspend,
.resume = i2c_device_resume,
};
+EXPORT_SYMBOL_GPL(i2c_bus_type);
-/* ------------------------------------------------------------------------- */
+/**
+ * i2c_new_device - instantiate an i2c device for use with a new style driver
+ * @adap: the adapter managing the device
+ * @info: describes one I2C device; bus_num is ignored
+ *
+ * Create a device to work with a new style i2c driver, where binding is
+ * handled through driver model probe()/remove() methods. This call is not
+ * appropriate for use by mainboad initialization logic, which usually runs
+ * during an arch_initcall() long before any i2c_adapter could exist.
+ *
+ * This returns the new i2c client, which may be saved for later use with
+ * i2c_unregister_device(); or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
+{
+ struct i2c_client *client;
+ int status;
-void i2c_adapter_dev_release(struct device *dev)
+ client = kzalloc(sizeof *client, GFP_KERNEL);
+ if (!client)
+ return NULL;
+
+ client->adapter = adap;
+
+ client->dev.platform_data = info->platform_data;
+ client->flags = info->flags;
+ client->addr = info->addr;
+ client->irq = info->irq;
+
+ strlcpy(client->driver_name, info->driver_name,
+ sizeof(client->driver_name));
+ strlcpy(client->name, info->type, sizeof(client->name));
+
+ /* a new style driver may be bound to this device when we
+ * return from this function, or any later moment (e.g. maybe
+ * hotplugging will load the driver module). and the device
+ * refcount model is the standard driver model one.
+ */
+ status = i2c_attach_client(client);
+ if (status < 0) {
+ kfree(client);
+ client = NULL;
+ }
+ return client;
+}
+EXPORT_SYMBOL_GPL(i2c_new_device);
+
+
+/**
+ * i2c_unregister_device - reverse effect of i2c_new_device()
+ * @client: value returned from i2c_new_device()
+ */
+void i2c_unregister_device(struct i2c_client *client)
{
- struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
- complete(&adap->dev_released);
+ struct i2c_adapter *adapter = client->adapter;
+ struct i2c_driver *driver = client->driver;
+
+ if (driver && !is_newstyle_driver(driver)) {
+ dev_err(&client->dev, "can't unregister devices "
+ "with legacy drivers\n");
+ WARN_ON(1);
+ return;
+ }
+
+ mutex_lock(&adapter->clist_lock);
+ list_del(&client->list);
+ mutex_unlock(&adapter->clist_lock);
+
+ device_unregister(&client->dev);
}
+EXPORT_SYMBOL_GPL(i2c_unregister_device);
-struct device_driver i2c_adapter_driver = {
- .owner = THIS_MODULE,
- .name = "i2c_adapter",
- .bus = &i2c_bus_type,
-};
/* ------------------------------------------------------------------------- */
/* I2C bus adapters -- one roots each I2C or SMBUS segment */
-static void i2c_adapter_class_dev_release(struct class_device *dev)
+void i2c_adapter_dev_release(struct device *dev)
{
- struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
- complete(&adap->class_dev_released);
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
+ complete(&adap->dev_released);
}
+EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */
-static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf)
+static ssize_t
+show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev);
+ struct i2c_adapter *adap = to_i2c_adapter(dev);
return sprintf(buf, "%s\n", adap->name);
}
-static struct class_device_attribute i2c_adapter_attrs[] = {
- __ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL),
+static struct device_attribute i2c_adapter_attrs[] = {
+ __ATTR(name, S_IRUGO, show_adapter_name, NULL),
{ },
};
struct class i2c_adapter_class = {
.owner = THIS_MODULE,
.name = "i2c-adapter",
- .class_dev_attrs = i2c_adapter_attrs,
- .release = &i2c_adapter_class_dev_release,
+ .dev_attrs = i2c_adapter_attrs,
};
+EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */
-static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
- return sprintf(buf, "%s\n", adap->name);
-}
-static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
-
-
-static void i2c_client_release(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- complete(&client->released);
-}
-
-static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf)
+static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
- struct i2c_client *client = to_i2c_client(dev);
- return sprintf(buf, "%s\n", client->name);
+ struct i2c_devinfo *devinfo;
+
+ mutex_lock(&__i2c_board_lock);
+ list_for_each_entry(devinfo, &__i2c_board_list, list) {
+ if (devinfo->busnum == adapter->nr
+ && !i2c_new_device(adapter,
+ &devinfo->board_info))
+ printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n",
+ i2c_adapter_id(adapter),
+ devinfo->board_info.addr);
+ }
+ mutex_unlock(&__i2c_board_lock);
}
-/*
- * We can't use the DEVICE_ATTR() macro here, as we used the same name for
- * an i2c adapter attribute (above).
- */
-static struct device_attribute dev_attr_client_name =
- __ATTR(name, S_IRUGO, &show_client_name, NULL);
-
-
-/* ---------------------------------------------------
- * registering functions
- * ---------------------------------------------------
- */
-
-/* -----
- * i2c_add_adapter is called from within the algorithm layer,
- * when a new hw adapter registers. A new device is register to be
- * available for clients.
- */
-int i2c_add_adapter(struct i2c_adapter *adap)
+static int i2c_register_adapter(struct i2c_adapter *adap)
{
- int id, res = 0;
+ int res = 0;
struct list_head *item;
struct i2c_driver *driver;
- mutex_lock(&core_lists);
-
- if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
- res = -ENOMEM;
- goto out_unlock;
- }
-
- res = idr_get_new(&i2c_adapter_idr, adap, &id);
- if (res < 0) {
- if (res == -EAGAIN)
- res = -ENOMEM;
- goto out_unlock;
- }
-
- adap->nr = id & MAX_ID_MASK;
mutex_init(&adap->bus_lock);
mutex_init(&adap->clist_lock);
- list_add_tail(&adap->list,&adapters);
INIT_LIST_HEAD(&adap->clients);
+ mutex_lock(&core_lists);
+ list_add_tail(&adap->list, &adapters);
+
/* Add the adapter to the driver core.
* If the parent pointer is not set up,
* we add this adapter to the host bus.
@@ -221,27 +346,19 @@ int i2c_add_adapter(struct i2c_adapter *adap)
"physical device\n", adap->name);
}
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
- adap->dev.driver = &i2c_adapter_driver;
adap->dev.release = &i2c_adapter_dev_release;
+ adap->dev.class = &i2c_adapter_class;
res = device_register(&adap->dev);
if (res)
goto out_list;
- res = device_create_file(&adap->dev, &dev_attr_name);
- if (res)
- goto out_unregister;
-
- /* Add this adapter to the i2c_adapter class */
- memset(&adap->class_dev, 0x00, sizeof(struct class_device));
- adap->class_dev.dev = &adap->dev;
- adap->class_dev.class = &i2c_adapter_class;
- strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
- res = class_device_register(&adap->class_dev);
- if (res)
- goto out_remove_name;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
- /* inform drivers of new adapters */
+ /* create pre-declared device nodes for new-style drivers */
+ if (adap->nr < __i2c_first_dynamic_bus_num)
+ i2c_scan_static_board_info(adap);
+
+ /* let legacy drivers scan this bus for matching devices */
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
if (driver->attach_adapter)
@@ -253,18 +370,98 @@ out_unlock:
mutex_unlock(&core_lists);
return res;
-out_remove_name:
- device_remove_file(&adap->dev, &dev_attr_name);
-out_unregister:
- init_completion(&adap->dev_released); /* Needed? */
- device_unregister(&adap->dev);
- wait_for_completion(&adap->dev_released);
out_list:
list_del(&adap->list);
idr_remove(&i2c_adapter_idr, adap->nr);
goto out_unlock;
}
+/**
+ * i2c_add_adapter - declare i2c adapter, use dynamic bus number
+ * @adapter: the adapter to add
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * doesn't matter. Examples: for I2C adapters dynamically added by
+ * USB links or PCI plugin cards.
+ *
+ * When this returns zero, a new bus number was allocated and stored
+ * in adap->nr, and the specified adapter became available for clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int i2c_add_adapter(struct i2c_adapter *adapter)
+{
+ int id, res = 0;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ mutex_lock(&core_lists);
+ /* "above" here means "above or equal to", sigh */
+ res = idr_get_new_above(&i2c_adapter_idr, adapter,
+ __i2c_first_dynamic_bus_num, &id);
+ mutex_unlock(&core_lists);
+
+ if (res < 0) {
+ if (res == -EAGAIN)
+ goto retry;
+ return res;
+ }
+
+ adapter->nr = id;
+ return i2c_register_adapter(adapter);
+}
+EXPORT_SYMBOL(i2c_add_adapter);
+
+/**
+ * i2c_add_numbered_adapter - declare i2c adapter, use static bus number
+ * @adap: the adapter to register (with adap->nr initialized)
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * matters. Example: for I2C adapters from system-on-chip CPUs, or
+ * otherwise built in to the system's mainboard, and where i2c_board_info
+ * is used to properly configure I2C devices.
+ *
+ * If no devices have pre-been declared for this bus, then be sure to
+ * register the adapter before any dynamically allocated ones. Otherwise
+ * the required bus ID may not be available.
+ *
+ * When this returns zero, the specified adapter became available for
+ * clients using the bus number provided in adap->nr. Also, the table
+ * of I2C devices pre-declared using i2c_register_board_info() is scanned,
+ * and the appropriate driver model device nodes are created. Otherwise, a
+ * negative errno value is returned.
+ */
+int i2c_add_numbered_adapter(struct i2c_adapter *adap)
+{
+ int id;
+ int status;
+
+ if (adap->nr & ~MAX_ID_MASK)
+ return -EINVAL;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ mutex_lock(&core_lists);
+ /* "above" here means "above or equal to", sigh;
+ * we need the "equal to" result to force the result
+ */
+ status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
+ if (status == 0 && id != adap->nr) {
+ status = -EBUSY;
+ idr_remove(&i2c_adapter_idr, id);
+ }
+ mutex_unlock(&core_lists);
+ if (status == -EAGAIN)
+ goto retry;
+
+ if (status == 0)
+ status = i2c_register_adapter(adap);
+ return status;
+}
+EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
int i2c_del_adapter(struct i2c_adapter *adap)
{
@@ -302,9 +499,19 @@ int i2c_del_adapter(struct i2c_adapter *adap)
/* detach any active clients. This must be done first, because
* it can fail; in which case we give up. */
list_for_each_safe(item, _n, &adap->clients) {
+ struct i2c_driver *driver;
+
client = list_entry(item, struct i2c_client, list);
+ driver = client->driver;
+
+ /* new style, follow standard driver model */
+ if (!driver || is_newstyle_driver(driver)) {
+ i2c_unregister_device(client);
+ continue;
+ }
- if ((res=client->driver->detach_client(client))) {
+ /* legacy drivers create and remove clients themselves */
+ if ((res = driver->detach_client(client))) {
dev_err(&adap->dev, "detach_client failed for client "
"[%s] at address 0x%02x\n", client->name,
client->addr);
@@ -314,17 +521,13 @@ int i2c_del_adapter(struct i2c_adapter *adap)
/* clean up the sysfs representation */
init_completion(&adap->dev_released);
- init_completion(&adap->class_dev_released);
- class_device_unregister(&adap->class_dev);
- device_remove_file(&adap->dev, &dev_attr_name);
device_unregister(&adap->dev);
list_del(&adap->list);
/* wait for sysfs to drop all references */
wait_for_completion(&adap->dev_released);
- wait_for_completion(&adap->class_dev_released);
- /* free dynamically allocated bus id */
+ /* free bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
@@ -333,24 +536,42 @@ int i2c_del_adapter(struct i2c_adapter *adap)
mutex_unlock(&core_lists);
return res;
}
+EXPORT_SYMBOL(i2c_del_adapter);
+
+/* ------------------------------------------------------------------------- */
-/* -----
- * What follows is the "upwards" interface: commands for talking to clients,
- * which implement the functions to access the physical information of the
- * chips.
+/*
+ * An i2c_driver is used with one or more i2c_client (device) nodes to access
+ * i2c slave chips, on a bus instance associated with some i2c_adapter. There
+ * are two models for binding the driver to its device: "new style" drivers
+ * follow the standard Linux driver model and just respond to probe() calls
+ * issued if the driver core sees they match(); "legacy" drivers create device
+ * nodes themselves.
*/
int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
- struct list_head *item;
- struct i2c_adapter *adapter;
int res;
+ /* new style driver methods can't mix with legacy ones */
+ if (is_newstyle_driver(driver)) {
+ if (driver->attach_adapter || driver->detach_adapter
+ || driver->detach_client) {
+ printk(KERN_WARNING
+ "i2c-core: driver [%s] is confused\n",
+ driver->driver.name);
+ return -EINVAL;
+ }
+ }
+
/* add the driver to the list of i2c drivers in the driver core */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
+ /* for new style drivers, when registration returns the driver core
+ * will have called probe() for all matching-but-unbound devices.
+ */
res = driver_register(&driver->driver);
if (res)
return res;
@@ -360,10 +581,11 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
list_add_tail(&driver->list,&drivers);
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
- /* now look for instances of driver on our adapters */
+ /* legacy drivers scan i2c busses directly */
if (driver->attach_adapter) {
- list_for_each(item,&adapters) {
- adapter = list_entry(item, struct i2c_adapter, list);
+ struct i2c_adapter *adapter;
+
+ list_for_each_entry(adapter, &adapters, list) {
driver->attach_adapter(adapter);
}
}
@@ -373,16 +595,22 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
}
EXPORT_SYMBOL(i2c_register_driver);
-int i2c_del_driver(struct i2c_driver *driver)
+/**
+ * i2c_del_driver - unregister I2C driver
+ * @driver: the driver being unregistered
+ */
+void i2c_del_driver(struct i2c_driver *driver)
{
struct list_head *item1, *item2, *_n;
struct i2c_client *client;
struct i2c_adapter *adap;
- int res = 0;
-
mutex_lock(&core_lists);
+ /* new-style driver? */
+ if (is_newstyle_driver(driver))
+ goto unregister;
+
/* Have a look at each adapter, if clients of this driver are still
* attached. If so, detach them to be able to kill the driver
* afterwards.
@@ -390,11 +618,10 @@ int i2c_del_driver(struct i2c_driver *driver)
list_for_each(item1,&adapters) {
adap = list_entry(item1, struct i2c_adapter, list);
if (driver->detach_adapter) {
- if ((res = driver->detach_adapter(adap))) {
+ if (driver->detach_adapter(adap)) {
dev_err(&adap->dev, "detach_adapter failed "
"for driver [%s]\n",
driver->driver.name);
- goto out_unlock;
}
} else {
list_for_each_safe(item2, _n, &adap->clients) {
@@ -404,25 +631,26 @@ int i2c_del_driver(struct i2c_driver *driver)
dev_dbg(&adap->dev, "detaching client [%s] "
"at 0x%02x\n", client->name,
client->addr);
- if ((res = driver->detach_client(client))) {
+ if (driver->detach_client(client)) {
dev_err(&adap->dev, "detach_client "
"failed for client [%s] at "
"0x%02x\n", client->name,
client->addr);
- goto out_unlock;
}
}
}
}
+ unregister:
driver_unregister(&driver->driver);
list_del(&driver->list);
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
- out_unlock:
mutex_unlock(&core_lists);
- return 0;
}
+EXPORT_SYMBOL(i2c_del_driver);
+
+/* ------------------------------------------------------------------------- */
static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
{
@@ -447,6 +675,7 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
return rval;
}
+EXPORT_SYMBOL(i2c_check_addr);
int i2c_attach_client(struct i2c_client *client)
{
@@ -463,9 +692,15 @@ int i2c_attach_client(struct i2c_client *client)
client->usage_count = 0;
client->dev.parent = &client->adapter->dev;
- client->dev.driver = &client->driver->driver;
client->dev.bus = &i2c_bus_type;
- client->dev.release = &i2c_client_release;
+
+ if (client->driver)
+ client->dev.driver = &client->driver->driver;
+
+ if (client->driver && !is_newstyle_driver(client->driver))
+ client->dev.release = i2c_client_release;
+ else
+ client->dev.release = i2c_client_dev_release;
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
@@ -474,9 +709,6 @@ int i2c_attach_client(struct i2c_client *client)
res = device_register(&client->dev);
if (res)
goto out_list;
- res = device_create_file(&client->dev, &dev_attr_client_name);
- if (res)
- goto out_unregister;
mutex_unlock(&adapter->clist_lock);
if (adapter->client_register) {
@@ -489,10 +721,6 @@ int i2c_attach_client(struct i2c_client *client)
return 0;
-out_unregister:
- init_completion(&client->released); /* Needed? */
- device_unregister(&client->dev);
- wait_for_completion(&client->released);
out_list:
list_del(&client->list);
dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
@@ -501,7 +729,7 @@ out_unlock:
mutex_unlock(&adapter->clist_lock);
return res;
}
-
+EXPORT_SYMBOL(i2c_attach_client);
int i2c_detach_client(struct i2c_client *client)
{
@@ -527,7 +755,6 @@ int i2c_detach_client(struct i2c_client *client)
mutex_lock(&adapter->clist_lock);
list_del(&client->list);
init_completion(&client->released);
- device_remove_file(&client->dev, &dev_attr_client_name);
device_unregister(&client->dev);
mutex_unlock(&adapter->clist_lock);
wait_for_completion(&client->released);
@@ -535,6 +762,7 @@ int i2c_detach_client(struct i2c_client *client)
out:
return res;
}
+EXPORT_SYMBOL(i2c_detach_client);
static int i2c_inc_use_client(struct i2c_client *client)
{
@@ -567,6 +795,7 @@ int i2c_use_client(struct i2c_client *client)
return 0;
}
+EXPORT_SYMBOL(i2c_use_client);
int i2c_release_client(struct i2c_client *client)
{
@@ -581,6 +810,7 @@ int i2c_release_client(struct i2c_client *client)
return 0;
}
+EXPORT_SYMBOL(i2c_release_client);
void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
{
@@ -601,6 +831,7 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
}
mutex_unlock(&adap->clist_lock);
}
+EXPORT_SYMBOL(i2c_clients_command);
static int __init i2c_init(void)
{
@@ -609,16 +840,12 @@ static int __init i2c_init(void)
retval = bus_register(&i2c_bus_type);
if (retval)
return retval;
- retval = driver_register(&i2c_adapter_driver);
- if (retval)
- return retval;
return class_register(&i2c_adapter_class);
}
static void __exit i2c_exit(void)
{
class_unregister(&i2c_adapter_class);
- driver_unregister(&i2c_adapter_driver);
bus_unregister(&i2c_bus_type);
}
@@ -638,8 +865,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
#ifdef DEBUG
for (ret = 0; ret < num; ret++) {
dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
- "len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
- 'R' : 'W', msgs[ret].addr, msgs[ret].len);
+ "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
+ ? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
+ (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
}
#endif
@@ -653,6 +881,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
return -ENOSYS;
}
}
+EXPORT_SYMBOL(i2c_transfer);
int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
{
@@ -671,6 +900,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count)
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
+EXPORT_SYMBOL(i2c_master_send);
int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
{
@@ -690,7 +920,7 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count)
transmitted, else error code. */
return (ret == 1) ? count : ret;
}
-
+EXPORT_SYMBOL(i2c_master_recv);
int i2c_control(struct i2c_client *client,
unsigned int cmd, unsigned long arg)
@@ -712,6 +942,7 @@ int i2c_control(struct i2c_client *client,
}
return ret;
}
+EXPORT_SYMBOL(i2c_control);
/* ----------------------------------------------------
* the i2c address scanning function
@@ -853,6 +1084,70 @@ int i2c_probe(struct i2c_adapter *adapter,
return 0;
}
+EXPORT_SYMBOL(i2c_probe);
+
+struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+ struct i2c_board_info *info,
+ unsigned short const *addr_list)
+{
+ int i;
+
+ /* Stop here if the bus doesn't support probing */
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) {
+ dev_err(&adap->dev, "Probing not supported\n");
+ return NULL;
+ }
+
+ mutex_lock(&adap->clist_lock);
+ for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
+ /* Check address validity */
+ if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
+ dev_warn(&adap->dev, "Invalid 7-bit address "
+ "0x%02x\n", addr_list[i]);
+ continue;
+ }
+
+ /* Check address availability */
+ if (__i2c_check_addr(adap, addr_list[i])) {
+ dev_dbg(&adap->dev, "Address 0x%02x already in "
+ "use, not probing\n", addr_list[i]);
+ continue;
+ }
+
+ /* Test address responsiveness
+ The default probe method is a quick write, but it is known
+ to corrupt the 24RF08 EEPROMs due to a state machine bug,
+ and could also irreversibly write-protect some EEPROMs, so
+ for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte
+ read instead. Also, some bus drivers don't implement
+ quick write, so we fallback to a byte read it that case
+ too. */
+ if ((addr_list[i] & ~0x07) == 0x30
+ || (addr_list[i] & ~0x0f) == 0x50
+ || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) {
+ if (i2c_smbus_xfer(adap, addr_list[i], 0,
+ I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE, NULL) >= 0)
+ break;
+ } else {
+ if (i2c_smbus_xfer(adap, addr_list[i], 0,
+ I2C_SMBUS_WRITE, 0,
+ I2C_SMBUS_QUICK, NULL) >= 0)
+ break;
+ }
+ }
+ mutex_unlock(&adap->clist_lock);
+
+ if (addr_list[i] == I2C_CLIENT_END) {
+ dev_dbg(&adap->dev, "Probing failed, no device found\n");
+ return NULL;
+ }
+
+ info->addr = addr_list[i];
+ return i2c_new_device(adap, info);
+}
+EXPORT_SYMBOL_GPL(i2c_new_probed_device);
struct i2c_adapter* i2c_get_adapter(int id)
{
@@ -866,11 +1161,13 @@ struct i2c_adapter* i2c_get_adapter(int id)
mutex_unlock(&core_lists);
return adapter;
}
+EXPORT_SYMBOL(i2c_get_adapter);
void i2c_put_adapter(struct i2c_adapter *adap)
{
module_put(adap->owner);
}
+EXPORT_SYMBOL(i2c_put_adapter);
/* The SMBus parts */
@@ -939,6 +1236,7 @@ s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value)
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
value,0,I2C_SMBUS_QUICK,NULL);
}
+EXPORT_SYMBOL(i2c_smbus_write_quick);
s32 i2c_smbus_read_byte(struct i2c_client *client)
{
@@ -949,12 +1247,14 @@ s32 i2c_smbus_read_byte(struct i2c_client *client)
else
return data.byte;
}
+EXPORT_SYMBOL(i2c_smbus_read_byte);
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL);
}
+EXPORT_SYMBOL(i2c_smbus_write_byte);
s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
{
@@ -965,6 +1265,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
else
return data.byte;
}
+EXPORT_SYMBOL(i2c_smbus_read_byte_data);
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
{
@@ -974,6 +1275,7 @@ s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
I2C_SMBUS_WRITE,command,
I2C_SMBUS_BYTE_DATA,&data);
}
+EXPORT_SYMBOL(i2c_smbus_write_byte_data);
s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
{
@@ -984,6 +1286,7 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
else
return data.word;
}
+EXPORT_SYMBOL(i2c_smbus_read_word_data);
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
{
@@ -993,6 +1296,23 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
I2C_SMBUS_WRITE,command,
I2C_SMBUS_WORD_DATA,&data);
}
+EXPORT_SYMBOL(i2c_smbus_write_word_data);
+
+/* Returns the number of read bytes */
+s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command,
+ u8 *values)
+{
+ union i2c_smbus_data data;
+
+ if (i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_READ, command,
+ I2C_SMBUS_BLOCK_DATA, &data))
+ return -1;
+
+ memcpy(values, &data.block[1], data.block[0]);
+ return data.block[0];
+}
+EXPORT_SYMBOL(i2c_smbus_read_block_data);
s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
u8 length, const u8 *values)
@@ -1007,6 +1327,7 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
I2C_SMBUS_WRITE,command,
I2C_SMBUS_BLOCK_DATA,&data);
}
+EXPORT_SYMBOL(i2c_smbus_write_block_data);
/* Returns the number of read bytes */
s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values)
@@ -1021,6 +1342,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val
memcpy(values, &data.block[1], data.block[0]);
return data.block[0];
}
+EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
u8 length, const u8 *values)
@@ -1035,6 +1357,7 @@ s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command,
I2C_SMBUS_WRITE, command,
I2C_SMBUS_I2C_BLOCK_DATA, &data);
}
+EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
@@ -1098,9 +1421,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
- dev_err(&adapter->dev, "Block read not supported "
- "under I2C emulation!\n");
- return -1;
+ msg[1].flags |= I2C_M_RECV_LEN;
+ msg[1].len = 1; /* block length will be added by
+ the underlying bus driver */
} else {
msg[0].len = data->block[0] + 2;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
@@ -1114,9 +1437,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
}
break;
case I2C_SMBUS_BLOCK_PROC_CALL:
- dev_dbg(&adapter->dev, "Block process call not supported "
- "under I2C emulation!\n");
- return -1;
+ num = 2; /* Another special case */
+ read_write = I2C_SMBUS_READ;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+ dev_err(&adapter->dev, "%s called with invalid "
+ "block proc call size (%d)\n", __FUNCTION__,
+ data->block[0]);
+ return -1;
+ }
+ msg[0].len = data->block[0] + 2;
+ for (i = 1; i < msg[0].len; i++)
+ msgbuf0[i] = data->block[i-1];
+ msg[1].flags |= I2C_M_RECV_LEN;
+ msg[1].len = 1; /* block length will be added by
+ the underlying bus driver */
+ break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
msg[1].len = I2C_SMBUS_BLOCK_MAX;
@@ -1180,6 +1515,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
data->block[i+1] = msgbuf1[i];
break;
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ for (i = 0; i < msgbuf1[0] + 1; i++)
+ data->block[i] = msgbuf1[i];
+ break;
}
return 0;
}
@@ -1204,43 +1544,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
return res;
}
-
-
-/* Next four are needed by i2c-isa */
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);
-EXPORT_SYMBOL_GPL(i2c_adapter_driver);
-EXPORT_SYMBOL_GPL(i2c_adapter_class);
-EXPORT_SYMBOL_GPL(i2c_bus_type);
-
-EXPORT_SYMBOL(i2c_add_adapter);
-EXPORT_SYMBOL(i2c_del_adapter);
-EXPORT_SYMBOL(i2c_del_driver);
-EXPORT_SYMBOL(i2c_attach_client);
-EXPORT_SYMBOL(i2c_detach_client);
-EXPORT_SYMBOL(i2c_use_client);
-EXPORT_SYMBOL(i2c_release_client);
-EXPORT_SYMBOL(i2c_clients_command);
-EXPORT_SYMBOL(i2c_check_addr);
-
-EXPORT_SYMBOL(i2c_master_send);
-EXPORT_SYMBOL(i2c_master_recv);
-EXPORT_SYMBOL(i2c_control);
-EXPORT_SYMBOL(i2c_transfer);
-EXPORT_SYMBOL(i2c_get_adapter);
-EXPORT_SYMBOL(i2c_put_adapter);
-EXPORT_SYMBOL(i2c_probe);
-
EXPORT_SYMBOL(i2c_smbus_xfer);
-EXPORT_SYMBOL(i2c_smbus_write_quick);
-EXPORT_SYMBOL(i2c_smbus_read_byte);
-EXPORT_SYMBOL(i2c_smbus_write_byte);
-EXPORT_SYMBOL(i2c_smbus_read_byte_data);
-EXPORT_SYMBOL(i2c_smbus_write_byte_data);
-EXPORT_SYMBOL(i2c_smbus_read_word_data);
-EXPORT_SYMBOL(i2c_smbus_write_word_data);
-EXPORT_SYMBOL(i2c_smbus_write_block_data);
-EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data);
-EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module");
diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h
new file mode 100644
index 00000000000..cd5bff87485
--- /dev/null
+++ b/drivers/i2c/i2c-core.h
@@ -0,0 +1,31 @@
+/*
+ * i2c-core.h - interfaces internal to the I2C framework
+ *
+ * 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.
+ */
+
+struct i2c_devinfo {
+ struct list_head list;
+ int busnum;
+ struct i2c_board_info board_info;
+};
+
+/* board_lock protects board_list and first_dynamic_bus_num.
+ * only i2c core components are allowed to use these symbols.
+ */
+extern struct mutex __i2c_board_lock;
+extern struct list_head __i2c_board_list;
+extern int __i2c_first_dynamic_bus_num;
+
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index cb4fa9bef8c..e7a70971059 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/i2c.h>
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 556455fbfa2..5e8efc89255 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -730,7 +730,7 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed)
if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
tune_cris_ide(drive, speed - XFER_PIO_0);
- return 0;
+ return ide_config_drive_speed(drive, speed);
}
switch(speed)
@@ -760,7 +760,8 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed)
hold = ATA_DMA2_HOLD;
break;
default:
- return 0;
+ BUG();
+ break;
}
if (speed >= XFER_UDMA_0)
@@ -768,7 +769,7 @@ static int speed_cris_ide(ide_drive_t *drive, u8 speed)
else
cris_ide_set_speed(TYPE_DMA, 0, strobe, hold);
- return 0;
+ return ide_config_drive_speed(drive, speed);
}
void __init
@@ -821,7 +822,6 @@ init_e100_ide (void)
hwif->udma_four = 0;
hwif->ultra_mask = cris_ultra_mask;
hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
- hwif->swdma_mask = 0x07; /* Singleword DMA 0-2 */
hwif->autodma = 1;
hwif->drives[0].autodma = 1;
hwif->drives[1].autodma = 1;
@@ -1010,7 +1010,6 @@ static int cris_config_drive_for_dma (ide_drive_t *drive)
return 0;
speed_cris_ide(drive, speed);
- ide_config_drive_speed(drive, speed);
return ide_dma_enable(drive);
}
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index b08c37c9f95..c6522a64d7e 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -401,6 +401,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index 990eafe5ea1..73bdf64dbbf 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -1,7 +1,8 @@
/*
- * linux/drivers/ide/pci/aec62xx.c Version 0.11 March 27, 2002
+ * linux/drivers/ide/pci/aec62xx.c Version 0.21 Apr 21, 2007
*
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com>
*
*/
@@ -193,18 +194,8 @@ static int config_chipset_for_dma (ide_drive_t *drive)
static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
{
- u8 speed = 0;
- u8 new_pio = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-
- switch(pio) {
- case 5: speed = new_pio; break;
- case 4: speed = XFER_PIO_4; break;
- case 3: speed = XFER_PIO_3; break;
- case 2: speed = XFER_PIO_2; break;
- case 1: speed = XFER_PIO_1; break;
- default: speed = XFER_PIO_0; break;
- }
- (void) aec62xx_tune_chipset(drive, speed);
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void) aec62xx_tune_chipset(drive, pio + XFER_PIO_0);
}
static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
@@ -213,7 +204,7 @@ static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- aec62xx_tune_drive(drive, 5);
+ aec62xx_tune_drive(drive, 255);
return -1;
}
@@ -288,11 +279,10 @@ static void __devinit init_hwif_aec62xx(ide_hwif_t *hwif)
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
hwif->ide_dma_check = &aec62xx_config_drive_xfer_rate;
hwif->ide_dma_lostirq = &aec62xx_irq_timeout;
- hwif->ide_dma_timeout = &aec62xx_irq_timeout;
+
if (!noautodma)
hwif->autodma = 1;
hwif->drives[0].autodma = hwif->autodma;
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 83e0aa65a43..946a12746cb 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -534,7 +534,7 @@ static int ali15x3_config_drive_for_dma(ide_drive_t *drive)
struct hd_driveid *id = drive->id;
if ((m5229_revision<=0x20) && (drive->media!=ide_disk))
- goto no_dma_set;
+ goto ata_pio;
drive->init_speed = 0;
@@ -555,20 +555,19 @@ try_dma_modes:
(id->dma_1word & hwif->swdma_mask)) {
/* Force if Capable regular DMA modes */
if (!config_chipset_for_dma(drive))
- goto no_dma_set;
+ goto ata_pio;
}
} else if (__ide_dma_good_drive(drive) &&
(id->eide_dma_time < 150)) {
/* Consult the list of known "good" drives */
if (!config_chipset_for_dma(drive))
- goto no_dma_set;
+ goto ata_pio;
} else {
goto ata_pio;
}
} else {
ata_pio:
hwif->tuneproc(drive, 255);
-no_dma_set:
return -1;
}
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 561197f7b5b..77f51ab6d43 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -1,10 +1,7 @@
-/* $Id: cmd64x.c,v 1.21 2000/01/30 23:23:16
- *
- * linux/drivers/ide/pci/cmd64x.c Version 1.42 Feb 8, 2007
+/*
+ * linux/drivers/ide/pci/cmd64x.c Version 1.47 Mar 19, 2007
*
* cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
- * Note, this driver is not used at all on other systems because
- * there the "BIOS" has done all of the following already.
* Due to massive hardware bugs, UltraDMA is only supported
* on the 646U2 and not on the 646U.
*
@@ -39,11 +36,12 @@
* CMD64x specific registers definition.
*/
#define CFR 0x50
-#define CFR_INTR_CH0 0x02
+#define CFR_INTR_CH0 0x04
#define CNTRL 0x51
-#define CNTRL_DIS_RA0 0x40
-#define CNTRL_DIS_RA1 0x80
-#define CNTRL_ENA_2ND 0x08
+#define CNTRL_ENA_1ST 0x04
+#define CNTRL_ENA_2ND 0x08
+#define CNTRL_DIS_RA0 0x40
+#define CNTRL_DIS_RA1 0x80
#define CMDTIM 0x52
#define ARTTIM0 0x53
@@ -90,86 +88,67 @@ static int n_cmd_devs;
static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
{
char *p = buf;
-
- u8 reg53 = 0, reg54 = 0, reg55 = 0, reg56 = 0; /* primary */
- u8 reg57 = 0, reg58 = 0, reg5b; /* secondary */
u8 reg72 = 0, reg73 = 0; /* primary */
u8 reg7a = 0, reg7b = 0; /* secondary */
- u8 reg50 = 0, reg71 = 0; /* extra */
+ u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0; /* extra */
+ u8 rev = 0;
p += sprintf(p, "\nController: %d\n", index);
- p += sprintf(p, "CMD%x Chipset.\n", dev->device);
+ p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
+
(void) pci_read_config_byte(dev, CFR, &reg50);
- (void) pci_read_config_byte(dev, ARTTIM0, &reg53);
- (void) pci_read_config_byte(dev, DRWTIM0, &reg54);
- (void) pci_read_config_byte(dev, ARTTIM1, &reg55);
- (void) pci_read_config_byte(dev, DRWTIM1, &reg56);
- (void) pci_read_config_byte(dev, ARTTIM2, &reg57);
- (void) pci_read_config_byte(dev, DRWTIM2, &reg58);
- (void) pci_read_config_byte(dev, DRWTIM3, &reg5b);
+ (void) pci_read_config_byte(dev, CNTRL, &reg51);
+ (void) pci_read_config_byte(dev, ARTTIM23, &reg57);
(void) pci_read_config_byte(dev, MRDMODE, &reg71);
(void) pci_read_config_byte(dev, BMIDESR0, &reg72);
(void) pci_read_config_byte(dev, UDIDETCR0, &reg73);
(void) pci_read_config_byte(dev, BMIDESR1, &reg7a);
(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
- p += sprintf(p, "--------------- Primary Channel "
- "---------------- Secondary Channel "
- "-------------\n");
- p += sprintf(p, " %sabled "
- " %sabled\n",
- (reg72&0x80)?"dis":" en",
- (reg7a&0x80)?"dis":" en");
- p += sprintf(p, "--------------- drive0 "
- "--------- drive1 -------- drive0 "
- "---------- drive1 ------\n");
- p += sprintf(p, "DMA enabled: %s %s"
- " %s %s\n",
- (reg72&0x20)?"yes":"no ", (reg72&0x40)?"yes":"no ",
- (reg7a&0x20)?"yes":"no ", (reg7a&0x40)?"yes":"no ");
-
- p += sprintf(p, "DMA Mode: %s(%s) %s(%s)",
- (reg72&0x20)?((reg73&0x01)?"UDMA":" DMA"):" PIO",
- (reg72&0x20)?(
- ((reg73&0x30)==0x30)?(((reg73&0x35)==0x35)?"3":"0"):
- ((reg73&0x20)==0x20)?(((reg73&0x25)==0x25)?"3":"1"):
- ((reg73&0x10)==0x10)?(((reg73&0x15)==0x15)?"4":"2"):
- ((reg73&0x00)==0x00)?(((reg73&0x05)==0x05)?"5":"2"):
- "X"):"?",
- (reg72&0x40)?((reg73&0x02)?"UDMA":" DMA"):" PIO",
- (reg72&0x40)?(
- ((reg73&0xC0)==0xC0)?(((reg73&0xC5)==0xC5)?"3":"0"):
- ((reg73&0x80)==0x80)?(((reg73&0x85)==0x85)?"3":"1"):
- ((reg73&0x40)==0x40)?(((reg73&0x4A)==0x4A)?"4":"2"):
- ((reg73&0x00)==0x00)?(((reg73&0x0A)==0x0A)?"5":"2"):
- "X"):"?");
- p += sprintf(p, " %s(%s) %s(%s)\n",
- (reg7a&0x20)?((reg7b&0x01)?"UDMA":" DMA"):" PIO",
- (reg7a&0x20)?(
- ((reg7b&0x30)==0x30)?(((reg7b&0x35)==0x35)?"3":"0"):
- ((reg7b&0x20)==0x20)?(((reg7b&0x25)==0x25)?"3":"1"):
- ((reg7b&0x10)==0x10)?(((reg7b&0x15)==0x15)?"4":"2"):
- ((reg7b&0x00)==0x00)?(((reg7b&0x05)==0x05)?"5":"2"):
- "X"):"?",
- (reg7a&0x40)?((reg7b&0x02)?"UDMA":" DMA"):" PIO",
- (reg7a&0x40)?(
- ((reg7b&0xC0)==0xC0)?(((reg7b&0xC5)==0xC5)?"3":"0"):
- ((reg7b&0x80)==0x80)?(((reg7b&0x85)==0x85)?"3":"1"):
- ((reg7b&0x40)==0x40)?(((reg7b&0x4A)==0x4A)?"4":"2"):
- ((reg7b&0x00)==0x00)?(((reg7b&0x0A)==0x0A)?"5":"2"):
- "X"):"?" );
- p += sprintf(p, "PIO Mode: %s %s"
- " %s %s\n",
- "?", "?", "?", "?");
- p += sprintf(p, " %s %s\n",
- (reg50 & CFR_INTR_CH0) ? "interrupting" : "polling ",
- (reg57 & ARTTIM23_INTR_CH1) ? "interrupting" : "polling");
- p += sprintf(p, " %s %s\n",
- (reg71 & MRDMODE_INTR_CH0) ? "pending" : "clear ",
- (reg71 & MRDMODE_INTR_CH1) ? "pending" : "clear");
- p += sprintf(p, " %s %s\n",
- (reg71 & MRDMODE_BLK_CH0) ? "blocked" : "enabled",
- (reg71 & MRDMODE_BLK_CH1) ? "blocked" : "enabled");
+ /* PCI0643/6 originally didn't have the primary channel enable bit */
+ (void) pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+ if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
+ (dev->device == PCI_DEVICE_ID_CMD_646 && rev < 3))
+ reg51 |= CNTRL_ENA_1ST;
+
+ p += sprintf(p, "---------------- Primary Channel "
+ "---------------- Secondary Channel ------------\n");
+ p += sprintf(p, " %s %s\n",
+ (reg51 & CNTRL_ENA_1ST) ? "enabled " : "disabled",
+ (reg51 & CNTRL_ENA_2ND) ? "enabled " : "disabled");
+ p += sprintf(p, "---------------- drive0 --------- drive1 "
+ "-------- drive0 --------- drive1 ------\n");
+ p += sprintf(p, "DMA enabled: %s %s"
+ " %s %s\n",
+ (reg72 & 0x20) ? "yes" : "no ", (reg72 & 0x40) ? "yes" : "no ",
+ (reg7a & 0x20) ? "yes" : "no ", (reg7a & 0x40) ? "yes" : "no ");
+ p += sprintf(p, "UltraDMA mode: %s (%c) %s (%c)",
+ ( reg73 & 0x01) ? " on" : "off",
+ ((reg73 & 0x30) == 0x30) ? ((reg73 & 0x04) ? '3' : '0') :
+ ((reg73 & 0x30) == 0x20) ? ((reg73 & 0x04) ? '3' : '1') :
+ ((reg73 & 0x30) == 0x10) ? ((reg73 & 0x04) ? '4' : '2') :
+ ((reg73 & 0x30) == 0x00) ? ((reg73 & 0x04) ? '5' : '2') : '?',
+ ( reg73 & 0x02) ? " on" : "off",
+ ((reg73 & 0xC0) == 0xC0) ? ((reg73 & 0x08) ? '3' : '0') :
+ ((reg73 & 0xC0) == 0x80) ? ((reg73 & 0x08) ? '3' : '1') :
+ ((reg73 & 0xC0) == 0x40) ? ((reg73 & 0x08) ? '4' : '2') :
+ ((reg73 & 0xC0) == 0x00) ? ((reg73 & 0x08) ? '5' : '2') : '?');
+ p += sprintf(p, " %s (%c) %s (%c)\n",
+ ( reg7b & 0x01) ? " on" : "off",
+ ((reg7b & 0x30) == 0x30) ? ((reg7b & 0x04) ? '3' : '0') :
+ ((reg7b & 0x30) == 0x20) ? ((reg7b & 0x04) ? '3' : '1') :
+ ((reg7b & 0x30) == 0x10) ? ((reg7b & 0x04) ? '4' : '2') :
+ ((reg7b & 0x30) == 0x00) ? ((reg7b & 0x04) ? '5' : '2') : '?',
+ ( reg7b & 0x02) ? " on" : "off",
+ ((reg7b & 0xC0) == 0xC0) ? ((reg7b & 0x08) ? '3' : '0') :
+ ((reg7b & 0xC0) == 0x80) ? ((reg7b & 0x08) ? '3' : '1') :
+ ((reg7b & 0xC0) == 0x40) ? ((reg7b & 0x08) ? '4' : '2') :
+ ((reg7b & 0xC0) == 0x00) ? ((reg7b & 0x08) ? '5' : '2') : '?');
+ p += sprintf(p, "Interrupt: %s, %s %s, %s\n",
+ (reg71 & MRDMODE_BLK_CH0 ) ? "blocked" : "enabled",
+ (reg50 & CFR_INTR_CH0 ) ? "pending" : "clear ",
+ (reg71 & MRDMODE_BLK_CH1 ) ? "blocked" : "enabled",
+ (reg57 & ARTTIM23_INTR_CH1) ? "pending" : "clear ");
return (char *)p;
}
@@ -179,7 +158,6 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
char *p = buffer;
int i;
- p += sprintf(p, "\n");
for (i = 0; i < n_cmd_devs; i++) {
struct pci_dev *dev = cmd_devs[i];
p = print_cmd64x_get_info(p, dev, i);
@@ -195,116 +173,103 @@ static u8 quantize_timing(int timing, int quant)
}
/*
- * This routine writes the prepared setup/active/recovery counts
- * for a drive into the cmd646 chipset registers to active them.
+ * This routine calculates active/recovery counts and then writes them into
+ * the chipset registers.
*/
-static void program_drive_counts (ide_drive_t *drive, int setup_count, int active_count, int recovery_count)
+static void program_cycle_times (ide_drive_t *drive, int cycle_time, int active_time)
{
- unsigned long flags;
- struct pci_dev *dev = HWIF(drive)->pci_dev;
- ide_drive_t *drives = HWIF(drive)->drives;
- u8 temp_b;
- static const u8 setup_counts[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
- static const u8 recovery_counts[] =
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ int clock_time = 1000 / system_bus_clock();
+ u8 cycle_count, active_count, recovery_count, drwtim;
+ static const u8 recovery_values[] =
{15, 15, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0};
- static const u8 arttim_regs[2][2] = {
- { ARTTIM0, ARTTIM1 },
- { ARTTIM23, ARTTIM23 }
- };
- static const u8 drwtim_regs[2][2] = {
- { DRWTIM0, DRWTIM1 },
- { DRWTIM2, DRWTIM3 }
- };
- int channel = (int) HWIF(drive)->channel;
- int slave = (drives != drive); /* Is this really the best way to determine this?? */
-
- cmdprintk("program_drive_count parameters = s(%d),a(%d),r(%d),p(%d)\n",
- setup_count, active_count, recovery_count, drive->present);
+ static const u8 drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM2, DRWTIM3};
+
+ cmdprintk("program_cycle_times parameters: total=%d, active=%d\n",
+ cycle_time, active_time);
+
+ cycle_count = quantize_timing( cycle_time, clock_time);
+ active_count = quantize_timing(active_time, clock_time);
+ recovery_count = cycle_count - active_count;
+
/*
- * Set up address setup count registers.
- * Primary interface has individual count/timing registers for
- * each drive. Secondary interface has one common set of registers,
- * for address setup so we merge these timings, using the slowest
- * value.
+ * In case we've got too long recovery phase, try to lengthen
+ * the active phase
*/
- if (channel) {
- drive->drive_data = setup_count;
- setup_count = max(drives[0].drive_data,
- drives[1].drive_data);
- cmdprintk("Secondary interface, setup_count = %d\n",
- setup_count);
+ if (recovery_count > 16) {
+ active_count += recovery_count - 16;
+ recovery_count = 16;
}
+ if (active_count > 16) /* shouldn't actually happen... */
+ active_count = 16;
+
+ cmdprintk("Final counts: total=%d, active=%d, recovery=%d\n",
+ cycle_count, active_count, recovery_count);
/*
* Convert values to internal chipset representation
*/
- setup_count = (setup_count > 5) ? 0xc0 : (int) setup_counts[setup_count];
- active_count &= 0xf; /* Remember, max value is 16 */
- recovery_count = (int) recovery_counts[recovery_count];
+ recovery_count = recovery_values[recovery_count];
+ active_count &= 0x0f;
- cmdprintk("Final values = %d,%d,%d\n",
- setup_count, active_count, recovery_count);
-
- /*
- * Now that everything is ready, program the new timings
- */
- local_irq_save(flags);
- /*
- * Program the address_setup clocks into ARTTIM reg,
- * and then the active/recovery counts into the DRWTIM reg
- */
- (void) pci_read_config_byte(dev, arttim_regs[channel][slave], &temp_b);
- (void) pci_write_config_byte(dev, arttim_regs[channel][slave],
- ((u8) setup_count) | (temp_b & 0x3f));
- (void) pci_write_config_byte(dev, drwtim_regs[channel][slave],
- (u8) ((active_count << 4) | recovery_count));
- cmdprintk ("Write %x to %x\n",
- ((u8) setup_count) | (temp_b & 0x3f),
- arttim_regs[channel][slave]);
- cmdprintk ("Write %x to %x\n",
- (u8) ((active_count << 4) | recovery_count),
- drwtim_regs[channel][slave]);
- local_irq_restore(flags);
+ /* Program the active/recovery counts into the DRWTIM register */
+ drwtim = (active_count << 4) | recovery_count;
+ (void) pci_write_config_byte(dev, drwtim_regs[drive->dn], drwtim);
+ cmdprintk("Write 0x%02x to reg 0x%x\n", drwtim, drwtim_regs[drive->dn]);
}
/*
- * This routine selects drive's best PIO mode, calculates setup/active/recovery
- * counts, and then writes them into the chipset registers.
+ * This routine selects drive's best PIO mode and writes into the chipset
+ * registers setup/active/recovery timings.
*/
static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
{
- int setup_time, active_time, cycle_time;
- u8 cycle_count, setup_count, active_count, recovery_count;
- u8 pio_mode;
- int clock_time = 1000 / system_bus_clock();
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
ide_pio_data_t pio;
-
+ u8 pio_mode, setup_count, arttim = 0;
+ static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
+ static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
- cycle_time = pio.cycle_time;
- setup_time = ide_pio_timings[pio_mode].setup_time;
- active_time = ide_pio_timings[pio_mode].active_time;
+ cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
+ drive->name, mode_wanted, pio_mode, pio.cycle_time,
+ pio.overridden ? " (overriding vendor mode)" : "");
- setup_count = quantize_timing( setup_time, clock_time);
- cycle_count = quantize_timing( cycle_time, clock_time);
- active_count = quantize_timing(active_time, clock_time);
+ program_cycle_times(drive, pio.cycle_time,
+ ide_pio_timings[pio_mode].active_time);
- recovery_count = cycle_count - active_count;
- /* program_drive_counts() takes care of zero recovery cycles */
- if (recovery_count > 16) {
- active_count += recovery_count - 16;
- recovery_count = 16;
+ setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
+ 1000 / system_bus_clock());
+
+ /*
+ * The primary channel has individual address setup timing registers
+ * for each drive and the hardware selects the slowest timing itself.
+ * The secondary channel has one common register and we have to select
+ * the slowest address setup timing ourselves.
+ */
+ if (hwif->channel) {
+ ide_drive_t *drives = hwif->drives;
+
+ drive->drive_data = setup_count;
+ setup_count = max(drives[0].drive_data, drives[1].drive_data);
}
- if (active_count > 16)
- active_count = 16; /* maximum allowed by cmd64x */
- program_drive_counts (drive, setup_count, active_count, recovery_count);
+ if (setup_count > 5) /* shouldn't actually happen... */
+ setup_count = 5;
+ cmdprintk("Final address setup count: %d\n", setup_count);
- cmdprintk("%s: PIO mode wanted %d, selected %d (%dns)%s, "
- "clocks=%d/%d/%d\n",
- drive->name, mode_wanted, pio_mode, cycle_time,
- pio.overridden ? " (overriding vendor mode)" : "",
- setup_count, active_count, recovery_count);
+ /*
+ * Program the address setup clocks into the ARTTIM registers.
+ * Avoid clearing the secondary channel's interrupt bit.
+ */
+ (void) pci_read_config_byte (dev, arttim_regs[drive->dn], &arttim);
+ if (hwif->channel)
+ arttim &= ~ARTTIM23_INTR_CH1;
+ arttim &= ~0xc0;
+ arttim |= setup_values[setup_count];
+ (void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
+ cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
return pio_mode;
}
@@ -376,61 +341,64 @@ static u8 cmd64x_ratemask (ide_drive_t *drive)
return mode;
}
-static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
+ u8 unit = drive->dn & 0x01;
+ u8 regU = 0, pciU = hwif->channel ? UDIDETCR1 : UDIDETCR0;
- u8 unit = (drive->select.b.unit & 0x01);
- u8 regU = 0, pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0;
- u8 regD = 0, pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0;
-
- u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed);
+ speed = ide_rate_filter(cmd64x_ratemask(drive), speed);
if (speed >= XFER_SW_DMA_0) {
- (void) pci_read_config_byte(dev, pciD, &regD);
(void) pci_read_config_byte(dev, pciU, &regU);
- regD &= ~(unit ? 0x40 : 0x20);
regU &= ~(unit ? 0xCA : 0x35);
- (void) pci_write_config_byte(dev, pciD, regD);
- (void) pci_write_config_byte(dev, pciU, regU);
- (void) pci_read_config_byte(dev, pciD, &regD);
- (void) pci_read_config_byte(dev, pciU, &regU);
}
switch(speed) {
- case XFER_UDMA_5: regU |= (unit ? 0x0A : 0x05); break;
- case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break;
- case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break;
- case XFER_UDMA_2: regU |= (unit ? 0x42 : 0x11); break;
- case XFER_UDMA_1: regU |= (unit ? 0x82 : 0x21); break;
- case XFER_UDMA_0: regU |= (unit ? 0xC2 : 0x31); break;
- case XFER_MW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
- case XFER_MW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
- case XFER_MW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
- case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break;
- case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break;
- case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break;
- case XFER_PIO_5:
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
- break;
-
- default:
- return 1;
+ case XFER_UDMA_5:
+ regU |= unit ? 0x0A : 0x05;
+ break;
+ case XFER_UDMA_4:
+ regU |= unit ? 0x4A : 0x15;
+ break;
+ case XFER_UDMA_3:
+ regU |= unit ? 0x8A : 0x25;
+ break;
+ case XFER_UDMA_2:
+ regU |= unit ? 0x42 : 0x11;
+ break;
+ case XFER_UDMA_1:
+ regU |= unit ? 0x82 : 0x21;
+ break;
+ case XFER_UDMA_0:
+ regU |= unit ? 0xC2 : 0x31;
+ break;
+ case XFER_MW_DMA_2:
+ program_cycle_times(drive, 120, 70);
+ break;
+ case XFER_MW_DMA_1:
+ program_cycle_times(drive, 150, 80);
+ break;
+ case XFER_MW_DMA_0:
+ program_cycle_times(drive, 480, 215);
+ break;
+ case XFER_PIO_5:
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ (void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
+ break;
+ default:
+ return 1;
}
- if (speed >= XFER_SW_DMA_0) {
+ if (speed >= XFER_SW_DMA_0)
(void) pci_write_config_byte(dev, pciU, regU);
- regD |= (unit ? 0x40 : 0x20);
- (void) pci_write_config_byte(dev, pciD, regD);
- }
- return (ide_config_drive_speed(drive, speed));
+ return ide_config_drive_speed(drive, speed);
}
static int config_chipset_for_dma (ide_drive_t *drive)
@@ -457,67 +425,80 @@ static int cmd64x_config_drive_for_dma (ide_drive_t *drive)
return -1;
}
-static int cmd64x_alt_dma_status (struct pci_dev *dev)
+static int cmd648_ide_dma_end (ide_drive_t *drive)
{
- switch(dev->device) {
- case PCI_DEVICE_ID_CMD_648:
- case PCI_DEVICE_ID_CMD_649:
- return 1;
- default:
- break;
- }
- return 0;
+ ide_hwif_t *hwif = HWIF(drive);
+ int err = __ide_dma_end(drive);
+ u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
+ MRDMODE_INTR_CH0;
+ u8 mrdmode = inb(hwif->dma_master + 0x01);
+
+ /* clear the interrupt bit */
+ outb(mrdmode | irq_mask, hwif->dma_master + 0x01);
+
+ return err;
}
static int cmd64x_ide_dma_end (ide_drive_t *drive)
{
- u8 dma_stat = 0, dma_cmd = 0;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
+ int irq_reg = hwif->channel ? ARTTIM23 : CFR;
+ u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
+ CFR_INTR_CH0;
+ u8 irq_stat = 0;
+ int err = __ide_dma_end(drive);
- drive->waiting_for_dma = 0;
- /* read DMA command state */
- dma_cmd = inb(hwif->dma_command);
- /* stop DMA */
- outb(dma_cmd & ~1, hwif->dma_command);
- /* get DMA status */
- dma_stat = inb(hwif->dma_status);
- /* clear the INTR & ERROR bits */
- outb(dma_stat | 6, hwif->dma_status);
- if (cmd64x_alt_dma_status(dev)) {
- u8 dma_intr = 0;
- u8 dma_mask = (hwif->channel) ? ARTTIM23_INTR_CH1 :
- CFR_INTR_CH0;
- u8 dma_reg = (hwif->channel) ? ARTTIM2 : CFR;
- (void) pci_read_config_byte(dev, dma_reg, &dma_intr);
- /* clear the INTR bit */
- (void) pci_write_config_byte(dev, dma_reg, dma_intr|dma_mask);
- }
- /* purge DMA mappings */
- ide_destroy_dmatable(drive);
- /* verify good DMA status */
- return (dma_stat & 7) != 4;
+ (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
+ /* clear the interrupt bit */
+ (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask);
+
+ return err;
+}
+
+static int cmd648_ide_dma_test_irq (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = HWIF(drive);
+ u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 :
+ MRDMODE_INTR_CH0;
+ u8 dma_stat = inb(hwif->dma_status);
+ u8 mrdmode = inb(hwif->dma_master + 0x01);
+
+#ifdef DEBUG
+ printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n",
+ drive->name, dma_stat, mrdmode, irq_mask);
+#endif
+ if (!(mrdmode & irq_mask))
+ return 0;
+
+ /* return 1 if INTR asserted */
+ if (dma_stat & 4)
+ return 1;
+
+ return 0;
}
static int cmd64x_ide_dma_test_irq (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- u8 dma_alt_stat = 0, mask = (hwif->channel) ? MRDMODE_INTR_CH1 :
- MRDMODE_INTR_CH0;
- u8 dma_stat = inb(hwif->dma_status);
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ int irq_reg = hwif->channel ? ARTTIM23 : CFR;
+ u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 :
+ CFR_INTR_CH0;
+ u8 dma_stat = inb(hwif->dma_status);
+ u8 irq_stat = 0;
+
+ (void) pci_read_config_byte(dev, irq_reg, &irq_stat);
- (void) pci_read_config_byte(dev, MRDMODE, &dma_alt_stat);
#ifdef DEBUG
- printk("%s: dma_stat: 0x%02x dma_alt_stat: "
- "0x%02x mask: 0x%02x\n", drive->name,
- dma_stat, dma_alt_stat, mask);
+ printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n",
+ drive->name, dma_stat, irq_stat, irq_mask);
#endif
- if (!(dma_alt_stat & mask))
+ if (!(irq_stat & irq_mask))
return 0;
/* return 1 if INTR asserted */
- if ((dma_stat & 4) == 4)
+ if (dma_stat & 4)
return 1;
return 0;
@@ -665,7 +646,6 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
hwif->ultra_mask = 0x3f;
hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
if (dev->device == PCI_DEVICE_ID_CMD_643)
hwif->ultra_mask = 0x80;
@@ -678,17 +658,25 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
if (!(hwif->udma_four))
hwif->udma_four = ata66_cmd64x(hwif);
- if (dev->device == PCI_DEVICE_ID_CMD_646) {
+ switch(dev->device) {
+ case PCI_DEVICE_ID_CMD_648:
+ case PCI_DEVICE_ID_CMD_649:
+ alt_irq_bits:
+ hwif->ide_dma_end = &cmd648_ide_dma_end;
+ hwif->ide_dma_test_irq = &cmd648_ide_dma_test_irq;
+ break;
+ case PCI_DEVICE_ID_CMD_646:
hwif->chipset = ide_cmd646;
if (class_rev == 0x01) {
hwif->ide_dma_end = &cmd646_1_ide_dma_end;
- } else {
- hwif->ide_dma_end = &cmd64x_ide_dma_end;
- hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
- }
- } else {
- hwif->ide_dma_end = &cmd64x_ide_dma_end;
- hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+ break;
+ } else if (class_rev >= 0x03)
+ goto alt_irq_bits;
+ /* fall thru */
+ default:
+ hwif->ide_dma_end = &cmd64x_ide_dma_end;
+ hwif->ide_dma_test_irq = &cmd64x_ide_dma_test_irq;
+ break;
}
@@ -698,42 +686,75 @@ static void __devinit init_hwif_cmd64x(ide_hwif_t *hwif)
hwif->drives[1].autodma = hwif->autodma;
}
+static int __devinit init_setup_cmd64x(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_cmd646(struct pci_dev *dev, ide_pci_device_t *d)
+{
+ u8 rev = 0;
+
+ /*
+ * The original PCI0646 didn't have the primary channel enable bit,
+ * it appeared starting with PCI0646U (i.e. revision ID 3).
+ */
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+ if (rev < 3)
+ d->enablebits[0].reg = 0;
+
+ return ide_setup_pci_device(dev, d);
+}
+
static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
{ /* 0 */
.name = "CMD643",
+ .init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
},{ /* 1 */
.name = "CMD646",
+ .init_setup = init_setup_cmd646,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
.channels = 2,
.autodma = AUTODMA,
- .enablebits = {{0x00,0x00,0x00}, {0x51,0x80,0x80}},
+ .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
},{ /* 2 */
.name = "CMD648",
+ .init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
},{ /* 3 */
.name = "CMD649",
+ .init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
.channels = 2,
.autodma = AUTODMA,
+ .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
}
};
+/*
+ * We may have to modify enablebits for PCI0646, so we'd better pass
+ * a local copy of the ide_pci_device_t structure down the call chain...
+ */
static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
- return ide_setup_pci_device(dev, &cmd64x_chipsets[id->driver_data]);
+ ide_pci_device_t d = cmd64x_chipsets[id->driver_data];
+
+ return d.init_setup(dev, &d);
}
static struct pci_device_id cmd64x_pci_tbl[] = {
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index ab6fa271aeb..cf9d344d19f 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/hpt366.c Version 1.02 Apr 18, 2007
+ * linux/drivers/ide/pci/hpt366.c Version 1.03 May 4, 2007
*
* Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
* Portions Copyright (C) 2001 Sun Microsystems, Inc.
@@ -1527,7 +1527,12 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
if (rev > 2)
goto init_single;
+ /*
+ * HPT36x chips are single channel and
+ * do not seem to have the channel enable bit...
+ */
d->channels = 1;
+ d->enablebits[0].reg = 0;
if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
u8 pin1 = 0, pin2 = 0;
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index a132767f7d9..4e1254813ee 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -1,8 +1,9 @@
/*
- * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
+ * linux/drivers/ide/pci/it821x.c Version 0.10 Mar 10 2007
*
* Copyright (C) 2004 Red Hat <alan@redhat.com>
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
*
* May be copied or modified under the terms of the GNU General Public License
* Based in part on the ITE vendor provided SCSI driver.
@@ -104,6 +105,7 @@ static int it8212_noraid;
/**
* it821x_program - program the PIO/MWDMA registers
* @drive: drive to tune
+ * @timing: timing info
*
* Program the PIO/MWDMA timing for this channel according to the
* current clock.
@@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
/**
* it821x_program_udma - program the UDMA registers
* @drive: drive to tune
+ * @timing: timing info
*
* Program the UDMA timing for this drive according to the
* current clock.
@@ -153,10 +156,9 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
}
}
-
/**
* it821x_clock_strategy
- * @hwif: hardware interface
+ * @drive: drive to set up
*
* Select between the 50 and 66Mhz base clocks to get the best
* results for this interface.
@@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
altclock = itdev->want[0][1];
}
- /* Master doesn't care does the slave ? */
- if(clock == ATA_ANY)
+ /*
+ * if both clocks can be used for the mode with the higher priority
+ * use the clock needed by the mode with the lower priority
+ */
+ if (clock == ATA_ANY)
clock = altclock;
/* Nobody cares - keep the same clock */
@@ -240,37 +245,56 @@ static u8 it821x_ratemask (ide_drive_t *drive)
}
/**
- * it821x_tuneproc - tune a drive
+ * it821x_tunepio - tune a drive
* @drive: drive to tune
- * @mode_wanted: the target operating mode
- *
- * Load the timing settings for this device mode into the
- * controller. By the time we are called the mode has been
- * modified as neccessary to handle the absence of seperate
- * master/slave timers for MWDMA/PIO.
+ * @pio: the desired PIO mode
*
- * This code is only used in pass through mode.
+ * Try to tune the drive/host to the desired PIO mode taking into
+ * the consideration the maximum PIO mode supported by the other
+ * device on the cable.
*/
-static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
{
ide_hwif_t *hwif = drive->hwif;
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
int unit = drive->select.b.unit;
+ ide_drive_t *pair = &hwif->drives[1 - unit];
/* Spec says 89 ref driver uses 88 */
static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
- if(itdev->smart)
- return;
+ /*
+ * Compute the best PIO mode we can for a given device. We must
+ * pick a speed that does not cause problems with the other device
+ * on the cable.
+ */
+ if (pair) {
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+ /* trim PIO to the slowest of the master/slave */
+ if (pair_pio < set_pio)
+ set_pio = pair_pio;
+ }
+
+ if (itdev->smart)
+ goto set_drive_speed;
/* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
- itdev->want[unit][1] = pio_want[mode_wanted];
+ itdev->want[unit][1] = pio_want[set_pio];
itdev->want[unit][0] = 1; /* PIO is lowest priority */
- itdev->pio[unit] = pio[mode_wanted];
+ itdev->pio[unit] = pio[set_pio];
it821x_clock_strategy(drive);
it821x_program(drive, itdev->pio[unit]);
+
+set_drive_speed:
+ return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
+}
+
+static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ (void)it821x_tunepio(drive, pio);
}
/**
@@ -354,40 +378,6 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
}
/**
- * config_it821x_chipset_for_pio - set drive timings
- * @drive: drive to tune
- * @speed we want
- *
- * Compute the best pio mode we can for a given device. We must
- * pick a speed that does not cause problems with the other device
- * on the cable.
- */
-
-static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
- u8 unit = drive->select.b.unit;
- ide_hwif_t *hwif = drive->hwif;
- ide_drive_t *pair = &hwif->drives[1-unit];
- u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
- u8 pair_pio;
-
- /* We have to deal with this mess in pairs */
- if(pair != NULL) {
- pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
- /* Trim PIO to the slowest of the master/slave */
- if(pair_pio < set_pio)
- set_pio = pair_pio;
- }
- it821x_tuneproc(drive, set_pio);
- speed = XFER_PIO_0 + set_pio;
- /* XXX - We trim to the lowest of the pair so the other drive
- will always be fine at this point until we do hotplug passthru */
-
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
-}
-
-/**
* it821x_dma_read - DMA hook
* @drive: drive for DMA
*
@@ -450,15 +440,17 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
struct it821x_dev *itdev = ide_get_hwifdata(hwif);
u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed);
- if(!itdev->smart) {
- switch(speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- it821x_tuneproc(drive, (speed - XFER_PIO_0));
- break;
+ switch (speed) {
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ return it821x_tunepio(drive, speed - XFER_PIO_0);
+ }
+
+ if (itdev->smart == 0) {
+ switch (speed) {
/* MWDMA tuning is really hard because our MWDMA and PIO
timings are kept in the same place. We can switch in the
host dma on/off callbacks */
@@ -498,14 +490,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
- if (speed) {
- config_it821x_chipset_for_pio(drive, 0);
- it821x_tune_chipset(drive, speed);
+ if (speed == 0)
+ return 0;
- return ide_dma_enable(drive);
- }
+ it821x_tune_chipset(drive, speed);
- return 0;
+ return ide_dma_enable(drive);
}
/**
@@ -523,7 +513,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive)
if (ide_use_dma(drive) && config_chipset_for_dma(drive))
return 0;
- config_it821x_chipset_for_pio(drive, 1);
+ it821x_tuneproc(drive, 255);
return -1;
}
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index ace98929cc3..2cdd629c653 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -255,9 +255,6 @@ static int config_chipset_for_dma(ide_drive_t *drive)
printk(KERN_WARNING "%s reduced to Ultra33 mode.\n", drive->name);
}
- if (drive->media != ide_disk && drive->media != ide_cdrom)
- return 0;
-
if (id->capability & 4) {
/*
* Set IORDY_EN & PREFETCH_EN (this seems to have
@@ -398,7 +395,7 @@ static void __devinit apple_kiwi_init(struct pci_dev *pdev)
unsigned int class_rev = 0;
u8 conf;
- if (np == NULL || !device_is_compatible(np, "kiwi-root"))
+ if (np == NULL || !of_device_is_compatible(np, "kiwi-root"))
return;
pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 71eccdf5f81..79cec50a242 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/siimage.c Version 1.11 Jan 27, 2007
+ * linux/drivers/ide/pci/siimage.c Version 1.12 Mar 10 2007
*
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat <alan@redhat.com>
@@ -287,11 +287,6 @@ static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
(void) ide_config_drive_speed(drive, speed);
}
-static void config_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
- config_siimage_chipset_for_pio(drive, set_speed);
-}
-
/**
* siimage_tune_chipset - set controller timings
* @drive: Drive to set up
@@ -396,8 +391,6 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, siimage_ratemask(drive));
- config_chipset_for_pio(drive, !speed);
-
if (!speed)
return 0;
@@ -423,7 +416,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- config_chipset_for_pio(drive, 1);
+ config_siimage_chipset_for_pio(drive, 1);
return -1;
}
@@ -838,7 +831,7 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
/*
* Now set up the hw. We have to do this ourselves as
- * the MMIO layout isnt the same as the the standard port
+ * the MMIO layout isnt the same as the standard port
* based I/O
*/
@@ -1015,7 +1008,6 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
- hwif->swdma_mask = 0x07;
if (!is_sata(hwif))
hwif->atapi_dma = 1;
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 3a8a76fc78c..fe3b4b91f85 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -11,6 +11,8 @@
* Merge in Russell's HW workarounds, fix various problems
* with the timing registers setup.
* -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
+ *
+ * Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
*/
#include <linux/types.h>
@@ -47,25 +49,19 @@
#define CTRL_P0EN (1 << 0)
/*
- * Convert a PIO mode and cycle time to the required on/off
- * times for the interface. This has protection against run-away
- * timings.
+ * Convert a PIO mode and cycle time to the required on/off times
+ * for the interface. This has protection against runaway timings.
*/
-static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
+static unsigned int get_pio_timings(ide_pio_data_t *p)
{
- unsigned int cmd_on;
- unsigned int cmd_off;
+ unsigned int cmd_on, cmd_off;
- cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
+ cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
- if (cmd_on > 32)
- cmd_on = 32;
if (cmd_on == 0)
cmd_on = 1;
- if (cmd_off > 32)
- cmd_off = 32;
if (cmd_off == 0)
cmd_off = 1;
@@ -73,100 +69,59 @@ static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
}
/*
- * Configure the drive and chipset for PIO
+ * Configure the chipset for PIO mode.
*/
-static void config_for_pio(ide_drive_t *drive, int pio, int report, int chipset_only)
+static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ int reg = 0x44 + drive->dn * 4;
ide_pio_data_t p;
- u16 drv_ctrl = 0x909;
- unsigned int xfer_mode, reg;
+ u16 drv_ctrl;
- DBG(("config_for_pio(drive:%s, pio:%d, report:%d, chipset_only:%d)\n",
- drive->name, pio, report, chipset_only));
-
- reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
+ DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
pio = ide_get_best_pio_mode(drive, pio, 5, &p);
- xfer_mode = XFER_PIO_0 + pio;
-
- if (chipset_only || ide_config_drive_speed(drive, xfer_mode) == 0) {
- drv_ctrl = get_timing_sl82c105(&p);
- drive->pio_speed = xfer_mode;
- } else
- drive->pio_speed = XFER_PIO_0;
+ drive->drive_data = drv_ctrl = get_pio_timings(&p);
- if (drive->using_dma == 0) {
+ if (!drive->using_dma) {
/*
* If we are actually using MW DMA, then we can not
* reprogram the interface drive control register.
*/
- pci_write_config_word(dev, reg, drv_ctrl);
- pci_read_config_word(dev, reg, &drv_ctrl);
-
- if (report) {
- printk("%s: selected %s (%dns) (%04X)\n", drive->name,
- ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
- }
+ pci_write_config_word(dev, reg, drv_ctrl);
+ pci_read_config_word (dev, reg, &drv_ctrl);
}
+
+ printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
+ ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl);
+
+ return pio;
}
/*
- * Configure the drive and the chipset for DMA
+ * Configure the drive for DMA.
+ * We'll program the chipset only when DMA is actually turned on.
*/
-static int config_for_dma (ide_drive_t *drive)
+static int config_for_dma(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- unsigned int reg;
-
DBG(("config_for_dma(drive:%s)\n", drive->name));
- reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
-
if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0)
- return 1;
+ return 0;
- pci_write_config_word(dev, reg, 0x0240);
-
- return 0;
+ return ide_dma_enable(drive);
}
/*
- * Check to see if the drive and
- * chipset is capable of DMA mode
+ * Check to see if the drive and chipset are capable of DMA mode.
*/
-
-static int sl82c105_check_drive (ide_drive_t *drive)
+static int sl82c105_ide_dma_check(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
-
- DBG(("sl82c105_check_drive(drive:%s)\n", drive->name));
-
- do {
- struct hd_driveid *id = drive->id;
-
- if (!drive->autodma)
- break;
-
- if (!id || !(id->capability & 1))
- break;
+ DBG(("sl82c105_ide_dma_check(drive:%s)\n", drive->name));
- /* Consult the list of known "bad" drives */
- if (__ide_dma_bad_drive(drive))
- break;
-
- if (id->field_valid & 2) {
- if ((id->dma_mword & hwif->mwdma_mask) ||
- (id->dma_1word & hwif->swdma_mask))
- return 0;
- }
-
- if (__ide_dma_good_drive(drive) && id->eide_dma_time < 150)
- return 0;
- } while (0);
+ if (ide_use_dma(drive) && config_for_dma(drive))
+ return 0;
return -1;
}
@@ -195,14 +150,14 @@ static inline void sl82c105_reset_host(struct pci_dev *dev)
* This function is called when the IDE timer expires, the drive
* indicates that it is READY, and we were waiting for DMA to complete.
*/
-static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
+static int sl82c105_ide_dma_lostirq(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
- unsigned long dma_base = hwif->dma_base;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
+ u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+ u8 dma_cmd;
- printk("sl82c105: lost IRQ: resetting host\n");
+ printk("sl82c105: lost IRQ, resetting host\n");
/*
* Check the raw interrupt from the drive.
@@ -215,15 +170,15 @@ static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
* Was DMA enabled? If so, disable it - we're resetting the
* host. The IDE layer will be handling the drive for us.
*/
- val = inb(dma_base);
- if (val & 1) {
- outb(val & ~1, dma_base);
+ dma_cmd = inb(hwif->dma_command);
+ if (dma_cmd & 1) {
+ outb(dma_cmd & ~1, hwif->dma_command);
printk("sl82c105: DMA was enabled\n");
}
sl82c105_reset_host(dev);
- /* ide_dmaproc would return 1, so we do as well */
+ /* __ide_dma_lostirq would return 1, so we do as well */
return 1;
}
@@ -235,10 +190,10 @@ static int sl82c105_ide_dma_lost_irq(ide_drive_t *drive)
* The generic IDE core will have disabled the BMEN bit before this
* function is called.
*/
-static void sl82c105_ide_dma_start(ide_drive_t *drive)
+static void sl82c105_dma_start(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
sl82c105_reset_host(dev);
ide_dma_start(drive);
@@ -246,8 +201,8 @@ static void sl82c105_ide_dma_start(ide_drive_t *drive)
static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
DBG(("sl82c105_ide_dma_timeout(drive:%s)\n", drive->name));
@@ -255,26 +210,32 @@ static int sl82c105_ide_dma_timeout(ide_drive_t *drive)
return __ide_dma_timeout(drive);
}
-static int sl82c105_ide_dma_on (ide_drive_t *drive)
+static int sl82c105_ide_dma_on(ide_drive_t *drive)
{
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ int rc, reg = 0x44 + drive->dn * 4;
+
DBG(("sl82c105_ide_dma_on(drive:%s)\n", drive->name));
- if (config_for_dma(drive))
- return 1;
- printk(KERN_INFO "%s: DMA enabled\n", drive->name);
- return __ide_dma_on(drive);
+ rc = __ide_dma_on(drive);
+ if (rc == 0) {
+ pci_write_config_word(dev, reg, 0x0200);
+
+ printk(KERN_INFO "%s: DMA enabled\n", drive->name);
+ }
+ return rc;
}
static void sl82c105_dma_off_quietly(ide_drive_t *drive)
{
- u8 speed = XFER_PIO_0;
+ struct pci_dev *dev = HWIF(drive)->pci_dev;
+ int reg = 0x44 + drive->dn * 4;
DBG(("sl82c105_dma_off_quietly(drive:%s)\n", drive->name));
+ pci_write_config_word(dev, reg, drive->drive_data);
+
ide_dma_off_quietly(drive);
- if (drive->pio_speed)
- speed = drive->pio_speed - XFER_PIO_0;
- config_for_pio(drive, speed, 0, 1);
}
/*
@@ -286,8 +247,8 @@ static void sl82c105_dma_off_quietly(ide_drive_t *drive)
*/
static void sl82c105_selectproc(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
+ ide_hwif_t *hwif = HWIF(drive);
+ struct pci_dev *dev = hwif->pci_dev;
u32 val, old, mask;
//DBG(("sl82c105_selectproc(drive:%s)\n", drive->name));
@@ -323,18 +284,12 @@ static void sl82c105_resetproc(ide_drive_t *drive)
* We only deal with PIO mode here - DMA mode 'using_dma' is not
* initialised at the point that this function is called.
*/
-static void tune_sl82c105(ide_drive_t *drive, u8 pio)
+static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio)
{
- DBG(("tune_sl82c105(drive:%s)\n", drive->name));
-
- config_for_pio(drive, pio, 1, 0);
+ DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio));
- /*
- * We support 32-bit I/O on this interface, and it
- * doesn't have problems with interrupts.
- */
- drive->io_32bit = 1;
- drive->unmask = 1;
+ pio = sl82c105_tune_pio(drive, pio);
+ (void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/*
@@ -393,7 +348,7 @@ static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const c
}
/*
- * Initialise the chip
+ * Initialise IDE channel
*/
static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
@@ -401,24 +356,22 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
- hwif->tuneproc = tune_sl82c105;
- hwif->selectproc = sl82c105_selectproc;
- hwif->resetproc = sl82c105_resetproc;
+ hwif->tuneproc = &sl82c105_tune_drive;
+ hwif->selectproc = &sl82c105_selectproc;
+ hwif->resetproc = &sl82c105_resetproc;
+
+ /*
+ * We support 32-bit I/O on this interface, and
+ * it doesn't have problems with interrupts.
+ */
+ hwif->drives[0].io_32bit = hwif->drives[1].io_32bit = 1;
+ hwif->drives[0].unmask = hwif->drives[1].unmask = 1;
/*
- * Default to PIO 0 for fallback unless tuned otherwise.
* We always autotune PIO, this is done before DMA is checked,
* so there's no risk of accidentally disabling DMA
*/
- hwif->drives[0].pio_speed = XFER_PIO_0;
- hwif->drives[0].autotune = 1;
- hwif->drives[1].pio_speed = XFER_PIO_0;
- hwif->drives[1].autotune = 1;
-
- hwif->atapi_dma = 0;
- hwif->mwdma_mask = 0;
- hwif->swdma_mask = 0;
- hwif->autodma = 0;
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
if (!hwif->dma_base)
return;
@@ -429,27 +382,27 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
* Never ever EVER under any circumstances enable
* DMA when the bridge is this old.
*/
- printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
- hwif->name, rev);
- } else {
- hwif->atapi_dma = 1;
- hwif->mwdma_mask = 0x04;
-
- hwif->ide_dma_check = &sl82c105_check_drive;
- hwif->ide_dma_on = &sl82c105_ide_dma_on;
- hwif->dma_off_quietly = &sl82c105_dma_off_quietly;
- hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq;
- hwif->dma_start = &sl82c105_ide_dma_start;
- hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
-
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
-
- if (hwif->mate)
- hwif->serialized = hwif->mate->serialized = 1;
+ printk(" %s: Winbond W83C553 bridge revision %d, "
+ "BM-DMA disabled\n", hwif->name, rev);
+ return;
}
+
+ hwif->atapi_dma = 1;
+ hwif->mwdma_mask = 0x04;
+
+ hwif->ide_dma_check = &sl82c105_ide_dma_check;
+ hwif->ide_dma_on = &sl82c105_ide_dma_on;
+ hwif->dma_off_quietly = &sl82c105_dma_off_quietly;
+ hwif->ide_dma_lostirq = &sl82c105_ide_dma_lostirq;
+ hwif->dma_start = &sl82c105_dma_start;
+ hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+
+ if (hwif->mate)
+ hwif->serialized = hwif->mate->serialized = 1;
}
static ide_pci_device_t sl82c105_chipset __devinitdata = {
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 071a030ec26..a49ebe44bab 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1157,32 +1157,32 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
- if (device_is_compatible(np, "shasta-ata"))
+ if (of_device_is_compatible(np, "shasta-ata"))
pmif->kind = controller_sh_ata6;
- else if (device_is_compatible(np, "kauai-ata"))
+ else if (of_device_is_compatible(np, "kauai-ata"))
pmif->kind = controller_un_ata6;
- else if (device_is_compatible(np, "K2-UATA"))
+ else if (of_device_is_compatible(np, "K2-UATA"))
pmif->kind = controller_k2_ata6;
- else if (device_is_compatible(np, "keylargo-ata")) {
+ else if (of_device_is_compatible(np, "keylargo-ata")) {
if (strcmp(np->name, "ata-4") == 0)
pmif->kind = controller_kl_ata4;
else
pmif->kind = controller_kl_ata3;
- } else if (device_is_compatible(np, "heathrow-ata"))
+ } else if (of_device_is_compatible(np, "heathrow-ata"))
pmif->kind = controller_heathrow;
else {
pmif->kind = controller_ohare;
pmif->broken_dma = 1;
}
- bidp = get_property(np, "AAPL,bus-id", NULL);
+ bidp = of_get_property(np, "AAPL,bus-id", NULL);
pmif->aapl_bus_id = bidp ? *bidp : 0;
/* Get cable type from device-tree */
if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6
|| pmif->kind == controller_sh_ata6) {
- const char* cable = get_property(np, "cable-type", NULL);
+ const char* cable = of_get_property(np, "cable-type", NULL);
if (cable && !strncmp(cable, "80-", 3))
pmif->cable_80 = 1;
}
@@ -1190,8 +1190,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
* they have a 80 conductor cable, this seem to be always the case unless
* the user mucked around
*/
- if (device_is_compatible(np, "K2-UATA") ||
- device_is_compatible(np, "shasta-ata"))
+ if (of_device_is_compatible(np, "K2-UATA") ||
+ of_device_is_compatible(np, "shasta-ata"))
pmif->cable_80 = 1;
/* On Kauai-type controllers, we make sure the FCR is correct */
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index cd84a55ecf2..61d7809a5a2 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -1,11 +1,8 @@
-# -*- shell-script -*-
-
menu "IEEE 1394 (FireWire) support"
config IEEE1394
tristate "IEEE 1394 (FireWire) support"
depends on PCI || BROKEN
- select NET
help
IEEE 1394 describes a high performance serial bus, which is also
known as FireWire(tm) or i.Link(tm) and is used for connecting all
@@ -35,24 +32,7 @@ config IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone
else says N.
-config IEEE1394_EXTRA_CONFIG_ROMS
- bool "Build in extra config rom entries for certain functionality"
- depends on IEEE1394
- help
- Some IEEE1394 functionality depends on extra config rom entries
- being available in the host adapters CSR. These options will
- allow you to choose which ones.
-
-config IEEE1394_CONFIG_ROM_IP1394
- bool "IP-1394 Entry"
- depends on IEEE1394_EXTRA_CONFIG_ROMS && IEEE1394
- help
- Adds an entry for using IP-over-1394. If you want to use your
- IEEE1394 bus as a network for IP systems (including interacting
- with MacOSX and WinXP IP-over-1394), enable this option and the
- eth1394 option below.
-
-comment "Device Drivers"
+comment "Controllers"
depends on IEEE1394
comment "Texas Instruments PCILynx requires I2C"
@@ -70,6 +50,10 @@ config IEEE1394_PCILYNX
To compile this driver as a module, say M here: the
module will be called pcilynx.
+ Only some old and now very rare PCI and CardBus cards and
+ PowerMacs G3 B&W contain the PCILynx controller. Therefore
+ almost everybody can say N here.
+
config IEEE1394_OHCI1394
tristate "OHCI-1394 support"
depends on PCI && IEEE1394
@@ -83,7 +67,7 @@ config IEEE1394_OHCI1394
To compile this driver as a module, say M here: the
module will be called ohci1394.
-comment "Protocol Drivers"
+comment "Protocols"
depends on IEEE1394
config IEEE1394_VIDEO1394
@@ -121,11 +105,15 @@ config IEEE1394_SBP2_PHYS_DMA
This option is buggy and currently broken on some architectures.
If unsure, say N.
+config IEEE1394_ETH1394_ROM_ENTRY
+ depends on IEEE1394
+ bool
+ default n
+
config IEEE1394_ETH1394
- tristate "Ethernet over 1394"
+ tristate "IP over 1394"
depends on IEEE1394 && EXPERIMENTAL && INET
- select IEEE1394_CONFIG_ROM_IP1394
- select IEEE1394_EXTRA_CONFIG_ROMS
+ select IEEE1394_ETH1394_ROM_ENTRY
help
This driver implements a functional majority of RFC 2734: IPv4 over
1394. It will provide IP connectivity with implementations of RFC
@@ -134,6 +122,8 @@ config IEEE1394_ETH1394
This driver is still considered experimental. It does not yet support
MCAP, therefore multicast support is significantly limited.
+ The module is called eth1394 although it does not emulate Ethernet.
+
config IEEE1394_DV1394
tristate "OHCI-DV I/O support (deprecated)"
depends on IEEE1394 && IEEE1394_OHCI1394
@@ -146,12 +136,12 @@ config IEEE1394_RAWIO
tristate "Raw IEEE1394 I/O support"
depends on IEEE1394
help
- Say Y here if you want support for the raw device. This is generally
- a good idea, so you should say Y here. The raw device enables
- direct communication of user programs with the IEEE 1394 bus and
- thus with the attached peripherals.
+ This option adds support for the raw1394 device file which enables
+ direct communication of user programs with the IEEE 1394 bus and thus
+ with the attached peripherals. Almost all application programs which
+ access FireWire require this option.
- To compile this driver as a module, say M here: the
- module will be called raw1394.
+ To compile this driver as a module, say M here: the module will be
+ called raw1394.
endmenu
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
index e2de6fa0c9f..1b981207fa7 100644
--- a/drivers/ieee1394/config_roms.c
+++ b/drivers/ieee1394/config_roms.c
@@ -26,12 +26,6 @@ struct hpsb_config_rom_entry {
/* Base initialization, called at module load */
int (*init)(void);
- /* Add entry to specified host */
- int (*add)(struct hpsb_host *host);
-
- /* Remove entry from specified host */
- void (*remove)(struct hpsb_host *host);
-
/* Cleanup called at module exit */
void (*cleanup)(void);
@@ -39,7 +33,7 @@ struct hpsb_config_rom_entry {
unsigned int flag;
};
-
+/* The default host entry. This must succeed. */
int hpsb_default_host_entry(struct hpsb_host *host)
{
struct csr1212_keyval *root;
@@ -63,9 +57,9 @@ int hpsb_default_host_entry(struct hpsb_host *host)
return -ENOMEM;
}
- ret = csr1212_associate_keyval(vend_id, text);
+ csr1212_associate_keyval(vend_id, text);
csr1212_release_keyval(text);
- ret |= csr1212_attach_keyval_to_directory(root, vend_id);
+ ret = csr1212_attach_keyval_to_directory(root, vend_id);
csr1212_release_keyval(vend_id);
if (ret != CSR1212_SUCCESS) {
csr1212_destroy_csr(host->csr.rom);
@@ -78,7 +72,7 @@ int hpsb_default_host_entry(struct hpsb_host *host)
}
-#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394
+#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
#include "eth1394.h"
static struct csr1212_keyval *ip1394_ud;
@@ -103,10 +97,12 @@ static int config_rom_ip1394_init(void)
if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
goto ip1394_fail;
- if (csr1212_associate_keyval(spec_id, spec_desc) == CSR1212_SUCCESS &&
- csr1212_associate_keyval(ver, ver_desc) == CSR1212_SUCCESS &&
- csr1212_attach_keyval_to_directory(ip1394_ud, spec_id) == CSR1212_SUCCESS &&
- csr1212_attach_keyval_to_directory(ip1394_ud, ver) == CSR1212_SUCCESS)
+ csr1212_associate_keyval(spec_id, spec_desc);
+ csr1212_associate_keyval(ver, ver_desc);
+ if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
+ == CSR1212_SUCCESS &&
+ csr1212_attach_keyval_to_directory(ip1394_ud, ver)
+ == CSR1212_SUCCESS)
ret = 0;
ip1394_fail:
@@ -135,7 +131,7 @@ static void config_rom_ip1394_cleanup(void)
}
}
-static int config_rom_ip1394_add(struct hpsb_host *host)
+int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
{
if (!ip1394_ud)
return -ENODEV;
@@ -144,92 +140,55 @@ static int config_rom_ip1394_add(struct hpsb_host *host)
ip1394_ud) != CSR1212_SUCCESS)
return -ENOMEM;
+ host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
+ host->update_config_rom = 1;
return 0;
}
+EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
-static void config_rom_ip1394_remove(struct hpsb_host *host)
+void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
{
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
+ host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
+ host->update_config_rom = 1;
}
+EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
static struct hpsb_config_rom_entry ip1394_entry = {
.name = "ip1394",
.init = config_rom_ip1394_init,
- .add = config_rom_ip1394_add,
- .remove = config_rom_ip1394_remove,
.cleanup = config_rom_ip1394_cleanup,
.flag = HPSB_CONFIG_ROM_ENTRY_IP1394,
};
-#endif /* CONFIG_IEEE1394_CONFIG_ROM_IP1394 */
+#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
static struct hpsb_config_rom_entry *const config_rom_entries[] = {
-#ifdef CONFIG_IEEE1394_CONFIG_ROM_IP1394
+#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
&ip1394_entry,
#endif
- NULL,
};
-
+/* Initialize all config roms */
int hpsb_init_config_roms(void)
{
int i, error = 0;
- for (i = 0; config_rom_entries[i]; i++) {
- if (!config_rom_entries[i]->init)
- continue;
-
+ for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
if (config_rom_entries[i]->init()) {
HPSB_ERR("Failed to initialize config rom entry `%s'",
config_rom_entries[i]->name);
error = -1;
- } else
- HPSB_DEBUG("Initialized config rom entry `%s'",
- config_rom_entries[i]->name);
- }
-
- return error;
-}
-
-void hpsb_cleanup_config_roms(void)
-{
- int i;
-
- for (i = 0; config_rom_entries[i]; i++) {
- if (config_rom_entries[i]->cleanup)
- config_rom_entries[i]->cleanup();
- }
-}
-
-int hpsb_add_extra_config_roms(struct hpsb_host *host)
-{
- int i, error = 0;
-
- for (i = 0; config_rom_entries[i]; i++) {
- if (config_rom_entries[i]->add(host)) {
- HPSB_ERR("fw-host%d: Failed to attach config rom entry `%s'",
- host->id, config_rom_entries[i]->name);
- error = -1;
- } else {
- host->config_roms |= config_rom_entries[i]->flag;
- host->update_config_rom = 1;
}
- }
return error;
}
-void hpsb_remove_extra_config_roms(struct hpsb_host *host)
+/* Cleanup all config roms */
+void hpsb_cleanup_config_roms(void)
{
int i;
- for (i = 0; config_rom_entries[i]; i++) {
- if (!(host->config_roms & config_rom_entries[i]->flag))
- continue;
-
- config_rom_entries[i]->remove(host);
-
- host->config_roms &= ~config_rom_entries[i]->flag;
- host->update_config_rom = 1;
- }
+ for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
+ config_rom_entries[i]->cleanup();
}
diff --git a/drivers/ieee1394/config_roms.h b/drivers/ieee1394/config_roms.h
index 0a70544cfe6..1f5cd1f16c4 100644
--- a/drivers/ieee1394/config_roms.h
+++ b/drivers/ieee1394/config_roms.h
@@ -1,27 +1,19 @@
#ifndef _IEEE1394_CONFIG_ROMS_H
#define _IEEE1394_CONFIG_ROMS_H
-#include "ieee1394_types.h"
-#include "hosts.h"
+struct hpsb_host;
-/* The default host entry. This must succeed. */
int hpsb_default_host_entry(struct hpsb_host *host);
-
-/* Initialize all config roms */
int hpsb_init_config_roms(void);
-
-/* Cleanup all config roms */
void hpsb_cleanup_config_roms(void);
-/* Add extra config roms to specified host */
-int hpsb_add_extra_config_roms(struct hpsb_host *host);
-
-/* Remove extra config roms from specified host */
-void hpsb_remove_extra_config_roms(struct hpsb_host *host);
-
-
/* List of flags to check if a host contains a certain extra config rom
* entry. Available in the host->config_roms member. */
#define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001
+#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
+int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
+void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
+#endif
+
#endif /* _IEEE1394_CONFIG_ROMS_H */
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index c28f639823d..d08166bda1c 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -31,12 +31,13 @@
/* TODO List:
* - Verify interface consistency: i.e., public functions that take a size
* parameter expect size to be in bytes.
- * - Convenience functions for reading a block of data from a given offset.
*/
-#ifndef __KERNEL__
-#include <string.h>
-#endif
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/bug.h>
+#include <asm/byteorder.h>
#include "csr1212.h"
@@ -46,7 +47,7 @@
#define __C (1 << CSR1212_KV_TYPE_CSR_OFFSET)
#define __D (1 << CSR1212_KV_TYPE_DIRECTORY)
#define __L (1 << CSR1212_KV_TYPE_LEAF)
-static const u_int8_t csr1212_key_id_type_map[0x30] = {
+static const u8 csr1212_key_id_type_map[0x30] = {
__C, /* used by Apple iSight */
__D | __L, /* Descriptor */
__I | __D | __L, /* Bus_Dependent_Info */
@@ -82,10 +83,10 @@ static const u_int8_t csr1212_key_id_type_map[0x30] = {
#undef __L
-#define quads_to_bytes(_q) ((_q) * sizeof(u_int32_t))
-#define bytes_to_quads(_b) (((_b) + sizeof(u_int32_t) - 1) / sizeof(u_int32_t))
+#define quads_to_bytes(_q) ((_q) * sizeof(u32))
+#define bytes_to_quads(_b) (((_b) + sizeof(u32) - 1) / sizeof(u32))
-static inline void free_keyval(struct csr1212_keyval *kv)
+static void free_keyval(struct csr1212_keyval *kv)
{
if ((kv->key.type == CSR1212_KV_TYPE_LEAF) &&
(kv->key.id != CSR1212_KV_ID_EXTENDED_ROM))
@@ -94,14 +95,14 @@ static inline void free_keyval(struct csr1212_keyval *kv)
CSR1212_FREE(kv);
}
-static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length)
+static u16 csr1212_crc16(const u32 *buffer, size_t length)
{
int shift;
- u_int32_t data;
- u_int16_t sum, crc = 0;
+ u32 data;
+ u16 sum, crc = 0;
for (; length; length--) {
- data = CSR1212_BE32_TO_CPU(*buffer);
+ data = be32_to_cpu(*buffer);
buffer++;
for (shift = 28; shift >= 0; shift -= 4 ) {
sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
@@ -110,21 +111,18 @@ static u_int16_t csr1212_crc16(const u_int32_t *buffer, size_t length)
crc &= 0xffff;
}
- return CSR1212_CPU_TO_BE16(crc);
+ return cpu_to_be16(crc);
}
-#if 0
-/* Microsoft computes the CRC with the bytes in reverse order. Therefore we
- * have a special version of the CRC algorithm to account for their buggy
- * software. */
-static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
+/* Microsoft computes the CRC with the bytes in reverse order. */
+static u16 csr1212_msft_crc16(const u32 *buffer, size_t length)
{
int shift;
- u_int32_t data;
- u_int16_t sum, crc = 0;
+ u32 data;
+ u16 sum, crc = 0;
for (; length; length--) {
- data = CSR1212_LE32_TO_CPU(*buffer);
+ data = le32_to_cpu(*buffer);
buffer++;
for (shift = 28; shift >= 0; shift -= 4 ) {
sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
@@ -133,38 +131,35 @@ static u_int16_t csr1212_msft_crc16(const u_int32_t *buffer, size_t length)
crc &= 0xffff;
}
- return CSR1212_CPU_TO_BE16(crc);
+ return cpu_to_be16(crc);
}
-#endif
-static inline struct csr1212_dentry *csr1212_find_keyval(struct csr1212_keyval *dir,
- struct csr1212_keyval *kv)
+static struct csr1212_dentry *
+csr1212_find_keyval(struct csr1212_keyval *dir, struct csr1212_keyval *kv)
{
struct csr1212_dentry *pos;
for (pos = dir->value.directory.dentries_head;
- pos != NULL; pos = pos->next) {
+ pos != NULL; pos = pos->next)
if (pos->kv == kv)
return pos;
- }
return NULL;
}
-
-static inline struct csr1212_keyval *csr1212_find_keyval_offset(struct csr1212_keyval *kv_list,
- u_int32_t offset)
+static struct csr1212_keyval *
+csr1212_find_keyval_offset(struct csr1212_keyval *kv_list, u32 offset)
{
struct csr1212_keyval *kv;
- for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next) {
+ for (kv = kv_list->next; kv && (kv != kv_list); kv = kv->next)
if (kv->offset == offset)
return kv;
- }
return NULL;
}
/* Creation Routines */
+
struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
size_t bus_info_size, void *private)
{
@@ -202,27 +197,17 @@ struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
return csr;
}
-
-
void csr1212_init_local_csr(struct csr1212_csr *csr,
- const u_int32_t *bus_info_data, int max_rom)
+ const u32 *bus_info_data, int max_rom)
{
static const int mr_map[] = { 4, 64, 1024, 0 };
-#ifdef __KERNEL__
BUG_ON(max_rom & ~0x3);
csr->max_rom = mr_map[max_rom];
-#else
- if (max_rom & ~0x3) /* caller supplied invalid argument */
- csr->max_rom = 0;
- else
- csr->max_rom = mr_map[max_rom];
-#endif
memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
}
-
-static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
+static struct csr1212_keyval *csr1212_new_keyval(u8 type, u8 key)
{
struct csr1212_keyval *kv;
@@ -246,10 +231,11 @@ static struct csr1212_keyval *csr1212_new_keyval(u_int8_t type, u_int8_t key)
return kv;
}
-struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value)
+struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value)
{
- struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
+ struct csr1212_keyval *kv;
+ kv = csr1212_new_keyval(CSR1212_KV_TYPE_IMMEDIATE, key);
if (!kv)
return NULL;
@@ -258,10 +244,12 @@ struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value)
return kv;
}
-struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t data_len)
+static struct csr1212_keyval *
+csr1212_new_leaf(u8 key, const void *data, size_t data_len)
{
- struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
+ struct csr1212_keyval *kv;
+ kv = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, key);
if (!kv)
return NULL;
@@ -285,10 +273,12 @@ struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data, size_t d
return kv;
}
-struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset)
+static struct csr1212_keyval *
+csr1212_new_csr_offset(u8 key, u32 csr_offset)
{
- struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
+ struct csr1212_keyval *kv;
+ kv = csr1212_new_keyval(CSR1212_KV_TYPE_CSR_OFFSET, key);
if (!kv)
return NULL;
@@ -299,10 +289,11 @@ struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key, u_int32_t csr_offset
return kv;
}
-struct csr1212_keyval *csr1212_new_directory(u_int8_t key)
+struct csr1212_keyval *csr1212_new_directory(u8 key)
{
- struct csr1212_keyval *kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
+ struct csr1212_keyval *kv;
+ kv = csr1212_new_keyval(CSR1212_KV_TYPE_DIRECTORY, key);
if (!kv)
return NULL;
@@ -314,43 +305,29 @@ struct csr1212_keyval *csr1212_new_directory(u_int8_t key)
return kv;
}
-int csr1212_associate_keyval(struct csr1212_keyval *kv,
- struct csr1212_keyval *associate)
+void csr1212_associate_keyval(struct csr1212_keyval *kv,
+ struct csr1212_keyval *associate)
{
- if (!kv || !associate)
- return CSR1212_EINVAL;
-
- if (kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
- (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
- associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
- associate->key.id < 0x30))
- return CSR1212_EINVAL;
-
- if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_KEY)
- return CSR1212_EINVAL;
-
- if (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
- associate->key.id != CSR1212_KV_ID_EXTENDED_DATA)
- return CSR1212_EINVAL;
-
- if (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
- kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID)
- return CSR1212_EINVAL;
-
- if (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
- kv->key.id != CSR1212_KV_ID_EXTENDED_KEY)
- return CSR1212_EINVAL;
+ BUG_ON(!kv || !associate || kv->key.id == CSR1212_KV_ID_DESCRIPTOR ||
+ (associate->key.id != CSR1212_KV_ID_DESCRIPTOR &&
+ associate->key.id != CSR1212_KV_ID_DEPENDENT_INFO &&
+ associate->key.id != CSR1212_KV_ID_EXTENDED_KEY &&
+ associate->key.id != CSR1212_KV_ID_EXTENDED_DATA &&
+ associate->key.id < 0x30) ||
+ (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID &&
+ associate->key.id != CSR1212_KV_ID_EXTENDED_KEY) ||
+ (kv->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
+ associate->key.id != CSR1212_KV_ID_EXTENDED_DATA) ||
+ (associate->key.id == CSR1212_KV_ID_EXTENDED_KEY &&
+ kv->key.id != CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) ||
+ (associate->key.id == CSR1212_KV_ID_EXTENDED_DATA &&
+ kv->key.id != CSR1212_KV_ID_EXTENDED_KEY));
if (kv->associate)
csr1212_release_keyval(kv->associate);
associate->refcnt++;
kv->associate = associate;
-
- return CSR1212_SUCCESS;
}
int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
@@ -358,12 +335,11 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
{
struct csr1212_dentry *dentry;
- if (!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY)
- return CSR1212_EINVAL;
+ BUG_ON(!kv || !dir || dir->key.type != CSR1212_KV_TYPE_DIRECTORY);
dentry = CSR1212_MALLOC(sizeof(*dentry));
if (!dentry)
- return CSR1212_ENOMEM;
+ return -ENOMEM;
dentry->kv = kv;
@@ -382,66 +358,22 @@ int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
return CSR1212_SUCCESS;
}
-struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec, u_int32_t key,
- u_int32_t value)
-{
- struct csr1212_keyval *kvs, *kvk, *kvv;
-
- kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec);
- kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key);
- kvv = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_DATA, value);
-
- if (!kvs || !kvk || !kvv) {
- if (kvs)
- free_keyval(kvs);
- if (kvk)
- free_keyval(kvk);
- if (kvv)
- free_keyval(kvv);
- return NULL;
- }
-
- /* Don't keep a local reference to the extended key or value. */
- kvk->refcnt = 0;
- kvv->refcnt = 0;
-
- csr1212_associate_keyval(kvk, kvv);
- csr1212_associate_keyval(kvs, kvk);
-
- return kvs;
-}
-
-struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec, u_int32_t key,
- const void *data, size_t data_len)
-{
- struct csr1212_keyval *kvs, *kvk, *kvv;
-
- kvs = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID, spec);
- kvk = csr1212_new_immediate(CSR1212_KV_ID_EXTENDED_KEY, key);
- kvv = csr1212_new_leaf(CSR1212_KV_ID_EXTENDED_DATA, data, data_len);
-
- if (!kvs || !kvk || !kvv) {
- if (kvs)
- free_keyval(kvs);
- if (kvk)
- free_keyval(kvk);
- if (kvv)
- free_keyval(kvv);
- return NULL;
- }
-
- /* Don't keep a local reference to the extended key or value. */
- kvk->refcnt = 0;
- kvv->refcnt = 0;
-
- csr1212_associate_keyval(kvk, kvv);
- csr1212_associate_keyval(kvs, kvk);
-
- return kvs;
-}
-
-struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t specifier_id,
- const void *data, size_t data_len)
+#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
+ (&((kv)->value.leaf.data[1]))
+
+#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
+ ((kv)->value.leaf.data[0] = \
+ cpu_to_be32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
+ ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
+#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
+ ((kv)->value.leaf.data[0] = \
+ cpu_to_be32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
+ CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
+ ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
+
+static struct csr1212_keyval *
+csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
+ const void *data, size_t data_len)
{
struct csr1212_keyval *kv;
@@ -453,197 +385,72 @@ struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype, u_int32_t spe
CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
- if (data) {
+ if (data)
memcpy(CSR1212_DESCRIPTOR_LEAF_DATA(kv), data, data_len);
- }
-
- return kv;
-}
-
-
-struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth,
- u_int16_t cset,
- u_int16_t language,
- const void *data,
- size_t data_len)
-{
- struct csr1212_keyval *kv;
- char *lstr;
-
- kv = csr1212_new_descriptor_leaf(0, 0, NULL, data_len +
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
- if (!kv)
- return NULL;
-
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, cwidth);
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, cset);
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
-
- lstr = (char*)CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
-
- /* make sure last quadlet is zeroed out */
- *((u_int32_t*)&(lstr[(data_len - 1) & ~0x3])) = 0;
-
- /* don't copy the NUL terminator */
- memcpy(lstr, data, data_len);
return kv;
}
+/* Check if string conforms to minimal ASCII as per IEEE 1212 clause 7.4 */
static int csr1212_check_minimal_ascii(const char *s)
{
static const char minimal_ascii_table[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
- 0x00, 0x00, 0x0a, 0x00, 0x0C, 0x0D, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20, 0x21, 0x22, 0x00, 0x00, 0x25, 0x26, 0x27,
- 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
- 0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x5f,
- 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
- 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
- 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 1 2 4 8 16 32 64 128 */
+ 128, /* --, --, --, --, --, --, --, 07, */
+ 4 + 16 + 32, /* --, --, 0a, --, 0C, 0D, --, --, */
+ 0, /* --, --, --, --, --, --, --, --, */
+ 0, /* --, --, --, --, --, --, --, --, */
+ 255 - 8 - 16, /* 20, 21, 22, --, --, 25, 26, 27, */
+ 255, /* 28, 29, 2a, 2b, 2c, 2d, 2e, 2f, */
+ 255, /* 30, 31, 32, 33, 34, 35, 36, 37, */
+ 255, /* 38, 39, 3a, 3b, 3c, 3d, 3e, 3f, */
+ 255, /* 40, 41, 42, 43, 44, 45, 46, 47, */
+ 255, /* 48, 49, 4a, 4b, 4c, 4d, 4e, 4f, */
+ 255, /* 50, 51, 52, 53, 54, 55, 56, 57, */
+ 1 + 2 + 4 + 128, /* 58, 59, 5a, --, --, --, --, 5f, */
+ 255 - 1, /* --, 61, 62, 63, 64, 65, 66, 67, */
+ 255, /* 68, 69, 6a, 6b, 6c, 6d, 6e, 6f, */
+ 255, /* 70, 71, 72, 73, 74, 75, 76, 77, */
+ 1 + 2 + 4, /* 78, 79, 7a, --, --, --, --, --, */
};
+ int i, j;
+
for (; *s; s++) {
- if (minimal_ascii_table[*s & 0x7F] != *s)
- return -1; /* failed */
+ i = *s >> 3; /* i = *s / 8; */
+ j = 1 << (*s & 3); /* j = 1 << (*s % 8); */
+
+ if (i >= ARRAY_SIZE(minimal_ascii_table) ||
+ !(minimal_ascii_table[i] & j))
+ return -EINVAL;
}
- /* String conforms to minimal-ascii, as specified by IEEE 1212,
- * par. 7.4 */
return 0;
}
+/* IEEE 1212 clause 7.5.4.1 textual descriptors (English, minimal ASCII) */
struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s)
{
- /* Check if string conform to minimal_ascii format */
- if (csr1212_check_minimal_ascii(s))
- return NULL;
-
- /* IEEE 1212, par. 7.5.4.1 Textual descriptors (minimal ASCII) */
- return csr1212_new_textual_descriptor_leaf(0, 0, 0, s, strlen(s));
-}
-
-struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
- u_int8_t palette_depth,
- u_int8_t color_space,
- u_int16_t language,
- u_int16_t hscan,
- u_int16_t vscan,
- u_int32_t *palette,
- u_int32_t *pixels)
-{
- static const int pd[4] = { 0, 4, 16, 256 };
- static const int cs[16] = { 4, 2 };
struct csr1212_keyval *kv;
- int palette_size;
- int pixel_size = (hscan * vscan + 3) & ~0x3;
+ u32 *text;
+ size_t str_len, quads;
- if (!pixels || (!palette && palette_depth) ||
- (palette_depth & ~0x3) || (color_space & ~0xf))
+ if (!s || !*s || csr1212_check_minimal_ascii(s))
return NULL;
- palette_size = pd[palette_depth] * cs[color_space];
-
- kv = csr1212_new_descriptor_leaf(1, 0, NULL,
- palette_size + pixel_size +
- CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD);
+ str_len = strlen(s);
+ quads = bytes_to_quads(str_len);
+ kv = csr1212_new_descriptor_leaf(0, 0, NULL, quads_to_bytes(quads) +
+ CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD);
if (!kv)
return NULL;
- CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version);
- CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth);
- CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space);
- CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language);
- CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan);
- CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan);
-
- if (palette_size)
- memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv), palette,
- palette_size);
-
- memcpy(CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(kv), pixels, pixel_size);
-
- return kv;
-}
-
-struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size,
- u_int64_t address)
-{
- struct csr1212_keyval *kv;
-
- /* IEEE 1212, par. 7.5.4.3 Modifiable descriptors */
- kv = csr1212_new_leaf(CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR, NULL, sizeof(u_int64_t));
- if(!kv)
- return NULL;
-
- CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, max_size);
- CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, address);
- CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, address);
+ kv->value.leaf.data[1] = 0; /* width, character_set, language */
+ text = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv);
+ text[quads - 1] = 0; /* padding */
+ memcpy(text, s, str_len);
return kv;
}
-static int csr1212_check_keyword(const char *s)
-{
- for (; *s; s++) {
-
- if (('A' <= *s) && (*s <= 'Z'))
- continue;
- if (('0' <= *s) && (*s <= '9'))
- continue;
- if (*s == '-')
- continue;
-
- return -1; /* failed */
- }
- /* String conforms to keyword, as specified by IEEE 1212,
- * par. 7.6.5 */
- return CSR1212_SUCCESS;
-}
-
-struct csr1212_keyval *csr1212_new_keyword_leaf(int strc, const char *strv[])
-{
- struct csr1212_keyval *kv;
- char *buffer;
- int i, data_len = 0;
-
- /* Check all keywords to see if they conform to restrictions:
- * Only the following characters is allowed ['A'..'Z','0'..'9','-']
- * Each word is zero-terminated.
- * Also calculate the total length of the keywords.
- */
- for (i = 0; i < strc; i++) {
- if (!strv[i] || csr1212_check_keyword(strv[i])) {
- return NULL;
- }
- data_len += strlen(strv[i]) + 1; /* Add zero-termination char. */
- }
-
- /* IEEE 1212, par. 7.6.5 Keyword leaves */
- kv = csr1212_new_leaf(CSR1212_KV_ID_KEYWORD, NULL, data_len);
- if (!kv)
- return NULL;
-
- buffer = (char *)kv->value.leaf.data;
-
- /* make sure last quadlet is zeroed out */
- *((u_int32_t*)&(buffer[(data_len - 1) & ~0x3])) = 0;
-
- /* Copy keyword(s) into leaf data buffer */
- for (i = 0; i < strc; i++) {
- int len = strlen(strv[i]) + 1;
- memcpy(buffer, strv[i], len);
- buffer += len;
- }
- return kv;
-}
-
/* Destruction Routines */
@@ -674,23 +481,12 @@ void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
csr1212_release_keyval(kv);
}
-
-void csr1212_disassociate_keyval(struct csr1212_keyval *kv)
-{
- if (kv->associate) {
- csr1212_release_keyval(kv->associate);
- }
-
- kv->associate = NULL;
-}
-
-
/* This function is used to free the memory taken by a keyval. If the given
* keyval is a directory type, then any keyvals contained in that directory
* will be destroyed as well if their respective refcnts are 0. By means of
* list manipulation, this routine will descend a directory structure in a
* non-recursive manner. */
-void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
+static void csr1212_destroy_keyval(struct csr1212_keyval *kv)
{
struct csr1212_keyval *k, *a;
struct csr1212_dentry dentry;
@@ -715,11 +511,13 @@ void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
a = k->associate;
if (k->key.type == CSR1212_KV_TYPE_DIRECTORY) {
- /* If the current entry is a directory, then move all
+ /* If the current entry is a directory, move all
* the entries to the destruction list. */
if (k->value.directory.dentries_head) {
- tail->next = k->value.directory.dentries_head;
- k->value.directory.dentries_head->prev = tail;
+ tail->next =
+ k->value.directory.dentries_head;
+ k->value.directory.dentries_head->prev =
+ tail;
tail = k->value.directory.dentries_tail;
}
}
@@ -729,15 +527,22 @@ void _csr1212_destroy_keyval(struct csr1212_keyval *kv)
head = head->next;
if (head) {
- if (head->prev && head->prev != &dentry) {
+ if (head->prev && head->prev != &dentry)
CSR1212_FREE(head->prev);
- }
head->prev = NULL;
- } else if (tail != &dentry)
+ } else if (tail != &dentry) {
CSR1212_FREE(tail);
+ }
}
}
+void csr1212_release_keyval(struct csr1212_keyval *kv)
+{
+ if (kv->refcnt > 1)
+ kv->refcnt--;
+ else
+ csr1212_destroy_keyval(kv);
+}
void csr1212_destroy_csr(struct csr1212_csr *csr)
{
@@ -763,49 +568,51 @@ void csr1212_destroy_csr(struct csr1212_csr *csr)
}
-
/* CSR Image Creation */
static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
{
struct csr1212_csr_rom_cache *cache;
- u_int64_t csr_addr;
+ u64 csr_addr;
- if (!csr || !csr->ops || !csr->ops->allocate_addr_range ||
- !csr->ops->release_addr || csr->max_rom < 1)
- return CSR1212_EINVAL;
+ BUG_ON(!csr || !csr->ops || !csr->ops->allocate_addr_range ||
+ !csr->ops->release_addr || csr->max_rom < 1);
/* ROM size must be a multiple of csr->max_rom */
romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
- csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom, csr->private);
- if (csr_addr == CSR1212_INVALID_ADDR_SPACE) {
- return CSR1212_ENOMEM;
- }
+ csr_addr = csr->ops->allocate_addr_range(romsize, csr->max_rom,
+ csr->private);
+ if (csr_addr == CSR1212_INVALID_ADDR_SPACE)
+ return -ENOMEM;
+
if (csr_addr < CSR1212_REGISTER_SPACE_BASE) {
/* Invalid address returned from allocate_addr_range(). */
csr->ops->release_addr(csr_addr, csr->private);
- return CSR1212_ENOMEM;
+ return -ENOMEM;
}
- cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE, romsize);
+ cache = csr1212_rom_cache_malloc(csr_addr - CSR1212_REGISTER_SPACE_BASE,
+ romsize);
if (!cache) {
csr->ops->release_addr(csr_addr, csr->private);
- return CSR1212_ENOMEM;
+ return -ENOMEM;
}
- cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF, CSR1212_KV_ID_EXTENDED_ROM);
+ cache->ext_rom = csr1212_new_keyval(CSR1212_KV_TYPE_LEAF,
+ CSR1212_KV_ID_EXTENDED_ROM);
if (!cache->ext_rom) {
csr->ops->release_addr(csr_addr, csr->private);
CSR1212_FREE(cache);
- return CSR1212_ENOMEM;
+ return -ENOMEM;
}
- if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) != CSR1212_SUCCESS) {
+ if (csr1212_attach_keyval_to_directory(csr->root_kv, cache->ext_rom) !=
+ CSR1212_SUCCESS) {
csr1212_release_keyval(cache->ext_rom);
csr->ops->release_addr(csr_addr, csr->private);
CSR1212_FREE(cache);
- return CSR1212_ENOMEM;
+ return -ENOMEM;
}
cache->ext_rom->offset = csr_addr - CSR1212_REGISTER_SPACE_BASE;
cache->ext_rom->value.leaf.len = -1;
@@ -818,8 +625,8 @@ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
return CSR1212_SUCCESS;
}
-static inline void csr1212_remove_cache(struct csr1212_csr *csr,
- struct csr1212_csr_rom_cache *cache)
+static void csr1212_remove_cache(struct csr1212_csr *csr,
+ struct csr1212_csr_rom_cache *cache)
{
if (csr->cache_head == cache)
csr->cache_head = cache->next;
@@ -832,7 +639,8 @@ static inline void csr1212_remove_cache(struct csr1212_csr *csr,
cache->next->prev = cache->prev;
if (cache->ext_rom) {
- csr1212_detach_keyval_from_directory(csr->root_kv, cache->ext_rom);
+ csr1212_detach_keyval_from_directory(csr->root_kv,
+ cache->ext_rom);
csr1212_release_keyval(cache->ext_rom);
}
@@ -852,28 +660,29 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
dentry = dentry->next) {
for (dkv = dentry->kv; dkv; dkv = dkv->associate) {
/* Special Case: Extended Key Specifier_ID */
- if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
- if (last_extkey_spec == NULL) {
+ if (dkv->key.id ==
+ CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
+ if (last_extkey_spec == NULL)
last_extkey_spec = dkv;
- } else if (dkv->value.immediate != last_extkey_spec->value.immediate) {
+ else if (dkv->value.immediate !=
+ last_extkey_spec->value.immediate)
last_extkey_spec = dkv;
- } else {
+ else
continue;
- }
/* Special Case: Extended Key */
} else if (dkv->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
- if (last_extkey == NULL) {
+ if (last_extkey == NULL)
last_extkey = dkv;
- } else if (dkv->value.immediate != last_extkey->value.immediate) {
+ else if (dkv->value.immediate !=
+ last_extkey->value.immediate)
last_extkey = dkv;
- } else {
+ else
continue;
- }
}
num_entries += 1;
- switch(dkv->key.type) {
+ switch (dkv->key.type) {
default:
case CSR1212_KV_TYPE_IMMEDIATE:
case CSR1212_KV_TYPE_CSR_OFFSET:
@@ -891,8 +700,9 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
/* Special case: Extended ROM leafs */
if (dkv->key.id == CSR1212_KV_ID_EXTENDED_ROM) {
dkv->value.leaf.len = -1;
- /* Don't add Extended ROM leafs in the layout list,
- * they are handled differently. */
+ /* Don't add Extended ROM leafs in the
+ * layout list, they are handled
+ * differently. */
break;
}
@@ -908,20 +718,21 @@ static int csr1212_generate_layout_subdir(struct csr1212_keyval *dir,
return num_entries;
}
-size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
+static size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
{
struct csr1212_keyval *ltail = kv;
size_t agg_size = 0;
- while(kv) {
- switch(kv->key.type) {
+ while (kv) {
+ switch (kv->key.type) {
case CSR1212_KV_TYPE_LEAF:
/* Add 1 quadlet for crc/len field */
agg_size += kv->value.leaf.len + 1;
break;
case CSR1212_KV_TYPE_DIRECTORY:
- kv->value.directory.len = csr1212_generate_layout_subdir(kv, &ltail);
+ kv->value.directory.len =
+ csr1212_generate_layout_subdir(kv, &ltail);
/* Add 1 quadlet for crc/len field */
agg_size += kv->value.directory.len + 1;
break;
@@ -931,9 +742,9 @@ size_t csr1212_generate_layout_order(struct csr1212_keyval *kv)
return quads_to_bytes(agg_size);
}
-struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
- struct csr1212_keyval *start_kv,
- int start_pos)
+static struct csr1212_keyval *
+csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
+ struct csr1212_keyval *start_kv, int start_pos)
{
struct csr1212_keyval *kv = start_kv;
struct csr1212_keyval *okv = start_kv;
@@ -942,13 +753,12 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *
cache->layout_head = kv;
- while(kv && pos < cache->size) {
+ while (kv && pos < cache->size) {
/* Special case: Extended ROM leafs */
- if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
+ if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
kv->offset = cache->offset + pos;
- }
- switch(kv->key.type) {
+ switch (kv->key.type) {
case CSR1212_KV_TYPE_LEAF:
kv_len = kv->value.leaf.len;
break;
@@ -959,6 +769,7 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *
default:
/* Should never get here */
+ WARN_ON(1);
break;
}
@@ -972,46 +783,55 @@ struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *
}
cache->layout_tail = okv;
- cache->len = (okv->offset - cache->offset) + quads_to_bytes(okv_len + 1);
+ cache->len = okv->offset - cache->offset + quads_to_bytes(okv_len + 1);
return kv;
}
-static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir,
- u_int32_t *data_buffer)
+#define CSR1212_KV_KEY_SHIFT 24
+#define CSR1212_KV_KEY_TYPE_SHIFT 6
+#define CSR1212_KV_KEY_ID_MASK 0x3f
+#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* after shift */
+
+static void
+csr1212_generate_tree_subdir(struct csr1212_keyval *dir, u32 *data_buffer)
{
struct csr1212_dentry *dentry;
struct csr1212_keyval *last_extkey_spec = NULL;
struct csr1212_keyval *last_extkey = NULL;
int index = 0;
- for (dentry = dir->value.directory.dentries_head; dentry; dentry = dentry->next) {
+ for (dentry = dir->value.directory.dentries_head;
+ dentry;
+ dentry = dentry->next) {
struct csr1212_keyval *a;
for (a = dentry->kv; a; a = a->associate) {
- u_int32_t value = 0;
+ u32 value = 0;
/* Special Case: Extended Key Specifier_ID */
- if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
- if (last_extkey_spec == NULL) {
+ if (a->key.id ==
+ CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID) {
+ if (last_extkey_spec == NULL)
last_extkey_spec = a;
- } else if (a->value.immediate != last_extkey_spec->value.immediate) {
+ else if (a->value.immediate !=
+ last_extkey_spec->value.immediate)
last_extkey_spec = a;
- } else {
+ else
continue;
- }
+
/* Special Case: Extended Key */
} else if (a->key.id == CSR1212_KV_ID_EXTENDED_KEY) {
- if (last_extkey == NULL) {
+ if (last_extkey == NULL)
last_extkey = a;
- } else if (a->value.immediate != last_extkey->value.immediate) {
+ else if (a->value.immediate !=
+ last_extkey->value.immediate)
last_extkey = a;
- } else {
+ else
continue;
- }
}
- switch(a->key.type) {
+ switch (a->key.type) {
case CSR1212_KV_TYPE_IMMEDIATE:
value = a->value.immediate;
break;
@@ -1030,32 +850,46 @@ static void csr1212_generate_tree_subdir(struct csr1212_keyval *dir,
break;
default:
/* Should never get here */
- break; /* GDB breakpoint */
+ WARN_ON(1);
+ break;
}
- value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) << CSR1212_KV_KEY_SHIFT;
+ value |= (a->key.id & CSR1212_KV_KEY_ID_MASK) <<
+ CSR1212_KV_KEY_SHIFT;
value |= (a->key.type & CSR1212_KV_KEY_TYPE_MASK) <<
- (CSR1212_KV_KEY_SHIFT + CSR1212_KV_KEY_TYPE_SHIFT);
- data_buffer[index] = CSR1212_CPU_TO_BE32(value);
+ (CSR1212_KV_KEY_SHIFT +
+ CSR1212_KV_KEY_TYPE_SHIFT);
+ data_buffer[index] = cpu_to_be32(value);
index++;
}
}
}
-void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
+struct csr1212_keyval_img {
+ u16 length;
+ u16 crc;
+
+ /* Must be last */
+ u32 data[0]; /* older gcc can't handle [] which is standard */
+};
+
+static void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
{
struct csr1212_keyval *kv, *nkv;
struct csr1212_keyval_img *kvi;
- for (kv = cache->layout_head; kv != cache->layout_tail->next; kv = nkv) {
- kvi = (struct csr1212_keyval_img *)
- (cache->data + bytes_to_quads(kv->offset - cache->offset));
- switch(kv->key.type) {
+ for (kv = cache->layout_head;
+ kv != cache->layout_tail->next;
+ kv = nkv) {
+ kvi = (struct csr1212_keyval_img *)(cache->data +
+ bytes_to_quads(kv->offset - cache->offset));
+ switch (kv->key.type) {
default:
case CSR1212_KV_TYPE_IMMEDIATE:
case CSR1212_KV_TYPE_CSR_OFFSET:
/* Should never get here */
- break; /* GDB breakpoint */
+ WARN_ON(1);
+ break;
case CSR1212_KV_TYPE_LEAF:
/* Don't copy over Extended ROM areas, they are
@@ -1064,15 +898,16 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
memcpy(kvi->data, kv->value.leaf.data,
quads_to_bytes(kv->value.leaf.len));
- kvi->length = CSR1212_CPU_TO_BE16(kv->value.leaf.len);
+ kvi->length = cpu_to_be16(kv->value.leaf.len);
kvi->crc = csr1212_crc16(kvi->data, kv->value.leaf.len);
break;
case CSR1212_KV_TYPE_DIRECTORY:
csr1212_generate_tree_subdir(kv, kvi->data);
- kvi->length = CSR1212_CPU_TO_BE16(kv->value.directory.len);
- kvi->crc = csr1212_crc16(kvi->data, kv->value.directory.len);
+ kvi->length = cpu_to_be16(kv->value.directory.len);
+ kvi->crc = csr1212_crc16(kvi->data,
+ kv->value.directory.len);
break;
}
@@ -1086,6 +921,10 @@ void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache)
}
}
+/* This size is arbitrarily chosen.
+ * The struct overhead is subtracted for more economic allocations. */
+#define CSR1212_EXTENDED_ROM_SIZE (2048 - sizeof(struct csr1212_csr_rom_cache))
+
int csr1212_generate_csr_image(struct csr1212_csr *csr)
{
struct csr1212_bus_info_block_img *bi;
@@ -1095,8 +934,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
int ret;
int init_offset;
- if (!csr)
- return CSR1212_EINVAL;
+ BUG_ON(!csr);
cache = csr->cache_head;
@@ -1113,18 +951,21 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
init_offset = csr->bus_info_len;
- for (kv = csr->root_kv, cache = csr->cache_head; kv; cache = cache->next) {
+ for (kv = csr->root_kv, cache = csr->cache_head;
+ kv;
+ cache = cache->next) {
if (!cache) {
/* Estimate approximate number of additional cache
* regions needed (it assumes that the cache holding
* the first 1K Config ROM space always exists). */
int est_c = agg_size / (CSR1212_EXTENDED_ROM_SIZE -
- (2 * sizeof(u_int32_t))) + 1;
+ (2 * sizeof(u32))) + 1;
/* Add additional cache regions, extras will be
* removed later */
for (; est_c; est_c--) {
- ret = csr1212_append_new_cache(csr, CSR1212_EXTENDED_ROM_SIZE);
+ ret = csr1212_append_new_cache(csr,
+ CSR1212_EXTENDED_ROM_SIZE);
if (ret != CSR1212_SUCCESS)
return ret;
}
@@ -1136,7 +977,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
}
kv = csr1212_generate_positions(cache, kv, init_offset);
agg_size -= cache->len;
- init_offset = sizeof(u_int32_t);
+ init_offset = sizeof(u32);
}
/* Remove unused, excess cache regions */
@@ -1149,15 +990,14 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
/* Go through the list backward so that when done, the correct CRC
* will be calculated for the Extended ROM areas. */
- for(cache = csr->cache_tail; cache; cache = cache->prev) {
+ for (cache = csr->cache_tail; cache; cache = cache->prev) {
/* Only Extended ROM caches should have this set. */
if (cache->ext_rom) {
int leaf_size;
/* Make sure the Extended ROM leaf is a multiple of
* max_rom in size. */
- if (csr->max_rom < 1)
- return CSR1212_EINVAL;
+ BUG_ON(csr->max_rom < 1);
leaf_size = (cache->len + (csr->max_rom - 1)) &
~(csr->max_rom - 1);
@@ -1166,7 +1006,7 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
leaf_size - cache->len);
/* Subtract leaf header */
- leaf_size -= sizeof(u_int32_t);
+ leaf_size -= sizeof(u32);
/* Update the Extended ROM leaf length */
cache->ext_rom->value.leaf.len =
@@ -1184,33 +1024,31 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
/* Set the length and CRC of the extended ROM. */
struct csr1212_keyval_img *kvi =
(struct csr1212_keyval_img*)cache->data;
+ u16 len = bytes_to_quads(cache->len) - 1;
- kvi->length = CSR1212_CPU_TO_BE16(bytes_to_quads(cache->len) - 1);
- kvi->crc = csr1212_crc16(kvi->data,
- bytes_to_quads(cache->len) - 1);
-
+ kvi->length = cpu_to_be16(len);
+ kvi->crc = csr1212_crc16(kvi->data, len);
}
}
return CSR1212_SUCCESS;
}
-int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer, u_int32_t len)
+int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer, u32 len)
{
struct csr1212_csr_rom_cache *cache;
- for (cache = csr->cache_head; cache; cache = cache->next) {
+ for (cache = csr->cache_head; cache; cache = cache->next)
if (offset >= cache->offset &&
(offset + len) <= (cache->offset + cache->size)) {
- memcpy(buffer,
- &cache->data[bytes_to_quads(offset - cache->offset)],
+ memcpy(buffer, &cache->data[
+ bytes_to_quads(offset - cache->offset)],
len);
return CSR1212_SUCCESS;
}
- }
- return CSR1212_ENOENT;
-}
+ return -ENOENT;
+}
/* Parse a chunk of data as a Config ROM */
@@ -1227,46 +1065,43 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
* Unfortunately, many IEEE 1394 devices do not abide by that, so the
* bus info block will be read 1 quadlet at a time. The rest of the
* ConfigROM will be read according to the max_rom field. */
- for (i = 0; i < csr->bus_info_len; i += sizeof(csr1212_quad_t)) {
+ for (i = 0; i < csr->bus_info_len; i += sizeof(u32)) {
ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- sizeof(csr1212_quad_t),
- &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
+ sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
+ csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
/* check ROM header's info_length */
if (i == 0 &&
- CSR1212_BE32_TO_CPU(csr->cache_head->data[0]) >> 24 !=
+ be32_to_cpu(csr->cache_head->data[0]) >> 24 !=
bytes_to_quads(csr->bus_info_len) - 1)
- return CSR1212_EINVAL;
+ return -EINVAL;
}
bi = (struct csr1212_bus_info_block_img*)csr->cache_head->data;
csr->crc_len = quads_to_bytes(bi->crc_length);
- /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that is not
- * always the case, so read the rest of the crc area 1 quadlet at a time. */
- for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(csr1212_quad_t)) {
+ /* IEEE 1212 recommends that crc_len be equal to bus_info_len, but that
+ * is not always the case, so read the rest of the crc area 1 quadlet at
+ * a time. */
+ for (i = csr->bus_info_len; i <= csr->crc_len; i += sizeof(u32)) {
ret = csr->ops->bus_read(csr, CSR1212_CONFIG_ROM_SPACE_BASE + i,
- sizeof(csr1212_quad_t),
- &csr->cache_head->data[bytes_to_quads(i)],
- csr->private);
+ sizeof(u32), &csr->cache_head->data[bytes_to_quads(i)],
+ csr->private);
if (ret != CSR1212_SUCCESS)
return ret;
}
-#if 0
- /* Apparently there are too many differnt wrong implementations of the
- * CRC algorithm that verifying them is moot. */
+ /* Apparently there are many different wrong implementations of the CRC
+ * algorithm. We don't fail, we just warn. */
if ((csr1212_crc16(bi->data, bi->crc_length) != bi->crc) &&
(csr1212_msft_crc16(bi->data, bi->crc_length) != bi->crc))
- return CSR1212_EINVAL;
-#endif
+ printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n");
cr = CSR1212_MALLOC(sizeof(*cr));
if (!cr)
- return CSR1212_ENOMEM;
+ return -ENOMEM;
cr->next = NULL;
cr->prev = NULL;
@@ -1279,21 +1114,26 @@ static int csr1212_parse_bus_info_block(struct csr1212_csr *csr)
return CSR1212_SUCCESS;
}
-static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
- csr1212_quad_t ki,
- u_int32_t kv_pos)
+#define CSR1212_KV_KEY(q) (be32_to_cpu(q) >> CSR1212_KV_KEY_SHIFT)
+#define CSR1212_KV_KEY_TYPE(q) (CSR1212_KV_KEY(q) >> CSR1212_KV_KEY_TYPE_SHIFT)
+#define CSR1212_KV_KEY_ID(q) (CSR1212_KV_KEY(q) & CSR1212_KV_KEY_ID_MASK)
+#define CSR1212_KV_VAL_MASK 0xffffff
+#define CSR1212_KV_VAL(q) (be32_to_cpu(q) & CSR1212_KV_VAL_MASK)
+
+static int
+csr1212_parse_dir_entry(struct csr1212_keyval *dir, u32 ki, u32 kv_pos)
{
int ret = CSR1212_SUCCESS;
struct csr1212_keyval *k = NULL;
- u_int32_t offset;
+ u32 offset;
- switch(CSR1212_KV_KEY_TYPE(ki)) {
+ switch (CSR1212_KV_KEY_TYPE(ki)) {
case CSR1212_KV_TYPE_IMMEDIATE:
k = csr1212_new_immediate(CSR1212_KV_KEY_ID(ki),
CSR1212_KV_VAL(ki));
if (!k) {
- ret = CSR1212_ENOMEM;
- goto fail;
+ ret = -ENOMEM;
+ goto out;
}
k->refcnt = 0; /* Don't keep local reference when parsing. */
@@ -1303,8 +1143,8 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
k = csr1212_new_csr_offset(CSR1212_KV_KEY_ID(ki),
CSR1212_KV_VAL(ki));
if (!k) {
- ret = CSR1212_ENOMEM;
- goto fail;
+ ret = -ENOMEM;
+ goto out;
}
k->refcnt = 0; /* Don't keep local reference when parsing. */
break;
@@ -1316,8 +1156,8 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
/* Uh-oh. Can't have a relative offset of 0 for Leaves
* or Directories. The Config ROM image is most likely
* messed up, so we'll just abort here. */
- ret = CSR1212_EIO;
- goto fail;
+ ret = -EIO;
+ goto out;
}
k = csr1212_find_keyval_offset(dir, offset);
@@ -1325,14 +1165,14 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
if (k)
break; /* Found it. */
- if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY) {
+ if (CSR1212_KV_KEY_TYPE(ki) == CSR1212_KV_TYPE_DIRECTORY)
k = csr1212_new_directory(CSR1212_KV_KEY_ID(ki));
- } else {
+ else
k = csr1212_new_leaf(CSR1212_KV_KEY_ID(ki), NULL, 0);
- }
+
if (!k) {
- ret = CSR1212_ENOMEM;
- goto fail;
+ ret = -ENOMEM;
+ goto out;
}
k->refcnt = 0; /* Don't keep local reference when parsing. */
k->valid = 0; /* Contents not read yet so it's not valid. */
@@ -1344,16 +1184,12 @@ static int csr1212_parse_dir_entry(struct csr1212_keyval *dir,
dir->next = k;
}
ret = csr1212_attach_keyval_to_directory(dir, k);
-
-fail:
- if (ret != CSR1212_SUCCESS) {
- if (k)
- free_keyval(k);
- }
+out:
+ if (ret != CSR1212_SUCCESS && k != NULL)
+ free_keyval(k);
return ret;
}
-
int csr1212_parse_keyval(struct csr1212_keyval *kv,
struct csr1212_csr_rom_cache *cache)
{
@@ -1362,24 +1198,20 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv,
int ret = CSR1212_SUCCESS;
int kvi_len;
- kvi = (struct csr1212_keyval_img*)&cache->data[bytes_to_quads(kv->offset -
- cache->offset)];
- kvi_len = CSR1212_BE16_TO_CPU(kvi->length);
+ kvi = (struct csr1212_keyval_img*)
+ &cache->data[bytes_to_quads(kv->offset - cache->offset)];
+ kvi_len = be16_to_cpu(kvi->length);
-#if 0
- /* Apparently there are too many differnt wrong implementations of the
- * CRC algorithm that verifying them is moot. */
+ /* Apparently there are many different wrong implementations of the CRC
+ * algorithm. We don't fail, we just warn. */
if ((csr1212_crc16(kvi->data, kvi_len) != kvi->crc) &&
- (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc)) {
- ret = CSR1212_EINVAL;
- goto fail;
- }
-#endif
+ (csr1212_msft_crc16(kvi->data, kvi_len) != kvi->crc))
+ printk(KERN_DEBUG "IEEE 1394 device has ROM CRC error\n");
- switch(kv->key.type) {
+ switch (kv->key.type) {
case CSR1212_KV_TYPE_DIRECTORY:
for (i = 0; i < kvi_len; i++) {
- csr1212_quad_t ki = kvi->data[i];
+ u32 ki = kvi->data[i];
/* Some devices put null entries in their unit
* directories. If we come across such an entry,
@@ -1387,76 +1219,72 @@ int csr1212_parse_keyval(struct csr1212_keyval *kv,
if (ki == 0x0)
continue;
ret = csr1212_parse_dir_entry(kv, ki,
- (kv->offset +
- quads_to_bytes(i + 1)));
+ kv->offset + quads_to_bytes(i + 1));
}
kv->value.directory.len = kvi_len;
break;
case CSR1212_KV_TYPE_LEAF:
if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM) {
- kv->value.leaf.data = CSR1212_MALLOC(quads_to_bytes(kvi_len));
+ size_t size = quads_to_bytes(kvi_len);
+
+ kv->value.leaf.data = CSR1212_MALLOC(size);
if (!kv->value.leaf.data) {
- ret = CSR1212_ENOMEM;
- goto fail;
+ ret = -ENOMEM;
+ goto out;
}
kv->value.leaf.len = kvi_len;
- memcpy(kv->value.leaf.data, kvi->data, quads_to_bytes(kvi_len));
+ memcpy(kv->value.leaf.data, kvi->data, size);
}
break;
}
kv->valid = 1;
-
-fail:
+out:
return ret;
}
-
-int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
+static int
+csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
{
struct csr1212_cache_region *cr, *ncr, *newcr = NULL;
struct csr1212_keyval_img *kvi = NULL;
struct csr1212_csr_rom_cache *cache;
int cache_index;
- u_int64_t addr;
- u_int32_t *cache_ptr;
- u_int16_t kv_len = 0;
+ u64 addr;
+ u32 *cache_ptr;
+ u16 kv_len = 0;
- if (!csr || !kv || csr->max_rom < 1)
- return CSR1212_EINVAL;
+ BUG_ON(!csr || !kv || csr->max_rom < 1);
/* First find which cache the data should be in (or go in if not read
* yet). */
- for (cache = csr->cache_head; cache; cache = cache->next) {
+ for (cache = csr->cache_head; cache; cache = cache->next)
if (kv->offset >= cache->offset &&
kv->offset < (cache->offset + cache->size))
break;
- }
if (!cache) {
- csr1212_quad_t q;
- u_int32_t cache_size;
+ u32 q, cache_size;
/* Only create a new cache for Extended ROM leaves. */
if (kv->key.id != CSR1212_KV_ID_EXTENDED_ROM)
- return CSR1212_EINVAL;
+ return -EINVAL;
if (csr->ops->bus_read(csr,
CSR1212_REGISTER_SPACE_BASE + kv->offset,
- sizeof(csr1212_quad_t), &q, csr->private)) {
- return CSR1212_EIO;
- }
+ sizeof(u32), &q, csr->private))
+ return -EIO;
- kv->value.leaf.len = CSR1212_BE32_TO_CPU(q) >> 16;
+ kv->value.leaf.len = be32_to_cpu(q) >> 16;
cache_size = (quads_to_bytes(kv->value.leaf.len + 1) +
(csr->max_rom - 1)) & ~(csr->max_rom - 1);
cache = csr1212_rom_cache_malloc(kv->offset, cache_size);
if (!cache)
- return CSR1212_ENOMEM;
+ return -ENOMEM;
kv->value.leaf.data = &cache->data[1];
csr->cache_tail->next = cache;
@@ -1465,12 +1293,11 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
csr->cache_tail = cache;
cache->filled_head =
CSR1212_MALLOC(sizeof(*cache->filled_head));
- if (!cache->filled_head) {
- return CSR1212_ENOMEM;
- }
+ if (!cache->filled_head)
+ return -ENOMEM;
cache->filled_head->offset_start = 0;
- cache->filled_head->offset_end = sizeof(csr1212_quad_t);
+ cache->filled_head->offset_end = sizeof(u32);
cache->filled_tail = cache->filled_head;
cache->filled_head->next = NULL;
cache->filled_head->prev = NULL;
@@ -1488,7 +1315,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
if (cache_index < cr->offset_start) {
newcr = CSR1212_MALLOC(sizeof(*newcr));
if (!newcr)
- return CSR1212_ENOMEM;
+ return -ENOMEM;
newcr->offset_start = cache_index & ~(csr->max_rom - 1);
newcr->offset_end = newcr->offset_start;
@@ -1501,18 +1328,18 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
(cache_index < cr->offset_end)) {
kvi = (struct csr1212_keyval_img*)
(&cache->data[bytes_to_quads(cache_index)]);
- kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +
- 1);
+ kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
break;
- } else if (cache_index == cr->offset_end)
+ } else if (cache_index == cr->offset_end) {
break;
+ }
}
if (!cr) {
cr = cache->filled_tail;
newcr = CSR1212_MALLOC(sizeof(*newcr));
if (!newcr)
- return CSR1212_ENOMEM;
+ return -ENOMEM;
newcr->offset_start = cache_index & ~(csr->max_rom - 1);
newcr->offset_end = newcr->offset_start;
@@ -1534,7 +1361,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
csr->private)) {
if (csr->max_rom == 4)
/* We've got problems! */
- return CSR1212_EIO;
+ return -EIO;
/* Apperently the max_rom value was a lie, set it to
* do quadlet reads and try again. */
@@ -1548,8 +1375,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
if (!kvi && (cr->offset_end > cache_index)) {
kvi = (struct csr1212_keyval_img*)
(&cache->data[bytes_to_quads(cache_index)]);
- kv_len = quads_to_bytes(CSR1212_BE16_TO_CPU(kvi->length) +
- 1);
+ kv_len = quads_to_bytes(be16_to_cpu(kvi->length) + 1);
}
if ((kv_len + (kv->offset - cache->offset)) > cache->size) {
@@ -1557,7 +1383,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
* beyond the ConfigROM image region and thus beyond the
* end of our cache region. Therefore, we abort now
* rather than seg faulting later. */
- return CSR1212_EIO;
+ return -EIO;
}
ncr = cr->next;
@@ -1579,7 +1405,16 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
return csr1212_parse_keyval(kv, cache);
}
-
+struct csr1212_keyval *
+csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
+{
+ if (!kv)
+ return NULL;
+ if (!kv->valid)
+ if (csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
+ return NULL;
+ return kv;
+}
int csr1212_parse_csr(struct csr1212_csr *csr)
{
@@ -1587,20 +1422,19 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
struct csr1212_dentry *dentry;
int ret;
- if (!csr || !csr->ops || !csr->ops->bus_read)
- return CSR1212_EINVAL;
+ BUG_ON(!csr || !csr->ops || !csr->ops->bus_read);
ret = csr1212_parse_bus_info_block(csr);
if (ret != CSR1212_SUCCESS)
return ret;
- if (!csr->ops->get_max_rom)
+ if (!csr->ops->get_max_rom) {
csr->max_rom = mr_map[0]; /* default value */
- else {
+ } else {
int i = csr->ops->get_max_rom(csr->bus_info_data,
csr->private);
if (i & ~0x3)
- return CSR1212_EINVAL;
+ return -EINVAL;
csr->max_rom = mr_map[i];
}
@@ -1613,7 +1447,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
csr->root_kv->valid = 0;
csr->root_kv->next = csr->root_kv;
csr->root_kv->prev = csr->root_kv;
- ret = _csr1212_read_keyval(csr, csr->root_kv);
+ ret = csr1212_read_keyval(csr, csr->root_kv);
if (ret != CSR1212_SUCCESS)
return ret;
@@ -1623,7 +1457,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
dentry; dentry = dentry->next) {
if (dentry->kv->key.id == CSR1212_KV_ID_EXTENDED_ROM &&
!dentry->kv->valid) {
- ret = _csr1212_read_keyval(csr, dentry->kv);
+ ret = csr1212_read_keyval(csr, dentry->kv);
if (ret != CSR1212_SUCCESS)
return ret;
}
diff --git a/drivers/ieee1394/csr1212.h b/drivers/ieee1394/csr1212.h
index 17ddd72dee4..df909ce6630 100644
--- a/drivers/ieee1394/csr1212.h
+++ b/drivers/ieee1394/csr1212.h
@@ -30,94 +30,13 @@
#ifndef __CSR1212_H__
#define __CSR1212_H__
-
-/* Compatibility layer */
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/vmalloc.h>
-#include <asm/pgalloc.h>
-
-#define CSR1212_MALLOC(size) vmalloc((size))
-#define CSR1212_FREE(ptr) vfree(ptr)
-#define CSR1212_BE16_TO_CPU(quad) be16_to_cpu(quad)
-#define CSR1212_CPU_TO_BE16(quad) cpu_to_be16(quad)
-#define CSR1212_BE32_TO_CPU(quad) be32_to_cpu(quad)
-#define CSR1212_CPU_TO_BE32(quad) cpu_to_be32(quad)
-#define CSR1212_BE64_TO_CPU(quad) be64_to_cpu(quad)
-#define CSR1212_CPU_TO_BE64(quad) cpu_to_be64(quad)
-
-#define CSR1212_LE16_TO_CPU(quad) le16_to_cpu(quad)
-#define CSR1212_CPU_TO_LE16(quad) cpu_to_le16(quad)
-#define CSR1212_LE32_TO_CPU(quad) le32_to_cpu(quad)
-#define CSR1212_CPU_TO_LE32(quad) cpu_to_le32(quad)
-#define CSR1212_LE64_TO_CPU(quad) le64_to_cpu(quad)
-#define CSR1212_CPU_TO_LE64(quad) cpu_to_le64(quad)
-
-#include <linux/errno.h>
-#define CSR1212_SUCCESS (0)
-#define CSR1212_EINVAL (-EINVAL)
-#define CSR1212_ENOMEM (-ENOMEM)
-#define CSR1212_ENOENT (-ENOENT)
-#define CSR1212_EIO (-EIO)
-#define CSR1212_EBUSY (-EBUSY)
-
-#else /* Userspace */
-
-#include <sys/types.h>
-#include <malloc.h>
-#define CSR1212_MALLOC(size) malloc(size)
-#define CSR1212_FREE(ptr) free(ptr)
-#include <endian.h>
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#include <byteswap.h>
-#define CSR1212_BE16_TO_CPU(quad) bswap_16(quad)
-#define CSR1212_CPU_TO_BE16(quad) bswap_16(quad)
-#define CSR1212_BE32_TO_CPU(quad) bswap_32(quad)
-#define CSR1212_CPU_TO_BE32(quad) bswap_32(quad)
-#define CSR1212_BE64_TO_CPU(quad) bswap_64(quad)
-#define CSR1212_CPU_TO_BE64(quad) bswap_64(quad)
-
-#define CSR1212_LE16_TO_CPU(quad) (quad)
-#define CSR1212_CPU_TO_LE16(quad) (quad)
-#define CSR1212_LE32_TO_CPU(quad) (quad)
-#define CSR1212_CPU_TO_LE32(quad) (quad)
-#define CSR1212_LE64_TO_CPU(quad) (quad)
-#define CSR1212_CPU_TO_LE64(quad) (quad)
-#else
-#define CSR1212_BE16_TO_CPU(quad) (quad)
-#define CSR1212_CPU_TO_BE16(quad) (quad)
-#define CSR1212_BE32_TO_CPU(quad) (quad)
-#define CSR1212_CPU_TO_BE32(quad) (quad)
-#define CSR1212_BE64_TO_CPU(quad) (quad)
-#define CSR1212_CPU_TO_BE64(quad) (quad)
-
-#define CSR1212_LE16_TO_CPU(quad) bswap_16(quad)
-#define CSR1212_CPU_TO_LE16(quad) bswap_16(quad)
-#define CSR1212_LE32_TO_CPU(quad) bswap_32(quad)
-#define CSR1212_CPU_TO_LE32(quad) bswap_32(quad)
-#define CSR1212_LE64_TO_CPU(quad) bswap_64(quad)
-#define CSR1212_CPU_TO_LE64(quad) bswap_64(quad)
-#endif
-
-#include <errno.h>
-#define CSR1212_SUCCESS (0)
-#define CSR1212_EINVAL (EINVAL)
-#define CSR1212_ENOMEM (ENOMEM)
-#define CSR1212_ENOENT (ENOENT)
-#define CSR1212_EIO (EIO)
-#define CSR1212_EBUSY (EBUSY)
-
-#endif
+#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
+#define CSR1212_FREE(ptr) kfree(ptr)
-#define CSR1212_KV_VAL_MASK 0xffffff
-#define CSR1212_KV_KEY_SHIFT 24
-#define CSR1212_KV_KEY_TYPE_SHIFT 6
-#define CSR1212_KV_KEY_ID_MASK 0x3f
-#define CSR1212_KV_KEY_TYPE_MASK 0x3 /* After shift */
+#define CSR1212_SUCCESS (0)
/* CSR 1212 key types */
@@ -190,48 +109,22 @@
#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
-#define CSR1212_EXTENDED_ROM_SIZE (0x10000 * sizeof(u_int32_t))
-
#define CSR1212_INVALID_ADDR_SPACE -1
+
/* Config ROM image structures */
struct csr1212_bus_info_block_img {
- u_int8_t length;
- u_int8_t crc_length;
- u_int16_t crc;
+ u8 length;
+ u8 crc_length;
+ u16 crc;
/* Must be last */
- u_int32_t data[0]; /* older gcc can't handle [] which is standard */
-};
-
-#define CSR1212_KV_KEY(quad) (CSR1212_BE32_TO_CPU(quad) >> CSR1212_KV_KEY_SHIFT)
-#define CSR1212_KV_KEY_TYPE(quad) (CSR1212_KV_KEY(quad) >> CSR1212_KV_KEY_TYPE_SHIFT)
-#define CSR1212_KV_KEY_ID(quad) (CSR1212_KV_KEY(quad) & CSR1212_KV_KEY_ID_MASK)
-#define CSR1212_KV_VAL(quad) (CSR1212_BE32_TO_CPU(quad) & CSR1212_KV_VAL_MASK)
-
-#define CSR1212_SET_KV_KEY(quad, key) ((quad) = \
- CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | ((key) << CSR1212_KV_KEY_SHIFT)))
-#define CSR1212_SET_KV_VAL(quad, val) ((quad) = \
- CSR1212_CPU_TO_BE32((CSR1212_KV_KEY(quad) << CSR1212_KV_KEY_SHIFT) | (val)))
-#define CSR1212_SET_KV_TYPEID(quad, type, id) ((quad) = \
- CSR1212_CPU_TO_BE32(CSR1212_KV_VAL(quad) | \
- (((((type) & CSR1212_KV_KEY_TYPE_MASK) << CSR1212_KV_KEY_TYPE_SHIFT) | \
- ((id) & CSR1212_KV_KEY_ID_MASK)) << CSR1212_KV_KEY_SHIFT)))
-
-typedef u_int32_t csr1212_quad_t;
-
-
-struct csr1212_keyval_img {
- u_int16_t length;
- u_int16_t crc;
-
- /* Must be last */
- csr1212_quad_t data[0]; /* older gcc can't handle [] which is standard */
+ u32 data[0]; /* older gcc can't handle [] which is standard */
};
struct csr1212_leaf {
int len;
- u_int32_t *data;
+ u32 *data;
};
struct csr1212_dentry {
@@ -246,12 +139,12 @@ struct csr1212_directory {
struct csr1212_keyval {
struct {
- u_int8_t type;
- u_int8_t id;
+ u8 type;
+ u8 id;
} key;
union {
- u_int32_t immediate;
- u_int32_t csr_offset;
+ u32 immediate;
+ u32 csr_offset;
struct csr1212_leaf leaf;
struct csr1212_directory directory;
} value;
@@ -260,15 +153,15 @@ struct csr1212_keyval {
/* used in generating and/or parsing CSR image */
struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
- u_int32_t offset; /* position in CSR from 0xffff f000 0000 */
- u_int8_t valid; /* flag indicating keyval has valid data*/
+ u32 offset; /* position in CSR from 0xffff f000 0000 */
+ u8 valid; /* flag indicating keyval has valid data*/
};
struct csr1212_cache_region {
struct csr1212_cache_region *next, *prev;
- u_int32_t offset_start; /* inclusive */
- u_int32_t offset_end; /* exclusive */
+ u32 offset_start; /* inclusive */
+ u32 offset_end; /* exclusive */
};
struct csr1212_csr_rom_cache {
@@ -276,18 +169,18 @@ struct csr1212_csr_rom_cache {
struct csr1212_cache_region *filled_head, *filled_tail;
struct csr1212_keyval *layout_head, *layout_tail;
size_t size;
- u_int32_t offset;
+ u32 offset;
struct csr1212_keyval *ext_rom;
size_t len;
/* Must be last */
- u_int32_t data[0]; /* older gcc can't handle [] which is standard */
+ u32 data[0]; /* older gcc can't handle [] which is standard */
};
struct csr1212_csr {
size_t bus_info_len; /* bus info block length in bytes */
size_t crc_len; /* crc length in bytes */
- u_int32_t *bus_info_data; /* bus info data incl bus name and EUI */
+ u32 *bus_info_data; /* bus info data incl bus name and EUI */
void *private; /* private, bus specific data */
struct csr1212_bus_ops *ops;
@@ -305,52 +198,38 @@ struct csr1212_bus_ops {
* from remote nodes when parsing a Config ROM (i.e., read Config ROM
* entries located in the Units Space. Must return 0 on success
* anything else indicates an error. */
- int (*bus_read) (struct csr1212_csr *csr, u_int64_t addr,
- u_int16_t length, void *buffer, void *private);
+ int (*bus_read) (struct csr1212_csr *csr, u64 addr,
+ u16 length, void *buffer, void *private);
/* This function is used by csr1212 to allocate a region in units space
* in the event that Config ROM entries don't all fit in the predefined
* 1K region. The void *private parameter is private member of struct
* csr1212_csr. */
- u_int64_t (*allocate_addr_range) (u_int64_t size, u_int32_t alignment,
- void *private);
-
+ u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
/* This function is used by csr1212 to release a region in units space
* that is no longer needed. */
- void (*release_addr) (u_int64_t addr, void *private);
+ void (*release_addr) (u64 addr, void *private);
/* This function is used by csr1212 to determine the max read request
* supported by a remote node when reading the ConfigROM space. Must
* return 0, 1, or 2 per IEEE 1212. */
- int (*get_max_rom) (u_int32_t *bus_info, void *private);
+ int (*get_max_rom) (u32 *bus_info, void *private);
};
-
-
/* Descriptor Leaf manipulation macros */
#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
-#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
+#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) >> CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
+ (be32_to_cpu((kv)->value.leaf.data[0]) >> \
+ CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[0]) & \
+ (be32_to_cpu((kv)->value.leaf.data[0]) & \
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
-#define CSR1212_DESCRIPTOR_LEAF_DATA(kv) \
- (&((kv)->value.leaf.data[1]))
-
-#define CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, type) \
- ((kv)->value.leaf.data[0] = \
- CSR1212_CPU_TO_BE32(CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) | \
- ((type) << CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)))
-#define CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, spec_id) \
- ((kv)->value.leaf.data[0] = \
- CSR1212_CPU_TO_BE32((CSR1212_DESCRIPTOR_LEAF_TYPE(kv) << \
- CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT) | \
- ((spec_id) & CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)))
+
/* Text Descriptor Leaf manipulation macros */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
@@ -358,182 +237,21 @@ struct csr1212_bus_ops {
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u_int32_t))
+#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
+ (be32_to_cpu((kv)->value.leaf.data[1]) >> \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
- ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) >> \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
+ ((be32_to_cpu((kv)->value.leaf.data[1]) >> \
+ CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
+ CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]) & \
+ (be32_to_cpu((kv)->value.leaf.data[1]) & \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
(&((kv)->value.leaf.data[2]))
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_WIDTH(kv, width) \
- ((kv)->value.leaf.data[1] = \
- ((kv)->value.leaf.data[1] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK << \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))) | \
- CSR1212_CPU_TO_BE32(((width) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK) << \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT))
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_CHAR_SET(kv, char_set) \
- ((kv)->value.leaf.data[1] = \
- ((kv)->value.leaf.data[1] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK << \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))) | \
- CSR1212_CPU_TO_BE32(((char_set) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK) << \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT))
-#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
- ((kv)->value.leaf.data[1] = \
- ((kv)->value.leaf.data[1] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
- CSR1212_CPU_TO_BE32(((language) & \
- CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
-
-
-/* Icon Descriptor Leaf manipulation macros */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK 0xffffff
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT 30
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK 0x3 /* after shift */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT 16
-#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK 0xf /* after shift */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
-#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT 16
-#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK 0xffff /* after shift */
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK 0xffff
-#define CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD (3 * sizeof(u_int32_t))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VERSION(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[2]) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
- CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv) \
- ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) >> \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[3]) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN(kv) \
- ((CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) >> \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_SHIFT) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_HSCAN_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN(kv) \
- (CSR1212_BE32_TO_CPU((kv)->value.leaf.data[4]) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE(kv) \
- (&((kv)->value.leaf.data[5]))
-
-static inline u_int32_t *CSR1212_ICON_DESCRIPTOR_LEAF_PIXELS(struct csr1212_keyval *kv)
-{
- static const int pd[4] = { 0, 4, 16, 256 };
- static const int cs[16] = { 4, 2 };
- int ps = pd[CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH(kv)];
-
- return &kv->value.leaf.data[5 +
- (ps * cs[CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE(kv)]) /
- sizeof(u_int32_t)];
-}
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VERSION(kv, version) \
- ((kv)->value.leaf.data[2] = \
- ((kv)->value.leaf.data[2] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK))) | \
- CSR1212_CPU_TO_BE32(((version) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_VERSION_MASK)))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_PALETTE_DEPTH(kv, palette_depth) \
- ((kv)->value.leaf.data[3] = \
- ((kv)->value.leaf.data[3] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK << \
- CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))) | \
- CSR1212_CPU_TO_BE32(((palette_depth) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_MASK) << \
- CSR1212_ICON_DESCRIPTOR_LEAF_PALETTE_DEPTH_SHIFT))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_COLOR_SPACE(kv, color_space) \
- ((kv)->value.leaf.data[3] = \
- ((kv)->value.leaf.data[3] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK << \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))) | \
- CSR1212_CPU_TO_BE32(((color_space) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_MASK) << \
- CSR1212_ICON_DESCRIPTOR_LEAF_COLOR_SPACE_SHIFT))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_LANGUAGE(kv, language) \
- ((kv)->value.leaf.data[3] = \
- ((kv)->value.leaf.data[3] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK))) | \
- CSR1212_CPU_TO_BE32(((language) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_LANGUAGE_MASK)))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_HSCAN(kv, hscan) \
- ((kv)->value.leaf.data[4] = \
- ((kv)->value.leaf.data[4] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK << \
- CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))) | \
- CSR1212_CPU_TO_BE32(((hscan) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_MASK) << \
- CSR1212_ICON_DESCRIPTOR_LEAF_HSCAN_SHIFT))
-
-#define CSR1212_ICON_DESCRIPTOR_LEAF_SET_VSCAN(kv, vscan) \
- ((kv)->value.leaf.data[4] = \
- (((kv)->value.leaf.data[4] & \
- CSR1212_CPU_TO_BE32(~CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK))) | \
- CSR1212_CPU_TO_BE32(((vscan) & \
- CSR1212_ICON_DESCRIPTOR_LEAF_VSCAN_MASK)))
-
-
-/* Modifiable Descriptor Leaf manipulation macros */
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT 16
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK 0xffff
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_SHIFT 32
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK 0xffff
-#define CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK 0xffffffffULL
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE(kv) \
- CSR1212_BE16_TO_CPU((kv)->value.leaf.data[0] >> CSR1212_MODIFIABLE_DESCRIPTOR_MAX_SIZE_SHIFT)
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_ADDRESS(kv) \
- (CSR1212_BE16_TO_CPU(((u_int64_t)((kv)->value.leaf.data[0])) << \
- CSR1212_MODIFIABLE_DESCRIPTOR_ADDR_HI_SHIFT) | \
- CSR1212_BE32_TO_CPU((kv)->value.leaf.data[1]))
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_MAX_SIZE(kv, size) \
- ((kv)->value.leaf.data[0] = \
- ((kv)->value.leaf.data[0] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK << \
- CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))) | \
- CSR1212_CPU_TO_BE32(((size) & \
- CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_MASK) << \
- CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_MAX_SIZE_SHIFT))
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_HI(kv, addr) \
- ((kv)->value.leaf.data[0] = \
- ((kv)->value.leaf.data[0] & \
- CSR1212_CPU_TO_BE32(~(CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK))) | \
- CSR1212_CPU_TO_BE32(((addr) & \
- CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_HI_MASK)))
-
-#define CSR1212_MODIFIABLE_DESCRIPTOR_SET_ADDRESS_LO(kv, addr) \
- ((kv)->value.leaf.data[1] = \
- CSR1212_CPU_TO_BE32(addr & CSR1212_MODIFIABLE_DESCRIPTOR_LEAF_ADDR_LO_MASK))
-
-
/* The following 2 function are for creating new Configuration ROM trees. The
* first function is used for both creating local trees and parsing remote
@@ -543,11 +261,10 @@ extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
size_t bus_info_size,
void *private);
extern void csr1212_init_local_csr(struct csr1212_csr *csr,
- const u_int32_t *bus_info_data, int max_rom);
+ const u32 *bus_info_data, int max_rom);
-/* The following function destroys a Configuration ROM tree and release all
- * memory taken by the tree. */
+/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
extern void csr1212_destroy_csr(struct csr1212_csr *csr);
@@ -555,50 +272,20 @@ extern void csr1212_destroy_csr(struct csr1212_csr *csr);
* a Configuration ROM tree. Code that creates new keyvals with these functions
* must release those keyvals with csr1212_release_keyval() when they are no
* longer needed. */
-extern struct csr1212_keyval *csr1212_new_immediate(u_int8_t key, u_int32_t value);
-extern struct csr1212_keyval *csr1212_new_leaf(u_int8_t key, const void *data,
- size_t data_len);
-extern struct csr1212_keyval *csr1212_new_csr_offset(u_int8_t key,
- u_int32_t csr_offset);
-extern struct csr1212_keyval *csr1212_new_directory(u_int8_t key);
-extern struct csr1212_keyval *csr1212_new_extended_immediate(u_int32_t spec,
- u_int32_t key,
- u_int32_t value);
-extern struct csr1212_keyval *csr1212_new_extended_leaf(u_int32_t spec,
- u_int32_t key,
- const void *data,
- size_t data_len);
-extern struct csr1212_keyval *csr1212_new_descriptor_leaf(u_int8_t dtype,
- u_int32_t specifier_id,
- const void *data,
- size_t data_len);
-extern struct csr1212_keyval *csr1212_new_textual_descriptor_leaf(u_int8_t cwidth,
- u_int16_t cset,
- u_int16_t language,
- const void *data,
- size_t data_len);
+extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
+extern struct csr1212_keyval *csr1212_new_directory(u8 key);
extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
-extern struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
- u_int8_t palette_depth,
- u_int8_t color_space,
- u_int16_t language,
- u_int16_t hscan,
- u_int16_t vscan,
- u_int32_t *palette,
- u_int32_t *pixels);
-extern struct csr1212_keyval *csr1212_new_modifiable_descriptor_leaf(u_int16_t max_size,
- u_int64_t address);
-extern struct csr1212_keyval *csr1212_new_keyword_leaf(int strc,
- const char *strv[]);
-
-
-/* The following functions manage association between keyvals. Typically,
+
+
+/* The following function manages association between keyvals. Typically,
* Descriptor Leaves and Directories will be associated with another keyval and
* it is desirable for the Descriptor keyval to be place immediately after the
- * keyval that it is associated with.*/
-extern int csr1212_associate_keyval(struct csr1212_keyval *kv,
- struct csr1212_keyval *associate);
-extern void csr1212_disassociate_keyval(struct csr1212_keyval *kv);
+ * keyval that it is associated with.
+ * Take care with subsequent ROM modifications: There is no function to remove
+ * previously specified associations.
+ */
+extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
+ struct csr1212_keyval *associate);
/* The following functions manage the association of a keyval and directories.
@@ -609,23 +296,15 @@ extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
struct csr1212_keyval *kv);
-/* The following functions create a Configuration ROM image from the tree of
- * keyvals provided. csr1212_generate_csr_image() creates a complete image in
- * the list of caches available via csr->cache_head. The other functions are
- * provided should there be a need to create a flat image without restrictions
- * placed by IEEE 1212. */
-extern struct csr1212_keyval *csr1212_generate_positions(struct csr1212_csr_rom_cache *cache,
- struct csr1212_keyval *start_kv,
- int start_pos);
-extern size_t csr1212_generate_layout_order(struct csr1212_keyval *kv);
-extern void csr1212_fill_cache(struct csr1212_csr_rom_cache *cache);
+/* Creates a complete Configuration ROM image in the list of caches available
+ * via csr->cache_head. */
extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
/* This is a convience function for reading a block of data out of one of the
* caches in the csr->cache_head list. */
-extern int csr1212_read(struct csr1212_csr *csr, u_int32_t offset, void *buffer,
- u_int32_t len);
+extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
+ u32 len);
/* The following functions are in place for parsing Configuration ROM images.
@@ -635,15 +314,11 @@ extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
struct csr1212_csr_rom_cache *cache);
extern int csr1212_parse_csr(struct csr1212_csr *csr);
-/* These are internal functions referenced by inline functions below. */
-extern int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
-extern void _csr1212_destroy_keyval(struct csr1212_keyval *kv);
-
/* This function allocates a new cache which may be used for either parsing or
* generating sub-sets of Configuration ROM images. */
-static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t offset,
- size_t size)
+static inline struct csr1212_csr_rom_cache *
+csr1212_rom_cache_malloc(u32 offset, size_t size)
{
struct csr1212_csr_rom_cache *cache;
@@ -667,16 +342,8 @@ static inline struct csr1212_csr_rom_cache *csr1212_rom_cache_malloc(u_int32_t o
/* This function ensures that a keyval contains data when referencing a keyval
* created by parsing a Configuration ROM. */
-static inline struct csr1212_keyval *csr1212_get_keyval(struct csr1212_csr *csr,
- struct csr1212_keyval *kv)
-{
- if (!kv)
- return NULL;
- if (!kv->valid)
- if (_csr1212_read_keyval(csr, kv) != CSR1212_SUCCESS)
- return NULL;
- return kv;
-}
+extern struct csr1212_keyval *
+csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
/* This function increments the reference count for a keyval should there be a
@@ -691,37 +358,29 @@ static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
* keyval when there are no more users of the keyval. This should be called by
* any code that calls csr1212_keep_keyval() or any of the keyval creation
* routines csr1212_new_*(). */
-static inline void csr1212_release_keyval(struct csr1212_keyval *kv)
-{
- if (kv->refcnt > 1)
- kv->refcnt--;
- else
- _csr1212_destroy_keyval(kv);
-}
+extern void csr1212_release_keyval(struct csr1212_keyval *kv);
/*
* This macro allows for looping over the keyval entries in a directory and it
* ensures that keyvals from remote ConfigROMs are parsed properly.
*
- * _csr is a struct csr1212_csr * that points to CSR associated with dir.
- * _kv is a struct csr1212_keyval * that'll point to the current keyval (loop index).
- * _dir is a struct csr1212_keyval * that points to the directory to be looped.
- * _pos is a struct csr1212_dentry * that is used internally for indexing.
+ * struct csr1212_csr *_csr points to the CSR associated with dir.
+ * struct csr1212_keyval *_kv points to the current keyval (loop index).
+ * struct csr1212_keyval *_dir points to the directory to be looped.
+ * struct csr1212_dentry *_pos is used internally for indexing.
*
* kv will be NULL upon exit of the loop.
*/
-#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
- for (csr1212_get_keyval((_csr), (_dir)), \
- _pos = (_dir)->value.directory.dentries_head, \
- _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL; \
- (_kv) && (_pos); \
- (_kv->associate == NULL) ? \
- ((_pos = _pos->next), \
- (_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : \
- NULL)) : \
+#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
+ for (csr1212_get_keyval((_csr), (_dir)), \
+ _pos = (_dir)->value.directory.dentries_head, \
+ _kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
+ (_kv) && (_pos); \
+ (_kv->associate == NULL) ? \
+ ((_pos = _pos->next), (_kv = (_pos) ? \
+ csr1212_get_keyval((_csr), _pos->kv) : \
+ NULL)) : \
(_kv = csr1212_get_keyval((_csr), _kv->associate)))
-
-
#endif /* __CSR1212_H__ */
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
index c68f328e1a2..45d60558192 100644
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -62,6 +62,9 @@ void dma_prog_region_free(struct dma_prog_region *prog)
/* dma_region */
+/**
+ * dma_region_init - clear out all fields but do not allocate anything
+ */
void dma_region_init(struct dma_region *dma)
{
dma->kvirt = NULL;
@@ -71,6 +74,9 @@ void dma_region_init(struct dma_region *dma)
dma->sglist = NULL;
}
+/**
+ * dma_region_alloc - allocate the buffer and map it to the IOMMU
+ */
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
struct pci_dev *dev, int direction)
{
@@ -128,6 +134,9 @@ int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
return -ENOMEM;
}
+/**
+ * dma_region_free - unmap and free the buffer
+ */
void dma_region_free(struct dma_region *dma)
{
if (dma->n_dma_pages) {
@@ -167,6 +176,12 @@ static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
return i;
}
+/**
+ * dma_region_offset_to_bus - get bus address of an offset within a DMA region
+ *
+ * Returns the DMA bus address of the byte with the given @offset relative to
+ * the beginning of the @dma.
+ */
dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
unsigned long offset)
{
@@ -177,6 +192,9 @@ dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
return sg_dma_address(sg) + rem;
}
+/**
+ * dma_region_sync_for_cpu - sync the CPU's view of the buffer
+ */
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
unsigned long len)
{
@@ -193,6 +211,9 @@ void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
dma->direction);
}
+/**
+ * dma_region_sync_for_device - sync the IO bus' view of the buffer
+ */
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
unsigned long len)
{
@@ -244,6 +265,9 @@ static struct vm_operations_struct dma_region_vm_ops = {
.nopage = dma_region_pagefault,
};
+/**
+ * dma_region_mmap - map the buffer into a user space process
+ */
int dma_region_mmap(struct dma_region *dma, struct file *file,
struct vm_area_struct *vma)
{
diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
index a1682aba71c..2727bcd2419 100644
--- a/drivers/ieee1394/dma.h
+++ b/drivers/ieee1394/dma.h
@@ -66,35 +66,23 @@ struct dma_region {
int direction;
};
-/* clear out all fields but do not allocate anything */
void dma_region_init(struct dma_region *dma);
-
-/* allocate the buffer and map it to the IOMMU */
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
struct pci_dev *dev, int direction);
-
-/* unmap and free the buffer */
void dma_region_free(struct dma_region *dma);
-
-/* sync the CPU's view of the buffer */
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
unsigned long len);
-
-/* sync the IO bus' view of the buffer */
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
unsigned long len);
-
-/* map the buffer into a user space process */
int dma_region_mmap(struct dma_region *dma, struct file *file,
struct vm_area_struct *vma);
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
+ unsigned long offset);
-/* macro to index into a DMA region (or dma_prog_region) */
+/**
+ * dma_region_i - macro to index into a DMA region (or dma_prog_region)
+ */
#define dma_region_i(_dma, _type, _index) \
( ((_type*) ((_dma)->kvirt)) + (_index) )
-/* return the DMA bus address of the byte with the given offset
- * relative to the beginning of the dma_region */
-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
- unsigned long offset);
-
#endif /* IEEE1394_DMA_H */
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 026e38face5..20814137761 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -94,7 +94,6 @@
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/bitops.h>
#include <asm/byteorder.h>
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index a364003ba47..2296d43a241 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1,5 +1,5 @@
/*
- * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem
+ * eth1394.c -- IPv4 driver for Linux IEEE-1394 Subsystem
*
* Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org>
* 2000 Bonin Franck <boninf@free.fr>
@@ -22,10 +22,9 @@
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/* This driver intends to support RFC 2734, which describes a method for
- * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver
- * will ultimately support that method, but currently falls short in
- * several areas.
+/*
+ * This driver intends to support RFC 2734, which describes a method for
+ * transporting IPv4 datagrams over IEEE-1394 serial busses.
*
* TODO:
* RFC 2734 related:
@@ -40,7 +39,6 @@
* - Consider garbage collecting old partial datagrams after X amount of time
*/
-
#include <linux/module.h>
#include <linux/kernel.h>
@@ -52,7 +50,6 @@
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
@@ -84,10 +81,6 @@
#define ETH1394_PRINT(level, dev_name, fmt, args...) \
printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)
-#define DEBUG(fmt, args...) \
- printk(KERN_ERR "%s:%s[%d]: " fmt "\n", driver_name, __FUNCTION__, __LINE__, ## args)
-#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
-
struct fragment_info {
struct list_head list;
int offset;
@@ -105,9 +98,9 @@ struct partial_datagram {
};
struct pdg_list {
- struct list_head list; /* partial datagram list per node */
- unsigned int sz; /* partial datagram list size per node */
- spinlock_t lock; /* partial datagram lock */
+ struct list_head list; /* partial datagram list per node */
+ unsigned int sz; /* partial datagram list size per node */
+ spinlock_t lock; /* partial datagram lock */
};
struct eth1394_host_info {
@@ -121,16 +114,14 @@ struct eth1394_node_ref {
};
struct eth1394_node_info {
- u16 maxpayload; /* Max payload */
- u8 sspd; /* Max speed */
- u64 fifo; /* FIFO address */
- struct pdg_list pdg; /* partial RX datagram lists */
- int dgl; /* Outgoing datagram label */
+ u16 maxpayload; /* max payload */
+ u8 sspd; /* max speed */
+ u64 fifo; /* FIFO address */
+ struct pdg_list pdg; /* partial RX datagram lists */
+ int dgl; /* outgoing datagram label */
};
-/* Our ieee1394 highlevel driver */
-#define ETH1394_DRIVER_NAME "eth1394"
-static const char driver_name[] = ETH1394_DRIVER_NAME;
+static const char driver_name[] = "eth1394";
static struct kmem_cache *packet_task_cache;
@@ -138,18 +129,12 @@ static struct hpsb_highlevel eth1394_highlevel;
/* Use common.lf to determine header len */
static const int hdr_type_len[] = {
- sizeof (struct eth1394_uf_hdr),
- sizeof (struct eth1394_ff_hdr),
- sizeof (struct eth1394_sf_hdr),
- sizeof (struct eth1394_sf_hdr)
+ sizeof(struct eth1394_uf_hdr),
+ sizeof(struct eth1394_ff_hdr),
+ sizeof(struct eth1394_sf_hdr),
+ sizeof(struct eth1394_sf_hdr)
};
-/* Change this to IEEE1394_SPEED_S100 to make testing easier */
-#define ETH1394_SPEED_DEF IEEE1394_SPEED_MAX
-
-/* For now, this needs to be 1500, so that XP works with us */
-#define ETH1394_DATA_LEN ETH_DATA_LEN
-
static const u16 eth1394_speedto_maxpayload[] = {
/* S100, S200, S400, S800, S1600, S3200 */
512, 1024, 2048, 4096, 4096, 4096
@@ -159,7 +144,8 @@ MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");
MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
MODULE_LICENSE("GPL");
-/* The max_partial_datagrams parameter is the maximum number of fragmented
+/*
+ * The max_partial_datagrams parameter is the maximum number of fragmented
* datagrams per node that eth1394 will keep in memory. Providing an upper
* bound allows us to limit the amount of memory that partial datagrams
* consume in the event that some partial datagrams are never completed.
@@ -179,10 +165,7 @@ static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);
static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
static void ether1394_header_cache_update(struct hh_cache *hh,
struct net_device *dev,
- unsigned char * haddr);
-static int ether1394_mac_addr(struct net_device *dev, void *p);
-
-static void purge_partial_datagram(struct list_head *old);
+ unsigned char *haddr);
static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
static void ether1394_iso(struct hpsb_iso *iso);
@@ -190,9 +173,9 @@ static struct ethtool_ops ethtool_ops;
static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
quadlet_t *data, u64 addr, size_t len, u16 flags);
-static void ether1394_add_host (struct hpsb_host *host);
-static void ether1394_remove_host (struct hpsb_host *host);
-static void ether1394_host_reset (struct hpsb_host *host);
+static void ether1394_add_host(struct hpsb_host *host);
+static void ether1394_remove_host(struct hpsb_host *host);
+static void ether1394_host_reset(struct hpsb_host *host);
/* Function for incoming 1394 packets */
static struct hpsb_address_ops addr_ops = {
@@ -207,89 +190,107 @@ static struct hpsb_highlevel eth1394_highlevel = {
.host_reset = ether1394_host_reset,
};
+static int ether1394_recv_init(struct eth1394_priv *priv)
+{
+ unsigned int iso_buf_size;
+
+ /* FIXME: rawiso limits us to PAGE_SIZE */
+ iso_buf_size = min((unsigned int)PAGE_SIZE,
+ 2 * (1U << (priv->host->csr.max_rec + 1)));
+
+ priv->iso = hpsb_iso_recv_init(priv->host,
+ ETHER1394_GASP_BUFFERS * iso_buf_size,
+ ETHER1394_GASP_BUFFERS,
+ priv->broadcast_channel,
+ HPSB_ISO_DMA_PACKET_PER_BUFFER,
+ 1, ether1394_iso);
+ if (priv->iso == NULL) {
+ ETH1394_PRINT_G(KERN_ERR, "Failed to allocate IR context\n");
+ priv->bc_state = ETHER1394_BC_ERROR;
+ return -EAGAIN;
+ }
+
+ if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
+ priv->bc_state = ETHER1394_BC_STOPPED;
+ else
+ priv->bc_state = ETHER1394_BC_RUNNING;
+ return 0;
+}
/* This is called after an "ifup" */
-static int ether1394_open (struct net_device *dev)
+static int ether1394_open(struct net_device *dev)
{
struct eth1394_priv *priv = netdev_priv(dev);
- int ret = 0;
+ int ret;
- /* Something bad happened, don't even try */
if (priv->bc_state == ETHER1394_BC_ERROR) {
- /* we'll try again */
- priv->iso = hpsb_iso_recv_init(priv->host,
- ETHER1394_ISO_BUF_SIZE,
- ETHER1394_GASP_BUFFERS,
- priv->broadcast_channel,
- HPSB_ISO_DMA_PACKET_PER_BUFFER,
- 1, ether1394_iso);
- if (priv->iso == NULL) {
- ETH1394_PRINT(KERN_ERR, dev->name,
- "Could not allocate isochronous receive "
- "context for the broadcast channel\n");
- priv->bc_state = ETHER1394_BC_ERROR;
- ret = -EAGAIN;
- } else {
- if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
- priv->bc_state = ETHER1394_BC_STOPPED;
- else
- priv->bc_state = ETHER1394_BC_RUNNING;
- }
+ ret = ether1394_recv_init(priv);
+ if (ret)
+ return ret;
}
-
- if (ret)
- return ret;
-
- netif_start_queue (dev);
+ netif_start_queue(dev);
return 0;
}
/* This is called after an "ifdown" */
-static int ether1394_stop (struct net_device *dev)
+static int ether1394_stop(struct net_device *dev)
{
- netif_stop_queue (dev);
+ netif_stop_queue(dev);
return 0;
}
/* Return statistics to the caller */
-static struct net_device_stats *ether1394_stats (struct net_device *dev)
+static struct net_device_stats *ether1394_stats(struct net_device *dev)
{
return &(((struct eth1394_priv *)netdev_priv(dev))->stats);
}
-/* What to do if we timeout. I think a host reset is probably in order, so
- * that's what we do. Should we increment the stat counters too? */
-static void ether1394_tx_timeout (struct net_device *dev)
+/* FIXME: What to do if we timeout? I think a host reset is probably in order,
+ * so that's what we do. Should we increment the stat counters too? */
+static void ether1394_tx_timeout(struct net_device *dev)
{
- ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n",
- ((struct eth1394_priv *)netdev_priv(dev))->host->driver->name);
+ struct hpsb_host *host =
+ ((struct eth1394_priv *)netdev_priv(dev))->host;
- highlevel_host_reset (((struct eth1394_priv *)netdev_priv(dev))->host);
+ ETH1394_PRINT(KERN_ERR, dev->name, "Timeout, resetting host\n");
+ ether1394_host_reset(host);
+}
- netif_wake_queue (dev);
+static inline int ether1394_max_mtu(struct hpsb_host* host)
+{
+ return (1 << (host->csr.max_rec + 1))
+ - sizeof(union eth1394_hdr) - ETHER1394_GASP_OVERHEAD;
}
static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
{
- struct eth1394_priv *priv = netdev_priv(dev);
+ int max_mtu;
- if ((new_mtu < 68) ||
- (new_mtu > min(ETH1394_DATA_LEN,
- (int)((1 << (priv->host->csr.max_rec + 1)) -
- (sizeof(union eth1394_hdr) +
- ETHER1394_GASP_OVERHEAD)))))
+ if (new_mtu < 68)
return -EINVAL;
+
+ max_mtu = ether1394_max_mtu(
+ ((struct eth1394_priv *)netdev_priv(dev))->host);
+ if (new_mtu > max_mtu) {
+ ETH1394_PRINT(KERN_INFO, dev->name,
+ "Local node constrains MTU to %d\n", max_mtu);
+ return -ERANGE;
+ }
+
dev->mtu = new_mtu;
return 0;
}
static void purge_partial_datagram(struct list_head *old)
{
- struct partial_datagram *pd = list_entry(old, struct partial_datagram, list);
+ struct partial_datagram *pd;
struct list_head *lh, *n;
+ struct fragment_info *fi;
+
+ pd = list_entry(old, struct partial_datagram, list);
list_for_each_safe(lh, n, &pd->frag_info) {
- struct fragment_info *fi = list_entry(lh, struct fragment_info, list);
+ fi = list_entry(lh, struct fragment_info, list);
list_del(lh);
kfree(fi);
}
@@ -330,35 +331,26 @@ static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl,
nodeid_t nodeid)
{
struct eth1394_node_ref *node;
- list_for_each_entry(node, inl, list) {
+
+ list_for_each_entry(node, inl, list)
if (node->ud->ne->nodeid == nodeid)
return node;
- }
return NULL;
}
-static int eth1394_probe(struct device *dev)
+static int eth1394_new_node(struct eth1394_host_info *hi,
+ struct unit_directory *ud)
{
- struct unit_directory *ud;
- struct eth1394_host_info *hi;
struct eth1394_priv *priv;
struct eth1394_node_ref *new_node;
struct eth1394_node_info *node_info;
- ud = container_of(dev, struct unit_directory, device);
-
- hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
- if (!hi)
- return -ENOENT;
-
- new_node = kmalloc(sizeof(*new_node),
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ new_node = kmalloc(sizeof(*new_node), GFP_KERNEL);
if (!new_node)
return -ENOMEM;
- node_info = kmalloc(sizeof(*node_info),
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+ node_info = kmalloc(sizeof(*node_info), GFP_KERNEL);
if (!node_info) {
kfree(new_node);
return -ENOMEM;
@@ -374,10 +366,22 @@ static int eth1394_probe(struct device *dev)
priv = netdev_priv(hi->dev);
list_add_tail(&new_node->list, &priv->ip_node_list);
-
return 0;
}
+static int eth1394_probe(struct device *dev)
+{
+ struct unit_directory *ud;
+ struct eth1394_host_info *hi;
+
+ ud = container_of(dev, struct unit_directory, device);
+ hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
+ if (!hi)
+ return -ENOENT;
+
+ return eth1394_new_node(hi, ud);
+}
+
static int eth1394_remove(struct device *dev)
{
struct unit_directory *ud;
@@ -396,24 +400,23 @@ static int eth1394_remove(struct device *dev)
priv = netdev_priv(hi->dev);
old_node = eth1394_find_node(&priv->ip_node_list, ud);
+ if (!old_node)
+ return 0;
- if (old_node) {
- list_del(&old_node->list);
- kfree(old_node);
+ list_del(&old_node->list);
+ kfree(old_node);
- node_info = (struct eth1394_node_info*)ud->device.driver_data;
+ node_info = (struct eth1394_node_info*)ud->device.driver_data;
- spin_lock_irqsave(&node_info->pdg.lock, flags);
- /* The partial datagram list should be empty, but we'll just
- * make sure anyway... */
- list_for_each_safe(lh, n, &node_info->pdg.list) {
- purge_partial_datagram(lh);
- }
- spin_unlock_irqrestore(&node_info->pdg.lock, flags);
+ spin_lock_irqsave(&node_info->pdg.lock, flags);
+ /* The partial datagram list should be empty, but we'll just
+ * make sure anyway... */
+ list_for_each_safe(lh, n, &node_info->pdg.list)
+ purge_partial_datagram(lh);
+ spin_unlock_irqrestore(&node_info->pdg.lock, flags);
- kfree(node_info);
- ud->device.driver_data = NULL;
- }
+ kfree(node_info);
+ ud->device.driver_data = NULL;
return 0;
}
@@ -422,44 +425,19 @@ static int eth1394_update(struct unit_directory *ud)
struct eth1394_host_info *hi;
struct eth1394_priv *priv;
struct eth1394_node_ref *node;
- struct eth1394_node_info *node_info;
hi = hpsb_get_hostinfo(&eth1394_highlevel, ud->ne->host);
if (!hi)
return -ENOENT;
priv = netdev_priv(hi->dev);
-
node = eth1394_find_node(&priv->ip_node_list, ud);
+ if (node)
+ return 0;
- if (!node) {
- node = kmalloc(sizeof(*node),
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!node)
- return -ENOMEM;
-
- node_info = kmalloc(sizeof(*node_info),
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
- if (!node_info) {
- kfree(node);
- return -ENOMEM;
- }
-
- spin_lock_init(&node_info->pdg.lock);
- INIT_LIST_HEAD(&node_info->pdg.list);
- node_info->pdg.sz = 0;
-
- ud->device.driver_data = node_info;
- node->ud = ud;
-
- priv = netdev_priv(hi->dev);
- list_add_tail(&node->list, &priv->ip_node_list);
- }
-
- return 0;
+ return eth1394_new_node(hi, ud);
}
-
static struct ieee1394_device_id eth1394_id_table[] = {
{
.match_flags = (IEEE1394_MATCH_SPECIFIER_ID |
@@ -473,7 +451,7 @@ static struct ieee1394_device_id eth1394_id_table[] = {
MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table);
static struct hpsb_protocol_driver eth1394_proto_driver = {
- .name = ETH1394_DRIVER_NAME,
+ .name = driver_name,
.id_table = eth1394_id_table,
.update = eth1394_update,
.driver = {
@@ -482,47 +460,50 @@ static struct hpsb_protocol_driver eth1394_proto_driver = {
},
};
-
-static void ether1394_reset_priv (struct net_device *dev, int set_mtu)
+static void ether1394_reset_priv(struct net_device *dev, int set_mtu)
{
unsigned long flags;
int i;
struct eth1394_priv *priv = netdev_priv(dev);
struct hpsb_host *host = priv->host;
- u64 guid = get_unaligned((u64*)&(host->csr.rom->bus_info_data[3]));
- u16 maxpayload = 1 << (host->csr.max_rec + 1);
+ u64 guid = get_unaligned((u64 *)&(host->csr.rom->bus_info_data[3]));
int max_speed = IEEE1394_SPEED_MAX;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
- memset(priv->ud_list, 0, sizeof(struct node_entry*) * ALL_NODES);
+ memset(priv->ud_list, 0, sizeof(priv->ud_list));
priv->bc_maxpayload = 512;
/* Determine speed limit */
- for (i = 0; i < host->node_count; i++)
+ /* FIXME: This is broken for nodes with link speed < PHY speed,
+ * and it is suboptimal for S200B...S800B hardware.
+ * The result of nodemgr's speed probe should be used somehow. */
+ for (i = 0; i < host->node_count; i++) {
+ /* take care of S100B...S400B PHY ports */
+ if (host->speed[i] == SELFID_SPEED_UNKNOWN) {
+ max_speed = IEEE1394_SPEED_100;
+ break;
+ }
if (max_speed > host->speed[i])
max_speed = host->speed[i];
+ }
priv->bc_sspd = max_speed;
- /* We'll use our maxpayload as the default mtu */
if (set_mtu) {
- dev->mtu = min(ETH1394_DATA_LEN,
- (int)(maxpayload -
- (sizeof(union eth1394_hdr) +
- ETHER1394_GASP_OVERHEAD)));
+ /* Use the RFC 2734 default 1500 octets or the maximum payload
+ * as initial MTU */
+ dev->mtu = min(1500, ether1394_max_mtu(host));
/* Set our hardware address while we're at it */
memcpy(dev->dev_addr, &guid, sizeof(u64));
memset(dev->broadcast, 0xff, sizeof(u64));
}
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
-/* This function is called right before register_netdev */
-static void ether1394_init_dev (struct net_device *dev)
+static void ether1394_init_dev(struct net_device *dev)
{
- /* Our functions */
dev->open = ether1394_open;
dev->stop = ether1394_stop;
dev->hard_start_xmit = ether1394_tx;
@@ -535,10 +516,9 @@ static void ether1394_init_dev (struct net_device *dev)
dev->hard_header_cache = ether1394_header_cache;
dev->header_cache_update= ether1394_header_cache_update;
dev->hard_header_parse = ether1394_header_parse;
- dev->set_mac_address = ether1394_mac_addr;
+
SET_ETHTOOL_OPS(dev, &ethtool_ops);
- /* Some constants */
dev->watchdog_timeo = ETHER1394_TIMEOUT;
dev->flags = IFF_BROADCAST | IFF_MULTICAST;
dev->features = NETIF_F_HIGHDMA;
@@ -546,7 +526,8 @@ static void ether1394_init_dev (struct net_device *dev)
dev->hard_header_len = ETH1394_HLEN;
dev->type = ARPHRD_IEEE1394;
- ether1394_reset_priv (dev, 1);
+ /* FIXME: This value was copied from ether_setup(). Is it too much? */
+ dev->tx_queue_len = 1000;
}
/*
@@ -554,34 +535,33 @@ static void ether1394_init_dev (struct net_device *dev)
* when the module is installed. This is where we add all of our ethernet
* devices. One for each host.
*/
-static void ether1394_add_host (struct hpsb_host *host)
+static void ether1394_add_host(struct hpsb_host *host)
{
struct eth1394_host_info *hi = NULL;
struct net_device *dev = NULL;
struct eth1394_priv *priv;
u64 fifo_addr;
- if (!(host->config_roms & HPSB_CONFIG_ROM_ENTRY_IP1394))
+ if (hpsb_config_rom_ip1394_add(host) != 0) {
+ ETH1394_PRINT_G(KERN_ERR, "Can't add IP-over-1394 ROM entry\n");
return;
+ }
fifo_addr = hpsb_allocate_and_register_addrspace(
&eth1394_highlevel, host, &addr_ops,
ETHER1394_REGION_ADDR_LEN, ETHER1394_REGION_ADDR_LEN,
CSR1212_INVALID_ADDR_SPACE, CSR1212_INVALID_ADDR_SPACE);
- if (fifo_addr == CSR1212_INVALID_ADDR_SPACE)
- goto out;
-
- /* We should really have our own alloc_hpsbdev() function in
- * net_init.c instead of calling the one for ethernet then hijacking
- * it for ourselves. That way we'd be a real networking device. */
- dev = alloc_etherdev(sizeof (struct eth1394_priv));
+ if (fifo_addr == CSR1212_INVALID_ADDR_SPACE) {
+ ETH1394_PRINT_G(KERN_ERR, "Cannot register CSR space\n");
+ hpsb_config_rom_ip1394_remove(host);
+ return;
+ }
+ dev = alloc_netdev(sizeof(*priv), "eth%d", ether1394_init_dev);
if (dev == NULL) {
- ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to allocate "
- "etherdevice for IEEE 1394 device %s-%d\n",
- host->driver->name, host->id);
+ ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
goto out;
- }
+ }
SET_MODULE_OWNER(dev);
#if 0
@@ -590,31 +570,26 @@ static void ether1394_add_host (struct hpsb_host *host)
#endif
priv = netdev_priv(dev);
-
INIT_LIST_HEAD(&priv->ip_node_list);
-
spin_lock_init(&priv->lock);
priv->host = host;
priv->local_fifo = fifo_addr;
hi = hpsb_create_hostinfo(&eth1394_highlevel, host, sizeof(*hi));
-
if (hi == NULL) {
- ETH1394_PRINT_G (KERN_ERR, "Out of memory trying to create "
- "hostinfo for IEEE 1394 device %s-%d\n",
- host->driver->name, host->id);
+ ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
goto out;
- }
+ }
- ether1394_init_dev(dev);
+ ether1394_reset_priv(dev, 1);
- if (register_netdev (dev)) {
- ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
+ if (register_netdev(dev)) {
+ ETH1394_PRINT_G(KERN_ERR, "Cannot register the driver\n");
goto out;
}
- ETH1394_PRINT (KERN_INFO, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (fw-host%d)\n",
- host->id);
+ ETH1394_PRINT(KERN_INFO, dev->name, "IPv4 over IEEE 1394 (fw-host%d)\n",
+ host->id);
hi->host = host;
hi->dev = dev;
@@ -623,61 +598,37 @@ static void ether1394_add_host (struct hpsb_host *host)
* be checked when the eth device is opened. */
priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
- priv->iso = hpsb_iso_recv_init(host,
- ETHER1394_ISO_BUF_SIZE,
- ETHER1394_GASP_BUFFERS,
- priv->broadcast_channel,
- HPSB_ISO_DMA_PACKET_PER_BUFFER,
- 1, ether1394_iso);
- if (priv->iso == NULL) {
- ETH1394_PRINT(KERN_ERR, dev->name,
- "Could not allocate isochronous receive context "
- "for the broadcast channel\n");
- priv->bc_state = ETHER1394_BC_ERROR;
- } else {
- if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0)
- priv->bc_state = ETHER1394_BC_STOPPED;
- else
- priv->bc_state = ETHER1394_BC_RUNNING;
- }
-
+ ether1394_recv_init(priv);
return;
-
out:
- if (dev != NULL)
+ if (dev)
free_netdev(dev);
if (hi)
hpsb_destroy_hostinfo(&eth1394_highlevel, host);
-
- return;
+ hpsb_unregister_addrspace(&eth1394_highlevel, host, fifo_addr);
+ hpsb_config_rom_ip1394_remove(host);
}
/* Remove a card from our list */
-static void ether1394_remove_host (struct hpsb_host *host)
+static void ether1394_remove_host(struct hpsb_host *host)
{
struct eth1394_host_info *hi;
+ struct eth1394_priv *priv;
hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
- if (hi != NULL) {
- struct eth1394_priv *priv = netdev_priv(hi->dev);
-
- hpsb_unregister_addrspace(&eth1394_highlevel, host,
- priv->local_fifo);
-
- if (priv->iso != NULL)
- hpsb_iso_shutdown(priv->iso);
-
- if (hi->dev) {
- unregister_netdev (hi->dev);
- free_netdev(hi->dev);
- }
- }
-
- return;
+ if (!hi)
+ return;
+ priv = netdev_priv(hi->dev);
+ hpsb_unregister_addrspace(&eth1394_highlevel, host, priv->local_fifo);
+ hpsb_config_rom_ip1394_remove(host);
+ if (priv->iso)
+ hpsb_iso_shutdown(priv->iso);
+ unregister_netdev(hi->dev);
+ free_netdev(hi->dev);
}
-/* A reset has just arisen */
-static void ether1394_host_reset (struct hpsb_host *host)
+/* A bus reset happened */
+static void ether1394_host_reset(struct hpsb_host *host)
{
struct eth1394_host_info *hi;
struct eth1394_priv *priv;
@@ -690,24 +641,23 @@ static void ether1394_host_reset (struct hpsb_host *host)
hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
/* This can happen for hosts that we don't use */
- if (hi == NULL)
+ if (!hi)
return;
dev = hi->dev;
- priv = (struct eth1394_priv *)netdev_priv(dev);
+ priv = netdev_priv(dev);
- /* Reset our private host data, but not our mtu */
- netif_stop_queue (dev);
- ether1394_reset_priv (dev, 0);
+ /* Reset our private host data, but not our MTU */
+ netif_stop_queue(dev);
+ ether1394_reset_priv(dev, 0);
list_for_each_entry(node, &priv->ip_node_list, list) {
- node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
+ node_info = node->ud->device.driver_data;
spin_lock_irqsave(&node_info->pdg.lock, flags);
- list_for_each_safe(lh, n, &node_info->pdg.list) {
+ list_for_each_safe(lh, n, &node_info->pdg.list)
purge_partial_datagram(lh);
- }
INIT_LIST_HEAD(&(node_info->pdg.list));
node_info->pdg.sz = 0;
@@ -715,7 +665,7 @@ static void ether1394_host_reset (struct hpsb_host *host)
spin_unlock_irqrestore(&node_info->pdg.lock, flags);
}
- netif_wake_queue (dev);
+ netif_wake_queue(dev);
}
/******************************************
@@ -723,7 +673,6 @@ static void ether1394_host_reset (struct hpsb_host *host)
******************************************/
/* These functions have been adapted from net/ethernet/eth.c */
-
/* Create a fake MAC header for an arbitrary protocol layer.
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp). */
@@ -731,25 +680,24 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr,
unsigned len)
{
- struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
+ struct eth1394hdr *eth =
+ (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
eth->h_proto = htons(type);
- if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) {
+ if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
memset(eth->h_dest, 0, dev->addr_len);
- return(dev->hard_header_len);
+ return dev->hard_header_len;
}
if (daddr) {
- memcpy(eth->h_dest,daddr,dev->addr_len);
+ memcpy(eth->h_dest, daddr, dev->addr_len);
return dev->hard_header_len;
}
return -dev->hard_header_len;
-
}
-
/* Rebuild the faked MAC header. This is called after an ARP
* (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields.
@@ -760,38 +708,30 @@ static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
static int ether1394_rebuild_header(struct sk_buff *skb)
{
struct eth1394hdr *eth = (struct eth1394hdr *)skb->data;
- struct net_device *dev = skb->dev;
- switch (eth->h_proto) {
-
-#ifdef CONFIG_INET
- case __constant_htons(ETH_P_IP):
- return arp_find((unsigned char*)&eth->h_dest, skb);
-#endif
- default:
- ETH1394_PRINT(KERN_DEBUG, dev->name,
- "unable to resolve type %04x addresses.\n",
- ntohs(eth->h_proto));
- break;
- }
+ if (eth->h_proto == htons(ETH_P_IP))
+ return arp_find((unsigned char *)&eth->h_dest, skb);
+ ETH1394_PRINT(KERN_DEBUG, skb->dev->name,
+ "unable to resolve type %04x addresses\n",
+ ntohs(eth->h_proto));
return 0;
}
static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
{
struct net_device *dev = skb->dev;
+
memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
return ETH1394_ALEN;
}
-
static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
{
unsigned short type = hh->hh_type;
- struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) +
- (16 - ETH1394_HLEN));
struct net_device *dev = neigh->dev;
+ struct eth1394hdr *eth =
+ (struct eth1394hdr *)((u8 *)hh->hh_data + 16 - ETH1394_HLEN);
if (type == htons(ETH_P_802_3))
return -1;
@@ -808,38 +748,25 @@ static void ether1394_header_cache_update(struct hh_cache *hh,
struct net_device *dev,
unsigned char * haddr)
{
- memcpy(((u8*)hh->hh_data) + (16 - ETH1394_HLEN), haddr, dev->addr_len);
+ memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
}
-static int ether1394_mac_addr(struct net_device *dev, void *p)
-{
- if (netif_running(dev))
- return -EBUSY;
-
- /* Not going to allow setting the MAC address, we really need to use
- * the real one supplied by the hardware */
- return -EINVAL;
- }
-
-
-
/******************************************
* Datagram reception code
******************************************/
/* Copied from net/ethernet/eth.c */
-static inline u16 ether1394_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static u16 ether1394_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct eth1394hdr *eth;
unsigned char *rawp;
skb_reset_mac_header(skb);
- skb_pull (skb, ETH1394_HLEN);
+ skb_pull(skb, ETH1394_HLEN);
eth = eth1394_hdr(skb);
if (*eth->h_dest & 1) {
- if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0)
+ if (memcmp(eth->h_dest, dev->broadcast, dev->addr_len) == 0)
skb->pkt_type = PACKET_BROADCAST;
#if 0
else
@@ -848,47 +775,45 @@ static inline u16 ether1394_type_trans(struct sk_buff *skb,
} else {
if (memcmp(eth->h_dest, dev->dev_addr, dev->addr_len))
skb->pkt_type = PACKET_OTHERHOST;
- }
+ }
- if (ntohs (eth->h_proto) >= 1536)
+ if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
rawp = skb->data;
- if (*(unsigned short *)rawp == 0xFFFF)
- return htons (ETH_P_802_3);
+ if (*(unsigned short *)rawp == 0xFFFF)
+ return htons(ETH_P_802_3);
- return htons (ETH_P_802_2);
+ return htons(ETH_P_802_2);
}
/* Parse an encapsulated IP1394 header into an ethernet frame packet.
* We also perform ARP translation here, if need be. */
-static inline u16 ether1394_parse_encap(struct sk_buff *skb,
- struct net_device *dev,
- nodeid_t srcid, nodeid_t destid,
- u16 ether_type)
+static u16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
+ nodeid_t srcid, nodeid_t destid,
+ u16 ether_type)
{
struct eth1394_priv *priv = netdev_priv(dev);
u64 dest_hw;
unsigned short ret = 0;
- /* Setup our hw addresses. We use these to build the
- * ethernet header. */
+ /* Setup our hw addresses. We use these to build the ethernet header. */
if (destid == (LOCAL_BUS | ALL_NODES))
dest_hw = ~0ULL; /* broadcast */
else
- dest_hw = cpu_to_be64((((u64)priv->host->csr.guid_hi) << 32) |
+ dest_hw = cpu_to_be64((u64)priv->host->csr.guid_hi << 32 |
priv->host->csr.guid_lo);
/* If this is an ARP packet, convert it. First, we want to make
* use of some of the fields, since they tell us a little bit
* about the sending machine. */
if (ether_type == htons(ETH_P_ARP)) {
- struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data;
+ struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
struct arphdr *arp = (struct arphdr *)skb->data;
unsigned char *arp_ptr = (unsigned char *)(arp + 1);
u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 |
- ntohl(arp1394->fifo_lo);
+ ntohl(arp1394->fifo_lo);
u8 max_rec = min(priv->host->csr.max_rec,
(u8)(arp1394->max_rec));
int sspd = arp1394->sspd;
@@ -902,16 +827,17 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
if (sspd > 5 || sspd < 0)
sspd = 0;
- maxpayload = min(eth1394_speedto_maxpayload[sspd], (u16)(1 << (max_rec + 1)));
+ maxpayload = min(eth1394_speedto_maxpayload[sspd],
+ (u16)(1 << (max_rec + 1)));
guid = get_unaligned(&arp1394->s_uniq_id);
node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid));
- if (!node) {
+ if (!node)
return 0;
- }
- node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
+ node_info =
+ (struct eth1394_node_info *)node->ud->device.driver_data;
/* Update our speed/payload/fifo_offset table */
node_info->maxpayload = maxpayload;
@@ -930,7 +856,7 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
arp->ar_hln = 8;
arp_ptr += arp->ar_hln; /* skip over sender unique id */
- *(u32*)arp_ptr = arp1394->sip; /* move sender IP addr */
+ *(u32 *)arp_ptr = arp1394->sip; /* move sender IP addr */
arp_ptr += arp->ar_pln; /* skip over sender IP addr */
if (arp->ar_op == htons(ARPOP_REQUEST))
@@ -947,65 +873,65 @@ static inline u16 ether1394_parse_encap(struct sk_buff *skb,
return ret;
}
-static inline int fragment_overlap(struct list_head *frag_list, int offset, int len)
+static int fragment_overlap(struct list_head *frag_list, int offset, int len)
{
struct fragment_info *fi;
+ int end = offset + len;
- list_for_each_entry(fi, frag_list, list) {
- if ( ! ((offset > (fi->offset + fi->len - 1)) ||
- ((offset + len - 1) < fi->offset)))
+ list_for_each_entry(fi, frag_list, list)
+ if (offset < fi->offset + fi->len && end > fi->offset)
return 1;
- }
+
return 0;
}
-static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
+static struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl)
{
struct partial_datagram *pd;
- list_for_each_entry(pd, pdgl, list) {
+ list_for_each_entry(pd, pdgl, list)
if (pd->dgl == dgl)
return &pd->list;
- }
+
return NULL;
}
/* Assumes that new fragment does not overlap any existing fragments */
-static inline int new_fragment(struct list_head *frag_info, int offset, int len)
+static int new_fragment(struct list_head *frag_info, int offset, int len)
{
struct list_head *lh;
struct fragment_info *fi, *fi2, *new;
list_for_each(lh, frag_info) {
fi = list_entry(lh, struct fragment_info, list);
- if ((fi->offset + fi->len) == offset) {
+ if (fi->offset + fi->len == offset) {
/* The new fragment can be tacked on to the end */
fi->len += len;
/* Did the new fragment plug a hole? */
fi2 = list_entry(lh->next, struct fragment_info, list);
- if ((fi->offset + fi->len) == fi2->offset) {
+ if (fi->offset + fi->len == fi2->offset) {
/* glue fragments together */
fi->len += fi2->len;
list_del(lh->next);
kfree(fi2);
}
return 0;
- } else if ((offset + len) == fi->offset) {
+ } else if (offset + len == fi->offset) {
/* The new fragment can be tacked on to the beginning */
fi->offset = offset;
fi->len += len;
/* Did the new fragment plug a hole? */
fi2 = list_entry(lh->prev, struct fragment_info, list);
- if ((fi2->offset + fi2->len) == fi->offset) {
+ if (fi2->offset + fi2->len == fi->offset) {
/* glue fragments together */
fi2->len += fi->len;
list_del(lh);
kfree(fi);
}
return 0;
- } else if (offset > (fi->offset + fi->len)) {
+ } else if (offset > fi->offset + fi->len) {
break;
- } else if ((offset + len) < fi->offset) {
+ } else if (offset + len < fi->offset) {
lh = lh->prev;
break;
}
@@ -1019,14 +945,12 @@ static inline int new_fragment(struct list_head *frag_info, int offset, int len)
new->len = len;
list_add(&new->list, lh);
-
return 0;
}
-static inline int new_partial_datagram(struct net_device *dev,
- struct list_head *pdgl, int dgl,
- int dg_size, char *frag_buf,
- int frag_off, int frag_len)
+static int new_partial_datagram(struct net_device *dev, struct list_head *pdgl,
+ int dgl, int dg_size, char *frag_buf,
+ int frag_off, int frag_len)
{
struct partial_datagram *new;
@@ -1059,33 +983,33 @@ static inline int new_partial_datagram(struct net_device *dev,
memcpy(new->pbuf + frag_off, frag_buf, frag_len);
list_add(&new->list, pdgl);
-
return 0;
}
-static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
- char *frag_buf, int frag_off, int frag_len)
+static int update_partial_datagram(struct list_head *pdgl, struct list_head *lh,
+ char *frag_buf, int frag_off, int frag_len)
{
- struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list);
+ struct partial_datagram *pd =
+ list_entry(lh, struct partial_datagram, list);
- if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0) {
+ if (new_fragment(&pd->frag_info, frag_off, frag_len) < 0)
return -ENOMEM;
- }
memcpy(pd->pbuf + frag_off, frag_buf, frag_len);
/* Move list entry to beginnig of list so that oldest partial
* datagrams percolate to the end of the list */
list_move(lh, pdgl);
-
return 0;
}
-static inline int is_datagram_complete(struct list_head *lh, int dg_size)
+static int is_datagram_complete(struct list_head *lh, int dg_size)
{
- struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list);
- struct fragment_info *fi = list_entry(pd->frag_info.next,
- struct fragment_info, list);
+ struct partial_datagram *pd;
+ struct fragment_info *fi;
+
+ pd = list_entry(lh, struct partial_datagram, list);
+ fi = list_entry(pd->frag_info.next, struct fragment_info, list);
return (fi->len == dg_size);
}
@@ -1108,7 +1032,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
if (!ud) {
struct eth1394_node_ref *node;
node = eth1394_find_node_nodeid(&priv->ip_node_list, srcid);
- if (!node) {
+ if (unlikely(!node)) {
HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid "
"lookup failure: " NODE_BUS_FMT,
NODE_BUS_ARGS(priv->host, srcid));
@@ -1120,7 +1044,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
}
- node_info = (struct eth1394_node_info*)ud->device.driver_data;
+ node_info = (struct eth1394_node_info *)ud->device.driver_data;
/* First, did we receive a fragmented or unfragmented datagram? */
hdr->words.word1 = ntohs(hdr->words.word1);
@@ -1133,13 +1057,14 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
* high level network layer. */
skb = dev_alloc_skb(len + dev->hard_header_len + 15);
- if (!skb) {
- HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+ if (unlikely(!skb)) {
+ ETH1394_PRINT_G(KERN_ERR, "Out of memory\n");
priv->stats.rx_dropped++;
return -1;
}
skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
- memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len);
+ memcpy(skb_put(skb, len - hdr_len), buf + hdr_len,
+ len - hdr_len);
ether_type = hdr->uf.ether_type;
} else {
/* A datagram fragment has been received, now the fun begins. */
@@ -1224,9 +1149,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
pd = list_entry(lh, struct partial_datagram, list);
- if (hdr->common.lf == ETH1394_HDR_LF_FF) {
+ if (hdr->common.lf == ETH1394_HDR_LF_FF)
pd->ether_type = ether_type;
- }
if (is_datagram_complete(lh, dg_size)) {
ether_type = pd->ether_type;
@@ -1253,8 +1177,8 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid,
ether_type);
-
spin_lock_irqsave(&priv->lock, flags);
+
if (!skb->protocol) {
priv->stats.rx_errors++;
priv->stats.rx_dropped++;
@@ -1288,9 +1212,9 @@ static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
struct eth1394_host_info *hi;
hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
- if (hi == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
- host->driver->name);
+ if (unlikely(!hi)) {
+ ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
+ host->id);
return RCODE_ADDRESS_ERROR;
}
@@ -1314,9 +1238,9 @@ static void ether1394_iso(struct hpsb_iso *iso)
int nready;
hi = hpsb_get_hostinfo(&eth1394_highlevel, iso->host);
- if (hi == NULL) {
- ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n",
- iso->host->driver->name);
+ if (unlikely(!hi)) {
+ ETH1394_PRINT_G(KERN_ERR, "No net device at fw-host%d\n",
+ iso->host->id);
return;
}
@@ -1326,20 +1250,20 @@ static void ether1394_iso(struct hpsb_iso *iso)
for (i = 0; i < nready; i++) {
struct hpsb_iso_packet_info *info =
&iso->infos[(iso->first_packet + i) % iso->buf_packets];
- data = (quadlet_t*) (iso->data_buf.kvirt + info->offset);
+ data = (quadlet_t *)(iso->data_buf.kvirt + info->offset);
/* skip over GASP header */
buf = (char *)data + 8;
len = info->len - 8;
- specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) |
- ((be32_to_cpu(data[1]) & 0xff000000) >> 24));
+ specifier_id = (be32_to_cpu(data[0]) & 0xffff) << 8 |
+ (be32_to_cpu(data[1]) & 0xff000000) >> 24;
source_id = be32_to_cpu(data[0]) >> 16;
priv = netdev_priv(dev);
- if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) ||
- specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
+ if (info->channel != (iso->host->csr.broadcast_channel & 0x3f)
+ || specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
/* This packet is not for us */
continue;
}
@@ -1367,35 +1291,31 @@ static void ether1394_iso(struct hpsb_iso *iso)
* speed, and unicast FIFO address information between the sender_unique_id
* and the IP addresses.
*/
-static inline void ether1394_arp_to_1394arp(struct sk_buff *skb,
- struct net_device *dev)
+static void ether1394_arp_to_1394arp(struct sk_buff *skb,
+ struct net_device *dev)
{
struct eth1394_priv *priv = netdev_priv(dev);
-
struct arphdr *arp = (struct arphdr *)skb->data;
unsigned char *arp_ptr = (unsigned char *)(arp + 1);
struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
- /* Believe it or not, all that need to happen is sender IP get moved
- * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */
arp1394->hw_addr_len = 16;
arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN);
arp1394->max_rec = priv->host->csr.max_rec;
arp1394->sspd = priv->host->csr.lnk_spd;
- arp1394->fifo_hi = htons (priv->local_fifo >> 32);
- arp1394->fifo_lo = htonl (priv->local_fifo & ~0x0);
-
- return;
+ arp1394->fifo_hi = htons(priv->local_fifo >> 32);
+ arp1394->fifo_lo = htonl(priv->local_fifo & ~0x0);
}
/* We need to encapsulate the standard header with our own. We use the
* ethernet header's proto for our own. */
-static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
- __be16 proto,
- union eth1394_hdr *hdr,
- u16 dg_size, u16 dgl)
+static unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
+ __be16 proto,
+ union eth1394_hdr *hdr,
+ u16 dg_size, u16 dgl)
{
- unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
+ unsigned int adj_max_payload =
+ max_payload - hdr_type_len[ETH1394_HDR_LF_UF];
/* Does it all fit in one packet? */
if (dg_size <= adj_max_payload) {
@@ -1408,19 +1328,19 @@ static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload,
hdr->ff.dgl = dgl;
adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF];
}
- return((dg_size + (adj_max_payload - 1)) / adj_max_payload);
+ return (dg_size + adj_max_payload - 1) / adj_max_payload;
}
-static inline unsigned int ether1394_encapsulate(struct sk_buff *skb,
- unsigned int max_payload,
- union eth1394_hdr *hdr)
+static unsigned int ether1394_encapsulate(struct sk_buff *skb,
+ unsigned int max_payload,
+ union eth1394_hdr *hdr)
{
union eth1394_hdr *bufhdr;
int ftype = hdr->common.lf;
int hdrsz = hdr_type_len[ftype];
unsigned int adj_max_payload = max_payload - hdrsz;
- switch(ftype) {
+ switch (ftype) {
case ETH1394_HDR_LF_UF:
bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz);
bufhdr->words.word1 = htons(hdr->words.word1);
@@ -1449,11 +1369,10 @@ static inline unsigned int ether1394_encapsulate(struct sk_buff *skb,
bufhdr->words.word3 = htons(hdr->words.word3);
bufhdr->words.word4 = 0;
}
-
return min(max_payload, skb->len);
}
-static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
+static struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host)
{
struct hpsb_packet *p;
@@ -1466,61 +1385,57 @@ static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host
return p;
}
-static inline int ether1394_prep_write_packet(struct hpsb_packet *p,
- struct hpsb_host *host,
- nodeid_t node, u64 addr,
- void * data, int tx_len)
+static int ether1394_prep_write_packet(struct hpsb_packet *p,
+ struct hpsb_host *host, nodeid_t node,
+ u64 addr, void *data, int tx_len)
{
p->node_id = node;
p->data = NULL;
p->tcode = TCODE_WRITEB;
- p->header[1] = (host->node_id << 16) | (addr >> 32);
+ p->header[1] = host->node_id << 16 | addr >> 32;
p->header[2] = addr & 0xffffffff;
p->header_size = 16;
p->expect_response = 1;
if (hpsb_get_tlabel(p)) {
- ETH1394_PRINT_G(KERN_ERR, "No more tlabels left while sending "
- "to node " NODE_BUS_FMT "\n", NODE_BUS_ARGS(host, node));
+ ETH1394_PRINT_G(KERN_ERR, "Out of tlabels\n");
return -1;
}
- p->header[0] = (p->node_id << 16) | (p->tlabel << 10)
- | (1 << 8) | (TCODE_WRITEB << 4);
+ p->header[0] =
+ p->node_id << 16 | p->tlabel << 10 | 1 << 8 | TCODE_WRITEB << 4;
p->header[3] = tx_len << 16;
p->data_size = (tx_len + 3) & ~3;
- p->data = (quadlet_t*)data;
+ p->data = data;
return 0;
}
-static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p,
- struct eth1394_priv *priv,
- struct sk_buff *skb, int length)
+static void ether1394_prep_gasp_packet(struct hpsb_packet *p,
+ struct eth1394_priv *priv,
+ struct sk_buff *skb, int length)
{
p->header_size = 4;
p->tcode = TCODE_STREAM_DATA;
- p->header[0] = (length << 16) | (3 << 14)
- | ((priv->broadcast_channel) << 8)
- | (TCODE_STREAM_DATA << 4);
+ p->header[0] = length << 16 | 3 << 14 | priv->broadcast_channel << 8 |
+ TCODE_STREAM_DATA << 4;
p->data_size = length;
- p->data = ((quadlet_t*)skb->data) - 2;
- p->data[0] = cpu_to_be32((priv->host->node_id << 16) |
+ p->data = (quadlet_t *)skb->data - 2;
+ p->data[0] = cpu_to_be32(priv->host->node_id << 16 |
ETHER1394_GASP_SPECIFIER_ID_HI);
- p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) |
+ p->data[1] = cpu_to_be32(ETHER1394_GASP_SPECIFIER_ID_LO << 24 |
ETHER1394_GASP_VERSION);
- /* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES)
- * prevents hpsb_send_packet() from setting the speed to an arbitrary
- * value based on packet->node_id if packet->node_id is not set. */
- p->node_id = ALL_NODES;
p->speed_code = priv->bc_sspd;
+
+ /* prevent hpsb_send_packet() from overriding our speed code */
+ p->node_id = LOCAL_BUS | ALL_NODES;
}
-static inline void ether1394_free_packet(struct hpsb_packet *packet)
+static void ether1394_free_packet(struct hpsb_packet *packet)
{
if (packet->tcode != TCODE_STREAM_DATA)
hpsb_free_tlabel(packet);
@@ -1539,7 +1454,7 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
return -1;
if (ptask->tx_type == ETH1394_GASP) {
- int length = tx_len + (2 * sizeof(quadlet_t));
+ int length = tx_len + 2 * sizeof(quadlet_t);
ether1394_prep_gasp_packet(packet, priv, ptask->skb, length);
} else if (ether1394_prep_write_packet(packet, priv->host,
@@ -1562,13 +1477,11 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len)
return 0;
}
-
/* Task function to be run when a datagram transmission is completed */
-static inline void ether1394_dg_complete(struct packet_task *ptask, int fail)
+static void ether1394_dg_complete(struct packet_task *ptask, int fail)
{
struct sk_buff *skb = ptask->skb;
- struct net_device *dev = skb->dev;
- struct eth1394_priv *priv = netdev_priv(dev);
+ struct eth1394_priv *priv = netdev_priv(skb->dev);
unsigned long flags;
/* Statistics */
@@ -1586,7 +1499,6 @@ static inline void ether1394_dg_complete(struct packet_task *ptask, int fail)
kmem_cache_free(packet_task_cache, ptask);
}
-
/* Callback for when a packet has been sent and the status of that packet is
* known */
static void ether1394_complete_cb(void *__ptask)
@@ -1614,19 +1526,15 @@ static void ether1394_complete_cb(void *__ptask)
}
}
-
-
/* Transmit a packet (called by kernel) */
-static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
+static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
{
- gfp_t kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
struct eth1394hdr *eth;
struct eth1394_priv *priv = netdev_priv(dev);
__be16 proto;
unsigned long flags;
nodeid_t dest_node;
eth1394_tx_type tx_type;
- int ret = 0;
unsigned int tx_len;
unsigned int max_payload;
u16 dg_size;
@@ -1635,29 +1543,24 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
struct eth1394_node_ref *node;
struct eth1394_node_info *node_info = NULL;
- ptask = kmem_cache_alloc(packet_task_cache, kmflags);
- if (ptask == NULL) {
- ret = -ENOMEM;
+ ptask = kmem_cache_alloc(packet_task_cache, GFP_ATOMIC);
+ if (ptask == NULL)
goto fail;
- }
/* XXX Ignore this for now. Noticed that when MacOSX is the IRM,
* it does not set our validity bit. We need to compensate for
* that somewhere else, but not in eth1394. */
#if 0
- if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000) {
- ret = -EAGAIN;
+ if ((priv->host->csr.broadcast_channel & 0xc0000000) != 0xc0000000)
goto fail;
- }
#endif
- if ((skb = skb_share_check (skb, kmflags)) == NULL) {
- ret = -ENOMEM;
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (!skb)
goto fail;
- }
/* Get rid of the fake eth1394 header, but save a pointer */
- eth = (struct eth1394hdr*)skb->data;
+ eth = (struct eth1394hdr *)skb->data;
skb_pull(skb, ETH1394_HLEN);
proto = eth->h_proto;
@@ -1672,7 +1575,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
tx_type = ETH1394_GASP;
dest_node = LOCAL_BUS | ALL_NODES;
max_payload = priv->bc_maxpayload - ETHER1394_GASP_OVERHEAD;
- BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD));
+ BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
dgl = priv->bc_dgl;
if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
priv->bc_dgl++;
@@ -1681,19 +1584,17 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
node = eth1394_find_node_guid(&priv->ip_node_list,
be64_to_cpu(guid));
- if (!node) {
- ret = -EAGAIN;
+ if (!node)
goto fail;
- }
- node_info = (struct eth1394_node_info*)node->ud->device.driver_data;
- if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE) {
- ret = -EAGAIN;
+
+ node_info =
+ (struct eth1394_node_info *)node->ud->device.driver_data;
+ if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
goto fail;
- }
dest_node = node->ud->ne->nodeid;
max_payload = node_info->maxpayload;
- BUG_ON(max_payload < (512 - ETHER1394_GASP_OVERHEAD));
+ BUG_ON(max_payload < 512 - ETHER1394_GASP_OVERHEAD);
dgl = node_info->dgl;
if (max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF])
@@ -1703,7 +1604,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
/* If this is an ARP packet, convert it */
if (proto == htons(ETH_P_ARP))
- ether1394_arp_to_1394arp (skb, dev);
+ ether1394_arp_to_1394arp(skb, dev);
ptask->hdr.words.word1 = 0;
ptask->hdr.words.word2 = 0;
@@ -1726,9 +1627,8 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
ptask->tx_type = tx_type;
ptask->max_payload = max_payload;
- ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto,
- &ptask->hdr, dg_size,
- dgl);
+ ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload,
+ proto, &ptask->hdr, dg_size, dgl);
/* Add the encapsulation header to the fragment */
tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr);
@@ -1737,7 +1637,7 @@ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev)
goto fail;
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
fail:
if (ptask)
kmem_cache_free(packet_task_cache, ptask);
@@ -1745,40 +1645,56 @@ fail:
if (skb != NULL)
dev_kfree_skb(skb);
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
priv->stats.tx_dropped++;
priv->stats.tx_errors++;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
if (netif_queue_stopped(dev))
netif_wake_queue(dev);
- return 0; /* returning non-zero causes serious problems */
+ /*
+ * FIXME: According to a patch from 2003-02-26, "returning non-zero
+ * causes serious problems" here, allegedly. Before that patch,
+ * -ERRNO was returned which is not appropriate under Linux 2.6.
+ * Perhaps more needs to be done? Stop the queue in serious
+ * conditions and restart it elsewhere?
+ */
+ /* return NETDEV_TX_BUSY; */
+ return NETDEV_TX_OK;
}
-static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+static void ether1394_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
{
- strcpy (info->driver, driver_name);
- /* FIXME XXX provide sane businfo */
- strcpy (info->bus_info, "ieee1394");
+ strcpy(info->driver, driver_name);
+ strcpy(info->bus_info, "ieee1394"); /* FIXME provide more detail? */
}
static struct ethtool_ops ethtool_ops = {
.get_drvinfo = ether1394_get_drvinfo
};
-static int __init ether1394_init_module (void)
+static int __init ether1394_init_module(void)
{
- packet_task_cache = kmem_cache_create("packet_task", sizeof(struct packet_task),
+ int err;
+
+ packet_task_cache = kmem_cache_create("packet_task",
+ sizeof(struct packet_task),
0, 0, NULL, NULL);
+ if (!packet_task_cache)
+ return -ENOMEM;
- /* Register ourselves as a highlevel driver */
hpsb_register_highlevel(&eth1394_highlevel);
-
- return hpsb_register_protocol(&eth1394_proto_driver);
+ err = hpsb_register_protocol(&eth1394_proto_driver);
+ if (err) {
+ hpsb_unregister_highlevel(&eth1394_highlevel);
+ kmem_cache_destroy(packet_task_cache);
+ }
+ return err;
}
-static void __exit ether1394_exit_module (void)
+static void __exit ether1394_exit_module(void)
{
hpsb_unregister_protocol(&eth1394_proto_driver);
hpsb_unregister_highlevel(&eth1394_highlevel);
diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h
index 1e835653514..a3439ee7cb4 100644
--- a/drivers/ieee1394/eth1394.h
+++ b/drivers/ieee1394/eth1394.h
@@ -25,8 +25,11 @@
#define __ETH1394_H
#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <asm/byteorder.h>
#include "ieee1394.h"
+#include "ieee1394_types.h"
/* Register for incoming packets. This is 4096 bytes, which supports up to
* S3200 (per Table 16-3 of IEEE 1394b-2002). */
@@ -34,22 +37,15 @@
/* GASP identifier numbers for IPv4 over IEEE 1394 */
#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
-#define ETHER1394_GASP_SPECIFIER_ID_HI ((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff)
-#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff)
+#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
+#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
#define ETHER1394_GASP_VERSION 1
-#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */
+#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */
-#define ETHER1394_GASP_BUFFERS 16
+#define ETHER1394_GASP_BUFFERS 16
-/* rawiso buffer size - due to a limitation in rawiso, we must limit each
- * GASP buffer to be less than PAGE_SIZE. */
-#define ETHER1394_ISO_BUF_SIZE ETHER1394_GASP_BUFFERS * \
- min((unsigned int)PAGE_SIZE, \
- 2 * (1U << (priv->host->csr.max_rec + 1)))
-
-/* Node set == 64 */
-#define NODE_SET (ALL_NODES + 1)
+#define NODE_SET (ALL_NODES + 1) /* Node set == 64 */
enum eth1394_bc_states { ETHER1394_BC_ERROR,
ETHER1394_BC_RUNNING,
@@ -85,19 +81,14 @@ struct eth1394hdr {
unsigned short h_proto; /* packet type ID field */
} __attribute__((packed));
-#ifdef __KERNEL__
-#include <linux/skbuff.h>
-
static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
{
return (struct eth1394hdr *)skb_mac_header(skb);
}
-#endif
typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
/* IP1394 headers */
-#include <asm/byteorder.h>
/* Unfragmented */
#if defined __BIG_ENDIAN_BITFIELD
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 694da82d820..83a49331275 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -70,8 +70,12 @@ static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
return NULL;
}
-/* Returns a per host/driver data structure that was previously stored by
- * hpsb_create_hostinfo. */
+/**
+ * hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
+ *
+ * Returns a per @host and @hl driver data structure that was previously stored
+ * by hpsb_create_hostinfo.
+ */
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
{
struct hl_host_info *hi = hl_get_hostinfo(hl, host);
@@ -79,7 +83,13 @@ void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
return hi ? hi->data : NULL;
}
-/* If size is zero, then the return here is only valid for error checking */
+/**
+ * hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
+ *
+ * Allocate a hostinfo pointer backed by memory with @data_size and bind it to
+ * to this @hl driver and @host. If @data_size is zero, then the return here is
+ * only valid for error checking.
+ */
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
size_t data_size)
{
@@ -113,6 +123,11 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
return data;
}
+/**
+ * hpsb_set_hostinfo - set the hostinfo pointer to something useful
+ *
+ * Usually follows a call to hpsb_create_hostinfo, where the size is 0.
+ */
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
void *data)
{
@@ -132,6 +147,11 @@ int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
return -EINVAL;
}
+/**
+ * hpsb_destroy_hostinfo - free and remove a hostinfo pointer
+ *
+ * Free and remove the hostinfo pointer bound to this @hl driver and @host.
+ */
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
{
struct hl_host_info *hi;
@@ -147,6 +167,12 @@ void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
return;
}
+/**
+ * hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
+ *
+ * Sets an alternate lookup key for the hostinfo bound to this @hl driver and
+ * @host.
+ */
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned long key)
{
@@ -158,6 +184,9 @@ void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
return;
}
+/**
+ * hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
+ */
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
{
struct hl_host_info *hi;
@@ -189,6 +218,12 @@ static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
return 0;
}
+/**
+ * hpsb_register_highlevel - register highlevel driver
+ *
+ * The name pointer in @hl has to stay valid at all times because the string is
+ * not copied.
+ */
void hpsb_register_highlevel(struct hpsb_highlevel *hl)
{
unsigned long flags;
@@ -258,6 +293,9 @@ static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
return 0;
}
+/**
+ * hpsb_unregister_highlevel - unregister highlevel driver
+ */
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
{
unsigned long flags;
@@ -273,6 +311,19 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
}
+/**
+ * hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
+ *
+ * @start and @end are 48 bit pointers and have to be quadlet aligned.
+ * @end points to the first address behind the handled addresses. This
+ * function can be called multiple times for a single hpsb_highlevel @hl to
+ * implement sparse register sets. The requested region must not overlap any
+ * previously allocated region, otherwise registering will fail.
+ *
+ * It returns true for successful allocation. Address spaces can be
+ * unregistered with hpsb_unregister_addrspace. All remaining address spaces
+ * are automatically deallocated together with the hpsb_highlevel @hl.
+ */
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host,
struct hpsb_address_ops *ops,
@@ -348,6 +399,19 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
return retval;
}
+/**
+ * hpsb_register_addrspace - register a host address space
+ *
+ * @start and @end are 48 bit pointers and have to be quadlet aligned.
+ * @end points to the first address behind the handled addresses. This
+ * function can be called multiple times for a single hpsb_highlevel @hl to
+ * implement sparse register sets. The requested region must not overlap any
+ * previously allocated region, otherwise registering will fail.
+ *
+ * It returns true for successful allocation. Address spaces can be
+ * unregistered with hpsb_unregister_addrspace. All remaining address spaces
+ * are automatically deallocated together with the hpsb_highlevel @hl.
+ */
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end)
{
@@ -419,6 +483,11 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
return retval;
}
+/**
+ * hpsb_listen_channel - enable receving a certain isochronous channel
+ *
+ * Reception is handled through the @hl's iso_receive op.
+ */
int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel)
{
@@ -431,6 +500,9 @@ int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
return 0;
}
+/**
+ * hpsb_unlisten_channel - disable receving a certain isochronous channel
+ */
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel)
{
@@ -528,6 +600,17 @@ void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
read_unlock_irqrestore(&hl_irqs_lock, flags);
}
+/*
+ * highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
+ *
+ * These functions are called to handle transactions. They are called when a
+ * packet arrives. The flags argument contains the second word of the first
+ * header quadlet of the incoming packet (containing transaction label, retry
+ * code, transaction code and priority). These functions either return a
+ * response code or a negative number. In the first case a response will be
+ * generated. In the latter case, no response will be sent and the driver which
+ * handled the request will send the response itself.
+ */
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
unsigned int length, u16 flags)
{
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index 4b330117067..63474f7ee69 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -99,16 +99,6 @@ struct hpsb_address_ops {
void highlevel_add_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
-
-/*
- * These functions are called to handle transactions. They are called when a
- * packet arrives. The flags argument contains the second word of the first
- * header quadlet of the incoming packet (containing transaction label, retry
- * code, transaction code and priority). These functions either return a
- * response code or a negative number. In the first case a response will be
- * generated. In the latter case, no response will be sent and the driver which
- * handled the request will send the response itself.
- */
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
unsigned int length, u16 flags);
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
@@ -119,30 +109,13 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
u16 flags);
-
void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length);
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
void *data, size_t length);
-/*
- * Register highlevel driver. The name pointer has to stay valid at all times
- * because the string is not copied.
- */
void hpsb_register_highlevel(struct hpsb_highlevel *hl);
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
-/*
- * Register handlers for host address spaces. Start and end are 48 bit pointers
- * and have to be quadlet aligned. Argument "end" points to the first address
- * behind the handled addresses. This function can be called multiple times for
- * a single hpsb_highlevel to implement sparse register sets. The requested
- * region must not overlap any previously allocated region, otherwise
- * registering will fail.
- *
- * It returns true for successful allocation. Address spaces can be
- * unregistered with hpsb_unregister_addrspace. All remaining address spaces
- * are automatically deallocated together with the hpsb_highlevel.
- */
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host,
struct hpsb_address_ops *ops,
@@ -152,45 +125,19 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
struct hpsb_address_ops *ops, u64 start, u64 end);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
u64 start);
-
-/*
- * Enable or disable receving a certain isochronous channel through the
- * iso_receive op.
- */
int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned int channel);
+ unsigned int channel);
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel);
-/* Retrieve a hostinfo pointer bound to this driver/host */
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-
-/* Allocate a hostinfo pointer of data_size bound to this driver/host */
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
size_t data_size);
-
-/* Free and remove the hostinfo pointer bound to this driver/host */
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
-
-/* Set an alternate lookup key for the hostinfo bound to this driver/host */
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned long key);
-
-/* Retrieve the alternate lookup key for the hostinfo bound to this
- * driver/host */
-unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl,
- struct hpsb_host *host);
-
-/* Retrieve a hostinfo pointer bound to this driver using its alternate key */
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
-
-/* Set the hostinfo pointer to something useful. Usually follows a call to
- * hpsb_create_hostinfo, where the size is 0. */
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
void *data);
-/* Retrieve hpsb_host using a highlevel handle and a key */
-struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl,
- unsigned long key);
-
#endif /* IEEE1394_HIGHLEVEL_H */
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 32a13092193..bd0755c789c 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -15,7 +15,6 @@
#include <linux/list.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
@@ -94,14 +93,6 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
return 0;
}
-/*
- * The pending_packet_queue is special in that it's processed
- * from hardirq context too (such as hpsb_bus_reset()). Hence
- * split the lock class from the usual networking skb-head
- * lock class by using a separate key for it:
- */
-static struct lock_class_key pending_packet_queue_key;
-
static DEFINE_MUTEX(host_num_alloc);
/**
@@ -137,9 +128,7 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
h->hostdata = h + 1;
h->driver = drv;
- skb_queue_head_init(&h->pending_packet_queue);
- lockdep_set_class(&h->pending_packet_queue.lock,
- &pending_packet_queue_key);
+ INIT_LIST_HEAD(&h->pending_packets);
INIT_LIST_HEAD(&h->addr_space);
for (i = 2; i < 16; i++)
@@ -190,7 +179,7 @@ int hpsb_add_host(struct hpsb_host *host)
{
if (hpsb_default_host_entry(host))
return -ENOMEM;
- hpsb_add_extra_config_roms(host);
+
highlevel_add_host(host);
return 0;
}
@@ -212,12 +201,19 @@ void hpsb_remove_host(struct hpsb_host *host)
host->driver = &dummy_driver;
highlevel_remove_host(host);
- hpsb_remove_extra_config_roms(host);
class_device_unregister(&host->class_dev);
device_unregister(&host->device);
}
+/**
+ * hpsb_update_config_rom_image - updates configuration ROM image of a host
+ *
+ * Updates the configuration ROM image of a host. rom_version must be the
+ * current version, otherwise it will fail with return value -1. If this
+ * host does not support config-rom-update, it will return -%EINVAL.
+ * Return value 0 indicates success.
+ */
int hpsb_update_config_rom_image(struct hpsb_host *host)
{
unsigned long reset_delay;
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index 4bf4fb7f67b..feb55d03229 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -3,7 +3,6 @@
#include <linux/device.h>
#include <linux/list.h>
-#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/workqueue.h>
@@ -25,8 +24,7 @@ struct hpsb_host {
atomic_t generation;
- struct sk_buff_head pending_packet_queue;
-
+ struct list_head pending_packets;
struct timer_list timeout;
unsigned long timeout_interval;
@@ -202,12 +200,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
int hpsb_add_host(struct hpsb_host *host);
void hpsb_resume_host(struct hpsb_host *host);
void hpsb_remove_host(struct hpsb_host *host);
-
-/* Updates the configuration rom image of a host. rom_version must be the
- * current version, otherwise it will fail with return value -1. If this
- * host does not support config-rom-update, it will return -EINVAL.
- * Return value 0 indicates success.
- */
int hpsb_update_config_rom_image(struct hpsb_host *host);
#endif /* _IEEE1394_HOSTS_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index d791d08c743..8f71b6a06aa 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -30,7 +30,6 @@
#include <linux/moduleparam.h>
#include <linux/bitops.h>
#include <linux/kdev_t.h>
-#include <linux/skbuff.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
#include <linux/preempt.h>
@@ -96,13 +95,15 @@ static void queue_packet_complete(struct hpsb_packet *packet);
/**
- * hpsb_set_packet_complete_task - set the task that runs when a packet
- * completes. You cannot call this more than once on a single packet
- * before it is sent.
- *
+ * hpsb_set_packet_complete_task - set task that runs when a packet completes
* @packet: the packet whose completion we want the task added to
* @routine: function to call
* @data: data (if any) to pass to the above function
+ *
+ * Set the task that runs when a packet completes. You cannot call this more
+ * than once on a single packet before it is sent.
+ *
+ * Typically, the complete @routine is responsible to call hpsb_free_packet().
*/
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
void (*routine)(void *), void *data)
@@ -115,12 +116,12 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
/**
* hpsb_alloc_packet - allocate new packet structure
- * @data_size: size of the data block to be allocated
+ * @data_size: size of the data block to be allocated, in bytes
*
* This function allocates, initializes and returns a new &struct hpsb_packet.
- * It can be used in interrupt context. A header block is always included, its
- * size is big enough to contain all possible 1394 headers. The data block is
- * only allocated when @data_size is not zero.
+ * It can be used in interrupt context. A header block is always included and
+ * initialized with zeros. Its size is big enough to contain all possible 1394
+ * headers. The data block is only allocated if @data_size is not zero.
*
* For packets for which responses will be received the @data_size has to be big
* enough to contain the response's data block since no further allocation
@@ -135,50 +136,49 @@ void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
*/
struct hpsb_packet *hpsb_alloc_packet(size_t data_size)
{
- struct hpsb_packet *packet = NULL;
- struct sk_buff *skb;
+ struct hpsb_packet *packet;
data_size = ((data_size + 3) & ~3);
- skb = alloc_skb(data_size + sizeof(*packet), GFP_ATOMIC);
- if (skb == NULL)
+ packet = kzalloc(sizeof(*packet) + data_size, GFP_ATOMIC);
+ if (!packet)
return NULL;
- memset(skb->data, 0, data_size + sizeof(*packet));
-
- packet = (struct hpsb_packet *)skb->data;
- packet->skb = skb;
-
- packet->header = packet->embedded_header;
packet->state = hpsb_unused;
packet->generation = -1;
INIT_LIST_HEAD(&packet->driver_list);
+ INIT_LIST_HEAD(&packet->queue);
atomic_set(&packet->refcnt, 1);
if (data_size) {
- packet->data = (quadlet_t *)(skb->data + sizeof(*packet));
- packet->data_size = data_size;
+ packet->data = packet->embedded_data;
+ packet->allocated_data_size = data_size;
}
-
return packet;
}
-
/**
* hpsb_free_packet - free packet and data associated with it
* @packet: packet to free (is NULL safe)
*
- * This function will free packet->data and finally the packet itself.
+ * Frees @packet->data only if it was allocated through hpsb_alloc_packet().
*/
void hpsb_free_packet(struct hpsb_packet *packet)
{
if (packet && atomic_dec_and_test(&packet->refcnt)) {
- BUG_ON(!list_empty(&packet->driver_list));
- kfree_skb(packet->skb);
+ BUG_ON(!list_empty(&packet->driver_list) ||
+ !list_empty(&packet->queue));
+ kfree(packet);
}
}
-
+/**
+ * hpsb_reset_bus - initiate bus reset on the given host
+ * @host: host controller whose bus to reset
+ * @type: one of enum reset_types
+ *
+ * Returns 1 if bus reset already in progress, 0 otherwise.
+ */
int hpsb_reset_bus(struct hpsb_host *host, int type)
{
if (!host->in_bus_reset) {
@@ -229,6 +229,14 @@ int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
return 0;
}
+/**
+ * hpsb_bus_reset - notify a bus reset to the core
+ *
+ * For host driver module usage. Safe to use in interrupt context, although
+ * quite complex; so you may want to run it in the bottom rather than top half.
+ *
+ * Returns 1 if bus reset already in progress, 0 otherwise.
+ */
int hpsb_bus_reset(struct hpsb_host *host)
{
if (host->in_bus_reset) {
@@ -405,6 +413,14 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
}
+/**
+ * hpsb_selfid_received - hand over received selfid packet to the core
+ *
+ * For host driver module usage. Safe to use in interrupt context.
+ *
+ * The host driver should have done a successful complement check (second
+ * quadlet is complement of first) beforehand.
+ */
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
{
if (host->in_bus_reset) {
@@ -416,6 +432,15 @@ void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid)
}
}
+/**
+ * hpsb_selfid_complete - notify completion of SelfID stage to the core
+ *
+ * For host driver module usage. Safe to use in interrupt context, although
+ * quite complex; so you may want to run it in the bottom rather than top half.
+ *
+ * Notify completion of SelfID stage to the core and report new physical ID
+ * and whether host is root now.
+ */
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
{
if (!host->in_bus_reset)
@@ -462,30 +487,41 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
highlevel_host_reset(host);
}
+static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED;
+/**
+ * hpsb_packet_sent - notify core of sending a packet
+ *
+ * For host driver module usage. Safe to call from within a transmit packet
+ * routine.
+ *
+ * Notify core of sending a packet. Ackcode is the ack code returned for async
+ * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
+ * for other cases (internal errors that don't justify a panic).
+ */
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode)
{
unsigned long flags;
- spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+ spin_lock_irqsave(&pending_packets_lock, flags);
packet->ack_code = ackcode;
if (packet->no_waiter || packet->state == hpsb_complete) {
/* if packet->no_waiter, must not have a tlabel allocated */
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
hpsb_free_packet(packet);
return;
}
atomic_dec(&packet->refcnt); /* drop HC's reference */
- /* here the packet must be on the host->pending_packet_queue */
+ /* here the packet must be on the host->pending_packets queue */
if (ackcode != ACK_PENDING || !packet->expect_response) {
packet->state = hpsb_complete;
- __skb_unlink(packet->skb, &host->pending_packet_queue);
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ list_del_init(&packet->queue);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
queue_packet_complete(packet);
return;
}
@@ -493,7 +529,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
packet->state = hpsb_pending;
packet->sendtime = jiffies;
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
mod_timer(&host->timeout, jiffies + host->timeout_interval);
}
@@ -504,9 +540,10 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
* @rootid: root whose force_root bit should get set (-1 = don't set force_root)
* @gapcnt: gap count value to set (-1 = don't set gap count)
*
- * This function sends a PHY config packet on the bus through the specified host.
+ * This function sends a PHY config packet on the bus through the specified
+ * host.
*
- * Return value: 0 for success or error number otherwise.
+ * Return value: 0 for success or negative error number otherwise.
*/
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
{
@@ -567,12 +604,16 @@ int hpsb_send_packet(struct hpsb_packet *packet)
WARN_ON(packet->no_waiter && packet->expect_response);
if (!packet->no_waiter || packet->expect_response) {
+ unsigned long flags;
+
atomic_inc(&packet->refcnt);
/* Set the initial "sendtime" to 10 seconds from now, to
prevent premature expiry. If a packet takes more than
10 seconds to hit the wire, we have bigger problems :) */
packet->sendtime = jiffies + 10 * HZ;
- skb_queue_tail(&host->pending_packet_queue, packet->skb);
+ spin_lock_irqsave(&pending_packets_lock, flags);
+ list_add_tail(&packet->queue, &host->pending_packets);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
}
if (packet->node_id == host->node_id) {
@@ -621,6 +662,12 @@ static void complete_packet(void *data)
complete((struct completion *) data);
}
+/**
+ * hpsb_send_packet_and_wait - enqueue packet, block until transaction completes
+ * @packet: packet to send
+ *
+ * Return value: 0 on success, negative errno on failure.
+ */
int hpsb_send_packet_and_wait(struct hpsb_packet *packet)
{
struct completion done;
@@ -642,86 +689,97 @@ static void send_packet_nocare(struct hpsb_packet *packet)
}
}
+static size_t packet_size_to_data_size(size_t packet_size, size_t header_size,
+ size_t buffer_size, int tcode)
+{
+ size_t ret = packet_size <= header_size ? 0 : packet_size - header_size;
+
+ if (unlikely(ret > buffer_size))
+ ret = buffer_size;
+
+ if (unlikely(ret + header_size != packet_size))
+ HPSB_ERR("unexpected packet size %zd (tcode %d), bug?",
+ packet_size, tcode);
+ return ret;
+}
static void handle_packet_response(struct hpsb_host *host, int tcode,
quadlet_t *data, size_t size)
{
- struct hpsb_packet *packet = NULL;
- struct sk_buff *skb;
- int tcode_match = 0;
- int tlabel;
+ struct hpsb_packet *packet;
+ int tlabel = (data[0] >> 10) & 0x3f;
+ size_t header_size;
unsigned long flags;
- tlabel = (data[0] >> 10) & 0x3f;
-
- spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
+ spin_lock_irqsave(&pending_packets_lock, flags);
- skb_queue_walk(&host->pending_packet_queue, skb) {
- packet = (struct hpsb_packet *)skb->data;
- if ((packet->tlabel == tlabel)
- && (packet->node_id == (data[1] >> 16))){
- break;
- }
-
- packet = NULL;
- }
+ list_for_each_entry(packet, &host->pending_packets, queue)
+ if (packet->tlabel == tlabel &&
+ packet->node_id == (data[1] >> 16))
+ goto found;
- if (packet == NULL) {
- HPSB_DEBUG("unsolicited response packet received - no tlabel match");
- dump_packet("contents", data, 16, -1);
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
- return;
- }
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ HPSB_DEBUG("unsolicited response packet received - %s",
+ "no tlabel match");
+ dump_packet("contents", data, 16, -1);
+ return;
+found:
switch (packet->tcode) {
case TCODE_WRITEQ:
case TCODE_WRITEB:
- if (tcode != TCODE_WRITE_RESPONSE)
+ if (unlikely(tcode != TCODE_WRITE_RESPONSE))
break;
- tcode_match = 1;
- memcpy(packet->header, data, 12);
- break;
+ header_size = 12;
+ size = 0;
+ goto dequeue;
+
case TCODE_READQ:
- if (tcode != TCODE_READQ_RESPONSE)
+ if (unlikely(tcode != TCODE_READQ_RESPONSE))
break;
- tcode_match = 1;
- memcpy(packet->header, data, 16);
- break;
+ header_size = 16;
+ size = 0;
+ goto dequeue;
+
case TCODE_READB:
- if (tcode != TCODE_READB_RESPONSE)
+ if (unlikely(tcode != TCODE_READB_RESPONSE))
break;
- tcode_match = 1;
- BUG_ON(packet->skb->len - sizeof(*packet) < size - 16);
- memcpy(packet->header, data, 16);
- memcpy(packet->data, data + 4, size - 16);
- break;
+ header_size = 16;
+ size = packet_size_to_data_size(size, header_size,
+ packet->allocated_data_size,
+ tcode);
+ goto dequeue;
+
case TCODE_LOCK_REQUEST:
- if (tcode != TCODE_LOCK_RESPONSE)
+ if (unlikely(tcode != TCODE_LOCK_RESPONSE))
break;
- tcode_match = 1;
- size = min((size - 16), (size_t)8);
- BUG_ON(packet->skb->len - sizeof(*packet) < size);
- memcpy(packet->header, data, 16);
- memcpy(packet->data, data + 4, size);
- break;
+ header_size = 16;
+ size = packet_size_to_data_size(min(size, (size_t)(16 + 8)),
+ header_size,
+ packet->allocated_data_size,
+ tcode);
+ goto dequeue;
}
- if (!tcode_match) {
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
- HPSB_INFO("unsolicited response packet received - tcode mismatch");
- dump_packet("contents", data, 16, -1);
- return;
- }
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ HPSB_DEBUG("unsolicited response packet received - %s",
+ "tcode mismatch");
+ dump_packet("contents", data, 16, -1);
+ return;
- __skb_unlink(skb, &host->pending_packet_queue);
+dequeue:
+ list_del_init(&packet->queue);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
if (packet->state == hpsb_queued) {
packet->sendtime = jiffies;
packet->ack_code = ACK_PENDING;
}
-
packet->state = hpsb_complete;
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+
+ memcpy(packet->header, data, header_size);
+ if (size)
+ memcpy(packet->data, data + 4, size);
queue_packet_complete(packet);
}
@@ -735,6 +793,7 @@ static struct hpsb_packet *create_reply_packet(struct hpsb_host *host,
p = hpsb_alloc_packet(dsize);
if (unlikely(p == NULL)) {
/* FIXME - send data_error response */
+ HPSB_ERR("out of memory, cannot send response packet");
return NULL;
}
@@ -784,7 +843,6 @@ static void fill_async_readblock_resp(struct hpsb_packet *packet, int rcode,
static void fill_async_write_resp(struct hpsb_packet *packet, int rcode)
{
PREP_ASYNC_HEAD_RCODE(TCODE_WRITE_RESPONSE);
- packet->header[2] = 0;
packet->header_size = 12;
packet->data_size = 0;
}
@@ -801,12 +859,9 @@ static void fill_async_lock_resp(struct hpsb_packet *packet, int rcode, int extc
packet->data_size = length;
}
-#define PREP_REPLY_PACKET(length) \
- packet = create_reply_packet(host, data, length); \
- if (packet == NULL) break
-
static void handle_incoming_packet(struct hpsb_host *host, int tcode,
- quadlet_t *data, size_t size, int write_acked)
+ quadlet_t *data, size_t size,
+ int write_acked)
{
struct hpsb_packet *packet;
int length, rcode, extcode;
@@ -816,74 +871,72 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
u16 flags = (u16) data[0];
u64 addr;
- /* big FIXME - no error checking is done for an out of bounds length */
+ /* FIXME?
+ * Out-of-bounds lengths are left for highlevel_read|write to cap. */
switch (tcode) {
case TCODE_WRITEQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data+3,
+ rcode = highlevel_write(host, source, dest, data + 3,
addr, 4, flags);
-
- if (!write_acked
- && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
- && (rcode >= 0)) {
- /* not a broadcast write, reply */
- PREP_REPLY_PACKET(0);
- fill_async_write_resp(packet, rcode);
- send_packet_nocare(packet);
- }
- break;
+ goto handle_write_request;
case TCODE_WRITEB:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- rcode = highlevel_write(host, source, dest, data+4,
- addr, data[3]>>16, flags);
-
- if (!write_acked
- && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
- && (rcode >= 0)) {
- /* not a broadcast write, reply */
- PREP_REPLY_PACKET(0);
+ rcode = highlevel_write(host, source, dest, data + 4,
+ addr, data[3] >> 16, flags);
+handle_write_request:
+ if (rcode < 0 || write_acked ||
+ NODEID_TO_NODE(data[0] >> 16) == NODE_MASK)
+ return;
+ /* not a broadcast write, reply */
+ packet = create_reply_packet(host, data, 0);
+ if (packet) {
fill_async_write_resp(packet, rcode);
send_packet_nocare(packet);
}
- break;
+ return;
case TCODE_READQ:
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, &buffer, addr, 4, flags);
+ if (rcode < 0)
+ return;
- if (rcode >= 0) {
- PREP_REPLY_PACKET(0);
+ packet = create_reply_packet(host, data, 0);
+ if (packet) {
fill_async_readquad_resp(packet, rcode, buffer);
send_packet_nocare(packet);
}
- break;
+ return;
case TCODE_READB:
length = data[3] >> 16;
- PREP_REPLY_PACKET(length);
+ packet = create_reply_packet(host, data, length);
+ if (!packet)
+ return;
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
rcode = highlevel_read(host, source, packet->data, addr,
length, flags);
-
- if (rcode >= 0) {
- fill_async_readblock_resp(packet, rcode, length);
- send_packet_nocare(packet);
- } else {
+ if (rcode < 0) {
hpsb_free_packet(packet);
+ return;
}
- break;
+ fill_async_readblock_resp(packet, rcode, length);
+ send_packet_nocare(packet);
+ return;
case TCODE_LOCK_REQUEST:
length = data[3] >> 16;
extcode = data[3] & 0xffff;
addr = (((u64)(data[1] & 0xffff)) << 32) | data[2];
- PREP_REPLY_PACKET(8);
+ packet = create_reply_packet(host, data, 8);
+ if (!packet)
+ return;
- if ((extcode == 0) || (extcode >= 7)) {
+ if (extcode == 0 || extcode >= 7) {
/* let switch default handle error */
length = 0;
}
@@ -891,12 +944,12 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
switch (length) {
case 4:
rcode = highlevel_lock(host, source, packet->data, addr,
- data[4], 0, extcode,flags);
+ data[4], 0, extcode, flags);
fill_async_lock_resp(packet, rcode, extcode, 4);
break;
case 8:
- if ((extcode != EXTCODE_FETCH_ADD)
- && (extcode != EXTCODE_LITTLE_ADD)) {
+ if (extcode != EXTCODE_FETCH_ADD &&
+ extcode != EXTCODE_LITTLE_ADD) {
rcode = highlevel_lock(host, source,
packet->data, addr,
data[5], data[4],
@@ -920,29 +973,38 @@ static void handle_incoming_packet(struct hpsb_host *host, int tcode,
break;
default:
rcode = RCODE_TYPE_ERROR;
- fill_async_lock_resp(packet, rcode,
- extcode, 0);
+ fill_async_lock_resp(packet, rcode, extcode, 0);
}
- if (rcode >= 0) {
- send_packet_nocare(packet);
- } else {
+ if (rcode < 0)
hpsb_free_packet(packet);
- }
- break;
+ else
+ send_packet_nocare(packet);
+ return;
}
-
}
-#undef PREP_REPLY_PACKET
-
+/**
+ * hpsb_packet_received - hand over received packet to the core
+ *
+ * For host driver module usage.
+ *
+ * The contents of data are expected to be the full packet but with the CRCs
+ * left out (data block follows header immediately), with the header (i.e. the
+ * first four quadlets) in machine byte order and the data block in big endian.
+ * *@data can be safely overwritten after this call.
+ *
+ * If the packet is a write request, @write_acked is to be set to true if it was
+ * ack_complete'd already, false otherwise. This argument is ignored for any
+ * other packet type.
+ */
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
int write_acked)
{
int tcode;
- if (host->in_bus_reset) {
- HPSB_INFO("received packet during reset; ignoring");
+ if (unlikely(host->in_bus_reset)) {
+ HPSB_DEBUG("received packet during reset; ignoring");
return;
}
@@ -976,23 +1038,27 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
break;
default:
- HPSB_NOTICE("received packet with bogus transaction code %d",
- tcode);
+ HPSB_DEBUG("received packet with bogus transaction code %d",
+ tcode);
break;
}
}
-
static void abort_requests(struct hpsb_host *host)
{
- struct hpsb_packet *packet;
- struct sk_buff *skb;
+ struct hpsb_packet *packet, *p;
+ struct list_head tmp;
+ unsigned long flags;
host->driver->devctl(host, CANCEL_REQUESTS, 0);
- while ((skb = skb_dequeue(&host->pending_packet_queue)) != NULL) {
- packet = (struct hpsb_packet *)skb->data;
+ INIT_LIST_HEAD(&tmp);
+ spin_lock_irqsave(&pending_packets_lock, flags);
+ list_splice_init(&host->pending_packets, &tmp);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
+ list_for_each_entry_safe(packet, p, &tmp, queue) {
+ list_del_init(&packet->queue);
packet->state = hpsb_complete;
packet->ack_code = ACKX_ABORTED;
queue_packet_complete(packet);
@@ -1002,87 +1068,90 @@ static void abort_requests(struct hpsb_host *host)
void abort_timedouts(unsigned long __opaque)
{
struct hpsb_host *host = (struct hpsb_host *)__opaque;
- unsigned long flags;
- struct hpsb_packet *packet;
- struct sk_buff *skb;
- unsigned long expire;
+ struct hpsb_packet *packet, *p;
+ struct list_head tmp;
+ unsigned long flags, expire, j;
spin_lock_irqsave(&host->csr.lock, flags);
expire = host->csr.expire;
spin_unlock_irqrestore(&host->csr.lock, flags);
- /* Hold the lock around this, since we aren't dequeuing all
- * packets, just ones we need. */
- spin_lock_irqsave(&host->pending_packet_queue.lock, flags);
-
- while (!skb_queue_empty(&host->pending_packet_queue)) {
- skb = skb_peek(&host->pending_packet_queue);
-
- packet = (struct hpsb_packet *)skb->data;
+ j = jiffies;
+ INIT_LIST_HEAD(&tmp);
+ spin_lock_irqsave(&pending_packets_lock, flags);
- if (time_before(packet->sendtime + expire, jiffies)) {
- __skb_unlink(skb, &host->pending_packet_queue);
- packet->state = hpsb_complete;
- packet->ack_code = ACKX_TIMEOUT;
- queue_packet_complete(packet);
- } else {
+ list_for_each_entry_safe(packet, p, &host->pending_packets, queue) {
+ if (time_before(packet->sendtime + expire, j))
+ list_move_tail(&packet->queue, &tmp);
+ else
/* Since packets are added to the tail, the oldest
* ones are first, always. When we get to one that
* isn't timed out, the rest aren't either. */
break;
- }
}
+ if (!list_empty(&host->pending_packets))
+ mod_timer(&host->timeout, j + host->timeout_interval);
- if (!skb_queue_empty(&host->pending_packet_queue))
- mod_timer(&host->timeout, jiffies + host->timeout_interval);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
- spin_unlock_irqrestore(&host->pending_packet_queue.lock, flags);
+ list_for_each_entry_safe(packet, p, &tmp, queue) {
+ list_del_init(&packet->queue);
+ packet->state = hpsb_complete;
+ packet->ack_code = ACKX_TIMEOUT;
+ queue_packet_complete(packet);
+ }
}
-
-/* Kernel thread and vars, which handles packets that are completed. Only
- * packets that have a "complete" function are sent here. This way, the
- * completion is run out of kernel context, and doesn't block the rest of
- * the stack. */
static struct task_struct *khpsbpkt_thread;
-static struct sk_buff_head hpsbpkt_queue;
+static LIST_HEAD(hpsbpkt_queue);
static void queue_packet_complete(struct hpsb_packet *packet)
{
+ unsigned long flags;
+
if (packet->no_waiter) {
hpsb_free_packet(packet);
return;
}
if (packet->complete_routine != NULL) {
- skb_queue_tail(&hpsbpkt_queue, packet->skb);
+ spin_lock_irqsave(&pending_packets_lock, flags);
+ list_add_tail(&packet->queue, &hpsbpkt_queue);
+ spin_unlock_irqrestore(&pending_packets_lock, flags);
wake_up_process(khpsbpkt_thread);
}
return;
}
+/*
+ * Kernel thread which handles packets that are completed. This way the
+ * packet's "complete" function is asynchronously run in process context.
+ * Only packets which have a "complete" function may be sent here.
+ */
static int hpsbpkt_thread(void *__hi)
{
- struct sk_buff *skb;
- struct hpsb_packet *packet;
- void (*complete_routine)(void*);
- void *complete_data;
+ struct hpsb_packet *packet, *p;
+ struct list_head tmp;
+ int may_schedule;
current->flags |= PF_NOFREEZE;
while (!kthread_should_stop()) {
- while ((skb = skb_dequeue(&hpsbpkt_queue)) != NULL) {
- packet = (struct hpsb_packet *)skb->data;
-
- complete_routine = packet->complete_routine;
- complete_data = packet->complete_data;
- packet->complete_routine = packet->complete_data = NULL;
+ INIT_LIST_HEAD(&tmp);
+ spin_lock_irq(&pending_packets_lock);
+ list_splice_init(&hpsbpkt_queue, &tmp);
+ spin_unlock_irq(&pending_packets_lock);
- complete_routine(complete_data);
+ list_for_each_entry_safe(packet, p, &tmp, queue) {
+ list_del_init(&packet->queue);
+ packet->complete_routine(packet->complete_data);
}
set_current_state(TASK_INTERRUPTIBLE);
- if (!skb_peek(&hpsbpkt_queue))
+ spin_lock_irq(&pending_packets_lock);
+ may_schedule = list_empty(&hpsbpkt_queue);
+ spin_unlock_irq(&pending_packets_lock);
+ if (may_schedule)
schedule();
__set_current_state(TASK_RUNNING);
}
@@ -1093,8 +1162,6 @@ static int __init ieee1394_init(void)
{
int i, ret;
- skb_queue_head_init(&hpsbpkt_queue);
-
/* non-fatal error */
if (hpsb_init_config_roms()) {
HPSB_ERR("Failed to initialize some config rom entries.\n");
@@ -1268,7 +1335,6 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo);
EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
-EXPORT_SYMBOL(highlevel_host_reset);
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
@@ -1311,11 +1377,10 @@ EXPORT_SYMBOL(hpsb_iso_wake);
EXPORT_SYMBOL(hpsb_iso_recv_flush);
/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
-EXPORT_SYMBOL(csr1212_release_keyval);
-EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_get_keyval);
+EXPORT_SYMBOL(csr1212_new_directory);
EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(_csr1212_read_keyval);
-EXPORT_SYMBOL(_csr1212_destroy_keyval);
+EXPORT_SYMBOL(csr1212_read);
+EXPORT_SYMBOL(csr1212_release_keyval);
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index bd29d8ef5bb..ad526523d0e 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -4,7 +4,6 @@
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/list.h>
-#include <linux/skbuff.h>
#include <linux/types.h>
#include <asm/atomic.h>
@@ -13,7 +12,7 @@
struct hpsb_packet {
/* This struct is basically read-only for hosts with the exception of
- * the data buffer contents and xnext - see below. */
+ * the data buffer contents and driver_list. */
/* This can be used for host driver internal linking.
*
@@ -49,134 +48,65 @@ struct hpsb_packet {
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
unsigned speed_code:2;
- /*
- * *header and *data are guaranteed to be 32-bit DMAable and may be
- * overwritten to allow in-place byte swapping. Neither of these is
- * CRCed (the sizes also don't include CRC), but contain space for at
- * least one additional quadlet to allow in-place CRCing. The memory is
- * also guaranteed to be DMA mappable.
- */
- quadlet_t *header;
- quadlet_t *data;
- size_t header_size;
- size_t data_size;
-
struct hpsb_host *host;
unsigned int generation;
atomic_t refcnt;
+ struct list_head queue;
/* Function (and possible data to pass to it) to call when this
* packet is completed. */
void (*complete_routine)(void *);
void *complete_data;
- /* XXX This is just a hack at the moment */
- struct sk_buff *skb;
-
/* Store jiffies for implementing bus timeouts. */
unsigned long sendtime;
- quadlet_t embedded_header[5];
+ /* Sizes are in bytes. *data can be DMA-mapped. */
+ size_t allocated_data_size; /* as allocated */
+ size_t data_size; /* as filled in */
+ size_t header_size; /* as filled in, not counting the CRC */
+ quadlet_t *data;
+ quadlet_t header[5];
+ quadlet_t embedded_data[0]; /* keep as last member */
};
-/* Set a task for when a packet completes */
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
void (*routine)(void *), void *data);
-
static inline struct hpsb_packet *driver_packet(struct list_head *l)
{
return list_entry(l, struct hpsb_packet, driver_list);
}
-
void abort_timedouts(unsigned long __opaque);
-
struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
void hpsb_free_packet(struct hpsb_packet *packet);
-/*
- * Generation counter for the complete 1394 subsystem. Generation gets
- * incremented on every change in the subsystem (e.g. bus reset).
+/**
+ * get_hpsb_generation - generation counter for the complete 1394 subsystem
*
- * Use the functions, not the variable.
+ * Generation gets incremented on every change in the subsystem (notably on bus
+ * resets). Use the functions, not the variable.
*/
static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
{
return atomic_read(&host->generation);
}
-/*
- * Send a PHY configuration packet, return 0 on success, negative
- * errno on failure.
- */
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
-
-/*
- * Queue packet for transmitting, return 0 on success, negative errno
- * on failure.
- */
int hpsb_send_packet(struct hpsb_packet *packet);
-
-/*
- * Queue packet for transmitting, and block until the transaction
- * completes. Return 0 on success, negative errno on failure.
- */
int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
-
-/* Initiate bus reset on the given host. Returns 1 if bus reset already in
- * progress, 0 otherwise. */
int hpsb_reset_bus(struct hpsb_host *host, int type);
-
int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
u64 *local_time);
-/*
- * The following functions are exported for host driver module usage. All of
- * them are safe to use in interrupt contexts, although some are quite
- * complicated so you may want to run them in bottom halves instead of calling
- * them directly.
- */
-
-/* Notify a bus reset to the core. Returns 1 if bus reset already in progress,
- * 0 otherwise. */
int hpsb_bus_reset(struct hpsb_host *host);
-
-/*
- * Hand over received selfid packet to the core. Complement check (second
- * quadlet is complement of first) is expected to be done and successful.
- */
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
-
-/*
- * Notify completion of SelfID stage to the core and report new physical ID
- * and whether host is root now.
- */
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-
-/*
- * Notify core of sending a packet. Ackcode is the ack code returned for async
- * transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
- * for other cases (internal errors that don't justify a panic). Safe to call
- * from within a transmit packet routine.
- */
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
int ackcode);
-
-/*
- * Hand over received packet to the core. The contents of data are expected to
- * be the full packet but with the CRCs left out (data block follows header
- * immediately), with the header (i.e. the first four quadlets) in machine byte
- * order and the data block in big endian. *data can be safely overwritten
- * after this call.
- *
- * If the packet is a write request, write_acked is to be set to true if it was
- * ack_complete'd already, false otherwise. This arg is ignored for any other
- * packet type.
- */
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
int write_acked);
-
/*
* CHARACTER DEVICE DISPATCHING
*
@@ -217,7 +147,9 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
-/* return the index (within a minor number block) of a file */
+/**
+ * ieee1394_file_to_instance - get the index within a minor number block
+ */
static inline unsigned char ieee1394_file_to_instance(struct file *file)
{
return file->f_path.dentry->d_inode->i_cindex;
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index 0833fc9f50c..40078ce930c 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -10,11 +10,16 @@
*/
#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/hardirq.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
#include <linux/wait.h>
#include <asm/bug.h>
#include <asm/errno.h>
+#include <asm/system.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
@@ -32,7 +37,7 @@
#ifndef HPSB_DEBUG_TLABELS
static
#endif
-spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(hpsb_tlabel_lock);
static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
@@ -212,6 +217,15 @@ void hpsb_free_tlabel(struct hpsb_packet *packet)
wake_up_interruptible(&tlabel_wq);
}
+/**
+ * hpsb_packet_success - Make sense of the ack and reply codes
+ *
+ * Make sense of the ack and reply codes and return more convenient error codes:
+ * 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
+ * probably resolved by retry. -%EREMOTEIO = node suffers from an internal
+ * error. -%EACCES = this transaction is not allowed on requested address.
+ * -%EINVAL = invalid address at node.
+ */
int hpsb_packet_success(struct hpsb_packet *packet)
{
switch (packet->ack_code) {
@@ -364,6 +378,13 @@ struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
}
packet->host = host;
+ /* Because it is too difficult to determine all PHY speeds and link
+ * speeds here, we use S100... */
+ packet->speed_code = IEEE1394_SPEED_100;
+
+ /* ...and prevent hpsb_send_packet() from overriding it. */
+ packet->node_id = LOCAL_BUS | ALL_NODES;
+
if (hpsb_get_tlabel(packet)) {
hpsb_free_packet(packet);
return NULL;
@@ -493,6 +514,16 @@ struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
* avoid in kernel buffers for user space callers
*/
+/**
+ * hpsb_read - generic read function
+ *
+ * Recognizes the local node ID and act accordingly. Automatically uses a
+ * quadlet read request if @length == 4 and and a block read request otherwise.
+ * It does not yet support lengths that are not a multiple of 4.
+ *
+ * You must explicitly specifiy the @generation for which the node ID is valid,
+ * to avoid sending packets to the wrong nodes when we race with a bus reset.
+ */
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t * buffer, size_t length)
{
@@ -532,6 +563,16 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
return retval;
}
+/**
+ * hpsb_write - generic write function
+ *
+ * Recognizes the local node ID and act accordingly. Automatically uses a
+ * quadlet write request if @length == 4 and and a block write request
+ * otherwise. It does not yet support lengths that are not a multiple of 4.
+ *
+ * You must explicitly specifiy the @generation for which the node ID is valid,
+ * to avoid sending packets to the wrong nodes when we race with a bus reset.
+ */
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t * buffer, size_t length)
{
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
index c1369c41469..86b8ee692ea 100644
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -27,27 +27,7 @@ struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
int length, int channel, int tag,
int sync);
-
-/*
- * hpsb_packet_success - Make sense of the ack and reply codes and
- * return more convenient error codes:
- * 0 success
- * -EBUSY node is busy, try again
- * -EAGAIN error which can probably resolved by retry
- * -EREMOTEIO node suffers from an internal error
- * -EACCES this transaction is not allowed on requested address
- * -EINVAL invalid address at node
- */
int hpsb_packet_success(struct hpsb_packet *packet);
-
-/*
- * The generic read and write functions. All recognize the local node ID
- * and act accordingly. Read and write automatically use quadlet commands if
- * length == 4 and and block commands otherwise (however, they do not yet
- * support lengths that are not a multiple of 4). You must explicitly specifiy
- * the generation for which the node ID is valid, to avoid sending packets to
- * the wrong nodes when we race with a bus reset.
- */
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length);
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
index c6227e51136..07ca35c98f9 100644
--- a/drivers/ieee1394/iso.c
+++ b/drivers/ieee1394/iso.c
@@ -10,11 +10,15 @@
*/
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include "hosts.h"
#include "iso.h"
+/**
+ * hpsb_iso_stop - stop DMA
+ */
void hpsb_iso_stop(struct hpsb_iso *iso)
{
if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
@@ -25,6 +29,9 @@ void hpsb_iso_stop(struct hpsb_iso *iso)
iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
}
+/**
+ * hpsb_iso_shutdown - deallocate buffer and DMA context
+ */
void hpsb_iso_shutdown(struct hpsb_iso *iso)
{
if (iso->flags & HPSB_ISO_DRIVER_INIT) {
@@ -130,6 +137,9 @@ static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
return NULL;
}
+/**
+ * hpsb_iso_n_ready - returns number of packets ready to send or receive
+ */
int hpsb_iso_n_ready(struct hpsb_iso *iso)
{
unsigned long flags;
@@ -142,6 +152,9 @@ int hpsb_iso_n_ready(struct hpsb_iso *iso)
return val;
}
+/**
+ * hpsb_iso_xmit_init - allocate the buffer and DMA context
+ */
struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
unsigned int data_buf_size,
unsigned int buf_packets,
@@ -172,6 +185,11 @@ struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
return NULL;
}
+/**
+ * hpsb_iso_recv_init - allocate the buffer and DMA context
+ *
+ * Note, if channel = -1, multi-channel receive is enabled.
+ */
struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
unsigned int data_buf_size,
unsigned int buf_packets,
@@ -199,6 +217,11 @@ struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
return NULL;
}
+/**
+ * hpsb_iso_recv_listen_channel
+ *
+ * multi-channel only
+ */
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
{
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
@@ -206,6 +229,11 @@ int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
}
+/**
+ * hpsb_iso_recv_unlisten_channel
+ *
+ * multi-channel only
+ */
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
{
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
@@ -213,6 +241,11 @@ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
}
+/**
+ * hpsb_iso_recv_set_channel_mask
+ *
+ * multi-channel only
+ */
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
{
if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
@@ -221,6 +254,12 @@ int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
(unsigned long)&mask);
}
+/**
+ * hpsb_iso_recv_flush - check for arrival of new packets
+ *
+ * check for arrival of new packets immediately (even if irq_interval
+ * has not yet been reached)
+ */
int hpsb_iso_recv_flush(struct hpsb_iso *iso)
{
if (iso->type != HPSB_ISO_RECV)
@@ -238,6 +277,9 @@ static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
return retval;
}
+/**
+ * hpsb_iso_xmit_start - start DMA
+ */
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
{
if (iso->type != HPSB_ISO_XMIT)
@@ -270,6 +312,9 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
return 0;
}
+/**
+ * hpsb_iso_recv_start - start DMA
+ */
int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
{
int retval = 0;
@@ -306,8 +351,7 @@ int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
}
/* check to make sure the user has not supplied bogus values of offset/len
- that would cause the kernel to access memory outside the buffer */
-
+ * that would cause the kernel to access memory outside the buffer */
static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
unsigned int offset, unsigned short len,
unsigned int *out_offset,
@@ -331,6 +375,12 @@ static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
return 0;
}
+/**
+ * hpsb_iso_xmit_queue_packet - queue a packet for transmission.
+ *
+ * @offset is relative to the beginning of the DMA buffer, where the packet's
+ * data payload should already have been placed.
+ */
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
u8 tag, u8 sy)
{
@@ -380,6 +430,9 @@ int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
return rv;
}
+/**
+ * hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
+ */
int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
{
if (iso->type != HPSB_ISO_XMIT)
@@ -390,6 +443,15 @@ int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
iso->buf_packets);
}
+/**
+ * hpsb_iso_packet_sent
+ *
+ * Available to low-level drivers.
+ *
+ * Call after a packet has been transmitted to the bus (interrupt context is
+ * OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
+ * non-zero if some sort of error occurred when sending the packet.
+ */
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
{
unsigned long flags;
@@ -413,6 +475,13 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
spin_unlock_irqrestore(&iso->lock, flags);
}
+/**
+ * hpsb_iso_packet_received
+ *
+ * Available to low-level drivers.
+ *
+ * Call after a packet has been received (interrupt context is OK).
+ */
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
u16 total_len, u16 cycle, u8 channel, u8 tag,
u8 sy)
@@ -442,6 +511,11 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
spin_unlock_irqrestore(&iso->lock, flags);
}
+/**
+ * hpsb_iso_recv_release_packets - release packets, reuse buffer
+ *
+ * @n_packets have been read out of the buffer, re-use the buffer space
+ */
int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
{
unsigned long flags;
@@ -477,6 +551,13 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
return rv;
}
+/**
+ * hpsb_iso_wake
+ *
+ * Available to low-level drivers.
+ *
+ * Call to wake waiting processes after buffer space has opened up.
+ */
void hpsb_iso_wake(struct hpsb_iso *iso)
{
wake_up_interruptible(&iso->waitq);
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
index 1210a97e868..b94e55e6eaa 100644
--- a/drivers/ieee1394/iso.h
+++ b/drivers/ieee1394/iso.h
@@ -150,8 +150,6 @@ struct hpsb_iso {
/* functions available to high-level drivers (e.g. raw1394) */
-/* allocate the buffer and DMA context */
-
struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
unsigned int data_buf_size,
unsigned int buf_packets,
@@ -159,8 +157,6 @@ struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
int speed,
int irq_interval,
void (*callback)(struct hpsb_iso*));
-
-/* note: if channel = -1, multi-channel receive is enabled */
struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
unsigned int data_buf_size,
unsigned int buf_packets,
@@ -168,56 +164,29 @@ struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
int dma_mode,
int irq_interval,
void (*callback)(struct hpsb_iso*));
-
-/* multi-channel only */
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
-
-/* start/stop DMA */
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
int prebuffer);
int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
int tag_mask, int sync);
void hpsb_iso_stop(struct hpsb_iso *iso);
-
-/* deallocate buffer and DMA context */
void hpsb_iso_shutdown(struct hpsb_iso *iso);
-
-/* queue a packet for transmission.
- * 'offset' is relative to the beginning of the DMA buffer, where the packet's
- * data payload should already have been placed. */
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
u8 tag, u8 sy);
-
-/* wait until all queued packets have been transmitted to the bus */
int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
-
-/* N packets have been read out of the buffer, re-use the buffer space */
-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
- unsigned int n_packets);
-
-/* check for arrival of new packets immediately (even if irq_interval
- * has not yet been reached) */
+int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
+ unsigned int n_packets);
int hpsb_iso_recv_flush(struct hpsb_iso *iso);
-
-/* returns # of packets ready to send or receive */
int hpsb_iso_n_ready(struct hpsb_iso *iso);
/* the following are callbacks available to low-level drivers */
-/* call after a packet has been transmitted to the bus (interrupt context is OK)
- * 'cycle' is the _exact_ cycle the packet was sent on
- * 'error' should be non-zero if some sort of error occurred when sending the
- * packet */
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
-
-/* call after a packet has been received (interrupt context OK) */
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
u16 total_len, u16 cycle, u8 channel, u8 tag,
u8 sy);
-
-/* call to wake waiting processes after buffer space has opened up. */
void hpsb_iso_wake(struct hpsb_iso *iso);
#endif /* IEEE1394_ISO_H */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index dbeba45a031..835937e3852 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -16,6 +16,7 @@
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/mutex.h>
#include <linux/freezer.h>
#include <asm/atomic.h>
@@ -115,7 +116,7 @@ static int nodemgr_bus_read(struct csr1212_csr *csr, u64 addr, u16 length,
static int nodemgr_get_max_rom(quadlet_t *bus_info_data, void *__ci)
{
- return (CSR1212_BE32_TO_CPU(bus_info_data[2]) >> 8) & 0x3;
+ return (be32_to_cpu(bus_info_data[2]) >> 8) & 0x3;
}
static struct csr1212_bus_ops nodemgr_csr_ops = {
@@ -580,7 +581,7 @@ static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
goto fail;
return;
fail:
- HPSB_ERR("Failed to add sysfs attribute for driver %s", driver->name);
+ HPSB_ERR("Failed to add sysfs attribute");
}
@@ -604,8 +605,7 @@ static void nodemgr_create_ne_dev_files(struct node_entry *ne)
goto fail;
return;
fail:
- HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
- (unsigned long long)ne->guid);
+ HPSB_ERR("Failed to add sysfs attribute");
}
@@ -619,7 +619,7 @@ static void nodemgr_create_host_dev_files(struct hpsb_host *host)
goto fail;
return;
fail:
- HPSB_ERR("Failed to add sysfs attribute for host %d", host->id);
+ HPSB_ERR("Failed to add sysfs attribute");
}
@@ -679,8 +679,7 @@ static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
}
return;
fail:
- HPSB_ERR("Failed to add sysfs attributes for unit %s",
- ud->device.bus_id);
+ HPSB_ERR("Failed to add sysfs attribute");
}
@@ -1144,13 +1143,13 @@ static void nodemgr_process_root_directory(struct host_info *hi, struct node_ent
last_key_id = kv->key.id;
}
- if (ne->vendor_name_kv &&
- device_create_file(&ne->device, &dev_attr_ne_vendor_name_kv))
- goto fail;
- return;
-fail:
- HPSB_ERR("Failed to add sysfs attribute for node %016Lx",
- (unsigned long long)ne->guid);
+ if (ne->vendor_name_kv) {
+ int error = device_create_file(&ne->device,
+ &dev_attr_ne_vendor_name_kv);
+
+ if (error && error != -EEXIST)
+ HPSB_ERR("Failed to add sysfs attribute");
+ }
}
#ifdef CONFIG_HOTPLUG
@@ -1703,7 +1702,7 @@ static int nodemgr_host_thread(void *__hi)
generation = get_hpsb_generation(host);
/* If we get a reset before we are done waiting, then
- * start the the waiting over again */
+ * start the waiting over again */
if (generation != g)
g = generation, i = 0;
}
@@ -1738,7 +1737,19 @@ exit:
return 0;
}
-int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
+/**
+ * nodemgr_for_each_host - call a function for each IEEE 1394 host
+ * @data: an address to supply to the callback
+ * @cb: function to call for each host
+ *
+ * Iterate the hosts, calling a given function with supplied data for each host.
+ * If the callback fails on a host, i.e. if it returns a non-zero value, the
+ * iteration is stopped.
+ *
+ * Return value: 0 on success, non-zero on failure (same as returned by last run
+ * of the callback).
+ */
+int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *))
{
struct class_device *cdev;
struct hpsb_host *host;
@@ -1748,7 +1759,7 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
list_for_each_entry(cdev, &hpsb_host_class.children, node) {
host = container_of(cdev, struct hpsb_host, class_dev);
- if ((error = cb(host, __data)))
+ if ((error = cb(host, data)))
break;
}
up(&hpsb_host_class.sem);
@@ -1756,7 +1767,7 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
return error;
}
-/* The following four convenience functions use a struct node_entry
+/* The following two convenience functions use a struct node_entry
* for addressing a node on the bus. They are intended for use by any
* process context, not just the nodemgr thread, so we need to be a
* little careful when reading out the node ID and generation. The
@@ -1771,12 +1782,20 @@ int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
* ID's.
*/
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt)
+/**
+ * hpsb_node_fill_packet - fill some destination information into a packet
+ * @ne: destination node
+ * @packet: packet to fill in
+ *
+ * This will fill in the given, pre-initialised hpsb_packet with the current
+ * information from the node entry (host, node ID, bus generation number).
+ */
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
{
- pkt->host = ne->host;
- pkt->generation = ne->generation;
+ packet->host = ne->host;
+ packet->generation = ne->generation;
barrier();
- pkt->node_id = ne->nodeid;
+ packet->node_id = ne->nodeid;
}
int hpsb_node_write(struct node_entry *ne, u64 addr,
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index 4147303ad44..e7ac683c72c 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -153,30 +153,10 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne)
{
return ne->generation == get_hpsb_generation(ne->host);
}
-
-/*
- * This will fill in the given, pre-initialised hpsb_packet with the current
- * information from the node entry (host, node ID, generation number). It will
- * return false if the node owning the GUID is not accessible (and not modify
- * the hpsb_packet) and return true otherwise.
- *
- * Note that packet sending may still fail in hpsb_send_packet if a bus reset
- * happens while you are trying to set up the packet (due to obsolete generation
- * number). It will at least reliably fail so that you don't accidentally and
- * unknowingly send your packet to the wrong node.
- */
-void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
-
-int hpsb_node_read(struct node_entry *ne, u64 addr,
- quadlet_t *buffer, size_t length);
+void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
int hpsb_node_write(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length);
-int hpsb_node_lock(struct node_entry *ne, u64 addr,
- int extcode, quadlet_t *data, quadlet_t arg);
-
-/* Iterate the hosts, calling a given function with supplied data for each
- * host. */
-int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *));
+int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
int init_ieee1394_nodemgr(void);
void cleanup_ieee1394_nodemgr(void);
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 06fac0d2126..5dadfd296f7 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -507,9 +507,8 @@ static void ohci_initialize(struct ti_ohci *ohci)
/* Set up self-id dma buffer */
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
- /* enable self-id and phys */
- reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID |
- OHCI1394_LinkControl_RcvPhyPkt);
+ /* enable self-id */
+ reg_write(ohci, OHCI1394_LinkControlSet, OHCI1394_LinkControl_RcvSelfID);
/* Set the Config ROM mapping register */
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->csr_config_rom_bus);
@@ -518,9 +517,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
ohci->max_packet_size =
1<<(((reg_read(ohci, OHCI1394_BusOptions)>>12)&0xf)+1);
- /* Don't accept phy packets into AR request context */
- reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
-
/* Clear the interrupt mask */
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
@@ -617,7 +613,7 @@ static void ohci_initialize(struct ti_ohci *ohci)
#endif
PRINT(KERN_DEBUG, "Serial EEPROM has suspicious values, "
- "attempting to setting max_packet_size to 512 bytes");
+ "attempting to set max_packet_size to 512 bytes");
reg_write(ohci, OHCI1394_BusOptions,
(reg_read(ohci, OHCI1394_BusOptions) & 0xf007) | 0x8002);
ohci->max_packet_size = 512;
@@ -2377,6 +2373,7 @@ static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
if (event & OHCI1394_postedWriteErr) {
PRINT(KERN_ERR, "physical posted write error");
/* no recovery strategy yet, had to involve protocol drivers */
+ event &= ~OHCI1394_postedWriteErr;
}
if (event & OHCI1394_cycleTooLong) {
if(printk_ratelimit())
@@ -3658,6 +3655,7 @@ static struct pci_driver ohci1394_pci_driver = {
/* essentially the only purpose of this code is to allow another
module to hook into ohci's interrupt handler */
+/* returns zero if successful, one if DMA context is locked up */
int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg)
{
int i=0;
diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h
index fa05f113f7f..f1ad539e7c1 100644
--- a/drivers/ieee1394/ohci1394.h
+++ b/drivers/ieee1394/ohci1394.h
@@ -461,9 +461,7 @@ int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
struct ohci1394_iso_tasklet *tasklet);
void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
struct ohci1394_iso_tasklet *tasklet);
-
-/* returns zero if successful, one if DMA context is locked up */
-int ohci1394_stop_context (struct ti_ohci *ohci, int reg, char *msg);
+int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
struct ti_ohci *ohci1394_get_struct(int card_num);
#endif
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index bb897a37d9f..d382500f421 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -35,7 +35,6 @@
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <linux/cdev.h>
@@ -938,7 +937,8 @@ static int handle_async_send(struct file_info *fi, struct pending_request *req)
int header_length = req->req.misc & 0xffff;
int expect_response = req->req.misc >> 16;
- if ((header_length > req->req.length) || (header_length < 12)) {
+ if (header_length > req->req.length || header_length < 12 ||
+ header_length > FIELD_SIZEOF(struct hpsb_packet, header)) {
req->req.error = RAW1394_ERROR_INVALID_ARG;
req->req.length = 0;
queue_complete_req(req);
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 4edfff46b1e..4cb6fa2bcfb 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -59,8 +59,10 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
@@ -469,19 +471,13 @@ static void sbp2util_write_doorbell(struct work_struct *work)
static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
{
struct sbp2_fwhost_info *hi = lu->hi;
- int i;
- unsigned long flags, orbs;
struct sbp2_command_info *cmd;
+ int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
- orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
-
- spin_lock_irqsave(&lu->cmd_orb_lock, flags);
for (i = 0; i < orbs; i++) {
- cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
- if (!cmd) {
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
return -ENOMEM;
- }
cmd->command_orb_dma = dma_map_single(hi->host->device.parent,
&cmd->command_orb,
sizeof(struct sbp2_command_orb),
@@ -489,11 +485,10 @@ static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
cmd->sge_dma = dma_map_single(hi->host->device.parent,
&cmd->scatter_gather_element,
sizeof(cmd->scatter_gather_element),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
INIT_LIST_HEAD(&cmd->list);
list_add_tail(&cmd->list, &lu->cmd_orb_completed);
}
- spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
return 0;
}
@@ -514,7 +509,7 @@ static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu)
DMA_TO_DEVICE);
dma_unmap_single(host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
kfree(cmd);
}
spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
@@ -757,6 +752,11 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
SBP2_ERR("failed to register lower 4GB address range");
goto failed_alloc;
}
+#else
+ if (dma_set_mask(hi->host->device.parent, DMA_32BIT_MASK)) {
+ SBP2_ERR("failed to set 4GB DMA mask");
+ goto failed_alloc;
+ }
#endif
}
@@ -865,11 +865,8 @@ static int sbp2_start_device(struct sbp2_lu *lu)
if (!lu->login_orb)
goto alloc_fail;
- if (sbp2util_create_command_orb_pool(lu)) {
- SBP2_ERR("sbp2util_create_command_orb_pool failed!");
- sbp2_remove_device(lu);
- return -ENOMEM;
- }
+ if (sbp2util_create_command_orb_pool(lu))
+ goto alloc_fail;
/* Wait a second before trying to log in. Previously logged in
* initiators need a chance to reconnect. */
@@ -1628,7 +1625,7 @@ static void sbp2_link_orb_command(struct sbp2_lu *lu,
DMA_TO_DEVICE);
dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
/* check to see if there are any previous orbs to use */
spin_lock_irqsave(&lu->cmd_orb_lock, flags);
@@ -1794,7 +1791,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
DMA_TO_DEVICE);
dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
/* Grab SCSI command pointers and check status. */
/*
* FIXME: If the src field in the status is 1, the ORB DMA must
@@ -1926,7 +1923,7 @@ static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
DMA_TO_DEVICE);
dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
sbp2util_mark_command_completed(lu, cmd);
if (cmd->Current_SCpnt) {
cmd->Current_SCpnt->result = status << 16;
@@ -2057,7 +2054,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
dma_sync_single_for_cpu(hi->host->device.parent,
cmd->sge_dma,
sizeof(cmd->scatter_gather_element),
- DMA_BIDIRECTIONAL);
+ DMA_TO_DEVICE);
sbp2util_mark_command_completed(lu, cmd);
if (cmd->Current_SCpnt) {
cmd->Current_SCpnt->result = DID_ABORT << 16;
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index 9ae842329bf..44402b9d82a 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -250,15 +250,15 @@ enum sbp2_dma_types {
/* Per SCSI command */
struct sbp2_command_info {
struct list_head list;
- struct sbp2_command_orb command_orb ____cacheline_aligned;
- dma_addr_t command_orb_dma ____cacheline_aligned;
+ struct sbp2_command_orb command_orb;
+ dma_addr_t command_orb_dma;
struct scsi_cmnd *Current_SCpnt;
void (*Current_done)(struct scsi_cmnd *);
/* Also need s/g structure for each sbp2 command */
struct sbp2_unrestricted_page_table
- scatter_gather_element[SG_ALL] ____cacheline_aligned;
- dma_addr_t sge_dma ____cacheline_aligned;
+ scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
+ dma_addr_t sge_dma;
void *sge_buffer;
dma_addr_t cmd_dma;
enum sbp2_dma_types dma_type;
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 95ca26d7527..87ebd0846c3 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -39,7 +39,6 @@
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/types.h>
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 842cd0b53e9..eff591deeb4 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -40,7 +40,6 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/random.h>
#include <linux/rbtree.h>
#include <linux/spinlock.h>
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 1d796e7c819..a06bcc65a87 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -43,6 +43,8 @@
#include "core_priv.h"
+#define PFX "fmr_pool: "
+
enum {
IB_FMR_MAX_REMAPS = 32,
@@ -150,7 +152,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
#ifdef DEBUG
if (fmr->ref_count !=0) {
- printk(KERN_WARNING "Unmapping FMR 0x%08x with ref count %d",
+ printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d",
fmr, fmr->ref_count);
}
#endif
@@ -168,7 +170,7 @@ static void ib_fmr_batch_release(struct ib_fmr_pool *pool)
ret = ib_unmap_fmr(&fmr_list);
if (ret)
- printk(KERN_WARNING "ib_unmap_fmr returned %d", ret);
+ printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret);
spin_lock_irq(&pool->pool_lock);
list_splice(&unmap_list, &pool->free_list);
@@ -226,20 +228,20 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
device = pd->device;
if (!device->alloc_fmr || !device->dealloc_fmr ||
!device->map_phys_fmr || !device->unmap_fmr) {
- printk(KERN_WARNING "Device %s does not support fast memory regions",
+ printk(KERN_INFO PFX "Device %s does not support FMRs\n",
device->name);
return ERR_PTR(-ENOSYS);
}
attr = kmalloc(sizeof *attr, GFP_KERNEL);
if (!attr) {
- printk(KERN_WARNING "couldn't allocate device attr struct");
+ printk(KERN_WARNING PFX "couldn't allocate device attr struct");
return ERR_PTR(-ENOMEM);
}
ret = ib_query_device(device, attr);
if (ret) {
- printk(KERN_WARNING "couldn't query device");
+ printk(KERN_WARNING PFX "couldn't query device: %d", ret);
kfree(attr);
return ERR_PTR(ret);
}
@@ -253,7 +255,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
pool = kmalloc(sizeof *pool, GFP_KERNEL);
if (!pool) {
- printk(KERN_WARNING "couldn't allocate pool struct");
+ printk(KERN_WARNING PFX "couldn't allocate pool struct");
return ERR_PTR(-ENOMEM);
}
@@ -270,7 +272,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
GFP_KERNEL);
if (!pool->cache_bucket) {
- printk(KERN_WARNING "Failed to allocate cache in pool");
+ printk(KERN_WARNING PFX "Failed to allocate cache in pool");
ret = -ENOMEM;
goto out_free_pool;
}
@@ -294,7 +296,7 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
"ib_fmr(%s)",
device->name);
if (IS_ERR(pool->thread)) {
- printk(KERN_WARNING "couldn't start cleanup thread");
+ printk(KERN_WARNING PFX "couldn't start cleanup thread");
ret = PTR_ERR(pool->thread);
goto out_free_pool;
}
@@ -311,8 +313,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
fmr = kmalloc(sizeof *fmr + params->max_pages_per_fmr * sizeof (u64),
GFP_KERNEL);
if (!fmr) {
- printk(KERN_WARNING "failed to allocate fmr struct "
- "for FMR %d", i);
+ printk(KERN_WARNING PFX "failed to allocate fmr "
+ "struct for FMR %d", i);
goto out_fail;
}
@@ -323,7 +325,8 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd,
fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
if (IS_ERR(fmr->fmr)) {
- printk(KERN_WARNING "fmr_create failed for FMR %d", i);
+ printk(KERN_WARNING PFX "fmr_create failed "
+ "for FMR %d", i);
kfree(fmr);
goto out_fail;
}
@@ -378,7 +381,7 @@ void ib_destroy_fmr_pool(struct ib_fmr_pool *pool)
}
if (i < pool->pool_size)
- printk(KERN_WARNING "pool still has %d regions registered",
+ printk(KERN_WARNING PFX "pool still has %d regions registered",
pool->pool_size - i);
kfree(pool->cache_bucket);
@@ -463,8 +466,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
list_add(&fmr->list, &pool->free_list);
spin_unlock_irqrestore(&pool->pool_lock, flags);
- printk(KERN_WARNING "fmr_map returns %d\n",
- result);
+ printk(KERN_WARNING PFX "fmr_map returns %d\n", result);
return ERR_PTR(result);
}
@@ -516,7 +518,7 @@ int ib_fmr_pool_unmap(struct ib_pool_fmr *fmr)
#ifdef DEBUG
if (fmr->ref_count < 0)
- printk(KERN_WARNING "FMR %p has ref count %d < 0",
+ printk(KERN_WARNING PFX "FMR %p has ref count %d < 0",
fmr, fmr->ref_count);
#endif
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 891d1fa7b2e..223b1aa7d92 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -39,7 +39,6 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/rbtree.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 6edfecf1be7..85ccf13b804 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -2771,7 +2771,7 @@ static int ib_mad_port_open(struct ib_device *device,
cq_size = (IB_MAD_QP_SEND_SIZE + IB_MAD_QP_RECV_SIZE) * 2;
port_priv->cq = ib_create_cq(port_priv->device,
ib_mad_thread_completion_handler,
- NULL, port_priv, cq_size);
+ NULL, port_priv, cq_size, 0);
if (IS_ERR(port_priv->cq)) {
printk(KERN_ERR PFX "Couldn't create ib_mad CQ\n");
ret = PTR_ERR(port_priv->cq);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index de89717f49f..9be5cc00a3a 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -39,7 +39,6 @@
#include <linux/completion.h>
#include <linux/err.h>
-#include <linux/pci.h>
#include <linux/workqueue.h>
#include <rdma/ib_mad.h>
#include <rdma/ib_smi.h>
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 4a579b3a1c9..1e13ab42b70 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -34,7 +34,6 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/bitops.h>
#include <linux/random.h>
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 9a7eaadb168..6469406ea9d 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -40,7 +40,6 @@
#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/kref.h>
#include <linux/idr.h>
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index 8199b83052a..d97ded25c4f 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -40,7 +40,6 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/cdev.h>
-#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/poll.h>
#include <linux/rwsem.h>
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 4fd75afa6a3..bab66769be1 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -802,6 +802,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
INIT_LIST_HEAD(&obj->async_list);
cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
+ cmd.comp_vector,
file->ucontext, &udata);
if (IS_ERR(cq)) {
ret = PTR_ERR(cq);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index f8bc822a3cc..d44e5479965 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -752,7 +752,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
spin_unlock(&map_lock);
uverbs_dev->ib_dev = device;
- uverbs_dev->num_comp_vectors = 1;
+ uverbs_dev->num_comp_vectors = device->num_comp_vectors;
uverbs_dev->dev = cdev_alloc();
if (!uverbs_dev->dev)
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index ccdf93d30b0..86ed8af9c7e 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -609,11 +609,11 @@ EXPORT_SYMBOL(ib_destroy_qp);
struct ib_cq *ib_create_cq(struct ib_device *device,
ib_comp_handler comp_handler,
void (*event_handler)(struct ib_event *, void *),
- void *cq_context, int cqe)
+ void *cq_context, int cqe, int comp_vector)
{
struct ib_cq *cq;
- cq = device->create_cq(device, cqe, NULL, NULL);
+ cq = device->create_cq(device, cqe, comp_vector, NULL, NULL);
if (!IS_ERR(cq)) {
cq->device = device;
diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/infiniband/hw/amso1100/c2.h
index 04a9db5de88..fa58200217a 100644
--- a/drivers/infiniband/hw/amso1100/c2.h
+++ b/drivers/infiniband/hw/amso1100/c2.h
@@ -519,7 +519,7 @@ extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
-extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
+extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
/* CM */
extern int c2_llp_connect(struct iw_cm_id *cm_id,
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
index 5175c99ee58..d2b3366786d 100644
--- a/drivers/infiniband/hw/amso1100/c2_cq.c
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -217,17 +217,19 @@ int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
return npolled;
}
-int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
{
struct c2_mq_shared __iomem *shared;
struct c2_cq *cq;
+ unsigned long flags;
+ int ret = 0;
cq = to_c2cq(ibcq);
shared = cq->mq.peer;
- if (notify == IB_CQ_NEXT_COMP)
+ if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_NEXT_COMP)
writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
- else if (notify == IB_CQ_SOLICITED)
+ else if ((notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
else
return -EINVAL;
@@ -241,7 +243,13 @@ int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
*/
readb(&shared->armed);
- return 0;
+ if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+ spin_lock_irqsave(&cq->lock, flags);
+ ret = !c2_mq_empty(&cq->mq);
+ spin_unlock_irqrestore(&cq->lock, flags);
+ }
+
+ return ret;
}
static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 607c09bf764..109166223c0 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -290,7 +290,7 @@ static int c2_destroy_qp(struct ib_qp *ib_qp)
return 0;
}
-static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries,
+static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries, int vector,
struct ib_ucontext *context,
struct ib_udata *udata)
{
@@ -795,6 +795,7 @@ int c2_register_device(struct c2_dev *dev)
memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
dev->ibdev.phys_port_cnt = 1;
+ dev->ibdev.num_comp_vectors = 1;
dev->ibdev.dma_device = &dev->pcidev->dev;
dev->ibdev.query_device = c2_query_device;
dev->ibdev.query_port = c2_query_port;
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index f5e9aeec6f6..76049afc765 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -114,7 +114,10 @@ int cxio_hal_cq_op(struct cxio_rdev *rdev_p, struct t3_cq *cq,
return -EIO;
}
}
+
+ return 1;
}
+
return 0;
}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index 90d7b8972cb..ff7290eacef 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -38,6 +38,7 @@
#include "firmware_exports.h"
#define T3_MAX_SGE 4
+#define T3_MAX_INLINE 64
#define Q_EMPTY(rptr,wptr) ((rptr)==(wptr))
#define Q_FULL(rptr,wptr,size_log2) ( (((wptr)-(rptr))>>(size_log2)) && \
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 3b4b0acd707..b2faff5abce 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -1109,6 +1109,15 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
PDBG("%s ep %p\n", __FUNCTION__, ep);
+ /*
+ * We get 2 abort replies from the HW. The first one must
+ * be ignored except for scribbling that we need one more.
+ */
+ if (!(ep->flags & ABORT_REQ_IN_PROGRESS)) {
+ ep->flags |= ABORT_REQ_IN_PROGRESS;
+ return CPL_RET_BUF_DONE;
+ }
+
close_complete_upcall(ep);
state_set(&ep->com, DEAD);
release_ep_resources(ep);
@@ -1189,6 +1198,7 @@ static int listen_stop(struct iwch_listen_ep *ep)
}
req = (struct cpl_close_listserv_req *) skb_put(skb, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+ req->cpu_idx = 0;
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
skb->priority = 1;
ep->com.tdev->send(ep->com.tdev, skb);
@@ -1475,6 +1485,15 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
int ret;
int state;
+ /*
+ * We get 2 peer aborts from the HW. The first one must
+ * be ignored except for scribbling that we need one more.
+ */
+ if (!(ep->flags & PEER_ABORT_IN_PROGRESS)) {
+ ep->flags |= PEER_ABORT_IN_PROGRESS;
+ return CPL_RET_BUF_DONE;
+ }
+
if (is_neg_adv_abort(req->status)) {
PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
ep->hwtid);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
index 0c6f281bd4a..21a388c313c 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -143,6 +143,11 @@ enum iwch_ep_state {
DEAD,
};
+enum iwch_ep_flags {
+ PEER_ABORT_IN_PROGRESS = (1 << 0),
+ ABORT_REQ_IN_PROGRESS = (1 << 1),
+};
+
struct iwch_ep_common {
struct iw_cm_id *cm_id;
struct iwch_qp *qp;
@@ -181,6 +186,7 @@ struct iwch_ep {
u16 plen;
u32 ird;
u32 ord;
+ u32 flags;
};
static inline struct iwch_ep *to_ep(struct iw_cm_id *cm_id)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index af28a317016..a891493fd34 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -139,7 +139,7 @@ static int iwch_destroy_cq(struct ib_cq *ib_cq)
return 0;
}
-static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries,
+static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int vector,
struct ib_ucontext *ib_context,
struct ib_udata *udata)
{
@@ -292,7 +292,7 @@ static int iwch_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
#endif
}
-static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
{
struct iwch_dev *rhp;
struct iwch_cq *chp;
@@ -303,7 +303,7 @@ static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
chp = to_iwch_cq(ibcq);
rhp = chp->rhp;
- if (notify == IB_CQ_SOLICITED)
+ if ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED)
cq_op = CQ_ARM_SE;
else
cq_op = CQ_ARM_AN;
@@ -317,9 +317,11 @@ static int iwch_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
PDBG("%s rptr 0x%x\n", __FUNCTION__, chp->cq.rptr);
err = cxio_hal_cq_op(&rhp->rdev, &chp->cq, cq_op, 0);
spin_unlock_irqrestore(&chp->lock, flag);
- if (err)
+ if (err < 0)
printk(KERN_ERR MOD "Error %d rearming CQID 0x%x\n", err,
chp->cq.cqid);
+ if (err > 0 && !(flags & IB_CQ_REPORT_MISSED_EVENTS))
+ err = 0;
return err;
}
@@ -780,6 +782,9 @@ static struct ib_qp *iwch_create_qp(struct ib_pd *pd,
if (rqsize > T3_MAX_RQ_SIZE)
return ERR_PTR(-EINVAL);
+ if (attrs->cap.max_inline_data > T3_MAX_INLINE)
+ return ERR_PTR(-EINVAL);
+
/*
* NOTE: The SQ and total WQ sizes don't need to be
* a power of two. However, all the code assumes
@@ -1107,6 +1112,7 @@ int iwch_register_device(struct iwch_dev *dev)
dev->ibdev.node_type = RDMA_NODE_RNIC;
memcpy(dev->ibdev.node_desc, IWCH_NODE_DESC, sizeof(IWCH_NODE_DESC));
dev->ibdev.phys_port_cnt = dev->rdev.port_info.nports;
+ dev->ibdev.num_comp_vectors = 1;
dev->ibdev.dma_device = &(dev->rdev.rnic_info.pdev->dev);
dev->ibdev.query_device = iwch_query_device;
dev->ibdev.query_port = iwch_query_port;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 0a472c9b44d..714dddbc9a9 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -471,43 +471,62 @@ int iwch_bind_mw(struct ib_qp *qp,
return err;
}
-static void build_term_codes(int t3err, u8 *layer_type, u8 *ecode, int tagged)
+static inline void build_term_codes(struct respQ_msg_t *rsp_msg,
+ u8 *layer_type, u8 *ecode)
{
- switch (t3err) {
+ int status = TPT_ERR_INTERNAL_ERR;
+ int tagged = 0;
+ int opcode = -1;
+ int rqtype = 0;
+ int send_inv = 0;
+
+ if (rsp_msg) {
+ status = CQE_STATUS(rsp_msg->cqe);
+ opcode = CQE_OPCODE(rsp_msg->cqe);
+ rqtype = RQ_TYPE(rsp_msg->cqe);
+ send_inv = (opcode == T3_SEND_WITH_INV) ||
+ (opcode == T3_SEND_WITH_SE_INV);
+ tagged = (opcode == T3_RDMA_WRITE) ||
+ (rqtype && (opcode == T3_READ_RESP));
+ }
+
+ switch (status) {
case TPT_ERR_STAG:
- if (tagged == 1) {
- *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
- *ecode = DDPT_INV_STAG;
- } else if (tagged == 2) {
+ if (send_inv) {
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_OP;
+ *ecode = RDMAP_CANT_INV_STAG;
+ } else {
*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
*ecode = RDMAP_INV_STAG;
}
break;
case TPT_ERR_PDID:
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ if ((opcode == T3_SEND_WITH_INV) ||
+ (opcode == T3_SEND_WITH_SE_INV))
+ *ecode = RDMAP_CANT_INV_STAG;
+ else
+ *ecode = RDMAP_STAG_NOT_ASSOC;
+ break;
case TPT_ERR_QPID:
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ *ecode = RDMAP_STAG_NOT_ASSOC;
+ break;
case TPT_ERR_ACCESS:
- if (tagged == 1) {
- *layer_type = LAYER_DDP|DDP_TAGGED_ERR;
- *ecode = DDPT_STAG_NOT_ASSOC;
- } else if (tagged == 2) {
- *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
- *ecode = RDMAP_STAG_NOT_ASSOC;
- }
+ *layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
+ *ecode = RDMAP_ACC_VIOL;
break;
case TPT_ERR_WRAP:
*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
*ecode = RDMAP_TO_WRAP;
break;
case TPT_ERR_BOUND:
- if (tagged == 1) {
+ if (tagged) {
*layer_type = LAYER_DDP|DDP_TAGGED_ERR;
*ecode = DDPT_BASE_BOUNDS;
- } else if (tagged == 2) {
+ } else {
*layer_type = LAYER_RDMAP|RDMAP_REMOTE_PROT;
*ecode = RDMAP_BASE_BOUNDS;
- } else {
- *layer_type = LAYER_DDP|DDP_UNTAGGED_ERR;
- *ecode = DDPU_MSG_TOOBIG;
}
break;
case TPT_ERR_INVALIDATE_SHARED_MR:
@@ -591,8 +610,6 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
{
union t3_wr *wqe;
struct terminate_message *term;
- int status;
- int tagged = 0;
struct sk_buff *skb;
PDBG("%s %d\n", __FUNCTION__, __LINE__);
@@ -610,17 +627,7 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
/* immediate data starts here. */
term = (struct terminate_message *)wqe->send.sgl;
- if (rsp_msg) {
- status = CQE_STATUS(rsp_msg->cqe);
- if (CQE_OPCODE(rsp_msg->cqe) == T3_RDMA_WRITE)
- tagged = 1;
- if ((CQE_OPCODE(rsp_msg->cqe) == T3_READ_REQ) ||
- (CQE_OPCODE(rsp_msg->cqe) == T3_READ_RESP))
- tagged = 2;
- } else {
- status = TPT_ERR_INTERNAL_ERR;
- }
- build_term_codes(status, &term->layer_etype, &term->ecode, tagged);
+ build_term_codes(rsp_msg, &term->layer_etype, &term->ecode);
build_fw_riwrh((void *)wqe, T3_WR_SEND,
T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1,
qhp->ep->hwtid, 5);
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index e2cdc1a16fe..67f0670fe3b 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -113,7 +113,7 @@ struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
return ret;
}
-struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
struct ib_ucontext *context,
struct ib_udata *udata)
{
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index f284be1c916..82dda2faf4d 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -745,6 +745,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
if(!create_comp_task(pool, cpu)) {
ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
@@ -752,24 +753,29 @@ static int comp_pool_callback(struct notifier_block *nfb,
}
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
kthread_bind(cct->task, any_online_cpu(cpu_online_map));
destroy_comp_task(pool, cpu);
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
kthread_bind(cct->task, cpu);
wake_up_process(cct->task);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
break;
case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
destroy_comp_task(pool, cpu);
take_over_work(pool, cpu);
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 95fd59fb452..e14b029332c 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -123,7 +123,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
-struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
struct ib_ucontext *context,
struct ib_udata *udata);
@@ -135,7 +135,7 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify);
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags);
struct ib_qp *ehca_create_qp(struct ib_pd *pd,
struct ib_qp_init_attr *init_attr,
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 3b23d677cb8..fe90e745456 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -313,6 +313,7 @@ int ehca_init_device(struct ehca_shca *shca)
shca->ib_device.node_type = RDMA_NODE_IB_CA;
shca->ib_device.phys_port_cnt = shca->num_ports;
+ shca->ib_device.num_comp_vectors = 1;
shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev;
shca->ib_device.query_device = ehca_query_device;
shca->ib_device.query_port = ehca_query_port;
@@ -375,7 +376,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
return -EPERM;
}
- ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
if (IS_ERR(ibcq)) {
ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
return PTR_ERR(ibcq);
@@ -565,11 +566,11 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
const struct of_device_id *id)
{
struct ehca_shca *shca;
- u64 *handle;
+ const u64 *handle;
struct ib_pd *ibpd;
int ret;
- handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+ handle = of_get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
if (!handle) {
ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
dev->ofdev.node->full_name);
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 08d3f892d9f..caec9dee09e 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -634,11 +634,13 @@ poll_cq_exit0:
return ret;
}
-int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags)
{
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ unsigned long spl_flags;
+ int ret = 0;
- switch (cq_notify) {
+ switch (notify_flags & IB_CQ_SOLICITED_MASK) {
case IB_CQ_SOLICITED:
hipz_set_cqx_n0(my_cq, 1);
break;
@@ -649,5 +651,11 @@ int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
return -EINVAL;
}
- return 0;
+ if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+ spin_lock_irqsave(&my_cq->spinlock, spl_flags);
+ ret = ipz_qeit_is_valid(&my_cq->ipz_queue);
+ spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
+ }
+
+ return ret;
}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index 8199c45768a..57f141a36bc 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -140,6 +140,14 @@ static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
return cqe;
}
+static inline int ipz_qeit_is_valid(struct ipz_queue *queue)
+{
+ struct ehca_cqe *cqe = ipz_qeit_get(queue);
+ u32 cqe_flags = cqe->cqe_flags;
+
+ return cqe_flags >> 7 == (queue->toggle_state & 1);
+}
+
/*
* returns and resets Queue Entry iterator
* returns address (kv) of first Queue Entry
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index ea78e6dddc9..3e9241badba 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -204,7 +204,7 @@ static void send_complete(unsigned long data)
*
* Called by ib_create_cq() in the generic verbs code.
*/
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
+struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
struct ib_ucontext *context,
struct ib_udata *udata)
{
@@ -243,33 +243,21 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
* See ipath_mmap() for details.
*/
if (udata && udata->outlen >= sizeof(__u64)) {
- struct ipath_mmap_info *ip;
- __u64 offset = (__u64) wc;
int err;
+ u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
- err = ib_copy_to_udata(udata, &offset, sizeof(offset));
- if (err) {
- ret = ERR_PTR(err);
+ cq->ip = ipath_create_mmap_info(dev, s, context, wc);
+ if (!cq->ip) {
+ ret = ERR_PTR(-ENOMEM);
goto bail_wc;
}
- /* Allocate info for ipath_mmap(). */
- ip = kmalloc(sizeof(*ip), GFP_KERNEL);
- if (!ip) {
- ret = ERR_PTR(-ENOMEM);
- goto bail_wc;
+ err = ib_copy_to_udata(udata, &cq->ip->offset,
+ sizeof(cq->ip->offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_ip;
}
- cq->ip = ip;
- ip->context = context;
- ip->obj = wc;
- kref_init(&ip->ref);
- ip->mmap_cnt = 0;
- ip->size = PAGE_ALIGN(sizeof(*wc) +
- sizeof(struct ib_wc) * entries);
- spin_lock_irq(&dev->pending_lock);
- ip->next = dev->pending_mmaps;
- dev->pending_mmaps = ip;
- spin_unlock_irq(&dev->pending_lock);
} else
cq->ip = NULL;
@@ -277,12 +265,18 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
spin_unlock(&dev->n_cqs_lock);
ret = ERR_PTR(-ENOMEM);
- goto bail_wc;
+ goto bail_ip;
}
dev->n_cqs_allocated++;
spin_unlock(&dev->n_cqs_lock);
+ if (cq->ip) {
+ spin_lock_irq(&dev->pending_lock);
+ list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps);
+ spin_unlock_irq(&dev->pending_lock);
+ }
+
/*
* ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
* The number of entries should be >= the number requested or return
@@ -301,12 +295,12 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
goto done;
+bail_ip:
+ kfree(cq->ip);
bail_wc:
vfree(wc);
-
bail_cq:
kfree(cq);
-
done:
return ret;
}
@@ -340,17 +334,18 @@ int ipath_destroy_cq(struct ib_cq *ibcq)
/**
* ipath_req_notify_cq - change the notification type for a completion queue
* @ibcq: the completion queue
- * @notify: the type of notification to request
+ * @notify_flags: the type of notification to request
*
* Returns 0 for success.
*
* This may be called from interrupt context. Also called by
* ib_req_notify_cq() in the generic verbs code.
*/
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags)
{
struct ipath_cq *cq = to_icq(ibcq);
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&cq->lock, flags);
/*
@@ -358,9 +353,15 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
* any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
*/
if (cq->notify != IB_CQ_NEXT_COMP)
- cq->notify = notify;
+ cq->notify = notify_flags & IB_CQ_SOLICITED_MASK;
+
+ if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+ cq->queue->head != cq->queue->tail)
+ ret = 1;
+
spin_unlock_irqrestore(&cq->lock, flags);
- return 0;
+
+ return ret;
}
/**
@@ -443,13 +444,12 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
if (cq->ip) {
struct ipath_ibdev *dev = to_idev(ibcq->device);
struct ipath_mmap_info *ip = cq->ip;
+ u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
- ip->obj = wc;
- ip->size = PAGE_ALIGN(sizeof(*wc) +
- sizeof(struct ib_wc) * cqe);
+ ipath_update_mmap_info(dev, ip, s, wc);
spin_lock_irq(&dev->pending_lock);
- ip->next = dev->pending_mmaps;
- dev->pending_mmaps = ip;
+ if (list_empty(&ip->pending_mmaps))
+ list_add(&ip->pending_mmaps, &dev->pending_mmaps);
spin_unlock_irq(&dev->pending_lock);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index ed55979bfd3..ebd5c7bd2cd 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -38,7 +38,6 @@
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/namei.h>
-#include <linux/pci.h>
#include "ipath_kernel.h"
@@ -524,7 +523,7 @@ static int ipathfs_fill_super(struct super_block *sb, void *data,
int ret;
static struct tree_descr files[] = {
- [1] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
+ [2] = {"atomic_stats", &atomic_stats_ops, S_IRUGO},
{""},
};
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
index e46aa4ed2a7..05a1d2b01d9 100644
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ b/drivers/infiniband/hw/ipath/ipath_layer.c
@@ -37,7 +37,6 @@
*/
#include <linux/io.h>
-#include <linux/pci.h>
#include <asm/byteorder.h>
#include "ipath_kernel.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
index a82157db468..937bc3396b5 100644
--- a/drivers/infiniband/hw/ipath/ipath_mmap.c
+++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
@@ -46,6 +46,11 @@ void ipath_release_mmap_info(struct kref *ref)
{
struct ipath_mmap_info *ip =
container_of(ref, struct ipath_mmap_info, ref);
+ struct ipath_ibdev *dev = to_idev(ip->context->device);
+
+ spin_lock_irq(&dev->pending_lock);
+ list_del(&ip->pending_mmaps);
+ spin_unlock_irq(&dev->pending_lock);
vfree(ip->obj);
kfree(ip);
@@ -60,14 +65,12 @@ static void ipath_vma_open(struct vm_area_struct *vma)
struct ipath_mmap_info *ip = vma->vm_private_data;
kref_get(&ip->ref);
- ip->mmap_cnt++;
}
static void ipath_vma_close(struct vm_area_struct *vma)
{
struct ipath_mmap_info *ip = vma->vm_private_data;
- ip->mmap_cnt--;
kref_put(&ip->ref, ipath_release_mmap_info);
}
@@ -87,7 +90,7 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
struct ipath_ibdev *dev = to_idev(context->device);
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long size = vma->vm_end - vma->vm_start;
- struct ipath_mmap_info *ip, **pp;
+ struct ipath_mmap_info *ip, *pp;
int ret = -EINVAL;
/*
@@ -96,15 +99,16 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
* CQ, QP, or SRQ is soon followed by a call to mmap().
*/
spin_lock_irq(&dev->pending_lock);
- for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) {
+ list_for_each_entry_safe(ip, pp, &dev->pending_mmaps,
+ pending_mmaps) {
/* Only the creator is allowed to mmap the object */
- if (context != ip->context || (void *) offset != ip->obj)
+ if (context != ip->context || (__u64) offset != ip->offset)
continue;
/* Don't allow a mmap larger than the object. */
if (size > ip->size)
break;
- *pp = ip->next;
+ list_del_init(&ip->pending_mmaps);
spin_unlock_irq(&dev->pending_lock);
ret = remap_vmalloc_range(vma, ip->obj, 0);
@@ -119,3 +123,51 @@ int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
done:
return ret;
}
+
+/*
+ * Allocate information for ipath_mmap
+ */
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+ u32 size,
+ struct ib_ucontext *context,
+ void *obj) {
+ struct ipath_mmap_info *ip;
+
+ ip = kmalloc(sizeof *ip, GFP_KERNEL);
+ if (!ip)
+ goto bail;
+
+ size = PAGE_ALIGN(size);
+
+ spin_lock_irq(&dev->mmap_offset_lock);
+ if (dev->mmap_offset == 0)
+ dev->mmap_offset = PAGE_SIZE;
+ ip->offset = dev->mmap_offset;
+ dev->mmap_offset += size;
+ spin_unlock_irq(&dev->mmap_offset_lock);
+
+ INIT_LIST_HEAD(&ip->pending_mmaps);
+ ip->size = size;
+ ip->context = context;
+ ip->obj = obj;
+ kref_init(&ip->ref);
+
+bail:
+ return ip;
+}
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+ struct ipath_mmap_info *ip,
+ u32 size, void *obj) {
+ size = PAGE_ALIGN(size);
+
+ spin_lock_irq(&dev->mmap_offset_lock);
+ if (dev->mmap_offset == 0)
+ dev->mmap_offset = PAGE_SIZE;
+ ip->offset = dev->mmap_offset;
+ dev->mmap_offset += size;
+ spin_unlock_irq(&dev->mmap_offset_lock);
+
+ ip->size = size;
+ ip->obj = obj;
+}
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 16db9ac0b40..bfef08ecd34 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -844,34 +844,36 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
* See ipath_mmap() for details.
*/
if (udata && udata->outlen >= sizeof(__u64)) {
- struct ipath_mmap_info *ip;
- __u64 offset = (__u64) qp->r_rq.wq;
int err;
- err = ib_copy_to_udata(udata, &offset, sizeof(offset));
- if (err) {
- ret = ERR_PTR(err);
- goto bail_rwq;
- }
+ if (!qp->r_rq.wq) {
+ __u64 offset = 0;
- if (qp->r_rq.wq) {
- /* Allocate info for ipath_mmap(). */
- ip = kmalloc(sizeof(*ip), GFP_KERNEL);
- if (!ip) {
+ err = ib_copy_to_udata(udata, &offset,
+ sizeof(offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_rwq;
+ }
+ } else {
+ u32 s = sizeof(struct ipath_rwq) +
+ qp->r_rq.size * sz;
+
+ qp->ip =
+ ipath_create_mmap_info(dev, s,
+ ibpd->uobject->context,
+ qp->r_rq.wq);
+ if (!qp->ip) {
ret = ERR_PTR(-ENOMEM);
goto bail_rwq;
}
- qp->ip = ip;
- ip->context = ibpd->uobject->context;
- ip->obj = qp->r_rq.wq;
- kref_init(&ip->ref);
- ip->mmap_cnt = 0;
- ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
- qp->r_rq.size * sz);
- spin_lock_irq(&dev->pending_lock);
- ip->next = dev->pending_mmaps;
- dev->pending_mmaps = ip;
- spin_unlock_irq(&dev->pending_lock);
+
+ err = ib_copy_to_udata(udata, &(qp->ip->offset),
+ sizeof(qp->ip->offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_ip;
+ }
}
}
@@ -885,6 +887,12 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
dev->n_qps_allocated++;
spin_unlock(&dev->n_qps_lock);
+ if (qp->ip) {
+ spin_lock_irq(&dev->pending_lock);
+ list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps);
+ spin_unlock_irq(&dev->pending_lock);
+ }
+
ret = &qp->ibqp;
goto bail;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index b4b88d0b53f..1915771fd03 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -98,13 +98,21 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
case OP(RDMA_READ_RESPONSE_LAST):
case OP(RDMA_READ_RESPONSE_ONLY):
case OP(ATOMIC_ACKNOWLEDGE):
- qp->s_ack_state = OP(ACKNOWLEDGE);
+ /*
+ * We can increment the tail pointer now that the last
+ * response has been sent instead of only being
+ * constructed.
+ */
+ if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
+ qp->s_tail_ack_queue = 0;
/* FALLTHROUGH */
+ case OP(SEND_ONLY):
case OP(ACKNOWLEDGE):
/* Check for no next entry in the queue. */
if (qp->r_head_ack_queue == qp->s_tail_ack_queue) {
if (qp->s_flags & IPATH_S_ACK_PENDING)
goto normal;
+ qp->s_ack_state = OP(ACKNOWLEDGE);
goto bail;
}
@@ -117,12 +125,8 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
if (len > pmtu) {
len = pmtu;
qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
- } else {
+ } else
qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
- if (++qp->s_tail_ack_queue >
- IPATH_MAX_RDMA_ATOMIC)
- qp->s_tail_ack_queue = 0;
- }
ohdr->u.aeth = ipath_compute_aeth(qp);
hwords++;
qp->s_ack_rdma_psn = e->psn;
@@ -139,8 +143,6 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
cpu_to_be32(e->atomic_data);
hwords += sizeof(ohdr->u.at) / sizeof(u32);
bth2 = e->psn;
- if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
- qp->s_tail_ack_queue = 0;
}
bth0 = qp->s_ack_state << 24;
break;
@@ -156,8 +158,6 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
ohdr->u.aeth = ipath_compute_aeth(qp);
hwords++;
qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
- if (++qp->s_tail_ack_queue > IPATH_MAX_RDMA_ATOMIC)
- qp->s_tail_ack_queue = 0;
}
bth0 = qp->s_ack_state << 24;
bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
@@ -171,7 +171,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
* the ACK before setting s_ack_state to ACKNOWLEDGE
* (see above).
*/
- qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE);
+ qp->s_ack_state = OP(SEND_ONLY);
qp->s_flags &= ~IPATH_S_ACK_PENDING;
qp->s_cur_sge = NULL;
if (qp->s_nak_state)
@@ -223,23 +223,18 @@ int ipath_make_rc_req(struct ipath_qp *qp,
/* Sending responses has higher priority over sending requests. */
if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
(qp->s_flags & IPATH_S_ACK_PENDING) ||
- qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE) &&
+ qp->s_ack_state != OP(ACKNOWLEDGE)) &&
ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
goto done;
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
- qp->s_rnr_timeout)
+ qp->s_rnr_timeout || qp->s_wait_credit)
goto bail;
/* Limit the number of packets sent without an ACK. */
if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
qp->s_wait_credit = 1;
dev->n_rc_stalls++;
- spin_lock(&dev->pending_lock);
- if (list_empty(&qp->timerwait))
- list_add_tail(&qp->timerwait,
- &dev->pending[dev->pending_index]);
- spin_unlock(&dev->pending_lock);
goto bail;
}
@@ -587,9 +582,12 @@ static void send_rc_ack(struct ipath_qp *qp)
u32 hwords;
struct ipath_ib_header hdr;
struct ipath_other_headers *ohdr;
+ unsigned long flags;
/* Don't send ACK or NAK if a RDMA read or atomic is pending. */
- if (qp->r_head_ack_queue != qp->s_tail_ack_queue)
+ if (qp->r_head_ack_queue != qp->s_tail_ack_queue ||
+ (qp->s_flags & IPATH_S_ACK_PENDING) ||
+ qp->s_ack_state != OP(ACKNOWLEDGE))
goto queue_ack;
/* Construct the header. */
@@ -640,11 +638,11 @@ static void send_rc_ack(struct ipath_qp *qp)
dev->n_rc_qacks++;
queue_ack:
- spin_lock_irq(&qp->s_lock);
+ spin_lock_irqsave(&qp->s_lock, flags);
qp->s_flags |= IPATH_S_ACK_PENDING;
qp->s_nak_state = qp->r_nak_state;
qp->s_ack_psn = qp->r_ack_psn;
- spin_unlock_irq(&qp->s_lock);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
/* Call ipath_do_rc_send() in another thread. */
tasklet_hi_schedule(&qp->s_task);
@@ -1261,6 +1259,7 @@ ack_err:
wc.dlid_path_bits = 0;
wc.port_num = 0;
ipath_sqerror_qp(qp, &wc);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
bail:
return;
}
@@ -1294,6 +1293,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
struct ipath_ack_entry *e;
u8 i, prev;
int old_req;
+ unsigned long flags;
if (diff > 0) {
/*
@@ -1327,7 +1327,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
psn &= IPATH_PSN_MASK;
e = NULL;
old_req = 1;
- spin_lock_irq(&qp->s_lock);
+ spin_lock_irqsave(&qp->s_lock, flags);
for (i = qp->r_head_ack_queue; ; i = prev) {
if (i == qp->s_tail_ack_queue)
old_req = 0;
@@ -1425,7 +1425,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
* after all the previous RDMA reads and atomics.
*/
if (i == qp->r_head_ack_queue) {
- spin_unlock_irq(&qp->s_lock);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
qp->r_nak_state = 0;
qp->r_ack_psn = qp->r_psn - 1;
goto send_ack;
@@ -1439,11 +1439,10 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
break;
}
qp->r_nak_state = 0;
- spin_unlock_irq(&qp->s_lock);
tasklet_hi_schedule(&qp->s_task);
unlock_done:
- spin_unlock_irq(&qp->s_lock);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
done:
return 1;
@@ -1453,10 +1452,12 @@ send_ack:
static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
{
- spin_lock_irq(&qp->s_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&qp->s_lock, flags);
qp->state = IB_QPS_ERR;
ipath_error_qp(qp, err);
- spin_unlock_irq(&qp->s_lock);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
}
/**
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
index 94033503400..03acae66ba8 100644
--- a/drivers/infiniband/hw/ipath/ipath_srq.c
+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
@@ -139,33 +139,24 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
* See ipath_mmap() for details.
*/
if (udata && udata->outlen >= sizeof(__u64)) {
- struct ipath_mmap_info *ip;
- __u64 offset = (__u64) srq->rq.wq;
int err;
+ u32 s = sizeof(struct ipath_rwq) + srq->rq.size * sz;
- err = ib_copy_to_udata(udata, &offset, sizeof(offset));
- if (err) {
- ret = ERR_PTR(err);
+ srq->ip =
+ ipath_create_mmap_info(dev, s,
+ ibpd->uobject->context,
+ srq->rq.wq);
+ if (!srq->ip) {
+ ret = ERR_PTR(-ENOMEM);
goto bail_wq;
}
- /* Allocate info for ipath_mmap(). */
- ip = kmalloc(sizeof(*ip), GFP_KERNEL);
- if (!ip) {
- ret = ERR_PTR(-ENOMEM);
- goto bail_wq;
+ err = ib_copy_to_udata(udata, &srq->ip->offset,
+ sizeof(srq->ip->offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_ip;
}
- srq->ip = ip;
- ip->context = ibpd->uobject->context;
- ip->obj = srq->rq.wq;
- kref_init(&ip->ref);
- ip->mmap_cnt = 0;
- ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
- srq->rq.size * sz);
- spin_lock_irq(&dev->pending_lock);
- ip->next = dev->pending_mmaps;
- dev->pending_mmaps = ip;
- spin_unlock_irq(&dev->pending_lock);
} else
srq->ip = NULL;
@@ -181,21 +172,27 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
spin_unlock(&dev->n_srqs_lock);
ret = ERR_PTR(-ENOMEM);
- goto bail_wq;
+ goto bail_ip;
}
dev->n_srqs_allocated++;
spin_unlock(&dev->n_srqs_lock);
+ if (srq->ip) {
+ spin_lock_irq(&dev->pending_lock);
+ list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps);
+ spin_unlock_irq(&dev->pending_lock);
+ }
+
ret = &srq->ibsrq;
goto done;
+bail_ip:
+ kfree(srq->ip);
bail_wq:
vfree(srq->rq.wq);
-
bail_srq:
kfree(srq);
-
done:
return ret;
}
@@ -312,13 +309,13 @@ int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
if (srq->ip) {
struct ipath_mmap_info *ip = srq->ip;
struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
+ u32 s = sizeof(struct ipath_rwq) + size * sz;
- ip->obj = wq;
- ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
- size * sz);
+ ipath_update_mmap_info(dev, ip, s, wq);
spin_lock_irq(&dev->pending_lock);
- ip->next = dev->pending_mmaps;
- dev->pending_mmaps = ip;
+ if (list_empty(&ip->pending_mmaps))
+ list_add(&ip->pending_mmaps,
+ &dev->pending_mmaps);
spin_unlock_irq(&dev->pending_lock);
}
} else if (attr_mask & IB_SRQ_LIMIT) {
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index 9307f7187ca..d8b5e4cefe2 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -31,8 +31,6 @@
* SOFTWARE.
*/
-#include <linux/pci.h>
-
#include "ipath_kernel.h"
struct infinipath_stats ipath_stats;
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index ffa6318ad0c..4dc398d5e01 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -32,7 +32,6 @@
*/
#include <linux/ctype.h>
-#include <linux/pci.h>
#include "ipath_kernel.h"
#include "ipath_common.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 18c6df2052c..12933e77c7e 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -1476,7 +1476,10 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
ret = -ENOMEM;
goto err_lk;
}
+ INIT_LIST_HEAD(&idev->pending_mmaps);
spin_lock_init(&idev->pending_lock);
+ idev->mmap_offset = PAGE_SIZE;
+ spin_lock_init(&idev->mmap_offset_lock);
INIT_LIST_HEAD(&idev->pending[0]);
INIT_LIST_HEAD(&idev->pending[1]);
INIT_LIST_HEAD(&idev->pending[2]);
@@ -1558,6 +1561,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
dev->node_type = RDMA_NODE_IB_CA;
dev->phys_port_cnt = 1;
+ dev->num_comp_vectors = 1;
dev->dma_device = &dd->pcidev->dev;
dev->query_device = ipath_query_device;
dev->modify_device = ipath_modify_device;
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 7c4929f1cb5..7064fc22272 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -173,12 +173,12 @@ struct ipath_ah {
* this as its vm_private_data.
*/
struct ipath_mmap_info {
- struct ipath_mmap_info *next;
+ struct list_head pending_mmaps;
struct ib_ucontext *context;
void *obj;
+ __u64 offset;
struct kref ref;
unsigned size;
- unsigned mmap_cnt;
};
/*
@@ -422,7 +422,7 @@ struct ipath_qp {
#define IPATH_S_RDMAR_PENDING 0x04
#define IPATH_S_ACK_PENDING 0x08
-#define IPATH_PSN_CREDIT 2048
+#define IPATH_PSN_CREDIT 512
/*
* Since struct ipath_swqe is not a fixed size, we can't simply index into
@@ -485,9 +485,10 @@ struct ipath_opcode_stats {
struct ipath_ibdev {
struct ib_device ibdev;
- struct list_head dev_list;
struct ipath_devdata *dd;
- struct ipath_mmap_info *pending_mmaps;
+ struct list_head pending_mmaps;
+ spinlock_t mmap_offset_lock;
+ u32 mmap_offset;
int ib_unit; /* This is the device number */
u16 sm_lid; /* in host order */
u8 sm_sl;
@@ -734,13 +735,13 @@ int ipath_destroy_srq(struct ib_srq *ibsrq);
int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
-struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
+struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
struct ib_ucontext *context,
struct ib_udata *udata);
int ipath_destroy_cq(struct ib_cq *ibcq);
-int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
+int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags);
int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata);
@@ -768,6 +769,15 @@ int ipath_dealloc_fmr(struct ib_fmr *ibfmr);
void ipath_release_mmap_info(struct kref *ref);
+struct ipath_mmap_info *ipath_create_mmap_info(struct ipath_ibdev *dev,
+ u32 size,
+ struct ib_ucontext *context,
+ void *obj);
+
+void ipath_update_mmap_info(struct ipath_ibdev *dev,
+ struct ipath_mmap_info *ip,
+ u32 size, void *obj);
+
int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index efd79ef109a..cf0868f6e96 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -726,11 +726,12 @@ repoll:
return err == 0 || err == -EAGAIN ? npolled : err;
}
-int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
{
__be32 doorbell[2];
- doorbell[0] = cpu_to_be32((notify == IB_CQ_SOLICITED ?
+ doorbell[0] = cpu_to_be32(((flags & IB_CQ_SOLICITED_MASK) ==
+ IB_CQ_SOLICITED ?
MTHCA_TAVOR_CQ_DB_REQ_NOT_SOL :
MTHCA_TAVOR_CQ_DB_REQ_NOT) |
to_mcq(cq)->cqn);
@@ -743,7 +744,7 @@ int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify)
return 0;
}
-int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
{
struct mthca_cq *cq = to_mcq(ibcq);
__be32 doorbell[2];
@@ -755,7 +756,8 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
doorbell[0] = ci;
doorbell[1] = cpu_to_be32((cq->cqn << 8) | (2 << 5) | (sn << 3) |
- (notify == IB_CQ_SOLICITED ? 1 : 2));
+ ((flags & IB_CQ_SOLICITED_MASK) ==
+ IB_CQ_SOLICITED ? 1 : 2));
mthca_write_db_rec(doorbell, cq->arm_db);
@@ -766,7 +768,7 @@ int mthca_arbel_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
wmb();
doorbell[0] = cpu_to_be32((sn << 28) |
- (notify == IB_CQ_SOLICITED ?
+ ((flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ?
MTHCA_ARBEL_CQ_DB_REQ_NOT_SOL :
MTHCA_ARBEL_CQ_DB_REQ_NOT) |
cq->cqn);
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index b7e42efaf43..9bae3cc6060 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -495,8 +495,8 @@ void mthca_unmap_eq_icm(struct mthca_dev *dev);
int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
struct ib_wc *entry);
-int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
-int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
+int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
+int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags);
int mthca_init_cq(struct mthca_dev *dev, int nent,
struct mthca_ucontext *ctx, u32 pdn,
struct mthca_cq *cq);
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index 594144145f4..a1ab06847b7 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -38,7 +38,6 @@
#define MTHCA_MEMFREE_H
#include <linux/list.h>
-#include <linux/pci.h>
#include <linux/mutex.h>
#define MTHCA_ICM_CHUNK_LEN \
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 47e6fd46d9c..1c05486c3c6 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -663,6 +663,7 @@ static int mthca_destroy_qp(struct ib_qp *qp)
}
static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
+ int comp_vector,
struct ib_ucontext *context,
struct ib_udata *udata)
{
@@ -1292,6 +1293,7 @@ int mthca_register_device(struct mthca_dev *dev)
(1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
dev->ib_dev.node_type = RDMA_NODE_IB_CA;
dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
+ dev->ib_dev.num_comp_vectors = 1;
dev->ib_dev.dma_device = &dev->pdev->dev;
dev->ib_dev.query_device = mthca_query_device;
dev->ib_dev.query_port = mthca_query_port;
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 8fe6fee7a97..fee60c852d1 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -701,6 +701,19 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_PRIMARY_ADDR_PATH);
}
+ if (ibqp->qp_type == IB_QPT_RC &&
+ cur_state == IB_QPS_INIT && new_state == IB_QPS_RTR) {
+ u8 sched_queue = ibqp->uobject ? 0x2 : 0x1;
+
+ if (mthca_is_memfree(dev))
+ qp_context->rlkey_arbel_sched_queue |= sched_queue;
+ else
+ qp_context->tavor_sched_queue |= cpu_to_be32(sched_queue);
+
+ qp_param->opt_param_mask |=
+ cpu_to_be32(MTHCA_QP_OPTPAR_SCHED_QUEUE);
+ }
+
if (attr_mask & IB_QP_TIMEOUT) {
qp_context->pri_path.ackto = attr->timeout << 3;
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index fd558267d1c..87310eeb6df 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -41,7 +41,6 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/workqueue.h>
-#include <linux/pci.h>
#include <linux/kref.h>
#include <linux/if_infiniband.h>
#include <linux/mutex.h>
@@ -311,6 +310,7 @@ extern struct workqueue_struct *ipoib_workqueue;
/* functions */
+int ipoib_poll(struct net_device *dev, int *budget);
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 0c4e59b906c..785bc8505f2 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -370,7 +370,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
if (!likely(wr_id & IPOIB_CM_RX_UPDATE_MASK)) {
p = wc->qp->qp_context;
- if (time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
+ if (p && time_after_eq(jiffies, p->jiffies + IPOIB_CM_RX_UPDATE_TIME)) {
spin_lock_irqsave(&priv->lock, flags);
p->jiffies = jiffies;
/* Move this entry to list head, but do
@@ -416,7 +416,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb->dev = dev;
/* XXX get correct PACKET_ type here */
skb->pkt_type = PACKET_HOST;
- netif_rx_ni(skb);
+ netif_receive_skb(skb);
repost:
if (unlikely(ipoib_cm_post_receive(dev, wr_id)))
@@ -592,7 +592,9 @@ int ipoib_cm_dev_open(struct net_device *dev)
priv->cm.id = ib_create_cm_id(priv->ca, ipoib_cm_rx_handler, dev);
if (IS_ERR(priv->cm.id)) {
printk(KERN_WARNING "%s: failed to create CM ID\n", priv->ca->name);
- return IS_ERR(priv->cm.id);
+ ret = PTR_ERR(priv->cm.id);
+ priv->cm.id = NULL;
+ return ret;
}
ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num),
@@ -601,6 +603,7 @@ int ipoib_cm_dev_open(struct net_device *dev)
printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name,
IPOIB_CM_IETF_ID | priv->qp->qp_num);
ib_destroy_cm_id(priv->cm.id);
+ priv->cm.id = NULL;
return ret;
}
return 0;
@@ -611,10 +614,11 @@ void ipoib_cm_dev_stop(struct net_device *dev)
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_cm_rx *p;
- if (!IPOIB_CM_SUPPORTED(dev->dev_addr))
+ if (!IPOIB_CM_SUPPORTED(dev->dev_addr) || !priv->cm.id)
return;
ib_destroy_cm_id(priv->cm.id);
+ priv->cm.id = NULL;
spin_lock_irq(&priv->lock);
while (!list_empty(&priv->cm.passive_ids)) {
p = list_entry(priv->cm.passive_ids.next, typeof(*p), list);
@@ -789,7 +793,7 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn,
}
p->cq = ib_create_cq(priv->ca, ipoib_cm_tx_completion, NULL, p,
- ipoib_sendq_size + 1);
+ ipoib_sendq_size + 1, 0);
if (IS_ERR(p->cq)) {
ret = PTR_ERR(p->cq);
ipoib_warn(priv, "failed to allocate tx cq: %d\n", ret);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 1bdb9101911..68d72c6f7ff 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -226,7 +226,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb->dev = dev;
/* XXX get correct PACKET_ type here */
skb->pkt_type = PACKET_HOST;
- netif_rx_ni(skb);
+ netif_receive_skb(skb);
} else {
ipoib_dbg_data(priv, "dropping loopback packet\n");
dev_kfree_skb_any(skb);
@@ -280,28 +280,63 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
wc->status, wr_id, wc->vendor_err);
}
-static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc)
+int ipoib_poll(struct net_device *dev, int *budget)
{
- if (wc->wr_id & IPOIB_CM_OP_SRQ)
- ipoib_cm_handle_rx_wc(dev, wc);
- else if (wc->wr_id & IPOIB_OP_RECV)
- ipoib_ib_handle_rx_wc(dev, wc);
- else
- ipoib_ib_handle_tx_wc(dev, wc);
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ int max = min(*budget, dev->quota);
+ int done;
+ int t;
+ int empty;
+ int n, i;
+
+ done = 0;
+ empty = 0;
+
+ while (max) {
+ t = min(IPOIB_NUM_WC, max);
+ n = ib_poll_cq(priv->cq, t, priv->ibwc);
+
+ for (i = 0; i < n; ++i) {
+ struct ib_wc *wc = priv->ibwc + i;
+
+ if (wc->wr_id & IPOIB_CM_OP_SRQ) {
+ ++done;
+ --max;
+ ipoib_cm_handle_rx_wc(dev, wc);
+ } else if (wc->wr_id & IPOIB_OP_RECV) {
+ ++done;
+ --max;
+ ipoib_ib_handle_rx_wc(dev, wc);
+ } else
+ ipoib_ib_handle_tx_wc(dev, wc);
+ }
+
+ if (n != t) {
+ empty = 1;
+ break;
+ }
+ }
+
+ dev->quota -= done;
+ *budget -= done;
+
+ if (empty) {
+ netif_rx_complete(dev);
+ if (unlikely(ib_req_notify_cq(priv->cq,
+ IB_CQ_NEXT_COMP |
+ IB_CQ_REPORT_MISSED_EVENTS)) &&
+ netif_rx_reschedule(dev, 0))
+ return 1;
+
+ return 0;
+ }
+
+ return 1;
}
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
{
- struct net_device *dev = (struct net_device *) dev_ptr;
- struct ipoib_dev_priv *priv = netdev_priv(dev);
- int n, i;
-
- ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
- do {
- n = ib_poll_cq(cq, IPOIB_NUM_WC, priv->ibwc);
- for (i = 0; i < n; ++i)
- ipoib_ib_handle_wc(dev, priv->ibwc + i);
- } while (n == IPOIB_NUM_WC);
+ netif_rx_schedule(dev_ptr);
}
static inline int post_send(struct ipoib_dev_priv *priv,
@@ -514,9 +549,10 @@ int ipoib_ib_dev_stop(struct net_device *dev)
struct ib_qp_attr qp_attr;
unsigned long begin;
struct ipoib_tx_buf *tx_req;
- int i;
+ int i, n;
clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
+ netif_poll_disable(dev);
ipoib_cm_dev_stop(dev);
@@ -568,6 +604,18 @@ int ipoib_ib_dev_stop(struct net_device *dev)
goto timeout;
}
+ do {
+ n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
+ for (i = 0; i < n; ++i) {
+ if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
+ ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
+ else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
+ ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
+ else
+ ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
+ }
+ } while (n == IPOIB_NUM_WC);
+
msleep(1);
}
@@ -596,6 +644,9 @@ timeout:
msleep(1);
}
+ netif_poll_enable(dev);
+ ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
+
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index b4c380c5a3b..0a428f2b05c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -948,6 +948,8 @@ static void ipoib_setup(struct net_device *dev)
dev->hard_header = ipoib_hard_header;
dev->set_multicast_list = ipoib_set_mcast_list;
dev->neigh_setup = ipoib_neigh_setup_dev;
+ dev->poll = ipoib_poll;
+ dev->weight = 100;
dev->watchdog_timeo = HZ;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 7f3ec205e35..5c3c6a43a52 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -187,7 +187,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
if (!ret)
size += ipoib_recvq_size;
- priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size);
+ priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
if (IS_ERR(priv->cq)) {
printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
goto out_free_mr;
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 278fcbccc2d..3651072f6c1 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -201,7 +201,7 @@ static int iser_post_receive_control(struct iscsi_conn *conn)
* what's common for both schemes is that the connection is not started
*/
if (conn->c_stage != ISCSI_CONN_STARTED)
- rx_data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+ rx_data_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
else /* FIXME till user space sets conn->max_recv_dlength correctly */
rx_data_size = 128;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 1fc967464a2..3702e237555 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -35,7 +35,6 @@
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/version.h>
@@ -76,7 +75,7 @@ static int iser_create_device_ib_res(struct iser_device *device)
iser_cq_callback,
iser_cq_event_callback,
(void *)device,
- ISER_MAX_CQ_LEN);
+ ISER_MAX_CQ_LEN, 0);
if (IS_ERR(device->cq))
goto cq_err;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 5e8ac577f0a..39bf057fbc4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -197,7 +197,7 @@ static int srp_create_target_ib(struct srp_target_port *target)
return -ENOMEM;
target->cq = ib_create_cq(target->srp_host->dev->dev, srp_completion,
- NULL, target, SRP_CQ_SIZE);
+ NULL, target, SRP_CQ_SIZE, 0);
if (IS_ERR(target->cq)) {
ret = PTR_ERR(target->cq);
goto out;
@@ -1468,6 +1468,25 @@ static ssize_t show_dgid(struct class_device *cdev, char *buf)
be16_to_cpu(((__be16 *) target->path.dgid.raw)[7]));
}
+static ssize_t show_orig_dgid(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ if (target->state == SRP_TARGET_DEAD ||
+ target->state == SRP_TARGET_REMOVED)
+ return -ENODEV;
+
+ return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ be16_to_cpu(target->orig_dgid[0]),
+ be16_to_cpu(target->orig_dgid[1]),
+ be16_to_cpu(target->orig_dgid[2]),
+ be16_to_cpu(target->orig_dgid[3]),
+ be16_to_cpu(target->orig_dgid[4]),
+ be16_to_cpu(target->orig_dgid[5]),
+ be16_to_cpu(target->orig_dgid[6]),
+ be16_to_cpu(target->orig_dgid[7]));
+}
+
static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(cdev));
@@ -1498,6 +1517,7 @@ static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
+static CLASS_DEVICE_ATTR(orig_dgid, S_IRUGO, show_orig_dgid, NULL);
static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
static CLASS_DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
@@ -1508,6 +1528,7 @@ static struct class_device_attribute *srp_host_attrs[] = {
&class_device_attr_service_id,
&class_device_attr_pkey,
&class_device_attr_dgid,
+ &class_device_attr_orig_dgid,
&class_device_attr_zero_req_lim,
&class_device_attr_local_ib_port,
&class_device_attr_local_ib_device,
@@ -1516,7 +1537,8 @@ static struct class_device_attribute *srp_host_attrs[] = {
static struct scsi_host_template srp_template = {
.module = THIS_MODULE,
- .name = DRV_NAME,
+ .name = "InfiniBand SRP initiator",
+ .proc_name = DRV_NAME,
.info = srp_target_info,
.queuecommand = srp_queuecommand,
.eh_abort_handler = srp_abort,
@@ -1662,6 +1684,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
}
kfree(p);
+ memcpy(target->orig_dgid, target->path.dgid.raw, 16);
break;
case SRP_OPT_PKEY:
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 2f3319c719a..1d53c7bc368 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -129,6 +129,7 @@ struct srp_target_port {
unsigned int scsi_id;
struct ib_sa_path_rec path;
+ __be16 orig_dgid[8];
struct ib_sa_query *path_query;
int path_query_id;
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 96232313b1b..0e9b69535ad 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -153,6 +153,8 @@ source "drivers/input/mouse/Kconfig"
source "drivers/input/joystick/Kconfig"
+source "drivers/input/tablet/Kconfig"
+
source "drivers/input/touchscreen/Kconfig"
source "drivers/input/misc/Kconfig"
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index da575deb3c7..8a2dd987546 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -13,12 +13,12 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
obj-$(CONFIG_INPUT_TSDEV) += tsdev.o
-obj-$(CONFIG_INPUT_POWER) += power.o
obj-$(CONFIG_INPUT_EVBUG) += evbug.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
obj-$(CONFIG_INPUT_MOUSE) += mouse/
obj-$(CONFIG_INPUT_JOYSTICK) += joystick/
+obj-$(CONFIG_INPUT_TABLET) += tablet/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
index 5a9653c3128..c21f2f12723 100644
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -38,31 +38,43 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Input driver event debug module");
MODULE_LICENSE("GPL");
-static char evbug_name[] = "evbug";
-
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
handle->dev->phys, type, code, value);
}
-static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
+static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct input_handle *handle;
+ int error;
- if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return NULL;
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
- handle->name = evbug_name;
+ handle->name = "evbug";
+
+ error = input_register_handle(handle);
+ if (error)
+ goto err_free_handle;
- input_open_device(handle);
+ error = input_open_device(handle);
+ if (error)
+ goto err_unregister_handle;
printk(KERN_DEBUG "evbug.c: Connected device: \"%s\", %s\n", dev->name, dev->phys);
- return handle;
+ return 0;
+
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_handle:
+ kfree(handle);
+ return error;
}
static void evbug_disconnect(struct input_handle *handle)
@@ -70,7 +82,7 @@ static void evbug_disconnect(struct input_handle *handle)
printk(KERN_DEBUG "evbug.c: Disconnected device: %s\n", handle->dev->phys);
input_close_device(handle);
-
+ input_unregister_handle(handle);
kfree(handle);
}
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 6439f378f6c..55a72592704 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/major.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/compat.h>
@@ -29,11 +28,11 @@ struct evdev {
char name[16];
struct input_handle handle;
wait_queue_head_t wait;
- struct evdev_list *grab;
- struct list_head list;
+ struct evdev_client *grab;
+ struct list_head client_list;
};
-struct evdev_list {
+struct evdev_client {
struct input_event buffer[EVDEV_BUFFER_SIZE];
int head;
int tail;
@@ -47,28 +46,28 @@ static struct evdev *evdev_table[EVDEV_MINORS];
static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct evdev *evdev = handle->private;
- struct evdev_list *list;
+ struct evdev_client *client;
if (evdev->grab) {
- list = evdev->grab;
+ client = evdev->grab;
- do_gettimeofday(&list->buffer[list->head].time);
- list->buffer[list->head].type = type;
- list->buffer[list->head].code = code;
- list->buffer[list->head].value = value;
- list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+ do_gettimeofday(&client->buffer[client->head].time);
+ client->buffer[client->head].type = type;
+ client->buffer[client->head].code = code;
+ client->buffer[client->head].value = value;
+ client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
} else
- list_for_each_entry(list, &evdev->list, node) {
+ list_for_each_entry(client, &evdev->client_list, node) {
- do_gettimeofday(&list->buffer[list->head].time);
- list->buffer[list->head].type = type;
- list->buffer[list->head].code = code;
- list->buffer[list->head].value = value;
- list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
+ do_gettimeofday(&client->buffer[client->head].time);
+ client->buffer[client->head].type = type;
+ client->buffer[client->head].code = code;
+ client->buffer[client->head].value = value;
+ client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1);
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&evdev->wait);
@@ -76,22 +75,23 @@ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned
static int evdev_fasync(int fd, struct file *file, int on)
{
+ struct evdev_client *client = file->private_data;
int retval;
- struct evdev_list *list = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
+ retval = fasync_helper(fd, file, on, &client->fasync);
return retval < 0 ? retval : 0;
}
static int evdev_flush(struct file *file, fl_owner_t id)
{
- struct evdev_list *list = file->private_data;
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
- if (!list->evdev->exist)
+ if (!evdev->exist)
return -ENODEV;
- return input_flush_device(&list->evdev->handle, file);
+ return input_flush_device(&evdev->handle, file);
}
static void evdev_free(struct evdev *evdev)
@@ -100,48 +100,62 @@ static void evdev_free(struct evdev *evdev)
kfree(evdev);
}
-static int evdev_release(struct inode * inode, struct file * file)
+static int evdev_release(struct inode *inode, struct file *file)
{
- struct evdev_list *list = file->private_data;
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
- if (list->evdev->grab == list) {
- input_release_device(&list->evdev->handle);
- list->evdev->grab = NULL;
+ if (evdev->grab == client) {
+ input_release_device(&evdev->handle);
+ evdev->grab = NULL;
}
evdev_fasync(-1, file, 0);
- list_del(&list->node);
+ list_del(&client->node);
+ kfree(client);
- if (!--list->evdev->open) {
- if (list->evdev->exist)
- input_close_device(&list->evdev->handle);
+ if (!--evdev->open) {
+ if (evdev->exist)
+ input_close_device(&evdev->handle);
else
- evdev_free(list->evdev);
+ evdev_free(evdev);
}
- kfree(list);
return 0;
}
-static int evdev_open(struct inode * inode, struct file * file)
+static int evdev_open(struct inode *inode, struct file *file)
{
- struct evdev_list *list;
+ struct evdev_client *client;
+ struct evdev *evdev;
int i = iminor(inode) - EVDEV_MINOR_BASE;
+ int error;
- if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
+ if (i >= EVDEV_MINORS)
return -ENODEV;
- if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
+ evdev = evdev_table[i];
+
+ if (!evdev || !evdev->exist)
+ return -ENODEV;
+
+ client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
+ if (!client)
return -ENOMEM;
- list->evdev = evdev_table[i];
- list_add_tail(&list->node, &evdev_table[i]->list);
- file->private_data = list;
+ client->evdev = evdev;
+ list_add_tail(&client->node, &evdev->client_list);
- if (!list->evdev->open++)
- if (list->evdev->exist)
- input_open_device(&list->evdev->handle);
+ if (!evdev->open++ && evdev->exist) {
+ error = input_open_device(&evdev->handle);
+ if (error) {
+ list_del(&client->node);
+ kfree(client);
+ return error;
+ }
+ }
+ file->private_data = client;
return 0;
}
@@ -243,54 +257,55 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev
#endif /* CONFIG_COMPAT */
-static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct evdev_list *list = file->private_data;
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
struct input_event event;
int retval = 0;
- if (!list->evdev->exist)
+ if (!evdev->exist)
return -ENODEV;
while (retval < count) {
if (evdev_event_from_user(buffer + retval, &event))
return -EFAULT;
- input_inject_event(&list->evdev->handle, event.type, event.code, event.value);
+ input_inject_event(&evdev->handle, event.type, event.code, event.value);
retval += evdev_event_size();
}
return retval;
}
-static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct evdev_list *list = file->private_data;
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
int retval;
if (count < evdev_event_size())
return -EINVAL;
- if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+ if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
- retval = wait_event_interruptible(list->evdev->wait,
- list->head != list->tail || (!list->evdev->exist));
-
+ retval = wait_event_interruptible(evdev->wait,
+ client->head != client->tail || !evdev->exist);
if (retval)
return retval;
- if (!list->evdev->exist)
+ if (!evdev->exist)
return -ENODEV;
- while (list->head != list->tail && retval + evdev_event_size() <= count) {
+ while (client->head != client->tail && retval + evdev_event_size() <= count) {
- struct input_event *event = (struct input_event *) list->buffer + list->tail;
+ struct input_event *event = (struct input_event *) client->buffer + client->tail;
if (evdev_event_to_user(buffer + retval, event))
return -EFAULT;
- list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+ client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += evdev_event_size();
}
@@ -300,11 +315,12 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
/* No kernel lock - fine */
static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
- struct evdev_list *list = file->private_data;
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
- poll_wait(file, &list->evdev->wait, wait);
- return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
- (list->evdev->exist ? 0 : (POLLHUP | POLLERR));
+ poll_wait(file, &evdev->wait, wait);
+ return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+ (evdev->exist ? 0 : (POLLHUP | POLLERR));
}
#ifdef CONFIG_COMPAT
@@ -387,8 +403,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
void __user *p, int compat_mode)
{
- struct evdev_list *list = file->private_data;
- struct evdev *evdev = list->evdev;
+ struct evdev_client *client = file->private_data;
+ struct evdev *evdev = client->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
struct ff_effect effect;
@@ -434,32 +450,21 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
case EVIOCGKEYCODE:
if (get_user(t, ip))
return -EFAULT;
- if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
- return -EINVAL;
- if (put_user(INPUT_KEYCODE(dev, t), ip + 1))
+
+ error = dev->getkeycode(dev, t, &v);
+ if (error)
+ return error;
+
+ if (put_user(v, ip + 1))
return -EFAULT;
+
return 0;
case EVIOCSKEYCODE:
- if (get_user(t, ip))
+ if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
- if (t < 0 || t >= dev->keycodemax || !dev->keycodesize)
- return -EINVAL;
- if (get_user(v, ip + 1))
- return -EFAULT;
- if (v < 0 || v > KEY_MAX)
- return -EINVAL;
- if (dev->keycodesize < sizeof(v) && (v >> (dev->keycodesize * 8)))
- return -EINVAL;
-
- u = SET_INPUT_KEYCODE(dev, t, v);
- clear_bit(u, dev->keybit);
- set_bit(v, dev->keybit);
- for (i = 0; i < dev->keycodemax; i++)
- if (INPUT_KEYCODE(dev, i) == u)
- set_bit(u, dev->keybit);
- return 0;
+ return dev->setkeycode(dev, t, v);
case EVIOCSFF:
if (copy_from_user(&effect, p, sizeof(effect)))
@@ -487,10 +492,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
return -EBUSY;
if (input_grab_device(&evdev->handle))
return -EBUSY;
- evdev->grab = list;
+ evdev->grab = client;
return 0;
} else {
- if (evdev->grab != list)
+ if (evdev->grab != client)
return -EINVAL;
input_release_device(&evdev->handle);
evdev->grab = NULL;
@@ -506,7 +511,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
- long *bits;
+ unsigned long *bits;
int len;
switch (_IOC_NR(cmd) & EV_MAX) {
@@ -551,7 +556,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
- int t = _IOC_NR(cmd) & ABS_MAX;
+ t = _IOC_NR(cmd) & ABS_MAX;
abs.value = dev->abs[t];
abs.minimum = dev->absmin[t];
@@ -571,7 +576,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
- int t = _IOC_NR(cmd) & ABS_MAX;
+ t = _IOC_NR(cmd) & ABS_MAX;
if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
return -EFAULT;
@@ -616,23 +621,26 @@ static const struct file_operations evdev_fops = {
.flush = evdev_flush
};
-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
+static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
+ dev_t devt;
int minor;
+ int error;
for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);
if (minor == EVDEV_MINORS) {
printk(KERN_ERR "evdev: no more free evdev devices\n");
- return NULL;
+ return -ENFILE;
}
- if (!(evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL)))
- return NULL;
+ evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);
+ if (!evdev)
+ return -ENOMEM;
- INIT_LIST_HEAD(&evdev->list);
+ INIT_LIST_HEAD(&evdev->client_list);
init_waitqueue_head(&evdev->wait);
evdev->exist = 1;
@@ -645,23 +653,45 @@ static struct input_handle *evdev_connect(struct input_handler *handler, struct
evdev_table[minor] = evdev;
- cdev = class_device_create(&input_class, &dev->cdev,
- MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
- dev->cdev.dev, evdev->name);
+ devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
+
+ cdev = class_device_create(&input_class, &dev->cdev, devt,
+ dev->cdev.dev, evdev->name);
+ if (IS_ERR(cdev)) {
+ error = PTR_ERR(cdev);
+ goto err_free_evdev;
+ }
/* temporary symlink to keep userspace happy */
- sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
- evdev->name);
+ error = sysfs_create_link(&input_class.subsys.kobj,
+ &cdev->kobj, evdev->name);
+ if (error)
+ goto err_cdev_destroy;
+
+ error = input_register_handle(&evdev->handle);
+ if (error)
+ goto err_remove_link;
- return &evdev->handle;
+ return 0;
+
+ err_remove_link:
+ sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
+ err_cdev_destroy:
+ class_device_destroy(&input_class, devt);
+ err_free_evdev:
+ kfree(evdev);
+ evdev_table[minor] = NULL;
+ return error;
}
static void evdev_disconnect(struct input_handle *handle)
{
struct evdev *evdev = handle->private;
- struct evdev_list *list;
+ struct evdev_client *client;
+
+ input_unregister_handle(handle);
- sysfs_remove_link(&input_class.subsys.kset.kobj, evdev->name);
+ sysfs_remove_link(&input_class.subsys.kobj, evdev->name);
class_device_destroy(&input_class,
MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + evdev->minor));
evdev->exist = 0;
@@ -670,8 +700,8 @@ static void evdev_disconnect(struct input_handle *handle)
input_flush_device(handle, NULL);
input_close_device(handle);
wake_up_interruptible(&evdev->wait);
- list_for_each_entry(list, &evdev->list, node)
- kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+ list_for_each_entry(client, &evdev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
} else
evdev_free(evdev);
}
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index 783b3412cea..eebc72465fc 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -281,7 +281,8 @@ int input_ff_event(struct input_dev *dev, unsigned int type,
break;
default:
- ff->playback(dev, code, value);
+ if (check_effect_access(ff, code, NULL) == 0)
+ ff->playback(dev, code, value);
break;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a9a706f8fff..ccd8abafcb7 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -11,7 +11,6 @@
*/
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/random.h>
@@ -299,12 +298,87 @@ void input_close_device(struct input_handle *handle)
}
EXPORT_SYMBOL(input_close_device);
-static void input_link_handle(struct input_handle *handle)
+static int input_fetch_keycode(struct input_dev *dev, int scancode)
{
- list_add_tail(&handle->d_node, &handle->dev->h_list);
- list_add_tail(&handle->h_node, &handle->handler->h_list);
+ switch (dev->keycodesize) {
+ case 1:
+ return ((u8 *)dev->keycode)[scancode];
+
+ case 2:
+ return ((u16 *)dev->keycode)[scancode];
+
+ default:
+ return ((u32 *)dev->keycode)[scancode];
+ }
+}
+
+static int input_default_getkeycode(struct input_dev *dev,
+ int scancode, int *keycode)
+{
+ if (!dev->keycodesize)
+ return -EINVAL;
+
+ if (scancode < 0 || scancode >= dev->keycodemax)
+ return -EINVAL;
+
+ *keycode = input_fetch_keycode(dev, scancode);
+
+ return 0;
+}
+
+static int input_default_setkeycode(struct input_dev *dev,
+ int scancode, int keycode)
+{
+ int old_keycode;
+ int i;
+
+ if (scancode < 0 || scancode >= dev->keycodemax)
+ return -EINVAL;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ if (!dev->keycodesize)
+ return -EINVAL;
+
+ if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
+ return -EINVAL;
+
+ switch (dev->keycodesize) {
+ case 1: {
+ u8 *k = (u8 *)dev->keycode;
+ old_keycode = k[scancode];
+ k[scancode] = keycode;
+ break;
+ }
+ case 2: {
+ u16 *k = (u16 *)dev->keycode;
+ old_keycode = k[scancode];
+ k[scancode] = keycode;
+ break;
+ }
+ default: {
+ u32 *k = (u32 *)dev->keycode;
+ old_keycode = k[scancode];
+ k[scancode] = keycode;
+ break;
+ }
+ }
+
+ clear_bit(old_keycode, dev->keybit);
+ set_bit(keycode, dev->keybit);
+
+ for (i = 0; i < dev->keycodemax; i++) {
+ if (input_fetch_keycode(dev, i) == old_keycode) {
+ set_bit(old_keycode, dev->keybit);
+ break; /* Setting the bit twice is useless, so break */
+ }
+ }
+
+ return 0;
}
+
#define MATCH_BIT(bit, max) \
for (i = 0; i < NBITS(max); i++) \
if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
@@ -351,6 +425,29 @@ static const struct input_device_id *input_match_device(const struct input_devic
return NULL;
}
+static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)
+{
+ const struct input_device_id *id;
+ int error;
+
+ if (handler->blacklist && input_match_device(handler->blacklist, dev))
+ return -ENODEV;
+
+ id = input_match_device(handler->id_table, dev);
+ if (!id)
+ return -ENODEV;
+
+ error = handler->connect(handler, dev, id);
+ if (error && error != -ENODEV)
+ printk(KERN_ERR
+ "input: failed to attach handler %s to device %s, "
+ "error: %d\n",
+ handler->name, kobject_name(&dev->cdev.kobj), error);
+
+ return error;
+}
+
+
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
@@ -439,6 +536,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : "");
seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");
seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");
+ seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");
seq_printf(seq, "H: Handlers=");
list_for_each_entry(handle, &dev->h_list, d_node)
@@ -753,6 +851,13 @@ static struct attribute_group input_dev_caps_attr_group = {
.attrs = input_dev_caps_attrs,
};
+static struct attribute_group *input_dev_attr_groups[] = {
+ &input_dev_attr_group,
+ &input_dev_id_attr_group,
+ &input_dev_caps_attr_group,
+ NULL
+};
+
static void input_dev_release(struct class_device *class_dev)
{
struct input_dev *dev = to_input_dev(class_dev);
@@ -906,6 +1011,7 @@ struct input_dev *input_allocate_device(void)
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
dev->cdev.class = &input_class;
+ dev->cdev.groups = input_dev_attr_groups;
class_device_initialize(&dev->cdev);
mutex_init(&dev->mutex);
INIT_LIST_HEAD(&dev->h_list);
@@ -934,23 +1040,71 @@ EXPORT_SYMBOL(input_allocate_device);
*/
void input_free_device(struct input_dev *dev)
{
- if (dev) {
-
- mutex_lock(&dev->mutex);
- dev->name = dev->phys = dev->uniq = NULL;
- mutex_unlock(&dev->mutex);
-
+ if (dev)
input_put_device(dev);
- }
}
EXPORT_SYMBOL(input_free_device);
+/**
+ * input_set_capability - mark device as capable of a certain event
+ * @dev: device that is capable of emitting or accepting event
+ * @type: type of the event (EV_KEY, EV_REL, etc...)
+ * @code: event code
+ *
+ * In addition to setting up corresponding bit in appropriate capability
+ * bitmap the function also adjusts dev->evbit.
+ */
+void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)
+{
+ switch (type) {
+ case EV_KEY:
+ __set_bit(code, dev->keybit);
+ break;
+
+ case EV_REL:
+ __set_bit(code, dev->relbit);
+ break;
+
+ case EV_ABS:
+ __set_bit(code, dev->absbit);
+ break;
+
+ case EV_MSC:
+ __set_bit(code, dev->mscbit);
+ break;
+
+ case EV_SW:
+ __set_bit(code, dev->swbit);
+ break;
+
+ case EV_LED:
+ __set_bit(code, dev->ledbit);
+ break;
+
+ case EV_SND:
+ __set_bit(code, dev->sndbit);
+ break;
+
+ case EV_FF:
+ __set_bit(code, dev->ffbit);
+ break;
+
+ default:
+ printk(KERN_ERR
+ "input_set_capability: unknown type %u (code %u)\n",
+ type, code);
+ dump_stack();
+ return;
+ }
+
+ __set_bit(type, dev->evbit);
+}
+EXPORT_SYMBOL(input_set_capability);
+
int input_register_device(struct input_dev *dev)
{
static atomic_t input_no = ATOMIC_INIT(0);
- struct input_handle *handle;
struct input_handler *handler;
- const struct input_device_id *id;
const char *path;
int error;
@@ -969,55 +1123,41 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33;
}
+ if (!dev->getkeycode)
+ dev->getkeycode = input_default_getkeycode;
+
+ if (!dev->setkeycode)
+ dev->setkeycode = input_default_setkeycode;
+
list_add_tail(&dev->node, &input_dev_list);
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
+ if (!dev->cdev.dev)
+ dev->cdev.dev = dev->dev.parent;
+
error = class_device_add(&dev->cdev);
if (error)
return error;
- error = sysfs_create_group(&dev->cdev.kobj, &input_dev_attr_group);
- if (error)
- goto fail1;
-
- error = sysfs_create_group(&dev->cdev.kobj, &input_dev_id_attr_group);
- if (error)
- goto fail2;
-
- error = sysfs_create_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
- if (error)
- goto fail3;
-
path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
kfree(path);
list_for_each_entry(handler, &input_handler_list, node)
- if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
- if ((id = input_match_device(handler->id_table, dev)))
- if ((handle = handler->connect(handler, dev, id))) {
- input_link_handle(handle);
- if (handler->start)
- handler->start(handle);
- }
+ input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
return 0;
-
- fail3: sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
- fail2: sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
- fail1: class_device_del(&dev->cdev);
- return error;
}
EXPORT_SYMBOL(input_register_device);
void input_unregister_device(struct input_dev *dev)
{
- struct list_head *node, *next;
+ struct input_handle *handle, *next;
int code;
for (code = 0; code <= KEY_MAX; code++)
@@ -1027,19 +1167,12 @@ void input_unregister_device(struct input_dev *dev)
del_timer_sync(&dev->timer);
- list_for_each_safe(node, next, &dev->h_list) {
- struct input_handle * handle = to_handle(node);
- list_del_init(&handle->d_node);
- list_del_init(&handle->h_node);
+ list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
handle->handler->disconnect(handle);
- }
+ WARN_ON(!list_empty(&dev->h_list));
list_del_init(&dev->node);
- sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
- sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
- sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
-
class_device_unregister(&dev->cdev);
input_wakeup_procfs_readers();
@@ -1049,8 +1182,6 @@ EXPORT_SYMBOL(input_unregister_device);
int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
- struct input_handle *handle;
- const struct input_device_id *id;
INIT_LIST_HEAD(&handler->h_list);
@@ -1064,13 +1195,7 @@ int input_register_handler(struct input_handler *handler)
list_add_tail(&handler->node, &input_handler_list);
list_for_each_entry(dev, &input_dev_list, node)
- if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
- if ((id = input_match_device(handler->id_table, dev)))
- if ((handle = handler->connect(handler, dev, id))) {
- input_link_handle(handle);
- if (handler->start)
- handler->start(handle);
- }
+ input_attach_handler(dev, handler);
input_wakeup_procfs_readers();
return 0;
@@ -1079,14 +1204,11 @@ EXPORT_SYMBOL(input_register_handler);
void input_unregister_handler(struct input_handler *handler)
{
- struct list_head *node, *next;
+ struct input_handle *handle, *next;
- list_for_each_safe(node, next, &handler->h_list) {
- struct input_handle * handle = to_handle_h(node);
- list_del_init(&handle->h_node);
- list_del_init(&handle->d_node);
+ list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
handler->disconnect(handle);
- }
+ WARN_ON(!list_empty(&handler->h_list));
list_del_init(&handler->node);
@@ -1097,6 +1219,27 @@ void input_unregister_handler(struct input_handler *handler)
}
EXPORT_SYMBOL(input_unregister_handler);
+int input_register_handle(struct input_handle *handle)
+{
+ struct input_handler *handler = handle->handler;
+
+ list_add_tail(&handle->d_node, &handle->dev->h_list);
+ list_add_tail(&handle->h_node, &handler->h_list);
+
+ if (handler->start)
+ handler->start(handle);
+
+ return 0;
+}
+EXPORT_SYMBOL(input_register_handle);
+
+void input_unregister_handle(struct input_handle *handle)
+{
+ list_del_init(&handle->h_node);
+ list_del_init(&handle->d_node);
+}
+EXPORT_SYMBOL(input_unregister_handle);
+
static int input_open_file(struct inode *inode, struct file *file)
{
struct input_handler *handler = input_table[iminor(inode) >> 5];
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 9f3529ad3fd..06f0541b24d 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
@@ -43,7 +42,7 @@ struct joydev {
char name[16];
struct input_handle handle;
wait_queue_head_t wait;
- struct list_head list;
+ struct list_head client_list;
struct js_corr corr[ABS_MAX + 1];
struct JS_DATA_SAVE_TYPE glue;
int nabs;
@@ -55,7 +54,7 @@ struct joydev {
__s16 abs[ABS_MAX + 1];
};
-struct joydev_list {
+struct joydev_client {
struct js_event buffer[JOYDEV_BUFFER_SIZE];
int head;
int tail;
@@ -87,7 +86,7 @@ static int joydev_correct(int value, struct js_corr *corr)
static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct joydev *joydev = handle->private;
- struct joydev_list *list;
+ struct joydev_client *client;
struct js_event event;
switch (type) {
@@ -115,15 +114,15 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
event.time = jiffies_to_msecs(jiffies);
- list_for_each_entry(list, &joydev->list, node) {
+ list_for_each_entry(client, &joydev->client_list, node) {
- memcpy(list->buffer + list->head, &event, sizeof(struct js_event));
+ memcpy(client->buffer + client->head, &event, sizeof(struct js_event));
- if (list->startup == joydev->nabs + joydev->nkey)
- if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
- list->startup = 0;
+ if (client->startup == joydev->nabs + joydev->nkey)
+ if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1)))
+ client->startup = 0;
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&joydev->wait);
@@ -132,9 +131,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
static int joydev_fasync(int fd, struct file *file, int on)
{
int retval;
- struct joydev_list *list = file->private_data;
+ struct joydev_client *client = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
+ retval = fasync_helper(fd, file, on, &client->fasync);
return retval < 0 ? retval : 0;
}
@@ -145,60 +144,73 @@ static void joydev_free(struct joydev *joydev)
kfree(joydev);
}
-static int joydev_release(struct inode * inode, struct file * file)
+static int joydev_release(struct inode *inode, struct file *file)
{
- struct joydev_list *list = file->private_data;
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
joydev_fasync(-1, file, 0);
- list_del(&list->node);
+ list_del(&client->node);
+ kfree(client);
- if (!--list->joydev->open) {
- if (list->joydev->exist)
- input_close_device(&list->joydev->handle);
+ if (!--joydev->open) {
+ if (joydev->exist)
+ input_close_device(&joydev->handle);
else
- joydev_free(list->joydev);
+ joydev_free(joydev);
}
- kfree(list);
return 0;
}
static int joydev_open(struct inode *inode, struct file *file)
{
- struct joydev_list *list;
+ struct joydev_client *client;
+ struct joydev *joydev;
int i = iminor(inode) - JOYDEV_MINOR_BASE;
+ int error;
+
+ if (i >= JOYDEV_MINORS)
+ return -ENODEV;
- if (i >= JOYDEV_MINORS || !joydev_table[i])
+ joydev = joydev_table[i];
+ if (!joydev || !joydev->exist)
return -ENODEV;
- if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL)))
+ client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL);
+ if (!client)
return -ENOMEM;
- list->joydev = joydev_table[i];
- list_add_tail(&list->node, &joydev_table[i]->list);
- file->private_data = list;
+ client->joydev = joydev;
+ list_add_tail(&client->node, &joydev->client_list);
- if (!list->joydev->open++)
- if (list->joydev->exist)
- input_open_device(&list->joydev->handle);
+ if (!joydev->open++ && joydev->exist) {
+ error = input_open_device(&joydev->handle);
+ if (error) {
+ list_del(&client->node);
+ kfree(client);
+ return error;
+ }
+ }
+ file->private_data = client;
return 0;
}
-static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
return -EINVAL;
}
static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
struct input_dev *input = joydev->handle.dev;
int retval = 0;
- if (!list->joydev->exist)
+ if (!joydev->exist)
return -ENODEV;
if (count < sizeof(struct js_event))
@@ -217,56 +229,55 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)))
return -EFAULT;
- list->startup = 0;
- list->tail = list->head;
+ client->startup = 0;
+ client->tail = client->head;
return sizeof(struct JS_DATA_TYPE);
}
- if (list->startup == joydev->nabs + joydev->nkey &&
- list->head == list->tail && (file->f_flags & O_NONBLOCK))
+ if (client->startup == joydev->nabs + joydev->nkey &&
+ client->head == client->tail && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
- retval = wait_event_interruptible(list->joydev->wait,
- !list->joydev->exist ||
- list->startup < joydev->nabs + joydev->nkey ||
- list->head != list->tail);
-
+ retval = wait_event_interruptible(joydev->wait,
+ !joydev->exist ||
+ client->startup < joydev->nabs + joydev->nkey ||
+ client->head != client->tail);
if (retval)
return retval;
- if (!list->joydev->exist)
+ if (!joydev->exist)
return -ENODEV;
- while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
+ while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) {
struct js_event event;
event.time = jiffies_to_msecs(jiffies);
- if (list->startup < joydev->nkey) {
+ if (client->startup < joydev->nkey) {
event.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- event.number = list->startup;
+ event.number = client->startup;
event.value = !!test_bit(joydev->keypam[event.number], input->key);
} else {
event.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- event.number = list->startup - joydev->nkey;
+ event.number = client->startup - joydev->nkey;
event.value = joydev->abs[event.number];
}
if (copy_to_user(buf + retval, &event, sizeof(struct js_event)))
return -EFAULT;
- list->startup++;
+ client->startup++;
retval += sizeof(struct js_event);
}
- while (list->head != list->tail && retval + sizeof(struct js_event) <= count) {
+ while (client->head != client->tail && retval + sizeof(struct js_event) <= count) {
- if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event)))
+ if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event)))
return -EFAULT;
- list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
+ client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1);
retval += sizeof(struct js_event);
}
@@ -276,11 +287,12 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
/* No kernel lock - fine */
static unsigned int joydev_poll(struct file *file, poll_table *wait)
{
- struct joydev_list *list = file->private_data;
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
- poll_wait(file, &list->joydev->wait, wait);
- return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
- (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
+ poll_wait(file, &joydev->wait, wait);
+ return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ?
+ (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR));
}
static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
@@ -374,8 +386,8 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
#ifdef CONFIG_COMPAT
static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
void __user *argp = (void __user *)arg;
s32 tmp32;
struct JS_DATA_SAVE_TYPE_32 ds32;
@@ -428,8 +440,8 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
+ struct joydev_client *client = file->private_data;
+ struct joydev *joydev = client->joydev;
void __user *argp = (void __user *)arg;
if (!joydev->exist)
@@ -465,23 +477,26 @@ static const struct file_operations joydev_fops = {
.fasync = joydev_fasync,
};
-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
+static int joydev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct joydev *joydev;
struct class_device *cdev;
+ dev_t devt;
int i, j, t, minor;
+ int error;
for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++);
if (minor == JOYDEV_MINORS) {
printk(KERN_ERR "joydev: no more free joydev devices\n");
- return NULL;
+ return -ENFILE;
}
- if (!(joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL)))
- return NULL;
+ joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL);
+ if (!joydev)
+ return -ENOMEM;
- INIT_LIST_HEAD(&joydev->list);
+ INIT_LIST_HEAD(&joydev->client_list);
init_waitqueue_head(&joydev->wait);
joydev->minor = minor;
@@ -534,31 +549,54 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct
joydev_table[minor] = joydev;
- cdev = class_device_create(&input_class, &dev->cdev,
- MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
- dev->cdev.dev, joydev->name);
+ devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
+
+ cdev = class_device_create(&input_class, &dev->cdev, devt,
+ dev->cdev.dev, joydev->name);
+ if (IS_ERR(cdev)) {
+ error = PTR_ERR(cdev);
+ goto err_free_joydev;
+ }
/* temporary symlink to keep userspace happy */
- sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
- joydev->name);
+ error = sysfs_create_link(&input_class.subsys.kobj,
+ &cdev->kobj, joydev->name);
+ if (error)
+ goto err_cdev_destroy;
+
+ error = input_register_handle(&joydev->handle);
+ if (error)
+ goto err_remove_link;
+
+ return 0;
- return &joydev->handle;
+ err_remove_link:
+ sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
+ err_cdev_destroy:
+ class_device_destroy(&input_class, devt);
+ err_free_joydev:
+ joydev_table[minor] = NULL;
+ kfree(joydev);
+ return error;
}
+
static void joydev_disconnect(struct input_handle *handle)
{
struct joydev *joydev = handle->private;
- struct joydev_list *list;
+ struct joydev_client *client;
+
+ input_unregister_handle(handle);
- sysfs_remove_link(&input_class.subsys.kset.kobj, joydev->name);
+ sysfs_remove_link(&input_class.subsys.kobj, joydev->name);
class_device_destroy(&input_class, MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + joydev->minor));
joydev->exist = 0;
if (joydev->open) {
input_close_device(handle);
wake_up_interruptible(&joydev->wait);
- list_for_each_entry(list, &joydev->list, node)
- kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+ list_for_each_entry(client, &joydev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
} else
joydev_free(joydev);
}
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 271263443c3..82f563e24fd 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -2,7 +2,7 @@
# Joystick driver configuration
#
menuconfig INPUT_JOYSTICK
- bool "Joysticks"
+ bool "Joysticks/Gamepads"
help
If you have a joystick, 6dof controller, gamepad, steering wheel,
weapon control system or something like that you can say Y here
@@ -196,7 +196,7 @@ config JOYSTICK_TWIDJOY
config JOYSTICK_DB9
tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads"
depends on PARPORT
- ---help---
+ help
Say Y here if you have a Sega Master System gamepad, Sega Genesis
gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
Commodore, Amstrad CPC joystick connected to your parallel port.
@@ -253,4 +253,18 @@ config JOYSTICK_JOYDUMP
To compile this driver as a module, choose M here: the
module will be called joydump.
+config JOYSTICK_XPAD
+ tristate "X-Box gamepad support"
+ select USB
+ help
+ Say Y here if you want to use the X-Box pad with your computer.
+ Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
+ and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
+
+ For information about how to connect the X-Box pad to USB, see
+ <file:Documentation/input/xpad.txt>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called xpad.
+
endif
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
index 5231f6ff75b..e855abb0cc5 100644
--- a/drivers/input/joystick/Makefile
+++ b/drivers/input/joystick/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o
obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o
obj-$(CONFIG_JOYSTICK_TWIDJOY) += twidjoy.o
obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
+obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
obj-$(CONFIG_JOYSTICK_IFORCE) += iforce/
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index b11a4bbc84c..ff701ab10d7 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -241,7 +241,7 @@ static void a3d_adc_close(struct gameport *gameport)
static int a3d_open(struct input_dev *dev)
{
- struct a3d *a3d = dev->private;
+ struct a3d *a3d = input_get_drvdata(dev);
gameport_start_polling(a3d->gameport);
return 0;
@@ -253,7 +253,7 @@ static int a3d_open(struct input_dev *dev)
static void a3d_close(struct input_dev *dev)
{
- struct a3d *a3d = dev->private;
+ struct a3d *a3d = input_get_drvdata(dev);
gameport_stop_polling(a3d->gameport);
}
@@ -314,11 +314,12 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ;
input_dev->id.product = a3d->mode;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &gameport->dev;
- input_dev->private = a3d;
+ input_dev->dev.parent = &gameport->dev;
input_dev->open = a3d_open;
input_dev->close = a3d_close;
+ input_set_drvdata(input_dev, a3d);
+
if (a3d->mode == A3D_MODE_PXL) {
int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 6279ced8a35..28140c4a110 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -290,7 +290,7 @@ static void adi_poll(struct gameport *gameport)
static int adi_open(struct input_dev *dev)
{
- struct adi_port *port = dev->private;
+ struct adi_port *port = input_get_drvdata(dev);
gameport_start_polling(port->gameport);
return 0;
@@ -302,7 +302,7 @@ static int adi_open(struct input_dev *dev)
static void adi_close(struct input_dev *dev)
{
- struct adi_port *port = dev->private;
+ struct adi_port *port = input_get_drvdata(dev);
gameport_stop_polling(port->gameport);
}
@@ -424,8 +424,9 @@ static int adi_init_input(struct adi *adi, struct adi_port *port, int half)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
input_dev->id.product = adi->id;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &port->gameport->dev;
- input_dev->private = port;
+ input_dev->dev.parent = &port->gameport->dev;
+
+ input_set_drvdata(input_dev, port);
input_dev->open = adi_open;
input_dev->close = adi_close;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 51f1e4bfff3..bdd157c1ebf 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -53,7 +53,7 @@ MODULE_LICENSE("GPL");
#define ANALOG_PORTS 16
static char *js[ANALOG_PORTS];
-static int js_nargs;
+static unsigned int js_nargs;
static int analog_options[ANALOG_PORTS];
module_param_array_named(map, js, charp, &js_nargs, 0);
MODULE_PARM_DESC(map, "Describes analog joysticks type/capabilities");
@@ -343,7 +343,7 @@ static void analog_poll(struct gameport *gameport)
static int analog_open(struct input_dev *dev)
{
- struct analog_port *port = dev->private;
+ struct analog_port *port = input_get_drvdata(dev);
gameport_start_polling(port->gameport);
return 0;
@@ -355,7 +355,7 @@ static int analog_open(struct input_dev *dev)
static void analog_close(struct input_dev *dev)
{
- struct analog_port *port = dev->private;
+ struct analog_port *port = input_get_drvdata(dev);
gameport_stop_polling(port->gameport);
}
@@ -449,10 +449,13 @@ static int analog_init_device(struct analog_port *port, struct analog *analog, i
input_dev->id.vendor = GAMEPORT_ID_VENDOR_ANALOG;
input_dev->id.product = analog->mask >> 4;
input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &port->gameport->dev;
+
+ input_set_drvdata(input_dev, port);
input_dev->open = analog_open;
input_dev->close = analog_close;
- input_dev->private = port;
+
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = j = 0; i < 4; i++)
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 034ec39c251..d3352a849b8 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -142,7 +142,7 @@ static void cobra_poll(struct gameport *gameport)
static int cobra_open(struct input_dev *dev)
{
- struct cobra *cobra = dev->private;
+ struct cobra *cobra = input_get_drvdata(dev);
gameport_start_polling(cobra->gameport);
return 0;
@@ -150,7 +150,7 @@ static int cobra_open(struct input_dev *dev)
static void cobra_close(struct input_dev *dev)
{
- struct cobra *cobra = dev->private;
+ struct cobra *cobra = input_get_drvdata(dev);
gameport_stop_polling(cobra->gameport);
}
@@ -211,8 +211,9 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE;
input_dev->id.product = 0x0008;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &gameport->dev;
- input_dev->private = cobra;
+ input_dev->dev.parent = &gameport->dev;
+
+ input_set_drvdata(input_dev, cobra);
input_dev->open = cobra_open;
input_dev->close = cobra_close;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index b41bd2eb37d..86ad1027e12 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -46,17 +46,17 @@ MODULE_LICENSE("GPL");
struct db9_config {
int args[2];
- int nargs;
+ unsigned int nargs;
};
#define DB9_MAX_PORTS 3
-static struct db9_config db9[DB9_MAX_PORTS] __initdata;
+static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata;
-module_param_array_named(dev, db9[0].args, int, &db9[0].nargs, 0);
+module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0);
MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
-module_param_array_named(dev2, db9[1].args, int, &db9[0].nargs, 0);
+module_param_array_named(dev2, db9_cfg[1].args, int, &db9_cfg[0].nargs, 0);
MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
-module_param_array_named(dev3, db9[2].args, int, &db9[2].nargs, 0);
+module_param_array_named(dev3, db9_cfg[2].args, int, &db9_cfg[2].nargs, 0);
MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
#define DB9_ARG_PARPORT 0
@@ -518,7 +518,7 @@ static void db9_timer(unsigned long private)
static int db9_open(struct input_dev *dev)
{
- struct db9 *db9 = dev->private;
+ struct db9 *db9 = input_get_drvdata(dev);
struct parport *port = db9->pd->port;
int err;
@@ -542,7 +542,7 @@ static int db9_open(struct input_dev *dev)
static void db9_close(struct input_dev *dev)
{
- struct db9 *db9 = dev->private;
+ struct db9 *db9 = input_get_drvdata(dev);
struct parport *port = db9->pd->port;
mutex_lock(&db9->mutex);
@@ -625,7 +625,8 @@ static struct db9 __init *db9_probe(int parport, int mode)
input_dev->id.vendor = 0x0002;
input_dev->id.product = mode;
input_dev->id.version = 0x0100;
- input_dev->private = db9;
+
+ input_set_drvdata(input_dev, db9);
input_dev->open = db9_open;
input_dev->close = db9_close;
@@ -679,17 +680,17 @@ static int __init db9_init(void)
int err = 0;
for (i = 0; i < DB9_MAX_PORTS; i++) {
- if (db9[i].nargs == 0 || db9[i].args[DB9_ARG_PARPORT] < 0)
+ if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0)
continue;
- if (db9[i].nargs < 2) {
+ if (db9_cfg[i].nargs < 2) {
printk(KERN_ERR "db9.c: Device type must be specified.\n");
err = -EINVAL;
break;
}
- db9_base[i] = db9_probe(db9[i].args[DB9_ARG_PARPORT],
- db9[i].args[DB9_ARG_MODE]);
+ db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT],
+ db9_cfg[i].args[DB9_ARG_MODE]);
if (IS_ERR(db9_base[i])) {
err = PTR_ERR(db9_base[i]);
break;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 711e4b3e9e6..1a452e0e5f2 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -48,16 +48,16 @@ MODULE_LICENSE("GPL");
struct gc_config {
int args[GC_MAX_DEVICES + 1];
- int nargs;
+ unsigned int nargs;
};
-static struct gc_config gc[GC_MAX_PORTS] __initdata;
+static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata;
-module_param_array_named(map, gc[0].args, int, &gc[0].nargs, 0);
+module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0);
MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)");
-module_param_array_named(map2, gc[1].args, int, &gc[1].nargs, 0);
+module_param_array_named(map2, gc_cfg[1].args, int, &gc_cfg[1].nargs, 0);
MODULE_PARM_DESC(map2, "Describes second set of devices");
-module_param_array_named(map3, gc[2].args, int, &gc[2].nargs, 0);
+module_param_array_named(map3, gc_cfg[2].args, int, &gc_cfg[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
/* see also gs_psx_delay parameter in PSX support section */
@@ -591,7 +591,7 @@ static void gc_timer(unsigned long private)
static int gc_open(struct input_dev *dev)
{
- struct gc *gc = dev->private;
+ struct gc *gc = input_get_drvdata(dev);
int err;
err = mutex_lock_interruptible(&gc->mutex);
@@ -610,7 +610,7 @@ static int gc_open(struct input_dev *dev)
static void gc_close(struct input_dev *dev)
{
- struct gc *gc = dev->private;
+ struct gc *gc = input_get_drvdata(dev);
mutex_lock(&gc->mutex);
if (!--gc->used) {
@@ -646,7 +646,8 @@ static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type)
input_dev->id.vendor = 0x0001;
input_dev->id.product = pad_type;
input_dev->id.version = 0x0100;
- input_dev->private = gc;
+
+ input_set_drvdata(input_dev, gc);
input_dev->open = gc_open;
input_dev->close = gc_close;
@@ -809,16 +810,17 @@ static int __init gc_init(void)
int err = 0;
for (i = 0; i < GC_MAX_PORTS; i++) {
- if (gc[i].nargs == 0 || gc[i].args[0] < 0)
+ if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0)
continue;
- if (gc[i].nargs < 2) {
+ if (gc_cfg[i].nargs < 2) {
printk(KERN_ERR "gamecon.c: at least one device must be specified\n");
err = -EINVAL;
break;
}
- gc_base[i] = gc_probe(gc[i].args[0], gc[i].args + 1, gc[i].nargs - 1);
+ gc_base[i] = gc_probe(gc_cfg[i].args[0],
+ gc_cfg[i].args + 1, gc_cfg[i].nargs - 1);
if (IS_ERR(gc_base[i])) {
err = PTR_ERR(gc_base[i]);
break;
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index bacbab5d1b6..d514aebf755 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -220,7 +220,7 @@ static void gf2k_poll(struct gameport *gameport)
static int gf2k_open(struct input_dev *dev)
{
- struct gf2k *gf2k = dev->private;
+ struct gf2k *gf2k = input_get_drvdata(dev);
gameport_start_polling(gf2k->gameport);
return 0;
@@ -228,7 +228,7 @@ static int gf2k_open(struct input_dev *dev)
static void gf2k_close(struct input_dev *dev)
{
- struct gf2k *gf2k = dev->private;
+ struct gf2k *gf2k = input_get_drvdata(dev);
gameport_stop_polling(gf2k->gameport);
}
@@ -308,11 +308,13 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS;
input_dev->id.product = gf2k->id;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &gameport->dev;
- input_dev->private = gf2k;
+ input_dev->dev.parent = &gameport->dev;
+
+ input_set_drvdata(input_dev, gf2k);
input_dev->open = gf2k_open;
input_dev->close = gf2k_close;
+
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
for (i = 0; i < gf2k_axes[gf2k->id]; i++)
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 17a90c436de..73eb5ab6f14 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -285,7 +285,7 @@ static void grip_poll(struct gameport *gameport)
static int grip_open(struct input_dev *dev)
{
- struct grip *grip = dev->private;
+ struct grip *grip = input_get_drvdata(dev);
gameport_start_polling(grip->gameport);
return 0;
@@ -293,7 +293,7 @@ static int grip_open(struct input_dev *dev)
static void grip_close(struct input_dev *dev)
{
- struct grip *grip = dev->private;
+ struct grip *grip = input_get_drvdata(dev);
gameport_stop_polling(grip->gameport);
}
@@ -363,8 +363,9 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
input_dev->id.product = grip->mode[i];
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &gameport->dev;
- input_dev->private = grip;
+ input_dev->dev.parent = &gameport->dev;
+
+ input_set_drvdata(input_dev, grip);
input_dev->open = grip_open;
input_dev->close = grip_close;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 8120a9c4077..555319e6378 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -562,7 +562,7 @@ static void grip_poll(struct gameport *gameport)
static int grip_open(struct input_dev *dev)
{
- struct grip_mp *grip = dev->private;
+ struct grip_mp *grip = input_get_drvdata(dev);
gameport_start_polling(grip->gameport);
return 0;
@@ -574,9 +574,9 @@ static int grip_open(struct input_dev *dev)
static void grip_close(struct input_dev *dev)
{
- struct grip_mp *grip = dev->private;
+ struct grip_mp *grip = input_get_drvdata(dev);
- gameport_start_polling(grip->gameport);
+ gameport_stop_polling(grip->gameport);
}
/*
@@ -599,8 +599,9 @@ static int register_slot(int slot, struct grip_mp *grip)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS;
input_dev->id.product = 0x0100 + port->mode;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &grip->gameport->dev;
- input_dev->private = grip;
+ input_dev->dev.parent = &grip->gameport->dev;
+
+ input_set_drvdata(input_dev, grip);
input_dev->open = grip_open;
input_dev->close = grip_close;
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index dbc5d92858b..d4e8073caf2 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -156,7 +156,7 @@ static void guillemot_poll(struct gameport *gameport)
static int guillemot_open(struct input_dev *dev)
{
- struct guillemot *guillemot = dev->private;
+ struct guillemot *guillemot = input_get_drvdata(dev);
gameport_start_polling(guillemot->gameport);
return 0;
@@ -168,7 +168,7 @@ static int guillemot_open(struct input_dev *dev)
static void guillemot_close(struct input_dev *dev)
{
- struct guillemot *guillemot = dev->private;
+ struct guillemot *guillemot = input_get_drvdata(dev);
gameport_stop_polling(guillemot->gameport);
}
@@ -231,8 +231,9 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT;
input_dev->id.product = guillemot_type[i].id;
input_dev->id.version = (int)data[14] << 8 | data[15];
- input_dev->cdev.dev = &gameport->dev;
- input_dev->private = guillemot;
+ input_dev->dev.parent = &gameport->dev;
+
+ input_set_drvdata(input_dev, guillemot);
input_dev->open = guillemot_open;
input_dev->close = guillemot_close;
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 8fb0c19cc60..f2a4381d0ab 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -2,7 +2,7 @@
* $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
@@ -205,7 +205,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
int i;
if (new->type != FF_SPRING && new->type != FF_FRICTION) {
- printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
+ warn("bad effect type in need_condition_modifier");
return 0;
}
@@ -227,7 +227,7 @@ static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
{
if (effect->type != FF_CONSTANT) {
- printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+ warn("bad effect type in need_envelope_modifier");
return 0;
}
@@ -258,7 +258,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
break;
default:
- printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
+ warn("bad effect type in need_envelope_modifier");
}
return 0;
@@ -271,7 +271,7 @@ static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effec
static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
{
if (new->type != FF_PERIODIC) {
- printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n");
+ warn("bad effect type in need_period_modifier");
return 0;
}
return (old->u.periodic.period != new->u.periodic.period
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 3393a37fec3..fb129c479a6 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -2,7 +2,7 @@
* $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
@@ -29,7 +29,7 @@
#include "iforce.h"
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
MODULE_LICENSE("GPL");
@@ -220,7 +220,7 @@ static void iforce_release(struct input_dev *dev)
/* Check: no effects should be present in memory */
for (i = 0; i < dev->ff->max_effects; i++) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
- printk(KERN_WARNING "iforce_release: Device still owns effects\n");
+ warn("iforce_release: Device still owns effects");
break;
}
}
@@ -232,7 +232,7 @@ static void iforce_release(struct input_dev *dev)
switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
case IFORCE_USB:
- usb_unlink_urb(iforce->irq);
+ usb_kill_urb(iforce->irq);
/* The device was unplugged before the file
* was released */
@@ -287,13 +287,13 @@ int iforce_init_device(struct iforce *iforce)
#ifdef CONFIG_JOYSTICK_IFORCE_USB
case IFORCE_USB:
input_dev->id.bustype = BUS_USB;
- input_dev->cdev.dev = &iforce->usbdev->dev;
+ input_dev->dev.parent = &iforce->usbdev->dev;
break;
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_232
case IFORCE_232:
input_dev->id.bustype = BUS_RS232;
- input_dev->cdev.dev = &iforce->serio->dev;
+ input_dev->dev.parent = &iforce->serio->dev;
break;
#endif
}
@@ -324,7 +324,7 @@ int iforce_init_device(struct iforce *iforce)
break;
if (i == 20) { /* 5 seconds */
- printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n");
+ err("Timeout waiting for response from device.");
error = -ENODEV;
goto fail;
}
@@ -336,26 +336,26 @@ int iforce_init_device(struct iforce *iforce)
if (!iforce_get_id_packet(iforce, "M"))
input_dev->id.vendor = (iforce->edata[2] << 8) | iforce->edata[1];
else
- printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n");
+ warn("Device does not respond to id packet M");
if (!iforce_get_id_packet(iforce, "P"))
input_dev->id.product = (iforce->edata[2] << 8) | iforce->edata[1];
else
- printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n");
+ warn("Device does not respond to id packet P");
if (!iforce_get_id_packet(iforce, "B"))
iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
else
- printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
+ warn("Device does not respond to id packet B");
if (!iforce_get_id_packet(iforce, "N"))
ff_effects = iforce->edata[1];
else
- printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
+ warn("Device does not respond to id packet N");
/* Check if the device can store more effects than the driver can really handle */
if (ff_effects > IFORCE_EFFECTS_MAX) {
- printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
+ warn("Limiting number of effects to %d (device reports %d)",
IFORCE_EFFECTS_MAX, ff_effects);
ff_effects = IFORCE_EFFECTS_MAX;
}
@@ -457,8 +457,6 @@ int iforce_init_device(struct iforce *iforce)
if (error)
goto fail;
- printk(KERN_DEBUG "iforce->dev->open = %p\n", iforce->dev->open);
-
return 0;
fail: input_free_device(input_dev);
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 808f05932a6..21c4e13d3a5 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -2,7 +2,7 @@
* $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
@@ -39,10 +39,10 @@ void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data)
{
int i;
- printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
+ printk(KERN_DEBUG __FILE__ ": %s cmd = %04x, data = ", msg, cmd);
for (i = 0; i < LO(cmd); i++)
printk("%02x ", data[i]);
- printk(")\n");
+ printk("\n");
}
/*
@@ -65,8 +65,9 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
head = iforce->xmit.head;
tail = iforce->xmit.tail;
+
if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
- printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n");
+ warn("not enough space in xmit buffer to send new packet");
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
return -1;
}
@@ -126,8 +127,6 @@ int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value)
{
unsigned char data[3];
-printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value);
-
data[0] = LO(id);
data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
data[2] = LO(value);
@@ -151,7 +150,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
return 0;
}
}
- printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr);
+ warn("unused effect %04x updated !!!", addr);
return -1;
}
@@ -162,7 +161,7 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
static int being_used = 0;
if (being_used)
- printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used);
+ warn("re-entrant call to iforce_process %d", being_used);
being_used++;
#ifdef CONFIG_JOYSTICK_IFORCE_232
@@ -266,7 +265,7 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
return -1;
}
#else
- printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n");
+ err("iforce_get_id_packet: iforce->bus = USB!");
#endif
break;
@@ -284,13 +283,12 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
return -1;
}
#else
- printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n");
+ err("iforce_get_id_packet: iforce->bus = SERIO!");
#endif
break;
default:
- printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n",
- iforce->bus);
+ err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
break;
}
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
index ec4be535f48..7b4bc19cef2 100644
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -2,7 +2,7 @@
* $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $
*
* Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
+ * Copyright (c) 2001, 2007 Johann Deneux <johann.deneux@gmail.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 80cdebcbcb9..750099d8e3c 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -2,7 +2,7 @@
* $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
@@ -65,7 +65,7 @@ void iforce_usb_xmit(struct iforce *iforce)
XMIT_INC(iforce->xmit.tail, n);
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
- printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n);
+ warn("usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -110,7 +110,7 @@ static void iforce_usb_out(struct urb *urb)
struct iforce *iforce = urb->context;
if (urb->status) {
- printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status);
+ dbg("urb->status %d, exiting", urb->status);
return;
}
@@ -190,10 +190,9 @@ fail:
/* Called by iforce_delete() */
void iforce_usb_delete(struct iforce* iforce)
{
- usb_unlink_urb(iforce->irq);
-/* Is it ok to unlink those ? */
- usb_unlink_urb(iforce->out);
- usb_unlink_urb(iforce->ctrl);
+ usb_kill_urb(iforce->irq);
+ usb_kill_urb(iforce->out);
+ usb_kill_urb(iforce->ctrl);
usb_free_urb(iforce->irq);
usb_free_urb(iforce->out);
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index ffaeaefa1a4..40a853ac21c 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -2,7 +2,7 @@
* $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $
*
* Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com>
+ * Copyright (c) 2001-2002, 2007 Johann Deneux <johann.deneux@gmail.com>
*
* USB/RS232 I-Force joysticks and wheels.
*/
@@ -124,7 +124,7 @@ struct iforce {
/* Buffer used for asynchronous sending of bytes to the device */
struct circ_buf xmit;
unsigned char xmit_data[XMIT_SIZE];
- long xmit_flags[1];
+ unsigned long xmit_flags[1];
/* Force Feedback */
wait_queue_head_t wait;
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index fec8b3d0967..1aec1e9d7c5 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -185,7 +185,7 @@ static void interact_poll(struct gameport *gameport)
static int interact_open(struct input_dev *dev)
{
- struct interact *interact = dev->private;
+ struct interact *interact = input_get_drvdata(dev);
gameport_start_polling(interact->gameport);
return 0;
@@ -197,7 +197,7 @@ static int interact_open(struct input_dev *dev)
static void interact_close(struct input_dev *dev)
{
- struct interact *interact = dev->private;
+ struct interact *interact = input_get_drvdata(dev);
gameport_stop_polling(interact->gameport);
}
@@ -262,7 +262,9 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT;
input_dev->id.product = interact_type[i].id;
input_dev->id.version = 0x0100;
- input_dev->private = interact;
+ input_dev->dev.parent = &gameport->dev;
+
+ input_set_drvdata(input_dev, interact);
input_dev->open = interact_open;
input_dev->close = interact_close;
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 4112789f119..b35604ee43a 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -168,8 +168,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_MAGELLAN;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = magellan;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index e58b22c018e..2adf73f63c9 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -509,7 +509,7 @@ static void sw_poll(struct gameport *gameport)
static int sw_open(struct input_dev *dev)
{
- struct sw *sw = dev->private;
+ struct sw *sw = input_get_drvdata(dev);
gameport_start_polling(sw->gameport);
return 0;
@@ -517,7 +517,7 @@ static int sw_open(struct input_dev *dev)
static void sw_close(struct input_dev *dev)
{
- struct sw *sw = dev->private;
+ struct sw *sw = input_get_drvdata(dev);
gameport_stop_polling(sw->gameport);
}
@@ -751,8 +751,9 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT;
input_dev->id.product = sw->type;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &gameport->dev;
- input_dev->private = sw;
+ input_dev->dev.parent = &gameport->dev;
+
+ input_set_drvdata(input_dev, sw);
input_dev->open = sw_open;
input_dev->close = sw_close;
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index 08bf113e62e..abb7c4cf54a 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -226,8 +226,7 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_SPACEBALL;
input_dev->id.product = id;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = spaceball;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index c9c79211af7..c4937f1e837 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -183,8 +183,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_SPACEORB;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = spaceorb;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index ecb0916215f..8581ee991d4 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -154,8 +154,7 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_STINGER;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = stinger;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) |
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index bb23ed2a04a..3b36ee04f72 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -265,7 +265,7 @@ static void tmdc_poll(struct gameport *gameport)
static int tmdc_open(struct input_dev *dev)
{
- struct tmdc *tmdc = dev->private;
+ struct tmdc *tmdc = input_get_drvdata(dev);
gameport_start_polling(tmdc->gameport);
return 0;
@@ -273,7 +273,7 @@ static int tmdc_open(struct input_dev *dev)
static void tmdc_close(struct input_dev *dev)
{
- struct tmdc *tmdc = dev->private;
+ struct tmdc *tmdc = input_get_drvdata(dev);
gameport_stop_polling(tmdc->gameport);
}
@@ -326,8 +326,9 @@ static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data)
input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
input_dev->id.product = model->id;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &tmdc->gameport->dev;
- input_dev->private = tmdc;
+ input_dev->dev.parent = &tmdc->gameport->dev;
+
+ input_set_drvdata(input_dev, tmdc);
input_dev->open = tmdc_open;
input_dev->close = tmdc_close;
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 037d3487fcc..8381c6f1437 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -48,16 +48,16 @@ MODULE_LICENSE("GPL");
struct tgfx_config {
int args[TGFX_MAX_DEVICES + 1];
- int nargs;
+ unsigned int nargs;
};
-static struct tgfx_config tgfx[TGFX_MAX_PORTS] __initdata;
+static struct tgfx_config tgfx_cfg[TGFX_MAX_PORTS] __initdata;
-module_param_array_named(map, tgfx[0].args, int, &tgfx[0].nargs, 0);
+module_param_array_named(map, tgfx_cfg[0].args, int, &tgfx_cfg[0].nargs, 0);
MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<js1>,<js2>,..<js7>");
-module_param_array_named(map2, tgfx[1].args, int, &tgfx[1].nargs, 0);
+module_param_array_named(map2, tgfx_cfg[1].args, int, &tgfx_cfg[1].nargs, 0);
MODULE_PARM_DESC(map2, "Describes second set of devices");
-module_param_array_named(map3, tgfx[2].args, int, &tgfx[2].nargs, 0);
+module_param_array_named(map3, tgfx_cfg[2].args, int, &tgfx_cfg[2].nargs, 0);
MODULE_PARM_DESC(map3, "Describes third set of devices");
#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
@@ -122,7 +122,7 @@ static void tgfx_timer(unsigned long private)
static int tgfx_open(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
+ struct tgfx *tgfx = input_get_drvdata(dev);
int err;
err = mutex_lock_interruptible(&tgfx->sem);
@@ -141,7 +141,7 @@ static int tgfx_open(struct input_dev *dev)
static void tgfx_close(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
+ struct tgfx *tgfx = input_get_drvdata(dev);
mutex_lock(&tgfx->sem);
if (!--tgfx->used) {
@@ -224,7 +224,8 @@ static struct tgfx __init *tgfx_probe(int parport, int *n_buttons, int n_devs)
input_dev->id.product = n_buttons[i];
input_dev->id.version = 0x0100;
- input_dev->private = tgfx;
+ input_set_drvdata(input_dev, tgfx);
+
input_dev->open = tgfx_open;
input_dev->close = tgfx_close;
@@ -282,16 +283,18 @@ static int __init tgfx_init(void)
int err = 0;
for (i = 0; i < TGFX_MAX_PORTS; i++) {
- if (tgfx[i].nargs == 0 || tgfx[i].args[0] < 0)
+ if (tgfx_cfg[i].nargs == 0 || tgfx_cfg[i].args[0] < 0)
continue;
- if (tgfx[i].nargs < 2) {
+ if (tgfx_cfg[i].nargs < 2) {
printk(KERN_ERR "turbografx.c: at least one joystick must be specified\n");
err = -EINVAL;
break;
}
- tgfx_base[i] = tgfx_probe(tgfx[i].args[0], tgfx[i].args + 1, tgfx[i].nargs - 1);
+ tgfx_base[i] = tgfx_probe(tgfx_cfg[i].args[0],
+ tgfx_cfg[i].args + 1,
+ tgfx_cfg[i].nargs - 1);
if (IS_ERR(tgfx_base[i])) {
err = PTR_ERR(tgfx_base[i]);
break;
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 9cf17d6ced8..c91504ec38e 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -205,11 +205,9 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_TWIDJOY;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = twidjoy;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
input_set_abs_params(input_dev, ABS_X, -50, 50, 4, 4);
input_set_abs_params(input_dev, ABS_Y, -50, 50, 4, 4);
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index 29d339acf43..4e85f72eefd 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -160,8 +160,7 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_WARRIOR;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = warrior;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
diff --git a/drivers/usb/input/xpad.c b/drivers/input/joystick/xpad.c
index e4bc76ebc83..8c8cd95a698 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -74,7 +74,6 @@
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/smp_lock.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.0.6"
@@ -267,7 +266,7 @@ exit:
static int xpad_open (struct input_dev *dev)
{
- struct usb_xpad *xpad = dev->private;
+ struct usb_xpad *xpad = input_get_drvdata(dev);
xpad->irq_in->dev = xpad->udev;
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
@@ -278,7 +277,7 @@ static int xpad_open (struct input_dev *dev)
static void xpad_close (struct input_dev *dev)
{
- struct usb_xpad *xpad = dev->private;
+ struct usb_xpad *xpad = input_get_drvdata(dev);
usb_kill_urb(xpad->irq_in);
}
@@ -312,6 +311,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct input_dev *input_dev;
struct usb_endpoint_descriptor *ep_irq_in;
int i;
+ int error = -ENOMEM;
for (i = 0; xpad_device[i].idVendor; i++) {
if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
@@ -344,8 +344,10 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->name = xpad_device[i].name;
input_dev->phys = xpad->phys;
usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = xpad;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, xpad);
+
input_dev->open = xpad_open;
input_dev->close = xpad_close;
@@ -373,15 +375,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->irq_in->transfer_dma = xpad->idata_dma;
xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_register_device(xpad->dev);
+ error = input_register_device(xpad->dev);
+ if (error)
+ goto fail3;
usb_set_intfdata(intf, xpad);
return 0;
-fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
-fail1: input_free_device(input_dev);
+ fail3: usb_free_urb(xpad->irq_in);
+ fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+ fail1: input_free_device(input_dev);
kfree(xpad);
- return -ENOMEM;
+ return error;
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f17e9c7d4b3..bd707b86c11 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -164,6 +164,17 @@ config KEYBOARD_AMIGA
To compile this driver as a module, choose M here: the
module will be called amikbd.
+config KEYBOARD_ATARI
+ tristate "Atari keyboard"
+ depends on ATARI
+ select ATARI_KBD_CORE
+ help
+ Say Y here if you are running Linux on any Atari and have a keyboard
+ attached.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atakbd.
+
config KEYBOARD_HIL_OLD
tristate "HP HIL keyboard support (simple driver)"
depends on GSC || HP300
@@ -203,9 +214,19 @@ config KEYBOARD_OMAP
To compile this driver as a module, choose M here: the
module will be called omap-keypad.
+config KEYBOARD_PXA27x
+ tristate "PXA27x keyboard support"
+ depends on PXA27x
+ help
+ Enable support for PXA27x matrix keyboard controller
+
+ To compile this driver as a module, choose M here: the
+ module will be called pxa27x_keyboard.
+
config KEYBOARD_AAED2000
tristate "AAED-2000 keyboard"
depends on MACH_AAED2000
+ select INPUT_POLLDEV
default y
help
Say Y here to enable the keyboard on the Agilent AAED-2000
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 586a0fe53be..28d211b87b1 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
+obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
@@ -17,6 +18,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
+obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
diff --git a/drivers/input/keyboard/aaed2000_kbd.c b/drivers/input/keyboard/aaed2000_kbd.c
index 65fcb6af63a..63d6ead6b87 100644
--- a/drivers/input/keyboard/aaed2000_kbd.c
+++ b/drivers/input/keyboard/aaed2000_kbd.c
@@ -14,12 +14,11 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/init.h>
-#include <linux/input.h>
+#include <linux/input-polldev.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <asm/arch/hardware.h>
#include <asm/arch/aaed2000.h>
@@ -46,8 +45,7 @@ static unsigned char aaedkbd_keycode[NR_SCANCODES] = {
struct aaedkbd {
unsigned char keycode[ARRAY_SIZE(aaedkbd_keycode)];
- struct input_dev *input;
- struct work_struct workq;
+ struct input_polled_dev *poll_dev;
int kbdscan_state[KB_COLS];
int kbdscan_count[KB_COLS];
};
@@ -64,14 +62,15 @@ static void aaedkbd_report_col(struct aaedkbd *aaedkbd,
scancode = SCANCODE(row, col);
pressed = rowd & KB_ROWMASK(row);
- input_report_key(aaedkbd->input, aaedkbd->keycode[scancode], pressed);
+ input_report_key(aaedkbd->poll_dev->input,
+ aaedkbd->keycode[scancode], pressed);
}
}
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void aaedkbd_work(void *data)
+static void aaedkbd_poll(struct input_polled_dev *dev)
{
- struct aaedkbd *aaedkbd = data;
+ struct aaedkbd *aaedkbd = dev->private;
unsigned int col, rowd;
col = 0;
@@ -90,59 +89,41 @@ static void aaedkbd_work(void *data)
} while (col < KB_COLS);
AAEC_GPIO_KSCAN = 0x07;
- input_sync(aaedkbd->input);
-
- schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
-}
-
-static int aaedkbd_open(struct input_dev *indev)
-{
- struct aaedkbd *aaedkbd = indev->private;
-
- schedule_delayed_work(&aaedkbd->workq, msecs_to_jiffies(SCAN_INTERVAL));
-
- return 0;
-}
-
-static void aaedkbd_close(struct input_dev *indev)
-{
- struct aaedkbd *aaedkbd = indev->private;
-
- cancel_delayed_work(&aaedkbd->workq);
- flush_scheduled_work();
+ input_sync(dev->input);
}
static int __devinit aaedkbd_probe(struct platform_device *pdev)
{
struct aaedkbd *aaedkbd;
+ struct input_polled_dev *poll_dev;
struct input_dev *input_dev;
int i;
int error;
aaedkbd = kzalloc(sizeof(struct aaedkbd), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!aaedkbd || !input_dev) {
+ poll_dev = input_allocate_polled_device();
+ if (!aaedkbd || !poll_dev) {
error = -ENOMEM;
goto fail;
}
platform_set_drvdata(pdev, aaedkbd);
- aaedkbd->input = input_dev;
-
- /* Init keyboard rescan workqueue */
- INIT_WORK(&aaedkbd->workq, aaedkbd_work, aaedkbd);
-
+ aaedkbd->poll_dev = poll_dev;
memcpy(aaedkbd->keycode, aaedkbd_keycode, sizeof(aaedkbd->keycode));
+ poll_dev->private = aaedkbd;
+ poll_dev->poll = aaedkbd_poll;
+ poll_dev->poll_interval = SCAN_INTERVAL;
+
+ input_dev = poll_dev->input;
input_dev->name = "AAED-2000 Keyboard";
input_dev->phys = "aaedkbd/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &pdev->dev;
- input_dev->private = aaedkbd;
+ input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = aaedkbd->keycode;
@@ -153,17 +134,14 @@ static int __devinit aaedkbd_probe(struct platform_device *pdev)
set_bit(aaedkbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
- input_dev->open = aaedkbd_open;
- input_dev->close = aaedkbd_close;
-
- error = input_register_device(aaedkbd->input);
+ error = input_register_polled_device(aaedkbd->poll_dev);
if (error)
goto fail;
return 0;
fail: kfree(aaedkbd);
- input_free_device(input_dev);
+ input_free_polled_device(poll_dev);
return error;
}
@@ -171,7 +149,8 @@ static int __devexit aaedkbd_remove(struct platform_device *pdev)
{
struct aaedkbd *aaedkbd = platform_get_drvdata(pdev);
- input_unregister_device(aaedkbd->input);
+ input_unregister_polled_device(aaedkbd->poll_dev);
+ input_free_polled_device(aaedkbd->poll_dev);
kfree(aaedkbd);
return 0;
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
new file mode 100644
index 00000000000..ded1d6ac6ff
--- /dev/null
+++ b/drivers/input/keyboard/atakbd.c
@@ -0,0 +1,134 @@
+/*
+ * atakbd.c
+ *
+ * Copyright (c) 2005 Michael Schmitz
+ *
+ * Based on amikbd.c, which is
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Hamish Macdonald
+ */
+
+/*
+ * Atari keyboard driver for Linux/m68k
+ *
+ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
+ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
+ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
+ * This driver only deals with handing key events off to the input layer.
+ */
+
+/*
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include <asm/atariints.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/irq.h>
+
+MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
+MODULE_DESCRIPTION("Atari keyboard driver");
+MODULE_LICENSE("GPL");
+
+static unsigned char atakbd_keycode[0x72];
+
+static struct input_dev *atakbd_dev;
+
+static void atakbd_interrupt(unsigned char scancode, char down)
+{
+
+ if (scancode < 0x72) { /* scancodes < 0xf2 are keys */
+
+ // report raw events here?
+
+ scancode = atakbd_keycode[scancode];
+
+ if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */
+ input_report_key(atakbd_dev, scancode, 1);
+ input_report_key(atakbd_dev, scancode, 0);
+ input_sync(atakbd_dev);
+ } else {
+ input_report_key(atakbd_dev, scancode, down);
+ input_sync(atakbd_dev);
+ }
+ } else /* scancodes >= 0xf2 are mouse data, most likely */
+ printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode);
+
+ return;
+}
+
+static int __init atakbd_init(void)
+{
+ int i;
+
+ if (!ATARIHW_PRESENT(ST_MFP))
+ return -EIO;
+
+ // TODO: request_mem_region if not done in arch code
+
+ if (!(atakbd_dev = input_allocate_device()))
+ return -ENOMEM;
+
+ // need to init core driver if not already done so
+ if (atari_keyb_init())
+ return -ENODEV;
+
+ atakbd_dev->name = "Atari Keyboard";
+ atakbd_dev->phys = "atakbd/input0";
+ atakbd_dev->id.bustype = BUS_ATARI;
+ atakbd_dev->id.vendor = 0x0001;
+ atakbd_dev->id.product = 0x0001;
+ atakbd_dev->id.version = 0x0100;
+
+ atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ atakbd_dev->keycode = atakbd_keycode;
+ atakbd_dev->keycodesize = sizeof(unsigned char);
+ atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
+
+ for (i = 1; i < 0x72; i++) {
+ atakbd_keycode[i] = i;
+ set_bit(atakbd_keycode[i], atakbd_dev->keybit);
+ }
+
+ input_register_device(atakbd_dev);
+
+ atari_input_keyboard_interrupt_hook = atakbd_interrupt;
+
+ printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name);
+
+ return 0;
+}
+
+static void __exit atakbd_exit(void)
+{
+ atari_input_keyboard_interrupt_hook = NULL;
+ input_unregister_device(atakbd_dev);
+}
+
+module_init(atakbd_init);
+module_exit(atakbd_exit);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 663877076bc..be1fe46cd30 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -586,7 +586,7 @@ static void atkbd_event_work(struct work_struct *work)
static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct atkbd *atkbd = dev->private;
+ struct atkbd *atkbd = input_get_drvdata(dev);
if (!atkbd->write)
return -1;
@@ -883,8 +883,9 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
input_dev->id.product = atkbd->translated ? 1 : atkbd->set;
input_dev->id.version = atkbd->id;
input_dev->event = atkbd_event;
- input_dev->private = atkbd;
- input_dev->cdev.dev = &atkbd->ps2dev.serio->dev;
+ input_dev->dev.parent = &atkbd->ps2dev.serio->dev;
+
+ input_set_drvdata(input_dev, atkbd);
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC);
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 1016c94e65d..6578bfff644 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -323,8 +323,7 @@ static int __init corgikbd_probe(struct platform_device *pdev)
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &pdev->dev;
- input_dev->private = corgikbd;
+ input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW);
input_dev->keycode = corgikbd->keycode;
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index ccf6df387b6..739212252b0 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -35,11 +35,14 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
struct input_dev *input = platform_get_drvdata(pdev);
for (i = 0; i < pdata->nbuttons; i++) {
- int gpio = pdata->buttons[i].gpio;
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ int gpio = button->gpio;
+
if (irq == gpio_to_irq(gpio)) {
- int state = (gpio_get_value(gpio) ? 1 : 0) ^ (pdata->buttons[i].active_low);
+ unsigned int type = button->type ?: EV_KEY;
+ int state = (gpio_get_value(gpio) ? 1 : 0) ^ button->active_low;
- input_report_key(input, pdata->buttons[i].keycode, state);
+ input_event(input, type, button->code, !!state);
input_sync(input);
}
}
@@ -63,8 +66,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
input->name = pdev->name;
input->phys = "gpio-keys/input0";
- input->cdev.dev = &pdev->dev;
- input->private = pdata;
+ input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
@@ -72,19 +74,21 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
input->id.version = 0x0100;
for (i = 0; i < pdata->nbuttons; i++) {
- int code = pdata->buttons[i].keycode;
- int irq = gpio_to_irq(pdata->buttons[i].gpio);
+ struct gpio_keys_button *button = &pdata->buttons[i];
+ int irq = gpio_to_irq(button->gpio);
+ unsigned int type = button->type ?: EV_KEY;
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM,
- pdata->buttons[i].desc ? pdata->buttons[i].desc : "gpio_keys",
+ button->desc ? button->desc : "gpio_keys",
pdev);
if (error) {
printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n",
irq, error);
goto fail;
}
- set_bit(code, input->keybit);
+
+ input_set_capability(input, type, button->code);
}
error = input_register_device(input);
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 7cc9728b04d..cdd254f2e6c 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -51,7 +51,7 @@ MODULE_LICENSE("Dual BSD/GPL");
#define HIL_KBD_SET1_UPBIT 0x01
#define HIL_KBD_SET1_SHIFT 1
-static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] =
+static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
{ HIL_KEYCODES_SET1 };
#define HIL_KBD_SET2_UPBIT 0x01
@@ -60,10 +60,10 @@ static unsigned int hil_kbd_set1[HIL_KEYCODES_SET1_TBLSIZE] =
#define HIL_KBD_SET3_UPBIT 0x80
#define HIL_KBD_SET3_SHIFT 0
-static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] =
+static unsigned int hil_kbd_set3[HIL_KEYCODES_SET3_TBLSIZE] __read_mostly =
{ HIL_KEYCODES_SET3 };
-static char hil_language[][16] = { HIL_LOCALE_MAP };
+static const char hil_language[][16] = { HIL_LOCALE_MAP };
struct hil_kbd {
struct input_dev *dev;
@@ -94,10 +94,12 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
idx = kbd->idx4/4;
p = data[idx - 1];
- if ((p & ~HIL_CMDCT_POL) ==
- (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
- if ((p & ~HIL_CMDCT_RPL) ==
- (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+ if ((p & ~HIL_CMDCT_POL) ==
+ (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+ goto report;
+ if ((p & ~HIL_CMDCT_RPL) ==
+ (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
+ goto report;
/* Not a poll response. See if we are loading config records. */
switch (p & HIL_PKT_DATA_MASK) {
@@ -107,27 +109,32 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
for (; i < HIL_KBD_MAX_LENGTH; i++)
kbd->idd[i] = 0;
break;
+
case HIL_CMD_RSC:
for (i = 0; i < idx; i++)
kbd->rsc[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_KBD_MAX_LENGTH; i++)
kbd->rsc[i] = 0;
break;
+
case HIL_CMD_EXD:
for (i = 0; i < idx; i++)
kbd->exd[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_KBD_MAX_LENGTH; i++)
kbd->exd[i] = 0;
break;
+
case HIL_CMD_RNM:
for (i = 0; i < idx; i++)
kbd->rnm[i] = kbd->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_KBD_MAX_LENGTH + 1; i++)
kbd->rnm[i] = '\0';
break;
+
default:
/* These occur when device isn't present */
- if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break;
+ if (p == (HIL_ERR_INT | HIL_PKT_CMD))
+ break;
/* Anything else we'd like to know about. */
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
break;
@@ -139,16 +146,19 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
switch (kbd->data[0] & HIL_POL_CHARTYPE_MASK) {
case HIL_POL_CHARTYPE_NONE:
break;
+
case HIL_POL_CHARTYPE_ASCII:
while (cnt < idx - 1)
input_report_key(dev, kbd->data[cnt++] & 0x7f, 1);
break;
+
case HIL_POL_CHARTYPE_RSVD1:
case HIL_POL_CHARTYPE_RSVD2:
case HIL_POL_CHARTYPE_BINARY:
while (cnt < idx - 1)
input_report_key(dev, kbd->data[cnt++], 1);
break;
+
case HIL_POL_CHARTYPE_SET1:
while (cnt < idx - 1) {
unsigned int key;
@@ -161,6 +171,7 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
input_report_key(dev, key, !up);
}
break;
+
case HIL_POL_CHARTYPE_SET2:
while (cnt < idx - 1) {
unsigned int key;
@@ -173,6 +184,7 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
input_report_key(dev, key, !up);
}
break;
+
case HIL_POL_CHARTYPE_SET3:
while (cnt < idx - 1) {
unsigned int key;
@@ -191,42 +203,43 @@ static void hil_kbd_process_record(struct hil_kbd *kbd)
up(&kbd->sem);
}
-static void hil_kbd_process_err(struct hil_kbd *kbd) {
+static void hil_kbd_process_err(struct hil_kbd *kbd)
+{
printk(KERN_WARNING PREFIX "errored HIL packet\n");
kbd->idx4 = 0;
up(&kbd->sem);
}
-static irqreturn_t hil_kbd_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags)
+static irqreturn_t hil_kbd_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
{
struct hil_kbd *kbd;
hil_packet packet;
int idx;
kbd = serio_get_drvdata(serio);
- if (kbd == NULL) {
- BUG();
- return IRQ_HANDLED;
- }
+ BUG_ON(kbd == NULL);
if (kbd->idx4 >= (HIL_KBD_MAX_LENGTH * sizeof(hil_packet))) {
hil_kbd_process_err(kbd);
return IRQ_HANDLED;
}
idx = kbd->idx4/4;
- if (!(kbd->idx4 % 4)) kbd->data[idx] = 0;
+ if (!(kbd->idx4 % 4))
+ kbd->data[idx] = 0;
packet = kbd->data[idx];
packet |= ((hil_packet)data) << ((3 - (kbd->idx4 % 4)) * 8);
kbd->data[idx] = packet;
/* Records of N 4-byte hil_packets must terminate with a command. */
- if ((++(kbd->idx4)) % 4) return IRQ_HANDLED;
+ if ((++(kbd->idx4)) % 4)
+ return IRQ_HANDLED;
if ((packet & 0xffff0000) != HIL_ERR_INT) {
hil_kbd_process_err(kbd);
return IRQ_HANDLED;
}
- if (packet & HIL_PKT_CMD) hil_kbd_process_record(kbd);
+ if (packet & HIL_PKT_CMD)
+ hil_kbd_process_record(kbd);
return IRQ_HANDLED;
}
@@ -235,10 +248,7 @@ static void hil_kbd_disconnect(struct serio *serio)
struct hil_kbd *kbd;
kbd = serio_get_drvdata(serio);
- if (kbd == NULL) {
- BUG();
- return;
- }
+ BUG_ON(kbd == NULL);
serio_close(serio);
input_unregister_device(kbd->dev);
@@ -259,42 +269,40 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
if (!kbd->dev)
goto bail0;
- kbd->dev->private = kbd;
-
if (serio_open(serio, drv))
goto bail1;
serio_set_drvdata(serio, kbd);
kbd->serio = serio;
- init_MUTEX_LOCKED(&(kbd->sem));
+ init_MUTEX_LOCKED(&kbd->sem);
/* Get device info. MLC driver supplies devid/status/etc. */
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_IDD);
- down(&(kbd->sem));
+ down(&kbd->sem);
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_RSC);
- down(&(kbd->sem));
+ down(&kbd->sem);
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_RNM);
- down(&(kbd->sem));
+ down(&kbd->sem);
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_EXD);
- down(&(kbd->sem));
+ down(&kbd->sem);
- up(&(kbd->sem));
+ up(&kbd->sem);
did = kbd->idd[0];
idd = kbd->idd + 1;
@@ -310,12 +318,11 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
goto bail2;
}
- if(HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
+ if (HIL_IDD_NUM_BUTTONS(idd) || HIL_IDD_NUM_AXES_PER_SET(*idd)) {
printk(KERN_INFO PREFIX "keyboards only, no combo devices supported.\n");
goto bail2;
}
-
kbd->dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
kbd->dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
kbd->dev->keycodemax = HIL_KEYCODES_SET1_TBLSIZE;
@@ -328,7 +335,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
kbd->dev->id.vendor = PCI_VENDOR_ID_HP;
kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
- kbd->dev->cdev.dev = &serio->dev;
+ kbd->dev->dev.parent = &serio->dev;
for (i = 0; i < 128; i++) {
set_bit(hil_kbd_set1[i], kbd->dev->keybit);
@@ -344,8 +351,8 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_EK1); /* Enable Keyswitch Autorepeat 1 */
- down(&(kbd->sem));
- up(&(kbd->sem));
+ down(&kbd->sem);
+ up(&kbd->sem);
return 0;
bail2:
@@ -368,26 +375,26 @@ static struct serio_device_id hil_kbd_ids[] = {
{ 0 }
};
-struct serio_driver hil_kbd_serio_drv = {
+static struct serio_driver hil_kbd_serio_drv = {
.driver = {
.name = "hil_kbd",
},
.description = "HP HIL keyboard driver",
.id_table = hil_kbd_ids,
- .connect = hil_kbd_connect,
- .disconnect = hil_kbd_disconnect,
- .interrupt = hil_kbd_interrupt
+ .connect = hil_kbd_connect,
+ .disconnect = hil_kbd_disconnect,
+ .interrupt = hil_kbd_interrupt
};
static int __init hil_kbd_init(void)
{
return serio_register_driver(&hil_kbd_serio_drv);
}
-
+
static void __exit hil_kbd_exit(void)
{
serio_unregister_driver(&hil_kbd_serio_drv);
}
-
+
module_init(hil_kbd_init);
module_exit(hil_kbd_exit);
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 4de4dc297d5..499b6974457 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1998 Philip Blundell <philb@gnu.org>
* Copyright (C) 1999 Matthew Wilcox <willy@bofh.ai>
- * Copyright (C) 1999-2006 Helge Deller <deller@gmx.de>
+ * Copyright (C) 1999-2007 Helge Deller <deller@gmx.de>
*
* Very basic HP Human Interface Loop (HIL) driver.
* This driver handles the keyboard on HP300 (m68k) and on some
@@ -52,7 +52,7 @@ MODULE_LICENSE("GPL v2");
#elif defined(CONFIG_HP300)
- #define HILBASE 0xf0428000 /* HP300 (m86k) port address */
+ #define HILBASE 0xf0428000UL /* HP300 (m68k) port address */
#define HIL_DATA 0x1
#define HIL_CMD 0x3
#define HIL_IRQ 2
@@ -89,7 +89,7 @@ MODULE_LICENSE("GPL v2");
#define HIL_READKBDSADR 0xF9
#define HIL_WRITEKBDSADR 0xE9
-static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] =
+static unsigned int hphilkeyb_keycode[HIL_KEYCODES_SET1_TBLSIZE] __read_mostly =
{ HIL_KEYCODES_SET1 };
/* HIL structure */
@@ -211,10 +211,10 @@ hil_keyb_init(void)
return -ENODEV; /* already initialized */
}
+ spin_lock_init(&hil_dev.lock);
hil_dev.dev = input_allocate_device();
if (!hil_dev.dev)
return -ENOMEM;
- hil_dev.dev->private = &hil_dev;
#if defined(CONFIG_HP300)
if (!hwreg_present((void *)(HILBASE + HIL_DATA))) {
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 3d4d0a0ede2..1b08f4e79dd 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -515,7 +515,7 @@ static int
lkkbd_event (struct input_dev *dev, unsigned int type, unsigned int code,
int value)
{
- struct lkkbd *lk = dev->private;
+ struct lkkbd *lk = input_get_drvdata (dev);
unsigned char leds_on = 0;
unsigned char leds_off = 0;
@@ -666,9 +666,10 @@ lkkbd_connect (struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_LKKBD;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
+ input_dev->dev.parent = &serio->dev;
input_dev->event = lkkbd_event;
- input_dev->private = lk;
+
+ input_set_drvdata (input_dev, lk);
set_bit (EV_KEY, input_dev->evbit);
set_bit (EV_LED, input_dev->evbit);
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 2ade5186cc4..7a41b271f22 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -231,7 +231,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->private = locomokbd;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = locomokbd->keycode;
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index aa29b50765c..b97a41e3ee5 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -104,8 +104,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_NEWTON;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = nkbd;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = nkbd->keycode;
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 5680a6d95b2..3a228634f10 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -370,8 +370,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
- input_dev->cdev.dev = &pdev->dev;
- input_dev->private = omap_kp;
+ input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
diff --git a/drivers/input/keyboard/pxa27x_keyboard.c b/drivers/input/keyboard/pxa27x_keyboard.c
new file mode 100644
index 00000000000..06eaf766d9d
--- /dev/null
+++ b/drivers/input/keyboard/pxa27x_keyboard.c
@@ -0,0 +1,258 @@
+/*
+ * linux/drivers/input/keyboard/pxa27x_keyboard.c
+ *
+ * Driver for the pxa27x matrix keyboard controller.
+ *
+ * Created: Feb 22, 2007
+ * Author: Rodolfo Giometti <giometti@linux.it>
+ *
+ * Based on a previous implementations by Kevin O'Connor
+ * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
+ * on some suggestions by Nicolas Pitre <nico@cam.org>.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/pxa27x_keyboard.h>
+
+#define DRIVER_NAME "pxa27x-keyboard"
+
+#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \
+ col/2 == 1 ? KPASMKP1 : \
+ col/2 == 2 ? KPASMKP2 : KPASMKP3)
+#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
+
+static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input_dev = platform_get_drvdata(pdev);
+ unsigned long kpc = KPC;
+ int p, row, col, rel;
+
+ if (kpc & KPC_DI) {
+ unsigned long kpdk = KPDK;
+
+ if (!(kpdk & KPDK_DKP)) {
+ /* better luck next time */
+ } else if (kpc & KPC_REE0) {
+ unsigned long kprec = KPREC;
+ KPREC = 0x7f;
+
+ if (kprec & KPREC_OF0)
+ rel = (kprec & 0xff) + 0x7f;
+ else if (kprec & KPREC_UF0)
+ rel = (kprec & 0xff) - 0x7f - 0xff;
+ else
+ rel = (kprec & 0xff) - 0x7f;
+
+ if (rel) {
+ input_report_rel(input_dev, REL_WHEEL, rel);
+ input_sync(input_dev);
+ }
+ }
+ }
+
+ if (kpc & KPC_MI) {
+ /* report the status of every button */
+ for (row = 0; row < pdata->nr_rows; row++) {
+ for (col = 0; col < pdata->nr_cols; col++) {
+ p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
+ 1 : 0;
+ pr_debug("keycode %x - pressed %x\n",
+ pdata->keycodes[row][col], p);
+ input_report_key(input_dev,
+ pdata->keycodes[row][col], p);
+ }
+ }
+ input_sync(input_dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int pxakbd_open(struct input_dev *dev)
+{
+ /* Set keypad control register */
+ KPC |= (KPC_ASACT |
+ KPC_MS_ALL |
+ (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL |
+ KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
+
+ KPC &= ~KPC_AS; /* disable automatic scan */
+ KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */
+
+ /* Set rotary count to mid-point value */
+ KPREC = 0x7F;
+
+ /* Enable unit clock */
+ pxa_set_cken(CKEN19_KEYPAD, 1);
+
+ return 0;
+}
+
+static void pxakbd_close(struct input_dev *dev)
+{
+ /* Disable clock unit */
+ pxa_set_cken(CKEN19_KEYPAD, 0);
+}
+
+#ifdef CONFIG_PM
+static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+
+ /* Save controller status */
+ pdata->reg_kpc = KPC;
+ pdata->reg_kprec = KPREC;
+
+ return 0;
+}
+
+static int pxakbd_resume(struct platform_device *pdev)
+{
+ struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input_dev = platform_get_drvdata(pdev);
+
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users) {
+ /* Restore controller status */
+ KPC = pdata->reg_kpc;
+ KPREC = pdata->reg_kprec;
+
+ /* Enable unit clock */
+ pxa_set_cken(CKEN19_KEYPAD, 1);
+ }
+
+ mutex_unlock(&input_dev->mutex);
+
+ return 0;
+}
+#else
+#define pxakbd_suspend NULL
+#define pxakbd_resume NULL
+#endif
+
+static int __devinit pxakbd_probe(struct platform_device *pdev)
+{
+ struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+ struct input_dev *input_dev;
+ int i, row, col, error;
+
+ /* Create and register the input driver. */
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ printk(KERN_ERR "Cannot request keypad device\n");
+ return -ENOMEM;
+ }
+
+ input_dev->name = DRIVER_NAME;
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->open = pxakbd_open;
+ input_dev->close = pxakbd_close;
+ input_dev->dev.parent = &pdev->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
+ input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL);
+ for (row = 0; row < pdata->nr_rows; row++) {
+ for (col = 0; col < pdata->nr_cols; col++) {
+ int code = pdata->keycodes[row][col];
+ if (code > 0)
+ set_bit(code, input_dev->keybit);
+ }
+ }
+
+ error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED,
+ DRIVER_NAME, pdev);
+ if (error) {
+ printk(KERN_ERR "Cannot request keypad IRQ\n");
+ pxa_set_cken(CKEN19_KEYPAD, 0);
+ goto err_free_dev;
+ }
+
+ platform_set_drvdata(pdev, input_dev);
+
+ /* Register the input device */
+ error = input_register_device(input_dev);
+ if (error)
+ goto err_free_irq;
+
+ /* Setup GPIOs. */
+ for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
+ pxa_gpio_mode(pdata->gpio_modes[i]);
+
+ /*
+ * Store rows/cols info into keyboard registers.
+ */
+
+ KPC |= (pdata->nr_rows - 1) << 26;
+ KPC |= (pdata->nr_cols - 1) << 23;
+
+ for (col = 0; col < pdata->nr_cols; col++)
+ KPC |= KPC_MS0 << col;
+
+ return 0;
+
+ err_free_irq:
+ platform_set_drvdata(pdev, NULL);
+ free_irq(IRQ_KEYPAD, pdev);
+ err_free_dev:
+ input_free_device(input_dev);
+ return error;
+}
+
+static int __devexit pxakbd_remove(struct platform_device *pdev)
+{
+ struct input_dev *input_dev = platform_get_drvdata(pdev);
+
+ input_unregister_device(input_dev);
+ free_irq(IRQ_KEYPAD, pdev);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver pxakbd_driver = {
+ .probe = pxakbd_probe,
+ .remove = __devexit_p(pxakbd_remove),
+ .suspend = pxakbd_suspend,
+ .resume = pxakbd_resume,
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+};
+
+static int __init pxakbd_init(void)
+{
+ return platform_driver_register(&pxakbd_driver);
+}
+
+static void __exit pxakbd_exit(void)
+{
+ platform_driver_unregister(&pxakbd_driver);
+}
+
+module_init(pxakbd_init);
+module_exit(pxakbd_exit);
+
+MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index 8a2166c77ff..41b80385476 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -372,10 +372,9 @@ static int __init spitzkbd_probe(struct platform_device *dev)
spitzkbd->input = input_dev;
- input_dev->private = spitzkbd;
input_dev->name = "Spitz Keyboard";
input_dev->phys = spitzkbd->phys;
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index f7b5c5b8145..b44b0684d54 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -108,8 +108,7 @@ static int skbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_STOWAWAY;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = skbd;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = skbd->keycode;
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index cc023836641..1d4e39624cf 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -146,7 +146,7 @@ out:
static int sunkbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct sunkbd *sunkbd = dev->private;
+ struct sunkbd *sunkbd = input_get_drvdata(dev);
switch (type) {
@@ -271,8 +271,10 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_SUNKBD;
input_dev->id.product = sunkbd->type;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = sunkbd;
+ input_dev->dev.parent = &serio->dev;
+
+ input_set_drvdata(input_dev, sunkbd);
+
input_dev->event = sunkbd_event;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_SND) | BIT(EV_REP);
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index a8209343213..f3a56eb58ed 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -108,8 +108,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = xtkbd;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = xtkbd->keycode;
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 41b42587f5e..6013ace94d9 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -40,6 +40,28 @@ config INPUT_M68K_BEEP
tristate "M68k Beeper support"
depends on M68K
+config INPUT_IXP4XX_BEEPER
+ tristate "IXP4XX Beeper support"
+ depends on ARCH_IXP4XX
+ help
+ If you say yes here, you can connect a beeper to the
+ ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+
+ If unsure, say Y.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ixp4xx-beeper.
+
+config INPUT_COBALT_BTNS
+ tristate "Cobalt button interface"
+ depends on MIPS_COBALT
+ select INPUT_POLLDEV
+ help
+ Say Y here if you want to support MIPS Cobalt button interface.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cobalt_btns.
+
config INPUT_WISTRON_BTNS
tristate "x86 Wistron laptop button interface"
depends on X86 && !X86_64
@@ -60,17 +82,79 @@ config INPUT_ATLAS_BTNS
To compile this driver as a module, choose M here: the module will
be called atlas_btns.
-config INPUT_IXP4XX_BEEPER
- tristate "IXP4XX Beeper support"
- depends on ARCH_IXP4XX
+config INPUT_ATI_REMOTE
+ tristate "ATI / X10 USB RF remote control"
+ select USB
help
- If you say yes here, you can connect a beeper to the
- ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+ Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
+ These are RF remotes with USB receivers.
+ The ATI remote comes with many of ATI's All-In-Wonder video cards.
+ The X10 "Lola" remote is available at:
+ <http://www.x10.com/products/lola_sg1.htm>
+ This driver provides mouse pointer, left and right mouse buttons,
+ and maps all the other remote buttons to keypress events.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ati_remote.
+
+config INPUT_ATI_REMOTE2
+ tristate "ATI / Philips USB RF remote control"
+ select USB
+ help
+ Say Y here if you want to use an ATI or Philips USB RF remote control.
+ These are RF remotes with USB receivers.
+ ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
+ and is also available as a separate product.
+ This driver provides mouse pointer, left and right mouse buttons,
+ and maps all the other remote buttons to keypress events.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ati_remote2.
+
+config INPUT_KEYSPAN_REMOTE
+ tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ select USB
+ help
+ Say Y here if you want to use a Keyspan DMR USB remote control.
+ Currently only the UIA-11 type of receiver has been tested. The tag
+ on the receiver that connects to the USB port should have a P/N that
+ will tell you what type of DMR you have. The UIA-10 type is not
+ supported at this time. This driver maps all buttons to keypress
+ events.
- If unsure, say Y.
+ To compile this driver as a module, choose M here: the module will
+ be called keyspan_remote.
+
+config INPUT_POWERMATE
+ tristate "Griffin PowerMate and Contour Jog support"
+ select USB
+ help
+ Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
+ These are aluminum dials which can measure clockwise and anticlockwise
+ rotation. The dial also acts as a pushbutton. The base contains an LED
+ which can be instructed to pulse or to switch to a particular intensity.
+
+ You can download userspace tools from
+ <http://sowerbutts.com/powermate/>.
To compile this driver as a module, choose M here: the
- module will be called ixp4xx-beeper.
+ module will be called powermate.
+
+config INPUT_YEALINK
+ tristate "Yealink usb-p1k voip phone"
+ depends EXPERIMENTAL
+ select USB
+ help
+ Say Y here if you want to enable keyboard and LCD functions of the
+ Yealink usb-p1k usb phones. The audio part is enabled by the generic
+ usb sound driver, so you might want to enable that as well.
+
+ For information about how to use these additional functions, see
+ <file:Documentation/input/yealink.txt>.
+
+ To compile this driver as a module, choose M here: the module will be
+ called yealink.
config INPUT_UINPUT
tristate "User level driver support"
@@ -81,8 +165,19 @@ config INPUT_UINPUT
To compile this driver as a module, choose M here: the
module will be called uinput.
+config INPUT_POLLDEV
+ tristate "Polled input device skeleton"
+ help
+ Say Y here if you are using a driver for an input
+ device that periodically polls hardware state. This
+ option is only useful for out-of-tree drivers since
+ in-tree drivers select it automatically.
+
+ To compile this driver as a module, choose M here: the
+ module will be called input-polldev.
+
config HP_SDC_RTC
- tristate "HP SDC Real Time Clock"
+ tristate "HP SDC Real Time Clock"
depends on GSC || HP300
select HP_SDC
help
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index e0a8d58c9e9..8b2f7799e25 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -4,11 +4,18 @@
# Each configuration option enables a list of files.
+obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
-obj-$(CONFIG_INPUT_UINPUT) += uinput.o
+obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
+obj-$(CONFIG_INPUT_ATI_REMOTE) += ati_remote.o
+obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
+obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
+obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
+obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
-obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+obj-$(CONFIG_INPUT_UINPUT) += uinput.o
diff --git a/drivers/usb/input/ati_remote.c b/drivers/input/misc/ati_remote.c
index b724e36f7b9..471aab20644 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/input/misc/ati_remote.c
@@ -120,6 +120,7 @@
* behaviour.
*/
#define FILTER_TIME 60 /* msec */
+#define REPEAT_DELAY 500 /* msec */
static unsigned long channel_mask;
module_param(channel_mask, ulong, 0644);
@@ -133,6 +134,10 @@ static int repeat_filter = FILTER_TIME;
module_param(repeat_filter, int, 0644);
MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
+static int repeat_delay = REPEAT_DELAY;
+module_param(repeat_delay, int, 0644);
+MODULE_PARM_DESC(repeat_delay, "Delay before sending repeats, default = 500 msec");
+
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
#undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg)
@@ -174,6 +179,8 @@ struct ati_remote {
unsigned char old_data[2]; /* Detect duplicate events */
unsigned long old_jiffies;
unsigned long acc_jiffies; /* handle acceleration */
+ unsigned long first_jiffies;
+
unsigned int repeat_count;
char name[NAME_BUFSIZE];
@@ -318,7 +325,7 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
*/
static int ati_remote_open(struct input_dev *inputdev)
{
- struct ati_remote *ati_remote = inputdev->private;
+ struct ati_remote *ati_remote = input_get_drvdata(inputdev);
/* On first open, submit the read urb which was set up previously. */
ati_remote->irq_urb->dev = ati_remote->udev;
@@ -336,7 +343,7 @@ static int ati_remote_open(struct input_dev *inputdev)
*/
static void ati_remote_close(struct input_dev *inputdev)
{
- struct ati_remote *ati_remote = inputdev->private;
+ struct ati_remote *ati_remote = input_get_drvdata(inputdev);
usb_kill_urb(ati_remote->irq_urb);
}
@@ -501,21 +508,31 @@ static void ati_remote_input_report(struct urb *urb)
}
if (ati_remote_tbl[index].kind == KIND_FILTERED) {
+ unsigned long now = jiffies;
+
/* Filter duplicate events which happen "too close" together. */
if (ati_remote->old_data[0] == data[1] &&
ati_remote->old_data[1] == data[2] &&
- time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) {
+ time_before(now, ati_remote->old_jiffies +
+ msecs_to_jiffies(repeat_filter))) {
ati_remote->repeat_count++;
} else {
ati_remote->repeat_count = 0;
+ ati_remote->first_jiffies = now;
}
ati_remote->old_data[0] = data[1];
ati_remote->old_data[1] = data[2];
- ati_remote->old_jiffies = jiffies;
+ ati_remote->old_jiffies = now;
+ /* Ensure we skip at least the 4 first duplicate events (generated
+ * by a single keypress), and continue skipping until repeat_delay
+ * msecs have passed
+ */
if (ati_remote->repeat_count > 0 &&
- ati_remote->repeat_count < 5)
+ (ati_remote->repeat_count < 5 ||
+ time_before(now, ati_remote->first_jiffies +
+ msecs_to_jiffies(repeat_delay))))
return;
@@ -653,7 +670,8 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
if (ati_remote_tbl[i].type == EV_KEY)
set_bit(ati_remote_tbl[i].code, idev->keybit);
- idev->private = ati_remote;
+ input_set_drvdata(idev, ati_remote);
+
idev->open = ati_remote_open;
idev->close = ati_remote_close;
@@ -661,7 +679,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
idev->phys = ati_remote->phys;
usb_to_input_id(ati_remote->udev, &idev->id);
- idev->cdev.dev = &ati_remote->udev->dev;
+ idev->dev.parent = &ati_remote->udev->dev;
}
static int ati_remote_initialize(struct ati_remote *ati_remote)
@@ -772,15 +790,17 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
goto fail3;
/* Set up and register input device */
- input_register_device(ati_remote->idev);
+ err = input_register_device(ati_remote->idev);
+ if (err)
+ goto fail3;
usb_set_intfdata(interface, ati_remote);
return 0;
-fail3: usb_kill_urb(ati_remote->irq_urb);
+ fail3: usb_kill_urb(ati_remote->irq_urb);
usb_kill_urb(ati_remote->out_urb);
-fail2: ati_remote_free_buffers(ati_remote);
-fail1: input_free_device(input_dev);
+ fail2: ati_remote_free_buffers(ati_remote);
+ fail1: input_free_device(input_dev);
kfree(ati_remote);
return err;
}
diff --git a/drivers/usb/input/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 6459be90599..1031543e5c3 100644
--- a/drivers/usb/input/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -131,7 +131,7 @@ static struct usb_driver ati_remote2_driver = {
static int ati_remote2_open(struct input_dev *idev)
{
- struct ati_remote2 *ar2 = idev->private;
+ struct ati_remote2 *ar2 = input_get_drvdata(idev);
int r;
r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
@@ -153,7 +153,7 @@ static int ati_remote2_open(struct input_dev *idev)
static void ati_remote2_close(struct input_dev *idev)
{
- struct ati_remote2 *ar2 = idev->private;
+ struct ati_remote2 *ar2 = input_get_drvdata(idev);
usb_kill_urb(ar2->urb[0]);
usb_kill_urb(ar2->urb[1]);
@@ -337,14 +337,14 @@ static void ati_remote2_complete_key(struct urb *urb)
static int ati_remote2_input_init(struct ati_remote2 *ar2)
{
struct input_dev *idev;
- int i;
+ int i, retval;
idev = input_allocate_device();
if (!idev)
return -ENOMEM;
ar2->idev = idev;
- idev->private = ar2;
+ input_set_drvdata(idev, ar2);
idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
@@ -362,13 +362,13 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->phys = ar2->phys;
usb_to_input_id(ar2->udev, &idev->id);
- idev->cdev.dev = &ar2->udev->dev;
+ idev->dev.parent = &ar2->udev->dev;
- i = input_register_device(idev);
- if (i)
+ retval = input_register_device(idev);
+ if (retval)
input_free_device(idev);
- return i;
+ return retval;
}
static int ati_remote2_urb_init(struct ati_remote2 *ar2)
@@ -405,9 +405,7 @@ static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
for (i = 0; i < 2; i++) {
usb_free_urb(ar2->urb[i]);
-
- if (ar2->buf[i])
- usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
+ usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
}
}
diff --git a/drivers/input/misc/cobalt_btns.c b/drivers/input/misc/cobalt_btns.c
new file mode 100644
index 00000000000..064b0793601
--- /dev/null
+++ b/drivers/input/misc/cobalt_btns.c
@@ -0,0 +1,172 @@
+/*
+ * Cobalt button interface driver.
+ *
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/input-polldev.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define BUTTONS_POLL_INTERVAL 30 /* msec */
+#define BUTTONS_COUNT_THRESHOLD 3
+#define BUTTONS_STATUS_MASK 0xfe000000
+
+struct buttons_dev {
+ struct input_polled_dev *poll_dev;
+ void __iomem *reg;
+};
+
+struct buttons_map {
+ uint32_t mask;
+ int keycode;
+ int count;
+};
+
+static struct buttons_map buttons_map[] = {
+ { 0x02000000, KEY_RESTART, },
+ { 0x04000000, KEY_LEFT, },
+ { 0x08000000, KEY_UP, },
+ { 0x10000000, KEY_DOWN, },
+ { 0x20000000, KEY_RIGHT, },
+ { 0x40000000, KEY_ENTER, },
+ { 0x80000000, KEY_SELECT, },
+};
+
+static void handle_buttons(struct input_polled_dev *dev)
+{
+ struct buttons_map *button = buttons_map;
+ struct buttons_dev *bdev = dev->private;
+ struct input_dev *input = dev->input;
+ uint32_t status;
+ int i;
+
+ status = readl(bdev->reg);
+ status = ~status & BUTTONS_STATUS_MASK;
+
+ for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
+ if (status & button->mask) {
+ button->count++;
+ } else {
+ if (button->count >= BUTTONS_COUNT_THRESHOLD) {
+ input_report_key(input, button->keycode, 0);
+ input_sync(input);
+ }
+ button->count = 0;
+ }
+
+ if (button->count == BUTTONS_COUNT_THRESHOLD) {
+ input_report_key(input, button->keycode, 1);
+ input_sync(input);
+ }
+
+ button++;
+ }
+}
+
+static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
+{
+ struct buttons_dev *bdev;
+ struct input_polled_dev *poll_dev;
+ struct input_dev *input;
+ struct resource *res;
+ int error, i;
+
+ bdev = kzalloc(sizeof(struct buttons_dev), GFP_KERNEL);
+ poll_dev = input_allocate_polled_device();
+ if (!bdev || !poll_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ poll_dev->private = bdev;
+ poll_dev->poll = handle_buttons;
+ poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
+
+ input = poll_dev->input;
+ input->name = "Cobalt buttons";
+ input->phys = "cobalt/input0";
+ input->id.bustype = BUS_HOST;
+ input->cdev.dev = &pdev->dev;
+
+ input->evbit[0] = BIT(EV_KEY);
+ for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
+ set_bit(buttons_map[i].keycode, input->keybit);
+ buttons_map[i].count = 0;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ error = -EBUSY;
+ goto err_free_mem;
+ }
+
+ bdev->poll_dev = poll_dev;
+ bdev->reg = ioremap(res->start, res->end - res->start + 1);
+ dev_set_drvdata(&pdev->dev, bdev);
+
+ error = input_register_polled_device(poll_dev);
+ if (error)
+ goto err_iounmap;
+
+ return 0;
+
+ err_iounmap:
+ iounmap(bdev->reg);
+ err_free_mem:
+ input_free_polled_device(poll_dev);
+ kfree(bdev);
+ dev_set_drvdata(&pdev->dev, NULL);
+ return error;
+}
+
+static int __devexit cobalt_buttons_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct buttons_dev *bdev = dev_get_drvdata(dev);
+
+ input_unregister_polled_device(bdev->poll_dev);
+ input_free_polled_device(bdev->poll_dev);
+ iounmap(bdev->reg);
+ kfree(bdev);
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver cobalt_buttons_driver = {
+ .probe = cobalt_buttons_probe,
+ .remove = __devexit_p(cobalt_buttons_remove),
+ .driver = {
+ .name = "Cobalt buttons",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cobalt_buttons_init(void)
+{
+ return platform_driver_register(&cobalt_buttons_driver);
+}
+
+static void __exit cobalt_buttons_exit(void)
+{
+ platform_driver_unregister(&cobalt_buttons_driver);
+}
+
+module_init(cobalt_buttons_init);
+module_exit(cobalt_buttons_exit);
diff --git a/drivers/input/misc/input-polldev.c b/drivers/input/misc/input-polldev.c
new file mode 100644
index 00000000000..1b2b9c9c5d8
--- /dev/null
+++ b/drivers/input/misc/input-polldev.c
@@ -0,0 +1,171 @@
+/*
+ * Generic implementation of a polled input device
+
+ * Copyright (c) 2007 Dmitry Torokhov
+ *
+ * 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/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/input-polldev.h>
+
+static DEFINE_MUTEX(polldev_mutex);
+static int polldev_users;
+static struct workqueue_struct *polldev_wq;
+
+static int input_polldev_start_workqueue(void)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&polldev_mutex);
+ if (retval)
+ return retval;
+
+ if (!polldev_users) {
+ polldev_wq = create_singlethread_workqueue("ipolldevd");
+ if (!polldev_wq) {
+ printk(KERN_ERR "input-polldev: failed to create "
+ "ipolldevd workqueue\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ polldev_users++;
+
+ out:
+ mutex_unlock(&polldev_mutex);
+ return retval;
+}
+
+static void input_polldev_stop_workqueue(void)
+{
+ mutex_lock(&polldev_mutex);
+
+ if (!--polldev_users)
+ destroy_workqueue(polldev_wq);
+
+ mutex_unlock(&polldev_mutex);
+}
+
+static void input_polled_device_work(struct work_struct *work)
+{
+ struct input_polled_dev *dev =
+ container_of(work, struct input_polled_dev, work.work);
+
+ dev->poll(dev);
+ queue_delayed_work(polldev_wq, &dev->work,
+ msecs_to_jiffies(dev->poll_interval));
+}
+
+static int input_open_polled_device(struct input_dev *input)
+{
+ struct input_polled_dev *dev = input->private;
+ int error;
+
+ error = input_polldev_start_workqueue();
+ if (error)
+ return error;
+
+ if (dev->flush)
+ dev->flush(dev);
+
+ queue_delayed_work(polldev_wq, &dev->work,
+ msecs_to_jiffies(dev->poll_interval));
+
+ return 0;
+}
+
+static void input_close_polled_device(struct input_dev *input)
+{
+ struct input_polled_dev *dev = input->private;
+
+ cancel_rearming_delayed_workqueue(polldev_wq, &dev->work);
+ input_polldev_stop_workqueue();
+}
+
+/**
+ * input_allocate_polled_device - allocated memory polled device
+ *
+ * The function allocates memory for a polled device and also
+ * for an input device associated with this polled device.
+ */
+struct input_polled_dev *input_allocate_polled_device(void)
+{
+ struct input_polled_dev *dev;
+
+ dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->input = input_allocate_device();
+ if (!dev->input) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL(input_allocate_polled_device);
+
+/**
+ * input_free_polled_device - free memory allocated for polled device
+ * @dev: device to free
+ *
+ * The function frees memory allocated for polling device and drops
+ * reference to the associated input device (if present).
+ */
+void input_free_polled_device(struct input_polled_dev *dev)
+{
+ if (dev) {
+ input_free_device(dev->input);
+ kfree(dev);
+ }
+}
+EXPORT_SYMBOL(input_free_polled_device);
+
+/**
+ * input_register_polled_device - register polled device
+ * @dev: device to register
+ *
+ * The function registers previously initialized polled input device
+ * with input layer. The device should be allocated with call to
+ * input_allocate_polled_device(). Callers should also set up poll()
+ * method and set up capabilities (id, name, phys, bits) of the
+ * corresponing input_dev structure.
+ */
+int input_register_polled_device(struct input_polled_dev *dev)
+{
+ struct input_dev *input = dev->input;
+
+ INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
+ if (!dev->poll_interval)
+ dev->poll_interval = 500;
+ input->private = dev;
+ input->open = input_open_polled_device;
+ input->close = input_close_polled_device;
+
+ return input_register_device(input);
+}
+EXPORT_SYMBOL(input_register_polled_device);
+
+/**
+ * input_unregister_polled_device - unregister polled device
+ * @dev: device to unregister
+ *
+ * The function unregisters previously registered polled input
+ * device from input layer. Polling is stopped and device is
+ * ready to be freed with call to input_free_polled_device().
+ * Callers should not attempt to access dev->input pointer
+ * after calling this function.
+ */
+void input_unregister_polled_device(struct input_polled_dev *dev)
+{
+ input_unregister_device(dev->input);
+ dev->input = NULL;
+}
+EXPORT_SYMBOL(input_unregister_polled_device);
+
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 105c6fc2782..3d4b619dada 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -51,7 +51,7 @@ static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- unsigned int pin = (unsigned int) dev->private;
+ unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
unsigned int count = 0;
if (type != EV_SND)
@@ -99,14 +99,15 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
if (!input_dev)
return -ENOMEM;
- input_dev->private = (void *) dev->id;
+ input_set_drvdata(input_dev, (void *) dev->id);
+
input_dev->name = "ixp4xx beeper",
input_dev->phys = "ixp4xx/gpio";
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
@@ -136,7 +137,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
{
struct input_dev *input_dev = platform_get_drvdata(dev);
- unsigned int pin = (unsigned int) input_dev->private;
+ unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
input_unregister_device(input_dev);
platform_set_drvdata(dev, NULL);
@@ -153,7 +154,7 @@ static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
static void ixp4xx_spkr_shutdown(struct platform_device *dev)
{
struct input_dev *input_dev = platform_get_drvdata(dev);
- unsigned int pin = (unsigned int) input_dev->private;
+ unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
/* turn off the speaker */
disable_irq(IRQ_IXP4XX_TIMER2);
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index 98bd323369c..1bffc9fa98c 100644
--- a/drivers/usb/input/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -394,7 +394,7 @@ resubmit:
static int keyspan_open(struct input_dev *dev)
{
- struct usb_keyspan *remote = dev->private;
+ struct usb_keyspan *remote = input_get_drvdata(dev);
remote->irq_urb->dev = remote->udev;
if (usb_submit_urb(remote->irq_urb, GFP_KERNEL))
@@ -405,7 +405,7 @@ static int keyspan_open(struct input_dev *dev)
static void keyspan_close(struct input_dev *dev)
{
- struct usb_keyspan *remote = dev->private;
+ struct usb_keyspan *remote = input_get_drvdata(dev);
usb_kill_urb(remote->irq_urb);
}
@@ -437,7 +437,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
struct usb_endpoint_descriptor *endpoint;
struct usb_keyspan *remote;
struct input_dev *input_dev;
- int i, retval;
+ int i, error;
endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
if (!endpoint)
@@ -446,7 +446,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
remote = kzalloc(sizeof(*remote), GFP_KERNEL);
input_dev = input_allocate_device();
if (!remote || !input_dev) {
- retval = -ENOMEM;
+ error = -ENOMEM;
goto fail1;
}
@@ -458,19 +458,19 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma);
if (!remote->in_buffer) {
- retval = -ENOMEM;
+ error = -ENOMEM;
goto fail1;
}
remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!remote->irq_urb) {
- retval = -ENOMEM;
+ error = -ENOMEM;
goto fail2;
}
- retval = keyspan_setup(udev);
- if (retval) {
- retval = -ENODEV;
+ error = keyspan_setup(udev);
+ if (error) {
+ error = -ENODEV;
goto fail3;
}
@@ -495,14 +495,15 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
input_dev->name = remote->name;
input_dev->phys = remote->phys;
usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &interface->dev;
+ input_dev->dev.parent = &interface->dev;
input_dev->evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */
for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
if (keyspan_key_table[i] != KEY_RESERVED)
set_bit(keyspan_key_table[i], input_dev->keybit);
- input_dev->private = remote;
+ input_set_drvdata(input_dev, remote);
+
input_dev->open = keyspan_open;
input_dev->close = keyspan_close;
@@ -517,7 +518,9 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* we can register the device now, as it is ready */
- input_register_device(remote->input);
+ error = input_register_device(remote->input);
+ if (error)
+ goto fail3;
/* save our data pointer in this interface device */
usb_set_intfdata(interface, remote);
@@ -529,7 +532,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
fail1: kfree(remote);
input_free_device(input_dev);
- return retval;
+ return error;
}
/*
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 8d6c3837bad..e9f26e766b4 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -63,7 +63,7 @@ static int __devinit m68kspkr_probe(struct platform_device *dev)
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
diff --git a/drivers/usb/input/map_to_7segment.h b/drivers/input/misc/map_to_7segment.h
index a424094d9fe..a424094d9fe 100644
--- a/drivers/usb/input/map_to_7segment.h
+++ b/drivers/input/misc/map_to_7segment.h
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index afd322185bb..31989dcd922 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -78,7 +78,7 @@ static int __devinit pcspkr_probe(struct platform_device *dev)
pcspkr_dev->id.vendor = 0x001f;
pcspkr_dev->id.product = 0x0001;
pcspkr_dev->id.version = 0x0100;
- pcspkr_dev->cdev.dev = &dev->dev;
+ pcspkr_dev->dev.parent = &dev->dev;
pcspkr_dev->evbit[0] = BIT(EV_SND);
pcspkr_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
diff --git a/drivers/usb/input/powermate.c b/drivers/input/misc/powermate.c
index fea97e5437f..448a470d28f 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -252,7 +252,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
static int powermate_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int _value)
{
unsigned int command = (unsigned int)_value;
- struct powermate_device *pm = dev->private;
+ struct powermate_device *pm = input_get_drvdata(dev);
if (type == EV_MSC && code == MSC_PULSELED){
/*
@@ -291,12 +291,10 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev
static void powermate_free_buffers(struct usb_device *udev, struct powermate_device *pm)
{
- if (pm->data)
- usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
- pm->data, pm->data_dma);
- if (pm->configcr)
- usb_buffer_free(udev, sizeof(*(pm->configcr)),
- pm->configcr, pm->configcr_dma);
+ usb_buffer_free(udev, POWERMATE_PAYLOAD_SIZE_MAX,
+ pm->data, pm->data_dma);
+ usb_buffer_free(udev, sizeof(*(pm->configcr)),
+ pm->configcr, pm->configcr_dma);
}
/* Called whenever a USB device matching one in our supported devices table is connected */
@@ -308,7 +306,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
struct powermate_device *pm;
struct input_dev *input_dev;
int pipe, maxp;
- int err = -ENOMEM;
+ int error = -ENOMEM;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
@@ -359,8 +357,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
input_dev->phys = pm->phys;
usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = pm;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, pm);
input_dev->event = powermate_input_event;
@@ -387,11 +386,14 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
/* register our interrupt URB with the USB system */
if (usb_submit_urb(pm->irq, GFP_KERNEL)) {
- err = -EIO;
+ error = -EIO;
goto fail4;
}
- input_register_device(pm->input);
+ error = input_register_device(pm->input);
+ if (error)
+ goto fail5;
+
/* force an update of everything */
pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
@@ -400,12 +402,13 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
usb_set_intfdata(intf, pm);
return 0;
-fail4: usb_free_urb(pm->config);
-fail3: usb_free_urb(pm->irq);
-fail2: powermate_free_buffers(udev, pm);
-fail1: input_free_device(input_dev);
+ fail5: usb_kill_urb(pm->irq);
+ fail4: usb_free_urb(pm->config);
+ fail3: usb_free_urb(pm->irq);
+ fail2: powermate_free_buffers(udev, pm);
+ fail1: input_free_device(input_dev);
kfree(pm);
- return err;
+ return error;
}
/* Called when a USB device we've accepted ownership of is removed */
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 106c94f33b9..e36ec1d92be 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -28,7 +28,7 @@ struct sparcspkr_state {
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
+ struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
unsigned int count = 0;
unsigned long flags;
@@ -61,7 +61,7 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
+ struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
unsigned int count = 0;
unsigned long flags;
@@ -113,7 +113,7 @@ static int __devinit sparcspkr_probe(struct device *dev)
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = dev;
+ input_dev->dev.parent = dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 42556232c52..a56ad4ba8fe 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -33,7 +33,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/input.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@@ -41,9 +40,7 @@
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct uinput_device *udev;
-
- udev = dev->private;
+ struct uinput_device *udev = input_get_drvdata(dev);
udev->buff[udev->head].type = type;
udev->buff[udev->head].code = code;
@@ -136,7 +133,7 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff
request.u.upload.effect = effect;
request.u.upload.old = old;
- retval = uinput_request_reserve_slot(dev->private, &request);
+ retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
if (!retval)
retval = uinput_request_submit(dev, &request);
@@ -156,7 +153,7 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
request.code = UI_FF_ERASE;
request.u.effect_id = effect_id;
- retval = uinput_request_reserve_slot(dev->private, &request);
+ retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request);
if (!retval)
retval = uinput_request_submit(dev, &request);
@@ -274,7 +271,7 @@ static int uinput_allocate_device(struct uinput_device *udev)
return -ENOMEM;
udev->dev->event = uinput_dev_event;
- udev->dev->private = udev;
+ input_set_drvdata(udev->dev, udev);
return 0;
}
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index e1183aeb8ed..961aad7a047 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -50,7 +50,7 @@
MODULE_AUTHOR("Miloslav Trmac <mitr@volny.cz>");
MODULE_DESCRIPTION("Wistron laptop button driver");
MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
static int force; /* = 0; */
module_param(force, bool, 0);
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(force, "Load even if computer is not in database");
static char *keymap_name; /* = NULL; */
module_param_named(keymap, keymap_name, charp, 0);
-MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected");
+MODULE_PARM_DESC(keymap, "Keymap name, if it can't be autodetected [generic, 1557/MS2141]");
static struct platform_device *wistron_device;
@@ -233,10 +233,20 @@ static void bios_set_state(u8 subsys, int enable)
struct key_entry {
char type; /* See KE_* below */
u8 code;
- unsigned keycode; /* For KE_KEY */
+ union {
+ u16 keycode; /* For KE_KEY */
+ struct { /* For KE_SW */
+ u8 code;
+ u8 value;
+ } sw;
+ };
};
-enum { KE_END, KE_KEY, KE_WIFI, KE_BLUETOOTH };
+enum { KE_END, KE_KEY, KE_SW, KE_WIFI, KE_BLUETOOTH };
+
+#define FE_MAIL_LED 0x01
+#define FE_WIFI_LED 0x02
+#define FE_UNTESTED 0x80
static const struct key_entry *keymap; /* = NULL; Current key map */
static int have_wifi;
@@ -256,93 +266,341 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
return 1;
}
-static struct key_entry keymap_empty[] = {
+static struct key_entry keymap_empty[] __initdata = {
{ KE_END, 0 }
};
-static struct key_entry keymap_fs_amilo_pro_v2000[] = {
- { KE_KEY, 0x01, KEY_HELP },
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_WIFI, 0x30, 0 },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
+static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_WIFI, 0x30 },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
{ KE_END, 0 }
};
-static struct key_entry keymap_fujitsu_n3510[] = {
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_KEY, 0x36, KEY_WWW },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x71, KEY_STOPCD },
- { KE_KEY, 0x72, KEY_PLAYPAUSE },
- { KE_KEY, 0x74, KEY_REWIND },
- { KE_KEY, 0x78, KEY_FORWARD },
+static struct key_entry keymap_fujitsu_n3510[] __initdata = {
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x71, {KEY_STOPCD} },
+ { KE_KEY, 0x72, {KEY_PLAYPAUSE} },
+ { KE_KEY, 0x74, {KEY_REWIND} },
+ { KE_KEY, 0x78, {KEY_FORWARD} },
{ KE_END, 0 }
};
-static struct key_entry keymap_wistron_ms2111[] = {
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_KEY, 0x13, KEY_PROG3 },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
- { KE_END, 0 }
+static struct key_entry keymap_wistron_ms2111[] __initdata = {
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_END, FE_MAIL_LED }
+};
+
+static struct key_entry keymap_wistron_md40100[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+ { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
};
-static struct key_entry keymap_wistron_ms2141[] = {
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_WIFI, 0x30, 0 },
- { KE_KEY, 0x22, KEY_REWIND },
- { KE_KEY, 0x23, KEY_FORWARD },
- { KE_KEY, 0x24, KEY_PLAYPAUSE },
- { KE_KEY, 0x25, KEY_STOPCD },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
+static struct key_entry keymap_wistron_ms2141[] __initdata = {
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_WIFI, 0x30 },
+ { KE_KEY, 0x22, {KEY_REWIND} },
+ { KE_KEY, 0x23, {KEY_FORWARD} },
+ { KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+ { KE_KEY, 0x25, {KEY_STOPCD} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
{ KE_END, 0 }
};
-static struct key_entry keymap_acer_aspire_1500[] = {
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_WIFI, 0x30, 0 },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
- { KE_BLUETOOTH, 0x44, 0 },
- { KE_END, 0 }
+static struct key_entry keymap_acer_aspire_1500[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_WIFI, 0x30 },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x49, {KEY_CONFIG} },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_END, FE_UNTESTED }
};
-static struct key_entry keymap_acer_travelmate_240[] = {
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_BLUETOOTH, 0x44, 0 },
- { KE_WIFI, 0x30, 0 },
- { KE_END, 0 }
+static struct key_entry keymap_acer_aspire_1600[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x49, {KEY_CONFIG} },
+ { KE_WIFI, 0x30 },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+/* 3020 has been tested */
+static struct key_entry keymap_acer_aspire_5020[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x6a, {KEY_CONFIG} },
+ { KE_WIFI, 0x30 },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_2410[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x6d, {KEY_POWER} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x6a, {KEY_CONFIG} },
+ { KE_WIFI, 0x30 },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_110[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x20, {KEY_VOLUMEUP} },
+ { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
+ { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
+ { KE_WIFI, 0x30 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_300[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x20, {KEY_VOLUMEUP} },
+ { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_WIFI, 0x30 },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
};
-static struct key_entry keymap_aopen_1559as[] = {
- { KE_KEY, 0x01, KEY_HELP },
- { KE_KEY, 0x06, KEY_PROG3 },
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_WIFI, 0x30, 0 },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
+static struct key_entry keymap_acer_travelmate_380[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x03, {KEY_POWER} }, /* not 370 */
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_WIFI, 0x30 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+/* unusual map */
+static struct key_entry keymap_acer_travelmate_220[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x11, {KEY_MAIL} },
+ { KE_KEY, 0x12, {KEY_WWW} },
+ { KE_KEY, 0x13, {KEY_PROG2} },
+ { KE_KEY, 0x31, {KEY_PROG1} },
+ { KE_END, FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_230[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_END, FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_240[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_WIFI, 0x30 },
+ { KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_350[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_MAIL} },
+ { KE_KEY, 0x14, {KEY_PROG3} },
+ { KE_KEY, 0x15, {KEY_WWW} },
+ { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_acer_travelmate_360[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_MAIL} },
+ { KE_KEY, 0x14, {KEY_PROG3} },
+ { KE_KEY, 0x15, {KEY_WWW} },
+ { KE_KEY, 0x40, {KEY_WLAN} },
+ { KE_END, FE_WIFI_LED | FE_UNTESTED } /* no mail led */
+};
+
+/* Wifi subsystem only activates the led. Therefore we need to pass
+ * wifi event as a normal key, then userspace can really change the wifi state.
+ * TODO we need to export led state to userspace (wifi and mail) */
+static struct key_entry keymap_acer_travelmate_610[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_KEY, 0x14, {KEY_MAIL} },
+ { KE_KEY, 0x15, {KEY_WWW} },
+ { KE_KEY, 0x40, {KEY_WLAN} },
+ { KE_END, FE_MAIL_LED | FE_WIFI_LED }
+};
+
+static struct key_entry keymap_acer_travelmate_630[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x08, {KEY_MUTE} }, /* not 620 */
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_KEY, 0x20, {KEY_VOLUMEUP} },
+ { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_WIFI, 0x30 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_aopen_1559as[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x06, {KEY_PROG3} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_WIFI, 0x30 },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
{ KE_END, 0 },
};
-static struct key_entry keymap_fs_amilo_d88x0[] = {
- { KE_KEY, 0x01, KEY_HELP },
- { KE_KEY, 0x08, KEY_MUTE },
- { KE_KEY, 0x31, KEY_MAIL },
- { KE_KEY, 0x36, KEY_WWW },
- { KE_KEY, 0x11, KEY_PROG1 },
- { KE_KEY, 0x12, KEY_PROG2 },
- { KE_KEY, 0x13, KEY_PROG3 },
+static struct key_entry keymap_fs_amilo_d88x0[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_END, FE_MAIL_LED | FE_WIFI_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_md2900[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_WIFI, 0x30 },
+ { KE_END, FE_MAIL_LED | FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_md96500[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+ { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x20, {KEY_VOLUMEUP} },
+ { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+ { KE_KEY, 0x22, {KEY_REWIND} },
+ { KE_KEY, 0x23, {KEY_FORWARD} },
+ { KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+ { KE_KEY, 0x25, {KEY_STOPCD} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_WIFI, 0x30 },
+ { KE_BLUETOOTH, 0x44 },
+ { KE_END, FE_UNTESTED }
+};
+
+static struct key_entry keymap_wistron_generic[] __initdata = {
+ { KE_KEY, 0x01, {KEY_HELP} },
+ { KE_KEY, 0x02, {KEY_CONFIG} },
+ { KE_KEY, 0x03, {KEY_POWER} },
+ { KE_KEY, 0x05, {KEY_SWITCHVIDEOMODE} }, /* Display selection */
+ { KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+ { KE_KEY, 0x08, {KEY_MUTE} },
+ { KE_KEY, 0x11, {KEY_PROG1} },
+ { KE_KEY, 0x12, {KEY_PROG2} },
+ { KE_KEY, 0x13, {KEY_PROG3} },
+ { KE_KEY, 0x14, {KEY_MAIL} },
+ { KE_KEY, 0x15, {KEY_WWW} },
+ { KE_KEY, 0x20, {KEY_VOLUMEUP} },
+ { KE_KEY, 0x21, {KEY_VOLUMEDOWN} },
+ { KE_KEY, 0x22, {KEY_REWIND} },
+ { KE_KEY, 0x23, {KEY_FORWARD} },
+ { KE_KEY, 0x24, {KEY_PLAYPAUSE} },
+ { KE_KEY, 0x25, {KEY_STOPCD} },
+ { KE_KEY, 0x31, {KEY_MAIL} },
+ { KE_KEY, 0x36, {KEY_WWW} },
+ { KE_KEY, 0x37, {KEY_DISPLAYTOGGLE} }, /* Display on/off */
+ { KE_KEY, 0x40, {KEY_WLAN} },
+ { KE_KEY, 0x49, {KEY_CONFIG} },
+ { KE_SW, 0x4a, {.sw = {SW_LID, 1}} }, /* lid close */
+ { KE_SW, 0x4b, {.sw = {SW_LID, 0}} }, /* lid open */
+ { KE_KEY, 0x6a, {KEY_CONFIG} },
+ { KE_KEY, 0x6d, {KEY_POWER} },
+ { KE_KEY, 0x71, {KEY_STOPCD} },
+ { KE_KEY, 0x72, {KEY_PLAYPAUSE} },
+ { KE_KEY, 0x74, {KEY_REWIND} },
+ { KE_KEY, 0x78, {KEY_FORWARD} },
+ { KE_WIFI, 0x30 },
+ { KE_BLUETOOTH, 0x44 },
{ KE_END, 0 }
};
@@ -390,6 +648,133 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
{
.callback = dmi_matched,
+ .ident = "Acer Aspire 1600",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1600"),
+ },
+ .driver_data = keymap_acer_aspire_1600
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer Aspire 3020",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
+ },
+ .driver_data = keymap_acer_aspire_5020
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer Aspire 5020",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
+ },
+ .driver_data = keymap_acer_aspire_5020
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 2100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2100"),
+ },
+ .driver_data = keymap_acer_aspire_5020
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 2410",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2410"),
+ },
+ .driver_data = keymap_acer_travelmate_2410
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate C300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C300"),
+ },
+ .driver_data = keymap_acer_travelmate_300
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate C100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C100"),
+ },
+ .driver_data = keymap_acer_travelmate_300
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate C110",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate C110"),
+ },
+ .driver_data = keymap_acer_travelmate_110
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 380",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 380"),
+ },
+ .driver_data = keymap_acer_travelmate_380
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 370",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 370"),
+ },
+ .driver_data = keymap_acer_travelmate_380 /* keyboard minus 1 key */
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 220",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 220"),
+ },
+ .driver_data = keymap_acer_travelmate_220
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 260",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 260"),
+ },
+ .driver_data = keymap_acer_travelmate_220
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 230",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 230"),
+ /* acerhk looks for "TravelMate F4..." ?! */
+ },
+ .driver_data = keymap_acer_travelmate_230
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 280",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 280"),
+ },
+ .driver_data = keymap_acer_travelmate_230
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer TravelMate 240",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -399,6 +784,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
{
.callback = dmi_matched,
+ .ident = "Acer TravelMate 250",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 250"),
+ },
+ .driver_data = keymap_acer_travelmate_240
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer TravelMate 2424NWXCi",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -408,6 +802,51 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
{
.callback = dmi_matched,
+ .ident = "Acer TravelMate 350",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 350"),
+ },
+ .driver_data = keymap_acer_travelmate_350
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 360",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+ },
+ .driver_data = keymap_acer_travelmate_360
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 610",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 610"),
+ },
+ .driver_data = keymap_acer_travelmate_610
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 620",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 620"),
+ },
+ .driver_data = keymap_acer_travelmate_630
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 630",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 630"),
+ },
+ .driver_data = keymap_acer_travelmate_630
+ },
+ {
+ .callback = dmi_matched,
.ident = "AOpen 1559AS",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "E2U"),
@@ -426,6 +865,51 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
{
.callback = dmi_matched,
+ .ident = "Medion MD 40100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WID2000"),
+ },
+ .driver_data = keymap_wistron_md40100
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Medion MD 2900",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2000"),
+ },
+ .driver_data = keymap_wistron_md2900
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Medion MD 96500",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2040"),
+ },
+ .driver_data = keymap_wistron_md96500
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Medion MD 95400",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2050"),
+ },
+ .driver_data = keymap_wistron_md96500
+ },
+ {
+ .callback = dmi_matched,
+ .ident = "Fujitsu Siemens Amilo D7820",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), /* not sure */
+ DMI_MATCH(DMI_PRODUCT_NAME, "Amilo D"),
+ },
+ .driver_data = keymap_fs_amilo_d88x0
+ },
+ {
+ .callback = dmi_matched,
.ident = "Fujitsu Siemens Amilo D88x0",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
@@ -436,17 +920,39 @@ static struct dmi_system_id dmi_ids[] __initdata = {
{ NULL, }
};
+/* Copy the good keymap, as the original ones are free'd */
+static int __init copy_keymap(void)
+{
+ const struct key_entry *key;
+ struct key_entry *new_keymap;
+ unsigned int length = 1;
+
+ for (key = keymap; key->type != KE_END; key++)
+ length++;
+
+ new_keymap = kmalloc(length * sizeof(struct key_entry), GFP_KERNEL);
+ if (!new_keymap)
+ return -ENOMEM;
+
+ memcpy(new_keymap, keymap, length * sizeof(struct key_entry));
+ keymap = new_keymap;
+
+ return 0;
+}
+
static int __init select_keymap(void)
{
+ dmi_check_system(dmi_ids);
if (keymap_name != NULL) {
if (strcmp (keymap_name, "1557/MS2141") == 0)
keymap = keymap_wistron_ms2141;
+ else if (strcmp (keymap_name, "generic") == 0)
+ keymap = keymap_wistron_generic;
else {
printk(KERN_ERR "wistron_btns: Keymap unknown\n");
return -EINVAL;
}
}
- dmi_check_system(dmi_ids);
if (keymap == NULL) {
if (!force) {
printk(KERN_ERR "wistron_btns: System unknown\n");
@@ -454,7 +960,8 @@ static int __init select_keymap(void)
}
keymap = keymap_empty;
}
- return 0;
+
+ return copy_keymap();
}
/* Input layer interface */
@@ -476,12 +983,28 @@ static int __devinit setup_input_dev(void)
input_dev->cdev.dev = &wistron_device->dev;
for (key = keymap; key->type != KE_END; key++) {
- if (key->type == KE_KEY) {
- input_dev->evbit[LONG(EV_KEY)] = BIT(EV_KEY);
- set_bit(key->keycode, input_dev->keybit);
+ switch (key->type) {
+ case KE_KEY:
+ set_bit(EV_KEY, input_dev->evbit);
+ set_bit(key->keycode, input_dev->keybit);
+ break;
+
+ case KE_SW:
+ set_bit(EV_SW, input_dev->evbit);
+ set_bit(key->sw.code, input_dev->swbit);
+ break;
+
+ default:
+ ;
}
}
+ /* reads information flags on KE_END */
+ if (key->code & FE_UNTESTED)
+ printk(KERN_WARNING "Untested laptop multimedia keys, "
+ "please report success or failure to eric.piel"
+ "@tremplin-utc.net\n");
+
error = input_register_device(input_dev);
if (error) {
input_free_device(input_dev);
@@ -499,6 +1022,12 @@ static void report_key(unsigned keycode)
input_sync(input_dev);
}
+static void report_switch(unsigned code, int value)
+{
+ input_report_switch(input_dev, code, value);
+ input_sync(input_dev);
+}
+
/* Driver core */
static int wifi_enabled;
@@ -519,6 +1048,10 @@ static void handle_key(u8 code)
report_key(key->keycode);
break;
+ case KE_SW:
+ report_switch(key->sw.code, key->sw.value);
+ break;
+
case KE_WIFI:
if (have_wifi) {
wifi_enabled = !wifi_enabled;
@@ -534,6 +1067,7 @@ static void handle_key(u8 code)
break;
case KE_END:
+ break;
default:
BUG();
}
@@ -690,6 +1224,7 @@ static void __exit wb_module_exit(void)
platform_device_unregister(wistron_device);
platform_driver_unregister(&wistron_driver);
unmap_bios();
+ kfree(keymap);
}
module_init(wb_module_init);
diff --git a/drivers/usb/input/yealink.c b/drivers/input/misc/yealink.c
index caff8e6d744..ab15880fd56 100644
--- a/drivers/usb/input/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -29,7 +29,7 @@
* This driver is based on:
* - the usbb2k-api http://savannah.nongnu.org/projects/usbb2k-api/
* - information from http://memeteau.free.fr/usbb2k
- * - the xpad-driver drivers/usb/input/xpad.c
+ * - the xpad-driver drivers/input/joystick/xpad.c
*
* Thanks to:
* - Olivier Vandorpe, for providing the usbb2k-api.
@@ -502,7 +502,7 @@ static int input_ev(struct input_dev *dev, unsigned int type,
static int input_open(struct input_dev *dev)
{
- struct yealink_dev *yld = dev->private;
+ struct yealink_dev *yld = input_get_drvdata(dev);
int i, ret;
dbg("%s", __FUNCTION__);
@@ -529,7 +529,7 @@ static int input_open(struct input_dev *dev)
static void input_close(struct input_dev *dev)
{
- struct yealink_dev *yld = dev->private;
+ struct yealink_dev *yld = input_get_drvdata(dev);
usb_kill_urb(yld->urb_ctl);
usb_kill_urb(yld->urb_irq);
@@ -818,18 +818,17 @@ static int usb_cleanup(struct yealink_dev *yld, int err)
else
input_unregister_device(yld->idev);
}
- if (yld->ctl_req)
- usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
- yld->ctl_req, yld->ctl_req_dma);
- if (yld->ctl_data)
- usb_buffer_free(yld->udev, USB_PKT_LEN,
- yld->ctl_data, yld->ctl_dma);
- if (yld->irq_data)
- usb_buffer_free(yld->udev, USB_PKT_LEN,
- yld->irq_data, yld->irq_dma);
-
- usb_free_urb(yld->urb_irq); /* parameter validation in core/urb */
- usb_free_urb(yld->urb_ctl); /* parameter validation in core/urb */
+
+ usb_free_urb(yld->urb_irq);
+ usb_free_urb(yld->urb_ctl);
+
+ usb_buffer_free(yld->udev, sizeof(*(yld->ctl_req)),
+ yld->ctl_req, yld->ctl_req_dma);
+ usb_buffer_free(yld->udev, USB_PKT_LEN,
+ yld->ctl_data, yld->ctl_dma);
+ usb_buffer_free(yld->udev, USB_PKT_LEN,
+ yld->irq_data, yld->irq_dma);
+
kfree(yld);
return err;
}
@@ -937,9 +936,10 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
input_dev->name = nfo->name;
input_dev->phys = yld->phys;
usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, yld);
- input_dev->private = yld;
input_dev->open = input_open;
input_dev->close = input_close;
/* input_dev->event = input_ev; TODO */
@@ -955,7 +955,9 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
}
}
- input_register_device(yld->idev);
+ ret = input_register_device(yld->idev);
+ if (ret)
+ return usb_cleanup(yld, ret);
usb_set_intfdata(intf, yld);
diff --git a/drivers/usb/input/yealink.h b/drivers/input/misc/yealink.h
index 48af0be9cbd..48af0be9cbd 100644
--- a/drivers/usb/input/yealink.h
+++ b/drivers/input/misc/yealink.h
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 35d998c3e57..2ccc114b3ff 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -2,7 +2,7 @@
# Mouse driver configuration
#
menuconfig INPUT_MOUSE
- bool "Mouse"
+ bool "Mice"
default y
help
Say Y here, and a list of supported mice will be displayed.
@@ -19,7 +19,7 @@ config MOUSE_PS2
select SERIO_LIBPS2
select SERIO_I8042 if X86_PC
select SERIO_GSCPS2 if GSC
- ---help---
+ help
Say Y here if you have a PS/2 mouse connected to your system. This
includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
mice with wheels and extra buttons, Microsoft, Logitech or Genius
@@ -37,10 +37,69 @@ config MOUSE_PS2
To compile this driver as a module, choose M here: the
module will be called psmouse.
+config MOUSE_PS2_ALPS
+ bool "ALPS PS/2 mouse protocol extension" if EMBEDDED
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have an ALPS PS/2 touchpad connected to
+ your system.
+
+ If unsure, say Y.
+
+config MOUSE_PS2_LOGIPS2PP
+ bool "Logictech PS/2++ mouse protocol extension" if EMBEDDED
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a Logictech PS/2++ mouse connected to
+ your system.
+
+ If unsure, say Y.
+
+config MOUSE_PS2_SYNAPTICS
+ bool "Synaptics PS/2 mouse protocol extension" if EMBEDDED
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a Synaptics PS/2 TouchPad connected to
+ your system.
+
+ If unsure, say Y.
+
+config MOUSE_PS2_LIFEBOOK
+ bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a Fujitsu B-series Lifebook PS/2
+ TouchScreen connected to your system.
+
+ If unsure, say Y.
+
+config MOUSE_PS2_TRACKPOINT
+ bool "IBM Trackpoint PS/2 mouse protocol extension" if EMBEDDED
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have an IBM Trackpoint PS/2 mouse connected
+ to your system.
+
+ If unsure, say Y.
+
+config MOUSE_PS2_TOUCHKIT
+ bool "eGalax TouchKit PS/2 protocol extension"
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have an eGalax TouchKit PS/2 touchscreen
+ connected to your system.
+
+ If unsure, say N.
+
config MOUSE_SERIAL
tristate "Serial mouse"
select SERIO
- ---help---
+ help
Say Y here if you have a serial (RS-232, COM port) mouse connected
to your system. This includes Sun, MouseSystems, Microsoft,
Logitech and all other compatible serial mice.
@@ -50,6 +109,26 @@ config MOUSE_SERIAL
To compile this driver as a module, choose M here: the
module will be called sermouse.
+config MOUSE_APPLETOUCH
+ tristate "Apple USB Touchpad support"
+ select USB
+ help
+ Say Y here if you want to use an Apple USB Touchpad.
+
+ These are the touchpads that can be found on post-February 2005
+ Apple Powerbooks (prior models have a Synaptics touchpad connected
+ to the ADB bus).
+
+ This driver provides a basic mouse driver but can be interfaced
+ with the synaptics X11 driver to provide acceleration and
+ scrolling in X11.
+
+ For further information, see
+ <file:Documentation/input/appletouch.txt>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called appletouch.
+
config MOUSE_INPORT
tristate "InPort/MS/ATIXL busmouse"
depends on ISA
@@ -96,6 +175,17 @@ config MOUSE_AMIGA
To compile this driver as a module, choose M here: the
module will be called amimouse.
+config MOUSE_ATARI
+ tristate "Atari mouse"
+ depends on ATARI
+ select ATARI_KBD_CORE
+ help
+ Say Y here if you have an Atari and want its native mouse
+ supported by the kernel.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atarimouse.
+
config MOUSE_RISCPC
tristate "Acorn RiscPC mouse"
depends on ARCH_ACORN
@@ -118,7 +208,7 @@ config MOUSE_VSXXXAA
digitizer (VSXXX-AB) DEC produced.
config MOUSE_HIL
- tristate "HIL pointers (mice etc)."
+ tristate "HIL pointers (mice etc)."
depends on GSC || HP300
select HP_SDC
select HIL_MLC
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 21a1de61a79..aa4ba878533 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -5,6 +5,8 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
+obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
+obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
@@ -14,4 +16,10 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
-psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o trackpoint.o
+psmouse-objs := psmouse-base.o synaptics.o
+
+psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
+psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
+psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
+psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
+psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4e71a66fc7f..cf3e4664e72 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -424,14 +424,15 @@ int alps_init(struct psmouse *psmouse)
struct input_dev *dev1 = psmouse->dev, *dev2;
int version;
- psmouse->private = priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
+ priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
dev2 = input_allocate_device();
if (!priv || !dev2)
goto init_fail;
priv->dev2 = dev2;
- if (!(priv->i = alps_get_model(psmouse, &version)))
+ priv->i = alps_get_model(psmouse, &version);
+ if (!priv->i)
goto init_fail;
if ((priv->i->flags & ALPS_PASS) && alps_passthrough_mode(psmouse, 1))
@@ -480,7 +481,8 @@ int alps_init(struct psmouse *psmouse)
dev2->relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
dev2->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- input_register_device(priv->dev2);
+ if (input_register_device(priv->dev2))
+ goto init_fail;
psmouse->protocol_handler = alps_process_byte;
psmouse->poll = alps_poll;
@@ -491,9 +493,11 @@ int alps_init(struct psmouse *psmouse)
/* We are having trouble resyncing ALPS touchpads so disable it for now */
psmouse->resync_time = 0;
+ psmouse->private = priv;
return 0;
init_fail:
+ psmouse_reset(psmouse);
input_free_device(dev2);
kfree(priv);
return -1;
@@ -504,7 +508,8 @@ int alps_detect(struct psmouse *psmouse, int set_properties)
int version;
const struct alps_model_info *model;
- if (!(model = alps_get_model(psmouse, &version)))
+ model = alps_get_model(psmouse, &version);
+ if (!model)
return -1;
if (set_properties) {
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 69db7325a49..4bbddc99962 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,9 +12,6 @@
#ifndef _ALPS_H
#define _ALPS_H
-int alps_detect(struct psmouse *psmouse, int set_properties);
-int alps_init(struct psmouse *psmouse);
-
struct alps_model_info {
unsigned char signature[3];
unsigned char byte0, mask0;
@@ -23,10 +20,23 @@ struct alps_model_info {
struct alps_data {
struct input_dev *dev2; /* Relative device */
- char name[32]; /* Name */
char phys[32]; /* Phys */
const struct alps_model_info *i;/* Info */
int prev_fin; /* Finger bit from previous packet */
};
+#ifdef CONFIG_MOUSE_PS2_ALPS
+int alps_detect(struct psmouse *psmouse, int set_properties);
+int alps_init(struct psmouse *psmouse);
+#else
+inline int alps_detect(struct psmouse *psmouse, int set_properties)
+{
+ return -ENOSYS;
+}
+inline int alps_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_ALPS */
+
#endif
diff --git a/drivers/usb/input/appletouch.c b/drivers/input/mouse/appletouch.c
index c77291d3d06..e3215267db1 100644
--- a/drivers/usb/input/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -466,7 +466,7 @@ exit:
static int atp_open(struct input_dev *input)
{
- struct atp *dev = input->private;
+ struct atp *dev = input_get_drvdata(input);
if (usb_submit_urb(dev->urb, GFP_ATOMIC))
return -EIO;
@@ -477,7 +477,7 @@ static int atp_open(struct input_dev *input)
static void atp_close(struct input_dev *input)
{
- struct atp *dev = input->private;
+ struct atp *dev = input_get_drvdata(input);
usb_kill_urb(dev->urb);
dev->open = 0;
@@ -491,8 +491,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int int_in_endpointAddr = 0;
- int i, retval = -ENOMEM;
-
+ int i, error = -ENOMEM;
/* set up the endpoint information */
/* use only the first interrupt-in endpoint */
@@ -567,17 +566,13 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
}
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->urb) {
- retval = -ENOMEM;
+ if (!dev->urb)
goto err_free_devs;
- }
dev->data = usb_buffer_alloc(dev->udev, dev->datalen, GFP_KERNEL,
&dev->urb->transfer_dma);
- if (!dev->data) {
- retval = -ENOMEM;
+ if (!dev->data)
goto err_free_urb;
- }
usb_fill_int_urb(dev->urb, udev,
usb_rcvintpipe(udev, int_in_endpointAddr),
@@ -589,9 +584,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
input_dev->name = "appletouch";
input_dev->phys = dev->phys;
usb_to_input_id(dev->udev, &input_dev->id);
- input_dev->cdev.dev = &iface->dev;
+ input_dev->dev.parent = &iface->dev;
+
+ input_set_drvdata(input_dev, dev);
- input_dev->private = dev;
input_dev->open = atp_open;
input_dev->close = atp_close;
@@ -633,20 +629,25 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
set_bit(BTN_LEFT, input_dev->keybit);
- input_register_device(dev->input);
+ error = input_register_device(dev->input);
+ if (error)
+ goto err_free_buffer;
/* save our data pointer in this interface device */
usb_set_intfdata(iface, dev);
return 0;
+ err_free_buffer:
+ usb_buffer_free(dev->udev, dev->datalen,
+ dev->data, dev->urb->transfer_dma);
err_free_urb:
usb_free_urb(dev->urb);
err_free_devs:
usb_set_intfdata(iface, NULL);
kfree(dev);
input_free_device(input_dev);
- return retval;
+ return error;
}
static void atp_disconnect(struct usb_interface *iface)
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
new file mode 100644
index 00000000000..43ab6566fb6
--- /dev/null
+++ b/drivers/input/mouse/atarimouse.c
@@ -0,0 +1,160 @@
+/*
+ * Atari mouse driver for Linux/m68k
+ *
+ * Copyright (c) 2005 Michael Schmitz
+ *
+ * Based on:
+ * Amiga mouse driver for Linux/m68k
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ */
+/*
+ * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
+ * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
+ * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
+ * This driver only deals with handing key events off to the input layer.
+ *
+ * Largely based on the old:
+ *
+ * Atari Mouse Driver for Linux
+ * by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
+ *
+ * 1996/02/11 Andreas Schwab
+ * Module support
+ * Allow multiple open's
+ *
+ * Converted to use new generic busmouse code. 5 Apr 1998
+ * Russell King <rmk@arm.uk.linux.org>
+ */
+
+
+/*
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/atarihw.h>
+#include <asm/atarikb.h>
+#include <asm/atariints.h>
+
+MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
+MODULE_DESCRIPTION("Atari mouse driver");
+MODULE_LICENSE("GPL");
+
+static int mouse_threshold[2] = {2,2};
+
+#ifdef __MODULE__
+MODULE_PARM(mouse_threshold, "2i");
+#endif
+#ifdef FIXED_ATARI_JOYSTICK
+extern int atari_mouse_buttons;
+#endif
+static int atamouse_used = 0;
+
+static struct input_dev *atamouse_dev;
+
+static void atamouse_interrupt(char *buf)
+{
+ int buttons, dx, dy;
+
+/* ikbd_mouse_disable(); */
+
+ buttons = (buf[0] & 1) | ((buf[0] & 2) << 1);
+#ifdef FIXED_ATARI_JOYSTICK
+ buttons |= atari_mouse_buttons & 2;
+ atari_mouse_buttons = buttons;
+#endif
+/* ikbd_mouse_rel_pos(); */
+
+ /* only relative events get here */
+ dx = buf[1];
+ dy = -buf[2];
+
+ input_report_rel(atamouse_dev, REL_X, dx);
+ input_report_rel(atamouse_dev, REL_Y, dy);
+
+ input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1);
+ input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
+ input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4);
+
+ input_sync(atamouse_dev);
+
+ return;
+}
+
+static int atamouse_open(struct input_dev *dev)
+{
+ if (atamouse_used++)
+ return 0;
+
+#ifdef FIXED_ATARI_JOYSTICK
+ atari_mouse_buttons = 0;
+#endif
+ ikbd_mouse_y0_top();
+ ikbd_mouse_thresh(mouse_threshold[0], mouse_threshold[1]);
+ ikbd_mouse_rel_pos();
+ atari_input_mouse_interrupt_hook = atamouse_interrupt;
+ return 0;
+}
+
+static void atamouse_close(struct input_dev *dev)
+{
+ if (!--atamouse_used) {
+ ikbd_mouse_disable();
+ atari_mouse_interrupt_hook = NULL;
+ }
+}
+
+static int __init atamouse_init(void)
+{
+ if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
+ return -ENODEV;
+
+ if (!(atamouse_dev = input_allocate_device()))
+ return -ENOMEM;
+
+ if (!(atari_keyb_init()))
+ return -ENODEV;
+
+ atamouse_dev->name = "Atari mouse";
+ atamouse_dev->phys = "atamouse/input0";
+ atamouse_dev->id.bustype = BUS_ATARI;
+ atamouse_dev->id.vendor = 0x0001;
+ atamouse_dev->id.product = 0x0002;
+ atamouse_dev->id.version = 0x0100;
+
+ atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ atamouse_dev->open = atamouse_open;
+ atamouse_dev->close = atamouse_close;
+
+ input_register_device(atamouse_dev);
+
+ printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name);
+ return 0;
+}
+
+static void __exit atamouse_exit(void)
+{
+ input_unregister_device(atamouse_dev);
+}
+
+module_init(atamouse_init);
+module_exit(atamouse_exit);
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
index bfb174fe323..449bf4dcbbc 100644
--- a/drivers/input/mouse/hil_ptr.c
+++ b/drivers/input/mouse/hil_ptr.c
@@ -88,10 +88,12 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
idx = ptr->idx4/4;
p = data[idx - 1];
- if ((p & ~HIL_CMDCT_POL) ==
- (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL)) goto report;
- if ((p & ~HIL_CMDCT_RPL) ==
- (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL)) goto report;
+ if ((p & ~HIL_CMDCT_POL) ==
+ (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+ goto report;
+ if ((p & ~HIL_CMDCT_RPL) ==
+ (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_RPL))
+ goto report;
/* Not a poll response. See if we are loading config records. */
switch (p & HIL_PKT_DATA_MASK) {
@@ -101,27 +103,32 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
for (; i < HIL_PTR_MAX_LENGTH; i++)
ptr->idd[i] = 0;
break;
+
case HIL_CMD_RSC:
for (i = 0; i < idx; i++)
ptr->rsc[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_PTR_MAX_LENGTH; i++)
ptr->rsc[i] = 0;
break;
+
case HIL_CMD_EXD:
for (i = 0; i < idx; i++)
ptr->exd[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_PTR_MAX_LENGTH; i++)
ptr->exd[i] = 0;
break;
+
case HIL_CMD_RNM:
for (i = 0; i < idx; i++)
ptr->rnm[i] = ptr->data[i] & HIL_PKT_DATA_MASK;
for (; i < HIL_PTR_MAX_LENGTH + 1; i++)
- ptr->rnm[i] = '\0';
+ ptr->rnm[i] = 0;
break;
+
default:
/* These occur when device isn't present */
- if (p == (HIL_ERR_INT | HIL_PKT_CMD)) break;
+ if (p == (HIL_ERR_INT | HIL_PKT_CMD))
+ break;
/* Anything else we'd like to know about. */
printk(KERN_WARNING PREFIX "Device sent unknown record %x\n", p);
break;
@@ -130,7 +137,8 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
report:
if ((p & HIL_CMDCT_POL) != idx - 1) {
- printk(KERN_WARNING PREFIX "Malformed poll packet %x (idx = %i)\n", p, idx);
+ printk(KERN_WARNING PREFIX
+ "Malformed poll packet %x (idx = %i)\n", p, idx);
goto out;
}
@@ -139,7 +147,7 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
laxis += i;
ax16 = ptr->idd[1] & HIL_IDD_HEADER_16BIT; /* 8 or 16bit resolution */
- absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
+ absdev = ptr->idd[1] & HIL_IDD_HEADER_ABS;
for (cnt = 1; i < laxis; i++) {
unsigned int lo,hi,val;
@@ -157,7 +165,8 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
input_report_abs(dev, ABS_X + i, val);
} else {
val = (int) (((int8_t)lo) | ((int8_t)hi<<8));
- if (i%3) val *= -1;
+ if (i%3)
+ val *= -1;
input_report_rel(dev, REL_X + i, val);
}
}
@@ -168,10 +177,11 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
btn = ptr->data[cnt++];
up = btn & 1;
btn &= 0xfe;
- if (btn == 0x8e) {
+ if (btn == 0x8e)
continue; /* TODO: proximity == touch? */
- }
- else if ((btn > 0x8c) || (btn < 0x80)) continue;
+ else
+ if ((btn > 0x8c) || (btn < 0x80))
+ continue;
btn = (btn - 0x80) >> 1;
btn = ptr->btnmap[btn];
input_report_key(dev, btn, !up);
@@ -182,14 +192,14 @@ static void hil_ptr_process_record(struct hil_ptr *ptr)
up(&ptr->sem);
}
-static void hil_ptr_process_err(struct hil_ptr *ptr) {
+static void hil_ptr_process_err(struct hil_ptr *ptr)
+{
printk(KERN_WARNING PREFIX "errored HIL packet\n");
ptr->idx4 = 0;
up(&ptr->sem);
- return;
}
-static irqreturn_t hil_ptr_interrupt(struct serio *serio,
+static irqreturn_t hil_ptr_interrupt(struct serio *serio,
unsigned char data, unsigned int flags)
{
struct hil_ptr *ptr;
@@ -197,29 +207,29 @@ static irqreturn_t hil_ptr_interrupt(struct serio *serio,
int idx;
ptr = serio_get_drvdata(serio);
- if (ptr == NULL) {
- BUG();
- return IRQ_HANDLED;
- }
+ BUG_ON(ptr == NULL);
if (ptr->idx4 >= (HIL_PTR_MAX_LENGTH * sizeof(hil_packet))) {
hil_ptr_process_err(ptr);
return IRQ_HANDLED;
}
idx = ptr->idx4/4;
- if (!(ptr->idx4 % 4)) ptr->data[idx] = 0;
+ if (!(ptr->idx4 % 4))
+ ptr->data[idx] = 0;
packet = ptr->data[idx];
packet |= ((hil_packet)data) << ((3 - (ptr->idx4 % 4)) * 8);
ptr->data[idx] = packet;
/* Records of N 4-byte hil_packets must terminate with a command. */
- if ((++(ptr->idx4)) % 4) return IRQ_HANDLED;
+ if ((++(ptr->idx4)) % 4)
+ return IRQ_HANDLED;
if ((packet & 0xffff0000) != HIL_ERR_INT) {
hil_ptr_process_err(ptr);
return IRQ_HANDLED;
}
- if (packet & HIL_PKT_CMD)
+ if (packet & HIL_PKT_CMD)
hil_ptr_process_record(ptr);
+
return IRQ_HANDLED;
}
@@ -228,10 +238,7 @@ static void hil_ptr_disconnect(struct serio *serio)
struct hil_ptr *ptr;
ptr = serio_get_drvdata(serio);
- if (ptr == NULL) {
- BUG();
- return;
- }
+ BUG_ON(ptr == NULL);
serio_close(serio);
input_unregister_device(ptr->dev);
@@ -241,7 +248,7 @@ static void hil_ptr_disconnect(struct serio *serio)
static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
{
struct hil_ptr *ptr;
- char *txt;
+ const char *txt;
unsigned int i, naxsets, btntype;
uint8_t did, *idd;
@@ -252,42 +259,40 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
if (!ptr->dev)
goto bail0;
- ptr->dev->private = ptr;
-
if (serio_open(serio, driver))
goto bail1;
serio_set_drvdata(serio, ptr);
ptr->serio = serio;
- init_MUTEX_LOCKED(&(ptr->sem));
+ init_MUTEX_LOCKED(&ptr->sem);
/* Get device info. MLC driver supplies devid/status/etc. */
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_IDD);
- down(&(ptr->sem));
+ down(&ptr->sem);
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_RSC);
- down(&(ptr->sem));
+ down(&ptr->sem);
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_RNM);
- down(&(ptr->sem));
+ down(&ptr->sem);
serio->write(serio, 0);
serio->write(serio, 0);
serio->write(serio, HIL_PKT_CMD >> 8);
serio->write(serio, HIL_CMD_EXD);
- down(&(ptr->sem));
+ down(&ptr->sem);
- up(&(ptr->sem));
+ up(&ptr->sem);
did = ptr->idd[0];
idd = ptr->idd + 1;
@@ -301,12 +306,12 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
ptr->dev->evbit[0] = BIT(EV_ABS);
txt = "absolute";
}
- if (!ptr->dev->evbit[0]) {
+ if (!ptr->dev->evbit[0])
goto bail2;
- }
ptr->nbtn = HIL_IDD_NUM_BUTTONS(idd);
- if (ptr->nbtn) ptr->dev->evbit[0] |= BIT(EV_KEY);
+ if (ptr->nbtn)
+ ptr->dev->evbit[0] |= BIT(EV_KEY);
naxsets = HIL_IDD_NUM_AXSETS(*idd);
ptr->naxes = HIL_IDD_NUM_AXES_PER_SET(*idd);
@@ -315,7 +320,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
did, txt);
printk(KERN_INFO PREFIX "HIL pointer has %i buttons and %i sets of %i axes\n",
ptr->nbtn, naxsets, ptr->naxes);
-
+
btntype = BTN_MISC;
if ((did & HIL_IDD_DID_ABS_TABLET_MASK) == HIL_IDD_DID_ABS_TABLET)
#ifdef TABLET_SIMULATES_MOUSE
@@ -325,7 +330,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
#endif
if ((did & HIL_IDD_DID_ABS_TSCREEN_MASK) == HIL_IDD_DID_ABS_TSCREEN)
btntype = BTN_TOUCH;
-
+
if ((did & HIL_IDD_DID_REL_MOUSE_MASK) == HIL_IDD_DID_REL_MOUSE)
btntype = BTN_MOUSE;
@@ -341,12 +346,10 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
}
if ((did & HIL_IDD_DID_TYPE_MASK) == HIL_IDD_DID_TYPE_REL) {
- for (i = 0; i < ptr->naxes; i++) {
+ for (i = 0; i < ptr->naxes; i++)
set_bit(REL_X + i, ptr->dev->relbit);
- }
- for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++) {
+ for (i = 3; (i < ptr->naxes + 3) && (naxsets > 1); i++)
set_bit(REL_X + i, ptr->dev->relbit);
- }
} else {
for (i = 0; i < ptr->naxes; i++) {
set_bit(ABS_X + i, ptr->dev->absbit);
@@ -375,7 +378,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
ptr->dev->id.vendor = PCI_VENDOR_ID_HP;
ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */
ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */
- ptr->dev->cdev.dev = &serio->dev;
+ ptr->dev->dev.parent = &serio->dev;
input_register_device(ptr->dev);
printk(KERN_INFO "input: %s (%s), ID: %d\n",
@@ -419,11 +422,11 @@ static int __init hil_ptr_init(void)
{
return serio_register_driver(&hil_ptr_serio_driver);
}
-
+
static void __exit hil_ptr_exit(void)
{
serio_unregister_driver(&hil_ptr_serio_driver);
}
-
+
module_init(hil_ptr_init);
module_exit(hil_ptr_exit);
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 29542f0631c..1740cadd959 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -20,6 +20,27 @@
#include "psmouse.h"
#include "lifebook.h"
+struct lifebook_data {
+ struct input_dev *dev2; /* Relative device */
+ char phys[32];
+};
+
+static const char *desired_serio_phys;
+
+static int lifebook_set_serio_phys(struct dmi_system_id *d)
+{
+ desired_serio_phys = d->driver_data;
+ return 0;
+}
+
+static unsigned char lifebook_use_6byte_proto;
+
+static int lifebook_set_6byte_proto(struct dmi_system_id *d)
+{
+ lifebook_use_6byte_proto = 1;
+ return 0;
+}
+
static struct dmi_system_id lifebook_dmi_table[] = {
{
.ident = "FLORA-ie 55mi",
@@ -56,6 +77,24 @@ static struct dmi_system_id lifebook_dmi_table[] = {
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "CF-18"),
},
+ .callback = lifebook_set_serio_phys,
+ .driver_data = "isa0060/serio3",
+ },
+ {
+ .ident = "Panasonic CF-28",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-28"),
+ },
+ .callback = lifebook_set_6byte_proto,
+ },
+ {
+ .ident = "Panasonic CF-29",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
+ },
+ .callback = lifebook_set_6byte_proto,
},
{
.ident = "Lifebook B142",
@@ -68,30 +107,70 @@ static struct dmi_system_id lifebook_dmi_table[] = {
static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{
+ struct lifebook_data *priv = psmouse->private;
+ struct input_dev *dev1 = psmouse->dev;
+ struct input_dev *dev2 = priv->dev2;
unsigned char *packet = psmouse->packet;
- struct input_dev *dev = psmouse->dev;
+ int relative_packet = packet[0] & 0x08;
- if (psmouse->pktcnt != 3)
- return PSMOUSE_GOOD_DATA;
+ if (relative_packet || !lifebook_use_6byte_proto) {
+ if (psmouse->pktcnt != 3)
+ return PSMOUSE_GOOD_DATA;
+ } else {
+ switch (psmouse->pktcnt) {
+ case 1:
+ return (packet[0] & 0xf8) == 0x00 ?
+ PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+ case 2:
+ return PSMOUSE_GOOD_DATA;
+ case 3:
+ return ((packet[2] & 0x30) << 2) == (packet[2] & 0xc0) ?
+ PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+ case 4:
+ return (packet[3] & 0xf8) == 0xc0 ?
+ PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+ case 5:
+ return (packet[4] & 0xc0) == (packet[2] & 0xc0) ?
+ PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA;
+ case 6:
+ if (((packet[5] & 0x30) << 2) != (packet[5] & 0xc0))
+ return PSMOUSE_BAD_DATA;
+ if ((packet[5] & 0xc0) != (packet[1] & 0xc0))
+ return PSMOUSE_BAD_DATA;
+ break; /* report data */
+ }
+ }
- /* calculate X and Y */
- if ((packet[0] & 0x08) == 0x00) {
- input_report_abs(dev, ABS_X,
+ if (relative_packet) {
+ if (!dev2)
+ printk(KERN_WARNING "lifebook.c: got relative packet "
+ "but no relative device set up\n");
+ } else if (lifebook_use_6byte_proto) {
+ input_report_abs(dev1, ABS_X,
+ ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f));
+ input_report_abs(dev1, ABS_Y,
+ 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f)));
+ } else {
+ input_report_abs(dev1, ABS_X,
(packet[1] | ((packet[0] & 0x30) << 4)));
- input_report_abs(dev, ABS_Y,
+ input_report_abs(dev1, ABS_Y,
1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
- } else {
- input_report_rel(dev, REL_X,
- ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
- input_report_rel(dev, REL_Y,
- -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
}
- input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
- input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
- input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+ input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04);
+ input_sync(dev1);
- input_sync(dev);
+ if (dev2) {
+ if (relative_packet) {
+ input_report_rel(dev2, REL_X,
+ ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+ input_report_rel(dev2, REL_Y,
+ -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+ }
+ input_report_key(dev2, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev2, BTN_RIGHT, packet[0] & 0x02);
+ input_sync(dev2);
+ }
return PSMOUSE_FULL_PACKET;
}
@@ -109,12 +188,20 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
you leave this call out the touchsreen will never send
absolute coordinates
*/
- param = 0x07;
+ param = lifebook_use_6byte_proto ? 0x08 : 0x07;
ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
return 0;
}
+static void lifebook_relative_mode(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param = 0x06;
+
+ ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+}
+
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
static const unsigned char params[] = { 0, 1, 2, 2, 3 };
@@ -131,6 +218,8 @@ static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolu
static void lifebook_disconnect(struct psmouse *psmouse)
{
psmouse_reset(psmouse);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
}
int lifebook_detect(struct psmouse *psmouse, int set_properties)
@@ -138,6 +227,10 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties)
if (!dmi_check_system(lifebook_dmi_table))
return -1;
+ if (desired_serio_phys &&
+ strcmp(psmouse->ps2dev.serio->phys, desired_serio_phys))
+ return -1;
+
if (set_properties) {
psmouse->vendor = "Fujitsu";
psmouse->name = "Lifebook TouchScreen";
@@ -146,24 +239,78 @@ int lifebook_detect(struct psmouse *psmouse, int set_properties)
return 0;
}
+static int lifebook_create_relative_device(struct psmouse *psmouse)
+{
+ struct input_dev *dev2;
+ struct lifebook_data *priv;
+ int error = -ENOMEM;
+
+ priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
+ dev2 = input_allocate_device();
+ if (!priv || !dev2)
+ goto err_out;
+
+ priv->dev2 = dev2;
+ snprintf(priv->phys, sizeof(priv->phys),
+ "%s/input1", psmouse->ps2dev.serio->phys);
+
+ dev2->phys = priv->phys;
+ dev2->name = "PS/2 Touchpad";
+ dev2->id.bustype = BUS_I8042;
+ dev2->id.vendor = 0x0002;
+ dev2->id.product = PSMOUSE_LIFEBOOK;
+ dev2->id.version = 0x0000;
+ dev2->dev.parent = &psmouse->ps2dev.serio->dev;
+
+ dev2->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ dev2->relbit[LONG(REL_X)] = BIT(REL_X) | BIT(REL_Y);
+ dev2->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+
+ error = input_register_device(priv->dev2);
+ if (error)
+ goto err_out;
+
+ psmouse->private = priv;
+ return 0;
+
+ err_out:
+ input_free_device(dev2);
+ kfree(priv);
+ return error;
+}
+
int lifebook_init(struct psmouse *psmouse)
{
- struct input_dev *input_dev = psmouse->dev;
+ struct input_dev *dev1 = psmouse->dev;
+ int max_coord = lifebook_use_6byte_proto ? 1024 : 4096;
if (lifebook_absolute_mode(psmouse))
return -1;
- input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
- input_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
- input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
- input_set_abs_params(input_dev, ABS_X, 0, 1024, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, 1024, 0, 0);
+ dev1->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+ dev1->relbit[0] = 0;
+ dev1->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_set_abs_params(dev1, ABS_X, 0, max_coord, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, max_coord, 0, 0);
+
+ if (!desired_serio_phys) {
+ if (lifebook_create_relative_device(psmouse)) {
+ lifebook_relative_mode(psmouse);
+ return -1;
+ }
+ }
psmouse->protocol_handler = lifebook_process_byte;
psmouse->set_resolution = lifebook_set_resolution;
psmouse->disconnect = lifebook_disconnect;
psmouse->reconnect = lifebook_absolute_mode;
+
+ psmouse->model = lifebook_use_6byte_proto ? 6 : 3;
+
+ /*
+ * Use packet size = 3 even when using 6-byte protocol because
+ * that's what POLL will return on Lifebooks (according to spec).
+ */
psmouse->pktsize = 3;
return 0;
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
index be1c0943825..c1647cf036c 100644
--- a/drivers/input/mouse/lifebook.h
+++ b/drivers/input/mouse/lifebook.h
@@ -11,7 +11,18 @@
#ifndef _LIFEBOOK_H
#define _LIFEBOOK_H
+#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
int lifebook_detect(struct psmouse *psmouse, int set_properties);
int lifebook_init(struct psmouse *psmouse);
+#else
+inline int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+ return -ENOSYS;
+}
+inline int lifebook_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+#endif
#endif
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index d3ddea26b8c..9df74b72e6c 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -200,6 +200,7 @@ static void ps2pp_disconnect(struct psmouse *psmouse)
static const struct ps2pp_info *get_model_info(unsigned char model)
{
static const struct ps2pp_info ps2pp_list[] = {
+ { 1, 0, 0 }, /* Simple 2-button mouse */
{ 12, 0, PS2PP_SIDE_BTN},
{ 13, 0, 0 },
{ 15, PS2PP_KIND_MX, /* MX1000 */
@@ -338,12 +339,12 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
param[1] = 0;
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
- if (!param[1])
- return -1;
-
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
buttons = param[1];
+ if (!model || !buttons)
+ return -1;
+
if ((model_info = get_model_info(model)) != NULL) {
/*
diff --git a/drivers/input/mouse/logips2pp.h b/drivers/input/mouse/logips2pp.h
index 64a8ec52ea6..6e5712525fd 100644
--- a/drivers/input/mouse/logips2pp.h
+++ b/drivers/input/mouse/logips2pp.h
@@ -11,6 +11,13 @@
#ifndef _LOGIPS2PP_H
#define _LOGIPS2PP_H
+#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
int ps2pp_init(struct psmouse *psmouse, int set_properties);
+#else
+inline int ps2pp_init(struct psmouse *psmouse, int set_properties)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */
#endif
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 0fe5869d7d4..f15f695777f 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -28,6 +28,7 @@
#include "alps.h"
#include "lifebook.h"
#include "trackpoint.h"
+#include "touchkit_ps2.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -569,7 +570,9 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_THINKPS;
/*
- * Try Synaptics TouchPad
+ * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol
+ * support is disabled in config - we need to know if it is synaptics so we
+ * can reset it properly after probing for intellimouse.
*/
if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) {
synaptics_hardware = 1;
@@ -605,14 +608,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
}
}
- if (max_proto > PSMOUSE_IMEX && genius_detect(psmouse, set_properties) == 0)
- return PSMOUSE_GENPS;
+ if (max_proto > PSMOUSE_IMEX) {
+
+ if (genius_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_GENPS;
- if (max_proto > PSMOUSE_IMEX && ps2pp_init(psmouse, set_properties) == 0)
- return PSMOUSE_PS2PP;
+ if (ps2pp_init(psmouse, set_properties) == 0)
+ return PSMOUSE_PS2PP;
- if (max_proto > PSMOUSE_IMEX && trackpoint_detect(psmouse, set_properties) == 0)
- return PSMOUSE_TRACKPOINT;
+ if (trackpoint_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_TRACKPOINT;
+
+ if (touchkit_ps2_detect(psmouse, set_properties) == 0)
+ return PSMOUSE_TOUCHKIT_PS2;
+ }
/*
* Reset to defaults in case the device got confused by extended
@@ -654,12 +663,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = 1,
.detect = ps2bare_detect,
},
+#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP
{
.type = PSMOUSE_PS2PP,
.name = "PS2++",
.alias = "logitech",
.detect = ps2pp_init,
},
+#endif
{
.type = PSMOUSE_THINKPS,
.name = "ThinkPS/2",
@@ -686,6 +697,7 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.maxproto = 1,
.detect = im_explorer_detect,
},
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
{
.type = PSMOUSE_SYNAPTICS,
.name = "SynPS/2",
@@ -693,6 +705,8 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = synaptics_detect,
.init = synaptics_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_ALPS
{
.type = PSMOUSE_ALPS,
.name = "AlpsPS/2",
@@ -700,18 +714,31 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = alps_detect,
.init = alps_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_LIFEBOOK
{
.type = PSMOUSE_LIFEBOOK,
.name = "LBPS/2",
.alias = "lifebook",
.init = lifebook_init,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
{
.type = PSMOUSE_TRACKPOINT,
.name = "TPPS/2",
.alias = "trackpoint",
.detect = trackpoint_detect,
},
+#endif
+#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
+ {
+ .type = PSMOUSE_TOUCHKIT_PS2,
+ .name = "touchkitPS/2",
+ .alias = "touchkit",
+ .detect = touchkit_ps2_detect,
+ },
+#endif
{
.type = PSMOUSE_AUTO,
.name = "auto",
@@ -823,12 +850,6 @@ static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
static void psmouse_initialize(struct psmouse *psmouse)
{
/*
- * We set the mouse into streaming mode.
- */
-
- ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM);
-
-/*
* We set the mouse report rate, resolution and scaling.
*/
@@ -1062,8 +1083,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse
{
struct input_dev *input_dev = psmouse->dev;
- input_dev->private = psmouse;
- input_dev->cdev.dev = &psmouse->ps2dev.serio->dev;
+ input_dev->dev.parent = &psmouse->ps2dev.serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index cf1de95b6f2..3964e8acbc5 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -87,6 +87,7 @@ enum psmouse_type {
PSMOUSE_ALPS,
PSMOUSE_LIFEBOOK,
PSMOUSE_TRACKPOINT,
+ PSMOUSE_TOUCHKIT_PS2,
PSMOUSE_AUTO /* This one should always be last */
};
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index a85d74710b4..77b8ee2b965 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -69,7 +69,8 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
switch (sermouse->count) {
case 0:
- if ((data & 0xf8) != 0x80) return;
+ if ((data & 0xf8) != 0x80)
+ return;
input_report_key(dev, BTN_LEFT, !(data & 4));
input_report_key(dev, BTN_RIGHT, !(data & 1));
input_report_key(dev, BTN_MIDDLE, !(data & 2));
@@ -107,7 +108,10 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
struct input_dev *dev = sermouse->dev;
signed char *buf = sermouse->buf;
- if (data & 0x40) sermouse->count = 0;
+ if (data & 0x40)
+ sermouse->count = 0;
+ else if (sermouse->count == 0)
+ return;
switch (sermouse->count) {
@@ -169,7 +173,8 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
case 5:
case 7: /* Ignore anything besides MZ++ */
- if (sermouse->type != SERIO_MZPP) break;
+ if (sermouse->type != SERIO_MZPP)
+ break;
switch (buf[1]) {
@@ -206,13 +211,16 @@ static irqreturn_t sermouse_interrupt(struct serio *serio,
{
struct sermouse *sermouse = serio_get_drvdata(serio);
- if (time_after(jiffies, sermouse->last + HZ/10)) sermouse->count = 0;
+ if (time_after(jiffies, sermouse->last + HZ/10))
+ sermouse->count = 0;
+
sermouse->last = jiffies;
if (sermouse->type > SERIO_SUN)
sermouse_process_ms(sermouse, data);
else
sermouse_process_msc(sermouse, data);
+
return IRQ_HANDLED;
}
@@ -258,12 +266,11 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = sermouse->type;
input_dev->id.product = c;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
- input_dev->private = sermouse;
if (c & 0x01) set_bit(BTN_MIDDLE, input_dev->keybit);
if (c & 0x02) set_bit(BTN_SIDE, input_dev->keybit);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index f0f9413d762..666ad3a53fd 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -40,33 +40,70 @@
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448
+
/*****************************************************************************
- * Synaptics communications functions
+ * Stuff we need even when we do not want native Synaptics support
****************************************************************************/
/*
- * Send a command to the synpatics touchpad by special commands
+ * Set the synaptics touchpad mode byte by special commands
*/
-static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
+static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
{
- if (psmouse_sliced_command(psmouse, c))
+ unsigned char param[1];
+
+ if (psmouse_sliced_command(psmouse, mode))
return -1;
- if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
+ param[0] = SYN_PS_SET_MODE2;
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
+int synaptics_detect(struct psmouse *psmouse, int set_properties)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[4];
+
+ param[0] = 0;
+
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
+
+ if (param[1] != 0x47)
+ return -ENODEV;
+
+ if (set_properties) {
+ psmouse->vendor = "Synaptics";
+ psmouse->name = "TouchPad";
+ }
+
+ return 0;
+}
+
+void synaptics_reset(struct psmouse *psmouse)
+{
+ /* reset touchpad back to relative mode, gestures enabled */
+ synaptics_mode_cmd(psmouse, 0);
+}
+
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS
+
+/*****************************************************************************
+ * Synaptics communications functions
+ ****************************************************************************/
+
/*
- * Set the synaptics touchpad mode byte by special commands
+ * Send a command to the synpatics touchpad by special commands
*/
-static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
+static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
{
- unsigned char param[1];
-
- if (psmouse_sliced_command(psmouse, mode))
+ if (psmouse_sliced_command(psmouse, c))
return -1;
- param[0] = SYN_PS_SET_MODE2;
- if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
return 0;
}
@@ -148,7 +185,7 @@ static int synaptics_query_hardware(struct psmouse *psmouse)
int retries = 0;
while ((retries++ < 3) && psmouse_reset(psmouse))
- printk(KERN_ERR "synaptics reset failed\n");
+ /* empty */;
if (synaptics_identify(psmouse))
return -1;
@@ -529,12 +566,6 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
clear_bit(REL_Y, dev->relbit);
}
-void synaptics_reset(struct psmouse *psmouse)
-{
- /* reset touchpad back to relative mode, gestures enabled */
- synaptics_mode_cmd(psmouse, 0);
-}
-
static void synaptics_disconnect(struct psmouse *psmouse)
{
synaptics_reset(psmouse);
@@ -569,30 +600,6 @@ static int synaptics_reconnect(struct psmouse *psmouse)
return 0;
}
-int synaptics_detect(struct psmouse *psmouse, int set_properties)
-{
- struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param[4];
-
- param[0] = 0;
-
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
- ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
-
- if (param[1] != 0x47)
- return -1;
-
- if (set_properties) {
- psmouse->vendor = "Synaptics";
- psmouse->name = "TouchPad";
- }
-
- return 0;
-}
-
#if defined(__i386__)
#include <linux/dmi.h>
static struct dmi_system_id toshiba_dmi_table[] = {
@@ -648,6 +655,16 @@ int synaptics_init(struct psmouse *psmouse)
set_input_params(psmouse->dev, priv);
+ /*
+ * Encode touchpad model so that it can be used to set
+ * input device->id.version and be visible to userspace.
+ * Because version is __u16 we have to drop something.
+ * Hardware info bits seem to be good candidates as they
+ * are documented to be for Synaptics corp. internal use.
+ */
+ psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) |
+ (priv->model_id & 0x000000ff);
+
psmouse->protocol_handler = synaptics_process_byte;
psmouse->set_rate = synaptics_set_rate;
psmouse->disconnect = synaptics_disconnect;
@@ -680,4 +697,12 @@ int synaptics_init(struct psmouse *psmouse)
return -1;
}
+#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
+
+int synaptics_init(struct psmouse *psmouse)
+{
+ return -ENOSYS;
+}
+
+#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 68fff1dcd7d..02aa4cf7bc7 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -9,10 +9,6 @@
#ifndef _SYNAPTICS_H
#define _SYNAPTICS_H
-extern int synaptics_detect(struct psmouse *psmouse, int set_properties);
-extern int synaptics_init(struct psmouse *psmouse);
-extern void synaptics_reset(struct psmouse *psmouse);
-
/* synaptics queries */
#define SYN_QUE_IDENTIFY 0x00
#define SYN_QUE_MODES 0x01
@@ -62,9 +58,9 @@ extern void synaptics_reset(struct psmouse *psmouse);
#define SYN_MODE_WMODE(m) ((m) & (1 << 0))
/* synaptics identify query bits */
-#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
-#define SYN_ID_MAJOR(i) ((i) & 0x0f)
-#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
+#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
+#define SYN_ID_MAJOR(i) ((i) & 0x0f)
+#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
/* synaptics special commands */
@@ -98,8 +94,8 @@ struct synaptics_hw_state {
struct synaptics_data {
/* Data read from the touchpad */
unsigned long int model_id; /* Model-ID */
- unsigned long int capabilities; /* Capabilities */
- unsigned long int ext_cap; /* Extended Capabilities */
+ unsigned long int capabilities; /* Capabilities */
+ unsigned long int ext_cap; /* Extended Capabilities */
unsigned long int identity; /* Identification */
unsigned char pkt_type; /* packet type - old, new, etc */
@@ -107,4 +103,8 @@ struct synaptics_data {
int scroll;
};
+int synaptics_detect(struct psmouse *psmouse, int set_properties);
+int synaptics_init(struct psmouse *psmouse);
+void synaptics_reset(struct psmouse *psmouse);
+
#endif /* _SYNAPTICS_H */
diff --git a/drivers/input/mouse/touchkit_ps2.c b/drivers/input/mouse/touchkit_ps2.c
new file mode 100644
index 00000000000..7b977fd2357
--- /dev/null
+++ b/drivers/input/mouse/touchkit_ps2.c
@@ -0,0 +1,100 @@
+/* ----------------------------------------------------------------------------
+ * touchkit_ps2.c -- Driver for eGalax TouchKit PS/2 Touchscreens
+ *
+ * Copyright (C) 2005 by Stefan Lucke
+ * Copyright (C) 2004 by Daniel Ritz
+ * Copyright (C) by Todd E. Johnson (mtouchusb.c)
+ *
+ * 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.
+ *
+ * Based upon touchkitusb.c
+ *
+ * Vendor documentation is available in support section of:
+ * http://www.egalax.com.tw/
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+
+#include "psmouse.h"
+#include "touchkit_ps2.h"
+
+#define TOUCHKIT_MAX_XC 0x07ff
+#define TOUCHKIT_MAX_YC 0x07ff
+
+#define TOUCHKIT_CMD 0x0a
+#define TOUCHKIT_CMD_LENGTH 1
+
+#define TOUCHKIT_CMD_ACTIVE 'A'
+#define TOUCHKIT_CMD_FIRMWARE_VERSION 'D'
+#define TOUCHKIT_CMD_CONTROLLER_TYPE 'E'
+
+#define TOUCHKIT_SEND_PARMS(s, r, c) ((s) << 12 | (r) << 8 | (c))
+
+#define TOUCHKIT_GET_TOUCHED(packet) (((packet)[0]) & 0x01)
+#define TOUCHKIT_GET_X(packet) (((packet)[1] << 7) | (packet)[2])
+#define TOUCHKIT_GET_Y(packet) (((packet)[3] << 7) | (packet)[4])
+
+static psmouse_ret_t touchkit_ps2_process_byte(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+
+ if (psmouse->pktcnt != 5)
+ return PSMOUSE_GOOD_DATA;
+
+ input_report_abs(dev, ABS_X, TOUCHKIT_GET_X(packet));
+ input_report_abs(dev, ABS_Y, TOUCHKIT_GET_Y(packet));
+ input_report_key(dev, BTN_TOUCH, TOUCHKIT_GET_TOUCHED(packet));
+ input_sync(dev);
+
+ return PSMOUSE_FULL_PACKET;
+}
+
+int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+{
+ struct input_dev *dev = psmouse->dev;
+ unsigned char param[3];
+ int command;
+
+ param[0] = TOUCHKIT_CMD_LENGTH;
+ param[1] = TOUCHKIT_CMD_ACTIVE;
+ command = TOUCHKIT_SEND_PARMS(2, 3, TOUCHKIT_CMD);
+
+ if (ps2_command(&psmouse->ps2dev, param, command))
+ return -ENODEV;
+
+ if (param[0] != TOUCHKIT_CMD || param[1] != 0x01 ||
+ param[2] != TOUCHKIT_CMD_ACTIVE)
+ return -ENODEV;
+
+ if (set_properties) {
+ dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ set_bit(BTN_TOUCH, dev->keybit);
+ input_set_abs_params(dev, ABS_X, 0, TOUCHKIT_MAX_XC, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 0, TOUCHKIT_MAX_YC, 0, 0);
+
+ psmouse->vendor = "eGalax";
+ psmouse->name = "Touchscreen";
+ psmouse->protocol_handler = touchkit_ps2_process_byte;
+ psmouse->pktsize = 5;
+ }
+
+ return 0;
+}
diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h
new file mode 100644
index 00000000000..61e9dfd8419
--- /dev/null
+++ b/drivers/input/mouse/touchkit_ps2.h
@@ -0,0 +1,24 @@
+/* ----------------------------------------------------------------------------
+ * touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens
+ *
+ * Copyright (C) 2005 by Stefan Lucke
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * 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.
+ */
+
+#ifndef _TOUCHKIT_PS2_H
+#define _TOUCHKIT_PS2_H
+
+#ifdef CONFIG_MOUSE_PS2_TOUCHKIT
+int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
+#else
+inline int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */
+
+#endif
diff --git a/drivers/input/mouse/trackpoint.h b/drivers/input/mouse/trackpoint.h
index 050298b1a09..c10a6e7d010 100644
--- a/drivers/input/mouse/trackpoint.h
+++ b/drivers/input/mouse/trackpoint.h
@@ -142,6 +142,13 @@ struct trackpoint_data
unsigned char ext_dev;
};
-extern int trackpoint_detect(struct psmouse *psmouse, int set_properties);
+#ifdef CONFIG_MOUSE_PS2_TRACKPOINT
+int trackpoint_detect(struct psmouse *psmouse, int set_properties);
+#else
+inline int trackpoint_detect(struct psmouse *psmouse, int set_properties)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */
#endif /* _TRACKPOINT_H */
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index c3d64fcc858..4a321576f34 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -508,8 +508,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
input_dev->name = mouse->name;
input_dev->phys = mouse->phys;
input_dev->id.bustype = BUS_RS232;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = mouse;
+ input_dev->dev.parent = &serio->dev;
set_bit (EV_KEY, input_dev->evbit); /* We have buttons */
set_bit (EV_REL, input_dev->evbit);
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 664bcc8116f..8675f950939 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -19,7 +19,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/input.h>
-#include <linux/smp_lock.h>
#include <linux/random.h>
#include <linux/major.h>
#include <linux/device.h>
@@ -63,9 +62,12 @@ struct mousedev {
int minor;
char name[16];
wait_queue_head_t wait;
- struct list_head list;
+ struct list_head client_list;
struct input_handle handle;
+ struct list_head mixdev_node;
+ int mixdev_open;
+
struct mousedev_hw_data packet;
unsigned int pkt_count;
int old_x[4], old_y[4];
@@ -85,7 +87,7 @@ struct mousedev_motion {
};
#define PACKET_QUEUE_LEN 16
-struct mousedev_list {
+struct mousedev_client {
struct fasync_struct *fasync;
struct mousedev *mousedev;
struct list_head node;
@@ -111,6 +113,7 @@ static struct input_handler mousedev_handler;
static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
static struct mousedev mousedev_mix;
+static LIST_HEAD(mousedev_mix_list);
#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
@@ -120,32 +123,33 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous
int size, tmp;
enum { FRACTION_DENOM = 128 };
- if (mousedev->touch) {
- size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0)
- size = 256 * 2;
-
- switch (code) {
- case ABS_X:
- fx(0) = value;
- if (mousedev->pkt_count >= 2) {
- tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
- tmp += mousedev->frac_dx;
- mousedev->packet.dx = tmp / FRACTION_DENOM;
- mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
- }
- break;
+ switch (code) {
+ case ABS_X:
+ fx(0) = value;
+ if (mousedev->touch && mousedev->pkt_count >= 2) {
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = 256 * 2;
+ tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size;
+ tmp += mousedev->frac_dx;
+ mousedev->packet.dx = tmp / FRACTION_DENOM;
+ mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM;
+ }
+ break;
- case ABS_Y:
- fy(0) = value;
- if (mousedev->pkt_count >= 2) {
- tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
- tmp += mousedev->frac_dy;
- mousedev->packet.dy = tmp / FRACTION_DENOM;
- mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
- }
- break;
- }
+ case ABS_Y:
+ fy(0) = value;
+ if (mousedev->touch && mousedev->pkt_count >= 2) {
+ /* use X size to keep the same scale */
+ size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
+ if (size == 0)
+ size = 256 * 2;
+ tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size;
+ tmp += mousedev->frac_dy;
+ mousedev->packet.dy = tmp / FRACTION_DENOM;
+ mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM;
+ }
+ break;
}
}
@@ -223,47 +227,47 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
{
- struct mousedev_list *list;
+ struct mousedev_client *client;
struct mousedev_motion *p;
unsigned long flags;
int wake_readers = 0;
- list_for_each_entry(list, &mousedev->list, node) {
- spin_lock_irqsave(&list->packet_lock, flags);
+ list_for_each_entry(client, &mousedev->client_list, node) {
+ spin_lock_irqsave(&client->packet_lock, flags);
- p = &list->packets[list->head];
- if (list->ready && p->buttons != mousedev->packet.buttons) {
- unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
- if (new_head != list->tail) {
- p = &list->packets[list->head = new_head];
+ p = &client->packets[client->head];
+ if (client->ready && p->buttons != mousedev->packet.buttons) {
+ unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN;
+ if (new_head != client->tail) {
+ p = &client->packets[client->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
}
}
if (packet->abs_event) {
- p->dx += packet->x - list->pos_x;
- p->dy += packet->y - list->pos_y;
- list->pos_x = packet->x;
- list->pos_y = packet->y;
+ p->dx += packet->x - client->pos_x;
+ p->dy += packet->y - client->pos_y;
+ client->pos_x = packet->x;
+ client->pos_y = packet->y;
}
- list->pos_x += packet->dx;
- list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
- list->pos_y += packet->dy;
- list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
+ client->pos_x += packet->dx;
+ client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x);
+ client->pos_y += packet->dy;
+ client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y);
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
- if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
- list->ready = 1;
+ if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons)
+ client->ready = 1;
- spin_unlock_irqrestore(&list->packet_lock, flags);
+ spin_unlock_irqrestore(&client->packet_lock, flags);
- if (list->ready) {
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ if (client->ready) {
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
wake_readers = 1;
}
}
@@ -351,9 +355,9 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
static int mousedev_fasync(int fd, struct file *file, int on)
{
int retval;
- struct mousedev_list *list = file->private_data;
+ struct mousedev_client *client = file->private_data;
- retval = fasync_helper(fd, file, on, &list->fasync);
+ retval = fasync_helper(fd, file, on, &client->fasync);
return retval < 0 ? retval : 0;
}
@@ -364,50 +368,95 @@ static void mousedev_free(struct mousedev *mousedev)
kfree(mousedev);
}
-static void mixdev_release(void)
+static int mixdev_add_device(struct mousedev *mousedev)
{
- struct input_handle *handle;
+ int error;
- list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
- struct mousedev *mousedev = handle->private;
+ if (mousedev_mix.open) {
+ error = input_open_device(&mousedev->handle);
+ if (error)
+ return error;
- if (!mousedev->open) {
- if (mousedev->exist)
- input_close_device(&mousedev->handle);
- else
- mousedev_free(mousedev);
+ mousedev->open++;
+ mousedev->mixdev_open++;
+ }
+
+ list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list);
+
+ return 0;
+}
+
+static void mixdev_remove_device(struct mousedev *mousedev)
+{
+ if (mousedev->mixdev_open) {
+ mousedev->mixdev_open = 0;
+ if (!--mousedev->open && mousedev->exist)
+ input_close_device(&mousedev->handle);
+ }
+
+ list_del_init(&mousedev->mixdev_node);
+}
+
+static void mixdev_open_devices(void)
+{
+ struct mousedev *mousedev;
+
+ list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+ if (mousedev->exist && !mousedev->open) {
+ if (input_open_device(&mousedev->handle))
+ continue;
+
+ mousedev->open++;
+ mousedev->mixdev_open++;
+ }
+ }
+}
+
+static void mixdev_close_devices(void)
+{
+ struct mousedev *mousedev, *next;
+
+ list_for_each_entry_safe(mousedev, next, &mousedev_mix_list, mixdev_node) {
+ if (mousedev->mixdev_open) {
+ mousedev->mixdev_open = 0;
+ if (!--mousedev->open) {
+ if (mousedev->exist)
+ input_close_device(&mousedev->handle);
+ else
+ mousedev_free(mousedev);
+ }
}
}
}
-static int mousedev_release(struct inode * inode, struct file * file)
+static int mousedev_release(struct inode *inode, struct file *file)
{
- struct mousedev_list *list = file->private_data;
+ struct mousedev_client *client = file->private_data;
+ struct mousedev *mousedev = client->mousedev;
mousedev_fasync(-1, file, 0);
- list_del(&list->node);
+ list_del(&client->node);
+ kfree(client);
- if (!--list->mousedev->open) {
- if (list->mousedev->minor == MOUSEDEV_MIX)
- mixdev_release();
- else if (!mousedev_mix.open) {
- if (list->mousedev->exist)
- input_close_device(&list->mousedev->handle);
- else
- mousedev_free(list->mousedev);
- }
+ if (!--mousedev->open) {
+ if (mousedev->minor == MOUSEDEV_MIX)
+ mixdev_close_devices();
+ else if (mousedev->exist)
+ input_close_device(&mousedev->handle);
+ else
+ mousedev_free(mousedev);
}
- kfree(list);
return 0;
}
-static int mousedev_open(struct inode * inode, struct file * file)
+
+static int mousedev_open(struct inode *inode, struct file *file)
{
- struct mousedev_list *list;
- struct input_handle *handle;
+ struct mousedev_client *client;
struct mousedev *mousedev;
+ int error;
int i;
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
@@ -417,31 +466,37 @@ static int mousedev_open(struct inode * inode, struct file * file)
#endif
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
- if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
+ if (i >= MOUSEDEV_MINORS)
+ return -ENODEV;
+
+ mousedev = mousedev_table[i];
+ if (!mousedev)
return -ENODEV;
- if (!(list = kzalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
+ client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
+ if (!client)
return -ENOMEM;
- spin_lock_init(&list->packet_lock);
- list->pos_x = xres / 2;
- list->pos_y = yres / 2;
- list->mousedev = mousedev_table[i];
- list_add_tail(&list->node, &mousedev_table[i]->list);
- file->private_data = list;
-
- if (!list->mousedev->open++) {
- if (list->mousedev->minor == MOUSEDEV_MIX) {
- list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
- mousedev = handle->private;
- if (!mousedev->open && mousedev->exist)
- input_open_device(handle);
+ spin_lock_init(&client->packet_lock);
+ client->pos_x = xres / 2;
+ client->pos_y = yres / 2;
+ client->mousedev = mousedev;
+ list_add_tail(&client->node, &mousedev->client_list);
+
+ if (!mousedev->open++) {
+ if (mousedev->minor == MOUSEDEV_MIX)
+ mixdev_open_devices();
+ else if (mousedev->exist) {
+ error = input_open_device(&mousedev->handle);
+ if (error) {
+ list_del(&client->node);
+ kfree(client);
+ return error;
}
- } else
- if (!mousedev_mix.open && list->mousedev->exist)
- input_open_device(&list->mousedev->handle);
+ }
}
+ file->private_data = client;
return 0;
}
@@ -450,13 +505,13 @@ static inline int mousedev_limit_delta(int delta, int limit)
return delta > limit ? limit : (delta < -limit ? -limit : delta);
}
-static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data)
{
struct mousedev_motion *p;
unsigned long flags;
- spin_lock_irqsave(&list->packet_lock, flags);
- p = &list->packets[list->tail];
+ spin_lock_irqsave(&client->packet_lock, flags);
+ p = &client->packets[client->tail];
ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
ps2_data[1] = mousedev_limit_delta(p->dx, 127);
@@ -464,44 +519,44 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data)
p->dx -= ps2_data[1];
p->dy -= ps2_data[2];
- switch (list->mode) {
+ switch (client->mode) {
case MOUSEDEV_EMUL_EXPS:
ps2_data[3] = mousedev_limit_delta(p->dz, 7);
p->dz -= ps2_data[3];
ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
- list->bufsiz = 4;
+ client->bufsiz = 4;
break;
case MOUSEDEV_EMUL_IMPS:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
ps2_data[3] = mousedev_limit_delta(p->dz, 127);
p->dz -= ps2_data[3];
- list->bufsiz = 4;
+ client->bufsiz = 4;
break;
case MOUSEDEV_EMUL_PS2:
default:
ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
p->dz = 0;
- list->bufsiz = 3;
+ client->bufsiz = 3;
break;
}
if (!p->dx && !p->dy && !p->dz) {
- if (list->tail == list->head) {
- list->ready = 0;
- list->last_buttons = p->buttons;
+ if (client->tail == client->head) {
+ client->ready = 0;
+ client->last_buttons = p->buttons;
} else
- list->tail = (list->tail + 1) % PACKET_QUEUE_LEN;
+ client->tail = (client->tail + 1) % PACKET_QUEUE_LEN;
}
- spin_unlock_irqrestore(&list->packet_lock, flags);
+ spin_unlock_irqrestore(&client->packet_lock, flags);
}
-static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
- struct mousedev_list *list = file->private_data;
+ struct mousedev_client *client = file->private_data;
unsigned char c;
unsigned int i;
@@ -510,95 +565,95 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
if (get_user(c, buffer + i))
return -EFAULT;
- if (c == mousedev_imex_seq[list->imexseq]) {
- if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
- list->imexseq = 0;
- list->mode = MOUSEDEV_EMUL_EXPS;
+ if (c == mousedev_imex_seq[client->imexseq]) {
+ if (++client->imexseq == MOUSEDEV_SEQ_LEN) {
+ client->imexseq = 0;
+ client->mode = MOUSEDEV_EMUL_EXPS;
}
} else
- list->imexseq = 0;
+ client->imexseq = 0;
- if (c == mousedev_imps_seq[list->impsseq]) {
- if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
- list->impsseq = 0;
- list->mode = MOUSEDEV_EMUL_IMPS;
+ if (c == mousedev_imps_seq[client->impsseq]) {
+ if (++client->impsseq == MOUSEDEV_SEQ_LEN) {
+ client->impsseq = 0;
+ client->mode = MOUSEDEV_EMUL_IMPS;
}
} else
- list->impsseq = 0;
+ client->impsseq = 0;
- list->ps2[0] = 0xfa;
+ client->ps2[0] = 0xfa;
switch (c) {
case 0xeb: /* Poll */
- mousedev_packet(list, &list->ps2[1]);
- list->bufsiz++; /* account for leading ACK */
+ mousedev_packet(client, &client->ps2[1]);
+ client->bufsiz++; /* account for leading ACK */
break;
case 0xf2: /* Get ID */
- switch (list->mode) {
- case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break;
- case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break;
- case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break;
+ switch (client->mode) {
+ case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break;
+ case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break;
+ case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break;
}
- list->bufsiz = 2;
+ client->bufsiz = 2;
break;
case 0xe9: /* Get info */
- list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
- list->bufsiz = 4;
+ client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200;
+ client->bufsiz = 4;
break;
case 0xff: /* Reset */
- list->impsseq = list->imexseq = 0;
- list->mode = MOUSEDEV_EMUL_PS2;
- list->ps2[1] = 0xaa; list->ps2[2] = 0x00;
- list->bufsiz = 3;
+ client->impsseq = client->imexseq = 0;
+ client->mode = MOUSEDEV_EMUL_PS2;
+ client->ps2[1] = 0xaa; client->ps2[2] = 0x00;
+ client->bufsiz = 3;
break;
default:
- list->bufsiz = 1;
+ client->bufsiz = 1;
break;
}
- list->buffer = list->bufsiz;
+ client->buffer = client->bufsiz;
}
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
- wake_up_interruptible(&list->mousedev->wait);
+ wake_up_interruptible(&client->mousedev->wait);
return count;
}
-static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- struct mousedev_list *list = file->private_data;
+ struct mousedev_client *client = file->private_data;
int retval = 0;
- if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
+ if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
- retval = wait_event_interruptible(list->mousedev->wait,
- !list->mousedev->exist || list->ready || list->buffer);
+ retval = wait_event_interruptible(client->mousedev->wait,
+ !client->mousedev->exist || client->ready || client->buffer);
if (retval)
return retval;
- if (!list->mousedev->exist)
+ if (!client->mousedev->exist)
return -ENODEV;
- if (!list->buffer && list->ready) {
- mousedev_packet(list, list->ps2);
- list->buffer = list->bufsiz;
+ if (!client->buffer && client->ready) {
+ mousedev_packet(client, client->ps2);
+ client->buffer = client->bufsiz;
}
- if (count > list->buffer)
- count = list->buffer;
+ if (count > client->buffer)
+ count = client->buffer;
- list->buffer -= count;
+ client->buffer -= count;
- if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
+ if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count))
return -EFAULT;
return count;
@@ -607,11 +662,12 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
/* No kernel lock - fine */
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
- struct mousedev_list *list = file->private_data;
+ struct mousedev_client *client = file->private_data;
+ struct mousedev *mousedev = client->mousedev;
- poll_wait(file, &list->mousedev->wait, wait);
- return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
- (list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
+ poll_wait(file, &mousedev->wait, wait);
+ return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) |
+ (mousedev->exist ? 0 : (POLLHUP | POLLERR));
}
static const struct file_operations mousedev_fops = {
@@ -624,23 +680,27 @@ static const struct file_operations mousedev_fops = {
.fasync = mousedev_fasync,
};
-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
+static int mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct mousedev *mousedev;
struct class_device *cdev;
- int minor = 0;
+ dev_t devt;
+ int minor;
+ int error;
for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++);
if (minor == MOUSEDEV_MINORS) {
printk(KERN_ERR "mousedev: no more free mousedev devices\n");
- return NULL;
+ return -ENFILE;
}
- if (!(mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL)))
- return NULL;
+ mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL);
+ if (!mousedev)
+ return -ENOMEM;
- INIT_LIST_HEAD(&mousedev->list);
+ INIT_LIST_HEAD(&mousedev->client_list);
+ INIT_LIST_HEAD(&mousedev->mixdev_node);
init_waitqueue_head(&mousedev->wait);
mousedev->minor = minor;
@@ -651,42 +711,66 @@ static struct input_handle *mousedev_connect(struct input_handler *handler, stru
mousedev->handle.private = mousedev;
sprintf(mousedev->name, "mouse%d", minor);
- if (mousedev_mix.open)
- input_open_device(&mousedev->handle);
-
mousedev_table[minor] = mousedev;
- cdev = class_device_create(&input_class, &dev->cdev,
- MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
- dev->cdev.dev, mousedev->name);
+ devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
+
+ cdev = class_device_create(&input_class, &dev->cdev, devt,
+ dev->cdev.dev, mousedev->name);
+ if (IS_ERR(cdev)) {
+ error = PTR_ERR(cdev);
+ goto err_free_mousedev;
+ }
/* temporary symlink to keep userspace happy */
- sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
- mousedev->name);
+ error = sysfs_create_link(&input_class.subsys.kobj,
+ &cdev->kobj, mousedev->name);
+ if (error)
+ goto err_cdev_destroy;
+
+ error = input_register_handle(&mousedev->handle);
+ if (error)
+ goto err_remove_link;
+
+ error = mixdev_add_device(mousedev);
+ if (error)
+ goto err_unregister_handle;
+
+ return 0;
- return &mousedev->handle;
+ err_unregister_handle:
+ input_unregister_handle(&mousedev->handle);
+ err_remove_link:
+ sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
+ err_cdev_destroy:
+ class_device_destroy(&input_class, devt);
+ err_free_mousedev:
+ mousedev_table[minor] = NULL;
+ kfree(mousedev);
+ return error;
}
static void mousedev_disconnect(struct input_handle *handle)
{
struct mousedev *mousedev = handle->private;
- struct mousedev_list *list;
+ struct mousedev_client *client;
- sysfs_remove_link(&input_class.subsys.kset.kobj, mousedev->name);
+ input_unregister_handle(handle);
+
+ sysfs_remove_link(&input_class.subsys.kobj, mousedev->name);
class_device_destroy(&input_class,
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + mousedev->minor));
mousedev->exist = 0;
+ mixdev_remove_device(mousedev);
+
if (mousedev->open) {
input_close_device(handle);
wake_up_interruptible(&mousedev->wait);
- list_for_each_entry(list, &mousedev->list, node)
- kill_fasync(&list->fasync, SIGIO, POLL_HUP);
- } else {
- if (mousedev_mix.open)
- input_close_device(handle);
+ list_for_each_entry(client, &mousedev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ } else
mousedev_free(mousedev);
- }
}
static const struct input_device_id mousedev_ids[] = {
@@ -714,7 +798,7 @@ static const struct input_device_id mousedev_ids[] = {
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) },
}, /* A touchpad */
- { }, /* Terminating entry */
+ { }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, mousedev_ids);
@@ -746,7 +830,7 @@ static int __init mousedev_init(void)
return error;
memset(&mousedev_mix, 0, sizeof(struct mousedev));
- INIT_LIST_HEAD(&mousedev_mix.list);
+ INIT_LIST_HEAD(&mousedev_mix.client_list);
init_waitqueue_head(&mousedev_mix.wait);
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
mousedev_mix.exist = 1;
diff --git a/drivers/input/power.c b/drivers/input/power.c
deleted file mode 100644
index ee82464a2fa..00000000000
--- a/drivers/input/power.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * $Id: power.c,v 1.10 2001/09/25 09:17:15 vojtech Exp $
- *
- * Copyright (c) 2001 "Crazy" James Simmons
- *
- * Input driver Power Management.
- *
- * Sponsored by Transvirtual Technology.
- */
-
-/*
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <jsimmons@transvirtual.com>.
- */
-
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-
-static struct input_handler power_handler;
-
-/*
- * Power management can't be done in a interrupt context. So we have to
- * use keventd.
- */
-static int suspend_button_pushed = 0;
-static void suspend_button_task_handler(void *data)
-{
- udelay(200); /* debounce */
- suspend_button_pushed = 0;
-}
-
-static DECLARE_WORK(suspend_button_task, suspend_button_task_handler, NULL);
-
-static void power_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int down)
-{
- struct input_dev *dev = handle->dev;
-
- printk("Entering power_event\n");
-
- if (type == EV_PWR) {
- switch (code) {
- case KEY_SUSPEND:
- printk("Powering down entire device\n");
-
- if (!suspend_button_pushed) {
- suspend_button_pushed = 1;
- schedule_work(&suspend_button_task);
- }
- break;
- case KEY_POWER:
- /* Hum power down the machine. */
- break;
- default:
- return;
- }
- }
-
- if (type == EV_KEY) {
- switch (code) {
- case KEY_SUSPEND:
- printk("Powering down input device\n");
- /* This is risky. See pm.h for details. */
- if (dev->state != PM_RESUME)
- dev->state = PM_RESUME;
- else
- dev->state = PM_SUSPEND;
- pm_send(dev->pm_dev, dev->state, dev);
- break;
- case KEY_POWER:
- /* Turn the input device off completely ? */
- break;
- default:
- return;
- }
- }
- return;
-}
-
-static struct input_handle *power_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
-{
- struct input_handle *handle;
-
- if (!(handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL)))
- return NULL;
-
- handle->dev = dev;
- handle->handler = handler;
-
- input_open_device(handle);
-
- printk(KERN_INFO "power.c: Adding power management to input layer\n");
- return handle;
-}
-
-static void power_disconnect(struct input_handle *handle)
-{
- input_close_device(handle);
- kfree(handle);
-}
-
-static const struct input_device_id power_ids[] = {
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
- .evbit = { BIT(EV_KEY) },
- .keybit = { [LONG(KEY_SUSPEND)] = BIT(KEY_SUSPEND) }
- },
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
- .evbit = { BIT(EV_KEY) },
- .keybit = { [LONG(KEY_POWER)] = BIT(KEY_POWER) }
- },
- {
- .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
- .evbit = { BIT(EV_PWR) },
- },
- { }, /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(input, power_ids);
-
-static struct input_handler power_handler = {
- .event = power_event,
- .connect = power_connect,
- .disconnect = power_disconnect,
- .name = "power",
- .id_table = power_ids,
-};
-
-static int __init power_init(void)
-{
- return input_register_handler(&power_handler);
-}
-
-static void __exit power_exit(void)
-{
- input_unregister_handler(&power_handler);
-}
-
-module_init(power_init);
-module_exit(power_exit);
-
-MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>");
-MODULE_DESCRIPTION("Input Power Management driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index 4fa93ff3091..93a1a6ba216 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -32,11 +32,11 @@
*
* Driver theory of operation:
*
- * Some access methods and an ISR is defined by the sub-driver
- * (e.g. hp_sdc_mlc.c). These methods are expected to provide a
- * few bits of logic in addition to raw access to the HIL MLC,
- * specifically, the ISR, which is entirely registered by the
- * sub-driver and invoked directly, must check for record
+ * Some access methods and an ISR is defined by the sub-driver
+ * (e.g. hp_sdc_mlc.c). These methods are expected to provide a
+ * few bits of logic in addition to raw access to the HIL MLC,
+ * specifically, the ISR, which is entirely registered by the
+ * sub-driver and invoked directly, must check for record
* termination or packet match, at which point a semaphore must
* be cleared and then the hil_mlcs_tasklet must be scheduled.
*
@@ -47,7 +47,7 @@
* itself if output is pending. (This rescheduling should be replaced
* at some point with a sub-driver-specific mechanism.)
*
- * A timer task prods the tasklet once per second to prevent
+ * A timer task prods the tasklet once per second to prevent
* hangups when attached devices do not return expected data
* and to initiate probes of the loop for new devices.
*/
@@ -83,69 +83,85 @@ DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
/********************** Device info/instance management **********************/
-static void hil_mlc_clear_di_map (hil_mlc *mlc, int val) {
+static void hil_mlc_clear_di_map(hil_mlc *mlc, int val)
+{
int j;
- for (j = val; j < 7 ; j++) {
+
+ for (j = val; j < 7 ; j++)
mlc->di_map[j] = -1;
- }
}
-static void hil_mlc_clear_di_scratch (hil_mlc *mlc) {
- memset(&(mlc->di_scratch), 0, sizeof(mlc->di_scratch));
+static void hil_mlc_clear_di_scratch(hil_mlc *mlc)
+{
+ memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch));
}
-static void hil_mlc_copy_di_scratch (hil_mlc *mlc, int idx) {
- memcpy(&(mlc->di[idx]), &(mlc->di_scratch), sizeof(mlc->di_scratch));
+static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx)
+{
+ memcpy(&mlc->di[idx], &mlc->di_scratch, sizeof(mlc->di_scratch));
}
-static int hil_mlc_match_di_scratch (hil_mlc *mlc) {
+static int hil_mlc_match_di_scratch(hil_mlc *mlc)
+{
int idx;
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
- int j, found;
+ int j, found = 0;
/* In-use slots are not eligible. */
- found = 0;
- for (j = 0; j < 7 ; j++) {
- if (mlc->di_map[j] == idx) found++;
- }
- if (found) continue;
- if (!memcmp(mlc->di + idx,
- &(mlc->di_scratch),
- sizeof(mlc->di_scratch))) break;
+ for (j = 0; j < 7 ; j++)
+ if (mlc->di_map[j] == idx)
+ found++;
+
+ if (found)
+ continue;
+
+ if (!memcmp(mlc->di + idx, &mlc->di_scratch,
+ sizeof(mlc->di_scratch)))
+ break;
}
- return((idx >= HIL_MLC_DEVMEM) ? -1 : idx);
+ return idx >= HIL_MLC_DEVMEM ? -1 : idx;
}
-static int hil_mlc_find_free_di(hil_mlc *mlc) {
+static int hil_mlc_find_free_di(hil_mlc *mlc)
+{
int idx;
- /* TODO: Pick all-zero slots first, failing that,
- * randomize the slot picked among those eligible.
+
+ /* TODO: Pick all-zero slots first, failing that,
+ * randomize the slot picked among those eligible.
*/
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
- int j, found;
- found = 0;
- for (j = 0; j < 7 ; j++) {
- if (mlc->di_map[j] == idx) found++;
- }
- if (!found) break;
+ int j, found = 0;
+
+ for (j = 0; j < 7 ; j++)
+ if (mlc->di_map[j] == idx)
+ found++;
+
+ if (!found)
+ break;
}
- return(idx); /* Note: It is guaranteed at least one above will match */
+
+ return idx; /* Note: It is guaranteed at least one above will match */
}
-static inline void hil_mlc_clean_serio_map(hil_mlc *mlc) {
+static inline void hil_mlc_clean_serio_map(hil_mlc *mlc)
+{
int idx;
+
for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
- int j, found;
- found = 0;
- for (j = 0; j < 7 ; j++) {
- if (mlc->di_map[j] == idx) found++;
- }
- if (!found) mlc->serio_map[idx].di_revmap = -1;
+ int j, found = 0;
+
+ for (j = 0; j < 7 ; j++)
+ if (mlc->di_map[j] == idx)
+ found++;
+
+ if (!found)
+ mlc->serio_map[idx].di_revmap = -1;
}
}
-static void hil_mlc_send_polls(hil_mlc *mlc) {
+static void hil_mlc_send_polls(hil_mlc *mlc)
+{
int did, i, cnt;
struct serio *serio;
struct serio_driver *drv;
@@ -157,26 +173,31 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
while (mlc->icount < 15 - i) {
hil_packet p;
+
p = mlc->ipacket[i];
if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
- if (drv == NULL || drv->interrupt == NULL) goto skip;
+ if (drv && drv->interrupt) {
+ drv->interrupt(serio, 0, 0);
+ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
+ drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
+ drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
+ }
- drv->interrupt(serio, 0, 0);
- drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
- drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
- drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
- skip:
did = (p & HIL_PKT_ADDR_MASK) >> 8;
serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
drv = (serio != NULL) ? serio->drv : NULL;
cnt = 0;
}
- cnt++; i++;
- if (drv == NULL || drv->interrupt == NULL) continue;
- drv->interrupt(serio, (p >> 24), 0);
- drv->interrupt(serio, (p >> 16) & 0xff, 0);
- drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
- drv->interrupt(serio, p & 0xff, 0);
+
+ cnt++;
+ i++;
+
+ if (drv && drv->interrupt) {
+ drv->interrupt(serio, (p >> 24), 0);
+ drv->interrupt(serio, (p >> 16) & 0xff, 0);
+ drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
+ drv->interrupt(serio, p & 0xff, 0);
+ }
}
}
@@ -215,12 +236,16 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
#define HILSEN_DOZE (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
#define HILSEN_SLEEP (HILSEN_SAME | HILSEN_BREAK)
-static int hilse_match(hil_mlc *mlc, int unused) {
+static int hilse_match(hil_mlc *mlc, int unused)
+{
int rc;
+
rc = hil_mlc_match_di_scratch(mlc);
if (rc == -1) {
rc = hil_mlc_find_free_di(mlc);
- if (rc == -1) goto err;
+ if (rc == -1)
+ goto err;
+
#ifdef HIL_MLC_DEBUG
printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
#endif
@@ -231,6 +256,7 @@ static int hilse_match(hil_mlc *mlc, int unused) {
serio_rescan(mlc->serio[rc]);
return -1;
}
+
mlc->di_map[mlc->ddi] = rc;
#ifdef HIL_MLC_DEBUG
printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
@@ -238,152 +264,177 @@ static int hilse_match(hil_mlc *mlc, int unused) {
mlc->serio_map[rc].di_revmap = mlc->ddi;
hil_mlc_clean_serio_map(mlc);
return 0;
+
err:
printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
return 1;
}
/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
-static int hilse_init_lcv(hil_mlc *mlc, int unused) {
+static int hilse_init_lcv(hil_mlc *mlc, int unused)
+{
struct timeval tv;
do_gettimeofday(&tv);
- if(mlc->lcv == 0) goto restart; /* First init, no need to dally */
- if(tv.tv_sec - mlc->lcv_tv.tv_sec < 5) return -1;
- restart:
+ if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5)
+ return -1;
+
mlc->lcv_tv = tv;
mlc->lcv = 0;
+
return 0;
}
-static int hilse_inc_lcv(hil_mlc *mlc, int lim) {
- if (mlc->lcv++ >= lim) return -1;
- return 0;
+static int hilse_inc_lcv(hil_mlc *mlc, int lim)
+{
+ return mlc->lcv++ >= lim ? -1 : 0;
}
#if 0
-static int hilse_set_lcv(hil_mlc *mlc, int val) {
+static int hilse_set_lcv(hil_mlc *mlc, int val)
+{
mlc->lcv = val;
+
return 0;
}
#endif
/* Management of the discovered device index (zero based, -1 means no devs) */
-static int hilse_set_ddi(hil_mlc *mlc, int val) {
+static int hilse_set_ddi(hil_mlc *mlc, int val)
+{
mlc->ddi = val;
hil_mlc_clear_di_map(mlc, val + 1);
+
return 0;
}
-static int hilse_dec_ddi(hil_mlc *mlc, int unused) {
+static int hilse_dec_ddi(hil_mlc *mlc, int unused)
+{
mlc->ddi--;
- if (mlc->ddi <= -1) {
+ if (mlc->ddi <= -1) {
mlc->ddi = -1;
hil_mlc_clear_di_map(mlc, 0);
return -1;
}
hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
+
return 0;
}
-static int hilse_inc_ddi(hil_mlc *mlc, int unused) {
- if (mlc->ddi >= 6) {
- BUG();
- return -1;
- }
+static int hilse_inc_ddi(hil_mlc *mlc, int unused)
+{
+ BUG_ON(mlc->ddi >= 6);
mlc->ddi++;
+
return 0;
}
-static int hilse_take_idd(hil_mlc *mlc, int unused) {
+static int hilse_take_idd(hil_mlc *mlc, int unused)
+{
int i;
- /* Help the state engine:
- * Is this a real IDD response or just an echo?
+ /* Help the state engine:
+ * Is this a real IDD response or just an echo?
*
- * Real IDD response does not start with a command.
+ * Real IDD response does not start with a command.
*/
- if (mlc->ipacket[0] & HIL_PKT_CMD) goto bail;
+ if (mlc->ipacket[0] & HIL_PKT_CMD)
+ goto bail;
+
/* Should have the command echoed further down. */
for (i = 1; i < 16; i++) {
- if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
+ if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
(mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) &&
- (mlc->ipacket[i] & HIL_PKT_CMD) &&
+ (mlc->ipacket[i] & HIL_PKT_CMD) &&
((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
break;
}
- if (i > 15) goto bail;
+ if (i > 15)
+ goto bail;
+
/* And the rest of the packets should still be clear. */
- while (++i < 16) {
- if (mlc->ipacket[i]) break;
- }
- if (i < 16) goto bail;
- for (i = 0; i < 16; i++) {
- mlc->di_scratch.idd[i] =
+ while (++i < 16)
+ if (mlc->ipacket[i])
+ break;
+
+ if (i < 16)
+ goto bail;
+
+ for (i = 0; i < 16; i++)
+ mlc->di_scratch.idd[i] =
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
- }
+
/* Next step is to see if RSC supported */
- if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC)
+ if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC)
return HILSEN_NEXT;
- if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
+
+ if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
return HILSEN_DOWN | 4;
+
return 0;
+
bail:
mlc->ddi--;
+
return -1; /* This should send us off to ACF */
}
-static int hilse_take_rsc(hil_mlc *mlc, int unused) {
+static int hilse_take_rsc(hil_mlc *mlc, int unused)
+{
int i;
- for (i = 0; i < 16; i++) {
- mlc->di_scratch.rsc[i] =
+ for (i = 0; i < 16; i++)
+ mlc->di_scratch.rsc[i] =
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
- }
+
/* Next step is to see if EXD supported (IDD has already been read) */
- if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
+ if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
return HILSEN_NEXT;
+
return 0;
}
-static int hilse_take_exd(hil_mlc *mlc, int unused) {
+static int hilse_take_exd(hil_mlc *mlc, int unused)
+{
int i;
- for (i = 0; i < 16; i++) {
- mlc->di_scratch.exd[i] =
+ for (i = 0; i < 16; i++)
+ mlc->di_scratch.exd[i] =
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
- }
+
/* Next step is to see if RNM supported. */
- if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM)
+ if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM)
return HILSEN_NEXT;
+
return 0;
}
-static int hilse_take_rnm(hil_mlc *mlc, int unused) {
+static int hilse_take_rnm(hil_mlc *mlc, int unused)
+{
int i;
- for (i = 0; i < 16; i++) {
- mlc->di_scratch.rnm[i] =
+ for (i = 0; i < 16; i++)
+ mlc->di_scratch.rnm[i] =
mlc->ipacket[i] & HIL_PKT_DATA_MASK;
- }
- do {
- char nam[17];
- snprintf(nam, 16, "%s", mlc->di_scratch.rnm);
- nam[16] = '\0';
- printk(KERN_INFO PREFIX "Device name gotten: %s\n", nam);
- } while (0);
+
+ printk(KERN_INFO PREFIX "Device name gotten: %16s\n",
+ mlc->di_scratch.rnm);
+
return 0;
}
-static int hilse_operate(hil_mlc *mlc, int repoll) {
+static int hilse_operate(hil_mlc *mlc, int repoll)
+{
- if (mlc->opercnt == 0) hil_mlcs_probe = 0;
+ if (mlc->opercnt == 0)
+ hil_mlcs_probe = 0;
mlc->opercnt = 1;
hil_mlc_send_polls(mlc);
- if (!hil_mlcs_probe) return 0;
+ if (!hil_mlcs_probe)
+ return 0;
hil_mlcs_probe = 0;
mlc->opercnt = 0;
return 1;
@@ -408,7 +459,7 @@ static int hilse_operate(hil_mlc *mlc, int repoll) {
#define OUT_LAST(pack) \
{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 },
-struct hilse_node hil_mlc_se[HILSEN_END] = {
+const struct hilse_node hil_mlc_se[HILSEN_END] = {
/* 0 HILSEN_START */
FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
@@ -428,7 +479,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
EXPECT(HIL_ERR_INT | TEST_PACKET(0xa),
2000, HILSEN_NEXT, HILSEN_RESTART, HILSEN_RESTART)
OUT(HIL_CTRL_ONLY | 0) /* Disable test mode */
-
+
/* 9 HILSEN_DHR */
FUNC(hilse_init_lcv, 0, HILSEN_NEXT, HILSEN_SLEEP, 0)
@@ -439,7 +490,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
IN(300000, HILSEN_DHR2, HILSEN_DHR2, HILSEN_NEXT)
/* 14 HILSEN_IFC */
- OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+ OUT(HIL_PKT_CMD | HIL_CMD_IFC)
EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
20000, HILSEN_DISC, HILSEN_DHR2, HILSEN_NEXT )
@@ -455,7 +506,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
/* 18 HILSEN_HEAL */
OUT_LAST(HIL_CMD_ELB)
- EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,
+ EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,
20000, HILSEN_REPOLL, HILSEN_DSR, HILSEN_NEXT)
FUNC(hilse_dec_ddi, 0, HILSEN_HEAL, HILSEN_NEXT, 0)
@@ -503,7 +554,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
/* 44 HILSEN_PROBE */
OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)
- IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT)
+ IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT)
OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
IN(10000, HILSEN_DISC, HILSEN_DSR, HILSEN_NEXT)
OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
@@ -514,7 +565,7 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
/* 52 HILSEN_DSR */
FUNC(hilse_set_ddi, -1, HILSEN_NEXT, 0, 0)
OUT(HIL_PKT_CMD | HIL_CMD_DSR)
- IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC)
+ IN(20000, HILSEN_DHR, HILSEN_DHR, HILSEN_IFC)
/* 55 HILSEN_REPOLL */
OUT(HIL_PKT_CMD | HIL_CMD_RPL)
@@ -523,14 +574,15 @@ struct hilse_node hil_mlc_se[HILSEN_END] = {
FUNC(hilse_operate, 1, HILSEN_OPERATE, HILSEN_IFC, HILSEN_PROBE)
/* 58 HILSEN_IFCACF */
- OUT(HIL_PKT_CMD | HIL_CMD_IFC)
+ OUT(HIL_PKT_CMD | HIL_CMD_IFC)
EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
20000, HILSEN_ACF2, HILSEN_DHR2, HILSEN_HEAL)
/* 60 HILSEN_END */
};
-static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
+static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node)
+{
switch (node->act) {
case HILSE_EXPECT_DISC:
@@ -555,29 +607,27 @@ static inline void hilse_setup_input(hil_mlc *mlc, struct hilse_node *node) {
do_gettimeofday(&(mlc->instart));
mlc->icount = 15;
memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
- BUG_ON(down_trylock(&(mlc->isem)));
-
- return;
+ BUG_ON(down_trylock(&mlc->isem));
}
#ifdef HIL_MLC_DEBUG
-static int doze = 0;
+static int doze;
static int seidx; /* For debug */
-static int kick = 1;
#endif
-static int hilse_donode (hil_mlc *mlc) {
- struct hilse_node *node;
+static int hilse_donode(hil_mlc *mlc)
+{
+ const struct hilse_node *node;
int nextidx = 0;
int sched_long = 0;
unsigned long flags;
#ifdef HIL_MLC_DEBUG
- if (mlc->seidx && (mlc->seidx != seidx) && mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
- printk(KERN_DEBUG PREFIX "z%i \n%s {%i}", doze, kick ? "K" : "", mlc->seidx);
+ if (mlc->seidx && mlc->seidx != seidx &&
+ mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
+ printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);
doze = 0;
}
- kick = 0;
seidx = mlc->seidx;
#endif
@@ -588,52 +638,61 @@ static int hilse_donode (hil_mlc *mlc) {
hil_packet pack;
case HILSE_FUNC:
- if (node->object.func == NULL) break;
+ BUG_ON(node->object.func == NULL);
rc = node->object.func(mlc, node->arg);
- nextidx = (rc > 0) ? node->ugly :
+ nextidx = (rc > 0) ? node->ugly :
((rc < 0) ? node->bad : node->good);
- if (nextidx == HILSEN_FOLLOW) nextidx = rc;
+ if (nextidx == HILSEN_FOLLOW)
+ nextidx = rc;
break;
+
case HILSE_EXPECT_LAST:
case HILSE_EXPECT_DISC:
case HILSE_EXPECT:
case HILSE_IN:
/* Already set up from previous HILSE_OUT_* */
- write_lock_irqsave(&(mlc->lock), flags);
+ write_lock_irqsave(&mlc->lock, flags);
rc = mlc->in(mlc, node->arg);
if (rc == 2) {
nextidx = HILSEN_DOZE;
sched_long = 1;
- write_unlock_irqrestore(&(mlc->lock), flags);
+ write_unlock_irqrestore(&mlc->lock, flags);
break;
}
- if (rc == 1) nextidx = node->ugly;
- else if (rc == 0) nextidx = node->good;
- else nextidx = node->bad;
+ if (rc == 1)
+ nextidx = node->ugly;
+ else if (rc == 0)
+ nextidx = node->good;
+ else
+ nextidx = node->bad;
mlc->istarted = 0;
- write_unlock_irqrestore(&(mlc->lock), flags);
+ write_unlock_irqrestore(&mlc->lock, flags);
break;
+
case HILSE_OUT_LAST:
- write_lock_irqsave(&(mlc->lock), flags);
+ write_lock_irqsave(&mlc->lock, flags);
pack = node->object.packet;
pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
goto out;
+
case HILSE_OUT_DISC:
- write_lock_irqsave(&(mlc->lock), flags);
+ write_lock_irqsave(&mlc->lock, flags);
pack = node->object.packet;
pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
goto out;
+
case HILSE_OUT:
- write_lock_irqsave(&(mlc->lock), flags);
+ write_lock_irqsave(&mlc->lock, flags);
pack = node->object.packet;
out:
- if (mlc->istarted) goto out2;
+ if (mlc->istarted)
+ goto out2;
/* Prepare to receive input */
if ((node + 1)->act & HILSE_IN)
hilse_setup_input(mlc, node + 1);
out2:
- write_unlock_irqrestore(&(mlc->lock), flags);
+ write_unlock_irqrestore(&mlc->lock, flags);
if (down_trylock(&mlc->osem)) {
nextidx = HILSEN_DOZE;
@@ -641,60 +700,71 @@ static int hilse_donode (hil_mlc *mlc) {
}
up(&mlc->osem);
- write_lock_irqsave(&(mlc->lock), flags);
- if (!(mlc->ostarted)) {
+ write_lock_irqsave(&mlc->lock, flags);
+ if (!mlc->ostarted) {
mlc->ostarted = 1;
mlc->opacket = pack;
mlc->out(mlc);
nextidx = HILSEN_DOZE;
- write_unlock_irqrestore(&(mlc->lock), flags);
+ write_unlock_irqrestore(&mlc->lock, flags);
break;
}
mlc->ostarted = 0;
do_gettimeofday(&(mlc->instart));
- write_unlock_irqrestore(&(mlc->lock), flags);
+ write_unlock_irqrestore(&mlc->lock, flags);
nextidx = HILSEN_NEXT;
break;
+
case HILSE_CTS:
+ write_lock_irqsave(&mlc->lock, flags);
nextidx = mlc->cts(mlc) ? node->bad : node->good;
+ write_unlock_irqrestore(&mlc->lock, flags);
break;
+
default:
BUG();
- nextidx = 0;
- break;
}
#ifdef HIL_MLC_DEBUG
- if (nextidx == HILSEN_DOZE) doze++;
+ if (nextidx == HILSEN_DOZE)
+ doze++;
#endif
while (nextidx & HILSEN_SCHED) {
struct timeval tv;
- if (!sched_long) goto sched;
+ if (!sched_long)
+ goto sched;
do_gettimeofday(&tv);
- tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+ tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
tv.tv_usec -= mlc->instart.tv_usec;
if (tv.tv_usec >= mlc->intimeout) goto sched;
- tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / 1000000;
+ tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC;
if (!tv.tv_usec) goto sched;
mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
break;
sched:
tasklet_schedule(&hil_mlcs_tasklet);
break;
- }
- if (nextidx & HILSEN_DOWN) mlc->seidx += nextidx & HILSEN_MASK;
- else if (nextidx & HILSEN_UP) mlc->seidx -= nextidx & HILSEN_MASK;
- else mlc->seidx = nextidx & HILSEN_MASK;
+ }
+
+ if (nextidx & HILSEN_DOWN)
+ mlc->seidx += nextidx & HILSEN_MASK;
+ else if (nextidx & HILSEN_UP)
+ mlc->seidx -= nextidx & HILSEN_MASK;
+ else
+ mlc->seidx = nextidx & HILSEN_MASK;
+
+ if (nextidx & HILSEN_BREAK)
+ return 1;
- if (nextidx & HILSEN_BREAK) return 1;
return 0;
}
/******************** tasklet context functions **************************/
-static void hil_mlcs_process(unsigned long unused) {
+static void hil_mlcs_process(unsigned long unused)
+{
struct list_head *tmp;
read_lock(&hil_mlcs_lock);
@@ -702,19 +772,20 @@ static void hil_mlcs_process(unsigned long unused) {
struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
while (hilse_donode(mlc) == 0) {
#ifdef HIL_MLC_DEBUG
- if (mlc->seidx != 41 &&
- mlc->seidx != 42 &&
- mlc->seidx != 43)
- printk(KERN_DEBUG PREFIX " + ");
+ if (mlc->seidx != 41 &&
+ mlc->seidx != 42 &&
+ mlc->seidx != 43)
+ printk(KERN_DEBUG PREFIX " + ");
#endif
- };
+ }
}
read_unlock(&hil_mlcs_lock);
}
/************************* Keepalive timer task *********************/
-void hil_mlcs_timer (unsigned long data) {
+void hil_mlcs_timer(unsigned long data)
+{
hil_mlcs_probe = 1;
tasklet_schedule(&hil_mlcs_tasklet);
/* Re-insert the periodic task. */
@@ -724,28 +795,25 @@ void hil_mlcs_timer (unsigned long data) {
/******************** user/kernel context functions **********************/
-static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
+static int hil_mlc_serio_write(struct serio *serio, unsigned char c)
+{
struct hil_mlc_serio_map *map;
struct hil_mlc *mlc;
struct serio_driver *drv;
uint8_t *idx, *last;
map = serio->port_data;
- if (map == NULL) {
- BUG();
- return -EIO;
- }
+ BUG_ON(map == NULL);
+
mlc = map->mlc;
- if (mlc == NULL) {
- BUG();
- return -EIO;
- }
- mlc->serio_opacket[map->didx] |=
+ BUG_ON(mlc == NULL);
+
+ mlc->serio_opacket[map->didx] |=
((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
if (mlc->serio_oidx[map->didx] >= 3) {
/* for now only commands */
- if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
+ if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
return -EIO;
switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
case HIL_CMD_IDD:
@@ -771,12 +839,11 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
return -EIO;
emu:
drv = serio->drv;
- if (drv == NULL) {
- BUG();
- return -EIO;
- }
+ BUG_ON(drv == NULL);
+
last = idx + 15;
- while ((last != idx) && (*last == 0)) last--;
+ while ((last != idx) && (*last == 0))
+ last--;
while (idx != last) {
drv->interrupt(serio, 0, 0);
@@ -789,14 +856,15 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
drv->interrupt(serio, *idx, 0);
-
+
mlc->serio_oidx[map->didx] = 0;
mlc->serio_opacket[map->didx] = 0;
return 0;
}
-static int hil_mlc_serio_open(struct serio *serio) {
+static int hil_mlc_serio_open(struct serio *serio)
+{
struct hil_mlc_serio_map *map;
struct hil_mlc *mlc;
@@ -804,67 +872,57 @@ static int hil_mlc_serio_open(struct serio *serio) {
return -EBUSY;
map = serio->port_data;
- if (map == NULL) {
- BUG();
- return -ENODEV;
- }
+ BUG_ON(map == NULL);
+
mlc = map->mlc;
- if (mlc == NULL) {
- BUG();
- return -ENODEV;
- }
+ BUG_ON(mlc == NULL);
return 0;
}
-static void hil_mlc_serio_close(struct serio *serio) {
+static void hil_mlc_serio_close(struct serio *serio)
+{
struct hil_mlc_serio_map *map;
struct hil_mlc *mlc;
map = serio->port_data;
- if (map == NULL) {
- BUG();
- return;
- }
+ BUG_ON(map == NULL);
+
mlc = map->mlc;
- if (mlc == NULL) {
- BUG();
- return;
- }
+ BUG_ON(mlc == NULL);
serio_set_drvdata(serio, NULL);
serio->drv = NULL;
/* TODO wake up interruptable */
}
-static struct serio_device_id hil_mlc_serio_id = {
+static const struct serio_device_id hil_mlc_serio_id = {
.type = SERIO_HIL_MLC,
.proto = SERIO_HIL,
.extra = SERIO_ANY,
.id = SERIO_ANY,
};
-int hil_mlc_register(hil_mlc *mlc) {
+int hil_mlc_register(hil_mlc *mlc)
+{
int i;
- unsigned long flags;
+ unsigned long flags;
- if (mlc == NULL) {
- return -EINVAL;
- }
+ BUG_ON(mlc == NULL);
mlc->istarted = 0;
- mlc->ostarted = 0;
+ mlc->ostarted = 0;
- rwlock_init(&mlc->lock);
- init_MUTEX(&(mlc->osem));
+ rwlock_init(&mlc->lock);
+ init_MUTEX(&mlc->osem);
- init_MUTEX(&(mlc->isem));
- mlc->icount = -1;
- mlc->imatch = 0;
+ init_MUTEX(&mlc->isem);
+ mlc->icount = -1;
+ mlc->imatch = 0;
mlc->opercnt = 0;
- init_MUTEX_LOCKED(&(mlc->csem));
+ init_MUTEX_LOCKED(&(mlc->csem));
hil_mlc_clear_di_scratch(mlc);
hil_mlc_clear_di_map(mlc, 0);
@@ -873,6 +931,8 @@ int hil_mlc_register(hil_mlc *mlc) {
hil_mlc_copy_di_scratch(mlc, i);
mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
mlc->serio[i] = mlc_serio;
+ snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
+ snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
mlc_serio->id = hil_mlc_serio_id;
mlc_serio->write = hil_mlc_serio_write;
mlc_serio->open = hil_mlc_serio_open;
@@ -897,19 +957,18 @@ int hil_mlc_register(hil_mlc *mlc) {
return 0;
}
-int hil_mlc_unregister(hil_mlc *mlc) {
+int hil_mlc_unregister(hil_mlc *mlc)
+{
struct list_head *tmp;
- unsigned long flags;
+ unsigned long flags;
int i;
- if (mlc == NULL)
- return -EINVAL;
+ BUG_ON(mlc == NULL);
write_lock_irqsave(&hil_mlcs_lock, flags);
- list_for_each(tmp, &hil_mlcs) {
+ list_for_each(tmp, &hil_mlcs)
if (list_entry(tmp, hil_mlc, list) == mlc)
goto found;
- }
/* not found in list */
write_unlock_irqrestore(&hil_mlcs_lock, flags);
@@ -918,7 +977,7 @@ int hil_mlc_unregister(hil_mlc *mlc) {
found:
list_del(tmp);
- write_unlock_irqrestore(&hil_mlcs_lock, flags);
+ write_unlock_irqrestore(&hil_mlcs_lock, flags);
for (i = 0; i < HIL_MLC_DEVMEM; i++) {
serio_unregister_port(mlc->serio[i]);
@@ -942,7 +1001,7 @@ static int __init hil_mlc_init(void)
return 0;
}
-
+
static void __exit hil_mlc_exit(void)
{
del_timer(&hil_mlcs_kicker);
@@ -950,6 +1009,6 @@ static void __exit hil_mlc_exit(void)
tasklet_disable(&hil_mlcs_tasklet);
tasklet_kill(&hil_mlcs_tasklet);
}
-
+
module_init(hil_mlc_init);
module_exit(hil_mlc_exit);
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index b57370dc4e3..6af199805ff 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -34,27 +34,27 @@
*
* Driver theory of operation:
*
- * hp_sdc_put does all writing to the SDC. ISR can run on a different
- * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time
+ * hp_sdc_put does all writing to the SDC. ISR can run on a different
+ * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time
* (it cannot really benefit from SMP anyway.) A tasket fit this perfectly.
*
- * All data coming back from the SDC is sent via interrupt and can be read
- * fully in the ISR, so there are no latency/throughput problems there.
- * The problem is with output, due to the slow clock speed of the SDC
- * compared to the CPU. This should not be too horrible most of the time,
- * but if used with HIL devices that support the multibyte transfer command,
- * keeping outbound throughput flowing at the 6500KBps that the HIL is
+ * All data coming back from the SDC is sent via interrupt and can be read
+ * fully in the ISR, so there are no latency/throughput problems there.
+ * The problem is with output, due to the slow clock speed of the SDC
+ * compared to the CPU. This should not be too horrible most of the time,
+ * but if used with HIL devices that support the multibyte transfer command,
+ * keeping outbound throughput flowing at the 6500KBps that the HIL is
* capable of is more than can be done at HZ=100.
*
- * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf
- * is set to 0 when the IBF flag in the status register has cleared. ISR
- * may do this, and may also access the parts of queued transactions related
- * to reading data back from the SDC, but otherwise will not touch the
+ * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf
+ * is set to 0 when the IBF flag in the status register has cleared. ISR
+ * may do this, and may also access the parts of queued transactions related
+ * to reading data back from the SDC, but otherwise will not touch the
* hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1.
*
* The i8042 write index and the values in the 4-byte input buffer
* starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively,
- * to minimize the amount of IO needed to the SDC. However these values
+ * to minimize the amount of IO needed to the SDC. However these values
* do not need to be locked since they are only ever accessed by hp_sdc_put.
*
* A timer task schedules the tasklet once per second just to make
@@ -100,39 +100,46 @@ EXPORT_SYMBOL(hp_sdc_release_timer_irq);
EXPORT_SYMBOL(hp_sdc_release_hil_irq);
EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
+EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */
/*************** primitives for use in any context *********************/
-static inline uint8_t hp_sdc_status_in8 (void) {
+static inline uint8_t hp_sdc_status_in8(void)
+{
uint8_t status;
unsigned long flags;
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
status = sdc_readb(hp_sdc.status_io);
- if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0;
+ if (!(status & HP_SDC_STATUS_IBF))
+ hp_sdc.ibf = 0;
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
return status;
}
-static inline uint8_t hp_sdc_data_in8 (void) {
- return sdc_readb(hp_sdc.data_io);
+static inline uint8_t hp_sdc_data_in8(void)
+{
+ return sdc_readb(hp_sdc.data_io);
}
-static inline void hp_sdc_status_out8 (uint8_t val) {
+static inline void hp_sdc_status_out8(uint8_t val)
+{
unsigned long flags;
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
hp_sdc.ibf = 1;
- if ((val & 0xf0) == 0xe0) hp_sdc.wi = 0xff;
+ if ((val & 0xf0) == 0xe0)
+ hp_sdc.wi = 0xff;
sdc_writeb(val, hp_sdc.status_io);
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
}
-static inline void hp_sdc_data_out8 (uint8_t val) {
+static inline void hp_sdc_data_out8(uint8_t val)
+{
unsigned long flags;
write_lock_irqsave(&hp_sdc.ibf_lock, flags);
@@ -141,11 +148,12 @@ static inline void hp_sdc_data_out8 (uint8_t val) {
write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
}
-/* Care must be taken to only invoke hp_sdc_spin_ibf when
- * absolutely needed, or in rarely invoked subroutines.
- * Not only does it waste CPU cycles, it also wastes bus cycles.
+/* Care must be taken to only invoke hp_sdc_spin_ibf when
+ * absolutely needed, or in rarely invoked subroutines.
+ * Not only does it waste CPU cycles, it also wastes bus cycles.
*/
-static inline void hp_sdc_spin_ibf(void) {
+static inline void hp_sdc_spin_ibf(void)
+{
unsigned long flags;
rwlock_t *lock;
@@ -158,19 +166,21 @@ static inline void hp_sdc_spin_ibf(void) {
}
read_unlock(lock);
write_lock(lock);
- while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {};
+ while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF)
+ { }
hp_sdc.ibf = 0;
write_unlock_irqrestore(lock, flags);
}
/************************ Interrupt context functions ************************/
-static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
+static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data)
+{
hp_sdc_transaction *curr;
read_lock(&hp_sdc.rtq_lock);
if (hp_sdc.rcurr < 0) {
- read_unlock(&hp_sdc.rtq_lock);
+ read_unlock(&hp_sdc.rtq_lock);
return;
}
curr = hp_sdc.tq[hp_sdc.rcurr];
@@ -183,25 +193,27 @@ static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
if (hp_sdc.rqty <= 0) {
/* All data has been gathered. */
- if(curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE) {
- if (curr->act.semaphore) up(curr->act.semaphore);
- }
- if(curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK) {
+ if (curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE)
+ if (curr->act.semaphore)
+ up(curr->act.semaphore);
+
+ if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK)
if (curr->act.irqhook)
curr->act.irqhook(irq, dev_id, status, data);
- }
+
curr->actidx = curr->idx;
curr->idx++;
/* Return control of this transaction */
write_lock(&hp_sdc.rtq_lock);
- hp_sdc.rcurr = -1;
+ hp_sdc.rcurr = -1;
hp_sdc.rqty = 0;
write_unlock(&hp_sdc.rtq_lock);
tasklet_schedule(&hp_sdc.task);
}
}
-static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
+static irqreturn_t hp_sdc_isr(int irq, void *dev_id)
+{
uint8_t status, data;
status = hp_sdc_status_in8();
@@ -209,67 +221,74 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
data = hp_sdc_data_in8();
/* For now we are ignoring these until we get the SDC to behave. */
- if (((status & 0xf1) == 0x51) && data == 0x82) {
- return IRQ_HANDLED;
- }
+ if (((status & 0xf1) == 0x51) && data == 0x82)
+ return IRQ_HANDLED;
- switch(status & HP_SDC_STATUS_IRQMASK) {
- case 0: /* This case is not documented. */
+ switch (status & HP_SDC_STATUS_IRQMASK) {
+ case 0: /* This case is not documented. */
break;
- case HP_SDC_STATUS_USERTIMER:
- case HP_SDC_STATUS_PERIODIC:
- case HP_SDC_STATUS_TIMER:
+
+ case HP_SDC_STATUS_USERTIMER:
+ case HP_SDC_STATUS_PERIODIC:
+ case HP_SDC_STATUS_TIMER:
read_lock(&hp_sdc.hook_lock);
- if (hp_sdc.timer != NULL)
+ if (hp_sdc.timer != NULL)
hp_sdc.timer(irq, dev_id, status, data);
read_unlock(&hp_sdc.hook_lock);
break;
- case HP_SDC_STATUS_REG:
+
+ case HP_SDC_STATUS_REG:
hp_sdc_take(irq, dev_id, status, data);
break;
- case HP_SDC_STATUS_HILCMD:
- case HP_SDC_STATUS_HILDATA:
+
+ case HP_SDC_STATUS_HILCMD:
+ case HP_SDC_STATUS_HILDATA:
read_lock(&hp_sdc.hook_lock);
if (hp_sdc.hil != NULL)
hp_sdc.hil(irq, dev_id, status, data);
read_unlock(&hp_sdc.hook_lock);
break;
- case HP_SDC_STATUS_PUP:
+
+ case HP_SDC_STATUS_PUP:
read_lock(&hp_sdc.hook_lock);
if (hp_sdc.pup != NULL)
hp_sdc.pup(irq, dev_id, status, data);
- else printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
+ else
+ printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
read_unlock(&hp_sdc.hook_lock);
break;
- default:
+
+ default:
read_lock(&hp_sdc.hook_lock);
if (hp_sdc.cooked != NULL)
hp_sdc.cooked(irq, dev_id, status, data);
read_unlock(&hp_sdc.hook_lock);
break;
}
+
return IRQ_HANDLED;
}
-static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
+static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id)
+{
int status;
-
+
status = hp_sdc_status_in8();
printk(KERN_WARNING PREFIX "NMI !\n");
-#if 0
+#if 0
if (status & HP_SDC_NMISTATUS_FHS) {
read_lock(&hp_sdc.hook_lock);
- if (hp_sdc.timer != NULL)
+ if (hp_sdc.timer != NULL)
hp_sdc.timer(irq, dev_id, status, 0);
read_unlock(&hp_sdc.hook_lock);
- }
- else {
+ } else {
/* TODO: pass this on to the HIL handler, or do SAK here? */
printk(KERN_WARNING PREFIX "HIL NMI\n");
}
#endif
+
return IRQ_HANDLED;
}
@@ -278,13 +297,17 @@ static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
unsigned long hp_sdc_put(void);
-static void hp_sdc_tasklet(unsigned long foo) {
-
+static void hp_sdc_tasklet(unsigned long foo)
+{
write_lock_irq(&hp_sdc.rtq_lock);
+
if (hp_sdc.rcurr >= 0) {
struct timeval tv;
+
do_gettimeofday(&tv);
- if (tv.tv_sec > hp_sdc.rtv.tv_sec) tv.tv_usec += 1000000;
+ if (tv.tv_sec > hp_sdc.rtv.tv_sec)
+ tv.tv_usec += USEC_PER_SEC;
+
if (tv.tv_usec - hp_sdc.rtv.tv_usec > HP_SDC_MAX_REG_DELAY) {
hp_sdc_transaction *curr;
uint8_t tmp;
@@ -300,27 +323,29 @@ static void hp_sdc_tasklet(unsigned long foo) {
hp_sdc.rqty = 0;
tmp = curr->seq[curr->actidx];
curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
- if(tmp & HP_SDC_ACT_SEMAPHORE) {
- if (curr->act.semaphore)
+ if (tmp & HP_SDC_ACT_SEMAPHORE)
+ if (curr->act.semaphore)
up(curr->act.semaphore);
- }
- if(tmp & HP_SDC_ACT_CALLBACK) {
+
+ if (tmp & HP_SDC_ACT_CALLBACK) {
/* Note this means that irqhooks may be called
* in tasklet/bh context.
*/
- if (curr->act.irqhook)
+ if (curr->act.irqhook)
curr->act.irqhook(0, NULL, 0, 0);
}
+
curr->actidx = curr->idx;
curr->idx++;
- hp_sdc.rcurr = -1;
+ hp_sdc.rcurr = -1;
}
}
write_unlock_irq(&hp_sdc.rtq_lock);
hp_sdc_put();
}
-unsigned long hp_sdc_put(void) {
+unsigned long hp_sdc_put(void)
+{
hp_sdc_transaction *curr;
uint8_t act;
int idx, curridx;
@@ -333,19 +358,24 @@ unsigned long hp_sdc_put(void) {
requires output, so we skip to the administrativa. */
if (hp_sdc.ibf) {
hp_sdc_status_in8();
- if (hp_sdc.ibf) goto finish;
+ if (hp_sdc.ibf)
+ goto finish;
}
anew:
/* See if we are in the middle of a sequence. */
- if (hp_sdc.wcurr < 0) hp_sdc.wcurr = 0;
+ if (hp_sdc.wcurr < 0)
+ hp_sdc.wcurr = 0;
read_lock_irq(&hp_sdc.rtq_lock);
- if (hp_sdc.rcurr == hp_sdc.wcurr) hp_sdc.wcurr++;
+ if (hp_sdc.rcurr == hp_sdc.wcurr)
+ hp_sdc.wcurr++;
read_unlock_irq(&hp_sdc.rtq_lock);
- if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+ if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+ hp_sdc.wcurr = 0;
curridx = hp_sdc.wcurr;
- if (hp_sdc.tq[curridx] != NULL) goto start;
+ if (hp_sdc.tq[curridx] != NULL)
+ goto start;
while (++curridx != hp_sdc.wcurr) {
if (curridx >= HP_SDC_QUEUE_LEN) {
@@ -358,7 +388,8 @@ unsigned long hp_sdc_put(void) {
continue;
}
read_unlock_irq(&hp_sdc.rtq_lock);
- if (hp_sdc.tq[curridx] != NULL) break; /* Found one. */
+ if (hp_sdc.tq[curridx] != NULL)
+ break; /* Found one. */
}
if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
curridx = -1;
@@ -374,7 +405,8 @@ unsigned long hp_sdc_put(void) {
goto finish;
}
- if (hp_sdc.wcurr == -1) goto done;
+ if (hp_sdc.wcurr == -1)
+ goto done;
curr = hp_sdc.tq[curridx];
idx = curr->actidx;
@@ -383,20 +415,23 @@ unsigned long hp_sdc_put(void) {
hp_sdc.tq[curridx] = NULL;
/* Interleave outbound data between the transactions. */
hp_sdc.wcurr++;
- if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
- goto finish;
+ if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+ hp_sdc.wcurr = 0;
+ goto finish;
}
act = curr->seq[idx];
idx++;
if (curr->idx >= curr->endidx) {
- if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+ if (act & HP_SDC_ACT_DEALLOC)
+ kfree(curr);
hp_sdc.tq[curridx] = NULL;
/* Interleave outbound data between the transactions. */
hp_sdc.wcurr++;
- if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
- goto finish;
+ if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+ hp_sdc.wcurr = 0;
+ goto finish;
}
while (act & HP_SDC_ACT_PRECMD) {
@@ -409,9 +444,10 @@ unsigned long hp_sdc_put(void) {
curr->idx++;
/* act finished? */
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
- goto actdone;
+ goto actdone;
/* skip quantity field if data-out sequence follows. */
- if (act & HP_SDC_ACT_DATAOUT) curr->idx++;
+ if (act & HP_SDC_ACT_DATAOUT)
+ curr->idx++;
goto finish;
}
if (act & HP_SDC_ACT_DATAOUT) {
@@ -423,15 +459,15 @@ unsigned long hp_sdc_put(void) {
hp_sdc_data_out8(curr->seq[curr->idx]);
curr->idx++;
/* act finished? */
- if ((curr->idx - idx >= qty) &&
- ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT))
+ if (curr->idx - idx >= qty &&
+ (act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)
goto actdone;
goto finish;
}
idx += qty;
act &= ~HP_SDC_ACT_DATAOUT;
- }
- else while (act & HP_SDC_ACT_DATAREG) {
+ } else
+ while (act & HP_SDC_ACT_DATAREG) {
int mask;
uint8_t w7[4];
@@ -445,26 +481,30 @@ unsigned long hp_sdc_put(void) {
act &= ~HP_SDC_ACT_DATAREG;
break;
}
-
+
w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
-
+
if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
- w7[hp_sdc.wi-0x70] == hp_sdc.r7[hp_sdc.wi-0x70]) {
+ w7[hp_sdc.wi - 0x70] == hp_sdc.r7[hp_sdc.wi - 0x70]) {
int i = 0;
- /* Need to point the write index register */
- while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+ /* Need to point the write index register */
+ while (i < 4 && w7[i] == hp_sdc.r7[i])
+ i++;
+
if (i < 4) {
hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
hp_sdc.wi = 0x70 + i;
goto finish;
}
+
idx++;
if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
goto actdone;
+
curr->idx = idx;
act &= ~HP_SDC_ACT_DATAREG;
break;
@@ -476,12 +516,13 @@ unsigned long hp_sdc_put(void) {
{
int i = 0;
- while ((i < 4) && w7[i] == hp_sdc.r7[i]) i++;
+ while ((i < 4) && w7[i] == hp_sdc.r7[i])
+ i++;
if (i >= 4) {
curr->idx = idx + 1;
- if ((act & HP_SDC_ACT_DURING) ==
+ if ((act & HP_SDC_ACT_DURING) ==
HP_SDC_ACT_DATAREG)
- goto actdone;
+ goto actdone;
}
}
goto finish;
@@ -497,7 +538,7 @@ unsigned long hp_sdc_put(void) {
if (act & HP_SDC_ACT_POSTCMD) {
- uint8_t postcmd;
+ uint8_t postcmd;
/* curr->idx should == idx at this point. */
postcmd = curr->seq[idx];
@@ -505,12 +546,12 @@ unsigned long hp_sdc_put(void) {
if (act & HP_SDC_ACT_DATAIN) {
/* Start a new read */
- hp_sdc.rqty = curr->seq[curr->idx];
+ hp_sdc.rqty = curr->seq[curr->idx];
do_gettimeofday(&hp_sdc.rtv);
curr->idx++;
/* Still need to lock here in case of spurious irq. */
write_lock_irq(&hp_sdc.rtq_lock);
- hp_sdc.rcurr = curridx;
+ hp_sdc.rcurr = curridx;
write_unlock_irq(&hp_sdc.rtq_lock);
hp_sdc_status_out8(postcmd);
goto finish;
@@ -519,75 +560,86 @@ unsigned long hp_sdc_put(void) {
goto actdone;
}
-actdone:
- if (act & HP_SDC_ACT_SEMAPHORE) {
+ actdone:
+ if (act & HP_SDC_ACT_SEMAPHORE)
up(curr->act.semaphore);
- }
- else if (act & HP_SDC_ACT_CALLBACK) {
+ else if (act & HP_SDC_ACT_CALLBACK)
curr->act.irqhook(0,NULL,0,0);
- }
+
if (curr->idx >= curr->endidx) { /* This transaction is over. */
- if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
+ if (act & HP_SDC_ACT_DEALLOC)
+ kfree(curr);
hp_sdc.tq[curridx] = NULL;
- }
- else {
+ } else {
curr->actidx = idx + 1;
curr->idx = idx + 2;
}
/* Interleave outbound data between the transactions. */
hp_sdc.wcurr++;
- if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN) hp_sdc.wcurr = 0;
+ if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
+ hp_sdc.wcurr = 0;
finish:
- /* If by some quirk IBF has cleared and our ISR has run to
+ /* If by some quirk IBF has cleared and our ISR has run to
see that that has happened, do it all again. */
- if (!hp_sdc.ibf && limit++ < 20) goto anew;
+ if (!hp_sdc.ibf && limit++ < 20)
+ goto anew;
done:
- if (hp_sdc.wcurr >= 0) tasklet_schedule(&hp_sdc.task);
+ if (hp_sdc.wcurr >= 0)
+ tasklet_schedule(&hp_sdc.task);
write_unlock(&hp_sdc.lock);
+
return 0;
}
/******* Functions called in either user or kernel context ****/
-int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
- unsigned long flags;
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
+{
int i;
if (this == NULL) {
- tasklet_schedule(&hp_sdc.task);
+ BUG();
return -EINVAL;
- };
-
- write_lock_irqsave(&hp_sdc.lock, flags);
+ }
/* Can't have same transaction on queue twice */
- for (i=0; i < HP_SDC_QUEUE_LEN; i++)
- if (hp_sdc.tq[i] == this) goto fail;
+ for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
+ if (hp_sdc.tq[i] == this)
+ goto fail;
this->actidx = 0;
this->idx = 1;
/* Search for empty slot */
- for (i=0; i < HP_SDC_QUEUE_LEN; i++) {
+ for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
if (hp_sdc.tq[i] == NULL) {
hp_sdc.tq[i] = this;
- write_unlock_irqrestore(&hp_sdc.lock, flags);
tasklet_schedule(&hp_sdc.task);
return 0;
}
- }
- write_unlock_irqrestore(&hp_sdc.lock, flags);
+
printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
return -EBUSY;
fail:
- write_unlock_irqrestore(&hp_sdc.lock,flags);
printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
return -EINVAL;
}
-int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
+int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&hp_sdc.lock, flags);
+ ret = __hp_sdc_enqueue_transaction(this);
+ write_unlock_irqrestore(&hp_sdc.lock,flags);
+
+ return ret;
+}
+
+int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
+{
unsigned long flags;
int i;
@@ -595,8 +647,9 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
/* TODO: don't remove it if it's not done. */
- for (i=0; i < HP_SDC_QUEUE_LEN; i++)
- if (hp_sdc.tq[i] == this) hp_sdc.tq[i] = NULL;
+ for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
+ if (hp_sdc.tq[i] == this)
+ hp_sdc.tq[i] = NULL;
write_unlock_irqrestore(&hp_sdc.lock, flags);
return 0;
@@ -605,11 +658,11 @@ int hp_sdc_dequeue_transaction(hp_sdc_transaction *this) {
/********************** User context functions **************************/
-int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
-
- if (callback == NULL || hp_sdc.dev == NULL) {
+int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback)
+{
+ if (callback == NULL || hp_sdc.dev == NULL)
return -EINVAL;
- }
+
write_lock_irq(&hp_sdc.hook_lock);
if (hp_sdc.timer != NULL) {
write_unlock_irq(&hp_sdc.hook_lock);
@@ -629,11 +682,11 @@ int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback) {
return 0;
}
-int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
-
- if (callback == NULL || hp_sdc.dev == NULL) {
+int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback)
+{
+ if (callback == NULL || hp_sdc.dev == NULL)
return -EINVAL;
- }
+
write_lock_irq(&hp_sdc.hook_lock);
if (hp_sdc.hil != NULL) {
write_unlock_irq(&hp_sdc.hook_lock);
@@ -650,11 +703,11 @@ int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback) {
return 0;
}
-int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
-
- if (callback == NULL || hp_sdc.dev == NULL) {
+int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback)
+{
+ if (callback == NULL || hp_sdc.dev == NULL)
return -EINVAL;
- }
+
write_lock_irq(&hp_sdc.hook_lock);
if (hp_sdc.cooked != NULL) {
write_unlock_irq(&hp_sdc.hook_lock);
@@ -672,9 +725,8 @@ int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback) {
return 0;
}
-int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
-
-
+int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback)
+{
write_lock_irq(&hp_sdc.hook_lock);
if ((callback != hp_sdc.timer) ||
(hp_sdc.timer == NULL)) {
@@ -694,8 +746,8 @@ int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback) {
return 0;
}
-int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
-
+int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback)
+{
write_lock_irq(&hp_sdc.hook_lock);
if ((callback != hp_sdc.hil) ||
(hp_sdc.hil == NULL)) {
@@ -715,8 +767,8 @@ int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback) {
return 0;
}
-int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
-
+int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
+{
write_lock_irq(&hp_sdc.hook_lock);
if ((callback != hp_sdc.cooked) ||
(hp_sdc.cooked == NULL)) {
@@ -738,7 +790,8 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) {
/************************* Keepalive timer task *********************/
-void hp_sdc_kicker (unsigned long data) {
+void hp_sdc_kicker (unsigned long data)
+{
tasklet_schedule(&hp_sdc.task);
/* Re-insert the periodic task. */
mod_timer(&hp_sdc.kicker, jiffies + HZ);
@@ -748,12 +801,12 @@ void hp_sdc_kicker (unsigned long data) {
#if defined(__hppa__)
-static struct parisc_device_id hp_sdc_tbl[] = {
+static const struct parisc_device_id hp_sdc_tbl[] = {
{
- .hw_type = HPHW_FIO,
+ .hw_type = HPHW_FIO,
.hversion_rev = HVERSION_REV_ANY_ID,
.hversion = HVERSION_ANY_ID,
- .sversion = 0x73,
+ .sversion = 0x73,
},
{ 0, }
};
@@ -772,16 +825,15 @@ static struct parisc_driver hp_sdc_driver = {
static int __init hp_sdc_init(void)
{
- int i;
char *errstr;
hp_sdc_transaction t_sync;
uint8_t ts_sync[6];
struct semaphore s_sync;
- rwlock_init(&hp_sdc.lock);
- rwlock_init(&hp_sdc.ibf_lock);
- rwlock_init(&hp_sdc.rtq_lock);
- rwlock_init(&hp_sdc.hook_lock);
+ rwlock_init(&hp_sdc.lock);
+ rwlock_init(&hp_sdc.ibf_lock);
+ rwlock_init(&hp_sdc.rtq_lock);
+ rwlock_init(&hp_sdc.hook_lock);
hp_sdc.timer = NULL;
hp_sdc.hil = NULL;
@@ -796,7 +848,8 @@ static int __init hp_sdc_init(void)
hp_sdc.r7[3] = 0xff;
hp_sdc.ibf = 1;
- for (i = 0; i < HP_SDC_QUEUE_LEN; i++) hp_sdc.tq[i] = NULL;
+ memset(&hp_sdc.tq, 0, sizeof(hp_sdc.tq));
+
hp_sdc.wcurr = -1;
hp_sdc.rcurr = -1;
hp_sdc.rqty = 0;
@@ -804,27 +857,32 @@ static int __init hp_sdc_init(void)
hp_sdc.dev_err = -ENODEV;
errstr = "IO not found for";
- if (!hp_sdc.base_io) goto err0;
+ if (!hp_sdc.base_io)
+ goto err0;
errstr = "IRQ not found for";
- if (!hp_sdc.irq) goto err0;
+ if (!hp_sdc.irq)
+ goto err0;
hp_sdc.dev_err = -EBUSY;
#if defined(__hppa__)
errstr = "IO not available for";
- if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name)) goto err0;
-#endif
+ if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
+ goto err0;
+#endif
errstr = "IRQ not available for";
- if(request_irq(hp_sdc.irq, &hp_sdc_isr, 0, "HP SDC",
- (void *) hp_sdc.base_io)) goto err1;
+ if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED|IRQF_SAMPLE_RANDOM,
+ "HP SDC", &hp_sdc))
+ goto err1;
errstr = "NMI not available for";
- if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, 0, "HP SDC NMI",
- (void *) hp_sdc.base_io)) goto err2;
+ if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED,
+ "HP SDC NMI", &hp_sdc))
+ goto err2;
- printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
+ printk(KERN_INFO PREFIX "HP SDC at 0x%p, IRQ %d (NMI IRQ %d)\n",
(void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
hp_sdc_status_in8();
@@ -854,13 +912,14 @@ static int __init hp_sdc_init(void)
hp_sdc.dev_err = 0;
return 0;
err2:
- free_irq(hp_sdc.irq, NULL);
+ free_irq(hp_sdc.irq, &hp_sdc);
err1:
release_region(hp_sdc.data_io, 2);
err0:
- printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
+ printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
hp_sdc.dev = NULL;
+
return hp_sdc.dev_err;
}
@@ -868,8 +927,10 @@ static int __init hp_sdc_init(void)
static int __init hp_sdc_init_hppa(struct parisc_device *d)
{
- if (!d) return 1;
- if (hp_sdc.dev != NULL) return 1; /* We only expect one SDC */
+ if (!d)
+ return 1;
+ if (hp_sdc.dev != NULL)
+ return 1; /* We only expect one SDC */
hp_sdc.dev = d;
hp_sdc.irq = d->irq;
@@ -898,18 +959,16 @@ static void hp_sdc_exit(void)
/* Wait until we know this has been processed by the i8042 */
hp_sdc_spin_ibf();
- free_irq(hp_sdc.nmi, NULL);
- free_irq(hp_sdc.irq, NULL);
+ free_irq(hp_sdc.nmi, &hp_sdc);
+ free_irq(hp_sdc.irq, &hp_sdc);
write_unlock_irq(&hp_sdc.lock);
del_timer(&hp_sdc.kicker);
tasklet_kill(&hp_sdc.task);
-/* release_region(hp_sdc.data_io, 2); */
-
#if defined(__hppa__)
- if (unregister_parisc_driver(&hp_sdc_driver))
+ if (unregister_parisc_driver(&hp_sdc_driver))
printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
#endif
}
@@ -923,7 +982,7 @@ static int __init hp_sdc_register(void)
mm_segment_t fs;
unsigned char i;
#endif
-
+
hp_sdc.dev = NULL;
hp_sdc.dev_err = 0;
#if defined(__hppa__)
@@ -960,8 +1019,8 @@ static int __init hp_sdc_register(void)
tq_init.seq = tq_init_seq;
tq_init.act.semaphore = &tq_init_sem;
- tq_init_seq[0] =
- HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
+ tq_init_seq[0] =
+ HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
tq_init_seq[2] = 1;
tq_init_seq[3] = 0;
@@ -979,13 +1038,13 @@ static int __init hp_sdc_register(void)
}
hp_sdc.r11 = tq_init_seq[4];
if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
- char *str;
+ const char *str;
printk(KERN_INFO PREFIX "New style SDC\n");
tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
tq_init.actidx = 0;
tq_init.idx = 1;
down(&tq_init_sem);
- hp_sdc_enqueue_transaction(&tq_init);
+ hp_sdc_enqueue_transaction(&tq_init);
down(&tq_init_sem);
up(&tq_init_sem);
if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
@@ -995,15 +1054,13 @@ static int __init hp_sdc_register(void)
hp_sdc.r7e = tq_init_seq[4];
HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
printk(KERN_INFO PREFIX "Revision: %s\n", str);
- if (hp_sdc.r7e & HP_SDC_XTD_BEEPER) {
+ if (hp_sdc.r7e & HP_SDC_XTD_BEEPER)
printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
- }
- if (hp_sdc.r7e & HP_SDC_XTD_BBRTC) {
+ if (hp_sdc.r7e & HP_SDC_XTD_BBRTC)
printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
- }
printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
"on next firmware reset.\n");
- tq_init_seq[0] = HP_SDC_ACT_PRECMD |
+ tq_init_seq[0] = HP_SDC_ACT_PRECMD |
HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
tq_init_seq[1] = HP_SDC_CMD_SET_STR;
tq_init_seq[2] = 1;
@@ -1012,14 +1069,12 @@ static int __init hp_sdc_register(void)
tq_init.idx = 1;
tq_init.endidx = 4;
down(&tq_init_sem);
- hp_sdc_enqueue_transaction(&tq_init);
+ hp_sdc_enqueue_transaction(&tq_init);
down(&tq_init_sem);
up(&tq_init_sem);
- }
- else {
- printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
+ } else
+ printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
(hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
- }
return 0;
}
@@ -1027,13 +1082,13 @@ static int __init hp_sdc_register(void)
module_init(hp_sdc_register);
module_exit(hp_sdc_exit);
-/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64)
+/* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64)
* cycles cycles-adj time
* between two consecutive mfctl(16)'s: 4 n/a 63ns
* hp_sdc_spin_ibf when idle: 119 115 1.7us
* gsc_writeb status register: 83 79 1.2us
* IBF to clear after sending SET_IM: 6204 6006 93us
- * IBF to clear after sending LOAD_RT: 4467 4352 68us
+ * IBF to clear after sending LOAD_RT: 4467 4352 68us
* IBF to clear after sending two LOAD_RTs: 18974 18859 295us
* READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us
* cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms
diff --git a/drivers/input/serio/hp_sdc_mlc.c b/drivers/input/serio/hp_sdc_mlc.c
index aa4a8a4ccfd..c45ea74d53e 100644
--- a/drivers/input/serio/hp_sdc_mlc.c
+++ b/drivers/input/serio/hp_sdc_mlc.c
@@ -58,12 +58,13 @@ struct hp_sdc_mlc_priv_s {
} hp_sdc_mlc_priv;
/************************* Interrupt context ******************************/
-static void hp_sdc_mlc_isr (int irq, void *dev_id,
- uint8_t status, uint8_t data) {
- int idx;
+static void hp_sdc_mlc_isr (int irq, void *dev_id,
+ uint8_t status, uint8_t data)
+{
+ int idx;
hil_mlc *mlc = &hp_sdc_mlc;
- write_lock(&(mlc->lock));
+ write_lock(&mlc->lock);
if (mlc->icount < 0) {
printk(KERN_WARNING PREFIX "HIL Overflow!\n");
up(&mlc->isem);
@@ -73,239 +74,232 @@ static void hp_sdc_mlc_isr (int irq, void *dev_id,
if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
mlc->ipacket[idx] |= data | HIL_ERR_INT;
mlc->icount--;
- if (hp_sdc_mlc_priv.got5x) goto check;
- if (!idx) goto check;
- if ((mlc->ipacket[idx-1] & HIL_PKT_ADDR_MASK) !=
+ if (hp_sdc_mlc_priv.got5x || !idx)
+ goto check;
+ if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) !=
(mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
- mlc->ipacket[idx] |= (mlc->ipacket[idx-1]
- & HIL_PKT_ADDR_MASK);
+ mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
+ & HIL_PKT_ADDR_MASK);
}
goto check;
}
/* We know status is 5X */
- if (data & HP_SDC_HIL_ISERR) goto err;
- mlc->ipacket[idx] =
+ if (data & HP_SDC_HIL_ISERR)
+ goto err;
+ mlc->ipacket[idx] =
(data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
hp_sdc_mlc_priv.got5x = 1;
goto out;
check:
hp_sdc_mlc_priv.got5x = 0;
- if (mlc->imatch == 0) goto done;
- if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
- && (mlc->ipacket[idx] == (mlc->imatch | idx))) goto done;
- if (mlc->ipacket[idx] == mlc->imatch) goto done;
+ if (mlc->imatch == 0)
+ goto done;
+ if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
+ && (mlc->ipacket[idx] == (mlc->imatch | idx)))
+ goto done;
+ if (mlc->ipacket[idx] == mlc->imatch)
+ goto done;
goto out;
- err:
+ err:
printk(KERN_DEBUG PREFIX "err code %x\n", data);
+
switch (data) {
case HP_SDC_HIL_RC_DONE:
printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
break;
+
case HP_SDC_HIL_ERR:
- mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
- HIL_ERR_FERR | HIL_ERR_FOF;
+ mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
+ HIL_ERR_FERR | HIL_ERR_FOF;
break;
+
case HP_SDC_HIL_TO:
mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
break;
+
case HP_SDC_HIL_RC:
printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
break;
+
default:
printk(KERN_WARNING PREFIX "Unkown HIL Error status (%x)!\n", data);
break;
}
+
/* No more data will be coming due to an error. */
done:
tasklet_schedule(mlc->tasklet);
- up(&(mlc->isem));
+ up(&mlc->isem);
out:
- write_unlock(&(mlc->lock));
+ write_unlock(&mlc->lock);
}
/******************** Tasklet or userspace context functions ****************/
-static int hp_sdc_mlc_in (hil_mlc *mlc, suseconds_t timeout) {
- unsigned long flags;
+static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
+{
struct hp_sdc_mlc_priv_s *priv;
int rc = 2;
priv = mlc->priv;
- write_lock_irqsave(&(mlc->lock), flags);
-
/* Try to down the semaphore */
- if (down_trylock(&(mlc->isem))) {
+ if (down_trylock(&mlc->isem)) {
struct timeval tv;
if (priv->emtestmode) {
- mlc->ipacket[0] =
- HIL_ERR_INT | (mlc->opacket &
- (HIL_PKT_CMD |
- HIL_PKT_ADDR_MASK |
+ mlc->ipacket[0] =
+ HIL_ERR_INT | (mlc->opacket &
+ (HIL_PKT_CMD |
+ HIL_PKT_ADDR_MASK |
HIL_PKT_DATA_MASK));
mlc->icount = 14;
/* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
goto wasup;
}
do_gettimeofday(&tv);
- tv.tv_usec += 1000000 * (tv.tv_sec - mlc->instart.tv_sec);
+ tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
if (tv.tv_usec - mlc->instart.tv_usec > mlc->intimeout) {
- /* printk("!%i %i",
- tv.tv_usec - mlc->instart.tv_usec,
- mlc->intimeout);
- */
+ /* printk("!%i %i",
+ tv.tv_usec - mlc->instart.tv_usec,
+ mlc->intimeout);
+ */
rc = 1;
- up(&(mlc->isem));
+ up(&mlc->isem);
}
goto done;
}
wasup:
- up(&(mlc->isem));
+ up(&mlc->isem);
rc = 0;
- goto done;
done:
- write_unlock_irqrestore(&(mlc->lock), flags);
return rc;
}
-static int hp_sdc_mlc_cts (hil_mlc *mlc) {
+static int hp_sdc_mlc_cts(hil_mlc *mlc)
+{
struct hp_sdc_mlc_priv_s *priv;
- unsigned long flags;
- priv = mlc->priv;
-
- write_lock_irqsave(&(mlc->lock), flags);
+ priv = mlc->priv;
/* Try to down the semaphores -- they should be up. */
- if (down_trylock(&(mlc->isem))) {
- BUG();
- goto busy;
- }
- if (down_trylock(&(mlc->osem))) {
- BUG();
- up(&(mlc->isem));
- goto busy;
- }
- up(&(mlc->isem));
- up(&(mlc->osem));
+ BUG_ON(down_trylock(&mlc->isem));
+ BUG_ON(down_trylock(&mlc->osem));
+
+ up(&mlc->isem);
+ up(&mlc->osem);
- if (down_trylock(&(mlc->csem))) {
- if (priv->trans.act.semaphore != &(mlc->csem)) goto poll;
- goto busy;
+ if (down_trylock(&mlc->csem)) {
+ if (priv->trans.act.semaphore != &mlc->csem)
+ goto poll;
+ else
+ goto busy;
}
- if (!(priv->tseq[4] & HP_SDC_USE_LOOP)) goto done;
+
+ if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
+ goto done;
poll:
- priv->trans.act.semaphore = &(mlc->csem);
+ priv->trans.act.semaphore = &mlc->csem;
priv->trans.actidx = 0;
priv->trans.idx = 1;
priv->trans.endidx = 5;
- priv->tseq[0] =
+ priv->tseq[0] =
HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
priv->tseq[1] = HP_SDC_CMD_READ_USE;
priv->tseq[2] = 1;
priv->tseq[3] = 0;
priv->tseq[4] = 0;
- hp_sdc_enqueue_transaction(&(priv->trans));
+ __hp_sdc_enqueue_transaction(&priv->trans);
busy:
- write_unlock_irqrestore(&(mlc->lock), flags);
return 1;
done:
- priv->trans.act.semaphore = &(mlc->osem);
- up(&(mlc->csem));
- write_unlock_irqrestore(&(mlc->lock), flags);
+ priv->trans.act.semaphore = &mlc->osem;
+ up(&mlc->csem);
return 0;
}
-static void hp_sdc_mlc_out (hil_mlc *mlc) {
+static void hp_sdc_mlc_out(hil_mlc *mlc)
+{
struct hp_sdc_mlc_priv_s *priv;
- unsigned long flags;
priv = mlc->priv;
- write_lock_irqsave(&(mlc->lock), flags);
-
/* Try to down the semaphore -- it should be up. */
- if (down_trylock(&(mlc->osem))) {
- BUG();
- goto done;
- }
+ BUG_ON(down_trylock(&mlc->osem));
- if (mlc->opacket & HIL_DO_ALTER_CTRL) goto do_control;
+ if (mlc->opacket & HIL_DO_ALTER_CTRL)
+ goto do_control;
do_data:
if (priv->emtestmode) {
- up(&(mlc->osem));
- goto done;
+ up(&mlc->osem);
+ return;
}
/* Shouldn't be sending commands when loop may be busy */
- if (down_trylock(&(mlc->csem))) {
- BUG();
- goto done;
- }
- up(&(mlc->csem));
+ BUG_ON(down_trylock(&mlc->csem));
+ up(&mlc->csem);
priv->trans.actidx = 0;
priv->trans.idx = 1;
- priv->trans.act.semaphore = &(mlc->osem);
+ priv->trans.act.semaphore = &mlc->osem;
priv->trans.endidx = 6;
- priv->tseq[0] =
+ priv->tseq[0] =
HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
priv->tseq[1] = 0x7;
- priv->tseq[2] =
- (mlc->opacket &
+ priv->tseq[2] =
+ (mlc->opacket &
(HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
>> HIL_PKT_ADDR_SHIFT;
- priv->tseq[3] =
- (mlc->opacket & HIL_PKT_DATA_MASK)
+ priv->tseq[3] =
+ (mlc->opacket & HIL_PKT_DATA_MASK)
>> HIL_PKT_DATA_SHIFT;
priv->tseq[4] = 0; /* No timeout */
- if (priv->tseq[3] == HIL_CMD_DHR) priv->tseq[4] = 1;
+ if (priv->tseq[3] == HIL_CMD_DHR)
+ priv->tseq[4] = 1;
priv->tseq[5] = HP_SDC_CMD_DO_HIL;
goto enqueue;
do_control:
priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
-
+
/* we cannot emulate this, it should not be used. */
BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
-
- if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY) goto control_only;
- if (mlc->opacket & HIL_CTRL_APE) {
- BUG(); /* Should not send command/data after engaging APE */
- goto done;
- }
- /* Disengaging APE this way would not be valid either since
+
+ if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
+ goto control_only;
+
+ /* Should not send command/data after engaging APE */
+ BUG_ON(mlc->opacket & HIL_CTRL_APE);
+
+ /* Disengaging APE this way would not be valid either since
* the loop must be allowed to idle.
*
- * So, it works out that we really never actually send control
- * and data when using SDC, we just send the data.
+ * So, it works out that we really never actually send control
+ * and data when using SDC, we just send the data.
*/
goto do_data;
control_only:
priv->trans.actidx = 0;
priv->trans.idx = 1;
- priv->trans.act.semaphore = &(mlc->osem);
+ priv->trans.act.semaphore = &mlc->osem;
priv->trans.endidx = 4;
- priv->tseq[0] =
+ priv->tseq[0] =
HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
priv->tseq[1] = HP_SDC_CMD_SET_LPC;
priv->tseq[2] = 1;
- // priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC;
+ /* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */
priv->tseq[3] = 0;
if (mlc->opacket & HIL_CTRL_APE) {
priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
- down_trylock(&(mlc->csem));
- }
+ down_trylock(&mlc->csem);
+ }
enqueue:
- hp_sdc_enqueue_transaction(&(priv->trans));
- done:
- write_unlock_irqrestore(&(mlc->lock), flags);
+ hp_sdc_enqueue_transaction(&priv->trans);
}
static int __init hp_sdc_mlc_init(void)
@@ -316,18 +310,18 @@ static int __init hp_sdc_mlc_init(void)
hp_sdc_mlc_priv.emtestmode = 0;
hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
- hp_sdc_mlc_priv.trans.act.semaphore = &(mlc->osem);
+ hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem;
hp_sdc_mlc_priv.got5x = 0;
- mlc->cts = &hp_sdc_mlc_cts;
- mlc->in = &hp_sdc_mlc_in;
- mlc->out = &hp_sdc_mlc_out;
+ mlc->cts = &hp_sdc_mlc_cts;
+ mlc->in = &hp_sdc_mlc_in;
+ mlc->out = &hp_sdc_mlc_out;
+ mlc->priv = &hp_sdc_mlc_priv;
if (hil_mlc_register(mlc)) {
printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
goto err0;
}
- mlc->priv = &hp_sdc_mlc_priv;
if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
@@ -335,10 +329,9 @@ static int __init hp_sdc_mlc_init(void)
}
return 0;
err1:
- if (hil_mlc_unregister(mlc)) {
+ if (hil_mlc_unregister(mlc))
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
"This is bad. Could cause an oops.\n");
- }
err0:
return -EBUSY;
}
@@ -346,14 +339,14 @@ static int __init hp_sdc_mlc_init(void)
static void __exit hp_sdc_mlc_exit(void)
{
hil_mlc *mlc = &hp_sdc_mlc;
- if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr)) {
+
+ if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr))
printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
"This is bad. Could cause an oops.\n");
- }
- if (hil_mlc_unregister(mlc)) {
+
+ if (hil_mlc_unregister(mlc))
printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
"This is bad. Could cause an oops.\n");
- }
}
module_init(hp_sdc_mlc_init);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index d36bd5475b6..6858bc58f0f 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -160,6 +160,28 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ /*
+ * No data is coming from the touchscreen unless KBC
+ * is in legacy mode.
+ */
+ .ident = "Panasonic CF-29",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Matsushita"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CF-29"),
+ },
+ },
+ {
+ /*
+ * Errors on MUX ports are reported without raising AUXDATA
+ * causing "spurious NAK" messages.
+ */
+ .ident = "HP Pavilion DV4017EA",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EA032EA#ABF)"),
+ },
+ },
+ {
.ident = "Toshiba P10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
@@ -280,6 +302,8 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
};
static struct pnp_device_id pnp_aux_devids[] = {
+ { .id = "FJC6000", .driver_data = 0 },
+ { .id = "FJC6001", .driver_data = 0 },
{ .id = "PNP0f03", .driver_data = 0 },
{ .id = "PNP0f0b", .driver_data = 0 },
{ .id = "PNP0f0e", .driver_data = 0 },
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index db9cca3b65e..3888dc307e0 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -526,6 +526,33 @@ static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/*
+ * i8042_toggle_aux - enables or disables AUX port on i8042 via command and
+ * verifies success by readinng CTR. Used when testing for presence of AUX
+ * port.
+ */
+static int __devinit i8042_toggle_aux(int on)
+{
+ unsigned char param;
+ int i;
+
+ if (i8042_command(&param,
+ on ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE))
+ return -1;
+
+ /* some chips need some time to set the I8042_CTR_AUXDIS bit */
+ for (i = 0; i < 100; i++) {
+ udelay(50);
+
+ if (i8042_command(&param, I8042_CMD_CTL_RCTR))
+ return -1;
+
+ if (!(param & I8042_CTR_AUXDIS) == on)
+ return 0;
+ }
+
+ return -1;
+}
/*
* i8042_check_aux() applies as much paranoia as it can at detecting
@@ -580,16 +607,12 @@ static int __devinit i8042_check_aux(void)
* Bit assignment test - filters out PS/2 i8042's in AT mode
*/
- if (i8042_command(&param, I8042_CMD_AUX_DISABLE))
- return -1;
- if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (~param & I8042_CTR_AUXDIS)) {
+ if (i8042_toggle_aux(0)) {
printk(KERN_WARNING "Failed to disable AUX port, but continuing anyway... Is this a SiS?\n");
printk(KERN_WARNING "If AUX port is really absent please use the 'i8042.noaux' option.\n");
}
- if (i8042_command(&param, I8042_CMD_AUX_ENABLE))
- return -1;
- if (i8042_command(&param, I8042_CMD_CTL_RCTR) || (param & I8042_CTR_AUXDIS))
+ if (i8042_toggle_aux(1))
return -1;
/*
@@ -768,6 +791,13 @@ static void i8042_controller_reset(void)
i8042_flush();
/*
+ * Disable both KBD and AUX interfaces so they don't get in the way
+ */
+
+ i8042_ctr |= I8042_CTR_KBDDIS | I8042_CTR_AUXDIS;
+ i8042_ctr &= ~(I8042_CTR_KBDINT | I8042_CTR_AUXINT);
+
+/*
* Disable MUX mode if present.
*/
diff --git a/drivers/input/tablet/Kconfig b/drivers/input/tablet/Kconfig
new file mode 100644
index 00000000000..12dfb0eb326
--- /dev/null
+++ b/drivers/input/tablet/Kconfig
@@ -0,0 +1,74 @@
+#
+# Tablet driver configuration
+#
+menuconfig INPUT_TABLET
+ bool "Tablets"
+ help
+ Say Y here, and a list of supported tablets will be displayed.
+ This option doesn't affect the kernel.
+
+ If unsure, say Y.
+
+if INPUT_TABLET
+
+config TABLET_USB_ACECAD
+ tristate "Acecad Flair tablet support (USB)"
+ select USB
+ help
+ Say Y here if you want to use the USB version of the Acecad Flair
+ tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called acecad.
+
+config TABLET_USB_AIPTEK
+ tristate "Aiptek 6000U/8000U tablet support (USB)"
+ select USB
+ help
+ Say Y here if you want to use the USB version of the Aiptek 6000U
+ or Aiptek 8000U tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called aiptek.
+
+config TABLET_USB_GTCO
+ tristate "GTCO CalComp/InterWrite USB Support"
+ depends on USB && INPUT
+ help
+ Say Y here if you want to use the USB version of the GTCO
+ CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gtco.
+
+config TABLET_USB_KBTAB
+ tristate "KB Gear JamStudio tablet support (USB)"
+ select USB
+ help
+ Say Y here if you want to use the USB version of the KB Gear
+ JamStudio tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called kbtab.
+
+config TABLET_USB_WACOM
+ tristate "Wacom Intuos/Graphire tablet support (USB)"
+ select USB
+ help
+ Say Y here if you want to use the USB version of the Wacom Intuos
+ or Graphire tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wacom.
+
+endif
diff --git a/drivers/input/tablet/Makefile b/drivers/input/tablet/Makefile
new file mode 100644
index 00000000000..ce8b9a9cfa4
--- /dev/null
+++ b/drivers/input/tablet/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the tablet drivers
+#
+
+# Multipart objects.
+wacom-objs := wacom_wac.o wacom_sys.o
+
+obj-$(CONFIG_TABLET_USB_ACECAD) += acecad.o
+obj-$(CONFIG_TABLET_USB_AIPTEK) += aiptek.o
+obj-$(CONFIG_TABLET_USB_GTCO) += gtco.o
+obj-$(CONFIG_TABLET_USB_KBTAB) += kbtab.o
+obj-$(CONFIG_TABLET_USB_WACOM) += wacom.o
diff --git a/drivers/usb/input/acecad.c b/drivers/input/tablet/acecad.c
index 909138e5aa0..dd2310458c4 100644
--- a/drivers/usb/input/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -54,7 +54,7 @@ struct usb_acecad {
struct input_dev *input;
struct urb *irq;
- signed char *data;
+ unsigned char *data;
dma_addr_t data_dma;
};
@@ -111,7 +111,7 @@ resubmit:
static int usb_acecad_open(struct input_dev *dev)
{
- struct usb_acecad *acecad = dev->private;
+ struct usb_acecad *acecad = input_get_drvdata(dev);
acecad->irq->dev = acecad->usbdev;
if (usb_submit_urb(acecad->irq, GFP_KERNEL))
@@ -122,7 +122,7 @@ static int usb_acecad_open(struct input_dev *dev)
static void usb_acecad_close(struct input_dev *dev)
{
- struct usb_acecad *acecad = dev->private;
+ struct usb_acecad *acecad = input_get_drvdata(dev);
usb_kill_urb(acecad->irq);
}
@@ -135,6 +135,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
struct usb_acecad *acecad;
struct input_dev *input_dev;
int pipe, maxp;
+ int err = -ENOMEM;
if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
@@ -149,16 +150,22 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
input_dev = input_allocate_device();
- if (!acecad || !input_dev)
+ if (!acecad || !input_dev) {
+ err = -ENOMEM;
goto fail1;
+ }
acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma);
- if (!acecad->data)
+ if (!acecad->data) {
+ err= -ENOMEM;
goto fail1;
+ }
acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!acecad->irq)
+ if (!acecad->irq) {
+ err = -ENOMEM;
goto fail2;
+ }
acecad->usbdev = dev;
acecad->input = input_dev;
@@ -178,8 +185,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
input_dev->name = acecad->name;
input_dev->phys = acecad->phys;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = acecad;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, acecad);
input_dev->open = usb_acecad_open;
input_dev->close = usb_acecad_close;
@@ -221,7 +229,9 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
acecad->irq->transfer_dma = acecad->data_dma;
acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_register_device(acecad->input);
+ err = input_register_device(acecad->input);
+ if (err)
+ goto fail2;
usb_set_intfdata(intf, acecad);
@@ -230,7 +240,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
fail1: input_free_device(input_dev);
kfree(acecad);
- return -ENOMEM;
+ return err;
}
static void usb_acecad_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/input/aiptek.c b/drivers/input/tablet/aiptek.c
index f857935e615..cc0a498763d 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -798,7 +798,7 @@ MODULE_DEVICE_TABLE(usb, aiptek_ids);
*/
static int aiptek_open(struct input_dev *inputdev)
{
- struct aiptek *aiptek = inputdev->private;
+ struct aiptek *aiptek = input_get_drvdata(inputdev);
aiptek->urb->dev = aiptek->usbdev;
if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
@@ -812,7 +812,7 @@ static int aiptek_open(struct input_dev *inputdev)
*/
static void aiptek_close(struct input_dev *inputdev)
{
- struct aiptek *aiptek = inputdev->private;
+ struct aiptek *aiptek = input_get_drvdata(inputdev);
usb_kill_urb(aiptek->urb);
}
@@ -1972,6 +1972,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
AIPTEK_PROGRAMMABLE_DELAY_200,
AIPTEK_PROGRAMMABLE_DELAY_300
};
+ int err = -ENOMEM;
/* programmableDelay is where the command-line specified
* delay is kept. We make it the first element of speeds[],
@@ -2043,8 +2044,10 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
inputdev->name = "Aiptek";
inputdev->phys = aiptek->features.usbPath;
usb_to_input_id(usbdev, &inputdev->id);
- inputdev->cdev.dev = &intf->dev;
- inputdev->private = aiptek;
+ inputdev->dev.parent = &intf->dev;
+
+ input_set_drvdata(inputdev, aiptek);
+
inputdev->open = aiptek_open;
inputdev->close = aiptek_close;
@@ -2133,7 +2136,9 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* Register the tablet as an Input Device
*/
- input_register_device(aiptek->inputdev);
+ err = input_register_device(aiptek->inputdev);
+ if (err)
+ goto fail2;
/* We now will look for the evdev device which is mapped to
* the tablet. The partial name is kept in the link list of
@@ -2165,23 +2170,13 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
return 0;
-fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
+ fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data,
aiptek->data_dma);
-fail1: input_free_device(inputdev);
+ fail1: input_free_device(inputdev);
kfree(aiptek);
- return -ENOMEM;
+ return err;
}
-/* Forward declaration */
-static void aiptek_disconnect(struct usb_interface *intf);
-
-static struct usb_driver aiptek_driver = {
- .name = "aiptek",
- .probe = aiptek_probe,
- .disconnect = aiptek_disconnect,
- .id_table = aiptek_ids,
-};
-
/***********************************************************************
* Deal with tablet disconnecting from the system.
*/
@@ -2206,6 +2201,13 @@ static void aiptek_disconnect(struct usb_interface *intf)
}
}
+static struct usb_driver aiptek_driver = {
+ .name = "aiptek",
+ .probe = aiptek_probe,
+ .disconnect = aiptek_disconnect,
+ .id_table = aiptek_ids,
+};
+
static int __init aiptek_init(void)
{
int result = usb_register(&aiptek_driver);
diff --git a/drivers/usb/input/gtco.c b/drivers/input/tablet/gtco.c
index ae756e0afc9..b2ca10f2fe0 100644
--- a/drivers/usb/input/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -187,7 +187,6 @@ struct hid_descriptor
/*
- *
* This is an abbreviated parser for the HID Report Descriptor. We
* know what devices we are talking to, so this is by no means meant
* to be generic. We can make some safe assumptions:
@@ -204,7 +203,7 @@ struct hid_descriptor
static void parse_hid_report_descriptor(struct gtco *device, char * report,
int length)
{
- int x,i=0;
+ int x, i = 0;
/* Tag primitive vars */
__u8 prefix;
@@ -215,7 +214,6 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
__u16 data16 = 0;
__u32 data32 = 0;
-
/* For parsing logic */
int inputnum = 0;
__u32 usage = 0;
@@ -225,46 +223,46 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
__u32 oldval[TAG_GLOB_MAX];
/* Debug stuff */
- char maintype='x';
+ char maintype = 'x';
char globtype[12];
- int indent=0;
- char indentstr[10]="";
-
+ int indent = 0;
+ char indentstr[10] = "";
dbg("======>>>>>>PARSE<<<<<<======");
/* Walk this report and pull out the info we need */
- while (i<length){
- prefix=report[i];
+ while (i < length) {
+ prefix = report[i];
/* Skip over prefix */
i++;
/* Determine data size and save the data in the proper variable */
size = PREF_SIZE(prefix);
- switch(size){
+ switch (size) {
case 1:
data = report[i];
break;
case 2:
- data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+ data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));
break;
case 3:
size = 4;
- data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+ data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));
+ break;
}
/* Skip size of data */
- i+=size;
+ i += size;
/* What we do depends on the tag type */
tag = PREF_TAG(prefix);
type = PREF_TYPE(prefix);
- switch(type){
+ switch (type) {
case TYPE_MAIN:
- strcpy(globtype,"");
- switch(tag){
+ strcpy(globtype, "");
+ switch (tag) {
case TAG_MAIN_INPUT:
/*
@@ -274,19 +272,17 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
* min/max values
*/
- maintype='I';
- if (data==2){
- strcpy(globtype,"Variable");
- }
- if (data==3){
- strcpy(globtype,"Var|Const");
- }
+ maintype = 'I';
+ if (data == 2)
+ strcpy(globtype, "Variable");
+ else if (data == 3)
+ strcpy(globtype, "Var|Const");
dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
- globalval[TAG_GLOB_REPORT_ID],inputnum,
- globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
- globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
- (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+ globalval[TAG_GLOB_REPORT_ID], inputnum,
+ globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
+ globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
+ globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
/*
@@ -295,43 +291,43 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
that, we look for everything else by
local usage value
*/
- switch (inputnum){
+ switch (inputnum) {
case 0: /* X coord */
- dbg("GER: X Usage: 0x%x",usage);
- if (device->max_X == 0){
+ dbg("GER: X Usage: 0x%x", usage);
+ if (device->max_X == 0) {
device->max_X = globalval[TAG_GLOB_LOG_MAX];
device->min_X = globalval[TAG_GLOB_LOG_MIN];
}
-
break;
+
case 1: /* Y coord */
- dbg("GER: Y Usage: 0x%x",usage);
- if (device->max_Y == 0){
+ dbg("GER: Y Usage: 0x%x", usage);
+ if (device->max_Y == 0) {
device->max_Y = globalval[TAG_GLOB_LOG_MAX];
device->min_Y = globalval[TAG_GLOB_LOG_MIN];
}
break;
+
default:
/* Tilt X */
- if (usage == DIGITIZER_USAGE_TILT_X){
- if (device->maxtilt_X == 0){
+ if (usage == DIGITIZER_USAGE_TILT_X) {
+ if (device->maxtilt_X == 0) {
device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
}
}
/* Tilt Y */
- if (usage == DIGITIZER_USAGE_TILT_Y){
- if (device->maxtilt_Y == 0){
+ if (usage == DIGITIZER_USAGE_TILT_Y) {
+ if (device->maxtilt_Y == 0) {
device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
}
}
-
/* Pressure */
- if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
- if (device->maxpressure == 0){
+ if (usage == DIGITIZER_USAGE_TIP_PRESSURE) {
+ if (device->maxpressure == 0) {
device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
device->minpressure = globalval[TAG_GLOB_LOG_MIN];
}
@@ -341,214 +337,226 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
}
inputnum++;
-
-
break;
+
case TAG_MAIN_OUTPUT:
- maintype='O';
+ maintype = 'O';
break;
+
case TAG_MAIN_FEATURE:
- maintype='F';
+ maintype = 'F';
break;
+
case TAG_MAIN_COL_START:
- maintype='S';
+ maintype = 'S';
- if (data==0){
+ if (data == 0) {
dbg("======>>>>>> Physical");
- strcpy(globtype,"Physical");
- }else{
+ strcpy(globtype, "Physical");
+ } else
dbg("======>>>>>>");
- }
/* Indent the debug output */
indent++;
- for (x=0;x<indent;x++){
- indentstr[x]='-';
- }
- indentstr[x]=0;
+ for (x = 0; x < indent; x++)
+ indentstr[x] = '-';
+ indentstr[x] = 0;
/* Save global tags */
- for (x=0;x<TAG_GLOB_MAX;x++){
+ for (x = 0; x < TAG_GLOB_MAX; x++)
oldval[x] = globalval[x];
- }
break;
+
case TAG_MAIN_COL_END:
dbg("<<<<<<======");
- maintype='E';
+ maintype = 'E';
indent--;
- for (x=0;x<indent;x++){
- indentstr[x]='-';
- }
- indentstr[x]=0;
+ for (x = 0; x < indent; x++)
+ indentstr[x] = '-';
+ indentstr[x] = 0;
/* Copy global tags back */
- for (x=0;x<TAG_GLOB_MAX;x++){
+ for (x = 0; x < TAG_GLOB_MAX; x++)
globalval[x] = oldval[x];
- }
break;
}
- switch (size){
+ switch (size) {
case 1:
dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr,tag,maintype,size,globtype,data);
+ indentstr, tag, maintype, size, globtype, data);
break;
+
case 2:
dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr,tag,maintype,size,globtype, data16);
+ indentstr, tag, maintype, size, globtype, data16);
break;
+
case 4:
dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr,tag,maintype,size,globtype,data32);
+ indentstr, tag, maintype, size, globtype, data32);
break;
}
break;
+
case TYPE_GLOBAL:
- switch(tag){
+ switch (tag) {
case TAG_GLOB_USAGE:
/*
* First time we hit the global usage tag,
* it should tell us the type of device
*/
- if (device->usage == 0){
+ if (device->usage == 0)
device->usage = data;
- }
- strcpy(globtype,"USAGE");
+
+ strcpy(globtype, "USAGE");
break;
- case TAG_GLOB_LOG_MIN :
- strcpy(globtype,"LOG_MIN");
+
+ case TAG_GLOB_LOG_MIN:
+ strcpy(globtype, "LOG_MIN");
break;
- case TAG_GLOB_LOG_MAX :
- strcpy(globtype,"LOG_MAX");
+
+ case TAG_GLOB_LOG_MAX:
+ strcpy(globtype, "LOG_MAX");
break;
- case TAG_GLOB_PHYS_MIN :
- strcpy(globtype,"PHYS_MIN");
+
+ case TAG_GLOB_PHYS_MIN:
+ strcpy(globtype, "PHYS_MIN");
break;
- case TAG_GLOB_PHYS_MAX :
- strcpy(globtype,"PHYS_MAX");
+
+ case TAG_GLOB_PHYS_MAX:
+ strcpy(globtype, "PHYS_MAX");
break;
- case TAG_GLOB_UNIT_EXP :
- strcpy(globtype,"EXP");
+
+ case TAG_GLOB_UNIT_EXP:
+ strcpy(globtype, "EXP");
break;
- case TAG_GLOB_UNIT :
- strcpy(globtype,"UNIT");
+
+ case TAG_GLOB_UNIT:
+ strcpy(globtype, "UNIT");
break;
- case TAG_GLOB_REPORT_SZ :
- strcpy(globtype,"REPORT_SZ");
+
+ case TAG_GLOB_REPORT_SZ:
+ strcpy(globtype, "REPORT_SZ");
break;
- case TAG_GLOB_REPORT_ID :
- strcpy(globtype,"REPORT_ID");
+
+ case TAG_GLOB_REPORT_ID:
+ strcpy(globtype, "REPORT_ID");
/* New report, restart numbering */
- inputnum=0;
+ inputnum = 0;
break;
+
case TAG_GLOB_REPORT_CNT:
- strcpy(globtype,"REPORT_CNT");
+ strcpy(globtype, "REPORT_CNT");
break;
- case TAG_GLOB_PUSH :
- strcpy(globtype,"PUSH");
+
+ case TAG_GLOB_PUSH:
+ strcpy(globtype, "PUSH");
break;
+
case TAG_GLOB_POP:
- strcpy(globtype,"POP");
+ strcpy(globtype, "POP");
break;
}
-
/* Check to make sure we have a good tag number
so we don't overflow array */
- if (tag < TAG_GLOB_MAX){
- switch (size){
+ if (tag < TAG_GLOB_MAX) {
+ switch (size) {
case 1:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
- globalval[tag]=data;
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+ indentstr, globtype, tag, size, data);
+ globalval[tag] = data;
break;
+
case 2:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
- globalval[tag]=data16;
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+ indentstr, globtype, tag, size, data16);
+ globalval[tag] = data16;
break;
+
case 4:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
- globalval[tag]=data32;
+ dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
+ indentstr, globtype, tag, size, data32);
+ globalval[tag] = data32;
break;
}
- }else{
+ } else {
dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
- indentstr,tag,size);
+ indentstr, tag, size);
}
-
-
break;
case TYPE_LOCAL:
- switch(tag){
+ switch (tag) {
case TAG_GLOB_USAGE:
- strcpy(globtype,"USAGE");
+ strcpy(globtype, "USAGE");
/* Always 1 byte */
usage = data;
break;
- case TAG_GLOB_LOG_MIN :
- strcpy(globtype,"MIN");
+
+ case TAG_GLOB_LOG_MIN:
+ strcpy(globtype, "MIN");
break;
- case TAG_GLOB_LOG_MAX :
- strcpy(globtype,"MAX");
+
+ case TAG_GLOB_LOG_MAX:
+ strcpy(globtype, "MAX");
break;
+
default:
- strcpy(globtype,"UNKNOWN");
+ strcpy(globtype, "UNKNOWN");
+ break;
}
- switch (size){
+ switch (size) {
case 1:
dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr,tag,globtype,size,data);
+ indentstr, tag, globtype, size, data);
break;
+
case 2:
dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr,tag,globtype,size,data16);
+ indentstr, tag, globtype, size, data16);
break;
+
case 4:
dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr,tag,globtype,size,data32);
+ indentstr, tag, globtype, size, data32);
break;
}
break;
}
-
}
-
}
-
-
/* INPUT DRIVER Routines */
-
/*
- * Called when opening the input device. This will submit the URB to
- * the usb system so we start getting reports
+ * Called when opening the input device. This will submit the URB to
+ * the usb system so we start getting reports
*/
static int gtco_input_open(struct input_dev *inputdev)
{
- struct gtco *device;
- device = inputdev->private;
+ struct gtco *device = input_get_drvdata(inputdev);
device->urbinfo->dev = device->usbdev;
- if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+ if (usb_submit_urb(device->urbinfo, GFP_KERNEL))
return -EIO;
- }
+
return 0;
}
-/**
- Called when closing the input device. This will unlink the URB
-*/
+/*
+ * Called when closing the input device. This will unlink the URB
+ */
static void gtco_input_close(struct input_dev *inputdev)
{
- struct gtco *device = inputdev->private;
+ struct gtco *device = input_get_drvdata(inputdev);
usb_kill_urb(device->urbinfo);
-
}
@@ -560,19 +568,16 @@ static void gtco_input_close(struct input_dev *inputdev)
* placed in the struct gtco structure
*
*/
-static void gtco_setup_caps(struct input_dev *inputdev)
+static void gtco_setup_caps(struct input_dev *inputdev)
{
- struct gtco *device = inputdev->private;
-
+ struct gtco *device = input_get_drvdata(inputdev);
/* Which events */
inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
-
/* Misc event menu block */
inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
-
/* Absolute values based on HID report info */
input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
0, 0);
@@ -590,17 +595,12 @@ static void gtco_setup_caps(struct input_dev *inputdev)
input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
device->maxpressure, 0, 0);
-
/* Transducer */
- input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
-
+ input_set_abs_params(inputdev, ABS_MISC, 0, 0xFF, 0, 0);
}
-
-
/* USB Routines */
-
/*
* URB callback routine. Called when we get IRQ reports from the
* digitizer.
@@ -610,9 +610,7 @@ static void gtco_setup_caps(struct input_dev *inputdev)
*/
static void gtco_urb_callback(struct urb *urbinfo)
{
-
-
- struct gtco *device = urbinfo->context;
+ struct gtco *device = urbinfo->context;
struct input_dev *inputdev;
int rc;
u32 val = 0;
@@ -621,19 +619,20 @@ static void gtco_urb_callback(struct urb *urbinfo)
inputdev = device->inputdevice;
-
/* Was callback OK? */
- if ((urbinfo->status == -ECONNRESET ) ||
- (urbinfo->status == -ENOENT ) ||
- (urbinfo->status == -ESHUTDOWN )){
+ if (urbinfo->status == -ECONNRESET ||
+ urbinfo->status == -ENOENT ||
+ urbinfo->status == -ESHUTDOWN) {
/* Shutdown is occurring. Return and don't queue up any more */
return;
}
- if (urbinfo->status != 0 ) {
- /* Some unknown error. Hopefully temporary. Just go and */
- /* requeue an URB */
+ if (urbinfo->status != 0) {
+ /*
+ * Some unknown error. Hopefully temporary. Just go and
+ * requeue an URB
+ */
goto resubmit;
}
@@ -642,10 +641,9 @@ static void gtco_urb_callback(struct urb *urbinfo)
*/
/* PID dependent when we interpret the report */
- if ((inputdev->id.product == PID_1000 )||
- (inputdev->id.product == PID_1001 )||
- (inputdev->id.product == PID_1002 ))
- {
+ if (inputdev->id.product == PID_1000 ||
+ inputdev->id.product == PID_1001 ||
+ inputdev->id.product == PID_1002) {
/*
* Switch on the report ID
@@ -653,10 +651,10 @@ static void gtco_urb_callback(struct urb *urbinfo)
* the report number. We can just fall through the case
* statements if we start with the highest number report
*/
- switch(device->buffer[0]){
+ switch (device->buffer[0]) {
case 5:
/* Pressure is 9 bits */
- val = ((u16)(device->buffer[8]) << 1);
+ val = ((u16)(device->buffer[8]) << 1);
val |= (u16)(device->buffer[7] >> 7);
input_report_abs(inputdev, ABS_PRESSURE,
device->buffer[8]);
@@ -664,7 +662,6 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* Mask out the Y tilt value used for pressure */
device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
-
/* Fall thru */
case 4:
/* Tilt */
@@ -684,11 +681,10 @@ static void gtco_urb_callback(struct urb *urbinfo)
input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
/* Fall thru */
-
case 2:
case 3:
/* Convert buttons, only 5 bits possible */
- val = (device->buffer[5])&MASK_BUTTON;
+ val = (device->buffer[5]) & MASK_BUTTON;
/* We don't apply any meaning to the bitmask,
just report */
@@ -696,132 +692,109 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* Fall thru */
case 1:
-
/* All reports have X and Y coords in the same place */
- val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+ val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
input_report_abs(inputdev, ABS_X, val);
- val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+ val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
input_report_abs(inputdev, ABS_Y, val);
-
/* Ditto for proximity bit */
- if (device->buffer[5]& MASK_INRANGE){
- val = 1;
- }else{
- val=0;
- }
+ val = device->buffer[5] & MASK_INRANGE ? 1 : 0;
input_report_abs(inputdev, ABS_DISTANCE, val);
-
/* Report 1 is an exception to how we handle buttons */
/* Buttons are an index, not a bitmask */
- if (device->buffer[0] == 1){
+ if (device->buffer[0] == 1) {
- /* Convert buttons, 5 bit index */
- /* Report value of index set as one,
- the rest as 0 */
- val = device->buffer[5]& MASK_BUTTON;
+ /*
+ * Convert buttons, 5 bit index
+ * Report value of index set as one,
+ * the rest as 0
+ */
+ val = device->buffer[5] & MASK_BUTTON;
dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
- val,val);
+ val, val);
/*
* We don't apply any meaning to the button
* index, just report it
*/
input_event(inputdev, EV_MSC, MSC_SERIAL, val);
-
-
}
-
break;
+
case 7:
/* Menu blocks */
input_event(inputdev, EV_MSC, MSC_SCAN,
device->buffer[1]);
-
-
break;
-
}
-
-
}
+
/* Other pid class */
- if ((inputdev->id.product == PID_400 )||
- (inputdev->id.product == PID_401 ))
- {
+ if (inputdev->id.product == PID_400 ||
+ inputdev->id.product == PID_401) {
/* Report 2 */
- if (device->buffer[0] == 2){
+ if (device->buffer[0] == 2) {
/* Menu blocks */
- input_event(inputdev, EV_MSC, MSC_SCAN,
- device->buffer[1]);
+ input_event(inputdev, EV_MSC, MSC_SCAN, device->buffer[1]);
}
/* Report 1 */
- if (device->buffer[0] == 1){
+ if (device->buffer[0] == 1) {
char buttonbyte;
-
/* IF X max > 64K, we still a bit from the y report */
- if (device->max_X > 0x10000){
+ if (device->max_X > 0x10000) {
- val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
- val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+ val = (u16)(((u16)(device->buffer[2] << 8)) | (u8)device->buffer[1]);
+ val |= (u32)(((u8)device->buffer[3] & 0x1) << 16);
input_report_abs(inputdev, ABS_X, val);
- le_buffer[0] = (u8)((u8)(device->buffer[3])>>1);
- le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
-
- le_buffer[1] = (u8)(device->buffer[4]>>1);
- le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+ le_buffer[0] = (u8)((u8)(device->buffer[3]) >> 1);
+ le_buffer[0] |= (u8)((device->buffer[3] & 0x1) << 7);
- val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+ le_buffer[1] = (u8)(device->buffer[4] >> 1);
+ le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7);
+ val = le16_to_cpu(get_unaligned((__le16 *)le_buffer));
input_report_abs(inputdev, ABS_Y, val);
-
/*
* Shift the button byte right by one to
* make it look like the standard report
*/
- buttonbyte = (device->buffer[5])>>1;
- }else{
+ buttonbyte = device->buffer[5] >> 1;
+ } else {
- val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+ val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
input_report_abs(inputdev, ABS_X, val);
- val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+ val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
input_report_abs(inputdev, ABS_Y, val);
buttonbyte = device->buffer[5];
-
}
-
/* BUTTONS and PROXIMITY */
- if (buttonbyte& MASK_INRANGE){
- val = 1;
- }else{
- val=0;
- }
+ val = buttonbyte & MASK_INRANGE ? 1 : 0;
input_report_abs(inputdev, ABS_DISTANCE, val);
/* Convert buttons, only 4 bits possible */
- val = buttonbyte&0x0F;
+ val = buttonbyte & 0x0F;
#ifdef USE_BUTTONS
- for ( i=0;i<5;i++){
- input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
- }
+ for (i = 0; i < 5; i++)
+ input_report_key(inputdev, BTN_DIGI + i, val & (1 << i));
#else
/* We don't apply any meaning to the bitmask, just report */
input_event(inputdev, EV_MSC, MSC_SERIAL, val);
#endif
+
/* TRANSDUCER */
input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
-
}
}
@@ -833,10 +806,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
resubmit:
rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
- if (rc != 0) {
- err("usb_submit_urb failed rc=0x%x",rc);
- }
-
+ if (rc != 0)
+ err("usb_submit_urb failed rc=0x%x", rc);
}
/*
@@ -854,58 +825,46 @@ static int gtco_probe(struct usb_interface *usbinterface,
const struct usb_device_id *id)
{
- struct gtco *device = NULL;
- char path[PATHLENGTH];
- struct input_dev *inputdev;
+ struct gtco *gtco;
+ struct input_dev *input_dev;
struct hid_descriptor *hid_desc;
- char *report;
- int result=0, retry;
+ char *report = NULL;
+ int result = 0, retry;
+ int error;
struct usb_endpoint_descriptor *endpoint;
/* Allocate memory for device structure */
- device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
- if (device == NULL) {
+ gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!gtco || !input_dev) {
err("No more memory");
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_free_devs;
}
-
- device->inputdevice = input_allocate_device();
- if (!device->inputdevice){
- kfree(device);
- err("No more memory");
- return -ENOMEM;
- }
-
- /* Get pointer to the input device */
- inputdev = device->inputdevice;
+ /* Set pointer to the input device */
+ gtco->inputdevice = input_dev;
/* Save interface information */
- device->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
-
+ gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
/* Allocate some data for incoming reports */
- device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
- GFP_KERNEL, &(device->buf_dma));
- if (!device->buffer){
- input_free_device(device->inputdevice);
- kfree(device);
- err("No more memory");
- return -ENOMEM;
+ gtco->buffer = usb_buffer_alloc(gtco->usbdev, REPORT_MAX_SIZE,
+ GFP_KERNEL, &gtco->buf_dma);
+ if (!gtco->buffer) {
+ err("No more memory for us buffers");
+ error = -ENOMEM;
+ goto err_free_devs;
}
/* Allocate URB for reports */
- device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
- if (!device->urbinfo) {
- usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
- device->buffer, device->buf_dma);
- input_free_device(device->inputdevice);
- kfree(device);
- err("No more memory");
+ gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+ if (!gtco->urbinfo) {
+ err("Failed to allocate URB");
return -ENOMEM;
+ goto err_free_buf;
}
-
/*
* The endpoint is always altsetting 0, we know this since we know
* this device only has one interrupt endpoint
@@ -913,51 +872,43 @@ static int gtco_probe(struct usb_interface *usbinterface,
endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
/* Some debug */
- dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
- dbg("num endpoints: %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
- dbg("interface class: %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
- dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+ dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
+ dbg("num endpoints: %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
+ dbg("interface class: %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
+ dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
dbg("endpoint: we have interrupt endpoint\n");
- dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
-
-
+ dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
/*
* Find the HID descriptor so we can find out the size of the
* HID report descriptor
*/
if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
- HID_DEVICE_TYPE,&hid_desc) != 0){
+ HID_DEVICE_TYPE, &hid_desc) != 0){
err("Can't retrieve exta USB descriptor to get hid report descriptor length");
- usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
- device->buffer, device->buf_dma);
- input_free_device(device->inputdevice);
- kfree(device);
- return -EIO;
+ error = -EIO;
+ goto err_free_urb;
}
dbg("Extra descriptor success: type:%d len:%d",
hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
- if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
- usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
- device->buffer, device->buf_dma);
-
- input_free_device(device->inputdevice);
- kfree(device);
- err("No more memory");
- return -ENOMEM;
+ report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL);
+ if (!report) {
+ err("No more memory for report");
+ error = -ENOMEM;
+ goto err_free_urb;
}
/* Couple of tries to get reply */
- for (retry=0;retry<3;retry++) {
- result = usb_control_msg(device->usbdev,
- usb_rcvctrlpipe(device->usbdev, 0),
+ for (retry = 0; retry < 3; retry++) {
+ result = usb_control_msg(gtco->usbdev,
+ usb_rcvctrlpipe(gtco->usbdev, 0),
USB_REQ_GET_DESCRIPTOR,
USB_RECIP_INTERFACE | USB_DIR_IN,
- (REPORT_DEVICE_TYPE << 8),
+ REPORT_DEVICE_TYPE << 8,
0, /* interface */
report,
hid_desc->wDescriptorLength,
@@ -969,72 +920,76 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* If we didn't get the report, fail */
dbg("usb_control_msg result: :%d", result);
- if (result != hid_desc->wDescriptorLength){
- kfree(report);
- usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
- device->buffer, device->buf_dma);
- input_free_device(device->inputdevice);
- kfree(device);
+ if (result != hid_desc->wDescriptorLength) {
err("Failed to get HID Report Descriptor of size: %d",
hid_desc->wDescriptorLength);
- return -EIO;
+ error = -EIO;
+ goto err_free_urb;
}
-
/* Now we parse the report */
- parse_hid_report_descriptor(device,report,result);
+ parse_hid_report_descriptor(gtco, report, result);
/* Now we delete it */
kfree(report);
/* Create a device file node */
- usb_make_path(device->usbdev, path, PATHLENGTH);
- sprintf(device->usbpath, "%s/input0", path);
-
+ usb_make_path(gtco->usbdev, gtco->usbpath, sizeof(gtco->usbpath));
+ strlcat(gtco->usbpath, "/input0", sizeof(gtco->usbpath));
/* Set Input device functions */
- inputdev->open = gtco_input_open;
- inputdev->close = gtco_input_close;
+ input_dev->open = gtco_input_open;
+ input_dev->close = gtco_input_close;
/* Set input device information */
- inputdev->name = "GTCO_CalComp";
- inputdev->phys = device->usbpath;
- inputdev->private = device;
+ input_dev->name = "GTCO_CalComp";
+ input_dev->phys = gtco->usbpath;
+ input_set_drvdata(input_dev, gtco);
/* Now set up all the input device capabilities */
- gtco_setup_caps(inputdev);
+ gtco_setup_caps(input_dev);
/* Set input device required ID information */
- usb_to_input_id(device->usbdev, &device->inputdevice->id);
- inputdev->cdev.dev = &usbinterface->dev;
+ usb_to_input_id(gtco->usbdev, &input_dev->id);
+ input_dev->dev.parent = &usbinterface->dev;
/* Setup the URB, it will be posted later on open of input device */
endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
- usb_fill_int_urb(device->urbinfo,
- device->usbdev,
- usb_rcvintpipe(device->usbdev,
+ usb_fill_int_urb(gtco->urbinfo,
+ gtco->usbdev,
+ usb_rcvintpipe(gtco->usbdev,
endpoint->bEndpointAddress),
- device->buffer,
+ gtco->buffer,
REPORT_MAX_SIZE,
gtco_urb_callback,
- device,
+ gtco,
endpoint->bInterval);
- device->urbinfo->transfer_dma = device->buf_dma;
- device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
+ gtco->urbinfo->transfer_dma = gtco->buf_dma;
+ gtco->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- /* Save device pointer in USB interface device */
- usb_set_intfdata(usbinterface, device);
+ /* Save gtco pointer in USB interface gtco */
+ usb_set_intfdata(usbinterface, gtco);
/* All done, now register the input device */
- input_register_device(inputdev);
+ error = input_register_device(input_dev);
+ if (error)
+ goto err_free_urb;
- info( "gtco driver created usb: %s\n", path);
return 0;
+ err_free_urb:
+ usb_free_urb(gtco->urbinfo);
+ err_free_buf:
+ usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
+ gtco->buffer, gtco->buf_dma);
+ err_free_devs:
+ kfree(report);
+ input_free_device(input_dev);
+ kfree(gtco);
+ return error;
}
/*
@@ -1044,47 +999,46 @@ static int gtco_probe(struct usb_interface *usbinterface,
*/
static void gtco_disconnect(struct usb_interface *interface)
{
-
/* Grab private device ptr */
- struct gtco *device = usb_get_intfdata (interface);
+ struct gtco *gtco = usb_get_intfdata(interface);
/* Now reverse all the registration stuff */
- if (device) {
- input_unregister_device(device->inputdevice);
- usb_kill_urb(device->urbinfo);
- usb_free_urb(device->urbinfo);
- usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
- device->buffer, device->buf_dma);
- kfree(device);
+ if (gtco) {
+ input_unregister_device(gtco->inputdevice);
+ usb_kill_urb(gtco->urbinfo);
+ usb_free_urb(gtco->urbinfo);
+ usb_buffer_free(gtco->usbdev, REPORT_MAX_SIZE,
+ gtco->buffer, gtco->buf_dma);
+ kfree(gtco);
}
info("gtco driver disconnected");
}
-
/* STANDARD MODULE LOAD ROUTINES */
static struct usb_driver gtco_driverinfo_table = {
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
- .owner = THIS_MODULE,
-#endif
- .name = "gtco",
- .id_table = gtco_usbid_table,
- .probe = gtco_probe,
- .disconnect = gtco_disconnect,
+ .name = "gtco",
+ .id_table = gtco_usbid_table,
+ .probe = gtco_probe,
+ .disconnect = gtco_disconnect,
};
+
/*
* Register this module with the USB subsystem
*/
static int __init gtco_init(void)
{
- int rc;
- rc = usb_register(&gtco_driverinfo_table);
- if (rc) {
- err("usb_register() failed rc=0x%x", rc);
+ int error;
+
+ error = usb_register(&gtco_driverinfo_table);
+ if (error) {
+ err("usb_register() failed rc=0x%x", error);
+ return error;
}
- printk("GTCO usb driver version: %s",GTCO_VERSION);
- return rc;
+
+ printk("GTCO usb driver version: %s", GTCO_VERSION);
+ return 0;
}
/*
@@ -1095,7 +1049,7 @@ static void __exit gtco_exit(void)
usb_deregister(&gtco_driverinfo_table);
}
-module_init (gtco_init);
-module_exit (gtco_exit);
+module_init(gtco_init);
+module_exit(gtco_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/kbtab.c b/drivers/input/tablet/kbtab.c
index fedbcb127c2..91e6d00d4a4 100644
--- a/drivers/usb/input/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -29,7 +29,7 @@ module_param(kb_pressure_click, int, 0);
MODULE_PARM_DESC(kb_pressure_click, "pressure threshold for clicks");
struct kbtab {
- signed char *data;
+ unsigned char *data;
dma_addr_t data_dma;
struct input_dev *dev;
struct usb_device *usbdev;
@@ -100,7 +100,7 @@ MODULE_DEVICE_TABLE(usb, kbtab_ids);
static int kbtab_open(struct input_dev *dev)
{
- struct kbtab *kbtab = dev->private;
+ struct kbtab *kbtab = input_get_drvdata(dev);
kbtab->irq->dev = kbtab->usbdev;
if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
@@ -111,7 +111,7 @@ static int kbtab_open(struct input_dev *dev)
static void kbtab_close(struct input_dev *dev)
{
- struct kbtab *kbtab = dev->private;
+ struct kbtab *kbtab = input_get_drvdata(dev);
usb_kill_urb(kbtab->irq);
}
@@ -122,6 +122,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
struct usb_endpoint_descriptor *endpoint;
struct kbtab *kbtab;
struct input_dev *input_dev;
+ int error = -ENOMEM;
kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
input_dev = input_allocate_device();
@@ -145,8 +146,9 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
input_dev->name = "KB Gear Tablet";
input_dev->phys = kbtab->phys;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = kbtab;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, kbtab);
input_dev->open = kbtab_open;
input_dev->close = kbtab_close;
@@ -168,15 +170,19 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
kbtab->irq->transfer_dma = kbtab->data_dma;
kbtab->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_register_device(kbtab->dev);
+ error = input_register_device(kbtab->dev);
+ if (error)
+ goto fail3;
usb_set_intfdata(intf, kbtab);
+
return 0;
-fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
-fail1: input_free_device(input_dev);
+ fail3: usb_free_urb(kbtab->irq);
+ fail2: usb_buffer_free(dev, 10, kbtab->data, kbtab->data_dma);
+ fail1: input_free_device(input_dev);
kfree(kbtab);
- return -ENOMEM;
+ return error;
}
static void kbtab_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/input/wacom.h b/drivers/input/tablet/wacom.h
index d85abfc5ab5..ef01a807ec0 100644
--- a/drivers/usb/input/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -1,5 +1,5 @@
/*
- * drivers/usb/input/wacom.h
+ * drivers/input/tablet/wacom.h
*
* USB Wacom Graphire and Wacom Intuos tablet support
*
diff --git a/drivers/usb/input/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 12b42746ded..83bddef6606 100644
--- a/drivers/usb/input/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -1,5 +1,5 @@
/*
- * drivers/usb/input/wacom_sys.c
+ * drivers/input/tablet/wacom_sys.c
*
* USB Wacom Graphire and Wacom Intuos tablet support - system specific code
*/
@@ -122,7 +122,7 @@ void wacom_input_sync(void *wcombo)
static int wacom_open(struct input_dev *dev)
{
- struct wacom *wacom = dev->private;
+ struct wacom *wacom = input_get_drvdata(dev);
wacom->irq->dev = wacom->usbdev;
if (usb_submit_urb(wacom->irq, GFP_KERNEL))
@@ -133,7 +133,7 @@ static int wacom_open(struct input_dev *dev)
static void wacom_close(struct input_dev *dev)
{
- struct wacom *wacom = dev->private;
+ struct wacom *wacom = input_get_drvdata(dev);
usb_kill_urb(wacom->irq);
}
@@ -201,6 +201,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
struct wacom *wacom;
struct wacom_wac *wacom_wac;
struct input_dev *input_dev;
+ int error = -ENOMEM;
char rep_data[2], limit = 0;
wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
@@ -229,8 +230,10 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->wacom_wac = wacom_wac;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = wacom;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, wacom);
+
input_dev->open = wacom_open;
input_dev->close = wacom_close;
@@ -252,7 +255,9 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->irq->transfer_dma = wacom->data_dma;
wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_register_device(wacom->dev);
+ error = input_register_device(wacom->dev);
+ if (error)
+ goto fail3;
/* Ask the tablet to report tablet data. Repeat until it succeeds */
do {
@@ -265,11 +270,12 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
usb_set_intfdata(intf, wacom);
return 0;
-fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
-fail1: input_free_device(input_dev);
+ fail3: usb_free_urb(wacom->irq);
+ fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
+ fail1: input_free_device(input_dev);
kfree(wacom);
kfree(wacom_wac);
- return -ENOMEM;
+ return error;
}
static void wacom_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 4f3e9bc7177..7661f03a2db 100644
--- a/drivers/usb/input/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1,5 +1,5 @@
/*
- * drivers/usb/input/wacom_wac.c
+ * drivers/input/tablet/wacom_wac.c
*
* USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
*
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index a2302228724..a5e12e8756d 100644
--- a/drivers/usb/input/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -1,5 +1,5 @@
/*
- * drivers/usb/input/wacom_wac.h
+ * drivers/input/tablet/wacom_wac.h
*
* 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
@@ -39,7 +39,7 @@ struct wacom_features {
};
struct wacom_wac {
- signed char *data;
+ unsigned char *data;
int tool[2];
int id[2];
__u32 serial[2];
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 971618059a6..5e640aeb03c 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1,5 +1,5 @@
#
-# Mouse driver configuration
+# Touchscreen driver configuration
#
menuconfig INPUT_TOUCHSCREEN
bool "Touchscreens"
@@ -44,9 +44,9 @@ config TOUCHSCREEN_BITSY
config TOUCHSCREEN_CORGI
tristate "SharpSL (Corgi and Spitz series) touchscreen driver"
depends on PXA_SHARPSL
- default y
+ default y
help
- Say Y here to enable the driver for the touchscreen on the
+ Say Y here to enable the driver for the touchscreen on the
Sharp SL-C7xx and SL-Cxx00 series of PDAs.
If unsure, say N.
@@ -164,4 +164,58 @@ config TOUCHSCREEN_UCB1400
To compile this driver as a module, choose M here: the
module will be called ucb1400_ts.
+config TOUCHSCREEN_USB_COMPOSITE
+ tristate "USB Touchscreen Driver"
+ select USB
+ help
+ USB Touchscreen driver for:
+ - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
+ - PanJit TouchSet USB
+ - 3M MicroTouch USB (EX II series)
+ - ITM
+ - some other eTurboTouch
+ - Gunze AHL61
+ - DMC TSC-10/25
+
+ Have a look at <http://linux.chapter7.ch/touchkit/> for
+ a usage description and the required user-space stuff.
+
+ To compile this driver as a module, choose M here: the
+ module will be called usbtouchscreen.
+
+config TOUCHSCREEN_USB_EGALAX
+ default y
+ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_PANJIT
+ default y
+ bool "PanJit device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_3M
+ default y
+ bool "3M/Microtouch EX II series device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ITM
+ default y
+ bool "ITM device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_ETURBO
+ default y
+ bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_GUNZE
+ default y
+ bool "Gunze AHL61 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
+config TOUCHSCREEN_USB_DMC_TSC10
+ default y
+ bool "DMC TSC-10/25 device support" if EMBEDDED
+ depends on TOUCHSCREEN_USB_COMPOSITE
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 30e6e2217a1..2f86d6ad06d 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -1,17 +1,18 @@
#
-# Makefile for the mouse drivers.
+# Makefile for the touchscreen drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
-obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
-obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
-obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
-obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
-obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
-obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
-obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
+obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
+obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
+obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
+obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 0a26e066354..693e3b2a65a 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -39,7 +39,8 @@
/*
* This code has been heavily tested on a Nokia 770, and lightly
* tested on other ads7846 devices (OSK/Mistral, Lubbock).
- * Support for ads7843 and ads7845 has only been stubbed in.
+ * Support for ads7843 tested on Atmel at91sam926x-EK.
+ * Support for ads7845 has only been stubbed in.
*
* IRQ handling needs a workaround because of a shortcoming in handling
* edge triggered IRQs on some platforms like the OMAP1/2. These
@@ -246,18 +247,16 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
/* REVISIT: take a few more samples, and compare ... */
- /* maybe off internal vREF */
- if (use_internal) {
- req->ref_off = REF_OFF;
- req->xfer[4].tx_buf = &req->ref_off;
- req->xfer[4].len = 1;
- spi_message_add_tail(&req->xfer[4], &req->msg);
-
- req->xfer[5].rx_buf = &req->scratch;
- req->xfer[5].len = 2;
- CS_CHANGE(req->xfer[5]);
- spi_message_add_tail(&req->xfer[5], &req->msg);
- }
+ /* converter in low power mode & enable PENIRQ */
+ req->ref_off = PWRDOWN;
+ req->xfer[4].tx_buf = &req->ref_off;
+ req->xfer[4].len = 1;
+ spi_message_add_tail(&req->xfer[4], &req->msg);
+
+ req->xfer[5].rx_buf = &req->scratch;
+ req->xfer[5].len = 2;
+ CS_CHANGE(req->xfer[5]);
+ spi_message_add_tail(&req->xfer[5], &req->msg);
ts->irq_disabled = 1;
disable_irq(spi->irq);
@@ -536,6 +535,9 @@ static void ads7846_rx(void *ads)
} else
Rt = 0;
+ if (ts->model == 7843)
+ Rt = ts->pressure_max / 2;
+
/* Sample found inconsistent by debouncing or pressure is beyond
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
@@ -897,7 +899,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
input_dev->name = "ADS784x Touchscreen";
input_dev->phys = ts->phys;
- input_dev->cdev.dev = &spi->dev;
+ input_dev->dev.parent = &spi->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index e2945582828..e6a31d11878 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -300,8 +300,7 @@ static int __init corgits_probe(struct platform_device *pdev)
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0002;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &pdev->dev;
- input_dev->private = corgi_ts;
+ input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 9d61cd133d0..557d781719f 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -312,14 +312,13 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
init_completion(&elo->cmd_done);
snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
- input_dev->private = elo;
input_dev->name = "Elo Serial TouchScreen";
input_dev->phys = elo->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_ELO;
input_dev->id.product = elo->id;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 9157eb148e8..39d602600d7 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -130,13 +130,13 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
gunze->dev = input_dev;
snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
- input_dev->private = gunze;
input_dev->name = "Gunze AHL-51S TouchScreen";
input_dev->phys = gunze->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_GUNZE;
input_dev->id.product = 0x0051;
input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, 24, 1000, 0, 0);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index c4116d4f64e..09ed7803cb8 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -147,7 +147,7 @@ enum flite_pwr {
unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
{
unsigned char brightness = (pwr == FLITE_PWR_OFF) ? 0 : flite_brightness;
- struct h3600_dev *ts = dev->private;
+ struct h3600_dev *ts = input_get_drvdata(dev);
/* Must be in this order */
ts->serio->write(ts->serio, 1);
@@ -260,7 +260,7 @@ static int h3600ts_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
#if 0
- struct h3600_dev *ts = dev->private;
+ struct h3600_dev *ts = input_get_drvdata(dev);
switch (type) {
case EV_LED: {
@@ -367,8 +367,9 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
input_dev->id.vendor = SERIO_H3600;
input_dev->id.product = 0x0666; /* FIXME !!! We can ask the hardware */
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
- input_dev->private = ts;
+ input_dev->dev.parent = &serio->dev;
+
+ input_set_drvdata(input_dev, ts);
input_dev->event = h3600ts_event;
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index 24908747274..61c15024c2a 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -21,7 +21,7 @@
static void do_softint(void *data);
static struct input_dev *hp680_ts_dev;
-static DECLARE_WORK(work, do_softint, 0);
+static DECLARE_WORK(work, do_softint);
static void do_softint(void *data)
{
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index c3c2d735d0e..4ec3b1f940c 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -144,13 +144,13 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
mtouch->dev = input_dev;
snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
- input_dev->private = mtouch;
input_dev->name = "MicroTouch Serial TouchScreen";
input_dev->phys = mtouch->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_MICROTOUCH;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(mtouch->dev, ABS_X, MTOUCH_MIN_XC, MTOUCH_MAX_XC, 0, 0);
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index bd2767991ae..f2c0d3c7149 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -105,14 +105,13 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
pm->dev = input_dev;
snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
- input_dev->private = pm;
input_dev->name = "Penmount Serial TouchScreen";
input_dev->phys = pm->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_PENMOUNT;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &serio->dev;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 35ba46c6ad2..3def7bb1df4 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -118,13 +118,13 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
tr->dev = input_dev;
snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
- input_dev->private = tr;
input_dev->name = "Touchright Serial TouchScreen";
input_dev->phys = tr->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_TOUCHRIGHT;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 4dc073dacab..ac4bdcf1866 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -125,13 +125,13 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
tw->dev = input_dev;
snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
- input_dev->private = tw;
input_dev->name = "Touchwindow Serial TouchScreen";
input_dev->phys = tw->phys;
input_dev->id.bustype = BUS_RS232;
input_dev->id.vendor = SERIO_TOUCHWIN;
input_dev->id.product = 0;
input_dev->id.version = 0x0100;
+ input_dev->dev.parent = &serio->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index e8606c48c9c..6582816a047 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -97,6 +97,8 @@ struct ucb1400 {
};
static int adcsync;
+static int ts_delay = 55; /* us */
+static int ts_delay_pressure; /* us */
static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg)
{
@@ -159,6 +161,7 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb)
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+ udelay(ts_delay_pressure);
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
}
@@ -180,7 +183,7 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb)
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
- udelay(55);
+ udelay(ts_delay);
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY);
}
@@ -203,7 +206,7 @@ static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb)
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
- udelay(55);
+ udelay(ts_delay);
return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX);
}
@@ -369,7 +372,7 @@ static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid)
static int ucb1400_ts_open(struct input_dev *idev)
{
- struct ucb1400 *ucb = idev->private;
+ struct ucb1400 *ucb = input_get_drvdata(idev);
int ret = 0;
BUG_ON(ucb->ts_task);
@@ -385,7 +388,7 @@ static int ucb1400_ts_open(struct input_dev *idev)
static void ucb1400_ts_close(struct input_dev *idev)
{
- struct ucb1400 *ucb = idev->private;
+ struct ucb1400 *ucb = input_get_drvdata(idev);
if (ucb->ts_task)
kthread_stop(ucb->ts_task);
@@ -507,8 +510,9 @@ static int ucb1400_ts_probe(struct device *dev)
}
printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq);
- idev->private = ucb;
- idev->cdev.dev = dev;
+ input_set_drvdata(idev, ucb);
+
+ idev->dev.parent = dev;
idev->name = "UCB1400 touchscreen interface";
idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1);
idev->id.product = id;
@@ -571,7 +575,15 @@ static void __exit ucb1400_ts_exit(void)
driver_unregister(&ucb1400_ts_driver);
}
-module_param(adcsync, int, 0444);
+module_param(adcsync, bool, 0444);
+MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin.");
+
+module_param(ts_delay, int, 0444);
+MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us.");
+
+module_param(ts_delay_pressure, int, 0444);
+MODULE_PARM_DESC(ts_delay_pressure,
+ "delay between panel setup and pressure read. Default = 0us.");
module_init(ucb1400_ts_init);
module_exit(ucb1400_ts_exit);
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 86e37a20f8e..8e18e6c6477 100644
--- a/drivers/usb/input/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -647,7 +647,7 @@ exit:
static int usbtouch_open(struct input_dev *input)
{
- struct usbtouch_usb *usbtouch = input->private;
+ struct usbtouch_usb *usbtouch = input_get_drvdata(input);
usbtouch->irq->dev = usbtouch->udev;
@@ -659,7 +659,7 @@ static int usbtouch_open(struct input_dev *input)
static void usbtouch_close(struct input_dev *input)
{
- struct usbtouch_usb *usbtouch = input->private;
+ struct usbtouch_usb *usbtouch = input_get_drvdata(input);
usb_kill_urb(usbtouch->irq);
}
@@ -668,9 +668,8 @@ static void usbtouch_close(struct input_dev *input)
static void usbtouch_free_buffers(struct usb_device *udev,
struct usbtouch_usb *usbtouch)
{
- if (usbtouch->data)
- usb_buffer_free(udev, usbtouch->type->rept_size,
- usbtouch->data, usbtouch->data_dma);
+ usb_buffer_free(udev, usbtouch->type->rept_size,
+ usbtouch->data, usbtouch->data_dma);
kfree(usbtouch->buffer);
}
@@ -740,8 +739,10 @@ static int usbtouch_probe(struct usb_interface *intf,
input_dev->name = usbtouch->name;
input_dev->phys = usbtouch->phys;
usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = usbtouch;
+ input_dev->dev.parent = &intf->dev;
+
+ input_set_drvdata(input_dev, usbtouch);
+
input_dev->open = usbtouch_open;
input_dev->close = usbtouch_close;
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index 0300dca8591..8238b13874c 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -48,7 +48,6 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/major.h>
-#include <linux/smp_lock.h>
#include <linux/random.h>
#include <linux/time.h>
#include <linux/device.h>
@@ -111,13 +110,13 @@ struct tsdev {
int minor;
char name[8];
wait_queue_head_t wait;
- struct list_head list;
+ struct list_head client_list;
struct input_handle handle;
int x, y, pressure;
struct ts_calibration cal;
};
-struct tsdev_list {
+struct tsdev_client {
struct fasync_struct *fasync;
struct list_head node;
struct tsdev *tsdev;
@@ -139,38 +138,49 @@ static struct tsdev *tsdev_table[TSDEV_MINORS/2];
static int tsdev_fasync(int fd, struct file *file, int on)
{
- struct tsdev_list *list = file->private_data;
+ struct tsdev_client *client = file->private_data;
int retval;
- retval = fasync_helper(fd, file, on, &list->fasync);
+ retval = fasync_helper(fd, file, on, &client->fasync);
return retval < 0 ? retval : 0;
}
static int tsdev_open(struct inode *inode, struct file *file)
{
int i = iminor(inode) - TSDEV_MINOR_BASE;
- struct tsdev_list *list;
+ struct tsdev_client *client;
+ struct tsdev *tsdev;
+ int error;
printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled "
"for removal.\nSee Documentation/feature-removal-schedule.txt "
"for details.\n");
- if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK])
+ if (i >= TSDEV_MINORS)
+ return -ENODEV;
+
+ tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
+ if (!tsdev || !tsdev->exist)
return -ENODEV;
- if (!(list = kzalloc(sizeof(struct tsdev_list), GFP_KERNEL)))
+ client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
+ if (!client)
return -ENOMEM;
- list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0;
+ client->tsdev = tsdev;
+ client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0;
+ list_add_tail(&client->node, &tsdev->client_list);
- i &= TSDEV_MINOR_MASK;
- list->tsdev = tsdev_table[i];
- list_add_tail(&list->node, &tsdev_table[i]->list);
- file->private_data = list;
+ if (!tsdev->open++ && tsdev->exist) {
+ error = input_open_device(&tsdev->handle);
+ if (error) {
+ list_del(&client->node);
+ kfree(client);
+ return error;
+ }
+ }
- if (!list->tsdev->open++)
- if (list->tsdev->exist)
- input_open_device(&list->tsdev->handle);
+ file->private_data = client;
return 0;
}
@@ -182,45 +192,48 @@ static void tsdev_free(struct tsdev *tsdev)
static int tsdev_release(struct inode *inode, struct file *file)
{
- struct tsdev_list *list = file->private_data;
+ struct tsdev_client *client = file->private_data;
+ struct tsdev *tsdev = client->tsdev;
tsdev_fasync(-1, file, 0);
- list_del(&list->node);
- if (!--list->tsdev->open) {
- if (list->tsdev->exist)
- input_close_device(&list->tsdev->handle);
+ list_del(&client->node);
+ kfree(client);
+
+ if (!--tsdev->open) {
+ if (tsdev->exist)
+ input_close_device(&tsdev->handle);
else
- tsdev_free(list->tsdev);
+ tsdev_free(tsdev);
}
- kfree(list);
+
return 0;
}
static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
- loff_t * ppos)
+ loff_t *ppos)
{
- struct tsdev_list *list = file->private_data;
+ struct tsdev_client *client = file->private_data;
+ struct tsdev *tsdev = client->tsdev;
int retval = 0;
- if (list->head == list->tail && list->tsdev->exist && (file->f_flags & O_NONBLOCK))
+ if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
- retval = wait_event_interruptible(list->tsdev->wait,
- list->head != list->tail || !list->tsdev->exist);
-
+ retval = wait_event_interruptible(tsdev->wait,
+ client->head != client->tail || !tsdev->exist);
if (retval)
return retval;
- if (!list->tsdev->exist)
+ if (!tsdev->exist)
return -ENODEV;
- while (list->head != list->tail &&
+ while (client->head != client->tail &&
retval + sizeof (struct ts_event) <= count) {
- if (copy_to_user (buffer + retval, list->event + list->tail,
+ if (copy_to_user (buffer + retval, client->event + client->tail,
sizeof (struct ts_event)))
return -EFAULT;
- list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
+ client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
retval += sizeof (struct ts_event);
}
@@ -228,32 +241,33 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
}
/* No kernel lock - fine */
-static unsigned int tsdev_poll(struct file *file, poll_table * wait)
+static unsigned int tsdev_poll(struct file *file, poll_table *wait)
{
- struct tsdev_list *list = file->private_data;
+ struct tsdev_client *client = file->private_data;
+ struct tsdev *tsdev = client->tsdev;
- poll_wait(file, &list->tsdev->wait, wait);
- return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
- (list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
+ poll_wait(file, &tsdev->wait, wait);
+ return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) |
+ (tsdev->exist ? 0 : (POLLHUP | POLLERR));
}
static int tsdev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct tsdev_list *list = file->private_data;
- struct tsdev *tsdev = list->tsdev;
+ struct tsdev_client *client = file->private_data;
+ struct tsdev *tsdev = client->tsdev;
int retval = 0;
switch (cmd) {
case TS_GET_CAL:
- if (copy_to_user ((void __user *)arg, &tsdev->cal,
- sizeof (struct ts_calibration)))
+ if (copy_to_user((void __user *)arg, &tsdev->cal,
+ sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
case TS_SET_CAL:
- if (copy_from_user (&tsdev->cal, (void __user *)arg,
- sizeof (struct ts_calibration)))
+ if (copy_from_user(&tsdev->cal, (void __user *)arg,
+ sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
@@ -279,7 +293,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
struct tsdev *tsdev = handle->private;
- struct tsdev_list *list;
+ struct tsdev_client *client;
struct timeval time;
switch (type) {
@@ -343,18 +357,18 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
if (type != EV_SYN || code != SYN_REPORT)
return;
- list_for_each_entry(list, &tsdev->list, node) {
+ list_for_each_entry(client, &tsdev->client_list, node) {
int x, y, tmp;
do_gettimeofday(&time);
- list->event[list->head].millisecs = time.tv_usec / 100;
- list->event[list->head].pressure = tsdev->pressure;
+ client->event[client->head].millisecs = time.tv_usec / 100;
+ client->event[client->head].pressure = tsdev->pressure;
x = tsdev->x;
y = tsdev->y;
/* Calibration */
- if (!list->raw) {
+ if (!client->raw) {
x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
if (tsdev->cal.xyswap) {
@@ -362,33 +376,35 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
}
}
- list->event[list->head].x = x;
- list->event[list->head].y = y;
- list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ client->event[client->head].x = x;
+ client->event[client->head].y = y;
+ client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1);
+ kill_fasync(&client->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&tsdev->wait);
}
-static struct input_handle *tsdev_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
+static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct tsdev *tsdev;
struct class_device *cdev;
+ dev_t devt;
int minor, delta;
+ int error;
for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
if (minor >= TSDEV_MINORS / 2) {
printk(KERN_ERR
"tsdev: You have way too many touchscreens\n");
- return NULL;
+ return -ENFILE;
}
- if (!(tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL)))
- return NULL;
+ tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL);
+ if (!tsdev)
+ return -ENOMEM;
- INIT_LIST_HEAD(&tsdev->list);
+ INIT_LIST_HEAD(&tsdev->client_list);
init_waitqueue_head(&tsdev->wait);
sprintf(tsdev->name, "ts%d", minor);
@@ -415,23 +431,45 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
tsdev_table[minor] = tsdev;
- cdev = class_device_create(&input_class, &dev->cdev,
- MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
- dev->cdev.dev, tsdev->name);
+ devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
+
+ cdev = class_device_create(&input_class, &dev->cdev, devt,
+ dev->cdev.dev, tsdev->name);
+ if (IS_ERR(cdev)) {
+ error = PTR_ERR(cdev);
+ goto err_free_tsdev;
+ }
/* temporary symlink to keep userspace happy */
- sysfs_create_link(&input_class.subsys.kset.kobj, &cdev->kobj,
- tsdev->name);
+ error = sysfs_create_link(&input_class.subsys.kobj,
+ &cdev->kobj, tsdev->name);
+ if (error)
+ goto err_cdev_destroy;
+
+ error = input_register_handle(&tsdev->handle);
+ if (error)
+ goto err_remove_link;
- return &tsdev->handle;
+ return 0;
+
+ err_remove_link:
+ sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
+ err_cdev_destroy:
+ class_device_destroy(&input_class, devt);
+ err_free_tsdev:
+ tsdev_table[minor] = NULL;
+ kfree(tsdev);
+ return error;
}
static void tsdev_disconnect(struct input_handle *handle)
{
struct tsdev *tsdev = handle->private;
- struct tsdev_list *list;
+ struct tsdev_client *client;
+
+ input_unregister_handle(handle);
- sysfs_remove_link(&input_class.subsys.kset.kobj, tsdev->name);
+ sysfs_remove_link(&input_class.subsys.kobj, tsdev->name);
class_device_destroy(&input_class,
MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + tsdev->minor));
tsdev->exist = 0;
@@ -439,8 +477,8 @@ static void tsdev_disconnect(struct input_handle *handle)
if (tsdev->open) {
input_close_device(handle);
wake_up_interruptible(&tsdev->wait);
- list_for_each_entry(list, &tsdev->list, node)
- kill_fasync(&list->fasync, SIGIO, POLL_HUP);
+ list_for_each_entry(client, &tsdev->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
} else
tsdev_free(tsdev);
}
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index c921d6c522f..c92f9d764fc 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -17,7 +17,7 @@ config CAPI_TRACE
help
If you say Y here, the kernelcapi driver can make verbose traces
of CAPI messages. This feature can be enabled/disabled via IOCTL for
- every controler (default disabled).
+ every controller (default disabled).
This will increase the size of the kernelcapi module by 20 KB.
If unsure, say Y.
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index db1260f73f1..81661b8bd3a 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -18,8 +18,8 @@
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
+#include <linux/mutex.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/wait.h>
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -147,7 +147,7 @@ struct capidev {
struct capincci *nccis;
- struct semaphore ncci_list_sem;
+ struct mutex ncci_list_mtx;
};
/* -------- global variables ---------------------------------------- */
@@ -395,7 +395,7 @@ static struct capidev *capidev_alloc(void)
if (!cdev)
return NULL;
- init_MUTEX(&cdev->ncci_list_sem);
+ mutex_init(&cdev->ncci_list_mtx);
skb_queue_head_init(&cdev->recvqueue);
init_waitqueue_head(&cdev->recvwait);
write_lock_irqsave(&capidev_list_lock, flags);
@@ -414,9 +414,9 @@ static void capidev_free(struct capidev *cdev)
}
skb_queue_purge(&cdev->recvqueue);
- down(&cdev->ncci_list_sem);
+ mutex_lock(&cdev->ncci_list_mtx);
capincci_free(cdev, 0xffffffff);
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
write_lock_irqsave(&capidev_list_lock, flags);
list_del(&cdev->list);
@@ -603,15 +603,15 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
u16 info = CAPIMSG_U16(skb->data, 12); // Info field
if (info == 0) {
- down(&cdev->ncci_list_sem);
+ mutex_lock(&cdev->ncci_list_mtx);
capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
}
}
if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_IND) {
- down(&cdev->ncci_list_sem);
+ mutex_lock(&cdev->ncci_list_mtx);
capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
}
spin_lock_irqsave(&workaround_lock, flags);
if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
@@ -752,9 +752,9 @@ capi_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos
CAPIMSG_SETAPPID(skb->data, cdev->ap.applid);
if (CAPIMSG_CMD(skb->data) == CAPI_DISCONNECT_B3_RESP) {
- down(&cdev->ncci_list_sem);
+ mutex_lock(&cdev->ncci_list_mtx);
capincci_free(cdev, CAPIMSG_NCCI(skb->data));
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
}
cdev->errcode = capi20_put_message(&cdev->ap, skb);
@@ -939,9 +939,9 @@ capi_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&ncci, argp, sizeof(ncci)))
return -EFAULT;
- down(&cdev->ncci_list_sem);
+ mutex_lock(&cdev->ncci_list_mtx);
if ((nccip = capincci_find(cdev, (u32) ncci)) == 0) {
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
return 0;
}
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -949,7 +949,7 @@ capi_ioctl(struct inode *inode, struct file *file,
count += atomic_read(&mp->ttyopencount);
}
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
return count;
}
return 0;
@@ -964,14 +964,14 @@ capi_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&ncci, argp,
sizeof(ncci)))
return -EFAULT;
- down(&cdev->ncci_list_sem);
+ mutex_lock(&cdev->ncci_list_mtx);
nccip = capincci_find(cdev, (u32) ncci);
if (!nccip || (mp = nccip->minorp) == 0) {
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
return -ESRCH;
}
unit = mp->minor;
- up(&cdev->ncci_list_sem);
+ mutex_unlock(&cdev->ncci_list_mtx);
return unit;
}
return 0;
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index ad1e2702c2d..22379b94e88 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -855,7 +855,7 @@ static _cdebbuf *g_debbuf;
static u_long g_debbuf_lock;
static _cmsg *g_cmsg;
-_cdebbuf *cdebbuf_alloc(void)
+static _cdebbuf *cdebbuf_alloc(void)
{
_cdebbuf *cdb;
@@ -989,11 +989,6 @@ _cdebbuf *capi_cmsg2str(_cmsg * cmsg)
return &g_debbuf;
}
-_cdebbuf *cdebbuf_alloc(void)
-{
- return &g_debbuf;
-}
-
void cdebbuf_free(_cdebbuf *cdb)
{
}
@@ -1009,7 +1004,6 @@ void __exit cdebug_exit(void)
#endif
-EXPORT_SYMBOL(cdebbuf_alloc);
EXPORT_SYMBOL(cdebbuf_free);
EXPORT_SYMBOL(capi_cmsg2message);
EXPORT_SYMBOL(capi_message2cmsg);
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 53a18900335..be77ee625bb 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
#else
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index c8e1c357cec..a1263019df5 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -138,8 +138,6 @@ struct usb_cardstate {
char bchars[6]; /* for request 0x19 */
};
-struct usb_bc_state {};
-
static inline unsigned tiocm_to_gigaset(unsigned state)
{
return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0);
@@ -579,25 +577,21 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
static int gigaset_freebcshw(struct bc_state *bcs)
{
- if (!bcs->hw.usb)
- return 0;
- //FIXME
- kfree(bcs->hw.usb);
+ /* unused */
return 1;
}
/* Initialize the b-channel structure */
static int gigaset_initbcshw(struct bc_state *bcs)
{
- bcs->hw.usb = kmalloc(sizeof(struct usb_bc_state), GFP_KERNEL);
- if (!bcs->hw.usb)
- return 0;
-
+ /* unused */
+ bcs->hw.usb = NULL;
return 1;
}
static void gigaset_reinitbcshw(struct bc_state *bcs)
{
+ /* nothing to do for M10x */
}
static void gigaset_freecshw(struct cardstate *cs)
diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
index 7a74ed35b1b..98fcdfc7ca5 100644
--- a/drivers/isdn/hardware/eicon/capimain.c
+++ b/drivers/isdn/hardware/eicon/capimain.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
#include <linux/skbuff.h>
#include "os_capi.h"
diff --git a/drivers/isdn/hardware/eicon/dbgioctl.h b/drivers/isdn/hardware/eicon/dbgioctl.h
deleted file mode 100644
index 0fb6f5e88b6..00000000000
--- a/drivers/isdn/hardware/eicon/dbgioctl.h
+++ /dev/null
@@ -1,198 +0,0 @@
-
-/*
- *
- Copyright (c) Eicon Technology Corporation, 2000.
- *
- This source file is supplied for the use with Eicon
- Technology Corporation's range of DIVA Server Adapters.
- *
- 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, or (at your option)
- any later version.
- *
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
- 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.
- *
- */
-/*------------------------------------------------------------------*/
-/* file: dbgioctl.h */
-/*------------------------------------------------------------------*/
-
-#if !defined(__DBGIOCTL_H__)
-
-#define __DBGIOCTL_H__
-
-#ifdef NOT_YET_NEEDED
-/*
- * The requested operation is passed in arg0 of DbgIoctlArgs,
- * additional arguments (if any) in arg1, arg2 and arg3.
- */
-
-typedef struct
-{ ULONG arg0 ;
- ULONG arg1 ;
- ULONG arg2 ;
- ULONG arg3 ;
-} DbgIoctlArgs ;
-
-#define DBG_COPY_LOGS 0 /* copy debugs to user until buffer full */
- /* arg1: size threshold */
- /* arg2: timeout in milliseconds */
-
-#define DBG_FLUSH_LOGS 1 /* flush pending debugs to user buffer */
- /* arg1: internal driver id */
-
-#define DBG_LIST_DRVS 2 /* return the list of registered drivers */
-
-#define DBG_GET_MASK 3 /* get current debug mask of driver */
- /* arg1: internal driver id */
-
-#define DBG_SET_MASK 4 /* set/change debug mask of driver */
- /* arg1: internal driver id */
- /* arg2: new debug mask */
-
-#define DBG_GET_BUFSIZE 5 /* get current buffer size of driver */
- /* arg1: internal driver id */
- /* arg2: new debug mask */
-
-#define DBG_SET_BUFSIZE 6 /* set new buffer size of driver */
- /* arg1: new buffer size */
-
-/*
- * common internal debug message structure
- */
-
-typedef struct
-{ unsigned short id ; /* virtual driver id */
- unsigned short type ; /* special message type */
- unsigned long seq ; /* sequence number of message */
- unsigned long size ; /* size of message in bytes */
- unsigned long next ; /* offset to next buffered message */
- LARGE_INTEGER NTtime ; /* 100 ns since 1.1.1601 */
- unsigned char data[4] ;/* message data */
-} OldDbgMessage ;
-
-typedef struct
-{ LARGE_INTEGER NTtime ; /* 100 ns since 1.1.1601 */
- unsigned short size ; /* size of message in bytes */
- unsigned short ffff ; /* always 0xffff to indicate new msg */
- unsigned short id ; /* virtual driver id */
- unsigned short type ; /* special message type */
- unsigned long seq ; /* sequence number of message */
- unsigned char data[4] ;/* message data */
-} DbgMessage ;
-
-#endif
-
-#define DRV_ID_UNKNOWN 0x0C /* for messages via prtComp() */
-
-#define MSG_PROC_FLAG 0x80
-#define MSG_PROC_NO_GET(x) (((x) & MSG_PROC_FLAG) ? (((x) >> 4) & 7) : -1)
-#define MSG_PROC_NO_SET(x) (MSG_PROC_FLAG | (((x) & 7) << 4))
-
-#define MSG_TYPE_DRV_ID 0x0001
-#define MSG_TYPE_FLAGS 0x0002
-#define MSG_TYPE_STRING 0x0003
-#define MSG_TYPE_BINARY 0x0004
-
-#define MSG_HEAD_SIZE ((unsigned long)&(((DbgMessage *)0)->data[0]))
-#define MSG_ALIGN(len) (((unsigned long)(len) + MSG_HEAD_SIZE + 3) & ~3)
-#define MSG_SIZE(pMsg) MSG_ALIGN((pMsg)->size)
-#define MSG_NEXT(pMsg) ((DbgMessage *)( ((char *)(pMsg)) + MSG_SIZE(pMsg) ))
-
-#define OLD_MSG_HEAD_SIZE ((unsigned long)&(((OldDbgMessage *)0)->data[0]))
-#define OLD_MSG_ALIGN(len) (((unsigned long)(len)+OLD_MSG_HEAD_SIZE+3) & ~3)
-
-/*
- * manifest constants
- */
-
-#define MSG_FRAME_MAX_SIZE 2150 /* maximum size of B1 frame */
-#define MSG_TEXT_MAX_SIZE 1024 /* maximum size of msg text */
-#define MSG_MAX_SIZE MSG_ALIGN(MSG_FRAME_MAX_SIZE)
-#define DBG_MIN_BUFFER_SIZE 0x00008000 /* minimal total buffer size 32 KB */
-#define DBG_DEF_BUFFER_SIZE 0x00020000 /* default total buffer size 128 KB */
-#define DBG_MAX_BUFFER_SIZE 0x00400000 /* maximal total buffer size 4 MB */
-
-#define DBGDRV_NAME "Diehl_DIMAINT"
-#define UNIDBG_DRIVER L"\\Device\\Diehl_DIMAINT" /* UNICODE name for kernel */
-#define DEBUG_DRIVER "\\\\.\\" DBGDRV_NAME /* traditional string for apps */
-#define DBGVXD_NAME "DIMAINT"
-#define DEBUG_VXD "\\\\.\\" DBGVXD_NAME /* traditional string for apps */
-
-/*
- * Special IDI interface debug construction
- */
-
-#define DBG_IDI_SIG_REQ (unsigned long)0xF479C402
-#define DBG_IDI_SIG_IND (unsigned long)0xF479C403
-#define DBG_IDI_NL_REQ (unsigned long)0xF479C404
-#define DBG_IDI_NL_IND (unsigned long)0xF479C405
-
-typedef struct
-{ unsigned long magic_type ;
- unsigned short data_len ;
- unsigned char layer_ID ;
- unsigned char entity_ID ;
- unsigned char request ;
- unsigned char ret_code ;
- unsigned char indication ;
- unsigned char complete ;
- unsigned char data[4] ;
-} DbgIdiAct, *DbgIdiAction ;
-
-/*
- * We want to use the same IOCTL codes in Win95 and WinNT.
- * The official constructor for IOCTL codes is the CTL_CODE macro
- * from <winoctl.h> (<devioctl.h> in WinNT DDK environment).
- * The problem here is that we don't know how to get <winioctl.h>
- * working in a Win95 DDK environment!
- */
-
-# ifdef CTL_CODE /*{*/
-
-/* Assert that we have the same idea of the CTL_CODE macro. */
-
-#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
- ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
-)
-
-# else /* !CTL_CODE */ /*}{*/
-
-/* Use the definitions stolen from <winioctl.h>. */
-
-#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
- ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
-)
-
-#define METHOD_BUFFERED 0
-#define METHOD_IN_DIRECT 1
-#define METHOD_OUT_DIRECT 2
-#define METHOD_NEITHER 3
-
-#define FILE_ANY_ACCESS 0
-#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe
-#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe
-
-# endif /* CTL_CODE */ /*}*/
-
-/*
- * Now we can define WinNT/Win95 DeviceIoControl codes.
- *
- * These codes are defined in di_defs.h too, a possible mismatch will be
- * detected when the dbgtool is compiled.
- */
-
-#define IOCTL_DRIVER_LNK \
- CTL_CODE(0x8001U,0x701,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
-#define IOCTL_DRIVER_DBG \
- CTL_CODE(0x8001U,0x702,METHOD_OUT_DIRECT,FILE_ANY_ACCESS)
-
-#endif /* __DBGIOCTL_H__ */
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
index 4aba5c502d8..c9092897424 100644
--- a/drivers/isdn/hardware/eicon/divamnt.c
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index 556b19615bc..78f141e7746 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -14,7 +14,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index 5e862e24411..6d39f936076 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -17,7 +17,6 @@
#include <linux/ioport.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/poll.h>
diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
index af3eb9e795b..85784a7ffb2 100644
--- a/drivers/isdn/hardware/eicon/divasync.h
+++ b/drivers/isdn/hardware/eicon/divasync.h
@@ -216,7 +216,7 @@ typedef struct
#define SERIAL_HOOK_RING 0x85
#define SERIAL_HOOK_DETACH 0x8f
unsigned char Flags; /* function refinements */
- /* parameters passed by the the ATTACH request */
+ /* parameters passed by the ATTACH request */
SERIAL_INT_CB InterruptHandler; /* called on each interrupt */
SERIAL_DPC_CB DeferredHandler; /* called on hook state changes */
void *HandlerContext; /* context for both handlers */
diff --git a/drivers/isdn/hardware/eicon/main_if.h b/drivers/isdn/hardware/eicon/main_if.h
deleted file mode 100644
index 0ea339afd42..00000000000
--- a/drivers/isdn/hardware/eicon/main_if.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *
- Copyright (c) Eicon Technology Corporation, 2000.
- *
- This source file is supplied for the use with Eicon
- Technology Corporation's range of DIVA Server Adapters.
- *
- 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, or (at your option)
- any later version.
- *
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
- 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.
- *
- */
-/*------------------------------------------------------------------*/
-/* file: main_if.h */
-/*------------------------------------------------------------------*/
-# ifndef MAIN_IF___H
-# define MAIN_IF___H
-
-# include "debug_if.h"
-
-void DI_lock (void) ;
-void DI_unlock (void) ;
-
-#ifdef NOT_YET_NEEDED
-void DI_nttime (LARGE_INTEGER *NTtime) ;
-void DI_ntlcltime(LARGE_INTEGER *NTtime, LARGE_INTEGER *lclNTtime) ;
-void DI_nttimefields(LARGE_INTEGER *NTtime, TIME_FIELDS *TimeFields);
-unsigned long DI_wintime(LARGE_INTEGER *NTtime) ;
-
-unsigned short DiInsertProcessorNumber (int type) ;
-void DiProcessEventLog (unsigned short id, unsigned long msgID, va_list ap);
-
-void StartIoctlTimer (void (*Handler)(void), unsigned long msec) ;
-void StopIoctlTimer (void) ;
-void UnpendIoctl (DbgRequest *pDbgReq) ;
-#endif
-
-void add_to_q(int, char* , unsigned int);
-# endif /* MAIN_IF___H */
-
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
index ff09f07f440..15d4942de53 100644
--- a/drivers/isdn/hardware/eicon/platform.h
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -26,7 +26,6 @@
#include <linux/vmalloc.h>
#include <linux/proc_fs.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <asm/types.h>
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 9f44d3e69fb..1f18f199338 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -37,7 +37,6 @@
#include <linux/kernel_stat.h>
#include <linux/usb.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include "hisax.h"
#include "hisax_if.h"
#include "hfc_usb.h"
@@ -1218,11 +1217,11 @@ usb_init(hfcusb_data * hfc)
/* aux = output, reset off */
write_usb(hfc, HFCUSB_CIRM, 0x10);
- /* set USB_SIZE to match the the wMaxPacketSize for INT or BULK transfers */
+ /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
write_usb(hfc, HFCUSB_USB_SIZE,
(hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
- /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */
+ /* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
/* enable PCM/GCI master mode */
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 38f648f9b0e..02c6fbaeccf 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -19,7 +19,6 @@
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
-#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include <asm/io.h>
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 84dccd526ac..6cdbad3a992 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -443,7 +443,7 @@ ergo_inithardware(hysdn_card * card)
card->waitpofready = ergo_waitpofready;
card->set_errlog_state = ergo_set_errlog_state;
INIT_WORK(&card->irq_queue, ergo_irq_bh);
- card->hysdn_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&card->hysdn_lock);
return (0);
} /* ergo_inithardware */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index f7e83a86f44..27b3991fb0e 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
-#include <linux/pci.h>
#include <linux/smp_lock.h>
#include "hysdn_defs.h"
@@ -298,8 +297,6 @@ hysdn_log_close(struct inode *ino, struct file *filep)
struct procdata *pd;
hysdn_card *card;
int retval = 0;
- unsigned long flags;
- spinlock_t hysdn_lock = SPIN_LOCK_UNLOCKED;
lock_kernel();
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
@@ -309,7 +306,6 @@ hysdn_log_close(struct inode *ino, struct file *filep)
/* read access -> log/debug read, mark one further file as closed */
pd = NULL;
- spin_lock_irqsave(&hysdn_lock, flags);
inf = *((struct log_data **) filep->private_data); /* get first log entry */
if (inf)
pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
@@ -332,7 +328,6 @@ hysdn_log_close(struct inode *ino, struct file *filep)
inf->usage_cnt--; /* decrement usage count for buffers */
inf = inf->next;
}
- spin_unlock_irqrestore(&hysdn_lock, flags);
if (pd)
if (pd->if_used <= 0) /* delete buffers if last file closed */
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index e93ad59f60b..bb92e3cd933 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -1462,7 +1462,7 @@ isdnloop_initcard(char *id)
skb_queue_head_init(&card->bqueue[i]);
}
skb_queue_head_init(&card->dqueue);
- card->isdnloop_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&card->isdnloop_lock);
card->next = cards;
cards = card;
if (!register_isdn(&card->interface)) {
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 0d122bf889d..41634fde8e1 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -51,16 +51,19 @@
#define UNMAPPED_GVA (~(gpa_t)0)
#define KVM_MAX_VCPUS 1
+#define KVM_ALIAS_SLOTS 4
#define KVM_MEMORY_SLOTS 4
#define KVM_NUM_MMU_PAGES 256
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
+#define KVM_MAX_CPUID_ENTRIES 40
#define FX_IMAGE_SIZE 512
#define FX_IMAGE_ALIGN 16
#define FX_BUF_SIZE (2 * FX_IMAGE_SIZE + FX_IMAGE_ALIGN)
#define DE_VECTOR 0
+#define NM_VECTOR 7
#define DF_VECTOR 8
#define TS_VECTOR 10
#define NP_VECTOR 11
@@ -73,6 +76,8 @@
#define IOPL_SHIFT 12
+#define KVM_PIO_PAGE_OFFSET 1
+
/*
* Address types:
*
@@ -106,6 +111,7 @@ struct kvm_pte_chain {
* bits 4:7 - page table level for this shadow (1-4)
* bits 8:9 - page table quadrant for 2-level guests
* bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
+ * bits 17:18 - "access" - the user and writable bits of a huge page pde
*/
union kvm_mmu_page_role {
unsigned word;
@@ -115,6 +121,7 @@ union kvm_mmu_page_role {
unsigned quadrant : 2;
unsigned pad_for_nice_hex_output : 6;
unsigned metaphysical : 1;
+ unsigned hugepage_access : 2;
};
};
@@ -133,7 +140,6 @@ struct kvm_mmu_page {
unsigned long slot_bitmap; /* One bit set per slot which has memory
* in this shadow page.
*/
- int global; /* Set if all ptes in this page are global */
int multimapped; /* More than one parent_pte? */
int root_count; /* Currently serving as active root */
union {
@@ -219,6 +225,34 @@ enum {
VCPU_SREG_LDTR,
};
+struct kvm_pio_request {
+ unsigned long count;
+ int cur_count;
+ struct page *guest_pages[2];
+ unsigned guest_page_offset;
+ int in;
+ int size;
+ int string;
+ int down;
+ int rep;
+};
+
+struct kvm_stat {
+ u32 pf_fixed;
+ u32 pf_guest;
+ u32 tlb_flush;
+ u32 invlpg;
+
+ u32 exits;
+ u32 io_exits;
+ u32 mmio_exits;
+ u32 signal_exits;
+ u32 irq_window_exits;
+ u32 halt_exits;
+ u32 request_irq_exits;
+ u32 irq_exits;
+};
+
struct kvm_vcpu {
struct kvm *kvm;
union {
@@ -228,6 +262,8 @@ struct kvm_vcpu {
struct mutex mutex;
int cpu;
int launched;
+ u64 host_tsc;
+ struct kvm_run *run;
int interrupt_window_open;
unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
@@ -266,6 +302,7 @@ struct kvm_vcpu {
char fx_buf[FX_BUF_SIZE];
char *host_fx_image;
char *guest_fx_image;
+ int fpu_active;
int mmio_needed;
int mmio_read_completed;
@@ -273,6 +310,14 @@ struct kvm_vcpu {
int mmio_size;
unsigned char mmio_data[8];
gpa_t mmio_phys_addr;
+ gva_t mmio_fault_cr2;
+ struct kvm_pio_request pio;
+ void *pio_data;
+
+ int sigset_active;
+ sigset_t sigset;
+
+ struct kvm_stat stat;
struct {
int active;
@@ -284,6 +329,15 @@ struct kvm_vcpu {
u32 ar;
} tr, es, ds, fs, gs;
} rmode;
+
+ int cpuid_nent;
+ struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES];
+};
+
+struct kvm_mem_alias {
+ gfn_t base_gfn;
+ unsigned long npages;
+ gfn_t target_gfn;
};
struct kvm_memory_slot {
@@ -296,6 +350,8 @@ struct kvm_memory_slot {
struct kvm {
spinlock_t lock; /* protects everything except vcpus */
+ int naliases;
+ struct kvm_mem_alias aliases[KVM_ALIAS_SLOTS];
int nmemslots;
struct kvm_memory_slot memslots[KVM_MEMORY_SLOTS];
/*
@@ -312,22 +368,6 @@ struct kvm {
struct file *filp;
};
-struct kvm_stat {
- u32 pf_fixed;
- u32 pf_guest;
- u32 tlb_flush;
- u32 invlpg;
-
- u32 exits;
- u32 io_exits;
- u32 mmio_exits;
- u32 signal_exits;
- u32 irq_window_exits;
- u32 halt_exits;
- u32 request_irq_exits;
- u32 irq_exits;
-};
-
struct descriptor_table {
u16 limit;
unsigned long base;
@@ -358,10 +398,8 @@ struct kvm_arch_ops {
void (*set_segment)(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
void (*get_cs_db_l_bits)(struct kvm_vcpu *vcpu, int *db, int *l);
- void (*decache_cr0_cr4_guest_bits)(struct kvm_vcpu *vcpu);
+ void (*decache_cr4_guest_bits)(struct kvm_vcpu *vcpu);
void (*set_cr0)(struct kvm_vcpu *vcpu, unsigned long cr0);
- void (*set_cr0_no_modeswitch)(struct kvm_vcpu *vcpu,
- unsigned long cr0);
void (*set_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
void (*set_cr4)(struct kvm_vcpu *vcpu, unsigned long cr4);
void (*set_efer)(struct kvm_vcpu *vcpu, u64 efer);
@@ -391,7 +429,6 @@ struct kvm_arch_ops {
unsigned char *hypercall_addr);
};
-extern struct kvm_stat kvm_stat;
extern struct kvm_arch_ops *kvm_arch_ops;
#define kvm_printf(kvm, fmt ...) printk(KERN_DEBUG fmt)
@@ -400,28 +437,29 @@ extern struct kvm_arch_ops *kvm_arch_ops;
int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module);
void kvm_exit_arch(void);
+int kvm_mmu_module_init(void);
+void kvm_mmu_module_exit(void);
+
void kvm_mmu_destroy(struct kvm_vcpu *vcpu);
int kvm_mmu_create(struct kvm_vcpu *vcpu);
int kvm_mmu_setup(struct kvm_vcpu *vcpu);
int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
+void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva);
+struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva);
void kvm_emulator_want_group7_invlpg(void);
extern hpa_t bad_page_address;
-static inline struct page *gfn_to_page(struct kvm_memory_slot *slot, gfn_t gfn)
-{
- return slot->phys_mem[gfn - slot->base_gfn];
-}
-
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
@@ -444,6 +482,10 @@ void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
struct x86_emulate_ctxt;
+int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned long count, int string, int down,
+ gva_t address, int rep, unsigned port);
+void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
int emulate_clts(struct kvm_vcpu *vcpu);
int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
@@ -493,12 +535,6 @@ static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
return vcpu->mmu.page_fault(vcpu, gva, error_code);
}
-static inline struct page *_gfn_to_page(struct kvm *kvm, gfn_t gfn)
-{
- struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
- return (slot) ? slot->phys_mem[gfn - slot->base_gfn] : NULL;
-}
-
static inline int is_long_mode(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index dc7a8c78cbf..0d892600ff0 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -51,27 +51,27 @@ static DEFINE_SPINLOCK(kvm_lock);
static LIST_HEAD(vm_list);
struct kvm_arch_ops *kvm_arch_ops;
-struct kvm_stat kvm_stat;
-EXPORT_SYMBOL_GPL(kvm_stat);
+
+#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
static struct kvm_stats_debugfs_item {
const char *name;
- u32 *data;
+ int offset;
struct dentry *dentry;
} debugfs_entries[] = {
- { "pf_fixed", &kvm_stat.pf_fixed },
- { "pf_guest", &kvm_stat.pf_guest },
- { "tlb_flush", &kvm_stat.tlb_flush },
- { "invlpg", &kvm_stat.invlpg },
- { "exits", &kvm_stat.exits },
- { "io_exits", &kvm_stat.io_exits },
- { "mmio_exits", &kvm_stat.mmio_exits },
- { "signal_exits", &kvm_stat.signal_exits },
- { "irq_window", &kvm_stat.irq_window_exits },
- { "halt_exits", &kvm_stat.halt_exits },
- { "request_irq", &kvm_stat.request_irq_exits },
- { "irq_exits", &kvm_stat.irq_exits },
- { NULL, NULL }
+ { "pf_fixed", STAT_OFFSET(pf_fixed) },
+ { "pf_guest", STAT_OFFSET(pf_guest) },
+ { "tlb_flush", STAT_OFFSET(tlb_flush) },
+ { "invlpg", STAT_OFFSET(invlpg) },
+ { "exits", STAT_OFFSET(exits) },
+ { "io_exits", STAT_OFFSET(io_exits) },
+ { "mmio_exits", STAT_OFFSET(mmio_exits) },
+ { "signal_exits", STAT_OFFSET(signal_exits) },
+ { "irq_window", STAT_OFFSET(irq_window_exits) },
+ { "halt_exits", STAT_OFFSET(halt_exits) },
+ { "request_irq", STAT_OFFSET(request_irq_exits) },
+ { "irq_exits", STAT_OFFSET(irq_exits) },
+ { NULL }
};
static struct dentry *debugfs_dir;
@@ -346,6 +346,17 @@ static void kvm_free_physmem(struct kvm *kvm)
kvm_free_physmem_slot(&kvm->memslots[i], NULL);
}
+static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
+{
+ int i;
+
+ for (i = 0; i < 2; ++i)
+ if (vcpu->pio.guest_pages[i]) {
+ __free_page(vcpu->pio.guest_pages[i]);
+ vcpu->pio.guest_pages[i] = NULL;
+ }
+}
+
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->vmcs)
@@ -355,6 +366,11 @@ static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
kvm_mmu_destroy(vcpu);
vcpu_put(vcpu);
kvm_arch_ops->vcpu_free(vcpu);
+ free_page((unsigned long)vcpu->run);
+ vcpu->run = NULL;
+ free_page((unsigned long)vcpu->pio_data);
+ vcpu->pio_data = NULL;
+ free_pio_guest_pages(vcpu);
}
static void kvm_free_vcpus(struct kvm *kvm)
@@ -404,12 +420,12 @@ static int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3)
u64 pdpte;
u64 *pdpt;
int ret;
- struct kvm_memory_slot *memslot;
+ struct page *page;
spin_lock(&vcpu->kvm->lock);
- memslot = gfn_to_memslot(vcpu->kvm, pdpt_gfn);
- /* FIXME: !memslot - emulate? 0xff? */
- pdpt = kmap_atomic(gfn_to_page(memslot, pdpt_gfn), KM_USER0);
+ page = gfn_to_page(vcpu->kvm, pdpt_gfn);
+ /* FIXME: !page - emulate? 0xff? */
+ pdpt = kmap_atomic(page, KM_USER0);
ret = 1;
for (i = 0; i < 4; ++i) {
@@ -494,7 +510,6 @@ EXPORT_SYMBOL_GPL(set_cr0);
void lmsw(struct kvm_vcpu *vcpu, unsigned long msw)
{
- kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
set_cr0(vcpu, (vcpu->cr0 & ~0x0ful) | (msw & 0x0f));
}
EXPORT_SYMBOL_GPL(lmsw);
@@ -830,7 +845,73 @@ out:
return r;
}
-struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
+/*
+ * Set a new alias region. Aliases map a portion of physical memory into
+ * another portion. This is useful for memory windows, for example the PC
+ * VGA region.
+ */
+static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
+ struct kvm_memory_alias *alias)
+{
+ int r, n;
+ struct kvm_mem_alias *p;
+
+ r = -EINVAL;
+ /* General sanity checks */
+ if (alias->memory_size & (PAGE_SIZE - 1))
+ goto out;
+ if (alias->guest_phys_addr & (PAGE_SIZE - 1))
+ goto out;
+ if (alias->slot >= KVM_ALIAS_SLOTS)
+ goto out;
+ if (alias->guest_phys_addr + alias->memory_size
+ < alias->guest_phys_addr)
+ goto out;
+ if (alias->target_phys_addr + alias->memory_size
+ < alias->target_phys_addr)
+ goto out;
+
+ spin_lock(&kvm->lock);
+
+ p = &kvm->aliases[alias->slot];
+ p->base_gfn = alias->guest_phys_addr >> PAGE_SHIFT;
+ p->npages = alias->memory_size >> PAGE_SHIFT;
+ p->target_gfn = alias->target_phys_addr >> PAGE_SHIFT;
+
+ for (n = KVM_ALIAS_SLOTS; n > 0; --n)
+ if (kvm->aliases[n - 1].npages)
+ break;
+ kvm->naliases = n;
+
+ spin_unlock(&kvm->lock);
+
+ vcpu_load(&kvm->vcpus[0]);
+ spin_lock(&kvm->lock);
+ kvm_mmu_zap_all(&kvm->vcpus[0]);
+ spin_unlock(&kvm->lock);
+ vcpu_put(&kvm->vcpus[0]);
+
+ return 0;
+
+out:
+ return r;
+}
+
+static gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
+{
+ int i;
+ struct kvm_mem_alias *alias;
+
+ for (i = 0; i < kvm->naliases; ++i) {
+ alias = &kvm->aliases[i];
+ if (gfn >= alias->base_gfn
+ && gfn < alias->base_gfn + alias->npages)
+ return alias->target_gfn + gfn - alias->base_gfn;
+ }
+ return gfn;
+}
+
+static struct kvm_memory_slot *__gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
{
int i;
@@ -843,7 +924,24 @@ struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
}
return NULL;
}
-EXPORT_SYMBOL_GPL(gfn_to_memslot);
+
+struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn)
+{
+ gfn = unalias_gfn(kvm, gfn);
+ return __gfn_to_memslot(kvm, gfn);
+}
+
+struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
+{
+ struct kvm_memory_slot *slot;
+
+ gfn = unalias_gfn(kvm, gfn);
+ slot = __gfn_to_memslot(kvm, gfn);
+ if (!slot)
+ return NULL;
+ return slot->phys_mem[gfn - slot->base_gfn];
+}
+EXPORT_SYMBOL_GPL(gfn_to_page);
void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
@@ -871,7 +969,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
}
static int emulator_read_std(unsigned long addr,
- unsigned long *val,
+ void *val,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
@@ -883,20 +981,20 @@ static int emulator_read_std(unsigned long addr,
unsigned offset = addr & (PAGE_SIZE-1);
unsigned tocopy = min(bytes, (unsigned)PAGE_SIZE - offset);
unsigned long pfn;
- struct kvm_memory_slot *memslot;
- void *page;
+ struct page *page;
+ void *page_virt;
if (gpa == UNMAPPED_GVA)
return X86EMUL_PROPAGATE_FAULT;
pfn = gpa >> PAGE_SHIFT;
- memslot = gfn_to_memslot(vcpu->kvm, pfn);
- if (!memslot)
+ page = gfn_to_page(vcpu->kvm, pfn);
+ if (!page)
return X86EMUL_UNHANDLEABLE;
- page = kmap_atomic(gfn_to_page(memslot, pfn), KM_USER0);
+ page_virt = kmap_atomic(page, KM_USER0);
- memcpy(data, page + offset, tocopy);
+ memcpy(data, page_virt + offset, tocopy);
- kunmap_atomic(page, KM_USER0);
+ kunmap_atomic(page_virt, KM_USER0);
bytes -= tocopy;
data += tocopy;
@@ -907,7 +1005,7 @@ static int emulator_read_std(unsigned long addr,
}
static int emulator_write_std(unsigned long addr,
- unsigned long val,
+ const void *val,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
@@ -917,7 +1015,7 @@ static int emulator_write_std(unsigned long addr,
}
static int emulator_read_emulated(unsigned long addr,
- unsigned long *val,
+ void *val,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
@@ -945,37 +1043,37 @@ static int emulator_read_emulated(unsigned long addr,
}
static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
- unsigned long val, int bytes)
+ const void *val, int bytes)
{
- struct kvm_memory_slot *m;
struct page *page;
void *virt;
if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
return 0;
- m = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
- if (!m)
+ page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+ if (!page)
return 0;
- page = gfn_to_page(m, gpa >> PAGE_SHIFT);
kvm_mmu_pre_write(vcpu, gpa, bytes);
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0);
- memcpy(virt + offset_in_page(gpa), &val, bytes);
+ memcpy(virt + offset_in_page(gpa), val, bytes);
kunmap_atomic(virt, KM_USER0);
kvm_mmu_post_write(vcpu, gpa, bytes);
return 1;
}
static int emulator_write_emulated(unsigned long addr,
- unsigned long val,
+ const void *val,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
struct kvm_vcpu *vcpu = ctxt->vcpu;
gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
- if (gpa == UNMAPPED_GVA)
+ if (gpa == UNMAPPED_GVA) {
+ kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
return X86EMUL_PROPAGATE_FAULT;
+ }
if (emulator_write_phys(vcpu, gpa, val, bytes))
return X86EMUL_CONTINUE;
@@ -984,14 +1082,14 @@ static int emulator_write_emulated(unsigned long addr,
vcpu->mmio_phys_addr = gpa;
vcpu->mmio_size = bytes;
vcpu->mmio_is_write = 1;
- memcpy(vcpu->mmio_data, &val, bytes);
+ memcpy(vcpu->mmio_data, val, bytes);
return X86EMUL_CONTINUE;
}
static int emulator_cmpxchg_emulated(unsigned long addr,
- unsigned long old,
- unsigned long new,
+ const void *old,
+ const void *new,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
@@ -1004,30 +1102,6 @@ static int emulator_cmpxchg_emulated(unsigned long addr,
return emulator_write_emulated(addr, new, bytes, ctxt);
}
-#ifdef CONFIG_X86_32
-
-static int emulator_cmpxchg8b_emulated(unsigned long addr,
- unsigned long old_lo,
- unsigned long old_hi,
- unsigned long new_lo,
- unsigned long new_hi,
- struct x86_emulate_ctxt *ctxt)
-{
- static int reported;
- int r;
-
- if (!reported) {
- reported = 1;
- printk(KERN_WARNING "kvm: emulating exchange8b as write\n");
- }
- r = emulator_write_emulated(addr, new_lo, 4, ctxt);
- if (r != X86EMUL_CONTINUE)
- return r;
- return emulator_write_emulated(addr+4, new_hi, 4, ctxt);
-}
-
-#endif
-
static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
return kvm_arch_ops->get_segment_base(vcpu, seg);
@@ -1042,7 +1116,6 @@ int emulate_clts(struct kvm_vcpu *vcpu)
{
unsigned long cr0;
- kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
cr0 = vcpu->cr0 & ~CR0_TS_MASK;
kvm_arch_ops->set_cr0(vcpu, cr0);
return X86EMUL_CONTINUE;
@@ -1102,9 +1175,6 @@ struct x86_emulate_ops emulate_ops = {
.read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated,
.cmpxchg_emulated = emulator_cmpxchg_emulated,
-#ifdef CONFIG_X86_32
- .cmpxchg8b_emulated = emulator_cmpxchg8b_emulated,
-#endif
};
int emulate_instruction(struct kvm_vcpu *vcpu,
@@ -1116,6 +1186,7 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
int r;
int cs_db, cs_l;
+ vcpu->mmio_fault_cr2 = cr2;
kvm_arch_ops->cache_regs(vcpu);
kvm_arch_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
@@ -1166,8 +1237,10 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
kvm_arch_ops->decache_regs(vcpu);
kvm_arch_ops->set_rflags(vcpu, emulate_ctxt.eflags);
- if (vcpu->mmio_is_write)
+ if (vcpu->mmio_is_write) {
+ vcpu->mmio_needed = 0;
return EMULATE_DO_MMIO;
+ }
return EMULATE_DONE;
}
@@ -1177,7 +1250,7 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
- kvm_arch_ops->decache_regs(vcpu);
+ kvm_arch_ops->cache_regs(vcpu);
ret = -KVM_EINVAL;
#ifdef CONFIG_X86_64
if (is_long_mode(vcpu)) {
@@ -1201,10 +1274,19 @@ int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
}
switch (nr) {
default:
- ;
+ run->hypercall.args[0] = a0;
+ run->hypercall.args[1] = a1;
+ run->hypercall.args[2] = a2;
+ run->hypercall.args[3] = a3;
+ run->hypercall.args[4] = a4;
+ run->hypercall.args[5] = a5;
+ run->hypercall.ret = ret;
+ run->hypercall.longmode = is_long_mode(vcpu);
+ kvm_arch_ops->decache_regs(vcpu);
+ return 0;
}
vcpu->regs[VCPU_REGS_RAX] = ret;
- kvm_arch_ops->cache_regs(vcpu);
+ kvm_arch_ops->decache_regs(vcpu);
return 1;
}
EXPORT_SYMBOL_GPL(kvm_hypercall);
@@ -1237,7 +1319,7 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr)
{
- kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ kvm_arch_ops->decache_cr4_guest_bits(vcpu);
switch (cr) {
case 0:
return vcpu->cr0;
@@ -1442,6 +1524,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
printk(KERN_WARNING "%s: MSR_IA32_MC0_STATUS 0x%llx, nop\n",
__FUNCTION__, data);
break;
+ case MSR_IA32_MCG_STATUS:
+ printk(KERN_WARNING "%s: MSR_IA32_MCG_STATUS 0x%llx, nop\n",
+ __FUNCTION__, data);
+ break;
case MSR_IA32_UCODE_REV:
case MSR_IA32_UCODE_WRITE:
case 0x200 ... 0x2ff: /* MTRRs */
@@ -1478,6 +1564,8 @@ static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
void kvm_resched(struct kvm_vcpu *vcpu)
{
+ if (!need_resched())
+ return;
vcpu_put(vcpu);
cond_resched();
vcpu_load(vcpu);
@@ -1502,29 +1590,250 @@ void save_msrs(struct vmx_msr_entry *e, int n)
}
EXPORT_SYMBOL_GPL(save_msrs);
+void kvm_emulate_cpuid(struct kvm_vcpu *vcpu)
+{
+ int i;
+ u32 function;
+ struct kvm_cpuid_entry *e, *best;
+
+ kvm_arch_ops->cache_regs(vcpu);
+ function = vcpu->regs[VCPU_REGS_RAX];
+ vcpu->regs[VCPU_REGS_RAX] = 0;
+ vcpu->regs[VCPU_REGS_RBX] = 0;
+ vcpu->regs[VCPU_REGS_RCX] = 0;
+ vcpu->regs[VCPU_REGS_RDX] = 0;
+ best = NULL;
+ for (i = 0; i < vcpu->cpuid_nent; ++i) {
+ e = &vcpu->cpuid_entries[i];
+ if (e->function == function) {
+ best = e;
+ break;
+ }
+ /*
+ * Both basic or both extended?
+ */
+ if (((e->function ^ function) & 0x80000000) == 0)
+ if (!best || e->function > best->function)
+ best = e;
+ }
+ if (best) {
+ vcpu->regs[VCPU_REGS_RAX] = best->eax;
+ vcpu->regs[VCPU_REGS_RBX] = best->ebx;
+ vcpu->regs[VCPU_REGS_RCX] = best->ecx;
+ vcpu->regs[VCPU_REGS_RDX] = best->edx;
+ }
+ kvm_arch_ops->decache_regs(vcpu);
+ kvm_arch_ops->skip_emulated_instruction(vcpu);
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_cpuid);
+
+static int pio_copy_data(struct kvm_vcpu *vcpu)
+{
+ void *p = vcpu->pio_data;
+ void *q;
+ unsigned bytes;
+ int nr_pages = vcpu->pio.guest_pages[1] ? 2 : 1;
+
+ kvm_arch_ops->vcpu_put(vcpu);
+ q = vmap(vcpu->pio.guest_pages, nr_pages, VM_READ|VM_WRITE,
+ PAGE_KERNEL);
+ if (!q) {
+ kvm_arch_ops->vcpu_load(vcpu);
+ free_pio_guest_pages(vcpu);
+ return -ENOMEM;
+ }
+ q += vcpu->pio.guest_page_offset;
+ bytes = vcpu->pio.size * vcpu->pio.cur_count;
+ if (vcpu->pio.in)
+ memcpy(q, p, bytes);
+ else
+ memcpy(p, q, bytes);
+ q -= vcpu->pio.guest_page_offset;
+ vunmap(q);
+ kvm_arch_ops->vcpu_load(vcpu);
+ free_pio_guest_pages(vcpu);
+ return 0;
+}
+
+static int complete_pio(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pio_request *io = &vcpu->pio;
+ long delta;
+ int r;
+
+ kvm_arch_ops->cache_regs(vcpu);
+
+ if (!io->string) {
+ if (io->in)
+ memcpy(&vcpu->regs[VCPU_REGS_RAX], vcpu->pio_data,
+ io->size);
+ } else {
+ if (io->in) {
+ r = pio_copy_data(vcpu);
+ if (r) {
+ kvm_arch_ops->cache_regs(vcpu);
+ return r;
+ }
+ }
+
+ delta = 1;
+ if (io->rep) {
+ delta *= io->cur_count;
+ /*
+ * The size of the register should really depend on
+ * current address size.
+ */
+ vcpu->regs[VCPU_REGS_RCX] -= delta;
+ }
+ if (io->down)
+ delta = -delta;
+ delta *= io->size;
+ if (io->in)
+ vcpu->regs[VCPU_REGS_RDI] += delta;
+ else
+ vcpu->regs[VCPU_REGS_RSI] += delta;
+ }
+
+ kvm_arch_ops->decache_regs(vcpu);
+
+ io->count -= io->cur_count;
+ io->cur_count = 0;
+
+ if (!io->count)
+ kvm_arch_ops->skip_emulated_instruction(vcpu);
+ return 0;
+}
+
+int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
+ int size, unsigned long count, int string, int down,
+ gva_t address, int rep, unsigned port)
+{
+ unsigned now, in_page;
+ int i;
+ int nr_pages = 1;
+ struct page *page;
+
+ vcpu->run->exit_reason = KVM_EXIT_IO;
+ vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
+ vcpu->run->io.size = size;
+ vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE;
+ vcpu->run->io.count = count;
+ vcpu->run->io.port = port;
+ vcpu->pio.count = count;
+ vcpu->pio.cur_count = count;
+ vcpu->pio.size = size;
+ vcpu->pio.in = in;
+ vcpu->pio.string = string;
+ vcpu->pio.down = down;
+ vcpu->pio.guest_page_offset = offset_in_page(address);
+ vcpu->pio.rep = rep;
+
+ if (!string) {
+ kvm_arch_ops->cache_regs(vcpu);
+ memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
+ kvm_arch_ops->decache_regs(vcpu);
+ return 0;
+ }
+
+ if (!count) {
+ kvm_arch_ops->skip_emulated_instruction(vcpu);
+ return 1;
+ }
+
+ now = min(count, PAGE_SIZE / size);
+
+ if (!down)
+ in_page = PAGE_SIZE - offset_in_page(address);
+ else
+ in_page = offset_in_page(address) + size;
+ now = min(count, (unsigned long)in_page / size);
+ if (!now) {
+ /*
+ * String I/O straddles page boundary. Pin two guest pages
+ * so that we satisfy atomicity constraints. Do just one
+ * transaction to avoid complexity.
+ */
+ nr_pages = 2;
+ now = 1;
+ }
+ if (down) {
+ /*
+ * String I/O in reverse. Yuck. Kill the guest, fix later.
+ */
+ printk(KERN_ERR "kvm: guest string pio down\n");
+ inject_gp(vcpu);
+ return 1;
+ }
+ vcpu->run->io.count = now;
+ vcpu->pio.cur_count = now;
+
+ for (i = 0; i < nr_pages; ++i) {
+ spin_lock(&vcpu->kvm->lock);
+ page = gva_to_page(vcpu, address + i * PAGE_SIZE);
+ if (page)
+ get_page(page);
+ vcpu->pio.guest_pages[i] = page;
+ spin_unlock(&vcpu->kvm->lock);
+ if (!page) {
+ inject_gp(vcpu);
+ free_pio_guest_pages(vcpu);
+ return 1;
+ }
+ }
+
+ if (!vcpu->pio.in)
+ return pio_copy_data(vcpu);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_setup_pio);
+
static int kvm_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
int r;
+ sigset_t sigsaved;
vcpu_load(vcpu);
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
+
/* re-sync apic's tpr */
vcpu->cr8 = kvm_run->cr8;
- if (kvm_run->emulated) {
- kvm_arch_ops->skip_emulated_instruction(vcpu);
- kvm_run->emulated = 0;
+ if (vcpu->pio.cur_count) {
+ r = complete_pio(vcpu);
+ if (r)
+ goto out;
}
- if (kvm_run->mmio_completed) {
+ if (vcpu->mmio_needed) {
memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
vcpu->mmio_read_completed = 1;
+ vcpu->mmio_needed = 0;
+ r = emulate_instruction(vcpu, kvm_run,
+ vcpu->mmio_fault_cr2, 0);
+ if (r == EMULATE_DO_MMIO) {
+ /*
+ * Read-modify-write. Back to userspace.
+ */
+ kvm_run->exit_reason = KVM_EXIT_MMIO;
+ r = 0;
+ goto out;
+ }
}
- vcpu->mmio_needed = 0;
+ if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL) {
+ kvm_arch_ops->cache_regs(vcpu);
+ vcpu->regs[VCPU_REGS_RAX] = kvm_run->hypercall.ret;
+ kvm_arch_ops->decache_regs(vcpu);
+ }
r = kvm_arch_ops->run(vcpu, kvm_run);
+out:
+ if (vcpu->sigset_active)
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+
vcpu_put(vcpu);
return r;
}
@@ -1633,7 +1942,7 @@ static int kvm_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
sregs->gdt.limit = dt.limit;
sregs->gdt.base = dt.base;
- kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ kvm_arch_ops->decache_cr4_guest_bits(vcpu);
sregs->cr0 = vcpu->cr0;
sregs->cr2 = vcpu->cr2;
sregs->cr3 = vcpu->cr3;
@@ -1665,16 +1974,6 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
vcpu_load(vcpu);
- set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
- set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
- set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
- set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
- set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
- set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
-
- set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
- set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
-
dt.limit = sregs->idt.limit;
dt.base = sregs->idt.base;
kvm_arch_ops->set_idt(vcpu, &dt);
@@ -1694,10 +1993,10 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
#endif
vcpu->apic_base = sregs->apic_base;
- kvm_arch_ops->decache_cr0_cr4_guest_bits(vcpu);
+ kvm_arch_ops->decache_cr4_guest_bits(vcpu);
mmu_reset_needed |= vcpu->cr0 != sregs->cr0;
- kvm_arch_ops->set_cr0_no_modeswitch(vcpu, sregs->cr0);
+ kvm_arch_ops->set_cr0(vcpu, sregs->cr0);
mmu_reset_needed |= vcpu->cr4 != sregs->cr4;
kvm_arch_ops->set_cr4(vcpu, sregs->cr4);
@@ -1714,6 +2013,16 @@ static int kvm_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
if (vcpu->irq_pending[i])
__set_bit(i, &vcpu->irq_summary);
+ set_segment(vcpu, &sregs->cs, VCPU_SREG_CS);
+ set_segment(vcpu, &sregs->ds, VCPU_SREG_DS);
+ set_segment(vcpu, &sregs->es, VCPU_SREG_ES);
+ set_segment(vcpu, &sregs->fs, VCPU_SREG_FS);
+ set_segment(vcpu, &sregs->gs, VCPU_SREG_GS);
+ set_segment(vcpu, &sregs->ss, VCPU_SREG_SS);
+
+ set_segment(vcpu, &sregs->tr, VCPU_SREG_TR);
+ set_segment(vcpu, &sregs->ldt, VCPU_SREG_LDTR);
+
vcpu_put(vcpu);
return 0;
@@ -1887,6 +2196,36 @@ static int kvm_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
return r;
}
+static struct page *kvm_vcpu_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type)
+{
+ struct kvm_vcpu *vcpu = vma->vm_file->private_data;
+ unsigned long pgoff;
+ struct page *page;
+
+ *type = VM_FAULT_MINOR;
+ pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+ if (pgoff == 0)
+ page = virt_to_page(vcpu->run);
+ else if (pgoff == KVM_PIO_PAGE_OFFSET)
+ page = virt_to_page(vcpu->pio_data);
+ else
+ return NOPAGE_SIGBUS;
+ get_page(page);
+ return page;
+}
+
+static struct vm_operations_struct kvm_vcpu_vm_ops = {
+ .nopage = kvm_vcpu_nopage,
+};
+
+static int kvm_vcpu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ vma->vm_ops = &kvm_vcpu_vm_ops;
+ return 0;
+}
+
static int kvm_vcpu_release(struct inode *inode, struct file *filp)
{
struct kvm_vcpu *vcpu = filp->private_data;
@@ -1899,6 +2238,7 @@ static struct file_operations kvm_vcpu_fops = {
.release = kvm_vcpu_release,
.unlocked_ioctl = kvm_vcpu_ioctl,
.compat_ioctl = kvm_vcpu_ioctl,
+ .mmap = kvm_vcpu_mmap,
};
/*
@@ -1947,6 +2287,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
{
int r;
struct kvm_vcpu *vcpu;
+ struct page *page;
r = -EINVAL;
if (!valid_vcpu(n))
@@ -1961,9 +2302,22 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
return -EEXIST;
}
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ r = -ENOMEM;
+ if (!page)
+ goto out_unlock;
+ vcpu->run = page_address(page);
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ r = -ENOMEM;
+ if (!page)
+ goto out_free_run;
+ vcpu->pio_data = page_address(page);
+
vcpu->host_fx_image = (char*)ALIGN((hva_t)vcpu->fx_buf,
FX_IMAGE_ALIGN);
vcpu->guest_fx_image = vcpu->host_fx_image + FX_IMAGE_SIZE;
+ vcpu->cr0 = 0x10;
r = kvm_arch_ops->vcpu_create(vcpu);
if (r < 0)
@@ -1990,11 +2344,107 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
out_free_vcpus:
kvm_free_vcpu(vcpu);
+out_free_run:
+ free_page((unsigned long)vcpu->run);
+ vcpu->run = NULL;
+out_unlock:
mutex_unlock(&vcpu->mutex);
out:
return r;
}
+static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
+ struct kvm_cpuid *cpuid,
+ struct kvm_cpuid_entry __user *entries)
+{
+ int r;
+
+ r = -E2BIG;
+ if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
+ goto out;
+ r = -EFAULT;
+ if (copy_from_user(&vcpu->cpuid_entries, entries,
+ cpuid->nent * sizeof(struct kvm_cpuid_entry)))
+ goto out;
+ vcpu->cpuid_nent = cpuid->nent;
+ return 0;
+
+out:
+ return r;
+}
+
+static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
+{
+ if (sigset) {
+ sigdelsetmask(sigset, sigmask(SIGKILL)|sigmask(SIGSTOP));
+ vcpu->sigset_active = 1;
+ vcpu->sigset = *sigset;
+ } else
+ vcpu->sigset_active = 0;
+ return 0;
+}
+
+/*
+ * fxsave fpu state. Taken from x86_64/processor.h. To be killed when
+ * we have asm/x86/processor.h
+ */
+struct fxsave {
+ u16 cwd;
+ u16 swd;
+ u16 twd;
+ u16 fop;
+ u64 rip;
+ u64 rdp;
+ u32 mxcsr;
+ u32 mxcsr_mask;
+ u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
+#ifdef CONFIG_X86_64
+ u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
+#else
+ u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
+#endif
+};
+
+static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+
+ vcpu_load(vcpu);
+
+ memcpy(fpu->fpr, fxsave->st_space, 128);
+ fpu->fcw = fxsave->cwd;
+ fpu->fsw = fxsave->swd;
+ fpu->ftwx = fxsave->twd;
+ fpu->last_opcode = fxsave->fop;
+ fpu->last_ip = fxsave->rip;
+ fpu->last_dp = fxsave->rdp;
+ memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
+static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
+{
+ struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
+
+ vcpu_load(vcpu);
+
+ memcpy(fxsave->st_space, fpu->fpr, 128);
+ fxsave->cwd = fpu->fcw;
+ fxsave->swd = fpu->fsw;
+ fxsave->twd = fpu->ftwx;
+ fxsave->fop = fpu->last_opcode;
+ fxsave->rip = fpu->last_ip;
+ fxsave->rdp = fpu->last_dp;
+ memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
+
+ vcpu_put(vcpu);
+
+ return 0;
+}
+
static long kvm_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -2003,21 +2453,12 @@ static long kvm_vcpu_ioctl(struct file *filp,
int r = -EINVAL;
switch (ioctl) {
- case KVM_RUN: {
- struct kvm_run kvm_run;
-
- r = -EFAULT;
- if (copy_from_user(&kvm_run, argp, sizeof kvm_run))
+ case KVM_RUN:
+ r = -EINVAL;
+ if (arg)
goto out;
- r = kvm_vcpu_ioctl_run(vcpu, &kvm_run);
- if (r < 0 && r != -EINTR)
- goto out;
- if (copy_to_user(argp, &kvm_run, sizeof kvm_run)) {
- r = -EFAULT;
- goto out;
- }
+ r = kvm_vcpu_ioctl_run(vcpu, vcpu->run);
break;
- }
case KVM_GET_REGS: {
struct kvm_regs kvm_regs;
@@ -2113,6 +2554,66 @@ static long kvm_vcpu_ioctl(struct file *filp,
case KVM_SET_MSRS:
r = msr_io(vcpu, argp, do_set_msr, 0);
break;
+ case KVM_SET_CPUID: {
+ struct kvm_cpuid __user *cpuid_arg = argp;
+ struct kvm_cpuid cpuid;
+
+ r = -EFAULT;
+ if (copy_from_user(&cpuid, cpuid_arg, sizeof cpuid))
+ goto out;
+ r = kvm_vcpu_ioctl_set_cpuid(vcpu, &cpuid, cpuid_arg->entries);
+ if (r)
+ goto out;
+ break;
+ }
+ case KVM_SET_SIGNAL_MASK: {
+ struct kvm_signal_mask __user *sigmask_arg = argp;
+ struct kvm_signal_mask kvm_sigmask;
+ sigset_t sigset, *p;
+
+ p = NULL;
+ if (argp) {
+ r = -EFAULT;
+ if (copy_from_user(&kvm_sigmask, argp,
+ sizeof kvm_sigmask))
+ goto out;
+ r = -EINVAL;
+ if (kvm_sigmask.len != sizeof sigset)
+ goto out;
+ r = -EFAULT;
+ if (copy_from_user(&sigset, sigmask_arg->sigset,
+ sizeof sigset))
+ goto out;
+ p = &sigset;
+ }
+ r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
+ break;
+ }
+ case KVM_GET_FPU: {
+ struct kvm_fpu fpu;
+
+ memset(&fpu, 0, sizeof fpu);
+ r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu);
+ if (r)
+ goto out;
+ r = -EFAULT;
+ if (copy_to_user(argp, &fpu, sizeof fpu))
+ goto out;
+ r = 0;
+ break;
+ }
+ case KVM_SET_FPU: {
+ struct kvm_fpu fpu;
+
+ r = -EFAULT;
+ if (copy_from_user(&fpu, argp, sizeof fpu))
+ goto out;
+ r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu);
+ if (r)
+ goto out;
+ r = 0;
+ break;
+ }
default:
;
}
@@ -2155,6 +2656,17 @@ static long kvm_vm_ioctl(struct file *filp,
goto out;
break;
}
+ case KVM_SET_MEMORY_ALIAS: {
+ struct kvm_memory_alias alias;
+
+ r = -EFAULT;
+ if (copy_from_user(&alias, argp, sizeof alias))
+ goto out;
+ r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
+ if (r)
+ goto out;
+ break;
+ }
default:
;
}
@@ -2168,15 +2680,11 @@ static struct page *kvm_vm_nopage(struct vm_area_struct *vma,
{
struct kvm *kvm = vma->vm_file->private_data;
unsigned long pgoff;
- struct kvm_memory_slot *slot;
struct page *page;
*type = VM_FAULT_MINOR;
pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
- slot = gfn_to_memslot(kvm, pgoff);
- if (!slot)
- return NOPAGE_SIGBUS;
- page = gfn_to_page(slot, pgoff);
+ page = gfn_to_page(kvm, pgoff);
if (!page)
return NOPAGE_SIGBUS;
get_page(page);
@@ -2248,13 +2756,19 @@ static long kvm_dev_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
void __user *argp = (void __user *)arg;
- int r = -EINVAL;
+ long r = -EINVAL;
switch (ioctl) {
case KVM_GET_API_VERSION:
+ r = -EINVAL;
+ if (arg)
+ goto out;
r = KVM_API_VERSION;
break;
case KVM_CREATE_VM:
+ r = -EINVAL;
+ if (arg)
+ goto out;
r = kvm_dev_ioctl_create_vm();
break;
case KVM_GET_MSR_INDEX_LIST: {
@@ -2284,6 +2798,18 @@ static long kvm_dev_ioctl(struct file *filp,
r = 0;
break;
}
+ case KVM_CHECK_EXTENSION:
+ /*
+ * No extensions defined at present.
+ */
+ r = 0;
+ break;
+ case KVM_GET_VCPU_MMAP_SIZE:
+ r = -EINVAL;
+ if (arg)
+ goto out;
+ r = 2 * PAGE_SIZE;
+ break;
default:
;
}
@@ -2299,7 +2825,7 @@ static struct file_operations kvm_chardev_ops = {
};
static struct miscdevice kvm_dev = {
- MISC_DYNAMIC_MINOR,
+ KVM_MINOR,
"kvm",
&kvm_chardev_ops,
};
@@ -2363,7 +2889,9 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
switch (val) {
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
cpu);
decache_vcpus_on_cpu(cpu);
@@ -2371,6 +2899,7 @@ static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
NULL, 0, 1);
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
cpu);
smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
@@ -2385,14 +2914,39 @@ static struct notifier_block kvm_cpu_notifier = {
.priority = 20, /* must be > scheduler priority */
};
+static u64 stat_get(void *_offset)
+{
+ unsigned offset = (long)_offset;
+ u64 total = 0;
+ struct kvm *kvm;
+ struct kvm_vcpu *vcpu;
+ int i;
+
+ spin_lock(&kvm_lock);
+ list_for_each_entry(kvm, &vm_list, vm_list)
+ for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+ vcpu = &kvm->vcpus[i];
+ total += *(u32 *)((void *)vcpu + offset);
+ }
+ spin_unlock(&kvm_lock);
+ return total;
+}
+
+static void stat_set(void *offset, u64 val)
+{
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(stat_fops, stat_get, stat_set, "%llu\n");
+
static __init void kvm_init_debug(void)
{
struct kvm_stats_debugfs_item *p;
debugfs_dir = debugfs_create_dir("kvm", NULL);
for (p = debugfs_entries; p->name; ++p)
- p->dentry = debugfs_create_u32(p->name, 0444, debugfs_dir,
- p->data);
+ p->dentry = debugfs_create_file(p->name, 0444, debugfs_dir,
+ (void *)(long)p->offset,
+ &stat_fops);
}
static void kvm_exit_debug(void)
@@ -2522,6 +3076,10 @@ static __init int kvm_init(void)
static struct page *bad_page;
int r;
+ r = kvm_mmu_module_init();
+ if (r)
+ goto out4;
+
r = register_filesystem(&kvm_fs_type);
if (r)
goto out3;
@@ -2550,6 +3108,8 @@ out:
out2:
unregister_filesystem(&kvm_fs_type);
out3:
+ kvm_mmu_module_exit();
+out4:
return r;
}
@@ -2559,6 +3119,7 @@ static __exit void kvm_exit(void)
__free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
mntput(kvmfs_mnt);
unregister_filesystem(&kvm_fs_type);
+ kvm_mmu_module_exit();
}
module_init(kvm_init)
diff --git a/drivers/kvm/kvm_svm.h b/drivers/kvm/kvm_svm.h
index 624f1ca4865..a869983d683 100644
--- a/drivers/kvm/kvm_svm.h
+++ b/drivers/kvm/kvm_svm.h
@@ -9,17 +9,15 @@
#include "svm.h"
#include "kvm.h"
-static const u32 host_save_msrs[] = {
+static const u32 host_save_user_msrs[] = {
#ifdef CONFIG_X86_64
MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
- MSR_FS_BASE, MSR_GS_BASE,
+ MSR_FS_BASE,
#endif
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
- MSR_IA32_DEBUGCTLMSR, /*MSR_IA32_LASTBRANCHFROMIP,
- MSR_IA32_LASTBRANCHTOIP, MSR_IA32_LASTINTFROMIP,MSR_IA32_LASTINTTOIP,*/
};
-#define NR_HOST_SAVE_MSRS ARRAY_SIZE(host_save_msrs)
+#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
#define NUM_DB_REGS 4
struct vcpu_svm {
@@ -28,13 +26,12 @@ struct vcpu_svm {
struct svm_cpu_data *svm_data;
uint64_t asid_generation;
- unsigned long cr0;
- unsigned long cr4;
unsigned long db_regs[NUM_DB_REGS];
u64 next_rip;
- u64 host_msrs[NR_HOST_SAVE_MSRS];
+ u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
+ u64 host_gs_base;
unsigned long host_cr2;
unsigned long host_db_regs[NUM_DB_REGS];
unsigned long host_dr6;
diff --git a/drivers/kvm/kvm_vmx.h b/drivers/kvm/kvm_vmx.h
deleted file mode 100644
index d139f73fb6e..00000000000
--- a/drivers/kvm/kvm_vmx.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __KVM_VMX_H
-#define __KVM_VMX_H
-
-#ifdef CONFIG_X86_64
-/*
- * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
- * mechanism (cpu bug AA24)
- */
-#define NR_BAD_MSRS 2
-#else
-#define NR_BAD_MSRS 0
-#endif
-
-#endif
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index cab26f301ea..e8e228118de 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -52,11 +52,15 @@ static void kvm_mmu_audit(struct kvm_vcpu *vcpu, const char *msg) {}
static int dbg = 1;
#endif
+#ifndef MMU_DEBUG
+#define ASSERT(x) do { } while (0)
+#else
#define ASSERT(x) \
if (!(x)) { \
printk(KERN_WARNING "assertion failed %s:%d: %s\n", \
__FILE__, __LINE__, #x); \
}
+#endif
#define PT64_PT_BITS 9
#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS)
@@ -159,6 +163,9 @@ struct kvm_rmap_desc {
struct kvm_rmap_desc *more;
};
+static struct kmem_cache *pte_chain_cache;
+static struct kmem_cache *rmap_desc_cache;
+
static int is_write_protection(struct kvm_vcpu *vcpu)
{
return vcpu->cr0 & CR0_WP_MASK;
@@ -196,14 +203,15 @@ static int is_rmap_pte(u64 pte)
}
static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
- size_t objsize, int min)
+ struct kmem_cache *base_cache, int min,
+ gfp_t gfp_flags)
{
void *obj;
if (cache->nobjs >= min)
return 0;
while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
- obj = kzalloc(objsize, GFP_NOWAIT);
+ obj = kmem_cache_zalloc(base_cache, gfp_flags);
if (!obj)
return -ENOMEM;
cache->objects[cache->nobjs++] = obj;
@@ -217,20 +225,35 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
kfree(mc->objects[--mc->nobjs]);
}
-static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
+static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
{
int r;
r = mmu_topup_memory_cache(&vcpu->mmu_pte_chain_cache,
- sizeof(struct kvm_pte_chain), 4);
+ pte_chain_cache, 4, gfp_flags);
if (r)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
- sizeof(struct kvm_rmap_desc), 1);
+ rmap_desc_cache, 1, gfp_flags);
out:
return r;
}
+static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu)
+{
+ int r;
+
+ r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
+ if (r < 0) {
+ spin_unlock(&vcpu->kvm->lock);
+ kvm_arch_ops->vcpu_put(vcpu);
+ r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
+ kvm_arch_ops->vcpu_load(vcpu);
+ spin_lock(&vcpu->kvm->lock);
+ }
+ return r;
+}
+
static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
@@ -390,13 +413,11 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
{
struct kvm *kvm = vcpu->kvm;
struct page *page;
- struct kvm_memory_slot *slot;
struct kvm_rmap_desc *desc;
u64 *spte;
- slot = gfn_to_memslot(kvm, gfn);
- BUG_ON(!slot);
- page = gfn_to_page(slot, gfn);
+ page = gfn_to_page(kvm, gfn);
+ BUG_ON(!page);
while (page_private(page)) {
if (!(page_private(page) & 1))
@@ -417,6 +438,7 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
}
}
+#ifdef MMU_DEBUG
static int is_empty_shadow_page(hpa_t page_hpa)
{
u64 *pos;
@@ -431,15 +453,15 @@ static int is_empty_shadow_page(hpa_t page_hpa)
}
return 1;
}
+#endif
static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa)
{
struct kvm_mmu_page *page_head = page_header(page_hpa);
ASSERT(is_empty_shadow_page(page_hpa));
- list_del(&page_head->link);
page_head->page_hpa = page_hpa;
- list_add(&page_head->link, &vcpu->free_pages);
+ list_move(&page_head->link, &vcpu->free_pages);
++vcpu->kvm->n_free_mmu_pages;
}
@@ -457,11 +479,9 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
return NULL;
page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link);
- list_del(&page->link);
- list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+ list_move(&page->link, &vcpu->kvm->active_mmu_pages);
ASSERT(is_empty_shadow_page(page->page_hpa));
page->slot_bitmap = 0;
- page->global = 1;
page->multimapped = 0;
page->parent_pte = parent_pte;
--vcpu->kvm->n_free_mmu_pages;
@@ -569,6 +589,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
gva_t gaddr,
unsigned level,
int metaphysical,
+ unsigned hugepage_access,
u64 *parent_pte)
{
union kvm_mmu_page_role role;
@@ -582,6 +603,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
role.glevels = vcpu->mmu.root_level;
role.level = level;
role.metaphysical = metaphysical;
+ role.hugepage_access = hugepage_access;
if (vcpu->mmu.root_level <= PT32_ROOT_LEVEL) {
quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level));
quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1;
@@ -669,10 +691,8 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
if (!page->root_count) {
hlist_del(&page->hash_link);
kvm_mmu_free_page(vcpu, page->page_hpa);
- } else {
- list_del(&page->link);
- list_add(&page->link, &vcpu->kvm->active_mmu_pages);
- }
+ } else
+ list_move(&page->link, &vcpu->kvm->active_mmu_pages);
}
static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -714,14 +734,12 @@ hpa_t safe_gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa)
{
- struct kvm_memory_slot *slot;
struct page *page;
ASSERT((gpa & HPA_ERR_MASK) == 0);
- slot = gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT);
- if (!slot)
+ page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
+ if (!page)
return gpa | HPA_ERR_MASK;
- page = gfn_to_page(slot, gpa >> PAGE_SHIFT);
return ((hpa_t)page_to_pfn(page) << PAGE_SHIFT)
| (gpa & (PAGE_SIZE-1));
}
@@ -735,6 +753,15 @@ hpa_t gva_to_hpa(struct kvm_vcpu *vcpu, gva_t gva)
return gpa_to_hpa(vcpu, gpa);
}
+struct page *gva_to_page(struct kvm_vcpu *vcpu, gva_t gva)
+{
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
+
+ if (gpa == UNMAPPED_GVA)
+ return NULL;
+ return pfn_to_page(gpa_to_hpa(vcpu, gpa) >> PAGE_SHIFT);
+}
+
static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
{
}
@@ -772,7 +799,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
>> PAGE_SHIFT;
new_table = kvm_mmu_get_page(vcpu, pseudo_gfn,
v, level - 1,
- 1, &table[index]);
+ 1, 0, &table[index]);
if (!new_table) {
pgprintk("nonpaging_map: ENOMEM\n");
return -ENOMEM;
@@ -804,10 +831,12 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
for (i = 0; i < 4; ++i) {
hpa_t root = vcpu->mmu.pae_root[i];
- ASSERT(VALID_PAGE(root));
- root &= PT64_BASE_ADDR_MASK;
- page = page_header(root);
- --page->root_count;
+ if (root) {
+ ASSERT(VALID_PAGE(root));
+ root &= PT64_BASE_ADDR_MASK;
+ page = page_header(root);
+ --page->root_count;
+ }
vcpu->mmu.pae_root[i] = INVALID_PAGE;
}
vcpu->mmu.root_hpa = INVALID_PAGE;
@@ -827,7 +856,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
ASSERT(!VALID_PAGE(root));
page = kvm_mmu_get_page(vcpu, root_gfn, 0,
- PT64_ROOT_LEVEL, 0, NULL);
+ PT64_ROOT_LEVEL, 0, 0, NULL);
root = page->page_hpa;
++page->root_count;
vcpu->mmu.root_hpa = root;
@@ -838,13 +867,17 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
hpa_t root = vcpu->mmu.pae_root[i];
ASSERT(!VALID_PAGE(root));
- if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL)
+ if (vcpu->mmu.root_level == PT32E_ROOT_LEVEL) {
+ if (!is_present_pte(vcpu->pdptrs[i])) {
+ vcpu->mmu.pae_root[i] = 0;
+ continue;
+ }
root_gfn = vcpu->pdptrs[i] >> PAGE_SHIFT;
- else if (vcpu->mmu.root_level == 0)
+ } else if (vcpu->mmu.root_level == 0)
root_gfn = 0;
page = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
PT32_ROOT_LEVEL, !is_paging(vcpu),
- NULL);
+ 0, NULL);
root = page->page_hpa;
++page->root_count;
vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
@@ -903,7 +936,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
static void kvm_mmu_flush_tlb(struct kvm_vcpu *vcpu)
{
- ++kvm_stat.tlb_flush;
+ ++vcpu->stat.tlb_flush;
kvm_arch_ops->tlb_flush(vcpu);
}
@@ -918,11 +951,6 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu)
kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
}
-static void mark_pagetable_nonglobal(void *shadow_pte)
-{
- page_header(__pa(shadow_pte))->global = 0;
-}
-
static inline void set_pte_common(struct kvm_vcpu *vcpu,
u64 *shadow_pte,
gpa_t gaddr,
@@ -940,9 +968,6 @@ static inline void set_pte_common(struct kvm_vcpu *vcpu,
*shadow_pte |= access_bits;
- if (!(*shadow_pte & PT_GLOBAL_MASK))
- mark_pagetable_nonglobal(shadow_pte);
-
if (is_error_hpa(paddr)) {
*shadow_pte |= gaddr;
*shadow_pte |= PT_SHADOW_IO_MARK;
@@ -1316,6 +1341,51 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
}
}
+void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+{
+ destroy_kvm_mmu(vcpu);
+
+ while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
+ struct kvm_mmu_page *page;
+
+ page = container_of(vcpu->kvm->active_mmu_pages.next,
+ struct kvm_mmu_page, link);
+ kvm_mmu_zap_page(vcpu, page);
+ }
+
+ mmu_free_memory_caches(vcpu);
+ kvm_arch_ops->tlb_flush(vcpu);
+ init_kvm_mmu(vcpu);
+}
+
+void kvm_mmu_module_exit(void)
+{
+ if (pte_chain_cache)
+ kmem_cache_destroy(pte_chain_cache);
+ if (rmap_desc_cache)
+ kmem_cache_destroy(rmap_desc_cache);
+}
+
+int kvm_mmu_module_init(void)
+{
+ pte_chain_cache = kmem_cache_create("kvm_pte_chain",
+ sizeof(struct kvm_pte_chain),
+ 0, 0, NULL, NULL);
+ if (!pte_chain_cache)
+ goto nomem;
+ rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
+ sizeof(struct kvm_rmap_desc),
+ 0, 0, NULL, NULL);
+ if (!rmap_desc_cache)
+ goto nomem;
+
+ return 0;
+
+nomem:
+ kvm_mmu_module_exit();
+ return -ENOMEM;
+}
+
#ifdef AUDIT
static const char *audit_msg;
@@ -1338,7 +1408,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
for (i = 0; i < PT64_ENT_PER_PAGE; ++i, va += va_delta) {
u64 ent = pt[i];
- if (!ent & PT_PRESENT_MASK)
+ if (!(ent & PT_PRESENT_MASK))
continue;
va = canonicalize(va);
@@ -1360,7 +1430,7 @@ static void audit_mappings_page(struct kvm_vcpu *vcpu, u64 page_pte,
static void audit_mappings(struct kvm_vcpu *vcpu)
{
- int i;
+ unsigned i;
if (vcpu->mmu.root_level == 4)
audit_mappings_page(vcpu, vcpu->mmu.root_hpa, 0, 4);
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index f3bcee90465..73ffbffb109 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -148,8 +148,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker,
break;
}
- if (walker->level != 3 || is_long_mode(vcpu))
- walker->inherited_ar &= walker->table[index];
+ walker->inherited_ar &= walker->table[index];
table_gfn = (*ptep & PT_BASE_ADDR_MASK) >> PAGE_SHIFT;
paddr = safe_gpa_to_hpa(vcpu, *ptep & PT_BASE_ADDR_MASK);
kunmap_atomic(walker->table, KM_USER0);
@@ -248,6 +247,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
u64 shadow_pte;
int metaphysical;
gfn_t table_gfn;
+ unsigned hugepage_access = 0;
if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
if (level == PT_PAGE_TABLE_LEVEL)
@@ -277,6 +277,9 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
if (level - 1 == PT_PAGE_TABLE_LEVEL
&& walker->level == PT_DIRECTORY_LEVEL) {
metaphysical = 1;
+ hugepage_access = *guest_ent;
+ hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+ hugepage_access >>= PT_WRITABLE_SHIFT;
table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
>> PAGE_SHIFT;
} else {
@@ -284,7 +287,8 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
table_gfn = walker->table_gfn[level - 2];
}
shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
- metaphysical, shadow_ent);
+ metaphysical, hugepage_access,
+ shadow_ent);
shadow_addr = shadow_page->page_hpa;
shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK
| PT_WRITABLE_MASK | PT_USER_MASK;
@@ -444,7 +448,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
if (is_io_pte(*shadow_pte))
return 1;
- ++kvm_stat.pf_fixed;
+ ++vcpu->stat.pf_fixed;
kvm_mmu_audit(vcpu, "post page fault (fixed)");
return write_pt;
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index 3d8ea7ac2ec..9c15f32eea1 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -44,6 +44,10 @@ MODULE_LICENSE("GPL");
#define KVM_EFER_LMA (1 << 10)
#define KVM_EFER_LME (1 << 8)
+#define SVM_FEATURE_NPT (1 << 0)
+#define SVM_FEATURE_LBRV (1 << 1)
+#define SVM_DEATURE_SVML (1 << 2)
+
unsigned long iopm_base;
unsigned long msrpm_base;
@@ -59,15 +63,16 @@ struct kvm_ldttss_desc {
struct svm_cpu_data {
int cpu;
- uint64_t asid_generation;
- uint32_t max_asid;
- uint32_t next_asid;
+ u64 asid_generation;
+ u32 max_asid;
+ u32 next_asid;
struct kvm_ldttss_desc *tss_desc;
struct page *save_area;
};
static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
+static uint32_t svm_features;
struct svm_init_data {
int cpu;
@@ -82,6 +87,11 @@ static u32 msrpm_ranges[] = {0, 0xc0000000, 0xc0010000};
#define MAX_INST_SIZE 15
+static inline u32 svm_has(u32 feat)
+{
+ return svm_features & feat;
+}
+
static unsigned get_addr_size(struct kvm_vcpu *vcpu)
{
struct vmcb_save_area *sa = &vcpu->svm->vmcb->save;
@@ -203,13 +213,6 @@ static void inject_ud(struct kvm_vcpu *vcpu)
UD_VECTOR;
}
-static void inject_db(struct kvm_vcpu *vcpu)
-{
- vcpu->svm->vmcb->control.event_inj = SVM_EVTINJ_VALID |
- SVM_EVTINJ_TYPE_EXEPT |
- DB_VECTOR;
-}
-
static int is_page_fault(uint32_t info)
{
info &= SVM_EVTINJ_VEC_MASK | SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
@@ -309,6 +312,7 @@ static void svm_hardware_enable(void *garbage)
svm_data->asid_generation = 1;
svm_data->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
svm_data->next_asid = svm_data->max_asid + 1;
+ svm_features = cpuid_edx(SVM_CPUID_FUNC);
asm volatile ( "sgdt %0" : "=m"(gdt_descr) );
gdt = (struct desc_struct *)gdt_descr.address;
@@ -459,7 +463,6 @@ static void init_vmcb(struct vmcb *vmcb)
{
struct vmcb_control_area *control = &vmcb->control;
struct vmcb_save_area *save = &vmcb->save;
- u64 tsc;
control->intercept_cr_read = INTERCEPT_CR0_MASK |
INTERCEPT_CR3_MASK |
@@ -511,12 +514,13 @@ static void init_vmcb(struct vmcb *vmcb)
(1ULL << INTERCEPT_VMSAVE) |
(1ULL << INTERCEPT_STGI) |
(1ULL << INTERCEPT_CLGI) |
- (1ULL << INTERCEPT_SKINIT);
+ (1ULL << INTERCEPT_SKINIT) |
+ (1ULL << INTERCEPT_MONITOR) |
+ (1ULL << INTERCEPT_MWAIT);
control->iopm_base_pa = iopm_base;
control->msrpm_base_pa = msrpm_base;
- rdtscll(tsc);
- control->tsc_offset = -tsc;
+ control->tsc_offset = 0;
control->int_ctl = V_INTR_MASKING_MASK;
init_seg(&save->es);
@@ -576,12 +580,15 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
vcpu->svm->vmcb = page_address(page);
memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
- vcpu->svm->cr0 = 0x00000010;
vcpu->svm->asid_generation = 0;
memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
init_vmcb(vcpu->svm->vmcb);
fx_init(vcpu);
+ vcpu->fpu_active = 1;
+ vcpu->apic_base = 0xfee00000 |
+ /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
+ MSR_IA32_APICBASE_ENABLE;
return 0;
@@ -602,11 +609,34 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
static void svm_vcpu_load(struct kvm_vcpu *vcpu)
{
- get_cpu();
+ int cpu, i;
+
+ cpu = get_cpu();
+ if (unlikely(cpu != vcpu->cpu)) {
+ u64 tsc_this, delta;
+
+ /*
+ * Make sure that the guest sees a monotonically
+ * increasing TSC.
+ */
+ rdtscll(tsc_this);
+ delta = vcpu->host_tsc - tsc_this;
+ vcpu->svm->vmcb->control.tsc_offset += delta;
+ vcpu->cpu = cpu;
+ }
+
+ for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
+ rdmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
{
+ int i;
+
+ for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
+ wrmsrl(host_save_user_msrs[i], vcpu->svm->host_user_msrs[i]);
+
+ rdtscll(vcpu->host_tsc);
put_cpu();
}
@@ -714,7 +744,7 @@ static void svm_set_gdt(struct kvm_vcpu *vcpu, struct descriptor_table *dt)
vcpu->svm->vmcb->save.gdtr.base = dt->base ;
}
-static void svm_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
+static void svm_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
{
}
@@ -733,9 +763,15 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
}
#endif
- vcpu->svm->cr0 = cr0;
- vcpu->svm->vmcb->save.cr0 = cr0 | CR0_PG_MASK | CR0_WP_MASK;
+ if ((vcpu->cr0 & CR0_TS_MASK) && !(cr0 & CR0_TS_MASK)) {
+ vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+ vcpu->fpu_active = 1;
+ }
+
vcpu->cr0 = cr0;
+ cr0 |= CR0_PG_MASK | CR0_WP_MASK;
+ cr0 &= ~(CR0_CD_MASK | CR0_NW_MASK);
+ vcpu->svm->vmcb->save.cr0 = cr0;
}
static void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -785,18 +821,16 @@ static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
static void load_host_msrs(struct kvm_vcpu *vcpu)
{
- int i;
-
- for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
- wrmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+#ifdef CONFIG_X86_64
+ wrmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+#endif
}
static void save_host_msrs(struct kvm_vcpu *vcpu)
{
- int i;
-
- for ( i = 0; i < NR_HOST_SAVE_MSRS; i++)
- rdmsrl(host_save_msrs[i], vcpu->svm->host_msrs[i]);
+#ifdef CONFIG_X86_64
+ rdmsrl(MSR_GS_BASE, vcpu->svm->host_gs_base);
+#endif
}
static void new_asid(struct kvm_vcpu *vcpu, struct svm_cpu_data *svm_data)
@@ -890,7 +924,7 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
case EMULATE_DONE:
return 1;
case EMULATE_DO_MMIO:
- ++kvm_stat.mmio_exits;
+ ++vcpu->stat.mmio_exits;
kvm_run->exit_reason = KVM_EXIT_MMIO;
return 0;
case EMULATE_FAIL:
@@ -904,6 +938,16 @@ static int pf_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
+static int nm_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
+{
+ vcpu->svm->vmcb->control.intercept_exceptions &= ~(1 << NM_VECTOR);
+ if (!(vcpu->cr0 & CR0_TS_MASK))
+ vcpu->svm->vmcb->save.cr0 &= ~CR0_TS_MASK;
+ vcpu->fpu_active = 1;
+
+ return 1;
+}
+
static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
/*
@@ -981,7 +1025,7 @@ static int io_get_override(struct kvm_vcpu *vcpu,
return 0;
}
-static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address)
+static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, gva_t *address)
{
unsigned long addr_mask;
unsigned long *reg;
@@ -1025,38 +1069,38 @@ static unsigned long io_adress(struct kvm_vcpu *vcpu, int ins, u64 *address)
static int io_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u32 io_info = vcpu->svm->vmcb->control.exit_info_1; //address size bug?
- int _in = io_info & SVM_IOIO_TYPE_MASK;
+ int size, down, in, string, rep;
+ unsigned port;
+ unsigned long count;
+ gva_t address = 0;
- ++kvm_stat.io_exits;
+ ++vcpu->stat.io_exits;
vcpu->svm->next_rip = vcpu->svm->vmcb->control.exit_info_2;
- kvm_run->exit_reason = KVM_EXIT_IO;
- kvm_run->io.port = io_info >> 16;
- kvm_run->io.direction = (_in) ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
- kvm_run->io.size = ((io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT);
- kvm_run->io.string = (io_info & SVM_IOIO_STR_MASK) != 0;
- kvm_run->io.rep = (io_info & SVM_IOIO_REP_MASK) != 0;
+ in = (io_info & SVM_IOIO_TYPE_MASK) != 0;
+ port = io_info >> 16;
+ size = (io_info & SVM_IOIO_SIZE_MASK) >> SVM_IOIO_SIZE_SHIFT;
+ string = (io_info & SVM_IOIO_STR_MASK) != 0;
+ rep = (io_info & SVM_IOIO_REP_MASK) != 0;
+ count = 1;
+ down = (vcpu->svm->vmcb->save.rflags & X86_EFLAGS_DF) != 0;
- if (kvm_run->io.string) {
+ if (string) {
unsigned addr_mask;
- addr_mask = io_adress(vcpu, _in, &kvm_run->io.address);
+ addr_mask = io_adress(vcpu, in, &address);
if (!addr_mask) {
printk(KERN_DEBUG "%s: get io address failed\n",
__FUNCTION__);
return 1;
}
- if (kvm_run->io.rep) {
- kvm_run->io.count
- = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
- kvm_run->io.string_down = (vcpu->svm->vmcb->save.rflags
- & X86_EFLAGS_DF) != 0;
- }
- } else
- kvm_run->io.value = vcpu->svm->vmcb->save.rax;
- return 0;
+ if (rep)
+ count = vcpu->regs[VCPU_REGS_RCX] & addr_mask;
+ }
+ return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
+ address, rep, port);
}
static int nop_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1072,13 +1116,14 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
kvm_run->exit_reason = KVM_EXIT_HLT;
- ++kvm_stat.halt_exits;
+ ++vcpu->stat.halt_exits;
return 0;
}
static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- vcpu->svm->vmcb->save.rip += 3;
+ vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 3;
+ skip_emulated_instruction(vcpu);
return kvm_hypercall(vcpu, kvm_run);
}
@@ -1098,8 +1143,8 @@ static int task_switch_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_r
static int cpuid_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 2;
- kvm_run->exit_reason = KVM_EXIT_CPUID;
- return 0;
+ kvm_emulate_cpuid(vcpu);
+ return 1;
}
static int emulate_on_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1239,7 +1284,7 @@ static int interrupt_window_interception(struct kvm_vcpu *vcpu,
*/
if (kvm_run->request_interrupt_window &&
!vcpu->irq_summary) {
- ++kvm_stat.irq_window_exits;
+ ++vcpu->stat.irq_window_exits;
kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
return 0;
}
@@ -1267,6 +1312,7 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
[SVM_EXIT_WRITE_DR5] = emulate_on_interception,
[SVM_EXIT_WRITE_DR7] = emulate_on_interception,
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
+ [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception,
[SVM_EXIT_INTR] = nop_on_interception,
[SVM_EXIT_NMI] = nop_on_interception,
[SVM_EXIT_SMI] = nop_on_interception,
@@ -1288,6 +1334,8 @@ static int (*svm_exit_handlers[])(struct kvm_vcpu *vcpu,
[SVM_EXIT_STGI] = invalid_op_interception,
[SVM_EXIT_CLGI] = invalid_op_interception,
[SVM_EXIT_SKINIT] = invalid_op_interception,
+ [SVM_EXIT_MONITOR] = invalid_op_interception,
+ [SVM_EXIT_MWAIT] = invalid_op_interception,
};
@@ -1295,8 +1343,6 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u32 exit_code = vcpu->svm->vmcb->control.exit_code;
- kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
-
if (is_external_interrupt(vcpu->svm->vmcb->control.exit_int_info) &&
exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR)
printk(KERN_ERR "%s: unexpected exit_ini_info 0x%x "
@@ -1307,12 +1353,7 @@ static int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
|| svm_exit_handlers[exit_code] == 0) {
kvm_run->exit_reason = KVM_EXIT_UNKNOWN;
- printk(KERN_ERR "%s: 0x%x @ 0x%llx cr0 0x%lx rflags 0x%llx\n",
- __FUNCTION__,
- exit_code,
- vcpu->svm->vmcb->save.rip,
- vcpu->cr0,
- vcpu->svm->vmcb->save.rflags);
+ kvm_run->hw.hardware_exit_reason = exit_code;
return 0;
}
@@ -1461,8 +1502,10 @@ again:
load_db_regs(vcpu->svm->db_regs);
}
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
+ if (vcpu->fpu_active) {
+ fx_save(vcpu->host_fx_image);
+ fx_restore(vcpu->guest_fx_image);
+ }
asm volatile (
#ifdef CONFIG_X86_64
@@ -1573,8 +1616,10 @@ again:
#endif
: "cc", "memory" );
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
+ if (vcpu->fpu_active) {
+ fx_save(vcpu->guest_fx_image);
+ fx_restore(vcpu->host_fx_image);
+ }
if ((vcpu->svm->vmcb->save.dr7 & 0xff))
load_db_regs(vcpu->svm->host_db_regs);
@@ -1606,8 +1651,9 @@ again:
vcpu->svm->next_rip = 0;
if (vcpu->svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
- kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
- kvm_run->exit_reason = vcpu->svm->vmcb->control.exit_code;
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ kvm_run->fail_entry.hardware_entry_failure_reason
+ = vcpu->svm->vmcb->control.exit_code;
post_kvm_run_save(vcpu, kvm_run);
return 0;
}
@@ -1615,14 +1661,16 @@ again:
r = handle_exit(vcpu, kvm_run);
if (r > 0) {
if (signal_pending(current)) {
- ++kvm_stat.signal_exits;
+ ++vcpu->stat.signal_exits;
post_kvm_run_save(vcpu, kvm_run);
+ kvm_run->exit_reason = KVM_EXIT_INTR;
return -EINTR;
}
if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- ++kvm_stat.request_irq_exits;
+ ++vcpu->stat.request_irq_exits;
post_kvm_run_save(vcpu, kvm_run);
+ kvm_run->exit_reason = KVM_EXIT_INTR;
return -EINTR;
}
kvm_resched(vcpu);
@@ -1641,6 +1689,12 @@ static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{
vcpu->svm->vmcb->save.cr3 = root;
force_new_asid(vcpu);
+
+ if (vcpu->fpu_active) {
+ vcpu->svm->vmcb->control.intercept_exceptions |= (1 << NM_VECTOR);
+ vcpu->svm->vmcb->save.cr0 |= CR0_TS_MASK;
+ vcpu->fpu_active = 0;
+ }
}
static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
@@ -1649,7 +1703,7 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
{
uint32_t exit_int_info = vcpu->svm->vmcb->control.exit_int_info;
- ++kvm_stat.pf_guest;
+ ++vcpu->stat.pf_guest;
if (is_page_fault(exit_int_info)) {
@@ -1709,9 +1763,8 @@ static struct kvm_arch_ops svm_arch_ops = {
.get_segment = svm_get_segment,
.set_segment = svm_set_segment,
.get_cs_db_l_bits = svm_get_cs_db_l_bits,
- .decache_cr0_cr4_guest_bits = svm_decache_cr0_cr4_guest_bits,
+ .decache_cr4_guest_bits = svm_decache_cr4_guest_bits,
.set_cr0 = svm_set_cr0,
- .set_cr0_no_modeswitch = svm_set_cr0,
.set_cr3 = svm_set_cr3,
.set_cr4 = svm_set_cr4,
.set_efer = svm_set_efer,
diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h
index df731c3fb58..5e93814400c 100644
--- a/drivers/kvm/svm.h
+++ b/drivers/kvm/svm.h
@@ -44,6 +44,9 @@ enum {
INTERCEPT_RDTSCP,
INTERCEPT_ICEBP,
INTERCEPT_WBINVD,
+ INTERCEPT_MONITOR,
+ INTERCEPT_MWAIT,
+ INTERCEPT_MWAIT_COND,
};
@@ -298,6 +301,9 @@ struct __attribute__ ((__packed__)) vmcb {
#define SVM_EXIT_RDTSCP 0x087
#define SVM_EXIT_ICEBP 0x088
#define SVM_EXIT_WBINVD 0x089
+#define SVM_EXIT_MONITOR 0x08a
+#define SVM_EXIT_MWAIT 0x08b
+#define SVM_EXIT_MWAIT_COND 0x08c
#define SVM_EXIT_NPF 0x400
#define SVM_EXIT_ERR -1
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index fbbf9d6b299..724db0027f0 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -17,7 +17,6 @@
#include "kvm.h"
#include "vmx.h"
-#include "kvm_vmx.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -70,6 +69,10 @@ static struct kvm_vmx_segment_field {
VMX_SEGMENT_FIELD(LDTR),
};
+/*
+ * Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
+ * away by decrementing the array size.
+ */
static const u32 vmx_msr_index[] = {
#ifdef CONFIG_X86_64
MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, MSR_KERNEL_GS_BASE,
@@ -78,6 +81,19 @@ static const u32 vmx_msr_index[] = {
};
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
+#ifdef CONFIG_X86_64
+static unsigned msr_offset_kernel_gs_base;
+#define NR_64BIT_MSRS 4
+/*
+ * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
+ * mechanism (cpu bug AA24)
+ */
+#define NR_BAD_MSRS 2
+#else
+#define NR_64BIT_MSRS 0
+#define NR_BAD_MSRS 0
+#endif
+
static inline int is_page_fault(u32 intr_info)
{
return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
@@ -85,6 +101,13 @@ static inline int is_page_fault(u32 intr_info)
(INTR_TYPE_EXCEPTION | PF_VECTOR | INTR_INFO_VALID_MASK);
}
+static inline int is_no_device(u32 intr_info)
+{
+ return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK |
+ INTR_INFO_VALID_MASK)) ==
+ (INTR_TYPE_EXCEPTION | NM_VECTOR | INTR_INFO_VALID_MASK);
+}
+
static inline int is_external_interrupt(u32 intr_info)
{
return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
@@ -200,6 +223,16 @@ static void vmcs_write64(unsigned long field, u64 value)
#endif
}
+static void vmcs_clear_bits(unsigned long field, u32 mask)
+{
+ vmcs_writel(field, vmcs_readl(field) & ~mask);
+}
+
+static void vmcs_set_bits(unsigned long field, u32 mask)
+{
+ vmcs_writel(field, vmcs_readl(field) | mask);
+}
+
/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
@@ -297,6 +330,44 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
}
/*
+ * Set up the vmcs to automatically save and restore system
+ * msrs. Don't touch the 64-bit msrs if the guest is in legacy
+ * mode, as fiddling with msrs is very expensive.
+ */
+static void setup_msrs(struct kvm_vcpu *vcpu)
+{
+ int nr_skip, nr_good_msrs;
+
+ if (is_long_mode(vcpu))
+ nr_skip = NR_BAD_MSRS;
+ else
+ nr_skip = NR_64BIT_MSRS;
+ nr_good_msrs = vcpu->nmsrs - nr_skip;
+
+ /*
+ * MSR_K6_STAR is only needed on long mode guests, and only
+ * if efer.sce is enabled.
+ */
+ if (find_msr_entry(vcpu, MSR_K6_STAR)) {
+ --nr_good_msrs;
+#ifdef CONFIG_X86_64
+ if (is_long_mode(vcpu) && (vcpu->shadow_efer & EFER_SCE))
+ ++nr_good_msrs;
+#endif
+ }
+
+ vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
+ virt_to_phys(vcpu->guest_msrs + nr_skip));
+ vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
+ virt_to_phys(vcpu->guest_msrs + nr_skip));
+ vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
+ virt_to_phys(vcpu->host_msrs + nr_skip));
+ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
+ vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+ vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+}
+
+/*
* reads and returns guest's timestamp counter "register"
* guest_tsc = host_tsc + tsc_offset -- 21.3
*/
@@ -712,6 +783,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_CS_AR_BYTES, 0xf3);
vmcs_write32(GUEST_CS_LIMIT, 0xffff);
+ if (vmcs_readl(GUEST_CS_BASE) == 0xffff0000)
+ vmcs_writel(GUEST_CS_BASE, 0xf0000);
vmcs_write16(GUEST_CS_SELECTOR, vmcs_readl(GUEST_CS_BASE) >> 4);
fix_rmode_seg(VCPU_SREG_ES, &vcpu->rmode.es);
@@ -754,11 +827,8 @@ static void exit_lmode(struct kvm_vcpu *vcpu)
#endif
-static void vmx_decache_cr0_cr4_guest_bits(struct kvm_vcpu *vcpu)
+static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
{
- vcpu->cr0 &= KVM_GUEST_CR0_MASK;
- vcpu->cr0 |= vmcs_readl(GUEST_CR0) & ~KVM_GUEST_CR0_MASK;
-
vcpu->cr4 &= KVM_GUEST_CR4_MASK;
vcpu->cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK;
}
@@ -780,22 +850,11 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
#endif
- vmcs_writel(CR0_READ_SHADOW, cr0);
- vmcs_writel(GUEST_CR0,
- (cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
- vcpu->cr0 = cr0;
-}
-
-/*
- * Used when restoring the VM to avoid corrupting segment registers
- */
-static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
-{
- if (!vcpu->rmode.active && !(cr0 & CR0_PE_MASK))
- enter_rmode(vcpu);
+ if (!(cr0 & CR0_TS_MASK)) {
+ vcpu->fpu_active = 1;
+ vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK);
+ }
- vcpu->rmode.active = ((cr0 & CR0_PE_MASK) == 0);
- update_exception_bitmap(vcpu);
vmcs_writel(CR0_READ_SHADOW, cr0);
vmcs_writel(GUEST_CR0,
(cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
@@ -805,6 +864,12 @@ static void vmx_set_cr0_no_modeswitch(struct kvm_vcpu *vcpu, unsigned long cr0)
static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
vmcs_writel(GUEST_CR3, cr3);
+
+ if (!(vcpu->cr0 & CR0_TS_MASK)) {
+ vcpu->fpu_active = 0;
+ vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+ }
}
static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -835,6 +900,7 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
msr->data = efer & ~EFER_LME;
}
+ setup_msrs(vcpu);
}
#endif
@@ -878,7 +944,14 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
vmcs_writel(sf->base, var->base);
vmcs_write32(sf->limit, var->limit);
vmcs_write16(sf->selector, var->selector);
- if (var->unusable)
+ if (vcpu->rmode.active && var->s) {
+ /*
+ * Hack real-mode segments into vm86 compatibility.
+ */
+ if (var->base == 0xffff0000 && var->selector == 0xf000)
+ vmcs_writel(sf->base, 0xf0000);
+ ar = 0xf3;
+ } else if (var->unusable)
ar = 1 << 16;
else {
ar = var->type & 15;
@@ -933,9 +1006,9 @@ static int init_rmode_tss(struct kvm* kvm)
gfn_t fn = rmode_tss_base(kvm) >> PAGE_SHIFT;
char *page;
- p1 = _gfn_to_page(kvm, fn++);
- p2 = _gfn_to_page(kvm, fn++);
- p3 = _gfn_to_page(kvm, fn);
+ p1 = gfn_to_page(kvm, fn++);
+ p2 = gfn_to_page(kvm, fn++);
+ p3 = gfn_to_page(kvm, fn);
if (!p1 || !p2 || !p3) {
kvm_printf(kvm,"%s: gfn_to_page failed\n", __FUNCTION__);
@@ -991,7 +1064,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
struct descriptor_table dt;
int i;
int ret = 0;
- int nr_good_msrs;
extern asmlinkage void kvm_vmx_return(void);
if (!init_rmode_tss(vcpu->kvm)) {
@@ -1136,23 +1208,17 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->host_msrs[j].reserved = 0;
vcpu->host_msrs[j].data = data;
vcpu->guest_msrs[j] = vcpu->host_msrs[j];
+#ifdef CONFIG_X86_64
+ if (index == MSR_KERNEL_GS_BASE)
+ msr_offset_kernel_gs_base = j;
+#endif
++vcpu->nmsrs;
}
- printk(KERN_DEBUG "kvm: msrs: %d\n", vcpu->nmsrs);
- nr_good_msrs = vcpu->nmsrs - NR_BAD_MSRS;
- vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
- virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
- vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
- virt_to_phys(vcpu->guest_msrs + NR_BAD_MSRS));
- vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
- virt_to_phys(vcpu->host_msrs + NR_BAD_MSRS));
+ setup_msrs(vcpu);
+
vmcs_write32_fixedbits(MSR_IA32_VMX_EXIT_CTLS, VM_EXIT_CONTROLS,
(HOST_IS_64 << 9)); /* 22.2,1, 20.7.1 */
- vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
- vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
- vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
-
/* 22.2.1, 20.8.1 */
vmcs_write32_fixedbits(MSR_IA32_VMX_ENTRY_CTLS,
@@ -1164,7 +1230,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vmcs_writel(TPR_THRESHOLD, 0);
#endif
- vmcs_writel(CR0_GUEST_HOST_MASK, KVM_GUEST_CR0_MASK);
+ vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
vcpu->cr0 = 0x60000010;
@@ -1190,7 +1256,7 @@ static void inject_rmode_irq(struct kvm_vcpu *vcpu, int irq)
u16 sp = vmcs_readl(GUEST_RSP);
u32 ss_limit = vmcs_read32(GUEST_SS_LIMIT);
- if (sp > ss_limit || sp - 6 > sp) {
+ if (sp > ss_limit || sp < 6 ) {
vcpu_printf(vcpu, "%s: #SS, rsp 0x%lx ss 0x%lx limit 0x%x\n",
__FUNCTION__,
vmcs_readl(GUEST_RSP),
@@ -1330,6 +1396,15 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
asm ("int $2");
return 1;
}
+
+ if (is_no_device(intr_info)) {
+ vcpu->fpu_active = 1;
+ vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+ if (!(vcpu->cr0 & CR0_TS_MASK))
+ vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+ return 1;
+ }
+
error_code = 0;
rip = vmcs_readl(GUEST_RIP);
if (intr_info & INTR_INFO_DELIEVER_CODE_MASK)
@@ -1355,7 +1430,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
case EMULATE_DONE:
return 1;
case EMULATE_DO_MMIO:
- ++kvm_stat.mmio_exits;
+ ++vcpu->stat.mmio_exits;
kvm_run->exit_reason = KVM_EXIT_MMIO;
return 0;
case EMULATE_FAIL:
@@ -1384,7 +1459,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
static int handle_external_interrupt(struct kvm_vcpu *vcpu,
struct kvm_run *kvm_run)
{
- ++kvm_stat.irq_exits;
+ ++vcpu->stat.irq_exits;
return 1;
}
@@ -1394,7 +1469,7 @@ static int handle_triple_fault(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 0;
}
-static int get_io_count(struct kvm_vcpu *vcpu, u64 *count)
+static int get_io_count(struct kvm_vcpu *vcpu, unsigned long *count)
{
u64 inst;
gva_t rip;
@@ -1439,33 +1514,35 @@ static int get_io_count(struct kvm_vcpu *vcpu, u64 *count)
done:
countr_size *= 8;
*count = vcpu->regs[VCPU_REGS_RCX] & (~0ULL >> (64 - countr_size));
+ //printk("cx: %lx\n", vcpu->regs[VCPU_REGS_RCX]);
return 1;
}
static int handle_io(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u64 exit_qualification;
+ int size, down, in, string, rep;
+ unsigned port;
+ unsigned long count;
+ gva_t address;
- ++kvm_stat.io_exits;
+ ++vcpu->stat.io_exits;
exit_qualification = vmcs_read64(EXIT_QUALIFICATION);
- kvm_run->exit_reason = KVM_EXIT_IO;
- if (exit_qualification & 8)
- kvm_run->io.direction = KVM_EXIT_IO_IN;
- else
- kvm_run->io.direction = KVM_EXIT_IO_OUT;
- kvm_run->io.size = (exit_qualification & 7) + 1;
- kvm_run->io.string = (exit_qualification & 16) != 0;
- kvm_run->io.string_down
- = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
- kvm_run->io.rep = (exit_qualification & 32) != 0;
- kvm_run->io.port = exit_qualification >> 16;
- if (kvm_run->io.string) {
- if (!get_io_count(vcpu, &kvm_run->io.count))
+ in = (exit_qualification & 8) != 0;
+ size = (exit_qualification & 7) + 1;
+ string = (exit_qualification & 16) != 0;
+ down = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_DF) != 0;
+ count = 1;
+ rep = (exit_qualification & 32) != 0;
+ port = exit_qualification >> 16;
+ address = 0;
+ if (string) {
+ if (rep && !get_io_count(vcpu, &count))
return 1;
- kvm_run->io.address = vmcs_readl(GUEST_LINEAR_ADDRESS);
- } else
- kvm_run->io.value = vcpu->regs[VCPU_REGS_RAX]; /* rax */
- return 0;
+ address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+ }
+ return kvm_setup_pio(vcpu, kvm_run, in, size, count, string, down,
+ address, rep, port);
}
static void
@@ -1514,6 +1591,15 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
};
break;
+ case 2: /* clts */
+ vcpu_load_rsp_rip(vcpu);
+ vcpu->fpu_active = 1;
+ vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
+ vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+ vcpu->cr0 &= ~CR0_TS_MASK;
+ vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
+ skip_emulated_instruction(vcpu);
+ return 1;
case 1: /*mov from cr*/
switch (cr) {
case 3:
@@ -1523,8 +1609,6 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
skip_emulated_instruction(vcpu);
return 1;
case 8:
- printk(KERN_DEBUG "handle_cr: read CR8 "
- "cpu erratum AA15\n");
vcpu_load_rsp_rip(vcpu);
vcpu->regs[reg] = vcpu->cr8;
vcpu_put_rsp_rip(vcpu);
@@ -1583,8 +1667,8 @@ static int handle_dr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
static int handle_cpuid(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- kvm_run->exit_reason = KVM_EXIT_CPUID;
- return 0;
+ kvm_emulate_cpuid(vcpu);
+ return 1;
}
static int handle_rdmsr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1639,7 +1723,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
if (kvm_run->request_interrupt_window &&
!vcpu->irq_summary) {
kvm_run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
- ++kvm_stat.irq_window_exits;
+ ++vcpu->stat.irq_window_exits;
return 0;
}
return 1;
@@ -1652,13 +1736,13 @@ static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
return 1;
kvm_run->exit_reason = KVM_EXIT_HLT;
- ++kvm_stat.halt_exits;
+ ++vcpu->stat.halt_exits;
return 0;
}
static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
- vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP)+3);
+ skip_emulated_instruction(vcpu);
return kvm_hypercall(vcpu, kvm_run);
}
@@ -1699,7 +1783,6 @@ static int kvm_handle_exit(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
exit_reason != EXIT_REASON_EXCEPTION_NMI )
printk(KERN_WARNING "%s: unexpected, valid vectoring info and "
"exit reason is 0x%x\n", __FUNCTION__, exit_reason);
- kvm_run->instruction_length = vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
if (exit_reason < kvm_vmx_max_exit_handlers
&& kvm_vmx_exit_handlers[exit_reason])
return kvm_vmx_exit_handlers[exit_reason](vcpu, kvm_run);
@@ -1763,11 +1846,21 @@ again:
if (vcpu->guest_debug.enabled)
kvm_guest_debug_pre(vcpu);
- fx_save(vcpu->host_fx_image);
- fx_restore(vcpu->guest_fx_image);
+ if (vcpu->fpu_active) {
+ fx_save(vcpu->host_fx_image);
+ fx_restore(vcpu->guest_fx_image);
+ }
+ /*
+ * Loading guest fpu may have cleared host cr0.ts
+ */
+ vmcs_writel(HOST_CR0, read_cr0());
- save_msrs(vcpu->host_msrs, vcpu->nmsrs);
- load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+#ifdef CONFIG_X86_64
+ if (is_long_mode(vcpu)) {
+ save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1);
+ load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+ }
+#endif
asm (
/* Store host registers */
@@ -1909,21 +2002,28 @@ again:
reload_tss();
}
- ++kvm_stat.exits;
+ ++vcpu->stat.exits;
- save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
- load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
+#ifdef CONFIG_X86_64
+ if (is_long_mode(vcpu)) {
+ save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
+ load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
+ }
+#endif
+
+ if (vcpu->fpu_active) {
+ fx_save(vcpu->guest_fx_image);
+ fx_restore(vcpu->host_fx_image);
+ }
- fx_save(vcpu->guest_fx_image);
- fx_restore(vcpu->host_fx_image);
vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
- kvm_run->exit_type = 0;
if (fail) {
- kvm_run->exit_type = KVM_EXIT_TYPE_FAIL_ENTRY;
- kvm_run->exit_reason = vmcs_read32(VM_INSTRUCTION_ERROR);
+ kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+ kvm_run->fail_entry.hardware_entry_failure_reason
+ = vmcs_read32(VM_INSTRUCTION_ERROR);
r = 0;
} else {
/*
@@ -1933,19 +2033,20 @@ again:
profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
vcpu->launched = 1;
- kvm_run->exit_type = KVM_EXIT_TYPE_VM_EXIT;
r = kvm_handle_exit(kvm_run, vcpu);
if (r > 0) {
/* Give scheduler a change to reschedule. */
if (signal_pending(current)) {
- ++kvm_stat.signal_exits;
+ ++vcpu->stat.signal_exits;
post_kvm_run_save(vcpu, kvm_run);
+ kvm_run->exit_reason = KVM_EXIT_INTR;
return -EINTR;
}
if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- ++kvm_stat.request_irq_exits;
+ ++vcpu->stat.request_irq_exits;
post_kvm_run_save(vcpu, kvm_run);
+ kvm_run->exit_reason = KVM_EXIT_INTR;
return -EINTR;
}
@@ -1969,7 +2070,7 @@ static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
{
u32 vect_info = vmcs_read32(IDT_VECTORING_INFO_FIELD);
- ++kvm_stat.pf_guest;
+ ++vcpu->stat.pf_guest;
if (is_page_fault(vect_info)) {
printk(KERN_DEBUG "inject_page_fault: "
@@ -2026,6 +2127,7 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
vmcs_clear(vmcs);
vcpu->vmcs = vmcs;
vcpu->launched = 0;
+ vcpu->fpu_active = 1;
return 0;
@@ -2062,9 +2164,8 @@ static struct kvm_arch_ops vmx_arch_ops = {
.get_segment = vmx_get_segment,
.set_segment = vmx_set_segment,
.get_cs_db_l_bits = vmx_get_cs_db_l_bits,
- .decache_cr0_cr4_guest_bits = vmx_decache_cr0_cr4_guest_bits,
+ .decache_cr4_guest_bits = vmx_decache_cr4_guest_bits,
.set_cr0 = vmx_set_cr0,
- .set_cr0_no_modeswitch = vmx_set_cr0_no_modeswitch,
.set_cr3 = vmx_set_cr3,
.set_cr4 = vmx_set_cr4,
#ifdef CONFIG_X86_64
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 7513cddb929..7ade09086aa 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -833,8 +833,9 @@ done_prefixes:
dst.ptr = (unsigned long *)cr2;
dst.bytes = (d & ByteOp) ? 1 : op_bytes;
if (d & BitOp) {
- dst.ptr += src.val / BITS_PER_LONG;
- dst.bytes = sizeof(long);
+ unsigned long mask = ~(dst.bytes * 8 - 1);
+
+ dst.ptr = (void *)dst.ptr + (src.val & mask) / 8;
}
if (!(d & Mov) && /* optimisation - avoid slow emulated read */
((rc = ops->read_emulated((unsigned long)dst.ptr,
@@ -1044,7 +1045,7 @@ done_prefixes:
if ((rc = ops->write_std(
register_address(ctxt->ss_base,
_regs[VCPU_REGS_RSP]),
- dst.val, dst.bytes, ctxt)) != 0)
+ &dst.val, dst.bytes, ctxt)) != 0)
goto done;
dst.val = dst.orig_val; /* skanky: disable writeback */
break;
@@ -1077,12 +1078,12 @@ writeback:
case OP_MEM:
if (lock_prefix)
rc = ops->cmpxchg_emulated((unsigned long)dst.
- ptr, dst.orig_val,
- dst.val, dst.bytes,
+ ptr, &dst.orig_val,
+ &dst.val, dst.bytes,
ctxt);
else
rc = ops->write_emulated((unsigned long)dst.ptr,
- dst.val, dst.bytes,
+ &dst.val, dst.bytes,
ctxt);
if (rc != 0)
goto done;
@@ -1320,36 +1321,8 @@ twobyte_special_insn:
realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
break;
case 0xc7: /* Grp9 (cmpxchg8b) */
-#if defined(__i386__)
- {
- unsigned long old_lo, old_hi;
- if (((rc = ops->read_emulated(cr2 + 0, &old_lo, 4,
- ctxt)) != 0)
- || ((rc = ops->read_emulated(cr2 + 4, &old_hi, 4,
- ctxt)) != 0))
- goto done;
- if ((old_lo != _regs[VCPU_REGS_RAX])
- || (old_hi != _regs[VCPU_REGS_RDX])) {
- _regs[VCPU_REGS_RAX] = old_lo;
- _regs[VCPU_REGS_RDX] = old_hi;
- _eflags &= ~EFLG_ZF;
- } else if (ops->cmpxchg8b_emulated == NULL) {
- rc = X86EMUL_UNHANDLEABLE;
- goto done;
- } else {
- if ((rc = ops->cmpxchg8b_emulated(cr2, old_lo,
- old_hi,
- _regs[VCPU_REGS_RBX],
- _regs[VCPU_REGS_RCX],
- ctxt)) != 0)
- goto done;
- _eflags |= EFLG_ZF;
- }
- break;
- }
-#elif defined(CONFIG_X86_64)
{
- unsigned long old, new;
+ u64 old, new;
if ((rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0)
goto done;
if (((u32) (old >> 0) != (u32) _regs[VCPU_REGS_RAX]) ||
@@ -1358,15 +1331,15 @@ twobyte_special_insn:
_regs[VCPU_REGS_RDX] = (u32) (old >> 32);
_eflags &= ~EFLG_ZF;
} else {
- new = (_regs[VCPU_REGS_RCX] << 32) | (u32) _regs[VCPU_REGS_RBX];
- if ((rc = ops->cmpxchg_emulated(cr2, old,
- new, 8, ctxt)) != 0)
+ new = ((u64)_regs[VCPU_REGS_RCX] << 32)
+ | (u32) _regs[VCPU_REGS_RBX];
+ if ((rc = ops->cmpxchg_emulated(cr2, &old,
+ &new, 8, ctxt)) != 0)
goto done;
_eflags |= EFLG_ZF;
}
break;
}
-#endif
}
goto writeback;
diff --git a/drivers/kvm/x86_emulate.h b/drivers/kvm/x86_emulate.h
index 5d41bd55125..ea3407d7fee 100644
--- a/drivers/kvm/x86_emulate.h
+++ b/drivers/kvm/x86_emulate.h
@@ -59,8 +59,7 @@ struct x86_emulate_ops {
* @val: [OUT] Value read from memory, zero-extended to 'u_long'.
* @bytes: [IN ] Number of bytes to read from memory.
*/
- int (*read_std)(unsigned long addr,
- unsigned long *val,
+ int (*read_std)(unsigned long addr, void *val,
unsigned int bytes, struct x86_emulate_ctxt * ctxt);
/*
@@ -71,8 +70,7 @@ struct x86_emulate_ops {
* required).
* @bytes: [IN ] Number of bytes to write to memory.
*/
- int (*write_std)(unsigned long addr,
- unsigned long val,
+ int (*write_std)(unsigned long addr, const void *val,
unsigned int bytes, struct x86_emulate_ctxt * ctxt);
/*
@@ -82,7 +80,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to read from memory.
*/
int (*read_emulated) (unsigned long addr,
- unsigned long *val,
+ void *val,
unsigned int bytes,
struct x86_emulate_ctxt * ctxt);
@@ -94,7 +92,7 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to write to memory.
*/
int (*write_emulated) (unsigned long addr,
- unsigned long val,
+ const void *val,
unsigned int bytes,
struct x86_emulate_ctxt * ctxt);
@@ -107,29 +105,11 @@ struct x86_emulate_ops {
* @bytes: [IN ] Number of bytes to access using CMPXCHG.
*/
int (*cmpxchg_emulated) (unsigned long addr,
- unsigned long old,
- unsigned long new,
+ const void *old,
+ const void *new,
unsigned int bytes,
struct x86_emulate_ctxt * ctxt);
- /*
- * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
- * emulated/special memory area.
- * @addr: [IN ] Linear address to access.
- * @old: [IN ] Value expected to be current at @addr.
- * @new: [IN ] Value to write to @addr.
- * NOTES:
- * 1. This function is only ever called when emulating a real CMPXCHG8B.
- * 2. This function is *never* called on x86/64 systems.
- * 2. Not defining this function (i.e., specifying NULL) is equivalent
- * to defining a function that always returns X86EMUL_UNHANDLEABLE.
- */
- int (*cmpxchg8b_emulated) (unsigned long addr,
- unsigned long old_lo,
- unsigned long old_hi,
- unsigned long new_lo,
- unsigned long new_hi,
- struct x86_emulate_ctxt * ctxt);
};
struct cpu_user_regs;
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
index 1d49d2ade55..677c99325be 100644
--- a/drivers/leds/leds-h1940.c
+++ b/drivers/leds/leds-h1940.c
@@ -1,5 +1,5 @@
/*
- * drivers/leds/h1940-leds.c
+ * drivers/leds/leds-h1940.c
* Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
*
* This file is subject to the terms and conditions of the GNU General Public
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 1a86387e23b..58926da0ae1 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -1,6 +1,10 @@
-menu "Macintosh device drivers"
+menuconfig MACINTOSH_DRIVERS
+ bool "Macintosh device drivers"
depends on PPC || MAC || X86
+ default y
+
+if MACINTOSH_DRIVERS
config ADB
bool "Apple Desktop Bus (ADB) support"
@@ -109,7 +113,9 @@ config PMAC_SMU
config PMAC_APM_EMU
tristate "APM emulation"
- depends on PPC_PMAC && PPC32 && PM && ADB_PMU
+ select SYS_SUPPORTS_APM_EMULATION
+ select APM_EMULATION
+ depends on ADB_PMU && PM
config PMAC_MEDIABAY
bool "Support PowerBook hotswap media bay"
@@ -231,7 +237,7 @@ config PMAC_RACKMETER
tristate "Support for Apple XServe front panel LEDs"
depends on PPC_PMAC
help
- This driver procides some support to control the front panel
+ This driver provides some support to control the front panel
blue LEDs "vu-meter" of the XServer macs.
-endmenu
+endif # MACINTOSH_DRIVERS
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index f729eebf771..adfea3c7c62 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -90,7 +90,7 @@ static int autopoll_devs;
int __adb_probe_sync;
#ifdef CONFIG_PM
-static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
+static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier adb_sleep_notifier = {
adb_notify_sleep,
SLEEP_LEVEL_ADB,
@@ -340,11 +340,9 @@ __initcall(adb_init);
/*
* notify clients before sleep and reset bus afterwards
*/
-int
+void
adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
{
- int ret;
-
switch (when) {
case PBOOK_SLEEP_REQUEST:
adb_got_sleep = 1;
@@ -353,22 +351,8 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
/* Stop autopoll */
if (adb_controller->autopoll)
adb_controller->autopoll(0);
- ret = blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_POWERDOWN, NULL);
- if (ret & NOTIFY_STOP_MASK) {
- up(&adb_probe_mutex);
- return PBOOK_SLEEP_REFUSE;
- }
- break;
- case PBOOK_SLEEP_REJECT:
- if (adb_got_sleep) {
- adb_got_sleep = 0;
- up(&adb_probe_mutex);
- adb_reset_bus();
- }
- break;
-
- case PBOOK_SLEEP_NOW:
+ blocking_notifier_call_chain(&adb_client_list,
+ ADB_MSG_POWERDOWN, NULL);
break;
case PBOOK_WAKE:
adb_got_sleep = 0;
@@ -376,14 +360,13 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
adb_reset_bus();
break;
}
- return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PM */
static int
do_adb_reset_bus(void)
{
- int ret, nret;
+ int ret;
if (adb_controller == NULL)
return -ENXIO;
@@ -391,13 +374,8 @@ do_adb_reset_bus(void)
if (adb_controller->autopoll)
adb_controller->autopoll(0);
- nret = blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_PRE_RESET, NULL);
- if (nret & NOTIFY_STOP_MASK) {
- if (adb_controller->autopoll)
- adb_controller->autopoll(autopoll_devs);
- return -EBUSY;
- }
+ blocking_notifier_call_chain(&adb_client_list,
+ ADB_MSG_PRE_RESET, NULL);
if (sleepy_trackpad) {
/* Let the trackpad settle down */
@@ -427,10 +405,8 @@ do_adb_reset_bus(void)
}
up(&adb_handler_sem);
- nret = blocking_notifier_call_chain(&adb_client_list,
- ADB_MSG_POST_RESET, NULL);
- if (nret & NOTIFY_STOP_MASK)
- return -EBUSY;
+ blocking_notifier_call_chain(&adb_client_list,
+ ADB_MSG_POST_RESET, NULL);
return ret;
}
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index cdd5a0f72e3..e54c4d9f636 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -145,11 +145,12 @@ anslcd_init(void)
int retval;
struct device_node* node;
- node = find_devices("lcd");
- if (!node || !node->parent)
- return -ENODEV;
- if (strcmp(node->parent->name, "gc"))
+ node = of_find_node_by_name(NULL, "lcd");
+ if (!node || !node->parent || strcmp(node->parent->name, "gc")) {
+ of_node_put(node);
return -ENODEV;
+ }
+ of_node_put(node);
anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c
index c5e4d43f97f..9821e6361e6 100644
--- a/drivers/macintosh/apm_emu.c
+++ b/drivers/macintosh/apm_emu.c
@@ -1,9 +1,7 @@
-/* APM emulation layer for PowerMac
- *
- * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+/*
+ * APM emulation for PMU-based machines
*
- * Lots of code inherited from apm.c, see appropriate notice in
- * arch/i386/kernel/apm.c
+ * Copyright 2001 Benjamin Herrenschmidt (benh@kernel.crashing.org)
*
* 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
@@ -18,434 +16,39 @@
*
*/
-#include <linux/module.h>
-
-#include <linux/poll.h>
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/timer.h>
-#include <linux/fcntl.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#include <linux/miscdevice.h>
-#include <linux/apm_bios.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/pm.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
-
+#include <linux/module.h>
+#include <linux/apm-emulation.h>
#include <linux/adb.h>
#include <linux/pmu.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(args...) printk(KERN_DEBUG args)
-//#define DBG(args...) xmon_printf(args)
-#else
-#define DBG(args...) do { } while (0)
-#endif
-
-/*
- * The apm_bios device is one of the misc char devices.
- * This is its minor number.
- */
-#define APM_MINOR_DEV 134
-
-/*
- * Maximum number of events stored
- */
-#define APM_MAX_EVENTS 20
-
-#define FAKE_APM_BIOS_VERSION 0x0101
-
-#define APM_USER_NOTIFY_TIMEOUT (5*HZ)
-
-/*
- * The per-file APM data
- */
-struct apm_user {
- int magic;
- struct apm_user * next;
- int suser: 1;
- int suspend_waiting: 1;
- int suspends_pending;
- int suspends_read;
- int event_head;
- int event_tail;
- apm_event_t events[APM_MAX_EVENTS];
-};
-
-/*
- * The magic number in apm_user
- */
-#define APM_BIOS_MAGIC 0x4101
-
-/*
- * Local variables
- */
-static int suspends_pending;
-
-static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
-static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-static struct apm_user * user_list;
-
-static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier apm_sleep_notifier = {
- apm_notify_sleep,
- SLEEP_LEVEL_USERLAND,
-};
-
-static const char driver_version[] = "0.5"; /* no spaces */
-
-#ifdef DEBUG
-static char * apm_event_name[] = {
- "system standby",
- "system suspend",
- "normal resume",
- "critical resume",
- "low battery",
- "power status change",
- "update time",
- "critical suspend",
- "user standby",
- "user suspend",
- "system standby resume",
- "capabilities change"
-};
-#define NR_APM_EVENT_NAME \
- (sizeof(apm_event_name) / sizeof(apm_event_name[0]))
-
-#endif
-
-static int queue_empty(struct apm_user *as)
-{
- return as->event_head == as->event_tail;
-}
-
-static apm_event_t get_queued_event(struct apm_user *as)
-{
- as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
- return as->events[as->event_tail];
-}
-
-static void queue_event(apm_event_t event, struct apm_user *sender)
-{
- struct apm_user * as;
-
- DBG("apm_emu: queue_event(%s)\n", apm_event_name[event-1]);
- if (user_list == NULL)
- return;
- for (as = user_list; as != NULL; as = as->next) {
- if (as == sender)
- continue;
- as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
- if (as->event_head == as->event_tail) {
- static int notified;
-
- if (notified++ == 0)
- printk(KERN_ERR "apm_emu: an event queue overflowed\n");
- as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
- }
- as->events[as->event_head] = event;
- if (!as->suser)
- continue;
- switch (event) {
- case APM_SYS_SUSPEND:
- case APM_USER_SUSPEND:
- as->suspends_pending++;
- suspends_pending++;
- break;
- case APM_NORMAL_RESUME:
- as->suspend_waiting = 0;
- break;
- }
- }
- wake_up_interruptible(&apm_waitqueue);
-}
-
-static int check_apm_user(struct apm_user *as, const char *func)
-{
- if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
- printk(KERN_ERR "apm_emu: %s passed bad filp\n", func);
- return 1;
- }
- return 0;
-}
-
-static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos)
-{
- struct apm_user * as;
- size_t i;
- apm_event_t event;
- DECLARE_WAITQUEUE(wait, current);
-
- as = fp->private_data;
- if (check_apm_user(as, "read"))
- return -EIO;
- if (count < sizeof(apm_event_t))
- return -EINVAL;
- if (queue_empty(as)) {
- if (fp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- add_wait_queue(&apm_waitqueue, &wait);
-repeat:
- set_current_state(TASK_INTERRUPTIBLE);
- if (queue_empty(as) && !signal_pending(current)) {
- schedule();
- goto repeat;
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&apm_waitqueue, &wait);
- }
- i = count;
- while ((i >= sizeof(event)) && !queue_empty(as)) {
- event = get_queued_event(as);
- DBG("apm_emu: do_read, returning: %s\n", apm_event_name[event-1]);
- if (copy_to_user(buf, &event, sizeof(event))) {
- if (i < count)
- break;
- return -EFAULT;
- }
- switch (event) {
- case APM_SYS_SUSPEND:
- case APM_USER_SUSPEND:
- as->suspends_read++;
- break;
- }
- buf += sizeof(event);
- i -= sizeof(event);
- }
- if (i < count)
- return count - i;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static unsigned int do_poll(struct file *fp, poll_table * wait)
-{
- struct apm_user * as;
-
- as = fp->private_data;
- if (check_apm_user(as, "poll"))
- return 0;
- poll_wait(fp, &apm_waitqueue, wait);
- if (!queue_empty(as))
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-static int do_ioctl(struct inode * inode, struct file *filp,
- u_int cmd, u_long arg)
-{
- struct apm_user * as;
- DECLARE_WAITQUEUE(wait, current);
-
- as = filp->private_data;
- if (check_apm_user(as, "ioctl"))
- return -EIO;
- if (!as->suser)
- return -EPERM;
- switch (cmd) {
- case APM_IOC_SUSPEND:
- /* If a suspend message was sent to userland, we
- * consider this as a confirmation message
- */
- if (as->suspends_read > 0) {
- as->suspends_read--;
- as->suspends_pending--;
- suspends_pending--;
- } else {
- // Route to PMU suspend ?
- break;
- }
- as->suspend_waiting = 1;
- add_wait_queue(&apm_waitqueue, &wait);
- DBG("apm_emu: ioctl waking up sleep waiter !\n");
- wake_up(&apm_suspend_waitqueue);
- mb();
- while(as->suspend_waiting && !signal_pending(current)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&apm_waitqueue, &wait);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int do_release(struct inode * inode, struct file * filp)
-{
- struct apm_user * as;
-
- as = filp->private_data;
- if (check_apm_user(as, "release"))
- return 0;
- filp->private_data = NULL;
- lock_kernel();
- if (as->suspends_pending > 0) {
- suspends_pending -= as->suspends_pending;
- if (suspends_pending <= 0)
- wake_up(&apm_suspend_waitqueue);
- }
- if (user_list == as)
- user_list = as->next;
- else {
- struct apm_user * as1;
-
- for (as1 = user_list;
- (as1 != NULL) && (as1->next != as);
- as1 = as1->next)
- ;
- if (as1 == NULL)
- printk(KERN_ERR "apm: filp not in user list\n");
- else
- as1->next = as->next;
- }
- unlock_kernel();
- kfree(as);
- return 0;
-}
-
-static int do_open(struct inode * inode, struct file * filp)
-{
- struct apm_user * as;
-
- as = kmalloc(sizeof(*as), GFP_KERNEL);
- if (as == NULL) {
- printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n",
- sizeof(*as));
- return -ENOMEM;
- }
- as->magic = APM_BIOS_MAGIC;
- as->event_tail = as->event_head = 0;
- as->suspends_pending = 0;
- as->suspends_read = 0;
- /*
- * XXX - this is a tiny bit broken, when we consider BSD
- * process accounting. If the device is opened by root, we
- * instantly flag that we used superuser privs. Who knows,
- * we might close the device immediately without doing a
- * privileged operation -- cevans
- */
- as->suser = capable(CAP_SYS_ADMIN);
- as->next = user_list;
- user_list = as;
- filp->private_data = as;
-
- DBG("apm_emu: opened by %s, suser: %d\n", current->comm, (int)as->suser);
-
- return 0;
-}
-
-/* Wait for all clients to ack the suspend request. APM API
- * doesn't provide a way to NAK, but this could be added
- * here.
- */
-static int wait_all_suspend(void)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&apm_suspend_waitqueue, &wait);
- DBG("apm_emu: wait_all_suspend(), suspends_pending: %d\n", suspends_pending);
- while(suspends_pending > 0) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&apm_suspend_waitqueue, &wait);
-
- DBG("apm_emu: wait_all_suspend() - complete !\n");
-
- return 1;
-}
-
-static int apm_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
- switch(when) {
- case PBOOK_SLEEP_REQUEST:
- queue_event(APM_SYS_SUSPEND, NULL);
- if (!wait_all_suspend())
- return PBOOK_SLEEP_REFUSE;
- break;
- case PBOOK_SLEEP_REJECT:
- case PBOOK_WAKE:
- queue_event(APM_NORMAL_RESUME, NULL);
- break;
- }
- return PBOOK_SLEEP_OK;
-}
-
#define APM_CRITICAL 10
#define APM_LOW 30
-static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length)
+static void pmu_apm_get_power_status(struct apm_power_info *info)
{
- /* Arguments, with symbols from linux/apm_bios.h. Information is
- from the Get Power Status (0x0a) call unless otherwise noted.
+ int percentage = -1;
+ int batteries = 0;
+ int time_units = -1;
+ int real_count = 0;
+ int i;
+ char charging = 0;
+ long charge = -1;
+ long amperage = 0;
+ unsigned long btype = 0;
+
+ info->battery_status = APM_BATTERY_STATUS_UNKNOWN;
+ info->battery_flag = APM_BATTERY_FLAG_UNKNOWN;
+ info->units = APM_UNITS_MINS;
+
+ if (pmu_power_flags & PMU_PWR_AC_PRESENT)
+ info->ac_line_status = APM_AC_ONLINE;
+ else
+ info->ac_line_status = APM_AC_OFFLINE;
- 0) Linux driver version (this will change if format changes)
- 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
- 2) APM flags from APM Installation Check (0x00):
- bit 0: APM_16_BIT_SUPPORT
- bit 1: APM_32_BIT_SUPPORT
- bit 2: APM_IDLE_SLOWS_CLOCK
- bit 3: APM_BIOS_DISABLED
- bit 4: APM_BIOS_DISENGAGED
- 3) AC line status
- 0x00: Off-line
- 0x01: On-line
- 0x02: On backup power (BIOS >= 1.1 only)
- 0xff: Unknown
- 4) Battery status
- 0x00: High
- 0x01: Low
- 0x02: Critical
- 0x03: Charging
- 0x04: Selected battery not present (BIOS >= 1.2 only)
- 0xff: Unknown
- 5) Battery flag
- bit 0: High
- bit 1: Low
- bit 2: Critical
- bit 3: Charging
- bit 7: No system battery
- 0xff: Unknown
- 6) Remaining battery life (percentage of charge):
- 0-100: valid
- -1: Unknown
- 7) Remaining battery life (time units):
- Number of remaining minutes or seconds
- -1: Unknown
- 8) min = minutes; sec = seconds */
-
- unsigned short ac_line_status;
- unsigned short battery_status = 0;
- unsigned short battery_flag = 0xff;
- int percentage = -1;
- int time_units = -1;
- int real_count = 0;
- int i;
- char * p = buf;
- char charging = 0;
- long charge = -1;
- long amperage = 0;
- unsigned long btype = 0;
-
- ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0);
for (i=0; i<pmu_battery_count; i++) {
if (pmu_batteries[i].flags & PMU_BATT_PRESENT) {
- battery_status++;
+ batteries++;
if (percentage < 0)
percentage = 0;
if (charge < 0)
@@ -461,9 +64,9 @@ static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length)
charging++;
}
}
- if (0 == battery_status)
- ac_line_status = 1;
- battery_status = 0xff;
+ if (batteries == 0)
+ info->ac_line_status = APM_AC_ONLINE;
+
if (real_count) {
if (amperage < 0) {
if (btype == PMU_BATT_TYPE_SMART)
@@ -473,85 +76,44 @@ static int apm_emu_get_info(char *buf, char **start, off_t fpos, int length)
}
percentage /= real_count;
if (charging > 0) {
- battery_status = 0x03;
- battery_flag = 0x08;
+ info->battery_status = APM_BATTERY_STATUS_CHARGING;
+ info->battery_flag = APM_BATTERY_FLAG_CHARGING;
} else if (percentage <= APM_CRITICAL) {
- battery_status = 0x02;
- battery_flag = 0x04;
+ info->battery_status = APM_BATTERY_STATUS_CRITICAL;
+ info->battery_flag = APM_BATTERY_FLAG_CRITICAL;
} else if (percentage <= APM_LOW) {
- battery_status = 0x01;
- battery_flag = 0x02;
+ info->battery_status = APM_BATTERY_STATUS_LOW;
+ info->battery_flag = APM_BATTERY_FLAG_LOW;
} else {
- battery_status = 0x00;
- battery_flag = 0x01;
+ info->battery_status = APM_BATTERY_STATUS_HIGH;
+ info->battery_flag = APM_BATTERY_FLAG_HIGH;
}
}
- p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
- driver_version,
- (FAKE_APM_BIOS_VERSION >> 8) & 0xff,
- FAKE_APM_BIOS_VERSION & 0xff,
- 0,
- ac_line_status,
- battery_status,
- battery_flag,
- percentage,
- time_units,
- "min");
- return p - buf;
+ info->battery_life = percentage;
+ info->time = time_units;
}
-static const struct file_operations apm_bios_fops = {
- .owner = THIS_MODULE,
- .read = do_read,
- .poll = do_poll,
- .ioctl = do_ioctl,
- .open = do_open,
- .release = do_release,
-};
-
-static struct miscdevice apm_device = {
- APM_MINOR_DEV,
- "apm_bios",
- &apm_bios_fops
-};
-
static int __init apm_emu_init(void)
{
- struct proc_dir_entry *apm_proc;
-
- if (sys_ctrler != SYS_CTRLER_PMU) {
- printk(KERN_INFO "apm_emu: Requires a machine with a PMU.\n");
- return -ENODEV;
- }
-
- apm_proc = create_proc_info_entry("apm", 0, NULL, apm_emu_get_info);
- if (apm_proc)
- apm_proc->owner = THIS_MODULE;
+ apm_get_power_status = pmu_apm_get_power_status;
- if (misc_register(&apm_device) != 0)
- printk(KERN_INFO "Could not create misc. device for apm\n");
-
- pmu_register_sleep_notifier(&apm_sleep_notifier);
-
- printk(KERN_INFO "apm_emu: APM Emulation %s initialized.\n", driver_version);
+ printk(KERN_INFO "apm_emu: PMU APM Emulation initialized.\n");
return 0;
}
static void __exit apm_emu_exit(void)
{
- pmu_unregister_sleep_notifier(&apm_sleep_notifier);
- misc_deregister(&apm_device);
- remove_proc_entry("apm", NULL);
+ if (apm_get_power_status == pmu_apm_get_power_status)
+ apm_get_power_status = NULL;
- printk(KERN_INFO "apm_emu: APM Emulation removed.\n");
+ printk(KERN_INFO "apm_emu: PMU APM Emulation removed.\n");
}
module_init(apm_emu_init);
module_exit(apm_emu_exit);
MODULE_AUTHOR("Benjamin Herrenschmidt");
-MODULE_DESCRIPTION("APM emulation layer for PowerMac");
+MODULE_DESCRIPTION("APM emulation for PowerMac");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index c1fd816e9f0..76c1e8e4a48 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -24,7 +24,7 @@ static int mouse_last_keycode;
#if defined(CONFIG_SYSCTL)
/* file(s) in /proc/sys/dev/mac_hid */
-ctl_table mac_hid_files[] = {
+static ctl_table mac_hid_files[] = {
{
.ctl_name = DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
.procname = "mouse_button_emulation",
@@ -53,7 +53,7 @@ ctl_table mac_hid_files[] = {
};
/* dir in /proc/sys/dev */
-ctl_table mac_hid_dir[] = {
+static ctl_table mac_hid_dir[] = {
{
.ctl_name = DEV_MAC_HID,
.procname = "mac_hid",
@@ -65,7 +65,7 @@ ctl_table mac_hid_dir[] = {
};
/* /proc/sys/dev itself, in case that is not there yet */
-ctl_table mac_hid_root_dir[] = {
+static ctl_table mac_hid_root_dir[] = {
{
.ctl_name = CTL_DEV,
.procname = "dev",
@@ -102,8 +102,6 @@ int mac_hid_mouse_emulate_buttons(int caller, unsigned int keycode, int down)
return 0;
}
-EXPORT_SYMBOL(mac_hid_mouse_emulate_buttons);
-
static int emumousebtn_input_register(void)
{
int ret;
@@ -129,7 +127,7 @@ static int emumousebtn_input_register(void)
return ret;
}
-int __init mac_hid_init(void)
+static int __init mac_hid_init(void)
{
int err;
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 026b67f4f65..79119f56e82 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -82,7 +82,14 @@ struct adb_driver macio_adb_driver = {
int macio_probe(void)
{
- return find_compatible_devices("adb", "chrp,adb0")? 0: -ENODEV;
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, "adb", "chrp,adb0");
+ if (np) {
+ of_node_put(np);
+ return 0;
+ }
+ return -ENODEV;
}
int macio_init(void)
@@ -91,12 +98,14 @@ int macio_init(void)
struct resource r;
unsigned int irq;
- adbs = find_compatible_devices("adb", "chrp,adb0");
+ adbs = of_find_compatible_node(NULL, "adb", "chrp,adb0");
if (adbs == 0)
return -ENXIO;
- if (of_address_to_resource(adbs, 0, &r))
+ if (of_address_to_resource(adbs, 0, &r)) {
+ of_node_put(adbs);
return -ENXIO;
+ }
adb = ioremap(r.start, sizeof(struct adb_regs));
out_8(&adb->ctrl.r, 0);
@@ -107,6 +116,7 @@ int macio_init(void)
out_8(&adb->autopoll.r, APE);
irq = irq_of_parse_and_map(adbs, 0);
+ of_node_put(adbs);
if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
printk(KERN_ERR "ADB: can't get irq %d\n", irq);
return -EAGAIN;
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index d5621606754..c96b7fe882a 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -134,108 +134,12 @@ static int macio_device_resume(struct device * dev)
return 0;
}
-static int macio_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
-{
- struct macio_dev * macio_dev;
- struct of_device * of;
- char *scratch;
- const char *compat, *compat2;
-
- int i = 0;
- int length, cplen, cplen2, seen = 0;
-
- if (!dev)
- return -ENODEV;
-
- macio_dev = to_macio_device(dev);
- if (!macio_dev)
- return -ENODEV;
-
- of = &macio_dev->ofdev;
-
- /* stuff we want to pass to /sbin/hotplug */
- envp[i++] = scratch = buffer;
- length = scnprintf (scratch, buffer_size, "OF_NAME=%s", of->node->name);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size, "OF_TYPE=%s", of->node->type);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- /* Since the compatible field can contain pretty much anything
- * it's not really legal to split it out with commas. We split it
- * up using a number of environment variables instead. */
-
- compat = get_property(of->node, "compatible", &cplen);
- compat2 = compat;
- cplen2= cplen;
- while (compat && cplen > 0) {
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size,
- "OF_COMPATIBLE_%d=%s", seen, compat);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
- length = strlen (compat) + 1;
- compat += length;
- cplen -= length;
- seen++;
- }
-
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size, "OF_COMPATIBLE_N=%d", seen);
- ++length;
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- envp[i++] = scratch;
- length = scnprintf (scratch, buffer_size, "MODALIAS=of:N%sT%s",
- of->node->name, of->node->type);
- /* overwrite '\0' */
- buffer_size -= length;
- if ((buffer_size <= 0) || (i >= num_envp))
- return -ENOMEM;
- scratch += length;
-
- if (!compat2) {
- compat2 = "";
- cplen2 = 1;
- }
- while (cplen2 > 0) {
- length = snprintf (scratch, buffer_size, "C%s", compat2);
- buffer_size -= length;
- if (buffer_size <= 0)
- return -ENOMEM;
- scratch += length;
- length = strlen (compat2) + 1;
- compat2 += length;
- cplen2 -= length;
- }
-
- envp[i] = NULL;
-
- return 0;
-}
-
extern struct device_attribute macio_dev_attrs[];
struct bus_type macio_bus_type = {
.name = "macio",
.match = macio_bus_match,
- .uevent = macio_uevent,
+ .uevent = of_device_uevent,
.probe = macio_device_probe,
.remove = macio_device_remove,
.shutdown = macio_device_shutdown,
@@ -491,7 +395,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
#endif
MAX_NODE_NAME_SIZE, np->name);
} else {
- reg = get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
chip->lbus.index,
reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
index 8566bdfdd4b..112e5ef728f 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -21,7 +21,7 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
int length = 0;
of = &to_macio_device (dev)->ofdev;
- compat = get_property(of->node, "compatible", &cplen);
+ compat = of_get_property(of->node, "compatible", &cplen);
if (!compat) {
*buf = '\0';
return 0;
@@ -41,26 +41,15 @@ compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t modalias_show (struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct of_device *of;
- const char *compat;
- int cplen;
- int length;
+ struct of_device *ofdev = to_of_device(dev);
+ int len;
- of = &to_macio_device (dev)->ofdev;
- compat = get_property(of->node, "compatible", &cplen);
- if (!compat) compat = "", cplen = 1;
- length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type);
- buf += length;
- while (cplen > 0) {
- int l;
- length += sprintf (buf, "C%s", compat);
- buf += length;
- l = strlen (compat) + 1;
- compat += l;
- cplen -= l;
- }
+ len = of_device_get_modalias(ofdev, buf, PAGE_SIZE);
- return length;
+ buf[len] = '\n';
+ buf[len+1] = 0;
+
+ return len+1;
}
macio_config_of_attr (name, "%s\n");
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index f83fad2a3ff..4177ff00475 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -387,7 +387,7 @@ static int __devinit rackmeter_probe(struct macio_dev* mdev,
if (strcmp(np->name, "lightshow") == 0)
break;
if ((strcmp(np->name, "sound") == 0) &&
- get_property(np, "virtual", NULL) != NULL)
+ of_get_property(np, "virtual", NULL) != NULL)
break;
}
if (np == NULL) {
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index c9f3dc4fd3e..f8e1a135bf9 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -491,7 +491,7 @@ int __init smu_init (void)
printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
goto fail;
}
- data = get_property(smu->db_node, "reg", NULL);
+ data = of_get_property(smu->db_node, "reg", NULL);
if (data == NULL) {
of_node_put(smu->db_node);
smu->db_node = NULL;
@@ -512,7 +512,7 @@ int __init smu_init (void)
smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
if (smu->msg_node == NULL)
break;
- data = get_property(smu->msg_node, "reg", NULL);
+ data = of_get_property(smu->msg_node, "reg", NULL);
if (data == NULL) {
of_node_put(smu->msg_node);
smu->msg_node = NULL;
@@ -606,7 +606,7 @@ static void smu_expose_childs(struct work_struct *unused)
struct device_node *np;
for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;)
- if (device_is_compatible(np, "smu-sensors"))
+ if (of_device_is_compatible(np, "smu-sensors"))
of_platform_device_create(np, "smu-sensors",
&smu->of_dev->dev);
}
@@ -952,7 +952,7 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
prop->name = ((char *)prop) + tlen - 18;
sprintf(prop->name, "sdb-partition-%02x", id);
prop->length = len;
- prop->value = (unsigned char *)hdr;
+ prop->value = hdr;
prop->next = NULL;
/* Read the datablock */
@@ -1004,7 +1004,7 @@ const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
} else
mutex_lock(&smu_part_access);
- part = get_property(smu->of_node, pname, size);
+ part = of_get_property(smu->of_node, pname, size);
if (part == NULL) {
DPRINTK("trying to extract from SMU ...\n");
part = smu_create_sdb_partition(id);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index a7ce5592663..bd55e6ab99f 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -19,7 +19,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
@@ -560,20 +559,20 @@ thermostat_init(void)
np = of_find_node_by_name(NULL, "fan");
if (!np)
return -ENODEV;
- if (device_is_compatible(np, "adt7460"))
+ if (of_device_is_compatible(np, "adt7460"))
therm_type = ADT7460;
- else if (device_is_compatible(np, "adt7467"))
+ else if (of_device_is_compatible(np, "adt7467"))
therm_type = ADT7467;
else
return -ENODEV;
- prop = get_property(np, "hwsensor-params-version", NULL);
+ prop = of_get_property(np, "hwsensor-params-version", NULL);
printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
(*prop == 1)?"":"un");
if (*prop != 1)
return -ENODEV;
- prop = get_property(np, "reg", NULL);
+ prop = of_get_property(np, "reg", NULL);
if (!prop)
return -ENODEV;
@@ -591,9 +590,9 @@ thermostat_init(void)
"limit_adjust: %d, fan_speed: %d\n",
therm_bus, therm_address, limit_adjust, fan_speed);
- if (get_property(np, "hwsensor-location", NULL)) {
+ if (of_get_property(np, "hwsensor-location", NULL)) {
for (i = 0; i < 3; i++) {
- sensor_location[i] = get_property(np,
+ sensor_location[i] = of_get_property(np,
"hwsensor-location", NULL) + offset;
if (sensor_location[i] == NULL)
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 2e4ad44a863..dbb22403979 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -117,7 +117,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/reboot.h>
#include <linux/kmod.h>
@@ -674,7 +673,7 @@ static int read_eeprom(int cpu, struct mpu_data *out)
printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid node from device-tree\n");
return -ENODEV;
}
- data = get_property(np, "cpuid", &len);
+ data = of_get_property(np, "cpuid", &len);
if (data == NULL) {
printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid property from device-tree\n");
of_node_put(np);
@@ -1337,7 +1336,7 @@ static int init_backside_state(struct backside_pid_state *state)
*/
u3 = of_find_node_by_path("/u3@0,f8000000");
if (u3 != NULL) {
- const u32 *vers = get_property(u3, "device-rev", NULL);
+ const u32 *vers = of_get_property(u3, "device-rev", NULL);
if (vers)
if (((*vers) & 0x3f) < 0x34)
u3h = 0;
@@ -2129,8 +2128,8 @@ static void fcu_lookup_fans(struct device_node *fcu_node)
continue;
/* Lookup for a matching location */
- loc = get_property(np, "location", NULL);
- reg = get_property(np, "reg", NULL);
+ loc = of_get_property(np, "location", NULL);
+ reg = of_get_property(np, "reg", NULL);
if (loc == NULL || reg == NULL)
continue;
DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index a1d3a987cb3..3d0354e96a9 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -459,7 +459,8 @@ therm_of_probe( struct of_device *dev, const struct of_device_id *match )
static int
therm_of_remove( struct of_device *dev )
{
- return i2c_del_driver( &g4fan_driver );
+ i2c_del_driver( &g4fan_driver );
+ return 0;
}
static struct of_device_id therm_of_match[] = {{
@@ -492,7 +493,7 @@ g4fan_init( void )
if( !(np=of_find_node_by_name(NULL, "power-mgt")) )
return -ENODEV;
- info = get_property(np, "thermal-info", NULL);
+ info = of_get_property(np, "thermal-info", NULL);
of_node_put(np);
if( !info || !machine_is_compatible("PowerMac3,6") )
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index d58fcf6cca0..741a93a3eb6 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16];
static unsigned char *reply_ptr;
static int reading_reply;
static int data_index;
+static int cuda_irq;
#ifdef CONFIG_PPC
static struct device_node *vias;
#endif
@@ -131,7 +132,7 @@ int __init find_via_cuda(void)
if (vias == 0)
return 0;
- reg = get_property(vias, "reg", NULL);
+ reg = of_get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
goto fail;
@@ -160,10 +161,8 @@ int __init find_via_cuda(void)
/* Clear and enable interrupts, but only on PPC. On 68K it's done */
/* for us by the main VIA driver in arch/m68k/mac/via.c */
-#ifndef CONFIG_MAC
out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */
out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
-#endif
/* enable autopoll */
cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
@@ -181,24 +180,22 @@ int __init find_via_cuda(void)
static int __init via_cuda_start(void)
{
- unsigned int irq;
-
if (via == NULL)
return -ENODEV;
#ifdef CONFIG_MAC
- irq = IRQ_MAC_ADB;
+ cuda_irq = IRQ_MAC_ADB;
#else /* CONFIG_MAC */
- irq = irq_of_parse_and_map(vias, 0);
- if (irq == NO_IRQ) {
+ cuda_irq = irq_of_parse_and_map(vias, 0);
+ if (cuda_irq == NO_IRQ) {
printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
vias->full_name);
return -ENODEV;
}
-#endif /* CONFIG_MAP */
+#endif /* CONFIG_MAC */
- if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
- printk(KERN_ERR "via-cuda: can't request irq %d\n", irq);
+ if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+ printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq);
return -EAGAIN;
}
@@ -238,6 +235,7 @@ cuda_init(void)
printk(KERN_ERR "cuda_init_via() failed\n");
return -ENODEV;
}
+ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */
return via_cuda_start();
#endif
@@ -263,15 +261,17 @@ cuda_init_via(void)
out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */
out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */
(void)in_8(&via[SR]); /* clear any left-over data */
-#ifndef CONFIG_MAC
+#ifdef CONFIG_PPC
out_8(&via[IER], 0x7f); /* disable interrupts from VIA */
(void)in_8(&via[IER]);
+#else
+ out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */
#endif
/* delay 4ms and then clear any pending interrupt */
mdelay(4);
(void)in_8(&via[SR]);
- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+ out_8(&via[IFR], SR_INT);
/* sync with the CUDA - assert TACK without TIP */
out_8(&via[B], in_8(&via[B]) & ~TACK);
@@ -282,7 +282,7 @@ cuda_init_via(void)
/* wait for the interrupt and then clear it */
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)");
(void)in_8(&via[SR]);
- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+ out_8(&via[IFR], SR_INT);
/* finish the sync by negating TACK */
out_8(&via[B], in_8(&via[B]) | TACK);
@@ -291,7 +291,7 @@ cuda_init_via(void)
WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)");
WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)");
(void)in_8(&via[SR]);
- out_8(&via[IFR], in_8(&via[IFR]) & 0x7f);
+ out_8(&via[IFR], SR_INT);
out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */
return 0;
@@ -428,16 +428,12 @@ cuda_start(void)
void
cuda_poll(void)
{
- unsigned long flags;
-
/* cuda_interrupt only takes a normal lock, we disable
* interrupts here to avoid re-entering and thus deadlocking.
- * An option would be to disable only the IRQ source with
- * disable_irq(), would that work on m68k ? --BenH
*/
- local_irq_save(flags);
+ disable_irq(cuda_irq);
cuda_interrupt(0, NULL);
- local_irq_restore(flags);
+ enable_irq(cuda_irq);
}
static irqreturn_t
@@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg)
unsigned char ibuf[16];
int ibuf_len = 0;
int complete = 0;
- unsigned char virq;
spin_lock(&cuda_lock);
- virq = in_8(&via[IFR]) & 0x7f;
- out_8(&via[IFR], virq);
- if ((virq & SR_INT) == 0) {
- spin_unlock(&cuda_lock);
- return IRQ_NONE;
+ /* On powermacs, this handler is registered for the VIA IRQ. But it uses
+ * just the shift register IRQ -- other VIA interrupt sources are disabled.
+ * On m68k macs, the VIA IRQ sources are dispatched individually. Unless
+ * we are polling, the shift register IRQ flag has already been cleared.
+ */
+
+#ifdef CONFIG_MAC
+ if (!arg)
+#endif
+ {
+ if ((in_8(&via[IFR]) & SR_INT) == 0) {
+ spin_unlock(&cuda_lock);
+ return IRQ_NONE;
+ } else {
+ out_8(&via[IFR], SR_INT);
+ }
}
status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT);
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 1b3bad62a1b..01b8eca7ccd 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -12,6 +12,15 @@
* 1999-08-02 (jmt) - Initial rewrite for Unified ADB.
* 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org>
* - Big overhaul, should actually work now.
+ * 2006-12-31 Finn Thain <fthain@telegraphics.com.au> - Another overhaul.
+ *
+ * Suggested reading:
+ * Inside Macintosh, ch. 5 ADB Manager
+ * Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus
+ * Rockwell R6522 VIA datasheet
+ *
+ * Apple's "ADB Analyzer" bus sniffer is invaluable:
+ * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/
*/
#include <stdarg.h>
@@ -26,7 +35,6 @@
#include <asm/macints.h>
#include <asm/machw.h>
#include <asm/mac_via.h>
-#include <asm/io.h>
#include <asm/system.h>
static volatile unsigned char *via;
@@ -51,9 +59,7 @@ static volatile unsigned char *via;
#define ANH (15*RS) /* A-side data, no handshake */
/* Bits in B data register: all active low */
-#define TREQ 0x08 /* Transfer request (input) */
-#define TACK 0x10 /* Transfer acknowledge (output) */
-#define TIP 0x20 /* Transfer in progress (output) */
+#define CTLR_IRQ 0x08 /* Controller rcv status (input) */
#define ST_MASK 0x30 /* mask for selecting ADB state bits */
/* Bits in ACR */
@@ -65,8 +71,6 @@ static volatile unsigned char *via;
#define IER_SET 0x80 /* set bits in IER */
#define IER_CLR 0 /* clear bits in IER */
#define SR_INT 0x04 /* Shift register full/empty */
-#define SR_DATA 0x08 /* Shift register data */
-#define SR_CLOCK 0x10 /* Shift register clock */
/* ADB transaction states according to GMHW */
#define ST_CMD 0x00 /* ADB state: command byte */
@@ -77,7 +81,6 @@ static volatile unsigned char *via;
static int macii_init_via(void);
static void macii_start(void);
static irqreturn_t macii_interrupt(int irq, void *arg);
-static void macii_retransmit(int);
static void macii_queue_poll(void);
static int macii_probe(void);
@@ -103,29 +106,37 @@ static enum macii_state {
sending,
reading,
read_done,
- awaiting_reply
} macii_state;
-static int need_poll;
-static int command_byte;
-static int last_reply;
-static int last_active;
-
-static struct adb_request *current_req;
-static struct adb_request *last_req;
-static struct adb_request *retry_req;
-static unsigned char reply_buf[16];
-static unsigned char *reply_ptr;
-static int reply_len;
-static int reading_reply;
-static int data_index;
-static int first_byte;
-static int prefix_len;
-static int status = ST_IDLE|TREQ;
-static int last_status;
-static int driver_running;
-
-/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */
+static struct adb_request *current_req; /* first request struct in the queue */
+static struct adb_request *last_req; /* last request struct in the queue */
+static unsigned char reply_buf[16]; /* storage for autopolled replies */
+static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */
+static int reading_reply; /* store reply in reply_buf else req->reply */
+static int data_index; /* index of the next byte to send from req->data */
+static int reply_len; /* number of bytes received in reply_buf or req->reply */
+static int status; /* VIA's ADB status bits captured upon interrupt */
+static int last_status; /* status bits as at previous interrupt */
+static int srq_asserted; /* have to poll for the device that asserted it */
+static int command_byte; /* the most recent command byte transmitted */
+static int autopoll_devs; /* bits set are device addresses to be polled */
+
+/* Sanity check for request queue. Doesn't check for cycles. */
+static int request_is_queued(struct adb_request *req) {
+ struct adb_request *cur;
+ unsigned long flags;
+ local_irq_save(flags);
+ cur = current_req;
+ while (cur) {
+ if (cur == req) {
+ local_irq_restore(flags);
+ return 1;
+ }
+ cur = cur->next;
+ }
+ local_irq_restore(flags);
+ return 0;
+}
/* Check for MacII style ADB */
static int macii_probe(void)
@@ -147,15 +158,16 @@ int macii_init(void)
local_irq_save(flags);
err = macii_init_via();
- if (err) return err;
+ if (err) goto out;
err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB",
macii_interrupt);
- if (err) return err;
+ if (err) goto out;
macii_state = idle;
+out:
local_irq_restore(flags);
- return 0;
+ return err;
}
/* initialize the hardware */
@@ -163,12 +175,12 @@ static int macii_init_via(void)
{
unsigned char x;
- /* Set the lines up. We want TREQ as input TACK|TIP as output */
- via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;
+ /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */
+ via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ;
/* Set up state: idle */
via[B] |= ST_IDLE;
- last_status = via[B] & (ST_MASK|TREQ);
+ last_status = via[B] & (ST_MASK|CTLR_IRQ);
/* Shift register on input */
via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;
@@ -179,81 +191,72 @@ static int macii_init_via(void)
return 0;
}
-/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */
+/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */
static void macii_queue_poll(void)
{
- static int device = 0;
- static int in_poll=0;
+ /* No point polling the active device as it will never assert SRQ, so
+ * poll the next device in the autopoll list. This could leave us
+ * stuck in a polling loop if an unprobed device is asserting SRQ.
+ * In theory, that could only happen if a device was plugged in after
+ * probing started. Unplugging it again will break the cycle.
+ * (Simply polling the next higher device often ends up polling almost
+ * every device (after wrapping around), which takes too long.)
+ */
+ int device_mask;
+ int next_device;
static struct adb_request req;
- unsigned long flags;
-
- if (in_poll) printk("macii_queue_poll: double poll!\n");
-
- in_poll++;
- if (++device > 15) device = 1;
-
- adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
- ADB_READREG(device, 0));
-
- local_irq_save(flags);
-
- req.next = current_req;
- current_req = &req;
- local_irq_restore(flags);
- macii_start();
- in_poll--;
-}
+ if (!autopoll_devs) return;
-/* Send an ADB retransmit (Talk, appended to the request queue) */
-static void macii_retransmit(int device)
-{
- static int in_retransmit = 0;
- static struct adb_request rt;
- unsigned long flags;
-
- if (in_retransmit) printk("macii_retransmit: double retransmit!\n");
+ device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1;
+ if (autopoll_devs & ~device_mask)
+ next_device = ffs(autopoll_devs & ~device_mask) - 1;
+ else
+ next_device = ffs(autopoll_devs) - 1;
- in_retransmit++;
+ BUG_ON(request_is_queued(&req));
- adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1,
- ADB_READREG(device, 0));
+ adb_request(&req, NULL, ADBREQ_NOSEND, 1,
+ ADB_READREG(next_device, 0));
- local_irq_save(flags);
+ req.sent = 0;
+ req.complete = 0;
+ req.reply_len = 0;
+ req.next = current_req;
if (current_req != NULL) {
- last_req->next = &rt;
- last_req = &rt;
+ current_req = &req;
} else {
- current_req = &rt;
- last_req = &rt;
+ current_req = &req;
+ last_req = &req;
}
-
- if (macii_state == idle) macii_start();
-
- local_irq_restore(flags);
- in_retransmit--;
}
/* Send an ADB request; if sync, poll out the reply 'till it's done */
static int macii_send_request(struct adb_request *req, int sync)
{
- int i;
+ int err;
+ unsigned long flags;
- i = macii_write(req);
- if (i) return i;
+ BUG_ON(request_is_queued(req));
- if (sync) {
- while (!req->complete) macii_poll();
+ local_irq_save(flags);
+ err = macii_write(req);
+ local_irq_restore(flags);
+
+ if (!err && sync) {
+ while (!req->complete) {
+ macii_poll();
+ }
+ BUG_ON(request_is_queued(req));
}
- return 0;
+
+ return err;
}
-/* Send an ADB request */
+/* Send an ADB request (append to request queue) */
static int macii_write(struct adb_request *req)
{
- unsigned long flags;
-
if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) {
req->complete = 1;
return -EINVAL;
@@ -264,8 +267,6 @@ static int macii_write(struct adb_request *req)
req->complete = 0;
req->reply_len = 0;
- local_irq_save(flags);
-
if (current_req != NULL) {
last_req->next = req;
last_req = req;
@@ -274,28 +275,52 @@ static int macii_write(struct adb_request *req)
last_req = req;
if (macii_state == idle) macii_start();
}
-
- local_irq_restore(flags);
return 0;
}
/* Start auto-polling */
static int macii_autopoll(int devs)
{
- /* Just ping a random default address */
- if (!(current_req || retry_req))
- macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3);
- return 0;
+ static struct adb_request req;
+ unsigned long flags;
+ int err = 0;
+
+ /* bit 1 == device 1, and so on. */
+ autopoll_devs = devs & 0xFFFE;
+
+ if (!autopoll_devs) return 0;
+
+ local_irq_save(flags);
+
+ if (current_req == NULL) {
+ /* Send a Talk Reg 0. The controller will repeatedly transmit
+ * this as long as it is idle.
+ */
+ adb_request(&req, NULL, ADBREQ_NOSEND, 1,
+ ADB_READREG(ffs(autopoll_devs) - 1, 0));
+ err = macii_write(&req);
+ }
+
+ local_irq_restore(flags);
+ return err;
+}
+
+static inline int need_autopoll(void) {
+ /* Was the last command Talk Reg 0
+ * and is the target on the autopoll list?
+ */
+ if ((command_byte & 0x0F) == 0x0C &&
+ ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs))
+ return 0;
+ return 1;
}
/* Prod the chip without interrupts */
static void macii_poll(void)
{
- unsigned long flags;
-
- local_irq_save(flags);
- if (via[IFR] & SR_INT) macii_interrupt(0, NULL);
- local_irq_restore(flags);
+ disable_irq(IRQ_MAC_ADB);
+ macii_interrupt(0, NULL);
+ enable_irq(IRQ_MAC_ADB);
}
/* Reset the bus */
@@ -303,73 +328,34 @@ static int macii_reset_bus(void)
{
static struct adb_request req;
+ if (request_is_queued(&req))
+ return 0;
+
/* Command = 0, Address = ignored */
adb_request(&req, NULL, 0, 1, ADB_BUSRESET);
+ /* Don't want any more requests during the Global Reset low time. */
+ udelay(3000);
+
return 0;
}
/* Start sending ADB packet */
static void macii_start(void)
{
- unsigned long flags;
struct adb_request *req;
req = current_req;
- if (!req) return;
-
- /* assert macii_state == idle */
- if (macii_state != idle) {
- printk("macii_start: called while driver busy (%p %x %x)!\n",
- req, macii_state, (uint) via1[B] & (ST_MASK|TREQ));
- return;
- }
- local_irq_save(flags);
-
- /*
- * IRQ signaled ?? (means ADB controller wants to send, or might
- * be end of packet if we were reading)
- */
-#if 0 /* FIXME: This is broke broke broke, for some reason */
- if ((via[B] & TREQ) == 0) {
- printk("macii_start: weird poll stuff. huh?\n");
- /*
- * FIXME - we need to restart this on a timer
- * or a collision at boot hangs us.
- * Never set macii_state to idle here, or macii_start
- * won't be called again from send_request!
- * (need to re-check other cases ...)
- */
- /*
- * if the interrupt handler set the need_poll
- * flag, it's hopefully a SRQ poll or re-Talk
- * so we try to send here anyway
- */
- if (!need_poll) {
- if (console_loglevel == 10)
- printk("macii_start: device busy - retry %p state %d status %x!\n",
- req, macii_state,
- (uint) via[B] & (ST_MASK|TREQ));
- retry_req = req;
- /* set ADB status here ? */
- local_irq_restore(flags);
- return;
- } else {
- need_poll = 0;
- }
- }
-#endif
- /*
- * Another retry pending? (sanity check)
+ BUG_ON(req == NULL);
+
+ BUG_ON(macii_state != idle);
+
+ /* Now send it. Be careful though, that first byte of the request
+ * is actually ADB_PACKET; the real data begins at index 1!
+ * And req->nbytes is the number of bytes of real data plus one.
*/
- if (retry_req) {
- retry_req = NULL;
- }
- /* Now send it. Be careful though, that first byte of the request */
- /* is actually ADB_PACKET; the real data begins at index 1! */
-
/* store command byte */
command_byte = req->data[1];
/* Output mode */
@@ -381,115 +367,97 @@ static void macii_start(void)
macii_state = sending;
data_index = 2;
-
- local_irq_restore(flags);
}
/*
- * The notorious ADB interrupt handler - does all of the protocol handling,
- * except for starting new send operations. Relies heavily on the ADB
- * controller sending and receiving data, thereby generating SR interrupts
- * for us. This means there has to be always activity on the ADB bus, otherwise
- * the whole process dies and has to be re-kicked by sending TALK requests ...
- * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type
- * ADB the problem isn't solved yet (retransmit of the latest active TALK seems
- * a good choice; either on timeout or on a timer interrupt).
+ * The notorious ADB interrupt handler - does all of the protocol handling.
+ * Relies on the ADB controller sending and receiving data, thereby
+ * generating shift register interrupts (SR_INT) for us. This means there has
+ * to be activity on the ADB bus. The chip will poll to achieve this.
*
* The basic ADB state machine was left unchanged from the original MacII code
* by Alan Cox, which was based on the CUDA driver for PowerMac.
- * The syntax of the ADB status lines seems to be totally different on MacII,
- * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for
- * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start
- * and end of a receive packet are signaled by asserting /IRQ on the interrupt
- * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on
- * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the
- * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB
- * protocol with a logic analyzer!!)
- *
- * Note: As of 21/10/97, the MacII ADB part works including timeout detection
- * and retransmit (Talk to the last active device).
+ * The syntax of the ADB status lines is totally different on MacII,
+ * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle
+ * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving.
+ * Start and end of a receive packet are signalled by asserting /IRQ on the
+ * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused
+ * with the VIA shift register interrupt. /IRQ never actually interrupts the
+ * processor, it's just an ordinary input.)
*/
static irqreturn_t macii_interrupt(int irq, void *arg)
{
- int x, adbdir;
- unsigned long flags;
+ int x;
+ static int entered;
struct adb_request *req;
- last_status = status;
-
- /* prevent races due to SCSI enabling ints */
- local_irq_save(flags);
-
- if (driver_running) {
- local_irq_restore(flags);
- return IRQ_NONE;
+ if (!arg) {
+ /* Clear the SR IRQ flag when polling. */
+ if (via[IFR] & SR_INT)
+ via[IFR] = SR_INT;
+ else
+ return IRQ_NONE;
}
- driver_running = 1;
-
- status = via[B] & (ST_MASK|TREQ);
- adbdir = via[ACR] & SR_OUT;
+ BUG_ON(entered++);
+
+ last_status = status;
+ status = via[B] & (ST_MASK|CTLR_IRQ);
switch (macii_state) {
case idle:
+ if (reading_reply) {
+ reply_ptr = current_req->reply;
+ } else {
+ BUG_ON(current_req != NULL);
+ reply_ptr = reply_buf;
+ }
+
x = via[SR];
- first_byte = x;
- /* set ADB state = even for first data byte */
- via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
- reply_buf[0] = first_byte; /* was command_byte?? */
- reply_ptr = reply_buf + 1;
- reply_len = 1;
- prefix_len = 1;
- reading_reply = 0;
-
- macii_state = reading;
- break;
+ if ((status & CTLR_IRQ) && (x == 0xFF)) {
+ /* Bus timeout without SRQ sequence:
+ * data is "FF" while CTLR_IRQ is "H"
+ */
+ reply_len = 0;
+ srq_asserted = 0;
+ macii_state = read_done;
+ } else {
+ macii_state = reading;
+ *reply_ptr = x;
+ reply_len = 1;
+ }
- case awaiting_reply:
- /* handshake etc. for II ?? */
- x = via[SR];
- first_byte = x;
/* set ADB state = even for first data byte */
via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
-
- current_req->reply[0] = first_byte;
- reply_ptr = current_req->reply + 1;
- reply_len = 1;
- prefix_len = 1;
- reading_reply = 1;
-
- macii_state = reading;
break;
case sending:
req = current_req;
if (data_index >= req->nbytes) {
- /* print an error message if a listen command has no data */
- if (((command_byte & 0x0C) == 0x08)
- /* && (console_loglevel == 10) */
- && (data_index == 2))
- printk("MacII ADB: listen command with no data: %x!\n",
- command_byte);
- /* reset to shift in */
- via[ACR] &= ~SR_OUT;
- x = via[SR];
- /* set ADB state idle - might get SRQ */
- via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
-
req->sent = 1;
+ macii_state = idle;
if (req->reply_expected) {
- macii_state = awaiting_reply;
+ reading_reply = 1;
} else {
req->complete = 1;
current_req = req->next;
if (req->done) (*req->done)(req);
- macii_state = idle;
- if (current_req || retry_req)
+
+ if (current_req)
macii_start();
else
- macii_retransmit((command_byte & 0xF0) >> 4);
+ if (need_autopoll())
+ macii_autopoll(autopoll_devs);
+ }
+
+ if (macii_state == idle) {
+ /* reset to shift in */
+ via[ACR] &= ~SR_OUT;
+ x = via[SR];
+ /* set ADB state idle - might get SRQ */
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
}
} else {
via[SR] = req->data[data_index++];
@@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int irq, void *arg)
break;
case reading:
+ x = via[SR];
+ BUG_ON((status & ST_MASK) == ST_CMD ||
+ (status & ST_MASK) == ST_IDLE);
+
+ /* Bus timeout with SRQ sequence:
+ * data is "XX FF" while CTLR_IRQ is "L L"
+ * End of packet without SRQ sequence:
+ * data is "XX...YY 00" while CTLR_IRQ is "L...H L"
+ * End of packet SRQ sequence:
+ * data is "XX...YY 00" while CTLR_IRQ is "L...L L"
+ * (where XX is the first response byte and
+ * YY is the last byte of valid response data.)
+ */
- /* timeout / SRQ handling for II hw */
- if( (first_byte == 0xFF && (reply_len-prefix_len)==2
- && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) ||
- ((reply_len-prefix_len)==3
- && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0))
- {
- /*
- * possible timeout (in fact, most probably a
- * timeout, since SRQ can't be signaled without
- * transfer on the bus).
- * The last three bytes seen were FF, together
- * with the starting byte (in case we started
- * on 'idle' or 'awaiting_reply') this probably
- * makes four. So this is mostl likely #5!
- * The timeout signal is a pattern 1 0 1 0 0..
- * on /INT, meaning we missed it :-(
- */
- x = via[SR];
- if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n");
-
- if ((status & TREQ) == (last_status & TREQ)) {
- /* Not a timeout. Unsolicited SRQ? weird. */
- /* Terminate the SRQ packet and poll */
- need_poll = 1;
+ srq_asserted = 0;
+ if (!(status & CTLR_IRQ)) {
+ if (x == 0xFF) {
+ if (!(last_status & CTLR_IRQ)) {
+ macii_state = read_done;
+ reply_len = 0;
+ srq_asserted = 1;
+ }
+ } else if (x == 0x00) {
+ macii_state = read_done;
+ if (!(last_status & CTLR_IRQ))
+ srq_asserted = 1;
}
- /* There's no packet to get, so reply is blank */
- via[B] ^= ST_MASK;
- reply_ptr -= (reply_len-prefix_len);
- reply_len = prefix_len;
- macii_state = read_done;
- break;
- } /* end timeout / SRQ handling for II hw. */
-
- if((reply_len-prefix_len)>3
- && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)
- {
- /* SRQ tacked on data packet */
- /* Terminate the packet (SRQ never ends) */
- x = via[SR];
- macii_state = read_done;
- reply_len -= 3;
- reply_ptr -= 3;
- need_poll = 1;
- /* need to continue; next byte not seen else */
- } else {
- /* Sanity check */
- if (reply_len > 15) reply_len = 0;
- /* read byte */
- x = via[SR];
- *reply_ptr = x;
+ }
+
+ if (macii_state == reading) {
+ BUG_ON(reply_len > 15);
reply_ptr++;
+ *reply_ptr = x;
reply_len++;
}
- /* The usual handshake ... */
-
- /*
- * NetBSD hints that the next to last byte
- * is sent with IRQ !!
- * Guido found out it's the last one (0x0),
- * but IRQ should be asserted already.
- * Problem with timeout detection: First
- * transition to /IRQ might be second
- * byte of timeout packet!
- * Timeouts are signaled by 4x FF.
- */
- if (((status & TREQ) == 0) && (x == 0x00)) { /* != 0xFF */
- /* invert state bits, toggle ODD/EVEN */
- via[B] ^= ST_MASK;
- /* adjust packet length */
- reply_len--;
- reply_ptr--;
- macii_state = read_done;
- } else {
- /* not caught: ST_CMD */
- /* required for re-entry 'reading'! */
- if ((status & ST_MASK) == ST_IDLE) {
- /* (in)sanity check - set even */
- via[B] = (via[B] & ~ST_MASK) | ST_EVEN;
- } else {
- /* invert state bits */
- via[B] ^= ST_MASK;
- }
- }
+ /* invert state bits, toggle ODD/EVEN */
+ via[B] ^= ST_MASK;
break;
case read_done:
x = via[SR];
+
if (reading_reply) {
+ reading_reply = 0;
req = current_req;
- req->reply_len = reply_ptr - req->reply;
+ req->reply_len = reply_len;
req->complete = 1;
current_req = req->next;
if (req->done) (*req->done)(req);
- } else {
- adb_input(reply_buf, reply_ptr - reply_buf, 0);
- }
+ } else if (reply_len && autopoll_devs)
+ adb_input(reply_buf, reply_len, 0);
- /*
- * remember this device ID; it's the latest we got a
- * reply from!
- */
- last_reply = command_byte;
- last_active = (command_byte & 0xF0) >> 4;
+ macii_state = idle;
/* SRQ seen before, initiate poll now */
- if (need_poll) {
- macii_state = idle;
+ if (srq_asserted)
macii_queue_poll();
- need_poll = 0;
- break;
- }
-
- /* set ADB state to idle */
- via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
-
- /* /IRQ seen, so the ADB controller has data for us */
- if ((via[B] & TREQ) != 0) {
- macii_state = reading;
- reply_buf[0] = command_byte;
- reply_ptr = reply_buf + 1;
- reply_len = 1;
- prefix_len = 1;
- reading_reply = 0;
- } else {
- /* no IRQ, send next packet or wait */
- macii_state = idle;
- if (current_req)
- macii_start();
- else
- macii_retransmit(last_active);
- }
+ if (current_req)
+ macii_start();
+ else
+ if (need_autopoll())
+ macii_autopoll(autopoll_devs);
+
+ if (macii_state == idle)
+ via[B] = (via[B] & ~ST_MASK) | ST_IDLE;
break;
default:
break;
}
- /* reset mutex and interrupts */
- driver_running = 0;
- local_irq_restore(flags);
+
+ entered--;
return IRQ_HANDLED;
}
diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
index 179af10105d..55ad9567138 100644
--- a/drivers/macintosh/via-pmu-led.c
+++ b/drivers/macintosh/via-pmu-led.c
@@ -31,7 +31,6 @@ static spinlock_t pmu_blink_lock;
static struct adb_request pmu_blink_req;
/* -1: no change, 0: request off, 1: request on */
static int requested_change;
-static int sleeping;
static void pmu_req_done(struct adb_request * req)
{
@@ -41,7 +40,7 @@ static void pmu_req_done(struct adb_request * req)
/* if someone requested a change in the meantime
* (we only see the last one which is fine)
* then apply it now */
- if (requested_change != -1 && !sleeping)
+ if (requested_change != -1 && !pmu_sys_suspended)
pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
/* reset requested change */
requested_change = -1;
@@ -66,7 +65,7 @@ static void pmu_led_set(struct led_classdev *led_cdev,
break;
}
/* if request isn't done, then don't do anything */
- if (pmu_blink_req.complete && !sleeping)
+ if (pmu_blink_req.complete && !pmu_sys_suspended)
pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
out:
spin_unlock_irqrestore(&pmu_blink_lock, flags);
@@ -80,34 +79,6 @@ static struct led_classdev pmu_led = {
.brightness_set = pmu_led_set,
};
-#ifdef CONFIG_PM
-static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pmu_blink_lock, flags);
-
- switch (when) {
- case PBOOK_SLEEP_REQUEST:
- sleeping = 1;
- break;
- case PBOOK_WAKE:
- sleeping = 0;
- break;
- default:
- /* do nothing */
- break;
- }
- spin_unlock_irqrestore(&pmu_blink_lock, flags);
-
- return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier via_pmu_led_sleep_notif = {
- .notifier_call = pmu_led_sleep_call,
-};
-#endif
-
static int __init via_pmu_led_init(void)
{
struct device_node *dt;
@@ -120,11 +91,13 @@ static int __init via_pmu_led_init(void)
dt = of_find_node_by_path("/");
if (dt == NULL)
return -ENODEV;
- model = get_property(dt, "model", NULL);
+ model = of_get_property(dt, "model", NULL);
if (model == NULL)
return -ENODEV;
if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
- strncmp(model, "iBook", strlen("iBook")) != 0) {
+ strncmp(model, "iBook", strlen("iBook")) != 0 &&
+ strcmp(model, "PowerMac7,2") != 0 &&
+ strcmp(model, "PowerMac7,3") != 0) {
of_node_put(dt);
/* ignore */
return -ENODEV;
@@ -135,9 +108,7 @@ static int __init via_pmu_led_init(void)
/* no outstanding req */
pmu_blink_req.complete = 1;
pmu_blink_req.done = pmu_req_done;
-#ifdef CONFIG_PM
- pmu_register_sleep_notifier(&via_pmu_led_sleep_notif);
-#endif
+
return led_classdev_register(NULL, &pmu_led);
}
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b6073bdb50c..157080b3b46 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -289,7 +289,7 @@ int __init find_via_pmu(void)
if (vias == NULL)
return 0;
- reg = get_property(vias, "reg", NULL);
+ reg = of_get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
goto fail;
@@ -310,19 +310,22 @@ int __init find_via_pmu(void)
PMU_INT_TICK;
if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
- || device_is_compatible(vias->parent, "ohare")))
+ || of_device_is_compatible(vias->parent, "ohare")))
pmu_kind = PMU_OHARE_BASED;
- else if (device_is_compatible(vias->parent, "paddington"))
+ else if (of_device_is_compatible(vias->parent, "paddington"))
pmu_kind = PMU_PADDINGTON_BASED;
- else if (device_is_compatible(vias->parent, "heathrow"))
+ else if (of_device_is_compatible(vias->parent, "heathrow"))
pmu_kind = PMU_HEATHROW_BASED;
- else if (device_is_compatible(vias->parent, "Keylargo")
- || device_is_compatible(vias->parent, "K2-Keylargo")) {
+ else if (of_device_is_compatible(vias->parent, "Keylargo")
+ || of_device_is_compatible(vias->parent, "K2-Keylargo")) {
struct device_node *gpiop;
+ struct device_node *adbp;
u64 gaddr = OF_BAD_ADDR;
pmu_kind = PMU_KEYLARGO_BASED;
- pmu_has_adb = (find_type_devices("adb") != NULL);
+ adbp = of_find_node_by_type(NULL, "adb");
+ pmu_has_adb = (adbp != NULL);
+ of_node_put(adbp);
pmu_intr_mask = PMU_INT_PCEJECT |
PMU_INT_SNDBRT |
PMU_INT_ADB |
@@ -331,7 +334,7 @@ int __init find_via_pmu(void)
gpiop = of_find_node_by_name(NULL, "gpio");
if (gpiop) {
- reg = get_property(gpiop, "reg", NULL);
+ reg = of_get_property(gpiop, "reg", NULL);
if (reg)
gaddr = of_translate_address(gpiop, reg);
if (gaddr != OF_BAD_ADDR)
@@ -484,10 +487,11 @@ static int __init via_pmu_dev_init(void)
pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
} else {
- struct device_node* prim = find_devices("power-mgt");
+ struct device_node* prim =
+ of_find_node_by_name(NULL, "power-mgt");
const u32 *prim_info = NULL;
if (prim)
- prim_info = get_property(prim, "prim-info", NULL);
+ prim_info = of_get_property(prim, "prim-info", NULL);
if (prim_info) {
/* Other stuffs here yet unknown */
pmu_battery_count = (prim_info[6] >> 16) & 0xff;
@@ -495,6 +499,7 @@ static int __init via_pmu_dev_init(void)
if (pmu_battery_count > 1)
pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
}
+ of_node_put(prim);
}
#endif /* CONFIG_PPC32 */
@@ -1769,35 +1774,21 @@ EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
/* Sleep is broadcast last-to-first */
-static int
-broadcast_sleep(int when, int fallback)
+static void broadcast_sleep(int when)
{
- int ret = PBOOK_SLEEP_OK;
struct list_head *list;
struct pmu_sleep_notifier *notifier;
for (list = sleep_notifiers.prev; list != &sleep_notifiers;
list = list->prev) {
notifier = list_entry(list, struct pmu_sleep_notifier, list);
- ret = notifier->notifier_call(notifier, when);
- if (ret != PBOOK_SLEEP_OK) {
- printk(KERN_DEBUG "sleep %d rejected by %p (%p)\n",
- when, notifier, notifier->notifier_call);
- for (; list != &sleep_notifiers; list = list->next) {
- notifier = list_entry(list, struct pmu_sleep_notifier, list);
- notifier->notifier_call(notifier, fallback);
- }
- return ret;
- }
+ notifier->notifier_call(notifier, when);
}
- return ret;
}
/* Wake is broadcast first-to-last */
-static int
-broadcast_wake(void)
+static void broadcast_wake(void)
{
- int ret = PBOOK_SLEEP_OK;
struct list_head *list;
struct pmu_sleep_notifier *notifier;
@@ -1806,7 +1797,6 @@ broadcast_wake(void)
notifier = list_entry(list, struct pmu_sleep_notifier, list);
notifier->notifier_call(notifier, PBOOK_WAKE);
}
- return ret;
}
/*
@@ -2013,12 +2003,8 @@ pmac_suspend_devices(void)
pm_prepare_console();
- /* Notify old-style device drivers & userland */
- ret = broadcast_sleep(PBOOK_SLEEP_REQUEST, PBOOK_SLEEP_REJECT);
- if (ret != PBOOK_SLEEP_OK) {
- printk(KERN_ERR "Sleep rejected by drivers\n");
- return -EBUSY;
- }
+ /* Notify old-style device drivers */
+ broadcast_sleep(PBOOK_SLEEP_REQUEST);
/* Sync the disks. */
/* XXX It would be nice to have some way to ensure that
@@ -2028,12 +2014,7 @@ pmac_suspend_devices(void)
*/
sys_sync();
- /* Sleep can fail now. May not be very robust but useful for debugging */
- ret = broadcast_sleep(PBOOK_SLEEP_NOW, PBOOK_WAKE);
- if (ret != PBOOK_SLEEP_OK) {
- printk(KERN_ERR "Driver sleep failed\n");
- return -EBUSY;
- }
+ broadcast_sleep(PBOOK_SLEEP_NOW);
/* Send suspend call to devices, hold the device core's dpm_sem */
ret = device_suspend(PMSG_SUSPEND);
@@ -2154,7 +2135,7 @@ static int powerbook_sleep_grackle(void)
int ret;
struct pci_dev *grackle;
- grackle = pci_find_slot(0, 0);
+ grackle = pci_get_bus_and_slot(0, 0);
if (!grackle)
return -ENODEV;
@@ -2202,6 +2183,8 @@ static int powerbook_sleep_grackle(void)
pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
pci_write_config_word(grackle, 0x70, pmcr1);
+ pci_dev_put(grackle);
+
/* Make sure the PMU is idle */
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
restore_via_state();
@@ -2776,7 +2759,7 @@ pmu_polled_request(struct adb_request *req)
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
-static int pmu_sys_suspended;
+int pmu_sys_suspended;
static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
{
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index 356c7216a17..dfdf11c1eec 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -111,7 +111,6 @@ static int pmu_send_request(struct adb_request *req, int sync);
static int pmu_autopoll(int devs);
void pmu_poll(void);
static int pmu_reset_bus(void);
-static int pmu_queue_request(struct adb_request *req);
static void pmu_start(void);
static void send_byte(int x);
@@ -475,7 +474,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
return pmu_queue_request(req);
}
-static int
+int
pmu_queue_request(struct adb_request *req)
{
unsigned long flags;
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 94c117ef20c..192b26e9777 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <linux/jiffies.h>
#include <linux/reboot.h>
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 3f7967feaf5..a0fabf3c200 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -176,7 +176,7 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
for (dev = NULL;
(dev = of_get_next_child(busnode, dev)) != NULL;) {
const char *loc =
- get_property(dev, "hwsensor-location", NULL);
+ of_get_property(dev, "hwsensor-location", NULL);
u8 addr;
/* We must re-match the adapter in order to properly check
@@ -188,10 +188,10 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
if (loc == NULL || addr == 0)
continue;
/* real lm75 */
- if (device_is_compatible(dev, "lm75"))
+ if (of_device_is_compatible(dev, "lm75"))
wf_lm75_create(adapter, addr, 0, loc);
/* ds1775 (compatible, better resolution */
- else if (device_is_compatible(dev, "ds1775"))
+ else if (of_device_is_compatible(dev, "ds1775"))
wf_lm75_create(adapter, addr, 1, loc);
}
return 0;
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index eae1189d6c4..5f03aab9fb5 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -131,10 +131,10 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
*/
if (!pmac_i2c_match_adapter(dev, adapter))
continue;
- if (!device_is_compatible(dev, "max6690"))
+ if (!of_device_is_compatible(dev, "max6690"))
continue;
addr = pmac_i2c_get_dev_addr(dev);
- loc = get_property(dev, "hwsensor-location", NULL);
+ loc = of_get_property(dev, "hwsensor-location", NULL);
if (loc == NULL || addr == 0)
continue;
printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 31b750d6120..58c2590f05e 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -167,7 +167,7 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
if (fct == NULL)
return NULL;
fct->ctrl.ops = &smu_fan_ops;
- l = get_property(node, "location", NULL);
+ l = of_get_property(node, "location", NULL);
if (l == NULL)
goto fail;
@@ -224,17 +224,17 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
goto fail;
/* Get min & max values*/
- v = get_property(node, "min-value", NULL);
+ v = of_get_property(node, "min-value", NULL);
if (v == NULL)
goto fail;
fct->min = *v;
- v = get_property(node, "max-value", NULL);
+ v = of_get_property(node, "max-value", NULL);
if (v == NULL)
goto fail;
fct->max = *v;
/* Get "reg" value */
- reg = get_property(node, "reg", NULL);
+ reg = of_get_property(node, "reg", NULL);
if (reg == NULL)
goto fail;
fct->reg = *reg;
@@ -263,7 +263,7 @@ static int __init smu_controls_init(void)
/* Look for RPM fans */
for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
if (!strcmp(fans->name, "rpm-fans") ||
- device_is_compatible(fans, "smu-rpm-fans"))
+ of_device_is_compatible(fans, "smu-rpm-fans"))
break;
for (fan = NULL;
fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 83f79de7174..1043b39aa12 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -241,7 +241,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
char *name;
int vsens[2], isens[2];
- reg = get_property(dev, "reg", NULL);
+ reg = of_get_property(dev, "reg", NULL);
if (reg == NULL)
return;
addr = *reg;
@@ -268,9 +268,9 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
isens[0] = isens[1] = -1;
child = NULL;
while ((child = of_get_next_child(dev, child)) != NULL) {
- reg = get_property(child, "reg", NULL);
- type = get_property(child, "device_type", NULL);
- loc = get_property(child, "location", NULL);
+ reg = of_get_property(child, "reg", NULL);
+ type = of_get_property(child, "device_type", NULL);
+ loc = of_get_property(child, "location", NULL);
if (reg == NULL || loc == NULL)
continue;
@@ -380,7 +380,7 @@ static int wf_sat_attach(struct i2c_adapter *adapter)
busnode = pmac_i2c_get_bus_node(bus);
while ((dev = of_get_next_child(busnode, dev)) != NULL)
- if (device_is_compatible(dev, "smu-sat"))
+ if (of_device_is_compatible(dev, "smu-sat"))
wf_sat_create(adapter, dev);
return 0;
}
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index 01b4c50143d..9c567b93f41 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -204,8 +204,8 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
if (ads == NULL)
return NULL;
- c = get_property(node, "device_type", NULL);
- l = get_property(node, "location", NULL);
+ c = of_get_property(node, "device_type", NULL);
+ l = of_get_property(node, "location", NULL);
if (c == NULL || l == NULL)
goto fail;
@@ -255,7 +255,7 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
} else
goto fail;
- v = get_property(node, "reg", NULL);
+ v = of_get_property(node, "reg", NULL);
if (v == NULL)
goto fail;
ads->reg = *v;
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
index da862e4632d..67b8e9453b1 100644
--- a/drivers/mca/mca-bus.c
+++ b/drivers/mca/mca-bus.c
@@ -47,19 +47,25 @@ static int mca_bus_match (struct device *dev, struct device_driver *drv)
{
struct mca_device *mca_dev = to_mca_device (dev);
struct mca_driver *mca_drv = to_mca_driver (drv);
- const short *mca_ids = mca_drv->id_table;
- int i;
-
- if (!mca_ids)
- return 0;
-
- for(i = 0; mca_ids[i]; i++) {
- if (mca_ids[i] == mca_dev->pos_id) {
- mca_dev->index = i;
- return 1;
+ const unsigned short *mca_ids = mca_drv->id_table;
+ int i = 0;
+
+ if (mca_ids) {
+ for(i = 0; mca_ids[i]; i++) {
+ if (mca_ids[i] == mca_dev->pos_id) {
+ mca_dev->index = i;
+ return 1;
+ }
}
}
-
+ /* If the integrated id is present, treat it as though it were an
+ * additional id in the id_table (it can't be because by definition,
+ * integrated id's overflow a short */
+ if (mca_drv->integrated_id && mca_dev->pos_id ==
+ mca_drv->integrated_id) {
+ mca_dev->index = i;
+ return 1;
+ }
return 0;
}
diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c
index 2223466b3d8..32cd39bcc71 100644
--- a/drivers/mca/mca-driver.c
+++ b/drivers/mca/mca-driver.c
@@ -36,12 +36,25 @@ int mca_register_driver(struct mca_driver *mca_drv)
mca_drv->driver.bus = &mca_bus_type;
if ((r = driver_register(&mca_drv->driver)) < 0)
return r;
+ mca_drv->integrated_id = 0;
}
return 0;
}
EXPORT_SYMBOL(mca_register_driver);
+int mca_register_driver_integrated(struct mca_driver *mca_driver,
+ int integrated_id)
+{
+ int r = mca_register_driver(mca_driver);
+
+ if (!r)
+ mca_driver->integrated_id = integrated_id;
+
+ return r;
+}
+EXPORT_SYMBOL(mca_register_driver_integrated);
+
void mca_unregister_driver(struct mca_driver *mca_drv)
{
if (MCA_bus)
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 4540ade6b6b..7df934d6913 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -262,6 +262,15 @@ config DM_MULTIPATH_EMC
---help---
Multipath support for EMC CX/AX series hardware.
+config DM_DELAY
+ tristate "I/O delaying target (EXPERIMENTAL)"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+ ---help---
+ A target that delays reads and/or writes and can send
+ them to different devices. Useful for testing.
+
+ If unsure, say N.
+
endmenu
endif
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 34957a68d92..38754084eac 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MD_FAULTY) += faulty.o
obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o
obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
+obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.o
obj-$(CONFIG_DM_SNAPSHOT) += dm-snapshot.o
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index e61e0efe9ec..5a4a74c1097 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1456,10 +1456,10 @@ int bitmap_create(mddev_t *mddev)
bitmap->offset = mddev->bitmap_offset;
if (file) {
get_file(file);
- do_sync_file_range(file, 0, LLONG_MAX,
- SYNC_FILE_RANGE_WAIT_BEFORE |
- SYNC_FILE_RANGE_WRITE |
- SYNC_FILE_RANGE_WAIT_AFTER);
+ do_sync_mapping_range(file->f_mapping, 0, LLONG_MAX,
+ SYNC_FILE_RANGE_WAIT_BEFORE |
+ SYNC_FILE_RANGE_WRITE |
+ SYNC_FILE_RANGE_WAIT_AFTER);
}
/* read superblock from bitmap file (this sets bitmap->chunksize) */
err = bitmap_read_sb(bitmap);
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index da4349649f7..c6be88826fa 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -8,17 +8,43 @@
#define DM_BIO_LIST_H
#include <linux/bio.h>
+#include <linux/prefetch.h>
struct bio_list {
struct bio *head;
struct bio *tail;
};
+static inline int bio_list_empty(const struct bio_list *bl)
+{
+ return bl->head == NULL;
+}
+
+#define BIO_LIST_INIT { .head = NULL, .tail = NULL }
+
+#define BIO_LIST(bl) \
+ struct bio_list bl = BIO_LIST_INIT
+
static inline void bio_list_init(struct bio_list *bl)
{
bl->head = bl->tail = NULL;
}
+#define bio_list_for_each(bio, bl) \
+ for (bio = (bl)->head; bio && ({ prefetch(bio->bi_next); 1; }); \
+ bio = bio->bi_next)
+
+static inline unsigned bio_list_size(const struct bio_list *bl)
+{
+ unsigned sz = 0;
+ struct bio *bio;
+
+ bio_list_for_each(bio, bl)
+ sz++;
+
+ return sz;
+}
+
static inline void bio_list_add(struct bio_list *bl, struct bio *bio)
{
bio->bi_next = NULL;
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 4c2471ee054..7b0fcfc9eaa 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -33,7 +33,6 @@
struct crypt_io {
struct dm_target *target;
struct bio *base_bio;
- struct bio *first_clone;
struct work_struct work;
atomic_t pending;
int error;
@@ -107,6 +106,8 @@ struct crypt_config {
static struct kmem_cache *_crypt_io_pool;
+static void clone_init(struct crypt_io *, struct bio *);
+
/*
* Different IV generation algorithms:
*
@@ -120,6 +121,9 @@ static struct kmem_cache *_crypt_io_pool;
* benbi: the 64-bit "big-endian 'narrow block'-count", starting at 1
* (needed for LRW-32-AES and possible other narrow block modes)
*
+ * null: the initial vector is always zero. Provides compatibility with
+ * obsolete loop_fish2 devices. Do not use for new devices.
+ *
* plumb: unimplemented, see:
* http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
*/
@@ -256,6 +260,13 @@ static int crypt_iv_benbi_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
return 0;
}
+static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+ memset(iv, 0, cc->iv_size);
+
+ return 0;
+}
+
static struct crypt_iv_operations crypt_iv_plain_ops = {
.generator = crypt_iv_plain_gen
};
@@ -272,6 +283,10 @@ static struct crypt_iv_operations crypt_iv_benbi_ops = {
.generator = crypt_iv_benbi_gen
};
+static struct crypt_iv_operations crypt_iv_null_ops = {
+ .generator = crypt_iv_null_gen
+};
+
static int
crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
struct scatterlist *in, unsigned int length,
@@ -378,36 +393,21 @@ static int crypt_convert(struct crypt_config *cc,
* This should never violate the device limitations
* May return a smaller bio when running out of pages
*/
-static struct bio *
-crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
- struct bio *base_bio, unsigned int *bio_vec_idx)
+static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int size)
{
+ struct crypt_config *cc = io->target->private;
struct bio *clone;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
unsigned int i;
- if (base_bio) {
- clone = bio_alloc_bioset(GFP_NOIO, base_bio->bi_max_vecs, cc->bs);
- __bio_clone(clone, base_bio);
- } else
- clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
-
+ clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
if (!clone)
return NULL;
- clone->bi_destructor = dm_crypt_bio_destructor;
-
- /* if the last bio was not complete, continue where that one ended */
- clone->bi_idx = *bio_vec_idx;
- clone->bi_vcnt = *bio_vec_idx;
- clone->bi_size = 0;
- clone->bi_flags &= ~(1 << BIO_SEG_VALID);
-
- /* clone->bi_idx pages have already been allocated */
- size -= clone->bi_idx * PAGE_SIZE;
+ clone_init(io, clone);
- for (i = clone->bi_idx; i < nr_iovecs; i++) {
+ for (i = 0; i < nr_iovecs; i++) {
struct bio_vec *bv = bio_iovec_idx(clone, i);
bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
@@ -419,7 +419,7 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
* return a partially allocated bio, the caller will then try
* to allocate additional bios while submitting this partial bio
*/
- if ((i - clone->bi_idx) == (MIN_BIO_PAGES - 1))
+ if (i == (MIN_BIO_PAGES - 1))
gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
bv->bv_offset = 0;
@@ -438,12 +438,6 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
return NULL;
}
- /*
- * Remember the last bio_vec allocated to be able
- * to correctly continue after the splitting.
- */
- *bio_vec_idx = clone->bi_vcnt;
-
return clone;
}
@@ -495,9 +489,6 @@ static void dec_pending(struct crypt_io *io, int error)
if (!atomic_dec_and_test(&io->pending))
return;
- if (io->first_clone)
- bio_put(io->first_clone);
-
bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
mempool_free(io, cc->io_pool);
@@ -562,6 +553,7 @@ static void clone_init(struct crypt_io *io, struct bio *clone)
clone->bi_end_io = crypt_endio;
clone->bi_bdev = cc->dev->bdev;
clone->bi_rw = io->base_bio->bi_rw;
+ clone->bi_destructor = dm_crypt_bio_destructor;
}
static void process_read(struct crypt_io *io)
@@ -585,7 +577,6 @@ static void process_read(struct crypt_io *io)
}
clone_init(io, clone);
- clone->bi_destructor = dm_crypt_bio_destructor;
clone->bi_idx = 0;
clone->bi_vcnt = bio_segments(base_bio);
clone->bi_size = base_bio->bi_size;
@@ -604,7 +595,6 @@ static void process_write(struct crypt_io *io)
struct convert_context ctx;
unsigned remaining = base_bio->bi_size;
sector_t sector = base_bio->bi_sector - io->target->begin;
- unsigned bvec_idx = 0;
atomic_inc(&io->pending);
@@ -615,14 +605,14 @@ static void process_write(struct crypt_io *io)
* so repeat the whole process until all the data can be handled.
*/
while (remaining) {
- clone = crypt_alloc_buffer(cc, base_bio->bi_size,
- io->first_clone, &bvec_idx);
+ clone = crypt_alloc_buffer(io, remaining);
if (unlikely(!clone)) {
dec_pending(io, -ENOMEM);
return;
}
ctx.bio_out = clone;
+ ctx.idx_out = 0;
if (unlikely(crypt_convert(cc, &ctx) < 0)) {
crypt_free_buffer_pages(cc, clone, clone->bi_size);
@@ -631,31 +621,26 @@ static void process_write(struct crypt_io *io)
return;
}
- clone_init(io, clone);
- clone->bi_sector = cc->start + sector;
-
- if (!io->first_clone) {
- /*
- * hold a reference to the first clone, because it
- * holds the bio_vec array and that can't be freed
- * before all other clones are released
- */
- bio_get(clone);
- io->first_clone = clone;
- }
+ /* crypt_convert should have filled the clone bio */
+ BUG_ON(ctx.idx_out < clone->bi_vcnt);
+ clone->bi_sector = cc->start + sector;
remaining -= clone->bi_size;
sector += bio_sectors(clone);
- /* prevent bio_put of first_clone */
+ /* Grab another reference to the io struct
+ * before we kick off the request */
if (remaining)
atomic_inc(&io->pending);
generic_make_request(clone);
+ /* Do not reference clone after this - it
+ * may be gone already. */
+
/* out of memory -> run queues */
if (remaining)
- congestion_wait(bio_data_dir(clone), HZ/100);
+ congestion_wait(WRITE, HZ/100);
}
}
@@ -832,6 +817,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->iv_gen_ops = &crypt_iv_essiv_ops;
else if (strcmp(ivmode, "benbi") == 0)
cc->iv_gen_ops = &crypt_iv_benbi_ops;
+ else if (strcmp(ivmode, "null") == 0)
+ cc->iv_gen_ops = &crypt_iv_null_ops;
else {
ti->error = "Invalid IV mode";
goto bad2;
@@ -867,7 +854,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad4;
}
- cc->bs = bioset_create(MIN_IOS, MIN_IOS, 4);
+ cc->bs = bioset_create(MIN_IOS, MIN_IOS);
if (!cc->bs) {
ti->error = "Cannot allocate crypt bioset";
goto bad_bs;
@@ -954,10 +941,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
struct crypt_config *cc = ti->private;
struct crypt_io *io;
+ if (bio_barrier(bio))
+ return -EOPNOTSUPP;
+
io = mempool_alloc(cc->io_pool, GFP_NOIO);
io->target = ti;
io->base_bio = bio;
- io->first_clone = NULL;
io->error = io->post_process = 0;
atomic_set(&io->pending, 0);
kcryptd_queue_io(io);
@@ -1057,7 +1046,7 @@ error:
static struct target_type crypt_target = {
.name = "crypt",
- .version= {1, 3, 0},
+ .version= {1, 5, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
new file mode 100644
index 00000000000..52c7cf9e580
--- /dev/null
+++ b/drivers/md/dm-delay.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2005-2007 Red Hat GmbH
+ *
+ * A target that delays reads and/or writes and can send
+ * them to different devices.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/slab.h>
+
+#include "dm.h"
+#include "dm-bio-list.h"
+
+#define DM_MSG_PREFIX "delay"
+
+struct delay_c {
+ struct timer_list delay_timer;
+ struct semaphore timer_lock;
+ struct work_struct flush_expired_bios;
+ struct list_head delayed_bios;
+ atomic_t may_delay;
+ mempool_t *delayed_pool;
+
+ struct dm_dev *dev_read;
+ sector_t start_read;
+ unsigned read_delay;
+ unsigned reads;
+
+ struct dm_dev *dev_write;
+ sector_t start_write;
+ unsigned write_delay;
+ unsigned writes;
+};
+
+struct delay_info {
+ struct delay_c *context;
+ struct list_head list;
+ struct bio *bio;
+ unsigned long expires;
+};
+
+static DEFINE_MUTEX(delayed_bios_lock);
+
+static struct workqueue_struct *kdelayd_wq;
+static struct kmem_cache *delayed_cache;
+
+static void handle_delayed_timer(unsigned long data)
+{
+ struct delay_c *dc = (struct delay_c *)data;
+
+ queue_work(kdelayd_wq, &dc->flush_expired_bios);
+}
+
+static void queue_timeout(struct delay_c *dc, unsigned long expires)
+{
+ down(&dc->timer_lock);
+
+ if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires)
+ mod_timer(&dc->delay_timer, expires);
+
+ up(&dc->timer_lock);
+}
+
+static void flush_bios(struct bio *bio)
+{
+ struct bio *n;
+
+ while (bio) {
+ n = bio->bi_next;
+ bio->bi_next = NULL;
+ generic_make_request(bio);
+ bio = n;
+ }
+}
+
+static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
+{
+ struct delay_info *delayed, *next;
+ unsigned long next_expires = 0;
+ int start_timer = 0;
+ BIO_LIST(flush_bios);
+
+ mutex_lock(&delayed_bios_lock);
+ list_for_each_entry_safe(delayed, next, &dc->delayed_bios, list) {
+ if (flush_all || time_after_eq(jiffies, delayed->expires)) {
+ list_del(&delayed->list);
+ bio_list_add(&flush_bios, delayed->bio);
+ if ((bio_data_dir(delayed->bio) == WRITE))
+ delayed->context->writes--;
+ else
+ delayed->context->reads--;
+ mempool_free(delayed, dc->delayed_pool);
+ continue;
+ }
+
+ if (!start_timer) {
+ start_timer = 1;
+ next_expires = delayed->expires;
+ } else
+ next_expires = min(next_expires, delayed->expires);
+ }
+
+ mutex_unlock(&delayed_bios_lock);
+
+ if (start_timer)
+ queue_timeout(dc, next_expires);
+
+ return bio_list_get(&flush_bios);
+}
+
+static void flush_expired_bios(struct work_struct *work)
+{
+ struct delay_c *dc;
+
+ dc = container_of(work, struct delay_c, flush_expired_bios);
+ flush_bios(flush_delayed_bios(dc, 0));
+}
+
+/*
+ * Mapping parameters:
+ * <device> <offset> <delay> [<write_device> <write_offset> <write_delay>]
+ *
+ * With separate write parameters, the first set is only used for reads.
+ * Delays are specified in milliseconds.
+ */
+static int delay_ctr(struct dm_target *ti, unsigned int argc, char **argv)
+{
+ struct delay_c *dc;
+ unsigned long long tmpll;
+
+ if (argc != 3 && argc != 6) {
+ ti->error = "requires exactly 3 or 6 arguments";
+ return -EINVAL;
+ }
+
+ dc = kmalloc(sizeof(*dc), GFP_KERNEL);
+ if (!dc) {
+ ti->error = "Cannot allocate context";
+ return -ENOMEM;
+ }
+
+ dc->reads = dc->writes = 0;
+
+ if (sscanf(argv[1], "%llu", &tmpll) != 1) {
+ ti->error = "Invalid device sector";
+ goto bad;
+ }
+ dc->start_read = tmpll;
+
+ if (sscanf(argv[2], "%u", &dc->read_delay) != 1) {
+ ti->error = "Invalid delay";
+ goto bad;
+ }
+
+ if (dm_get_device(ti, argv[0], dc->start_read, ti->len,
+ dm_table_get_mode(ti->table), &dc->dev_read)) {
+ ti->error = "Device lookup failed";
+ goto bad;
+ }
+
+ if (argc == 3) {
+ dc->dev_write = NULL;
+ goto out;
+ }
+
+ if (sscanf(argv[4], "%llu", &tmpll) != 1) {
+ ti->error = "Invalid write device sector";
+ goto bad;
+ }
+ dc->start_write = tmpll;
+
+ if (sscanf(argv[5], "%u", &dc->write_delay) != 1) {
+ ti->error = "Invalid write delay";
+ goto bad;
+ }
+
+ if (dm_get_device(ti, argv[3], dc->start_write, ti->len,
+ dm_table_get_mode(ti->table), &dc->dev_write)) {
+ ti->error = "Write device lookup failed";
+ dm_put_device(ti, dc->dev_read);
+ goto bad;
+ }
+
+out:
+ dc->delayed_pool = mempool_create_slab_pool(128, delayed_cache);
+ if (!dc->delayed_pool) {
+ DMERR("Couldn't create delayed bio pool.");
+ goto bad;
+ }
+
+ init_timer(&dc->delay_timer);
+ dc->delay_timer.function = handle_delayed_timer;
+ dc->delay_timer.data = (unsigned long)dc;
+
+ INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
+ INIT_LIST_HEAD(&dc->delayed_bios);
+ init_MUTEX(&dc->timer_lock);
+ atomic_set(&dc->may_delay, 1);
+
+ ti->private = dc;
+ return 0;
+
+bad:
+ kfree(dc);
+ return -EINVAL;
+}
+
+static void delay_dtr(struct dm_target *ti)
+{
+ struct delay_c *dc = ti->private;
+
+ flush_workqueue(kdelayd_wq);
+
+ dm_put_device(ti, dc->dev_read);
+
+ if (dc->dev_write)
+ dm_put_device(ti, dc->dev_write);
+
+ mempool_destroy(dc->delayed_pool);
+ kfree(dc);
+}
+
+static int delay_bio(struct delay_c *dc, int delay, struct bio *bio)
+{
+ struct delay_info *delayed;
+ unsigned long expires = 0;
+
+ if (!delay || !atomic_read(&dc->may_delay))
+ return 1;
+
+ delayed = mempool_alloc(dc->delayed_pool, GFP_NOIO);
+
+ delayed->context = dc;
+ delayed->bio = bio;
+ delayed->expires = expires = jiffies + (delay * HZ / 1000);
+
+ mutex_lock(&delayed_bios_lock);
+
+ if (bio_data_dir(bio) == WRITE)
+ dc->writes++;
+ else
+ dc->reads++;
+
+ list_add_tail(&delayed->list, &dc->delayed_bios);
+
+ mutex_unlock(&delayed_bios_lock);
+
+ queue_timeout(dc, expires);
+
+ return 0;
+}
+
+static void delay_presuspend(struct dm_target *ti)
+{
+ struct delay_c *dc = ti->private;
+
+ atomic_set(&dc->may_delay, 0);
+ del_timer_sync(&dc->delay_timer);
+ flush_bios(flush_delayed_bios(dc, 1));
+}
+
+static void delay_resume(struct dm_target *ti)
+{
+ struct delay_c *dc = ti->private;
+
+ atomic_set(&dc->may_delay, 1);
+}
+
+static int delay_map(struct dm_target *ti, struct bio *bio,
+ union map_info *map_context)
+{
+ struct delay_c *dc = ti->private;
+
+ if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
+ bio->bi_bdev = dc->dev_write->bdev;
+ bio->bi_sector = dc->start_write +
+ (bio->bi_sector - ti->begin);
+
+ return delay_bio(dc, dc->write_delay, bio);
+ }
+
+ bio->bi_bdev = dc->dev_read->bdev;
+ bio->bi_sector = dc->start_read +
+ (bio->bi_sector - ti->begin);
+
+ return delay_bio(dc, dc->read_delay, bio);
+}
+
+static int delay_status(struct dm_target *ti, status_type_t type,
+ char *result, unsigned maxlen)
+{
+ struct delay_c *dc = ti->private;
+ int sz = 0;
+
+ switch (type) {
+ case STATUSTYPE_INFO:
+ DMEMIT("%u %u", dc->reads, dc->writes);
+ break;
+
+ case STATUSTYPE_TABLE:
+ DMEMIT("%s %llu %u", dc->dev_read->name,
+ (unsigned long long) dc->start_read,
+ dc->read_delay);
+ if (dc->dev_write)
+ DMEMIT("%s %llu %u", dc->dev_write->name,
+ (unsigned long long) dc->start_write,
+ dc->write_delay);
+ break;
+ }
+
+ return 0;
+}
+
+static struct target_type delay_target = {
+ .name = "delay",
+ .version = {1, 0, 2},
+ .module = THIS_MODULE,
+ .ctr = delay_ctr,
+ .dtr = delay_dtr,
+ .map = delay_map,
+ .presuspend = delay_presuspend,
+ .resume = delay_resume,
+ .status = delay_status,
+};
+
+static int __init dm_delay_init(void)
+{
+ int r = -ENOMEM;
+
+ kdelayd_wq = create_workqueue("kdelayd");
+ if (!kdelayd_wq) {
+ DMERR("Couldn't start kdelayd");
+ goto bad_queue;
+ }
+
+ delayed_cache = kmem_cache_create("dm-delay",
+ sizeof(struct delay_info),
+ __alignof__(struct delay_info),
+ 0, NULL, NULL);
+ if (!delayed_cache) {
+ DMERR("Couldn't create delayed bio cache.");
+ goto bad_memcache;
+ }
+
+ r = dm_register_target(&delay_target);
+ if (r < 0) {
+ DMERR("register failed %d", r);
+ goto bad_register;
+ }
+
+ return 0;
+
+bad_register:
+ kmem_cache_destroy(delayed_cache);
+bad_memcache:
+ destroy_workqueue(kdelayd_wq);
+bad_queue:
+ return r;
+}
+
+static void __exit dm_delay_exit(void)
+{
+ int r = dm_unregister_target(&delay_target);
+
+ if (r < 0)
+ DMERR("unregister failed %d", r);
+
+ kmem_cache_destroy(delayed_cache);
+ destroy_workqueue(kdelayd_wq);
+}
+
+/* Module hooks */
+module_init(dm_delay_init);
+module_exit(dm_delay_exit);
+
+MODULE_DESCRIPTION(DM_NAME " delay target");
+MODULE_AUTHOR("Heinz Mauelshagen <mauelshagen@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 99cdffa7fbf..07e0a0c84f6 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -1,7 +1,8 @@
/*
- * dm-snapshot.c
+ * dm-exception-store.c
*
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
*
* This file is released under the GPL.
*/
@@ -123,6 +124,7 @@ struct pstore {
atomic_t pending_count;
uint32_t callback_count;
struct commit_callback *callbacks;
+ struct dm_io_client *io_client;
};
static inline unsigned int sectors_to_pages(unsigned int sectors)
@@ -159,14 +161,20 @@ static void free_area(struct pstore *ps)
*/
static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
{
- struct io_region where;
- unsigned long bits;
-
- where.bdev = ps->snap->cow->bdev;
- where.sector = ps->snap->chunk_size * chunk;
- where.count = ps->snap->chunk_size;
-
- return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
+ struct io_region where = {
+ .bdev = ps->snap->cow->bdev,
+ .sector = ps->snap->chunk_size * chunk,
+ .count = ps->snap->chunk_size,
+ };
+ struct dm_io_request io_req = {
+ .bi_rw = rw,
+ .mem.type = DM_IO_VMA,
+ .mem.ptr.vma = ps->area,
+ .client = ps->io_client,
+ .notify.fn = NULL,
+ };
+
+ return dm_io(&io_req, 1, &where, NULL);
}
/*
@@ -213,17 +221,18 @@ static int read_header(struct pstore *ps, int *new_snapshot)
chunk_size_supplied = 0;
}
- r = dm_io_get(sectors_to_pages(ps->snap->chunk_size));
- if (r)
- return r;
+ ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
+ chunk_size));
+ if (IS_ERR(ps->io_client))
+ return PTR_ERR(ps->io_client);
r = alloc_area(ps);
if (r)
- goto bad1;
+ return r;
r = chunk_io(ps, 0, READ);
if (r)
- goto bad2;
+ goto bad;
dh = (struct disk_header *) ps->area;
@@ -235,7 +244,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
DMWARN("Invalid or corrupt snapshot");
r = -ENXIO;
- goto bad2;
+ goto bad;
}
*new_snapshot = 0;
@@ -252,27 +261,22 @@ static int read_header(struct pstore *ps, int *new_snapshot)
(unsigned long long)ps->snap->chunk_size);
/* We had a bogus chunk_size. Fix stuff up. */
- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
free_area(ps);
ps->snap->chunk_size = chunk_size;
ps->snap->chunk_mask = chunk_size - 1;
ps->snap->chunk_shift = ffs(chunk_size) - 1;
- r = dm_io_get(sectors_to_pages(chunk_size));
+ r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
+ ps->io_client);
if (r)
return r;
r = alloc_area(ps);
- if (r)
- goto bad1;
-
- return 0;
+ return r;
-bad2:
+bad:
free_area(ps);
-bad1:
- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
return r;
}
@@ -405,7 +409,7 @@ static void persistent_destroy(struct exception_store *store)
{
struct pstore *ps = get_info(store);
- dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+ dm_io_client_destroy(ps->io_client);
vfree(ps->callbacks);
free_area(ps);
kfree(ps);
diff --git a/drivers/md/dm-hw-handler.h b/drivers/md/dm-hw-handler.h
index 32eff28e4ad..e0832e6fcf3 100644
--- a/drivers/md/dm-hw-handler.h
+++ b/drivers/md/dm-hw-handler.h
@@ -16,6 +16,7 @@
struct hw_handler_type;
struct hw_handler {
struct hw_handler_type *type;
+ struct mapped_device *md;
void *context;
};
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 4eb73d39521..352c6fbeac5 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003 Sistina Software
+ * Copyright (C) 2006 Red Hat GmbH
*
* This file is released under the GPL.
*/
@@ -12,13 +13,17 @@
#include <linux/sched.h>
#include <linux/slab.h>
-static struct bio_set *_bios;
+struct dm_io_client {
+ mempool_t *pool;
+ struct bio_set *bios;
+};
/* FIXME: can we shrink this ? */
struct io {
unsigned long error;
atomic_t count;
struct task_struct *sleeper;
+ struct dm_io_client *client;
io_notify_fn callback;
void *context;
};
@@ -26,63 +31,58 @@ struct io {
/*
* io contexts are only dynamically allocated for asynchronous
* io. Since async io is likely to be the majority of io we'll
- * have the same number of io contexts as buffer heads ! (FIXME:
- * must reduce this).
+ * have the same number of io contexts as bios! (FIXME: must reduce this).
*/
-static unsigned _num_ios;
-static mempool_t *_io_pool;
static unsigned int pages_to_ios(unsigned int pages)
{
return 4 * pages; /* too many ? */
}
-static int resize_pool(unsigned int new_ios)
+/*
+ * Create a client with mempool and bioset.
+ */
+struct dm_io_client *dm_io_client_create(unsigned num_pages)
{
- int r = 0;
-
- if (_io_pool) {
- if (new_ios == 0) {
- /* free off the pool */
- mempool_destroy(_io_pool);
- _io_pool = NULL;
- bioset_free(_bios);
-
- } else {
- /* resize the pool */
- r = mempool_resize(_io_pool, new_ios, GFP_KERNEL);
- }
+ unsigned ios = pages_to_ios(num_pages);
+ struct dm_io_client *client;
- } else {
- /* create new pool */
- _io_pool = mempool_create_kmalloc_pool(new_ios,
- sizeof(struct io));
- if (!_io_pool)
- return -ENOMEM;
-
- _bios = bioset_create(16, 16, 4);
- if (!_bios) {
- mempool_destroy(_io_pool);
- _io_pool = NULL;
- return -ENOMEM;
- }
- }
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return ERR_PTR(-ENOMEM);
+
+ client->pool = mempool_create_kmalloc_pool(ios, sizeof(struct io));
+ if (!client->pool)
+ goto bad;
- if (!r)
- _num_ios = new_ios;
+ client->bios = bioset_create(16, 16);
+ if (!client->bios)
+ goto bad;
- return r;
+ return client;
+
+ bad:
+ if (client->pool)
+ mempool_destroy(client->pool);
+ kfree(client);
+ return ERR_PTR(-ENOMEM);
}
+EXPORT_SYMBOL(dm_io_client_create);
-int dm_io_get(unsigned int num_pages)
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client)
{
- return resize_pool(_num_ios + pages_to_ios(num_pages));
+ return mempool_resize(client->pool, pages_to_ios(num_pages),
+ GFP_KERNEL);
}
+EXPORT_SYMBOL(dm_io_client_resize);
-void dm_io_put(unsigned int num_pages)
+void dm_io_client_destroy(struct dm_io_client *client)
{
- resize_pool(_num_ios - pages_to_ios(num_pages));
+ mempool_destroy(client->pool);
+ bioset_free(client->bios);
+ kfree(client);
}
+EXPORT_SYMBOL(dm_io_client_destroy);
/*-----------------------------------------------------------------
* We need to keep track of which region a bio is doing io for.
@@ -118,7 +118,7 @@ static void dec_count(struct io *io, unsigned int region, int error)
io_notify_fn fn = io->callback;
void *context = io->context;
- mempool_free(io, _io_pool);
+ mempool_free(io, io->client->pool);
fn(r, context);
}
}
@@ -126,7 +126,8 @@ static void dec_count(struct io *io, unsigned int region, int error)
static int endio(struct bio *bio, unsigned int done, int error)
{
- struct io *io = (struct io *) bio->bi_private;
+ struct io *io;
+ unsigned region;
/* keep going until we've finished */
if (bio->bi_size)
@@ -135,10 +136,17 @@ static int endio(struct bio *bio, unsigned int done, int error)
if (error && bio_data_dir(bio) == READ)
zero_fill_bio(bio);
- dec_count(io, bio_get_region(bio), error);
+ /*
+ * The bio destructor in bio_put() may use the io object.
+ */
+ io = bio->bi_private;
+ region = bio_get_region(bio);
+
bio->bi_max_vecs++;
bio_put(bio);
+ dec_count(io, region, error);
+
return 0;
}
@@ -209,6 +217,9 @@ static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec)
dp->context_ptr = bvec;
}
+/*
+ * Functions for getting the pages from a VMA.
+ */
static void vm_get_page(struct dpages *dp,
struct page **p, unsigned long *len, unsigned *offset)
{
@@ -233,7 +244,34 @@ static void vm_dp_init(struct dpages *dp, void *data)
static void dm_bio_destructor(struct bio *bio)
{
- bio_free(bio, _bios);
+ struct io *io = bio->bi_private;
+
+ bio_free(bio, io->client->bios);
+}
+
+/*
+ * Functions for getting the pages from kernel memory.
+ */
+static void km_get_page(struct dpages *dp, struct page **p, unsigned long *len,
+ unsigned *offset)
+{
+ *p = virt_to_page(dp->context_ptr);
+ *offset = dp->context_u;
+ *len = PAGE_SIZE - dp->context_u;
+}
+
+static void km_next_page(struct dpages *dp)
+{
+ dp->context_ptr += PAGE_SIZE - dp->context_u;
+ dp->context_u = 0;
+}
+
+static void km_dp_init(struct dpages *dp, void *data)
+{
+ dp->get_page = km_get_page;
+ dp->next_page = km_next_page;
+ dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+ dp->context_ptr = data;
}
/*-----------------------------------------------------------------
@@ -256,7 +294,7 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
* to hide it from bio_add_page().
*/
num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
- bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, _bios);
+ bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
bio->bi_end_io = endio;
@@ -311,8 +349,9 @@ static void dispatch_io(int rw, unsigned int num_regions,
dec_count(io, 0, 0);
}
-static int sync_io(unsigned int num_regions, struct io_region *where,
- int rw, struct dpages *dp, unsigned long *error_bits)
+static int sync_io(struct dm_io_client *client, unsigned int num_regions,
+ struct io_region *where, int rw, struct dpages *dp,
+ unsigned long *error_bits)
{
struct io io;
@@ -324,6 +363,7 @@ static int sync_io(unsigned int num_regions, struct io_region *where,
io.error = 0;
atomic_set(&io.count, 1); /* see dispatch_io() */
io.sleeper = current;
+ io.client = client;
dispatch_io(rw, num_regions, where, dp, &io, 1);
@@ -340,12 +380,15 @@ static int sync_io(unsigned int num_regions, struct io_region *where,
if (atomic_read(&io.count))
return -EINTR;
- *error_bits = io.error;
+ if (error_bits)
+ *error_bits = io.error;
+
return io.error ? -EIO : 0;
}
-static int async_io(unsigned int num_regions, struct io_region *where, int rw,
- struct dpages *dp, io_notify_fn fn, void *context)
+static int async_io(struct dm_io_client *client, unsigned int num_regions,
+ struct io_region *where, int rw, struct dpages *dp,
+ io_notify_fn fn, void *context)
{
struct io *io;
@@ -355,10 +398,11 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw,
return -EIO;
}
- io = mempool_alloc(_io_pool, GFP_NOIO);
+ io = mempool_alloc(client->pool, GFP_NOIO);
io->error = 0;
atomic_set(&io->count, 1); /* see dispatch_io() */
io->sleeper = NULL;
+ io->client = client;
io->callback = fn;
io->context = context;
@@ -366,61 +410,51 @@ static int async_io(unsigned int num_regions, struct io_region *where, int rw,
return 0;
}
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- unsigned long *error_bits)
+static int dp_init(struct dm_io_request *io_req, struct dpages *dp)
{
- struct dpages dp;
- list_dp_init(&dp, pl, offset);
- return sync_io(num_regions, where, rw, &dp, error_bits);
-}
+ /* Set up dpages based on memory type */
+ switch (io_req->mem.type) {
+ case DM_IO_PAGE_LIST:
+ list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
+ break;
+
+ case DM_IO_BVEC:
+ bvec_dp_init(dp, io_req->mem.ptr.bvec);
+ break;
+
+ case DM_IO_VMA:
+ vm_dp_init(dp, io_req->mem.ptr.vma);
+ break;
+
+ case DM_IO_KMEM:
+ km_dp_init(dp, io_req->mem.ptr.addr);
+ break;
+
+ default:
+ return -EINVAL;
+ }
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, unsigned long *error_bits)
-{
- struct dpages dp;
- bvec_dp_init(&dp, bvec);
- return sync_io(num_regions, where, rw, &dp, error_bits);
+ return 0;
}
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, unsigned long *error_bits)
+/*
+ * New collapsed (a)synchronous interface
+ */
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+ struct io_region *where, unsigned long *sync_error_bits)
{
+ int r;
struct dpages dp;
- vm_dp_init(&dp, data);
- return sync_io(num_regions, where, rw, &dp, error_bits);
-}
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- io_notify_fn fn, void *context)
-{
- struct dpages dp;
- list_dp_init(&dp, pl, offset);
- return async_io(num_regions, where, rw, &dp, fn, context);
-}
+ r = dp_init(io_req, &dp);
+ if (r)
+ return r;
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, io_notify_fn fn, void *context)
-{
- struct dpages dp;
- bvec_dp_init(&dp, bvec);
- return async_io(num_regions, where, rw, &dp, fn, context);
-}
+ if (!io_req->notify.fn)
+ return sync_io(io_req->client, num_regions, where,
+ io_req->bi_rw, &dp, sync_error_bits);
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, io_notify_fn fn, void *context)
-{
- struct dpages dp;
- vm_dp_init(&dp, data);
- return async_io(num_regions, where, rw, &dp, fn, context);
+ return async_io(io_req->client, num_regions, where, io_req->bi_rw,
+ &dp, io_req->notify.fn, io_req->notify.context);
}
-
-EXPORT_SYMBOL(dm_io_get);
-EXPORT_SYMBOL(dm_io_put);
-EXPORT_SYMBOL(dm_io_sync);
-EXPORT_SYMBOL(dm_io_async);
-EXPORT_SYMBOL(dm_io_sync_bvec);
-EXPORT_SYMBOL(dm_io_async_bvec);
-EXPORT_SYMBOL(dm_io_sync_vm);
-EXPORT_SYMBOL(dm_io_async_vm);
+EXPORT_SYMBOL(dm_io);
diff --git a/drivers/md/dm-io.h b/drivers/md/dm-io.h
index f9035bfd1a9..f647e2cceaa 100644
--- a/drivers/md/dm-io.h
+++ b/drivers/md/dm-io.h
@@ -12,7 +12,7 @@
struct io_region {
struct block_device *bdev;
sector_t sector;
- sector_t count;
+ sector_t count; /* If this is zero the region is ignored. */
};
struct page_list {
@@ -20,55 +20,60 @@ struct page_list {
struct page *page;
};
-
-/*
- * 'error' is a bitset, with each bit indicating whether an error
- * occurred doing io to the corresponding region.
- */
typedef void (*io_notify_fn)(unsigned long error, void *context);
+enum dm_io_mem_type {
+ DM_IO_PAGE_LIST,/* Page list */
+ DM_IO_BVEC, /* Bio vector */
+ DM_IO_VMA, /* Virtual memory area */
+ DM_IO_KMEM, /* Kernel memory */
+};
+
+struct dm_io_memory {
+ enum dm_io_mem_type type;
+
+ union {
+ struct page_list *pl;
+ struct bio_vec *bvec;
+ void *vma;
+ void *addr;
+ } ptr;
+
+ unsigned offset;
+};
+
+struct dm_io_notify {
+ io_notify_fn fn; /* Callback for asynchronous requests */
+ void *context; /* Passed to callback */
+};
/*
- * Before anyone uses the IO interface they should call
- * dm_io_get(), specifying roughly how many pages they are
- * expecting to perform io on concurrently.
- *
- * This function may block.
+ * IO request structure
*/
-int dm_io_get(unsigned int num_pages);
-void dm_io_put(unsigned int num_pages);
+struct dm_io_client;
+struct dm_io_request {
+ int bi_rw; /* READ|WRITE - not READA */
+ struct dm_io_memory mem; /* Memory to use for io */
+ struct dm_io_notify notify; /* Synchronous if notify.fn is NULL */
+ struct dm_io_client *client; /* Client memory handler */
+};
/*
- * Synchronous IO.
+ * For async io calls, users can alternatively use the dm_io() function below
+ * and dm_io_client_create() to create private mempools for the client.
*
- * Please ensure that the rw flag in the next two functions is
- * either READ or WRITE, ie. we don't take READA. Any
- * regions with a zero count field will be ignored.
+ * Create/destroy may block.
*/
-int dm_io_sync(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- unsigned long *error_bits);
-
-int dm_io_sync_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, unsigned long *error_bits);
-
-int dm_io_sync_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, unsigned long *error_bits);
+struct dm_io_client *dm_io_client_create(unsigned num_pages);
+int dm_io_client_resize(unsigned num_pages, struct dm_io_client *client);
+void dm_io_client_destroy(struct dm_io_client *client);
/*
- * Aynchronous IO.
- *
- * The 'where' array may be safely allocated on the stack since
- * the function takes a copy.
+ * IO interface using private per-client pools.
+ * Each bit in the optional 'sync_error_bits' bitset indicates whether an
+ * error occurred doing io to the corresponding region.
*/
-int dm_io_async(unsigned int num_regions, struct io_region *where, int rw,
- struct page_list *pl, unsigned int offset,
- io_notify_fn fn, void *context);
-
-int dm_io_async_bvec(unsigned int num_regions, struct io_region *where, int rw,
- struct bio_vec *bvec, io_notify_fn fn, void *context);
-
-int dm_io_async_vm(unsigned int num_regions, struct io_region *where, int rw,
- void *data, io_notify_fn fn, void *context);
+int dm_io(struct dm_io_request *io_req, unsigned num_regions,
+ struct io_region *region, unsigned long *sync_error_bits);
#endif
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 6a926135184..a66428d860f 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -149,9 +149,12 @@ struct log_c {
FORCESYNC, /* Force a sync to happen */
} sync;
+ struct dm_io_request io_req;
+
/*
* Disk log fields
*/
+ int log_dev_failed;
struct dm_dev *log_dev;
struct log_header header;
@@ -199,13 +202,20 @@ static void header_from_disk(struct log_header *core, struct log_header *disk)
core->nr_regions = le64_to_cpu(disk->nr_regions);
}
+static int rw_header(struct log_c *lc, int rw)
+{
+ lc->io_req.bi_rw = rw;
+ lc->io_req.mem.ptr.vma = lc->disk_header;
+ lc->io_req.notify.fn = NULL;
+
+ return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
+}
+
static int read_header(struct log_c *log)
{
int r;
- unsigned long ebits;
- r = dm_io_sync_vm(1, &log->header_location, READ,
- log->disk_header, &ebits);
+ r = rw_header(log, READ);
if (r)
return r;
@@ -233,11 +243,8 @@ static int read_header(struct log_c *log)
static inline int write_header(struct log_c *log)
{
- unsigned long ebits;
-
header_to_disk(&log->header, log->disk_header);
- return dm_io_sync_vm(1, &log->header_location, WRITE,
- log->disk_header, &ebits);
+ return rw_header(log, WRITE);
}
/*----------------------------------------------------------------
@@ -256,6 +263,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
uint32_t region_size;
unsigned int region_count;
size_t bitset_size, buf_size;
+ int r;
if (argc < 1 || argc > 2) {
DMWARN("wrong number of arguments to mirror log");
@@ -315,6 +323,7 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
lc->disk_header = NULL;
} else {
lc->log_dev = dev;
+ lc->log_dev_failed = 0;
lc->header_location.bdev = lc->log_dev->bdev;
lc->header_location.sector = 0;
@@ -324,6 +333,15 @@ static int create_log_context(struct dirty_log *log, struct dm_target *ti,
buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
bitset_size, ti->limits.hardsect_size);
lc->header_location.count = buf_size >> SECTOR_SHIFT;
+ lc->io_req.mem.type = DM_IO_VMA;
+ lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
+ PAGE_SIZE));
+ if (IS_ERR(lc->io_req.client)) {
+ r = PTR_ERR(lc->io_req.client);
+ DMWARN("couldn't allocate disk io client");
+ kfree(lc);
+ return -ENOMEM;
+ }
lc->disk_header = vmalloc(buf_size);
if (!lc->disk_header) {
@@ -424,6 +442,7 @@ static void disk_dtr(struct dirty_log *log)
dm_put_device(lc->ti, lc->log_dev);
vfree(lc->disk_header);
+ dm_io_client_destroy(lc->io_req.client);
destroy_log_context(lc);
}
@@ -437,6 +456,15 @@ static int count_bits32(uint32_t *addr, unsigned size)
return count;
}
+static void fail_log_device(struct log_c *lc)
+{
+ if (lc->log_dev_failed)
+ return;
+
+ lc->log_dev_failed = 1;
+ dm_table_event(lc->ti->table);
+}
+
static int disk_resume(struct dirty_log *log)
{
int r;
@@ -446,8 +474,19 @@ static int disk_resume(struct dirty_log *log)
/* read the disk header */
r = read_header(lc);
- if (r)
- return r;
+ if (r) {
+ DMWARN("%s: Failed to read header on mirror log device",
+ lc->log_dev->name);
+ fail_log_device(lc);
+ /*
+ * If the log device cannot be read, we must assume
+ * all regions are out-of-sync. If we simply return
+ * here, the state will be uninitialized and could
+ * lead us to return 'in-sync' status for regions
+ * that are actually 'out-of-sync'.
+ */
+ lc->header.nr_regions = 0;
+ }
/* set or clear any new bits -- device has grown */
if (lc->sync == NOSYNC)
@@ -472,7 +511,14 @@ static int disk_resume(struct dirty_log *log)
lc->header.nr_regions = lc->region_count;
/* write the new header */
- return write_header(lc);
+ r = write_header(lc);
+ if (r) {
+ DMWARN("%s: Failed to write header on mirror log device",
+ lc->log_dev->name);
+ fail_log_device(lc);
+ }
+
+ return r;
}
static uint32_t core_get_region_size(struct dirty_log *log)
@@ -516,7 +562,9 @@ static int disk_flush(struct dirty_log *log)
return 0;
r = write_header(lc);
- if (!r)
+ if (r)
+ fail_log_device(lc);
+ else
lc->touched = 0;
return r;
@@ -591,6 +639,7 @@ static int core_status(struct dirty_log *log, status_type_t status,
switch(status) {
case STATUSTYPE_INFO:
+ DMEMIT("1 %s", log->type->name);
break;
case STATUSTYPE_TABLE:
@@ -606,17 +655,17 @@ static int disk_status(struct dirty_log *log, status_type_t status,
char *result, unsigned int maxlen)
{
int sz = 0;
- char buffer[16];
struct log_c *lc = log->context;
switch(status) {
case STATUSTYPE_INFO:
+ DMEMIT("3 %s %s %c", log->type->name, lc->log_dev->name,
+ lc->log_dev_failed ? 'D' : 'A');
break;
case STATUSTYPE_TABLE:
- format_dev_t(buffer, lc->log_dev->bdev->bd_dev);
DMEMIT("%s %u %s %u ", log->type->name,
- lc->sync == DEFAULTSYNC ? 2 : 3, buffer,
+ lc->sync == DEFAULTSYNC ? 2 : 3, lc->log_dev->name,
lc->region_size);
DMEMIT_SYNC;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 3aa01350696..de54b39e6ff 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -668,6 +668,9 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m)
return -EINVAL;
}
+ m->hw_handler.md = dm_table_get_md(ti->table);
+ dm_put(m->hw_handler.md);
+
r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
if (r) {
dm_put_hw_handler(hwht);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 23a642619be..ef124b71ccc 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -21,15 +21,11 @@
#include <linux/workqueue.h>
#define DM_MSG_PREFIX "raid1"
+#define DM_IO_PAGES 64
-static struct workqueue_struct *_kmirrord_wq;
-static struct work_struct _kmirrord_work;
-static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
+#define DM_RAID1_HANDLE_ERRORS 0x01
-static inline void wake(void)
-{
- queue_work(_kmirrord_wq, &_kmirrord_work);
-}
+static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
/*-----------------------------------------------------------------
* Region hash
@@ -125,17 +121,23 @@ struct mirror_set {
struct list_head list;
struct region_hash rh;
struct kcopyd_client *kcopyd_client;
+ uint64_t features;
spinlock_t lock; /* protects the next two lists */
struct bio_list reads;
struct bio_list writes;
+ struct dm_io_client *io_client;
+
/* recovery */
region_t nr_regions;
int in_sync;
struct mirror *default_mirror; /* Default mirror */
+ struct workqueue_struct *kmirrord_wq;
+ struct work_struct kmirrord_work;
+
unsigned int nr_mirrors;
struct mirror mirror[0];
};
@@ -153,6 +155,11 @@ static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
return region << rh->region_shift;
}
+static void wake(struct mirror_set *ms)
+{
+ queue_work(ms->kmirrord_wq, &ms->kmirrord_work);
+}
+
/* FIXME move this */
static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw);
@@ -398,8 +405,7 @@ static void rh_update_states(struct region_hash *rh)
mempool_free(reg, rh->region_pool);
}
- if (!list_empty(&recovered))
- rh->log->type->flush(rh->log);
+ rh->log->type->flush(rh->log);
list_for_each_entry_safe (reg, next, &clean, list)
mempool_free(reg, rh->region_pool);
@@ -471,7 +477,7 @@ static void rh_dec(struct region_hash *rh, region_t region)
spin_unlock_irqrestore(&rh->region_lock, flags);
if (should_wake)
- wake();
+ wake(rh->ms);
}
/*
@@ -558,7 +564,7 @@ static void rh_recovery_end(struct region *reg, int success)
list_add(&reg->list, &reg->rh->recovered_regions);
spin_unlock_irq(&rh->region_lock);
- wake();
+ wake(rh->ms);
}
static void rh_flush(struct region_hash *rh)
@@ -592,7 +598,7 @@ static void rh_start_recovery(struct region_hash *rh)
for (i = 0; i < MAX_RECOVERY; i++)
up(&rh->recovery_count);
- wake();
+ wake(rh->ms);
}
/*
@@ -735,7 +741,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
/*
* We can only read balance if the region is in sync.
*/
- if (rh_in_sync(&ms->rh, region, 0))
+ if (rh_in_sync(&ms->rh, region, 1))
m = choose_mirror(ms, bio->bi_sector);
else
m = ms->default_mirror;
@@ -792,6 +798,14 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
unsigned int i;
struct io_region io[KCOPYD_MAX_REGIONS+1];
struct mirror *m;
+ struct dm_io_request io_req = {
+ .bi_rw = WRITE,
+ .mem.type = DM_IO_BVEC,
+ .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
+ .notify.fn = write_callback,
+ .notify.context = bio,
+ .client = ms->io_client,
+ };
for (i = 0; i < ms->nr_mirrors; i++) {
m = ms->mirror + i;
@@ -802,9 +816,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
}
bio_set_ms(bio, ms);
- dm_io_async_bvec(ms->nr_mirrors, io, WRITE,
- bio->bi_io_vec + bio->bi_idx,
- write_callback, bio);
+
+ (void) dm_io(&io_req, ms->nr_mirrors, io, NULL);
}
static void do_writes(struct mirror_set *ms, struct bio_list *writes)
@@ -870,11 +883,10 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
/*-----------------------------------------------------------------
* kmirrord
*---------------------------------------------------------------*/
-static LIST_HEAD(_mirror_sets);
-static DECLARE_RWSEM(_mirror_sets_lock);
-
-static void do_mirror(struct mirror_set *ms)
+static void do_mirror(struct work_struct *work)
{
+ struct mirror_set *ms =container_of(work, struct mirror_set,
+ kmirrord_work);
struct bio_list reads, writes;
spin_lock(&ms->lock);
@@ -890,16 +902,6 @@ static void do_mirror(struct mirror_set *ms)
do_writes(ms, &writes);
}
-static void do_work(struct work_struct *ignored)
-{
- struct mirror_set *ms;
-
- down_read(&_mirror_sets_lock);
- list_for_each_entry (ms, &_mirror_sets, list)
- do_mirror(ms);
- up_read(&_mirror_sets_lock);
-}
-
/*-----------------------------------------------------------------
* Target functions
*---------------------------------------------------------------*/
@@ -931,6 +933,13 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
ms->in_sync = 0;
ms->default_mirror = &ms->mirror[DEFAULT_MIRROR];
+ ms->io_client = dm_io_client_create(DM_IO_PAGES);
+ if (IS_ERR(ms->io_client)) {
+ ti->error = "Error creating dm_io client";
+ kfree(ms);
+ return NULL;
+ }
+
if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
ti->error = "Error creating dirty region hash";
kfree(ms);
@@ -946,6 +955,7 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
while (m--)
dm_put_device(ti, ms->mirror[m].dev);
+ dm_io_client_destroy(ms->io_client);
rh_exit(&ms->rh);
kfree(ms);
}
@@ -978,23 +988,6 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
return 0;
}
-static int add_mirror_set(struct mirror_set *ms)
-{
- down_write(&_mirror_sets_lock);
- list_add_tail(&ms->list, &_mirror_sets);
- up_write(&_mirror_sets_lock);
- wake();
-
- return 0;
-}
-
-static void del_mirror_set(struct mirror_set *ms)
-{
- down_write(&_mirror_sets_lock);
- list_del(&ms->list);
- up_write(&_mirror_sets_lock);
-}
-
/*
* Create dirty log: log_type #log_params <log_params>
*/
@@ -1037,16 +1030,55 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
return dl;
}
+static int parse_features(struct mirror_set *ms, unsigned argc, char **argv,
+ unsigned *args_used)
+{
+ unsigned num_features;
+ struct dm_target *ti = ms->ti;
+
+ *args_used = 0;
+
+ if (!argc)
+ return 0;
+
+ if (sscanf(argv[0], "%u", &num_features) != 1) {
+ ti->error = "Invalid number of features";
+ return -EINVAL;
+ }
+
+ argc--;
+ argv++;
+ (*args_used)++;
+
+ if (num_features > argc) {
+ ti->error = "Not enough arguments to support feature count";
+ return -EINVAL;
+ }
+
+ if (!strcmp("handle_errors", argv[0]))
+ ms->features |= DM_RAID1_HANDLE_ERRORS;
+ else {
+ ti->error = "Unrecognised feature requested";
+ return -EINVAL;
+ }
+
+ (*args_used)++;
+
+ return 0;
+}
+
/*
* Construct a mirror mapping:
*
* log_type #log_params <log_params>
* #mirrors [mirror_path offset]{2,}
+ * [#features <features>]
*
* log_type is "core" or "disk"
* #log_params is between 1 and 3
+ *
+ * If present, features must be "handle_errors".
*/
-#define DM_IO_PAGES 64
static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
int r;
@@ -1070,8 +1102,8 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv++, argc--;
- if (argc != nr_mirrors * 2) {
- ti->error = "Wrong number of mirror arguments";
+ if (argc < nr_mirrors * 2) {
+ ti->error = "Too few mirror arguments";
dm_destroy_dirty_log(dl);
return -EINVAL;
}
@@ -1096,13 +1128,37 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->private = ms;
ti->split_io = ms->rh.region_size;
+ ms->kmirrord_wq = create_singlethread_workqueue("kmirrord");
+ if (!ms->kmirrord_wq) {
+ DMERR("couldn't start kmirrord");
+ free_context(ms, ti, m);
+ return -ENOMEM;
+ }
+ INIT_WORK(&ms->kmirrord_work, do_mirror);
+
+ r = parse_features(ms, argc, argv, &args_used);
+ if (r) {
+ free_context(ms, ti, ms->nr_mirrors);
+ return r;
+ }
+
+ argv += args_used;
+ argc -= args_used;
+
+ if (argc) {
+ ti->error = "Too many mirror arguments";
+ free_context(ms, ti, ms->nr_mirrors);
+ return -EINVAL;
+ }
+
r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
if (r) {
+ destroy_workqueue(ms->kmirrord_wq);
free_context(ms, ti, ms->nr_mirrors);
return r;
}
- add_mirror_set(ms);
+ wake(ms);
return 0;
}
@@ -1110,8 +1166,9 @@ static void mirror_dtr(struct dm_target *ti)
{
struct mirror_set *ms = (struct mirror_set *) ti->private;
- del_mirror_set(ms);
+ flush_workqueue(ms->kmirrord_wq);
kcopyd_client_destroy(ms->kcopyd_client);
+ destroy_workqueue(ms->kmirrord_wq);
free_context(ms, ti, ms->nr_mirrors);
}
@@ -1127,7 +1184,7 @@ static void queue_bio(struct mirror_set *ms, struct bio *bio, int rw)
spin_unlock(&ms->lock);
if (should_wake)
- wake();
+ wake(ms);
}
/*
@@ -1222,11 +1279,9 @@ static void mirror_resume(struct dm_target *ti)
static int mirror_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen)
{
- unsigned int m, sz;
+ unsigned int m, sz = 0;
struct mirror_set *ms = (struct mirror_set *) ti->private;
- sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
-
switch (type) {
case STATUSTYPE_INFO:
DMEMIT("%d ", ms->nr_mirrors);
@@ -1237,13 +1292,21 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
(unsigned long long)ms->rh.log->type->
get_sync_count(ms->rh.log),
(unsigned long long)ms->nr_regions);
+
+ sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
break;
case STATUSTYPE_TABLE:
+ sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+
DMEMIT("%d", ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++)
DMEMIT(" %s %llu", ms->mirror[m].dev->name,
(unsigned long long)ms->mirror[m].offset);
+
+ if (ms->features & DM_RAID1_HANDLE_ERRORS)
+ DMEMIT(" 1 handle_errors");
}
return 0;
@@ -1251,7 +1314,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
static struct target_type mirror_target = {
.name = "mirror",
- .version = {1, 0, 2},
+ .version = {1, 0, 3},
.module = THIS_MODULE,
.ctr = mirror_ctr,
.dtr = mirror_dtr,
@@ -1270,20 +1333,11 @@ static int __init dm_mirror_init(void)
if (r)
return r;
- _kmirrord_wq = create_singlethread_workqueue("kmirrord");
- if (!_kmirrord_wq) {
- DMERR("couldn't start kmirrord");
- dm_dirty_log_exit();
- return r;
- }
- INIT_WORK(&_kmirrord_work, do_work);
-
r = dm_register_target(&mirror_target);
if (r < 0) {
DMERR("%s: Failed to register mirror target",
mirror_target.name);
dm_dirty_log_exit();
- destroy_workqueue(_kmirrord_wq);
}
return r;
@@ -1297,7 +1351,6 @@ static void __exit dm_mirror_exit(void)
if (r < 0)
DMERR("%s: unregister failed %d", mirror_target.name, r);
- destroy_workqueue(_kmirrord_wq);
dm_dirty_log_exit();
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 05befa91807..2fc199b0016 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -425,13 +425,15 @@ static void close_dev(struct dm_dev *d, struct mapped_device *md)
}
/*
- * If possible (ie. blk_size[major] is set), this checks an area
- * of a destination device is valid.
+ * If possible, this checks an area of a destination device is valid.
*/
static int check_device_area(struct dm_dev *dd, sector_t start, sector_t len)
{
- sector_t dev_size;
- dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+ sector_t dev_size = dd->bdev->bd_inode->i_size >> SECTOR_SHIFT;
+
+ if (!dev_size)
+ return 1;
+
return ((start < dev_size) && (len <= (dev_size - start)));
}
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 3668b170ea6..2717a355dc5 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1012,7 +1012,7 @@ static struct mapped_device *alloc_dev(int minor)
if (!md->tio_pool)
goto bad3;
- md->bs = bioset_create(16, 16, 4);
+ md->bs = bioset_create(16, 16);
if (!md->bs)
goto bad_no_bioset;
@@ -1236,6 +1236,7 @@ void dm_put(struct mapped_device *md)
free_dev(md);
}
}
+EXPORT_SYMBOL_GPL(dm_put);
/*
* Process the deferred bios
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index b46f6c575f7..dbc234e3c69 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006 Red Hat GmbH
*
* This file is released under the GPL.
*
@@ -45,6 +46,8 @@ struct kcopyd_client {
unsigned int nr_pages;
unsigned int nr_free_pages;
+ struct dm_io_client *io_client;
+
wait_queue_head_t destroyq;
atomic_t nr_jobs;
};
@@ -342,16 +345,20 @@ static void complete_io(unsigned long error, void *context)
static int run_io_job(struct kcopyd_job *job)
{
int r;
+ struct dm_io_request io_req = {
+ .bi_rw = job->rw,
+ .mem.type = DM_IO_PAGE_LIST,
+ .mem.ptr.pl = job->pages,
+ .mem.offset = job->offset,
+ .notify.fn = complete_io,
+ .notify.context = job,
+ .client = job->kc->io_client,
+ };
if (job->rw == READ)
- r = dm_io_async(1, &job->source, job->rw,
- job->pages,
- job->offset, complete_io, job);
-
+ r = dm_io(&io_req, 1, &job->source, NULL);
else
- r = dm_io_async(job->num_dests, job->dests, job->rw,
- job->pages,
- job->offset, complete_io, job);
+ r = dm_io(&io_req, job->num_dests, job->dests, NULL);
return r;
}
@@ -670,8 +677,9 @@ int kcopyd_client_create(unsigned int nr_pages, struct kcopyd_client **result)
return r;
}
- r = dm_io_get(nr_pages);
- if (r) {
+ kc->io_client = dm_io_client_create(nr_pages);
+ if (IS_ERR(kc->io_client)) {
+ r = PTR_ERR(kc->io_client);
client_free_pages(kc);
kfree(kc);
kcopyd_exit();
@@ -691,7 +699,7 @@ void kcopyd_client_destroy(struct kcopyd_client *kc)
/* Wait for completion of all jobs submitted by this client. */
wait_event(kc->destroyq, !atomic_read(&kc->nr_jobs));
- dm_io_put(kc->nr_pages);
+ dm_io_client_destroy(kc->io_client);
client_free_pages(kc);
client_del(kc);
kfree(kc);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 509171ca7fa..2901d0c0ee9 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -33,6 +33,7 @@
*/
#include <linux/module.h>
+#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/linkage.h>
#include <linux/raid/md.h>
@@ -273,6 +274,7 @@ static mddev_t * mddev_find(dev_t unit)
atomic_set(&new->active, 1);
spin_lock_init(&new->write_lock);
init_waitqueue_head(&new->sb_wait);
+ new->reshape_position = MaxSector;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
@@ -589,14 +591,41 @@ abort:
return ret;
}
+
+static u32 md_csum_fold(u32 csum)
+{
+ csum = (csum & 0xffff) + (csum >> 16);
+ return (csum & 0xffff) + (csum >> 16);
+}
+
static unsigned int calc_sb_csum(mdp_super_t * sb)
{
+ u64 newcsum = 0;
+ u32 *sb32 = (u32*)sb;
+ int i;
unsigned int disk_csum, csum;
disk_csum = sb->sb_csum;
sb->sb_csum = 0;
- csum = csum_partial((void *)sb, MD_SB_BYTES, 0);
+
+ for (i = 0; i < MD_SB_BYTES/4 ; i++)
+ newcsum += sb32[i];
+ csum = (newcsum & 0xffffffff) + (newcsum>>32);
+
+
+#ifdef CONFIG_ALPHA
+ /* This used to use csum_partial, which was wrong for several
+ * reasons including that different results are returned on
+ * different architectures. It isn't critical that we get exactly
+ * the same return value as before (we always csum_fold before
+ * testing, and that removes any differences). However as we
+ * know that csum_partial always returned a 16bit value on
+ * alphas, do a fold to maximise conformity to previous behaviour.
+ */
+ sb->sb_csum = md_csum_fold(disk_csum);
+#else
sb->sb_csum = disk_csum;
+#endif
return csum;
}
@@ -684,7 +713,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
if (sb->raid_disks <= 0)
goto abort;
- if (csum_fold(calc_sb_csum(sb)) != csum_fold(sb->sb_csum)) {
+ if (md_csum_fold(calc_sb_csum(sb)) != md_csum_fold(sb->sb_csum)) {
printk(KERN_WARNING "md: invalid superblock checksum on %s\n",
b);
goto abort;
@@ -694,6 +723,17 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
rdev->data_offset = 0;
rdev->sb_size = MD_SB_BYTES;
+ if (sb->state & (1<<MD_SB_BITMAP_PRESENT)) {
+ if (sb->level != 1 && sb->level != 4
+ && sb->level != 5 && sb->level != 6
+ && sb->level != 10) {
+ /* FIXME use a better test */
+ printk(KERN_WARNING
+ "md: bitmaps not supported for this level.\n");
+ goto abort;
+ }
+ }
+
if (sb->level == LEVEL_MULTIPATH)
rdev->desc_nr = -1;
else
@@ -792,16 +832,8 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->max_disks = MD_SB_DISKS;
if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
- mddev->bitmap_file == NULL) {
- if (mddev->level != 1 && mddev->level != 4
- && mddev->level != 5 && mddev->level != 6
- && mddev->level != 10) {
- /* FIXME use a better test */
- printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
- return -EINVAL;
- }
+ mddev->bitmap_file == NULL)
mddev->bitmap_offset = mddev->default_bitmap_offset;
- }
} else if (mddev->pers == NULL) {
/* Insist on good event counter while assembling */
@@ -1058,6 +1090,18 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
bdevname(rdev->bdev,b));
return -EINVAL;
}
+ if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET)) {
+ if (sb->level != cpu_to_le32(1) &&
+ sb->level != cpu_to_le32(4) &&
+ sb->level != cpu_to_le32(5) &&
+ sb->level != cpu_to_le32(6) &&
+ sb->level != cpu_to_le32(10)) {
+ printk(KERN_WARNING
+ "md: bitmaps not supported for this level.\n");
+ return -EINVAL;
+ }
+ }
+
rdev->preferred_minor = 0xffff;
rdev->data_offset = le64_to_cpu(sb->data_offset);
atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
@@ -1141,14 +1185,9 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->max_disks = (4096-256)/2;
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
- mddev->bitmap_file == NULL ) {
- if (mddev->level != 1 && mddev->level != 5 && mddev->level != 6
- && mddev->level != 10) {
- printk(KERN_WARNING "md: bitmaps not supported for this level.\n");
- return -EINVAL;
- }
+ mddev->bitmap_file == NULL )
mddev->bitmap_offset = (__s32)le32_to_cpu(sb->bitmap_offset);
- }
+
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
mddev->reshape_position = le64_to_cpu(sb->reshape_position);
mddev->delta_disks = le32_to_cpu(sb->delta_disks);
@@ -2204,6 +2243,10 @@ static ssize_t
layout_show(mddev_t *mddev, char *page)
{
/* just a number, not meaningful for all levels */
+ if (mddev->reshape_position != MaxSector &&
+ mddev->layout != mddev->new_layout)
+ return sprintf(page, "%d (%d)\n",
+ mddev->new_layout, mddev->layout);
return sprintf(page, "%d\n", mddev->layout);
}
@@ -2212,13 +2255,16 @@ layout_store(mddev_t *mddev, const char *buf, size_t len)
{
char *e;
unsigned long n = simple_strtoul(buf, &e, 10);
- if (mddev->pers)
- return -EBUSY;
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
- mddev->layout = n;
+ if (mddev->pers)
+ return -EBUSY;
+ if (mddev->reshape_position != MaxSector)
+ mddev->new_layout = n;
+ else
+ mddev->layout = n;
return len;
}
static struct md_sysfs_entry md_layout =
@@ -2230,6 +2276,10 @@ raid_disks_show(mddev_t *mddev, char *page)
{
if (mddev->raid_disks == 0)
return 0;
+ if (mddev->reshape_position != MaxSector &&
+ mddev->delta_disks != 0)
+ return sprintf(page, "%d (%d)\n", mddev->raid_disks,
+ mddev->raid_disks - mddev->delta_disks);
return sprintf(page, "%d\n", mddev->raid_disks);
}
@@ -2247,7 +2297,11 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
if (mddev->pers)
rv = update_raid_disks(mddev, n);
- else
+ else if (mddev->reshape_position != MaxSector) {
+ int olddisks = mddev->raid_disks - mddev->delta_disks;
+ mddev->delta_disks = n - olddisks;
+ mddev->raid_disks = n;
+ } else
mddev->raid_disks = n;
return rv ? rv : len;
}
@@ -2257,6 +2311,10 @@ __ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
static ssize_t
chunk_size_show(mddev_t *mddev, char *page)
{
+ if (mddev->reshape_position != MaxSector &&
+ mddev->chunk_size != mddev->new_chunk)
+ return sprintf(page, "%d (%d)\n", mddev->new_chunk,
+ mddev->chunk_size);
return sprintf(page, "%d\n", mddev->chunk_size);
}
@@ -2267,12 +2325,15 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
char *e;
unsigned long n = simple_strtoul(buf, &e, 10);
- if (mddev->pers)
- return -EBUSY;
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
- mddev->chunk_size = n;
+ if (mddev->pers)
+ return -EBUSY;
+ else if (mddev->reshape_position != MaxSector)
+ mddev->new_chunk = n;
+ else
+ mddev->chunk_size = n;
return len;
}
static struct md_sysfs_entry md_chunk_size =
@@ -2637,8 +2698,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
minor = simple_strtoul(buf, &e, 10);
if (e==buf || (*e && *e != '\n') )
return -EINVAL;
- if (major >= sizeof(super_types)/sizeof(super_types[0]) ||
- super_types[major].name == NULL)
+ if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
return -ENOENT;
mddev->major_version = major;
mddev->minor_version = minor;
@@ -2859,6 +2919,37 @@ suspend_hi_store(mddev_t *mddev, const char *buf, size_t len)
static struct md_sysfs_entry md_suspend_hi =
__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
+static ssize_t
+reshape_position_show(mddev_t *mddev, char *page)
+{
+ if (mddev->reshape_position != MaxSector)
+ return sprintf(page, "%llu\n",
+ (unsigned long long)mddev->reshape_position);
+ strcpy(page, "none\n");
+ return 5;
+}
+
+static ssize_t
+reshape_position_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ char *e;
+ unsigned long long new = simple_strtoull(buf, &e, 10);
+ if (mddev->pers)
+ return -EBUSY;
+ if (buf == e || (*e && *e != '\n'))
+ return -EINVAL;
+ mddev->reshape_position = new;
+ mddev->delta_disks = 0;
+ mddev->new_level = mddev->level;
+ mddev->new_layout = mddev->layout;
+ mddev->new_chunk = mddev->chunk_size;
+ return len;
+}
+
+static struct md_sysfs_entry md_reshape_position =
+__ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
+ reshape_position_store);
+
static struct attribute *md_default_attrs[] = {
&md_level.attr,
@@ -2871,6 +2962,7 @@ static struct attribute *md_default_attrs[] = {
&md_new_device.attr,
&md_safe_delay.attr,
&md_array_state.attr,
+ &md_reshape_position.attr,
NULL,
};
@@ -3012,6 +3104,7 @@ static int do_md_run(mddev_t * mddev)
struct gendisk *disk;
struct mdk_personality *pers;
char b[BDEVNAME_SIZE];
+ struct block_device *bdev;
if (list_empty(&mddev->disks))
/* cannot run an array with no devices.. */
@@ -3080,7 +3173,7 @@ static int do_md_run(mddev_t * mddev)
if (test_bit(Faulty, &rdev->flags))
continue;
sync_blockdev(rdev->bdev);
- invalidate_bdev(rdev->bdev, 0);
+ invalidate_bdev(rdev->bdev);
}
md_probe(mddev->unit, NULL, NULL);
@@ -3239,7 +3332,13 @@ static int do_md_run(mddev_t * mddev)
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
- mddev->changed = 1;
+ bdev = bdget_disk(mddev->gendisk, 0);
+ if (bdev) {
+ bd_set_size(bdev, mddev->array_size << 1);
+ blkdev_ioctl(bdev->bd_inode, NULL, BLKRRPART, 0);
+ bdput(bdev);
+ }
+
md_new_event(mddev);
kobject_uevent(&mddev->gendisk->kobj, KOBJ_CHANGE);
return 0;
@@ -3361,7 +3460,6 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->pers = NULL;
set_capacity(disk, 0);
- mddev->changed = 1;
if (mddev->ro)
mddev->ro = 0;
@@ -3409,6 +3507,7 @@ static int do_md_stop(mddev_t * mddev, int mode)
mddev->size = 0;
mddev->raid_disks = 0;
mddev->recovery_cp = 0;
+ mddev->reshape_position = MaxSector;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4019,7 +4118,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
if (info->raid_disks == 0) {
/* just setting version number for superblock loading */
if (info->major_version < 0 ||
- info->major_version >= sizeof(super_types)/sizeof(super_types[0]) ||
+ info->major_version >= ARRAY_SIZE(super_types) ||
super_types[info->major_version].name == NULL) {
/* maybe try to auto-load a module? */
printk(KERN_INFO
@@ -4500,20 +4599,6 @@ static int md_release(struct inode *inode, struct file * file)
return 0;
}
-static int md_media_changed(struct gendisk *disk)
-{
- mddev_t *mddev = disk->private_data;
-
- return mddev->changed;
-}
-
-static int md_revalidate(struct gendisk *disk)
-{
- mddev_t *mddev = disk->private_data;
-
- mddev->changed = 0;
- return 0;
-}
static struct block_device_operations md_fops =
{
.owner = THIS_MODULE,
@@ -4521,8 +4606,6 @@ static struct block_device_operations md_fops =
.release = md_release,
.ioctl = md_ioctl,
.getgeo = md_getgeo,
- .media_changed = md_media_changed,
- .revalidate_disk= md_revalidate,
};
static int md_thread(void * arg)
@@ -4941,15 +5024,6 @@ static int md_seq_open(struct inode *inode, struct file *file)
return error;
}
-static int md_seq_release(struct inode *inode, struct file *file)
-{
- struct seq_file *m = file->private_data;
- struct mdstat_info *mi = m->private;
- m->private = NULL;
- kfree(mi);
- return seq_release(inode, file);
-}
-
static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
{
struct seq_file *m = filp->private_data;
@@ -4971,7 +5045,7 @@ static const struct file_operations md_seq_fops = {
.open = md_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = md_seq_release,
+ .release = seq_release_private,
.poll = mdstat_poll,
};
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 97ee870b265..1b7130cad21 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2063,7 +2063,6 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
*/
mddev->array_size = sectors>>1;
set_capacity(mddev->gendisk, mddev->array_size << 1);
- mddev->changed = 1;
if (mddev->array_size > mddev->size && mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->size << 1;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 8d59914f205..a72e70ad097 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -353,8 +353,8 @@ static int grow_stripes(raid5_conf_t *conf, int num)
struct kmem_cache *sc;
int devs = conf->raid_disks;
- sprintf(conf->cache_name[0], "raid5/%s", mdname(conf->mddev));
- sprintf(conf->cache_name[1], "raid5/%s-alt", mdname(conf->mddev));
+ sprintf(conf->cache_name[0], "raid5-%s", mdname(conf->mddev));
+ sprintf(conf->cache_name[1], "raid5-%s-alt", mdname(conf->mddev));
conf->active_name = 0;
sc = kmem_cache_create(conf->cache_name[conf->active_name],
sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
@@ -3864,7 +3864,6 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
mddev->array_size = (sectors * (mddev->raid_disks-conf->max_degraded))>>1;
set_capacity(mddev->gendisk, mddev->array_size << 1);
- mddev->changed = 1;
if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
mddev->recovery_cp = mddev->size << 1;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
@@ -3999,7 +3998,6 @@ static void end_reshape(raid5_conf_t *conf)
conf->mddev->array_size = conf->mddev->size *
(conf->raid_disks - conf->max_degraded);
set_capacity(conf->mddev->gendisk, conf->mddev->array_size << 1);
- conf->mddev->changed = 1;
bdev = bdget_disk(conf->mddev->gendisk, 0);
if (bdev) {
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 5347a406fff..02a0ea6e1c1 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -183,7 +183,8 @@ int flexcop_i2c_init(struct flexcop_device *fc)
mutex_init(&fc->i2c_mutex);
memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
- strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE);
+ strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",
+ sizeof(fc->i2c_adap.name));
i2c_set_adapdata(&fc->i2c_adap,fc);
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 3bf084f2e52..87623d203a8 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -22,7 +22,6 @@
#ifndef DST_COMMON_H
#define DST_COMMON_H
-#include <linux/smp_lock.h>
#include <linux/dvb/frontend.h>
#include <linux/device.h>
#include <linux/mutex.h>
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index a6cbbdd262d..34d7abc900d 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -26,11 +26,11 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
-#include <linux/pci.h>
#include <linux/input.h>
#include <linux/dvb/frontend.h>
#include <linux/mutex.h>
#include <linux/mm.h>
+#include <asm/io.h>
#include "dmxdev.h"
#include "dvb_demux.h"
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 70df31b0a8a..088b6dee3a7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
return -EINVAL;
}
- strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE);
+ strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
#else
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 68ed3a78808..9200a30dd1b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -3,7 +3,7 @@
* Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
- * This file contains functions for initializing the the input-device and for handling remote-control-queries.
+ * This file contains functions for initializing the input-device and for handling remote-control-queries.
*/
#include "dvb-usb-common.h"
#include <linux/usb/input.h>
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index f5d40aa3d27..f64546c6aeb 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -266,7 +266,7 @@ static int dib7000m_sad_calib(struct dib7000m_state *state)
{
/* internal */
-// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+// dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 0349a4b5da3..aece458cfe1 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -223,7 +223,7 @@ static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
static int dib7000p_sad_calib(struct dib7000p_state *state)
{
/* internal */
-// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
+// dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index a18c8f45a2e..315e09e95b0 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -105,9 +105,9 @@ struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enu
}
EXPORT_SYMBOL(dibx000_get_i2c_adapter);
-static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst)
+static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst)
{
- strncpy(i2c_adap->name, name, I2C_NAME_SIZE);
+ strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
i2c_adap->class = I2C_CLASS_TV_DIGITAL,
i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 110536843e8..e725f612a6b 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -1,6 +1,6 @@
/*
TDA10021 - Single Chip Cable Channel Receiver driver module
- used on the the Siemens DVB-C cards
+ used on the Siemens DVB-C cards
Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 54d7b07571b..23fd0303c91 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -306,7 +306,7 @@ static int ves1x93_read_status(struct dvb_frontend* fe, fe_status_t* status)
* The ves1893 sometimes returns sync values that make no sense,
* because, e.g., the SIGNAL bit is 0, while some of the higher
* bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
- * Tests showed that the the VITERBI and SYNC bits are returned
+ * Tests showed that the VITERBI and SYNC bits are returned
* reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
* If such a case occurs, we read the value again, until we get a
* valid value.
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 654c9e919e0..58678c05aa5 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index e9b4e88e793..e1c1294bb76 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -34,7 +34,6 @@
#include <linux/fs.h>
#include <linux/timer.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include "av7110.h"
#include "av7110_hw.h"
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 4d7150e15d1..70aee4eb5da 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index cde5d3ae7ec..fcd9994058d 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -31,7 +31,6 @@
#include <linux/fs.h>
#include <linux/timer.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include "av7110.h"
#include "av7110_hw.h"
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index df8d0520d1d..449df1bb00d 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -79,7 +79,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
/*
* Version Information
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 639e8b6c35b..bc773781993 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -577,14 +577,14 @@ config VIDEO_ZORAN_AVS6EYES
config VIDEO_MEYE
tristate "Sony Vaio Picturebook Motion Eye Video For Linux"
- depends on PCI && SONYPI && VIDEO_V4L1
+ depends on PCI && SONY_LAPTOP && VIDEO_V4L1
---help---
This is the video4linux driver for the Motion Eye camera found
in the Vaio Picturebook laptops. Please read the material in
<file:Documentation/video4linux/meye.txt> for more information.
- If you say Y or M here, you need to say Y or M to "Sony Programmable
- I/O Control Device" in the character device section.
+ If you say Y or M here, you need to say Y or M to "Sony Laptop
+ Extras" in the misc device section.
To compile this driver as a module, choose M here: the
module will be called meye.
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 2aa9ce92060..823cd6cc471 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -37,7 +37,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index a3246a283aa..05c7820fe53 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -33,7 +33,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 68673863d5c..59a43603b5c 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -37,7 +37,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 42e2299dcb2..853b1a3d6a1 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -37,7 +37,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 772fd52d551..2e4cf1efdd2 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -37,7 +37,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index 6eaa692021c..78392fb6f94 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -47,7 +47,6 @@
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
struct cpia_camera_ops
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index 19711aaf9a3..c431df8248d 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -34,7 +34,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/kmod.h>
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 88dbdddeec4..d73c86aeeaa 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/videodev2.h>
-#include <linux/i2c.h>
#include <media/tuner.h>
#include <media/cx2341x.h>
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 3956c257556..2d666b56020 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -27,6 +27,8 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+
#include <asm/delay.h>
#include <sound/driver.h>
#include <sound/core.h>
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index b2eb32e01ae..2ebde2fdbcb 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -26,6 +26,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <asm/delay.h>
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 97ef421dd09..259ea08e784 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -43,14 +43,12 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/poll.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/kthread.h>
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index fbce1d50578..b94ef8ab28c 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,4 +1,3 @@
-
/*
*
* device driver for Conexant 2388x based TV cards
@@ -34,6 +33,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <asm/div64.h>
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index ff4b238090a..a5731f90be0 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -37,7 +37,6 @@
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include "dabusb.h"
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index ed882ebc7b9..418ea8b7f85 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -23,7 +23,6 @@
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/usb.h>
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 563a8319e60..54ccc6e1f92 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -70,7 +70,7 @@ static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr,
ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len);
if (ret != 2 + len) {
- em28xx_warn("writting to i2c device failed (error=%i)\n", ret);
+ em28xx_warn("writing to i2c device failed (error=%i)\n", ret);
return -EIO;
}
for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0;
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index bec67609500..2c7b158ce7e 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1729,7 +1729,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
endpoint = &interface->cur_altsetting->endpoint[1].desc;
- /* check if the the device has the iso in endpoint at the correct place */
+ /* check if the device has the iso in endpoint at the correct place */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 98681da5e3b..664aba8b4d8 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -925,13 +925,13 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
return -EINVAL;
mutex_lock(&meye.lock);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
p->brightness >> 10);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
p->hue >> 10);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
p->colour >> 10);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
p->contrast >> 10);
meye.picture = *p;
mutex_unlock(&meye.lock);
@@ -1043,11 +1043,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.params.quality != jp->quality)
mchip_hic_stop(); /* need restart */
meye.params = *jp;
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
meye.params.sharpness);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
meye.params.agc);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE,
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
meye.params.picture);
mutex_unlock(&meye.lock);
break;
@@ -1287,38 +1287,38 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
mutex_lock(&meye.lock);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERABRIGHTNESS, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
meye.picture.brightness = c->value << 10;
break;
case V4L2_CID_HUE:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERAHUE, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
meye.picture.hue = c->value << 10;
break;
case V4L2_CID_CONTRAST:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERACONTRAST, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
meye.picture.contrast = c->value << 10;
break;
case V4L2_CID_SATURATION:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERACOLOR, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
meye.picture.colour = c->value << 10;
break;
case V4L2_CID_AGC:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERAAGC, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
meye.params.agc = c->value;
break;
case V4L2_CID_SHARPNESS:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERASHARPNESS, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
meye.params.sharpness = c->value;
break;
case V4L2_CID_PICTURE:
- sonypi_camera_command(
- SONYPI_COMMAND_SETCAMERAPICTURE, c->value);
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
meye.params.picture = c->value;
break;
case V4L2_CID_JPEGQUAL:
@@ -1848,7 +1848,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
memcpy(meye.video_dev, &meye_template, sizeof(meye_template));
meye.video_dev->dev = &meye.mchip_dev->dev;
- if ((ret = sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 1))) {
+ if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) {
printk(KERN_ERR "meye: unable to power on the camera\n");
printk(KERN_ERR "meye: did you enable the camera in "
"sonypi using the module options ?\n");
@@ -1928,13 +1928,13 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
meye.params.picture = 0;
meye.params.framerate = 0;
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACOLOR, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERASHARPNESS, 32);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, 0);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERAAGC, 48);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS, 32);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION);
@@ -1953,7 +1953,7 @@ outremap:
outregions:
pci_disable_device(meye.mchip_dev);
outenabledev:
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
outsonypienable:
kfifo_free(meye.doneq);
outkfifoalloc2:
@@ -1986,7 +1986,7 @@ static void __devexit meye_remove(struct pci_dev *pcidev)
pci_disable_device(meye.mchip_dev);
- sonypi_camera_command(SONYPI_COMMAND_SETCAMERA, 0);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 0);
kfifo_free(meye.doneq);
kfifo_free(meye.grabq);
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index ea107cb5c84..323d0074120 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -255,7 +255,7 @@
/****************************************************************************/
/* Sony Programmable I/O Controller for accessing the camera commands */
-#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
/* private API definitions */
#include <linux/meye.h>
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 68b082bcee1..18c64222dd1 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -4,7 +4,6 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
index 1231335a9f4..50c7763d44b 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -15,6 +15,7 @@
#ifndef __LINUX_OVCAMCHIP_PRIV_H
#define __LINUX_OVCAMCHIP_PRIV_H
+#include <linux/i2c.h>
#include <media/ovcamchip.h>
#ifdef DEBUG
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index fe184f93c01..1455a8f4e93 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -2160,7 +2160,7 @@ static int find_planb(void)
if (!machine_is(powermac))
return 0;
- planb_devices = find_devices("planb");
+ planb_devices = of_find_node_by_name(NULL, "planb");
if (planb_devices == 0) {
planb_num=0;
printk(KERN_WARNING "PlanB: no device found!\n");
@@ -2175,12 +2175,14 @@ static int find_planb(void)
if (planb_devices->n_addrs != 1) {
printk (KERN_WARNING "PlanB: expecting 1 address for planb "
"(got %d)", planb_devices->n_addrs);
+ of_node_put(planb_devices);
return 0;
}
if (planb_devices->n_intrs == 0) {
printk(KERN_WARNING "PlanB: no intrs for device %s\n",
planb_devices->full_name);
+ of_node_put(planb_devices);
return 0;
} else {
irq = planb_devices->intrs[0].line;
@@ -2202,6 +2204,7 @@ static int find_planb(void)
confreg = planb_devices->addrs[0].space & 0xff;
old_base = planb_devices->addrs[0].address;
new_base = 0xf1000000;
+ of_node_put(planb_devices);
DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
"membase 0x%x (base reg. 0x%x)\n",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index e976c484c05..9ea41c6699b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
index f5e84841031..f9f3584281d 100644
--- a/drivers/media/video/pwc/philips.txt
+++ b/drivers/media/video/pwc/philips.txt
@@ -54,9 +54,9 @@ fps
Specifies the desired framerate. Is an integer in the range of 4-30.
fbufs
- This paramter specifies the number of internal buffers to use for storing
+ This parameter specifies the number of internal buffers to use for storing
frames from the cam. This will help if the process that reads images from
- the cam is a bit slow or momentarely busy. However, on slow machines it
+ the cam is a bit slow or momentarily busy. However, on slow machines it
only introduces lag, so choose carefully. The default is 3, which is
reasonable. You can set it between 2 and 5.
@@ -209,7 +209,7 @@ trace
128 0x80 PWCX debugging Off
- For example, to trace the open() & read() fuctions, sum 8 + 4 = 12,
+ For example, to trace the open() & read() functions, sum 8 + 4 = 12,
so you would supply trace=12 during insmod or modprobe. If
you want to turn the initialization and probing tracing off, set trace=0.
The default value for trace is 35 (0x23).
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index 44dc7479119..74839f98b7c 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -36,7 +36,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 2ce3321ab99..87c3144ec7f 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -39,7 +39,6 @@
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 269d7114a93..80bf9118785 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -30,7 +30,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index dd759d6d8d2..7b56041186d 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <asm/div64.h>
#include "saa7134-reg.h"
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index e0fdb1ab758..339592e7722 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -33,7 +33,6 @@
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
index c0891b3e001..835ef872e80 100644
--- a/drivers/media/video/se401.h
+++ b/drivers/media/video/se401.h
@@ -5,7 +5,6 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#define se401_DEBUG /* Turn on debug messages */
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index a2da5d2afff..c9bf9dbc2ea 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -26,7 +26,6 @@
#include <linux/videodev.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index 687f026753b..37ce36b9e58 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/spinlock.h>
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 876fd276824..982b115193f 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -28,7 +28,7 @@
*
* Portions of this code were also copied from usbvideo.c
*
- * Special thanks to the the whole team at Sourceforge for help making
+ * Special thanks to the whole team at Sourceforge for help making
* this driver become a reality. Notably:
* Andy Armstrong who reverse engineered the color encoding and
* Pavel Machek and Chris Cheney who worked on reverse engineering the
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 13f69fe6360..51ab265d566 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -24,7 +24,6 @@
#include <linux/list.h>
-#include <linux/i2c.h>
#include <media/v4l2-dev.h>
#include <media/tuner.h>
#include "usbvision.h"
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index bcb551adb7e..9118a6227ea 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -30,7 +30,6 @@
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/highmem.h>
-#include <linux/smp_lock.h>
#include <linux/videodev.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 216704170a4..aa3258bbb4a 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -52,7 +52,6 @@
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/highmem.h>
-#include <linux/smp_lock.h>
#include <linux/videodev.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index d2c1ae0dbfb..a861e150865 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -23,7 +23,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 49f1df74aa2..13ee550d321 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -47,7 +47,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 80ac5f86d9e..5263b50463e 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 07432373335..cf0ed6cbb0e 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -2034,7 +2034,7 @@ zoran_do_ioctl (struct inode *inode,
* but moving the free code outside the munmap() handler fixes
* all this... If someone knows why, please explain me (Ronald)
*/
- if (!!mutex_trylock(&zr->resource_lock)) {
+ if (mutex_trylock(&zr->resource_lock)) {
/* we obtained it! Let's try to free some things */
if (fh->jpg_buffers.ready_to_be_freed)
jpg_fbuffer_free(file);
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index d6b4c607453..ddc7ae029dd 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -571,7 +571,7 @@ mpi_fc.h
* 11-02-00 01.01.01 Original release for post 1.0 work
* 12-04-00 01.01.02 Added messages for Common Transport Send and
* Primitive Send.
- * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix
+ * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix
* and modified the FcPrimitiveSend flags.
* 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger
* field.
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 083acfd91d8..5021d1a2a1d 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1531,6 +1531,7 @@ mpt_resume(struct pci_dev *pdev)
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
u32 device_state = pdev->current_state;
int recovery_state;
+ int err;
printk(MYIOC_s_INFO_FMT
"pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n",
@@ -1538,7 +1539,9 @@ mpt_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
/* enable interrupts */
CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM);
@@ -3582,7 +3585,7 @@ initChainBuffers(MPT_ADAPTER *ioc)
* index = chain_idx
*
* Calculate the number of chain buffers needed(plus 1) per I/O
- * then multiply the the maximum number of simultaneous cmds
+ * then multiply the maximum number of simultaneous cmds
*
* num_sge = num sge in request frame + last chain buffer
* scale = num sge per chain buffer if no chain element
@@ -4739,12 +4742,8 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum)
}
/**
- * mpt_inactive_raid_list_free
- *
- * This clears this link list.
- *
- * @ioc - pointer to per adapter structure
- *
+ * mpt_inactive_raid_list_free - This clears this link list.
+ * @ioc : pointer to per adapter structure
**/
static void
mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
@@ -4764,15 +4763,11 @@ mpt_inactive_raid_list_free(MPT_ADAPTER *ioc)
}
/**
- * mpt_inactive_raid_volumes
- *
- * This sets up link list of phy_disk_nums for devices belonging in an inactive volume
- *
- * @ioc - pointer to per adapter structure
- * @channel - volume channel
- * @id - volume target id
- *
+ * mpt_inactive_raid_volumes - sets up link list of phy_disk_nums for devices belonging in an inactive volume
*
+ * @ioc : pointer to per adapter structure
+ * @channel : volume channel
+ * @id : volume target id
**/
static void
mpt_inactive_raid_volumes(MPT_ADAPTER *ioc, u8 channel, u8 id)
@@ -6663,7 +6658,7 @@ union loginfo_type {
/**
* mpt_iocstatus_info_config - IOCSTATUS information for config pages
* @ioc: Pointer to MPT_ADAPTER structure
- * ioc_status: U32 IOCStatus word from IOC
+ * @ioc_status: U32 IOCStatus word from IOC
* @mf: Pointer to MPT request frame
*
* Refer to lsi/mpi.h.
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index e3a39272aad..d25d3be8fcd 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -994,6 +994,7 @@ typedef struct _MPT_SCSI_HOST {
int scandv_wait_done;
long last_queue_full;
u16 tm_iocstatus;
+ u16 spi_pending;
struct list_head target_reset_list;
} MPT_SCSI_HOST;
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 2a3e9e66d4e..fa0f7761652 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -819,10 +819,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->resid=0;
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
- if (scsi_status == MPI_SCSI_STATUS_BUSY)
- sc->result = (DID_BUS_BUSY << 16) | scsi_status;
- else
- sc->result = (DID_OK << 16) | scsi_status;
+ sc->result = (DID_OK << 16) | scsi_status;
if (scsi_state == 0) {
;
} else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) {
@@ -1188,20 +1185,7 @@ mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
int
mptscsih_resume(struct pci_dev *pdev)
{
- MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- struct Scsi_Host *host = ioc->sh;
- MPT_SCSI_HOST *hd;
-
- mpt_resume(pdev);
-
- if(!host)
- return 0;
-
- hd = (MPT_SCSI_HOST *)host->hostdata;
- if(!hd)
- return 0;
-
- return 0;
+ return mpt_resume(pdev);
}
#endif
@@ -1537,21 +1521,23 @@ mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx)
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mptscsih_TMHandler - Generic handler for SCSI Task Management.
- * Fall through to mpt_HardResetHandler if: not operational, too many
- * failed TM requests or handshake failure.
- *
- * @ioc: Pointer to MPT_ADAPTER structure
+ * @hd: Pointer to MPT SCSI HOST structure
* @type: Task Management type
+ * @channel: channel number for task management
* @id: Logical Target ID for reset (if appropriate)
* @lun: Logical Unit for reset (if appropriate)
* @ctx2abort: Context for the task to be aborted (if appropriate)
+ * @timeout: timeout for task management control
+ *
+ * Fall through to mpt_HardResetHandler if: not operational, too many
+ * failed TM requests or handshake failure.
*
* Remark: Currently invoked from a non-interrupt thread (_bh).
*
* Remark: With old EH code, at most 1 SCSI TaskMgmt function per IOC
* will be active.
*
- * Returns 0 for SUCCESS, or FAILED.
+ * Returns 0 for SUCCESS, or %FAILED.
**/
int
mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout)
@@ -1650,9 +1636,11 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int c
* mptscsih_IssueTaskMgmt - Generic send Task Management function.
* @hd: Pointer to MPT_SCSI_HOST structure
* @type: Task Management type
+ * @channel: channel number for task management
* @id: Logical Target ID for reset (if appropriate)
* @lun: Logical Unit for reset (if appropriate)
* @ctx2abort: Context for the task to be aborted (if appropriate)
+ * @timeout: timeout for task management control
*
* Remark: _HardResetHandler can be invoked from an interrupt thread (timer)
* or a non-interrupt thread. In the former, must not call schedule().
@@ -2022,6 +2010,7 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd)
/**
* mptscsih_tm_wait_for_completion - wait for completion of TM task
* @hd: Pointer to MPT host structure.
+ * @timeout: timeout value
*
* Returns {SUCCESS,FAILED}.
*/
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 85f21b54cb7..d75f7ffbb02 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -96,14 +96,13 @@ static int mptspiTaskCtx = -1;
static int mptspiInternalCtx = -1; /* Used only for internal commands */
/**
- * mptspi_setTargetNegoParms - Update the target negotiation
- * parameters based on the the Inquiry data, adapter capabilities,
- * and NVRAM settings
- *
+ * mptspi_setTargetNegoParms - Update the target negotiation parameters
* @hd: Pointer to a SCSI Host Structure
- * @vtarget: per target private data
+ * @target: per target private data
* @sdev: SCSI device
*
+ * Update the target negotiation parameters based on the the Inquiry
+ * data, adapter capabilities, and NVRAM settings.
**/
static void
mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
@@ -234,7 +233,7 @@ mptspi_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtTarget *target,
/**
* mptspi_writeIOCPage4 - write IOC Page 4
* @hd: Pointer to a SCSI Host Structure
- * @channel:
+ * @channel: channel number
* @id: write IOC Page4 for this ID & Bus
*
* Return: -EAGAIN if unable to obtain a Message Frame
@@ -446,7 +445,7 @@ static int mptspi_target_alloc(struct scsi_target *starget)
return 0;
}
-void
+static void
mptspi_target_destroy(struct scsi_target *starget)
{
if (starget->hostdata)
@@ -677,7 +676,9 @@ static void mptspi_dv_device(struct _MPT_SCSI_HOST *hd,
return;
}
+ hd->spi_pending |= (1 << sdev->id);
spi_dv_device(sdev);
+ hd->spi_pending &= ~(1 << sdev->id);
if (sdev->channel == 1 &&
mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
@@ -1203,11 +1204,27 @@ mptspi_dv_renegotiate_work(struct work_struct *work)
container_of(work, struct work_queue_wrapper, work);
struct _MPT_SCSI_HOST *hd = wqw->hd;
struct scsi_device *sdev;
+ struct scsi_target *starget;
+ struct _CONFIG_PAGE_SCSI_DEVICE_1 pg1;
+ u32 nego;
kfree(wqw);
- shost_for_each_device(sdev, hd->ioc->sh)
- mptspi_dv_device(hd, sdev);
+ if (hd->spi_pending) {
+ shost_for_each_device(sdev, hd->ioc->sh) {
+ if (hd->spi_pending & (1 << sdev->id))
+ continue;
+ starget = scsi_target(sdev);
+ nego = mptspi_getRP(starget);
+ pg1.RequestedParameters = cpu_to_le32(nego);
+ pg1.Reserved = 0;
+ pg1.Configuration = 0;
+ mptspi_write_spi_device_pg1(starget, &pg1);
+ }
+ } else {
+ shost_for_each_device(sdev, hd->ioc->sh)
+ mptspi_dv_device(hd, sdev);
+ }
}
static void
@@ -1453,6 +1470,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
init_waitqueue_head(&hd->scandv_waitq);
hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
+ hd->spi_pending = 0;
/* Some versions of the firmware don't support page 0; without
* that we can't get the parameters */
diff --git a/drivers/message/i2o/i2o_lan.h b/drivers/message/i2o/i2o_lan.h
deleted file mode 100644
index 6502b817df5..00000000000
--- a/drivers/message/i2o/i2o_lan.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * i2o_lan.h I2O LAN Class definitions
- *
- * I2O LAN CLASS OSM May 26th 2000
- *
- * (C) Copyright 1999, 2000 University of Helsinki,
- * Department of Computer Science
- *
- * This code is still under development / test.
- *
- * Author: Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Taneli Vähäkangas <Taneli.Vahakangas@cs.Helsinki.FI>
- */
-
-#ifndef _I2O_LAN_H
-#define _I2O_LAN_H
-
-/* Default values for tunable parameters first */
-
-#define I2O_LAN_MAX_BUCKETS_OUT 96
-#define I2O_LAN_BUCKET_THRESH 18 /* 9 buckets in one message */
-#define I2O_LAN_RX_COPYBREAK 200
-#define I2O_LAN_TX_TIMEOUT (1*HZ)
-#define I2O_LAN_TX_BATCH_MODE 2 /* 2=automatic, 1=on, 0=off */
-#define I2O_LAN_EVENT_MASK 0 /* 0=None, 0xFFC00002=All */
-
-/* LAN types */
-#define I2O_LAN_ETHERNET 0x0030
-#define I2O_LAN_100VG 0x0040
-#define I2O_LAN_TR 0x0050
-#define I2O_LAN_FDDI 0x0060
-#define I2O_LAN_FIBRE_CHANNEL 0x0070
-#define I2O_LAN_UNKNOWN 0x00000000
-
-/* Connector types */
-
-/* Ethernet */
-#define I2O_LAN_AUI (I2O_LAN_ETHERNET << 4) + 0x00000001
-#define I2O_LAN_10BASE5 (I2O_LAN_ETHERNET << 4) + 0x00000002
-#define I2O_LAN_FIORL (I2O_LAN_ETHERNET << 4) + 0x00000003
-#define I2O_LAN_10BASE2 (I2O_LAN_ETHERNET << 4) + 0x00000004
-#define I2O_LAN_10BROAD36 (I2O_LAN_ETHERNET << 4) + 0x00000005
-#define I2O_LAN_10BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000006
-#define I2O_LAN_10BASE_FP (I2O_LAN_ETHERNET << 4) + 0x00000007
-#define I2O_LAN_10BASE_FB (I2O_LAN_ETHERNET << 4) + 0x00000008
-#define I2O_LAN_10BASE_FL (I2O_LAN_ETHERNET << 4) + 0x00000009
-#define I2O_LAN_100BASE_TX (I2O_LAN_ETHERNET << 4) + 0x0000000A
-#define I2O_LAN_100BASE_FX (I2O_LAN_ETHERNET << 4) + 0x0000000B
-#define I2O_LAN_100BASE_T4 (I2O_LAN_ETHERNET << 4) + 0x0000000C
-#define I2O_LAN_1000BASE_SX (I2O_LAN_ETHERNET << 4) + 0x0000000D
-#define I2O_LAN_1000BASE_LX (I2O_LAN_ETHERNET << 4) + 0x0000000E
-#define I2O_LAN_1000BASE_CX (I2O_LAN_ETHERNET << 4) + 0x0000000F
-#define I2O_LAN_1000BASE_T (I2O_LAN_ETHERNET << 4) + 0x00000010
-
-/* AnyLAN */
-#define I2O_LAN_100VG_ETHERNET (I2O_LAN_100VG << 4) + 0x00000001
-#define I2O_LAN_100VG_TR (I2O_LAN_100VG << 4) + 0x00000002
-
-/* Token Ring */
-#define I2O_LAN_4MBIT (I2O_LAN_TR << 4) + 0x00000001
-#define I2O_LAN_16MBIT (I2O_LAN_TR << 4) + 0x00000002
-
-/* FDDI */
-#define I2O_LAN_125MBAUD (I2O_LAN_FDDI << 4) + 0x00000001
-
-/* Fibre Channel */
-#define I2O_LAN_POINT_POINT (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000001
-#define I2O_LAN_ARB_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000002
-#define I2O_LAN_PUBLIC_LOOP (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000003
-#define I2O_LAN_FABRIC (I2O_LAN_FIBRE_CHANNEL << 4) + 0x00000004
-
-#define I2O_LAN_EMULATION 0x00000F00
-#define I2O_LAN_OTHER 0x00000F01
-#define I2O_LAN_DEFAULT 0xFFFFFFFF
-
-/* LAN class functions */
-
-#define LAN_PACKET_SEND 0x3B
-#define LAN_SDU_SEND 0x3D
-#define LAN_RECEIVE_POST 0x3E
-#define LAN_RESET 0x35
-#define LAN_SUSPEND 0x37
-
-/* LAN DetailedStatusCode defines */
-#define I2O_LAN_DSC_SUCCESS 0x00
-#define I2O_LAN_DSC_DEVICE_FAILURE 0x01
-#define I2O_LAN_DSC_DESTINATION_NOT_FOUND 0x02
-#define I2O_LAN_DSC_TRANSMIT_ERROR 0x03
-#define I2O_LAN_DSC_TRANSMIT_ABORTED 0x04
-#define I2O_LAN_DSC_RECEIVE_ERROR 0x05
-#define I2O_LAN_DSC_RECEIVE_ABORTED 0x06
-#define I2O_LAN_DSC_DMA_ERROR 0x07
-#define I2O_LAN_DSC_BAD_PACKET_DETECTED 0x08
-#define I2O_LAN_DSC_OUT_OF_MEMORY 0x09
-#define I2O_LAN_DSC_BUCKET_OVERRUN 0x0A
-#define I2O_LAN_DSC_IOP_INTERNAL_ERROR 0x0B
-#define I2O_LAN_DSC_CANCELED 0x0C
-#define I2O_LAN_DSC_INVALID_TRANSACTION_CONTEXT 0x0D
-#define I2O_LAN_DSC_DEST_ADDRESS_DETECTED 0x0E
-#define I2O_LAN_DSC_DEST_ADDRESS_OMITTED 0x0F
-#define I2O_LAN_DSC_PARTIAL_PACKET_RETURNED 0x10
-#define I2O_LAN_DSC_SUSPENDED 0x11
-
-struct i2o_packet_info {
- u32 offset:24;
- u32 flags:8;
- u32 len:24;
- u32 status:8;
-};
-
-struct i2o_bucket_descriptor {
- u32 context; /* FIXME: 64bit support */
- struct i2o_packet_info packet_info[1];
-};
-
-/* Event Indicator Mask Flags for LAN OSM */
-
-#define I2O_LAN_EVT_LINK_DOWN 0x01
-#define I2O_LAN_EVT_LINK_UP 0x02
-#define I2O_LAN_EVT_MEDIA_CHANGE 0x04
-
-#include <linux/netdevice.h>
-#include <linux/fddidevice.h>
-
-struct i2o_lan_local {
- u8 unit;
- struct i2o_device *i2o_dev;
-
- struct fddi_statistics stats; /* see also struct net_device_stats */
- unsigned short (*type_trans) (struct sk_buff *, struct net_device *);
- atomic_t buckets_out; /* nbr of unused buckets on DDM */
- atomic_t tx_out; /* outstanding TXes */
- u8 tx_count; /* packets in one TX message frame */
- u16 tx_max_out; /* DDM's Tx queue len */
- u8 sgl_max; /* max SGLs in one message frame */
- u32 m; /* IOP address of the batch msg frame */
-
- struct work_struct i2o_batch_send_task;
- int send_active;
- struct sk_buff **i2o_fbl; /* Free bucket list (to reuse skbs) */
- int i2o_fbl_tail;
- spinlock_t fbl_lock;
-
- spinlock_t tx_lock;
-
- u32 max_size_mc_table; /* max number of multicast addresses */
-
- /* LAN OSM configurable parameters are here: */
-
- u16 max_buckets_out; /* max nbr of buckets to send to DDM */
- u16 bucket_thresh; /* send more when this many used */
- u16 rx_copybreak;
-
- u8 tx_batch_mode; /* Set when using batch mode sends */
- u32 i2o_event_mask; /* To turn on interesting event flags */
-};
-
-#endif /* _I2O_LAN_H */
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index ce1a4810821..cb8c264eaff 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -21,7 +21,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/delay.h>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 80b199fa0aa..877e7909a0e 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -25,6 +25,15 @@ config IBM_ASM
information on the specific driver level and support statement
for your IBM server.
+config PHANTOM
+ tristate "Sensable PHANToM"
+ depends on PCI
+ help
+ Say Y here if you want to build a driver for Sensable PHANToM device.
+
+ If you choose to build module, its name will be phantom. If unsure,
+ say N here.
+
If unsure, say N.
@@ -112,14 +121,79 @@ config SONY_LAPTOP
depends on X86 && ACPI
select BACKLIGHT_CLASS_DEVICE
---help---
- This mini-driver drives the SNC device present in the ACPI BIOS of
- the Sony Vaio laptops.
+ This mini-driver drives the SNC and SPIC devices present in the ACPI
+ BIOS of the Sony Vaio laptops.
- It gives access to some extra laptop functionalities. In its current
- form, this driver let the user set or query the screen brightness
- through the backlight subsystem and remove/apply power to some
+ It gives access to some extra laptop functionalities like Bluetooth,
+ screen brightness control, Fn keys and allows powering on/off some
devices.
Read <file:Documentation/sony-laptop.txt> for more information.
+config SONY_LAPTOP_OLD
+ bool "Sonypi compatibility"
+ depends on SONY_LAPTOP
+ ---help---
+ Build the sonypi driver compatibility code into the sony-laptop driver.
+
+config THINKPAD_ACPI
+ tristate "ThinkPad ACPI Laptop Extras"
+ depends on X86 && ACPI
+ select BACKLIGHT_CLASS_DEVICE
+ select HWMON
+ ---help---
+ This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
+ support for Fn-Fx key combinations, Bluetooth control, video
+ output switching, ThinkLight control, UltraBay eject and more.
+ For more information about this driver see
+ <file:Documentation/thinkpad-acpi.txt> and <http://ibm-acpi.sf.net/> .
+
+ This driver was formely known as ibm-acpi.
+
+ If you have an IBM or Lenovo ThinkPad laptop, say Y or M here.
+
+config THINKPAD_ACPI_DEBUG
+ bool "Verbose debug mode"
+ depends on THINKPAD_ACPI
+ default n
+ ---help---
+ Enables extra debugging information, at the expense of a slightly
+ increase in driver size.
+
+ If you are not sure, say N here.
+
+config THINKPAD_ACPI_DOCK
+ bool "Legacy Docking Station Support"
+ depends on THINKPAD_ACPI
+ depends on ACPI_DOCK=n
+ default n
+ ---help---
+ Allows the thinkpad_acpi driver to handle docking station events.
+ This support was made obsolete by the generic ACPI docking station
+ support (CONFIG_ACPI_DOCK). It will allow locking and removing the
+ laptop from the docking station, but will not properly connect PCI
+ devices.
+
+ If you are not sure, say N here.
+
+config THINKPAD_ACPI_BAY
+ bool "Legacy Removable Bay Support"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Allows the thinkpad_acpi driver to handle removable bays. It will
+ eletrically disable the device in the bay, and also generate
+ notifications when the bay lever is ejected or inserted.
+
+ If you are not sure, say Y here.
+
+config BLINK
+ tristate "Keyboard blink driver"
+ help
+ Driver that when loaded will blink the keyboard LEDs continuously.
+ This is useful for debugging and for kernels that cannot necessarily
+ output something to the screen like kexec kernels to give the user
+ a visual indication that the kernel is doing something.
+
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 7793ccd7904..5b6d46de005 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,8 +7,11 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_BLINK) += blink.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
+obj-$(CONFIG_PHANTOM) += phantom.o
obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
+obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 4b232124a1a..65c32a95e12 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -3,7 +3,7 @@
*
*
* Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- * Copyright (C) 2006 Corentin Chary
+ * Copyright (C) 2006-2007 Corentin Chary
*
* 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
@@ -48,7 +48,7 @@
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
-#define ASUS_LAPTOP_VERSION "0.40"
+#define ASUS_LAPTOP_VERSION "0.41"
#define ASUS_HOTK_NAME "Asus Laptop Support"
#define ASUS_HOTK_CLASS "hotkey"
@@ -81,7 +81,8 @@
#define TLED_ON 0x08 //touchpad LED
#define RLED_ON 0x10 //Record LED
#define PLED_ON 0x20 //Phone LED
-#define LCD_ON 0x40 //LCD backlight
+#define GLED_ON 0x40 //Gaming LED
+#define LCD_ON 0x80 //LCD backlight
#define ASUS_LOG ASUS_HOTK_FILE ": "
#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -94,6 +95,19 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
MODULE_DESCRIPTION(ASUS_HOTK_NAME);
MODULE_LICENSE("GPL");
+/* WAPF defines the behavior of the Fn+Fx wlan key
+ * The significance of values is yet to be found, but
+ * most of the time:
+ * 0x0 will do nothing
+ * 0x1 will allow to control the device with Fn+Fx key.
+ * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
+ * 0x5 like 0x1 or 0x4
+ * So, if something doesn't work as you want, just try other values =)
+ */
+static uint wapf = 1;
+module_param(wapf, uint, 0644);
+MODULE_PARM_DESC(wapf, "WAPF value");
+
#define ASUS_HANDLE(object, paths...) \
static acpi_handle object##_handle = NULL; \
static char *object##_paths[] = { paths }
@@ -103,6 +117,7 @@ ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED"); /* W1JC */
ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED"); /* A7J */
+ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
/* LEDD */
ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
@@ -221,6 +236,7 @@ ASUS_LED(mled, "mail");
ASUS_LED(tled, "touchpad");
ASUS_LED(rled, "record");
ASUS_LED(pled, "phone");
+ASUS_LED(gled, "gaming");
/*
* This function evaluates an ACPI method, given an int as parameter, the
@@ -245,32 +261,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
return (status == AE_OK);
}
-static int read_acpi_int(acpi_handle handle, const char *method, int *val,
- struct acpi_object_list *params)
-{
- struct acpi_buffer output;
- union acpi_object out_obj;
- acpi_status status;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- status = acpi_evaluate_object(handle, (char *)method, params, &output);
- *val = out_obj.integer.value;
- return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
static int read_wireless_status(int mask)
{
- int status;
+ ulong status;
+ acpi_status rv = AE_OK;
if (!wireless_status_handle)
return (hotk->status & mask) ? 1 : 0;
- if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
- return (status & mask) ? 1 : 0;
- } else
+ rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);
+ if (ACPI_FAILURE(rv))
printk(ASUS_WARNING "Error reading Wireless status\n");
+ else
+ return (status & mask) ? 1 : 0;
return (hotk->status & mask) ? 1 : 0;
}
@@ -285,19 +288,28 @@ static int read_status(int mask)
return (hotk->status & mask) ? 1 : 0;
}
-static void write_status(acpi_handle handle, int out, int mask, int invert)
+static void write_status(acpi_handle handle, int out, int mask)
{
hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
- if (invert) /* invert target value */
+ switch (mask) {
+ case MLED_ON:
out = !out & 0x1;
+ break;
+ case GLED_ON:
+ out = (out & 0x1) + 1;
+ break;
+ default:
+ out &= 0x1;
+ break;
+ }
if (handle && !write_acpi_int(handle, NULL, out, NULL))
- printk(ASUS_WARNING " write failed\n");
+ printk(ASUS_WARNING " write failed %x\n", mask);
}
/* /sys/class/led handlers */
-#define ASUS_LED_HANDLER(object, mask, invert) \
+#define ASUS_LED_HANDLER(object, mask) \
static void object##_led_set(struct led_classdev *led_cdev, \
enum led_brightness value) \
{ \
@@ -307,13 +319,14 @@ static void write_status(acpi_handle handle, int out, int mask, int invert)
static void object##_led_update(struct work_struct *ignored) \
{ \
int value = object##_led_wk; \
- write_status(object##_set_handle, value, (mask), (invert)); \
+ write_status(object##_set_handle, value, (mask)); \
}
-ASUS_LED_HANDLER(mled, MLED_ON, 1);
-ASUS_LED_HANDLER(pled, PLED_ON, 0);
-ASUS_LED_HANDLER(rled, RLED_ON, 0);
-ASUS_LED_HANDLER(tled, TLED_ON, 0);
+ASUS_LED_HANDLER(mled, MLED_ON);
+ASUS_LED_HANDLER(pled, PLED_ON);
+ASUS_LED_HANDLER(rled, RLED_ON);
+ASUS_LED_HANDLER(tled, TLED_ON);
+ASUS_LED_HANDLER(gled, GLED_ON);
static int get_lcd_state(void)
{
@@ -338,7 +351,7 @@ static int set_lcd_state(int value)
printk(ASUS_WARNING "Error switching LCD\n");
}
- write_status(NULL, lcd, LCD_ON, 0);
+ write_status(NULL, lcd, LCD_ON);
return 0;
}
@@ -354,9 +367,11 @@ static void lcd_blank(int blank)
static int read_brightness(struct backlight_device *bd)
{
- int value;
+ ulong value;
+ acpi_status rv = AE_OK;
- if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+ rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);
+ if (ACPI_FAILURE(rv))
printk(ASUS_WARNING "Error reading brightness\n");
return value;
@@ -403,8 +418,10 @@ static ssize_t show_infos(struct device *dev,
struct device_attribute *attr, char *page)
{
int len = 0;
- int temp;
+ ulong temp;
char buf[16]; //enough for all info
+ acpi_status rv = AE_OK;
+
/*
* We use the easy way, we don't care of off and count, so we don't set eof
* to 1
@@ -418,9 +435,10 @@ static ssize_t show_infos(struct device *dev,
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* The significance of others is yet to be found.
*/
- if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
- len +=
- sprintf(page + len, "SFUN value : 0x%04x\n", temp);
+ rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
+ if (!ACPI_FAILURE(rv))
+ len += sprintf(page + len, "SFUN value : 0x%04x\n",
+ (uint) temp);
/*
* Another value for userspace: the ASYM method returns 0x02 for
* battery low and 0x04 for battery critical, its readings tend to be
@@ -428,9 +446,10 @@ static ssize_t show_infos(struct device *dev,
* Note: since not all the laptops provide this method, errors are
* silently ignored.
*/
- if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
- len +=
- sprintf(page + len, "ASYM value : 0x%04x\n", temp);
+ rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
+ if (!ACPI_FAILURE(rv))
+ len += sprintf(page + len, "ASYM value : 0x%04x\n",
+ (uint) temp);
if (asus_info) {
snprintf(buf, 16, "%d", asus_info->length);
len += sprintf(page + len, "DSDT length : %s\n", buf);
@@ -465,7 +484,7 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
}
static ssize_t store_status(const char *buf, size_t count,
- acpi_handle handle, int mask, int invert)
+ acpi_handle handle, int mask)
{
int rv, value;
int out = 0;
@@ -474,7 +493,7 @@ static ssize_t store_status(const char *buf, size_t count,
if (rv > 0)
out = value ? 1 : 0;
- write_status(handle, out, mask, invert);
+ write_status(handle, out, mask);
return rv;
}
@@ -515,7 +534,7 @@ static ssize_t show_wlan(struct device *dev,
static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+ return store_status(buf, count, wl_switch_handle, WL_ON);
}
/*
@@ -531,7 +550,7 @@ static ssize_t store_bluetooth(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
- return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+ return store_status(buf, count, bt_switch_handle, BT_ON);
}
/*
@@ -547,12 +566,15 @@ static void set_display(int value)
static int read_display(void)
{
- int value = 0;
+ ulong value = 0;
+ acpi_status rv = AE_OK;
/* In most of the case, we know how to set the display, but sometime
we can't read it */
if (display_get_handle) {
- if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+ rv = acpi_evaluate_integer(display_get_handle, NULL,
+ NULL, &value);
+ if (ACPI_FAILURE(rv))
printk(ASUS_WARNING "Error reading display status\n");
}
@@ -656,10 +678,10 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
* switched
*/
if (event == ATKD_LCD_ON) {
- write_status(NULL, 1, LCD_ON, 0);
+ write_status(NULL, 1, LCD_ON);
lcd_blank(FB_BLANK_UNBLANK);
} else if (event == ATKD_LCD_OFF) {
- write_status(NULL, 0, LCD_ON, 0);
+ write_status(NULL, 0, LCD_ON);
lcd_blank(FB_BLANK_POWERDOWN);
}
@@ -771,7 +793,7 @@ static int asus_hotk_get_info(void)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
- int bsts_result, hwrs_result;
+ ulong bsts_result, hwrs_result;
char *string = NULL;
acpi_status status;
@@ -794,11 +816,16 @@ static int asus_hotk_get_info(void)
}
/* This needs to be called for some laptops to init properly */
- if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+ status =
+ acpi_evaluate_integer(hotk->handle, "BSTS", NULL, &bsts_result);
+ if (ACPI_FAILURE(status))
printk(ASUS_WARNING "Error calling BSTS\n");
else if (bsts_result)
printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
- bsts_result);
+ (uint) bsts_result);
+
+ /* This too ... */
+ write_acpi_int(hotk->handle, "CWAP", wapf, NULL);
/*
* Try to match the object returned by INIT to the specific model.
@@ -831,6 +858,7 @@ static int asus_hotk_get_info(void)
ASUS_HANDLE_INIT(tled_set);
ASUS_HANDLE_INIT(rled_set);
ASUS_HANDLE_INIT(pled_set);
+ ASUS_HANDLE_INIT(gled_set);
ASUS_HANDLE_INIT(ledd_set);
@@ -840,7 +868,9 @@ static int asus_hotk_get_info(void)
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
*/
- if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+ status =
+ acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &hwrs_result);
+ if (ACPI_FAILURE(status))
hwrs_result = WL_HWRS | BT_HWRS;
if (hwrs_result & WL_HWRS)
@@ -928,11 +958,15 @@ static int asus_hotk_add(struct acpi_device *device)
asus_hotk_found = 1;
/* WLED and BLED are on by default */
- write_status(bt_switch_handle, 1, BT_ON, 0);
- write_status(wl_switch_handle, 1, WL_ON, 0);
+ write_status(bt_switch_handle, 1, BT_ON);
+ write_status(wl_switch_handle, 1, WL_ON);
+
+ /* If the h/w switch is off, we need to check the real status */
+ write_status(NULL, read_status(BT_ON), BT_ON);
+ write_status(NULL, read_status(WL_ON), WL_ON);
/* LCD Backlight is on by default */
- write_status(NULL, 1, LCD_ON, 0);
+ write_status(NULL, 1, LCD_ON);
/* LED display is off by default */
hotk->ledd_status = 0xFFF;
@@ -991,6 +1025,7 @@ static void asus_led_exit(void)
ASUS_LED_UNREGISTER(tled);
ASUS_LED_UNREGISTER(pled);
ASUS_LED_UNREGISTER(rled);
+ ASUS_LED_UNREGISTER(gled);
destroy_workqueue(led_workqueue);
}
@@ -1062,6 +1097,10 @@ static int asus_led_init(struct device *dev)
if (rv)
return rv;
+ rv = ASUS_LED_REGISTER(gled, dev);
+ if (rv)
+ return rv;
+
led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!led_workqueue)
return -ENOMEM;
diff --git a/drivers/misc/blink.c b/drivers/misc/blink.c
new file mode 100644
index 00000000000..634431ce118
--- /dev/null
+++ b/drivers/misc/blink.c
@@ -0,0 +1,27 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+
+static void do_blink(unsigned long data);
+
+static DEFINE_TIMER(blink_timer, do_blink, 0 ,0);
+
+static void do_blink(unsigned long data)
+{
+ static long count;
+ if (panic_blink)
+ panic_blink(count++);
+ blink_timer.expires = jiffies + msecs_to_jiffies(1);
+ add_timer(&blink_timer);
+}
+
+static int blink_init(void)
+{
+ printk(KERN_INFO "Enabling keyboard blinking\n");
+ do_blink(0);
+ return 0;
+}
+
+module_init(blink_init);
+
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index ca86f113f36..276ba3c5143 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 6a51e99a807..60c8b26f067 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -18,7 +18,6 @@
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/hdpu_features.h>
-#include <linux/pci.h>
#include <linux/platform_device.h>
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
new file mode 100644
index 00000000000..35b139b0e5f
--- /dev/null
+++ b/drivers/misc/phantom.c
@@ -0,0 +1,463 @@
+/*
+ * Copyright (C) 2005-2007 Jiri Slaby <jirislaby@gmail.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.
+ *
+ * You need an userspace library to cooperate with this driver. It (and other
+ * info) may be obtained here:
+ * http://www.fi.muni.cz/~xslaby/phantom.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/phantom.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+
+#define PHANTOM_VERSION "n0.9.5"
+
+#define PHANTOM_MAX_MINORS 8
+
+#define PHN_IRQCTL 0x4c /* irq control in caddr space */
+
+#define PHB_RUNNING 1
+
+static struct class *phantom_class;
+static int phantom_major;
+
+struct phantom_device {
+ unsigned int opened;
+ void __iomem *caddr;
+ u32 __iomem *iaddr;
+ u32 __iomem *oaddr;
+ unsigned long status;
+ atomic_t counter;
+
+ wait_queue_head_t wait;
+ struct cdev cdev;
+
+ struct mutex open_lock;
+};
+
+static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
+
+static int phantom_status(struct phantom_device *dev, unsigned long newstat)
+{
+ pr_debug("phantom_status %lx %lx\n", dev->status, newstat);
+
+ if (!(dev->status & PHB_RUNNING) && (newstat & PHB_RUNNING)) {
+ atomic_set(&dev->counter, 0);
+ iowrite32(PHN_CTL_IRQ, dev->iaddr + PHN_CONTROL);
+ iowrite32(0x43, dev->caddr + PHN_IRQCTL);
+ } else if ((dev->status & PHB_RUNNING) && !(newstat & PHB_RUNNING))
+ iowrite32(0, dev->caddr + PHN_IRQCTL);
+
+ dev->status = newstat;
+
+ return 0;
+}
+
+/*
+ * File ops
+ */
+
+static int phantom_ioctl(struct inode *inode, struct file *file, u_int cmd,
+ u_long arg)
+{
+ struct phantom_device *dev = file->private_data;
+ struct phm_regs rs;
+ struct phm_reg r;
+ void __user *argp = (void __user *)arg;
+ unsigned int i;
+
+ if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
+ _IOC_NR(cmd) > PH_IOC_MAXNR)
+ return -ENOTTY;
+
+ switch (cmd) {
+ case PHN_SET_REG:
+ if (copy_from_user(&r, argp, sizeof(r)))
+ return -EFAULT;
+
+ if (r.reg > 7)
+ return -EINVAL;
+
+ if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
+ phantom_status(dev, dev->status | PHB_RUNNING))
+ return -ENODEV;
+
+ pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
+ iowrite32(r.value, dev->iaddr + r.reg);
+
+ if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
+ phantom_status(dev, dev->status & ~PHB_RUNNING);
+ break;
+ case PHN_SET_REGS:
+ if (copy_from_user(&rs, argp, sizeof(rs)))
+ return -EFAULT;
+
+ pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
+ for (i = 0; i < min(rs.count, 8U); i++)
+ if ((1 << i) & rs.mask)
+ iowrite32(rs.values[i], dev->oaddr + i);
+ break;
+ case PHN_GET_REG:
+ if (copy_from_user(&r, argp, sizeof(r)))
+ return -EFAULT;
+
+ if (r.reg > 7)
+ return -EINVAL;
+
+ r.value = ioread32(dev->iaddr + r.reg);
+
+ if (copy_to_user(argp, &r, sizeof(r)))
+ return -EFAULT;
+ break;
+ case PHN_GET_REGS:
+ if (copy_from_user(&rs, argp, sizeof(rs)))
+ return -EFAULT;
+
+ pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
+ for (i = 0; i < min(rs.count, 8U); i++)
+ if ((1 << i) & rs.mask)
+ rs.values[i] = ioread32(dev->iaddr + i);
+
+ if (copy_to_user(argp, &rs, sizeof(rs)))
+ return -EFAULT;
+ break;
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+static int phantom_open(struct inode *inode, struct file *file)
+{
+ struct phantom_device *dev = container_of(inode->i_cdev,
+ struct phantom_device, cdev);
+
+ nonseekable_open(inode, file);
+
+ if (mutex_lock_interruptible(&dev->open_lock))
+ return -ERESTARTSYS;
+
+ if (dev->opened) {
+ mutex_unlock(&dev->open_lock);
+ return -EINVAL;
+ }
+
+ file->private_data = dev;
+
+ dev->opened++;
+ mutex_unlock(&dev->open_lock);
+
+ return 0;
+}
+
+static int phantom_release(struct inode *inode, struct file *file)
+{
+ struct phantom_device *dev = file->private_data;
+
+ mutex_lock(&dev->open_lock);
+
+ dev->opened = 0;
+ phantom_status(dev, dev->status & ~PHB_RUNNING);
+
+ mutex_unlock(&dev->open_lock);
+
+ return 0;
+}
+
+static unsigned int phantom_poll(struct file *file, poll_table *wait)
+{
+ struct phantom_device *dev = file->private_data;
+ unsigned int mask = 0;
+
+ pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
+ poll_wait(file, &dev->wait, wait);
+ if (atomic_read(&dev->counter)) {
+ mask = POLLIN | POLLRDNORM;
+ atomic_dec(&dev->counter);
+ } else if ((dev->status & PHB_RUNNING) == 0)
+ mask = POLLIN | POLLRDNORM | POLLERR;
+ pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
+
+ return mask;
+}
+
+static struct file_operations phantom_file_ops = {
+ .open = phantom_open,
+ .release = phantom_release,
+ .ioctl = phantom_ioctl,
+ .poll = phantom_poll,
+};
+
+static irqreturn_t phantom_isr(int irq, void *data)
+{
+ struct phantom_device *dev = data;
+
+ if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ))
+ return IRQ_NONE;
+
+ iowrite32(0, dev->iaddr);
+ iowrite32(0xc0, dev->iaddr);
+
+ atomic_inc(&dev->counter);
+ wake_up_interruptible(&dev->wait);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Init and deinit driver
+ */
+
+static unsigned int __devinit phantom_get_free(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < PHANTOM_MAX_MINORS; i++)
+ if (phantom_devices[i] == 0)
+ break;
+
+ return i;
+}
+
+static int __devinit phantom_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ struct phantom_device *pht;
+ unsigned int minor;
+ int retval;
+
+ retval = pci_enable_device(pdev);
+ if (retval)
+ goto err;
+
+ minor = phantom_get_free();
+ if (minor == PHANTOM_MAX_MINORS) {
+ dev_err(&pdev->dev, "too many devices found!\n");
+ retval = -EIO;
+ goto err_dis;
+ }
+
+ phantom_devices[minor] = 1;
+
+ retval = pci_request_regions(pdev, "phantom");
+ if (retval)
+ goto err_null;
+
+ retval = -ENOMEM;
+ pht = kzalloc(sizeof(*pht), GFP_KERNEL);
+ if (pht == NULL) {
+ dev_err(&pdev->dev, "unable to allocate device\n");
+ goto err_reg;
+ }
+
+ pht->caddr = pci_iomap(pdev, 0, 0);
+ if (pht->caddr == NULL) {
+ dev_err(&pdev->dev, "can't remap conf space\n");
+ goto err_fr;
+ }
+ pht->iaddr = pci_iomap(pdev, 2, 0);
+ if (pht->iaddr == NULL) {
+ dev_err(&pdev->dev, "can't remap input space\n");
+ goto err_unmc;
+ }
+ pht->oaddr = pci_iomap(pdev, 3, 0);
+ if (pht->oaddr == NULL) {
+ dev_err(&pdev->dev, "can't remap output space\n");
+ goto err_unmi;
+ }
+
+ mutex_init(&pht->open_lock);
+ init_waitqueue_head(&pht->wait);
+ cdev_init(&pht->cdev, &phantom_file_ops);
+ pht->cdev.owner = THIS_MODULE;
+
+ iowrite32(0, pht->caddr + PHN_IRQCTL);
+ retval = request_irq(pdev->irq, phantom_isr,
+ IRQF_SHARED | IRQF_DISABLED, "phantom", pht);
+ if (retval) {
+ dev_err(&pdev->dev, "can't establish ISR\n");
+ goto err_unmo;
+ }
+
+ retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1);
+ if (retval) {
+ dev_err(&pdev->dev, "chardev registration failed\n");
+ goto err_irq;
+ }
+
+ if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major,
+ minor), "phantom%u", minor)))
+ dev_err(&pdev->dev, "can't create device\n");
+
+ pci_set_drvdata(pdev, pht);
+
+ return 0;
+err_irq:
+ free_irq(pdev->irq, pht);
+err_unmo:
+ pci_iounmap(pdev, pht->oaddr);
+err_unmi:
+ pci_iounmap(pdev, pht->iaddr);
+err_unmc:
+ pci_iounmap(pdev, pht->caddr);
+err_fr:
+ kfree(pht);
+err_reg:
+ pci_release_regions(pdev);
+err_null:
+ phantom_devices[minor] = 0;
+err_dis:
+ pci_disable_device(pdev);
+err:
+ return retval;
+}
+
+static void __devexit phantom_remove(struct pci_dev *pdev)
+{
+ struct phantom_device *pht = pci_get_drvdata(pdev);
+ unsigned int minor = MINOR(pht->cdev.dev);
+
+ device_destroy(phantom_class, MKDEV(phantom_major, minor));
+
+ cdev_del(&pht->cdev);
+
+ iowrite32(0, pht->caddr + PHN_IRQCTL);
+ free_irq(pdev->irq, pht);
+
+ pci_iounmap(pdev, pht->oaddr);
+ pci_iounmap(pdev, pht->iaddr);
+ pci_iounmap(pdev, pht->caddr);
+
+ kfree(pht);
+
+ pci_release_regions(pdev);
+
+ phantom_devices[minor] = 0;
+
+ pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM
+static int phantom_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct phantom_device *dev = pci_get_drvdata(pdev);
+
+ iowrite32(0, dev->caddr + PHN_IRQCTL);
+
+ return 0;
+}
+
+static int phantom_resume(struct pci_dev *pdev)
+{
+ struct phantom_device *dev = pci_get_drvdata(pdev);
+
+ iowrite32(0, dev->caddr + PHN_IRQCTL);
+
+ return 0;
+}
+#else
+#define phantom_suspend NULL
+#define phantom_resume NULL
+#endif
+
+static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
+ .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
+
+static struct pci_driver phantom_pci_driver = {
+ .name = "phantom",
+ .id_table = phantom_pci_tbl,
+ .probe = phantom_probe,
+ .remove = __devexit_p(phantom_remove),
+ .suspend = phantom_suspend,
+ .resume = phantom_resume
+};
+
+static ssize_t phantom_show_version(struct class *cls, char *buf)
+{
+ return sprintf(buf, PHANTOM_VERSION "\n");
+}
+
+static CLASS_ATTR(version, 0444, phantom_show_version, NULL);
+
+static int __init phantom_init(void)
+{
+ int retval;
+ dev_t dev;
+
+ phantom_class = class_create(THIS_MODULE, "phantom");
+ if (IS_ERR(phantom_class)) {
+ retval = PTR_ERR(phantom_class);
+ printk(KERN_ERR "phantom: can't register phantom class\n");
+ goto err;
+ }
+ retval = class_create_file(phantom_class, &class_attr_version);
+ if (retval) {
+ printk(KERN_ERR "phantom: can't create sysfs version file\n");
+ goto err_class;
+ }
+
+ retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom");
+ if (retval) {
+ printk(KERN_ERR "phantom: can't register character device\n");
+ goto err_attr;
+ }
+ phantom_major = MAJOR(dev);
+
+ retval = pci_register_driver(&phantom_pci_driver);
+ if (retval) {
+ printk(KERN_ERR "phantom: can't register pci driver\n");
+ goto err_unchr;
+ }
+
+ printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", "
+ "init OK\n");
+
+ return 0;
+err_unchr:
+ unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
+err_attr:
+ class_remove_file(phantom_class, &class_attr_version);
+err_class:
+ class_destroy(phantom_class);
+err:
+ return retval;
+}
+
+static void __exit phantom_exit(void)
+{
+ pci_unregister_driver(&phantom_pci_driver);
+
+ unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
+
+ class_remove_file(phantom_class, &class_attr_version);
+ class_destroy(phantom_class);
+
+ pr_debug("phantom: module successfully removed\n");
+}
+
+module_init(phantom_init);
+module_exit(phantom_exit);
+
+MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
+MODULE_DESCRIPTION("Sensable Phantom driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PHANTOM_VERSION);
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index ac708bc2f9f..c15c1f61bd1 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -1,5 +1,5 @@
/*
- * ACPI Sony Notebook Control Driver (SNC)
+ * ACPI Sony Notebook Control Driver (SNC and SPIC)
*
* Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
* Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
@@ -7,6 +7,25 @@
* Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
* which are copyrighted by their respective authors.
*
+ * The SNY6001 driver part is based on the sonypi driver which includes
+ * material from:
+ *
+ * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
+ *
+ * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
+ *
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ *
+ * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
+ *
+ * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
+ *
+ * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
+ *
+ * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
+ *
+ * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
+ *
* 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
@@ -31,40 +50,404 @@
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/err.h>
+#include <linux/dmi.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/kfifo.h>
+#include <linux/workqueue.h>
+#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
+#include <linux/sonypi.h>
+#include <linux/sony-laptop.h>
+#ifdef CONFIG_SONY_LAPTOP_OLD
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#endif
-#define ACPI_SNC_CLASS "sony"
-#define ACPI_SNC_HID "SNY5001"
-#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4"
+#define DRV_PFX "sony-laptop: "
+#define dprintk(msg...) do { \
+ if (debug) printk(KERN_WARNING DRV_PFX msg); \
+} while (0)
-/* the device uses 1-based values, while the backlight subsystem uses
- 0-based values */
-#define SONY_MAX_BRIGHTNESS 8
+#define SONY_LAPTOP_DRIVER_VERSION "0.5"
+
+#define SONY_NC_CLASS "sony-nc"
+#define SONY_NC_HID "SNY5001"
+#define SONY_NC_DRIVER_NAME "Sony Notebook Control Driver"
-#define LOG_PFX KERN_WARNING "sony-laptop: "
+#define SONY_PIC_CLASS "sony-pic"
+#define SONY_PIC_HID "SNY6001"
+#define SONY_PIC_DRIVER_NAME "Sony Programmable IO Control Driver"
MODULE_AUTHOR("Stelian Pop, Mattia Dongili");
-MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME);
+MODULE_DESCRIPTION("Sony laptop extras driver (SPIC and SNC ACPI device)");
MODULE_LICENSE("GPL");
+MODULE_VERSION(SONY_LAPTOP_DRIVER_VERSION);
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help "
"the development of this driver");
-static ssize_t sony_acpi_show(struct device *, struct device_attribute *,
+static int no_spic; /* = 0 */
+module_param(no_spic, int, 0444);
+MODULE_PARM_DESC(no_spic,
+ "set this if you don't want to enable the SPIC device");
+
+static int compat; /* = 0 */
+module_param(compat, int, 0444);
+MODULE_PARM_DESC(compat,
+ "set this if you want to enable backward compatibility mode");
+
+static unsigned long mask = 0xffffffff;
+module_param(mask, ulong, 0644);
+MODULE_PARM_DESC(mask,
+ "set this to the mask of event you want to enable (see doc)");
+
+static int camera; /* = 0 */
+module_param(camera, int, 0444);
+MODULE_PARM_DESC(camera,
+ "set this to 1 to enable Motion Eye camera controls "
+ "(only use it if you have a C1VE or C1VN model)");
+
+#ifdef CONFIG_SONY_LAPTOP_OLD
+static int minor = -1;
+module_param(minor, int, 0);
+MODULE_PARM_DESC(minor,
+ "minor number of the misc device for the SPIC compatibility code, "
+ "default is -1 (automatic)");
+#endif
+
+/*********** Input Devices ***********/
+
+#define SONY_LAPTOP_BUF_SIZE 128
+struct sony_laptop_input_s {
+ atomic_t users;
+ struct input_dev *jog_dev;
+ struct input_dev *key_dev;
+ struct kfifo *fifo;
+ spinlock_t fifo_lock;
+ struct workqueue_struct *wq;
+};
+static struct sony_laptop_input_s sony_laptop_input = {
+ .users = ATOMIC_INIT(0),
+};
+
+struct sony_laptop_keypress {
+ struct input_dev *dev;
+ int key;
+};
+
+/* Correspondance table between sonypi events and input layer events */
+static struct {
+ int sonypiev;
+ int inputev;
+} sony_laptop_inputkeys[] = {
+ { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
+ { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
+ { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
+ { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
+ { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
+ { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
+ { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
+ { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
+ { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
+ { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
+ { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
+ { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
+ { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
+ { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
+ { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
+ { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
+ { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
+ { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
+ { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
+ { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
+ { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
+ { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
+ { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
+ { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
+ { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
+ { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
+ { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
+ { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
+ { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
+ { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
+ { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
+ { 0, 0 },
+};
+
+/* release buttons after a short delay if pressed */
+static void do_sony_laptop_release_key(struct work_struct *work)
+{
+ struct sony_laptop_keypress kp;
+
+ while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
+ sizeof(kp)) == sizeof(kp)) {
+ msleep(10);
+ input_report_key(kp.dev, kp.key, 0);
+ input_sync(kp.dev);
+ }
+}
+static DECLARE_WORK(sony_laptop_release_key_work,
+ do_sony_laptop_release_key);
+
+/* forward event to the input subsytem */
+static void sony_laptop_report_input_event(u8 event)
+{
+ struct input_dev *jog_dev = sony_laptop_input.jog_dev;
+ struct input_dev *key_dev = sony_laptop_input.key_dev;
+ struct sony_laptop_keypress kp = { NULL };
+ int i;
+
+ if (event == SONYPI_EVENT_FNKEY_RELEASED) {
+ /* Nothing, not all VAIOs generate this event */
+ return;
+ }
+
+ /* report events */
+ switch (event) {
+ /* jog_dev events */
+ case SONYPI_EVENT_JOGDIAL_UP:
+ case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
+ input_report_rel(jog_dev, REL_WHEEL, 1);
+ input_sync(jog_dev);
+ return;
+
+ case SONYPI_EVENT_JOGDIAL_DOWN:
+ case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
+ input_report_rel(jog_dev, REL_WHEEL, -1);
+ input_sync(jog_dev);
+ return;
+
+ /* key_dev events */
+ case SONYPI_EVENT_JOGDIAL_PRESSED:
+ kp.key = BTN_MIDDLE;
+ kp.dev = jog_dev;
+ break;
+
+ default:
+ for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+ if (event == sony_laptop_inputkeys[i].sonypiev) {
+ kp.dev = key_dev;
+ kp.key = sony_laptop_inputkeys[i].inputev;
+ break;
+ }
+ break;
+ }
+
+ if (kp.dev) {
+ input_report_key(kp.dev, kp.key, 1);
+ input_sync(kp.dev);
+ kfifo_put(sony_laptop_input.fifo,
+ (unsigned char *)&kp, sizeof(kp));
+
+ if (!work_pending(&sony_laptop_release_key_work))
+ queue_work(sony_laptop_input.wq,
+ &sony_laptop_release_key_work);
+ } else
+ dprintk("unknown input event %.2x\n", event);
+}
+
+static int sony_laptop_setup_input(void)
+{
+ struct input_dev *jog_dev;
+ struct input_dev *key_dev;
+ int i;
+ int error;
+
+ /* don't run again if already initialized */
+ if (atomic_add_return(1, &sony_laptop_input.users) > 1)
+ return 0;
+
+ /* kfifo */
+ spin_lock_init(&sony_laptop_input.fifo_lock);
+ sony_laptop_input.fifo =
+ kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+ &sony_laptop_input.fifo_lock);
+ if (IS_ERR(sony_laptop_input.fifo)) {
+ printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+ error = PTR_ERR(sony_laptop_input.fifo);
+ goto err_dec_users;
+ }
+
+ /* init workqueue */
+ sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
+ if (!sony_laptop_input.wq) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to create workqueue.\n");
+ error = -ENXIO;
+ goto err_free_kfifo;
+ }
+
+ /* input keys */
+ key_dev = input_allocate_device();
+ if (!key_dev) {
+ error = -ENOMEM;
+ goto err_destroy_wq;
+ }
+
+ key_dev->name = "Sony Vaio Keys";
+ key_dev->id.bustype = BUS_ISA;
+ key_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+ /* Initialize the Input Drivers: special keys */
+ key_dev->evbit[0] = BIT(EV_KEY);
+ for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
+ if (sony_laptop_inputkeys[i].inputev)
+ set_bit(sony_laptop_inputkeys[i].inputev,
+ key_dev->keybit);
+
+ error = input_register_device(key_dev);
+ if (error)
+ goto err_free_keydev;
+
+ sony_laptop_input.key_dev = key_dev;
+
+ /* jogdial */
+ jog_dev = input_allocate_device();
+ if (!jog_dev) {
+ error = -ENOMEM;
+ goto err_unregister_keydev;
+ }
+
+ jog_dev->name = "Sony Vaio Jogdial";
+ jog_dev->id.bustype = BUS_ISA;
+ jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
+
+ jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
+ jog_dev->relbit[0] = BIT(REL_WHEEL);
+
+ error = input_register_device(jog_dev);
+ if (error)
+ goto err_free_jogdev;
+
+ sony_laptop_input.jog_dev = jog_dev;
+
+ return 0;
+
+err_free_jogdev:
+ input_free_device(jog_dev);
+
+err_unregister_keydev:
+ input_unregister_device(key_dev);
+ /* to avoid kref underflow below at input_free_device */
+ key_dev = NULL;
+
+err_free_keydev:
+ input_free_device(key_dev);
+
+err_destroy_wq:
+ destroy_workqueue(sony_laptop_input.wq);
+
+err_free_kfifo:
+ kfifo_free(sony_laptop_input.fifo);
+
+err_dec_users:
+ atomic_dec(&sony_laptop_input.users);
+ return error;
+}
+
+static void sony_laptop_remove_input(void)
+{
+ /* cleanup only after the last user has gone */
+ if (!atomic_dec_and_test(&sony_laptop_input.users))
+ return;
+
+ /* flush workqueue first */
+ flush_workqueue(sony_laptop_input.wq);
+
+ /* destroy input devs */
+ input_unregister_device(sony_laptop_input.key_dev);
+ sony_laptop_input.key_dev = NULL;
+
+ if (sony_laptop_input.jog_dev) {
+ input_unregister_device(sony_laptop_input.jog_dev);
+ sony_laptop_input.jog_dev = NULL;
+ }
+
+ destroy_workqueue(sony_laptop_input.wq);
+ kfifo_free(sony_laptop_input.fifo);
+}
+
+/*********** Platform Device ***********/
+
+static atomic_t sony_pf_users = ATOMIC_INIT(0);
+static struct platform_driver sony_pf_driver = {
+ .driver = {
+ .name = "sony-laptop",
+ .owner = THIS_MODULE,
+ }
+};
+static struct platform_device *sony_pf_device;
+
+static int sony_pf_add(void)
+{
+ int ret = 0;
+
+ /* don't run again if already initialized */
+ if (atomic_add_return(1, &sony_pf_users) > 1)
+ return 0;
+
+ ret = platform_driver_register(&sony_pf_driver);
+ if (ret)
+ goto out;
+
+ sony_pf_device = platform_device_alloc("sony-laptop", -1);
+ if (!sony_pf_device) {
+ ret = -ENOMEM;
+ goto out_platform_registered;
+ }
+
+ ret = platform_device_add(sony_pf_device);
+ if (ret)
+ goto out_platform_alloced;
+
+ return 0;
+
+ out_platform_alloced:
+ platform_device_put(sony_pf_device);
+ sony_pf_device = NULL;
+ out_platform_registered:
+ platform_driver_unregister(&sony_pf_driver);
+ out:
+ atomic_dec(&sony_pf_users);
+ return ret;
+}
+
+static void sony_pf_remove(void)
+{
+ /* deregister only after the last user has gone */
+ if (!atomic_dec_and_test(&sony_pf_users))
+ return;
+
+ platform_device_del(sony_pf_device);
+ platform_device_put(sony_pf_device);
+ platform_driver_unregister(&sony_pf_driver);
+}
+
+/*********** SNC (SNY5001) Device ***********/
+
+/* the device uses 1-based values, while the backlight subsystem uses
+ 0-based values */
+#define SONY_MAX_BRIGHTNESS 8
+
+#define SNC_VALIDATE_IN 0
+#define SNC_VALIDATE_OUT 1
+
+static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *,
char *);
-static ssize_t sony_acpi_store(struct device *, struct device_attribute *,
+static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *,
const char *, size_t);
static int boolean_validate(const int, const int);
static int brightness_default_validate(const int, const int);
-#define SNC_VALIDATE_IN 0
-#define SNC_VALIDATE_OUT 1
-
-struct sony_acpi_value {
+struct sony_nc_value {
char *name; /* name of the entry */
char **acpiget; /* names of the ACPI get function */
char **acpiset; /* names of the ACPI set function */
@@ -75,65 +458,65 @@ struct sony_acpi_value {
struct device_attribute devattr; /* sysfs atribute */
};
-#define HANDLE_NAMES(_name, _values...) \
+#define SNC_HANDLE_NAMES(_name, _values...) \
static char *snc_##_name[] = { _values, NULL }
-#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \
+#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \
{ \
.name = __stringify(_name), \
.acpiget = _getters, \
.acpiset = _setters, \
.validate = _validate, \
.debug = _debug, \
- .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \
+ .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \
}
-#define SONY_ACPI_VALUE_NULL { .name = NULL }
+#define SNC_HANDLE_NULL { .name = NULL }
-HANDLE_NAMES(fnkey_get, "GHKE");
+SNC_HANDLE_NAMES(fnkey_get, "GHKE");
-HANDLE_NAMES(brightness_def_get, "GPBR");
-HANDLE_NAMES(brightness_def_set, "SPBR");
+SNC_HANDLE_NAMES(brightness_def_get, "GPBR");
+SNC_HANDLE_NAMES(brightness_def_set, "SPBR");
-HANDLE_NAMES(cdpower_get, "GCDP");
-HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
+SNC_HANDLE_NAMES(cdpower_get, "GCDP");
+SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");
-HANDLE_NAMES(audiopower_get, "GAZP");
-HANDLE_NAMES(audiopower_set, "AZPW");
+SNC_HANDLE_NAMES(audiopower_get, "GAZP");
+SNC_HANDLE_NAMES(audiopower_set, "AZPW");
-HANDLE_NAMES(lanpower_get, "GLNP");
-HANDLE_NAMES(lanpower_set, "LNPW");
+SNC_HANDLE_NAMES(lanpower_get, "GLNP");
+SNC_HANDLE_NAMES(lanpower_set, "LNPW");
-HANDLE_NAMES(PID_get, "GPID");
+SNC_HANDLE_NAMES(PID_get, "GPID");
-HANDLE_NAMES(CTR_get, "GCTR");
-HANDLE_NAMES(CTR_set, "SCTR");
+SNC_HANDLE_NAMES(CTR_get, "GCTR");
+SNC_HANDLE_NAMES(CTR_set, "SCTR");
-HANDLE_NAMES(PCR_get, "GPCR");
-HANDLE_NAMES(PCR_set, "SPCR");
+SNC_HANDLE_NAMES(PCR_get, "GPCR");
+SNC_HANDLE_NAMES(PCR_set, "SPCR");
-HANDLE_NAMES(CMI_get, "GCMI");
-HANDLE_NAMES(CMI_set, "SCMI");
+SNC_HANDLE_NAMES(CMI_get, "GCMI");
+SNC_HANDLE_NAMES(CMI_set, "SCMI");
-static struct sony_acpi_value sony_acpi_values[] = {
- SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get,
+static struct sony_nc_value sony_nc_values[] = {
+ SNC_HANDLE(brightness_default, snc_brightness_def_get,
snc_brightness_def_set, brightness_default_validate, 0),
- SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0),
- SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
- SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set,
+ SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
+ SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
+ SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
boolean_validate, 0),
- SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set,
+ SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
boolean_validate, 1),
/* unknown methods */
- SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1),
- SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
- SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
- SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
- SONY_ACPI_VALUE_NULL
+ SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
+ SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
+ SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1),
+ SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1),
+ SNC_HANDLE_NULL
};
-static acpi_handle sony_acpi_handle;
-static struct acpi_device *sony_acpi_acpi_device = NULL;
+static acpi_handle sony_nc_acpi_handle;
+static struct acpi_device *sony_nc_acpi_device = NULL;
/*
* acpi_evaluate_object wrappers
@@ -153,7 +536,7 @@ static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
return 0;
}
- printk(LOG_PFX "acpi_callreadfunc failed\n");
+ printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
return -1;
}
@@ -179,7 +562,7 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
if (status == AE_OK) {
if (result != NULL) {
if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(LOG_PFX "acpi_evaluate_object bad "
+ printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
"return type\n");
return -1;
}
@@ -188,13 +571,13 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
return 0;
}
- printk(LOG_PFX "acpi_evaluate_object failed\n");
+ printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
return -1;
}
/*
- * sony_acpi_values input/output validate functions
+ * sony_nc_values input/output validate functions
*/
/* brightness_default_validate:
@@ -229,19 +612,19 @@ static int boolean_validate(const int direction, const int value)
}
/*
- * Sysfs show/store common to all sony_acpi_values
+ * Sysfs show/store common to all sony_nc_values
*/
-static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
+static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
char *buffer)
{
int value;
- struct sony_acpi_value *item =
- container_of(attr, struct sony_acpi_value, devattr);
+ struct sony_nc_value *item =
+ container_of(attr, struct sony_nc_value, devattr);
if (!*item->acpiget)
return -EIO;
- if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0)
+ if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
return -EIO;
if (item->validate)
@@ -250,13 +633,13 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr,
return snprintf(buffer, PAGE_SIZE, "%d\n", value);
}
-static ssize_t sony_acpi_store(struct device *dev,
+static ssize_t sony_nc_sysfs_store(struct device *dev,
struct device_attribute *attr,
const char *buffer, size_t count)
{
int value;
- struct sony_acpi_value *item =
- container_of(attr, struct sony_acpi_value, devattr);
+ struct sony_nc_value *item =
+ container_of(attr, struct sony_nc_value, devattr);
if (!item->acpiset)
return -EIO;
@@ -272,118 +655,20 @@ static ssize_t sony_acpi_store(struct device *dev,
if (value < 0)
return value;
- if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0)
+ if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
return -EIO;
item->value = value;
item->valid = 1;
return count;
}
-/*
- * Platform device
- */
-static struct platform_driver sncpf_driver = {
- .driver = {
- .name = "sony-laptop",
- .owner = THIS_MODULE,
- }
-};
-static struct platform_device *sncpf_device;
-
-static int sony_snc_pf_add(void)
-{
- acpi_handle handle;
- struct sony_acpi_value *item;
- int ret = 0;
-
- ret = platform_driver_register(&sncpf_driver);
- if (ret)
- goto out;
-
- sncpf_device = platform_device_alloc("sony-laptop", -1);
- if (!sncpf_device) {
- ret = -ENOMEM;
- goto out_platform_registered;
- }
-
- ret = platform_device_add(sncpf_device);
- if (ret)
- goto out_platform_alloced;
-
- for (item = sony_acpi_values; item->name; ++item) {
-
- if (!debug && item->debug)
- continue;
-
- /* find the available acpiget as described in the DSDT */
- for (; item->acpiget && *item->acpiget; ++item->acpiget) {
- if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
- *item->acpiget,
- &handle))) {
- if (debug)
- printk(LOG_PFX "Found %s getter: %s\n",
- item->name, *item->acpiget);
- item->devattr.attr.mode |= S_IRUGO;
- break;
- }
- }
-
- /* find the available acpiset as described in the DSDT */
- for (; item->acpiset && *item->acpiset; ++item->acpiset) {
- if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle,
- *item->acpiset,
- &handle))) {
- if (debug)
- printk(LOG_PFX "Found %s setter: %s\n",
- item->name, *item->acpiset);
- item->devattr.attr.mode |= S_IWUSR;
- break;
- }
- }
-
- if (item->devattr.attr.mode != 0) {
- ret =
- device_create_file(&sncpf_device->dev,
- &item->devattr);
- if (ret)
- goto out_sysfs;
- }
- }
-
- return 0;
-
- out_sysfs:
- for (item = sony_acpi_values; item->name; ++item) {
- device_remove_file(&sncpf_device->dev, &item->devattr);
- }
- platform_device_del(sncpf_device);
- out_platform_alloced:
- platform_device_put(sncpf_device);
- out_platform_registered:
- platform_driver_unregister(&sncpf_driver);
- out:
- return ret;
-}
-
-static void sony_snc_pf_remove(void)
-{
- struct sony_acpi_value *item;
-
- for (item = sony_acpi_values; item->name; ++item) {
- device_remove_file(&sncpf_device->dev, &item->devattr);
- }
-
- platform_device_del(sncpf_device);
- platform_device_put(sncpf_device);
- platform_driver_unregister(&sncpf_driver);
-}
/*
* Backlight device
*/
static int sony_backlight_update_status(struct backlight_device *bd)
{
- return acpi_callsetfunc(sony_acpi_handle, "SBRT",
+ return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
bd->props.brightness + 1, NULL);
}
@@ -391,7 +676,7 @@ static int sony_backlight_get_brightness(struct backlight_device *bd)
{
int value;
- if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value))
+ if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
return 0;
/* brightness levels are 1-based, while backlight ones are 0-based */
return value - 1;
@@ -408,9 +693,9 @@ static struct backlight_ops sony_backlight_ops = {
*/
static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
{
- if (debug)
- printk(LOG_PFX "sony_acpi_notify, event: %d\n", event);
- acpi_bus_generate_event(sony_acpi_acpi_device, 1, event);
+ dprintk("sony_acpi_notify, event: %d\n", event);
+ sony_laptop_report_input_event(event);
+ acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
}
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -422,7 +707,7 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
node = (struct acpi_namespace_node *)handle;
operand = (union acpi_operand_object *)node->object;
- printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
+ printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii,
(u32) operand->method.param_count);
return AE_OK;
@@ -431,16 +716,16 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
/*
* ACPI device
*/
-static int sony_acpi_resume(struct acpi_device *device)
+static int sony_nc_resume(struct acpi_device *device)
{
- struct sony_acpi_value *item;
+ struct sony_nc_value *item;
- for (item = sony_acpi_values; item->name; item++) {
+ for (item = sony_nc_values; item->name; item++) {
int ret;
if (!item->valid)
continue;
- ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset,
+ ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
item->value, NULL);
if (ret < 0) {
printk("%s: %d\n", __FUNCTION__, ret);
@@ -450,42 +735,55 @@ static int sony_acpi_resume(struct acpi_device *device)
return 0;
}
-static int sony_acpi_add(struct acpi_device *device)
+static int sony_nc_add(struct acpi_device *device)
{
acpi_status status;
int result = 0;
acpi_handle handle;
+ struct sony_nc_value *item;
+
+ printk(KERN_INFO DRV_PFX "%s v%s.\n",
+ SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
- sony_acpi_acpi_device = device;
+ sony_nc_acpi_device = device;
+ strcpy(acpi_device_class(device), "sony/hotkey");
- sony_acpi_handle = device->handle;
+ sony_nc_acpi_handle = device->handle;
if (debug) {
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle,
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
1, sony_walk_callback, NULL, NULL);
if (ACPI_FAILURE(status)) {
- printk(LOG_PFX "unable to walk acpi resources\n");
+ printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
result = -ENODEV;
goto outwalk;
}
}
- status = acpi_install_notify_handler(sony_acpi_handle,
+ /* setup input devices and helper fifo */
+ result = sony_laptop_setup_input();
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to create input devices.\n");
+ goto outwalk;
+ }
+
+ status = acpi_install_notify_handler(sony_nc_acpi_handle,
ACPI_DEVICE_NOTIFY,
sony_acpi_notify, NULL);
if (ACPI_FAILURE(status)) {
- printk(LOG_PFX "unable to install notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
result = -ENODEV;
- goto outwalk;
+ goto outinput;
}
- if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
sony_backlight_device = backlight_device_register("sony", NULL,
NULL,
&sony_backlight_ops);
if (IS_ERR(sony_backlight_device)) {
- printk(LOG_PFX "unable to register backlight device\n");
+ printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
sony_backlight_device = NULL;
} else {
sony_backlight_device->props.brightness =
@@ -497,68 +795,1497 @@ static int sony_acpi_add(struct acpi_device *device)
}
- if (sony_snc_pf_add())
+ result = sony_pf_add();
+ if (result)
goto outbacklight;
- printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n");
+ /* create sony_pf sysfs attributes related to the SNC device */
+ for (item = sony_nc_values; item->name; ++item) {
+
+ if (!debug && item->debug)
+ continue;
+
+ /* find the available acpiget as described in the DSDT */
+ for (; item->acpiget && *item->acpiget; ++item->acpiget) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+ *item->acpiget,
+ &handle))) {
+ dprintk("Found %s getter: %s\n",
+ item->name, *item->acpiget);
+ item->devattr.attr.mode |= S_IRUGO;
+ break;
+ }
+ }
+
+ /* find the available acpiset as described in the DSDT */
+ for (; item->acpiset && *item->acpiset; ++item->acpiset) {
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle,
+ *item->acpiset,
+ &handle))) {
+ dprintk("Found %s setter: %s\n",
+ item->name, *item->acpiset);
+ item->devattr.attr.mode |= S_IWUSR;
+ break;
+ }
+ }
+
+ if (item->devattr.attr.mode != 0) {
+ result =
+ device_create_file(&sony_pf_device->dev,
+ &item->devattr);
+ if (result)
+ goto out_sysfs;
+ }
+ }
return 0;
+ out_sysfs:
+ for (item = sony_nc_values; item->name; ++item) {
+ device_remove_file(&sony_pf_device->dev, &item->devattr);
+ }
+ sony_pf_remove();
+
outbacklight:
if (sony_backlight_device)
backlight_device_unregister(sony_backlight_device);
- status = acpi_remove_notify_handler(sony_acpi_handle,
+ status = acpi_remove_notify_handler(sony_nc_acpi_handle,
ACPI_DEVICE_NOTIFY,
sony_acpi_notify);
if (ACPI_FAILURE(status))
- printk(LOG_PFX "unable to remove notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
+
+ outinput:
+ sony_laptop_remove_input();
+
outwalk:
return result;
}
-static int sony_acpi_remove(struct acpi_device *device, int type)
+static int sony_nc_remove(struct acpi_device *device, int type)
{
acpi_status status;
+ struct sony_nc_value *item;
if (sony_backlight_device)
backlight_device_unregister(sony_backlight_device);
- sony_acpi_acpi_device = NULL;
+ sony_nc_acpi_device = NULL;
- status = acpi_remove_notify_handler(sony_acpi_handle,
+ status = acpi_remove_notify_handler(sony_nc_acpi_handle,
ACPI_DEVICE_NOTIFY,
sony_acpi_notify);
if (ACPI_FAILURE(status))
- printk(LOG_PFX "unable to remove notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to remove notify handler\n");
- sony_snc_pf_remove();
+ for (item = sony_nc_values; item->name; ++item) {
+ device_remove_file(&sony_pf_device->dev, &item->devattr);
+ }
- printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n");
+ sony_pf_remove();
+ sony_laptop_remove_input();
+ dprintk(SONY_NC_DRIVER_NAME " removed.\n");
return 0;
}
-static struct acpi_driver sony_acpi_driver = {
- .name = ACPI_SNC_DRIVER_NAME,
- .class = ACPI_SNC_CLASS,
- .ids = ACPI_SNC_HID,
+static struct acpi_driver sony_nc_driver = {
+ .name = SONY_NC_DRIVER_NAME,
+ .class = SONY_NC_CLASS,
+ .ids = SONY_NC_HID,
+ .owner = THIS_MODULE,
.ops = {
- .add = sony_acpi_add,
- .remove = sony_acpi_remove,
- .resume = sony_acpi_resume,
+ .add = sony_nc_add,
+ .remove = sony_nc_remove,
+ .resume = sony_nc_resume,
},
};
-static int __init sony_acpi_init(void)
+/*********** SPIC (SNY6001) Device ***********/
+
+#define SONYPI_DEVICE_TYPE1 0x00000001
+#define SONYPI_DEVICE_TYPE2 0x00000002
+#define SONYPI_DEVICE_TYPE3 0x00000004
+
+#define SONY_PIC_EV_MASK 0xff
+
+struct sony_pic_ioport {
+ struct acpi_resource_io io;
+ struct list_head list;
+};
+
+struct sony_pic_irq {
+ struct acpi_resource_irq irq;
+ struct list_head list;
+};
+
+struct sony_pic_dev {
+ int model;
+ u8 camera_power;
+ u8 bluetooth_power;
+ u8 wwan_power;
+ struct acpi_device *acpi_dev;
+ struct sony_pic_irq *cur_irq;
+ struct sony_pic_ioport *cur_ioport;
+ struct list_head interrupts;
+ struct list_head ioports;
+ struct mutex lock;
+};
+
+static struct sony_pic_dev spic_dev = {
+ .interrupts = LIST_HEAD_INIT(spic_dev.interrupts),
+ .ioports = LIST_HEAD_INIT(spic_dev.ioports),
+};
+
+/* Event masks */
+#define SONYPI_JOGGER_MASK 0x00000001
+#define SONYPI_CAPTURE_MASK 0x00000002
+#define SONYPI_FNKEY_MASK 0x00000004
+#define SONYPI_BLUETOOTH_MASK 0x00000008
+#define SONYPI_PKEY_MASK 0x00000010
+#define SONYPI_BACK_MASK 0x00000020
+#define SONYPI_HELP_MASK 0x00000040
+#define SONYPI_LID_MASK 0x00000080
+#define SONYPI_ZOOM_MASK 0x00000100
+#define SONYPI_THUMBPHRASE_MASK 0x00000200
+#define SONYPI_MEYE_MASK 0x00000400
+#define SONYPI_MEMORYSTICK_MASK 0x00000800
+#define SONYPI_BATTERY_MASK 0x00001000
+#define SONYPI_WIRELESS_MASK 0x00002000
+
+struct sonypi_event {
+ u8 data;
+ u8 event;
+};
+
+/* The set of possible button release events */
+static struct sonypi_event sonypi_releaseev[] = {
+ { 0x00, SONYPI_EVENT_ANYBUTTON_RELEASED },
+ { 0, 0 }
+};
+
+/* The set of possible jogger events */
+static struct sonypi_event sonypi_joggerev[] = {
+ { 0x1f, SONYPI_EVENT_JOGDIAL_UP },
+ { 0x01, SONYPI_EVENT_JOGDIAL_DOWN },
+ { 0x5f, SONYPI_EVENT_JOGDIAL_UP_PRESSED },
+ { 0x41, SONYPI_EVENT_JOGDIAL_DOWN_PRESSED },
+ { 0x1e, SONYPI_EVENT_JOGDIAL_FAST_UP },
+ { 0x02, SONYPI_EVENT_JOGDIAL_FAST_DOWN },
+ { 0x5e, SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED },
+ { 0x42, SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED },
+ { 0x1d, SONYPI_EVENT_JOGDIAL_VFAST_UP },
+ { 0x03, SONYPI_EVENT_JOGDIAL_VFAST_DOWN },
+ { 0x5d, SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED },
+ { 0x43, SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED },
+ { 0x40, SONYPI_EVENT_JOGDIAL_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible capture button events */
+static struct sonypi_event sonypi_captureev[] = {
+ { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
+ { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
+ { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
+ { 0, 0 }
+};
+
+/* The set of possible fnkeys events */
+static struct sonypi_event sonypi_fnkeyev[] = {
+ { 0x10, SONYPI_EVENT_FNKEY_ESC },
+ { 0x11, SONYPI_EVENT_FNKEY_F1 },
+ { 0x12, SONYPI_EVENT_FNKEY_F2 },
+ { 0x13, SONYPI_EVENT_FNKEY_F3 },
+ { 0x14, SONYPI_EVENT_FNKEY_F4 },
+ { 0x15, SONYPI_EVENT_FNKEY_F5 },
+ { 0x16, SONYPI_EVENT_FNKEY_F6 },
+ { 0x17, SONYPI_EVENT_FNKEY_F7 },
+ { 0x18, SONYPI_EVENT_FNKEY_F8 },
+ { 0x19, SONYPI_EVENT_FNKEY_F9 },
+ { 0x1a, SONYPI_EVENT_FNKEY_F10 },
+ { 0x1b, SONYPI_EVENT_FNKEY_F11 },
+ { 0x1c, SONYPI_EVENT_FNKEY_F12 },
+ { 0x1f, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x21, SONYPI_EVENT_FNKEY_1 },
+ { 0x22, SONYPI_EVENT_FNKEY_2 },
+ { 0x31, SONYPI_EVENT_FNKEY_D },
+ { 0x32, SONYPI_EVENT_FNKEY_E },
+ { 0x33, SONYPI_EVENT_FNKEY_F },
+ { 0x34, SONYPI_EVENT_FNKEY_S },
+ { 0x35, SONYPI_EVENT_FNKEY_B },
+ { 0x36, SONYPI_EVENT_FNKEY_ONLY },
+ { 0, 0 }
+};
+
+/* The set of possible program key events */
+static struct sonypi_event sonypi_pkeyev[] = {
+ { 0x01, SONYPI_EVENT_PKEY_P1 },
+ { 0x02, SONYPI_EVENT_PKEY_P2 },
+ { 0x04, SONYPI_EVENT_PKEY_P3 },
+ { 0x5c, SONYPI_EVENT_PKEY_P1 },
+ { 0, 0 }
+};
+
+/* The set of possible bluetooth events */
+static struct sonypi_event sonypi_blueev[] = {
+ { 0x55, SONYPI_EVENT_BLUETOOTH_PRESSED },
+ { 0x59, SONYPI_EVENT_BLUETOOTH_ON },
+ { 0x5a, SONYPI_EVENT_BLUETOOTH_OFF },
+ { 0, 0 }
+};
+
+/* The set of possible wireless events */
+static struct sonypi_event sonypi_wlessev[] = {
+ { 0x59, SONYPI_EVENT_WIRELESS_ON },
+ { 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+ { 0, 0 }
+};
+
+/* The set of possible back button events */
+static struct sonypi_event sonypi_backev[] = {
+ { 0x20, SONYPI_EVENT_BACK_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible help button events */
+static struct sonypi_event sonypi_helpev[] = {
+ { 0x3b, SONYPI_EVENT_HELP_PRESSED },
+ { 0, 0 }
+};
+
+
+/* The set of possible lid events */
+static struct sonypi_event sonypi_lidev[] = {
+ { 0x51, SONYPI_EVENT_LID_CLOSED },
+ { 0x50, SONYPI_EVENT_LID_OPENED },
+ { 0, 0 }
+};
+
+/* The set of possible zoom events */
+static struct sonypi_event sonypi_zoomev[] = {
+ { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible thumbphrase events */
+static struct sonypi_event sonypi_thumbphraseev[] = {
+ { 0x3a, SONYPI_EVENT_THUMBPHRASE_PRESSED },
+ { 0, 0 }
+};
+
+/* The set of possible motioneye camera events */
+static struct sonypi_event sonypi_meyeev[] = {
+ { 0x00, SONYPI_EVENT_MEYE_FACE },
+ { 0x01, SONYPI_EVENT_MEYE_OPPOSITE },
+ { 0, 0 }
+};
+
+/* The set of possible memorystick events */
+static struct sonypi_event sonypi_memorystickev[] = {
+ { 0x53, SONYPI_EVENT_MEMORYSTICK_INSERT },
+ { 0x54, SONYPI_EVENT_MEMORYSTICK_EJECT },
+ { 0, 0 }
+};
+
+/* The set of possible battery events */
+static struct sonypi_event sonypi_batteryev[] = {
+ { 0x20, SONYPI_EVENT_BATTERY_INSERT },
+ { 0x30, SONYPI_EVENT_BATTERY_REMOVE },
+ { 0, 0 }
+};
+
+static struct sonypi_eventtypes {
+ int model;
+ u8 data;
+ unsigned long mask;
+ struct sonypi_event * events;
+} sony_pic_eventtypes[] = {
+ { SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
+ { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
+ { SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
+ { SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+ { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
+
+ { SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
+ { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
+ { SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
+ { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
+ { SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
+ { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
+ { SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
+ { SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
+ { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+
+ { SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
+ { SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
+ { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
+ { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
+ { SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
+ { SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
+ { 0 }
+};
+
+static int sony_pic_detect_device_type(void)
+{
+ struct pci_dev *pcidev;
+ int model = 0;
+
+ if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
+ model = SONYPI_DEVICE_TYPE1;
+
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
+ model = SONYPI_DEVICE_TYPE3;
+
+ else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
+ model = SONYPI_DEVICE_TYPE3;
+
+ else
+ model = SONYPI_DEVICE_TYPE2;
+
+ if (pcidev)
+ pci_dev_put(pcidev);
+
+ printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+ model == SONYPI_DEVICE_TYPE1 ? 1 :
+ model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
+ return model;
+}
+
+#define ITERATIONS_LONG 10000
+#define ITERATIONS_SHORT 10
+#define wait_on_command(command, iterations) { \
+ unsigned int n = iterations; \
+ while (--n && (command)) \
+ udelay(1); \
+ if (!n) \
+ dprintk("command failed at %s : %s (line %d)\n", \
+ __FILE__, __FUNCTION__, __LINE__); \
+}
+
+static u8 sony_pic_call1(u8 dev)
+{
+ u8 v1, v2;
+
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+ v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4);
+ v2 = inb_p(spic_dev.cur_ioport->io.minimum);
+ dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1);
+ return v2;
+}
+
+static u8 sony_pic_call2(u8 dev, u8 fn)
+{
+ u8 v1;
+
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2,
+ ITERATIONS_LONG);
+ outb(fn, spic_dev.cur_ioport->io.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ dprintk("sony_pic_call2: 0x%.4x\n", v1);
+ return v1;
+}
+
+static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
+{
+ u8 v1;
+
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(dev, spic_dev.cur_ioport->io.minimum + 4);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(fn, spic_dev.cur_ioport->io.minimum);
+ wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG);
+ outb(v, spic_dev.cur_ioport->io.minimum);
+ v1 = inb_p(spic_dev.cur_ioport->io.minimum);
+ dprintk("sony_pic_call3: 0x%.4x\n", v1);
+ return v1;
+}
+
+/* camera tests and poweron/poweroff */
+#define SONYPI_CAMERA_PICTURE 5
+#define SONYPI_CAMERA_CONTROL 0x10
+
+#define SONYPI_CAMERA_BRIGHTNESS 0
+#define SONYPI_CAMERA_CONTRAST 1
+#define SONYPI_CAMERA_HUE 2
+#define SONYPI_CAMERA_COLOR 3
+#define SONYPI_CAMERA_SHARPNESS 4
+
+#define SONYPI_CAMERA_EXPOSURE_MASK 0xC
+#define SONYPI_CAMERA_WHITE_BALANCE_MASK 0x3
+#define SONYPI_CAMERA_PICTURE_MODE_MASK 0x30
+#define SONYPI_CAMERA_MUTE_MASK 0x40
+
+/* the rest don't need a loop until not 0xff */
+#define SONYPI_CAMERA_AGC 6
+#define SONYPI_CAMERA_AGC_MASK 0x30
+#define SONYPI_CAMERA_SHUTTER_MASK 0x7
+
+#define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
+#define SONYPI_CAMERA_CONTROL 0x10
+
+#define SONYPI_CAMERA_STATUS 7
+#define SONYPI_CAMERA_STATUS_READY 0x2
+#define SONYPI_CAMERA_STATUS_POSITION 0x4
+
+#define SONYPI_DIRECTION_BACKWARDS 0x4
+
+#define SONYPI_CAMERA_REVISION 8
+#define SONYPI_CAMERA_ROMVERSION 9
+
+static int __sony_pic_camera_ready(void)
+{
+ u8 v;
+
+ v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
+ return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
+}
+
+static int __sony_pic_camera_off(void)
+{
+ if (!camera) {
+ printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+ return -ENODEV;
+ }
+
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
+ SONYPI_CAMERA_MUTE_MASK),
+ ITERATIONS_SHORT);
+
+ if (spic_dev.camera_power) {
+ sony_pic_call2(0x91, 0);
+ spic_dev.camera_power = 0;
+ }
+ return 0;
+}
+
+static int __sony_pic_camera_on(void)
{
- return acpi_bus_register_driver(&sony_acpi_driver);
+ int i, j, x;
+
+ if (!camera) {
+ printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+ return -ENODEV;
+ }
+
+ if (spic_dev.camera_power)
+ return 0;
+
+ for (j = 5; j > 0; j--) {
+
+ for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
+ msleep(10);
+ sony_pic_call1(0x93);
+
+ for (i = 400; i > 0; i--) {
+ if (__sony_pic_camera_ready())
+ break;
+ msleep(10);
+ }
+ if (i)
+ break;
+ }
+
+ if (j == 0) {
+ printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
+ return -ENODEV;
+ }
+
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL,
+ 0x5a),
+ ITERATIONS_SHORT);
+
+ spic_dev.camera_power = 1;
+ return 0;
+}
+
+/* External camera command (exported to the motion eye v4l driver) */
+int sony_pic_camera_command(int command, u8 value)
+{
+ if (!camera)
+ return -EIO;
+
+ mutex_lock(&spic_dev.lock);
+
+ switch (command) {
+ case SONY_PIC_COMMAND_SETCAMERA:
+ if (value)
+ __sony_pic_camera_on();
+ else
+ __sony_pic_camera_off();
+ break;
+ case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERACONTRAST:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAHUE:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERACOLOR:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAPICTURE:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
+ ITERATIONS_SHORT);
+ break;
+ case SONY_PIC_COMMAND_SETCAMERAAGC:
+ wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
+ ITERATIONS_SHORT);
+ break;
+ default:
+ printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+ command);
+ break;
+ }
+ mutex_unlock(&spic_dev.lock);
+ return 0;
+}
+EXPORT_SYMBOL(sony_pic_camera_command);
+
+/* gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise */
+static void sony_pic_set_wwanpower(u8 state)
+{
+ state = !!state;
+ mutex_lock(&spic_dev.lock);
+ if (spic_dev.wwan_power == state) {
+ mutex_unlock(&spic_dev.lock);
+ return;
+ }
+ sony_pic_call2(0xB0, state);
+ spic_dev.wwan_power = state;
+ mutex_unlock(&spic_dev.lock);
+}
+
+static ssize_t sony_pic_wwanpower_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+ sony_pic_set_wwanpower(value);
+
+ return count;
+}
+
+static ssize_t sony_pic_wwanpower_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t count;
+ mutex_lock(&spic_dev.lock);
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.wwan_power);
+ mutex_unlock(&spic_dev.lock);
+ return count;
+}
+
+/* bluetooth subsystem power state */
+static void __sony_pic_set_bluetoothpower(u8 state)
+{
+ state = !!state;
+ if (spic_dev.bluetooth_power == state)
+ return;
+ sony_pic_call2(0x96, state);
+ sony_pic_call1(0x82);
+ spic_dev.bluetooth_power = state;
+}
+
+static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+ mutex_lock(&spic_dev.lock);
+ __sony_pic_set_bluetoothpower(value);
+ mutex_unlock(&spic_dev.lock);
+
+ return count;
+}
+
+static ssize_t sony_pic_bluetoothpower_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ ssize_t count = 0;
+ mutex_lock(&spic_dev.lock);
+ count = snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power);
+ mutex_unlock(&spic_dev.lock);
+ return count;
+}
+
+/* fan speed */
+/* FAN0 information (reverse engineered from ACPI tables) */
+#define SONY_PIC_FAN0_STATUS 0x93
+static int sony_pic_set_fanspeed(unsigned long value)
+{
+ return ec_write(SONY_PIC_FAN0_STATUS, value);
+}
+
+static int sony_pic_get_fanspeed(u8 *value)
+{
+ return ec_read(SONY_PIC_FAN0_STATUS, value);
+}
+
+static ssize_t sony_pic_fanspeed_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ unsigned long value;
+ if (count > 31)
+ return -EINVAL;
+
+ value = simple_strtoul(buffer, NULL, 10);
+ if (sony_pic_set_fanspeed(value))
+ return -EIO;
+
+ return count;
+}
+
+static ssize_t sony_pic_fanspeed_show(struct device *dev,
+ struct device_attribute *attr, char *buffer)
+{
+ u8 value = 0;
+ if (sony_pic_get_fanspeed(&value))
+ return -EIO;
+
+ return snprintf(buffer, PAGE_SIZE, "%d\n", value);
+}
+
+#define SPIC_ATTR(_name, _mode) \
+struct device_attribute spic_attr_##_name = __ATTR(_name, \
+ _mode, sony_pic_## _name ##_show, \
+ sony_pic_## _name ##_store)
+
+static SPIC_ATTR(bluetoothpower, 0644);
+static SPIC_ATTR(wwanpower, 0644);
+static SPIC_ATTR(fanspeed, 0644);
+
+static struct attribute *spic_attributes[] = {
+ &spic_attr_bluetoothpower.attr,
+ &spic_attr_wwanpower.attr,
+ &spic_attr_fanspeed.attr,
+ NULL
+};
+
+static struct attribute_group spic_attribute_group = {
+ .attrs = spic_attributes
+};
+
+/******** SONYPI compatibility **********/
+#ifdef CONFIG_SONY_LAPTOP_OLD
+
+/* battery / brightness / temperature addresses */
+#define SONYPI_BAT_FLAGS 0x81
+#define SONYPI_LCD_LIGHT 0x96
+#define SONYPI_BAT1_PCTRM 0xa0
+#define SONYPI_BAT1_LEFT 0xa2
+#define SONYPI_BAT1_MAXRT 0xa4
+#define SONYPI_BAT2_PCTRM 0xa8
+#define SONYPI_BAT2_LEFT 0xaa
+#define SONYPI_BAT2_MAXRT 0xac
+#define SONYPI_BAT1_MAXTK 0xb0
+#define SONYPI_BAT1_FULL 0xb2
+#define SONYPI_BAT2_MAXTK 0xb8
+#define SONYPI_BAT2_FULL 0xba
+#define SONYPI_TEMP_STATUS 0xC1
+
+struct sonypi_compat_s {
+ struct fasync_struct *fifo_async;
+ struct kfifo *fifo;
+ spinlock_t fifo_lock;
+ wait_queue_head_t fifo_proc_list;
+ atomic_t open_count;
+};
+static struct sonypi_compat_s sonypi_compat = {
+ .open_count = ATOMIC_INIT(0),
+};
+
+static int sonypi_misc_fasync(int fd, struct file *filp, int on)
+{
+ int retval;
+
+ retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
+ if (retval < 0)
+ return retval;
+ return 0;
+}
+
+static int sonypi_misc_release(struct inode *inode, struct file *file)
+{
+ sonypi_misc_fasync(-1, file, 0);
+ atomic_dec(&sonypi_compat.open_count);
+ return 0;
+}
+
+static int sonypi_misc_open(struct inode *inode, struct file *file)
+{
+ /* Flush input queue on first open */
+ if (atomic_inc_return(&sonypi_compat.open_count) == 1)
+ kfifo_reset(sonypi_compat.fifo);
+ return 0;
+}
+
+static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ ssize_t ret;
+ unsigned char c;
+
+ if ((kfifo_len(sonypi_compat.fifo) == 0) &&
+ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
+ kfifo_len(sonypi_compat.fifo) != 0);
+ if (ret)
+ return ret;
+
+ while (ret < count &&
+ (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) {
+ if (put_user(c, buf++))
+ return -EFAULT;
+ ret++;
+ }
+
+ if (ret > 0) {
+ struct inode *inode = file->f_path.dentry->d_inode;
+ inode->i_atime = current_fs_time(inode->i_sb);
+ }
+
+ return ret;
+}
+
+static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
+ if (kfifo_len(sonypi_compat.fifo))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static int ec_read16(u8 addr, u16 *value)
+{
+ u8 val_lb, val_hb;
+ if (ec_read(addr, &val_lb))
+ return -1;
+ if (ec_read(addr + 1, &val_hb))
+ return -1;
+ *value = val_lb | (val_hb << 8);
+ return 0;
+}
+
+static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ void __user *argp = (void __user *)arg;
+ u8 val8;
+ u16 val16;
+ int value;
+
+ mutex_lock(&spic_dev.lock);
+ switch (cmd) {
+ case SONYPI_IOCGBRT:
+ if (sony_backlight_device == NULL) {
+ ret = -EIO;
+ break;
+ }
+ if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
+ ret = -EIO;
+ break;
+ }
+ val8 = ((value & 0xff) - 1) << 5;
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCSBRT:
+ if (sony_backlight_device == NULL) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_from_user(&val8, argp, sizeof(val8))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
+ (val8 >> 5) + 1, NULL)) {
+ ret = -EIO;
+ break;
+ }
+ /* sync the backlight device status */
+ sony_backlight_device->props.brightness =
+ sony_backlight_get_brightness(sony_backlight_device);
+ break;
+ case SONYPI_IOCGBAT1CAP:
+ if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBAT1REM:
+ if (ec_read16(SONYPI_BAT1_LEFT, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBAT2CAP:
+ if (ec_read16(SONYPI_BAT2_FULL, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBAT2REM:
+ if (ec_read16(SONYPI_BAT2_LEFT, &val16)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val16, sizeof(val16)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBATFLAGS:
+ if (ec_read(SONYPI_BAT_FLAGS, &val8)) {
+ ret = -EIO;
+ break;
+ }
+ val8 &= 0x07;
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCGBLUE:
+ val8 = spic_dev.bluetooth_power;
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCSBLUE:
+ if (copy_from_user(&val8, argp, sizeof(val8))) {
+ ret = -EFAULT;
+ break;
+ }
+ __sony_pic_set_bluetoothpower(val8);
+ break;
+ /* FAN Controls */
+ case SONYPI_IOCGFAN:
+ if (sony_pic_get_fanspeed(&val8)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ case SONYPI_IOCSFAN:
+ if (copy_from_user(&val8, argp, sizeof(val8))) {
+ ret = -EFAULT;
+ break;
+ }
+ if (sony_pic_set_fanspeed(val8))
+ ret = -EIO;
+ break;
+ /* GET Temperature (useful under APM) */
+ case SONYPI_IOCGTEMP:
+ if (ec_read(SONYPI_TEMP_STATUS, &val8)) {
+ ret = -EIO;
+ break;
+ }
+ if (copy_to_user(argp, &val8, sizeof(val8)))
+ ret = -EFAULT;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&spic_dev.lock);
+ return ret;
+}
+
+static const struct file_operations sonypi_misc_fops = {
+ .owner = THIS_MODULE,
+ .read = sonypi_misc_read,
+ .poll = sonypi_misc_poll,
+ .open = sonypi_misc_open,
+ .release = sonypi_misc_release,
+ .fasync = sonypi_misc_fasync,
+ .ioctl = sonypi_misc_ioctl,
+};
+
+static struct miscdevice sonypi_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sonypi",
+ .fops = &sonypi_misc_fops,
+};
+
+static void sonypi_compat_report_event(u8 event)
+{
+ kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event));
+ kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
+ wake_up_interruptible(&sonypi_compat.fifo_proc_list);
+}
+
+static int sonypi_compat_init(void)
+{
+ int error;
+
+ spin_lock_init(&sonypi_compat.fifo_lock);
+ sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
+ &sonypi_compat.fifo_lock);
+ if (IS_ERR(sonypi_compat.fifo)) {
+ printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+ return PTR_ERR(sonypi_compat.fifo);
+ }
+
+ init_waitqueue_head(&sonypi_compat.fifo_proc_list);
+
+ if (minor != -1)
+ sonypi_misc_device.minor = minor;
+ error = misc_register(&sonypi_misc_device);
+ if (error) {
+ printk(KERN_ERR DRV_PFX "misc_register failed\n");
+ goto err_free_kfifo;
+ }
+ if (minor == -1)
+ printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
+ sonypi_misc_device.minor);
+
+ return 0;
+
+err_free_kfifo:
+ kfifo_free(sonypi_compat.fifo);
+ return error;
+}
+
+static void sonypi_compat_exit(void)
+{
+ misc_deregister(&sonypi_misc_device);
+ kfifo_free(sonypi_compat.fifo);
+}
+#else
+static int sonypi_compat_init(void) { return 0; }
+static void sonypi_compat_exit(void) { }
+static void sonypi_compat_report_event(u8 event) { }
+#endif /* CONFIG_SONY_LAPTOP_OLD */
+
+/*
+ * ACPI callbacks
+ */
+static acpi_status
+sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
+{
+ u32 i;
+ struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
+
+ switch (resource->type) {
+ case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+ case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+ return AE_OK;
+
+ case ACPI_RESOURCE_TYPE_IRQ:
+ {
+ struct acpi_resource_irq *p = &resource->data.irq;
+ struct sony_pic_irq *interrupt = NULL;
+ if (!p || !p->interrupt_count) {
+ /*
+ * IRQ descriptors may have no IRQ# bits set,
+ * particularly those those w/ _STA disabled
+ */
+ dprintk("Blank IRQ resource\n");
+ return AE_OK;
+ }
+ for (i = 0; i < p->interrupt_count; i++) {
+ if (!p->interrupts[i]) {
+ printk(KERN_WARNING DRV_PFX
+ "Invalid IRQ %d\n",
+ p->interrupts[i]);
+ continue;
+ }
+ interrupt = kzalloc(sizeof(*interrupt),
+ GFP_KERNEL);
+ if (!interrupt)
+ return AE_ERROR;
+
+ list_add_tail(&interrupt->list, &dev->interrupts);
+ interrupt->irq.triggering = p->triggering;
+ interrupt->irq.polarity = p->polarity;
+ interrupt->irq.sharable = p->sharable;
+ interrupt->irq.interrupt_count = 1;
+ interrupt->irq.interrupts[0] = p->interrupts[i];
+ }
+ return AE_OK;
+ }
+ case ACPI_RESOURCE_TYPE_IO:
+ {
+ struct acpi_resource_io *io = &resource->data.io;
+ struct sony_pic_ioport *ioport = NULL;
+ if (!io) {
+ dprintk("Blank IO resource\n");
+ return AE_OK;
+ }
+
+ ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
+ if (!ioport)
+ return AE_ERROR;
+
+ list_add_tail(&ioport->list, &dev->ioports);
+ memcpy(&ioport->io, io, sizeof(*io));
+ return AE_OK;
+ }
+ default:
+ dprintk("Resource %d isn't an IRQ nor an IO port\n",
+ resource->type);
+
+ case ACPI_RESOURCE_TYPE_END_TAG:
+ return AE_OK;
+ }
+ return AE_CTRL_TERMINATE;
+}
+
+static int sony_pic_possible_resources(struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+
+ if (!device)
+ return -EINVAL;
+
+ /* get device status */
+ /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
+ dprintk("Evaluating _STA\n");
+ result = acpi_bus_get_status(device);
+ if (result) {
+ printk(KERN_WARNING DRV_PFX "Unable to read status\n");
+ goto end;
+ }
+
+ if (!device->status.enabled)
+ dprintk("Device disabled\n");
+ else
+ dprintk("Device enabled\n");
+
+ /*
+ * Query and parse 'method'
+ */
+ dprintk("Evaluating %s\n", METHOD_NAME__PRS);
+ status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
+ sony_pic_read_possible_resource, &spic_dev);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_WARNING DRV_PFX
+ "Failure evaluating %s\n",
+ METHOD_NAME__PRS);
+ result = -ENODEV;
+ }
+end:
+ return result;
+}
+
+/*
+ * Disable the spic device by calling its _DIS method
+ */
+static int sony_pic_disable(struct acpi_device *device)
+{
+ if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
+ return -ENXIO;
+
+ dprintk("Device disabled\n");
+ return 0;
+}
+
+
+/*
+ * Based on drivers/acpi/pci_link.c:acpi_pci_link_set
+ *
+ * Call _SRS to set current resources
+ */
+static int sony_pic_enable(struct acpi_device *device,
+ struct sony_pic_ioport *ioport, struct sony_pic_irq *irq)
+{
+ acpi_status status;
+ int result = 0;
+ struct {
+ struct acpi_resource io_res;
+ struct acpi_resource irq_res;
+ struct acpi_resource end;
+ } *resource;
+ struct acpi_buffer buffer = { 0, NULL };
+
+ if (!ioport || !irq)
+ return -EINVAL;
+
+ /* init acpi_buffer */
+ resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
+ if (!resource)
+ return -ENOMEM;
+
+ buffer.length = sizeof(*resource) + 1;
+ buffer.pointer = resource;
+
+ /* setup io resource */
+ resource->io_res.type = ACPI_RESOURCE_TYPE_IO;
+ resource->io_res.length = sizeof(struct acpi_resource);
+ memcpy(&resource->io_res.data.io, &ioport->io,
+ sizeof(struct acpi_resource_io));
+
+ /* setup irq resource */
+ resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ;
+ resource->irq_res.length = sizeof(struct acpi_resource);
+ memcpy(&resource->irq_res.data.irq, &irq->irq,
+ sizeof(struct acpi_resource_irq));
+ /* we requested a shared irq */
+ resource->irq_res.data.irq.sharable = ACPI_SHARED;
+
+ resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
+
+ /* Attempt to set the resource */
+ dprintk("Evaluating _SRS\n");
+ status = acpi_set_current_resources(device->handle, &buffer);
+
+ /* check for total failure */
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR DRV_PFX "Error evaluating _SRS");
+ result = -ENODEV;
+ goto end;
+ }
+
+ /* Necessary device initializations calls (from sonypi) */
+ sony_pic_call1(0x82);
+ sony_pic_call2(0x81, 0xff);
+ sony_pic_call1(compat ? 0x92 : 0x82);
+
+end:
+ kfree(resource);
+ return result;
+}
+
+/*****************
+ *
+ * ISR: some event is available
+ *
+ *****************/
+static irqreturn_t sony_pic_irq(int irq, void *dev_id)
+{
+ int i, j;
+ u32 port_val = 0;
+ u8 ev = 0;
+ u8 data_mask = 0;
+ u8 device_event = 0;
+
+ struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
+
+ acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
+ dev->cur_ioport->io.address_length);
+ ev = port_val & SONY_PIC_EV_MASK;
+ data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+
+ dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
+ port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+
+ if (ev == 0x00 || ev == 0xff)
+ return IRQ_HANDLED;
+
+ for (i = 0; sony_pic_eventtypes[i].model; i++) {
+
+ if (spic_dev.model != sony_pic_eventtypes[i].model)
+ continue;
+
+ if ((data_mask & sony_pic_eventtypes[i].data) !=
+ sony_pic_eventtypes[i].data)
+ continue;
+
+ if (!(mask & sony_pic_eventtypes[i].mask))
+ continue;
+
+ for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
+ if (ev == sony_pic_eventtypes[i].events[j].data) {
+ device_event =
+ sony_pic_eventtypes[i].events[j].event;
+ goto found;
+ }
+ }
+ }
+ return IRQ_HANDLED;
+
+found:
+ sony_laptop_report_input_event(device_event);
+ acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
+ sonypi_compat_report_event(device_event);
+
+ return IRQ_HANDLED;
+}
+
+/*****************
+ *
+ * ACPI driver
+ *
+ *****************/
+static int sony_pic_remove(struct acpi_device *device, int type)
+{
+ struct sony_pic_ioport *io, *tmp_io;
+ struct sony_pic_irq *irq, *tmp_irq;
+
+ sonypi_compat_exit();
+
+ if (sony_pic_disable(device)) {
+ printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
+ return -ENXIO;
+ }
+
+ free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+ release_region(spic_dev.cur_ioport->io.minimum,
+ spic_dev.cur_ioport->io.address_length);
+
+ sony_laptop_remove_input();
+
+ /* pf attrs */
+ sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+ sony_pf_remove();
+
+ list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+ list_del(&io->list);
+ kfree(io);
+ }
+ list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+ list_del(&irq->list);
+ kfree(irq);
+ }
+ spic_dev.cur_ioport = NULL;
+ spic_dev.cur_irq = NULL;
+
+ dprintk(SONY_PIC_DRIVER_NAME " removed.\n");
+ return 0;
+}
+
+static int sony_pic_add(struct acpi_device *device)
+{
+ int result;
+ struct sony_pic_ioport *io, *tmp_io;
+ struct sony_pic_irq *irq, *tmp_irq;
+
+ printk(KERN_INFO DRV_PFX "%s v%s.\n",
+ SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+
+ spic_dev.acpi_dev = device;
+ strcpy(acpi_device_class(device), "sony/hotkey");
+ spic_dev.model = sony_pic_detect_device_type();
+ mutex_init(&spic_dev.lock);
+
+ /* read _PRS resources */
+ result = sony_pic_possible_resources(device);
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to read possible resources.\n");
+ goto err_free_resources;
+ }
+
+ /* setup input devices and helper fifo */
+ result = sony_laptop_setup_input();
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unabe to create input devices.\n");
+ goto err_free_resources;
+ }
+
+ /* request io port */
+ list_for_each_entry(io, &spic_dev.ioports, list) {
+ if (request_region(io->io.minimum, io->io.address_length,
+ "Sony Programable I/O Device")) {
+ dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n",
+ io->io.minimum, io->io.maximum,
+ io->io.address_length);
+ spic_dev.cur_ioport = io;
+ break;
+ }
+ }
+ if (!spic_dev.cur_ioport) {
+ printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
+ result = -ENODEV;
+ goto err_remove_input;
+ }
+
+ /* request IRQ */
+ list_for_each_entry(irq, &spic_dev.interrupts, list) {
+ if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
+ IRQF_SHARED, "sony-laptop", &spic_dev)) {
+ dprintk("IRQ: %d - triggering: %d - "
+ "polarity: %d - shr: %d\n",
+ irq->irq.interrupts[0],
+ irq->irq.triggering,
+ irq->irq.polarity,
+ irq->irq.sharable);
+ spic_dev.cur_irq = irq;
+ break;
+ }
+ }
+ if (!spic_dev.cur_irq) {
+ printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
+ result = -ENODEV;
+ goto err_release_region;
+ }
+
+ /* set resource status _SRS */
+ result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+ if (result) {
+ printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
+ goto err_free_irq;
+ }
+
+ spic_dev.bluetooth_power = -1;
+ /* create device attributes */
+ result = sony_pf_add();
+ if (result)
+ goto err_disable_device;
+
+ result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+ if (result)
+ goto err_remove_pf;
+
+ if (sonypi_compat_init())
+ goto err_remove_pf;
+
+ return 0;
+
+err_remove_pf:
+ sony_pf_remove();
+
+err_disable_device:
+ sony_pic_disable(device);
+
+err_free_irq:
+ free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
+
+err_release_region:
+ release_region(spic_dev.cur_ioport->io.minimum,
+ spic_dev.cur_ioport->io.address_length);
+
+err_remove_input:
+ sony_laptop_remove_input();
+
+err_free_resources:
+ list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
+ list_del(&io->list);
+ kfree(io);
+ }
+ list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
+ list_del(&irq->list);
+ kfree(irq);
+ }
+ spic_dev.cur_ioport = NULL;
+ spic_dev.cur_irq = NULL;
+
+ return result;
+}
+
+static int sony_pic_suspend(struct acpi_device *device, pm_message_t state)
+{
+ if (sony_pic_disable(device))
+ return -ENXIO;
+ return 0;
+}
+
+static int sony_pic_resume(struct acpi_device *device)
+{
+ sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
+ return 0;
+}
+
+static struct acpi_driver sony_pic_driver = {
+ .name = SONY_PIC_DRIVER_NAME,
+ .class = SONY_PIC_CLASS,
+ .ids = SONY_PIC_HID,
+ .owner = THIS_MODULE,
+ .ops = {
+ .add = sony_pic_add,
+ .remove = sony_pic_remove,
+ .suspend = sony_pic_suspend,
+ .resume = sony_pic_resume,
+ },
+};
+
+static struct dmi_system_id __initdata sonypi_dmi_table[] = {
+ {
+ .ident = "Sony Vaio",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PCG-"),
+ },
+ },
+ {
+ .ident = "Sony Vaio",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-"),
+ },
+ },
+ { }
+};
+
+static int __init sony_laptop_init(void)
+{
+ int result;
+
+ if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
+ result = acpi_bus_register_driver(&sony_pic_driver);
+ if (result) {
+ printk(KERN_ERR DRV_PFX
+ "Unable to register SPIC driver.");
+ goto out;
+ }
+ }
+
+ result = acpi_bus_register_driver(&sony_nc_driver);
+ if (result) {
+ printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
+ goto out_unregister_pic;
+ }
+
+ return 0;
+
+out_unregister_pic:
+ if (!no_spic)
+ acpi_bus_unregister_driver(&sony_pic_driver);
+out:
+ return result;
}
-static void __exit sony_acpi_exit(void)
+static void __exit sony_laptop_exit(void)
{
- acpi_bus_unregister_driver(&sony_acpi_driver);
+ acpi_bus_unregister_driver(&sony_nc_driver);
+ if (!no_spic)
+ acpi_bus_unregister_driver(&sony_pic_driver);
}
-module_init(sony_acpi_init);
-module_exit(sony_acpi_exit);
+module_init(sony_laptop_init);
+module_exit(sony_laptop_exit);
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
new file mode 100644
index 00000000000..6c36a55cb3d
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.c
@@ -0,0 +1,4312 @@
+/*
+ * thinkpad_acpi.c - ThinkPad ACPI Extras
+ *
+ *
+ * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#define IBM_VERSION "0.14"
+#define TPACPI_SYSFS_VERSION 0x000100
+
+/*
+ * Changelog:
+ * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to
+ * drivers/misc.
+ *
+ * 2006-11-22 0.13 new maintainer
+ * changelog now lives in git commit history, and will
+ * not be updated further in-file.
+ *
+ * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels
+ * 2005-03-17 0.11 support for 600e, 770x
+ * thanks to Jamie Lentin <lentinj@dial.pipex.com>
+ * support for 770e, G41
+ * G40 and G41 don't have a thinklight
+ * temperatures no longer experimental
+ * experimental brightness control
+ * experimental volume control
+ * experimental fan enable/disable
+ * 2005-01-16 0.10 fix module loading on R30, R31
+ * 2005-01-16 0.9 support for 570, R30, R31
+ * ultrabay support on A22p, A3x
+ * limit arg for cmos, led, beep, drop experimental status
+ * more capable led control on A21e, A22p, T20-22, X20
+ * experimental temperatures and fan speed
+ * experimental embedded controller register dump
+ * mark more functions as __init, drop incorrect __exit
+ * use MODULE_VERSION
+ * thanks to Henrik Brix Andersen <brix@gentoo.org>
+ * fix parameter passing on module loading
+ * thanks to Rusty Russell <rusty@rustcorp.com.au>
+ * thanks to Jim Radford <radford@blackbean.org>
+ * 2004-11-08 0.8 fix init error case, don't return from a macro
+ * thanks to Chris Wright <chrisw@osdl.org>
+ * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
+ * fix led control on A21e
+ * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
+ * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
+ * proc file format changed
+ * video_switch command
+ * experimental cmos control
+ * experimental led control
+ * experimental acpi sounds
+ * 2004-09-16 0.4 support for module parameters
+ * hotkey mask can be prefixed by 0x
+ * video output switching
+ * video expansion control
+ * ultrabay eject support
+ * removed lcd brightness/on/off control, didn't work
+ * 2004-08-17 0.3 support for R40
+ * lcd off, brightness control
+ * thinklight on/off
+ * 2004-08-14 0.2 support for T series, X20
+ * bluetooth enable/disable
+ * hotkey events disabled by default
+ * removed fan control, currently useless
+ * 2004-08-09 0.1 initial release, support for X series
+ */
+
+#include "thinkpad_acpi.h"
+
+MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");
+MODULE_DESCRIPTION(IBM_DESC);
+MODULE_VERSION(IBM_VERSION);
+MODULE_LICENSE("GPL");
+
+/* Please remove this in year 2009 */
+MODULE_ALIAS("ibm_acpi");
+
+#define __unused __attribute__ ((unused))
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * ACPI Helpers and device model
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * ACPI basic handles
+ */
+
+static acpi_handle root_handle = NULL;
+
+#define IBM_HANDLE(object, parent, paths...) \
+ static acpi_handle object##_handle; \
+ static acpi_handle *object##_parent = &parent##_handle; \
+ static char *object##_path; \
+ static char *object##_paths[] = { paths }
+
+IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */
+ "\\_SB.PCI.ISA.EC", /* 570 */
+ "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */
+ "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */
+ "\\_SB.PCI0.ICH3.EC0", /* R31 */
+ "\\_SB.PCI0.LPC.EC", /* all others */
+ );
+
+IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */
+IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 */
+
+
+/*************************************************************************
+ * Misc ACPI handles
+ */
+
+IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */
+ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */
+ "\\CMS", /* R40, R40e */
+ ); /* all others */
+
+IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
+ "^HKEY", /* R30, R31 */
+ "HKEY", /* all others */
+ ); /* 570 */
+
+
+/*************************************************************************
+ * ACPI helpers
+ */
+
+static int acpi_evalf(acpi_handle handle,
+ void *res, char *method, char *fmt, ...)
+{
+ char *fmt0 = fmt;
+ struct acpi_object_list params;
+ union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+ struct acpi_buffer result, *resultp;
+ union acpi_object out_obj;
+ acpi_status status;
+ va_list ap;
+ char res_type;
+ int success;
+ int quiet;
+
+ if (!*fmt) {
+ printk(IBM_ERR "acpi_evalf() called with empty format\n");
+ return 0;
+ }
+
+ if (*fmt == 'q') {
+ quiet = 1;
+ fmt++;
+ } else
+ quiet = 0;
+
+ res_type = *(fmt++);
+
+ params.count = 0;
+ params.pointer = &in_objs[0];
+
+ va_start(ap, fmt);
+ while (*fmt) {
+ char c = *(fmt++);
+ switch (c) {
+ case 'd': /* int */
+ in_objs[params.count].integer.value = va_arg(ap, int);
+ in_objs[params.count++].type = ACPI_TYPE_INTEGER;
+ break;
+ /* add more types as needed */
+ default:
+ printk(IBM_ERR "acpi_evalf() called "
+ "with invalid format character '%c'\n", c);
+ return 0;
+ }
+ }
+ va_end(ap);
+
+ if (res_type != 'v') {
+ result.length = sizeof(out_obj);
+ result.pointer = &out_obj;
+ resultp = &result;
+ } else
+ resultp = NULL;
+
+ status = acpi_evaluate_object(handle, method, &params, resultp);
+
+ switch (res_type) {
+ case 'd': /* int */
+ if (res)
+ *(int *)res = out_obj.integer.value;
+ success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+ break;
+ case 'v': /* void */
+ success = status == AE_OK;
+ break;
+ /* add more types as needed */
+ default:
+ printk(IBM_ERR "acpi_evalf() called "
+ "with invalid format character '%c'\n", res_type);
+ return 0;
+ }
+
+ if (!success && !quiet)
+ printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+ method, fmt0, status);
+
+ return success;
+}
+
+static void __unused acpi_print_int(acpi_handle handle, char *method)
+{
+ int i;
+
+ if (acpi_evalf(handle, &i, method, "d"))
+ printk(IBM_INFO "%s = 0x%x\n", method, i);
+ else
+ printk(IBM_ERR "error calling %s\n", method);
+}
+
+static int acpi_ec_read(int i, u8 * p)
+{
+ int v;
+
+ if (ecrd_handle) {
+ if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i))
+ return 0;
+ *p = v;
+ } else {
+ if (ec_read(i, p) < 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int acpi_ec_write(int i, u8 v)
+{
+ if (ecwr_handle) {
+ if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v))
+ return 0;
+ } else {
+ if (ec_write(i, v) < 0)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int _sta(acpi_handle handle)
+{
+ int status;
+
+ if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
+ status = 0;
+
+ return status;
+}
+
+static int issue_thinkpad_cmos_command(int cmos_cmd)
+{
+ if (!cmos_handle)
+ return -ENXIO;
+
+ if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
+ return -EIO;
+
+ return 0;
+}
+
+/*************************************************************************
+ * ACPI device model
+ */
+
+static void drv_acpi_handle_init(char *name,
+ acpi_handle *handle, acpi_handle parent,
+ char **paths, int num_paths, char **path)
+{
+ int i;
+ acpi_status status;
+
+ vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n",
+ name);
+
+ for (i = 0; i < num_paths; i++) {
+ status = acpi_get_handle(parent, paths[i], handle);
+ if (ACPI_SUCCESS(status)) {
+ *path = paths[i];
+ dbg_printk(TPACPI_DBG_INIT,
+ "Found ACPI handle %s for %s\n",
+ *path, name);
+ return;
+ }
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n",
+ name);
+ *handle = NULL;
+}
+
+static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ibm_struct *ibm = data;
+
+ if (!ibm || !ibm->acpi || !ibm->acpi->notify)
+ return;
+
+ ibm->acpi->notify(ibm, event);
+}
+
+static int __init setup_acpi_notify(struct ibm_struct *ibm)
+{
+ acpi_status status;
+ int rc;
+
+ BUG_ON(!ibm->acpi);
+
+ if (!*ibm->acpi->handle)
+ return 0;
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "setting up ACPI notify for %s\n", ibm->name);
+
+ rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
+ if (rc < 0) {
+ printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n",
+ ibm->name, rc);
+ return -ENODEV;
+ }
+
+ acpi_driver_data(ibm->acpi->device) = ibm;
+ sprintf(acpi_device_class(ibm->acpi->device), "%s/%s",
+ IBM_ACPI_EVENT_PREFIX,
+ ibm->name);
+
+ status = acpi_install_notify_handler(*ibm->acpi->handle,
+ ibm->acpi->type, dispatch_acpi_notify, ibm);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_ALREADY_EXISTS) {
+ printk(IBM_NOTICE "another device driver is already handling %s events\n",
+ ibm->name);
+ } else {
+ printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
+ ibm->name, status);
+ }
+ return -ENODEV;
+ }
+ ibm->flags.acpi_notify_installed = 1;
+ return 0;
+}
+
+static int __init tpacpi_device_add(struct acpi_device *device)
+{
+ return 0;
+}
+
+static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
+{
+ int rc;
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "registering %s as an ACPI driver\n", ibm->name);
+
+ BUG_ON(!ibm->acpi);
+
+ ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+ if (!ibm->acpi->driver) {
+ printk(IBM_ERR "kzalloc(ibm->driver) failed\n");
+ return -ENOMEM;
+ }
+
+ sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
+ ibm->acpi->driver->ids = ibm->acpi->hid;
+ ibm->acpi->driver->ops.add = &tpacpi_device_add;
+
+ rc = acpi_bus_register_driver(ibm->acpi->driver);
+ if (rc < 0) {
+ printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+ ibm->acpi->hid, rc);
+ kfree(ibm->acpi->driver);
+ ibm->acpi->driver = NULL;
+ } else if (!rc)
+ ibm->flags.acpi_driver_registered = 1;
+
+ return rc;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Procfs Helpers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct ibm_struct *ibm = data;
+ int len;
+
+ if (!ibm || !ibm->read)
+ return -EINVAL;
+
+ len = ibm->read(page);
+ if (len < 0)
+ return len;
+
+ if (len <= off + count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+
+static int dispatch_procfs_write(struct file *file,
+ const char __user * userbuf,
+ unsigned long count, void *data)
+{
+ struct ibm_struct *ibm = data;
+ char *kernbuf;
+ int ret;
+
+ if (!ibm || !ibm->write)
+ return -EINVAL;
+
+ kernbuf = kmalloc(count + 2, GFP_KERNEL);
+ if (!kernbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(kernbuf, userbuf, count)) {
+ kfree(kernbuf);
+ return -EFAULT;
+ }
+
+ kernbuf[count] = 0;
+ strcat(kernbuf, ",");
+ ret = ibm->write(kernbuf);
+ if (ret == 0)
+ ret = count;
+
+ kfree(kernbuf);
+
+ return ret;
+}
+
+static char *next_cmd(char **cmds)
+{
+ char *start = *cmds;
+ char *end;
+
+ while ((end = strchr(start, ',')) && end == start)
+ start = end + 1;
+
+ if (!end)
+ return NULL;
+
+ *end = 0;
+ *cmds = end + 1;
+ return start;
+}
+
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Device model: hwmon and platform
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+static struct platform_device *tpacpi_pdev = NULL;
+static struct class_device *tpacpi_hwmon = NULL;
+
+static struct platform_driver tpacpi_pdriver = {
+ .driver = {
+ .name = IBM_DRVR_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/*************************************************************************
+ * thinkpad-acpi driver attributes
+ */
+
+/* interface_version --------------------------------------------------- */
+static ssize_t tpacpi_driver_interface_version_show(
+ struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);
+}
+
+static DRIVER_ATTR(interface_version, S_IRUGO,
+ tpacpi_driver_interface_version_show, NULL);
+
+/* debug_level --------------------------------------------------------- */
+static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);
+}
+
+static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 0xffff, &t))
+ return -EINVAL;
+
+ dbg_level = t;
+
+ return count;
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ tpacpi_driver_debug_show, tpacpi_driver_debug_store);
+
+/* version ------------------------------------------------------------- */
+static ssize_t tpacpi_driver_version_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO,
+ tpacpi_driver_version_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct driver_attribute* tpacpi_driver_attributes[] = {
+ &driver_attr_debug_level, &driver_attr_version,
+ &driver_attr_interface_version,
+};
+
+static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
+{
+ int i, res;
+
+ i = 0;
+ res = 0;
+ while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
+ res = driver_create_file(drv, tpacpi_driver_attributes[i]);
+ i++;
+ }
+
+ return res;
+}
+
+static void tpacpi_remove_driver_attributes(struct device_driver *drv)
+{
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
+ driver_remove_file(drv, tpacpi_driver_attributes[i]);
+}
+
+/*************************************************************************
+ * sysfs support helpers
+ */
+
+struct attribute_set_obj {
+ struct attribute_set s;
+ struct attribute *a;
+} __attribute__((packed));
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+ const char* name)
+{
+ struct attribute_set_obj *sobj;
+
+ if (max_members == 0)
+ return NULL;
+
+ /* Allocates space for implicit NULL at the end too */
+ sobj = kzalloc(sizeof(struct attribute_set_obj) +
+ max_members * sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!sobj)
+ return NULL;
+ sobj->s.max_members = max_members;
+ sobj->s.group.attrs = &sobj->a;
+ sobj->s.group.name = name;
+
+ return &sobj->s;
+}
+
+/* not multi-threaded safe, use it in a single thread per set */
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr)
+{
+ if (!s || !attr)
+ return -EINVAL;
+
+ if (s->members >= s->max_members)
+ return -ENOMEM;
+
+ s->group.attrs[s->members] = attr;
+ s->members++;
+
+ return 0;
+}
+
+static int add_many_to_attr_set(struct attribute_set* s,
+ struct attribute **attr,
+ unsigned int count)
+{
+ int i, res;
+
+ for (i = 0; i < count; i++) {
+ res = add_to_attr_set(s, attr[i]);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj)
+{
+ sysfs_remove_group(kobj, &s->group);
+ destroy_attr_set(s);
+}
+
+static int parse_strtoul(const char *buf,
+ unsigned long max, unsigned long *value)
+{
+ char *endp;
+
+ *value = simple_strtoul(buf, &endp, 0);
+ while (*endp && isspace(*endp))
+ endp++;
+ if (*endp || *value > max)
+ return -EINVAL;
+
+ return 0;
+}
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Subdrivers
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/*************************************************************************
+ * thinkpad-acpi init subdriver
+ */
+
+static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
+{
+ printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
+ printk(IBM_INFO "%s\n", IBM_URL);
+
+ if (ibm_thinkpad_ec_found)
+ printk(IBM_INFO "ThinkPad EC firmware %s\n",
+ ibm_thinkpad_ec_found);
+
+ return 0;
+}
+
+static int thinkpad_acpi_driver_read(char *p)
+{
+ int len = 0;
+
+ len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
+ len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+
+ return len;
+}
+
+static struct ibm_struct thinkpad_acpi_driver_data = {
+ .name = "driver",
+ .read = thinkpad_acpi_driver_read,
+};
+
+/*************************************************************************
+ * Hotkey subdriver
+ */
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct attribute_set *hotkey_dev_attributes = NULL;
+
+/* sysfs hotkey enable ------------------------------------------------- */
+static ssize_t hotkey_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, status, mask;
+
+ res = hotkey_get(&status, &mask);
+ if (res)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status);
+}
+
+static ssize_t hotkey_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res, status, mask;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ res = hotkey_get(&status, &mask);
+ if (!res)
+ res = hotkey_set(t, mask);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_enable =
+ __ATTR(enable, S_IWUSR | S_IRUGO,
+ hotkey_enable_show, hotkey_enable_store);
+
+/* sysfs hotkey mask --------------------------------------------------- */
+static ssize_t hotkey_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, status, mask;
+
+ res = hotkey_get(&status, &mask);
+ if (res)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+}
+
+static ssize_t hotkey_mask_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res, status, mask;
+
+ if (parse_strtoul(buf, 0xffff, &t))
+ return -EINVAL;
+
+ res = hotkey_get(&status, &mask);
+ if (!res)
+ hotkey_set(status, t);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_hotkey_mask =
+ __ATTR(mask, S_IWUSR | S_IRUGO,
+ hotkey_mask_show, hotkey_mask_store);
+
+/* sysfs hotkey bios_enabled ------------------------------------------- */
+static ssize_t hotkey_bios_enabled_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_enabled =
+ __ATTR(bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);
+
+/* sysfs hotkey bios_mask ---------------------------------------------- */
+static ssize_t hotkey_bios_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_bios_mask =
+ __ATTR(bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *hotkey_mask_attributes[] = {
+ &dev_attr_hotkey_mask.attr,
+ &dev_attr_hotkey_bios_enabled.attr,
+ &dev_attr_hotkey_bios_mask.attr,
+};
+
+static int __init hotkey_init(struct ibm_init_struct *iibm)
+{
+ int res;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(hkey);
+ mutex_init(&hotkey_mutex);
+
+ /* hotkey not supported on 570 */
+ tp_features.hotkey = hkey_handle != NULL;
+
+ vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",
+ str_supported(tp_features.hotkey));
+
+ if (tp_features.hotkey) {
+ hotkey_dev_attributes = create_attr_set(4,
+ TPACPI_HOTKEY_SYSFS_GROUP);
+ if (!hotkey_dev_attributes)
+ return -ENOMEM;
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_enable.attr);
+ if (res)
+ return res;
+
+ /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ A30, R30, R31, T20-22, X20-21, X22-24 */
+ tp_features.hotkey_mask =
+ acpi_evalf(hkey_handle, NULL, "DHKN", "qv");
+
+ vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
+ str_supported(tp_features.hotkey_mask));
+
+ res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
+ if (!res && tp_features.hotkey_mask) {
+ res = add_many_to_attr_set(hotkey_dev_attributes,
+ hotkey_mask_attributes,
+ ARRAY_SIZE(hotkey_mask_attributes));
+ }
+ if (!res)
+ res = register_attr_set_with_sysfs(
+ hotkey_dev_attributes,
+ &tpacpi_pdev->dev.kobj);
+
+ if (res)
+ return res;
+ }
+
+ return (tp_features.hotkey)? 0 : 1;
+}
+
+static void hotkey_exit(void)
+{
+ int res;
+
+ if (tp_features.hotkey) {
+ dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n");
+ res = hotkey_set(hotkey_orig_status, hotkey_orig_mask);
+ if (res)
+ printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n");
+ }
+
+ if (hotkey_dev_attributes) {
+ delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj);
+ hotkey_dev_attributes = NULL;
+ }
+}
+
+static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+{
+ int hkey;
+
+ if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
+ acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+ else {
+ printk(IBM_ERR "unknown hotkey event %d\n", event);
+ acpi_bus_generate_event(ibm->acpi->device, event, 0);
+ }
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_get(int *status, int *mask)
+{
+ if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+ return -EIO;
+
+ if (tp_features.hotkey_mask)
+ if (!acpi_evalf(hkey_handle, mask, "DHKN", "d"))
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Call with hotkey_mutex held
+ */
+static int hotkey_set(int status, int mask)
+{
+ int i;
+
+ if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+ return -EIO;
+
+ if (tp_features.hotkey_mask)
+ for (i = 0; i < 32; i++) {
+ int bit = ((1 << i) & mask) != 0;
+ if (!acpi_evalf(hkey_handle,
+ NULL, "MHKM", "vdd", i + 1, bit))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int hotkey_read(char *p)
+{
+ int res, status, mask;
+ int len = 0;
+
+ if (!tp_features.hotkey) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ return len;
+ }
+
+ res = mutex_lock_interruptible(&hotkey_mutex);
+ if (res < 0)
+ return res;
+ res = hotkey_get(&status, &mask);
+ mutex_unlock(&hotkey_mutex);
+ if (res)
+ return res;
+
+ len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+ if (tp_features.hotkey_mask) {
+ len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+ len += sprintf(p + len,
+ "commands:\tenable, disable, reset, <mask>\n");
+ } else {
+ len += sprintf(p + len, "mask:\t\tnot supported\n");
+ len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+ }
+
+ return len;
+}
+
+static int hotkey_write(char *buf)
+{
+ int res, status, mask;
+ char *cmd;
+ int do_cmd = 0;
+
+ if (!tp_features.hotkey)
+ return -ENODEV;
+
+ res = mutex_lock_interruptible(&hotkey_mutex);
+ if (res < 0)
+ return res;
+
+ res = hotkey_get(&status, &mask);
+ if (res)
+ goto errexit;
+
+ res = 0;
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ status = 1;
+ } else if (strlencmp(cmd, "disable") == 0) {
+ status = 0;
+ } else if (strlencmp(cmd, "reset") == 0) {
+ status = hotkey_orig_status;
+ mask = hotkey_orig_mask;
+ } else if (sscanf(cmd, "0x%x", &mask) == 1) {
+ /* mask set */
+ } else if (sscanf(cmd, "%x", &mask) == 1) {
+ /* mask set */
+ } else {
+ res = -EINVAL;
+ goto errexit;
+ }
+ do_cmd = 1;
+ }
+
+ if (do_cmd)
+ res = hotkey_set(status, mask);
+
+errexit:
+ mutex_unlock(&hotkey_mutex);
+ return res;
+}
+
+static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
+ .hid = IBM_HKEY_HID,
+ .notify = hotkey_notify,
+ .handle = &hkey_handle,
+ .type = ACPI_DEVICE_NOTIFY,
+};
+
+static struct ibm_struct hotkey_driver_data = {
+ .name = "hotkey",
+ .read = hotkey_read,
+ .write = hotkey_write,
+ .exit = hotkey_exit,
+ .acpi = &ibm_hotkey_acpidriver,
+};
+
+/*************************************************************************
+ * Bluetooth subdriver
+ */
+
+/* sysfs bluetooth enable ---------------------------------------------- */
+static ssize_t bluetooth_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int status;
+
+ status = bluetooth_get_radiosw();
+ if (status < 0)
+ return status;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t bluetooth_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ res = bluetooth_set_radiosw(t);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_bluetooth_enable =
+ __ATTR(enable, S_IWUSR | S_IRUGO,
+ bluetooth_enable_show, bluetooth_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *bluetooth_attributes[] = {
+ &dev_attr_bluetooth_enable.attr,
+ NULL
+};
+
+static const struct attribute_group bluetooth_attr_group = {
+ .name = TPACPI_BLUETH_SYSFS_GROUP,
+ .attrs = bluetooth_attributes,
+};
+
+static int __init bluetooth_init(struct ibm_init_struct *iibm)
+{
+ int res;
+ int status = 0;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(hkey);
+
+ /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ G4x, R30, R31, R40e, R50e, T20-22, X20-21 */
+ tp_features.bluetooth = hkey_handle &&
+ acpi_evalf(hkey_handle, &status, "GBDC", "qd");
+
+ vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n",
+ str_supported(tp_features.bluetooth),
+ status);
+
+ if (tp_features.bluetooth) {
+ if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) {
+ /* no bluetooth hardware present in system */
+ tp_features.bluetooth = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "bluetooth hardware not installed\n");
+ } else {
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &bluetooth_attr_group);
+ if (res)
+ return res;
+ }
+ }
+
+ return (tp_features.bluetooth)? 0 : 1;
+}
+
+static void bluetooth_exit(void)
+{
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &bluetooth_attr_group);
+}
+
+static int bluetooth_get_radiosw(void)
+{
+ int status;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ return -EIO;
+
+ return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);
+}
+
+static int bluetooth_set_radiosw(int radio_on)
+{
+ int status;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ return -EIO;
+ if (radio_on)
+ status |= TP_ACPI_BLUETOOTH_RADIOSSW;
+ else
+ status &= ~TP_ACPI_BLUETOOTH_RADIOSSW;
+ if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int bluetooth_read(char *p)
+{
+ int len = 0;
+ int status = bluetooth_get_radiosw();
+
+ if (!tp_features.bluetooth)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status)? "enabled" : "disabled");
+ len += sprintf(p + len, "commands:\tenable, disable\n");
+ }
+
+ return len;
+}
+
+static int bluetooth_write(char *buf)
+{
+ char *cmd;
+
+ if (!tp_features.bluetooth)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ bluetooth_set_radiosw(1);
+ } else if (strlencmp(cmd, "disable") == 0) {
+ bluetooth_set_radiosw(0);
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct bluetooth_driver_data = {
+ .name = "bluetooth",
+ .read = bluetooth_read,
+ .write = bluetooth_write,
+ .exit = bluetooth_exit,
+};
+
+/*************************************************************************
+ * Wan subdriver
+ */
+
+/* sysfs wan enable ---------------------------------------------------- */
+static ssize_t wan_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int status;
+
+ status = wan_get_radiosw();
+ if (status < 0)
+ return status;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);
+}
+
+static ssize_t wan_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res;
+
+ if (parse_strtoul(buf, 1, &t))
+ return -EINVAL;
+
+ res = wan_set_radiosw(t);
+
+ return (res) ? res : count;
+}
+
+static struct device_attribute dev_attr_wan_enable =
+ __ATTR(enable, S_IWUSR | S_IRUGO,
+ wan_enable_show, wan_enable_store);
+
+/* --------------------------------------------------------------------- */
+
+static struct attribute *wan_attributes[] = {
+ &dev_attr_wan_enable.attr,
+ NULL
+};
+
+static const struct attribute_group wan_attr_group = {
+ .name = TPACPI_WAN_SYSFS_GROUP,
+ .attrs = wan_attributes,
+};
+
+static int __init wan_init(struct ibm_init_struct *iibm)
+{
+ int res;
+ int status = 0;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(hkey);
+
+ tp_features.wan = hkey_handle &&
+ acpi_evalf(hkey_handle, &status, "GWAN", "qd");
+
+ vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",
+ str_supported(tp_features.wan),
+ status);
+
+ if (tp_features.wan) {
+ if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {
+ /* no wan hardware present in system */
+ tp_features.wan = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "wan hardware not installed\n");
+ } else {
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &wan_attr_group);
+ if (res)
+ return res;
+ }
+ }
+
+ return (tp_features.wan)? 0 : 1;
+}
+
+static void wan_exit(void)
+{
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &wan_attr_group);
+}
+
+static int wan_get_radiosw(void)
+{
+ int status;
+
+ if (!tp_features.wan)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ return -EIO;
+
+ return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);
+}
+
+static int wan_set_radiosw(int radio_on)
+{
+ int status;
+
+ if (!tp_features.wan)
+ return -ENODEV;
+
+ if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))
+ return -EIO;
+ if (radio_on)
+ status |= TP_ACPI_WANCARD_RADIOSSW;
+ else
+ status &= ~TP_ACPI_WANCARD_RADIOSSW;
+ if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+/* procfs -------------------------------------------------------------- */
+static int wan_read(char *p)
+{
+ int len = 0;
+ int status = wan_get_radiosw();
+
+ if (!tp_features.wan)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status)? "enabled" : "disabled");
+ len += sprintf(p + len, "commands:\tenable, disable\n");
+ }
+
+ return len;
+}
+
+static int wan_write(char *buf)
+{
+ char *cmd;
+
+ if (!tp_features.wan)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ wan_set_radiosw(1);
+ } else if (strlencmp(cmd, "disable") == 0) {
+ wan_set_radiosw(0);
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct wan_driver_data = {
+ .name = "wan",
+ .read = wan_read,
+ .write = wan_write,
+ .exit = wan_exit,
+ .flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Video subdriver
+ */
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+
+IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
+ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
+ "\\_SB.PCI0.VID0", /* 770e */
+ "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
+ "\\_SB.PCI0.AGP.VID", /* all others */
+ ); /* R30, R31 */
+
+IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
+
+static int __init video_init(struct ibm_init_struct *iibm)
+{
+ int ivga;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(vid);
+ IBM_ACPIHANDLE_INIT(vid2);
+
+ if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)
+ /* G41, assume IVGA doesn't change */
+ vid_handle = vid2_handle;
+
+ if (!vid_handle)
+ /* video switching not supported on R30, R31 */
+ video_supported = TPACPI_VIDEO_NONE;
+ else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))
+ /* 570 */
+ video_supported = TPACPI_VIDEO_570;
+ else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))
+ /* 600e/x, 770e, 770x */
+ video_supported = TPACPI_VIDEO_770;
+ else
+ /* all others */
+ video_supported = TPACPI_VIDEO_NEW;
+
+ vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",
+ str_supported(video_supported != TPACPI_VIDEO_NONE),
+ video_supported);
+
+ return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;
+}
+
+static void video_exit(void)
+{
+ dbg_printk(TPACPI_DBG_EXIT,
+ "restoring original video autoswitch mode\n");
+ if (video_autosw_set(video_orig_autosw))
+ printk(IBM_ERR "error while trying to restore original "
+ "video autoswitch mode\n");
+}
+
+static int video_outputsw_get(void)
+{
+ int status = 0;
+ int i;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",
+ TP_ACPI_VIDEO_570_PHSCMD))
+ return -EIO;
+ status = i & TP_ACPI_VIDEO_570_PHSMASK;
+ break;
+ case TPACPI_VIDEO_770:
+ if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_LCD;
+ if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_CRT;
+ break;
+ case TPACPI_VIDEO_NEW:
+ if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||
+ !acpi_evalf(NULL, &i, "\\VCDC", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_CRT;
+
+ if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||
+ !acpi_evalf(NULL, &i, "\\VCDL", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_LCD;
+ if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))
+ return -EIO;
+ if (i)
+ status |= TP_ACPI_VIDEO_S_DVI;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return status;
+}
+
+static int video_outputsw_set(int status)
+{
+ int autosw;
+ int res = 0;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ res = acpi_evalf(NULL, NULL,
+ "\\_SB.PHS2", "vdd",
+ TP_ACPI_VIDEO_570_PHS2CMD,
+ status | TP_ACPI_VIDEO_570_PHS2SET);
+ break;
+ case TPACPI_VIDEO_770:
+ autosw = video_autosw_get();
+ if (autosw < 0)
+ return autosw;
+
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ res = acpi_evalf(vid_handle, NULL,
+ "ASWT", "vdd", status * 0x100, 0);
+ if (!autosw && video_autosw_set(autosw)) {
+ printk(IBM_ERR "video auto-switch left enabled due to error\n");
+ return -EIO;
+ }
+ break;
+ case TPACPI_VIDEO_NEW:
+ res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&
+ acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return (res)? 0 : -EIO;
+}
+
+static int video_autosw_get(void)
+{
+ int autosw = 0;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))
+ return -EIO;
+ break;
+ case TPACPI_VIDEO_770:
+ case TPACPI_VIDEO_NEW:
+ if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))
+ return -EIO;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return autosw & 1;
+}
+
+static int video_autosw_set(int enable)
+{
+ if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))
+ return -EIO;
+ return 0;
+}
+
+static int video_outputsw_cycle(void)
+{
+ int autosw = video_autosw_get();
+ int res;
+
+ if (autosw < 0)
+ return autosw;
+
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ res = acpi_evalf(ec_handle, NULL, "_Q16", "v");
+ break;
+ case TPACPI_VIDEO_770:
+ case TPACPI_VIDEO_NEW:
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ res = acpi_evalf(vid_handle, NULL, "VSWT", "v");
+ break;
+ default:
+ return -ENOSYS;
+ }
+ if (!autosw && video_autosw_set(autosw)) {
+ printk(IBM_ERR "video auto-switch left enabled due to error\n");
+ return -EIO;
+ }
+
+ return (res)? 0 : -EIO;
+}
+
+static int video_expand_toggle(void)
+{
+ switch (video_supported) {
+ case TPACPI_VIDEO_570:
+ return acpi_evalf(ec_handle, NULL, "_Q17", "v")?
+ 0 : -EIO;
+ case TPACPI_VIDEO_770:
+ return acpi_evalf(vid_handle, NULL, "VEXP", "v")?
+ 0 : -EIO;
+ case TPACPI_VIDEO_NEW:
+ return acpi_evalf(NULL, NULL, "\\VEXP", "v")?
+ 0 : -EIO;
+ default:
+ return -ENOSYS;
+ }
+ /* not reached */
+}
+
+static int video_read(char *p)
+{
+ int status, autosw;
+ int len = 0;
+
+ if (video_supported == TPACPI_VIDEO_NONE) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ return len;
+ }
+
+ status = video_outputsw_get();
+ if (status < 0)
+ return status;
+
+ autosw = video_autosw_get();
+ if (autosw < 0)
+ return autosw;
+
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+ len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+ if (video_supported == TPACPI_VIDEO_NEW)
+ len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+ len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));
+ len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");
+ len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");
+ if (video_supported == TPACPI_VIDEO_NEW)
+ len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");
+ len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");
+ len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+
+ return len;
+}
+
+static int video_write(char *buf)
+{
+ char *cmd;
+ int enable, disable, status;
+ int res;
+
+ if (video_supported == TPACPI_VIDEO_NONE)
+ return -ENODEV;
+
+ enable = 0;
+ disable = 0;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "lcd_enable") == 0) {
+ enable |= TP_ACPI_VIDEO_S_LCD;
+ } else if (strlencmp(cmd, "lcd_disable") == 0) {
+ disable |= TP_ACPI_VIDEO_S_LCD;
+ } else if (strlencmp(cmd, "crt_enable") == 0) {
+ enable |= TP_ACPI_VIDEO_S_CRT;
+ } else if (strlencmp(cmd, "crt_disable") == 0) {
+ disable |= TP_ACPI_VIDEO_S_CRT;
+ } else if (video_supported == TPACPI_VIDEO_NEW &&
+ strlencmp(cmd, "dvi_enable") == 0) {
+ enable |= TP_ACPI_VIDEO_S_DVI;
+ } else if (video_supported == TPACPI_VIDEO_NEW &&
+ strlencmp(cmd, "dvi_disable") == 0) {
+ disable |= TP_ACPI_VIDEO_S_DVI;
+ } else if (strlencmp(cmd, "auto_enable") == 0) {
+ res = video_autosw_set(1);
+ if (res)
+ return res;
+ } else if (strlencmp(cmd, "auto_disable") == 0) {
+ res = video_autosw_set(0);
+ if (res)
+ return res;
+ } else if (strlencmp(cmd, "video_switch") == 0) {
+ res = video_outputsw_cycle();
+ if (res)
+ return res;
+ } else if (strlencmp(cmd, "expand_toggle") == 0) {
+ res = video_expand_toggle();
+ if (res)
+ return res;
+ } else
+ return -EINVAL;
+ }
+
+ if (enable || disable) {
+ status = video_outputsw_get();
+ if (status < 0)
+ return status;
+ res = video_outputsw_set((status & ~disable) | enable);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct video_driver_data = {
+ .name = "video",
+ .read = video_read,
+ .write = video_write,
+ .exit = video_exit,
+};
+
+/*************************************************************************
+ * Light (thinklight) subdriver
+ */
+
+IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
+IBM_HANDLE(ledb, ec, "LEDB"); /* G4x */
+
+static int __init light_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(ledb);
+ IBM_ACPIHANDLE_INIT(lght);
+ IBM_ACPIHANDLE_INIT(cmos);
+
+ /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
+ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
+
+ if (tp_features.light)
+ /* light status not supported on
+ 570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */
+ tp_features.light_status =
+ acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+
+ vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
+ str_supported(tp_features.light));
+
+ return (tp_features.light)? 0 : 1;
+}
+
+static int light_read(char *p)
+{
+ int len = 0;
+ int status = 0;
+
+ if (!tp_features.light) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ } else if (!tp_features.light_status) {
+ len += sprintf(p + len, "status:\t\tunknown\n");
+ len += sprintf(p + len, "commands:\ton, off\n");
+ } else {
+ if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+ return -EIO;
+ len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+ len += sprintf(p + len, "commands:\ton, off\n");
+ }
+
+ return len;
+}
+
+static int light_write(char *buf)
+{
+ int cmos_cmd, lght_cmd;
+ char *cmd;
+ int success;
+
+ if (!tp_features.light)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "on") == 0) {
+ cmos_cmd = 0x0c;
+ lght_cmd = 1;
+ } else if (strlencmp(cmd, "off") == 0) {
+ cmos_cmd = 0x0d;
+ lght_cmd = 0;
+ } else
+ return -EINVAL;
+
+ success = cmos_handle ?
+ acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
+ acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
+ if (!success)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct light_driver_data = {
+ .name = "light",
+ .read = light_read,
+ .write = light_write,
+};
+
+/*************************************************************************
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+
+IBM_HANDLE(dock, root, "\\_SB.GDCK", /* X30, X31, X40 */
+ "\\_SB.PCI0.DOCK", /* 600e/x,770e,770x,A2xm/p,T20-22,X20-21 */
+ "\\_SB.PCI0.PCI1.DOCK", /* all others */
+ "\\_SB.PCI.ISA.SLCE", /* 570 */
+ ); /* A21e,G4x,R30,R31,R32,R40,R40e,R50e */
+
+/* don't list other alternatives as we install a notify handler on the 570 */
+IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
+
+static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
+ {
+ .notify = dock_notify,
+ .handle = &dock_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
+ {
+ .hid = IBM_PCI_HID,
+ .notify = dock_notify,
+ .handle = &pci_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
+};
+
+static struct ibm_struct dock_driver_data[2] = {
+ {
+ .name = "dock",
+ .read = dock_read,
+ .write = dock_write,
+ .acpi = &ibm_dock_acpidriver[0],
+ },
+ {
+ .name = "dock",
+ .acpi = &ibm_dock_acpidriver[1],
+ },
+};
+
+#define dock_docked() (_sta(dock_handle) & 1)
+
+static int __init dock_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(dock);
+
+ vdbg_printk(TPACPI_DBG_INIT, "dock is %s\n",
+ str_supported(dock_handle != NULL));
+
+ return (dock_handle)? 0 : 1;
+}
+
+static int __init dock_init2(struct ibm_init_struct *iibm)
+{
+ int dock2_needed;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing dock subdriver part 2\n");
+
+ if (dock_driver_data[0].flags.acpi_driver_registered &&
+ dock_driver_data[0].flags.acpi_notify_installed) {
+ IBM_ACPIHANDLE_INIT(pci);
+ dock2_needed = (pci_handle != NULL);
+ vdbg_printk(TPACPI_DBG_INIT,
+ "dock PCI handler for the TP 570 is %s\n",
+ str_supported(dock2_needed));
+ } else {
+ vdbg_printk(TPACPI_DBG_INIT,
+ "dock subdriver part 2 not required\n");
+ dock2_needed = 0;
+ }
+
+ return (dock2_needed)? 0 : 1;
+}
+
+static void dock_notify(struct ibm_struct *ibm, u32 event)
+{
+ int docked = dock_docked();
+ int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+
+ if (event == 1 && !pci) /* 570 */
+ acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
+ else if (event == 1 && pci) /* 570 */
+ acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
+ else if (event == 3 && docked)
+ acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
+ else if (event == 3 && !docked)
+ acpi_bus_generate_event(ibm->acpi->device, event, 2); /* undock */
+ else if (event == 0 && docked)
+ acpi_bus_generate_event(ibm->acpi->device, event, 3); /* dock */
+ else {
+ printk(IBM_ERR "unknown dock event %d, status %d\n",
+ event, _sta(dock_handle));
+ acpi_bus_generate_event(ibm->acpi->device, event, 0); /* unknown */
+ }
+}
+
+static int dock_read(char *p)
+{
+ int len = 0;
+ int docked = dock_docked();
+
+ if (!dock_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else if (!docked)
+ len += sprintf(p + len, "status:\t\tundocked\n");
+ else {
+ len += sprintf(p + len, "status:\t\tdocked\n");
+ len += sprintf(p + len, "commands:\tdock, undock\n");
+ }
+
+ return len;
+}
+
+static int dock_write(char *buf)
+{
+ char *cmd;
+
+ if (!dock_docked())
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "undock") == 0) {
+ if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0) ||
+ !acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
+ return -EIO;
+ } else if (strlencmp(cmd, "dock") == 0) {
+ if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+/*************************************************************************
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_HANDLE(bay, root, "\\_SB.PCI.IDE.SECN.MAST", /* 570 */
+ "\\_SB.PCI0.IDE0.IDES.IDSM", /* 600e/x, 770e, 770x */
+ "\\_SB.PCI0.SATA.SCND.MSTR", /* T60, X60, Z60 */
+ "\\_SB.PCI0.IDE0.SCND.MSTR", /* all others */
+ ); /* A21e, R30, R31 */
+IBM_HANDLE(bay_ej, bay, "_EJ3", /* 600e/x, A2xm/p, A3x */
+ "_EJ0", /* all others */
+ ); /* 570,A21e,G4x,R30,R31,R32,R40e,R50e */
+IBM_HANDLE(bay2, root, "\\_SB.PCI0.IDE0.PRIM.SLAV", /* A3x, R32 */
+ "\\_SB.PCI0.IDE0.IDEP.IDPS", /* 600e/x, 770e, 770x */
+ ); /* all others */
+IBM_HANDLE(bay2_ej, bay2, "_EJ3", /* 600e/x, 770e, A3x */
+ "_EJ0", /* 770x */
+ ); /* all others */
+
+static int __init bay_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing bay subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(bay);
+ if (bay_handle)
+ IBM_ACPIHANDLE_INIT(bay_ej);
+ IBM_ACPIHANDLE_INIT(bay2);
+ if (bay2_handle)
+ IBM_ACPIHANDLE_INIT(bay2_ej);
+
+ tp_features.bay_status = bay_handle &&
+ acpi_evalf(bay_handle, NULL, "_STA", "qv");
+ tp_features.bay_status2 = bay2_handle &&
+ acpi_evalf(bay2_handle, NULL, "_STA", "qv");
+
+ tp_features.bay_eject = bay_handle && bay_ej_handle &&
+ (strlencmp(bay_ej_path, "_EJ0") == 0 || experimental);
+ tp_features.bay_eject2 = bay2_handle && bay2_ej_handle &&
+ (strlencmp(bay2_ej_path, "_EJ0") == 0 || experimental);
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "bay 1: status %s, eject %s; bay 2: status %s, eject %s\n",
+ str_supported(tp_features.bay_status),
+ str_supported(tp_features.bay_eject),
+ str_supported(tp_features.bay_status2),
+ str_supported(tp_features.bay_eject2));
+
+ return (tp_features.bay_status || tp_features.bay_eject ||
+ tp_features.bay_status2 || tp_features.bay_eject2)? 0 : 1;
+}
+
+static void bay_notify(struct ibm_struct *ibm, u32 event)
+{
+ acpi_bus_generate_event(ibm->acpi->device, event, 0);
+}
+
+#define bay_occupied(b) (_sta(b##_handle) & 1)
+
+static int bay_read(char *p)
+{
+ int len = 0;
+ int occupied = bay_occupied(bay);
+ int occupied2 = bay_occupied(bay2);
+ int eject, eject2;
+
+ len += sprintf(p + len, "status:\t\t%s\n",
+ tp_features.bay_status ?
+ (occupied ? "occupied" : "unoccupied") :
+ "not supported");
+ if (tp_features.bay_status2)
+ len += sprintf(p + len, "status2:\t%s\n", occupied2 ?
+ "occupied" : "unoccupied");
+
+ eject = tp_features.bay_eject && occupied;
+ eject2 = tp_features.bay_eject2 && occupied2;
+
+ if (eject && eject2)
+ len += sprintf(p + len, "commands:\teject, eject2\n");
+ else if (eject)
+ len += sprintf(p + len, "commands:\teject\n");
+ else if (eject2)
+ len += sprintf(p + len, "commands:\teject2\n");
+
+ return len;
+}
+
+static int bay_write(char *buf)
+{
+ char *cmd;
+
+ if (!tp_features.bay_eject && !tp_features.bay_eject2)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (tp_features.bay_eject && strlencmp(cmd, "eject") == 0) {
+ if (!acpi_evalf(bay_ej_handle, NULL, NULL, "vd", 1))
+ return -EIO;
+ } else if (tp_features.bay_eject2 &&
+ strlencmp(cmd, "eject2") == 0) {
+ if (!acpi_evalf(bay2_ej_handle, NULL, NULL, "vd", 1))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct tp_acpi_drv_struct ibm_bay_acpidriver = {
+ .notify = bay_notify,
+ .handle = &bay_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+};
+
+static struct ibm_struct bay_driver_data = {
+ .name = "bay",
+ .read = bay_read,
+ .write = bay_write,
+ .acpi = &ibm_bay_acpidriver,
+};
+
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+/*************************************************************************
+ * CMOS subdriver
+ */
+
+/* sysfs cmos_command -------------------------------------------------- */
+static ssize_t cmos_command_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long cmos_cmd;
+ int res;
+
+ if (parse_strtoul(buf, 21, &cmos_cmd))
+ return -EINVAL;
+
+ res = issue_thinkpad_cmos_command(cmos_cmd);
+ return (res)? res : count;
+}
+
+static struct device_attribute dev_attr_cmos_command =
+ __ATTR(cmos_command, S_IWUSR, NULL, cmos_command_store);
+
+/* --------------------------------------------------------------------- */
+
+static int __init cmos_init(struct ibm_init_struct *iibm)
+{
+ int res;
+
+ vdbg_printk(TPACPI_DBG_INIT,
+ "initializing cmos commands subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(cmos);
+
+ vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
+ str_supported(cmos_handle != NULL));
+
+ res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+ if (res)
+ return res;
+
+ return (cmos_handle)? 0 : 1;
+}
+
+static void cmos_exit(void)
+{
+ device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
+}
+
+static int cmos_read(char *p)
+{
+ int len = 0;
+
+ /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,
+ R30, R31, T20-22, X20-21 */
+ if (!cmos_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n");
+ }
+
+ return len;
+}
+
+static int cmos_write(char *buf)
+{
+ char *cmd;
+ int cmos_cmd, res;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &cmos_cmd) == 1 &&
+ cmos_cmd >= 0 && cmos_cmd <= 21) {
+ /* cmos_cmd set */
+ } else
+ return -EINVAL;
+
+ res = issue_thinkpad_cmos_command(cmos_cmd);
+ if (res)
+ return res;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct cmos_driver_data = {
+ .name = "cmos",
+ .read = cmos_read,
+ .write = cmos_write,
+ .exit = cmos_exit,
+};
+
+/*************************************************************************
+ * LED subdriver
+ */
+
+static enum led_access_mode led_supported;
+
+IBM_HANDLE(led, ec, "SLED", /* 570 */
+ "SYSL", /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ "LED", /* all others */
+ ); /* R30, R31 */
+
+static int __init led_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(led);
+
+ if (!led_handle)
+ /* led not supported on R30, R31 */
+ led_supported = TPACPI_LED_NONE;
+ else if (strlencmp(led_path, "SLED") == 0)
+ /* 570 */
+ led_supported = TPACPI_LED_570;
+ else if (strlencmp(led_path, "SYSL") == 0)
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ led_supported = TPACPI_LED_OLD;
+ else
+ /* all others */
+ led_supported = TPACPI_LED_NEW;
+
+ vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
+ str_supported(led_supported), led_supported);
+
+ return (led_supported != TPACPI_LED_NONE)? 0 : 1;
+}
+
+#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+
+static int led_read(char *p)
+{
+ int len = 0;
+
+ if (!led_supported) {
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ return len;
+ }
+ len += sprintf(p + len, "status:\t\tsupported\n");
+
+ if (led_supported == TPACPI_LED_570) {
+ /* 570 */
+ int i, status;
+ for (i = 0; i < 8; i++) {
+ if (!acpi_evalf(ec_handle,
+ &status, "GLED", "dd", 1 << i))
+ return -EIO;
+ len += sprintf(p + len, "%d:\t\t%s\n",
+ i, led_status(status));
+ }
+ }
+
+ len += sprintf(p + len, "commands:\t"
+ "<led> on, <led> off, <led> blink (<led> is 0-7)\n");
+
+ return len;
+}
+
+/* off, on, blink */
+static const int led_sled_arg1[] = { 0, 1, 3 };
+static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
+static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
+static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+static int led_write(char *buf)
+{
+ char *cmd;
+ int led, ind, ret;
+
+ if (!led_supported)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 7)
+ return -EINVAL;
+
+ if (strstr(cmd, "off")) {
+ ind = 0;
+ } else if (strstr(cmd, "on")) {
+ ind = 1;
+ } else if (strstr(cmd, "blink")) {
+ ind = 2;
+ } else
+ return -EINVAL;
+
+ if (led_supported == TPACPI_LED_570) {
+ /* 570 */
+ led = 1 << led;
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_sled_arg1[ind]))
+ return -EIO;
+ } else if (led_supported == TPACPI_LED_OLD) {
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+ led = 1 << led;
+ ret = ec_write(TPACPI_LED_EC_HLMS, led);
+ if (ret >= 0)
+ ret =
+ ec_write(TPACPI_LED_EC_HLBL,
+ led * led_exp_hlbl[ind]);
+ if (ret >= 0)
+ ret =
+ ec_write(TPACPI_LED_EC_HLCL,
+ led * led_exp_hlcl[ind]);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* all others */
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_led_arg1[ind]))
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static struct ibm_struct led_driver_data = {
+ .name = "led",
+ .read = led_read,
+ .write = led_write,
+};
+
+/*************************************************************************
+ * Beep subdriver
+ */
+
+IBM_HANDLE(beep, ec, "BEEP"); /* all except R30, R31 */
+
+static int __init beep_init(struct ibm_init_struct *iibm)
+{
+ vdbg_printk(TPACPI_DBG_INIT, "initializing beep subdriver\n");
+
+ IBM_ACPIHANDLE_INIT(beep);
+
+ vdbg_printk(TPACPI_DBG_INIT, "beep is %s\n",
+ str_supported(beep_handle != NULL));
+
+ return (beep_handle)? 0 : 1;
+}
+
+static int beep_read(char *p)
+{
+ int len = 0;
+
+ if (!beep_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n");
+ }
+
+ return len;
+}
+
+static int beep_write(char *buf)
+{
+ char *cmd;
+ int beep_cmd;
+
+ if (!beep_handle)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &beep_cmd) == 1 &&
+ beep_cmd >= 0 && beep_cmd <= 17) {
+ /* beep_cmd set */
+ } else
+ return -EINVAL;
+ if (!acpi_evalf(beep_handle, NULL, NULL, "vdd", beep_cmd, 0))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct beep_driver_data = {
+ .name = "beep",
+ .read = beep_read,
+ .write = beep_write,
+};
+
+/*************************************************************************
+ * Thermal subdriver
+ */
+
+static enum thermal_access_mode thermal_read_mode;
+
+/* sysfs temp##_input -------------------------------------------------- */
+
+static ssize_t thermal_temp_input_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr =
+ to_sensor_dev_attr(attr);
+ int idx = sensor_attr->index;
+ s32 value;
+ int res;
+
+ res = thermal_get_sensor(idx, &value);
+ if (res)
+ return res;
+ if (value == TP_EC_THERMAL_TMP_NA * 1000)
+ return -ENXIO;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+#define THERMAL_SENSOR_ATTR_TEMP(_idxA, _idxB) \
+ SENSOR_ATTR(temp##_idxA##_input, S_IRUGO, thermal_temp_input_show, NULL, _idxB)
+
+static struct sensor_device_attribute sensor_dev_attr_thermal_temp_input[] = {
+ THERMAL_SENSOR_ATTR_TEMP(1, 0),
+ THERMAL_SENSOR_ATTR_TEMP(2, 1),
+ THERMAL_SENSOR_ATTR_TEMP(3, 2),
+ THERMAL_SENSOR_ATTR_TEMP(4, 3),
+ THERMAL_SENSOR_ATTR_TEMP(5, 4),
+ THERMAL_SENSOR_ATTR_TEMP(6, 5),
+ THERMAL_SENSOR_ATTR_TEMP(7, 6),
+ THERMAL_SENSOR_ATTR_TEMP(8, 7),
+ THERMAL_SENSOR_ATTR_TEMP(9, 8),
+ THERMAL_SENSOR_ATTR_TEMP(10, 9),
+ THERMAL_SENSOR_ATTR_TEMP(11, 10),
+ THERMAL_SENSOR_ATTR_TEMP(12, 11),
+ THERMAL_SENSOR_ATTR_TEMP(13, 12),
+ THERMAL_SENSOR_ATTR_TEMP(14, 13),
+ THERMAL_SENSOR_ATTR_TEMP(15, 14),
+ THERMAL_SENSOR_ATTR_TEMP(16, 15),
+};
+
+#define THERMAL_ATTRS(X) \
+ &sensor_dev_attr_thermal_temp_input[X].dev_attr.attr
+
+static struct attribute *thermal_temp_input_attr[] = {
+ THERMAL_ATTRS(8),
+ THERMAL_ATTRS(9),
+ THERMAL_ATTRS(10),
+ THERMAL_ATTRS(11),
+ THERMAL_ATTRS(12),
+ THERMAL_ATTRS(13),
+ THERMAL_ATTRS(14),
+ THERMAL_ATTRS(15),
+ THERMAL_ATTRS(0),
+ THERMAL_ATTRS(1),
+ THERMAL_ATTRS(2),
+ THERMAL_ATTRS(3),
+ THERMAL_ATTRS(4),
+ THERMAL_ATTRS(5),
+ THERMAL_ATTRS(6),
+ THERMAL_ATTRS(7),
+ NULL
+};
+
+static const struct attribute_group thermal_temp_input16_group = {
+ .attrs = thermal_temp_input_attr
+};
+
+static const struct attribute_group thermal_temp_input8_group = {
+ .attrs = &thermal_temp_input_attr[8]
+};
+
+#undef THERMAL_SENSOR_ATTR_TEMP
+#undef THERMAL_ATTRS
+
+/* --------------------------------------------------------------------- */
+
+static int __init thermal_init(struct ibm_init_struct *iibm)
+{
+ u8 t, ta1, ta2;
+ int i;
+ int acpi_tmp7;
+ int res;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
+
+ acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
+
+ if (ibm_thinkpad_ec_found && experimental) {
+ /*
+ * Direct EC access mode: sensors at registers
+ * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
+ * non-implemented, thermal sensors return 0x80 when
+ * not available
+ */
+
+ ta1 = ta2 = 0;
+ for (i = 0; i < 8; i++) {
+ if (acpi_ec_read(TP_EC_THERMAL_TMP0 + i, &t)) {
+ ta1 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ if (acpi_ec_read(TP_EC_THERMAL_TMP8 + i, &t)) {
+ ta2 |= t;
+ } else {
+ ta1 = 0;
+ break;
+ }
+ }
+ if (ta1 == 0) {
+ /* This is sheer paranoia, but we handle it anyway */
+ if (acpi_tmp7) {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "falling back to ACPI TMPx access mode\n");
+ thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "disabling thermal sensors access\n");
+ thermal_read_mode = TPACPI_THERMAL_NONE;
+ }
+ } else {
+ thermal_read_mode =
+ (ta2 != 0) ?
+ TPACPI_THERMAL_TPEC_16 : TPACPI_THERMAL_TPEC_8;
+ }
+ } else if (acpi_tmp7) {
+ if (acpi_evalf(ec_handle, NULL, "UPDT", "qv")) {
+ /* 600e/x, 770e, 770x */
+ thermal_read_mode = TPACPI_THERMAL_ACPI_UPDT;
+ } else {
+ /* Standard ACPI TMPx access, max 8 sensors */
+ thermal_read_mode = TPACPI_THERMAL_ACPI_TMP07;
+ }
+ } else {
+ /* temperatures not supported on 570, G4x, R30, R31, R32 */
+ thermal_read_mode = TPACPI_THERMAL_NONE;
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "thermal is %s, mode %d\n",
+ str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
+ thermal_read_mode);
+
+ switch(thermal_read_mode) {
+ case TPACPI_THERMAL_TPEC_16:
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ if (res)
+ return res;
+ break;
+ case TPACPI_THERMAL_TPEC_8:
+ case TPACPI_THERMAL_ACPI_TMP07:
+ case TPACPI_THERMAL_ACPI_UPDT:
+ res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input8_group);
+ if (res)
+ return res;
+ break;
+ case TPACPI_THERMAL_NONE:
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static void thermal_exit(void)
+{
+ switch(thermal_read_mode) {
+ case TPACPI_THERMAL_TPEC_16:
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ break;
+ case TPACPI_THERMAL_TPEC_8:
+ case TPACPI_THERMAL_ACPI_TMP07:
+ case TPACPI_THERMAL_ACPI_UPDT:
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj,
+ &thermal_temp_input16_group);
+ break;
+ case TPACPI_THERMAL_NONE:
+ default:
+ break;
+ }
+}
+
+/* idx is zero-based */
+static int thermal_get_sensor(int idx, s32 *value)
+{
+ int t;
+ s8 tmp;
+ char tmpi[5];
+
+ t = TP_EC_THERMAL_TMP0;
+
+ switch (thermal_read_mode) {
+#if TPACPI_MAX_THERMAL_SENSORS >= 16
+ case TPACPI_THERMAL_TPEC_16:
+ if (idx >= 8 && idx <= 15) {
+ t = TP_EC_THERMAL_TMP8;
+ idx -= 8;
+ }
+ /* fallthrough */
+#endif
+ case TPACPI_THERMAL_TPEC_8:
+ if (idx <= 7) {
+ if (!acpi_ec_read(t + idx, &tmp))
+ return -EIO;
+ *value = tmp * 1000;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_ACPI_UPDT:
+ if (idx <= 7) {
+ snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+ if (!acpi_evalf(ec_handle, NULL, "UPDT", "v"))
+ return -EIO;
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ *value = (t - 2732) * 100;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_ACPI_TMP07:
+ if (idx <= 7) {
+ snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
+ if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
+ return -EIO;
+ *value = t * 1000;
+ return 0;
+ }
+ break;
+
+ case TPACPI_THERMAL_NONE:
+ default:
+ return -ENOSYS;
+ }
+
+ return -EINVAL;
+}
+
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s)
+{
+ int res, i;
+ int n;
+
+ n = 8;
+ i = 0;
+
+ if (!s)
+ return -EINVAL;
+
+ if (thermal_read_mode == TPACPI_THERMAL_TPEC_16)
+ n = 16;
+
+ for(i = 0 ; i < n; i++) {
+ res = thermal_get_sensor(i, &s->temp[i]);
+ if (res)
+ return res;
+ }
+
+ return n;
+}
+
+static int thermal_read(char *p)
+{
+ int len = 0;
+ int n, i;
+ struct ibm_thermal_sensors_struct t;
+
+ n = thermal_get_sensors(&t);
+ if (unlikely(n < 0))
+ return n;
+
+ len += sprintf(p + len, "temperatures:\t");
+
+ if (n > 0) {
+ for (i = 0; i < (n - 1); i++)
+ len += sprintf(p + len, "%d ", t.temp[i] / 1000);
+ len += sprintf(p + len, "%d\n", t.temp[i] / 1000);
+ } else
+ len += sprintf(p + len, "not supported\n");
+
+ return len;
+}
+
+static struct ibm_struct thermal_driver_data = {
+ .name = "thermal",
+ .read = thermal_read,
+ .exit = thermal_exit,
+};
+
+/*************************************************************************
+ * EC Dump subdriver
+ */
+
+static u8 ecdump_regs[256];
+
+static int ecdump_read(char *p)
+{
+ int len = 0;
+ int i, j;
+ u8 v;
+
+ len += sprintf(p + len, "EC "
+ " +00 +01 +02 +03 +04 +05 +06 +07"
+ " +08 +09 +0a +0b +0c +0d +0e +0f\n");
+ for (i = 0; i < 256; i += 16) {
+ len += sprintf(p + len, "EC 0x%02x:", i);
+ for (j = 0; j < 16; j++) {
+ if (!acpi_ec_read(i + j, &v))
+ break;
+ if (v != ecdump_regs[i + j])
+ len += sprintf(p + len, " *%02x", v);
+ else
+ len += sprintf(p + len, " %02x", v);
+ ecdump_regs[i + j] = v;
+ }
+ len += sprintf(p + len, "\n");
+ if (j != 16)
+ break;
+ }
+
+ /* These are way too dangerous to advertise openly... */
+#if 0
+ len += sprintf(p + len, "commands:\t0x<offset> 0x<value>"
+ " (<offset> is 00-ff, <value> is 00-ff)\n");
+ len += sprintf(p + len, "commands:\t0x<offset> <value> "
+ " (<offset> is 00-ff, <value> is 0-255)\n");
+#endif
+ return len;
+}
+
+static int ecdump_write(char *buf)
+{
+ char *cmd;
+ int i, v;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) {
+ /* i and v set */
+ } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) {
+ /* i and v set */
+ } else
+ return -EINVAL;
+ if (i >= 0 && i < 256 && v >= 0 && v < 256) {
+ if (!acpi_ec_write(i, v))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct ecdump_driver_data = {
+ .name = "ecdump",
+ .read = ecdump_read,
+ .write = ecdump_write,
+ .flags.experimental = 1,
+};
+
+/*************************************************************************
+ * Backlight/brightness subdriver
+ */
+
+static struct backlight_device *ibm_backlight_device = NULL;
+
+static struct backlight_ops ibm_backlight_data = {
+ .get_brightness = brightness_get,
+ .update_status = brightness_update_status,
+};
+
+static int __init brightness_init(struct ibm_init_struct *iibm)
+{
+ int b;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+
+ b = brightness_get(NULL);
+ if (b < 0)
+ return b;
+
+ ibm_backlight_device = backlight_device_register(
+ TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
+ &ibm_backlight_data);
+ if (IS_ERR(ibm_backlight_device)) {
+ printk(IBM_ERR "Could not register backlight device\n");
+ return PTR_ERR(ibm_backlight_device);
+ }
+ vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n");
+
+ ibm_backlight_device->props.max_brightness = 7;
+ ibm_backlight_device->props.brightness = b;
+ backlight_update_status(ibm_backlight_device);
+
+ return 0;
+}
+
+static void brightness_exit(void)
+{
+ if (ibm_backlight_device) {
+ vdbg_printk(TPACPI_DBG_EXIT,
+ "calling backlight_device_unregister()\n");
+ backlight_device_unregister(ibm_backlight_device);
+ ibm_backlight_device = NULL;
+ }
+}
+
+static int brightness_update_status(struct backlight_device *bd)
+{
+ return brightness_set(
+ (bd->props.fb_blank == FB_BLANK_UNBLANK &&
+ bd->props.power == FB_BLANK_UNBLANK) ?
+ bd->props.brightness : 0);
+}
+
+static int brightness_get(struct backlight_device *bd)
+{
+ u8 level;
+ if (!acpi_ec_read(brightness_offset, &level))
+ return -EIO;
+
+ level &= 0x7;
+
+ return level;
+}
+
+static int brightness_set(int value)
+{
+ int cmos_cmd, inc, i;
+ int current_value = brightness_get(NULL);
+
+ value &= 7;
+
+ cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+ inc = value > current_value ? 1 : -1;
+ for (i = current_value; i != value; i += inc) {
+ if (issue_thinkpad_cmos_command(cmos_cmd))
+ return -EIO;
+ if (!acpi_ec_write(brightness_offset, i + inc))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int brightness_read(char *p)
+{
+ int len = 0;
+ int level;
+
+ if ((level = brightness_get(NULL)) < 0) {
+ len += sprintf(p + len, "level:\t\tunreadable\n");
+ } else {
+ len += sprintf(p + len, "level:\t\t%d\n", level & 0x7);
+ len += sprintf(p + len, "commands:\tup, down\n");
+ len += sprintf(p + len, "commands:\tlevel <level>"
+ " (<level> is 0-7)\n");
+ }
+
+ return len;
+}
+
+static int brightness_write(char *buf)
+{
+ int level;
+ int new_level;
+ char *cmd;
+
+ while ((cmd = next_cmd(&buf))) {
+ if ((level = brightness_get(NULL)) < 0)
+ return level;
+ level &= 7;
+
+ if (strlencmp(cmd, "up") == 0) {
+ new_level = level == 7 ? 7 : level + 1;
+ } else if (strlencmp(cmd, "down") == 0) {
+ new_level = level == 0 ? 0 : level - 1;
+ } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+ new_level >= 0 && new_level <= 7) {
+ /* new_level set */
+ } else
+ return -EINVAL;
+
+ brightness_set(new_level);
+ }
+
+ return 0;
+}
+
+static struct ibm_struct brightness_driver_data = {
+ .name = "brightness",
+ .read = brightness_read,
+ .write = brightness_write,
+ .exit = brightness_exit,
+};
+
+/*************************************************************************
+ * Volume subdriver
+ */
+
+static int volume_read(char *p)
+{
+ int len = 0;
+ u8 level;
+
+ if (!acpi_ec_read(volume_offset, &level)) {
+ len += sprintf(p + len, "level:\t\tunreadable\n");
+ } else {
+ len += sprintf(p + len, "level:\t\t%d\n", level & 0xf);
+ len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6));
+ len += sprintf(p + len, "commands:\tup, down, mute\n");
+ len += sprintf(p + len, "commands:\tlevel <level>"
+ " (<level> is 0-15)\n");
+ }
+
+ return len;
+}
+
+static int volume_write(char *buf)
+{
+ int cmos_cmd, inc, i;
+ u8 level, mute;
+ int new_level, new_mute;
+ char *cmd;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (!acpi_ec_read(volume_offset, &level))
+ return -EIO;
+ new_mute = mute = level & 0x40;
+ new_level = level = level & 0xf;
+
+ if (strlencmp(cmd, "up") == 0) {
+ if (mute)
+ new_mute = 0;
+ else
+ new_level = level == 15 ? 15 : level + 1;
+ } else if (strlencmp(cmd, "down") == 0) {
+ if (mute)
+ new_mute = 0;
+ else
+ new_level = level == 0 ? 0 : level - 1;
+ } else if (sscanf(cmd, "level %d", &new_level) == 1 &&
+ new_level >= 0 && new_level <= 15) {
+ /* new_level set */
+ } else if (strlencmp(cmd, "mute") == 0) {
+ new_mute = 0x40;
+ } else
+ return -EINVAL;
+
+ if (new_level != level) { /* mute doesn't change */
+ cmos_cmd = new_level > level ? TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN;
+ inc = new_level > level ? 1 : -1;
+
+ if (mute && (issue_thinkpad_cmos_command(cmos_cmd) ||
+ !acpi_ec_write(volume_offset, level)))
+ return -EIO;
+
+ for (i = level; i != new_level; i += inc)
+ if (issue_thinkpad_cmos_command(cmos_cmd) ||
+ !acpi_ec_write(volume_offset, i + inc))
+ return -EIO;
+
+ if (mute && (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) ||
+ !acpi_ec_write(volume_offset,
+ new_level + mute)))
+ return -EIO;
+ }
+
+ if (new_mute != mute) { /* level doesn't change */
+ cmos_cmd = new_mute ? TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP;
+
+ if (issue_thinkpad_cmos_command(cmos_cmd) ||
+ !acpi_ec_write(volume_offset, level + new_mute))
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static struct ibm_struct volume_driver_data = {
+ .name = "volume",
+ .read = volume_read,
+ .write = volume_write,
+};
+
+/*************************************************************************
+ * Fan subdriver
+ */
+
+/*
+ * FAN ACCESS MODES
+ *
+ * TPACPI_FAN_RD_ACPI_GFAN:
+ * ACPI GFAN method: returns fan level
+ *
+ * see TPACPI_FAN_WR_ACPI_SFAN
+ * EC 0x2f (HFSP) not available if GFAN exists
+ *
+ * TPACPI_FAN_WR_ACPI_SFAN:
+ * ACPI SFAN method: sets fan level, 0 (stop) to 7 (max)
+ *
+ * EC 0x2f (HFSP) might be available *for reading*, but do not use
+ * it for writing.
+ *
+ * TPACPI_FAN_WR_TPEC:
+ * ThinkPad EC register 0x2f (HFSP): fan control loop mode
+ * Supported on almost all ThinkPads
+ *
+ * Fan speed changes of any sort (including those caused by the
+ * disengaged mode) are usually done slowly by the firmware as the
+ * maximum ammount of fan duty cycle change per second seems to be
+ * limited.
+ *
+ * Reading is not available if GFAN exists.
+ * Writing is not available if SFAN exists.
+ *
+ * Bits
+ * 7 automatic mode engaged;
+ * (default operation mode of the ThinkPad)
+ * fan level is ignored in this mode.
+ * 6 full speed mode (takes precedence over bit 7);
+ * not available on all thinkpads. May disable
+ * the tachometer while the fan controller ramps up
+ * the speed (which can take up to a few *minutes*).
+ * Speeds up fan to 100% duty-cycle, which is far above
+ * the standard RPM levels. It is not impossible that
+ * it could cause hardware damage.
+ * 5-3 unused in some models. Extra bits for fan level
+ * in others, but still useless as all values above
+ * 7 map to the same speed as level 7 in these models.
+ * 2-0 fan level (0..7 usually)
+ * 0x00 = stop
+ * 0x07 = max (set when temperatures critical)
+ * Some ThinkPads may have other levels, see
+ * TPACPI_FAN_WR_ACPI_FANS (X31/X40/X41)
+ *
+ * FIRMWARE BUG: on some models, EC 0x2f might not be initialized at
+ * boot. Apparently the EC does not intialize it, so unless ACPI DSDT
+ * does so, its initial value is meaningless (0x07).
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * ----
+ *
+ * ThinkPad EC register 0x84 (LSB), 0x85 (MSB):
+ * Main fan tachometer reading (in RPM)
+ *
+ * This register is present on all ThinkPads with a new-style EC, and
+ * it is known not to be present on the A21m/e, and T22, as there is
+ * something else in offset 0x84 according to the ACPI DSDT. Other
+ * ThinkPads from this same time period (and earlier) probably lack the
+ * tachometer as well.
+ *
+ * Unfortunately a lot of ThinkPads with new-style ECs but whose firwmare
+ * was never fixed by IBM to report the EC firmware version string
+ * probably support the tachometer (like the early X models), so
+ * detecting it is quite hard. We need more data to know for sure.
+ *
+ * FIRMWARE BUG: always read 0x84 first, otherwise incorrect readings
+ * might result.
+ *
+ * FIRMWARE BUG: may go stale while the EC is switching to full speed
+ * mode.
+ *
+ * For firmware bugs, refer to:
+ * http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *
+ * TPACPI_FAN_WR_ACPI_FANS:
+ * ThinkPad X31, X40, X41. Not available in the X60.
+ *
+ * FANS ACPI handle: takes three arguments: low speed, medium speed,
+ * high speed. ACPI DSDT seems to map these three speeds to levels
+ * as follows: STOP LOW LOW MED MED HIGH HIGH HIGH HIGH
+ * (this map is stored on FAN0..FAN8 as "0,1,1,2,2,3,3,3,3")
+ *
+ * The speeds are stored on handles
+ * (FANA:FAN9), (FANC:FANB), (FANE:FAND).
+ *
+ * There are three default speed sets, acessible as handles:
+ * FS1L,FS1M,FS1H; FS2L,FS2M,FS2H; FS3L,FS3M,FS3H
+ *
+ * ACPI DSDT switches which set is in use depending on various
+ * factors.
+ *
+ * TPACPI_FAN_WR_TPEC is also available and should be used to
+ * command the fan. The X31/X40/X41 seems to have 8 fan levels,
+ * but the ACPI tables just mention level 7.
+ */
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+
+static void fan_watchdog_fire(struct work_struct *ignored);
+static int fan_watchdog_maxinterval;
+static DECLARE_DELAYED_WORK(fan_watchdog_task, fan_watchdog_fire);
+
+IBM_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
+IBM_HANDLE(gfan, ec, "GFAN", /* 570 */
+ "\\FSPD", /* 600e/x, 770e, 770x */
+ ); /* all others */
+IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
+ "JFNS", /* 770x-JL */
+ ); /* all others */
+
+/*
+ * SYSFS fan layout: hwmon compatible (device)
+ *
+ * pwm*_enable:
+ * 0: "disengaged" mode
+ * 1: manual mode
+ * 2: native EC "auto" mode (recommended, hardware default)
+ *
+ * pwm*: set speed in manual mode, ignored otherwise.
+ * 0 is level 0; 255 is level 7. Intermediate points done with linear
+ * interpolation.
+ *
+ * fan*_input: tachometer reading, RPM
+ *
+ *
+ * SYSFS fan layout: extensions
+ *
+ * fan_watchdog (driver):
+ * fan watchdog interval in seconds, 0 disables (default), max 120
+ */
+
+/* sysfs fan pwm1_enable ----------------------------------------------- */
+static ssize_t fan_pwm1_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, mode;
+ u8 status;
+
+ res = fan_get_status_safe(&status);
+ if (res)
+ return res;
+
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (status != fan_control_initial_status) {
+ tp_features.fan_ctrl_status_undef = 0;
+ } else {
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ status = TP_EC_FAN_AUTO;
+ }
+ }
+
+ if (status & TP_EC_FAN_FULLSPEED) {
+ mode = 0;
+ } else if (status & TP_EC_FAN_AUTO) {
+ mode = 2;
+ } else
+ mode = 1;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", mode);
+}
+
+static ssize_t fan_pwm1_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+ int res, level;
+
+ if (parse_strtoul(buf, 2, &t))
+ return -EINVAL;
+
+ switch (t) {
+ case 0:
+ level = TP_EC_FAN_FULLSPEED;
+ break;
+ case 1:
+ level = TPACPI_FAN_LAST_LEVEL;
+ break;
+ case 2:
+ level = TP_EC_FAN_AUTO;
+ break;
+ case 3:
+ /* reserved for software-controlled auto mode */
+ return -ENOSYS;
+ default:
+ return -EINVAL;
+ }
+
+ res = fan_set_level_safe(level);
+ if (res == -ENXIO)
+ return -EINVAL;
+ else if (res < 0)
+ return res;
+
+ fan_watchdog_reset();
+
+ return count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1_enable =
+ __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ fan_pwm1_enable_show, fan_pwm1_enable_store);
+
+/* sysfs fan pwm1 ------------------------------------------------------ */
+static ssize_t fan_pwm1_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res;
+ u8 status;
+
+ res = fan_get_status_safe(&status);
+ if (res)
+ return res;
+
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (status != fan_control_initial_status) {
+ tp_features.fan_ctrl_status_undef = 0;
+ } else {
+ status = TP_EC_FAN_AUTO;
+ }
+ }
+
+ if ((status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
+ status = fan_control_desired_level;
+
+ if (status > 7)
+ status = 7;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
+}
+
+static ssize_t fan_pwm1_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long s;
+ int rc;
+ u8 status, newlevel;
+
+ if (parse_strtoul(buf, 255, &s))
+ return -EINVAL;
+
+ /* scale down from 0-255 to 0-7 */
+ newlevel = (s >> 5) & 0x07;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = fan_get_status(&status);
+ if (!rc && (status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+ rc = fan_set_level(newlevel);
+ if (rc == -ENXIO)
+ rc = -EINVAL;
+ else if (!rc) {
+ fan_update_desired_level(newlevel);
+ fan_watchdog_reset();
+ }
+ }
+
+ mutex_unlock(&fan_mutex);
+ return (rc)? rc : count;
+}
+
+static struct device_attribute dev_attr_fan_pwm1 =
+ __ATTR(pwm1, S_IWUSR | S_IRUGO,
+ fan_pwm1_show, fan_pwm1_store);
+
+/* sysfs fan fan1_input ------------------------------------------------ */
+static ssize_t fan_fan1_input_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res;
+ unsigned int speed;
+
+ res = fan_get_speed(&speed);
+ if (res < 0)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", speed);
+}
+
+static struct device_attribute dev_attr_fan_fan1_input =
+ __ATTR(fan1_input, S_IRUGO,
+ fan_fan1_input_show, NULL);
+
+/* sysfs fan fan_watchdog (driver) ------------------------------------- */
+static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
+}
+
+static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ unsigned long t;
+
+ if (parse_strtoul(buf, 120, &t))
+ return -EINVAL;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ fan_watchdog_maxinterval = t;
+ fan_watchdog_reset();
+
+ return count;
+}
+
+static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
+ fan_fan_watchdog_show, fan_fan_watchdog_store);
+
+/* --------------------------------------------------------------------- */
+static struct attribute *fan_attributes[] = {
+ &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
+ &dev_attr_fan_fan1_input.attr,
+ NULL
+};
+
+static const struct attribute_group fan_attr_group = {
+ .attrs = fan_attributes,
+};
+
+static int __init fan_init(struct ibm_init_struct *iibm)
+{
+ int rc;
+
+ vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
+
+ mutex_init(&fan_mutex);
+ fan_status_access_mode = TPACPI_FAN_NONE;
+ fan_control_access_mode = TPACPI_FAN_WR_NONE;
+ fan_control_commands = 0;
+ fan_watchdog_maxinterval = 0;
+ tp_features.fan_ctrl_status_undef = 0;
+ fan_control_desired_level = 7;
+
+ IBM_ACPIHANDLE_INIT(fans);
+ IBM_ACPIHANDLE_INIT(gfan);
+ IBM_ACPIHANDLE_INIT(sfan);
+
+ if (gfan_handle) {
+ /* 570, 600e/x, 770e, 770x */
+ fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
+ } else {
+ /* all other ThinkPads: note that even old-style
+ * ThinkPad ECs supports the fan control register */
+ if (likely(acpi_ec_read(fan_status_offset,
+ &fan_control_initial_status))) {
+ fan_status_access_mode = TPACPI_FAN_RD_TPEC;
+
+ /* In some ThinkPads, neither the EC nor the ACPI
+ * DSDT initialize the fan status, and it ends up
+ * being set to 0x07 when it *could* be either
+ * 0x07 or 0x80.
+ *
+ * Enable for TP-1Y (T43), TP-78 (R51e),
+ * TP-76 (R52), TP-70 (T43, R52), which are known
+ * to be buggy. */
+ if (fan_control_initial_status == 0x07 &&
+ ibm_thinkpad_ec_found &&
+ ((ibm_thinkpad_ec_found[0] == '1' &&
+ ibm_thinkpad_ec_found[1] == 'Y') ||
+ (ibm_thinkpad_ec_found[0] == '7' &&
+ (ibm_thinkpad_ec_found[1] == '6' ||
+ ibm_thinkpad_ec_found[1] == '8' ||
+ ibm_thinkpad_ec_found[1] == '0'))
+ )) {
+ printk(IBM_NOTICE
+ "fan_init: initial fan status is "
+ "unknown, assuming it is in auto "
+ "mode\n");
+ tp_features.fan_ctrl_status_undef = 1;
+ }
+ } else {
+ printk(IBM_ERR
+ "ThinkPad ACPI EC access misbehaving, "
+ "fan status and control unavailable\n");
+ return 1;
+ }
+ }
+
+ if (sfan_handle) {
+ /* 570, 770x-JL */
+ fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
+ } else {
+ if (!gfan_handle) {
+ /* gfan without sfan means no fan control */
+ /* all other models implement TP EC 0x2f control */
+
+ if (fans_handle) {
+ /* X31, X40, X41 */
+ fan_control_access_mode =
+ TPACPI_FAN_WR_ACPI_FANS;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_SPEED |
+ TPACPI_FAN_CMD_LEVEL |
+ TPACPI_FAN_CMD_ENABLE;
+ } else {
+ fan_control_access_mode = TPACPI_FAN_WR_TPEC;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_LEVEL |
+ TPACPI_FAN_CMD_ENABLE;
+ }
+ }
+ }
+
+ vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n",
+ str_supported(fan_status_access_mode != TPACPI_FAN_NONE ||
+ fan_control_access_mode != TPACPI_FAN_WR_NONE),
+ fan_status_access_mode, fan_control_access_mode);
+
+ /* fan control master switch */
+ if (!fan_control_allowed) {
+ fan_control_access_mode = TPACPI_FAN_WR_NONE;
+ fan_control_commands = 0;
+ dbg_printk(TPACPI_DBG_INIT,
+ "fan control features disabled by parameter\n");
+ }
+
+ /* update fan_control_desired_level */
+ if (fan_status_access_mode != TPACPI_FAN_NONE)
+ fan_get_status_safe(NULL);
+
+ if (fan_status_access_mode != TPACPI_FAN_NONE ||
+ fan_control_access_mode != TPACPI_FAN_WR_NONE) {
+ rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
+ &fan_attr_group);
+ if (!(rc < 0))
+ rc = driver_create_file(&tpacpi_pdriver.driver,
+ &driver_attr_fan_watchdog);
+ if (rc < 0)
+ return rc;
+ return 0;
+ } else
+ return 1;
+}
+
+/*
+ * Call with fan_mutex held
+ */
+static void fan_update_desired_level(u8 status)
+{
+ if ((status &
+ (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
+ if (status > 7)
+ fan_control_desired_level = 7;
+ else
+ fan_control_desired_level = status;
+ }
+}
+
+static int fan_get_status(u8 *status)
+{
+ u8 s;
+
+ /* TODO:
+ * Add TPACPI_FAN_RD_ACPI_FANS ? */
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+
+ if (unlikely(!acpi_evalf(gfan_handle, &s, NULL, "d")))
+ return -EIO;
+
+ if (likely(status))
+ *status = s & 0x07;
+
+ break;
+
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
+ return -EIO;
+
+ if (likely(status))
+ *status = s;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int fan_get_status_safe(u8 *status)
+{
+ int rc;
+ u8 s;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+ rc = fan_get_status(&s);
+ if (!rc)
+ fan_update_desired_level(s);
+ mutex_unlock(&fan_mutex);
+
+ if (status)
+ *status = s;
+
+ return rc;
+}
+
+static void fan_exit(void)
+{
+ vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
+
+ /* FIXME: can we really do this unconditionally? */
+ sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
+ driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
+
+ cancel_delayed_work(&fan_watchdog_task);
+ flush_scheduled_work();
+}
+
+static int fan_get_speed(unsigned int *speed)
+{
+ u8 hi, lo;
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if (unlikely(!acpi_ec_read(fan_rpm_offset, &lo) ||
+ !acpi_ec_read(fan_rpm_offset + 1, &hi)))
+ return -EIO;
+
+ if (likely(speed))
+ *speed = (hi << 8) | lo;
+
+ break;
+
+ default:
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void fan_watchdog_fire(struct work_struct *ignored)
+{
+ int rc;
+
+ printk(IBM_NOTICE "fan watchdog: enabling fan\n");
+ rc = fan_set_enable();
+ if (rc < 0) {
+ printk(IBM_ERR "fan watchdog: error %d while enabling fan, "
+ "will try again later...\n", -rc);
+ /* reschedule for later */
+ fan_watchdog_reset();
+ }
+}
+
+static void fan_watchdog_reset(void)
+{
+ static int fan_watchdog_active = 0;
+
+ if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
+ return;
+
+ if (fan_watchdog_active)
+ cancel_delayed_work(&fan_watchdog_task);
+
+ if (fan_watchdog_maxinterval > 0) {
+ fan_watchdog_active = 1;
+ if (!schedule_delayed_work(&fan_watchdog_task,
+ msecs_to_jiffies(fan_watchdog_maxinterval
+ * 1000))) {
+ printk(IBM_ERR "failed to schedule the fan watchdog, "
+ "watchdog will not trigger\n");
+ }
+ } else
+ fan_watchdog_active = 0;
+}
+
+static int fan_set_level(int level)
+{
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ if (level >= 0 && level <= 7) {
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
+ return -EIO;
+ } else
+ return -EINVAL;
+ break;
+
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ if ((level != TP_EC_FAN_AUTO) &&
+ (level != TP_EC_FAN_FULLSPEED) &&
+ ((level < 0) || (level > 7)))
+ return -EINVAL;
+
+ /* safety net should the EC not support AUTO
+ * or FULLSPEED mode bits and just ignore them */
+ if (level & TP_EC_FAN_FULLSPEED)
+ level |= 7; /* safety min speed 7 */
+ else if (level & TP_EC_FAN_FULLSPEED)
+ level |= 4; /* safety min speed 4 */
+
+ if (!acpi_ec_write(fan_status_offset, level))
+ return -EIO;
+ else
+ tp_features.fan_ctrl_status_undef = 0;
+ break;
+
+ default:
+ return -ENXIO;
+ }
+ return 0;
+}
+
+static int fan_set_level_safe(int level)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ if (level == TPACPI_FAN_LAST_LEVEL)
+ level = fan_control_desired_level;
+
+ rc = fan_set_level(level);
+ if (!rc)
+ fan_update_desired_level(level);
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_enable(void)
+{
+ u8 s;
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
+
+ /* Don't go out of emergency fan mode */
+ if (s != 7) {
+ s &= 0x07;
+ s |= TP_EC_FAN_AUTO | 4; /* min fan speed 4 */
+ }
+
+ if (!acpi_ec_write(fan_status_offset, s))
+ rc = -EIO;
+ else {
+ tp_features.fan_ctrl_status_undef = 0;
+ rc = 0;
+ }
+ break;
+
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ rc = fan_get_status(&s);
+ if (rc < 0)
+ break;
+
+ s &= 0x07;
+
+ /* Set fan to at least level 4 */
+ s |= 4;
+
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", s))
+ rc= -EIO;
+ else
+ rc = 0;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_disable(void)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ case TPACPI_FAN_WR_TPEC:
+ if (!acpi_ec_write(fan_status_offset, 0x00))
+ rc = -EIO;
+ else {
+ fan_control_desired_level = 0;
+ tp_features.fan_ctrl_status_undef = 0;
+ }
+ break;
+
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
+ rc = -EIO;
+ else
+ fan_control_desired_level = 0;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_set_speed(int speed)
+{
+ int rc;
+
+ if (!fan_control_allowed)
+ return -EPERM;
+
+ rc = mutex_lock_interruptible(&fan_mutex);
+ if (rc < 0)
+ return rc;
+
+ rc = 0;
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_FANS:
+ if (speed >= 0 && speed <= 65535) {
+ if (!acpi_evalf(fans_handle, NULL, NULL, "vddd",
+ speed, speed, speed))
+ rc = -EIO;
+ } else
+ rc = -EINVAL;
+ break;
+
+ default:
+ rc = -ENXIO;
+ }
+
+ mutex_unlock(&fan_mutex);
+ return rc;
+}
+
+static int fan_read(char *p)
+{
+ int len = 0;
+ int rc;
+ u8 status;
+ unsigned int speed = 0;
+
+ switch (fan_status_access_mode) {
+ case TPACPI_FAN_RD_ACPI_GFAN:
+ /* 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status_safe(&status)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "status:\t\t%s\n"
+ "level:\t\t%d\n",
+ (status != 0) ? "enabled" : "disabled", status);
+ break;
+
+ case TPACPI_FAN_RD_TPEC:
+ /* all except 570, 600e/x, 770e, 770x */
+ if ((rc = fan_get_status_safe(&status)) < 0)
+ return rc;
+
+ if (unlikely(tp_features.fan_ctrl_status_undef)) {
+ if (status != fan_control_initial_status)
+ tp_features.fan_ctrl_status_undef = 0;
+ else
+ /* Return most likely status. In fact, it
+ * might be the only possible status */
+ status = TP_EC_FAN_AUTO;
+ }
+
+ len += sprintf(p + len, "status:\t\t%s\n",
+ (status != 0) ? "enabled" : "disabled");
+
+ if ((rc = fan_get_speed(&speed)) < 0)
+ return rc;
+
+ len += sprintf(p + len, "speed:\t\t%d\n", speed);
+
+ if (status & TP_EC_FAN_FULLSPEED)
+ /* Disengaged mode takes precedence */
+ len += sprintf(p + len, "level:\t\tdisengaged\n");
+ else if (status & TP_EC_FAN_AUTO)
+ len += sprintf(p + len, "level:\t\tauto\n");
+ else
+ len += sprintf(p + len, "level:\t\t%d\n", status);
+ break;
+
+ case TPACPI_FAN_NONE:
+ default:
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ }
+
+ if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) {
+ len += sprintf(p + len, "commands:\tlevel <level>");
+
+ switch (fan_control_access_mode) {
+ case TPACPI_FAN_WR_ACPI_SFAN:
+ len += sprintf(p + len, " (<level> is 0-7)\n");
+ break;
+
+ default:
+ len += sprintf(p + len, " (<level> is 0-7, "
+ "auto, disengaged, full-speed)\n");
+ break;
+ }
+ }
+
+ if (fan_control_commands & TPACPI_FAN_CMD_ENABLE)
+ len += sprintf(p + len, "commands:\tenable, disable\n"
+ "commands:\twatchdog <timeout> (<timeout> is 0 (off), "
+ "1-120 (seconds))\n");
+
+ if (fan_control_commands & TPACPI_FAN_CMD_SPEED)
+ len += sprintf(p + len, "commands:\tspeed <speed>"
+ " (<speed> is 0-65535)\n");
+
+ return len;
+}
+
+static int fan_write_cmd_level(const char *cmd, int *rc)
+{
+ int level;
+
+ if (strlencmp(cmd, "level auto") == 0)
+ level = TP_EC_FAN_AUTO;
+ else if ((strlencmp(cmd, "level disengaged") == 0) |
+ (strlencmp(cmd, "level full-speed") == 0))
+ level = TP_EC_FAN_FULLSPEED;
+ else if (sscanf(cmd, "level %d", &level) != 1)
+ return 0;
+
+ if ((*rc = fan_set_level_safe(level)) == -ENXIO)
+ printk(IBM_ERR "level command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_enable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "enable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_enable()) == -ENXIO)
+ printk(IBM_ERR "enable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_disable(const char *cmd, int *rc)
+{
+ if (strlencmp(cmd, "disable") != 0)
+ return 0;
+
+ if ((*rc = fan_set_disable()) == -ENXIO)
+ printk(IBM_ERR "disable command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_speed(const char *cmd, int *rc)
+{
+ int speed;
+
+ /* TODO:
+ * Support speed <low> <medium> <high> ? */
+
+ if (sscanf(cmd, "speed %d", &speed) != 1)
+ return 0;
+
+ if ((*rc = fan_set_speed(speed)) == -ENXIO)
+ printk(IBM_ERR "speed command accepted for unsupported "
+ "access mode %d", fan_control_access_mode);
+
+ return 1;
+}
+
+static int fan_write_cmd_watchdog(const char *cmd, int *rc)
+{
+ int interval;
+
+ if (sscanf(cmd, "watchdog %d", &interval) != 1)
+ return 0;
+
+ if (interval < 0 || interval > 120)
+ *rc = -EINVAL;
+ else
+ fan_watchdog_maxinterval = interval;
+
+ return 1;
+}
+
+static int fan_write(char *buf)
+{
+ char *cmd;
+ int rc = 0;
+
+ while (!rc && (cmd = next_cmd(&buf))) {
+ if (!((fan_control_commands & TPACPI_FAN_CMD_LEVEL) &&
+ fan_write_cmd_level(cmd, &rc)) &&
+ !((fan_control_commands & TPACPI_FAN_CMD_ENABLE) &&
+ (fan_write_cmd_enable(cmd, &rc) ||
+ fan_write_cmd_disable(cmd, &rc) ||
+ fan_write_cmd_watchdog(cmd, &rc))) &&
+ !((fan_control_commands & TPACPI_FAN_CMD_SPEED) &&
+ fan_write_cmd_speed(cmd, &rc))
+ )
+ rc = -EINVAL;
+ else if (!rc)
+ fan_watchdog_reset();
+ }
+
+ return rc;
+}
+
+static struct ibm_struct fan_driver_data = {
+ .name = "fan",
+ .read = fan_read,
+ .write = fan_write,
+ .exit = fan_exit,
+};
+
+/****************************************************************************
+ ****************************************************************************
+ *
+ * Infrastructure
+ *
+ ****************************************************************************
+ ****************************************************************************/
+
+/* /proc support */
+static struct proc_dir_entry *proc_dir = NULL;
+
+/* Subdriver registry */
+static LIST_HEAD(tpacpi_all_drivers);
+
+
+/*
+ * Module and infrastructure proble, init and exit handling
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+static const char * __init str_supported(int is_supported)
+{
+ static char text_unsupported[] __initdata = "not supported";
+
+ return (is_supported)? &text_unsupported[4] : &text_unsupported[0];
+}
+#endif /* CONFIG_THINKPAD_ACPI_DEBUG */
+
+static int __init ibm_init(struct ibm_init_struct *iibm)
+{
+ int ret;
+ struct ibm_struct *ibm = iibm->data;
+ struct proc_dir_entry *entry;
+
+ BUG_ON(ibm == NULL);
+
+ INIT_LIST_HEAD(&ibm->all_drivers);
+
+ if (ibm->flags.experimental && !experimental)
+ return 0;
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "probing for %s\n", ibm->name);
+
+ if (iibm->init) {
+ ret = iibm->init(iibm);
+ if (ret > 0)
+ return 0; /* probe failed */
+ if (ret)
+ return ret;
+
+ ibm->flags.init_called = 1;
+ }
+
+ if (ibm->acpi) {
+ if (ibm->acpi->hid) {
+ ret = register_tpacpi_subdriver(ibm);
+ if (ret)
+ goto err_out;
+ }
+
+ if (ibm->acpi->notify) {
+ ret = setup_acpi_notify(ibm);
+ if (ret == -ENODEV) {
+ printk(IBM_NOTICE "disabling subdriver %s\n",
+ ibm->name);
+ ret = 0;
+ goto err_out;
+ }
+ if (ret < 0)
+ goto err_out;
+ }
+ }
+
+ dbg_printk(TPACPI_DBG_INIT,
+ "%s installed\n", ibm->name);
+
+ if (ibm->read) {
+ entry = create_proc_entry(ibm->name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ proc_dir);
+ if (!entry) {
+ printk(IBM_ERR "unable to create proc entry %s\n",
+ ibm->name);
+ ret = -ENODEV;
+ goto err_out;
+ }
+ entry->owner = THIS_MODULE;
+ entry->data = ibm;
+ entry->read_proc = &dispatch_procfs_read;
+ if (ibm->write)
+ entry->write_proc = &dispatch_procfs_write;
+ ibm->flags.proc_created = 1;
+ }
+
+ list_add_tail(&ibm->all_drivers, &tpacpi_all_drivers);
+
+ return 0;
+
+err_out:
+ dbg_printk(TPACPI_DBG_INIT,
+ "%s: at error exit path with result %d\n",
+ ibm->name, ret);
+
+ ibm_exit(ibm);
+ return (ret < 0)? ret : 0;
+}
+
+static void ibm_exit(struct ibm_struct *ibm)
+{
+ dbg_printk(TPACPI_DBG_EXIT, "removing %s\n", ibm->name);
+
+ list_del_init(&ibm->all_drivers);
+
+ if (ibm->flags.acpi_notify_installed) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "%s: acpi_remove_notify_handler\n", ibm->name);
+ BUG_ON(!ibm->acpi);
+ acpi_remove_notify_handler(*ibm->acpi->handle,
+ ibm->acpi->type,
+ dispatch_acpi_notify);
+ ibm->flags.acpi_notify_installed = 0;
+ ibm->flags.acpi_notify_installed = 0;
+ }
+
+ if (ibm->flags.proc_created) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "%s: remove_proc_entry\n", ibm->name);
+ remove_proc_entry(ibm->name, proc_dir);
+ ibm->flags.proc_created = 0;
+ }
+
+ if (ibm->flags.acpi_driver_registered) {
+ dbg_printk(TPACPI_DBG_EXIT,
+ "%s: acpi_bus_unregister_driver\n", ibm->name);
+ BUG_ON(!ibm->acpi);
+ acpi_bus_unregister_driver(ibm->acpi->driver);
+ kfree(ibm->acpi->driver);
+ ibm->acpi->driver = NULL;
+ ibm->flags.acpi_driver_registered = 0;
+ }
+
+ if (ibm->flags.init_called && ibm->exit) {
+ ibm->exit();
+ ibm->flags.init_called = 0;
+ }
+
+ dbg_printk(TPACPI_DBG_INIT, "finished removing %s\n", ibm->name);
+}
+
+/* Probing */
+
+static char *ibm_thinkpad_ec_found = NULL;
+
+static char* __init check_dmi_for_ec(void)
+{
+ struct dmi_device *dev = NULL;
+ char ec_fw_string[18];
+
+ /*
+ * ThinkPad T23 or newer, A31 or newer, R50e or newer,
+ * X32 or newer, all Z series; Some models must have an
+ * up-to-date BIOS or they will not be detected.
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ */
+ while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+ if (sscanf(dev->name,
+ "IBM ThinkPad Embedded Controller -[%17c",
+ ec_fw_string) == 1) {
+ ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
+ ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
+ return kstrdup(ec_fw_string, GFP_KERNEL);
+ }
+ }
+ return NULL;
+}
+
+static int __init probe_for_thinkpad(void)
+{
+ int is_thinkpad;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /*
+ * Non-ancient models have better DMI tagging, but very old models
+ * don't.
+ */
+ is_thinkpad = dmi_name_in_vendors("ThinkPad");
+
+ /* ec is required because many other handles are relative to it */
+ IBM_ACPIHANDLE_INIT(ec);
+ if (!ec_handle) {
+ if (is_thinkpad)
+ printk(IBM_ERR
+ "Not yet supported ThinkPad detected!\n");
+ return -ENODEV;
+ }
+
+ /*
+ * Risks a regression on very old machines, but reduces potential
+ * false positives a damn great deal
+ */
+ if (!is_thinkpad)
+ is_thinkpad = dmi_name_in_vendors("IBM");
+
+ if (!is_thinkpad && !force_load)
+ return -ENODEV;
+
+ return 0;
+}
+
+
+/* Module init, exit, parameters */
+
+static struct ibm_init_struct ibms_init[] __initdata = {
+ {
+ .init = thinkpad_acpi_driver_init,
+ .data = &thinkpad_acpi_driver_data,
+ },
+ {
+ .init = hotkey_init,
+ .data = &hotkey_driver_data,
+ },
+ {
+ .init = bluetooth_init,
+ .data = &bluetooth_driver_data,
+ },
+ {
+ .init = wan_init,
+ .data = &wan_driver_data,
+ },
+ {
+ .init = video_init,
+ .data = &video_driver_data,
+ },
+ {
+ .init = light_init,
+ .data = &light_driver_data,
+ },
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+ {
+ .init = dock_init,
+ .data = &dock_driver_data[0],
+ },
+ {
+ .init = dock_init2,
+ .data = &dock_driver_data[1],
+ },
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+ {
+ .init = bay_init,
+ .data = &bay_driver_data,
+ },
+#endif
+ {
+ .init = cmos_init,
+ .data = &cmos_driver_data,
+ },
+ {
+ .init = led_init,
+ .data = &led_driver_data,
+ },
+ {
+ .init = beep_init,
+ .data = &beep_driver_data,
+ },
+ {
+ .init = thermal_init,
+ .data = &thermal_driver_data,
+ },
+ {
+ .data = &ecdump_driver_data,
+ },
+ {
+ .init = brightness_init,
+ .data = &brightness_driver_data,
+ },
+ {
+ .data = &volume_driver_data,
+ },
+ {
+ .init = fan_init,
+ .data = &fan_driver_data,
+ },
+};
+
+static int __init set_ibm_param(const char *val, struct kernel_param *kp)
+{
+ unsigned int i;
+ struct ibm_struct *ibm;
+
+ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+ ibm = ibms_init[i].data;
+ BUG_ON(ibm == NULL);
+
+ if (strcmp(ibm->name, kp->name) == 0 && ibm->write) {
+ if (strlen(val) > sizeof(ibms_init[i].param) - 2)
+ return -ENOSPC;
+ strcpy(ibms_init[i].param, val);
+ strcat(ibms_init[i].param, ",");
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int experimental;
+module_param(experimental, int, 0);
+
+static u32 dbg_level;
+module_param_named(debug, dbg_level, uint, 0);
+
+static int force_load;
+module_param(force_load, int, 0);
+
+static int fan_control_allowed;
+module_param_named(fan_control, fan_control_allowed, int, 0);
+
+#define IBM_PARAM(feature) \
+ module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+
+IBM_PARAM(hotkey);
+IBM_PARAM(bluetooth);
+IBM_PARAM(video);
+IBM_PARAM(light);
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+IBM_PARAM(dock);
+#endif
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+IBM_PARAM(bay);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+IBM_PARAM(cmos);
+IBM_PARAM(led);
+IBM_PARAM(beep);
+IBM_PARAM(ecdump);
+IBM_PARAM(brightness);
+IBM_PARAM(volume);
+IBM_PARAM(fan);
+
+static int __init thinkpad_acpi_module_init(void)
+{
+ int ret, i;
+
+ /* Driver-level probe */
+ ret = probe_for_thinkpad();
+ if (ret)
+ return ret;
+
+ /* Driver initialization */
+ ibm_thinkpad_ec_found = check_dmi_for_ec();
+ IBM_ACPIHANDLE_INIT(ecrd);
+ IBM_ACPIHANDLE_INIT(ecwr);
+
+ proc_dir = proc_mkdir(IBM_PROC_DIR, acpi_root_dir);
+ if (!proc_dir) {
+ printk(IBM_ERR "unable to create proc dir " IBM_PROC_DIR);
+ thinkpad_acpi_module_exit();
+ return -ENODEV;
+ }
+ proc_dir->owner = THIS_MODULE;
+
+ ret = platform_driver_register(&tpacpi_pdriver);
+ if (ret) {
+ printk(IBM_ERR "unable to register platform driver\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
+ if (ret) {
+ printk(IBM_ERR "unable to create sysfs driver attributes\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+
+
+ /* Device initialization */
+ tpacpi_pdev = platform_device_register_simple(IBM_DRVR_NAME, -1,
+ NULL, 0);
+ if (IS_ERR(tpacpi_pdev)) {
+ ret = PTR_ERR(tpacpi_pdev);
+ tpacpi_pdev = NULL;
+ printk(IBM_ERR "unable to register platform device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev);
+ if (IS_ERR(tpacpi_hwmon)) {
+ ret = PTR_ERR(tpacpi_hwmon);
+ tpacpi_hwmon = NULL;
+ printk(IBM_ERR "unable to register hwmon device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
+ ret = ibm_init(&ibms_init[i]);
+ if (ret >= 0 && *ibms_init[i].param)
+ ret = ibms_init[i].data->write(ibms_init[i].param);
+ if (ret < 0) {
+ thinkpad_acpi_module_exit();
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void thinkpad_acpi_module_exit(void)
+{
+ struct ibm_struct *ibm, *itmp;
+
+ list_for_each_entry_safe_reverse(ibm, itmp,
+ &tpacpi_all_drivers,
+ all_drivers) {
+ ibm_exit(ibm);
+ }
+
+ dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+
+ if (tpacpi_hwmon)
+ hwmon_device_unregister(tpacpi_hwmon);
+
+ if (tpacpi_pdev)
+ platform_device_unregister(tpacpi_pdev);
+
+ tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+ platform_driver_unregister(&tpacpi_pdriver);
+
+ if (proc_dir)
+ remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
+
+ kfree(ibm_thinkpad_ec_found);
+}
+
+module_init(thinkpad_acpi_module_init);
+module_exit(thinkpad_acpi_module_exit);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
new file mode 100644
index 00000000000..440145a0261
--- /dev/null
+++ b/drivers/misc/thinkpad_acpi.h
@@ -0,0 +1,572 @@
+/*
+ * thinkpad_acpi.h - ThinkPad ACPI Extras
+ *
+ *
+ * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
+ * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __THINKPAD_ACPI_H__
+#define __THINKPAD_ACPI_H__
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+
+#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/uaccess.h>
+
+#include <linux/dmi.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+
+/****************************************************************************
+ * Main driver
+ */
+
+#define IBM_NAME "thinkpad"
+#define IBM_DESC "ThinkPad ACPI Extras"
+#define IBM_FILE "thinkpad_acpi"
+#define IBM_URL "http://ibm-acpi.sf.net/"
+#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
+
+#define IBM_PROC_DIR "ibm"
+#define IBM_ACPI_EVENT_PREFIX "ibm"
+#define IBM_DRVR_NAME IBM_FILE
+
+#define IBM_LOG IBM_FILE ": "
+#define IBM_ERR KERN_ERR IBM_LOG
+#define IBM_NOTICE KERN_NOTICE IBM_LOG
+#define IBM_INFO KERN_INFO IBM_LOG
+#define IBM_DEBUG KERN_DEBUG IBM_LOG
+
+#define IBM_MAX_ACPI_ARGS 3
+
+/* ThinkPad CMOS commands */
+#define TP_CMOS_VOLUME_DOWN 0
+#define TP_CMOS_VOLUME_UP 1
+#define TP_CMOS_VOLUME_MUTE 2
+#define TP_CMOS_BRIGHTNESS_UP 4
+#define TP_CMOS_BRIGHTNESS_DOWN 5
+
+#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
+
+/* Debugging */
+#define TPACPI_DBG_ALL 0xffff
+#define TPACPI_DBG_ALL 0xffff
+#define TPACPI_DBG_INIT 0x0001
+#define TPACPI_DBG_EXIT 0x0002
+#define dbg_printk(a_dbg_level, format, arg...) \
+ do { if (dbg_level & a_dbg_level) \
+ printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
+#ifdef CONFIG_THINKPAD_ACPI_DEBUG
+#define vdbg_printk(a_dbg_level, format, arg...) \
+ dbg_printk(a_dbg_level, format, ## arg)
+static const char *str_supported(int is_supported);
+#else
+#define vdbg_printk(a_dbg_level, format, arg...)
+#endif
+
+/* ACPI HIDs */
+#define IBM_HKEY_HID "IBM0068"
+#define IBM_PCI_HID "PNP0A03"
+
+/* ACPI helpers */
+static int __must_check acpi_evalf(acpi_handle handle,
+ void *res, char *method, char *fmt, ...);
+static int __must_check acpi_ec_read(int i, u8 * p);
+static int __must_check acpi_ec_write(int i, u8 v);
+static int __must_check _sta(acpi_handle handle);
+
+/* ACPI handles */
+static acpi_handle root_handle; /* root namespace */
+static acpi_handle ec_handle; /* EC */
+static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
+static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
+
+static void drv_acpi_handle_init(char *name,
+ acpi_handle *handle, acpi_handle parent,
+ char **paths, int num_paths, char **path);
+#define IBM_ACPIHANDLE_INIT(object) \
+ drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
+ object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
+
+/* ThinkPad ACPI helpers */
+static int issue_thinkpad_cmos_command(int cmos_cmd);
+
+/* procfs support */
+static struct proc_dir_entry *proc_dir;
+
+/* procfs helpers */
+static int dispatch_procfs_read(char *page, char **start, off_t off,
+ int count, int *eof, void *data);
+static int dispatch_procfs_write(struct file *file,
+ const char __user * userbuf,
+ unsigned long count, void *data);
+static char *next_cmd(char **cmds);
+
+/* sysfs support */
+struct attribute_set {
+ unsigned int members, max_members;
+ struct attribute_group group;
+};
+
+static struct attribute_set *create_attr_set(unsigned int max_members,
+ const char* name);
+#define destroy_attr_set(_set) \
+ kfree(_set);
+static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
+static int add_many_to_attr_set(struct attribute_set* s,
+ struct attribute **attr,
+ unsigned int count);
+#define register_attr_set_with_sysfs(_attr_set, _kobj) \
+ sysfs_create_group(_kobj, &_attr_set->group)
+static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
+
+static int parse_strtoul(const char *buf, unsigned long max,
+ unsigned long *value);
+
+/* Device model */
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct platform_driver tpacpi_pdriver;
+static int tpacpi_create_driver_attributes(struct device_driver *drv);
+static void tpacpi_remove_driver_attributes(struct device_driver *drv);
+
+/* Module */
+static int experimental;
+static u32 dbg_level;
+static int force_load;
+static char *ibm_thinkpad_ec_found;
+
+static char* check_dmi_for_ec(void);
+static int thinkpad_acpi_module_init(void);
+static void thinkpad_acpi_module_exit(void);
+
+
+/****************************************************************************
+ * Subdrivers
+ */
+
+struct ibm_struct;
+
+struct tp_acpi_drv_struct {
+ char *hid;
+ struct acpi_driver *driver;
+
+ void (*notify) (struct ibm_struct *, u32);
+ acpi_handle *handle;
+ u32 type;
+ struct acpi_device *device;
+};
+
+struct ibm_struct {
+ char *name;
+
+ int (*read) (char *);
+ int (*write) (char *);
+ void (*exit) (void);
+
+ struct list_head all_drivers;
+
+ struct tp_acpi_drv_struct *acpi;
+
+ struct {
+ u8 acpi_driver_registered:1;
+ u8 acpi_notify_installed:1;
+ u8 proc_created:1;
+ u8 init_called:1;
+ u8 experimental:1;
+ } flags;
+};
+
+struct ibm_init_struct {
+ char param[32];
+
+ int (*init) (struct ibm_init_struct *);
+ struct ibm_struct *data;
+};
+
+static struct {
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+ u16 bay_status:1;
+ u16 bay_eject:1;
+ u16 bay_status2:1;
+ u16 bay_eject2:1;
+#endif
+ u16 bluetooth:1;
+ u16 hotkey:1;
+ u16 hotkey_mask:1;
+ u16 light:1;
+ u16 light_status:1;
+ u16 wan:1;
+ u16 fan_ctrl_status_undef:1;
+} tp_features;
+
+static struct list_head tpacpi_all_drivers;
+
+static struct ibm_init_struct ibms_init[];
+static int set_ibm_param(const char *val, struct kernel_param *kp);
+static int ibm_init(struct ibm_init_struct *iibm);
+static void ibm_exit(struct ibm_struct *ibm);
+
+
+/*
+ * procfs master subdriver
+ */
+static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
+static int thinkpad_acpi_driver_read(char *p);
+
+
+/*
+ * Bay subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_BAY
+static acpi_handle bay_handle, bay_ej_handle;
+static acpi_handle bay2_handle, bay2_ej_handle;
+
+static int bay_init(struct ibm_init_struct *iibm);
+static void bay_notify(struct ibm_struct *ibm, u32 event);
+static int bay_read(char *p);
+static int bay_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_BAY */
+
+
+/*
+ * Beep subdriver
+ */
+
+static acpi_handle beep_handle;
+
+static int beep_read(char *p);
+static int beep_write(char *buf);
+
+
+/*
+ * Bluetooth subdriver
+ */
+
+#define TPACPI_BLUETH_SYSFS_GROUP "bluetooth"
+
+enum {
+ /* ACPI GBDC/SBDC bits */
+ TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
+ TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
+ TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
+};
+
+static int bluetooth_init(struct ibm_init_struct *iibm);
+static int bluetooth_get_radiosw(void);
+static int bluetooth_set_radiosw(int radio_on);
+static int bluetooth_read(char *p);
+static int bluetooth_write(char *buf);
+
+
+/*
+ * Brightness (backlight) subdriver
+ */
+
+#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+
+static struct backlight_device *ibm_backlight_device;
+static int brightness_offset = 0x31;
+
+static int brightness_init(struct ibm_init_struct *iibm);
+static void brightness_exit(void);
+static int brightness_get(struct backlight_device *bd);
+static int brightness_set(int value);
+static int brightness_update_status(struct backlight_device *bd);
+static int brightness_read(char *p);
+static int brightness_write(char *buf);
+
+
+/*
+ * CMOS subdriver
+ */
+
+static int cmos_read(char *p);
+static int cmos_write(char *buf);
+
+
+/*
+ * Dock subdriver
+ */
+
+#ifdef CONFIG_THINKPAD_ACPI_DOCK
+static acpi_handle pci_handle;
+static acpi_handle dock_handle;
+
+static void dock_notify(struct ibm_struct *ibm, u32 event);
+static int dock_read(char *p);
+static int dock_write(char *buf);
+#endif /* CONFIG_THINKPAD_ACPI_DOCK */
+
+
+/*
+ * EC dump subdriver
+ */
+
+static int ecdump_read(char *p) ;
+static int ecdump_write(char *buf);
+
+
+/*
+ * Fan subdriver
+ */
+
+enum { /* Fan control constants */
+ fan_status_offset = 0x2f, /* EC register 0x2f */
+ fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
+ * 0x84 must be read before 0x85 */
+
+ TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
+ TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
+
+ TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
+};
+
+enum fan_status_access_mode {
+ TPACPI_FAN_NONE = 0, /* No fan status or control */
+ TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
+ TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
+};
+
+enum fan_control_access_mode {
+ TPACPI_FAN_WR_NONE = 0, /* No fan control */
+ TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
+ TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
+ TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
+};
+
+enum fan_control_commands {
+ TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
+ TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
+ TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
+ * and also watchdog cmd */
+};
+
+static int fan_control_allowed;
+
+static enum fan_status_access_mode fan_status_access_mode;
+static enum fan_control_access_mode fan_control_access_mode;
+static enum fan_control_commands fan_control_commands;
+static u8 fan_control_initial_status;
+static u8 fan_control_desired_level;
+static int fan_watchdog_maxinterval;
+
+static struct mutex fan_mutex;
+
+static acpi_handle fans_handle, gfan_handle, sfan_handle;
+
+static int fan_init(struct ibm_init_struct *iibm);
+static void fan_exit(void);
+static int fan_get_status(u8 *status);
+static int fan_get_status_safe(u8 *status);
+static int fan_get_speed(unsigned int *speed);
+static void fan_update_desired_level(u8 status);
+static void fan_watchdog_fire(struct work_struct *ignored);
+static void fan_watchdog_reset(void);
+static int fan_set_level(int level);
+static int fan_set_level_safe(int level);
+static int fan_set_enable(void);
+static int fan_set_disable(void);
+static int fan_set_speed(int speed);
+static int fan_read(char *p);
+static int fan_write(char *buf);
+static int fan_write_cmd_level(const char *cmd, int *rc);
+static int fan_write_cmd_enable(const char *cmd, int *rc);
+static int fan_write_cmd_disable(const char *cmd, int *rc);
+static int fan_write_cmd_speed(const char *cmd, int *rc);
+static int fan_write_cmd_watchdog(const char *cmd, int *rc);
+
+
+/*
+ * Hotkey subdriver
+ */
+
+#define TPACPI_HOTKEY_SYSFS_GROUP "hotkey"
+
+static int hotkey_orig_status;
+static int hotkey_orig_mask;
+
+static struct mutex hotkey_mutex;
+
+static int hotkey_init(struct ibm_init_struct *iibm);
+static void hotkey_exit(void);
+static int hotkey_get(int *status, int *mask);
+static int hotkey_set(int status, int mask);
+static void hotkey_notify(struct ibm_struct *ibm, u32 event);
+static int hotkey_read(char *p);
+static int hotkey_write(char *buf);
+
+
+/*
+ * LED subdriver
+ */
+
+enum led_access_mode {
+ TPACPI_LED_NONE = 0,
+ TPACPI_LED_570, /* 570 */
+ TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
+ TPACPI_LED_NEW, /* all others */
+};
+
+enum { /* For TPACPI_LED_OLD */
+ TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
+ TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
+ TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
+};
+
+static enum led_access_mode led_supported;
+static acpi_handle led_handle;
+
+static int led_init(struct ibm_init_struct *iibm);
+static int led_read(char *p);
+static int led_write(char *buf);
+
+/*
+ * Light (thinklight) subdriver
+ */
+
+static acpi_handle lght_handle, ledb_handle;
+
+static int light_init(struct ibm_init_struct *iibm);
+static int light_read(char *p);
+static int light_write(char *buf);
+
+
+/*
+ * Thermal subdriver
+ */
+
+enum thermal_access_mode {
+ TPACPI_THERMAL_NONE = 0, /* No thermal support */
+ TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
+ TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
+ TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
+ TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
+};
+
+enum { /* TPACPI_THERMAL_TPEC_* */
+ TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
+ TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
+ TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
+};
+
+#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
+struct ibm_thermal_sensors_struct {
+ s32 temp[TPACPI_MAX_THERMAL_SENSORS];
+};
+
+static enum thermal_access_mode thermal_read_mode;
+
+static int thermal_init(struct ibm_init_struct *iibm);
+static int thermal_get_sensor(int idx, s32 *value);
+static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
+static int thermal_read(char *p);
+
+
+/*
+ * Video subdriver
+ */
+
+enum video_access_mode {
+ TPACPI_VIDEO_NONE = 0,
+ TPACPI_VIDEO_570, /* 570 */
+ TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
+ TPACPI_VIDEO_NEW, /* all others */
+};
+
+enum { /* video status flags, based on VIDEO_570 */
+ TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
+ TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
+ TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
+};
+
+enum { /* TPACPI_VIDEO_570 constants */
+ TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
+ TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
+ * video_status_flags */
+ TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
+ TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
+};
+
+static enum video_access_mode video_supported;
+static int video_orig_autosw;
+static acpi_handle vid_handle, vid2_handle;
+
+static int video_init(struct ibm_init_struct *iibm);
+static void video_exit(void);
+static int video_outputsw_get(void);
+static int video_outputsw_set(int status);
+static int video_autosw_get(void);
+static int video_autosw_set(int enable);
+static int video_outputsw_cycle(void);
+static int video_expand_toggle(void);
+static int video_read(char *p);
+static int video_write(char *buf);
+
+
+/*
+ * Volume subdriver
+ */
+
+static int volume_offset = 0x30;
+
+static int volume_read(char *p);
+static int volume_write(char *buf);
+
+
+/*
+ * Wan subdriver
+ */
+
+#define TPACPI_WAN_SYSFS_GROUP "wwan"
+
+enum {
+ /* ACPI GWAN/SWAN bits */
+ TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
+ TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
+ TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
+};
+
+static int wan_init(struct ibm_init_struct *iibm);
+static int wan_get_radiosw(void);
+static int wan_set_radiosw(int radio_on);
+static int wan_read(char *p);
+static int wan_write(char *buf);
+
+
+#endif /* __THINKPAD_ACPI_H */
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index bc60e2fc3c2..c08ad8f823d 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -11,10 +11,20 @@
#include <linux/tifm.h>
#include <linux/dma-mapping.h>
-#include <linux/freezer.h>
#define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8"
+
+#define TIFM_IRQ_ENABLE 0x80000000
+#define TIFM_IRQ_SOCKMASK(x) (x)
+#define TIFM_IRQ_CARDMASK(x) ((x) << 8)
+#define TIFM_IRQ_FIFOMASK(x) ((x) << 16)
+#define TIFM_IRQ_SETALL 0xffffffff
+
+static void tifm_7xx1_dummy_eject(struct tifm_adapter *fm,
+ struct tifm_dev *sock)
+{
+}
static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
{
@@ -22,7 +32,7 @@ static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
spin_lock_irqsave(&fm->lock, flags);
fm->socket_change_set |= 1 << sock->socket_id;
- wake_up_all(&fm->change_set_notify);
+ tifm_queue_work(&fm->media_switcher);
spin_unlock_irqrestore(&fm->lock, flags);
}
@@ -30,8 +40,7 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
{
struct tifm_adapter *fm = dev_id;
struct tifm_dev *sock;
- unsigned int irq_status;
- unsigned int sock_irq_status, cnt;
+ unsigned int irq_status, cnt;
spin_lock(&fm->lock);
irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
@@ -45,12 +54,12 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
for (cnt = 0; cnt < fm->num_sockets; cnt++) {
sock = fm->sockets[cnt];
- sock_irq_status = (irq_status >> cnt)
- & (TIFM_IRQ_FIFOMASK(1)
- | TIFM_IRQ_CARDMASK(1));
-
- if (sock && sock_irq_status)
- sock->signal_irq(sock, sock_irq_status);
+ if (sock) {
+ if ((irq_status >> cnt) & TIFM_IRQ_FIFOMASK(1))
+ sock->data_event(sock);
+ if ((irq_status >> cnt) & TIFM_IRQ_CARDMASK(1))
+ sock->card_event(sock);
+ }
}
fm->socket_change_set |= irq_status
@@ -58,196 +67,163 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
}
writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
- if (!fm->socket_change_set)
+ if (fm->finish_me)
+ complete_all(fm->finish_me);
+ else if (!fm->socket_change_set)
writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
else
- wake_up_all(&fm->change_set_notify);
+ tifm_queue_work(&fm->media_switcher);
spin_unlock(&fm->lock);
return IRQ_HANDLED;
}
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
- int is_x2)
+static unsigned char tifm_7xx1_toggle_sock_power(char __iomem *sock_addr)
{
unsigned int s_state;
int cnt;
writel(0x0e00, sock_addr + SOCK_CONTROL);
- for (cnt = 0; cnt < 100; cnt++) {
+ for (cnt = 16; cnt <= 256; cnt <<= 1) {
if (!(TIFM_SOCK_STATE_POWERED
& readl(sock_addr + SOCK_PRESENT_STATE)))
break;
- msleep(10);
+
+ msleep(cnt);
}
s_state = readl(sock_addr + SOCK_PRESENT_STATE);
if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
- return FM_NULL;
-
- if (is_x2) {
- writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
- } else {
- // SmartMedia cards need extra 40 msec
- if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
- msleep(40);
- writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
- sock_addr + SOCK_CONTROL);
- msleep(10);
- writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
- sock_addr + SOCK_CONTROL);
- }
+ return 0;
+
+ writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
+ sock_addr + SOCK_CONTROL);
- for (cnt = 0; cnt < 100; cnt++) {
+ /* xd needs some extra time before power on */
+ if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7)
+ == TIFM_TYPE_XD)
+ msleep(40);
+
+ writel((s_state & TIFM_CTRL_POWER_MASK) | 0x0c00,
+ sock_addr + SOCK_CONTROL);
+ /* wait for power to stabilize */
+ msleep(20);
+ for (cnt = 16; cnt <= 256; cnt <<= 1) {
if ((TIFM_SOCK_STATE_POWERED
& readl(sock_addr + SOCK_PRESENT_STATE)))
break;
- msleep(10);
+
+ msleep(cnt);
}
- if (!is_x2)
- writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
- sock_addr + SOCK_CONTROL);
+ writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
+ sock_addr + SOCK_CONTROL);
return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
}
+inline static void tifm_7xx1_sock_power_off(char __iomem *sock_addr)
+{
+ writel((~TIFM_CTRL_POWER_MASK) & readl(sock_addr + SOCK_CONTROL),
+ sock_addr + SOCK_CONTROL);
+}
+
inline static char __iomem *
tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
{
return base_addr + ((sock_num + 1) << 10);
}
-static int tifm_7xx1_switch_media(void *data)
+static void tifm_7xx1_switch_media(struct work_struct *work)
{
- struct tifm_adapter *fm = data;
- unsigned long flags;
- tifm_media_id media_id;
- char *card_name = "xx";
- int cnt, rc;
+ struct tifm_adapter *fm = container_of(work, struct tifm_adapter,
+ media_switcher);
struct tifm_dev *sock;
- unsigned int socket_change_set;
-
- while (1) {
- rc = wait_event_interruptible(fm->change_set_notify,
- fm->socket_change_set);
- if (rc == -ERESTARTSYS)
- try_to_freeze();
+ char __iomem *sock_addr;
+ unsigned long flags;
+ unsigned char media_id;
+ unsigned int socket_change_set, cnt;
- spin_lock_irqsave(&fm->lock, flags);
- socket_change_set = fm->socket_change_set;
- fm->socket_change_set = 0;
+ spin_lock_irqsave(&fm->lock, flags);
+ socket_change_set = fm->socket_change_set;
+ fm->socket_change_set = 0;
- dev_dbg(fm->dev, "checking media set %x\n",
- socket_change_set);
+ dev_dbg(fm->cdev.dev, "checking media set %x\n",
+ socket_change_set);
- if (kthread_should_stop())
- socket_change_set = (1 << fm->num_sockets) - 1;
+ if (!socket_change_set) {
spin_unlock_irqrestore(&fm->lock, flags);
+ return;
+ }
- if (!socket_change_set)
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (!(socket_change_set & (1 << cnt)))
continue;
-
- spin_lock_irqsave(&fm->lock, flags);
- for (cnt = 0; cnt < fm->num_sockets; cnt++) {
- if (!(socket_change_set & (1 << cnt)))
- continue;
- sock = fm->sockets[cnt];
- if (sock) {
- printk(KERN_INFO DRIVER_NAME
- ": demand removing card from socket %d\n",
- cnt);
- fm->sockets[cnt] = NULL;
- spin_unlock_irqrestore(&fm->lock, flags);
- device_unregister(&sock->dev);
- spin_lock_irqsave(&fm->lock, flags);
- writel(0x0e00,
- tifm_7xx1_sock_addr(fm->addr, cnt)
- + SOCK_CONTROL);
- }
- if (kthread_should_stop())
- continue;
-
+ sock = fm->sockets[cnt];
+ if (sock) {
+ printk(KERN_INFO
+ "%s : demand removing card from socket %u:%u\n",
+ fm->cdev.class_id, fm->id, cnt);
+ fm->sockets[cnt] = NULL;
+ sock_addr = sock->addr;
spin_unlock_irqrestore(&fm->lock, flags);
- media_id = tifm_7xx1_toggle_sock_power(
- tifm_7xx1_sock_addr(fm->addr, cnt),
- fm->num_sockets == 2);
- if (media_id) {
- sock = tifm_alloc_device(fm);
- if (sock) {
- sock->addr = tifm_7xx1_sock_addr(fm->addr,
- cnt);
- sock->media_id = media_id;
- sock->socket_id = cnt;
- switch (media_id) {
- case 1:
- card_name = "xd";
- break;
- case 2:
- card_name = "ms";
- break;
- case 3:
- card_name = "sd";
- break;
- default:
- tifm_free_device(&sock->dev);
- spin_lock_irqsave(&fm->lock, flags);
- continue;
- }
- snprintf(sock->dev.bus_id, BUS_ID_SIZE,
- "tifm_%s%u:%u", card_name,
- fm->id, cnt);
- printk(KERN_INFO DRIVER_NAME
- ": %s card detected in socket %d\n",
- card_name, cnt);
- if (!device_register(&sock->dev)) {
- spin_lock_irqsave(&fm->lock, flags);
- if (!fm->sockets[cnt]) {
- fm->sockets[cnt] = sock;
- sock = NULL;
- }
- spin_unlock_irqrestore(&fm->lock, flags);
- }
- if (sock)
- tifm_free_device(&sock->dev);
- }
- spin_lock_irqsave(&fm->lock, flags);
- }
+ device_unregister(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ tifm_7xx1_sock_power_off(sock_addr);
+ writel(0x0e00, sock_addr + SOCK_CONTROL);
}
- if (!kthread_should_stop()) {
- writel(TIFM_IRQ_FIFOMASK(socket_change_set)
- | TIFM_IRQ_CARDMASK(socket_change_set),
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_FIFOMASK(socket_change_set)
- | TIFM_IRQ_CARDMASK(socket_change_set),
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_ENABLE,
- fm->addr + FM_SET_INTERRUPT_ENABLE);
- spin_unlock_irqrestore(&fm->lock, flags);
- } else {
- for (cnt = 0; cnt < fm->num_sockets; cnt++) {
- if (fm->sockets[cnt])
- fm->socket_change_set |= 1 << cnt;
- }
- if (!fm->socket_change_set) {
- spin_unlock_irqrestore(&fm->lock, flags);
- return 0;
- } else {
+ spin_unlock_irqrestore(&fm->lock, flags);
+
+ media_id = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, cnt));
+
+ // tifm_alloc_device will check if media_id is valid
+ sock = tifm_alloc_device(fm, cnt, media_id);
+ if (sock) {
+ sock->addr = tifm_7xx1_sock_addr(fm->addr, cnt);
+
+ if (!device_register(&sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = sock;
+ sock = NULL;
+ }
spin_unlock_irqrestore(&fm->lock, flags);
}
+ if (sock)
+ tifm_free_device(&sock->dev);
}
+ spin_lock_irqsave(&fm->lock, flags);
}
- return 0;
+
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+
+ writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+ | TIFM_IRQ_CARDMASK(socket_change_set),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
}
#ifdef CONFIG_PM
static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ int cnt;
+
dev_dbg(&dev->dev, "suspending host\n");
+ for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+ if (fm->sockets[cnt])
+ tifm_7xx1_sock_power_off(fm->sockets[cnt]->addr);
+ }
+
pci_save_state(dev);
pci_enable_wake(dev, pci_choose_state(dev, state), 0);
pci_disable_device(dev);
@@ -258,9 +234,11 @@ static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
static int tifm_7xx1_resume(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
- int cnt, rc;
+ int rc;
+ unsigned int good_sockets = 0, bad_sockets = 0;
unsigned long flags;
- tifm_media_id new_ids[fm->num_sockets];
+ unsigned char new_ids[fm->num_sockets];
+ DECLARE_COMPLETION_ONSTACK(finish_resume);
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
@@ -271,45 +249,49 @@ static int tifm_7xx1_resume(struct pci_dev *dev)
dev_dbg(&dev->dev, "resuming host\n");
- for (cnt = 0; cnt < fm->num_sockets; cnt++)
- new_ids[cnt] = tifm_7xx1_toggle_sock_power(
- tifm_7xx1_sock_addr(fm->addr, cnt),
- fm->num_sockets == 2);
+ for (rc = 0; rc < fm->num_sockets; rc++)
+ new_ids[rc] = tifm_7xx1_toggle_sock_power(
+ tifm_7xx1_sock_addr(fm->addr, rc));
spin_lock_irqsave(&fm->lock, flags);
- fm->socket_change_set = 0;
- for (cnt = 0; cnt < fm->num_sockets; cnt++) {
- if (fm->sockets[cnt]) {
- if (fm->sockets[cnt]->media_id == new_ids[cnt])
- fm->socket_change_set |= 1 << cnt;
-
- fm->sockets[cnt]->media_id = new_ids[cnt];
+ for (rc = 0; rc < fm->num_sockets; rc++) {
+ if (fm->sockets[rc]) {
+ if (fm->sockets[rc]->type == new_ids[rc])
+ good_sockets |= 1 << rc;
+ else
+ bad_sockets |= 1 << rc;
}
}
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE);
- if (!fm->socket_change_set) {
- spin_unlock_irqrestore(&fm->lock, flags);
- return 0;
- } else {
- fm->socket_change_set = 0;
+ dev_dbg(&dev->dev, "change sets on resume: good %x, bad %x\n",
+ good_sockets, bad_sockets);
+
+ fm->socket_change_set = 0;
+ if (good_sockets) {
+ fm->finish_me = &finish_resume;
spin_unlock_irqrestore(&fm->lock, flags);
+ rc = wait_for_completion_timeout(&finish_resume, HZ);
+ dev_dbg(&dev->dev, "wait returned %d\n", rc);
+ writel(TIFM_IRQ_FIFOMASK(good_sockets)
+ | TIFM_IRQ_CARDMASK(good_sockets),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_FIFOMASK(good_sockets)
+ | TIFM_IRQ_CARDMASK(good_sockets),
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->finish_me = NULL;
+ fm->socket_change_set ^= good_sockets & fm->socket_change_set;
}
- wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+ fm->socket_change_set |= bad_sockets;
+ if (fm->socket_change_set)
+ tifm_queue_work(&fm->media_switcher);
- spin_lock_irqsave(&fm->lock, flags);
- writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
- | TIFM_IRQ_CARDMASK(fm->socket_change_set),
- fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
- writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
- | TIFM_IRQ_CARDMASK(fm->socket_change_set),
- fm->addr + FM_SET_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
writel(TIFM_IRQ_ENABLE,
fm->addr + FM_SET_INTERRUPT_ENABLE);
- fm->socket_change_set = 0;
- spin_unlock_irqrestore(&fm->lock, flags);
return 0;
}
@@ -345,20 +327,14 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
pci_intx(dev, 1);
- fm = tifm_alloc_adapter();
+ fm = tifm_alloc_adapter(dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM
+ ? 4 : 2, &dev->dev);
if (!fm) {
rc = -ENOMEM;
goto err_out_int;
}
- fm->dev = &dev->dev;
- fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
- ? 4 : 2;
- fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
- GFP_KERNEL);
- if (!fm->sockets)
- goto err_out_free;
-
+ INIT_WORK(&fm->media_switcher, tifm_7xx1_switch_media);
fm->eject = tifm_7xx1_eject;
pci_set_drvdata(dev, fm);
@@ -367,19 +343,16 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
if (!fm->addr)
goto err_out_free;
- rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm);
+ rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
if (rc)
goto err_out_unmap;
- init_waitqueue_head(&fm->change_set_notify);
- rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
+ rc = tifm_add_adapter(fm);
if (rc)
goto err_out_irq;
- writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE);
- wake_up_process(fm->media_switcher);
return 0;
err_out_irq:
@@ -401,20 +374,18 @@ err_out:
static void tifm_7xx1_remove(struct pci_dev *dev)
{
struct tifm_adapter *fm = pci_get_drvdata(dev);
- unsigned long flags;
+ int cnt;
+ fm->eject = tifm_7xx1_dummy_eject;
writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
mmiowb();
free_irq(dev->irq, fm);
- spin_lock_irqsave(&fm->lock, flags);
- fm->socket_change_set = (1 << fm->num_sockets) - 1;
- spin_unlock_irqrestore(&fm->lock, flags);
-
- kthread_stop(fm->media_switcher);
-
tifm_remove_adapter(fm);
+ for (cnt = 0; cnt < fm->num_sockets; cnt++)
+ tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt));
+
pci_set_drvdata(dev, NULL);
iounmap(fm->addr);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 6b10ebe9d93..d195fb088f4 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -14,71 +14,124 @@
#include <linux/idr.h>
#define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.7"
+#define DRIVER_VERSION "0.8"
+static struct workqueue_struct *workqueue;
static DEFINE_IDR(tifm_adapter_idr);
static DEFINE_SPINLOCK(tifm_adapter_lock);
-static tifm_media_id *tifm_device_match(tifm_media_id *ids,
- struct tifm_dev *dev)
+static const char *tifm_media_type_name(unsigned char type, unsigned char nt)
{
- while (*ids) {
- if (dev->media_id == *ids)
- return ids;
- ids++;
- }
- return NULL;
+ const char *card_type_name[3][3] = {
+ { "SmartMedia/xD", "MemoryStick", "MMC/SD" },
+ { "XD", "MS", "SD"},
+ { "xd", "ms", "sd"}
+ };
+
+ if (nt > 2 || type < 1 || type > 3)
+ return NULL;
+ return card_type_name[nt][type - 1];
}
-static int tifm_match(struct device *dev, struct device_driver *drv)
+static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)
{
- struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- struct tifm_driver *fm_drv;
-
- fm_drv = container_of(drv, struct tifm_driver, driver);
- if (!fm_drv->id_table)
- return -EINVAL;
- if (tifm_device_match(fm_drv->id_table, fm_dev))
+ if (sock->type == id->type)
return 1;
- return -ENODEV;
+ return 0;
+}
+
+static int tifm_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver,
+ driver);
+ struct tifm_device_id *ids = fm_drv->id_table;
+
+ if (ids) {
+ while (ids->type) {
+ if (tifm_dev_match(sock, ids))
+ return 1;
+ ++ids;
+ }
+ }
+ return 0;
}
static int tifm_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
- struct tifm_dev *fm_dev;
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
int i = 0;
int length = 0;
- const char *card_type_name[] = {"INV", "SM", "MS", "SD"};
- if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
- return -ENODEV;
if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
- "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id]))
+ "TIFM_CARD_TYPE=%s",
+ tifm_media_type_name(sock->type, 1)))
return -ENOMEM;
return 0;
}
+static int tifm_device_probe(struct device *dev)
+{
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+ driver);
+ int rc = -ENODEV;
+
+ get_device(dev);
+ if (dev->driver && drv->probe) {
+ rc = drv->probe(sock);
+ if (!rc)
+ return 0;
+ }
+ put_device(dev);
+ return rc;
+}
+
+static void tifm_dummy_event(struct tifm_dev *sock)
+{
+ return;
+}
+
+static int tifm_device_remove(struct device *dev)
+{
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+ driver);
+
+ if (dev->driver && drv->remove) {
+ sock->card_event = tifm_dummy_event;
+ sock->data_event = tifm_dummy_event;
+ drv->remove(sock);
+ sock->dev.driver = NULL;
+ }
+
+ put_device(dev);
+ return 0;
+}
+
#ifdef CONFIG_PM
static int tifm_device_suspend(struct device *dev, pm_message_t state)
{
- struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- struct tifm_driver *drv = fm_dev->drv;
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+ driver);
- if (drv && drv->suspend)
- return drv->suspend(fm_dev, state);
+ if (dev->driver && drv->suspend)
+ return drv->suspend(sock, state);
return 0;
}
static int tifm_device_resume(struct device *dev)
{
- struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- struct tifm_driver *drv = fm_dev->drv;
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
+ driver);
- if (drv && drv->resume)
- return drv->resume(fm_dev);
+ if (dev->driver && drv->resume)
+ return drv->resume(sock);
return 0;
}
@@ -89,19 +142,33 @@ static int tifm_device_resume(struct device *dev)
#endif /* CONFIG_PM */
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ return sprintf(buf, "%x", sock->type);
+}
+
+static struct device_attribute tifm_dev_attrs[] = {
+ __ATTR(type, S_IRUGO, type_show, NULL),
+ __ATTR_NULL
+};
+
static struct bus_type tifm_bus_type = {
- .name = "tifm",
- .match = tifm_match,
- .uevent = tifm_uevent,
- .suspend = tifm_device_suspend,
- .resume = tifm_device_resume
+ .name = "tifm",
+ .dev_attrs = tifm_dev_attrs,
+ .match = tifm_bus_match,
+ .uevent = tifm_uevent,
+ .probe = tifm_device_probe,
+ .remove = tifm_device_remove,
+ .suspend = tifm_device_suspend,
+ .resume = tifm_device_resume
};
static void tifm_free(struct class_device *cdev)
{
struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
- kfree(fm->sockets);
kfree(fm);
}
@@ -110,28 +177,25 @@ static struct class tifm_adapter_class = {
.release = tifm_free
};
-struct tifm_adapter *tifm_alloc_adapter(void)
+struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
+ struct device *dev)
{
struct tifm_adapter *fm;
- fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
+ fm = kzalloc(sizeof(struct tifm_adapter)
+ + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
if (fm) {
fm->cdev.class = &tifm_adapter_class;
- spin_lock_init(&fm->lock);
+ fm->cdev.dev = dev;
class_device_initialize(&fm->cdev);
+ spin_lock_init(&fm->lock);
+ fm->num_sockets = num_sockets;
}
return fm;
}
EXPORT_SYMBOL(tifm_alloc_adapter);
-void tifm_free_adapter(struct tifm_adapter *fm)
-{
- class_device_put(&fm->cdev);
-}
-EXPORT_SYMBOL(tifm_free_adapter);
-
-int tifm_add_adapter(struct tifm_adapter *fm,
- int (*mediathreadfn)(void *data))
+int tifm_add_adapter(struct tifm_adapter *fm)
{
int rc;
@@ -141,59 +205,80 @@ int tifm_add_adapter(struct tifm_adapter *fm,
spin_lock(&tifm_adapter_lock);
rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
spin_unlock(&tifm_adapter_lock);
- if (!rc) {
- snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
- fm->media_switcher = kthread_create(mediathreadfn,
- fm, "tifm/%u", fm->id);
-
- if (!IS_ERR(fm->media_switcher))
- return class_device_add(&fm->cdev);
+ if (rc)
+ return rc;
+ snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
+ rc = class_device_add(&fm->cdev);
+ if (rc) {
spin_lock(&tifm_adapter_lock);
idr_remove(&tifm_adapter_idr, fm->id);
spin_unlock(&tifm_adapter_lock);
- rc = -ENOMEM;
}
+
return rc;
}
EXPORT_SYMBOL(tifm_add_adapter);
void tifm_remove_adapter(struct tifm_adapter *fm)
{
- class_device_del(&fm->cdev);
+ unsigned int cnt;
+
+ flush_workqueue(workqueue);
+ for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
+ if (fm->sockets[cnt])
+ device_unregister(&fm->sockets[cnt]->dev);
+ }
spin_lock(&tifm_adapter_lock);
idr_remove(&tifm_adapter_idr, fm->id);
spin_unlock(&tifm_adapter_lock);
+ class_device_del(&fm->cdev);
}
EXPORT_SYMBOL(tifm_remove_adapter);
-void tifm_free_device(struct device *dev)
+void tifm_free_adapter(struct tifm_adapter *fm)
{
- struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- kfree(fm_dev);
+ class_device_put(&fm->cdev);
}
-EXPORT_SYMBOL(tifm_free_device);
+EXPORT_SYMBOL(tifm_free_adapter);
-static void tifm_dummy_signal_irq(struct tifm_dev *sock,
- unsigned int sock_irq_status)
+void tifm_free_device(struct device *dev)
{
- return;
+ struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
+ kfree(sock);
}
+EXPORT_SYMBOL(tifm_free_device);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
+ unsigned char type)
{
- struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
-
- if (dev) {
- spin_lock_init(&dev->lock);
-
- dev->dev.parent = fm->dev;
- dev->dev.bus = &tifm_bus_type;
- dev->dev.release = tifm_free_device;
- dev->signal_irq = tifm_dummy_signal_irq;
+ struct tifm_dev *sock = NULL;
+
+ if (!tifm_media_type_name(type, 0))
+ return sock;
+
+ sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
+ if (sock) {
+ spin_lock_init(&sock->lock);
+ sock->type = type;
+ sock->socket_id = id;
+ sock->card_event = tifm_dummy_event;
+ sock->data_event = tifm_dummy_event;
+
+ sock->dev.parent = fm->cdev.dev;
+ sock->dev.bus = &tifm_bus_type;
+ sock->dev.dma_mask = fm->cdev.dev->dma_mask;
+ sock->dev.release = tifm_free_device;
+
+ snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+ "tifm_%s%u:%u", tifm_media_type_name(type, 2),
+ fm->id, id);
+ printk(KERN_INFO DRIVER_NAME
+ ": %s card detected in socket %u:%u\n",
+ tifm_media_type_name(type, 0), fm->id, id);
}
- return dev;
+ return sock;
}
EXPORT_SYMBOL(tifm_alloc_device);
@@ -218,54 +303,15 @@ void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
}
EXPORT_SYMBOL(tifm_unmap_sg);
-static int tifm_device_probe(struct device *dev)
-{
- struct tifm_driver *drv;
- struct tifm_dev *fm_dev;
- int rc = 0;
- const tifm_media_id *id;
-
- drv = container_of(dev->driver, struct tifm_driver, driver);
- fm_dev = container_of(dev, struct tifm_dev, dev);
- get_device(dev);
- if (!fm_dev->drv && drv->probe && drv->id_table) {
- rc = -ENODEV;
- id = tifm_device_match(drv->id_table, fm_dev);
- if (id)
- rc = drv->probe(fm_dev);
- if (rc >= 0) {
- rc = 0;
- fm_dev->drv = drv;
- }
- }
- if (rc)
- put_device(dev);
- return rc;
-}
-
-static int tifm_device_remove(struct device *dev)
+void tifm_queue_work(struct work_struct *work)
{
- struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
- struct tifm_driver *drv = fm_dev->drv;
-
- if (drv) {
- fm_dev->signal_irq = tifm_dummy_signal_irq;
- if (drv->remove)
- drv->remove(fm_dev);
- fm_dev->drv = NULL;
- }
-
- put_device(dev);
- return 0;
+ queue_work(workqueue, work);
}
+EXPORT_SYMBOL(tifm_queue_work);
int tifm_register_driver(struct tifm_driver *drv)
{
drv->driver.bus = &tifm_bus_type;
- drv->driver.probe = tifm_device_probe;
- drv->driver.remove = tifm_device_remove;
- drv->driver.suspend = tifm_device_suspend;
- drv->driver.resume = tifm_device_resume;
return driver_register(&drv->driver);
}
@@ -279,13 +325,25 @@ EXPORT_SYMBOL(tifm_unregister_driver);
static int __init tifm_init(void)
{
- int rc = bus_register(&tifm_bus_type);
+ int rc;
- if (!rc) {
- rc = class_register(&tifm_adapter_class);
- if (rc)
- bus_unregister(&tifm_bus_type);
- }
+ workqueue = create_freezeable_workqueue("tifm");
+ if (!workqueue)
+ return -ENOMEM;
+
+ rc = bus_register(&tifm_bus_type);
+
+ if (rc)
+ goto err_out_wq;
+
+ rc = class_register(&tifm_adapter_class);
+ if (!rc)
+ return 0;
+
+ bus_unregister(&tifm_bus_type);
+
+err_out_wq:
+ destroy_workqueue(workqueue);
return rc;
}
@@ -294,6 +352,7 @@ static void __exit tifm_exit(void)
{
class_unregister(&tifm_adapter_class);
bus_unregister(&tifm_bus_type);
+ destroy_workqueue(workqueue);
}
subsys_initcall(tifm_init);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 12af9c71876..45b7d53b949 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -2,10 +2,8 @@
# MMC subsystem configuration
#
-menu "MMC/SD Card support"
-
-config MMC
- tristate "MMC support"
+menuconfig MMC
+ tristate "MMC/SD card support"
help
MMC is the "multi-media card" bus protocol.
@@ -19,110 +17,12 @@ config MMC_DEBUG
This is an option for use by developers; most people should
say N here. This enables MMC core and driver debugging.
-config MMC_BLOCK
- tristate "MMC block device driver"
- depends on MMC && BLOCK
- default y
- help
- Say Y here to enable the MMC block device driver support.
- This provides a block device driver, which you can use to
- mount the filesystem. Almost everyone wishing MMC support
- should say Y or M here.
-
-config MMC_ARMMMCI
- tristate "ARM AMBA Multimedia Card Interface support"
- depends on ARM_AMBA && MMC
- help
- This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
- Interface (PL180 and PL181) support. If you have an ARM(R)
- platform with a Multimedia Card slot, say Y or M here.
-
- If unsure, say N.
-
-config MMC_PXA
- tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
- depends on ARCH_PXA && MMC
- help
- This selects the Intel(R) PXA(R) Multimedia card Interface.
- If you have a PXA(R) platform with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI
- tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)"
- depends on PCI && MMC && EXPERIMENTAL
- help
- This select the generic Secure Digital Host Controller Interface.
- It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
- and Toshiba(R). Most controllers found in laptops are of this type.
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_OMAP
- tristate "TI OMAP Multimedia Card Interface support"
- depends on ARCH_OMAP && MMC
- select TPS65010 if MACH_OMAP_H2
- help
- This selects the TI OMAP Multimedia card Interface.
- If you have an OMAP board with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_WBSD
- tristate "Winbond W83L51xD SD/MMC Card Interface support"
- depends on MMC && ISA_DMA_API
- help
- This selects the Winbond(R) W83L51xD Secure digital and
- Multimedia card Interface.
- If you have a machine with a integrated W83L518D or W83L519D
- SD/MMC card reader, say Y or M here.
+if MMC
- If unsure, say N.
+source "drivers/mmc/core/Kconfig"
-config MMC_AU1X
- tristate "Alchemy AU1XX0 MMC Card Interface support"
- depends on MMC && SOC_AU1200
- help
- This selects the AMD Alchemy(R) Multimedia card interface.
- If you have a Alchemy platform with a MMC slot, say Y or M here.
-
- If unsure, say N.
-
-config MMC_AT91
- tristate "AT91 SD/MMC Card Interface support"
- depends on ARCH_AT91 && MMC
- help
- This selects the AT91 MCI controller.
-
- If unsure, say N.
-
-config MMC_IMX
- tristate "Motorola i.MX Multimedia Card Interface support"
- depends on ARCH_IMX && MMC
- help
- This selects the Motorola i.MX Multimedia card Interface.
- If you have a i.MX platform with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_TIFM_SD
- tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
- depends on MMC && EXPERIMENTAL && PCI
- select TIFM_CORE
- help
- Say Y here if you want to be able to access MMC/SD cards with
- the Texas Instruments(R) Flash Media card reader, found in many
- laptops.
- This option 'selects' (turns on, enables) 'TIFM_CORE', but you
- probably also need appropriate card reader host adapter, such as
- 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
- (TIFM_7XX1)'.
+source "drivers/mmc/card/Kconfig"
- To compile this driver as a module, choose M here: the
- module will be called tifm_sd.
+source "drivers/mmc/host/Kconfig"
-endmenu
+endif # MMC
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 83ffb9326a5..9979f5e9765 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -2,32 +2,11 @@
# Makefile for the kernel mmc device drivers.
#
-#
-# Core
-#
-obj-$(CONFIG_MMC) += mmc_core.o
-
-#
-# Media drivers
-#
-obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
-
-#
-# Host drivers
-#
-obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
-obj-$(CONFIG_MMC_PXA) += pxamci.o
-obj-$(CONFIG_MMC_IMX) += imxmmc.o
-obj-$(CONFIG_MMC_SDHCI) += sdhci.o
-obj-$(CONFIG_MMC_WBSD) += wbsd.o
-obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
-obj-$(CONFIG_MMC_OMAP) += omap.o
-obj-$(CONFIG_MMC_AT91) += at91_mci.o
-obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
-
-mmc_core-y := mmc.o mmc_sysfs.o
-mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
-
ifeq ($(CONFIG_MMC_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
+ EXTRA_CFLAGS += -DDEBUG
endif
+
+obj-$(CONFIG_MMC) += core/
+obj-$(CONFIG_MMC) += card/
+obj-$(CONFIG_MMC) += host/
+
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
new file mode 100644
index 00000000000..9320a8c7323
--- /dev/null
+++ b/drivers/mmc/card/Kconfig
@@ -0,0 +1,16 @@
+#
+# MMC/SD card drivers
+#
+
+comment "MMC/SD Card Drivers"
+
+config MMC_BLOCK
+ tristate "MMC block device driver"
+ depends on BLOCK
+ default y
+ help
+ Say Y here to enable the MMC block device driver support.
+ This provides a block device driver, which you can use to
+ mount the filesystem. Almost everyone wishing MMC support
+ should say Y or M here.
+
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
new file mode 100644
index 00000000000..cf8c939867f
--- /dev/null
+++ b/drivers/mmc/card/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for MMC/SD card drivers
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
+mmc_block-objs := block.o queue.o
+
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/card/block.c
index 86439a0bb27..d24ab234394 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/card/block.c
@@ -2,6 +2,7 @@
* Block driver for media (i.e., flash cards)
*
* Copyright 2002 Hewlett-Packard Company
+ * Copyright 2005-2007 Pierre Ossman
*
* Use consistent with the GNU GPL is permitted,
* provided that this copyright notice is
@@ -31,13 +32,13 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include "mmc_queue.h"
+#include "queue.h"
/*
* max 8 partitions per card
@@ -223,10 +224,9 @@ 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;
+ int ret = 1, sg_pos, data_size;
- if (mmc_card_claim_host(card))
- goto flush_queue;
+ mmc_claim_host(card->host);
do {
struct mmc_command cmd;
@@ -283,6 +283,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.data.sg = mq->sg;
brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
+ if (brq.data.blocks !=
+ (req->nr_sectors >> (md->block_bits - 9))) {
+ data_size = brq.data.blocks * brq.data.blksz;
+ for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) {
+ data_size -= mq->sg[sg_pos].length;
+ if (data_size <= 0) {
+ mq->sg[sg_pos].length += data_size;
+ sg_pos++;
+ break;
+ }
+ }
+ brq.data.sg_len = sg_pos;
+ }
+
mmc_wait_for_req(card->host, &brq.mrq);
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write command\n",
@@ -342,7 +356,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
} while (ret);
- mmc_card_release_host(card);
+ mmc_release_host(card->host);
return 1;
@@ -378,9 +392,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
-flush_queue:
-
- mmc_card_release_host(card);
+ mmc_release_host(card->host);
spin_lock_irq(&md->lock);
while (ret) {
@@ -477,11 +489,20 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
- /*
- * The CSD capacity field is in units of read_blkbits.
- * set_capacity takes units of 512 bytes.
- */
- set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9));
+ if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
+ /*
+ * The EXT_CSD sector count is in number or 512 byte
+ * sectors.
+ */
+ set_capacity(md->disk, card->ext_csd.sectors);
+ } else {
+ /*
+ * The CSD capacity field is in units of read_blkbits.
+ * set_capacity takes units of 512 bytes.
+ */
+ set_capacity(md->disk,
+ card->csd.capacity << (card->csd.read_blkbits - 9));
+ }
return md;
err_putdisk:
@@ -502,12 +523,12 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
if (mmc_card_blockaddr(card))
return 0;
- mmc_card_claim_host(card);
+ mmc_claim_host(card->host);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
- mmc_card_release_host(card);
+ mmc_release_host(card->host);
if (err) {
printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/card/queue.c
index c27e42645cd..2e77963db33 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/card/queue.c
@@ -1,7 +1,8 @@
/*
- * linux/drivers/mmc/mmc_queue.c
+ * linux/drivers/mmc/queue.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
+ * Copyright 2006-2007 Pierre Ossman
*
* 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
@@ -14,7 +15,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
-#include "mmc_queue.h"
+#include "queue.h"
#define MMC_QUEUE_SUSPENDED (1 << 0)
@@ -179,7 +180,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_cleanup_queue(mq->queue);
return ret;
}
-EXPORT_SYMBOL(mmc_init_queue);
void mmc_cleanup_queue(struct mmc_queue *mq)
{
@@ -191,6 +191,9 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
q->queuedata = NULL;
spin_unlock_irqrestore(q->queue_lock, flags);
+ /* Make sure the queue isn't suspended, as that will deadlock */
+ mmc_queue_resume(mq);
+
/* Then terminate our worker thread */
kthread_stop(mq->thread);
@@ -226,7 +229,6 @@ void mmc_queue_suspend(struct mmc_queue *mq)
down(&mq->thread_sem);
}
}
-EXPORT_SYMBOL(mmc_queue_suspend);
/**
* mmc_queue_resume - resume a previously suspended MMC request queue
@@ -247,4 +249,4 @@ void mmc_queue_resume(struct mmc_queue *mq)
spin_unlock_irqrestore(q->queue_lock, flags);
}
}
-EXPORT_SYMBOL(mmc_queue_resume);
+
diff --git a/drivers/mmc/mmc_queue.h b/drivers/mmc/card/queue.h
index c9f139e764f..c9f139e764f 100644
--- a/drivers/mmc/mmc_queue.h
+++ b/drivers/mmc/card/queue.h
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
new file mode 100644
index 00000000000..ab37a6d9d32
--- /dev/null
+++ b/drivers/mmc/core/Kconfig
@@ -0,0 +1,16 @@
+#
+# MMC core configuration
+#
+
+config MMC_UNSAFE_RESUME
+ bool "Allow unsafe resume (DANGEROUS)"
+ help
+ If you say Y here, the MMC layer will assume that all cards
+ stayed in their respective slots during the suspend. The
+ normal behaviour is to remove them at suspend and
+ redetecting them at resume. Breaking this assumption will
+ in most cases result in data corruption.
+
+ This option is usually just for embedded systems which use
+ a MMC/SD card for rootfs. Most people should say N here.
+
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
new file mode 100644
index 00000000000..1075b02ae75
--- /dev/null
+++ b/drivers/mmc/core/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the kernel mmc core.
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_MMC) += mmc_core.o
+mmc_core-y := core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o
+
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
new file mode 100644
index 00000000000..7385acfa1dd
--- /dev/null
+++ b/drivers/mmc/core/core.c
@@ -0,0 +1,729 @@
+/*
+ * linux/drivers/mmc/core/core.c
+ *
+ * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/pagemap.h>
+#include <linux/err.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include "core.h"
+#include "sysfs.h"
+
+#include "mmc_ops.h"
+#include "sd_ops.h"
+
+extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
+
+/**
+ * mmc_request_done - finish processing an MMC request
+ * @host: MMC host which completed request
+ * @mrq: MMC request which request
+ *
+ * MMC drivers should call this function when they have completed
+ * their processing of a request.
+ */
+void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
+{
+ struct mmc_command *cmd = mrq->cmd;
+ int err = cmd->error;
+
+ pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), cmd->opcode, err,
+ mrq->data ? mrq->data->error : 0,
+ mrq->stop ? mrq->stop->error : 0,
+ cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+
+ if (err && cmd->retries) {
+ cmd->retries--;
+ cmd->error = 0;
+ host->ops->request(host, mrq);
+ } else if (mrq->done) {
+ mrq->done(mrq);
+ }
+}
+
+EXPORT_SYMBOL(mmc_request_done);
+
+/**
+ * mmc_start_request - start a command on a host
+ * @host: MMC host to start command on
+ * @mrq: MMC request to start
+ *
+ * Queue a command on the specified host. We expect the
+ * caller to be holding the host lock with interrupts disabled.
+ */
+void
+mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+{
+#ifdef CONFIG_MMC_DEBUG
+ unsigned int i, sz;
+#endif
+
+ pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
+ mmc_hostname(host), mrq->cmd->opcode,
+ mrq->cmd->arg, mrq->cmd->flags);
+
+ WARN_ON(!host->claimed);
+
+ mrq->cmd->error = 0;
+ mrq->cmd->mrq = mrq;
+ if (mrq->data) {
+ BUG_ON(mrq->data->blksz > host->max_blk_size);
+ BUG_ON(mrq->data->blocks > host->max_blk_count);
+ BUG_ON(mrq->data->blocks * mrq->data->blksz >
+ host->max_req_size);
+
+#ifdef CONFIG_MMC_DEBUG
+ sz = 0;
+ for (i = 0;i < mrq->data->sg_len;i++)
+ sz += mrq->data->sg[i].length;
+ BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
+#endif
+
+ mrq->cmd->data = mrq->data;
+ mrq->data->error = 0;
+ mrq->data->mrq = mrq;
+ if (mrq->stop) {
+ mrq->data->stop = mrq->stop;
+ mrq->stop->error = 0;
+ mrq->stop->mrq = mrq;
+ }
+ }
+ host->ops->request(host, mrq);
+}
+
+EXPORT_SYMBOL(mmc_start_request);
+
+static void mmc_wait_done(struct mmc_request *mrq)
+{
+ complete(mrq->done_data);
+}
+
+int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+{
+ DECLARE_COMPLETION_ONSTACK(complete);
+
+ mrq->done_data = &complete;
+ mrq->done = mmc_wait_done;
+
+ mmc_start_request(host, mrq);
+
+ wait_for_completion(&complete);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_req);
+
+/**
+ * mmc_wait_for_cmd - start a command and wait for completion
+ * @host: MMC host to start command
+ * @cmd: MMC command to start
+ * @retries: maximum number of retries
+ *
+ * Start a new MMC command for a host, and wait for the command
+ * to complete. Return any error that occurred while the command
+ * was executing. Do not attempt to parse the response.
+ */
+int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
+{
+ struct mmc_request mrq;
+
+ BUG_ON(!host->claimed);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = retries;
+
+ mrq.cmd = cmd;
+ cmd->data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ return cmd->error;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_cmd);
+
+/**
+ * mmc_set_data_timeout - set the timeout for a data command
+ * @data: data phase for command
+ * @card: the MMC card associated with the data transfer
+ * @write: flag to differentiate reads from writes
+ */
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
+ int write)
+{
+ unsigned int mult;
+
+ /*
+ * SD cards use a 100 multiplier rather than 10
+ */
+ mult = mmc_card_sd(card) ? 100 : 10;
+
+ /*
+ * Scale up the multiplier (and therefore the timeout) by
+ * the r2w factor for writes.
+ */
+ if (write)
+ mult <<= card->csd.r2w_factor;
+
+ data->timeout_ns = card->csd.tacc_ns * mult;
+ data->timeout_clks = card->csd.tacc_clks * mult;
+
+ /*
+ * SD cards also have an upper limit on the timeout.
+ */
+ if (mmc_card_sd(card)) {
+ unsigned int timeout_us, limit_us;
+
+ timeout_us = data->timeout_ns / 1000;
+ timeout_us += data->timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (write)
+ limit_us = 250000;
+ else
+ limit_us = 100000;
+
+ /*
+ * SDHC cards always use these fixed values.
+ */
+ if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
+ data->timeout_ns = limit_us * 1000;
+ data->timeout_clks = 0;
+ }
+ }
+}
+EXPORT_SYMBOL(mmc_set_data_timeout);
+
+/**
+ * __mmc_claim_host - exclusively claim a host
+ * @host: mmc host to claim
+ * @card: mmc card to claim host for
+ *
+ * Claim a host for a set of operations. If a valid card
+ * is passed and this wasn't the last card selected, select
+ * the card before returning.
+ *
+ * Note: you should use mmc_card_claim_host or mmc_claim_host.
+ */
+void mmc_claim_host(struct mmc_host *host)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+
+ add_wait_queue(&host->wq, &wait);
+ spin_lock_irqsave(&host->lock, flags);
+ while (1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if (!host->claimed)
+ break;
+ spin_unlock_irqrestore(&host->lock, flags);
+ schedule();
+ spin_lock_irqsave(&host->lock, flags);
+ }
+ set_current_state(TASK_RUNNING);
+ host->claimed = 1;
+ spin_unlock_irqrestore(&host->lock, flags);
+ remove_wait_queue(&host->wq, &wait);
+}
+
+EXPORT_SYMBOL(mmc_claim_host);
+
+/**
+ * mmc_release_host - release a host
+ * @host: mmc host to release
+ *
+ * Release a MMC host, allowing others to claim the host
+ * for their operations.
+ */
+void mmc_release_host(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ BUG_ON(!host->claimed);
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->claimed = 0;
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ wake_up(&host->wq);
+}
+
+EXPORT_SYMBOL(mmc_release_host);
+
+/*
+ * Internal function that does the actual ios call to the host driver,
+ * optionally printing some debug output.
+ */
+static inline void mmc_set_ios(struct mmc_host *host)
+{
+ struct mmc_ios *ios = &host->ios;
+
+ pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
+ "width %u timing %u\n",
+ mmc_hostname(host), ios->clock, ios->bus_mode,
+ ios->power_mode, ios->chip_select, ios->vdd,
+ ios->bus_width, ios->timing);
+
+ host->ops->set_ios(host, ios);
+}
+
+/*
+ * Control chip select pin on a host.
+ */
+void mmc_set_chip_select(struct mmc_host *host, int mode)
+{
+ host->ios.chip_select = mode;
+ mmc_set_ios(host);
+}
+
+/*
+ * Sets the host clock to the highest possible frequency that
+ * is below "hz".
+ */
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+ WARN_ON(hz < host->f_min);
+
+ if (hz > host->f_max)
+ hz = host->f_max;
+
+ host->ios.clock = hz;
+ mmc_set_ios(host);
+}
+
+/*
+ * Change the bus mode (open drain/push-pull) of a host.
+ */
+void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
+{
+ host->ios.bus_mode = mode;
+ mmc_set_ios(host);
+}
+
+/*
+ * Change data bus width of a host.
+ */
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+{
+ host->ios.bus_width = width;
+ mmc_set_ios(host);
+}
+
+/*
+ * Mask off any voltages we don't support and select
+ * the lowest voltage
+ */
+u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
+{
+ int bit;
+
+ ocr &= host->ocr_avail;
+
+ bit = ffs(ocr);
+ if (bit) {
+ bit -= 1;
+
+ ocr &= 3 << bit;
+
+ host->ios.vdd = bit;
+ mmc_set_ios(host);
+ } else {
+ ocr = 0;
+ }
+
+ return ocr;
+}
+
+/*
+ * Select timing parameters for host.
+ */
+void mmc_set_timing(struct mmc_host *host, unsigned int timing)
+{
+ host->ios.timing = timing;
+ mmc_set_ios(host);
+}
+
+/*
+ * Allocate a new MMC card
+ */
+struct mmc_card *mmc_alloc_card(struct mmc_host *host)
+{
+ struct mmc_card *card;
+
+ card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+ if (!card)
+ return ERR_PTR(-ENOMEM);
+
+ mmc_init_card(card, host);
+
+ return card;
+}
+
+/*
+ * Apply power to the MMC stack. This is a two-stage process.
+ * First, we enable power to the card without the clock running.
+ * We then wait a bit for the power to stabilise. Finally,
+ * enable the bus drivers and clock to the card.
+ *
+ * We must _NOT_ enable the clock prior to power stablising.
+ *
+ * If a host does all the power sequencing itself, ignore the
+ * initial MMC_POWER_UP stage.
+ */
+static void mmc_power_up(struct mmc_host *host)
+{
+ int bit = fls(host->ocr_avail) - 1;
+
+ host->ios.vdd = bit;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.power_mode = MMC_POWER_UP;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+ mmc_set_ios(host);
+
+ mmc_delay(1);
+
+ host->ios.clock = host->f_min;
+ host->ios.power_mode = MMC_POWER_ON;
+ mmc_set_ios(host);
+
+ mmc_delay(2);
+}
+
+static void mmc_power_off(struct mmc_host *host)
+{
+ host->ios.clock = 0;
+ host->ios.vdd = 0;
+ host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.power_mode = MMC_POWER_OFF;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+ mmc_set_ios(host);
+}
+
+/*
+ * Assign a mmc bus handler to a host. Only one bus handler may control a
+ * host at any given time.
+ */
+void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
+{
+ unsigned long flags;
+
+ BUG_ON(!host);
+ BUG_ON(!ops);
+
+ BUG_ON(!host->claimed);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ BUG_ON(host->bus_ops);
+ BUG_ON(host->bus_refs);
+
+ host->bus_ops = ops;
+ host->bus_refs = 1;
+ host->bus_dead = 0;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * Remove the current bus handler from a host. Assumes that there are
+ * no interesting cards left, so the bus is powered down.
+ */
+void mmc_detach_bus(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ BUG_ON(!host);
+
+ BUG_ON(!host->claimed);
+ BUG_ON(!host->bus_ops);
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->bus_dead = 1;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ mmc_power_off(host);
+
+ mmc_bus_put(host);
+}
+
+/*
+ * Cleanup when the last reference to the bus operator is dropped.
+ */
+void __mmc_release_bus(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(host->bus_refs);
+ BUG_ON(!host->bus_dead);
+
+ host->bus_ops = NULL;
+}
+
+/**
+ * mmc_detect_change - process change of state on a MMC socket
+ * @host: host which changed state.
+ * @delay: optional delay to wait before detection (jiffies)
+ *
+ * All we know is that card(s) have been inserted or removed
+ * from the socket(s). We don't know which socket or cards.
+ */
+void mmc_detect_change(struct mmc_host *host, unsigned long delay)
+{
+#ifdef CONFIG_MMC_DEBUG
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
+ BUG_ON(host->removed);
+ spin_unlock_irqrestore(&host->lock, flags);
+#endif
+
+ mmc_schedule_delayed_work(&host->detect, delay);
+}
+
+EXPORT_SYMBOL(mmc_detect_change);
+
+
+static void mmc_rescan(struct work_struct *work)
+{
+ struct mmc_host *host =
+ container_of(work, struct mmc_host, detect.work);
+ u32 ocr;
+ int err;
+
+ mmc_bus_get(host);
+
+ if (host->bus_ops == NULL) {
+ /*
+ * Only we can add a new handler, so it's safe to
+ * release the lock here.
+ */
+ mmc_bus_put(host);
+
+ mmc_claim_host(host);
+
+ mmc_power_up(host);
+ mmc_go_idle(host);
+
+ mmc_send_if_cond(host, host->ocr_avail);
+
+ err = mmc_send_app_op_cond(host, 0, &ocr);
+ if (err == MMC_ERR_NONE) {
+ if (mmc_attach_sd(host, ocr))
+ mmc_power_off(host);
+ } else {
+ /*
+ * If we fail to detect any SD cards then try
+ * searching for MMC cards.
+ */
+ err = mmc_send_op_cond(host, 0, &ocr);
+ if (err == MMC_ERR_NONE) {
+ if (mmc_attach_mmc(host, ocr))
+ mmc_power_off(host);
+ } else {
+ mmc_power_off(host);
+ mmc_release_host(host);
+ }
+ }
+ } else {
+ if (host->bus_ops->detect && !host->bus_dead)
+ host->bus_ops->detect(host);
+
+ mmc_bus_put(host);
+ }
+}
+
+
+/**
+ * mmc_alloc_host - initialise the per-host structure.
+ * @extra: sizeof private data structure
+ * @dev: pointer to host device model structure
+ *
+ * Initialise the per-host structure.
+ */
+struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
+{
+ struct mmc_host *host;
+
+ host = mmc_alloc_host_sysfs(extra, dev);
+ if (host) {
+ spin_lock_init(&host->lock);
+ init_waitqueue_head(&host->wq);
+ INIT_DELAYED_WORK(&host->detect, mmc_rescan);
+
+ /*
+ * By default, hosts do not support SGIO or large requests.
+ * They have to set these according to their abilities.
+ */
+ host->max_hw_segs = 1;
+ host->max_phys_segs = 1;
+ host->max_seg_size = PAGE_CACHE_SIZE;
+
+ host->max_req_size = PAGE_CACHE_SIZE;
+ host->max_blk_size = 512;
+ host->max_blk_count = PAGE_CACHE_SIZE / 512;
+ }
+
+ return host;
+}
+
+EXPORT_SYMBOL(mmc_alloc_host);
+
+/**
+ * mmc_add_host - initialise host hardware
+ * @host: mmc host
+ */
+int mmc_add_host(struct mmc_host *host)
+{
+ int ret;
+
+ ret = mmc_add_host_sysfs(host);
+ if (ret == 0) {
+ mmc_power_off(host);
+ mmc_detect_change(host, 0);
+ }
+
+ return ret;
+}
+
+EXPORT_SYMBOL(mmc_add_host);
+
+/**
+ * mmc_remove_host - remove host hardware
+ * @host: mmc host
+ *
+ * Unregister and remove all cards associated with this host,
+ * and power down the MMC bus.
+ */
+void mmc_remove_host(struct mmc_host *host)
+{
+#ifdef CONFIG_MMC_DEBUG
+ unsigned long flags;
+ spin_lock_irqsave(&host->lock, flags);
+ host->removed = 1;
+ spin_unlock_irqrestore(&host->lock, flags);
+#endif
+
+ mmc_flush_scheduled_work();
+
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+ mmc_bus_put(host);
+
+ BUG_ON(host->card);
+
+ mmc_power_off(host);
+ mmc_remove_host_sysfs(host);
+}
+
+EXPORT_SYMBOL(mmc_remove_host);
+
+/**
+ * mmc_free_host - free the host structure
+ * @host: mmc host
+ *
+ * Free the host once all references to it have been dropped.
+ */
+void mmc_free_host(struct mmc_host *host)
+{
+ mmc_free_host_sysfs(host);
+}
+
+EXPORT_SYMBOL(mmc_free_host);
+
+#ifdef CONFIG_PM
+
+/**
+ * mmc_suspend_host - suspend a host
+ * @host: mmc host
+ * @state: suspend mode (PM_SUSPEND_xxx)
+ */
+int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
+{
+ mmc_flush_scheduled_work();
+
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ if (host->bus_ops->suspend)
+ host->bus_ops->suspend(host);
+ if (!host->bus_ops->resume) {
+ if (host->bus_ops->remove)
+ host->bus_ops->remove(host);
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+ }
+ mmc_bus_put(host);
+
+ mmc_power_off(host);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(mmc_suspend_host);
+
+/**
+ * mmc_resume_host - resume a previously suspended host
+ * @host: mmc host
+ */
+int mmc_resume_host(struct mmc_host *host)
+{
+ mmc_bus_get(host);
+ if (host->bus_ops && !host->bus_dead) {
+ mmc_power_up(host);
+ BUG_ON(!host->bus_ops->resume);
+ host->bus_ops->resume(host);
+ }
+ mmc_bus_put(host);
+
+ /*
+ * We add a slight delay here so that resume can progress
+ * in parallel.
+ */
+ mmc_detect_change(host, 1);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(mmc_resume_host);
+
+#endif
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
new file mode 100644
index 00000000000..177264d090a
--- /dev/null
+++ b/drivers/mmc/core/core.h
@@ -0,0 +1,70 @@
+/*
+ * linux/drivers/mmc/core/core.h
+ *
+ * Copyright (C) 2003 Russell King, All Rights Reserved.
+ * Copyright 2007 Pierre Ossman
+ *
+ * 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.
+ */
+#ifndef _MMC_CORE_CORE_H
+#define _MMC_CORE_CORE_H
+
+#include <linux/delay.h>
+
+#define MMC_CMD_RETRIES 3
+
+struct mmc_bus_ops {
+ void (*remove)(struct mmc_host *);
+ void (*detect)(struct mmc_host *);
+ void (*suspend)(struct mmc_host *);
+ void (*resume)(struct mmc_host *);
+};
+
+void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
+void mmc_detach_bus(struct mmc_host *host);
+
+void __mmc_release_bus(struct mmc_host *host);
+
+static inline void mmc_bus_get(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs++;
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static inline void mmc_bus_put(struct mmc_host *host)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ host->bus_refs--;
+ if ((host->bus_refs == 0) && host->bus_ops)
+ __mmc_release_bus(host);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+void mmc_set_chip_select(struct mmc_host *host, int mode);
+void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
+u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
+void mmc_set_timing(struct mmc_host *host, unsigned int timing);
+
+struct mmc_card *mmc_alloc_card(struct mmc_host *host);
+
+static inline void mmc_delay(unsigned int ms)
+{
+ if (ms < 1000 / HZ) {
+ cond_resched();
+ mdelay(ms);
+ } else {
+ msleep(ms);
+ }
+}
+
+#endif
+
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
new file mode 100644
index 00000000000..42cc2867ed7
--- /dev/null
+++ b/drivers/mmc/core/mmc.c
@@ -0,0 +1,537 @@
+/*
+ * linux/drivers/mmc/mmc.c
+ *
+ * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
+ *
+ * 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/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "sysfs.h"
+#include "mmc_ops.h"
+
+static const unsigned int tran_exp[] = {
+ 10000, 100000, 1000000, 10000000,
+ 0, 0, 0, 0
+};
+
+static const unsigned char tran_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned int tacc_exp[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+#define UNSTUFF_BITS(resp,start,size) \
+ ({ \
+ const int __size = size; \
+ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
+ const int __off = 3 - ((start) / 32); \
+ const int __shft = (start) & 31; \
+ u32 __res; \
+ \
+ __res = resp[__off] >> __shft; \
+ if (__size + __shft > 32) \
+ __res |= resp[__off-1] << ((32 - __shft) % 32); \
+ __res & __mask; \
+ })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static int mmc_decode_cid(struct mmc_card *card)
+{
+ u32 *resp = card->raw_cid;
+
+ /*
+ * The selection of the format here is based upon published
+ * specs from sandisk and from what people have reported.
+ */
+ switch (card->csd.mmca_vsn) {
+ case 0: /* MMC v1.0 - v1.2 */
+ case 1: /* MMC v1.4 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
+ card->cid.month = UNSTUFF_BITS(resp, 12, 4);
+ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ break;
+
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
+ case 4: /* MMC v4 */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
+ card->cid.month = UNSTUFF_BITS(resp, 12, 4);
+ card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
+ break;
+
+ default:
+ printk("%s: card has unknown MMCA version %d\n",
+ mmc_hostname(card->host), card->csd.mmca_vsn);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
+static int mmc_decode_csd(struct mmc_card *card)
+{
+ struct mmc_csd *csd = &card->csd;
+ unsigned int e, m, csd_struct;
+ u32 *resp = card->raw_csd;
+
+ /*
+ * We only understand CSD structure v1.1 and v1.2.
+ * v1.2 has extra information in bits 15, 11 and 10.
+ */
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+ if (csd_struct != 1 && csd_struct != 2) {
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ return -EINVAL;
+ }
+
+ csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+
+ return 0;
+}
+
+/*
+ * Read and decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card)
+{
+ int err;
+ u8 *ext_csd;
+
+ BUG_ON(!card);
+
+ err = MMC_ERR_FAILED;
+
+ if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+ return MMC_ERR_NONE;
+
+ /*
+ * As the ext_csd is so large and mostly unused, we don't store the
+ * raw block in mmc_card.
+ */
+ ext_csd = kmalloc(512, GFP_KERNEL);
+ if (!ext_csd) {
+ printk(KERN_ERR "%s: could not allocate a buffer to "
+ "receive the ext_csd. mmc v4 cards will be "
+ "treated as v3.\n", mmc_hostname(card->host));
+ return MMC_ERR_FAILED;
+ }
+
+ err = mmc_send_ext_csd(card, ext_csd);
+ if (err != MMC_ERR_NONE) {
+ /*
+ * High capacity cards should have this "magic" size
+ * stored in their CSD.
+ */
+ if (card->csd.capacity == (4096 * 512)) {
+ printk(KERN_ERR "%s: unable to read EXT_CSD "
+ "on a possible high capacity card. "
+ "Card will be ignored.\n",
+ mmc_hostname(card->host));
+ } else {
+ printk(KERN_WARNING "%s: unable to read "
+ "EXT_CSD, performance might "
+ "suffer.\n",
+ mmc_hostname(card->host));
+ err = MMC_ERR_NONE;
+ }
+ goto out;
+ }
+
+ card->ext_csd.sectors =
+ ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+ ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+ ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+ ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ if (card->ext_csd.sectors)
+ mmc_card_set_blockaddr(card);
+
+ switch (ext_csd[EXT_CSD_CARD_TYPE]) {
+ case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 52000000;
+ break;
+ case EXT_CSD_CARD_TYPE_26:
+ card->ext_csd.hs_max_dtr = 26000000;
+ break;
+ default:
+ /* MMC v4 spec says this cannot happen */
+ printk(KERN_WARNING "%s: card is mmc v4 but doesn't "
+ "support any high-speed modes.\n",
+ mmc_hostname(card->host));
+ goto out;
+ }
+
+out:
+ kfree(ext_csd);
+
+ return err;
+}
+
+/*
+ * Handle the detection and initialisation of a card.
+ *
+ * In the case of a resume, "curcard" will contain the card
+ * we're trying to reinitialise.
+ */
+static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+ struct mmc_card *oldcard)
+{
+ struct mmc_card *card;
+ int err;
+ u32 cid[4];
+ unsigned int max_dtr;
+
+ BUG_ON(!host);
+ BUG_ON(!host->claimed);
+
+ /*
+ * Since we're changing the OCR value, we seem to
+ * need to tell some cards to go back to the idle
+ * state. We wait 1ms to give cards time to
+ * respond.
+ */
+ mmc_go_idle(host);
+
+ /* The extra bit indicates that we support high capacity */
+ err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ /*
+ * Fetch CID from card.
+ */
+ err = mmc_all_send_cid(host, cid);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ if (oldcard) {
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ goto err;
+
+ card = oldcard;
+ } else {
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host);
+ if (IS_ERR(card))
+ goto err;
+
+ card->type = MMC_TYPE_MMC;
+ card->rca = 1;
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ }
+
+ /*
+ * Set card RCA.
+ */
+ err = mmc_set_relative_addr(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+
+ if (!oldcard) {
+ /*
+ * Fetch CSD from card.
+ */
+ err = mmc_send_csd(card, card->raw_csd);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ err = mmc_decode_csd(card);
+ if (err < 0)
+ goto free_card;
+ err = mmc_decode_cid(card);
+ if (err < 0)
+ goto free_card;
+ }
+
+ /*
+ * Select card, as all following commands rely on that.
+ */
+ err = mmc_select_card(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ if (!oldcard) {
+ /*
+ * Fetch and process extened CSD.
+ */
+ err = mmc_read_ext_csd(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+ }
+
+ /*
+ * Activate high speed (if supported)
+ */
+ if ((card->ext_csd.hs_max_dtr != 0) &&
+ (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, 1);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_card_set_highspeed(card);
+
+ mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+ }
+
+ /*
+ * Compute bus speed.
+ */
+ max_dtr = (unsigned int)-1;
+
+ if (mmc_card_highspeed(card)) {
+ if (max_dtr > card->ext_csd.hs_max_dtr)
+ max_dtr = card->ext_csd.hs_max_dtr;
+ } else if (max_dtr > card->csd.max_dtr) {
+ max_dtr = card->csd.max_dtr;
+ }
+
+ mmc_set_clock(host, max_dtr);
+
+ /*
+ * Activate wide bus (if supported).
+ */
+ if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+ (host->caps & MMC_CAP_4_BIT_DATA)) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+ }
+
+ if (!oldcard)
+ host->card = card;
+
+ return MMC_ERR_NONE;
+
+free_card:
+ if (!oldcard)
+ mmc_remove_card(card);
+err:
+
+ return MMC_ERR_FAILED;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_remove(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_detect(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ /*
+ * Just check if our card has been removed.
+ */
+ err = mmc_send_status(host->card, NULL);
+
+ mmc_release_host(host);
+
+ if (err != MMC_ERR_NONE) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+}
+
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+
+/*
+ * Suspend callback from host.
+ */
+static void mmc_suspend(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+ mmc_deselect_cards(host);
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
+ mmc_release_host(host);
+}
+
+/*
+ * Resume callback from host.
+ *
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+static void mmc_resume(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ err = mmc_sd_init_card(host, host->ocr, host->card);
+ if (err != MMC_ERR_NONE) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+
+ mmc_detach_bus(host);
+ }
+
+ mmc_release_host(host);
+}
+
+#else
+
+#define mmc_suspend NULL
+#define mmc_resume NULL
+
+#endif
+
+static const struct mmc_bus_ops mmc_ops = {
+ .remove = mmc_remove,
+ .detect = mmc_detect,
+ .suspend = mmc_suspend,
+ .resume = mmc_resume,
+};
+
+/*
+ * Starting point for MMC card init.
+ */
+int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->claimed);
+
+ mmc_attach_bus(host, &mmc_ops);
+
+ /*
+ * Sanity check the voltages that the card claims to
+ * support.
+ */
+ if (ocr & 0x7F) {
+ printk(KERN_WARNING "%s: card claims to support voltages "
+ "below the defined range. These will be ignored.\n",
+ mmc_hostname(host));
+ ocr &= ~0x7F;
+ }
+
+ host->ocr = mmc_select_voltage(host, ocr);
+
+ /*
+ * Can we support the voltage of the card?
+ */
+ if (!host->ocr)
+ goto err;
+
+ /*
+ * Detect and init the card.
+ */
+ err = mmc_sd_init_card(host, host->ocr, NULL);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ mmc_release_host(host);
+
+ err = mmc_register_card(host->card);
+ if (err)
+ goto reclaim_host;
+
+ return 0;
+
+reclaim_host:
+ mmc_claim_host(host);
+ mmc_remove_card(host->card);
+ host->card = NULL;
+err:
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ return 0;
+}
+
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
new file mode 100644
index 00000000000..7dd720fa589
--- /dev/null
+++ b/drivers/mmc/core/mmc_ops.c
@@ -0,0 +1,276 @@
+/*
+ * linux/drivers/mmc/mmc_ops.h
+ *
+ * Copyright 2006-2007 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
+ * your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "mmc_ops.h"
+
+static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SELECT_CARD;
+
+ if (card) {
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ } else {
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
+ }
+
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_select_card(struct mmc_card *card)
+{
+ BUG_ON(!card);
+
+ return _mmc_select_card(card->host, card);
+}
+
+int mmc_deselect_cards(struct mmc_host *host)
+{
+ return _mmc_select_card(host, NULL);
+}
+
+int mmc_go_idle(struct mmc_host *host)
+{
+ int err;
+ struct mmc_command cmd;
+
+ mmc_set_chip_select(host, MMC_CS_HIGH);
+
+ mmc_delay(1);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_GO_IDLE_STATE;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+
+ mmc_delay(1);
+
+ mmc_set_chip_select(host, MMC_CS_DONTCARE);
+
+ mmc_delay(1);
+
+ return err;
+}
+
+int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ BUG_ON(!host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err != MMC_ERR_NONE)
+ break;
+
+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ break;
+
+ err = MMC_ERR_TIMEOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[0];
+
+ return err;
+}
+
+int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!host);
+ BUG_ON(!cid);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_ALL_SEND_CID;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ memcpy(cid, cmd.resp, sizeof(u32) * 4);
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_set_relative_addr(struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SET_RELATIVE_ADDR;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+ BUG_ON(!csd);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_CSD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ memcpy(csd, cmd.resp, sizeof(u32) * 4);
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+ BUG_ON(!ext_csd);
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = MMC_SEND_EXT_CSD;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 512;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, ext_csd, 512);
+
+ mmc_set_data_timeout(&data, card, 0);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error != MMC_ERR_NONE)
+ return cmd.error;
+ if (data.error != MMC_ERR_NONE)
+ return data.error;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SWITCH;
+ cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
+ (index << 16) |
+ (value << 8) |
+ set;
+ cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_send_status(struct mmc_card *card, u32 *status)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ if (status)
+ *status = cmd.resp[0];
+
+ return MMC_ERR_NONE;
+}
+
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
new file mode 100644
index 00000000000..7a481e8ca5e
--- /dev/null
+++ b/drivers/mmc/core/mmc_ops.h
@@ -0,0 +1,27 @@
+/*
+ * linux/drivers/mmc/mmc_ops.h
+ *
+ * Copyright 2006-2007 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
+ * your option) any later version.
+ */
+
+#ifndef _MMC_MMC_OPS_H
+#define _MMC_MMC_OPS_H
+
+int mmc_select_card(struct mmc_card *card);
+int mmc_deselect_cards(struct mmc_host *host);
+int mmc_go_idle(struct mmc_host *host);
+int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_set_relative_addr(struct mmc_card *card);
+int mmc_send_csd(struct mmc_card *card, u32 *csd);
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
+int mmc_send_status(struct mmc_card *card, u32 *status);
+
+#endif
+
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
new file mode 100644
index 00000000000..c1dfd03d559
--- /dev/null
+++ b/drivers/mmc/core/sd.c
@@ -0,0 +1,587 @@
+/*
+ * linux/drivers/mmc/sd.c
+ *
+ * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
+ * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *
+ * 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/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+
+#include "core.h"
+#include "sysfs.h"
+#include "mmc_ops.h"
+#include "sd_ops.h"
+
+#include "core.h"
+
+static const unsigned int tran_exp[] = {
+ 10000, 100000, 1000000, 10000000,
+ 0, 0, 0, 0
+};
+
+static const unsigned char tran_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+static const unsigned int tacc_exp[] = {
+ 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+};
+
+static const unsigned int tacc_mant[] = {
+ 0, 10, 12, 13, 15, 20, 25, 30,
+ 35, 40, 45, 50, 55, 60, 70, 80,
+};
+
+#define UNSTUFF_BITS(resp,start,size) \
+ ({ \
+ const int __size = size; \
+ const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
+ const int __off = 3 - ((start) / 32); \
+ const int __shft = (start) & 31; \
+ u32 __res; \
+ \
+ __res = resp[__off] >> __shft; \
+ if (__size + __shft > 32) \
+ __res |= resp[__off-1] << ((32 - __shft) % 32); \
+ __res & __mask; \
+ })
+
+/*
+ * Given the decoded CSD structure, decode the raw CID to our CID structure.
+ */
+static void mmc_decode_cid(struct mmc_card *card)
+{
+ u32 *resp = card->raw_cid;
+
+ memset(&card->cid, 0, sizeof(struct mmc_cid));
+
+ /*
+ * SD doesn't currently have a version field so we will
+ * have to assume we can parse this.
+ */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
+ card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
+ card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
+ card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
+ card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
+ card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
+ card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
+ card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
+ card->cid.year = UNSTUFF_BITS(resp, 12, 8);
+ card->cid.month = UNSTUFF_BITS(resp, 8, 4);
+
+ card->cid.year += 2000; /* SD cards year offset */
+}
+
+/*
+ * Given a 128-bit response, decode to our card CSD structure.
+ */
+static int mmc_decode_csd(struct mmc_card *card)
+{
+ struct mmc_csd *csd = &card->csd;
+ unsigned int e, m, csd_struct;
+ u32 *resp = card->raw_csd;
+
+ csd_struct = UNSTUFF_BITS(resp, 126, 2);
+
+ switch (csd_struct) {
+ case 0:
+ m = UNSTUFF_BITS(resp, 115, 4);
+ e = UNSTUFF_BITS(resp, 112, 3);
+ csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+ csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ e = UNSTUFF_BITS(resp, 47, 3);
+ m = UNSTUFF_BITS(resp, 62, 12);
+ csd->capacity = (1 + m) << (e + 2);
+
+ csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+ csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+ csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+ csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+ csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+ csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+ csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+ break;
+ case 1:
+ /*
+ * This is a block-addressed SDHC card. Most
+ * interesting fields are unused and have fixed
+ * values. To avoid getting tripped by buggy cards,
+ * we assume those fixed values ourselves.
+ */
+ mmc_card_set_blockaddr(card);
+
+ csd->tacc_ns = 0; /* Unused */
+ csd->tacc_clks = 0; /* Unused */
+
+ m = UNSTUFF_BITS(resp, 99, 4);
+ e = UNSTUFF_BITS(resp, 96, 3);
+ csd->max_dtr = tran_exp[e] * tran_mant[m];
+ csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+
+ m = UNSTUFF_BITS(resp, 48, 22);
+ csd->capacity = (1 + m) << 10;
+
+ csd->read_blkbits = 9;
+ csd->read_partial = 0;
+ csd->write_misalign = 0;
+ csd->read_misalign = 0;
+ csd->r2w_factor = 4; /* Unused */
+ csd->write_blkbits = 9;
+ csd->write_partial = 0;
+ break;
+ default:
+ printk("%s: unrecognised CSD structure version %d\n",
+ mmc_hostname(card->host), csd_struct);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Given a 64-bit response, decode to our card SCR structure.
+ */
+static int mmc_decode_scr(struct mmc_card *card)
+{
+ struct sd_scr *scr = &card->scr;
+ unsigned int scr_struct;
+ u32 resp[4];
+
+ BUG_ON(!mmc_card_sd(card));
+
+ resp[3] = card->raw_scr[1];
+ resp[2] = card->raw_scr[0];
+
+ scr_struct = UNSTUFF_BITS(resp, 60, 4);
+ if (scr_struct != 0) {
+ printk("%s: unrecognised SCR structure version %d\n",
+ mmc_hostname(card->host), scr_struct);
+ return -EINVAL;
+ }
+
+ scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
+ scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+
+ return 0;
+}
+
+/*
+ * Fetches and decodes switch information
+ */
+static int mmc_read_switch(struct mmc_card *card)
+{
+ int err;
+ u8 *status;
+
+ err = MMC_ERR_FAILED;
+
+ status = kmalloc(64, GFP_KERNEL);
+ if (!status) {
+ printk("%s: could not allocate a buffer for switch "
+ "capabilities.\n",
+ mmc_hostname(card->host));
+ return err;
+ }
+
+ err = mmc_sd_switch(card, 0, 0, 1, status);
+ if (err != MMC_ERR_NONE) {
+ /*
+ * Card not supporting high-speed will ignore the
+ * command.
+ */
+ err = MMC_ERR_NONE;
+ goto out;
+ }
+
+ if (status[13] & 0x02)
+ card->sw_caps.hs_max_dtr = 50000000;
+
+out:
+ kfree(status);
+
+ return err;
+}
+
+/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int mmc_switch_hs(struct mmc_card *card)
+{
+ int err;
+ u8 *status;
+
+ if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+ return MMC_ERR_NONE;
+
+ if (card->sw_caps.hs_max_dtr == 0)
+ return MMC_ERR_NONE;
+
+ err = MMC_ERR_FAILED;
+
+ status = kmalloc(64, GFP_KERNEL);
+ if (!status) {
+ printk("%s: could not allocate a buffer for switch "
+ "capabilities.\n",
+ mmc_hostname(card->host));
+ return err;
+ }
+
+ err = mmc_sd_switch(card, 1, 0, 1, status);
+ if (err != MMC_ERR_NONE)
+ goto out;
+
+ if ((status[16] & 0xF) != 1) {
+ printk(KERN_WARNING "%s: Problem switching card "
+ "into high-speed mode!\n",
+ mmc_hostname(card->host));
+ } else {
+ mmc_card_set_highspeed(card);
+ mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+ }
+
+out:
+ kfree(status);
+
+ return err;
+}
+
+/*
+ * Handle the detection and initialisation of a card.
+ *
+ * In the case of a resume, "curcard" will contain the card
+ * we're trying to reinitialise.
+ */
+static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
+ struct mmc_card *oldcard)
+{
+ struct mmc_card *card;
+ int err;
+ u32 cid[4];
+ unsigned int max_dtr;
+
+ BUG_ON(!host);
+ BUG_ON(!host->claimed);
+
+ /*
+ * Since we're changing the OCR value, we seem to
+ * need to tell some cards to go back to the idle
+ * state. We wait 1ms to give cards time to
+ * respond.
+ */
+ mmc_go_idle(host);
+
+ /*
+ * If SD_SEND_IF_COND indicates an SD 2.0
+ * compliant card and we should set bit 30
+ * of the ocr to indicate that we can handle
+ * block-addressed SDHC cards.
+ */
+ err = mmc_send_if_cond(host, ocr);
+ if (err == MMC_ERR_NONE)
+ ocr |= 1 << 30;
+
+ err = mmc_send_app_op_cond(host, ocr, NULL);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ /*
+ * Fetch CID from card.
+ */
+ err = mmc_all_send_cid(host, cid);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ if (oldcard) {
+ if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+ goto err;
+
+ card = oldcard;
+ } else {
+ /*
+ * Allocate card structure.
+ */
+ card = mmc_alloc_card(host);
+ if (IS_ERR(card))
+ goto err;
+
+ card->type = MMC_TYPE_SD;
+ memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
+ }
+
+ /*
+ * Set card RCA.
+ */
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+
+ if (!oldcard) {
+ /*
+ * Fetch CSD from card.
+ */
+ err = mmc_send_csd(card, card->raw_csd);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ err = mmc_decode_csd(card);
+ if (err < 0)
+ goto free_card;
+
+ mmc_decode_cid(card);
+ }
+
+ /*
+ * Select card, as all following commands rely on that.
+ */
+ err = mmc_select_card(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ if (!oldcard) {
+ /*
+ * Fetch SCR from card.
+ */
+ err = mmc_app_send_scr(card, card->raw_scr);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ err = mmc_decode_scr(card);
+ if (err < 0)
+ goto free_card;
+
+ /*
+ * Fetch switch information from card.
+ */
+ err = mmc_read_switch(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+ }
+
+ /*
+ * Attempt to change to high-speed (if supported)
+ */
+ err = mmc_switch_hs(card);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ /*
+ * Compute bus speed.
+ */
+ max_dtr = (unsigned int)-1;
+
+ if (mmc_card_highspeed(card)) {
+ if (max_dtr > card->sw_caps.hs_max_dtr)
+ max_dtr = card->sw_caps.hs_max_dtr;
+ } else if (max_dtr > card->csd.max_dtr) {
+ max_dtr = card->csd.max_dtr;
+ }
+
+ mmc_set_clock(host, max_dtr);
+
+ /*
+ * Switch to wider bus (if supported).
+ */
+ if ((host->caps && MMC_CAP_4_BIT_DATA) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err != MMC_ERR_NONE)
+ goto free_card;
+
+ mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+ }
+
+ if (!oldcard)
+ host->card = card;
+
+ return MMC_ERR_NONE;
+
+free_card:
+ if (!oldcard)
+ mmc_remove_card(card);
+err:
+
+ return MMC_ERR_FAILED;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_sd_remove(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_remove_card(host->card);
+ host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_sd_detect(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ /*
+ * Just check if our card has been removed.
+ */
+ err = mmc_send_status(host->card, NULL);
+
+ mmc_release_host(host);
+
+ if (err != MMC_ERR_NONE) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+
+ mmc_claim_host(host);
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+ }
+}
+
+#ifdef CONFIG_MMC_UNSAFE_RESUME
+
+/*
+ * Suspend callback from host.
+ */
+static void mmc_sd_suspend(struct mmc_host *host)
+{
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+ mmc_deselect_cards(host);
+ host->card->state &= ~MMC_STATE_HIGHSPEED;
+ mmc_release_host(host);
+}
+
+/*
+ * Resume callback from host.
+ *
+ * This function tries to determine if the same card is still present
+ * and, if so, restore all state to it.
+ */
+static void mmc_sd_resume(struct mmc_host *host)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->card);
+
+ mmc_claim_host(host);
+
+ err = mmc_sd_init_card(host, host->ocr, host->card);
+ if (err != MMC_ERR_NONE) {
+ mmc_remove_card(host->card);
+ host->card = NULL;
+
+ mmc_detach_bus(host);
+ }
+
+ mmc_release_host(host);
+}
+
+#else
+
+#define mmc_sd_suspend NULL
+#define mmc_sd_resume NULL
+
+#endif
+
+static const struct mmc_bus_ops mmc_sd_ops = {
+ .remove = mmc_sd_remove,
+ .detect = mmc_sd_detect,
+ .suspend = mmc_sd_suspend,
+ .resume = mmc_sd_resume,
+};
+
+/*
+ * Starting point for SD card init.
+ */
+int mmc_attach_sd(struct mmc_host *host, u32 ocr)
+{
+ int err;
+
+ BUG_ON(!host);
+ BUG_ON(!host->claimed);
+
+ mmc_attach_bus(host, &mmc_sd_ops);
+
+ /*
+ * Sanity check the voltages that the card claims to
+ * support.
+ */
+ if (ocr & 0x7F) {
+ printk(KERN_WARNING "%s: card claims to support voltages "
+ "below the defined range. These will be ignored.\n",
+ mmc_hostname(host));
+ ocr &= ~0x7F;
+ }
+
+ if (ocr & MMC_VDD_165_195) {
+ printk(KERN_WARNING "%s: SD card claims to support the "
+ "incompletely defined 'low voltage range'. This "
+ "will be ignored.\n", mmc_hostname(host));
+ ocr &= ~MMC_VDD_165_195;
+ }
+
+ host->ocr = mmc_select_voltage(host, ocr);
+
+ /*
+ * Can we support the voltage(s) of the card(s)?
+ */
+ if (!host->ocr)
+ goto err;
+
+ /*
+ * Detect and init the card.
+ */
+ err = mmc_sd_init_card(host, host->ocr, NULL);
+ if (err != MMC_ERR_NONE)
+ goto err;
+
+ mmc_release_host(host);
+
+ err = mmc_register_card(host->card);
+ if (err)
+ goto reclaim_host;
+
+ return 0;
+
+reclaim_host:
+ mmc_claim_host(host);
+ mmc_remove_card(host->card);
+ host->card = NULL;
+err:
+ mmc_detach_bus(host);
+ mmc_release_host(host);
+
+ return 0;
+}
+
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
new file mode 100644
index 00000000000..9697ce58110
--- /dev/null
+++ b/drivers/mmc/core/sd_ops.c
@@ -0,0 +1,316 @@
+/*
+ * linux/drivers/mmc/sd_ops.h
+ *
+ * Copyright 2006-2007 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
+ * your option) any later version.
+ */
+
+#include <linux/types.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include "core.h"
+#include "sd_ops.h"
+
+/**
+ * mmc_wait_for_app_cmd - start an application command and wait for
+ completion
+ * @host: MMC host to start command
+ * @rca: RCA to send MMC_APP_CMD to
+ * @cmd: MMC command to start
+ * @retries: maximum number of retries
+ *
+ * Sends a MMC_APP_CMD, checks the card response, sends the command
+ * in the parameter and waits for it to complete. Return any error
+ * that occurred while the command was executing. Do not attempt to
+ * parse the response.
+ */
+int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
+ struct mmc_command *cmd, int retries)
+{
+ struct mmc_request mrq;
+
+ int i, err;
+
+ BUG_ON(!cmd);
+ BUG_ON(retries < 0);
+
+ err = MMC_ERR_INVALID;
+
+ /*
+ * We have to resend MMC_APP_CMD for each attempt so
+ * we cannot use the retries field in mmc_command.
+ */
+ for (i = 0;i <= retries;i++) {
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ err = mmc_app_cmd(host, card);
+ if (err != MMC_ERR_NONE)
+ continue;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ memset(cmd->resp, 0, sizeof(cmd->resp));
+ cmd->retries = 0;
+
+ mrq.cmd = cmd;
+ cmd->data = NULL;
+
+ mmc_wait_for_req(host, &mrq);
+
+ err = cmd->error;
+ if (cmd->error == MMC_ERR_NONE)
+ break;
+ }
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!host);
+ BUG_ON(card && (card->host != host));
+
+ cmd.opcode = MMC_APP_CMD;
+
+ if (card) {
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ } else {
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
+ }
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ /* Check that card supported application commands */
+ if (!(cmd.resp[0] & R1_APP_CMD))
+ return MMC_ERR_FAILED;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_app_set_bus_width(struct mmc_card *card, int width)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SET_BUS_WIDTH;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ switch (width) {
+ case MMC_BUS_WIDTH_1:
+ cmd.arg = SD_BUS_WIDTH_1;
+ break;
+ case MMC_BUS_WIDTH_4:
+ cmd.arg = SD_BUS_WIDTH_4;
+ break;
+ default:
+ return MMC_ERR_INVALID;
+ }
+
+ err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+ struct mmc_command cmd;
+ int i, err = 0;
+
+ BUG_ON(!host);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_OP_COND;
+ cmd.arg = ocr;
+ cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+
+ for (i = 100; i; i--) {
+ err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ break;
+
+ if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+ break;
+
+ err = MMC_ERR_TIMEOUT;
+
+ mmc_delay(10);
+ }
+
+ if (rocr)
+ *rocr = cmd.resp[0];
+
+ return err;
+}
+
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
+{
+ struct mmc_command cmd;
+ int err;
+ static const u8 test_pattern = 0xAA;
+
+ /*
+ * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+ * before SD_APP_OP_COND. This command will harmlessly fail for
+ * SD 1.0 cards.
+ */
+ cmd.opcode = SD_SEND_IF_COND;
+ cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+ cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ if ((cmd.resp[0] & 0xFF) != test_pattern)
+ return MMC_ERR_FAILED;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
+{
+ int err;
+ struct mmc_command cmd;
+
+ BUG_ON(!host);
+ BUG_ON(!rca);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_SEND_RELATIVE_ADDR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
+
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ *rca = cmd.resp[0] >> 16;
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
+{
+ int err;
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+ BUG_ON(!scr);
+
+ err = mmc_app_cmd(card->host, card);
+ if (err != MMC_ERR_NONE)
+ return err;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = SD_APP_SEND_SCR;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 8;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, scr, 8);
+
+ mmc_set_data_timeout(&data, card, 0);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error != MMC_ERR_NONE)
+ return cmd.error;
+ if (data.error != MMC_ERR_NONE)
+ return data.error;
+
+ scr[0] = ntohl(scr[0]);
+ scr[1] = ntohl(scr[1]);
+
+ return MMC_ERR_NONE;
+}
+
+int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+ u8 value, u8 *resp)
+{
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ struct scatterlist sg;
+
+ BUG_ON(!card);
+ BUG_ON(!card->host);
+
+ mode = !!mode;
+ value &= 0xF;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = SD_SWITCH;
+ cmd.arg = mode << 31 | 0x00FFFFFF;
+ cmd.arg &= ~(0xF << (group * 4));
+ cmd.arg |= value << (group * 4);
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = 64;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ sg_init_one(&sg, resp, 64);
+
+ mmc_set_data_timeout(&data, card, 0);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error != MMC_ERR_NONE)
+ return cmd.error;
+ if (data.error != MMC_ERR_NONE)
+ return data.error;
+
+ return MMC_ERR_NONE;
+}
+
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
new file mode 100644
index 00000000000..1240fddba5e
--- /dev/null
+++ b/drivers/mmc/core/sd_ops.h
@@ -0,0 +1,25 @@
+/*
+ * linux/drivers/mmc/sd_ops.h
+ *
+ * Copyright 2006-2007 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
+ * your option) any later version.
+ */
+
+#ifndef _MMC_SD_OPS_H
+#define _MMC_SD_OPS_H
+
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
+int mmc_app_set_bus_width(struct mmc_card *card, int width);
+int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
+int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
+int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
+int mmc_sd_switch(struct mmc_card *card, int mode, int group,
+ u8 value, u8 *resp);
+
+#endif
+
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/core/sysfs.c
index e0e82d849d5..843b1fbba55 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/core/sysfs.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/mmc/mmc_sysfs.c
+ * linux/drivers/mmc/core/sysfs.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
*
@@ -18,7 +18,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
-#include "mmc.h"
+#include "sysfs.h"
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
@@ -72,12 +72,11 @@ static void mmc_release_card(struct device *dev)
/*
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
- * probe method. However, we force "bad" cards to fail.
+ * probe method.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
- struct mmc_card *card = dev_to_mmc_card(dev);
- return !mmc_card_bad(card);
+ return 1;
}
static int
@@ -217,6 +216,8 @@ int mmc_register_card(struct mmc_card *card)
device_del(&card->dev);
}
}
+ if (ret == 0)
+ mmc_card_set_present(card);
return ret;
}
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/core/sysfs.h
index 149affe0b68..80e29b35828 100644
--- a/drivers/mmc/mmc.h
+++ b/drivers/mmc/core/sysfs.h
@@ -1,15 +1,16 @@
/*
- * linux/drivers/mmc/mmc.h
+ * linux/drivers/mmc/core/sysfs.h
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
+ * Copyright 2007 Pierre Ossman
*
* 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.
*/
-#ifndef _MMC_H
-#define _MMC_H
-/* core-internal functions */
+#ifndef _MMC_CORE_SYSFS_H
+#define _MMC_CORE_SYSFS_H
+
void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
int mmc_register_card(struct mmc_card *card);
void mmc_remove_card(struct mmc_card *card);
@@ -22,4 +23,5 @@ void mmc_free_host_sysfs(struct mmc_host *host);
int mmc_schedule_work(struct work_struct *work);
int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay);
void mmc_flush_scheduled_work(void);
+
#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
new file mode 100644
index 00000000000..e23082fe88d
--- /dev/null
+++ b/drivers/mmc/host/Kconfig
@@ -0,0 +1,102 @@
+#
+# MMC/SD host controller drivers
+#
+
+comment "MMC/SD Host Controller Drivers"
+
+config MMC_ARMMMCI
+ tristate "ARM AMBA Multimedia Card Interface support"
+ depends on ARM_AMBA
+ help
+ This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
+ Interface (PL180 and PL181) support. If you have an ARM(R)
+ platform with a Multimedia Card slot, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_PXA
+ tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
+ depends on ARCH_PXA
+ help
+ This selects the Intel(R) PXA(R) Multimedia card Interface.
+ If you have a PXA(R) platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
+config MMC_SDHCI
+ tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This select the generic Secure Digital Host Controller Interface.
+ It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
+ and Toshiba(R). Most controllers found in laptops are of this type.
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_OMAP
+ tristate "TI OMAP Multimedia Card Interface support"
+ depends on ARCH_OMAP
+ select TPS65010 if MACH_OMAP_H2
+ help
+ This selects the TI OMAP Multimedia card Interface.
+ If you have an OMAP board with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
+config MMC_WBSD
+ tristate "Winbond W83L51xD SD/MMC Card Interface support"
+ depends on ISA_DMA_API
+ help
+ This selects the Winbond(R) W83L51xD Secure digital and
+ Multimedia card Interface.
+ If you have a machine with a integrated W83L518D or W83L519D
+ SD/MMC card reader, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_AU1X
+ tristate "Alchemy AU1XX0 MMC Card Interface support"
+ depends on SOC_AU1200
+ help
+ This selects the AMD Alchemy(R) Multimedia card interface.
+ If you have a Alchemy platform with a MMC slot, say Y or M here.
+
+ If unsure, say N.
+
+config MMC_AT91
+ tristate "AT91 SD/MMC Card Interface support"
+ depends on ARCH_AT91
+ help
+ This selects the AT91 MCI controller.
+
+ If unsure, say N.
+
+config MMC_IMX
+ tristate "Motorola i.MX Multimedia Card Interface support"
+ depends on ARCH_IMX
+ help
+ This selects the Motorola i.MX Multimedia card Interface.
+ If you have a i.MX platform with a Multimedia Card slot,
+ say Y or M here.
+
+ If unsure, say N.
+
+config MMC_TIFM_SD
+ tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && PCI
+ select TIFM_CORE
+ help
+ Say Y here if you want to be able to access MMC/SD cards with
+ the Texas Instruments(R) Flash Media card reader, found in many
+ laptops.
+ This option 'selects' (turns on, enables) 'TIFM_CORE', but you
+ probably also need appropriate card reader host adapter, such as
+ 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
+ (TIFM_7XX1)'.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tifm_sd.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
new file mode 100644
index 00000000000..6685f64345b
--- /dev/null
+++ b/drivers/mmc/host/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for MMC/SD host controller drivers
+#
+
+ifeq ($(CONFIG_MMC_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_MMC_ARMMMCI) += mmci.o
+obj-$(CONFIG_MMC_PXA) += pxamci.o
+obj-$(CONFIG_MMC_IMX) += imxmmc.o
+obj-$(CONFIG_MMC_SDHCI) += sdhci.o
+obj-$(CONFIG_MMC_WBSD) += wbsd.o
+obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+obj-$(CONFIG_MMC_OMAP) += omap.o
+obj-$(CONFIG_MMC_AT91) += at91_mci.o
+obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
+
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 459f4b4fede..e37943c314c 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -67,7 +67,6 @@
#include <linux/atmel_pdc.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index b834be261ab..b7156a4555b 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -42,7 +42,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <asm/io.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
diff --git a/drivers/mmc/au1xmmc.h b/drivers/mmc/host/au1xmmc.h
index 341cbdf0bac..341cbdf0bac 100644
--- a/drivers/mmc/au1xmmc.h
+++ b/drivers/mmc/host/au1xmmc.h
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/host/imxmmc.c
index 0de5c9e94e7..7ee2045acbe 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -41,7 +41,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
-#include <linux/mmc/protocol.h>
#include <linux/delay.h>
#include <asm/dma.h>
diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/host/imxmmc.h
index e5339e334db..e5339e334db 100644
--- a/drivers/mmc/imxmmc.h
+++ b/drivers/mmc/host/imxmmc.h
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/host/mmci.c
index 5941dd951e8..d11c2d23cee 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -17,7 +17,6 @@
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <linux/amba/bus.h>
#include <linux/clk.h>
diff --git a/drivers/mmc/mmci.h b/drivers/mmc/host/mmci.h
index 6d7eadc9a67..6d7eadc9a67 100644
--- a/drivers/mmc/mmci.h
+++ b/drivers/mmc/host/mmci.h
diff --git a/drivers/mmc/omap.c b/drivers/mmc/host/omap.c
index 1e96a2f6502..1914e65d4db 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -22,7 +22,6 @@
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <linux/mmc/card.h>
#include <linux/clk.h>
@@ -605,7 +604,7 @@ static void mmc_omap_switch_handler(struct work_struct *work)
}
if (mmc_omap_cover_is_open(host)) {
if (!complained) {
- dev_info(mmc_dev(host->mmc), "cover is open");
+ dev_info(mmc_dev(host->mmc), "cover is open\n");
complained = 1;
}
if (mmc_omap_enable_poll)
@@ -937,48 +936,55 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)
}
}
-static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmc_omap_host *host = mmc_priv(mmc);
+ int func_clk_rate = clk_get_rate(host->fclk);
int dsor;
- int realclock, i;
-
- realclock = ios->clock;
if (ios->clock == 0)
- dsor = 0;
- else {
- int func_clk_rate = clk_get_rate(host->fclk);
-
- dsor = func_clk_rate / realclock;
- if (dsor < 1)
- dsor = 1;
+ return 0;
- if (func_clk_rate / dsor > realclock)
- dsor++;
+ dsor = func_clk_rate / ios->clock;
+ if (dsor < 1)
+ dsor = 1;
- if (dsor > 250)
- dsor = 250;
+ if (func_clk_rate / dsor > ios->clock)
dsor++;
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- dsor |= 1 << 15;
- }
+ if (dsor > 250)
+ dsor = 250;
+ dsor++;
+
+ if (ios->bus_width == MMC_BUS_WIDTH_4)
+ dsor |= 1 << 15;
+
+ return dsor;
+}
+
+static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct mmc_omap_host *host = mmc_priv(mmc);
+ int dsor;
+ int i;
+
+ dsor = mmc_omap_calc_divisor(mmc, ios);
+ host->bus_mode = ios->bus_mode;
+ host->hw_bus_mode = host->bus_mode;
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_omap_power(host, 0);
break;
case MMC_POWER_UP:
- case MMC_POWER_ON:
+ /* Cannot touch dsor yet, just power up MMC */
mmc_omap_power(host, 1);
+ return;
+ case MMC_POWER_ON:
dsor |= 1 << 11;
break;
}
- host->bus_mode = ios->bus_mode;
- host->hw_bus_mode = host->bus_mode;
-
clk_enable(host->fclk);
/* On insanely high arm_per frequencies something sometimes
@@ -987,7 +993,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
* Writing to the CON register twice seems to do the trick. */
for (i = 0; i < 2; i++)
OMAP_MMC_WRITE(host, CON, dsor);
- if (ios->power_mode == MMC_POWER_UP) {
+ if (ios->power_mode == MMC_POWER_ON) {
/* Send clock cycles, poll completion */
OMAP_MMC_WRITE(host, IE, 0);
OMAP_MMC_WRITE(host, STAT, 0xffff);
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/host/pxamci.c
index 9774fc68b61..d97d3864b57 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <asm/dma.h>
#include <asm/io.h>
@@ -369,14 +368,14 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (CLOCKRATE / clk > ios->clock)
clk <<= 1;
host->clkrt = fls(clk) - 1;
- pxa_set_cken(CKEN12_MMC, 1);
+ pxa_set_cken(CKEN_MMC, 1);
/*
* we write clkrt on the next command
*/
} else {
pxamci_stop_clock(host);
- pxa_set_cken(CKEN12_MMC, 0);
+ pxa_set_cken(CKEN_MMC, 0);
}
if (host->power_mode != ios->power_mode) {
diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/host/pxamci.h
index 1b163220df2..1b163220df2 100644
--- a/drivers/mmc/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/host/sdhci.c
index d749f08601b..ff5bf73cdd2 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
*
- * Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
* 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
@@ -15,7 +15,6 @@
#include <linux/dma-mapping.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <asm/scatterlist.h>
@@ -247,14 +246,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
chunk_remain = min(blksize, 4);
}
- size = min(host->size, host->remain);
- size = min(size, chunk_remain);
+ size = min(host->remain, chunk_remain);
chunk_remain -= size;
blksize -= size;
host->offset += size;
host->remain -= size;
- host->size -= size;
+
while (size) {
*buffer = data & 0xFF;
buffer++;
@@ -289,14 +287,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
buffer = sdhci_sg_to_buffer(host) + host->offset;
while (blksize) {
- size = min(host->size, host->remain);
- size = min(size, chunk_remain);
+ size = min(host->remain, chunk_remain);
chunk_remain -= size;
blksize -= size;
host->offset += size;
host->remain -= size;
- host->size -= size;
+
while (size) {
data >>= 8;
data |= (u32)*buffer << 24;
@@ -325,7 +322,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
BUG_ON(!host->data);
- if (host->size == 0)
+ if (host->num_sg == 0)
return;
if (host->data->flags & MMC_DATA_READ)
@@ -339,10 +336,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
else
sdhci_write_block_pio(host);
- if (host->size == 0)
+ if (host->num_sg == 0)
break;
-
- BUG_ON(host->num_sg == 0);
}
DBG("PIO transfer complete.\n");
@@ -408,8 +403,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
} else {
- host->size = data->blksz * data->blocks;
-
host->cur_sg = data->sg;
host->num_sg = data->sg_len;
@@ -473,10 +466,6 @@ static void sdhci_finish_data(struct sdhci_host *host)
"though there were blocks left.\n",
mmc_hostname(host->mmc));
data->error = MMC_ERR_FAILED;
- } else if (host->size != 0) {
- printk(KERN_ERR "%s: %d bytes were left untransferred.\n",
- mmc_hostname(host->mmc), host->size);
- data->error = MMC_ERR_FAILED;
}
DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
@@ -669,20 +658,16 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
pwr = SDHCI_POWER_ON;
- switch (power) {
- case MMC_VDD_170:
- case MMC_VDD_180:
- case MMC_VDD_190:
+ switch (1 << power) {
+ case MMC_VDD_165_195:
pwr |= SDHCI_POWER_180;
break;
- case MMC_VDD_290:
- case MMC_VDD_300:
- case MMC_VDD_310:
+ case MMC_VDD_29_30:
+ case MMC_VDD_30_31:
pwr |= SDHCI_POWER_300;
break;
- case MMC_VDD_320:
- case MMC_VDD_330:
- case MMC_VDD_340:
+ case MMC_VDD_32_33:
+ case MMC_VDD_33_34:
pwr |= SDHCI_POWER_330;
break;
default:
@@ -1294,7 +1279,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
if (caps & SDHCI_CAN_VDD_300)
mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
if (caps & SDHCI_CAN_VDD_180)
- mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
+ mmc->ocr_avail |= MMC_VDD_165_195;
if (mmc->ocr_avail == 0) {
printk(KERN_ERR "%s: Hardware doesn't report any "
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/host/sdhci.h
index e324f0a623d..7400f4bc114 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
*
- * Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*
* 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
@@ -187,8 +187,6 @@ struct sdhci_host {
int offset; /* Offset into current sg */
int remain; /* Bytes left in current */
- int size; /* Remaining bytes in transfer */
-
char slot_descr[20]; /* Name for reservations */
int irq; /* Device IRQ */
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
new file mode 100644
index 00000000000..8b736e96844
--- /dev/null
+++ b/drivers/mmc/host/tifm_sd.c
@@ -0,0 +1,1091 @@
+/*
+ * tifm_sd.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
+ *
+ * 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.
+ *
+ * Special thanks to Brad Campbell for extensive testing of this driver.
+ *
+ */
+
+
+#include <linux/tifm.h>
+#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+#include <asm/io.h>
+
+#define DRIVER_NAME "tifm_sd"
+#define DRIVER_VERSION "0.8"
+
+static int no_dma = 0;
+static int fixed_timeout = 0;
+module_param(no_dma, bool, 0644);
+module_param(fixed_timeout, bool, 0644);
+
+/* Constants here are mostly from OMAP5912 datasheet */
+#define TIFM_MMCSD_RESET 0x0002
+#define TIFM_MMCSD_CLKMASK 0x03ff
+#define TIFM_MMCSD_POWER 0x0800
+#define TIFM_MMCSD_4BBUS 0x8000
+#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
+#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
+#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
+#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
+#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
+#define TIFM_MMCSD_READ 0x8000
+
+#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
+#define TIFM_MMCSD_CD 0x0002 /* card detect */
+#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
+#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
+#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
+#define TIFM_MMCSD_DTO 0x0020 /* data time-out */
+#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
+#define TIFM_MMCSD_CTO 0x0080 /* command time-out */
+#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
+#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
+#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
+#define TIFM_MMCSD_OCRB 0x1000 /* OCR busy */
+#define TIFM_MMCSD_CIRQ 0x2000 /* card irq (cmd40/sdio) */
+#define TIFM_MMCSD_CERR 0x4000 /* card status error */
+
+#define TIFM_MMCSD_ODTO 0x0040 /* open drain / extended timeout */
+#define TIFM_MMCSD_CARD_RO 0x0200 /* card is read-only */
+
+#define TIFM_MMCSD_FIFO_SIZE 0x0020
+
+#define TIFM_MMCSD_RSP_R0 0x0000
+#define TIFM_MMCSD_RSP_R1 0x0100
+#define TIFM_MMCSD_RSP_R2 0x0200
+#define TIFM_MMCSD_RSP_R3 0x0300
+#define TIFM_MMCSD_RSP_R4 0x0400
+#define TIFM_MMCSD_RSP_R5 0x0500
+#define TIFM_MMCSD_RSP_R6 0x0600
+
+#define TIFM_MMCSD_RSP_BUSY 0x0800
+
+#define TIFM_MMCSD_CMD_BC 0x0000
+#define TIFM_MMCSD_CMD_BCR 0x1000
+#define TIFM_MMCSD_CMD_AC 0x2000
+#define TIFM_MMCSD_CMD_ADTC 0x3000
+
+#define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL
+
+enum {
+ CMD_READY = 0x0001,
+ FIFO_READY = 0x0002,
+ BRS_READY = 0x0004,
+ SCMD_ACTIVE = 0x0008,
+ SCMD_READY = 0x0010,
+ CARD_BUSY = 0x0020,
+ DATA_CARRY = 0x0040
+};
+
+struct tifm_sd {
+ struct tifm_dev *dev;
+
+ unsigned short eject:1,
+ open_drain:1,
+ no_dma:1;
+ unsigned short cmd_flags;
+
+ unsigned int clk_freq;
+ unsigned int clk_div;
+ unsigned long timeout_jiffies;
+
+ struct tasklet_struct finish_tasklet;
+ struct timer_list timer;
+ struct mmc_request *req;
+
+ int sg_len;
+ int sg_pos;
+ unsigned int block_pos;
+ struct scatterlist bounce_buf;
+ unsigned char bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE];
+};
+
+/* for some reason, host won't respond correctly to readw/writew */
+static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
+ unsigned int off, unsigned int cnt)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned char *buf;
+ unsigned int pos = 0, val;
+
+ buf = kmap_atomic(pg, KM_BIO_DST_IRQ) + off;
+ if (host->cmd_flags & DATA_CARRY) {
+ buf[pos++] = host->bounce_buf_data[0];
+ host->cmd_flags &= ~DATA_CARRY;
+ }
+
+ while (pos < cnt) {
+ val = readl(sock->addr + SOCK_MMCSD_DATA);
+ buf[pos++] = val & 0xff;
+ if (pos == cnt) {
+ host->bounce_buf_data[0] = (val >> 8) & 0xff;
+ host->cmd_flags |= DATA_CARRY;
+ break;
+ }
+ buf[pos++] = (val >> 8) & 0xff;
+ }
+ kunmap_atomic(buf - off, KM_BIO_DST_IRQ);
+}
+
+static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
+ unsigned int off, unsigned int cnt)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned char *buf;
+ unsigned int pos = 0, val;
+
+ buf = kmap_atomic(pg, KM_BIO_SRC_IRQ) + off;
+ if (host->cmd_flags & DATA_CARRY) {
+ val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
+ writel(val, sock->addr + SOCK_MMCSD_DATA);
+ host->cmd_flags &= ~DATA_CARRY;
+ }
+
+ while (pos < cnt) {
+ val = buf[pos++];
+ if (pos == cnt) {
+ host->bounce_buf_data[0] = val & 0xff;
+ host->cmd_flags |= DATA_CARRY;
+ break;
+ }
+ val |= (buf[pos++] << 8) & 0xff00;
+ writel(val, sock->addr + SOCK_MMCSD_DATA);
+ }
+ kunmap_atomic(buf - off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_transfer_data(struct tifm_sd *host)
+{
+ struct mmc_data *r_data = host->req->cmd->data;
+ struct scatterlist *sg = r_data->sg;
+ unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
+ unsigned int p_off, p_cnt;
+ struct page *pg;
+
+ if (host->sg_pos == host->sg_len)
+ return;
+ while (t_size) {
+ cnt = sg[host->sg_pos].length - host->block_pos;
+ if (!cnt) {
+ host->block_pos = 0;
+ host->sg_pos++;
+ if (host->sg_pos == host->sg_len) {
+ if ((r_data->flags & MMC_DATA_WRITE)
+ && DATA_CARRY)
+ writel(host->bounce_buf_data[0],
+ host->dev->addr
+ + SOCK_MMCSD_DATA);
+
+ return;
+ }
+ cnt = sg[host->sg_pos].length;
+ }
+ off = sg[host->sg_pos].offset + host->block_pos;
+
+ pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+ p_off = offset_in_page(off);
+ p_cnt = PAGE_SIZE - p_off;
+ p_cnt = min(p_cnt, cnt);
+ p_cnt = min(p_cnt, t_size);
+
+ if (r_data->flags & MMC_DATA_READ)
+ tifm_sd_read_fifo(host, pg, p_off, p_cnt);
+ else if (r_data->flags & MMC_DATA_WRITE)
+ tifm_sd_write_fifo(host, pg, p_off, p_cnt);
+
+ t_size -= p_cnt;
+ host->block_pos += p_cnt;
+ }
+}
+
+static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
+ struct page *src, unsigned int src_off,
+ unsigned int count)
+{
+ unsigned char *src_buf = kmap_atomic(src, KM_BIO_SRC_IRQ) + src_off;
+ unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off;
+
+ memcpy(dst_buf, src_buf, count);
+
+ kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ);
+ kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ);
+}
+
+static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
+{
+ struct scatterlist *sg = r_data->sg;
+ unsigned int t_size = r_data->blksz;
+ unsigned int off, cnt;
+ unsigned int p_off, p_cnt;
+ struct page *pg;
+
+ dev_dbg(&host->dev->dev, "bouncing block\n");
+ while (t_size) {
+ cnt = sg[host->sg_pos].length - host->block_pos;
+ if (!cnt) {
+ host->block_pos = 0;
+ host->sg_pos++;
+ if (host->sg_pos == host->sg_len)
+ return;
+ cnt = sg[host->sg_pos].length;
+ }
+ off = sg[host->sg_pos].offset + host->block_pos;
+
+ pg = nth_page(sg[host->sg_pos].page, off >> PAGE_SHIFT);
+ p_off = offset_in_page(off);
+ p_cnt = PAGE_SIZE - p_off;
+ p_cnt = min(p_cnt, cnt);
+ p_cnt = min(p_cnt, t_size);
+
+ if (r_data->flags & MMC_DATA_WRITE)
+ tifm_sd_copy_page(host->bounce_buf.page,
+ r_data->blksz - t_size,
+ pg, p_off, p_cnt);
+ else if (r_data->flags & MMC_DATA_READ)
+ tifm_sd_copy_page(pg, p_off, host->bounce_buf.page,
+ r_data->blksz - t_size, p_cnt);
+
+ t_size -= p_cnt;
+ host->block_pos += p_cnt;
+ }
+}
+
+static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
+ unsigned int dma_len, dma_blk_cnt, dma_off;
+ struct scatterlist *sg = NULL;
+ unsigned long flags;
+
+ if (host->sg_pos == host->sg_len)
+ return 1;
+
+ if (host->cmd_flags & DATA_CARRY) {
+ host->cmd_flags &= ~DATA_CARRY;
+ local_irq_save(flags);
+ tifm_sd_bounce_block(host, r_data);
+ local_irq_restore(flags);
+ if (host->sg_pos == host->sg_len)
+ return 1;
+ }
+
+ dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos;
+ if (!dma_len) {
+ host->block_pos = 0;
+ host->sg_pos++;
+ if (host->sg_pos == host->sg_len)
+ return 1;
+ dma_len = sg_dma_len(&r_data->sg[host->sg_pos]);
+ }
+
+ if (dma_len < t_size) {
+ dma_blk_cnt = dma_len / r_data->blksz;
+ dma_off = host->block_pos;
+ host->block_pos += dma_blk_cnt * r_data->blksz;
+ } else {
+ dma_blk_cnt = TIFM_DMA_TSIZE;
+ dma_off = host->block_pos;
+ host->block_pos += t_size;
+ }
+
+ if (dma_blk_cnt)
+ sg = &r_data->sg[host->sg_pos];
+ else if (dma_len) {
+ if (r_data->flags & MMC_DATA_WRITE) {
+ local_irq_save(flags);
+ tifm_sd_bounce_block(host, r_data);
+ local_irq_restore(flags);
+ } else
+ host->cmd_flags |= DATA_CARRY;
+
+ sg = &host->bounce_buf;
+ dma_off = 0;
+ dma_blk_cnt = 1;
+ } else
+ return 1;
+
+ dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt);
+ writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS);
+ if (r_data->flags & MMC_DATA_WRITE)
+ writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
+ sock->addr + SOCK_DMA_CONTROL);
+ else
+ writel((dma_blk_cnt << 8) | TIFM_DMA_EN,
+ sock->addr + SOCK_DMA_CONTROL);
+
+ return 0;
+}
+
+static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
+{
+ unsigned int rc = 0;
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ rc |= TIFM_MMCSD_RSP_R0;
+ break;
+ case MMC_RSP_R1B:
+ rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
+ case MMC_RSP_R1:
+ rc |= TIFM_MMCSD_RSP_R1;
+ break;
+ case MMC_RSP_R2:
+ rc |= TIFM_MMCSD_RSP_R2;
+ break;
+ case MMC_RSP_R3:
+ rc |= TIFM_MMCSD_RSP_R3;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (mmc_cmd_type(cmd)) {
+ case MMC_CMD_BC:
+ rc |= TIFM_MMCSD_CMD_BC;
+ break;
+ case MMC_CMD_BCR:
+ rc |= TIFM_MMCSD_CMD_BCR;
+ break;
+ case MMC_CMD_AC:
+ rc |= TIFM_MMCSD_CMD_AC;
+ break;
+ case MMC_CMD_ADTC:
+ rc |= TIFM_MMCSD_CMD_ADTC;
+ break;
+ default:
+ BUG();
+ }
+ return rc;
+}
+
+static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int cmd_mask = tifm_sd_op_flags(cmd);
+
+ if (host->open_drain)
+ cmd_mask |= TIFM_MMCSD_ODTO;
+
+ if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+ cmd_mask |= TIFM_MMCSD_READ;
+
+ dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
+ cmd->opcode, cmd->arg, cmd_mask);
+
+ writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
+ writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
+ writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
+}
+
+static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
+{
+ cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
+ cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
+ cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
+ cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
+}
+
+static void tifm_sd_check_status(struct tifm_sd *host)
+{
+ struct tifm_dev *sock = host->dev;
+ struct mmc_command *cmd = host->req->cmd;
+
+ if (cmd->error != MMC_ERR_NONE)
+ goto finish_request;
+
+ if (!(host->cmd_flags & CMD_READY))
+ return;
+
+ if (cmd->data) {
+ if (cmd->data->error != MMC_ERR_NONE) {
+ if ((host->cmd_flags & SCMD_ACTIVE)
+ && !(host->cmd_flags & SCMD_READY))
+ return;
+
+ goto finish_request;
+ }
+
+ if (!(host->cmd_flags & BRS_READY))
+ return;
+
+ if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
+ return;
+
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ if (host->req->stop) {
+ if (!(host->cmd_flags & SCMD_ACTIVE)) {
+ host->cmd_flags |= SCMD_ACTIVE;
+ writel(TIFM_MMCSD_EOFB
+ | readl(sock->addr
+ + SOCK_MMCSD_INT_ENABLE),
+ sock->addr
+ + SOCK_MMCSD_INT_ENABLE);
+ tifm_sd_exec(host, host->req->stop);
+ return;
+ } else {
+ if (!(host->cmd_flags & SCMD_READY)
+ || (host->cmd_flags & CARD_BUSY))
+ return;
+ writel((~TIFM_MMCSD_EOFB)
+ & readl(sock->addr
+ + SOCK_MMCSD_INT_ENABLE),
+ sock->addr
+ + SOCK_MMCSD_INT_ENABLE);
+ }
+ } else {
+ if (host->cmd_flags & CARD_BUSY)
+ return;
+ writel((~TIFM_MMCSD_EOFB)
+ & readl(sock->addr
+ + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ }
+ } else {
+ if (host->req->stop) {
+ if (!(host->cmd_flags & SCMD_ACTIVE)) {
+ host->cmd_flags |= SCMD_ACTIVE;
+ tifm_sd_exec(host, host->req->stop);
+ return;
+ } else {
+ if (!(host->cmd_flags & SCMD_READY))
+ return;
+ }
+ }
+ }
+ }
+finish_request:
+ tasklet_schedule(&host->finish_tasklet);
+}
+
+/* Called from interrupt handler */
+static void tifm_sd_data_event(struct tifm_dev *sock)
+{
+ struct tifm_sd *host;
+ unsigned int fifo_status = 0;
+ struct mmc_data *r_data = NULL;
+
+ spin_lock(&sock->lock);
+ host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+ fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+ dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
+ fifo_status, host->cmd_flags);
+
+ if (host->req) {
+ r_data = host->req->cmd->data;
+
+ if (r_data && (fifo_status & TIFM_FIFO_READY)) {
+ if (tifm_sd_set_dma_data(host, r_data)) {
+ host->cmd_flags |= FIFO_READY;
+ tifm_sd_check_status(host);
+ }
+ }
+ }
+
+ writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+ spin_unlock(&sock->lock);
+}
+
+/* Called from interrupt handler */
+static void tifm_sd_card_event(struct tifm_dev *sock)
+{
+ struct tifm_sd *host;
+ unsigned int host_status = 0;
+ int cmd_error = MMC_ERR_NONE;
+ struct mmc_command *cmd = NULL;
+ unsigned long flags;
+
+ spin_lock(&sock->lock);
+ host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
+ host_status, host->cmd_flags);
+
+ if (host->req) {
+ cmd = host->req->cmd;
+
+ if (host_status & TIFM_MMCSD_ERRMASK) {
+ writel(host_status & TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_STATUS);
+ if (host_status & TIFM_MMCSD_CTO)
+ cmd_error = MMC_ERR_TIMEOUT;
+ else if (host_status & TIFM_MMCSD_CCRC)
+ cmd_error = MMC_ERR_BADCRC;
+
+ if (cmd->data) {
+ if (host_status & TIFM_MMCSD_DTO)
+ cmd->data->error = MMC_ERR_TIMEOUT;
+ else if (host_status & TIFM_MMCSD_DCRC)
+ cmd->data->error = MMC_ERR_BADCRC;
+ }
+
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
+
+ if (host->req->stop) {
+ if (host->cmd_flags & SCMD_ACTIVE) {
+ host->req->stop->error = cmd_error;
+ host->cmd_flags |= SCMD_READY;
+ } else {
+ cmd->error = cmd_error;
+ host->cmd_flags |= SCMD_ACTIVE;
+ tifm_sd_exec(host, host->req->stop);
+ goto done;
+ }
+ } else
+ cmd->error = cmd_error;
+ } else {
+ if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
+ if (!(host->cmd_flags & CMD_READY)) {
+ host->cmd_flags |= CMD_READY;
+ tifm_sd_fetch_resp(cmd, sock);
+ } else if (host->cmd_flags & SCMD_ACTIVE) {
+ host->cmd_flags |= SCMD_READY;
+ tifm_sd_fetch_resp(host->req->stop,
+ sock);
+ }
+ }
+ if (host_status & TIFM_MMCSD_BRS)
+ host->cmd_flags |= BRS_READY;
+ }
+
+ if (host->no_dma && cmd->data) {
+ if (host_status & TIFM_MMCSD_AE)
+ writel(host_status & TIFM_MMCSD_AE,
+ sock->addr + SOCK_MMCSD_STATUS);
+
+ if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
+ | TIFM_MMCSD_BRS)) {
+ local_irq_save(flags);
+ tifm_sd_transfer_data(host);
+ local_irq_restore(flags);
+ host_status &= ~TIFM_MMCSD_AE;
+ }
+ }
+
+ if (host_status & TIFM_MMCSD_EOFB)
+ host->cmd_flags &= ~CARD_BUSY;
+ else if (host_status & TIFM_MMCSD_CB)
+ host->cmd_flags |= CARD_BUSY;
+
+ tifm_sd_check_status(host);
+ }
+done:
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+ spin_unlock(&sock->lock);
+}
+
+static void tifm_sd_set_data_timeout(struct tifm_sd *host,
+ struct mmc_data *data)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int data_timeout = data->timeout_clks;
+
+ if (fixed_timeout)
+ return;
+
+ data_timeout += data->timeout_ns /
+ ((1000000000UL / host->clk_freq) * host->clk_div);
+
+ if (data_timeout < 0xffff) {
+ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel((~TIFM_MMCSD_DPE)
+ & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+ } else {
+ data_timeout = (data_timeout >> 10) + 1;
+ if (data_timeout > 0xffff)
+ data_timeout = 0; /* set to unlimited */
+ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ writel(TIFM_MMCSD_DPE
+ | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+ }
+}
+
+static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+ struct mmc_data *r_data = mrq->cmd->data;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (host->eject) {
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (host->req) {
+ printk(KERN_ERR "%s : unfinished request detected\n",
+ sock->dev.bus_id);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ host->cmd_flags = 0;
+ host->block_pos = 0;
+ host->sg_pos = 0;
+
+ if (r_data) {
+ tifm_sd_set_data_timeout(host, r_data);
+
+ if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)
+ writel(TIFM_MMCSD_EOFB
+ | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+ if (host->no_dma) {
+ writel(TIFM_MMCSD_BUFINT
+ | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+ | (TIFM_MMCSD_FIFO_SIZE - 1),
+ sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ host->sg_len = r_data->sg_len;
+ } else {
+ sg_init_one(&host->bounce_buf, host->bounce_buf_data,
+ r_data->blksz);
+
+ if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,
+ r_data->flags & MMC_DATA_WRITE
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE)) {
+ printk(KERN_ERR "%s : scatterlist map failed\n",
+ sock->dev.bus_id);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+ host->sg_len = tifm_map_sg(sock, r_data->sg,
+ r_data->sg_len,
+ r_data->flags
+ & MMC_DATA_WRITE
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE);
+ if (host->sg_len < 1) {
+ printk(KERN_ERR "%s : scatterlist map failed\n",
+ sock->dev.bus_id);
+ tifm_unmap_sg(sock, &host->bounce_buf, 1,
+ r_data->flags & MMC_DATA_WRITE
+ ? PCI_DMA_TODEVICE
+ : PCI_DMA_FROMDEVICE);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(ilog2(r_data->blksz) - 2,
+ sock->addr + SOCK_FIFO_PAGE_SIZE);
+ writel(TIFM_FIFO_ENABLE,
+ sock->addr + SOCK_FIFO_CONTROL);
+ writel(TIFM_FIFO_INTMASK,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+ if (r_data->flags & MMC_DATA_WRITE)
+ writel(TIFM_MMCSD_TXDE,
+ sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ else
+ writel(TIFM_MMCSD_RXDE,
+ sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ tifm_sd_set_dma_data(host, r_data);
+ }
+
+ writel(r_data->blocks - 1,
+ sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(r_data->blksz - 1,
+ sock->addr + SOCK_MMCSD_BLOCK_LEN);
+ }
+
+ host->req = mrq;
+ mod_timer(&host->timer, jiffies + host->timeout_jiffies);
+ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ tifm_sd_exec(host, mrq->cmd);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+
+err_out:
+ mrq->cmd->error = MMC_ERR_TIMEOUT;
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd(unsigned long data)
+{
+ struct tifm_sd *host = (struct tifm_sd*)data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct mmc_request *mrq;
+ struct mmc_data *r_data = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ del_timer(&host->timer);
+ mrq = host->req;
+ host->req = NULL;
+
+ if (!mrq) {
+ printk(KERN_ERR " %s : no request to complete?\n",
+ sock->dev.bus_id);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+ }
+
+ r_data = mrq->cmd->data;
+ if (r_data) {
+ if (host->no_dma) {
+ writel((~TIFM_MMCSD_BUFINT)
+ & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ } else {
+ tifm_unmap_sg(sock, &host->bounce_buf, 1,
+ (r_data->flags & MMC_DATA_WRITE)
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+ (r_data->flags & MMC_DATA_WRITE)
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ }
+
+ r_data->bytes_xfered = r_data->blocks
+ - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+ r_data->bytes_xfered *= r_data->blksz;
+ r_data->bytes_xfered += r_data->blksz
+ - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+ }
+
+ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_abort(unsigned long data)
+{
+ struct tifm_sd *host = (struct tifm_sd*)data;
+
+ printk(KERN_ERR
+ "%s : card failed to respond for a long period of time "
+ "(%x, %x)\n",
+ host->dev->dev.bus_id, host->req->cmd->opcode, host->cmd_flags);
+
+ tifm_eject(host->dev);
+}
+
+static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned int clk_div1, clk_div2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, "
+ "chip_select = %x, power_mode = %x, bus_width = %x\n",
+ ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,
+ ios->power_mode, ios->bus_width);
+
+ if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
+ } else {
+ writel((~TIFM_MMCSD_4BBUS)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
+ }
+
+ if (ios->clock) {
+ clk_div1 = 20000000 / ios->clock;
+ if (!clk_div1)
+ clk_div1 = 1;
+
+ clk_div2 = 24000000 / ios->clock;
+ if (!clk_div2)
+ clk_div2 = 1;
+
+ if ((20000000 / clk_div1) > ios->clock)
+ clk_div1++;
+ if ((24000000 / clk_div2) > ios->clock)
+ clk_div2++;
+ if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
+ host->clk_freq = 20000000;
+ host->clk_div = clk_div1;
+ writel((~TIFM_CTRL_FAST_CLK)
+ & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ } else {
+ host->clk_freq = 24000000;
+ host->clk_div = clk_div2;
+ writel(TIFM_CTRL_FAST_CLK
+ | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ }
+ } else {
+ host->clk_div = 0;
+ }
+ host->clk_div &= TIFM_MMCSD_CLKMASK;
+ writel(host->clk_div
+ | ((~TIFM_MMCSD_CLKMASK)
+ & readl(sock->addr + SOCK_MMCSD_CONFIG)),
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);
+
+ /* chip_select : maybe later */
+ //vdd
+ //power is set before probe / after remove
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static int tifm_sd_ro(struct mmc_host *mmc)
+{
+ int rc = 0;
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))
+ rc = 1;
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return rc;
+}
+
+static const struct mmc_host_ops tifm_sd_ops = {
+ .request = tifm_sd_request,
+ .set_ios = tifm_sd_ios,
+ .get_ro = tifm_sd_ro
+};
+
+static int tifm_sd_initialize_host(struct tifm_sd *host)
+{
+ int rc;
+ unsigned int host_status = 0;
+ struct tifm_dev *sock = host->dev;
+
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ host->clk_div = 61;
+ host->clk_freq = 20000000;
+ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ /* wait up to 0.51 sec for reset */
+ for (rc = 32; rc <= 256; rc <<= 1) {
+ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR "%s : controller failed to reset\n",
+ sock->dev.bus_id);
+ return -ENODEV;
+ }
+
+ writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ // command timeout fixed to 64 clocks for now
+ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+ for (rc = 16; rc <= 64; rc <<= 1) {
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+ if (!(host_status & TIFM_MMCSD_ERRMASK)
+ && (host_status & TIFM_MMCSD_EOC)) {
+ rc = 0;
+ break;
+ }
+ msleep(rc);
+ }
+
+ if (rc) {
+ printk(KERN_ERR
+ "%s : card not ready - probe failed on initialization\n",
+ sock->dev.bus_id);
+ return -ENODEV;
+ }
+
+ writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
+ | TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+
+ return 0;
+}
+
+static int tifm_sd_probe(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc;
+ struct tifm_sd *host;
+ int rc = -EIO;
+
+ if (!(TIFM_SOCK_STATE_OCCUPIED
+ & readl(sock->addr + SOCK_PRESENT_STATE))) {
+ printk(KERN_WARNING "%s : card gone, unexpectedly\n",
+ sock->dev.bus_id);
+ return rc;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ host = mmc_priv(mmc);
+ host->no_dma = no_dma;
+ tifm_set_drvdata(sock, mmc);
+ host->dev = sock;
+ host->timeout_jiffies = msecs_to_jiffies(1000);
+
+ tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
+ (unsigned long)host);
+ setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
+ mmc->ops = &tifm_sd_ops;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
+ mmc->f_min = 20000000 / 60;
+ mmc->f_max = 24000000;
+
+ mmc->max_blk_count = 2048;
+ mmc->max_hw_segs = mmc->max_blk_count;
+ mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
+ mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
+ mmc->max_req_size = mmc->max_seg_size;
+ mmc->max_phys_segs = mmc->max_hw_segs;
+
+ sock->card_event = tifm_sd_card_event;
+ sock->data_event = tifm_sd_data_event;
+ rc = tifm_sd_initialize_host(host);
+
+ if (!rc)
+ rc = mmc_add_host(mmc);
+ if (!rc)
+ return 0;
+
+ mmc_free_host(mmc);
+ return rc;
+}
+
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ host->eject = 1;
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ mmiowb();
+ spin_unlock_irqrestore(&sock->lock, flags);
+
+ tasklet_kill(&host->finish_tasklet);
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (host->req) {
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+ host->req->cmd->error = MMC_ERR_TIMEOUT;
+ if (host->req->stop)
+ host->req->stop->error = MMC_ERR_TIMEOUT;
+ tasklet_schedule(&host->finish_tasklet);
+ }
+ spin_unlock_irqrestore(&sock->lock, flags);
+ mmc_remove_host(mmc);
+ dev_dbg(&sock->dev, "after remove\n");
+
+ mmc_free_host(mmc);
+}
+
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
+{
+ return mmc_suspend_host(tifm_get_drvdata(sock), state);
+}
+
+static int tifm_sd_resume(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
+ int rc;
+
+ rc = tifm_sd_initialize_host(host);
+ dev_dbg(&sock->dev, "resume initialize %d\n", rc);
+
+ if (rc)
+ host->eject = 1;
+ else
+ rc = mmc_resume_host(mmc);
+
+ return rc;
+}
+
+#else
+
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct tifm_device_id tifm_sd_id_tbl[] = {
+ { TIFM_TYPE_SD }, { }
+};
+
+static struct tifm_driver tifm_sd_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE
+ },
+ .id_table = tifm_sd_id_tbl,
+ .probe = tifm_sd_probe,
+ .remove = tifm_sd_remove,
+ .suspend = tifm_sd_suspend,
+ .resume = tifm_sd_resume
+};
+
+static int __init tifm_sd_init(void)
+{
+ return tifm_register_driver(&tifm_sd_driver);
+}
+
+static void __exit tifm_sd_exit(void)
+{
+ tifm_unregister_driver(&tifm_sd_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia SD driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_sd_init);
+module_exit(tifm_sd_exit);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/host/wbsd.c
index 05ccfc43168..867ca6a6929 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
*
* 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
@@ -33,7 +33,6 @@
#include <linux/pnp.h>
#include <linux/highmem.h>
#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
#include <asm/io.h>
#include <asm/dma.h>
@@ -178,9 +177,8 @@ static void wbsd_init_device(struct wbsd_host *host)
ier = 0;
ier |= WBSD_EINT_CARD;
ier |= WBSD_EINT_FIFO_THRE;
- ier |= WBSD_EINT_CCRC;
- ier |= WBSD_EINT_TIMEOUT;
ier |= WBSD_EINT_CRC;
+ ier |= WBSD_EINT_TIMEOUT;
ier |= WBSD_EINT_TC;
outb(ier, host->base + WBSD_EIR);
@@ -278,90 +276,36 @@ static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
{
- unsigned int len, i, size;
+ unsigned int len, i;
struct scatterlist *sg;
char *dmabuf = host->dma_buffer;
char *sgbuf;
- size = host->size;
-
sg = data->sg;
len = data->sg_len;
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
for (i = 0; i < len; i++) {
sgbuf = page_address(sg[i].page) + sg[i].offset;
- if (size < sg[i].length)
- memcpy(dmabuf, sgbuf, size);
- else
- memcpy(dmabuf, sgbuf, sg[i].length);
+ memcpy(dmabuf, sgbuf, sg[i].length);
dmabuf += sg[i].length;
-
- if (size < sg[i].length)
- size = 0;
- else
- size -= sg[i].length;
-
- if (size == 0)
- break;
}
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
-
- BUG_ON(size != 0);
-
- host->size -= size;
}
static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
{
- unsigned int len, i, size;
+ unsigned int len, i;
struct scatterlist *sg;
char *dmabuf = host->dma_buffer;
char *sgbuf;
- size = host->size;
-
sg = data->sg;
len = data->sg_len;
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
for (i = 0; i < len; i++) {
sgbuf = page_address(sg[i].page) + sg[i].offset;
- if (size < sg[i].length)
- memcpy(sgbuf, dmabuf, size);
- else
- memcpy(sgbuf, dmabuf, sg[i].length);
+ memcpy(sgbuf, dmabuf, sg[i].length);
dmabuf += sg[i].length;
-
- if (size < sg[i].length)
- size = 0;
- else
- size -= sg[i].length;
-
- if (size == 0)
- break;
}
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
-
- BUG_ON(size != 0);
-
- host->size -= size;
}
/*
@@ -484,7 +428,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
/*
* Handle excessive data.
*/
- if (data->bytes_xfered == host->size)
+ if (host->num_sg == 0)
return;
buffer = wbsd_sg_to_buffer(host) + host->offset;
@@ -514,31 +458,14 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
data->bytes_xfered++;
/*
- * Transfer done?
- */
- if (data->bytes_xfered == host->size)
- return;
-
- /*
* End of scatter list entry?
*/
if (host->remain == 0) {
/*
* Get next entry. Check if last.
*/
- if (!wbsd_next_sg(host)) {
- /*
- * We should never reach this point.
- * It means that we're trying to
- * transfer more blocks than can fit
- * into the scatter list.
- */
- BUG_ON(1);
-
- host->size = data->bytes_xfered;
-
+ if (!wbsd_next_sg(host))
return;
- }
buffer = wbsd_sg_to_buffer(host);
}
@@ -550,7 +477,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
* hardware problem. The chip doesn't trigger
* FIFO threshold interrupts properly.
*/
- if ((host->size - data->bytes_xfered) < 16)
+ if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
tasklet_schedule(&host->fifo_tasklet);
}
@@ -564,7 +491,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
* Check that we aren't being called after the
* entire buffer has been transfered.
*/
- if (data->bytes_xfered == host->size)
+ if (host->num_sg == 0)
return;
buffer = wbsd_sg_to_buffer(host) + host->offset;
@@ -594,31 +521,14 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
data->bytes_xfered++;
/*
- * Transfer done?
- */
- if (data->bytes_xfered == host->size)
- return;
-
- /*
* End of scatter list entry?
*/
if (host->remain == 0) {
/*
* Get next entry. Check if last.
*/
- if (!wbsd_next_sg(host)) {
- /*
- * We should never reach this point.
- * It means that we're trying to
- * transfer more blocks than can fit
- * into the scatter list.
- */
- BUG_ON(1);
-
- host->size = data->bytes_xfered;
-
+ if (!wbsd_next_sg(host))
return;
- }
buffer = wbsd_sg_to_buffer(host);
}
@@ -638,6 +548,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
u16 blksize;
u8 setup;
unsigned long dmaflags;
+ unsigned int size;
DBGF("blksz %04x blks %04x flags %08x\n",
data->blksz, data->blocks, data->flags);
@@ -647,7 +558,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
/*
* Calculate size.
*/
- host->size = data->blocks * data->blksz;
+ size = data->blocks * data->blksz;
/*
* Check timeout values for overflow.
@@ -705,8 +616,8 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
/*
* The buffer for DMA is only 64 kB.
*/
- BUG_ON(host->size > 0x10000);
- if (host->size > 0x10000) {
+ BUG_ON(size > 0x10000);
+ if (size > 0x10000) {
data->error = MMC_ERR_INVALID;
return;
}
@@ -729,7 +640,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
else
set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
set_dma_addr(host->dma, host->dma_addr);
- set_dma_count(host->dma, host->size);
+ set_dma_count(host->dma, size);
enable_dma(host->dma);
release_dma_lock(dmaflags);
@@ -812,6 +723,10 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
count = get_dma_residue(host->dma);
release_dma_lock(dmaflags);
+ data->bytes_xfered = host->mrq->data->blocks *
+ host->mrq->data->blksz - count;
+ data->bytes_xfered -= data->bytes_xfered % data->blksz;
+
/*
* Any leftover data?
*/
@@ -820,7 +735,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
"%d bytes left.\n",
mmc_hostname(host->mmc), count);
- data->error = MMC_ERR_FAILED;
+ if (data->error == MMC_ERR_NONE)
+ data->error = MMC_ERR_FAILED;
} else {
/*
* Transfer data from DMA buffer to
@@ -828,8 +744,11 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
*/
if (data->flags & MMC_DATA_READ)
wbsd_dma_to_sg(host, data);
+ }
- data->bytes_xfered = host->size;
+ if (data->error != MMC_ERR_NONE) {
+ if (data->bytes_xfered)
+ data->bytes_xfered -= data->blksz;
}
}
@@ -869,24 +788,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
goto done;
}
- /*
- * Does the request include data?
- */
if (cmd->data) {
- wbsd_prepare_data(host, cmd->data);
-
- if (cmd->data->error != MMC_ERR_NONE)
- goto done;
- }
-
- wbsd_send_command(host, cmd);
-
- /*
- * If this is a data transfer the request
- * will be finished after the data has
- * transfered.
- */
- if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
* The hardware is so delightfully stupid that it has a list
* of "data" commands. If a command isn't on this list, it'll
@@ -918,14 +820,30 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
"supported by this controller.\n",
mmc_hostname(host->mmc), cmd->opcode);
#endif
- cmd->data->error = MMC_ERR_INVALID;
-
- if (cmd->data->stop)
- wbsd_send_command(host, cmd->data->stop);
+ cmd->error = MMC_ERR_INVALID;
goto done;
};
+ }
+
+ /*
+ * Does the request include data?
+ */
+ if (cmd->data) {
+ wbsd_prepare_data(host, cmd->data);
+
+ if (cmd->data->error != MMC_ERR_NONE)
+ goto done;
+ }
+
+ wbsd_send_command(host, cmd);
+ /*
+ * If this is a data transfer the request
+ * will be finished after the data has
+ * transfered.
+ */
+ if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
/*
* Dirty fix for hardware bug.
*/
@@ -1167,7 +1085,7 @@ static void wbsd_tasklet_fifo(unsigned long param)
/*
* Done?
*/
- if (host->size == data->bytes_xfered) {
+ if (host->num_sg == 0) {
wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
tasklet_schedule(&host->finish_tasklet);
}
@@ -1245,30 +1163,6 @@ end:
spin_unlock(&host->lock);
}
-static void wbsd_tasklet_block(unsigned long param)
-{
- struct wbsd_host *host = (struct wbsd_host *)param;
- struct mmc_data *data;
-
- spin_lock(&host->lock);
-
- if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) !=
- WBSD_CRC_OK) {
- data = wbsd_get_data(host);
- if (!data)
- goto end;
-
- DBGF("CRC error\n");
-
- data->error = MMC_ERR_BADCRC;
-
- tasklet_schedule(&host->finish_tasklet);
- }
-
-end:
- spin_unlock(&host->lock);
-}
-
/*
* Interrupt handling
*/
@@ -1299,8 +1193,6 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id)
tasklet_hi_schedule(&host->crc_tasklet);
if (isr & WBSD_INT_TIMEOUT)
tasklet_hi_schedule(&host->timeout_tasklet);
- if (isr & WBSD_INT_BUSYEND)
- tasklet_hi_schedule(&host->block_tasklet);
if (isr & WBSD_INT_TC)
tasklet_schedule(&host->finish_tasklet);
@@ -1601,8 +1493,6 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
(unsigned long)host);
tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
(unsigned long)host);
- tasklet_init(&host->block_tasklet, wbsd_tasklet_block,
- (unsigned long)host);
return 0;
}
@@ -1621,7 +1511,6 @@ static void __devexit wbsd_release_irq(struct wbsd_host *host)
tasklet_kill(&host->crc_tasklet);
tasklet_kill(&host->timeout_tasklet);
tasklet_kill(&host->finish_tasklet);
- tasklet_kill(&host->block_tasklet);
}
/*
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/host/wbsd.h
index d06718b0e2a..873bda1e59b 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/host/wbsd.h
@@ -1,7 +1,7 @@
/*
* linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
*
- * Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
*
* 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
@@ -46,10 +46,10 @@
#define WBSD_EINT_CARD 0x40
#define WBSD_EINT_FIFO_THRE 0x20
-#define WBSD_EINT_CCRC 0x10
+#define WBSD_EINT_CRC 0x10
#define WBSD_EINT_TIMEOUT 0x08
#define WBSD_EINT_PROGEND 0x04
-#define WBSD_EINT_CRC 0x02
+#define WBSD_EINT_BUSYEND 0x02
#define WBSD_EINT_TC 0x01
#define WBSD_INT_PENDING 0x80
@@ -158,8 +158,6 @@ struct wbsd_host
unsigned int offset; /* Offset into current entry */
unsigned int remain; /* Data left in curren entry */
- int size; /* Total size of transfer */
-
char* dma_buffer; /* ISA DMA buffer */
dma_addr_t dma_addr; /* Physical address for same */
@@ -182,7 +180,6 @@ struct wbsd_host
struct tasklet_struct crc_tasklet;
struct tasklet_struct timeout_tasklet;
struct tasklet_struct finish_tasklet;
- struct tasklet_struct block_tasklet;
struct timer_list ignore_timer; /* Ignore detection timer */
};
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
deleted file mode 100644
index 4a73e8b2428..00000000000
--- a/drivers/mmc/mmc.c
+++ /dev/null
@@ -1,1724 +0,0 @@
-/*
- * linux/drivers/mmc/mmc.c
- *
- * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
- * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- * SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
- * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/pagemap.h>
-#include <linux/err.h>
-#include <asm/scatterlist.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/protocol.h>
-
-#include "mmc.h"
-
-#define CMD_RETRIES 3
-
-/*
- * OCR Bit positions to 10s of Vdd mV.
- */
-static const unsigned short mmc_ocr_bit_to_vdd[] = {
- 150, 155, 160, 165, 170, 180, 190, 200,
- 210, 220, 230, 240, 250, 260, 270, 280,
- 290, 300, 310, 320, 330, 340, 350, 360
-};
-
-static const unsigned int tran_exp[] = {
- 10000, 100000, 1000000, 10000000,
- 0, 0, 0, 0
-};
-
-static const unsigned char tran_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-static const unsigned int tacc_exp[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
-};
-
-static const unsigned int tacc_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-
-/**
- * mmc_request_done - finish processing an MMC request
- * @host: MMC host which completed request
- * @mrq: MMC request which request
- *
- * MMC drivers should call this function when they have completed
- * their processing of a request.
- */
-void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
-{
- struct mmc_command *cmd = mrq->cmd;
- int err = cmd->error;
-
- pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
- mmc_hostname(host), cmd->opcode, err,
- mrq->data ? mrq->data->error : 0,
- mrq->stop ? mrq->stop->error : 0,
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
- if (err && cmd->retries) {
- cmd->retries--;
- cmd->error = 0;
- host->ops->request(host, mrq);
- } else if (mrq->done) {
- mrq->done(mrq);
- }
-}
-
-EXPORT_SYMBOL(mmc_request_done);
-
-/**
- * mmc_start_request - start a command on a host
- * @host: MMC host to start command on
- * @mrq: MMC request to start
- *
- * Queue a command on the specified host. We expect the
- * caller to be holding the host lock with interrupts disabled.
- */
-void
-mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
-{
- pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->cmd->opcode,
- mrq->cmd->arg, mrq->cmd->flags);
-
- WARN_ON(!host->claimed);
-
- mrq->cmd->error = 0;
- mrq->cmd->mrq = mrq;
- if (mrq->data) {
- BUG_ON(mrq->data->blksz > host->max_blk_size);
- BUG_ON(mrq->data->blocks > host->max_blk_count);
- BUG_ON(mrq->data->blocks * mrq->data->blksz >
- host->max_req_size);
-
- mrq->cmd->data = mrq->data;
- mrq->data->error = 0;
- mrq->data->mrq = mrq;
- if (mrq->stop) {
- mrq->data->stop = mrq->stop;
- mrq->stop->error = 0;
- mrq->stop->mrq = mrq;
- }
- }
- host->ops->request(host, mrq);
-}
-
-EXPORT_SYMBOL(mmc_start_request);
-
-static void mmc_wait_done(struct mmc_request *mrq)
-{
- complete(mrq->done_data);
-}
-
-int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
-{
- DECLARE_COMPLETION_ONSTACK(complete);
-
- mrq->done_data = &complete;
- mrq->done = mmc_wait_done;
-
- mmc_start_request(host, mrq);
-
- wait_for_completion(&complete);
-
- return 0;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_req);
-
-/**
- * mmc_wait_for_cmd - start a command and wait for completion
- * @host: MMC host to start command
- * @cmd: MMC command to start
- * @retries: maximum number of retries
- *
- * Start a new MMC command for a host, and wait for the command
- * to complete. Return any error that occurred while the command
- * was executing. Do not attempt to parse the response.
- */
-int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
-{
- struct mmc_request mrq;
-
- BUG_ON(!host->claimed);
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- memset(cmd->resp, 0, sizeof(cmd->resp));
- cmd->retries = retries;
-
- mrq.cmd = cmd;
- cmd->data = NULL;
-
- mmc_wait_for_req(host, &mrq);
-
- return cmd->error;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_cmd);
-
-/**
- * mmc_wait_for_app_cmd - start an application command and wait for
- completion
- * @host: MMC host to start command
- * @rca: RCA to send MMC_APP_CMD to
- * @cmd: MMC command to start
- * @retries: maximum number of retries
- *
- * Sends a MMC_APP_CMD, checks the card response, sends the command
- * in the parameter and waits for it to complete. Return any error
- * that occurred while the command was executing. Do not attempt to
- * parse the response.
- */
-int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
- struct mmc_command *cmd, int retries)
-{
- struct mmc_request mrq;
- struct mmc_command appcmd;
-
- int i, err;
-
- BUG_ON(!host->claimed);
- BUG_ON(retries < 0);
-
- err = MMC_ERR_INVALID;
-
- /*
- * We have to resend MMC_APP_CMD for each attempt so
- * we cannot use the retries field in mmc_command.
- */
- for (i = 0;i <= retries;i++) {
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- appcmd.opcode = MMC_APP_CMD;
- appcmd.arg = rca << 16;
- appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- appcmd.retries = 0;
- memset(appcmd.resp, 0, sizeof(appcmd.resp));
- appcmd.data = NULL;
-
- mrq.cmd = &appcmd;
- appcmd.data = NULL;
-
- mmc_wait_for_req(host, &mrq);
-
- if (appcmd.error) {
- err = appcmd.error;
- continue;
- }
-
- /* Check that card supported application commands */
- if (!(appcmd.resp[0] & R1_APP_CMD))
- return MMC_ERR_FAILED;
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- memset(cmd->resp, 0, sizeof(cmd->resp));
- cmd->retries = 0;
-
- mrq.cmd = cmd;
- cmd->data = NULL;
-
- mmc_wait_for_req(host, &mrq);
-
- err = cmd->error;
- if (cmd->error == MMC_ERR_NONE)
- break;
- }
-
- return err;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-
-/**
- * mmc_set_data_timeout - set the timeout for a data command
- * @data: data phase for command
- * @card: the MMC card associated with the data transfer
- * @write: flag to differentiate reads from writes
- */
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
- int write)
-{
- unsigned int mult;
-
- /*
- * SD cards use a 100 multiplier rather than 10
- */
- mult = mmc_card_sd(card) ? 100 : 10;
-
- /*
- * Scale up the multiplier (and therefore the timeout) by
- * the r2w factor for writes.
- */
- if (write)
- mult <<= card->csd.r2w_factor;
-
- data->timeout_ns = card->csd.tacc_ns * mult;
- data->timeout_clks = card->csd.tacc_clks * mult;
-
- /*
- * SD cards also have an upper limit on the timeout.
- */
- if (mmc_card_sd(card)) {
- unsigned int timeout_us, limit_us;
-
- timeout_us = data->timeout_ns / 1000;
- timeout_us += data->timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
-
- if (write)
- limit_us = 250000;
- else
- limit_us = 100000;
-
- /*
- * SDHC cards always use these fixed values.
- */
- if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
- data->timeout_ns = limit_us * 1000;
- data->timeout_clks = 0;
- }
- }
-}
-EXPORT_SYMBOL(mmc_set_data_timeout);
-
-static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
-
-/**
- * __mmc_claim_host - exclusively claim a host
- * @host: mmc host to claim
- * @card: mmc card to claim host for
- *
- * Claim a host for a set of operations. If a valid card
- * is passed and this wasn't the last card selected, select
- * the card before returning.
- *
- * Note: you should use mmc_card_claim_host or mmc_claim_host.
- */
-int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int err = 0;
-
- add_wait_queue(&host->wq, &wait);
- spin_lock_irqsave(&host->lock, flags);
- while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (!host->claimed)
- break;
- spin_unlock_irqrestore(&host->lock, flags);
- schedule();
- spin_lock_irqsave(&host->lock, flags);
- }
- set_current_state(TASK_RUNNING);
- host->claimed = 1;
- spin_unlock_irqrestore(&host->lock, flags);
- remove_wait_queue(&host->wq, &wait);
-
- if (card != (void *)-1) {
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE)
- return err;
- }
-
- return err;
-}
-
-EXPORT_SYMBOL(__mmc_claim_host);
-
-/**
- * mmc_release_host - release a host
- * @host: mmc host to release
- *
- * Release a MMC host, allowing others to claim the host
- * for their operations.
- */
-void mmc_release_host(struct mmc_host *host)
-{
- unsigned long flags;
-
- BUG_ON(!host->claimed);
-
- spin_lock_irqsave(&host->lock, flags);
- host->claimed = 0;
- spin_unlock_irqrestore(&host->lock, flags);
-
- wake_up(&host->wq);
-}
-
-EXPORT_SYMBOL(mmc_release_host);
-
-static inline void mmc_set_ios(struct mmc_host *host)
-{
- struct mmc_ios *ios = &host->ios;
-
- pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
- "width %u timing %u\n",
- mmc_hostname(host), ios->clock, ios->bus_mode,
- ios->power_mode, ios->chip_select, ios->vdd,
- ios->bus_width, ios->timing);
-
- host->ops->set_ios(host, ios);
-}
-
-static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
-{
- int err;
- struct mmc_command cmd;
-
- BUG_ON(!host->claimed);
-
- if (host->card_selected == card)
- return MMC_ERR_NONE;
-
- host->card_selected = card;
-
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- return err;
-
- /*
- * We can only change the bus width of SD cards when
- * they are selected so we have to put the handling
- * here.
- *
- * The card is in 1 bit mode by default so
- * we only need to change if it supports the
- * wider version.
- */
- if (mmc_card_sd(card) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
-
- /*
- * Default bus width is 1 bit.
- */
- host->ios.bus_width = MMC_BUS_WIDTH_1;
-
- if (host->caps & MMC_CAP_4_BIT_DATA) {
- struct mmc_command cmd;
- cmd.opcode = SD_APP_SET_BUS_WIDTH;
- cmd.arg = SD_BUS_WIDTH_4;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
- CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- return err;
-
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- }
- }
-
- mmc_set_ios(host);
-
- return MMC_ERR_NONE;
-}
-
-/*
- * Ensure that no card is selected.
- */
-static void mmc_deselect_cards(struct mmc_host *host)
-{
- struct mmc_command cmd;
-
- if (host->card_selected) {
- host->card_selected = NULL;
-
- cmd.opcode = MMC_SELECT_CARD;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
-
- mmc_wait_for_cmd(host, &cmd, 0);
- }
-}
-
-
-static inline void mmc_delay(unsigned int ms)
-{
- if (ms < 1000 / HZ) {
- cond_resched();
- mdelay(ms);
- } else {
- msleep(ms);
- }
-}
-
-/*
- * Mask off any voltages we don't support and select
- * the lowest voltage
- */
-static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
-{
- int bit;
-
- ocr &= host->ocr_avail;
-
- bit = ffs(ocr);
- if (bit) {
- bit -= 1;
-
- ocr &= 3 << bit;
-
- host->ios.vdd = bit;
- mmc_set_ios(host);
- } else {
- ocr = 0;
- }
-
- return ocr;
-}
-
-#define UNSTUFF_BITS(resp,start,size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
- const int __off = 3 - ((start) / 32); \
- const int __shft = (start) & 31; \
- u32 __res; \
- \
- __res = resp[__off] >> __shft; \
- if (__size + __shft > 32) \
- __res |= resp[__off-1] << ((32 - __shft) % 32); \
- __res & __mask; \
- })
-
-/*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-static void mmc_decode_cid(struct mmc_card *card)
-{
- u32 *resp = card->raw_cid;
-
- memset(&card->cid, 0, sizeof(struct mmc_cid));
-
- if (mmc_card_sd(card)) {
- /*
- * SD doesn't currently have a version field so we will
- * have to assume we can parse this.
- */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
- card->cid.year = UNSTUFF_BITS(resp, 12, 8);
- card->cid.month = UNSTUFF_BITS(resp, 8, 4);
-
- card->cid.year += 2000; /* SD cards year offset */
- } else {
- /*
- * The selection of the format here is based upon published
- * specs from sandisk and from what people have reported.
- */
- switch (card->csd.mmca_vsn) {
- case 0: /* MMC v1.0 - v1.2 */
- case 1: /* MMC v1.4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
-
- case 2: /* MMC v2.0 - v2.2 */
- case 3: /* MMC v3.1 - v3.3 */
- case 4: /* MMC v4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
-
- default:
- printk("%s: card has unknown MMCA version %d\n",
- mmc_hostname(card->host), card->csd.mmca_vsn);
- mmc_card_set_bad(card);
- break;
- }
- }
-}
-
-/*
- * Given a 128-bit response, decode to our card CSD structure.
- */
-static void mmc_decode_csd(struct mmc_card *card)
-{
- struct mmc_csd *csd = &card->csd;
- unsigned int e, m, csd_struct;
- u32 *resp = card->raw_csd;
-
- if (mmc_card_sd(card)) {
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
-
- switch (csd_struct) {
- case 0:
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
- break;
- case 1:
- /*
- * This is a block-addressed SDHC card. Most
- * interesting fields are unused and have fixed
- * values. To avoid getting tripped by buggy cards,
- * we assume those fixed values ourselves.
- */
- mmc_card_set_blockaddr(card);
-
- csd->tacc_ns = 0; /* Unused */
- csd->tacc_clks = 0; /* Unused */
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- m = UNSTUFF_BITS(resp, 48, 22);
- csd->capacity = (1 + m) << 10;
-
- csd->read_blkbits = 9;
- csd->read_partial = 0;
- csd->write_misalign = 0;
- csd->read_misalign = 0;
- csd->r2w_factor = 4; /* Unused */
- csd->write_blkbits = 9;
- csd->write_partial = 0;
- break;
- default:
- printk("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
- mmc_card_set_bad(card);
- return;
- }
- } else {
- /*
- * We only understand CSD structure v1.1 and v1.2.
- * v1.2 has extra information in bits 15, 11 and 10.
- */
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
- if (csd_struct != 1 && csd_struct != 2) {
- printk("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
- mmc_card_set_bad(card);
- return;
- }
-
- csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
- }
-}
-
-/*
- * Given a 64-bit response, decode to our card SCR structure.
- */
-static void mmc_decode_scr(struct mmc_card *card)
-{
- struct sd_scr *scr = &card->scr;
- unsigned int scr_struct;
- u32 resp[4];
-
- BUG_ON(!mmc_card_sd(card));
-
- resp[3] = card->raw_scr[1];
- resp[2] = card->raw_scr[0];
-
- scr_struct = UNSTUFF_BITS(resp, 60, 4);
- if (scr_struct != 0) {
- printk("%s: unrecognised SCR structure version %d\n",
- mmc_hostname(card->host), scr_struct);
- mmc_card_set_bad(card);
- return;
- }
-
- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
-}
-
-/*
- * Locate a MMC card on this MMC host given a raw CID.
- */
-static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid)
-{
- struct mmc_card *card;
-
- list_for_each_entry(card, &host->cards, node) {
- if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0)
- return card;
- }
- return NULL;
-}
-
-/*
- * Allocate a new MMC card, and assign a unique RCA.
- */
-static struct mmc_card *
-mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca)
-{
- struct mmc_card *card, *c;
- unsigned int rca = *frca;
-
- card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
- if (!card)
- return ERR_PTR(-ENOMEM);
-
- mmc_init_card(card, host);
- memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid));
-
- again:
- list_for_each_entry(c, &host->cards, node)
- if (c->rca == rca) {
- rca++;
- goto again;
- }
-
- card->rca = rca;
-
- *frca = rca;
-
- return card;
-}
-
-/*
- * Tell attached cards to go to IDLE state
- */
-static void mmc_idle_cards(struct mmc_host *host)
-{
- struct mmc_command cmd;
-
- host->ios.chip_select = MMC_CS_HIGH;
- mmc_set_ios(host);
-
- mmc_delay(1);
-
- cmd.opcode = MMC_GO_IDLE_STATE;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
-
- mmc_wait_for_cmd(host, &cmd, 0);
-
- mmc_delay(1);
-
- host->ios.chip_select = MMC_CS_DONTCARE;
- mmc_set_ios(host);
-
- mmc_delay(1);
-}
-
-/*
- * Apply power to the MMC stack. This is a two-stage process.
- * First, we enable power to the card without the clock running.
- * We then wait a bit for the power to stabilise. Finally,
- * enable the bus drivers and clock to the card.
- *
- * We must _NOT_ enable the clock prior to power stablising.
- *
- * If a host does all the power sequencing itself, ignore the
- * initial MMC_POWER_UP stage.
- */
-static void mmc_power_up(struct mmc_host *host)
-{
- int bit = fls(host->ocr_avail) - 1;
-
- host->ios.vdd = bit;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.power_mode = MMC_POWER_UP;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
-
- mmc_delay(1);
-
- host->ios.clock = host->f_min;
- host->ios.power_mode = MMC_POWER_ON;
- mmc_set_ios(host);
-
- mmc_delay(2);
-}
-
-static void mmc_power_off(struct mmc_host *host)
-{
- host->ios.clock = 0;
- host->ios.vdd = 0;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.power_mode = MMC_POWER_OFF;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
-}
-
-static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
- struct mmc_command cmd;
- int i, err = 0;
-
- cmd.opcode = MMC_SEND_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
- for (i = 100; i; i--) {
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err != MMC_ERR_NONE)
- break;
-
- if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
- break;
-
- err = MMC_ERR_TIMEOUT;
-
- mmc_delay(10);
- }
-
- if (rocr)
- *rocr = cmd.resp[0];
-
- return err;
-}
-
-static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
- struct mmc_command cmd;
- int i, err = 0;
-
- cmd.opcode = SD_APP_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
- for (i = 100; i; i--) {
- err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- break;
-
- if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
- break;
-
- err = MMC_ERR_TIMEOUT;
-
- mmc_delay(10);
- }
-
- if (rocr)
- *rocr = cmd.resp[0];
-
- return err;
-}
-
-static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
-{
- struct mmc_command cmd;
- int err, sd2;
- static const u8 test_pattern = 0xAA;
-
- /*
- * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
- * before SD_APP_OP_COND. This command will harmlessly fail for
- * SD 1.0 cards.
- */
- cmd.opcode = SD_SEND_IF_COND;
- cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
- cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err == MMC_ERR_NONE) {
- if ((cmd.resp[0] & 0xFF) == test_pattern) {
- sd2 = 1;
- } else {
- sd2 = 0;
- err = MMC_ERR_FAILED;
- }
- } else {
- /*
- * Treat errors as SD 1.0 card.
- */
- sd2 = 0;
- err = MMC_ERR_NONE;
- }
- if (rsd2)
- *rsd2 = sd2;
- return err;
-}
-
-/*
- * Discover cards by requesting their CID. If this command
- * times out, it is not an error; there are no further cards
- * to be discovered. Add new cards to the list.
- *
- * Create a mmc_card entry for each discovered card, assigning
- * it an RCA, and save the raw CID for decoding later.
- */
-static void mmc_discover_cards(struct mmc_host *host)
-{
- struct mmc_card *card;
- unsigned int first_rca = 1, err;
-
- while (1) {
- struct mmc_command cmd;
-
- cmd.opcode = MMC_ALL_SEND_CID;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_TIMEOUT) {
- err = MMC_ERR_NONE;
- break;
- }
- if (err != MMC_ERR_NONE) {
- printk(KERN_ERR "%s: error requesting CID: %d\n",
- mmc_hostname(host), err);
- break;
- }
-
- card = mmc_find_card(host, cmd.resp);
- if (!card) {
- card = mmc_alloc_card(host, cmd.resp, &first_rca);
- if (IS_ERR(card)) {
- err = PTR_ERR(card);
- break;
- }
- list_add(&card->node, &host->cards);
- }
-
- card->state &= ~MMC_STATE_DEAD;
-
- if (host->mode == MMC_MODE_SD) {
- mmc_card_set_sd(card);
-
- cmd.opcode = SD_SEND_RELATIVE_ADDR;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(card);
- else {
- card->rca = cmd.resp[0] >> 16;
-
- if (!host->ops->get_ro) {
- printk(KERN_WARNING "%s: host does not "
- "support reading read-only "
- "switch. assuming write-enable.\n",
- mmc_hostname(host));
- } else {
- if (host->ops->get_ro(host))
- mmc_card_set_readonly(card);
- }
- }
- } else {
- cmd.opcode = MMC_SET_RELATIVE_ADDR;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE)
- mmc_card_set_dead(card);
- }
- }
-}
-
-static void mmc_read_csds(struct mmc_host *host)
-{
- struct mmc_card *card;
-
- list_for_each_entry(card, &host->cards, node) {
- struct mmc_command cmd;
- int err;
-
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
-
- cmd.opcode = MMC_SEND_CSD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd));
-
- mmc_decode_csd(card);
- mmc_decode_cid(card);
- }
-}
-
-static void mmc_process_ext_csds(struct mmc_host *host)
-{
- int err;
- struct mmc_card *card;
-
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
-
- struct scatterlist sg;
-
- /*
- * As the ext_csd is so large and mostly unused, we don't store the
- * raw block in mmc_card.
- */
- u8 *ext_csd;
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- printk("%s: could not allocate a buffer to receive the ext_csd."
- "mmc v4 cards will be treated as v3.\n",
- mmc_hostname(host));
- return;
- }
-
- list_for_each_entry(card, &host->cards, node) {
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
- if (mmc_card_sd(card))
- continue;
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- continue;
-
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = MMC_SEND_EXT_CSD;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- memset(&data, 0, sizeof(struct mmc_data));
-
- mmc_set_data_timeout(&data, card, 0);
-
- data.blksz = 512;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- sg_init_one(&sg, ext_csd, 512);
-
- mmc_wait_for_req(host, &mrq);
-
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- printk("%s: unable to read EXT_CSD, performance "
- "might suffer.\n", mmc_hostname(card->host));
- continue;
- }
-
- switch (ext_csd[EXT_CSD_CARD_TYPE]) {
- case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- break;
- case EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 26000000;
- break;
- default:
- /* MMC v4 spec says this cannot happen */
- printk("%s: card is mmc v4 but doesn't support "
- "any high-speed modes.\n",
- mmc_hostname(card->host));
- continue;
- }
-
- if (host->caps & MMC_CAP_MMC_HIGHSPEED) {
- /* Activate highspeed support. */
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_HS_TIMING << 16) |
- (1 << 8) |
- EXT_CSD_CMD_SET_NORMAL;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to mmc v4 "
- "high-speed mode.\n",
- mmc_hostname(card->host));
- continue;
- }
-
- mmc_card_set_highspeed(card);
-
- host->ios.timing = MMC_TIMING_SD_HS;
- mmc_set_ios(host);
- }
-
- /* Check for host support for wide-bus modes. */
- if (host->caps & MMC_CAP_4_BIT_DATA) {
- /* Activate 4-bit support. */
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (EXT_CSD_BUS_WIDTH << 16) |
- (EXT_CSD_BUS_WIDTH_4 << 8) |
- EXT_CSD_CMD_SET_NORMAL;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err != MMC_ERR_NONE) {
- printk("%s: failed to switch card to "
- "mmc v4 4-bit bus mode.\n",
- mmc_hostname(card->host));
- continue;
- }
-
- host->ios.bus_width = MMC_BUS_WIDTH_4;
- mmc_set_ios(host);
- }
- }
-
- kfree(ext_csd);
-
- mmc_deselect_cards(host);
-}
-
-static void mmc_read_scrs(struct mmc_host *host)
-{
- int err;
- struct mmc_card *card;
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
- struct scatterlist sg;
-
- list_for_each_entry(card, &host->cards, node) {
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
- if (!mmc_card_sd(card))
- continue;
-
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = MMC_APP_CMD;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = SD_APP_SEND_SCR;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- memset(&data, 0, sizeof(struct mmc_data));
-
- mmc_set_data_timeout(&data, card, 0);
-
- data.blksz = 1 << 3;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- sg_init_one(&sg, (u8*)card->raw_scr, 8);
-
- mmc_wait_for_req(host, &mrq);
-
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- card->raw_scr[0] = ntohl(card->raw_scr[0]);
- card->raw_scr[1] = ntohl(card->raw_scr[1]);
-
- mmc_decode_scr(card);
- }
-
- mmc_deselect_cards(host);
-}
-
-static void mmc_read_switch_caps(struct mmc_host *host)
-{
- int err;
- struct mmc_card *card;
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
- unsigned char *status;
- struct scatterlist sg;
-
- if (!(host->caps & MMC_CAP_SD_HIGHSPEED))
- return;
-
- status = kmalloc(64, GFP_KERNEL);
- if (!status) {
- printk(KERN_WARNING "%s: Unable to allocate buffer for "
- "reading switch capabilities.\n",
- mmc_hostname(host));
- return;
- }
-
- list_for_each_entry(card, &host->cards, node) {
- if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
- continue;
- if (!mmc_card_sd(card))
- continue;
- if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- continue;
-
- err = mmc_select_card(host, card);
- if (err != MMC_ERR_NONE) {
- mmc_card_set_dead(card);
- continue;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = SD_SWITCH;
- cmd.arg = 0x00FFFFF1;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- memset(&data, 0, sizeof(struct mmc_data));
-
- mmc_set_data_timeout(&data, card, 0);
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- sg_init_one(&sg, status, 64);
-
- mmc_wait_for_req(host, &mrq);
-
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
- printk("%s: unable to read switch capabilities, "
- "performance might suffer.\n",
- mmc_hostname(card->host));
- continue;
- }
-
- if (status[13] & 0x02)
- card->sw_caps.hs_max_dtr = 50000000;
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = SD_SWITCH;
- cmd.arg = 0x80FFFFF1;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- memset(&data, 0, sizeof(struct mmc_data));
-
- mmc_set_data_timeout(&data, card, 0);
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- sg_init_one(&sg, status, 64);
-
- mmc_wait_for_req(host, &mrq);
-
- if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
- (status[16] & 0xF) != 1) {
- printk(KERN_WARNING "%s: Problem switching card "
- "into high-speed mode!\n",
- mmc_hostname(host));
- continue;
- }
-
- mmc_card_set_highspeed(card);
-
- host->ios.timing = MMC_TIMING_SD_HS;
- mmc_set_ios(host);
- }
-
- kfree(status);
-
- mmc_deselect_cards(host);
-}
-
-static unsigned int mmc_calculate_clock(struct mmc_host *host)
-{
- struct mmc_card *card;
- unsigned int max_dtr = host->f_max;
-
- list_for_each_entry(card, &host->cards, node)
- if (!mmc_card_dead(card)) {
- if (mmc_card_highspeed(card) && mmc_card_sd(card)) {
- if (max_dtr > card->sw_caps.hs_max_dtr)
- max_dtr = card->sw_caps.hs_max_dtr;
- } else if (mmc_card_highspeed(card) && !mmc_card_sd(card)) {
- if (max_dtr > card->ext_csd.hs_max_dtr)
- max_dtr = card->ext_csd.hs_max_dtr;
- } else if (max_dtr > card->csd.max_dtr) {
- max_dtr = card->csd.max_dtr;
- }
- }
-
- pr_debug("%s: selected %d.%03dMHz transfer rate\n",
- mmc_hostname(host),
- max_dtr / 1000000, (max_dtr / 1000) % 1000);
-
- return max_dtr;
-}
-
-/*
- * Check whether cards we already know about are still present.
- * We do this by requesting status, and checking whether a card
- * responds.
- *
- * A request for status does not cause a state change in data
- * transfer mode.
- */
-static void mmc_check_cards(struct mmc_host *host)
-{
- struct list_head *l, *n;
-
- mmc_deselect_cards(host);
-
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
- struct mmc_command cmd;
- int err;
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_NONE)
- continue;
-
- mmc_card_set_dead(card);
- }
-}
-
-static void mmc_setup(struct mmc_host *host)
-{
- if (host->ios.power_mode != MMC_POWER_ON) {
- int err;
- u32 ocr;
-
- host->mode = MMC_MODE_SD;
-
- mmc_power_up(host);
- mmc_idle_cards(host);
-
- err = mmc_send_if_cond(host, host->ocr_avail, NULL);
- if (err != MMC_ERR_NONE) {
- return;
- }
- err = mmc_send_app_op_cond(host, 0, &ocr);
-
- /*
- * If we fail to detect any SD cards then try
- * searching for MMC cards.
- */
- if (err != MMC_ERR_NONE) {
- host->mode = MMC_MODE_MMC;
-
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err != MMC_ERR_NONE)
- return;
- }
-
- host->ocr = mmc_select_voltage(host, ocr);
-
- /*
- * Since we're changing the OCR value, we seem to
- * need to tell some cards to go back to the idle
- * state. We wait 1ms to give cards time to
- * respond.
- */
- if (host->ocr)
- mmc_idle_cards(host);
- } else {
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.clock = host->f_min;
- mmc_set_ios(host);
-
- /*
- * We should remember the OCR mask from the existing
- * cards, and detect the new cards OCR mask, combine
- * the two and re-select the VDD. However, if we do
- * change VDD, we should do an idle, and then do a
- * full re-initialisation. We would need to notify
- * drivers so that they can re-setup the cards as
- * well, while keeping their queues at bay.
- *
- * For the moment, we take the easy way out - if the
- * new cards don't like our currently selected VDD,
- * they drop off the bus.
- */
- }
-
- if (host->ocr == 0)
- return;
-
- /*
- * Send the selected OCR multiple times... until the cards
- * all get the idea that they should be ready for CMD2.
- * (My SanDisk card seems to need this.)
- */
- if (host->mode == MMC_MODE_SD) {
- int err, sd2;
- err = mmc_send_if_cond(host, host->ocr, &sd2);
- if (err == MMC_ERR_NONE) {
- /*
- * If SD_SEND_IF_COND indicates an SD 2.0
- * compliant card and we should set bit 30
- * of the ocr to indicate that we can handle
- * block-addressed SDHC cards.
- */
- mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
- }
- } else {
- mmc_send_op_cond(host, host->ocr, NULL);
- }
-
- mmc_discover_cards(host);
-
- /*
- * Ok, now switch to push-pull mode.
- */
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- mmc_set_ios(host);
-
- mmc_read_csds(host);
-
- if (host->mode == MMC_MODE_SD) {
- mmc_read_scrs(host);
- mmc_read_switch_caps(host);
- } else
- mmc_process_ext_csds(host);
-}
-
-
-/**
- * mmc_detect_change - process change of state on a MMC socket
- * @host: host which changed state.
- * @delay: optional delay to wait before detection (jiffies)
- *
- * All we know is that card(s) have been inserted or removed
- * from the socket(s). We don't know which socket or cards.
- */
-void mmc_detect_change(struct mmc_host *host, unsigned long delay)
-{
- mmc_schedule_delayed_work(&host->detect, delay);
-}
-
-EXPORT_SYMBOL(mmc_detect_change);
-
-
-static void mmc_rescan(struct work_struct *work)
-{
- struct mmc_host *host =
- container_of(work, struct mmc_host, detect.work);
- struct list_head *l, *n;
- unsigned char power_mode;
-
- mmc_claim_host(host);
-
- /*
- * Check for removed cards and newly inserted ones. We check for
- * removed cards first so we can intelligently re-select the VDD.
- */
- power_mode = host->ios.power_mode;
- if (power_mode == MMC_POWER_ON)
- mmc_check_cards(host);
-
- mmc_setup(host);
-
- /*
- * Some broken cards process CMD1 even in stand-by state. There is
- * no reply, but an ILLEGAL_COMMAND error is cached and returned
- * after next command. We poll for card status here to clear any
- * possibly pending error.
- */
- if (power_mode == MMC_POWER_ON)
- mmc_check_cards(host);
-
- if (!list_empty(&host->cards)) {
- /*
- * (Re-)calculate the fastest clock rate which the
- * attached cards and the host support.
- */
- host->ios.clock = mmc_calculate_clock(host);
- mmc_set_ios(host);
- }
-
- mmc_release_host(host);
-
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
-
- /*
- * If this is a new and good card, register it.
- */
- if (!mmc_card_present(card) && !mmc_card_dead(card)) {
- if (mmc_register_card(card))
- mmc_card_set_dead(card);
- else
- mmc_card_set_present(card);
- }
-
- /*
- * If this card is dead, destroy it.
- */
- if (mmc_card_dead(card)) {
- list_del(&card->node);
- mmc_remove_card(card);
- }
- }
-
- /*
- * If we discover that there are no cards on the
- * bus, turn off the clock and power down.
- */
- if (list_empty(&host->cards))
- mmc_power_off(host);
-}
-
-
-/**
- * mmc_alloc_host - initialise the per-host structure.
- * @extra: sizeof private data structure
- * @dev: pointer to host device model structure
- *
- * Initialise the per-host structure.
- */
-struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
-{
- struct mmc_host *host;
-
- host = mmc_alloc_host_sysfs(extra, dev);
- if (host) {
- spin_lock_init(&host->lock);
- init_waitqueue_head(&host->wq);
- INIT_LIST_HEAD(&host->cards);
- INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-
- /*
- * By default, hosts do not support SGIO or large requests.
- * They have to set these according to their abilities.
- */
- host->max_hw_segs = 1;
- host->max_phys_segs = 1;
- host->max_seg_size = PAGE_CACHE_SIZE;
-
- host->max_req_size = PAGE_CACHE_SIZE;
- host->max_blk_size = 512;
- host->max_blk_count = PAGE_CACHE_SIZE / 512;
- }
-
- return host;
-}
-
-EXPORT_SYMBOL(mmc_alloc_host);
-
-/**
- * mmc_add_host - initialise host hardware
- * @host: mmc host
- */
-int mmc_add_host(struct mmc_host *host)
-{
- int ret;
-
- ret = mmc_add_host_sysfs(host);
- if (ret == 0) {
- mmc_power_off(host);
- mmc_detect_change(host, 0);
- }
-
- return ret;
-}
-
-EXPORT_SYMBOL(mmc_add_host);
-
-/**
- * mmc_remove_host - remove host hardware
- * @host: mmc host
- *
- * Unregister and remove all cards associated with this host,
- * and power down the MMC bus.
- */
-void mmc_remove_host(struct mmc_host *host)
-{
- struct list_head *l, *n;
-
- list_for_each_safe(l, n, &host->cards) {
- struct mmc_card *card = mmc_list_to_card(l);
-
- mmc_remove_card(card);
- }
-
- mmc_power_off(host);
- mmc_remove_host_sysfs(host);
-}
-
-EXPORT_SYMBOL(mmc_remove_host);
-
-/**
- * mmc_free_host - free the host structure
- * @host: mmc host
- *
- * Free the host once all references to it have been dropped.
- */
-void mmc_free_host(struct mmc_host *host)
-{
- mmc_flush_scheduled_work();
- mmc_free_host_sysfs(host);
-}
-
-EXPORT_SYMBOL(mmc_free_host);
-
-#ifdef CONFIG_PM
-
-/**
- * mmc_suspend_host - suspend a host
- * @host: mmc host
- * @state: suspend mode (PM_SUSPEND_xxx)
- */
-int mmc_suspend_host(struct mmc_host *host, pm_message_t state)
-{
- mmc_claim_host(host);
- mmc_deselect_cards(host);
- mmc_power_off(host);
- mmc_release_host(host);
-
- return 0;
-}
-
-EXPORT_SYMBOL(mmc_suspend_host);
-
-/**
- * mmc_resume_host - resume a previously suspended host
- * @host: mmc host
- */
-int mmc_resume_host(struct mmc_host *host)
-{
- mmc_rescan(&host->detect.work);
-
- return 0;
-}
-
-EXPORT_SYMBOL(mmc_resume_host);
-
-#endif
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
deleted file mode 100644
index 0581d09c58f..00000000000
--- a/drivers/mmc/tifm_sd.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * tifm_sd.c - TI FlashMedia driver
- *
- * Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
- *
- * 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/tifm.h>
-#include <linux/mmc/protocol.h>
-#include <linux/mmc/host.h>
-#include <linux/highmem.h>
-#include <asm/io.h>
-
-#define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.7"
-
-static int no_dma = 0;
-static int fixed_timeout = 0;
-module_param(no_dma, bool, 0644);
-module_param(fixed_timeout, bool, 0644);
-
-/* Constants here are mostly from OMAP5912 datasheet */
-#define TIFM_MMCSD_RESET 0x0002
-#define TIFM_MMCSD_CLKMASK 0x03ff
-#define TIFM_MMCSD_POWER 0x0800
-#define TIFM_MMCSD_4BBUS 0x8000
-#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
-#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
-#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
-#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
-#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
-#define TIFM_MMCSD_READ 0x8000
-
-#define TIFM_MMCSD_DATAMASK 0x401d /* set bits: CERR, EOFB, BRS, CB, EOC */
-#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */
-#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
-#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
-#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
-#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
-#define TIFM_MMCSD_DTO 0x0020 /* data time-out */
-#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
-#define TIFM_MMCSD_CTO 0x0080 /* command time-out */
-#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
-#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
-#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
-#define TIFM_MMCSD_CERR 0x4000 /* card status error */
-
-#define TIFM_MMCSD_FIFO_SIZE 0x0020
-
-#define TIFM_MMCSD_RSP_R0 0x0000
-#define TIFM_MMCSD_RSP_R1 0x0100
-#define TIFM_MMCSD_RSP_R2 0x0200
-#define TIFM_MMCSD_RSP_R3 0x0300
-#define TIFM_MMCSD_RSP_R4 0x0400
-#define TIFM_MMCSD_RSP_R5 0x0500
-#define TIFM_MMCSD_RSP_R6 0x0600
-
-#define TIFM_MMCSD_RSP_BUSY 0x0800
-
-#define TIFM_MMCSD_CMD_BC 0x0000
-#define TIFM_MMCSD_CMD_BCR 0x1000
-#define TIFM_MMCSD_CMD_AC 0x2000
-#define TIFM_MMCSD_CMD_ADTC 0x3000
-
-typedef enum {
- IDLE = 0,
- CMD, /* main command ended */
- BRS, /* block transfer finished */
- SCMD, /* stop command ended */
- CARD, /* card left busy state */
- FIFO, /* FIFO operation completed (uncertain) */
- READY
-} card_state_t;
-
-enum {
- FIFO_RDY = 0x0001, /* hardware dependent value */
- EJECT = 0x0004,
- EJECT_DONE = 0x0008,
- CARD_BUSY = 0x0010,
- OPENDRAIN = 0x0040, /* hardware dependent value */
- CARD_EVENT = 0x0100, /* hardware dependent value */
- CARD_RO = 0x0200, /* hardware dependent value */
- FIFO_EVENT = 0x10000 }; /* hardware dependent value */
-
-struct tifm_sd {
- struct tifm_dev *dev;
-
- unsigned int flags;
- card_state_t state;
- unsigned int clk_freq;
- unsigned int clk_div;
- unsigned long timeout_jiffies;
-
- struct tasklet_struct finish_tasklet;
- struct timer_list timer;
- struct mmc_request *req;
- wait_queue_head_t notify;
-
- size_t written_blocks;
- size_t buffer_size;
- size_t buffer_pos;
-
-};
-
-static char* tifm_sd_data_buffer(struct mmc_data *data)
-{
- return page_address(data->sg->page) + data->sg->offset;
-}
-
-static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
- unsigned int host_status)
-{
- struct mmc_command *cmd = host->req->cmd;
- unsigned int t_val = 0, cnt = 0;
- char *buffer;
-
- if (host_status & TIFM_MMCSD_BRS) {
- /* in non-dma rx mode BRS fires when fifo is still not empty */
- if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
- buffer = tifm_sd_data_buffer(host->req->data);
- while (host->buffer_size > host->buffer_pos) {
- t_val = readl(sock->addr + SOCK_MMCSD_DATA);
- buffer[host->buffer_pos++] = t_val & 0xff;
- buffer[host->buffer_pos++] =
- (t_val >> 8) & 0xff;
- }
- }
- return 1;
- } else if (no_dma) {
- buffer = tifm_sd_data_buffer(host->req->data);
- if ((cmd->data->flags & MMC_DATA_READ) &&
- (host_status & TIFM_MMCSD_AF)) {
- for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
- t_val = readl(sock->addr + SOCK_MMCSD_DATA);
- if (host->buffer_size > host->buffer_pos) {
- buffer[host->buffer_pos++] =
- t_val & 0xff;
- buffer[host->buffer_pos++] =
- (t_val >> 8) & 0xff;
- }
- }
- } else if ((cmd->data->flags & MMC_DATA_WRITE)
- && (host_status & TIFM_MMCSD_AE)) {
- for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
- if (host->buffer_size > host->buffer_pos) {
- t_val = buffer[host->buffer_pos++]
- & 0x00ff;
- t_val |= ((buffer[host->buffer_pos++])
- << 8) & 0xff00;
- writel(t_val,
- sock->addr + SOCK_MMCSD_DATA);
- }
- }
- }
- }
- return 0;
-}
-
-static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
-{
- unsigned int rc = 0;
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- rc |= TIFM_MMCSD_RSP_R0;
- break;
- case MMC_RSP_R1B:
- rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
- case MMC_RSP_R1:
- rc |= TIFM_MMCSD_RSP_R1;
- break;
- case MMC_RSP_R2:
- rc |= TIFM_MMCSD_RSP_R2;
- break;
- case MMC_RSP_R3:
- rc |= TIFM_MMCSD_RSP_R3;
- break;
- default:
- BUG();
- }
-
- switch (mmc_cmd_type(cmd)) {
- case MMC_CMD_BC:
- rc |= TIFM_MMCSD_CMD_BC;
- break;
- case MMC_CMD_BCR:
- rc |= TIFM_MMCSD_CMD_BCR;
- break;
- case MMC_CMD_AC:
- rc |= TIFM_MMCSD_CMD_AC;
- break;
- case MMC_CMD_ADTC:
- rc |= TIFM_MMCSD_CMD_ADTC;
- break;
- default:
- BUG();
- }
- return rc;
-}
-
-static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
-{
- struct tifm_dev *sock = host->dev;
- unsigned int cmd_mask = tifm_sd_op_flags(cmd) |
- (host->flags & OPENDRAIN);
-
- if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
- cmd_mask |= TIFM_MMCSD_READ;
-
- dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
- cmd->opcode, cmd->arg, cmd_mask);
-
- writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
- writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
- writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
-}
-
-static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
-{
- cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
- cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
- cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
- cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
-}
-
-static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
- unsigned int host_status)
-{
- struct mmc_command *cmd = host->req->cmd;
-
-change_state:
- switch (host->state) {
- case IDLE:
- return;
- case CMD:
- if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
- tifm_sd_fetch_resp(cmd, sock);
- if (cmd->data) {
- host->state = BRS;
- } else {
- host->state = READY;
- }
- goto change_state;
- }
- break;
- case BRS:
- if (tifm_sd_transfer_data(sock, host, host_status)) {
- if (cmd->data->flags & MMC_DATA_WRITE) {
- host->state = CARD;
- } else {
- if (no_dma) {
- if (host->req->stop) {
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
- } else {
- host->state = READY;
- }
- } else {
- host->state = FIFO;
- }
- }
- goto change_state;
- }
- break;
- case SCMD:
- if (host_status & TIFM_MMCSD_EOC) {
- tifm_sd_fetch_resp(host->req->stop, sock);
- host->state = READY;
- goto change_state;
- }
- break;
- case CARD:
- dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
- host->written_blocks);
- if (!(host->flags & CARD_BUSY)
- && (host->written_blocks == cmd->data->blocks)) {
- if (no_dma) {
- if (host->req->stop) {
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
- } else {
- host->state = READY;
- }
- } else {
- host->state = FIFO;
- }
- goto change_state;
- }
- break;
- case FIFO:
- if (host->flags & FIFO_RDY) {
- host->flags &= ~FIFO_RDY;
- if (host->req->stop) {
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
- } else {
- host->state = READY;
- }
- goto change_state;
- }
- break;
- case READY:
- tasklet_schedule(&host->finish_tasklet);
- return;
- }
-
-}
-
-/* Called from interrupt handler */
-static void tifm_sd_signal_irq(struct tifm_dev *sock,
- unsigned int sock_irq_status)
-{
- struct tifm_sd *host;
- unsigned int host_status = 0, fifo_status = 0;
- int error_code = 0;
-
- spin_lock(&sock->lock);
- host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
-
- if (sock_irq_status & FIFO_EVENT) {
- fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
- writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
-
- host->flags |= fifo_status & FIFO_RDY;
- }
-
- if (sock_irq_status & CARD_EVENT) {
- host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
- writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
-
- if (!host->req)
- goto done;
-
- if (host_status & TIFM_MMCSD_ERRMASK) {
- if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
- error_code = MMC_ERR_TIMEOUT;
- else if (host_status
- & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
- error_code = MMC_ERR_BADCRC;
-
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
-
- if (host->req->stop) {
- if (host->state == SCMD) {
- host->req->stop->error = error_code;
- } else if (host->state == BRS
- || host->state == CARD
- || host->state == FIFO) {
- host->req->cmd->error = error_code;
- tifm_sd_exec(host, host->req->stop);
- host->state = SCMD;
- goto done;
- } else {
- host->req->cmd->error = error_code;
- }
- } else {
- host->req->cmd->error = error_code;
- }
- host->state = READY;
- }
-
- if (host_status & TIFM_MMCSD_CB)
- host->flags |= CARD_BUSY;
- if ((host_status & TIFM_MMCSD_EOFB)
- && (host->flags & CARD_BUSY)) {
- host->written_blocks++;
- host->flags &= ~CARD_BUSY;
- }
- }
-
- if (host->req)
- tifm_sd_process_cmd(sock, host, host_status);
-done:
- dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
- host_status, fifo_status);
- spin_unlock(&sock->lock);
-}
-
-static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
-{
- struct tifm_dev *sock = host->dev;
- unsigned int dest_cnt;
-
- /* DMA style IO */
- dev_dbg(&sock->dev, "setting dma for %d blocks\n",
- cmd->data->blocks);
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(ilog2(cmd->data->blksz) - 2,
- sock->addr + SOCK_FIFO_PAGE_SIZE);
- writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
- writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-
- dest_cnt = (cmd->data->blocks) << 8;
-
- writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS);
-
- writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
-
- if (cmd->data->flags & MMC_DATA_WRITE) {
- writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
- writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
- sock->addr + SOCK_DMA_CONTROL);
- } else {
- writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
- writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
- }
-}
-
-static void tifm_sd_set_data_timeout(struct tifm_sd *host,
- struct mmc_data *data)
-{
- struct tifm_dev *sock = host->dev;
- unsigned int data_timeout = data->timeout_clks;
-
- if (fixed_timeout)
- return;
-
- data_timeout += data->timeout_ns /
- ((1000000000UL / host->clk_freq) * host->clk_div);
-
- if (data_timeout < 0xffff) {
- writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
- writel((~TIFM_MMCSD_DPE)
- & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
- } else {
- data_timeout = (data_timeout >> 10) + 1;
- if (data_timeout > 0xffff)
- data_timeout = 0; /* set to unlimited */
- writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
- writel(TIFM_MMCSD_DPE
- | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
- }
-}
-
-static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned long flags;
- int sg_count = 0;
- struct mmc_data *r_data = mrq->cmd->data;
-
- spin_lock_irqsave(&sock->lock, flags);
- if (host->flags & EJECT) {
- spin_unlock_irqrestore(&sock->lock, flags);
- goto err_out;
- }
-
- if (host->req) {
- printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
- spin_unlock_irqrestore(&sock->lock, flags);
- goto err_out;
- }
-
- if (r_data) {
- tifm_sd_set_data_timeout(host, r_data);
-
- sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len,
- mrq->cmd->flags & MMC_DATA_WRITE
- ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- if (sg_count != 1) {
- printk(KERN_ERR DRIVER_NAME
- ": scatterlist map failed\n");
- spin_unlock_irqrestore(&sock->lock, flags);
- goto err_out;
- }
-
- host->written_blocks = 0;
- host->flags &= ~CARD_BUSY;
- tifm_sd_prepare_data(host, mrq->cmd);
- }
-
- host->req = mrq;
- mod_timer(&host->timer, jiffies + host->timeout_jiffies);
- host->state = CMD;
- writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- tifm_sd_exec(host, mrq->cmd);
- spin_unlock_irqrestore(&sock->lock, flags);
- return;
-
-err_out:
- if (sg_count > 0)
- tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
- (r_data->flags & MMC_DATA_WRITE)
- ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
-
- mrq->cmd->error = MMC_ERR_TIMEOUT;
- mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_end_cmd(unsigned long data)
-{
- struct tifm_sd *host = (struct tifm_sd*)data;
- struct tifm_dev *sock = host->dev;
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct mmc_request *mrq;
- struct mmc_data *r_data = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
-
- del_timer(&host->timer);
- mrq = host->req;
- host->req = NULL;
- host->state = IDLE;
-
- if (!mrq) {
- printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
- spin_unlock_irqrestore(&sock->lock, flags);
- return;
- }
-
- r_data = mrq->cmd->data;
- if (r_data) {
- if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks
- * r_data->blksz;
- } else {
- r_data->bytes_xfered = r_data->blocks -
- readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
- r_data->bytes_xfered *= r_data->blksz;
- r_data->bytes_xfered += r_data->blksz -
- readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
- }
- tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
- (r_data->flags & MMC_DATA_WRITE)
- ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- }
-
- writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
-
- spin_unlock_irqrestore(&sock->lock, flags);
- mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned long flags;
- struct mmc_data *r_data = mrq->cmd->data;
-
- spin_lock_irqsave(&sock->lock, flags);
- if (host->flags & EJECT) {
- spin_unlock_irqrestore(&sock->lock, flags);
- goto err_out;
- }
-
- if (host->req) {
- printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
- spin_unlock_irqrestore(&sock->lock, flags);
- goto err_out;
- }
-
- if (r_data) {
- tifm_sd_set_data_timeout(host, r_data);
-
- host->buffer_size = mrq->cmd->data->blocks
- * mrq->cmd->data->blksz;
-
- writel(TIFM_MMCSD_BUFINT
- | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
- sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
- | (TIFM_MMCSD_FIFO_SIZE - 1),
- sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
- host->written_blocks = 0;
- host->flags &= ~CARD_BUSY;
- host->buffer_pos = 0;
- writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
- }
-
- host->req = mrq;
- mod_timer(&host->timer, jiffies + host->timeout_jiffies);
- host->state = CMD;
- writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- tifm_sd_exec(host, mrq->cmd);
- spin_unlock_irqrestore(&sock->lock, flags);
- return;
-
-err_out:
- mrq->cmd->error = MMC_ERR_TIMEOUT;
- mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_end_cmd_nodma(unsigned long data)
-{
- struct tifm_sd *host = (struct tifm_sd*)data;
- struct tifm_dev *sock = host->dev;
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct mmc_request *mrq;
- struct mmc_data *r_data = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
-
- del_timer(&host->timer);
- mrq = host->req;
- host->req = NULL;
- host->state = IDLE;
-
- if (!mrq) {
- printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
- spin_unlock_irqrestore(&sock->lock, flags);
- return;
- }
-
- r_data = mrq->cmd->data;
- if (r_data) {
- writel((~TIFM_MMCSD_BUFINT) &
- readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
- sock->addr + SOCK_MMCSD_INT_ENABLE);
-
- if (r_data->flags & MMC_DATA_WRITE) {
- r_data->bytes_xfered = host->written_blocks
- * r_data->blksz;
- } else {
- r_data->bytes_xfered = r_data->blocks -
- readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
- r_data->bytes_xfered *= r_data->blksz;
- r_data->bytes_xfered += r_data->blksz -
- readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
- }
- host->buffer_pos = 0;
- host->buffer_size = 0;
- }
-
- writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
-
- spin_unlock_irqrestore(&sock->lock, flags);
-
- mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_terminate(struct tifm_sd *host)
-{
- struct tifm_dev *sock = host->dev;
- unsigned long flags;
-
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- mmiowb();
- spin_lock_irqsave(&sock->lock, flags);
- host->flags |= EJECT;
- if (host->req) {
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
- tasklet_schedule(&host->finish_tasklet);
- }
- spin_unlock_irqrestore(&sock->lock, flags);
-}
-
-static void tifm_sd_abort(unsigned long data)
-{
- struct tifm_sd *host = (struct tifm_sd*)data;
-
- printk(KERN_ERR DRIVER_NAME
- ": card failed to respond for a long period of time");
-
- tifm_sd_terminate(host);
- tifm_eject(host->dev);
-}
-
-static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned int clk_div1, clk_div2;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
-
- dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width,
- ios->power_mode);
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
- sock->addr + SOCK_MMCSD_CONFIG);
- } else {
- writel((~TIFM_MMCSD_4BBUS)
- & readl(sock->addr + SOCK_MMCSD_CONFIG),
- sock->addr + SOCK_MMCSD_CONFIG);
- }
-
- if (ios->clock) {
- clk_div1 = 20000000 / ios->clock;
- if (!clk_div1)
- clk_div1 = 1;
-
- clk_div2 = 24000000 / ios->clock;
- if (!clk_div2)
- clk_div2 = 1;
-
- if ((20000000 / clk_div1) > ios->clock)
- clk_div1++;
- if ((24000000 / clk_div2) > ios->clock)
- clk_div2++;
- if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
- host->clk_freq = 20000000;
- host->clk_div = clk_div1;
- writel((~TIFM_CTRL_FAST_CLK)
- & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- } else {
- host->clk_freq = 24000000;
- host->clk_div = clk_div2;
- writel(TIFM_CTRL_FAST_CLK
- | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- }
- } else {
- host->clk_div = 0;
- }
- host->clk_div &= TIFM_MMCSD_CLKMASK;
- writel(host->clk_div
- | ((~TIFM_MMCSD_CLKMASK)
- & readl(sock->addr + SOCK_MMCSD_CONFIG)),
- sock->addr + SOCK_MMCSD_CONFIG);
-
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
- host->flags |= OPENDRAIN;
- else
- host->flags &= ~OPENDRAIN;
-
- /* chip_select : maybe later */
- //vdd
- //power is set before probe / after remove
- //I believe, power_off when already marked for eject is sufficient to
- // allow removal.
- if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
- host->flags |= EJECT_DONE;
- wake_up_all(&host->notify);
- }
-
- spin_unlock_irqrestore(&sock->lock, flags);
-}
-
-static int tifm_sd_ro(struct mmc_host *mmc)
-{
- int rc;
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
-
- host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE));
- rc = (host->flags & CARD_RO) ? 1 : 0;
-
- spin_unlock_irqrestore(&sock->lock, flags);
- return rc;
-}
-
-static struct mmc_host_ops tifm_sd_ops = {
- .request = tifm_sd_request,
- .set_ios = tifm_sd_ios,
- .get_ro = tifm_sd_ro
-};
-
-static int tifm_sd_initialize_host(struct tifm_sd *host)
-{
- int rc;
- unsigned int host_status = 0;
- struct tifm_dev *sock = host->dev;
-
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- mmiowb();
- host->clk_div = 61;
- host->clk_freq = 20000000;
- writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
-
- /* wait up to 0.51 sec for reset */
- for (rc = 2; rc <= 256; rc <<= 1) {
- if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
- rc = 0;
- break;
- }
- msleep(rc);
- }
-
- if (rc) {
- printk(KERN_ERR DRIVER_NAME
- ": controller failed to reset\n");
- return -ENODEV;
- }
-
- writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
- writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
- // command timeout fixed to 64 clocks for now
- writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
- writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
-
- /* INAB should take much less than reset */
- for (rc = 1; rc <= 16; rc <<= 1) {
- host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
- writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
- if (!(host_status & TIFM_MMCSD_ERRMASK)
- && (host_status & TIFM_MMCSD_EOC)) {
- rc = 0;
- break;
- }
- msleep(rc);
- }
-
- if (rc) {
- printk(KERN_ERR DRIVER_NAME
- ": card not ready - probe failed on initialization\n");
- return -ENODEV;
- }
-
- writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
- sock->addr + SOCK_MMCSD_INT_ENABLE);
- mmiowb();
-
- return 0;
-}
-
-static int tifm_sd_probe(struct tifm_dev *sock)
-{
- struct mmc_host *mmc;
- struct tifm_sd *host;
- int rc = -EIO;
-
- if (!(TIFM_SOCK_STATE_OCCUPIED
- & readl(sock->addr + SOCK_PRESENT_STATE))) {
- printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
- return rc;
- }
-
- mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
- if (!mmc)
- return -ENOMEM;
-
- host = mmc_priv(mmc);
- tifm_set_drvdata(sock, mmc);
- host->dev = sock;
- host->timeout_jiffies = msecs_to_jiffies(1000);
-
- init_waitqueue_head(&host->notify);
- tasklet_init(&host->finish_tasklet,
- no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
- (unsigned long)host);
- setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
-
- tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
- mmc->ops = &tifm_sd_ops;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
- mmc->f_min = 20000000 / 60;
- mmc->f_max = 24000000;
- mmc->max_hw_segs = 1;
- mmc->max_phys_segs = 1;
- // limited by DMA counter - it's safer to stick with
- // block counter has 11 bits though
- mmc->max_blk_count = 256;
- // 2k maximum hw block length
- mmc->max_blk_size = 2048;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_seg_size = mmc->max_req_size;
- sock->signal_irq = tifm_sd_signal_irq;
- rc = tifm_sd_initialize_host(host);
-
- if (!rc)
- rc = mmc_add_host(mmc);
- if (rc)
- goto out_free_mmc;
-
- return 0;
-out_free_mmc:
- mmc_free_host(mmc);
- return rc;
-}
-
-static void tifm_sd_remove(struct tifm_dev *sock)
-{
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
-
- del_timer_sync(&host->timer);
- tifm_sd_terminate(host);
- wait_event_timeout(host->notify, host->flags & EJECT_DONE,
- host->timeout_jiffies);
- tasklet_kill(&host->finish_tasklet);
- mmc_remove_host(mmc);
-
- /* The meaning of the bit majority in this constant is unknown. */
- writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
-
- tifm_set_drvdata(sock, NULL);
- mmc_free_host(mmc);
-}
-
-#ifdef CONFIG_PM
-
-static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
-{
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- int rc;
-
- rc = mmc_suspend_host(mmc, state);
- /* The meaning of the bit majority in this constant is unknown. */
- writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- return rc;
-}
-
-static int tifm_sd_resume(struct tifm_dev *sock)
-{
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
-
- if (sock->media_id != FM_SD
- || tifm_sd_initialize_host(host)) {
- tifm_eject(sock);
- return 0;
- } else {
- return mmc_resume_host(mmc);
- }
-}
-
-#else
-
-#define tifm_sd_suspend NULL
-#define tifm_sd_resume NULL
-
-#endif /* CONFIG_PM */
-
-static tifm_media_id tifm_sd_id_tbl[] = {
- FM_SD, 0
-};
-
-static struct tifm_driver tifm_sd_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE
- },
- .id_table = tifm_sd_id_tbl,
- .probe = tifm_sd_probe,
- .remove = tifm_sd_remove,
- .suspend = tifm_sd_suspend,
- .resume = tifm_sd_resume
-};
-
-static int __init tifm_sd_init(void)
-{
- return tifm_register_driver(&tifm_sd_driver);
-}
-
-static void __exit tifm_sd_exit(void)
-{
- tifm_unregister_driver(&tifm_sd_driver);
-}
-
-MODULE_AUTHOR("Alex Dubov");
-MODULE_DESCRIPTION("TI FlashMedia SD driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
-MODULE_VERSION(DRIVER_VERSION);
-
-module_init(tifm_sd_init);
-module_exit(tifm_sd_exit);
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 690c94236d7..ff642f8fbee 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -49,8 +49,8 @@ config MTD_MS02NV
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt>. The module will
- be called ms02-nv.o.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
+ The module will be called ms02-nv.ko.
config MTD_DATAFLASH
tristate "Support for AT45xxx DataFlash"
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 4070720561f..be4b9948c76 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -40,13 +40,11 @@ struct block2mtd_dev {
static LIST_HEAD(blkmtd_device_list);
-static struct page* page_read(struct address_space *mapping, int index)
+static struct page *page_read(struct address_space *mapping, int index)
{
- filler_t *filler = (filler_t*)mapping->a_ops->readpage;
- return read_cache_page(mapping, index, filler, NULL);
+ return read_mapping_page(mapping, index, NULL);
}
-
/* erase a specified part of the device */
static int _block2mtd_erase(struct block2mtd_dev *dev, loff_t to, size_t len)
{
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index 8a0c4dec635..c73e96bfafc 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -13,7 +13,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/sched.h>
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 6f368aec5d5..6413efc045e 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -13,7 +13,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 88ba82df0fb..2b30b587c6e 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -17,7 +17,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c
index 52b5d638077..fd8a8daba3a 100644
--- a/drivers/mtd/devices/docecc.c
+++ b/drivers/mtd/devices/docecc.c
@@ -29,7 +29,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index acf3ba22329..ecac0e438f4 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -31,7 +31,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index aab5506adfa..b665e4ac220 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -60,7 +60,7 @@ config MTD_PHYSMAP_BANKWIDTH
(i.e., run-time calling physmap_configure()).
config MTD_PHYSMAP_OF
- tristate "Flash device in physical memory map based on OF descirption"
+ tristate "Flash device in physical memory map based on OF description"
depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
help
This provides a 'mapping' driver which allows the NOR Flash and
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 9f53c655af3..7b96cd02f82 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -358,7 +358,7 @@ int __init nettel_init(void)
/* Turn other PAR off so the first probe doesn't find it */
*intel1par = 0;
- /* Probe for the the size of the first Intel flash */
+ /* Probe for the size of the first Intel flash */
nettel_intel_map.size = maxsize;
nettel_intel_map.phys = intel0addr;
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 8ec2fbe1074..bbb42c35b69 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -48,7 +48,7 @@ static int parse_flash_partitions(struct device_node *node,
const u32 *part;
const char *name;
- part = get_property(node, "partitions", &plen);
+ part = of_get_property(node, "partitions", &plen);
if (part == NULL)
goto err;
@@ -59,7 +59,7 @@ static int parse_flash_partitions(struct device_node *node,
goto err;
}
- name = get_property(node, "partition-names", &plen);
+ name = of_get_property(node, "partition-names", &plen);
for (i = 0; i < retval; i++) {
(*parts)[i].offset = *part++;
@@ -153,7 +153,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
goto err_out;
}
- width = get_property(dp, "bank-width", NULL);
+ width = of_get_property(dp, "bank-width", NULL);
if (width == NULL) {
dev_err(&dev->dev, "Can't get the flash bank width!\n");
err = -EINVAL;
@@ -174,7 +174,7 @@ static int __devinit of_physmap_probe(struct of_device *dev, const struct of_dev
simple_map_init(&info->map);
- of_probe = get_property(dp, "probe-type", NULL);
+ of_probe = of_get_property(dp, "probe-type", NULL);
if (of_probe == NULL) {
probe_type = rom_probe_types;
for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 524b83b5ebf..51bc7e2f1f2 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -216,7 +216,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
int last_devnum = -1;
struct gendisk *gd;
- if (!!mutex_trylock(&mtd_table_mutex)) {
+ if (mutex_trylock(&mtd_table_mutex)) {
mutex_unlock(&mtd_table_mutex);
BUG();
}
@@ -294,7 +294,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old)
{
- if (!!mutex_trylock(&mtd_table_mutex)) {
+ if (mutex_trylock(&mtd_table_mutex)) {
mutex_unlock(&mtd_table_mutex);
BUG();
}
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index 8296305c829..89deff00711 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -20,7 +20,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
-#include <linux/pci.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index e6ef7d7f9f1..0c9ce19ea27 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -17,7 +17,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/init.h>
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 000794c6caf..0537fac8de7 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -2192,7 +2192,7 @@ static int onenand_check_maf(int manuf)
* @param mtd MTD device structure
*
* OneNAND detection method:
- * Compare the the values from command with ones from register
+ * Compare the values from command with ones from register
*/
static int onenand_probe(struct mtd_info *mtd)
{
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index d847ee1da3d..3dba5733ed1 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -940,8 +940,7 @@ static void ltree_entry_ctor(void *obj, struct kmem_cache *cache,
{
struct ltree_entry *le = obj;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) !=
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
return;
le->users = 0;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index c7511c4d3b6..127f60841b1 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -83,7 +83,6 @@ static int max_interrupt_work = 10;
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/pm.h>
-#include <linux/pm_legacy.h>
#include <linux/skbuff.h>
#include <linux/delay.h> /* for udelay() */
#include <linux/spinlock.h>
@@ -96,8 +95,7 @@ static int max_interrupt_work = 10;
#include <asm/io.h>
#include <asm/irq.h>
-static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
-static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n";
+static char version[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n";
#if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA))
#define EL3_SUSPEND
@@ -361,7 +359,7 @@ static int __init el3_common_init(struct net_device *dev)
printk(", IRQ %d.\n", dev->irq);
if (el3_debug > 0)
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s", version);
return 0;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80924f76dee..f26ca331615 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -103,7 +103,7 @@ static int vortex_debug = 1;
static char version[] __devinitdata =
-DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n";
+DRV_NAME ": Donald Becker and others.\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index d396f996af5..0877fc372f4 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -565,9 +565,9 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
ib->btx_ring [entry].length = (-len) | 0xf000;
ib->btx_ring [entry].misc = 0;
- if (skb->len < ETH_ZLEN)
- memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
- skb_copy_from_linear_data(skb, &ib->tx_buf[entry][0], skblen);
+ if (skb->len < ETH_ZLEN)
+ memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
+ skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen);
/* Now, give the packet to the lance */
ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index a3d46ea3712..b86ccd2ecd5 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -311,7 +311,7 @@ config MAC8390
config MAC89x0
tristate "Macintosh CS89x0 based ethernet cards"
- depends on NET_ETHERNET && MAC && BROKEN
+ depends on NET_ETHERNET && MAC
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
Nubus or LC-PDS network (Ethernet) card of this type, say Y and
@@ -337,8 +337,8 @@ config MACSONIC
be called macsonic.
config MACMACE
- bool "Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)"
- depends on NET_ETHERNET && MAC && EXPERIMENTAL
+ bool "Macintosh (AV) onboard MACE ethernet"
+ depends on NET_ETHERNET && MAC
select CRC32
help
Support for the onboard AMD 79C940 MACE Ethernet controller used in
@@ -486,8 +486,8 @@ config SGI_IOC3_ETH_HW_TX_CSUM
enables offloading for checksums on transmit. If unsure, say Y.
config MIPS_SIM_NET
- tristate "MIPS simulator Network device (EXPERIMENTAL)"
- depends on MIPS_SIM && EXPERIMENTAL
+ tristate "MIPS simulator Network device"
+ depends on NET_ETHERNET && MIPS_SIM
help
The MIPSNET device is a simple Ethernet network device which is
emulated by the MIPS Simulator.
@@ -822,7 +822,7 @@ config SMC91X
tristate "SMC 91C9x/91C1xxx support"
select CRC32
select MII
- depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00)
+ depends on NET_ETHERNET && (ARM || REDWOOD_5 || REDWOOD_6 || M32R || SUPERH || SOC_AU1X00 || BFIN)
help
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
@@ -833,8 +833,8 @@ config SMC91X
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called smc91x. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt> as well
- as <file:Documentation/networking/net-modules.txt>.
+ module, say M here and read <file:Documentation/kbuild/modules.txt>
+ as well as <file:Documentation/networking/net-modules.txt>.
config SMC9194
tristate "SMC 9194 support"
@@ -889,7 +889,7 @@ config SMC911X
This driver is also available as a module. The module will be
called smc911x. If you want to compile it as a module, say M
- here and read <file:Documentation/modules.txt>
+ here and read <file:Documentation/kbuild/modules.txt>
config NET_VENDOR_RACAL
bool "Racal-Interlan (Micom) NI cards"
@@ -1104,7 +1104,7 @@ config ETH16I
config NE2000
tristate "NE2000/NE1000 support"
- depends on NET_ISA || (Q40 && m) || M32R
+ depends on NET_ISA || (Q40 && m) || M32R || TOSHIBA_RBTX4927 || TOSHIBA_RBTX4938
select CRC32
---help---
If you have a network (Ethernet) card of this type, say Y and read
@@ -1444,7 +1444,8 @@ config CS89x0
config TC35815
tristate "TOSHIBA TC35815 Ethernet support"
- depends on NET_PCI && PCI && TOSHIBA_JMR3927
+ depends on NET_PCI && PCI && MIPS
+ select MII
config DGRS
tristate "Digi Intl. RightSwitch SE-X support"
@@ -2273,11 +2274,12 @@ config GFAR_NAPI
depends on GIANFAR
config UCC_GETH
- tristate "Freescale QE UCC GETH"
- depends on QUICC_ENGINE && UCC_FAST
+ tristate "Freescale QE Gigabit Ethernet"
+ depends on QUICC_ENGINE
+ select UCC_FAST
help
- This driver supports the Gigabit Ethernet mode of QE UCC.
- QE can be found on MPC836x CPUs.
+ This driver supports the Gigabit Ethernet mode of the QUICC Engine,
+ which is available on some Freescale SOCs.
config UGETH_NAPI
bool "NAPI Support"
@@ -2291,14 +2293,10 @@ config UGETH_FILTERING
bool "Mac address filtering support"
depends on UCC_GETH
-config UGETH_TX_ON_DEMOND
- bool "Transmit on Demond support"
+config UGETH_TX_ON_DEMAND
+ bool "Transmit on Demand support"
depends on UCC_GETH
-config UGETH_HAS_GIGA
- bool
- depends on UCC_GETH && PPC_MPC836x
-
config MV643XX_ETH
tristate "MV-643XX Ethernet support"
depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
@@ -2490,6 +2488,7 @@ config NETXEN_NIC
config PASEMI_MAC
tristate "PA Semi 1/10Gbit MAC"
depends on PPC64 && PCI
+ select PHYLIB
help
This driver supports the on-chip 1/10Gbit Ethernet controller on
PA Semi's PWRficient line of chips.
@@ -2929,11 +2928,6 @@ endif #NETDEVICES
config NETPOLL
def_bool NETCONSOLE
-config NETPOLL_RX
- bool "Netpoll support for trapping incoming packets"
- default n
- depends on NETPOLL
-
config NETPOLL_TRAP
bool "Netpoll traffic trapping"
default n
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 58527322a39..59c0459a037 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \
gianfar_sysfs.o
obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o
#
# link order important here
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index dd8ed456c8b..1c3e293fbaf 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -83,7 +83,6 @@ extern struct net_device *bagetlance_probe(int unit);
extern struct net_device *mvme147lance_probe(int unit);
extern struct net_device *tc515_probe(int unit);
extern struct net_device *lance_probe(int unit);
-extern struct net_device *mace_probe(int unit);
extern struct net_device *mac8390_probe(int unit);
extern struct net_device *mac89x0_probe(int unit);
extern struct net_device *mc32_probe(int unit);
@@ -274,9 +273,6 @@ static struct devprobe2 m68k_probes[] __initdata = {
#ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */
{mvme147lance_probe, 0},
#endif
-#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */
- {mace_probe, 0},
-#endif
#ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */
{mac8390_probe, 0},
#endif
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 1226cbba045..81d5a374042 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -562,7 +562,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
volatile struct lance_init_block *ib = lp->init_block;
int entry, skblen, len;
int status = 0;
- static int outs;
unsigned long flags;
skblen = skb->len;
@@ -598,17 +597,16 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
ib->btx_ring [entry].length = (-len) | 0xf000;
ib->btx_ring [entry].misc = 0;
- skb_copy_from_linear_data(skb, &ib->tx_buf [entry][0], skblen);
+ skb_copy_from_linear_data(skb, (void *)&ib->tx_buf [entry][0], skblen);
/* Clear the slack of the packet, do I need this? */
if (len != skblen)
- memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
+ memset ((void *) &ib->tx_buf [entry][skblen], 0, len - skblen);
/* Now, give the packet to the lance */
ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
-
- outs++;
+ lp->stats.tx_bytes += skblen;
if (TX_BUFFS_AVAIL <= 0)
netif_stop_queue(dev);
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index a0e68e71853..a241ae7855a 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -677,6 +677,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev)
priv->cur_tx -= TX_RING_SIZE;
priv->dirty_tx -= TX_RING_SIZE;
}
+ priv->stats.tx_bytes += len;
/* Trigger an immediate send poll. */
lance->RAP = CSR0; /* PCnet-ISA Controller Status */
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 152fa7a042b..ef2cc80256a 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -225,6 +225,16 @@ static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
if (!(phy & ((1 << 2) | 1)))
goto done;
}
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* ack interrupt in Teridian PHY */
+ read_phy(lp->phy_address, MII_T78Q21INT_REG, &phy);
+ if (!(phy & ((1 << 2) | 1)))
+ goto done;
+ }
+ else if (lp->phy_type == MII_DP83848_ID) {
+ read_phy(lp->phy_address, MII_DPPHYSTS_REG, &phy); /* ack interrupt in DP83848 PHY */
+ if (!(phy & (1 << 7)))
+ goto done;
+ }
update_linkspeed(dev, 0);
@@ -280,6 +290,19 @@ static void enable_phyirq(struct net_device *dev)
dsintr = (1 << 10) | ( 1 << 8);
write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
}
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
+ read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+ dsintr = dsintr | 0x500; /* set bits 8, 10 */
+ write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
+ read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
+ dsintr = dsintr | 0x3c; /* set bits 2..5 */
+ write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+ read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
+ dsintr = dsintr | 0x3; /* set bits 0,1 */
+ write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+ }
disable_mdi();
spin_unlock_irq(&lp->lock);
@@ -323,6 +346,19 @@ static void disable_phyirq(struct net_device *dev)
dsintr = ~((1 << 10) | (1 << 8));
write_phy(lp->phy_address, MII_TPISTATUS, dsintr);
}
+ else if (lp->phy_type == MII_T78Q21x3_ID) { /* for Teridian PHY */
+ read_phy(lp->phy_address, MII_T78Q21INT_REG, &dsintr);
+ dsintr = dsintr & ~0x500; /* clear bits 8, 10 */
+ write_phy(lp->phy_address, MII_T78Q21INT_REG, dsintr);
+ }
+ else if (lp->phy_type == MII_DP83848_ID) { /* National Semiconductor DP83848 PHY */
+ read_phy(lp->phy_address, MII_DPMICR_REG, &dsintr);
+ dsintr = dsintr & ~0x3; /* clear bits 0, 1 */
+ write_phy(lp->phy_address, MII_DPMICR_REG, dsintr);
+ read_phy(lp->phy_address, MII_DPMISR_REG, &dsintr);
+ dsintr = dsintr & ~0x3c; /* clear bits 2..5 */
+ write_phy(lp->phy_address, MII_DPMISR_REG, dsintr);
+ }
disable_mdi();
spin_unlock_irq(&lp->lock);
@@ -535,8 +571,8 @@ static void at91ether_sethashtable(struct net_device *dev)
mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
}
- at91_emac_write(AT91_EMAC_HSH, mc_filter[0]);
- at91_emac_write(AT91_EMAC_HSL, mc_filter[1]);
+ at91_emac_write(AT91_EMAC_HSL, mc_filter[0]);
+ at91_emac_write(AT91_EMAC_HSH, mc_filter[1]);
}
/*
@@ -1062,10 +1098,16 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name);
else if (phy_type == MII_DP83847_ID)
printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name);
+ else if (phy_type == MII_DP83848_ID)
+ printk(KERN_INFO "%s: National Semiconductor DP83848 PHY\n", dev->name);
else if (phy_type == MII_AC101L_ID)
printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name);
else if (phy_type == MII_KS8721_ID)
printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name);
+ else if (phy_type == MII_T78Q21x3_ID)
+ printk(KERN_INFO "%s: Teridian 78Q21x3 PHY\n", dev->name);
+ else if (phy_type == MII_LAN83C185_ID)
+ printk(KERN_INFO "%s: SMSC LAN83C185 PHY\n", dev->name);
return 0;
}
@@ -1103,8 +1145,11 @@ static int __init at91ether_probe(struct platform_device *pdev)
case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
case MII_DP83847_ID: /* National Semiconductor DP83847: */
+ case MII_DP83848_ID: /* National Semiconductor DP83848: */
case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
+ case MII_T78Q21x3_ID: /* Teridian 78Q21x3: PHY_ID1 = 0x0E, PHY_ID2 = 7237 */
+ case MII_LAN83C185_ID: /* SMSC LAN83C185: PHY_ID1 = 0x0007, PHY_ID2 = 0xC0A1 */
detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
break;
}
diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h
index b6b665de2ea..a38fd2d053a 100644
--- a/drivers/net/arm/at91_ether.h
+++ b/drivers/net/arm/at91_ether.h
@@ -17,39 +17,46 @@
/* Davicom 9161 PHY */
-#define MII_DM9161_ID 0x0181b880
-#define MII_DM9161A_ID 0x0181b8a0
-
-/* Davicom specific registers */
-#define MII_DSCR_REG 16
-#define MII_DSCSR_REG 17
-#define MII_DSINTR_REG 21
+#define MII_DM9161_ID 0x0181b880
+#define MII_DM9161A_ID 0x0181b8a0
+#define MII_DSCR_REG 16
+#define MII_DSCSR_REG 17
+#define MII_DSINTR_REG 21
/* Intel LXT971A PHY */
-#define MII_LXT971A_ID 0x001378E0
-
-/* Intel specific registers */
-#define MII_ISINTE_REG 18
-#define MII_ISINTS_REG 19
-#define MII_LEDCTRL_REG 20
+#define MII_LXT971A_ID 0x001378E0
+#define MII_ISINTE_REG 18
+#define MII_ISINTS_REG 19
+#define MII_LEDCTRL_REG 20
/* Realtek RTL8201 PHY */
-#define MII_RTL8201_ID 0x00008200
+#define MII_RTL8201_ID 0x00008200
/* Broadcom BCM5221 PHY */
-#define MII_BCM5221_ID 0x004061e0
-
-/* Broadcom specific registers */
-#define MII_BCMINTR_REG 26
+#define MII_BCM5221_ID 0x004061e0
+#define MII_BCMINTR_REG 26
/* National Semiconductor DP83847 */
-#define MII_DP83847_ID 0x20005c30
+#define MII_DP83847_ID 0x20005c30
+
+/* National Semiconductor DP83848 */
+#define MII_DP83848_ID 0x20005c90
+#define MII_DPPHYSTS_REG 16
+#define MII_DPMICR_REG 17
+#define MII_DPMISR_REG 18
/* Altima AC101L PHY */
-#define MII_AC101L_ID 0x00225520
+#define MII_AC101L_ID 0x00225520
/* Micrel KS8721 PHY */
-#define MII_KS8721_ID 0x00221610
+#define MII_KS8721_ID 0x00221610
+
+/* Teridian 78Q2123/78Q2133 */
+#define MII_T78Q21x3_ID 0x000e7230
+#define MII_T78Q21INT_REG 17
+
+/* SMSC LAN83C185 */
+#define MII_LAN83C185_ID 0x0007C0A0
/* ........................................................................ */
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
index c11c27798e5..1f616c5c147 100644
--- a/drivers/net/atl1/atl1_ethtool.c
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -156,8 +156,7 @@ static int atl1_set_settings(struct net_device *netdev,
u16 old_media_type = hw->media_type;
if (netif_running(adapter->netdev)) {
- printk(KERN_DEBUG "%s: ethtool shutting down adapter\n",
- atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "ethtool shutting down adapter\n");
atl1_down(adapter);
}
@@ -166,9 +165,8 @@ static int atl1_set_settings(struct net_device *netdev,
else {
if (ecmd->speed == SPEED_1000) {
if (ecmd->duplex != DUPLEX_FULL) {
- printk(KERN_WARNING
- "%s: can't force to 1000M half duplex\n",
- atl1_driver_name);
+ dev_warn(&adapter->pdev->dev,
+ "can't force to 1000M half duplex\n");
ret_val = -EINVAL;
goto exit_sset;
}
@@ -206,9 +204,8 @@ static int atl1_set_settings(struct net_device *netdev,
}
if (atl1_phy_setup_autoneg_adv(hw)) {
ret_val = -EINVAL;
- printk(KERN_WARNING
- "%s: invalid ethtool speed/duplex setting\n",
- atl1_driver_name);
+ dev_warn(&adapter->pdev->dev,
+ "invalid ethtool speed/duplex setting\n");
goto exit_sset;
}
if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
@@ -239,12 +236,10 @@ exit_sset:
hw->media_type = old_media_type;
if (netif_running(adapter->netdev)) {
- printk(KERN_DEBUG "%s: ethtool starting adapter\n",
- atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "ethtool starting adapter\n");
atl1_up(adapter);
} else if (!ret_val) {
- printk(KERN_DEBUG "%s: ethtool resetting adapter\n",
- atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "ethtool resetting adapter\n");
atl1_reset(adapter);
}
return ret_val;
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
index 69482e0d849..ef886bdeac1 100644
--- a/drivers/net/atl1/atl1_hw.c
+++ b/drivers/net/atl1/atl1_hw.c
@@ -2,20 +2,20 @@
* Copyright(c) 2005 - 2006 Attansic Corporation. All rights reserved.
* Copyright(c) 2006 Chris Snook <csnook@redhat.com>
* Copyright(c) 2006 Jay Cliburn <jcliburn@gmail.com>
- *
+ *
* Derived from Intel e1000 driver
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
- *
+ *
* 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., 59
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
@@ -38,12 +38,13 @@
*/
s32 atl1_reset_hw(struct atl1_hw *hw)
{
+ struct pci_dev *pdev = hw->back->pdev;
u32 icr;
int i;
- /*
+ /*
* Clear Interrupt mask to stop board from generating
- * interrupts & Clear any pending interrupt events
+ * interrupts & Clear any pending interrupt events
*/
/*
* iowrite32(0, hw->hw_addr + REG_IMR);
@@ -74,7 +75,7 @@ s32 atl1_reset_hw(struct atl1_hw *hw)
}
if (icr) {
- printk (KERN_DEBUG "icr = %x\n", icr);
+ dev_dbg(&pdev->dev, "ICR = 0x%x\n", icr);
return icr;
}
@@ -136,8 +137,8 @@ s32 atl1_read_phy_reg(struct atl1_hw *hw, u16 reg_addr, u16 *phy_data)
int i;
val = ((u32) (reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
- MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
- MDIO_CLK_SEL_SHIFT;
+ MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | MDIO_CLK_25_4 <<
+ MDIO_CLK_SEL_SHIFT;
iowrite32(val, hw->hw_addr + REG_MDIO_CTRL);
ioread32(hw->hw_addr + REG_MDIO_CTRL);
@@ -204,7 +205,7 @@ static bool atl1_spi_read(struct atl1_hw *hw, u32 addr, u32 *buf)
/*
* get_permanent_address
- * return 0 if get valid mac address,
+ * return 0 if get valid mac address,
*/
static int atl1_get_permanent_address(struct atl1_hw *hw)
{
@@ -301,7 +302,7 @@ static int atl1_get_permanent_address(struct atl1_hw *hw)
}
/*
- * Reads the adapter's MAC address from the EEPROM
+ * Reads the adapter's MAC address from the EEPROM
* hw - Struct containing variables accessed by shared code
*/
s32 atl1_read_mac_addr(struct atl1_hw *hw)
@@ -437,6 +438,7 @@ s32 atl1_phy_enter_power_saving(struct atl1_hw *hw)
*/
static s32 atl1_phy_reset(struct atl1_hw *hw)
{
+ struct pci_dev *pdev = hw->back->pdev;
s32 ret_val;
u16 phy_data;
@@ -468,8 +470,7 @@ static s32 atl1_phy_reset(struct atl1_hw *hw)
u32 val;
int i;
/* pcie serdes link may be down! */
- printk(KERN_DEBUG "%s: autoneg caused pcie phy link down\n",
- atl1_driver_name);
+ dev_dbg(&pdev->dev, "pcie phy link down\n");
for (i = 0; i < 25; i++) {
msleep(1);
@@ -479,9 +480,7 @@ static s32 atl1_phy_reset(struct atl1_hw *hw)
}
if ((val & (MDIO_START | MDIO_BUSY)) != 0) {
- printk(KERN_WARNING
- "%s: pcie link down at least for 25ms\n",
- atl1_driver_name);
+ dev_warn(&pdev->dev, "pcie link down at least 25ms\n");
return ret_val;
}
}
@@ -571,6 +570,7 @@ s32 atl1_phy_setup_autoneg_adv(struct atl1_hw *hw)
*/
static s32 atl1_setup_link(struct atl1_hw *hw)
{
+ struct pci_dev *pdev = hw->back->pdev;
s32 ret_val;
/*
@@ -581,15 +581,13 @@ static s32 atl1_setup_link(struct atl1_hw *hw)
*/
ret_val = atl1_phy_setup_autoneg_adv(hw);
if (ret_val) {
- printk(KERN_DEBUG "%s: error setting up autonegotiation\n",
- atl1_driver_name);
+ dev_dbg(&pdev->dev, "error setting up autonegotiation\n");
return ret_val;
}
/* SW.Reset , En-Auto-Neg if needed */
ret_val = atl1_phy_reset(hw);
if (ret_val) {
- printk(KERN_DEBUG "%s: error resetting the phy\n",
- atl1_driver_name);
+ dev_dbg(&pdev->dev, "error resetting phy\n");
return ret_val;
}
hw->phy_configured = true;
@@ -631,7 +629,7 @@ static void atl1_init_flash_opcode(struct atl1_hw *hw)
* Performs basic configuration of the adapter.
* hw - Struct containing variables accessed by shared code
* Assumes that the controller has previously been reset and is in a
- * post-reset uninitialized state. Initializes multicast table,
+ * post-reset uninitialized state. Initializes multicast table,
* and Calls routines to setup link
* Leaves the transmit and receive units disabled and uninitialized.
*/
@@ -669,6 +667,7 @@ s32 atl1_init_hw(struct atl1_hw *hw)
*/
s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
{
+ struct pci_dev *pdev = hw->back->pdev;
s32 ret_val;
u16 phy_data;
@@ -691,8 +690,7 @@ s32 atl1_get_speed_and_duplex(struct atl1_hw *hw, u16 *speed, u16 *duplex)
*speed = SPEED_10;
break;
default:
- printk(KERN_DEBUG "%s: error getting speed\n",
- atl1_driver_name);
+ dev_dbg(&pdev->dev, "error getting speed\n");
return ATL1_ERR_PHY_SPEED;
break;
}
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index 4b1d4d153ec..d28f88bbdd5 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -188,8 +188,7 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
size = sizeof(struct atl1_buffer) * (tpd_ring->count + rfd_ring->count);
tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
if (unlikely(!tpd_ring->buffer_info)) {
- printk(KERN_WARNING "%s: kzalloc failed , size = D%d\n",
- atl1_driver_name, size);
+ dev_err(&pdev->dev, "kzalloc failed , size = D%d\n", size);
goto err_nomem;
}
rfd_ring->buffer_info =
@@ -207,9 +206,7 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
&ring_header->dma);
if (unlikely(!ring_header->desc)) {
- printk(KERN_WARNING
- "%s: pci_alloc_consistent failed, size = D%d\n",
- atl1_driver_name, size);
+ dev_err(&pdev->dev, "pci_alloc_consistent failed\n");
goto err_nomem;
}
@@ -373,8 +370,7 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter,
if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
ERR_FLAG_CODE | ERR_FLAG_OV)) {
adapter->hw_csum_err++;
- printk(KERN_DEBUG "%s: rx checksum error\n",
- atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "rx checksum error\n");
return;
}
}
@@ -393,8 +389,9 @@ static void atl1_rx_checksum(struct atl1_adapter *adapter,
}
/* IPv4, but hardware thinks its checksum is wrong */
- printk(KERN_DEBUG "%s: hw csum wrong pkt_flag:%x, err_flag:%x\n",
- atl1_driver_name, rrd->pkt_flg, rrd->err_flg);
+ dev_dbg(&adapter->pdev->dev,
+ "hw csum wrong, pkt_flag:%x, err_flag:%x\n",
+ rrd->pkt_flg, rrd->err_flg);
skb->ip_summed = CHECKSUM_COMPLETE;
skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
adapter->hw_csum_err++;
@@ -507,14 +504,13 @@ chk_rrd:
/* rrd seems to be bad */
if (unlikely(i-- > 0)) {
/* rrd may not be DMAed completely */
- printk(KERN_DEBUG
- "%s: RRD may not be DMAed completely\n",
- atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev,
+ "incomplete RRD DMA transfer\n");
udelay(1);
goto chk_rrd;
}
/* bad rrd */
- printk(KERN_DEBUG "%s: bad RRD\n", atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "bad RRD\n");
/* see if update RFD index */
if (rrd->num_buf > 1) {
u16 num_buf;
@@ -685,8 +681,8 @@ static void atl1_check_for_link(struct atl1_adapter *adapter)
/* notify upper layer link down ASAP */
if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
if (netif_carrier_ok(netdev)) { /* old link state: Up */
- printk(KERN_INFO "%s: %s link is down\n",
- atl1_driver_name, netdev->name);
+ dev_info(&adapter->pdev->dev, "%s link is down\n",
+ netdev->name);
adapter->link_speed = SPEED_0;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -731,8 +727,8 @@ static irqreturn_t atl1_intr(int irq, void *data)
/* check if PCIE PHY Link down */
if (status & ISR_PHY_LINKDOWN) {
- printk(KERN_DEBUG "%s: pcie phy link down %x\n",
- atl1_driver_name, status);
+ dev_dbg(&adapter->pdev->dev, "pcie phy link down %x\n",
+ status);
if (netif_running(adapter->netdev)) { /* reset MAC */
iowrite32(0, adapter->hw.hw_addr + REG_IMR);
schedule_work(&adapter->pcie_dma_to_rst_task);
@@ -742,9 +738,9 @@ static irqreturn_t atl1_intr(int irq, void *data)
/* check if DMA read/write error ? */
if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
- printk(KERN_DEBUG
- "%s: pcie DMA r/w error (status = 0x%x)\n",
- atl1_driver_name, status);
+ dev_dbg(&adapter->pdev->dev,
+ "pcie DMA r/w error (status = 0x%x)\n",
+ status);
iowrite32(0, adapter->hw.hw_addr + REG_IMR);
schedule_work(&adapter->pcie_dma_to_rst_task);
return IRQ_HANDLED;
@@ -762,14 +758,13 @@ static irqreturn_t atl1_intr(int irq, void *data)
/* rx exception */
if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+ ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+ ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+ if (status & (ISR_RXF_OV | ISR_RFD_UNRUN |
ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
- ISR_HOST_RRD_OV | ISR_CMB_RX))) {
- if (status &
- (ISR_RXF_OV | ISR_RFD_UNRUN | ISR_RRD_OV |
- ISR_HOST_RFD_UNRUN | ISR_HOST_RRD_OV))
- printk(KERN_INFO
- "%s: rx exception: status = 0x%x\n",
- atl1_driver_name, status);
+ ISR_HOST_RRD_OV))
+ dev_dbg(&adapter->pdev->dev,
+ "rx exception, ISR = 0x%x\n", status);
atl1_intr_rx(adapter);
}
@@ -874,8 +869,7 @@ static u32 atl1_check_link(struct atl1_adapter *adapter)
atl1_read_phy_reg(hw, MII_BMSR, &phy_data);
if (!(phy_data & BMSR_LSTATUS)) { /* link down */
if (netif_carrier_ok(netdev)) { /* old link state: Up */
- printk(KERN_INFO "%s: link is down\n",
- atl1_driver_name);
+ dev_info(&adapter->pdev->dev, "link is down\n");
adapter->link_speed = SPEED_0;
netif_carrier_off(netdev);
netif_stop_queue(netdev);
@@ -918,11 +912,11 @@ static u32 atl1_check_link(struct atl1_adapter *adapter)
adapter->link_speed = speed;
adapter->link_duplex = duplex;
atl1_setup_mac_ctrl(adapter);
- printk(KERN_INFO "%s: %s link is up %d Mbps %s\n",
- atl1_driver_name, netdev->name,
- adapter->link_speed,
- adapter->link_duplex ==
- FULL_DUPLEX ? "full duplex" : "half duplex");
+ dev_info(&adapter->pdev->dev,
+ "%s link is up %d Mbps %s\n",
+ netdev->name, adapter->link_speed,
+ adapter->link_duplex == FULL_DUPLEX ?
+ "full duplex" : "half duplex");
}
if (!netif_carrier_ok(netdev)) { /* Link down -> Up */
netif_carrier_on(netdev);
@@ -1330,8 +1324,8 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
cso = skb_transport_offset(skb);
css = cso + skb->csum_offset;
if (unlikely(cso & 0x1)) {
- printk(KERN_DEBUG "%s: payload offset != even number\n",
- atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev,
+ "payload offset not an even number\n");
return -1;
}
csum->csumpl |= (cso & CSUM_PARAM_PLOADOFFSET_MASK) <<
@@ -1579,7 +1573,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (!spin_trylock(&adapter->lock)) {
/* Can't get lock - tell upper layer to requeue */
local_irq_restore(flags);
- printk(KERN_DEBUG "%s: TX locked\n", atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "tx locked\n");
return NETDEV_TX_LOCKED;
}
@@ -1587,7 +1581,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* not enough descriptors */
netif_stop_queue(netdev);
spin_unlock_irqrestore(&adapter->lock, flags);
- printk(KERN_DEBUG "%s: TX busy\n", atl1_driver_name);
+ dev_dbg(&adapter->pdev->dev, "tx busy\n");
return NETDEV_TX_BUSY;
}
@@ -1841,8 +1835,7 @@ static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
(max_frame > MAX_JUMBO_FRAME_SIZE)) {
- printk(KERN_WARNING "%s: invalid MTU setting\n",
- atl1_driver_name);
+ dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
return -EINVAL;
}
@@ -2136,9 +2129,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
if (err) {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_DEBUG
- "%s: no usable DMA configuration, aborting\n",
- atl1_driver_name);
+ dev_err(&pdev->dev, "no usable DMA configuration\n");
goto err_dma;
}
pci_using_64 = false;
@@ -2175,7 +2166,9 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
goto err_pci_iomap;
}
/* get device revision number */
- adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr + (REG_MASTER_CTRL + 2));
+ adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr +
+ (REG_MASTER_CTRL + 2));
+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
/* set default ring resource counts */
adapter->rfd_ring.count = adapter->rrd_ring.count = ATL1_DEFAULT_RFD;
@@ -2466,8 +2459,6 @@ static void __exit atl1_exit_module(void)
*/
static int __init atl1_init_module(void)
{
- printk(KERN_INFO "%s - version %s\n", atl1_driver_string, DRIVER_VERSION);
- printk(KERN_INFO "%s\n", atl1_copyright);
return pci_register_driver(&atl1_driver);
}
diff --git a/drivers/net/atl1/atl1_param.c b/drivers/net/atl1/atl1_param.c
index c407214339f..4246bb9bd50 100644
--- a/drivers/net/atl1/atl1_param.c
+++ b/drivers/net/atl1/atl1_param.c
@@ -22,8 +22,8 @@
*/
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/moduleparam.h>
+#include <linux/pci.h>
#include "atl1.h"
/*
@@ -94,7 +94,7 @@ struct atl1_option {
} arg;
};
-static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
+static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, struct pci_dev *pdev)
{
if (*value == OPTION_UNSET) {
*value = opt->def;
@@ -105,19 +105,17 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
case enable_option:
switch (*value) {
case OPTION_ENABLED:
- printk(KERN_INFO "%s: %s Enabled\n", atl1_driver_name,
- opt->name);
+ dev_info(&pdev->dev, "%s enabled\n", opt->name);
return 0;
case OPTION_DISABLED:
- printk(KERN_INFO "%s: %s Disabled\n", atl1_driver_name,
- opt->name);
+ dev_info(&pdev->dev, "%s disabled\n", opt->name);
return 0;
}
break;
case range_option:
if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
- printk(KERN_INFO "%s: %s set to %i\n",
- atl1_driver_name, opt->name, *value);
+ dev_info(&pdev->dev, "%s set to %i\n", opt->name,
+ *value);
return 0;
}
break;
@@ -129,8 +127,8 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
ent = &opt->arg.l.p[i];
if (*value == ent->i) {
if (ent->str[0] != '\0')
- printk(KERN_INFO "%s: %s\n",
- atl1_driver_name, ent->str);
+ dev_info(&pdev->dev, "%s\n",
+ ent->str);
return 0;
}
}
@@ -141,8 +139,8 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
break;
}
- printk(KERN_INFO "%s: invalid %s specified (%i) %s\n",
- atl1_driver_name, opt->name, *value, opt->err);
+ dev_info(&pdev->dev, "invalid %s specified (%i) %s\n",
+ opt->name, *value, opt->err);
*value = opt->def;
return -1;
}
@@ -158,12 +156,11 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt)
*/
void __devinit atl1_check_options(struct atl1_adapter *adapter)
{
+ struct pci_dev *pdev = adapter->pdev;
int bd = adapter->bd_number;
if (bd >= ATL1_MAX_NIC) {
- printk(KERN_NOTICE "%s: warning: no configuration for board #%i\n",
- atl1_driver_name, bd);
- printk(KERN_NOTICE "%s: using defaults for all values\n",
- atl1_driver_name);
+ dev_notice(&pdev->dev, "no configuration for board#%i\n", bd);
+ dev_notice(&pdev->dev, "using defaults for all values\n");
}
{ /* Interrupt Moderate Timer */
struct atl1_option opt = {
@@ -178,7 +175,7 @@ void __devinit atl1_check_options(struct atl1_adapter *adapter)
int val;
if (num_int_mod_timer > bd) {
val = int_mod_timer[bd];
- atl1_validate_option(&val, &opt);
+ atl1_validate_option(&val, &opt, pdev);
adapter->imt = (u16) val;
} else
adapter->imt = (u16) (opt.def);
@@ -198,7 +195,7 @@ void __devinit atl1_check_options(struct atl1_adapter *adapter)
int val;
if (num_flash_vendor > bd) {
val = flash_vendor[bd];
- atl1_validate_option(&val, &opt);
+ atl1_validate_option(&val, &opt, pdev);
adapter->hw.flash_vendor = (u8) val;
} else
adapter->hw.flash_vendor = (u8) (opt.def);
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 18aba838c1f..82d78ff8399 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -31,10 +31,8 @@
*/
-static const char versionA[] =
+static const char version[] =
"atp.c:v1.09=ac 2002/10/01 Donald Becker <becker@scyld.com>\n";
-static const char versionB[] =
-" http://www.scyld.com/network/atp.html\n";
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
@@ -324,7 +322,7 @@ static int __init atp_probe1(long ioaddr)
#ifndef MODULE
if (net_debug)
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s", version);
#endif
printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
@@ -926,7 +924,7 @@ static void set_rx_mode_8012(struct net_device *dev)
static int __init atp_init_module(void) {
if (debug) /* Emit version even if no cards detected. */
- printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+ printk(KERN_INFO "%s", version);
return atp_init();
}
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index d10fb80e9a6..c39ab803c5d 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -45,7 +45,6 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 4612725965d..9b8d7d9dbe8 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1260,9 +1260,10 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
return -ENODEV;
}
- prop_addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
+ prop_addr = of_get_property(macio_get_of_node(mdev),
+ "mac-address", NULL);
if (prop_addr == NULL) {
- prop_addr = get_property(macio_get_of_node(mdev),
+ prop_addr = of_get_property(macio_get_of_node(mdev),
"local-mac-address", NULL);
if (prop_addr == NULL) {
printk(KERN_ERR "BMAC: Can't get mac-address\n");
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index f98a2205a09..88b33c6ddda 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -1,6 +1,6 @@
/* bnx2.c: Broadcom NX2 network driver.
*
- * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ * Copyright (c) 2004-2007 Broadcom Corporation
*
* 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
@@ -54,8 +54,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.5.8"
-#define DRV_MODULE_RELDATE "April 24, 2007"
+#define DRV_MODULE_VERSION "1.5.10"
+#define DRV_MODULE_RELDATE "May 1, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -84,6 +84,7 @@ typedef enum {
BCM5708,
BCM5708S,
BCM5709,
+ BCM5709S,
} board_t;
/* indexed by board_t, above */
@@ -98,6 +99,7 @@ static const struct {
{ "Broadcom NetXtreme II BCM5708 1000Base-T" },
{ "Broadcom NetXtreme II BCM5708 1000Base-SX" },
{ "Broadcom NetXtreme II BCM5709 1000Base-T" },
+ { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
};
static struct pci_device_id bnx2_pci_tbl[] = {
@@ -117,6 +119,8 @@ static struct pci_device_id bnx2_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
{ 0, }
};
@@ -230,21 +234,29 @@ static inline u32 bnx2_tx_avail(struct bnx2 *bp)
static u32
bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
{
+ u32 val;
+
+ spin_lock_bh(&bp->indirect_lock);
REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
- return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW));
+ val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
+ spin_unlock_bh(&bp->indirect_lock);
+ return val;
}
static void
bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
{
+ spin_lock_bh(&bp->indirect_lock);
REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
+ spin_unlock_bh(&bp->indirect_lock);
}
static void
bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
{
offset += cid_addr;
+ spin_lock_bh(&bp->indirect_lock);
if (CHIP_NUM(bp) == CHIP_NUM_5709) {
int i;
@@ -262,6 +274,7 @@ bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
REG_WR(bp, BNX2_CTX_DATA, val);
}
+ spin_unlock_bh(&bp->indirect_lock);
}
static int
@@ -572,8 +585,8 @@ bnx2_report_fw_link(struct bnx2 *bp)
if (bp->autoneg) {
fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
if (!(bmsr & BMSR_ANEGCOMPLETE) ||
bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
@@ -654,8 +667,8 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
return;
}
- bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
- bnx2_read_phy(bp, MII_LPA, &remote_adv);
+ bnx2_read_phy(bp, bp->mii_adv, &local_adv);
+ bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
if (bp->phy_flags & PHY_SERDES_FLAG) {
u32 new_local_adv = 0;
@@ -700,6 +713,45 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
}
static int
+bnx2_5709s_linkup(struct bnx2 *bp)
+{
+ u32 val, speed;
+
+ bp->link_up = 1;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
+ bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+ if ((bp->autoneg & AUTONEG_SPEED) == 0) {
+ bp->line_speed = bp->req_line_speed;
+ bp->duplex = bp->req_duplex;
+ return 0;
+ }
+ speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
+ switch (speed) {
+ case MII_BNX2_GP_TOP_AN_SPEED_10:
+ bp->line_speed = SPEED_10;
+ break;
+ case MII_BNX2_GP_TOP_AN_SPEED_100:
+ bp->line_speed = SPEED_100;
+ break;
+ case MII_BNX2_GP_TOP_AN_SPEED_1G:
+ case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
+ bp->line_speed = SPEED_1000;
+ break;
+ case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
+ bp->line_speed = SPEED_2500;
+ break;
+ }
+ if (val & MII_BNX2_GP_TOP_AN_FD)
+ bp->duplex = DUPLEX_FULL;
+ else
+ bp->duplex = DUPLEX_HALF;
+ return 0;
+}
+
+static int
bnx2_5708s_linkup(struct bnx2 *bp)
{
u32 val;
@@ -736,7 +788,7 @@ bnx2_5706s_linkup(struct bnx2 *bp)
bp->link_up = 1;
bp->line_speed = SPEED_1000;
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
if (bmcr & BMCR_FULLDPLX) {
bp->duplex = DUPLEX_FULL;
}
@@ -748,8 +800,8 @@ bnx2_5706s_linkup(struct bnx2 *bp)
return 0;
}
- bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
- bnx2_read_phy(bp, MII_LPA, &remote_adv);
+ bnx2_read_phy(bp, bp->mii_adv, &local_adv);
+ bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
common = local_adv & remote_adv;
if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
@@ -770,7 +822,7 @@ bnx2_copper_linkup(struct bnx2 *bp)
{
u32 bmcr;
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
if (bmcr & BMCR_ANENABLE) {
u32 local_adv, remote_adv, common;
@@ -787,8 +839,8 @@ bnx2_copper_linkup(struct bnx2 *bp)
bp->duplex = DUPLEX_HALF;
}
else {
- bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
- bnx2_read_phy(bp, MII_LPA, &remote_adv);
+ bnx2_read_phy(bp, bp->mii_adv, &local_adv);
+ bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
common = local_adv & remote_adv;
if (common & ADVERTISE_100FULL) {
@@ -898,6 +950,145 @@ bnx2_set_mac_link(struct bnx2 *bp)
return 0;
}
+static void
+bnx2_enable_bmsr1(struct bnx2 *bp)
+{
+ if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+ (CHIP_NUM(bp) == CHIP_NUM_5709))
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_GP_STATUS);
+}
+
+static void
+bnx2_disable_bmsr1(struct bnx2 *bp)
+{
+ if ((bp->phy_flags & PHY_SERDES_FLAG) &&
+ (CHIP_NUM(bp) == CHIP_NUM_5709))
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+}
+
+static int
+bnx2_test_and_enable_2g5(struct bnx2 *bp)
+{
+ u32 up1;
+ int ret = 1;
+
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+ return 0;
+
+ if (bp->autoneg & AUTONEG_SPEED)
+ bp->advertising |= ADVERTISED_2500baseX_Full;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+
+ bnx2_read_phy(bp, bp->mii_up1, &up1);
+ if (!(up1 & BCM5708S_UP1_2G5)) {
+ up1 |= BCM5708S_UP1_2G5;
+ bnx2_write_phy(bp, bp->mii_up1, up1);
+ ret = 0;
+ }
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+ return ret;
+}
+
+static int
+bnx2_test_and_disable_2g5(struct bnx2 *bp)
+{
+ u32 up1;
+ int ret = 0;
+
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+ return 0;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+
+ bnx2_read_phy(bp, bp->mii_up1, &up1);
+ if (up1 & BCM5708S_UP1_2G5) {
+ up1 &= ~BCM5708S_UP1_2G5;
+ bnx2_write_phy(bp, bp->mii_up1, up1);
+ ret = 1;
+ }
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+ return ret;
+}
+
+static void
+bnx2_enable_forced_2g5(struct bnx2 *bp)
+{
+ u32 bmcr;
+
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+ return;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ u32 val;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_SERDES_DIG);
+ bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
+ val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
+ val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+
+ } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ bmcr |= BCM5708S_BMCR_FORCE_2500;
+ }
+
+ if (bp->autoneg & AUTONEG_SPEED) {
+ bmcr &= ~BMCR_ANENABLE;
+ if (bp->req_duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+ }
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
+}
+
+static void
+bnx2_disable_forced_2g5(struct bnx2 *bp)
+{
+ u32 bmcr;
+
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+ return;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ u32 val;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_SERDES_DIG);
+ bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
+ val &= ~MII_BNX2_SD_MISC1_FORCE;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
+ MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+
+ } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ bmcr &= ~BCM5708S_BMCR_FORCE_2500;
+ }
+
+ if (bp->autoneg & AUTONEG_SPEED)
+ bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
+}
+
static int
bnx2_set_link(struct bnx2 *bp)
{
@@ -911,8 +1102,10 @@ bnx2_set_link(struct bnx2 *bp)
link_up = bp->link_up;
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_enable_bmsr1(bp);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_disable_bmsr1(bp);
if ((bp->phy_flags & PHY_SERDES_FLAG) &&
(CHIP_NUM(bp) == CHIP_NUM_5706)) {
@@ -933,6 +1126,8 @@ bnx2_set_link(struct bnx2 *bp)
bnx2_5706s_linkup(bp);
else if (CHIP_NUM(bp) == CHIP_NUM_5708)
bnx2_5708s_linkup(bp);
+ else if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bnx2_5709s_linkup(bp);
}
else {
bnx2_copper_linkup(bp);
@@ -941,17 +1136,9 @@ bnx2_set_link(struct bnx2 *bp)
}
else {
if ((bp->phy_flags & PHY_SERDES_FLAG) &&
- (bp->autoneg & AUTONEG_SPEED)) {
+ (bp->autoneg & AUTONEG_SPEED))
+ bnx2_disable_forced_2g5(bp);
- u32 bmcr;
-
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
- bmcr &= ~BCM5708S_BMCR_FORCE_2500;
- if (!(bmcr & BMCR_ANENABLE)) {
- bnx2_write_phy(bp, MII_BMCR, bmcr |
- BMCR_ANENABLE);
- }
- }
bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
bp->link_up = 0;
}
@@ -971,13 +1158,13 @@ bnx2_reset_phy(struct bnx2 *bp)
int i;
u32 reg;
- bnx2_write_phy(bp, MII_BMCR, BMCR_RESET);
+ bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
#define PHY_RESET_MAX_WAIT 100
for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
udelay(10);
- bnx2_read_phy(bp, MII_BMCR, &reg);
+ bnx2_read_phy(bp, bp->mii_bmcr, &reg);
if (!(reg & BMCR_RESET)) {
udelay(20);
break;
@@ -1026,34 +1213,40 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
static int
bnx2_setup_serdes_phy(struct bnx2 *bp)
{
- u32 adv, bmcr, up1;
+ u32 adv, bmcr;
u32 new_adv = 0;
if (!(bp->autoneg & AUTONEG_SPEED)) {
u32 new_bmcr;
int force_link_down = 0;
- bnx2_read_phy(bp, MII_ADVERTISE, &adv);
+ if (bp->req_line_speed == SPEED_2500) {
+ if (!bnx2_test_and_enable_2g5(bp))
+ force_link_down = 1;
+ } else if (bp->req_line_speed == SPEED_1000) {
+ if (bnx2_test_and_disable_2g5(bp))
+ force_link_down = 1;
+ }
+ bnx2_read_phy(bp, bp->mii_adv, &adv);
adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
- new_bmcr = bmcr & ~(BMCR_ANENABLE | BCM5708S_BMCR_FORCE_2500);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
+ new_bmcr = bmcr & ~BMCR_ANENABLE;
new_bmcr |= BMCR_SPEED1000;
- if (bp->req_line_speed == SPEED_2500) {
- new_bmcr |= BCM5708S_BMCR_FORCE_2500;
- bnx2_read_phy(bp, BCM5708S_UP1, &up1);
- if (!(up1 & BCM5708S_UP1_2G5)) {
- up1 |= BCM5708S_UP1_2G5;
- bnx2_write_phy(bp, BCM5708S_UP1, up1);
- force_link_down = 1;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ if (bp->req_line_speed == SPEED_2500)
+ bnx2_enable_forced_2g5(bp);
+ else if (bp->req_line_speed == SPEED_1000) {
+ bnx2_disable_forced_2g5(bp);
+ new_bmcr &= ~0x2000;
}
+
} else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
- bnx2_read_phy(bp, BCM5708S_UP1, &up1);
- if (up1 & BCM5708S_UP1_2G5) {
- up1 &= ~BCM5708S_UP1_2G5;
- bnx2_write_phy(bp, BCM5708S_UP1, up1);
- force_link_down = 1;
- }
+ if (bp->req_line_speed == SPEED_2500)
+ new_bmcr |= BCM5708S_BMCR_FORCE_2500;
+ else
+ new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
}
if (bp->req_duplex == DUPLEX_FULL) {
@@ -1067,49 +1260,48 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
if ((new_bmcr != bmcr) || (force_link_down)) {
/* Force a link down visible on the other side */
if (bp->link_up) {
- bnx2_write_phy(bp, MII_ADVERTISE, adv &
+ bnx2_write_phy(bp, bp->mii_adv, adv &
~(ADVERTISE_1000XFULL |
ADVERTISE_1000XHALF));
- bnx2_write_phy(bp, MII_BMCR, bmcr |
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
BMCR_ANRESTART | BMCR_ANENABLE);
bp->link_up = 0;
netif_carrier_off(bp->dev);
- bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+ bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
bnx2_report_link(bp);
}
- bnx2_write_phy(bp, MII_ADVERTISE, adv);
- bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+ bnx2_write_phy(bp, bp->mii_adv, adv);
+ bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
+ } else {
+ bnx2_resolve_flow_ctrl(bp);
+ bnx2_set_mac_link(bp);
}
return 0;
}
- if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
- bnx2_read_phy(bp, BCM5708S_UP1, &up1);
- up1 |= BCM5708S_UP1_2G5;
- bnx2_write_phy(bp, BCM5708S_UP1, up1);
- }
+ bnx2_test_and_enable_2g5(bp);
if (bp->advertising & ADVERTISED_1000baseT_Full)
new_adv |= ADVERTISE_1000XFULL;
new_adv |= bnx2_phy_get_pause_adv(bp);
- bnx2_read_phy(bp, MII_ADVERTISE, &adv);
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_adv, &adv);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bp->serdes_an_pending = 0;
if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
/* Force a link down visible on the other side */
if (bp->link_up) {
- bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+ bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
spin_unlock_bh(&bp->phy_lock);
msleep(20);
spin_lock_bh(&bp->phy_lock);
}
- bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
- bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
+ bnx2_write_phy(bp, bp->mii_adv, new_adv);
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
BMCR_ANENABLE);
/* Speed up link-up time when the link partner
* does not autonegotiate which is very common
@@ -1122,6 +1314,9 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
bp->current_interval = SERDES_AN_TIMEOUT;
bp->serdes_an_pending = 1;
mod_timer(&bp->timer, jiffies + bp->current_interval);
+ } else {
+ bnx2_resolve_flow_ctrl(bp);
+ bnx2_set_mac_link(bp);
}
return 0;
@@ -1146,14 +1341,14 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
u32 bmcr;
u32 new_bmcr;
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
if (bp->autoneg & AUTONEG_SPEED) {
u32 adv_reg, adv1000_reg;
u32 new_adv_reg = 0;
u32 new_adv1000_reg = 0;
- bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg);
+ bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
@@ -1179,9 +1374,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
(adv_reg != new_adv_reg) ||
((bmcr & BMCR_ANENABLE) == 0)) {
- bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg);
+ bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
- bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART |
+ bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
BMCR_ANENABLE);
}
else if (bp->link_up) {
@@ -1204,21 +1399,21 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
if (new_bmcr != bmcr) {
u32 bmsr;
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
if (bmsr & BMSR_LSTATUS) {
/* Force link down */
- bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+ bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
spin_unlock_bh(&bp->phy_lock);
msleep(50);
spin_lock_bh(&bp->phy_lock);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
}
- bnx2_write_phy(bp, MII_BMCR, new_bmcr);
+ bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
/* Normally, the new speed is setup after the link has
* gone down and up again. In some cases, link will not go
@@ -1230,6 +1425,9 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
bnx2_resolve_flow_ctrl(bp);
bnx2_set_mac_link(bp);
}
+ } else {
+ bnx2_resolve_flow_ctrl(bp);
+ bnx2_set_mac_link(bp);
}
return 0;
}
@@ -1249,10 +1447,63 @@ bnx2_setup_phy(struct bnx2 *bp)
}
static int
+bnx2_init_5709s_phy(struct bnx2 *bp)
+{
+ u32 val;
+
+ bp->mii_bmcr = MII_BMCR + 0x10;
+ bp->mii_bmsr = MII_BMSR + 0x10;
+ bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
+ bp->mii_adv = MII_ADVERTISE + 0x10;
+ bp->mii_lpa = MII_LPA + 0x10;
+ bp->mii_up1 = MII_BNX2_OVER1G_UP1;
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
+ bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+ bnx2_reset_phy(bp);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
+
+ bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
+ val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
+ val |= MII_BNX2_SD_1000XCTL1_FIBER;
+ bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
+ bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
+ if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+ val |= BCM5708S_UP1_2G5;
+ else
+ val &= ~BCM5708S_UP1_2G5;
+ bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
+ bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
+ val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
+ bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
+
+ val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
+ MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
+ bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
+
+ bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
+
+ return 0;
+}
+
+static int
bnx2_init_5708s_phy(struct bnx2 *bp)
{
u32 val;
+ bnx2_reset_phy(bp);
+
+ bp->mii_up1 = BCM5708S_UP1;
+
bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
@@ -1305,6 +1556,8 @@ bnx2_init_5708s_phy(struct bnx2 *bp)
static int
bnx2_init_5706s_phy(struct bnx2 *bp)
{
+ bnx2_reset_phy(bp);
+
bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
if (CHIP_NUM(bp) == CHIP_NUM_5706)
@@ -1342,6 +1595,8 @@ bnx2_init_copper_phy(struct bnx2 *bp)
{
u32 val;
+ bnx2_reset_phy(bp);
+
if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
bnx2_write_phy(bp, 0x18, 0x0c00);
bnx2_write_phy(bp, 0x17, 0x000a);
@@ -1396,9 +1651,13 @@ bnx2_init_phy(struct bnx2 *bp)
bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
- REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+ bp->mii_bmcr = MII_BMCR;
+ bp->mii_bmsr = MII_BMSR;
+ bp->mii_bmsr1 = MII_BMSR;
+ bp->mii_adv = MII_ADVERTISE;
+ bp->mii_lpa = MII_LPA;
- bnx2_reset_phy(bp);
+ REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
bnx2_read_phy(bp, MII_PHYSID1, &val);
bp->phy_id = val << 16;
@@ -1410,6 +1669,8 @@ bnx2_init_phy(struct bnx2 *bp)
rc = bnx2_init_5706s_phy(bp);
else if (CHIP_NUM(bp) == CHIP_NUM_5708)
rc = bnx2_init_5708s_phy(bp);
+ else if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ rc = bnx2_init_5709s_phy(bp);
}
else {
rc = bnx2_init_copper_phy(bp);
@@ -1442,7 +1703,7 @@ bnx2_set_phy_loopback(struct bnx2 *bp)
int rc, i;
spin_lock_bh(&bp->phy_lock);
- rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
+ rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
BMCR_SPEED1000);
spin_unlock_bh(&bp->phy_lock);
if (rc)
@@ -1681,25 +1942,33 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
return 0;
}
-static void
-bnx2_phy_int(struct bnx2 *bp)
+static int
+bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
{
+ struct status_block *sblk = bp->status_blk;
u32 new_link_state, old_link_state;
+ int is_set = 1;
- new_link_state = bp->status_blk->status_attn_bits &
- STATUS_ATTN_BITS_LINK_STATE;
- old_link_state = bp->status_blk->status_attn_bits_ack &
- STATUS_ATTN_BITS_LINK_STATE;
+ new_link_state = sblk->status_attn_bits & event;
+ old_link_state = sblk->status_attn_bits_ack & event;
if (new_link_state != old_link_state) {
- if (new_link_state) {
- REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD,
- STATUS_ATTN_BITS_LINK_STATE);
- }
- else {
- REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD,
- STATUS_ATTN_BITS_LINK_STATE);
- }
+ if (new_link_state)
+ REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
+ else
+ REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
+ } else
+ is_set = 0;
+
+ return is_set;
+}
+
+static void
+bnx2_phy_int(struct bnx2 *bp)
+{
+ if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) {
+ spin_lock(&bp->phy_lock);
bnx2_set_link(bp);
+ spin_unlock(&bp->phy_lock);
}
}
@@ -1993,6 +2262,23 @@ bnx2_msi(int irq, void *dev_instance)
}
static irqreturn_t
+bnx2_msi_1shot(int irq, void *dev_instance)
+{
+ struct net_device *dev = dev_instance;
+ struct bnx2 *bp = netdev_priv(dev);
+
+ prefetch(bp->status_blk);
+
+ /* Return here if interrupt is disabled. */
+ if (unlikely(atomic_read(&bp->intr_sem) != 0))
+ return IRQ_HANDLED;
+
+ netif_rx_schedule(dev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
bnx2_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
@@ -2022,6 +2308,8 @@ bnx2_interrupt(int irq, void *dev_instance)
return IRQ_HANDLED;
}
+#define STATUS_ATTN_EVENTS STATUS_ATTN_BITS_LINK_STATE
+
static inline int
bnx2_has_work(struct bnx2 *bp)
{
@@ -2031,8 +2319,8 @@ bnx2_has_work(struct bnx2 *bp)
(sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
return 1;
- if ((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
- (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE))
+ if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
+ (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
return 1;
return 0;
@@ -2042,15 +2330,14 @@ static int
bnx2_poll(struct net_device *dev, int *budget)
{
struct bnx2 *bp = netdev_priv(dev);
+ struct status_block *sblk = bp->status_blk;
+ u32 status_attn_bits = sblk->status_attn_bits;
+ u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
- if ((bp->status_blk->status_attn_bits &
- STATUS_ATTN_BITS_LINK_STATE) !=
- (bp->status_blk->status_attn_bits_ack &
- STATUS_ATTN_BITS_LINK_STATE)) {
+ if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
+ (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
- spin_lock(&bp->phy_lock);
bnx2_phy_int(bp);
- spin_unlock(&bp->phy_lock);
/* This is needed to take care of transient status
* during link changes.
@@ -3489,17 +3776,21 @@ bnx2_init_chip(struct bnx2 *bp)
REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
if (CHIP_ID(bp) == CHIP_ID_5706_A1)
- REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS);
+ val = BNX2_HC_CONFIG_COLLECT_STATS;
else {
- REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE |
- BNX2_HC_CONFIG_TX_TMR_MODE |
- BNX2_HC_CONFIG_COLLECT_STATS);
+ val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
+ BNX2_HC_CONFIG_COLLECT_STATS;
}
+ if (bp->flags & ONE_SHOT_MSI_FLAG)
+ val |= BNX2_HC_CONFIG_ONE_SHOT;
+
+ REG_WR(bp, BNX2_HC_CONFIG, val);
+
/* Clear internal stats counters. */
REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
- REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
+ REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
BNX2_PORT_FEATURE_ASF_ENABLED)
@@ -3763,10 +4054,11 @@ static int
bnx2_test_registers(struct bnx2 *bp)
{
int ret;
- int i;
+ int i, is_5709;
static const struct {
u16 offset;
u16 flags;
+#define BNX2_FL_NOT_5709 1
u32 rw_mask;
u32 ro_mask;
} reg_tbl[] = {
@@ -3774,26 +4066,26 @@ bnx2_test_registers(struct bnx2 *bp)
{ 0x0090, 0, 0xffffffff, 0x00000000 },
{ 0x0094, 0, 0x00000000, 0x00000000 },
- { 0x0404, 0, 0x00003f00, 0x00000000 },
- { 0x0418, 0, 0x00000000, 0xffffffff },
- { 0x041c, 0, 0x00000000, 0xffffffff },
- { 0x0420, 0, 0x00000000, 0x80ffffff },
- { 0x0424, 0, 0x00000000, 0x00000000 },
- { 0x0428, 0, 0x00000000, 0x00000001 },
- { 0x0450, 0, 0x00000000, 0x0000ffff },
- { 0x0454, 0, 0x00000000, 0xffffffff },
- { 0x0458, 0, 0x00000000, 0xffffffff },
-
- { 0x0808, 0, 0x00000000, 0xffffffff },
- { 0x0854, 0, 0x00000000, 0xffffffff },
- { 0x0868, 0, 0x00000000, 0x77777777 },
- { 0x086c, 0, 0x00000000, 0x77777777 },
- { 0x0870, 0, 0x00000000, 0x77777777 },
- { 0x0874, 0, 0x00000000, 0x77777777 },
-
- { 0x0c00, 0, 0x00000000, 0x00000001 },
- { 0x0c04, 0, 0x00000000, 0x03ff0001 },
- { 0x0c08, 0, 0x0f0ff073, 0x00000000 },
+ { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
+ { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+ { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+ { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
+ { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
+ { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
+ { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
+ { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+ { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+
+ { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+ { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
+ { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+ { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+ { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+ { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
+
+ { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
+ { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
+ { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
{ 0x1000, 0, 0x00000000, 0x00000001 },
{ 0x1004, 0, 0x00000000, 0x000f0001 },
@@ -3840,7 +4132,6 @@ bnx2_test_registers(struct bnx2 *bp)
{ 0x5004, 0, 0x00000000, 0x0000007f },
{ 0x5008, 0, 0x0f0007ff, 0x00000000 },
- { 0x500c, 0, 0xf800f800, 0x07ff07ff },
{ 0x5c00, 0, 0x00000000, 0x00000001 },
{ 0x5c04, 0, 0x00000000, 0x0003000f },
@@ -3880,8 +4171,16 @@ bnx2_test_registers(struct bnx2 *bp)
};
ret = 0;
+ is_5709 = 0;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ is_5709 = 1;
+
for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
u32 offset, rw_mask, ro_mask, save_val, val;
+ u16 flags = reg_tbl[i].flags;
+
+ if (is_5709 && (flags & BNX2_FL_NOT_5709))
+ continue;
offset = (u32) reg_tbl[i].offset;
rw_mask = reg_tbl[i].rw_mask;
@@ -3950,10 +4249,10 @@ bnx2_test_memory(struct bnx2 *bp)
{
int ret = 0;
int i;
- static const struct {
+ static struct mem_entry {
u32 offset;
u32 len;
- } mem_tbl[] = {
+ } mem_tbl_5706[] = {
{ 0x60000, 0x4000 },
{ 0xa0000, 0x3000 },
{ 0xe0000, 0x4000 },
@@ -3961,7 +4260,21 @@ bnx2_test_memory(struct bnx2 *bp)
{ 0x1a0000, 0x4000 },
{ 0x160000, 0x4000 },
{ 0xffffffff, 0 },
+ },
+ mem_tbl_5709[] = {
+ { 0x60000, 0x4000 },
+ { 0xa0000, 0x3000 },
+ { 0xe0000, 0x4000 },
+ { 0x120000, 0x4000 },
+ { 0x1a0000, 0x4000 },
+ { 0xffffffff, 0 },
};
+ struct mem_entry *mem_tbl;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ mem_tbl = mem_tbl_5709;
+ else
+ mem_tbl = mem_tbl_5706;
for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
@@ -4163,8 +4476,10 @@ bnx2_test_link(struct bnx2 *bp)
u32 bmsr;
spin_lock_bh(&bp->phy_lock);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
- bnx2_read_phy(bp, MII_BMSR, &bmsr);
+ bnx2_enable_bmsr1(bp);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
+ bnx2_disable_bmsr1(bp);
spin_unlock_bh(&bp->phy_lock);
if (bmsr & BMSR_LSTATUS) {
@@ -4214,7 +4529,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
bp->current_interval = bp->timer_interval;
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
if (bmcr & BMCR_ANENABLE) {
u32 phy1, phy2;
@@ -4232,7 +4547,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
bmcr &= ~BMCR_ANENABLE;
bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
- bnx2_write_phy(bp, MII_BMCR, bmcr);
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
}
}
@@ -4246,9 +4561,9 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
if (phy2 & 0x20) {
u32 bmcr;
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bmcr |= BMCR_ANENABLE;
- bnx2_write_phy(bp, MII_BMCR, bmcr);
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
}
@@ -4272,17 +4587,12 @@ bnx2_5708_serdes_timer(struct bnx2 *bp)
else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
u32 bmcr;
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
-
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
if (bmcr & BMCR_ANENABLE) {
- bmcr &= ~BMCR_ANENABLE;
- bmcr |= BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500;
- bnx2_write_phy(bp, MII_BMCR, bmcr);
+ bnx2_enable_forced_2g5(bp);
bp->current_interval = SERDES_FORCED_TIMEOUT;
} else {
- bmcr &= ~(BMCR_FULLDPLX | BCM5708S_BMCR_FORCE_2500);
- bmcr |= BMCR_ANENABLE;
- bnx2_write_phy(bp, MII_BMCR, bmcr);
+ bnx2_disable_forced_2g5(bp);
bp->serdes_an_pending = 2;
bp->current_interval = bp->timer_interval;
}
@@ -4313,7 +4623,7 @@ bnx2_timer(unsigned long data)
if (bp->phy_flags & PHY_SERDES_FLAG) {
if (CHIP_NUM(bp) == CHIP_NUM_5706)
bnx2_5706_serdes_timer(bp);
- else if (CHIP_NUM(bp) == CHIP_NUM_5708)
+ else
bnx2_5708_serdes_timer(bp);
}
@@ -4321,6 +4631,38 @@ bnx2_restart_timer:
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
+static int
+bnx2_request_irq(struct bnx2 *bp)
+{
+ struct net_device *dev = bp->dev;
+ int rc = 0;
+
+ if (bp->flags & USING_MSI_FLAG) {
+ irq_handler_t fn = bnx2_msi;
+
+ if (bp->flags & ONE_SHOT_MSI_FLAG)
+ fn = bnx2_msi_1shot;
+
+ rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev);
+ } else
+ rc = request_irq(bp->pdev->irq, bnx2_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ return rc;
+}
+
+static void
+bnx2_free_irq(struct bnx2 *bp)
+{
+ struct net_device *dev = bp->dev;
+
+ if (bp->flags & USING_MSI_FLAG) {
+ free_irq(bp->pdev->irq, dev);
+ pci_disable_msi(bp->pdev);
+ bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
+ } else
+ free_irq(bp->pdev->irq, dev);
+}
+
/* Called with rtnl_lock */
static int
bnx2_open(struct net_device *dev)
@@ -4328,6 +4670,8 @@ bnx2_open(struct net_device *dev)
struct bnx2 *bp = netdev_priv(dev);
int rc;
+ netif_carrier_off(dev);
+
bnx2_set_power_state(bp, PCI_D0);
bnx2_disable_int(bp);
@@ -4335,24 +4679,15 @@ bnx2_open(struct net_device *dev)
if (rc)
return rc;
- if ((CHIP_ID(bp) != CHIP_ID_5706_A0) &&
- (CHIP_ID(bp) != CHIP_ID_5706_A1) &&
- !disable_msi) {
-
+ if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
if (pci_enable_msi(bp->pdev) == 0) {
bp->flags |= USING_MSI_FLAG;
- rc = request_irq(bp->pdev->irq, bnx2_msi, 0, dev->name,
- dev);
- }
- else {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt,
- IRQF_SHARED, dev->name, dev);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ bp->flags |= ONE_SHOT_MSI_FLAG;
}
}
- else {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED,
- dev->name, dev);
- }
+ rc = bnx2_request_irq(bp);
+
if (rc) {
bnx2_free_mem(bp);
return rc;
@@ -4361,11 +4696,7 @@ bnx2_open(struct net_device *dev)
rc = bnx2_init_nic(bp);
if (rc) {
- free_irq(bp->pdev->irq, dev);
- if (bp->flags & USING_MSI_FLAG) {
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
- }
+ bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
return rc;
@@ -4389,16 +4720,13 @@ bnx2_open(struct net_device *dev)
bp->dev->name);
bnx2_disable_int(bp);
- free_irq(bp->pdev->irq, dev);
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
+ bnx2_free_irq(bp);
rc = bnx2_init_nic(bp);
- if (!rc) {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt,
- IRQF_SHARED, dev->name, dev);
- }
+ if (!rc)
+ rc = bnx2_request_irq(bp);
+
if (rc) {
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
@@ -4508,40 +4836,53 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
- if ((mss = skb_shinfo(skb)->gso_size) &&
- (skb->len > (bp->dev->mtu + ETH_HLEN))) {
+ if ((mss = skb_shinfo(skb)->gso_size)) {
u32 tcp_opt_len, ip_tcp_len;
struct iphdr *iph;
- if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
- tcp_opt_len = 0;
- if (tcp_hdr(skb)->doff > 5)
- tcp_opt_len = tcp_optlen(skb);
+ tcp_opt_len = tcp_optlen(skb);
+
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
+ u32 tcp_off = skb_transport_offset(skb) -
+ sizeof(struct ipv6hdr) - ETH_HLEN;
- ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
+ vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
+ TX_BD_FLAGS_SW_FLAGS;
+ if (likely(tcp_off == 0))
+ vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
+ else {
+ tcp_off >>= 3;
+ vlan_tag_flags |= ((tcp_off & 0x3) <<
+ TX_BD_FLAGS_TCP6_OFF0_SHL) |
+ ((tcp_off & 0x10) <<
+ TX_BD_FLAGS_TCP6_OFF4_SHL);
+ mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
+ }
+ } else {
+ if (skb_header_cloned(skb) &&
+ pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
- iph = ip_hdr(skb);
- iph->check = 0;
- iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
- tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
- iph->daddr, 0,
- IPPROTO_TCP, 0);
- if (tcp_opt_len || (iph->ihl > 5)) {
- vlan_tag_flags |= ((iph->ihl - 5) +
- (tcp_opt_len >> 2)) << 8;
+ ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
+
+ iph = ip_hdr(skb);
+ iph->check = 0;
+ iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
+ tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+ iph->daddr, 0,
+ IPPROTO_TCP,
+ 0);
+ if (tcp_opt_len || (iph->ihl > 5)) {
+ vlan_tag_flags |= ((iph->ihl - 5) +
+ (tcp_opt_len >> 2)) << 8;
+ }
}
- }
- else
- {
+ } else
mss = 0;
- }
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
@@ -4622,11 +4963,7 @@ bnx2_close(struct net_device *dev)
else
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
bnx2_reset_chip(bp, reset_code);
- free_irq(bp->pdev->irq, dev);
- if (bp->flags & USING_MSI_FLAG) {
- pci_disable_msi(bp->pdev);
- bp->flags &= ~USING_MSI_FLAG;
- }
+ bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
bp->link_up = 0;
@@ -4735,6 +5072,8 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (bp->phy_flags & PHY_SERDES_FLAG) {
cmd->supported |= SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE;
+ if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
+ cmd->supported |= SUPPORTED_2500baseX_Full;
cmd->port = PORT_FIBRE;
}
@@ -4798,8 +5137,10 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
advertising = cmd->advertising;
- }
- else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
+ } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
+ return -EINVAL;
+ } else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
advertising = cmd->advertising;
}
else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
@@ -4975,7 +5316,7 @@ bnx2_nway_reset(struct net_device *dev)
/* Force a link down visible on the other side */
if (bp->phy_flags & PHY_SERDES_FLAG) {
- bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
+ bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
spin_unlock_bh(&bp->phy_lock);
msleep(20);
@@ -4987,9 +5328,9 @@ bnx2_nway_reset(struct net_device *dev)
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
- bnx2_read_phy(bp, MII_BMCR, &bmcr);
+ bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
bmcr &= ~BMCR_LOOPBACK;
- bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
+ bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
spin_unlock_bh(&bp->phy_lock);
@@ -5209,10 +5550,15 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
static int
bnx2_set_tso(struct net_device *dev, u32 data)
{
- if (data)
+ struct bnx2 *bp = netdev_priv(dev);
+
+ if (data) {
dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
- else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ dev->features |= NETIF_F_TSO6;
+ } else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_TSO_ECN);
return 0;
}
@@ -5510,6 +5856,17 @@ bnx2_phys_id(struct net_device *dev, u32 data)
return 0;
}
+static int
+bnx2_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct bnx2 *bp = netdev_priv(dev);
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ return (ethtool_op_set_tx_hw_csum(dev, data));
+ else
+ return (ethtool_op_set_tx_csum(dev, data));
+}
+
static const struct ethtool_ops bnx2_ethtool_ops = {
.get_settings = bnx2_get_settings,
.set_settings = bnx2_set_settings,
@@ -5532,7 +5889,7 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.get_rx_csum = bnx2_get_rx_csum,
.set_rx_csum = bnx2_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_tx_csum = bnx2_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
@@ -5562,6 +5919,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG: {
u32 mii_regval;
+ if (!netif_running(dev))
+ return -EAGAIN;
+
spin_lock_bh(&bp->phy_lock);
err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
spin_unlock_bh(&bp->phy_lock);
@@ -5575,6 +5935,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (!netif_running(dev))
+ return -EAGAIN;
+
spin_lock_bh(&bp->phy_lock);
err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
spin_unlock_bh(&bp->phy_lock);
@@ -5676,6 +6039,58 @@ bnx2_get_5709_media(struct bnx2 *bp)
}
}
+static void __devinit
+bnx2_get_pci_speed(struct bnx2 *bp)
+{
+ u32 reg;
+
+ reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
+ if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
+ u32 clkreg;
+
+ bp->flags |= PCIX_FLAG;
+
+ clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
+
+ clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
+ switch (clkreg) {
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
+ bp->bus_speed_mhz = 133;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
+ bp->bus_speed_mhz = 100;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
+ bp->bus_speed_mhz = 66;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
+ bp->bus_speed_mhz = 50;
+ break;
+
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
+ case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
+ bp->bus_speed_mhz = 33;
+ break;
+ }
+ }
+ else {
+ if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
+ bp->bus_speed_mhz = 66;
+ else
+ bp->bus_speed_mhz = 33;
+ }
+
+ if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
+ bp->flags |= PCI_32BIT_FLAG;
+
+}
+
static int __devinit
bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
{
@@ -5683,6 +6098,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
unsigned long mem_len;
int rc;
u32 reg;
+ u64 dma_mask, persist_dma_mask;
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -5721,25 +6137,11 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
goto err_out_release;
}
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
- bp->flags |= USING_DAC_FLAG;
- if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
- dev_err(&pdev->dev,
- "pci_set_consistent_dma_mask failed, aborting.\n");
- rc = -EIO;
- goto err_out_release;
- }
- }
- else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
- dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
- rc = -EIO;
- goto err_out_release;
- }
-
bp->dev = dev;
bp->pdev = pdev;
spin_lock_init(&bp->phy_lock);
+ spin_lock_init(&bp->indirect_lock);
INIT_WORK(&bp->reset_task, bnx2_reset_task);
dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
@@ -5767,7 +6169,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
- if (CHIP_NUM(bp) != CHIP_NUM_5709) {
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
+ dev_err(&pdev->dev,
+ "Cannot find PCIE capability, aborting.\n");
+ rc = -EIO;
+ goto err_out_unmap;
+ }
+ bp->flags |= PCIE_FLAG;
+ } else {
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
dev_err(&pdev->dev,
@@ -5777,51 +6187,33 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
}
}
- /* Get bus information. */
- reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
- if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
- u32 clkreg;
-
- bp->flags |= PCIX_FLAG;
-
- clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
-
- clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
- switch (clkreg) {
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
- bp->bus_speed_mhz = 133;
- break;
-
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
- bp->bus_speed_mhz = 100;
- break;
-
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
- bp->bus_speed_mhz = 66;
- break;
+ if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
+ bp->flags |= MSI_CAP_FLAG;
+ }
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
- bp->bus_speed_mhz = 50;
- break;
+ /* 5708 cannot support DMA addresses > 40-bit. */
+ if (CHIP_NUM(bp) == CHIP_NUM_5708)
+ persist_dma_mask = dma_mask = DMA_40BIT_MASK;
+ else
+ persist_dma_mask = dma_mask = DMA_64BIT_MASK;
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
- case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
- bp->bus_speed_mhz = 33;
- break;
+ /* Configure DMA attributes. */
+ if (pci_set_dma_mask(pdev, dma_mask) == 0) {
+ dev->features |= NETIF_F_HIGHDMA;
+ rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "pci_set_consistent_dma_mask failed, aborting.\n");
+ goto err_out_unmap;
}
- }
- else {
- if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
- bp->bus_speed_mhz = 66;
- else
- bp->bus_speed_mhz = 33;
+ } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+ dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
+ goto err_out_unmap;
}
- if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
- bp->flags |= PCI_32BIT_FLAG;
+ if (!(bp->flags & PCIE_FLAG))
+ bnx2_get_pci_speed(bp);
/* 5706A0 may falsely detect SERR and PERR. */
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
@@ -6005,6 +6397,26 @@ err_out:
return rc;
}
+static char * __devinit
+bnx2_bus_string(struct bnx2 *bp, char *str)
+{
+ char *s = str;
+
+ if (bp->flags & PCIE_FLAG) {
+ s += sprintf(s, "PCI Express");
+ } else {
+ s += sprintf(s, "PCI");
+ if (bp->flags & PCIX_FLAG)
+ s += sprintf(s, "-X");
+ if (bp->flags & PCI_32BIT_FLAG)
+ s += sprintf(s, " 32-bit");
+ else
+ s += sprintf(s, " 64-bit");
+ s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
+ }
+ return str;
+}
+
static int __devinit
bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -6012,6 +6424,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *dev = NULL;
struct bnx2 *bp;
int rc, i;
+ char str[40];
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -6052,6 +6465,23 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->poll_controller = poll_bnx2;
#endif
+ pci_set_drvdata(pdev, dev);
+
+ memcpy(dev->dev_addr, bp->mac_addr, 6);
+ memcpy(dev->perm_addr, bp->mac_addr, 6);
+ bp->name = board_info[ent->driver_data].name;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
+ else
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+#ifdef BCM_VLAN
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+#endif
+ dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ dev->features |= NETIF_F_TSO6;
+
if ((rc = register_netdev(dev))) {
dev_err(&pdev->dev, "Cannot register net device\n");
if (bp->regview)
@@ -6063,20 +6493,13 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
- pci_set_drvdata(pdev, dev);
-
- memcpy(dev->dev_addr, bp->mac_addr, 6);
- memcpy(dev->perm_addr, bp->mac_addr, 6);
- bp->name = board_info[ent->driver_data].name,
- printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
+ printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
"IRQ %d, ",
dev->name,
bp->name,
((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
((CHIP_ID(bp) & 0x0ff0) >> 4),
- ((bp->flags & PCIX_FLAG) ? "-X" : ""),
- ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
- bp->bus_speed_mhz,
+ bnx2_bus_string(bp, str),
dev->base_addr,
bp->pdev->irq);
@@ -6085,17 +6508,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
printk("%2.2x", dev->dev_addr[i]);
printk("\n");
- dev->features |= NETIF_F_SG;
- if (bp->flags & USING_DAC_FLAG)
- dev->features |= NETIF_F_HIGHDMA;
- dev->features |= NETIF_F_IP_CSUM;
-#ifdef BCM_VLAN
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-#endif
- dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-
- netif_carrier_off(bp->dev);
-
return 0;
}
@@ -6140,6 +6552,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
bnx2_reset_chip(bp, reset_code);
bnx2_free_skbs(bp);
+ pci_save_state(pdev);
bnx2_set_power_state(bp, pci_choose_state(pdev, state));
return 0;
}
@@ -6153,6 +6566,7 @@ bnx2_resume(struct pci_dev *pdev)
if (!netif_running(dev))
return 0;
+ pci_restore_state(pdev);
bnx2_set_power_state(bp, PCI_D0);
netif_device_attach(dev);
bnx2_init_nic(bp);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 878eee58f12..bd6288d6350 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -1,6 +1,6 @@
/* bnx2.h: Broadcom NX2 network driver.
*
- * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
+ * Copyright (c) 2004-2007 Broadcom Corporation
*
* 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
@@ -24,8 +24,11 @@ struct tx_bd {
u32 tx_bd_haddr_hi;
u32 tx_bd_haddr_lo;
u32 tx_bd_mss_nbytes;
+ #define TX_BD_TCP6_OFF2_SHL (14)
u32 tx_bd_vlan_tag_flags;
#define TX_BD_FLAGS_CONN_FAULT (1<<0)
+ #define TX_BD_FLAGS_TCP6_OFF0_MSK (3<<1)
+ #define TX_BD_FLAGS_TCP6_OFF0_SHL (1)
#define TX_BD_FLAGS_TCP_UDP_CKSUM (1<<1)
#define TX_BD_FLAGS_IP_CKSUM (1<<2)
#define TX_BD_FLAGS_VLAN_TAG (1<<3)
@@ -34,6 +37,7 @@ struct tx_bd {
#define TX_BD_FLAGS_END (1<<6)
#define TX_BD_FLAGS_START (1<<7)
#define TX_BD_FLAGS_SW_OPTION_WORD (0x1f<<8)
+ #define TX_BD_FLAGS_TCP6_OFF4_SHL (12)
#define TX_BD_FLAGS_SW_FLAGS (1<<13)
#define TX_BD_FLAGS_SW_SNAP (1<<14)
#define TX_BD_FLAGS_SW_LSO (1<<15)
@@ -6292,6 +6296,41 @@ struct l2_fhdr {
#define MII_BNX2_DSP_ADDRESS 0x17
#define MII_BNX2_DSP_EXPAND_REG 0x0f00
+#define MII_BNX2_BLK_ADDR 0x1f
+#define MII_BNX2_BLK_ADDR_IEEE0 0x0000
+#define MII_BNX2_BLK_ADDR_GP_STATUS 0x8120
+#define MII_BNX2_GP_TOP_AN_STATUS1 0x1b
+#define MII_BNX2_GP_TOP_AN_SPEED_MSK 0x3f00
+#define MII_BNX2_GP_TOP_AN_SPEED_10 0x0000
+#define MII_BNX2_GP_TOP_AN_SPEED_100 0x0100
+#define MII_BNX2_GP_TOP_AN_SPEED_1G 0x0200
+#define MII_BNX2_GP_TOP_AN_SPEED_2_5G 0x0300
+#define MII_BNX2_GP_TOP_AN_SPEED_1GKV 0x0d00
+#define MII_BNX2_GP_TOP_AN_FD 0x8
+#define MII_BNX2_BLK_ADDR_SERDES_DIG 0x8300
+#define MII_BNX2_SERDES_DIG_1000XCTL1 0x10
+#define MII_BNX2_SD_1000XCTL1_FIBER 0x01
+#define MII_BNX2_SD_1000XCTL1_AUTODET 0x10
+#define MII_BNX2_SERDES_DIG_MISC1 0x18
+#define MII_BNX2_SD_MISC1_FORCE_MSK 0xf
+#define MII_BNX2_SD_MISC1_FORCE_2_5G 0x0
+#define MII_BNX2_SD_MISC1_FORCE 0x10
+#define MII_BNX2_BLK_ADDR_OVER1G 0x8320
+#define MII_BNX2_OVER1G_UP1 0x19
+#define MII_BNX2_BLK_ADDR_BAM_NXTPG 0x8350
+#define MII_BNX2_BAM_NXTPG_CTL 0x10
+#define MII_BNX2_NXTPG_CTL_BAM 0x1
+#define MII_BNX2_NXTPG_CTL_T2 0x2
+#define MII_BNX2_BLK_ADDR_CL73_USERB0 0x8370
+#define MII_BNX2_CL73_BAM_CTL1 0x12
+#define MII_BNX2_CL73_BAM_EN 0x8000
+#define MII_BNX2_CL73_BAM_STA_MGR_EN 0x4000
+#define MII_BNX2_CL73_BAM_NP_AFT_BP_EN 0x2000
+#define MII_BNX2_BLK_ADDR_AER 0xffd0
+#define MII_BNX2_AER_AER 0x1e
+#define MII_BNX2_AER_AER_AN_MMD 0x3800
+#define MII_BNX2_BLK_ADDR_COMBO_IEEEB0 0xffe0
+
#define MIN_ETHERNET_PACKET_SIZE 60
#define MAX_ETHERNET_PACKET_SIZE 1514
#define MAX_ETHERNET_JUMBO_PACKET_SIZE 9014
@@ -6429,13 +6468,15 @@ struct bnx2 {
u32 last_status_idx;
u32 flags;
-#define PCIX_FLAG 1
-#define PCI_32BIT_FLAG 2
-#define ONE_TDMA_FLAG 4 /* no longer used */
-#define NO_WOL_FLAG 8
-#define USING_DAC_FLAG 0x10
-#define USING_MSI_FLAG 0x20
-#define ASF_ENABLE_FLAG 0x40
+#define PCIX_FLAG 0x00000001
+#define PCI_32BIT_FLAG 0x00000002
+#define ONE_TDMA_FLAG 0x00000004 /* no longer used */
+#define NO_WOL_FLAG 0x00000008
+#define USING_MSI_FLAG 0x00000020
+#define ASF_ENABLE_FLAG 0x00000040
+#define MSI_CAP_FLAG 0x00000080
+#define ONE_SHOT_MSI_FLAG 0x00000100
+#define PCIE_FLAG 0x00000200
/* Put tx producer and consumer fields in separate cache lines. */
@@ -6484,6 +6525,7 @@ struct bnx2 {
/* Used to synchronize phy accesses. */
spinlock_t phy_lock;
+ spinlock_t indirect_lock;
u32 phy_flags;
#define PHY_SERDES_FLAG 1
@@ -6495,6 +6537,13 @@ struct bnx2 {
#define PHY_INT_MODE_LINK_READY_FLAG 0x200
#define PHY_DIS_EARLY_DAC_FLAG 0x400
+ u32 mii_bmcr;
+ u32 mii_bmsr;
+ u32 mii_bmsr1;
+ u32 mii_adv;
+ u32 mii_lpa;
+ u32 mii_up1;
+
u32 chip_id;
/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */
#define CHIP_NUM(bp) (((bp)->chip_id) & 0xffff0000)
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index 21d368ff424..b49f439e0f6 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -15,680 +15,1071 @@
*/
static u8 bnx2_COM_b06FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x09, 0x83, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5b, 0x7d, 0x6c,
- 0x5b, 0xd7, 0x75, 0x3f, 0xef, 0xf1, 0x51, 0x7a, 0x96, 0x68, 0xf9, 0x99,
- 0x7e, 0x96, 0x59, 0x4f, 0xb1, 0x49, 0xf1, 0xc9, 0xd2, 0x62, 0x2d, 0x63,
- 0x34, 0x35, 0xd1, 0x3a, 0x26, 0x66, 0x48, 0xda, 0x71, 0x36, 0x67, 0xa0,
- 0x1d, 0x05, 0x51, 0x51, 0xaf, 0xd0, 0x48, 0xd9, 0xcd, 0xb2, 0x0c, 0x73,
- 0x96, 0xb4, 0x70, 0xbc, 0xb4, 0xa1, 0x25, 0x79, 0xf5, 0x06, 0x45, 0xcf,
- 0xb3, 0x34, 0x39, 0xc0, 0x82, 0x41, 0x10, 0x9d, 0x3a, 0x7f, 0x30, 0xa5,
- 0xed, 0x7c, 0x19, 0xe8, 0x12, 0x29, 0xb2, 0x93, 0xb5, 0x43, 0xd0, 0xa6,
- 0x68, 0xff, 0xe8, 0x8a, 0x6e, 0x30, 0x52, 0x0c, 0xf3, 0x3a, 0xa0, 0x30,
- 0xfa, 0xc7, 0xe6, 0x2d, 0x1f, 0xdc, 0xef, 0xdc, 0x77, 0x1f, 0xf9, 0x48,
- 0x51, 0x96, 0x1c, 0x34, 0x5d, 0xb7, 0x99, 0x80, 0xf0, 0xde, 0xbd, 0xf7,
- 0xbc, 0x7b, 0xcf, 0x3d, 0xdf, 0xe7, 0xdc, 0xab, 0x5f, 0x53, 0xa9, 0x85,
- 0xe4, 0x6f, 0x2d, 0xfe, 0xc2, 0x7f, 0xf4, 0xc7, 0xb9, 0xdb, 0x3e, 0x7d,
- 0x5b, 0x1f, 0x5e, 0x07, 0x54, 0xdd, 0xaf, 0x72, 0xbf, 0x0f, 0x7f, 0x26,
- 0xfe, 0xfa, 0xe4, 0x7b, 0xa3, 0x9f, 0x81, 0xbf, 0x2b, 0x18, 0x1c, 0xfe,
- 0x09, 0x91, 0xb2, 0x0c, 0x8c, 0xf7, 0x57, 0x2e, 0x5f, 0x7f, 0x9c, 0x17,
- 0x0e, 0xaf, 0x62, 0x9e, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf,
- 0x9b, 0xbf, 0x9b, 0xbf, 0x9b, 0xbf, 0xff, 0x3f, 0x3f, 0x9f, 0x13, 0x72,
- 0x88, 0x98, 0x85, 0xff, 0x48, 0x57, 0xe3, 0x89, 0xa1, 0xa4, 0x45, 0xba,
- 0x2f, 0x7e, 0x65, 0x28, 0x67, 0x11, 0x25, 0x8a, 0xdb, 0xc3, 0x29, 0xfa,
- 0xb0, 0x9c, 0x37, 0x35, 0xe2, 0xfe, 0x5b, 0xe2, 0x1f, 0x3c, 0xfd, 0xfa,
- 0x9d, 0x91, 0xab, 0xb3, 0x3e, 0xd2, 0x8d, 0xf8, 0xcb, 0xba, 0xb1, 0x8d,
- 0xf4, 0x0e, 0x7c, 0xf3, 0x5c, 0xf7, 0x7f, 0xa8, 0xd4, 0xe6, 0xce, 0x75,
- 0xa5, 0xfc, 0x7a, 0x37, 0xe5, 0x37, 0xc7, 0x75, 0x52, 0xe3, 0x5d, 0x3f,
- 0x48, 0xfa, 0x8c, 0x61, 0x5f, 0xdc, 0xa0, 0xf9, 0x12, 0x65, 0x0e, 0x4c,
- 0xf0, 0x1a, 0xb1, 0x75, 0xf7, 0x62, 0x2e, 0x2d, 0x3e, 0x3c, 0xf4, 0x67,
- 0xd6, 0xd3, 0x65, 0xd5, 0xb2, 0x7a, 0xe6, 0x28, 0x30, 0xf0, 0x7c, 0x3f,
- 0xc6, 0x8b, 0x91, 0x1e, 0xa2, 0x3b, 0x49, 0xb5, 0xf2, 0x01, 0x9f, 0xa5,
- 0x53, 0xb2, 0x64, 0x51, 0xaa, 0x44, 0xf4, 0x77, 0x45, 0x85, 0x9e, 0xb7,
- 0xda, 0x69, 0xae, 0xf7, 0x83, 0x72, 0x02, 0xb8, 0xbc, 0x6d, 0x0d, 0x0f,
- 0x8d, 0x5b, 0x3c, 0x57, 0x7c, 0x9d, 0x83, 0x6f, 0x6f, 0x5b, 0xce, 0xd2,
- 0x68, 0xb4, 0xc8, 0x7d, 0xbd, 0x2d, 0xdc, 0xe7, 0x8f, 0x3f, 0x1c, 0x7c,
- 0xde, 0x0a, 0xc8, 0xbe, 0x1f, 0xa5, 0x92, 0x98, 0x6f, 0xac, 0xc8, 0xb0,
- 0xcf, 0xde, 0x91, 0xb3, 0x4c, 0xd9, 0x6f, 0xc5, 0x93, 0x56, 0x08, 0xfd,
- 0x1d, 0x72, 0x2c, 0xbd, 0x2e, 0x67, 0x59, 0x72, 0xac, 0x88, 0x6f, 0x7a,
- 0x65, 0xff, 0x3b, 0xa9, 0x9c, 0x15, 0x93, 0xfd, 0x57, 0x93, 0x49, 0xab,
- 0x5f, 0xf6, 0x1f, 0xbe, 0x2b, 0x67, 0xc5, 0x65, 0xff, 0xf7, 0x81, 0x8b,
- 0x41, 0xc7, 0x8a, 0x61, 0xfc, 0x25, 0x30, 0xfe, 0x9a, 0x41, 0x6d, 0x19,
- 0x8c, 0x61, 0xef, 0xb6, 0x4e, 0x97, 0x7d, 0x21, 0x7a, 0xbd, 0xfb, 0x32,
- 0x68, 0x63, 0xd0, 0xd9, 0x12, 0x29, 0x99, 0xee, 0x10, 0x68, 0x62, 0xd2,
- 0xb9, 0x52, 0x2b, 0xf9, 0x4e, 0xfa, 0xb0, 0xe7, 0xcf, 0x51, 0xd6, 0xd4,
- 0x69, 0xfd, 0x8c, 0x42, 0x9d, 0x7d, 0x6b, 0x28, 0x61, 0xe4, 0x29, 0xd5,
- 0x8d, 0x28, 0x6e, 0xd2, 0x24, 0x6d, 0x66, 0x71, 0xbd, 0x8a, 0x1e, 0x95,
- 0x22, 0xa1, 0x2c, 0x28, 0x3c, 0x72, 0xfa, 0x5d, 0x8e, 0x39, 0xb1, 0x26,
- 0xff, 0x85, 0x29, 0x35, 0x71, 0x2b, 0x0d, 0x1b, 0x8c, 0x0f, 0x80, 0x05,
- 0x1f, 0x74, 0x25, 0x79, 0x2a, 0x44, 0xc7, 0xec, 0x80, 0x92, 0x3a, 0x75,
- 0x37, 0x25, 0x63, 0x64, 0xaa, 0xd4, 0x25, 0xbe, 0x2d, 0x14, 0x43, 0x34,
- 0x6e, 0x93, 0x92, 0xb4, 0x99, 0x5e, 0xed, 0x18, 0x6f, 0x13, 0xb0, 0xe8,
- 0xeb, 0xf0, 0x51, 0x97, 0x91, 0x22, 0x9d, 0x71, 0x46, 0x7f, 0x50, 0x49,
- 0x8b, 0x39, 0x44, 0x7f, 0x78, 0x8c, 0x02, 0x74, 0xba, 0x68, 0x4a, 0xd8,
- 0x72, 0x39, 0x19, 0x33, 0x00, 0x07, 0xda, 0xd9, 0x26, 0x0d, 0xe3, 0x39,
- 0x6a, 0xf3, 0xfa, 0x21, 0xc8, 0xcc, 0xb7, 0x87, 0xb2, 0xd3, 0x62, 0xbe,
- 0xb0, 0x2f, 0xce, 0xf3, 0x75, 0x00, 0xee, 0x1d, 0xe0, 0xa5, 0x90, 0x26,
- 0x78, 0x95, 0xa0, 0xec, 0x84, 0x02, 0x79, 0xc2, 0x53, 0xd0, 0x2d, 0x0d,
- 0xfc, 0x35, 0xb2, 0xfa, 0x14, 0xca, 0x59, 0x9b, 0x28, 0x6f, 0xa0, 0x5d,
- 0xbc, 0xa0, 0x26, 0xed, 0x66, 0x4a, 0x69, 0x61, 0xec, 0x5f, 0xc8, 0x0a,
- 0x8d, 0xe1, 0x1b, 0xd5, 0x62, 0x98, 0x9f, 0x61, 0xef, 0xc3, 0x82, 0xfe,
- 0x4d, 0xf1, 0xfd, 0x74, 0x69, 0x22, 0xaf, 0x26, 0x4b, 0xed, 0xe4, 0x9b,
- 0x89, 0x40, 0x9a, 0xc7, 0xd5, 0xd4, 0x19, 0x8d, 0xfc, 0x93, 0x0a, 0x41,
- 0x3e, 0x0c, 0x5f, 0xfc, 0xb8, 0xba, 0xb3, 0x74, 0x41, 0x4d, 0x95, 0xf8,
- 0x1b, 0xc0, 0x16, 0x55, 0xd0, 0x96, 0xdf, 0xb7, 0x83, 0x96, 0x34, 0xac,
- 0xc6, 0x75, 0x3d, 0x51, 0x64, 0x99, 0xe5, 0x6f, 0xc1, 0x0f, 0xec, 0xe5,
- 0x9c, 0x0d, 0xfe, 0x08, 0x7e, 0x85, 0xc1, 0xaf, 0x6f, 0x82, 0x5f, 0xfd,
- 0xe0, 0x53, 0x8c, 0xde, 0x28, 0xf5, 0xd2, 0x6b, 0xa5, 0x1e, 0x7a, 0x15,
- 0x32, 0xf9, 0x4a, 0x29, 0x4c, 0x2f, 0x97, 0x3a, 0xe8, 0xa5, 0x52, 0x88,
- 0xce, 0x0b, 0x1e, 0xa6, 0x21, 0xff, 0x82, 0xaf, 0xfa, 0x26, 0xf0, 0xa4,
- 0x1d, 0x3c, 0x59, 0x0f, 0x79, 0xd9, 0x08, 0xf9, 0x9b, 0xee, 0xd6, 0x69,
- 0xaa, 0x9b, 0x12, 0x41, 0xf4, 0x6f, 0x89, 0x6b, 0x82, 0x4e, 0x1a, 0xc6,
- 0xc7, 0x26, 0xfc, 0x94, 0x32, 0x4e, 0xd3, 0x7b, 0x93, 0x1a, 0x8d, 0x95,
- 0xa6, 0x36, 0x3a, 0x7c, 0xe3, 0xf6, 0x2c, 0x5d, 0x44, 0x5f, 0xca, 0x98,
- 0xa5, 0x4b, 0xdb, 0x54, 0x1a, 0x9d, 0xfe, 0x1b, 0x4a, 0x9e, 0x39, 0x4d,
- 0x3f, 0xfe, 0x3a, 0x51, 0x06, 0x34, 0x51, 0xfb, 0x7e, 0x5a, 0x4e, 0x18,
- 0xa0, 0x45, 0x5f, 0xaf, 0x90, 0x08, 0xb5, 0x8f, 0x79, 0x19, 0x86, 0xae,
- 0x68, 0x4a, 0xca, 0x7e, 0x01, 0xfa, 0xd2, 0xaa, 0x24, 0xa7, 0x88, 0x72,
- 0x53, 0x65, 0xca, 0xc5, 0xfc, 0xf4, 0x98, 0x51, 0xa6, 0x74, 0xac, 0x89,
- 0xbe, 0x68, 0xb4, 0xd3, 0x68, 0xef, 0x6f, 0xf8, 0xdc, 0x5c, 0x65, 0xba,
- 0xd4, 0x8f, 0x77, 0xee, 0x23, 0x9a, 0x12, 0xef, 0x4e, 0x7f, 0xbe, 0xe4,
- 0xa7, 0x84, 0x99, 0x0f, 0x69, 0xf4, 0x8e, 0xcf, 0xc1, 0x29, 0xe1, 0x8e,
- 0x81, 0x57, 0xc3, 0xb0, 0x0f, 0x8e, 0x0c, 0x66, 0x27, 0xd6, 0x5c, 0x4b,
- 0x88, 0x6e, 0xc0, 0x0b, 0xd9, 0xd3, 0x18, 0x8f, 0x61, 0x25, 0x6e, 0x52,
- 0xa7, 0xd0, 0x8d, 0x7e, 0xc0, 0x0c, 0x28, 0xfb, 0x4a, 0xcc, 0x6b, 0xbc,
- 0x17, 0x19, 0xd7, 0xcd, 0x80, 0xd5, 0xf0, 0x4c, 0x48, 0x9c, 0xbd, 0x78,
- 0xf2, 0x5c, 0x8c, 0x27, 0x3f, 0x7f, 0xcf, 0x83, 0xe7, 0xe7, 0x2b, 0xef,
- 0x53, 0x9e, 0xf7, 0x7c, 0xe9, 0x4f, 0x03, 0x0e, 0x7e, 0x4c, 0xcf, 0x01,
- 0x1a, 0x9d, 0x38, 0x2c, 0xd7, 0xc2, 0x7b, 0x91, 0xd7, 0x38, 0x0d, 0x3a,
- 0x09, 0xc8, 0x15, 0xd6, 0x3a, 0xec, 0x59, 0xeb, 0x49, 0xcf, 0x5a, 0x4f,
- 0x7a, 0xd6, 0xca, 0x83, 0xb6, 0xb4, 0x4e, 0xb5, 0xfc, 0xd0, 0x51, 0xee,
- 0x39, 0x8e, 0x39, 0x9f, 0x03, 0x5f, 0xbe, 0x0a, 0x98, 0x38, 0x2d, 0xda,
- 0xa0, 0xc7, 0x94, 0x46, 0x7b, 0x4d, 0x7e, 0x7f, 0xb1, 0xd5, 0xc1, 0x8b,
- 0xdf, 0x2f, 0x48, 0x9c, 0x5a, 0x1d, 0xb8, 0xd2, 0x15, 0xa1, 0xff, 0xf3,
- 0x25, 0xd6, 0x4f, 0x8a, 0xf9, 0x2c, 0x3a, 0x94, 0x8e, 0xb5, 0xd3, 0x98,
- 0xa1, 0xc4, 0x46, 0x7b, 0x9a, 0x99, 0x8e, 0x09, 0xd5, 0x6a, 0x85, 0x0e,
- 0x50, 0x58, 0x65, 0xdb, 0x25, 0xf0, 0x7b, 0x49, 0xe2, 0x61, 0x70, 0x3b,
- 0xa3, 0x5a, 0xc1, 0xba, 0x7e, 0x96, 0xdf, 0x57, 0xf0, 0xce, 0x32, 0x9c,
- 0xd4, 0x9c, 0xb5, 0x5f, 0x45, 0x9b, 0xed, 0xce, 0x66, 0xd9, 0x76, 0xc7,
- 0xff, 0xa0, 0xa9, 0xb6, 0xfd, 0x05, 0xb3, 0xb6, 0xed, 0xea, 0x82, 0xd7,
- 0x66, 0xf1, 0xde, 0xc2, 0xe4, 0xb3, 0x58, 0x8e, 0xfc, 0xc0, 0x35, 0x06,
- 0x3d, 0x6c, 0x96, 0x38, 0x7c, 0x4b, 0xe2, 0x00, 0x5c, 0x01, 0x37, 0x5a,
- 0xe2, 0x6f, 0x04, 0x4b, 0xea, 0xda, 0x4c, 0x43, 0xf7, 0x7d, 0xad, 0x18,
- 0xbf, 0xec, 0xe3, 0x75, 0xdc, 0x27, 0x29, 0x69, 0xe8, 0xc9, 0xd8, 0xb4,
- 0x46, 0xd9, 0xd8, 0x26, 0x21, 0xd7, 0xd9, 0x58, 0xd5, 0x06, 0x8c, 0x4e,
- 0xd4, 0xdb, 0x00, 0xfe, 0x8e, 0x6d, 0x80, 0xa3, 0xfb, 0x63, 0xd3, 0x6c,
- 0x0b, 0x1c, 0xdd, 0x3f, 0x36, 0xc1, 0x36, 0x41, 0xcc, 0x09, 0xfd, 0x67,
- 0x3b, 0xe0, 0xda, 0x00, 0xfe, 0x86, 0x6d, 0x80, 0x0f, 0xf2, 0xcd, 0xf3,
- 0xb9, 0x6b, 0x8f, 0xd7, 0xcd, 0x3b, 0xce, 0xb6, 0x45, 0xd9, 0xd9, 0xcd,
- 0x30, 0xc7, 0xb1, 0x76, 0x80, 0x0a, 0xd3, 0xcc, 0xc3, 0x48, 0xe8, 0x08,
- 0x1d, 0x17, 0x36, 0xef, 0xf4, 0x04, 0x25, 0x0e, 0x9e, 0x18, 0xa0, 0x34,
- 0x6c, 0xc0, 0xdc, 0xc4, 0xb5, 0x32, 0xf8, 0x78, 0x47, 0x13, 0x59, 0xb0,
- 0x75, 0xf0, 0x93, 0xfd, 0x7e, 0xf2, 0xc5, 0xe3, 0x90, 0xb7, 0x98, 0xf0,
- 0x5d, 0xd5, 0x9f, 0xa6, 0xed, 0xaa, 0x69, 0x37, 0xc1, 0x3f, 0x62, 0xde,
- 0xfe, 0x98, 0x90, 0x4d, 0xef, 0x2f, 0x09, 0x1b, 0x94, 0x8c, 0x7d, 0x08,
- 0xf9, 0x75, 0x69, 0xe4, 0xea, 0x1f, 0xdb, 0xfa, 0x2b, 0x1e, 0x1f, 0xb2,
- 0x05, 0x76, 0xdf, 0x84, 0x3c, 0xb9, 0x76, 0x9f, 0xed, 0x71, 0x88, 0x6d,
- 0x26, 0xf4, 0x8d, 0x6d, 0x70, 0x80, 0xd4, 0x19, 0x4d, 0xda, 0x69, 0x5d,
- 0xda, 0xe9, 0x00, 0x6c, 0x34, 0xb7, 0x0d, 0xd9, 0x36, 0x45, 0x1b, 0xf6,
- 0x1a, 0xf6, 0x70, 0x77, 0x3a, 0x35, 0xc1, 0xfe, 0x10, 0xbe, 0x7b, 0x86,
- 0x75, 0xf8, 0xdb, 0x43, 0x23, 0xd3, 0xc2, 0x07, 0xb0, 0xff, 0x80, 0x65,
- 0x66, 0x1b, 0xce, 0xb6, 0x1c, 0xfb, 0x2e, 0x62, 0xdd, 0x8a, 0xad, 0x64,
- 0x39, 0xf1, 0xe2, 0xc5, 0x38, 0xad, 0x21, 0xf5, 0xa4, 0x43, 0x6b, 0x35,
- 0xfe, 0xa8, 0x46, 0x2d, 0x4c, 0x63, 0xc6, 0x7f, 0x2b, 0x70, 0xe6, 0x7d,
- 0xfd, 0x4f, 0xe0, 0xcc, 0xeb, 0xd6, 0xe3, 0x4d, 0x7a, 0x6b, 0xfc, 0xac,
- 0xfe, 0xf0, 0x33, 0xa4, 0x37, 0xc7, 0xcf, 0xd2, 0xbf, 0x58, 0x74, 0x9f,
- 0x0e, 0x3f, 0xdb, 0xad, 0xc0, 0xcf, 0x16, 0xa1, 0xef, 0x53, 0x3a, 0x1d,
- 0x3c, 0x15, 0xc9, 0xfc, 0x2b, 0x45, 0x61, 0x3f, 0x76, 0xd0, 0xc8, 0x94,
- 0x42, 0x7a, 0x17, 0xb5, 0xc3, 0x7f, 0xf4, 0x37, 0x61, 0xfe, 0x5d, 0x44,
- 0x9b, 0x1d, 0xbf, 0xd9, 0x15, 0x1e, 0x05, 0xff, 0xd3, 0x2f, 0x7e, 0x05,
- 0xdf, 0x3c, 0x4d, 0x07, 0xa7, 0x0e, 0x2b, 0x39, 0xfb, 0x08, 0xe0, 0x97,
- 0x83, 0xd5, 0x01, 0x9b, 0x07, 0xec, 0x97, 0x31, 0xef, 0xd3, 0xa4, 0xdf,
- 0x1e, 0x19, 0x48, 0x28, 0xc0, 0xe3, 0x45, 0x01, 0x2f, 0x7d, 0x71, 0x97,
- 0xb1, 0x53, 0xf0, 0x3f, 0x40, 0xef, 0x15, 0x2f, 0x80, 0xbe, 0xbd, 0xf0,
- 0x39, 0x91, 0x67, 0x61, 0x93, 0xe1, 0x8f, 0x22, 0x57, 0x31, 0x2d, 0x7c,
- 0x11, 0x29, 0x0f, 0x76, 0xa7, 0x41, 0xef, 0x38, 0xfc, 0xd3, 0x00, 0xfc,
- 0x53, 0x0c, 0xbe, 0xa9, 0x07, 0x7e, 0xc9, 0x82, 0x5f, 0x0a, 0x83, 0x1f,
- 0x06, 0xcd, 0xc2, 0x47, 0xcd, 0x42, 0xfe, 0xe7, 0x66, 0x48, 0x19, 0x04,
- 0xad, 0xcf, 0xc1, 0x3f, 0x26, 0x63, 0x77, 0x42, 0xcf, 0x22, 0x17, 0x66,
- 0xd5, 0x41, 0xca, 0xc1, 0x9f, 0x77, 0x6e, 0x8b, 0x62, 0xbd, 0x26, 0x4a,
- 0x84, 0x5c, 0x1d, 0xe5, 0xdf, 0x7e, 0x85, 0xac, 0x7f, 0x06, 0xef, 0x22,
- 0x61, 0xa2, 0x3d, 0x94, 0xb5, 0xa3, 0x46, 0xa7, 0xda, 0x03, 0x18, 0x6e,
- 0x87, 0x95, 0x03, 0x53, 0x11, 0x05, 0xfb, 0x03, 0xcd, 0x27, 0x60, 0xeb,
- 0xcb, 0x34, 0x1e, 0x63, 0x3d, 0x29, 0xd3, 0xf3, 0xb1, 0xc8, 0x40, 0x9e,
- 0x5a, 0xe9, 0x98, 0x39, 0x21, 0x7c, 0xbc, 0x16, 0x3f, 0x21, 0x74, 0x2c,
- 0x67, 0xe1, 0x59, 0xec, 0x54, 0xb2, 0x53, 0xbc, 0x7e, 0x14, 0x5a, 0xee,
- 0xc7, 0x93, 0xe7, 0x07, 0xdd, 0xfa, 0x49, 0x39, 0xd8, 0x9d, 0x87, 0x77,
- 0x88, 0x18, 0x8b, 0x58, 0x39, 0x35, 0x11, 0x0d, 0x45, 0x55, 0x8d, 0x86,
- 0x35, 0x85, 0x46, 0x61, 0x6f, 0xd2, 0xb1, 0xff, 0x2c, 0x1f, 0x33, 0x79,
- 0xbc, 0x99, 0xbe, 0x2a, 0xfc, 0x0d, 0xd6, 0x2e, 0x4c, 0x63, 0x5d, 0x3f,
- 0xf8, 0xcb, 0xeb, 0xf2, 0x3c, 0x68, 0xc3, 0xf6, 0x6b, 0x56, 0xe4, 0xd9,
- 0x3c, 0xed, 0x00, 0x6d, 0xd9, 0x66, 0xc1, 0x3e, 0x0c, 0x60, 0xed, 0x5e,
- 0xd8, 0x4f, 0x3c, 0x93, 0xbd, 0x1c, 0x07, 0x05, 0x68, 0xd8, 0x64, 0x79,
- 0xd4, 0xe5, 0x98, 0xe9, 0x19, 0xf3, 0xcb, 0xb1, 0x20, 0xfe, 0xe0, 0x7f,
- 0x4d, 0x96, 0x19, 0x6e, 0x73, 0x4c, 0xc6, 0x34, 0x09, 0xd3, 0xdc, 0x64,
- 0x02, 0x34, 0x8b, 0x9c, 0x4d, 0x10, 0xd3, 0x0c, 0x46, 0x7b, 0x7f, 0x82,
- 0xbe, 0x64, 0xaf, 0xf7, 0x3b, 0xb6, 0xb0, 0x55, 0x49, 0xc1, 0x17, 0xa8,
- 0x56, 0x0b, 0x7c, 0x45, 0x98, 0x5e, 0x15, 0xb0, 0x64, 0xa8, 0xf1, 0x68,
- 0xe8, 0x4b, 0x74, 0xab, 0xb0, 0x11, 0x09, 0xc3, 0x4b, 0xe3, 0xff, 0x52,
- 0xc9, 0x72, 0xbf, 0x69, 0xa5, 0xec, 0x20, 0xf3, 0x89, 0xd7, 0x33, 0x68,
- 0xae, 0xe4, 0xbc, 0xfb, 0x10, 0xa3, 0x16, 0x60, 0x6b, 0xce, 0x4f, 0xaa,
- 0xf4, 0xf8, 0x1d, 0xf0, 0x65, 0xb1, 0x6d, 0x58, 0xcb, 0xc4, 0x78, 0x1e,
- 0x6d, 0x15, 0x6d, 0xe8, 0x99, 0x11, 0x02, 0x8f, 0xb9, 0x9f, 0xe1, 0x4c,
- 0xfc, 0xbd, 0xcf, 0xb1, 0x75, 0x3e, 0xab, 0xde, 0x4a, 0x14, 0x64, 0x7a,
- 0xc5, 0x40, 0x2b, 0xcb, 0x50, 0xd5, 0x6d, 0xc2, 0x5f, 0x3b, 0xb6, 0xc4,
- 0x82, 0x2e, 0xc2, 0xe6, 0xf6, 0x79, 0x75, 0x91, 0xe3, 0x09, 0x57, 0x17,
- 0x23, 0xa1, 0x84, 0x0a, 0x5b, 0xdc, 0xa7, 0xd1, 0x09, 0xd1, 0x56, 0x28,
- 0x31, 0x18, 0x09, 0x2d, 0xa8, 0x1c, 0x4b, 0x33, 0x6c, 0x18, 0xf1, 0x4a,
- 0x40, 0xc2, 0x22, 0x9e, 0xb3, 0xdd, 0x98, 0x30, 0x84, 0x7e, 0x53, 0xf4,
- 0x1f, 0xab, 0xe8, 0xa8, 0x13, 0xff, 0xa9, 0x88, 0x11, 0x0b, 0x88, 0x11,
- 0x53, 0x42, 0x47, 0x8d, 0x04, 0x72, 0x04, 0xd0, 0xdc, 0xd1, 0xcf, 0x42,
- 0x91, 0x71, 0xc9, 0xb1, 0x5c, 0x0e, 0x00, 0x99, 0x13, 0x8e, 0x7d, 0xa4,
- 0x3c, 0xc7, 0x91, 0xa3, 0xea, 0x53, 0x34, 0x5c, 0x60, 0x3f, 0x8e, 0x3f,
- 0x9b, 0x6d, 0x2d, 0xec, 0xa3, 0xf0, 0xc5, 0x51, 0xf0, 0x39, 0x0f, 0x1a,
- 0xac, 0x97, 0x74, 0xdd, 0x4f, 0x07, 0xec, 0x3d, 0xa0, 0x79, 0x9c, 0x46,
- 0x4e, 0x8d, 0xb0, 0xcc, 0xf6, 0x14, 0x28, 0xd2, 0x73, 0x8c, 0xb6, 0x1b,
- 0x73, 0x2c, 0xdf, 0x83, 0xe5, 0x1d, 0xe0, 0x85, 0xd0, 0x51, 0xc8, 0x20,
- 0x65, 0x0b, 0x23, 0xf4, 0x58, 0x89, 0xfb, 0xf2, 0xa0, 0x1d, 0xe2, 0xda,
- 0xfe, 0xfd, 0x52, 0xce, 0x31, 0x9f, 0xe6, 0xce, 0x37, 0x22, 0xe7, 0x63,
- 0x38, 0x86, 0xe1, 0x6f, 0xaa, 0xf3, 0xee, 0x14, 0x3c, 0x8d, 0x18, 0x5d,
- 0x6a, 0x79, 0x87, 0x1f, 0xe3, 0xcf, 0xf7, 0xf3, 0x3b, 0xe6, 0x81, 0xef,
- 0x6f, 0xb6, 0xf6, 0x00, 0x76, 0x10, 0x73, 0xfa, 0xa9, 0xb3, 0xdd, 0xc5,
- 0x37, 0x81, 0xb5, 0xd9, 0xcf, 0x31, 0x9f, 0x1f, 0xa1, 0xec, 0xa9, 0x7c,
- 0x8f, 0x0a, 0x19, 0x9b, 0xcd, 0x28, 0xe4, 0xb7, 0x1e, 0xa6, 0xdc, 0xa9,
- 0xa3, 0x6c, 0x37, 0x40, 0xab, 0x3d, 0xb4, 0x6b, 0x22, 0xd2, 0x73, 0x80,
- 0x34, 0xb1, 0xce, 0x5b, 0x24, 0xe8, 0x1f, 0x9b, 0x15, 0xbe, 0x20, 0x43,
- 0xe9, 0x89, 0xed, 0xa1, 0x4b, 0xe8, 0x1b, 0x1e, 0x8c, 0x84, 0x17, 0xe8,
- 0x09, 0xd0, 0xe5, 0x23, 0xf8, 0x22, 0xab, 0x67, 0x0c, 0x3a, 0x84, 0x9c,
- 0x0a, 0xeb, 0x8f, 0x4a, 0xda, 0xe0, 0xbb, 0xcc, 0x51, 0xd0, 0x8f, 0xf2,
- 0x0e, 0x4d, 0x99, 0x9e, 0x4c, 0xcb, 0xaf, 0xc0, 0xf6, 0x1c, 0x11, 0xb1,
- 0x4b, 0x56, 0xd0, 0xee, 0xd2, 0x06, 0x47, 0x0e, 0x60, 0x8b, 0x30, 0xef,
- 0xe5, 0x41, 0x85, 0xb6, 0x20, 0x4e, 0x3f, 0x24, 0x78, 0xeb, 0xa3, 0x7d,
- 0x66, 0xd4, 0xd8, 0x47, 0xf3, 0x7e, 0x27, 0x56, 0xc0, 0x3c, 0x3d, 0xf7,
- 0x60, 0x0f, 0x90, 0x53, 0xfb, 0xeb, 0xeb, 0xa8, 0x2d, 0x12, 0x4e, 0xa8,
- 0x09, 0xfa, 0x93, 0xd2, 0xdd, 0xe4, 0xe8, 0x77, 0x2b, 0xdb, 0x7e, 0xf0,
- 0xb0, 0xd3, 0x69, 0x5b, 0x78, 0x16, 0x3a, 0xb1, 0x1e, 0xe3, 0xfe, 0xac,
- 0xc0, 0x7d, 0x84, 0xba, 0xa1, 0x6b, 0x22, 0x8f, 0x39, 0x51, 0x8b, 0x17,
- 0xf3, 0xbc, 0x9e, 0xcf, 0x5f, 0xc6, 0x3c, 0xdc, 0xcf, 0x70, 0x78, 0x2f,
- 0x3c, 0x41, 0x23, 0x90, 0xc7, 0x5c, 0x7f, 0x57, 0x68, 0x0c, 0xdf, 0xa4,
- 0x4a, 0x4d, 0x74, 0x54, 0xe3, 0xf1, 0x48, 0x38, 0xaf, 0x1e, 0x42, 0xdc,
- 0xf3, 0xb8, 0xea, 0xb7, 0x7e, 0xe6, 0x67, 0xbf, 0xe3, 0xb7, 0xae, 0x29,
- 0xd5, 0xb9, 0x10, 0x87, 0x8a, 0xdc, 0x60, 0x41, 0x19, 0x2c, 0x5d, 0x52,
- 0x92, 0x85, 0x6b, 0x4a, 0xaa, 0xc4, 0x30, 0x8e, 0xce, 0x67, 0xcf, 0x74,
- 0x82, 0x4e, 0x1f, 0x89, 0xef, 0xe6, 0x7a, 0x8f, 0x50, 0xea, 0xd4, 0xad,
- 0x94, 0x9e, 0xe6, 0xbc, 0x34, 0x02, 0x7c, 0x3f, 0x2a, 0xe7, 0x62, 0x41,
- 0xca, 0x9d, 0xe1, 0x31, 0xb6, 0x5f, 0xd6, 0xd5, 0x45, 0x1f, 0xef, 0x9f,
- 0xf9, 0x6f, 0x52, 0xc1, 0x7e, 0x53, 0xd2, 0x8f, 0xdf, 0x7d, 0x9c, 0x93,
- 0xe1, 0xf7, 0x6f, 0x86, 0xd3, 0xb7, 0x95, 0x16, 0x36, 0xdc, 0xc8, 0x3e,
- 0x57, 0xb3, 0xc7, 0x47, 0x7d, 0x7e, 0x6b, 0x7b, 0x13, 0xb5, 0x84, 0x80,
- 0xc3, 0x4a, 0x7b, 0x64, 0x98, 0x5f, 0x87, 0x1c, 0xb0, 0x4d, 0xd9, 0x0d,
- 0x7e, 0x5a, 0x6c, 0xc3, 0x60, 0x93, 0x76, 0x53, 0xae, 0xc4, 0xb2, 0x1d,
- 0x35, 0x32, 0x90, 0xb1, 0x34, 0x75, 0xb1, 0x1e, 0xb9, 0xba, 0x07, 0xdb,
- 0x9d, 0x87, 0xed, 0x46, 0x3c, 0x64, 0x53, 0xbe, 0x29, 0xce, 0x36, 0xbc,
- 0x0b, 0xb2, 0x85, 0xbe, 0x62, 0x55, 0x17, 0x77, 0x2d, 0xc1, 0x5d, 0x5b,
- 0xc2, 0xa3, 0x02, 0xd5, 0xe2, 0x3f, 0x4b, 0x8c, 0xff, 0x5f, 0x00, 0xff,
- 0xcf, 0x01, 0x7f, 0xc6, 0xa9, 0x31, 0xfe, 0x3b, 0x2b, 0xf8, 0x33, 0x0c,
- 0xfc, 0x1c, 0x64, 0xf1, 0x0d, 0xe8, 0xe2, 0x6b, 0x36, 0x7c, 0x9d, 0x0d,
- 0xff, 0x67, 0xc3, 0xdf, 0xd9, 0xf0, 0x8b, 0x36, 0x7c, 0x1e, 0xf6, 0x74,
- 0x0e, 0x36, 0xe9, 0xac, 0x9d, 0x34, 0x58, 0x9f, 0x92, 0x31, 0xf6, 0x9d,
- 0xbb, 0x65, 0xde, 0x1d, 0x92, 0x71, 0xf7, 0xa7, 0x64, 0x2c, 0x7b, 0x00,
- 0xb1, 0xec, 0x66, 0x1a, 0xed, 0xe1, 0x9c, 0xa4, 0x05, 0xcf, 0x75, 0x78,
- 0x22, 0x6e, 0xed, 0x49, 0x48, 0xbd, 0xfc, 0x0c, 0x62, 0x5c, 0xd8, 0xff,
- 0x1e, 0xe4, 0x37, 0x19, 0xc4, 0x6a, 0x56, 0x1f, 0xc7, 0xe5, 0xb0, 0x65,
- 0xef, 0x37, 0x39, 0x76, 0xfe, 0x2e, 0x19, 0x03, 0xbb, 0xed, 0x56, 0xc0,
- 0xa4, 0xd1, 0xd7, 0x8a, 0x6f, 0x7e, 0x07, 0xb2, 0xdf, 0x86, 0xf6, 0xce,
- 0x3a, 0x18, 0xe4, 0xb3, 0x56, 0x16, 0x7d, 0x11, 0xc0, 0xb4, 0x61, 0x9d,
- 0x0e, 0xb4, 0xf7, 0xa0, 0x7d, 0x8b, 0xb3, 0x8e, 0xf1, 0x2b, 0x68, 0xa7,
- 0xea, 0xbe, 0xd9, 0x8a, 0xbe, 0x4c, 0x5d, 0xdf, 0x9b, 0xe8, 0x4b, 0xa2,
- 0x6f, 0x51, 0x7e, 0x97, 0x47, 0x3b, 0x52, 0x07, 0xb3, 0x88, 0x3e, 0xc6,
- 0xf1, 0x5b, 0x78, 0xde, 0x47, 0xa3, 0x19, 0x8e, 0x03, 0xdc, 0xb1, 0xdc,
- 0x7a, 0x6a, 0xe3, 0xdc, 0xf7, 0x43, 0x21, 0x3b, 0xf3, 0xd2, 0x46, 0xa7,
- 0x27, 0xd8, 0x4f, 0x8c, 0x20, 0xee, 0xe1, 0x71, 0xe1, 0x9c, 0x3c, 0xfd,
- 0x1f, 0x00, 0xf6, 0x61, 0x8c, 0x21, 0x56, 0xb7, 0xcb, 0x4d, 0x8d, 0xc7,
- 0x1f, 0xc5, 0xf8, 0x5f, 0xca, 0x6f, 0x2b, 0x73, 0x03, 0xfe, 0x1b, 0x75,
- 0x7d, 0x6a, 0xb0, 0xb6, 0xbd, 0xd6, 0xf3, 0xbe, 0x4d, 0x5f, 0xfa, 0xfd,
- 0x48, 0x1d, 0xfc, 0xef, 0x6e, 0xa8, 0x6d, 0x3f, 0xc5, 0xdf, 0x20, 0x87,
- 0x70, 0xdb, 0x09, 0xc8, 0x1d, 0xdb, 0xa4, 0xfa, 0x79, 0x3e, 0x6b, 0xd4,
- 0xf6, 0x6d, 0x32, 0x6b, 0xdb, 0x1c, 0x27, 0x31, 0x5c, 0x08, 0xf2, 0xde,
- 0xa1, 0xec, 0xb2, 0x7f, 0x13, 0xe3, 0x61, 0xe5, 0x5e, 0xdb, 0x8b, 0x67,
- 0x48, 0xe6, 0x46, 0xe1, 0x4a, 0xcc, 0x3b, 0x5f, 0x0a, 0x40, 0xae, 0x3e,
- 0x0f, 0x9e, 0x73, 0xdc, 0x53, 0xd5, 0xf1, 0xf7, 0x68, 0x39, 0x1d, 0x67,
- 0x1f, 0xc0, 0x31, 0xfe, 0x36, 0x11, 0x1f, 0xfb, 0xe2, 0x4f, 0x70, 0x0c,
- 0xf6, 0xb4, 0xe3, 0x5b, 0x2c, 0xf8, 0x43, 0xb4, 0x4b, 0x7e, 0xc7, 0x6e,
- 0x22, 0x9f, 0xc8, 0x16, 0xd8, 0x9f, 0xb1, 0x0f, 0x89, 0xc0, 0x4e, 0xb3,
- 0x1f, 0xfd, 0x24, 0x7d, 0xc6, 0x5d, 0xcd, 0x6c, 0xfb, 0x34, 0xeb, 0x05,
- 0xc4, 0x0b, 0x1c, 0xe7, 0xb1, 0xed, 0xc6, 0x7b, 0xd1, 0x8d, 0x57, 0xee,
- 0xd7, 0xc8, 0xaa, 0xfa, 0x11, 0x67, 0x8f, 0x5b, 0x59, 0x37, 0x56, 0xb1,
- 0xef, 0xc6, 0xb6, 0xed, 0xc7, 0x75, 0xb6, 0xe1, 0xb2, 0xb0, 0x0d, 0x0f,
- 0x6a, 0x7e, 0xeb, 0xf7, 0x9b, 0x1d, 0x79, 0x6d, 0x6c, 0x1b, 0xee, 0xad,
- 0xd8, 0x06, 0x57, 0x5e, 0xbd, 0x79, 0xeb, 0x0f, 0xc0, 0x1b, 0x0b, 0xbc,
- 0xa9, 0xaf, 0xd5, 0x70, 0x8e, 0xe2, 0x87, 0x1f, 0xe2, 0x18, 0x91, 0x73,
- 0xd9, 0x18, 0xe5, 0x62, 0x45, 0xc4, 0x6a, 0x91, 0xd9, 0xd9, 0x4a, 0x8e,
- 0xf5, 0x35, 0x69, 0xbb, 0x6b, 0xe2, 0x22, 0x7a, 0xbc, 0x78, 0x09, 0xf8,
- 0x73, 0xbc, 0xa5, 0x49, 0x1b, 0xc1, 0xfd, 0xe3, 0x12, 0x47, 0x7e, 0xe7,
- 0x3a, 0x1e, 0x7c, 0x69, 0xf1, 0x47, 0xe0, 0x15, 0xc7, 0x7d, 0x51, 0x27,
- 0xde, 0xab, 0x89, 0xa9, 0xd7, 0xf8, 0xc9, 0xe2, 0x78, 0x89, 0x61, 0x74,
- 0x19, 0x2f, 0x05, 0x64, 0x5e, 0x63, 0xc8, 0x3c, 0x87, 0x63, 0x6d, 0xae,
- 0xb1, 0xd6, 0xc7, 0x50, 0x0b, 0x43, 0xc1, 0x6d, 0xcc, 0x13, 0x8e, 0xa1,
- 0xda, 0x28, 0x39, 0xe3, 0xc4, 0x50, 0x4e, 0x9d, 0xcd, 0xcd, 0x71, 0x5c,
- 0x5c, 0xd9, 0x0f, 0xef, 0xc0, 0x3e, 0x45, 0x9e, 0x14, 0x74, 0xea, 0x7f,
- 0x1a, 0xec, 0xf6, 0x51, 0xf4, 0x8f, 0xba, 0xfd, 0x9e, 0x5c, 0xc3, 0xc5,
- 0x85, 0x7d, 0xbd, 0x1b, 0xd3, 0xed, 0x96, 0x31, 0x1d, 0x62, 0x18, 0xdb,
- 0xc9, 0xbb, 0xf6, 0x16, 0x33, 0xe8, 0xe3, 0x75, 0x11, 0x1b, 0x12, 0xc7,
- 0x49, 0x90, 0xaf, 0xfd, 0x91, 0x50, 0x58, 0xad, 0xc7, 0xab, 0x75, 0xa1,
- 0x16, 0xaf, 0x41, 0xf1, 0xdd, 0xf8, 0x92, 0xef, 0x48, 0xc4, 0x92, 0xe3,
- 0xf6, 0x10, 0xe8, 0xc5, 0xf8, 0xb9, 0xba, 0xe1, 0xc6, 0xc9, 0x8c, 0xd3,
- 0x3f, 0x82, 0xc6, 0xbb, 0x15, 0xfe, 0x7e, 0xcc, 0xde, 0x2f, 0xe8, 0x96,
- 0x15, 0xb8, 0x0e, 0x7b, 0x70, 0x1d, 0x91, 0xb8, 0xb2, 0x2e, 0xb0, 0x7e,
- 0x78, 0x6b, 0x9a, 0xa6, 0xd8, 0x1b, 0x70, 0x0e, 0xf3, 0xb9, 0xb9, 0x6a,
- 0x2d, 0x0c, 0xf9, 0xb6, 0xc1, 0x1f, 0x02, 0xd7, 0xac, 0x88, 0x43, 0x03,
- 0x0b, 0xf5, 0x34, 0x1c, 0xc7, 0x5a, 0x88, 0xdb, 0x81, 0x8f, 0xcb, 0xf3,
- 0x26, 0x89, 0xcf, 0x37, 0xc5, 0xdc, 0x63, 0xa2, 0x06, 0xea, 0xd3, 0x39,
- 0x77, 0xc9, 0x0a, 0xde, 0x69, 0x92, 0x77, 0x8f, 0x56, 0xf0, 0x73, 0x78,
- 0x1c, 0x90, 0x74, 0xe5, 0xdc, 0x95, 0x75, 0x5a, 0xf0, 0xa7, 0x9d, 0x73,
- 0xd3, 0x41, 0x6a, 0x14, 0x23, 0x2f, 0x0c, 0xa9, 0xdb, 0x1c, 0x3a, 0x3a,
- 0x31, 0xf2, 0xda, 0xba, 0x18, 0xf9, 0xb6, 0x20, 0xc7, 0x5a, 0xc3, 0x50,
- 0x82, 0x79, 0xf8, 0xba, 0x97, 0x6d, 0xc8, 0x36, 0x70, 0x3d, 0x5f, 0x53,
- 0xbb, 0xec, 0x59, 0xa6, 0xd6, 0x1c, 0x20, 0xdf, 0x0c, 0xfb, 0x0e, 0x0b,
- 0x79, 0x06, 0x91, 0x36, 0xc9, 0x3a, 0xcb, 0xbe, 0xbd, 0x1a, 0x67, 0xcf,
- 0x51, 0xa3, 0x18, 0xfb, 0x46, 0xfd, 0xfa, 0x79, 0xbf, 0xdf, 0x3a, 0xac,
- 0x3b, 0x36, 0x73, 0x25, 0xbf, 0xee, 0xc2, 0xed, 0x41, 0x9c, 0xad, 0x50,
- 0x93, 0x55, 0xc0, 0xfe, 0xde, 0xf0, 0x37, 0x5b, 0xae, 0x2e, 0x06, 0x68,
- 0xfd, 0xcc, 0x2d, 0x42, 0x1f, 0x8d, 0xc9, 0xaa, 0x3e, 0x8e, 0x82, 0x37,
- 0x19, 0xa7, 0x06, 0x60, 0xae, 0xa7, 0xeb, 0xd7, 0x0b, 0xc6, 0xed, 0x37,
- 0xfd, 0xaa, 0xe5, 0xca, 0xc0, 0xf5, 0xf2, 0x91, 0x4f, 0xd5, 0xd1, 0xba,
- 0x51, 0x4d, 0xf8, 0x2c, 0xe8, 0x1a, 0x47, 0xde, 0x1d, 0x79, 0x81, 0x10,
- 0x3b, 0x39, 0x79, 0x78, 0x1a, 0xb9, 0x77, 0xe4, 0x02, 0xe7, 0xe3, 0x6e,
- 0x7e, 0xfe, 0x6a, 0x29, 0x72, 0x36, 0x8f, 0x9c, 0x79, 0x1e, 0x39, 0xf9,
- 0xcb, 0xc8, 0xc9, 0xcf, 0x97, 0x7a, 0x41, 0xff, 0x1e, 0x99, 0x8f, 0xb3,
- 0x8e, 0x99, 0x74, 0x11, 0xb9, 0xd3, 0x77, 0x67, 0xd8, 0x46, 0x74, 0xd1,
- 0x3d, 0xc8, 0x35, 0xbe, 0x3f, 0xa9, 0x68, 0x9d, 0x7d, 0x01, 0x5f, 0xc2,
- 0xb8, 0x91, 0x38, 0x71, 0x29, 0x4f, 0x1a, 0xc7, 0x8a, 0x23, 0x4d, 0x7e,
- 0x6b, 0xae, 0x95, 0x5a, 0xf6, 0x2c, 0xcb, 0x93, 0x6a, 0xac, 0xe8, 0xc2,
- 0x19, 0xd4, 0xd9, 0xf7, 0x87, 0x9c, 0xdb, 0xc4, 0x48, 0xe4, 0xd3, 0xeb,
- 0xe8, 0xed, 0x93, 0x65, 0xda, 0x19, 0xbb, 0x56, 0xbe, 0x68, 0xad, 0xa3,
- 0x6c, 0xef, 0x43, 0x32, 0x97, 0x5c, 0x78, 0x28, 0x69, 0xe5, 0x43, 0x3e,
- 0xf7, 0x7c, 0x62, 0x42, 0x47, 0x84, 0xc8, 0xbf, 0x20, 0xcd, 0x0d, 0x20,
- 0x71, 0x6e, 0xd9, 0xfe, 0x02, 0x1f, 0x10, 0xb1, 0x6d, 0x9c, 0x33, 0x03,
- 0xa2, 0xd6, 0xb6, 0xd1, 0xe2, 0x7e, 0x03, 0xfc, 0xbe, 0x8f, 0xe6, 0x90,
- 0x43, 0x14, 0x44, 0x1e, 0xde, 0x0e, 0x78, 0x37, 0x0f, 0xbf, 0x1f, 0xb9,
- 0x01, 0xd3, 0xd8, 0x04, 0xfc, 0x6f, 0x03, 0xc6, 0x6b, 0x43, 0x9f, 0x6b,
- 0x22, 0xf1, 0x3d, 0x8f, 0xb7, 0x13, 0xd7, 0x65, 0xab, 0xf3, 0xf2, 0x9c,
- 0x3c, 0xf6, 0x61, 0xf9, 0xf6, 0xbe, 0x3e, 0xcf, 0xdc, 0x6d, 0x9e, 0xb9,
- 0xef, 0xf0, 0xcc, 0xed, 0xc3, 0xb7, 0x2e, 0x3e, 0x41, 0x7c, 0xeb, 0xae,
- 0xf1, 0xb7, 0x9e, 0x35, 0x5c, 0xdc, 0xdb, 0x3d, 0xb8, 0xbf, 0x8f, 0xf9,
- 0xb9, 0xcf, 0xf4, 0xf4, 0xf1, 0x9a, 0x1b, 0x68, 0x6e, 0xb0, 0x8d, 0x16,
- 0x4f, 0x72, 0x5f, 0xd0, 0x83, 0x0b, 0xe3, 0x17, 0x90, 0x63, 0x6d, 0x74,
- 0xf1, 0x64, 0x8b, 0xc0, 0x9b, 0xfd, 0xf9, 0xc6, 0xca, 0x9a, 0x57, 0xb0,
- 0xa6, 0x3b, 0x97, 0x89, 0x6f, 0x19, 0x96, 0xf1, 0xe3, 0x31, 0xee, 0xe3,
- 0xb1, 0x37, 0xcb, 0x5f, 0x33, 0x82, 0xce, 0x9e, 0x0d, 0xc6, 0xcd, 0xfd,
- 0x56, 0x6b, 0x26, 0x8b, 0xdb, 0x9d, 0x34, 0x1b, 0xd4, 0xc0, 0x37, 0x55,
- 0xfa, 0x28, 0xae, 0x23, 0xa8, 0x4a, 0xb4, 0x8f, 0xf9, 0xbc, 0x4e, 0xd6,
- 0xaf, 0x5b, 0x30, 0x6f, 0xd8, 0xcd, 0xd1, 0x88, 0xe5, 0x38, 0x27, 0xec,
- 0xbe, 0x26, 0xc7, 0xd9, 0xee, 0xb3, 0xdf, 0xc7, 0x53, 0xc8, 0xaa, 0x3c,
- 0xaf, 0x29, 0xed, 0xa0, 0x83, 0x50, 0xcf, 0x8b, 0xb2, 0x9e, 0xb2, 0xe8,
- 0xad, 0x99, 0x18, 0x4e, 0x1c, 0xe3, 0x9c, 0xed, 0xac, 0x85, 0xfe, 0xe0,
- 0xbd, 0x98, 0x00, 0x1e, 0x61, 0x8a, 0xe2, 0xaf, 0x50, 0xca, 0xe3, 0x69,
- 0xe1, 0xa9, 0xe0, 0xc9, 0xf5, 0x0c, 0x1d, 0x4f, 0xe8, 0x18, 0xec, 0x53,
- 0xb4, 0xef, 0x92, 0x93, 0x3f, 0x41, 0x37, 0xde, 0x9e, 0x74, 0xea, 0x51,
- 0x8b, 0xd6, 0x72, 0xf5, 0xa8, 0x3f, 0x67, 0x9e, 0x9c, 0x70, 0xeb, 0x51,
- 0x8b, 0x24, 0xea, 0x51, 0x27, 0x56, 0xa8, 0x47, 0x25, 0x56, 0x5f, 0x8f,
- 0xe2, 0xf9, 0x35, 0xda, 0xd7, 0x4f, 0xca, 0x17, 0x64, 0x3d, 0xea, 0x3d,
- 0x72, 0xea, 0x51, 0x17, 0xa9, 0x71, 0x3d, 0xea, 0x78, 0x5d, 0x3d, 0x2a,
- 0x28, 0xea, 0x51, 0x3c, 0x8f, 0x53, 0x8f, 0x12, 0xed, 0xbe, 0x88, 0xa7,
- 0xee, 0x42, 0xf4, 0xee, 0x64, 0x07, 0x68, 0x66, 0xd0, 0xf7, 0x1a, 0xda,
- 0x34, 0x45, 0xc8, 0xdb, 0x4a, 0x35, 0xd0, 0x07, 0x6e, 0xb8, 0xbe, 0xa2,
- 0xd0, 0x06, 0xcc, 0x9b, 0xec, 0x7b, 0xd8, 0x53, 0x63, 0x61, 0x9a, 0xff,
- 0x62, 0xea, 0x2c, 0x07, 0x45, 0x9d, 0xe5, 0x87, 0x6b, 0xbc, 0x75, 0x96,
- 0x45, 0xba, 0x7e, 0x9d, 0xe5, 0x60, 0x83, 0x3a, 0xcb, 0x5b, 0x54, 0xad,
- 0xb3, 0xbc, 0x45, 0xd5, 0x3a, 0xcb, 0xc1, 0x12, 0xe7, 0xe2, 0x3e, 0x89,
- 0x5f, 0x06, 0xed, 0x41, 0xf1, 0xc7, 0xb5, 0x97, 0xc5, 0xca, 0x1e, 0x7e,
- 0xd9, 0x6a, 0x2f, 0x6c, 0x03, 0x22, 0x17, 0x2e, 0xd7, 0xd4, 0x5e, 0xb8,
- 0x0d, 0x9d, 0xb1, 0xd7, 0x08, 0x19, 0x99, 0x83, 0x7f, 0x5f, 0x9c, 0x0c,
- 0x61, 0xce, 0x0e, 0xf8, 0x8c, 0x0e, 0xe4, 0x06, 0x61, 0xb4, 0x15, 0xda,
- 0x64, 0x0d, 0xa1, 0x8f, 0xc7, 0xd9, 0x0e, 0x43, 0xb7, 0x6c, 0x77, 0x7f,
- 0x0f, 0x48, 0x1a, 0x44, 0x68, 0xb8, 0x9d, 0xf4, 0x20, 0xfb, 0x8e, 0xc9,
- 0x3d, 0x74, 0xc8, 0xde, 0x22, 0xf6, 0xbd, 0xc1, 0xaa, 0x95, 0xb9, 0xc1,
- 0x1b, 0x90, 0xb9, 0xcc, 0xaa, 0x65, 0x8e, 0xe5, 0xcd, 0x39, 0xf7, 0xdd,
- 0x60, 0xf1, 0xfa, 0x1d, 0x02, 0xa7, 0x77, 0x1b, 0xc8, 0xfb, 0x18, 0xec,
- 0x8e, 0x33, 0xbf, 0x2e, 0xd7, 0xab, 0x8f, 0x87, 0x9f, 0x6d, 0x66, 0xff,
- 0xbd, 0x72, 0x3d, 0xb1, 0xde, 0x7f, 0xaf, 0xe4, 0x47, 0x15, 0x61, 0x93,
- 0xb3, 0x25, 0xae, 0xed, 0x7b, 0xf9, 0x33, 0x8f, 0x9c, 0x00, 0x7d, 0x42,
- 0x0f, 0x98, 0xae, 0x41, 0xf0, 0x01, 0xeb, 0xd8, 0x4f, 0xc9, 0x5a, 0x16,
- 0x9e, 0x05, 0x97, 0x7f, 0xad, 0xb0, 0x99, 0xee, 0x18, 0xdb, 0x01, 0x0b,
- 0xfe, 0x8f, 0xeb, 0x28, 0x7c, 0x8e, 0xca, 0xfd, 0x2e, 0x5f, 0xbb, 0x2e,
- 0xbc, 0xa7, 0x72, 0xbb, 0x5c, 0xce, 0x8a, 0x7a, 0x2d, 0xa9, 0x9d, 0x7d,
- 0xd3, 0x2d, 0x6c, 0x6b, 0xb6, 0x58, 0xae, 0xcc, 0x26, 0xf0, 0xce, 0x7c,
- 0x7d, 0x17, 0x36, 0x9c, 0xcf, 0xaa, 0xbf, 0x23, 0x6a, 0x04, 0x73, 0x36,
- 0xdb, 0x6b, 0x8e, 0x41, 0x7f, 0x0b, 0xb2, 0xc4, 0xef, 0x51, 0x71, 0x2e,
- 0x21, 0x6a, 0xf8, 0x83, 0xdc, 0x76, 0xed, 0x4a, 0x94, 0xed, 0x30, 0xf6,
- 0x5c, 0xa5, 0x31, 0xe2, 0x23, 0xc8, 0x0c, 0xc7, 0xb1, 0x0c, 0xe7, 0xc6,
- 0x9e, 0x9a, 0xa7, 0x66, 0xab, 0xcb, 0xb8, 0x88, 0x75, 0x39, 0x00, 0x9a,
- 0xed, 0x10, 0x31, 0xea, 0xb8, 0x5d, 0xa6, 0xea, 0x19, 0x3f, 0xd3, 0xdc,
- 0x39, 0xe7, 0x3f, 0x66, 0x2f, 0x47, 0xfb, 0xcd, 0x37, 0x48, 0x7b, 0x47,
- 0x1f, 0x6b, 0xe9, 0xae, 0x23, 0x7e, 0x71, 0xe9, 0xee, 0xfa, 0xa8, 0x49,
- 0x49, 0x83, 0xa8, 0xac, 0x2b, 0x7e, 0x5a, 0x9e, 0x29, 0xfd, 0x5f, 0xd8,
- 0xaf, 0xe2, 0xd9, 0xaf, 0xab, 0xbb, 0xfb, 0xe4, 0x7e, 0xc3, 0x75, 0xba,
- 0x1b, 0x97, 0x75, 0xb9, 0x5f, 0x84, 0xee, 0xba, 0x7b, 0xe2, 0xb5, 0xb7,
- 0x5c, 0x67, 0xdd, 0x67, 0x48, 0x8d, 0xaf, 0x14, 0x7b, 0xff, 0xb4, 0xf9,
- 0xe3, 0xc5, 0xde, 0x1f, 0x87, 0x9e, 0x5e, 0xbd, 0x65, 0x1a, 0xb6, 0x89,
- 0xb8, 0xc2, 0xd1, 0x1f, 0xd8, 0xe3, 0x82, 0x9f, 0x16, 0x1e, 0xd2, 0xe9,
- 0x9f, 0xee, 0xe4, 0xfa, 0xac, 0x26, 0x73, 0x7c, 0x6e, 0x7f, 0xb1, 0x95,
- 0x63, 0xab, 0x4d, 0xd6, 0x77, 0x44, 0x6e, 0x95, 0x57, 0x4d, 0x8f, 0x1f,
- 0x31, 0x30, 0xce, 0x63, 0x61, 0xba, 0x1c, 0xbc, 0x91, 0xb8, 0xbc, 0xcb,
- 0x58, 0xf4, 0xad, 0x26, 0x2e, 0xbf, 0x55, 0xf7, 0x5b, 0x7f, 0xdd, 0x7a,
- 0xbd, 0x3a, 0x47, 0x35, 0x2e, 0xe7, 0x7c, 0x3e, 0xe8, 0xd4, 0x18, 0x4c,
- 0x8e, 0xcf, 0xd7, 0x4a, 0x9e, 0xf0, 0x3b, 0x72, 0x11, 0x1b, 0x79, 0x08,
- 0x64, 0xfc, 0x55, 0xc8, 0xca, 0x2b, 0x36, 0xf2, 0x0e, 0x1b, 0xf9, 0x88,
- 0x8d, 0xdc, 0xc3, 0x46, 0xee, 0x61, 0xf7, 0xc8, 0x1c, 0x26, 0x23, 0xeb,
- 0x56, 0x7c, 0x46, 0xcb, 0xf9, 0x61, 0x5e, 0xc9, 0xd8, 0xe3, 0x7c, 0x1f,
- 0x41, 0x4d, 0xc6, 0x36, 0xca, 0x78, 0xf0, 0x38, 0xdf, 0x77, 0x28, 0xab,
- 0x71, 0xae, 0x45, 0x91, 0xaa, 0xc6, 0x6f, 0x87, 0x8f, 0xda, 0x0e, 0xbc,
- 0x9a, 0x79, 0xdc, 0xa7, 0xc6, 0x5b, 0x99, 0x76, 0x8a, 0x1a, 0x5f, 0x2b,
- 0xcf, 0x0d, 0x7a, 0x03, 0x0e, 0xfe, 0xdd, 0xdc, 0xd6, 0xd4, 0xf8, 0xdd,
- 0xec, 0xd3, 0xc2, 0xa4, 0xba, 0xfd, 0xb7, 0x07, 0x98, 0xae, 0xa4, 0xde,
- 0x16, 0xe0, 0xb8, 0x76, 0xde, 0xf6, 0x8b, 0x3b, 0x05, 0xc9, 0x18, 0xd7,
- 0xcc, 0xb8, 0x5d, 0xa5, 0xab, 0xba, 0x2c, 0x5d, 0xfd, 0x95, 0xfa, 0x3f,
- 0xd3, 0xd2, 0xc7, 0x70, 0xa2, 0x36, 0xc6, 0x34, 0x75, 0xe7, 0xe3, 0xf3,
- 0x66, 0x5e, 0x47, 0xdc, 0x63, 0xc0, 0xf3, 0x60, 0x33, 0xb5, 0x0d, 0x0e,
- 0xf9, 0x2d, 0xef, 0xba, 0x6c, 0x43, 0x76, 0x90, 0x37, 0xc7, 0x5a, 0x7e,
- 0xcd, 0xa8, 0x38, 0x1b, 0x49, 0xf6, 0x47, 0x85, 0xec, 0xb0, 0xac, 0x69,
- 0xe2, 0xce, 0xd5, 0x47, 0xe2, 0x1e, 0x09, 0xcb, 0x19, 0xcb, 0xf2, 0x78,
- 0x7f, 0x57, 0x58, 0x53, 0x5b, 0xb0, 0x46, 0x98, 0xd2, 0x25, 0x71, 0x56,
- 0x80, 0x7c, 0xe9, 0xdc, 0x3a, 0x6a, 0xfb, 0x07, 0xbd, 0x9a, 0xc7, 0x46,
- 0x9d, 0xb3, 0x7a, 0xbb, 0xde, 0xff, 0x8d, 0x8a, 0x73, 0x65, 0xc7, 0x06,
- 0xb9, 0xe7, 0xc3, 0xab, 0x3b, 0xff, 0xbe, 0xbe, 0x3e, 0xb5, 0xd4, 0xd7,
- 0x0d, 0x24, 0x0d, 0x98, 0x36, 0x8d, 0xcf, 0xee, 0xe7, 0x4b, 0x7c, 0xaf,
- 0x25, 0x12, 0xe3, 0xdc, 0x6d, 0x44, 0xdc, 0xf9, 0x50, 0x21, 0x85, 0x3a,
- 0x8d, 0x19, 0x9c, 0xf3, 0x85, 0x86, 0x7d, 0x71, 0xca, 0x64, 0x27, 0x48,
- 0x43, 0xac, 0x98, 0xa9, 0xd6, 0x03, 0x1f, 0x5c, 0x43, 0x96, 0x2b, 0x97,
- 0x51, 0xce, 0x1f, 0x6a, 0xce, 0xed, 0x16, 0xe9, 0xb0, 0x72, 0xa0, 0x74,
- 0x84, 0x0e, 0x34, 0x8c, 0x29, 0x1b, 0xd7, 0x03, 0x2f, 0xd6, 0xd5, 0x14,
- 0x16, 0x44, 0x4d, 0x21, 0xb7, 0xc6, 0x6f, 0x3d, 0x19, 0x70, 0xee, 0xb5,
- 0x34, 0xd6, 0x93, 0x5d, 0x15, 0x3d, 0x71, 0xe1, 0xf8, 0x2c, 0xbe, 0x8d,
- 0x76, 0x8a, 0xb5, 0x0e, 0x2b, 0x59, 0xbb, 0x95, 0x76, 0x1a, 0x0e, 0xd6,
- 0xa3, 0x36, 0xe3, 0x75, 0x58, 0x39, 0x68, 0xe7, 0x95, 0xb4, 0xa8, 0x3d,
- 0x70, 0x8c, 0xbf, 0xe6, 0xda, 0x30, 0x95, 0xe9, 0xed, 0x98, 0xfb, 0x3d,
- 0xc3, 0x78, 0x6b, 0x8a, 0x2e, 0x9d, 0xf8, 0x2e, 0x51, 0x58, 0xe6, 0x6f,
- 0xce, 0x7c, 0xb9, 0x29, 0xae, 0x25, 0xde, 0x8f, 0xfd, 0x33, 0xfc, 0x6e,
- 0x25, 0x39, 0x55, 0x2e, 0xa7, 0x31, 0x3e, 0xd6, 0x7b, 0xaf, 0xc8, 0x8d,
- 0xd4, 0x38, 0x0d, 0x71, 0x8e, 0xac, 0x2d, 0xc9, 0x91, 0xd3, 0xd0, 0x35,
- 0xc4, 0x20, 0x76, 0x13, 0xbe, 0x75, 0xe3, 0x91, 0xcf, 0xae, 0x75, 0x64,
- 0xe4, 0xbb, 0x12, 0x0f, 0x1e, 0xff, 0xfb, 0x80, 0x7b, 0x0f, 0x28, 0x77,
- 0x2a, 0x8d, 0xfd, 0x37, 0x51, 0xca, 0x74, 0xf2, 0xbb, 0xec, 0x99, 0x23,
- 0x1b, 0x6a, 0xe1, 0xd1, 0x77, 0xca, 0x85, 0x0f, 0xd6, 0xc1, 0xf3, 0x19,
- 0xd7, 0x5f, 0xd5, 0xc1, 0x07, 0x3d, 0xf0, 0x66, 0x1d, 0x3c, 0xe2, 0xae,
- 0x33, 0xdf, 0xa8, 0x83, 0x37, 0x3d, 0xf0, 0xed, 0x75, 0xf0, 0xed, 0x80,
- 0x7f, 0xa3, 0x0e, 0x1e, 0x7d, 0xa7, 0x90, 0x13, 0x08, 0xda, 0x70, 0x8c,
- 0x74, 0x48, 0xe6, 0x89, 0x78, 0x2e, 0xb9, 0x1f, 0xc9, 0xf2, 0xd3, 0x01,
- 0x1a, 0x7b, 0xeb, 0xb5, 0x09, 0xd8, 0xa8, 0xaa, 0x4c, 0x39, 0xfa, 0xea,
- 0x95, 0x25, 0x96, 0xbd, 0x3c, 0xe4, 0x15, 0x7a, 0x54, 0x80, 0x3e, 0x15,
- 0x5c, 0x5f, 0xca, 0x77, 0xaa, 0x22, 0xc7, 0x1d, 0x3d, 0x56, 0x68, 0xbd,
- 0x35, 0x2f, 0x73, 0x91, 0xab, 0x8c, 0x3b, 0xfc, 0x86, 0xeb, 0x3b, 0xe8,
- 0x84, 0x63, 0x57, 0x58, 0xbf, 0x79, 0x7e, 0x69, 0x5f, 0x4a, 0x2c, 0x87,
- 0xce, 0x3a, 0xe9, 0x25, 0x32, 0x1b, 0x5e, 0x52, 0x77, 0xf1, 0xd5, 0xd9,
- 0x77, 0x12, 0xf6, 0x3d, 0xd7, 0xe2, 0xb7, 0x36, 0xac, 0xbd, 0x9e, 0x7d,
- 0xcf, 0x78, 0xec, 0x7b, 0x38, 0x58, 0xf5, 0xf9, 0x8f, 0x09, 0x9f, 0xdf,
- 0xd1, 0xc0, 0x66, 0xac, 0xde, 0xe7, 0xef, 0xfd, 0xd8, 0x3e, 0x7f, 0xb9,
- 0x75, 0x57, 0xe3, 0xf3, 0x1f, 0x69, 0xf9, 0x78, 0x3e, 0x9f, 0xd7, 0xac,
- 0xaf, 0x65, 0x7a, 0xcf, 0x59, 0x8e, 0xca, 0x18, 0x7b, 0xb7, 0x27, 0xc6,
- 0x66, 0xfc, 0xbe, 0x27, 0xef, 0x02, 0x9e, 0x5e, 0xeb, 0xc8, 0xdb, 0x51,
- 0x19, 0xa7, 0x73, 0xec, 0x8d, 0xf7, 0xc2, 0x23, 0x90, 0xd1, 0x7c, 0x8f,
- 0x8f, 0x54, 0x9a, 0x35, 0x9d, 0xb3, 0xed, 0x9f, 0x6f, 0xae, 0x17, 0xa1,
- 0xcb, 0xc2, 0x9f, 0x24, 0x3e, 0x81, 0x5a, 0xea, 0x49, 0xc8, 0x8f, 0xbb,
- 0xaf, 0x95, 0x6a, 0xa9, 0xf5, 0xe7, 0x1f, 0x7c, 0xee, 0x41, 0xca, 0x03,
- 0x95, 0x73, 0x10, 0xaf, 0x4e, 0xe9, 0x94, 0x9d, 0x21, 0xdd, 0x8c, 0x93,
- 0xb2, 0x8f, 0x71, 0x8e, 0xfd, 0xb0, 0x52, 0x6f, 0x3f, 0x24, 0x6b, 0x30,
- 0xea, 0xb2, 0x77, 0x82, 0x7e, 0x02, 0x7c, 0x58, 0xaf, 0x9c, 0x1a, 0x8c,
- 0xea, 0xdc, 0x09, 0x3a, 0xfe, 0xf3, 0xbb, 0x13, 0xc4, 0xf3, 0x6b, 0xb4,
- 0xb7, 0xc1, 0x9d, 0x20, 0xdf, 0x2a, 0xef, 0x04, 0xad, 0x17, 0x35, 0x18,
- 0x9e, 0xc7, 0xa9, 0xc1, 0x70, 0xbb, 0xb3, 0x8f, 0xe5, 0x3a, 0x4c, 0xa3,
- 0x93, 0xb7, 0x88, 0x7b, 0xa8, 0x9d, 0x7d, 0xb5, 0xf2, 0xbd, 0xef, 0x13,
- 0x8d, 0xa5, 0x79, 0xbd, 0xa3, 0x0d, 0xef, 0xb6, 0x24, 0x3f, 0xc1, 0x9a,
- 0xcb, 0x21, 0x51, 0x73, 0xb9, 0xb3, 0xcd, 0x5b, 0x73, 0x51, 0x57, 0xb8,
- 0xdb, 0x72, 0xa8, 0x41, 0xcd, 0xc5, 0xef, 0xb9, 0xdb, 0xe2, 0xf7, 0xdc,
- 0x6d, 0x39, 0x24, 0xeb, 0x2b, 0xea, 0x2f, 0xd1, 0xdd, 0x96, 0xe4, 0x8a,
- 0x77, 0x5b, 0xb6, 0x4a, 0x7d, 0xf5, 0xc2, 0xaf, 0xfe, 0xbc, 0x32, 0x55,
- 0x67, 0xe7, 0x13, 0xc2, 0xce, 0xdf, 0xd5, 0xea, 0xb7, 0x9e, 0x69, 0xbb,
- 0x9e, 0x9d, 0xdf, 0x57, 0xd1, 0x53, 0xbe, 0xa3, 0xcd, 0x77, 0xbe, 0x58,
- 0x16, 0xf9, 0x7c, 0xa6, 0x89, 0x72, 0x03, 0xbf, 0x2a, 0x68, 0xf6, 0x58,
- 0x6f, 0xed, 0x99, 0x63, 0xf5, 0x5e, 0xa4, 0xee, 0xb9, 0x17, 0x69, 0xa2,
- 0x5f, 0xaf, 0xab, 0x87, 0x04, 0xe4, 0xdd, 0x7e, 0xf8, 0xc2, 0x19, 0x43,
- 0xda, 0x5e, 0xc4, 0x70, 0x98, 0xae, 0x50, 0xe4, 0x3b, 0x95, 0x6d, 0xe4,
- 0x9b, 0x71, 0xce, 0x4b, 0x54, 0x11, 0x63, 0x42, 0x8e, 0x8b, 0x7e, 0xe1,
- 0x6f, 0xd4, 0xb8, 0x23, 0xb3, 0xe3, 0xf6, 0x05, 0xe0, 0xbf, 0x21, 0x51,
- 0x6d, 0x9b, 0x95, 0x5a, 0xce, 0x58, 0xe5, 0x0e, 0xbf, 0x09, 0xfb, 0xe0,
- 0xdc, 0x07, 0xca, 0x98, 0x7c, 0x67, 0xe4, 0x62, 0x5b, 0xf5, 0x3e, 0xd0,
- 0x67, 0xa4, 0x9c, 0x3a, 0xf7, 0x81, 0x48, 0x4d, 0x40, 0x3e, 0x6e, 0xe4,
- 0x3e, 0x50, 0xd7, 0x92, 0xfb, 0x40, 0x2b, 0xf3, 0x66, 0xe9, 0x7d, 0xa0,
- 0xc6, 0xfc, 0xe1, 0xfb, 0x40, 0xff, 0xde, 0xe6, 0xdc, 0x43, 0x5d, 0x89,
- 0x3f, 0x6e, 0x9c, 0xf4, 0x11, 0xe0, 0xf9, 0x3e, 0x50, 0xe5, 0x1e, 0x90,
- 0xe7, 0x0e, 0x10, 0xdf, 0x25, 0x59, 0xee, 0x0c, 0xce, 0x7b, 0xff, 0xa4,
- 0xa7, 0x72, 0xff, 0xe4, 0x7c, 0xc9, 0xf5, 0xed, 0xee, 0xb9, 0x1c, 0xc7,
- 0x39, 0xbb, 0x44, 0x8e, 0x7a, 0xae, 0x54, 0x5b, 0xc3, 0x60, 0xbe, 0x8f,
- 0x16, 0xcf, 0x81, 0x3e, 0x6f, 0x89, 0xdc, 0x00, 0x7c, 0xde, 0xe2, 0x23,
- 0xe6, 0x1d, 0x29, 0xa0, 0x8b, 0x38, 0xcb, 0x75, 0xf8, 0xdd, 0x21, 0x64,
- 0xc1, 0x91, 0x8b, 0xdd, 0x9e, 0xf3, 0xd0, 0xaa, 0x1c, 0x38, 0x67, 0xba,
- 0x0e, 0xef, 0x6a, 0x65, 0x46, 0x9c, 0xdd, 0x0c, 0xed, 0xb5, 0x9c, 0xf3,
- 0xc6, 0xa8, 0x38, 0xb7, 0x6d, 0xaf, 0xb3, 0x5b, 0x3a, 0xe4, 0x06, 0x31,
- 0x67, 0x8c, 0xeb, 0xd5, 0x8c, 0xfb, 0x66, 0xc1, 0xe3, 0x46, 0x67, 0x71,
- 0x2b, 0xd7, 0xf1, 0xdc, 0x9a, 0x0a, 0x21, 0x97, 0xd8, 0x9d, 0xce, 0x09,
- 0xbb, 0xe9, 0xac, 0xdd, 0x29, 0xd6, 0xde, 0x58, 0x77, 0x96, 0xcd, 0x72,
- 0xb5, 0x5c, 0x4c, 0x70, 0x3d, 0x9a, 0xde, 0xb3, 0x84, 0xa6, 0xb5, 0xba,
- 0x84, 0xdc, 0xb5, 0x62, 0xe3, 0x3b, 0x2a, 0xba, 0x34, 0x2e, 0xee, 0x21,
- 0xbb, 0xe7, 0xb5, 0x0e, 0xfd, 0xaa, 0xba, 0xb7, 0x5c, 0x3c, 0x53, 0x4f,
- 0xbf, 0x4d, 0xff, 0x4b, 0xe8, 0x77, 0x15, 0xf4, 0xe3, 0x77, 0x03, 0xef,
- 0xef, 0x8a, 0x7a, 0xc0, 0xb9, 0x52, 0xe4, 0x78, 0x9e, 0x38, 0x4e, 0x88,
- 0xcc, 0x2e, 0x50, 0x0f, 0xe8, 0xc8, 0xff, 0xeb, 0xe2, 0xde, 0x9d, 0x60,
- 0xfa, 0xb2, 0x7d, 0x8f, 0xbc, 0x70, 0x99, 0xd8, 0xc6, 0xdf, 0x8d, 0x7d,
- 0x94, 0xcb, 0x2f, 0xc5, 0x5c, 0xfa, 0xb3, 0xee, 0x73, 0x9d, 0xaa, 0x76,
- 0x5f, 0x7b, 0x57, 0xed, 0x53, 0x1d, 0xf9, 0xcc, 0x34, 0x90, 0xcf, 0x8c,
- 0xdc, 0xa3, 0x6f, 0xa6, 0x71, 0xbc, 0x9a, 0x9a, 0xfc, 0xef, 0x5e, 0xae,
- 0x26, 0xb6, 0x8d, 0x22, 0x0a, 0xbf, 0xac, 0xd7, 0x4e, 0xe3, 0xa4, 0x61,
- 0x93, 0x3a, 0xad, 0x69, 0xd2, 0x60, 0xc7, 0x4b, 0x12, 0x29, 0xa5, 0xa4,
- 0x52, 0x55, 0x45, 0x60, 0xa9, 0x21, 0x4e, 0xda, 0x0a, 0x71, 0x70, 0x0b,
- 0x48, 0x51, 0xc5, 0x21, 0x4d, 0xd3, 0x7b, 0x85, 0x84, 0x54, 0xa1, 0x8a,
- 0x46, 0x4e, 0x02, 0x15, 0x4a, 0xe5, 0x0a, 0x96, 0x72, 0x41, 0xa2, 0xd8,
- 0x8e, 0x02, 0x52, 0x2a, 0xf7, 0xca, 0x85, 0xba, 0xbf, 0x08, 0x89, 0x03,
- 0x70, 0x06, 0x29, 0x2a, 0x3f, 0xe2, 0xc0, 0x8d, 0x1b, 0x54, 0x5d, 0xde,
- 0x37, 0xb3, 0x63, 0xaf, 0x77, 0xd7, 0x8e, 0x03, 0x11, 0x07, 0x27, 0xbb,
- 0xf6, 0xcc, 0xce, 0xec, 0xcc, 0x37, 0x6f, 0xbe, 0xf7, 0x37, 0xfd, 0xbe,
- 0x78, 0x8d, 0x5a, 0xdb, 0x5b, 0xf3, 0x55, 0xec, 0xe7, 0xaf, 0x37, 0x18,
- 0x57, 0xed, 0xba, 0xe4, 0xa9, 0xf5, 0xe3, 0x9a, 0x72, 0xd9, 0x1b, 0xf0,
- 0xfe, 0xc7, 0x68, 0x51, 0xd8, 0x86, 0x94, 0xad, 0xee, 0xc5, 0x40, 0x9b,
- 0xd9, 0xff, 0x33, 0x16, 0x03, 0x3e, 0x9b, 0x68, 0xad, 0x6d, 0x8a, 0xed,
- 0x71, 0xd9, 0x16, 0xde, 0xda, 0xc2, 0xb6, 0x10, 0x3c, 0x16, 0xfd, 0x9e,
- 0xb1, 0xa8, 0xc9, 0xea, 0xa1, 0x16, 0xed, 0x74, 0x88, 0x21, 0xbf, 0x9d,
- 0x67, 0x6c, 0x05, 0xca, 0xce, 0x4f, 0x5d, 0x36, 0x3c, 0xe0, 0x73, 0xdc,
- 0x59, 0xeb, 0xc0, 0x27, 0xb5, 0x9d, 0x1a, 0x51, 0xed, 0x01, 0x8f, 0xc9,
- 0xc5, 0x45, 0x82, 0xbe, 0x86, 0x36, 0xe3, 0x82, 0xe3, 0xfa, 0x39, 0x14,
- 0x8f, 0xf1, 0xfa, 0x1b, 0x88, 0xe5, 0x70, 0xda, 0x3f, 0xd9, 0x76, 0xae,
- 0x9c, 0xe5, 0xbd, 0x42, 0xd4, 0x63, 0xbd, 0xef, 0x52, 0xdb, 0x82, 0xa8,
- 0x27, 0xe3, 0x20, 0x1c, 0x1d, 0xd0, 0xe1, 0xe2, 0x8d, 0x74, 0x3f, 0xff,
- 0x9e, 0x13, 0xcc, 0xdd, 0x7f, 0xdd, 0x1d, 0x36, 0x3f, 0x34, 0x64, 0xae,
- 0xde, 0x56, 0xdc, 0x5d, 0xd9, 0x89, 0x06, 0x85, 0xaf, 0xc1, 0xad, 0x7b,
- 0x41, 0x76, 0x5d, 0xe0, 0x3d, 0x7c, 0xa8, 0xba, 0x7f, 0xef, 0x84, 0x7d,
- 0xe8, 0x99, 0x16, 0x62, 0x1d, 0x44, 0x8e, 0xe5, 0x2b, 0x53, 0xc8, 0x45,
- 0xaa, 0xe6, 0xef, 0x78, 0xf3, 0x3c, 0x20, 0x3f, 0x55, 0x9e, 0x87, 0xca,
- 0x23, 0xc5, 0x7b, 0x24, 0x02, 0xf2, 0x3c, 0xdc, 0x32, 0x18, 0xf5, 0xea,
- 0xdf, 0xc3, 0x2d, 0x7f, 0x57, 0x1c, 0xf9, 0x5b, 0xf0, 0xd8, 0xe3, 0x97,
- 0xf3, 0x6a, 0x2d, 0x20, 0xe7, 0x43, 0xf1, 0x94, 0xde, 0x00, 0x9e, 0x12,
- 0x9c, 0xeb, 0xa1, 0xa5, 0x2f, 0xf2, 0x5e, 0x7e, 0x08, 0x7b, 0xb9, 0x51,
- 0x8b, 0xe9, 0x95, 0x72, 0xf0, 0xdc, 0x3a, 0x64, 0xa2, 0xca, 0xb9, 0x81,
- 0x5c, 0x44, 0x2c, 0x3c, 0xe6, 0xba, 0xe4, 0x60, 0x11, 0xbf, 0xa9, 0x58,
- 0x52, 0xa5, 0x47, 0xbd, 0x23, 0xf2, 0x0c, 0xbe, 0x1b, 0x3f, 0xcc, 0x1c,
- 0x18, 0xf2, 0x13, 0x76, 0xa6, 0x43, 0x0e, 0x1f, 0xbe, 0xcc, 0xbf, 0x8d,
- 0x39, 0xd7, 0x92, 0x8b, 0xca, 0x6b, 0xa5, 0x4b, 0xfd, 0xd0, 0x41, 0xe6,
- 0x6f, 0x0e, 0x2f, 0xad, 0xb3, 0x41, 0xc4, 0x53, 0xda, 0xdb, 0x74, 0xa1,
- 0xd8, 0x0c, 0x83, 0xf5, 0xf8, 0x4b, 0x79, 0x38, 0x4f, 0x42, 0x70, 0x9e,
- 0x9f, 0x3a, 0xc2, 0xe6, 0x44, 0x4f, 0xb3, 0x38, 0x9c, 0x53, 0x55, 0xfc,
- 0xa9, 0x72, 0xaa, 0x6f, 0x8f, 0x3a, 0x10, 0xa7, 0xe6, 0xc7, 0x04, 0xe6,
- 0x1f, 0xfa, 0x9c, 0x5a, 0x87, 0xd0, 0xeb, 0x10, 0xf3, 0x87, 0x76, 0x8d,
- 0x06, 0x6b, 0xb0, 0x66, 0x13, 0x2f, 0x50, 0x2b, 0xb1, 0x7f, 0xc9, 0xd1,
- 0x0a, 0x9d, 0xed, 0x69, 0xa6, 0xf3, 0x9e, 0x08, 0xd4, 0x79, 0x83, 0x72,
- 0xa4, 0xcc, 0x80, 0x1c, 0x29, 0x37, 0x0e, 0x75, 0x17, 0x0e, 0xe3, 0x2e,
- 0x2e, 0x30, 0xc0, 0xdc, 0xb9, 0x8b, 0xf1, 0x04, 0xee, 0x1c, 0xa5, 0xd0,
- 0x07, 0x6e, 0xee, 0xec, 0xf7, 0x13, 0x49, 0x5c, 0xfe, 0xdb, 0xdc, 0xa9,
- 0xa0, 0x7e, 0x27, 0x7c, 0xfd, 0x86, 0x1c, 0x9f, 0x6c, 0xc8, 0x13, 0x82,
- 0x38, 0xfe, 0x4e, 0xf7, 0xd3, 0xbb, 0xf6, 0xd1, 0xa6, 0x09, 0xfd, 0x70,
- 0x74, 0xb1, 0xba, 0xee, 0x5f, 0xf0, 0xd9, 0xb9, 0xc1, 0x67, 0x43, 0xc2,
- 0x27, 0xd7, 0x25, 0xf6, 0x90, 0x9d, 0x93, 0x61, 0x9d, 0x1e, 0x19, 0x66,
- 0xf7, 0xd4, 0xec, 0xfc, 0x88, 0x21, 0xec, 0x73, 0x74, 0x0e, 0xb9, 0xef,
- 0x14, 0x1a, 0xc6, 0xa5, 0xe2, 0x3b, 0xe9, 0x1b, 0x38, 0x77, 0x04, 0xb2,
- 0x1b, 0xf2, 0xfc, 0xf4, 0x6c, 0xd8, 0x34, 0x1c, 0x1f, 0x03, 0xfc, 0x08,
- 0xc0, 0xa9, 0x7a, 0x7e, 0x90, 0x0d, 0x3d, 0x68, 0x0e, 0x87, 0x7c, 0x73,
- 0x28, 0xf1, 0x06, 0x6e, 0x8f, 0x58, 0xbc, 0x83, 0x9e, 0x38, 0xc5, 0x9d,
- 0x18, 0x93, 0xee, 0x80, 0x78, 0x41, 0xc4, 0xfa, 0xf9, 0xfa, 0xcb, 0xef,
- 0x7c, 0x51, 0xf3, 0xaf, 0xad, 0x49, 0x6d, 0xba, 0x3c, 0xad, 0x4d, 0x15,
- 0x51, 0xee, 0xa2, 0x56, 0xdb, 0x97, 0x36, 0x5d, 0x1c, 0x11, 0x7c, 0x30,
- 0x79, 0xad, 0x42, 0x78, 0x4f, 0xdb, 0xbe, 0x25, 0xb8, 0xed, 0x80, 0x0f,
- 0xab, 0x8a, 0x73, 0x18, 0x2d, 0xbc, 0x97, 0xb4, 0xbd, 0xb8, 0xb9, 0x8e,
- 0x5b, 0xbe, 0x3f, 0x1d, 0x20, 0xdf, 0x9b, 0xd9, 0x0a, 0x91, 0xbf, 0x29,
- 0xe2, 0xb2, 0xa9, 0x68, 0x21, 0xde, 0xf1, 0x30, 0xe2, 0x7b, 0xe1, 0xd7,
- 0xa8, 0x62, 0xe1, 0x6e, 0x30, 0x16, 0xaa, 0xf6, 0x60, 0x1d, 0xb9, 0xa3,
- 0x2c, 0x8b, 0xc3, 0xe9, 0x5e, 0x0a, 0x99, 0x28, 0xff, 0x6c, 0xe2, 0x3e,
- 0x1d, 0x73, 0x78, 0x09, 0xfc, 0x3c, 0xb2, 0xde, 0x4c, 0x0b, 0x76, 0xe1,
- 0x60, 0x7f, 0x46, 0x84, 0x65, 0xf3, 0x67, 0xbd, 0xad, 0xf9, 0x33, 0x54,
- 0x39, 0xd4, 0xed, 0xa2, 0x35, 0x0b, 0x71, 0x92, 0xf0, 0x2f, 0x75, 0x77,
- 0xb4, 0x9b, 0x41, 0xf2, 0x4f, 0xc5, 0x7e, 0x82, 0x1f, 0xc9, 0xb9, 0xba,
- 0x41, 0x98, 0x3b, 0x9b, 0xbe, 0x6f, 0x30, 0x57, 0xdb, 0xb1, 0x29, 0x37,
- 0x9f, 0x2b, 0xc3, 0x33, 0x57, 0xd8, 0x8b, 0x9a, 0xcd, 0x95, 0xf2, 0x43,
- 0x2a, 0xdf, 0xdc, 0x51, 0xc8, 0x93, 0x45, 0xf7, 0x5c, 0xed, 0x8c, 0x7f,
- 0x4e, 0xce, 0xd9, 0x4e, 0xfb, 0xe0, 0x1a, 0x8f, 0x43, 0x34, 0xd0, 0x76,
- 0x12, 0x2c, 0x33, 0xfc, 0x6b, 0xeb, 0x86, 0x5c, 0x5b, 0xcc, 0x2b, 0x9e,
- 0x6f, 0xb8, 0xb6, 0xb0, 0x0f, 0x5c, 0x70, 0xf6, 0x81, 0xd3, 0x3e, 0x7d,
- 0x51, 0xd9, 0xbc, 0xff, 0xab, 0xed, 0x0d, 0xcf, 0x7d, 0x22, 0xce, 0xe9,
- 0xc8, 0x91, 0xdc, 0x47, 0xce, 0x37, 0xe4, 0x61, 0x3d, 0xdb, 0x5c, 0xa7,
- 0x6a, 0xee, 0x91, 0x73, 0x01, 0x79, 0x99, 0xa5, 0xf3, 0xf9, 0xc7, 0x06,
- 0x75, 0xf7, 0x53, 0xa4, 0x1a, 0xd3, 0x72, 0x40, 0xf0, 0x61, 0xb7, 0xbe,
- 0xbc, 0xec, 0xe4, 0x28, 0xe6, 0x5c, 0x63, 0xb0, 0x9c, 0xcf, 0x36, 0x89,
- 0xa7, 0x6f, 0x25, 0x9e, 0x63, 0xc0, 0x23, 0x37, 0xbd, 0x73, 0x35, 0xa1,
- 0x65, 0xf2, 0xa8, 0xb3, 0x87, 0xce, 0xea, 0x9f, 0xf0, 0x18, 0x3d, 0xb1,
- 0x23, 0xe2, 0x9c, 0x11, 0xe0, 0xd2, 0xb6, 0x97, 0xcd, 0x0e, 0x5a, 0x94,
- 0x7e, 0x46, 0x9a, 0xfa, 0xf8, 0x12, 0x15, 0x85, 0x7f, 0x0b, 0xb9, 0x51,
- 0xb0, 0x71, 0xc3, 0x47, 0x87, 0xe7, 0xf0, 0xf7, 0x1b, 0x13, 0x8e, 0xcc,
- 0xfd, 0x93, 0x31, 0x8c, 0x7a, 0x38, 0x0b, 0x01, 0xeb, 0x9d, 0x34, 0xc9,
- 0x31, 0xb9, 0x1d, 0x71, 0x4e, 0x80, 0x8c, 0xcd, 0xbb, 0x5d, 0xde, 0x8e,
- 0x4f, 0xa1, 0x55, 0xbd, 0xe4, 0xeb, 0x68, 0xd8, 0xfc, 0x72, 0xcf, 0xf6,
- 0x7d, 0x0a, 0x2a, 0x77, 0x5f, 0x71, 0x58, 0x75, 0x2d, 0x73, 0x69, 0xc1,
- 0x99, 0xe7, 0xd7, 0x55, 0xde, 0x6d, 0x77, 0x40, 0xde, 0x6d, 0x88, 0xe6,
- 0x84, 0xaf, 0x2e, 0x44, 0x39, 0x47, 0x37, 0x93, 0x9c, 0x5a, 0xd9, 0x6a,
- 0x23, 0x4e, 0xfc, 0x29, 0xee, 0xdd, 0x39, 0xf9, 0x7c, 0x5f, 0x04, 0xcf,
- 0x46, 0x4e, 0xb5, 0x2d, 0x62, 0xf1, 0x33, 0xa2, 0x5c, 0xa7, 0xa7, 0x1c,
- 0xdf, 0x17, 0xd5, 0x33, 0x3b, 0xb9, 0x7c, 0x8a, 0x64, 0x0e, 0x7d, 0x27,
- 0xcd, 0x15, 0x9b, 0xf5, 0x6b, 0x1f, 0xe2, 0x81, 0xe3, 0xf0, 0x95, 0x0a,
- 0xbf, 0x95, 0xa1, 0xfa, 0x80, 0x3e, 0xb5, 0x57, 0xfb, 0x04, 0xf9, 0x14,
- 0x12, 0x7e, 0x05, 0xbe, 0x76, 0xda, 0x99, 0x23, 0x77, 0xbf, 0xc2, 0xdc,
- 0x2f, 0x3c, 0xa7, 0xd3, 0x55, 0xb6, 0xd3, 0x55, 0xb6, 0x36, 0x5e, 0x3a,
- 0xeb, 0x54, 0x0b, 0xe5, 0x1f, 0x59, 0x2f, 0xfd, 0x56, 0xd8, 0xe6, 0xe6,
- 0xb3, 0x06, 0x2d, 0xac, 0xf7, 0xf2, 0x27, 0xc6, 0x1f, 0x94, 0xdb, 0xcb,
- 0xff, 0xdd, 0x9c, 0xa2, 0x5f, 0xc4, 0x02, 0xb6, 0xce, 0x07, 0x83, 0xf1,
- 0x1f, 0xbc, 0x6e, 0x13, 0x01, 0xeb, 0xb6, 0xf9, 0xbe, 0x22, 0xf7, 0x93,
- 0xe4, 0x95, 0x8a, 0x23, 0xaf, 0x36, 0x69, 0xd0, 0x27, 0xa7, 0x82, 0xd6,
- 0x29, 0xfa, 0x78, 0xca, 0xe9, 0xe3, 0x9b, 0xa2, 0x3f, 0xe3, 0x54, 0xa8,
- 0xe6, 0x0d, 0x1f, 0xe1, 0xeb, 0x98, 0xb2, 0xd1, 0x35, 0x90, 0xab, 0xdf,
- 0x6c, 0x43, 0xc6, 0x04, 0x71, 0xb2, 0x03, 0x01, 0xfa, 0x80, 0xee, 0xd2,
- 0x07, 0xe2, 0x55, 0x7d, 0x60, 0x45, 0xe8, 0x09, 0xbb, 0x1c, 0x1d, 0x34,
- 0xd8, 0x16, 0x97, 0xcb, 0xe3, 0xcc, 0x1b, 0xd8, 0xf8, 0xa4, 0x1d, 0x7d,
- 0xda, 0xaa, 0x9e, 0x99, 0xc3, 0xba, 0x65, 0x8d, 0x4b, 0xfb, 0xe5, 0x09,
- 0xce, 0xac, 0xa8, 0xcc, 0x3e, 0x30, 0xa3, 0xa4, 0xa5, 0x93, 0xf1, 0xa9,
- 0x50, 0x84, 0x16, 0xac, 0x28, 0x15, 0xac, 0x14, 0x73, 0x70, 0xf0, 0xe3,
- 0xd0, 0x80, 0x46, 0x11, 0x96, 0x35, 0x11, 0x2a, 0x95, 0x94, 0x4e, 0x76,
- 0x86, 0xc8, 0x2c, 0xc6, 0xa4, 0x0d, 0x9b, 0x71, 0x9a, 0x1f, 0x33, 0xe6,
- 0x49, 0x43, 0xcc, 0x8b, 0x93, 0xa3, 0x0e, 0x0c, 0x8a, 0x38, 0x4b, 0xfd,
- 0xe5, 0x91, 0x28, 0xb5, 0xa7, 0xa5, 0xcd, 0x68, 0x86, 0xdb, 0xf8, 0xc2,
- 0x8a, 0xd1, 0x95, 0x7c, 0xd2, 0x38, 0xc1, 0xed, 0x64, 0xac, 0x64, 0x62,
- 0x92, 0x9f, 0x5d, 0x2c, 0x45, 0x28, 0x67, 0x45, 0xa8, 0x50, 0x4a, 0x19,
- 0x43, 0x6d, 0xa2, 0xcd, 0x18, 0xda, 0x7c, 0x49, 0x1f, 0x33, 0x4e, 0x92,
- 0xbb, 0xcd, 0xaf, 0x9c, 0x36, 0xbd, 0x6d, 0xfd, 0x61, 0xe3, 0xfe, 0x44,
- 0xa8, 0x32, 0x7b, 0x9f, 0xf1, 0x92, 0x5b, 0x9d, 0x60, 0xd9, 0x14, 0x13,
- 0x67, 0xdb, 0x68, 0xe9, 0x34, 0xcb, 0x1d, 0x9c, 0x6d, 0x61, 0xd0, 0x62,
- 0x39, 0x4e, 0xef, 0x57, 0xed, 0x07, 0x12, 0x43, 0x39, 0x91, 0x43, 0x84,
- 0x33, 0x17, 0x2a, 0xb3, 0xbf, 0x9b, 0x5e, 0x7f, 0x3f, 0xeb, 0x5b, 0x1f,
- 0xc5, 0x28, 0x72, 0x15, 0x71, 0xdd, 0x36, 0x5d, 0x1b, 0x4f, 0x5e, 0xd9,
- 0x14, 0x79, 0x68, 0x09, 0x5a, 0x33, 0xa5, 0x3c, 0xcd, 0x71, 0xf9, 0x15,
- 0x94, 0x5b, 0x4b, 0xd0, 0x3d, 0x91, 0x8f, 0xd6, 0x4e, 0x77, 0xf4, 0x18,
- 0x85, 0x6e, 0x9a, 0xc6, 0xbc, 0xf0, 0x0b, 0x57, 0x66, 0x87, 0x86, 0x0d,
- 0xd2, 0xae, 0xa2, 0x1e, 0xff, 0xbf, 0x89, 0xfb, 0x28, 0x61, 0x7e, 0x66,
- 0xac, 0x31, 0x5e, 0x49, 0xc3, 0xf1, 0x12, 0x64, 0xf3, 0x41, 0x89, 0xa5,
- 0x39, 0x23, 0x42, 0xd0, 0x5f, 0x61, 0x7b, 0xeb, 0x35, 0x27, 0x7b, 0xa4,
- 0xfe, 0xe4, 0x3b, 0x9b, 0x43, 0x9f, 0x19, 0x71, 0x9f, 0xcf, 0x51, 0x7b,
- 0x66, 0xc6, 0x92, 0xef, 0xb9, 0x52, 0xee, 0xa5, 0x25, 0x6e, 0x7b, 0x64,
- 0xf8, 0x8c, 0x73, 0xa6, 0x0f, 0xff, 0xd9, 0x8b, 0x7b, 0x85, 0xb7, 0x7d,
- 0x7d, 0x14, 0xc5, 0x3d, 0x0d, 0xe8, 0x3c, 0xc7, 0xb0, 0xe9, 0x87, 0xc5,
- 0xb8, 0xa7, 0xe2, 0x98, 0xcb, 0xb9, 0xb8, 0x3a, 0x97, 0x08, 0x65, 0xba,
- 0xe9, 0x91, 0xd5, 0x45, 0x3f, 0x8b, 0xf3, 0x47, 0xf8, 0xba, 0x84, 0x9c,
- 0xa3, 0x36, 0xca, 0x64, 0xbb, 0x69, 0xb3, 0x14, 0x66, 0x71, 0x05, 0xec,
- 0x44, 0xb9, 0x4c, 0x81, 0xa6, 0xd6, 0x5f, 0xeb, 0x83, 0x1f, 0x66, 0x52,
- 0xab, 0x61, 0xe9, 0x51, 0x00, 0x96, 0x7e, 0xa9, 0xc3, 0xd2, 0xd1, 0xbe,
- 0xe6, 0x58, 0xea, 0x77, 0x62, 0xd6, 0xa3, 0x14, 0x71, 0x70, 0xf4, 0x39,
- 0xe3, 0xe8, 0x3d, 0xc6, 0xd1, 0xf1, 0x06, 0x38, 0xd2, 0x3c, 0x38, 0x3a,
- 0x51, 0x87, 0xa3, 0x6c, 0x5f, 0x33, 0x1c, 0x1d, 0x0f, 0xa1, 0xff, 0xcd,
- 0xd6, 0x32, 0xfa, 0xb0, 0x9f, 0x39, 0xbd, 0x49, 0xa5, 0xd5, 0xe4, 0xf8,
- 0x24, 0x55, 0x90, 0x73, 0x92, 0x58, 0xa2, 0xb4, 0xe0, 0x76, 0x05, 0x81,
- 0xbf, 0x2c, 0x8f, 0xc9, 0xae, 0x06, 0xe7, 0xaa, 0x24, 0x9c, 0x79, 0x93,
- 0x73, 0x99, 0xc9, 0x57, 0x66, 0x1f, 0x32, 0x36, 0xee, 0x6d, 0xe8, 0x3a,
- 0x7e, 0x0b, 0xb1, 0x8c, 0xbc, 0xbb, 0x81, 0x73, 0x5b, 0xe2, 0x74, 0xdf,
- 0x1a, 0xa0, 0x7b, 0xd6, 0x7e, 0xba, 0x6b, 0x0d, 0xd2, 0x03, 0x0b, 0x6d,
- 0x60, 0x0e, 0xf8, 0x5e, 0xcc, 0x81, 0x46, 0x33, 0x31, 0x2e, 0x53, 0xda,
- 0x4f, 0x95, 0x92, 0xc2, 0x35, 0xb0, 0x03, 0x0c, 0x35, 0xc6, 0x4e, 0xa6,
- 0x0e, 0x3b, 0xb2, 0x0e, 0x30, 0xb3, 0xe4, 0xb7, 0xad, 0xed, 0x32, 0xf8,
- 0x5d, 0x0d, 0xc6, 0x56, 0x58, 0xc4, 0x91, 0x24, 0x47, 0x67, 0x42, 0x90,
- 0x59, 0xb7, 0x18, 0x53, 0x3c, 0x17, 0x3c, 0x7e, 0xda, 0xf5, 0x41, 0x96,
- 0x39, 0x4f, 0x09, 0x1b, 0xf4, 0x94, 0xa9, 0xc7, 0x33, 0x64, 0x5f, 0xd6,
- 0xcc, 0x31, 0x91, 0xeb, 0xb6, 0x54, 0xf6, 0x9e, 0x31, 0x91, 0xe1, 0xb1,
- 0x57, 0x78, 0xf4, 0xca, 0xa1, 0x76, 0xaa, 0x38, 0x31, 0x4c, 0x85, 0x55,
- 0xdb, 0x7e, 0xc8, 0xfc, 0x7f, 0xcd, 0x84, 0xcc, 0xfe, 0xdb, 0xae, 0xc4,
- 0x74, 0x5a, 0x36, 0x55, 0xdf, 0xee, 0x08, 0x7c, 0x31, 0x47, 0xa4, 0x77,
- 0x37, 0xaa, 0xaf, 0xc4, 0xbf, 0xe3, 0xbb, 0xbf, 0x04, 0x97, 0x59, 0xab,
- 0x96, 0x85, 0xed, 0xf8, 0xd2, 0xd8, 0xc2, 0x2a, 0xce, 0x7e, 0x7b, 0xfc,
- 0xea, 0xf9, 0xd5, 0x5c, 0x1f, 0x4b, 0xd8, 0x94, 0x4e, 0x76, 0x68, 0x79,
- 0x3c, 0xf7, 0x5c, 0x98, 0x86, 0x19, 0x97, 0x38, 0x83, 0x6b, 0x6c, 0x34,
- 0x2c, 0xce, 0x38, 0xd9, 0xcd, 0x78, 0xc8, 0x0a, 0x3b, 0xfd, 0xd4, 0x91,
- 0x09, 0x9a, 0x2c, 0xa7, 0xf9, 0x53, 0x3f, 0x7e, 0xb5, 0xb9, 0xe3, 0xe1,
- 0x48, 0xe3, 0x37, 0x37, 0xff, 0xa8, 0xd5, 0x9d, 0xe6, 0xba, 0x33, 0x5b,
- 0xd6, 0x55, 0xe7, 0x12, 0xfd, 0x03, 0x69, 0xae, 0x1b, 0xa3, 0xbc, 0x57,
- 0x00, 0x00, 0x00 };
+ 0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a,
+ 0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15,
+ 0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96,
+ 0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1,
+ 0x65, 0x6b, 0x4a, 0xa2, 0x6d, 0x05, 0x11, 0x02, 0x62, 0x49, 0xa9, 0x46,
+ 0x50, 0xb7, 0x92, 0xab, 0xb6, 0x81, 0x6b, 0x4b, 0x6b, 0x92, 0x6a, 0x09,
+ 0x84, 0xe6, 0x08, 0x11, 0x43, 0x19, 0xa9, 0x11, 0x10, 0xa4, 0x1c, 0xbb,
+ 0xc0, 0xb6, 0x2b, 0xbf, 0x05, 0x34, 0x2e, 0x15, 0x4a, 0x6e, 0xd4, 0x34,
+ 0x30, 0xfc, 0xa7, 0xa8, 0x51, 0x38, 0xad, 0xe1, 0x04, 0xa8, 0x9b, 0x16,
+ 0x45, 0xd0, 0xfc, 0x88, 0x0a, 0xdb, 0xd9, 0x7e, 0xdf, 0x9d, 0x3b, 0xcb,
+ 0xe1, 0x92, 0xd4, 0xc3, 0x8f, 0xfe, 0x28, 0x81, 0xe5, 0xcc, 0xbd, 0x73,
+ 0xe7, 0xde, 0x73, 0xcf, 0xe3, 0x3b, 0x8f, 0xb9, 0x77, 0x8a, 0x34, 0x88,
+ 0xfe, 0x5b, 0x8f, 0x5f, 0xf2, 0xd1, 0x3f, 0x18, 0xbe, 0xab, 0xe7, 0xae,
+ 0xbb, 0x71, 0x7b, 0xb7, 0x19, 0xb1, 0x22, 0xec, 0xe7, 0x3f, 0x07, 0xbf,
+ 0x6e, 0x7d, 0xbf, 0xda, 0x9f, 0x8d, 0xdf, 0x65, 0xfc, 0x86, 0x7e, 0x2e,
+ 0x62, 0xac, 0x31, 0x26, 0xfc, 0x57, 0xa9, 0x5c, 0xfd, 0xb9, 0x49, 0x5a,
+ 0xae, 0xf2, 0x3c, 0xe2, 0x2f, 0xa9, 0x68, 0xe6, 0x4f, 0x62, 0x66, 0x46,
+ 0x8e, 0xe7, 0x5c, 0x89, 0x45, 0x32, 0x1f, 0x1c, 0x1f, 0x76, 0x45, 0xb2,
+ 0xa5, 0x6d, 0xc9, 0xbc, 0x7c, 0x5c, 0x29, 0x3a, 0x96, 0xb0, 0xff, 0xd6,
+ 0xcc, 0x47, 0x27, 0xde, 0xd8, 0x91, 0xfa, 0xc5, 0x6c, 0x44, 0x62, 0x76,
+ 0xe6, 0x15, 0xb1, 0xb7, 0x4a, 0xac, 0x15, 0xef, 0x3c, 0xdb, 0x99, 0x33,
+ 0xa4, 0x29, 0x98, 0xeb, 0x83, 0xca, 0x1b, 0x9d, 0x52, 0xdc, 0x9c, 0x89,
+ 0x89, 0x99, 0xe9, 0x78, 0x27, 0x17, 0xb1, 0x87, 0x22, 0x19, 0x5b, 0x16,
+ 0xca, 0x32, 0x30, 0x32, 0x29, 0xb1, 0x58, 0x66, 0x22, 0x56, 0xdf, 0x21,
+ 0xb1, 0x68, 0x66, 0xe8, 0xf8, 0xf7, 0xdc, 0x13, 0x15, 0xd3, 0x75, 0x93,
+ 0xa3, 0x12, 0xef, 0x1d, 0xef, 0xc1, 0xf3, 0x52, 0x0a, 0x04, 0xef, 0x10,
+ 0xd3, 0x2d, 0xc6, 0x23, 0x6e, 0x4c, 0x72, 0x65, 0x57, 0xf2, 0x65, 0x91,
+ 0x1f, 0x96, 0x0c, 0x19, 0x77, 0x5b, 0x64, 0x74, 0xfb, 0x47, 0x95, 0x2c,
+ 0x68, 0xf9, 0x3b, 0x77, 0xe8, 0xf8, 0x73, 0x2e, 0xe9, 0x9d, 0x8e, 0xf9,
+ 0xf4, 0x8e, 0xd7, 0x0f, 0xbb, 0x96, 0xcc, 0x95, 0xd8, 0x77, 0xd0, 0x64,
+ 0x9f, 0x95, 0xf9, 0x7e, 0xc3, 0xb8, 0x1b, 0xd7, 0x7d, 0x13, 0xd9, 0x1c,
+ 0xe6, 0x9b, 0x2f, 0x71, 0xec, 0xbb, 0x5f, 0x18, 0x76, 0x1d, 0xdd, 0x9f,
+ 0xdd, 0x91, 0x73, 0x13, 0xe8, 0x6f, 0xd5, 0xcf, 0x9e, 0x79, 0x74, 0xd8,
+ 0x75, 0xf5, 0x33, 0xcb, 0xca, 0xb9, 0x5d, 0xba, 0xbf, 0xb4, 0x6b, 0xd8,
+ 0xdd, 0xae, 0xfb, 0x7f, 0xbc, 0x2b, 0xe7, 0xa6, 0x75, 0x7f, 0xef, 0x57,
+ 0x86, 0xdd, 0x1e, 0xdd, 0xff, 0xf6, 0xce, 0x9c, 0xdb, 0xab, 0xfb, 0x4f,
+ 0xf5, 0x0e, 0xbb, 0xb6, 0x9c, 0x2d, 0x25, 0xf1, 0x9b, 0x88, 0x59, 0x1d,
+ 0x19, 0x3d, 0xe6, 0x59, 0xd0, 0x9b, 0xc5, 0x98, 0x3e, 0xf4, 0xef, 0xc1,
+ 0xaf, 0x1f, 0xbf, 0xf2, 0x06, 0x69, 0x1a, 0xc0, 0xf3, 0x0f, 0xb7, 0xf8,
+ 0x3c, 0x04, 0xaf, 0xbc, 0x98, 0xbc, 0x17, 0x49, 0xc8, 0x1b, 0x9d, 0xef,
+ 0x81, 0x97, 0xb6, 0x9c, 0x2b, 0x8b, 0x31, 0xd0, 0x99, 0x00, 0x0f, 0x1d,
+ 0x79, 0xb1, 0xdc, 0x28, 0x91, 0x6f, 0x45, 0xc0, 0xa3, 0xaf, 0x4a, 0xc1,
+ 0x89, 0xc9, 0xc6, 0x19, 0x43, 0xda, 0xba, 0xd7, 0x49, 0xd6, 0x2e, 0x4a,
+ 0xbe, 0x13, 0x52, 0x9f, 0x72, 0xc4, 0x9a, 0x59, 0xdc, 0x68, 0xa2, 0xc7,
+ 0x94, 0x54, 0xa2, 0x80, 0x19, 0x47, 0xce, 0xbe, 0x4b, 0x1d, 0xa5, 0x7c,
+ 0xf1, 0x4b, 0x4a, 0x7e, 0xf2, 0x0e, 0x19, 0xb2, 0x49, 0xe7, 0x9f, 0xdd,
+ 0xea, 0xaf, 0x19, 0x33, 0x72, 0x67, 0x06, 0xe5, 0xa4, 0x17, 0x37, 0xf2,
+ 0x67, 0x76, 0x4a, 0x2e, 0x2d, 0x8e, 0x29, 0x1d, 0xea, 0xdd, 0xf9, 0xd2,
+ 0xa0, 0x8c, 0x7b, 0x62, 0xe4, 0x3c, 0x4b, 0x46, 0x4b, 0x2d, 0x78, 0xde,
+ 0xa4, 0xc6, 0xa2, 0xaf, 0x35, 0x22, 0x1d, 0x76, 0x5e, 0x62, 0xe8, 0xb7,
+ 0xd1, 0xdf, 0x6c, 0xf4, 0xa9, 0x39, 0x54, 0x7f, 0x72, 0x4c, 0xe2, 0xd8,
+ 0x9b, 0xa3, 0xc7, 0x56, 0x2a, 0xb9, 0xb4, 0x8d, 0x71, 0x83, 0x32, 0xe6,
+ 0x39, 0x32, 0x84, 0xeb, 0xa8, 0xc7, 0xf5, 0x13, 0xd0, 0xb1, 0xb7, 0x8e,
+ 0x17, 0xa6, 0xd5, 0x7c, 0xc9, 0x48, 0x86, 0xf3, 0xb5, 0x62, 0xdc, 0x05,
+ 0xd0, 0x65, 0x88, 0xa5, 0x64, 0x9b, 0x95, 0xc2, 0xa4, 0x21, 0xe4, 0x5b,
+ 0x41, 0xf1, 0xb0, 0x0f, 0xf4, 0x5b, 0xe2, 0x76, 0x1b, 0x32, 0xec, 0xde,
+ 0x2c, 0x45, 0x1b, 0xed, 0xd2, 0x79, 0x33, 0xe7, 0xd5, 0x4b, 0xde, 0x4a,
+ 0x62, 0xff, 0x94, 0xfd, 0x90, 0x8c, 0xe1, 0x1d, 0xd3, 0xe5, 0x98, 0x8f,
+ 0xb0, 0x77, 0xb4, 0xf1, 0x6e, 0x5d, 0xe6, 0xa0, 0x5c, 0x9a, 0x2c, 0x9a,
+ 0xb9, 0x72, 0x8b, 0x44, 0x66, 0x52, 0xd0, 0xfe, 0x71, 0x33, 0xff, 0xbc,
+ 0x25, 0xd1, 0x29, 0xea, 0x97, 0xd8, 0x91, 0xcc, 0x84, 0xb9, 0xbb, 0x7c,
+ 0xde, 0xcc, 0x97, 0xf9, 0x0e, 0xc6, 0x96, 0x4c, 0xf0, 0x96, 0xf7, 0xdb,
+ 0xc0, 0x4b, 0xea, 0x36, 0xdf, 0x81, 0x1c, 0xb0, 0x87, 0x17, 0x3d, 0xc8,
+ 0x45, 0xc9, 0x29, 0x09, 0x39, 0x89, 0xd1, 0xd7, 0x19, 0x93, 0xb1, 0x69,
+ 0x4b, 0x0a, 0xe9, 0x9b, 0x15, 0xe7, 0x0b, 0xe9, 0x25, 0x9a, 0x46, 0x27,
+ 0x6b, 0x69, 0xe2, 0x7b, 0xa4, 0xc9, 0xa7, 0x65, 0x6c, 0x9a, 0xb4, 0xf9,
+ 0xb4, 0x9c, 0x9c, 0x24, 0x8d, 0x5c, 0x87, 0xf4, 0x90, 0xae, 0x80, 0x26,
+ 0xbe, 0x43, 0x9a, 0x36, 0x61, 0x7e, 0x65, 0xc0, 0x46, 0x1f, 0x68, 0x18,
+ 0xf3, 0x2c, 0xc8, 0x26, 0x2e, 0x05, 0xbb, 0x68, 0x8c, 0xf5, 0x6e, 0x4b,
+ 0xc0, 0xaa, 0x8d, 0xd1, 0x5e, 0xd2, 0xeb, 0x42, 0x7e, 0x75, 0x4a, 0xce,
+ 0x66, 0x66, 0x9c, 0x3c, 0xc3, 0x78, 0xae, 0x8d, 0xfb, 0x92, 0x2d, 0xe3,
+ 0x6a, 0x3e, 0xd2, 0xf3, 0x59, 0xcc, 0x43, 0x7a, 0x2f, 0x43, 0x57, 0x7b,
+ 0xa0, 0xa3, 0x69, 0xf9, 0xdb, 0xf2, 0x76, 0x79, 0xbd, 0xdc, 0x25, 0xaf,
+ 0xc1, 0x7e, 0x5f, 0x2d, 0x27, 0xe5, 0x95, 0x72, 0xab, 0xbc, 0x5c, 0x4e,
+ 0xc8, 0x4b, 0x4a, 0x7f, 0xfb, 0x44, 0x9a, 0x94, 0x4e, 0xc7, 0x6e, 0x86,
+ 0x3e, 0xb6, 0x40, 0x1f, 0x9b, 0x61, 0x4f, 0x1b, 0x61, 0xab, 0xdf, 0x06,
+ 0x0f, 0xa7, 0x3b, 0x25, 0xbb, 0x09, 0xfd, 0xb7, 0x65, 0x2c, 0xa5, 0x23,
+ 0x16, 0x9e, 0x8f, 0x4d, 0x46, 0x25, 0x6f, 0x9f, 0x95, 0xf7, 0xa7, 0x2c,
+ 0x19, 0x2b, 0x3f, 0x79, 0x9b, 0xaf, 0xb3, 0x6c, 0xcf, 0xca, 0x45, 0xf4,
+ 0xe5, 0xed, 0x59, 0xb9, 0xb4, 0xd5, 0x94, 0xd1, 0xe9, 0xef, 0x4a, 0xee,
+ 0xf9, 0xb3, 0xf2, 0xd3, 0xbf, 0x16, 0x19, 0x00, 0xef, 0xcd, 0xee, 0xff,
+ 0xaa, 0x64, 0x6d, 0xec, 0xb1, 0x7b, 0xbb, 0x92, 0x89, 0xd9, 0x4d, 0x3d,
+ 0x4e, 0x02, 0x57, 0x2c, 0x23, 0xef, 0xbd, 0x00, 0x6c, 0x69, 0x34, 0x72,
+ 0xa7, 0x45, 0x86, 0x4f, 0x57, 0x64, 0x38, 0x1d, 0x95, 0xc7, 0xec, 0x8a,
+ 0xf4, 0xa5, 0xeb, 0xe4, 0xa8, 0x4d, 0xac, 0x39, 0x6e, 0x04, 0xb8, 0xfe,
+ 0xed, 0xf2, 0x09, 0xdc, 0xb3, 0x4f, 0x64, 0x5a, 0xdd, 0xfb, 0xfd, 0xc5,
+ 0x72, 0x54, 0xb2, 0x4e, 0x31, 0x61, 0x49, 0x9b, 0xe9, 0xd3, 0xf4, 0xcd,
+ 0xe0, 0x19, 0x78, 0x35, 0x04, 0x2c, 0xf5, 0xed, 0xaf, 0x30, 0xb9, 0xee,
+ 0x4a, 0x56, 0x75, 0x47, 0x29, 0x3b, 0xe8, 0x34, 0x79, 0x9d, 0x1c, 0x32,
+ 0x32, 0x8e, 0xb4, 0x29, 0xbc, 0xe8, 0xc1, 0x98, 0x5e, 0x63, 0x7f, 0x99,
+ 0x7a, 0x8e, 0xfb, 0x12, 0x69, 0xdd, 0x8c, 0xb1, 0x16, 0xae, 0x59, 0x4d,
+ 0x73, 0x98, 0x4e, 0xce, 0x45, 0x3a, 0x79, 0x7d, 0x21, 0x44, 0xe7, 0x5f,
+ 0x56, 0xef, 0xa7, 0x43, 0xf7, 0xc5, 0xf2, 0x0f, 0x1a, 0x7c, 0xfa, 0xc8,
+ 0xcf, 0x5e, 0xe8, 0xe3, 0x37, 0xf4, 0x5a, 0xb8, 0x2f, 0x71, 0x8d, 0xb3,
+ 0x15, 0x5f, 0xa7, 0x8a, 0xd7, 0x58, 0xeb, 0x62, 0x68, 0xad, 0x4b, 0xa1,
+ 0xb5, 0x2e, 0x85, 0xd6, 0x2a, 0x82, 0xb7, 0xb2, 0xc1, 0x74, 0xa3, 0xc0,
+ 0x27, 0xf6, 0x4c, 0x60, 0xce, 0x67, 0x21, 0x97, 0x9f, 0x60, 0x4c, 0x46,
+ 0x16, 0x3d, 0xf0, 0xe3, 0x74, 0x54, 0xf6, 0xa9, 0x67, 0xbd, 0x9a, 0xae,
+ 0xf0, 0xb3, 0x98, 0xec, 0x75, 0x78, 0x1f, 0x3c, 0xb3, 0xc0, 0x63, 0xb6,
+ 0xff, 0xe1, 0x16, 0xbf, 0xcd, 0xfb, 0xf3, 0x9a, 0xfe, 0x87, 0xfc, 0xf7,
+ 0xca, 0x1f, 0x28, 0x9c, 0x5c, 0x28, 0x13, 0xc7, 0x24, 0x1d, 0x71, 0xe5,
+ 0x48, 0x5f, 0x1a, 0x76, 0x65, 0x1b, 0xe9, 0xd1, 0xae, 0x7a, 0xf2, 0x3c,
+ 0x6b, 0xba, 0x8d, 0xc0, 0x0a, 0x49, 0x9a, 0xd0, 0xb3, 0x51, 0xb5, 0x97,
+ 0x75, 0xa6, 0x4f, 0xb3, 0xcd, 0xf6, 0x80, 0xe9, 0x36, 0xd7, 0xf4, 0xd3,
+ 0xde, 0x1b, 0x71, 0x4f, 0xdd, 0x7e, 0x4c, 0xcb, 0x37, 0x8e, 0x36, 0xf1,
+ 0xb9, 0x5f, 0xb7, 0x83, 0xe7, 0x39, 0x6b, 0x79, 0xfb, 0xed, 0x2d, 0xcb,
+ 0xdb, 0x01, 0x76, 0x84, 0xb1, 0x9d, 0x7b, 0x4d, 0x4a, 0xc4, 0xa5, 0xce,
+ 0x45, 0x41, 0x6b, 0x1a, 0xb6, 0x58, 0xaf, 0x69, 0xb8, 0x5d, 0xd3, 0x00,
+ 0x5a, 0x31, 0x6e, 0x54, 0xd9, 0x98, 0x12, 0x5f, 0x4d, 0x9b, 0xfc, 0x0e,
+ 0xee, 0xd7, 0xab, 0xe7, 0xbe, 0x2d, 0x06, 0x57, 0x31, 0x76, 0x77, 0x52,
+ 0xe6, 0x13, 0x90, 0x79, 0x5c, 0xe6, 0xa7, 0xc9, 0xb3, 0x54, 0xe2, 0x71,
+ 0x41, 0xbb, 0x94, 0x90, 0xb3, 0x93, 0x92, 0x3d, 0x7c, 0xaa, 0x57, 0xfa,
+ 0x60, 0x9f, 0x73, 0x93, 0x57, 0x2a, 0xe0, 0xdb, 0xbd, 0x75, 0xe2, 0x02,
+ 0x83, 0xe1, 0xef, 0x7b, 0xa2, 0x12, 0xc9, 0x64, 0xa0, 0x0b, 0x69, 0xe5,
+ 0x83, 0x97, 0xfe, 0x2c, 0xeb, 0xfe, 0x65, 0xed, 0x3a, 0xf8, 0x79, 0xcc,
+ 0xdb, 0x93, 0x56, 0x7a, 0x13, 0xfe, 0xcb, 0x01, 0x57, 0x72, 0xe9, 0x8f,
+ 0xa1, 0x5b, 0x01, 0x4d, 0x81, 0x6d, 0xd0, 0x07, 0x7d, 0x10, 0xf2, 0x6d,
+ 0xad, 0xc0, 0x17, 0x07, 0xf2, 0x0b, 0xfc, 0x11, 0xfd, 0x44, 0x82, 0x58,
+ 0x0e, 0x5b, 0xa0, 0x6f, 0x88, 0x8b, 0x39, 0x63, 0x69, 0xff, 0x11, 0xd3,
+ 0xfe, 0x23, 0x0e, 0xdf, 0xc1, 0xb6, 0xad, 0xdb, 0x8e, 0x6e, 0x27, 0xd0,
+ 0x46, 0xec, 0x31, 0x43, 0xbb, 0x7a, 0xeb, 0xf8, 0xc8, 0xb4, 0xf2, 0x49,
+ 0xf4, 0x67, 0xf0, 0x14, 0xf4, 0x29, 0xf4, 0x2d, 0xd8, 0x6f, 0x09, 0xeb,
+ 0x55, 0x31, 0x9c, 0xf2, 0x08, 0xd3, 0x43, 0x5a, 0xd6, 0x89, 0x09, 0x3f,
+ 0x9b, 0x75, 0x48, 0xef, 0x77, 0x20, 0x0f, 0x62, 0x25, 0xe9, 0xbe, 0x15,
+ 0xb4, 0x72, 0x3f, 0xff, 0x97, 0xb4, 0x72, 0xbd, 0x5a, 0x7a, 0x3f, 0x2d,
+ 0x66, 0x2b, 0xec, 0xc0, 0x9e, 0x33, 0xc0, 0x66, 0x31, 0xf6, 0x77, 0x0e,
+ 0x62, 0xcf, 0x03, 0xc0, 0xee, 0x7e, 0x60, 0xf7, 0x1e, 0x60, 0x77, 0x1f,
+ 0xb0, 0x3b, 0x0b, 0xec, 0xee, 0x05, 0x6e, 0xf7, 0x00, 0xb7, 0xd3, 0xe0,
+ 0x8d, 0x23, 0xb3, 0xc0, 0xf1, 0x59, 0xe8, 0xcb, 0x2c, 0xe6, 0x28, 0xcc,
+ 0x88, 0xf1, 0x35, 0xec, 0xe1, 0xe8, 0x54, 0x6a, 0x16, 0xfa, 0x9d, 0x18,
+ 0x32, 0xa1, 0x07, 0xe9, 0xbb, 0x61, 0x6f, 0x88, 0x9b, 0xca, 0x83, 0x32,
+ 0x0c, 0xbf, 0xdf, 0xb6, 0xb5, 0x1d, 0xfa, 0x84, 0x68, 0x24, 0x11, 0xe8,
+ 0x68, 0xbf, 0x14, 0xbc, 0x76, 0xbb, 0xcd, 0xec, 0x42, 0x5f, 0x2a, 0x89,
+ 0x18, 0xd5, 0x38, 0x74, 0x3a, 0x65, 0x8c, 0x9c, 0x26, 0x0f, 0x26, 0x81,
+ 0x83, 0x15, 0x19, 0x4f, 0x53, 0x4f, 0x2b, 0xf2, 0x5c, 0x3a, 0xd5, 0x5b,
+ 0x94, 0x46, 0x39, 0xe9, 0x4c, 0x2a, 0xdf, 0x6f, 0x65, 0x4e, 0x29, 0x1f,
+ 0x3a, 0xec, 0xe2, 0x5a, 0x6a, 0x33, 0x0a, 0xa7, 0xb9, 0xd7, 0x76, 0xfc,
+ 0xa2, 0x58, 0xf7, 0x57, 0x90, 0x91, 0x25, 0x7d, 0x3d, 0x62, 0x1c, 0xee,
+ 0x2c, 0x02, 0x39, 0x53, 0xf6, 0x22, 0x56, 0xcb, 0x4f, 0xb6, 0x27, 0xda,
+ 0x4d, 0x4b, 0x86, 0x2c, 0x43, 0x46, 0x61, 0x5f, 0x7d, 0xe9, 0xff, 0xa9,
+ 0x9c, 0x74, 0xf8, 0xbc, 0x5e, 0xfe, 0x5c, 0x61, 0x31, 0xd6, 0x9e, 0x9f,
+ 0xc6, 0xba, 0x51, 0xf0, 0x9b, 0xeb, 0x72, 0x1e, 0xb4, 0x81, 0x8b, 0x96,
+ 0x9b, 0x9a, 0x2d, 0xca, 0x2e, 0xd8, 0xe9, 0x06, 0xc9, 0x6d, 0xaf, 0x93,
+ 0xec, 0x40, 0x52, 0x0a, 0x53, 0xbb, 0x80, 0x8d, 0x31, 0x65, 0xab, 0x85,
+ 0xc1, 0xa4, 0x3c, 0x36, 0xc5, 0xbe, 0x2c, 0xf6, 0x9a, 0x3a, 0x95, 0x15,
+ 0xee, 0xd5, 0x90, 0xec, 0xc1, 0xac, 0x3c, 0xe6, 0x65, 0x65, 0x04, 0xf2,
+ 0x3a, 0x0b, 0x5e, 0x1e, 0xf2, 0x5c, 0x79, 0x0e, 0xbe, 0x26, 0x7f, 0x1a,
+ 0x58, 0xeb, 0xae, 0x07, 0x2e, 0xa6, 0xce, 0x31, 0xc6, 0x37, 0x19, 0x87,
+ 0x82, 0x97, 0x7f, 0x34, 0x45, 0x5e, 0x9a, 0x32, 0x7d, 0xaf, 0x01, 0x3c,
+ 0x48, 0x82, 0x77, 0xae, 0xfc, 0xb1, 0x97, 0x3a, 0x9f, 0x35, 0x81, 0xc5,
+ 0xe9, 0xde, 0x88, 0x34, 0x24, 0x30, 0xce, 0x1f, 0x93, 0x4f, 0x47, 0x20,
+ 0xd7, 0x22, 0xc6, 0xa6, 0xd0, 0xcf, 0x77, 0x1d, 0xfc, 0xb2, 0x18, 0x07,
+ 0x5d, 0xb5, 0x53, 0xe7, 0x67, 0x4d, 0x8e, 0x4f, 0x42, 0x3e, 0x36, 0xc6,
+ 0x03, 0xf8, 0x6c, 0xde, 0xa7, 0x8d, 0x02, 0x69, 0xf0, 0xa8, 0x53, 0x88,
+ 0x49, 0xcb, 0xc4, 0xd4, 0xf6, 0x73, 0xaf, 0x0b, 0xd7, 0xf9, 0x22, 0xc6,
+ 0x7f, 0x88, 0x38, 0xdc, 0x96, 0x79, 0xc8, 0xe5, 0xa7, 0xe0, 0x55, 0x36,
+ 0xe1, 0xb7, 0x0b, 0x33, 0xa9, 0x73, 0x8b, 0x26, 0xef, 0xdd, 0xe2, 0xa8,
+ 0xd9, 0x23, 0xd2, 0x4c, 0x7e, 0xa5, 0xc1, 0x2b, 0xd7, 0x36, 0xcd, 0xb4,
+ 0xf2, 0x65, 0xbe, 0x2d, 0xdf, 0x05, 0x9a, 0xa0, 0xf3, 0xdd, 0x61, 0x9b,
+ 0xa0, 0xaf, 0x0d, 0x6c, 0x22, 0x95, 0x98, 0x35, 0xe1, 0x9f, 0xbb, 0x2d,
+ 0x39, 0xa5, 0xda, 0xe0, 0xd1, 0x60, 0x2a, 0x91, 0x35, 0x11, 0x33, 0x95,
+ 0xba, 0xe4, 0xac, 0xc7, 0xf1, 0x49, 0x85, 0x51, 0xfe, 0x78, 0xc4, 0x7a,
+ 0x1e, 0xe3, 0xc5, 0x2e, 0xd0, 0xec, 0xdb, 0xc9, 0xdc, 0xa4, 0xa3, 0x9e,
+ 0x9d, 0xf4, 0xfc, 0xb8, 0xd0, 0x44, 0xec, 0x38, 0x8b, 0xd8, 0x31, 0xaf,
+ 0x6c, 0xc6, 0xce, 0x22, 0xd7, 0x80, 0xce, 0xfb, 0xf6, 0x32, 0x5f, 0xba,
+ 0x4f, 0x86, 0xcf, 0x7c, 0x3f, 0x6e, 0x22, 0xce, 0x2a, 0x38, 0xa4, 0x8b,
+ 0xe3, 0xcf, 0x81, 0x4e, 0xf2, 0x4e, 0x86, 0x18, 0x57, 0x21, 0x16, 0x7e,
+ 0x84, 0x32, 0x1e, 0xed, 0x7e, 0x88, 0x7c, 0x2b, 0x82, 0xe8, 0x53, 0x3e,
+ 0x8e, 0x49, 0x91, 0x71, 0xe8, 0x62, 0xe4, 0x09, 0x19, 0x9a, 0xa7, 0x2f,
+ 0xc4, 0xcf, 0x23, 0x26, 0x02, 0xc7, 0x94, 0xcf, 0x6a, 0x87, 0x3e, 0x14,
+ 0xc1, 0xef, 0x8d, 0x3a, 0x0e, 0x3b, 0x08, 0xf9, 0xf6, 0x43, 0xfe, 0x19,
+ 0x19, 0x39, 0x33, 0x42, 0xdd, 0xee, 0x9a, 0x97, 0x54, 0xd7, 0x49, 0xd9,
+ 0x66, 0xcf, 0xc1, 0x06, 0xb3, 0x83, 0x95, 0x5d, 0x66, 0x86, 0xef, 0x9c,
+ 0xc0, 0x3b, 0xb8, 0xce, 0x8f, 0xc8, 0xd1, 0x32, 0xfb, 0x9e, 0x05, 0xdf,
+ 0x11, 0x17, 0xf7, 0x1c, 0xd4, 0xf6, 0x80, 0xf9, 0xac, 0x60, 0xbe, 0x11,
+ 0x3d, 0x1f, 0xc7, 0x71, 0x0c, 0xdf, 0x59, 0x9a, 0x77, 0x37, 0x7d, 0x22,
+ 0x30, 0xa8, 0xc3, 0xac, 0xec, 0x8a, 0xe2, 0xf9, 0x73, 0x3d, 0xbc, 0xc7,
+ 0x3c, 0xf0, 0x89, 0xb6, 0xdb, 0x8f, 0xb1, 0x83, 0x98, 0x73, 0x9d, 0xb4,
+ 0xb5, 0x04, 0xf4, 0x52, 0x3f, 0x18, 0xab, 0xb0, 0x3d, 0xb2, 0xc9, 0x97,
+ 0xd1, 0xab, 0x11, 0xdf, 0xc7, 0xcc, 0xa2, 0x4d, 0x3b, 0x3c, 0x26, 0x79,
+ 0x2f, 0x85, 0x7d, 0x42, 0x06, 0xe5, 0x51, 0xbd, 0x47, 0xc8, 0x69, 0xe0,
+ 0x29, 0xf0, 0x41, 0x8a, 0x3e, 0x6f, 0xc8, 0x17, 0xf2, 0xe4, 0x38, 0x6c,
+ 0xe0, 0x71, 0x8c, 0x41, 0xbc, 0xab, 0x78, 0x60, 0x6f, 0xf2, 0xe3, 0xf5,
+ 0x54, 0x31, 0xcb, 0xbc, 0xb3, 0x99, 0xba, 0x0d, 0xdc, 0x2a, 0x0f, 0xd8,
+ 0x9c, 0x7b, 0xd6, 0x64, 0x7e, 0x92, 0x4a, 0x5e, 0x88, 0xec, 0x67, 0xbb,
+ 0x6b, 0xd6, 0x84, 0x8c, 0x20, 0xc7, 0xdc, 0xf6, 0x76, 0x8d, 0x55, 0xef,
+ 0x28, 0x5d, 0xa6, 0xde, 0x17, 0xbc, 0x6d, 0xf6, 0x43, 0x42, 0x5d, 0x76,
+ 0xa0, 0x17, 0xc4, 0x0b, 0x5e, 0x2d, 0xf8, 0xee, 0x04, 0x74, 0x61, 0xbd,
+ 0xa6, 0x9d, 0xf7, 0x96, 0xcc, 0xda, 0x58, 0xc3, 0xfb, 0x8f, 0x0d, 0x7e,
+ 0x1f, 0xef, 0x19, 0x33, 0x05, 0x72, 0x0c, 0x68, 0xa5, 0x3c, 0x6b, 0x65,
+ 0xf8, 0x24, 0x68, 0x67, 0x3f, 0xae, 0xf3, 0xc7, 0x60, 0xa7, 0xc0, 0x94,
+ 0x9e, 0x8e, 0xc4, 0x45, 0x8c, 0xcf, 0x03, 0xf7, 0x8b, 0x16, 0x9f, 0x5d,
+ 0x31, 0x96, 0xde, 0x31, 0x19, 0x27, 0x23, 0x1e, 0xbf, 0x60, 0x7c, 0x0d,
+ 0xb1, 0x4e, 0x6e, 0xfe, 0x8a, 0x91, 0x87, 0x5e, 0xcc, 0x7b, 0x77, 0x43,
+ 0x9f, 0x68, 0x57, 0x36, 0xd6, 0x4e, 0x25, 0xfe, 0xc9, 0x6c, 0x4f, 0xce,
+ 0x01, 0x03, 0x0e, 0x81, 0xb1, 0xbe, 0x2c, 0x5d, 0x25, 0xdb, 0x45, 0x33,
+ 0xaa, 0xf1, 0x8f, 0xed, 0x94, 0xfd, 0xb0, 0xc0, 0x58, 0x1a, 0xf6, 0x80,
+ 0xcf, 0x7b, 0x64, 0xb8, 0x9c, 0x91, 0xc2, 0x99, 0x6d, 0xf6, 0x28, 0x72,
+ 0xf5, 0x25, 0xda, 0x89, 0x75, 0x45, 0x60, 0x1d, 0xfc, 0xb7, 0x27, 0xc5,
+ 0xba, 0x0c, 0x31, 0xaf, 0x03, 0xfa, 0x84, 0xbe, 0xd2, 0x92, 0x4e, 0xde,
+ 0xbf, 0x62, 0x3f, 0xf4, 0xdb, 0xcb, 0xf7, 0x34, 0x2f, 0xd7, 0xde, 0xd3,
+ 0xee, 0xea, 0x9e, 0x88, 0x31, 0xf0, 0x03, 0x1e, 0xfc, 0x00, 0x74, 0xfa,
+ 0x75, 0x0f, 0x7e, 0xc0, 0x83, 0x1f, 0x80, 0x3d, 0xbe, 0x02, 0x7d, 0x7c,
+ 0xd9, 0x83, 0x2f, 0xf0, 0xe0, 0x0b, 0x3c, 0xf8, 0x02, 0x2f, 0x07, 0xd9,
+ 0x11, 0xef, 0xe9, 0x4b, 0x0e, 0x54, 0xfd, 0xa7, 0x1f, 0x83, 0xdd, 0xa2,
+ 0xe3, 0x1a, 0xd8, 0xae, 0xbd, 0x59, 0x46, 0xbb, 0x98, 0x13, 0x35, 0xe0,
+ 0xda, 0x88, 0x2b, 0x62, 0x98, 0xae, 0x2f, 0x69, 0xdb, 0x79, 0x1c, 0x74,
+ 0x01, 0x17, 0xba, 0xbe, 0x08, 0xdd, 0x44, 0x1c, 0xe1, 0xfe, 0x86, 0x8e,
+ 0x7f, 0x7e, 0x64, 0xf9, 0xba, 0xd9, 0x88, 0xbe, 0xfb, 0xd0, 0xd7, 0x88,
+ 0x31, 0x47, 0x31, 0x86, 0xf1, 0x53, 0x93, 0xee, 0x0b, 0x8f, 0x63, 0x1c,
+ 0xf5, 0x00, 0xd6, 0x4a, 0x61, 0x5c, 0x13, 0xe6, 0x6e, 0xc5, 0x98, 0x9d,
+ 0x18, 0x73, 0x2b, 0xda, 0x8c, 0xb9, 0xb7, 0xa0, 0x7d, 0x4f, 0xcd, 0x3b,
+ 0xb7, 0xa3, 0xef, 0x4b, 0x35, 0x7d, 0x8b, 0xe8, 0xeb, 0x41, 0xdf, 0x45,
+ 0xfd, 0x5e, 0x11, 0xed, 0x96, 0x9a, 0x31, 0x97, 0xd1, 0x87, 0xb8, 0xd9,
+ 0xfe, 0x7b, 0x5c, 0xfb, 0x71, 0x25, 0x4d, 0xc1, 0x33, 0xc6, 0xcd, 0xc8,
+ 0x41, 0xab, 0xb1, 0xef, 0x5b, 0x8c, 0x0b, 0xe1, 0x7b, 0x7f, 0x6c, 0xf9,
+ 0x71, 0xe3, 0x77, 0x6d, 0x5f, 0x57, 0x83, 0xf6, 0x8f, 0x6a, 0xda, 0x1c,
+ 0xfb, 0xdf, 0x35, 0x7d, 0x3b, 0x36, 0x2e, 0x6f, 0xdf, 0x59, 0xb7, 0xf2,
+ 0x9d, 0x89, 0x9a, 0x31, 0x2f, 0x37, 0x2f, 0x6f, 0xff, 0xe9, 0x2a, 0xef,
+ 0xec, 0xd9, 0xb0, 0xbc, 0xef, 0xd1, 0x4d, 0x35, 0x63, 0xa0, 0x53, 0x0e,
+ 0x72, 0xab, 0x60, 0xfc, 0x03, 0x37, 0xf9, 0xcf, 0xc9, 0xdf, 0x5a, 0x5d,
+ 0x52, 0x5b, 0x47, 0xdb, 0x84, 0x1c, 0x2e, 0x18, 0xb0, 0x39, 0xdb, 0xcc,
+ 0x5c, 0x32, 0xf2, 0xd0, 0xa9, 0x5c, 0x39, 0x98, 0x8f, 0xb6, 0x5c, 0x5b,
+ 0xdb, 0x08, 0x6a, 0x1a, 0x8c, 0xbb, 0xe2, 0xd0, 0x9b, 0xfd, 0x90, 0x71,
+ 0x6a, 0xa2, 0x28, 0x4b, 0x36, 0xdc, 0x66, 0xae, 0x65, 0xc3, 0x4f, 0x6b,
+ 0xdc, 0x7a, 0x0a, 0x74, 0x56, 0x64, 0x20, 0x5d, 0x4f, 0xff, 0xa4, 0xf1,
+ 0x8c, 0x58, 0x54, 0xa9, 0x44, 0xb6, 0x56, 0xe4, 0x48, 0xfa, 0xc3, 0x8a,
+ 0x28, 0x1c, 0x9c, 0x50, 0x58, 0x94, 0x34, 0xdb, 0x21, 0x23, 0x1b, 0xb9,
+ 0x8d, 0x23, 0x43, 0x0e, 0xfd, 0xd9, 0x31, 0xc6, 0x29, 0x27, 0x7c, 0x9c,
+ 0x25, 0x16, 0xa1, 0x8d, 0xbc, 0xae, 0x70, 0xda, 0x50, 0x31, 0x70, 0x61,
+ 0x9e, 0xd8, 0x4e, 0x3c, 0x85, 0xdf, 0xb6, 0x39, 0xef, 0x6a, 0x78, 0x19,
+ 0x8b, 0x32, 0x3e, 0xb4, 0xdc, 0x17, 0xe0, 0x1b, 0xf9, 0x8c, 0x71, 0x04,
+ 0xee, 0x4b, 0xaa, 0xae, 0x56, 0x5c, 0xbe, 0x97, 0xcd, 0xcc, 0x43, 0xae,
+ 0x63, 0x7f, 0xab, 0x63, 0x54, 0xbb, 0x79, 0x6d, 0x7b, 0xde, 0x5b, 0xb5,
+ 0xe7, 0x40, 0xdf, 0x56, 0xab, 0x59, 0xbc, 0xa3, 0xf8, 0xff, 0x52, 0x39,
+ 0x75, 0xaa, 0x08, 0xfb, 0x59, 0x50, 0x39, 0x7a, 0x20, 0x0b, 0xc6, 0x3c,
+ 0xa9, 0x67, 0x66, 0xe9, 0x2d, 0x54, 0x8e, 0xc2, 0xfc, 0xa4, 0x22, 0xbb,
+ 0xd3, 0xff, 0xa6, 0xf6, 0x9e, 0x35, 0x3b, 0xeb, 0x18, 0x63, 0x2c, 0x78,
+ 0xe4, 0x53, 0x1a, 0xcf, 0x11, 0xfb, 0xa7, 0x7f, 0x26, 0x79, 0x87, 0x7d,
+ 0xbf, 0xac, 0xcc, 0x21, 0x36, 0x52, 0xf1, 0x92, 0x8a, 0x0f, 0x18, 0xef,
+ 0x1d, 0x01, 0x8f, 0xc8, 0xc7, 0x01, 0xf0, 0x36, 0x88, 0x19, 0xfe, 0x91,
+ 0xbe, 0x58, 0x96, 0xc7, 0xd1, 0xc8, 0xb4, 0x4a, 0x97, 0x30, 0xa7, 0x89,
+ 0xf9, 0xe8, 0xe3, 0xe8, 0x47, 0xd8, 0x5f, 0x88, 0x32, 0xb6, 0xf3, 0x63,
+ 0x83, 0x08, 0xd6, 0xb3, 0x80, 0x83, 0xef, 0x0a, 0x63, 0x9a, 0x61, 0x25,
+ 0x03, 0x62, 0x29, 0x9f, 0xb1, 0x2f, 0xa6, 0x63, 0xef, 0xb8, 0x8e, 0xb5,
+ 0x6d, 0x1d, 0x6b, 0x93, 0x0e, 0xd6, 0x2d, 0x83, 0x38, 0x82, 0x72, 0xba,
+ 0x70, 0xdc, 0xdc, 0xca, 0x38, 0xa2, 0x49, 0x56, 0x8f, 0x23, 0x02, 0x9a,
+ 0x76, 0x82, 0x26, 0xc6, 0x7d, 0xaa, 0x4e, 0xd5, 0xec, 0xd7, 0xc6, 0x48,
+ 0x43, 0xe0, 0x27, 0x95, 0x3f, 0x9e, 0x80, 0xeb, 0xc3, 0xde, 0x10, 0x48,
+ 0x02, 0xdb, 0x73, 0x93, 0x3b, 0xb5, 0xdf, 0x65, 0x0e, 0xc1, 0xf8, 0xdd,
+ 0xd7, 0xd3, 0x5c, 0x7a, 0x34, 0x98, 0xa7, 0x05, 0x9e, 0x32, 0x54, 0x43,
+ 0xe3, 0x5a, 0x8c, 0x7b, 0x82, 0x18, 0x68, 0x8f, 0x8e, 0x81, 0xfa, 0xe5,
+ 0x88, 0xe7, 0xe7, 0x0c, 0x03, 0xa5, 0x01, 0xf4, 0x29, 0xda, 0x13, 0x8c,
+ 0x35, 0x4d, 0x93, 0xb1, 0x66, 0x0a, 0xc9, 0x87, 0xbf, 0x97, 0xb6, 0xad,
+ 0xac, 0x65, 0x06, 0x7b, 0x69, 0xbc, 0xb0, 0x7c, 0x2f, 0xbb, 0x94, 0xde,
+ 0x9b, 0xe0, 0x9d, 0x8f, 0x4d, 0x9c, 0xf3, 0x7c, 0x94, 0xb8, 0x35, 0x50,
+ 0x1a, 0x54, 0xf3, 0x8e, 0xaf, 0x98, 0x57, 0xb0, 0xc7, 0x03, 0x6b, 0x3c,
+ 0xe3, 0xfe, 0x19, 0x5b, 0xd8, 0x7a, 0xff, 0x81, 0x0c, 0x2f, 0x63, 0xce,
+ 0x2e, 0xa3, 0xa0, 0xe2, 0xb6, 0x83, 0x4a, 0x1e, 0x85, 0xd2, 0x10, 0xae,
+ 0xb4, 0x17, 0x35, 0x8f, 0xb2, 0x99, 0x51, 0x25, 0x83, 0x11, 0xb5, 0xc7,
+ 0xb9, 0xd2, 0x23, 0x88, 0xd7, 0xbe, 0x0e, 0x3f, 0x18, 0xae, 0x2b, 0x3a,
+ 0x18, 0x43, 0x5e, 0x15, 0x43, 0x78, 0x4a, 0x9a, 0x59, 0x33, 0xbc, 0x82,
+ 0x35, 0xb8, 0xe7, 0x38, 0xe4, 0x6f, 0xf8, 0xcf, 0xd5, 0xfa, 0x01, 0xcf,
+ 0xeb, 0x42, 0xf4, 0x54, 0x10, 0xbf, 0x26, 0x40, 0x43, 0xf8, 0x9d, 0x63,
+ 0xd2, 0xe7, 0x51, 0x56, 0xed, 0x89, 0x11, 0xe4, 0xbb, 0x05, 0x09, 0x62,
+ 0x11, 0xae, 0x4f, 0x0c, 0xc8, 0x23, 0x97, 0x4a, 0x60, 0x7f, 0x01, 0x5f,
+ 0x03, 0x9e, 0xc6, 0x2f, 0xd4, 0xea, 0xc7, 0x38, 0xe8, 0x19, 0xf6, 0xc8,
+ 0xa7, 0x40, 0x6f, 0x83, 0xb5, 0x2f, 0xab, 0xfd, 0x8c, 0xa9, 0xda, 0xe7,
+ 0xfa, 0xba, 0x40, 0x7f, 0x47, 0x11, 0xb7, 0xf8, 0xfa, 0xf8, 0x7b, 0x9a,
+ 0x37, 0x81, 0xde, 0xc6, 0xb5, 0x0e, 0x30, 0x47, 0xa4, 0x5d, 0x05, 0x3a,
+ 0xd2, 0x61, 0xef, 0x57, 0xbc, 0xe0, 0x33, 0x95, 0x13, 0x2a, 0x39, 0x0f,
+ 0x55, 0xe5, 0xbc, 0xbe, 0x46, 0x67, 0x3b, 0x6d, 0xdf, 0x46, 0x69, 0x8b,
+ 0xb0, 0x69, 0xd0, 0xf7, 0xd2, 0x32, 0xdb, 0xef, 0x5a, 0xa3, 0xae, 0x1c,
+ 0x97, 0xc8, 0xcc, 0x0f, 0xc0, 0xcb, 0xdb, 0x91, 0xd7, 0x20, 0xcb, 0x9f,
+ 0x22, 0x46, 0x31, 0xfe, 0x58, 0x8a, 0x89, 0xe7, 0x64, 0xb5, 0x78, 0xf8,
+ 0x5a, 0xb1, 0xc7, 0x9d, 0xd7, 0x19, 0x7b, 0xfc, 0x49, 0x1d, 0xf3, 0x9c,
+ 0x05, 0xd8, 0xe9, 0x21, 0xbc, 0x5f, 0xe7, 0xfe, 0x10, 0x3e, 0xed, 0xaf,
+ 0xac, 0x7a, 0x37, 0xc0, 0x8b, 0xb8, 0x6c, 0x9c, 0xd9, 0xac, 0x30, 0xc3,
+ 0x9e, 0x5a, 0xc2, 0x8c, 0x51, 0xcf, 0xd7, 0x5f, 0xf0, 0xca, 0xd9, 0x28,
+ 0xd7, 0x9b, 0x77, 0x2f, 0xe5, 0x10, 0x43, 0xd5, 0x1c, 0xe2, 0x96, 0x1a,
+ 0x3e, 0xae, 0x86, 0x99, 0xe7, 0x54, 0xbe, 0xfc, 0x6a, 0x39, 0xf5, 0x82,
+ 0x48, 0x1f, 0xf2, 0xe4, 0xd4, 0x79, 0x91, 0x2c, 0x72, 0x65, 0xe6, 0x73,
+ 0x7b, 0x90, 0x3b, 0xa7, 0x7e, 0x21, 0xd2, 0x8b, 0x9c, 0x99, 0xf9, 0x70,
+ 0x3f, 0xf8, 0xda, 0x03, 0x4c, 0x4d, 0x03, 0x63, 0xb7, 0x83, 0xbf, 0x5d,
+ 0x0a, 0x57, 0x0f, 0x9d, 0x46, 0xae, 0xad, 0xea, 0xec, 0xb4, 0x75, 0x07,
+ 0x7e, 0xb5, 0x52, 0x79, 0x2c, 0xdd, 0x8e, 0x7c, 0x3f, 0x29, 0x5f, 0xb6,
+ 0x98, 0xf3, 0x1a, 0x56, 0xae, 0x7b, 0x26, 0x12, 0x8e, 0x63, 0x0b, 0xd7,
+ 0xf4, 0x11, 0x2b, 0x79, 0x3f, 0xac, 0xfc, 0xc4, 0x78, 0xe4, 0x6a, 0xbc,
+ 0xdf, 0x5f, 0xe5, 0xfd, 0x9d, 0x0d, 0xd2, 0xd0, 0xaf, 0xea, 0x0b, 0xb9,
+ 0xee, 0xaf, 0x13, 0xcb, 0xd2, 0xf0, 0xf3, 0xf0, 0xc7, 0x15, 0xb9, 0x3f,
+ 0x7d, 0xa5, 0x72, 0xd1, 0xdd, 0x20, 0x85, 0xed, 0x07, 0x34, 0x9e, 0x1f,
+ 0x78, 0x32, 0xe7, 0x16, 0x61, 0x1f, 0xfa, 0xdb, 0xc2, 0x64, 0x0c, 0x51,
+ 0x29, 0xff, 0x9a, 0x65, 0xae, 0xf7, 0xf6, 0x7a, 0x69, 0xd8, 0xf6, 0x02,
+ 0x8b, 0x63, 0xc4, 0x99, 0x39, 0x27, 0xae, 0xea, 0xdd, 0x37, 0xb9, 0xec,
+ 0xb7, 0x21, 0xd3, 0xdf, 0x92, 0x39, 0xc4, 0x13, 0xf3, 0xbd, 0xa0, 0x71,
+ 0x7b, 0x0b, 0xc6, 0xd3, 0xee, 0xc8, 0xf3, 0xdf, 0x96, 0xa1, 0x41, 0xf2,
+ 0xd4, 0xc1, 0xf8, 0xfb, 0x31, 0xa6, 0x19, 0xd7, 0x07, 0x23, 0x73, 0x76,
+ 0xcc, 0x6f, 0x0f, 0x70, 0x0e, 0xfa, 0x52, 0xce, 0xc3, 0xb5, 0x5a, 0x94,
+ 0xcd, 0x2f, 0xcd, 0xcf, 0xb9, 0xf9, 0xec, 0xe3, 0xca, 0xbe, 0xee, 0xee,
+ 0xd0, 0x1a, 0x4d, 0xa1, 0x35, 0x7a, 0x42, 0x6b, 0x90, 0xb6, 0xe6, 0x10,
+ 0x6d, 0xcd, 0x78, 0xff, 0x3e, 0xac, 0xd7, 0xaf, 0xe3, 0x94, 0x60, 0x9d,
+ 0x60, 0x1f, 0x2d, 0xa1, 0xb1, 0x1f, 0x62, 0x0d, 0xf6, 0x39, 0xa1, 0x3e,
+ 0xae, 0x0b, 0x1c, 0x73, 0xd8, 0x6e, 0x0e, 0xd1, 0x42, 0xfa, 0x1a, 0xd0,
+ 0xaf, 0xe6, 0x02, 0x3f, 0x1b, 0xe0, 0xbb, 0x4c, 0xf8, 0x8f, 0x08, 0xe2,
+ 0xaa, 0x60, 0x4f, 0xc1, 0x1c, 0x0e, 0xde, 0xe3, 0x18, 0xff, 0xb9, 0xff,
+ 0x0e, 0xfb, 0xf9, 0x3c, 0x22, 0xdf, 0x53, 0xf4, 0xb2, 0xcd, 0x3d, 0x34,
+ 0x81, 0x56, 0x5e, 0x53, 0x32, 0xdb, 0x0c, 0xd9, 0x77, 0x33, 0x9f, 0x36,
+ 0xe4, 0x36, 0xd7, 0x34, 0xf2, 0xdd, 0x94, 0xef, 0x06, 0x8d, 0x97, 0x0d,
+ 0x46, 0xee, 0x34, 0x6b, 0x08, 0x8d, 0x3a, 0xf7, 0x43, 0xbe, 0xa1, 0x7c,
+ 0x4c, 0xe0, 0x03, 0xe8, 0x63, 0x18, 0xab, 0xd0, 0x7f, 0x66, 0xf5, 0x3d,
+ 0xae, 0xd0, 0xd3, 0xc3, 0xf3, 0xcd, 0x72, 0x51, 0xf1, 0xd0, 0x96, 0xc5,
+ 0x2a, 0x0f, 0xa3, 0xfa, 0xbb, 0xd1, 0x31, 0xfd, 0x4d, 0x66, 0x3f, 0xe2,
+ 0x01, 0xdc, 0x97, 0x80, 0xb9, 0xdd, 0xd0, 0xb7, 0x6e, 0xe6, 0x70, 0x45,
+ 0x5c, 0x59, 0xc3, 0x30, 0x70, 0x75, 0x70, 0x8d, 0xe1, 0x0a, 0xbf, 0x04,
+ 0xac, 0xc9, 0x77, 0xbf, 0x0d, 0x1d, 0x82, 0x6c, 0xca, 0xb6, 0x71, 0xbf,
+ 0xe7, 0xd7, 0x87, 0x16, 0xdd, 0xd5, 0xeb, 0x43, 0x8b, 0xa2, 0xea, 0x43,
+ 0x13, 0xd7, 0xa8, 0x0f, 0x65, 0xaf, 0xbf, 0x3e, 0x74, 0xa2, 0x9e, 0x18,
+ 0xbc, 0xb7, 0x47, 0x8c, 0xdf, 0xd5, 0xf5, 0xa1, 0xf7, 0xc5, 0xaf, 0x0f,
+ 0x5d, 0x94, 0xd5, 0xeb, 0x43, 0x13, 0x35, 0xf5, 0xa1, 0x8d, 0xaa, 0x3e,
+ 0xc4, 0x79, 0xfc, 0xfa, 0x10, 0xdb, 0x6d, 0xdd, 0xbd, 0xa1, 0x3a, 0x08,
+ 0xf0, 0x54, 0xe5, 0x84, 0xb6, 0x31, 0xe8, 0x05, 0x18, 0x45, 0x2c, 0xbf,
+ 0xb9, 0xea, 0x8f, 0x96, 0xf0, 0xca, 0x50, 0xba, 0x75, 0x2d, 0xbc, 0x1a,
+ 0xf4, 0x63, 0x90, 0x65, 0x58, 0x35, 0x5e, 0x8d, 0x53, 0x5e, 0xab, 0x67,
+ 0xde, 0x3c, 0x56, 0x5a, 0x9a, 0x77, 0x0c, 0xb2, 0x1d, 0xaa, 0xd6, 0x50,
+ 0xd6, 0x8a, 0x85, 0x1c, 0x39, 0xb6, 0xea, 0x37, 0xb8, 0x44, 0x76, 0xe5,
+ 0x37, 0x38, 0x43, 0x1c, 0xd0, 0xd9, 0xd6, 0x5d, 0x50, 0x79, 0xd5, 0x9c,
+ 0xf7, 0x55, 0xb9, 0xf0, 0xb0, 0x0d, 0x3c, 0x09, 0x6a, 0x26, 0x94, 0xe5,
+ 0x92, 0x8f, 0x28, 0x98, 0x9f, 0x5f, 0xdd, 0xe4, 0xb0, 0xaa, 0x9b, 0xfc,
+ 0xbc, 0x3e, 0x5c, 0x37, 0x59, 0x94, 0xab, 0xd7, 0x4d, 0x0e, 0xaf, 0x52,
+ 0x37, 0x79, 0x53, 0x96, 0xea, 0x26, 0x6f, 0x4a, 0x50, 0x37, 0x89, 0xc8,
+ 0x85, 0x4d, 0x9c, 0xe7, 0x08, 0xde, 0x19, 0xc0, 0xaf, 0x1f, 0x3f, 0xbf,
+ 0x8e, 0xb2, 0x58, 0xa5, 0x7f, 0xb5, 0x3a, 0x4a, 0x7d, 0xec, 0x93, 0xd4,
+ 0x51, 0x7c, 0x4c, 0x0f, 0xea, 0x28, 0x0d, 0x88, 0x5f, 0xe0, 0x43, 0xcc,
+ 0x70, 0x1d, 0xa5, 0x15, 0xf3, 0xb2, 0x8f, 0x6d, 0xf6, 0xc3, 0x2e, 0xe0,
+ 0x67, 0xb2, 0xaa, 0xce, 0xf1, 0x9b, 0x9a, 0x87, 0x07, 0xb0, 0xe7, 0x24,
+ 0x64, 0x41, 0x3e, 0xb6, 0xab, 0x38, 0x32, 0x6b, 0x25, 0x8c, 0x5c, 0x27,
+ 0xbc, 0xd3, 0x24, 0xbf, 0xd9, 0x27, 0x64, 0xa4, 0x4c, 0x1d, 0x6f, 0x45,
+ 0xdc, 0x6d, 0xa1, 0xef, 0x00, 0xda, 0x41, 0x8c, 0xd4, 0x5d, 0x9d, 0x83,
+ 0x76, 0x38, 0xc7, 0x7a, 0x9f, 0x73, 0x3d, 0x3e, 0x67, 0x27, 0x68, 0x0e,
+ 0xef, 0xa3, 0x08, 0x7f, 0x83, 0x3e, 0x25, 0x73, 0xc6, 0x8a, 0x01, 0x2d,
+ 0x49, 0xda, 0xf4, 0x75, 0xcc, 0xc7, 0xbe, 0x9d, 0x2a, 0xdf, 0x1a, 0xee,
+ 0xe1, 0x5e, 0xe9, 0xbb, 0x16, 0x40, 0x1f, 0xfa, 0xe6, 0x99, 0xe3, 0xd1,
+ 0x8f, 0x05, 0x39, 0x58, 0x5c, 0xe5, 0x60, 0x2d, 0x8a, 0x1f, 0xe4, 0xf5,
+ 0x23, 0x31, 0xe2, 0x63, 0x8b, 0xcb, 0x3d, 0xf4, 0x6b, 0x5c, 0x63, 0xdb,
+ 0xcf, 0xf5, 0x58, 0x8f, 0x6e, 0x71, 0x9f, 0x80, 0x5c, 0x59, 0xab, 0x09,
+ 0xe4, 0xf7, 0x0d, 0xbd, 0xef, 0x5e, 0x29, 0xb6, 0x48, 0x6c, 0x23, 0xe8,
+ 0x69, 0x9b, 0x62, 0x8c, 0x7d, 0x8f, 0xca, 0x37, 0x1c, 0x77, 0x6d, 0xbb,
+ 0xdd, 0x7f, 0x03, 0x76, 0x3b, 0x70, 0x55, 0xbb, 0x3d, 0x1b, 0x0b, 0xdb,
+ 0xed, 0xfe, 0x1b, 0xb0, 0xdb, 0x23, 0x37, 0x64, 0xb7, 0xdc, 0x1b, 0x31,
+ 0x29, 0xa8, 0x8b, 0xad, 0x8c, 0x9b, 0x82, 0x75, 0x47, 0xb1, 0x66, 0x76,
+ 0x8d, 0x35, 0x87, 0xd6, 0xac, 0xbb, 0xd6, 0xc6, 0x4c, 0xd7, 0x23, 0x6f,
+ 0xe6, 0x21, 0xf4, 0xab, 0x71, 0xed, 0x83, 0x9e, 0xd6, 0x3a, 0x1f, 0xe4,
+ 0xed, 0x61, 0xfb, 0xa1, 0x5e, 0x50, 0x17, 0x7e, 0x02, 0x7e, 0x51, 0x1f,
+ 0x02, 0x9b, 0x6b, 0xaf, 0xd1, 0xc1, 0x05, 0xe4, 0xf3, 0xed, 0x5a, 0x07,
+ 0x29, 0xeb, 0x4e, 0xf5, 0x3d, 0x69, 0xde, 0x7b, 0xc2, 0xcf, 0xe3, 0xa1,
+ 0x03, 0x85, 0xf9, 0xc0, 0xd6, 0x92, 0x58, 0x37, 0x78, 0x46, 0x3e, 0xba,
+ 0x88, 0x61, 0xb6, 0x21, 0xfe, 0x02, 0x8f, 0x54, 0xff, 0xf2, 0x3a, 0xf0,
+ 0xd5, 0xf1, 0x4c, 0x8a, 0x51, 0x8c, 0x7d, 0xae, 0x07, 0x36, 0xde, 0x43,
+ 0x8c, 0xca, 0x20, 0x8f, 0xa1, 0x1e, 0x52, 0x37, 0x3b, 0xba, 0x0e, 0x99,
+ 0x8c, 0x91, 0x0e, 0xc2, 0xf6, 0x6c, 0xa5, 0xc7, 0xbb, 0xcb, 0x1d, 0xe7,
+ 0x16, 0x4d, 0xae, 0x51, 0xa9, 0x14, 0x54, 0xbd, 0x5e, 0xcc, 0x5c, 0xf7,
+ 0x4d, 0xeb, 0xe8, 0x97, 0x6e, 0x76, 0x23, 0x5a, 0xd7, 0xb2, 0xb8, 0xa7,
+ 0xde, 0xfe, 0x2b, 0x7c, 0x3b, 0xf2, 0x89, 0xee, 0x7f, 0x41, 0x7f, 0x02,
+ 0x36, 0x4f, 0x5f, 0xce, 0xfc, 0x62, 0x87, 0x1e, 0xd7, 0xae, 0xbe, 0x95,
+ 0xaa, 0xef, 0x2d, 0x4e, 0xe0, 0x7f, 0x52, 0xf4, 0xcf, 0xcb, 0xe4, 0xcc,
+ 0xb3, 0x1b, 0x79, 0x95, 0x9f, 0xf0, 0x7d, 0xa5, 0x93, 0xc8, 0x29, 0xac,
+ 0x50, 0x9d, 0x3d, 0xa6, 0x73, 0x31, 0xda, 0x58, 0x5c, 0xe5, 0x89, 0x7e,
+ 0xee, 0xc1, 0x5c, 0x75, 0xf9, 0x99, 0x8d, 0xd5, 0x75, 0x60, 0xf3, 0x27,
+ 0xd0, 0x81, 0x5a, 0xf9, 0xc5, 0x60, 0xfb, 0x81, 0xfc, 0x82, 0x98, 0x65,
+ 0x56, 0xef, 0xbb, 0xdd, 0x97, 0xe1, 0xff, 0x8b, 0x7d, 0x1a, 0xa1, 0x7d,
+ 0x06, 0x78, 0x74, 0x58, 0xef, 0x73, 0x47, 0x0d, 0x1e, 0x0d, 0xd4, 0xd8,
+ 0xec, 0xe7, 0x89, 0x47, 0x97, 0xd7, 0x7d, 0xfe, 0x78, 0xc4, 0x7d, 0x6d,
+ 0x59, 0x15, 0x87, 0xfc, 0x7d, 0x3c, 0x2d, 0x66, 0xe6, 0xb3, 0xcc, 0xdf,
+ 0x3e, 0x89, 0x7c, 0xc2, 0x38, 0x42, 0x99, 0x34, 0xa9, 0x78, 0xd5, 0xb7,
+ 0x3d, 0xf8, 0xf2, 0xf9, 0xa8, 0xbc, 0xf7, 0x50, 0x4c, 0x7e, 0x75, 0x2f,
+ 0xbf, 0x95, 0x59, 0xba, 0x7e, 0xc5, 0x76, 0xb4, 0xc1, 0xf7, 0x43, 0x48,
+ 0x24, 0x94, 0xdf, 0xe1, 0x3b, 0x81, 0x3d, 0xdb, 0x78, 0xce, 0x67, 0x5b,
+ 0xe4, 0x42, 0xf3, 0x8d, 0xe4, 0x74, 0x1d, 0xf6, 0xfb, 0xe6, 0x6a, 0x39,
+ 0xdd, 0xd5, 0x6b, 0x7f, 0x4b, 0x39, 0x1d, 0x71, 0xb6, 0x59, 0xd7, 0x7b,
+ 0x98, 0xd7, 0xec, 0xd7, 0xd8, 0xc9, 0x7b, 0xe4, 0xaa, 0x1e, 0xf2, 0x57,
+ 0xc8, 0xf6, 0x35, 0xc4, 0x4b, 0xaf, 0x7a, 0xc8, 0x59, 0x3d, 0xe4, 0xaa,
+ 0x1e, 0x72, 0x55, 0x0f, 0xb9, 0xaa, 0xd7, 0xa5, 0x73, 0xde, 0x01, 0x5d,
+ 0xd7, 0xe7, 0xf7, 0x70, 0xd6, 0x0b, 0x8a, 0xf0, 0x25, 0xe3, 0x3c, 0x63,
+ 0x61, 0xe6, 0xd2, 0xeb, 0x82, 0x73, 0x48, 0xba, 0xe6, 0xdd, 0xaa, 0x6b,
+ 0x30, 0x75, 0x37, 0x29, 0xdf, 0x6c, 0xbe, 0xd1, 0xe0, 0x7f, 0x33, 0xe7,
+ 0xf9, 0x8f, 0x3f, 0x44, 0x5c, 0xc2, 0x1a, 0xd8, 0x04, 0x6d, 0xb4, 0x62,
+ 0x66, 0x58, 0x63, 0x11, 0xd3, 0xcc, 0x7c, 0x01, 0xef, 0x6c, 0xc3, 0x1e,
+ 0xea, 0x69, 0xdb, 0x11, 0x33, 0xd3, 0x48, 0x9e, 0x1a, 0x66, 0x66, 0xbd,
+ 0x9e, 0xeb, 0x6f, 0x1a, 0xfc, 0xd8, 0xaa, 0x93, 0x6d, 0xcb, 0x64, 0x9c,
+ 0xa0, 0x62, 0xed, 0xa0, 0x7f, 0x4f, 0xf3, 0xf2, 0xb5, 0xa2, 0x0a, 0xdf,
+ 0x73, 0xe9, 0x87, 0x31, 0x9f, 0x3a, 0xdb, 0x54, 0xe5, 0xb7, 0xb9, 0x26,
+ 0xbf, 0xa3, 0x9a, 0xdf, 0x3e, 0x8f, 0x23, 0x1c, 0xa7, 0xea, 0xbe, 0xe4,
+ 0x75, 0x30, 0x9f, 0xaa, 0xe1, 0x61, 0x1d, 0x75, 0x8e, 0x03, 0xd7, 0xbb,
+ 0xa2, 0xd2, 0x34, 0x78, 0x20, 0xea, 0x86, 0xd7, 0x25, 0x46, 0xf5, 0x2e,
+ 0xfb, 0xfe, 0xb4, 0xf6, 0x9a, 0xed, 0xea, 0xdb, 0x99, 0xef, 0x33, 0xa2,
+ 0x4a, 0x07, 0x2d, 0x75, 0x36, 0xef, 0xd7, 0xea, 0xcc, 0x0d, 0xf5, 0x2f,
+ 0x8f, 0x3c, 0x66, 0xbc, 0xa7, 0x23, 0x69, 0x99, 0x7f, 0xd1, 0xc0, 0x5a,
+ 0x6b, 0x5f, 0x39, 0xc0, 0x3d, 0xae, 0x57, 0xeb, 0xc7, 0x59, 0x27, 0x0b,
+ 0xf0, 0x4c, 0x36, 0xfb, 0xf5, 0xb3, 0x4f, 0x63, 0x4b, 0x0d, 0x35, 0xb6,
+ 0x14, 0xec, 0xd3, 0xcf, 0x57, 0xf9, 0xdd, 0x7a, 0xb5, 0xb3, 0x13, 0x0b,
+ 0xe5, 0xd0, 0xf7, 0x8f, 0xaa, 0x6e, 0xf0, 0x5c, 0xcb, 0x83, 0xd0, 0x41,
+ 0xd6, 0xfe, 0xf7, 0xc0, 0x8e, 0x2a, 0x95, 0x3e, 0xd6, 0x93, 0xb7, 0x3f,
+ 0xa0, 0xcf, 0x27, 0x3c, 0xa3, 0xea, 0x09, 0xd6, 0x8a, 0x7a, 0x42, 0x1f,
+ 0x74, 0x05, 0x31, 0x00, 0x6c, 0xb0, 0xa0, 0x64, 0xc9, 0x78, 0xa0, 0xf6,
+ 0xfb, 0xca, 0xf9, 0x46, 0x9f, 0x0f, 0xb7, 0x37, 0xfa, 0xdf, 0x18, 0x7e,
+ 0xe9, 0x2c, 0x6f, 0xf3, 0xfd, 0x44, 0x63, 0x70, 0xce, 0x67, 0xf8, 0x4c,
+ 0x1f, 0x74, 0xb1, 0x4e, 0xf2, 0x6a, 0x3e, 0xc4, 0xbb, 0xcf, 0xff, 0xac,
+ 0x79, 0xf9, 0x78, 0xf4, 0x9d, 0x09, 0xc6, 0x37, 0xd7, 0x8c, 0x6f, 0xc6,
+ 0xf8, 0x7f, 0xaf, 0x19, 0xdf, 0x1c, 0x1a, 0xef, 0xd4, 0x8c, 0x77, 0x30,
+ 0xbe, 0x7e, 0xd3, 0xf2, 0xf1, 0x4e, 0x68, 0x7c, 0x4b, 0xcd, 0xf8, 0x16,
+ 0x8c, 0x6f, 0xa8, 0x19, 0x8f, 0xbe, 0x33, 0x75, 0xfa, 0xbb, 0x17, 0x31,
+ 0xf6, 0x88, 0xce, 0xbb, 0x71, 0x2d, 0xd5, 0x7e, 0x4b, 0xa1, 0xde, 0xb5,
+ 0x42, 0x06, 0xc1, 0x39, 0x3b, 0xda, 0x6b, 0x16, 0xf6, 0xba, 0x14, 0xcb,
+ 0xf8, 0xfa, 0x18, 0xd6, 0x45, 0xe2, 0x43, 0x51, 0x22, 0x2e, 0x74, 0x67,
+ 0x1e, 0x3a, 0x34, 0x1f, 0xf8, 0x24, 0x9e, 0x99, 0x4a, 0x75, 0xf9, 0x7a,
+ 0x6a, 0x48, 0xd4, 0x5d, 0xd0, 0x39, 0xd8, 0x4e, 0xd2, 0x0e, 0xbc, 0x0c,
+ 0x30, 0x53, 0x4e, 0xf9, 0x76, 0x43, 0xfd, 0xe5, 0xfc, 0xda, 0x7e, 0xa8,
+ 0xab, 0x7a, 0x9d, 0xbe, 0x15, 0xb8, 0x96, 0x5c, 0x51, 0xab, 0x8a, 0x5c,
+ 0x07, 0xae, 0x0d, 0x54, 0x71, 0xed, 0x41, 0x99, 0xad, 0xe6, 0xdb, 0xfd,
+ 0x72, 0xd4, 0xdb, 0xcb, 0xf3, 0x38, 0xa7, 0xb2, 0xf2, 0xd9, 0xe4, 0xdb,
+ 0x7b, 0xab, 0x7e, 0x32, 0x35, 0x91, 0x95, 0x0b, 0xc7, 0x99, 0x43, 0x05,
+ 0xb5, 0xd6, 0x71, 0xef, 0x5b, 0x94, 0x0b, 0x6c, 0xe3, 0x46, 0xf3, 0x6d,
+ 0xce, 0xe7, 0xc8, 0x51, 0xff, 0x2c, 0x44, 0x75, 0xde, 0x62, 0x75, 0xde,
+ 0x84, 0xb6, 0x37, 0xfa, 0xe0, 0x25, 0x7f, 0x99, 0x87, 0xbf, 0x1c, 0x42,
+ 0xce, 0xbd, 0xe0, 0xad, 0x56, 0xef, 0xbc, 0x51, 0x7f, 0x59, 0x5b, 0x37,
+ 0xae, 0xf5, 0x97, 0x5c, 0xa7, 0xb6, 0x56, 0x9c, 0xac, 0xc1, 0x7f, 0xea,
+ 0xd3, 0x53, 0x3a, 0xa6, 0xc6, 0x75, 0xfe, 0x29, 0xd8, 0xa3, 0x29, 0x43,
+ 0x4a, 0x7f, 0xd9, 0x0e, 0x72, 0xcb, 0x03, 0xd5, 0xdc, 0x72, 0x29, 0x1f,
+ 0x44, 0xec, 0xda, 0x75, 0x9f, 0xc6, 0x47, 0xc6, 0xc8, 0xe3, 0xe8, 0x3f,
+ 0x05, 0x1d, 0xe0, 0x33, 0xd6, 0x3f, 0xef, 0x90, 0x2f, 0x5b, 0xbe, 0x7f,
+ 0xf2, 0xeb, 0x50, 0x07, 0x54, 0xfc, 0xcf, 0xfa, 0xff, 0x70, 0x7a, 0xa3,
+ 0x8e, 0xf7, 0xae, 0x85, 0xab, 0xcb, 0x73, 0x53, 0xd3, 0x3c, 0x81, 0x77,
+ 0x99, 0x9b, 0x3e, 0x10, 0x27, 0x86, 0xe6, 0xca, 0x57, 0x7d, 0xbf, 0x48,
+ 0xff, 0x32, 0xac, 0xbe, 0xfb, 0xa9, 0x3c, 0x14, 0xe3, 0x16, 0xf4, 0xfb,
+ 0x7e, 0x1e, 0x9a, 0x2b, 0x6f, 0x89, 0xfb, 0x38, 0x78, 0xb5, 0x9c, 0xe5,
+ 0x58, 0x9c, 0xb5, 0xbc, 0x05, 0xef, 0x5a, 0xb4, 0xae, 0xcc, 0x7b, 0x23,
+ 0x2b, 0xf2, 0xde, 0x41, 0x9d, 0xd7, 0x7e, 0x45, 0xe5, 0xbd, 0x3e, 0x8f,
+ 0xb9, 0x97, 0x70, 0x1e, 0xe5, 0x02, 0x0b, 0xf9, 0x8d, 0x84, 0xf8, 0x30,
+ 0xaa, 0xfc, 0x56, 0x61, 0xf2, 0x77, 0xd4, 0xf9, 0x89, 0x95, 0x7a, 0xf3,
+ 0x79, 0xfb, 0x89, 0x60, 0xef, 0x4f, 0x89, 0x5f, 0xaf, 0xdb, 0x03, 0x5a,
+ 0x98, 0x5b, 0x45, 0xb5, 0x3e, 0xa4, 0x34, 0x5e, 0x07, 0xe3, 0x82, 0x3c,
+ 0xbe, 0xfa, 0x5d, 0xb5, 0x98, 0x5d, 0x56, 0x3f, 0xd9, 0x42, 0x18, 0x86,
+ 0xdc, 0xb3, 0x37, 0xf0, 0x1d, 0xe2, 0xd3, 0x9c, 0x7f, 0xa8, 0xf5, 0x6b,
+ 0xfc, 0x46, 0xda, 0xaa, 0xcf, 0xc7, 0xb9, 0xb0, 0x01, 0x9e, 0x65, 0x0e,
+ 0xe3, 0xab, 0x3a, 0x03, 0x17, 0x73, 0x32, 0x62, 0xec, 0x23, 0x7d, 0xe9,
+ 0x7f, 0xd6, 0xfb, 0x4c, 0xc8, 0x91, 0x29, 0xbf, 0xbe, 0x69, 0xae, 0x71,
+ 0xfe, 0xcd, 0x34, 0xaf, 0xab, 0xbe, 0x79, 0x03, 0xe7, 0xdf, 0x5e, 0x8f,
+ 0x07, 0xf5, 0xcd, 0xda, 0xf3, 0x6f, 0x91, 0xeb, 0x3c, 0xff, 0xe6, 0xd7,
+ 0x37, 0x39, 0x4f, 0xb8, 0xbe, 0x79, 0x8f, 0x3a, 0x43, 0x36, 0x3a, 0xd5,
+ 0xa3, 0xce, 0x23, 0xb7, 0x75, 0xaf, 0x8d, 0xb3, 0xfb, 0x3e, 0xb3, 0x7c,
+ 0xe4, 0x3f, 0xe3, 0xe1, 0x7c, 0x64, 0xdf, 0xe7, 0x92, 0x8f, 0x70, 0x2f,
+ 0xbf, 0xef, 0x7f, 0xb7, 0xad, 0x39, 0xfb, 0x95, 0xfb, 0x1c, 0x6b, 0x98,
+ 0x47, 0x54, 0x0d, 0x73, 0xcb, 0xfa, 0x70, 0x0d, 0xd3, 0xbc, 0xc6, 0xd9,
+ 0xaf, 0x23, 0xab, 0xd4, 0x30, 0xa3, 0xa1, 0xb3, 0x5f, 0x51, 0x7d, 0xf6,
+ 0x6b, 0xa3, 0x8b, 0xbc, 0x51, 0xd7, 0x2c, 0xcd, 0xab, 0x9e, 0xfd, 0xea,
+ 0x59, 0xff, 0x49, 0x6a, 0x96, 0xb9, 0x65, 0x35, 0xcb, 0x15, 0x67, 0xbf,
+ 0xe0, 0xd7, 0x36, 0x4b, 0x32, 0x94, 0xe3, 0xe4, 0x6e, 0xf0, 0x6c, 0x43,
+ 0xfe, 0x3a, 0xe2, 0x80, 0x7d, 0x55, 0x5b, 0xe5, 0xd9, 0xfd, 0x3a, 0xec,
+ 0x39, 0x2a, 0x7b, 0x1d, 0xea, 0x27, 0xcf, 0x38, 0x76, 0xc2, 0x16, 0x70,
+ 0x2d, 0xb3, 0xdd, 0x45, 0x19, 0x19, 0x03, 0x9d, 0xcb, 0xcf, 0x17, 0x2c,
+ 0x9d, 0xd3, 0x8d, 0x55, 0xcf, 0xe9, 0x9e, 0x84, 0xde, 0x98, 0x53, 0x31,
+ 0x99, 0x0b, 0xe9, 0xd4, 0x38, 0x62, 0x3b, 0x73, 0xc6, 0xd6, 0xcf, 0x93,
+ 0x12, 0x99, 0x72, 0x80, 0x6f, 0x3c, 0xdb, 0xdb, 0x24, 0x91, 0x19, 0xff,
+ 0x7b, 0xa3, 0xa9, 0xf0, 0x33, 0x81, 0x31, 0x3c, 0xdb, 0x19, 0x95, 0xa3,
+ 0xaa, 0x3e, 0x11, 0xe8, 0xf2, 0x37, 0xc1, 0xe3, 0x4d, 0xd9, 0xa5, 0xb6,
+ 0xb3, 0x8a, 0x8f, 0x47, 0xcc, 0x38, 0x45, 0x7d, 0xbe, 0x5b, 0xf2, 0xba,
+ 0xf6, 0x33, 0x5c, 0xde, 0xa9, 0x73, 0x09, 0xf5, 0xcd, 0x06, 0xbc, 0x6c,
+ 0xd3, 0xfe, 0x16, 0xd7, 0xf9, 0x36, 0xfa, 0x37, 0xc6, 0xcc, 0xd2, 0x37,
+ 0xb9, 0x2d, 0x31, 0x02, 0x6c, 0x1b, 0x52, 0x6b, 0xde, 0x08, 0xcf, 0x8d,
+ 0x15, 0xf1, 0xd7, 0x8d, 0xf1, 0x3d, 0x88, 0x85, 0xdf, 0xc4, 0xfe, 0xda,
+ 0xa0, 0x1f, 0x8f, 0x4b, 0xfe, 0xcc, 0x1d, 0xd2, 0x37, 0x9d, 0x02, 0x3d,
+ 0xbf, 0xae, 0x0c, 0xa7, 0x11, 0x37, 0x3f, 0xcf, 0x33, 0x60, 0xc0, 0x4b,
+ 0xf0, 0xed, 0x95, 0x15, 0xdf, 0xa0, 0xc3, 0xe7, 0xc6, 0xba, 0xaa, 0xe7,
+ 0x80, 0x5e, 0x2a, 0x4b, 0xac, 0x99, 0x34, 0x4f, 0x2d, 0x9d, 0x09, 0x5f,
+ 0x28, 0xef, 0x56, 0x7e, 0xec, 0xc5, 0xf2, 0xff, 0x52, 0x77, 0x6d, 0xb1,
+ 0x6d, 0x9d, 0xf7, 0xfd, 0xcf, 0x43, 0xea, 0x12, 0xdd, 0x7c, 0x24, 0xd3,
+ 0x32, 0x2d, 0xd1, 0xf2, 0x39, 0xd2, 0xb1, 0xc5, 0xd8, 0x5a, 0xc7, 0x6a,
+ 0xca, 0x26, 0xac, 0x5a, 0xc2, 0x52, 0xf4, 0x65, 0x59, 0x36, 0xd0, 0x97,
+ 0x76, 0x1e, 0x16, 0xa0, 0x0e, 0x65, 0x3b, 0x1d, 0xd0, 0x07, 0xb7, 0xd9,
+ 0x80, 0xa4, 0x03, 0x6c, 0x96, 0xb2, 0x1c, 0xaf, 0x53, 0x4d, 0x36, 0x66,
+ 0xd5, 0xac, 0x1b, 0x50, 0x4e, 0x92, 0x9d, 0xb4, 0x50, 0xc0, 0x64, 0xbd,
+ 0x60, 0xd8, 0x43, 0xad, 0xc9, 0xf6, 0xf6, 0xb2, 0x87, 0x6c, 0xd8, 0x83,
+ 0x81, 0x0d, 0x98, 0x63, 0x05, 0x68, 0x96, 0x02, 0x49, 0x87, 0x15, 0x43,
+ 0x1e, 0x36, 0x70, 0xff, 0xdf, 0x77, 0x21, 0x0f, 0x0f, 0x0f, 0x75, 0x89,
+ 0x9d, 0x01, 0x33, 0x60, 0x88, 0xe7, 0x9c, 0xef, 0x9c, 0xf3, 0x7d, 0xff,
+ 0xef, 0x7f, 0xbf, 0x9d, 0x3a, 0x3f, 0x8f, 0xd8, 0xc3, 0xdc, 0xca, 0x5b,
+ 0x0c, 0x8b, 0xbb, 0x42, 0x96, 0xcd, 0xe5, 0x69, 0x28, 0x48, 0xd8, 0x0f,
+ 0x0a, 0x30, 0x0c, 0x44, 0x6e, 0x86, 0x8c, 0xcd, 0x47, 0xc5, 0xbe, 0x4a,
+ 0x5e, 0x71, 0xcc, 0x95, 0x5b, 0x51, 0xdb, 0x5b, 0x99, 0x73, 0x21, 0xf7,
+ 0x42, 0xe6, 0x85, 0x00, 0x9e, 0xab, 0x17, 0x8f, 0x3b, 0x32, 0x2f, 0x64,
+ 0x64, 0x01, 0xe7, 0xfa, 0x3d, 0x72, 0xae, 0x9d, 0x71, 0x00, 0x39, 0x44,
+ 0xc8, 0x05, 0xc7, 0x9c, 0x85, 0x5f, 0xc3, 0x37, 0x2e, 0xbd, 0x3d, 0xff,
+ 0xaa, 0x7c, 0xe7, 0xb0, 0x78, 0xe7, 0x2e, 0xc5, 0xb3, 0x74, 0x0e, 0x78,
+ 0x3c, 0x30, 0x93, 0x1f, 0x8d, 0x04, 0x19, 0xbf, 0x67, 0xca, 0xb0, 0xa5,
+ 0x9b, 0xe9, 0x6b, 0x1b, 0xc1, 0x33, 0xd1, 0x00, 0xcf, 0x7a, 0x9a, 0x60,
+ 0xdb, 0xbb, 0xca, 0xbb, 0x25, 0xec, 0xe4, 0x79, 0xe4, 0xb7, 0xeb, 0xfc,
+ 0x04, 0x09, 0xbb, 0x2a, 0x0d, 0x5d, 0x73, 0xe7, 0x26, 0xd4, 0x60, 0x77,
+ 0xa6, 0x0a, 0xbb, 0xdd, 0xff, 0x8f, 0x60, 0x77, 0x4f, 0xe8, 0xba, 0x6f,
+ 0x95, 0x91, 0x83, 0xa6, 0xe5, 0xbd, 0xae, 0x5d, 0x02, 0x1c, 0xc1, 0x4f,
+ 0xed, 0xd2, 0x2a, 0x81, 0xa7, 0x22, 0x6f, 0xb8, 0x52, 0xf9, 0x41, 0xbc,
+ 0xea, 0x93, 0x64, 0x1b, 0x04, 0xb6, 0x08, 0x7c, 0x77, 0xcd, 0x65, 0xe4,
+ 0xf1, 0x8f, 0x25, 0x23, 0xa1, 0x17, 0x79, 0x6d, 0x91, 0x1f, 0xf5, 0xb8,
+ 0x6d, 0x91, 0xe3, 0xdb, 0xb4, 0x45, 0x2e, 0x48, 0x5b, 0x24, 0xbb, 0x75,
+ 0x5b, 0x64, 0xa0, 0x21, 0x5f, 0xab, 0xb6, 0x9e, 0xed, 0xdb, 0x22, 0xc6,
+ 0x86, 0xb6, 0xc8, 0x88, 0xcb, 0xef, 0x82, 0xf9, 0xfe, 0x2e, 0x65, 0x4f,
+ 0x80, 0xc7, 0x69, 0x38, 0x03, 0xc6, 0x27, 0x3c, 0x3e, 0xe0, 0x4f, 0x12,
+ 0xd6, 0xe6, 0x8e, 0xff, 0x5b, 0x58, 0x0f, 0x36, 0xf8, 0xb7, 0x6b, 0xeb,
+ 0xa1, 0xf0, 0xce, 0x6d, 0xe9, 0xec, 0x5e, 0x58, 0x0f, 0x36, 0xf5, 0x93,
+ 0x36, 0xcf, 0x45, 0xac, 0xf7, 0x93, 0x0e, 0x1b, 0xcd, 0x78, 0xfb, 0x77,
+ 0x5d, 0xfe, 0x53, 0x37, 0x7f, 0x07, 0x4d, 0x51, 0xe0, 0xf8, 0xa8, 0x7e,
+ 0x17, 0x68, 0xc9, 0xce, 0x66, 0x09, 0xf6, 0x11, 0xde, 0x17, 0x11, 0xb4,
+ 0xe6, 0xd1, 0xb7, 0xf8, 0x7d, 0xbc, 0xbe, 0xd7, 0x9e, 0x15, 0x72, 0x4a,
+ 0xfa, 0x1a, 0x30, 0x3e, 0x16, 0x38, 0x2b, 0xc6, 0xca, 0xdc, 0x24, 0xe5,
+ 0x7b, 0x50, 0x7a, 0x7e, 0x33, 0x9f, 0x43, 0xa3, 0xcc, 0xdb, 0x9e, 0x5d,
+ 0xa0, 0x69, 0x7c, 0x1f, 0xef, 0x4b, 0xa4, 0xce, 0xae, 0x02, 0xff, 0xbc,
+ 0xc0, 0x7a, 0xc1, 0x70, 0x55, 0x27, 0xa8, 0xdf, 0x9b, 0xcb, 0xc2, 0x7e,
+ 0xd3, 0xbc, 0x33, 0x2d, 0xf2, 0xdd, 0x24, 0xef, 0x84, 0x9e, 0xa6, 0x79,
+ 0xa7, 0x57, 0x0f, 0xde, 0xe7, 0x83, 0x17, 0xbe, 0x75, 0xa7, 0x7a, 0xef,
+ 0x2c, 0xe4, 0x8f, 0xa7, 0x7c, 0xf7, 0xae, 0x5a, 0x77, 0x95, 0xad, 0x8d,
+ 0x95, 0xf7, 0xa7, 0xc4, 0xba, 0xa2, 0x4f, 0x27, 0x51, 0x13, 0x57, 0xad,
+ 0x09, 0xf2, 0xd6, 0x41, 0x41, 0x0e, 0x68, 0x3a, 0xd4, 0x75, 0xe2, 0x80,
+ 0x45, 0xcc, 0xa7, 0x0e, 0xca, 0x2d, 0x4b, 0x70, 0x9f, 0x17, 0x16, 0x35,
+ 0x39, 0x32, 0xa7, 0xe4, 0xc8, 0xa2, 0x8b, 0x8f, 0x37, 0xea, 0xed, 0x7d,
+ 0x3e, 0x7a, 0xbb, 0xbb, 0xb6, 0x43, 0xd4, 0xb8, 0x35, 0xa9, 0xed, 0xf0,
+ 0xab, 0x99, 0xc2, 0xd8, 0x17, 0x59, 0x5f, 0xf9, 0x14, 0xf4, 0x15, 0x13,
+ 0x35, 0x4b, 0x52, 0x67, 0xc1, 0x75, 0x96, 0x49, 0xaf, 0x45, 0x18, 0xa7,
+ 0x8e, 0xd1, 0x79, 0xd6, 0xc9, 0x6f, 0xd2, 0xe3, 0xca, 0x66, 0x4b, 0xb8,
+ 0xf2, 0x4c, 0x91, 0xdf, 0x1f, 0xa0, 0xec, 0xb3, 0x76, 0x2c, 0x41, 0xc7,
+ 0xe8, 0x9c, 0xc8, 0x99, 0x41, 0xcc, 0x0f, 0x79, 0x08, 0x07, 0xc5, 0x3c,
+ 0xa5, 0x7f, 0xe3, 0x51, 0xe4, 0xcd, 0x6d, 0x3d, 0x67, 0x5f, 0xd7, 0xfa,
+ 0x25, 0xc5, 0x3b, 0x97, 0x15, 0xed, 0x89, 0x73, 0x7c, 0xff, 0x8b, 0x46,
+ 0xe3, 0xfd, 0x09, 0x23, 0x55, 0x4e, 0x19, 0xc9, 0x25, 0x8c, 0x7b, 0xd1,
+ 0x98, 0x2e, 0xc3, 0xd6, 0xd4, 0xb8, 0x64, 0xc7, 0x41, 0x97, 0x6b, 0xb4,
+ 0x79, 0x7c, 0x62, 0x91, 0x3c, 0xf5, 0x13, 0x5b, 0x98, 0xf7, 0x91, 0xba,
+ 0x79, 0x6b, 0xf8, 0xe2, 0x37, 0x7c, 0x40, 0x09, 0x86, 0xa9, 0xd6, 0x7f,
+ 0x3b, 0xe0, 0x73, 0x8f, 0x65, 0x69, 0x23, 0xfd, 0xd7, 0x6e, 0xd0, 0x7f,
+ 0x17, 0x37, 0x9d, 0xf7, 0xc3, 0xf2, 0x02, 0x59, 0xc3, 0x1d, 0x74, 0x84,
+ 0x9e, 0xcb, 0xf3, 0xae, 0xd3, 0x81, 0x3d, 0x38, 0x85, 0x31, 0xda, 0x37,
+ 0xae, 0x7d, 0x63, 0x3d, 0x2a, 0x1f, 0x58, 0xe7, 0x2c, 0x74, 0x28, 0x3c,
+ 0xc6, 0x75, 0xd8, 0x62, 0xab, 0x3c, 0x3f, 0xd8, 0x65, 0x4f, 0x8a, 0x39,
+ 0xb2, 0x5d, 0x66, 0x4d, 0x93, 0xf4, 0x7f, 0x9f, 0x2d, 0xd7, 0xd5, 0x8f,
+ 0xfa, 0xd4, 0x51, 0x0e, 0xfb, 0xd4, 0x51, 0xba, 0x69, 0x32, 0xe4, 0xa2,
+ 0xc9, 0x88, 0x4b, 0xbf, 0x8b, 0xb2, 0x7d, 0xd3, 0xc5, 0xbc, 0x06, 0xf6,
+ 0x4d, 0x07, 0x05, 0x5f, 0x71, 0xdb, 0x37, 0xde, 0xba, 0x7d, 0xd0, 0x27,
+ 0x74, 0x38, 0x69, 0xeb, 0xa4, 0x8a, 0xd5, 0x9a, 0x7f, 0x5e, 0x77, 0xad,
+ 0x66, 0x71, 0xa9, 0xa1, 0xbe, 0xd2, 0x6f, 0xbe, 0x43, 0x0d, 0xf3, 0x85,
+ 0x9c, 0x4b, 0x34, 0xd5, 0xfd, 0xfc, 0xec, 0xaf, 0x47, 0x35, 0x3f, 0x2f,
+ 0xdf, 0xc3, 0xbb, 0x86, 0x85, 0x1f, 0x3c, 0x5b, 0xe5, 0x79, 0x93, 0x72,
+ 0xbe, 0xf9, 0x7a, 0x7b, 0x24, 0x78, 0x8d, 0x14, 0xec, 0xfc, 0x65, 0xc0,
+ 0xf6, 0x7c, 0x6a, 0x9d, 0x1e, 0xf9, 0x3c, 0xd1, 0x2b, 0x7d, 0x65, 0x2d,
+ 0x2a, 0xd7, 0x7a, 0x97, 0xb2, 0x0b, 0x37, 0xc3, 0x77, 0x9c, 0x6b, 0x51,
+ 0xfe, 0x45, 0xdb, 0x2a, 0x11, 0xf0, 0xfc, 0xc4, 0xe9, 0x16, 0xc7, 0x54,
+ 0xf1, 0x2d, 0xc4, 0xb0, 0x80, 0xf7, 0xfa, 0xf9, 0xb2, 0xd6, 0x6a, 0xf3,
+ 0x3d, 0xb3, 0x1a, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x32, 0xe4, 0x10, 0x8f,
+ 0x79, 0xf2, 0xb8, 0x1f, 0x06, 0x16, 0x3d, 0x3e, 0xb9, 0xcd, 0xc8, 0x4d,
+ 0x6e, 0x36, 0xcf, 0xfb, 0x2e, 0xfd, 0x1d, 0xf3, 0xad, 0x54, 0xde, 0x8c,
+ 0x0f, 0x48, 0x99, 0x5d, 0xf6, 0xd7, 0xa5, 0xcc, 0x2d, 0xcf, 0xcf, 0x2b,
+ 0xa3, 0xf7, 0x6c, 0x51, 0x46, 0x8b, 0x7e, 0x28, 0x81, 0xc3, 0x82, 0x07,
+ 0xa0, 0x06, 0x1b, 0x39, 0xd6, 0x9f, 0x06, 0xcd, 0x33, 0x9f, 0x75, 0xd5,
+ 0xaa, 0xf9, 0xef, 0x63, 0x35, 0xce, 0x12, 0x42, 0x2f, 0x88, 0x09, 0xe4,
+ 0x9b, 0xf4, 0x31, 0xef, 0xc1, 0xf8, 0xfd, 0xd6, 0x1d, 0xf8, 0x80, 0x95,
+ 0x9f, 0x2a, 0xa5, 0xe4, 0xcb, 0xe1, 0x2d, 0xc4, 0x5b, 0xb6, 0xc7, 0xa7,
+ 0x6d, 0x6b, 0x95, 0x10, 0x0b, 0x42, 0x4e, 0xf0, 0x0b, 0x3d, 0xd4, 0x73,
+ 0xaa, 0xad, 0xcd, 0xb9, 0xdb, 0x2b, 0xe3, 0x53, 0xb8, 0xd6, 0x45, 0x37,
+ 0x8a, 0xc8, 0xd7, 0xc6, 0xb5, 0xdf, 0xe3, 0x6b, 0x7e, 0x3c, 0x4a, 0xe7,
+ 0x9b, 0x43, 0xe7, 0x93, 0xfb, 0x53, 0x22, 0xd8, 0x54, 0x15, 0xfa, 0xa7,
+ 0xf8, 0xaf, 0xc8, 0x18, 0x47, 0xf9, 0x51, 0xc7, 0x6f, 0xfc, 0xfc, 0x8a,
+ 0x46, 0xdf, 0xc7, 0xcd, 0x97, 0xfc, 0xf2, 0x96, 0xfc, 0x8a, 0xc8, 0xbb,
+ 0xdf, 0x4a, 0x1c, 0x45, 0xc7, 0x8b, 0x27, 0x44, 0xed, 0xa9, 0x1b, 0x0f,
+ 0x1e, 0x4d, 0xcc, 0x18, 0xf8, 0x30, 0xd4, 0xc0, 0xab, 0x1e, 0x3e, 0x06,
+ 0xe0, 0x85, 0x6b, 0x87, 0xaf, 0x4f, 0xcb, 0x3f, 0x36, 0x8c, 0x3c, 0x00,
+ 0xf8, 0xb3, 0x9f, 0xa2, 0xb3, 0xd7, 0x81, 0xc3, 0x06, 0x63, 0xdb, 0x08,
+ 0xcd, 0x86, 0x51, 0x57, 0x24, 0x6a, 0x73, 0x54, 0x2c, 0x51, 0xd6, 0x0a,
+ 0x9d, 0x15, 0x75, 0x8f, 0xfb, 0x23, 0xeb, 0x94, 0x66, 0xb9, 0x97, 0xa5,
+ 0x73, 0x2c, 0x63, 0xcf, 0x2d, 0xd5, 0x74, 0xfc, 0xc6, 0xda, 0xc7, 0x7a,
+ 0x1c, 0x5f, 0x17, 0x38, 0x1e, 0xdd, 0x10, 0xc7, 0x8f, 0x56, 0x71, 0x7c,
+ 0xae, 0x4f, 0xe2, 0xf3, 0x45, 0x7e, 0x56, 0x0f, 0x1d, 0x16, 0xcf, 0xcd,
+ 0xf2, 0xef, 0x4e, 0x3a, 0x2c, 0xfb, 0x62, 0xf0, 0xbb, 0x99, 0xc7, 0xe7,
+ 0xb3, 0x74, 0xfe, 0x7a, 0x36, 0x90, 0x12, 0x35, 0x0a, 0xee, 0xbe, 0x1e,
+ 0xfa, 0x7e, 0x8c, 0x6b, 0x86, 0xff, 0x9a, 0x2f, 0xc9, 0x9a, 0xab, 0x92,
+ 0xe4, 0x4f, 0xf4, 0x76, 0x7c, 0xd0, 0x83, 0xff, 0xf5, 0x36, 0xe6, 0x05,
+ 0x25, 0x03, 0x4f, 0x6c, 0xe0, 0xff, 0x68, 0xc4, 0xcb, 0x5e, 0x1f, 0xbd,
+ 0xf9, 0x8d, 0x3e, 0x19, 0xbb, 0xda, 0xc8, 0xff, 0xe1, 0xc6, 0xd1, 0xba,
+ 0x58, 0x3e, 0xf3, 0xfd, 0x84, 0xaa, 0xff, 0x7b, 0xa7, 0x4f, 0xca, 0x0b,
+ 0xd4, 0x04, 0xa6, 0x19, 0x0e, 0x6f, 0xb2, 0xae, 0x32, 0x48, 0xad, 0xaf,
+ 0xe8, 0xb5, 0x0e, 0x0a, 0x7e, 0xeb, 0xf6, 0xe7, 0x5c, 0x56, 0xb5, 0xe0,
+ 0x39, 0xd7, 0x9a, 0x2e, 0x0b, 0x5b, 0xa8, 0x39, 0xbd, 0x35, 0xcf, 0xc3,
+ 0x8a, 0x7a, 0x64, 0x82, 0x17, 0xdf, 0xd0, 0x2f, 0x05, 0xfb, 0x4b, 0x86,
+ 0xd4, 0x83, 0x27, 0x59, 0xbf, 0xdd, 0x6e, 0x0c, 0xe9, 0x61, 0x75, 0x44,
+ 0x6f, 0x4f, 0x0e, 0xef, 0x6f, 0xec, 0x83, 0xb4, 0x39, 0x32, 0xaf, 0x3d,
+ 0x25, 0x78, 0xc1, 0xe5, 0xb1, 0x0a, 0x4d, 0xc7, 0xbb, 0x29, 0x33, 0xc6,
+ 0xef, 0x9e, 0x44, 0x4f, 0xac, 0x20, 0x65, 0x99, 0x7e, 0x33, 0x63, 0x8f,
+ 0x29, 0x7d, 0x51, 0xfb, 0xdd, 0xdb, 0x54, 0xee, 0xc3, 0x45, 0x11, 0xab,
+ 0x94, 0xfd, 0x84, 0xf8, 0xf7, 0x92, 0x7e, 0xf6, 0x45, 0x11, 0x33, 0xcd,
+ 0x5c, 0x6f, 0x55, 0xe3, 0x3a, 0x5d, 0xe3, 0x30, 0xa6, 0x53, 0x8d, 0xc5,
+ 0x33, 0xb5, 0x4e, 0xd1, 0xae, 0xf8, 0x2d, 0xe8, 0x30, 0xad, 0x6a, 0xf5,
+ 0x70, 0xfd, 0x02, 0xcd, 0x54, 0xd7, 0xd2, 0xc9, 0x63, 0xff, 0x5b, 0xf5,
+ 0xf2, 0xe8, 0x64, 0x9d, 0x17, 0xf3, 0x6e, 0x9c, 0x13, 0xd6, 0x12, 0x14,
+ 0x71, 0x24, 0xfe, 0xad, 0xde, 0x73, 0xa6, 0x3a, 0x27, 0xe4, 0x6d, 0xd8,
+ 0x11, 0xf9, 0x2c, 0x3d, 0xae, 0xd3, 0x35, 0x4e, 0xf3, 0x0a, 0x1d, 0xa7,
+ 0xf8, 0x57, 0x9e, 0xc7, 0x3f, 0xa8, 0xbc, 0x5e, 0x53, 0xc4, 0x54, 0x65,
+ 0xde, 0x86, 0xfe, 0x0d, 0x3f, 0x34, 0xf2, 0x2c, 0x90, 0x3b, 0xe1, 0xe6,
+ 0x37, 0x72, 0xbd, 0x21, 0xc8, 0xa2, 0x32, 0x62, 0xa9, 0x88, 0x6b, 0x34,
+ 0xd3, 0x9d, 0xf7, 0x20, 0x5f, 0x7f, 0x1b, 0x3a, 0xe8, 0x56, 0xe8, 0xcf,
+ 0xf2, 0xa1, 0x3f, 0xf7, 0xfb, 0x51, 0xeb, 0x86, 0x9a, 0xb7, 0x6c, 0xcc,
+ 0xa0, 0x0a, 0xdb, 0x0a, 0x06, 0x95, 0xcc, 0x00, 0x9d, 0x77, 0xec, 0xf8,
+ 0x12, 0xc9, 0x9a, 0xc9, 0xe9, 0x79, 0x3b, 0xb6, 0x4a, 0x87, 0xcc, 0x73,
+ 0x24, 0x7b, 0x25, 0x94, 0x58, 0x06, 0x9f, 0xa1, 0x18, 0xdb, 0x47, 0x6c,
+ 0x7f, 0x9e, 0x42, 0x5c, 0x46, 0xef, 0x0b, 0x6a, 0xe3, 0xf1, 0x37, 0xc6,
+ 0x70, 0xba, 0xb9, 0x93, 0x3a, 0x12, 0xfc, 0xcc, 0x18, 0xf8, 0x13, 0x3f,
+ 0x27, 0x4d, 0x49, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x39, 0x65, 0x9b, 0x25,
+ 0x32, 0x78, 0x2c, 0x6c, 0x57, 0x3c, 0x07, 0xf7, 0x27, 0xcc, 0x16, 0xf2,
+ 0xd6, 0xe1, 0x5e, 0x14, 0x75, 0x8a, 0x6f, 0xc7, 0x0f, 0x92, 0xd1, 0x0f,
+ 0x7e, 0x85, 0x7d, 0x1b, 0x55, 0xf1, 0xa4, 0x4b, 0xfc, 0xdb, 0x51, 0xbf,
+ 0xbf, 0x2a, 0xea, 0xdd, 0xe4, 0x6f, 0xe0, 0xf6, 0x2f, 0xab, 0x3d, 0xab,
+ 0xcb, 0x09, 0x89, 0x8c, 0x18, 0x5f, 0xa5, 0x0b, 0x4b, 0x1b, 0xf9, 0x66,
+ 0xfc, 0xea, 0x5b, 0xbb, 0xb6, 0x58, 0xdf, 0xba, 0xbe, 0x53, 0xd6, 0x8c,
+ 0xe1, 0xfd, 0x7e, 0xba, 0x97, 0x77, 0x6d, 0xee, 0x7a, 0xd5, 0xef, 0xd0,
+ 0xb4, 0xac, 0x35, 0x56, 0xb8, 0x70, 0xbd, 0x89, 0x7f, 0xf3, 0x49, 0x21,
+ 0x2f, 0xcf, 0xca, 0x38, 0xc3, 0x80, 0xec, 0x6d, 0x16, 0xa2, 0xe5, 0x6a,
+ 0xed, 0x67, 0x50, 0xd5, 0x7f, 0x30, 0x53, 0x7c, 0xa4, 0x75, 0x9f, 0x3a,
+ 0x57, 0x15, 0x71, 0xa7, 0xb4, 0x2b, 0x8f, 0x22, 0xa4, 0xf2, 0x24, 0x70,
+ 0xdf, 0x48, 0x18, 0x75, 0x5b, 0xb2, 0xd6, 0x12, 0x63, 0x50, 0xe7, 0x08,
+ 0x1b, 0x12, 0x75, 0xae, 0xf0, 0xfb, 0x35, 0xab, 0x05, 0xc5, 0x78, 0xf8,
+ 0x9f, 0xb4, 0x5d, 0x78, 0x5a, 0xd0, 0x98, 0x7c, 0xa7, 0xac, 0xd9, 0x5c,
+ 0x5c, 0x39, 0x23, 0xea, 0x24, 0x93, 0xaa, 0xf6, 0x33, 0x43, 0x5d, 0x42,
+ 0x6f, 0xfa, 0xf8, 0x35, 0x9b, 0xe7, 0xc2, 0xdb, 0xaf, 0xd9, 0x74, 0xdf,
+ 0xb3, 0xbd, 0x9a, 0x4d, 0x93, 0xd7, 0x6e, 0x2c, 0xc8, 0x9a, 0xcd, 0xfa,
+ 0x58, 0x80, 0xf4, 0x43, 0x65, 0x5c, 0xf2, 0x48, 0xea, 0x7f, 0x5f, 0x72,
+ 0xe5, 0x08, 0xcb, 0x7a, 0xcc, 0xc5, 0xaa, 0x0e, 0x24, 0xeb, 0x31, 0x65,
+ 0x4e, 0xb1, 0xbb, 0x0f, 0x89, 0x8c, 0x39, 0xc8, 0xf7, 0x74, 0x7b, 0x62,
+ 0x0e, 0x2d, 0x4c, 0xa3, 0xa3, 0xaa, 0xe6, 0xbc, 0x19, 0x6e, 0xd6, 0xd9,
+ 0x2a, 0x4c, 0x73, 0x15, 0xfa, 0x69, 0xfc, 0xd3, 0x74, 0x3f, 0x1c, 0x51,
+ 0xb9, 0x74, 0xc8, 0x9d, 0x3b, 0xa8, 0xe0, 0xa8, 0xf5, 0x0f, 0xf2, 0xd1,
+ 0x3f, 0x7e, 0x5b, 0xe4, 0x10, 0x4b, 0xfd, 0x65, 0x50, 0xd1, 0x24, 0xe8,
+ 0x36, 0xe2, 0xa2, 0xdb, 0x5d, 0x4d, 0xe8, 0x16, 0xf4, 0xf9, 0xdd, 0x1d,
+ 0xb2, 0x4f, 0x01, 0xe2, 0xde, 0xdf, 0x57, 0xbf, 0x37, 0xa3, 0xbf, 0xf7,
+ 0x78, 0x6f, 0x40, 0x83, 0x78, 0xc6, 0x87, 0xe1, 0x1a, 0x1d, 0xea, 0xdf,
+ 0x98, 0xcb, 0x7e, 0xd7, 0x5c, 0x86, 0x5d, 0x73, 0xd9, 0xd7, 0x64, 0x2e,
+ 0xac, 0x4f, 0x94, 0x2f, 0xf0, 0xff, 0x8f, 0x3b, 0x27, 0xe1, 0xab, 0x65,
+ 0x5a, 0x8d, 0x0b, 0xf9, 0x9a, 0x03, 0x1c, 0x85, 0x9e, 0x32, 0xaa, 0xea,
+ 0xe0, 0xdd, 0xf3, 0x6c, 0x66, 0xab, 0x41, 0x16, 0xa0, 0xd7, 0x41, 0x82,
+ 0xef, 0xeb, 0x6c, 0xd2, 0xeb, 0x00, 0x3a, 0x86, 0x5f, 0xaf, 0x03, 0x37,
+ 0x8f, 0x77, 0xeb, 0x52, 0xd0, 0x7d, 0x21, 0x03, 0xa1, 0xf3, 0xa2, 0x57,
+ 0xc1, 0x2f, 0xd1, 0x85, 0xaa, 0x8e, 0x79, 0x90, 0xd2, 0x4a, 0xc7, 0xbc,
+ 0xb0, 0xa4, 0xf7, 0x7c, 0xd8, 0xb3, 0xe7, 0x7e, 0x3a, 0xe7, 0x90, 0xca,
+ 0xf1, 0xd1, 0xb0, 0xca, 0xba, 0x60, 0x95, 0xf5, 0x81, 0x95, 0x78, 0x47,
+ 0x93, 0x79, 0x03, 0x3e, 0xb8, 0x07, 0xff, 0xbf, 0x13, 0x41, 0x8f, 0x16,
+ 0xa2, 0xdf, 0xd8, 0x55, 0xf3, 0x0b, 0xe8, 0xdf, 0x98, 0x63, 0xd3, 0xdc,
+ 0x4f, 0xa5, 0x0f, 0x0e, 0x06, 0x8e, 0x5c, 0x67, 0x03, 0x9d, 0x65, 0x5e,
+ 0xbd, 0x2d, 0xa8, 0x75, 0x85, 0x03, 0x82, 0xef, 0xdd, 0x0f, 0x22, 0x77,
+ 0x45, 0x9f, 0xeb, 0xd6, 0xbe, 0x5c, 0xb5, 0xfe, 0xd6, 0x3a, 0x7d, 0xa2,
+ 0xa6, 0x4b, 0xe8, 0x1c, 0x54, 0xfd, 0x5b, 0xcb, 0xc0, 0x7b, 0x75, 0xfe,
+ 0x89, 0x5b, 0x75, 0xfd, 0x06, 0xe1, 0x0b, 0xea, 0x4e, 0x1b, 0x4e, 0x4a,
+ 0xe4, 0x91, 0xf6, 0x3a, 0xf0, 0x7b, 0x25, 0x99, 0x37, 0xf7, 0xa6, 0x91,
+ 0xb3, 0xdc, 0x7b, 0xcd, 0xa2, 0x93, 0xf9, 0x2f, 0xed, 0x95, 0x74, 0x7a,
+ 0x89, 0x86, 0xc7, 0x79, 0xfc, 0x14, 0x7c, 0xbd, 0x76, 0x2c, 0xc9, 0x4a,
+ 0xe4, 0x5c, 0xb9, 0x8d, 0x16, 0x59, 0x5b, 0x0f, 0x3a, 0x25, 0xe1, 0xbb,
+ 0x63, 0x99, 0x51, 0x40, 0x6f, 0x55, 0x63, 0xa1, 0x95, 0x9f, 0xdb, 0x4f,
+ 0xcb, 0x45, 0xd0, 0x7c, 0x8b, 0xea, 0x11, 0x82, 0xb1, 0x01, 0xea, 0x73,
+ 0xfe, 0x84, 0xe1, 0xf5, 0x05, 0x91, 0x47, 0xb9, 0x58, 0xb8, 0x24, 0xff,
+ 0x96, 0x5e, 0x52, 0xef, 0xe0, 0xf7, 0x95, 0xff, 0x86, 0x12, 0x7d, 0x96,
+ 0xcb, 0x36, 0x73, 0xff, 0xf3, 0xd7, 0x3f, 0x8e, 0x6f, 0x4b, 0xff, 0xc8,
+ 0xa6, 0x6b, 0xfa, 0x87, 0xfb, 0xd9, 0x5a, 0x17, 0x39, 0xd6, 0x2f, 0xfb,
+ 0x37, 0x00, 0x06, 0x9d, 0xd0, 0xad, 0xd2, 0x80, 0xa5, 0x31, 0x65, 0x47,
+ 0x92, 0xc1, 0x49, 0x9a, 0x2d, 0x47, 0x8d, 0x4c, 0x01, 0x3a, 0x30, 0xff,
+ 0x2d, 0x5d, 0xd9, 0x2d, 0x7d, 0x2e, 0xfa, 0x1e, 0xf0, 0xf5, 0x9d, 0x3c,
+ 0xfe, 0x3f, 0xfa, 0x65, 0xee, 0xb5, 0xfb, 0x7c, 0x0f, 0x9f, 0x7f, 0x2e,
+ 0x52, 0x7f, 0xfe, 0x31, 0x3e, 0xdf, 0xc7, 0xe7, 0xe1, 0x87, 0x84, 0x9f,
+ 0x31, 0x46, 0x39, 0xde, 0x9f, 0xd9, 0x32, 0xf3, 0xa9, 0x57, 0x58, 0x5e,
+ 0x2c, 0xe9, 0x71, 0xbb, 0x50, 0x97, 0x23, 0xf6, 0xc4, 0xe0, 0x31, 0x97,
+ 0xf3, 0x63, 0x3c, 0x6e, 0x90, 0x82, 0xaf, 0x58, 0x34, 0xbb, 0xa4, 0x71,
+ 0x52, 0xe7, 0xd4, 0xbf, 0xc3, 0xf0, 0x45, 0xde, 0xce, 0x47, 0xbb, 0x25,
+ 0xfc, 0x62, 0xc2, 0x87, 0x89, 0x3c, 0x8e, 0x2b, 0x02, 0xf7, 0xec, 0x49,
+ 0xab, 0xfa, 0x7e, 0xe0, 0x96, 0x88, 0x73, 0xf0, 0x1a, 0x58, 0x2e, 0x4d,
+ 0x39, 0x66, 0xae, 0x9a, 0x8f, 0xf6, 0xe7, 0x03, 0xf2, 0xfe, 0xff, 0xda,
+ 0x25, 0xfb, 0xa3, 0xbe, 0x3f, 0xa0, 0xfb, 0x24, 0x4a, 0x9d, 0x00, 0x39,
+ 0xca, 0x01, 0x01, 0x9b, 0xe0, 0x02, 0xe4, 0x95, 0xc1, 0xbf, 0x79, 0x3d,
+ 0x69, 0xcc, 0xb1, 0xad, 0x5f, 0xf7, 0x7c, 0x91, 0xeb, 0x3a, 0xc6, 0xf3,
+ 0x4d, 0xf1, 0xba, 0xf4, 0xf9, 0x04, 0x1f, 0xfb, 0xed, 0x2f, 0x9e, 0xd5,
+ 0x91, 0x46, 0x5d, 0x70, 0xe6, 0x54, 0x47, 0x3a, 0x13, 0x93, 0xfb, 0x5c,
+ 0xf3, 0xd1, 0x46, 0xaa, 0x3e, 0xda, 0xb9, 0xfc, 0x78, 0x3f, 0xfc, 0x15,
+ 0xc6, 0x35, 0xde, 0xef, 0xf0, 0x15, 0x1e, 0x8b, 0x7a, 0x84, 0x1c, 0xff,
+ 0xed, 0x52, 0xf9, 0x3c, 0x8d, 0xb8, 0x22, 0xf3, 0x23, 0xb4, 0x5e, 0x81,
+ 0x7b, 0x9f, 0xe0, 0x67, 0x48, 0xdd, 0xa2, 0xf9, 0x7b, 0xa8, 0x21, 0xff,
+ 0xa5, 0x11, 0xc7, 0x36, 0xf2, 0xab, 0x8a, 0x38, 0xa2, 0x0f, 0x9e, 0x6d,
+ 0xd4, 0x83, 0xe0, 0x9e, 0xf0, 0x8b, 0x4d, 0x37, 0xd0, 0x2b, 0xe8, 0x38,
+ 0x44, 0x2f, 0xcc, 0x67, 0xe9, 0x31, 0xde, 0xab, 0x3f, 0x30, 0x3e, 0x83,
+ 0x38, 0x3b, 0xc9, 0x5c, 0x27, 0x86, 0x71, 0xde, 0x89, 0x9d, 0x33, 0x52,
+ 0xe0, 0x8b, 0x95, 0x90, 0xd3, 0x45, 0xad, 0x4c, 0xab, 0xbf, 0x49, 0x23,
+ 0x6c, 0xcf, 0x81, 0x66, 0x9d, 0x48, 0x8a, 0x40, 0x6f, 0xb6, 0x79, 0x84,
+ 0x71, 0x62, 0xba, 0x0c, 0x7c, 0x36, 0xe8, 0x8b, 0x45, 0xa2, 0xe7, 0x8b,
+ 0x23, 0xe6, 0xf7, 0xc8, 0xb1, 0x6a, 0xd7, 0x6d, 0x33, 0xc9, 0xf3, 0x48,
+ 0x95, 0x5f, 0xa2, 0xf7, 0x44, 0xdf, 0x12, 0xc0, 0x51, 0xef, 0xfb, 0x1f,
+ 0xd1, 0x99, 0x34, 0xe6, 0xbd, 0x75, 0xfa, 0x3c, 0xb9, 0x2d, 0xfa, 0xec,
+ 0xf0, 0xa1, 0xcf, 0x7f, 0x54, 0x78, 0x53, 0x61, 0x1c, 0xed, 0xa0, 0x99,
+ 0x02, 0x72, 0xbf, 0x3e, 0x8b, 0xfe, 0x52, 0x85, 0x0c, 0xf3, 0xa5, 0x4c,
+ 0x8d, 0x2f, 0x5d, 0x4d, 0x06, 0x13, 0xa0, 0x71, 0xf4, 0x65, 0x53, 0xf9,
+ 0x3e, 0x58, 0xc7, 0x00, 0x8d, 0x2c, 0x74, 0x22, 0xf6, 0xb5, 0x9a, 0x9c,
+ 0x48, 0xa8, 0xfa, 0x7c, 0xdb, 0x9a, 0x66, 0xfe, 0x38, 0xc7, 0xb4, 0x9c,
+ 0x2b, 0x1c, 0xa4, 0xc5, 0x70, 0x94, 0x86, 0x17, 0x74, 0xbf, 0x12, 0x11,
+ 0x37, 0x89, 0x4a, 0x9e, 0xa4, 0xd7, 0xfd, 0x84, 0xf0, 0x45, 0x58, 0x37,
+ 0x3f, 0xa9, 0x75, 0x77, 0x6e, 0xc2, 0x97, 0xde, 0x57, 0x34, 0x5b, 0xb9,
+ 0x95, 0x8c, 0x53, 0x36, 0x39, 0xf1, 0xef, 0x02, 0xff, 0x87, 0x6f, 0xc2,
+ 0xaf, 0x06, 0x1e, 0x6d, 0x51, 0x3a, 0xef, 0x85, 0x45, 0x94, 0xd7, 0x8d,
+ 0xeb, 0x95, 0x0f, 0x67, 0xe2, 0x2f, 0x09, 0xdd, 0x6b, 0xe4, 0x26, 0x8f,
+ 0x13, 0xf2, 0x48, 0xf3, 0x0d, 0x3f, 0x3c, 0xd4, 0x3d, 0x29, 0x35, 0x2e,
+ 0xca, 0x7c, 0x4e, 0x93, 0x9f, 0x9b, 0x0e, 0x7a, 0x71, 0xf2, 0x5e, 0xe0,
+ 0xf8, 0xbc, 0x45, 0x27, 0xf2, 0xf6, 0xab, 0x59, 0x9a, 0x64, 0xba, 0x76,
+ 0xcb, 0x0b, 0x1e, 0x4f, 0xc0, 0xb3, 0x29, 0xd0, 0x3e, 0x65, 0x0a, 0x96,
+ 0xcc, 0xb7, 0x13, 0x3d, 0xe5, 0x70, 0x8c, 0xda, 0xe2, 0xee, 0xdd, 0x5a,
+ 0x1e, 0x64, 0x0a, 0xa8, 0x15, 0xe4, 0xbf, 0x25, 0x1e, 0x8f, 0xfc, 0xfe,
+ 0x22, 0x9e, 0x03, 0x19, 0x87, 0xb9, 0xf3, 0xf1, 0xb2, 0xdc, 0xd7, 0x61,
+ 0x7e, 0xf6, 0xc8, 0x38, 0xbf, 0xb3, 0x3c, 0xc6, 0xfb, 0xdb, 0x23, 0x78,
+ 0xb3, 0xdc, 0xcf, 0x29, 0xba, 0xec, 0xcb, 0x57, 0xe4, 0xbe, 0x64, 0x5c,
+ 0xf4, 0x9d, 0x11, 0xf4, 0x3d, 0x25, 0xf6, 0x23, 0x53, 0x34, 0x58, 0x5f,
+ 0xd6, 0xbe, 0x04, 0xb6, 0x9b, 0x8b, 0x21, 0xc5, 0x43, 0x70, 0xed, 0x89,
+ 0xdd, 0x22, 0x1f, 0x11, 0xf6, 0x74, 0x11, 0x7f, 0xa7, 0xe8, 0x0a, 0xeb,
+ 0xfd, 0x2f, 0xe7, 0xdb, 0xe8, 0x4e, 0xa1, 0x8d, 0xee, 0x16, 0xa2, 0x74,
+ 0x7b, 0x7e, 0x07, 0x5d, 0x66, 0x9b, 0xe6, 0xb2, 0x13, 0xb2, 0x72, 0xb4,
+ 0x03, 0xf1, 0x42, 0xe4, 0x0a, 0x31, 0xdd, 0x61, 0x3c, 0xf4, 0xef, 0xe4,
+ 0x1e, 0xc6, 0x39, 0xb6, 0x8d, 0xda, 0xe9, 0x5d, 0x7e, 0x67, 0x2e, 0xaf,
+ 0x73, 0x1c, 0xe0, 0x63, 0xdf, 0x5f, 0xb5, 0x1f, 0x36, 0xc7, 0x11, 0x73,
+ 0x13, 0x1c, 0x99, 0x12, 0xbc, 0x7e, 0x76, 0x3e, 0x8a, 0xbe, 0xca, 0xd9,
+ 0x16, 0xf8, 0x49, 0x99, 0x3f, 0x3f, 0x17, 0xc2, 0x78, 0x9c, 0x73, 0x64,
+ 0x8e, 0xa4, 0x58, 0x5b, 0x84, 0x8f, 0x03, 0xa2, 0x0e, 0x5a, 0xc2, 0xa1,
+ 0x9d, 0xd7, 0x17, 0x10, 0xe3, 0x33, 0xcb, 0xed, 0x74, 0xb6, 0x68, 0xf2,
+ 0x71, 0x90, 0xf5, 0x44, 0x8c, 0xed, 0xdd, 0xa7, 0xfb, 0xcb, 0x5e, 0xe6,
+ 0xb9, 0xe7, 0xc4, 0x38, 0xfe, 0xbb, 0xdc, 0x43, 0xb3, 0xc5, 0x2e, 0x75,
+ 0x7c, 0x50, 0xe6, 0xf2, 0x8a, 0x5c, 0x6c, 0x5c, 0xdb, 0x88, 0xbf, 0xbd,
+ 0xcd, 0x38, 0x05, 0x99, 0x2a, 0x75, 0x7c, 0xf0, 0x9a, 0x5b, 0x0d, 0xfd,
+ 0x90, 0x81, 0x73, 0x93, 0xf4, 0x4d, 0x96, 0xb7, 0xc3, 0xaf, 0xc0, 0x1f,
+ 0xfc, 0xfb, 0xc0, 0x9b, 0x52, 0x96, 0x06, 0xf9, 0x18, 0x7d, 0x8e, 0x82,
+ 0xa2, 0x96, 0x69, 0x3a, 0x1c, 0x13, 0xf5, 0x1f, 0x92, 0x46, 0x4f, 0x89,
+ 0x9e, 0x73, 0x3f, 0x12, 0xbc, 0xc9, 0xce, 0x5a, 0x06, 0xf4, 0x11, 0xf8,
+ 0x54, 0x64, 0xee, 0xd5, 0x49, 0xa7, 0xf7, 0xed, 0x5d, 0x53, 0xa3, 0x94,
+ 0xe8, 0x07, 0xde, 0x4b, 0x9a, 0x55, 0x3d, 0x04, 0x04, 0xbf, 0x37, 0x0f,
+ 0xe8, 0x9a, 0x48, 0x7d, 0xac, 0x65, 0x85, 0x3e, 0xee, 0xf2, 0x5c, 0x37,
+ 0x3d, 0xd7, 0xab, 0x79, 0x72, 0x2c, 0xf3, 0x58, 0xce, 0x93, 0xec, 0x39,
+ 0x84, 0xbe, 0x71, 0xc0, 0x3f, 0xf3, 0xc0, 0x7e, 0xf3, 0x73, 0xca, 0x06,
+ 0xca, 0xac, 0x8c, 0x44, 0x7a, 0x8d, 0x98, 0x91, 0x19, 0xfb, 0x97, 0x4a,
+ 0x22, 0x0d, 0xbd, 0xe8, 0xc6, 0x6e, 0xc9, 0xe3, 0x30, 0xaf, 0x6c, 0x1c,
+ 0xaa, 0xdb, 0xa9, 0x95, 0x2e, 0x5a, 0x15, 0x7d, 0xb5, 0xa0, 0x63, 0xe0,
+ 0x7e, 0x3c, 0x27, 0x6b, 0xb6, 0xb0, 0x7d, 0x77, 0xc3, 0x01, 0x8d, 0x1f,
+ 0x8a, 0xdc, 0xe4, 0xfd, 0x4c, 0xad, 0x7c, 0x54, 0x39, 0x23, 0xfa, 0xd2,
+ 0x60, 0x6c, 0x0f, 0xcd, 0x08, 0x9b, 0x8b, 0xf5, 0x97, 0x3a, 0xbb, 0x76,
+ 0x12, 0xf3, 0xcc, 0x22, 0x56, 0x62, 0x38, 0xdf, 0x0e, 0x64, 0x4a, 0x32,
+ 0xf6, 0x9d, 0xf2, 0xc4, 0xbe, 0x4f, 0x89, 0xd8, 0x37, 0xe2, 0xde, 0x80,
+ 0x2b, 0x60, 0xe9, 0x97, 0xcb, 0x82, 0x7d, 0x8c, 0xf3, 0x3e, 0x5a, 0x34,
+ 0x77, 0x5d, 0xf0, 0x9b, 0xc9, 0xe9, 0x60, 0xa2, 0xb7, 0x85, 0xac, 0x40,
+ 0xd2, 0xb1, 0xe3, 0x0f, 0x58, 0x87, 0xb8, 0x5d, 0xc0, 0x3c, 0x5f, 0xa2,
+ 0xf5, 0x52, 0x0b, 0xd3, 0x89, 0xcd, 0x78, 0xb7, 0xca, 0x3a, 0xed, 0x2c,
+ 0xbd, 0x5b, 0x22, 0xba, 0x5d, 0xbc, 0x8a, 0x5e, 0xbb, 0xb1, 0x07, 0x4c,
+ 0x2b, 0x88, 0x05, 0x67, 0x62, 0xf0, 0xb1, 0xb1, 0x5e, 0x1b, 0x6b, 0x55,
+ 0xb8, 0xd9, 0xc5, 0xb6, 0xa3, 0xc9, 0xff, 0x1d, 0xfe, 0x1f, 0x89, 0x00,
+ 0x2e, 0x6b, 0xc5, 0x31, 0xc1, 0x4b, 0x97, 0xf8, 0xfc, 0x12, 0x9f, 0x87,
+ 0x4c, 0x5d, 0x2b, 0x56, 0xde, 0x49, 0xc6, 0x13, 0x56, 0x72, 0xe2, 0xa4,
+ 0x1c, 0xc3, 0x38, 0x77, 0xf9, 0x7a, 0x62, 0x4f, 0x88, 0xe7, 0x31, 0xc3,
+ 0xf3, 0x58, 0x27, 0x99, 0xeb, 0x9d, 0x12, 0xef, 0x26, 0xba, 0x23, 0xde,
+ 0xcb, 0x3a, 0x53, 0xfc, 0x71, 0x3a, 0x13, 0x96, 0xef, 0xcf, 0xc5, 0x51,
+ 0x73, 0xd5, 0x49, 0xb3, 0x63, 0xa3, 0xaa, 0xe6, 0xea, 0xcd, 0x26, 0x35,
+ 0x57, 0xed, 0xb4, 0x36, 0x0f, 0xbb, 0xb7, 0x9d, 0xe9, 0xdd, 0x14, 0xb9,
+ 0x7a, 0x6b, 0xf3, 0xa2, 0x1f, 0x3e, 0xaf, 0xa7, 0xb2, 0x3e, 0xc3, 0xaa,
+ 0x79, 0x26, 0xde, 0x2d, 0x74, 0xa7, 0xdb, 0xcb, 0xbf, 0xc5, 0xf3, 0x49,
+ 0x58, 0x99, 0x09, 0xf7, 0x3a, 0xc4, 0x7c, 0xd7, 0xa7, 0xc5, 0xb8, 0xa0,
+ 0x67, 0x5c, 0x82, 0x32, 0x13, 0x98, 0xbf, 0x18, 0xf3, 0x3f, 0xc9, 0xb8,
+ 0x5e, 0x8f, 0xfb, 0x7e, 0x8b, 0x72, 0x42, 0xdf, 0xe7, 0xbf, 0x4b, 0x3d,
+ 0x81, 0xf5, 0x02, 0xfc, 0x26, 0x06, 0xe3, 0x3f, 0xe6, 0x66, 0x51, 0x76,
+ 0x89, 0xd7, 0x75, 0xbd, 0x2b, 0xf0, 0xa0, 0xf0, 0x93, 0x4a, 0xa6, 0x2e,
+ 0xb7, 0xa5, 0xde, 0xbf, 0x2e, 0x6d, 0xae, 0x28, 0x39, 0xd7, 0x20, 0x4b,
+ 0x21, 0x47, 0xb3, 0x95, 0xa0, 0x03, 0xbd, 0x0f, 0xb6, 0xd0, 0x25, 0xe6,
+ 0x63, 0x32, 0x3f, 0x89, 0x79, 0x2a, 0xf3, 0x32, 0x49, 0x47, 0xa9, 0xba,
+ 0xcf, 0x32, 0x48, 0x5c, 0x1e, 0xae, 0xe5, 0x45, 0xba, 0xe2, 0xe6, 0x21,
+ 0x57, 0xdc, 0xdc, 0x74, 0xe5, 0x45, 0x86, 0x85, 0x9e, 0x56, 0xd3, 0xad,
+ 0xc2, 0x4a, 0xb7, 0x8a, 0x8a, 0x9e, 0xf4, 0xe0, 0x71, 0x8b, 0x55, 0x1e,
+ 0xb7, 0x73, 0x13, 0x1e, 0xe7, 0x67, 0x9b, 0xae, 0x2a, 0x7e, 0x62, 0xc7,
+ 0x21, 0x6b, 0x6e, 0x31, 0xdf, 0xf8, 0x71, 0x79, 0x82, 0xf9, 0x49, 0x9c,
+ 0xf9, 0xc9, 0x18, 0xf3, 0x93, 0x18, 0xf3, 0x13, 0x87, 0x61, 0x60, 0xf1,
+ 0xda, 0xef, 0x05, 0x6e, 0xcf, 0x43, 0x8e, 0x4c, 0xd2, 0x95, 0x32, 0x78,
+ 0xf3, 0x18, 0xeb, 0x42, 0xf7, 0x02, 0x6b, 0xf3, 0x3d, 0x8c, 0xc7, 0x52,
+ 0xff, 0xa9, 0xb7, 0x6f, 0xec, 0x57, 0x51, 0x1f, 0x97, 0x8c, 0xaf, 0x81,
+ 0xff, 0xbc, 0x99, 0xa5, 0xee, 0xc0, 0xed, 0x42, 0x57, 0x60, 0xad, 0xf0,
+ 0x13, 0xf4, 0xa5, 0x78, 0x1d, 0x34, 0x8e, 0xbe, 0xbf, 0x3f, 0x1c, 0x9d,
+ 0xe4, 0xb9, 0x77, 0x07, 0x66, 0x79, 0x5f, 0xbe, 0x12, 0x4f, 0xf4, 0xf6,
+ 0x49, 0x5a, 0xc8, 0xe6, 0xc0, 0x3d, 0x17, 0x76, 0xd0, 0xfe, 0xf1, 0xe4,
+ 0x9e, 0x5e, 0xa6, 0x5b, 0xe0, 0x7b, 0xad, 0xef, 0x4e, 0x90, 0xf1, 0xb0,
+ 0x43, 0xf5, 0xeb, 0xb1, 0x58, 0x5e, 0x7e, 0xc8, 0xf7, 0x7f, 0x10, 0xc8,
+ 0x15, 0x5e, 0xe3, 0x67, 0xe3, 0xf8, 0x4f, 0xe1, 0xdf, 0x64, 0x7b, 0x01,
+ 0xbd, 0x7e, 0x3a, 0x79, 0x0c, 0xc6, 0xe2, 0xd8, 0x8e, 0x31, 0x6f, 0x8b,
+ 0xaf, 0x1a, 0xf6, 0x64, 0xc2, 0x78, 0x3e, 0x8a, 0x9e, 0xf1, 0x3f, 0x2c,
+ 0x3f, 0x15, 0x95, 0x31, 0xb6, 0xe7, 0xf6, 0x48, 0x3e, 0xc2, 0xb8, 0x19,
+ 0x4e, 0x08, 0x9b, 0xad, 0xe5, 0x9a, 0x94, 0x9b, 0x8b, 0xbc, 0xbf, 0x4b,
+ 0xf1, 0x18, 0xef, 0x6f, 0x97, 0x92, 0x99, 0x59, 0xbe, 0x2e, 0xe4, 0x31,
+ 0xcb, 0x4e, 0x86, 0x77, 0x91, 0x4c, 0xd1, 0x03, 0xe2, 0x14, 0xfa, 0xea,
+ 0x3c, 0x83, 0xe7, 0x31, 0xb6, 0x82, 0x6f, 0x7c, 0x18, 0xc8, 0x14, 0xf0,
+ 0x5e, 0xe0, 0x1f, 0xff, 0x2e, 0x4d, 0xd2, 0xd5, 0xbc, 0x9e, 0xc3, 0x80,
+ 0x61, 0x7c, 0x13, 0xf3, 0x08, 0xd0, 0x4e, 0xe7, 0xdf, 0x18, 0x4e, 0x7c,
+ 0xfc, 0x97, 0xde, 0x39, 0x9d, 0x57, 0x73, 0x42, 0x9f, 0xca, 0x36, 0x5e,
+ 0xc3, 0x4e, 0x42, 0xff, 0xa2, 0x45, 0xd1, 0x47, 0xb2, 0x55, 0xd8, 0xaa,
+ 0x8b, 0xc2, 0xe6, 0x38, 0xba, 0xa7, 0xd6, 0xdb, 0xf2, 0x71, 0xcf, 0xb9,
+ 0x9f, 0x07, 0x72, 0xf3, 0x87, 0x85, 0x6e, 0x36, 0x3c, 0xbe, 0x47, 0xd5,
+ 0x9c, 0x7e, 0x5e, 0x5c, 0x33, 0x16, 0x70, 0xed, 0x49, 0x75, 0xed, 0xd7,
+ 0x84, 0x4e, 0x8c, 0xfc, 0xb8, 0xd0, 0x35, 0x81, 0xdf, 0xbc, 0xaf, 0x4e,
+ 0x8c, 0xf1, 0x3b, 0xb2, 0x04, 0xdf, 0xbc, 0x80, 0xa7, 0x86, 0x07, 0x60,
+ 0x01, 0x9c, 0xef, 0x52, 0xf8, 0x6e, 0x5b, 0xa9, 0xa0, 0x5e, 0x77, 0x33,
+ 0x38, 0xb3, 0x8e, 0x93, 0xc7, 0x5a, 0xb1, 0xa6, 0xdd, 0x81, 0x44, 0xc9,
+ 0x32, 0x72, 0xf3, 0xb0, 0x71, 0xe0, 0x7f, 0xdc, 0x8b, 0xbc, 0x28, 0x9e,
+ 0xc3, 0x6e, 0x4a, 0xa4, 0x31, 0x2f, 0x8c, 0xd3, 0x30, 0x18, 0xf7, 0xc0,
+ 0xc2, 0x7d, 0xdf, 0x0e, 0x75, 0x5f, 0xbb, 0xd8, 0x0b, 0x32, 0xf0, 0x1e,
+ 0xfd, 0x6e, 0xbc, 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x2e,
+ 0xe6, 0xd7, 0xc9, 0x09, 0xf9, 0x2c, 0xe3, 0xa6, 0xbc, 0xb6, 0xcb, 0xf1,
+ 0x9f, 0xaf, 0xdc, 0x3f, 0xdc, 0xab, 0xf7, 0x6f, 0x07, 0x95, 0x84, 0x5f,
+ 0x09, 0xd7, 0xba, 0xc5, 0xb5, 0xa4, 0xd3, 0x2d, 0xf6, 0x75, 0x8e, 0x8f,
+ 0xcf, 0x16, 0x7a, 0x02, 0xb0, 0xd5, 0x73, 0xe9, 0xee, 0x40, 0xa9, 0x84,
+ 0xf5, 0x76, 0x07, 0x52, 0x8c, 0xf3, 0xd3, 0x85, 0x23, 0x95, 0x59, 0xc1,
+ 0x5b, 0x58, 0xc7, 0xed, 0xb3, 0xcd, 0x33, 0xc6, 0xcf, 0xc4, 0x9a, 0xf8,
+ 0x7d, 0xfc, 0x9b, 0xe9, 0x2e, 0xcf, 0x74, 0x97, 0x67, 0xba, 0xcb, 0x33,
+ 0xdd, 0xb1, 0x8d, 0xfa, 0x83, 0x3c, 0xd3, 0x1d, 0xcb, 0x90, 0xb7, 0x58,
+ 0x86, 0x48, 0x5a, 0x4d, 0x28, 0xdf, 0x9e, 0xa6, 0x55, 0x6f, 0x4d, 0xa6,
+ 0xa6, 0x4d, 0xc8, 0x6d, 0x0a, 0x1c, 0x1d, 0xad, 0xa7, 0xd1, 0x3b, 0x4c,
+ 0xa3, 0x2d, 0x53, 0xfd, 0xf4, 0xa0, 0x88, 0x3d, 0xb3, 0xad, 0x39, 0xe6,
+ 0xd1, 0xa9, 0x20, 0x74, 0xac, 0x10, 0xd3, 0x13, 0x74, 0x4c, 0x9b, 0xe1,
+ 0xde, 0x4f, 0xeb, 0xc5, 0x76, 0x1e, 0x03, 0x9a, 0xdd, 0xab, 0x8e, 0xf3,
+ 0x4c, 0xb3, 0x90, 0x7b, 0xd7, 0x02, 0x77, 0x0a, 0x06, 0xeb, 0x62, 0x21,
+ 0x33, 0x43, 0xe0, 0x9f, 0x42, 0x3f, 0xe3, 0x7d, 0x5f, 0x65, 0x7e, 0x0f,
+ 0xdf, 0x29, 0x7a, 0x77, 0x95, 0x20, 0x3b, 0x22, 0xb7, 0x99, 0x7f, 0x5e,
+ 0x28, 0x5e, 0x63, 0x3a, 0xef, 0xa3, 0x2f, 0x17, 0x21, 0x9f, 0x01, 0x23,
+ 0x3e, 0x2e, 0x91, 0xf0, 0x7d, 0x19, 0x53, 0x58, 0xfb, 0xfe, 0xac, 0x21,
+ 0xf0, 0xe4, 0xaf, 0x01, 0x07, 0x86, 0xfd, 0xdd, 0x3d, 0xe8, 0x69, 0x9f,
+ 0x30, 0x5a, 0x95, 0x8f, 0x17, 0xbf, 0x31, 0x1e, 0x63, 0x01, 0x37, 0x1c,
+ 0x37, 0x8b, 0x2f, 0xe2, 0x1b, 0x11, 0x71, 0x86, 0x87, 0x97, 0x5f, 0x5d,
+ 0xe5, 0xfb, 0x05, 0xbc, 0x26, 0x93, 0x41, 0xd4, 0x87, 0xd3, 0xd7, 0x82,
+ 0x53, 0x93, 0xf4, 0x72, 0x19, 0xf3, 0xbe, 0x42, 0xb3, 0x61, 0xf0, 0x1f,
+ 0x3b, 0x7e, 0x9f, 0x24, 0xec, 0xda, 0x59, 0xdf, 0xfc, 0xa2, 0x3f, 0x4f,
+ 0xb3, 0x92, 0x42, 0x3f, 0x6e, 0x63, 0x7b, 0x07, 0xb0, 0x79, 0x83, 0x71,
+ 0x2d, 0x0e, 0x1f, 0x80, 0xe2, 0x67, 0xdf, 0x67, 0x9e, 0x83, 0x3d, 0xc3,
+ 0x71, 0x3d, 0x0f, 0x5b, 0x53, 0x3c, 0xcc, 0x71, 0xf1, 0xb0, 0x5c, 0x95,
+ 0x87, 0x31, 0x2e, 0x08, 0xde, 0x05, 0xde, 0x74, 0x82, 0xf5, 0x45, 0xf9,
+ 0x1b, 0x7a, 0xe0, 0x4e, 0xc1, 0xab, 0x98, 0xb7, 0xb3, 0xfd, 0xb0, 0x58,
+ 0xce, 0x06, 0x8e, 0x08, 0x9e, 0xa1, 0xf1, 0xf9, 0xa9, 0x01, 0x49, 0x07,
+ 0xed, 0xd2, 0x1f, 0x79, 0x0a, 0x7c, 0xca, 0x6f, 0xfc, 0x67, 0x78, 0x1c,
+ 0xc6, 0x3b, 0x91, 0xd7, 0x99, 0x7f, 0x2d, 0xc6, 0x63, 0x22, 0x06, 0x22,
+ 0x6d, 0x9c, 0x2c, 0xdb, 0x01, 0xbb, 0x90, 0x6b, 0x69, 0x25, 0xab, 0xfc,
+ 0x4b, 0xd7, 0x1f, 0xc1, 0xaf, 0x88, 0x3d, 0x4e, 0xf4, 0x1a, 0x72, 0x1d,
+ 0x16, 0xd6, 0x31, 0x5b, 0xa4, 0xd0, 0x4c, 0x1c, 0xb9, 0x71, 0xe0, 0xeb,
+ 0x1f, 0xf0, 0xba, 0xb1, 0xaf, 0x1f, 0x60, 0x5f, 0xe5, 0xb5, 0x89, 0x63,
+ 0x62, 0x5e, 0xb3, 0xcb, 0x35, 0xfe, 0x37, 0x97, 0x1f, 0x30, 0x16, 0x0b,
+ 0x72, 0x6e, 0x4b, 0xa3, 0x92, 0xc7, 0x2d, 0x96, 0xd0, 0xab, 0x4b, 0xcc,
+ 0x91, 0xe7, 0xa6, 0xd7, 0x85, 0xf7, 0x6a, 0x7a, 0xdf, 0x0a, 0x6d, 0x3d,
+ 0xc3, 0x74, 0x84, 0x3d, 0xc8, 0xba, 0x70, 0xe4, 0x5b, 0xfc, 0x7e, 0x9c,
+ 0x6b, 0x9c, 0xff, 0x83, 0xea, 0xfc, 0x9f, 0xe4, 0xf9, 0x63, 0xcc, 0x07,
+ 0x2c, 0xef, 0xe5, 0xfc, 0x1f, 0x54, 0xe7, 0x5f, 0x54, 0xf3, 0xa7, 0x9c,
+ 0x31, 0xd5, 0xab, 0xf4, 0xf7, 0xa6, 0xcf, 0x6a, 0x9f, 0x99, 0x10, 0x63,
+ 0xcd, 0x19, 0xe8, 0x44, 0xa6, 0x9e, 0x8b, 0xb6, 0x0d, 0xdd, 0x73, 0xb1,
+ 0x63, 0xf7, 0xe9, 0x8f, 0x49, 0xea, 0x1d, 0x43, 0xac, 0x77, 0xe0, 0x3c,
+ 0xcd, 0x82, 0xcf, 0xe6, 0xc2, 0xe8, 0x11, 0x3b, 0xc8, 0x30, 0x62, 0x3b,
+ 0x6a, 0x82, 0xff, 0x0a, 0xbf, 0x18, 0x9e, 0xa3, 0xef, 0xff, 0x43, 0x5a,
+ 0x9f, 0x07, 0x2f, 0x86, 0xfe, 0x29, 0xfb, 0xc8, 0xae, 0xaf, 0x48, 0xff,
+ 0x6b, 0xca, 0xd7, 0xff, 0x0a, 0xdf, 0xeb, 0x04, 0xf4, 0x73, 0x13, 0x7e,
+ 0xda, 0x69, 0xf5, 0xed, 0x8f, 0x5c, 0x19, 0xcf, 0xf2, 0xe3, 0x2b, 0x93,
+ 0xae, 0x1c, 0x35, 0xe4, 0x8c, 0x64, 0x99, 0x4f, 0x38, 0x66, 0x8b, 0x21,
+ 0x6b, 0x64, 0x6e, 0x95, 0xb5, 0xae, 0x73, 0x8c, 0xf7, 0xc4, 0x89, 0x1b,
+ 0x46, 0x4a, 0xf8, 0x08, 0xda, 0x9d, 0x2e, 0x6a, 0x63, 0x39, 0x78, 0x8e,
+ 0xd0, 0xe7, 0xcc, 0xb6, 0x10, 0x3b, 0xb9, 0xca, 0x38, 0x36, 0x1b, 0xb7,
+ 0x23, 0xcf, 0x0b, 0x7b, 0x12, 0xf2, 0x01, 0xdf, 0x4e, 0x01, 0xac, 0x30,
+ 0x07, 0xfe, 0xbd, 0x8c, 0x9e, 0x95, 0x71, 0x5e, 0x3f, 0x7c, 0xbd, 0x23,
+ 0xd6, 0x5d, 0x96, 0x2b, 0x57, 0x85, 0x3f, 0xe5, 0x12, 0xeb, 0x92, 0xb6,
+ 0x79, 0x54, 0xd0, 0x99, 0x31, 0xc4, 0x54, 0xc1, 0x74, 0x82, 0x1c, 0x81,
+ 0xfd, 0xa2, 0xa7, 0x8e, 0xb4, 0x51, 0x78, 0x95, 0x2b, 0xaa, 0x57, 0x41,
+ 0x1a, 0xb4, 0xbf, 0x75, 0x5f, 0x42, 0xfa, 0xa1, 0x7d, 0x28, 0x6e, 0x1d,
+ 0xca, 0xeb, 0xa7, 0x86, 0x3d, 0x66, 0x89, 0xde, 0x8c, 0x80, 0x9d, 0xf0,
+ 0x03, 0x1a, 0x63, 0x0c, 0x37, 0xfd, 0x9d, 0x1a, 0xb7, 0xbd, 0x7f, 0x5e,
+ 0xd4, 0xdc, 0xbf, 0x59, 0x96, 0x32, 0x34, 0xc7, 0xb6, 0xf8, 0xec, 0xb8,
+ 0x5b, 0xa7, 0xb0, 0x0b, 0xd3, 0xc2, 0x07, 0x33, 0x40, 0xc9, 0x85, 0x31,
+ 0xfa, 0x7c, 0x1e, 0x3c, 0x88, 0xee, 0x27, 0x1d, 0xf1, 0xcd, 0x25, 0x9e,
+ 0xd3, 0x18, 0xa5, 0xca, 0x80, 0x51, 0x80, 0x66, 0x99, 0xcb, 0xe7, 0x0a,
+ 0x88, 0xbd, 0xf3, 0xef, 0x12, 0xbe, 0xa9, 0xf2, 0x3b, 0xca, 0xb7, 0x1d,
+ 0xa5, 0xe9, 0x05, 0xca, 0x66, 0xe2, 0x4f, 0x8b, 0x3e, 0xd3, 0x99, 0xf8,
+ 0xa8, 0xf2, 0xc9, 0x44, 0xf8, 0x3c, 0xfc, 0x5c, 0x16, 0x7d, 0x2e, 0x6f,
+ 0x67, 0x33, 0x24, 0x7d, 0x0d, 0xc4, 0x73, 0x30, 0x58, 0x76, 0xee, 0x64,
+ 0x9e, 0x70, 0x52, 0xf8, 0x1b, 0x58, 0xd3, 0x98, 0xc7, 0x78, 0xf8, 0x0a,
+ 0xfa, 0x08, 0xf6, 0x55, 0xa6, 0xf0, 0x92, 0x1a, 0x5b, 0x21, 0x93, 0x71,
+ 0xc1, 0xfc, 0x55, 0x27, 0x1b, 0x37, 0x6a, 0xf7, 0xc3, 0x57, 0x71, 0x52,
+ 0xe8, 0x7d, 0x43, 0xb4, 0x24, 0x68, 0xbd, 0x52, 0x99, 0x11, 0x7e, 0x07,
+ 0x3e, 0x2e, 0x4d, 0x0e, 0x4a, 0x5e, 0x25, 0xcf, 0x4b, 0x7f, 0x04, 0x3f,
+ 0xb3, 0xc4, 0xf3, 0xa8, 0xcb, 0x7f, 0x8f, 0x52, 0x62, 0x1b, 0xfe, 0xa1,
+ 0x53, 0x8f, 0xd4, 0x3f, 0xc4, 0xb0, 0x66, 0xd9, 0x71, 0x8b, 0x69, 0xe3,
+ 0xc7, 0x9b, 0xda, 0x6d, 0xef, 0x69, 0x19, 0xcc, 0xb0, 0x32, 0xc5, 0xb7,
+ 0x2b, 0xa0, 0x33, 0xcf, 0x96, 0xe7, 0xf0, 0x1d, 0x99, 0x40, 0x5a, 0xe8,
+ 0xb2, 0x11, 0xd6, 0x4d, 0xa0, 0xa3, 0x8c, 0x88, 0x78, 0x62, 0xe2, 0x59,
+ 0xcb, 0x98, 0x5d, 0xc1, 0xb7, 0xa1, 0xa0, 0x9b, 0xe9, 0x9c, 0x86, 0x76,
+ 0x91, 0xa7, 0x2e, 0xe3, 0xbc, 0x90, 0xaf, 0xe0, 0x79, 0x3f, 0x0f, 0x64,
+ 0x56, 0x9e, 0xde, 0xa5, 0xf3, 0xd5, 0x12, 0x61, 0x9d, 0x0f, 0xa3, 0x79,
+ 0x8a, 0xc6, 0x3d, 0x1d, 0xa3, 0x70, 0x7f, 0xcb, 0x0b, 0xb4, 0xeb, 0xd6,
+ 0x09, 0xe0, 0x57, 0x12, 0x7b, 0x74, 0x15, 0xb1, 0x31, 0xa3, 0x2e, 0xfe,
+ 0xd0, 0xc6, 0xfb, 0x64, 0x31, 0x6e, 0xc0, 0x5f, 0xf7, 0x05, 0xfe, 0x8b,
+ 0x38, 0x42, 0x69, 0x10, 0x7a, 0x50, 0xaf, 0xc3, 0x38, 0x33, 0x81, 0xe3,
+ 0x7e, 0x5a, 0x2c, 0x6a, 0xbd, 0x55, 0xfa, 0x90, 0x16, 0x97, 0xf5, 0x7e,
+ 0xc1, 0x7f, 0x34, 0xac, 0x7a, 0x08, 0xd8, 0x64, 0xf5, 0x01, 0x4e, 0x9f,
+ 0x14, 0x3d, 0x6e, 0x16, 0x73, 0xd8, 0x4a, 0xce, 0x11, 0xbe, 0x2f, 0x86,
+ 0x9e, 0x99, 0xfb, 0x00, 0x7b, 0xde, 0x23, 0x77, 0x4c, 0x62, 0x4e, 0x7d,
+ 0xff, 0xe7, 0x51, 0xed, 0xdb, 0x63, 0x3e, 0xfb, 0xf6, 0xd1, 0xa0, 0x8c,
+ 0x73, 0x3d, 0xa7, 0xc6, 0xf8, 0xe5, 0x99, 0xfe, 0xf3, 0x0b, 0xf0, 0x1f,
+ 0xd5, 0xea, 0x25, 0xee, 0x09, 0xbe, 0xd2, 0xe8, 0xc3, 0x8e, 0x30, 0x3f,
+ 0x95, 0x74, 0x7c, 0xd2, 0x87, 0x8e, 0xfb, 0x78, 0x8f, 0x4f, 0x3c, 0x04,
+ 0x1d, 0x9f, 0x68, 0x4a, 0xc7, 0x87, 0xa2, 0xd2, 0x87, 0xda, 0x48, 0xc7,
+ 0xa8, 0xd9, 0x39, 0x59, 0x6e, 0xe6, 0xaf, 0xc2, 0x3e, 0xa0, 0xf6, 0x1c,
+ 0xfe, 0x04, 0xc0, 0x4a, 0xfb, 0x14, 0x10, 0xdb, 0x03, 0x3e, 0x22, 0x56,
+ 0xf2, 0x17, 0x94, 0x9a, 0xf7, 0xc6, 0x38, 0x37, 0xba, 0xe7, 0x7d, 0x9f,
+ 0x7b, 0xa0, 0x6b, 0x83, 0x16, 0xec, 0x88, 0xb4, 0xd5, 0x35, 0xbc, 0xde,
+ 0x0d, 0x1c, 0x29, 0xda, 0xd9, 0x12, 0x18, 0x63, 0x4f, 0x98, 0xce, 0x23,
+ 0x8e, 0xaf, 0x7c, 0xbe, 0xc7, 0xf3, 0x72, 0xdd, 0xe6, 0xb8, 0xc0, 0x07,
+ 0xe8, 0xa3, 0x91, 0x74, 0x30, 0xcd, 0x7b, 0x2a, 0xfd, 0xbd, 0x99, 0xe5,
+ 0x88, 0xda, 0x27, 0x1e, 0x8b, 0xe7, 0xf9, 0xd6, 0xf3, 0x61, 0x7f, 0xec,
+ 0x57, 0x57, 0xab, 0x79, 0xc1, 0x90, 0x05, 0x15, 0xfa, 0x05, 0xcb, 0xb9,
+ 0xe0, 0xb8, 0x29, 0xfa, 0x28, 0xdc, 0x2a, 0x8f, 0xb3, 0x7e, 0x88, 0x3d,
+ 0x84, 0xaf, 0x50, 0xfb, 0x72, 0x7f, 0x31, 0x44, 0x3d, 0x87, 0x58, 0xea,
+ 0x1b, 0xe4, 0xb0, 0x7e, 0x68, 0x8c, 0x23, 0xbf, 0xdb, 0xe2, 0x7b, 0xd0,
+ 0xff, 0x69, 0xbf, 0x95, 0xa2, 0x2e, 0xf8, 0x09, 0xd0, 0xa7, 0xd9, 0xca,
+ 0xd5, 0xd1, 0xd4, 0x69, 0x41, 0x53, 0xa9, 0x95, 0xd3, 0x8a, 0xa6, 0x4e,
+ 0x2b, 0x7f, 0xf9, 0x69, 0x45, 0x53, 0xa7, 0x15, 0x4d, 0x9d, 0x56, 0x34,
+ 0x75, 0x9a, 0xf1, 0x7a, 0xc4, 0xec, 0x13, 0x3a, 0xbb, 0xf6, 0x57, 0xf6,
+ 0x50, 0xa6, 0x88, 0xf3, 0x90, 0xc7, 0x5e, 0xba, 0x7a, 0x75, 0x48, 0xd2,
+ 0xd5, 0x24, 0x2d, 0xca, 0x3c, 0x39, 0x7e, 0x17, 0xf6, 0xe0, 0xeb, 0x83,
+ 0xd4, 0x73, 0x2f, 0x70, 0x76, 0x1e, 0x73, 0x0d, 0xd0, 0xb4, 0xe8, 0xe1,
+ 0xda, 0x42, 0x49, 0xb7, 0x2e, 0x6b, 0xa2, 0x7e, 0x4b, 0xda, 0x6a, 0xd9,
+ 0xa6, 0xb5, 0x5c, 0x1a, 0x2f, 0xa6, 0xd4, 0x7e, 0x79, 0xed, 0x98, 0x36,
+ 0x4a, 0x17, 0x00, 0x57, 0xe4, 0x32, 0x5a, 0xbc, 0x37, 0x02, 0x4e, 0x59,
+ 0xd3, 0x07, 0x06, 0xc7, 0x15, 0x0c, 0xbe, 0x22, 0xd6, 0x88, 0x5c, 0x40,
+ 0xf8, 0x1c, 0x9b, 0xc3, 0x21, 0x97, 0x1f, 0xe1, 0xe7, 0x30, 0xee, 0x8f,
+ 0x47, 0x98, 0x07, 0x6d, 0x1d, 0x0e, 0xb5, 0xb5, 0x37, 0xe3, 0x35, 0x5b,
+ 0xad, 0x87, 0xb9, 0xef, 0x92, 0x1d, 0x11, 0x25, 0x37, 0xa4, 0x9e, 0xfb,
+ 0x98, 0x63, 0xa7, 0xb3, 0x3c, 0xb7, 0xbf, 0x8f, 0xb7, 0xef, 0xa5, 0x8e,
+ 0x0a, 0x1d, 0x8b, 0x03, 0x9f, 0x7b, 0xd8, 0x6e, 0xe4, 0x39, 0xec, 0xaf,
+ 0xd0, 0xd5, 0xf8, 0x01, 0xb6, 0x4d, 0xf0, 0x2d, 0xa6, 0x11, 0xfe, 0xef,
+ 0x24, 0x82, 0x01, 0xcc, 0xab, 0x8b, 0xef, 0x0d, 0x93, 0xd1, 0x9b, 0xe8,
+ 0x6d, 0x57, 0xba, 0x29, 0xfc, 0x6e, 0xac, 0x9b, 0x1a, 0x33, 0xf1, 0x1d,
+ 0xaa, 0xa6, 0x0c, 0xbe, 0x6a, 0xc4, 0xb1, 0x7e, 0x56, 0x91, 0xbd, 0x00,
+ 0xa2, 0xea, 0xf8, 0xa7, 0x95, 0x44, 0x14, 0xc7, 0x26, 0xdd, 0x60, 0x7b,
+ 0x39, 0x11, 0x18, 0xd9, 0x2b, 0x74, 0xf6, 0x80, 0x7d, 0x4c, 0xe6, 0x30,
+ 0xd8, 0xa6, 0x15, 0xf0, 0xc3, 0x77, 0xa9, 0xeb, 0xd4, 0xf2, 0x4c, 0x81,
+ 0xff, 0x15, 0xfa, 0x4f, 0xa6, 0x55, 0x93, 0x10, 0xb3, 0x98, 0x14, 0xb5,
+ 0xce, 0xc8, 0x33, 0x3e, 0x3b, 0x0f, 0x9a, 0x85, 0xdf, 0xd0, 0x51, 0x7b,
+ 0xfc, 0x29, 0xe4, 0x89, 0x15, 0x16, 0x69, 0x63, 0x59, 0x01, 0xbf, 0xd8,
+ 0xc8, 0xc2, 0x5a, 0x6f, 0x58, 0xd4, 0x5e, 0xc3, 0xcf, 0xa9, 0xf3, 0x89,
+ 0xf7, 0xf3, 0xf3, 0x43, 0xe2, 0xdb, 0x72, 0xd3, 0xd7, 0x30, 0xae, 0x95,
+ 0x86, 0x17, 0x2a, 0x4f, 0xf1, 0x75, 0x11, 0x2f, 0xcc, 0x50, 0xbb, 0x8a,
+ 0x05, 0x74, 0xa9, 0xf8, 0x51, 0x84, 0x69, 0xa8, 0x56, 0x53, 0x3c, 0x5c,
+ 0xf5, 0x9d, 0x01, 0xb7, 0xbd, 0xbe, 0xb3, 0xaf, 0x6d, 0x22, 0x67, 0x36,
+ 0xc3, 0x67, 0xe4, 0x82, 0xb6, 0x91, 0xf2, 0x09, 0x5a, 0xb3, 0xb4, 0xd5,
+ 0xda, 0xb9, 0x6d, 0xdf, 0xd3, 0xde, 0x3a, 0xb5, 0x7a, 0xf1, 0xae, 0xd3,
+ 0xa1, 0xf0, 0xa8, 0x95, 0xce, 0x16, 0x3b, 0x58, 0x56, 0xa3, 0xce, 0x09,
+ 0xf0, 0x0a, 0x46, 0x51, 0x27, 0xf2, 0x5c, 0xa8, 0x95, 0x96, 0x97, 0x91,
+ 0xd3, 0xf0, 0x67, 0x7b, 0x65, 0x7e, 0x6e, 0x9a, 0xe1, 0x72, 0x88, 0xe5,
+ 0x9a, 0xa1, 0x62, 0x35, 0x38, 0x07, 0x9e, 0x20, 0x7a, 0x78, 0x86, 0x9e,
+ 0x1e, 0xed, 0x60, 0x7d, 0x5e, 0xfa, 0xfa, 0x0f, 0xf3, 0xb3, 0xbf, 0x57,
+ 0x4c, 0xc3, 0x4f, 0x65, 0x1e, 0xe5, 0xe7, 0x4f, 0xb3, 0x1e, 0x90, 0xa0,
+ 0x56, 0x5a, 0x5a, 0x6e, 0x65, 0x7d, 0xbe, 0x95, 0xf5, 0x80, 0x11, 0x73,
+ 0x38, 0x20, 0xde, 0x25, 0x6a, 0x52, 0x3e, 0x1b, 0x3a, 0x64, 0x1e, 0x13,
+ 0x79, 0x36, 0x7f, 0xa5, 0xde, 0xe5, 0x7d, 0xc7, 0x07, 0x15, 0x1c, 0x1f,
+ 0x0d, 0xae, 0x5e, 0xbc, 0xe3, 0x98, 0x8c, 0x7f, 0x93, 0xac, 0xf3, 0x86,
+ 0xc5, 0xf7, 0x17, 0x8d, 0xa9, 0x29, 0xd6, 0xff, 0xf1, 0x8d, 0xb7, 0x67,
+ 0x28, 0x5b, 0x3e, 0x45, 0x5f, 0x2f, 0xbb, 0x7d, 0xaf, 0xcf, 0xf0, 0x9c,
+ 0x65, 0xed, 0x7c, 0x1b, 0xcf, 0xeb, 0x3d, 0xc7, 0xcb, 0x2b, 0x3a, 0x28,
+ 0xf8, 0xad, 0x30, 0xb5, 0x7e, 0x03, 0x3e, 0x8f, 0x0a, 0x15, 0xe2, 0xf6,
+ 0xd5, 0xfb, 0x24, 0xfd, 0xbc, 0x37, 0x44, 0x5e, 0x2a, 0xdf, 0xcf, 0xcf,
+ 0x9c, 0xc3, 0xb8, 0x1b, 0x16, 0xdd, 0x76, 0x24, 0xbc, 0xff, 0x36, 0x14,
+ 0xa6, 0xe0, 0x1b, 0xc8, 0xf5, 0x82, 0x8e, 0xb5, 0x7a, 0xd1, 0x39, 0xc0,
+ 0x7c, 0xfa, 0x1b, 0xb8, 0x8f, 0xff, 0xbe, 0x81, 0xe3, 0x0e, 0x5e, 0x27,
+ 0xe4, 0x2c, 0x72, 0x4a, 0xc0, 0xdf, 0x0e, 0x45, 0x4c, 0x81, 0x7f, 0xcf,
+ 0x30, 0x4e, 0xb5, 0x08, 0x1f, 0x5f, 0x1f, 0xc6, 0x3a, 0x83, 0xac, 0x13,
+ 0xac, 0x5e, 0x1c, 0x3d, 0x80, 0xe3, 0x44, 0x6f, 0x90, 0x61, 0x24, 0x71,
+ 0xa8, 0xe1, 0x9b, 0x75, 0xa1, 0xc3, 0xa3, 0xe4, 0xfa, 0x6e, 0x1d, 0x7a,
+ 0x26, 0x75, 0x50, 0x8a, 0xdf, 0x31, 0x5d, 0x94, 0xeb, 0x9e, 0x2b, 0x07,
+ 0x49, 0xfa, 0x87, 0x52, 0x43, 0xfa, 0xfb, 0x84, 0xd4, 0x8f, 0x67, 0x6b,
+ 0x5a, 0xc1, 0xef, 0x1e, 0x7a, 0x50, 0xec, 0xa2, 0x75, 0x15, 0x43, 0x7a,
+ 0x20, 0xec, 0x29, 0xe6, 0xc5, 0xe9, 0x1e, 0xba, 0xbf, 0xdc, 0x42, 0xd4,
+ 0xd7, 0x21, 0x62, 0xbc, 0x0f, 0x8a, 0x8b, 0x94, 0x7c, 0xed, 0xc9, 0x21,
+ 0xe9, 0x4f, 0xa9, 0xe1, 0xc8, 0x03, 0x1f, 0x1c, 0x79, 0x57, 0xe0, 0xc8,
+ 0xf0, 0xd0, 0xc6, 0x38, 0xb2, 0x47, 0xe7, 0x22, 0x52, 0xab, 0xc2, 0x8f,
+ 0xd7, 0x19, 0x3f, 0x5e, 0x66, 0xfc, 0x38, 0xd2, 0x04, 0x3f, 0x0c, 0x0f,
+ 0x7e, 0x1c, 0x15, 0xf8, 0xf1, 0xeb, 0x43, 0x1b, 0xe1, 0xc7, 0x91, 0xe0,
+ 0x46, 0x3e, 0x1e, 0x8d, 0x9b, 0x03, 0xb4, 0x54, 0x74, 0x68, 0x79, 0xde,
+ 0x8e, 0x27, 0x68, 0x35, 0x22, 0x63, 0x83, 0x53, 0xa2, 0x4e, 0x65, 0x51,
+ 0xe0, 0x55, 0x5a, 0xf8, 0x2f, 0xfd, 0xbf, 0x1b, 0x68, 0x29, 0xf8, 0xcb,
+ 0x3d, 0x99, 0xce, 0xaf, 0x5e, 0xfc, 0x3b, 0xde, 0xc7, 0xdb, 0x2b, 0xa1,
+ 0x10, 0xae, 0x05, 0xa7, 0xc2, 0xb4, 0xb6, 0x82, 0xef, 0x12, 0x46, 0xe8,
+ 0x4e, 0x31, 0x4a, 0xb7, 0x8b, 0x03, 0xb4, 0x56, 0x1c, 0xa2, 0xbb, 0x45,
+ 0xbc, 0x03, 0x30, 0xe7, 0x63, 0x01, 0x73, 0x83, 0x0e, 0x87, 0x79, 0xcc,
+ 0xf2, 0x00, 0xad, 0x2e, 0x6b, 0x7c, 0x05, 0xae, 0x62, 0xff, 0xe1, 0x27,
+ 0xf0, 0xc7, 0x81, 0xe9, 0x3a, 0x1c, 0x90, 0xf7, 0x60, 0xef, 0x67, 0x1b,
+ 0x6b, 0x64, 0x45, 0x9e, 0xa5, 0xc9, 0x38, 0xd2, 0x32, 0x65, 0x0b, 0x5f,
+ 0xea, 0xe1, 0x20, 0x74, 0xd9, 0xc4, 0x3e, 0xea, 0xe1, 0x3d, 0x70, 0x90,
+ 0x27, 0x34, 0xc4, 0x7a, 0xe9, 0x0e, 0xa1, 0x87, 0x26, 0x9d, 0x50, 0x64,
+ 0x9a, 0x2a, 0x97, 0x0c, 0x07, 0x3d, 0x0f, 0xd3, 0xfc, 0x3c, 0x43, 0xf9,
+ 0x71, 0xba, 0x5d, 0xf8, 0xe4, 0xd5, 0x39, 0x11, 0x8b, 0x7d, 0x96, 0xe7,
+ 0x0c, 0xf9, 0x58, 0x8b, 0x73, 0x50, 0x35, 0xce, 0xd1, 0xce, 0xeb, 0x96,
+ 0xb4, 0x34, 0xe3, 0xf0, 0xb8, 0x32, 0x8f, 0x2b, 0x23, 0x76, 0xc6, 0xe7,
+ 0x97, 0x11, 0xb7, 0x8d, 0xd2, 0xda, 0x3c, 0x68, 0x0e, 0x7e, 0x89, 0x5a,
+ 0xac, 0x74, 0x6d, 0x05, 0xe7, 0xe1, 0x9b, 0xa8, 0xc5, 0x4a, 0xd7, 0x54,
+ 0xac, 0x74, 0x6d, 0x65, 0x4a, 0xf0, 0xe1, 0xd9, 0xff, 0xdd, 0x14, 0x60,
+ 0x19, 0x30, 0x85, 0x19, 0xba, 0x4e, 0x53, 0x0d, 0x7a, 0xbf, 0x4e, 0x0c,
+ 0x78, 0x6c, 0x58, 0x50, 0x05, 0x7f, 0x18, 0xba, 0x62, 0x84, 0xa1, 0x0d,
+ 0xb8, 0xfd, 0xe3, 0x02, 0x34, 0xd3, 0x79, 0x4a, 0x0c, 0x30, 0x3c, 0x23,
+ 0x80, 0x79, 0x49, 0x18, 0x9a, 0x97, 0x60, 0x73, 0xaf, 0xfc, 0x0c, 0x90,
+ 0xbb, 0x7a, 0x6c, 0xc0, 0x6d, 0x7c, 0x48, 0xf9, 0x23, 0x83, 0x56, 0xfe,
+ 0x30, 0xb0, 0x38, 0xa9, 0x43, 0xf4, 0x37, 0xad, 0x7f, 0x2c, 0x07, 0x1b,
+ 0x5f, 0x6b, 0x02, 0x9a, 0xdb, 0x3c, 0x85, 0x94, 0xb9, 0x5b, 0x60, 0xbd,
+ 0x89, 0x75, 0x5d, 0x26, 0xb1, 0x76, 0xc3, 0xd2, 0x42, 0x0c, 0x19, 0xe9,
+ 0x09, 0x62, 0x06, 0x22, 0x3d, 0xd9, 0x00, 0xcb, 0x4e, 0x16, 0x60, 0x5e,
+ 0x11, 0x02, 0xd6, 0x0f, 0x0c, 0xd0, 0x3a, 0xe6, 0x00, 0x78, 0x2c, 0xa1,
+ 0x89, 0x01, 0x74, 0x07, 0x27, 0xd0, 0xfe, 0x7e, 0x65, 0xf0, 0xba, 0xe3,
+ 0x06, 0x09, 0x88, 0xa1, 0x8b, 0x7a, 0x14, 0xe5, 0x41, 0x79, 0xd4, 0x49,
+ 0x85, 0x81, 0xc4, 0xfc, 0x04, 0xf2, 0x1f, 0xd0, 0x1f, 0x20, 0x3f, 0x02,
+ 0xf3, 0x93, 0x33, 0x50, 0x0e, 0xb4, 0x36, 0xaa, 0x79, 0x0d, 0x48, 0x1f,
+ 0x28, 0x0c, 0x41, 0x65, 0x2a, 0x68, 0x8c, 0x03, 0xc8, 0x5e, 0x22, 0x04,
+ 0x0d, 0x3b, 0x20, 0x0d, 0x64, 0x37, 0x4f, 0x11, 0x01, 0xf3, 0x93, 0x02,
+ 0x84, 0x18, 0x1a, 0xe0, 0xf9, 0x89, 0x1d, 0xe8, 0x52, 0x98, 0x9b, 0xfe,
+ 0xff, 0x3f, 0xa6, 0xc2, 0x02, 0x4c, 0x7b, 0xa0, 0xb5, 0xb5, 0xbf, 0xff,
+ 0x1f, 0x10, 0x61, 0x61, 0x68, 0x81, 0xaf, 0xd1, 0x0b, 0x94, 0x07, 0x95,
+ 0x73, 0x0b, 0x80, 0xac, 0x36, 0x78, 0xbd, 0x0d, 0x92, 0x07, 0x89, 0xfd,
+ 0x02, 0x96, 0x2b, 0xff, 0xff, 0x2f, 0x85, 0xab, 0x05, 0x01, 0x00, 0xb3,
+ 0x28, 0x79, 0xae, 0x58, 0x7d, 0x00, 0x00, 0x00 };
-static u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b06FwRodata[(0x58/4) + 1] = {
- 0x08002428, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c, 0x0800245c,
- 0x08002380, 0x0800245c, 0x080023e4, 0x0800245c, 0x0800231c, 0x0800245c,
- 0x0800245c, 0x0800245c, 0x08002328, 0x00000000, 0x08003240, 0x08003270,
- 0x080032a0, 0x080032d0, 0x08003300, 0x00000000, 0x00000000 };
-static u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b06FwSbss[(0x1c/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b06FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b06FwRodata[(0x88/4) + 1] = {
+ 0x08001c1c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c, 0x08001c4c,
+ 0x08001b74, 0x08001c4c, 0x08001bdc, 0x08001c4c, 0x08001b08, 0x08001c4c,
+ 0x08001c4c, 0x08001c4c, 0x08001b14, 0x00000000, 0x08002b58, 0x08002ba8,
+ 0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc,
+ 0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140,
+ 0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 };
+static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 };
static struct fw_info bnx2_com_fw_06 = {
- .ver_major = 0x1,
- .ver_minor = 0x0,
- .ver_fix = 0x0,
+ .ver_major = 0x3,
+ .ver_minor = 0x4,
+ .ver_fix = 0x3,
- .start_addr = 0x080008b4,
+ .start_addr = 0x080000b4,
.text_addr = 0x08000000,
- .text_len = 0x57bc,
+ .text_len = 0x7d54,
.text_index = 0x0,
.gz_text = bnx2_COM_b06FwText,
.gz_text_len = sizeof(bnx2_COM_b06FwText),
- .data_addr = 0x08005840,
+ .data_addr = 0x08007e00,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_COM_b06FwData,
- .sbss_addr = 0x08005840,
- .sbss_len = 0x1c,
+ .sbss_addr = 0x08007e00,
+ .sbss_len = 0x60,
.sbss_index = 0x0,
.sbss = bnx2_COM_b06FwSbss,
- .bss_addr = 0x08005860,
+ .bss_addr = 0x08007e60,
.bss_len = 0x88,
.bss_index = 0x0,
.bss = bnx2_COM_b06FwBss,
- .rodata_addr = 0x080057c0,
- .rodata_len = 0x58,
+ .rodata_addr = 0x08007d58,
+ .rodata_len = 0x88,
.rodata_index = 0x0,
.rodata = bnx2_COM_b06FwRodata,
};
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index 680c769a3fc..2c067531f03 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -1,13 +1,13 @@
/* bnx2_fw2.h: Broadcom NX2 network driver.
*
- * Copyright (c) 2006 Broadcom Corporation
+ * Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation
*
* 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, except as noted below.
*
* This file contains firmware data derived from proprietary unpublished
- * source code, Copyright (c) 2006 Broadcom Corporation.
+ * source code, Copyright (c) 2004, 2005, 2006, 2007 Broadcom Corporation.
*
* Permission is hereby granted for the distribution of this firmware data
* in hexadecimal or equivalent format, provided this copyright notice is
@@ -15,3289 +15,3260 @@
*/
static u8 bnx2_COM_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0xac, 0xfb, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xdc, 0x5b, 0x6b, 0x70,
- 0x1b, 0xd7, 0x75, 0x3e, 0xfb, 0x00, 0x09, 0x91, 0x10, 0xb5, 0xa4, 0x60,
- 0x1a, 0x96, 0x68, 0x07, 0x20, 0x57, 0x22, 0x6a, 0xb1, 0x29, 0x4c, 0x33,
- 0x16, 0x9b, 0xc2, 0x12, 0x02, 0x50, 0xae, 0x26, 0xc3, 0x3a, 0x94, 0xcd,
- 0xd8, 0x4a, 0xaa, 0xc9, 0x30, 0x00, 0xa5, 0xf4, 0x61, 0xb7, 0x92, 0xab,
- 0xa9, 0x5d, 0xd7, 0xaa, 0x21, 0x92, 0x6a, 0xf5, 0x83, 0xe5, 0x2a, 0x16,
- 0x43, 0xa9, 0xd3, 0x74, 0xc2, 0x12, 0x56, 0xac, 0x4e, 0x31, 0x85, 0xfc,
- 0xd6, 0x38, 0xb1, 0xc9, 0x4a, 0x76, 0xeb, 0xf4, 0xe1, 0xa6, 0x33, 0xcd,
- 0xa3, 0x9d, 0x36, 0xf6, 0xa8, 0x3f, 0xea, 0xe9, 0xd3, 0x33, 0x6e, 0xa7,
- 0xea, 0xd8, 0x0e, 0xfa, 0x7d, 0x77, 0x77, 0x81, 0x25, 0x48, 0xbd, 0xfc,
- 0xc8, 0x8f, 0x70, 0x06, 0xb3, 0x7b, 0xef, 0xde, 0xbd, 0xf7, 0xdc, 0xf3,
- 0xf8, 0xce, 0x63, 0x2f, 0xfb, 0x44, 0x5a, 0xc4, 0xfb, 0x5b, 0x8b, 0x5f,
- 0xfc, 0xfe, 0x5f, 0x2d, 0x7c, 0x7c, 0xf0, 0xe3, 0xfd, 0x22, 0xb7, 0xdc,
- 0xa2, 0xb7, 0x86, 0x75, 0xf6, 0x1b, 0xf8, 0x45, 0xf1, 0xeb, 0xf7, 0xee,
- 0x57, 0xfb, 0xb3, 0xf0, 0x7b, 0x13, 0x0f, 0xc7, 0xfe, 0x55, 0x44, 0xbb,
- 0xc4, 0x98, 0xe0, 0x5f, 0xb5, 0x7a, 0xf9, 0xe7, 0x5c, 0x38, 0x7e, 0x89,
- 0x67, 0x86, 0xbb, 0x9c, 0xa2, 0x97, 0x3f, 0x09, 0xeb, 0x69, 0x39, 0x94,
- 0xb5, 0x25, 0x6c, 0xa4, 0xdf, 0x3c, 0x54, 0xb0, 0x45, 0x32, 0xe5, 0x2d,
- 0xf1, 0x9c, 0xbc, 0x57, 0x2d, 0x46, 0x4d, 0x61, 0xff, 0x8d, 0xe9, 0x77,
- 0xbf, 0xf6, 0xe2, 0xd6, 0xc4, 0x5b, 0xf3, 0x86, 0x84, 0xad, 0xf4, 0x19,
- 0xb1, 0x36, 0x4b, 0xb8, 0x0b, 0xef, 0x7c, 0xb5, 0xf7, 0x3d, 0x91, 0x36,
- 0x7f, 0xae, 0x37, 0xab, 0x2f, 0xf6, 0x4a, 0x71, 0x43, 0x3a, 0x2c, 0x7a,
- 0x7a, 0xd3, 0xf7, 0xb3, 0x86, 0x35, 0x66, 0xa4, 0x2d, 0x59, 0xac, 0xc8,
- 0xc8, 0xde, 0x69, 0x09, 0x87, 0xd3, 0x47, 0x9b, 0x9b, 0x37, 0x49, 0xd8,
- 0x4c, 0x8f, 0x1d, 0xfa, 0x6d, 0xfb, 0xd1, 0xaa, 0x6e, 0xdb, 0xc9, 0x05,
- 0x89, 0x0c, 0x9e, 0x1a, 0xc0, 0xf3, 0x72, 0x22, 0x29, 0xb2, 0x55, 0x74,
- 0xbb, 0x18, 0x31, 0xec, 0xb0, 0x64, 0x2b, 0xb6, 0xe4, 0x2a, 0x22, 0x7f,
- 0x5e, 0xd6, 0xe4, 0x94, 0xdd, 0x29, 0x0b, 0x7d, 0xef, 0x56, 0x33, 0xa0,
- 0xe5, 0xcf, 0xec, 0xb1, 0x43, 0x53, 0x36, 0xe9, 0x9d, 0x6d, 0x76, 0xe9,
- 0x9d, 0x6a, 0x2a, 0xd8, 0xa6, 0x4c, 0x94, 0xd9, 0x37, 0xa2, 0xb3, 0x2f,
- 0x94, 0x7e, 0x68, 0xcd, 0x29, 0x3b, 0xe2, 0xf5, 0xed, 0xdc, 0x9e, 0xc5,
- 0x7c, 0x93, 0x65, 0x8e, 0x3d, 0x93, 0x2a, 0xd8, 0x51, 0xaf, 0x3f, 0x79,
- 0x5b, 0xd6, 0x8e, 0xa1, 0xbf, 0xcb, 0x7b, 0x76, 0xf2, 0xbe, 0x82, 0x6d,
- 0x7b, 0xcf, 0xbe, 0x8a, 0xb9, 0x93, 0x5e, 0xff, 0x7d, 0xdb, 0x0a, 0x76,
- 0x9f, 0xd7, 0x3f, 0xbd, 0x2d, 0x6b, 0xa7, 0xbc, 0xfe, 0xe4, 0xee, 0x82,
- 0x3d, 0xe0, 0xf5, 0x9f, 0xbd, 0x3d, 0x6b, 0x0f, 0x7a, 0xfd, 0x0f, 0x6d,
- 0x2d, 0xd8, 0x69, 0xf4, 0x1f, 0x6d, 0xd6, 0x37, 0x59, 0x72, 0xa4, 0x1c,
- 0xc7, 0x2f, 0x83, 0x67, 0x43, 0xe8, 0xdb, 0x89, 0xdf, 0x30, 0x7e, 0xbf,
- 0xb8, 0x4e, 0xda, 0x46, 0x70, 0xfd, 0xc6, 0x46, 0x97, 0x77, 0xe0, 0x91,
- 0x13, 0x96, 0x37, 0x8c, 0x98, 0xbc, 0xd8, 0xfb, 0x06, 0x78, 0x68, 0xc9,
- 0x99, 0x8a, 0x68, 0x23, 0xbd, 0x31, 0xf0, 0x2e, 0x2a, 0x4f, 0x56, 0x5a,
- 0xc5, 0x78, 0xcc, 0x00, 0x6f, 0x3e, 0x2f, 0xf9, 0x68, 0x58, 0xda, 0xe7,
- 0x34, 0xe9, 0xee, 0x0f, 0x4b, 0xc6, 0x52, 0x72, 0x13, 0x7d, 0x26, 0x2a,
- 0xc6, 0x5c, 0x66, 0xbd, 0x2e, 0x9b, 0xac, 0x9c, 0x14, 0xc1, 0xbb, 0xef,
- 0x51, 0x27, 0xf1, 0x2c, 0x2e, 0xb9, 0xe9, 0x9b, 0x65, 0xcc, 0x22, 0x5d,
- 0x3b, 0x6f, 0x74, 0xd7, 0x0a, 0x6b, 0xd9, 0x13, 0x23, 0x72, 0xc4, 0x89,
- 0x68, 0xb9, 0x13, 0xdb, 0x24, 0x9b, 0x92, 0x28, 0xde, 0x8b, 0xe5, 0xf1,
- 0xa4, 0x54, 0x1e, 0x91, 0x29, 0x47, 0xb4, 0xac, 0x43, 0x7e, 0x76, 0xe2,
- 0x79, 0x9b, 0x1a, 0x8b, 0xbe, 0x2e, 0x43, 0xcd, 0x1d, 0x46, 0xbf, 0x85,
- 0xfe, 0x0e, 0x6d, 0x48, 0xcd, 0xa1, 0xfa, 0xe3, 0x93, 0x12, 0x91, 0xc7,
- 0xcb, 0x51, 0x6f, 0x6c, 0xb5, 0x9a, 0x4d, 0x59, 0x18, 0x37, 0x22, 0x93,
- 0x4e, 0x54, 0xc6, 0x70, 0x9d, 0x70, 0xb8, 0x7e, 0x0c, 0x3a, 0xf5, 0xda,
- 0xa1, 0xfc, 0xac, 0x9a, 0x2f, 0x6e, 0xa4, 0x39, 0x5f, 0x17, 0xc6, 0x4d,
- 0x80, 0x2e, 0x4d, 0x4c, 0x25, 0xcb, 0x8c, 0xe4, 0xa7, 0x35, 0xe8, 0x1b,
- 0xae, 0x8a, 0xaf, 0x43, 0xa0, 0xdf, 0x14, 0xbb, 0x5f, 0x93, 0x02, 0x64,
- 0x55, 0xb4, 0xd0, 0x2e, 0x9f, 0xd5, 0xb3, 0x4e, 0xb3, 0xe4, 0xcc, 0xb8,
- 0x18, 0x33, 0x4a, 0x97, 0x64, 0x12, 0xef, 0xe8, 0x36, 0xc7, 0x5c, 0xc4,
- 0xbe, 0xc7, 0x94, 0x1c, 0x9a, 0xd2, 0x45, 0x3d, 0x57, 0xe9, 0x14, 0x7d,
- 0x6e, 0x8f, 0xbc, 0x3c, 0x2d, 0x96, 0x91, 0x7e, 0xb7, 0x9a, 0xb5, 0xa7,
- 0xf4, 0xec, 0x13, 0xa6, 0x84, 0x66, 0x34, 0x99, 0xb2, 0x13, 0xb0, 0x80,
- 0xa3, 0xfa, 0x8e, 0xca, 0x59, 0x8c, 0xe3, 0x7b, 0x18, 0x57, 0xd6, 0xc1,
- 0x57, 0xde, 0x6f, 0xb1, 0x74, 0xa5, 0xcf, 0x1c, 0x03, 0x19, 0x60, 0x1f,
- 0x4f, 0x3a, 0x90, 0x89, 0x92, 0x51, 0x1c, 0x32, 0x7a, 0x15, 0x32, 0x1a,
- 0x80, 0x6c, 0x52, 0xf2, 0x52, 0xa5, 0x4f, 0x9e, 0xaf, 0x24, 0xe5, 0x39,
- 0xe8, 0xeb, 0xb3, 0x95, 0xb8, 0x3c, 0x53, 0xe9, 0x92, 0xa7, 0x2b, 0x31,
- 0x79, 0x4a, 0xc9, 0x2d, 0x07, 0xdb, 0x50, 0xb2, 0x0c, 0x5f, 0x9f, 0x96,
- 0x70, 0x27, 0xe4, 0xd1, 0x01, 0xfd, 0x69, 0x87, 0x6e, 0x7e, 0xa5, 0x37,
- 0x2c, 0xb3, 0xbd, 0x92, 0x59, 0x8f, 0xfe, 0x9b, 0xd2, 0xa6, 0xe2, 0x91,
- 0x89, 0xe7, 0x93, 0xd3, 0x21, 0xc9, 0x59, 0x8f, 0xcb, 0x85, 0x19, 0x53,
- 0x26, 0x2b, 0xdb, 0x6f, 0x72, 0x65, 0xc6, 0xf6, 0xbc, 0x9c, 0x9f, 0x69,
- 0xc2, 0xb3, 0x79, 0x79, 0x79, 0xb3, 0x2e, 0x13, 0xb3, 0x6f, 0x89, 0x09,
- 0x1e, 0x0e, 0x29, 0x79, 0x3f, 0x2e, 0xff, 0xfc, 0x27, 0x22, 0x23, 0xe0,
- 0x8b, 0xde, 0xff, 0xef, 0xd5, 0x8c, 0x05, 0x7e, 0xf4, 0xf7, 0x41, 0x3f,
- 0x74, 0x5c, 0x29, 0xcf, 0x38, 0xc6, 0x98, 0x5a, 0xce, 0x39, 0x0d, 0x9b,
- 0x6a, 0xd5, 0xb2, 0xc7, 0x45, 0x0a, 0xc7, 0xab, 0x52, 0x48, 0x85, 0xe4,
- 0x01, 0xab, 0x2a, 0x43, 0xa9, 0x26, 0x39, 0x60, 0x75, 0xca, 0x44, 0xdf,
- 0xcf, 0x68, 0x3e, 0x96, 0x7d, 0xa5, 0x92, 0xc6, 0x3d, 0xfb, 0x44, 0x66,
- 0xd5, 0xbd, 0xdb, 0x5f, 0xac, 0x84, 0x24, 0x13, 0x2d, 0xc6, 0x4c, 0xb9,
- 0xa0, 0xb9, 0xb4, 0xed, 0xf4, 0x9f, 0x41, 0x5e, 0x63, 0xc0, 0x90, 0x84,
- 0xd2, 0xa5, 0xfc, 0xf4, 0x9a, 0x8b, 0x19, 0xd5, 0x1d, 0x52, 0x7a, 0x6a,
- 0xa4, 0x4d, 0xd2, 0x31, 0xa6, 0xa5, 0xa3, 0xd2, 0xad, 0xec, 0x64, 0x00,
- 0x63, 0x06, 0xb5, 0xbb, 0x2b, 0x94, 0x37, 0xee, 0xcb, 0xa4, 0x75, 0x03,
- 0xc6, 0x9a, 0xb8, 0x66, 0x3c, 0x9a, 0x83, 0x74, 0x72, 0x2e, 0xd2, 0xc9,
- 0xeb, 0xde, 0x00, 0x9d, 0xfb, 0x6a, 0xf7, 0xb3, 0x81, 0xfb, 0x62, 0xe5,
- 0xd7, 0x5b, 0x5c, 0xfa, 0xc8, 0xd7, 0x41, 0x99, 0x98, 0x7e, 0xc8, 0x5b,
- 0x0b, 0xf7, 0x65, 0xae, 0xb1, 0x00, 0x3e, 0xa9, 0x91, 0x57, 0x58, 0xab,
- 0x18, 0x58, 0xeb, 0x70, 0x60, 0xad, 0xc3, 0x81, 0xb5, 0x8a, 0xe0, 0xad,
- 0xac, 0xd3, 0x81, 0x33, 0x79, 0xc2, 0xbc, 0x1c, 0xc5, 0x9c, 0x6f, 0x88,
- 0x91, 0xa6, 0x2d, 0xf8, 0x36, 0xf9, 0x07, 0x18, 0x9f, 0x96, 0x73, 0x0e,
- 0x78, 0x73, 0x3c, 0x24, 0x77, 0xa9, 0x71, 0xff, 0xb1, 0xc6, 0xa5, 0x31,
- 0xf8, 0x2c, 0x2c, 0xbb, 0xa2, 0xbc, 0xf7, 0x9f, 0x99, 0xe0, 0x37, 0xdb,
- 0x93, 0x37, 0xb8, 0x6d, 0xde, 0x9f, 0xf5, 0xf6, 0xd2, 0xee, 0xbe, 0x57,
- 0x79, 0x53, 0x61, 0xc6, 0x62, 0x85, 0xb6, 0x2d, 0x29, 0xc3, 0x96, 0xfd,
- 0x43, 0xa9, 0x4e, 0x99, 0xb4, 0xb4, 0xd4, 0x44, 0xb2, 0x99, 0xfc, 0xcf,
- 0xe8, 0x76, 0x2b, 0xec, 0x47, 0xe2, 0x3a, 0x71, 0x51, 0xed, 0xeb, 0x5b,
- 0x1e, 0xfd, 0x16, 0xdb, 0x23, 0xba, 0xdd, 0xd1, 0xd0, 0x4f, 0xfd, 0xff,
- 0x4b, 0xdc, 0xd3, 0x06, 0xfa, 0x75, 0x77, 0xed, 0xbf, 0x42, 0x9b, 0x58,
- 0x15, 0xf1, 0xda, 0xfe, 0xf3, 0xff, 0x32, 0x96, 0xb7, 0x8f, 0x6d, 0x5c,
- 0xde, 0xf6, 0x6d, 0x29, 0x88, 0x73, 0xdc, 0x2b, 0x6c, 0xd8, 0xa6, 0xfe,
- 0x85, 0x40, 0x6b, 0x0a, 0x36, 0xdc, 0xec, 0xd1, 0xf0, 0xba, 0x47, 0x03,
- 0x68, 0xc5, 0xb8, 0x89, 0x0a, 0xdf, 0x51, 0xa2, 0x6c, 0x68, 0x93, 0xf7,
- 0xfe, 0xfd, 0x5a, 0xf5, 0xfc, 0x0d, 0x83, 0xeb, 0xf8, 0x57, 0xd1, 0x86,
- 0x60, 0x67, 0x93, 0xb3, 0xa6, 0xe4, 0x53, 0x31, 0x65, 0x0f, 0xf9, 0x54,
- 0x1d, 0x3f, 0x26, 0xa7, 0x1b, 0xf1, 0x83, 0xef, 0x11, 0x3f, 0x5c, 0xec,
- 0x98, 0x98, 0x25, 0x8e, 0xd4, 0x71, 0xe3, 0xc8, 0xb4, 0x8f, 0x25, 0x9c,
- 0x9b, 0x18, 0xe2, 0xe3, 0x07, 0xdf, 0x23, 0x7e, 0x18, 0x90, 0x15, 0xe7,
- 0xf4, 0xd7, 0x9f, 0x6a, 0x98, 0x7b, 0x4a, 0x61, 0x93, 0x8b, 0xcb, 0x6f,
- 0x06, 0x70, 0xbe, 0x0b, 0x18, 0x1d, 0x85, 0xfc, 0x7c, 0x8c, 0x26, 0x76,
- 0xc6, 0x80, 0xeb, 0xe0, 0x91, 0xc2, 0xe4, 0x08, 0x70, 0xcc, 0xf4, 0x30,
- 0x35, 0xec, 0x61, 0x6a, 0x04, 0x78, 0xca, 0xb6, 0xe5, 0xb5, 0xa3, 0x5e,
- 0x3b, 0x86, 0x36, 0xfc, 0xef, 0x1c, 0x6d, 0xec, 0xb5, 0x43, 0xe3, 0xb3,
- 0x0a, 0xa7, 0x89, 0xf1, 0xc0, 0x0a, 0xe2, 0x2c, 0xf1, 0xb6, 0x4b, 0x16,
- 0xca, 0x58, 0xaf, 0x86, 0x69, 0x94, 0x47, 0x90, 0x1e, 0xd2, 0xb2, 0x46,
- 0xf4, 0xc7, 0xdc, 0xfd, 0xe8, 0xe9, 0xcf, 0xeb, 0xd2, 0xc2, 0x7d, 0x90,
- 0xee, 0x1b, 0x41, 0x2b, 0xf7, 0xf6, 0xa3, 0xa4, 0x95, 0xeb, 0x35, 0xd2,
- 0x7b, 0x1a, 0xf4, 0x66, 0x80, 0xb7, 0xa2, 0x8d, 0xf6, 0x8e, 0x82, 0xde,
- 0x11, 0x60, 0xf1, 0x30, 0xb0, 0x78, 0x27, 0xb0, 0x78, 0x08, 0x58, 0x9c,
- 0x06, 0x0e, 0x0f, 0x02, 0x87, 0x07, 0x80, 0xc3, 0x29, 0xec, 0x2b, 0x2a,
- 0xf3, 0xc0, 0xe5, 0x79, 0xe0, 0xf3, 0x3c, 0xe4, 0x35, 0x31, 0x27, 0xda,
- 0x17, 0xb0, 0xfe, 0x63, 0x33, 0x89, 0xd3, 0xd0, 0xcd, 0x58, 0x51, 0x87,
- 0x3d, 0xa5, 0x06, 0xa1, 0x23, 0x49, 0x29, 0x55, 0x46, 0xa5, 0x40, 0x3f,
- 0xb6, 0xb9, 0x07, 0xb6, 0x0b, 0xfb, 0x89, 0xf9, 0x71, 0xd3, 0x5a, 0xef,
- 0xfa, 0xf7, 0x22, 0xf6, 0x1f, 0x83, 0x27, 0x89, 0xb8, 0xc8, 0xb0, 0xe4,
- 0x9d, 0x1e, 0x2b, 0xab, 0x27, 0x31, 0x8e, 0xed, 0xb8, 0xb6, 0xf7, 0x78,
- 0x42, 0x1b, 0x3f, 0xce, 0x3d, 0x4d, 0x03, 0xe3, 0xaa, 0x32, 0x95, 0xa2,
- 0xad, 0x56, 0xe5, 0x54, 0x2a, 0x31, 0x58, 0x94, 0x56, 0x39, 0x12, 0x9d,
- 0x56, 0xfe, 0xcd, 0x4c, 0x1f, 0x53, 0xfa, 0x51, 0xb0, 0x71, 0x2d, 0x77,
- 0x6b, 0xf9, 0xe3, 0xf4, 0x3b, 0x3d, 0xf8, 0x85, 0x40, 0x0b, 0xe7, 0x37,
- 0x65, 0x68, 0x40, 0xb4, 0x7d, 0xbd, 0x45, 0xa0, 0x62, 0xc2, 0x3a, 0x87,
- 0x95, 0x73, 0xd3, 0x3d, 0xb1, 0x9c, 0x6e, 0xca, 0x98, 0xa9, 0xc9, 0x04,
- 0xec, 0x65, 0x28, 0xf5, 0x7f, 0xd5, 0x23, 0x51, 0x3e, 0x6f, 0x96, 0xdf,
- 0x51, 0x38, 0x8b, 0xb5, 0x4b, 0xb3, 0x58, 0x37, 0x04, 0xfe, 0x71, 0x5d,
- 0xce, 0x83, 0x36, 0x30, 0xcf, 0xb4, 0x13, 0xa7, 0x8b, 0xb2, 0x1d, 0x76,
- 0xb7, 0x4e, 0xb2, 0x7d, 0x4d, 0x92, 0x19, 0x89, 0xcb, 0xc4, 0xcc, 0x76,
- 0xe0, 0x1e, 0x64, 0x60, 0xb7, 0x48, 0x7e, 0x34, 0x2e, 0x5f, 0x9e, 0x61,
- 0x5f, 0x06, 0xfb, 0x4f, 0x1c, 0xcd, 0x08, 0xf7, 0x1f, 0x52, 0xfb, 0x8a,
- 0xeb, 0x19, 0x39, 0xe0, 0xbc, 0xa4, 0xbb, 0x76, 0xe9, 0xb6, 0xf7, 0x42,
- 0x1e, 0xa7, 0xc0, 0xef, 0xbc, 0x63, 0xcb, 0x02, 0xfc, 0x4a, 0xee, 0x38,
- 0x70, 0xd5, 0x6e, 0x03, 0x06, 0x26, 0xce, 0xd2, 0x3e, 0x0c, 0xc4, 0x5a,
- 0x25, 0xc5, 0xeb, 0x2e, 0x39, 0x3e, 0xa3, 0xcb, 0xb3, 0xb7, 0xc5, 0xd1,
- 0x06, 0xd6, 0xa6, 0x12, 0x67, 0xc6, 0xf4, 0x2e, 0xb9, 0xb5, 0x23, 0x86,
- 0xf7, 0x52, 0x5a, 0xde, 0xf9, 0x37, 0xf2, 0xf2, 0x64, 0x5c, 0xe7, 0x58,
- 0x5d, 0x72, 0x29, 0x03, 0x3a, 0x56, 0xc4, 0xf8, 0x7f, 0x40, 0x7f, 0x97,
- 0xcc, 0x21, 0xbe, 0x99, 0x03, 0x4d, 0xd9, 0x14, 0xb1, 0x30, 0x71, 0x72,
- 0x49, 0x07, 0x66, 0xcd, 0x41, 0x37, 0x47, 0x11, 0x3f, 0xcc, 0xfc, 0x37,
- 0xc6, 0xc4, 0x21, 0xd3, 0x1e, 0x6b, 0x02, 0xf8, 0x92, 0xe9, 0xe2, 0x3d,
- 0xe7, 0xb4, 0xe5, 0x94, 0x43, 0x1d, 0x8a, 0xcb, 0xe3, 0x15, 0xbe, 0xd7,
- 0x73, 0xf6, 0x69, 0xb1, 0xe5, 0x41, 0xe7, 0x7f, 0x30, 0xfe, 0x1d, 0xc4,
- 0x9e, 0x96, 0x94, 0x20, 0xb7, 0x02, 0x78, 0x99, 0x89, 0xb9, 0xed, 0x89,
- 0xb9, 0xc4, 0xd9, 0x0b, 0x3a, 0xef, 0xed, 0xe2, 0x82, 0x7e, 0xb3, 0x48,
- 0x07, 0xf9, 0x99, 0x02, 0x2f, 0x6d, 0x4b, 0xd7, 0x37, 0x7b, 0xf1, 0x16,
- 0x6d, 0xc0, 0x06, 0x7d, 0xa6, 0x2c, 0xf4, 0x07, 0x6d, 0x80, 0x7e, 0xd6,
- 0xb7, 0x81, 0x44, 0x6c, 0x49, 0xd7, 0xf1, 0xdc, 0x94, 0x63, 0xaa, 0xad,
- 0x81, 0xd6, 0x44, 0x8c, 0xfb, 0x9b, 0x2c, 0x27, 0xe5, 0x71, 0x87, 0xe3,
- 0xc1, 0xe7, 0xe9, 0x88, 0x37, 0x1e, 0xf1, 0x8e, 0xc3, 0x98, 0x29, 0x09,
- 0x9a, 0x5d, 0xbb, 0x58, 0x98, 0x8e, 0xaa, 0x67, 0x47, 0x1c, 0x37, 0x36,
- 0xd2, 0x11, 0x3f, 0xcd, 0x23, 0x7e, 0xca, 0x29, 0x1b, 0xb1, 0x32, 0x88,
- 0xaf, 0xe1, 0x67, 0x5d, 0xfb, 0x28, 0x95, 0x49, 0xcb, 0x3d, 0xa0, 0x2f,
- 0x51, 0x04, 0x31, 0xc7, 0x74, 0xb8, 0xeb, 0xec, 0x80, 0x14, 0x19, 0x63,
- 0x9d, 0x33, 0x1e, 0x91, 0xb1, 0x12, 0xfd, 0x1b, 0x7e, 0x8e, 0x6d, 0x31,
- 0xa6, 0xcf, 0x28, 0xdf, 0xd3, 0x03, 0x3d, 0x80, 0x5f, 0x4a, 0xb5, 0x8b,
- 0xeb, 0x07, 0xf7, 0x40, 0x9e, 0xc3, 0x90, 0x7b, 0x5a, 0xc6, 0x4f, 0x8c,
- 0x53, 0xa7, 0x93, 0x25, 0x49, 0x24, 0x8f, 0xc8, 0x16, 0x6b, 0x01, 0xbe,
- 0x30, 0x33, 0x5a, 0xdd, 0xae, 0xa7, 0xf9, 0xce, 0xa3, 0x78, 0x07, 0xd7,
- 0xd2, 0xb8, 0x3c, 0x50, 0x61, 0xdf, 0x9d, 0x86, 0xb4, 0xc0, 0x56, 0x06,
- 0xf6, 0x78, 0x76, 0x80, 0xf9, 0x4c, 0x7f, 0xbe, 0x71, 0x6f, 0x3e, 0x8e,
- 0xe3, 0x18, 0xbe, 0x53, 0x9f, 0x77, 0x07, 0x7d, 0x1b, 0xb0, 0x64, 0x87,
- 0x5e, 0xdd, 0x1e, 0xc2, 0xf3, 0x53, 0x03, 0xbc, 0xc7, 0x3c, 0xf0, 0x6d,
- 0x96, 0x3d, 0x8c, 0xb1, 0xa3, 0x98, 0x73, 0x8d, 0x64, 0x3b, 0x7d, 0x7a,
- 0xa9, 0x03, 0x8c, 0x3f, 0xd8, 0x8e, 0xae, 0x77, 0x79, 0xff, 0x25, 0xc3,
- 0xd5, 0xc9, 0x11, 0xb4, 0x69, 0x7f, 0x07, 0x25, 0xe7, 0x24, 0xb0, 0x4f,
- 0xf0, 0xb6, 0x32, 0xe1, 0xed, 0x11, 0xfc, 0x1f, 0x39, 0x0c, 0x3e, 0x48,
- 0xd1, 0xe5, 0x0d, 0xf9, 0x42, 0x9e, 0xfc, 0x16, 0x74, 0xff, 0x61, 0x8c,
- 0x81, 0x7f, 0x50, 0x3c, 0x58, 0xea, 0x70, 0x63, 0xd1, 0x44, 0x31, 0xc3,
- 0xfc, 0xa9, 0x83, 0x98, 0x07, 0xfc, 0xa9, 0x40, 0xb1, 0x30, 0xf7, 0x92,
- 0xbe, 0x86, 0xf4, 0xc6, 0x97, 0x0c, 0x83, 0xed, 0xe4, 0x12, 0x74, 0xb8,
- 0x04, 0xf9, 0x64, 0xfb, 0x68, 0xb3, 0x36, 0xe4, 0x31, 0x63, 0x50, 0x5f,
- 0x4b, 0x88, 0x05, 0xf3, 0xce, 0x16, 0xeb, 0x5e, 0xf2, 0xcd, 0xb2, 0xe4,
- 0x69, 0x27, 0x88, 0x1d, 0x3b, 0x30, 0x94, 0x7a, 0x18, 0x85, 0x1e, 0x98,
- 0xf0, 0xc9, 0x31, 0xc8, 0xfc, 0xc5, 0x0e, 0x77, 0x2f, 0xbc, 0x37, 0x65,
- 0xde, 0xc2, 0x9a, 0xce, 0xef, 0xaf, 0x73, 0xfb, 0x78, 0xcf, 0xb8, 0xc8,
- 0x97, 0xab, 0x4f, 0x3b, 0xe5, 0xdb, 0x28, 0xd3, 0x43, 0xd8, 0x0b, 0xfb,
- 0x71, 0x2d, 0x1d, 0x94, 0x71, 0xd0, 0x56, 0x18, 0xd8, 0x14, 0x3b, 0x8f,
- 0xf1, 0x39, 0xe0, 0x79, 0xd1, 0xe4, 0xb3, 0x8b, 0x5a, 0xfd, 0x1d, 0xc4,
- 0x5c, 0x36, 0xfd, 0xd9, 0x92, 0xf6, 0x85, 0xca, 0xcb, 0x5a, 0xb6, 0x74,
- 0x51, 0xcb, 0x41, 0x4f, 0x4a, 0x0e, 0x73, 0x06, 0xda, 0x8f, 0x85, 0xb5,
- 0x13, 0xb1, 0xb7, 0xf5, 0x9e, 0xf8, 0x02, 0xb0, 0x60, 0x2f, 0x6c, 0x3a,
- 0x67, 0xee, 0x94, 0x02, 0xb0, 0x35, 0x7f, 0x62, 0x0b, 0xec, 0x2d, 0x1e,
- 0xa0, 0x8b, 0x78, 0x56, 0xa4, 0x4f, 0xd5, 0x76, 0x38, 0x52, 0x6c, 0x4a,
- 0x13, 0xd7, 0x36, 0x41, 0x77, 0xd0, 0x57, 0xae, 0xeb, 0xdf, 0x1d, 0x2b,
- 0x68, 0x45, 0x7e, 0x39, 0xb0, 0x9c, 0xde, 0x92, 0x5c, 0x99, 0xde, 0x1d,
- 0x35, 0x7a, 0x89, 0x19, 0xc0, 0x7f, 0xd8, 0xcd, 0x4b, 0xd0, 0xdf, 0xe7,
- 0x1d, 0xe0, 0xbf, 0x03, 0xfc, 0x87, 0x4d, 0x3d, 0x03, 0xdd, 0x7b, 0xda,
- 0x81, 0x0f, 0x70, 0xe0, 0x03, 0x1c, 0xf8, 0x00, 0x27, 0x0b, 0x39, 0x11,
- 0xe7, 0xe9, 0x43, 0x76, 0xd7, 0x7c, 0x9e, 0x1b, 0x37, 0xdd, 0xe0, 0xc5,
- 0x22, 0xa3, 0x88, 0x45, 0x36, 0xc8, 0x44, 0xf2, 0x7a, 0xec, 0xad, 0x05,
- 0xd7, 0x56, 0x5c, 0xb1, 0x46, 0xf2, 0x76, 0xcf, 0x4e, 0x1e, 0x06, 0x5d,
- 0x88, 0xbf, 0x93, 0x3f, 0x0d, 0x3d, 0x6c, 0x02, 0x3d, 0x3f, 0xe5, 0xc5,
- 0x2c, 0x0f, 0x9a, 0xae, 0x1e, 0xb6, 0xa2, 0xef, 0x93, 0xe8, 0x6b, 0xc5,
- 0x98, 0x03, 0x18, 0xc3, 0x98, 0xa7, 0xcd, 0xeb, 0x0b, 0x8e, 0x63, 0xec,
- 0xf3, 0x19, 0xac, 0x95, 0xc0, 0xb8, 0x36, 0xcc, 0xdd, 0x85, 0x31, 0xdb,
- 0x30, 0xe6, 0x46, 0xb4, 0x19, 0x33, 0x6f, 0x44, 0xfb, 0x13, 0x0d, 0xef,
- 0x7c, 0x0c, 0x7d, 0xb7, 0x37, 0xf4, 0x9d, 0x43, 0x1f, 0xf2, 0x50, 0xeb,
- 0xbc, 0xf7, 0x5e, 0x11, 0xed, 0xce, 0x86, 0x31, 0xaf, 0xa2, 0x0f, 0x71,
- 0xaf, 0xf5, 0x2d, 0x5c, 0x91, 0x7f, 0x5a, 0xa4, 0xc9, 0x7f, 0xc6, 0xb8,
- 0x37, 0x8e, 0xfe, 0x90, 0x17, 0xbb, 0xfe, 0xa6, 0x09, 0xbd, 0xd3, 0x86,
- 0x9c, 0xdf, 0x30, 0xdd, 0x58, 0xef, 0x4e, 0xcb, 0xd5, 0x43, 0xbf, 0xfd,
- 0x70, 0x43, 0x9b, 0x63, 0x17, 0x1a, 0xfa, 0xfe, 0xa5, 0xa1, 0xfd, 0xdd,
- 0xd0, 0xca, 0x77, 0x06, 0xdb, 0x97, 0xf7, 0x15, 0x3a, 0x96, 0xb7, 0xed,
- 0xa6, 0x95, 0xef, 0xe8, 0xeb, 0x96, 0xf7, 0xdd, 0xb8, 0xbe, 0x61, 0x0c,
- 0x74, 0x2a, 0x8a, 0x1c, 0xc9, 0x1f, 0x1f, 0xbe, 0xce, 0x7d, 0x4e, 0xfe,
- 0x36, 0xea, 0x92, 0xda, 0x3a, 0xda, 0x3a, 0xe4, 0xb0, 0xa4, 0xc1, 0x9e,
- 0x2c, 0x3d, 0xfd, 0xb2, 0x96, 0x83, 0x4e, 0x65, 0x2b, 0xfe, 0x7c, 0xb4,
- 0xd9, 0xc6, 0xdc, 0xdc, 0xcf, 0xc9, 0x19, 0x2b, 0x45, 0xa0, 0x37, 0xf7,
- 0xd0, 0x27, 0x1d, 0x2d, 0x4a, 0xdd, 0x3e, 0xbb, 0xf5, 0x4b, 0xd9, 0xe7,
- 0xed, 0x1e, 0x46, 0x1d, 0x06, 0x9d, 0x55, 0x19, 0x49, 0x35, 0xd3, 0xc7,
- 0x78, 0xd8, 0x45, 0xdc, 0xa9, 0x56, 0x8d, 0xcd, 0x55, 0xd9, 0x9f, 0x7a,
- 0xa7, 0x2a, 0x0a, 0xf3, 0x06, 0x15, 0xee, 0xc4, 0xf5, 0x1e, 0xc8, 0xc8,
- 0x42, 0x6e, 0x82, 0x7c, 0x3a, 0x4a, 0x9f, 0x74, 0x90, 0xf1, 0xc9, 0xa3,
- 0x2e, 0xa6, 0x12, 0x77, 0xd0, 0x46, 0x5e, 0x96, 0x3f, 0xce, 0xf5, 0x71,
- 0x2d, 0x11, 0xc7, 0x47, 0x95, 0x4f, 0xc9, 0x5b, 0x9c, 0x77, 0x35, 0x6c,
- 0x3c, 0x6b, 0x32, 0xa6, 0x33, 0xed, 0xd3, 0xf0, 0x6f, 0x7c, 0xc6, 0x58,
- 0xe1, 0x34, 0xe3, 0x92, 0x00, 0x56, 0x6d, 0x35, 0xe0, 0x32, 0x8b, 0xcb,
- 0xf7, 0xb5, 0x81, 0x79, 0xc4, 0x55, 0xec, 0x75, 0x75, 0x2c, 0xea, 0xd1,
- 0xaf, 0x6c, 0xdb, 0xbb, 0x6a, 0xb6, 0xed, 0xeb, 0xde, 0x6a, 0x39, 0xf8,
- 0xf7, 0x95, 0x2c, 0x9e, 0xaa, 0x24, 0x8e, 0x15, 0x61, 0x4b, 0x8b, 0x2a,
- 0xef, 0xf6, 0xe5, 0xc2, 0x18, 0x27, 0x71, 0x72, 0x1e, 0x6f, 0x8e, 0xab,
- 0x1c, 0x83, 0xf9, 0x45, 0x55, 0x76, 0xa4, 0x5a, 0xa3, 0xe4, 0x43, 0x46,
- 0xff, 0x76, 0x88, 0x31, 0xc3, 0xa2, 0x43, 0x9e, 0xa5, 0xf0, 0x3c, 0x05,
- 0x4c, 0xf8, 0x27, 0xc9, 0x45, 0xd9, 0xf7, 0x76, 0x75, 0x01, 0x71, 0x95,
- 0x8a, 0x8f, 0x94, 0xbf, 0x67, 0x7c, 0xb7, 0x1f, 0xfc, 0x22, 0x4f, 0x47,
- 0xc0, 0x67, 0x3f, 0x06, 0x78, 0x8d, 0x75, 0x15, 0x59, 0x1e, 0x07, 0x8b,
- 0x3c, 0x50, 0x7e, 0x19, 0x73, 0xea, 0x6e, 0xac, 0xc2, 0x3c, 0xdc, 0x66,
- 0x7f, 0x47, 0x88, 0xb1, 0x9c, 0xeb, 0xeb, 0x0d, 0xac, 0x87, 0xdc, 0xbe,
- 0xfc, 0x8f, 0x2a, 0x6e, 0x2a, 0x28, 0x79, 0x20, 0x86, 0xaa, 0xf0, 0x19,
- 0xfb, 0xc2, 0x5e, 0xec, 0x1c, 0xf1, 0x62, 0x65, 0xcb, 0x8b, 0x95, 0x49,
- 0x07, 0x6b, 0x6f, 0x7e, 0x5c, 0x40, 0x99, 0x2d, 0x1d, 0xd2, 0x37, 0x33,
- 0x2e, 0x68, 0x93, 0xd5, 0xe3, 0x02, 0x9f, 0xa6, 0x6d, 0xa0, 0x89, 0x71,
- 0x9e, 0xaa, 0xbd, 0x74, 0xb8, 0xf5, 0x1e, 0xd2, 0xe0, 0xfb, 0x47, 0xe5,
- 0x87, 0x8f, 0xc2, 0xe5, 0x61, 0x6f, 0x69, 0xd0, 0xba, 0x53, 0xb2, 0xd3,
- 0xdb, 0x3c, 0x7f, 0xcb, 0x1c, 0x80, 0xf1, 0xb7, 0xab, 0xb3, 0xd9, 0xd4,
- 0x84, 0x3f, 0x4f, 0x27, 0x3c, 0x64, 0xa0, 0x2e, 0xc4, 0xb5, 0x18, 0xc7,
- 0xf8, 0x31, 0xcd, 0x4e, 0x2f, 0xa6, 0x19, 0x96, 0xfd, 0x8e, 0x1b, 0xf3,
- 0x8f, 0xa0, 0x3f, 0xef, 0x28, 0xda, 0x63, 0x8c, 0x2d, 0x75, 0xc4, 0xdc,
- 0x99, 0x3d, 0x09, 0x24, 0x0f, 0xee, 0x5e, 0xba, 0xb1, 0x97, 0x52, 0x6d,
- 0x2f, 0xad, 0x4b, 0xcb, 0xf7, 0x32, 0xaa, 0xde, 0x9d, 0x5a, 0xf1, 0xae,
- 0x60, 0x1f, 0xbb, 0x2f, 0xf1, 0x8c, 0x7b, 0x64, 0xdc, 0x60, 0x79, 0x7b,
- 0xf4, 0xe5, 0x74, 0x00, 0x7b, 0x4c, 0x6a, 0x79, 0x15, 0x6b, 0xed, 0x51,
- 0x3c, 0xcf, 0x97, 0xc7, 0x70, 0xa5, 0x7d, 0xa8, 0x79, 0x94, 0x8d, 0x4c,
- 0x28, 0x3e, 0x8f, 0xab, 0x7d, 0x2c, 0x94, 0x7f, 0x41, 0x0a, 0x27, 0x7e,
- 0x09, 0x7e, 0x2f, 0x58, 0x0f, 0x63, 0x2d, 0x91, 0xfc, 0x28, 0x06, 0xf0,
- 0x93, 0x7b, 0x65, 0xad, 0xeb, 0x0f, 0x43, 0x6e, 0x7e, 0x10, 0x81, 0x8c,
- 0x35, 0xf7, 0xb9, 0x5a, 0xdf, 0xe7, 0x6b, 0x53, 0x80, 0x9e, 0x2a, 0x62,
- 0xce, 0x18, 0x68, 0x08, 0xbe, 0x73, 0x50, 0x86, 0x1c, 0xca, 0xa3, 0x27,
- 0x36, 0x2e, 0xb6, 0x95, 0x17, 0x3f, 0xce, 0xe0, 0xfa, 0xb4, 0xf9, 0x5c,
- 0xcc, 0x10, 0xd6, 0x2f, 0x7d, 0xde, 0xf9, 0x7c, 0x8b, 0x2c, 0x35, 0xea,
- 0xc0, 0x14, 0xe8, 0x29, 0x38, 0xe4, 0x93, 0xaf, 0x9b, 0xfe, 0xda, 0xaf,
- 0xaa, 0xfd, 0x4c, 0xaa, 0x9a, 0xdd, 0x73, 0x35, 0x1d, 0x9d, 0x40, 0x0c,
- 0xe2, 0xea, 0xdc, 0x7d, 0x1e, 0x6f, 0x7c, 0xdd, 0x8c, 0x78, 0x72, 0x66,
- 0x1e, 0x47, 0xdb, 0xf1, 0xf5, 0x60, 0x93, 0x75, 0xb7, 0xe2, 0x05, 0x9f,
- 0x11, 0x53, 0x5c, 0x59, 0x8e, 0xd5, 0x64, 0xb9, 0xb6, 0x41, 0x2f, 0xbf,
- 0xb7, 0xce, 0xb5, 0x43, 0xda, 0x1b, 0xec, 0x16, 0xf4, 0x3d, 0xb5, 0xcc,
- 0xbe, 0x93, 0x97, 0xa8, 0x83, 0x46, 0xc4, 0x98, 0xfb, 0x53, 0xf0, 0xf2,
- 0x63, 0xc8, 0x55, 0x44, 0xcc, 0x19, 0xe2, 0x10, 0xe3, 0x8d, 0x7a, 0xbc,
- 0xbb, 0x20, 0xab, 0xc5, 0xba, 0x57, 0x8a, 0x35, 0x7e, 0xf2, 0x2a, 0x63,
- 0x8d, 0x78, 0x93, 0xb4, 0x10, 0x8b, 0x86, 0x11, 0xdb, 0x6a, 0xd2, 0x64,
- 0x3f, 0x08, 0x1f, 0x76, 0xc6, 0x6c, 0xb6, 0x7d, 0x4c, 0x88, 0x48, 0xfb,
- 0xdc, 0x06, 0x85, 0x0b, 0xd6, 0x4c, 0x1d, 0x17, 0x26, 0xc0, 0xfb, 0x11,
- 0xb7, 0xb6, 0x1a, 0x6d, 0x97, 0xab, 0xcd, 0x8d, 0xeb, 0x71, 0xff, 0x58,
- 0x2d, 0xee, 0xbf, 0xa1, 0x81, 0x8f, 0xab, 0xe1, 0xe2, 0x19, 0xf0, 0x2d,
- 0x8d, 0xfc, 0x97, 0x79, 0xed, 0x10, 0xf2, 0x61, 0xe6, 0x62, 0x19, 0xe4,
- 0xc4, 0x89, 0x33, 0xc0, 0x2a, 0xe4, 0xc8, 0x89, 0xb7, 0xe0, 0x57, 0x90,
- 0x37, 0x27, 0xe6, 0x99, 0xbb, 0x2e, 0x22, 0x3f, 0x7e, 0x1a, 0xf9, 0xf1,
- 0x53, 0x95, 0x3e, 0xf0, 0x37, 0xa9, 0xb0, 0x73, 0xef, 0x71, 0xd1, 0xee,
- 0x52, 0xf5, 0x61, 0xda, 0x73, 0x14, 0x7e, 0xb4, 0x5a, 0x3d, 0x90, 0xea,
- 0x41, 0x4e, 0x1e, 0x97, 0x4f, 0x99, 0xcc, 0x63, 0x35, 0xb3, 0xbb, 0x7f,
- 0xc1, 0x08, 0xc6, 0xa4, 0xd9, 0x2b, 0xfa, 0x81, 0x95, 0xbc, 0xcf, 0x29,
- 0x5f, 0x70, 0xcc, 0xb8, 0x1c, 0xef, 0xef, 0xaa, 0xf1, 0xfe, 0xc2, 0x1a,
- 0x69, 0x19, 0x56, 0x35, 0x80, 0xee, 0xfe, 0x03, 0xc4, 0xab, 0x14, 0xfc,
- 0x3a, 0xfc, 0x6f, 0x55, 0xee, 0x48, 0x5d, 0xac, 0x9e, 0xb7, 0xd7, 0x49,
- 0xbe, 0xef, 0x8b, 0x1e, 0x66, 0x8f, 0x3d, 0x92, 0xb5, 0x8b, 0xb0, 0x0f,
- 0xb7, 0x16, 0x39, 0x3e, 0x1d, 0x46, 0x14, 0xca, 0xbf, 0x0e, 0x59, 0x18,
- 0xfc, 0x1b, 0xc8, 0x70, 0xcb, 0x69, 0x16, 0xb0, 0x74, 0xe0, 0xf0, 0x42,
- 0x34, 0xa2, 0xea, 0x33, 0xd7, 0xd9, 0xec, 0xb7, 0x20, 0xd3, 0x51, 0x59,
- 0x40, 0xfc, 0x50, 0x1a, 0x04, 0x8d, 0x7d, 0x9d, 0x18, 0x4f, 0xbb, 0x23,
- 0xcf, 0x47, 0xe1, 0x7b, 0xc9, 0xd3, 0x28, 0xc6, 0xef, 0xc2, 0x98, 0x0e,
- 0x5c, 0xbf, 0x68, 0x2c, 0x58, 0xcc, 0x9d, 0x7f, 0x0e, 0x6d, 0xce, 0x11,
- 0xf4, 0x9d, 0x9f, 0x0e, 0x89, 0x9a, 0x93, 0xef, 0x74, 0x2a, 0xfb, 0xaf,
- 0xaf, 0xc5, 0x75, 0xf8, 0xec, 0xbd, 0xea, 0x2d, 0xfd, 0x83, 0x81, 0xf5,
- 0xda, 0x02, 0xeb, 0x0d, 0x06, 0xd6, 0x23, 0x9d, 0x1d, 0x01, 0x3a, 0x3b,
- 0xf0, 0x7e, 0x0e, 0x6b, 0x0f, 0xab, 0x98, 0xa7, 0xbe, 0xe6, 0xfd, 0x81,
- 0x35, 0xfd, 0xfd, 0x75, 0x06, 0xde, 0x7b, 0x07, 0xeb, 0xb1, 0x2f, 0x1a,
- 0xe8, 0x23, 0x0d, 0xeb, 0xd1, 0xc7, 0x76, 0x47, 0x80, 0x2e, 0xd2, 0xba,
- 0x16, 0xfd, 0x2a, 0x7e, 0x02, 0x9f, 0x5b, 0xe0, 0xb7, 0x74, 0xf8, 0x0e,
- 0xd6, 0xa0, 0x1b, 0xf7, 0xfa, 0x65, 0xac, 0xeb, 0xcf, 0x17, 0xc5, 0x1c,
- 0x1c, 0xcf, 0xb1, 0x86, 0xf7, 0x3e, 0xfb, 0xf9, 0xfc, 0x1b, 0xd5, 0xaf,
- 0x2b, 0xbe, 0xad, 0x07, 0xed, 0xaa, 0xee, 0x22, 0xf3, 0x1d, 0x26, 0xe4,
- 0xc9, 0xfc, 0x58, 0x93, 0x9b, 0x6c, 0x5d, 0xeb, 0xe9, 0xa7, 0xec, 0xd7,
- 0x79, 0x58, 0xda, 0xa2, 0x65, 0x8f, 0xb3, 0x5e, 0xd0, 0xea, 0xe5, 0x7c,
- 0xc8, 0x3d, 0x94, 0x8f, 0x31, 0xbd, 0xe7, 0xf4, 0x31, 0x8c, 0x5b, 0xe8,
- 0x3f, 0x33, 0xde, 0x3d, 0xae, 0xd0, 0xe1, 0x7d, 0xa5, 0x0e, 0x39, 0xaf,
- 0x78, 0x6a, 0xc9, 0xb9, 0x1a, 0x4f, 0x43, 0xde, 0xb7, 0x90, 0x83, 0xde,
- 0x77, 0x06, 0x03, 0x71, 0x11, 0xee, 0xcb, 0x19, 0xd0, 0x10, 0x97, 0x9e,
- 0x7e, 0xe6, 0x6e, 0x45, 0x5c, 0x59, 0xa7, 0xd0, 0x70, 0x75, 0xeb, 0x17,
- 0x3d, 0xfd, 0xf0, 0x4b, 0xc0, 0xa1, 0x9e, 0xfe, 0xef, 0xa8, 0x7c, 0xae,
- 0x54, 0xb1, 0xb4, 0x3b, 0x1c, 0xb7, 0x46, 0x74, 0xce, 0xbe, 0x5c, 0x8d,
- 0x68, 0xa0, 0x99, 0x75, 0x0d, 0xbf, 0x46, 0x74, 0x4e, 0x54, 0x8d, 0xe8,
- 0xe4, 0x15, 0x6a, 0x44, 0x99, 0xab, 0xaf, 0x11, 0x71, 0x7e, 0x53, 0xee,
- 0x1e, 0x10, 0xed, 0x4b, 0x5e, 0x8d, 0xe8, 0x82, 0xb8, 0x35, 0xa2, 0xf3,
- 0xb2, 0x7a, 0x8d, 0xe8, 0x68, 0x43, 0x8d, 0x68, 0xbd, 0xaa, 0x11, 0x71,
- 0x1e, 0xb7, 0x46, 0xc4, 0x76, 0xbe, 0x7f, 0x30, 0x50, 0xeb, 0x00, 0xfe,
- 0x3a, 0xb7, 0x82, 0x6f, 0x96, 0x36, 0xea, 0xf8, 0x98, 0x46, 0xec, 0xbf,
- 0xbe, 0xe6, 0xbf, 0xea, 0xf8, 0xa6, 0x29, 0x9d, 0xbb, 0x12, 0xbe, 0x8d,
- 0xba, 0x71, 0xc9, 0x32, 0x6c, 0x9b, 0xaa, 0xc5, 0x2e, 0xbf, 0xdc, 0xcc,
- 0x1c, 0x7a, 0xb2, 0x5c, 0x9f, 0x77, 0x12, 0xf2, 0x1e, 0xab, 0xd5, 0x49,
- 0x2e, 0x15, 0x1f, 0x45, 0xe5, 0xe0, 0xaa, 0xdf, 0x9a, 0x62, 0x99, 0x95,
- 0xdf, 0x9a, 0x34, 0x89, 0x82, 0xce, 0x7c, 0x7f, 0x5e, 0xe5, 0x5d, 0x0b,
- 0xce, 0xcf, 0xcb, 0xd2, 0xbd, 0x16, 0xf0, 0xc7, 0xaf, 0x9f, 0x50, 0xbe,
- 0x75, 0x9f, 0x92, 0xd5, 0x3f, 0xba, 0x1a, 0xca, 0x3e, 0x55, 0x43, 0xf9,
- 0x5a, 0x73, 0xb0, 0x86, 0x72, 0x4e, 0x2e, 0x5f, 0x43, 0xd9, 0xb7, 0x4a,
- 0x0d, 0xe5, 0x15, 0xa9, 0xd7, 0x50, 0x5e, 0x11, 0xbf, 0x86, 0x62, 0xc8,
- 0xd2, 0x7a, 0xce, 0xb3, 0x1f, 0xef, 0x8c, 0xe0, 0x37, 0x8c, 0x9f, 0x5b,
- 0x53, 0x39, 0x57, 0xa3, 0x7f, 0xb5, 0x9a, 0xca, 0x37, 0x9b, 0xdf, 0x4f,
- 0x4d, 0xc5, 0xf5, 0x01, 0x7e, 0x4d, 0xa5, 0x05, 0xf1, 0x0e, 0x7c, 0x8e,
- 0x1e, 0xac, 0xa9, 0xfc, 0x2d, 0xed, 0x01, 0x7d, 0x2a, 0x46, 0x40, 0x3f,
- 0xec, 0x02, 0x7e, 0x29, 0xa3, 0x6a, 0x1c, 0x9f, 0xf6, 0x78, 0xb8, 0x1b,
- 0x7b, 0x8e, 0x43, 0x16, 0xe4, 0x63, 0x8f, 0x8a, 0x2d, 0x33, 0x66, 0x4c,
- 0xcb, 0xf6, 0xc2, 0x9b, 0x4d, 0xf3, 0x5b, 0x74, 0x4c, 0xc6, 0x2b, 0xd4,
- 0xf1, 0x2e, 0xc4, 0xe2, 0x26, 0xfa, 0x76, 0xa3, 0xed, 0xc7, 0x54, 0xfd,
- 0xb5, 0x39, 0x68, 0x9b, 0x0b, 0xc0, 0x59, 0xe0, 0xc4, 0x55, 0xf8, 0xa8,
- 0x6d, 0xa0, 0x39, 0xb8, 0x8f, 0x22, 0xfc, 0x13, 0xfa, 0x94, 0xcc, 0x19,
- 0x5b, 0xfa, 0xb4, 0xc4, 0x69, 0xe7, 0x57, 0x31, 0x1f, 0xfb, 0xb6, 0xa9,
- 0x7c, 0xac, 0x30, 0xc0, 0xbd, 0xd2, 0xd7, 0x2d, 0x82, 0x3e, 0xf4, 0x95,
- 0x98, 0x03, 0xd2, 0xef, 0xf9, 0x39, 0x5a, 0x44, 0xe5, 0x68, 0x9d, 0x8a,
- 0x1f, 0xe4, 0xf5, 0x8d, 0x61, 0x62, 0x65, 0xa7, 0xcd, 0x3d, 0x0c, 0x7b,
- 0x58, 0xc7, 0xb6, 0x9b, 0x0b, 0x66, 0x74, 0xde, 0x3f, 0x02, 0xb9, 0xb2,
- 0x4e, 0xe3, 0xcb, 0xef, 0x21, 0x6f, 0xdf, 0x83, 0x52, 0xec, 0x94, 0xf0,
- 0x7a, 0xd0, 0x93, 0x9f, 0x61, 0xdc, 0xfd, 0x09, 0x95, 0x83, 0x44, 0xed,
- 0x4b, 0xdb, 0xed, 0x5d, 0xd7, 0x60, 0xb7, 0x23, 0x97, 0xb5, 0xdb, 0xcf,
- 0x85, 0x83, 0x76, 0x7b, 0xd7, 0x35, 0xd8, 0xed, 0xfe, 0x6b, 0xb2, 0x5b,
- 0xee, 0x8d, 0x98, 0xe4, 0xd7, 0xc4, 0x56, 0xc6, 0x59, 0xfe, 0xba, 0x13,
- 0x58, 0x33, 0x73, 0x89, 0x35, 0xc7, 0x2e, 0x59, 0x5b, 0x6d, 0x8c, 0xb1,
- 0xae, 0x46, 0xde, 0xcc, 0xad, 0xe8, 0x6f, 0x23, 0x9e, 0x5f, 0xba, 0xdd,
- 0xcb, 0xe7, 0xfd, 0xbc, 0x3e, 0x68, 0x3f, 0xd4, 0x0b, 0xea, 0xc2, 0x63,
- 0xe0, 0x17, 0xf5, 0xc1, 0xb7, 0xb9, 0x9e, 0x06, 0x1d, 0x5c, 0x44, 0xbe,
- 0xdf, 0xe3, 0xe9, 0x20, 0x65, 0xdd, 0xab, 0xbe, 0x11, 0x95, 0x9c, 0x47,
- 0xdc, 0x3c, 0x1f, 0x3a, 0x90, 0x2f, 0xf9, 0xb6, 0x06, 0x9e, 0x44, 0xfd,
- 0x67, 0xe4, 0xa3, 0x8d, 0x98, 0x67, 0x0b, 0xe2, 0x35, 0xf0, 0x48, 0xf5,
- 0x2f, 0xaf, 0x09, 0x5f, 0x1e, 0xcf, 0xa4, 0x18, 0xc2, 0xd8, 0x53, 0x03,
- 0xb0, 0xf1, 0x01, 0x62, 0x54, 0x1a, 0x79, 0x0f, 0xf5, 0x90, 0xba, 0xb9,
- 0x29, 0xb9, 0x43, 0x67, 0x4c, 0xb5, 0x07, 0xb6, 0x47, 0x7d, 0x8d, 0xcb,
- 0x8e, 0xca, 0xa6, 0x33, 0xe7, 0x74, 0xae, 0x51, 0xad, 0xe6, 0x99, 0x2b,
- 0x5a, 0xa2, 0x77, 0xf7, 0xff, 0x45, 0x98, 0x7e, 0xe9, 0x7a, 0xdb, 0xf0,
- 0x74, 0x2d, 0x83, 0x7b, 0xea, 0xed, 0xeb, 0xf0, 0xf7, 0xfc, 0xc6, 0xfe,
- 0x03, 0xf4, 0xc7, 0x60, 0xf3, 0xf4, 0xef, 0xcc, 0x47, 0xb6, 0x7a, 0xe3,
- 0x7a, 0xd4, 0xf7, 0xcf, 0x6c, 0xea, 0x56, 0xef, 0xbb, 0x13, 0xfd, 0x4f,
- 0x82, 0x3e, 0x7b, 0x99, 0x9c, 0x79, 0x46, 0x21, 0xa7, 0xf2, 0x19, 0xbe,
- 0xaf, 0x74, 0x12, 0x39, 0x88, 0x19, 0xa8, 0xa5, 0x87, 0xbd, 0xdc, 0x8d,
- 0x36, 0x16, 0x81, 0x0c, 0xb7, 0x7b, 0xb9, 0x0a, 0xf3, 0xd7, 0xe5, 0x67,
- 0x13, 0x56, 0xd7, 0x81, 0x0d, 0xef, 0x43, 0x07, 0x1a, 0xe5, 0x17, 0x86,
- 0xed, 0xfb, 0xf2, 0xf3, 0xe3, 0x98, 0x79, 0x6f, 0xdf, 0x3d, 0xae, 0x0c,
- 0x7f, 0x2c, 0xf6, 0xa9, 0x05, 0xf6, 0xe9, 0xe3, 0xd1, 0x3e, 0x6f, 0x9f,
- 0x5b, 0x1b, 0xf0, 0x68, 0xa4, 0xc1, 0x66, 0x3f, 0x4a, 0x3c, 0x3a, 0xb4,
- 0xe6, 0xa3, 0xc7, 0x23, 0xee, 0x6b, 0xe3, 0xaa, 0x38, 0xe4, 0xee, 0xe3,
- 0x77, 0x45, 0x4f, 0x7f, 0x98, 0xf9, 0xde, 0xfb, 0x91, 0x4f, 0x10, 0x47,
- 0x28, 0x93, 0x36, 0x15, 0xc3, 0xba, 0xb6, 0x07, 0x5f, 0x5e, 0x0a, 0xc9,
- 0x1b, 0xf7, 0x84, 0xe5, 0x7f, 0x6f, 0xe3, 0xf7, 0x30, 0xd3, 0xab, 0x69,
- 0xb1, 0xfd, 0xc2, 0x1a, 0xd7, 0x0f, 0xbd, 0xd0, 0xee, 0xfa, 0x1d, 0xbe,
- 0xe3, 0xdb, 0xb3, 0x85, 0xe7, 0x7c, 0xb6, 0x91, 0x5f, 0x4c, 0xae, 0x21,
- 0x07, 0xdc, 0x64, 0x5d, 0xd0, 0x57, 0xcb, 0x01, 0x2f, 0x5f, 0x0f, 0xac,
- 0xe7, 0x80, 0xc4, 0xd9, 0x0e, 0xa5, 0x1b, 0xf9, 0x28, 0x73, 0x1f, 0xc3,
- 0xc3, 0x4e, 0xde, 0x23, 0xb7, 0x75, 0x90, 0xef, 0x42, 0xb6, 0xcf, 0x21,
- 0x5e, 0x7a, 0xd6, 0x41, 0x8e, 0xeb, 0x20, 0xb7, 0x75, 0x90, 0xdb, 0x3a,
- 0xc8, 0x6d, 0x9d, 0xa4, 0x97, 0x23, 0x8f, 0x78, 0x75, 0x7f, 0x7e, 0xe3,
- 0x66, 0x7d, 0xa1, 0x08, 0x5f, 0x32, 0xc5, 0x73, 0x13, 0x7a, 0x36, 0xb5,
- 0xc6, 0xdb, 0x9f, 0x5f, 0x13, 0xef, 0xf2, 0x6a, 0x36, 0xdf, 0x54, 0x75,
- 0x43, 0xd1, 0x1f, 0x68, 0x71, 0xbf, 0x83, 0xf3, 0x7c, 0xc7, 0xaf, 0x21,
- 0x2e, 0x51, 0x67, 0x88, 0x68, 0xa3, 0x55, 0x3d, 0xcd, 0x9a, 0x8c, 0xe8,
- 0x7a, 0xfa, 0x16, 0xbc, 0xb3, 0xc5, 0xcd, 0x09, 0xa2, 0x62, 0xe8, 0xe9,
- 0x56, 0xf2, 0x54, 0xd3, 0xd3, 0x6b, 0xbd, 0xb9, 0xf6, 0xb7, 0xb8, 0xb1,
- 0x55, 0x2f, 0xdb, 0xa6, 0xce, 0x38, 0x41, 0xc5, 0xda, 0x7e, 0xff, 0xc5,
- 0xf6, 0xe5, 0x6b, 0x85, 0x14, 0xbe, 0x67, 0x53, 0xf7, 0x62, 0x3e, 0xb6,
- 0xeb, 0xfc, 0xd6, 0x2f, 0xc9, 0xef, 0x90, 0xc7, 0x6f, 0x97, 0xc7, 0x06,
- 0xc7, 0xa9, 0xba, 0x30, 0x79, 0xed, 0xcf, 0xa7, 0xea, 0x7a, 0x58, 0x47,
- 0x9d, 0xcd, 0xc0, 0xf5, 0x07, 0xa6, 0xb4, 0x8d, 0xee, 0x0e, 0xd9, 0xc1,
- 0x75, 0xfd, 0x6f, 0xe2, 0x57, 0xb3, 0x66, 0x8f, 0xfa, 0x8e, 0xe6, 0xfa,
- 0x8c, 0x90, 0xd2, 0x41, 0x33, 0xcd, 0x7d, 0xfd, 0x50, 0x9d, 0xa9, 0xa1,
- 0xfe, 0xe5, 0x90, 0xc7, 0x4c, 0x0d, 0x6c, 0x8a, 0x9b, 0xfa, 0x48, 0x0b,
- 0xeb, 0xaf, 0x43, 0x15, 0x1f, 0xf7, 0xb8, 0x5e, 0xa3, 0x1f, 0x67, 0x5d,
- 0xcd, 0xc7, 0x33, 0xd9, 0xe0, 0xd6, 0xdb, 0x3e, 0x88, 0x2d, 0xb5, 0x34,
- 0xd8, 0x92, 0xbf, 0x4f, 0xee, 0x9f, 0xd7, 0xd5, 0xcf, 0x43, 0x2c, 0x56,
- 0x02, 0xdf, 0x47, 0x6a, 0xba, 0xc1, 0xb3, 0x2a, 0x9f, 0x85, 0x0e, 0xf2,
- 0xdb, 0xc0, 0x4e, 0xd8, 0x51, 0xb5, 0x3a, 0xc4, 0x1a, 0x73, 0xdf, 0x67,
- 0x54, 0x7e, 0xa9, 0xa7, 0xe7, 0x55, 0xfd, 0xc1, 0x5c, 0x51, 0x7f, 0x18,
- 0x82, 0xae, 0x20, 0x06, 0x70, 0xda, 0x54, 0x4c, 0xa7, 0xe2, 0x85, 0x4a,
- 0xe3, 0xf7, 0x97, 0xfb, 0x5b, 0x5d, 0x3e, 0xfc, 0x5d, 0x8b, 0xfb, 0x0d,
- 0xe2, 0x8f, 0xa2, 0xcb, 0xdb, 0x7c, 0xff, 0xaf, 0x5b, 0xfc, 0xb3, 0x3b,
- 0x85, 0x13, 0x43, 0xd0, 0x45, 0xe4, 0xe4, 0x6a, 0x3e, 0xc4, 0xbb, 0x4f,
- 0xcc, 0x76, 0x2c, 0x1f, 0x8f, 0xbe, 0x13, 0xfe, 0xf8, 0x8e, 0x86, 0xf1,
- 0x1d, 0x18, 0xff, 0x7b, 0x0d, 0xe3, 0x3b, 0x02, 0xe3, 0xa3, 0x0d, 0xe3,
- 0xa3, 0x18, 0xff, 0x7c, 0xc3, 0xf8, 0x68, 0x60, 0x7c, 0x67, 0xc3, 0xf8,
- 0x4e, 0x8c, 0x7f, 0xa1, 0x61, 0x3c, 0xfa, 0x4e, 0x34, 0x79, 0xdf, 0xc5,
- 0x88, 0xb1, 0xfb, 0xbd, 0x5c, 0x1c, 0xd7, 0x72, 0xe3, 0xb7, 0x16, 0xea,
- 0x5d, 0x17, 0x64, 0xe0, 0x9f, 0xa7, 0xa3, 0xbd, 0x66, 0x60, 0xaf, 0xf5,
- 0x58, 0xc6, 0xd5, 0xc7, 0xa0, 0x2e, 0x12, 0x1f, 0x8a, 0x62, 0xd8, 0xd0,
- 0x9d, 0x12, 0x74, 0xa8, 0xe4, 0xfb, 0x24, 0x9e, 0x83, 0xe2, 0x19, 0x53,
- 0xd7, 0xf7, 0x86, 0xec, 0x45, 0x2f, 0x07, 0x7b, 0x9b, 0xb4, 0x03, 0x2f,
- 0x7d, 0xcc, 0x94, 0x63, 0xae, 0xdd, 0x50, 0x7f, 0x39, 0xbf, 0x67, 0x3f,
- 0xd4, 0x55, 0x6f, 0x9d, 0xa1, 0x15, 0xb8, 0x16, 0x5f, 0x51, 0xdb, 0x32,
- 0xae, 0x02, 0xd7, 0x46, 0x6a, 0xb8, 0xf6, 0x59, 0x99, 0xaf, 0xe5, 0xdb,
- 0xc3, 0x72, 0xc0, 0xd9, 0xc5, 0x33, 0x36, 0xc7, 0x32, 0xf2, 0xe1, 0xe4,
- 0xdb, 0xbb, 0x6a, 0x7e, 0x92, 0x67, 0x3a, 0x96, 0x0e, 0x31, 0x87, 0xf2,
- 0x6b, 0xb3, 0x53, 0xce, 0xcf, 0xb6, 0x42, 0x2e, 0xb0, 0x8d, 0x6b, 0xcd,
- 0xb7, 0x39, 0x5f, 0x54, 0x0e, 0xb8, 0xe7, 0x1d, 0x6a, 0xf3, 0x16, 0x6b,
- 0xf3, 0xc6, 0x3c, 0x7b, 0xa3, 0x0f, 0xae, 0xfb, 0xcb, 0x1c, 0xfc, 0xe5,
- 0x18, 0x72, 0xee, 0x45, 0x67, 0xb5, 0xfa, 0xe8, 0xb5, 0xfa, 0xcb, 0xc6,
- 0x3a, 0x73, 0xa3, 0xbf, 0xe4, 0x3a, 0x8d, 0xb5, 0xe5, 0x78, 0x03, 0xfe,
- 0x53, 0x9f, 0x0e, 0x7b, 0x31, 0x35, 0xae, 0xa5, 0xc3, 0xb0, 0x47, 0x5d,
- 0xc6, 0x94, 0xfe, 0xb2, 0xed, 0xe7, 0x96, 0xbb, 0x6b, 0xb9, 0x65, 0x3d,
- 0x1f, 0x44, 0xec, 0x9a, 0xfc, 0xa4, 0x87, 0x8f, 0x8c, 0x91, 0xa7, 0xd0,
- 0x7f, 0x0c, 0x3a, 0xc0, 0x67, 0xac, 0x97, 0xde, 0x2c, 0x9f, 0x32, 0x5d,
- 0xff, 0xe4, 0xd6, 0xa6, 0x76, 0xab, 0xf8, 0x9f, 0xdf, 0x0b, 0x0a, 0xa9,
- 0x76, 0x2f, 0xde, 0xbb, 0x12, 0xae, 0x2e, 0xcf, 0x4d, 0x75, 0xfd, 0x51,
- 0xbc, 0xcb, 0xdc, 0xd4, 0x8c, 0x10, 0x43, 0xb3, 0x95, 0xcb, 0xbe, 0x5f,
- 0xa4, 0x7f, 0x29, 0xa8, 0xef, 0x82, 0x2a, 0x0f, 0xc5, 0xb8, 0x45, 0xef,
- 0x7d, 0x37, 0x0f, 0xcd, 0x56, 0xbe, 0xdd, 0xea, 0xe2, 0xe0, 0xe5, 0x72,
- 0x96, 0x9f, 0x88, 0xb0, 0xae, 0xb7, 0xe8, 0x5c, 0x89, 0xd6, 0x95, 0x79,
- 0xaf, 0xb1, 0x22, 0xef, 0x1d, 0xf5, 0xf2, 0xda, 0xcf, 0xa9, 0xbc, 0xd7,
- 0xe5, 0x31, 0xf7, 0x12, 0xcc, 0xa3, 0x6c, 0x60, 0x21, 0xbf, 0xa9, 0x10,
- 0x1f, 0x26, 0x94, 0xdf, 0xca, 0x4f, 0xdf, 0x09, 0x3e, 0x47, 0x57, 0xd1,
- 0x9b, 0x8f, 0xda, 0x4f, 0xf8, 0x7b, 0x3f, 0x2c, 0x6e, 0xbd, 0x6e, 0x27,
- 0x68, 0x61, 0x6e, 0x15, 0xf2, 0xf4, 0xe1, 0xbb, 0xde, 0x39, 0x53, 0x7f,
- 0x9c, 0x9f, 0xc7, 0xd7, 0xbe, 0xbb, 0x16, 0x33, 0xcb, 0xea, 0x27, 0x1b,
- 0x09, 0xc3, 0x90, 0x7b, 0xe6, 0x1a, 0xbe, 0x5b, 0x7c, 0x90, 0xf3, 0x11,
- 0x8d, 0x7e, 0x8d, 0xdf, 0x4d, 0xf9, 0xad, 0x54, 0xb4, 0xbb, 0x7b, 0x6d,
- 0xd8, 0x00, 0xcf, 0x2c, 0x07, 0xf1, 0x35, 0x2c, 0xf9, 0x39, 0x09, 0x47,
- 0xd3, 0xfc, 0x06, 0x40, 0xff, 0xff, 0xba, 0xb7, 0xcf, 0x98, 0xec, 0x9f,
- 0x71, 0x6b, 0x9e, 0xfa, 0x65, 0xcf, 0xc5, 0x1d, 0x00, 0x1f, 0x12, 0x47,
- 0xfd, 0x9a, 0xa7, 0xee, 0x9e, 0x8b, 0x3b, 0xfa, 0xe1, 0x9d, 0x8b, 0xe3,
- 0xfc, 0xa6, 0xec, 0x5a, 0xe5, 0x5c, 0x9c, 0x71, 0x95, 0xe7, 0xe2, 0xda,
- 0x55, 0xcd, 0x93, 0xf3, 0xb8, 0x35, 0x4f, 0xb6, 0xbb, 0xfb, 0x59, 0x2b,
- 0xe1, 0xd9, 0xb7, 0x01, 0x75, 0x06, 0xb9, 0xbb, 0xff, 0x47, 0x91, 0xa3,
- 0x7c, 0x3d, 0xf2, 0xd1, 0xe7, 0x28, 0xdc, 0xcb, 0xaf, 0xb8, 0xdf, 0x77,
- 0xe5, 0x5a, 0xea, 0x00, 0x1f, 0xac, 0xae, 0xb9, 0x5f, 0xd5, 0x35, 0xbf,
- 0x13, 0x09, 0xd6, 0x35, 0xf5, 0x2b, 0x9c, 0x0d, 0xdb, 0xbf, 0x4a, 0x5d,
- 0x33, 0x14, 0x38, 0x1b, 0x16, 0xf2, 0xce, 0x86, 0xb5, 0xdb, 0xc8, 0x25,
- 0xbd, 0x3a, 0xa6, 0x7e, 0xd9, 0xb3, 0x61, 0xff, 0x19, 0xf9, 0xe0, 0x75,
- 0xcc, 0x15, 0x67, 0xc3, 0xe0, 0xeb, 0x36, 0x48, 0xfc, 0x9a, 0xf2, 0x9e,
- 0x0f, 0x92, 0xf3, 0xf0, 0xbc, 0x7e, 0x13, 0xf6, 0x1c, 0x92, 0x5d, 0x51,
- 0xea, 0x27, 0xcf, 0x36, 0xf6, 0xc2, 0x16, 0x70, 0xad, 0xb0, 0x9d, 0xa4,
- 0x8c, 0xb4, 0x91, 0xde, 0xe5, 0xe7, 0x10, 0xea, 0xe7, 0x71, 0xc3, 0xb5,
- 0xf3, 0xb8, 0x47, 0xa0, 0x37, 0xfa, 0x4c, 0x58, 0x16, 0x02, 0x3a, 0x35,
- 0x85, 0x78, 0x4f, 0x9f, 0xb3, 0xbc, 0xe7, 0xfc, 0x9f, 0x8a, 0x28, 0x30,
- 0x8f, 0x67, 0x78, 0xdb, 0xc4, 0x98, 0x73, 0xbf, 0x59, 0xba, 0xff, 0x57,
- 0x12, 0xc3, 0x18, 0x9e, 0xf1, 0x0c, 0xc9, 0x01, 0x55, 0xb3, 0xf0, 0x75,
- 0x79, 0xc7, 0x5a, 0x69, 0x59, 0x9f, 0xa9, 0xb7, 0xa3, 0xab, 0xf8, 0x7d,
- 0xc4, 0x91, 0x33, 0xd4, 0xe7, 0x5b, 0x25, 0xe7, 0xd5, 0x83, 0x0a, 0x95,
- 0x6d, 0x5e, 0x7e, 0xa1, 0xbe, 0xed, 0x80, 0x97, 0xdd, 0x9e, 0x0f, 0xc6,
- 0xb5, 0xd4, 0x4d, 0x9f, 0x87, 0x35, 0x4e, 0xca, 0xd0, 0xf4, 0x96, 0xd8,
- 0x38, 0xf0, 0x6e, 0x4c, 0xad, 0x79, 0x2d, 0x3c, 0xd7, 0x2e, 0xf1, 0xbd,
- 0xf1, 0x6a, 0xf9, 0xee, 0xc7, 0xc7, 0x8f, 0x62, 0x7f, 0xdd, 0xd0, 0x8f,
- 0x87, 0x25, 0x77, 0xe2, 0x66, 0x19, 0x9a, 0x4d, 0x80, 0x9e, 0x1f, 0x56,
- 0x0b, 0x29, 0xc4, 0xd2, 0x4f, 0xf0, 0xdc, 0x18, 0x30, 0x14, 0x7c, 0x7b,
- 0x66, 0xc5, 0x77, 0xec, 0xe0, 0x59, 0xb3, 0x64, 0xed, 0xec, 0xd0, 0x53,
- 0x15, 0x09, 0x77, 0x90, 0xe6, 0x99, 0xfa, 0xd9, 0xef, 0xc5, 0xca, 0x0e,
- 0xe5, 0xdb, 0x9e, 0xac, 0x2c, 0xab, 0xfd, 0x28, 0x19, 0x4e, 0x94, 0x9f,
- 0x04, 0x2f, 0x5e, 0x51, 0xfe, 0xed, 0x88, 0x23, 0x37, 0x19, 0x42, 0x79,
- 0x88, 0x06, 0x1e, 0xa8, 0x33, 0x1c, 0xee, 0xf7, 0xfd, 0x2e, 0x25, 0x57,
- 0x17, 0x2b, 0x76, 0x06, 0xce, 0x60, 0xd4, 0x65, 0xeb, 0x9e, 0xcd, 0x70,
- 0x65, 0xe1, 0x9e, 0x1f, 0x21, 0x3f, 0x97, 0x0e, 0xed, 0xb2, 0xdd, 0xf3,
- 0x23, 0x3d, 0x73, 0xec, 0xeb, 0x6c, 0xf0, 0x7d, 0x61, 0xe8, 0x00, 0xcf,
- 0x1d, 0xf1, 0xcc, 0x37, 0x69, 0x56, 0xb5, 0x8e, 0x55, 0xbf, 0x6d, 0x5f,
- 0x5b, 0xcd, 0xd5, 0x5d, 0xb3, 0x5b, 0xad, 0x79, 0x9d, 0x87, 0x59, 0xfe,
- 0x59, 0xef, 0x94, 0xf6, 0xff, 0xd4, 0x5d, 0x7b, 0x6c, 0x1b, 0xf7, 0x7d,
- 0xff, 0xf2, 0x48, 0x3d, 0xac, 0xe7, 0x49, 0xa6, 0x64, 0x5a, 0x52, 0x94,
- 0x3b, 0xe9, 0x64, 0x29, 0xb1, 0x12, 0x70, 0x9e, 0xba, 0x0a, 0x88, 0x9a,
- 0xb0, 0x24, 0xfd, 0x58, 0x10, 0x0c, 0xb4, 0xad, 0x64, 0xee, 0x92, 0xad,
- 0x0e, 0x25, 0xa7, 0x1d, 0x30, 0x60, 0x6e, 0xd6, 0x02, 0x69, 0x07, 0xc7,
- 0x0c, 0x65, 0x27, 0xc6, 0xaa, 0x88, 0x4c, 0xcc, 0x6a, 0x1d, 0xb0, 0x62,
- 0x1c, 0xa5, 0x38, 0x69, 0xa7, 0x80, 0x69, 0xda, 0x04, 0xc5, 0xfe, 0xb1,
- 0x26, 0x3b, 0x7b, 0x61, 0x7f, 0x04, 0xdb, 0x80, 0x1a, 0x5b, 0x81, 0xba,
- 0x76, 0x8a, 0x65, 0x1b, 0xe0, 0x34, 0xdb, 0xb0, 0x75, 0x58, 0x0b, 0xee,
- 0xfb, 0xf9, 0x3d, 0xc8, 0x23, 0x79, 0xd4, 0xc3, 0x71, 0x06, 0x4c, 0x80,
- 0x40, 0xde, 0xf1, 0x77, 0x77, 0xbf, 0xdf, 0xf7, 0xf7, 0x7d, 0xbf, 0x6e,
- 0x2e, 0x33, 0x1e, 0xf2, 0x33, 0x7e, 0xcf, 0x15, 0x61, 0x5f, 0x37, 0xd2,
- 0xe1, 0x36, 0x83, 0x67, 0xa4, 0x0e, 0x9e, 0xd5, 0x34, 0xc1, 0xf6, 0x78,
- 0x99, 0x77, 0x4b, 0xd8, 0xc9, 0xf3, 0xc8, 0x63, 0xd7, 0x39, 0x0e, 0x12,
- 0x76, 0x65, 0x1a, 0x5a, 0x72, 0xe7, 0x37, 0x54, 0x60, 0x77, 0xb2, 0x0c,
- 0xbb, 0x3d, 0xff, 0x8f, 0x60, 0x77, 0x4d, 0xe8, 0xbf, 0xdf, 0x2e, 0x22,
- 0x6f, 0x4d, 0xeb, 0x00, 0xba, 0x6e, 0x09, 0x70, 0x04, 0x3f, 0xb5, 0xf3,
- 0xeb, 0x04, 0x9e, 0x8a, 0xbc, 0xe2, 0x52, 0xe9, 0x3b, 0xe1, 0xb2, 0x9f,
- 0x92, 0xed, 0x12, 0xd8, 0x27, 0xf0, 0xe7, 0x35, 0x96, 0x91, 0x47, 0x6f,
- 0x4b, 0x46, 0x42, 0x57, 0xaa, 0xb5, 0x4f, 0x7e, 0xbb, 0xcb, 0x6d, 0x9f,
- 0x1c, 0xdd, 0xa1, 0x7d, 0x72, 0x5a, 0xda, 0x27, 0xa9, 0xed, 0xdb, 0x27,
- 0x03, 0x75, 0x79, 0x5d, 0x95, 0xf5, 0xec, 0xdc, 0x3e, 0x31, 0x36, 0xb5,
- 0x4f, 0x46, 0x5d, 0xbe, 0x18, 0xcc, 0xf7, 0x57, 0x29, 0x75, 0x0c, 0x3c,
- 0x4e, 0xc3, 0x19, 0x30, 0x3e, 0x56, 0xe3, 0x17, 0xfe, 0x38, 0x61, 0xfd,
- 0xd7, 0xff, 0xc7, 0xb0, 0x1e, 0xac, 0xf3, 0x79, 0x57, 0xd6, 0x03, 0x21,
- 0xfe, 0x51, 0x60, 0x3d, 0xd8, 0xd0, 0x77, 0xda, 0x38, 0x67, 0xb1, 0xda,
- 0x77, 0x3a, 0x62, 0x34, 0xe2, 0xed, 0x7f, 0xe4, 0xf2, 0xa9, 0xba, 0xf9,
- 0x3b, 0x68, 0x8a, 0x7c, 0x47, 0xc7, 0xf5, 0xb3, 0x40, 0x4b, 0x76, 0x2a,
- 0x45, 0xb0, 0x99, 0xf0, 0xbc, 0x90, 0xa0, 0xb5, 0x1a, 0x7d, 0x8b, 0x9f,
- 0xc7, 0xeb, 0x7b, 0xf5, 0x09, 0x21, 0xa7, 0xa4, 0xff, 0x01, 0xe3, 0x27,
- 0x7c, 0xf3, 0x62, 0xac, 0xcc, 0x6f, 0x52, 0xfe, 0x08, 0xa5, 0xfb, 0x37,
- 0xf2, 0x43, 0xd4, 0xcb, 0xbc, 0x9d, 0xd9, 0x0a, 0x9a, 0xc6, 0xef, 0xe6,
- 0x7d, 0x09, 0x55, 0xd9, 0x5a, 0xe0, 0x9f, 0xa7, 0x59, 0x2f, 0x18, 0x29,
- 0xeb, 0x04, 0xd5, 0x7b, 0x73, 0x4e, 0xd8, 0x74, 0x9a, 0x77, 0x26, 0x64,
- 0xee, 0xa9, 0x38, 0x0f, 0x3d, 0x4d, 0xf3, 0xce, 0x5a, 0x3d, 0xf8, 0x6e,
- 0x0f, 0xbc, 0xf0, 0xca, 0x69, 0x2a, 0xef, 0x9d, 0x85, 0x9c, 0xf3, 0xb8,
- 0xe7, 0xde, 0x95, 0x6b, 0xc2, 0x52, 0x95, 0xb1, 0xf2, 0xfa, 0xb8, 0x58,
- 0xd7, 0x0f, 0x8e, 0x44, 0x51, 0xfb, 0x56, 0xae, 0x17, 0xab, 0xad, 0x77,
- 0x82, 0x1c, 0xd0, 0x74, 0xa8, 0x6b, 0xa2, 0x01, 0x8b, 0x61, 0x8f, 0x7a,
- 0x27, 0xb7, 0x2c, 0xc1, 0x75, 0xb5, 0xb0, 0xa8, 0xc8, 0x91, 0xf3, 0x4a,
- 0x8e, 0x14, 0x5c, 0x7c, 0xbc, 0x5e, 0x6f, 0xef, 0xf5, 0xd0, 0xdb, 0xbd,
- 0x6a, 0x9e, 0x30, 0xa7, 0x67, 0x58, 0x0f, 0xb9, 0x1f, 0x7a, 0x88, 0x89,
- 0xba, 0x25, 0xa9, 0x8b, 0xe0, 0x77, 0x96, 0x35, 0xaf, 0x86, 0x18, 0x57,
- 0x8e, 0xd0, 0x53, 0xac, 0x6b, 0x5f, 0xa2, 0x7b, 0x94, 0x7d, 0x16, 0x71,
- 0xe5, 0x99, 0x22, 0x8f, 0xdf, 0x47, 0xa9, 0x27, 0xec, 0x89, 0x08, 0x1d,
- 0xa1, 0x53, 0x22, 0x67, 0x06, 0xf1, 0x3d, 0xe4, 0x1c, 0xdc, 0x2b, 0x9e,
- 0x2f, 0x7d, 0x19, 0x77, 0x22, 0xa7, 0x6e, 0xfb, 0xf9, 0xfb, 0xba, 0x56,
- 0x2f, 0x2a, 0x9e, 0xb9, 0xaa, 0x68, 0x4a, 0x9c, 0xe3, 0xeb, 0x9f, 0x31,
- 0xea, 0xaf, 0x8f, 0x18, 0xf1, 0x62, 0xdc, 0x88, 0xae, 0x60, 0xdc, 0x33,
- 0x46, 0xac, 0x08, 0x1b, 0x52, 0xe3, 0x88, 0x1d, 0x06, 0xbd, 0x6d, 0xd0,
- 0xd6, 0xb1, 0x88, 0x02, 0xd5, 0xd4, 0x49, 0x6c, 0x63, 0xde, 0x87, 0xaa,
- 0xe6, 0xad, 0xe1, 0x8b, 0xef, 0xf0, 0xf7, 0x44, 0x18, 0xa6, 0x5a, 0xaf,
- 0x6d, 0x83, 0x7f, 0x7d, 0x22, 0x45, 0x9b, 0xe9, 0xb5, 0x76, 0x9d, 0x5e,
- 0x5b, 0xd8, 0x72, 0xde, 0x1f, 0x95, 0xc6, 0x65, 0x3d, 0xa2, 0xdf, 0x11,
- 0xfa, 0x2b, 0xcf, 0xbb, 0x4a, 0xb7, 0xad, 0xc1, 0x29, 0x8c, 0xd1, 0x7e,
- 0x70, 0xed, 0x07, 0xeb, 0x52, 0xf9, 0xc0, 0x3a, 0x3f, 0xa1, 0x0d, 0xf5,
- 0x5e, 0xa6, 0xcc, 0x6b, 0x85, 0x8d, 0xb5, 0xce, 0xf3, 0x83, 0xbd, 0xf5,
- 0xa0, 0x98, 0x23, 0xdb, 0x5b, 0x56, 0x8c, 0xa4, 0xaf, 0x7b, 0xbe, 0x58,
- 0x55, 0xff, 0xe9, 0x51, 0x07, 0x39, 0xe2, 0x51, 0x07, 0xe9, 0xa6, 0xb5,
- 0x80, 0x8b, 0xd6, 0x42, 0x2e, 0xbd, 0x6d, 0x88, 0xed, 0x96, 0x0e, 0xe6,
- 0x21, 0xb0, 0x5b, 0xda, 0xc8, 0xff, 0xb2, 0xdb, 0x6e, 0xa9, 0xad, 0x45,
- 0x07, 0xdd, 0x41, 0x37, 0x93, 0x36, 0x4c, 0x3c, 0x57, 0xae, 0x63, 0xe7,
- 0x75, 0x57, 0x6a, 0x0e, 0x57, 0xea, 0xea, 0x23, 0xbd, 0xe6, 0x3b, 0x5c,
- 0x37, 0x5f, 0xc8, 0xaf, 0x48, 0x43, 0x9d, 0xce, 0xcb, 0xae, 0xba, 0x53,
- 0xf3, 0xab, 0xe5, 0x67, 0x78, 0xd6, 0x88, 0xf0, 0x79, 0xa7, 0xca, 0xbc,
- 0x6c, 0x5a, 0xce, 0x37, 0x53, 0x6d, 0x67, 0xf8, 0x97, 0x48, 0xc1, 0xce,
- 0x9b, 0xb7, 0xef, 0xcc, 0x7f, 0xd6, 0x5e, 0x23, 0x77, 0xdf, 0x33, 0xa5,
- 0x5f, 0xac, 0x49, 0xe5, 0x61, 0xf7, 0x29, 0x7b, 0x6f, 0x2b, 0x7c, 0xc7,
- 0xb9, 0x26, 0xe5, 0x4b, 0xb4, 0xad, 0x3c, 0x01, 0xcf, 0x8f, 0x9d, 0x68,
- 0x72, 0x4c, 0x15, 0xcb, 0x42, 0xbc, 0x0a, 0x78, 0xaf, 0xef, 0x0f, 0x9e,
- 0xbd, 0x9d, 0x3d, 0xb3, 0xea, 0xf6, 0x4c, 0xe2, 0x15, 0x6c, 0x2d, 0xe4,
- 0x17, 0x4f, 0xd6, 0xe4, 0x78, 0x7f, 0x14, 0x58, 0x74, 0x79, 0xe4, 0x3d,
- 0x23, 0x6f, 0xb9, 0xd1, 0x3c, 0xaf, 0xbb, 0xf4, 0x72, 0xcc, 0xb7, 0x54,
- 0x7a, 0x23, 0x3c, 0x20, 0x65, 0x71, 0xd1, 0x5b, 0x47, 0x32, 0xb7, 0x3d,
- 0xbf, 0x5a, 0xd9, 0xbb, 0x77, 0x9b, 0xb2, 0x57, 0xf4, 0xf4, 0xf0, 0x1d,
- 0x14, 0x3c, 0xa0, 0x83, 0x56, 0x72, 0xc8, 0xbf, 0xfe, 0x05, 0xd0, 0x3c,
- 0xf3, 0x59, 0x57, 0x4d, 0x9a, 0xf7, 0x3e, 0x96, 0x63, 0x2a, 0x81, 0x19,
- 0xc4, 0xfe, 0x90, 0x5b, 0xd2, 0xcb, 0xbc, 0x07, 0xe3, 0xc7, 0xac, 0xab,
- 0xf0, 0xf7, 0x2a, 0xff, 0x53, 0x5c, 0xc9, 0x97, 0x83, 0xdb, 0x88, 0xad,
- 0xec, 0x8c, 0x4f, 0xdb, 0xd6, 0x3a, 0x21, 0xee, 0x83, 0x7c, 0xe1, 0xfb,
- 0xba, 0xa8, 0xeb, 0x33, 0x2d, 0x2d, 0xce, 0x97, 0x7a, 0x64, 0x2c, 0x0a,
- 0xbf, 0x75, 0xd0, 0x2b, 0x39, 0xe4, 0x72, 0xe3, 0xb7, 0xdf, 0xe0, 0xdf,
- 0xbc, 0x78, 0x94, 0xce, 0x45, 0x87, 0x2e, 0x27, 0xf7, 0x27, 0x4f, 0xb0,
- 0x95, 0x4a, 0xf4, 0xb7, 0xe1, 0x5f, 0x94, 0xf1, 0x8c, 0xe2, 0x9d, 0x8e,
- 0xd5, 0x78, 0xf9, 0x0b, 0xdf, 0xec, 0xb9, 0xdd, 0xdc, 0xc8, 0x2f, 0x6c,
- 0xcb, 0x5f, 0x88, 0x38, 0xff, 0x76, 0x62, 0x26, 0x3a, 0x36, 0x3c, 0x25,
- 0x6a, 0x4e, 0xdd, 0x78, 0x70, 0x67, 0xe2, 0xc3, 0xc0, 0x87, 0xe1, 0x3a,
- 0x5e, 0xf5, 0xd1, 0xfd, 0xfd, 0xb5, 0x70, 0x6d, 0xf3, 0xf4, 0x55, 0x79,
- 0xc7, 0x81, 0x11, 0xf3, 0x87, 0x9f, 0xfa, 0x21, 0x9a, 0xbf, 0x08, 0x1c,
- 0x36, 0x18, 0xdb, 0x46, 0x69, 0x21, 0x88, 0xba, 0x22, 0x51, 0x9b, 0xa3,
- 0xe2, 0x86, 0xb2, 0x56, 0x68, 0x5e, 0xd4, 0x40, 0x8e, 0x85, 0x6e, 0xf2,
- 0xbc, 0xe7, 0x8b, 0x29, 0x3a, 0xc5, 0x32, 0xf6, 0xd4, 0x4a, 0x45, 0x77,
- 0xaf, 0xaf, 0x83, 0xac, 0xc6, 0xf1, 0x9b, 0x02, 0xc7, 0x87, 0x36, 0xc5,
- 0xf1, 0xc3, 0x65, 0x1c, 0xff, 0x44, 0xaf, 0xc4, 0xe7, 0x67, 0xf9, 0x5e,
- 0x5d, 0x74, 0x50, 0xdc, 0x37, 0xc5, 0xdf, 0xdb, 0xe9, 0xa0, 0xec, 0x61,
- 0xc1, 0xcf, 0x66, 0x1e, 0x9f, 0x49, 0xd1, 0x53, 0x17, 0x53, 0xbe, 0xb8,
- 0xa8, 0x5f, 0x70, 0xf7, 0xe8, 0xd0, 0xd7, 0x63, 0x5c, 0x23, 0xfc, 0xd7,
- 0x7c, 0x49, 0xd6, 0x5c, 0xe5, 0x25, 0x7f, 0xa2, 0x77, 0xc3, 0x83, 0x35,
- 0xf8, 0x5f, 0x6d, 0x3b, 0x9e, 0x56, 0x32, 0xf0, 0xd8, 0x26, 0x7e, 0x8d,
- 0x7a, 0xbc, 0xec, 0xf1, 0xd0, 0x87, 0x7f, 0xbd, 0x57, 0xc6, 0xa9, 0x36,
- 0xf3, 0x6b, 0xb8, 0x71, 0xb4, 0x2a, 0x6e, 0xcf, 0x7c, 0xff, 0xbf, 0x55,
- 0x1c, 0xfd, 0xa5, 0x5e, 0x29, 0x2f, 0x50, 0x1f, 0x98, 0x60, 0x38, 0x9c,
- 0x64, 0x5d, 0x65, 0x90, 0x9a, 0x5f, 0xd6, 0x6b, 0x1d, 0x14, 0xfc, 0xd6,
- 0xed, 0xa7, 0x39, 0xa7, 0x6a, 0xbb, 0xd3, 0xae, 0x35, 0x9d, 0x13, 0x36,
- 0x4e, 0x63, 0x7a, 0x6b, 0x9c, 0x73, 0x35, 0x54, 0x23, 0x13, 0x6a, 0xf1,
- 0x0d, 0xbd, 0x4f, 0xb0, 0xbf, 0x64, 0x48, 0x3d, 0x78, 0x9a, 0xf5, 0xdb,
- 0x9d, 0xc6, 0x8b, 0x3e, 0xaa, 0x8e, 0x58, 0xdb, 0x53, 0xa3, 0xf6, 0x3b,
- 0xf6, 0x41, 0xda, 0x1c, 0xc9, 0x57, 0x1f, 0x12, 0xbc, 0xe0, 0xdc, 0x64,
- 0x89, 0x62, 0xe1, 0x4e, 0x4a, 0x4e, 0xf2, 0xb3, 0xa7, 0x1d, 0xb6, 0xbd,
- 0xfc, 0x94, 0x62, 0xfa, 0x4d, 0x4e, 0xee, 0x52, 0xfa, 0xa2, 0xf6, 0xa7,
- 0xb7, 0xa8, 0x3c, 0x87, 0x67, 0x45, 0x5c, 0x52, 0xf6, 0xc6, 0xe0, 0xef,
- 0x2b, 0xfa, 0xde, 0xcf, 0x8a, 0xf8, 0x68, 0xf2, 0x62, 0xb3, 0x1a, 0xd7,
- 0xee, 0x1a, 0x87, 0x31, 0xed, 0x6a, 0x2c, 0xee, 0xa9, 0x75, 0x8a, 0x56,
- 0xc5, 0x6f, 0x1f, 0x11, 0x75, 0x60, 0xb2, 0x56, 0x0f, 0xbf, 0x9f, 0xa6,
- 0xb9, 0xf2, 0x5a, 0xda, 0x79, 0xec, 0xcf, 0x4a, 0x11, 0x61, 0xcb, 0xb5,
- 0xb3, 0xce, 0x8b, 0x79, 0xd7, 0xcf, 0x09, 0x6b, 0xf1, 0x8b, 0xf8, 0x10,
- 0x7f, 0x57, 0xcf, 0x39, 0x59, 0x9e, 0x13, 0x72, 0x34, 0xec, 0x90, 0xbc,
- 0x97, 0x1e, 0xd7, 0xee, 0x1a, 0xa7, 0x79, 0x85, 0x8e, 0x3f, 0xfc, 0x80,
- 0xe7, 0xf1, 0x37, 0x2a, 0x87, 0xd7, 0x14, 0xf1, 0x53, 0x99, 0xa3, 0xa1,
- 0xbf, 0xc3, 0xbf, 0x8c, 0x9c, 0x0a, 0xe4, 0x49, 0xb8, 0xf9, 0x8d, 0x5c,
- 0x6f, 0x00, 0xb2, 0xa8, 0x88, 0xb8, 0x29, 0xe2, 0x15, 0x8d, 0x74, 0xe7,
- 0xbd, 0xc8, 0xcd, 0xdf, 0x81, 0x0e, 0xba, 0x1d, 0xfa, 0xb3, 0x3c, 0xe8,
- 0xcf, 0xfd, 0x7c, 0xd4, 0xc1, 0xa1, 0x1e, 0x2e, 0x35, 0x61, 0x50, 0x89,
- 0x6d, 0x05, 0x83, 0xf2, 0xa6, 0x8f, 0x9e, 0x72, 0xec, 0xf0, 0x0a, 0xc9,
- 0x9a, 0xc9, 0xd8, 0xa2, 0x3d, 0xb1, 0x4e, 0xfb, 0x45, 0xcd, 0x38, 0x7a,
- 0x1f, 0xe4, 0x59, 0x06, 0x9f, 0xa4, 0x09, 0xb6, 0x8f, 0xd8, 0xfe, 0x9c,
- 0x45, 0xbc, 0x45, 0xef, 0x0b, 0x6a, 0xe0, 0xf1, 0x39, 0xc1, 0x70, 0x7a,
- 0x6c, 0x37, 0xb5, 0x45, 0xf8, 0x9e, 0x13, 0xe0, 0x4f, 0xe8, 0xe7, 0x45,
- 0x51, 0xb6, 0x93, 0x60, 0xb3, 0x9e, 0x9c, 0xb5, 0xcd, 0x3c, 0x19, 0x3c,
- 0x16, 0xb6, 0x2b, 0xee, 0x83, 0xeb, 0x23, 0x66, 0x13, 0xd5, 0xd6, 0xe4,
- 0x3e, 0x2b, 0xea, 0x14, 0xdf, 0x0d, 0xdf, 0x47, 0x46, 0x3f, 0xf8, 0x15,
- 0xf6, 0xed, 0x5e, 0x15, 0x27, 0x3a, 0xcb, 0xdf, 0xc7, 0xd5, 0xf7, 0xaf,
- 0x88, 0xfd, 0x94, 0xdf, 0x35, 0x7e, 0xe3, 0xef, 0x5f, 0x5a, 0xc8, 0xf9,
- 0xa1, 0xca, 0x59, 0xa9, 0xca, 0x05, 0x09, 0x8d, 0x1a, 0x5f, 0xa1, 0xd3,
- 0x2b, 0x9b, 0xf9, 0x5f, 0xbc, 0x6a, 0x5d, 0xbb, 0xb7, 0x59, 0xeb, 0xfa,
- 0x07, 0xbb, 0x65, 0x6d, 0x99, 0x7b, 0x2e, 0xff, 0xc9, 0x73, 0xf1, 0xd2,
- 0xc9, 0xea, 0xf4, 0x44, 0x5e, 0x6f, 0x89, 0xfe, 0x29, 0xfc, 0x49, 0xba,
- 0x1e, 0x0c, 0xa9, 0x9c, 0x25, 0xe4, 0x28, 0xdd, 0xa7, 0xf0, 0x5a, 0xf3,
- 0x7e, 0xf2, 0xe0, 0xfd, 0x8f, 0x89, 0x5c, 0x4d, 0x29, 0x3b, 0x06, 0x15,
- 0x3c, 0x00, 0xb3, 0x90, 0x0b, 0x66, 0x7d, 0x2e, 0x98, 0x19, 0xea, 0x7b,
- 0xa7, 0x38, 0x3e, 0xbd, 0xf2, 0x99, 0x6e, 0x59, 0x2f, 0x8e, 0x58, 0xe2,
- 0xbc, 0xfa, 0xbe, 0xd5, 0x7a, 0x7f, 0xce, 0x6b, 0x15, 0xfe, 0x26, 0xd7,
- 0x5a, 0x5f, 0x27, 0x72, 0x5a, 0x82, 0xf5, 0x30, 0xf8, 0x8e, 0xeb, 0x3c,
- 0xe6, 0x38, 0xe6, 0x9a, 0xe3, 0x88, 0x6b, 0x8e, 0x77, 0x37, 0x98, 0x23,
- 0xf3, 0xf8, 0xe2, 0x69, 0xfe, 0xbf, 0xdd, 0xb9, 0xca, 0x79, 0xce, 0x0b,
- 0x78, 0xb6, 0x53, 0x3a, 0x18, 0x52, 0xb2, 0xe3, 0xfb, 0xaa, 0x16, 0xdd,
- 0x6b, 0xce, 0xff, 0x40, 0x8d, 0xf7, 0xcd, 0x8d, 0xab, 0xee, 0xfa, 0xe3,
- 0x97, 0x28, 0x26, 0xeb, 0xc8, 0x15, 0x6d, 0x7f, 0xb5, 0x81, 0x1f, 0xfa,
- 0x41, 0xa1, 0xff, 0xcc, 0xcb, 0x78, 0xd0, 0x80, 0xec, 0xbf, 0x16, 0xa0,
- 0xd5, 0x72, 0x2d, 0xaf, 0x5f, 0xd5, 0xee, 0xdc, 0x1f, 0xbc, 0xb3, 0x75,
- 0xbc, 0x38, 0xff, 0x88, 0xf0, 0xe5, 0xc9, 0xf8, 0x51, 0x42, 0xd5, 0x23,
- 0xdb, 0x16, 0x72, 0x03, 0x0a, 0x6b, 0xf0, 0xbf, 0x36, 0xaa, 0xdd, 0xc5,
- 0xb5, 0xf0, 0x03, 0x6a, 0x3b, 0xfe, 0x84, 0xe0, 0x89, 0xd2, 0x3f, 0x26,
- 0xeb, 0x6f, 0x0b, 0x6b, 0x27, 0x45, 0xcd, 0x6b, 0x54, 0xd5, 0xf1, 0x26,
- 0xa9, 0x43, 0xe8, 0xb9, 0xb7, 0x5f, 0x7f, 0xfb, 0x5c, 0x70, 0xe7, 0xf5,
- 0xb7, 0xee, 0x6b, 0x76, 0x56, 0x7f, 0x6b, 0xf2, 0xda, 0x8d, 0x65, 0x59,
- 0x7f, 0x5b, 0x1d, 0x93, 0x91, 0xfe, 0xc0, 0xa4, 0x4b, 0x7f, 0x90, 0xfa,
- 0xfa, 0x6f, 0xb9, 0xf2, 0xb7, 0x65, 0x6d, 0x6d, 0xa1, 0xac, 0xb3, 0xca,
- 0xda, 0x5a, 0x99, 0xef, 0xed, 0xee, 0x03, 0x23, 0x63, 0x3f, 0xf2, 0x39,
- 0x9d, 0x35, 0xb1, 0x1f, 0x59, 0x53, 0x6b, 0x19, 0x8d, 0x6c, 0x38, 0xd1,
- 0xe7, 0xa2, 0x8f, 0xba, 0x22, 0x8c, 0xbb, 0xed, 0x0d, 0xfa, 0x21, 0x44,
- 0x1a, 0xf4, 0x43, 0x70, 0xf3, 0x7e, 0xb7, 0x8e, 0x05, 0x9d, 0x18, 0xb2,
- 0x11, 0xba, 0x30, 0xfa, 0x19, 0x84, 0xe9, 0x74, 0x59, 0xf7, 0xbc, 0x8f,
- 0x12, 0x4a, 0xf7, 0x3c, 0xbd, 0xa2, 0xf9, 0xd1, 0x48, 0x0d, 0x3f, 0xf2,
- 0xd2, 0x45, 0x6d, 0x95, 0xe7, 0xa3, 0xe9, 0x35, 0xe5, 0xa2, 0xd7, 0x94,
- 0x07, 0xbd, 0x8a, 0x67, 0x34, 0x98, 0xf7, 0xf7, 0xd5, 0x35, 0xf8, 0x4f,
- 0x84, 0xd0, 0xb3, 0x85, 0x79, 0x6a, 0x50, 0xe9, 0x7f, 0x2e, 0x7a, 0x3d,
- 0xc5, 0xf4, 0xaa, 0xcf, 0x63, 0xbe, 0x0d, 0x73, 0x41, 0x95, 0xce, 0x38,
- 0xe8, 0x3b, 0x74, 0xf1, 0x1b, 0x22, 0x4f, 0xaa, 0xda, 0x5e, 0xd4, 0xfa,
- 0xc4, 0x3e, 0x41, 0x4b, 0xd7, 0xfd, 0xc8, 0x5b, 0xd1, 0xe7, 0x4c, 0xe5,
- 0x27, 0xd3, 0xb0, 0x68, 0xae, 0xd2, 0x39, 0x2a, 0xfa, 0x86, 0xc8, 0xf1,
- 0x75, 0xcd, 0xed, 0x43, 0x9e, 0x9b, 0x3e, 0xaf, 0x65, 0xe6, 0xb5, 0x2a,
- 0x7f, 0xc6, 0xe5, 0xaa, 0x9e, 0x83, 0xf0, 0x1d, 0x75, 0x26, 0x0c, 0x27,
- 0x2e, 0x72, 0x4c, 0x7b, 0x1c, 0xf8, 0xc9, 0xa2, 0x4c, 0xfb, 0x3d, 0x09,
- 0xe4, 0x33, 0xf7, 0x2c, 0x59, 0x74, 0x3c, 0x73, 0xff, 0x5d, 0x12, 0x57,
- 0xce, 0x8a, 0x3e, 0x92, 0xe8, 0x67, 0x16, 0x63, 0xf9, 0x1c, 0xf5, 0x4f,
- 0xd3, 0xf9, 0x62, 0x0b, 0x15, 0x58, 0xbb, 0xf7, 0x3b, 0x79, 0xe1, 0xeb,
- 0x63, 0x9e, 0x94, 0x45, 0x2f, 0x51, 0x63, 0xb9, 0x99, 0xef, 0xdb, 0x4f,
- 0xab, 0xb9, 0x31, 0xd1, 0x13, 0x4a, 0xf6, 0x17, 0xc1, 0x58, 0x1f, 0xf5,
- 0x3a, 0x07, 0xfb, 0xa8, 0xed, 0xb3, 0x22, 0xc7, 0xb2, 0x90, 0x3d, 0x2b,
- 0x3f, 0xf3, 0x0f, 0xa8, 0x67, 0xf0, 0xf3, 0x8a, 0x7f, 0x4a, 0x91, 0x5e,
- 0xcb, 0x65, 0xcb, 0xb9, 0xff, 0xbc, 0xf5, 0x95, 0xa3, 0x3b, 0xd2, 0x57,
- 0x52, 0x89, 0x8a, 0xbe, 0xe2, 0xbe, 0x77, 0x39, 0x07, 0xa6, 0x5f, 0xf6,
- 0x7b, 0x00, 0x0c, 0xda, 0xa1, 0x8b, 0x25, 0x00, 0x4b, 0x63, 0xc6, 0x0e,
- 0x45, 0xfd, 0x53, 0xb4, 0x50, 0x1c, 0x32, 0x92, 0x59, 0xe8, 0xcc, 0xfc,
- 0x99, 0x8f, 0xee, 0x91, 0x3e, 0x1a, 0x7d, 0x0d, 0xf8, 0xca, 0x6e, 0x1e,
- 0xff, 0x7a, 0xbf, 0xcc, 0xcb, 0x76, 0x9f, 0xef, 0xe2, 0xf3, 0x7b, 0x42,
- 0xd5, 0xe7, 0x77, 0xf1, 0xf9, 0xde, 0x04, 0xf6, 0xd0, 0x58, 0x82, 0x5f,
- 0xd2, 0xa1, 0x34, 0xef, 0xcd, 0x42, 0x91, 0x65, 0xeb, 0xcb, 0xcc, 0x47,
- 0x57, 0xf4, 0xb8, 0x3e, 0xd4, 0xec, 0x88, 0x3d, 0x31, 0x78, 0xcc, 0xb9,
- 0xcc, 0x04, 0x8f, 0x1b, 0x24, 0xff, 0xcb, 0x6c, 0x8b, 0xae, 0x68, 0x5c,
- 0xd5, 0xf9, 0xf6, 0xdf, 0xe8, 0x93, 0x39, 0x55, 0xdf, 0xdd, 0x23, 0xe1,
- 0xe7, 0x08, 0x9e, 0x72, 0x9e, 0xe1, 0xf2, 0xbc, 0xc0, 0x43, 0x7b, 0xda,
- 0x2a, 0x3f, 0xbf, 0x13, 0x78, 0xd5, 0x8a, 0xbc, 0xd9, 0xc0, 0x12, 0xf3,
- 0xc5, 0x19, 0xc7, 0x4c, 0x97, 0x73, 0xd5, 0x1e, 0x1f, 0x90, 0xd7, 0xbf,
- 0xd9, 0x27, 0xfb, 0x83, 0x7e, 0x6b, 0x40, 0xf7, 0x48, 0x94, 0x32, 0x07,
- 0xf9, 0xcb, 0x3e, 0x01, 0x1b, 0xff, 0x32, 0xf8, 0xa5, 0xc1, 0xdf, 0x79,
- 0x3d, 0x09, 0xcc, 0xf1, 0x4a, 0x9f, 0xee, 0x17, 0x23, 0xd7, 0x15, 0xe7,
- 0xf9, 0x46, 0x78, 0x5d, 0xfa, 0xfc, 0x0c, 0x1f, 0x7b, 0xed, 0x2f, 0xee,
- 0xd5, 0x96, 0x90, 0xfd, 0xc5, 0xda, 0x12, 0xc9, 0x09, 0xb9, 0xcf, 0x15,
- 0x9f, 0x6e, 0xa8, 0xec, 0xd3, 0x3d, 0x9f, 0xb9, 0xd5, 0x07, 0xff, 0x86,
- 0xb1, 0xc4, 0xfb, 0x1d, 0x7c, 0x9e, 0xc7, 0xa2, 0x56, 0x21, 0xcd, 0x9f,
- 0x1d, 0x2a, 0xaf, 0xa7, 0x1e, 0x57, 0x64, 0x9e, 0x84, 0x96, 0x5b, 0xb8,
- 0xf6, 0x43, 0xbe, 0x87, 0x94, 0x5d, 0x8d, 0x9f, 0x43, 0x75, 0x79, 0x30,
- 0xf5, 0x38, 0xb6, 0x99, 0x1f, 0x56, 0xc4, 0x13, 0x3d, 0xf0, 0x6c, 0xb3,
- 0x7e, 0x06, 0xd7, 0x84, 0x1f, 0x2d, 0x56, 0x47, 0xaf, 0xa0, 0xe3, 0x00,
- 0xfd, 0xce, 0x62, 0x8a, 0x76, 0xf1, 0x5e, 0xfd, 0xa6, 0xf1, 0x00, 0xe2,
- 0xed, 0x24, 0x73, 0x9e, 0x18, 0xc6, 0x19, 0x67, 0xe2, 0x94, 0x11, 0x01,
- 0xbf, 0x2c, 0x05, 0x9c, 0x0e, 0x6a, 0x66, 0x5a, 0xfd, 0x65, 0x1a, 0x65,
- 0xfb, 0x0f, 0x34, 0xeb, 0x84, 0xe2, 0x04, 0x7a, 0xb3, 0xcd, 0x43, 0xac,
- 0x13, 0xc7, 0x8a, 0xc0, 0x67, 0x83, 0x3e, 0x9f, 0x23, 0xfa, 0x5c, 0x6e,
- 0xd4, 0xfc, 0x26, 0x39, 0x56, 0xe5, 0x77, 0xdb, 0x8c, 0xf2, 0x3c, 0xe2,
- 0xc5, 0x2f, 0xd3, 0xfb, 0xa2, 0xcf, 0x09, 0xe0, 0xa8, 0xf7, 0xfd, 0x4b,
- 0x74, 0x32, 0x81, 0x79, 0x6f, 0x9f, 0x3e, 0x8f, 0xef, 0x88, 0x3e, 0xdb,
- 0x3c, 0xe8, 0xf3, 0xc5, 0x7e, 0x89, 0x37, 0x25, 0xc6, 0xd1, 0x36, 0x9a,
- 0xcb, 0x22, 0x07, 0xec, 0xd3, 0xe8, 0x3b, 0x95, 0x4d, 0x32, 0x5f, 0x4a,
- 0x56, 0xf8, 0xd2, 0x85, 0x28, 0x1b, 0xc3, 0x4c, 0xe3, 0xe8, 0xcb, 0xa6,
- 0xf2, 0x7e, 0xb0, 0x8e, 0x01, 0x1a, 0x5d, 0x6e, 0xe7, 0x6b, 0x69, 0x3d,
- 0x3a, 0x15, 0x51, 0xb5, 0xfe, 0xb6, 0x15, 0x63, 0xfe, 0x78, 0x9e, 0x69,
- 0x39, 0x9d, 0xbd, 0x97, 0x0a, 0xc1, 0x21, 0x1a, 0x59, 0xd6, 0xfd, 0x4d,
- 0x44, 0xce, 0xc6, 0xa0, 0xe4, 0x49, 0x7a, 0xdd, 0x9f, 0x10, 0xbe, 0x0b,
- 0xeb, 0xd2, 0xc7, 0xb5, 0xee, 0xf6, 0x2d, 0xf8, 0xd2, 0x25, 0x45, 0xb3,
- 0xa5, 0xcb, 0xd1, 0x30, 0xa5, 0xa2, 0x53, 0xaf, 0xf4, 0x03, 0xff, 0x47,
- 0x2e, 0xc1, 0x0f, 0x07, 0x1e, 0x6d, 0x51, 0x22, 0x53, 0x0b, 0x8b, 0x21,
- 0x5e, 0x37, 0x7e, 0x2f, 0x7d, 0x30, 0x17, 0x7e, 0x40, 0xc8, 0xfe, 0xd1,
- 0x4b, 0x3c, 0x4e, 0xca, 0x26, 0xc5, 0x37, 0xbc, 0xf0, 0x50, 0xf7, 0xc5,
- 0xd4, 0xb8, 0x28, 0x73, 0x3d, 0x59, 0x7f, 0x33, 0x13, 0xfe, 0x5a, 0x9c,
- 0xbc, 0xe6, 0x3b, 0xba, 0x68, 0xd1, 0xb1, 0x8c, 0xfd, 0xf5, 0x14, 0x4d,
- 0x31, 0x5d, 0xbb, 0xe5, 0x05, 0x8f, 0x27, 0xe0, 0xd9, 0x34, 0xd3, 0x3e,
- 0xdb, 0xcd, 0x59, 0x4b, 0xe6, 0xdd, 0x89, 0xde, 0x73, 0x38, 0x46, 0xdd,
- 0xf1, 0x5f, 0xf5, 0x6b, 0x79, 0x90, 0xcc, 0xa2, 0x8e, 0x90, 0x3f, 0xf3,
- 0x3c, 0x1e, 0xb9, 0xff, 0x39, 0xdc, 0x07, 0xf2, 0x0e, 0x73, 0xe7, 0xe3,
- 0x55, 0xb9, 0xaf, 0x23, 0x7c, 0x6f, 0xd4, 0xdd, 0x1f, 0x2b, 0x4e, 0xf2,
- 0xfe, 0x76, 0x09, 0xde, 0x2c, 0xf7, 0x73, 0x9a, 0xce, 0x79, 0xf2, 0x15,
- 0xb9, 0x2f, 0x49, 0x17, 0x7d, 0x27, 0x05, 0x7d, 0x4f, 0x8b, 0xfd, 0x48,
- 0xe6, 0x0c, 0xd6, 0xd7, 0xb4, 0xef, 0x81, 0xed, 0xec, 0x5c, 0x40, 0xe7,
- 0x06, 0xf2, 0xf7, 0x0f, 0xfb, 0x45, 0x5e, 0x22, 0xec, 0xef, 0x1c, 0x3e,
- 0xa7, 0xe9, 0x79, 0x96, 0xeb, 0x2f, 0x64, 0x5a, 0xe8, 0x6a, 0xb6, 0x85,
- 0xde, 0xc9, 0x0e, 0xd1, 0x95, 0xc5, 0x6e, 0x3a, 0xc7, 0x3a, 0xf3, 0x39,
- 0x27, 0x60, 0xa5, 0xa9, 0x1b, 0xf1, 0x45, 0xe4, 0x0c, 0x31, 0xdd, 0x61,
- 0x3c, 0xf4, 0xbf, 0xe8, 0x5e, 0xc6, 0x39, 0xd6, 0xbd, 0x5b, 0xe9, 0x3d,
- 0x7e, 0x66, 0x3a, 0xa3, 0x73, 0x1d, 0xe0, 0x93, 0x1f, 0x2b, 0xeb, 0xaf,
- 0x5b, 0xe3, 0x88, 0xb9, 0x05, 0x8e, 0x4c, 0x8b, 0xf8, 0xd6, 0xc2, 0x22,
- 0xff, 0xbe, 0x08, 0xff, 0x39, 0xc3, 0x9b, 0xf9, 0xf3, 0x93, 0x01, 0x8c,
- 0xc7, 0x39, 0x47, 0xe6, 0x4a, 0x8a, 0xb5, 0x85, 0xf8, 0xd8, 0x27, 0x6a,
- 0xa4, 0x25, 0x1c, 0x5a, 0x79, 0x7d, 0x3e, 0x31, 0x3e, 0xb9, 0xda, 0x4a,
- 0xf3, 0x39, 0xd6, 0x41, 0x72, 0x7e, 0xb6, 0x61, 0x30, 0xf6, 0xef, 0x54,
- 0x6f, 0x61, 0xdc, 0xbf, 0x8b, 0xd2, 0x62, 0x1c, 0x7f, 0xae, 0x76, 0xd1,
- 0x42, 0xae, 0x43, 0x1d, 0xdf, 0x2b, 0x72, 0xdc, 0x65, 0x1f, 0x23, 0xfc,
- 0xb6, 0x19, 0x7f, 0x7b, 0x97, 0x71, 0x0a, 0x32, 0x55, 0xda, 0xa5, 0xe0,
- 0x35, 0x97, 0xeb, 0x7a, 0x22, 0x03, 0xe7, 0xa6, 0xe8, 0x25, 0x96, 0xb7,
- 0x23, 0x2f, 0xc3, 0x7f, 0xfc, 0x38, 0xf0, 0x26, 0x9f, 0xa2, 0x41, 0x3e,
- 0x46, 0x5f, 0x24, 0xbf, 0xa8, 0x73, 0x8a, 0x05, 0x27, 0x44, 0x6d, 0x88,
- 0xa4, 0xd1, 0x59, 0xd1, 0x8b, 0xee, 0x2d, 0xc1, 0x9b, 0xec, 0x94, 0x65,
- 0x40, 0x1f, 0x81, 0x0f, 0x46, 0xe6, 0x60, 0x1d, 0x77, 0x7a, 0xde, 0xed,
- 0x9b, 0x19, 0xa7, 0x48, 0x3f, 0xf0, 0x5e, 0xd2, 0xac, 0xea, 0x2f, 0x20,
- 0xf8, 0xbd, 0xb9, 0x4f, 0xd7, 0x4b, 0xea, 0x63, 0x2d, 0x2b, 0xf4, 0x71,
- 0x47, 0xcd, 0xef, 0x66, 0xcd, 0xef, 0xe5, 0x7c, 0x39, 0x96, 0x79, 0x2c,
- 0xe7, 0x49, 0xf6, 0x28, 0x4a, 0x2e, 0x4b, 0xfc, 0x33, 0xf7, 0x8d, 0x99,
- 0x8f, 0x2a, 0x1d, 0x3c, 0xb9, 0x36, 0x1a, 0xea, 0x31, 0x26, 0x8c, 0xe4,
- 0xe4, 0x3f, 0x96, 0x22, 0x09, 0xe8, 0x45, 0x4f, 0xee, 0x51, 0xf9, 0xa7,
- 0x3c, 0xaf, 0x54, 0x18, 0xaa, 0xdb, 0xec, 0x5a, 0x07, 0xad, 0x8b, 0x9e,
- 0x5c, 0x42, 0xc7, 0xe0, 0xeb, 0x71, 0x9f, 0x94, 0xd9, 0x44, 0xe8, 0x73,
- 0x0e, 0x1a, 0xdf, 0x1f, 0xba, 0xc4, 0xfb, 0x19, 0x5f, 0xfb, 0x69, 0xe9,
- 0xa4, 0xe8, 0x71, 0x83, 0xb1, 0x5d, 0x34, 0x27, 0x74, 0x7e, 0xd6, 0x5f,
- 0xaa, 0xec, 0xaa, 0x29, 0xcc, 0x33, 0x85, 0xd8, 0x8a, 0xe1, 0xfc, 0xbe,
- 0x2f, 0x99, 0x97, 0xb1, 0xf2, 0x78, 0x4d, 0xac, 0x7c, 0x56, 0xc4, 0xca,
- 0x11, 0x27, 0x07, 0x5c, 0x01, 0x4b, 0xaf, 0x9c, 0x16, 0xec, 0x63, 0x98,
- 0x90, 0x1b, 0x7e, 0xee, 0xa2, 0xe0, 0x37, 0xe1, 0x98, 0x5f, 0xe6, 0x57,
- 0xc7, 0x79, 0xc6, 0x06, 0x5d, 0x60, 0x7c, 0xb0, 0x27, 0x36, 0x58, 0x97,
- 0x58, 0xc9, 0x7e, 0x99, 0xae, 0xe4, 0x9b, 0x58, 0xd7, 0x5b, 0xa0, 0x8d,
- 0x3c, 0xb1, 0x4e, 0xd8, 0x4d, 0x0b, 0x61, 0xc6, 0xb1, 0x89, 0x36, 0xde,
- 0x4f, 0xd6, 0x6b, 0x27, 0x98, 0xee, 0x78, 0xee, 0x2b, 0xb9, 0xd2, 0x8f,
- 0xd2, 0xe1, 0x88, 0x15, 0x9d, 0xea, 0x60, 0xbb, 0xc5, 0xe4, 0x7f, 0x87,
- 0xff, 0x77, 0x85, 0x00, 0x93, 0xc2, 0x2a, 0x7e, 0x67, 0x9d, 0x27, 0x53,
- 0xfa, 0xd1, 0x1c, 0x8f, 0x99, 0x9b, 0x82, 0xfd, 0x03, 0x3b, 0xcf, 0xe1,
- 0x7f, 0x39, 0x66, 0x65, 0x95, 0xf1, 0xfb, 0x62, 0x2a, 0x64, 0x08, 0xde,
- 0xbe, 0xce, 0x3c, 0xfe, 0x02, 0xcd, 0xf1, 0x1c, 0xae, 0x10, 0xae, 0xb5,
- 0x28, 0x19, 0xde, 0xc7, 0x78, 0xdf, 0xcd, 0x9f, 0xa8, 0xbf, 0x6a, 0xa7,
- 0x85, 0xc9, 0x31, 0x55, 0x7f, 0xf5, 0xbd, 0x06, 0xf5, 0x57, 0xb8, 0x8e,
- 0xe5, 0xfe, 0x62, 0xe9, 0xe6, 0x5c, 0xd8, 0xfd, 0x3c, 0x32, 0x92, 0xe1,
- 0x4e, 0xa1, 0x23, 0xad, 0xac, 0xfa, 0xf8, 0xd9, 0x11, 0x2b, 0x39, 0xc5,
- 0x73, 0xcc, 0xb9, 0xe7, 0x5d, 0xba, 0x19, 0x0b, 0x63, 0x9c, 0xbf, 0x66,
- 0x1c, 0xdb, 0xca, 0x53, 0x72, 0x3d, 0x85, 0x5c, 0xe9, 0xe7, 0xd1, 0xb0,
- 0x5e, 0x9f, 0xfb, 0x5a, 0xac, 0x03, 0xf4, 0xc4, 0x9f, 0x2b, 0x5d, 0xbe,
- 0x2b, 0x59, 0xd8, 0xdf, 0x06, 0xe3, 0x39, 0x66, 0x34, 0x44, 0xa9, 0x15,
- 0xa6, 0xef, 0x8b, 0x1d, 0xbe, 0x8d, 0xec, 0x95, 0x52, 0xb2, 0x2a, 0x97,
- 0xa5, 0xda, 0xef, 0x2e, 0x6d, 0xae, 0x21, 0x72, 0x96, 0x20, 0x33, 0x21,
- 0x2f, 0x53, 0x25, 0xbf, 0x03, 0xfd, 0x0e, 0xb6, 0xd0, 0x59, 0xe6, 0x57,
- 0x32, 0x1f, 0x89, 0x79, 0x27, 0xf3, 0x2c, 0x49, 0x2f, 0xf1, 0xaa, 0xd7,
- 0x0d, 0x48, 0x9c, 0x1d, 0xa9, 0xe4, 0x41, 0xba, 0xe2, 0xe9, 0x01, 0x57,
- 0x3c, 0xdd, 0x74, 0xe5, 0x41, 0x06, 0x85, 0x3e, 0x56, 0xd1, 0xa1, 0x82,
- 0x4a, 0x87, 0x82, 0xae, 0x25, 0x79, 0x59, 0xa1, 0xcc, 0xcb, 0x76, 0x6f,
- 0xc1, 0xcb, 0xbc, 0x6c, 0xd3, 0x75, 0xc5, 0x37, 0xec, 0x30, 0xe4, 0xfc,
- 0xe5, 0xe2, 0x34, 0xbd, 0xcd, 0x3c, 0xe2, 0xad, 0x62, 0x98, 0xf9, 0xc6,
- 0x24, 0xf3, 0x8d, 0x09, 0xe6, 0x1b, 0x0e, 0xc3, 0xc0, 0xe2, 0xb5, 0x5f,
- 0xf3, 0x5d, 0x59, 0x84, 0xbc, 0x98, 0xa2, 0xe7, 0x8b, 0xe0, 0xc1, 0x93,
- 0xac, 0xf3, 0x5c, 0xf3, 0x6d, 0x2c, 0x76, 0x31, 0xbe, 0x4a, 0x3d, 0xa7,
- 0xda, 0x8e, 0x41, 0xaf, 0x15, 0xf8, 0x87, 0xaf, 0x82, 0xcf, 0xbc, 0x91,
- 0xa2, 0x4e, 0x86, 0x3d, 0xe0, 0xbc, 0x8e, 0xde, 0x14, 0xaf, 0x81, 0x96,
- 0xd1, 0x13, 0xf8, 0xbb, 0xe3, 0x53, 0x3c, 0xf7, 0x4e, 0xdf, 0x02, 0xef,
- 0xcb, 0xd3, 0xe1, 0x94, 0xd9, 0xcb, 0x38, 0x7f, 0xac, 0x82, 0xf3, 0xa9,
- 0x34, 0xaf, 0xa0, 0x67, 0xb9, 0x9b, 0xc6, 0x0e, 0x44, 0xf7, 0xf6, 0x30,
- 0x9d, 0x22, 0x37, 0xa2, 0xd2, 0xa7, 0xc7, 0x4f, 0x27, 0x83, 0x6d, 0xaa,
- 0xbf, 0x8f, 0xc5, 0xf2, 0xf1, 0x03, 0xbe, 0xcf, 0x2d, 0x5f, 0x3a, 0xfb,
- 0x2a, 0x3f, 0x03, 0xc7, 0x5f, 0x85, 0xff, 0x93, 0xed, 0x83, 0x56, 0xe1,
- 0x3f, 0x2a, 0x88, 0xb1, 0x38, 0xb6, 0x27, 0x98, 0x97, 0x85, 0xd7, 0x0d,
- 0x7b, 0x3a, 0x62, 0x30, 0xd1, 0x75, 0x99, 0xbc, 0xde, 0xd2, 0xa0, 0x8c,
- 0xc1, 0xed, 0xdd, 0x2b, 0xf9, 0x06, 0xe3, 0x66, 0x30, 0x22, 0x6c, 0xb4,
- 0xa6, 0x25, 0x29, 0x27, 0x0b, 0xbc, 0xcf, 0x2b, 0xe1, 0x09, 0xde, 0xe7,
- 0x0e, 0x25, 0x23, 0x53, 0xfc, 0xbb, 0x90, 0xbf, 0x2c, 0x2b, 0x87, 0xd0,
- 0xb3, 0xda, 0x14, 0xfd, 0x20, 0x66, 0xd1, 0x6f, 0xa7, 0x83, 0xef, 0x6b,
- 0x33, 0xd6, 0x82, 0x4f, 0x7c, 0xe0, 0x4b, 0x66, 0xf1, 0x5c, 0xe0, 0x21,
- 0x7f, 0xcf, 0x4f, 0xd1, 0x85, 0x8c, 0x9e, 0xc3, 0x80, 0x61, 0xbc, 0x84,
- 0x79, 0xf8, 0x68, 0xb7, 0xf3, 0x43, 0x86, 0x17, 0x1f, 0xff, 0x71, 0xed,
- 0x9c, 0x86, 0xd5, 0x9c, 0xd0, 0xd3, 0xb2, 0x05, 0x3d, 0x7c, 0x08, 0xbd,
- 0x8f, 0x0a, 0xa2, 0xe7, 0x64, 0xb3, 0xb0, 0x4d, 0x0b, 0xc2, 0xc6, 0x28,
- 0x85, 0x2a, 0x7d, 0x30, 0xef, 0xa9, 0x39, 0xf7, 0x13, 0x5f, 0x7a, 0xf1,
- 0xa0, 0xd0, 0xc5, 0x46, 0x0e, 0xec, 0x55, 0xf5, 0xa7, 0x5d, 0xe2, 0xbe,
- 0xc6, 0x32, 0x7e, 0x7b, 0x50, 0xfd, 0xf6, 0x49, 0xa1, 0x03, 0x23, 0x2f,
- 0x2e, 0xb0, 0x24, 0xf0, 0x9c, 0xf7, 0xd7, 0x99, 0x60, 0x3c, 0x0f, 0xad,
- 0xc0, 0x77, 0x2f, 0xe0, 0xa9, 0xe1, 0x01, 0x58, 0x00, 0xf7, 0x3b, 0x14,
- 0xde, 0xdb, 0x56, 0xdc, 0xaf, 0xd7, 0xdd, 0x08, 0xce, 0xac, 0xd3, 0x64,
- 0xb0, 0x56, 0xac, 0x69, 0x8f, 0x2f, 0x92, 0xb7, 0x8c, 0xf4, 0x22, 0x6c,
- 0x1a, 0xd4, 0xb5, 0xdc, 0x85, 0xbc, 0x29, 0x9e, 0xc3, 0x1e, 0x8a, 0x24,
- 0x30, 0x2f, 0x8c, 0xd3, 0x30, 0xf8, 0xb7, 0x1a, 0x58, 0xb8, 0xaf, 0xeb,
- 0x56, 0xd7, 0xb5, 0x8a, 0xbd, 0x20, 0x03, 0xcf, 0xd1, 0xcf, 0xc6, 0x73,
- 0xf1, 0x7c, 0x5c, 0x87, 0xfb, 0xc9, 0xfb, 0xf6, 0x31, 0x7f, 0x8e, 0x4e,
- 0xc9, 0x7b, 0x19, 0x97, 0xe4, 0x6f, 0x7d, 0x8e, 0xf7, 0x7c, 0xe5, 0xfe,
- 0xf9, 0x54, 0xbf, 0x1e, 0xec, 0x5f, 0x37, 0xe5, 0x85, 0x8f, 0x13, 0xbf,
- 0x75, 0x8a, 0xdf, 0xa2, 0x4e, 0xa7, 0xd8, 0xd7, 0xf3, 0x7c, 0x3c, 0x9f,
- 0xed, 0xf2, 0xc1, 0x36, 0x4f, 0x27, 0x3a, 0x7d, 0xf9, 0x3c, 0xd6, 0xdb,
- 0xe9, 0x8b, 0x33, 0xee, 0xc7, 0xb2, 0xf1, 0xd2, 0x82, 0xe0, 0x31, 0xac,
- 0xd3, 0xf6, 0xda, 0xe6, 0x49, 0xe3, 0x4f, 0x86, 0x64, 0x6f, 0x5b, 0x7c,
- 0x67, 0xfa, 0xcb, 0x30, 0xfd, 0x65, 0x98, 0xfe, 0x32, 0x4c, 0x7f, 0x19,
- 0xa6, 0x3f, 0xb6, 0x4b, 0xdf, 0x64, 0x99, 0xf1, 0x6d, 0x96, 0x19, 0x92,
- 0x66, 0x23, 0xca, 0x8f, 0xa9, 0x69, 0xb6, 0xb6, 0x3e, 0x53, 0xd3, 0x28,
- 0xe4, 0x34, 0xf9, 0x0e, 0x8f, 0x57, 0xd3, 0xea, 0x55, 0xa6, 0xd5, 0xa6,
- 0x99, 0x7e, 0xba, 0x91, 0xc3, 0x9e, 0xd9, 0xd6, 0x79, 0xe6, 0xd1, 0x71,
- 0x3f, 0x74, 0xaa, 0x00, 0xd3, 0x13, 0x74, 0x4a, 0x9b, 0xe1, 0xde, 0x4f,
- 0x37, 0x99, 0x4f, 0xdf, 0xc8, 0x81, 0x76, 0xef, 0x52, 0xc7, 0x19, 0xa6,
- 0x5d, 0xc8, 0xb9, 0x25, 0xdf, 0xd5, 0xac, 0xc1, 0xba, 0x57, 0xc0, 0x4c,
- 0x12, 0xf8, 0xa8, 0xd0, 0xc7, 0x78, 0xdf, 0xd7, 0x99, 0xdf, 0xc3, 0x57,
- 0x87, 0xbe, 0x5f, 0x79, 0x1f, 0xcb, 0x89, 0xd0, 0x15, 0xe6, 0xa3, 0xa7,
- 0x73, 0x4b, 0x4c, 0xef, 0xbd, 0xf4, 0x85, 0x1c, 0xe4, 0x31, 0x60, 0xc4,
- 0xc7, 0x79, 0x12, 0x3e, 0x30, 0x63, 0x06, 0x6b, 0x1f, 0x4b, 0x19, 0x02,
- 0x4f, 0x9e, 0x01, 0x1c, 0x18, 0xf6, 0x67, 0xf6, 0xa2, 0x67, 0x7d, 0xc4,
- 0x68, 0x56, 0x3e, 0x45, 0x7c, 0xc7, 0x78, 0x8c, 0x05, 0xdc, 0x70, 0xdc,
- 0x28, 0xfe, 0x88, 0xf7, 0x42, 0x84, 0x19, 0x1e, 0xb5, 0x7c, 0xeb, 0x02,
- 0x7a, 0x91, 0x02, 0x5e, 0xd3, 0x51, 0x3f, 0x6a, 0xc5, 0xe9, 0x39, 0xbc,
- 0xff, 0xe0, 0x85, 0x22, 0xe6, 0xbd, 0x48, 0x0b, 0x41, 0xf0, 0x21, 0x3b,
- 0x7c, 0x9d, 0x24, 0xec, 0x5a, 0x59, 0xbf, 0xfc, 0xbc, 0x37, 0x6f, 0xb3,
- 0xa2, 0x42, 0x1f, 0x6e, 0x61, 0xfb, 0x06, 0xb0, 0x79, 0x8b, 0x71, 0x2d,
- 0x0c, 0x9b, 0x5f, 0xf1, 0xb5, 0x37, 0x99, 0xe7, 0x60, 0xcf, 0x3a, 0x85,
- 0x8c, 0xf1, 0xe2, 0x65, 0x1b, 0x8a, 0x97, 0x39, 0x2e, 0x5e, 0x96, 0x2e,
- 0xf3, 0x32, 0xc6, 0x09, 0xc1, 0xc3, 0xc0, 0xa3, 0x66, 0x59, 0x4f, 0x94,
- 0xdf, 0xa1, 0xff, 0xed, 0x16, 0x3c, 0x8b, 0x79, 0x3d, 0xdb, 0x0d, 0x85,
- 0x62, 0xca, 0x77, 0x48, 0xf0, 0x0e, 0x8d, 0xd7, 0xff, 0xa3, 0xe8, 0xa1,
- 0x55, 0xf0, 0x81, 0xf4, 0x2c, 0xf8, 0x95, 0xd7, 0xf8, 0xff, 0x02, 0x6c,
- 0x79, 0xbc, 0x13, 0x7a, 0x8d, 0xf9, 0x58, 0x21, 0x0c, 0x9b, 0xb5, 0x43,
- 0xd9, 0x36, 0xe8, 0xbb, 0xb5, 0x07, 0xb9, 0x96, 0x56, 0xb4, 0xcc, 0xc7,
- 0x76, 0x2b, 0xbf, 0x05, 0xfc, 0x8c, 0xd8, 0xeb, 0x3a, 0x5d, 0xc0, 0x82,
- 0x2e, 0xc0, 0x63, 0x03, 0x0c, 0x1f, 0xd1, 0x1b, 0x9c, 0xe8, 0x16, 0xc3,
- 0x01, 0xfb, 0x7c, 0x0b, 0xfb, 0xcc, 0xba, 0x2c, 0x05, 0xe6, 0xa6, 0x02,
- 0x03, 0x98, 0xdf, 0xc2, 0x6a, 0x85, 0x1f, 0x9e, 0xcf, 0x0c, 0x18, 0x85,
- 0xac, 0x9c, 0xe3, 0xca, 0xb8, 0xe4, 0x79, 0x85, 0x3c, 0x7a, 0x7b, 0x89,
- 0xb9, 0xf2, 0x1c, 0xf5, 0xfa, 0x04, 0xff, 0x52, 0x74, 0xbf, 0x1d, 0x5a,
- 0x4b, 0x30, 0x5d, 0x61, 0x4f, 0x52, 0x2e, 0x9c, 0x79, 0x94, 0x9f, 0x8f,
- 0x73, 0x8d, 0xd7, 0x71, 0xb3, 0xbc, 0x8e, 0x08, 0xaf, 0x03, 0x63, 0x6f,
- 0xf9, 0x6e, 0xa8, 0x75, 0xdc, 0x28, 0xaf, 0x63, 0x56, 0xad, 0x83, 0xd2,
- 0xc6, 0xcc, 0x6e, 0xa5, 0xc7, 0x6f, 0x79, 0xcf, 0xd6, 0x28, 0xeb, 0x27,
- 0xe9, 0x55, 0xc0, 0xf3, 0x1e, 0x85, 0x2f, 0x6e, 0x7f, 0xa8, 0x7b, 0x6e,
- 0xf6, 0xc4, 0x75, 0xfa, 0x5d, 0xba, 0x29, 0xf4, 0x93, 0x61, 0xd6, 0x4f,
- 0x70, 0x9e, 0x16, 0xc0, 0x87, 0xd3, 0x41, 0xf4, 0x9b, 0x1d, 0x64, 0x98,
- 0xb1, 0x5d, 0x35, 0xc5, 0x9f, 0xc2, 0x4f, 0x86, 0xfb, 0xe8, 0xeb, 0xbf,
- 0x48, 0x37, 0x17, 0xc1, 0xab, 0xa1, 0x8f, 0xca, 0x9e, 0xb4, 0x37, 0xd7,
- 0xa4, 0x9f, 0x36, 0xee, 0xe9, 0xa7, 0x85, 0x8f, 0x36, 0x0c, 0x7d, 0xdd,
- 0x84, 0x3f, 0x37, 0x26, 0xde, 0x67, 0xc1, 0xc7, 0x45, 0xdc, 0xcb, 0x8b,
- 0xef, 0x4c, 0xbb, 0x72, 0xdc, 0x90, 0x73, 0x92, 0x62, 0x3e, 0xe2, 0x98,
- 0x4d, 0x86, 0xac, 0x9d, 0xb9, 0x5c, 0xd4, 0x3a, 0x51, 0x9c, 0xf7, 0xc8,
- 0x09, 0x1b, 0x46, 0x44, 0xf8, 0x0c, 0x5a, 0x9d, 0x0e, 0x6a, 0x61, 0x39,
- 0x79, 0x8a, 0xd0, 0x13, 0xcd, 0xb6, 0xe0, 0xcb, 0xbf, 0xc0, 0xb8, 0xb7,
- 0x10, 0xb6, 0x43, 0x9f, 0x13, 0xf6, 0x25, 0xe4, 0x07, 0xde, 0xa7, 0x02,
- 0x18, 0x63, 0x0e, 0xfc, 0x7d, 0x15, 0xfd, 0x30, 0xc3, 0xbc, 0x7e, 0xf8,
- 0x81, 0x47, 0xad, 0x77, 0x58, 0xee, 0x5c, 0x10, 0xfe, 0x95, 0xb3, 0x94,
- 0x66, 0x3a, 0x3c, 0x2c, 0xe8, 0xd0, 0x18, 0x66, 0x6a, 0x61, 0xfa, 0x41,
- 0x8e, 0xc1, 0x98, 0xe8, 0xbf, 0x23, 0x6d, 0x16, 0x5e, 0xe5, 0x9a, 0xea,
- 0x6b, 0x90, 0x00, 0x6f, 0xd8, 0xbe, 0x6f, 0x21, 0xf1, 0x91, 0x7d, 0x2a,
- 0x6e, 0x5d, 0xab, 0xd6, 0x87, 0x0d, 0xfb, 0xcc, 0x12, 0x7d, 0x1f, 0x01,
- 0x3b, 0xe1, 0x17, 0x34, 0x26, 0x19, 0x6e, 0xfa, 0xdd, 0x35, 0x6e, 0xfb,
- 0xff, 0x29, 0x51, 0x9f, 0xff, 0x46, 0x51, 0xca, 0xd8, 0x34, 0xdb, 0xe6,
- 0x0b, 0x07, 0xdc, 0x3a, 0x87, 0x9d, 0x8d, 0x09, 0x9f, 0xcc, 0x00, 0x45,
- 0x97, 0x27, 0xe9, 0xb1, 0x0c, 0x78, 0x14, 0x5d, 0x8f, 0x3a, 0x78, 0xc3,
- 0x06, 0x68, 0x79, 0x92, 0xe2, 0x45, 0xc0, 0xc8, 0x47, 0x0b, 0x2c, 0x05,
- 0xd2, 0x59, 0xc4, 0xee, 0xf9, 0x7b, 0x1e, 0xef, 0x57, 0xf9, 0x15, 0xe5,
- 0xf7, 0x1e, 0xa2, 0xd8, 0x32, 0xa5, 0x92, 0xe1, 0x87, 0x45, 0xcf, 0xea,
- 0x64, 0x78, 0x5c, 0xf9, 0x68, 0x42, 0x7c, 0x1e, 0x7e, 0x2f, 0x8b, 0x1e,
- 0xcd, 0xd8, 0xa9, 0x24, 0x49, 0xdf, 0x03, 0xf1, 0x1c, 0x0c, 0x96, 0xad,
- 0xbb, 0x99, 0x57, 0x1c, 0x17, 0xfe, 0x07, 0xd6, 0x44, 0x16, 0x31, 0x1e,
- 0xbe, 0x83, 0x5e, 0x82, 0xbd, 0x95, 0xcc, 0x3e, 0xa0, 0xc6, 0x96, 0xc8,
- 0x64, 0x5c, 0x30, 0x7f, 0xc9, 0x49, 0x85, 0x8d, 0xca, 0xf5, 0xf0, 0x5d,
- 0x1c, 0x17, 0xfa, 0xe1, 0x30, 0xdb, 0x30, 0x62, 0x5c, 0x69, 0x4e, 0xf8,
- 0x21, 0xf8, 0x38, 0xff, 0xd3, 0x01, 0xfd, 0x6e, 0x03, 0x9c, 0x97, 0xfe,
- 0x09, 0xbe, 0x67, 0x9e, 0xe7, 0x51, 0x95, 0x17, 0x3f, 0x44, 0x91, 0x1d,
- 0xf8, 0x8b, 0x66, 0xef, 0xa8, 0xbf, 0x88, 0x61, 0xcd, 0xb2, 0xe5, 0x32,
- 0xd3, 0xc6, 0xdb, 0x5b, 0xda, 0x71, 0xef, 0x6b, 0x19, 0xcd, 0xb0, 0x32,
- 0xc5, 0xfb, 0x2f, 0xd0, 0xeb, 0x73, 0xa1, 0xf8, 0x29, 0xbc, 0x47, 0xc6,
- 0x97, 0x10, 0x3a, 0x6f, 0x88, 0x75, 0x17, 0xe8, 0x30, 0xa3, 0x22, 0xbe,
- 0x15, 0x79, 0xc2, 0x32, 0x16, 0xd6, 0xfa, 0xc9, 0x0f, 0xbf, 0x9a, 0xa3,
- 0x73, 0x22, 0x5a, 0x45, 0xfe, 0xba, 0x8c, 0x2b, 0x42, 0xfe, 0x82, 0x07,
- 0xfe, 0xc4, 0x97, 0x5c, 0xf3, 0xf7, 0xe9, 0x7c, 0xb7, 0x48, 0xb0, 0x9c,
- 0x4f, 0xa3, 0x78, 0x8a, 0xc6, 0x3d, 0x1d, 0xb3, 0x70, 0xbf, 0xd7, 0x0a,
- 0xb4, 0xeb, 0xd6, 0x19, 0xe0, 0x67, 0x12, 0x7b, 0x74, 0x01, 0x71, 0x5c,
- 0xa3, 0x2a, 0x1e, 0xd1, 0xc2, 0xfb, 0x04, 0x3b, 0x0f, 0xfe, 0xbb, 0xcf,
- 0xf2, 0x27, 0xe2, 0x0a, 0x27, 0x07, 0xa1, 0x27, 0xf5, 0x38, 0x8c, 0x33,
- 0x53, 0x38, 0xee, 0x67, 0xbb, 0x4b, 0xeb, 0xb5, 0xd2, 0xa7, 0xc4, 0xb6,
- 0x98, 0xda, 0x2f, 0xf8, 0x93, 0x46, 0x54, 0xbf, 0x01, 0x9b, 0xac, 0x5e,
- 0xc0, 0xe9, 0xe3, 0xa2, 0xc7, 0xad, 0x62, 0x10, 0xdb, 0xc9, 0x59, 0xc2,
- 0x3b, 0xb7, 0xd0, 0x77, 0xf3, 0x6e, 0xc0, 0x9e, 0xf7, 0xc8, 0x1d, 0xa3,
- 0xf8, 0x94, 0x7a, 0xff, 0xcf, 0x9d, 0xda, 0xb7, 0x5d, 0x1e, 0xfb, 0xf6,
- 0xbd, 0x41, 0x19, 0x03, 0xbb, 0x4b, 0x8d, 0xf1, 0xca, 0x53, 0xfd, 0xfb,
- 0xa7, 0xe1, 0x4f, 0xaa, 0xd4, 0x51, 0x5c, 0x13, 0x7c, 0xa5, 0xde, 0xa7,
- 0x1d, 0x62, 0x7e, 0x2a, 0xe9, 0xf8, 0xb8, 0x07, 0x1d, 0xf7, 0xce, 0x40,
- 0x2f, 0xb9, 0x7d, 0x3a, 0x3e, 0xd6, 0x90, 0x8e, 0xff, 0x75, 0x50, 0xfa,
- 0x54, 0xeb, 0xe9, 0x18, 0xb5, 0x3c, 0xc7, 0x8b, 0x8d, 0xfc, 0x57, 0xd8,
- 0x07, 0xd4, 0xa4, 0xc3, 0xe7, 0x01, 0x58, 0x69, 0xbf, 0x07, 0xe2, 0x7e,
- 0xc0, 0x47, 0xc4, 0x4e, 0xfe, 0x90, 0xe2, 0x8b, 0xb5, 0xb1, 0xd0, 0xcd,
- 0xae, 0xf9, 0x96, 0xc7, 0x35, 0xd0, 0xc5, 0x41, 0x0b, 0x76, 0x48, 0xda,
- 0xf4, 0x1a, 0x5e, 0xef, 0xf9, 0x0e, 0xe5, 0xec, 0x54, 0x9e, 0xe0, 0xa3,
- 0x0e, 0xd2, 0x53, 0x88, 0x2b, 0x2b, 0x1f, 0xf0, 0xd1, 0x8c, 0x5c, 0xb7,
- 0x79, 0x40, 0xe0, 0x03, 0xf4, 0xd5, 0x50, 0xc2, 0x9f, 0xe0, 0x3d, 0x95,
- 0xfe, 0xdf, 0xe4, 0x6a, 0x48, 0xed, 0x13, 0x8f, 0xc5, 0xfd, 0x3c, 0xeb,
- 0xfc, 0xb0, 0x3f, 0xf6, 0xd7, 0xd7, 0xcb, 0x79, 0xc5, 0x90, 0x05, 0x25,
- 0xfa, 0x0f, 0x96, 0x73, 0xfe, 0x03, 0xa6, 0xe8, 0xb9, 0x70, 0xb9, 0x78,
- 0x80, 0xf5, 0x47, 0xec, 0x21, 0x7c, 0x87, 0xda, 0xb7, 0xfb, 0xf6, 0x30,
- 0x75, 0xed, 0x67, 0xa9, 0x6f, 0x90, 0xc3, 0x7a, 0xa3, 0x71, 0x00, 0xf9,
- 0xe1, 0x16, 0x5f, 0x83, 0x5e, 0x51, 0x63, 0x56, 0x9c, 0x3a, 0xe0, 0x4f,
- 0x40, 0x0f, 0x68, 0x2b, 0x5d, 0x45, 0x53, 0xb3, 0x82, 0xa6, 0xe2, 0x6b,
- 0xb3, 0x8a, 0xa6, 0x66, 0x95, 0xff, 0x7c, 0x56, 0xd1, 0xd4, 0xac, 0xa2,
- 0xa9, 0x59, 0x45, 0x53, 0xb3, 0x8c, 0xd7, 0xa3, 0xac, 0xaf, 0x42, 0xf7,
- 0xd0, 0xfe, 0xcb, 0x2e, 0x4a, 0xe6, 0x70, 0x1e, 0xf2, 0xb8, 0x96, 0xae,
- 0x7e, 0x6d, 0x58, 0xfb, 0x47, 0x0b, 0x32, 0xcf, 0x8e, 0x9f, 0x85, 0x3d,
- 0x78, 0x98, 0xe1, 0x77, 0xcd, 0x37, 0xbf, 0x88, 0xb9, 0xfa, 0x28, 0x26,
- 0x7a, 0xc0, 0x36, 0x51, 0xd4, 0xad, 0xe3, 0x9a, 0xa8, 0xeb, 0x92, 0xb6,
- 0x5c, 0xaa, 0x61, 0x8d, 0x97, 0xc6, 0x8b, 0x69, 0xb5, 0x5f, 0xb5, 0x76,
- 0x4e, 0x0b, 0x25, 0xb2, 0x80, 0x2b, 0x72, 0x21, 0x2d, 0xde, 0x1b, 0x01,
- 0xa7, 0x94, 0xe9, 0x01, 0x83, 0xa3, 0x0a, 0x06, 0x4f, 0x8b, 0x35, 0x22,
- 0x97, 0x10, 0x3e, 0xc8, 0xc6, 0x70, 0x48, 0x67, 0x46, 0xf9, 0x3e, 0x8c,
- 0xfb, 0x07, 0x42, 0xcc, 0x83, 0xb6, 0x0b, 0x07, 0xf7, 0xda, 0x1b, 0xf1,
- 0x9a, 0xed, 0xd6, 0xd3, 0x5c, 0x77, 0xc9, 0x8e, 0x90, 0x92, 0x1b, 0x52,
- 0xef, 0xdd, 0xe5, 0xd8, 0x89, 0x14, 0xcf, 0xed, 0x2f, 0xc2, 0x7f, 0x39,
- 0x44, 0x6d, 0x25, 0x3a, 0x12, 0x06, 0x3e, 0x77, 0xb1, 0x5d, 0xc9, 0x73,
- 0x18, 0x2b, 0xd1, 0x85, 0xf0, 0x3e, 0xb6, 0x5d, 0xf6, 0xb3, 0x0e, 0x3a,
- 0xca, 0xff, 0x4e, 0xc4, 0xef, 0xc3, 0xbc, 0x3a, 0xf8, 0xda, 0x7e, 0x32,
- 0x7a, 0x52, 0x66, 0x2b, 0xeb, 0x07, 0x47, 0x2a, 0xf6, 0x88, 0x05, 0xff,
- 0x1c, 0xeb, 0xb6, 0xc6, 0x5c, 0xb8, 0x5b, 0xd5, 0x9c, 0xc1, 0x87, 0x8d,
- 0xf8, 0xd6, 0x3f, 0x97, 0x64, 0xaf, 0x80, 0x21, 0x75, 0xfc, 0xe3, 0x52,
- 0x64, 0x08, 0xc7, 0x78, 0xe7, 0x90, 0x3d, 0x11, 0xf1, 0xfd, 0x58, 0xea,
- 0xf2, 0x3e, 0xfb, 0x88, 0x7c, 0x3f, 0x80, 0x6d, 0x5a, 0x3e, 0x2f, 0xbc,
- 0x97, 0x3a, 0x4f, 0x25, 0x5f, 0x15, 0x74, 0x50, 0xa2, 0x7f, 0x67, 0x9a,
- 0x35, 0x09, 0xb1, 0x8c, 0x29, 0x51, 0x0b, 0x8d, 0x7c, 0xe5, 0xf9, 0x45,
- 0x3d, 0x2f, 0x47, 0xed, 0xf5, 0xfd, 0xc8, 0x37, 0xcb, 0x16, 0x68, 0x73,
- 0x99, 0x01, 0x3f, 0xda, 0xe8, 0xf2, 0x46, 0x4f, 0x50, 0xd4, 0x66, 0x77,
- 0xb3, 0x8e, 0xa3, 0xf3, 0x92, 0xc7, 0xf8, 0xfe, 0x01, 0xf1, 0xbe, 0xb9,
- 0xd8, 0x12, 0xc6, 0x35, 0xd3, 0xc8, 0x72, 0xe9, 0x21, 0xfe, 0x5d, 0xc4,
- 0x11, 0x93, 0xd4, 0xaa, 0x62, 0x04, 0x1d, 0x2a, 0xae, 0x14, 0x62, 0x5a,
- 0xaa, 0xd4, 0x1c, 0x8f, 0x94, 0x7d, 0x6d, 0xc0, 0xf1, 0x5a, 0x5f, 0xdb,
- 0x73, 0x5b, 0xc8, 0x9b, 0xad, 0xf0, 0x1a, 0x39, 0xa5, 0x2d, 0xa4, 0x7c,
- 0x88, 0xd6, 0x02, 0x6d, 0xb7, 0xb6, 0x6e, 0xc7, 0xd7, 0xb4, 0x36, 0xcf,
- 0xac, 0x9f, 0x79, 0xc7, 0x69, 0x53, 0xf8, 0xd4, 0x4c, 0xf3, 0xb9, 0x36,
- 0x96, 0xd9, 0xa8, 0x97, 0x02, 0xbc, 0xfc, 0x43, 0xa8, 0x37, 0x79, 0x32,
- 0xd0, 0x4c, 0xab, 0xab, 0xc8, 0x79, 0x78, 0xfc, 0x2e, 0x99, 0xe7, 0xfb,
- 0x08, 0xc3, 0x65, 0x3f, 0xcb, 0x37, 0x43, 0xc5, 0x70, 0x70, 0x0e, 0xbc,
- 0x41, 0xf4, 0xfd, 0x0c, 0x3c, 0x3c, 0xde, 0xc6, 0x7a, 0xbd, 0x8c, 0x01,
- 0x1c, 0xe4, 0x7b, 0x7f, 0x33, 0xf7, 0x08, 0xfc, 0x59, 0xe6, 0x61, 0xbe,
- 0x7f, 0x8c, 0xf5, 0x81, 0x08, 0x35, 0xd3, 0xca, 0x6a, 0x33, 0xeb, 0xf5,
- 0xcd, 0xac, 0x0f, 0x8c, 0x9a, 0x23, 0x3e, 0xf1, 0x2c, 0x51, 0xdb, 0xf2,
- 0xe9, 0xc0, 0x7e, 0xc6, 0x41, 0x3c, 0xeb, 0x8b, 0xea, 0x59, 0xb5, 0xcf,
- 0xb8, 0x55, 0xc2, 0xf1, 0x61, 0xff, 0xfa, 0x99, 0xab, 0x78, 0x2f, 0xd4,
- 0xe2, 0x34, 0xeb, 0xbe, 0x41, 0xf1, 0x6e, 0x46, 0x63, 0x66, 0x86, 0xed,
- 0x80, 0x30, 0x1f, 0x1f, 0xa1, 0x54, 0x31, 0x41, 0xbf, 0x57, 0x74, 0xfb,
- 0x6a, 0x8f, 0xf0, 0x9c, 0x65, 0x6d, 0x7d, 0x0b, 0xcf, 0xeb, 0x7d, 0xa7,
- 0x96, 0x67, 0xb4, 0x91, 0xff, 0x6b, 0x41, 0x6a, 0x7e, 0x11, 0xbe, 0x91,
- 0x12, 0x65, 0xc3, 0xf6, 0x85, 0xeb, 0xe2, 0xbd, 0x1b, 0x16, 0xbd, 0x22,
- 0xf2, 0x5b, 0xf9, 0x7a, 0xbe, 0xe7, 0x79, 0x8c, 0x7b, 0xc5, 0xa2, 0x2b,
- 0x8e, 0x84, 0xf7, 0x9f, 0x05, 0x82, 0xe4, 0x7f, 0x1d, 0x39, 0x48, 0xd0,
- 0xb5, 0xd6, 0xcf, 0x38, 0xfb, 0x98, 0x5f, 0xbf, 0x88, 0xeb, 0xf8, 0xf3,
- 0x75, 0x1c, 0xb7, 0xf1, 0x3a, 0x21, 0x6f, 0x91, 0x77, 0x02, 0x3e, 0xb7,
- 0x3f, 0x64, 0x0a, 0xfc, 0x3b, 0xc2, 0x38, 0xd5, 0x24, 0x7c, 0x81, 0xbd,
- 0x18, 0xeb, 0x0c, 0xb2, 0x6e, 0xb0, 0x7e, 0x66, 0x7c, 0x1f, 0x8e, 0x23,
- 0x3d, 0x7e, 0x86, 0x91, 0xc4, 0xa1, 0xb0, 0x78, 0xff, 0xa1, 0xeb, 0x2f,
- 0x70, 0x70, 0x9c, 0x78, 0x3f, 0xa1, 0x3f, 0xf0, 0x7e, 0x9a, 0xe8, 0xb3,
- 0xd4, 0x46, 0x71, 0x7e, 0x46, 0x2c, 0x27, 0xd7, 0x7d, 0xbe, 0xe8, 0x27,
- 0xe9, 0x47, 0x6a, 0x1e, 0xd6, 0xef, 0x29, 0xa4, 0x7e, 0xdc, 0x5b, 0xd3,
- 0x0a, 0xbe, 0x77, 0xd1, 0x8d, 0x5c, 0x07, 0xdd, 0x54, 0xb1, 0xa5, 0x1b,
- 0xc2, 0xae, 0x62, 0x9e, 0x9c, 0xe8, 0xa2, 0xeb, 0xab, 0x4d, 0x44, 0xbd,
- 0x6d, 0x22, 0xf6, 0x7b, 0x23, 0x97, 0xc7, 0xf3, 0x87, 0xa5, 0xdf, 0xa5,
- 0x82, 0x23, 0x37, 0x3c, 0x70, 0xe4, 0x3d, 0x81, 0x23, 0xef, 0x6d, 0x81,
- 0x23, 0x7b, 0x95, 0x2d, 0xd1, 0x46, 0xcd, 0x0a, 0x3f, 0x5e, 0x63, 0xfc,
- 0x78, 0x81, 0xf1, 0xe3, 0x50, 0x03, 0xfc, 0x30, 0x6a, 0xf0, 0xe3, 0xb0,
- 0xc0, 0x8f, 0x9f, 0x6d, 0x8a, 0x1f, 0x87, 0xfc, 0x9b, 0xf9, 0x82, 0x34,
- 0x6e, 0x0e, 0xd0, 0x4a, 0xce, 0xa1, 0xd5, 0x45, 0x9b, 0x2d, 0x7b, 0xd8,
- 0xe6, 0x88, 0x19, 0xce, 0x88, 0x7a, 0x97, 0x82, 0xc0, 0x2b, 0x96, 0xe3,
- 0x33, 0xa8, 0x69, 0xaa, 0xdb, 0x03, 0x12, 0xef, 0xa5, 0x14, 0xf0, 0x97,
- 0x7b, 0x12, 0xcb, 0xac, 0x9f, 0xf9, 0x73, 0xde, 0xc7, 0x2b, 0x6b, 0x81,
- 0x00, 0x7e, 0xf3, 0xcf, 0x04, 0x69, 0x63, 0x8d, 0xed, 0x54, 0xc6, 0xb1,
- 0xab, 0xb9, 0x21, 0xba, 0x92, 0x1b, 0xa0, 0x8d, 0xdc, 0x30, 0xbd, 0x93,
- 0xc3, 0x33, 0x00, 0x73, 0x3e, 0x16, 0x30, 0x37, 0xe8, 0x60, 0x90, 0xc7,
- 0xac, 0x0e, 0xd0, 0xfa, 0xaa, 0xc6, 0x57, 0xe0, 0x2a, 0xf6, 0x3f, 0xd2,
- 0x23, 0xeb, 0xd0, 0xea, 0x71, 0x20, 0x56, 0x85, 0x03, 0xf2, 0x1a, 0xec,
- 0xfd, 0x42, 0x7d, 0x0d, 0x6d, 0xab, 0x39, 0x83, 0x1c, 0xb8, 0x36, 0xb6,
- 0xc9, 0x6d, 0xe1, 0x73, 0x3d, 0xe8, 0x87, 0x4e, 0x6b, 0xdc, 0x4d, 0x5d,
- 0xbc, 0x07, 0x0e, 0xf2, 0x87, 0x86, 0x59, 0x3f, 0xed, 0x16, 0xfa, 0x68,
- 0xd4, 0x09, 0x84, 0x62, 0x54, 0x3a, 0x6b, 0x38, 0xe8, 0x93, 0xf8, 0x08,
- 0xdf, 0xcf, 0x50, 0x7e, 0x9e, 0x4e, 0x17, 0x3e, 0xd5, 0xea, 0x9e, 0x88,
- 0xd1, 0x9e, 0xe0, 0x39, 0x43, 0x4e, 0x56, 0xe2, 0x22, 0x54, 0x8e, 0x8b,
- 0xb4, 0xf2, 0xba, 0x25, 0x2d, 0xcd, 0x39, 0x3c, 0xae, 0xc8, 0xe3, 0x8a,
- 0x88, 0xa9, 0xf1, 0xf9, 0x55, 0xc4, 0x73, 0x87, 0x68, 0x63, 0x11, 0x34,
- 0x07, 0xff, 0x44, 0x25, 0x86, 0xba, 0xb1, 0x86, 0xf3, 0xf0, 0x51, 0x54,
- 0x62, 0xa8, 0x1b, 0x2a, 0x86, 0xba, 0xb1, 0x36, 0x2d, 0xf8, 0xf0, 0x42,
- 0x8e, 0x79, 0x40, 0xce, 0xaf, 0xf2, 0x07, 0xf7, 0xa9, 0x77, 0xf6, 0x9c,
- 0x10, 0x3e, 0xe4, 0x1e, 0x67, 0x73, 0x18, 0x1e, 0xac, 0x83, 0xe1, 0xb4,
- 0xd0, 0x83, 0xe2, 0x7c, 0xcf, 0x58, 0xee, 0x04, 0xc3, 0x73, 0x96, 0x69,
- 0x69, 0xb7, 0xa2, 0x25, 0x1d, 0x93, 0xed, 0x26, 0xf5, 0xfe, 0x1f, 0xa1,
- 0xeb, 0x4b, 0xfe, 0x33, 0x54, 0xc3, 0x7f, 0x28, 0x10, 0x1d, 0x97, 0xd7,
- 0xa7, 0x8b, 0xaf, 0x0c, 0x6b, 0xff, 0x5b, 0x9a, 0xef, 0xbb, 0x90, 0xdb,
- 0x49, 0x4c, 0x97, 0xe5, 0xa6, 0x67, 0xce, 0xe0, 0x76, 0x9f, 0xad, 0x71,
- 0xe1, 0xc4, 0x6d, 0xe0, 0x93, 0xbc, 0x47, 0x05, 0x9f, 0xfe, 0x77, 0x16,
- 0xc0, 0xb2, 0x93, 0x05, 0x98, 0x57, 0x84, 0x80, 0xf5, 0x03, 0x03, 0xb4,
- 0x8e, 0x39, 0x00, 0x1e, 0x53, 0x68, 0x02, 0xe6, 0x19, 0xa7, 0xf5, 0x40,
- 0xfb, 0xfb, 0x95, 0xc1, 0xeb, 0x5d, 0x1b, 0xa0, 0x67, 0x4f, 0x2d, 0xea,
- 0x79, 0x2c, 0x07, 0xca, 0xa3, 0x4e, 0x2a, 0x0c, 0x24, 0xe6, 0x27, 0x90,
- 0xff, 0x80, 0xfe, 0x00, 0xf9, 0x11, 0x98, 0x9f, 0x9c, 0x81, 0x72, 0xa0,
- 0x35, 0x53, 0xcd, 0x6b, 0x40, 0xfa, 0x40, 0x61, 0x08, 0x2a, 0x53, 0x41,
- 0x63, 0x1d, 0x40, 0xf6, 0x12, 0x21, 0x68, 0xd8, 0x01, 0x69, 0x20, 0xbb,
- 0x79, 0x8a, 0x08, 0x98, 0x9f, 0x14, 0x20, 0xc4, 0xd0, 0x00, 0xcf, 0x4f,
- 0xec, 0x40, 0x97, 0xc2, 0xdc, 0xf4, 0xff, 0xff, 0x31, 0x15, 0x16, 0x60,
- 0xda, 0x03, 0xad, 0xf9, 0xfc, 0xfd, 0xff, 0x80, 0x08, 0x0b, 0x43, 0x0b,
- 0x7c, 0xed, 0x9e, 0xb0, 0x3c, 0xa8, 0x9c, 0x5b, 0x00, 0x64, 0xb5, 0xc1,
- 0xeb, 0x6d, 0x16, 0xf0, 0x7d, 0xc4, 0x0b, 0x18, 0x7e, 0x01, 0xcb, 0x95,
- 0xff, 0xff, 0x97, 0xc2, 0xd5, 0x82, 0x00, 0x00, 0xd4, 0xc2, 0xcb, 0x42,
- 0x60, 0x7c, 0x00, 0x00, 0x00 };
-static u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
- 0x08001ad8, 0x08001b14, 0x08001b14, 0x08001b14, 0x08001b14, 0x08001b14,
- 0x08001a24, 0x08001b14, 0x08001a98, 0x08001b14, 0x080019ac, 0x08001b14,
- 0x08001b14, 0x08001b14, 0x080019b8, 0x0, 0x08002a2c, 0x08002a7c,
- 0x08002aac, 0x08002adc, 0x08002b0c, 0x0, 0x08005fac, 0x08005fac,
- 0x08005fac, 0x08005fac, 0x08005fac, 0x08005fd8, 0x08005fd8, 0x08006018,
- 0x08006024, 0x08006024, 0x08005fac, 0x0, 0x0 };
-static u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
-static u32 bnx2_COM_b09FwSbss[(0x5c/4) + 1] = { 0x0 };
+ 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b,
+ 0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92,
+ 0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0,
+ 0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c,
+ 0x69, 0x64, 0x50, 0x80, 0xb6, 0x4c, 0x46, 0xec, 0x1a, 0x9a, 0x4e, 0x87,
+ 0xd6, 0xa6, 0x6e, 0x9b, 0xc9, 0x34, 0x78, 0x47, 0x1f, 0x8d, 0xa7, 0x15,
+ 0xba, 0x06, 0x1b, 0xd9, 0xd3, 0xd0, 0xa0, 0x6a, 0x71, 0xf1, 0x8f, 0x8d,
+ 0xaf, 0xf9, 0x48, 0xaa, 0x4c, 0x4d, 0xa5, 0x18, 0x48, 0x69, 0xa7, 0x4d,
+ 0xfb, 0xa3, 0x9e, 0xa1, 0x5f, 0x84, 0x32, 0xfd, 0xc1, 0x74, 0xda, 0x4e,
+ 0x3a, 0x24, 0x53, 0x08, 0x84, 0xed, 0xf3, 0x9c, 0x7b, 0xee, 0xea, 0x6a,
+ 0x25, 0x7f, 0xf1, 0x91, 0x1f, 0xd5, 0xcc, 0xfa, 0xde, 0xf3, 0xfd, 0x9e,
+ 0xf7, 0xbc, 0xef, 0xf3, 0x7e, 0xdc, 0xe3, 0x4f, 0x8a, 0xb4, 0x8a, 0xf9,
+ 0xdb, 0x80, 0x5f, 0xfa, 0xc1, 0xdf, 0x2c, 0x5f, 0x37, 0x78, 0xdd, 0x0d,
+ 0x78, 0xbd, 0x41, 0xc5, 0xec, 0x18, 0xeb, 0xf9, 0x4f, 0x12, 0xbf, 0x01,
+ 0xf3, 0xbe, 0xd6, 0x9f, 0x83, 0xdf, 0x9b, 0x68, 0x1c, 0xfb, 0x0f, 0x11,
+ 0xeb, 0x3c, 0x7d, 0xa2, 0x7f, 0xf5, 0xfa, 0x85, 0xdb, 0x15, 0x69, 0xb9,
+ 0x40, 0x7b, 0x2c, 0x58, 0x52, 0xd3, 0xcc, 0x9f, 0x24, 0x54, 0x6e, 0xec,
+ 0xe1, 0x82, 0x2b, 0x89, 0x58, 0x6e, 0xf7, 0xc1, 0xb2, 0x2b, 0x92, 0xaf,
+ 0xed, 0x48, 0x17, 0xe5, 0x67, 0xf5, 0x4a, 0xd2, 0x16, 0xd6, 0x5f, 0x95,
+ 0x7b, 0xef, 0xc9, 0x17, 0x6e, 0xca, 0xfc, 0x68, 0x2e, 0x26, 0x09, 0x27,
+ 0xf7, 0xbc, 0x38, 0xdb, 0x25, 0xd1, 0x83, 0x31, 0x4f, 0xf4, 0xe5, 0x2d,
+ 0xe9, 0x08, 0xe7, 0x7a, 0xb3, 0xfe, 0x42, 0x9f, 0x54, 0xb6, 0xe4, 0x12,
+ 0xa2, 0x72, 0xdb, 0x5e, 0x2d, 0xc4, 0x9c, 0xb1, 0x58, 0xce, 0x91, 0x45,
+ 0x5f, 0x46, 0xee, 0x9f, 0x96, 0x44, 0x22, 0xf7, 0xe5, 0xc4, 0xba, 0x6d,
+ 0x92, 0xb0, 0x73, 0x4b, 0x0f, 0xff, 0xbe, 0x7b, 0xb0, 0xae, 0x5c, 0xb7,
+ 0x7f, 0x5e, 0xda, 0x87, 0x4e, 0x0c, 0xa2, 0xbd, 0x96, 0xe9, 0x17, 0xb9,
+ 0x49, 0x94, 0x5b, 0x69, 0x8f, 0xb9, 0x09, 0x29, 0xf8, 0xae, 0x14, 0x7d,
+ 0x91, 0xbf, 0xac, 0x59, 0x72, 0xc2, 0xed, 0x92, 0xf9, 0x9d, 0xef, 0xd5,
+ 0xf3, 0xa0, 0xe5, 0xfb, 0xee, 0xd2, 0xc3, 0x93, 0x2e, 0xe9, 0x3d, 0x90,
+ 0x08, 0xe8, 0xdd, 0xbb, 0xae, 0xec, 0xda, 0x32, 0x5e, 0x63, 0xdd, 0xa8,
+ 0x62, 0x5d, 0x3c, 0x97, 0x68, 0x3d, 0xe1, 0xb6, 0x9b, 0xba, 0x57, 0x6f,
+ 0x29, 0x60, 0xbe, 0x89, 0x1a, 0xfb, 0xe6, 0xaf, 0x2f, 0xbb, 0x49, 0x53,
+ 0xbf, 0x70, 0x63, 0xc1, 0x4d, 0xa1, 0xbe, 0xc7, 0xb4, 0x8d, 0x3d, 0x58,
+ 0x76, 0x5d, 0xd3, 0xf6, 0x76, 0xac, 0xe0, 0xf6, 0x9b, 0xfa, 0xf7, 0x6e,
+ 0x2e, 0xbb, 0x3b, 0x4d, 0x7d, 0x0f, 0xe6, 0xca, 0x9a, 0xfa, 0x85, 0x7b,
+ 0xca, 0xee, 0xa0, 0xa9, 0xdf, 0x7d, 0x73, 0xc1, 0x1d, 0x32, 0xf5, 0x89,
+ 0xa1, 0xb2, 0x9b, 0x43, 0xfd, 0x97, 0x13, 0x6a, 0x9b, 0x23, 0x53, 0xb5,
+ 0x34, 0x7e, 0x79, 0xb4, 0x0d, 0xa3, 0x6e, 0x37, 0x7e, 0xb7, 0xe3, 0xf7,
+ 0xc8, 0x46, 0xe9, 0x18, 0xc1, 0xf3, 0xbf, 0xba, 0x03, 0xde, 0x81, 0x47,
+ 0x5e, 0x42, 0x5e, 0x8f, 0xa5, 0xe4, 0x85, 0xbe, 0xd7, 0xc1, 0x43, 0x47,
+ 0x4e, 0xfb, 0x62, 0x8d, 0xf4, 0xa5, 0xc0, 0xbb, 0xa4, 0x3c, 0xe3, 0xb7,
+ 0x49, 0xec, 0xb1, 0x18, 0x78, 0xf3, 0xcb, 0x52, 0x4a, 0x26, 0x64, 0xd3,
+ 0xac, 0x25, 0x5b, 0x07, 0x12, 0x92, 0x77, 0xb8, 0x36, 0x4e, 0x7b, 0x26,
+ 0x29, 0xb1, 0xd9, 0xfc, 0x66, 0x25, 0xdb, 0x9c, 0xa2, 0x54, 0xc0, 0xbb,
+ 0x57, 0x29, 0x97, 0x68, 0x4b, 0x4b, 0x71, 0xfa, 0x5a, 0x19, 0x73, 0x48,
+ 0xd7, 0x1f, 0x5c, 0x15, 0xac, 0x95, 0xb0, 0x0a, 0xc7, 0x46, 0x65, 0xca,
+ 0x6b, 0xb7, 0x8a, 0xc7, 0x6e, 0x96, 0x42, 0x56, 0x92, 0x18, 0x97, 0x2a,
+ 0xa1, 0xa5, 0x5a, 0x1b, 0x95, 0x49, 0x4f, 0xac, 0x82, 0x47, 0x7e, 0x76,
+ 0xa1, 0xbd, 0x43, 0xf7, 0x45, 0x5d, 0x4f, 0x4c, 0xcf, 0x9d, 0x40, 0xbd,
+ 0x83, 0xfa, 0x4e, 0x6b, 0x58, 0xcf, 0xa1, 0xeb, 0xd3, 0x13, 0xd2, 0x2e,
+ 0x4f, 0xd5, 0x92, 0xa6, 0x6f, 0xbd, 0x5e, 0xc8, 0x3a, 0xe8, 0x37, 0x2a,
+ 0x13, 0x5e, 0x52, 0xc6, 0xf0, 0x1c, 0xf7, 0xb8, 0x7e, 0x0a, 0x32, 0x75,
+ 0xdd, 0xc1, 0xd2, 0x51, 0x3d, 0x5f, 0x3a, 0x96, 0xe3, 0x7c, 0x3d, 0xe8,
+ 0xf7, 0x12, 0xe8, 0xb2, 0xc4, 0xd6, 0x67, 0x99, 0x97, 0xd2, 0xb4, 0x05,
+ 0x79, 0xc3, 0x53, 0xf3, 0x75, 0x18, 0xf4, 0xdb, 0xe2, 0x0e, 0x58, 0x52,
+ 0xc6, 0x59, 0x55, 0x1c, 0x94, 0x6b, 0x0b, 0xaa, 0xe0, 0xad, 0x93, 0xa2,
+ 0x9d, 0x96, 0xd8, 0x0c, 0x65, 0x69, 0x4c, 0x26, 0x30, 0x46, 0xb9, 0xec,
+ 0xf3, 0x0e, 0xf6, 0x3d, 0xa6, 0xcf, 0xa1, 0x25, 0x57, 0x51, 0x45, 0xbf,
+ 0x4b, 0xd4, 0xec, 0xbd, 0xf2, 0xd2, 0xb4, 0x38, 0x38, 0xc7, 0x7a, 0xc1,
+ 0x9d, 0x54, 0x85, 0xa7, 0x6d, 0x89, 0xcf, 0x58, 0x32, 0xe9, 0x66, 0xa0,
+ 0x01, 0x87, 0xd4, 0x2e, 0x7f, 0x01, 0xfd, 0x38, 0x0e, 0xfd, 0x6a, 0x0a,
+ 0x7c, 0xe5, 0xfb, 0x0e, 0x47, 0x69, 0x79, 0x66, 0x1f, 0x9c, 0x01, 0xf6,
+ 0xf1, 0x8c, 0x87, 0x33, 0xd1, 0x67, 0x94, 0xc6, 0x19, 0x89, 0x35, 0xdc,
+ 0x07, 0x99, 0x3a, 0x6a, 0x4b, 0x29, 0x8b, 0x7d, 0xa1, 0x77, 0x29, 0xbb,
+ 0x4c, 0xd7, 0xc4, 0x74, 0x33, 0x5d, 0x1c, 0x47, 0xba, 0x02, 0x9a, 0xc6,
+ 0x8f, 0x92, 0xbe, 0x65, 0x7a, 0xa6, 0xa6, 0x43, 0x1a, 0xb9, 0x1e, 0x69,
+ 0x0b, 0xe9, 0xe2, 0x38, 0xd2, 0xb5, 0x99, 0x67, 0xcd, 0x3f, 0x6b, 0x18,
+ 0x74, 0x4c, 0x78, 0x36, 0xce, 0xa8, 0x5d, 0x4a, 0x4e, 0xc5, 0x9a, 0x18,
+ 0xda, 0x91, 0x82, 0x36, 0x5b, 0xe3, 0x43, 0xa4, 0xd9, 0xc5, 0x39, 0xb6,
+ 0xe8, 0xf3, 0x56, 0xb9, 0x49, 0xf2, 0x0e, 0xfd, 0xb9, 0x3e, 0xde, 0x6b,
+ 0x8e, 0x4c, 0xea, 0xf9, 0x48, 0xd3, 0x47, 0x31, 0x0f, 0x69, 0x7d, 0x05,
+ 0xb2, 0x3a, 0x08, 0x19, 0xcd, 0xca, 0x5f, 0xf8, 0x3b, 0xe5, 0xcf, 0xfc,
+ 0x7e, 0xf9, 0x0e, 0xf4, 0xf6, 0xdb, 0x7e, 0x5a, 0x9e, 0xf7, 0x7b, 0xe4,
+ 0x39, 0x3f, 0x25, 0xcf, 0x6a, 0xf9, 0x1d, 0x16, 0xe9, 0xa0, 0x4c, 0xa7,
+ 0xa5, 0x13, 0xfa, 0xb3, 0x09, 0xba, 0xf9, 0x38, 0xf8, 0x77, 0xb4, 0x4f,
+ 0xf2, 0x9b, 0x73, 0x92, 0xb8, 0x1a, 0xbf, 0x2b, 0xf0, 0xeb, 0xca, 0xd9,
+ 0x5a, 0x56, 0xec, 0x1c, 0x79, 0x68, 0x4b, 0x51, 0xef, 0xd9, 0x96, 0x09,
+ 0xff, 0x91, 0xab, 0x03, 0xd9, 0x15, 0x19, 0x01, 0x8f, 0xd5, 0xc0, 0x4f,
+ 0xea, 0x79, 0x07, 0xfb, 0x18, 0xd8, 0xa1, 0x79, 0xaf, 0x06, 0x28, 0xb3,
+ 0x69, 0xc8, 0xbd, 0x6d, 0x15, 0xbd, 0x93, 0xc0, 0x8d, 0x36, 0xab, 0x70,
+ 0xa4, 0x22, 0xe5, 0x23, 0x75, 0x29, 0x67, 0xe3, 0xf2, 0x90, 0x53, 0x97,
+ 0xe1, 0x6c, 0x8b, 0xec, 0x77, 0xc0, 0xfb, 0x9d, 0xbf, 0x6d, 0x85, 0x98,
+ 0xfd, 0xb8, 0xff, 0x3b, 0x78, 0x67, 0x9d, 0xc8, 0x51, 0xfd, 0x1e, 0xd4,
+ 0x57, 0xfc, 0xb8, 0xe4, 0x93, 0x95, 0x94, 0x2d, 0x5b, 0x54, 0xb0, 0xee,
+ 0x78, 0xd8, 0x06, 0x7e, 0x2c, 0x01, 0x27, 0x33, 0x5a, 0x5f, 0x4a, 0xd3,
+ 0xeb, 0xdf, 0xce, 0xeb, 0x6a, 0xf4, 0x77, 0x06, 0xe5, 0xac, 0xe6, 0x67,
+ 0x7a, 0xcc, 0xca, 0x25, 0x65, 0x6b, 0x8d, 0xe5, 0x21, 0xeb, 0x4e, 0x9f,
+ 0xf2, 0x8c, 0x77, 0x9f, 0x74, 0x5e, 0x89, 0x7e, 0x36, 0x9e, 0x79, 0x43,
+ 0x6f, 0x94, 0x46, 0xce, 0x43, 0x1a, 0xf9, 0xfc, 0x66, 0x84, 0xc6, 0x27,
+ 0x1b, 0xef, 0x47, 0x23, 0xef, 0x15, 0xff, 0x8f, 0x5a, 0x03, 0xda, 0x86,
+ 0xe4, 0x8d, 0x99, 0xaf, 0x98, 0x75, 0xf0, 0x7e, 0x8a, 0xf3, 0x7f, 0xab,
+ 0x1e, 0xc8, 0x4b, 0xe5, 0x22, 0xeb, 0x2c, 0x44, 0xd6, 0xf9, 0x6e, 0x64,
+ 0x9d, 0xef, 0x46, 0xd6, 0xa9, 0x80, 0xa7, 0xb2, 0x51, 0x41, 0x86, 0x4b,
+ 0x34, 0x63, 0x72, 0x08, 0x73, 0xbe, 0x2e, 0xb1, 0x1c, 0xf5, 0x3c, 0xc4,
+ 0x9b, 0x73, 0xe8, 0x9f, 0x93, 0xb3, 0x33, 0x15, 0x29, 0x1d, 0x89, 0xcb,
+ 0x1d, 0xba, 0xdf, 0x26, 0x43, 0x5f, 0xb4, 0x2d, 0x21, 0x7b, 0x92, 0x7c,
+ 0x0f, 0xdb, 0x6c, 0xf0, 0x99, 0xe5, 0x6f, 0x5d, 0x19, 0x94, 0xf9, 0xbe,
+ 0x60, 0xf6, 0x32, 0x1a, 0x8c, 0x3b, 0xf5, 0xa6, 0xc6, 0xc3, 0x45, 0x9f,
+ 0xb8, 0x25, 0xd9, 0x98, 0x2b, 0xfb, 0x86, 0xb3, 0x5d, 0x32, 0xe1, 0x58,
+ 0xd9, 0xf1, 0xfe, 0x75, 0xd4, 0x8b, 0xbc, 0x72, 0xdb, 0x80, 0x0d, 0x92,
+ 0x56, 0xc4, 0x7c, 0xbd, 0x2f, 0x4b, 0x05, 0xf4, 0x3b, 0x2c, 0x8f, 0x28,
+ 0xb7, 0xb3, 0xa9, 0x9e, 0xba, 0x1d, 0xc3, 0x3b, 0x65, 0x78, 0x97, 0x39,
+ 0x63, 0x1b, 0x65, 0xe2, 0xf0, 0x35, 0xa6, 0x1c, 0xb6, 0x6f, 0xb6, 0x57,
+ 0x96, 0xcf, 0x76, 0xaf, 0x2c, 0x87, 0x38, 0x11, 0xc5, 0x70, 0xee, 0x15,
+ 0xf8, 0xe4, 0x52, 0xee, 0xe2, 0xa0, 0x35, 0x0b, 0x9d, 0x5b, 0x67, 0x68,
+ 0xb8, 0xc2, 0xd0, 0x00, 0x5a, 0xfb, 0x20, 0x59, 0x5a, 0x97, 0xb4, 0x68,
+ 0x35, 0x95, 0xc9, 0xfb, 0xf0, 0x7d, 0x83, 0x6e, 0x0f, 0x74, 0x2e, 0x7c,
+ 0x86, 0xf8, 0xfe, 0x66, 0xc4, 0x5e, 0xf4, 0x40, 0x67, 0x93, 0xe0, 0x55,
+ 0x88, 0xf5, 0xc4, 0xe0, 0x14, 0xec, 0x03, 0x64, 0x55, 0x63, 0x7b, 0x3b,
+ 0xf0, 0xd0, 0x36, 0xd8, 0x9c, 0x30, 0xd8, 0xdc, 0x0e, 0x5c, 0x66, 0xd9,
+ 0x31, 0xe5, 0xa4, 0x29, 0xa7, 0x50, 0x86, 0x1d, 0x9f, 0x25, 0x2e, 0x5f,
+ 0x77, 0x70, 0xef, 0x51, 0x8d, 0xf7, 0xb4, 0x15, 0x40, 0x61, 0xe2, 0x35,
+ 0x71, 0xbb, 0x47, 0xe6, 0x6b, 0x58, 0xaf, 0x81, 0x8d, 0xdc, 0x7b, 0x94,
+ 0x1e, 0xd2, 0xb2, 0x5e, 0x14, 0x6c, 0x57, 0x3e, 0x49, 0x7a, 0x1f, 0xc4,
+ 0xde, 0x89, 0x3f, 0xa4, 0xfb, 0x2a, 0xd0, 0xca, 0x7d, 0xfc, 0x3c, 0x69,
+ 0xe5, 0x7a, 0xcd, 0xf4, 0x7e, 0x58, 0x1c, 0x24, 0xed, 0x27, 0xb1, 0xe7,
+ 0x3c, 0x30, 0x4f, 0xac, 0xd1, 0xbe, 0x51, 0xec, 0x79, 0x04, 0x78, 0x78,
+ 0x3b, 0xf0, 0x70, 0x37, 0xf0, 0x70, 0x18, 0x78, 0x98, 0x03, 0x16, 0x0e,
+ 0x01, 0x0b, 0x07, 0x81, 0x85, 0x59, 0xf0, 0x26, 0x29, 0x73, 0xc0, 0xc6,
+ 0x39, 0x60, 0xe4, 0x1c, 0xe6, 0x18, 0x9f, 0x15, 0xeb, 0x4b, 0xd8, 0xc3,
+ 0x63, 0x33, 0x99, 0x93, 0x90, 0xa5, 0x54, 0x45, 0x41, 0xfe, 0xb3, 0x43,
+ 0x90, 0xed, 0x7e, 0xa9, 0xfa, 0xb6, 0x94, 0x69, 0x53, 0xb7, 0xf7, 0x42,
+ 0xd7, 0x20, 0xef, 0x29, 0x31, 0x7f, 0x1b, 0xcc, 0xf3, 0x1f, 0x45, 0xdc,
+ 0xbf, 0xa3, 0x2c, 0xa6, 0x45, 0xce, 0x48, 0xc9, 0xeb, 0x75, 0x0a, 0xaa,
+ 0x1f, 0xfd, 0x58, 0xce, 0xaa, 0xfb, 0x8f, 0x5c, 0xaf, 0xf6, 0x1e, 0x21,
+ 0x5f, 0xa6, 0x81, 0x57, 0x75, 0x99, 0xcc, 0x52, 0xb7, 0xea, 0x72, 0x22,
+ 0x9b, 0x19, 0xaa, 0x48, 0x9b, 0x4c, 0x25, 0xa7, 0xb5, 0xad, 0xb5, 0x73,
+ 0x87, 0xb5, 0xbd, 0x2a, 0xbb, 0x78, 0xd6, 0x06, 0x54, 0xe9, 0x08, 0xf7,
+ 0xdf, 0x8b, 0x5f, 0x1c, 0xb4, 0x70, 0x7e, 0x5b, 0x86, 0x07, 0x1d, 0xf5,
+ 0x40, 0x5f, 0x05, 0x08, 0x96, 0x71, 0xce, 0x62, 0xe5, 0xe2, 0x74, 0x6f,
+ 0xaa, 0xa8, 0x6c, 0x19, 0xb3, 0x2d, 0x19, 0x87, 0x7c, 0x0f, 0x67, 0xdf,
+ 0xa9, 0x4f, 0x25, 0xd9, 0xbe, 0x4e, 0xbe, 0xae, 0x7d, 0x0e, 0xac, 0x5d,
+ 0x3d, 0x8a, 0x75, 0xe3, 0x38, 0x03, 0xae, 0xcb, 0x79, 0x50, 0xae, 0xd9,
+ 0x28, 0x67, 0x4e, 0x56, 0xc4, 0x87, 0x9e, 0x6c, 0x94, 0xc2, 0xce, 0x16,
+ 0xc9, 0x8f, 0xa4, 0x65, 0x7c, 0xc6, 0x07, 0x4e, 0xe1, 0x1c, 0xdd, 0x56,
+ 0x29, 0x8d, 0xa6, 0xe5, 0xd1, 0x19, 0xd6, 0x9d, 0xc6, 0xfe, 0x33, 0x87,
+ 0xf2, 0xc2, 0xfd, 0xc7, 0xf5, 0xbe, 0xd2, 0xea, 0xb4, 0xec, 0xf7, 0xde,
+ 0x30, 0x7a, 0x14, 0x94, 0xef, 0xc7, 0x99, 0x9e, 0xf0, 0x17, 0xb0, 0x7f,
+ 0x57, 0xe6, 0x81, 0xff, 0xc5, 0x23, 0xc0, 0x41, 0xb7, 0x03, 0x98, 0x95,
+ 0x59, 0xa0, 0x4d, 0x8d, 0xc1, 0xef, 0xab, 0x6a, 0x5e, 0xf7, 0xc8, 0x91,
+ 0x19, 0x25, 0xdf, 0xbe, 0x31, 0x8d, 0x32, 0xb0, 0x31, 0x9b, 0x39, 0x3d,
+ 0xa6, 0x7a, 0xe4, 0x86, 0xce, 0x14, 0xc6, 0xe5, 0x54, 0xc9, 0xdb, 0x18,
+ 0x03, 0x2f, 0x8f, 0xa7, 0x15, 0xfb, 0x2a, 0x29, 0x66, 0x63, 0x38, 0xff,
+ 0x0a, 0xfa, 0xbf, 0x8f, 0xf5, 0x7a, 0x64, 0x16, 0xbe, 0xd6, 0xec, 0x4c,
+ 0x1e, 0xe3, 0x88, 0x5d, 0x99, 0xe3, 0x4b, 0x0a, 0x18, 0x33, 0x0b, 0xf9,
+ 0x1e, 0x85, 0x2f, 0x33, 0x03, 0xd1, 0x69, 0x4d, 0xe3, 0x4c, 0x7b, 0x9d,
+ 0x71, 0xe0, 0x41, 0xbe, 0x87, 0xef, 0x9c, 0xd3, 0x95, 0x13, 0x1e, 0xe5,
+ 0x30, 0x2d, 0x4f, 0xf9, 0x1c, 0xd7, 0xbb, 0xf0, 0x1c, 0x7c, 0x9f, 0xdf,
+ 0xf5, 0xae, 0x44, 0xff, 0x77, 0xe1, 0x07, 0x3b, 0x52, 0xc5, 0xb9, 0x95,
+ 0xc1, 0xcb, 0x7c, 0x2a, 0x28, 0x8f, 0xcf, 0x66, 0x16, 0xde, 0x50, 0x7c,
+ 0x77, 0x2b, 0xf3, 0xea, 0x5a, 0x91, 0x4e, 0xf2, 0x33, 0x0b, 0x5e, 0xba,
+ 0x8e, 0x52, 0xdb, 0x8d, 0xef, 0x47, 0x3d, 0x72, 0x41, 0x9f, 0x2d, 0xf3,
+ 0x03, 0x51, 0x3d, 0xa2, 0x3d, 0x0c, 0xf5, 0x28, 0x93, 0x5a, 0x52, 0x0a,
+ 0xed, 0xb6, 0x1c, 0xd6, 0x65, 0x0b, 0xb4, 0x66, 0x52, 0xdc, 0xdf, 0x44,
+ 0xad, 0x5f, 0x9e, 0xf2, 0xd8, 0x1f, 0x7c, 0x9e, 0x6e, 0x37, 0xfd, 0x4f,
+ 0x83, 0x87, 0xf4, 0xdf, 0xfa, 0x41, 0x73, 0xa0, 0x5b, 0xf3, 0xd3, 0x49,
+ 0xdd, 0x36, 0xe5, 0x05, 0x7e, 0x9a, 0x82, 0x2f, 0x37, 0x07, 0x5f, 0xae,
+ 0xa8, 0xf5, 0xcc, 0xc9, 0xc3, 0xd7, 0x87, 0x9e, 0x04, 0x3a, 0x56, 0xad,
+ 0x91, 0x96, 0xbb, 0x40, 0x5f, 0xa6, 0x02, 0x62, 0x0e, 0xab, 0x1c, 0xce,
+ 0x7d, 0x50, 0x2a, 0xf4, 0xf7, 0xce, 0xc6, 0x9e, 0x92, 0xb1, 0x2a, 0xed,
+ 0x11, 0x7e, 0x9e, 0xeb, 0x30, 0xbe, 0xc8, 0x6b, 0x5b, 0xd1, 0x0d, 0x39,
+ 0x80, 0x1d, 0xc9, 0x6e, 0x32, 0x7e, 0xce, 0x13, 0x38, 0xcf, 0x33, 0x38,
+ 0xf7, 0x9a, 0xec, 0x3d, 0xf6, 0x0a, 0x65, 0xba, 0xbf, 0x2a, 0x99, 0xfe,
+ 0x29, 0xd9, 0xe1, 0xcc, 0x43, 0x1f, 0xf3, 0xa3, 0xf5, 0x5b, 0x54, 0x8e,
+ 0x63, 0x0e, 0x62, 0x0c, 0x9e, 0xd5, 0x57, 0xe4, 0x21, 0x9f, 0x75, 0x0f,
+ 0x81, 0x9f, 0xd0, 0x95, 0xc1, 0x27, 0x8c, 0x1e, 0x60, 0x3e, 0x3b, 0x9c,
+ 0xef, 0x15, 0x33, 0x1f, 0xfb, 0xb1, 0x0f, 0xc7, 0x2c, 0xcf, 0xbb, 0x8b,
+ 0xb6, 0x08, 0x78, 0xb4, 0x4b, 0xd5, 0x6f, 0x89, 0xa3, 0xfd, 0xc4, 0x20,
+ 0xdf, 0x31, 0x0f, 0x6c, 0x91, 0xe3, 0x9e, 0x41, 0x5f, 0xf8, 0x7a, 0xde,
+ 0x7a, 0x29, 0x74, 0x85, 0xf4, 0x52, 0x06, 0xe8, 0x27, 0x68, 0x1b, 0xbc,
+ 0x39, 0xe0, 0xfd, 0x1f, 0xc6, 0x02, 0x99, 0x3c, 0x80, 0x32, 0xf5, 0xef,
+ 0x80, 0x14, 0xbd, 0x0c, 0xf6, 0x09, 0x1d, 0xf3, 0x3b, 0xac, 0x60, 0x8f,
+ 0xe0, 0xff, 0xc8, 0x39, 0xf0, 0x41, 0x2a, 0x01, 0x6f, 0xc8, 0x17, 0xf2,
+ 0xa4, 0x03, 0xb2, 0x0f, 0xb9, 0x87, 0xdc, 0x96, 0x34, 0x0f, 0xfe, 0xbd,
+ 0x33, 0xf0, 0x8b, 0x33, 0x95, 0x3c, 0xe3, 0xb9, 0x4e, 0xe2, 0x26, 0x30,
+ 0xcc, 0x87, 0x70, 0x60, 0xee, 0x25, 0xb5, 0x9e, 0xf4, 0xa6, 0x97, 0x62,
+ 0x7d, 0x2c, 0xf7, 0x2f, 0x41, 0x86, 0xab, 0x38, 0x9f, 0xc2, 0xce, 0x5e,
+ 0x83, 0x5b, 0xcf, 0xc6, 0x28, 0xaf, 0x55, 0x60, 0x4c, 0xc9, 0xdb, 0xe1,
+ 0xdc, 0x4d, 0xbe, 0x39, 0x8e, 0x3c, 0xe7, 0x45, 0xb1, 0x03, 0xb6, 0xcf,
+ 0xa5, 0x1c, 0x26, 0x21, 0x07, 0x36, 0x6c, 0x68, 0x0a, 0x67, 0xfe, 0x6f,
+ 0x9d, 0xc1, 0x5e, 0xf8, 0x6e, 0xcb, 0x9c, 0x83, 0x35, 0xbd, 0xc5, 0x8d,
+ 0x41, 0x1d, 0xdf, 0xb7, 0xf0, 0x8c, 0x0e, 0xaf, 0xa4, 0x9d, 0xe7, 0xdb,
+ 0x7c, 0xa6, 0x27, 0xb0, 0x17, 0xd6, 0xe3, 0x59, 0x3d, 0x2e, 0x7b, 0x89,
+ 0x9b, 0x83, 0xdb, 0x52, 0x2f, 0xa2, 0x7f, 0x11, 0x36, 0xa1, 0x62, 0xb3,
+ 0xed, 0x6d, 0x6b, 0x79, 0x8c, 0xa2, 0x5f, 0x0a, 0x1f, 0x78, 0xc9, 0xfa,
+ 0x92, 0xff, 0x92, 0x55, 0xa8, 0xbe, 0x6d, 0x15, 0x21, 0x27, 0x55, 0x8f,
+ 0xf1, 0x0b, 0xf5, 0xc7, 0xc1, 0xda, 0x99, 0xd4, 0x5b, 0xaa, 0x37, 0x3d,
+ 0x0f, 0x2c, 0xb8, 0x1f, 0x3a, 0x5d, 0xb4, 0x17, 0xa4, 0xec, 0xd7, 0xa4,
+ 0x74, 0x6c, 0x07, 0xf4, 0x2d, 0x1d, 0xa1, 0x8b, 0x78, 0x56, 0xa1, 0x1f,
+ 0x6e, 0xed, 0xf2, 0xa4, 0xd2, 0x92, 0x23, 0xae, 0x6d, 0x83, 0xec, 0xa0,
+ 0xae, 0xb6, 0x2c, 0x7f, 0xb7, 0xad, 0xa2, 0x15, 0xb1, 0xee, 0xe0, 0x4a,
+ 0x7a, 0xab, 0x72, 0x71, 0x7a, 0x77, 0x35, 0xe8, 0x25, 0x66, 0x00, 0xff,
+ 0x3d, 0xe0, 0xbf, 0x07, 0xfc, 0xf7, 0x80, 0xff, 0x1e, 0xf0, 0xdf, 0x83,
+ 0x6d, 0xf0, 0x60, 0x03, 0x3c, 0xd8, 0x00, 0x0f, 0x36, 0xc0, 0x83, 0x0d,
+ 0xf0, 0x0a, 0x38, 0x27, 0xe2, 0x3c, 0x6d, 0xc8, 0x3d, 0x0d, 0xbb, 0x19,
+ 0xf8, 0x39, 0x57, 0x1a, 0xdf, 0x01, 0xfa, 0xe7, 0x6c, 0x91, 0xf1, 0xfe,
+ 0x2b, 0xb0, 0xb7, 0x56, 0x3c, 0xdb, 0xf0, 0xc4, 0x1a, 0xfd, 0x9f, 0x35,
+ 0x7a, 0xf2, 0x55, 0xd0, 0xa5, 0x50, 0xfe, 0x05, 0xc8, 0x61, 0x0b, 0xe8,
+ 0xf9, 0x94, 0xf1, 0x31, 0xbe, 0x61, 0x07, 0x72, 0xd8, 0x86, 0xba, 0xcf,
+ 0xa0, 0xae, 0x0d, 0x7d, 0xf6, 0xa3, 0x0f, 0x7d, 0x94, 0x0e, 0x53, 0x17,
+ 0xed, 0x47, 0x5f, 0xe5, 0x0b, 0x58, 0x2b, 0x83, 0x7e, 0x1d, 0x98, 0xbb,
+ 0x07, 0x7d, 0x6e, 0x46, 0x9f, 0xab, 0x50, 0xa6, 0x6f, 0xdb, 0x8d, 0xf2,
+ 0xa7, 0x9b, 0xc6, 0x5c, 0x83, 0xba, 0xcf, 0x36, 0xd5, 0x9d, 0x45, 0x1d,
+ 0x62, 0x62, 0xe7, 0x45, 0x33, 0xae, 0x82, 0x72, 0x57, 0x53, 0x9f, 0x57,
+ 0x50, 0x37, 0x84, 0xba, 0xbf, 0xc2, 0x13, 0xb1, 0xb0, 0x43, 0x9a, 0xc2,
+ 0x36, 0xfa, 0xa9, 0x69, 0xd4, 0xc7, 0x8d, 0xaf, 0xf9, 0x24, 0x7d, 0x2f,
+ 0xd8, 0xdc, 0x3f, 0xb6, 0x03, 0xdf, 0x0c, 0xde, 0xab, 0x96, 0xc3, 0xb0,
+ 0xfc, 0xcd, 0xa6, 0x32, 0xfb, 0x7e, 0xbf, 0xa9, 0xae, 0x6d, 0xd3, 0xca,
+ 0xf2, 0x4f, 0xe3, 0xab, 0xc7, 0xdc, 0xdb, 0xd4, 0xe7, 0xeb, 0x9d, 0x2b,
+ 0xcb, 0xbb, 0x5b, 0x56, 0x8f, 0xd9, 0xbe, 0x71, 0x65, 0xdd, 0xad, 0x9b,
+ 0x57, 0x96, 0xe9, 0x03, 0x26, 0x11, 0xc3, 0x84, 0xfd, 0x77, 0x7e, 0x22,
+ 0x68, 0x27, 0x7f, 0x9b, 0x65, 0x49, 0x2b, 0x23, 0xca, 0x0a, 0xe7, 0xb0,
+ 0x64, 0x41, 0x9f, 0x1c, 0x95, 0x7b, 0xc9, 0x2a, 0x42, 0xa6, 0x0a, 0x7e,
+ 0x38, 0x1f, 0x75, 0xb6, 0x39, 0x4f, 0x10, 0xe6, 0x07, 0xe8, 0x6f, 0xb5,
+ 0x43, 0x6e, 0xee, 0xa2, 0x4d, 0x3a, 0x54, 0x91, 0x65, 0xfd, 0xdc, 0xaa,
+ 0xce, 0xa7, 0x9f, 0xf7, 0x19, 0x8c, 0x3a, 0x07, 0x3a, 0xeb, 0x32, 0x92,
+ 0x5d, 0x47, 0x1b, 0x63, 0xb0, 0x8b, 0xb8, 0x53, 0xaf, 0xc7, 0xb6, 0xd7,
+ 0x65, 0x5f, 0xf6, 0xdd, 0xba, 0x68, 0xcc, 0xbb, 0x57, 0xe3, 0x4e, 0x5a,
+ 0x75, 0xe3, 0x8c, 0x1c, 0xc4, 0x12, 0x88, 0xed, 0x93, 0xb4, 0x49, 0xc7,
+ 0xe9, 0x9f, 0x1c, 0x0c, 0x30, 0x95, 0xb8, 0x83, 0xb2, 0x3f, 0x85, 0x39,
+ 0xb9, 0x3e, 0x9e, 0x55, 0xe2, 0xb8, 0xad, 0x6d, 0x4a, 0xc9, 0xe1, 0xbc,
+ 0x6b, 0x61, 0xe3, 0xbf, 0xd8, 0xf4, 0x0b, 0x6d, 0xf7, 0x24, 0xec, 0x1b,
+ 0xdb, 0xe8, 0x2b, 0x9c, 0xa4, 0x5f, 0x12, 0xc1, 0xaa, 0x9b, 0x62, 0xe2,
+ 0x2e, 0x63, 0x66, 0xb0, 0xaf, 0x2d, 0xf4, 0xfb, 0x2f, 0x61, 0xaf, 0x6b,
+ 0x63, 0x51, 0xaf, 0xba, 0xb8, 0x6e, 0xef, 0x69, 0xe8, 0x76, 0x28, 0x7b,
+ 0x6b, 0xe5, 0x03, 0x5e, 0xd5, 0x67, 0xf1, 0xac, 0x9f, 0x39, 0x5c, 0x81,
+ 0x2e, 0x2d, 0xea, 0xd8, 0x37, 0x3c, 0x17, 0xfa, 0x38, 0x99, 0xe3, 0x73,
+ 0x90, 0xed, 0xbd, 0x3a, 0x26, 0x60, 0x3c, 0x50, 0x97, 0x5d, 0xd9, 0x4f,
+ 0x25, 0xc9, 0x87, 0xbc, 0xfa, 0x71, 0x9c, 0x3e, 0xc3, 0xa2, 0x47, 0x9e,
+ 0x65, 0xd1, 0x9e, 0x05, 0x26, 0xfc, 0xab, 0x14, 0x93, 0xac, 0x7b, 0xab,
+ 0x3e, 0x0f, 0xbf, 0x4a, 0xfb, 0x47, 0xda, 0xde, 0xd3, 0xbf, 0x83, 0x5d,
+ 0xf7, 0xc9, 0xd3, 0x25, 0xf0, 0x39, 0xf4, 0x01, 0x7e, 0x40, 0x1f, 0x55,
+ 0x56, 0xfa, 0xd2, 0x22, 0x0f, 0xd5, 0xfe, 0x01, 0x36, 0x47, 0x05, 0xbe,
+ 0x0a, 0xe3, 0x65, 0x97, 0xf5, 0x37, 0xc6, 0xe9, 0xcb, 0x05, 0xb6, 0x3e,
+ 0x86, 0xf5, 0x10, 0x5f, 0xd7, 0xfe, 0xd3, 0x2a, 0x79, 0x3d, 0xf4, 0xb3,
+ 0xb0, 0x7f, 0xf8, 0x50, 0x3e, 0xdb, 0x58, 0x97, 0x30, 0xfe, 0x77, 0xbb,
+ 0xf1, 0xb7, 0x1d, 0xe3, 0x6f, 0x6b, 0x3a, 0x12, 0x4e, 0x2e, 0xf4, 0x0b,
+ 0x78, 0x66, 0xe9, 0x83, 0x6a, 0x3b, 0xfd, 0x82, 0x0e, 0x59, 0xdb, 0x2f,
+ 0x08, 0x69, 0x3a, 0x85, 0x7d, 0xd2, 0xcf, 0xd3, 0x79, 0xa0, 0xce, 0x20,
+ 0xf7, 0x44, 0x1a, 0x42, 0xfb, 0xa8, 0xed, 0xf0, 0x21, 0x98, 0x3c, 0xe6,
+ 0x24, 0x41, 0xeb, 0x6e, 0x29, 0x4c, 0x9f, 0x32, 0xf6, 0x96, 0x71, 0x04,
+ 0x7d, 0xf8, 0x40, 0x66, 0x0b, 0xd9, 0x0e, 0xcb, 0xcc, 0xd3, 0x05, 0x0b,
+ 0x19, 0xc9, 0x51, 0x71, 0x2d, 0xfa, 0x31, 0xa1, 0x4f, 0xb3, 0x60, 0x7c,
+ 0x9a, 0x33, 0xb2, 0xcf, 0x0b, 0xe2, 0x86, 0x91, 0xda, 0x12, 0xea, 0x34,
+ 0xed, 0x29, 0xfa, 0x96, 0x0a, 0x3e, 0x77, 0xfe, 0xde, 0x0c, 0x02, 0x90,
+ 0x60, 0x2f, 0x5b, 0xb1, 0x97, 0x6a, 0x63, 0x2f, 0x6d, 0x4b, 0xcd, 0x3e,
+ 0x0e, 0xc7, 0x4e, 0xae, 0x1a, 0x2b, 0xd8, 0xc7, 0xdc, 0x79, 0xda, 0xb8,
+ 0x47, 0xfa, 0x0d, 0x8e, 0xd9, 0x63, 0x78, 0x4e, 0x8f, 0x63, 0x8f, 0x49,
+ 0xab, 0xa4, 0x7d, 0x2d, 0xfa, 0x2d, 0x88, 0xb3, 0x6b, 0x2f, 0xe1, 0x49,
+ 0xfd, 0xd0, 0xf3, 0x60, 0x4f, 0xed, 0x7a, 0x4f, 0x53, 0xde, 0x2b, 0x7a,
+ 0x1f, 0xf3, 0xb5, 0xbf, 0x91, 0xf2, 0xb1, 0x1f, 0xc0, 0xee, 0x45, 0x73,
+ 0x73, 0xcc, 0x6b, 0x92, 0x1f, 0x95, 0x08, 0x7e, 0x72, 0xaf, 0xcc, 0xbb,
+ 0xbd, 0x1c, 0x0f, 0xe2, 0x83, 0x69, 0x9c, 0xb1, 0x15, 0xb4, 0xeb, 0xf5,
+ 0x43, 0xbe, 0xb6, 0x44, 0xe8, 0xa9, 0xc3, 0xe7, 0x4c, 0x81, 0x86, 0xe8,
+ 0x98, 0x03, 0x32, 0xec, 0xf1, 0x3c, 0x7a, 0x53, 0x7b, 0xc5, 0x75, 0x4a,
+ 0x12, 0xfa, 0x19, 0x5c, 0x9f, 0x3a, 0x5f, 0x84, 0xe3, 0xcb, 0x5c, 0x6a,
+ 0xc8, 0xbb, 0x90, 0x6f, 0xed, 0x4b, 0xcd, 0x32, 0x30, 0x89, 0x58, 0xab,
+ 0xec, 0x91, 0x4f, 0xa1, 0x6c, 0x86, 0x6b, 0xbf, 0x6a, 0x71, 0x3f, 0x13,
+ 0x3a, 0x7f, 0xf8, 0x4f, 0x0d, 0x19, 0x1d, 0x07, 0x76, 0x04, 0x32, 0xf7,
+ 0xf7, 0x86, 0x37, 0xa1, 0x6c, 0xb6, 0x9b, 0x73, 0x66, 0x2c, 0x48, 0xdd,
+ 0x09, 0xe5, 0x60, 0x9b, 0x73, 0xa7, 0xe6, 0x05, 0xdb, 0xb4, 0xcf, 0xad,
+ 0xcf, 0x72, 0xac, 0x71, 0x96, 0x1b, 0x9a, 0xe4, 0xf2, 0xdd, 0x8d, 0x81,
+ 0x1e, 0x52, 0xdf, 0xa0, 0xb7, 0xe0, 0xd7, 0xb3, 0x2b, 0xf4, 0xbb, 0xff,
+ 0x3c, 0x39, 0xd9, 0x76, 0x89, 0xcd, 0x7e, 0x0f, 0xbc, 0xbc, 0x06, 0xb1,
+ 0x8a, 0x88, 0x3d, 0x43, 0x1c, 0xa2, 0xbf, 0xb1, 0xec, 0xef, 0xce, 0xcb,
+ 0x5a, 0xbe, 0xee, 0xc5, 0x7c, 0x8d, 0x4f, 0x5e, 0xa2, 0xaf, 0x31, 0xdc,
+ 0x22, 0xad, 0xc4, 0xa2, 0x33, 0xf0, 0x6d, 0x2d, 0x69, 0x71, 0xbf, 0x01,
+ 0x1b, 0x76, 0xda, 0x5e, 0xe7, 0x86, 0x98, 0xd0, 0x2e, 0x9b, 0x66, 0xb7,
+ 0x68, 0x5c, 0x70, 0x66, 0x96, 0x71, 0x61, 0x1c, 0xbc, 0x1f, 0x09, 0xf2,
+ 0xbc, 0xc9, 0x4d, 0x72, 0xa9, 0xf1, 0xf5, 0xb2, 0xdf, 0x3f, 0xd6, 0xf0,
+ 0xfb, 0xaf, 0x6c, 0xe2, 0xe3, 0x5a, 0xb8, 0x78, 0x1a, 0x7c, 0xcb, 0x21,
+ 0xfe, 0x65, 0x5c, 0x3b, 0x8c, 0x78, 0x98, 0xb1, 0x58, 0x1e, 0x31, 0x71,
+ 0xe6, 0xb4, 0xc8, 0x6e, 0xc4, 0xc8, 0x99, 0x1f, 0x31, 0x7f, 0xf5, 0xbc,
+ 0x9f, 0x99, 0x13, 0xb9, 0x1d, 0x7c, 0x1d, 0x04, 0x6e, 0x66, 0x81, 0xa3,
+ 0x3b, 0xc1, 0xdf, 0x7e, 0x8d, 0x9d, 0xf7, 0x1f, 0x11, 0xeb, 0x0e, 0x9d,
+ 0xab, 0xa6, 0x3e, 0x27, 0x61, 0x47, 0xeb, 0xf5, 0xfd, 0xd9, 0x5e, 0xc4,
+ 0xf5, 0x69, 0xb9, 0xd5, 0x66, 0x1c, 0x6b, 0xd9, 0x5b, 0x07, 0xe6, 0x63,
+ 0x51, 0x9f, 0xb4, 0x70, 0x51, 0x3b, 0xb0, 0x9a, 0xf7, 0x45, 0x6d, 0x0b,
+ 0x0e, 0xc7, 0x2e, 0xc4, 0xfb, 0x3b, 0x1a, 0xbc, 0x6f, 0x69, 0x95, 0xd6,
+ 0xdb, 0x75, 0x1e, 0x61, 0xeb, 0xc0, 0x7e, 0xe2, 0x55, 0x16, 0x76, 0x1d,
+ 0xf6, 0xb7, 0x2e, 0xb7, 0x65, 0xdf, 0xae, 0xbf, 0xe8, 0x6e, 0x94, 0xd2,
+ 0xce, 0xfb, 0x0c, 0x66, 0x2f, 0x7d, 0xad, 0xe0, 0x56, 0xa0, 0x1f, 0x41,
+ 0xce, 0x70, 0xef, 0x74, 0x02, 0x96, 0x80, 0x7f, 0x9d, 0x32, 0x3f, 0xf4,
+ 0x16, 0xce, 0x70, 0xc7, 0x49, 0x26, 0x9c, 0x14, 0x70, 0x78, 0x3e, 0xd9,
+ 0xae, 0xf3, 0xc5, 0x9f, 0x70, 0x59, 0xef, 0xe0, 0x4c, 0x47, 0x65, 0x1e,
+ 0xfe, 0x43, 0x75, 0x08, 0x34, 0xee, 0xec, 0x42, 0x7f, 0xea, 0x1d, 0x79,
+ 0x3e, 0x0a, 0xdb, 0x4b, 0x9e, 0x26, 0xd1, 0x7f, 0x0f, 0xfa, 0x74, 0xe2,
+ 0x79, 0x5f, 0x6c, 0xde, 0x61, 0xec, 0xfc, 0x79, 0x94, 0x39, 0x47, 0xd4,
+ 0x76, 0x7e, 0x2e, 0x2e, 0x7a, 0x4e, 0x8e, 0xe9, 0xd2, 0xfa, 0xbf, 0xbc,
+ 0x16, 0xd7, 0x61, 0xdb, 0xcf, 0xea, 0xd7, 0x0f, 0x0c, 0x45, 0xd6, 0xeb,
+ 0x88, 0xac, 0x37, 0x14, 0x59, 0x8f, 0x74, 0x76, 0x46, 0xe8, 0xec, 0xc4,
+ 0xf8, 0x22, 0xd6, 0x26, 0x3f, 0xa2, 0x6b, 0x3e, 0x18, 0x59, 0x33, 0xdc,
+ 0x5f, 0x57, 0x64, 0xdc, 0xbb, 0x58, 0x8f, 0x75, 0xc9, 0x48, 0x1d, 0x69,
+ 0xd8, 0x8c, 0x3a, 0x96, 0x3b, 0x23, 0x74, 0x91, 0xd6, 0x0d, 0xa8, 0xd7,
+ 0xfe, 0x13, 0xf8, 0xdc, 0x0a, 0xbb, 0xa5, 0x60, 0x3b, 0x5a, 0xe0, 0x5f,
+ 0x35, 0xef, 0xf5, 0x51, 0xac, 0x1b, 0xce, 0x97, 0xc4, 0x1c, 0xec, 0xcf,
+ 0xbe, 0x31, 0x33, 0x9e, 0xf5, 0x6c, 0xff, 0xf3, 0xfa, 0x9f, 0x6a, 0xbe,
+ 0x6d, 0x06, 0xed, 0x3a, 0xef, 0x22, 0x73, 0x9d, 0x36, 0xce, 0x93, 0xf1,
+ 0xb1, 0x25, 0x57, 0xbb, 0xca, 0xea, 0x1d, 0xe0, 0xd9, 0x6f, 0x34, 0x58,
+ 0xda, 0x6a, 0x15, 0x8e, 0x30, 0x5f, 0xd0, 0x66, 0x62, 0x3e, 0xc4, 0x1e,
+ 0xda, 0xc6, 0xd8, 0xa6, 0x9d, 0x36, 0x86, 0x7e, 0x0b, 0xed, 0xe7, 0x69,
+ 0xf3, 0x8e, 0x27, 0x64, 0xf8, 0x81, 0x6a, 0xa7, 0xbc, 0xa8, 0x79, 0xea,
+ 0xc8, 0xd9, 0x06, 0x4f, 0xe3, 0xe6, 0xbb, 0xcc, 0x01, 0xf3, 0xcd, 0xa3,
+ 0x0f, 0x7e, 0x11, 0xde, 0x6b, 0x79, 0xd0, 0x90, 0x96, 0xde, 0x01, 0xc6,
+ 0x6e, 0x15, 0x3c, 0x99, 0xa7, 0xb0, 0xf0, 0x0c, 0xf2, 0x17, 0xbd, 0x03,
+ 0xb0, 0x4b, 0xc0, 0xa1, 0xde, 0x81, 0x73, 0x3a, 0x9e, 0xab, 0xfa, 0x8e,
+ 0x75, 0x9b, 0x17, 0xe4, 0x88, 0xce, 0xba, 0x17, 0xca, 0x11, 0xdd, 0xb3,
+ 0x8e, 0x79, 0x8d, 0x30, 0x47, 0x74, 0x56, 0x74, 0x8e, 0xe8, 0xf8, 0x45,
+ 0x72, 0x44, 0xf9, 0x4b, 0xcf, 0x11, 0x71, 0x7e, 0x5b, 0xee, 0x1c, 0x74,
+ 0xd4, 0xaf, 0x9a, 0x1c, 0xd1, 0x1b, 0x12, 0xe4, 0x88, 0x5e, 0x94, 0xb5,
+ 0x73, 0x44, 0x87, 0x9a, 0x72, 0x44, 0x9b, 0x75, 0x8e, 0x88, 0xf3, 0x04,
+ 0x39, 0x22, 0x96, 0x4b, 0x03, 0x43, 0x91, 0x5c, 0x07, 0xf0, 0xd7, 0xbb,
+ 0x01, 0x7c, 0x73, 0xac, 0x51, 0x2f, 0xc4, 0x34, 0x62, 0xff, 0x15, 0x0d,
+ 0xfb, 0xb5, 0x8c, 0x6f, 0x96, 0x96, 0xb9, 0x8b, 0xe1, 0xdb, 0x68, 0xe0,
+ 0x97, 0xac, 0xc0, 0xb6, 0xc9, 0x86, 0xef, 0xe2, 0xad, 0x63, 0x0c, 0x3d,
+ 0x51, 0x5b, 0x9e, 0x77, 0x02, 0xbc, 0x1e, 0x6b, 0xe4, 0x49, 0xce, 0xe7,
+ 0x1f, 0x25, 0xe5, 0xc0, 0x9a, 0xdf, 0xbd, 0x52, 0xf9, 0xd5, 0xdf, 0xbd,
+ 0x2c, 0x49, 0x82, 0xce, 0xd2, 0x40, 0x49, 0xc7, 0x5d, 0xf3, 0xde, 0xaf,
+ 0xc8, 0xd2, 0xdd, 0x0e, 0xf0, 0x27, 0xcc, 0x9f, 0xf0, 0x7c, 0x97, 0x6d,
+ 0x4a, 0x41, 0x7d, 0x7c, 0x39, 0x94, 0x07, 0x74, 0x0e, 0xe5, 0xc5, 0x75,
+ 0xd1, 0x1c, 0xca, 0x59, 0xb9, 0x70, 0x0e, 0xe5, 0x81, 0x35, 0x72, 0x28,
+ 0x2f, 0xcb, 0x72, 0x0e, 0xe5, 0x65, 0x09, 0x73, 0x28, 0x31, 0x59, 0xda,
+ 0x1c, 0x48, 0xe3, 0x03, 0xfe, 0x12, 0x7e, 0x67, 0xf0, 0x0b, 0x72, 0x2a,
+ 0x67, 0x1b, 0xf4, 0xaf, 0x95, 0x53, 0x79, 0x7d, 0xdd, 0x07, 0xc9, 0xa9,
+ 0x04, 0x36, 0x20, 0xcc, 0xa9, 0xe0, 0xe7, 0xc0, 0xe6, 0xa8, 0x68, 0x4e,
+ 0xe5, 0x27, 0xd4, 0x07, 0xd4, 0xb1, 0xcc, 0x7a, 0xe8, 0x05, 0xec, 0x52,
+ 0x5e, 0xe7, 0x38, 0x3e, 0x67, 0x78, 0x38, 0x87, 0x3d, 0xa7, 0x71, 0x16,
+ 0xe4, 0x63, 0xaf, 0xf6, 0x2d, 0xf3, 0x76, 0xca, 0x2a, 0xf4, 0xc1, 0x9a,
+ 0x4d, 0xf3, 0xbb, 0xb8, 0x6d, 0xed, 0xf5, 0x29, 0xe3, 0x09, 0xab, 0x8c,
+ 0xbd, 0x0c, 0x4f, 0xcf, 0xc9, 0x5e, 0x3f, 0xf4, 0xa9, 0x06, 0x1a, 0x73,
+ 0x50, 0x37, 0xe7, 0x81, 0xb3, 0xc0, 0x89, 0x4b, 0xb0, 0x51, 0xa7, 0x40,
+ 0x73, 0x74, 0x1f, 0x88, 0x89, 0x07, 0x51, 0xa7, 0xcf, 0x9c, 0xbe, 0x65,
+ 0x48, 0x4b, 0x9a, 0x7a, 0x7e, 0x09, 0xf3, 0xb1, 0xee, 0x94, 0x8e, 0xc7,
+ 0xca, 0x83, 0xdc, 0x2b, 0x6d, 0xdd, 0x22, 0xe8, 0x43, 0x5d, 0x95, 0x31,
+ 0x20, 0xed, 0x5e, 0x18, 0xa3, 0xb5, 0xeb, 0x18, 0xad, 0x4b, 0xf3, 0x83,
+ 0xbc, 0xbe, 0x35, 0x41, 0xac, 0xec, 0x72, 0xb9, 0x87, 0x33, 0x06, 0xeb,
+ 0x58, 0x0e, 0x62, 0xc1, 0xbc, 0xe2, 0xfb, 0xef, 0xe1, 0x5c, 0x99, 0xa7,
+ 0x09, 0xcf, 0xef, 0x2b, 0x66, 0xdf, 0x43, 0x52, 0xe9, 0x92, 0xc4, 0x66,
+ 0xd0, 0x53, 0x9a, 0xa1, 0xdf, 0xfd, 0x69, 0x1d, 0x83, 0x24, 0xdd, 0xf3,
+ 0xeb, 0xed, 0x1d, 0x97, 0xa1, 0xb7, 0x23, 0x17, 0xd4, 0xdb, 0xaf, 0x25,
+ 0xa2, 0x7a, 0x7b, 0xc7, 0x65, 0xe8, 0xed, 0xbe, 0xcb, 0xd2, 0x5b, 0xee,
+ 0x8d, 0x98, 0x14, 0xe6, 0xc4, 0x56, 0xfb, 0x59, 0xe1, 0xba, 0xe3, 0x58,
+ 0x33, 0x7f, 0x9e, 0x35, 0xc7, 0xce, 0x9b, 0x5b, 0x6d, 0xf6, 0xb1, 0x2e,
+ 0xe5, 0xbc, 0x19, 0x5b, 0xd1, 0xde, 0xb6, 0x1b, 0xbb, 0x74, 0x9f, 0x89,
+ 0xe7, 0xc3, 0xb8, 0x3e, 0xaa, 0x3f, 0x94, 0x0b, 0xca, 0xc2, 0x77, 0xc0,
+ 0x2f, 0xca, 0x43, 0xa8, 0x73, 0xdd, 0x4d, 0x32, 0xb8, 0x88, 0x78, 0xbf,
+ 0xdb, 0xc8, 0x20, 0xcf, 0xba, 0x4f, 0x7f, 0x67, 0xaa, 0x7a, 0x4f, 0x05,
+ 0x71, 0xbe, 0x8b, 0x67, 0x35, 0xd4, 0x35, 0xf0, 0x24, 0x19, 0xb6, 0x91,
+ 0x8f, 0x2e, 0x7c, 0x9e, 0x1d, 0xf0, 0xd7, 0xc0, 0x23, 0x5d, 0xbf, 0x32,
+ 0x27, 0x7c, 0x61, 0x3c, 0x93, 0x4a, 0x1c, 0x7d, 0x4f, 0x0c, 0x42, 0xc7,
+ 0x07, 0x89, 0x51, 0x35, 0xc4, 0x3d, 0x94, 0x43, 0xca, 0xe6, 0xb6, 0xfe,
+ 0x5d, 0x8a, 0x3e, 0xd5, 0x13, 0x88, 0x83, 0x29, 0xaf, 0x69, 0xd9, 0xe5,
+ 0x6f, 0x3b, 0x7d, 0x56, 0x71, 0x8d, 0x7a, 0xbd, 0xc4, 0x58, 0xd1, 0x11,
+ 0xb5, 0x75, 0xe0, 0xbf, 0x13, 0xb4, 0x4b, 0x57, 0xb8, 0x31, 0x23, 0x6b,
+ 0x79, 0xbc, 0x53, 0x6e, 0x7f, 0x08, 0x7b, 0xcf, 0xef, 0xfd, 0xaf, 0xa1,
+ 0x3e, 0x05, 0x9d, 0xa7, 0x7d, 0x67, 0x3c, 0x72, 0x93, 0xe9, 0xd7, 0xad,
+ 0xbf, 0x57, 0x16, 0xb2, 0x37, 0x98, 0x6f, 0x57, 0xb4, 0x3f, 0x19, 0xda,
+ 0xec, 0x15, 0xe7, 0xcc, 0xfb, 0x12, 0x45, 0x1d, 0xcf, 0x70, 0xbc, 0x96,
+ 0x49, 0xc4, 0x20, 0x76, 0x24, 0x97, 0x9e, 0x30, 0xb1, 0x1b, 0x75, 0xac,
+ 0x1d, 0x67, 0xe8, 0x9b, 0x58, 0x85, 0xf1, 0xeb, 0xca, 0x7b, 0x12, 0x6b,
+ 0xcb, 0xc0, 0x96, 0x0f, 0x20, 0x03, 0xcd, 0xe7, 0x97, 0x80, 0xee, 0x87,
+ 0xe7, 0x17, 0xfa, 0x31, 0x73, 0x66, 0xdf, 0xdd, 0xc1, 0x19, 0xfe, 0xbf,
+ 0xd8, 0xa7, 0x15, 0xd9, 0x67, 0x88, 0x47, 0x0f, 0x98, 0x7d, 0xde, 0xd4,
+ 0x84, 0x47, 0x23, 0x4d, 0x3a, 0xfb, 0x71, 0xe2, 0xd1, 0x9f, 0xac, 0xff,
+ 0xf8, 0xf1, 0x88, 0xfb, 0xea, 0x5e, 0x13, 0x87, 0x82, 0x7d, 0x3c, 0x22,
+ 0x2a, 0xf7, 0x51, 0xc6, 0x7b, 0x1f, 0xe4, 0x7c, 0xa2, 0x38, 0xc2, 0x33,
+ 0xe9, 0xd0, 0x3e, 0x6c, 0xa0, 0x7b, 0xb0, 0xe5, 0xd5, 0xb8, 0xbc, 0x7e,
+ 0x57, 0x42, 0xfe, 0xf7, 0x46, 0x7e, 0x0f, 0xb3, 0x4d, 0x4e, 0x8b, 0xe5,
+ 0xd7, 0xd6, 0x07, 0x76, 0xe8, 0xb5, 0x4d, 0x81, 0xdd, 0xe1, 0x98, 0x50,
+ 0x9f, 0x1d, 0xb4, 0xb3, 0xad, 0x5b, 0x96, 0x3a, 0x2f, 0x27, 0x06, 0xdc,
+ 0xe6, 0xbc, 0xa1, 0xd6, 0x8a, 0x01, 0x2f, 0x9c, 0x0f, 0x5c, 0x8e, 0x01,
+ 0x89, 0xb3, 0x9d, 0x5a, 0x36, 0x4a, 0x49, 0xc6, 0x3e, 0x7d, 0x06, 0x3b,
+ 0xf9, 0x8e, 0xd8, 0xd6, 0x43, 0xbc, 0xeb, 0x21, 0xd6, 0xf5, 0x10, 0xff,
+ 0x7a, 0x88, 0x71, 0x3d, 0xc4, 0xb6, 0x1e, 0x62, 0x5b, 0x0f, 0xb1, 0xad,
+ 0xd7, 0x6f, 0x62, 0xe4, 0x11, 0x93, 0xf7, 0xe7, 0x77, 0x72, 0xe6, 0x17,
+ 0x2a, 0xb0, 0x25, 0x93, 0xbc, 0xe7, 0xa0, 0x0a, 0xd9, 0xf5, 0x66, 0x7f,
+ 0x61, 0x4e, 0xbc, 0xc7, 0xe4, 0x6c, 0x5e, 0xd7, 0x79, 0x43, 0x51, 0xb3,
+ 0xad, 0xc1, 0xb7, 0x74, 0xde, 0xc7, 0xf8, 0x2d, 0xf8, 0x25, 0xfa, 0x3e,
+ 0x13, 0x75, 0xb4, 0xae, 0x72, 0xcc, 0xc9, 0x88, 0x52, 0xb9, 0xeb, 0x31,
+ 0x66, 0x47, 0x10, 0x13, 0x24, 0x25, 0xa6, 0x72, 0x6d, 0xe4, 0xa9, 0xa5,
+ 0x72, 0x1b, 0xcc, 0x5c, 0x47, 0x5b, 0x03, 0xdf, 0xaa, 0x8f, 0x65, 0x5b,
+ 0xe5, 0x6e, 0xe6, 0x13, 0xe7, 0x1e, 0xd6, 0xf7, 0x74, 0xae, 0x5c, 0x6b,
+ 0x4a, 0xe3, 0x7b, 0x21, 0x7b, 0x37, 0xe6, 0xd3, 0xf7, 0x88, 0x1a, 0xfc,
+ 0x56, 0xe7, 0xe5, 0xf7, 0x94, 0xe1, 0x77, 0xc0, 0xe3, 0x18, 0xfb, 0xe9,
+ 0xbc, 0x30, 0x79, 0x1d, 0xce, 0xa7, 0xf3, 0x7a, 0x58, 0x47, 0xdf, 0xa5,
+ 0xc0, 0x53, 0xc5, 0xa5, 0x63, 0xf4, 0x9e, 0xb8, 0x1b, 0x5d, 0x37, 0xfc,
+ 0x26, 0x7e, 0x29, 0x6b, 0x76, 0xeb, 0xef, 0x68, 0x81, 0xcd, 0x98, 0xd2,
+ 0x32, 0x68, 0xe7, 0xb8, 0xaf, 0xf7, 0x21, 0x7f, 0x53, 0x5a, 0xfe, 0x8a,
+ 0x88, 0x63, 0x26, 0x07, 0xb7, 0xa5, 0x6d, 0x75, 0xa0, 0x95, 0xf9, 0xd7,
+ 0x61, 0x3f, 0xc4, 0x3d, 0xae, 0xd7, 0x6c, 0xc7, 0x99, 0x57, 0x0b, 0xf1,
+ 0x4c, 0xb6, 0x04, 0xf9, 0xb6, 0x0f, 0xa3, 0x4b, 0xad, 0x4d, 0xba, 0x14,
+ 0xee, 0x93, 0xfb, 0xe7, 0x73, 0xed, 0x3b, 0x15, 0x8b, 0x7e, 0xe4, 0xfb,
+ 0x48, 0x43, 0x36, 0x78, 0xb7, 0xe4, 0x8b, 0x90, 0x41, 0xfd, 0x9d, 0x02,
+ 0x7a, 0x54, 0xaf, 0x0f, 0x33, 0xc7, 0xbc, 0xf3, 0x0b, 0xe6, 0xde, 0x82,
+ 0x3c, 0xcc, 0xfc, 0x83, 0xbd, 0x2a, 0xff, 0x30, 0x0c, 0x59, 0x81, 0x0f,
+ 0xe0, 0x75, 0x68, 0x9f, 0x4e, 0xb9, 0xf4, 0x07, 0x9a, 0xbf, 0xbf, 0x3c,
+ 0xda, 0x16, 0xf0, 0xe1, 0xed, 0xd6, 0xe0, 0x1b, 0xc4, 0xdf, 0x26, 0x57,
+ 0x96, 0x39, 0xfe, 0x7f, 0x8c, 0xac, 0x1c, 0x86, 0x6d, 0x1e, 0x86, 0x2c,
+ 0x22, 0x26, 0xd7, 0xf3, 0x1d, 0x96, 0xd2, 0xd3, 0x0b, 0x9d, 0x2b, 0xfb,
+ 0xa3, 0xee, 0x58, 0xd8, 0xff, 0xb1, 0xa6, 0xfe, 0x8f, 0xa1, 0xff, 0x0b,
+ 0x4d, 0xfd, 0x1f, 0x8b, 0xf4, 0x3f, 0xda, 0xd4, 0x1f, 0x31, 0xe2, 0xd3,
+ 0xff, 0xdc, 0xd4, 0xff, 0x68, 0xa4, 0xff, 0x6c, 0x53, 0xff, 0x59, 0xf4,
+ 0x7f, 0xad, 0xa9, 0x3f, 0xea, 0x8e, 0xb5, 0x98, 0xef, 0x62, 0xc4, 0xd8,
+ 0x7d, 0x26, 0x16, 0xc7, 0xb3, 0xd6, 0xfc, 0xad, 0x85, 0x72, 0xd7, 0x83,
+ 0x33, 0x08, 0xef, 0xb4, 0x51, 0x5f, 0xf3, 0xd0, 0xd7, 0x65, 0x5f, 0x26,
+ 0x90, 0xc7, 0xa8, 0x2c, 0x12, 0x1f, 0x2a, 0x12, 0x73, 0x7d, 0xfa, 0x47,
+ 0x56, 0xb9, 0x1a, 0xda, 0x24, 0xde, 0x5b, 0xe2, 0x7d, 0xd7, 0xc0, 0xf6,
+ 0xc6, 0xdd, 0x45, 0x13, 0x83, 0x5d, 0xd1, 0x06, 0xda, 0x81, 0x97, 0x21,
+ 0x66, 0xca, 0xe1, 0x40, 0x6f, 0x28, 0xbf, 0x9c, 0xdf, 0xe8, 0x0f, 0x65,
+ 0xd5, 0xac, 0x33, 0xbc, 0x0a, 0xd7, 0xd2, 0xab, 0x72, 0x5b, 0xb1, 0x4b,
+ 0xc0, 0xb5, 0x91, 0x06, 0xae, 0x7d, 0x51, 0xe6, 0x1a, 0xf1, 0xf6, 0x19,
+ 0xd9, 0xef, 0xed, 0xe1, 0x3d, 0x9d, 0xc3, 0x79, 0xf9, 0x68, 0xe2, 0xed,
+ 0x3d, 0x0d, 0x3b, 0xc9, 0x3b, 0x1d, 0xe9, 0x83, 0xbc, 0x83, 0x1b, 0xe6,
+ 0x66, 0x27, 0xbd, 0x5f, 0xc7, 0xfe, 0x69, 0x33, 0x2f, 0x37, 0xde, 0xe6,
+ 0x7c, 0x49, 0xd9, 0x1f, 0xdc, 0x77, 0x68, 0xcc, 0x5b, 0x69, 0xcc, 0x9b,
+ 0x32, 0xfa, 0x46, 0x1b, 0xbc, 0x6c, 0x2f, 0x8b, 0xb0, 0x97, 0x63, 0x88,
+ 0xb9, 0x17, 0xbd, 0xb5, 0xf2, 0xa3, 0x97, 0x6b, 0x2f, 0x9b, 0xf3, 0xcc,
+ 0xcd, 0xf6, 0x92, 0xeb, 0x34, 0xe7, 0x96, 0xd3, 0x4d, 0xf8, 0x4f, 0x79,
+ 0x3a, 0x67, 0x7c, 0x6a, 0x3c, 0xab, 0xe7, 0xa0, 0x8f, 0x4a, 0xc6, 0xb4,
+ 0xfc, 0xb2, 0x1c, 0xc6, 0x96, 0xf7, 0x34, 0x62, 0xcb, 0xe5, 0x78, 0x10,
+ 0xbe, 0x6b, 0xff, 0x67, 0x0c, 0x3e, 0xd2, 0x47, 0x76, 0xac, 0xb2, 0xb7,
+ 0x5b, 0xed, 0xd5, 0x6d, 0xcc, 0x97, 0x5e, 0x2b, 0xb7, 0xea, 0x38, 0xfe,
+ 0x8c, 0xc9, 0x4d, 0xcd, 0x69, 0xff, 0x9f, 0xdf, 0x0b, 0xca, 0xd9, 0x4d,
+ 0xc6, 0xdf, 0xbb, 0x18, 0xae, 0xae, 0x8c, 0x4d, 0x95, 0x3a, 0x88, 0xb1,
+ 0x8c, 0x4d, 0xfb, 0xdb, 0x89, 0xa1, 0x05, 0xff, 0x82, 0xe3, 0x31, 0x8e,
+ 0xe3, 0xd9, 0x47, 0xc7, 0xa1, 0xe8, 0xb7, 0x68, 0xc6, 0x07, 0x71, 0x68,
+ 0xc1, 0xff, 0x71, 0x5b, 0x80, 0x83, 0x17, 0x8a, 0x59, 0x3e, 0xdf, 0xce,
+ 0xbc, 0xde, 0xa2, 0x77, 0x31, 0x5a, 0x57, 0xc7, 0xbd, 0xb1, 0x55, 0x71,
+ 0xaf, 0x6d, 0xe2, 0xda, 0x5f, 0xd2, 0x71, 0x6f, 0xc0, 0x63, 0xee, 0x25,
+ 0x1a, 0x47, 0xb9, 0xc0, 0x42, 0x7e, 0x53, 0x21, 0x3e, 0xd0, 0x47, 0x81,
+ 0x9f, 0x35, 0xfd, 0x8b, 0xe0, 0x73, 0x72, 0x0d, 0xb9, 0xf9, 0xb8, 0xed,
+ 0x44, 0xb8, 0xf7, 0x73, 0x12, 0xe4, 0xeb, 0x76, 0x83, 0x16, 0xc6, 0x56,
+ 0x71, 0x23, 0x0f, 0x3f, 0x35, 0xf7, 0x2a, 0xc3, 0x7e, 0x61, 0x1c, 0xdf,
+ 0xf8, 0xee, 0x5a, 0xc9, 0xaf, 0xc8, 0x9f, 0x74, 0x33, 0x0d, 0x8d, 0x73,
+ 0xcf, 0x5f, 0xc6, 0x77, 0x8b, 0x0f, 0x73, 0x3f, 0xa2, 0xd9, 0xae, 0xf1,
+ 0xbb, 0x29, 0xbf, 0x95, 0x8a, 0x75, 0x67, 0x9f, 0x0b, 0x1d, 0xe0, 0xbd,
+ 0xe1, 0x28, 0xbe, 0x26, 0xa4, 0x34, 0x2b, 0x89, 0x64, 0x8e, 0xdf, 0x00,
+ 0x68, 0xff, 0x7f, 0x68, 0xf6, 0x99, 0x92, 0x7d, 0x33, 0x41, 0xce, 0x53,
+ 0x5d, 0xf0, 0x5e, 0xdc, 0xe3, 0xe0, 0x43, 0xe6, 0x50, 0x98, 0xf3, 0x54,
+ 0xc1, 0xbd, 0xb8, 0x43, 0x1f, 0xdd, 0xbd, 0x38, 0xce, 0x6f, 0xcb, 0x9e,
+ 0x35, 0xee, 0xc5, 0xc5, 0x2e, 0xf1, 0x5e, 0xdc, 0x26, 0x9d, 0xf3, 0xe4,
+ 0x3c, 0x41, 0xce, 0x93, 0xe5, 0xad, 0x03, 0xcc, 0x95, 0xf0, 0xee, 0xdb,
+ 0xa0, 0xbe, 0x2f, 0xbc, 0x75, 0xe0, 0xe7, 0x11, 0xa3, 0xfc, 0x75, 0xfb,
+ 0xc7, 0x1f, 0xa3, 0x70, 0x2f, 0xbf, 0x11, 0x7c, 0xdf, 0x95, 0xcb, 0xc9,
+ 0x03, 0x7c, 0xb8, 0xbc, 0xe6, 0x3e, 0x9d, 0xd7, 0x7c, 0xa7, 0x3d, 0x9a,
+ 0xd7, 0x54, 0x17, 0xb9, 0x1b, 0xb6, 0x6f, 0x8d, 0xbc, 0x66, 0x3c, 0x72,
+ 0x37, 0x2c, 0x6e, 0xee, 0x86, 0x6d, 0x72, 0x11, 0x4b, 0x9a, 0x3c, 0xa6,
+ 0xba, 0xe0, 0xdd, 0xb0, 0xce, 0x0d, 0x1f, 0x3e, 0x8f, 0xb9, 0xea, 0x6e,
+ 0x18, 0x6c, 0xdd, 0x16, 0x49, 0x5f, 0x56, 0xdc, 0xf3, 0x61, 0x62, 0x1e,
+ 0xde, 0xab, 0x6f, 0xc1, 0x9e, 0xe3, 0xb2, 0x27, 0x49, 0xf9, 0xe4, 0xdd,
+ 0xc6, 0x3e, 0xe8, 0x02, 0x9e, 0x3e, 0xcb, 0xfd, 0x3c, 0x23, 0x6b, 0xa4,
+ 0x6f, 0xe5, 0x3d, 0x84, 0xe5, 0x3b, 0xbd, 0x89, 0xc6, 0x9d, 0xde, 0x29,
+ 0xc8, 0x8d, 0x9a, 0x49, 0xc8, 0x7c, 0x44, 0xa6, 0x26, 0x3d, 0xf8, 0x4b,
+ 0xb3, 0x8e, 0x69, 0xe7, 0xff, 0xef, 0x48, 0x02, 0xf3, 0x78, 0x0f, 0xb8,
+ 0x43, 0x62, 0xb3, 0xc1, 0x37, 0xcb, 0xe0, 0xff, 0xb8, 0xa4, 0xd0, 0x87,
+ 0x77, 0x3c, 0xe3, 0xb2, 0x5f, 0xe7, 0x2c, 0x42, 0x59, 0xfe, 0x35, 0xf0,
+ 0x78, 0x73, 0x7e, 0xb9, 0x9c, 0x5c, 0xc3, 0xee, 0x27, 0xa5, 0x3c, 0x43,
+ 0x79, 0xbe, 0xc1, 0xfc, 0xff, 0x82, 0xd3, 0x52, 0xf6, 0x4f, 0x99, 0xf8,
+ 0x42, 0x7f, 0xdb, 0x01, 0x2f, 0xb7, 0x18, 0x1b, 0x8c, 0x67, 0x75, 0x0b,
+ 0x6d, 0x1e, 0xd6, 0x38, 0x2e, 0xc3, 0xd3, 0x3b, 0x52, 0x7b, 0x81, 0x77,
+ 0x63, 0x7a, 0xcd, 0xcb, 0xe1, 0xb9, 0x75, 0x9e, 0xef, 0x8d, 0x97, 0xca,
+ 0xf7, 0xd0, 0x3f, 0xae, 0x62, 0x7f, 0x5b, 0x20, 0x1f, 0x5f, 0x95, 0xe2,
+ 0xb1, 0x6b, 0x65, 0xf8, 0x68, 0x06, 0xf4, 0xbc, 0x5f, 0x2f, 0x67, 0xe1,
+ 0x4b, 0x3f, 0xcd, 0x7b, 0x63, 0xc0, 0x50, 0xf0, 0xed, 0xf9, 0x55, 0xdf,
+ 0xb1, 0xa3, 0x77, 0xcd, 0xfa, 0x1b, 0x77, 0x87, 0x9e, 0xf5, 0x25, 0xd1,
+ 0x49, 0x9a, 0x67, 0x96, 0xef, 0x8f, 0x2f, 0xfa, 0xbb, 0xb4, 0x6d, 0x7b,
+ 0xc6, 0x5f, 0x91, 0xfb, 0xd1, 0x67, 0x38, 0x5e, 0xfb, 0x1e, 0xec, 0xdb,
+ 0x39, 0x8b, 0xf6, 0x6d, 0xca, 0x93, 0xab, 0x63, 0xc2, 0xf3, 0x10, 0x0b,
+ 0x3c, 0xd0, 0x77, 0x38, 0x82, 0xef, 0xfb, 0x3d, 0xfa, 0x5c, 0x03, 0xac,
+ 0x58, 0x88, 0xdc, 0xc1, 0x58, 0x3e, 0xdb, 0xe0, 0x6e, 0x46, 0x70, 0x16,
+ 0xc1, 0xfd, 0x11, 0xed, 0x6f, 0x1e, 0xdc, 0xe3, 0x06, 0xf7, 0x47, 0x7a,
+ 0x67, 0x59, 0xd7, 0xd5, 0x64, 0xfb, 0x12, 0x90, 0x01, 0xde, 0x3b, 0xe2,
+ 0xbd, 0x71, 0xd2, 0xac, 0x73, 0x1d, 0xff, 0x47, 0xdd, 0xd5, 0xc7, 0xb6,
+ 0x75, 0x5d, 0xf7, 0xc3, 0x47, 0xea, 0xc3, 0xb4, 0x2c, 0x53, 0x32, 0x25,
+ 0xd3, 0x96, 0x2c, 0xbf, 0x27, 0x3d, 0x59, 0x72, 0xac, 0x14, 0xac, 0xab,
+ 0xad, 0x02, 0x46, 0xa4, 0x0c, 0x49, 0x7f, 0xb4, 0x08, 0x06, 0xfa, 0xa3,
+ 0x99, 0x8b, 0x66, 0xab, 0x4b, 0xd9, 0x4e, 0x0a, 0xf4, 0x0f, 0xb7, 0xc5,
+ 0x80, 0x6c, 0x58, 0x60, 0x86, 0xb4, 0x12, 0x63, 0x56, 0x4c, 0xd6, 0x66,
+ 0x85, 0x0c, 0xd8, 0x30, 0x4e, 0x54, 0x9c, 0x14, 0x50, 0xc6, 0x04, 0x69,
+ 0x83, 0xa2, 0x58, 0x61, 0x45, 0x76, 0x36, 0x6c, 0x7f, 0x65, 0x43, 0xd0,
+ 0x05, 0x9b, 0xb3, 0x38, 0x76, 0xb0, 0x06, 0x45, 0xd6, 0x7d, 0x62, 0x18,
+ 0xd0, 0x0d, 0xdc, 0xf9, 0xdd, 0x0f, 0xf2, 0xf1, 0xf1, 0x51, 0x1f, 0x89,
+ 0x33, 0x60, 0x02, 0x04, 0xbe, 0xf7, 0x78, 0xdf, 0x7b, 0xf7, 0x9e, 0x7b,
+ 0xce, 0xb9, 0xbf, 0x73, 0xee, 0x39, 0x87, 0x9e, 0x7b, 0xdb, 0x9b, 0xf3,
+ 0xb9, 0xca, 0x77, 0x8e, 0x8a, 0x77, 0x0e, 0x28, 0x9d, 0xa5, 0xe3, 0xc5,
+ 0x63, 0xc6, 0x6c, 0x61, 0x22, 0xe2, 0x67, 0xfe, 0x9e, 0xad, 0xc2, 0xbe,
+ 0x6e, 0x87, 0xe1, 0xd6, 0xa2, 0x67, 0xbc, 0x85, 0x9e, 0xcd, 0x32, 0xc1,
+ 0xf6, 0x78, 0x5d, 0x77, 0x4b, 0xda, 0xc9, 0xeb, 0x88, 0x85, 0xd7, 0x31,
+ 0x0e, 0x92, 0x76, 0x75, 0x19, 0xba, 0xe2, 0x8c, 0x6f, 0x68, 0xd0, 0xee,
+ 0x74, 0x9d, 0x76, 0x3b, 0xff, 0x1f, 0xd1, 0xee, 0x1d, 0x81, 0x7f, 0x5f,
+ 0xad, 0x22, 0x6e, 0x4d, 0x63, 0x00, 0x9d, 0x3b, 0x04, 0x3a, 0x42, 0x9f,
+ 0x5a, 0xe5, 0x15, 0x82, 0x4e, 0x45, 0x5c, 0x71, 0xad, 0xf6, 0x5a, 0xb4,
+ 0xee, 0xa7, 0x64, 0xbb, 0x04, 0xf6, 0x09, 0xfc, 0x79, 0xed, 0xd7, 0xc8,
+ 0x63, 0x1f, 0x6b, 0x8d, 0x04, 0x56, 0x72, 0xdb, 0x27, 0x0c, 0x08, 0x1d,
+ 0xf6, 0xc9, 0xb1, 0x4d, 0xda, 0x27, 0xe7, 0xa5, 0x7d, 0x92, 0xdd, 0xb8,
+ 0x7d, 0xb2, 0xbb, 0x25, 0xae, 0xab, 0x31, 0x9e, 0xcd, 0xdb, 0x27, 0xc6,
+ 0x9a, 0xf6, 0xc9, 0x90, 0xc3, 0x17, 0x83, 0xfe, 0xfe, 0x06, 0x65, 0x8f,
+ 0x43, 0xc7, 0x69, 0x3a, 0x83, 0xc6, 0xc7, 0x5d, 0x7e, 0xe1, 0x4f, 0x93,
+ 0xd6, 0xbf, 0xf8, 0x3f, 0xa6, 0xf5, 0x50, 0x8b, 0xcf, 0xbb, 0x31, 0x1e,
+ 0x0a, 0xef, 0xd8, 0x14, 0x8e, 0x77, 0xd3, 0x7a, 0xa8, 0xad, 0xef, 0xb4,
+ 0x7d, 0xcc, 0x62, 0xb3, 0xef, 0x74, 0xd4, 0x68, 0xa7, 0xdb, 0xff, 0xd8,
+ 0xe1, 0x53, 0x75, 0xea, 0x77, 0xc8, 0x14, 0xf9, 0x8e, 0x4d, 0xe8, 0x77,
+ 0x41, 0x96, 0xac, 0x6c, 0x96, 0x60, 0x33, 0xe1, 0x7d, 0x11, 0x21, 0x6b,
+ 0x2e, 0xbc, 0xc5, 0xef, 0x63, 0x7a, 0xbe, 0xf8, 0x87, 0x62, 0x9d, 0x92,
+ 0xfe, 0x07, 0xb4, 0x0f, 0xfb, 0xce, 0x88, 0xb6, 0x32, 0xbe, 0x49, 0xf9,
+ 0x23, 0x14, 0xf6, 0x6f, 0xe7, 0x87, 0x68, 0x5d, 0xf3, 0x36, 0x67, 0x2b,
+ 0x68, 0x19, 0xdf, 0xcb, 0xf3, 0x12, 0x69, 0xb2, 0xb5, 0xa0, 0x3f, 0xcf,
+ 0x33, 0x2e, 0x18, 0xad, 0x63, 0x82, 0xe6, 0xb9, 0xb9, 0x28, 0x6c, 0x3a,
+ 0xad, 0x3b, 0x57, 0x64, 0xec, 0xa9, 0xb8, 0x0e, 0x9c, 0xa6, 0x75, 0xa7,
+ 0x1b, 0x07, 0xef, 0xf5, 0xe0, 0x0b, 0xcf, 0xdc, 0x4f, 0x3d, 0x77, 0x26,
+ 0x62, 0xce, 0x53, 0x9e, 0x73, 0x57, 0xcf, 0xe1, 0xca, 0x36, 0xda, 0xca,
+ 0xfb, 0x53, 0x62, 0x5c, 0xdf, 0xfc, 0x62, 0x02, 0xb9, 0x6a, 0xf5, 0xfc,
+ 0x21, 0x77, 0xce, 0x14, 0xd6, 0x01, 0x2d, 0x87, 0x3a, 0x3f, 0x1b, 0xb4,
+ 0x18, 0xf1, 0xc8, 0x99, 0x72, 0xae, 0x25, 0xb8, 0xcf, 0x4d, 0x8b, 0xc6,
+ 0x3a, 0x32, 0xa7, 0xd6, 0x91, 0x45, 0x87, 0x1e, 0x6f, 0xc5, 0xed, 0xfd,
+ 0x1e, 0xb8, 0xdd, 0x2b, 0x6f, 0x0a, 0x7d, 0x7a, 0x92, 0x71, 0xc8, 0x67,
+ 0x80, 0x43, 0x42, 0xc8, 0x5b, 0x92, 0x58, 0x04, 0xdf, 0x17, 0x19, 0x8f,
+ 0x44, 0x98, 0x57, 0x7e, 0x44, 0xe7, 0x18, 0x6b, 0x5f, 0xa7, 0xfd, 0xca,
+ 0x3e, 0x83, 0xdc, 0xea, 0x38, 0x53, 0xc4, 0xf1, 0xfb, 0x28, 0xfb, 0x98,
+ 0x35, 0x19, 0xa7, 0x1f, 0xd1, 0x59, 0x11, 0x33, 0x83, 0xfd, 0x3d, 0xc4,
+ 0x1c, 0x3c, 0x20, 0xde, 0x2f, 0x7d, 0x19, 0xf7, 0x23, 0xa6, 0x6e, 0xe3,
+ 0xf1, 0xfb, 0x2a, 0xb7, 0x8e, 0xdb, 0xe1, 0x9d, 0x4b, 0x4a, 0xa6, 0xc4,
+ 0x35, 0xbe, 0xff, 0x49, 0xa3, 0xf5, 0xfe, 0xb8, 0x91, 0xaa, 0xa6, 0x8c,
+ 0x44, 0x05, 0xed, 0x9e, 0x34, 0x92, 0x55, 0xd8, 0x90, 0x9a, 0x47, 0xac,
+ 0x28, 0xe4, 0x6d, 0x95, 0xd6, 0xdf, 0x8b, 0x58, 0x24, 0x57, 0x9e, 0xc4,
+ 0x06, 0xfa, 0x7d, 0xb8, 0xa9, 0xdf, 0x9a, 0xbe, 0x38, 0x86, 0xbf, 0xe7,
+ 0x15, 0xa6, 0xa9, 0xc6, 0xb5, 0x41, 0xf8, 0xd7, 0x27, 0xb3, 0xb4, 0x16,
+ 0xae, 0xb5, 0x5a, 0x70, 0xed, 0xe2, 0xba, 0xfd, 0xfe, 0xa4, 0x32, 0x2e,
+ 0xf3, 0xa3, 0xfd, 0xb6, 0xc0, 0xaf, 0xdc, 0xef, 0x26, 0x6c, 0xeb, 0xe2,
+ 0x29, 0xb4, 0xd1, 0x7e, 0x70, 0xed, 0x07, 0xeb, 0x55, 0xf1, 0xc0, 0x3a,
+ 0x3e, 0x21, 0x88, 0x7c, 0xaf, 0x90, 0x8c, 0x6b, 0x85, 0x8d, 0xb5, 0xc2,
+ 0xfd, 0x83, 0xbd, 0x05, 0x9f, 0x8f, 0xb0, 0xb7, 0xcc, 0x24, 0x49, 0x5f,
+ 0xf7, 0x99, 0xaa, 0xd3, 0xbf, 0xeb, 0x95, 0x4b, 0x39, 0xea, 0x91, 0x4b,
+ 0xe9, 0x94, 0xb5, 0x80, 0x43, 0xd6, 0x22, 0x0e, 0xdc, 0x36, 0xcc, 0x76,
+ 0x4b, 0x0f, 0xeb, 0x90, 0x1e, 0xb1, 0x6d, 0xe2, 0xbf, 0xea, 0xb4, 0x5b,
+ 0xdc, 0x79, 0xf1, 0x90, 0x3b, 0x60, 0x33, 0x69, 0xc3, 0xa4, 0x4a, 0xf5,
+ 0x9c, 0x7a, 0x1e, 0x77, 0x23, 0x6f, 0xb1, 0xd2, 0x92, 0x63, 0xe9, 0xd5,
+ 0xdf, 0x91, 0x96, 0xfe, 0x62, 0xfd, 0x8a, 0xb7, 0xc5, 0x74, 0x5e, 0x76,
+ 0xd5, 0xfd, 0xea, 0x9f, 0x5b, 0x9f, 0xe1, 0x5d, 0xa3, 0xc2, 0xe7, 0x9d,
+ 0xad, 0xeb, 0xb2, 0x19, 0xd9, 0xdf, 0x42, 0xb3, 0x9d, 0xe1, 0xbf, 0x42,
+ 0x8a, 0x76, 0xde, 0xba, 0x7d, 0x73, 0xfe, 0xb3, 0xad, 0x6e, 0x1c, 0xdc,
+ 0x27, 0xfd, 0x62, 0x73, 0x2a, 0x0e, 0x7b, 0x40, 0xd9, 0x7b, 0xeb, 0xf1,
+ 0x3b, 0xae, 0xcd, 0x29, 0x5f, 0xa2, 0x65, 0x96, 0x09, 0x7c, 0x7e, 0xfc,
+ 0x54, 0x87, 0x1d, 0x52, 0x7b, 0x59, 0xd8, 0xaf, 0x02, 0xdf, 0xeb, 0xe7,
+ 0x43, 0x67, 0x6f, 0x64, 0xce, 0xcc, 0x96, 0x39, 0x93, 0x7c, 0x05, 0x5b,
+ 0x0b, 0xf1, 0xc5, 0x53, 0xae, 0x18, 0xef, 0x4f, 0x42, 0x8b, 0x5e, 0x8f,
+ 0xb8, 0x67, 0xc4, 0x2d, 0xb7, 0xeb, 0xe7, 0x1d, 0x07, 0x2e, 0x47, 0x7f,
+ 0x6b, 0xb5, 0x57, 0xa2, 0xbb, 0xe5, 0x5a, 0x5c, 0xf5, 0xc6, 0x48, 0xa1,
+ 0x0d, 0xf7, 0xcf, 0xbd, 0xf6, 0xee, 0xda, 0xe0, 0xda, 0x2b, 0xea, 0x8b,
+ 0xf8, 0x0e, 0x09, 0x1d, 0xd0, 0x43, 0x95, 0x12, 0xe2, 0xaf, 0x3f, 0x0b,
+ 0x99, 0x67, 0x3d, 0xeb, 0xc8, 0x49, 0xf3, 0x9e, 0xc7, 0xfa, 0x9e, 0x4a,
+ 0x20, 0x86, 0xbd, 0x3f, 0xc4, 0x96, 0xf4, 0xb3, 0xee, 0x41, 0xfb, 0x71,
+ 0xf3, 0x16, 0xfc, 0xbd, 0xca, 0xff, 0x94, 0x52, 0xeb, 0xcb, 0xa1, 0x0d,
+ 0xec, 0xad, 0x6c, 0x4e, 0x4f, 0x5b, 0xe6, 0x0a, 0x61, 0xdf, 0x07, 0xf1,
+ 0xc2, 0xc7, 0x7a, 0xa9, 0xf7, 0x2b, 0x5d, 0x5d, 0xf6, 0x1f, 0xf4, 0xc9,
+ 0xbd, 0x28, 0x7c, 0xd7, 0x43, 0x2f, 0x94, 0x10, 0xcb, 0x8d, 0xef, 0x7e,
+ 0x8b, 0xbf, 0xf3, 0xd2, 0x51, 0x3a, 0x16, 0x1d, 0x58, 0x4e, 0xce, 0x4f,
+ 0x99, 0x60, 0x2b, 0xd5, 0xe8, 0x6f, 0xa2, 0x9f, 0x93, 0xfb, 0x19, 0xd5,
+ 0xfb, 0xbd, 0x57, 0xe3, 0xe5, 0x2f, 0xfc, 0x69, 0xdf, 0xc7, 0x8d, 0x8d,
+ 0xfc, 0xd6, 0x86, 0xfc, 0x85, 0xd8, 0xe7, 0xdf, 0xc8, 0x9e, 0x89, 0xde,
+ 0x1b, 0x9e, 0x16, 0x39, 0xa7, 0x4e, 0x3e, 0xb8, 0x3f, 0xfb, 0xc3, 0xe0,
+ 0x87, 0x91, 0x16, 0x5d, 0xf5, 0xc9, 0xfd, 0xfd, 0x6e, 0xba, 0x06, 0x3d,
+ 0x7d, 0x55, 0xde, 0xfb, 0xc0, 0xd8, 0xf3, 0x87, 0x9f, 0xba, 0x4a, 0x67,
+ 0xae, 0x81, 0x87, 0x0d, 0xe6, 0xb6, 0x31, 0xca, 0x87, 0x91, 0x57, 0x24,
+ 0x72, 0x73, 0xf4, 0xbe, 0xa1, 0xc8, 0x15, 0x3a, 0x23, 0x72, 0x20, 0xc7,
+ 0x23, 0xf7, 0x78, 0x3d, 0x3c, 0x53, 0x7d, 0x9b, 0xce, 0x56, 0x82, 0xfc,
+ 0xdf, 0xc0, 0xee, 0xad, 0x79, 0x90, 0xcd, 0x3c, 0x7e, 0x4f, 0xf0, 0xf8,
+ 0xf0, 0x9a, 0x3c, 0x7e, 0xa4, 0xce, 0xe3, 0x5f, 0xe9, 0x97, 0xfc, 0xdc,
+ 0xcb, 0xcf, 0xea, 0xa5, 0x43, 0xe2, 0xb9, 0x6f, 0xf3, 0xf1, 0x56, 0x3a,
+ 0x14, 0x92, 0xc7, 0x67, 0x2b, 0xac, 0xe3, 0x0b, 0x6f, 0xd3, 0xb9, 0x6b,
+ 0x59, 0x5f, 0x4a, 0xe4, 0x2f, 0x38, 0x6b, 0x69, 0xe8, 0xfb, 0xd1, 0xae,
+ 0x1d, 0xff, 0x6b, 0xbd, 0x24, 0x73, 0xae, 0xca, 0x52, 0x3f, 0xd1, 0x5b,
+ 0xd1, 0x21, 0x17, 0xff, 0x37, 0xdb, 0x8e, 0xe7, 0xd5, 0x1a, 0x78, 0x7c,
+ 0x0d, 0xbf, 0x46, 0x2b, 0x5f, 0xf6, 0x79, 0xe0, 0xe1, 0xa7, 0xfb, 0xe5,
+ 0x3e, 0xd5, 0x5a, 0x7e, 0x8d, 0xa6, 0xb8, 0x0e, 0xe7, 0xbe, 0x3d, 0xeb,
+ 0xfd, 0x3d, 0x2a, 0x17, 0xf0, 0x87, 0xfd, 0x72, 0xbd, 0x40, 0x7e, 0xe0,
+ 0x0a, 0xd3, 0xe1, 0x22, 0x63, 0x95, 0x21, 0xea, 0xbc, 0xaa, 0xc7, 0x3a,
+ 0x24, 0xf4, 0xad, 0xd3, 0x4f, 0x73, 0x51, 0xe5, 0x76, 0xe7, 0x1c, 0x63,
+ 0xba, 0x28, 0x6c, 0x9c, 0xf6, 0xf2, 0xd6, 0x3e, 0xe6, 0x6a, 0xd8, 0xb5,
+ 0x26, 0xb8, 0xf9, 0x0d, 0x75, 0x4a, 0x30, 0xbf, 0x64, 0x48, 0x1c, 0x3c,
+ 0xc3, 0xf8, 0x76, 0xb3, 0xfb, 0x45, 0x9f, 0x14, 0x23, 0xba, 0x6b, 0x60,
+ 0xb8, 0x8f, 0x31, 0x0f, 0xd2, 0xe6, 0xc8, 0xbc, 0x58, 0x15, 0xba, 0xe0,
+ 0xe2, 0x54, 0x8d, 0x92, 0xd1, 0x6d, 0x94, 0x99, 0xe2, 0x77, 0xcf, 0xd8,
+ 0x6c, 0x7b, 0xf9, 0x29, 0xcb, 0xf2, 0x9b, 0x99, 0xda, 0xa2, 0xf0, 0xa2,
+ 0xf6, 0xa7, 0x77, 0xa9, 0x38, 0x87, 0x5e, 0xb1, 0x2f, 0x29, 0x6b, 0xf5,
+ 0xf0, 0x71, 0x45, 0x3f, 0x1b, 0xd7, 0xc1, 0xbb, 0x9d, 0xaa, 0xdd, 0x65,
+ 0x47, 0x3b, 0xb4, 0xb9, 0xac, 0xda, 0xe2, 0x99, 0x1a, 0x53, 0x74, 0x2b,
+ 0x7d, 0x0b, 0x39, 0x5c, 0x51, 0xb9, 0x7a, 0xc2, 0x7e, 0xa0, 0xd9, 0xfa,
+ 0x58, 0x2e, 0x73, 0xdb, 0xff, 0xae, 0xc5, 0x85, 0x2d, 0x77, 0x99, 0x31,
+ 0x6f, 0x55, 0xc8, 0x8a, 0xbb, 0x4f, 0x18, 0x8b, 0x5f, 0xec, 0x0f, 0xf1,
+ 0xb1, 0x7a, 0xcf, 0xe9, 0x7a, 0x9f, 0x10, 0xa3, 0x61, 0x45, 0xe4, 0xb3,
+ 0x74, 0xbb, 0xcb, 0x8e, 0x76, 0x5a, 0x57, 0xe8, 0xfd, 0x87, 0x8f, 0x7c,
+ 0xb3, 0x85, 0xdb, 0x3e, 0x19, 0xc3, 0x1b, 0x12, 0xfb, 0xa7, 0x32, 0x46,
+ 0x43, 0x1f, 0xc3, 0xbf, 0x8c, 0x98, 0x0a, 0xc4, 0x49, 0x38, 0xf5, 0x8d,
+ 0x1c, 0x6f, 0x00, 0x6b, 0x51, 0x15, 0xfb, 0xa6, 0xd8, 0xaf, 0x68, 0x87,
+ 0x9d, 0x77, 0x21, 0x36, 0x7f, 0x13, 0x18, 0x74, 0x23, 0xf2, 0x67, 0x7a,
+ 0xc8, 0x9f, 0xf3, 0xfd, 0xc8, 0x83, 0x43, 0x3e, 0x5c, 0x76, 0xd2, 0xa0,
+ 0x1a, 0xdb, 0x0a, 0x06, 0x95, 0x43, 0x3e, 0x3a, 0x67, 0x5b, 0xd1, 0x8a,
+ 0xc0, 0x9a, 0x8f, 0xc0, 0x7f, 0x35, 0xb9, 0x42, 0x07, 0x44, 0xce, 0x38,
+ 0x6a, 0x1f, 0x94, 0x79, 0x0d, 0x3e, 0xcd, 0x3c, 0x78, 0x96, 0xed, 0x8f,
+ 0xec, 0x49, 0xec, 0xb7, 0xe8, 0x79, 0x41, 0x0e, 0x3c, 0x3e, 0x4d, 0x9e,
+ 0xbb, 0xdf, 0xdd, 0x41, 0xc1, 0x38, 0x3f, 0xd3, 0x84, 0x7e, 0xe2, 0xe7,
+ 0xa4, 0x29, 0xc1, 0x76, 0x12, 0x6c, 0xd6, 0xd3, 0x27, 0xad, 0x50, 0x99,
+ 0x0c, 0x6e, 0x0b, 0xdb, 0x15, 0xcf, 0xc1, 0xfd, 0xf1, 0x50, 0x07, 0xb9,
+ 0x73, 0x72, 0x7b, 0x45, 0x9e, 0xe2, 0x5b, 0xd1, 0x07, 0xc9, 0x18, 0x84,
+ 0xbe, 0xc2, 0xbc, 0x3d, 0xa0, 0xf6, 0x89, 0xb6, 0xf3, 0xf1, 0x84, 0x3a,
+ 0x0e, 0x8a, 0xf9, 0x94, 0xc7, 0x9a, 0xbf, 0xf1, 0xf7, 0xf3, 0x2e, 0xb2,
+ 0xfd, 0x6a, 0xfe, 0x9a, 0x62, 0x41, 0x22, 0x63, 0x46, 0x90, 0xce, 0x57,
+ 0xd6, 0xf2, 0xbf, 0x78, 0xe5, 0xba, 0x6e, 0xdf, 0x60, 0xae, 0xeb, 0x4f,
+ 0x76, 0xc8, 0xdc, 0x32, 0x67, 0x5f, 0xfe, 0x93, 0xfb, 0xe2, 0x85, 0xc9,
+ 0x5a, 0x70, 0x22, 0x8f, 0xb7, 0x46, 0x3f, 0x8b, 0x7e, 0x9e, 0xee, 0x84,
+ 0x23, 0x2a, 0x66, 0x09, 0x31, 0x4a, 0x0f, 0x2a, 0xbe, 0xd6, 0xba, 0x9f,
+ 0x3c, 0x74, 0xff, 0xa3, 0x22, 0x56, 0x53, 0xae, 0x1d, 0x43, 0x8a, 0x1e,
+ 0xa0, 0x59, 0xc4, 0x41, 0xb3, 0x01, 0x07, 0xcd, 0x0c, 0x75, 0xbc, 0x4d,
+ 0x9c, 0x9f, 0xaf, 0x3c, 0xb5, 0x5d, 0xe6, 0x8b, 0x63, 0x2f, 0xf1, 0x92,
+ 0x3a, 0x5e, 0x6f, 0xbc, 0x56, 0x98, 0x82, 0xc2, 0xdf, 0xe4, 0x18, 0xeb,
+ 0xcb, 0x44, 0xf6, 0x81, 0x70, 0x2b, 0x0d, 0x5e, 0x73, 0x5c, 0x47, 0x1f,
+ 0xc7, 0x1d, 0x7d, 0x1c, 0x75, 0xf4, 0x71, 0x6f, 0x9b, 0x3e, 0xb2, 0x8e,
+ 0xe7, 0xf7, 0x9c, 0xad, 0x7e, 0xdc, 0xbe, 0xa2, 0x9f, 0xc8, 0x23, 0x06,
+ 0x3d, 0xb7, 0x52, 0x2e, 0x1c, 0x51, 0x6b, 0xc7, 0x2f, 0x55, 0x2e, 0xba,
+ 0x57, 0x9f, 0xff, 0x8e, 0xda, 0xcf, 0x9b, 0x93, 0x57, 0x9d, 0xf9, 0xc7,
+ 0xdf, 0xa5, 0xa4, 0xcc, 0x23, 0x57, 0xb2, 0x7d, 0xb9, 0x8d, 0x1f, 0x1a,
+ 0xf1, 0x1c, 0xc0, 0x20, 0xc2, 0x2e, 0xdc, 0x2d, 0x6b, 0xc1, 0x05, 0x68,
+ 0xa9, 0x9e, 0xcb, 0xeb, 0x57, 0xb9, 0x3b, 0xc7, 0xc3, 0xf7, 0x37, 0x8f,
+ 0x17, 0xd7, 0xff, 0x4c, 0xf8, 0xf2, 0xe4, 0xfe, 0xd1, 0x8a, 0xca, 0x47,
+ 0xb6, 0x4c, 0xc4, 0x06, 0x2c, 0x2e, 0xc3, 0xff, 0xda, 0x2e, 0x77, 0x57,
+ 0xea, 0xa2, 0x4c, 0xbd, 0x3e, 0x4a, 0x59, 0xe4, 0x35, 0x48, 0xff, 0x98,
+ 0xcc, 0xbf, 0x5d, 0x5c, 0xbe, 0x25, 0x72, 0x5e, 0x13, 0x2a, 0x8f, 0x37,
+ 0x43, 0x3d, 0x02, 0xe7, 0x7e, 0xfc, 0xfc, 0xdb, 0x17, 0xc2, 0x9b, 0xcf,
+ 0xbf, 0x75, 0xde, 0xb3, 0xb9, 0xfc, 0xdb, 0x10, 0x8f, 0xdd, 0x58, 0x90,
+ 0xf9, 0xb7, 0xcd, 0x7b, 0x32, 0x32, 0xff, 0x36, 0xe3, 0xc0, 0x0f, 0x12,
+ 0xaf, 0xbf, 0xe5, 0x88, 0xdf, 0x96, 0xb9, 0xb5, 0x8b, 0x75, 0xcc, 0x2a,
+ 0x73, 0x6b, 0x65, 0xbc, 0xb7, 0xb3, 0x0e, 0x8c, 0xdc, 0xfb, 0x91, 0xef,
+ 0xd9, 0xe6, 0xda, 0xfb, 0x91, 0x39, 0xb5, 0xa6, 0xd1, 0xce, 0x86, 0xc3,
+ 0x1a, 0x81, 0x7a, 0x08, 0x71, 0xe6, 0xdd, 0xad, 0x6d, 0xea, 0x21, 0xc4,
+ 0xdb, 0xd4, 0x43, 0x70, 0xea, 0x7e, 0x27, 0xc6, 0x02, 0x26, 0xc6, 0xda,
+ 0x08, 0x2c, 0x8c, 0x7a, 0x06, 0x51, 0x3a, 0x5f, 0xc7, 0x9e, 0x0f, 0x52,
+ 0x5a, 0x61, 0xcf, 0xf3, 0x15, 0xad, 0x8f, 0x46, 0x5d, 0xfa, 0xc8, 0x0b,
+ 0x8b, 0x5a, 0x2a, 0xce, 0x47, 0xcb, 0x6b, 0xd6, 0x21, 0xaf, 0x59, 0x0f,
+ 0x79, 0xc5, 0x3d, 0xd9, 0x36, 0xfd, 0xfe, 0xa5, 0xba, 0x07, 0xff, 0x4f,
+ 0x46, 0x50, 0xb3, 0x85, 0x68, 0xf7, 0x80, 0xc2, 0x7f, 0x0e, 0x79, 0x3d,
+ 0xcb, 0xf2, 0xaa, 0xaf, 0xa3, 0xbf, 0xed, 0x6c, 0x00, 0x8d, 0x19, 0x87,
+ 0x7c, 0x87, 0xaf, 0xbd, 0x21, 0xe2, 0xa4, 0x9a, 0xed, 0x45, 0x8d, 0x27,
+ 0xf6, 0x09, 0x59, 0xba, 0xe3, 0x47, 0xdc, 0x8a, 0xbe, 0x16, 0x52, 0x7e,
+ 0x32, 0x4d, 0x8b, 0xce, 0x26, 0xcc, 0xd1, 0xc0, 0x1b, 0x22, 0xc6, 0xd7,
+ 0xd1, 0xb7, 0x7f, 0xe5, 0xbe, 0xe9, 0xeb, 0x7a, 0xcd, 0x7c, 0xa7, 0xc9,
+ 0x9f, 0x71, 0xa3, 0xa9, 0xee, 0x1f, 0x7c, 0x47, 0xdb, 0xd2, 0x86, 0x9d,
+ 0x12, 0x31, 0xa6, 0x7d, 0x36, 0xfc, 0x64, 0x09, 0x96, 0xfd, 0xbe, 0x34,
+ 0xe2, 0x99, 0xfb, 0xae, 0x98, 0x74, 0xa2, 0x70, 0x7e, 0x8f, 0xe4, 0x95,
+ 0x0b, 0xa2, 0xa6, 0x25, 0x6a, 0x20, 0x26, 0x79, 0x7d, 0x4e, 0x30, 0xe8,
+ 0x9c, 0xab, 0x76, 0xd1, 0x22, 0xa3, 0x7b, 0xbf, 0x5d, 0x16, 0xbe, 0x3e,
+ 0xd6, 0x49, 0x45, 0xd4, 0x36, 0x35, 0x16, 0x3a, 0xf9, 0xb9, 0x83, 0xb4,
+ 0x54, 0x1a, 0x17, 0x35, 0xa1, 0x64, 0x7d, 0x11, 0xb4, 0xf5, 0x51, 0xbf,
+ 0xfd, 0x0d, 0xa6, 0xdd, 0xd7, 0x44, 0x8c, 0xe5, 0x62, 0xf1, 0x82, 0xfc,
+ 0x2c, 0x3f, 0xa5, 0xde, 0xc1, 0xef, 0xab, 0xfe, 0x98, 0xe2, 0xfd, 0xa6,
+ 0xc3, 0x96, 0x73, 0xfe, 0x79, 0xe3, 0x95, 0x63, 0x9b, 0xc2, 0x2b, 0xd9,
+ 0x74, 0x03, 0xaf, 0x38, 0x9f, 0xad, 0xb1, 0xcb, 0xe4, 0xa0, 0xac, 0xf7,
+ 0x00, 0x1a, 0x6c, 0x05, 0x16, 0x4b, 0x83, 0x96, 0x46, 0xcc, 0x8a, 0x24,
+ 0xfc, 0x33, 0x94, 0xaf, 0x5e, 0xa7, 0x4c, 0x11, 0x98, 0x99, 0x3f, 0xcb,
+ 0xe7, 0x76, 0x4a, 0x1f, 0x8d, 0xbe, 0x07, 0x7a, 0x65, 0x07, 0xb7, 0xff,
+ 0xeb, 0x41, 0x19, 0x97, 0xed, 0xbc, 0xde, 0xcb, 0xd7, 0xbf, 0x10, 0x69,
+ 0xbe, 0xbe, 0x85, 0xaf, 0xf7, 0xa7, 0x31, 0x87, 0xc6, 0x15, 0xf8, 0x25,
+ 0x27, 0x29, 0xc7, 0xf3, 0x93, 0xaf, 0xf2, 0xda, 0x7a, 0x95, 0xf5, 0x55,
+ 0x45, 0xb7, 0x1b, 0x40, 0xce, 0x8e, 0x98, 0x13, 0x83, 0xdb, 0x5c, 0x2c,
+ 0x4c, 0x71, 0xbb, 0x21, 0xf2, 0x5f, 0x35, 0x29, 0x5f, 0xd1, 0xbc, 0xaa,
+ 0xe3, 0xed, 0xdf, 0x18, 0x90, 0x31, 0x55, 0xef, 0xec, 0x94, 0xf4, 0x9b,
+ 0x14, 0x3e, 0x4f, 0xc4, 0x73, 0x3c, 0x23, 0xf8, 0xd0, 0x9a, 0x31, 0xeb,
+ 0xef, 0xdf, 0x06, 0xbe, 0x42, 0xdd, 0x54, 0x1e, 0x03, 0xeb, 0xc5, 0x98,
+ 0x1d, 0xca, 0xd5, 0x63, 0xd5, 0x9e, 0xdb, 0x2d, 0xef, 0xff, 0xe9, 0x80,
+ 0xac, 0x55, 0x7a, 0x5b, 0x9d, 0xeb, 0x35, 0x07, 0xf1, 0xcb, 0x3e, 0x41,
+ 0x1b, 0xff, 0x02, 0xf4, 0xa5, 0xc1, 0xc7, 0x3c, 0x9e, 0x34, 0xfa, 0xf8,
+ 0xb3, 0x01, 0x5d, 0x9f, 0x50, 0x8e, 0xeb, 0x28, 0xf7, 0x37, 0xc5, 0xe3,
+ 0xd2, 0xd7, 0xe3, 0x7c, 0xee, 0x35, 0xbf, 0x78, 0x56, 0x30, 0x2d, 0xeb,
+ 0x8b, 0x05, 0xd3, 0x99, 0x49, 0x39, 0xcf, 0x0d, 0x9f, 0x6e, 0xa4, 0xee,
+ 0xd3, 0x9d, 0x2b, 0xf4, 0x0f, 0xc2, 0xbf, 0x61, 0x5c, 0xe1, 0xf9, 0x0e,
+ 0x3f, 0xc3, 0x6d, 0x91, 0xab, 0x90, 0xe3, 0xcf, 0x1e, 0x15, 0xd7, 0xd3,
+ 0xca, 0x2b, 0x32, 0x4e, 0x42, 0xaf, 0x5b, 0xb8, 0x77, 0x80, 0x9f, 0x21,
+ 0xd7, 0xae, 0xf6, 0xef, 0xa1, 0x96, 0x38, 0x98, 0x56, 0x1e, 0x5b, 0xcb,
+ 0x0f, 0x2b, 0xf6, 0x13, 0x3d, 0xf8, 0x6c, 0xad, 0x7a, 0x06, 0xef, 0x08,
+ 0x3f, 0x5a, 0xb2, 0x45, 0x5e, 0x21, 0xc7, 0x01, 0xfa, 0xce, 0x7c, 0x96,
+ 0xb6, 0xf0, 0x5c, 0x7d, 0xc3, 0xf8, 0x35, 0xec, 0xb7, 0x93, 0x8c, 0x79,
+ 0x62, 0x1a, 0x17, 0xec, 0xc9, 0xb3, 0x06, 0xd3, 0xb9, 0x90, 0xad, 0x05,
+ 0xec, 0x1e, 0xea, 0x64, 0x59, 0xfd, 0x22, 0x8d, 0xb1, 0xfd, 0x07, 0x99,
+ 0xb5, 0x23, 0x29, 0x82, 0xbc, 0x59, 0xa1, 0xc3, 0xcc, 0x13, 0xc9, 0x2a,
+ 0xf8, 0xd9, 0xa0, 0x27, 0x4a, 0x44, 0x8f, 0x97, 0xc6, 0x42, 0xdf, 0x27,
+ 0xdb, 0x6c, 0x7c, 0x6f, 0x85, 0x12, 0xdc, 0x8f, 0x54, 0xf5, 0x77, 0xe8,
+ 0x43, 0x51, 0xe7, 0x04, 0x74, 0xd4, 0xf3, 0xfe, 0xdb, 0x74, 0x3a, 0x8d,
+ 0x7e, 0x6f, 0x5c, 0x3e, 0x4f, 0x6c, 0x4a, 0x3e, 0x83, 0x1e, 0xf2, 0xf9,
+ 0xea, 0xa0, 0xe4, 0x9b, 0x1a, 0xf3, 0x68, 0x90, 0x66, 0x8b, 0x88, 0x01,
+ 0x7b, 0x18, 0x75, 0xa7, 0x8a, 0x19, 0xd6, 0x4b, 0x99, 0x86, 0x5e, 0xba,
+ 0x94, 0xf0, 0xc7, 0x21, 0xe3, 0xa8, 0xcb, 0xa6, 0xe2, 0x7e, 0x30, 0x8e,
+ 0xdd, 0x34, 0xb6, 0xb0, 0x95, 0xef, 0xa5, 0x95, 0xc4, 0x74, 0x5c, 0xe5,
+ 0xfa, 0x5b, 0x66, 0x92, 0xf5, 0xe3, 0x1c, 0xcb, 0x72, 0xae, 0xf8, 0x00,
+ 0x2d, 0x86, 0x87, 0x69, 0x74, 0x41, 0xd7, 0x37, 0xc1, 0x58, 0xff, 0x6d,
+ 0x48, 0xea, 0x24, 0x3d, 0xee, 0x5f, 0x11, 0xbe, 0x0b, 0xf3, 0xfa, 0xa7,
+ 0x35, 0xee, 0xad, 0xeb, 0xe8, 0xa5, 0xbf, 0x52, 0x32, 0x5b, 0xbb, 0x91,
+ 0x88, 0x52, 0x36, 0x31, 0xfd, 0x97, 0x82, 0xff, 0x47, 0xaf, 0xc3, 0x0f,
+ 0x07, 0x1d, 0x6d, 0x52, 0xba, 0xe0, 0xa6, 0xc5, 0x30, 0x8f, 0x1b, 0xdf,
+ 0xd7, 0xfe, 0x79, 0x36, 0xfa, 0x94, 0x58, 0xfb, 0xc7, 0xae, 0x73, 0x3b,
+ 0xb1, 0x36, 0x69, 0xbd, 0xe1, 0xc5, 0x87, 0xba, 0x8e, 0xa5, 0xe6, 0x45,
+ 0x19, 0xeb, 0xc9, 0xf8, 0x2d, 0x94, 0xf6, 0xbb, 0x79, 0xf2, 0x23, 0x3a,
+ 0x36, 0x6f, 0xd2, 0xf1, 0x82, 0xf5, 0x7c, 0x96, 0x66, 0x58, 0xae, 0x9d,
+ 0xeb, 0x05, 0xb7, 0x27, 0xf0, 0x59, 0x8c, 0x65, 0x9f, 0xed, 0xe6, 0xa2,
+ 0x29, 0xe3, 0xee, 0x44, 0xed, 0xb9, 0x2e, 0xa1, 0x47, 0x43, 0xf6, 0x3f,
+ 0x0d, 0xea, 0xf5, 0x20, 0x53, 0x44, 0x1e, 0x21, 0x7f, 0x96, 0xb9, 0x7d,
+ 0x61, 0x90, 0x32, 0x25, 0x3c, 0x07, 0xeb, 0x1d, 0xfa, 0xce, 0xe7, 0x4b,
+ 0x72, 0x5e, 0x47, 0xf9, 0xd9, 0xc8, 0xbb, 0x3f, 0x5e, 0x9d, 0x12, 0xb1,
+ 0x77, 0xd0, 0xcd, 0x72, 0x3e, 0x63, 0x74, 0xd1, 0x53, 0xaf, 0x28, 0x4c,
+ 0xe9, 0x90, 0xef, 0x8c, 0x90, 0xef, 0x98, 0x98, 0x8f, 0x4c, 0xc9, 0x60,
+ 0xbc, 0xa6, 0x7d, 0x0f, 0xfd, 0x7c, 0x1e, 0x50, 0x3a, 0x04, 0xdf, 0x0d,
+ 0xec, 0x14, 0x71, 0x89, 0x36, 0xae, 0xe3, 0x33, 0x46, 0xcf, 0x30, 0xee,
+ 0x7c, 0xb6, 0xd0, 0x45, 0xb7, 0x8a, 0x5d, 0xf4, 0x66, 0x71, 0x98, 0x6e,
+ 0xce, 0x6f, 0xa7, 0x8b, 0x8c, 0x99, 0x2f, 0xda, 0x01, 0x33, 0xc7, 0xf6,
+ 0xc5, 0x0b, 0x51, 0x11, 0x33, 0xc4, 0x72, 0x87, 0xf6, 0xc0, 0x7f, 0x89,
+ 0x5d, 0xcc, 0x73, 0x8c, 0xbd, 0xbb, 0xe9, 0x03, 0x7e, 0x67, 0xae, 0xa0,
+ 0x63, 0x1d, 0xe0, 0x93, 0x1f, 0xaf, 0xe3, 0xd7, 0xf5, 0x79, 0x24, 0xb4,
+ 0x0e, 0x8f, 0xc4, 0x84, 0xae, 0xcf, 0xcf, 0xf3, 0xf7, 0xf3, 0xf0, 0x9f,
+ 0x33, 0xbd, 0x59, 0x3f, 0x7f, 0x3d, 0x80, 0xf6, 0xb8, 0x66, 0xcb, 0x58,
+ 0x49, 0x31, 0xb6, 0x08, 0x9f, 0x83, 0xb6, 0x11, 0x45, 0x87, 0x6e, 0x1e,
+ 0x9f, 0x4f, 0xb4, 0xcf, 0x2c, 0x75, 0xd3, 0x99, 0x12, 0x63, 0x90, 0x92,
+ 0x9f, 0x6d, 0x18, 0xb4, 0x0d, 0xec, 0xd5, 0xf5, 0x5f, 0x2f, 0x72, 0xdf,
+ 0x73, 0x25, 0x89, 0x41, 0x72, 0x4b, 0xbd, 0x94, 0x2f, 0xf5, 0xa8, 0xf3,
+ 0x07, 0x44, 0x8c, 0xbb, 0xac, 0x63, 0x84, 0xef, 0xd6, 0xd2, 0x6f, 0x6f,
+ 0x31, 0x4f, 0x61, 0x4d, 0x95, 0x76, 0x29, 0x74, 0xcd, 0x8d, 0x96, 0xba,
+ 0xc4, 0xe0, 0xb9, 0x19, 0xfa, 0x2e, 0xaf, 0xb7, 0xa3, 0x57, 0xe1, 0x3f,
+ 0xfe, 0x2a, 0xf8, 0xa6, 0x0c, 0x1e, 0x1b, 0xbd, 0x8a, 0xba, 0x48, 0x7e,
+ 0x91, 0xe7, 0x94, 0x0c, 0x4f, 0x8a, 0xdc, 0x10, 0x29, 0xa3, 0x27, 0x45,
+ 0x2d, 0xba, 0x1f, 0x0a, 0xdd, 0x64, 0x65, 0x4d, 0x03, 0x78, 0x04, 0x3e,
+ 0x18, 0x19, 0x83, 0x75, 0xc2, 0xee, 0x7b, 0x6b, 0x20, 0x36, 0x41, 0xf1,
+ 0x41, 0xf0, 0xbd, 0x94, 0x59, 0x55, 0x5f, 0x40, 0xe8, 0xfb, 0xd0, 0x3e,
+ 0x9d, 0x2f, 0xa9, 0xcf, 0xf5, 0x5a, 0xa1, 0xcf, 0x7b, 0x5c, 0xdf, 0x87,
+ 0x5c, 0xdf, 0xd7, 0xe3, 0xe5, 0x78, 0xcd, 0xe3, 0x75, 0x9e, 0x64, 0x8d,
+ 0xa2, 0xcc, 0x82, 0xe4, 0xbf, 0xd0, 0xbe, 0xf1, 0xd0, 0x97, 0x15, 0x06,
+ 0xcf, 0x2c, 0x8f, 0x45, 0xfa, 0x8c, 0x1e, 0x7f, 0x66, 0xea, 0xef, 0x6b,
+ 0xf1, 0x34, 0x70, 0xd1, 0xdc, 0x4e, 0xa9, 0xe3, 0xd0, 0xaf, 0x6c, 0x14,
+ 0xd0, 0xed, 0xe4, 0x72, 0x0f, 0xad, 0x88, 0x9a, 0x5c, 0xc0, 0x18, 0xb8,
+ 0x1f, 0xcf, 0xc9, 0x86, 0x3a, 0x08, 0x35, 0xd7, 0x21, 0xe3, 0x07, 0x22,
+ 0xd7, 0x79, 0x3e, 0x53, 0xcb, 0xff, 0x55, 0x3b, 0x2d, 0x6a, 0xdc, 0xa0,
+ 0x2d, 0x63, 0x48, 0x81, 0xf9, 0x19, 0xbf, 0x34, 0xd9, 0x55, 0x33, 0xe8,
+ 0x67, 0x16, 0x7b, 0x2b, 0x86, 0xfd, 0x22, 0xcb, 0x98, 0xdc, 0x2b, 0x4f,
+ 0xb9, 0xf6, 0xca, 0x4f, 0x8a, 0xbd, 0x72, 0xec, 0x93, 0x83, 0xae, 0xa0,
+ 0xa5, 0x57, 0x4c, 0x0b, 0xe6, 0x31, 0xca, 0xf3, 0x68, 0xd2, 0xc5, 0x6b,
+ 0x42, 0xdf, 0x44, 0x93, 0x7e, 0x19, 0x5f, 0x9d, 0xa2, 0xac, 0x88, 0xbf,
+ 0x96, 0x9f, 0x71, 0x23, 0x61, 0x5b, 0x93, 0xab, 0x8c, 0x29, 0x2a, 0xc5,
+ 0x2d, 0x74, 0xb3, 0xdc, 0xc1, 0x98, 0xef, 0x6f, 0x69, 0xb5, 0x4c, 0x8c,
+ 0x0d, 0xb7, 0x53, 0x3e, 0xca, 0xbc, 0x36, 0x19, 0xe4, 0x79, 0x65, 0x7c,
+ 0x3b, 0xc9, 0xf2, 0xc7, 0x63, 0xa8, 0x94, 0x6a, 0xef, 0xe7, 0xa2, 0x71,
+ 0x33, 0x31, 0xdd, 0xc3, 0xf6, 0x4b, 0x88, 0xff, 0x6d, 0xfe, 0xff, 0x6c,
+ 0x04, 0xb4, 0x59, 0x5c, 0xc2, 0xf7, 0x8c, 0x7d, 0x0a, 0xb5, 0xf7, 0x67,
+ 0xb9, 0xcd, 0xec, 0x34, 0xec, 0x20, 0xd8, 0x7b, 0x36, 0xff, 0xcb, 0x36,
+ 0x15, 0xe6, 0xbb, 0xdc, 0xb5, 0x6c, 0xc4, 0x10, 0x3a, 0x1e, 0x75, 0x5d,
+ 0xc6, 0xd4, 0x67, 0xdc, 0x98, 0xe5, 0xbe, 0xdc, 0x24, 0x3c, 0xc3, 0xa4,
+ 0x4c, 0x74, 0x1f, 0xcb, 0xc1, 0x76, 0xfe, 0x44, 0x3e, 0xd6, 0x56, 0xca,
+ 0x4f, 0x8d, 0xab, 0x7c, 0xac, 0x48, 0x9b, 0x7c, 0x2c, 0xdc, 0xc7, 0x38,
+ 0x60, 0xbe, 0x76, 0x6f, 0x36, 0xea, 0x7c, 0x2f, 0x19, 0x99, 0xe8, 0x36,
+ 0x81, 0x99, 0x2a, 0x4b, 0xfb, 0xb9, 0x0f, 0x71, 0x33, 0x33, 0xcd, 0x7d,
+ 0x2d, 0x39, 0xfb, 0x5f, 0xbb, 0x97, 0x8c, 0xa2, 0x9d, 0xdf, 0xd5, 0x2e,
+ 0x4e, 0xa2, 0xed, 0x12, 0xda, 0xd7, 0xfe, 0x27, 0x11, 0xd5, 0xe3, 0x74,
+ 0xde, 0x8b, 0xf1, 0x40, 0xbe, 0xf8, 0xb3, 0x72, 0x9b, 0x6e, 0x16, 0x61,
+ 0x8f, 0x1b, 0xcc, 0xf7, 0xe8, 0x91, 0x49, 0xd9, 0x0a, 0x63, 0xc0, 0x6b,
+ 0x7b, 0x7d, 0xab, 0xc5, 0x37, 0x6a, 0x99, 0xa6, 0xd8, 0x96, 0x66, 0x3f,
+ 0xbc, 0xb4, 0xc1, 0x86, 0xc9, 0xbe, 0x82, 0x35, 0x14, 0xeb, 0x67, 0xb6,
+ 0xe6, 0xb7, 0x81, 0xf7, 0x60, 0x1b, 0x5d, 0x60, 0xfd, 0x25, 0xe3, 0x93,
+ 0x58, 0x97, 0xb2, 0x0e, 0x93, 0xf2, 0x93, 0x6a, 0xfa, 0x39, 0x04, 0xc9,
+ 0xc3, 0xa3, 0x8d, 0xb8, 0x48, 0xc7, 0xfe, 0x7a, 0xc0, 0xb1, 0xbf, 0x1e,
+ 0x72, 0xc4, 0x45, 0x86, 0x05, 0x3e, 0x6b, 0x60, 0xaa, 0xb0, 0xc2, 0x54,
+ 0xc0, 0x5e, 0x52, 0xb7, 0x2d, 0xd6, 0x75, 0xdb, 0x8e, 0x75, 0x74, 0x9b,
+ 0x97, 0xad, 0xba, 0xa2, 0xf4, 0x88, 0x15, 0xc5, 0x1a, 0x73, 0x83, 0xf5,
+ 0xc5, 0xeb, 0xd5, 0x69, 0xd6, 0x23, 0x51, 0xd6, 0x23, 0x53, 0xac, 0x47,
+ 0x26, 0x59, 0x8f, 0xd8, 0x4c, 0x03, 0x93, 0xc7, 0xfe, 0x11, 0xeb, 0x69,
+ 0xac, 0x1f, 0x33, 0xf4, 0x4c, 0x15, 0x3a, 0x79, 0x8a, 0x31, 0xd0, 0x47,
+ 0xb4, 0x3a, 0xdf, 0xcb, 0xfc, 0x2b, 0x71, 0x4f, 0xb3, 0x5d, 0x83, 0xda,
+ 0x2b, 0xf0, 0x17, 0xff, 0x39, 0xf4, 0xce, 0x2b, 0x59, 0x1a, 0xf1, 0xdd,
+ 0x2c, 0x82, 0xce, 0xab, 0xa8, 0x55, 0xf1, 0x12, 0x64, 0x1b, 0x35, 0x82,
+ 0x7f, 0x30, 0x31, 0xc3, 0x7d, 0x1f, 0xf1, 0xe5, 0x79, 0x5e, 0xbe, 0x1d,
+ 0xcd, 0x86, 0xfa, 0x59, 0x06, 0x8e, 0x2b, 0x19, 0x38, 0xde, 0x90, 0x81,
+ 0x6c, 0x8e, 0x47, 0xd2, 0xb7, 0xb0, 0x9d, 0xc6, 0x0f, 0x26, 0x76, 0xf5,
+ 0xb1, 0xfc, 0x22, 0x66, 0xa2, 0x51, 0xbf, 0xc7, 0x4f, 0xa7, 0xc3, 0x41,
+ 0x55, 0xf7, 0xc7, 0x14, 0x39, 0xef, 0xf9, 0xe2, 0xbb, 0x8c, 0x4b, 0x58,
+ 0x4e, 0x43, 0x38, 0xbf, 0x0c, 0xbf, 0x28, 0xdb, 0x0d, 0xdd, 0xc2, 0xaf,
+ 0xb4, 0x28, 0xda, 0xe2, 0xdc, 0x9a, 0x64, 0x1d, 0x17, 0x5d, 0x31, 0xac,
+ 0x99, 0xb8, 0xf1, 0x9b, 0xc3, 0xa8, 0xe1, 0xfe, 0x83, 0xea, 0xe7, 0x86,
+ 0xe5, 0xde, 0x5c, 0x72, 0x97, 0xd4, 0x27, 0xcc, 0xa3, 0xe1, 0xb8, 0xb0,
+ 0xdd, 0x3a, 0xae, 0xc8, 0xf5, 0x73, 0x91, 0xe7, 0xbb, 0x12, 0x9d, 0xe4,
+ 0xf9, 0xee, 0x51, 0x6b, 0x67, 0x96, 0xbf, 0x17, 0xeb, 0x32, 0xaf, 0xa1,
+ 0xc3, 0xa8, 0x7f, 0x1f, 0x12, 0x75, 0x22, 0x4e, 0xa2, 0x0e, 0x4f, 0x02,
+ 0xcf, 0x63, 0xee, 0x85, 0xfe, 0xf8, 0x07, 0x5e, 0xa3, 0xf1, 0x5e, 0xf0,
+ 0x23, 0x1f, 0x97, 0x67, 0xe8, 0x52, 0x41, 0xf7, 0xe1, 0x3d, 0x32, 0xbe,
+ 0x8b, 0x7e, 0xf8, 0x68, 0x87, 0xfd, 0x9e, 0xc8, 0x05, 0x31, 0xfe, 0xc4,
+ 0xdd, 0xa7, 0xa3, 0xaa, 0x4f, 0xa8, 0x75, 0xd9, 0x85, 0xda, 0x3e, 0x84,
+ 0x9a, 0x48, 0x8b, 0xa2, 0x16, 0x65, 0xa7, 0xb0, 0x59, 0x17, 0x85, 0xed,
+ 0xb1, 0x7f, 0x57, 0xa3, 0x3e, 0xe6, 0x7e, 0xd7, 0xb5, 0x3b, 0xbc, 0x6e,
+ 0x1d, 0x12, 0x18, 0x6d, 0x14, 0xf5, 0xda, 0x45, 0x5e, 0xea, 0x8c, 0xf8,
+ 0xce, 0x58, 0xc0, 0x77, 0x0f, 0xa9, 0xef, 0x3e, 0x2f, 0xb0, 0xb1, 0x11,
+ 0xeb, 0x66, 0xbd, 0x28, 0xf8, 0x9d, 0xe7, 0xd9, 0x9e, 0x64, 0x7e, 0x8f,
+ 0x54, 0xf8, 0xb9, 0xa7, 0x05, 0x3d, 0x35, 0x3d, 0x40, 0x0b, 0xc8, 0x40,
+ 0x8f, 0xe2, 0x7f, 0xcb, 0x4c, 0xf9, 0xf5, 0xb8, 0xdb, 0xd1, 0x99, 0xb1,
+ 0x4e, 0x01, 0x63, 0xc5, 0x98, 0x4c, 0x5f, 0xbc, 0x1c, 0xf1, 0xe5, 0xe6,
+ 0x61, 0xeb, 0x20, 0xdf, 0x65, 0x0f, 0xe2, 0xa9, 0xb8, 0x0f, 0x3b, 0x29,
+ 0x9e, 0x46, 0xbf, 0xd0, 0x4e, 0xd3, 0xc0, 0x76, 0xd1, 0xc2, 0x79, 0xdf,
+ 0x76, 0x75, 0x5f, 0xb7, 0x98, 0x0b, 0x32, 0xf0, 0x1e, 0xfd, 0x6e, 0xbc,
+ 0x17, 0xef, 0xc7, 0x7d, 0x78, 0x9e, 0x7c, 0xee, 0x00, 0xeb, 0xed, 0xc4,
+ 0xb4, 0x7c, 0x96, 0x71, 0x5d, 0x7e, 0x37, 0x60, 0x7b, 0xf7, 0x57, 0xce,
+ 0x9f, 0x4f, 0xd5, 0xf1, 0xc1, 0xfc, 0x6d, 0xa7, 0xb2, 0xf0, 0x7d, 0xe2,
+ 0xbb, 0x11, 0x9f, 0xb0, 0x6b, 0x6d, 0xfe, 0xe4, 0x79, 0x9d, 0xe3, 0xf3,
+ 0x33, 0xc5, 0xdb, 0xc2, 0x66, 0xcf, 0xa5, 0x47, 0x7c, 0xe5, 0x32, 0xc6,
+ 0x3b, 0xe2, 0x4b, 0xb1, 0x0c, 0x24, 0x8b, 0x89, 0x5a, 0x5e, 0xe2, 0x02,
+ 0x3a, 0xdd, 0x6f, 0x85, 0x4e, 0x1b, 0xef, 0x0f, 0xcb, 0x9a, 0xb7, 0x38,
+ 0x66, 0x39, 0x2c, 0xb0, 0x1c, 0x16, 0x58, 0x0e, 0x0b, 0x2c, 0x87, 0x6c,
+ 0xab, 0xbe, 0x56, 0x60, 0x39, 0xe4, 0xb5, 0xe4, 0x55, 0x5e, 0x4b, 0xa4,
+ 0xec, 0xc6, 0x95, 0x7f, 0x53, 0xcb, 0xae, 0x3b, 0x6f, 0x53, 0xcb, 0x2a,
+ 0xd6, 0x6f, 0xf2, 0x1d, 0x99, 0x68, 0x96, 0xd9, 0x5b, 0x2c, 0xb3, 0x1d,
+ 0xb1, 0x41, 0xba, 0x5b, 0xc2, 0x9c, 0x59, 0xe6, 0x1c, 0xeb, 0xea, 0x94,
+ 0x1f, 0x58, 0x2b, 0xc0, 0xf2, 0x04, 0xac, 0x69, 0x31, 0xdd, 0x07, 0xe9,
+ 0x1e, 0xeb, 0xeb, 0xbb, 0x25, 0xc8, 0xf0, 0x1e, 0x75, 0x6e, 0xb1, 0x0c,
+ 0x63, 0xfd, 0xb3, 0x7d, 0xb7, 0x8a, 0x06, 0x63, 0xb2, 0x40, 0x28, 0x43,
+ 0xd0, 0xa7, 0x02, 0xa7, 0xf1, 0xbc, 0xaf, 0xb0, 0xde, 0x87, 0x0f, 0x0f,
+ 0xeb, 0xc5, 0x19, 0x1f, 0xaf, 0x17, 0x91, 0x9b, 0xac, 0x4f, 0xcf, 0x97,
+ 0x6c, 0x96, 0xfb, 0x7e, 0xfa, 0x56, 0x09, 0xeb, 0x34, 0x68, 0xc4, 0xe7,
+ 0x65, 0x12, 0xbe, 0x31, 0x23, 0x86, 0xb1, 0x8f, 0x67, 0x0d, 0xc1, 0x27,
+ 0x7f, 0x0a, 0x3a, 0x30, 0xed, 0x5f, 0xdc, 0x85, 0xda, 0xf3, 0x71, 0xa3,
+ 0x53, 0xf9, 0x1a, 0x71, 0x8c, 0xf6, 0x68, 0x0b, 0xba, 0xe1, 0xbc, 0xdd,
+ 0xbe, 0x24, 0x7e, 0xb3, 0x21, 0x0a, 0xff, 0x9b, 0x4b, 0x7f, 0x5d, 0xe2,
+ 0xfb, 0x05, 0xbd, 0x66, 0x12, 0x7e, 0xe4, 0x90, 0xd3, 0xd3, 0xfe, 0xd8,
+ 0x0c, 0x3d, 0x5b, 0x45, 0xbf, 0xaf, 0x52, 0x3e, 0x0c, 0x7d, 0x64, 0x45,
+ 0xef, 0x90, 0xa4, 0x5d, 0x37, 0xe3, 0xce, 0x27, 0xbc, 0x75, 0x9c, 0x99,
+ 0x10, 0x38, 0xb9, 0x8b, 0xf5, 0x0b, 0x68, 0xf3, 0x13, 0xe6, 0x35, 0x7e,
+ 0x5f, 0x41, 0xeb, 0xb7, 0x1f, 0xb3, 0xce, 0xc1, 0x9c, 0xe1, 0x7c, 0x6d,
+ 0x9d, 0xb6, 0xaa, 0x74, 0x9a, 0xed, 0xd0, 0x69, 0xb9, 0xba, 0x4e, 0x63,
+ 0xde, 0x10, 0xba, 0x0c, 0xba, 0xea, 0x51, 0xc6, 0x91, 0xf2, 0x18, 0xf8,
+ 0x70, 0x87, 0xd0, 0x5d, 0xac, 0xfb, 0xd9, 0xae, 0x58, 0xac, 0x66, 0x7d,
+ 0x87, 0x85, 0x0e, 0xd1, 0xfc, 0xbd, 0x7f, 0xb7, 0x94, 0x8b, 0x6e, 0xa1,
+ 0x0f, 0x72, 0x27, 0xa1, 0xb7, 0xbc, 0xda, 0x8f, 0x73, 0x3b, 0xb4, 0xb7,
+ 0x23, 0x2f, 0xb1, 0x3e, 0x5b, 0x8c, 0xc2, 0xa6, 0xed, 0x51, 0xb6, 0x0f,
+ 0xea, 0x72, 0x61, 0xaf, 0x0b, 0x63, 0xd5, 0xfa, 0x6c, 0x40, 0xf9, 0x35,
+ 0xe0, 0x87, 0xc4, 0x9c, 0xb7, 0xc5, 0x08, 0x26, 0x30, 0x02, 0xdf, 0x13,
+ 0x60, 0x7a, 0x89, 0x1a, 0xe2, 0x44, 0xef, 0xd2, 0xaa, 0x90, 0x8d, 0x77,
+ 0x05, 0x76, 0xc9, 0xf3, 0x77, 0xb3, 0xd3, 0x07, 0x45, 0x3f, 0xf3, 0x4b,
+ 0x0d, 0xfd, 0x38, 0x57, 0x78, 0x0f, 0xeb, 0x86, 0xe8, 0x6b, 0x65, 0x42,
+ 0xea, 0xc0, 0xc5, 0x32, 0x6a, 0x80, 0x89, 0x3e, 0x73, 0x5f, 0xf5, 0x38,
+ 0xd1, 0x0f, 0xad, 0x0f, 0x36, 0x22, 0x7b, 0x8c, 0x6b, 0xfb, 0x31, 0x47,
+ 0x59, 0x07, 0x0f, 0x3d, 0xcb, 0xef, 0xc7, 0xb5, 0xf5, 0xc7, 0x73, 0xaf,
+ 0x3e, 0x1e, 0xf8, 0xf6, 0x70, 0xcf, 0xbb, 0x74, 0x57, 0x8d, 0xe7, 0x6e,
+ 0x7d, 0x3c, 0xcf, 0xa8, 0xf1, 0x50, 0xce, 0x88, 0x0d, 0x28, 0xdc, 0xbf,
+ 0xe1, 0x67, 0x77, 0x27, 0x18, 0xc7, 0xe4, 0x96, 0x40, 0xe7, 0xfd, 0x8a,
+ 0x9f, 0x9c, 0x7e, 0x54, 0x67, 0x5f, 0xad, 0xc9, 0x3b, 0xac, 0x7f, 0xef,
+ 0x09, 0x1c, 0x33, 0xc2, 0x38, 0x06, 0xd7, 0x29, 0x0f, 0x3d, 0x9d, 0x0b,
+ 0xa3, 0x4e, 0xed, 0x0c, 0x8f, 0x9b, 0xed, 0xb1, 0x69, 0xfe, 0x14, 0xfe,
+ 0x35, 0x3c, 0x47, 0xdf, 0xff, 0x3c, 0xdd, 0x9b, 0x87, 0x2e, 0x07, 0x8e,
+ 0x95, 0xb5, 0x6c, 0xef, 0x2d, 0x4b, 0xff, 0x6e, 0xca, 0xd3, 0xbf, 0x0b,
+ 0xdf, 0xee, 0x34, 0x70, 0x7e, 0x08, 0x7e, 0xe0, 0xa4, 0xfa, 0xad, 0x8f,
+ 0x5c, 0x15, 0xcf, 0xf2, 0xd2, 0x4b, 0x33, 0x8e, 0xd8, 0x38, 0xc4, 0xaa,
+ 0x64, 0x59, 0xcf, 0xd8, 0xa1, 0x0e, 0x43, 0xe6, 0xdc, 0xdc, 0xa8, 0x6a,
+ 0xec, 0x74, 0x94, 0xe7, 0xcc, 0x8e, 0x1a, 0x46, 0x4a, 0xf8, 0x1a, 0xba,
+ 0xed, 0x1e, 0xea, 0xe2, 0x75, 0xf4, 0x2c, 0xa1, 0x96, 0x9a, 0x65, 0x62,
+ 0x0f, 0xe0, 0x12, 0xf3, 0x64, 0x3e, 0x6a, 0x45, 0x1e, 0x17, 0x76, 0x29,
+ 0xd6, 0x17, 0x03, 0x74, 0x62, 0x5a, 0xa3, 0x0f, 0x7c, 0xbc, 0x84, 0x3a,
+ 0x9a, 0x51, 0x1e, 0x3f, 0xfc, 0xc7, 0x63, 0xe6, 0x9b, 0xbc, 0x2e, 0x5d,
+ 0x12, 0x7e, 0x99, 0x0b, 0x94, 0x63, 0x39, 0x3d, 0x22, 0xe4, 0xd4, 0x18,
+ 0x61, 0x29, 0x62, 0xb9, 0x42, 0x6c, 0xc2, 0xb8, 0xa8, 0xdb, 0x23, 0x6d,
+ 0x1d, 0x1e, 0xe5, 0xb2, 0xaa, 0x87, 0x90, 0x86, 0xee, 0xd8, 0xb8, 0x4f,
+ 0x22, 0xfd, 0x89, 0x7d, 0x31, 0x4e, 0x4c, 0xe6, 0xf6, 0x7d, 0xc3, 0xae,
+ 0x33, 0x45, 0xbd, 0x48, 0xd0, 0x4e, 0xf8, 0x13, 0x8d, 0x29, 0xa6, 0x9b,
+ 0xfe, 0xdd, 0x19, 0xa7, 0xdf, 0xe0, 0x9c, 0xc8, 0xeb, 0x7f, 0xa5, 0x2a,
+ 0xd7, 0xe0, 0x1c, 0xdb, 0xf4, 0xf9, 0x83, 0x4e, 0x4c, 0x62, 0x15, 0x93,
+ 0xc2, 0x97, 0xb3, 0x9b, 0x12, 0x0b, 0x53, 0xf4, 0x68, 0x01, 0x3a, 0x8c,
+ 0xee, 0x24, 0x6c, 0xfc, 0xa2, 0x0c, 0x64, 0x7c, 0x8a, 0x52, 0x55, 0xd0,
+ 0xc8, 0xc7, 0x58, 0x89, 0x79, 0xaf, 0x88, 0x3d, 0x7f, 0x3e, 0x2e, 0xe3,
+ 0x77, 0x54, 0x7e, 0x5d, 0xf9, 0xcb, 0x87, 0x29, 0xb9, 0x40, 0xd9, 0x4c,
+ 0xf4, 0x4b, 0xa2, 0xd6, 0x75, 0x26, 0x3a, 0xa1, 0x7c, 0x3b, 0x11, 0xbe,
+ 0x0e, 0x7f, 0x99, 0x49, 0x5f, 0x2e, 0x58, 0xd9, 0x0c, 0x49, 0x9f, 0x05,
+ 0x71, 0x1f, 0x0c, 0x5e, 0x7b, 0x77, 0xb0, 0x0e, 0x39, 0x21, 0xfc, 0x16,
+ 0x8c, 0x54, 0xe6, 0xd1, 0x1e, 0x3e, 0x87, 0x7e, 0x82, 0x9d, 0x96, 0x29,
+ 0x3e, 0xa5, 0xda, 0xd6, 0x28, 0xc4, 0xbc, 0x10, 0xfa, 0x55, 0x3b, 0x1b,
+ 0x35, 0x1a, 0xf7, 0xc3, 0xe7, 0x71, 0x42, 0xe0, 0xc8, 0x11, 0xb6, 0x79,
+ 0x44, 0xbb, 0xda, 0xac, 0xf0, 0x5f, 0xf0, 0x79, 0xf9, 0x81, 0x21, 0xfd,
+ 0x9b, 0x08, 0xb8, 0x2e, 0xfd, 0x1a, 0xfc, 0xcc, 0x32, 0xf7, 0xa3, 0x29,
+ 0x9e, 0x7e, 0x98, 0xe2, 0x9b, 0xf0, 0x33, 0x9d, 0xbc, 0xaf, 0x7e, 0x26,
+ 0xa6, 0x35, 0xaf, 0x3d, 0x37, 0x58, 0x36, 0x5e, 0x5f, 0xd7, 0xfe, 0xfb,
+ 0x50, 0xaf, 0xe1, 0x4c, 0xab, 0x90, 0xf8, 0xdd, 0x0c, 0x60, 0xf0, 0x7c,
+ 0xf5, 0x71, 0xfc, 0x5e, 0x8c, 0x2f, 0x2d, 0xb0, 0x71, 0x84, 0xb1, 0x0d,
+ 0x30, 0xce, 0x98, 0xd8, 0x17, 0x8b, 0x3f, 0x16, 0xf1, 0xe5, 0x97, 0x07,
+ 0xc9, 0x0f, 0x7f, 0x9c, 0xad, 0x63, 0x29, 0xba, 0x45, 0xdc, 0xbb, 0xdc,
+ 0x8f, 0xc4, 0xfa, 0x0c, 0x9d, 0x78, 0x87, 0xed, 0x86, 0x09, 0x15, 0x87,
+ 0xd3, 0x21, 0x6a, 0x53, 0xc9, 0xbd, 0x54, 0xad, 0x53, 0x34, 0xef, 0xe9,
+ 0xbd, 0x0e, 0xe7, 0x6f, 0x73, 0x41, 0x76, 0x9d, 0x98, 0x02, 0xfe, 0x29,
+ 0x31, 0x47, 0x97, 0x88, 0xe4, 0x1c, 0x37, 0xf6, 0x31, 0xba, 0x78, 0x9e,
+ 0x60, 0x0f, 0xc2, 0xef, 0xf7, 0x35, 0xfe, 0xc4, 0x7e, 0xc4, 0xd5, 0x21,
+ 0xe0, 0xa8, 0x3e, 0x9b, 0x79, 0x66, 0x1a, 0xe7, 0x83, 0x6c, 0x9f, 0x69,
+ 0xdc, 0x2b, 0x7d, 0x51, 0x6c, 0xb3, 0xa9, 0xf9, 0x82, 0x1f, 0x6a, 0x54,
+ 0xd5, 0x29, 0xb0, 0xc8, 0xec, 0x07, 0x9d, 0x3e, 0x2d, 0x79, 0x5c, 0x6f,
+ 0xef, 0x62, 0x23, 0xb1, 0x4e, 0xf8, 0xdd, 0x30, 0xd4, 0xeb, 0xdc, 0x0b,
+ 0xda, 0xf3, 0x1c, 0x39, 0xf7, 0x36, 0x1e, 0xdf, 0xa5, 0x7f, 0xb3, 0xe8,
+ 0xfe, 0xcc, 0xdb, 0x16, 0x8f, 0x79, 0xfb, 0xf9, 0x90, 0xdc, 0x3b, 0x7b,
+ 0x58, 0xb5, 0xf1, 0x8a, 0x6f, 0x5d, 0xfe, 0x0e, 0xfc, 0x50, 0x8d, 0xfc,
+ 0x8b, 0x77, 0x84, 0x5e, 0x69, 0xf5, 0x85, 0x47, 0x58, 0x9f, 0x4a, 0x39,
+ 0x3e, 0xe1, 0x21, 0xc7, 0xfd, 0x31, 0xe0, 0x96, 0x8f, 0x2f, 0xc7, 0xc7,
+ 0xdb, 0xca, 0xf1, 0x9e, 0x61, 0xe9, 0x8b, 0x6d, 0x95, 0x63, 0xe4, 0x00,
+ 0x9d, 0xa8, 0xb6, 0xf3, 0x7b, 0x61, 0x1e, 0x90, 0xcb, 0xee, 0xf4, 0x95,
+ 0x80, 0x66, 0xda, 0x5f, 0x82, 0x7d, 0x43, 0xf0, 0x25, 0xf6, 0x5e, 0x4e,
+ 0x1a, 0xa9, 0x79, 0xf7, 0x5e, 0xea, 0x46, 0xee, 0xbd, 0xed, 0x71, 0x2f,
+ 0xb0, 0x3b, 0x64, 0xc3, 0x8a, 0x48, 0x5f, 0x80, 0xa6, 0xdf, 0xb0, 0xef,
+ 0x70, 0xc9, 0xca, 0x96, 0x09, 0xbe, 0xee, 0x30, 0x9d, 0xc3, 0xfe, 0xb4,
+ 0xf2, 0x25, 0x1f, 0x2b, 0x48, 0x3a, 0x84, 0x0e, 0x0a, 0xfe, 0x00, 0xbe,
+ 0x8d, 0xa4, 0xfd, 0x69, 0x9e, 0x63, 0xe9, 0x47, 0xce, 0x2c, 0x45, 0xd4,
+ 0xbc, 0x71, 0x5b, 0x3c, 0xcf, 0x33, 0x5f, 0x10, 0xf3, 0x65, 0x3d, 0xbf,
+ 0x52, 0x8f, 0x4f, 0xc6, 0xda, 0x50, 0xa3, 0xff, 0xe0, 0x75, 0xcf, 0x7f,
+ 0x30, 0x24, 0x6a, 0x37, 0xdc, 0xa8, 0x1e, 0x64, 0xbc, 0x89, 0x39, 0x85,
+ 0x0f, 0x52, 0xfb, 0x88, 0x1f, 0xda, 0x4b, 0xbd, 0x07, 0x18, 0x05, 0x18,
+ 0x64, 0x33, 0xbe, 0x34, 0x0e, 0x22, 0xce, 0xdc, 0xe4, 0x7b, 0x50, 0x73,
+ 0x6a, 0xdc, 0x4c, 0x51, 0x0f, 0xfc, 0x10, 0xa8, 0x25, 0x6d, 0xe6, 0x9a,
+ 0x64, 0xec, 0x94, 0x90, 0xb1, 0xd4, 0xf2, 0x29, 0x25, 0x63, 0xa7, 0x94,
+ 0x1f, 0xfe, 0x94, 0x92, 0xb1, 0x53, 0x4a, 0xc6, 0x4e, 0x29, 0x19, 0x3b,
+ 0xc5, 0x7c, 0x3e, 0xc6, 0xf8, 0x16, 0x58, 0x44, 0xfb, 0x41, 0x7b, 0x29,
+ 0x53, 0xc2, 0x75, 0xac, 0xcf, 0x6e, 0x39, 0x7b, 0x69, 0x44, 0xca, 0x19,
+ 0x63, 0x13, 0x19, 0xaf, 0xc7, 0xef, 0xc2, 0x1c, 0xfc, 0x1e, 0xd3, 0xef,
+ 0x23, 0x3a, 0x33, 0x8f, 0xbe, 0xfa, 0x28, 0x29, 0x6a, 0xc9, 0x76, 0x50,
+ 0xc2, 0x89, 0x85, 0x43, 0xc8, 0x0f, 0x93, 0xb6, 0x5f, 0xb6, 0x6d, 0xae,
+ 0x98, 0xe6, 0x93, 0x98, 0x9a, 0x2f, 0xb7, 0x5d, 0xd4, 0x45, 0xe9, 0x22,
+ 0xe8, 0x8a, 0x98, 0x4a, 0x93, 0xe7, 0x46, 0xd0, 0x49, 0x86, 0x44, 0xb9,
+ 0x68, 0x70, 0x4c, 0xd1, 0xe0, 0xdb, 0x62, 0x8c, 0x88, 0x49, 0x84, 0x2f,
+ 0xb3, 0x3d, 0x1d, 0x72, 0x85, 0x31, 0x7e, 0x0e, 0xcb, 0xc2, 0xc1, 0x08,
+ 0xeb, 0xa4, 0x8d, 0xd3, 0xa1, 0x31, 0xf6, 0x76, 0xba, 0x67, 0xa3, 0x79,
+ 0x39, 0x77, 0x1c, 0x6b, 0x49, 0x44, 0xad, 0x23, 0x12, 0x17, 0x6f, 0xb1,
+ 0x6b, 0x74, 0x34, 0xba, 0x97, 0x8f, 0xad, 0x74, 0x96, 0x0e, 0x90, 0xd1,
+ 0x57, 0xa3, 0xbf, 0x60, 0x39, 0xe8, 0x66, 0x39, 0x38, 0xaa, 0xec, 0x92,
+ 0xa3, 0x75, 0xbb, 0x64, 0xcf, 0x1e, 0xc4, 0x65, 0x64, 0xc4, 0xbe, 0xd7,
+ 0x56, 0x55, 0x43, 0x00, 0xbe, 0x6f, 0x9c, 0x77, 0x51, 0x7c, 0x18, 0xe7,
+ 0xf8, 0x2d, 0x22, 0x6b, 0x32, 0xee, 0x1b, 0xdf, 0x23, 0xb0, 0xbb, 0xcf,
+ 0xc2, 0x3d, 0x47, 0xa5, 0xde, 0xf3, 0x91, 0x7f, 0xfc, 0x36, 0xe3, 0x89,
+ 0x1a, 0x3d, 0xc1, 0xef, 0xcc, 0x17, 0xf7, 0xf1, 0xb3, 0x75, 0x4d, 0x09,
+ 0x3b, 0x6e, 0xf8, 0xb6, 0x92, 0xbf, 0xaf, 0xdd, 0xbb, 0x2d, 0xc1, 0x8f,
+ 0x8c, 0xa7, 0x8d, 0xd9, 0xe8, 0x7b, 0xb5, 0xd3, 0x27, 0xe1, 0x63, 0x87,
+ 0x9c, 0x58, 0x21, 0xd3, 0xe7, 0x25, 0x1f, 0x12, 0x2b, 0x35, 0xe2, 0x63,
+ 0x21, 0x2f, 0x35, 0xfa, 0x77, 0x1e, 0x5b, 0x88, 0xb0, 0x77, 0x22, 0x9f,
+ 0x9f, 0xa6, 0x19, 0x91, 0x83, 0x8d, 0x38, 0xe9, 0x33, 0xf3, 0xfa, 0x5d,
+ 0xb6, 0xe2, 0x8d, 0xcf, 0x20, 0xce, 0xad, 0xb8, 0x48, 0x6b, 0xaf, 0x39,
+ 0xf0, 0xd7, 0x8d, 0x2d, 0xac, 0xf6, 0x85, 0x45, 0x4e, 0xf8, 0x76, 0xc6,
+ 0x48, 0x3a, 0x1e, 0x7a, 0x9c, 0x9f, 0x0f, 0x3f, 0x5e, 0x80, 0x92, 0x57,
+ 0xd0, 0xae, 0x93, 0x46, 0x17, 0x6a, 0x5f, 0xe0, 0xef, 0xc5, 0xfe, 0x65,
+ 0x86, 0xba, 0xd5, 0xde, 0x44, 0x8f, 0xda, 0xcf, 0x8a, 0xb0, 0xec, 0x35,
+ 0x72, 0x9d, 0x47, 0xeb, 0x3e, 0x3d, 0xc8, 0x84, 0xdb, 0xa7, 0xf7, 0xf4,
+ 0x3a, 0xeb, 0xd5, 0x7a, 0x72, 0x80, 0x58, 0xd6, 0x2e, 0x52, 0xbe, 0x4a,
+ 0x33, 0x4f, 0x1b, 0xcd, 0xe9, 0xdb, 0xf4, 0x3d, 0xdd, 0x9d, 0x31, 0xf3,
+ 0xc2, 0x9b, 0x76, 0x50, 0xf1, 0x5f, 0x27, 0x9d, 0x29, 0x05, 0x79, 0xcd,
+ 0x87, 0x6e, 0x05, 0xbd, 0xfc, 0xc3, 0xc8, 0x73, 0xf9, 0x7a, 0xa0, 0x93,
+ 0x96, 0x96, 0x10, 0x6b, 0xf1, 0x47, 0x7b, 0x64, 0x7c, 0x71, 0x9a, 0xe9,
+ 0x72, 0x80, 0xd7, 0x47, 0x43, 0xed, 0x1d, 0xe1, 0x1a, 0x74, 0x89, 0xa8,
+ 0x37, 0x1a, 0xf8, 0xd2, 0x44, 0x90, 0xed, 0x02, 0xb9, 0xf7, 0x70, 0x88,
+ 0x9f, 0xfd, 0xfd, 0x52, 0x1a, 0xfe, 0xb2, 0xd0, 0x11, 0x7e, 0x7e, 0x92,
+ 0xf1, 0x44, 0x9c, 0x3a, 0xa9, 0xb2, 0xd4, 0xc9, 0x76, 0x41, 0x27, 0xe3,
+ 0x89, 0xb1, 0xd0, 0xa8, 0x4f, 0xbc, 0x4b, 0xe4, 0xd4, 0x3c, 0x1c, 0x38,
+ 0xc0, 0x7c, 0x85, 0x77, 0xbd, 0xae, 0xde, 0xe5, 0x7e, 0xc7, 0x2f, 0x6a,
+ 0x38, 0x3f, 0xe2, 0x37, 0x2f, 0xdc, 0xc2, 0xef, 0x51, 0xcd, 0xcf, 0x30,
+ 0x76, 0x0e, 0x53, 0x7e, 0xbe, 0x83, 0xc7, 0x10, 0x63, 0x3b, 0x22, 0xca,
+ 0xe7, 0x8f, 0x50, 0xb6, 0x7a, 0x92, 0x7e, 0xbf, 0xea, 0xf4, 0x09, 0x3f,
+ 0xc2, 0x7d, 0x96, 0x39, 0xfd, 0x5d, 0xdc, 0xaf, 0x0f, 0x6d, 0xb7, 0x8e,
+ 0x09, 0x92, 0xff, 0x7b, 0x61, 0xea, 0x7c, 0x0e, 0xbe, 0x97, 0x1a, 0x15,
+ 0xa3, 0xd6, 0xa5, 0x3b, 0x24, 0xfd, 0xcf, 0x2f, 0x88, 0xb8, 0x5a, 0xbe,
+ 0x9f, 0x9f, 0x39, 0x87, 0x76, 0x2f, 0x98, 0x74, 0xd3, 0x96, 0xf4, 0x7e,
+ 0x23, 0x10, 0x26, 0xff, 0xcb, 0x88, 0x7d, 0x02, 0x56, 0x33, 0x2f, 0xd8,
+ 0xfb, 0x58, 0xbf, 0x3f, 0x87, 0xfb, 0xf8, 0xf3, 0x65, 0x9c, 0x07, 0x79,
+ 0x9c, 0x58, 0xaf, 0x11, 0xef, 0x02, 0xbd, 0x78, 0x20, 0x12, 0x12, 0xfc,
+ 0xf7, 0x08, 0xf3, 0x54, 0x87, 0xf0, 0x35, 0xf6, 0xa3, 0xad, 0x3d, 0xc4,
+ 0xd8, 0xc2, 0xbc, 0x30, 0xb1, 0x0f, 0xe7, 0xf1, 0x3e, 0x3f, 0xd3, 0x48,
+ 0xf2, 0x10, 0xc6, 0xd3, 0xc4, 0xdc, 0x81, 0x43, 0x13, 0xc4, 0xf3, 0x09,
+ 0xfc, 0xc1, 0xf3, 0x19, 0x42, 0x7d, 0xa7, 0x20, 0xa5, 0xf8, 0x1d, 0xc9,
+ 0x92, 0x1c, 0xf7, 0x5c, 0xd5, 0x4f, 0xd2, 0x4f, 0x75, 0x74, 0x44, 0xff,
+ 0x9e, 0x21, 0x0d, 0xe2, 0xd9, 0x5a, 0x56, 0x70, 0xdc, 0x4b, 0x77, 0x4b,
+ 0x3d, 0x74, 0x4f, 0xed, 0x69, 0xdd, 0x15, 0x76, 0x19, 0xeb, 0xf0, 0x74,
+ 0x2f, 0xdd, 0x59, 0xea, 0x20, 0xea, 0x0f, 0x8a, 0x3d, 0xe7, 0xbb, 0xa5,
+ 0x32, 0xbf, 0x3f, 0x31, 0x22, 0xfd, 0x3a, 0x0d, 0x1e, 0xb9, 0xeb, 0xc1,
+ 0x23, 0x1f, 0x08, 0x1e, 0xd9, 0x37, 0xb2, 0x36, 0x8f, 0xec, 0x52, 0xb6,
+ 0x48, 0x90, 0x3a, 0x15, 0x7f, 0xbc, 0xc4, 0xfc, 0xf1, 0x2c, 0xf3, 0xc7,
+ 0xe1, 0x36, 0xfc, 0x61, 0xb8, 0xf8, 0xe3, 0x88, 0xe0, 0x8f, 0x87, 0x46,
+ 0xd6, 0xe2, 0x8f, 0xc3, 0xfe, 0xb5, 0x7c, 0x4d, 0xe2, 0xb7, 0x3c, 0x2f,
+ 0xcc, 0xd9, 0xbb, 0x99, 0xd7, 0x6d, 0xaa, 0xcc, 0x23, 0x67, 0x61, 0x25,
+ 0x6a, 0xd0, 0xbf, 0x08, 0x9b, 0x6c, 0x55, 0xd8, 0xfc, 0x31, 0x11, 0xc3,
+ 0xba, 0x28, 0xf8, 0x8b, 0xd7, 0xff, 0x18, 0x72, 0xaa, 0xdc, 0x73, 0xd1,
+ 0x4d, 0x37, 0xa3, 0x98, 0x0b, 0x53, 0xcd, 0x05, 0xae, 0x75, 0xe9, 0xfa,
+ 0x90, 0x01, 0xbe, 0x7e, 0xe1, 0x03, 0xf0, 0xe8, 0x72, 0x4f, 0x20, 0x59,
+ 0xf8, 0xe6, 0x08, 0xf0, 0x5f, 0x7e, 0x99, 0x1c, 0xd7, 0x03, 0x7c, 0x3d,
+ 0x2c, 0x7e, 0xfb, 0x09, 0xb2, 0xf2, 0x8f, 0x88, 0x71, 0x64, 0x9e, 0xbc,
+ 0x59, 0x1a, 0xa6, 0x5b, 0xa5, 0xdd, 0xb4, 0x5a, 0x1a, 0xa1, 0x37, 0x45,
+ 0x2d, 0x0d, 0x99, 0x1b, 0xb9, 0x2a, 0xe6, 0xc8, 0xa0, 0x43, 0x61, 0x6e,
+ 0xb3, 0xb4, 0x9b, 0x56, 0x96, 0x34, 0x7f, 0x83, 0xb7, 0xc1, 0x2f, 0xf1,
+ 0x3e, 0x99, 0x2f, 0xd7, 0xca, 0x33, 0xc9, 0x26, 0x9e, 0x91, 0xf7, 0x80,
+ 0x57, 0xf2, 0xad, 0xb9, 0xbe, 0xdd, 0xa1, 0x18, 0x62, 0xf5, 0x82, 0xd4,
+ 0x81, 0xb8, 0x45, 0xc3, 0x9a, 0x3c, 0xe4, 0x07, 0x86, 0xfe, 0x2a, 0xaf,
+ 0xb9, 0x3c, 0x67, 0x36, 0xe2, 0x9c, 0x46, 0x18, 0x0f, 0x6f, 0x17, 0xf8,
+ 0x37, 0x61, 0x07, 0x22, 0x49, 0xaa, 0x5d, 0x30, 0x6c, 0xd4, 0x73, 0x4c,
+ 0xf3, 0xf3, 0x0c, 0xe5, 0x6f, 0xda, 0xe6, 0xe0, 0x3f, 0x37, 0xd6, 0xc5,
+ 0x5e, 0xf2, 0x63, 0xdc, 0x67, 0xac, 0xc3, 0x8d, 0xfd, 0x1a, 0xaa, 0xef,
+ 0xd7, 0x74, 0xf3, 0xb8, 0xa5, 0xec, 0xcd, 0xda, 0xdc, 0xae, 0xca, 0xed,
+ 0xaa, 0xd8, 0xfb, 0xe3, 0xeb, 0x4b, 0xd8, 0x77, 0x1e, 0xa6, 0xd5, 0x79,
+ 0xc8, 0x28, 0xfc, 0x21, 0x8d, 0xbd, 0xde, 0xd5, 0x65, 0x5c, 0x87, 0x4f,
+ 0xa4, 0xb1, 0xd7, 0xbb, 0xaa, 0xf6, 0x7a, 0x57, 0x97, 0x63, 0x42, 0x6f,
+ 0xe7, 0x4b, 0x4c, 0xf7, 0x92, 0x5f, 0xc5, 0x39, 0xee, 0x53, 0xbf, 0x2d,
+ 0xf4, 0x98, 0xf0, 0x69, 0xf7, 0xd9, 0x6b, 0xd3, 0xf0, 0x50, 0x0b, 0x0d,
+ 0x63, 0x02, 0x67, 0xa5, 0xf8, 0x99, 0xc9, 0xd2, 0x63, 0xff, 0x3b, 0x60,
+ 0x78, 0x46, 0x00, 0xf3, 0x9e, 0x30, 0x34, 0xef, 0xc1, 0xe6, 0x8e, 0xf9,
+ 0x19, 0x20, 0xf7, 0x14, 0xd9, 0x80, 0xfb, 0x16, 0x90, 0xf2, 0x4a, 0x06,
+ 0xad, 0xbc, 0x02, 0xa6, 0x09, 0x75, 0x88, 0xfe, 0xa6, 0xf5, 0x9f, 0xe5,
+ 0x60, 0xe3, 0x80, 0x4d, 0x40, 0x73, 0x9b, 0xa7, 0x90, 0x32, 0xf7, 0x0c,
+ 0xac, 0x6f, 0xb1, 0xae, 0x6d, 0xb4, 0x01, 0xef, 0xb1, 0x5e, 0x34, 0x85,
+ 0x85, 0x61, 0x49, 0x0f, 0x03, 0xb0, 0x7e, 0x00, 0xa5, 0x75, 0x50, 0x1d,
+ 0x01, 0x4f, 0xef, 0x02, 0x4d, 0x40, 0xf7, 0x39, 0x01, 0xdb, 0xa2, 0xce,
+ 0xfd, 0xca, 0xe0, 0xb5, 0xb2, 0x0d, 0xd0, 0x73, 0xab, 0x16, 0xf5, 0x88,
+ 0xc9, 0x83, 0xf2, 0x99, 0x93, 0x0a, 0x03, 0x19, 0x79, 0x81, 0x0d, 0x9a,
+ 0x17, 0xc0, 0xe1, 0x04, 0x4c, 0xeb, 0xc0, 0x32, 0x6a, 0x8d, 0x2e, 0xd0,
+ 0x3c, 0x1e, 0x16, 0x97, 0x7e, 0x90, 0x18, 0x03, 0x54, 0x8c, 0x05, 0xc8,
+ 0x97, 0x01, 0xb6, 0x29, 0x41, 0x7e, 0x05, 0xe5, 0x05, 0x90, 0xd9, 0x20,
+ 0xbf, 0x83, 0xca, 0x4e, 0x50, 0x5e, 0x04, 0xb2, 0x97, 0x08, 0x41, 0xfd,
+ 0x0c, 0xa4, 0x81, 0xec, 0xe6, 0x29, 0x22, 0x60, 0x7e, 0x52, 0x80, 0x10,
+ 0x43, 0x03, 0x3c, 0x1f, 0x10, 0x1b, 0xc6, 0x30, 0xf5, 0x31, 0x64, 0xe4,
+ 0x1b, 0x88, 0x19, 0x88, 0x7c, 0xc3, 0xce, 0x70, 0x40, 0x00, 0x16, 0x56,
+ 0xff, 0xff, 0x1f, 0x53, 0x61, 0x01, 0xa6, 0x53, 0xd0, 0x3a, 0xd6, 0xdf,
+ 0xff, 0x0f, 0x88, 0xb0, 0x30, 0xb4, 0xc0, 0xd7, 0x23, 0xe6, 0xc8, 0x83,
+ 0xca, 0xd0, 0x05, 0x40, 0x56, 0x1b, 0xbc, 0x4d, 0xc0, 0x02, 0xbe, 0xef,
+ 0x79, 0x01, 0xc3, 0x2f, 0x60, 0x99, 0xf5, 0xff, 0xff, 0x52, 0xb8, 0x5a,
+ 0x10, 0x00, 0x00, 0x19, 0x3f, 0x16, 0x21, 0xc4, 0x7d, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_COM_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b09FwRodata[(0x88/4) + 1] = {
+ 0x08001b68, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4, 0x08001ba4,
+ 0x08001ab4, 0x08001ba4, 0x08001b28, 0x08001ba4, 0x08001a3c, 0x08001ba4,
+ 0x08001ba4, 0x08001ba4, 0x08001a48, 0x00000000, 0x08002abc, 0x08002b0c,
+ 0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c,
+ 0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8,
+ 0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 };
+static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
+static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 };
static struct fw_info bnx2_com_fw_09 = {
- .ver_major = 0x1,
- .ver_minor = 0x0,
- .ver_fix = 0x0,
+ .ver_major = 0x3,
+ .ver_minor = 0x4,
+ .ver_fix = 0x3,
- .start_addr = 0x080000b0,
+ .start_addr = 0x080000b4,
.text_addr = 0x08000000,
- .text_len = 0x7c5c,
+ .text_len = 0x7dc0,
.text_index = 0x0,
.gz_text = bnx2_COM_b09FwText,
.gz_text_len = sizeof(bnx2_COM_b09FwText),
- .data_addr = 0x08007d00,
+ .data_addr = 0x08007e60,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_COM_b09FwData,
- .sbss_addr = 0x08007d00,
- .sbss_len = 0x5c,
+ .sbss_addr = 0x08007e60,
+ .sbss_len = 0x60,
.sbss_index = 0x0,
.sbss = bnx2_COM_b09FwSbss,
- .bss_addr = 0x08007d60,
+ .bss_addr = 0x08007ec0,
.bss_len = 0x88,
.bss_index = 0x0,
.bss = bnx2_COM_b09FwBss,
- .rodata_addr = 0x08007c60,
+ .rodata_addr = 0x08007dc0,
.rodata_len = 0x88,
.rodata_index = 0x0,
.rodata = bnx2_COM_b09FwRodata,
};
static u8 bnx2_CP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x8e, 0xfc, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xbd, 0x7d, 0x0d, 0x74,
- 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x79, 0x92, 0xc6, 0xb2, 0x2c, 0x3f,
- 0xcb, 0x63, 0x65, 0x22, 0x0b, 0x7b, 0x46, 0x7a, 0xb2, 0x95, 0x58, 0x64,
- 0xc7, 0xae, 0x00, 0x6d, 0x3b, 0x85, 0xe9, 0x48, 0xb2, 0x9d, 0x0f, 0x8a,
- 0x4c, 0x44, 0x4f, 0x5a, 0xe8, 0x22, 0xc6, 0x76, 0x48, 0x80, 0xb2, 0x4e,
- 0x09, 0x69, 0x80, 0x04, 0x0f, 0x23, 0xf9, 0x83, 0x74, 0xec, 0x51, 0x12,
- 0xc5, 0x76, 0x4f, 0x73, 0x58, 0x55, 0x92, 0x1d, 0x43, 0xa7, 0x1e, 0x27,
- 0x71, 0x68, 0xf6, 0x6c, 0x68, 0xb4, 0x4a, 0xe2, 0xa6, 0x3d, 0xd9, 0xd6,
- 0xf4, 0x84, 0x6e, 0xda, 0x43, 0x77, 0x85, 0x71, 0x88, 0x4b, 0xb3, 0x4b,
- 0xf8, 0x68, 0x61, 0xa1, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d, 0xd2, 0xe8,
- 0xc3, 0x09, 0xa1, 0xbb, 0xf5, 0x39, 0xcf, 0x6f, 0xde, 0xfd, 0xfc, 0xdf,
- 0xff, 0xfd, 0x7f, 0xdf, 0x0f, 0xad, 0x17, 0xa9, 0x17, 0xfb, 0x6f, 0x15,
- 0x9e, 0x6d, 0x89, 0x7d, 0xbb, 0xb7, 0x5e, 0xd7, 0x73, 0x1d, 0x7e, 0x6e,
- 0x75, 0x57, 0x46, 0x95, 0xbc, 0x89, 0x7f, 0x89, 0x9f, 0xa1, 0x4c, 0x44,
- 0xc4, 0x0b, 0xfb, 0xe2, 0x23, 0x51, 0x95, 0x1e, 0xfc, 0x64, 0xd6, 0x97,
- 0x68, 0x24, 0x7d, 0xf6, 0xb3, 0xbb, 0x7d, 0x91, 0x4c, 0x79, 0x4b, 0xa2,
- 0x57, 0xfe, 0x25, 0xc8, 0xc7, 0x5c, 0x61, 0xfa, 0x5b, 0xd2, 0xff, 0xfc,
- 0x9f, 0xbe, 0xf2, 0x8e, 0xe4, 0x6b, 0xe3, 0x11, 0x89, 0x7a, 0xe9, 0x8f,
- 0x89, 0xb7, 0x49, 0xa2, 0xad, 0xe9, 0x81, 0x4f, 0x3e, 0xbc, 0xf9, 0x6f,
- 0x44, 0x1a, 0xc3, 0xb6, 0x2e, 0x07, 0x5f, 0xd9, 0x2c, 0xf9, 0x96, 0x74,
- 0x7c, 0xc8, 0x4d, 0x7b, 0xf2, 0x74, 0x45, 0x06, 0x0a, 0xc5, 0xa8, 0x44,
- 0xd2, 0x1d, 0x2f, 0xf5, 0x46, 0xf6, 0x07, 0x11, 0xdf, 0xf7, 0x7a, 0xa5,
- 0xa1, 0x27, 0xdb, 0x8d, 0xf4, 0xf2, 0x56, 0x51, 0x7e, 0x54, 0xb2, 0x15,
- 0x69, 0x50, 0xbe, 0x8f, 0x77, 0xbd, 0xa8, 0x74, 0xd2, 0xcb, 0x46, 0x5c,
- 0x29, 0x54, 0x2e, 0xac, 0x30, 0x6d, 0x96, 0xec, 0xfb, 0x6f, 0xa2, 0xe6,
- 0x8d, 0x36, 0x4b, 0x51, 0x99, 0x8d, 0xc4, 0x05, 0xfd, 0x00, 0xe6, 0x06,
- 0x19, 0x2e, 0x25, 0x24, 0x5b, 0x64, 0xbf, 0xae, 0xe4, 0x3c, 0xf6, 0xd9,
- 0x80, 0xfa, 0x2b, 0x9d, 0xe5, 0xcb, 0xb3, 0xec, 0x4b, 0x28, 0x9b, 0x40,
- 0xb9, 0x56, 0x79, 0xbc, 0x12, 0x97, 0xc7, 0x2a, 0x31, 0x79, 0xb4, 0x72,
- 0x87, 0x64, 0x50, 0xf7, 0x6c, 0x05, 0x7d, 0x97, 0x6a, 0xa5, 0x77, 0xac,
- 0x5e, 0xb2, 0x63, 0xed, 0xf1, 0x9c, 0x04, 0xc1, 0x27, 0x52, 0x1f, 0x95,
- 0xa1, 0x26, 0x94, 0x2f, 0x31, 0x2f, 0xbe, 0x20, 0x2f, 0x97, 0xda, 0xe2,
- 0xe5, 0x94, 0x23, 0x99, 0xc1, 0x64, 0x7c, 0x48, 0xf1, 0xbb, 0x46, 0xb2,
- 0x5d, 0xf8, 0x1e, 0x70, 0x25, 0xe2, 0x07, 0xc1, 0x1d, 0xa9, 0x26, 0xc0,
- 0x91, 0x4c, 0x24, 0x14, 0xeb, 0xb2, 0x5e, 0x32, 0x9f, 0x50, 0x51, 0xc9,
- 0x57, 0xae, 0x93, 0x44, 0x53, 0x10, 0xbc, 0x37, 0xe5, 0x21, 0x5d, 0xa4,
- 0xb7, 0x28, 0xfb, 0x54, 0xda, 0x47, 0x9b, 0x92, 0x52, 0xe9, 0xb5, 0x18,
- 0xc7, 0x16, 0xe0, 0xa9, 0x56, 0x32, 0x31, 0xc9, 0xa8, 0xb4, 0x24, 0x54,
- 0x7a, 0x05, 0xd2, 0x1c, 0xa9, 0xf1, 0xa7, 0x2c, 0x9d, 0xac, 0xc6, 0xb7,
- 0x0c, 0xa8, 0x74, 0xd3, 0xa2, 0xf4, 0x64, 0x42, 0xd4, 0x8f, 0xea, 0xd0,
- 0x67, 0x67, 0x46, 0x31, 0x0d, 0x6f, 0x9d, 0x76, 0xfd, 0x32, 0x69, 0x1f,
- 0x74, 0x16, 0xa6, 0x3d, 0xb5, 0x8a, 0xb0, 0x8a, 0xe2, 0xef, 0x28, 0xe0,
- 0x6a, 0x41, 0xff, 0xed, 0x5e, 0x0d, 0xc6, 0x35, 0x90, 0x4a, 0x7a, 0xfd,
- 0xea, 0xc5, 0x40, 0x9a, 0x09, 0x33, 0xf3, 0x14, 0xf2, 0x50, 0x34, 0x9d,
- 0xc2, 0xbc, 0xb9, 0x72, 0x08, 0x63, 0xbb, 0x38, 0x96, 0xf4, 0xda, 0x14,
- 0xde, 0x53, 0xfc, 0xdd, 0x34, 0x14, 0x49, 0x07, 0x41, 0x36, 0x35, 0x2e,
- 0xb9, 0x72, 0xd2, 0x9b, 0x05, 0x70, 0xbd, 0x63, 0x71, 0x8c, 0x1f, 0xe3,
- 0x88, 0x65, 0x92, 0x6b, 0xa4, 0xcb, 0xce, 0xcf, 0x5f, 0xa2, 0xef, 0x76,
- 0xef, 0x0e, 0xd5, 0xee, 0xa5, 0x54, 0xd2, 0x9b, 0x90, 0x3f, 0xc4, 0x77,
- 0x10, 0xec, 0x4a, 0x25, 0xe3, 0x79, 0xcc, 0xdd, 0xa5, 0x62, 0x4c, 0x5e,
- 0x2e, 0x26, 0x41, 0xa9, 0xc9, 0xce, 0x49, 0xd9, 0x92, 0x9a, 0x04, 0xdc,
- 0x05, 0x3c, 0x07, 0x99, 0x57, 0x46, 0x5e, 0x99, 0x75, 0x83, 0xe0, 0xe6,
- 0xd4, 0x89, 0x60, 0xa8, 0xd9, 0xd0, 0xfe, 0xd3, 0x25, 0xcc, 0x2b, 0xe6,
- 0xe9, 0xb1, 0x12, 0xe6, 0xb5, 0x84, 0x39, 0xd5, 0xf3, 0xdf, 0x89, 0xf9,
- 0x27, 0x8d, 0x90, 0x3e, 0xb6, 0x59, 0x7a, 0x7d, 0xb7, 0x7d, 0x8b, 0x64,
- 0x4b, 0x8e, 0x64, 0x53, 0x3f, 0x09, 0x32, 0x9a, 0x27, 0xc4, 0xe9, 0x2d,
- 0x91, 0x26, 0x6b, 0x00, 0x2b, 0x3f, 0x7f, 0xdd, 0x96, 0x8b, 0x3a, 0x18,
- 0x06, 0xe7, 0x83, 0xf9, 0x51, 0xe5, 0xd7, 0xd9, 0xfc, 0x90, 0xf6, 0xf9,
- 0x0f, 0x74, 0xe7, 0xcf, 0x97, 0xcb, 0x92, 0x36, 0x2b, 0x22, 0xb9, 0x07,
- 0x03, 0xe9, 0x4d, 0x01, 0x5f, 0x6c, 0xd3, 0x4b, 0x89, 0xae, 0xeb, 0xb1,
- 0x8c, 0x2e, 0x8b, 0x7f, 0x3f, 0xae, 0x41, 0x1f, 0x4e, 0x5f, 0x69, 0xbe,
- 0x6e, 0x5f, 0xe9, 0x85, 0x98, 0x85, 0x0f, 0xdf, 0x3d, 0x4e, 0xb6, 0xf2,
- 0x77, 0x76, 0x8e, 0xc3, 0x71, 0x74, 0x2d, 0x43, 0xe3, 0x2e, 0xf8, 0xc1,
- 0x93, 0x5c, 0xb1, 0x07, 0xfd, 0xc6, 0xf0, 0x0e, 0x82, 0x91, 0x54, 0x26,
- 0xe9, 0x4a, 0x1a, 0xdf, 0x03, 0x98, 0xaf, 0x0e, 0xe0, 0x4f, 0xdc, 0xec,
- 0xe6, 0x94, 0xf4, 0x55, 0x40, 0x7b, 0x95, 0x37, 0x96, 0x14, 0x7a, 0x0c,
- 0xa9, 0x7f, 0xb1, 0xb8, 0x61, 0x3f, 0x7c, 0xbb, 0x32, 0x02, 0xfa, 0x28,
- 0x8c, 0xf9, 0x32, 0x5c, 0x9c, 0xf6, 0x94, 0x24, 0x41, 0xbb, 0x69, 0xe9,
- 0xad, 0xf8, 0x52, 0x28, 0xe2, 0x5d, 0x6a, 0x07, 0xfd, 0xba, 0x92, 0x89,
- 0x9b, 0x39, 0x29, 0x14, 0x7f, 0x09, 0xe3, 0x02, 0x8e, 0x7d, 0xfe, 0xee,
- 0xb1, 0xb0, 0x80, 0xf7, 0xbb, 0x53, 0x1a, 0x3f, 0x6f, 0x0e, 0x06, 0xf6,
- 0x8d, 0x31, 0x60, 0x9c, 0x85, 0xb2, 0x8b, 0x77, 0x0c, 0xef, 0x90, 0x16,
- 0xe3, 0x80, 0xa9, 0x55, 0x86, 0x41, 0x8b, 0xbd, 0x82, 0xdf, 0x53, 0x84,
- 0x91, 0xfd, 0xb6, 0xe8, 0xdf, 0xc3, 0x63, 0x1b, 0xf4, 0x77, 0x6e, 0xa0,
- 0x45, 0xf2, 0x53, 0xe1, 0x58, 0x28, 0x0f, 0x28, 0x03, 0x92, 0x87, 0x45,
- 0x28, 0x13, 0x82, 0xe0, 0xc1, 0x14, 0xe5, 0x42, 0x10, 0x3c, 0x96, 0xa2,
- 0x9c, 0x38, 0x07, 0xfe, 0xa7, 0x6c, 0x20, 0xaf, 0xae, 0x55, 0x9c, 0x83,
- 0x6c, 0x11, 0x7d, 0x40, 0x4e, 0xe4, 0xba, 0x4e, 0x40, 0x6e, 0x50, 0xae,
- 0x5c, 0xf8, 0x44, 0xd6, 0xcf, 0xc7, 0x23, 0x1a, 0x0f, 0x98, 0x6f, 0xc8,
- 0xbc, 0x8c, 0x86, 0xbc, 0x4d, 0x0a, 0x5d, 0xa3, 0xb6, 0xcc, 0x65, 0x5d,
- 0xc6, 0x5d, 0x52, 0xe6, 0x76, 0x65, 0xf8, 0xae, 0x15, 0xf3, 0xb1, 0x42,
- 0x11, 0x4f, 0x6d, 0x9b, 0xf8, 0x2d, 0xd1, 0x9a, 0xf4, 0x97, 0x90, 0x37,
- 0x7d, 0xd7, 0x49, 0x7f, 0xb9, 0xbc, 0x59, 0x77, 0x69, 0xde, 0x88, 0xb8,
- 0x7e, 0xb2, 0x73, 0x97, 0x9a, 0x01, 0x3d, 0x05, 0xc1, 0xc9, 0x54, 0x98,
- 0xfe, 0x8f, 0xee, 0xd2, 0x3e, 0x12, 0x35, 0x4b, 0xd3, 0xee, 0x5d, 0x26,
- 0xed, 0xc4, 0x32, 0x69, 0x1b, 0x6a, 0x97, 0xa6, 0xbd, 0x7f, 0x99, 0xb4,
- 0xfb, 0x97, 0x49, 0xfb, 0x5f, 0xcb, 0xa4, 0x7d, 0x67, 0x99, 0xb4, 0xef,
- 0x2d, 0x93, 0xd6, 0x52, 0xb7, 0x34, 0xcd, 0x05, 0x3f, 0x6d, 0x92, 0x42,
- 0xec, 0x73, 0x1c, 0xbb, 0xc5, 0xcd, 0xfe, 0xc8, 0x52, 0xdc, 0xd4, 0xa0,
- 0x5c, 0xeb, 0xa2, 0x72, 0x53, 0xcb, 0x94, 0xab, 0x45, 0xb9, 0xa6, 0x45,
- 0xe5, 0x92, 0xcb, 0xe0, 0xba, 0x4e, 0xeb, 0xaf, 0x85, 0xe5, 0x0a, 0xcb,
- 0x94, 0x63, 0xfa, 0x1e, 0xdb, 0xcf, 0x16, 0x68, 0x99, 0xd7, 0x9b, 0xaf,
- 0x5a, 0x91, 0x66, 0xa6, 0xb7, 0x42, 0x47, 0xac, 0x50, 0x86, 0xdf, 0x29,
- 0x5b, 0x98, 0xe6, 0x81, 0xee, 0xa3, 0xa0, 0x3b, 0xca, 0x47, 0xf0, 0x91,
- 0x4f, 0xfe, 0x5d, 0x25, 0x43, 0xb1, 0x2d, 0xde, 0x2f, 0xa8, 0x06, 0xd0,
- 0x58, 0xd2, 0x4b, 0x28, 0xf2, 0x97, 0xe4, 0x23, 0x69, 0x3f, 0xdf, 0x2b,
- 0x2a, 0xa6, 0x24, 0x90, 0xbe, 0x94, 0x6a, 0x52, 0xb2, 0x1f, 0xfc, 0x93,
- 0x81, 0x4e, 0xda, 0x15, 0xf4, 0x6a, 0x1e, 0x32, 0x65, 0xaf, 0x2c, 0x2b,
- 0x7d, 0x39, 0x48, 0x19, 0x97, 0xce, 0xdc, 0x95, 0xf5, 0xa7, 0x7b, 0x6a,
- 0x41, 0xb3, 0x17, 0x51, 0x67, 0x07, 0x6a, 0xee, 0x2d, 0xbb, 0xd2, 0x57,
- 0xee, 0x04, 0x2f, 0x38, 0x72, 0xde, 0x5f, 0x2d, 0xe7, 0x53, 0x28, 0x5b,
- 0x89, 0xc8, 0x4c, 0xcc, 0x91, 0x19, 0x7c, 0x67, 0x53, 0xc8, 0xab, 0x84,
- 0xbc, 0xd5, 0x29, 0x07, 0x4a, 0xbe, 0x1c, 0x2e, 0xfd, 0x92, 0x0a, 0xf5,
- 0x56, 0x7f, 0x6a, 0xa5, 0x9c, 0xf6, 0x4c, 0xdb, 0x3b, 0xfc, 0x69, 0x68,
- 0x4c, 0x57, 0x2e, 0xfa, 0xc9, 0xf8, 0x8c, 0xe6, 0x89, 0x1f, 0x06, 0x7d,
- 0x68, 0x67, 0xc2, 0x4f, 0x7a, 0x7f, 0x8a, 0xef, 0xa1, 0x32, 0xed, 0x90,
- 0xf9, 0xb6, 0x86, 0xd1, 0xd6, 0xa1, 0xd2, 0x2a, 0xf9, 0xb0, 0xad, 0xbf,
- 0xdd, 0x9f, 0xee, 0x04, 0xcf, 0x79, 0xa7, 0x28, 0x23, 0x8a, 0x80, 0x6b,
- 0x10, 0xbc, 0x8d, 0xba, 0xcf, 0x69, 0x39, 0x05, 0xbb, 0xa5, 0xb8, 0x1a,
- 0x72, 0xf7, 0x1f, 0x83, 0x0f, 0xc7, 0x58, 0x9e, 0x69, 0xd4, 0x25, 0x32,
- 0xaa, 0xd2, 0x90, 0x09, 0xdd, 0x94, 0x85, 0x09, 0xc8, 0x41, 0xc8, 0x96,
- 0xd2, 0x4f, 0x83, 0x8c, 0x5b, 0x2d, 0xdf, 0x24, 0x3f, 0x5f, 0x86, 0x69,
- 0x09, 0x23, 0x2f, 0x4b, 0xb3, 0x73, 0xb2, 0x22, 0x0f, 0xf9, 0xf2, 0x74,
- 0x85, 0x72, 0xe1, 0x7a, 0xf0, 0x68, 0xab, 0xf4, 0x15, 0x93, 0xf9, 0x8c,
- 0x6c, 0xc2, 0xfc, 0x7d, 0x1e, 0x73, 0xea, 0xe2, 0xb9, 0xaf, 0x5e, 0x1a,
- 0x53, 0xd0, 0xcd, 0x4c, 0x47, 0xa3, 0xcd, 0x51, 0xc8, 0xa8, 0xdf, 0x03,
- 0x1e, 0x86, 0x39, 0xe7, 0xf1, 0x6c, 0xc4, 0x19, 0xa0, 0x3d, 0x32, 0x40,
- 0xfd, 0x50, 0x66, 0xdb, 0x84, 0x37, 0x6e, 0x7f, 0x47, 0xb5, 0x8c, 0x31,
- 0xbf, 0x1b, 0xf0, 0x3b, 0x61, 0x7f, 0x7b, 0xf8, 0xed, 0xdb, 0xdf, 0x31,
- 0xfc, 0xee, 0xb4, 0xbf, 0xa1, 0x5b, 0x8b, 0x5d, 0xfa, 0xf7, 0x48, 0x69,
- 0xfb, 0x76, 0xe5, 0x5f, 0x27, 0xb9, 0xa9, 0x56, 0x39, 0x50, 0xf4, 0xad,
- 0x6c, 0xc1, 0x23, 0x4f, 0x3a, 0x66, 0x9c, 0x80, 0x9b, 0xb2, 0xb3, 0x94,
- 0x77, 0x06, 0x08, 0x3f, 0x68, 0xa0, 0xb7, 0xb8, 0xc5, 0x5b, 0x23, 0xa4,
- 0x81, 0x11, 0xa7, 0xb7, 0xe2, 0x64, 0x60, 0xaf, 0xc5, 0x87, 0xe5, 0x30,
- 0x7e, 0x8b, 0x17, 0x49, 0x3f, 0x89, 0xb7, 0xc1, 0x01, 0xf5, 0xce, 0x70,
- 0x89, 0xf2, 0xd2, 0xc7, 0xd8, 0x13, 0x72, 0x6e, 0x81, 0x0d, 0x45, 0x5c,
- 0x28, 0xc9, 0x8d, 0x25, 0x4f, 0xe4, 0x25, 0x99, 0x1f, 0x07, 0x43, 0xec,
- 0x4a, 0xb9, 0xf2, 0xde, 0x14, 0x68, 0xf7, 0x3a, 0x47, 0xb6, 0x5f, 0xe7,
- 0xc2, 0xe6, 0xf1, 0xc7, 0xb7, 0x83, 0xfe, 0x31, 0xcf, 0x9a, 0x1e, 0xd4,
- 0x19, 0x81, 0x9d, 0x08, 0x6c, 0x9f, 0xe9, 0xea, 0x1b, 0x2e, 0xe6, 0x3e,
- 0xa6, 0xd2, 0xfb, 0x3e, 0x95, 0xed, 0xbe, 0x46, 0x72, 0x83, 0x0a, 0x38,
- 0x6a, 0x1e, 0x82, 0x1e, 0xc4, 0xb8, 0x82, 0x00, 0xf4, 0x0c, 0x79, 0x7e,
- 0xf3, 0xcd, 0x91, 0x74, 0x8d, 0xf4, 0x0e, 0x36, 0xa3, 0x0e, 0xf3, 0x88,
- 0xaf, 0xaf, 0xa2, 0x9d, 0x64, 0xa2, 0x4f, 0xe4, 0x9e, 0x91, 0xee, 0x59,
- 0x67, 0x78, 0xf4, 0x37, 0xc0, 0x93, 0x5b, 0x51, 0xff, 0x01, 0xd4, 0x7f,
- 0xcd, 0x29, 0x8c, 0xfd, 0xc8, 0x19, 0x1e, 0xfb, 0x9e, 0x33, 0x32, 0xb6,
- 0x61, 0x43, 0x7f, 0xcf, 0x86, 0x0d, 0xbb, 0x7b, 0x5c, 0x99, 0x00, 0x8f,
- 0x65, 0xbc, 0x0d, 0x1b, 0x46, 0x7a, 0xba, 0x80, 0x83, 0x2d, 0x5e, 0x9f,
- 0xf8, 0xde, 0x76, 0x01, 0xff, 0xc4, 0xd8, 0x67, 0x14, 0xf9, 0x49, 0xe4,
- 0xb3, 0x7e, 0x5c, 0xe7, 0xf7, 0xca, 0x96, 0x78, 0x93, 0xb0, 0xff, 0x88,
- 0x2d, 0x53, 0x13, 0x91, 0xfa, 0x07, 0xec, 0xfc, 0x66, 0x9c, 0x1a, 0x9f,
- 0xe9, 0x1c, 0x0b, 0xd3, 0x39, 0xb7, 0x7f, 0x67, 0x6d, 0xd5, 0xd5, 0x48,
- 0xe7, 0x37, 0x71, 0x46, 0xbc, 0xd0, 0xc6, 0xa8, 0xd1, 0xb6, 0x61, 0xae,
- 0x48, 0x9a, 0x71, 0x65, 0x4f, 0xd1, 0x41, 0x1d, 0xd0, 0xc5, 0x19, 0xfb,
- 0x1c, 0x05, 0x6c, 0x83, 0x68, 0xeb, 0xe8, 0x21, 0xd4, 0xa3, 0xcc, 0x48,
- 0x76, 0x8a, 0xfa, 0x00, 0xca, 0x6c, 0xf1, 0xd6, 0x0a, 0x6d, 0x89, 0x3b,
- 0x25, 0x57, 0x22, 0x7f, 0x77, 0x00, 0x9e, 0xa8, 0x24, 0x9a, 0xf1, 0x5d,
- 0x81, 0x4d, 0xf1, 0x60, 0x8d, 0x58, 0xdb, 0x45, 0xe6, 0x6d, 0x91, 0x3b,
- 0x94, 0xc0, 0xde, 0x18, 0x9a, 0x5c, 0x8f, 0x72, 0x0e, 0xf0, 0x42, 0xfb,
- 0x03, 0xb4, 0x36, 0x99, 0x91, 0xec, 0x26, 0xf0, 0xc9, 0xa4, 0x87, 0x6f,
- 0xc0, 0x35, 0xf9, 0x16, 0xbc, 0x23, 0xfa, 0xdb, 0xc0, 0x09, 0xbc, 0xa6,
- 0x22, 0x56, 0x67, 0x75, 0xa1, 0xef, 0xf7, 0x48, 0x76, 0x34, 0x4e, 0x5b,
- 0x62, 0x75, 0xd6, 0xcf, 0x40, 0xd7, 0x2b, 0x28, 0x41, 0x8c, 0x61, 0xd2,
- 0x81, 0x3c, 0xa9, 0x95, 0xdd, 0x8f, 0xe0, 0xf7, 0x83, 0xc6, 0xe6, 0xdd,
- 0x3d, 0xc9, 0x7e, 0x1a, 0x00, 0x13, 0x6c, 0x90, 0x47, 0x60, 0x9b, 0x3e,
- 0x02, 0x1b, 0xe4, 0x91, 0x66, 0x3c, 0x1c, 0x1b, 0xdb, 0x9f, 0x59, 0x03,
- 0x31, 0xa9, 0xbf, 0x73, 0xa4, 0x57, 0xd8, 0xea, 0xb9, 0x62, 0xca, 0x94,
- 0x2f, 0x76, 0xeb, 0xb7, 0xa1, 0xeb, 0x1e, 0xfb, 0x3b, 0xae, 0xf9, 0x3a,
- 0xdf, 0x04, 0x9a, 0xaf, 0x74, 0x69, 0x99, 0x93, 0xf5, 0xf1, 0x86, 0xcd,
- 0x99, 0x69, 0xe2, 0x18, 0xe3, 0x36, 0x2d, 0xae, 0xd3, 0x12, 0x4d, 0xd6,
- 0xde, 0x28, 0x59, 0x5b, 0x03, 0xb8, 0x19, 0x6a, 0x06, 0xc4, 0x94, 0xcf,
- 0x12, 0xe2, 0x93, 0x32, 0x00, 0xf4, 0x0b, 0x9b, 0xe2, 0xdc, 0x15, 0xe5,
- 0xdf, 0xac, 0xb6, 0xb1, 0xce, 0x56, 0x48, 0xc7, 0xa4, 0xed, 0x20, 0xb8,
- 0x3f, 0x55, 0x87, 0xf6, 0xc9, 0xf3, 0xb0, 0x40, 0x8e, 0x02, 0x26, 0x60,
- 0xa2, 0xc6, 0x3f, 0xab, 0x69, 0xa0, 0xd6, 0x27, 0x0d, 0x57, 0xf3, 0x97,
- 0xe8, 0xf1, 0x9e, 0x05, 0x8f, 0xc1, 0xbe, 0x81, 0xfd, 0xd6, 0x01, 0xdb,
- 0x98, 0x7d, 0x1c, 0xe6, 0xb7, 0xa7, 0xc0, 0x53, 0xd9, 0x39, 0x9e, 0x12,
- 0x99, 0x28, 0x12, 0x37, 0xa1, 0x5d, 0xc7, 0x79, 0x26, 0x7e, 0x32, 0x18,
- 0x33, 0xdf, 0x7d, 0x16, 0x4f, 0x3b, 0x2d, 0x9e, 0x6e, 0xb2, 0xef, 0x11,
- 0xbc, 0x69, 0xe3, 0x0d, 0xe0, 0xcd, 0xf9, 0x19, 0xc4, 0x9b, 0xbc, 0x75,
- 0x0b, 0xde, 0x28, 0x5b, 0xca, 0xc8, 0x6e, 0x6d, 0x87, 0x45, 0xe4, 0x57,
- 0xb4, 0x6c, 0xfb, 0x02, 0xe6, 0xb2, 0x48, 0xfa, 0x95, 0x7c, 0x2c, 0x02,
- 0x9c, 0x14, 0xf0, 0xfb, 0x4e, 0xd7, 0xd0, 0x2a, 0x71, 0xb2, 0xc0, 0x57,
- 0xaa, 0x82, 0x29, 0x66, 0xe5, 0x5c, 0x42, 0xdb, 0xfa, 0xb9, 0xe2, 0x07,
- 0x34, 0x5c, 0xb7, 0x42, 0xde, 0xe5, 0x45, 0x35, 0x43, 0x37, 0x80, 0x16,
- 0x54, 0x0c, 0x9a, 0x2b, 0x78, 0x06, 0x7a, 0x29, 0x37, 0x49, 0xdb, 0xb8,
- 0x8d, 0x7e, 0x49, 0x34, 0xd7, 0xd5, 0x48, 0x3a, 0x52, 0x0a, 0xf6, 0x17,
- 0xbe, 0x55, 0xae, 0x4b, 0xd3, 0xa9, 0xa3, 0xfc, 0x98, 0xb6, 0x7f, 0x5d,
- 0x1f, 0xd2, 0xd6, 0xf8, 0xbd, 0xae, 0xf2, 0xd7, 0x2e, 0x4e, 0x4b, 0x50,
- 0x0f, 0xa3, 0x5e, 0x22, 0xd7, 0xd5, 0x4c, 0x1e, 0xf3, 0x40, 0xbf, 0x19,
- 0xe5, 0x6b, 0xdf, 0x27, 0xaf, 0xba, 0x57, 0x2f, 0x2a, 0xaf, 0xdf, 0x8e,
- 0xfd, 0x76, 0xed, 0xdb, 0xb3, 0xef, 0x84, 0x7d, 0xe7, 0xdd, 0x6e, 0xbe,
- 0x1d, 0x71, 0xd3, 0x7c, 0x83, 0x92, 0xd3, 0x6c, 0x43, 0xf3, 0x95, 0x95,
- 0x33, 0x1d, 0x5e, 0x41, 0xc8, 0x57, 0x9f, 0x93, 0x5b, 0x27, 0x8d, 0xfc,
- 0xdd, 0x0e, 0x19, 0x04, 0xff, 0xcc, 0x9b, 0x11, 0xc0, 0x3f, 0x98, 0x96,
- 0x5b, 0x2b, 0xc4, 0xdb, 0xef, 0x02, 0x7f, 0x60, 0xe2, 0x7a, 0xea, 0x74,
- 0xca, 0xdd, 0x3b, 0x61, 0xf7, 0xa2, 0x7c, 0x91, 0x38, 0x1f, 0xd2, 0x73,
- 0x53, 0x28, 0xee, 0xd1, 0x73, 0x73, 0xb0, 0x38, 0x03, 0xfc, 0xdc, 0x06,
- 0xba, 0x0f, 0x82, 0x99, 0x54, 0x01, 0x94, 0xf3, 0x11, 0xfc, 0x86, 0x1d,
- 0x50, 0xfc, 0x18, 0xf2, 0x1b, 0xa5, 0x30, 0x4a, 0x9e, 0x73, 0x2d, 0x0f,
- 0xbf, 0x13, 0xfc, 0x14, 0x45, 0xbb, 0x48, 0xeb, 0xe6, 0xef, 0x9f, 0x20,
- 0x0f, 0xef, 0x49, 0x4c, 0x62, 0x33, 0x6d, 0x1d, 0xf6, 0xcd, 0xb9, 0xe3,
- 0x9c, 0xc5, 0xb4, 0x2c, 0x3f, 0x3b, 0x37, 0x6f, 0x97, 0xe7, 0xe8, 0x36,
- 0x4f, 0x1f, 0x8f, 0xf9, 0x1a, 0x56, 0xd2, 0xfd, 0xb7, 0xb4, 0x5c, 0x72,
- 0x8f, 0xce, 0xac, 0x30, 0xef, 0xc5, 0x75, 0x39, 0xe7, 0xd5, 0x34, 0x48,
- 0xbf, 0x25, 0xd9, 0x93, 0x07, 0x3f, 0x61, 0x9c, 0xd2, 0xa7, 0x7d, 0x1d,
- 0xd2, 0x04, 0x69, 0x60, 0xdc, 0xd2, 0xe6, 0x94, 0xa5, 0xcd, 0x27, 0xf1,
- 0xc6, 0x53, 0xba, 0x60, 0x69, 0xf3, 0x29, 0xbc, 0xf1, 0x94, 0x5e, 0x9c,
- 0xe3, 0xe3, 0x5e, 0xf8, 0x72, 0xdb, 0xa1, 0xdf, 0x76, 0x57, 0x40, 0xbf,
- 0xe0, 0xbb, 0x1c, 0x7c, 0x80, 0x5c, 0x69, 0x1f, 0xde, 0xec, 0x67, 0xa3,
- 0x6d, 0x3f, 0x23, 0x7b, 0x4a, 0x01, 0xc6, 0x78, 0x37, 0xc6, 0xfb, 0x39,
- 0xbc, 0x3f, 0xa3, 0xe5, 0x8c, 0xf2, 0x0f, 0x5b, 0x79, 0xf5, 0x79, 0xbc,
- 0xdb, 0xe3, 0x07, 0xa5, 0xdd, 0x8b, 0xc8, 0x34, 0xda, 0xfa, 0xba, 0xec,
- 0xa9, 0xcc, 0xe2, 0xb9, 0x84, 0xe7, 0x55, 0x3c, 0x97, 0xd1, 0xde, 0x0b,
- 0x48, 0x5f, 0x29, 0xd3, 0x5e, 0x3d, 0xca, 0xbf, 0x86, 0xdf, 0xcf, 0xcb,
- 0xd0, 0x23, 0x2f, 0xe1, 0xf9, 0x01, 0xf2, 0x9f, 0x45, 0xfd, 0x60, 0xf5,
- 0x8c, 0x4f, 0x19, 0xf6, 0x9c, 0x6d, 0x3b, 0xe5, 0xe4, 0x2a, 0xa0, 0xe9,
- 0xd2, 0x00, 0xfa, 0xde, 0xa3, 0x79, 0xa6, 0x0f, 0x32, 0x3f, 0x07, 0x19,
- 0x37, 0xa4, 0x61, 0x6a, 0x07, 0x7c, 0x79, 0xcc, 0x05, 0xde, 0x93, 0xb5,
- 0x32, 0x1b, 0xa3, 0x1d, 0x79, 0x93, 0x2e, 0x9f, 0x2b, 0x35, 0x69, 0xbb,
- 0x7a, 0x7c, 0x09, 0xff, 0xd0, 0xef, 0x0a, 0xe5, 0x81, 0x91, 0xc6, 0x13,
- 0x45, 0xca, 0x02, 0xe8, 0x9f, 0xe2, 0x08, 0xde, 0xb5, 0x5a, 0x26, 0x14,
- 0x24, 0x94, 0x07, 0xac, 0x47, 0x99, 0x50, 0x2d, 0x77, 0x28, 0x6b, 0x28,
- 0x7b, 0x28, 0x4b, 0xcc, 0x7c, 0xec, 0x7e, 0x90, 0x32, 0x1c, 0xb4, 0x10,
- 0xa3, 0xfd, 0xe1, 0x19, 0x1f, 0x64, 0xec, 0x3e, 0x2b, 0x4f, 0x47, 0xf5,
- 0x5c, 0xec, 0x29, 0xaa, 0x98, 0x2b, 0xa7, 0x91, 0x86, 0xe7, 0xf8, 0xc3,
- 0x78, 0x7f, 0x49, 0xf6, 0xe0, 0xc9, 0x1d, 0xff, 0x02, 0x7e, 0x73, 0x6e,
- 0xca, 0x28, 0x87, 0xa7, 0x74, 0x02, 0x6f, 0x3c, 0xa5, 0x31, 0x2b, 0x47,
- 0xc6, 0xad, 0x1c, 0xe1, 0x9c, 0xde, 0x04, 0x3c, 0x70, 0x7c, 0x4a, 0xc7,
- 0x17, 0xc0, 0xcf, 0x4e, 0x6e, 0xf2, 0x5d, 0xd6, 0x8f, 0x6d, 0x14, 0xc3,
- 0x83, 0x78, 0x3a, 0xc9, 0xcf, 0x0d, 0xda, 0x0e, 0xce, 0x69, 0xda, 0xfd,
- 0x2b, 0xd7, 0xf0, 0x62, 0xcc, 0xe8, 0x14, 0xaf, 0x59, 0x34, 0xef, 0xcf,
- 0xe1, 0x31, 0x63, 0xf1, 0xc8, 0xdf, 0xca, 0xfe, 0x86, 0xdc, 0x82, 0x4d,
- 0x9b, 0xf5, 0x7d, 0xcc, 0x03, 0xc6, 0x72, 0x7c, 0x14, 0x7d, 0x3b, 0xb2,
- 0xdb, 0xa7, 0x0c, 0x67, 0x0c, 0x81, 0xe3, 0x63, 0xbb, 0x48, 0xd7, 0x38,
- 0x48, 0xc9, 0xbc, 0x6f, 0x7e, 0x13, 0xe6, 0x2c, 0x23, 0x7b, 0x4b, 0xf7,
- 0x6a, 0x5f, 0xb9, 0xf6, 0x68, 0x93, 0xf5, 0x73, 0xc2, 0x72, 0xa0, 0xd5,
- 0x18, 0x6d, 0x9b, 0x2f, 0xc5, 0x0c, 0xcd, 0xf3, 0x37, 0xe5, 0x73, 0xb5,
- 0xbc, 0x37, 0x76, 0x4d, 0x61, 0x81, 0xac, 0xa3, 0x6d, 0x81, 0x39, 0x2b,
- 0x57, 0xe3, 0x9d, 0xbe, 0x3b, 0xf9, 0x8a, 0xfc, 0x74, 0x10, 0x3c, 0xf1,
- 0x5d, 0xcb, 0xfb, 0xf4, 0x35, 0xd8, 0xe7, 0x62, 0x7e, 0xf2, 0x60, 0xfb,
- 0xba, 0x72, 0x0a, 0xb6, 0xdb, 0xf6, 0xb9, 0x36, 0xae, 0x06, 0x3c, 0x51,
- 0x79, 0xa4, 0xd8, 0x20, 0x93, 0x45, 0xd5, 0x1c, 0xb1, 0xb2, 0x33, 0x22,
- 0x09, 0x4d, 0xdf, 0xb4, 0xef, 0x7a, 0xc7, 0x22, 0x96, 0xee, 0xd6, 0xd5,
- 0x48, 0xfd, 0xef, 0x42, 0xc7, 0xa6, 0xa1, 0x63, 0x1b, 0xa1, 0x83, 0x17,
- 0xcb, 0x88, 0x35, 0x35, 0x4b, 0x65, 0x04, 0xeb, 0x24, 0xe1, 0x75, 0x1f,
- 0x44, 0xbd, 0x90, 0xfe, 0xa2, 0x9a, 0xd6, 0x72, 0x92, 0x77, 0xb6, 0x57,
- 0x46, 0x9c, 0x1d, 0x95, 0xc5, 0x3a, 0x68, 0x8b, 0xe7, 0x8a, 0x81, 0xf5,
- 0x91, 0x22, 0x6d, 0xd4, 0x64, 0x2a, 0x0b, 0x9c, 0xec, 0x00, 0xcc, 0xcf,
- 0x8c, 0xc2, 0x4f, 0xa7, 0x5c, 0x06, 0xcc, 0xa7, 0x01, 0xf3, 0xc4, 0xa8,
- 0x13, 0xda, 0x06, 0xc2, 0xa0, 0xc8, 0xc4, 0x58, 0x97, 0xcc, 0x4c, 0x91,
- 0x0e, 0x21, 0x03, 0x46, 0x31, 0x9f, 0xa9, 0x15, 0xb0, 0x03, 0xd8, 0x3f,
- 0xe4, 0xf6, 0x58, 0x8b, 0xce, 0x33, 0xfa, 0xbc, 0x55, 0x66, 0xca, 0x69,
- 0x0b, 0xdb, 0xe1, 0x2a, 0xd8, 0x56, 0xcc, 0xc1, 0xb6, 0x03, 0xb0, 0xed,
- 0x5c, 0x16, 0xb6, 0xe5, 0x74, 0x71, 0x1b, 0x6c, 0x1a, 0xa3, 0x8b, 0x0d,
- 0x5e, 0x9b, 0x2d, 0x3d, 0xbc, 0xdf, 0xda, 0xbb, 0xb4, 0x89, 0x7e, 0x0a,
- 0x78, 0x48, 0x63, 0xf8, 0x3d, 0x79, 0x2f, 0x65, 0x19, 0xd2, 0xf9, 0xbd,
- 0x07, 0x65, 0xf0, 0x3d, 0xf9, 0x67, 0x2b, 0x4c, 0xd9, 0xbb, 0x2d, 0x2c,
- 0xb4, 0x13, 0x32, 0xb0, 0x89, 0xfb, 0x9c, 0xec, 0x24, 0x61, 0xf8, 0x8f,
- 0x80, 0x17, 0x79, 0x95, 0xea, 0x36, 0xf9, 0x66, 0xbb, 0xd7, 0xda, 0x76,
- 0xd8, 0x76, 0x38, 0x96, 0x95, 0x56, 0xcf, 0x87, 0xf4, 0x15, 0xda, 0xd7,
- 0x23, 0x4e, 0x66, 0xc9, 0xb8, 0xaa, 0x69, 0x8e, 0xf2, 0xd6, 0x95, 0x7e,
- 0xd0, 0x49, 0xff, 0x02, 0x5a, 0x33, 0x72, 0xc3, 0xd0, 0xf1, 0x0a, 0x3b,
- 0xbe, 0x1a, 0xc3, 0x37, 0xa9, 0x28, 0xf4, 0x21, 0xe5, 0xcd, 0x0e, 0xe3,
- 0x9b, 0xcb, 0x43, 0x80, 0x35, 0xfc, 0x3e, 0xa8, 0x6d, 0xce, 0xa7, 0x4b,
- 0x94, 0x49, 0xf3, 0xb4, 0x68, 0x7c, 0x97, 0x56, 0xf4, 0x55, 0x6d, 0xaf,
- 0xbb, 0x32, 0x60, 0xe6, 0xfc, 0x30, 0xe7, 0x9c, 0xbe, 0x48, 0xfb, 0x03,
- 0x03, 0x96, 0xbf, 0x92, 0xa3, 0x79, 0x79, 0xbb, 0x1d, 0xfb, 0x1f, 0x2e,
- 0x33, 0x77, 0x8d, 0x73, 0x73, 0x37, 0x50, 0x59, 0x3c, 0x46, 0x91, 0xb6,
- 0x07, 0x58, 0xcf, 0x85, 0x8d, 0x94, 0x92, 0x5a, 0x9f, 0xf2, 0x93, 0xb6,
- 0x12, 0xd2, 0x27, 0xb6, 0x78, 0x4d, 0xf0, 0x01, 0x9e, 0x5e, 0x62, 0x77,
- 0x25, 0xac, 0xdc, 0xa4, 0x1f, 0x1c, 0xf6, 0x91, 0xb7, 0x72, 0x32, 0x8f,
- 0xf6, 0x47, 0x9c, 0xfe, 0xca, 0x72, 0xf2, 0x32, 0x94, 0x93, 0x1c, 0x8f,
- 0x23, 0x77, 0x3c, 0x48, 0x1e, 0x7d, 0xbf, 0xb6, 0xaf, 0xb7, 0x6e, 0xab,
- 0x01, 0xfe, 0x08, 0xc7, 0xcc, 0x1a, 0xa2, 0x33, 0xf7, 0x08, 0x6c, 0x22,
- 0x3b, 0x6f, 0xbb, 0xe7, 0xe6, 0x5f, 0xd3, 0x05, 0x7e, 0x33, 0x8e, 0x6a,
- 0x68, 0xa4, 0xc6, 0x77, 0x34, 0x2d, 0xd4, 0x2e, 0xb1, 0x65, 0x39, 0x06,
- 0xda, 0xb3, 0xb5, 0xc6, 0x16, 0x2c, 0xd1, 0xfe, 0xa4, 0xec, 0xa2, 0xfd,
- 0xf9, 0x43, 0xe0, 0x88, 0xe3, 0xe9, 0xb2, 0x69, 0xb4, 0x53, 0x17, 0x8f,
- 0x6f, 0xb1, 0xff, 0x48, 0x38, 0x09, 0xb7, 0xa1, 0xad, 0x84, 0x22, 0x6c,
- 0x81, 0x0c, 0x80, 0x97, 0x39, 0x07, 0x8a, 0xb6, 0xeb, 0xb6, 0xbf, 0xa8,
- 0x31, 0x31, 0xe4, 0xd5, 0xb5, 0x52, 0xcf, 0x3e, 0xc9, 0x7f, 0x7c, 0xaf,
- 0xd2, 0xf6, 0xef, 0x52, 0x59, 0x56, 0xad, 0x7b, 0xae, 0x9e, 0xc3, 0x5f,
- 0xff, 0x82, 0x39, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x35, 0x0e, 0x49, 0x13,
- 0x86, 0x16, 0x0c, 0x2d, 0x6e, 0xb4, 0xfa, 0x26, 0xa4, 0xbd, 0xab, 0x40,
- 0x7b, 0xf7, 0x81, 0xc6, 0x28, 0xc3, 0x19, 0x97, 0x5b, 0x8b, 0xef, 0x23,
- 0xf8, 0x0e, 0xf9, 0xe4, 0x4a, 0x32, 0x9c, 0xf2, 0x9b, 0x75, 0xb2, 0x56,
- 0xee, 0x87, 0x7e, 0x2e, 0xeb, 0x70, 0xdc, 0x94, 0xff, 0xff, 0x15, 0xed,
- 0xac, 0xad, 0x35, 0xf6, 0xca, 0x8d, 0xb5, 0x94, 0xaf, 0x6b, 0xe4, 0x60,
- 0x55, 0xda, 0x95, 0xe4, 0x77, 0xf5, 0x98, 0xd7, 0xff, 0x3f, 0x18, 0x73,
- 0x7c, 0xd1, 0x98, 0x3d, 0x3b, 0xe6, 0x77, 0x21, 0xbf, 0xc9, 0xf8, 0x38,
- 0x1e, 0xf9, 0x2e, 0x1c, 0xb3, 0xc5, 0x85, 0x1e, 0x57, 0xb5, 0x9c, 0x08,
- 0x65, 0x04, 0xc7, 0x35, 0x60, 0xc7, 0xf0, 0xb9, 0xaa, 0x71, 0x0d, 0xbc,
- 0x89, 0x71, 0xb5, 0x2e, 0x18, 0xd7, 0xf6, 0x2b, 0x8e, 0x6b, 0x39, 0x1e,
- 0x27, 0x2f, 0x87, 0xe3, 0x8b, 0xca, 0xae, 0x22, 0xc7, 0xd8, 0x8f, 0x31,
- 0x1e, 0xd4, 0xfe, 0x80, 0x19, 0x63, 0xda, 0x8e, 0x51, 0x54, 0xdb, 0xb6,
- 0x7f, 0x8f, 0xdf, 0xd5, 0xe3, 0xa3, 0xee, 0xff, 0x3e, 0x68, 0xba, 0x4e,
- 0xb2, 0x5d, 0x75, 0x56, 0xfe, 0xdf, 0x24, 0x1f, 0x2e, 0x71, 0xae, 0x93,
- 0x19, 0x91, 0x51, 0xe8, 0xe0, 0xff, 0x5c, 0xcb, 0xd8, 0xfd, 0xf6, 0x94,
- 0xd5, 0x63, 0xd0, 0x17, 0x3b, 0x60, 0xf3, 0xf5, 0x17, 0x55, 0x77, 0x44,
- 0x82, 0xe0, 0xb6, 0xd4, 0xa7, 0xd1, 0xf7, 0x7e, 0xed, 0xab, 0x2e, 0x8d,
- 0x9b, 0x3f, 0x57, 0x2b, 0x3e, 0xed, 0x0d, 0xea, 0x73, 0xe8, 0xbb, 0xe3,
- 0xb4, 0xc1, 0xb2, 0xb0, 0x93, 0x33, 0xf1, 0x88, 0xb6, 0xc5, 0xa8, 0x13,
- 0x93, 0xf1, 0x8c, 0xa4, 0xd1, 0x5f, 0x26, 0xae, 0x84, 0x7d, 0xc0, 0x56,
- 0x83, 0x0d, 0xf9, 0xe1, 0xca, 0x3e, 0x3c, 0x0f, 0xcb, 0xad, 0xb0, 0x77,
- 0x6e, 0x7d, 0xe4, 0x0b, 0x72, 0x1b, 0x6c, 0x9d, 0xdb, 0x1e, 0x19, 0x93,
- 0xbd, 0xb0, 0x6d, 0xf6, 0xc2, 0xce, 0xd9, 0x5b, 0xa1, 0xed, 0x39, 0x8e,
- 0xb2, 0xad, 0x55, 0xb4, 0x46, 0x1b, 0x87, 0xe3, 0x23, 0xee, 0x0f, 0x72,
- 0x0e, 0x52, 0x09, 0xf5, 0x8a, 0x9e, 0x97, 0xa6, 0x05, 0x69, 0xaf, 0x27,
- 0xab, 0x42, 0xfd, 0xb4, 0xca, 0xc6, 0x8d, 0x8c, 0x0d, 0x78, 0x65, 0xda,
- 0x22, 0x8d, 0x78, 0xc0, 0x33, 0xf1, 0x47, 0xda, 0xaa, 0x1e, 0x7f, 0x63,
- 0x9d, 0xf8, 0x2b, 0xeb, 0xa4, 0xfe, 0x73, 0x90, 0xaf, 0xd5, 0x34, 0xc5,
- 0xb7, 0x67, 0x75, 0x0d, 0x69, 0x8b, 0x32, 0x38, 0xa4, 0x87, 0x8d, 0xaf,
- 0x23, 0x7f, 0xaf, 0x48, 0x4f, 0xfb, 0xb9, 0x2e, 0xb3, 0xbb, 0x5b, 0x56,
- 0x33, 0x1e, 0x90, 0xad, 0xcc, 0xc7, 0x04, 0x94, 0x5f, 0x1d, 0x13, 0xa0,
- 0x9f, 0xf5, 0x01, 0xe0, 0xec, 0x16, 0x3c, 0xfb, 0x64, 0x88, 0x71, 0x87,
- 0x4a, 0x68, 0x97, 0x7f, 0xd5, 0xda, 0xe5, 0x21, 0x1c, 0x09, 0xc0, 0x61,
- 0xe4, 0xf3, 0x52, 0x3d, 0xb7, 0x50, 0x7f, 0xe7, 0xe7, 0x6c, 0xda, 0x84,
- 0xec, 0x2a, 0x71, 0xdc, 0x94, 0xc1, 0xc4, 0x4d, 0xb5, 0x0c, 0x8e, 0x5b,
- 0x3b, 0x0a, 0x65, 0xb4, 0xfc, 0x5c, 0x2a, 0x3b, 0x29, 0xf7, 0x18, 0x9f,
- 0x7f, 0x20, 0x45, 0x5a, 0x7f, 0xb7, 0x64, 0xe6, 0xe2, 0xf3, 0x02, 0x7a,
- 0x93, 0x54, 0x24, 0xad, 0xd7, 0xd3, 0xbc, 0x09, 0xd9, 0x21, 0xbd, 0x31,
- 0xc6, 0x3a, 0x19, 0xcf, 0xf3, 0xf3, 0x13, 0xb0, 0x1f, 0x86, 0x4b, 0x0a,
- 0x16, 0x7c, 0xad, 0x0c, 0x79, 0x81, 0x6c, 0x4f, 0x39, 0x3a, 0x76, 0x6c,
- 0x74, 0x6d, 0xa9, 0xce, 0xd8, 0xae, 0x8e, 0x8e, 0xff, 0xce, 0x80, 0xfa,
- 0x66, 0xb4, 0x7d, 0xab, 0xb4, 0xfe, 0x9d, 0xd6, 0x65, 0x46, 0xeb, 0xc2,
- 0x38, 0xe6, 0x8c, 0x17, 0xb1, 0xe5, 0xaa, 0xd3, 0xa7, 0xea, 0x42, 0x5b,
- 0xb0, 0x50, 0x09, 0xd3, 0x9e, 0x5c, 0x26, 0xed, 0x85, 0x65, 0xd2, 0xfe,
- 0x76, 0x99, 0x34, 0x13, 0x17, 0xec, 0x2f, 0x5e, 0x46, 0xde, 0x88, 0xe6,
- 0x55, 0x69, 0x36, 0xf6, 0x75, 0x7e, 0xae, 0xcc, 0x2a, 0xeb, 0x97, 0x31,
- 0x46, 0x6c, 0x62, 0xc3, 0x39, 0x1d, 0x1b, 0xde, 0xe2, 0x6d, 0x53, 0x8c,
- 0x75, 0x11, 0x17, 0x09, 0xd9, 0xab, 0xf1, 0x42, 0x9c, 0x7c, 0x85, 0x31,
- 0xe0, 0x3c, 0xd7, 0x5a, 0x13, 0xea, 0x4a, 0xb4, 0x3d, 0x6f, 0x9b, 0x98,
- 0x79, 0x8b, 0xe9, 0x75, 0xd5, 0x3e, 0xd8, 0x0a, 0xfd, 0xc5, 0x26, 0xd9,
- 0x3e, 0x96, 0x58, 0x41, 0xbd, 0xb5, 0x63, 0xcc, 0xf8, 0x83, 0x7b, 0xc1,
- 0x57, 0x19, 0x21, 0x8c, 0xc9, 0x94, 0x08, 0x6d, 0xe2, 0xa5, 0xb6, 0xf0,
- 0xeb, 0xb7, 0xd7, 0x7b, 0x85, 0xf6, 0x1c, 0xd8, 0x0e, 0x3f, 0x6b, 0x7b,
- 0xf5, 0xd2, 0x37, 0x16, 0xe2, 0x4a, 0xfd, 0x9c, 0xf5, 0x22, 0x57, 0xa8,
- 0xa7, 0xed, 0x12, 0x79, 0x66, 0x4e, 0x16, 0x6f, 0x84, 0xcd, 0x24, 0x41,
- 0xb6, 0x5b, 0x5a, 0x23, 0xa2, 0x63, 0x3c, 0x29, 0x23, 0x9b, 0x3b, 0xb8,
- 0xb6, 0x03, 0xfa, 0x37, 0xb6, 0x8a, 0x89, 0x9b, 0x86, 0x76, 0xca, 0x72,
- 0xb4, 0x7b, 0xbd, 0xa5, 0x5d, 0xae, 0xa9, 0xee, 0xa0, 0xcc, 0xc5, 0x9c,
- 0x18, 0x3a, 0xde, 0x5e, 0x94, 0x44, 0x48, 0xc7, 0x33, 0xf0, 0x8b, 0xab,
- 0xe9, 0x78, 0x46, 0x52, 0x9a, 0x8e, 0x6b, 0x17, 0xd0, 0x71, 0xab, 0xa5,
- 0xe3, 0x77, 0x44, 0x0d, 0x5d, 0x28, 0xad, 0xa7, 0x48, 0xa7, 0x86, 0x8e,
- 0x1d, 0x4d, 0xc7, 0x33, 0x78, 0xbb, 0x7e, 0x8f, 0x2d, 0x13, 0xb1, 0x69,
- 0xfc, 0x1d, 0xa6, 0x51, 0x2e, 0xfe, 0x66, 0xd4, 0xe8, 0xa5, 0x14, 0xe8,
- 0x28, 0x4c, 0xff, 0x60, 0xd4, 0xd0, 0x67, 0x75, 0x9a, 0x89, 0x8f, 0xf4,
- 0x17, 0xdf, 0x13, 0x5d, 0x48, 0x9f, 0x29, 0xd0, 0x67, 0x58, 0xe6, 0xf5,
- 0xe8, 0xb3, 0xde, 0xae, 0x5b, 0x44, 0xf5, 0xba, 0x7b, 0x26, 0x66, 0x68,
- 0xf5, 0x56, 0x3d, 0x76, 0x8e, 0xfb, 0xd9, 0x9f, 0x81, 0x56, 0xcd, 0xdc,
- 0x9c, 0x9f, 0xf7, 0xb7, 0x19, 0x8b, 0x4a, 0x98, 0x18, 0x36, 0xe3, 0xa4,
- 0x57, 0xb2, 0x1d, 0x8d, 0x7c, 0xaa, 0xd1, 0xf2, 0xa9, 0x71, 0x48, 0xa5,
- 0xab, 0x65, 0x76, 0x37, 0x74, 0x05, 0x6d, 0x6c, 0x2d, 0xa7, 0x91, 0xd7,
- 0x9a, 0xc8, 0x16, 0xff, 0xd9, 0xee, 0x5f, 0xe0, 0xba, 0x80, 0x0c, 0x39,
- 0x48, 0x6b, 0x2b, 0x9b, 0x71, 0x29, 0xbf, 0x11, 0xdf, 0xdd, 0xd2, 0x56,
- 0x56, 0x72, 0xfb, 0x58, 0x83, 0xec, 0x2b, 0xba, 0xf2, 0x51, 0xd4, 0xff,
- 0x48, 0xd1, 0x83, 0x3f, 0x3e, 0x1e, 0xa5, 0x5d, 0xb8, 0xb7, 0xc8, 0xf5,
- 0x49, 0xc7, 0xac, 0x19, 0x2d, 0x58, 0xf3, 0x8c, 0x48, 0x5b, 0x47, 0x01,
- 0x9e, 0x8a, 0xb8, 0x3b, 0x01, 0x47, 0x5d, 0x3a, 0x2d, 0xaf, 0x74, 0x0f,
- 0x38, 0xda, 0x97, 0x70, 0x7a, 0xe4, 0xc6, 0x4a, 0x5a, 0x6e, 0xa8, 0x98,
- 0x75, 0xd2, 0xf9, 0x75, 0xd0, 0xa4, 0x37, 0x0d, 0x9d, 0x93, 0xf1, 0x82,
- 0xe0, 0x3c, 0xe4, 0xb7, 0x3a, 0xe2, 0x4a, 0xb4, 0x23, 0x19, 0x9f, 0x16,
- 0xf3, 0x7d, 0xb1, 0xfc, 0xe3, 0x60, 0x28, 0xe6, 0xca, 0x2b, 0x3e, 0xc7,
- 0xd5, 0x23, 0xd7, 0x97, 0xab, 0xfb, 0xe3, 0x5a, 0xe9, 0x13, 0x51, 0xae,
- 0x4d, 0x64, 0x2b, 0xe5, 0x28, 0xe3, 0xe7, 0x22, 0x79, 0x69, 0x7b, 0x2b,
- 0x7c, 0x37, 0x48, 0xeb, 0xb6, 0xb7, 0x82, 0x56, 0x62, 0xd0, 0xf3, 0x5b,
- 0x01, 0xd7, 0x56, 0xc6, 0xbb, 0x18, 0xe7, 0xe2, 0xf7, 0x5f, 0xa2, 0x5f,
- 0xd6, 0xfd, 0x5d, 0xbd, 0x66, 0x25, 0x8a, 0x73, 0x6e, 0xf8, 0x65, 0x79,
- 0x5d, 0xd3, 0x38, 0x14, 0x4d, 0x8b, 0x13, 0x7d, 0x5b, 0x5c, 0x56, 0xf8,
- 0xd5, 0xfd, 0x73, 0xed, 0x57, 0x14, 0x70, 0xe8, 0xee, 0xd8, 0xdc, 0x23,
- 0x7d, 0x18, 0x5f, 0xff, 0x92, 0xf1, 0xed, 0x17, 0xc6, 0x54, 0x2f, 0x16,
- 0x39, 0x86, 0xf9, 0x71, 0xa9, 0x3f, 0x32, 0xe3, 0x8a, 0x76, 0x2c, 0x1e,
- 0x8f, 0xae, 0xaf, 0x4e, 0x01, 0x96, 0xe7, 0xf4, 0x1e, 0x81, 0x20, 0xb8,
- 0xa6, 0xe3, 0x62, 0x90, 0x58, 0x97, 0xec, 0x9c, 0x9e, 0x5f, 0xd3, 0x19,
- 0x8a, 0xa4, 0x33, 0x1a, 0xff, 0xf8, 0x4e, 0xe4, 0xca, 0xdd, 0x98, 0x3b,
- 0x71, 0x73, 0x5d, 0xae, 0xe6, 0x8d, 0x9c, 0xdf, 0x6d, 0xd7, 0xad, 0x42,
- 0xbf, 0x29, 0x08, 0x94, 0xbf, 0x58, 0x56, 0x50, 0x47, 0x61, 0xec, 0xb2,
- 0xdb, 0xee, 0x4b, 0x49, 0x31, 0x6e, 0x38, 0xe4, 0xa6, 0xa3, 0x89, 0x42,
- 0xb9, 0x0b, 0xbf, 0x1b, 0xf0, 0xfe, 0x45, 0xd8, 0x28, 0x3d, 0xb0, 0x61,
- 0x24, 0xa6, 0x8c, 0x3c, 0x00, 0xfd, 0x76, 0xe4, 0x95, 0x22, 0x3f, 0x7a,
- 0x89, 0xe1, 0x72, 0x2c, 0x31, 0x5a, 0xde, 0xcb, 0xfa, 0x28, 0x7b, 0xa5,
- 0xf8, 0x1d, 0xfb, 0x62, 0x1f, 0xf4, 0x79, 0x7f, 0x96, 0x3e, 0x5c, 0xdb,
- 0x36, 0xdb, 0x0c, 0xf1, 0xe2, 0xd2, 0x0d, 0xc7, 0xbf, 0x6e, 0xeb, 0x8f,
- 0x70, 0x7c, 0x7b, 0x2d, 0xdc, 0x8b, 0xfb, 0x7d, 0x49, 0xdb, 0x2c, 0x8f,
- 0x55, 0x68, 0x27, 0x72, 0x4d, 0x27, 0x79, 0x62, 0x5c, 0x08, 0x47, 0x10,
- 0x5c, 0x48, 0x19, 0x7d, 0xfd, 0x74, 0x85, 0xeb, 0x1a, 0x41, 0xf0, 0x5d,
- 0xda, 0xc2, 0x83, 0x25, 0xf4, 0x17, 0xe2, 0x60, 0x63, 0xde, 0x85, 0x2c,
- 0x1c, 0xe9, 0x26, 0x7e, 0x05, 0x5e, 0x69, 0x87, 0xb7, 0x4b, 0xa2, 0x89,
- 0xdf, 0x2e, 0x37, 0x24, 0x3e, 0x51, 0xf6, 0x80, 0x67, 0x8e, 0x3b, 0x96,
- 0xd8, 0x63, 0xc7, 0xcc, 0xfd, 0x20, 0xaf, 0xbf, 0x4f, 0xe3, 0xa5, 0x05,
- 0x3e, 0x12, 0x61, 0x9a, 0x87, 0x85, 0xb0, 0x25, 0x2c, 0x6e, 0x82, 0xe0,
- 0xfb, 0x29, 0xf6, 0xd9, 0xcd, 0xfd, 0x00, 0x23, 0xe8, 0x37, 0xbf, 0x56,
- 0x11, 0x0f, 0xd1, 0xc4, 0x1d, 0xe8, 0xfb, 0xb7, 0xd1, 0xf7, 0xbe, 0x32,
- 0xfb, 0x83, 0x7c, 0xc0, 0xd8, 0x47, 0x2a, 0x21, 0xbc, 0xcb, 0xf5, 0x1d,
- 0xce, 0x79, 0xa7, 0xb5, 0xeb, 0xc2, 0x6f, 0x8d, 0x48, 0x4f, 0xc1, 0x97,
- 0xcb, 0x56, 0x66, 0xd6, 0xb8, 0xf2, 0x2e, 0xc8, 0xda, 0x40, 0x4e, 0x42,
- 0x86, 0xcd, 0x68, 0xba, 0xc9, 0xae, 0xe7, 0xff, 0x11, 0xf9, 0xe4, 0x0a,
- 0xc6, 0x94, 0x7b, 0x7d, 0xda, 0xab, 0xb3, 0xc1, 0x8c, 0x4f, 0x99, 0xbc,
- 0x4a, 0xc6, 0xbd, 0x7c, 0x27, 0xf4, 0x03, 0xd2, 0x1a, 0xe9, 0x63, 0x27,
- 0xb2, 0x91, 0x64, 0x62, 0x58, 0xb8, 0xc7, 0x89, 0xfb, 0x13, 0xb8, 0xef,
- 0x87, 0xf2, 0xc0, 0x85, 0x9c, 0xe3, 0x1c, 0x9a, 0xfe, 0x86, 0xcb, 0xf3,
- 0x65, 0x0f, 0x08, 0xd7, 0x09, 0x93, 0xf1, 0xbd, 0xda, 0x26, 0x01, 0xd5,
- 0x15, 0x59, 0x76, 0x33, 0x2c, 0x12, 0xbf, 0xaa, 0xbc, 0xde, 0x73, 0x05,
- 0x3e, 0x67, 0x1c, 0x21, 0x1a, 0xcd, 0x16, 0xe5, 0xb5, 0x48, 0xb7, 0xbc,
- 0x96, 0x4d, 0xd5, 0x4b, 0xaf, 0x96, 0xf9, 0xcc, 0xd3, 0xe9, 0xb3, 0x26,
- 0xdd, 0x85, 0x2e, 0xe1, 0x9c, 0xf4, 0x40, 0x46, 0x4f, 0x00, 0x6e, 0xe2,
- 0xb0, 0x87, 0x32, 0x89, 0xf3, 0xa7, 0x54, 0x3a, 0x16, 0xcd, 0x95, 0xa5,
- 0x2f, 0x57, 0xb4, 0xb1, 0x9e, 0x01, 0x8e, 0x7f, 0x95, 0xc5, 0x43, 0xa3,
- 0xb8, 0x80, 0xad, 0x2f, 0x92, 0x70, 0xe0, 0x2b, 0x43, 0xd7, 0x3f, 0xba,
- 0x4a, 0x1a, 0x89, 0x9b, 0x1e, 0xf0, 0x52, 0x0d, 0x74, 0xd1, 0xfd, 0xcd,
- 0x5c, 0x37, 0xd5, 0x36, 0x64, 0xec, 0x63, 0xbf, 0xac, 0xd2, 0x7f, 0x1b,
- 0x57, 0xe9, 0x51, 0x2b, 0x2f, 0xa3, 0x7d, 0x94, 0x97, 0x4f, 0x97, 0x08,
- 0x8f, 0x78, 0x11, 0x3f, 0xd1, 0xd7, 0x5b, 0x16, 0x15, 0x49, 0x7b, 0xd1,
- 0xde, 0xf2, 0x42, 0xfa, 0x7f, 0xba, 0xf2, 0x61, 0x6b, 0x0b, 0x56, 0xc7,
- 0x54, 0xab, 0xf3, 0xc8, 0x83, 0xcb, 0xe5, 0x11, 0x26, 0x89, 0xae, 0x48,
- 0x5f, 0xf8, 0x54, 0x7b, 0x47, 0xde, 0xab, 0x15, 0xe2, 0x39, 0x80, 0xdc,
- 0x06, 0xae, 0xcb, 0x5c, 0xaf, 0xde, 0x8f, 0x79, 0xfb, 0x3f, 0x41, 0x26,
- 0xc6, 0x7c, 0x4f, 0xea, 0xe0, 0xdb, 0xbe, 0x0c, 0xdd, 0xf9, 0x8a, 0x7f,
- 0xe1, 0x53, 0x9d, 0x1d, 0x41, 0xf0, 0xac, 0x9f, 0x4f, 0xb8, 0x90, 0x1f,
- 0x87, 0x2d, 0xbe, 0x87, 0x81, 0xef, 0x89, 0x39, 0x7c, 0x27, 0xe4, 0x62,
- 0xd7, 0xf7, 0x03, 0xae, 0xf5, 0x0d, 0x97, 0x6f, 0xbd, 0x55, 0xa5, 0x3f,
- 0xfe, 0xa1, 0x6c, 0x37, 0xfb, 0x1b, 0x91, 0xc3, 0x95, 0x9b, 0x88, 0xbf,
- 0x28, 0xc6, 0x7a, 0x4f, 0x9f, 0x6f, 0xfa, 0xed, 0x5b, 0xd0, 0x2f, 0xe9,
- 0xe5, 0x47, 0xac, 0x8b, 0x32, 0xd5, 0x75, 0x33, 0xa0, 0xcb, 0xbc, 0xad,
- 0x3b, 0x70, 0x85, 0xba, 0xde, 0x15, 0xea, 0x1e, 0x46, 0xdd, 0x3d, 0xb6,
- 0xee, 0x85, 0xcf, 0xbc, 0xb9, 0x7e, 0x07, 0xb8, 0xc7, 0x0e, 0x3e, 0x80,
- 0xb8, 0x11, 0xff, 0x36, 0xfc, 0xbe, 0x85, 0xed, 0x28, 0xda, 0xf7, 0x23,
- 0x95, 0x21, 0x19, 0xae, 0xec, 0xc4, 0x33, 0x88, 0xb4, 0x3e, 0x3c, 0xfb,
- 0xf0, 0x3b, 0x8d, 0x47, 0xa2, 0x6e, 0xfa, 0xc2, 0x5d, 0xc3, 0x7e, 0x88,
- 0x57, 0xae, 0xcd, 0xb3, 0x0f, 0xd8, 0x17, 0x5d, 0x3f, 0x41, 0x1f, 0x61,
- 0xfa, 0x07, 0x50, 0x67, 0x1a, 0x69, 0x2b, 0x69, 0x7b, 0x62, 0xae, 0xab,
- 0xeb, 0x54, 0xc3, 0x36, 0x1d, 0xce, 0x05, 0xf2, 0x0d, 0x8d, 0xf6, 0x16,
- 0x43, 0x18, 0xef, 0x44, 0x1b, 0xe3, 0x57, 0x29, 0xff, 0x1e, 0xc2, 0x15,
- 0x57, 0xfe, 0xc7, 0xf0, 0x7e, 0x2d, 0xd8, 0x9d, 0x62, 0x4c, 0x9e, 0xf3,
- 0x7e, 0xdd, 0xaa, 0xa5, 0x7b, 0x9f, 0x42, 0x1a, 0xe8, 0x84, 0x4e, 0x69,
- 0xb0, 0x74, 0x5a, 0x80, 0xe5, 0x43, 0x1a, 0xe5, 0x98, 0x17, 0x97, 0x4d,
- 0x76, 0xe6, 0xa5, 0x07, 0xba, 0x8c, 0xb2, 0xf6, 0xd3, 0xf5, 0x26, 0x0e,
- 0x03, 0xcb, 0xd1, 0xef, 0x04, 0x3d, 0x37, 0x88, 0x87, 0xfa, 0x03, 0x11,
- 0x0f, 0x34, 0x18, 0xd6, 0x4f, 0x7a, 0x03, 0x11, 0x8e, 0x19, 0x1c, 0x5f,
- 0xe6, 0xba, 0x34, 0x6d, 0x6b, 0xd6, 0x0f, 0x6d, 0x1c, 0xfe, 0x7b, 0x59,
- 0xc4, 0x67, 0x1a, 0xdb, 0x0b, 0xde, 0x55, 0xe3, 0x2f, 0x59, 0x63, 0xc1,
- 0x38, 0xf3, 0x49, 0x68, 0x30, 0xaf, 0x4f, 0xcb, 0xe9, 0xfc, 0x35, 0x35,
- 0xd2, 0xe0, 0xf5, 0xeb, 0xdf, 0x2c, 0xd3, 0xe0, 0x81, 0x4f, 0x17, 0x95,
- 0x61, 0x1a, 0xf3, 0x0a, 0x6b, 0x94, 0xde, 0xab, 0xa4, 0xf7, 0x28, 0xc9,
- 0x83, 0xa9, 0x64, 0x62, 0x48, 0x25, 0xbd, 0x71, 0xd9, 0x0f, 0xb9, 0x43,
- 0x39, 0x39, 0x73, 0x7f, 0x44, 0xb8, 0x9f, 0xef, 0x5d, 0x92, 0xf5, 0x29,
- 0x3f, 0x0b, 0x9f, 0x57, 0x94, 0x75, 0x95, 0x97, 0x1a, 0xcc, 0xd8, 0xb8,
- 0x0f, 0x01, 0x70, 0x36, 0xd1, 0x86, 0xbb, 0xb5, 0x81, 0x3c, 0x94, 0x50,
- 0x11, 0xd9, 0x45, 0x3f, 0x5f, 0x7d, 0xb1, 0x5e, 0xea, 0xa7, 0xd7, 0x78,
- 0x52, 0xd1, 0xe9, 0x66, 0x7f, 0x60, 0xb2, 0x73, 0x48, 0x89, 0x1e, 0x7b,
- 0x46, 0xbd, 0x91, 0xcc, 0x9e, 0xb5, 0xfa, 0x23, 0x90, 0xc7, 0xb4, 0xbe,
- 0x98, 0xf9, 0xbc, 0x2b, 0x17, 0x82, 0xb6, 0x4d, 0x17, 0xda, 0xb3, 0x5d,
- 0xb4, 0x73, 0x57, 0xd9, 0xfd, 0x95, 0x8c, 0x63, 0xbd, 0x4b, 0x9e, 0xf3,
- 0x0b, 0x18, 0xf7, 0x7e, 0xb9, 0xe0, 0xb3, 0xbf, 0x99, 0xcf, 0x79, 0xc2,
- 0x74, 0xc2, 0x6e, 0xfa, 0x13, 0xf5, 0xa7, 0x80, 0x87, 0x7d, 0x52, 0x07,
- 0x5f, 0xc9, 0xee, 0x4b, 0x0e, 0xe4, 0x45, 0xcf, 0x4b, 0x8f, 0xa0, 0xad,
- 0x15, 0x3e, 0xf8, 0x10, 0x76, 0x73, 0xcd, 0x91, 0xab, 0x21, 0x77, 0x1d,
- 0xbd, 0xc7, 0x02, 0x93, 0xe1, 0x4d, 0x61, 0xde, 0x33, 0x03, 0x2c, 0x57,
- 0x2f, 0xd3, 0x31, 0xf2, 0xba, 0xe6, 0x97, 0x4f, 0x65, 0xfd, 0x76, 0x4f,
- 0x39, 0xc3, 0x8c, 0x31, 0x00, 0xaf, 0xa4, 0xcd, 0x54, 0x6c, 0xbb, 0xcf,
- 0xb6, 0x58, 0xe6, 0x2a, 0xf9, 0xf6, 0xc0, 0x85, 0x7f, 0x78, 0xd6, 0xff,
- 0x7b, 0xc0, 0x91, 0x81, 0x4c, 0xe0, 0xf3, 0x6a, 0x90, 0x8f, 0x31, 0xa6,
- 0xf5, 0xbf, 0xeb, 0xad, 0x9d, 0xac, 0x79, 0x7f, 0x58, 0xef, 0x93, 0x79,
- 0xfe, 0x33, 0x59, 0xae, 0x77, 0xc0, 0x36, 0xc9, 0x69, 0xb9, 0x18, 0xfd,
- 0x69, 0x0e, 0xf0, 0x14, 0x2a, 0xb4, 0x43, 0xfe, 0x06, 0x76, 0x88, 0xd6,
- 0x93, 0xf2, 0xed, 0x41, 0xe6, 0xb1, 0xdd, 0xec, 0xd5, 0xae, 0xd6, 0x0b,
- 0x21, 0x2c, 0xc9, 0xce, 0x1c, 0xf2, 0x47, 0xb4, 0x1d, 0xef, 0xc9, 0xac,
- 0xe7, 0xea, 0x7d, 0x27, 0xf9, 0xc1, 0x20, 0x78, 0xc5, 0x77, 0xe5, 0xa4,
- 0x86, 0xf9, 0x05, 0xf4, 0xe1, 0xc8, 0xc4, 0x80, 0xfb, 0xd3, 0x93, 0x3e,
- 0xc7, 0xc7, 0x3c, 0xae, 0x2b, 0x6d, 0x8e, 0x1b, 0xf8, 0x68, 0x9b, 0x7e,
- 0x2f, 0x98, 0x8d, 0x71, 0xdd, 0x02, 0x3c, 0x5d, 0x6a, 0xf7, 0x6e, 0x90,
- 0xdb, 0xe6, 0x6c, 0x9a, 0x69, 0x31, 0x36, 0xa3, 0xd1, 0x69, 0x17, 0xfe,
- 0x61, 0xc4, 0xbf, 0xb0, 0xba, 0x80, 0xb9, 0x81, 0x0e, 0x5b, 0x0c, 0x4b,
- 0x8a, 0xb0, 0x0c, 0x6b, 0x58, 0x62, 0xc0, 0xa5, 0x0b, 0xd9, 0x77, 0x9b,
- 0x1c, 0x02, 0xde, 0x87, 0x06, 0x45, 0x9e, 0x85, 0x4d, 0x76, 0xbe, 0x0a,
- 0x9e, 0x19, 0xc0, 0x73, 0xde, 0xe7, 0x5e, 0x00, 0xe6, 0xf9, 0xde, 0xb0,
- 0x70, 0x2f, 0x00, 0x71, 0xd8, 0x81, 0xdf, 0x22, 0x33, 0xd0, 0xbf, 0x27,
- 0xfd, 0xd7, 0x82, 0xf1, 0x18, 0x75, 0x23, 0xda, 0x99, 0xdb, 0x1b, 0x14,
- 0xc8, 0xe7, 0x53, 0xd4, 0x43, 0xb5, 0xd2, 0xb6, 0x8e, 0x7e, 0x88, 0x91,
- 0x9f, 0x37, 0xf8, 0x19, 0xf4, 0xf5, 0x5b, 0x2b, 0xa5, 0x3e, 0x2f, 0xfd,
- 0x1d, 0x75, 0xc8, 0x73, 0x6d, 0xde, 0x80, 0xce, 0xeb, 0xef, 0x38, 0x8c,
- 0xfc, 0x8f, 0xaf, 0x64, 0xbc, 0xdb, 0xf5, 0xd7, 0x4b, 0xdb, 0x1a, 0xe6,
- 0x55, 0xf3, 0xe0, 0xab, 0xdc, 0x83, 0x69, 0x75, 0x38, 0x64, 0x59, 0x29,
- 0xef, 0x71, 0xa7, 0xdd, 0x21, 0xcc, 0xc5, 0x6e, 0x9f, 0xb2, 0xed, 0xbf,
- 0xa3, 0x6e, 0x4a, 0x6e, 0xf4, 0x07, 0x91, 0x37, 0x8d, 0xbc, 0xc3, 0x36,
- 0x6f, 0xd0, 0xe6, 0x6d, 0x43, 0xde, 0x3e, 0xe0, 0xef, 0x6e, 0x9d, 0x9e,
- 0xe5, 0x6f, 0x53, 0xc7, 0x5b, 0xd9, 0x71, 0xe1, 0x33, 0x37, 0xf8, 0x84,
- 0x0b, 0x79, 0x25, 0xae, 0x8b, 0xde, 0x26, 0x79, 0x2f, 0x79, 0x0b, 0x7b,
- 0xfd, 0x66, 0xb1, 0x0e, 0xb2, 0x89, 0x7b, 0x80, 0x69, 0xb3, 0x6e, 0xf1,
- 0x5e, 0x96, 0xff, 0x40, 0xba, 0xeb, 0xc9, 0x38, 0x5f, 0x5b, 0xc9, 0xb8,
- 0xd8, 0x88, 0x4f, 0xfb, 0x3a, 0x90, 0x9c, 0x5e, 0x3f, 0xa1, 0x7f, 0x5b,
- 0x44, 0x3a, 0xe9, 0x41, 0x35, 0x45, 0xf4, 0x3e, 0x2d, 0x7e, 0x47, 0x61,
- 0xf7, 0x06, 0x42, 0x9f, 0x8f, 0x36, 0x5d, 0xc6, 0xe3, 0xda, 0x50, 0x98,
- 0xe7, 0x21, 0x4f, 0x6d, 0x8a, 0xc0, 0x26, 0xaa, 0xf5, 0x1d, 0x1d, 0xa3,
- 0x2e, 0xe8, 0x75, 0x00, 0xc6, 0xdf, 0x32, 0xf0, 0x63, 0x02, 0xe9, 0x47,
- 0xdf, 0xa4, 0xfd, 0x68, 0x87, 0xef, 0x1d, 0x10, 0xee, 0x67, 0x65, 0x7a,
- 0xbb, 0xf7, 0x6d, 0x99, 0xa7, 0xf3, 0x19, 0x49, 0x66, 0x94, 0x03, 0xff,
- 0x75, 0xab, 0x23, 0xf5, 0xb0, 0x3d, 0x6e, 0x30, 0xfa, 0xcd, 0xe3, 0x9e,
- 0xc4, 0x8b, 0xda, 0x56, 0x6b, 0xb4, 0xf3, 0x91, 0x05, 0x6e, 0xb8, 0x1f,
- 0x7c, 0xe0, 0x9e, 0xdd, 0x7e, 0x21, 0x09, 0x6a, 0xd4, 0xba, 0x71, 0x18,
- 0xb4, 0x91, 0x4d, 0x19, 0xdd, 0x78, 0xc3, 0x9c, 0x6e, 0xfc, 0xf3, 0x95,
- 0xe4, 0x89, 0xe1, 0x72, 0x1c, 0x75, 0xf5, 0x3a, 0x4a, 0x82, 0x75, 0x6b,
- 0x31, 0x9f, 0xe7, 0xfd, 0xec, 0x35, 0xa0, 0x2f, 0xc8, 0xe1, 0x64, 0xe7,
- 0x29, 0xd4, 0x2d, 0xa0, 0xee, 0xe4, 0x5c, 0x5d, 0x47, 0x46, 0x7c, 0xbd,
- 0xef, 0x59, 0x26, 0xcb, 0x21, 0x1d, 0x26, 0xe3, 0xb7, 0x6a, 0x5e, 0xe0,
- 0x7e, 0x30, 0x37, 0x71, 0x9f, 0x6c, 0xd6, 0xb4, 0xdd, 0x27, 0xdc, 0x27,
- 0xc5, 0xb6, 0xef, 0x0b, 0xda, 0xd6, 0x10, 0xbe, 0x12, 0xde, 0xa4, 0x8d,
- 0x31, 0xbc, 0xc3, 0xf9, 0x37, 0xf3, 0x3e, 0xe4, 0x10, 0xdf, 0xbf, 0x1f,
- 0xe4, 0x07, 0x39, 0x2f, 0xfc, 0x9e, 0xa7, 0xb9, 0x11, 0xd0, 0x5c, 0xc4,
- 0x7f, 0xbb, 0x0c, 0xeb, 0x3d, 0x10, 0x29, 0x99, 0xd0, 0xf1, 0xcc, 0x0b,
- 0xc1, 0x23, 0x0b, 0xe4, 0xf8, 0x47, 0x94, 0xa1, 0x21, 0xfe, 0x2e, 0x24,
- 0xea, 0x64, 0x66, 0x4d, 0x9d, 0xde, 0xf1, 0x41, 0x7c, 0x8c, 0xde, 0x73,
- 0x3b, 0xf8, 0xf5, 0xfa, 0xb9, 0xb1, 0x00, 0xdf, 0xc0, 0xe3, 0x4e, 0x63,
- 0xeb, 0x63, 0x1c, 0x19, 0xed, 0xbf, 0x67, 0x8b, 0x4a, 0xef, 0x0b, 0xa2,
- 0x8e, 0x3f, 0x00, 0x9d, 0x6a, 0xf6, 0xa4, 0xe0, 0x5d, 0xe1, 0xbc, 0x29,
- 0xed, 0x73, 0x1c, 0x04, 0x0f, 0x1f, 0xf4, 0xb3, 0x6b, 0x6a, 0x75, 0xdb,
- 0x49, 0xef, 0x7a, 0x6d, 0x13, 0x6e, 0x94, 0x99, 0x14, 0xdb, 0x23, 0x5e,
- 0xfe, 0x47, 0x30, 0xe4, 0xcd, 0xa0, 0x7f, 0x43, 0xff, 0x59, 0x5f, 0xb5,
- 0xd4, 0x49, 0xf5, 0x3e, 0x53, 0xe2, 0xc9, 0x85, 0xbd, 0xd2, 0x01, 0xfc,
- 0x18, 0x78, 0x73, 0xe5, 0xb7, 0x49, 0x21, 0xe6, 0xda, 0xb1, 0x45, 0xb4,
- 0x2f, 0x37, 0x91, 0xaa, 0x83, 0x2d, 0xf8, 0x17, 0xc1, 0xe4, 0x82, 0x31,
- 0x1e, 0xac, 0x1a, 0xe3, 0x4c, 0x02, 0xd8, 0x68, 0x89, 0xcc, 0xc9, 0x01,
- 0xf6, 0x65, 0x64, 0x52, 0x38, 0xc6, 0x3a, 0x8c, 0x71, 0xc7, 0xdc, 0x18,
- 0x0f, 0x2f, 0x1a, 0xe3, 0x61, 0x8c, 0x11, 0xf6, 0x42, 0x29, 0xd3, 0xe9,
- 0xce, 0xcf, 0xfb, 0xd5, 0x35, 0x73, 0xf3, 0x29, 0xdc, 0xeb, 0x84, 0xf1,
- 0xd3, 0xa6, 0xd8, 0x08, 0x78, 0x74, 0x5b, 0x90, 0x71, 0x0e, 0x64, 0x5b,
- 0x76, 0x4d, 0x8d, 0x1d, 0xff, 0x76, 0x96, 0x2b, 0x1b, 0x1c, 0x9c, 0x4c,
- 0xb9, 0x9d, 0x8f, 0xa0, 0xbf, 0xbd, 0x76, 0x5c, 0xbd, 0xe5, 0xab, 0x31,
- 0xae, 0x0b, 0xdf, 0xc1, 0x18, 0xe0, 0xb3, 0x9d, 0xa0, 0x0f, 0x9c, 0x18,
- 0x92, 0x05, 0xb2, 0xeb, 0x33, 0xf3, 0x72, 0xd4, 0xc0, 0x4c, 0xdb, 0xba,
- 0x30, 0x07, 0xf3, 0xdd, 0x8b, 0x60, 0xbe, 0x1b, 0x30, 0xef, 0xb3, 0xf3,
- 0xb2, 0xaf, 0x6a, 0xcf, 0x62, 0x48, 0x47, 0xfc, 0xfd, 0xbc, 0xf5, 0x45,
- 0x3e, 0x20, 0xf7, 0x97, 0x3a, 0xe5, 0xcb, 0x95, 0xe4, 0x59, 0xc6, 0xd1,
- 0xcf, 0x55, 0x92, 0xe3, 0x22, 0x5d, 0xf2, 0xc7, 0xb0, 0x73, 0xae, 0x82,
- 0x6f, 0xf1, 0x34, 0xfc, 0xd7, 0x3f, 0xa9, 0xf8, 0xf2, 0xc4, 0xdc, 0x7e,
- 0x38, 0xea, 0xba, 0xb4, 0x9c, 0x84, 0x4f, 0xbb, 0xed, 0x68, 0x1b, 0xf7,
- 0x2a, 0x11, 0xbe, 0xbb, 0xa8, 0x73, 0xda, 0x94, 0xe6, 0xc5, 0xef, 0x62,
- 0xbc, 0xa7, 0xa9, 0x6b, 0xd6, 0xfa, 0xbe, 0x77, 0xb3, 0x5a, 0x47, 0x99,
- 0x90, 0xff, 0x5a, 0xe4, 0x03, 0xf5, 0x26, 0xc6, 0x92, 0xf1, 0x9a, 0xc9,
- 0x1b, 0xdb, 0x3a, 0x12, 0x7d, 0x42, 0x5b, 0x82, 0xfe, 0x36, 0x6c, 0xa1,
- 0xd2, 0xe6, 0xf8, 0x5a, 0xa1, 0x4c, 0xa2, 0x5d, 0x94, 0x96, 0x09, 0xc0,
- 0x3e, 0x06, 0x89, 0x50, 0x68, 0xf6, 0x47, 0x7b, 0xd5, 0x44, 0x03, 0x79,
- 0x70, 0xdb, 0x19, 0xd0, 0xd7, 0x36, 0x8c, 0xa9, 0x2b, 0x79, 0x76, 0x46,
- 0x65, 0x4e, 0xac, 0x95, 0x57, 0x82, 0xa1, 0x66, 0x47, 0x9e, 0xd8, 0xc4,
- 0x3c, 0x2d, 0xb7, 0x3f, 0xd5, 0x0b, 0xf9, 0xd4, 0xce, 0x73, 0x0b, 0x03,
- 0xf2, 0x2f, 0x77, 0x80, 0x06, 0x7f, 0xb8, 0xe9, 0x6b, 0xc1, 0x6c, 0xb3,
- 0x2b, 0x5b, 0x37, 0x25, 0xbd, 0xbc, 0xc2, 0x78, 0x4a, 0x18, 0x4f, 0x09,
- 0xe3, 0xe3, 0x98, 0x4b, 0x18, 0xd7, 0x15, 0xf7, 0x4a, 0xf5, 0x2c, 0x88,
- 0xcb, 0x1a, 0x3f, 0x2d, 0x93, 0x77, 0x65, 0x83, 0xdd, 0x2b, 0x35, 0x5c,
- 0x1f, 0xae, 0xb1, 0x65, 0x64, 0x3c, 0x28, 0xf8, 0x7f, 0x70, 0x55, 0xb6,
- 0x2b, 0xb6, 0x58, 0xe7, 0xdc, 0x35, 0xaf, 0x73, 0x44, 0x9e, 0x33, 0xf3,
- 0x86, 0x39, 0xf3, 0xbd, 0x49, 0x6e, 0x86, 0x87, 0x0e, 0xdc, 0xaa, 0xf7,
- 0x3c, 0x77, 0xe0, 0x9b, 0x36, 0xd5, 0xa7, 0xf5, 0x3a, 0xe2, 0x4c, 0xf9,
- 0x1e, 0x3b, 0x77, 0xf7, 0x68, 0x3d, 0xbb, 0x75, 0xd3, 0xa5, 0x80, 0xfb,
- 0xdc, 0xbc, 0x4d, 0xcb, 0xc5, 0x22, 0x68, 0xef, 0xd5, 0x69, 0xde, 0xe7,
- 0x7a, 0x76, 0x41, 0x9f, 0x13, 0x01, 0xde, 0xe6, 0xe2, 0x62, 0xf5, 0x48,
- 0xa3, 0xbe, 0xf8, 0x69, 0x83, 0x59, 0x47, 0xa5, 0x6c, 0x58, 0x83, 0x34,
- 0xd7, 0xec, 0x05, 0x5e, 0x90, 0xf7, 0xdf, 0xea, 0xcd, 0x9e, 0x8f, 0xea,
- 0xb2, 0xe0, 0x31, 0xbd, 0x2f, 0x84, 0xfb, 0x03, 0x7f, 0x79, 0xa5, 0xb1,
- 0x4d, 0xc3, 0x7c, 0xa6, 0xff, 0x38, 0x98, 0xd0, 0x31, 0x36, 0xf6, 0xf5,
- 0x43, 0xfc, 0x5e, 0xbc, 0x5f, 0x24, 0xb4, 0x5d, 0xeb, 0x40, 0xf7, 0xda,
- 0x5f, 0x16, 0x94, 0x89, 0xe7, 0x25, 0x22, 0x13, 0x55, 0x30, 0x4e, 0x10,
- 0xee, 0x52, 0xd7, 0xaa, 0xf9, 0xd8, 0xdd, 0x6a, 0xa4, 0x11, 0xc6, 0x75,
- 0x8b, 0xf2, 0xc8, 0x1b, 0xad, 0x2b, 0x49, 0x37, 0xd3, 0xc2, 0xb4, 0xf9,
- 0x31, 0xcd, 0x68, 0xfb, 0xb9, 0x6d, 0x95, 0xde, 0xfb, 0xc4, 0x35, 0x46,
- 0xc6, 0x08, 0x63, 0x26, 0xdf, 0xf5, 0xff, 0x56, 0xd7, 0x19, 0x9a, 0xab,
- 0xa3, 0xe7, 0x02, 0xf9, 0x6e, 0x55, 0x5e, 0x35, 0xdc, 0xd4, 0x5f, 0x43,
- 0x9d, 0x75, 0xd0, 0x89, 0x17, 0x53, 0xab, 0xc3, 0xbd, 0xf0, 0xb0, 0x21,
- 0xb2, 0xd7, 0xd4, 0x5a, 0x99, 0x3f, 0x81, 0x79, 0x7d, 0x26, 0x65, 0x78,
- 0x51, 0xf3, 0x61, 0xf1, 0x36, 0xf8, 0xeb, 0xa1, 0xde, 0xa0, 0x9c, 0x26,
- 0x6f, 0x22, 0xad, 0x42, 0x9f, 0xe0, 0xc2, 0xea, 0x99, 0xae, 0x57, 0x03,
- 0xee, 0xb3, 0x7c, 0x45, 0xdb, 0x51, 0x43, 0xb2, 0xb0, 0xed, 0xd1, 0x7b,
- 0x5e, 0xbf, 0xed, 0xa1, 0x65, 0xda, 0x1e, 0xb2, 0x6d, 0x8b, 0x6b, 0xda,
- 0x8e, 0x5e, 0xa1, 0xed, 0x81, 0x37, 0x68, 0x7b, 0x70, 0x99, 0xb6, 0x07,
- 0xc3, 0xb6, 0x95, 0x69, 0xdb, 0x0b, 0xdb, 0x4e, 0x2c, 0xc2, 0xc9, 0x67,
- 0x5e, 0xbf, 0xed, 0x7d, 0xcb, 0xb4, 0xbd, 0x6f, 0x11, 0xdc, 0xc4, 0x49,
- 0x2d, 0x74, 0xff, 0x3d, 0xda, 0xe6, 0xac, 0x03, 0xdf, 0x5c, 0x84, 0xfc,
- 0x36, 0xfe, 0xc8, 0x85, 0xbb, 0x66, 0xcb, 0xe0, 0x2b, 0xf8, 0xd7, 0x99,
- 0x72, 0x03, 0x9e, 0x71, 0xd8, 0x33, 0x28, 0x07, 0x7b, 0xbc, 0x26, 0x1d,
- 0xc8, 0xc9, 0x6e, 0x96, 0xcd, 0xc7, 0x6b, 0xe7, 0xf4, 0xc6, 0x3d, 0xe8,
- 0x8f, 0x6d, 0xfb, 0x5e, 0xbf, 0xbc, 0xa6, 0xfb, 0xcb, 0x95, 0xe9, 0x8f,
- 0x21, 0xbd, 0x42, 0x1f, 0x97, 0xf5, 0x42, 0x19, 0x58, 0x67, 0xd7, 0x3e,
- 0x68, 0x6b, 0x32, 0x0e, 0xa7, 0xed, 0x51, 0x29, 0x94, 0x7f, 0x12, 0x4c,
- 0x83, 0x2e, 0x46, 0xe6, 0x74, 0xc8, 0x93, 0xab, 0x68, 0xb3, 0x8f, 0x53,
- 0xb3, 0x54, 0xc5, 0xa0, 0x46, 0x7c, 0xa6, 0xfd, 0x98, 0x6d, 0xc2, 0x0e,
- 0x0c, 0xcb, 0x32, 0x6e, 0x6c, 0x62, 0x4e, 0x67, 0x21, 0x33, 0xcd, 0x9e,
- 0x0e, 0xfa, 0x2a, 0x4f, 0x81, 0x97, 0xf7, 0x43, 0x76, 0x24, 0xf3, 0x22,
- 0x3d, 0x8d, 0xe6, 0xac, 0x45, 0x4c, 0x72, 0x5d, 0xbf, 0x69, 0xf1, 0xb8,
- 0xef, 0xce, 0xe5, 0xcf, 0x59, 0x40, 0x3e, 0x38, 0x94, 0x91, 0xd7, 0x37,
- 0x9a, 0x75, 0xbb, 0xb7, 0x36, 0x32, 0x1e, 0xa3, 0x36, 0x75, 0xaf, 0xd6,
- 0xf2, 0xc7, 0x09, 0xbf, 0xbf, 0xb2, 0xe8, 0x3b, 0xac, 0xf7, 0x93, 0xd5,
- 0x0b, 0xeb, 0x85, 0xe9, 0x70, 0x4d, 0x16, 0xa4, 0x1f, 0x58, 0xb3, 0xb0,
- 0x7e, 0xac, 0x69, 0xe1, 0xf7, 0xe0, 0xa2, 0xef, 0xcf, 0x2c, 0xfa, 0x7e,
- 0x61, 0xd1, 0xf7, 0x75, 0x6b, 0x17, 0x95, 0x5f, 0xf4, 0xfd, 0xe5, 0xb5,
- 0xcb, 0xc3, 0xfb, 0x57, 0x6b, 0x17, 0xc2, 0xf5, 0x94, 0x5e, 0x73, 0x1d,
- 0xaf, 0xb8, 0xb2, 0xbd, 0x88, 0x7c, 0xe7, 0xd6, 0x18, 0xf2, 0xe1, 0xcb,
- 0x54, 0xe7, 0x73, 0x8d, 0xe3, 0x1d, 0xb1, 0x85, 0xed, 0xcd, 0xd7, 0xdb,
- 0x31, 0x5f, 0x2f, 0x35, 0x5f, 0xcf, 0xf8, 0x23, 0x13, 0x15, 0xe6, 0x31,
- 0x3d, 0x6c, 0xd7, 0xd4, 0x1d, 0x29, 0x79, 0xfa, 0x3c, 0xc2, 0x80, 0x3e,
- 0x8f, 0x90, 0x80, 0x6f, 0xf4, 0x94, 0x8e, 0xeb, 0xaf, 0x51, 0x48, 0xaf,
- 0x34, 0xea, 0xd8, 0xbe, 0xe8, 0x33, 0x09, 0x03, 0xb0, 0xb9, 0x78, 0x0e,
- 0x21, 0x90, 0x9d, 0x29, 0xf3, 0x36, 0xe7, 0x12, 0x0e, 0x07, 0xbd, 0x5e,
- 0x10, 0x0c, 0xfb, 0x67, 0xad, 0x2c, 0xc7, 0xbb, 0x62, 0xea, 0xd0, 0xd7,
- 0x7c, 0x14, 0xfa, 0x66, 0xde, 0xc7, 0x7c, 0x8a, 0xf6, 0x3a, 0x68, 0xa6,
- 0x1b, 0x7a, 0x37, 0xf9, 0xa4, 0x68, 0xdd, 0xd1, 0x05, 0x9d, 0xeb, 0xdd,
- 0xfb, 0x3e, 0xd8, 0x3a, 0x5f, 0x06, 0xad, 0x1f, 0x4b, 0xf5, 0x68, 0xff,
- 0xff, 0x1c, 0x74, 0x31, 0xe3, 0x84, 0x8f, 0x69, 0xda, 0x22, 0x8d, 0x35,
- 0xe8, 0xb3, 0x50, 0x27, 0x53, 0x4e, 0x34, 0xdb, 0x75, 0xde, 0xc4, 0xcd,
- 0x53, 0xed, 0xde, 0x73, 0xe0, 0xb5, 0x7e, 0x7f, 0x03, 0x6c, 0x66, 0xd1,
- 0x3a, 0xbf, 0x50, 0x5a, 0x6f, 0x6d, 0x83, 0x66, 0x19, 0x77, 0xb9, 0x56,
- 0x93, 0xec, 0x19, 0x32, 0x3e, 0x66, 0x3c, 0xa1, 0x18, 0x23, 0xe6, 0xfa,
- 0x05, 0xcf, 0x39, 0x70, 0x9d, 0x9b, 0xf1, 0x90, 0xf1, 0x7b, 0x47, 0xfc,
- 0xbc, 0x17, 0xb1, 0x67, 0x23, 0xb2, 0x45, 0x43, 0x9b, 0x7b, 0xb4, 0xad,
- 0x1a, 0x05, 0x3f, 0x7d, 0x0f, 0x74, 0xcf, 0xba, 0xa4, 0xfd, 0xef, 0x04,
- 0x93, 0xae, 0x89, 0x4f, 0x29, 0xd4, 0xcb, 0x6a, 0x5c, 0x3d, 0x25, 0x07,
- 0x4a, 0xe4, 0xff, 0xa8, 0x96, 0xe5, 0xbb, 0x53, 0x94, 0x07, 0x51, 0xe0,
- 0x71, 0x0a, 0xf8, 0x6b, 0x90, 0xdd, 0x5d, 0x45, 0x94, 0x89, 0xc8, 0xd0,
- 0x40, 0x03, 0x78, 0x8f, 0x76, 0x09, 0xdf, 0x2e, 0xca, 0x7b, 0x32, 0x55,
- 0x1c, 0xd7, 0x7b, 0x9e, 0x1f, 0x43, 0xdd, 0xc7, 0xf1, 0x4c, 0x14, 0xcb,
- 0xa8, 0xf3, 0xb0, 0x2e, 0x3f, 0x31, 0xca, 0x73, 0x22, 0x02, 0x7b, 0xff,
- 0x49, 0x29, 0x4c, 0xb6, 0xc1, 0x2f, 0x99, 0x1e, 0x77, 0xe7, 0xe2, 0xe4,
- 0xff, 0xa5, 0x91, 0xeb, 0xcc, 0x85, 0xeb, 0xb8, 0x27, 0x47, 0xdc, 0x81,
- 0xcd, 0xaa, 0xb3, 0x49, 0xaf, 0xf9, 0xf4, 0x48, 0x3f, 0x6c, 0x8a, 0x9b,
- 0x2b, 0xcf, 0xc4, 0xcc, 0xda, 0xc0, 0x82, 0xf5, 0x86, 0xc3, 0xc4, 0x8a,
- 0x3a, 0xea, 0xf2, 0xdc, 0xa7, 0x4c, 0x9c, 0x81, 0xf6, 0x39, 0x1a, 0xae,
- 0xe7, 0x30, 0xcd, 0x93, 0xb6, 0xeb, 0x00, 0xd7, 0x99, 0x7f, 0xd2, 0xf2,
- 0xf5, 0x89, 0x4d, 0x61, 0x5f, 0xf9, 0x60, 0x6c, 0x53, 0x5e, 0x3e, 0x81,
- 0x27, 0x77, 0x5d, 0x72, 0x34, 0xab, 0xd8, 0xef, 0x37, 0x02, 0xc6, 0x02,
- 0x54, 0xba, 0x55, 0xf2, 0x4d, 0xd5, 0xfd, 0x33, 0xad, 0xc3, 0x2b, 0xa8,
- 0xd7, 0x83, 0x63, 0x26, 0x11, 0x03, 0x0e, 0xf2, 0x6f, 0x08, 0xcf, 0x16,
- 0xcf, 0x57, 0xcb, 0xc1, 0x73, 0xc2, 0xae, 0xd7, 0x70, 0x0d, 0x66, 0x05,
- 0xf0, 0xd2, 0x80, 0xf4, 0x09, 0x19, 0x39, 0xfe, 0x3b, 0x31, 0xee, 0x17,
- 0xaa, 0xd1, 0x7e, 0xf5, 0x7d, 0xf5, 0x26, 0x06, 0xf2, 0x2c, 0xca, 0x30,
- 0x7f, 0x1c, 0x75, 0x92, 0xf9, 0x6c, 0x64, 0xad, 0x0c, 0xe9, 0x7e, 0x83,
- 0x48, 0xdb, 0xb6, 0x7a, 0xbd, 0x4f, 0x5f, 0xce, 0x30, 0x6e, 0x11, 0xd6,
- 0x7d, 0x56, 0xef, 0x83, 0x73, 0xd3, 0xc9, 0x7c, 0x5f, 0x84, 0xf2, 0xa9,
- 0x53, 0x7a, 0xb9, 0xce, 0x73, 0x66, 0x5c, 0xd3, 0x76, 0xfb, 0x26, 0x9e,
- 0x07, 0xdd, 0x02, 0xfb, 0xef, 0x3b, 0x80, 0x89, 0x30, 0x9e, 0x40, 0x3a,
- 0x7c, 0xc2, 0xd7, 0x85, 0x61, 0xfa, 0x4d, 0xc2, 0x30, 0xfd, 0x26, 0x61,
- 0x20, 0x2e, 0x00, 0x47, 0xa5, 0x7d, 0x75, 0x68, 0x53, 0x5c, 0x85, 0x71,
- 0x1c, 0x2c, 0x4d, 0xc3, 0xbf, 0xd5, 0x31, 0x94, 0xce, 0x69, 0x45, 0x9e,
- 0xf7, 0xc0, 0x73, 0xe0, 0xad, 0x12, 0x78, 0x0f, 0xb6, 0xe1, 0x97, 0x61,
- 0x1b, 0x3e, 0x01, 0xdb, 0xf0, 0x1c, 0x6c, 0xc3, 0xc7, 0x31, 0x37, 0x8f,
- 0x2d, 0xe0, 0xd5, 0x8c, 0xe6, 0xd5, 0x42, 0xe9, 0x02, 0x78, 0xb5, 0xeb,
- 0x0a, 0xfc, 0xe8, 0xc2, 0xc6, 0xa7, 0x0d, 0xed, 0xc0, 0x96, 0xff, 0xb8,
- 0xf6, 0x8b, 0x1f, 0x4c, 0x8d, 0xb1, 0x0e, 0x68, 0x38, 0x49, 0x9f, 0x16,
- 0xf2, 0x3f, 0x99, 0x07, 0xef, 0x61, 0xac, 0x8e, 0xa3, 0xae, 0x5b, 0x23,
- 0xd4, 0x1f, 0xee, 0x36, 0xee, 0xef, 0xe6, 0x58, 0x13, 0x8b, 0xf0, 0x64,
- 0xf8, 0x73, 0x8f, 0x4f, 0x3d, 0x42, 0xbe, 0x4c, 0x7c, 0x76, 0xc4, 0xaf,
- 0xe6, 0xc5, 0x1d, 0x1c, 0x5f, 0xe0, 0x6d, 0x5a, 0xae, 0xee, 0x7c, 0xf9,
- 0x35, 0x73, 0xe5, 0x75, 0xff, 0xa3, 0xe4, 0x37, 0xe8, 0x6e, 0xe2, 0x3e,
- 0x91, 0x8d, 0x6c, 0xb0, 0xb8, 0xdf, 0x2f, 0x6d, 0xdb, 0x60, 0xaf, 0x0f,
- 0x82, 0x7e, 0xa7, 0x02, 0xf1, 0xb7, 0x85, 0x6d, 0xce, 0xb7, 0xe3, 0xd9,
- 0x76, 0x76, 0xc3, 0x96, 0xed, 0xdb, 0xc4, 0xb5, 0x5e, 0xd8, 0xf2, 0xa9,
- 0x70, 0x3e, 0x60, 0xf9, 0xea, 0x39, 0xa7, 0x0c, 0xa5, 0xec, 0x6c, 0xb0,
- 0xf1, 0x7e, 0xb6, 0x77, 0x61, 0xd1, 0x3c, 0x5d, 0x0a, 0x78, 0xce, 0x76,
- 0xc4, 0x1f, 0xab, 0xa2, 0x95, 0xbf, 0xb2, 0xb4, 0xa2, 0x16, 0x8d, 0xe3,
- 0x9c, 0xa5, 0x95, 0x10, 0xde, 0x58, 0x48, 0x2b, 0x75, 0x21, 0xad, 0xe4,
- 0xc7, 0x43, 0x5a, 0x61, 0xdd, 0x73, 0x21, 0xad, 0x24, 0xaa, 0x69, 0x25,
- 0x3f, 0xee, 0xe0, 0x59, 0x0c, 0x07, 0xe9, 0x85, 0xed, 0x90, 0x5e, 0x00,
- 0x4b, 0xa5, 0x32, 0x47, 0x2f, 0x31, 0xb4, 0x73, 0xa8, 0xa4, 0x34, 0xad,
- 0x0c, 0xa9, 0x50, 0x47, 0x78, 0x98, 0x73, 0xcc, 0xfd, 0x15, 0x69, 0x24,
- 0x65, 0x69, 0x64, 0xfe, 0x2c, 0xd1, 0x22, 0xda, 0x00, 0xee, 0x79, 0x5e,
- 0x60, 0xb3, 0xa6, 0x8d, 0xfb, 0x53, 0x2f, 0xa0, 0xec, 0x28, 0x68, 0x23,
- 0xc4, 0xc1, 0x03, 0x16, 0x07, 0x8b, 0xe7, 0xf2, 0xb4, 0xc5, 0xc1, 0xa8,
- 0xc5, 0x81, 0xe6, 0x97, 0x3c, 0xe7, 0x4c, 0x69, 0x1c, 0xd4, 0x69, 0x1c,
- 0x88, 0x0a, 0xeb, 0x9e, 0x5e, 0x06, 0x07, 0x2c, 0x33, 0xaa, 0xc7, 0x1f,
- 0xc1, 0xf8, 0xf7, 0x61, 0xfc, 0x4a, 0x8f, 0x9f, 0xf3, 0xc0, 0xf1, 0x03,
- 0x96, 0xca, 0x77, 0xe6, 0xc6, 0xdf, 0x84, 0x36, 0x0e, 0x6a, 0xdb, 0x99,
- 0xf1, 0x54, 0xea, 0x46, 0x33, 0xfe, 0xc7, 0x2a, 0xe6, 0x8c, 0xc9, 0x63,
- 0x4b, 0xf4, 0xd8, 0x0b, 0x96, 0x37, 0x7c, 0xbd, 0xce, 0xc6, 0x73, 0x6d,
- 0xe7, 0xa0, 0xbb, 0xc6, 0x52, 0x09, 0x7b, 0xe6, 0xd4, 0xd8, 0x43, 0x5f,
- 0x4d, 0x91, 0x77, 0x3e, 0xaa, 0xf7, 0xfa, 0x9d, 0xa5, 0x5d, 0x54, 0x6a,
- 0x92, 0xbe, 0xb1, 0x6a, 0xb8, 0x09, 0x6f, 0x3e, 0x50, 0x3e, 0x63, 0x37,
- 0xfb, 0xa1, 0x3b, 0x4c, 0xdc, 0x1a, 0xb4, 0x84, 0xf4, 0x64, 0xbe, 0x37,
- 0x52, 0x27, 0xea, 0x81, 0x0f, 0x60, 0xcc, 0x2e, 0x7c, 0xcc, 0x76, 0x6f,
- 0x9b, 0xa2, 0xae, 0xbb, 0xba, 0x4a, 0xd7, 0x35, 0x5b, 0x5d, 0xb7, 0x86,
- 0xba, 0x0e, 0x70, 0x3f, 0x25, 0x87, 0x4b, 0x9c, 0xbf, 0x7c, 0xa2, 0x4e,
- 0xc7, 0x40, 0x1d, 0x1b, 0xe7, 0x4b, 0xc6, 0x0f, 0x6b, 0x5a, 0xa6, 0xce,
- 0x4a, 0xea, 0xb8, 0xe4, 0x4c, 0xd7, 0x3f, 0xd9, 0x75, 0x10, 0xea, 0xb5,
- 0xef, 0x07, 0x7f, 0xb0, 0x8c, 0x5e, 0x83, 0xfe, 0xd1, 0xf6, 0x59, 0x0d,
- 0x64, 0xad, 0x9c, 0x6a, 0xc6, 0xb3, 0x9a, 0xe7, 0xc1, 0x3a, 0x3b, 0x54,
- 0xbd, 0xd4, 0x9c, 0x6a, 0x94, 0x3d, 0x63, 0x7a, 0xdd, 0x5c, 0xd4, 0x29,
- 0xe0, 0xff, 0x14, 0xcf, 0x14, 0x88, 0x3e, 0x03, 0x95, 0x1b, 0x85, 0x3f,
- 0x33, 0xf1, 0x94, 0xd9, 0x1b, 0x38, 0x56, 0xa3, 0x7f, 0xd3, 0xc6, 0x28,
- 0xa4, 0x32, 0xfa, 0xec, 0xd0, 0x1e, 0xb4, 0xd9, 0xbe, 0xa9, 0x16, 0x63,
- 0x8e, 0xa1, 0x2e, 0xf7, 0x16, 0xaa, 0x36, 0x57, 0x6a, 0xc5, 0x9d, 0x88,
- 0xea, 0xf3, 0x4b, 0x3c, 0x7f, 0x9f, 0xed, 0x69, 0x42, 0x5e, 0x44, 0xaf,
- 0x15, 0xd4, 0x9c, 0x9a, 0x3f, 0xa7, 0xae, 0x8e, 0x8a, 0x5d, 0xc3, 0x4f,
- 0x6b, 0xbd, 0x12, 0x39, 0x4a, 0x9d, 0xc3, 0xfd, 0x55, 0x3d, 0x98, 0xf7,
- 0xe5, 0xf4, 0x8d, 0x31, 0x62, 0xb3, 0x98, 0x3f, 0x75, 0x86, 0x67, 0x8d,
- 0x5b, 0xf1, 0x0e, 0xdb, 0x0b, 0xf5, 0x08, 0x74, 0xdf, 0xdb, 0x3f, 0xe1,
- 0x49, 0x3d, 0xf0, 0x3d, 0xa1, 0x80, 0x6b, 0x57, 0xd3, 0x42, 0x5e, 0x85,
- 0xb1, 0x69, 0x43, 0x0f, 0x8f, 0xbf, 0x21, 0x3f, 0x90, 0x26, 0x3a, 0x6d,
- 0x6c, 0xc1, 0xb7, 0x31, 0x7e, 0xd2, 0xb6, 0xa1, 0x87, 0x47, 0x53, 0x19,
- 0xc5, 0xbd, 0x51, 0x66, 0x1d, 0x94, 0xb4, 0x41, 0x9a, 0x4f, 0xe8, 0xf5,
- 0xd1, 0x8c, 0xbc, 0x2c, 0x99, 0xa6, 0x76, 0xd8, 0x5d, 0xff, 0xb6, 0x73,
- 0x6c, 0xee, 0x2e, 0xd0, 0x34, 0x07, 0xdd, 0xc4, 0x7d, 0xca, 0x9d, 0xf2,
- 0x5e, 0x9e, 0x57, 0x98, 0x70, 0xa0, 0x94, 0x9f, 0xd2, 0x7b, 0xbf, 0x77,
- 0x14, 0x57, 0xcb, 0xad, 0xa9, 0xa8, 0x5d, 0xe7, 0xac, 0x05, 0x1d, 0x40,
- 0x50, 0x9f, 0xaa, 0xc5, 0x13, 0x75, 0x38, 0x7f, 0x17, 0x53, 0x99, 0xa4,
- 0x22, 0xb3, 0xc3, 0xe7, 0x9f, 0x91, 0x2d, 0xde, 0x1e, 0x7d, 0xce, 0x4e,
- 0x9c, 0xba, 0x53, 0x7f, 0xe9, 0xd1, 0x06, 0x25, 0xfd, 0xcc, 0xf8, 0xb5,
- 0x7a, 0x5d, 0xab, 0x3f, 0x15, 0x04, 0x39, 0xcc, 0x5f, 0x41, 0x4c, 0xfc,
- 0x6c, 0xc2, 0x67, 0x1a, 0xfd, 0xda, 0x06, 0xa7, 0xf6, 0x4c, 0xa3, 0x63,
- 0x68, 0x45, 0x22, 0x2a, 0x5d, 0xef, 0xd4, 0x9c, 0xba, 0x93, 0x73, 0x06,
- 0xba, 0xf2, 0x1c, 0x43, 0x57, 0x31, 0x67, 0x9e, 0xae, 0xd6, 0xd9, 0xdf,
- 0x2a, 0x5d, 0x27, 0x99, 0x64, 0x1d, 0xc6, 0xdb, 0x5b, 0x0c, 0x61, 0x3c,
- 0x0c, 0xb8, 0x08, 0xcf, 0xdd, 0x18, 0xc3, 0x30, 0x9e, 0x3c, 0x60, 0x01,
- 0xb3, 0x9f, 0x2a, 0x00, 0xe6, 0x83, 0x78, 0x18, 0x27, 0x6b, 0x76, 0x22,
- 0x13, 0xd5, 0xf0, 0x12, 0xc6, 0x1f, 0x5b, 0x78, 0x5f, 0x0f, 0x56, 0x4f,
- 0x66, 0xba, 0x8b, 0x80, 0x87, 0x70, 0xde, 0x07, 0x18, 0x69, 0x97, 0x8e,
- 0xe2, 0xdb, 0x03, 0x7c, 0x63, 0x16, 0x26, 0xd0, 0xe3, 0xd8, 0x43, 0xf3,
- 0xbf, 0x8b, 0xb4, 0x93, 0x8f, 0xd9, 0xef, 0xd6, 0x45, 0x32, 0xe0, 0x15,
- 0x87, 0x78, 0x1e, 0x29, 0xbd, 0xe6, 0xc0, 0x0e, 0x00, 0xdf, 0xbf, 0xe4,
- 0x44, 0xce, 0xc4, 0xe5, 0x50, 0x91, 0x31, 0x84, 0xe3, 0x0e, 0xe7, 0x41,
- 0xf9, 0x57, 0xa1, 0x4c, 0x5c, 0xc9, 0xc4, 0xd5, 0x78, 0xde, 0x82, 0x67,
- 0x03, 0x9e, 0x8d, 0x78, 0xd6, 0xe3, 0x69, 0xc5, 0xf3, 0x2d, 0x94, 0x53,
- 0xb1, 0x3a, 0xe1, 0x7e, 0xd5, 0x16, 0xa5, 0x34, 0x1f, 0x71, 0xcf, 0xc2,
- 0x65, 0xc0, 0xe5, 0x2b, 0xd0, 0x3b, 0x1e, 0x9e, 0xf1, 0xf8, 0x3a, 0xfa,
- 0x98, 0xc5, 0xd3, 0xa9, 0xe4, 0x4c, 0x17, 0x9e, 0x14, 0x9e, 0x6e, 0x3c,
- 0x3d, 0x78, 0xd2, 0x78, 0x5e, 0x75, 0x0c, 0xcf, 0x5d, 0x02, 0xbe, 0x42,
- 0x1e, 0x01, 0xce, 0x17, 0xf0, 0x9c, 0xe7, 0xbc, 0x09, 0x9e, 0x73, 0x2c,
- 0xcf, 0x39, 0xf3, 0x3c, 0x57, 0xeb, 0xa8, 0x63, 0xf5, 0x4e, 0xe4, 0x18,
- 0x7d, 0x85, 0x5a, 0xc7, 0xf0, 0x7f, 0x44, 0x7a, 0x07, 0x41, 0x4b, 0xc7,
- 0x30, 0x67, 0xc7, 0x48, 0x57, 0x2e, 0xd2, 0xc7, 0x16, 0xf5, 0x3b, 0xfa,
- 0x26, 0xfa, 0x3d, 0x61, 0xfb, 0x7d, 0xb8, 0xaa, 0xdf, 0x83, 0x68, 0xfb,
- 0x3e, 0xdb, 0xef, 0xc1, 0xaa, 0x7e, 0x41, 0x2b, 0xc7, 0xf2, 0x78, 0x48,
- 0x17, 0x23, 0x48, 0x0f, 0x65, 0xc2, 0xdd, 0x6b, 0xa4, 0xbe, 0x46, 0x9f,
- 0x27, 0x8d, 0xf9, 0x35, 0x73, 0xba, 0x31, 0x53, 0xa5, 0x1f, 0x7e, 0x16,
- 0xfd, 0x38, 0x5c, 0xa2, 0x8d, 0x38, 0x5d, 0x25, 0x17, 0xe8, 0xfb, 0x04,
- 0x72, 0x5c, 0xfb, 0x39, 0xf4, 0x79, 0xe8, 0xff, 0x2c, 0xb6, 0xad, 0x3e,
- 0xae, 0xf7, 0xe7, 0xde, 0x55, 0x6c, 0x95, 0x4f, 0x14, 0x69, 0x13, 0x92,
- 0x5e, 0x82, 0x60, 0xcf, 0x36, 0xda, 0xa7, 0xf9, 0x60, 0x9d, 0x9f, 0xd4,
- 0xb1, 0xb5, 0x4f, 0x2e, 0xd5, 0x19, 0xa3, 0xbd, 0xf0, 0xcd, 0xb3, 0x47,
- 0x3f, 0x08, 0x9d, 0x51, 0x03, 0xb8, 0x9f, 0xd2, 0x77, 0x80, 0xec, 0x1a,
- 0x55, 0x23, 0x6b, 0x25, 0x2e, 0x37, 0x17, 0x6b, 0x61, 0xf7, 0x30, 0x56,
- 0x5e, 0x2f, 0xed, 0xdb, 0xa2, 0xe6, 0x6c, 0x8d, 0x17, 0xc3, 0x6f, 0xcf,
- 0x9c, 0xf5, 0x89, 0xc5, 0x91, 0x1f, 0x69, 0xa2, 0x1c, 0x8c, 0xf9, 0xef,
- 0xd4, 0xfb, 0x26, 0xdb, 0xb6, 0xd1, 0x6e, 0xb9, 0x41, 0xeb, 0x70, 0x77,
- 0x89, 0x9d, 0xa4, 0x5a, 0x3c, 0x99, 0xb7, 0xd1, 0x76, 0x17, 0x93, 0x09,
- 0xc2, 0xf5, 0x90, 0x70, 0x3f, 0xc1, 0x7e, 0x29, 0xa4, 0x1a, 0x25, 0x92,
- 0xe6, 0xba, 0x5c, 0xb2, 0x93, 0xb6, 0xd1, 0xc4, 0x98, 0x67, 0xcf, 0x9e,
- 0xac, 0x96, 0x0b, 0xba, 0x9f, 0x5a, 0x0d, 0xa3, 0x39, 0x8f, 0xc6, 0x35,
- 0x2f, 0x9e, 0x81, 0x72, 0xf1, 0x6e, 0xd0, 0x7a, 0x67, 0xa2, 0xcc, 0xb3,
- 0x4e, 0xf0, 0x97, 0xca, 0x31, 0x7d, 0xc6, 0xd4, 0x7b, 0x3b, 0xfc, 0xd8,
- 0xf2, 0x06, 0xd9, 0x3d, 0xb6, 0x82, 0xeb, 0x28, 0xb1, 0xb5, 0xd0, 0x1f,
- 0xac, 0xd3, 0xb6, 0x0d, 0xfe, 0xdf, 0xf8, 0x46, 0x79, 0x7c, 0x9c, 0x6d,
- 0xb7, 0xc8, 0xe4, 0x94, 0x38, 0xde, 0xdb, 0x57, 0xa2, 0x8c, 0xc7, 0xf1,
- 0x08, 0xf7, 0x3c, 0xb5, 0x6d, 0x13, 0xe5, 0xbd, 0xdd, 0x95, 0xf3, 0xdd,
- 0x11, 0xbd, 0x26, 0xe3, 0x82, 0x4e, 0xd8, 0xde, 0xf9, 0xee, 0x56, 0x39,
- 0x3b, 0x05, 0x9a, 0x80, 0xdc, 0xef, 0x3b, 0x45, 0x98, 0x44, 0xb6, 0x4f,
- 0xc0, 0x5e, 0x90, 0x76, 0x3c, 0xa0, 0x0f, 0xc8, 0xef, 0x5b, 0xbb, 0xd9,
- 0x17, 0xf4, 0x12, 0x74, 0x5c, 0xdb, 0x36, 0x23, 0x0b, 0x32, 0x13, 0x35,
- 0x48, 0x67, 0xbb, 0xf0, 0x0f, 0x07, 0xd9, 0x4e, 0x58, 0x57, 0x61, 0x4c,
- 0xb5, 0x9a, 0x5e, 0x66, 0x17, 0xe9, 0x8f, 0x73, 0x3f, 0x97, 0xfd, 0xcd,
- 0x36, 0x3a, 0x41, 0x2b, 0xbe, 0xde, 0xc3, 0x63, 0x6c, 0x2b, 0xce, 0x09,
- 0x6d, 0x22, 0xda, 0x55, 0xd7, 0x6a, 0xfb, 0x62, 0xb2, 0xc2, 0x19, 0xe4,
- 0xda, 0x48, 0x38, 0x47, 0x71, 0x39, 0x59, 0x9a, 0x9b, 0xa7, 0x0d, 0x35,
- 0x0b, 0xe7, 0x89, 0xb4, 0x92, 0x1a, 0xb2, 0xb6, 0xc7, 0x8c, 0x3c, 0x0f,
- 0xbb, 0xac, 0x53, 0xcf, 0xd9, 0x0c, 0x6c, 0x59, 0x3b, 0x67, 0xda, 0x9e,
- 0x2d, 0x84, 0x73, 0x36, 0x00, 0x8d, 0x53, 0xbe, 0x41, 0xcf, 0x99, 0x07,
- 0xba, 0xc9, 0x03, 0xef, 0x79, 0xcc, 0x53, 0x1e, 0x73, 0x94, 0x2f, 0xb7,
- 0xc8, 0xc4, 0x71, 0xd5, 0x5a, 0x23, 0x92, 0xd8, 0xed, 0xb7, 0xc8, 0xf0,
- 0x14, 0x63, 0x05, 0x1b, 0x60, 0x83, 0x6d, 0xc4, 0xd3, 0x8a, 0x6f, 0xd6,
- 0xe3, 0x1d, 0x1f, 0x0a, 0x75, 0xeb, 0x96, 0xd8, 0x59, 0x67, 0xd1, 0xf7,
- 0xd3, 0xc0, 0xc3, 0xa3, 0xc0, 0xc3, 0x3c, 0xef, 0xbc, 0x50, 0x15, 0x5f,
- 0xe2, 0x58, 0xb5, 0x0e, 0xc5, 0x78, 0x63, 0x7a, 0x3e, 0x75, 0x9c, 0xa9,
- 0x54, 0xfb, 0x66, 0xec, 0xa9, 0x38, 0xed, 0xa9, 0xdc, 0xa8, 0x67, 0xce,
- 0x60, 0x0d, 0xc0, 0x77, 0xf2, 0xf7, 0x69, 0x5a, 0x1f, 0x1a, 0x27, 0x5c,
- 0xd1, 0x10, 0xae, 0x05, 0x73, 0xc6, 0x33, 0xb3, 0x4b, 0xe3, 0x18, 0x2f,
- 0xcc, 0xed, 0x11, 0x87, 0x2e, 0x97, 0xd1, 0x14, 0xe3, 0x24, 0xad, 0xcb,
- 0xc0, 0xf4, 0x94, 0xb6, 0x61, 0x45, 0x9d, 0x96, 0x03, 0x25, 0x9e, 0xb7,
- 0xe5, 0x1a, 0xcc, 0xef, 0x31, 0x7e, 0xd4, 0x39, 0x21, 0xc7, 0xd0, 0x37,
- 0xd7, 0xc5, 0x95, 0x8d, 0xcf, 0xac, 0xb2, 0x7b, 0xf2, 0xaa, 0x63, 0x34,
- 0x66, 0xdd, 0x7c, 0xe1, 0xd9, 0x93, 0xe4, 0xc0, 0xac, 0x5e, 0x77, 0xe5,
- 0x9a, 0xa1, 0x8c, 0x46, 0xa0, 0xfd, 0x76, 0x77, 0x27, 0x7b, 0xcc, 0x59,
- 0xc3, 0x84, 0xf4, 0x97, 0xcc, 0xf8, 0x2f, 0xea, 0x7d, 0x93, 0x66, 0x7f,
- 0xb8, 0xd9, 0x53, 0xb9, 0x5f, 0x2e, 0xa6, 0xa2, 0x55, 0x73, 0x5b, 0x27,
- 0xc3, 0xc0, 0x85, 0x5e, 0xcb, 0x84, 0x5d, 0x9c, 0xeb, 0x7e, 0xbc, 0x89,
- 0x67, 0xd1, 0xa2, 0x98, 0x9f, 0xc2, 0x38, 0xcf, 0xa7, 0xb3, 0xdd, 0x2b,
- 0xb5, 0x45, 0x31, 0xcb, 0xb3, 0x4e, 0x90, 0x95, 0x6f, 0xdd, 0x12, 0xaf,
- 0xd7, 0xf9, 0x2b, 0xec, 0x99, 0x16, 0xd8, 0x0d, 0xbb, 0x02, 0xf9, 0x33,
- 0xe8, 0xc9, 0xd3, 0x76, 0x4c, 0x09, 0x1d, 0x93, 0x92, 0xe0, 0x7c, 0x2a,
- 0x6e, 0xe3, 0xce, 0x1c, 0xcb, 0x98, 0xa5, 0x6f, 0x63, 0xff, 0xcc, 0xdb,
- 0xd0, 0x5d, 0x9a, 0xd6, 0x1f, 0xd7, 0xb2, 0xb0, 0xcb, 0xda, 0xce, 0x3a,
- 0x8e, 0x73, 0x42, 0xf4, 0x1e, 0xac, 0xd0, 0x37, 0xea, 0xa8, 0xf2, 0x0b,
- 0x8c, 0x2f, 0x57, 0x18, 0x5b, 0x4e, 0x46, 0xcd, 0xfb, 0x84, 0xf4, 0xe5,
- 0xf6, 0x6c, 0xe2, 0xdd, 0x30, 0xa1, 0x2f, 0xd7, 0x65, 0x7d, 0xb9, 0x46,
- 0xed, 0xcb, 0x99, 0xd8, 0x43, 0xe3, 0x9c, 0x2f, 0x57, 0x18, 0xcb, 0x83,
- 0x56, 0x6a, 0xed, 0x59, 0x09, 0x63, 0x0b, 0x0d, 0x17, 0x5d, 0xbd, 0x6f,
- 0x24, 0x37, 0xa0, 0xe0, 0x37, 0x18, 0x1f, 0x8b, 0xb1, 0x0a, 0xa5, 0xfe,
- 0xce, 0xfa, 0x17, 0x1b, 0x24, 0xd3, 0xbc, 0x02, 0xe3, 0x7e, 0x4a, 0xcf,
- 0xb9, 0x59, 0xc3, 0x82, 0x5c, 0x1b, 0x64, 0xcc, 0x87, 0x67, 0x47, 0x35,
- 0x7f, 0x25, 0x7a, 0x23, 0x9d, 0xc6, 0x9e, 0xf5, 0x13, 0x6b, 0xa5, 0xfe,
- 0xb8, 0x53, 0x18, 0x8f, 0xda, 0x7e, 0x13, 0x80, 0xa9, 0x06, 0x73, 0xf3,
- 0x4e, 0x2b, 0x93, 0xd9, 0xf7, 0x3b, 0xea, 0x18, 0x1b, 0x98, 0x2a, 0x9a,
- 0x18, 0x60, 0x5f, 0x31, 0x12, 0x9e, 0x5b, 0x57, 0x5c, 0x47, 0xce, 0x0c,
- 0xae, 0x00, 0x2c, 0x2b, 0x96, 0xb5, 0x59, 0x1f, 0x7b, 0x43, 0x1d, 0x45,
- 0x9a, 0x7a, 0x4a, 0xef, 0x2f, 0x5c, 0xd9, 0x9d, 0xdc, 0xa9, 0xcf, 0x23,
- 0xe9, 0x58, 0x62, 0x5e, 0xb8, 0x7f, 0xf7, 0x9b, 0xf2, 0x36, 0x2d, 0xfb,
- 0x0f, 0xa4, 0xa8, 0xc7, 0xb6, 0xe9, 0xdf, 0xb5, 0xe9, 0x20, 0x38, 0xdf,
- 0xfd, 0x2c, 0x6c, 0x16, 0xdf, 0xfb, 0x96, 0xb4, 0xc7, 0x7b, 0xb5, 0x0d,
- 0x85, 0xb9, 0x1a, 0xac, 0x97, 0x15, 0xfe, 0xb8, 0xdd, 0xab, 0x68, 0xd6,
- 0x03, 0x0b, 0xc2, 0xfb, 0x17, 0x3a, 0x6c, 0x5e, 0x3e, 0xa8, 0x07, 0x3d,
- 0x7d, 0x44, 0x8c, 0xac, 0xc9, 0xcd, 0xcb, 0x1a, 0xee, 0xa7, 0xcb, 0x90,
- 0xa0, 0xdd, 0x23, 0x92, 0xe4, 0xdd, 0x49, 0xec, 0xbb, 0x20, 0x57, 0x41,
- 0x3f, 0xb3, 0x1e, 0x6d, 0x56, 0x7e, 0x73, 0x0f, 0x8a, 0xef, 0x1d, 0x84,
- 0x8e, 0xb9, 0x61, 0xa9, 0x8e, 0x89, 0xd3, 0xbf, 0xcf, 0x8d, 0xd2, 0x47,
- 0x5c, 0x89, 0x3a, 0x2d, 0xf2, 0xd1, 0xb1, 0xdf, 0x5a, 0x4b, 0x1e, 0x1b,
- 0x82, 0x7c, 0x57, 0xf7, 0x87, 0xe7, 0x2e, 0x99, 0xc6, 0x7c, 0xb6, 0x5b,
- 0x27, 0x89, 0xf7, 0x79, 0xf2, 0xc5, 0x4a, 0x32, 0x31, 0x0b, 0x1d, 0x35,
- 0xe4, 0x0c, 0xb7, 0x9a, 0xd8, 0xe9, 0xa7, 0xd6, 0x9a, 0x73, 0x5a, 0xf5,
- 0xc0, 0x69, 0x18, 0x4f, 0xad, 0xa6, 0xdd, 0x59, 0x2b, 0x97, 0x83, 0xa0,
- 0xbe, 0x5b, 0xcb, 0xe2, 0x9d, 0x94, 0xc5, 0x07, 0x52, 0x1d, 0x86, 0x07,
- 0xb4, 0xef, 0xc4, 0x3d, 0x00, 0xc0, 0x43, 0xb7, 0xcb, 0xbd, 0xd0, 0x96,
- 0x4f, 0xfd, 0xcc, 0x8c, 0x95, 0x4f, 0xca, 0x59, 0xca, 0x9f, 0x6a, 0x6b,
- 0x74, 0x81, 0xec, 0x3d, 0x34, 0x46, 0xbd, 0x9c, 0x9a, 0xfe, 0x26, 0xe4,
- 0x55, 0x4e, 0xe3, 0xa1, 0x45, 0xee, 0x1b, 0x93, 0xcc, 0x45, 0xe8, 0xac,
- 0xc2, 0xd4, 0x42, 0x1e, 0x5d, 0xda, 0x1e, 0xc7, 0x7a, 0x7a, 0xad, 0xf1,
- 0x71, 0x17, 0x8e, 0x75, 0x9a, 0x7b, 0x8c, 0xf4, 0x58, 0xb9, 0x37, 0xff,
- 0x9c, 0x1d, 0xeb, 0xca, 0x70, 0xac, 0x3d, 0x0b, 0xc7, 0x1a, 0xfa, 0xf8,
- 0xa1, 0xfc, 0x4d, 0xe8, 0xb3, 0x49, 0xfa, 0x4c, 0xcc, 0xd8, 0x4a, 0xe9,
- 0x1d, 0x6d, 0xb4, 0x72, 0xd3, 0x83, 0x0e, 0xe2, 0x79, 0xa1, 0xe9, 0xcf,
- 0x79, 0x62, 0x71, 0xa6, 0x88, 0x07, 0xca, 0xdc, 0x26, 0x7d, 0x9e, 0x71,
- 0x02, 0x7e, 0xd6, 0x87, 0x8b, 0x2c, 0x1b, 0xe6, 0x5f, 0x29, 0x46, 0x1c,
- 0xfa, 0xd6, 0xf4, 0x9f, 0x3a, 0x97, 0xc4, 0x16, 0x4c, 0x1c, 0x98, 0xf1,
- 0x5f, 0x73, 0xcf, 0x02, 0xf7, 0x7d, 0xdf, 0x01, 0xde, 0xfa, 0xed, 0x62,
- 0xb2, 0x27, 0x1b, 0xa1, 0x3c, 0x9d, 0x95, 0x43, 0x95, 0x3e, 0x69, 0xd3,
- 0x67, 0xed, 0xdf, 0x30, 0x46, 0x9c, 0xa9, 0x8e, 0x11, 0x8b, 0x63, 0x62,
- 0xc4, 0x3b, 0x7f, 0x8e, 0x18, 0xb1, 0x38, 0x26, 0x46, 0xbc, 0x9c, 0x9f,
- 0x35, 0x52, 0x9a, 0xc5, 0xb8, 0xea, 0x21, 0x53, 0x94, 0x93, 0x9b, 0x6a,
- 0xc0, 0xbb, 0x16, 0x6f, 0xc0, 0x32, 0x56, 0xc0, 0xdb, 0xc3, 0xfb, 0x20,
- 0xde, 0x31, 0x19, 0x99, 0xd3, 0x1d, 0xb3, 0x90, 0x1f, 0xd4, 0x69, 0xac,
- 0x6b, 0xfc, 0x82, 0xc9, 0x72, 0x33, 0xca, 0x5d, 0x72, 0x26, 0x58, 0xaf,
- 0xd4, 0x28, 0xc3, 0x63, 0x94, 0xdd, 0x4d, 0x32, 0x3a, 0x16, 0xda, 0xb8,
- 0x9f, 0x5d, 0xcf, 0xb5, 0x81, 0x21, 0x09, 0x6d, 0xd8, 0x67, 0xd6, 0x9b,
- 0xb5, 0xdb, 0x2d, 0x31, 0xa9, 0x5f, 0x8d, 0x39, 0x38, 0xee, 0x5c, 0x1c,
- 0x5f, 0xbd, 0xc0, 0x96, 0x4d, 0xd8, 0xd8, 0xe0, 0xb8, 0xd5, 0xc1, 0xcb,
- 0xcb, 0x88, 0xea, 0xf9, 0x8f, 0xdb, 0x73, 0xbc, 0x51, 0x7b, 0xd7, 0x5f,
- 0x42, 0xcf, 0xcf, 0x40, 0x65, 0x16, 0xfd, 0xad, 0x57, 0x99, 0x71, 0x8e,
- 0x73, 0xee, 0x7e, 0x1e, 0xc8, 0xc5, 0x56, 0x35, 0x34, 0xbe, 0x80, 0x2e,
- 0x41, 0xb7, 0x1c, 0x9b, 0x03, 0xda, 0xbd, 0x57, 0x26, 0x46, 0x09, 0x5f,
- 0x47, 0x3c, 0xa2, 0xcf, 0xf5, 0xe2, 0x7b, 0xdc, 0x9c, 0x27, 0xea, 0xad,
- 0x84, 0x67, 0x7a, 0xd7, 0x00, 0xde, 0xc5, 0xe7, 0x7a, 0xad, 0x9e, 0xd6,
- 0x36, 0x04, 0xcf, 0xf7, 0x86, 0x63, 0x58, 0x8e, 0x9e, 0x02, 0x19, 0xd6,
- 0xfb, 0x7d, 0xd7, 0xca, 0xe9, 0x07, 0xe7, 0xce, 0x17, 0x34, 0xc1, 0x56,
- 0x69, 0x85, 0xa9, 0x3c, 0xe0, 0xa6, 0xb9, 0xef, 0x82, 0xfb, 0x0b, 0x3a,
- 0xe2, 0xb7, 0xe9, 0x73, 0x1f, 0xf3, 0x67, 0xac, 0xe7, 0xcf, 0x7e, 0x84,
- 0x67, 0x5a, 0xe3, 0xd2, 0x07, 0x3a, 0xec, 0xd7, 0xe9, 0x31, 0x8c, 0x87,
- 0x6b, 0xbe, 0x1a, 0x0f, 0x90, 0x3d, 0x5c, 0xfb, 0xc5, 0xd8, 0x2b, 0x2d,
- 0x2a, 0xa7, 0xcf, 0x58, 0x47, 0x2d, 0x8d, 0x5d, 0x76, 0xf6, 0x94, 0x13,
- 0x6a, 0x4f, 0xd9, 0x57, 0x7b, 0xcb, 0x36, 0xaf, 0xfb, 0x01, 0xcc, 0x07,
- 0x7e, 0x8f, 0x17, 0x9d, 0x21, 0xe0, 0xab, 0x50, 0x3a, 0xe2, 0x64, 0xf4,
- 0xfb, 0xa8, 0x7d, 0x43, 0x0e, 0x60, 0xae, 0x7a, 0xc7, 0xa3, 0x5a, 0xde,
- 0xcf, 0xdf, 0xd3, 0x17, 0xce, 0xeb, 0x0b, 0x7a, 0x0d, 0x68, 0x5a, 0x88,
- 0x6b, 0xcf, 0xda, 0x10, 0xc7, 0x9d, 0x9c, 0xc6, 0x3d, 0xcb, 0x7c, 0x4b,
- 0xff, 0x06, 0x9d, 0x2b, 0xd3, 0x5e, 0x2b, 0xde, 0x8b, 0xf7, 0x4d, 0x86,
- 0xfa, 0x86, 0x70, 0xdf, 0x09, 0xbd, 0x16, 0xec, 0x37, 0xf2, 0x6a, 0x56,
- 0x46, 0x2a, 0x5c, 0xc3, 0x64, 0x3b, 0x48, 0x2f, 0xd7, 0xc0, 0x1e, 0x58,
- 0x78, 0xbe, 0xba, 0x7f, 0x7e, 0x1e, 0x12, 0xe3, 0x42, 0x58, 0xee, 0xd6,
- 0x67, 0x17, 0xab, 0xef, 0x1e, 0xb9, 0xf2, 0xbf, 0x70, 0xfd, 0xd0, 0xc8,
- 0x50, 0x0b, 0x47, 0x86, 0xf2, 0xce, 0xc8, 0x95, 0xaf, 0xcb, 0x41, 0xe0,
- 0xf1, 0x30, 0x60, 0x52, 0xf7, 0xf3, 0xce, 0xab, 0x57, 0xa5, 0x30, 0x59,
- 0x2f, 0xea, 0xa1, 0x82, 0xe3, 0x3e, 0x54, 0x2b, 0x91, 0x87, 0x94, 0x53,
- 0xf3, 0x50, 0xbb, 0xf6, 0xcf, 0x77, 0xa4, 0xda, 0xe3, 0x7b, 0xe5, 0xb8,
- 0xe3, 0xde, 0xaf, 0xf4, 0x59, 0xdb, 0x82, 0xc7, 0x58, 0xdf, 0x71, 0x27,
- 0x72, 0x7f, 0xd4, 0x9e, 0xd3, 0x37, 0xf1, 0xbd, 0x59, 0xcd, 0xf7, 0xdf,
- 0x58, 0x47, 0x9c, 0xcd, 0x0a, 0xf1, 0xf1, 0x59, 0xc8, 0xad, 0x4f, 0x4b,
- 0x76, 0x34, 0x31, 0x57, 0xc6, 0xec, 0xb3, 0xdf, 0xb0, 0xce, 0xf0, 0x0b,
- 0xcb, 0xbc, 0xe2, 0xf0, 0xce, 0x1c, 0xa3, 0x33, 0x3e, 0xdf, 0x12, 0xee,
- 0xb9, 0x37, 0x73, 0xca, 0xfc, 0xc6, 0x75, 0x52, 0xff, 0x0a, 0xe6, 0x8b,
- 0xfd, 0x11, 0x57, 0xab, 0xf4, 0x3d, 0x05, 0x9e, 0x6c, 0x89, 0xd7, 0xcd,
- 0xd9, 0x43, 0x46, 0xf6, 0xd6, 0x01, 0x6e, 0xc0, 0x6f, 0xec, 0x3b, 0x21,
- 0x9d, 0x0a, 0x24, 0x37, 0x69, 0xb6, 0xa3, 0x67, 0x87, 0x98, 0x39, 0x33,
- 0x34, 0xb3, 0xc2, 0xd8, 0x91, 0xf8, 0x36, 0x74, 0xa1, 0x64, 0xfb, 0xd8,
- 0x4b, 0x4e, 0x3f, 0xcf, 0x3c, 0x8a, 0xb6, 0x1b, 0x97, 0xb3, 0x09, 0xc1,
- 0x4b, 0xcf, 0x5b, 0xff, 0x32, 0x08, 0xc6, 0x52, 0x29, 0xde, 0x2b, 0xb8,
- 0x8c, 0x4f, 0xb9, 0xca, 0x99, 0x1c, 0x6d, 0x70, 0x26, 0x46, 0x03, 0xd9,
- 0x93, 0xe2, 0x9d, 0x49, 0xdc, 0x93, 0xa0, 0xe3, 0xe3, 0x48, 0x6b, 0x87,
- 0x6e, 0x7d, 0xc7, 0x3a, 0xee, 0x71, 0xbb, 0xd9, 0x6f, 0xb4, 0xe5, 0x88,
- 0x63, 0xfa, 0xca, 0xed, 0x27, 0x72, 0xc2, 0xbb, 0x8b, 0xb6, 0xc4, 0x63,
- 0x7a, 0x7f, 0xe2, 0x17, 0x50, 0x0f, 0x7d, 0x94, 0xd8, 0xaf, 0xeb, 0x4c,
- 0x40, 0x9e, 0x4d, 0x8e, 0xf1, 0xbe, 0x14, 0x9e, 0x63, 0x88, 0xb4, 0x2a,
- 0xb9, 0xd6, 0x1b, 0xb6, 0xf7, 0x69, 0xe6, 0xe1, 0x0a, 0x45, 0x74, 0xda,
- 0x16, 0x6f, 0xf7, 0xdc, 0x1d, 0x9b, 0x61, 0x5a, 0x78, 0xd7, 0xa6, 0xd2,
- 0x67, 0x56, 0xe0, 0xd3, 0x9e, 0x1e, 0x92, 0xb8, 0x33, 0x55, 0x6c, 0x75,
- 0x4e, 0x16, 0x33, 0x5b, 0xd7, 0x81, 0x3e, 0xce, 0xa7, 0x3e, 0x46, 0xf9,
- 0x05, 0xdb, 0xef, 0x45, 0xc9, 0x57, 0x3e, 0x24, 0xe3, 0x2d, 0xed, 0xde,
- 0xfd, 0x7a, 0x6e, 0x2e, 0x03, 0x67, 0x2d, 0x2a, 0x3b, 0xfa, 0xc4, 0x3a,
- 0xea, 0xb7, 0xdd, 0x45, 0x05, 0x5e, 0x56, 0xbf, 0x88, 0x07, 0x36, 0x6e,
- 0xad, 0xb6, 0x51, 0xf6, 0xa6, 0x58, 0xae, 0xc1, 0xe9, 0x1d, 0x5d, 0x85,
- 0x79, 0xdc, 0x05, 0xfd, 0xe9, 0xc0, 0x46, 0x22, 0xae, 0x1b, 0x9c, 0x3d,
- 0xa3, 0x79, 0xf4, 0xc8, 0x7d, 0xd6, 0xbc, 0xf7, 0xf0, 0x30, 0xc6, 0xa8,
- 0xe5, 0x2b, 0x78, 0xf7, 0x12, 0xd7, 0xdb, 0x83, 0x49, 0xd8, 0x06, 0xb9,
- 0xae, 0x7f, 0x67, 0xd7, 0xab, 0xa7, 0xaf, 0xb0, 0x5e, 0xed, 0xc9, 0x23,
- 0x15, 0x7d, 0x6f, 0x48, 0xe7, 0xb8, 0xe2, 0x3a, 0x6e, 0xf3, 0x55, 0x7a,
- 0x7e, 0x54, 0x87, 0xdd, 0x1b, 0x78, 0x72, 0x9d, 0xbd, 0xd3, 0x06, 0x70,
- 0x5c, 0x05, 0x18, 0x36, 0x62, 0xfc, 0x84, 0xc1, 0xd4, 0x11, 0x75, 0x4b,
- 0x9c, 0x3a, 0x70, 0x56, 0x4e, 0xaf, 0x0b, 0xf7, 0x7b, 0xa0, 0x1d, 0xc8,
- 0xb5, 0x47, 0xe3, 0x46, 0x37, 0xae, 0x5d, 0xa6, 0x9d, 0x70, 0x3c, 0x8e,
- 0x1d, 0x0f, 0x69, 0x75, 0x43, 0x0b, 0xfd, 0x89, 0x59, 0xa9, 0x5b, 0x54,
- 0x9e, 0xf1, 0xfc, 0x5d, 0xad, 0x66, 0xdf, 0x11, 0xcb, 0x7a, 0xb0, 0x4b,
- 0x69, 0xe3, 0x12, 0x77, 0x7a, 0xae, 0x8a, 0xdc, 0x5b, 0x9c, 0xf3, 0x2f,
- 0x43, 0x9e, 0x5c, 0xeb, 0xbd, 0x4d, 0x91, 0xf6, 0x42, 0xfc, 0x12, 0xb7,
- 0x09, 0xe0, 0x95, 0x71, 0x95, 0xd3, 0x41, 0x66, 0x80, 0x7c, 0xc5, 0x36,
- 0x98, 0xff, 0xa2, 0x8e, 0xe5, 0x0e, 0xa6, 0x18, 0x27, 0x6a, 0x3f, 0x71,
- 0x87, 0x0a, 0x65, 0xd3, 0x2c, 0xd7, 0x10, 0x1c, 0xde, 0x21, 0xba, 0x0b,
- 0x1d, 0x5e, 0x9c, 0x52, 0xce, 0x37, 0xc7, 0x5c, 0x7c, 0xd7, 0xd8, 0xfb,
- 0x42, 0x8d, 0x6e, 0x12, 0xf9, 0xeb, 0x70, 0xbc, 0xf1, 0x3c, 0xe6, 0xfb,
- 0x12, 0xe6, 0x7b, 0xf9, 0xfb, 0x41, 0x91, 0x57, 0x46, 0x5e, 0xf9, 0x43,
- 0x41, 0xa6, 0x89, 0xf4, 0x47, 0x9a, 0x7b, 0x3d, 0x9f, 0x59, 0xef, 0x63,
- 0x02, 0x6c, 0x67, 0xc1, 0x0b, 0x19, 0xae, 0x25, 0x07, 0xc7, 0x52, 0x37,
- 0x81, 0x17, 0x76, 0xca, 0x9f, 0xc0, 0x16, 0xf8, 0xe3, 0x4a, 0x1a, 0x3c,
- 0xd1, 0x03, 0x1e, 0xe9, 0x06, 0x5f, 0xa4, 0xb4, 0x5d, 0xfc, 0x28, 0x74,
- 0xde, 0xd9, 0x4a, 0xc9, 0xd9, 0x3b, 0x5a, 0x74, 0x72, 0xa3, 0x47, 0x41,
- 0x17, 0xdc, 0x03, 0xab, 0xae, 0xa9, 0x11, 0x37, 0x3e, 0x29, 0xa4, 0xff,
- 0x76, 0xee, 0xed, 0x68, 0x06, 0xae, 0xce, 0x10, 0x57, 0x93, 0x95, 0x2d,
- 0xde, 0x3a, 0xf0, 0x41, 0xb3, 0xe6, 0x83, 0x46, 0x27, 0xe3, 0xdd, 0x64,
- 0xf9, 0x60, 0x04, 0x7c, 0x50, 0x58, 0xc2, 0x07, 0xcf, 0x58, 0x9a, 0x9f,
- 0xae, 0xe2, 0x83, 0x49, 0x9b, 0x36, 0x7e, 0x05, 0x3e, 0xb8, 0xca, 0x4f,
- 0x3e, 0x39, 0x24, 0x27, 0xc0, 0x07, 0x0f, 0x6b, 0x3e, 0xb8, 0x4a, 0xf3,
- 0x01, 0xe3, 0x46, 0xe4, 0x85, 0x56, 0xc8, 0x0e, 0xf2, 0xc2, 0xb3, 0x32,
- 0x0b, 0x5e, 0x78, 0x51, 0xb1, 0xef, 0xcb, 0xb4, 0x0f, 0x46, 0xe9, 0x8f,
- 0x9d, 0x2a, 0x15, 0xc1, 0xbb, 0x4a, 0xbe, 0x30, 0x16, 0x04, 0x33, 0xf0,
- 0xd1, 0x1f, 0x84, 0x0d, 0xef, 0xea, 0x3b, 0x69, 0xa7, 0x61, 0xbb, 0x10,
- 0x36, 0xda, 0xe4, 0xe3, 0x0e, 0xe8, 0xfd, 0xf0, 0x04, 0xc6, 0xb0, 0x47,
- 0xfd, 0x3e, 0xfc, 0x60, 0x0f, 0xf3, 0x4a, 0xdb, 0xfe, 0xb8, 0xe6, 0x9b,
- 0x1a, 0xe8, 0x80, 0x93, 0xdd, 0x8c, 0x33, 0xf9, 0xde, 0x5e, 0xd5, 0x9e,
- 0xef, 0x03, 0xcc, 0x11, 0x75, 0xbf, 0x30, 0xc6, 0xd1, 0xb4, 0xc8, 0xb6,
- 0xa7, 0x5c, 0x18, 0x90, 0xfb, 0x6c, 0x5e, 0x3e, 0xa8, 0x83, 0x1d, 0x5a,
- 0xa7, 0x8c, 0x5d, 0xae, 0xb6, 0x25, 0xbd, 0xdf, 0x80, 0xd0, 0xac, 0x4d,
- 0x9b, 0x3d, 0x81, 0x7d, 0xc5, 0x6a, 0xbb, 0xfe, 0x5e, 0xd8, 0xf5, 0xac,
- 0x23, 0xae, 0xb1, 0xeb, 0xef, 0xb2, 0xbc, 0xc6, 0xdf, 0x9e, 0xb6, 0xf1,
- 0x0f, 0x00, 0xbe, 0x1d, 0x73, 0x36, 0x3e, 0xdb, 0xa0, 0xad, 0x21, 0x72,
- 0x03, 0xec, 0xbc, 0x1b, 0xc1, 0x83, 0x37, 0xc1, 0x8f, 0x7a, 0x77, 0xd1,
- 0x93, 0x9d, 0xc5, 0x66, 0xf8, 0xdb, 0xad, 0xf2, 0xab, 0x63, 0x1b, 0xa5,
- 0x7f, 0xf4, 0x77, 0x9a, 0xa1, 0x57, 0x61, 0x97, 0xbe, 0x08, 0x38, 0x23,
- 0x56, 0x56, 0x47, 0xc1, 0x03, 0xed, 0x89, 0x1f, 0xa8, 0x44, 0xab, 0x91,
- 0xed, 0x3c, 0x4b, 0xbe, 0x5c, 0x3b, 0x31, 0xd4, 0x67, 0x1c, 0xa5, 0x45,
- 0xce, 0x1c, 0xa7, 0xe7, 0x95, 0x80, 0x2d, 0x9e, 0x82, 0x1d, 0xb2, 0x01,
- 0xed, 0x31, 0x96, 0xbc, 0x5a, 0x9e, 0xd9, 0xea, 0xde, 0x9d, 0xd3, 0x7c,
- 0x78, 0xc9, 0xc9, 0x8e, 0xdd, 0x24, 0x85, 0xc1, 0x28, 0xc6, 0xa0, 0x9a,
- 0xd7, 0xca, 0xf5, 0xd2, 0xaf, 0xc7, 0x73, 0x59, 0x0e, 0x42, 0x1f, 0xff,
- 0x69, 0xb1, 0x5f, 0x66, 0x07, 0x9a, 0xf0, 0x1d, 0x95, 0x67, 0x8a, 0x5b,
- 0xe0, 0xef, 0xfc, 0x0a, 0x70, 0x54, 0x8b, 0xef, 0x5a, 0xe9, 0x5d, 0x47,
- 0x5e, 0x6d, 0x90, 0x19, 0xa4, 0xdf, 0x28, 0xbf, 0x64, 0xd3, 0x99, 0x46,
- 0xde, 0x68, 0x40, 0xdd, 0xa8, 0x9c, 0x2f, 0xd2, 0x96, 0xd4, 0x3c, 0xd1,
- 0xf3, 0xb2, 0x6c, 0xc9, 0xbc, 0x0c, 0xdb, 0xf4, 0x59, 0x3c, 0xcf, 0x4b,
- 0x72, 0xe7, 0x6e, 0x67, 0x4b, 0xa2, 0xdd, 0x81, 0xbe, 0xc4, 0xe3, 0x3a,
- 0x5b, 0xbc, 0x5a, 0xe7, 0x5a, 0xdb, 0x46, 0x8d, 0x3c, 0x3f, 0xa8, 0xe2,
- 0x0d, 0x98, 0x93, 0xcd, 0x4e, 0x87, 0x4d, 0xe3, 0xb7, 0xbe, 0x2f, 0x51,
- 0xda, 0xcf, 0xa8, 0x0d, 0xab, 0x44, 0xda, 0x1a, 0x60, 0xe7, 0xec, 0x11,
- 0xd5, 0xdc, 0x20, 0xae, 0xb4, 0x4f, 0xa8, 0x56, 0xa4, 0xf9, 0x36, 0x2d,
- 0xd6, 0x00, 0x9d, 0x80, 0xb4, 0x16, 0xa4, 0x6d, 0xb2, 0x69, 0x4d, 0x0d,
- 0x52, 0x8b, 0xb4, 0xcb, 0x9a, 0xe7, 0x2f, 0x76, 0xf8, 0x5e, 0xce, 0xa9,
- 0x97, 0xb6, 0x53, 0x0d, 0x90, 0x0d, 0xab, 0x65, 0x66, 0x6b, 0x9d, 0xb4,
- 0x21, 0x8f, 0x31, 0xee, 0xd4, 0xa9, 0xa8, 0xbc, 0xf3, 0x54, 0x7b, 0xfc,
- 0xa3, 0x18, 0x43, 0xfb, 0x19, 0xc6, 0xbc, 0xff, 0xac, 0x99, 0x31, 0x9f,
- 0xb6, 0x33, 0x7c, 0xd7, 0x69, 0xf9, 0x43, 0x7c, 0x98, 0x3b, 0xdf, 0x60,
- 0x63, 0x94, 0x8e, 0x3b, 0xc3, 0xa3, 0xd4, 0xdb, 0xed, 0xf6, 0x7e, 0xa2,
- 0xff, 0xd9, 0x4c, 0x5f, 0x6d, 0x82, 0x36, 0x54, 0x89, 0xfc, 0x48, 0xdd,
- 0x83, 0xf7, 0xb8, 0x23, 0x85, 0x79, 0x99, 0x35, 0x45, 0xbe, 0x3a, 0xae,
- 0xb8, 0x4f, 0x05, 0x69, 0x95, 0x77, 0x05, 0x66, 0x8e, 0xc9, 0x0b, 0x46,
- 0x2e, 0xfd, 0x9a, 0x91, 0x4b, 0xa7, 0xcf, 0x2d, 0x90, 0x4b, 0x05, 0x2d,
- 0x97, 0x06, 0x05, 0xef, 0xa9, 0x02, 0xe4, 0xd2, 0x08, 0xbe, 0x3d, 0x2d,
- 0x97, 0x62, 0x62, 0x6d, 0x64, 0x89, 0x5e, 0xc5, 0xfe, 0x27, 0x4b, 0xae,
- 0xb6, 0xa5, 0x0a, 0xe3, 0xb0, 0x43, 0x4a, 0x23, 0x56, 0x67, 0x4b, 0xba,
- 0x49, 0x3a, 0x7a, 0x7e, 0x2a, 0xa1, 0x9d, 0x39, 0xdb, 0xcc, 0x3b, 0x8f,
- 0x5f, 0x54, 0x94, 0x61, 0x27, 0x20, 0xc3, 0x1e, 0xbe, 0x82, 0x0c, 0x43,
- 0x5e, 0x19, 0x79, 0x65, 0xb6, 0xfb, 0xdd, 0x9f, 0x0e, 0x79, 0x94, 0x1f,
- 0x94, 0x19, 0x90, 0x49, 0x25, 0xc8, 0xa4, 0x12, 0xe4, 0x54, 0x09, 0x72,
- 0xa9, 0x04, 0xb9, 0x54, 0x82, 0x5c, 0x2a, 0x41, 0x2e, 0x41, 0xc6, 0x3d,
- 0x0a, 0x19, 0x67, 0x64, 0xda, 0x00, 0xed, 0x35, 0xb9, 0xcf, 0xea, 0x77,
- 0x13, 0x27, 0xe9, 0xb2, 0x7e, 0x91, 0xd9, 0xb3, 0x7a, 0xae, 0x2a, 0x2e,
- 0xb8, 0xeb, 0x88, 0xe6, 0x77, 0xcf, 0x57, 0xd7, 0x3a, 0xdc, 0x1f, 0xf3,
- 0x03, 0xed, 0xb3, 0x6f, 0xe6, 0x6f, 0xa9, 0x03, 0x5f, 0xbf, 0x62, 0xf9,
- 0x7a, 0xf3, 0x1c, 0x5f, 0x27, 0x1d, 0xc6, 0x89, 0x97, 0xe7, 0xeb, 0x16,
- 0x9b, 0x97, 0x0f, 0x56, 0x80, 0xaf, 0x57, 0x2c, 0xe2, 0xeb, 0x28, 0xf8,
- 0x7a, 0xe7, 0x12, 0xbe, 0x5e, 0xe5, 0xf4, 0xea, 0x3a, 0x3c, 0x83, 0xc6,
- 0xef, 0x5a, 0x67, 0x9e, 0xaf, 0xf7, 0x6b, 0xbe, 0x3e, 0x04, 0xbe, 0xbe,
- 0xbe, 0x8a, 0xaf, 0x77, 0x4a, 0xf2, 0x96, 0x6c, 0x64, 0xa3, 0xec, 0xbe,
- 0x5f, 0x35, 0xaf, 0x91, 0x7f, 0x11, 0x53, 0xdf, 0xf0, 0x58, 0xef, 0x58,
- 0xb3, 0xe4, 0x1e, 0xfa, 0x11, 0xd7, 0x06, 0xc8, 0x23, 0x43, 0x19, 0xc7,
- 0x93, 0x83, 0x47, 0x7e, 0x20, 0xd3, 0x9a, 0xb7, 0x44, 0xf6, 0x1c, 0x89,
- 0xca, 0xf0, 0x11, 0xc6, 0x1e, 0xbe, 0x63, 0xe9, 0xbd, 0x4e, 0x86, 0x07,
- 0xb9, 0x5f, 0xd2, 0x95, 0xdd, 0x47, 0xe0, 0x63, 0x1d, 0x61, 0xec, 0xe1,
- 0xf2, 0x1c, 0x8f, 0x4d, 0x43, 0xb6, 0xec, 0x3e, 0xa2, 0xe7, 0x1a, 0xed,
- 0x34, 0xc8, 0xa1, 0x23, 0x22, 0xb7, 0x1d, 0x71, 0xe5, 0xf6, 0x23, 0x73,
- 0xbc, 0x36, 0x10, 0xf2, 0xda, 0x9f, 0x83, 0xd7, 0xda, 0x2d, 0xaf, 0xa9,
- 0x39, 0x5e, 0xfb, 0x5a, 0x15, 0xaf, 0xb1, 0x3e, 0x79, 0xed, 0x82, 0x4d,
- 0xe3, 0xb7, 0x2b, 0x7b, 0x8f, 0xb4, 0xca, 0xee, 0x87, 0xde, 0x22, 0x7b,
- 0xee, 0x27, 0xac, 0xe6, 0x9e, 0x3c, 0xda, 0x5f, 0xe3, 0x95, 0x76, 0xb4,
- 0x1f, 0xee, 0x0f, 0xd2, 0x77, 0x65, 0x75, 0x4e, 0x48, 0x32, 0xcf, 0xfe,
- 0x6a, 0xe1, 0x3b, 0x9f, 0x82, 0x4f, 0xb1, 0x17, 0x30, 0xdd, 0x7a, 0x44,
- 0x92, 0xae, 0xbc, 0x26, 0x23, 0xa9, 0x47, 0x5b, 0x8d, 0x3d, 0x71, 0x09,
- 0xbc, 0x42, 0xfa, 0xcf, 0x48, 0xee, 0xed, 0x81, 0xf6, 0x2b, 0x46, 0xcb,
- 0x42, 0xff, 0x9f, 0x31, 0x73, 0xc7, 0xdc, 0x77, 0xc7, 0xf3, 0xbe, 0x35,
- 0xfa, 0xbc, 0x9b, 0x8e, 0xd7, 0x76, 0x33, 0xbf, 0x46, 0xef, 0x37, 0xcd,
- 0xe9, 0xb3, 0xdc, 0xac, 0xcf, 0x76, 0x62, 0x3a, 0x9e, 0x5e, 0x28, 0xf3,
- 0x8e, 0x30, 0xde, 0xbd, 0xcc, 0xbb, 0x06, 0xff, 0xf8, 0x2a, 0x13, 0x9b,
- 0x25, 0xdf, 0x7d, 0xdd, 0xc9, 0x15, 0x2f, 0xe9, 0x7d, 0x85, 0x59, 0x1f,
- 0xbf, 0xcb, 0xfc, 0x66, 0xf9, 0x4b, 0x8c, 0x71, 0x24, 0x12, 0xea, 0x81,
- 0x56, 0xee, 0x3b, 0x18, 0x9c, 0x32, 0x76, 0x94, 0xe1, 0xd1, 0x06, 0xed,
- 0x6b, 0x8c, 0xe0, 0x7b, 0xf7, 0x68, 0xa3, 0x53, 0xa0, 0x6d, 0x32, 0xd0,
- 0xe0, 0xe4, 0xc7, 0xf7, 0xb4, 0x1a, 0x9b, 0x79, 0x20, 0xce, 0x3d, 0x85,
- 0x19, 0xb5, 0x54, 0x26, 0x9f, 0x92, 0x50, 0x26, 0x27, 0x6f, 0xc9, 0xc0,
- 0xb6, 0xce, 0x1d, 0xd1, 0xf7, 0xf7, 0x25, 0xda, 0x15, 0xc7, 0xf4, 0x09,
- 0xc8, 0xd7, 0x90, 0x16, 0xe2, 0xf2, 0xf1, 0x23, 0xa4, 0x07, 0x15, 0x6b,
- 0x94, 0xdf, 0xb2, 0xf4, 0x70, 0x59, 0x8a, 0x90, 0x3b, 0x47, 0x8e, 0xdc,
- 0x2e, 0xe3, 0xbb, 0x16, 0xd3, 0xc3, 0x9e, 0x79, 0x7a, 0x88, 0xc1, 0x3e,
- 0x73, 0xaa, 0xe9, 0xe1, 0x37, 0xe7, 0xe8, 0x61, 0xdc, 0xf9, 0xd7, 0xd2,
- 0xc3, 0x0d, 0x0b, 0xe8, 0x61, 0x44, 0xd3, 0x43, 0xff, 0x1c, 0x3d, 0x8c,
- 0x1c, 0x61, 0xbf, 0x7a, 0x5d, 0xd4, 0x9b, 0x71, 0x38, 0xe7, 0x73, 0xb4,
- 0x90, 0x18, 0xd6, 0xfb, 0x44, 0x93, 0x79, 0x9e, 0x25, 0x5d, 0xa5, 0x18,
- 0x1b, 0x99, 0x9f, 0xff, 0xc6, 0x7f, 0xd3, 0xf9, 0x7f, 0x47, 0xfc, 0xff,
- 0xef, 0xfc, 0x5f, 0x8f, 0xf6, 0x29, 0x8b, 0x43, 0x79, 0x1c, 0xd2, 0xc3,
- 0x7b, 0xe2, 0x46, 0x2f, 0x70, 0x8e, 0xf9, 0x6d, 0xf6, 0xac, 0x9f, 0x83,
- 0xfc, 0x7b, 0x1c, 0xf2, 0xef, 0xb1, 0x05, 0xeb, 0x01, 0x3d, 0x36, 0x06,
- 0x11, 0xc8, 0xc1, 0xd4, 0x3c, 0x3e, 0x66, 0xba, 0x89, 0x0f, 0xb3, 0xf7,
- 0xe4, 0x6c, 0x65, 0x31, 0x4e, 0x5c, 0xbd, 0xdf, 0xe8, 0x64, 0xaa, 0x1a,
- 0x27, 0x84, 0x7b, 0xb6, 0x6a, 0x8c, 0xf8, 0x5d, 0xe6, 0xf7, 0x65, 0xbd,
- 0x87, 0xa4, 0xa0, 0xd7, 0x9f, 0x88, 0x17, 0xae, 0x3f, 0x11, 0x27, 0xae,
- 0xb6, 0xf7, 0x0b, 0xe5, 0x3a, 0xbd, 0x2f, 0xfc, 0xc0, 0x54, 0x4c, 0x66,
- 0x62, 0x8c, 0xeb, 0xf1, 0xde, 0x57, 0xfa, 0xca, 0x7e, 0xbc, 0x20, 0x79,
- 0x7b, 0xd6, 0x67, 0x95, 0xa5, 0x6d, 0xc6, 0x03, 0x79, 0x27, 0x42, 0xb8,
- 0x0e, 0xd1, 0x69, 0x65, 0x5d, 0x43, 0x55, 0x9c, 0x12, 0x78, 0x1f, 0x93,
- 0x44, 0xb6, 0x1b, 0xef, 0x29, 0xf6, 0xfd, 0xa4, 0x8c, 0x3c, 0x58, 0x86,
- 0x2d, 0xf7, 0x30, 0x74, 0x8e, 0x23, 0x10, 0x93, 0xfa, 0x2e, 0x14, 0xc2,
- 0x30, 0xa1, 0xef, 0xf5, 0xa3, 0xdf, 0x47, 0x7a, 0x88, 0xe3, 0xfb, 0xb2,
- 0x8d, 0x25, 0xc5, 0xa5, 0x50, 0xfc, 0x01, 0xe0, 0xe7, 0x1d, 0x94, 0x3f,
- 0xc2, 0xfb, 0x8d, 0xe6, 0xc3, 0xf8, 0x21, 0x03, 0xfa, 0xcd, 0xb9, 0x79,
- 0xcd, 0xc9, 0x94, 0xcd, 0xfe, 0x96, 0xaa, 0xfb, 0xf5, 0xe5, 0xb0, 0xb6,
- 0x9f, 0xd3, 0x76, 0x5f, 0x0b, 0xcf, 0xe7, 0x19, 0x1b, 0xfa, 0xcb, 0xb0,
- 0xa1, 0x9f, 0xa8, 0x64, 0xf4, 0x1a, 0xd6, 0x63, 0xb0, 0xa1, 0x1f, 0x85,
- 0xee, 0xa1, 0xce, 0x89, 0x59, 0x9d, 0x33, 0xa2, 0x76, 0x69, 0x9d, 0xf3,
- 0xd7, 0x5a, 0xe7, 0xfc, 0xea, 0x12, 0x9d, 0x73, 0x48, 0xb5, 0x8f, 0x52,
- 0xe7, 0xf4, 0xaa, 0x9d, 0x0e, 0xed, 0xc5, 0xb5, 0xcb, 0xe8, 0x9c, 0xf7,
- 0xca, 0xaf, 0xd8, 0xbc, 0xfd, 0xf2, 0xbe, 0x6d, 0x7a, 0xdd, 0xc6, 0x9b,
- 0x50, 0xbc, 0xcb, 0xce, 0xe8, 0xa0, 0xeb, 0x55, 0xa7, 0x5e, 0xef, 0xfd,
- 0x6a, 0x95, 0xce, 0x69, 0x53, 0xdd, 0x4e, 0xaf, 0xae, 0xc3, 0x78, 0x04,
- 0xbf, 0x53, 0x4e, 0x66, 0xa0, 0x0e, 0xdf, 0x71, 0x89, 0x1c, 0xc1, 0xd8,
- 0xcd, 0x7d, 0x7b, 0xca, 0xe4, 0x5d, 0x63, 0xf3, 0x54, 0x98, 0xee, 0x9a,
- 0xf4, 0x76, 0x9b, 0x6e, 0x74, 0x55, 0x9b, 0x6a, 0xd5, 0xba, 0x6a, 0x33,
- 0x18, 0x6a, 0x02, 0xfa, 0x75, 0xa2, 0x14, 0xea, 0x2c, 0xfe, 0x66, 0xbc,
- 0x99, 0x71, 0x89, 0x30, 0x6e, 0x9d, 0x40, 0x19, 0x3c, 0xa5, 0xd0, 0xa6,
- 0xe4, 0x6f, 0xf8, 0x0a, 0x78, 0xa6, 0x80, 0xd7, 0x5b, 0xc0, 0x3f, 0xbf,
- 0x5e, 0x64, 0xdc, 0xb3, 0x59, 0x8e, 0x8e, 0x55, 0xe7, 0xb5, 0xca, 0xbb,
- 0xc7, 0x36, 0xc8, 0xbe, 0x51, 0xff, 0x6a, 0xa9, 0xdf, 0x28, 0x23, 0xa3,
- 0x2f, 0xea, 0xfb, 0x40, 0xd6, 0xe8, 0x7b, 0x92, 0x78, 0x7f, 0x98, 0x91,
- 0x91, 0xfd, 0x8e, 0x91, 0x91, 0x19, 0x35, 0x6f, 0xb3, 0x86, 0x6d, 0xf2,
- 0x6e, 0xa6, 0xbe, 0xd1, 0xb8, 0xbe, 0x43, 0x7a, 0xa2, 0x72, 0xad, 0xfc,
- 0xd1, 0x71, 0x75, 0xa7, 0x9a, 0xbf, 0x4b, 0x41, 0xdb, 0xac, 0x93, 0x0b,
- 0x6c, 0xd6, 0xbf, 0x97, 0x99, 0xf7, 0x45, 0x31, 0x4e, 0xd0, 0xf0, 0x75,
- 0x2f, 0x73, 0x1d, 0xb4, 0x39, 0x26, 0x97, 0xa4, 0x4f, 0xe3, 0x8f, 0xf2,
- 0xb4, 0x01, 0x72, 0x70, 0x56, 0xeb, 0xd7, 0xb5, 0xbc, 0xf3, 0xf8, 0x08,
- 0x6d, 0xd7, 0xaf, 0x6b, 0x79, 0xb6, 0xd6, 0xda, 0xae, 0xd3, 0x90, 0xd3,
- 0x94, 0xa3, 0x37, 0xca, 0x5f, 0xdb, 0x74, 0xa6, 0x25, 0xe3, 0xb3, 0x42,
- 0x7d, 0x17, 0x83, 0x0c, 0xa5, 0x3c, 0xfd, 0x59, 0x6d, 0xd7, 0xe7, 0x6c,
- 0x1b, 0x94, 0x9f, 0x46, 0x76, 0x6f, 0x76, 0xa6, 0x6d, 0x1a, 0xbf, 0xc3,
- 0x18, 0xba, 0x9f, 0xc9, 0x59, 0x3e, 0x53, 0xce, 0x93, 0xc8, 0x5f, 0x83,
- 0x7c, 0xf2, 0xd9, 0x63, 0x9a, 0xcf, 0xb4, 0x7d, 0xe2, 0x74, 0xd9, 0x35,
- 0x85, 0xb9, 0xf5, 0x80, 0x3c, 0xf9, 0x4c, 0x1d, 0xf5, 0xa6, 0x8d, 0x3c,
- 0xf0, 0x90, 0xfe, 0x45, 0xe8, 0x0e, 0xd6, 0x45, 0xfa, 0xb1, 0x0c, 0xe6,
- 0xf0, 0x24, 0xfc, 0x9f, 0x46, 0x7c, 0x37, 0xe3, 0x7b, 0x42, 0x7e, 0x75,
- 0x30, 0xaa, 0xc7, 0x3d, 0x82, 0x71, 0x1c, 0x38, 0x82, 0x31, 0x39, 0xc6,
- 0x76, 0x76, 0xcf, 0xb8, 0x52, 0x73, 0x86, 0x7c, 0xc7, 0x33, 0x86, 0x41,
- 0xb0, 0xb7, 0x8b, 0x74, 0x9b, 0xf4, 0xfa, 0xf5, 0xf9, 0xb7, 0xcd, 0xf1,
- 0x08, 0x70, 0x72, 0x00, 0xf3, 0x31, 0x52, 0xf4, 0xbd, 0xac, 0xe3, 0xc7,
- 0x31, 0x4e, 0xd8, 0x80, 0xed, 0xb0, 0x05, 0xdb, 0x61, 0x07, 0xb6, 0xc3,
- 0x0e, 0x5c, 0x2d, 0xa7, 0xb6, 0x72, 0x7f, 0x49, 0xfe, 0x9d, 0xbc, 0x77,
- 0xf9, 0x1b, 0x3a, 0x36, 0x5f, 0x7b, 0x4b, 0x1f, 0x7c, 0x76, 0xf1, 0x92,
- 0x03, 0xdc, 0x63, 0x3f, 0xeb, 0xd5, 0xde, 0xd2, 0x2f, 0xed, 0x3d, 0xc8,
- 0xef, 0xb9, 0x24, 0x1d, 0xb7, 0x7c, 0xd8, 0xa9, 0x1d, 0xe8, 0x03, 0x1e,
- 0x33, 0x4e, 0x32, 0x3e, 0xe4, 0x30, 0x4e, 0x91, 0xdd, 0x1c, 0xd1, 0x67,
- 0xc4, 0xa6, 0x19, 0x8b, 0xb8, 0xa5, 0x3d, 0xb2, 0x25, 0xb1, 0xdb, 0x49,
- 0x0e, 0xa8, 0x48, 0x72, 0xa0, 0xcf, 0x09, 0xcb, 0xf1, 0x0e, 0x6a, 0xc8,
- 0x19, 0xc0, 0x7a, 0xa0, 0xf4, 0x75, 0xd0, 0xd3, 0x79, 0x29, 0x1c, 0x6f,
- 0x90, 0xa9, 0x62, 0xbb, 0x97, 0x55, 0x31, 0xe1, 0xbe, 0x12, 0x75, 0x0a,
- 0x44, 0x7f, 0x26, 0x2a, 0x13, 0xa3, 0x1b, 0x45, 0x69, 0xdb, 0xbd, 0x45,
- 0xb2, 0x63, 0xa3, 0x72, 0xbe, 0x5b, 0x9a, 0x14, 0xda, 0xe7, 0xdd, 0xde,
- 0xea, 0x14, 0xd7, 0x11, 0x43, 0x5e, 0x58, 0x4f, 0x3e, 0x19, 0x05, 0x0e,
- 0x41, 0xb7, 0x8c, 0xeb, 0xd6, 0x09, 0xe5, 0xde, 0xed, 0x3a, 0x66, 0xca,
- 0x38, 0x6d, 0xf5, 0x7a, 0x03, 0xf9, 0x23, 0xba, 0x2c, 0x7f, 0x4c, 0x96,
- 0xb8, 0x36, 0x23, 0x79, 0x97, 0x71, 0x61, 0x1f, 0xbf, 0xc7, 0x59, 0xb6,
- 0x4e, 0x46, 0xba, 0xf3, 0x76, 0x8f, 0xc7, 0x37, 0xc1, 0x07, 0x1c, 0x9f,
- 0x5e, 0x27, 0x01, 0xaf, 0x2f, 0x5e, 0xcf, 0x88, 0x56, 0xc9, 0x03, 0x47,
- 0x66, 0x46, 0xc3, 0xf5, 0x0f, 0xb6, 0x87, 0xef, 0x71, 0x23, 0x6f, 0xb3,
- 0x4b, 0xea, 0x11, 0x2e, 0xae, 0x55, 0x2e, 0x94, 0xb1, 0x4a, 0x9f, 0x13,
- 0xf6, 0xb4, 0x7c, 0x3d, 0x5d, 0x31, 0xb2, 0x75, 0xbc, 0x12, 0xea, 0x96,
- 0xa8, 0xd1, 0xa5, 0x4b, 0xf4, 0x89, 0x89, 0x60, 0xce, 0xeb, 0x93, 0x4b,
- 0x3a, 0x46, 0xf7, 0x6b, 0x53, 0x2d, 0xe2, 0x1e, 0x93, 0xd9, 0x11, 0xff,
- 0x54, 0x2b, 0xf7, 0x69, 0x8c, 0xa4, 0xde, 0x8c, 0x7e, 0x8c, 0xb5, 0x50,
- 0x1f, 0x0e, 0xa9, 0xb5, 0x78, 0xaf, 0xd1, 0xf4, 0x07, 0x9e, 0xc2, 0xb7,
- 0xf1, 0x13, 0xbe, 0x0c, 0x3f, 0xe1, 0x09, 0xe8, 0xba, 0x73, 0xf0, 0x13,
- 0x1e, 0x87, 0x9f, 0xf0, 0x18, 0xfc, 0x84, 0x47, 0xa1, 0x27, 0xab, 0xfd,
- 0x83, 0xe1, 0x05, 0xfe, 0x41, 0xa0, 0xf9, 0x9f, 0x31, 0xc0, 0xc7, 0xab,
- 0x7c, 0x83, 0xbd, 0x46, 0x5f, 0xc1, 0xef, 0x37, 0x7c, 0xd4, 0xa6, 0x6e,
- 0xd6, 0xfa, 0xd1, 0xec, 0xd9, 0x1d, 0x98, 0xd3, 0x57, 0x6d, 0xca, 0xe8,
- 0xab, 0x89, 0x79, 0x7d, 0x65, 0xf8, 0xe8, 0xd8, 0xa8, 0x44, 0xfc, 0xd1,
- 0xe9, 0x6c, 0x6a, 0xbb, 0xe6, 0xa1, 0x26, 0x7f, 0xa3, 0x44, 0x1e, 0x50,
- 0xcd, 0x35, 0x92, 0xb5, 0xdf, 0xa0, 0xaf, 0xa3, 0x5f, 0x47, 0x5b, 0xef,
- 0x94, 0x9c, 0xb6, 0xcf, 0xae, 0x8c, 0xef, 0x47, 0x17, 0xe1, 0xbb, 0x50,
- 0x7a, 0x56, 0xe3, 0xfc, 0x7e, 0x7d, 0x26, 0xbf, 0x41, 0x86, 0xcb, 0x21,
- 0xce, 0x79, 0x06, 0x8e, 0xfb, 0x30, 0x5a, 0x25, 0x72, 0xac, 0x45, 0xfa,
- 0x53, 0xa2, 0x72, 0xa9, 0x95, 0x7a, 0xff, 0xca, 0xa9, 0x6e, 0x89, 0xe7,
- 0xba, 0x49, 0xab, 0xf7, 0xc9, 0x84, 0x9e, 0x8b, 0x16, 0xa9, 0x39, 0x46,
- 0x1b, 0x25, 0x5c, 0xc3, 0xbb, 0xbd, 0xc5, 0xde, 0x41, 0x1d, 0x35, 0xe5,
- 0x44, 0x0e, 0xea, 0xf9, 0x9a, 0xd5, 0x7b, 0x0c, 0x6f, 0x9e, 0x62, 0x2c,
- 0x9e, 0xf7, 0xfd, 0x31, 0x0e, 0xff, 0xaf, 0x99, 0xbf, 0x42, 0x8b, 0xb1,
- 0x67, 0xd6, 0x58, 0x3b, 0xc6, 0xc4, 0xa9, 0x96, 0xb7, 0x61, 0xd8, 0x4e,
- 0xf5, 0x1d, 0xb5, 0xab, 0xe0, 0x03, 0x37, 0xa0, 0x4d, 0xae, 0x63, 0xdb,
- 0xbf, 0x17, 0xe4, 0xfd, 0xb3, 0x73, 0xc0, 0x5f, 0x85, 0xb4, 0x06, 0xe4,
- 0x31, 0x66, 0xf3, 0x85, 0x16, 0xc6, 0x65, 0xb3, 0x7e, 0xa3, 0x4d, 0x5b,
- 0xe5, 0x8c, 0x8c, 0xb6, 0xc3, 0x37, 0xe7, 0x39, 0x76, 0xe6, 0xf7, 0x73,
- 0xee, 0x84, 0x7f, 0xab, 0x69, 0x12, 0xf2, 0x67, 0x8f, 0x5c, 0x6b, 0xe3,
- 0xce, 0xd4, 0xc3, 0xbf, 0xb8, 0x60, 0xbd, 0xf6, 0x10, 0xf4, 0xd8, 0xad,
- 0x90, 0x47, 0xd4, 0xc3, 0x87, 0xe4, 0x17, 0x2c, 0x3d, 0x2f, 0xd4, 0xc3,
- 0x17, 0x85, 0xb1, 0xe1, 0x2e, 0xe4, 0xe5, 0x83, 0x28, 0xe8, 0xe1, 0x70,
- 0x95, 0xaf, 0x46, 0xbf, 0xaf, 0x2e, 0x6d, 0xd6, 0xc0, 0x16, 0xfa, 0x7d,
- 0x90, 0x03, 0xb1, 0xd0, 0xcf, 0xab, 0x9d, 0x5b, 0xa3, 0xdd, 0x69, 0xeb,
- 0x8e, 0xa4, 0x5e, 0x22, 0x8e, 0x12, 0x87, 0xe4, 0xf6, 0xf5, 0xbc, 0x26,
- 0xcf, 0xf5, 0xbf, 0xa5, 0x71, 0x26, 0x8a, 0xb4, 0xb7, 0x46, 0xc3, 0x68,
- 0xe5, 0x7c, 0x22, 0xdc, 0xbf, 0x51, 0xb0, 0x75, 0xf7, 0xd8, 0xf5, 0xf8,
- 0x82, 0x7c, 0x9b, 0x71, 0xce, 0x44, 0x5f, 0x64, 0x25, 0xcf, 0x64, 0xa3,
- 0xee, 0xed, 0xda, 0x6f, 0xcf, 0x48, 0xd8, 0x16, 0xbf, 0x6b, 0xaa, 0xda,
- 0xa6, 0x1d, 0xc5, 0xf7, 0xe2, 0xfb, 0x1b, 0x9e, 0xd7, 0x6b, 0x8b, 0xe6,
- 0x6e, 0x9a, 0x90, 0x4f, 0xc8, 0x3b, 0x09, 0x7d, 0x8e, 0xc9, 0x3f, 0x46,
- 0xbb, 0x87, 0xeb, 0xae, 0xde, 0xf4, 0x70, 0xea, 0x23, 0xfa, 0x0e, 0xd5,
- 0x71, 0x11, 0xa7, 0x90, 0xda, 0xab, 0xf7, 0x9d, 0x14, 0x74, 0x7c, 0x39,
- 0x8f, 0xf7, 0xbc, 0x8f, 0xda, 0x76, 0x8c, 0x7f, 0x0b, 0x88, 0x69, 0x1f,
- 0x04, 0x6c, 0xd4, 0x21, 0x94, 0xbd, 0x31, 0x69, 0x3b, 0xfa, 0x7e, 0xcd,
- 0x0b, 0x6b, 0xe1, 0x0b, 0xf4, 0x1e, 0x85, 0xae, 0x3e, 0x1a, 0x97, 0xfe,
- 0xa3, 0x5a, 0x37, 0x66, 0x96, 0xc6, 0x0a, 0xb6, 0x78, 0x2e, 0xfd, 0x89,
- 0x98, 0x27, 0xd7, 0x1c, 0x8d, 0xc8, 0xe1, 0xd8, 0x16, 0xaf, 0xc3, 0xb9,
- 0xd1, 0xea, 0x42, 0x43, 0x7f, 0xa0, 0x15, 0xd4, 0x37, 0xeb, 0x90, 0xbd,
- 0xf3, 0xb1, 0x6b, 0xd4, 0x7f, 0x49, 0x46, 0xc8, 0x4b, 0x95, 0x88, 0x8c,
- 0x0f, 0xb6, 0x02, 0x9e, 0xb7, 0xae, 0x07, 0x0e, 0x40, 0x53, 0x98, 0x1f,
- 0xfd, 0xf7, 0x3c, 0xdc, 0x38, 0xe5, 0x57, 0x1b, 0xfa, 0xef, 0x3b, 0x4a,
- 0x1d, 0xe6, 0x6b, 0xbe, 0x46, 0xbf, 0x5e, 0x8d, 0xf6, 0x3d, 0xc8, 0x8b,
- 0x6f, 0x11, 0xff, 0x01, 0xc8, 0xb5, 0xa3, 0x51, 0xe9, 0x38, 0xda, 0x20,
- 0x9b, 0x8e, 0xd2, 0xf7, 0xa8, 0xf6, 0x45, 0x69, 0x8b, 0x5e, 0xc2, 0xb8,
- 0x6e, 0x34, 0xf7, 0x0d, 0x4e, 0x45, 0x65, 0x1f, 0xf9, 0x15, 0x65, 0x73,
- 0xb0, 0x93, 0xb3, 0x47, 0x3d, 0xbd, 0x16, 0x9a, 0xc5, 0x38, 0xf9, 0x37,
- 0x2c, 0xfa, 0x8e, 0x1a, 0x39, 0x53, 0xa0, 0x6f, 0x32, 0xd0, 0x02, 0xbc,
- 0x3e, 0x60, 0xf9, 0xe5, 0x3d, 0xeb, 0x2d, 0x5f, 0xfe, 0x9c, 0xfc, 0x96,
- 0x5b, 0x6f, 0xe4, 0xe5, 0x87, 0xd6, 0x73, 0x2f, 0xd2, 0x5a, 0x9f, 0xef,
- 0x3a, 0x6d, 0x43, 0x18, 0xb9, 0xf9, 0x7a, 0xfc, 0x27, 0xc0, 0x51, 0xb8,
- 0xfe, 0x44, 0x3e, 0xe4, 0x1a, 0xb2, 0x3e, 0xb3, 0x92, 0x9a, 0xd1, 0x7f,
- 0x53, 0x89, 0x6b, 0x61, 0xf3, 0xf7, 0x59, 0x6d, 0xaf, 0x30, 0x36, 0xfe,
- 0x4c, 0xf8, 0x37, 0x9c, 0xaa, 0xf6, 0x19, 0x56, 0xaf, 0x75, 0x31, 0xbe,
- 0x34, 0xb7, 0x17, 0x28, 0x18, 0xd5, 0x77, 0xc2, 0xc5, 0x9c, 0x8b, 0xc5,
- 0x5a, 0xe7, 0x9b, 0x63, 0x12, 0xb8, 0x7e, 0xdc, 0xf9, 0x96, 0xcf, 0xb5,
- 0x71, 0xcf, 0x79, 0xb9, 0xe8, 0x83, 0xf7, 0xfe, 0x02, 0xe3, 0x68, 0x75,
- 0x5e, 0xc1, 0x9c, 0x1e, 0x2c, 0x65, 0x92, 0x9e, 0x8d, 0x83, 0x3f, 0x5b,
- 0x6c, 0x75, 0x9e, 0x9b, 0x8f, 0x21, 0xf5, 0x84, 0x74, 0x71, 0x88, 0x79,
- 0x65, 0xe4, 0x95, 0x19, 0xeb, 0xad, 0x77, 0x26, 0xc7, 0xec, 0x7e, 0x12,
- 0xa3, 0x8b, 0xe6, 0xd6, 0x5f, 0x06, 0xf4, 0xfa, 0x84, 0xeb, 0x4c, 0x4e,
- 0x4d, 0xaf, 0x37, 0xfb, 0x8a, 0x6a, 0x91, 0x67, 0xf6, 0x58, 0x4e, 0x4c,
- 0xd5, 0xa2, 0x4c, 0xbd, 0x33, 0xa1, 0x63, 0x5e, 0xda, 0xf6, 0x70, 0xc6,
- 0xa7, 0xea, 0x9d, 0x29, 0xbd, 0xd6, 0x1c, 0x75, 0x4e, 0x8e, 0xb1, 0xed,
- 0x28, 0xca, 0x88, 0x73, 0x0a, 0xed, 0x4d, 0x8d, 0xb5, 0xc7, 0xf7, 0x49,
- 0x3b, 0x6c, 0x01, 0xfe, 0x8d, 0x34, 0xde, 0x17, 0xe0, 0x3a, 0x53, 0x73,
- 0xed, 0x2a, 0xb4, 0xc3, 0xb2, 0xa4, 0x41, 0xf6, 0xeb, 0xa2, 0xfd, 0xa5,
- 0x6b, 0x52, 0x4b, 0x71, 0x32, 0x06, 0x9c, 0x1c, 0xb4, 0x38, 0x39, 0x61,
- 0x71, 0x32, 0x5a, 0x85, 0x93, 0x87, 0x17, 0xe1, 0xe4, 0x04, 0x70, 0xf2,
- 0xf0, 0x15, 0x70, 0x82, 0xbc, 0xf2, 0xc3, 0x16, 0x27, 0xf7, 0x2d, 0xc2,
- 0x49, 0x7e, 0x2e, 0x16, 0x6f, 0x70, 0x32, 0x02, 0x9c, 0xd4, 0xb4, 0x1a,
- 0xd8, 0x0f, 0x5a, 0x9c, 0xe0, 0x3d, 0x75, 0x10, 0x65, 0xee, 0xab, 0xc2,
- 0xc9, 0x41, 0xe0, 0xe4, 0x3e, 0x8b, 0x93, 0xc3, 0x16, 0x27, 0x87, 0x51,
- 0x26, 0x0f, 0x9c, 0x14, 0x96, 0xc1, 0xc9, 0x08, 0x70, 0x12, 0xb6, 0x5b,
- 0x40, 0x3b, 0x87, 0xab, 0x70, 0x32, 0xb2, 0x0c, 0x4e, 0xb8, 0xe6, 0x1a,
- 0xee, 0xe1, 0xbe, 0xfc, 0x06, 0x7b, 0xb8, 0x53, 0x9f, 0x7d, 0xe3, 0x3d,
- 0xdc, 0x2c, 0x73, 0xb9, 0xea, 0xcc, 0xfb, 0xb3, 0x76, 0x4f, 0x9a, 0xd9,
- 0xfb, 0x37, 0x7f, 0x0f, 0x5e, 0x3b, 0xf8, 0xbc, 0x90, 0xf7, 0xc4, 0xec,
- 0x21, 0x75, 0xb7, 0x4d, 0x81, 0xd7, 0x8e, 0xca, 0x81, 0xe3, 0xb5, 0x87,
- 0x73, 0x36, 0xcd, 0xdf, 0xd6, 0x9e, 0x57, 0x8a, 0x79, 0xe1, 0xde, 0x83,
- 0x17, 0xcd, 0x5d, 0x50, 0x31, 0x9e, 0xc7, 0xa8, 0x5e, 0x7b, 0x7e, 0xd1,
- 0xde, 0x55, 0xe4, 0xdd, 0x9b, 0xf5, 0xa7, 0x13, 0xdc, 0x57, 0x55, 0xd0,
- 0xf0, 0x72, 0x2d, 0xad, 0x47, 0xef, 0xa5, 0xca, 0x16, 0x69, 0x67, 0x27,
- 0xb8, 0x27, 0x0d, 0xf6, 0x31, 0xf7, 0xed, 0x9a, 0x7d, 0xba, 0xbd, 0x0b,
- 0xf6, 0xe9, 0x56, 0x9f, 0xef, 0x26, 0xdf, 0xcd, 0xd3, 0xcd, 0xc1, 0xb9,
- 0xbb, 0x57, 0x8f, 0x3b, 0xcf, 0xe8, 0xf8, 0x70, 0x3d, 0xe6, 0x27, 0x08,
- 0x4e, 0xa7, 0x4c, 0x5c, 0x76, 0x46, 0xc7, 0x65, 0x05, 0x1e, 0xf8, 0xb0,
- 0x8d, 0xcd, 0x76, 0xf4, 0x5c, 0x9e, 0x8b, 0xcb, 0x2e, 0xd8, 0xa3, 0xa3,
- 0xef, 0xff, 0xc8, 0x8e, 0x5e, 0xd2, 0x7b, 0x71, 0xfa, 0x52, 0x8e, 0x14,
- 0x20, 0x23, 0xf6, 0x8c, 0xbf, 0x2a, 0xc3, 0x0f, 0xf2, 0x9b, 0x3a, 0x2d,
- 0x02, 0xbd, 0x45, 0xb9, 0x9d, 0x97, 0x6c, 0x0f, 0xd3, 0x4c, 0x9d, 0x3e,
- 0xed, 0x23, 0x1f, 0x77, 0x7a, 0xe7, 0xfa, 0x27, 0x7e, 0xc3, 0x35, 0x70,
- 0xfe, 0xa6, 0x9d, 0x93, 0x71, 0xb2, 0x15, 0xe6, 0x87, 0x6b, 0xe1, 0x77,
- 0xdb, 0xfb, 0x08, 0x99, 0x5f, 0x7d, 0xff, 0xb5, 0xe1, 0xd3, 0xac, 0xfe,
- 0x3b, 0x22, 0x23, 0x4e, 0x1f, 0xea, 0x4c, 0x7b, 0x0d, 0x03, 0x2a, 0x7d,
- 0xd3, 0x00, 0xcf, 0xca, 0x4d, 0x2c, 0xf9, 0xfb, 0x01, 0xf3, 0xba, 0xb0,
- 0xa0, 0xe7, 0x94, 0xfb, 0xb0, 0xa6, 0x41, 0x8b, 0x9a, 0xb6, 0x34, 0xfd,
- 0x1f, 0x98, 0xd3, 0x91, 0xd4, 0xad, 0xd4, 0x93, 0xa1, 0x8e, 0x4c, 0xc6,
- 0xfb, 0x78, 0x7f, 0x84, 0xa6, 0x71, 0x7b, 0x97, 0xc4, 0xd4, 0x39, 0xad,
- 0xdf, 0x47, 0x52, 0xbc, 0x5f, 0x66, 0x99, 0xb2, 0xa3, 0x55, 0x65, 0xf5,
- 0xb8, 0x3d, 0xf9, 0x43, 0xcc, 0xcd, 0x17, 0x61, 0x6f, 0xf6, 0x8e, 0xbd,
- 0x0a, 0x9f, 0x31, 0x2e, 0x5f, 0x2a, 0xbd, 0x04, 0x7a, 0xcd, 0xaf, 0xb5,
- 0x77, 0xe1, 0x65, 0x01, 0x37, 0xcf, 0x38, 0xeb, 0xfd, 0xc3, 0x91, 0x3f,
- 0x02, 0x5d, 0xfc, 0xc1, 0x4b, 0xec, 0x03, 0xb0, 0x44, 0x60, 0xcf, 0xc3,
- 0x36, 0x18, 0x7f, 0x49, 0xef, 0x95, 0xbb, 0xbe, 0xfc, 0x92, 0x8e, 0x53,
- 0xf4, 0x97, 0x5b, 0x65, 0x7b, 0xb9, 0x41, 0x76, 0x40, 0x2f, 0xec, 0x28,
- 0xfb, 0x78, 0xa2, 0x72, 0x63, 0xd9, 0xcc, 0xd3, 0x47, 0xca, 0x9c, 0xef,
- 0x6d, 0x32, 0x71, 0xbc, 0x9a, 0x66, 0xa7, 0xed, 0xde, 0x31, 0xd2, 0x0f,
- 0x9e, 0x52, 0x32, 0x3f, 0xad, 0xc7, 0xce, 0x5d, 0xac, 0xc9, 0xc3, 0xb3,
- 0xc2, 0xbd, 0xf8, 0xfc, 0x1b, 0x74, 0xdf, 0x68, 0xe5, 0x19, 0x77, 0xde,
- 0x8f, 0xd8, 0x5f, 0x09, 0xf7, 0x86, 0xbf, 0xfe, 0x19, 0x10, 0xfd, 0x77,
- 0x5d, 0xf4, 0xde, 0x70, 0x4d, 0x7b, 0xd2, 0x76, 0x26, 0xa6, 0x75, 0x84,
- 0xa1, 0xf1, 0xf9, 0xbf, 0xe7, 0x22, 0xf2, 0x7f, 0x01, 0x95, 0xf6, 0x2d,
- 0x58, 0xd0, 0x73, 0x00, 0x00, 0x00 };
-static u32 bnx2_CP_b09FwData[(0x50/4) + 1] = {
- 0x00010030, 0x00000030, 0x00000000, 0x00000001, 0x00010fd0, 0x00000fd0,
- 0x00001430, 0x0000007f, 0x00030400, 0x00001000, 0x00000030, 0x00000020,
- 0x00050200, 0x00001000, 0x00000030, 0x00000010, 0x00010400, 0x00000400,
- 0x00001030, 0x00000020, 0x00000000 };
-static u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
- 0x080005d8, 0x080007f8, 0x0800073c, 0x08000764, 0x0800078c, 0x080007b4,
- 0x08000610, 0x080005fc, 0x08000820, 0x08000820, 0x0800062c, 0x08000648,
- 0x08000648, 0x08000820, 0x08000660, 0x08000674, 0x08000820, 0x08000688,
- 0x08000820, 0x08000820, 0x0800069c, 0x08000820, 0x08000820, 0x08000820,
- 0x08000820, 0x08000820, 0x08000820, 0x08000820, 0x08000820, 0x08000820,
- 0x08000820, 0x080006b0, 0x08000820, 0x080006c4, 0x080006d8, 0x080006ec,
- 0x08000820, 0x08000700, 0x08000714, 0x08000728, 0x08003740, 0x08003758,
- 0x08003768, 0x08003778, 0x08003790, 0x080037a8, 0x080037b8, 0x080037c8,
- 0x080037e8, 0x080037f8, 0x08003808, 0x08003898, 0x080037d8, 0x08003818,
- 0x08003828, 0x08003840, 0x08003860, 0x08003898, 0x08003878, 0x08003878,
- 0x080055f0, 0x080055f0, 0x080055f0, 0x080055f0, 0x080055f0, 0x08005618,
- 0x08005618, 0x08005640, 0x08005690, 0x08005660, 0x00000000 };
-static u32 bnx2_CP_b09FwBss[(0x870/4) + 1] = { 0x0 };
-static u32 bnx2_CP_b09FwSbss[(0xe9/4) + 1] = { 0x0 };
+ 0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d,
+ 0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59,
+ 0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22,
+ 0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12,
+ 0x02, 0xab, 0x10, 0x43, 0xb3, 0x1c, 0x4a, 0xc5, 0x48, 0x4e, 0x02, 0x04,
+ 0xea, 0x40, 0xe8, 0x86, 0xdd, 0xec, 0x66, 0x32, 0x92, 0x3f, 0x9a, 0x8e,
+ 0x3d, 0x93, 0x44, 0x89, 0xbd, 0xdd, 0x9c, 0xad, 0x90, 0x14, 0x3b, 0x74,
+ 0x07, 0x4f, 0xe2, 0x98, 0x96, 0x73, 0x0a, 0x8d, 0x50, 0x8c, 0x9b, 0xe6,
+ 0xb0, 0xdd, 0xd0, 0xa6, 0x34, 0xdb, 0x86, 0x22, 0x8c, 0x81, 0xf4, 0x2c,
+ 0xdd, 0x86, 0x42, 0x77, 0xd3, 0x36, 0xe5, 0xed, 0xef, 0x77, 0xef, 0x7d,
+ 0x9a, 0x91, 0x34, 0xce, 0x07, 0xdd, 0xad, 0xcf, 0x79, 0x7e, 0xf3, 0xee,
+ 0xbb, 0x1f, 0xff, 0xfb, 0xbf, 0xff, 0xef, 0xfb, 0xbf, 0x4f, 0x97, 0x8b,
+ 0x34, 0x8b, 0xfd, 0xb7, 0x01, 0xd7, 0xd5, 0xc9, 0xfd, 0xe3, 0x57, 0x5f,
+ 0x39, 0x70, 0x25, 0x9f, 0xa3, 0x91, 0x68, 0x44, 0xde, 0xc4, 0xbf, 0xe4,
+ 0x1b, 0xa8, 0x83, 0x0e, 0xdd, 0x70, 0x2c, 0x5e, 0x12, 0x53, 0x43, 0xde,
+ 0xfe, 0x8c, 0x27, 0xb1, 0xc8, 0x50, 0xee, 0xce, 0x71, 0x4f, 0x24, 0x5d,
+ 0xee, 0x4b, 0x0e, 0xcb, 0x3f, 0x05, 0xb9, 0x78, 0x54, 0x58, 0xfe, 0x96,
+ 0xa1, 0x57, 0x7f, 0xeb, 0x2b, 0xff, 0x2a, 0xf5, 0xf2, 0x4c, 0x44, 0x62,
+ 0xee, 0xd0, 0xed, 0xe2, 0x6e, 0x93, 0x58, 0xe7, 0x50, 0x72, 0xff, 0x23,
+ 0xdb, 0x97, 0x44, 0x5a, 0xc3, 0xbe, 0x5e, 0x0a, 0xbe, 0xb2, 0x5d, 0x72,
+ 0x1d, 0x43, 0x89, 0xb1, 0x86, 0x21, 0x57, 0x9e, 0xaa, 0xc8, 0xe8, 0x89,
+ 0xc2, 0xcb, 0x41, 0x74, 0x28, 0x88, 0x4c, 0x0d, 0x38, 0x12, 0x19, 0x92,
+ 0xb3, 0xe3, 0x03, 0xf7, 0x04, 0xca, 0xf3, 0xfc, 0x45, 0x69, 0x19, 0x3c,
+ 0x37, 0x80, 0xf7, 0x65, 0x41, 0xdd, 0xbd, 0xd7, 0x9c, 0x28, 0xc4, 0x44,
+ 0x0d, 0xf5, 0xbc, 0x90, 0x89, 0x5c, 0x25, 0x7c, 0x7f, 0x56, 0x7a, 0xfc,
+ 0xa7, 0x05, 0xe5, 0xe5, 0x98, 0x64, 0x2a, 0xd2, 0x82, 0x32, 0xdc, 0x9b,
+ 0x51, 0x27, 0xe5, 0x66, 0x22, 0xae, 0xe4, 0x2b, 0x3f, 0x5e, 0x67, 0xc6,
+ 0x9d, 0xb3, 0xf7, 0xbf, 0x8e, 0x99, 0x3b, 0xc6, 0x2d, 0xc6, 0x64, 0x29,
+ 0x92, 0x10, 0xc0, 0x82, 0x79, 0x25, 0x64, 0xb2, 0x98, 0x94, 0x4c, 0x81,
+ 0xb0, 0x45, 0x25, 0xeb, 0x12, 0xae, 0x04, 0xda, 0xb7, 0x39, 0xf5, 0xeb,
+ 0xb3, 0xee, 0x0b, 0xa8, 0x9b, 0x44, 0xbd, 0x4e, 0x79, 0x12, 0x75, 0x4f,
+ 0x57, 0xe2, 0xf2, 0x44, 0xe5, 0x57, 0x25, 0x8d, 0xb6, 0x8f, 0x57, 0x30,
+ 0x76, 0xb1, 0x51, 0x86, 0xa7, 0x9b, 0x25, 0x33, 0xdd, 0x9d, 0xc8, 0x4a,
+ 0x10, 0x7c, 0xda, 0xff, 0xa8, 0x8c, 0xb5, 0xa1, 0x7e, 0x91, 0xef, 0x12,
+ 0x2b, 0xde, 0x65, 0xfd, 0x3e, 0x37, 0xab, 0x1c, 0x49, 0xef, 0x4d, 0x25,
+ 0xc6, 0x14, 0x9f, 0x1b, 0x24, 0xd3, 0x8f, 0xe7, 0xd1, 0xa8, 0x44, 0xbc,
+ 0x20, 0xb8, 0xc3, 0xbf, 0x0c, 0x70, 0xa4, 0x92, 0x49, 0xc5, 0xb6, 0x6c,
+ 0x97, 0xca, 0x25, 0x55, 0x5c, 0x72, 0x95, 0x2b, 0x25, 0xd9, 0x16, 0x04,
+ 0xef, 0xf3, 0x3b, 0x51, 0x2e, 0x32, 0x5c, 0x90, 0xfd, 0x58, 0x23, 0xf4,
+ 0x29, 0xbe, 0x1a, 0xda, 0x8c, 0x79, 0xf4, 0xb9, 0xc3, 0xd2, 0x28, 0xe9,
+ 0xb8, 0xa4, 0xd5, 0x90, 0x24, 0xd5, 0xd0, 0x3a, 0x94, 0x39, 0xd2, 0xe0,
+ 0x7d, 0xc1, 0xd2, 0xd2, 0x46, 0x3c, 0xcb, 0xa8, 0x1a, 0x6a, 0x5b, 0x55,
+ 0x9e, 0x4a, 0x8a, 0x5a, 0x07, 0x5c, 0xa5, 0x7a, 0xd3, 0x8a, 0x65, 0xb8,
+ 0xeb, 0xb2, 0x0f, 0x36, 0xad, 0x2d, 0xdb, 0xef, 0xac, 0x2c, 0xbb, 0xbd,
+ 0x85, 0xb0, 0x8a, 0xe2, 0xef, 0xb8, 0x9e, 0x6b, 0x3a, 0xde, 0xed, 0x36,
+ 0x60, 0x5e, 0xa3, 0x7e, 0xca, 0xdd, 0xa9, 0x9e, 0x0f, 0xa4, 0x9d, 0x30,
+ 0xf3, 0x9d, 0xc2, 0x3b, 0x54, 0x1d, 0xf2, 0xb1, 0x6e, 0xae, 0x1c, 0xc2,
+ 0xdc, 0xce, 0x4f, 0xa7, 0xdc, 0x2e, 0x85, 0xfb, 0x3c, 0x7f, 0x07, 0x41,
+ 0xc6, 0xcf, 0xe9, 0x35, 0xfd, 0xee, 0x74, 0x02, 0xcf, 0x80, 0x3f, 0x9e,
+ 0x4e, 0x6d, 0x92, 0xab, 0xed, 0xba, 0x7c, 0x13, 0x63, 0x76, 0xbb, 0x77,
+ 0xa8, 0x6e, 0xd7, 0x57, 0x29, 0x77, 0x56, 0xce, 0xe0, 0x39, 0x08, 0x6e,
+ 0xf4, 0x53, 0x89, 0x1c, 0xd6, 0xec, 0x42, 0x21, 0x2e, 0xdf, 0x2b, 0xa4,
+ 0x40, 0xc5, 0xa9, 0xde, 0x39, 0xe9, 0xf3, 0xe7, 0x00, 0x6f, 0x1e, 0xd7,
+ 0x41, 0xbe, 0x2b, 0xe3, 0x5d, 0x99, 0x6d, 0x83, 0xe0, 0x26, 0xff, 0x37,
+ 0x83, 0xb1, 0x76, 0xc3, 0x17, 0x4f, 0x15, 0xb1, 0x9e, 0x80, 0xf9, 0x74,
+ 0x11, 0xeb, 0x89, 0xb5, 0x7a, 0x5c, 0xaf, 0x7b, 0x2f, 0xd6, 0x9d, 0xb4,
+ 0x41, 0xba, 0xd8, 0x61, 0x69, 0xf9, 0x03, 0xf6, 0x2e, 0x92, 0x29, 0x3a,
+ 0x92, 0xf1, 0xff, 0x31, 0x48, 0x6b, 0x7e, 0x11, 0x67, 0xb8, 0x48, 0x5a,
+ 0x6c, 0x00, 0xac, 0x7c, 0xcc, 0xda, 0x7a, 0x1b, 0x1d, 0xe0, 0x96, 0xeb,
+ 0xc0, 0xf7, 0x31, 0xe5, 0x35, 0xd9, 0xf7, 0x21, 0x5f, 0xf0, 0xdf, 0x26,
+ 0x47, 0xbc, 0x6a, 0xbd, 0x0c, 0x69, 0xb2, 0x92, 0x93, 0xec, 0x83, 0x81,
+ 0x0c, 0xfb, 0xc0, 0x13, 0xfb, 0x74, 0x7d, 0xd1, 0x6d, 0x5d, 0xd6, 0xd1,
+ 0x75, 0xf1, 0x6f, 0x7d, 0x23, 0xc6, 0x70, 0x46, 0x8a, 0xd5, 0xb6, 0x23,
+ 0xc5, 0xfc, 0x66, 0x0b, 0x1f, 0x9e, 0x07, 0x9d, 0x4c, 0xe5, 0x82, 0x5d,
+ 0xdb, 0x70, 0x1e, 0x57, 0xd7, 0xa1, 0x6d, 0x17, 0x7c, 0xe0, 0x4a, 0xb6,
+ 0x30, 0x88, 0x71, 0xe3, 0xb8, 0x07, 0xc1, 0x94, 0x9f, 0x4e, 0x45, 0x65,
+ 0x08, 0xcf, 0xa3, 0xe4, 0x3d, 0xe0, 0x4f, 0xa2, 0x99, 0xed, 0xbe, 0x8c,
+ 0x80, 0xee, 0xf3, 0x95, 0xd7, 0x97, 0x22, 0x7a, 0x0e, 0xfe, 0x3f, 0x59,
+ 0xdc, 0x70, 0x1c, 0x33, 0xe6, 0x54, 0xb1, 0x43, 0xf2, 0xd3, 0x9e, 0x4c,
+ 0x16, 0x16, 0x7a, 0x95, 0xbc, 0x4c, 0x7e, 0xc7, 0xfa, 0xa5, 0x40, 0xbb,
+ 0x43, 0x32, 0x5c, 0xf1, 0x24, 0x5f, 0xc0, 0xbd, 0xd8, 0x0d, 0xfa, 0x8d,
+ 0x4a, 0x3a, 0x61, 0xd6, 0x26, 0x5f, 0x18, 0xc1, 0xfc, 0x80, 0x6b, 0x8f,
+ 0xbf, 0x07, 0x2d, 0x4c, 0xae, 0x64, 0x06, 0x48, 0x3f, 0x6f, 0x06, 0x96,
+ 0x98, 0xcc, 0xfa, 0xe0, 0x0b, 0xd7, 0xc0, 0x92, 0x2f, 0xc6, 0xa2, 0xc3,
+ 0x98, 0xf7, 0x70, 0xf9, 0x57, 0xd0, 0x7f, 0x8b, 0xfe, 0x0d, 0x7e, 0xb2,
+ 0x65, 0x51, 0xdc, 0xe3, 0xb8, 0x13, 0xe6, 0x90, 0x56, 0x21, 0x1b, 0xa6,
+ 0x3b, 0x65, 0x12, 0xb4, 0x3a, 0x2c, 0xf8, 0x3d, 0xcf, 0xb9, 0x10, 0xae,
+ 0x0e, 0xfd, 0x7b, 0x72, 0x7a, 0x8b, 0x7e, 0xce, 0x8e, 0x76, 0x48, 0x6e,
+ 0x3e, 0x9c, 0x33, 0xe5, 0x05, 0x65, 0x44, 0xea, 0xb0, 0x08, 0x65, 0x46,
+ 0x10, 0x3c, 0xe8, 0x53, 0x6e, 0x04, 0xc1, 0x69, 0x9f, 0x72, 0xe4, 0x0c,
+ 0xe4, 0x03, 0x65, 0x07, 0x79, 0xd9, 0x53, 0x5c, 0xab, 0x4c, 0xa1, 0x17,
+ 0xeb, 0xd1, 0x28, 0xd9, 0xfe, 0xe3, 0x84, 0x15, 0x72, 0xe7, 0xa5, 0x4f,
+ 0x66, 0xbc, 0x5c, 0x22, 0xa2, 0xf1, 0x04, 0xca, 0x82, 0x3c, 0x4c, 0xeb,
+ 0x99, 0x75, 0x49, 0xbe, 0xbf, 0x64, 0xeb, 0xc8, 0xaf, 0xb2, 0x4e, 0x74,
+ 0x4d, 0x9d, 0x7f, 0xa7, 0x0c, 0x5f, 0xf6, 0x62, 0xdd, 0x3a, 0x14, 0xf1,
+ 0xd8, 0xb5, 0x8d, 0xcf, 0x12, 0x6b, 0x18, 0xfa, 0x3d, 0xbc, 0x7b, 0xee,
+ 0x53, 0x8f, 0x7a, 0xf5, 0xde, 0xfd, 0x28, 0xba, 0xf6, 0xdd, 0x94, 0x44,
+ 0xbd, 0x54, 0xef, 0x8d, 0xea, 0x4f, 0x1a, 0xa4, 0x35, 0x08, 0x1e, 0xf5,
+ 0xc3, 0xf2, 0xc6, 0x86, 0xb5, 0x63, 0x5c, 0x55, 0xa7, 0xec, 0x68, 0x9d,
+ 0xb2, 0xcf, 0xd7, 0x29, 0x7b, 0x7b, 0xe3, 0xda, 0xb2, 0xdb, 0xeb, 0x94,
+ 0xcd, 0xd6, 0x29, 0xfb, 0x69, 0x9d, 0x32, 0x69, 0x5a, 0x5b, 0x16, 0xa9,
+ 0x53, 0xd6, 0x57, 0xa7, 0x2c, 0x0a, 0xbe, 0xdb, 0x26, 0xf9, 0xf8, 0xbd,
+ 0x9c, 0xbb, 0xc5, 0x4d, 0x29, 0xb2, 0x16, 0x37, 0x0d, 0xa8, 0xd7, 0xb9,
+ 0xaa, 0xde, 0x17, 0xeb, 0xd4, 0x6b, 0x44, 0xbd, 0xb6, 0x55, 0xf5, 0x76,
+ 0xd4, 0xc1, 0x75, 0x13, 0xea, 0xc5, 0x56, 0xd5, 0x7b, 0xb0, 0x4e, 0x3d,
+ 0x96, 0x7f, 0xc6, 0x8e, 0xd3, 0x07, 0x2d, 0xf4, 0x5a, 0xeb, 0xd5, 0x28,
+ 0xd2, 0xce, 0xf2, 0x5e, 0xe8, 0x90, 0x0e, 0x65, 0xe4, 0x02, 0x65, 0x10,
+ 0xcb, 0x3a, 0x41, 0xe7, 0x71, 0xd0, 0x1d, 0xe5, 0x28, 0xf8, 0x8c, 0x73,
+ 0xa9, 0x6c, 0x90, 0xb1, 0x78, 0x9f, 0x7b, 0xb5, 0x6a, 0x01, 0x8d, 0xa5,
+ 0xdc, 0xa4, 0x22, 0xff, 0x49, 0x2e, 0x32, 0xe4, 0xe5, 0x86, 0x45, 0xc5,
+ 0x95, 0x04, 0x32, 0xe2, 0xab, 0x36, 0x25, 0xf7, 0x80, 0xbf, 0xd2, 0xd0,
+ 0x59, 0x37, 0x06, 0xc3, 0x9a, 0xb7, 0x4c, 0xdd, 0x8b, 0xcb, 0x54, 0x5f,
+ 0x0e, 0x52, 0x16, 0x0e, 0x8d, 0x7e, 0x2a, 0xe3, 0x2d, 0x0c, 0x36, 0x82,
+ 0x66, 0xcf, 0xa3, 0xcd, 0x6e, 0xb4, 0xdc, 0x57, 0x8e, 0xca, 0x48, 0x79,
+ 0x00, 0xbc, 0xe0, 0xc8, 0x39, 0x6f, 0xa3, 0x9c, 0xf3, 0x51, 0xb7, 0x12,
+ 0x91, 0xc5, 0xb8, 0x23, 0x8b, 0x78, 0xce, 0xf8, 0x78, 0x57, 0x09, 0x79,
+ 0x6b, 0x40, 0x0e, 0x14, 0x7d, 0x39, 0x5c, 0xbc, 0x41, 0x85, 0x7a, 0x6d,
+ 0xa7, 0xbf, 0x5e, 0x1e, 0x73, 0x4d, 0xdf, 0xbb, 0xbd, 0x05, 0x68, 0xd4,
+ 0xa8, 0x9c, 0xf7, 0x52, 0x89, 0x45, 0xcd, 0x13, 0xff, 0x27, 0x18, 0x41,
+ 0x3f, 0xb3, 0x5e, 0xca, 0xfd, 0x03, 0x3c, 0x8f, 0x95, 0x69, 0xcb, 0x54,
+ 0xfb, 0x9a, 0x44, 0x5f, 0x87, 0x8a, 0x1b, 0xe4, 0x56, 0xdb, 0x7e, 0x97,
+ 0xb7, 0xd0, 0x0b, 0x9e, 0x73, 0x4f, 0x50, 0x86, 0x14, 0x00, 0xd7, 0x5e,
+ 0xf0, 0x36, 0xda, 0x7e, 0x4d, 0xcb, 0x33, 0xd8, 0x3e, 0x85, 0x8d, 0x90,
+ 0xcf, 0x7f, 0x17, 0xdc, 0x1a, 0x67, 0x7d, 0x96, 0x51, 0xe7, 0x48, 0x49,
+ 0x0d, 0x41, 0x26, 0x0c, 0x50, 0x66, 0x26, 0x21, 0x2f, 0x21, 0x7b, 0x8a,
+ 0x3f, 0x0d, 0xd2, 0xd1, 0x5a, 0x39, 0x28, 0xb9, 0x6a, 0x1d, 0x96, 0x25,
+ 0x8d, 0x5c, 0x2d, 0x2e, 0x2d, 0xcb, 0x8a, 0x1c, 0xe4, 0xcb, 0x53, 0x15,
+ 0xca, 0x85, 0x0f, 0x82, 0x47, 0x3b, 0x65, 0xa4, 0x90, 0xca, 0xa5, 0x65,
+ 0x1b, 0xd6, 0xef, 0xd7, 0xb1, 0xa6, 0x51, 0x5c, 0x0f, 0xad, 0x97, 0x56,
+ 0x1f, 0xba, 0x9b, 0xe5, 0xe8, 0xb4, 0x9d, 0x36, 0xd2, 0x6f, 0x03, 0x0f,
+ 0x93, 0x5c, 0xf3, 0x44, 0x26, 0xe2, 0x8c, 0xd2, 0x5e, 0x19, 0x85, 0x7c,
+ 0xcc, 0x96, 0xd9, 0x37, 0xe1, 0x4d, 0xd8, 0xdf, 0xb0, 0x9b, 0x0a, 0x9d,
+ 0xf6, 0x77, 0x0b, 0x7e, 0x27, 0xed, 0x6f, 0xc8, 0xd4, 0x82, 0x67, 0x7f,
+ 0xc7, 0xb5, 0x1c, 0x32, 0xbf, 0x13, 0xf8, 0xdd, 0xaf, 0x7f, 0x4f, 0x15,
+ 0x77, 0xed, 0x52, 0xde, 0x95, 0x92, 0x9d, 0xef, 0x94, 0x03, 0x85, 0x77,
+ 0x58, 0xd9, 0x82, 0x4b, 0xbe, 0xe4, 0x98, 0x79, 0x26, 0xf4, 0xba, 0xe7,
+ 0x8b, 0x39, 0x67, 0x94, 0xf0, 0xe3, 0xf7, 0x70, 0xa1, 0xcf, 0xdd, 0x24,
+ 0xa4, 0x81, 0x29, 0x67, 0xb8, 0xe2, 0xa4, 0x23, 0x43, 0x3d, 0x89, 0x49,
+ 0x39, 0x8c, 0xdf, 0xe2, 0x46, 0x86, 0xbe, 0x84, 0xbb, 0xc1, 0xc1, 0x57,
+ 0xb6, 0x43, 0xb6, 0x16, 0x29, 0x2f, 0x3d, 0xcc, 0x3d, 0x29, 0x67, 0x56,
+ 0xd8, 0x58, 0xc4, 0x85, 0x92, 0xec, 0x74, 0xea, 0x78, 0x4e, 0x52, 0xb9,
+ 0x19, 0x30, 0xc4, 0x8d, 0x7e, 0x54, 0xde, 0xe7, 0x83, 0x76, 0xaf, 0x74,
+ 0x64, 0xd7, 0x95, 0x51, 0xd8, 0x44, 0xde, 0xcc, 0x2e, 0xc8, 0x58, 0xc8,
+ 0xbe, 0x08, 0xe9, 0x41, 0x9d, 0x92, 0xb1, 0xe8, 0x10, 0xb0, 0x7d, 0xaa,
+ 0x7f, 0x64, 0xb2, 0x90, 0xbd, 0x5d, 0x0d, 0xed, 0xff, 0x6c, 0x66, 0xe0,
+ 0xad, 0x92, 0xdd, 0xab, 0x80, 0xa3, 0xf6, 0x31, 0xc8, 0x4c, 0xcc, 0x2b,
+ 0x08, 0x40, 0xcf, 0x90, 0xe7, 0x37, 0xdd, 0x14, 0x19, 0x6a, 0x90, 0xe1,
+ 0xbd, 0xed, 0x68, 0xc3, 0x77, 0xc4, 0xd7, 0x79, 0xe0, 0x33, 0x95, 0x1c,
+ 0x11, 0xb9, 0x7b, 0x6a, 0x60, 0xc9, 0x99, 0x2c, 0x7d, 0x10, 0x3c, 0x79,
+ 0x15, 0xda, 0x3f, 0x80, 0xf6, 0x2f, 0x3b, 0xf9, 0xe9, 0x57, 0x9c, 0xc9,
+ 0xe9, 0xbf, 0x75, 0xa6, 0xa6, 0xb7, 0x6c, 0xd9, 0x39, 0xb8, 0x65, 0xcb,
+ 0xf8, 0x60, 0xd4, 0xea, 0x97, 0x2d, 0x5b, 0xa6, 0x06, 0x07, 0x81, 0x83,
+ 0x3e, 0x77, 0x44, 0x3c, 0x77, 0x97, 0x80, 0x7f, 0xe2, 0x1c, 0x93, 0xfa,
+ 0x27, 0x85, 0xf7, 0x6c, 0xef, 0xe9, 0xf7, 0xc3, 0xd2, 0x97, 0x68, 0x13,
+ 0x8e, 0x1f, 0xb1, 0x75, 0xda, 0x01, 0xfb, 0x03, 0x76, 0x7d, 0x0b, 0xaa,
+ 0xc1, 0x63, 0x39, 0xe7, 0xc2, 0x72, 0xae, 0xed, 0x8f, 0xac, 0x2d, 0xbb,
+ 0x11, 0xe5, 0x7c, 0x26, 0xce, 0x88, 0x17, 0xda, 0x22, 0x0d, 0xda, 0x76,
+ 0xcc, 0x16, 0x48, 0x33, 0x51, 0x99, 0x28, 0xb4, 0xa1, 0x0d, 0xe8, 0xe2,
+ 0x94, 0xbd, 0x8e, 0x02, 0xb6, 0xbd, 0xe8, 0xeb, 0xe8, 0x21, 0xb4, 0xa3,
+ 0xcc, 0x48, 0xf5, 0x8a, 0xfa, 0x04, 0xea, 0xf4, 0xb9, 0x9b, 0x85, 0x36,
+ 0xc7, 0x71, 0xc9, 0x16, 0xc9, 0xdf, 0x3d, 0x80, 0x27, 0x26, 0xc9, 0x76,
+ 0x3c, 0x57, 0x0e, 0xc0, 0x0e, 0x69, 0xb0, 0x3a, 0x33, 0x94, 0x17, 0xfc,
+ 0x77, 0x87, 0x12, 0xef, 0x80, 0x8c, 0xcd, 0x5d, 0x8e, 0x7a, 0x0e, 0xf0,
+ 0x42, 0x3b, 0x05, 0x36, 0xcb, 0x5c, 0x5a, 0x32, 0xdb, 0xee, 0xc5, 0xdd,
+ 0xc5, 0x73, 0x1e, 0xf7, 0xb7, 0xe0, 0x3e, 0x89, 0x7b, 0x08, 0x27, 0xf0,
+ 0xea, 0x47, 0xac, 0xce, 0xba, 0x06, 0x63, 0xff, 0x6b, 0xc9, 0x94, 0x12,
+ 0xb4, 0x39, 0x36, 0x66, 0xbc, 0xb4, 0xab, 0x44, 0x6d, 0x56, 0x32, 0x85,
+ 0xfa, 0xf0, 0x09, 0xbc, 0x83, 0x32, 0x7e, 0x12, 0xbf, 0x1f, 0xa4, 0x4d,
+ 0x3c, 0x25, 0xe3, 0x73, 0x1c, 0xa7, 0x00, 0x98, 0x4a, 0x92, 0x3d, 0xf9,
+ 0x00, 0xae, 0x69, 0x5c, 0x0f, 0xe3, 0xe2, 0xdc, 0xd8, 0xff, 0xe2, 0x26,
+ 0x05, 0x5c, 0xf3, 0x39, 0x4b, 0x3a, 0xae, 0xe0, 0x37, 0x69, 0xb8, 0x42,
+ 0xdb, 0x06, 0xf4, 0x5b, 0x09, 0xe9, 0xda, 0xb7, 0xbf, 0x13, 0x9a, 0xaf,
+ 0x73, 0x6d, 0xa0, 0x99, 0xca, 0xa0, 0x96, 0x39, 0x19, 0x0f, 0xf7, 0x0a,
+ 0x6c, 0x8f, 0x36, 0xce, 0xd1, 0xb3, 0x65, 0x9e, 0x2e, 0x4b, 0xea, 0xb2,
+ 0x7e, 0x5b, 0x86, 0x7b, 0xa5, 0x41, 0xc6, 0xda, 0x01, 0x31, 0xe5, 0xb3,
+ 0x84, 0xf8, 0xa4, 0x0c, 0x00, 0xfd, 0xc2, 0x66, 0x38, 0x73, 0x51, 0xf9,
+ 0xb7, 0xa4, 0x6d, 0xb1, 0xc7, 0x2b, 0xa4, 0x63, 0xd2, 0x76, 0x10, 0xdc,
+ 0xef, 0x37, 0xa1, 0x7f, 0xf2, 0xbc, 0x48, 0xc3, 0xd1, 0xa8, 0xcc, 0xb8,
+ 0xa4, 0x85, 0x77, 0xb4, 0x90, 0x06, 0x1a, 0x3d, 0xd2, 0x70, 0x2d, 0x7f,
+ 0x71, 0x0d, 0xd9, 0x5f, 0x0e, 0xf6, 0x1d, 0xed, 0xbc, 0x1e, 0xd8, 0xce,
+ 0x1c, 0xe3, 0x30, 0x9f, 0x5d, 0x05, 0x9e, 0xca, 0x2c, 0xf3, 0x94, 0xc8,
+ 0x6c, 0x81, 0xb8, 0x09, 0xed, 0x3f, 0xae, 0x33, 0xf1, 0xf3, 0x38, 0xe6,
+ 0xcc, 0xfb, 0x19, 0x8b, 0xa7, 0x2f, 0x59, 0x3c, 0x7d, 0xd9, 0xde, 0x5d,
+ 0x27, 0xab, 0x6d, 0xc1, 0x05, 0x3c, 0x73, 0x7d, 0xa2, 0x1a, 0x67, 0xd9,
+ 0xc2, 0x0c, 0xee, 0xa8, 0x5b, 0x7c, 0x5c, 0xc6, 0xb5, 0x9d, 0x16, 0x91,
+ 0x77, 0x69, 0xd9, 0x06, 0x21, 0xdd, 0x5c, 0x00, 0xcc, 0x0d, 0x92, 0x8b,
+ 0x47, 0xf4, 0xda, 0x47, 0xbd, 0x03, 0x51, 0x43, 0xab, 0xc4, 0xc9, 0x0a,
+ 0x5f, 0xaa, 0x06, 0xa6, 0xb8, 0x95, 0x73, 0x84, 0x8b, 0xb4, 0xfb, 0x88,
+ 0x86, 0xeb, 0x16, 0xc8, 0xbb, 0x9c, 0xa8, 0xf6, 0x46, 0xb9, 0x0c, 0xb4,
+ 0xa0, 0xe2, 0xd0, 0x5c, 0xc1, 0xd3, 0xb0, 0x9b, 0xb2, 0x73, 0xb4, 0xa1,
+ 0xbb, 0xe8, 0xb7, 0xc4, 0xb2, 0xfd, 0xad, 0xa4, 0x23, 0xa5, 0x60, 0x7f,
+ 0xe1, 0x59, 0x65, 0xfb, 0x35, 0x9d, 0x3a, 0xca, 0x8b, 0x6b, 0x3b, 0x19,
+ 0xbc, 0x12, 0xb1, 0xbe, 0x73, 0x54, 0x79, 0x9b, 0x57, 0x97, 0x25, 0xa9,
+ 0x87, 0xd1, 0x2e, 0x99, 0xed, 0x6f, 0x27, 0x8f, 0xb9, 0xca, 0x03, 0x2e,
+ 0x3d, 0xed, 0x1b, 0xe5, 0xd4, 0xc0, 0xc6, 0x55, 0xf5, 0xf5, 0xdd, 0xb1,
+ 0xcf, 0x51, 0x7b, 0x77, 0xed, 0x3d, 0x69, 0xef, 0xb9, 0xe8, 0x00, 0xef,
+ 0x8e, 0x44, 0x87, 0x78, 0xc7, 0x1a, 0x0e, 0xb1, 0x0f, 0xcd, 0x57, 0x56,
+ 0xce, 0xf4, 0xb8, 0x79, 0x21, 0x5f, 0xfd, 0xa9, 0xdc, 0x32, 0x67, 0xe4,
+ 0xef, 0x2e, 0xc8, 0x20, 0xf8, 0x6f, 0xee, 0xa2, 0x00, 0xfe, 0xbd, 0x65,
+ 0xb9, 0xa5, 0x42, 0xbc, 0xfd, 0x06, 0xf0, 0xb7, 0x35, 0x4a, 0xde, 0x74,
+ 0x85, 0x72, 0xf7, 0x4e, 0xd1, 0xf6, 0x69, 0x81, 0x38, 0x3f, 0x2b, 0x5c,
+ 0x9b, 0x7c, 0xe1, 0x19, 0xbd, 0x36, 0x07, 0x0b, 0x8b, 0xc0, 0xcf, 0xd7,
+ 0x41, 0xf7, 0x41, 0xb0, 0xe8, 0xe7, 0x41, 0x39, 0x7f, 0x84, 0xdf, 0xe8,
+ 0xbb, 0xf0, 0x1c, 0xde, 0xb7, 0x4a, 0xbe, 0x44, 0x9e, 0x8b, 0x5a, 0x1e,
+ 0x3e, 0x05, 0x7e, 0xba, 0x0c, 0xfd, 0xa2, 0x6c, 0x80, 0xbf, 0xff, 0x11,
+ 0xef, 0x70, 0x9f, 0xc3, 0x22, 0xb6, 0xd3, 0xd6, 0xe1, 0xd8, 0x5c, 0x3b,
+ 0xae, 0x59, 0x5c, 0xfb, 0xad, 0x8f, 0x2f, 0xaf, 0x1b, 0xd7, 0x2b, 0xd5,
+ 0x9b, 0x93, 0x70, 0xcd, 0x44, 0x1e, 0x2f, 0xb0, 0x3e, 0xe9, 0xff, 0x1f,
+ 0x62, 0x46, 0x17, 0xfc, 0xc9, 0x3a, 0x73, 0x5f, 0xdd, 0x96, 0x6b, 0x5e,
+ 0x4b, 0x83, 0xf4, 0x6f, 0x52, 0x83, 0x39, 0xc8, 0x9d, 0xa8, 0xd7, 0x2a,
+ 0x23, 0xda, 0x27, 0x22, 0x4d, 0x90, 0x06, 0x6e, 0x56, 0x86, 0x36, 0x3f,
+ 0xa4, 0x0c, 0x6d, 0x3e, 0x03, 0x5a, 0xc4, 0x55, 0x5c, 0x72, 0x0c, 0x6d,
+ 0x7e, 0x1d, 0x77, 0x5c, 0xc5, 0x0b, 0x4e, 0xc8, 0xc7, 0xc3, 0xf0, 0xf9,
+ 0x76, 0x15, 0xa2, 0xce, 0x78, 0x05, 0xf4, 0x5b, 0x8c, 0xa1, 0x7c, 0x81,
+ 0x38, 0xc7, 0xfc, 0x39, 0xce, 0x56, 0xdb, 0xff, 0xe3, 0x32, 0x51, 0x0c,
+ 0xb4, 0x5d, 0x95, 0x9d, 0xbb, 0x17, 0xf7, 0xf5, 0x5a, 0xce, 0x28, 0x2f,
+ 0xad, 0x8c, 0xbc, 0x7a, 0x17, 0xee, 0xdd, 0x89, 0x83, 0xd2, 0xed, 0x46,
+ 0xe4, 0x39, 0xf4, 0xf5, 0x43, 0x67, 0xa2, 0xf2, 0x32, 0xae, 0x9f, 0xe0,
+ 0x7a, 0x15, 0xd7, 0x2b, 0xe8, 0xf7, 0x45, 0x94, 0xaf, 0x97, 0x05, 0xb7,
+ 0x19, 0xf5, 0x45, 0x8d, 0x57, 0x5e, 0x70, 0xc6, 0x4e, 0xbe, 0x84, 0x2b,
+ 0xaa, 0x26, 0x2a, 0xcf, 0x3b, 0xd9, 0xb9, 0x60, 0xe3, 0xa2, 0x47, 0x19,
+ 0xf6, 0xa7, 0x8e, 0xe9, 0x7b, 0x08, 0x73, 0x00, 0x4d, 0x17, 0x17, 0x30,
+ 0xf6, 0x33, 0x9a, 0x67, 0x46, 0x20, 0xf3, 0xb3, 0xb0, 0x4b, 0xc6, 0x34,
+ 0x4c, 0x97, 0x03, 0x3e, 0xf8, 0xba, 0x03, 0xb8, 0xcf, 0x35, 0xca, 0x52,
+ 0x9c, 0x76, 0xe4, 0x97, 0x75, 0xfd, 0x6c, 0xb1, 0x5b, 0xe3, 0x76, 0x66,
+ 0x0d, 0xff, 0xd0, 0x3f, 0x0b, 0xe5, 0x81, 0x91, 0xc6, 0xb3, 0x05, 0xca,
+ 0x02, 0xe8, 0x9f, 0xc2, 0x14, 0xee, 0x8d, 0x5a, 0x26, 0xe4, 0x25, 0x94,
+ 0x07, 0x6c, 0x47, 0x99, 0x50, 0x2b, 0x77, 0x28, 0x6b, 0x28, 0x7b, 0x28,
+ 0x4b, 0xcc, 0x7a, 0x8c, 0x3f, 0x48, 0x19, 0x7e, 0x2d, 0xfc, 0x53, 0xda,
+ 0x1f, 0x9d, 0xc6, 0x07, 0x99, 0xce, 0x28, 0x23, 0x4f, 0xf7, 0xe8, 0xb5,
+ 0x98, 0x28, 0xa8, 0x38, 0x20, 0x47, 0x19, 0xae, 0x63, 0x7b, 0x71, 0xcf,
+ 0xaa, 0x09, 0x5c, 0xd9, 0x63, 0x1f, 0xc0, 0x6f, 0xae, 0xcd, 0x04, 0xea,
+ 0xe1, 0x2a, 0x8e, 0xe2, 0x8e, 0x0b, 0xb6, 0x99, 0x91, 0x23, 0x5c, 0xd3,
+ 0x84, 0x5d, 0xd3, 0x2f, 0x03, 0x0f, 0x9c, 0x9f, 0xd2, 0xf1, 0x07, 0xe5,
+ 0xed, 0x00, 0xde, 0x2b, 0xd6, 0xdf, 0x6d, 0x15, 0xc3, 0x83, 0xb8, 0x7a,
+ 0xc9, 0xcf, 0x2d, 0x66, 0xbd, 0x34, 0xed, 0x7e, 0x37, 0x6a, 0x78, 0x31,
+ 0x8e, 0xb2, 0x08, 0xca, 0xda, 0x45, 0xf3, 0xfe, 0x32, 0x1e, 0xd3, 0x16,
+ 0x8f, 0xfc, 0xad, 0xec, 0x6f, 0xd0, 0x13, 0x6c, 0xda, 0x8c, 0x37, 0x80,
+ 0x71, 0x31, 0x97, 0x63, 0x7b, 0xd4, 0x38, 0xe4, 0xf7, 0xb8, 0x47, 0x19,
+ 0xce, 0x38, 0x03, 0xe7, 0xc7, 0x7e, 0x51, 0xae, 0x71, 0xe0, 0x4b, 0xd5,
+ 0x87, 0xff, 0x32, 0xd6, 0xec, 0x71, 0xd9, 0x57, 0xbc, 0x5a, 0xfb, 0xd4,
+ 0x8d, 0x47, 0xcd, 0x7a, 0x88, 0x0a, 0xeb, 0xa1, 0xef, 0x38, 0x6d, 0x9b,
+ 0x31, 0xfd, 0x3e, 0x7a, 0x94, 0xbf, 0x29, 0x9f, 0x6b, 0xe5, 0xbd, 0xb1,
+ 0x6b, 0xf2, 0x2b, 0x64, 0x1d, 0x6d, 0x0b, 0xac, 0x59, 0xb9, 0x16, 0xef,
+ 0xf4, 0xf1, 0x29, 0xf3, 0xc8, 0x4f, 0x07, 0xc1, 0x13, 0xaa, 0xc1, 0xf0,
+ 0x3e, 0x7d, 0x8d, 0x7a, 0xfc, 0x04, 0xfb, 0x0b, 0xbc, 0x72, 0x02, 0xb6,
+ 0xdb, 0xae, 0xe5, 0x3e, 0x20, 0x2b, 0xe3, 0x31, 0x39, 0x59, 0x68, 0x91,
+ 0xb9, 0x82, 0x82, 0xc1, 0x60, 0x64, 0x67, 0x44, 0x12, 0x5a, 0xff, 0xd2,
+ 0xbe, 0x1b, 0x9e, 0x8e, 0x58, 0xba, 0x83, 0xc3, 0xd2, 0xfc, 0x1b, 0xd0,
+ 0xb1, 0x65, 0xe8, 0xd8, 0x56, 0xe8, 0xe0, 0xd5, 0x32, 0xa2, 0xab, 0x61,
+ 0xad, 0x8c, 0x60, 0x9b, 0x14, 0xbc, 0xf2, 0x83, 0x68, 0x17, 0xd2, 0x5f,
+ 0x4c, 0xd3, 0x5a, 0x56, 0x72, 0xce, 0xae, 0xca, 0x94, 0xb3, 0xbb, 0xb2,
+ 0x5a, 0x07, 0xf5, 0xb9, 0x51, 0x31, 0xb0, 0x9e, 0xd4, 0x71, 0xbc, 0x94,
+ 0x9f, 0x01, 0x4e, 0x76, 0x83, 0xee, 0x9e, 0x2e, 0xc1, 0x8f, 0xa7, 0x5c,
+ 0x06, 0xcc, 0x8f, 0x01, 0xe6, 0xd9, 0x92, 0x13, 0xda, 0x06, 0xc2, 0xe0,
+ 0xc9, 0xec, 0x74, 0xbf, 0x2c, 0xce, 0x93, 0x0e, 0x21, 0x03, 0x4a, 0x58,
+ 0x4f, 0x7f, 0x1d, 0xec, 0x00, 0x8e, 0x0f, 0xb9, 0x3d, 0xdd, 0xa1, 0xdf,
+ 0x19, 0x7d, 0xde, 0x29, 0x8b, 0xe5, 0xf7, 0x58, 0xd8, 0x0e, 0xd7, 0xc0,
+ 0xb6, 0x6e, 0x19, 0xb6, 0xdd, 0x80, 0x6d, 0x4f, 0x5d, 0xd8, 0xea, 0xe9,
+ 0xe2, 0x2e, 0xd8, 0x34, 0xe4, 0x8f, 0x10, 0xaf, 0xed, 0x96, 0x1e, 0x6e,
+ 0xb7, 0xf6, 0x2e, 0x6d, 0xa2, 0x9f, 0x02, 0x1e, 0xd2, 0x18, 0x7e, 0xcf,
+ 0x3d, 0x4a, 0x59, 0x86, 0x72, 0x3e, 0x7f, 0x06, 0x75, 0xf0, 0x3c, 0xf7,
+ 0xe7, 0x56, 0x0e, 0xde, 0x65, 0x61, 0xa1, 0x9d, 0x90, 0x86, 0x4d, 0x3c,
+ 0xe2, 0x64, 0xe6, 0x08, 0x43, 0x0e, 0xf0, 0xe2, 0x5d, 0xa5, 0xb6, 0x4f,
+ 0xde, 0xd9, 0xef, 0x15, 0xb6, 0x1f, 0xf6, 0x1d, 0xce, 0x65, 0xbd, 0xd5,
+ 0xf3, 0x21, 0x7d, 0x85, 0xf6, 0xf5, 0x94, 0x93, 0x5e, 0x33, 0xaf, 0x5a,
+ 0x9a, 0xa3, 0xbc, 0x8d, 0xca, 0x4e, 0xd0, 0xc9, 0xce, 0x15, 0xb4, 0xa6,
+ 0xdd, 0x10, 0x4b, 0xc7, 0xeb, 0xec, 0xfc, 0x0e, 0x18, 0xbe, 0xf1, 0x63,
+ 0xd0, 0x87, 0x94, 0x37, 0x37, 0x1b, 0xdf, 0x5c, 0x4e, 0x00, 0xd6, 0xf0,
+ 0x99, 0xb4, 0xc9, 0xdf, 0x94, 0x49, 0x55, 0x5a, 0x34, 0xbe, 0x4b, 0xa7,
+ 0x8e, 0x9f, 0x56, 0xed, 0xf5, 0xa8, 0x8c, 0x9a, 0x35, 0x3f, 0xcc, 0x35,
+ 0xa7, 0x2f, 0xd2, 0xfd, 0xc0, 0xa8, 0xe5, 0xaf, 0x54, 0x29, 0x27, 0xbb,
+ 0xed, 0xdc, 0xbf, 0x5c, 0x67, 0xed, 0x5a, 0x97, 0xd7, 0x6e, 0xb4, 0xb2,
+ 0x7a, 0x8e, 0x22, 0x5d, 0x0f, 0x44, 0xb5, 0x6f, 0x2b, 0xca, 0x97, 0x46,
+ 0x8f, 0xf2, 0x93, 0xb6, 0x12, 0xca, 0x67, 0xfb, 0xdc, 0x36, 0xd0, 0xdb,
+ 0x53, 0x6b, 0xec, 0xae, 0xa4, 0x95, 0x9b, 0xf4, 0x83, 0xc3, 0x31, 0x72,
+ 0x56, 0x4e, 0xe6, 0xd0, 0xff, 0x94, 0xb3, 0xb3, 0x52, 0x4f, 0x5e, 0x86,
+ 0x72, 0x92, 0xf3, 0xb9, 0x57, 0xee, 0x78, 0x90, 0x3c, 0x7a, 0xbb, 0xb6,
+ 0xaf, 0xaf, 0xda, 0x71, 0x00, 0xf8, 0x23, 0xfc, 0x8b, 0x9b, 0x60, 0x32,
+ 0x40, 0xe7, 0xa6, 0x65, 0xdc, 0xae, 0xdb, 0xf8, 0xf2, 0xfa, 0xf3, 0x6a,
+ 0xc7, 0x6f, 0xc6, 0x59, 0x95, 0x85, 0x59, 0xdb, 0xb1, 0xb0, 0xeb, 0x56,
+ 0xdb, 0xb2, 0x9c, 0x03, 0xed, 0xd9, 0x46, 0x63, 0x0b, 0x16, 0x69, 0x7f,
+ 0x52, 0x76, 0xd1, 0xfe, 0x8c, 0x35, 0x4a, 0x33, 0xe7, 0x33, 0x68, 0xcb,
+ 0x68, 0xa7, 0xae, 0x9e, 0xdf, 0x6a, 0xff, 0x91, 0x70, 0x12, 0x6e, 0x43,
+ 0x5b, 0x49, 0x45, 0xd8, 0x02, 0x19, 0xf5, 0xaf, 0xd5, 0x6b, 0xa0, 0x68,
+ 0xbb, 0xee, 0xf8, 0x76, 0x83, 0x89, 0x31, 0x27, 0xd1, 0x3f, 0xc7, 0x24,
+ 0xff, 0xf1, 0x4e, 0x3b, 0xbf, 0x9e, 0x2c, 0xab, 0xd5, 0x3d, 0x97, 0x2d,
+ 0xe3, 0x6f, 0xe7, 0x8a, 0x35, 0x0a, 0xf1, 0x17, 0xd2, 0x45, 0x2d, 0x0e,
+ 0x49, 0x13, 0xa4, 0x85, 0x90, 0x16, 0xb7, 0x5a, 0x7d, 0x13, 0xd2, 0xde,
+ 0xa5, 0xa0, 0xbd, 0xfb, 0x80, 0x27, 0xca, 0x70, 0xc6, 0xed, 0x36, 0xe3,
+ 0xf9, 0x08, 0x9e, 0x43, 0x3e, 0xb9, 0x98, 0x0c, 0xa7, 0xfc, 0x66, 0x9b,
+ 0x8c, 0x95, 0xfb, 0xa1, 0x9f, 0xcb, 0x36, 0x9c, 0x37, 0xe5, 0xff, 0x57,
+ 0xe9, 0x77, 0x35, 0x1a, 0x3b, 0xfd, 0x43, 0x8d, 0x94, 0xaf, 0x9b, 0xe4,
+ 0x60, 0x4d, 0xd9, 0xc5, 0xe4, 0x77, 0xed, 0x9c, 0x2f, 0xff, 0x7f, 0x30,
+ 0xe7, 0xc4, 0xaa, 0x39, 0xbb, 0x76, 0xce, 0x15, 0xbc, 0x6f, 0xc3, 0xfb,
+ 0x16, 0xea, 0x82, 0x64, 0x55, 0xde, 0x58, 0x5c, 0xe8, 0x79, 0xd5, 0xca,
+ 0x89, 0x50, 0x46, 0x70, 0x5e, 0x1f, 0xb1, 0x73, 0x78, 0xa0, 0x66, 0x5e,
+ 0x1f, 0x79, 0x13, 0xf3, 0xea, 0x5c, 0x31, 0xaf, 0x5d, 0x17, 0x9d, 0x57,
+ 0x3d, 0x1e, 0x27, 0x2f, 0x87, 0xf3, 0x8b, 0xc9, 0x8d, 0x05, 0xce, 0x71,
+ 0x27, 0xe6, 0x48, 0x18, 0xc2, 0x39, 0x0e, 0xd9, 0x39, 0x8a, 0xea, 0xda,
+ 0xf1, 0x73, 0xf8, 0x5d, 0x3b, 0x3f, 0xea, 0xfe, 0x1f, 0x83, 0xa6, 0x9b,
+ 0x24, 0xd3, 0xdf, 0x64, 0xe5, 0xff, 0x97, 0xe5, 0xd6, 0x22, 0xd7, 0x3a,
+ 0x95, 0x16, 0xd9, 0xa3, 0xf6, 0x15, 0x9f, 0x6d, 0x64, 0x8c, 0x7f, 0x97,
+ 0x6f, 0xf5, 0x18, 0xf4, 0xc5, 0x6e, 0xd8, 0x7c, 0x3b, 0x0b, 0x6a, 0x20,
+ 0x22, 0x41, 0x70, 0x9b, 0xdf, 0x8c, 0xb1, 0x37, 0x6a, 0x5f, 0x75, 0x6d,
+ 0x7c, 0xfd, 0x99, 0x46, 0xf1, 0x68, 0x6f, 0x50, 0x9f, 0x43, 0xdf, 0x1d,
+ 0xa3, 0x0d, 0x96, 0x81, 0x9d, 0x9c, 0x4e, 0x44, 0xb4, 0x2d, 0x46, 0x9d,
+ 0x98, 0x4a, 0xa4, 0xa5, 0x2c, 0xd9, 0x63, 0xe9, 0x84, 0x12, 0x8e, 0x01,
+ 0x5b, 0x0d, 0x36, 0xe4, 0xad, 0x90, 0x35, 0xb7, 0x56, 0xf6, 0xaa, 0x5b,
+ 0x60, 0xef, 0xdc, 0x72, 0xf2, 0x03, 0xea, 0x36, 0xd8, 0x3a, 0xb7, 0x9d,
+ 0xbc, 0x41, 0xed, 0x83, 0x6d, 0xb3, 0x0f, 0x76, 0xce, 0xbe, 0x0a, 0x6d,
+ 0xcf, 0x9b, 0x41, 0x7b, 0x9d, 0x35, 0xb4, 0x46, 0x1b, 0x87, 0xf3, 0x23,
+ 0xee, 0x8f, 0x71, 0x0d, 0xfc, 0xa4, 0x7a, 0x45, 0xaf, 0x4b, 0xdb, 0x8a,
+ 0xb2, 0xd7, 0x92, 0x55, 0xa1, 0x7e, 0xda, 0x60, 0xe3, 0x46, 0x94, 0xb7,
+ 0xaf, 0x45, 0x5b, 0xa4, 0x11, 0x17, 0x78, 0x26, 0xfe, 0x48, 0x5b, 0xb5,
+ 0xf3, 0xdf, 0xd4, 0x24, 0x5e, 0x67, 0x93, 0x34, 0xdf, 0x0b, 0xf9, 0x5a,
+ 0x4b, 0x53, 0xbc, 0xbb, 0x56, 0xd7, 0x90, 0xb6, 0x28, 0x83, 0x43, 0x7a,
+ 0xd8, 0xfa, 0x1a, 0xf2, 0xf7, 0xa2, 0xf4, 0x74, 0x4f, 0x64, 0x28, 0x08,
+ 0xc6, 0x07, 0x64, 0x23, 0xe3, 0x01, 0x99, 0x4a, 0x35, 0x26, 0xa0, 0xbc,
+ 0xda, 0x98, 0x00, 0xfd, 0xac, 0x47, 0x80, 0xdf, 0x19, 0x5c, 0x22, 0x63,
+ 0x8c, 0x3b, 0x54, 0x42, 0xbb, 0xfc, 0x1b, 0xd6, 0x2e, 0x0f, 0xe1, 0x48,
+ 0x02, 0x0e, 0x23, 0x9f, 0xd7, 0xea, 0xb9, 0x95, 0xfa, 0x3b, 0xb7, 0x6c,
+ 0xd3, 0x26, 0xe5, 0xc6, 0x22, 0xe7, 0x4d, 0x19, 0x4c, 0xdc, 0xd4, 0xca,
+ 0xe0, 0x84, 0xb5, 0xa3, 0x50, 0x47, 0xcb, 0xcf, 0xb5, 0xb2, 0x93, 0x72,
+ 0x8f, 0xf1, 0xf9, 0x07, 0x7c, 0xd2, 0xfa, 0x7b, 0x24, 0xbd, 0x1c, 0x9f,
+ 0x17, 0xd0, 0x9b, 0xf8, 0x91, 0x21, 0xbd, 0xdf, 0xe6, 0xce, 0xca, 0x6e,
+ 0x19, 0x8e, 0x33, 0xd6, 0xc9, 0x78, 0x9e, 0x97, 0x9b, 0x05, 0x0f, 0x4c,
+ 0x16, 0x15, 0x2c, 0xf8, 0x46, 0x19, 0x73, 0x03, 0xd9, 0xe5, 0x3b, 0x3a,
+ 0x76, 0x6c, 0x74, 0xed, 0x4c, 0x93, 0xb1, 0x5d, 0x1d, 0x1d, 0xff, 0x5d,
+ 0x04, 0xf5, 0x2d, 0x6a, 0xfb, 0x56, 0x69, 0xfd, 0xbb, 0xa0, 0xeb, 0x7c,
+ 0xae, 0x29, 0x8c, 0x63, 0x2e, 0xba, 0x11, 0x5b, 0xaf, 0xb6, 0xfc, 0x8b,
+ 0x36, 0x3e, 0x9d, 0x84, 0xec, 0x0f, 0xcb, 0xfe, 0xb0, 0x4e, 0xd9, 0xb7,
+ 0xea, 0x94, 0xfd, 0xcf, 0x3a, 0x65, 0x26, 0x2e, 0xb8, 0xb3, 0xf0, 0xf7,
+ 0x78, 0x37, 0xa5, 0x7d, 0x77, 0xb1, 0xfb, 0x61, 0xb9, 0xe5, 0x3a, 0x1b,
+ 0xac, 0x5f, 0xc6, 0x18, 0xb1, 0x89, 0x0d, 0x67, 0x75, 0x6c, 0xb8, 0xcf,
+ 0xdd, 0xa1, 0xf4, 0x5e, 0xca, 0x7e, 0xc6, 0x19, 0xf7, 0x69, 0xbc, 0x10,
+ 0x27, 0x5f, 0x61, 0x0c, 0x38, 0xc7, 0xbd, 0xd8, 0xa4, 0xba, 0x18, 0x6d,
+ 0x57, 0x6d, 0x13, 0xb3, 0x6e, 0xb4, 0x8b, 0x5b, 0x64, 0x04, 0xb6, 0xc2,
+ 0xce, 0x42, 0x9b, 0xec, 0x9a, 0x1e, 0x58, 0x47, 0xbd, 0xb5, 0x7b, 0xda,
+ 0xf8, 0x83, 0xfb, 0xc0, 0x57, 0x69, 0x21, 0x8c, 0x29, 0x5f, 0x84, 0x36,
+ 0xf1, 0x5a, 0x5b, 0xf8, 0xb5, 0xfb, 0xfb, 0xa5, 0x8b, 0xf4, 0xe7, 0xc0,
+ 0x76, 0x78, 0xa3, 0xfd, 0x35, 0xcb, 0xc8, 0x74, 0x88, 0x2b, 0xf5, 0x33,
+ 0xb6, 0x8b, 0x5c, 0xa4, 0x9d, 0xb6, 0x4b, 0xe4, 0xe9, 0x65, 0x59, 0xbc,
+ 0x15, 0x36, 0x93, 0x04, 0x99, 0x01, 0xe9, 0x8c, 0x88, 0x8e, 0xf1, 0xf8,
+ 0x46, 0x36, 0xf7, 0x70, 0x6f, 0x07, 0xf4, 0x6f, 0x6c, 0x15, 0x13, 0x37,
+ 0x0d, 0xed, 0x94, 0x7a, 0xb4, 0x7b, 0x9d, 0xa5, 0x5d, 0xee, 0xb9, 0xee,
+ 0xa6, 0xcc, 0xd5, 0x6b, 0x42, 0x3a, 0xde, 0x55, 0x90, 0x64, 0x48, 0xc7,
+ 0x8b, 0x92, 0x5e, 0x41, 0xc7, 0x8b, 0x32, 0xa4, 0xe9, 0xb8, 0x71, 0x05,
+ 0x1d, 0x77, 0x5a, 0x3a, 0xde, 0x13, 0x33, 0x74, 0xa1, 0xb4, 0x9e, 0x22,
+ 0x9d, 0x1a, 0x3a, 0x76, 0x34, 0x1d, 0x2f, 0xe2, 0x1e, 0xf5, 0xae, 0xb3,
+ 0x75, 0x22, 0xb6, 0x8c, 0xbf, 0xc3, 0x32, 0xca, 0xc5, 0x4f, 0xc6, 0x8c,
+ 0x5e, 0x1a, 0x02, 0x1d, 0x85, 0xe5, 0xfb, 0x6d, 0xfc, 0xa0, 0xb6, 0xcc,
+ 0xc4, 0x47, 0x76, 0x16, 0xc6, 0x62, 0x2b, 0xe9, 0x73, 0x08, 0xf4, 0x19,
+ 0xd6, 0x79, 0x2d, 0xfa, 0x6c, 0xb6, 0xfb, 0x16, 0x71, 0xbd, 0x2f, 0x9f,
+ 0x8e, 0x1b, 0x5a, 0xbd, 0x45, 0xcf, 0x9d, 0xf3, 0x3e, 0xfb, 0x06, 0x68,
+ 0xd5, 0xac, 0xcd, 0xb9, 0xaa, 0xbf, 0xcd, 0x58, 0x54, 0xd2, 0xc4, 0xb0,
+ 0x19, 0x27, 0xbd, 0x98, 0xed, 0x68, 0xe4, 0x53, 0x83, 0x96, 0x4f, 0xad,
+ 0x63, 0xcc, 0x35, 0xa8, 0xca, 0xec, 0x01, 0xe8, 0x0a, 0xda, 0xd8, 0x5a,
+ 0x4e, 0xe3, 0x5d, 0x67, 0x32, 0x53, 0x78, 0x35, 0x88, 0x78, 0x8c, 0x0f,
+ 0x71, 0x5f, 0x40, 0xc6, 0x1c, 0x94, 0x75, 0x95, 0xcd, 0xbc, 0x94, 0xd7,
+ 0x8a, 0xe7, 0x01, 0xe9, 0x2a, 0x2b, 0xf9, 0xe8, 0x74, 0x8b, 0xec, 0x2f,
+ 0x44, 0xe5, 0xe3, 0x68, 0xff, 0xb1, 0x82, 0x0b, 0x7f, 0xfc, 0x4c, 0x8c,
+ 0x76, 0xe1, 0xbe, 0x02, 0xf7, 0x27, 0x59, 0x37, 0xbe, 0x6a, 0x7f, 0x36,
+ 0x22, 0x5d, 0x3d, 0x79, 0x78, 0x2a, 0x12, 0xdd, 0x03, 0x38, 0x9a, 0x86,
+ 0x86, 0xe4, 0x07, 0x03, 0x1b, 0x51, 0xf6, 0xb2, 0x1d, 0x6f, 0xd4, 0x31,
+ 0xf1, 0xde, 0x41, 0x79, 0x77, 0x65, 0x48, 0xae, 0xaf, 0x98, 0x3d, 0xd5,
+ 0xea, 0x9e, 0x69, 0xca, 0x5d, 0x80, 0xfe, 0x49, 0xbb, 0x41, 0x70, 0xce,
+ 0xc3, 0xaa, 0x1f, 0x89, 0x4a, 0xac, 0x27, 0x95, 0x58, 0x10, 0xf3, 0x7c,
+ 0xbe, 0xfc, 0x0f, 0xc1, 0x58, 0x3c, 0x2a, 0x3f, 0xf0, 0x38, 0xc7, 0x41,
+ 0xb9, 0xae, 0x5c, 0x3b, 0x36, 0x97, 0xf3, 0x0f, 0x63, 0xdc, 0xa7, 0xc8,
+ 0x54, 0x16, 0x62, 0x8c, 0xa5, 0xd3, 0xe7, 0xe8, 0x7a, 0x1b, 0xfc, 0x38,
+ 0x48, 0xee, 0xae, 0xb7, 0x81, 0x6e, 0xe2, 0xd0, 0xf9, 0x57, 0x01, 0xc6,
+ 0xab, 0x18, 0xfb, 0x62, 0xcc, 0x8b, 0xcf, 0x5f, 0xc7, 0xb8, 0x6c, 0xfb,
+ 0x1b, 0xd6, 0x5e, 0xe6, 0xfa, 0x1b, 0xde, 0xa9, 0xaf, 0x77, 0x5a, 0xc7,
+ 0x62, 0x43, 0xe2, 0xc4, 0xde, 0x91, 0x90, 0x75, 0x5e, 0xed, 0xf8, 0xdc,
+ 0x27, 0x86, 0xc5, 0x38, 0x20, 0xd1, 0xdd, 0xdb, 0x07, 0x65, 0x04, 0xf3,
+ 0xdb, 0xb9, 0x66, 0x7e, 0xf7, 0x08, 0xe3, 0xab, 0xe7, 0x0b, 0x9c, 0x43,
+ 0x75, 0x5e, 0xea, 0x0b, 0x66, 0x5e, 0xb1, 0x9e, 0xd5, 0xf3, 0xd1, 0xed,
+ 0xd5, 0x09, 0xc0, 0xf2, 0x35, 0x9d, 0x57, 0x10, 0x04, 0x6f, 0xed, 0x39,
+ 0x1f, 0x24, 0x2f, 0x49, 0xf5, 0x2e, 0x54, 0xf7, 0x77, 0xc6, 0x22, 0x43,
+ 0x69, 0xad, 0xcf, 0xf0, 0x9c, 0xcc, 0x96, 0xd3, 0x58, 0x47, 0x89, 0x66,
+ 0xfb, 0xa3, 0x9a, 0x4f, 0xb2, 0x5e, 0xda, 0xee, 0x61, 0x85, 0x3e, 0x54,
+ 0x10, 0x28, 0x6f, 0xb5, 0xdc, 0xa0, 0xbe, 0xc2, 0xdc, 0xe5, 0xdf, 0xda,
+ 0x1c, 0x96, 0x5e, 0xc6, 0xb3, 0xc6, 0xa2, 0x43, 0xb1, 0x64, 0xbe, 0xec,
+ 0xe1, 0x77, 0x0b, 0xee, 0x3b, 0x60, 0xaf, 0xf8, 0xb0, 0x67, 0x24, 0xae,
+ 0x8c, 0x6c, 0x00, 0x2d, 0xf7, 0xe4, 0x94, 0x22, 0x6f, 0xba, 0xc9, 0xc9,
+ 0x72, 0x3c, 0x59, 0x2a, 0x7f, 0x96, 0xed, 0x51, 0xb7, 0x5e, 0x2c, 0xcf,
+ 0xc8, 0x86, 0xa7, 0x2a, 0x1c, 0x83, 0xfe, 0xef, 0x1b, 0x19, 0x23, 0x6a,
+ 0xfb, 0x66, 0x9f, 0x21, 0x5e, 0xa2, 0x74, 0xc9, 0xf1, 0x2f, 0x6d, 0x7d,
+ 0x13, 0xce, 0xef, 0xb3, 0x16, 0xee, 0xd5, 0xe3, 0xbe, 0xa0, 0xed, 0x97,
+ 0xd3, 0x15, 0xda, 0x8c, 0xdc, 0xdf, 0x49, 0x1d, 0x9f, 0x11, 0xc2, 0x11,
+ 0x04, 0xcf, 0xf9, 0x46, 0x77, 0x3f, 0x55, 0xe1, 0x1e, 0x47, 0x10, 0xfc,
+ 0x88, 0x76, 0xf1, 0xde, 0x22, 0xc6, 0x0b, 0x71, 0xb0, 0x35, 0x17, 0x85,
+ 0x5c, 0x9c, 0x1a, 0x20, 0x7e, 0x05, 0x1e, 0x6a, 0x8f, 0x7b, 0xa3, 0xc4,
+ 0x92, 0x9f, 0x2a, 0xb7, 0x24, 0x3f, 0x5d, 0x76, 0x81, 0x67, 0xce, 0x3b,
+ 0x9e, 0x9c, 0xb0, 0x73, 0xce, 0x96, 0x89, 0xdf, 0xd7, 0xda, 0x87, 0x7c,
+ 0x61, 0x85, 0xbf, 0x44, 0x98, 0xaa, 0xb0, 0x10, 0xb6, 0xa4, 0xc5, 0x4d,
+ 0x10, 0xfc, 0xd8, 0x37, 0x6b, 0x3a, 0x55, 0x94, 0x29, 0x8c, 0x9b, 0xdb,
+ 0xac, 0x88, 0x87, 0x58, 0xf2, 0x0e, 0x8c, 0xfd, 0x29, 0x8c, 0xbd, 0xbf,
+ 0xcc, 0xf1, 0x20, 0x2b, 0x30, 0xf7, 0xa9, 0x4a, 0x08, 0x6f, 0xbd, 0xb1,
+ 0xc3, 0x35, 0xef, 0xb5, 0x36, 0x5e, 0xf8, 0xac, 0x11, 0xd9, 0xae, 0xbc,
+ 0x7e, 0xd0, 0xd7, 0xe2, 0xa6, 0xa8, 0xfc, 0x22, 0xe4, 0x6e, 0x20, 0x8f,
+ 0x42, 0x9e, 0x2d, 0x6a, 0xba, 0xc9, 0x5c, 0xce, 0xff, 0x23, 0xf2, 0xeb,
+ 0xeb, 0x18, 0x5f, 0x1e, 0xf6, 0x68, 0xbb, 0x2e, 0x05, 0x8b, 0x1e, 0xe5,
+ 0xf3, 0x06, 0x99, 0x71, 0x73, 0xbd, 0xd0, 0x15, 0x28, 0x6b, 0xa5, 0xbf,
+ 0x9d, 0xcc, 0x44, 0x52, 0xc9, 0x49, 0x61, 0x3e, 0x14, 0x73, 0x15, 0x98,
+ 0x23, 0x44, 0xd9, 0x10, 0x85, 0xcc, 0xe3, 0x1a, 0x9a, 0xf1, 0x26, 0xcb,
+ 0xd5, 0xba, 0x07, 0x84, 0x7b, 0x86, 0xa9, 0xc4, 0x3e, 0x6d, 0x9f, 0x88,
+ 0x8c, 0x17, 0x58, 0x77, 0x3b, 0xac, 0x13, 0xaf, 0xa6, 0xbe, 0xce, 0xe1,
+ 0x02, 0x9f, 0x87, 0x71, 0xac, 0x58, 0x2c, 0x53, 0x90, 0x97, 0x23, 0x03,
+ 0xf2, 0x32, 0xed, 0xce, 0x61, 0xd0, 0xb6, 0xeb, 0xf1, 0xbd, 0x29, 0xcf,
+ 0xf8, 0xb2, 0x94, 0x19, 0xec, 0xa3, 0x9d, 0x9d, 0x53, 0x9a, 0x27, 0x44,
+ 0xa1, 0x6d, 0x2c, 0x5b, 0x96, 0x91, 0x6c, 0xc1, 0xc6, 0x7a, 0x46, 0x39,
+ 0xe7, 0x0d, 0x35, 0x73, 0x6f, 0x95, 0x28, 0x60, 0x1a, 0x89, 0x24, 0x9d,
+ 0x06, 0xef, 0x23, 0x2d, 0x46, 0xe7, 0x43, 0xee, 0xb7, 0xdd, 0xdf, 0xce,
+ 0x3d, 0x53, 0x05, 0x1f, 0x5a, 0xb5, 0xdf, 0x7e, 0x8d, 0x1a, 0xfa, 0xf3,
+ 0x04, 0xf4, 0xa0, 0x95, 0x95, 0xb1, 0x91, 0xae, 0x65, 0xfa, 0xe6, 0xf8,
+ 0xd2, 0x1e, 0xf1, 0x92, 0x23, 0xc3, 0x65, 0x51, 0x91, 0x21, 0x37, 0x36,
+ 0x5c, 0x5e, 0x49, 0xf3, 0x4f, 0x55, 0xfe, 0xbd, 0xb5, 0x05, 0x6b, 0x63,
+ 0xaa, 0xb5, 0xef, 0xc8, 0x77, 0x2b, 0xf6, 0x2b, 0x92, 0x26, 0x07, 0x86,
+ 0xfb, 0xb4, 0x5c, 0x93, 0xf4, 0x5b, 0x1b, 0xa0, 0x7c, 0x66, 0xb4, 0x8f,
+ 0xc6, 0x9c, 0x8b, 0x98, 0xcd, 0x3d, 0x33, 0xb8, 0x4e, 0x97, 0x1d, 0x99,
+ 0x82, 0x7c, 0x38, 0x20, 0x7f, 0x1f, 0xa4, 0xe3, 0xe6, 0xbd, 0x59, 0x5f,
+ 0xd6, 0xe7, 0x5e, 0x44, 0xb3, 0xe4, 0x4f, 0x46, 0x25, 0x77, 0x92, 0x7b,
+ 0x60, 0xcf, 0xed, 0xaf, 0xe6, 0x6d, 0x50, 0x0e, 0x70, 0xbf, 0xd6, 0x91,
+ 0x3c, 0xfc, 0xda, 0x11, 0xee, 0xc3, 0xf7, 0xff, 0x1f, 0xf4, 0xc1, 0x7a,
+ 0x61, 0xdb, 0x16, 0xb4, 0x6d, 0xb4, 0x6d, 0x47, 0xef, 0x78, 0x73, 0x6d,
+ 0x5b, 0xd1, 0x36, 0x16, 0x8e, 0xfb, 0x06, 0xdb, 0x6a, 0x7c, 0x5e, 0x33,
+ 0x5c, 0x28, 0x2e, 0xc1, 0x4f, 0x4e, 0x4c, 0x48, 0xda, 0x19, 0x1f, 0xd0,
+ 0xf3, 0xb9, 0x66, 0xb8, 0x0c, 0x38, 0xe2, 0x41, 0x90, 0xf7, 0x43, 0x3d,
+ 0xcc, 0x7f, 0xc7, 0x44, 0x3c, 0x96, 0x71, 0xdf, 0x92, 0xfe, 0x04, 0xa3,
+ 0xa4, 0x2e, 0xf3, 0xd9, 0x24, 0xcf, 0xfd, 0xc9, 0xf8, 0x46, 0xdc, 0x55,
+ 0x17, 0x71, 0x92, 0xf5, 0x18, 0xef, 0xdd, 0x68, 0xcb, 0x23, 0x2c, 0x4f,
+ 0x45, 0x21, 0x4b, 0x4c, 0x79, 0xc4, 0x96, 0x03, 0x26, 0x3f, 0x9f, 0x04,
+ 0xb7, 0xd9, 0x72, 0x3e, 0x2b, 0x5d, 0x6e, 0x9e, 0x0d, 0x0f, 0x8d, 0x09,
+ 0xe3, 0x3a, 0x99, 0xeb, 0x1a, 0x64, 0x2b, 0xd6, 0x87, 0x3e, 0xa3, 0x23,
+ 0xcd, 0x80, 0xe3, 0x9c, 0xff, 0x76, 0xd8, 0xd6, 0x81, 0xfc, 0xc0, 0x37,
+ 0xf4, 0x3f, 0x2b, 0x3d, 0x69, 0xe5, 0x30, 0x07, 0x20, 0x90, 0x9d, 0xfe,
+ 0xb6, 0xc4, 0x2e, 0xfc, 0x1e, 0xef, 0x4f, 0xca, 0xec, 0x20, 0xe8, 0xb1,
+ 0x9f, 0xbc, 0xb1, 0x15, 0x36, 0x0f, 0x7e, 0xf7, 0xb4, 0xc8, 0x92, 0x9b,
+ 0x73, 0xd7, 0xc1, 0x5f, 0x1b, 0xc1, 0xac, 0xe6, 0x0a, 0x9e, 0x7b, 0x1b,
+ 0x84, 0x5c, 0xda, 0xed, 0xc1, 0xbd, 0x76, 0xbe, 0xdf, 0xc2, 0x7c, 0x7f,
+ 0xad, 0x59, 0x9a, 0x59, 0x5e, 0x5b, 0xb7, 0x51, 0xf6, 0xb8, 0xdb, 0xdd,
+ 0xd8, 0x8a, 0xba, 0xe7, 0x51, 0x97, 0x65, 0x9e, 0xcb, 0x1c, 0x9d, 0xd9,
+ 0x32, 0xe9, 0xcc, 0xc0, 0xda, 0xd5, 0x13, 0x04, 0xd7, 0xf9, 0x1c, 0x37,
+ 0x08, 0xae, 0xf7, 0xfb, 0xdc, 0x67, 0xe5, 0xf9, 0xc0, 0xd8, 0x54, 0x21,
+ 0xed, 0x3c, 0x67, 0xe5, 0x75, 0x10, 0xbc, 0xec, 0xf7, 0xca, 0xef, 0x54,
+ 0x52, 0x8f, 0xd3, 0xe7, 0x3e, 0x83, 0xe7, 0x33, 0xbe, 0xc9, 0x2b, 0xfa,
+ 0x13, 0xb4, 0x8b, 0xab, 0x7e, 0xd0, 0xb0, 0x27, 0x5f, 0xd4, 0x3e, 0x3a,
+ 0xf1, 0x67, 0x62, 0xfc, 0x55, 0x18, 0x30, 0x61, 0x2f, 0xb3, 0xc9, 0x65,
+ 0x7e, 0xa0, 0xa6, 0xdf, 0xda, 0x77, 0x0a, 0xef, 0x58, 0x16, 0x04, 0x97,
+ 0x0c, 0xfc, 0x31, 0xe6, 0x94, 0x2a, 0x71, 0xef, 0xee, 0x03, 0x9a, 0xff,
+ 0x04, 0x7e, 0x3d, 0xe9, 0x24, 0xea, 0x2a, 0xe5, 0x1d, 0xee, 0x52, 0xa9,
+ 0x9c, 0xc8, 0x5b, 0xb0, 0xfe, 0x5c, 0x63, 0x30, 0x48, 0x1b, 0x60, 0xdf,
+ 0xb6, 0xbd, 0xd9, 0xc4, 0x92, 0xe8, 0x4b, 0xa7, 0x37, 0xc1, 0xd7, 0xd5,
+ 0xf6, 0x4c, 0x14, 0x7c, 0x3d, 0xd1, 0x16, 0x04, 0xef, 0xf7, 0xc3, 0x35,
+ 0xb3, 0xb1, 0x6a, 0xe8, 0xf8, 0x6c, 0xff, 0xb9, 0x66, 0x63, 0xc7, 0x31,
+ 0x4f, 0x30, 0xa9, 0xe3, 0xfa, 0xaa, 0x1d, 0x3a, 0x64, 0xdb, 0x57, 0x39,
+ 0x7e, 0x8e, 0xe5, 0xef, 0xf3, 0x43, 0x98, 0xaa, 0xed, 0xb3, 0xfd, 0xeb,
+ 0xac, 0xcd, 0x19, 0x05, 0x2e, 0x3d, 0xb7, 0x4b, 0xfd, 0x4d, 0x60, 0x74,
+ 0x6b, 0x48, 0xc3, 0x7f, 0x17, 0x3c, 0x18, 0x37, 0xcf, 0x99, 0x6d, 0xec,
+ 0x63, 0xab, 0x4c, 0x6e, 0xc3, 0x73, 0xf4, 0x5a, 0xdc, 0x87, 0x2f, 0x8b,
+ 0xc8, 0x15, 0x89, 0x61, 0xb5, 0xcd, 0x7d, 0x50, 0xfa, 0xac, 0x8c, 0xfb,
+ 0x1a, 0xf4, 0x7d, 0x0e, 0xfe, 0x78, 0x93, 0x3c, 0x08, 0x9a, 0x56, 0x03,
+ 0xa9, 0xe4, 0x82, 0x4a, 0xf5, 0xce, 0xa8, 0x94, 0x3f, 0xa6, 0xae, 0xe7,
+ 0xbc, 0x06, 0x89, 0x8b, 0x19, 0xe2, 0xb7, 0x08, 0xfc, 0x17, 0x81, 0xe3,
+ 0x8b, 0xee, 0xf1, 0xfa, 0x56, 0xb7, 0x18, 0xfd, 0x96, 0xd3, 0xb4, 0x69,
+ 0xec, 0xf2, 0x3f, 0xf6, 0xc3, 0x35, 0x84, 0x6d, 0xc8, 0x1c, 0x99, 0xba,
+ 0x6b, 0x94, 0xe5, 0x1a, 0x41, 0x31, 0xe4, 0x40, 0xf7, 0xa9, 0xe4, 0x84,
+ 0x5a, 0x0a, 0x36, 0xed, 0xe8, 0xee, 0x7d, 0x42, 0xf7, 0x93, 0xf2, 0xd3,
+ 0x2a, 0x0f, 0x78, 0xb6, 0x4a, 0xd3, 0x0e, 0xe2, 0x99, 0xb0, 0xc6, 0x18,
+ 0x4f, 0x72, 0xef, 0x40, 0xdd, 0x31, 0xa5, 0xf7, 0xa0, 0x6d, 0x1d, 0xc2,
+ 0x1c, 0x5f, 0x2f, 0xcd, 0xd4, 0x43, 0x8c, 0x93, 0xbd, 0x96, 0x2e, 0x84,
+ 0x4c, 0x3a, 0x46, 0x19, 0x18, 0x31, 0xb1, 0xdf, 0xca, 0xcf, 0xa1, 0x9d,
+ 0xce, 0x67, 0x89, 0x45, 0x21, 0xa3, 0xa6, 0xc0, 0xc5, 0x87, 0x8e, 0x49,
+ 0xb4, 0xc1, 0xfb, 0x5f, 0xcd, 0xc6, 0x6f, 0xa2, 0x0f, 0xc5, 0xb1, 0x1b,
+ 0x24, 0xbf, 0x26, 0xde, 0x52, 0x02, 0xfc, 0xcd, 0x32, 0x79, 0x8c, 0x6b,
+ 0x11, 0x85, 0xcc, 0xe1, 0xd8, 0x12, 0xcd, 0xf4, 0x07, 0xc1, 0x38, 0xcb,
+ 0x4f, 0x92, 0x7f, 0x25, 0xc5, 0x77, 0xb9, 0x93, 0x0b, 0x9b, 0xd4, 0x0a,
+ 0x59, 0xdb, 0x62, 0xe1, 0xd0, 0x78, 0x92, 0x92, 0x96, 0x23, 0xd4, 0x37,
+ 0xb7, 0xd5, 0xc0, 0x33, 0x7a, 0xc7, 0x94, 0xd7, 0xf8, 0x26, 0xe0, 0xf9,
+ 0x3d, 0xc0, 0xd3, 0x62, 0xe1, 0x69, 0x5c, 0x05, 0x4f, 0x4b, 0x08, 0x0f,
+ 0xe4, 0x1c, 0xe5, 0x6a, 0xec, 0x9a, 0x74, 0x59, 0x9c, 0xbc, 0x27, 0x9d,
+ 0x4a, 0xfb, 0x2f, 0xd4, 0x37, 0x8d, 0xee, 0xf8, 0x80, 0x2b, 0xe3, 0x5a,
+ 0xd7, 0x44, 0xaf, 0xe9, 0x2e, 0x2f, 0xc0, 0x7a, 0x15, 0x27, 0xe3, 0x11,
+ 0xf6, 0x7a, 0x76, 0xd5, 0x3d, 0x90, 0xff, 0x8b, 0xa9, 0xa8, 0xb5, 0x25,
+ 0x4a, 0x3e, 0xfd, 0x96, 0xb8, 0xde, 0xdb, 0xaf, 0xc2, 0xf4, 0x12, 0x60,
+ 0x82, 0x3c, 0x3e, 0xd6, 0xe7, 0x8e, 0xca, 0xa5, 0xda, 0x37, 0xb3, 0xb8,
+ 0xc6, 0xdc, 0x62, 0x35, 0x73, 0x83, 0xfe, 0x53, 0xe1, 0xdc, 0x20, 0x13,
+ 0x51, 0xaf, 0x24, 0xf7, 0x5b, 0x5c, 0xb4, 0x62, 0x4e, 0xb1, 0x9a, 0xf9,
+ 0x74, 0x27, 0xf6, 0xb3, 0xcc, 0xcc, 0xa7, 0x27, 0xef, 0xc5, 0x2c, 0x7e,
+ 0x57, 0xc3, 0x58, 0xf5, 0x17, 0x67, 0x24, 0x90, 0x29, 0x1f, 0x6b, 0xd4,
+ 0x4b, 0xff, 0x24, 0x66, 0xf3, 0x98, 0x15, 0x9e, 0x37, 0x58, 0xfe, 0x72,
+ 0x25, 0xaf, 0xfd, 0xb7, 0x2f, 0xad, 0x37, 0x7c, 0x1a, 0xb5, 0xf9, 0x6b,
+ 0xfc, 0xdd, 0xb1, 0xde, 0xee, 0xef, 0xe7, 0xd2, 0xf2, 0xfb, 0xeb, 0x69,
+ 0x97, 0x34, 0x78, 0x43, 0xab, 0xca, 0x62, 0x28, 0xbb, 0x7d, 0xbd, 0x95,
+ 0x0b, 0x28, 0xbb, 0x07, 0x7e, 0x1a, 0xf3, 0x34, 0xf8, 0x8e, 0x32, 0xb8,
+ 0x16, 0x27, 0x7d, 0x60, 0x45, 0xf2, 0x3c, 0xe5, 0x22, 0x6d, 0x4a, 0xcc,
+ 0x51, 0x7d, 0x27, 0x8c, 0xa3, 0xe3, 0x77, 0x3d, 0xdb, 0x9f, 0xf8, 0x26,
+ 0xae, 0xe5, 0xdb, 0x53, 0xe0, 0xfb, 0x03, 0xbe, 0x13, 0x9d, 0x65, 0x1e,
+ 0x80, 0xa6, 0xe1, 0xda, 0xbe, 0xaf, 0x47, 0xdf, 0x21, 0x2d, 0x93, 0x5e,
+ 0xae, 0xd7, 0x74, 0xd3, 0x44, 0x5d, 0x7c, 0x8c, 0xf4, 0xc7, 0x58, 0x72,
+ 0xb3, 0xd6, 0x8f, 0xd5, 0x75, 0x6c, 0x82, 0xae, 0x89, 0x1b, 0x1e, 0x75,
+ 0xcd, 0x7e, 0x77, 0xb5, 0xbf, 0x31, 0xf4, 0x47, 0x3b, 0x0d, 0x7e, 0xba,
+ 0xc7, 0x68, 0x0e, 0xe5, 0x97, 0x13, 0x55, 0x57, 0x6a, 0x3f, 0x33, 0xa6,
+ 0xf3, 0x8e, 0x96, 0xeb, 0x4e, 0xd8, 0xb1, 0x49, 0xb7, 0x26, 0xfe, 0x5f,
+ 0x1d, 0x5f, 0x1c, 0xb5, 0x4d, 0x40, 0x65, 0x8d, 0x32, 0x35, 0x40, 0x1a,
+ 0xe5, 0xdc, 0xb5, 0x0d, 0x75, 0x0d, 0xed, 0x08, 0x43, 0x9f, 0xb4, 0x9d,
+ 0xa2, 0xd7, 0x64, 0x0b, 0x8d, 0xc6, 0x67, 0x89, 0xcb, 0xe6, 0x06, 0x9d,
+ 0x47, 0x80, 0xb2, 0x72, 0xa8, 0xcb, 0xa2, 0x32, 0xdb, 0xff, 0xbf, 0x83,
+ 0xf4, 0x5e, 0xd6, 0xad, 0xbb, 0x6f, 0x9f, 0x98, 0x11, 0x8d, 0xa7, 0xbf,
+ 0xa8, 0xe2, 0xc9, 0xce, 0x2d, 0xbe, 0x7a, 0x6e, 0x05, 0xc0, 0x7b, 0x0f,
+ 0x64, 0x27, 0xd7, 0xc9, 0xe4, 0x6f, 0x3f, 0x2e, 0x4e, 0x34, 0xd3, 0x5b,
+ 0x6f, 0x6e, 0xa5, 0x10, 0xaf, 0x9c, 0x1b, 0x68, 0x35, 0x9c, 0x17, 0x69,
+ 0x3b, 0xae, 0xf7, 0x89, 0x94, 0x22, 0x2c, 0xad, 0xab, 0x70, 0x1b, 0xd2,
+ 0x9d, 0xa1, 0xb9, 0xa7, 0x34, 0xcd, 0xb5, 0x58, 0x9a, 0x43, 0x5d, 0x97,
+ 0xfb, 0xde, 0xa3, 0x2d, 0x55, 0x9a, 0xdb, 0x60, 0x69, 0xee, 0x99, 0xf5,
+ 0x66, 0x4f, 0xfc, 0xfd, 0x2d, 0x66, 0x4f, 0xea, 0x2f, 0x57, 0x3d, 0x6f,
+ 0xa2, 0xcd, 0x08, 0x5f, 0x2c, 0x7c, 0xae, 0x85, 0xf5, 0x0c, 0x60, 0xad,
+ 0x95, 0x35, 0x4d, 0x36, 0xee, 0xc6, 0xfd, 0x73, 0xfa, 0x7d, 0x51, 0x79,
+ 0x14, 0x76, 0x50, 0xbe, 0xfc, 0x8f, 0xc1, 0x02, 0x7c, 0xbf, 0xa9, 0x65,
+ 0xdd, 0x7b, 0x5b, 0x0b, 0xf9, 0x6d, 0x06, 0xbf, 0x0e, 0xd6, 0xf8, 0x3c,
+ 0x98, 0x2f, 0xca, 0xfe, 0x01, 0xeb, 0x01, 0xb9, 0xbc, 0x5c, 0x97, 0x31,
+ 0x0b, 0xe3, 0xe3, 0x30, 0x66, 0x68, 0xf6, 0x13, 0x29, 0xe7, 0xef, 0x84,
+ 0x4f, 0x74, 0x0f, 0xf4, 0x24, 0xe9, 0xfb, 0xa5, 0x16, 0x93, 0xe7, 0x1b,
+ 0x87, 0x1e, 0xfb, 0x65, 0x9b, 0x0b, 0x75, 0xf8, 0x57, 0xeb, 0xe7, 0xf8,
+ 0x82, 0xf6, 0x1d, 0xd2, 0xcc, 0xdf, 0xb7, 0x98, 0x98, 0xf1, 0xb7, 0x5a,
+ 0xc8, 0x67, 0x6a, 0xdb, 0x0f, 0x37, 0x68, 0xbe, 0x70, 0xc2, 0xe7, 0xcf,
+ 0xb4, 0xae, 0x7c, 0x0e, 0xdb, 0x3d, 0xd9, 0xba, 0xb2, 0x5d, 0x58, 0xfe,
+ 0x73, 0x1b, 0x57, 0x96, 0x5f, 0xe3, 0xae, 0x6c, 0xff, 0xf5, 0x55, 0xcf,
+ 0x2d, 0x9b, 0x56, 0x3e, 0x5f, 0xbd, 0xea, 0x79, 0x6a, 0xd5, 0xf3, 0x85,
+ 0x55, 0xcf, 0x57, 0xb5, 0xad, 0x7c, 0xbe, 0xbd, 0xad, 0x3e, 0xbc, 0x87,
+ 0xdb, 0x56, 0xc2, 0x75, 0xa7, 0x8e, 0xf7, 0xcf, 0x54, 0xa2, 0xb2, 0xab,
+ 0x80, 0xf7, 0x4e, 0xe7, 0x66, 0xa3, 0xd7, 0x6a, 0xdf, 0x33, 0xbe, 0xf6,
+ 0xd7, 0xab, 0xfa, 0xab, 0xb6, 0xdb, 0x5d, 0x6d, 0xe7, 0x57, 0xdb, 0x19,
+ 0xd9, 0x36, 0x5b, 0xe1, 0x3b, 0x96, 0x87, 0xfd, 0x9a, 0xb6, 0x53, 0xc5,
+ 0x4e, 0x9d, 0x0b, 0x3b, 0xaa, 0x73, 0x61, 0x93, 0xe0, 0xc3, 0x3b, 0x75,
+ 0x4c, 0x69, 0x93, 0x42, 0x79, 0xa5, 0x55, 0xc7, 0x95, 0x74, 0x2c, 0xb5,
+ 0x30, 0x0a, 0xdb, 0x96, 0x39, 0xb0, 0x81, 0xec, 0xf1, 0xcd, 0xdd, 0xe4,
+ 0xc4, 0x1e, 0x0e, 0x86, 0xdd, 0x20, 0x98, 0xf4, 0x6e, 0xb3, 0xf9, 0x62,
+ 0xb8, 0x57, 0x4c, 0x1b, 0xea, 0xe0, 0x27, 0xa0, 0x83, 0xab, 0xba, 0xf7,
+ 0x4e, 0x8c, 0xb5, 0x00, 0x9a, 0x19, 0x90, 0xdf, 0xad, 0xa4, 0xbe, 0x24,
+ 0xfa, 0xcc, 0x4d, 0x3f, 0x6c, 0xb8, 0xa5, 0x4f, 0xbd, 0xdf, 0xf3, 0x61,
+ 0xeb, 0x05, 0xf2, 0xb0, 0x3f, 0x08, 0x1a, 0xea, 0x85, 0xbd, 0xe7, 0x69,
+ 0xbf, 0xf4, 0xb4, 0xa6, 0x2d, 0xd2, 0x58, 0x8b, 0xce, 0xd7, 0x7f, 0xd4,
+ 0x77, 0x62, 0x99, 0xfe, 0x3f, 0x32, 0x71, 0x1a, 0xbf, 0xdb, 0xfd, 0x1a,
+ 0xf8, 0x76, 0xa7, 0xb7, 0x05, 0x3e, 0x0a, 0x69, 0x88, 0xf1, 0xaf, 0xcb,
+ 0x75, 0x1e, 0x21, 0x03, 0x68, 0x33, 0x51, 0xc6, 0x09, 0x53, 0x83, 0x63,
+ 0xc2, 0x79, 0xa7, 0x12, 0x49, 0xa5, 0xed, 0xaa, 0xe0, 0x46, 0x9f, 0x39,
+ 0xb6, 0xdc, 0x63, 0x21, 0x3f, 0xef, 0xff, 0xf4, 0x94, 0x97, 0x73, 0x23,
+ 0x36, 0x2f, 0x37, 0x53, 0x30, 0xb4, 0x39, 0x41, 0xda, 0x84, 0x3f, 0xb5,
+ 0xd8, 0xff, 0xb7, 0x01, 0xed, 0xfb, 0xa4, 0x22, 0xed, 0xff, 0x4d, 0x30,
+ 0x17, 0x65, 0x5f, 0x84, 0x7b, 0xff, 0xa7, 0x33, 0x1a, 0x57, 0x77, 0xca,
+ 0x81, 0x22, 0x6d, 0xe1, 0x98, 0xce, 0xe7, 0x18, 0xf7, 0x69, 0xa7, 0xc5,
+ 0x80, 0xc7, 0x0f, 0x01, 0x7f, 0x2d, 0xb0, 0xb9, 0x47, 0x50, 0x27, 0x22,
+ 0x63, 0x60, 0xf1, 0xd9, 0x02, 0xf9, 0x93, 0xf7, 0x28, 0xea, 0xbb, 0x32,
+ 0x5f, 0xb8, 0x59, 0xe7, 0xdb, 0x9d, 0x46, 0xdb, 0x27, 0x71, 0xcd, 0x16,
+ 0x26, 0xd0, 0x66, 0xaf, 0xae, 0x3f, 0x5b, 0x62, 0x8e, 0xb2, 0x40, 0x2e,
+ 0xed, 0x97, 0xfc, 0x5c, 0x97, 0x8c, 0xc5, 0x17, 0x66, 0xa2, 0xcb, 0x71,
+ 0x99, 0x8f, 0x6f, 0xe0, 0x1e, 0x47, 0xfe, 0x4a, 0xee, 0x07, 0x4b, 0x74,
+ 0x74, 0xbb, 0xea, 0x6d, 0xd3, 0x3e, 0xd7, 0xa0, 0xec, 0xac, 0x0c, 0xc9,
+ 0x4d, 0x95, 0xcf, 0x6e, 0x36, 0xb1, 0xa8, 0x15, 0xf1, 0xad, 0xc3, 0xc4,
+ 0x8a, 0x3a, 0x1a, 0xe5, 0xb9, 0x25, 0x99, 0x3d, 0x25, 0x12, 0x39, 0x1a,
+ 0xc6, 0x12, 0x59, 0xe6, 0x4a, 0xd7, 0x95, 0x80, 0xeb, 0x14, 0x64, 0x6b,
+ 0x3c, 0x26, 0x5f, 0xdc, 0x16, 0x8e, 0x95, 0x0b, 0xa6, 0xb7, 0xe5, 0xe4,
+ 0xd3, 0xb8, 0xb2, 0x57, 0xa6, 0x4a, 0x19, 0xc5, 0x71, 0xbf, 0x13, 0x50,
+ 0x96, 0xa9, 0x21, 0x4f, 0x72, 0x6d, 0xe1, 0xd8, 0xf0, 0x6f, 0x76, 0x84,
+ 0xe3, 0xd3, 0xe6, 0x36, 0x67, 0x1e, 0xf2, 0xdc, 0x77, 0x01, 0xfd, 0x45,
+ 0x86, 0xee, 0xde, 0x40, 0xdf, 0x61, 0x58, 0xd8, 0x0e, 0x32, 0x5d, 0xb1,
+ 0x6f, 0xc2, 0x49, 0xf8, 0x6b, 0xe1, 0x5c, 0x4c, 0xc6, 0x81, 0xa3, 0xdc,
+ 0xeb, 0xc2, 0xdb, 0xe7, 0x7a, 0xaa, 0x1e, 0xbc, 0xa3, 0x36, 0x96, 0xc8,
+ 0xf8, 0xe0, 0x3a, 0xe0, 0xad, 0x05, 0xe5, 0x1f, 0x94, 0xa9, 0x63, 0x6f,
+ 0xdb, 0xcc, 0xbd, 0xec, 0x06, 0xcf, 0xb1, 0x39, 0xa7, 0x3c, 0xbf, 0x73,
+ 0x37, 0xea, 0xf0, 0xfd, 0xcd, 0x68, 0x93, 0xca, 0x65, 0x22, 0x9b, 0xe1,
+ 0x13, 0x71, 0xdc, 0x20, 0xd2, 0xb5, 0xa3, 0x59, 0xe7, 0x90, 0xca, 0x29,
+ 0xea, 0xf3, 0xb0, 0xed, 0xdd, 0x3a, 0x47, 0x03, 0x7e, 0x7b, 0x6e, 0x24,
+ 0x42, 0xf9, 0xd5, 0x2b, 0xc3, 0xd4, 0x27, 0xa7, 0x6e, 0xd6, 0xb4, 0xdf,
+ 0xbd, 0x8d, 0x67, 0x99, 0xfa, 0x8c, 0x8d, 0x1e, 0x27, 0x8c, 0xa3, 0x28,
+ 0x87, 0xfd, 0xfe, 0x9a, 0x30, 0xdc, 0xf5, 0x26, 0x61, 0xb8, 0xeb, 0x4d,
+ 0xc2, 0x40, 0x5c, 0x00, 0x8e, 0xca, 0x5f, 0x6c, 0x08, 0x63, 0xd5, 0x97,
+ 0x62, 0x1e, 0x07, 0x8b, 0x77, 0xc9, 0xa1, 0xa2, 0xa3, 0xe3, 0x8e, 0x0b,
+ 0x8a, 0x32, 0xc1, 0x05, 0x4f, 0x82, 0xf7, 0x8a, 0xe0, 0xcd, 0x22, 0x78,
+ 0xb1, 0x08, 0xbe, 0x84, 0xfd, 0x7f, 0x06, 0xf6, 0xff, 0x93, 0x58, 0x9b,
+ 0xd3, 0x2b, 0x78, 0x39, 0xad, 0x79, 0x39, 0x5f, 0xa4, 0xaf, 0xd6, 0x7f,
+ 0x11, 0x7e, 0x8d, 0xca, 0x70, 0x21, 0x05, 0x55, 0xe2, 0x44, 0xb3, 0xfd,
+ 0x9f, 0x24, 0xbf, 0xca, 0x83, 0xfe, 0x0d, 0x68, 0x73, 0x18, 0x34, 0x9e,
+ 0xa2, 0x1d, 0x48, 0xfb, 0x27, 0x07, 0xde, 0x3c, 0x4c, 0x5f, 0x4d, 0x5d,
+ 0xb9, 0x49, 0xa8, 0x5f, 0xa2, 0x3b, 0x98, 0x7b, 0xc8, 0xb9, 0x26, 0x57,
+ 0xe1, 0xc9, 0xf0, 0xef, 0x84, 0x47, 0x3d, 0x43, 0xbe, 0x7d, 0x99, 0x7c,
+ 0x5b, 0xc3, 0xab, 0x01, 0xe7, 0x17, 0xb8, 0xdb, 0xea, 0xb5, 0xad, 0xd6,
+ 0xdf, 0xb4, 0x5c, 0x5f, 0x8f, 0x5f, 0x22, 0x3f, 0x42, 0x27, 0x11, 0xf7,
+ 0xc9, 0x4c, 0x64, 0x8b, 0xc5, 0x3d, 0x6c, 0xb7, 0x1d, 0x97, 0x00, 0xf7,
+ 0x9d, 0x92, 0x9b, 0x0f, 0xc4, 0xdb, 0x11, 0xf6, 0x59, 0xed, 0xc7, 0xb5,
+ 0xfd, 0x8c, 0x17, 0x1c, 0x19, 0xd9, 0xc6, 0x7d, 0x08, 0x07, 0x7a, 0x3e,
+ 0x5c, 0x0f, 0xd8, 0xfb, 0x7a, 0xcd, 0x29, 0x63, 0x29, 0x5b, 0x5b, 0x6c,
+ 0xfc, 0x89, 0xfd, 0x1d, 0x5e, 0xb5, 0x4e, 0x17, 0x02, 0x9e, 0x11, 0x9b,
+ 0xf2, 0x6e, 0xa8, 0xa1, 0x95, 0xfb, 0x2c, 0xad, 0xa8, 0x55, 0xf3, 0xb8,
+ 0xdd, 0xd2, 0x4a, 0x08, 0x6f, 0x3c, 0xa4, 0x95, 0xa6, 0x90, 0x56, 0x72,
+ 0x33, 0x21, 0xad, 0xb0, 0xed, 0xed, 0x21, 0xad, 0x24, 0x6b, 0x69, 0x25,
+ 0x37, 0xe3, 0xe0, 0x5a, 0x0d, 0x07, 0xe9, 0x85, 0xfd, 0x90, 0x5e, 0x00,
+ 0x4b, 0xe5, 0xd6, 0xd6, 0x90, 0x5e, 0xe2, 0xe8, 0xe7, 0x50, 0xd1, 0xe4,
+ 0x74, 0xc0, 0xef, 0xb2, 0x3a, 0xc4, 0xc5, 0x9a, 0x1b, 0x1f, 0xb1, 0x3e,
+ 0x8d, 0xf8, 0x96, 0x46, 0xaa, 0x79, 0xee, 0xab, 0x68, 0x03, 0xb8, 0x67,
+ 0x2e, 0xeb, 0x76, 0x4d, 0x1b, 0xf7, 0xfb, 0x53, 0xa8, 0xbb, 0x07, 0xb4,
+ 0x11, 0xe2, 0xe0, 0x7a, 0x8b, 0x83, 0xd5, 0x6b, 0x39, 0x66, 0x71, 0xb0,
+ 0xc7, 0xe2, 0x40, 0xf3, 0x4b, 0x8e, 0x6b, 0xa6, 0x34, 0x0e, 0x9a, 0x34,
+ 0x0e, 0x44, 0x85, 0x6d, 0xc7, 0xea, 0xe0, 0x80, 0x75, 0xf6, 0xe8, 0xf9,
+ 0x47, 0x30, 0xff, 0xfd, 0x98, 0xbf, 0xd2, 0xf3, 0xe7, 0x3a, 0x70, 0xfe,
+ 0x80, 0xa5, 0x72, 0x72, 0x79, 0xfe, 0x6d, 0xe8, 0xe3, 0x60, 0x31, 0xa2,
+ 0xe7, 0x0f, 0xdb, 0x7e, 0x30, 0x9c, 0xff, 0xe9, 0x8a, 0xc9, 0x7f, 0x3e,
+ 0xbd, 0x46, 0xcf, 0x4d, 0x59, 0xde, 0xf0, 0xb4, 0x5f, 0xcc, 0x98, 0xf6,
+ 0x19, 0xe8, 0xb6, 0x69, 0x3f, 0x69, 0xcf, 0x43, 0x19, 0x7b, 0xe9, 0x1b,
+ 0x3e, 0x79, 0xe7, 0xe3, 0x3a, 0x0f, 0xe5, 0x71, 0xda, 0x4d, 0xc5, 0x36,
+ 0x19, 0x99, 0xae, 0x85, 0x9b, 0xf0, 0xe6, 0xb4, 0x1c, 0xcd, 0x62, 0x7e,
+ 0xe3, 0x7e, 0x2f, 0xe4, 0x9b, 0xa6, 0x25, 0x94, 0xa7, 0x72, 0xc3, 0x91,
+ 0x26, 0x51, 0x0f, 0x7c, 0x08, 0x73, 0x8e, 0xca, 0x66, 0xaf, 0xdb, 0xdd,
+ 0xa1, 0xa8, 0x0b, 0x2f, 0xab, 0xd1, 0x85, 0xed, 0x56, 0x17, 0x6e, 0xa2,
+ 0x2e, 0x04, 0xdc, 0x77, 0xca, 0xe1, 0x22, 0xd7, 0x2f, 0x97, 0x6c, 0x82,
+ 0xfe, 0xff, 0x81, 0xc7, 0xb3, 0x27, 0x3a, 0x6e, 0x96, 0x38, 0xac, 0x69,
+ 0x99, 0x3a, 0x2d, 0xa5, 0xcf, 0x6a, 0x2c, 0xd2, 0xc6, 0x8e, 0x33, 0x16,
+ 0x4a, 0xbd, 0xf7, 0xe3, 0xe0, 0x73, 0x75, 0xf4, 0xde, 0x64, 0xd1, 0xd8,
+ 0x6f, 0x0d, 0xb0, 0x09, 0xe5, 0x44, 0x3b, 0xae, 0x8d, 0x3c, 0xab, 0xd0,
+ 0xdb, 0xa3, 0x9a, 0xa5, 0xe1, 0x44, 0xab, 0x4c, 0x4c, 0x1b, 0x1b, 0x57,
+ 0x9d, 0x00, 0xfe, 0x4f, 0x30, 0xdf, 0x55, 0x74, 0x7e, 0x7e, 0xb6, 0x04,
+ 0x3b, 0x77, 0xf6, 0x4e, 0x93, 0xb7, 0x32, 0xdd, 0xa0, 0x7f, 0xd3, 0x06,
+ 0xc9, 0xfb, 0x69, 0xe8, 0xbb, 0x98, 0x4c, 0xa0, 0xcf, 0xee, 0x6d, 0x8d,
+ 0x98, 0x73, 0x1c, 0x6d, 0xe9, 0xf3, 0x31, 0x8e, 0xd6, 0x28, 0xd1, 0xd9,
+ 0xb8, 0xce, 0xad, 0xe7, 0xd9, 0xd1, 0xcc, 0x60, 0x1b, 0xde, 0x31, 0x9f,
+ 0xc1, 0xc5, 0x58, 0xa1, 0xec, 0x47, 0xbf, 0x47, 0xc5, 0xee, 0xf7, 0x0c,
+ 0x69, 0xfd, 0x17, 0x39, 0xea, 0xda, 0x33, 0x74, 0x83, 0x58, 0xf7, 0x7a,
+ 0x7a, 0xd1, 0x18, 0xb9, 0x19, 0xac, 0x9f, 0x3a, 0x15, 0xc5, 0xbd, 0x13,
+ 0xf7, 0xb0, 0xbf, 0x50, 0x8f, 0x40, 0x37, 0xbe, 0xb3, 0x6f, 0xa3, 0x34,
+ 0x03, 0xdf, 0xb3, 0x0a, 0xb8, 0x36, 0x39, 0x59, 0x39, 0xcd, 0x0b, 0x55,
+ 0x7a, 0x78, 0xf2, 0x75, 0xf9, 0x81, 0x34, 0x41, 0x5a, 0xa0, 0x5c, 0x24,
+ 0x6d, 0x50, 0x26, 0x3a, 0xfa, 0x6c, 0x03, 0xe9, 0xe1, 0x09, 0xdf, 0x8b,
+ 0x70, 0xdf, 0xde, 0xc4, 0xe5, 0x49, 0x1b, 0xa4, 0xf9, 0xa4, 0x8e, 0xd7,
+ 0xa7, 0xe5, 0x7b, 0x92, 0x6e, 0xeb, 0x86, 0x5d, 0xf6, 0x2f, 0xbb, 0xc6,
+ 0xe6, 0xdc, 0xad, 0xa6, 0x39, 0xe8, 0x26, 0xe6, 0xd0, 0xf5, 0xca, 0xfb,
+ 0x2a, 0x39, 0xe0, 0xe1, 0x5e, 0x28, 0xe5, 0x3b, 0x75, 0x5e, 0xe2, 0xee,
+ 0xc2, 0x46, 0xb9, 0xc5, 0x8f, 0xd9, 0xb8, 0xfb, 0x41, 0xd0, 0xc1, 0xa2,
+ 0x23, 0x27, 0xce, 0xe2, 0x3a, 0xe7, 0x70, 0xfd, 0xce, 0xfb, 0xe9, 0x94,
+ 0x22, 0xb3, 0x7b, 0xd1, 0xc4, 0xa2, 0xf4, 0xb9, 0x13, 0xfa, 0x0c, 0xc8,
+ 0x82, 0xd3, 0x74, 0xe2, 0xd0, 0x46, 0xe3, 0x4b, 0x03, 0x16, 0xaf, 0xd1,
+ 0x1d, 0xa1, 0x2d, 0xe7, 0x07, 0x41, 0x96, 0x76, 0x83, 0x28, 0xed, 0x23,
+ 0xc1, 0xe7, 0x43, 0x19, 0xe3, 0x13, 0x5b, 0x9d, 0xc6, 0x53, 0x2f, 0x5a,
+ 0x5a, 0x91, 0x88, 0x1a, 0x7a, 0xc6, 0x69, 0x38, 0x71, 0x9c, 0x6b, 0xa6,
+ 0xf3, 0xa4, 0x0d, 0x5d, 0x3d, 0xe7, 0x54, 0xe9, 0xea, 0x1b, 0xf6, 0xb7,
+ 0x1a, 0x6a, 0x92, 0x74, 0xaa, 0x09, 0xf3, 0x1d, 0x2e, 0x84, 0x30, 0x7e,
+ 0x1f, 0x70, 0x11, 0x1e, 0xd0, 0xed, 0xec, 0x9f, 0xe1, 0x5a, 0x02, 0x2c,
+ 0xf7, 0x01, 0xee, 0xf3, 0x80, 0xf9, 0x02, 0x2e, 0xd5, 0x11, 0x91, 0x3f,
+ 0x76, 0x22, 0xb3, 0xb5, 0xf0, 0x12, 0xc6, 0xd3, 0x16, 0xde, 0xd7, 0x82,
+ 0xd5, 0x95, 0xc5, 0x81, 0x2e, 0xc0, 0x43, 0x38, 0x5f, 0x02, 0x8c, 0xb4,
+ 0x5b, 0x9f, 0xc7, 0xb3, 0x0b, 0xf8, 0x5e, 0xb0, 0x30, 0x81, 0x1e, 0xa7,
+ 0xff, 0x47, 0xf5, 0x77, 0x81, 0x76, 0xf4, 0x9f, 0xdb, 0xe7, 0xce, 0x55,
+ 0x32, 0xa0, 0xc7, 0x21, 0x9e, 0xa7, 0x8a, 0x4b, 0xb4, 0x03, 0xc0, 0xf7,
+ 0x3f, 0x94, 0xc8, 0xa9, 0x84, 0x1c, 0x2a, 0x70, 0x0f, 0xe8, 0x24, 0xf0,
+ 0xa1, 0xcf, 0xa4, 0xa0, 0xce, 0x15, 0xb8, 0xa0, 0xec, 0x67, 0xb7, 0xe3,
+ 0xea, 0xc5, 0xf5, 0x56, 0x5c, 0x20, 0x87, 0xd9, 0x13, 0xb8, 0xfa, 0xd0,
+ 0xb7, 0x8a, 0x37, 0x09, 0x73, 0xa9, 0xbe, 0x8d, 0x36, 0xda, 0xb6, 0xcc,
+ 0xa9, 0xa1, 0x01, 0xe0, 0x6f, 0x00, 0xb0, 0x25, 0x70, 0x31, 0xff, 0xf8,
+ 0x87, 0x8e, 0x9c, 0x7a, 0x19, 0x17, 0x18, 0xec, 0x14, 0x08, 0xf3, 0xd4,
+ 0x20, 0x2e, 0x28, 0xb1, 0x53, 0x69, 0x5c, 0x23, 0xb8, 0xfe, 0xd2, 0x31,
+ 0x3c, 0xd7, 0x09, 0x7c, 0x85, 0x3c, 0x02, 0x9c, 0xaf, 0xe0, 0xb9, 0xaf,
+ 0x3b, 0x6f, 0x9c, 0xe7, 0x7e, 0xe2, 0x18, 0x9e, 0x7b, 0xc5, 0xa9, 0xf2,
+ 0xdc, 0x59, 0x47, 0x3d, 0xfc, 0x8c, 0x13, 0x79, 0x98, 0xbe, 0xc4, 0x59,
+ 0xc7, 0xf0, 0x7f, 0x44, 0x86, 0xf7, 0x82, 0x96, 0x1e, 0x5e, 0xc0, 0x45,
+ 0xba, 0x7a, 0x16, 0xe5, 0x2f, 0xac, 0x1a, 0xf7, 0xf9, 0x37, 0x31, 0xee,
+ 0xab, 0x76, 0x5c, 0x51, 0xd5, 0x71, 0x2f, 0xa0, 0xef, 0x97, 0xec, 0xb8,
+ 0x17, 0x6a, 0xc6, 0x05, 0xad, 0x3c, 0xbc, 0x84, 0x8b, 0x74, 0xf1, 0x22,
+ 0xca, 0x43, 0x99, 0x80, 0x85, 0x6e, 0x6e, 0xd0, 0x67, 0x9d, 0xe2, 0x5e,
+ 0xc3, 0xb2, 0x6e, 0x4c, 0xd7, 0xe8, 0x87, 0x37, 0xa2, 0x1f, 0x27, 0x8b,
+ 0xb4, 0x11, 0x17, 0x6a, 0xe4, 0x02, 0x7d, 0xa3, 0x40, 0x8e, 0x69, 0x3f,
+ 0x88, 0x3e, 0x11, 0xfd, 0xa3, 0xd5, 0xb6, 0xd5, 0x27, 0x75, 0xee, 0xd8,
+ 0xaf, 0x15, 0x3a, 0xe5, 0xd3, 0x05, 0xda, 0x84, 0xa4, 0x97, 0x20, 0x98,
+ 0xd8, 0x41, 0xfb, 0x34, 0x17, 0x5c, 0xe2, 0x91, 0x4e, 0x3c, 0xf7, 0x33,
+ 0x6b, 0x75, 0x46, 0x69, 0x18, 0xbe, 0x7b, 0xe6, 0xe8, 0xaf, 0x40, 0x67,
+ 0x34, 0x00, 0x6e, 0xd2, 0x5b, 0x87, 0xdc, 0x58, 0x52, 0x53, 0x9b, 0x25,
+ 0x21, 0x37, 0x15, 0x1a, 0x61, 0xf7, 0x30, 0xaf, 0xaa, 0x59, 0xba, 0x77,
+ 0xc4, 0x4c, 0xde, 0xb7, 0x1b, 0xc7, 0x6f, 0xd7, 0xe4, 0xa1, 0xc7, 0x13,
+ 0x78, 0xff, 0x7b, 0x2e, 0xe5, 0x60, 0xdc, 0xbb, 0x56, 0xe7, 0xf4, 0x74,
+ 0xed, 0xa0, 0xdd, 0x72, 0xbd, 0xd6, 0xe1, 0xd1, 0x35, 0x76, 0x92, 0xea,
+ 0x70, 0xa5, 0x6a, 0xa3, 0x8d, 0x17, 0x52, 0x49, 0xc2, 0xf5, 0x90, 0x70,
+ 0xff, 0xeb, 0x1e, 0xc9, 0xfb, 0xad, 0xf0, 0x0b, 0x18, 0x3b, 0x4f, 0xf5,
+ 0xd2, 0x36, 0x9a, 0x9d, 0x76, 0x6d, 0x5e, 0xf4, 0x46, 0x79, 0x4e, 0x8f,
+ 0xd3, 0xa8, 0x61, 0x34, 0x67, 0x25, 0xb8, 0x8f, 0x10, 0xd3, 0xe7, 0x73,
+ 0x66, 0xcb, 0x2d, 0x5a, 0xef, 0xcc, 0x96, 0x99, 0x87, 0x0f, 0x7f, 0xaa,
+ 0xcc, 0xbc, 0x7b, 0x5f, 0xdc, 0x77, 0xc2, 0xcf, 0x2d, 0x6f, 0x91, 0xf1,
+ 0xe9, 0x75, 0xd2, 0xe8, 0xa9, 0xf8, 0x66, 0xc8, 0x47, 0xb6, 0xe9, 0xda,
+ 0x01, 0xff, 0x70, 0x66, 0xab, 0x3c, 0x39, 0xc3, 0xbe, 0x3b, 0x64, 0x6e,
+ 0x5e, 0x1c, 0xf7, 0x9d, 0xeb, 0x51, 0x07, 0x72, 0x7d, 0x07, 0xcb, 0x92,
+ 0xb8, 0x8b, 0x72, 0xdf, 0x19, 0x95, 0x73, 0x03, 0x7c, 0x66, 0xee, 0xbf,
+ 0x44, 0xd9, 0xdf, 0xb9, 0x81, 0x4e, 0x79, 0x7c, 0x1e, 0x34, 0x01, 0xb9,
+ 0x3f, 0x72, 0x82, 0x30, 0x89, 0xec, 0x9a, 0x65, 0x2c, 0xbd, 0xdb, 0x65,
+ 0xdc, 0x94, 0xfb, 0x34, 0xb7, 0x0c, 0x70, 0x2c, 0xe8, 0x25, 0xe8, 0xb8,
+ 0xae, 0x1d, 0x46, 0x16, 0xa4, 0x67, 0x1b, 0x50, 0xce, 0x7e, 0xe1, 0x3f,
+ 0xee, 0x65, 0x3f, 0x61, 0x5b, 0x85, 0x39, 0x35, 0x6a, 0x7a, 0x59, 0x5a,
+ 0xa5, 0x3f, 0xce, 0xfc, 0x4c, 0xf6, 0x37, 0xfb, 0xe8, 0xd5, 0x7b, 0x21,
+ 0xdc, 0x53, 0x36, 0xb6, 0x15, 0xd7, 0x44, 0xef, 0x29, 0xc0, 0xae, 0xba,
+ 0x42, 0xdb, 0x17, 0x73, 0x15, 0xae, 0x20, 0x63, 0x51, 0xe1, 0x1a, 0x25,
+ 0xe4, 0xd1, 0xe2, 0xf2, 0x3a, 0x6d, 0x69, 0x58, 0xb9, 0x4e, 0xa4, 0x15,
+ 0x7f, 0xcc, 0xda, 0x1e, 0x8b, 0x92, 0x83, 0x5d, 0xd6, 0xab, 0xd7, 0x6c,
+ 0x11, 0xb6, 0xac, 0x5d, 0x33, 0x6d, 0xcf, 0xe6, 0xc3, 0x35, 0x1b, 0x85,
+ 0xc6, 0x29, 0xab, 0x4d, 0x5c, 0x33, 0x97, 0xf1, 0x6e, 0xe0, 0x3d, 0x87,
+ 0x75, 0xca, 0x61, 0x8d, 0x72, 0xe5, 0x0e, 0x99, 0x3d, 0xa6, 0x3a, 0x1b,
+ 0x44, 0x92, 0xe3, 0x5e, 0x87, 0x4c, 0xce, 0x33, 0x96, 0xb0, 0x05, 0x36,
+ 0xd8, 0x56, 0x5c, 0x9d, 0x78, 0x66, 0x3b, 0xf0, 0x54, 0x59, 0xa1, 0x6d,
+ 0xd3, 0x1a, 0x3b, 0xeb, 0x71, 0x8c, 0xcd, 0x1c, 0xe1, 0x27, 0x80, 0x87,
+ 0x2a, 0xef, 0x4c, 0xd5, 0xc4, 0x9f, 0x38, 0x57, 0xad, 0x43, 0x31, 0xdf,
+ 0xb8, 0x5e, 0x4f, 0x1d, 0x87, 0x2a, 0x36, 0xbe, 0x19, 0x7b, 0x2a, 0x41,
+ 0x7b, 0x2a, 0x5b, 0x72, 0xcd, 0xf9, 0x80, 0x51, 0xf8, 0x4e, 0x5e, 0xef,
+ 0x26, 0xd2, 0xfa, 0xd8, 0x0c, 0xe1, 0x8a, 0x85, 0x70, 0xad, 0x58, 0x33,
+ 0x9e, 0xe7, 0x5a, 0x1b, 0xe7, 0x98, 0x5a, 0xce, 0x5f, 0x34, 0xb1, 0x7d,
+ 0xc6, 0x51, 0x3a, 0xeb, 0xc0, 0x74, 0xa7, 0xb6, 0x61, 0x45, 0x8d, 0xc9,
+ 0x81, 0x22, 0xcf, 0x82, 0x31, 0x9e, 0x78, 0x23, 0xe3, 0x49, 0xbd, 0xb3,
+ 0xf2, 0x5e, 0x8c, 0xcd, 0x5c, 0x1d, 0x65, 0xe3, 0x37, 0x1b, 0x6c, 0x8e,
+ 0x48, 0x6d, 0x0c, 0xc7, 0xe4, 0xf2, 0xac, 0xcc, 0x8b, 0x4e, 0x8d, 0x2e,
+ 0x61, 0x9d, 0x7f, 0x5d, 0xef, 0x0d, 0x4a, 0x29, 0x02, 0xed, 0x37, 0x3e,
+ 0x90, 0x1a, 0x34, 0xe7, 0x60, 0x92, 0xb2, 0xb3, 0x68, 0xe6, 0x7f, 0x5e,
+ 0xe7, 0xf4, 0x98, 0xdc, 0x45, 0x93, 0xef, 0x73, 0x8f, 0x9c, 0x87, 0x0e,
+ 0xaf, 0xae, 0x6d, 0x93, 0x4c, 0x02, 0x17, 0x59, 0xbd, 0x2f, 0x91, 0x94,
+ 0xec, 0xc0, 0xc7, 0x37, 0xf1, 0x9c, 0x44, 0x0c, 0xeb, 0x93, 0x9f, 0xe1,
+ 0xd9, 0x49, 0xf6, 0x7b, 0xb1, 0xbe, 0x28, 0x66, 0x99, 0x87, 0x0f, 0x59,
+ 0xf9, 0xb6, 0xbe, 0x44, 0xb3, 0x7e, 0xbf, 0xce, 0xe6, 0x5b, 0x3b, 0x22,
+ 0x37, 0x06, 0xf2, 0x87, 0x10, 0x9f, 0x8f, 0xd9, 0x39, 0x25, 0x75, 0xcc,
+ 0x4a, 0x82, 0x73, 0x7e, 0xc2, 0xc6, 0x2c, 0x39, 0x97, 0x1b, 0x2c, 0x7d,
+ 0x1b, 0xfb, 0xa7, 0x6a, 0x43, 0x9b, 0x7d, 0xbf, 0x27, 0xb5, 0x2c, 0xec,
+ 0xb7, 0xb6, 0xb3, 0x8e, 0xf3, 0x1c, 0x17, 0x9d, 0x13, 0x10, 0xfa, 0x46,
+ 0x3d, 0x35, 0x7e, 0x81, 0xf1, 0xe5, 0xf2, 0xd3, 0xf5, 0x64, 0x54, 0xd5,
+ 0x27, 0xa4, 0x2f, 0x37, 0xb1, 0x8d, 0xdf, 0x2d, 0x08, 0x7d, 0xb9, 0x7e,
+ 0xeb, 0xcb, 0xb5, 0x6a, 0x5f, 0xce, 0xc4, 0x1e, 0x5a, 0x97, 0x7d, 0xb9,
+ 0xfc, 0x74, 0x0e, 0xb4, 0x12, 0x7e, 0x67, 0xc1, 0xd8, 0x42, 0x93, 0x05,
+ 0x9e, 0x79, 0x69, 0x94, 0xec, 0xa8, 0x82, 0xdf, 0x60, 0x7c, 0x2c, 0xc6,
+ 0x2a, 0x94, 0xfa, 0x96, 0xf5, 0x2f, 0x3a, 0x25, 0xdd, 0xbe, 0x0e, 0xf3,
+ 0xbe, 0x53, 0xaf, 0xf9, 0x5c, 0xc1, 0xec, 0x7d, 0x66, 0xf7, 0x32, 0x26,
+ 0xc4, 0x73, 0x4d, 0x9a, 0xbf, 0x92, 0xc3, 0x91, 0x5e, 0x63, 0xcf, 0x7a,
+ 0xdf, 0x04, 0xde, 0x4f, 0x02, 0xe7, 0x31, 0x3b, 0x6e, 0x12, 0x30, 0x1d,
+ 0xc0, 0xda, 0x5c, 0x6b, 0x65, 0x32, 0xc7, 0xde, 0xd3, 0xc4, 0xd8, 0xc0,
+ 0x7c, 0x21, 0x8c, 0x11, 0x46, 0xec, 0x99, 0x4a, 0x2f, 0xd2, 0xe8, 0xad,
+ 0xab, 0x6b, 0xab, 0x9e, 0x7e, 0x5d, 0xdd, 0x44, 0x5a, 0xba, 0x53, 0xe7,
+ 0xb9, 0xac, 0x1f, 0x48, 0xed, 0xd1, 0x39, 0xf2, 0x3a, 0xc6, 0x98, 0x13,
+ 0xe6, 0x94, 0x7d, 0x57, 0xde, 0xa1, 0x65, 0xfe, 0x01, 0x9f, 0xfa, 0x6b,
+ 0x87, 0xfe, 0xdd, 0x38, 0x14, 0x04, 0xe7, 0x06, 0xee, 0x86, 0xad, 0xe2,
+ 0xb9, 0xdf, 0x97, 0xee, 0xc4, 0xb0, 0xb6, 0x9d, 0xb0, 0x46, 0x7b, 0x9b,
+ 0x65, 0x9d, 0x77, 0xb3, 0xcd, 0x99, 0xc9, 0x41, 0x6e, 0xa6, 0x60, 0x33,
+ 0xf1, 0x4c, 0x70, 0x8f, 0x7d, 0x97, 0x0b, 0x9a, 0x41, 0x47, 0x1f, 0x13,
+ 0x23, 0x63, 0xb2, 0x55, 0x19, 0xc3, 0x5c, 0x83, 0x34, 0x09, 0x39, 0x7a,
+ 0x44, 0x52, 0xfc, 0xee, 0x07, 0xc7, 0xce, 0xcb, 0xa5, 0xd0, 0xcb, 0x6c,
+ 0xa7, 0xbf, 0xd9, 0x83, 0x67, 0xee, 0xe1, 0x78, 0xee, 0x41, 0xe8, 0x96,
+ 0xeb, 0xd7, 0xea, 0x96, 0x04, 0xfd, 0xfa, 0x6c, 0x89, 0xbe, 0xe1, 0x7a,
+ 0xb4, 0xe9, 0x90, 0x8f, 0x4f, 0x77, 0xb7, 0x91, 0xb7, 0xc6, 0x20, 0xd7,
+ 0xd5, 0xfd, 0xe1, 0x59, 0x20, 0x96, 0xf1, 0x3d, 0xfb, 0x6d, 0x92, 0xe4,
+ 0xfb, 0x5d, 0xf9, 0x7c, 0x25, 0x95, 0x5c, 0x82, 0x6e, 0x1a, 0x73, 0x7e,
+ 0xf1, 0x72, 0x13, 0x53, 0x7d, 0x7b, 0x9b, 0x39, 0x3b, 0xd0, 0x4c, 0x9b,
+ 0xdd, 0xc6, 0x59, 0x6b, 0x69, 0x76, 0xc9, 0xca, 0xe3, 0x20, 0x68, 0x1e,
+ 0xd0, 0x32, 0x78, 0x0f, 0x65, 0xf0, 0x01, 0xbf, 0xc7, 0xd0, 0xbe, 0xf6,
+ 0x99, 0x02, 0xac, 0x23, 0xf0, 0x30, 0x10, 0x65, 0x7e, 0x9e, 0xe5, 0x4f,
+ 0x2f, 0xbd, 0x68, 0xe5, 0x92, 0x72, 0xd6, 0xf2, 0xa5, 0xba, 0x2a, 0xb6,
+ 0x42, 0xe6, 0x1e, 0x9a, 0xa6, 0x3e, 0xf6, 0x17, 0xbe, 0x0b, 0x39, 0x95,
+ 0xd5, 0x78, 0xe8, 0x90, 0xfb, 0xa6, 0x25, 0x7d, 0x1e, 0xba, 0x2a, 0x3f,
+ 0xbf, 0x92, 0x37, 0xd7, 0xf6, 0xc7, 0xb9, 0x7e, 0xb8, 0xcd, 0xf8, 0xb6,
+ 0x2b, 0xe7, 0xba, 0x80, 0xb9, 0xa6, 0xf5, 0x5c, 0xb9, 0x6f, 0xf3, 0x31,
+ 0x3b, 0xd7, 0xf5, 0xe1, 0x5c, 0x07, 0x57, 0xce, 0x35, 0xf4, 0xed, 0x43,
+ 0xb9, 0x9b, 0xd4, 0xf9, 0xf2, 0x3a, 0x4f, 0x7b, 0x7a, 0xbd, 0x0c, 0x97,
+ 0x5a, 0xad, 0xbc, 0x74, 0xa1, 0x7b, 0x98, 0xc3, 0xbe, 0x70, 0xaf, 0x2b,
+ 0x16, 0x67, 0x8a, 0x78, 0xa0, 0xac, 0x6d, 0xd3, 0x67, 0x6c, 0x66, 0xe1,
+ 0x5f, 0xdd, 0x5a, 0x60, 0xdd, 0xf0, 0xfd, 0xc5, 0x62, 0xc7, 0xa1, 0x4f,
+ 0x4d, 0xbf, 0xa9, 0x77, 0x4d, 0x4c, 0xc1, 0xc4, 0x87, 0x19, 0x17, 0x36,
+ 0x67, 0x7f, 0x99, 0x8b, 0x78, 0x07, 0x78, 0xea, 0x53, 0x85, 0xd4, 0x60,
+ 0x26, 0x42, 0x39, 0x7a, 0x5c, 0x0e, 0x55, 0x46, 0xa4, 0x4b, 0x9f, 0xff,
+ 0x7c, 0xdd, 0xd8, 0x71, 0xba, 0x36, 0x76, 0xcc, 0x74, 0x02, 0xc6, 0x8e,
+ 0xf7, 0xfc, 0x0c, 0xb1, 0x63, 0x71, 0x4c, 0xec, 0xb8, 0x9e, 0x7f, 0x35,
+ 0x55, 0x3c, 0x8e, 0x79, 0x35, 0x43, 0x96, 0x2c, 0x3a, 0xd9, 0xf9, 0x16,
+ 0xdc, 0xcf, 0xe2, 0x1e, 0xc3, 0xfd, 0x3c, 0xee, 0x2e, 0xee, 0x17, 0x70,
+ 0x8f, 0xcb, 0xd4, 0xb2, 0xce, 0x38, 0x0e, 0xb9, 0x41, 0x5d, 0xc6, 0xb6,
+ 0xc6, 0x1f, 0x98, 0x2b, 0xb7, 0xf3, 0x7b, 0x2d, 0xce, 0xec, 0x3c, 0xe7,
+ 0xd0, 0x2a, 0x93, 0xd3, 0x94, 0xd9, 0x6d, 0x52, 0x9a, 0x0e, 0x6d, 0xdb,
+ 0x9f, 0xef, 0xe0, 0x9e, 0xc1, 0x98, 0x84, 0xb6, 0xeb, 0x3d, 0x1d, 0x66,
+ 0xaf, 0xf1, 0x3b, 0x58, 0xe3, 0x8d, 0x58, 0x83, 0x93, 0x72, 0x7e, 0x66,
+ 0xe3, 0x0a, 0x1b, 0x36, 0x69, 0x63, 0x82, 0x33, 0x56, 0xf7, 0xd6, 0x97,
+ 0x11, 0xb5, 0xeb, 0x9f, 0xb0, 0x67, 0xcb, 0xc2, 0x1c, 0xa1, 0xa4, 0x5e,
+ 0x9f, 0xd1, 0xca, 0x71, 0x8c, 0x37, 0x28, 0xe9, 0x19, 0xce, 0x73, 0xf9,
+ 0x9b, 0x11, 0x90, 0x87, 0x27, 0xa0, 0x57, 0x57, 0xd0, 0x25, 0xe8, 0x96,
+ 0x73, 0x73, 0x40, 0xbb, 0x8f, 0xca, 0x6c, 0x89, 0xf0, 0xf5, 0x24, 0x22,
+ 0xfa, 0xac, 0x19, 0x9e, 0x67, 0x4c, 0x8e, 0xfb, 0x70, 0x25, 0x3c, 0x67,
+ 0xb6, 0x89, 0x67, 0x07, 0x57, 0x9d, 0x35, 0xb3, 0xfa, 0x59, 0xdb, 0x0e,
+ 0x3c, 0x73, 0x16, 0xce, 0xa1, 0x1e, 0x3d, 0x05, 0x32, 0xa9, 0xf3, 0xce,
+ 0x36, 0xcb, 0x63, 0x0f, 0x2e, 0xe7, 0xbc, 0xb6, 0xc1, 0x46, 0xe9, 0x84,
+ 0x89, 0x3c, 0x1a, 0x1d, 0xea, 0x81, 0x8f, 0xc7, 0x3c, 0x99, 0x9e, 0xc4,
+ 0x6d, 0x3a, 0x17, 0xb9, 0x7a, 0xee, 0xaf, 0x9a, 0x8f, 0x1c, 0x9e, 0xb3,
+ 0x4a, 0xe8, 0xef, 0x5a, 0xec, 0xd4, 0xe5, 0x71, 0xcc, 0x87, 0xfb, 0x7e,
+ 0x1a, 0x0f, 0x09, 0x7e, 0xa7, 0xeb, 0x29, 0xe0, 0x60, 0xb2, 0xf2, 0x6d,
+ 0xd0, 0xbb, 0x63, 0xcf, 0x9c, 0x91, 0xc6, 0x06, 0x64, 0xa2, 0x9c, 0x70,
+ 0x26, 0xca, 0x03, 0xce, 0xbe, 0xb2, 0x7d, 0x37, 0xb0, 0x67, 0xb3, 0x34,
+ 0xe3, 0xf7, 0x4c, 0x97, 0x33, 0x06, 0x7c, 0xe5, 0x8b, 0xdd, 0x4e, 0x5a,
+ 0xdf, 0x3d, 0x7b, 0x87, 0x1c, 0xc0, 0x5a, 0x0d, 0xcf, 0xc4, 0xb5, 0x9c,
+ 0xaf, 0x7e, 0x5b, 0x2a, 0x5c, 0x57, 0x7e, 0x13, 0x89, 0x7c, 0x7c, 0x5c,
+ 0x7f, 0xe7, 0xc8, 0xd8, 0x0e, 0x27, 0xd1, 0xdf, 0x71, 0x1b, 0x13, 0xef,
+ 0x73, 0xb2, 0xba, 0x1f, 0xb3, 0x1e, 0xf9, 0xe2, 0x09, 0xdc, 0x57, 0x9f,
+ 0x79, 0x0e, 0xf5, 0x8c, 0x85, 0xbb, 0x10, 0xdc, 0x63, 0xe4, 0xd5, 0x71,
+ 0x99, 0xaa, 0x30, 0x7f, 0xc4, 0xd1, 0x7c, 0x34, 0x59, 0x3e, 0x00, 0x9d,
+ 0xb4, 0xf2, 0xcc, 0xdf, 0xce, 0xea, 0x3a, 0x24, 0x67, 0x84, 0xb0, 0x70,
+ 0x0d, 0x56, 0x9e, 0x87, 0xbf, 0xf8, 0xbf, 0x70, 0x5f, 0xd1, 0xc8, 0x50,
+ 0x0b, 0x47, 0x9a, 0xf2, 0xce, 0xc8, 0x95, 0x69, 0x39, 0x08, 0x78, 0x0e,
+ 0xe3, 0x52, 0xf7, 0xf3, 0x3b, 0x2c, 0xf3, 0x92, 0x9f, 0xbb, 0x4f, 0xd4,
+ 0x43, 0xe7, 0x9d, 0xe8, 0x43, 0x07, 0x25, 0xf2, 0xd0, 0xa2, 0xd3, 0xf0,
+ 0x50, 0xb7, 0xf6, 0xcb, 0x77, 0xfb, 0xdd, 0x89, 0x7d, 0x72, 0x52, 0xa2,
+ 0xf7, 0x2b, 0x7d, 0xfe, 0x2b, 0xef, 0x32, 0xc6, 0x77, 0x52, 0x22, 0xf7,
+ 0xc7, 0xec, 0xd9, 0x51, 0x13, 0xd7, 0x5b, 0xd2, 0x7c, 0xff, 0x9b, 0x71,
+ 0xe2, 0x6c, 0x49, 0x8e, 0x6b, 0xde, 0x19, 0x86, 0x9e, 0xc8, 0x94, 0x92,
+ 0xcb, 0x75, 0x4c, 0xbe, 0xe7, 0xf3, 0x9b, 0x0d, 0xbf, 0xb0, 0x4e, 0x8f,
+ 0xc3, 0xef, 0x38, 0x18, 0x9d, 0x91, 0xb9, 0x2c, 0xcc, 0xfd, 0x34, 0x6b,
+ 0xca, 0xf7, 0x67, 0xb1, 0x86, 0x3d, 0x58, 0x2f, 0x8e, 0xe7, 0xe8, 0xfd,
+ 0x5c, 0x9e, 0x9d, 0x75, 0xa5, 0x2f, 0xd1, 0xb4, 0x6c, 0x07, 0xb1, 0xee,
+ 0x7d, 0xd2, 0x04, 0xb8, 0xd5, 0x43, 0x79, 0x63, 0xd7, 0x09, 0xe9, 0x54,
+ 0x20, 0xb9, 0x49, 0xb3, 0x3d, 0x83, 0xbb, 0xf5, 0x1a, 0xde, 0x6b, 0x69,
+ 0x66, 0x9d, 0xb1, 0x1f, 0xf1, 0x6c, 0xe8, 0x22, 0x2f, 0xbb, 0xa6, 0x7f,
+ 0x08, 0x3d, 0xcf, 0x7d, 0x17, 0x6d, 0x2f, 0xd6, 0xb1, 0x05, 0xc9, 0x4b,
+ 0xcf, 0x58, 0xbf, 0x32, 0x08, 0xa6, 0x7d, 0x1f, 0x78, 0xac, 0xe7, 0x4b,
+ 0x6e, 0x71, 0xe6, 0x4a, 0x5b, 0x9d, 0xd9, 0x52, 0x20, 0x13, 0x3e, 0xbf,
+ 0xe3, 0xc1, 0x1c, 0x00, 0xda, 0x5b, 0x2c, 0xeb, 0x86, 0x6e, 0xfd, 0xeb,
+ 0xcd, 0x3c, 0x8f, 0x74, 0x93, 0xf7, 0xa2, 0x98, 0x7a, 0xc4, 0x31, 0x7d,
+ 0xe4, 0xee, 0xe3, 0x59, 0xe1, 0xf7, 0x34, 0xfa, 0x12, 0x71, 0xfd, 0x5d,
+ 0x8f, 0xcf, 0xa1, 0x1d, 0xc6, 0x28, 0x72, 0xdc, 0x67, 0x9d, 0x59, 0xc8,
+ 0xb3, 0xb9, 0x69, 0x9e, 0xe1, 0x67, 0x3e, 0x6d, 0xa4, 0x53, 0xc9, 0x15,
+ 0xee, 0xa4, 0xfd, 0x06, 0x5c, 0x0e, 0x2e, 0x50, 0x44, 0x97, 0xf5, 0xb9,
+ 0xe3, 0xcb, 0xdf, 0x85, 0x0b, 0xcb, 0xc2, 0xef, 0xc3, 0x29, 0x9d, 0x3b,
+ 0x0d, 0x5f, 0xf6, 0xb1, 0x31, 0xf9, 0x89, 0x33, 0x5f, 0x78, 0xc5, 0x79,
+ 0xb4, 0x90, 0xbe, 0xea, 0x12, 0xd0, 0xc7, 0x39, 0xbf, 0x97, 0xf2, 0x0b,
+ 0x36, 0x5f, 0x41, 0x72, 0x95, 0x09, 0x99, 0xe9, 0xe8, 0x76, 0xef, 0xd7,
+ 0x6b, 0x33, 0x03, 0x9c, 0x7d, 0x1b, 0xeb, 0xf7, 0xc9, 0x38, 0xf5, 0xdb,
+ 0x78, 0x41, 0x81, 0x97, 0xd5, 0xcf, 0xe3, 0x82, 0x6d, 0xdb, 0xa8, 0x6d,
+ 0x94, 0x7d, 0x3e, 0xeb, 0x6d, 0x75, 0x86, 0x4b, 0x5b, 0xb0, 0x8e, 0x7b,
+ 0xa1, 0x3f, 0x1d, 0xd8, 0x69, 0xa0, 0x6d, 0x94, 0x4d, 0x02, 0x07, 0xe3,
+ 0xbe, 0x91, 0xe7, 0xc3, 0x92, 0xd3, 0x3e, 0x9e, 0xb9, 0xa7, 0x95, 0x89,
+ 0x99, 0x05, 0xc1, 0x1c, 0xec, 0x83, 0x6c, 0x7f, 0x09, 0xbc, 0xf0, 0x08,
+ 0xae, 0xb7, 0xdb, 0x3d, 0xed, 0x17, 0x2e, 0xb2, 0xa7, 0xed, 0xca, 0xc9,
+ 0x8a, 0x3e, 0xd7, 0xae, 0xf3, 0xab, 0x92, 0xea, 0xbf, 0x5f, 0xa2, 0xd7,
+ 0x4a, 0xf5, 0xe8, 0x9c, 0xb4, 0xb4, 0x7c, 0x38, 0x6e, 0xf4, 0x30, 0x61,
+ 0x4a, 0x02, 0x9e, 0xad, 0xc0, 0x05, 0xe1, 0x31, 0x6d, 0x44, 0x6d, 0xba,
+ 0x94, 0xfa, 0x70, 0x49, 0x3e, 0x12, 0x0f, 0xcf, 0x14, 0xa0, 0x1f, 0xc8,
+ 0xb8, 0x8f, 0x5d, 0x6a, 0xf4, 0xe4, 0xe6, 0x3a, 0xfd, 0x84, 0x73, 0x73,
+ 0xec, 0xdc, 0x48, 0xb7, 0x7f, 0x96, 0xa0, 0x4f, 0xb1, 0x24, 0x4d, 0xab,
+ 0xea, 0x33, 0xa6, 0xbf, 0xe1, 0x72, 0x73, 0x46, 0x81, 0x75, 0x5d, 0xd8,
+ 0xa6, 0xb4, 0x73, 0x89, 0x47, 0xbd, 0x6e, 0x05, 0x25, 0x3c, 0x67, 0x00,
+ 0x6e, 0xae, 0x5c, 0xe1, 0xbe, 0x43, 0x91, 0x0e, 0x43, 0x5c, 0x7f, 0x5b,
+ 0xf3, 0xc9, 0x78, 0x81, 0xb1, 0x95, 0x47, 0x83, 0xf4, 0x28, 0x79, 0x8c,
+ 0x7d, 0xf0, 0x7d, 0x41, 0xc7, 0x73, 0xf7, 0xfa, 0x8c, 0x15, 0x75, 0x1f,
+ 0xbf, 0x43, 0x85, 0x72, 0x0a, 0xfa, 0xb7, 0xb8, 0xe8, 0xf0, 0x1b, 0x78,
+ 0x37, 0x0a, 0xee, 0xf3, 0x8b, 0xce, 0x77, 0xa7, 0x9f, 0xc5, 0x73, 0x83,
+ 0xfd, 0xee, 0x9d, 0xd1, 0x53, 0x22, 0xc5, 0x70, 0xbe, 0x89, 0x1c, 0xd6,
+ 0xfe, 0x02, 0xd6, 0xbe, 0xfe, 0x77, 0xee, 0xf0, 0xae, 0x8c, 0x77, 0xe5,
+ 0x0f, 0x07, 0xe9, 0x36, 0xd2, 0x22, 0xe9, 0xef, 0xb5, 0xfc, 0xe6, 0x41,
+ 0xcd, 0x17, 0x93, 0xc5, 0xc7, 0xc1, 0x17, 0x69, 0xee, 0x37, 0x07, 0x0f,
+ 0xfb, 0x37, 0x80, 0x2f, 0xf6, 0xc8, 0xef, 0xc3, 0x2e, 0xf8, 0xdd, 0xca,
+ 0x10, 0xf8, 0x63, 0x10, 0xfc, 0x32, 0x00, 0x1e, 0xf1, 0xb5, 0x8d, 0xfc,
+ 0x04, 0xf4, 0x1f, 0xf4, 0x9a, 0xb3, 0xaf, 0xd4, 0xe5, 0x64, 0x4b, 0x9e,
+ 0x33, 0x51, 0xe2, 0xf7, 0x5a, 0xd4, 0x5b, 0x1b, 0x24, 0x9a, 0x98, 0x13,
+ 0xf2, 0x42, 0x37, 0x73, 0x1c, 0xdb, 0x81, 0xab, 0x53, 0xc4, 0xd5, 0x5c,
+ 0xa5, 0xcf, 0xbd, 0x04, 0x3c, 0xd1, 0xae, 0x79, 0xa2, 0xd5, 0x49, 0xbb,
+ 0x37, 0x58, 0x9e, 0x78, 0x11, 0x3c, 0x71, 0x7e, 0x0d, 0x4f, 0x3c, 0x6d,
+ 0xe9, 0x7f, 0xa1, 0x86, 0x27, 0xe6, 0x6c, 0xd9, 0xcc, 0x45, 0x78, 0xe2,
+ 0x52, 0x2f, 0xf5, 0xa5, 0x31, 0x79, 0x15, 0x3c, 0x21, 0x8a, 0x3c, 0x71,
+ 0xa9, 0xe6, 0x09, 0xc6, 0x8e, 0xc8, 0x17, 0x9d, 0x90, 0x23, 0xe4, 0x8b,
+ 0xb3, 0xb2, 0x04, 0xbe, 0x78, 0x5e, 0x71, 0xec, 0x19, 0xda, 0x0a, 0x25,
+ 0xfa, 0x64, 0x27, 0x8a, 0x5d, 0xe0, 0x77, 0x25, 0xff, 0x65, 0x3a, 0x08,
+ 0x16, 0xe1, 0xa7, 0x3f, 0x08, 0x7b, 0x3e, 0xaa, 0xbf, 0xa9, 0xb8, 0x00,
+ 0xba, 0x0f, 0xe9, 0x7d, 0xc2, 0x01, 0xbd, 0x1f, 0x9e, 0xc5, 0x1c, 0x26,
+ 0xd4, 0x7f, 0x86, 0x2f, 0xec, 0x62, 0x5d, 0x69, 0xe7, 0x1f, 0xd3, 0x3c,
+ 0xd4, 0x00, 0x7d, 0xf0, 0xe8, 0x00, 0x63, 0x4d, 0x9e, 0xbb, 0x4f, 0x75,
+ 0xe7, 0x46, 0x00, 0x73, 0x44, 0xdd, 0x2f, 0x8c, 0x73, 0xb4, 0xad, 0xb2,
+ 0xf3, 0x29, 0x23, 0x46, 0x21, 0xeb, 0xcc, 0xbb, 0x5c, 0xd0, 0x04, 0x9b,
+ 0xb4, 0x49, 0x19, 0x1b, 0x5d, 0xed, 0x48, 0xb9, 0x1f, 0x84, 0x00, 0x6d,
+ 0x84, 0xbd, 0xb0, 0x0b, 0xab, 0x3d, 0x52, 0xa8, 0xb5, 0xf1, 0xff, 0x03,
+ 0x6c, 0x7c, 0xb6, 0x91, 0xa8, 0xb1, 0xf1, 0x7f, 0xcd, 0xf2, 0x1a, 0x7f,
+ 0xbb, 0xda, 0xde, 0x3f, 0x00, 0xf8, 0x76, 0x2f, 0xdb, 0xfb, 0xec, 0x83,
+ 0x76, 0x87, 0xc8, 0xf5, 0xb0, 0xf9, 0xde, 0x0d, 0x1e, 0xbc, 0x01, 0xbe,
+ 0xd4, 0x7b, 0x0a, 0xae, 0xec, 0x29, 0xb4, 0xc3, 0xe7, 0xee, 0x94, 0xf7,
+ 0x4e, 0x6f, 0x95, 0x9d, 0x25, 0xff, 0x12, 0x69, 0xee, 0x80, 0x8d, 0x5a,
+ 0x00, 0x9c, 0x11, 0x2b, 0xb7, 0xcf, 0x02, 0x6f, 0xdd, 0xc9, 0x9f, 0xa8,
+ 0x17, 0xad, 0x5d, 0xc4, 0xb3, 0x8e, 0xf5, 0xfa, 0x89, 0xa3, 0x3d, 0x63,
+ 0x29, 0x1d, 0x72, 0xea, 0x18, 0xbd, 0xaf, 0x24, 0xec, 0x72, 0x1f, 0x36,
+ 0xc9, 0x16, 0xf4, 0xc7, 0x78, 0xf2, 0x46, 0x79, 0xfa, 0xaa, 0xe8, 0x5d,
+ 0x59, 0xcd, 0x87, 0x9d, 0x4e, 0x66, 0x1a, 0x3e, 0xc0, 0xde, 0x18, 0xe6,
+ 0xa0, 0xda, 0x37, 0xcb, 0x75, 0xb2, 0x53, 0xcf, 0x67, 0x46, 0x0e, 0x42,
+ 0x37, 0xff, 0x41, 0x61, 0xa7, 0x2c, 0x8d, 0xb6, 0xe1, 0x39, 0x26, 0x4f,
+ 0x17, 0xfa, 0xe0, 0xfb, 0xbc, 0x0b, 0x38, 0x6a, 0xc4, 0x73, 0xa3, 0x0c,
+ 0x5f, 0x42, 0x5e, 0x6d, 0x91, 0x45, 0x94, 0xbf, 0x5b, 0x7e, 0xc1, 0x96,
+ 0xb3, 0x8c, 0xbc, 0xd1, 0x82, 0xb6, 0x31, 0x39, 0x57, 0xa0, 0x5d, 0xa9,
+ 0x79, 0x62, 0xf0, 0x7b, 0xd2, 0x97, 0xfe, 0x1e, 0xec, 0xd4, 0xb3, 0xb8,
+ 0x9e, 0x91, 0xd4, 0x9e, 0x71, 0xa7, 0x2f, 0xd9, 0xed, 0x40, 0x77, 0xe2,
+ 0x8a, 0x3a, 0x7d, 0x6e, 0xa3, 0x73, 0x85, 0xed, 0xa3, 0x41, 0x9e, 0xd9,
+ 0xab, 0x12, 0x2d, 0x58, 0x93, 0xed, 0x4e, 0x8f, 0x2d, 0xe3, 0x73, 0xca,
+ 0x78, 0x40, 0xa7, 0xd4, 0x96, 0x0d, 0x22, 0x5d, 0x2d, 0xb0, 0x79, 0x26,
+ 0x44, 0xb5, 0xb7, 0x48, 0x54, 0xba, 0x67, 0x55, 0x27, 0xca, 0x3c, 0x5b,
+ 0x16, 0x6f, 0x81, 0x7e, 0x40, 0x59, 0x07, 0xca, 0xb6, 0xd9, 0xb2, 0xb6,
+ 0x16, 0x69, 0x44, 0xd9, 0x8c, 0xe6, 0xf9, 0xf3, 0x3d, 0x9e, 0x9b, 0x75,
+ 0x9a, 0xa5, 0xeb, 0x44, 0x0b, 0x64, 0xc3, 0x46, 0x59, 0xbc, 0xaa, 0x49,
+ 0xba, 0xf0, 0x8e, 0x71, 0x6e, 0xff, 0x44, 0x4c, 0xae, 0x3d, 0xd1, 0x9d,
+ 0xf8, 0x38, 0xe6, 0xd0, 0x7d, 0x8a, 0x71, 0xef, 0xfc, 0x25, 0x8c, 0xfb,
+ 0x74, 0x9d, 0xe2, 0xbd, 0x49, 0xcb, 0x1f, 0xe2, 0xc3, 0x7c, 0x93, 0x88,
+ 0x32, 0xf9, 0x24, 0xfc, 0x5c, 0xea, 0xf0, 0x6e, 0xfb, 0xfd, 0x8c, 0xe3,
+ 0x97, 0xd0, 0x6f, 0x9b, 0xa5, 0x5d, 0x52, 0x24, 0x3f, 0x52, 0x0f, 0xe1,
+ 0x3e, 0xe3, 0x48, 0xbe, 0x2a, 0xb3, 0xe6, 0xc9, 0x57, 0xc7, 0x14, 0x73,
+ 0x59, 0x50, 0x56, 0xf9, 0xc5, 0xc0, 0xac, 0x31, 0x79, 0xc1, 0xc8, 0xa5,
+ 0x0f, 0x18, 0xb9, 0xf4, 0xd8, 0x99, 0x15, 0x72, 0xe9, 0xbc, 0x96, 0x4b,
+ 0x7b, 0x05, 0xf7, 0xf9, 0xf3, 0x90, 0x4b, 0x2f, 0xe2, 0xd9, 0xd5, 0x72,
+ 0x29, 0x2e, 0xd6, 0x5e, 0x96, 0xaf, 0xea, 0xf1, 0xe7, 0x8a, 0x51, 0x6d,
+ 0x57, 0xe5, 0x67, 0x60, 0x93, 0x14, 0xa7, 0xac, 0xfe, 0x96, 0xa1, 0x36,
+ 0xe9, 0x19, 0xfc, 0xa9, 0x84, 0x36, 0xe7, 0x7f, 0xba, 0x84, 0xdf, 0xee,
+ 0x7c, 0x5e, 0x51, 0x86, 0xbd, 0x0a, 0x19, 0x26, 0xaa, 0xbe, 0x0c, 0xc3,
+ 0xbb, 0x32, 0xde, 0x95, 0xd9, 0xef, 0x8f, 0x7e, 0x3a, 0xe6, 0x52, 0x7e,
+ 0x50, 0x66, 0x40, 0x26, 0x15, 0x21, 0x93, 0x8a, 0x90, 0x53, 0x45, 0xc8,
+ 0x25, 0xd8, 0x6c, 0x67, 0x8a, 0x90, 0x4b, 0x45, 0xc8, 0x25, 0xc8, 0xb8,
+ 0x27, 0x20, 0xe3, 0x8c, 0x4c, 0x1b, 0x85, 0x4c, 0x9b, 0x91, 0xfb, 0xac,
+ 0xae, 0x37, 0xb1, 0x92, 0x7e, 0xeb, 0x23, 0x0d, 0xe8, 0x18, 0xf2, 0x99,
+ 0x9a, 0xd8, 0xe0, 0x8d, 0x47, 0x34, 0xbf, 0xbb, 0x9e, 0xba, 0xc2, 0x61,
+ 0x0e, 0xcd, 0x4f, 0xb4, 0xff, 0xbe, 0x9d, 0xbf, 0xa5, 0x09, 0x7c, 0xfd,
+ 0x03, 0xcb, 0xd7, 0xdb, 0x97, 0xf9, 0x3a, 0xe5, 0x30, 0x56, 0x5c, 0x9f,
+ 0xaf, 0x3b, 0xec, 0xbb, 0x5c, 0xb0, 0x0e, 0x7c, 0xbd, 0x6e, 0x15, 0x5f,
+ 0xc7, 0xc0, 0xd7, 0x7b, 0xd6, 0xf0, 0xf5, 0x06, 0x67, 0x58, 0xb7, 0xe1,
+ 0x19, 0x09, 0x3e, 0x37, 0x3a, 0x55, 0xbe, 0xbe, 0x47, 0xf3, 0xf5, 0x21,
+ 0xf0, 0xf5, 0x75, 0x35, 0x7c, 0xbd, 0x47, 0x52, 0x37, 0x67, 0x22, 0x5b,
+ 0x65, 0xfc, 0x7e, 0xd5, 0xbe, 0x49, 0xfe, 0x49, 0x4c, 0x7b, 0xc3, 0x63,
+ 0xc3, 0xd3, 0xed, 0x92, 0x7d, 0xe8, 0x15, 0x94, 0x91, 0xcf, 0x52, 0x63,
+ 0x69, 0xc7, 0x95, 0x83, 0x47, 0x7e, 0x22, 0x0b, 0x9a, 0xb7, 0x44, 0x26,
+ 0x8e, 0xc4, 0x64, 0xf2, 0x08, 0xe3, 0x10, 0x7f, 0x63, 0xe9, 0xbd, 0x49,
+ 0x26, 0xf7, 0x32, 0x6f, 0x2e, 0x2a, 0xe3, 0x47, 0xe0, 0x6f, 0x1d, 0x61,
+ 0x1c, 0xe2, 0xa5, 0x65, 0x1e, 0x5b, 0x80, 0x6c, 0x19, 0x3f, 0xc2, 0xb5,
+ 0x8e, 0xa1, 0x9f, 0x16, 0x39, 0x74, 0x44, 0xe4, 0xb6, 0x23, 0x51, 0xf9,
+ 0xe8, 0x91, 0x65, 0x5e, 0x1b, 0x0d, 0x79, 0xed, 0x59, 0xf0, 0x5a, 0xb7,
+ 0xe5, 0x35, 0xb5, 0xcc, 0x6b, 0x7f, 0x5a, 0xc3, 0x6b, 0x6c, 0x4f, 0x5e,
+ 0x7b, 0xce, 0x96, 0xf1, 0x39, 0x2a, 0xfb, 0x8e, 0x74, 0xca, 0xf8, 0x43,
+ 0x6f, 0x91, 0x89, 0xfb, 0x09, 0xab, 0xf9, 0x8e, 0x13, 0x6d, 0xb1, 0x99,
+ 0x4a, 0x37, 0xfa, 0x0f, 0x73, 0x88, 0xf4, 0xf7, 0x10, 0x7a, 0x67, 0x25,
+ 0x95, 0xe3, 0x78, 0x8d, 0xf0, 0xa3, 0x4f, 0xc0, 0xbf, 0xd8, 0x07, 0x98,
+ 0x6e, 0x39, 0x22, 0xa9, 0xa8, 0xbc, 0x2c, 0x53, 0xfe, 0x27, 0x2e, 0x37,
+ 0xf6, 0x04, 0x6c, 0x11, 0x6d, 0xfb, 0xa4, 0x25, 0xfb, 0xce, 0x40, 0xfb,
+ 0x18, 0xa5, 0xb2, 0x30, 0x16, 0xc0, 0xb8, 0xb9, 0x63, 0xbe, 0xc7, 0xc4,
+ 0xfc, 0xc7, 0x06, 0x7d, 0xe6, 0x45, 0xc7, 0x6c, 0x07, 0xf8, 0x9e, 0xcf,
+ 0xb0, 0x67, 0xf4, 0x59, 0x43, 0xb6, 0x7f, 0x44, 0x7f, 0x1b, 0x91, 0x31,
+ 0xf5, 0x7c, 0x99, 0xdf, 0xb0, 0x81, 0xff, 0x59, 0xe6, 0xb7, 0xb0, 0xf6,
+ 0xb7, 0x9b, 0xf8, 0x2c, 0xf9, 0xee, 0x87, 0x0e, 0xbf, 0x5d, 0x35, 0xa5,
+ 0x73, 0xbd, 0xf0, 0xbb, 0xcc, 0x67, 0xd6, 0x7f, 0x84, 0xf1, 0x8e, 0x64,
+ 0x52, 0xbd, 0xf7, 0x72, 0xe6, 0x1e, 0xec, 0x9d, 0x67, 0xdd, 0xad, 0x96,
+ 0x47, 0xb7, 0x6a, 0xbf, 0x83, 0x36, 0xd6, 0x78, 0xe9, 0x45, 0xc9, 0xd3,
+ 0x36, 0x19, 0xdd, 0xea, 0xe4, 0x66, 0x92, 0x97, 0x1b, 0xfb, 0x79, 0xdd,
+ 0xa5, 0xcc, 0x3b, 0x4c, 0xab, 0xb5, 0x32, 0xf9, 0x84, 0x84, 0x32, 0x39,
+ 0x75, 0x33, 0xbf, 0xb7, 0x9b, 0x3d, 0xa2, 0xbf, 0x2f, 0x95, 0xec, 0x56,
+ 0x9c, 0xd3, 0xa7, 0x21, 0x5f, 0x43, 0x5a, 0x48, 0xc8, 0x27, 0x8f, 0x90,
+ 0x1e, 0x54, 0xbc, 0x55, 0x3e, 0x61, 0xe9, 0x61, 0x46, 0x0a, 0x90, 0x3b,
+ 0x47, 0x8e, 0x7c, 0x54, 0x66, 0x6e, 0x5c, 0x4d, 0x0f, 0x13, 0x55, 0x7a,
+ 0x88, 0xc3, 0x3e, 0x73, 0x6a, 0xe9, 0xe1, 0x97, 0x97, 0xe9, 0x61, 0xc6,
+ 0xf9, 0xe7, 0xd2, 0xc3, 0xf5, 0x2b, 0xe8, 0x61, 0x4a, 0xd3, 0xc3, 0xce,
+ 0x65, 0x7a, 0x98, 0x3a, 0xc2, 0x71, 0xf5, 0xde, 0xa8, 0xbb, 0xe8, 0x70,
+ 0xcd, 0x97, 0x69, 0x21, 0x39, 0xa9, 0xf3, 0xf5, 0x53, 0x39, 0x9e, 0x6f,
+ 0xda, 0xa0, 0x18, 0x27, 0xa9, 0xae, 0x7f, 0xeb, 0xbf, 0xe8, 0xfa, 0xbf,
+ 0xfc, 0xff, 0x79, 0xfd, 0xd5, 0xa5, 0xcc, 0xdd, 0xe7, 0x99, 0x55, 0x23,
+ 0x8f, 0x43, 0x7a, 0x88, 0x5d, 0x6a, 0xf4, 0x02, 0xd7, 0x98, 0xcf, 0x90,
+ 0x67, 0x90, 0x7f, 0x67, 0x20, 0xff, 0x9e, 0x84, 0xfc, 0x3b, 0xbd, 0x62,
+ 0x4f, 0x60, 0xd0, 0xc6, 0x23, 0x02, 0x39, 0xe8, 0x57, 0xf1, 0xb1, 0x38,
+ 0x40, 0x7c, 0x98, 0xfc, 0x13, 0xe6, 0xfe, 0xae, 0xc4, 0x49, 0x54, 0xe7,
+ 0x1c, 0x3d, 0xea, 0xd7, 0xe2, 0x84, 0x70, 0xbf, 0x5c, 0x33, 0x47, 0xfc,
+ 0x2e, 0xf3, 0x79, 0x46, 0xe7, 0x91, 0xe4, 0xf5, 0x1e, 0x14, 0xf1, 0xc2,
+ 0x3d, 0x28, 0xe2, 0x24, 0xaa, 0xed, 0xfd, 0x7c, 0xb9, 0x49, 0xe7, 0xd0,
+ 0x1f, 0x98, 0x8f, 0xcb, 0x62, 0x9c, 0x31, 0x3e, 0x7e, 0x97, 0x90, 0x7e,
+ 0xb3, 0x97, 0xc8, 0x4b, 0x8e, 0xb9, 0x72, 0xe0, 0xe9, 0x0d, 0x96, 0xb6,
+ 0x19, 0x1b, 0xe4, 0x99, 0xdd, 0x70, 0x2f, 0xa2, 0xd7, 0xca, 0xba, 0x96,
+ 0x9a, 0x98, 0x25, 0xf0, 0x3e, 0x2d, 0xc9, 0xcc, 0x00, 0xee, 0xf3, 0x1c,
+ 0x7b, 0xbf, 0x4c, 0x3d, 0x38, 0x01, 0x5b, 0x6e, 0x2f, 0x74, 0x0e, 0xcf,
+ 0x9f, 0x99, 0xef, 0x70, 0x13, 0x86, 0x59, 0xfd, 0xdd, 0x29, 0xfa, 0x80,
+ 0xa4, 0x87, 0x04, 0x9e, 0x67, 0x6c, 0x5c, 0x29, 0x21, 0xf9, 0xc2, 0x05,
+ 0xf3, 0x6d, 0xcb, 0xc2, 0x4b, 0xb8, 0xbf, 0xde, 0x7a, 0x18, 0x3f, 0x64,
+ 0xd4, 0xdc, 0xd1, 0xd7, 0x92, 0xa4, 0xcb, 0x26, 0xc7, 0xa5, 0x1a, 0x37,
+ 0x99, 0x91, 0xc3, 0xda, 0x7e, 0x1e, 0xb2, 0xb9, 0x2d, 0xa9, 0xd1, 0x9c,
+ 0x18, 0x1b, 0xfa, 0x77, 0x60, 0x43, 0x7f, 0xb1, 0x92, 0xd6, 0xfb, 0x58,
+ 0xa7, 0x61, 0x43, 0x3f, 0x01, 0xdd, 0x43, 0x9d, 0x13, 0xb7, 0x3a, 0x67,
+ 0x4a, 0xdd, 0xa8, 0x75, 0xce, 0x37, 0xb5, 0xce, 0x79, 0xef, 0x1a, 0x9d,
+ 0x73, 0x48, 0x75, 0x97, 0xa8, 0x73, 0x86, 0xd5, 0x1e, 0x87, 0xf6, 0xe2,
+ 0xe6, 0x3a, 0x3a, 0xe7, 0x7d, 0xf2, 0x2e, 0xfb, 0xee, 0x1e, 0x79, 0xff,
+ 0x0e, 0xbd, 0x77, 0xe3, 0xce, 0x2a, 0x7e, 0x6b, 0xc9, 0xe8, 0xa0, 0xeb,
+ 0x54, 0xaf, 0xde, 0xf3, 0xfd, 0x46, 0x8d, 0xce, 0xe9, 0x52, 0x03, 0xce,
+ 0xb0, 0x6e, 0xc3, 0xd8, 0x04, 0x9f, 0x7d, 0x27, 0x3d, 0xda, 0x84, 0xe7,
+ 0x84, 0x44, 0x8e, 0x60, 0xee, 0xe6, 0x7b, 0x50, 0xca, 0xbc, 0x7b, 0xab,
+ 0x7d, 0xa7, 0xc2, 0xf2, 0xa8, 0x29, 0xef, 0xb6, 0xe5, 0x46, 0x57, 0x75,
+ 0xa9, 0x4e, 0xad, 0xab, 0xb6, 0x83, 0xa1, 0x66, 0xa1, 0x5f, 0x67, 0x8b,
+ 0xa1, 0xce, 0xe2, 0x6f, 0xc6, 0x9e, 0x19, 0xa3, 0x08, 0x63, 0xd8, 0x49,
+ 0xd4, 0xc1, 0x55, 0x0c, 0x6d, 0x4a, 0xfe, 0x86, 0xaf, 0x80, 0x6b, 0x1e,
+ 0x78, 0xbd, 0x19, 0xfc, 0xf3, 0x6f, 0x0a, 0x8c, 0x81, 0xb6, 0xcb, 0xd1,
+ 0xe9, 0xda, 0x77, 0x9d, 0xf2, 0x9e, 0xe9, 0x2d, 0xb2, 0xbf, 0xf4, 0x2d,
+ 0xf0, 0xc1, 0x56, 0x99, 0x2a, 0x15, 0xf4, 0x79, 0xf5, 0x4d, 0xfa, 0x3b,
+ 0x1e, 0xfc, 0xbe, 0x8d, 0x91, 0x91, 0x3b, 0x1d, 0x23, 0x23, 0xd3, 0xaa,
+ 0x6a, 0xb3, 0x86, 0x7d, 0xf2, 0xdb, 0x21, 0x23, 0xa5, 0x84, 0xfe, 0xc6,
+ 0xe9, 0x6c, 0xe5, 0x0a, 0xf9, 0xc2, 0x31, 0x75, 0xa7, 0xaa, 0x9e, 0xef,
+ 0xd5, 0x36, 0xeb, 0xdc, 0x0a, 0x9b, 0xf5, 0xaf, 0x64, 0xf1, 0xfd, 0x31,
+ 0xcc, 0x13, 0x34, 0x7c, 0xe5, 0xf7, 0xb8, 0x17, 0xda, 0x1e, 0x97, 0x0b,
+ 0x32, 0xa2, 0xf1, 0x47, 0x79, 0xda, 0x02, 0x39, 0xb8, 0xa4, 0xf5, 0xeb,
+ 0x66, 0xd0, 0x20, 0x65, 0xe9, 0xc7, 0xe4, 0x45, 0x2d, 0xcf, 0x36, 0x5b,
+ 0xdb, 0x75, 0x81, 0xb1, 0xd4, 0x23, 0xb4, 0x5d, 0xbf, 0x69, 0xcb, 0x59,
+ 0x96, 0x4a, 0x2c, 0x09, 0xf5, 0x5d, 0x1c, 0x32, 0x94, 0xf2, 0xf4, 0x8d,
+ 0xda, 0xae, 0x5f, 0xb3, 0x7d, 0x50, 0x7e, 0x1a, 0xd9, 0xbd, 0xdd, 0x59,
+ 0xb0, 0x65, 0x7c, 0x0e, 0xe3, 0xe9, 0x5e, 0x3a, 0x6b, 0xf9, 0x4c, 0x39,
+ 0x5f, 0xc2, 0xfb, 0x4d, 0x78, 0x4f, 0x3e, 0x3b, 0xad, 0xf9, 0x4c, 0xdb,
+ 0x27, 0x4e, 0xbf, 0xdd, 0x5f, 0x58, 0xde, 0x1b, 0xc8, 0x91, 0xcf, 0xd4,
+ 0x51, 0x77, 0xc1, 0xc8, 0x03, 0xe6, 0xa9, 0x7e, 0x1e, 0xba, 0x83, 0x6d,
+ 0x51, 0xfe, 0x70, 0x9a, 0xbe, 0x2d, 0xfc, 0x9f, 0x56, 0x3c, 0xb7, 0xe3,
+ 0x79, 0x56, 0xde, 0xbb, 0x37, 0xa6, 0xe7, 0x3d, 0x85, 0x79, 0x1c, 0x38,
+ 0x82, 0x39, 0x39, 0xc6, 0x76, 0x8e, 0x9e, 0x8a, 0x4a, 0xc3, 0x29, 0xf2,
+ 0x1d, 0xcf, 0xda, 0x04, 0xc1, 0xbe, 0x7e, 0xd2, 0x6d, 0xca, 0xdd, 0xa9,
+ 0xcf, 0x96, 0x6e, 0x4f, 0x44, 0x80, 0x93, 0x03, 0x58, 0x8f, 0xa9, 0x82,
+ 0xe7, 0x66, 0x1c, 0x2f, 0x81, 0x79, 0xc2, 0x06, 0xec, 0x86, 0x2d, 0xd8,
+ 0x0d, 0x3b, 0xb0, 0x1b, 0x76, 0xe0, 0x46, 0x39, 0x71, 0x15, 0x73, 0x4c,
+ 0x72, 0xd7, 0xc2, 0x2b, 0x97, 0xef, 0xe8, 0x38, 0x7d, 0xe3, 0xcd, 0x23,
+ 0xf0, 0xd9, 0xc5, 0x4d, 0x8d, 0x32, 0x0f, 0x7f, 0xc9, 0x6d, 0xbc, 0x79,
+ 0xa7, 0x74, 0x0f, 0xe2, 0xfd, 0xe0, 0x05, 0xe9, 0xb9, 0xf9, 0x56, 0xa7,
+ 0x71, 0x74, 0x04, 0x78, 0x4c, 0x3b, 0xa9, 0xc4, 0x98, 0xb3, 0x80, 0x71,
+ 0x32, 0xdb, 0x23, 0xc2, 0xb8, 0xe5, 0x02, 0x63, 0x11, 0x37, 0x77, 0x47,
+ 0xfa, 0x92, 0xe3, 0x4e, 0x6a, 0x54, 0x45, 0x52, 0xa3, 0x23, 0x4e, 0x58,
+ 0x8f, 0xdf, 0x48, 0x85, 0x9c, 0x01, 0xac, 0x07, 0x8a, 0xd3, 0xa0, 0xa7,
+ 0xff, 0x28, 0xf9, 0x63, 0x2d, 0x32, 0x5f, 0xe8, 0x76, 0x33, 0x2a, 0xae,
+ 0x73, 0x4b, 0xd4, 0x09, 0x10, 0xfd, 0xa9, 0x98, 0xcc, 0x96, 0xb6, 0x8a,
+ 0xd2, 0xb6, 0x7b, 0x87, 0x64, 0xa6, 0x4b, 0x72, 0x6e, 0x40, 0xda, 0x14,
+ 0xfa, 0xe7, 0xb7, 0x67, 0xd5, 0x09, 0xee, 0x25, 0x86, 0xbc, 0x70, 0x39,
+ 0xf9, 0xa4, 0x04, 0x1c, 0x82, 0x6e, 0x19, 0xe3, 0x6d, 0x12, 0xca, 0xbd,
+ 0x8f, 0xea, 0xf8, 0x29, 0x63, 0xb6, 0xb5, 0x7b, 0x0f, 0xe4, 0x8f, 0x58,
+ 0x5d, 0xfe, 0x98, 0x2b, 0x72, 0x9f, 0x46, 0x72, 0x51, 0xc6, 0x88, 0x3d,
+ 0xfc, 0x9e, 0x61, 0xdd, 0x26, 0x99, 0x1a, 0xc8, 0xd9, 0x3c, 0x8f, 0x47,
+ 0x12, 0xcc, 0x21, 0x26, 0x4e, 0xc6, 0x07, 0xc8, 0xeb, 0xab, 0xf7, 0x36,
+ 0x62, 0x35, 0xf2, 0xc0, 0x91, 0xc5, 0x52, 0xb8, 0x17, 0xc2, 0xfe, 0xf0,
+ 0x3c, 0x63, 0xe4, 0x6d, 0x66, 0x4d, 0x3b, 0xc2, 0xc5, 0xfd, 0xca, 0x95,
+ 0x32, 0x56, 0x79, 0x94, 0xa9, 0xae, 0x96, 0xaf, 0x8f, 0x55, 0x8c, 0x6c,
+ 0x9d, 0xa9, 0x84, 0xba, 0x25, 0x66, 0x74, 0xe9, 0x1a, 0x7d, 0x62, 0xa2,
+ 0x99, 0x55, 0x7d, 0x42, 0xbd, 0xa8, 0xe4, 0x03, 0xf3, 0x1d, 0x12, 0x7d,
+ 0x58, 0x96, 0xa6, 0xbc, 0xec, 0xe5, 0xcc, 0xd5, 0x98, 0xf2, 0xdf, 0x8c,
+ 0x7e, 0xfc, 0x6f, 0x09, 0xea, 0xc3, 0x31, 0xf5, 0x75, 0xdc, 0x37, 0x69,
+ 0xfa, 0x03, 0x4f, 0xe1, 0xd9, 0xf8, 0x09, 0xbf, 0x03, 0x3f, 0xe1, 0x8b,
+ 0xd0, 0x75, 0x67, 0xe0, 0x27, 0x3c, 0x09, 0x3f, 0xe1, 0x34, 0xfc, 0x84,
+ 0x27, 0xa0, 0x27, 0x6b, 0xfd, 0x83, 0xc9, 0x15, 0xfe, 0x41, 0xa0, 0xf9,
+ 0x9f, 0xf1, 0xc0, 0x27, 0x6b, 0x7c, 0x83, 0x7d, 0x46, 0x5f, 0xc1, 0xef,
+ 0x37, 0x7c, 0xd4, 0xa5, 0x6e, 0xd2, 0xfa, 0xd1, 0xe4, 0xed, 0x8e, 0x2e,
+ 0xeb, 0xab, 0x2e, 0x65, 0xf4, 0xd5, 0x6c, 0x55, 0x5f, 0x19, 0x3e, 0x7a,
+ 0xb8, 0x24, 0x11, 0xaf, 0xb4, 0x90, 0xf1, 0x77, 0x69, 0x1e, 0x6a, 0xf3,
+ 0xb6, 0x4a, 0xe4, 0x01, 0xd5, 0xde, 0x20, 0x19, 0xfb, 0x0c, 0xfa, 0x3a,
+ 0x3a, 0x8d, 0xbe, 0xae, 0x95, 0xac, 0xb6, 0xcf, 0x2e, 0x8e, 0xef, 0x27,
+ 0x56, 0xe1, 0x3b, 0x5f, 0xbc, 0x5b, 0xe3, 0xfc, 0xfe, 0x32, 0xf7, 0x59,
+ 0x5a, 0x64, 0xb2, 0x1c, 0xe2, 0x9c, 0xe7, 0x59, 0x99, 0x8b, 0xd1, 0x29,
+ 0x91, 0x87, 0x3b, 0x78, 0xce, 0x4a, 0x65, 0xfd, 0xf5, 0x3a, 0x87, 0xe5,
+ 0xc4, 0x80, 0x24, 0xb2, 0x03, 0xa4, 0xd5, 0xfb, 0x64, 0x56, 0xaf, 0x45,
+ 0x87, 0x34, 0x3c, 0x4c, 0x1b, 0x25, 0xdc, 0xcf, 0xeb, 0xba, 0xcc, 0x7e,
+ 0x23, 0x35, 0x66, 0xea, 0x89, 0x1c, 0xd4, 0xeb, 0x75, 0x5c, 0xe7, 0x19,
+ 0xde, 0x34, 0xcf, 0xb8, 0x3c, 0xbf, 0x47, 0xc5, 0x98, 0xfc, 0x3f, 0x67,
+ 0xfd, 0x7e, 0xe1, 0x32, 0x63, 0xcf, 0x6c, 0xb2, 0x76, 0x8c, 0x89, 0x53,
+ 0xd5, 0xb7, 0x61, 0xd8, 0x4f, 0xed, 0x37, 0x14, 0xb7, 0x38, 0x93, 0xa5,
+ 0xad, 0x4e, 0xbe, 0xc4, 0xbd, 0x6c, 0xfb, 0xf7, 0x2e, 0xdc, 0x3d, 0xce,
+ 0x01, 0x6f, 0x0b, 0xca, 0x18, 0xb3, 0x64, 0xcc, 0xe6, 0x97, 0x2e, 0x63,
+ 0x8c, 0x36, 0xe3, 0x71, 0x6c, 0x96, 0x6d, 0x71, 0xa6, 0x4a, 0xdd, 0xf0,
+ 0xcd, 0x79, 0xae, 0x8a, 0xef, 0x77, 0x72, 0xed, 0xa0, 0x83, 0x5d, 0x7d,
+ 0x66, 0x77, 0x42, 0xae, 0xb0, 0x31, 0x68, 0xea, 0xe1, 0x9f, 0x5f, 0xb1,
+ 0x77, 0x7b, 0x08, 0x7a, 0xec, 0x16, 0xc8, 0x23, 0xea, 0xe1, 0x43, 0x72,
+ 0xb5, 0xa5, 0xe7, 0x95, 0x7a, 0xf8, 0xbc, 0x30, 0x4e, 0xdc, 0x8f, 0x77,
+ 0xb9, 0x20, 0x06, 0x7a, 0x38, 0x5c, 0xe3, 0xab, 0xd1, 0xef, 0x6b, 0x1a,
+ 0x32, 0xfb, 0x61, 0x2b, 0xfd, 0x3e, 0xc8, 0x81, 0x78, 0xe8, 0xe7, 0x35,
+ 0x2e, 0xef, 0xd7, 0xee, 0xb1, 0x6d, 0xa7, 0xfc, 0xfb, 0x89, 0xa3, 0xe4,
+ 0x21, 0xe9, 0x81, 0x2e, 0x63, 0x0e, 0xc8, 0x6f, 0x69, 0x9c, 0x89, 0x22,
+ 0xed, 0x6d, 0xd2, 0x30, 0x5a, 0x39, 0x9f, 0x0c, 0x73, 0x38, 0xf2, 0xb6,
+ 0xed, 0x84, 0xdd, 0x93, 0xcf, 0xcb, 0xdc, 0x65, 0xd4, 0x83, 0x23, 0x91,
+ 0xf5, 0xfc, 0x7e, 0x22, 0xda, 0xf6, 0x18, 0xbd, 0x28, 0x61, 0x5f, 0x7c,
+ 0x6e, 0xa8, 0xe9, 0x9b, 0x76, 0x14, 0xef, 0xab, 0xcf, 0x91, 0x3d, 0xa3,
+ 0xf7, 0x19, 0xcd, 0xf7, 0x12, 0x42, 0x3e, 0x21, 0xef, 0x24, 0xf5, 0x59,
+ 0x27, 0xef, 0x61, 0xda, 0x3d, 0xdc, 0x83, 0x75, 0x17, 0x26, 0xfd, 0x4f,
+ 0xe8, 0x6f, 0xfc, 0xcd, 0x88, 0x38, 0x79, 0xff, 0x36, 0x9d, 0x7b, 0x92,
+ 0xd7, 0xb1, 0xe6, 0x1c, 0xee, 0x55, 0x1f, 0xb5, 0xeb, 0x61, 0xfe, 0x4d,
+ 0x0b, 0x96, 0x65, 0x01, 0x1b, 0x75, 0x08, 0x65, 0x6f, 0x5c, 0xba, 0x8e,
+ 0x7e, 0x58, 0xf3, 0xc2, 0x66, 0xf8, 0x02, 0xc3, 0x47, 0xa1, 0xab, 0x8f,
+ 0x26, 0x64, 0xe7, 0x51, 0xad, 0x1b, 0xd3, 0x6b, 0x63, 0x05, 0x7d, 0x6e,
+ 0xd4, 0x79, 0x8f, 0x3e, 0xc7, 0xf6, 0xd6, 0xa3, 0x11, 0x39, 0x1c, 0xef,
+ 0x73, 0x7b, 0x9c, 0xf7, 0x5a, 0x5d, 0x18, 0xc6, 0xb0, 0x5b, 0xd0, 0xfe,
+ 0xf5, 0xe2, 0xd8, 0x61, 0xfc, 0x3a, 0x22, 0x33, 0x7b, 0x3b, 0x01, 0xdb,
+ 0x5f, 0x5d, 0x66, 0xce, 0x20, 0x63, 0xad, 0xf4, 0xb7, 0xe7, 0xa3, 0x09,
+ 0xca, 0xb2, 0x2e, 0xc0, 0x32, 0x72, 0x94, 0xfa, 0xcc, 0xd3, 0x3c, 0x0e,
+ 0x18, 0xdc, 0x06, 0xed, 0x87, 0x90, 0x2f, 0xdf, 0x22, 0xde, 0x03, 0x90,
+ 0x71, 0x47, 0x63, 0xd2, 0x73, 0xb4, 0x45, 0xb6, 0x1d, 0xa5, 0x1f, 0x52,
+ 0xeb, 0x97, 0xd2, 0x2e, 0x7d, 0x04, 0x73, 0x7c, 0xb7, 0x96, 0x93, 0xdc,
+ 0xd3, 0xdc, 0x4f, 0xde, 0x45, 0xdd, 0x2c, 0x6c, 0xe6, 0xcc, 0x51, 0x57,
+ 0xef, 0x91, 0x66, 0x30, 0xe7, 0x6c, 0xd9, 0xc5, 0x38, 0x46, 0xe6, 0xe4,
+ 0xe9, 0xa7, 0x8c, 0x76, 0x00, 0xc7, 0xef, 0xb5, 0xbc, 0xb3, 0xbe, 0xc3,
+ 0xf2, 0xe8, 0xcf, 0xc8, 0x7b, 0x5b, 0x3a, 0x8c, 0xec, 0x7c, 0x4b, 0x07,
+ 0x73, 0x93, 0x36, 0x7b, 0xbc, 0x37, 0x69, 0x7b, 0xc2, 0xc8, 0xd0, 0xd7,
+ 0xe2, 0x45, 0x01, 0x8e, 0xc2, 0x7d, 0x29, 0x7d, 0x96, 0x2f, 0x38, 0xe7,
+ 0xeb, 0xf3, 0x2b, 0xfe, 0xa2, 0xfe, 0x3b, 0x21, 0xdc, 0x23, 0xab, 0x7e,
+ 0x6f, 0x65, 0x57, 0x85, 0x71, 0xf2, 0xcf, 0x86, 0x7f, 0x97, 0xa4, 0x26,
+ 0xef, 0xb0, 0x76, 0x0f, 0x8c, 0xb1, 0xa6, 0xe5, 0xdc, 0xa0, 0xa0, 0xa4,
+ 0xbf, 0x5f, 0xf4, 0x9c, 0x73, 0xbe, 0x70, 0xd6, 0xf9, 0xee, 0xb4, 0x04,
+ 0x51, 0xef, 0x27, 0xce, 0xf7, 0x3d, 0xee, 0x99, 0x7f, 0xdd, 0xf9, 0x5e,
+ 0xc1, 0x03, 0x1f, 0xde, 0x87, 0x79, 0xbc, 0xe2, 0xfc, 0x00, 0xeb, 0x7b,
+ 0xb0, 0x98, 0x4e, 0xb9, 0x36, 0x26, 0x7e, 0xb6, 0xf0, 0x8a, 0xf3, 0xb5,
+ 0x6a, 0x3c, 0x69, 0x30, 0xa4, 0x91, 0x43, 0x7c, 0x57, 0xc6, 0xbb, 0xb2,
+ 0xde, 0xff, 0x71, 0xe6, 0xa6, 0x6d, 0x7e, 0x89, 0xe6, 0xe3, 0x85, 0xe5,
+ 0x7d, 0x99, 0x51, 0xbd, 0x57, 0xf1, 0xac, 0x33, 0x37, 0x7f, 0x77, 0x87,
+ 0xc9, 0x33, 0x3a, 0x8b, 0x77, 0x26, 0xe7, 0x72, 0x76, 0xfe, 0x2c, 0xea,
+ 0x3c, 0xe3, 0xcc, 0xea, 0xf8, 0x97, 0xf6, 0xc5, 0x9d, 0x99, 0xf9, 0x67,
+ 0x9c, 0x79, 0xbd, 0x07, 0x7d, 0xce, 0x79, 0x74, 0x9a, 0x7d, 0x9f, 0x43,
+ 0x9d, 0x05, 0xe7, 0x04, 0xfa, 0x9b, 0x9f, 0xe6, 0x79, 0xdc, 0x6e, 0xd8,
+ 0x05, 0xfc, 0x7b, 0x3f, 0xfc, 0x1e, 0xc7, 0xb3, 0xce, 0xfc, 0x72, 0xbf,
+ 0x8b, 0xe8, 0x87, 0x75, 0x49, 0x8b, 0x1c, 0xf7, 0x59, 0xf4, 0xbf, 0x76,
+ 0xaf, 0x6a, 0x2d, 0x4e, 0x5e, 0x00, 0x4e, 0x2e, 0x58, 0x9c, 0xbc, 0x6a,
+ 0x71, 0xf2, 0x7c, 0x0d, 0x4e, 0x44, 0xad, 0xc4, 0xc9, 0xab, 0xc0, 0x89,
+ 0xa8, 0xfa, 0x38, 0xc1, 0xbb, 0x32, 0xde, 0x69, 0x9c, 0xbc, 0xb4, 0x0a,
+ 0x27, 0x4b, 0xcb, 0x71, 0x79, 0x83, 0x93, 0x17, 0x81, 0x93, 0xaf, 0x5a,
+ 0xd8, 0x2f, 0x58, 0x9c, 0xe0, 0x3e, 0x7f, 0x01, 0x75, 0x5e, 0xaa, 0xc1,
+ 0xc9, 0x05, 0xe0, 0xe4, 0x25, 0x8b, 0x93, 0xef, 0x5b, 0x9c, 0x7c, 0x1f,
+ 0x75, 0x96, 0x80, 0x93, 0xf3, 0x75, 0x70, 0xf2, 0x22, 0x70, 0x12, 0xf6,
+ 0x7b, 0x1e, 0xfd, 0x7c, 0xbf, 0x06, 0x27, 0x2f, 0xd6, 0xc1, 0x09, 0xf7,
+ 0x62, 0xc3, 0x9c, 0xee, 0x99, 0xd7, 0xc9, 0xe9, 0x96, 0x3b, 0x5f, 0x3f,
+ 0xa7, 0x9b, 0x75, 0x66, 0xa4, 0xfa, 0x37, 0x25, 0xee, 0xb6, 0x39, 0x6a,
+ 0x26, 0x17, 0xb0, 0xfa, 0xcd, 0xa6, 0x6e, 0xf0, 0x79, 0x3e, 0xe7, 0x8a,
+ 0xc9, 0x29, 0x8d, 0xee, 0xf8, 0x10, 0x78, 0x6d, 0x97, 0x1c, 0x38, 0xd6,
+ 0x78, 0x38, 0x6b, 0xcb, 0xbc, 0x1d, 0xdd, 0x39, 0xa5, 0xf8, 0x2e, 0xcc,
+ 0x49, 0xa0, 0x5f, 0xd2, 0xc0, 0x6f, 0x0b, 0xf6, 0xa6, 0xa5, 0x76, 0x4f,
+ 0xba, 0xc0, 0x6f, 0x34, 0x61, 0xec, 0x25, 0xfe, 0xfd, 0x8b, 0x24, 0xf3,
+ 0xac, 0xf2, 0x1a, 0xde, 0x14, 0xf4, 0xc7, 0xa0, 0xce, 0xad, 0xca, 0x14,
+ 0x68, 0x73, 0x27, 0x99, 0xa3, 0x06, 0x5b, 0x79, 0xc8, 0x9e, 0x09, 0xf3,
+ 0xf5, 0x39, 0x95, 0x2a, 0xff, 0xd4, 0x9e, 0x87, 0x26, 0xdf, 0x55, 0xe9,
+ 0xe6, 0xe0, 0xf2, 0x77, 0x02, 0x4f, 0xca, 0xd3, 0x3a, 0x56, 0xdc, 0x8c,
+ 0xf5, 0x09, 0x82, 0xc7, 0x7c, 0x13, 0xa3, 0x5d, 0xd4, 0x31, 0x5a, 0x81,
+ 0x37, 0x3e, 0x69, 0xe3, 0xb4, 0x3d, 0x83, 0x2f, 0x2d, 0xc7, 0x68, 0x6b,
+ 0xf3, 0x59, 0xcc, 0xfe, 0x7a, 0xa6, 0xf4, 0x88, 0xce, 0xd1, 0x19, 0xe1,
+ 0xf7, 0x37, 0x20, 0x23, 0x26, 0x66, 0xe6, 0x65, 0xf2, 0x41, 0x3e, 0x53,
+ 0xbf, 0x45, 0xa0, 0xc3, 0x28, 0xc3, 0x73, 0x92, 0x19, 0x64, 0x99, 0x69,
+ 0x33, 0xa2, 0xfd, 0xe5, 0x93, 0x32, 0xbc, 0x3c, 0x3e, 0xf1, 0x7b, 0x57,
+ 0xcd, 0x77, 0xab, 0x69, 0xf3, 0xa4, 0x9d, 0x4c, 0x85, 0xef, 0xc3, 0x3d,
+ 0xf2, 0xbb, 0xec, 0xb7, 0xb3, 0xf8, 0xbe, 0xf6, 0x5b, 0xad, 0x5a, 0x74,
+ 0xe0, 0x37, 0xbf, 0x87, 0x36, 0xe5, 0x8c, 0xa0, 0xcd, 0x82, 0xdb, 0x32,
+ 0xaa, 0x86, 0x6e, 0x18, 0xe5, 0xb9, 0xb9, 0xd9, 0x35, 0xdf, 0xba, 0xae,
+ 0xea, 0xc5, 0xbc, 0x5e, 0x53, 0xe6, 0x67, 0xdd, 0x05, 0x5a, 0xd4, 0xb4,
+ 0xa5, 0xe9, 0xff, 0xc0, 0xb2, 0xbe, 0xa4, 0x9e, 0x35, 0xdf, 0x9e, 0x31,
+ 0xfa, 0x32, 0x95, 0x18, 0xc1, 0xf8, 0xfa, 0x6f, 0x2a, 0xd8, 0x73, 0xbd,
+ 0xd9, 0xf9, 0xdb, 0xb5, 0xae, 0x9f, 0xf2, 0xd3, 0xc9, 0xa8, 0xd4, 0xa9,
+ 0x5b, 0xaa, 0xa9, 0xab, 0xe7, 0xed, 0xca, 0x7f, 0xc5, 0xda, 0x7c, 0xbe,
+ 0x58, 0x96, 0xe1, 0xe9, 0xbf, 0x84, 0xff, 0x98, 0x90, 0xdf, 0x2e, 0x96,
+ 0x40, 0xaf, 0xb9, 0xcd, 0xf6, 0x5b, 0x4d, 0x19, 0xc0, 0xcd, 0x6f, 0xaf,
+ 0xe8, 0x7c, 0xe2, 0xc8, 0x17, 0x40, 0x17, 0x9f, 0x2b, 0x71, 0x0c, 0xc0,
+ 0x12, 0x81, 0x6d, 0x0f, 0x3b, 0x61, 0xa6, 0xa4, 0x73, 0xe7, 0xae, 0x2b,
+ 0x97, 0x74, 0xcc, 0x62, 0x67, 0xb9, 0x53, 0x76, 0x95, 0x5b, 0x64, 0x37,
+ 0xf4, 0xc2, 0xee, 0xb2, 0x87, 0x2b, 0x26, 0xef, 0x2e, 0x9b, 0x75, 0xfa,
+ 0x58, 0x99, 0xeb, 0xbd, 0x43, 0x66, 0x8f, 0xad, 0xfe, 0x3e, 0xe7, 0x42,
+ 0x2e, 0xfc, 0x3b, 0x4b, 0x4a, 0x31, 0xbf, 0x8c, 0xb4, 0x84, 0xab, 0x98,
+ 0x3a, 0xbc, 0xa0, 0xf1, 0xc0, 0x0c, 0xd7, 0x54, 0x69, 0x49, 0x98, 0xa7,
+ 0xcf, 0xbf, 0xad, 0x34, 0x73, 0x39, 0xcf, 0x4d, 0xf3, 0x5b, 0x5e, 0x3b,
+ 0x2b, 0x61, 0xde, 0x78, 0xbd, 0x9c, 0x71, 0xd8, 0xf9, 0x3b, 0xc2, 0x1c,
+ 0xbf, 0x18, 0x73, 0xc6, 0xa5, 0xeb, 0x54, 0x0b, 0xee, 0xa7, 0x2f, 0xd7,
+ 0x67, 0x9b, 0x4f, 0x89, 0x2d, 0xd3, 0xf9, 0xe4, 0x78, 0x5e, 0xfd, 0x7d,
+ 0xb5, 0x90, 0x1f, 0xaa, 0x7f, 0xa7, 0x40, 0xe4, 0xff, 0x02, 0xfb, 0x2e,
+ 0x88, 0x71, 0xec, 0x6e, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_CP_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_CP_b09FwRodata[(0x118/4) + 1] = {
+ 0x0800061c, 0x0800083c, 0x08000780, 0x080007a8, 0x080007d0, 0x080007f8,
+ 0x08000654, 0x08000640, 0x08000864, 0x08000864, 0x08000670, 0x0800068c,
+ 0x0800068c, 0x08000864, 0x080006a4, 0x080006b8, 0x08000864, 0x080006cc,
+ 0x08000864, 0x08000864, 0x080006e0, 0x08000864, 0x08000864, 0x08000864,
+ 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864, 0x08000864,
+ 0x08000864, 0x080006f4, 0x08000864, 0x08000708, 0x0800071c, 0x08000730,
+ 0x08000864, 0x08000744, 0x08000758, 0x0800076c, 0x08003200, 0x08003218,
+ 0x08003228, 0x08003238, 0x08003250, 0x08003268, 0x08003278, 0x08003288,
+ 0x080032a8, 0x080032b8, 0x080032c8, 0x08003358, 0x08003298, 0x080032d8,
+ 0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338,
+ 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc,
+ 0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 };
+static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 };
+static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 };
static struct fw_info bnx2_cp_fw_09 = {
- .ver_major = 0x1,
- .ver_minor = 0x0,
- .ver_fix = 0x0,
+ .ver_major = 0x3,
+ .ver_minor = 0x4,
+ .ver_fix = 0x3,
.start_addr = 0x0800006c,
.text_addr = 0x08000000,
- .text_len = 0x73cc,
+ .text_len = 0x6ee8,
.text_index = 0x0,
.gz_text = bnx2_CP_b09FwText,
.gz_text_len = sizeof(bnx2_CP_b09FwText),
- .data_addr = 0x08007500,
- .data_len = 0x50,
+ .data_addr = 0x08007020,
+ .data_len = 0x0,
.data_index = 0x0,
.data = bnx2_CP_b09FwData,
- .sbss_addr = 0x08007554,
- .sbss_len = 0xe9,
+ .sbss_addr = 0x08007024,
+ .sbss_len = 0xa1,
.sbss_index = 0x0,
.sbss = bnx2_CP_b09FwSbss,
- .bss_addr = 0x08007640,
- .bss_len = 0x870,
+ .bss_addr = 0x080070d0,
+ .bss_len = 0x3b0,
.bss_index = 0x0,
.bss = bnx2_CP_b09FwBss,
- .rodata_addr = 0x080073d0,
+ .rodata_addr = 0x08006ee8,
.rodata_len = 0x118,
.rodata_index = 0x0,
.rodata = bnx2_CP_b09FwRodata,
};
static u8 bnx2_RXP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x19, 0xfd, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6b, 0x6c,
- 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x20, 0xb5, 0xa2, 0xf8, 0x18, 0x2e, 0x57,
- 0xcc, 0x4a, 0x66, 0xec, 0x5d, 0x71, 0x24, 0xb2, 0x16, 0x6b, 0x8c, 0xd8,
- 0xad, 0x4d, 0x04, 0x6b, 0x7b, 0x33, 0xbb, 0x92, 0x98, 0x54, 0x85, 0x29,
- 0x87, 0x75, 0x0c, 0xc3, 0x75, 0xd9, 0xa5, 0x1a, 0xbb, 0xae, 0x51, 0xc8,
- 0x8f, 0xc4, 0x06, 0x6a, 0xd6, 0x9b, 0x25, 0xdd, 0xa8, 0xe9, 0x82, 0x43,
- 0x4b, 0xaa, 0xe9, 0x02, 0x69, 0xbb, 0x20, 0xa9, 0xc7, 0x8f, 0x85, 0x56,
- 0x76, 0x52, 0xc7, 0xf9, 0xe1, 0x48, 0x50, 0x95, 0x20, 0x28, 0x0c, 0x43,
- 0x48, 0x8d, 0xd6, 0x3f, 0xda, 0x40, 0x95, 0x9f, 0x68, 0x92, 0x42, 0x41,
- 0x0b, 0xc7, 0x68, 0x6c, 0x4f, 0xbf, 0xef, 0xce, 0x0c, 0xb9, 0xa4, 0x5f,
- 0x40, 0x7f, 0xf4, 0x4f, 0xe7, 0x02, 0x8b, 0xb9, 0xf7, 0xce, 0x3d, 0xe7,
- 0x9e, 0x7b, 0xde, 0xe7, 0x0e, 0xa5, 0xdf, 0xef, 0x94, 0x0e, 0x09, 0x5b,
- 0x17, 0x7e, 0x99, 0xc3, 0x8f, 0x3d, 0x74, 0xc3, 0xd8, 0x0d, 0xa3, 0x22,
- 0x7b, 0xf6, 0x18, 0x5b, 0x12, 0x7a, 0x34, 0x1f, 0xb7, 0xb8, 0xc5, 0x2d,
- 0x6e, 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e,
- 0x71, 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71,
- 0x8b, 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b,
- 0x5b, 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b,
- 0xdc, 0xe2, 0x16, 0xb7, 0xb8, 0xc5, 0x2d, 0x6e, 0x71, 0x8b, 0x5b, 0xdc,
- 0xe2, 0xf6, 0xff, 0xbd, 0x19, 0x22, 0x16, 0x9f, 0x5d, 0xe1, 0x4f, 0x12,
- 0x7a, 0xfe, 0xf2, 0x1f, 0xba, 0xb6, 0x24, 0x8c, 0xfc, 0xcf, 0x66, 0xa6,
- 0x6d, 0x91, 0x42, 0x63, 0x77, 0xa6, 0x28, 0xef, 0xfb, 0x95, 0x94, 0x29,
- 0x9c, 0xff, 0x6c, 0xfe, 0xbd, 0xbf, 0x7d, 0xf1, 0xa6, 0xec, 0xd5, 0xba,
- 0x21, 0x09, 0x2b, 0x3f, 0xb7, 0xc7, 0xda, 0x25, 0x89, 0x01, 0xc0, 0x7c,
- 0x6b, 0xe8, 0xc7, 0xdd, 0xd2, 0x2d, 0x6b, 0x78, 0xec, 0x84, 0x5c, 0x36,
- 0x5e, 0xd0, 0xdc, 0xa6, 0xef, 0x9f, 0x70, 0x7c, 0xff, 0x87, 0xf8, 0xbd,
- 0xe5, 0x60, 0xec, 0x7d, 0xe0, 0x17, 0x4c, 0x43, 0x74, 0xfb, 0x2f, 0x34,
- 0x77, 0xb9, 0x43, 0xaa, 0x8b, 0xa6, 0xcc, 0x7a, 0x29, 0x39, 0xe2, 0x55,
- 0xb4, 0x52, 0xb3, 0xa6, 0xed, 0x3d, 0x35, 0xaf, 0xed, 0x3b, 0x75, 0x44,
- 0xdb, 0x7f, 0x6a, 0x41, 0x73, 0x4f, 0x49, 0x45, 0xdf, 0xd3, 0x29, 0x05,
- 0xeb, 0xb4, 0x56, 0x6c, 0xf6, 0x6b, 0xee, 0xe2, 0x7b, 0xbe, 0xeb, 0x64,
- 0xad, 0xbb, 0xc4, 0x2c, 0x80, 0x16, 0x71, 0x6b, 0x3e, 0xc6, 0xa6, 0x14,
- 0x52, 0xbe, 0xaf, 0xe7, 0xfd, 0x27, 0xdc, 0x9c, 0x6d, 0xe9, 0x5a, 0x4a,
- 0xaa, 0xcd, 0x7e, 0xe0, 0xed, 0xd4, 0x8a, 0x8b, 0xa6, 0x56, 0xf2, 0xfc,
- 0x73, 0xae, 0x23, 0x03, 0x86, 0xf8, 0xfe, 0x9c, 0xb3, 0x33, 0x7d, 0x48,
- 0x4e, 0x02, 0x6f, 0x03, 0xf8, 0xc4, 0xd2, 0xf3, 0xa4, 0x8f, 0x74, 0x92,
- 0xe4, 0x8a, 0x56, 0x1c, 0x8a, 0xe8, 0x93, 0x0c, 0xe9, 0x2f, 0xaf, 0xe8,
- 0xa0, 0x73, 0x8b, 0x94, 0xeb, 0x96, 0x4c, 0xad, 0x6c, 0x5c, 0x7f, 0xd9,
- 0x7f, 0x71, 0x28, 0x25, 0xcf, 0x36, 0xb3, 0x47, 0x2a, 0x92, 0x90, 0x39,
- 0x2f, 0x23, 0x7a, 0x5e, 0x0a, 0x6e, 0x6e, 0x40, 0xce, 0x35, 0xd3, 0xf2,
- 0x5c, 0xd3, 0x4e, 0x57, 0x65, 0x93, 0x94, 0x53, 0x96, 0x9c, 0x6d, 0xa6,
- 0x70, 0x46, 0xff, 0x9c, 0x6e, 0xdb, 0x56, 0x15, 0x6b, 0xab, 0xcd, 0x97,
- 0xf8, 0xef, 0x5f, 0xac, 0xe9, 0x9c, 0x82, 0xa9, 0x80, 0xee, 0x70, 0x2d,
- 0xcf, 0xa1, 0xd6, 0xaa, 0xb3, 0x04, 0x6b, 0xa5, 0x32, 0x9d, 0xc3, 0x5c,
- 0x73, 0x34, 0xe4, 0xef, 0x16, 0x9c, 0x97, 0x4f, 0x4b, 0xaa, 0x9e, 0x01,
- 0xde, 0xb0, 0xff, 0xcf, 0xc0, 0x37, 0x80, 0xf3, 0x5e, 0xab, 0x7e, 0xee,
- 0xa2, 0xa4, 0x74, 0xd9, 0x99, 0x2e, 0x0b, 0x78, 0xdb, 0xec, 0xc4, 0x98,
- 0xf4, 0xf9, 0xfe, 0x7e, 0x47, 0xac, 0xaa, 0xd3, 0x03, 0x98, 0x8c, 0x54,
- 0x9d, 0x6e, 0xe0, 0x69, 0x13, 0xcb, 0xe6, 0xb9, 0xb8, 0xd7, 0x66, 0xcc,
- 0xfb, 0x5d, 0x46, 0xde, 0xf7, 0xa7, 0x73, 0xd2, 0x1d, 0xcc, 0xed, 0x56,
- 0x38, 0xa6, 0x26, 0x34, 0xac, 0xfb, 0x05, 0x69, 0x4e, 0x24, 0xf3, 0xec,
- 0xf3, 0x99, 0x13, 0x77, 0xfe, 0xda, 0x90, 0x96, 0x34, 0x68, 0xb9, 0x26,
- 0xec, 0x83, 0xff, 0x1e, 0xf8, 0xe0, 0x7c, 0x06, 0x63, 0xed, 0x3a, 0xe0,
- 0x19, 0xae, 0x0a, 0xf7, 0xe8, 0x93, 0xa5, 0x94, 0xe8, 0x57, 0x9c, 0xde,
- 0x70, 0x5d, 0x37, 0x68, 0x8d, 0xf4, 0xa0, 0x5f, 0xe6, 0x16, 0xc9, 0xeb,
- 0x1a, 0x64, 0x83, 0xe7, 0x8d, 0x15, 0xad, 0xd0, 0x3c, 0x82, 0xbe, 0x29,
- 0xd3, 0xb6, 0x7f, 0x6e, 0xce, 0x99, 0xd7, 0x8a, 0xa7, 0x4e, 0x6a, 0xa5,
- 0x53, 0x2f, 0x68, 0x7b, 0x9b, 0x2f, 0x74, 0x49, 0x47, 0x16, 0xa7, 0x4e,
- 0xc8, 0x93, 0x9e, 0x26, 0xa4, 0x73, 0x09, 0xbc, 0x2b, 0x58, 0x15, 0x31,
- 0xed, 0x6e, 0x6d, 0x1f, 0xf0, 0xb4, 0xd9, 0x7f, 0xd2, 0x29, 0xdd, 0x86,
- 0x6c, 0xb2, 0xa3, 0xb5, 0x29, 0xf9, 0x33, 0xd0, 0x74, 0xc1, 0x49, 0x91,
- 0x5f, 0x3d, 0x01, 0x4c, 0x44, 0x07, 0xf5, 0x8a, 0x3a, 0xa5, 0x17, 0x4a,
- 0xc7, 0xff, 0xbc, 0xaf, 0x3a, 0xb2, 0x85, 0x6b, 0xa0, 0xff, 0xd6, 0xfd,
- 0xd3, 0xb6, 0xdb, 0x6b, 0x4a, 0xc5, 0xd2, 0x25, 0x6b, 0x15, 0xe5, 0x3a,
- 0x99, 0x73, 0x44, 0x8a, 0x35, 0xec, 0x69, 0x9b, 0xe0, 0x8d, 0x0d, 0xde,
- 0xec, 0x3c, 0x32, 0xa8, 0xff, 0x96, 0x64, 0xfa, 0x2b, 0x9a, 0x19, 0xf2,
- 0x71, 0x49, 0x6e, 0x51, 0xf0, 0x7a, 0xde, 0x81, 0x7e, 0x76, 0xb0, 0x8f,
- 0x7d, 0x13, 0x6a, 0x5f, 0x23, 0x6f, 0xa7, 0x97, 0x45, 0x34, 0x3d, 0xbf,
- 0x1b, 0xf8, 0xa8, 0xb7, 0x5c, 0xf7, 0x04, 0x68, 0x24, 0xed, 0xec, 0xdb,
- 0x80, 0x49, 0x88, 0xeb, 0x74, 0xb5, 0xd0, 0x49, 0x79, 0x93, 0xd7, 0xe4,
- 0x9d, 0x3a, 0xa7, 0xb6, 0x76, 0xce, 0x5f, 0xf9, 0x9b, 0x46, 0x4d, 0xf9,
- 0xa1, 0x3a, 0x2f, 0x6d, 0x8c, 0xeb, 0x52, 0xa1, 0x4e, 0x24, 0xa0, 0x47,
- 0xa2, 0x95, 0x1d, 0x6b, 0x15, 0x57, 0x59, 0x44, 0x37, 0xf2, 0x9d, 0x52,
- 0x54, 0xf4, 0x8d, 0x61, 0x2f, 0xda, 0x1e, 0x6c, 0xc8, 0xe6, 0x59, 0x38,
- 0x97, 0x87, 0x8d, 0x67, 0xd9, 0x97, 0xf2, 0x02, 0xed, 0x9d, 0xb4, 0x9d,
- 0xcf, 0xaa, 0x7f, 0x8e, 0x45, 0x5d, 0x3c, 0xd6, 0x03, 0xda, 0x38, 0x86,
- 0x1d, 0xda, 0x78, 0x3f, 0xa2, 0x89, 0x3b, 0x36, 0x08, 0xfe, 0x70, 0x9d,
- 0x9d, 0x81, 0x9c, 0x0b, 0x2e, 0xf6, 0x74, 0x9d, 0xdf, 0x50, 0x3c, 0xe8,
- 0xc5, 0x79, 0x06, 0xe7, 0xc9, 0xaf, 0x0e, 0xe8, 0xb6, 0x26, 0x65, 0x27,
- 0x9b, 0xa1, 0xdc, 0x03, 0xda, 0x75, 0xd9, 0x74, 0x63, 0x2b, 0xed, 0x91,
- 0xac, 0xa8, 0x87, 0xa6, 0x24, 0x47, 0xb9, 0x96, 0xeb, 0xb8, 0x3e, 0x3b,
- 0x26, 0xfa, 0xaf, 0x7c, 0x6b, 0xdd, 0x59, 0x6d, 0xd9, 0x31, 0x0f, 0x1a,
- 0x02, 0xde, 0x82, 0x27, 0x9f, 0xb6, 0x96, 0x7c, 0xdd, 0xc8, 0x3f, 0xae,
- 0x6d, 0x5d, 0x07, 0x9d, 0xe8, 0x27, 0x0d, 0x27, 0x3a, 0x03, 0x5b, 0x8b,
- 0x68, 0x8a, 0x64, 0xa3, 0x85, 0x38, 0x3e, 0xe9, 0x1c, 0x5c, 0x0f, 0x1f,
- 0xe0, 0xc1, 0x07, 0xc0, 0xaf, 0x3d, 0xeb, 0xc1, 0xfe, 0x3d, 0xfa, 0x8c,
- 0x8c, 0xbc, 0x38, 0x04, 0x1f, 0xb7, 0xe6, 0x63, 0xd0, 0xc6, 0xd1, 0xd7,
- 0xc5, 0x80, 0x8f, 0x99, 0xad, 0xeb, 0xb0, 0x59, 0xf0, 0x78, 0x85, 0x73,
- 0xb0, 0xed, 0x95, 0x12, 0x9e, 0xb6, 0x54, 0x1b, 0xd4, 0xab, 0xc8, 0x97,
- 0xd2, 0xe7, 0xa4, 0xe1, 0x5f, 0xe8, 0x77, 0xe8, 0x57, 0xb8, 0xd6, 0xf7,
- 0x4b, 0x0e, 0x61, 0x7d, 0x99, 0x70, 0x68, 0x43, 0x9d, 0xa2, 0x27, 0x2b,
- 0xda, 0xc1, 0x21, 0xd8, 0xd6, 0xf5, 0x6d, 0xa0, 0x95, 0x36, 0x76, 0x8d,
- 0x48, 0x3b, 0xf7, 0xfb, 0x69, 0x57, 0xf0, 0xef, 0xee, 0x36, 0x61, 0x0d,
- 0x9f, 0xef, 0x86, 0x63, 0x2d, 0xf4, 0x2d, 0x7c, 0x9f, 0xcd, 0x14, 0xa4,
- 0x3f, 0x1c, 0xb3, 0xbf, 0x4a, 0xaf, 0xa3, 0xdf, 0x98, 0x90, 0x1d, 0x27,
- 0x03, 0x9f, 0xb8, 0x63, 0xc9, 0x12, 0xfb, 0x64, 0x40, 0xe3, 0x8e, 0x33,
- 0x91, 0x6f, 0x7c, 0x1f, 0xf0, 0xa0, 0xcf, 0x5b, 0x8d, 0x03, 0x68, 0x3f,
- 0xd3, 0x60, 0x2a, 0x98, 0xdb, 0xc8, 0x0b, 0xfa, 0x63, 0xda, 0x9b, 0xd5,
- 0x6a, 0x6f, 0x7b, 0x60, 0x6f, 0x4e, 0xbb, 0x64, 0x9d, 0xbf, 0x87, 0xbd,
- 0x7d, 0xc3, 0xd1, 0xc0, 0x1b, 0x91, 0x8b, 0xb5, 0x34, 0x6c, 0xdd, 0x4c,
- 0xbf, 0x26, 0x3b, 0x33, 0xb3, 0xa2, 0xc9, 0x09, 0xce, 0x35, 0x30, 0xa7,
- 0x7c, 0x71, 0xe0, 0x0b, 0x2e, 0x1b, 0x4f, 0x81, 0x2e, 0xdf, 0x9f, 0x05,
- 0xce, 0xf2, 0x88, 0x11, 0xda, 0x56, 0x34, 0x6f, 0xdd, 0xef, 0xda, 0xee,
- 0xaf, 0x19, 0x52, 0x19, 0x6e, 0x93, 0xec, 0xf0, 0x12, 0x70, 0x4f, 0x3b,
- 0x81, 0x1d, 0x53, 0xd7, 0x97, 0x81, 0x7f, 0xce, 0x1b, 0x82, 0x1e, 0xd3,
- 0x0e, 0x40, 0x17, 0xf0, 0x2f, 0x03, 0xff, 0x5c, 0xb3, 0x4d, 0xbe, 0x6e,
- 0x46, 0xb1, 0x32, 0x3a, 0x4f, 0x37, 0x96, 0x45, 0xfb, 0x1e, 0x96, 0x2f,
- 0x7a, 0x49, 0xcd, 0x3d, 0x46, 0xff, 0x5a, 0x1d, 0x86, 0x9d, 0x68, 0x55,
- 0x87, 0x7b, 0x1b, 0xb2, 0xbc, 0xba, 0x46, 0x0a, 0xd5, 0xc0, 0x06, 0x0b,
- 0xee, 0x50, 0x25, 0x6d, 0x28, 0x5f, 0x22, 0xb2, 0x0f, 0xb6, 0xb7, 0x6c,
- 0x73, 0xcc, 0xf9, 0x60, 0x6e, 0xbc, 0xd6, 0x0f, 0x9f, 0xc8, 0xf1, 0x7b,
- 0xfe, 0xb4, 0x13, 0xcc, 0x7d, 0xa1, 0x76, 0x57, 0x37, 0xfd, 0x2e, 0xe2,
- 0x44, 0xa6, 0xea, 0xfc, 0xbb, 0x0f, 0xfd, 0x5d, 0x07, 0xf3, 0xd1, 0x78,
- 0xb2, 0xe3, 0x81, 0xce, 0x8a, 0xb6, 0xdf, 0xd6, 0xfb, 0xdb, 0x43, 0x1f,
- 0xb6, 0x1f, 0x93, 0x7b, 0x6b, 0xd5, 0xbe, 0x76, 0x79, 0xcf, 0x60, 0x1c,
- 0xbd, 0x22, 0x62, 0xba, 0xb5, 0x5d, 0xe0, 0x47, 0xb5, 0xb7, 0x65, 0x2e,
- 0x51, 0xaa, 0xf9, 0x72, 0xc1, 0x09, 0x60, 0x30, 0xee, 0x2c, 0xd6, 0xf4,
- 0xfe, 0x84, 0xac, 0x8e, 0x2d, 0xc2, 0xac, 0xc8, 0xae, 0xe1, 0x65, 0x51,
- 0xb0, 0x7d, 0x89, 0x35, 0xd8, 0x54, 0xa9, 0x56, 0xed, 0x6d, 0x19, 0xa7,
- 0x8b, 0xc0, 0xa5, 0xef, 0x59, 0x85, 0x1d, 0x58, 0x83, 0xdd, 0x2a, 0x99,
- 0x5e, 0xc2, 0xeb, 0xfd, 0x9b, 0xd7, 0x70, 0x67, 0x42, 0x7a, 0xfa, 0x36,
- 0xaf, 0xe1, 0xb0, 0x89, 0xb3, 0x65, 0x3c, 0x4c, 0x9c, 0x3b, 0xd6, 0x70,
- 0x8e, 0xac, 0xa7, 0xe7, 0xb0, 0xc0, 0x07, 0x25, 0xda, 0xf3, 0xb2, 0xe7,
- 0x62, 0x6d, 0x70, 0xe2, 0x8b, 0x82, 0x58, 0x37, 0xb2, 0x29, 0xf4, 0xc9,
- 0xe6, 0x1e, 0x17, 0xbc, 0x32, 0x85, 0x3e, 0x4e, 0x93, 0x2a, 0xe4, 0x7c,
- 0x7f, 0x43, 0xf6, 0x5c, 0x68, 0x98, 0xa1, 0x2e, 0x51, 0x27, 0xde, 0x86,
- 0x8d, 0x75, 0x4e, 0x99, 0x88, 0xc3, 0xe7, 0x94, 0x8d, 0xc9, 0x44, 0xb5,
- 0x26, 0x95, 0xed, 0xf9, 0x27, 0x7c, 0xe8, 0xe2, 0x94, 0x05, 0x3f, 0x5a,
- 0x94, 0xce, 0x31, 0x37, 0x87, 0xf9, 0x06, 0x6d, 0x0b, 0x7e, 0x05, 0xb0,
- 0xd0, 0xb5, 0x84, 0x31, 0xbf, 0xf3, 0x55, 0xd7, 0xe0, 0x3e, 0x19, 0xe4,
- 0x4d, 0x89, 0x84, 0x3e, 0x7f, 0xd5, 0xa7, 0x9e, 0x4d, 0x8f, 0x5c, 0x45,
- 0x9e, 0x62, 0xc1, 0x57, 0xc2, 0x7f, 0x40, 0xdf, 0x67, 0x9b, 0x82, 0xb8,
- 0xfe, 0x40, 0x4f, 0x60, 0x63, 0x47, 0xb7, 0x06, 0x4f, 0x31, 0xe9, 0x9b,
- 0xa7, 0x73, 0xcc, 0x01, 0xda, 0x13, 0x6e, 0x6e, 0x7c, 0x9b, 0x71, 0xe6,
- 0xc0, 0x36, 0xfd, 0x4c, 0x65, 0x9b, 0x0e, 0x9f, 0x0e, 0x9b, 0xd2, 0xdd,
- 0x1c, 0xfa, 0x67, 0x22, 0x1b, 0x4a, 0xc3, 0x86, 0xde, 0x56, 0x39, 0xc8,
- 0xb9, 0xe6, 0x29, 0xd8, 0xab, 0xa2, 0x55, 0x26, 0x90, 0x13, 0xe8, 0xa3,
- 0xef, 0x43, 0x4f, 0x70, 0x16, 0xf8, 0xc0, 0x02, 0xb8, 0xa4, 0x8f, 0xbe,
- 0x11, 0xda, 0x33, 0xfb, 0xef, 0xf8, 0x41, 0x7c, 0xf8, 0x7c, 0xb8, 0xff,
- 0x3f, 0x75, 0x07, 0x3e, 0x20, 0xc2, 0x45, 0x3c, 0xc3, 0xda, 0x04, 0xf2,
- 0x99, 0x89, 0xa6, 0xa9, 0xd1, 0x9f, 0x17, 0x3d, 0xe6, 0x21, 0xcc, 0x41,
- 0x1e, 0x0b, 0xfd, 0x22, 0x73, 0x8f, 0xce, 0x90, 0xa7, 0xb9, 0x28, 0xce,
- 0x29, 0x7b, 0x43, 0xcc, 0xc9, 0x94, 0x9d, 0x36, 0xe5, 0x93, 0xa7, 0x73,
- 0x9d, 0x58, 0x87, 0xb9, 0x26, 0xce, 0x0d, 0xbf, 0x84, 0x5c, 0x06, 0x6b,
- 0xce, 0x63, 0x7d, 0x7b, 0x68, 0xf3, 0x17, 0xa5, 0x0c, 0x9f, 0x6a, 0xda,
- 0x7c, 0x9f, 0xeb, 0x91, 0x0e, 0x8c, 0x1b, 0xd8, 0x0b, 0x7e, 0xc2, 0x50,
- 0x7c, 0x46, 0x2c, 0x48, 0x5d, 0xc7, 0x1c, 0x09, 0x6b, 0x33, 0x58, 0x4b,
- 0xbf, 0xcb, 0xb5, 0xcf, 0x82, 0x0e, 0x8c, 0x1b, 0x84, 0xa1, 0x8f, 0x12,
- 0xdf, 0xcd, 0x6d, 0x86, 0x26, 0xf9, 0xe7, 0x0c, 0x3b, 0x5a, 0x1b, 0xe1,
- 0xdd, 0xb8, 0x96, 0xf9, 0x09, 0x71, 0xf7, 0x84, 0xf1, 0x7f, 0x5c, 0x0a,
- 0xcd, 0x02, 0x7e, 0x22, 0xd3, 0xc7, 0x90, 0x8f, 0xd9, 0x6d, 0x88, 0x55,
- 0x9c, 0xdf, 0x6a, 0x05, 0x67, 0x8d, 0xe0, 0xee, 0xef, 0x5b, 0x3f, 0xfe,
- 0x42, 0x72, 0xcd, 0x47, 0xd2, 0xc2, 0xa4, 0x80, 0x18, 0x01, 0x5e, 0x65,
- 0xa6, 0x98, 0xc3, 0x15, 0x1b, 0x4a, 0xa6, 0x98, 0x1b, 0x83, 0x5f, 0x0c,
- 0xf2, 0xa2, 0x73, 0xde, 0x46, 0xd9, 0x59, 0xe0, 0x77, 0x01, 0x3c, 0xce,
- 0x40, 0x87, 0xc6, 0x01, 0x2b, 0x87, 0x81, 0x83, 0xf1, 0xd7, 0xd1, 0xf3,
- 0x49, 0x29, 0x5b, 0xcc, 0x13, 0xda, 0x49, 0x67, 0x81, 0xf6, 0xaf, 0xe7,
- 0x37, 0x63, 0x8e, 0xfd, 0x7b, 0x7b, 0x02, 0x99, 0x75, 0x71, 0x3c, 0xa1,
- 0xe7, 0x7b, 0x36, 0xcc, 0x7f, 0xbf, 0x2b, 0xa0, 0x4d, 0x8d, 0x31, 0xff,
- 0xf2, 0x86, 0xf1, 0xef, 0x25, 0xd7, 0x8f, 0xef, 0xda, 0x16, 0xea, 0x20,
- 0xfa, 0x8f, 0x85, 0xf4, 0x82, 0xb6, 0x55, 0x5a, 0xa3, 0x9c, 0x57, 0x16,
- 0x74, 0xe4, 0x7f, 0x6e, 0x6e, 0x27, 0x62, 0x7d, 0x46, 0x4a, 0x4d, 0xd0,
- 0xbd, 0x1a, 0xcb, 0x56, 0xd7, 0x54, 0xd6, 0xd6, 0x04, 0xbe, 0xbe, 0xd4,
- 0xf4, 0x91, 0x3b, 0xb5, 0xc6, 0xbd, 0x61, 0xf4, 0x2b, 0xd8, 0xa7, 0x20,
- 0xd3, 0xde, 0x85, 0x82, 0x6e, 0x1f, 0x09, 0xf2, 0x3e, 0xfb, 0x9b, 0x5a,
- 0x69, 0x99, 0xf9, 0x20, 0xec, 0xc9, 0x56, 0xf9, 0x3f, 0xe2, 0xca, 0x51,
- 0xad, 0x70, 0xea, 0x38, 0xf2, 0xc1, 0x15, 0xfc, 0x4e, 0xe3, 0xd7, 0xc0,
- 0x2f, 0xca, 0xc3, 0x9f, 0x41, 0x1e, 0xaf, 0x7c, 0x2c, 0xe2, 0x41, 0xb0,
- 0xff, 0x1b, 0x2b, 0xd0, 0xb3, 0xe3, 0x29, 0xf9, 0x86, 0xad, 0xf7, 0xe9,
- 0x81, 0x5f, 0x29, 0x20, 0x8f, 0xb5, 0xde, 0x96, 0xdf, 0x0e, 0xf3, 0x22,
- 0x91, 0xd7, 0x16, 0xc0, 0xc7, 0x91, 0xfd, 0xa1, 0xce, 0x16, 0xee, 0x75,
- 0x95, 0xff, 0x0c, 0xf3, 0x1e, 0xe4, 0x5f, 0x05, 0xb5, 0xea, 0x5b, 0xe0,
- 0x8d, 0x26, 0x6f, 0x41, 0x87, 0x5e, 0x5b, 0xe8, 0x00, 0x3d, 0xb6, 0x94,
- 0x27, 0x91, 0x2f, 0x68, 0x83, 0xd6, 0x26, 0xad, 0x03, 0x76, 0x0c, 0x1b,
- 0x57, 0x63, 0x49, 0xb4, 0xe5, 0x2f, 0xcd, 0x2c, 0xd5, 0x74, 0xac, 0x45,
- 0xee, 0x93, 0x43, 0x1f, 0xb2, 0xbf, 0xb2, 0x40, 0x38, 0x5d, 0x5e, 0x5f,
- 0x30, 0xe4, 0x4d, 0xe4, 0x52, 0x6f, 0xd9, 0x97, 0x66, 0x10, 0xb7, 0xfa,
- 0x11, 0x23, 0x50, 0x8b, 0xec, 0xa4, 0x9f, 0xde, 0x61, 0xe2, 0x59, 0xc2,
- 0x6f, 0x1f, 0x72, 0xc1, 0x8f, 0x86, 0xf9, 0xb8, 0xf5, 0xa4, 0x2d, 0x01,
- 0x18, 0xae, 0x37, 0x41, 0x5b, 0x37, 0xe4, 0x9f, 0xb5, 0xa6, 0xe4, 0xf5,
- 0x1e, 0x95, 0xaf, 0x68, 0x9c, 0x0f, 0x7c, 0xd3, 0x87, 0xe7, 0xc9, 0x67,
- 0x03, 0x3a, 0xce, 0x31, 0xdf, 0xd1, 0x87, 0x12, 0x5f, 0x76, 0xac, 0x80,
- 0xc3, 0x5c, 0x59, 0x08, 0xfa, 0xd1, 0x9c, 0x68, 0x51, 0x1c, 0xa3, 0x6f,
- 0x2c, 0xc1, 0x4e, 0x38, 0x9e, 0x10, 0x25, 0x83, 0x75, 0xf2, 0x94, 0x84,
- 0x99, 0x3f, 0x3b, 0x33, 0x67, 0x53, 0xae, 0xf0, 0x71, 0xb5, 0x48, 0xae,
- 0x94, 0x51, 0xbb, 0x54, 0x17, 0xbe, 0x09, 0xb9, 0xea, 0x61, 0xbe, 0x0f,
- 0x1b, 0x3f, 0x4e, 0xf9, 0xa2, 0xfe, 0x5b, 0x40, 0xee, 0xb3, 0x20, 0xc9,
- 0xa0, 0x5e, 0x39, 0x8a, 0x3c, 0x1f, 0xf2, 0xab, 0x1d, 0x07, 0x0e, 0xd8,
- 0x69, 0x6d, 0x05, 0x4f, 0xd4, 0x16, 0xb5, 0xd3, 0x78, 0x0e, 0xe0, 0xd9,
- 0xa0, 0x6e, 0x86, 0xb9, 0xc6, 0x87, 0xe8, 0x81, 0x3d, 0x95, 0x68, 0x4f,
- 0xf2, 0xfd, 0x66, 0x5e, 0xbe, 0xdb, 0x1c, 0x93, 0xe7, 0x9b, 0x39, 0xf9,
- 0xbb, 0xa6, 0x23, 0xdf, 0x69, 0x8e, 0xc8, 0xb7, 0x9b, 0xc3, 0xac, 0xc9,
- 0x90, 0x37, 0x65, 0x98, 0x37, 0xc9, 0xbd, 0xde, 0xad, 0xb0, 0x77, 0xca,
- 0xff, 0xd2, 0x4c, 0xa1, 0x31, 0x28, 0xe5, 0x63, 0xf0, 0xcf, 0xce, 0xcd,
- 0xac, 0x25, 0xe5, 0x11, 0x87, 0x35, 0x41, 0x1b, 0xdf, 0xa3, 0xce, 0x84,
- 0xff, 0x86, 0x3f, 0x9b, 0x4a, 0x65, 0x4f, 0xbb, 0x46, 0x47, 0xe8, 0x03,
- 0x6e, 0x49, 0x4a, 0x07, 0xf6, 0x82, 0x0f, 0x5c, 0x7a, 0x1a, 0x36, 0xa0,
- 0x6a, 0x9a, 0x04, 0xfc, 0x0d, 0x73, 0x01, 0x93, 0x76, 0x8c, 0x3a, 0x30,
- 0x9b, 0x71, 0x0d, 0xd6, 0x77, 0xb4, 0x67, 0x03, 0x81, 0x83, 0x70, 0xfb,
- 0x2c, 0xca, 0xcd, 0xb4, 0xe9, 0x57, 0x0b, 0xa1, 0x8f, 0x4b, 0x84, 0x7a,
- 0x69, 0x61, 0xfe, 0xf1, 0xd0, 0x27, 0x6f, 0xdc, 0x07, 0xf1, 0x02, 0xf9,
- 0x64, 0xb0, 0x8e, 0xb0, 0x5a, 0x08, 0xdb, 0x17, 0xce, 0x75, 0x82, 0xdf,
- 0x8e, 0x94, 0xbd, 0x37, 0x35, 0xe6, 0xd9, 0xc8, 0x77, 0x30, 0x1e, 0xc1,
- 0xf8, 0x4a, 0x38, 0xfe, 0x9c, 0x4c, 0x2f, 0x0a, 0x68, 0xfd, 0x89, 0x56,
- 0x54, 0xe3, 0x31, 0x8c, 0x75, 0x8c, 0x0d, 0xd6, 0x02, 0x68, 0x37, 0x27,
- 0xa9, 0xeb, 0xba, 0x4d, 0x5f, 0x38, 0x19, 0xfa, 0xc3, 0x82, 0x1c, 0xf6,
- 0x06, 0x0b, 0x57, 0x11, 0x33, 0xb4, 0xb6, 0x28, 0xff, 0xd9, 0x0e, 0xbe,
- 0xf8, 0xfe, 0xed, 0xac, 0xb9, 0x93, 0xa6, 0x7c, 0x7b, 0x3e, 0x6b, 0x3d,
- 0xa4, 0x7f, 0x0d, 0x67, 0xf2, 0xfd, 0x83, 0x76, 0xf6, 0xc8, 0x94, 0xde,
- 0x25, 0xdf, 0x3d, 0xca, 0xd8, 0x7b, 0x76, 0xe6, 0x07, 0xd0, 0xbd, 0xfa,
- 0x4a, 0xbb, 0xd4, 0xeb, 0xa6, 0x5c, 0x19, 0x1d, 0x04, 0x9d, 0x96, 0xd4,
- 0x1b, 0x49, 0xe4, 0x73, 0x9b, 0x65, 0xb6, 0x5f, 0x19, 0x18, 0xfc, 0xf4,
- 0xb0, 0xf2, 0xd3, 0xae, 0x8d, 0x67, 0xe3, 0xe7, 0x3d, 0xeb, 0xcf, 0x5c,
- 0x02, 0xfd, 0xd0, 0xeb, 0xe4, 0x76, 0x25, 0xe7, 0xb2, 0x37, 0x68, 0x95,
- 0x75, 0xc4, 0x2e, 0x73, 0xd0, 0xba, 0x57, 0xff, 0x2f, 0xff, 0xf3, 0x26,
- 0x65, 0xf7, 0xaa, 0xaa, 0x61, 0x54, 0xac, 0xc3, 0x7e, 0x4b, 0x2b, 0x2f,
- 0x83, 0x16, 0xf8, 0xd8, 0xc6, 0xf6, 0x70, 0x9c, 0x51, 0xbc, 0x38, 0xdb,
- 0xe8, 0x90, 0xef, 0xd4, 0xb7, 0xc8, 0x72, 0x9d, 0xef, 0xdb, 0x65, 0xa9,
- 0x3e, 0x78, 0xb5, 0x4f, 0xef, 0x97, 0xf3, 0xd7, 0x5c, 0x6f, 0xdd, 0xa3,
- 0x23, 0x37, 0x98, 0xfc, 0x40, 0x7e, 0x39, 0xda, 0x23, 0x3f, 0xfe, 0x72,
- 0xf6, 0x99, 0x3f, 0xd5, 0x61, 0x03, 0xa3, 0x9d, 0xb4, 0x6d, 0xf4, 0x39,
- 0x9f, 0xbd, 0x5a, 0xd0, 0xa9, 0xdb, 0x3f, 0x02, 0x4f, 0xb3, 0x0b, 0x81,
- 0x1d, 0x10, 0x37, 0xf1, 0x42, 0x37, 0xec, 0xef, 0x01, 0x27, 0xde, 0x35,
- 0x06, 0x81, 0xeb, 0x7b, 0x8a, 0x17, 0xb7, 0x3b, 0xd9, 0xab, 0x08, 0x49,
- 0xfe, 0x15, 0x7b, 0x70, 0x78, 0x87, 0xbe, 0x5d, 0xea, 0xe9, 0xeb, 0xad,
- 0xe7, 0xe0, 0xff, 0x0b, 0xa9, 0xec, 0x91, 0xcb, 0x72, 0x76, 0xe6, 0xa2,
- 0x4d, 0xfd, 0xa7, 0xdf, 0x78, 0x09, 0xb9, 0xa7, 0x25, 0x0b, 0x0d, 0xfa,
- 0x4b, 0xe2, 0x62, 0xfe, 0xbf, 0xcb, 0x3a, 0xac, 0x33, 0x4f, 0xc0, 0x3b,
- 0xcc, 0x1b, 0xbf, 0x4e, 0x39, 0xb7, 0x11, 0x76, 0xb8, 0xa0, 0xff, 0x62,
- 0x03, 0x8f, 0x06, 0xad, 0xbd, 0x3a, 0xf7, 0xfb, 0x37, 0xec, 0xfb, 0x0e,
- 0x68, 0x1d, 0x04, 0x2c, 0x62, 0x66, 0xba, 0x75, 0x8f, 0x57, 0xd4, 0x1e,
- 0xc7, 0x1a, 0xc8, 0xf5, 0x56, 0xf7, 0xc0, 0x5c, 0x43, 0xc7, 0x39, 0x4d,
- 0x25, 0x97, 0x2b, 0xa3, 0xe4, 0xef, 0x9e, 0x5e, 0xe6, 0x99, 0x46, 0xfe,
- 0xaf, 0xfd, 0xa8, 0x7e, 0x7c, 0x7e, 0x7e, 0x12, 0xfe, 0xd9, 0xf7, 0x2f,
- 0xec, 0x1a, 0x04, 0x0d, 0xa8, 0x43, 0xd3, 0xe4, 0xf9, 0xd9, 0x19, 0x17,
- 0x38, 0x8a, 0x0a, 0xf7, 0x25, 0x59, 0x01, 0xee, 0x09, 0xf2, 0x01, 0xb8,
- 0xe7, 0x38, 0xaf, 0x64, 0x80, 0xf9, 0x46, 0x06, 0x78, 0x23, 0xfd, 0x4c,
- 0x42, 0xd7, 0x76, 0x5b, 0xb7, 0x07, 0xba, 0x9e, 0x60, 0x6c, 0x7b, 0x0e,
- 0xba, 0x57, 0x48, 0x52, 0x7f, 0xda, 0x7b, 0xd7, 0xf4, 0xa7, 0x15, 0x7f,
- 0xbb, 0x94, 0x16, 0x12, 0xc0, 0x6b, 0xca, 0x5c, 0x8e, 0x78, 0x31, 0xae,
- 0x53, 0xf7, 0x2b, 0xa1, 0xee, 0x77, 0x86, 0xb8, 0x17, 0xc1, 0x93, 0x6c,
- 0xa6, 0xae, 0xb3, 0x8e, 0xda, 0xa6, 0x6a, 0x5b, 0x03, 0x36, 0x5d, 0xae,
- 0xb1, 0x0e, 0xe5, 0xfd, 0xc8, 0xa5, 0x99, 0x69, 0xd4, 0xaa, 0xe5, 0xda,
- 0x88, 0x56, 0x6e, 0xda, 0x5a, 0xd9, 0xa3, 0xbe, 0xed, 0xb2, 0x2e, 0x28,
- 0x1e, 0xa7, 0x65, 0xa9, 0xf9, 0x4b, 0xbf, 0xba, 0x6b, 0x13, 0xfa, 0xd0,
- 0xfd, 0x09, 0xca, 0xf7, 0xb3, 0xa4, 0x0b, 0x41, 0x9c, 0xfc, 0x4e, 0xc9,
- 0xc9, 0x21, 0x14, 0xbd, 0xc8, 0xad, 0x4e, 0x0d, 0x11, 0x3f, 0xe8, 0x48,
- 0xa5, 0x64, 0xd9, 0xe3, 0x1e, 0x67, 0x67, 0xc8, 0xcb, 0xf2, 0x71, 0x4b,
- 0x0e, 0x2b, 0xf9, 0xbd, 0xac, 0x6c, 0xbb, 0xbc, 0x62, 0xc8, 0x74, 0x72,
- 0xd0, 0x7a, 0x58, 0xb2, 0x57, 0x2f, 0x18, 0xd9, 0x67, 0xa6, 0x60, 0xd7,
- 0x4b, 0x8b, 0x86, 0xb8, 0xaa, 0xde, 0xa2, 0x8c, 0xb2, 0x0b, 0xb0, 0xfc,
- 0xf0, 0xec, 0x7b, 0x5b, 0xce, 0xde, 0x2d, 0x2b, 0x4f, 0xff, 0x26, 0x7c,
- 0xce, 0x01, 0xc8, 0xc2, 0xcc, 0x1c, 0x42, 0x5e, 0xf1, 0xb4, 0x0c, 0x5a,
- 0x55, 0xe4, 0xc9, 0xe0, 0x3b, 0xda, 0x01, 0x65, 0x03, 0x17, 0x74, 0x8c,
- 0x07, 0xc8, 0x27, 0x8e, 0xaf, 0x95, 0x0b, 0xca, 0x96, 0xd2, 0xea, 0xdd,
- 0x0e, 0xe0, 0x08, 0xde, 0x71, 0xfc, 0x19, 0xd9, 0xa1, 0xde, 0xdd, 0xa9,
- 0xde, 0x55, 0xe9, 0x2b, 0x94, 0xfc, 0xbe, 0x82, 0x3d, 0xc9, 0xe3, 0x68,
- 0xbe, 0x4b, 0x02, 0x5b, 0x8a, 0xf8, 0x6e, 0xc9, 0xc1, 0x46, 0x4a, 0xbe,
- 0x84, 0xfa, 0xe7, 0x8e, 0xc6, 0x80, 0x94, 0x20, 0xc7, 0xe9, 0xdc, 0x83,
- 0xbd, 0x3c, 0x5b, 0x71, 0x25, 0xfb, 0x8c, 0xe8, 0xa4, 0xf5, 0x4e, 0x39,
- 0xe4, 0x45, 0xf4, 0x74, 0x86, 0xf4, 0x4d, 0x86, 0xe3, 0x44, 0x48, 0x43,
- 0x2b, 0xbe, 0x4e, 0xe0, 0x42, 0xac, 0xcf, 0x79, 0x21, 0x1e, 0xfa, 0x11,
- 0xd0, 0x3a, 0x99, 0x96, 0x15, 0x8f, 0x74, 0x6c, 0x91, 0x6a, 0x8a, 0xfd,
- 0x03, 0xd0, 0x37, 0xe2, 0xd9, 0xc4, 0x7c, 0x66, 0x1d, 0x8f, 0x1f, 0x6c,
- 0x54, 0xc0, 0x63, 0xf2, 0x97, 0xeb, 0x10, 0x23, 0x3e, 0x47, 0xf9, 0xed,
- 0x46, 0x2e, 0x6f, 0x07, 0xba, 0x69, 0xad, 0xed, 0x59, 0x3a, 0xde, 0x0d,
- 0x59, 0x71, 0xdf, 0x0e, 0x99, 0x84, 0xdd, 0x17, 0xeb, 0xdc, 0x7f, 0x12,
- 0x7a, 0x74, 0x51, 0xed, 0x5f, 0x5a, 0xe9, 0x0f, 0xe1, 0x09, 0xdb, 0xbd,
- 0x01, 0xb6, 0x5d, 0xf6, 0x2e, 0x58, 0x1f, 0x01, 0xff, 0xbb, 0x80, 0xd7,
- 0xe5, 0x44, 0x8e, 0xf0, 0xc4, 0x83, 0x75, 0xf5, 0xd4, 0x27, 0xe0, 0x49,
- 0xaa, 0xba, 0xbe, 0x58, 0x6f, 0x97, 0xe2, 0x42, 0x84, 0x8b, 0x78, 0x3e,
- 0x40, 0xdd, 0x7b, 0xb7, 0xc2, 0x35, 0xad, 0x70, 0xe1, 0x7d, 0x9d, 0x3e,
- 0xe7, 0x26, 0xc0, 0xa3, 0x76, 0xb7, 0x41, 0x5b, 0xb2, 0x4b, 0xaa, 0xaa,
- 0x76, 0xef, 0x50, 0xbe, 0xa6, 0x9a, 0xdc, 0x8c, 0xf7, 0x3e, 0xf6, 0xdc,
- 0x8d, 0x7c, 0xa6, 0x1b, 0x73, 0x99, 0x0d, 0x73, 0x1b, 0xe9, 0x4f, 0x6c,
- 0xa0, 0xff, 0xbf, 0x7b, 0x19, 0x52, 0xe6, 0x72, 0xc1, 0xba, 0x12, 0xd6,
- 0xcd, 0x1e, 0x87, 0x4d, 0x30, 0x4f, 0x4f, 0x31, 0x36, 0x5f, 0xa3, 0x68,
- 0x99, 0x5d, 0xf9, 0x29, 0xd6, 0xf5, 0x03, 0x36, 0x1a, 0x07, 0x7c, 0x78,
- 0x0a, 0x78, 0x8e, 0xd7, 0xd5, 0x1d, 0x05, 0x64, 0xf0, 0xbe, 0x3a, 0x7b,
- 0xb5, 0xfe, 0x69, 0x3c, 0xbb, 0xa6, 0x85, 0x5f, 0xe4, 0x15, 0xe9, 0x25,
- 0xad, 0xbc, 0x2f, 0x82, 0xbd, 0x39, 0xd0, 0xe3, 0xa4, 0x21, 0xa5, 0x1c,
- 0xe2, 0xba, 0xc7, 0xbb, 0x57, 0xda, 0xe5, 0x40, 0x50, 0x23, 0xd8, 0x8c,
- 0xef, 0xa6, 0x3a, 0xfb, 0xa1, 0x15, 0xde, 0xbf, 0x66, 0x78, 0x47, 0x37,
- 0x8c, 0xda, 0x5b, 0x1e, 0x5a, 0xb1, 0xe5, 0x6b, 0x8d, 0x61, 0x79, 0xb8,
- 0x91, 0xb5, 0xee, 0x81, 0x0f, 0x28, 0xaf, 0xde, 0xcb, 0x6e, 0x4b, 0xd2,
- 0x7f, 0x99, 0xc8, 0x3d, 0xdb, 0xec, 0x20, 0x17, 0xa9, 0xb2, 0x36, 0x3b,
- 0x9e, 0xe5, 0x7d, 0x8d, 0x55, 0x97, 0x8d, 0xf9, 0xca, 0xff, 0x65, 0xae,
- 0xc2, 0xfd, 0xe9, 0xaf, 0x91, 0x9b, 0x78, 0xc8, 0x4d, 0x3c, 0xe4, 0x26,
- 0x1e, 0x72, 0x13, 0x0f, 0xb9, 0x89, 0x87, 0xdc, 0xc4, 0x43, 0x6e, 0xe2,
- 0x21, 0x37, 0x41, 0x1d, 0x10, 0xd4, 0x07, 0xe3, 0xc8, 0xb9, 0xe1, 0xbf,
- 0xbc, 0x5b, 0xc2, 0xdc, 0x22, 0x8a, 0xcd, 0x9c, 0x3b, 0xbf, 0xc9, 0x0d,
- 0xea, 0x2b, 0xe5, 0x13, 0x0a, 0xcd, 0x89, 0x30, 0x07, 0xe2, 0x9a, 0x28,
- 0x76, 0x73, 0x9d, 0x8c, 0xb9, 0xa8, 0x3d, 0x0b, 0x93, 0xcc, 0x91, 0x82,
- 0x98, 0x15, 0xe4, 0xe7, 0xaf, 0x22, 0x4f, 0xca, 0x20, 0x4f, 0x1a, 0x40,
- 0x4e, 0xc4, 0x7b, 0xea, 0xe8, 0x2e, 0xa9, 0xa0, 0x1d, 0xf4, 0xc6, 0xb5,
- 0x2f, 0x79, 0xcc, 0xdf, 0xed, 0x4c, 0x59, 0xd7, 0x8f, 0xf7, 0x89, 0x2f,
- 0xc5, 0xd1, 0xaf, 0x23, 0x57, 0xfe, 0x4b, 0x75, 0x6f, 0x36, 0x31, 0x44,
- 0x99, 0xdf, 0xf7, 0x31, 0xf9, 0x72, 0xc4, 0xdf, 0xe0, 0xbe, 0x4f, 0x5f,
- 0x22, 0xff, 0x44, 0x7a, 0xcf, 0x80, 0xe1, 0x67, 0x12, 0x92, 0x3c, 0xb9,
- 0x05, 0x73, 0x96, 0xf4, 0xa9, 0x3b, 0x23, 0x88, 0xf2, 0xcc, 0x7f, 0x40,
- 0x5e, 0xb6, 0xe8, 0x67, 0x78, 0xb3, 0x40, 0xbc, 0xf4, 0xaf, 0xf5, 0x99,
- 0x62, 0xbd, 0xae, 0x74, 0xea, 0x60, 0xa3, 0x84, 0x3c, 0xca, 0xe8, 0x93,
- 0x0e, 0x13, 0xb5, 0x54, 0x84, 0x9b, 0x38, 0xdf, 0x4c, 0xaa, 0x1a, 0xe7,
- 0xcc, 0xaa, 0x3c, 0x21, 0x6b, 0xee, 0x53, 0x9f, 0xa9, 0x2e, 0x64, 0xd3,
- 0xac, 0x71, 0x0b, 0x56, 0x7d, 0xe6, 0x49, 0xe0, 0x58, 0x46, 0x6e, 0x60,
- 0xa8, 0xbd, 0xeb, 0x33, 0xb3, 0x0b, 0xc1, 0xbd, 0x55, 0x40, 0x03, 0xe3,
- 0x55, 0x87, 0x18, 0x4b, 0xc1, 0xfd, 0x95, 0xae, 0x60, 0x09, 0x47, 0x78,
- 0x13, 0x70, 0x94, 0xdb, 0x30, 0x60, 0x29, 0x3b, 0xd2, 0x50, 0x9f, 0xa9,
- 0xd4, 0x5b, 0x69, 0x20, 0x1e, 0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0x24, 0x45,
- 0x3f, 0xe9, 0xfb, 0xe5, 0xd1, 0x81, 0xb0, 0xae, 0x44, 0x1d, 0x79, 0xcc,
- 0x0c, 0xf4, 0x5c, 0x8d, 0xff, 0x58, 0xc5, 0xa9, 0x8c, 0xce, 0x79, 0x3e,
- 0xf1, 0x2e, 0xf7, 0x28, 0xe6, 0x30, 0x5e, 0x8e, 0xd6, 0xea, 0xe1, 0xda,
- 0xae, 0x16, 0x7e, 0xb6, 0x85, 0xfb, 0x91, 0x26, 0x9e, 0xf3, 0x15, 0xec,
- 0x45, 0xba, 0xb8, 0xc6, 0x04, 0x6d, 0x90, 0xa5, 0xf7, 0xbf, 0xe5, 0x7d,
- 0xeb, 0x99, 0xc8, 0x53, 0x13, 0x30, 0x5c, 0x4f, 0x1c, 0x11, 0x0c, 0x5e,
- 0x9c, 0x09, 0xe0, 0xf4, 0xd5, 0x7b, 0xbe, 0x4f, 0xda, 0xb7, 0x95, 0xd6,
- 0x68, 0xff, 0x08, 0xcf, 0x70, 0x20, 0xb7, 0x55, 0x78, 0xf5, 0x7f, 0x7f,
- 0xe1, 0x09, 0x5d, 0xfc, 0xd0, 0x7d, 0xe9, 0x70, 0x4b, 0x8d, 0x1c, 0xdd,
- 0x3b, 0xb0, 0xfe, 0x67, 0x3d, 0xcf, 0xef, 0x03, 0xad, 0xf5, 0x69, 0x29,
- 0x8c, 0x65, 0xdb, 0xa4, 0x60, 0xb2, 0x56, 0x19, 0x0f, 0xc7, 0x5b, 0x11,
- 0xdb, 0x38, 0xbe, 0x15, 0xfc, 0x85, 0x2e, 0x3b, 0x1d, 0x61, 0xad, 0x94,
- 0x0c, 0xbe, 0xeb, 0x0c, 0xd3, 0x8e, 0x58, 0x6b, 0x6e, 0x0e, 0xe7, 0x22,
- 0x3b, 0xa2, 0x1f, 0x36, 0xc3, 0x39, 0xfa, 0x5b, 0x1d, 0xf5, 0x12, 0xfb,
- 0xc0, 0xb3, 0xdc, 0x6a, 0x4b, 0xd1, 0x33, 0x29, 0xa7, 0x17, 0x23, 0xbf,
- 0x05, 0x9f, 0x32, 0x64, 0x86, 0xbe, 0xbf, 0x13, 0xbe, 0xaf, 0x5b, 0xf6,
- 0xc2, 0x67, 0xed, 0x83, 0xcf, 0xda, 0x8f, 0x1a, 0x75, 0x7c, 0xa5, 0xf5,
- 0x3e, 0x97, 0x75, 0x71, 0x55, 0x0e, 0x29, 0xf9, 0x57, 0x7c, 0xc3, 0xfe,
- 0x00, 0x3a, 0xb0, 0x53, 0xe5, 0x7b, 0x81, 0x4e, 0xc0, 0xdf, 0x3a, 0x49,
- 0xe8, 0xc4, 0xc6, 0x7b, 0xe3, 0x61, 0xd8, 0x46, 0x47, 0x41, 0xc5, 0x86,
- 0x95, 0x80, 0xf7, 0xd5, 0x7a, 0xc0, 0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5,
- 0xd2, 0xb0, 0xa4, 0x82, 0x7d, 0x2b, 0xd8, 0xb7, 0x82, 0xda, 0x72, 0xb6,
- 0xd1, 0xfa, 0xed, 0xaa, 0x2b, 0xa4, 0x9d, 0xb0, 0x51, 0xdf, 0x6a, 0x39,
- 0x7f, 0xf4, 0x3c, 0x02, 0xfe, 0x3f, 0x02, 0xfe, 0x1f, 0x46, 0x4d, 0xf5,
- 0x00, 0x6a, 0xaa, 0xfb, 0x50, 0x53, 0x1d, 0x42, 0x4d, 0x35, 0x85, 0x9a,
- 0xea, 0x6e, 0xf8, 0x8f, 0x3b, 0xe1, 0x3f, 0x26, 0xe1, 0x3f, 0x26, 0xd4,
- 0x9d, 0xd1, 0x41, 0x6f, 0xe3, 0x1d, 0x4a, 0xb4, 0x17, 0xdb, 0x1b, 0x22,
- 0x50, 0x81, 0xf2, 0xb1, 0x71, 0xa9, 0x37, 0x59, 0x5b, 0x39, 0xea, 0x3e,
- 0x6c, 0xda, 0x99, 0xd4, 0xa6, 0x90, 0xbf, 0xdf, 0x33, 0xc2, 0x9a, 0x2b,
- 0xa9, 0x15, 0x55, 0xcd, 0x95, 0x7d, 0xc1, 0x45, 0x8a, 0x84, 0xdc, 0x0f,
- 0x67, 0xce, 0x9e, 0x2e, 0x1a, 0x51, 0xbd, 0xd3, 0xbb, 0x5a, 0xef, 0x2c,
- 0xcf, 0xb3, 0xde, 0x79, 0x75, 0xb5, 0xde, 0x59, 0x9e, 0x67, 0xbd, 0xf3,
- 0xca, 0xba, 0x7a, 0xe7, 0xca, 0xd3, 0x97, 0xd6, 0xd5, 0x3b, 0x57, 0x9e,
- 0x7e, 0x29, 0x1c, 0x4b, 0xa8, 0x0f, 0x21, 0xad, 0x96, 0x83, 0x67, 0x4f,
- 0x98, 0x73, 0x34, 0xfb, 0xd6, 0xff, 0xdf, 0x74, 0xca, 0x96, 0x35, 0xb1,
- 0xff, 0x68, 0x6b, 0x50, 0x23, 0xb5, 0xce, 0x77, 0xb7, 0xcc, 0x5f, 0x56,
- 0xdf, 0x4b, 0xcb, 0xb5, 0xcd, 0xef, 0xc2, 0x03, 0xcb, 0xca, 0x10, 0xf3,
- 0xbc, 0x0f, 0x7c, 0x7e, 0xf3, 0x73, 0xf5, 0x0e, 0xf5, 0xcd, 0xcd, 0x55,
- 0xf9, 0x36, 0xec, 0x7c, 0xf4, 0xd1, 0xad, 0x81, 0x2f, 0x60, 0x3f, 0xa5,
- 0x05, 0xfe, 0xfd, 0x01, 0xe0, 0x01, 0xaf, 0x3d, 0x53, 0xdd, 0x07, 0x05,
- 0xe7, 0x0d, 0xee, 0xc6, 0xcd, 0xfc, 0xe5, 0x19, 0xe6, 0xd6, 0x55, 0x85,
- 0x9b, 0xf5, 0x23, 0x6b, 0xce, 0x28, 0x06, 0x44, 0xb8, 0x5e, 0x4d, 0x05,
- 0x74, 0xbb, 0xa8, 0x1d, 0xb9, 0x26, 0x1a, 0xb7, 0xd6, 0x9a, 0x9d, 0xe1,
- 0xbd, 0xdb, 0xe5, 0x20, 0xaf, 0x52, 0xf8, 0xcc, 0x10, 0xdf, 0xcf, 0xfd,
- 0xc0, 0xf7, 0x10, 0xde, 0x6a, 0x81, 0x1f, 0x47, 0xae, 0xc7, 0x7b, 0x1a,
- 0xe6, 0x6c, 0xa6, 0xbc, 0x33, 0xdf, 0x25, 0xff, 0x79, 0xd4, 0xf7, 0x27,
- 0x9c, 0xec, 0xf0, 0x25, 0xd4, 0x1e, 0x27, 0x69, 0x27, 0xa3, 0xa4, 0x73,
- 0x30, 0x33, 0x2b, 0xa9, 0x3e, 0xd2, 0x72, 0x5e, 0x3f, 0xac, 0x7d, 0x98,
- 0x6e, 0x3d, 0xdc, 0xe7, 0x1f, 0x5b, 0xf6, 0xc9, 0xb4, 0xec, 0x53, 0xa0,
- 0xcd, 0xd6, 0xef, 0xc0, 0x99, 0x2b, 0xdb, 0xaf, 0xb7, 0x52, 0x61, 0x5d,
- 0xf6, 0xf0, 0xe8, 0x66, 0x59, 0xe8, 0xcf, 0x9e, 0x7d, 0x05, 0xf9, 0x7a,
- 0x79, 0x14, 0x73, 0xa9, 0x41, 0xbc, 0xe3, 0x7c, 0xb6, 0x8e, 0x5c, 0xf4,
- 0x6c, 0x5d, 0xb6, 0x01, 0x3e, 0x5b, 0x11, 0xe1, 0x3c, 0xfb, 0x8a, 0xb6,
- 0x7a, 0xe8, 0x03, 0xd2, 0x17, 0x70, 0xe6, 0x29, 0xd4, 0x5f, 0x87, 0x83,
- 0x7b, 0xb4, 0x70, 0x9f, 0x1b, 0xb5, 0x20, 0x6f, 0xce, 0x69, 0x95, 0xf0,
- 0x0e, 0xf0, 0x2b, 0xf0, 0x17, 0x86, 0x4e, 0xd8, 0x77, 0x80, 0x5b, 0x93,
- 0xa5, 0xa3, 0x86, 0xba, 0x3b, 0x2d, 0x8f, 0x52, 0xd6, 0x7c, 0x7e, 0x14,
- 0xef, 0xa2, 0x33, 0xfd, 0x4d, 0x78, 0xa6, 0xd1, 0xb0, 0x6e, 0x8f, 0xce,
- 0x94, 0x90, 0xd7, 0xe7, 0x2d, 0xc0, 0x8e, 0x80, 0x1f, 0x25, 0x59, 0x69,
- 0x66, 0x3e, 0x05, 0x4f, 0xad, 0x85, 0x37, 0xe6, 0x06, 0x19, 0x46, 0x75,
- 0x0f, 0x78, 0x30, 0x91, 0x86, 0x1d, 0xde, 0xd7, 0x17, 0xdd, 0xe9, 0x1a,
- 0xb6, 0xae, 0x05, 0x75, 0x3c, 0xe7, 0x07, 0x60, 0x8b, 0x19, 0xd8, 0x27,
- 0x73, 0xa6, 0x12, 0x6b, 0x15, 0xda, 0x93, 0xe5, 0x1a, 0x59, 0x6b, 0x52,
- 0x86, 0x51, 0xef, 0xf0, 0xfc, 0x79, 0x59, 0x6e, 0x46, 0x34, 0xe4, 0x60,
- 0x8f, 0x63, 0xf8, 0x8d, 0xe0, 0x9d, 0x83, 0x1f, 0x6b, 0xa5, 0x82, 0x7c,
- 0x55, 0xe5, 0xe2, 0xc8, 0xb5, 0x87, 0x48, 0xdf, 0x01, 0xac, 0xa7, 0x3e,
- 0x53, 0x4f, 0x0f, 0x88, 0xdb, 0x4f, 0x5f, 0x91, 0x06, 0x6e, 0xc0, 0x78,
- 0xaf, 0xc1, 0xd6, 0x07, 0xf0, 0xcc, 0x5a, 0x65, 0xf2, 0x56, 0xe1, 0xf7,
- 0x7d, 0x23, 0xc7, 0x6f, 0x11, 0xe3, 0xe1, 0x78, 0xd0, 0xfa, 0x1d, 0xea,
- 0x5e, 0xfa, 0x5a, 0x39, 0xbb, 0x18, 0xc5, 0xc1, 0x19, 0xd8, 0x20, 0xef,
- 0x68, 0xc7, 0xc1, 0x17, 0x8e, 0xb5, 0x30, 0x1e, 0x62, 0x7e, 0xf9, 0xaf,
- 0x70, 0xee, 0xbc, 0x9c, 0x44, 0xfd, 0x2f, 0xfd, 0x7c, 0x66, 0x80, 0x7f,
- 0x4b, 0xa8, 0xef, 0xeb, 0xe1, 0x0d, 0x9b, 0xfd, 0x71, 0xd0, 0x67, 0xb6,
- 0xc0, 0x13, 0x26, 0xac, 0x4f, 0x04, 0xf1, 0x38, 0xed, 0xdf, 0xaa, 0xe7,
- 0xef, 0x96, 0x3f, 0x50, 0x67, 0xca, 0xcb, 0xa1, 0x45, 0xdf, 0x77, 0x73,
- 0x83, 0xc3, 0xcb, 0x92, 0x1d, 0x7e, 0x52, 0x76, 0x5b, 0x7b, 0x59, 0x8f,
- 0x59, 0xc4, 0xe3, 0xdf, 0xda, 0x96, 0xf7, 0xfd, 0x13, 0xa0, 0xfd, 0x07,
- 0x6a, 0x9f, 0xbb, 0x41, 0x3f, 0x78, 0xa5, 0x6a, 0x12, 0xd2, 0x0a, 0xde,
- 0xa4, 0x48, 0x6f, 0xa7, 0x1c, 0x6a, 0x3e, 0x1f, 0xca, 0xe6, 0x11, 0x71,
- 0xbd, 0xb7, 0x0d, 0xde, 0x6f, 0x97, 0x9b, 0x8f, 0x86, 0xb4, 0xe5, 0x41,
- 0x2f, 0xf6, 0x6f, 0xfe, 0x43, 0x8a, 0xbe, 0x81, 0x32, 0x77, 0x91, 0x35,
- 0xba, 0xa3, 0xcf, 0x40, 0x07, 0x3f, 0xce, 0x0f, 0x24, 0x65, 0xbd, 0x1f,
- 0x20, 0x5c, 0xf2, 0x23, 0x74, 0x85, 0x74, 0x88, 0xf2, 0x9f, 0x2a, 0x6e,
- 0x29, 0x7c, 0xc6, 0x06, 0x5f, 0xf0, 0xa4, 0x7a, 0x9e, 0x37, 0xe8, 0x9b,
- 0x18, 0xff, 0xa8, 0xc3, 0xdd, 0xf0, 0x7f, 0xd0, 0x41, 0xd8, 0x71, 0x71,
- 0x91, 0xf7, 0x13, 0x43, 0xea, 0x4e, 0xab, 0x04, 0xd9, 0x2e, 0xf1, 0x3b,
- 0x63, 0x2a, 0xc8, 0x27, 0x83, 0xfa, 0x2b, 0x43, 0x5f, 0x88, 0xf6, 0xb8,
- 0xf2, 0x93, 0x25, 0xf5, 0x5d, 0x31, 0x89, 0x35, 0x3e, 0x9e, 0xad, 0x7f,
- 0x27, 0xf1, 0xa3, 0x42, 0xf0, 0x77, 0x12, 0xe1, 0x37, 0xde, 0x7a, 0x90,
- 0x47, 0x3c, 0xd8, 0x30, 0x65, 0xaa, 0x11, 0xfd, 0xdd, 0x04, 0xe5, 0x60,
- 0x4b, 0xb9, 0x11, 0xe5, 0x0e, 0x7e, 0x50, 0xd3, 0xac, 0x93, 0xe5, 0xe3,
- 0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4, 0x78, 0x39, 0x90, 0xdf, 0x92,
- 0xbe, 0x03, 0xf2, 0x03, 0xcf, 0x3d, 0x13, 0xb6, 0x94, 0x0e, 0xe3, 0xba,
- 0xc5, 0x1a, 0x33, 0xac, 0x7b, 0xb7, 0x4b, 0x75, 0x92, 0xef, 0x13, 0xf2,
- 0xda, 0xfc, 0x40, 0x70, 0x4f, 0x24, 0x89, 0xf0, 0x3d, 0xc7, 0x49, 0x29,
- 0xab, 0xf7, 0x77, 0x86, 0xf8, 0x50, 0xa7, 0xdd, 0x19, 0x8d, 0xd3, 0x90,
- 0x63, 0x00, 0x37, 0x8d, 0x58, 0xf6, 0x55, 0xc4, 0xb1, 0x69, 0xf0, 0xbd,
- 0x38, 0x51, 0x91, 0x6b, 0x6d, 0x4b, 0xc5, 0x7d, 0x37, 0x49, 0x1d, 0xa3,
- 0x7e, 0x11, 0xa6, 0x07, 0xb9, 0x2a, 0xce, 0x3b, 0x2a, 0x53, 0x46, 0xfe,
- 0xdd, 0xdb, 0xca, 0xb5, 0xac, 0x55, 0x90, 0xf7, 0x7d, 0xd7, 0xe4, 0xf8,
- 0xfc, 0x6d, 0x0f, 0x06, 0x77, 0xfe, 0xba, 0x9e, 0xbf, 0x78, 0x5b, 0x39,
- 0xe8, 0xe3, 0xcc, 0xef, 0x86, 0x7d, 0xc2, 0x19, 0xea, 0x7b, 0xec, 0x4f,
- 0x6e, 0x32, 0xe5, 0xc2, 0x4d, 0xbe, 0x7f, 0x0f, 0xbf, 0x09, 0x85, 0x75,
- 0xac, 0xa5, 0xea, 0xd8, 0x0e, 0x95, 0x8f, 0xb8, 0xa3, 0x19, 0xad, 0x04,
- 0xdb, 0x3d, 0xe9, 0xa1, 0xe6, 0xd1, 0xb3, 0x63, 0xe7, 0x75, 0x0b, 0xf1,
- 0x37, 0x9b, 0x39, 0x2e, 0xb9, 0x3e, 0x7e, 0x63, 0x9e, 0x73, 0xb8, 0x66,
- 0x5b, 0x70, 0xef, 0x75, 0x83, 0xab, 0x7c, 0xae, 0x48, 0x18, 0x87, 0x6e,
- 0x68, 0xb5, 0x8f, 0xd6, 0x3c, 0x93, 0x76, 0x21, 0x53, 0x26, 0xe8, 0xa9,
- 0xd6, 0xa2, 0x9c, 0x8d, 0x7f, 0x0f, 0x70, 0xfe, 0xb6, 0xa7, 0x1a, 0x17,
- 0x6f, 0x9b, 0x85, 0x7c, 0x78, 0xa6, 0xd9, 0x46, 0xa4, 0x7f, 0x51, 0xdd,
- 0xc0, 0x3e, 0xe2, 0xbf, 0x87, 0xf8, 0xef, 0x21, 0xfe, 0x7b, 0x88, 0xff,
- 0x1e, 0xe2, 0xbf, 0x87, 0xf8, 0x0f, 0x1e, 0x3e, 0x07, 0x7d, 0x79, 0xd6,
- 0x9b, 0x08, 0x73, 0xb6, 0xc7, 0x56, 0x73, 0x36, 0xfe, 0xcd, 0xcb, 0xb9,
- 0xa6, 0xa2, 0xa5, 0x52, 0x91, 0x20, 0xe7, 0x15, 0x9d, 0xf9, 0x4d, 0x94,
- 0xf3, 0x7e, 0xf4, 0xf7, 0x90, 0x00, 0x8e, 0xf9, 0x1e, 0xe1, 0x2a, 0x9a,
- 0x6e, 0x13, 0x2e, 0xc8, 0xf9, 0x58, 0x67, 0xad, 0x87, 0xe1, 0x77, 0x37,
- 0xfa, 0xb6, 0xe0, 0x9b, 0x4f, 0xf0, 0x7d, 0xa9, 0x76, 0x87, 0x8b, 0x58,
- 0x5c, 0x6e, 0xa8, 0x78, 0x8c, 0x71, 0xe3, 0x0e, 0xfe, 0xad, 0x02, 0x64,
- 0xc0, 0x77, 0x5f, 0x66, 0x6d, 0x51, 0x6e, 0x20, 0x2f, 0x5a, 0x8e, 0x72,
- 0x21, 0xc0, 0x79, 0x6f, 0x6a, 0xa5, 0x05, 0xca, 0x59, 0x97, 0xd9, 0x14,
- 0x98, 0x62, 0xb7, 0xe6, 0x78, 0x97, 0x54, 0xbd, 0x74, 0xb6, 0x49, 0x7a,
- 0x46, 0x40, 0x5b, 0x74, 0x8f, 0x2c, 0x62, 0xcc, 0xa7, 0x44, 0x9f, 0x47,
- 0x7e, 0x6b, 0x0f, 0xa9, 0xbf, 0x6f, 0xe8, 0xc5, 0x3e, 0xfa, 0xfc, 0x8e,
- 0x96, 0x7b, 0x5a, 0x29, 0x04, 0x3e, 0x9b, 0xb1, 0x87, 0xe7, 0x48, 0xc1,
- 0x76, 0xdd, 0x6d, 0x38, 0x1b, 0xe4, 0xfa, 0xaf, 0x5b, 0x55, 0x0e, 0x0e,
- 0x3f, 0x7a, 0x62, 0xa8, 0xbf, 0x5f, 0xba, 0xb7, 0xcb, 0xc9, 0x21, 0xd6,
- 0x6b, 0x9b, 0x81, 0x8f, 0x6b, 0x79, 0xff, 0xb4, 0x5d, 0x4e, 0x2d, 0xc2,
- 0xcf, 0x2e, 0x66, 0x1d, 0xea, 0xf2, 0xd2, 0x50, 0x0a, 0xfe, 0xf9, 0xe6,
- 0x7e, 0xc6, 0xe7, 0xe5, 0x26, 0x75, 0xa5, 0x17, 0xf0, 0x03, 0xd0, 0xcb,
- 0x4d, 0xb0, 0x27, 0x1d, 0xfb, 0x47, 0xb8, 0xff, 0x45, 0xe1, 0xee, 0xb5,
- 0x9d, 0x6d, 0x4a, 0x37, 0xf4, 0xac, 0x95, 0xd1, 0x41, 0xfb, 0xff, 0x14,
- 0x6e, 0x6d, 0x31, 0x71, 0x5c, 0x67, 0xf8, 0x3f, 0xb3, 0xdc, 0x8c, 0xd7,
- 0x30, 0x86, 0xf5, 0xb2, 0x58, 0xae, 0xba, 0x03, 0x63, 0x33, 0xd1, 0x62,
- 0x65, 0xb0, 0xec, 0x16, 0x55, 0x96, 0xba, 0xda, 0x05, 0x42, 0xe2, 0x3a,
- 0xdd, 0x24, 0xb4, 0x72, 0xd5, 0x2a, 0x42, 0x60, 0x37, 0x8e, 0xfa, 0xd2,
- 0x46, 0x55, 0xdb, 0x37, 0xaf, 0x16, 0xec, 0x38, 0xcd, 0xac, 0x17, 0x37,
- 0x38, 0xf4, 0x71, 0xb3, 0x2c, 0x0e, 0x90, 0x75, 0x56, 0x6e, 0xf2, 0x90,
- 0x3e, 0x19, 0x6d, 0xa2, 0x24, 0x55, 0xa5, 0xbc, 0x54, 0x7d, 0xab, 0x5a,
- 0x0b, 0x27, 0xc4, 0x0f, 0xa9, 0xad, 0xf6, 0xa5, 0x77, 0x4d, 0xbf, 0xef,
- 0xcc, 0x2c, 0xc6, 0xa4, 0x51, 0x91, 0x56, 0x73, 0xe6, 0xcc, 0xb9, 0x9f,
- 0xff, 0xf2, 0xfd, 0x17, 0x3e, 0x67, 0x67, 0xba, 0xc2, 0xbd, 0xcd, 0x95,
- 0x76, 0xc6, 0xfe, 0xb6, 0xd4, 0xcc, 0x02, 0xf3, 0x1a, 0x86, 0x64, 0xdc,
- 0x64, 0xae, 0xcf, 0x96, 0x3a, 0x57, 0x66, 0x1b, 0x1b, 0x65, 0xda, 0xe4,
- 0x4b, 0x6a, 0xa6, 0xdc, 0x23, 0x17, 0x41, 0xc7, 0x85, 0xe1, 0xd6, 0xd0,
- 0xf7, 0xda, 0x19, 0xf2, 0x73, 0x77, 0x3c, 0xd4, 0x57, 0x1a, 0x57, 0x16,
- 0x34, 0xb6, 0xee, 0xde, 0xf5, 0xed, 0x49, 0xac, 0x29, 0x41, 0x5f, 0x79,
- 0x5c, 0xcb, 0x26, 0x83, 0xef, 0x7d, 0xbb, 0xde, 0xe3, 0xbb, 0xde, 0x0f,
- 0xfc, 0x8f, 0xf6, 0x2c, 0xef, 0xa6, 0x07, 0xae, 0xd3, 0x1a, 0xe5, 0x2c,
- 0x05, 0xcf, 0x36, 0x66, 0x3d, 0x2b, 0x4d, 0x5c, 0x90, 0x15, 0x5f, 0x65,
- 0xdd, 0x36, 0xc8, 0xbb, 0x36, 0x99, 0x5f, 0x04, 0xcd, 0x63, 0x1f, 0xed,
- 0x36, 0x63, 0xe4, 0x43, 0x71, 0xf2, 0x4c, 0x07, 0xae, 0xc1, 0xb0, 0x07,
- 0x13, 0x68, 0xe7, 0x3f, 0xef, 0xa6, 0xcc, 0xb3, 0xda, 0x97, 0x43, 0x3c,
- 0xe3, 0xab, 0x82, 0xce, 0xf7, 0x60, 0x9b, 0x16, 0xb9, 0x63, 0x67, 0x7a,
- 0xc2, 0x7c, 0x20, 0xd8, 0xbe, 0x5f, 0x8d, 0x13, 0x6b, 0x3c, 0xe7, 0x6e,
- 0xd7, 0x99, 0x9b, 0xc2, 0x1c, 0x2b, 0x10, 0xcd, 0x53, 0x22, 0xe5, 0xaa,
- 0xc8, 0xeb, 0xf8, 0xfd, 0xa6, 0x1a, 0xc6, 0x4f, 0x14, 0xed, 0xee, 0x93,
- 0xb2, 0x5e, 0xfa, 0x9a, 0xd4, 0xa0, 0x7f, 0xd6, 0x5c, 0xdf, 0xbf, 0xeb,
- 0x26, 0xf5, 0x99, 0xbf, 0xe8, 0x29, 0x19, 0x18, 0xa1, 0x7e, 0x6b, 0x93,
- 0x97, 0x17, 0x5b, 0x64, 0xc3, 0xb4, 0xcc, 0xbb, 0x44, 0x01, 0x5e, 0x42,
- 0x26, 0x63, 0x11, 0x8d, 0x51, 0xe5, 0x5b, 0x22, 0x5b, 0xf8, 0xb6, 0xb5,
- 0xf8, 0x4c, 0x9c, 0xfe, 0x97, 0x4f, 0x16, 0xf9, 0x6e, 0xe0, 0x69, 0x48,
- 0xc3, 0x8e, 0x00, 0xcb, 0x42, 0x08, 0x99, 0x3c, 0x77, 0xee, 0xf7, 0xbb,
- 0x5c, 0x1b, 0xea, 0x68, 0xcf, 0xb6, 0x49, 0xe1, 0x30, 0x64, 0xa2, 0x1a,
- 0xd4, 0x39, 0x47, 0x8d, 0x98, 0x96, 0xd1, 0x91, 0x0a, 0x7d, 0xf8, 0xe6,
- 0x5e, 0x2d, 0xaf, 0x33, 0x37, 0x7e, 0xa4, 0xf7, 0x82, 0x72, 0xbe, 0xe2,
- 0x92, 0x56, 0x4d, 0x59, 0x03, 0xaf, 0xad, 0xd6, 0x5f, 0xed, 0xe3, 0x5d,
- 0xad, 0xd7, 0x5f, 0x88, 0x07, 0xf6, 0x1a, 0xeb, 0x7e, 0x1c, 0x0f, 0xea,
- 0x92, 0xa1, 0xfd, 0x45, 0x3b, 0xad, 0x8c, 0xbd, 0xbd, 0x20, 0xf5, 0xa5,
- 0x9f, 0xc9, 0x3b, 0xa5, 0x9f, 0xc8, 0xaf, 0x97, 0xce, 0x00, 0x7f, 0x58,
- 0xe5, 0x3c, 0xf4, 0xc9, 0xcd, 0xba, 0xef, 0xdf, 0x74, 0xa7, 0x60, 0x2b,
- 0xf8, 0xfe, 0xef, 0xdc, 0x0d, 0x19, 0x38, 0xf6, 0x3d, 0xec, 0x39, 0x07,
- 0x1e, 0xa2, 0x2c, 0x9c, 0x04, 0xbd, 0xb9, 0x7d, 0xd2, 0x19, 0xd5, 0x74,
- 0x32, 0x78, 0xac, 0x15, 0x7b, 0x30, 0x42, 0x4c, 0xce, 0xbd, 0x8c, 0xf4,
- 0x91, 0x66, 0x8c, 0x7a, 0x09, 0xf3, 0xb7, 0x82, 0x2f, 0xf6, 0xe2, 0xa7,
- 0xe4, 0xee, 0x08, 0xd6, 0x3a, 0x42, 0xda, 0x6b, 0x95, 0x81, 0x47, 0xb1,
- 0x8f, 0x5c, 0x8b, 0xdc, 0xf3, 0x7e, 0x19, 0xa7, 0x6f, 0xef, 0x9e, 0xc7,
- 0xb2, 0xf1, 0x95, 0x2e, 0xf1, 0xa5, 0x05, 0xba, 0x7c, 0xfe, 0x78, 0x80,
- 0x9b, 0xde, 0x55, 0x43, 0x68, 0x6f, 0xe7, 0xdf, 0x53, 0xc4, 0x79, 0x79,
- 0xbf, 0x15, 0xb8, 0x7c, 0x1c, 0x78, 0x28, 0x53, 0xbf, 0x20, 0x8d, 0x91,
- 0x28, 0xda, 0x10, 0xaf, 0x68, 0x59, 0x22, 0x59, 0x8f, 0x39, 0x5a, 0xcc,
- 0x97, 0xc2, 0x1a, 0xa7, 0x74, 0x2e, 0x57, 0x1f, 0xcf, 0x9c, 0x58, 0x3e,
- 0xa8, 0xb3, 0x41, 0x23, 0xac, 0x23, 0x7d, 0xa7, 0x35, 0xa6, 0x82, 0x0e,
- 0xc5, 0x78, 0xc3, 0x92, 0xd1, 0xe5, 0x2e, 0x8c, 0x77, 0x41, 0x32, 0x6e,
- 0x73, 0xcc, 0x51, 0xb4, 0xa1, 0x9c, 0x19, 0x05, 0x96, 0xf8, 0x58, 0x8d,
- 0x2d, 0xc6, 0xa0, 0xcb, 0xe3, 0x32, 0x66, 0xee, 0xd9, 0xb1, 0xc7, 0xbc,
- 0xb6, 0x15, 0x0c, 0x63, 0x38, 0x5c, 0x53, 0xd7, 0x8e, 0x35, 0xb1, 0x3f,
- 0x7e, 0xb0, 0x93, 0x33, 0x8b, 0x0b, 0x90, 0x53, 0x0b, 0x1f, 0x66, 0xdc,
- 0x67, 0x25, 0x1b, 0x6b, 0xd3, 0xb6, 0x4d, 0x05, 0xf7, 0x92, 0xf5, 0xe8,
- 0xd3, 0xfa, 0x0e, 0xe4, 0xd0, 0x9e, 0xb0, 0x8e, 0x6d, 0xc5, 0xc8, 0xe0,
- 0xec, 0x03, 0x1b, 0x97, 0x75, 0x5f, 0x96, 0xcc, 0x42, 0x4e, 0x26, 0x74,
- 0x3f, 0x9e, 0xe1, 0x41, 0x8d, 0x43, 0xc8, 0xab, 0x03, 0xbd, 0x38, 0xcb,
- 0xd4, 0x03, 0x7b, 0x38, 0xd9, 0x4b, 0x2e, 0xfa, 0x4f, 0xc8, 0xb3, 0xf8,
- 0xd6, 0xcb, 0x3b, 0x6a, 0x93, 0x81, 0x67, 0xa0, 0x2f, 0xbd, 0x66, 0x7d,
- 0x54, 0x3e, 0xf3, 0xfc, 0x38, 0x63, 0x2e, 0x7f, 0xf6, 0x4c, 0xf9, 0xc4,
- 0xd3, 0xb1, 0xd8, 0xe9, 0x88, 0x58, 0xe7, 0x03, 0x5b, 0xfd, 0xf0, 0xf4,
- 0xbc, 0xe2, 0xf7, 0xc3, 0xe7, 0x57, 0x54, 0x07, 0xda, 0x46, 0xd1, 0x8e,
- 0xeb, 0x30, 0x65, 0xdc, 0xfb, 0xab, 0x3f, 0x73, 0xc4, 0xf7, 0x27, 0x74,
- 0x4e, 0x58, 0xca, 0x9c, 0x57, 0x4d, 0x7c, 0xee, 0x88, 0x17, 0x6b, 0xc7,
- 0x5c, 0x29, 0x73, 0x45, 0x1d, 0xc6, 0x7a, 0x58, 0xee, 0x25, 0x4f, 0x24,
- 0x36, 0x84, 0xe3, 0x5b, 0x93, 0xcb, 0x2a, 0x95, 0x1c, 0x54, 0x56, 0xba,
- 0x80, 0x5f, 0x8b, 0xd2, 0x71, 0xcc, 0x44, 0x52, 0x81, 0x77, 0xb1, 0x27,
- 0xfb, 0xa8, 0xef, 0x4f, 0xda, 0xac, 0x4f, 0x99, 0x51, 0x45, 0xdf, 0x4b,
- 0xa7, 0x8e, 0x77, 0x5e, 0x3e, 0x90, 0x32, 0x8f, 0xaa, 0xfd, 0xe1, 0xfb,
- 0x28, 0x64, 0xe6, 0xf6, 0x78, 0x67, 0x96, 0x95, 0x29, 0x2f, 0x79, 0xa9,
- 0xe4, 0xac, 0xb2, 0x72, 0x18, 0x33, 0x37, 0xa6, 0x28, 0x37, 0x52, 0x66,
- 0xa7, 0xa2, 0x7f, 0xb4, 0x5d, 0xef, 0x7b, 0x12, 0xfd, 0x53, 0xaa, 0x25,
- 0x5c, 0x0f, 0xef, 0xeb, 0x4a, 0x5f, 0xc0, 0x33, 0x94, 0x39, 0xfd, 0xc6,
- 0xcc, 0x02, 0xf3, 0xcb, 0x74, 0x5e, 0x43, 0x7a, 0xe0, 0x18, 0xdf, 0x0d,
- 0xb9, 0x7f, 0xe2, 0x6f, 0xa8, 0x43, 0xb9, 0xcc, 0x3a, 0x27, 0xe4, 0xb7,
- 0x23, 0x1a, 0x3f, 0xdf, 0x3f, 0x91, 0xd7, 0xb9, 0x8b, 0x0d, 0x35, 0x10,
- 0xee, 0x7b, 0xfb, 0xce, 0x92, 0x19, 0xf7, 0x4b, 0x1c, 0x67, 0x21, 0x72,
- 0xb2, 0x5d, 0x98, 0x23, 0x3a, 0x5e, 0x6a, 0xd2, 0x06, 0x7d, 0x03, 0xcc,
- 0x15, 0x68, 0xc6, 0xdd, 0x2f, 0x88, 0x71, 0xac, 0x63, 0x07, 0x9d, 0x00,
- 0x77, 0x02, 0xaf, 0x56, 0x31, 0x4e, 0x61, 0x51, 0xf2, 0x41, 0x7f, 0xe9,
- 0x60, 0x4e, 0x6a, 0xa1, 0xfa, 0x45, 0x63, 0x04, 0x3a, 0x70, 0x1c, 0xef,
- 0xf7, 0x4f, 0x90, 0x3e, 0x79, 0x36, 0x49, 0x35, 0xbe, 0xc4, 0xf5, 0x1c,
- 0x94, 0x89, 0x45, 0x60, 0x23, 0xfc, 0xe6, 0x17, 0x83, 0x7b, 0xbb, 0x0e,
- 0x9c, 0x3d, 0xe1, 0x99, 0x9a, 0x5f, 0x67, 0x5d, 0xc6, 0x4f, 0xc0, 0x2b,
- 0x3a, 0x8f, 0x8a, 0x7d, 0x99, 0x4b, 0x78, 0x88, 0xfa, 0xd1, 0x6d, 0x48,
- 0x0c, 0x6d, 0x89, 0x59, 0x59, 0x6f, 0x8d, 0x26, 0x23, 0xdd, 0x32, 0x0f,
- 0x79, 0x57, 0x81, 0xee, 0x2c, 0x5c, 0x89, 0xca, 0xac, 0xa7, 0xe3, 0xd9,
- 0xc9, 0x8f, 0x95, 0x2b, 0xb5, 0xfa, 0x71, 0xb9, 0x51, 0x77, 0xf4, 0x37,
- 0xea, 0xb5, 0xc2, 0xab, 0x86, 0x7c, 0xff, 0x88, 0xce, 0xa5, 0x73, 0x2a,
- 0xd2, 0xd9, 0x4f, 0xcc, 0xb3, 0xa2, 0xf3, 0xea, 0x20, 0x3b, 0x80, 0x39,
- 0xde, 0x06, 0xe6, 0x78, 0x0b, 0x98, 0xe3, 0x57, 0xc0, 0xd8, 0x37, 0x4b,
- 0x93, 0xa1, 0xfc, 0x9f, 0x86, 0x1c, 0xa2, 0xae, 0xb6, 0xce, 0xe0, 0x4e,
- 0xa7, 0xf3, 0xa0, 0xc1, 0xdb, 0xb0, 0x3f, 0xd6, 0x4b, 0x19, 0x59, 0x5d,
- 0x9a, 0x90, 0xb5, 0xa5, 0x20, 0x0f, 0xf9, 0x03, 0xe6, 0x7d, 0x8d, 0xf0,
- 0x9e, 0x1c, 0xc8, 0xa1, 0x3d, 0x32, 0x70, 0x94, 0xf2, 0xa3, 0x43, 0x96,
- 0x8b, 0xab, 0x5a, 0x0e, 0x2d, 0x17, 0x59, 0x8e, 0x88, 0xce, 0x21, 0x9b,
- 0xda, 0x90, 0x8a, 0x5b, 0x47, 0xfd, 0x3e, 0xed, 0x0f, 0x0a, 0xfc, 0xf3,
- 0x94, 0x97, 0x7f, 0x0a, 0xef, 0x5e, 0xe9, 0xdc, 0xba, 0x19, 0xb3, 0x1b,
- 0xed, 0x9a, 0xb2, 0x6b, 0x30, 0x88, 0xb9, 0xab, 0xdb, 0x68, 0x83, 0x39,
- 0x80, 0x19, 0xaf, 0x43, 0x87, 0x34, 0x9c, 0x6e, 0x8d, 0xfd, 0x1a, 0xce,
- 0x21, 0x9d, 0x77, 0xcb, 0x71, 0x0a, 0x45, 0x5b, 0xe6, 0x8a, 0x56, 0x32,
- 0x0f, 0xfa, 0xbb, 0x01, 0xbb, 0x6d, 0x15, 0x77, 0xb0, 0x86, 0x33, 0x58,
- 0xaf, 0x53, 0xcf, 0x6f, 0x6a, 0xd9, 0xbb, 0x5c, 0xff, 0x23, 0xc6, 0xb1,
- 0xce, 0xa4, 0xe5, 0x0f, 0x7d, 0x94, 0x81, 0xf4, 0x4d, 0x65, 0x75, 0xff,
- 0xa0, 0xdf, 0x2a, 0xda, 0xae, 0xd5, 0x29, 0x8f, 0x45, 0x2e, 0x79, 0x36,
- 0x74, 0xc9, 0xcb, 0x09, 0x62, 0x80, 0xb2, 0x6a, 0xf6, 0xf3, 0xc3, 0x35,
- 0xfb, 0xfe, 0x5e, 0x9b, 0xeb, 0x72, 0x42, 0xb9, 0x4d, 0xdd, 0xbf, 0xa1,
- 0xb1, 0x8d, 0x57, 0x7a, 0x56, 0xde, 0xc4, 0x7d, 0x07, 0x18, 0x27, 0x27,
- 0x6f, 0x00, 0xe3, 0xd5, 0x4b, 0xcd, 0xbc, 0xed, 0x93, 0x38, 0xa7, 0x92,
- 0x9a, 0xbb, 0xda, 0x29, 0x97, 0xaf, 0x15, 0xd4, 0x4b, 0xd7, 0x3c, 0xf5,
- 0xf3, 0xab, 0x45, 0x55, 0xb8, 0xea, 0xfb, 0xff, 0x70, 0x67, 0xe4, 0x9d,
- 0x25, 0x5f, 0x4e, 0xbb, 0x46, 0x7f, 0x44, 0x9a, 0xf9, 0x74, 0xbe, 0xdf,
- 0x01, 0xd9, 0xbc, 0x7e, 0xc0, 0xf7, 0x1f, 0x19, 0x19, 0x11, 0xe7, 0x00,
- 0x31, 0xca, 0x70, 0x82, 0x39, 0xae, 0x94, 0x39, 0x19, 0xdb, 0x3e, 0x5f,
- 0x51, 0x0a, 0xf2, 0xad, 0x3b, 0xc0, 0x2f, 0x8f, 0xee, 0x0b, 0xe3, 0x26,
- 0x3f, 0x7c, 0x9e, 0x7e, 0xe5, 0xc4, 0xe7, 0xfc, 0xca, 0xa6, 0x9c, 0x2d,
- 0xf6, 0xa2, 0x7f, 0x4c, 0x7e, 0x50, 0x8c, 0xee, 0x2a, 0x9b, 0x78, 0x3a,
- 0x46, 0xa1, 0x78, 0xcf, 0x1f, 0xd4, 0xf1, 0x03, 0x60, 0x12, 0xd3, 0xf7,
- 0x67, 0x5d, 0xce, 0xd7, 0x8d, 0xf9, 0x36, 0xcc, 0x7d, 0xd0, 0xff, 0xa7,
- 0xb5, 0x7e, 0x2e, 0x2b, 0xd8, 0xc1, 0xe0, 0xef, 0x98, 0x8c, 0x15, 0xa1,
- 0xe3, 0x15, 0xf3, 0x4c, 0x89, 0x15, 0xac, 0xc4, 0x2c, 0x64, 0xc7, 0x0c,
- 0xe4, 0xcd, 0x29, 0x1d, 0x67, 0xed, 0xd5, 0xb2, 0x67, 0x8e, 0xe5, 0x9c,
- 0xa4, 0x2b, 0x6e, 0x8f, 0x3e, 0xbf, 0xcd, 0x1b, 0x2f, 0x26, 0x82, 0x3b,
- 0x07, 0x1f, 0xe7, 0x94, 0xb4, 0xc1, 0x1e, 0xca, 0xae, 0x4c, 0x81, 0x27,
- 0x12, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x0d, 0xe8, 0xef, 0x86, 0xf6, 0x29,
- 0x06, 0xb1, 0x8b, 0x86, 0xc9, 0x76, 0xa7, 0xd0, 0xaf, 0x5d, 0x32, 0x57,
- 0xdb, 0xb4, 0x5c, 0x7d, 0xb8, 0x2e, 0x0d, 0x1c, 0xf2, 0x04, 0xca, 0x11,
- 0xd4, 0x25, 0xc3, 0xb2, 0x81, 0xf2, 0x34, 0xca, 0x2d, 0x78, 0xb2, 0xcd,
- 0x61, 0xe0, 0x0a, 0x3c, 0x5f, 0xc3, 0x78, 0x23, 0x58, 0x73, 0xce, 0x94,
- 0x8f, 0x4e, 0x50, 0x97, 0x38, 0x06, 0x73, 0x91, 0x67, 0x6d, 0x3c, 0x6b,
- 0x45, 0x95, 0x5d, 0x60, 0x19, 0xcf, 0x72, 0xf0, 0xfd, 0x21, 0x99, 0x84,
- 0x3e, 0x99, 0x6b, 0x81, 0x4c, 0xfa, 0x68, 0x5b, 0x26, 0xb1, 0xae, 0x5d,
- 0xc6, 0xae, 0x92, 0xd7, 0x4d, 0xd0, 0x5b, 0xa7, 0x64, 0xaf, 0xc5, 0x34,
- 0x1e, 0xad, 0x80, 0x16, 0xaf, 0x83, 0xae, 0x96, 0x41, 0x53, 0x99, 0xa2,
- 0x35, 0x3a, 0xad, 0x92, 0xda, 0x2f, 0xf0, 0x38, 0xe8, 0xb5, 0xe3, 0x0a,
- 0xb1, 0x28, 0x79, 0xd9, 0x01, 0xed, 0x89, 0xdf, 0x61, 0xdb, 0x93, 0x8e,
- 0xb2, 0x41, 0x83, 0xa0, 0xcb, 0x62, 0xc0, 0xd3, 0xef, 0x29, 0x2d, 0x57,
- 0x47, 0xef, 0x48, 0x2a, 0x7d, 0x47, 0x2c, 0xc8, 0x02, 0xcb, 0xfd, 0x50,
- 0x5c, 0x8c, 0x79, 0x5c, 0x5e, 0xc7, 0x3c, 0x06, 0xf8, 0xfb, 0xc8, 0x90,
- 0xe6, 0xef, 0x51, 0x89, 0xec, 0xe6, 0x71, 0xd0, 0x1b, 0x64, 0x50, 0xc0,
- 0xd3, 0xe9, 0x90, 0x46, 0x9f, 0x06, 0xff, 0x5a, 0xb0, 0xca, 0x92, 0x32,
- 0x0f, 0xfe, 0xbf, 0x8e, 0xef, 0xb7, 0xea, 0x9f, 0xaa, 0xb9, 0x05, 0x15,
- 0xe6, 0xb2, 0x7c, 0x1b, 0x38, 0xf9, 0xf7, 0x38, 0xbb, 0x2e, 0x8d, 0xdd,
- 0x07, 0x46, 0x18, 0x4b, 0xfb, 0xb7, 0xba, 0x6c, 0x1f, 0x95, 0xcd, 0xe1,
- 0xe3, 0x28, 0xef, 0xc3, 0xd3, 0xc0, 0x39, 0x44, 0x75, 0x2c, 0x7c, 0xd9,
- 0x1b, 0x36, 0x0a, 0x3a, 0xef, 0xe0, 0x98, 0xce, 0xcf, 0x37, 0xec, 0x03,
- 0xf8, 0x4e, 0xbf, 0x0c, 0xf7, 0x06, 0xcc, 0xa4, 0x12, 0x3a, 0xc7, 0xb4,
- 0x02, 0x2c, 0xb1, 0x82, 0xf1, 0xde, 0xa7, 0x5f, 0xaf, 0x06, 0x1e, 0x1e,
- 0xfe, 0xa7, 0x9f, 0x8e, 0x31, 0x27, 0x7d, 0x33, 0x11, 0xe8, 0xbf, 0xcf,
- 0xfc, 0x4d, 0x7b, 0x6e, 0xd4, 0xc0, 0xcb, 0x6d, 0x33, 0x86, 0xb6, 0xd0,
- 0x65, 0xd0, 0x45, 0x65, 0x4d, 0xbf, 0x6c, 0x17, 0xf4, 0x2d, 0xd4, 0x52,
- 0xe6, 0x07, 0x12, 0xf4, 0x9d, 0xb7, 0xa9, 0x77, 0xda, 0x21, 0x5f, 0x92,
- 0x1a, 0x57, 0xbe, 0x6f, 0xe7, 0x21, 0x15, 0xac, 0xe4, 0x24, 0x68, 0xb4,
- 0x4d, 0x2c, 0x67, 0x5c, 0x1e, 0xcc, 0x3b, 0xab, 0xfb, 0xb2, 0x6d, 0xb3,
- 0x6f, 0x73, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0xa7, 0x36, 0x35,
- 0x8d, 0x36, 0x6a, 0xed, 0xfd, 0x01, 0x8d, 0x36, 0xf7, 0x11, 0xfb, 0x3f,
- 0xfb, 0x20, 0x9d, 0x0c, 0x1b, 0x41, 0x0e, 0x06, 0x9e, 0x35, 0x9e, 0xe7,
- 0xa7, 0xc0, 0xf7, 0x3b, 0xe9, 0xa7, 0xe9, 0x67, 0x0c, 0xe8, 0xe7, 0x91,
- 0x6d, 0xfa, 0x21, 0xdd, 0x74, 0xca, 0xd8, 0x35, 0x5b, 0x26, 0x8a, 0xfa,
- 0xbe, 0x81, 0x35, 0xe9, 0x3f, 0x3a, 0x0e, 0xba, 0x21, 0xad, 0x93, 0xb7,
- 0x4c, 0x29, 0x83, 0x8e, 0xca, 0x90, 0x4f, 0x65, 0xd0, 0x14, 0x31, 0x50,
- 0x19, 0xf2, 0xad, 0x5c, 0xb7, 0x9c, 0x2a, 0xf6, 0x4c, 0x9d, 0xbd, 0x02,
- 0x3a, 0xba, 0x5e, 0xe7, 0xfd, 0xeb, 0x35, 0x9b, 0xd4, 0x83, 0xb7, 0xb6,
- 0xef, 0xfe, 0xef, 0xb8, 0xfb, 0x43, 0x72, 0x03, 0x76, 0xcb, 0x9b, 0xa5,
- 0x61, 0xc8, 0x24, 0x21, 0x5e, 0x04, 0x6d, 0x8c, 0xca, 0x6a, 0xe9, 0xa4,
- 0xac, 0x41, 0x3f, 0xad, 0x2f, 0x0d, 0x00, 0x4f, 0x43, 0x8e, 0xbe, 0x72,
- 0x44, 0xde, 0x58, 0x52, 0x32, 0x63, 0x43, 0xbf, 0x2c, 0xd3, 0x07, 0x0f,
- 0x7a, 0x2e, 0x77, 0xea, 0x98, 0xfd, 0x58, 0x35, 0xf0, 0xc5, 0x8f, 0x57,
- 0xbb, 0x64, 0xa2, 0x6a, 0xca, 0x63, 0xd5, 0x1e, 0x79, 0xa2, 0x1a, 0x93,
- 0xd3, 0xb5, 0x84, 0x7c, 0xa3, 0x7a, 0x50, 0x4e, 0x55, 0x0f, 0xc9, 0x93,
- 0xb5, 0xa4, 0x7c, 0x13, 0x76, 0x61, 0xae, 0xe6, 0xc8, 0x64, 0x6d, 0x58,
- 0x1e, 0xaf, 0xd1, 0xc7, 0x8e, 0xf9, 0xf0, 0xcb, 0x6e, 0xfb, 0x2e, 0xb8,
- 0xae, 0x0e, 0xac, 0xcb, 0x51, 0xe3, 0x3a, 0x66, 0x29, 0xb9, 0xc0, 0xff,
- 0x21, 0x72, 0x0e, 0x7d, 0x2f, 0xbe, 0xa2, 0xa4, 0xa2, 0xe7, 0x6f, 0xfe,
- 0xdf, 0x48, 0x54, 0xdb, 0x46, 0xe7, 0xca, 0x07, 0xd1, 0xc6, 0xa6, 0x4d,
- 0x12, 0xfa, 0x41, 0x9a, 0xfe, 0xff, 0xa6, 0xed, 0x65, 0x68, 0x1f, 0xf6,
- 0x2d, 0xda, 0x5e, 0xfa, 0xec, 0x29, 0x3f, 0x68, 0xe7, 0xd0, 0xd6, 0xda,
- 0x19, 0xe7, 0x68, 0xce, 0x7b, 0x31, 0xf7, 0xf0, 0xff, 0xa7, 0x04, 0xf1,
- 0xaa, 0xb3, 0xb5, 0x83, 0xfc, 0x3f, 0x15, 0xac, 0xe5, 0x8b, 0xf3, 0xc5,
- 0x27, 0x4a, 0x63, 0xea, 0xb1, 0x12, 0x11, 0x8d, 0x2f, 0x17, 0xb7, 0x73,
- 0xf2, 0xbe, 0x2e, 0xcb, 0x6e, 0x54, 0xaf, 0x21, 0xf0, 0xdb, 0xa7, 0x75,
- 0x7e, 0xde, 0xd8, 0x10, 0xe9, 0x8f, 0x71, 0xb8, 0xae, 0x30, 0xb6, 0x00,
- 0x6c, 0xeb, 0x9a, 0x72, 0xa9, 0x1a, 0xf8, 0xaf, 0xe6, 0x34, 0xbd, 0xbc,
- 0x05, 0x9a, 0x63, 0xfc, 0x21, 0x78, 0xe6, 0xcb, 0x41, 0xdf, 0xec, 0x90,
- 0x43, 0x7b, 0x1c, 0xfb, 0x35, 0x7a, 0x38, 0x17, 0xff, 0x4f, 0x07, 0xe5,
- 0x70, 0xbd, 0xcc, 0x2f, 0xb6, 0x35, 0x2d, 0x06, 0x31, 0x5e, 0x47, 0x9e,
- 0xc3, 0x5d, 0x54, 0x4c, 0xae, 0xbf, 0x43, 0x2a, 0x0e, 0x6d, 0x5b, 0xca,
- 0xef, 0x21, 0x29, 0x63, 0x9e, 0x8a, 0xd3, 0xf4, 0x8d, 0x05, 0x72, 0xb6,
- 0x62, 0x3e, 0x98, 0x77, 0xba, 0xbc, 0x1f, 0xef, 0xa8, 0x73, 0x80, 0x99,
- 0xa6, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0xe6, 0xf0, 0x4c, 0x84, 0x75,
- 0xaf, 0xf5, 0x6b, 0xac, 0x7e, 0xf2, 0x41, 0xbf, 0x99, 0xb2, 0x95, 0xcf,
- 0x44, 0xb6, 0x94, 0xf1, 0x8b, 0xf5, 0x7e, 0xca, 0xdc, 0xfd, 0x36, 0x7f,
- 0x51, 0xf9, 0x8b, 0xa9, 0x7d, 0x0a, 0xe1, 0xb7, 0x3d, 0xf2, 0x94, 0xc9,
- 0xdc, 0xf5, 0xb4, 0x1a, 0x2b, 0xfd, 0x34, 0xcc, 0xd3, 0xdd, 0x52, 0xfb,
- 0x2b, 0x6f, 0xf7, 0x07, 0x79, 0xee, 0x1c, 0x7b, 0x67, 0x6e, 0xfb, 0x4e,
- 0x3a, 0x61, 0x8e, 0x7b, 0x3b, 0x70, 0xab, 0x56, 0x62, 0xe0, 0x41, 0xc8,
- 0x3b, 0xbb, 0x45, 0xf3, 0x63, 0xa1, 0xf6, 0x2f, 0x7f, 0x43, 0xf3, 0x73,
- 0xd3, 0xc7, 0xf0, 0xdb, 0x7e, 0xda, 0xb6, 0x94, 0x1b, 0x97, 0x02, 0xbf,
- 0x91, 0xb6, 0xa1, 0x21, 0x2b, 0x50, 0x47, 0x5e, 0x05, 0x9f, 0x6c, 0xb7,
- 0xe5, 0xdf, 0x7f, 0x01, 0x99, 0xe7, 0xd3, 0x46, 0x40, 0x67, 0x00, 0x00,
- 0x00 };
-static u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
- 0x08003fa4, 0x08003ea4, 0x08003f48, 0x08003f60, 0x08003f78, 0x08003f98,
- 0x08003fa4, 0x08003fa4, 0x08003eac, 0x00000000, 0x080049d4, 0x08004a0c,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004a44, 0x08004c08,
- 0x08004b50, 0x08004b88, 0x08004c08, 0x08004ad8, 0x08004c08, 0x08004c08,
- 0x08004b88, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004bc8,
- 0x08004c08, 0x08004bc8, 0x08004b50, 0x08004c08, 0x08004c08, 0x08004bc8,
- 0x08004bc8, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08, 0x08004c08,
- 0x08004ab4, 0x00000000, 0x0800602c, 0x08006044, 0x08006044, 0x08006044,
- 0x0800602c, 0x08006044, 0x08006044, 0x08006044, 0x0800602c, 0x08006044,
- 0x08006044, 0x08006044, 0x0800602c, 0x08006044, 0x08006044, 0x08006044,
- 0x08006038, 0x00000000, 0x00000000 };
-static u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
+ 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c,
+ 0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67,
+ 0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a,
+ 0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1,
+ 0x03, 0x53, 0xb6, 0x62, 0x07, 0x45, 0x6a, 0xb0, 0x4b, 0xb9, 0x0e, 0x8c,
+ 0x06, 0x90, 0xff, 0x52, 0xbf, 0xb0, 0xde, 0x2c, 0xa9, 0x58, 0x4d, 0x17,
+ 0x9c, 0xb5, 0x4d, 0x9b, 0x0e, 0x60, 0xb7, 0x0b, 0x92, 0x12, 0xf5, 0xb0,
+ 0xd0, 0xb2, 0xa9, 0xdb, 0xea, 0xc1, 0x8e, 0x09, 0x56, 0xb1, 0x53, 0xa0,
+ 0x2d, 0x5c, 0x27, 0x69, 0xfc, 0x10, 0x14, 0xaa, 0xec, 0xc4, 0x42, 0xd1,
+ 0xa2, 0x02, 0x12, 0xd8, 0x29, 0x22, 0x7b, 0xfa, 0x7d, 0x77, 0x66, 0xc8,
+ 0x25, 0x2d, 0xdb, 0x41, 0x1f, 0xfa, 0xd2, 0xbd, 0xc0, 0x62, 0xee, 0xbd,
+ 0x73, 0xee, 0xb9, 0xe7, 0x9e, 0xff, 0x73, 0x87, 0xd2, 0x1f, 0x74, 0x48,
+ 0xbb, 0x84, 0xad, 0x13, 0xbf, 0xd4, 0x89, 0x27, 0x1e, 0xb9, 0x69, 0xf4,
+ 0xa6, 0x9b, 0xd1, 0xbd, 0xd9, 0x30, 0x4c, 0x23, 0x9a, 0x6f, 0xb6, 0x66,
+ 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+ 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+ 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+ 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+ 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66,
+ 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0x6b, 0xb6, 0x66, 0xfb, 0xff, 0xde,
+ 0x0c, 0x11, 0x8b, 0xcf, 0xce, 0xf0, 0x27, 0x31, 0x3d, 0x23, 0x0f, 0xb9,
+ 0xb6, 0xc4, 0x8c, 0xcc, 0xd5, 0xa9, 0x49, 0x5b, 0x24, 0x5b, 0xdb, 0x97,
+ 0xca, 0xc9, 0x87, 0x7e, 0x31, 0x61, 0x0a, 0xe7, 0xaf, 0xcf, 0x5c, 0xfd,
+ 0x8b, 0x57, 0x6f, 0x4d, 0x5f, 0xa9, 0x1a, 0x12, 0xb3, 0x32, 0x33, 0x07,
+ 0xac, 0xbd, 0x12, 0xeb, 0xc7, 0x9a, 0x17, 0x87, 0xfe, 0xa9, 0x4b, 0xba,
+ 0x22, 0x5c, 0x22, 0x0b, 0xe5, 0xb4, 0x73, 0x18, 0xcf, 0x33, 0xb5, 0x7d,
+ 0xce, 0x9a, 0x98, 0xb2, 0x6a, 0x05, 0x3b, 0x96, 0xca, 0x1a, 0xf1, 0x48,
+ 0xa9, 0x16, 0x93, 0x8b, 0xea, 0xdf, 0x79, 0x60, 0x4f, 0x9b, 0xfd, 0xf3,
+ 0x9a, 0x5b, 0xf7, 0xfd, 0xd3, 0x8e, 0xef, 0xbf, 0x8e, 0xdf, 0x7b, 0x0e,
+ 0xc6, 0xde, 0x47, 0x7e, 0xd6, 0x34, 0x44, 0xb7, 0xff, 0x4c, 0x73, 0x17,
+ 0x5b, 0xa5, 0x34, 0x2f, 0x32, 0xed, 0xc5, 0xe4, 0x94, 0x57, 0xd4, 0xf2,
+ 0xf5, 0xb2, 0x76, 0x68, 0x79, 0x56, 0x3b, 0xbc, 0x7c, 0x4a, 0x3b, 0xb2,
+ 0x5c, 0xd1, 0xdc, 0x65, 0x29, 0xea, 0x07, 0x3a, 0x24, 0x6b, 0x9d, 0xd5,
+ 0x72, 0xf5, 0x3e, 0xcd, 0x9d, 0xbf, 0xea, 0xbb, 0x4e, 0xda, 0xfa, 0x3d,
+ 0x31, 0xb3, 0xdc, 0xcf, 0x2d, 0xfb, 0x18, 0x9b, 0x92, 0x4d, 0xf8, 0xbe,
+ 0x9e, 0xf1, 0x9f, 0x74, 0x47, 0x6d, 0x4b, 0xd7, 0x62, 0x52, 0xaa, 0xb7,
+ 0x03, 0x6f, 0x87, 0x96, 0x9b, 0x37, 0xb5, 0xbc, 0xe7, 0xbf, 0xe6, 0x3a,
+ 0xd2, 0x6f, 0x88, 0xef, 0xcf, 0x38, 0x7b, 0x92, 0xc7, 0xe5, 0x0c, 0xf0,
+ 0xd6, 0x80, 0x4f, 0x2c, 0x3d, 0x43, 0xfa, 0x22, 0x9a, 0x8b, 0x5a, 0x6e,
+ 0x28, 0xa2, 0x4f, 0x52, 0xa4, 0xbf, 0xb0, 0xa4, 0x83, 0xce, 0xed, 0x52,
+ 0xa8, 0x5a, 0x32, 0xb1, 0xb4, 0x15, 0xfe, 0xa2, 0xff, 0xea, 0x50, 0x42,
+ 0xfe, 0xb2, 0x9e, 0x3e, 0x55, 0x04, 0x2f, 0x66, 0xbc, 0x94, 0x80, 0xcf,
+ 0x59, 0x77, 0xb4, 0x5f, 0x5e, 0xab, 0x27, 0xe5, 0xbb, 0x75, 0x3b, 0x59,
+ 0x92, 0x6d, 0x52, 0x48, 0x58, 0xb2, 0x82, 0x35, 0xd3, 0xa0, 0x43, 0xb7,
+ 0x6d, 0xab, 0x04, 0xd8, 0x52, 0xfd, 0x27, 0xfc, 0xb7, 0x32, 0xd6, 0xe4,
+ 0xa8, 0x5a, 0x53, 0x04, 0xdd, 0x21, 0x2c, 0xcf, 0xa1, 0x60, 0xd5, 0x59,
+ 0x02, 0x58, 0x29, 0x4e, 0x8e, 0x62, 0xae, 0xfe, 0x85, 0x50, 0x16, 0xad,
+ 0x38, 0x2f, 0x9f, 0xbb, 0x71, 0xbe, 0xdd, 0xe0, 0x89, 0x24, 0x74, 0xd9,
+ 0x93, 0x2c, 0x60, 0x66, 0xba, 0xde, 0x81, 0x31, 0x69, 0xf1, 0xfd, 0x23,
+ 0x8e, 0x58, 0x25, 0xa7, 0x1b, 0xbc, 0x4b, 0x49, 0xc9, 0xe9, 0xc2, 0x9a,
+ 0x16, 0xb1, 0x6c, 0x9e, 0x81, 0x78, 0xdb, 0x30, 0xef, 0x77, 0x1a, 0x19,
+ 0xdf, 0x9f, 0x1c, 0x95, 0xae, 0x60, 0x6e, 0x1f, 0x70, 0x98, 0x32, 0x31,
+ 0xae, 0x01, 0xee, 0x03, 0xd2, 0x17, 0x8b, 0x67, 0xd8, 0xe7, 0x73, 0x54,
+ 0xdc, 0xd9, 0x54, 0xb8, 0x6f, 0x87, 0x94, 0xbc, 0xeb, 0xc3, 0x3e, 0x78,
+ 0xed, 0xe1, 0xcc, 0xce, 0x4e, 0x8c, 0xb5, 0x1b, 0x80, 0xc7, 0x29, 0x09,
+ 0xf7, 0xd8, 0x21, 0x6b, 0x09, 0xd1, 0x2f, 0x39, 0xbd, 0x21, 0x5c, 0x17,
+ 0x68, 0x8d, 0x64, 0xde, 0x2e, 0x33, 0xf3, 0xad, 0x72, 0x72, 0x9e, 0xbc,
+ 0x2d, 0x43, 0x16, 0x78, 0xde, 0x52, 0xd4, 0xb2, 0xf5, 0x53, 0xe8, 0x9b,
+ 0x32, 0x69, 0xfb, 0xaf, 0xcd, 0x38, 0xb3, 0x5a, 0x6e, 0xf9, 0x8c, 0x96,
+ 0x87, 0x0e, 0x1c, 0x5a, 0x3e, 0xaf, 0x1d, 0xae, 0xaf, 0x76, 0x4a, 0x7b,
+ 0x1a, 0xda, 0x66, 0xca, 0x49, 0x4f, 0x13, 0xd2, 0xbb, 0x00, 0x7e, 0x65,
+ 0x2d, 0x70, 0xde, 0xee, 0xd2, 0x0e, 0x03, 0x57, 0x8b, 0xfd, 0xad, 0x0e,
+ 0xe9, 0x32, 0x64, 0x9b, 0x1d, 0xc1, 0xc6, 0xe4, 0x5b, 0xa0, 0x6d, 0xcd,
+ 0x49, 0x00, 0x4e, 0xba, 0x83, 0x35, 0x3d, 0x21, 0x3d, 0xd4, 0x25, 0xea,
+ 0x91, 0x9e, 0xcd, 0xcf, 0xfd, 0x69, 0x6f, 0x69, 0xff, 0x76, 0xc2, 0xc0,
+ 0x3e, 0x52, 0x0f, 0x4d, 0xda, 0x6e, 0x8f, 0x29, 0x45, 0x4b, 0x97, 0xb4,
+ 0x95, 0x93, 0x1b, 0x64, 0xc6, 0x11, 0xc9, 0x41, 0xbf, 0x75, 0xdb, 0x04,
+ 0x8f, 0x6c, 0xf0, 0x68, 0xcf, 0xa9, 0x41, 0xfd, 0x0e, 0x49, 0xf5, 0x15,
+ 0x35, 0x33, 0xe4, 0xe7, 0x82, 0xdc, 0xa6, 0xd6, 0xeb, 0x19, 0x07, 0x3a,
+ 0xd9, 0xce, 0x3e, 0xf6, 0x8d, 0xa9, 0x7d, 0x8d, 0x8c, 0x9d, 0x5c, 0x14,
+ 0xd1, 0xf4, 0xcc, 0x3e, 0xe0, 0xa3, 0xae, 0x12, 0xee, 0x29, 0xd0, 0x48,
+ 0xda, 0xd9, 0xb7, 0xb1, 0x26, 0x26, 0xae, 0xd3, 0xd9, 0x40, 0x27, 0xe8,
+ 0x49, 0x90, 0xe7, 0xe4, 0xa1, 0x3a, 0xa7, 0xb6, 0x71, 0xce, 0x5f, 0xfb,
+ 0xdb, 0x46, 0x4c, 0x79, 0x5d, 0x9d, 0x97, 0x76, 0x45, 0x38, 0x75, 0x46,
+ 0x21, 0x7f, 0xa6, 0x3d, 0xd1, 0x0a, 0x8e, 0xb5, 0x8e, 0x0b, 0x7a, 0xa1,
+ 0x1b, 0x99, 0x0e, 0xc9, 0x29, 0xfa, 0x0e, 0x62, 0x2f, 0xda, 0x1b, 0xec,
+ 0xc6, 0xe6, 0x59, 0x38, 0x97, 0x81, 0xed, 0xa6, 0x95, 0xfe, 0x14, 0x2a,
+ 0xf4, 0x07, 0xa4, 0x6d, 0x35, 0xad, 0x4b, 0x80, 0xaf, 0xf4, 0x6c, 0x37,
+ 0x68, 0xe3, 0x18, 0xb6, 0x67, 0xe3, 0xfd, 0x7e, 0xd8, 0xfa, 0xc1, 0x41,
+ 0xf0, 0x87, 0x70, 0x76, 0x0a, 0xf2, 0xce, 0xba, 0xd8, 0xd3, 0x75, 0x6e,
+ 0x56, 0x3c, 0xe8, 0xc1, 0x79, 0x06, 0x67, 0xc9, 0xaf, 0x76, 0xe8, 0xb3,
+ 0x26, 0x05, 0x27, 0x9d, 0xa2, 0xfc, 0x03, 0xda, 0x75, 0xd9, 0x76, 0x4b,
+ 0x23, 0xed, 0x91, 0xac, 0xa8, 0x8f, 0xa6, 0xc4, 0x47, 0x08, 0x4b, 0x38,
+ 0xc2, 0xa7, 0x0f, 0x8a, 0xfe, 0x6b, 0xdf, 0xda, 0x74, 0x56, 0x5b, 0x06,
+ 0x66, 0x41, 0x43, 0xc0, 0x5b, 0xf0, 0xe4, 0xb3, 0x60, 0xc9, 0xd7, 0xad,
+ 0xfc, 0x23, 0x6c, 0x23, 0x1c, 0x74, 0xa2, 0x8f, 0x34, 0xac, 0x74, 0x04,
+ 0xf6, 0x15, 0xd1, 0x14, 0xc9, 0x46, 0x0b, 0x71, 0x7c, 0xda, 0x39, 0x08,
+ 0x0f, 0xbb, 0xf7, 0x60, 0xf7, 0x1e, 0x7c, 0x82, 0x07, 0x9b, 0xf7, 0xe8,
+ 0x27, 0x52, 0xf2, 0xea, 0x10, 0xfc, 0xda, 0x86, 0x5f, 0x41, 0x1b, 0x43,
+ 0x5f, 0x17, 0x03, 0x7e, 0x65, 0xba, 0xaa, 0xc3, 0x76, 0x61, 0x43, 0x4b,
+ 0x9c, 0xb3, 0xf0, 0xcc, 0xe3, 0x69, 0xc3, 0x8f, 0x52, 0xaf, 0x22, 0xff,
+ 0x49, 0x3f, 0x93, 0x84, 0x4f, 0xa1, 0xaf, 0xa1, 0x2f, 0x21, 0xac, 0xef,
+ 0xe7, 0x1d, 0xae, 0xf5, 0x65, 0xdc, 0xa1, 0x1d, 0x75, 0x88, 0x1e, 0x2f,
+ 0x6a, 0x47, 0x87, 0x60, 0x63, 0x37, 0xb6, 0x80, 0x56, 0xda, 0xda, 0x75,
+ 0x74, 0x15, 0x68, 0xbf, 0xe8, 0x0c, 0xfe, 0x5d, 0xde, 0x36, 0xc0, 0x28,
+ 0xa1, 0x76, 0x05, 0xe3, 0xb6, 0xd0, 0x9f, 0xf0, 0x7d, 0x3a, 0x95, 0x95,
+ 0xdd, 0xe1, 0x98, 0xfd, 0x75, 0x7a, 0x1d, 0xfd, 0x96, 0x98, 0x0c, 0x9c,
+ 0x09, 0xfc, 0xe0, 0xc0, 0x82, 0x25, 0xf6, 0x99, 0x80, 0xc6, 0x81, 0x73,
+ 0x91, 0x3f, 0x6c, 0x01, 0x3e, 0xd0, 0xe7, 0x6d, 0xc4, 0x09, 0x91, 0xf7,
+ 0x34, 0x98, 0x0a, 0xe6, 0xb6, 0xf2, 0x82, 0x3e, 0x98, 0xf6, 0x66, 0x35,
+ 0xda, 0xdb, 0x01, 0xd8, 0x9b, 0xd3, 0x2a, 0x69, 0xe7, 0xef, 0x60, 0x6f,
+ 0x4f, 0x39, 0x1a, 0x78, 0x23, 0x72, 0xa1, 0xdc, 0x01, 0x5b, 0x37, 0x93,
+ 0xef, 0xc8, 0x9e, 0xd4, 0xb4, 0x68, 0x72, 0x9a, 0x73, 0x35, 0xcc, 0x29,
+ 0xff, 0x1b, 0xd8, 0xf7, 0x45, 0xe3, 0x69, 0xd0, 0xe5, 0xfb, 0xd3, 0xc0,
+ 0x59, 0xd8, 0x6f, 0x84, 0xb6, 0x15, 0xcd, 0xa7, 0x10, 0xf3, 0xdc, 0xcf,
+ 0x19, 0x52, 0x1c, 0x6e, 0x91, 0xf4, 0xf0, 0x02, 0x70, 0x4f, 0x3a, 0x81,
+ 0x1d, 0x53, 0xd7, 0x17, 0x81, 0x7f, 0xc6, 0x1b, 0x82, 0x1e, 0xd3, 0x0e,
+ 0x40, 0x17, 0xf0, 0x2f, 0x02, 0xff, 0x4c, 0xbd, 0x45, 0xbe, 0x69, 0x46,
+ 0xb1, 0x34, 0x3a, 0x4f, 0x1b, 0xc0, 0xa2, 0x7d, 0x4f, 0xc8, 0x17, 0xbd,
+ 0xb8, 0xe6, 0x3e, 0x4b, 0x3f, 0x5b, 0x1a, 0x86, 0x9d, 0x68, 0x25, 0x87,
+ 0x7b, 0x1b, 0xb2, 0xb8, 0x0e, 0x23, 0xd9, 0x52, 0x60, 0x83, 0x59, 0x77,
+ 0xa8, 0x98, 0x34, 0x94, 0x2f, 0x11, 0x39, 0x5c, 0x36, 0x01, 0xc3, 0x31,
+ 0xe7, 0x83, 0xb9, 0xb1, 0x72, 0x1f, 0x7c, 0x23, 0xc7, 0x57, 0xfd, 0x49,
+ 0x27, 0x98, 0xfb, 0xdd, 0x72, 0x81, 0x32, 0x62, 0xdc, 0x4e, 0x95, 0x9c,
+ 0x7f, 0xf7, 0xa1, 0xbf, 0x9b, 0xd6, 0x5c, 0x1b, 0x4f, 0x7a, 0x2c, 0x8c,
+ 0xf5, 0xda, 0x11, 0x5b, 0xef, 0x6b, 0x0d, 0x7d, 0xd8, 0x11, 0x4c, 0x1e,
+ 0x2a, 0x97, 0x7a, 0x5b, 0xe5, 0xaa, 0xc1, 0xd8, 0x79, 0x09, 0x46, 0xed,
+ 0x96, 0xf7, 0x82, 0x1f, 0xa5, 0x9e, 0x86, 0xb9, 0x58, 0xbe, 0xec, 0xcb,
+ 0x9a, 0x13, 0xac, 0xc1, 0xb8, 0x23, 0x57, 0xd6, 0xfb, 0x62, 0xb2, 0x3e,
+ 0xb6, 0xb8, 0x66, 0x49, 0xf6, 0x0e, 0x2f, 0x8a, 0x5a, 0xdb, 0x1b, 0xdb,
+ 0x58, 0x9b, 0xc8, 0x97, 0x4b, 0x3d, 0x0d, 0xe3, 0x64, 0x0e, 0xb8, 0xf4,
+ 0x03, 0xeb, 0x6b, 0xfb, 0x37, 0xd6, 0xee, 0x90, 0x54, 0x0f, 0xd7, 0xeb,
+ 0x7d, 0x6d, 0x1b, 0xb8, 0x53, 0x21, 0x3d, 0xbd, 0x6d, 0x1b, 0x38, 0x6c,
+ 0xe2, 0x6c, 0x18, 0x0f, 0x13, 0xe7, 0xc0, 0x06, 0xce, 0xfd, 0x9b, 0xe9,
+ 0x39, 0x21, 0xf0, 0x41, 0xb1, 0xd6, 0x8c, 0x1c, 0xb8, 0x50, 0x1e, 0x1c,
+ 0xff, 0xa2, 0x20, 0xe6, 0xed, 0xdf, 0x16, 0xfa, 0x64, 0xf3, 0x80, 0x0b,
+ 0x5e, 0x99, 0x42, 0x1f, 0xa7, 0x49, 0x09, 0x72, 0x7e, 0xa8, 0x26, 0x07,
+ 0xd6, 0x6a, 0x12, 0xea, 0x12, 0x75, 0xe2, 0x32, 0x6c, 0x4c, 0x8a, 0xbb,
+ 0x32, 0x1d, 0x13, 0x66, 0xc6, 0x82, 0xad, 0xc9, 0x78, 0x09, 0x3e, 0xd9,
+ 0xc8, 0xec, 0x79, 0x3b, 0x67, 0x3c, 0xe9, 0x1b, 0x88, 0xdb, 0x39, 0xe9,
+ 0x38, 0xe8, 0x8e, 0x62, 0xbe, 0x46, 0xdb, 0x82, 0x5f, 0xa9, 0x13, 0xf7,
+ 0x7c, 0xb7, 0x74, 0x21, 0x2e, 0xd6, 0x5e, 0xda, 0x11, 0xd8, 0x8e, 0x98,
+ 0x26, 0x7c, 0xed, 0xcc, 0x28, 0xe3, 0x78, 0x6b, 0x0c, 0xf0, 0x13, 0x46,
+ 0x66, 0x6c, 0xe7, 0xf1, 0xda, 0x9d, 0x3b, 0x0b, 0xb5, 0xe2, 0xce, 0x42,
+ 0xd9, 0xa2, 0x9d, 0xe8, 0xee, 0x28, 0xfa, 0x2a, 0x57, 0x4a, 0xc2, 0x26,
+ 0x2e, 0xab, 0x3c, 0xe2, 0xb5, 0x7a, 0x1d, 0xf6, 0x47, 0xfb, 0x16, 0x19,
+ 0xf7, 0xb0, 0xc7, 0xc8, 0x87, 0x90, 0x3b, 0x68, 0x83, 0x4f, 0xcb, 0xe2,
+ 0xd4, 0xfa, 0xc8, 0xbf, 0x85, 0xf6, 0xc9, 0xfe, 0xfb, 0x7e, 0xe0, 0xef,
+ 0xef, 0xe8, 0x0e, 0xe6, 0xde, 0x0a, 0x6d, 0x3a, 0xc2, 0x45, 0x3c, 0xc3,
+ 0xda, 0x38, 0x72, 0x92, 0xf1, 0xba, 0xa9, 0xd1, 0x3f, 0xe7, 0x3c, 0xe6,
+ 0x12, 0xcc, 0x23, 0xa6, 0x43, 0x3f, 0x27, 0xd9, 0x1c, 0xfc, 0x88, 0x8e,
+ 0xdc, 0xa2, 0x00, 0xbb, 0x31, 0x33, 0x57, 0x64, 0x46, 0xf9, 0x48, 0x89,
+ 0xb5, 0x64, 0x9e, 0x00, 0xcc, 0x7f, 0xc0, 0xe6, 0xda, 0xba, 0x43, 0x3d,
+ 0x0c, 0x7d, 0xbc, 0xf2, 0xbb, 0x80, 0xbd, 0xbc, 0x05, 0xf6, 0xdd, 0x46,
+ 0x58, 0xbc, 0xbf, 0xb8, 0xe5, 0xfd, 0x4f, 0x69, 0xbf, 0x78, 0xb7, 0x0a,
+ 0x7f, 0xda, 0x1a, 0xda, 0xfe, 0x05, 0x29, 0xc0, 0xb7, 0x9a, 0x36, 0x73,
+ 0xc7, 0xdb, 0xb0, 0x16, 0xe3, 0x1a, 0x68, 0x84, 0xbf, 0x40, 0xcc, 0x04,
+ 0xbf, 0x11, 0x13, 0x12, 0x37, 0x30, 0x3f, 0xa2, 0x9f, 0x00, 0x2c, 0xfd,
+ 0x2f, 0x61, 0x5f, 0xe9, 0x20, 0xcf, 0x0b, 0x35, 0xae, 0xa1, 0xaf, 0x12,
+ 0xdf, 0x1d, 0x6d, 0x83, 0x46, 0xf9, 0xaf, 0x19, 0x76, 0x04, 0x1b, 0xe1,
+ 0xdd, 0x0a, 0xcb, 0x7c, 0x85, 0xb8, 0xbb, 0xc3, 0x3c, 0x60, 0x4c, 0xb2,
+ 0xf5, 0x2c, 0x7e, 0x45, 0x99, 0x7c, 0x16, 0xb9, 0x98, 0xdd, 0x42, 0x5e,
+ 0x90, 0x35, 0x56, 0xc0, 0xa3, 0x68, 0xdd, 0x13, 0xbd, 0x9b, 0xc7, 0xf7,
+ 0xc5, 0x37, 0x7c, 0x25, 0x2d, 0x4d, 0xb2, 0x88, 0x15, 0xe0, 0x71, 0x6a,
+ 0x42, 0xcf, 0x24, 0x24, 0x57, 0x0b, 0xf8, 0x8b, 0x78, 0x0b, 0xff, 0xc8,
+ 0x2e, 0x64, 0xb2, 0xee, 0x07, 0x23, 0x99, 0x53, 0xcf, 0xb2, 0x90, 0x4d,
+ 0x0a, 0xba, 0x34, 0x86, 0xb5, 0x72, 0x02, 0x38, 0x18, 0x87, 0x1d, 0x3d,
+ 0x13, 0x97, 0x82, 0xc5, 0x7c, 0x41, 0xe5, 0x7a, 0x59, 0xfa, 0x01, 0x3d,
+ 0xd3, 0x86, 0x39, 0xf6, 0x1f, 0xee, 0x0e, 0x64, 0xdd, 0xc9, 0xf1, 0xb8,
+ 0x9e, 0xe9, 0xde, 0x32, 0xff, 0x7a, 0x67, 0x40, 0x9b, 0x1a, 0x63, 0xfe,
+ 0x5f, 0xb6, 0x8c, 0xbf, 0x1e, 0xdf, 0x3c, 0x7e, 0x60, 0x67, 0xa4, 0x0f,
+ 0x7a, 0xe6, 0x89, 0x90, 0x5e, 0xea, 0xe9, 0x56, 0x5a, 0x7f, 0x13, 0x7d,
+ 0x79, 0x0e, 0x38, 0x95, 0x8e, 0xff, 0x06, 0xfa, 0xb2, 0x0e, 0xfb, 0x09,
+ 0xfa, 0xd2, 0x48, 0xc3, 0x7a, 0x5d, 0x51, 0xd1, 0x91, 0x93, 0xba, 0xa3,
+ 0x7b, 0x90, 0x77, 0xa4, 0x24, 0x5f, 0x07, 0xef, 0xd6, 0xe3, 0xea, 0x3a,
+ 0x4c, 0x71, 0x03, 0x26, 0x88, 0x3b, 0xf9, 0xba, 0x8f, 0x3c, 0xae, 0x31,
+ 0x06, 0x0f, 0xa3, 0x5f, 0xc4, 0x59, 0x57, 0x64, 0xd2, 0x5b, 0xcb, 0xea,
+ 0xf6, 0xa9, 0x20, 0x0f, 0xb5, 0xbf, 0xad, 0xe5, 0x17, 0x99, 0xa3, 0xc6,
+ 0xd0, 0x57, 0xf5, 0x07, 0x62, 0xdc, 0x33, 0x5a, 0x76, 0x79, 0x0e, 0xf9,
+ 0xe9, 0x12, 0x7e, 0x67, 0xf1, 0xab, 0xe1, 0x17, 0xd5, 0x01, 0x2f, 0xa0,
+ 0x8e, 0x50, 0xfe, 0x1e, 0xb1, 0x29, 0xd8, 0xff, 0x67, 0x4b, 0xc8, 0x8f,
+ 0xe7, 0x12, 0xf2, 0x94, 0xad, 0xf7, 0xea, 0x81, 0x8f, 0xcb, 0x22, 0xb7,
+ 0xb6, 0x2e, 0xcb, 0x97, 0xc2, 0x1c, 0x4d, 0xe4, 0x9d, 0x0a, 0x64, 0xb9,
+ 0xff, 0x48, 0xe8, 0x9f, 0xbe, 0xf6, 0xa0, 0xab, 0x7c, 0x79, 0x98, 0x83,
+ 0xc1, 0xef, 0x64, 0x15, 0xd4, 0x1b, 0xe0, 0x8f, 0x26, 0xef, 0x41, 0x8f,
+ 0xdf, 0xa9, 0xb4, 0x83, 0x1e, 0x5b, 0x0a, 0xc7, 0x90, 0xbb, 0x68, 0x83,
+ 0xd6, 0x36, 0xad, 0x1d, 0x79, 0x18, 0xfc, 0x8e, 0x1a, 0x93, 0x67, 0x17,
+ 0xa7, 0x16, 0xca, 0x3a, 0x60, 0xc1, 0xf3, 0x51, 0xf4, 0xa1, 0x7f, 0x97,
+ 0x2a, 0x5c, 0xa7, 0xcb, 0xbb, 0x15, 0x43, 0x7e, 0x8e, 0xbc, 0xee, 0x3d,
+ 0xfb, 0xe2, 0x14, 0x6c, 0xb0, 0x0f, 0xf1, 0x0a, 0xb5, 0xd0, 0x1e, 0xc6,
+ 0x8c, 0x01, 0x13, 0xcf, 0x3c, 0x7e, 0x87, 0x91, 0xe7, 0x5d, 0x7b, 0xcd,
+ 0x27, 0xc1, 0x93, 0xb6, 0x18, 0xd6, 0x10, 0xde, 0x04, 0x6d, 0x5d, 0xd0,
+ 0xc1, 0xb4, 0x35, 0x21, 0xdd, 0x96, 0xca, 0x9d, 0x34, 0xce, 0x07, 0x7e,
+ 0xf2, 0xe3, 0xf3, 0xe4, 0xb3, 0x01, 0x1d, 0xe2, 0x98, 0xef, 0xe8, 0xcf,
+ 0x89, 0x2f, 0x7d, 0x30, 0x8b, 0xc3, 0x5c, 0xaa, 0x04, 0xfd, 0x68, 0x4e,
+ 0xb4, 0x28, 0xa6, 0xd2, 0x4f, 0xe7, 0x61, 0xab, 0x1c, 0x8f, 0x8b, 0x92,
+ 0xc1, 0x26, 0x79, 0x52, 0x8f, 0x56, 0xa7, 0x66, 0x6c, 0xca, 0xd5, 0x92,
+ 0xe9, 0x72, 0x24, 0x57, 0xca, 0x08, 0x75, 0x66, 0xe5, 0xdb, 0x90, 0xab,
+ 0x1e, 0xd6, 0x20, 0xf0, 0x03, 0x73, 0x94, 0x2f, 0xea, 0xc4, 0x0a, 0xf2,
+ 0xb0, 0x8a, 0xc4, 0x83, 0x1a, 0xea, 0x19, 0xd4, 0x1d, 0x90, 0x5f, 0x79,
+ 0x0e, 0x38, 0x12, 0x78, 0x2e, 0xe1, 0x99, 0xc4, 0xf3, 0x2c, 0x9e, 0xfd,
+ 0x78, 0xd6, 0x68, 0x1f, 0x61, 0xde, 0xf3, 0x31, 0x7a, 0x60, 0x27, 0x79,
+ 0xda, 0xb4, 0x7c, 0xaf, 0x9e, 0x91, 0xbf, 0xad, 0x1f, 0x94, 0xbf, 0xa9,
+ 0x8f, 0xca, 0x5f, 0xd7, 0x1d, 0x79, 0xb9, 0xbe, 0x5f, 0xfe, 0xaa, 0x3e,
+ 0xcc, 0x9a, 0x10, 0x39, 0x5c, 0x0a, 0xbe, 0xf9, 0xbc, 0x3c, 0xe8, 0xd5,
+ 0xe1, 0x73, 0x28, 0xff, 0x8b, 0x53, 0xd9, 0xda, 0x75, 0x52, 0x78, 0xd6,
+ 0x42, 0x9e, 0x69, 0xb0, 0x2e, 0x93, 0xc7, 0x9c, 0x3b, 0xe2, 0x94, 0xbd,
+ 0x6e, 0xb3, 0x4e, 0x39, 0x49, 0x38, 0xd4, 0xbb, 0x1a, 0xf2, 0x97, 0x16,
+ 0x99, 0x48, 0xa4, 0x57, 0x5c, 0x23, 0x19, 0xfa, 0xa3, 0x3b, 0x01, 0x87,
+ 0x3d, 0xbd, 0x0e, 0x59, 0x7b, 0x1e, 0xb6, 0xe0, 0xa0, 0x56, 0x4e, 0xc4,
+ 0xe0, 0xfb, 0x54, 0x7e, 0xa2, 0x7c, 0x4b, 0xe0, 0x4b, 0xa3, 0x9a, 0x91,
+ 0x73, 0xd9, 0x70, 0x8e, 0xf1, 0xd1, 0x02, 0xec, 0x72, 0x18, 0x43, 0xb6,
+ 0xe2, 0xa4, 0x6f, 0x3c, 0x16, 0xfa, 0xc7, 0x15, 0x39, 0xe1, 0x0d, 0x66,
+ 0xaf, 0x20, 0xf6, 0x68, 0x2d, 0x51, 0x5e, 0xb4, 0x0b, 0xb4, 0xf9, 0xfe,
+ 0xdd, 0xac, 0xbf, 0xe3, 0xa6, 0xfc, 0x70, 0x36, 0x6d, 0x3d, 0xa2, 0xcf,
+ 0x40, 0xce, 0xbe, 0x7f, 0xd4, 0x4e, 0x9f, 0x9a, 0xd0, 0x3b, 0xe5, 0x27,
+ 0xcf, 0x30, 0x26, 0xaf, 0x4e, 0x7d, 0x1f, 0x7a, 0x50, 0x5d, 0x6a, 0x95,
+ 0x6a, 0xd5, 0x94, 0x4b, 0x23, 0x83, 0x6a, 0xdf, 0x6a, 0x2d, 0x8e, 0x3c,
+ 0xaf, 0x4d, 0xa6, 0xfb, 0x94, 0xb2, 0xc3, 0x6f, 0x0f, 0x2b, 0xbf, 0xed,
+ 0xda, 0x78, 0xd6, 0x92, 0xd6, 0x66, 0x5a, 0x5e, 0x96, 0x82, 0x07, 0x1d,
+ 0x8b, 0xef, 0x02, 0x4f, 0xd8, 0x1f, 0xb4, 0x0a, 0x3a, 0x62, 0xa0, 0x39,
+ 0x68, 0x3d, 0xa8, 0xff, 0xd2, 0xff, 0x1d, 0x93, 0x7c, 0x7c, 0x1b, 0xb1,
+ 0x85, 0xb1, 0x52, 0x53, 0x7a, 0xb7, 0xb0, 0xf4, 0x53, 0x8b, 0xfe, 0x65,
+ 0xa5, 0xb6, 0x2b, 0x1c, 0xd3, 0xbf, 0x73, 0xdc, 0x2e, 0x2f, 0x57, 0xb7,
+ 0xcb, 0x62, 0x95, 0xef, 0x5b, 0x65, 0xa1, 0x3a, 0x78, 0xa5, 0x57, 0xef,
+ 0x93, 0xd5, 0xeb, 0x6e, 0xb4, 0xee, 0xd7, 0xc1, 0x93, 0x63, 0x1f, 0xc9,
+ 0x07, 0x23, 0xdd, 0xf2, 0xd6, 0x7d, 0xe9, 0x17, 0xfe, 0x44, 0x87, 0x3e,
+ 0x8e, 0x74, 0xd0, 0xce, 0xd0, 0xe7, 0x7c, 0xfa, 0x4a, 0x56, 0xa7, 0x9e,
+ 0xfd, 0x00, 0xfa, 0x95, 0xae, 0x04, 0x3a, 0x49, 0xdc, 0xc4, 0x0b, 0xf9,
+ 0xd8, 0x6f, 0x00, 0x27, 0xde, 0xd5, 0x06, 0x81, 0xeb, 0x0d, 0xc5, 0x8b,
+ 0xbb, 0x9d, 0xf4, 0x15, 0x84, 0x28, 0xff, 0x92, 0x3d, 0x38, 0x3c, 0xa0,
+ 0xef, 0x92, 0x6a, 0xf2, 0x46, 0xeb, 0xbb, 0x88, 0x07, 0xd9, 0x44, 0xfa,
+ 0xd4, 0x45, 0x59, 0x9d, 0xba, 0x60, 0x53, 0x17, 0x69, 0xc3, 0xff, 0x80,
+ 0x9c, 0xd4, 0x92, 0x4a, 0x8d, 0xbe, 0x8b, 0xb8, 0x58, 0x17, 0xec, 0xb5,
+ 0x4e, 0x80, 0x06, 0x77, 0x3f, 0xde, 0x61, 0xde, 0xf8, 0x3c, 0xe5, 0xd6,
+ 0xc2, 0xb5, 0xc3, 0x59, 0xbd, 0x7f, 0x0b, 0x8f, 0x06, 0xad, 0x43, 0x3a,
+ 0xf7, 0xfb, 0x2f, 0xec, 0xfb, 0x3e, 0x68, 0x1d, 0xc4, 0x5a, 0xc4, 0xd0,
+ 0x64, 0xe3, 0x1e, 0x3f, 0x52, 0x7b, 0x3c, 0x5b, 0x43, 0x0e, 0xb8, 0xbe,
+ 0x07, 0xe6, 0x6a, 0x3a, 0xce, 0x69, 0x2a, 0xb9, 0x5c, 0x1a, 0x21, 0x7f,
+ 0x6f, 0xef, 0x61, 0x2c, 0x37, 0x32, 0x2f, 0x85, 0x79, 0x46, 0x4c, 0x7e,
+ 0x8c, 0xba, 0x6b, 0x12, 0xfe, 0x7f, 0x61, 0xef, 0x20, 0x68, 0x40, 0x7d,
+ 0x9a, 0x54, 0xf1, 0x7c, 0xca, 0x05, 0x8e, 0x9c, 0xc2, 0xfd, 0xa6, 0x2c,
+ 0x01, 0xf7, 0x38, 0xf9, 0x00, 0xdc, 0x33, 0x9c, 0x57, 0x32, 0xc0, 0x7c,
+ 0x2d, 0x05, 0xbc, 0xbd, 0xa1, 0xff, 0x8b, 0x43, 0x57, 0xf7, 0x59, 0x77,
+ 0x4b, 0x2c, 0xf4, 0x7f, 0x71, 0x79, 0xeb, 0x79, 0xe8, 0x7d, 0x9c, 0xfa,
+ 0x93, 0xe8, 0xd9, 0xd0, 0x9f, 0x46, 0xfc, 0xad, 0x92, 0xaf, 0xc4, 0x80,
+ 0x17, 0x39, 0xf7, 0x28, 0xf1, 0x62, 0x5c, 0xa5, 0x2e, 0x17, 0x43, 0x5d,
+ 0xee, 0x08, 0x71, 0xaf, 0x41, 0x97, 0xd3, 0xa9, 0x55, 0x9d, 0xf5, 0xd5,
+ 0x4e, 0x55, 0xf3, 0x1a, 0xb0, 0xaf, 0x42, 0x99, 0xb1, 0x88, 0xb6, 0x75,
+ 0x71, 0x6a, 0x12, 0x35, 0x6c, 0xa1, 0x7c, 0x50, 0x2f, 0xd4, 0x47, 0xf5,
+ 0x82, 0x47, 0x7d, 0xdb, 0x6b, 0x2d, 0x28, 0x1e, 0x27, 0x65, 0xa1, 0xfe,
+ 0x81, 0x5f, 0xda, 0xbb, 0x0d, 0x7d, 0xe8, 0xfe, 0x38, 0xe5, 0x7b, 0x3d,
+ 0xe9, 0x42, 0x50, 0x27, 0xbf, 0x13, 0x72, 0x66, 0xe8, 0x7b, 0xdd, 0xcc,
+ 0xd1, 0x96, 0x87, 0x88, 0x1f, 0x74, 0x24, 0x12, 0xb2, 0xe8, 0x71, 0x8f,
+ 0xd5, 0x29, 0xf2, 0xb2, 0x30, 0x67, 0xc9, 0x09, 0x25, 0x3f, 0x9e, 0x9b,
+ 0xf7, 0x47, 0x86, 0x4c, 0xc6, 0x07, 0xad, 0x47, 0x25, 0x7d, 0x65, 0xcd,
+ 0x48, 0xbf, 0x30, 0x81, 0xb8, 0xba, 0x30, 0x6f, 0x88, 0xab, 0xea, 0x30,
+ 0xca, 0x28, 0x5d, 0x81, 0x35, 0x86, 0x67, 0xbf, 0xa7, 0xe1, 0xec, 0x5d,
+ 0x72, 0xe1, 0xf9, 0xcf, 0xc3, 0xee, 0x5f, 0x81, 0x2c, 0xcc, 0xd4, 0x71,
+ 0xe4, 0x19, 0xcf, 0xc9, 0xa0, 0x55, 0x42, 0xfe, 0x0c, 0xbe, 0xa3, 0xbd,
+ 0xa2, 0x6c, 0x60, 0x41, 0xc7, 0xb8, 0x9f, 0x7c, 0xe2, 0x78, 0xb7, 0x2c,
+ 0xf4, 0x05, 0x36, 0xce, 0x77, 0x03, 0xc0, 0x11, 0xbc, 0xe3, 0xf8, 0xb7,
+ 0x64, 0x40, 0xbd, 0xab, 0xaa, 0x75, 0x25, 0xe9, 0x0d, 0xe5, 0xf7, 0x18,
+ 0xf6, 0x24, 0x8f, 0xa3, 0xf9, 0x4e, 0x09, 0x6c, 0x29, 0xe2, 0xbb, 0x25,
+ 0x47, 0x6b, 0x09, 0xb9, 0xa7, 0x96, 0x94, 0x2f, 0xd7, 0xfa, 0x25, 0x0f,
+ 0x39, 0x4e, 0x8e, 0x3e, 0xd9, 0xc3, 0xb3, 0xe5, 0x96, 0xd2, 0x2f, 0x88,
+ 0x4e, 0x5a, 0xab, 0x72, 0xdc, 0x8b, 0xe8, 0xe9, 0x08, 0xe9, 0x33, 0xc3,
+ 0x71, 0x2c, 0xa4, 0xa1, 0x11, 0x5f, 0x07, 0x70, 0x65, 0x81, 0xe7, 0xa5,
+ 0x10, 0x0f, 0xfd, 0x08, 0x68, 0x3d, 0x96, 0x94, 0x25, 0x8f, 0x74, 0x6c,
+ 0x97, 0x52, 0x82, 0xfd, 0x57, 0xa0, 0x6f, 0xc4, 0xb3, 0x8d, 0xf9, 0xcd,
+ 0x26, 0x1e, 0x3f, 0x5c, 0x2b, 0x82, 0xc7, 0xe4, 0x2f, 0xe1, 0xe0, 0xaf,
+ 0xbf, 0x40, 0xf9, 0xed, 0x43, 0x8e, 0x6f, 0x07, 0xba, 0x69, 0x6d, 0xec,
+ 0x99, 0x9f, 0xeb, 0x82, 0xac, 0xb8, 0x6f, 0xbb, 0x1c, 0x83, 0xdd, 0xe7,
+ 0xaa, 0xdc, 0xff, 0x18, 0xf4, 0xe8, 0x2d, 0xb5, 0x7f, 0x7e, 0xa9, 0x2f,
+ 0x5c, 0xcf, 0xb5, 0x5d, 0x5b, 0xd6, 0xb6, 0xca, 0xa1, 0x8a, 0x75, 0x8d,
+ 0xf5, 0xbf, 0x8f, 0xf5, 0xba, 0x9c, 0x1e, 0xe5, 0x7a, 0xe2, 0x01, 0x5c,
+ 0x35, 0xf1, 0x29, 0x78, 0xe2, 0xaa, 0xde, 0xcf, 0x55, 0x5b, 0x25, 0x57,
+ 0x89, 0x70, 0x11, 0xcf, 0x47, 0xa8, 0x87, 0xbf, 0xaa, 0x70, 0x4d, 0x2a,
+ 0x5c, 0x78, 0x5f, 0xa5, 0xcf, 0xb9, 0x15, 0xeb, 0x3b, 0xe8, 0xff, 0xa5,
+ 0x14, 0xef, 0x94, 0x92, 0xaa, 0xe9, 0xdb, 0x95, 0xaf, 0x29, 0xc5, 0xdb,
+ 0xf0, 0xbe, 0x13, 0x36, 0xbf, 0x0f, 0xb9, 0x45, 0x17, 0xeb, 0xdc, 0x2d,
+ 0x73, 0x5b, 0xe9, 0x8f, 0x6d, 0xa1, 0x3f, 0x06, 0xb8, 0x5e, 0xec, 0x19,
+ 0xc0, 0xe5, 0x01, 0x37, 0x3d, 0x07, 0x3e, 0x3b, 0xf4, 0x2b, 0x8c, 0x93,
+ 0xd7, 0x29, 0x5a, 0xa6, 0x97, 0xfe, 0x1b, 0xe7, 0xea, 0xc3, 0xda, 0x68,
+ 0x1c, 0xf0, 0xe1, 0x69, 0xe0, 0x99, 0xab, 0xaa, 0xbb, 0x0b, 0xc8, 0x60,
+ 0x7b, 0x9c, 0x67, 0x2f, 0x55, 0x3f, 0x8b, 0x67, 0xd7, 0x35, 0xf0, 0x8b,
+ 0xbc, 0x22, 0xbd, 0xa4, 0x95, 0xf7, 0x48, 0xb0, 0x37, 0x07, 0x7a, 0x1c,
+ 0x37, 0x24, 0x3f, 0x6a, 0x21, 0x3f, 0xe7, 0x3d, 0x2c, 0xed, 0xd2, 0xe2,
+ 0xdd, 0x67, 0x4c, 0xb7, 0x19, 0x6b, 0x4d, 0x75, 0xf6, 0xe3, 0x4b, 0xbc,
+ 0x8b, 0x4d, 0xf1, 0xee, 0x6e, 0x98, 0xd7, 0x18, 0x8f, 0x2c, 0xd9, 0xf2,
+ 0x78, 0x6d, 0x58, 0x1e, 0xad, 0xa5, 0xad, 0xfb, 0xe1, 0x03, 0x0a, 0xeb,
+ 0x77, 0xb4, 0x43, 0x71, 0xfa, 0x2f, 0x13, 0x79, 0x60, 0x8b, 0x1d, 0xe4,
+ 0x05, 0x25, 0xd6, 0x6c, 0x73, 0x69, 0xde, 0xe3, 0x58, 0x55, 0xd9, 0x9a,
+ 0x3b, 0xfc, 0x5f, 0xe6, 0x0d, 0xdc, 0x9f, 0xfe, 0x1a, 0x79, 0x82, 0x87,
+ 0x3c, 0xc1, 0x43, 0x9e, 0xe0, 0x21, 0x4f, 0xf0, 0x90, 0x27, 0x78, 0xc8,
+ 0x13, 0x3c, 0xe4, 0x09, 0x1e, 0xf2, 0x04, 0xc4, 0xee, 0xa0, 0x5e, 0x18,
+ 0x43, 0xfe, 0x0b, 0xff, 0xe5, 0xdd, 0x06, 0x3e, 0xf1, 0xfe, 0x92, 0x31,
+ 0x87, 0xb1, 0x99, 0x73, 0xab, 0xdb, 0x5c, 0xca, 0x4d, 0xf9, 0xbe, 0x3b,
+ 0x31, 0x37, 0x1e, 0xe6, 0x23, 0x84, 0x89, 0x62, 0x37, 0xe1, 0xe4, 0xa0,
+ 0xeb, 0x68, 0xb0, 0x31, 0xe6, 0x2b, 0x41, 0xcc, 0x0a, 0x72, 0xe5, 0xb7,
+ 0x91, 0xb3, 0xa4, 0x90, 0xb3, 0xf4, 0x23, 0x3f, 0xe1, 0x9d, 0x75, 0x74,
+ 0xc7, 0x94, 0xd5, 0x8e, 0x7a, 0x63, 0xda, 0x3d, 0x1e, 0x73, 0x69, 0x3b,
+ 0x55, 0xd0, 0xf5, 0xb9, 0x5e, 0xf1, 0x25, 0x37, 0xf2, 0x4d, 0xe4, 0xad,
+ 0xcf, 0xa9, 0xfb, 0xb4, 0xf1, 0x21, 0xca, 0xbc, 0xf2, 0x09, 0xb9, 0x6b,
+ 0xc4, 0xdf, 0xe0, 0x1e, 0x50, 0x5f, 0x20, 0xff, 0x44, 0x7a, 0xce, 0x81,
+ 0xe1, 0xe7, 0x62, 0x12, 0x3f, 0xb3, 0x1d, 0x73, 0x96, 0xf4, 0xaa, 0xbb,
+ 0x24, 0x88, 0xf2, 0xdc, 0x55, 0xc8, 0xcb, 0x16, 0xfd, 0x1c, 0x6f, 0x1c,
+ 0x88, 0x97, 0xfe, 0x75, 0x65, 0x2a, 0x57, 0x5d, 0x51, 0x3a, 0x75, 0xb4,
+ 0x96, 0x47, 0x7d, 0xd4, 0xd3, 0x2b, 0xed, 0x26, 0x6a, 0xab, 0x08, 0x37,
+ 0x71, 0xfe, 0x32, 0xae, 0x6a, 0x9e, 0x73, 0xeb, 0xf2, 0x84, 0xac, 0xb9,
+ 0xcf, 0xca, 0x54, 0xa9, 0x92, 0x4e, 0xb2, 0x56, 0xce, 0x5a, 0x2b, 0x53,
+ 0x27, 0x81, 0x63, 0x11, 0xb9, 0x81, 0xa1, 0xf6, 0x5e, 0x99, 0x9a, 0xae,
+ 0x04, 0xf7, 0x59, 0x01, 0x0d, 0x8c, 0x57, 0xed, 0x62, 0x2c, 0x04, 0xf7,
+ 0x5a, 0xba, 0x5a, 0xcb, 0x75, 0x5c, 0x6f, 0x62, 0x1d, 0xe5, 0x36, 0x8c,
+ 0xb5, 0x94, 0x1d, 0x69, 0x58, 0x99, 0x2a, 0x56, 0x1b, 0x69, 0x20, 0x1e,
+ 0xe2, 0x8d, 0xce, 0xc3, 0xb3, 0xc4, 0x45, 0x3f, 0xe3, 0xfb, 0x85, 0x91,
+ 0xfe, 0x30, 0xef, 0x3a, 0x89, 0xfc, 0xce, 0x0c, 0xf4, 0x5c, 0x8d, 0xbf,
+ 0xa3, 0xe2, 0x54, 0x4a, 0xe7, 0x3c, 0x9f, 0x78, 0x37, 0xba, 0x80, 0x39,
+ 0x8c, 0x17, 0x23, 0x58, 0x3d, 0x84, 0xed, 0x6c, 0xe0, 0x67, 0x4b, 0xb8,
+ 0x1f, 0x69, 0xe2, 0x39, 0x2f, 0x61, 0x2f, 0xd2, 0x45, 0x98, 0x38, 0x68,
+ 0x83, 0x2c, 0xbd, 0xff, 0x2d, 0xef, 0x1b, 0xcf, 0x44, 0x9e, 0x9a, 0x58,
+ 0x43, 0x78, 0xe2, 0x88, 0xd6, 0xe0, 0xc5, 0xb9, 0x60, 0x9d, 0xbe, 0x7e,
+ 0xff, 0xf7, 0x69, 0xfb, 0x36, 0xd2, 0x1a, 0xed, 0x1f, 0xe1, 0x19, 0x0e,
+ 0xe4, 0xb6, 0xbe, 0x5e, 0xfd, 0x9f, 0x61, 0x78, 0x42, 0x17, 0x3f, 0x76,
+ 0x8f, 0x3a, 0xdc, 0x50, 0x87, 0x46, 0xf7, 0x17, 0xbc, 0x0f, 0x60, 0x7d,
+ 0xcf, 0x6f, 0x07, 0x8d, 0xb5, 0xe2, 0xcb, 0x61, 0x2c, 0xdb, 0x29, 0x59,
+ 0x93, 0x75, 0xc3, 0xf9, 0x70, 0xbc, 0x03, 0xb1, 0x8d, 0xe3, 0x3a, 0xf8,
+ 0x0b, 0x5d, 0x76, 0xda, 0xc3, 0xba, 0x25, 0x1e, 0x7c, 0xe3, 0x19, 0xa6,
+ 0x1d, 0xb1, 0xee, 0x6b, 0x0b, 0xe7, 0x22, 0x3b, 0xa2, 0x1f, 0x36, 0xc3,
+ 0x39, 0xfa, 0x5b, 0x1d, 0xb5, 0x0b, 0xfb, 0xc0, 0xb3, 0xd8, 0x68, 0x4b,
+ 0xd1, 0x33, 0x2e, 0x67, 0xe7, 0x23, 0xbf, 0x05, 0x9f, 0x32, 0x64, 0x86,
+ 0xbe, 0xbf, 0x03, 0xbe, 0xaf, 0x4b, 0x0e, 0xc1, 0x67, 0x1d, 0x86, 0xcf,
+ 0x3a, 0x82, 0x7a, 0x71, 0x6c, 0xa9, 0xf1, 0x9e, 0x97, 0x35, 0x6a, 0x97,
+ 0x76, 0x5c, 0xc9, 0xbf, 0xe8, 0x1b, 0xf6, 0x47, 0xd0, 0x01, 0xd6, 0x5d,
+ 0x91, 0x4e, 0xc0, 0xdf, 0x3a, 0x71, 0xe8, 0xc4, 0xd6, 0xfb, 0xe4, 0x61,
+ 0xd8, 0x46, 0x7b, 0x56, 0xc5, 0x86, 0xa5, 0x80, 0xf7, 0xa5, 0x6a, 0xc0,
+ 0x7b, 0xf8, 0x65, 0xe0, 0x37, 0xa5, 0x58, 0xb3, 0xa4, 0x88, 0x7d, 0x8b,
+ 0xd8, 0xb7, 0x88, 0x3a, 0x6f, 0xba, 0xd6, 0xf8, 0x1d, 0xab, 0x33, 0xa4,
+ 0x9d, 0x6b, 0xa3, 0xbe, 0xd5, 0x70, 0xfe, 0xe8, 0x79, 0x0a, 0xfc, 0x7f,
+ 0x0c, 0xfc, 0x3f, 0x81, 0xfa, 0xe6, 0x8f, 0x50, 0xdf, 0x7c, 0x0d, 0xf5,
+ 0xcd, 0x71, 0xd4, 0x37, 0x13, 0xa8, 0x6f, 0xbe, 0x0a, 0xff, 0xf1, 0x15,
+ 0xf8, 0x8f, 0x63, 0xf0, 0x1f, 0xe3, 0xea, 0xee, 0xe9, 0xa8, 0xb7, 0xf5,
+ 0x4e, 0x25, 0xda, 0x8b, 0xed, 0x67, 0x22, 0x76, 0x11, 0x67, 0x1a, 0x93,
+ 0x6a, 0x9d, 0xf5, 0x8d, 0x23, 0xee, 0x41, 0xd6, 0x37, 0xc7, 0xb4, 0x09,
+ 0xe4, 0xef, 0xf7, 0xef, 0x67, 0xdd, 0x13, 0xd7, 0x72, 0xaa, 0xee, 0x49,
+ 0x9f, 0x77, 0x91, 0x22, 0x21, 0xf7, 0xc3, 0x99, 0xd3, 0x67, 0x73, 0xa0,
+ 0x25, 0xc8, 0xf9, 0x7a, 0x42, 0xbf, 0xd7, 0x21, 0x8b, 0xb3, 0xa8, 0x19,
+ 0xbc, 0x1f, 0x6b, 0x05, 0xe5, 0x1b, 0x2d, 0x8c, 0x51, 0x2b, 0x7b, 0xff,
+ 0x1c, 0x8e, 0x47, 0x64, 0x72, 0x1e, 0xb5, 0xed, 0xf3, 0xff, 0xa8, 0xe5,
+ 0xd4, 0xd8, 0xc1, 0x18, 0xf9, 0xee, 0xf3, 0x7f, 0x1f, 0x8e, 0x8b, 0xa1,
+ 0x3e, 0x84, 0xb4, 0x5a, 0x0e, 0x9e, 0xdd, 0x61, 0xce, 0xf1, 0x6a, 0xef,
+ 0xe6, 0xff, 0xd3, 0x8e, 0xad, 0x45, 0x13, 0xfb, 0x1b, 0x3b, 0x82, 0xfa,
+ 0xac, 0x71, 0xbe, 0xab, 0x61, 0xfe, 0x8a, 0xfa, 0xce, 0x5a, 0x28, 0xb7,
+ 0xfd, 0x0a, 0x1e, 0x58, 0x96, 0x86, 0x98, 0xe7, 0x7d, 0xe4, 0xf3, 0xfb,
+ 0x9f, 0xab, 0xb7, 0xab, 0x6f, 0x72, 0xae, 0xca, 0xb7, 0x61, 0xe7, 0x23,
+ 0xa5, 0x1d, 0x81, 0x2f, 0x60, 0x3f, 0xa1, 0x05, 0xfe, 0xfd, 0x8f, 0x81,
+ 0x07, 0xbc, 0xf6, 0x1a, 0x6b, 0x38, 0x2b, 0xbc, 0x4b, 0xb9, 0x32, 0xc5,
+ 0xdc, 0xba, 0xa4, 0x70, 0xb3, 0xd6, 0x63, 0xdd, 0x17, 0xc5, 0x80, 0x08,
+ 0xd7, 0xcf, 0x13, 0x01, 0xdd, 0xe3, 0xa8, 0xe9, 0x08, 0x13, 0x8d, 0x1b,
+ 0xeb, 0xbf, 0x8e, 0xf0, 0x1e, 0xee, 0x4a, 0x90, 0x57, 0x29, 0x7c, 0x66,
+ 0x88, 0xef, 0x3f, 0xfd, 0xc0, 0xf7, 0x70, 0xbd, 0xd5, 0xb0, 0xfe, 0x3c,
+ 0x72, 0x3d, 0xde, 0x99, 0xec, 0x52, 0xdf, 0x19, 0xdf, 0x9f, 0xed, 0x94,
+ 0x5f, 0x3c, 0xe3, 0xfb, 0xe3, 0x4e, 0x7a, 0xf8, 0x4d, 0xd4, 0x1e, 0x67,
+ 0x68, 0x27, 0x23, 0xa4, 0x73, 0x30, 0x35, 0x2d, 0x03, 0xbd, 0x41, 0x2e,
+ 0xfe, 0x75, 0xed, 0xe3, 0x74, 0xeb, 0xe1, 0x3e, 0x3f, 0x6c, 0xd8, 0x27,
+ 0xd5, 0xb0, 0xcf, 0x0a, 0x6d, 0xb6, 0x7a, 0x2f, 0xce, 0x5c, 0xdc, 0x75,
+ 0xa3, 0x95, 0x08, 0xeb, 0xb2, 0x47, 0x47, 0xda, 0xa4, 0xd2, 0x97, 0x5e,
+ 0xf9, 0x11, 0xf2, 0xf5, 0xc2, 0x08, 0xe6, 0x12, 0x83, 0x78, 0xc7, 0xf9,
+ 0x74, 0x15, 0xb9, 0xe8, 0x4a, 0x55, 0x86, 0xb0, 0x3e, 0x5d, 0x14, 0xe1,
+ 0x3c, 0xfb, 0x8a, 0xb6, 0x6a, 0xe8, 0x03, 0x92, 0x6b, 0x38, 0xf3, 0x04,
+ 0xea, 0xaf, 0x13, 0xeb, 0xf5, 0x30, 0xf7, 0xb9, 0x59, 0x5b, 0x53, 0xb9,
+ 0xf1, 0x01, 0xad, 0x98, 0x08, 0xce, 0xf8, 0x87, 0xf0, 0x17, 0x86, 0xce,
+ 0xb5, 0xef, 0x03, 0xb7, 0x26, 0x0b, 0xcf, 0x18, 0xea, 0x0e, 0xb6, 0x30,
+ 0x42, 0x59, 0xf3, 0x79, 0x2d, 0xde, 0x45, 0x67, 0xfa, 0xf3, 0xf0, 0x4c,
+ 0xd9, 0xb0, 0x9e, 0x8e, 0xce, 0x14, 0x93, 0x77, 0x67, 0x2d, 0xac, 0xfd,
+ 0x1c, 0xf8, 0x91, 0x97, 0xa5, 0x7a, 0xea, 0x33, 0xf0, 0x94, 0x1b, 0x78,
+ 0x63, 0x6e, 0x91, 0x61, 0x71, 0xa3, 0x86, 0x1f, 0x4f, 0xc2, 0x0e, 0xbf,
+ 0xd1, 0x1b, 0xdd, 0x0d, 0x1b, 0xb6, 0xcf, 0xba, 0x07, 0x8d, 0xf3, 0xfd,
+ 0xb0, 0xc5, 0x14, 0xec, 0x93, 0x39, 0x53, 0x9e, 0xb5, 0x0a, 0xed, 0xc9,
+ 0x72, 0x8d, 0xb4, 0x75, 0x4c, 0x86, 0x51, 0xef, 0xf0, 0xfc, 0x19, 0x59,
+ 0xac, 0x47, 0x34, 0x8c, 0xc2, 0x1e, 0x0f, 0xe2, 0xb7, 0x1f, 0xef, 0x1c,
+ 0xfc, 0x58, 0x2b, 0xad, 0xc8, 0xe3, 0x2a, 0x17, 0x47, 0xae, 0x3d, 0x44,
+ 0xfa, 0xee, 0x04, 0x3c, 0xf5, 0x99, 0x7a, 0x7a, 0xa7, 0xb8, 0x7d, 0xf4,
+ 0x15, 0x49, 0xe0, 0xc6, 0x1a, 0xef, 0x22, 0x6c, 0xbd, 0x1f, 0xcf, 0xb4,
+ 0x55, 0x20, 0x6f, 0x15, 0x7e, 0xdf, 0x37, 0x46, 0xf9, 0x8d, 0xe2, 0x7c,
+ 0x38, 0x1e, 0xb4, 0xbe, 0x4c, 0xdd, 0x4b, 0xee, 0x96, 0x95, 0xf9, 0x28,
+ 0x0e, 0x9e, 0x86, 0x0d, 0xf2, 0xce, 0x76, 0x0c, 0x7c, 0xe1, 0x58, 0x0b,
+ 0xe3, 0x21, 0xe6, 0x17, 0x97, 0x71, 0xee, 0x8c, 0x9c, 0x41, 0xfd, 0x2f,
+ 0x7d, 0x7c, 0xa6, 0x80, 0x7f, 0x7b, 0xa8, 0xef, 0x9b, 0xd7, 0x1b, 0x36,
+ 0xfb, 0x63, 0xa0, 0xcf, 0x6c, 0x58, 0xcf, 0x35, 0x41, 0x7d, 0xb2, 0x26,
+ 0x88, 0xc7, 0x49, 0xff, 0x76, 0x3d, 0xf3, 0xa2, 0x3c, 0xa0, 0xce, 0x54,
+ 0x93, 0xe3, 0xf3, 0xbe, 0xef, 0x8e, 0x0e, 0x0e, 0x2f, 0x4a, 0x7a, 0xf8,
+ 0xa4, 0xec, 0xb3, 0x0e, 0xb1, 0x1e, 0xb3, 0x88, 0xc7, 0xbf, 0xbd, 0x25,
+ 0xe3, 0xfb, 0xa7, 0x41, 0xfb, 0xf7, 0xd5, 0x3e, 0x2f, 0x82, 0x7e, 0xf0,
+ 0x4a, 0xd5, 0x24, 0xa4, 0x15, 0xcf, 0x04, 0xe9, 0x2d, 0xcb, 0xf1, 0xfa,
+ 0x85, 0x50, 0x36, 0x8f, 0x89, 0xeb, 0x5d, 0x36, 0x5c, 0xbb, 0x0c, 0xd8,
+ 0x85, 0x90, 0xb6, 0x0c, 0xe8, 0xc5, 0xfe, 0xf5, 0xb7, 0x13, 0xf4, 0x0d,
+ 0x94, 0xb9, 0x8b, 0xac, 0xd1, 0x1d, 0x41, 0x1e, 0x95, 0xf8, 0x24, 0x3f,
+ 0x10, 0x97, 0xcd, 0x7e, 0x80, 0xeb, 0xe2, 0xd7, 0xd0, 0x15, 0xd2, 0x51,
+ 0x54, 0xfe, 0x53, 0xc5, 0x2d, 0x85, 0xcf, 0xd8, 0xe2, 0x0b, 0x2a, 0xea,
+ 0xb9, 0x6a, 0xd0, 0x37, 0x31, 0xfe, 0x51, 0x87, 0xbb, 0xe0, 0xff, 0xa0,
+ 0x83, 0xb0, 0xe3, 0xdc, 0x3c, 0xef, 0x27, 0x86, 0x78, 0xaf, 0x74, 0x36,
+ 0x0f, 0xd9, 0x2e, 0xf0, 0xfb, 0x63, 0x22, 0xa8, 0x31, 0x83, 0xfa, 0x2b,
+ 0x45, 0x5f, 0x88, 0xb6, 0xa4, 0xfc, 0x64, 0x5e, 0x7d, 0x6f, 0x8c, 0x03,
+ 0xc6, 0xa7, 0xef, 0x6c, 0xf8, 0x9b, 0x89, 0x1f, 0x64, 0x83, 0xbf, 0x99,
+ 0x08, 0xbf, 0xfd, 0x56, 0x83, 0x3c, 0xe2, 0xe1, 0x9a, 0x29, 0x13, 0xb5,
+ 0xe8, 0x6f, 0x28, 0x28, 0x07, 0xf8, 0xe6, 0x5a, 0x94, 0x3b, 0xf8, 0x41,
+ 0x4d, 0xb3, 0x49, 0x96, 0x4b, 0x61, 0x4e, 0xc4, 0x1a, 0x80, 0x3c, 0xc4,
+ 0x78, 0x31, 0xaa, 0x2f, 0x07, 0x20, 0x3f, 0xf0, 0x1c, 0x74, 0xbd, 0x3b,
+ 0x1b, 0xd4, 0xb9, 0x25, 0xfa, 0xc5, 0xfe, 0xa8, 0xee, 0xdd, 0x25, 0xa5,
+ 0x63, 0x7c, 0x1f, 0x93, 0x77, 0x66, 0x63, 0xea, 0x7d, 0x41, 0x62, 0xe1,
+ 0x7b, 0x8e, 0xe3, 0x52, 0x50, 0xef, 0xab, 0x21, 0x3e, 0xd4, 0x69, 0x5f,
+ 0x89, 0xc6, 0xa6, 0x76, 0xbc, 0x1e, 0xac, 0x9b, 0xac, 0x57, 0xe5, 0xf1,
+ 0xfa, 0x2a, 0xce, 0xaf, 0x49, 0x6e, 0xbc, 0x28, 0xbb, 0x6d, 0x4b, 0xc5,
+ 0x7d, 0x37, 0x4e, 0x1d, 0xa3, 0x7e, 0x8d, 0xa9, 0xba, 0xb3, 0x88, 0x7c,
+ 0xa1, 0x30, 0xc2, 0x6f, 0x3c, 0xbf, 0xba, 0xab, 0x50, 0x4e, 0x5b, 0x59,
+ 0xf9, 0xd0, 0x77, 0x4d, 0x8e, 0x45, 0x47, 0x3d, 0x74, 0xd7, 0xc3, 0xb5,
+ 0x0b, 0x77, 0x05, 0x67, 0xc5, 0xfb, 0x1a, 0x61, 0x0d, 0xf5, 0x6d, 0xf6,
+ 0x5f, 0x6f, 0x35, 0x65, 0xed, 0x56, 0xdf, 0xbf, 0xdf, 0xb1, 0xc4, 0x0d,
+ 0x6b, 0x57, 0x4b, 0xd5, 0xae, 0xed, 0x2a, 0x07, 0x71, 0x47, 0x52, 0x5a,
+ 0x1e, 0xf6, 0x7a, 0xc6, 0x43, 0x9d, 0xa3, 0xa7, 0x0f, 0xae, 0xea, 0x16,
+ 0x62, 0x6e, 0x3a, 0x35, 0x27, 0x6e, 0x2f, 0xbf, 0x37, 0xcf, 0x38, 0x84,
+ 0xd9, 0x19, 0xdc, 0x75, 0xdd, 0x34, 0xae, 0xfc, 0xac, 0x48, 0x18, 0x7b,
+ 0x6e, 0x6a, 0xb4, 0x89, 0xc6, 0xdc, 0x92, 0xb6, 0x20, 0x13, 0x26, 0x68,
+ 0x29, 0x95, 0xa3, 0x3c, 0x8d, 0x7f, 0x1b, 0xb0, 0x7a, 0xd7, 0xd3, 0xa0,
+ 0x73, 0x1a, 0x74, 0xf2, 0x1c, 0xd3, 0xb5, 0x48, 0xe7, 0xa2, 0x5a, 0x81,
+ 0x7d, 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0x3d,
+ 0xc4, 0x7c, 0x0f, 0x31, 0xdf, 0x43, 0xcc, 0xf7, 0x10, 0xf3, 0xbd, 0xf1,
+ 0x30, 0x4f, 0x7b, 0x62, 0x3d, 0x4f, 0x5b, 0xa9, 0xf3, 0x3b, 0x94, 0xa2,
+ 0xa5, 0x58, 0x94, 0x20, 0xcf, 0x15, 0x9d, 0x39, 0x4d, 0x94, 0xe7, 0x5e,
+ 0xfb, 0x9b, 0x48, 0xb0, 0x8e, 0x39, 0x1e, 0xd7, 0x15, 0x35, 0xdd, 0xe6,
+ 0xba, 0x20, 0xcf, 0x63, 0x6d, 0xb5, 0x79, 0x0d, 0xf2, 0xb5, 0x0c, 0xfd,
+ 0x19, 0xed, 0x22, 0x11, 0xd4, 0x8b, 0x99, 0xf3, 0xf7, 0xba, 0x88, 0xbf,
+ 0x85, 0x9a, 0x8a, 0xc1, 0xbc, 0x17, 0xbc, 0x97, 0x7f, 0xb7, 0x00, 0x39,
+ 0xf0, 0xdd, 0x7d, 0xac, 0x27, 0x0a, 0xb5, 0xa4, 0x14, 0x17, 0xa3, 0xfc,
+ 0x07, 0xeb, 0xbc, 0x7d, 0x5a, 0xbe, 0x42, 0xd9, 0xea, 0x32, 0x9d, 0x00,
+ 0x53, 0xec, 0xc6, 0xbc, 0xee, 0x4d, 0x55, 0x23, 0xad, 0xd4, 0x49, 0xcf,
+ 0x7e, 0xd0, 0x16, 0xdd, 0xe3, 0x8a, 0x18, 0xb3, 0x09, 0xd1, 0x67, 0x91,
+ 0xd3, 0xda, 0x43, 0xea, 0x6f, 0x1d, 0x7a, 0xb0, 0x8f, 0x3e, 0x3b, 0x10,
+ 0xfd, 0x2d, 0x06, 0xeb, 0xae, 0xec, 0xc6, 0xfd, 0x2b, 0xcf, 0x91, 0x80,
+ 0xbd, 0x7e, 0x69, 0x27, 0xce, 0x06, 0xb9, 0x5e, 0xde, 0xa1, 0xf2, 0x6e,
+ 0xf8, 0xce, 0xd3, 0x43, 0xe9, 0x3e, 0xe9, 0xda, 0x25, 0x67, 0x86, 0x58,
+ 0xa3, 0xb5, 0x01, 0x1f, 0x61, 0x79, 0xe7, 0xb4, 0x4b, 0x96, 0xe7, 0xe1,
+ 0x5b, 0xe7, 0xd3, 0x0e, 0xff, 0xbe, 0x60, 0x01, 0x21, 0x6d, 0xa1, 0x3e,
+ 0xd6, 0xc7, 0x98, 0xbc, 0x58, 0xa7, 0xae, 0xf4, 0x60, 0x7d, 0x3f, 0x74,
+ 0x71, 0x1b, 0x6c, 0x48, 0xc7, 0xfe, 0x11, 0xee, 0xf7, 0x14, 0xee, 0x1e,
+ 0xfb, 0xb7, 0x77, 0x2a, 0xdd, 0xd0, 0xd3, 0x56, 0x4a, 0x07, 0xed, 0x1f,
+ 0xab, 0x2d, 0x1d, 0xe1, 0xf7, 0xc2, 0x69, 0xaf, 0xf1, 0xbb, 0xe1, 0x3e,
+ 0xad, 0x50, 0xe1, 0xdf, 0x38, 0x0c, 0xc9, 0x21, 0x8b, 0x7f, 0xff, 0xb3,
+ 0x4f, 0x7b, 0xa0, 0x4a, 0x18, 0x1b, 0x7d, 0xd6, 0xe1, 0xcb, 0xb0, 0xe5,
+ 0xff, 0x29, 0xdc, 0xea, 0x62, 0xdb, 0x3a, 0xcb, 0xf0, 0xfb, 0x1d, 0xe7,
+ 0xc7, 0x4d, 0xdd, 0xe4, 0x34, 0x71, 0x12, 0x27, 0xca, 0xc0, 0xc7, 0x39,
+ 0x49, 0x3d, 0x39, 0xd5, 0x4e, 0xa2, 0x14, 0x22, 0x88, 0x84, 0xe5, 0xfc,
+ 0xcc, 0x63, 0x14, 0x3c, 0xc8, 0xa6, 0x4e, 0x42, 0x55, 0x94, 0x74, 0x5b,
+ 0x27, 0xee, 0xb8, 0x40, 0x5c, 0x80, 0x6a, 0x39, 0x69, 0xe9, 0x86, 0x3d,
+ 0xa7, 0x5b, 0xba, 0x00, 0x57, 0x9e, 0xe3, 0xa4, 0x4d, 0xe7, 0xcc, 0x1a,
+ 0x03, 0x69, 0x70, 0x41, 0x23, 0x33, 0x6d, 0xe3, 0x66, 0x37, 0x48, 0x5c,
+ 0x57, 0x29, 0x83, 0x02, 0x6b, 0x2b, 0xb8, 0xe1, 0xef, 0xe2, 0xf0, 0x3c,
+ 0xdf, 0x39, 0x76, 0xd3, 0xc0, 0x44, 0x24, 0xeb, 0x7c, 0xe7, 0x3b, 0xdf,
+ 0xff, 0xf7, 0xbe, 0xcf, 0xfb, 0x9b, 0x6e, 0xb9, 0x08, 0x3a, 0xce, 0x8d,
+ 0xb5, 0xfa, 0xfe, 0xd6, 0x0e, 0x9f, 0x87, 0x07, 0xfb, 0x7c, 0x19, 0xa5,
+ 0x75, 0xc9, 0x9c, 0xd6, 0xa7, 0xbb, 0x0e, 0x7d, 0x7b, 0x16, 0x6b, 0x8a,
+ 0xe0, 0x1c, 0x1e, 0xe9, 0xd3, 0x78, 0x64, 0xf0, 0xbd, 0xff, 0xd0, 0x7b,
+ 0xdf, 0xa1, 0xf7, 0xde, 0xff, 0xd1, 0x9e, 0xe5, 0xc3, 0xf4, 0xc0, 0x75,
+ 0x5a, 0x53, 0x1a, 0xfd, 0xf2, 0x93, 0x6a, 0x39, 0x6f, 0x25, 0xa9, 0x0b,
+ 0xcc, 0x88, 0xab, 0x66, 0x9c, 0x36, 0x60, 0x5c, 0x9b, 0xac, 0xae, 0x83,
+ 0xe6, 0xb1, 0x8f, 0x76, 0x9b, 0xf1, 0xf2, 0x89, 0x3e, 0xf2, 0x4c, 0x10,
+ 0xd7, 0x60, 0xd8, 0xc3, 0x11, 0xb4, 0x73, 0x5f, 0x74, 0x12, 0xe6, 0x39,
+ 0xed, 0xbf, 0xa1, 0x0e, 0xe3, 0xaa, 0x9c, 0xce, 0xfd, 0x60, 0x9b, 0x16,
+ 0xb9, 0x6d, 0xa7, 0xba, 0xfd, 0xdc, 0x20, 0xd8, 0xbb, 0xa9, 0x3e, 0xea,
+ 0x17, 0x2f, 0x38, 0xcd, 0x3a, 0x73, 0x5f, 0x98, 0x77, 0x05, 0xa2, 0x79,
+ 0x4a, 0xa4, 0x54, 0x11, 0xb9, 0x86, 0xdf, 0x6f, 0x2a, 0x7e, 0xfc, 0x42,
+ 0xd1, 0xd6, 0x9e, 0x96, 0x1b, 0xc5, 0x2f, 0x48, 0x15, 0x32, 0x67, 0xc7,
+ 0x71, 0xdd, 0x3b, 0x4e, 0x54, 0x9f, 0xf9, 0x0f, 0xf2, 0x4a, 0x62, 0xe3,
+ 0x94, 0x69, 0x6d, 0xf2, 0xc3, 0x75, 0xe6, 0xd5, 0x59, 0xe6, 0x1d, 0x61,
+ 0x7e, 0x5b, 0x44, 0xd2, 0xe1, 0x80, 0xd6, 0x4b, 0xe5, 0x69, 0x68, 0x12,
+ 0xf8, 0xf6, 0x87, 0xf5, 0xb3, 0x7d, 0xf4, 0xb9, 0x7c, 0xbc, 0xce, 0x77,
+ 0x03, 0x4f, 0x43, 0xea, 0x76, 0x00, 0xfa, 0x2b, 0x80, 0xc7, 0xe4, 0xb9,
+ 0x73, 0xbf, 0xcf, 0x73, 0x6d, 0xa8, 0xa3, 0x0d, 0xdb, 0x26, 0xb9, 0x11,
+ 0xe0, 0xa0, 0x1a, 0xd6, 0xf9, 0x47, 0xf5, 0xb0, 0xc6, 0xe5, 0x40, 0x99,
+ 0x7e, 0x7b, 0xf3, 0xa8, 0xc6, 0xe8, 0xd4, 0xee, 0xf7, 0xf4, 0x5e, 0x50,
+ 0xce, 0x96, 0x1d, 0xd2, 0xaa, 0x29, 0x3b, 0xe0, 0xb5, 0xeb, 0xb5, 0x37,
+ 0xfa, 0x79, 0x57, 0x37, 0x6a, 0xdf, 0xef, 0xf3, 0x6c, 0x34, 0xd6, 0x5d,
+ 0xe8, 0xf3, 0xea, 0xa2, 0xbe, 0xcd, 0x45, 0xdb, 0xac, 0x84, 0xbd, 0x7d,
+ 0x5b, 0x6a, 0x1b, 0xdf, 0x95, 0x77, 0x8b, 0xdf, 0x91, 0x5f, 0x6c, 0x9c,
+ 0x81, 0xce, 0x61, 0x95, 0xb2, 0x90, 0x27, 0x6f, 0xd7, 0x5c, 0xf7, 0x6d,
+ 0x67, 0x01, 0xf6, 0x81, 0xeb, 0xfe, 0xd6, 0xd9, 0x93, 0xd8, 0xc4, 0x37,
+ 0xb1, 0xe7, 0x0c, 0x78, 0x88, 0x58, 0x98, 0x06, 0xbd, 0x7d, 0xb1, 0x5f,
+ 0x3a, 0x42, 0x9a, 0x4e, 0x86, 0x27, 0x5a, 0xb1, 0x07, 0xc3, 0xd7, 0xc3,
+ 0xb9, 0x97, 0xe9, 0x7e, 0xd2, 0x8c, 0x51, 0xfb, 0x09, 0xe6, 0x6f, 0x05,
+ 0x5f, 0x1c, 0xc5, 0x4f, 0xc9, 0x9d, 0x71, 0xac, 0x75, 0x9c, 0xb4, 0xd7,
+ 0x2a, 0xb1, 0xc7, 0xb0, 0x8f, 0x4c, 0x8b, 0xdc, 0xcb, 0x6f, 0xf6, 0xd1,
+ 0x9f, 0x77, 0x2f, 0xcf, 0xb2, 0xf1, 0xb9, 0x4e, 0x71, 0xa5, 0x05, 0xf2,
+ 0x7b, 0x75, 0xd2, 0xd3, 0x95, 0x7e, 0xad, 0x4e, 0xa0, 0xbd, 0x9d, 0x7d,
+ 0x4f, 0x51, 0xb7, 0xcb, 0xba, 0xad, 0xd0, 0xc5, 0xe7, 0xa0, 0x03, 0xa5,
+ 0x6a, 0x17, 0xa4, 0x3e, 0x1e, 0x42, 0x1b, 0xea, 0x28, 0x1a, 0x4b, 0x64,
+ 0x26, 0xcf, 0x7c, 0x2d, 0xe6, 0x4e, 0x61, 0x8d, 0x0b, 0xc4, 0x0d, 0xae,
+ 0xb1, 0x8d, 0x31, 0x38, 0xbf, 0xce, 0x06, 0x8d, 0xb0, 0x8e, 0xf4, 0x9d,
+ 0x04, 0x4f, 0x26, 0x29, 0x37, 0x31, 0xde, 0x18, 0xc6, 0x63, 0xb9, 0x13,
+ 0xe3, 0x5d, 0x90, 0x94, 0xd3, 0x18, 0x73, 0x0a, 0x6d, 0x88, 0x33, 0x53,
+ 0xd0, 0x1f, 0x86, 0xd4, 0xec, 0x7a, 0x18, 0xf2, 0xbb, 0x4f, 0x66, 0xcd,
+ 0x23, 0x07, 0xf6, 0x98, 0xd5, 0xf6, 0x81, 0x61, 0x8c, 0xf9, 0x6b, 0xea,
+ 0x3c, 0xb0, 0x26, 0xf6, 0xc7, 0x0f, 0xb6, 0x71, 0x6a, 0x7d, 0x0d, 0x38,
+ 0xb5, 0xf6, 0x61, 0xca, 0x39, 0x2b, 0x33, 0x61, 0xae, 0x89, 0xf5, 0x61,
+ 0xac, 0x99, 0x7e, 0xac, 0x67, 0x81, 0x43, 0x47, 0xfc, 0x3a, 0xb6, 0x15,
+ 0x23, 0x85, 0xb3, 0xf7, 0xec, 0x5a, 0xd6, 0x7d, 0x56, 0x52, 0x6b, 0x19,
+ 0x99, 0xd7, 0xfd, 0x78, 0x86, 0x83, 0x5a, 0xf7, 0x20, 0xaf, 0xc6, 0x7a,
+ 0x70, 0x96, 0x89, 0x07, 0x36, 0x70, 0xb4, 0x47, 0xcb, 0xcc, 0x7e, 0x8f,
+ 0x67, 0xf1, 0xad, 0x87, 0x77, 0xd4, 0x26, 0xb1, 0x6f, 0x40, 0x46, 0xe6,
+ 0x1b, 0xf5, 0x21, 0xf9, 0x24, 0xdf, 0xd1, 0xcf, 0x38, 0xcb, 0xdd, 0xbc,
+ 0x29, 0x1f, 0xe7, 0x75, 0x2c, 0x74, 0x31, 0x20, 0xd6, 0x79, 0xcf, 0x3e,
+ 0x1f, 0x59, 0x5c, 0x55, 0xfc, 0x3e, 0x72, 0x7e, 0x4b, 0x05, 0xd1, 0x36,
+ 0x84, 0x76, 0x5c, 0x87, 0x29, 0x73, 0xf9, 0xbf, 0xb9, 0x4b, 0xa3, 0xae,
+ 0x3b, 0xaf, 0xf3, 0xc3, 0x12, 0xe6, 0xaa, 0x6a, 0xe8, 0xe4, 0x71, 0xc9,
+ 0x87, 0xdb, 0x31, 0x57, 0xc2, 0xdc, 0x52, 0x23, 0x58, 0x0f, 0xcb, 0x3d,
+ 0xe4, 0x89, 0xc8, 0x9e, 0x70, 0x7c, 0x2b, 0xbd, 0xa9, 0x12, 0xd1, 0x61,
+ 0x65, 0x25, 0x73, 0xf8, 0xb5, 0x28, 0x1d, 0x47, 0x8c, 0x44, 0x15, 0x78,
+ 0x17, 0x7b, 0xb2, 0x4f, 0xba, 0x6e, 0xda, 0x66, 0x7d, 0xc2, 0x0c, 0x29,
+ 0xfa, 0x5b, 0x3a, 0x74, 0xbc, 0xf1, 0x72, 0x6f, 0xc2, 0x3c, 0xa9, 0x8e,
+ 0xfb, 0xef, 0x53, 0xc0, 0xcc, 0xe6, 0x78, 0x67, 0x36, 0x95, 0x29, 0x2f,
+ 0xe5, 0x13, 0xd1, 0x65, 0x65, 0x65, 0x30, 0x66, 0x66, 0x56, 0x11, 0x37,
+ 0x12, 0x66, 0x87, 0xa2, 0x4f, 0xb4, 0x5d, 0xef, 0x3b, 0x8d, 0xfe, 0x09,
+ 0xd5, 0xe2, 0xaf, 0x87, 0xf7, 0xf5, 0xe3, 0x7e, 0x8f, 0x67, 0x88, 0x39,
+ 0xa3, 0xc0, 0x4c, 0xe6, 0x9a, 0xe9, 0xdc, 0x86, 0x64, 0x6c, 0x62, 0x54,
+ 0x63, 0xe8, 0xfd, 0x53, 0x7f, 0x47, 0x1d, 0xca, 0x25, 0xd6, 0xc5, 0x7d,
+ 0x7e, 0x1b, 0xd5, 0x3a, 0xf3, 0xfd, 0x53, 0x59, 0x9d, 0xc7, 0x58, 0x57,
+ 0x31, 0x7f, 0xdf, 0xcd, 0x3b, 0x8b, 0xa6, 0x9c, 0x47, 0x38, 0xce, 0x5a,
+ 0x60, 0xba, 0x5d, 0x98, 0x23, 0x3a, 0x57, 0x6c, 0xd0, 0x06, 0xfd, 0x01,
+ 0xcc, 0x17, 0x68, 0xc4, 0xbd, 0x2f, 0x88, 0x31, 0x11, 0x3c, 0x40, 0x27,
+ 0xd0, 0x35, 0xa1, 0xa3, 0x56, 0x30, 0x4e, 0x6e, 0x5d, 0xb2, 0x5e, 0x7f,
+ 0x09, 0x32, 0x27, 0x35, 0x57, 0xf9, 0xb4, 0x31, 0x38, 0x37, 0xe6, 0xc0,
+ 0xfb, 0xfd, 0x53, 0xa4, 0x4f, 0x9e, 0x4d, 0x54, 0xcd, 0x6d, 0x70, 0x3d,
+ 0x83, 0x32, 0xbf, 0x3e, 0x24, 0xcb, 0xf8, 0xad, 0xae, 0x7b, 0xf7, 0xb6,
+ 0x0d, 0xdd, 0x7a, 0x3e, 0x6f, 0x6a, 0x7e, 0x5d, 0x76, 0x18, 0x33, 0x01,
+ 0xaf, 0xe8, 0x9c, 0x2a, 0xf6, 0x65, 0x5e, 0xe1, 0x10, 0xe5, 0xa3, 0x53,
+ 0x87, 0x5c, 0xdd, 0xae, 0x51, 0x4f, 0x65, 0xbd, 0x35, 0x15, 0x0d, 0x74,
+ 0xc9, 0x2a, 0xf0, 0xae, 0x0c, 0xd9, 0x99, 0x7b, 0x25, 0x24, 0xcb, 0x79,
+ 0x1d, 0x4f, 0x8e, 0xfe, 0x5e, 0x39, 0x52, 0xad, 0x4d, 0xca, 0x6e, 0x2d,
+ 0xae, 0xbf, 0x51, 0xae, 0xe5, 0x5e, 0x37, 0xe4, 0xf9, 0x51, 0x9d, 0x57,
+ 0x17, 0x2f, 0x4b, 0xef, 0x00, 0x75, 0x9e, 0x2d, 0x9d, 0x63, 0x07, 0xec,
+ 0x80, 0xce, 0xf1, 0x33, 0xe8, 0x1c, 0xef, 0x40, 0xe7, 0xf8, 0x69, 0x11,
+ 0xf8, 0x52, 0x4c, 0xfb, 0xf8, 0xbf, 0x08, 0x1c, 0xa2, 0xac, 0xb6, 0xce,
+ 0xe0, 0x4e, 0x17, 0xb3, 0xa0, 0xc1, 0x5b, 0x92, 0x06, 0xde, 0xa6, 0xe4,
+ 0xfa, 0xc6, 0xbc, 0xec, 0x6c, 0x78, 0x79, 0xc8, 0x1f, 0x30, 0x07, 0x6c,
+ 0x9c, 0xf7, 0x14, 0x07, 0x0e, 0x1d, 0x91, 0xd8, 0x49, 0xe2, 0x47, 0x50,
+ 0x36, 0x0b, 0xef, 0x68, 0x1c, 0xda, 0x2c, 0xb0, 0x1c, 0x10, 0x9d, 0x4f,
+ 0xb6, 0xb0, 0x27, 0x65, 0xe7, 0x97, 0xa8, 0x3f, 0xa6, 0x7d, 0x40, 0x9e,
+ 0x4f, 0x9e, 0x78, 0xf9, 0x67, 0xff, 0xee, 0x95, 0xce, 0xb3, 0x5b, 0x32,
+ 0xbb, 0xd0, 0xae, 0x81, 0x5d, 0xc3, 0x5e, 0xcc, 0x5b, 0xfd, 0x05, 0x6d,
+ 0x30, 0x47, 0xb1, 0x4b, 0xb6, 0x21, 0x43, 0xea, 0xf1, 0x2e, 0xad, 0xfb,
+ 0xd5, 0xe3, 0x43, 0x3a, 0x17, 0x97, 0xe3, 0xe4, 0x0a, 0xb6, 0xac, 0x14,
+ 0xac, 0x68, 0x16, 0xf4, 0xb7, 0x0b, 0x5b, 0xed, 0x3a, 0xee, 0x60, 0x07,
+ 0x67, 0x70, 0xa3, 0x46, 0x39, 0x7f, 0x57, 0x63, 0xef, 0x66, 0xed, 0x4f,
+ 0x18, 0xc7, 0x3a, 0x93, 0x94, 0x3f, 0xf6, 0x13, 0x03, 0xe9, 0x8f, 0x9a,
+ 0xd1, 0xfd, 0xbd, 0x7e, 0xd7, 0xd1, 0x76, 0xa7, 0x46, 0x3c, 0x16, 0xb9,
+ 0x94, 0xb7, 0x21, 0x4b, 0x5e, 0x8f, 0x50, 0x07, 0x28, 0xa9, 0x46, 0x3f,
+ 0xd7, 0x5f, 0xb3, 0xeb, 0x1e, 0xb5, 0xb9, 0xae, 0xb8, 0x8f, 0xdb, 0x94,
+ 0xfd, 0x7b, 0x5a, 0xee, 0xe7, 0x8b, 0x67, 0xe5, 0x2d, 0xdc, 0xb7, 0xa7,
+ 0xe3, 0x64, 0xe4, 0x4d, 0xe8, 0x78, 0xb5, 0x62, 0x23, 0x6f, 0x7b, 0x1a,
+ 0xe7, 0x64, 0xa9, 0x95, 0x2b, 0x2f, 0xcb, 0xe5, 0xab, 0xfb, 0xea, 0xa5,
+ 0xab, 0x31, 0xf5, 0xf2, 0x95, 0x61, 0x95, 0xbb, 0xe2, 0xba, 0xff, 0x74,
+ 0x96, 0xe4, 0xdd, 0x0d, 0x57, 0x4e, 0x3b, 0xc6, 0x40, 0x40, 0x1a, 0xb9,
+ 0x75, 0xae, 0x1b, 0x04, 0x36, 0xdf, 0xe8, 0x75, 0xdd, 0x47, 0xc7, 0xc7,
+ 0x25, 0xde, 0x4b, 0x1d, 0xe5, 0xf3, 0x11, 0xe6, 0xbb, 0x12, 0x73, 0x52,
+ 0xb6, 0x7d, 0xbe, 0xac, 0x14, 0xf0, 0xad, 0xcb, 0xd3, 0x5f, 0x1e, 0x3b,
+ 0xe6, 0xc7, 0x4a, 0x7e, 0xf4, 0x22, 0x7d, 0xc9, 0x91, 0xff, 0xf2, 0x25,
+ 0x9b, 0x72, 0xae, 0xf0, 0x19, 0xf4, 0x0f, 0xcb, 0xb7, 0x0a, 0xa1, 0x43,
+ 0x65, 0x13, 0xcf, 0x31, 0x95, 0x2b, 0xdc, 0x73, 0x87, 0x75, 0xcc, 0x00,
+ 0x3a, 0x89, 0xe9, 0xba, 0xcb, 0x0e, 0xe7, 0xeb, 0xc2, 0x7c, 0x7b, 0xe6,
+ 0x31, 0xc8, 0xff, 0xd3, 0x5a, 0x3e, 0x9f, 0x53, 0xb0, 0x7d, 0xc1, 0xdf,
+ 0x61, 0x99, 0x2d, 0x40, 0xc6, 0x2b, 0xe6, 0x9c, 0x52, 0x57, 0xb0, 0x22,
+ 0xcb, 0xc0, 0x8e, 0x25, 0xe0, 0xcd, 0x93, 0x3a, 0xb6, 0xda, 0xa3, 0xb1,
+ 0x67, 0x85, 0xe5, 0x8c, 0x24, 0xcb, 0x4e, 0xb7, 0x3e, 0xbf, 0xfd, 0xdd,
+ 0x57, 0x23, 0xde, 0x9d, 0x83, 0x8f, 0x33, 0x4a, 0xda, 0x60, 0x03, 0xcd,
+ 0x6c, 0x2d, 0x80, 0x27, 0x22, 0x38, 0xdb, 0x56, 0xcd, 0x0f, 0x75, 0xc8,
+ 0xef, 0xba, 0xf6, 0x23, 0x7a, 0xf1, 0x8a, 0xba, 0xc9, 0x76, 0xcf, 0xa0,
+ 0x5f, 0xbb, 0xa4, 0xae, 0xb4, 0x69, 0x5c, 0x7d, 0xb8, 0x2e, 0x09, 0x3d,
+ 0xe4, 0x69, 0x94, 0x03, 0xa8, 0x8b, 0xfa, 0x65, 0x03, 0xe5, 0x45, 0x94,
+ 0x5b, 0xf0, 0x64, 0x9b, 0x11, 0xe8, 0x15, 0x78, 0xbe, 0x81, 0xf1, 0xc6,
+ 0xb1, 0xe6, 0x8c, 0x29, 0x1f, 0x9d, 0xa2, 0x2c, 0x19, 0x53, 0xcc, 0x4b,
+ 0x5e, 0xb6, 0xf1, 0xac, 0x0e, 0xab, 0x99, 0x35, 0x96, 0xf1, 0x2c, 0x79,
+ 0xdf, 0x1f, 0xc2, 0x24, 0xf4, 0x49, 0x5d, 0xf5, 0x30, 0xe9, 0xa3, 0x26,
+ 0x26, 0xb1, 0xae, 0x5d, 0x66, 0xaf, 0x90, 0xd7, 0x4d, 0xd0, 0x5b, 0x87,
+ 0xcc, 0x5c, 0x0d, 0x6b, 0x7d, 0xb4, 0x0c, 0x5a, 0xdc, 0x06, 0x5d, 0x6d,
+ 0x82, 0xa6, 0x52, 0x05, 0x6b, 0x6a, 0x51, 0x45, 0xb5, 0x2f, 0xe0, 0x09,
+ 0xd0, 0x6b, 0xf0, 0x15, 0xea, 0xa2, 0xe4, 0xe5, 0x38, 0x68, 0x4f, 0xdc,
+ 0xa0, 0x6d, 0xa7, 0xe3, 0xca, 0x06, 0x0d, 0x82, 0x2e, 0x0b, 0x1e, 0x4f,
+ 0xbf, 0xa7, 0x34, 0xae, 0x4e, 0xdd, 0x96, 0x44, 0xf2, 0xb6, 0x58, 0xc0,
+ 0x02, 0xcb, 0xf9, 0x50, 0x1c, 0x8c, 0x39, 0x29, 0xd7, 0x30, 0x8f, 0x01,
+ 0xfe, 0x1e, 0x3d, 0xa1, 0xf9, 0x7b, 0x4a, 0x02, 0x87, 0x79, 0x1c, 0xf4,
+ 0x06, 0x0c, 0xf2, 0x78, 0x3a, 0xe9, 0xd3, 0xe8, 0xd7, 0xc1, 0xbf, 0x16,
+ 0x2c, 0xb1, 0xb0, 0xac, 0x82, 0xff, 0xb7, 0xf1, 0xfd, 0x66, 0x6d, 0x44,
+ 0xad, 0xac, 0x29, 0x3f, 0x97, 0xe4, 0x19, 0xe8, 0xc9, 0xb7, 0x70, 0x76,
+ 0x9d, 0x5a, 0x77, 0x8f, 0x8d, 0x33, 0x7e, 0x96, 0x56, 0x97, 0xed, 0x93,
+ 0xb2, 0x3f, 0x36, 0x89, 0xf2, 0x31, 0x3c, 0x0d, 0x9c, 0x43, 0x48, 0xc7,
+ 0xbf, 0x37, 0xf3, 0x8e, 0xf2, 0xfe, 0x67, 0x61, 0x42, 0xe7, 0xe7, 0x1b,
+ 0x76, 0x2f, 0xbe, 0xd3, 0x17, 0xc3, 0xbd, 0x41, 0x67, 0x52, 0x11, 0x9d,
+ 0x6f, 0x5a, 0x86, 0x2e, 0xb1, 0x85, 0xf1, 0xde, 0xa7, 0x2f, 0xaf, 0x0a,
+ 0x1e, 0x1e, 0xfb, 0x97, 0x9b, 0x0c, 0x33, 0x47, 0xfd, 0x6e, 0xc4, 0x93,
+ 0x7f, 0x9f, 0xb8, 0xfb, 0xf6, 0xca, 0x94, 0x81, 0x97, 0x5b, 0x66, 0x18,
+ 0x6d, 0x21, 0xcb, 0x20, 0x8b, 0x4a, 0x9a, 0x7e, 0xd9, 0xce, 0xeb, 0x9b,
+ 0xab, 0x26, 0xcc, 0x0f, 0xc4, 0xeb, 0xbb, 0x6a, 0x53, 0xee, 0xb4, 0x03,
+ 0x5f, 0xa2, 0x5a, 0xaf, 0x7c, 0xdf, 0xce, 0x02, 0x15, 0xac, 0x68, 0x1a,
+ 0x34, 0xda, 0x26, 0x56, 0x7c, 0x4e, 0x1e, 0xcc, 0xbb, 0xac, 0xfb, 0xb2,
+ 0x6d, 0xa3, 0x6f, 0x63, 0x5e, 0xae, 0x9f, 0x7b, 0xe1, 0x1e, 0xe8, 0x9b,
+ 0x36, 0x35, 0x8d, 0xd6, 0xab, 0xdd, 0x03, 0x1e, 0x8d, 0x36, 0xf6, 0x11,
+ 0xfe, 0x3f, 0xfb, 0x20, 0x9d, 0x38, 0xca, 0xcb, 0xbb, 0xc0, 0xb3, 0xca,
+ 0xf3, 0x1c, 0x01, 0x6d, 0x1c, 0xa4, 0x9f, 0x86, 0x6f, 0xd1, 0xa3, 0x9f,
+ 0x47, 0x9b, 0xf4, 0x43, 0xba, 0xe9, 0x90, 0xd9, 0xab, 0xb6, 0xcc, 0x17,
+ 0xf4, 0x7d, 0x43, 0xd7, 0xa4, 0xcf, 0x68, 0x12, 0x74, 0x43, 0x5a, 0x27,
+ 0x6f, 0x99, 0x52, 0x02, 0x1d, 0x95, 0x80, 0x4f, 0x25, 0xd0, 0x54, 0x19,
+ 0xf8, 0x56, 0x02, 0xbe, 0x95, 0x6a, 0x56, 0xbc, 0x82, 0x3d, 0x53, 0x66,
+ 0x6f, 0x81, 0x8e, 0xb6, 0x6b, 0xbc, 0x7f, 0xbd, 0x66, 0x93, 0x72, 0xf0,
+ 0x66, 0xf3, 0xee, 0xff, 0x81, 0xbb, 0x1f, 0x92, 0x5d, 0xd8, 0x2d, 0x6f,
+ 0x15, 0xc7, 0x80, 0x49, 0x02, 0x8c, 0x72, 0x40, 0x1b, 0x53, 0x72, 0xbd,
+ 0x38, 0x2d, 0x3b, 0x90, 0x4f, 0x37, 0x36, 0x62, 0xd0, 0xa7, 0x23, 0xb2,
+ 0xf2, 0xda, 0xa8, 0xbc, 0xb9, 0xa1, 0x64, 0x09, 0xf4, 0x9b, 0xdb, 0xa4,
+ 0xdf, 0x1d, 0xf4, 0x5c, 0xea, 0xd0, 0x71, 0xfa, 0xd9, 0x8a, 0xe7, 0x7f,
+ 0x9f, 0xab, 0x74, 0xca, 0x7c, 0xc5, 0x94, 0xc7, 0x2b, 0xdd, 0xf2, 0xe5,
+ 0x4a, 0x58, 0x4e, 0xc3, 0x0e, 0xfc, 0x4a, 0x65, 0x50, 0x9e, 0xac, 0x0c,
+ 0xc9, 0x57, 0xab, 0x51, 0xf9, 0x5a, 0xd5, 0x96, 0x4c, 0x35, 0x2e, 0xe9,
+ 0xea, 0x98, 0x3c, 0x51, 0xa5, 0x5f, 0x1d, 0xf3, 0xe1, 0x37, 0xd3, 0xf4,
+ 0x57, 0x70, 0x5d, 0x41, 0xac, 0x2b, 0xae, 0xe6, 0x74, 0x9c, 0x52, 0x32,
+ 0x9e, 0xcf, 0x43, 0xe4, 0x39, 0x8c, 0x75, 0xf1, 0x35, 0x25, 0x65, 0x3d,
+ 0x7f, 0xe3, 0xff, 0x46, 0x42, 0xda, 0x36, 0x7a, 0xae, 0x34, 0x88, 0x36,
+ 0x90, 0x7b, 0xf9, 0x86, 0xef, 0xa3, 0xe1, 0xf3, 0x6f, 0xd8, 0x5e, 0x86,
+ 0xf6, 0x5b, 0xdf, 0xa4, 0xed, 0xa5, 0xcf, 0x9e, 0xf8, 0x41, 0x3b, 0xe7,
+ 0x9a, 0xf6, 0x9b, 0x3c, 0x88, 0x6d, 0x34, 0xe6, 0xbd, 0x98, 0x79, 0xf8,
+ 0xff, 0x53, 0xbc, 0x18, 0xd5, 0xb9, 0xea, 0x20, 0xff, 0x4f, 0x05, 0x6b,
+ 0xf9, 0xf4, 0xdc, 0xf1, 0xf9, 0xe2, 0xac, 0x7a, 0xbc, 0x48, 0x8d, 0xc6,
+ 0x95, 0x8b, 0xcd, 0x9c, 0xb8, 0x2f, 0xc9, 0xa6, 0x13, 0xd2, 0x6b, 0xf0,
+ 0xf3, 0x1f, 0x75, 0x7e, 0xdc, 0xec, 0x09, 0xd2, 0x1f, 0x63, 0x6f, 0x9d,
+ 0x7e, 0x3c, 0x01, 0xba, 0xad, 0x63, 0xca, 0xa5, 0x8a, 0xe7, 0xb3, 0x5a,
+ 0xd1, 0xf4, 0xf2, 0x2b, 0xd0, 0x1c, 0x63, 0x0e, 0xde, 0x33, 0x5b, 0xf2,
+ 0xfa, 0xce, 0xe0, 0xde, 0x60, 0x8f, 0x63, 0xbf, 0x46, 0x37, 0xe7, 0xe2,
+ 0xff, 0xe9, 0xa0, 0xec, 0xaf, 0x97, 0xb9, 0xc6, 0xb6, 0xa6, 0x45, 0x2f,
+ 0xae, 0x1b, 0x97, 0x17, 0x70, 0x7e, 0x65, 0x93, 0xeb, 0x0f, 0x4a, 0x39,
+ 0x4e, 0xdb, 0x96, 0xf8, 0x7d, 0x42, 0x4a, 0x98, 0xa7, 0x1c, 0x6f, 0xf8,
+ 0xc3, 0x3c, 0x9c, 0x2d, 0x9b, 0x0f, 0xe6, 0x5d, 0x2c, 0x1d, 0xc7, 0x3b,
+ 0xea, 0xe2, 0xd0, 0x99, 0x16, 0xf8, 0x7e, 0x11, 0x65, 0xfa, 0x46, 0x56,
+ 0xf0, 0x8c, 0xf8, 0x75, 0xd5, 0x01, 0xad, 0xab, 0x4f, 0x3f, 0xe8, 0xb7,
+ 0x54, 0xb2, 0xb2, 0xa9, 0x40, 0x42, 0x19, 0xaf, 0xfe, 0x7c, 0x80, 0x98,
+ 0x7b, 0xdc, 0xe6, 0x2f, 0x24, 0x7f, 0x35, 0xb5, 0x4f, 0xc1, 0xff, 0x76,
+ 0x44, 0x9e, 0x32, 0x99, 0xc7, 0x9e, 0x54, 0xb3, 0xc5, 0x9c, 0x9f, 0xe3,
+ 0x9b, 0x50, 0xc7, 0xcb, 0x37, 0x07, 0xbc, 0x9c, 0x77, 0x8e, 0x7d, 0x30,
+ 0xcf, 0xfd, 0x20, 0x9d, 0x30, 0xdf, 0xbd, 0xbd, 0xf9, 0x3f, 0x52, 0xe5,
+ 0x3c, 0xf0, 0xce, 0x6e, 0xd1, 0xfc, 0x98, 0xab, 0xfe, 0xdb, 0xdd, 0xd3,
+ 0xfc, 0xdc, 0xf0, 0x31, 0xfc, 0x6e, 0x80, 0xb6, 0x2d, 0x71, 0xe3, 0x92,
+ 0x97, 0x3b, 0xaa, 0x6d, 0x68, 0x60, 0x05, 0xea, 0xc8, 0xab, 0xe0, 0x93,
+ 0x66, 0x5b, 0xfe, 0xfd, 0x07, 0x69, 0x3f, 0x51, 0x42, 0x6c, 0x67, 0x00,
+ 0x00, 0x00 };
+
+static const u32 bnx2_RXP_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_RXP_b09FwRodata[(0x278/4) + 1] = {
+ 0x08004050, 0x08003f50, 0x08003ff4, 0x0800400c, 0x08004024, 0x08004044,
+ 0x08004050, 0x08004050, 0x08003f58, 0x00000000, 0x08004a0c, 0x08004a44,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004a7c, 0x08004c40,
+ 0x08004b88, 0x08004bc0, 0x08004c40, 0x08004b10, 0x08004c40, 0x08004c40,
+ 0x08004bc0, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c00,
+ 0x08004c40, 0x08004c00, 0x08004b88, 0x08004c40, 0x08004c40, 0x08004c00,
+ 0x08004c00, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40, 0x08004c40,
+ 0x08004aec, 0x00000000, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
+ 0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070,
+ 0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
+ 0x08006064, 0x00000000, 0x00000000 };
+static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
+static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 };
static struct fw_info bnx2_rxp_fw_09 = {
- .ver_major = 0x1,
- .ver_minor = 0x0,
- .ver_fix = 0x0,
+ .ver_major = 0x3,
+ .ver_minor = 0x4,
+ .ver_fix = 0x3,
.start_addr = 0x08003184,
.text_addr = 0x08000000,
- .text_len = 0x673c,
+ .text_len = 0x6768,
.text_index = 0x0,
.gz_text = bnx2_RXP_b09FwText,
.gz_text_len = sizeof(bnx2_RXP_b09FwText),
- .data_addr = 0x080069e0,
+ .data_addr = 0x08006a00,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_RXP_b09FwData,
- .sbss_addr = 0x080069e0,
- .sbss_len = 0x2c,
+ .sbss_addr = 0x08006a00,
+ .sbss_len = 0x20,
.sbss_index = 0x0,
.sbss = bnx2_RXP_b09FwSbss,
- .bss_addr = 0x08006a10,
+ .bss_addr = 0x08006a20,
.bss_len = 0x13dc,
.bss_index = 0x0,
.bss = bnx2_RXP_b09FwBss,
- .rodata_addr = 0x08006740,
+ .rodata_addr = 0x08006768,
.rodata_len = 0x278,
.rodata_index = 0x0,
.rodata = bnx2_RXP_b09FwRodata,
};
static u8 bnx2_TPAT_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0xdb, 0xfd, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x58, 0x5d, 0x6c,
- 0x1c, 0x57, 0x15, 0x3e, 0xf3, 0xbb, 0x13, 0x77, 0xed, 0xbd, 0x49, 0x97,
- 0x6a, 0x13, 0xb9, 0x74, 0xc6, 0x1e, 0x3b, 0x8b, 0x1c, 0x35, 0x93, 0xb0,
- 0x24, 0x16, 0x5a, 0xd1, 0xc9, 0xcc, 0xae, 0x6b, 0xe5, 0x29, 0x86, 0xbc,
- 0xf1, 0xb2, 0xac, 0xed, 0x46, 0x54, 0x48, 0x4d, 0x51, 0x84, 0x22, 0x81,
- 0x94, 0x65, 0x76, 0x53, 0x40, 0x5a, 0x65, 0xc1, 0xa0, 0x04, 0x21, 0x84,
- 0x22, 0x9b, 0x66, 0x91, 0x58, 0x3c, 0x4d, 0xe9, 0x6b, 0x94, 0xbc, 0x90,
- 0x96, 0x17, 0x9e, 0x4b, 0x9e, 0xac, 0x02, 0x12, 0x0f, 0xa8, 0x8a, 0x78,
- 0x40, 0x15, 0x0d, 0x1e, 0xbe, 0x33, 0x3f, 0x9b, 0x5d, 0xd7, 0x29, 0x79,
- 0xa8, 0x84, 0xa5, 0xf1, 0xcc, 0xfd, 0x39, 0xf7, 0xe7, 0x7c, 0xdf, 0x77,
- 0xee, 0xb9, 0x5b, 0x92, 0x69, 0x82, 0xd2, 0xbf, 0x49, 0x3c, 0x97, 0xbe,
- 0x71, 0xf1, 0xd2, 0xe2, 0x8b, 0x27, 0x4d, 0x3a, 0x71, 0xe2, 0x45, 0xe9,
- 0x19, 0x43, 0xa6, 0xcf, 0xe0, 0x4f, 0x21, 0x12, 0xd9, 0xf8, 0xfc, 0x90,
- 0x21, 0x57, 0x6f, 0x4e, 0x7b, 0x36, 0x19, 0x4a, 0xd5, 0x79, 0x61, 0xd5,
- 0x26, 0x72, 0x07, 0x0b, 0xa6, 0x4f, 0xff, 0x89, 0x5a, 0x45, 0x95, 0xb8,
- 0xfe, 0xf9, 0xea, 0xa3, 0xe3, 0x77, 0x4e, 0x5b, 0x0f, 0x6f, 0x2a, 0x64,
- 0x88, 0x6a, 0xc3, 0x10, 0xf3, 0x64, 0x4c, 0xc3, 0xe6, 0x97, 0x47, 0x57,
- 0x34, 0x9a, 0xca, 0xc6, 0x12, 0x14, 0xf4, 0x0c, 0xaa, 0x77, 0x31, 0x8e,
- 0x7d, 0x59, 0xf2, 0x43, 0x55, 0xf2, 0x6f, 0x18, 0x24, 0x57, 0x5d, 0xc9,
- 0x0b, 0x6d, 0xb4, 0x49, 0xe4, 0x39, 0x39, 0x72, 0x45, 0x14, 0x7d, 0xd3,
- 0x91, 0x49, 0xb6, 0x77, 0xa3, 0xd9, 0xb9, 0x25, 0xc9, 0xeb, 0x2f, 0x4b,
- 0x7e, 0xdf, 0xe3, 0x7d, 0x63, 0x1d, 0x4b, 0x92, 0xdb, 0xe7, 0x77, 0xd5,
- 0xf0, 0xbb, 0x53, 0xd4, 0x28, 0x52, 0x41, 0xb6, 0xd9, 0xd6, 0x24, 0xdf,
- 0x59, 0x28, 0x29, 0x34, 0x8b, 0xe7, 0x00, 0xad, 0x3b, 0x94, 0xf7, 0x1c,
- 0x52, 0x15, 0x5b, 0x26, 0xbf, 0x28, 0xd1, 0xaf, 0x2b, 0x1a, 0x9e, 0xb3,
- 0x52, 0xad, 0xbf, 0x96, 0x8e, 0x53, 0xa4, 0x36, 0xd6, 0xd2, 0x2c, 0xf2,
- 0xda, 0x12, 0x7b, 0xcf, 0x59, 0x10, 0x32, 0xcd, 0xe2, 0x99, 0xc4, 0x77,
- 0x13, 0xfd, 0x34, 0xf2, 0x2a, 0x7b, 0xdb, 0x0e, 0xe0, 0x1b, 0xeb, 0xc4,
- 0x58, 0x5e, 0xbc, 0x0e, 0x13, 0xeb, 0xb0, 0xa9, 0xd3, 0x5b, 0xc6, 0x3e,
- 0xe6, 0x4a, 0x4d, 0xd2, 0xa9, 0x13, 0xaf, 0x7d, 0x92, 0x02, 0xa1, 0x50,
- 0x70, 0x4c, 0x23, 0xf7, 0x9c, 0x8a, 0xf2, 0x21, 0x6a, 0x09, 0x09, 0x7d,
- 0x3a, 0x29, 0x7e, 0x39, 0xb4, 0xeb, 0xa8, 0x2f, 0x50, 0x50, 0x3c, 0x28,
- 0xc9, 0xd5, 0xef, 0xa1, 0x7e, 0x4e, 0x34, 0xe9, 0xbb, 0x78, 0x4b, 0x28,
- 0x1f, 0xe4, 0xf1, 0x50, 0x96, 0x48, 0xb1, 0x49, 0x78, 0xa1, 0x49, 0xed,
- 0x30, 0xb3, 0xe5, 0xfa, 0xa4, 0xae, 0x15, 0xee, 0xc5, 0x0e, 0xfd, 0x7a,
- 0x75, 0x6a, 0x08, 0x6a, 0xa9, 0x55, 0xf4, 0xe9, 0xd9, 0xa2, 0x06, 0x9c,
- 0xdc, 0x18, 0xcf, 0x97, 0xb8, 0x9e, 0xff, 0x50, 0x6f, 0x92, 0x52, 0xb5,
- 0x85, 0x4f, 0x5f, 0xa6, 0xa4, 0x8d, 0xf7, 0x29, 0x63, 0x6f, 0xa7, 0xd2,
- 0x72, 0x51, 0x78, 0x37, 0xbe, 0x48, 0x6e, 0xec, 0x1f, 0x03, 0xdf, 0x02,
- 0x7b, 0xd4, 0x81, 0x75, 0xe0, 0xca, 0xd4, 0x2a, 0x19, 0x64, 0x2d, 0xae,
- 0xa1, 0xe5, 0x6f, 0x5d, 0x05, 0x7e, 0x67, 0xdc, 0xd4, 0xd4, 0x8e, 0x71,
- 0xfe, 0x23, 0xd6, 0xd9, 0x12, 0x06, 0xf0, 0x6e, 0x9c, 0x8f, 0xa2, 0x37,
- 0x9d, 0x28, 0xd2, 0xab, 0x76, 0xf9, 0x16, 0x2d, 0x94, 0x34, 0x9a, 0x17,
- 0x78, 0xc3, 0x8f, 0x36, 0x7c, 0xa5, 0x65, 0xeb, 0xc9, 0x78, 0x86, 0xbf,
- 0xcb, 0x12, 0x96, 0x42, 0x1f, 0x74, 0xdf, 0x63, 0x7f, 0x94, 0x97, 0x62,
- 0x9b, 0x28, 0xda, 0x5c, 0xfc, 0x34, 0x9b, 0xef, 0xa7, 0x36, 0x51, 0x54,
- 0xaf, 0xf0, 0xbc, 0x16, 0xf6, 0xcc, 0x5c, 0x25, 0xaa, 0x0f, 0x1c, 0xa3,
- 0xd9, 0xc5, 0xfa, 0x6c, 0xbc, 0x07, 0x25, 0xec, 0xc1, 0x2a, 0x9b, 0x92,
- 0x41, 0x81, 0x1d, 0xbd, 0x00, 0x7e, 0xb8, 0xbe, 0x6d, 0xbd, 0xef, 0x2b,
- 0x05, 0xda, 0x72, 0xf2, 0xd4, 0x09, 0x4b, 0x14, 0x84, 0x1d, 0xf2, 0x42,
- 0x19, 0x73, 0x14, 0x68, 0xd3, 0x7e, 0x18, 0xd5, 0x1d, 0x07, 0x7e, 0x21,
- 0xb6, 0x2b, 0xd5, 0x69, 0x1a, 0xed, 0x0b, 0x62, 0x8d, 0x1c, 0x60, 0x21,
- 0xc3, 0x37, 0xb3, 0xf1, 0x77, 0x10, 0x3a, 0x68, 0xa7, 0x96, 0x5c, 0xb1,
- 0x44, 0x40, 0x56, 0xc9, 0x53, 0x48, 0xc8, 0x55, 0x81, 0x3e, 0x2d, 0xaa,
- 0x85, 0x06, 0xed, 0x28, 0x97, 0x63, 0x7e, 0xb7, 0x7b, 0x3b, 0xd1, 0x9d,
- 0xa3, 0x25, 0xba, 0x1b, 0x16, 0xe9, 0x76, 0x48, 0x72, 0xd3, 0x01, 0x37,
- 0x8a, 0x82, 0xde, 0x0a, 0x47, 0xf7, 0xf2, 0x1b, 0xec, 0x25, 0x38, 0xa2,
- 0x40, 0x83, 0xab, 0xce, 0x3d, 0x30, 0xc8, 0x02, 0x46, 0x2d, 0xec, 0x3d,
- 0x7b, 0xf3, 0xbe, 0x76, 0xa6, 0x57, 0x6d, 0xeb, 0x87, 0x3e, 0xa3, 0x76,
- 0x4d, 0x43, 0xed, 0x5e, 0x7f, 0x0c, 0x30, 0x86, 0xa0, 0xab, 0xd0, 0x93,
- 0x0c, 0xbf, 0xcc, 0x6c, 0x1b, 0xd4, 0xef, 0xe6, 0xc8, 0xdc, 0x54, 0xa9,
- 0xd9, 0x2b, 0x92, 0x33, 0x6f, 0x99, 0x24, 0xcb, 0x45, 0x99, 0x54, 0x9a,
- 0xd9, 0x8c, 0x68, 0x09, 0xeb, 0xb8, 0x6f, 0xff, 0x48, 0xa7, 0xa9, 0xc0,
- 0xd1, 0x89, 0xfb, 0x18, 0x34, 0x73, 0xcb, 0x90, 0xfc, 0x1e, 0xef, 0x83,
- 0x7d, 0x6e, 0xa4, 0x3e, 0x57, 0x25, 0xef, 0x46, 0x8e, 0x66, 0x37, 0xfe,
- 0x11, 0x79, 0x36, 0x7c, 0x0d, 0x9e, 0xaf, 0x56, 0xbe, 0xa0, 0xd0, 0x04,
- 0xea, 0x36, 0xb9, 0xed, 0x61, 0x5a, 0xcf, 0x63, 0x44, 0x91, 0xe7, 0x3c,
- 0x4b, 0x1e, 0xf3, 0xff, 0x3c, 0xdb, 0xe4, 0x68, 0x66, 0x83, 0x75, 0x83,
- 0xf7, 0x26, 0x97, 0x79, 0x6d, 0x07, 0xa8, 0x89, 0x1d, 0x35, 0xcb, 0x45,
- 0xf8, 0x41, 0x8e, 0x35, 0xd2, 0xc4, 0x8e, 0x65, 0x7b, 0x02, 0x6f, 0x9e,
- 0xef, 0xac, 0x92, 0xf0, 0x9d, 0xe3, 0x46, 0x9e, 0x7c, 0xe0, 0xab, 0x62,
- 0x3d, 0x6b, 0x34, 0x57, 0x5a, 0x8f, 0xdb, 0x50, 0x37, 0xe0, 0x36, 0xb1,
- 0xa7, 0x0d, 0xe5, 0x41, 0xb6, 0x06, 0x70, 0xda, 0x6e, 0x63, 0x16, 0x2d,
- 0xde, 0x6b, 0xdd, 0xe1, 0xfe, 0xdc, 0xb7, 0x55, 0xd6, 0xc8, 0x2a, 0x6f,
- 0x62, 0xf4, 0x7e, 0x17, 0xfb, 0xbd, 0xce, 0xb1, 0xc8, 0x36, 0xff, 0x4a,
- 0xdc, 0x7f, 0x16, 0x7b, 0x9e, 0x5b, 0x6c, 0x73, 0xdb, 0x40, 0x23, 0x7b,
- 0xa3, 0x25, 0x54, 0xf8, 0x5f, 0x86, 0xf3, 0xfd, 0x1f, 0xff, 0x2b, 0xd2,
- 0xaa, 0xe0, 0x74, 0xa5, 0x00, 0x7c, 0x2c, 0xb3, 0x0d, 0xbd, 0xdb, 0x18,
- 0x37, 0x70, 0x14, 0xd8, 0x25, 0x38, 0x71, 0xbf, 0xa5, 0x6e, 0x44, 0xed,
- 0x78, 0xae, 0x2b, 0x3c, 0x17, 0x62, 0x92, 0xbd, 0xf8, 0x07, 0x70, 0xa3,
- 0x49, 0x79, 0x9a, 0xdf, 0xce, 0xd3, 0x85, 0x41, 0x9e, 0x66, 0xae, 0xe9,
- 0xf0, 0x43, 0x14, 0x75, 0x2a, 0xac, 0x51, 0xe0, 0x6d, 0x73, 0x3f, 0xab,
- 0xa4, 0xc8, 0xbc, 0x0e, 0xb4, 0x6f, 0x13, 0xad, 0x0d, 0x74, 0xf8, 0x4d,
- 0x1d, 0x19, 0x5b, 0xa6, 0x97, 0x7f, 0x46, 0xf4, 0xf2, 0x80, 0x6d, 0x79,
- 0xfc, 0xc4, 0xa6, 0x89, 0x3d, 0xcb, 0xc0, 0xfc, 0xc2, 0x40, 0x46, 0xbc,
- 0x40, 0x3c, 0xed, 0x7b, 0x88, 0x93, 0x35, 0x3c, 0x4b, 0x88, 0x9d, 0x8c,
- 0x0d, 0xc7, 0x91, 0x5d, 0xe0, 0xb3, 0x8c, 0xb6, 0xb3, 0xa8, 0x4b, 0xf4,
- 0xae, 0xd8, 0x3a, 0xd5, 0x9c, 0x49, 0x6a, 0x67, 0xb1, 0x4a, 0x70, 0xac,
- 0x3a, 0x08, 0x4e, 0x1d, 0x40, 0xfc, 0xf9, 0x9d, 0x32, 0x1e, 0xab, 0x10,
- 0xd3, 0x8a, 0x87, 0x11, 0x9b, 0xfa, 0xa8, 0xe7, 0xf1, 0x6e, 0xe1, 0x7d,
- 0x00, 0xe5, 0xc3, 0xe8, 0x3b, 0x1a, 0xa7, 0x32, 0xbb, 0x27, 0xc5, 0x28,
- 0xf0, 0x6e, 0xc3, 0x40, 0x7f, 0x13, 0xba, 0x61, 0x7f, 0xe7, 0x10, 0x3f,
- 0xd8, 0xe7, 0x39, 0xf8, 0x54, 0xc7, 0xdc, 0x82, 0x66, 0xb7, 0xa9, 0xa5,
- 0xa4, 0xf1, 0xcb, 0x1f, 0xc6, 0xaf, 0x52, 0xcc, 0x83, 0x20, 0x14, 0xb0,
- 0x61, 0xfd, 0x66, 0x7a, 0x65, 0xec, 0xc8, 0xf5, 0xa0, 0x65, 0x4f, 0x89,
- 0xa2, 0x55, 0xa7, 0x40, 0x4d, 0xe0, 0xee, 0x42, 0xc3, 0x4d, 0x68, 0xd8,
- 0x1f, 0xd1, 0xb0, 0xff, 0x3f, 0x35, 0x0c, 0x7d, 0x42, 0x23, 0xb7, 0xc1,
- 0xa9, 0xb7, 0x7a, 0xfb, 0xe9, 0x99, 0xb5, 0xcc, 0x9a, 0x36, 0xe9, 0xce,
- 0xd1, 0xa7, 0xd5, 0x74, 0x49, 0x7e, 0x4a, 0x4d, 0xb7, 0x58, 0xd3, 0x2a,
- 0x6b, 0xba, 0xb8, 0x57, 0xd3, 0xd3, 0x18, 0x23, 0xd1, 0xe6, 0x19, 0xb5,
- 0x48, 0xda, 0x3c, 0xf0, 0xd8, 0xc8, 0x93, 0x72, 0xed, 0x31, 0xef, 0x98,
- 0xcb, 0xfe, 0x00, 0xff, 0xb6, 0x35, 0xb4, 0x49, 0xe3, 0xf5, 0x88, 0x81,
- 0x6a, 0xd5, 0x2a, 0xad, 0xc5, 0x7d, 0x54, 0xd2, 0xe1, 0xff, 0xd7, 0x8f,
- 0x5a, 0xa6, 0x29, 0x8f, 0x6a, 0x1f, 0xea, 0xdf, 0x88, 0xae, 0x68, 0x55,
- 0x9e, 0xa7, 0x65, 0x82, 0xf3, 0xe6, 0x4f, 0x80, 0x55, 0xbb, 0xcb, 0x7c,
- 0xb7, 0x45, 0x3d, 0xe6, 0x19, 0xca, 0xd0, 0x84, 0x06, 0xde, 0xe6, 0xd0,
- 0x4f, 0xdd, 0x48, 0x74, 0x74, 0x1b, 0xe3, 0x6e, 0x75, 0x99, 0x67, 0x06,
- 0xe9, 0xd7, 0xed, 0xd2, 0x85, 0x38, 0x06, 0xcf, 0x8a, 0x25, 0x62, 0x0d,
- 0xf2, 0xb9, 0x88, 0xf6, 0x41, 0x8e, 0x94, 0x58, 0xf7, 0x13, 0xa9, 0xee,
- 0x9f, 0x87, 0xaf, 0x26, 0x50, 0x66, 0xed, 0x1f, 0x4e, 0xb5, 0x3f, 0x85,
- 0x37, 0xd7, 0xad, 0xa8, 0x09, 0x87, 0xc0, 0xc7, 0x0d, 0xc6, 0x37, 0x8f,
- 0x58, 0xc7, 0xf3, 0xff, 0x33, 0x5a, 0xb5, 0x19, 0x63, 0xdb, 0xfc, 0x01,
- 0xcd, 0x41, 0x7f, 0xa8, 0xdf, 0xe6, 0xbe, 0x6c, 0x93, 0xf5, 0x15, 0x69,
- 0xdf, 0x0f, 0xf7, 0xf4, 0x45, 0xfd, 0x36, 0xf7, 0x63, 0x7d, 0x1c, 0x22,
- 0xe5, 0x3a, 0x9f, 0xdb, 0x1e, 0xeb, 0x03, 0x76, 0x35, 0xd4, 0x71, 0x6e,
- 0xc1, 0xf6, 0x7c, 0x86, 0xf3, 0x3a, 0x39, 0xef, 0xe0, 0x73, 0x7e, 0xcf,
- 0x79, 0x3e, 0xd4, 0xc8, 0x19, 0xf0, 0xfe, 0x3b, 0xea, 0x27, 0x35, 0xb2,
- 0x02, 0x4d, 0x5c, 0x54, 0x13, 0x8d, 0xbc, 0x86, 0xf7, 0x19, 0x94, 0x57,
- 0xf6, 0x68, 0x24, 0xb3, 0x7b, 0xf2, 0x39, 0x1e, 0xf4, 0x4a, 0xf1, 0x99,
- 0xcb, 0xf3, 0x29, 0x1b, 0xd4, 0xd2, 0x52, 0x3d, 0xd4, 0x87, 0x7a, 0x98,
- 0x40, 0xcc, 0xc8, 0xa5, 0x5c, 0xc7, 0xdb, 0xfe, 0x48, 0xf1, 0x1d, 0x4b,
- 0xb4, 0x89, 0xb5, 0x31, 0x7a, 0x9e, 0xfd, 0xbf, 0xf4, 0x41, 0xe0, 0x51,
- 0x3c, 0x37, 0x72, 0x11, 0x3e, 0x17, 0xa2, 0xe8, 0x15, 0x07, 0xed, 0x59,
- 0x4e, 0x12, 0x63, 0x9f, 0xc3, 0xd9, 0xcb, 0x78, 0x20, 0x0f, 0xb4, 0x67,
- 0xa1, 0x07, 0x8e, 0x05, 0xbb, 0xd1, 0x96, 0xed, 0xa1, 0xae, 0x06, 0xff,
- 0x33, 0x26, 0xcb, 0xd2, 0x52, 0xdf, 0x60, 0x3b, 0xe8, 0x6d, 0xbf, 0x5c,
- 0x4c, 0x87, 0xae, 0x1e, 0xe3, 0xc4, 0x3c, 0x6a, 0x8e, 0xe0, 0xd4, 0x88,
- 0x71, 0xda, 0x19, 0xe2, 0xd4, 0x4c, 0x71, 0x6a, 0xc6, 0x38, 0x3d, 0x48,
- 0x71, 0xfa, 0xf3, 0x13, 0x70, 0xda, 0x79, 0x0a, 0x9c, 0x0c, 0xda, 0xb2,
- 0x4b, 0x38, 0x6f, 0xf5, 0x38, 0x77, 0xbd, 0xef, 0xec, 0x97, 0x7b, 0xb1,
- 0xdf, 0xc7, 0xb0, 0x8a, 0x18, 0xab, 0x2d, 0x1a, 0xcd, 0x43, 0x2c, 0xf3,
- 0x1e, 0x15, 0x70, 0x6e, 0xe4, 0xe9, 0xea, 0x9e, 0x5c, 0x24, 0x00, 0x4e,
- 0xb5, 0x14, 0xa7, 0xab, 0xc0, 0xa9, 0x96, 0xe2, 0xb4, 0x3e, 0x82, 0xd3,
- 0xfa, 0x18, 0x4e, 0x1c, 0x53, 0x2a, 0xc6, 0x7a, 0x37, 0xc3, 0x28, 0xc3,
- 0x47, 0xa7, 0x9b, 0x62, 0x0a, 0xfb, 0x3f, 0x4e, 0xed, 0x9f, 0xaa, 0x9c,
- 0xff, 0x02, 0xbb, 0x97, 0x54, 0x39, 0x3e, 0x17, 0xf8, 0xfb, 0x71, 0xbe,
- 0x82, 0xb9, 0x5c, 0xcf, 0xe1, 0x3d, 0x21, 0xcf, 0xb5, 0x47, 0x63, 0xd1,
- 0x07, 0x88, 0x45, 0x5c, 0xc7, 0xfd, 0x54, 0xa9, 0x06, 0xcd, 0x2b, 0xc8,
- 0xe1, 0xfd, 0x61, 0x0e, 0x9f, 0xf8, 0xe1, 0x6a, 0x9a, 0xc3, 0x6f, 0xd9,
- 0x9c, 0xc3, 0x9f, 0xd0, 0x68, 0x62, 0x39, 0xc5, 0x93, 0x79, 0x3d, 0x89,
- 0xb6, 0xb3, 0x31, 0xee, 0x6d, 0xc4, 0xf2, 0x55, 0xf8, 0xa0, 0x19, 0xf3,
- 0x13, 0x79, 0x57, 0xca, 0x5d, 0xe4, 0xbb, 0xe4, 0x87, 0x09, 0x4f, 0x3f,
- 0xdb, 0x5c, 0xec, 0xef, 0x88, 0xd9, 0x46, 0x43, 0xc5, 0x1d, 0xe0, 0x6e,
- 0x18, 0xc7, 0xea, 0x73, 0x41, 0x97, 0x5a, 0x47, 0xaa, 0x57, 0x22, 0xe0,
- 0xee, 0x7e, 0xfd, 0x34, 0x9f, 0x39, 0xf9, 0x45, 0xaf, 0x82, 0xfa, 0x81,
- 0x41, 0xc8, 0x83, 0x70, 0xa7, 0xa1, 0x96, 0x77, 0x5a, 0x42, 0xbe, 0x83,
- 0x32, 0x6c, 0x82, 0x70, 0xba, 0x21, 0x57, 0x4b, 0xe0, 0x43, 0x8b, 0x5c,
- 0xac, 0xd3, 0x0d, 0xe3, 0x7b, 0x4d, 0x43, 0xa9, 0x1a, 0xc8, 0x37, 0xc9,
- 0xc0, 0x99, 0x0f, 0x9f, 0x98, 0x46, 0x7b, 0x80, 0x9c, 0x08, 0x79, 0x80,
- 0xb7, 0x08, 0xbf, 0x1c, 0x03, 0x76, 0xa1, 0x0a, 0xdb, 0x6f, 0xe9, 0xc9,
- 0x9d, 0x88, 0xc8, 0x8b, 0xfd, 0xf5, 0x71, 0xca, 0x91, 0x38, 0xe7, 0x92,
- 0x6a, 0x3d, 0x32, 0x9b, 0x0e, 0xb8, 0x8e, 0x33, 0xa5, 0x13, 0x72, 0x5e,
- 0x7d, 0xcc, 0x90, 0xaf, 0x71, 0x3c, 0x7f, 0x00, 0x1f, 0xe2, 0x7b, 0x9b,
- 0xcf, 0x19, 0x85, 0x73, 0x73, 0xdc, 0x7d, 0xca, 0x88, 0x37, 0x34, 0x89,
- 0xd8, 0x87, 0xd8, 0x3b, 0xcd, 0x58, 0xb9, 0xc9, 0x19, 0xc4, 0xe3, 0x1d,
- 0x97, 0x93, 0x79, 0xfe, 0xa4, 0x25, 0x1c, 0xc6, 0x7d, 0x07, 0xfe, 0x5b,
- 0xed, 0x39, 0x1c, 0x73, 0x3f, 0xaf, 0xd0, 0x43, 0x8a, 0x39, 0x29, 0x4e,
- 0x20, 0x16, 0x9f, 0x86, 0x8d, 0x1b, 0xeb, 0x31, 0xc9, 0xbd, 0x32, 0x9b,
- 0x0f, 0xf7, 0x8c, 0xf1, 0x17, 0x65, 0xbc, 0xec, 0x82, 0xd3, 0x95, 0x74,
- 0xbe, 0x51, 0x8e, 0x2c, 0x20, 0xe5, 0x79, 0xa0, 0x0d, 0xf3, 0xb7, 0xa2,
- 0x8e, 0x7e, 0xbc, 0x46, 0xd6, 0x25, 0xdb, 0x1c, 0xd1, 0xc6, 0xc7, 0x99,
- 0xdd, 0x67, 0x8c, 0xea, 0xc8, 0x18, 0x45, 0xde, 0x9b, 0x68, 0x3a, 0xcf,
- 0xa4, 0xf7, 0x0c, 0x8e, 0x2d, 0x02, 0x3a, 0x95, 0x9f, 0x93, 0xb1, 0x0f,
- 0x0f, 0x7b, 0xf6, 0xe3, 0xfa, 0x5f, 0xe9, 0xe3, 0xe3, 0xfe, 0x56, 0x4d,
- 0xca, 0xc7, 0x12, 0x6e, 0xda, 0x78, 0x87, 0x0f, 0x46, 0xd6, 0xae, 0xed,
- 0x33, 0xef, 0xd7, 0x38, 0x5d, 0x43, 0xbc, 0x21, 0x57, 0xc1, 0x1d, 0xcc,
- 0x27, 0x7c, 0x87, 0xaf, 0x67, 0x3e, 0x04, 0x6f, 0xe8, 0x5c, 0x3b, 0xe5,
- 0x8b, 0x9c, 0xf0, 0x85, 0xf3, 0xba, 0xc5, 0x55, 0xf0, 0xa5, 0x0d, 0xbe,
- 0xc0, 0xae, 0xa1, 0x55, 0xa7, 0xc1, 0x05, 0x8e, 0x4d, 0x28, 0x87, 0xcc,
- 0x1d, 0xe6, 0x0a, 0xf3, 0xe6, 0x31, 0x5f, 0x5e, 0xe9, 0x1a, 0xc6, 0xe6,
- 0xa7, 0x70, 0xe5, 0x8d, 0x98, 0x2b, 0xcc, 0xd9, 0x24, 0x7e, 0x74, 0x80,
- 0x55, 0x90, 0xc6, 0x8f, 0x00, 0xf1, 0xa3, 0xc6, 0xf9, 0x4f, 0x1c, 0x0b,
- 0x12, 0xfd, 0xac, 0x41, 0x3f, 0x35, 0x85, 0xf3, 0x23, 0xd6, 0x0e, 0xdb,
- 0xb1, 0x7e, 0xd8, 0xae, 0x90, 0xda, 0x8d, 0xc7, 0x91, 0x76, 0xcf, 0x32,
- 0xb3, 0x38, 0xd2, 0x86, 0x76, 0x3a, 0xa9, 0x8e, 0xda, 0xa9, 0x8e, 0xd0,
- 0xa7, 0xa5, 0x54, 0xf8, 0x4c, 0xb0, 0x4c, 0x1f, 0xf1, 0xa3, 0x13, 0x8f,
- 0xd9, 0xa2, 0xe4, 0x2e, 0xc3, 0xda, 0xe6, 0xb8, 0x3b, 0x12, 0x6f, 0xd3,
- 0x7b, 0x6e, 0x23, 0xbe, 0xe7, 0x7e, 0x45, 0x1f, 0x8f, 0xb7, 0x38, 0x6b,
- 0xe2, 0x7b, 0xee, 0x29, 0x9d, 0xef, 0xb9, 0x01, 0x7d, 0x49, 0x1f, 0xbd,
- 0xe7, 0x06, 0x63, 0xf7, 0xdc, 0xcc, 0x96, 0xeb, 0xf7, 0x8b, 0xbb, 0x99,
- 0x4f, 0x38, 0xf6, 0x32, 0x9f, 0xf6, 0xcb, 0x15, 0xb3, 0x3e, 0x1c, 0x93,
- 0x58, 0xef, 0x1c, 0xcb, 0x92, 0xdc, 0xec, 0x6e, 0x98, 0xe9, 0xe2, 0x55,
- 0xcc, 0x83, 0x72, 0x6f, 0x3f, 0x5d, 0x18, 0xa9, 0x2e, 0x26, 0x13, 0x9b,
- 0xde, 0xa8, 0x36, 0x5e, 0xd5, 0xc7, 0xb5, 0x91, 0x8d, 0x93, 0x69, 0x23,
- 0x19, 0x73, 0x47, 0x29, 0xe1, 0x0c, 0x2c, 0x23, 0x1e, 0x09, 0xbe, 0xa3,
- 0x21, 0x5e, 0x54, 0xf3, 0xb8, 0xa7, 0x14, 0x78, 0xec, 0x76, 0xf8, 0x2c,
- 0x35, 0x8a, 0x8c, 0x0b, 0xaf, 0xff, 0x61, 0x7c, 0x7f, 0xc0, 0xba, 0x0b,
- 0x01, 0xff, 0xfe, 0xf1, 0x09, 0x3e, 0xbe, 0x06, 0x3e, 0x66, 0xfb, 0x19,
- 0xad, 0xbf, 0x34, 0x52, 0x5f, 0x4e, 0x31, 0x4f, 0x7c, 0x7e, 0x2f, 0xd5,
- 0xc8, 0x26, 0x72, 0xb7, 0xfb, 0xc8, 0x8b, 0xde, 0x44, 0xfc, 0x0e, 0x06,
- 0x1f, 0x47, 0xf7, 0x8a, 0x2a, 0x75, 0x86, 0x36, 0xbf, 0xc0, 0xba, 0x2d,
- 0x71, 0x13, 0x5f, 0x6f, 0x0c, 0xb2, 0xb1, 0xb9, 0x9d, 0xeb, 0xfe, 0x8d,
- 0xf3, 0x19, 0x79, 0xdf, 0xb0, 0xef, 0xfb, 0x11, 0xe7, 0xbb, 0x77, 0x81,
- 0xc5, 0x3b, 0xe1, 0x34, 0xfd, 0x1e, 0x1c, 0x7b, 0x3b, 0xce, 0x79, 0x93,
- 0x5c, 0x17, 0xfe, 0xc3, 0x99, 0xc7, 0x67, 0xbd, 0xf7, 0x39, 0x99, 0x2e,
- 0xd3, 0x57, 0x1d, 0xae, 0x93, 0xa9, 0x7e, 0x2a, 0x8a, 0x2e, 0xe2, 0xdc,
- 0x5f, 0x19, 0x3b, 0xf7, 0x71, 0x07, 0x3c, 0xc9, 0xf9, 0x7f, 0x96, 0xf3,
- 0xef, 0x46, 0x33, 0xf3, 0xd6, 0x4d, 0x97, 0x5c, 0xa9, 0xde, 0xe7, 0x7c,
- 0x6c, 0x98, 0x8b, 0x11, 0x1d, 0x7a, 0x14, 0xc9, 0xf3, 0x7c, 0x36, 0xbd,
- 0x9b, 0xfa, 0x1c, 0x6d, 0x37, 0x1e, 0xe1, 0x1e, 0x53, 0x8b, 0x7f, 0x17,
- 0x72, 0xfb, 0x3c, 0x0f, 0x97, 0xf1, 0x0e, 0x39, 0x47, 0x78, 0xd2, 0x6f,
- 0x35, 0x2a, 0xf0, 0xb5, 0xcc, 0x75, 0x85, 0xe2, 0x7b, 0x21, 0xee, 0x6e,
- 0x3f, 0x6f, 0x53, 0x12, 0x3b, 0x6a, 0xce, 0x39, 0xac, 0x05, 0x98, 0x88,
- 0x06, 0x30, 0x9e, 0x47, 0xac, 0xb2, 0xcc, 0x93, 0x72, 0xf2, 0x5b, 0xd5,
- 0x1a, 0xc6, 0x56, 0x4e, 0x72, 0x2e, 0xf9, 0x51, 0xb4, 0x36, 0x88, 0xcf,
- 0x44, 0x87, 0xb9, 0xe6, 0x87, 0x07, 0x65, 0x7e, 0xbb, 0x21, 0x7f, 0xeb,
- 0x98, 0xc7, 0x7c, 0x02, 0x0f, 0x8b, 0xa2, 0x76, 0xc3, 0x14, 0xf5, 0x9e,
- 0x29, 0x96, 0x7a, 0x32, 0x54, 0x52, 0xc8, 0xd1, 0x14, 0xe7, 0x08, 0x3a,
- 0xd1, 0x73, 0x58, 0xcb, 0x2d, 0x53, 0xf8, 0xc8, 0xa3, 0xbe, 0xad, 0x58,
- 0x62, 0x85, 0x76, 0xb1, 0xc7, 0x47, 0x51, 0x72, 0xa7, 0x35, 0x45, 0x6d,
- 0x38, 0xf7, 0x23, 0xcc, 0xcd, 0x6b, 0x62, 0x2d, 0xf3, 0x79, 0xb6, 0x2c,
- 0x9d, 0x83, 0x8f, 0xce, 0xf7, 0x77, 0x11, 0x43, 0xf9, 0x3c, 0xcb, 0x23,
- 0xe6, 0x59, 0x26, 0x5f, 0xf6, 0xef, 0x62, 0xff, 0xef, 0xf4, 0x80, 0x0f,
- 0x72, 0xc7, 0xb7, 0x87, 0x79, 0x1a, 0x63, 0x58, 0x06, 0x17, 0xd9, 0x3e,
- 0x8a, 0x82, 0xc5, 0x38, 0x47, 0xc1, 0x5a, 0xe6, 0xca, 0xb7, 0x90, 0xa7,
- 0xd7, 0x69, 0xa1, 0x5c, 0x8f, 0xdf, 0x11, 0x72, 0x12, 0xfe, 0x5d, 0xc0,
- 0x12, 0x4d, 0x7c, 0xd7, 0xd2, 0xef, 0x80, 0x73, 0xf8, 0x45, 0x1e, 0x83,
- 0x73, 0x79, 0xd6, 0xe1, 0x7f, 0x01, 0x17, 0xc6, 0xf1, 0xb2, 0x84, 0x14,
- 0x00, 0x00, 0x00 };
-static u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b09FwBss[(0x250/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b09FwSbss[(0x34/4) + 1] = { 0x0 };
+ 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58,
+ 0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb,
+ 0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13,
+ 0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c,
+ 0x28, 0xc5, 0x90, 0x87, 0x52, 0x50, 0x57, 0x32, 0x09, 0x79, 0x69, 0xda,
+ 0xc6, 0x90, 0x3e, 0x79, 0x3b, 0x2b, 0xc7, 0x0e, 0x6c, 0xbc, 0x8d, 0x52,
+ 0xe4, 0x52, 0xfa, 0x60, 0xd6, 0xb1, 0x05, 0xcd, 0x46, 0x93, 0xd4, 0x7e,
+ 0x35, 0x36, 0x4e, 0x93, 0xa7, 0x42, 0x9f, 0x52, 0xf4, 0x18, 0xd2, 0x12,
+ 0xda, 0x52, 0x8a, 0x69, 0xa1, 0x09, 0x8d, 0xeb, 0xdb, 0xef, 0xdc, 0x99,
+ 0x91, 0x57, 0xb6, 0xec, 0xa4, 0x25, 0x85, 0x0a, 0x56, 0x77, 0xe6, 0xce,
+ 0x3d, 0xe7, 0x9e, 0x7b, 0xee, 0x77, 0xbe, 0x73, 0xee, 0x2d, 0xeb, 0x34,
+ 0x48, 0xd9, 0xdf, 0x30, 0x7e, 0x2f, 0x7e, 0xf7, 0x85, 0x17, 0xab, 0x8f,
+ 0x3c, 0xea, 0x10, 0x3d, 0xfa, 0x88, 0x66, 0x98, 0x06, 0x7d, 0x09, 0x7f,
+ 0x50, 0x22, 0x72, 0xfd, 0xfc, 0x23, 0x5b, 0xaf, 0x9d, 0x72, 0x42, 0x8f,
+ 0x6c, 0xa3, 0x26, 0xbe, 0xbe, 0xe4, 0x11, 0x05, 0xbd, 0x69, 0xa7, 0x4e,
+ 0xff, 0x92, 0xcd, 0x92, 0x49, 0xdc, 0xff, 0x50, 0xed, 0xc6, 0xfe, 0xcb,
+ 0x07, 0xdd, 0xeb, 0x67, 0x0d, 0xb2, 0x45, 0x6d, 0xd1, 0x16, 0x93, 0x64,
+ 0x8f, 0xd5, 0x9a, 0xce, 0x2f, 0xf6, 0x1e, 0x28, 0xd0, 0xae, 0x5c, 0x97,
+ 0xa0, 0xb8, 0x43, 0x4d, 0xab, 0x66, 0x53, 0xd4, 0x7e, 0x49, 0x0b, 0x3b,
+ 0x9e, 0x98, 0x85, 0x8e, 0xa0, 0x04, 0xfd, 0x1e, 0xde, 0x13, 0x53, 0x8b,
+ 0xce, 0xd8, 0xa4, 0xd7, 0x02, 0x3c, 0x4f, 0x51, 0xab, 0x23, 0xe5, 0x2b,
+ 0xbe, 0x46, 0x4b, 0xbe, 0x4d, 0x8b, 0xc2, 0x0d, 0x1c, 0xed, 0xa6, 0xac,
+ 0x4c, 0x48, 0xf9, 0x9c, 0xaf, 0x93, 0xee, 0xcd, 0x69, 0xe1, 0xfa, 0xbc,
+ 0x56, 0x5f, 0x9f, 0x67, 0x7f, 0xc0, 0xbe, 0x39, 0x2d, 0x58, 0xe7, 0xb6,
+ 0x66, 0xd7, 0xdb, 0xbb, 0x68, 0xb1, 0x44, 0x23, 0xba, 0x37, 0x85, 0xf9,
+ 0x4a, 0xd0, 0xe3, 0x50, 0xe8, 0x4f, 0x0b, 0x9d, 0x2a, 0xf8, 0x0d, 0xd0,
+ 0xac, 0x4f, 0x03, 0xba, 0xa7, 0x53, 0xa3, 0xa4, 0xd1, 0x1b, 0x55, 0x0b,
+ 0xbf, 0xc3, 0x5a, 0xb4, 0xfe, 0x7c, 0xa6, 0x87, 0xc7, 0xdb, 0xf8, 0xc6,
+ 0x36, 0xb3, 0x7c, 0xbf, 0xec, 0x30, 0x9e, 0x9f, 0xc3, 0x38, 0x8b, 0xc2,
+ 0xea, 0xed, 0xdf, 0x06, 0xf0, 0xac, 0xa1, 0xff, 0x30, 0xec, 0x62, 0x3d,
+ 0x0e, 0xec, 0x28, 0xd3, 0x4a, 0x67, 0x1e, 0xeb, 0x29, 0x50, 0x53, 0x4c,
+ 0x4c, 0x35, 0xc8, 0x84, 0x8c, 0x41, 0x41, 0xe9, 0x8a, 0xd4, 0x6b, 0x52,
+ 0x86, 0x55, 0x6f, 0xaa, 0xab, 0xe6, 0xd0, 0xc9, 0xf0, 0x0a, 0x14, 0xf9,
+ 0xc3, 0xd4, 0x12, 0x06, 0xc5, 0xfb, 0x2c, 0x0a, 0x16, 0x4c, 0xac, 0x71,
+ 0x14, 0x72, 0x1a, 0xe4, 0x5f, 0xcb, 0xf6, 0xbc, 0x48, 0xb1, 0x28, 0xa0,
+ 0x7f, 0x84, 0xe2, 0xd2, 0x6e, 0x4d, 0xaf, 0xbd, 0x82, 0xfe, 0x09, 0xd1,
+ 0xa5, 0x53, 0x68, 0x35, 0xbc, 0xef, 0xc6, 0x58, 0x7e, 0xd7, 0xa0, 0x8f,
+ 0x44, 0x98, 0x78, 0xd4, 0x4a, 0x72, 0x59, 0xee, 0x4f, 0xfb, 0x9a, 0xc9,
+ 0xed, 0xfb, 0xed, 0xc1, 0x4e, 0x41, 0x27, 0x3a, 0xb3, 0x98, 0x8f, 0x9a,
+ 0x46, 0x0d, 0xe3, 0xb0, 0x37, 0xbc, 0xbf, 0x81, 0xc2, 0xc1, 0xe3, 0xdc,
+ 0xcf, 0x7f, 0xe8, 0x77, 0xc8, 0xa8, 0xf1, 0xb7, 0x6f, 0x52, 0xfa, 0x2d,
+ 0xb5, 0x3f, 0xf4, 0x1f, 0xcb, 0xde, 0x4b, 0x22, 0x3c, 0xf3, 0x28, 0xd6,
+ 0xa8, 0x60, 0x83, 0xe7, 0x02, 0xf0, 0x11, 0xcf, 0xe8, 0xd4, 0x2c, 0x17,
+ 0xc9, 0xf5, 0x8f, 0xa2, 0xf7, 0xd7, 0x6d, 0x83, 0xea, 0xec, 0x2b, 0xdf,
+ 0xcc, 0x64, 0x18, 0x1b, 0x1f, 0x64, 0x76, 0x0a, 0x5a, 0x3c, 0x22, 0xe5,
+ 0x8a, 0x2f, 0xa5, 0x55, 0xf3, 0x9c, 0x13, 0x34, 0x5d, 0x36, 0x69, 0x52,
+ 0xa0, 0x85, 0x8f, 0xbd, 0x72, 0x83, 0x2c, 0x60, 0xa1, 0x1f, 0xff, 0xfc,
+ 0xf7, 0xa6, 0x86, 0x25, 0xd0, 0xb5, 0x36, 0xeb, 0x98, 0x70, 0x66, 0x95,
+ 0x8c, 0x94, 0xf1, 0xcc, 0xbd, 0x64, 0x2e, 0x65, 0x32, 0x52, 0x46, 0x55,
+ 0x81, 0x3d, 0x6f, 0x0a, 0xd8, 0x87, 0x75, 0x31, 0xc6, 0x89, 0xa2, 0x9e,
+ 0x6f, 0x37, 0xda, 0xb0, 0xd1, 0x43, 0xdb, 0x13, 0xf0, 0x0f, 0x51, 0x0b,
+ 0x63, 0xf5, 0xea, 0x7d, 0x8c, 0x0d, 0xec, 0xef, 0x82, 0x1d, 0xb5, 0xdd,
+ 0xf2, 0x29, 0x5a, 0xb0, 0xeb, 0xbd, 0xe9, 0xf2, 0x32, 0x3d, 0xc4, 0x73,
+ 0xd8, 0x56, 0xed, 0x88, 0xdd, 0x55, 0x72, 0x88, 0xc4, 0x41, 0x3c, 0xf7,
+ 0x88, 0xe2, 0x36, 0x69, 0xa1, 0x7f, 0x1f, 0xaf, 0x15, 0x72, 0xf3, 0x99,
+ 0xdc, 0x7c, 0x26, 0x37, 0x92, 0xc9, 0x3d, 0xd5, 0x27, 0xf7, 0x14, 0xcb,
+ 0x61, 0x6c, 0x90, 0x8d, 0x0d, 0xb2, 0xb1, 0x66, 0x36, 0x36, 0xca, 0xc6,
+ 0xa2, 0xed, 0x8d, 0xc1, 0x36, 0x77, 0xca, 0xd1, 0x6c, 0x8a, 0x3d, 0xf9,
+ 0x70, 0xe8, 0x53, 0x50, 0xf7, 0xdc, 0xcd, 0xba, 0x31, 0x42, 0xe7, 0xfc,
+ 0x21, 0x5a, 0x49, 0xc6, 0x28, 0x4e, 0x56, 0x28, 0x4c, 0x74, 0xc8, 0x8e,
+ 0x50, 0xd7, 0xbb, 0x2e, 0x67, 0x7d, 0x1f, 0x7b, 0x66, 0xb3, 0x5c, 0x79,
+ 0x96, 0x1c, 0x7c, 0x9f, 0x16, 0xcb, 0xe4, 0x03, 0x2b, 0x3a, 0xf6, 0xad,
+ 0xa2, 0x9e, 0xe3, 0xc4, 0xe7, 0x35, 0x37, 0xf5, 0xaa, 0x2b, 0x62, 0x72,
+ 0xcb, 0xa1, 0x41, 0x42, 0xaf, 0xc1, 0x4f, 0x49, 0x93, 0xa2, 0xc4, 0xa6,
+ 0x0f, 0x8d, 0x97, 0x54, 0x8c, 0xc6, 0x9d, 0x4d, 0x79, 0x79, 0xaf, 0x43,
+ 0x57, 0x30, 0xcf, 0xc5, 0xa4, 0x4c, 0xbf, 0x4a, 0x4a, 0xf4, 0x4e, 0x42,
+ 0x7a, 0xe8, 0x03, 0xc3, 0x25, 0x41, 0x6f, 0x27, 0xfd, 0x3e, 0xff, 0x88,
+ 0x7d, 0x6e, 0xdf, 0x5f, 0x23, 0x7b, 0xb4, 0xc6, 0x38, 0x4b, 0x39, 0xa0,
+ 0x9e, 0x72, 0x80, 0xc2, 0x52, 0xab, 0x13, 0x3f, 0x68, 0x80, 0x7f, 0x96,
+ 0xfc, 0x60, 0xb7, 0xa1, 0xf6, 0xa3, 0x89, 0x3d, 0xcc, 0x5b, 0xde, 0x9b,
+ 0xab, 0xce, 0x92, 0xe7, 0x9e, 0xaa, 0x33, 0x6a, 0x4f, 0x5b, 0x39, 0x2e,
+ 0xfb, 0xe6, 0xf8, 0x33, 0xe6, 0x18, 0xa2, 0x06, 0xe2, 0xec, 0x09, 0x13,
+ 0xb1, 0xe3, 0xfd, 0xdd, 0x60, 0x5c, 0x39, 0x1b, 0x8c, 0x6f, 0xa2, 0xf1,
+ 0x0d, 0x9b, 0xd6, 0xdb, 0x45, 0x72, 0xba, 0x43, 0xb4, 0xd4, 0x19, 0xa4,
+ 0xca, 0x05, 0x13, 0x63, 0xef, 0xa3, 0xca, 0xaa, 0x5e, 0xe2, 0x38, 0xae,
+ 0xc3, 0xc7, 0xe3, 0x5d, 0x09, 0x7c, 0x0e, 0xd2, 0xf8, 0x9a, 0xab, 0xb0,
+ 0xb3, 0xe4, 0xb5, 0x7c, 0x83, 0x7e, 0x4c, 0xd7, 0xf6, 0x15, 0xb0, 0xa6,
+ 0x12, 0xf9, 0x93, 0xfd, 0xf3, 0xe9, 0x80, 0x18, 0xf7, 0xc5, 0x45, 0xda,
+ 0xe5, 0x3a, 0xa4, 0xb3, 0x3e, 0x9b, 0xc6, 0x2f, 0xd8, 0x5a, 0xbd, 0xc3,
+ 0x3e, 0x63, 0xfc, 0xd9, 0x19, 0xfe, 0x4c, 0x2d, 0x3c, 0x53, 0xc4, 0x5c,
+ 0x7f, 0x91, 0xa1, 0x27, 0xb1, 0x0f, 0x3a, 0x2d, 0x55, 0x7f, 0x04, 0xfb,
+ 0xd0, 0xd7, 0xe5, 0x6f, 0xd7, 0xb3, 0x7e, 0xd6, 0x01, 0x7e, 0xf0, 0xef,
+ 0xa7, 0x90, 0xb9, 0xe0, 0x08, 0xcb, 0x14, 0x69, 0x7c, 0x95, 0xf9, 0x05,
+ 0x6d, 0x97, 0xdf, 0x79, 0x6d, 0x03, 0xd4, 0x80, 0x57, 0x1a, 0x53, 0x25,
+ 0xd8, 0xa5, 0x2b, 0xbe, 0x68, 0x80, 0x3f, 0x74, 0x6f, 0x10, 0x2d, 0xcf,
+ 0xf7, 0x73, 0x23, 0x8f, 0xa9, 0xb8, 0x33, 0x44, 0x75, 0xe0, 0xd7, 0x84,
+ 0x3d, 0xcb, 0x34, 0x51, 0x3e, 0xaa, 0xbe, 0xa1, 0xaf, 0xc7, 0xdf, 0xc4,
+ 0x6d, 0xdf, 0xf0, 0xde, 0xcb, 0x6d, 0x40, 0x6c, 0x7b, 0x2d, 0xcc, 0x62,
+ 0x65, 0x7e, 0xe1, 0xf1, 0xcd, 0x32, 0xf6, 0x06, 0x7c, 0x46, 0xf0, 0x25,
+ 0x51, 0xb7, 0x6d, 0x82, 0x6f, 0xf4, 0xaf, 0xea, 0x2c, 0x57, 0x62, 0x3d,
+ 0x58, 0xff, 0x9a, 0xa9, 0xd5, 0xcf, 0x78, 0xce, 0x1f, 0x88, 0xe5, 0x2b,
+ 0xf0, 0xc1, 0xc4, 0x4c, 0x8b, 0xc7, 0xf7, 0x2c, 0xf2, 0x56, 0x9b, 0xc2,
+ 0xc4, 0x9e, 0xc2, 0x73, 0x54, 0xff, 0xc9, 0x08, 0xf6, 0xda, 0x75, 0x5a,
+ 0xf4, 0x5b, 0xd8, 0x53, 0x20, 0xaf, 0x6b, 0xd2, 0x1b, 0x6d, 0xf6, 0x85,
+ 0x4d, 0x95, 0x35, 0x29, 0x4f, 0xfa, 0xbc, 0x27, 0xbf, 0x83, 0x5f, 0x08,
+ 0x2b, 0x9c, 0x98, 0xf9, 0x08, 0xfb, 0xb3, 0xde, 0xe3, 0xbd, 0xb1, 0x94,
+ 0x4f, 0xbc, 0xd5, 0x29, 0xec, 0xeb, 0x54, 0x66, 0x23, 0xef, 0x97, 0x49,
+ 0x2b, 0x55, 0x9d, 0xce, 0x57, 0x3f, 0x93, 0xba, 0xc7, 0xfc, 0x5a, 0x80,
+ 0x6f, 0x31, 0xae, 0x8b, 0x71, 0x49, 0x01, 0x3e, 0xfc, 0x07, 0x78, 0x45,
+ 0xca, 0xf3, 0x55, 0xf4, 0xaf, 0x1e, 0x87, 0xad, 0x06, 0x64, 0x53, 0x8c,
+ 0xb1, 0x3d, 0x73, 0xed, 0x7c, 0x7d, 0xde, 0xcc, 0x7b, 0x4a, 0xdf, 0x10,
+ 0x4d, 0x6e, 0x0c, 0xd1, 0xb3, 0xbd, 0x21, 0x1a, 0x3f, 0xcd, 0x32, 0xe0,
+ 0xa6, 0xaa, 0x27, 0x22, 0xc6, 0xa8, 0xa7, 0xfc, 0x50, 0x36, 0x74, 0x5e,
+ 0x27, 0xbe, 0x6f, 0x10, 0x2d, 0xf7, 0x78, 0x0e, 0xb3, 0x4f, 0xa7, 0x4e,
+ 0x87, 0x7e, 0x4a, 0x74, 0xa8, 0xc7, 0xb2, 0x5b, 0xbe, 0x83, 0x5e, 0x01,
+ 0x9d, 0x82, 0x38, 0x0f, 0x19, 0x1e, 0xf2, 0xdd, 0x7a, 0x88, 0xfc, 0x15,
+ 0xe1, 0x37, 0x87, 0x9c, 0xc6, 0xeb, 0x9f, 0x42, 0xfc, 0x31, 0x8f, 0xdf,
+ 0xc4, 0xda, 0x0b, 0xb4, 0xe2, 0xcf, 0x63, 0x0c, 0xef, 0xf1, 0x61, 0x7c,
+ 0x1f, 0x46, 0x1e, 0xc8, 0xf2, 0x84, 0xe0, 0x3c, 0xb1, 0x1b, 0x71, 0x30,
+ 0x00, 0xee, 0xdf, 0x63, 0x6e, 0xcf, 0x13, 0x18, 0x57, 0xda, 0x83, 0xbc,
+ 0x70, 0x3f, 0xfa, 0x59, 0xd7, 0x28, 0xda, 0x01, 0xbc, 0xef, 0xc1, 0xd8,
+ 0xfe, 0x1c, 0x91, 0xcb, 0xdd, 0x2d, 0x3f, 0x20, 0x26, 0x56, 0x11, 0x2b,
+ 0x6b, 0x9c, 0x27, 0x38, 0x16, 0x79, 0x4f, 0x8b, 0xe0, 0x6f, 0x1b, 0x3a,
+ 0x78, 0x6f, 0x8b, 0xd8, 0x43, 0xce, 0x71, 0x82, 0x2a, 0x1b, 0x3b, 0xe5,
+ 0x0f, 0x5e, 0x0f, 0x38, 0xec, 0x34, 0xaf, 0xc5, 0x15, 0x0d, 0xf0, 0x59,
+ 0xb8, 0x31, 0x8d, 0xef, 0xc8, 0x85, 0x22, 0xb2, 0x1b, 0xa7, 0x53, 0x2e,
+ 0x6b, 0x6c, 0x8c, 0x29, 0x9c, 0xc6, 0x89, 0xc0, 0x3b, 0x73, 0x59, 0xce,
+ 0x5d, 0x8c, 0x25, 0x0a, 0x20, 0xbb, 0x19, 0x1a, 0x52, 0x2e, 0xf9, 0x23,
+ 0xd4, 0x00, 0x2e, 0x03, 0xf0, 0x59, 0x03, 0x7c, 0x56, 0xef, 0xe3, 0xb3,
+ 0xfa, 0xe7, 0xf2, 0x19, 0xb8, 0xaa, 0x03, 0xae, 0xea, 0x80, 0xab, 0x50,
+ 0x1b, 0xbc, 0x03, 0xec, 0xbf, 0xdd, 0xd9, 0x89, 0xe3, 0x98, 0xdf, 0x98,
+ 0xe7, 0xa6, 0xe8, 0xf2, 0xde, 0xff, 0x94, 0xe7, 0x8e, 0x83, 0x13, 0x6c,
+ 0xfa, 0xfe, 0xde, 0x7b, 0x73, 0xdd, 0x09, 0x70, 0x9d, 0xf5, 0xf9, 0x5c,
+ 0xd7, 0x64, 0xae, 0x33, 0x81, 0xbd, 0x26, 0x78, 0x40, 0x5f, 0xed, 0x9f,
+ 0xe7, 0x24, 0xe6, 0xe1, 0x3e, 0x33, 0xcb, 0xa5, 0x3a, 0x75, 0x81, 0x7b,
+ 0xc3, 0xe3, 0x79, 0x60, 0x73, 0x92, 0x72, 0xd1, 0x13, 0x66, 0x89, 0xac,
+ 0x49, 0xe0, 0x61, 0x75, 0x88, 0x8c, 0xd3, 0xb7, 0xf0, 0x8e, 0x7a, 0x00,
+ 0x71, 0x8e, 0x7f, 0x1b, 0xb9, 0x8e, 0x41, 0x70, 0x8d, 0x49, 0x85, 0x55,
+ 0x0b, 0xef, 0xda, 0xb6, 0x71, 0x87, 0x90, 0x6f, 0x8c, 0x9a, 0x3b, 0xf3,
+ 0x7b, 0x7e, 0xee, 0xf1, 0x98, 0x41, 0xd2, 0xd7, 0x5c, 0xc7, 0xd1, 0x5d,
+ 0xff, 0x1a, 0xb8, 0xe1, 0x7d, 0x8f, 0xf9, 0x2f, 0x06, 0x0a, 0x0a, 0x64,
+ 0xae, 0xca, 0xe3, 0x56, 0x8d, 0xe7, 0x6e, 0x3a, 0x88, 0x73, 0xe7, 0x35,
+ 0xe0, 0x87, 0x73, 0xe7, 0xf9, 0x2a, 0xd7, 0x7b, 0x69, 0x8c, 0xb6, 0x7a,
+ 0xf9, 0x9c, 0xa3, 0xb0, 0xdb, 0x82, 0x4c, 0xff, 0x58, 0xc6, 0x8b, 0x94,
+ 0xcf, 0x62, 0x4d, 0x06, 0xe6, 0xb1, 0xd6, 0x6c, 0x2a, 0xac, 0xb1, 0x5f,
+ 0x5c, 0xc8, 0x57, 0xc4, 0x1c, 0x6d, 0x6e, 0xe3, 0x83, 0x93, 0xbd, 0x0f,
+ 0x4c, 0xe6, 0x50, 0x03, 0xb1, 0x59, 0xc4, 0xbc, 0xd6, 0x96, 0x2e, 0xca,
+ 0x74, 0xb1, 0xbc, 0x57, 0x7e, 0x76, 0x4b, 0x9e, 0x79, 0x6d, 0xa2, 0xcc,
+ 0xfc, 0xc5, 0x76, 0x18, 0x8a, 0x4b, 0x07, 0x33, 0x2e, 0xad, 0x60, 0x3f,
+ 0x07, 0x55, 0x5c, 0xea, 0xde, 0xc3, 0x19, 0x9f, 0xee, 0x46, 0xcb, 0x7d,
+ 0x37, 0xb2, 0x38, 0x31, 0x61, 0x2f, 0xeb, 0x1d, 0x24, 0x03, 0x76, 0x45,
+ 0x6a, 0x4d, 0x7f, 0x93, 0x4b, 0x1e, 0x73, 0x04, 0xe3, 0x53, 0x71, 0x29,
+ 0xfa, 0x27, 0x60, 0x33, 0xf3, 0x02, 0xcb, 0xb1, 0xfc, 0x4e, 0x72, 0x7f,
+ 0x85, 0x9c, 0xd8, 0x41, 0x0e, 0x7d, 0x1b, 0x2c, 0xc3, 0xdc, 0x30, 0x8a,
+ 0xf1, 0x21, 0xf3, 0x02, 0x7c, 0xc6, 0xb2, 0xe5, 0x2c, 0x0e, 0x23, 0x7c,
+ 0xe3, 0xba, 0x97, 0xe3, 0x23, 0x20, 0xab, 0xc6, 0xeb, 0xe0, 0x9a, 0x98,
+ 0xf3, 0x22, 0xd7, 0xa1, 0x5c, 0x6f, 0xe6, 0xf5, 0xa9, 0x37, 0x35, 0x7b,
+ 0xb7, 0x5a, 0x53, 0xf4, 0xd7, 0x9a, 0xe8, 0xd8, 0xb1, 0xd6, 0xf4, 0xac,
+ 0xb4, 0xd6, 0xac, 0x58, 0x77, 0xaf, 0x35, 0x73, 0xd9, 0x7b, 0xd7, 0x9a,
+ 0x71, 0x87, 0xf7, 0x08, 0xb9, 0x54, 0xf0, 0x5a, 0xa8, 0x69, 0x66, 0x7c,
+ 0x11, 0xdd, 0xc6, 0x17, 0xd1, 0x69, 0xb7, 0x7c, 0x8e, 0x38, 0xa6, 0xdd,
+ 0x72, 0x8b, 0x6b, 0xa0, 0x0d, 0xae, 0x81, 0x0c, 0xe4, 0xd2, 0x7e, 0xce,
+ 0xc8, 0x7d, 0xc2, 0xbe, 0x1c, 0x04, 0x27, 0xb3, 0x1f, 0x8b, 0x19, 0x3f,
+ 0xa0, 0xf5, 0x3e, 0x05, 0x3f, 0xe4, 0xbc, 0xc2, 0x3e, 0xfb, 0x7f, 0xe2,
+ 0x15, 0xb2, 0x07, 0xc0, 0x0f, 0x36, 0xea, 0xcd, 0x46, 0x47, 0xd9, 0x02,
+ 0x5f, 0x48, 0x39, 0xe7, 0x33, 0xf6, 0x53, 0xbe, 0x50, 0x3e, 0x51, 0x78,
+ 0x2c, 0xd2, 0xbb, 0x3e, 0x63, 0x01, 0xe7, 0x23, 0x8f, 0x73, 0x22, 0xf3,
+ 0xef, 0x4d, 0xf9, 0xae, 0x17, 0xa2, 0x2f, 0xc2, 0x9e, 0x33, 0x0e, 0xe6,
+ 0xb5, 0x43, 0xeb, 0x36, 0xe4, 0x18, 0x0b, 0xe5, 0x3b, 0xce, 0x3d, 0xe9,
+ 0xf9, 0x84, 0x6b, 0xe1, 0xff, 0x16, 0x1b, 0x17, 0xef, 0x82, 0x8d, 0x37,
+ 0x33, 0x6c, 0xfc, 0xf2, 0x1e, 0xd8, 0xb8, 0xf8, 0x05, 0xb1, 0xe1, 0x3a,
+ 0x1f, 0xa3, 0x5e, 0x7a, 0xcf, 0x63, 0x7c, 0x48, 0xf9, 0xb1, 0xbf, 0x53,
+ 0x3e, 0x09, 0x6c, 0xe3, 0xd5, 0x9b, 0x32, 0xce, 0x72, 0x89, 0xfe, 0xd6,
+ 0xad, 0x5c, 0x32, 0xfe, 0x6a, 0x8a, 0x8b, 0xf1, 0xb7, 0xa4, 0x3c, 0xb7,
+ 0x03, 0x0e, 0xb8, 0x56, 0xbe, 0x0a, 0x1e, 0x68, 0xd1, 0xff, 0xa2, 0x56,
+ 0x66, 0xce, 0xae, 0xda, 0x47, 0xdb, 0xf9, 0xbe, 0xe7, 0x7b, 0x5e, 0xa0,
+ 0xb3, 0x62, 0x17, 0xfc, 0xb5, 0x9f, 0x5a, 0xaf, 0x9b, 0x7c, 0x7e, 0x00,
+ 0x1e, 0x1e, 0x37, 0x39, 0x56, 0x71, 0x56, 0xc4, 0x73, 0x7f, 0x3d, 0x0d,
+ 0x3c, 0xfa, 0xbc, 0x76, 0xb5, 0xee, 0x3e, 0xae, 0xff, 0x1e, 0x4a, 0x92,
+ 0x3b, 0xf2, 0xc8, 0xb6, 0x73, 0xb3, 0x81, 0x73, 0x73, 0x5d, 0xe9, 0xe0,
+ 0xb3, 0x55, 0xea, 0xbf, 0x13, 0xea, 0xac, 0x7c, 0x53, 0x9e, 0x53, 0xe7,
+ 0xe5, 0xd1, 0x02, 0x0d, 0xce, 0x67, 0x58, 0x61, 0x5f, 0x0c, 0xab, 0x7a,
+ 0x82, 0x31, 0xd5, 0x42, 0xbe, 0x5d, 0x82, 0x3f, 0x1a, 0x2a, 0x16, 0xb0,
+ 0xf6, 0xcc, 0x1f, 0x2d, 0xf8, 0xa3, 0x9e, 0xa4, 0x31, 0xf1, 0xe5, 0x9e,
+ 0x1d, 0xfe, 0x88, 0x7c, 0x6a, 0x2f, 0x9a, 0x38, 0x6f, 0x5f, 0x49, 0x54,
+ 0xfe, 0x5c, 0x68, 0xb5, 0xa9, 0xf9, 0x60, 0xed, 0x38, 0xd7, 0x6d, 0x5c,
+ 0x77, 0xcd, 0x2c, 0x55, 0xd1, 0xd7, 0xb3, 0x29, 0x84, 0x4f, 0xbe, 0x7d,
+ 0x90, 0x16, 0x8d, 0x1a, 0xe3, 0x17, 0xef, 0x09, 0x35, 0xc3, 0x83, 0xa8,
+ 0xa5, 0x92, 0xb1, 0x45, 0xbd, 0x36, 0x06, 0x1c, 0x35, 0x29, 0x80, 0x9d,
+ 0x01, 0x74, 0xcf, 0xb5, 0x6d, 0x7b, 0xb9, 0xcd, 0x67, 0xa4, 0x26, 0xf1,
+ 0x19, 0xbc, 0xdb, 0xbb, 0x0e, 0x7d, 0x03, 0xcf, 0xe0, 0xcc, 0xea, 0xc4,
+ 0xc0, 0xd5, 0xcb, 0x89, 0x45, 0xad, 0x12, 0xdf, 0x51, 0x30, 0x57, 0x96,
+ 0xa1, 0xe3, 0x99, 0x42, 0x8a, 0xcb, 0x32, 0xf4, 0x70, 0xcc, 0x10, 0xe6,
+ 0x63, 0xff, 0xe5, 0x58, 0x2b, 0xf7, 0xd5, 0xee, 0x85, 0xec, 0xbc, 0x4a,
+ 0xca, 0x07, 0xec, 0xdf, 0xd0, 0x7b, 0xbe, 0x90, 0xdf, 0xc7, 0xb4, 0x10,
+ 0xf3, 0x8d, 0x7d, 0x8c, 0x43, 0x0d, 0x78, 0xc3, 0x98, 0x84, 0xfb, 0x90,
+ 0x57, 0xf6, 0x21, 0x37, 0x97, 0x8a, 0xaa, 0x6d, 0x26, 0xc7, 0xb2, 0xf1,
+ 0xba, 0x1a, 0xc7, 0x39, 0x21, 0x4e, 0xd4, 0x59, 0x41, 0x8b, 0x3a, 0xe4,
+ 0x34, 0x7c, 0x9c, 0x81, 0x50, 0x5b, 0xac, 0x24, 0x9c, 0xcf, 0xf7, 0xd9,
+ 0xba, 0xe2, 0xb9, 0x4d, 0xc8, 0xe0, 0x79, 0x83, 0xf4, 0x86, 0xcf, 0xf7,
+ 0x07, 0xd9, 0xdd, 0x46, 0x89, 0x86, 0x21, 0x0f, 0xbb, 0xc6, 0xd8, 0xae,
+ 0xa0, 0xa1, 0x6a, 0x11, 0xd6, 0xbd, 0x5f, 0x4f, 0xef, 0x5c, 0x7e, 0x93,
+ 0xcd, 0x65, 0x83, 0x5f, 0x08, 0xe7, 0x1d, 0x9f, 0xf3, 0xda, 0xd7, 0x0c,
+ 0xba, 0x4e, 0x8a, 0x23, 0xc5, 0x37, 0x90, 0xef, 0x0e, 0x42, 0x26, 0x50,
+ 0xfc, 0x92, 0x9e, 0x19, 0x72, 0x99, 0x8a, 0xb1, 0x5d, 0xc7, 0x77, 0xcc,
+ 0xed, 0xef, 0x01, 0x62, 0xab, 0x9a, 0xcd, 0xd7, 0x8f, 0xd3, 0x4d, 0xe0,
+ 0x74, 0xb3, 0xb0, 0x75, 0xee, 0x28, 0x15, 0x30, 0x8e, 0x6d, 0x64, 0x2e,
+ 0x61, 0x99, 0x4f, 0xac, 0xed, 0x7a, 0x2a, 0x3b, 0xe8, 0xf8, 0x53, 0x9f,
+ 0x8e, 0x12, 0xaf, 0x4d, 0x34, 0xd2, 0xf3, 0xb3, 0xfa, 0x6b, 0xc0, 0xcf,
+ 0x38, 0x6f, 0x3c, 0xa0, 0x63, 0x1d, 0x5c, 0x7f, 0xd5, 0x55, 0x3f, 0x0e,
+ 0x56, 0xdb, 0xf4, 0xfe, 0x30, 0x9b, 0x67, 0x5f, 0x1a, 0x0f, 0x1e, 0xda,
+ 0x64, 0xb3, 0xcf, 0x76, 0x6b, 0x87, 0x79, 0x91, 0xd8, 0xbd, 0x19, 0x8d,
+ 0xf1, 0x66, 0xd4, 0x38, 0x07, 0xe3, 0x79, 0x0b, 0x1f, 0x8c, 0xd5, 0xcf,
+ 0xc7, 0xa8, 0xf5, 0x05, 0x31, 0xfa, 0x46, 0x9b, 0xb9, 0x22, 0xc5, 0x68,
+ 0xe3, 0x0e, 0x8c, 0xa2, 0x06, 0x2a, 0xe5, 0xf8, 0xe4, 0x78, 0xc9, 0xf1,
+ 0x99, 0x3f, 0xf3, 0xfd, 0x08, 0x38, 0x38, 0xe3, 0xb6, 0x18, 0xdc, 0x16,
+ 0xa9, 0x1c, 0xe7, 0x96, 0x23, 0x4a, 0xe3, 0x78, 0x19, 0x71, 0x1c, 0x19,
+ 0x9c, 0xf3, 0x38, 0x86, 0x59, 0x8e, 0xe3, 0x98, 0xe5, 0x46, 0x32, 0x39,
+ 0xb4, 0x88, 0xe7, 0x28, 0x8b, 0xe7, 0x16, 0x78, 0x37, 0xca, 0xe2, 0xb9,
+ 0x85, 0x18, 0x5e, 0xc9, 0xe2, 0xb9, 0x95, 0xc5, 0x33, 0xdf, 0xdb, 0x19,
+ 0x55, 0x95, 0x8b, 0x9d, 0x3a, 0x78, 0x6d, 0x45, 0xe9, 0x6c, 0x62, 0x9d,
+ 0xb0, 0xb1, 0x93, 0xc7, 0xc5, 0x1d, 0xf7, 0x5b, 0x58, 0xcf, 0xad, 0xbc,
+ 0x32, 0x8b, 0xbc, 0x72, 0x0e, 0x79, 0xa5, 0xdb, 0x77, 0xbf, 0x75, 0x56,
+ 0xe5, 0x95, 0x27, 0x8b, 0x79, 0x5e, 0xe9, 0x66, 0x79, 0xa5, 0xab, 0xf2,
+ 0xca, 0x13, 0x45, 0xce, 0x2b, 0x31, 0x05, 0xc5, 0xfe, 0xbc, 0x12, 0x6f,
+ 0xcb, 0x2b, 0xb9, 0x2c, 0xf7, 0xef, 0x94, 0x57, 0x72, 0x9f, 0x71, 0x6e,
+ 0xb1, 0x72, 0x5e, 0xbd, 0x2d, 0x9f, 0xe4, 0x63, 0xd8, 0x56, 0xe6, 0x25,
+ 0xe6, 0xe0, 0xb4, 0xae, 0xbf, 0x92, 0xe4, 0xb1, 0x74, 0x0c, 0xf3, 0xe0,
+ 0xbd, 0xb3, 0x53, 0x2c, 0xd9, 0x59, 0x2c, 0x0d, 0xa7, 0x32, 0x9d, 0xfe,
+ 0x78, 0x3a, 0x56, 0xdc, 0x1e, 0x4f, 0xb9, 0x9e, 0x3c, 0x9e, 0x52, 0x9d,
+ 0x1f, 0x1a, 0x65, 0xae, 0x07, 0x70, 0x96, 0x76, 0xfd, 0x39, 0xf4, 0x5e,
+ 0xe8, 0x4d, 0xa3, 0xae, 0x36, 0xe9, 0x6a, 0xce, 0x37, 0xea, 0xbe, 0x07,
+ 0x6d, 0x2f, 0xb7, 0xb5, 0xb8, 0xf5, 0xad, 0x8b, 0xda, 0xfa, 0x7d, 0xf0,
+ 0xc8, 0x79, 0xf5, 0xfd, 0x33, 0x79, 0xb5, 0x84, 0x33, 0xb0, 0x97, 0x8f,
+ 0x7b, 0x1d, 0xf3, 0xb9, 0xe2, 0x2c, 0x9e, 0x5e, 0xee, 0xdd, 0x82, 0xf9,
+ 0x8a, 0xc7, 0x7d, 0xff, 0x44, 0x0e, 0x41, 0x5d, 0xbe, 0x35, 0x96, 0xcf,
+ 0x38, 0x1e, 0xd6, 0xec, 0xd0, 0xa5, 0x6d, 0xe7, 0x9c, 0xf4, 0x7c, 0x83,
+ 0x75, 0xa3, 0x3e, 0xe1, 0x3a, 0x25, 0xfc, 0x8a, 0x4e, 0x2f, 0xd1, 0xb7,
+ 0x7c, 0xee, 0xd3, 0x69, 0xf6, 0x31, 0x29, 0x5f, 0x40, 0xcd, 0xf2, 0xf4,
+ 0xb6, 0x9a, 0xa5, 0x48, 0xe3, 0x07, 0xfa, 0xcf, 0x87, 0x37, 0xe5, 0xf8,
+ 0xa4, 0x7b, 0x36, 0xa0, 0x40, 0x9b, 0x5d, 0xe7, 0x5a, 0x76, 0xab, 0x76,
+ 0x25, 0x1a, 0xbd, 0x21, 0xf5, 0x49, 0xce, 0x85, 0x57, 0x33, 0x5f, 0xe1,
+ 0xdb, 0x99, 0x1b, 0xe0, 0xd6, 0x48, 0xdd, 0xf1, 0x06, 0xeb, 0x3c, 0x0f,
+ 0xbf, 0xa3, 0x4d, 0xb8, 0xbe, 0xb9, 0xdb, 0xbd, 0xab, 0x89, 0x7d, 0x71,
+ 0x9d, 0xa3, 0x06, 0xa9, 0xbb, 0x8b, 0x25, 0xdf, 0xfd, 0x59, 0x8b, 0x52,
+ 0x9e, 0x88, 0xfc, 0x05, 0xd8, 0x02, 0x9c, 0x8b, 0x45, 0xec, 0xcd, 0x24,
+ 0x78, 0xc9, 0x75, 0x0e, 0xe8, 0x42, 0x61, 0x7f, 0x19, 0xba, 0x8d, 0x03,
+ 0x5c, 0x3f, 0x7e, 0x2a, 0x97, 0x7b, 0x2a, 0x07, 0xfb, 0x8c, 0x91, 0x7a,
+ 0xb2, 0x5b, 0xe7, 0x36, 0x48, 0xf8, 0xb9, 0x80, 0x79, 0x9c, 0xbb, 0xe0,
+ 0xa7, 0x24, 0xa2, 0x33, 0x8e, 0x98, 0xed, 0x38, 0x62, 0xae, 0xa3, 0x03,
+ 0xdd, 0xb6, 0x4d, 0xbb, 0xb0, 0x27, 0xc8, 0xc1, 0xf4, 0x00, 0x6c, 0xb9,
+ 0xe0, 0x88, 0x3a, 0x6a, 0xc1, 0x1f, 0x18, 0xae, 0x78, 0x9a, 0x3e, 0xc1,
+ 0x1a, 0x6f, 0xc8, 0xf4, 0xde, 0xc5, 0x11, 0xd1, 0xd6, 0xdc, 0x37, 0x30,
+ 0x37, 0xdb, 0xc4, 0x31, 0xca, 0xf9, 0x72, 0x5e, 0x5b, 0x80, 0x8f, 0x8e,
+ 0xac, 0x6b, 0xe0, 0x35, 0xce, 0x97, 0x23, 0xd9, 0xfd, 0x12, 0xf6, 0x07,
+ 0xeb, 0xbf, 0x74, 0x47, 0xad, 0x99, 0xd7, 0x94, 0xe9, 0xdd, 0x69, 0x3c,
+ 0xc3, 0xf3, 0x13, 0x6c, 0x99, 0x98, 0xba, 0xa0, 0xce, 0x3d, 0xd3, 0xa8,
+ 0xf1, 0xb8, 0x95, 0xa8, 0x83, 0xf8, 0xae, 0x8b, 0x6b, 0x27, 0x89, 0xf8,
+ 0x4f, 0x9f, 0x63, 0x3e, 0x13, 0xcd, 0xb0, 0x0e, 0x3e, 0x1b, 0x71, 0xfc,
+ 0xfc, 0x1b, 0x2f, 0xf3, 0x0a, 0xbd, 0x68, 0x18, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 };
+static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
static struct fw_info bnx2_tpat_fw_09 = {
- .ver_major = 0x1,
- .ver_minor = 0x0,
- .ver_fix = 0x0,
+ .ver_major = 0x3,
+ .ver_minor = 0x4,
+ .ver_fix = 0x3,
.start_addr = 0x08000860,
.text_addr = 0x08000800,
- .text_len = 0x1480,
+ .text_len = 0x1864,
.text_index = 0x0,
.gz_text = bnx2_TPAT_b09FwText,
.gz_text_len = sizeof(bnx2_TPAT_b09FwText),
- .data_addr = 0x08001ca0,
+ .data_addr = 0x08002080,
.data_len = 0x0,
.data_index = 0x0,
.data = bnx2_TPAT_b09FwData,
- .sbss_addr = 0x08001ca0,
- .sbss_len = 0x34,
+ .sbss_addr = 0x08002088,
+ .sbss_len = 0x2c,
.sbss_index = 0x0,
.sbss = bnx2_TPAT_b09FwSbss,
- .bss_addr = 0x08001ce0,
- .bss_len = 0x250,
+ .bss_addr = 0x080020c0,
+ .bss_len = 0x850,
.bss_index = 0x0,
.bss = bnx2_TPAT_b09FwBss,
@@ -3308,732 +3279,769 @@ static struct fw_info bnx2_tpat_fw_09 = {
};
static u8 bnx2_TXP_b09FwText[] = {
- 0x1f, 0x8b, 0x08, 0x08, 0x51, 0xfe, 0x2f, 0x45, 0x00, 0x03, 0x74, 0x65,
- 0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x7b, 0x7f, 0x70,
- 0x1b, 0xe7, 0x99, 0xde, 0xbb, 0x0b, 0x80, 0x04, 0x29, 0x8a, 0x5a, 0x31,
- 0x30, 0x83, 0x38, 0xb4, 0x8d, 0x15, 0x17, 0x34, 0x6d, 0xf2, 0x1c, 0x58,
- 0xe5, 0xf9, 0xd8, 0x06, 0xb5, 0xd7, 0xc0, 0x92, 0xa2, 0x63, 0x26, 0x47,
- 0xbb, 0xcc, 0x9d, 0x92, 0x51, 0x7d, 0x28, 0x48, 0x29, 0x6e, 0xe3, 0xb4,
- 0xaa, 0xe3, 0x3f, 0x34, 0x4d, 0x5b, 0xc3, 0x00, 0x25, 0xcb, 0x2e, 0x44,
- 0xd0, 0x16, 0x63, 0xa5, 0x33, 0x37, 0x53, 0x18, 0x80, 0x28, 0xe7, 0xba,
- 0x24, 0xdc, 0xe4, 0x2e, 0xe9, 0x1f, 0xc9, 0x99, 0xa5, 0x6c, 0xc5, 0x6d,
- 0xae, 0x33, 0xbe, 0x3f, 0xda, 0xa6, 0x37, 0xd7, 0x19, 0x8d, 0xfc, 0x23,
- 0xce, 0x8f, 0xb9, 0xb8, 0x69, 0x7a, 0x56, 0x5b, 0xd9, 0xe8, 0xf3, 0x7c,
- 0xbb, 0x4b, 0x82, 0x32, 0x15, 0x5b, 0xd7, 0x76, 0xa6, 0x9c, 0xc1, 0x10,
- 0xfb, 0xed, 0xb7, 0xdf, 0xf7, 0xfe, 0x7e, 0xdf, 0xe7, 0xfd, 0x16, 0x71,
- 0x91, 0x6e, 0xf1, 0xff, 0x76, 0xe3, 0x93, 0x38, 0x7a, 0xec, 0xb1, 0x3b,
- 0xc6, 0xef, 0xd8, 0x2f, 0x72, 0xe7, 0x9d, 0xb2, 0x2b, 0xaa, 0xf3, 0xe6,
- 0xdb, 0x21, 0x91, 0xdc, 0x4f, 0xe5, 0xaf, 0xfc, 0x87, 0xc7, 0x8d, 0x60,
- 0x7d, 0x7e, 0x24, 0xaa, 0xa7, 0x5f, 0xcc, 0x64, 0x2c, 0x89, 0x86, 0xd2,
- 0x33, 0x9f, 0x9d, 0xb3, 0x44, 0x6c, 0x77, 0x24, 0x91, 0x95, 0xf7, 0x5a,
- 0x85, 0x58, 0x58, 0x38, 0x7e, 0x53, 0xfa, 0xca, 0xe3, 0xdf, 0xff, 0x2d,
- 0xf3, 0x9d, 0x6a, 0x48, 0xa2, 0x46, 0x3a, 0x27, 0xc6, 0x90, 0x44, 0x07,
- 0xf0, 0xcc, 0xef, 0xdf, 0x3a, 0xa5, 0x4b, 0x6f, 0xb0, 0x56, 0x5c, 0x16,
- 0x2a, 0x6f, 0xb7, 0xbe, 0x7f, 0x6b, 0x4c, 0xfe, 0x55, 0xd3, 0x90, 0x17,
- 0x9b, 0x61, 0x6d, 0xb2, 0xd2, 0x23, 0xa5, 0x8a, 0x2b, 0xc7, 0xcb, 0x05,
- 0xc9, 0x36, 0x5f, 0x90, 0xe2, 0xb2, 0xd1, 0x9b, 0x39, 0xf7, 0x07, 0x52,
- 0x5a, 0xee, 0xeb, 0xcd, 0x9e, 0x73, 0xa5, 0x58, 0x8e, 0xf7, 0x66, 0x9a,
- 0x46, 0x6f, 0xf6, 0x4c, 0x0c, 0xd7, 0x7d, 0xbd, 0x99, 0x33, 0x66, 0x41,
- 0xa4, 0x1f, 0x73, 0xe2, 0xbd, 0xd9, 0x8a, 0x99, 0x13, 0x19, 0x4c, 0xbd,
- 0x22, 0x03, 0xbd, 0xd9, 0x66, 0x4d, 0x5b, 0x37, 0x34, 0x29, 0xfe, 0x86,
- 0x18, 0xbd, 0xe9, 0xcb, 0xad, 0x4f, 0x58, 0x86, 0xec, 0xb5, 0x64, 0xcf,
- 0x1e, 0x4b, 0x9e, 0x88, 0xa7, 0xa3, 0x92, 0x3f, 0xdd, 0x25, 0xb6, 0xe2,
- 0xc9, 0x90, 0xfc, 0x99, 0x11, 0x63, 0x43, 0x22, 0x62, 0xc7, 0x82, 0xeb,
- 0x56, 0x2b, 0x93, 0xfa, 0x02, 0xe5, 0x8a, 0xbd, 0xa4, 0x77, 0xb2, 0x29,
- 0x92, 0xa9, 0x44, 0x25, 0x93, 0x7a, 0xaf, 0xe5, 0x3d, 0x13, 0xc5, 0xbe,
- 0xe1, 0xde, 0x89, 0x4a, 0xab, 0xe5, 0xa4, 0xb0, 0x47, 0x2a, 0x78, 0x36,
- 0x22, 0xd5, 0x98, 0x5d, 0x2d, 0xa5, 0x4c, 0xdd, 0xd3, 0x09, 0x79, 0xe4,
- 0xb5, 0x2d, 0xba, 0xf5, 0xdb, 0x92, 0x8f, 0x49, 0xb5, 0x98, 0xba, 0x4b,
- 0x9e, 0x4e, 0x19, 0x72, 0x12, 0xeb, 0x3d, 0x95, 0x82, 0x1c, 0xad, 0x63,
- 0x5a, 0xa6, 0x69, 0xc6, 0x45, 0x7b, 0x5a, 0x32, 0x67, 0x06, 0x8d, 0xac,
- 0x60, 0x6f, 0xab, 0x75, 0x4b, 0x26, 0x85, 0xfd, 0x46, 0xff, 0x67, 0xcb,
- 0x8e, 0x99, 0xb9, 0xaa, 0x0c, 0x48, 0xb1, 0x32, 0x98, 0xfa, 0x13, 0xd1,
- 0xa4, 0xd3, 0xa2, 0x7c, 0x5a, 0x72, 0x3f, 0xf6, 0xcd, 0x58, 0x18, 0x6f,
- 0x8a, 0xad, 0x27, 0x23, 0xf2, 0x0f, 0x0c, 0x33, 0x91, 0x09, 0xf5, 0x4b,
- 0xf1, 0x74, 0x27, 0xe8, 0xb4, 0xfb, 0x74, 0xcc, 0x3d, 0x30, 0x26, 0xb1,
- 0x5d, 0x22, 0x5a, 0x28, 0x9d, 0xc4, 0xba, 0x22, 0x45, 0x77, 0x00, 0xcf,
- 0x26, 0xc7, 0x7f, 0x2a, 0x7b, 0x24, 0xb1, 0x37, 0x2c, 0x25, 0xb7, 0x1b,
- 0x72, 0x34, 0xa0, 0x83, 0xe4, 0xf8, 0x5f, 0x40, 0x29, 0xba, 0x95, 0x8c,
- 0x1f, 0x93, 0x9c, 0x96, 0x6d, 0x76, 0x48, 0x29, 0x19, 0x95, 0x05, 0xd0,
- 0xb1, 0x90, 0xfa, 0xa2, 0x96, 0x39, 0x77, 0x50, 0xcb, 0x9e, 0xc3, 0xbc,
- 0x66, 0xdd, 0xb7, 0x35, 0x03, 0xeb, 0xe8, 0x52, 0x4c, 0x1e, 0xc4, 0xbd,
- 0xa8, 0xcc, 0x61, 0xde, 0x1c, 0x78, 0x2a, 0x35, 0xf7, 0xc8, 0xfa, 0x6c,
- 0xac, 0x37, 0x03, 0x1d, 0x16, 0x71, 0xff, 0xb7, 0x67, 0x34, 0x31, 0x2c,
- 0x5b, 0x7e, 0x3c, 0x06, 0x1d, 0x9e, 0x81, 0xfe, 0xce, 0xc4, 0xe5, 0x78,
- 0x45, 0x62, 0xba, 0x24, 0xe3, 0x79, 0x79, 0x41, 0xea, 0x2e, 0xf5, 0x0f,
- 0x7d, 0x42, 0xdf, 0x45, 0x97, 0xcf, 0x41, 0x6f, 0x15, 0x07, 0xf2, 0x98,
- 0x02, 0x0d, 0x0f, 0x6a, 0xf7, 0xd7, 0x67, 0xb5, 0x03, 0xcd, 0x1f, 0x6b,
- 0xd2, 0x7d, 0x4c, 0xfb, 0x5c, 0xf3, 0x88, 0xe6, 0xcb, 0x1e, 0xba, 0x8b,
- 0x8a, 0x3d, 0x13, 0x95, 0x95, 0xa6, 0xa7, 0xbb, 0x1a, 0xec, 0xd3, 0x36,
- 0x6c, 0xe8, 0xe1, 0x6f, 0x6f, 0xce, 0x59, 0x69, 0xc6, 0x64, 0x01, 0xb4,
- 0x1d, 0x6f, 0x72, 0xfe, 0xef, 0x41, 0x3f, 0x51, 0x71, 0x6f, 0xed, 0x91,
- 0x1c, 0xc6, 0x8b, 0x67, 0xc4, 0xce, 0xa4, 0x74, 0x3c, 0xd3, 0x2b, 0x21,
- 0xab, 0x1f, 0x9f, 0x6e, 0x99, 0xab, 0x77, 0xda, 0x21, 0x2b, 0x26, 0x73,
- 0x4d, 0xca, 0x10, 0xff, 0x2b, 0x81, 0x1c, 0x49, 0x2b, 0xc7, 0xf9, 0x1c,
- 0xc7, 0x0d, 0x8c, 0xb7, 0x8f, 0xd1, 0x2e, 0x7a, 0x41, 0x8f, 0x39, 0x2c,
- 0x18, 0xcb, 0x57, 0x92, 0xc6, 0xe7, 0xf8, 0xbf, 0x49, 0xd9, 0x06, 0x32,
- 0x0d, 0x63, 0xae, 0x2e, 0xf9, 0x3a, 0xf6, 0x39, 0x7d, 0xa5, 0x15, 0x19,
- 0xc3, 0xb5, 0xf5, 0x4b, 0xc8, 0x92, 0xfb, 0x86, 0x41, 0x93, 0x2e, 0xb9,
- 0x3a, 0xd7, 0xe2, 0x7d, 0x81, 0xee, 0x8b, 0x7b, 0x75, 0x19, 0x86, 0x7e,
- 0x4d, 0xec, 0xd3, 0x85, 0x39, 0x3d, 0x90, 0x1f, 0x78, 0x3d, 0x87, 0xef,
- 0xe0, 0x5d, 0xb7, 0x74, 0x3c, 0xdf, 0x29, 0x73, 0x29, 0xda, 0x0b, 0xe9,
- 0xdc, 0x85, 0xb5, 0xbb, 0x64, 0xfe, 0x34, 0xe5, 0x01, 0xbb, 0xaa, 0xc4,
- 0xa4, 0x74, 0xc6, 0x34, 0x1c, 0x31, 0x21, 0x1b, 0x1b, 0xf3, 0x3a, 0x25,
- 0x67, 0xb4, 0x5a, 0x13, 0xa9, 0x11, 0xe3, 0x9b, 0xca, 0xce, 0x47, 0x8c,
- 0xa4, 0x26, 0x85, 0x8e, 0xf4, 0x10, 0x64, 0x6b, 0x1e, 0x14, 0xe1, 0xf5,
- 0x0f, 0xc4, 0x9e, 0xa5, 0xff, 0xc4, 0xb8, 0x17, 0xfc, 0xa9, 0x1f, 0xf4,
- 0xd3, 0xe7, 0x06, 0xa0, 0x97, 0xb8, 0xf2, 0x83, 0x89, 0x1d, 0xfd, 0xc0,
- 0x9c, 0xaa, 0x82, 0xdf, 0xe2, 0xb9, 0x30, 0xfd, 0x2f, 0x05, 0x73, 0x93,
- 0x5d, 0x56, 0x14, 0xb6, 0x40, 0x5a, 0xc6, 0xb1, 0x7e, 0xab, 0xf5, 0xd9,
- 0x94, 0x47, 0x53, 0xf1, 0x8c, 0x8d, 0x67, 0xc3, 0x90, 0xbb, 0xf9, 0x70,
- 0x42, 0xed, 0x3f, 0xee, 0xef, 0x6f, 0xc8, 0x1c, 0xe8, 0x2e, 0x56, 0x42,
- 0x92, 0x35, 0xb8, 0xc6, 0x9f, 0x71, 0x3c, 0xe7, 0xad, 0x05, 0xbb, 0x3d,
- 0x35, 0x68, 0xdc, 0x07, 0x5f, 0xa2, 0x8f, 0x15, 0x57, 0x29, 0x63, 0xac,
- 0x33, 0x46, 0x19, 0x1b, 0x8a, 0xc6, 0xcc, 0x19, 0xda, 0x91, 0x0c, 0x84,
- 0x84, 0x76, 0x8e, 0x98, 0x01, 0xbb, 0x2a, 0xf9, 0x76, 0x95, 0x77, 0xa9,
- 0xff, 0xbb, 0x7d, 0xff, 0xd4, 0x65, 0x28, 0x49, 0x7b, 0x7f, 0x5a, 0xb2,
- 0xf0, 0xf1, 0x39, 0xec, 0x54, 0x07, 0x4f, 0xb5, 0xca, 0x20, 0x64, 0x15,
- 0xf8, 0x1d, 0xf4, 0x3b, 0xfa, 0x6e, 0x2b, 0x88, 0x05, 0xc5, 0x0a, 0x7d,
- 0xa6, 0x68, 0xe8, 0x52, 0xc0, 0x07, 0x76, 0x63, 0x99, 0xc3, 0x99, 0x90,
- 0x39, 0x93, 0x03, 0x6d, 0xb0, 0x7b, 0xc9, 0xdc, 0x49, 0x7b, 0xc6, 0x9c,
- 0xa6, 0xec, 0x0f, 0xfc, 0xac, 0xe6, 0x52, 0x4f, 0xdd, 0xd8, 0x37, 0xa0,
- 0x29, 0x8c, 0x31, 0xae, 0x13, 0x85, 0xcd, 0x07, 0x36, 0x43, 0xfb, 0x33,
- 0xed, 0x75, 0xe9, 0x90, 0xe1, 0x24, 0x62, 0xd9, 0x19, 0x1d, 0xfa, 0x1b,
- 0x40, 0x4c, 0x09, 0xcb, 0x11, 0xc8, 0xea, 0x4b, 0x15, 0xd2, 0xe7, 0xc0,
- 0xef, 0x10, 0xdb, 0xce, 0x4c, 0xc2, 0xcf, 0xa6, 0xb4, 0x09, 0xf8, 0xc4,
- 0x67, 0xea, 0xa4, 0xa9, 0x25, 0xf4, 0x4b, 0xe7, 0x5c, 0x4e, 0x9b, 0x6c,
- 0x1e, 0xd4, 0xa6, 0xce, 0xd1, 0x4f, 0xe8, 0x23, 0xa6, 0xf1, 0x80, 0x78,
- 0x3c, 0x14, 0x9b, 0xaf, 0x68, 0xf4, 0xd5, 0xe2, 0xa9, 0x2e, 0xd0, 0xb1,
- 0x0b, 0xf4, 0x18, 0xf0, 0x3d, 0xd8, 0x97, 0x65, 0xce, 0xd0, 0x66, 0x9c,
- 0xa4, 0x95, 0xf8, 0xe7, 0xf2, 0x41, 0x39, 0x4c, 0x6c, 0xca, 0x61, 0x04,
- 0x32, 0xd9, 0x2e, 0x87, 0x85, 0x0f, 0xca, 0xc1, 0x2e, 0x40, 0x0e, 0x0b,
- 0x88, 0x43, 0x0b, 0x4d, 0xf2, 0xdc, 0x12, 0xfd, 0x4e, 0x81, 0x75, 0xca,
- 0xbd, 0x7a, 0x9a, 0x36, 0x4a, 0x3f, 0x49, 0x26, 0x4a, 0x58, 0xa1, 0xe1,
- 0xf6, 0x28, 0xdf, 0x98, 0x54, 0xb2, 0xf8, 0x30, 0x7e, 0xc9, 0xdf, 0x16,
- 0xcf, 0x53, 0x75, 0xc6, 0x1b, 0xd8, 0x79, 0xd2, 0x32, 0xbe, 0x20, 0x5b,
- 0x7c, 0xdf, 0xb7, 0xc5, 0x37, 0xf6, 0x09, 0x62, 0x10, 0x79, 0x0e, 0xe2,
- 0x31, 0x6d, 0xe5, 0xa5, 0x56, 0xc8, 0xb2, 0xa0, 0x03, 0xda, 0x0b, 0x69,
- 0x30, 0x8d, 0xcf, 0x0a, 0xfe, 0x23, 0x2e, 0xd0, 0x97, 0x72, 0x6a, 0x5e,
- 0x87, 0xe4, 0xf6, 0x7a, 0xf3, 0xe7, 0x2a, 0xad, 0x5f, 0xe8, 0xe9, 0xf7,
- 0x5b, 0x99, 0x31, 0xcb, 0xf7, 0xf1, 0xa8, 0x7c, 0xb9, 0x6e, 0xe6, 0x12,
- 0x5a, 0x8f, 0x14, 0x6e, 0x40, 0x5c, 0xa9, 0xd0, 0x3f, 0xfa, 0xaf, 0x11,
- 0xcb, 0x06, 0xfc, 0x58, 0xf6, 0x13, 0xc8, 0x9e, 0xb9, 0xe7, 0xf0, 0xfb,
- 0xeb, 0x31, 0xfe, 0x4f, 0x1a, 0x33, 0xf2, 0x05, 0xe6, 0x9b, 0x3d, 0xba,
- 0x8a, 0xdf, 0x16, 0x73, 0x41, 0x21, 0x9c, 0xee, 0x96, 0xc2, 0x5e, 0x29,
- 0x84, 0xd2, 0xf4, 0x23, 0xfa, 0x46, 0x87, 0x4f, 0x77, 0x90, 0x3b, 0xf8,
- 0x77, 0x4c, 0x17, 0x8b, 0x73, 0x90, 0x27, 0x2a, 0xe4, 0xe3, 0xbd, 0x40,
- 0x27, 0x78, 0x46, 0x22, 0x9e, 0xcd, 0x4d, 0x23, 0x66, 0x52, 0xa6, 0xed,
- 0xf6, 0xc2, 0x58, 0x2a, 0x09, 0xdd, 0x62, 0x2c, 0x15, 0x23, 0x94, 0x7e,
- 0x50, 0xb3, 0xeb, 0x5f, 0xd4, 0x6c, 0xc8, 0xce, 0x86, 0xec, 0x6c, 0xc8,
- 0x2e, 0x03, 0xd9, 0x65, 0x9b, 0xa4, 0x87, 0xb4, 0x78, 0xeb, 0x3b, 0xde,
- 0xfa, 0xa0, 0xb3, 0x5f, 0xf2, 0xca, 0xc7, 0xc9, 0x2f, 0x62, 0xb2, 0x8a,
- 0x07, 0x93, 0x9a, 0x17, 0x0f, 0xb8, 0xde, 0x14, 0x9e, 0xbf, 0x1b, 0x79,
- 0xce, 0xd6, 0x75, 0x6b, 0x4b, 0x26, 0x0b, 0x6d, 0x32, 0x29, 0xb9, 0x94,
- 0x11, 0xe7, 0xd3, 0x97, 0x5d, 0xe8, 0x3d, 0x90, 0xcb, 0x34, 0x68, 0xe8,
- 0x24, 0xef, 0x3e, 0x1f, 0x5c, 0xbf, 0xcf, 0x5f, 0xff, 0xd3, 0x58, 0x93,
- 0xbe, 0xbb, 0xd3, 0xbe, 0xdc, 0x93, 0xb9, 0xf4, 0xd7, 0xf1, 0x83, 0x5a,
- 0x02, 0x31, 0xfa, 0x45, 0xf8, 0xda, 0xc5, 0x50, 0x5c, 0xbe, 0x7f, 0xeb,
- 0x6b, 0xa8, 0x2f, 0xa4, 0x70, 0x63, 0xba, 0x95, 0x08, 0xa7, 0xdf, 0x6b,
- 0x2d, 0x8c, 0x21, 0x7e, 0xa6, 0xcd, 0x78, 0x26, 0x34, 0x2a, 0x2f, 0x35,
- 0x87, 0xe5, 0x3b, 0x4d, 0x4b, 0xfe, 0xa8, 0x99, 0x90, 0x3f, 0x6c, 0x0e,
- 0xc8, 0xb7, 0x9b, 0x71, 0xf9, 0x56, 0x33, 0xa8, 0x45, 0xe2, 0xb4, 0xa5,
- 0x5e, 0xa7, 0xb9, 0x53, 0x3d, 0x04, 0x3b, 0xc7, 0x5a, 0x99, 0xb1, 0x70,
- 0x2e, 0x94, 0x56, 0x35, 0xc2, 0xcc, 0xd1, 0xf2, 0xe3, 0x2d, 0xdd, 0xb2,
- 0x0a, 0xba, 0xde, 0x33, 0x6e, 0xdc, 0x25, 0x39, 0x3d, 0x8d, 0x31, 0x77,
- 0x3c, 0xec, 0x94, 0xbb, 0x90, 0x5f, 0xa2, 0xa8, 0x65, 0x06, 0xa4, 0x80,
- 0x75, 0x0b, 0xcd, 0x56, 0x6b, 0x29, 0xf5, 0x0f, 0x3f, 0x65, 0xfc, 0x8d,
- 0x7f, 0xd9, 0x29, 0xbd, 0xdf, 0x5e, 0x37, 0x86, 0xfe, 0xbb, 0x5f, 0x0f,
- 0xa1, 0xc6, 0xea, 0x57, 0x8b, 0xe7, 0xb4, 0xf4, 0xa8, 0x93, 0x70, 0x37,
- 0x70, 0x5f, 0xa2, 0xfd, 0xd6, 0xcf, 0x51, 0x85, 0xc8, 0xee, 0x98, 0xc5,
- 0x9a, 0x6b, 0x26, 0xfb, 0x79, 0xfc, 0xff, 0x58, 0x5a, 0xf6, 0xf4, 0xe1,
- 0xff, 0xde, 0x34, 0x4c, 0x2a, 0xcd, 0x98, 0xac, 0xb5, 0xc5, 0x64, 0xd1,
- 0x1c, 0xe4, 0xdf, 0x05, 0xf0, 0xe4, 0x40, 0x1e, 0xbf, 0xd3, 0x8c, 0x6a,
- 0xd9, 0xd3, 0xfd, 0x52, 0xaa, 0x33, 0xaf, 0x71, 0x5e, 0xd4, 0xaf, 0x7b,
- 0x78, 0xdd, 0x81, 0x6b, 0x41, 0xae, 0xf9, 0x94, 0x48, 0xaf, 0xf9, 0xa3,
- 0xcf, 0x4b, 0xdd, 0xaf, 0x5b, 0x22, 0xb2, 0xac, 0x6c, 0x8c, 0xe3, 0xaf,
- 0x65, 0xbf, 0x36, 0xb4, 0x35, 0xfe, 0xec, 0xe6, 0xf8, 0x3b, 0xd9, 0x4f,
- 0x6f, 0x8e, 0x77, 0x87, 0x3d, 0x1e, 0xc6, 0xb5, 0x99, 0x66, 0xc1, 0x1f,
- 0xbb, 0x0c, 0xb9, 0xb7, 0x5a, 0x0b, 0xc8, 0x3d, 0x45, 0xeb, 0x32, 0xea,
- 0x24, 0xc6, 0x9f, 0xeb, 0x89, 0x37, 0xdb, 0x62, 0x8d, 0x91, 0x09, 0x51,
- 0x9f, 0x51, 0xf1, 0xd6, 0xe4, 0xfd, 0x4e, 0xc4, 0x9d, 0xcb, 0xf8, 0xce,
- 0x3c, 0x17, 0xc4, 0x3c, 0xce, 0xe1, 0xf3, 0x6f, 0x5f, 0x43, 0xe7, 0x31,
- 0xe8, 0xfc, 0xff, 0x1b, 0xdd, 0xe2, 0x4f, 0xe9, 0x56, 0xc5, 0x9d, 0x97,
- 0xb6, 0xd9, 0x2c, 0xe9, 0xef, 0xf6, 0x69, 0x96, 0x68, 0x38, 0x6d, 0x38,
- 0x0b, 0xd6, 0x8d, 0x12, 0x41, 0x0d, 0x4b, 0x9b, 0x2d, 0x35, 0xbf, 0x8b,
- 0xe7, 0x99, 0x27, 0x25, 0x1a, 0x49, 0xd3, 0x2e, 0xd6, 0x07, 0x32, 0xd6,
- 0x31, 0xa7, 0xe6, 0x1e, 0x73, 0xce, 0x2a, 0x3b, 0x59, 0xbf, 0xc9, 0xab,
- 0xcd, 0x7f, 0x74, 0x13, 0x6a, 0x73, 0x3c, 0xcf, 0x98, 0xcb, 0xf1, 0x46,
- 0x4f, 0xc6, 0x62, 0x0e, 0x5a, 0x72, 0x8a, 0xf8, 0x2c, 0xa8, 0xb9, 0xaf,
- 0x0e, 0x70, 0x6e, 0x67, 0x3a, 0x76, 0xd3, 0x8f, 0xf1, 0xbf, 0x23, 0xfd,
- 0xce, 0x4d, 0x17, 0x2c, 0xae, 0x3b, 0x75, 0xd3, 0x59, 0xb5, 0x46, 0x18,
- 0xf1, 0x8c, 0xf3, 0x2e, 0xdf, 0xc4, 0x67, 0x9f, 0x44, 0x1c, 0x3f, 0xe1,
- 0x42, 0x97, 0xee, 0x8b, 0x4e, 0x1e, 0x9f, 0x39, 0xd2, 0x54, 0xe1, 0x7d,
- 0xe3, 0xe6, 0x8c, 0x15, 0x56, 0xf9, 0xf6, 0x4b, 0x98, 0x73, 0x04, 0x73,
- 0x0e, 0xbb, 0x01, 0x3f, 0xea, 0xbe, 0x93, 0xc5, 0xfd, 0xc3, 0x65, 0xc3,
- 0x71, 0xca, 0xe6, 0x38, 0x6a, 0x8e, 0xf8, 0x71, 0xe4, 0xe3, 0x1c, 0x72,
- 0xa0, 0x2d, 0xe6, 0x70, 0x41, 0xd2, 0x5d, 0x93, 0xa8, 0xe5, 0x56, 0x90,
- 0x4f, 0x50, 0x87, 0xa4, 0xaa, 0x32, 0xd8, 0x95, 0x39, 0xad, 0xc3, 0x3e,
- 0xef, 0x80, 0xbd, 0x1a, 0x8e, 0x9e, 0x44, 0x5c, 0x47, 0xdc, 0x5c, 0xa8,
- 0x58, 0x5a, 0xb6, 0x3c, 0x68, 0x94, 0xe4, 0x56, 0x59, 0x37, 0xcc, 0xf8,
- 0xa4, 0xec, 0x92, 0x6c, 0x18, 0xf3, 0x86, 0x3f, 0x2e, 0xb9, 0xb8, 0x86,
- 0xd8, 0x70, 0x03, 0xe2, 0x16, 0xeb, 0xe4, 0xf6, 0x18, 0xfa, 0x0b, 0x11,
- 0xeb, 0x8b, 0x21, 0xc6, 0x9e, 0x4e, 0x8b, 0x75, 0x3f, 0xe7, 0xed, 0x92,
- 0x8d, 0x0f, 0xcc, 0x7b, 0xb7, 0x6d, 0x5e, 0xfb, 0xf8, 0x7b, 0x18, 0xdf,
- 0x25, 0x17, 0x41, 0x47, 0x38, 0x39, 0x26, 0x25, 0xf0, 0x10, 0x39, 0xd5,
- 0x6a, 0x5d, 0x00, 0x3f, 0x3a, 0xf8, 0x2f, 0x56, 0x59, 0x0b, 0x84, 0xa4,
- 0x6a, 0xe0, 0x9e, 0xdb, 0x6a, 0xd5, 0x10, 0x46, 0xf5, 0x55, 0xd2, 0x1c,
- 0x95, 0x49, 0x77, 0x48, 0xec, 0x06, 0xe5, 0x60, 0xc2, 0xeb, 0xfe, 0xac,
- 0x2b, 0x7b, 0x86, 0x39, 0x13, 0x16, 0xb1, 0xfa, 0xe7, 0x5d, 0x19, 0xe4,
- 0x3e, 0x7d, 0xf5, 0x62, 0x57, 0x16, 0x7a, 0x0f, 0xad, 0xfe, 0xe7, 0x2e,
- 0xe7, 0x34, 0xe9, 0x0a, 0x21, 0xf7, 0xdd, 0x22, 0x45, 0xa3, 0x25, 0xdf,
- 0x44, 0x8d, 0x50, 0x1c, 0x46, 0x2e, 0x83, 0x17, 0xe8, 0xa0, 0xbb, 0x60,
- 0x48, 0xb4, 0x3b, 0xfd, 0x7d, 0xd0, 0x37, 0x06, 0xd9, 0xec, 0xc2, 0x9c,
- 0x10, 0xc6, 0x87, 0xf0, 0xbf, 0x7d, 0xfc, 0x8d, 0x2e, 0xe4, 0x05, 0xc4,
- 0x60, 0x89, 0x66, 0xc6, 0x7a, 0xb0, 0xfe, 0xf7, 0x30, 0x8e, 0x09, 0xc9,
- 0xcd, 0xf1, 0x27, 0xbc, 0xf1, 0xb7, 0x41, 0x0b, 0x9f, 0x63, 0x8d, 0x22,
- 0xd1, 0xb9, 0x31, 0x03, 0x34, 0x70, 0x6e, 0x4c, 0xcd, 0x75, 0xce, 0xd0,
- 0x06, 0x0c, 0xa7, 0x66, 0xdd, 0x2c, 0xd9, 0xe5, 0x7e, 0x99, 0x5c, 0xee,
- 0x93, 0x03, 0xcb, 0xe6, 0x4c, 0x95, 0xd8, 0x0f, 0x3c, 0x0b, 0xea, 0x30,
- 0x7d, 0x55, 0x20, 0x01, 0x33, 0x7e, 0x44, 0x06, 0xe3, 0x5f, 0x92, 0x5f,
- 0xb6, 0x90, 0xef, 0x91, 0xeb, 0x7b, 0x24, 0xac, 0xd6, 0x89, 0x07, 0x7b,
- 0xd2, 0x46, 0xb7, 0xed, 0xeb, 0x9c, 0xb9, 0xd6, 0xba, 0x70, 0xfe, 0xd5,
- 0xf8, 0x55, 0xeb, 0xfe, 0x85, 0xbf, 0xae, 0x81, 0x75, 0x07, 0xb0, 0x26,
- 0x79, 0x34, 0xbb, 0x26, 0x4e, 0x8b, 0xdd, 0x09, 0xfa, 0x9c, 0xe4, 0x8d,
- 0xc0, 0x86, 0xfd, 0x72, 0x62, 0x99, 0xf1, 0x42, 0xfa, 0xf1, 0x19, 0x8d,
- 0x48, 0x72, 0xf8, 0x1c, 0xea, 0xae, 0x09, 0xb5, 0x86, 0x57, 0x93, 0xe9,
- 0xab, 0x29, 0xd4, 0xc4, 0x3f, 0x05, 0x3d, 0xac, 0x15, 0xc8, 0x73, 0x18,
- 0xfc, 0xa6, 0x50, 0x8b, 0x11, 0x47, 0xb5, 0x1e, 0xcf, 0xa4, 0xf0, 0xfd,
- 0x5c, 0xa2, 0x2b, 0x8b, 0x98, 0x08, 0xff, 0xbe, 0x39, 0xa4, 0x72, 0x18,
- 0xf5, 0x32, 0xda, 0x45, 0x3c, 0x83, 0xe7, 0xa1, 0x27, 0xca, 0x68, 0xbc,
- 0xcb, 0xa9, 0x50, 0x46, 0x02, 0x7a, 0x2c, 0xd8, 0x64, 0x58, 0x61, 0x29,
- 0x7d, 0xd5, 0xc6, 0xbc, 0xb7, 0x42, 0xac, 0x77, 0x33, 0x16, 0xbf, 0x23,
- 0xe6, 0xac, 0x4e, 0x61, 0x2e, 0xbf, 0xdf, 0x85, 0x75, 0x07, 0x87, 0x8b,
- 0xd2, 0x31, 0x7c, 0x18, 0xf1, 0x4e, 0x1f, 0x1b, 0x01, 0x6d, 0xb4, 0xf3,
- 0x16, 0xb0, 0xc0, 0x6f, 0x81, 0x1f, 0xf8, 0x46, 0xd2, 0x92, 0xf9, 0x25,
- 0xca, 0x55, 0x3e, 0x0e, 0x1e, 0xc0, 0x7f, 0x12, 0x71, 0x8d, 0x3c, 0x70,
- 0x6f, 0x41, 0x8e, 0xbe, 0x5b, 0xf2, 0x4b, 0x51, 0x55, 0xeb, 0xdb, 0x06,
- 0xf7, 0xd7, 0x34, 0x3d, 0xdd, 0x0d, 0x1d, 0x93, 0xb7, 0x1c, 0x68, 0x7b,
- 0x0c, 0x79, 0x80, 0xbc, 0x91, 0x2f, 0xfa, 0xca, 0x28, 0xfc, 0x84, 0xf4,
- 0xfb, 0xb6, 0xa7, 0xad, 0x23, 0xa6, 0xa8, 0x38, 0x98, 0xca, 0x20, 0xb0,
- 0xbd, 0xd4, 0x1c, 0x97, 0x3f, 0x6e, 0x8e, 0xc9, 0x77, 0x9b, 0x29, 0xe4,
- 0xc0, 0x51, 0xe4, 0xc0, 0x61, 0xe4, 0x40, 0x0b, 0x39, 0x30, 0x81, 0x1c,
- 0x38, 0x80, 0x1c, 0x18, 0x47, 0x9c, 0x14, 0x39, 0xa1, 0xf2, 0x6d, 0x2c,
- 0x0a, 0xcc, 0x1d, 0xb5, 0x9b, 0x0e, 0x78, 0x99, 0xc1, 0x5e, 0xb3, 0xe0,
- 0xeb, 0x50, 0xd7, 0x44, 0x65, 0x1c, 0x31, 0xd7, 0x42, 0x3c, 0x4a, 0x20,
- 0xdf, 0x8c, 0x01, 0x6b, 0x89, 0x6c, 0x2c, 0x25, 0x10, 0x13, 0x5b, 0xe2,
- 0x00, 0x13, 0x97, 0x8c, 0x14, 0x9e, 0xdd, 0xab, 0xec, 0x33, 0x94, 0xbe,
- 0x3b, 0x2c, 0xdd, 0xa3, 0x92, 0x2f, 0x9f, 0xc4, 0x58, 0x1c, 0xeb, 0x75,
- 0x21, 0x2f, 0x31, 0x2e, 0x30, 0x06, 0x2c, 0x39, 0xbf, 0x6b, 0xd1, 0xd7,
- 0xba, 0xb5, 0xcc, 0xe9, 0x82, 0x30, 0x96, 0x23, 0x0f, 0xc0, 0x1e, 0x38,
- 0x36, 0x89, 0xe7, 0xf8, 0xfd, 0x2f, 0xfd, 0x98, 0xf9, 0xb1, 0x4e, 0x81,
- 0xd1, 0xbe, 0xc4, 0x9c, 0x67, 0x61, 0x3d, 0xb7, 0xdd, 0x4f, 0x9f, 0x47,
- 0xad, 0x14, 0xdc, 0x27, 0xae, 0x66, 0x3f, 0xe1, 0x24, 0x68, 0x1e, 0x04,
- 0xbe, 0x47, 0x6d, 0x75, 0xb0, 0x8a, 0xef, 0xed, 0xf3, 0x5d, 0xcc, 0x57,
- 0x63, 0x51, 0x23, 0x6d, 0xb1, 0x9e, 0x43, 0xac, 0x3c, 0x86, 0xb8, 0x68,
- 0x3b, 0xfa, 0x5a, 0x03, 0x7c, 0x42, 0x8e, 0x65, 0xdb, 0x09, 0x0f, 0xbd,
- 0xd6, 0x7a, 0xd6, 0x1a, 0x96, 0x89, 0xb5, 0x31, 0xc9, 0xae, 0x0d, 0xc6,
- 0xcf, 0x4b, 0xd7, 0x65, 0x5b, 0x5e, 0x6b, 0x95, 0x5c, 0xf3, 0xa4, 0x0d,
- 0xbb, 0xdc, 0xb7, 0xdf, 0x90, 0x1a, 0x30, 0xdc, 0xbe, 0xfd, 0x9d, 0xac,
- 0xe9, 0x5f, 0x14, 0x3d, 0x21, 0x99, 0x45, 0x5b, 0xc6, 0xf6, 0x07, 0xb5,
- 0xe7, 0x2f, 0x3b, 0xa4, 0x1b, 0x63, 0x6b, 0x09, 0xcc, 0x61, 0xdd, 0xaf,
- 0xfa, 0x27, 0xe0, 0x59, 0xf3, 0x9e, 0x51, 0x39, 0x8f, 0x98, 0x19, 0xbc,
- 0x37, 0x6d, 0xe7, 0xfc, 0x22, 0x70, 0x0d, 0xe4, 0x99, 0x59, 0x24, 0xee,
- 0xda, 0x05, 0x39, 0x45, 0x60, 0x23, 0xd4, 0xfd, 0x20, 0x9e, 0x6d, 0xc9,
- 0x57, 0x53, 0xb4, 0x87, 0xc7, 0x20, 0x4b, 0xac, 0x15, 0x0e, 0xf8, 0xf9,
- 0x9a, 0xcc, 0x2d, 0x51, 0x7e, 0x71, 0xd4, 0x96, 0xdc, 0x5b, 0xa2, 0x5d,
- 0xe9, 0xab, 0xeb, 0x46, 0xdb, 0xd9, 0x58, 0xc4, 0xfa, 0x43, 0xc4, 0xd8,
- 0x88, 0xd5, 0x65, 0xf6, 0x06, 0x58, 0x53, 0x1d, 0x80, 0x4e, 0xa6, 0x15,
- 0xe6, 0xce, 0xd4, 0x53, 0x62, 0x9d, 0x62, 0xac, 0x92, 0x44, 0xc8, 0x22,
- 0xbe, 0x17, 0x43, 0x4f, 0xcf, 0xe2, 0x1e, 0xe5, 0xc9, 0x5a, 0x1f, 0xf7,
- 0x57, 0xff, 0xa3, 0xd2, 0x49, 0x08, 0xba, 0xcb, 0xef, 0x67, 0x11, 0x22,
- 0x4b, 0xa1, 0x34, 0x62, 0xe0, 0x18, 0x79, 0x50, 0x7b, 0xa3, 0x9e, 0xa4,
- 0xdf, 0x81, 0x67, 0xd8, 0x46, 0x5b, 0x5d, 0xa9, 0xfe, 0x4a, 0x95, 0x08,
- 0x6c, 0x59, 0x0a, 0x91, 0x34, 0x78, 0x1a, 0xc3, 0x77, 0x38, 0xff, 0x09,
- 0xe8, 0xf3, 0x2c, 0x9e, 0x5f, 0x00, 0x5f, 0x1b, 0x65, 0xd2, 0x9d, 0x4c,
- 0x1c, 0x57, 0xbe, 0x8b, 0x6b, 0x97, 0xb5, 0xcc, 0xd7, 0xe4, 0xbc, 0xe2,
- 0xef, 0x13, 0xac, 0x9d, 0xa1, 0xa7, 0xeb, 0xe1, 0x6f, 0xf2, 0x3a, 0xf9,
- 0xf3, 0xd6, 0x67, 0xce, 0xca, 0x58, 0x09, 0xc9, 0x96, 0x5f, 0x6a, 0x85,
- 0x2d, 0x2b, 0x3e, 0xef, 0xeb, 0x31, 0xeb, 0x46, 0x41, 0x07, 0xfb, 0x00,
- 0xfb, 0x95, 0x2e, 0x41, 0x07, 0x6d, 0xa7, 0x10, 0x4d, 0x3f, 0x2e, 0x2b,
- 0x4b, 0xff, 0x54, 0x6a, 0x4b, 0x05, 0xa9, 0x2f, 0xfd, 0x23, 0x39, 0xb7,
- 0xd4, 0x92, 0x0b, 0x29, 0x15, 0x93, 0xac, 0x0e, 0xe5, 0xcf, 0x72, 0xa3,
- 0x87, 0x07, 0x93, 0xe3, 0x97, 0x20, 0xc0, 0x95, 0xaa, 0x47, 0xfb, 0x54,
- 0x1b, 0xed, 0x17, 0x60, 0x6b, 0xaf, 0x58, 0xa4, 0x7f, 0x4c, 0x6a, 0x65,
- 0xd2, 0xfe, 0xa0, 0xa2, 0xfd, 0xc0, 0x26, 0xed, 0x92, 0x0b, 0x59, 0xa4,
- 0x7f, 0x27, 0xda, 0x81, 0xf3, 0xfb, 0x49, 0x7f, 0x02, 0xcf, 0x7e, 0xd0,
- 0xfe, 0x6a, 0xee, 0x6b, 0xad, 0x8d, 0x72, 0x44, 0xd1, 0x1c, 0x4a, 0x8f,
- 0x41, 0x3e, 0xaf, 0xb5, 0xd6, 0x5d, 0xfa, 0x11, 0xbe, 0xbb, 0xf7, 0x20,
- 0x46, 0xf5, 0x61, 0xaf, 0x5e, 0xc9, 0xcf, 0x46, 0x11, 0x27, 0xc7, 0xa1,
- 0xdb, 0x2e, 0xe5, 0x87, 0x08, 0x17, 0xd0, 0xd9, 0x34, 0xe6, 0x1f, 0xa2,
- 0xbf, 0x29, 0xb9, 0x38, 0x90, 0x4b, 0xb1, 0x9c, 0x8e, 0xa0, 0xfe, 0xc7,
- 0x3e, 0x86, 0x93, 0x73, 0xf9, 0xcc, 0x00, 0x62, 0x1a, 0xff, 0x7f, 0x64,
- 0x7b, 0x28, 0x20, 0xd6, 0x42, 0xe7, 0x3d, 0x90, 0x1f, 0xe8, 0x18, 0x9b,
- 0x41, 0x6e, 0x4d, 0x0e, 0xd7, 0x54, 0x7f, 0x91, 0x71, 0xe5, 0x28, 0xf2,
- 0xe9, 0x21, 0x7c, 0xbc, 0xfd, 0x26, 0x9a, 0xdc, 0x73, 0x3b, 0x4f, 0x45,
- 0x77, 0x7d, 0x2f, 0x01, 0x52, 0xa6, 0xc9, 0x7d, 0x0b, 0x12, 0x4a, 0x87,
- 0xb0, 0x2f, 0xc7, 0x7a, 0x10, 0x63, 0x06, 0xa2, 0xd9, 0xe6, 0xcf, 0x31,
- 0x4e, 0x5f, 0x66, 0x7c, 0x0f, 0x68, 0x1f, 0xc5, 0x9a, 0x8c, 0xbb, 0x63,
- 0xe0, 0x99, 0x35, 0x26, 0xe3, 0x26, 0xf2, 0x48, 0xe3, 0x47, 0xcc, 0x2d,
- 0xf8, 0x3e, 0xe0, 0x7f, 0xe7, 0x7d, 0x89, 0xde, 0x9c, 0x36, 0xab, 0x05,
- 0x31, 0xb1, 0x27, 0x74, 0x6e, 0xc5, 0xa5, 0xd8, 0x30, 0x5f, 0x20, 0x66,
- 0xd4, 0x29, 0x83, 0x35, 0xca, 0x89, 0xfd, 0x27, 0xd4, 0x7f, 0xb5, 0xe7,
- 0x21, 0x8f, 0xa8, 0xec, 0xb5, 0x0e, 0x22, 0xa6, 0x80, 0xfe, 0xca, 0x18,
- 0x78, 0x63, 0x8f, 0x66, 0x10, 0xf9, 0x2b, 0x04, 0x21, 0xa0, 0x96, 0x5a,
- 0x0b, 0xc9, 0xbd, 0xe1, 0x11, 0xa3, 0x28, 0x8f, 0x46, 0x58, 0x36, 0x17,
- 0xd6, 0x98, 0x07, 0xc2, 0xb2, 0xb0, 0x26, 0x72, 0x69, 0x91, 0x71, 0x45,
- 0xfd, 0x41, 0xe6, 0x86, 0x33, 0x8f, 0x3c, 0x5b, 0x5a, 0x62, 0x8c, 0x61,
- 0x9c, 0xb8, 0x01, 0xba, 0x48, 0x7e, 0xe3, 0xab, 0xc8, 0x49, 0xa5, 0xf2,
- 0x20, 0x62, 0xa6, 0xac, 0xeb, 0x90, 0x29, 0x72, 0x19, 0x6b, 0xd4, 0x1d,
- 0xfa, 0x32, 0x41, 0x4f, 0x26, 0x2a, 0xc5, 0x45, 0xf6, 0x63, 0xa2, 0xa0,
- 0x85, 0x35, 0x76, 0x48, 0xd5, 0x3f, 0x37, 0xa8, 0xd8, 0xca, 0xff, 0xe1,
- 0xb6, 0x7d, 0x93, 0x27, 0xf7, 0xe9, 0x8c, 0x63, 0x37, 0x8b, 0x3d, 0x63,
- 0x77, 0x1d, 0xa8, 0x74, 0x48, 0xb5, 0x8f, 0x76, 0x49, 0xfd, 0xbf, 0xa0,
- 0x62, 0xed, 0x02, 0x78, 0x2a, 0x2e, 0x12, 0xe3, 0x86, 0x31, 0x2f, 0xe6,
- 0xcf, 0xa3, 0x5c, 0xff, 0x89, 0xcc, 0xed, 0x7f, 0x17, 0x74, 0x79, 0x71,
- 0x2d, 0xbf, 0x1f, 0xf1, 0x76, 0x46, 0x97, 0x3b, 0xef, 0x1a, 0xc7, 0xb3,
- 0xcc, 0x81, 0xef, 0xf8, 0x78, 0x92, 0x63, 0xec, 0x61, 0x81, 0xbe, 0x15,
- 0x03, 0xff, 0xfb, 0xa4, 0xb0, 0x12, 0x85, 0x1c, 0x90, 0x4b, 0x6b, 0xde,
- 0x5a, 0xac, 0x77, 0x4f, 0x42, 0x47, 0xfa, 0xa9, 0xa8, 0x44, 0x4e, 0xf5,
- 0x49, 0xf8, 0xeb, 0xdd, 0xd2, 0xf1, 0xf5, 0x21, 0x09, 0x7d, 0xdd, 0x64,
- 0x4e, 0x4f, 0x9c, 0x80, 0xbe, 0xe6, 0x65, 0x5c, 0x9e, 0x44, 0xde, 0x62,
- 0x5e, 0x57, 0x76, 0x6a, 0xf4, 0x4b, 0x08, 0x05, 0xab, 0xfe, 0x8c, 0x2d,
- 0x8f, 0xee, 0xff, 0x85, 0xea, 0x33, 0x01, 0xc3, 0x8b, 0xfe, 0xfc, 0x94,
- 0xd8, 0xcd, 0x77, 0x21, 0x6b, 0xc3, 0x79, 0xed, 0xd6, 0xa0, 0xa6, 0x1c,
- 0x56, 0xfd, 0xc2, 0x47, 0xf7, 0x7b, 0x35, 0x25, 0xf0, 0xb8, 0xe6, 0xa8,
- 0x9a, 0x12, 0xf1, 0x35, 0xcc, 0x79, 0xfd, 0xa2, 0x63, 0xaf, 0xbc, 0x0c,
- 0x42, 0x4f, 0xb7, 0x88, 0x7d, 0x08, 0x7e, 0xf1, 0x9c, 0x2c, 0xe9, 0x69,
- 0x4d, 0xad, 0x19, 0x7a, 0x86, 0x71, 0x8a, 0xf1, 0x8b, 0x36, 0x9e, 0x4c,
- 0x14, 0x61, 0x7f, 0xa1, 0xe7, 0x19, 0xa3, 0x3c, 0xdb, 0x9e, 0x68, 0x8b,
- 0x75, 0x0b, 0x95, 0x7b, 0xa0, 0x43, 0xd4, 0xf2, 0x16, 0xe2, 0x9c, 0x81,
- 0x5c, 0x6e, 0xf1, 0xda, 0xeb, 0xe1, 0xe5, 0x63, 0x31, 0x75, 0x5d, 0xac,
- 0x7a, 0x18, 0xdc, 0x5b, 0x9f, 0x75, 0x07, 0x62, 0x4c, 0x93, 0x74, 0x70,
- 0xdf, 0x01, 0x09, 0x3d, 0x17, 0x93, 0xf0, 0x73, 0xb4, 0x3f, 0x33, 0xe1,
- 0x40, 0x7e, 0x0b, 0x16, 0x31, 0xd0, 0x0a, 0xb0, 0xc5, 0xcd, 0xa2, 0xaf,
- 0x0c, 0xc0, 0x77, 0xcc, 0x78, 0x55, 0x92, 0x12, 0xaa, 0x45, 0xe5, 0xad,
- 0x45, 0x33, 0x41, 0x7b, 0x39, 0x6b, 0x61, 0xbc, 0xd9, 0x75, 0x79, 0x5d,
- 0x51, 0xc1, 0xb1, 0x2f, 0x87, 0x80, 0x19, 0x86, 0x6d, 0xbd, 0x47, 0x5e,
- 0x87, 0xbe, 0x73, 0x6a, 0xec, 0x66, 0xac, 0x0b, 0x1a, 0x9e, 0x33, 0xc1,
- 0x03, 0xd7, 0xfd, 0x1e, 0xd6, 0x54, 0xf8, 0xca, 0xd9, 0x60, 0x4d, 0xba,
- 0x48, 0xdb, 0xed, 0x83, 0xdd, 0xe1, 0xba, 0xd9, 0x21, 0xb9, 0xd9, 0x84,
- 0xe8, 0x8b, 0x9f, 0x91, 0xc1, 0xfd, 0xba, 0xc7, 0x8f, 0xe2, 0x91, 0x63,
- 0xec, 0xc7, 0xdd, 0xae, 0xfc, 0x51, 0x5f, 0x83, 0xcd, 0x3c, 0x48, 0x1d,
- 0x23, 0xf7, 0x23, 0x8f, 0x31, 0x8e, 0x85, 0x90, 0xc7, 0xb2, 0x4d, 0x4f,
- 0xef, 0xd5, 0x07, 0xfb, 0xe5, 0xc9, 0xe7, 0x68, 0x4f, 0xb8, 0xb7, 0x69,
- 0x53, 0x41, 0x0f, 0x98, 0xf7, 0x2c, 0x39, 0xf9, 0x6c, 0x50, 0x73, 0xb0,
- 0xbe, 0x32, 0xe3, 0x07, 0xc0, 0x8f, 0x7e, 0x27, 0xe3, 0x81, 0xae, 0x6c,
- 0x37, 0x6f, 0x59, 0x5e, 0xdd, 0x51, 0x49, 0xb0, 0x2f, 0x6e, 0xb0, 0x4e,
- 0xb3, 0xe3, 0x9e, 0xbc, 0x8b, 0x18, 0x2b, 0x35, 0x67, 0x11, 0xa3, 0x23,
- 0x72, 0x71, 0xd6, 0x86, 0xee, 0x3f, 0x0b, 0xba, 0x0e, 0x75, 0x11, 0x23,
- 0x5f, 0x9c, 0x75, 0x70, 0x7d, 0x48, 0xd5, 0x66, 0xa1, 0x3b, 0x61, 0xc7,
- 0xcd, 0x7e, 0xfa, 0x91, 0xaf, 0xa7, 0x84, 0x56, 0x5c, 0x32, 0xb5, 0x12,
- 0x62, 0xf6, 0x64, 0x8a, 0x39, 0xbe, 0x53, 0xf5, 0x4d, 0xd9, 0xaf, 0xc9,
- 0x2b, 0xbc, 0xb0, 0x4f, 0x2b, 0x56, 0x19, 0xe7, 0x0b, 0xf1, 0x0e, 0x21,
- 0x0e, 0x11, 0xad, 0x66, 0x51, 0x27, 0x9a, 0x9c, 0x57, 0xbd, 0x58, 0x11,
- 0xc7, 0x3d, 0x42, 0x19, 0x68, 0xf5, 0xea, 0x3e, 0xad, 0x50, 0x0d, 0xc9,
- 0xc5, 0x18, 0xe9, 0x4e, 0xa8, 0xfa, 0x7d, 0xbf, 0xb2, 0xb5, 0x1e, 0xe4,
- 0x12, 0xd8, 0x4c, 0xea, 0x93, 0xd8, 0x57, 0x8d, 0xc1, 0xa6, 0xa8, 0x7b,
- 0xea, 0x5d, 0xc5, 0x48, 0x5f, 0xf7, 0x3b, 0xe5, 0x4c, 0xd0, 0x51, 0x26,
- 0x7e, 0xef, 0xf4, 0xf1, 0xfb, 0xa2, 0x5f, 0x0f, 0x3d, 0x26, 0xac, 0x53,
- 0x16, 0x2a, 0xa4, 0x05, 0xf1, 0xd6, 0xdd, 0xc9, 0x96, 0x28, 0x47, 0x2f,
- 0xa6, 0x1c, 0x45, 0x1d, 0xa3, 0xaf, 0x19, 0xbe, 0x0d, 0xf0, 0x6f, 0x14,
- 0xf7, 0xbc, 0x5a, 0xaa, 0xd8, 0x8c, 0xc0, 0xdf, 0xa7, 0x21, 0x23, 0xea,
- 0x06, 0xfa, 0x5b, 0xe3, 0x99, 0x0a, 0xf4, 0xb7, 0xf6, 0xf2, 0xfb, 0x76,
- 0x1f, 0x63, 0xde, 0xb0, 0x3c, 0x89, 0xf1, 0x13, 0x67, 0x48, 0xcf, 0xb8,
- 0x8f, 0xc7, 0x12, 0x90, 0x09, 0x63, 0xfc, 0xa8, 0xbc, 0xd5, 0x70, 0x14,
- 0xfe, 0xdb, 0xb7, 0x7f, 0x46, 0xe6, 0xdd, 0x59, 0xe0, 0x3f, 0xc8, 0xdf,
- 0x48, 0xc0, 0x3f, 0xe3, 0x2a, 0x3e, 0x1e, 0xfe, 0x68, 0x35, 0x49, 0xd8,
- 0xcb, 0xd9, 0xf7, 0x5e, 0x67, 0xce, 0xde, 0x0d, 0xfc, 0xf5, 0x91, 0xd6,
- 0x0f, 0x79, 0xeb, 0xff, 0x17, 0xe8, 0xea, 0x73, 0xd8, 0x23, 0x0a, 0xfa,
- 0xfa, 0x29, 0xd3, 0x0f, 0x7b, 0x4e, 0xf7, 0x9e, 0xbb, 0xff, 0x3a, 0xe9,
- 0x32, 0xa4, 0x01, 0x8c, 0x50, 0x50, 0x79, 0x94, 0xb5, 0x62, 0xc4, 0xd7,
- 0xdf, 0x31, 0x60, 0x67, 0xae, 0x1b, 0xc4, 0xde, 0x4e, 0x29, 0xf4, 0x05,
- 0xf5, 0x27, 0x62, 0xf6, 0xe6, 0x78, 0x50, 0xcf, 0xf2, 0xf9, 0x94, 0x93,
- 0x2f, 0xb3, 0x4f, 0xc8, 0x5c, 0xc0, 0x31, 0x65, 0x87, 0x1f, 0x42, 0xb7,
- 0x09, 0xcf, 0x20, 0xdd, 0xf7, 0x29, 0xba, 0x1d, 0x45, 0x37, 0xfd, 0x8b,
- 0x67, 0x3a, 0xec, 0xa3, 0x05, 0x7d, 0x33, 0xae, 0x07, 0x4c, 0x00, 0x7d,
- 0x7f, 0x17, 0x3a, 0xfe, 0x4e, 0x05, 0x98, 0xa0, 0x02, 0x4c, 0x80, 0x3d,
- 0xbe, 0x0d, 0x1d, 0x7f, 0xab, 0x02, 0x4c, 0x50, 0x89, 0xfb, 0x3d, 0x0a,
- 0x9b, 0x98, 0xfe, 0x23, 0xda, 0x6e, 0xd0, 0x93, 0xb9, 0xda, 0x2e, 0x39,
- 0xce, 0xf9, 0x01, 0x36, 0x8e, 0xc2, 0x8e, 0x78, 0x6e, 0x11, 0xf4, 0x3b,
- 0xfc, 0x1c, 0xd1, 0xe0, 0xb9, 0x00, 0x72, 0x44, 0x83, 0xe7, 0x18, 0x23,
- 0xf1, 0x10, 0x30, 0x61, 0x48, 0xe2, 0xc2, 0x5e, 0xef, 0xdc, 0x18, 0xd6,
- 0x1a, 0x1d, 0x84, 0x27, 0x75, 0xa8, 0xbe, 0xd6, 0x71, 0xd5, 0x6f, 0x40,
- 0x5c, 0xa8, 0x06, 0xb5, 0x5b, 0x52, 0x26, 0x96, 0x88, 0x33, 0x65, 0xaf,
- 0x9e, 0x86, 0x0e, 0x5c, 0x62, 0xc3, 0xcd, 0xbe, 0xf4, 0x70, 0x1d, 0x7b,
- 0x16, 0x2d, 0x8f, 0xbe, 0xe3, 0xee, 0xd6, 0x33, 0x07, 0x10, 0x9f, 0xa7,
- 0xca, 0x09, 0x99, 0x2c, 0x7b, 0x98, 0x00, 0xf5, 0xcf, 0x55, 0xfd, 0x51,
- 0x9b, 0x7a, 0x80, 0xfe, 0x36, 0x6d, 0x23, 0x71, 0x3e, 0x45, 0x19, 0x53,
- 0xff, 0xd3, 0xaa, 0x67, 0x7d, 0xa0, 0xee, 0xf5, 0xe5, 0x27, 0x95, 0x2d,
- 0x84, 0x19, 0x67, 0xa8, 0x3f, 0xcf, 0x87, 0x61, 0x17, 0x79, 0x37, 0x90,
- 0x4b, 0x3b, 0x1e, 0xf9, 0xbc, 0x26, 0xd6, 0x4e, 0xe3, 0xb9, 0xb6, 0xf1,
- 0xcd, 0xfb, 0x3e, 0xbd, 0x88, 0x7d, 0x9b, 0x3d, 0x06, 0xc6, 0xa9, 0xad,
- 0xf1, 0x10, 0xea, 0x87, 0xb0, 0xba, 0x8f, 0x18, 0xde, 0x88, 0x49, 0xb6,
- 0x61, 0x89, 0x53, 0xe5, 0x3c, 0xf6, 0x2d, 0x18, 0x8f, 0x9e, 0x90, 0xec,
- 0x52, 0xaf, 0xe4, 0x62, 0x66, 0xca, 0x96, 0xbf, 0x27, 0x1b, 0xcb, 0x85,
- 0x04, 0xcf, 0x0d, 0x0b, 0x33, 0x1a, 0x9e, 0x7b, 0x18, 0xd7, 0xa4, 0xd9,
- 0x92, 0xc3, 0x65, 0xe6, 0x9d, 0x91, 0x78, 0x03, 0xf7, 0x72, 0xb3, 0xec,
- 0xd5, 0x54, 0x61, 0x93, 0x66, 0xa2, 0x8a, 0x78, 0xf0, 0x72, 0x99, 0xfb,
- 0x01, 0x1b, 0x95, 0xd9, 0xcf, 0x09, 0xee, 0x3f, 0x01, 0x1c, 0x88, 0x58,
- 0x1d, 0xf3, 0xe7, 0x28, 0x5e, 0x6d, 0x23, 0x2c, 0x81, 0xae, 0x3b, 0x65,
- 0xdd, 0x8f, 0xbb, 0xb5, 0xb2, 0xd7, 0x47, 0x39, 0x4b, 0x7a, 0xdc, 0xff,
- 0xd5, 0x5a, 0x8f, 0xa1, 0x16, 0xda, 0xe4, 0xf5, 0x8f, 0xb9, 0x8f, 0x81,
- 0xb0, 0x2b, 0x27, 0xdc, 0x40, 0x26, 0xbc, 0xcf, 0x31, 0x9e, 0x8d, 0xb6,
- 0x5a, 0x67, 0xad, 0xf6, 0x9e, 0xdf, 0xf5, 0xf4, 0xcc, 0xde, 0xb8, 0x2d,
- 0x63, 0xbd, 0xe6, 0xa0, 0x26, 0xf6, 0x7b, 0x66, 0x87, 0x46, 0xbc, 0x9e,
- 0xd9, 0xfc, 0xc8, 0xf6, 0x9e, 0xd9, 0xcf, 0x6f, 0xf3, 0x7a, 0x66, 0x17,
- 0x9d, 0x22, 0x3e, 0x5e, 0xcf, 0x6c, 0xf8, 0x76, 0xaf, 0x67, 0xf6, 0xf0,
- 0xed, 0x5e, 0xcf, 0xec, 0x91, 0x11, 0xaf, 0x67, 0xf6, 0xfb, 0xb7, 0x6f,
- 0xef, 0x99, 0x3d, 0x36, 0xb2, 0xbd, 0x67, 0x26, 0x13, 0xc8, 0x77, 0x13,
- 0x5b, 0x3d, 0xb3, 0xf2, 0xc8, 0xb5, 0x7b, 0x66, 0xaf, 0x06, 0x78, 0x1d,
- 0xfc, 0x8c, 0x81, 0x87, 0x14, 0xf0, 0xfa, 0x28, 0xf0, 0xfa, 0xaf, 0xeb,
- 0x59, 0x87, 0xc1, 0xe7, 0xcd, 0x7e, 0x5e, 0xb8, 0x1e, 0xdc, 0x7e, 0xbb,
- 0xff, 0x8c, 0xa0, 0xde, 0x4d, 0xf8, 0xb5, 0x0a, 0xb1, 0xfb, 0x1e, 0xbf,
- 0x66, 0xfb, 0x6b, 0xd1, 0xad, 0xf3, 0xec, 0xf6, 0xff, 0x37, 0xa0, 0xf4,
- 0x0e, 0xf0, 0x3c, 0xf9, 0x79, 0x0d, 0xb5, 0x1f, 0xf9, 0x47, 0xa2, 0xef,
- 0xbe, 0xe8, 0x7c, 0xd5, 0x22, 0xc6, 0x7f, 0x1c, 0xbe, 0x6a, 0xef, 0x0d,
- 0xc9, 0x3a, 0xfc, 0x96, 0x39, 0xea, 0xa4, 0x64, 0x31, 0x3f, 0xab, 0xe6,
- 0x27, 0x26, 0xb6, 0xe6, 0xa7, 0x26, 0xbe, 0xaa, 0x6a, 0x52, 0xf3, 0x5f,
- 0xe3, 0xf3, 0x0d, 0x65, 0xdf, 0x96, 0x87, 0xe1, 0x9d, 0x4a, 0x80, 0xb7,
- 0xc2, 0x3e, 0x76, 0x36, 0x1c, 0xdb, 0x9d, 0xc0, 0x33, 0xe6, 0x8b, 0xb6,
- 0x34, 0x14, 0x7e, 0x0f, 0xa5, 0xcd, 0x17, 0x73, 0xaa, 0x5e, 0x33, 0x9c,
- 0xbc, 0x1b, 0xd4, 0xdf, 0xa8, 0xa1, 0x86, 0x06, 0xd5, 0xf9, 0x9b, 0xbe,
- 0x36, 0x8c, 0x3c, 0xd6, 0x5e, 0x63, 0xb3, 0xae, 0xd6, 0xfd, 0xba, 0xda,
- 0x90, 0xbb, 0xf7, 0xb7, 0x63, 0x73, 0x99, 0xf8, 0x5b, 0x0a, 0x9b, 0xef,
- 0x42, 0x6d, 0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7e,
- 0x01, 0xeb, 0x19, 0xe6, 0x46, 0xd6, 0x37, 0x31, 0x7c, 0xf8, 0xbe, 0x41,
- 0x80, 0xd1, 0x3b, 0xfc, 0xf8, 0xce, 0xba, 0x28, 0xc0, 0x2a, 0x77, 0x75,
- 0x7b, 0xb5, 0xd1, 0x2e, 0xcd, 0xab, 0x3f, 0x13, 0xfe, 0x9c, 0xf0, 0x26,
- 0x16, 0x0e, 0x6f, 0x62, 0xe1, 0x6d, 0xe7, 0x30, 0xa2, 0xde, 0x6d, 0x50,
- 0xe7, 0x39, 0x3c, 0xdf, 0x11, 0x4d, 0x4f, 0xf3, 0x8c, 0x07, 0x38, 0xc7,
- 0xe2, 0x99, 0x0f, 0x7d, 0xe9, 0x41, 0x2d, 0x5b, 0x37, 0x10, 0xef, 0x99,
- 0x7f, 0x90, 0x6b, 0xcb, 0xc1, 0xd9, 0x62, 0xa0, 0x27, 0xca, 0x8e, 0x63,
- 0x7f, 0xaa, 0xa1, 0xe6, 0x4d, 0x45, 0xac, 0x43, 0xa0, 0x65, 0x0a, 0xff,
- 0x03, 0x99, 0xde, 0xa3, 0x72, 0x5f, 0x27, 0x6c, 0xf6, 0x78, 0x85, 0xd8,
- 0xf5, 0x71, 0x69, 0xf8, 0xf8, 0x75, 0x65, 0xc9, 0xc3, 0xae, 0xe1, 0xed,
- 0xd8, 0x35, 0xb5, 0x21, 0x1e, 0x8d, 0x07, 0x76, 0xa4, 0xd1, 0x70, 0x5e,
- 0x19, 0x22, 0x66, 0x25, 0x9d, 0xcc, 0x3d, 0xd3, 0x88, 0x81, 0xcc, 0x39,
- 0xcc, 0x37, 0xc4, 0xa5, 0xd7, 0xa2, 0x4f, 0x8d, 0x1d, 0xed, 0xb0, 0xa2,
- 0xf8, 0xcc, 0x83, 0x8e, 0x19, 0x3c, 0x93, 0x96, 0x85, 0xd3, 0x5f, 0xd1,
- 0x9c, 0xfa, 0x3c, 0xe8, 0x99, 0x42, 0xae, 0xa3, 0x2d, 0x15, 0x0c, 0xcf,
- 0x8e, 0xd6, 0x11, 0xf7, 0x5d, 0xc6, 0x02, 0xd4, 0xae, 0xa8, 0x47, 0xca,
- 0x8c, 0xbd, 0x3c, 0xeb, 0x0a, 0x62, 0x2e, 0xfb, 0x26, 0xa8, 0x59, 0x59,
- 0xbb, 0x2e, 0x72, 0xdf, 0xed, 0xba, 0xa8, 0xb9, 0xc4, 0x5d, 0x86, 0xb3,
- 0xbe, 0x46, 0xdc, 0xf8, 0x51, 0x31, 0xa4, 0xe1, 0xbc, 0x3c, 0x44, 0x1c,
- 0x79, 0x3d, 0xf8, 0xd1, 0x84, 0x34, 0xcd, 0x17, 0xd6, 0xf5, 0x76, 0xfc,
- 0xe8, 0x61, 0xc7, 0xcc, 0xda, 0x41, 0xac, 0xc9, 0xda, 0x8c, 0x38, 0xd1,
- 0x44, 0x98, 0x1b, 0xc4, 0xb3, 0x83, 0xe0, 0xc7, 0xc3, 0x8a, 0x59, 0x60,
- 0xc5, 0xbf, 0x03, 0xac, 0x58, 0x92, 0xf7, 0xa2, 0xc4, 0x8a, 0xb6, 0x8f,
- 0x15, 0x1d, 0xd8, 0x71, 0x7e, 0x9b, 0x1d, 0x6b, 0xaa, 0x07, 0xc5, 0x7b,
- 0x79, 0x60, 0xbd, 0xec, 0xa2, 0x79, 0x1d, 0xf8, 0x50, 0x93, 0x98, 0x3a,
- 0xaf, 0x0f, 0xb7, 0xad, 0x19, 0xe0, 0xc0, 0x7d, 0x0a, 0xdf, 0xdd, 0x57,
- 0xd9, 0x85, 0xda, 0x44, 0xe1, 0x3d, 0xff, 0x9c, 0x2f, 0x7c, 0xd5, 0xd9,
- 0x67, 0xb8, 0xed, 0xec, 0x73, 0x0b, 0x17, 0xe2, 0x39, 0xbf, 0xc7, 0x17,
- 0x81, 0xde, 0xfe, 0x07, 0x69, 0x82, 0x5f, 0xd1, 0x07, 0x34, 0xcf, 0x4f,
- 0xb6, 0xe1, 0xc3, 0xff, 0x7a, 0x15, 0x3e, 0x44, 0xce, 0x5a, 0x89, 0x49,
- 0x06, 0xd8, 0xd0, 0x5e, 0xe3, 0x5a, 0xf4, 0xe5, 0x51, 0xe9, 0x00, 0x7f,
- 0x9d, 0x8b, 0x7d, 0xc0, 0x44, 0xdd, 0x12, 0x05, 0x36, 0x8a, 0x28, 0x6c,
- 0x34, 0x44, 0x0c, 0x33, 0x7c, 0x18, 0x98, 0xa6, 0xb1, 0x89, 0x8f, 0xcc,
- 0xd4, 0x0f, 0xa0, 0x97, 0x87, 0x95, 0xad, 0x8c, 0xcb, 0x53, 0x88, 0x9d,
- 0x1d, 0x6b, 0xc0, 0x75, 0x2b, 0x1e, 0x6e, 0x8a, 0x5c, 0x85, 0x9b, 0x8e,
- 0xec, 0x88, 0x9b, 0x54, 0xbf, 0x7e, 0x9c, 0x32, 0x79, 0xdd, 0xf5, 0xfa,
- 0xf5, 0x97, 0x5c, 0xaf, 0x5f, 0xff, 0xba, 0xdb, 0xde, 0xaf, 0xbf, 0x49,
- 0x8a, 0x86, 0x69, 0x5f, 0x94, 0xab, 0xfa, 0xf5, 0x33, 0xec, 0x7f, 0x57,
- 0xbb, 0xbc, 0xbe, 0x7c, 0xb7, 0xdf, 0xaf, 0x37, 0xa5, 0xb8, 0x6d, 0xdc,
- 0x90, 0xb7, 0xad, 0xa0, 0x5f, 0xff, 0x2f, 0x30, 0xd6, 0x83, 0x3d, 0xb6,
- 0xf7, 0xea, 0x2f, 0xb9, 0xec, 0xd5, 0xc7, 0x38, 0xcf, 0xef, 0xd5, 0x73,
- 0x1e, 0x6a, 0x78, 0x97, 0x7d, 0xfa, 0x9b, 0x21, 0x8b, 0x7e, 0xc8, 0xa1,
- 0x4f, 0x3a, 0x9e, 0x8b, 0x73, 0x8e, 0xea, 0xcf, 0x5f, 0x74, 0x63, 0x78,
- 0xce, 0xeb, 0xa3, 0x1f, 0x86, 0x5d, 0x1d, 0xd9, 0xec, 0xcf, 0x7b, 0x7b,
- 0xbc, 0xe1, 0x6e, 0x5f, 0x7f, 0xfb, 0x3a, 0x03, 0xfe, 0x3a, 0x31, 0xac,
- 0x13, 0xbf, 0x6a, 0x9d, 0xad, 0x7e, 0xfc, 0x1b, 0xae, 0xd7, 0x8b, 0x77,
- 0x4e, 0x8b, 0xdd, 0x81, 0x98, 0xfc, 0xe2, 0xd0, 0x8d, 0xfe, 0x1a, 0x9b,
- 0xbd, 0x78, 0xc6, 0x0e, 0xe0, 0x75, 0xc6, 0x0f, 0x3e, 0xff, 0xff, 0xbe,
- 0x17, 0xcf, 0x3e, 0xbc, 0x77, 0x9e, 0x42, 0xff, 0x04, 0x2e, 0x7f, 0xd6,
- 0xeb, 0xc1, 0x4f, 0x54, 0x82, 0xde, 0x3a, 0xeb, 0xc6, 0xe0, 0xbd, 0x8c,
- 0xc1, 0xc4, 0x71, 0xa1, 0xad, 0x90, 0x3e, 0xae, 0xdb, 0x23, 0x73, 0x0a,
- 0x17, 0xc1, 0xa6, 0x92, 0xd7, 0xc6, 0xc6, 0xb5, 0xc5, 0x00, 0x1b, 0xc7,
- 0x14, 0x36, 0xae, 0xad, 0x05, 0xd8, 0x38, 0x73, 0x0d, 0x6c, 0xfc, 0xdf,
- 0xba, 0xbc, 0xf8, 0x1f, 0x95, 0x82, 0xc2, 0xc6, 0xd7, 0x7a, 0xc7, 0x86,
- 0xf7, 0xba, 0x89, 0x03, 0xc4, 0x3b, 0x17, 0xef, 0xbb, 0x86, 0xaf, 0x05,
- 0x78, 0x99, 0xb9, 0xbe, 0x5f, 0x66, 0x9e, 0xdb, 0xc2, 0xcb, 0x1e, 0x26,
- 0x36, 0x13, 0x47, 0x55, 0x2e, 0x04, 0x3e, 0x68, 0xb2, 0xef, 0x7d, 0x48,
- 0xd9, 0x6e, 0xa9, 0x32, 0xab, 0x70, 0x59, 0x1e, 0xb5, 0x6d, 0x51, 0xe1,
- 0x60, 0x62, 0xe0, 0x2e, 0x91, 0xbe, 0x20, 0x17, 0x05, 0x18, 0x33, 0xec,
- 0xc7, 0x67, 0x9e, 0x29, 0xbc, 0x1d, 0xca, 0x10, 0x03, 0xbb, 0x41, 0x8d,
- 0x40, 0x39, 0x0f, 0x23, 0x76, 0x19, 0xbe, 0xac, 0x3c, 0x9f, 0xdd, 0xb7,
- 0xff, 0x87, 0xef, 0xdb, 0x06, 0xe3, 0x5a, 0x80, 0x11, 0x51, 0x03, 0x55,
- 0xc6, 0xd5, 0xbb, 0x0e, 0x1e, 0x46, 0xf4, 0xf0, 0x61, 0xd6, 0x9d, 0x01,
- 0x4e, 0x9e, 0x95, 0x09, 0xe0, 0xf3, 0xf5, 0xdf, 0x65, 0xef, 0x29, 0xc0,
- 0x44, 0x36, 0xfe, 0xb7, 0xf7, 0xa2, 0x78, 0xdd, 0xa1, 0xce, 0xfe, 0xce,
- 0x0f, 0x45, 0xdb, 0xc6, 0xff, 0x3e, 0xe2, 0x37, 0xea, 0xa1, 0x0a, 0x73,
- 0x1d, 0xb1, 0xd0, 0x6f, 0x40, 0x07, 0x63, 0xd7, 0xc0, 0x42, 0x57, 0xe7,
- 0x26, 0xe6, 0xcb, 0xad, 0xbc, 0xe4, 0x6c, 0xe6, 0x25, 0xee, 0xf1, 0xeb,
- 0x72, 0x27, 0xc7, 0x6c, 0x23, 0x62, 0x4d, 0xe1, 0x33, 0x8f, 0x7c, 0xbd,
- 0x3d, 0x37, 0xcd, 0x5d, 0x47, 0x6e, 0x9a, 0x50, 0xb9, 0x89, 0xf4, 0xa2,
- 0x9e, 0x83, 0x4c, 0xbe, 0x0b, 0x59, 0x7e, 0x07, 0xb4, 0xff, 0x11, 0xf8,
- 0xf9, 0x43, 0x60, 0xac, 0x6f, 0x03, 0x63, 0x7d, 0xab, 0xd2, 0xfe, 0x0e,
- 0xc3, 0xb8, 0xb0, 0x0e, 0xf4, 0xea, 0x66, 0x0f, 0xc3, 0x1f, 0x86, 0x57,
- 0x35, 0xca, 0x86, 0x33, 0x57, 0x1e, 0x31, 0xe6, 0xbd, 0xf3, 0xd2, 0x44,
- 0x4e, 0xd2, 0x88, 0x11, 0xcc, 0x15, 0xea, 0x3a, 0xce, 0x7e, 0x25, 0xb1,
- 0x42, 0x5d, 0xd5, 0x93, 0x43, 0x52, 0x6d, 0x78, 0xf8, 0x6a, 0xe1, 0x8c,
- 0xb7, 0xc6, 0x9c, 0x8f, 0xaf, 0xf2, 0x3e, 0xbe, 0xca, 0x35, 0x36, 0x12,
- 0xac, 0xcf, 0x17, 0x52, 0xdb, 0x31, 0xd5, 0x61, 0x1f, 0x53, 0xcd, 0xff,
- 0x15, 0x31, 0x15, 0xf7, 0xca, 0xe3, 0x99, 0xc9, 0xa5, 0x84, 0x1c, 0x80,
- 0x7c, 0x27, 0xca, 0xd4, 0x93, 0x69, 0xc3, 0x6e, 0x3e, 0x44, 0x57, 0x8e,
- 0xd2, 0x4b, 0x28, 0xe9, 0xe9, 0x69, 0x12, 0x7a, 0x9a, 0xf8, 0xb5, 0xf5,
- 0x8d, 0x1a, 0x33, 0xde, 0x1c, 0x8b, 0xe2, 0xf3, 0x7f, 0xaa, 0x23, 0xd2,
- 0x4f, 0x3d, 0x5d, 0x8d, 0xb9, 0xae, 0x07, 0x7b, 0x6d, 0xc7, 0x5d, 0xb6,
- 0xc2, 0x5d, 0x1d, 0xfe, 0x9c, 0x99, 0x89, 0x49, 0xe8, 0xf0, 0xdf, 0x63,
- 0xce, 0x9f, 0xc0, 0xb7, 0x7e, 0x88, 0x78, 0xfd, 0xef, 0xa0, 0x8b, 0x7f,
- 0x8b, 0xda, 0xe0, 0x55, 0xe4, 0x9f, 0x1f, 0x60, 0x6c, 0x0b, 0xc7, 0xa8,
- 0x33, 0xfa, 0xd1, 0x8c, 0x95, 0x98, 0x28, 0xba, 0x89, 0x09, 0x0f, 0x7f,
- 0xfc, 0xea, 0x6f, 0x66, 0xac, 0x29, 0xbe, 0xc3, 0x00, 0xf9, 0xfe, 0xf9,
- 0xdd, 0x73, 0x0a, 0x7b, 0x04, 0x98, 0x23, 0x67, 0x73, 0xff, 0x92, 0x9b,
- 0x9a, 0xa8, 0xe1, 0xe3, 0x61, 0x9b, 0xef, 0xd9, 0x1e, 0xb6, 0x59, 0xfa,
- 0xeb, 0xd4, 0xbb, 0x87, 0x6b, 0x1e, 0x4e, 0xd3, 0xaf, 0xeb, 0xc0, 0x1c,
- 0x35, 0xf8, 0x64, 0xa1, 0x69, 0xab, 0xcf, 0xf1, 0x8a, 0x6d, 0x46, 0x20,
- 0x1f, 0xf6, 0x58, 0x4f, 0xd1, 0x0b, 0x5d, 0xd3, 0x28, 0x13, 0x81, 0xba,
- 0x66, 0xfc, 0x9f, 0xf9, 0xd7, 0x4f, 0xfb, 0xd7, 0x4f, 0xf9, 0xd7, 0x27,
- 0x91, 0x77, 0x9f, 0x54, 0xb9, 0x93, 0xe3, 0x1c, 0x83, 0x72, 0x5d, 0xac,
- 0x85, 0xf5, 0xce, 0x8e, 0xfe, 0xb4, 0x55, 0x8d, 0x79, 0xfe, 0x5c, 0x68,
- 0x3a, 0xf8, 0xfc, 0x63, 0x7c, 0x0e, 0xe2, 0x33, 0x8d, 0xcf, 0x63, 0xf8,
- 0x6c, 0xca, 0x54, 0xcb, 0x56, 0xa8, 0xa3, 0x61, 0xc9, 0x62, 0xbc, 0x88,
- 0x3a, 0x34, 0x93, 0x7a, 0x44, 0x8a, 0xf5, 0x92, 0x94, 0x96, 0x34, 0xe9,
- 0xb6, 0xd2, 0x52, 0xaa, 0x1f, 0x93, 0xe3, 0x4b, 0xde, 0xb9, 0x61, 0x57,
- 0xda, 0xc6, 0xdc, 0x96, 0x3c, 0x9c, 0x7a, 0x5c, 0xf4, 0x3b, 0x8f, 0x61,
- 0x9e, 0xe8, 0xc5, 0xd1, 0xdb, 0xd4, 0xf9, 0x58, 0x3d, 0xe5, 0xc9, 0xf8,
- 0x80, 0x65, 0x9b, 0xc8, 0x5b, 0xc3, 0x4f, 0x62, 0xed, 0x8c, 0x7a, 0x3f,
- 0x30, 0x2d, 0x27, 0x4e, 0x6f, 0xec, 0xf5, 0x62, 0xa9, 0x69, 0xbc, 0x81,
- 0x4d, 0xeb, 0xe0, 0xc3, 0x46, 0xec, 0x9b, 0x82, 0x9d, 0x1f, 0x71, 0xc3,
- 0xda, 0x04, 0x62, 0xe0, 0x84, 0xab, 0x6a, 0x3d, 0xc4, 0x2a, 0xc3, 0x49,
- 0x9e, 0x8a, 0xe1, 0x9a, 0xef, 0xd0, 0x20, 0x0f, 0x2a, 0x5b, 0xd9, 0x00,
- 0x8e, 0xd1, 0x54, 0xbf, 0xaf, 0xb4, 0x79, 0x0e, 0xa4, 0xfa, 0xff, 0x4e,
- 0x32, 0xa9, 0x4b, 0x7e, 0x8c, 0x38, 0xd6, 0x56, 0xb9, 0xa8, 0x51, 0xb6,
- 0x3f, 0xc1, 0xda, 0xf0, 0x75, 0x61, 0x5e, 0xbb, 0x07, 0xf3, 0x06, 0x10,
- 0x7f, 0x71, 0xaf, 0x09, 0x5e, 0x4e, 0x93, 0x57, 0x3e, 0x83, 0xda, 0xb6,
- 0xfa, 0x49, 0xbd, 0xb8, 0xe4, 0xd7, 0x44, 0xaa, 0x76, 0x48, 0x48, 0x7d,
- 0xf3, 0xcc, 0xc9, 0xeb, 0x93, 0xd4, 0xdd, 0x00, 0x3b, 0xf4, 0x60, 0x0e,
- 0xeb, 0x08, 0xc8, 0xc8, 0x3b, 0x27, 0x53, 0x67, 0x64, 0x45, 0xf7, 0x93,
- 0x7a, 0x69, 0x29, 0x83, 0x71, 0xf6, 0xa4, 0xf1, 0xbd, 0xaa, 0x2b, 0xec,
- 0x7f, 0x31, 0x74, 0x58, 0x1a, 0xd5, 0x16, 0xe8, 0x45, 0x8e, 0xdd, 0x7b,
- 0x58, 0x6a, 0xd5, 0x79, 0x79, 0xa1, 0xba, 0xb1, 0x0b, 0xd8, 0x09, 0x32,
- 0x25, 0xfd, 0x3d, 0x3e, 0xfd, 0x54, 0x41, 0x30, 0x0e, 0x79, 0x9e, 0x2e,
- 0xc4, 0xbd, 0xba, 0x96, 0xb8, 0xed, 0x24, 0xdf, 0x1b, 0x8c, 0xf3, 0x3d,
- 0xbe, 0x23, 0xcb, 0xb4, 0xc9, 0x8b, 0xf7, 0x2e, 0x58, 0x9f, 0x92, 0x0b,
- 0xa9, 0x3d, 0xb2, 0x91, 0x52, 0xf5, 0x2f, 0xf1, 0x01, 0x7c, 0xdb, 0x34,
- 0xd6, 0xe5, 0x6e, 0x39, 0x01, 0x3f, 0xbd, 0x90, 0xca, 0xa9, 0xf3, 0x9b,
- 0xe3, 0x4d, 0x62, 0xfb, 0x79, 0xd6, 0x54, 0xb2, 0xae, 0x7a, 0x60, 0xad,
- 0xd6, 0x64, 0x8a, 0xb1, 0xa7, 0x43, 0x36, 0x14, 0xd6, 0xf2, 0x7a, 0xe3,
- 0x1b, 0xb3, 0x9e, 0x6f, 0x84, 0x94, 0xbd, 0xff, 0x1b, 0xd0, 0x71, 0x0c,
- 0x36, 0x1b, 0x51, 0x73, 0x42, 0xe9, 0x4e, 0x7f, 0x8e, 0xc2, 0x66, 0x6d,
- 0x73, 0xc6, 0xc7, 0x33, 0x96, 0xf1, 0xa9, 0x8c, 0x35, 0x36, 0xe1, 0xf5,
- 0x53, 0x4c, 0xc3, 0xd6, 0x2e, 0xb6, 0x82, 0xf7, 0x4d, 0xa6, 0xe0, 0x4f,
- 0x2f, 0x6d, 0x62, 0x63, 0x18, 0xe7, 0xf3, 0x0b, 0xd0, 0x6b, 0x58, 0x3a,
- 0x4e, 0xb5, 0xee, 0x99, 0x4b, 0x8d, 0x24, 0x8e, 0x08, 0xdf, 0x30, 0x62,
- 0xfd, 0x6c, 0x82, 0xda, 0x05, 0xe4, 0xc3, 0x2b, 0xc4, 0x08, 0xc3, 0xe7,
- 0xe5, 0xca, 0x3d, 0x99, 0xd4, 0x7e, 0xad, 0x36, 0x8b, 0xea, 0xe4, 0xf9,
- 0x29, 0xe6, 0xd3, 0xa3, 0xec, 0x7d, 0x86, 0x4e, 0xbd, 0xad, 0x39, 0x65,
- 0xf5, 0x8e, 0x39, 0xf4, 0xd2, 0xd2, 0xe6, 0x21, 0x37, 0x3c, 0x3f, 0xc3,
- 0x04, 0xa8, 0x5b, 0x83, 0x09, 0x47, 0x72, 0xec, 0x71, 0x49, 0x7e, 0x59,
- 0xf6, 0x65, 0x10, 0x47, 0xed, 0x99, 0x0e, 0x99, 0x6f, 0x18, 0xce, 0xe0,
- 0xe2, 0x51, 0xac, 0x31, 0x87, 0xb5, 0xa6, 0x51, 0x83, 0xcc, 0x22, 0x27,
- 0x53, 0xae, 0x8c, 0xd5, 0x0f, 0x43, 0x46, 0x37, 0xf1, 0xcc, 0x78, 0x3c,
- 0x27, 0xe6, 0x4c, 0x41, 0xad, 0xfb, 0x9e, 0x96, 0x1f, 0xfd, 0x18, 0x72,
- 0x5a, 0x58, 0x0e, 0x24, 0x45, 0x9f, 0x4e, 0x86, 0xdf, 0x9f, 0xb3, 0x38,
- 0x16, 0xe5, 0x98, 0x8e, 0xb1, 0xf0, 0xe7, 0x92, 0x51, 0x3d, 0x93, 0x34,
- 0xc7, 0xd9, 0xef, 0x0d, 0x59, 0x73, 0x12, 0x7a, 0xbe, 0xb7, 0x47, 0xba,
- 0xa7, 0xa5, 0x77, 0xd5, 0x1c, 0x7f, 0x1d, 0xb4, 0x84, 0x55, 0x6c, 0x9f,
- 0x13, 0xdd, 0x1f, 0xef, 0xd9, 0x1c, 0x0f, 0xfb, 0xe3, 0xd3, 0xd2, 0xbd,
- 0x3a, 0x62, 0xbc, 0x29, 0x87, 0xb1, 0x66, 0x48, 0x2e, 0xa1, 0xa6, 0xb1,
- 0x86, 0xe6, 0xe0, 0x73, 0x0f, 0x91, 0x96, 0x83, 0xc0, 0x14, 0xf0, 0x09,
- 0xd4, 0xd9, 0xd6, 0x27, 0xe5, 0x4b, 0x46, 0x97, 0xe4, 0x55, 0x4d, 0x1b,
- 0xf6, 0x7a, 0xa5, 0xb0, 0xf3, 0x5b, 0x87, 0xa6, 0x77, 0x7b, 0xfd, 0x00,
- 0x9e, 0x67, 0x8c, 0x62, 0xec, 0x4a, 0x6b, 0xc5, 0xe2, 0x18, 0xef, 0x5d,
- 0x69, 0xd5, 0xad, 0x11, 0x23, 0xab, 0x45, 0xfd, 0x73, 0xed, 0x79, 0xc5,
- 0x7b, 0xa1, 0x3a, 0x68, 0xd4, 0xe4, 0x16, 0x2d, 0x7b, 0x03, 0xf2, 0x83,
- 0xfb, 0x19, 0xcc, 0xbd, 0xd2, 0xca, 0x58, 0xf3, 0xaa, 0x7f, 0x5f, 0x93,
- 0xe0, 0x9a, 0xeb, 0x8c, 0x18, 0x93, 0xea, 0xd9, 0x11, 0xe3, 0x84, 0xd6,
- 0xfe, 0xac, 0xa1, 0x4d, 0x6e, 0x7b, 0xb6, 0x5b, 0xc9, 0x28, 0x64, 0x79,
- 0x73, 0x4a, 0xd5, 0x69, 0x79, 0xda, 0xe5, 0xbc, 0x2b, 0xad, 0xac, 0x15,
- 0xd1, 0x4e, 0xdc, 0xc0, 0x18, 0xc8, 0xb9, 0x97, 0xaf, 0xda, 0x87, 0xd7,
- 0xd7, 0xda, 0xe3, 0x5d, 0xd9, 0xbe, 0xc7, 0x2e, 0x35, 0xe7, 0x82, 0x9a,
- 0x13, 0x56, 0xb2, 0xde, 0xbe, 0xcf, 0xcf, 0x64, 0xfb, 0x3e, 0xdd, 0x9b,
- 0x3c, 0x97, 0xb0, 0xe6, 0x93, 0x98, 0x5b, 0x76, 0x07, 0xe3, 0x75, 0xb9,
- 0xdc, 0xca, 0x5b, 0x17, 0xe5, 0xc2, 0xe6, 0xda, 0xbf, 0xc2, 0x75, 0x3b,
- 0x4d, 0xbf, 0xf2, 0x69, 0xe4, 0x77, 0x8e, 0x3d, 0xaa, 0xe4, 0xbd, 0xdb,
- 0x1a, 0x3c, 0x58, 0xd3, 0xcc, 0xf1, 0x9f, 0x09, 0x75, 0x75, 0x44, 0xc5,
- 0x98, 0xdb, 0xa0, 0xa7, 0x7d, 0xcf, 0xc0, 0x67, 0x47, 0x6d, 0x35, 0xe7,
- 0x92, 0x35, 0x2d, 0xfb, 0x4e, 0x0d, 0x1a, 0x97, 0x10, 0xdb, 0x9c, 0x18,
- 0xaf, 0x51, 0x2b, 0x59, 0x7c, 0x27, 0xfe, 0x4e, 0xd6, 0x01, 0xd0, 0xe5,
- 0xe0, 0xf0, 0xcf, 0xe4, 0xa8, 0x9c, 0xa8, 0x1c, 0x43, 0x2e, 0x9c, 0x93,
- 0xe1, 0x67, 0x90, 0x37, 0x2a, 0x05, 0x3c, 0x49, 0x9f, 0xf5, 0x72, 0xe0,
- 0x9c, 0x7a, 0xcf, 0xfc, 0x24, 0xea, 0x64, 0xd8, 0x6e, 0x79, 0x70, 0x78,
- 0x05, 0xcf, 0xbc, 0xa0, 0x70, 0xa8, 0x2b, 0x0d, 0xf8, 0x40, 0xe2, 0xf9,
- 0x3d, 0xb2, 0xfb, 0x01, 0xda, 0x22, 0x32, 0xfd, 0x6d, 0x11, 0xf5, 0xee,
- 0xbd, 0x6e, 0x75, 0x8a, 0xec, 0xa5, 0xdd, 0x34, 0x61, 0x63, 0x73, 0xde,
- 0x99, 0xd6, 0xb6, 0x6b, 0x73, 0xe6, 0xa2, 0xac, 0x2a, 0xfb, 0xbb, 0x7d,
- 0xd5, 0xfb, 0x3f, 0xba, 0x8a, 0x72, 0x38, 0x39, 0x2d, 0x77, 0xac, 0x7a,
- 0xf6, 0x56, 0x5a, 0x3a, 0xaa, 0xe4, 0x3a, 0xa7, 0xe4, 0xda, 0x92, 0xc3,
- 0x29, 0xca, 0x9c, 0xbc, 0xf0, 0xbd, 0x40, 0x4f, 0x16, 0xf7, 0xfb, 0xf6,
- 0x33, 0xf8, 0x0c, 0x7f, 0x57, 0x42, 0xd9, 0xb0, 0xee, 0xbe, 0x7f, 0x37,
- 0xcf, 0x59, 0xf7, 0xad, 0x92, 0xcf, 0x1b, 0xb7, 0xf1, 0xf9, 0x14, 0x62,
- 0xea, 0xd0, 0x90, 0xc7, 0xeb, 0xab, 0x4b, 0x1f, 0xce, 0xeb, 0x37, 0x37,
- 0x79, 0x0d, 0x49, 0x43, 0xd5, 0xaf, 0x5d, 0xbd, 0xd2, 0x8d, 0xa8, 0x07,
- 0x7b, 0xf8, 0x09, 0xf6, 0x9a, 0x12, 0xd2, 0xe0, 0xed, 0xb7, 0xe1, 0x92,
- 0x96, 0x80, 0x76, 0xd2, 0x73, 0x9f, 0xaf, 0x2f, 0xee, 0x7f, 0x74, 0xc7,
- 0x7b, 0x97, 0xc4, 0x70, 0x86, 0x31, 0xa6, 0x2b, 0x9d, 0x65, 0x7d, 0xff,
- 0x9a, 0x16, 0x5d, 0xe9, 0xcc, 0xde, 0xd4, 0xd9, 0xeb, 0xd0, 0x59, 0x5d,
- 0x7e, 0x13, 0xbc, 0xc0, 0x9f, 0x9f, 0x19, 0x31, 0x0e, 0x13, 0x5b, 0x18,
- 0x5c, 0x0f, 0x31, 0xd4, 0xd7, 0x5d, 0xc7, 0x47, 0xd0, 0xdd, 0x9b, 0xa2,
- 0xf4, 0x07, 0x7e, 0x90, 0x7f, 0xd4, 0xf3, 0x8c, 0x61, 0xe4, 0xa9, 0x43,
- 0xf9, 0x3e, 0x69, 0x53, 0x67, 0xfc, 0x33, 0x9e, 0x3e, 0x95, 0x6f, 0xfb,
- 0xfa, 0xcc, 0xcd, 0x50, 0x67, 0xe6, 0x6e, 0x4f, 0x7f, 0x9d, 0x6a, 0xce,
- 0x62, 0x32, 0xa1, 0xfc, 0xda, 0x1a, 0xba, 0x65, 0x37, 0x75, 0xf8, 0xb4,
- 0xeb, 0xfd, 0x2f, 0xbb, 0xd3, 0xb2, 0xe8, 0x7e, 0x98, 0x1e, 0x3d, 0x1d,
- 0x4e, 0x88, 0xe7, 0x3f, 0x57, 0xeb, 0x4f, 0x5f, 0x0d, 0x2b, 0x5b, 0x9d,
- 0x80, 0xec, 0x4e, 0x56, 0x3e, 0xe6, 0xdb, 0xb7, 0xc7, 0xeb, 0xd0, 0x87,
- 0xf0, 0x7a, 0xb8, 0x3c, 0x68, 0xbc, 0x8d, 0xb5, 0x26, 0x15, 0x86, 0x8b,
- 0x88, 0xe3, 0xf3, 0x9a, 0xd8, 0xe4, 0x35, 0xa0, 0xcd, 0x9b, 0x97, 0x65,
- 0x5d, 0xea, 0x32, 0x3e, 0x3d, 0xaa, 0xde, 0xbf, 0x7f, 0xa3, 0xcc, 0xb8,
- 0x0c, 0xcc, 0x13, 0xeb, 0x93, 0x4b, 0x8d, 0x84, 0x5c, 0x22, 0x96, 0x18,
- 0xc3, 0x7f, 0xf7, 0x98, 0x9f, 0x9b, 0xa3, 0xf2, 0x66, 0xb9, 0xbd, 0x56,
- 0x1c, 0x95, 0xd7, 0xcb, 0x41, 0xbd, 0x48, 0x2c, 0xcb, 0xfc, 0x3f, 0x27,
- 0x6f, 0x2d, 0x0d, 0xca, 0xfa, 0x0c, 0xf2, 0xf8, 0x10, 0x65, 0x30, 0x62,
- 0x7c, 0x46, 0xfd, 0xbe, 0xe2, 0x4a, 0xeb, 0xbc, 0x85, 0x75, 0x97, 0x5b,
- 0x72, 0x84, 0xe7, 0xd0, 0xfc, 0xde, 0xf8, 0x04, 0x56, 0xe1, 0xbc, 0x3e,
- 0xa9, 0x2d, 0xa3, 0x2e, 0x2f, 0x73, 0x5d, 0xca, 0x69, 0x5a, 0x7d, 0x9f,
- 0xc4, 0x3e, 0xf7, 0xf3, 0xbd, 0xf4, 0x18, 0x75, 0x71, 0xa5, 0xb5, 0x61,
- 0xf1, 0x1c, 0x72, 0x4e, 0x1a, 0xd0, 0xd7, 0x97, 0x93, 0x3c, 0x27, 0xcf,
- 0x0b, 0x7f, 0x9f, 0x52, 0x6b, 0xcc, 0xa0, 0x16, 0xb8, 0xd2, 0x5a, 0xb0,
- 0x9e, 0x52, 0x7a, 0x6a, 0x54, 0x1f, 0xf0, 0xc7, 0x79, 0xcd, 0x7b, 0x86,
- 0xb3, 0x6f, 0x88, 0xf5, 0xe7, 0x03, 0xc8, 0xff, 0xac, 0x3d, 0x89, 0xb7,
- 0x28, 0x8b, 0x04, 0x6a, 0x5c, 0xae, 0xc5, 0xdf, 0x04, 0x25, 0x87, 0xf3,
- 0x32, 0x09, 0x7a, 0x80, 0xcb, 0x5c, 0xc6, 0xfd, 0x5b, 0x65, 0x23, 0xe6,
- 0xc5, 0x77, 0xbe, 0xaf, 0xb5, 0x81, 0x98, 0xbf, 0xb1, 0x19, 0xf3, 0xfb,
- 0x71, 0x6d, 0x38, 0xa9, 0xa1, 0xff, 0x84, 0xf5, 0xd9, 0x77, 0x61, 0xcc,
- 0x1f, 0xc7, 0x7c, 0x8e, 0xf5, 0x49, 0x69, 0x59, 0x6c, 0xf6, 0x99, 0x6a,
- 0xc2, 0x77, 0x31, 0x72, 0xb2, 0xd8, 0x18, 0x8c, 0x9f, 0xd7, 0x1c, 0xf5,
- 0xce, 0x46, 0x72, 0x88, 0x7d, 0xb7, 0x3e, 0x69, 0x2c, 0x4b, 0x22, 0x94,
- 0x7e, 0x48, 0xdc, 0x86, 0x87, 0xb9, 0x17, 0x34, 0xf6, 0xdf, 0x6c, 0x69,
- 0x6c, 0x9f, 0x63, 0x84, 0xd2, 0x87, 0xe4, 0x0f, 0xfc, 0x39, 0x8e, 0x9a,
- 0xf3, 0x1f, 0x76, 0xf3, 0xec, 0xab, 0xe1, 0xf6, 0x82, 0x06, 0xd2, 0x76,
- 0x63, 0xfb, 0xbe, 0x89, 0xad, 0x7d, 0xb9, 0x27, 0x6a, 0x98, 0xbd, 0x36,
- 0xf6, 0x7d, 0x15, 0xcf, 0x3c, 0x04, 0x3a, 0xae, 0x84, 0x74, 0xeb, 0x21,
- 0x29, 0x36, 0xae, 0xde, 0xa3, 0x9d, 0x06, 0x3e, 0xc3, 0xf5, 0xb9, 0xcf,
- 0x21, 0xd0, 0x77, 0x45, 0xd3, 0xad, 0x43, 0x90, 0xa5, 0xb7, 0x47, 0xe8,
- 0x39, 0xd3, 0xf8, 0xa1, 0x0c, 0x89, 0xbe, 0xa2, 0x29, 0xf9, 0xeb, 0xb5,
- 0x51, 0x38, 0xc4, 0x94, 0x74, 0xaf, 0xcd, 0x4a, 0x68, 0x8d, 0x3d, 0x00,
- 0xda, 0x22, 0xf5, 0xb8, 0x0b, 0x7e, 0x2c, 0x76, 0xd8, 0x22, 0xde, 0x67,
- 0x1f, 0x77, 0xb5, 0x57, 0x7a, 0x89, 0xf7, 0x59, 0x0f, 0x1c, 0xc4, 0x7f,
- 0xd6, 0x04, 0x2f, 0xb5, 0x32, 0xa9, 0x77, 0x54, 0xde, 0xcc, 0x37, 0x78,
- 0xdf, 0x4c, 0x88, 0xf0, 0x1e, 0xe3, 0x43, 0x9f, 0x44, 0xbe, 0x3e, 0x8c,
- 0x98, 0x90, 0x03, 0x76, 0xc6, 0xba, 0xa7, 0x86, 0x24, 0xec, 0xbd, 0xeb,
- 0xa0, 0xfa, 0x25, 0x6f, 0x2d, 0x9b, 0xfe, 0xef, 0x53, 0x64, 0xdf, 0xf9,
- 0x14, 0x7b, 0x9a, 0x03, 0xb0, 0x53, 0xd6, 0x23, 0xa2, 0x6f, 0xa0, 0xde,
- 0xbc, 0xd4, 0x88, 0xf6, 0xf2, 0x7d, 0xcb, 0xd7, 0x5d, 0x5c, 0x13, 0xbb,
- 0xc7, 0x14, 0x56, 0xf4, 0xef, 0xf1, 0x3b, 0xea, 0xa0, 0x6d, 0x98, 0x32,
- 0x01, 0x4c, 0xc9, 0x3a, 0x69, 0xca, 0x7f, 0xe7, 0xcd, 0x70, 0x4e, 0x6c,
- 0xab, 0x95, 0x86, 0x65, 0x03, 0x38, 0x6b, 0xdd, 0xb5, 0x10, 0x07, 0xdf,
- 0xd6, 0xea, 0x65, 0xf5, 0xbb, 0x34, 0xed, 0x01, 0x60, 0xac, 0x44, 0x9f,
- 0xaa, 0x75, 0x4e, 0x3e, 0x20, 0x9e, 0xbd, 0xc3, 0xca, 0x54, 0xcc, 0x5a,
- 0xaf, 0x7a, 0xb5, 0xc5, 0x46, 0x75, 0x4a, 0xfe, 0xd4, 0x5d, 0x50, 0xbd,
- 0xd2, 0x25, 0xd4, 0x1b, 0xe1, 0x45, 0x55, 0x6b, 0xb5, 0xe1, 0x54, 0xc4,
- 0xb7, 0x67, 0x8f, 0xc0, 0x07, 0x4d, 0xf5, 0x6e, 0x81, 0xbe, 0xd2, 0x6a,
- 0x65, 0x11, 0x2f, 0x74, 0xcb, 0x32, 0x8a, 0xc8, 0x73, 0x59, 0xf5, 0x7e,
- 0x0a, 0xfd, 0xf7, 0xf7, 0x54, 0x1c, 0x96, 0x1a, 0x64, 0xf3, 0x5c, 0x02,
- 0xeb, 0x68, 0xca, 0x3e, 0x43, 0x4a, 0x0f, 0x0f, 0x28, 0xec, 0x1a, 0x5a,
- 0x41, 0x80, 0x5a, 0x1b, 0x12, 0x59, 0x81, 0xbf, 0xc2, 0x77, 0xc3, 0x6b,
- 0xd4, 0x01, 0x65, 0x3b, 0x2b, 0x11, 0xc8, 0x9e, 0x58, 0x22, 0xb4, 0x48,
- 0x19, 0xc7, 0x61, 0x17, 0x5c, 0x07, 0x32, 0xe6, 0xbb, 0x2c, 0xcb, 0x1d,
- 0xf2, 0x4c, 0xc3, 0xf4, 0xdf, 0x3d, 0x7f, 0x89, 0xef, 0xa3, 0xeb, 0x73,
- 0x63, 0x03, 0xc4, 0x4f, 0x52, 0x6a, 0x00, 0x63, 0x9c, 0x66, 0x0d, 0xce,
- 0x18, 0x50, 0x88, 0x47, 0x94, 0xaf, 0xb3, 0x06, 0xf6, 0x7c, 0x9f, 0xf8,
- 0x3a, 0x62, 0x11, 0xdb, 0x8e, 0x62, 0x8f, 0x9d, 0xe4, 0xea, 0xd5, 0x9e,
- 0x93, 0xa0, 0xf3, 0xfc, 0x92, 0x39, 0x55, 0x90, 0x14, 0xdf, 0x71, 0x9e,
- 0xb1, 0xc1, 0xf7, 0x06, 0xe2, 0xe4, 0x42, 0x85, 0xef, 0x33, 0x17, 0xe1,
- 0x59, 0x53, 0x72, 0xbe, 0xcc, 0x1a, 0xf0, 0x76, 0xe8, 0x8b, 0xd7, 0xc5,
- 0xf1, 0x10, 0xfc, 0xff, 0xa2, 0xc1, 0xdf, 0x91, 0xf1, 0x77, 0x41, 0x66,
- 0x2a, 0xa1, 0x1d, 0x84, 0x8e, 0x0b, 0x46, 0xc4, 0xb7, 0x03, 0xa7, 0x4c,
- 0x8c, 0x35, 0x62, 0x9c, 0xc3, 0xf7, 0x97, 0xdd, 0xcb, 0x2d, 0xd6, 0x3f,
- 0x17, 0x10, 0xe7, 0xa6, 0x92, 0x53, 0xb0, 0x9d, 0x42, 0xbc, 0x13, 0xb4,
- 0xfe, 0x5d, 0xdc, 0xcb, 0xbb, 0xdc, 0xc7, 0x4c, 0x5d, 0x94, 0x22, 0x30,
- 0xfd, 0x48, 0xe2, 0x65, 0xd9, 0x83, 0x3a, 0x55, 0x93, 0x37, 0x2d, 0x73,
- 0x5c, 0x34, 0xb5, 0xde, 0xf0, 0x7d, 0xb0, 0xbd, 0x37, 0x10, 0xdf, 0x3a,
- 0xfc, 0xda, 0x3d, 0x5b, 0x26, 0x16, 0x3a, 0xaa, 0xde, 0x05, 0xb8, 0x60,
- 0xb1, 0x7f, 0xc7, 0xdf, 0x44, 0xfe, 0xa5, 0xda, 0x63, 0xeb, 0x8c, 0x8d,
- 0xfd, 0x63, 0xd2, 0xe7, 0xf1, 0x78, 0xc0, 0xf2, 0x68, 0xe4, 0x3a, 0x91,
- 0xb6, 0x75, 0xce, 0xfb, 0xeb, 0x9c, 0xf5, 0xd7, 0xa9, 0xf9, 0xeb, 0x5c,
- 0xd8, 0x5c, 0xe7, 0x6e, 0xe8, 0xbf, 0xd5, 0x7a, 0x0a, 0xf8, 0x21, 0x93,
- 0x6a, 0xb5, 0x1c, 0xd4, 0x59, 0xa5, 0xd1, 0x79, 0x75, 0x46, 0xaa, 0xa7,
- 0xbf, 0x71, 0x6f, 0xc6, 0x2a, 0xc4, 0xc3, 0x0a, 0x7b, 0xa0, 0x92, 0x82,
- 0x1d, 0x16, 0xc4, 0xc3, 0xdc, 0x3c, 0xb7, 0xf3, 0xce, 0xf5, 0xba, 0xa1,
- 0xc3, 0x1c, 0x72, 0x86, 0x91, 0x39, 0x67, 0x49, 0x61, 0xdf, 0x6f, 0xea,
- 0xb0, 0xf3, 0x5e, 0xe4, 0x87, 0x9f, 0xc0, 0x66, 0x8c, 0x4c, 0xbd, 0x91,
- 0x43, 0xbd, 0xc3, 0xf9, 0x77, 0x40, 0x8f, 0x85, 0x4c, 0xad, 0x51, 0xc8,
- 0x9c, 0xe5, 0x79, 0x0e, 0xe6, 0xd5, 0x1a, 0x3d, 0x90, 0x7b, 0x8f, 0xea,
- 0x8b, 0xbc, 0x5c, 0x8e, 0x31, 0x06, 0xc1, 0xd6, 0x63, 0x18, 0x8b, 0xab,
- 0xdf, 0x68, 0xd5, 0xdd, 0x65, 0xf8, 0x74, 0x02, 0xe3, 0xd5, 0xae, 0x49,
- 0x85, 0x47, 0x2d, 0x59, 0x71, 0x7f, 0xa5, 0x15, 0xcb, 0x97, 0xb5, 0x52,
- 0x79, 0x18, 0x73, 0x46, 0xf9, 0x5b, 0x9f, 0x3d, 0xc0, 0x49, 0x53, 0xd5,
- 0x1d, 0x69, 0x4a, 0x80, 0x26, 0xbd, 0x8d, 0xa6, 0x04, 0xe8, 0x41, 0xcc,
- 0x3c, 0xc5, 0xde, 0xf1, 0xa8, 0x9c, 0x28, 0xf3, 0x9d, 0x26, 0xfe, 0x46,
- 0xd5, 0x90, 0x30, 0xb0, 0x65, 0xe4, 0x94, 0x19, 0x5f, 0x57, 0xbd, 0x1a,
- 0x73, 0xb8, 0x2e, 0x23, 0xa9, 0xba, 0xa8, 0xfc, 0x92, 0x38, 0x81, 0x7c,
- 0xf5, 0x86, 0xdb, 0x23, 0x6f, 0xfa, 0x7b, 0x5d, 0x14, 0x9e, 0x33, 0x6e,
- 0xdf, 0xeb, 0xc9, 0x4a, 0x2a, 0xf3, 0x8a, 0x15, 0xf2, 0xf9, 0xea, 0xc3,
- 0x5e, 0x7b, 0x30, 0x37, 0x95, 0x39, 0xdf, 0xd8, 0x69, 0xae, 0x83, 0xb9,
- 0x91, 0xb6, 0xb9, 0x0e, 0xe6, 0xf5, 0x20, 0xef, 0xf5, 0x28, 0x9e, 0x4a,
- 0xa0, 0xeb, 0x52, 0x99, 0x3c, 0xf1, 0x0c, 0x82, 0x7b, 0x1a, 0xc4, 0xc6,
- 0x53, 0xe2, 0x9f, 0xd9, 0xf2, 0xf7, 0x7a, 0x57, 0xf5, 0x6b, 0x94, 0x0d,
- 0x4c, 0x58, 0x3c, 0x9b, 0x99, 0xd1, 0xb2, 0xf5, 0x3c, 0x72, 0xd5, 0x8d,
- 0xc4, 0x43, 0x29, 0x1b, 0xb9, 0x92, 0xe7, 0x3c, 0x8d, 0x72, 0x81, 0xef,
- 0x3d, 0xc3, 0x2e, 0xde, 0x21, 0x5e, 0xbe, 0x31, 0xa4, 0xde, 0x43, 0x70,
- 0xfc, 0x73, 0x20, 0x31, 0x32, 0x63, 0x7c, 0xf7, 0xe0, 0x6e, 0xa9, 0x2f,
- 0x7f, 0x11, 0x63, 0x19, 0xe4, 0xc5, 0x43, 0x5a, 0xe6, 0xdc, 0x24, 0xae,
- 0x1f, 0xc2, 0x35, 0xe2, 0xf0, 0x72, 0x0e, 0xf7, 0x1f, 0xc2, 0xf5, 0xbc,
- 0x96, 0x6d, 0xe6, 0x70, 0xfd, 0x30, 0xae, 0x27, 0x48, 0x9b, 0xf3, 0x8a,
- 0x35, 0xa5, 0xd9, 0x58, 0xcb, 0x3e, 0x37, 0x89, 0x4f, 0xfb, 0x7a, 0xbc,
- 0x07, 0x3d, 0x95, 0x79, 0x3e, 0x96, 0x04, 0x4d, 0x0f, 0x6a, 0x4e, 0xbd,
- 0x1b, 0x6b, 0x0c, 0xe1, 0x79, 0xda, 0x54, 0xfb, 0x39, 0xd4, 0x6d, 0xaa,
- 0x67, 0x14, 0x4a, 0xa7, 0x81, 0x77, 0x1f, 0x41, 0xde, 0xd7, 0xc4, 0xb1,
- 0x1e, 0x97, 0x62, 0x2a, 0x2d, 0x0b, 0xf5, 0x90, 0x64, 0x63, 0x05, 0x7c,
- 0x2f, 0x48, 0x66, 0x1c, 0xf7, 0xeb, 0xb4, 0x05, 0xce, 0x2b, 0x49, 0xb1,
- 0x4a, 0xfc, 0xce, 0x7e, 0xd1, 0x57, 0xc0, 0x37, 0xfb, 0x44, 0x79, 0xc8,
- 0x20, 0x46, 0xfb, 0xdd, 0xa1, 0xa7, 0xe5, 0xbd, 0xd3, 0x8c, 0x7c, 0xac,
- 0x65, 0xea, 0xfe, 0x59, 0x9d, 0xc5, 0xdf, 0x2b, 0xb1, 0x47, 0x25, 0xc5,
- 0x50, 0x9a, 0x7d, 0x0e, 0xd5, 0x17, 0x4f, 0x79, 0x67, 0x7a, 0xed, 0xef,
- 0x90, 0x04, 0xfe, 0xc2, 0x7d, 0xbf, 0x82, 0xe7, 0xbd, 0xbe, 0x54, 0xb6,
- 0xf9, 0x41, 0x5d, 0xf0, 0x5d, 0xfd, 0x15, 0xe8, 0xe2, 0xfc, 0x87, 0xf6,
- 0xb9, 0xd8, 0xe3, 0x9a, 0x47, 0x2c, 0x62, 0x7f, 0x2c, 0x90, 0xdf, 0xd5,
- 0x34, 0x92, 0xbe, 0xc3, 0x58, 0x4b, 0x52, 0x8c, 0xb3, 0xb9, 0x58, 0x42,
- 0xd5, 0xbe, 0x1b, 0x4b, 0xf2, 0xc4, 0x16, 0xbd, 0xa4, 0x95, 0x72, 0x78,
- 0x04, 0xf5, 0x1a, 0x7f, 0xff, 0xf0, 0xb8, 0xe4, 0x53, 0xec, 0xd1, 0x84,
- 0x90, 0x0b, 0x0b, 0xf8, 0xbe, 0x25, 0xb7, 0x92, 0x2f, 0xb7, 0x7c, 0xf5,
- 0x5b, 0x4a, 0x77, 0x35, 0x8b, 0xfb, 0x05, 0xbd, 0x8b, 0x69, 0xa5, 0xb3,
- 0x9a, 0x7a, 0xcf, 0x36, 0xe0, 0x3d, 0xe8, 0xbf, 0xed, 0x6c, 0x73, 0x93,
- 0x16, 0x69, 0xfb, 0x38, 0xdf, 0x5b, 0x18, 0xb6, 0x85, 0xf4, 0x93, 0x0f,
- 0xe6, 0xac, 0xe0, 0x5c, 0x34, 0xe0, 0x21, 0xe0, 0xf3, 0xa3, 0xca, 0x85,
- 0x74, 0xee, 0x31, 0xa4, 0x7b, 0xca, 0x08, 0x59, 0xcc, 0x01, 0x9f, 0xf6,
- 0xfb, 0xf8, 0xff, 0x37, 0xe5, 0xea, 0xf1, 0x1e, 0x86, 0xa8, 0xfc, 0xdf,
- 0x8b, 0xee, 0xa0, 0xf7, 0xab, 0xcf, 0x80, 0x0d, 0xe7, 0xac, 0xb5, 0xc5,
- 0x67, 0x6d, 0x07, 0x3e, 0x6b, 0x3e, 0x9f, 0x1f, 0x7e, 0x4e, 0xea, 0xd1,
- 0x59, 0x5b, 0xb2, 0xc1, 0x23, 0x6d, 0x6a, 0x27, 0x7b, 0xe3, 0x6f, 0x9c,
- 0xd4, 0xef, 0xad, 0xa2, 0xb6, 0x7b, 0xad, 0x5e, 0x27, 0xeb, 0x64, 0xcf,
- 0xee, 0xce, 0x22, 0xd7, 0x55, 0xab, 0x5e, 0xcd, 0x5c, 0x75, 0xd9, 0x6b,
- 0xde, 0x69, 0x6f, 0x0d, 0x34, 0xff, 0x8e, 0x7a, 0xef, 0xa4, 0xe4, 0x7a,
- 0x7d, 0xa9, 0x6a, 0xb5, 0x3d, 0x57, 0xde, 0xc0, 0x3c, 0x39, 0x5c, 0x90,
- 0x19, 0xe8, 0x31, 0x89, 0xeb, 0x9b, 0xe5, 0xe5, 0x65, 0x75, 0x86, 0xe4,
- 0x9f, 0xd5, 0xf0, 0x0c, 0x46, 0x9d, 0x43, 0x23, 0x5e, 0xcd, 0xaa, 0x78,
- 0xbd, 0xb1, 0xac, 0xee, 0xa9, 0xdf, 0x3c, 0xd4, 0xdd, 0x19, 0xc4, 0x73,
- 0xd4, 0x06, 0xd6, 0x6e, 0x29, 0xa2, 0x86, 0x3e, 0x6b, 0xcd, 0x18, 0xc4,
- 0x29, 0x5c, 0x6b, 0x03, 0x6b, 0x9d, 0x5f, 0x96, 0xbd, 0x7c, 0xa7, 0xa3,
- 0xaa, 0xce, 0xbd, 0xbc, 0x7e, 0xf5, 0xbc, 0x04, 0xbf, 0xd7, 0x8d, 0xfa,
- 0x39, 0x8e, 0xef, 0x95, 0xf0, 0xb7, 0xa7, 0x8c, 0x01, 0xa8, 0x6b, 0x66,
- 0x0a, 0x58, 0xaf, 0xd5, 0xf2, 0xfa, 0xd9, 0x2d, 0xd8, 0x7d, 0x84, 0xbf,
- 0x65, 0xc0, 0xdf, 0x23, 0xb0, 0x13, 0xf8, 0xc1, 0xe6, 0x38, 0xaf, 0x59,
- 0x4b, 0x04, 0xd7, 0x4c, 0x58, 0xff, 0x1b, 0xed, 0xcc, 0xfa, 0xa1, 0x98,
- 0x41, 0x00, 0x00, 0x00 };
-static u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
+ 0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c,
+ 0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1,
+ 0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42,
+ 0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48,
+ 0xd1, 0x6c, 0x68, 0x95, 0x49, 0x94, 0x54, 0xe3, 0x62, 0x41, 0x52, 0xf1,
+ 0xb6, 0xce, 0x54, 0x9b, 0x78, 0x5a, 0x4d, 0xeb, 0xad, 0x11, 0x90, 0xfa,
+ 0xe7, 0x85, 0x04, 0xda, 0x62, 0x44, 0x7f, 0xc8, 0x07, 0x18, 0x80, 0x24,
+ 0x6f, 0xf2, 0x44, 0x28, 0x9b, 0x7f, 0xfd, 0xd0, 0xac, 0x50, 0x4a, 0xd6,
+ 0xba, 0x9b, 0xb4, 0xa3, 0xed, 0x66, 0x67, 0x3b, 0xd3, 0x2f, 0x1c, 0x49,
+ 0xf6, 0x7a, 0x77, 0x67, 0x36, 0xda, 0x6e, 0xb6, 0xab, 0xb6, 0xb2, 0xd1,
+ 0xdf, 0xef, 0xbe, 0xf7, 0x28, 0x90, 0xa6, 0x6c, 0xcb, 0xb3, 0xed, 0x94,
+ 0x33, 0x18, 0xe0, 0xdd, 0x77, 0xdf, 0xb9, 0xe7, 0x9e, 0x73, 0xee, 0x39,
+ 0xe7, 0x77, 0xee, 0x7d, 0x0c, 0x8b, 0x74, 0x89, 0xf7, 0xf7, 0x00, 0x3e,
+ 0x91, 0x43, 0x87, 0x9f, 0xd9, 0x3e, 0xb2, 0xfd, 0x13, 0xf8, 0xf9, 0x09,
+ 0x31, 0x02, 0x06, 0x6f, 0xbe, 0x69, 0x88, 0x64, 0xff, 0x42, 0x3e, 0xf0,
+ 0x1f, 0x1e, 0x37, 0x7d, 0xfa, 0xfc, 0x48, 0x50, 0x4f, 0x4c, 0xec, 0x4a,
+ 0x5a, 0x12, 0x34, 0x12, 0xb2, 0x6f, 0xca, 0x12, 0xb1, 0x9d, 0xa1, 0x48,
+ 0x4a, 0xde, 0x6a, 0xe6, 0x43, 0x01, 0x61, 0xfb, 0x47, 0x12, 0x77, 0x9e,
+ 0xfb, 0xc9, 0xa7, 0xa3, 0xb7, 0xca, 0x86, 0x04, 0xcd, 0x44, 0x56, 0xcc,
+ 0x01, 0x09, 0xf6, 0xe1, 0x99, 0x6f, 0x3f, 0x6a, 0x18, 0xd2, 0xb3, 0xca,
+ 0xab, 0xcc, 0x95, 0x56, 0x9a, 0x3f, 0x79, 0x34, 0x2c, 0xbf, 0x57, 0x0f,
+ 0xc9, 0xf7, 0xea, 0xa6, 0x5c, 0xac, 0x07, 0xb4, 0xf1, 0x92, 0x29, 0xb3,
+ 0xa5, 0x69, 0xfd, 0x48, 0x31, 0x2f, 0xa9, 0x7a, 0x56, 0x2f, 0x2c, 0x98,
+ 0x3d, 0xc9, 0xf3, 0x39, 0x7d, 0x76, 0xa1, 0xb7, 0x27, 0x75, 0x7e, 0x5a,
+ 0x2f, 0x14, 0xc3, 0x3d, 0xc9, 0xba, 0xd9, 0x93, 0x5a, 0x0c, 0xe1, 0xba,
+ 0xb7, 0x27, 0xb9, 0x18, 0x9d, 0x17, 0xd9, 0x8a, 0x3e, 0xe1, 0x9e, 0x54,
+ 0x29, 0x9a, 0x15, 0xe9, 0x8f, 0xbf, 0x2a, 0x7d, 0x3d, 0xa9, 0xfa, 0x3f,
+ 0xd1, 0x1b, 0xa6, 0x26, 0x85, 0x5f, 0x15, 0x33, 0x9c, 0xb8, 0xd5, 0x7c,
+ 0xc8, 0xd2, 0xc4, 0xb4, 0x6e, 0x37, 0xb7, 0x58, 0x41, 0xc9, 0x9d, 0xee,
+ 0x14, 0x5b, 0xcd, 0xc9, 0x94, 0xdc, 0xe2, 0x90, 0xb9, 0x2c, 0x6d, 0x62,
+ 0x87, 0xfc, 0xeb, 0x66, 0x33, 0x19, 0xff, 0x32, 0xe5, 0x8a, 0x71, 0xa4,
+ 0x67, 0xbc, 0x2e, 0x92, 0x2c, 0x05, 0x25, 0x19, 0x7f, 0xab, 0xe9, 0x3e,
+ 0x13, 0xc4, 0x98, 0x81, 0x9e, 0xb1, 0x52, 0xb3, 0x99, 0x8e, 0x83, 0x7e,
+ 0xdc, 0x7f, 0xb6, 0x4d, 0xca, 0x21, 0xbb, 0x3c, 0x1b, 0xff, 0x6f, 0xba,
+ 0xab, 0x13, 0xce, 0x91, 0xd7, 0xb6, 0xe8, 0x56, 0x5e, 0x72, 0x21, 0x29,
+ 0x17, 0xe2, 0x9f, 0x92, 0x13, 0xf1, 0x30, 0xe6, 0x17, 0x94, 0x63, 0x71,
+ 0xc8, 0xd1, 0x3a, 0xac, 0x25, 0xeb, 0xd1, 0x48, 0x56, 0x9e, 0x97, 0xe4,
+ 0x62, 0xbf, 0x99, 0x16, 0x8c, 0x6d, 0x35, 0x3f, 0x9a, 0x8c, 0x63, 0xbc,
+ 0xe1, 0xff, 0xd5, 0xb4, 0x43, 0xd1, 0x6c, 0x59, 0x06, 0xa5, 0x50, 0xea,
+ 0x8f, 0xff, 0x4c, 0x34, 0x09, 0x5a, 0x62, 0x4f, 0x59, 0x26, 0xe4, 0x16,
+ 0x1d, 0x4c, 0x19, 0x4d, 0xd9, 0x83, 0xf1, 0x93, 0x16, 0xee, 0xd7, 0x65,
+ 0xb3, 0x6e, 0xb5, 0x4b, 0xc1, 0x94, 0x50, 0x97, 0x3c, 0x22, 0x85, 0xd3,
+ 0x68, 0x8f, 0xdb, 0xbd, 0x3a, 0x9e, 0xc9, 0x8c, 0xb0, 0x4d, 0x34, 0x23,
+ 0x11, 0x33, 0x53, 0xe0, 0xa8, 0xe2, 0x0c, 0x62, 0xfc, 0x98, 0xdd, 0xa9,
+ 0x99, 0xb2, 0x62, 0x06, 0xa4, 0xea, 0xc4, 0xec, 0xb0, 0xd6, 0x2e, 0xc7,
+ 0x62, 0x5d, 0x90, 0x69, 0x18, 0xb4, 0xe5, 0x9b, 0x7a, 0x22, 0x16, 0xce,
+ 0x41, 0x51, 0x3a, 0x64, 0x35, 0x07, 0x7e, 0xe6, 0xe2, 0x59, 0x2d, 0x55,
+ 0xff, 0x8a, 0x96, 0x3c, 0xbf, 0x5f, 0xdb, 0x75, 0x1e, 0x7d, 0xea, 0xe7,
+ 0x3c, 0xbb, 0x0b, 0x83, 0x37, 0x1d, 0xcf, 0xb2, 0x1d, 0x3c, 0x2b, 0xde,
+ 0xd1, 0x06, 0x5d, 0x36, 0x26, 0x43, 0x3d, 0x49, 0xa5, 0x4b, 0xf2, 0xa6,
+ 0x4b, 0x6e, 0x42, 0x93, 0x5e, 0xcb, 0x96, 0xe0, 0x27, 0xa1, 0xcf, 0x45,
+ 0xe8, 0x72, 0x31, 0x22, 0x47, 0x4a, 0x12, 0xd2, 0x85, 0x63, 0x65, 0xf5,
+ 0xaa, 0x43, 0x7b, 0x80, 0x6e, 0xa1, 0xfb, 0x82, 0xc3, 0x67, 0xa1, 0xc3,
+ 0x52, 0x1a, 0xf2, 0xc9, 0x60, 0xec, 0x7d, 0xda, 0x9e, 0xea, 0xa4, 0x96,
+ 0x81, 0x9d, 0x14, 0x4e, 0x0f, 0x41, 0x77, 0xd1, 0xc8, 0x8a, 0x6c, 0x96,
+ 0x82, 0x65, 0x45, 0xbe, 0x2c, 0xdd, 0x72, 0x6c, 0xd1, 0x92, 0x23, 0x8b,
+ 0x21, 0xc9, 0x9b, 0x51, 0xb3, 0x26, 0x7d, 0xd9, 0x4d, 0x89, 0x1e, 0x79,
+ 0xfe, 0x74, 0x34, 0x53, 0x96, 0x7e, 0xfb, 0x75, 0xdc, 0xcf, 0x9d, 0xa4,
+ 0x4e, 0x25, 0x9f, 0x8a, 0x1b, 0x92, 0x85, 0x4d, 0x18, 0xd6, 0x1f, 0x81,
+ 0xff, 0xe6, 0x73, 0xc9, 0x78, 0x34, 0x2c, 0xa2, 0x4b, 0xea, 0x0b, 0xfd,
+ 0xe6, 0x6e, 0x89, 0x9a, 0x19, 0xca, 0x3f, 0x3e, 0x04, 0x3d, 0xfc, 0x77,
+ 0xca, 0x1e, 0xb4, 0xa8, 0xe3, 0xa1, 0xf0, 0x31, 0xe8, 0x32, 0xab, 0x74,
+ 0xdc, 0x83, 0xf1, 0x03, 0x9e, 0xed, 0xf4, 0x48, 0xbe, 0x7a, 0xc3, 0x93,
+ 0x43, 0x8f, 0xcc, 0x57, 0xbb, 0xa5, 0x00, 0x1d, 0x16, 0xc4, 0x92, 0xc2,
+ 0xf9, 0x3f, 0xf7, 0xda, 0x2d, 0x99, 0x3b, 0xff, 0x32, 0xec, 0xe1, 0xb0,
+ 0xb6, 0xbf, 0xfe, 0x0b, 0xcd, 0xb3, 0x1f, 0xd8, 0x5f, 0x50, 0xec, 0x89,
+ 0xa0, 0x9c, 0xab, 0xbb, 0xf6, 0x57, 0xc1, 0x1a, 0xb3, 0x4d, 0x1b, 0xb6,
+ 0xf4, 0xc6, 0x6a, 0x9f, 0x73, 0xf5, 0x3e, 0x3c, 0x1b, 0x94, 0x23, 0x75,
+ 0xf6, 0xcf, 0xc3, 0xc6, 0x82, 0xb2, 0xf4, 0x68, 0xb7, 0x64, 0xd1, 0x5e,
+ 0x58, 0x14, 0x3b, 0x19, 0xd7, 0xf1, 0x4c, 0x0f, 0xe6, 0xb2, 0x15, 0x9f,
+ 0x2e, 0x99, 0xaa, 0x76, 0xd8, 0x86, 0x15, 0x92, 0xa9, 0x3a, 0xf5, 0x8f,
+ 0xef, 0x92, 0x6f, 0x03, 0x94, 0x2f, 0xdb, 0xf9, 0x1c, 0xdb, 0x4d, 0xb4,
+ 0xb7, 0xb6, 0xd1, 0xb6, 0x37, 0x53, 0xa6, 0x83, 0x82, 0xb6, 0x5c, 0x29,
+ 0x66, 0xee, 0xe7, 0x77, 0x9d, 0xf6, 0xd0, 0x6a, 0x0b, 0x01, 0xf4, 0x87,
+ 0x1e, 0xab, 0x18, 0xeb, 0xf4, 0x9d, 0x66, 0xdb, 0x08, 0xae, 0x2d, 0x2c,
+ 0xaa, 0x2e, 0x8e, 0x1d, 0x00, 0x5f, 0xba, 0x64, 0xab, 0x8a, 0xb7, 0x08,
+ 0x6d, 0xc0, 0x9d, 0x47, 0x9f, 0xcc, 0x2e, 0x76, 0xf7, 0xa4, 0x17, 0xd9,
+ 0x9e, 0x0c, 0x1b, 0x98, 0xe7, 0x54, 0x5c, 0x1a, 0x73, 0x71, 0xbd, 0x3f,
+ 0x00, 0xbe, 0xa6, 0xb1, 0xe0, 0x30, 0x0f, 0x8f, 0xc7, 0x06, 0xee, 0xf7,
+ 0xca, 0xd4, 0x79, 0xf6, 0xe5, 0x18, 0x85, 0x2d, 0xba, 0x24, 0xc0, 0x1b,
+ 0x3e, 0x56, 0x14, 0xf7, 0x3b, 0x31, 0x4e, 0x37, 0x6c, 0x27, 0x83, 0x31,
+ 0x9b, 0x8f, 0x27, 0xe3, 0xbd, 0x92, 0x5d, 0xed, 0x2b, 0xb0, 0x3b, 0xf6,
+ 0x1f, 0x5c, 0xd7, 0x17, 0xf2, 0x3d, 0x0f, 0x9a, 0x8b, 0x9d, 0x90, 0x21,
+ 0xdb, 0x75, 0xf0, 0xdc, 0x01, 0x1e, 0x82, 0x98, 0x4f, 0x3f, 0xd6, 0x43,
+ 0x07, 0xe8, 0x6f, 0xc2, 0x9c, 0x3a, 0x65, 0xfa, 0x74, 0x2f, 0x74, 0x61,
+ 0xa2, 0x6f, 0x50, 0x9e, 0x2f, 0x45, 0x61, 0x03, 0xec, 0x0f, 0x1d, 0x2c,
+ 0x46, 0xc3, 0x55, 0xb1, 0x65, 0x2e, 0xde, 0x01, 0xfb, 0x6a, 0x36, 0x67,
+ 0x60, 0x1f, 0xdf, 0x51, 0xfe, 0x62, 0xc8, 0x1c, 0xd3, 0x24, 0xdf, 0x91,
+ 0x38, 0x0c, 0x7e, 0xa2, 0x4f, 0x89, 0xf0, 0x7a, 0x87, 0xc6, 0x35, 0x0b,
+ 0x39, 0x72, 0x6c, 0xf8, 0xa4, 0xad, 0x90, 0x21, 0xfd, 0x56, 0x1f, 0xec,
+ 0x39, 0xac, 0xfc, 0xc9, 0xd8, 0x86, 0xfe, 0x24, 0x3a, 0x51, 0xc6, 0x58,
+ 0x85, 0xf3, 0x01, 0xfa, 0xb0, 0x51, 0x2c, 0x57, 0x79, 0x00, 0x6b, 0x6f,
+ 0x56, 0xd9, 0xc7, 0x09, 0xce, 0xb7, 0xf9, 0xf9, 0x38, 0xf9, 0xe2, 0x7c,
+ 0x6d, 0x3c, 0x4b, 0x1b, 0x8c, 0x1e, 0xb6, 0xd5, 0xf8, 0x27, 0xbc, 0xf1,
+ 0x5d, 0xde, 0x0b, 0xa5, 0x1e, 0x2d, 0xa5, 0x78, 0xf0, 0xe9, 0x88, 0x2c,
+ 0x9f, 0xec, 0x37, 0xf7, 0xc0, 0x86, 0xe9, 0xa7, 0x96, 0x2f, 0x50, 0xc7,
+ 0xa0, 0x31, 0x42, 0x1d, 0x9b, 0x8a, 0xbf, 0xe4, 0x22, 0xd7, 0x9e, 0xf4,
+ 0x19, 0x42, 0x1f, 0x01, 0x9f, 0x8b, 0xb5, 0x38, 0xeb, 0xad, 0xc5, 0x9c,
+ 0x43, 0xfb, 0x7b, 0x06, 0xcf, 0xea, 0x32, 0x16, 0xa3, 0x7f, 0x78, 0x5e,
+ 0x52, 0xf0, 0x91, 0xd0, 0xa3, 0x54, 0x31, 0x97, 0x4a, 0xa9, 0xd5, 0x6f,
+ 0xc1, 0xb6, 0x86, 0xff, 0xae, 0xe9, 0xfa, 0x43, 0xfa, 0x06, 0xfa, 0x9a,
+ 0x82, 0xa9, 0x43, 0x72, 0x3a, 0x9c, 0x21, 0x74, 0x13, 0x4f, 0x1a, 0xd1,
+ 0x4c, 0x16, 0x7c, 0x4d, 0x59, 0x4d, 0xb1, 0x1e, 0x13, 0x44, 0x0c, 0xf4,
+ 0xa9, 0xcb, 0x4e, 0xdf, 0x3f, 0x2d, 0x3b, 0xbe, 0x2e, 0xa8, 0x57, 0xea,
+ 0xc1, 0xf7, 0x11, 0x01, 0xb9, 0x0c, 0xdf, 0x35, 0x57, 0xea, 0x96, 0x06,
+ 0x78, 0xba, 0xe2, 0xf8, 0xb6, 0x66, 0x78, 0xb6, 0xc6, 0x67, 0xba, 0xf1,
+ 0x7c, 0x00, 0x7e, 0x4d, 0xf2, 0x46, 0x02, 0xbf, 0x8b, 0xa4, 0xc9, 0x36,
+ 0xdf, 0xce, 0xb9, 0x66, 0xa2, 0x76, 0x59, 0xda, 0x25, 0x13, 0x43, 0xfc,
+ 0x58, 0xd4, 0x31, 0x56, 0x1f, 0x7c, 0x79, 0x40, 0x0e, 0x96, 0x42, 0xf2,
+ 0xd5, 0x12, 0xe7, 0x95, 0xd6, 0x52, 0xd0, 0x5b, 0x72, 0xb1, 0x09, 0x9d,
+ 0x8f, 0xc3, 0xe7, 0x65, 0xb4, 0x31, 0xf8, 0x9f, 0xdd, 0xd5, 0xaf, 0x68,
+ 0xe9, 0xf3, 0x59, 0x6d, 0xbc, 0xbe, 0x5f, 0xcb, 0x9c, 0x9f, 0xd4, 0x76,
+ 0xb5, 0xf8, 0x22, 0xd1, 0xde, 0xdd, 0x17, 0x9d, 0x38, 0xcd, 0x31, 0xfb,
+ 0xe3, 0x1b, 0xfb, 0xa2, 0x5f, 0x6a, 0xad, 0xbe, 0xa8, 0x1f, 0xbe, 0x28,
+ 0x03, 0x5f, 0x34, 0x7e, 0xdf, 0xbe, 0xa8, 0x5d, 0xdf, 0xd8, 0x17, 0x75,
+ 0xeb, 0x77, 0x7d, 0x11, 0x63, 0xcf, 0xbf, 0xc6, 0xb5, 0x29, 0xdb, 0x76,
+ 0xfa, 0x72, 0x0e, 0xc3, 0x0f, 0x6f, 0x82, 0xac, 0xbb, 0xb8, 0x76, 0x22,
+ 0x05, 0xd8, 0xfd, 0x34, 0xc6, 0xfa, 0x4d, 0xd8, 0xfb, 0xb6, 0x98, 0x65,
+ 0x3e, 0xa1, 0xc6, 0x7d, 0xa7, 0xce, 0xc7, 0x56, 0x75, 0x4e, 0x1e, 0xdf,
+ 0x53, 0xe7, 0xb6, 0xab, 0x73, 0xea, 0xba, 0x53, 0x66, 0xd4, 0xb8, 0x4d,
+ 0x09, 0x3c, 0x26, 0xf0, 0x2a, 0xf2, 0x59, 0x23, 0x11, 0x05, 0x3d, 0x1d,
+ 0xe3, 0x53, 0x5f, 0x31, 0xf0, 0x20, 0xd0, 0x6f, 0xb7, 0xf2, 0x45, 0xbb,
+ 0xa0, 0xf7, 0x65, 0xe7, 0xfe, 0x74, 0x95, 0x69, 0xd1, 0xd5, 0x9e, 0x35,
+ 0xba, 0xea, 0x90, 0xe1, 0x98, 0xaf, 0xa3, 0xcd, 0x92, 0x8c, 0x51, 0x67,
+ 0xf7, 0xa3, 0xab, 0x7f, 0xaa, 0xff, 0xfd, 0xe8, 0xea, 0xb7, 0xee, 0xa1,
+ 0xab, 0x7f, 0xb5, 0x4e, 0x57, 0x96, 0xf9, 0x82, 0x46, 0xda, 0x8c, 0x1f,
+ 0xf4, 0x47, 0xcd, 0x8f, 0x4e, 0x31, 0x7f, 0xa8, 0x73, 0x4d, 0xfb, 0x79,
+ 0x07, 0xd7, 0xf3, 0xa5, 0xa6, 0x61, 0x59, 0x90, 0x1d, 0xd7, 0x34, 0xe5,
+ 0x16, 0x35, 0x3f, 0x4f, 0xfe, 0x11, 0x3b, 0xa6, 0x10, 0x6b, 0x5c, 0x1e,
+ 0xda, 0xa5, 0xbc, 0xc5, 0xed, 0x3f, 0x55, 0x6a, 0xfe, 0x42, 0x4f, 0xbc,
+ 0xdd, 0x4c, 0x8e, 0x58, 0x5e, 0x1c, 0x08, 0xca, 0xd7, 0xaa, 0xd1, 0xac,
+ 0xad, 0x75, 0x4b, 0xfe, 0x41, 0xc4, 0x9e, 0x12, 0xfd, 0xd7, 0xd6, 0x7b,
+ 0xc4, 0xe8, 0x3e, 0x2f, 0x46, 0x57, 0xc1, 0x2b, 0xf3, 0xab, 0xef, 0xbe,
+ 0xd5, 0x08, 0xf1, 0x3b, 0x66, 0xee, 0x93, 0x2f, 0x73, 0x8e, 0x88, 0xf7,
+ 0x8c, 0xfb, 0x16, 0x73, 0x9e, 0x7c, 0x20, 0xd1, 0x25, 0xf9, 0x2d, 0x5c,
+ 0x8f, 0xf4, 0x73, 0xf4, 0x5d, 0xed, 0x1e, 0xdf, 0x7e, 0x8e, 0xa4, 0x78,
+ 0x33, 0x30, 0x65, 0xf4, 0x41, 0x3e, 0x54, 0xe2, 0x3c, 0xde, 0xf2, 0xec,
+ 0x89, 0xb9, 0x82, 0xb4, 0xb9, 0xbe, 0x61, 0x2f, 0x72, 0x01, 0xda, 0x81,
+ 0xaf, 0x73, 0xea, 0x9b, 0x39, 0x82, 0x44, 0x74, 0x8b, 0x39, 0x82, 0x98,
+ 0x46, 0x62, 0x9f, 0x66, 0x43, 0xf7, 0x36, 0x74, 0x6f, 0x43, 0xf7, 0x36,
+ 0x74, 0x9f, 0xac, 0x1f, 0xc6, 0x3d, 0x95, 0x87, 0x80, 0x17, 0x97, 0x7e,
+ 0xda, 0xa5, 0x0f, 0x3e, 0xb7, 0x4a, 0x4e, 0xe9, 0x84, 0xf3, 0x45, 0xae,
+ 0xa1, 0xfc, 0xf5, 0xb8, 0xe6, 0xfa, 0x6b, 0xd2, 0xcb, 0xe0, 0xf9, 0xdb,
+ 0x98, 0xa7, 0xad, 0xeb, 0xd6, 0x5d, 0x99, 0xcc, 0xb5, 0xc8, 0x64, 0xd6,
+ 0xa1, 0x8c, 0xd8, 0x9f, 0x3e, 0x77, 0x5a, 0xaf, 0xac, 0xca, 0x65, 0x2f,
+ 0x78, 0xe8, 0xe0, 0xdc, 0xbd, 0x79, 0x90, 0x7e, 0xaf, 0x47, 0xff, 0x6f,
+ 0xd1, 0x87, 0xfe, 0x75, 0xa3, 0x71, 0x39, 0x26, 0x73, 0xc6, 0x77, 0x9b,
+ 0x0f, 0x72, 0x66, 0xac, 0x81, 0xef, 0x21, 0x96, 0x5f, 0x44, 0x2c, 0x59,
+ 0x31, 0x22, 0xf2, 0x93, 0x47, 0xaf, 0x21, 0x97, 0x96, 0xfc, 0xc3, 0x89,
+ 0x66, 0x24, 0x90, 0x78, 0xab, 0x39, 0x37, 0x82, 0x18, 0x97, 0x88, 0x86,
+ 0x93, 0xc6, 0xb0, 0x5c, 0xaa, 0x0f, 0xca, 0x8f, 0xea, 0x96, 0xfc, 0xb0,
+ 0x1e, 0x91, 0x1f, 0x20, 0xe6, 0x7f, 0xbf, 0xde, 0x9a, 0x73, 0x47, 0x68,
+ 0x4f, 0x3d, 0xe9, 0xfa, 0x46, 0xb9, 0x7f, 0x13, 0x34, 0xde, 0x82, 0x9d,
+ 0x04, 0xb2, 0xc8, 0xf5, 0x19, 0xbf, 0x26, 0x0e, 0x15, 0x9f, 0x6b, 0x82,
+ 0xb7, 0x6c, 0x5b, 0xc2, 0xca, 0xeb, 0x7a, 0xf7, 0xa8, 0xf9, 0x29, 0xb4,
+ 0x39, 0xa3, 0x81, 0x6a, 0xb1, 0x53, 0xe5, 0x8b, 0xd0, 0x91, 0xd8, 0xf5,
+ 0x60, 0xb0, 0x56, 0xbc, 0x85, 0x7e, 0xcd, 0xe6, 0xa1, 0xf8, 0x6f, 0xed,
+ 0x30, 0xff, 0x81, 0x85, 0x35, 0xdd, 0xf9, 0x25, 0x23, 0xb1, 0x49, 0x66,
+ 0x43, 0xdf, 0x6f, 0x98, 0x03, 0x7d, 0x59, 0x3d, 0x11, 0x94, 0x74, 0x91,
+ 0x6b, 0x2a, 0x24, 0xb3, 0x55, 0x28, 0xff, 0x3c, 0xd7, 0x85, 0x3c, 0x3b,
+ 0x17, 0xef, 0x86, 0xed, 0xff, 0x9a, 0xe1, 0xae, 0x03, 0x18, 0x50, 0x75,
+ 0x50, 0xf2, 0xe0, 0x37, 0x5f, 0x7f, 0xcb, 0xc3, 0x0e, 0xf0, 0x2a, 0x5b,
+ 0x21, 0xf8, 0xc4, 0x70, 0xda, 0x76, 0xfe, 0x30, 0x88, 0xb6, 0xe0, 0x56,
+ 0xeb, 0xce, 0x26, 0x7c, 0x3f, 0x10, 0xb2, 0x88, 0x4d, 0x24, 0xf3, 0x05,
+ 0x7c, 0xff, 0x4a, 0x42, 0x36, 0xf7, 0xe2, 0x7b, 0x4b, 0x02, 0x26, 0x99,
+ 0x60, 0xcc, 0xd5, 0x5a, 0x62, 0xae, 0x68, 0x69, 0xc8, 0x6e, 0x0e, 0x73,
+ 0x4f, 0x43, 0x9e, 0x5f, 0xac, 0x07, 0xb5, 0xd4, 0xe9, 0x47, 0xc0, 0x87,
+ 0x9f, 0x3b, 0x23, 0x3f, 0x33, 0x97, 0xb7, 0x04, 0xe4, 0x16, 0x7c, 0x5c,
+ 0x12, 0x7e, 0xcc, 0x46, 0x6e, 0xb1, 0x03, 0xcb, 0x35, 0xfa, 0x5f, 0xbf,
+ 0x20, 0x5f, 0xf3, 0x78, 0x6b, 0x93, 0x05, 0x65, 0xa3, 0x6c, 0xcf, 0x67,
+ 0xfe, 0xcd, 0xc0, 0xdd, 0xf6, 0x17, 0x57, 0xdb, 0xcb, 0x99, 0x7f, 0xb8,
+ 0xda, 0xde, 0xdb, 0xe6, 0xf2, 0x3f, 0xaa, 0x4d, 0xd4, 0xf7, 0x78, 0x6d,
+ 0xb7, 0xa1, 0xb3, 0x66, 0x93, 0xb9, 0x45, 0x01, 0xd8, 0x24, 0x1d, 0xa7,
+ 0x2f, 0xbe, 0x1f, 0x5f, 0xbb, 0xc6, 0xcf, 0x9a, 0x49, 0x83, 0xb6, 0x10,
+ 0x14, 0x97, 0x26, 0xef, 0x77, 0x20, 0x7f, 0xbf, 0x8d, 0xdf, 0x8c, 0xa3,
+ 0x7e, 0x6e, 0xce, 0x3e, 0x7c, 0xfe, 0xcd, 0x7b, 0xd8, 0x4b, 0x08, 0xf6,
+ 0xf2, 0xff, 0xab, 0x5d, 0x5c, 0xba, 0x1f, 0xbb, 0xc0, 0x9f, 0xb2, 0x0b,
+ 0xd5, 0xff, 0xd2, 0xea, 0x5a, 0x09, 0x43, 0x3e, 0x8c, 0x07, 0x83, 0xd0,
+ 0xf1, 0x66, 0x99, 0xb5, 0xc8, 0x8f, 0x15, 0xc9, 0xc1, 0x5f, 0x9e, 0x58,
+ 0x17, 0xbb, 0xbb, 0x10, 0x0f, 0x8e, 0x9f, 0x8e, 0x8e, 0x32, 0x1e, 0xc4,
+ 0xe0, 0x1b, 0x93, 0xef, 0x88, 0x07, 0x37, 0x8c, 0xd6, 0x78, 0x60, 0x20,
+ 0x1e, 0xec, 0x7a, 0x97, 0x78, 0x70, 0xe2, 0x1d, 0xf1, 0x40, 0x83, 0x6c,
+ 0x38, 0xbf, 0xbf, 0x35, 0xfc, 0x78, 0x50, 0x58, 0x13, 0x0f, 0x7c, 0x5d,
+ 0x59, 0x0a, 0x0b, 0xdc, 0xd5, 0x5b, 0x97, 0xa7, 0x2b, 0x09, 0x06, 0x12,
+ 0x8d, 0xcc, 0x9c, 0xf5, 0xb0, 0xb4, 0xc1, 0xe7, 0x5e, 0xaa, 0x8f, 0x40,
+ 0x67, 0x97, 0x30, 0xf7, 0x68, 0x9c, 0x89, 0x65, 0x5b, 0x82, 0xeb, 0xe1,
+ 0xcd, 0x08, 0x30, 0xe2, 0x6e, 0xe0, 0xbe, 0xdd, 0x67, 0xd5, 0xfa, 0x78,
+ 0x33, 0xea, 0x61, 0xf7, 0x6d, 0xc0, 0xee, 0x78, 0x3e, 0x00, 0x4c, 0xc8,
+ 0xf6, 0x2b, 0x66, 0x12, 0x7a, 0xaa, 0x3a, 0xf6, 0xee, 0x02, 0x3e, 0x73,
+ 0xaa, 0xef, 0xad, 0x08, 0xfb, 0x76, 0x24, 0x12, 0xd1, 0x3f, 0xc3, 0x77,
+ 0x7b, 0x22, 0xbc, 0xed, 0xaa, 0x45, 0xba, 0x87, 0xa2, 0x67, 0x15, 0x8d,
+ 0x80, 0x14, 0xd4, 0xb3, 0x91, 0x6d, 0x7c, 0xf6, 0x18, 0x62, 0xf6, 0x51,
+ 0xc7, 0x94, 0x23, 0x4e, 0x76, 0x77, 0x0e, 0x1f, 0x62, 0xd5, 0x4b, 0x25,
+ 0xde, 0x1f, 0xc5, 0xfd, 0x80, 0x30, 0x97, 0xfc, 0x2a, 0xfa, 0x1c, 0x44,
+ 0x9f, 0x19, 0xc7, 0xd7, 0x05, 0xef, 0x37, 0x32, 0x29, 0xdc, 0x9f, 0x29,
+ 0x36, 0x32, 0xe9, 0x22, 0xf3, 0xd6, 0xa1, 0xf0, 0x11, 0xc8, 0x33, 0x8b,
+ 0x5c, 0xcd, 0x96, 0xe8, 0x60, 0x5e, 0x9e, 0xee, 0x1c, 0x07, 0x4e, 0x3a,
+ 0x87, 0x1c, 0xc2, 0x9e, 0x8c, 0xc6, 0xcb, 0xf2, 0xe1, 0xce, 0xe4, 0x69,
+ 0xe4, 0x0b, 0xf1, 0xed, 0x90, 0x61, 0x23, 0xa3, 0xc7, 0x04, 0xb6, 0x1e,
+ 0x87, 0x5f, 0x1e, 0xd1, 0x53, 0xc5, 0x7e, 0x73, 0x56, 0x1e, 0x95, 0x86,
+ 0x19, 0x0d, 0x8f, 0xcb, 0x26, 0x49, 0x05, 0xd0, 0x6f, 0xf0, 0x43, 0x92,
+ 0x0d, 0x53, 0xd6, 0x0f, 0xc2, 0xdf, 0x6b, 0xd2, 0x61, 0xb5, 0xc6, 0x9e,
+ 0x5b, 0x10, 0x6f, 0x2e, 0x40, 0x9f, 0xdd, 0x61, 0x75, 0x7a, 0x3a, 0xd9,
+ 0x24, 0xcb, 0xef, 0xe8, 0x77, 0xbb, 0xa5, 0x5f, 0x6b, 0xfb, 0xdb, 0x68,
+ 0xdf, 0x84, 0x9c, 0xb3, 0x91, 0x09, 0xc4, 0x20, 0x7f, 0xcc, 0xa1, 0x0d,
+ 0x76, 0x72, 0x15, 0xf3, 0x61, 0x1c, 0x2c, 0x94, 0x99, 0xf7, 0x18, 0x52,
+ 0x36, 0x71, 0xcf, 0x69, 0x36, 0x2b, 0x16, 0xf8, 0xbd, 0x40, 0x9e, 0x83,
+ 0x32, 0xee, 0x0c, 0x88, 0x5d, 0xa3, 0x1c, 0xa2, 0xf0, 0x4a, 0x0f, 0x77,
+ 0xa5, 0x16, 0xa3, 0x76, 0x1e, 0x14, 0x8d, 0x0b, 0x7d, 0x5d, 0x49, 0xe4,
+ 0x39, 0xfa, 0x85, 0x48, 0x57, 0x0a, 0x36, 0x6b, 0x5c, 0x78, 0xa8, 0x2b,
+ 0x7d, 0x9a, 0x7c, 0x19, 0xc8, 0x73, 0x3e, 0x0a, 0x9c, 0xdf, 0x94, 0xdf,
+ 0x45, 0x2e, 0x5b, 0x18, 0x44, 0x0e, 0x80, 0xd5, 0xaf, 0x83, 0xef, 0xbc,
+ 0x29, 0xc1, 0xae, 0xc4, 0xab, 0xe0, 0x6f, 0x18, 0xb2, 0xd9, 0x84, 0x3e,
+ 0x06, 0xda, 0x07, 0x58, 0x13, 0x68, 0x69, 0xb7, 0xba, 0x10, 0x4f, 0x11,
+ 0xbb, 0x24, 0x98, 0x1c, 0xe9, 0x06, 0xfd, 0x2b, 0x01, 0xe6, 0x82, 0xc1,
+ 0xd8, 0x6a, 0xfb, 0x37, 0xdd, 0xf6, 0x41, 0xf0, 0xc2, 0xe7, 0x88, 0x09,
+ 0x24, 0x38, 0x35, 0x62, 0x82, 0x07, 0xf6, 0x0d, 0xa9, 0xbe, 0xe9, 0x45,
+ 0xda, 0x40, 0x23, 0x53, 0xb1, 0x1e, 0x91, 0xd4, 0xc2, 0x56, 0x19, 0x5f,
+ 0xe8, 0x95, 0x5d, 0x0b, 0xc4, 0x30, 0xac, 0x69, 0x60, 0x2a, 0xc0, 0x18,
+ 0xfa, 0x05, 0xe6, 0x76, 0xd1, 0xf0, 0x41, 0xe9, 0x0f, 0x7f, 0x15, 0xeb,
+ 0x60, 0xca, 0x8a, 0x45, 0x66, 0xb1, 0xc6, 0x02, 0x8a, 0x4e, 0xd8, 0x1f,
+ 0x93, 0x36, 0xba, 0x66, 0xdc, 0xf4, 0xe2, 0xbd, 0xe8, 0x62, 0xe1, 0x5c,
+ 0x08, 0xaf, 0xa3, 0xfb, 0x57, 0x1e, 0x5d, 0x13, 0x74, 0xfb, 0x40, 0x93,
+ 0x73, 0x7c, 0xa8, 0x73, 0xec, 0xb4, 0xd8, 0x1d, 0xe0, 0x2f, 0x1d, 0x7b,
+ 0x58, 0x66, 0x41, 0xe7, 0xe8, 0x02, 0xfd, 0xa4, 0x6c, 0xc5, 0x67, 0xb8,
+ 0x4d, 0x62, 0x83, 0xe7, 0x81, 0x73, 0xc6, 0x14, 0x0d, 0x17, 0x73, 0xe8,
+ 0x17, 0x12, 0xc0, 0xa9, 0x1f, 0x07, 0x3f, 0xcc, 0xb1, 0x38, 0xe7, 0x00,
+ 0xe6, 0x9b, 0xc0, 0x3a, 0x64, 0x7d, 0x85, 0xeb, 0x1b, 0xbf, 0xcf, 0x87,
+ 0x3b, 0x53, 0xa7, 0xdb, 0xb1, 0xee, 0xe4, 0x11, 0x43, 0xc5, 0x7e, 0xea,
+ 0xc5, 0xea, 0x4c, 0x96, 0x14, 0xdf, 0x9d, 0xa9, 0x12, 0x65, 0x14, 0xef,
+ 0x4c, 0x97, 0x28, 0x23, 0x01, 0x3f, 0x71, 0xd8, 0x64, 0x40, 0x22, 0x5b,
+ 0xa8, 0xc7, 0x43, 0xe8, 0xf7, 0x57, 0x01, 0xe2, 0xb8, 0xa4, 0xc5, 0xdf,
+ 0xf0, 0xb5, 0x17, 0x0e, 0xa3, 0x2f, 0x7f, 0x6f, 0x07, 0xdd, 0xfe, 0xc1,
+ 0x82, 0xb4, 0x0f, 0xce, 0xc0, 0x4f, 0xe8, 0x23, 0xc0, 0x91, 0xca, 0xce,
+ 0x9b, 0xc0, 0xd8, 0x3b, 0x30, 0x1f, 0xac, 0x8d, 0x98, 0x25, 0xd3, 0xf3,
+ 0x94, 0xab, 0x7c, 0x08, 0x73, 0xc0, 0xfc, 0x63, 0xf0, 0x2d, 0x9c, 0x03,
+ 0xc7, 0x16, 0xe4, 0x36, 0x4b, 0x92, 0x9b, 0x0f, 0x2a, 0x2c, 0x6b, 0x9b,
+ 0x1c, 0x5f, 0xd3, 0xf4, 0x44, 0x17, 0x74, 0xcc, 0xb9, 0xcd, 0x81, 0xb7,
+ 0x67, 0x10, 0xff, 0xa2, 0x0a, 0x43, 0x19, 0x17, 0xb8, 0x56, 0x46, 0xb1,
+ 0x4e, 0xc8, 0xbf, 0x67, 0x7b, 0x5a, 0x03, 0x3e, 0x45, 0xf9, 0x7f, 0xe4,
+ 0xea, 0x09, 0xf8, 0x91, 0x51, 0xf9, 0x7d, 0xf8, 0x92, 0x1f, 0xd7, 0xe3,
+ 0xc8, 0x1b, 0x86, 0x91, 0x37, 0x0c, 0x22, 0x6f, 0xb0, 0x90, 0x37, 0x44,
+ 0x90, 0x37, 0xf4, 0x21, 0x6f, 0x08, 0x23, 0x3e, 0x88, 0x1c, 0xad, 0xe7,
+ 0x61, 0x63, 0x0d, 0xf8, 0x41, 0x33, 0x68, 0xd7, 0x43, 0xc1, 0x64, 0x3d,
+ 0x1c, 0x4c, 0xd5, 0x03, 0x98, 0xd3, 0x01, 0x8e, 0x89, 0xf9, 0xe5, 0x3b,
+ 0xc7, 0x4a, 0xc3, 0x88, 0x39, 0x36, 0xfc, 0x52, 0x1a, 0xf1, 0x36, 0x2e,
+ 0x47, 0xf0, 0xcc, 0xf2, 0x7c, 0x04, 0xcf, 0x34, 0x25, 0x1d, 0x6f, 0x93,
+ 0x59, 0x33, 0x0e, 0x1a, 0x5b, 0x94, 0x9d, 0x22, 0xdf, 0x6a, 0x83, 0x9d,
+ 0x4a, 0xae, 0xc8, 0x7c, 0xab, 0x0f, 0xf4, 0x3a, 0x11, 0x97, 0xe9, 0x1f,
+ 0xe8, 0x0b, 0xec, 0xdd, 0x5f, 0xb2, 0xb8, 0xe6, 0xba, 0xb4, 0xe4, 0xe9,
+ 0xbc, 0x10, 0x6b, 0x22, 0x0e, 0xc2, 0x2e, 0xd8, 0x36, 0x81, 0xe7, 0xf8,
+ 0xfb, 0x6d, 0xcf, 0xef, 0x7f, 0x24, 0x28, 0x30, 0xde, 0x4b, 0x8c, 0xf9,
+ 0x16, 0xe8, 0x39, 0xad, 0xeb, 0xb5, 0xa6, 0x8b, 0xe5, 0xdf, 0x67, 0xfd,
+ 0x8d, 0x35, 0xc7, 0xd7, 0xc0, 0x73, 0xbf, 0xb9, 0x8c, 0x1c, 0xd9, 0xde,
+ 0xbf, 0x82, 0xdf, 0xad, 0xfd, 0xeb, 0xe8, 0xaf, 0xda, 0x82, 0x66, 0x22,
+ 0xce, 0x7c, 0x18, 0x3e, 0x73, 0x10, 0xfe, 0xf1, 0x56, 0x46, 0x5f, 0xba,
+ 0x89, 0x79, 0x42, 0x9e, 0xc5, 0x5b, 0x99, 0xc0, 0xc0, 0xb5, 0xe6, 0x8b,
+ 0xc0, 0x37, 0x63, 0x4b, 0x23, 0x92, 0x5a, 0xea, 0x0f, 0x5f, 0x96, 0xce,
+ 0xdb, 0xb6, 0x5c, 0x6b, 0xce, 0x3a, 0xd1, 0xe3, 0xb6, 0x10, 0x6f, 0x99,
+ 0x52, 0x01, 0xa9, 0x6d, 0x3b, 0x3b, 0x88, 0x19, 0x2f, 0x8a, 0x1e, 0x91,
+ 0xe4, 0x29, 0x5b, 0x46, 0x76, 0xfa, 0xb9, 0xfb, 0x9d, 0x0e, 0xe9, 0x42,
+ 0xdb, 0x52, 0x04, 0x7d, 0x88, 0x53, 0x39, 0xef, 0x2c, 0xe6, 0xac, 0xb9,
+ 0xcf, 0x78, 0xf5, 0xc9, 0x42, 0x09, 0x73, 0xaf, 0xdf, 0xca, 0x5c, 0x3e,
+ 0x05, 0xec, 0x0e, 0x1d, 0x25, 0x4f, 0xb1, 0xae, 0xb0, 0x09, 0x72, 0x1a,
+ 0x83, 0xad, 0xd0, 0x06, 0xfa, 0xf1, 0x6c, 0x53, 0xbe, 0x11, 0xa7, 0x5d,
+ 0xbc, 0x04, 0x59, 0x82, 0x56, 0xc0, 0x9f, 0x0f, 0x70, 0xde, 0x3c, 0xe5,
+ 0x17, 0x46, 0x6e, 0xce, 0xb1, 0x25, 0xd8, 0x99, 0x58, 0x9f, 0x77, 0xdf,
+ 0xca, 0x2c, 0x9f, 0x02, 0xfd, 0x01, 0xd6, 0xde, 0xe0, 0xb3, 0x8b, 0xac,
+ 0x1d, 0x32, 0x27, 0xdd, 0x05, 0x3d, 0xed, 0x55, 0xb5, 0xb8, 0x64, 0x35,
+ 0x2e, 0xd6, 0x49, 0xfa, 0x2c, 0x89, 0x18, 0xd6, 0x7e, 0xe4, 0xaf, 0x62,
+ 0xea, 0x89, 0x49, 0xdc, 0xa3, 0x3c, 0x35, 0xe4, 0x1c, 0xb8, 0x7f, 0x61,
+ 0x45, 0xe9, 0xc4, 0x80, 0xee, 0x72, 0x3b, 0x99, 0x84, 0xc9, 0xbc, 0x91,
+ 0x80, 0x2f, 0x1c, 0xe1, 0x1c, 0xd4, 0xd8, 0xc8, 0xc7, 0xb9, 0xfe, 0x30,
+ 0x67, 0xd8, 0x55, 0x4b, 0x5e, 0xae, 0xfe, 0x66, 0x4b, 0x47, 0x60, 0xd3,
+ 0x92, 0x6f, 0x43, 0x3e, 0x90, 0x1c, 0xc1, 0x6f, 0x38, 0x81, 0xa3, 0xd0,
+ 0xe7, 0xd9, 0x11, 0xd6, 0x3f, 0x5f, 0x02, 0xb6, 0x27, 0xdf, 0xb1, 0xc8,
+ 0x11, 0xb5, 0x86, 0x71, 0xed, 0x30, 0x97, 0xdb, 0x24, 0x97, 0xd5, 0xfc,
+ 0x1e, 0x22, 0xf6, 0x80, 0x9e, 0xee, 0x67, 0x7e, 0xe3, 0xf7, 0x39, 0x3f,
+ 0x97, 0x3e, 0x63, 0x57, 0xd2, 0x8a, 0x48, 0xaa, 0x78, 0xa9, 0x19, 0xb0,
+ 0x2c, 0x60, 0x67, 0x57, 0x8f, 0x29, 0x27, 0x08, 0x3e, 0x58, 0x6b, 0xdb,
+ 0xa9, 0x74, 0x09, 0x3e, 0x68, 0x3b, 0xf9, 0x60, 0x62, 0xb3, 0x9c, 0x9b,
+ 0xef, 0x91, 0xca, 0xfc, 0xcf, 0xa5, 0x3a, 0xdf, 0x25, 0xe7, 0xe7, 0x9b,
+ 0x72, 0x35, 0xae, 0x7c, 0x93, 0xd5, 0xae, 0xd6, 0xb5, 0x3c, 0xec, 0xd6,
+ 0x61, 0x62, 0xa3, 0xd7, 0xe5, 0x79, 0x39, 0x57, 0x76, 0x79, 0xcf, 0xb4,
+ 0xf0, 0x7e, 0x15, 0xb6, 0xf6, 0xaa, 0x45, 0xfe, 0x47, 0xa4, 0x52, 0x24,
+ 0xef, 0xfb, 0x14, 0xef, 0xbb, 0x56, 0x79, 0x97, 0xac, 0x61, 0x91, 0xff,
+ 0x8d, 0x78, 0xef, 0x90, 0xec, 0x56, 0xf2, 0x1f, 0xc1, 0xb3, 0xef, 0xb4,
+ 0xbf, 0x8a, 0x73, 0xad, 0xb9, 0x5c, 0x6c, 0x53, 0x3c, 0x1b, 0x89, 0x11,
+ 0xc8, 0xe7, 0x5a, 0xb3, 0xe1, 0x70, 0x1d, 0xe1, 0xb7, 0xf3, 0x2f, 0xe0,
+ 0xab, 0x7a, 0x55, 0xce, 0x92, 0x9b, 0xec, 0xee, 0x4c, 0x2e, 0x8e, 0x42,
+ 0xb7, 0x9d, 0x6a, 0x1d, 0xc2, 0x6d, 0x40, 0x67, 0xff, 0x1e, 0xfd, 0xbf,
+ 0xcd, 0xf5, 0xa6, 0xe4, 0x92, 0x86, 0x5c, 0x0a, 0xc5, 0xf1, 0x76, 0xe0,
+ 0x27, 0x8c, 0xd3, 0xc8, 0x64, 0x1d, 0x3e, 0xd3, 0x07, 0xdf, 0xc6, 0xef,
+ 0xf7, 0x6d, 0x0f, 0x79, 0xf8, 0x5c, 0xe8, 0x1c, 0x79, 0x05, 0xd7, 0xf3,
+ 0x48, 0x03, 0x31, 0x36, 0x36, 0x58, 0x51, 0xfb, 0x10, 0x71, 0x85, 0x85,
+ 0x67, 0x9d, 0x6f, 0xe3, 0xe3, 0x8e, 0x37, 0x56, 0xe7, 0x98, 0x6b, 0xe7,
+ 0x54, 0x70, 0x1a, 0xc8, 0xdf, 0x2d, 0xd0, 0xe5, 0xb8, 0x79, 0x31, 0x12,
+ 0x06, 0xc6, 0x65, 0x5b, 0x37, 0x7c, 0x4c, 0x04, 0x3e, 0x6b, 0x18, 0xbe,
+ 0x9f, 0x6b, 0x99, 0x7e, 0xde, 0xe7, 0x7d, 0x18, 0x34, 0xe9, 0x7f, 0x87,
+ 0x31, 0x67, 0xe6, 0xd8, 0xf4, 0x9f, 0x88, 0x27, 0xb5, 0x70, 0x57, 0xf2,
+ 0xb4, 0x5b, 0x1b, 0x74, 0x7f, 0xf3, 0xbe, 0x04, 0x1f, 0x49, 0x44, 0xcb,
+ 0x79, 0xe4, 0x7e, 0x29, 0xac, 0xd1, 0xa4, 0x85, 0x3c, 0xbb, 0x16, 0x7d,
+ 0x85, 0x98, 0x5b, 0xa7, 0x0c, 0x96, 0x28, 0x27, 0xd6, 0xa9, 0x4c, 0xc9,
+ 0x57, 0xbe, 0x0b, 0x79, 0x04, 0x65, 0x8b, 0x95, 0x85, 0x4f, 0x01, 0xff,
+ 0x98, 0xfb, 0x5c, 0x89, 0xb5, 0xc8, 0x7e, 0xc4, 0x31, 0x03, 0x42, 0x40,
+ 0x4e, 0xb5, 0x64, 0xc8, 0x67, 0x03, 0x43, 0xc8, 0x01, 0x9f, 0x45, 0xdf,
+ 0x80, 0xe4, 0x97, 0x18, 0x0f, 0x02, 0x32, 0xb7, 0x24, 0x72, 0xfd, 0x14,
+ 0xfd, 0x8a, 0xfa, 0x83, 0xcc, 0x1b, 0x99, 0x69, 0x62, 0xed, 0x79, 0xfa,
+ 0x18, 0xfa, 0x89, 0x07, 0xa1, 0x8b, 0xd8, 0x4b, 0xdf, 0x40, 0x6c, 0x9a,
+ 0x2d, 0xf6, 0xc3, 0x67, 0x4a, 0x43, 0x87, 0x4c, 0x11, 0xd3, 0x98, 0xa3,
+ 0x6f, 0x50, 0x77, 0xf4, 0x6b, 0x8e, 0x41, 0x29, 0x9c, 0x62, 0xbd, 0x31,
+ 0x08, 0x5e, 0x98, 0xb7, 0x1a, 0x2a, 0x0f, 0x7a, 0x50, 0xf9, 0x56, 0x7e,
+ 0x07, 0x5a, 0xc6, 0x8d, 0x1d, 0xdf, 0xa6, 0xd3, 0x8f, 0x3d, 0x22, 0xf6,
+ 0xc4, 0xa1, 0xce, 0x5d, 0xa5, 0x76, 0x29, 0xf7, 0xd2, 0x2e, 0xa9, 0xff,
+ 0xac, 0x4e, 0x5f, 0x8b, 0x3c, 0x0c, 0xf4, 0x58, 0x23, 0x08, 0xa0, 0x5f,
+ 0xc8, 0xeb, 0x47, 0xb9, 0xfe, 0xb6, 0x4c, 0xed, 0xfc, 0x3b, 0xf0, 0xe5,
+ 0xfa, 0xb5, 0xdc, 0x4e, 0xf8, 0xdb, 0x09, 0x5d, 0x1e, 0xfb, 0x54, 0x1a,
+ 0xcf, 0x32, 0x16, 0xde, 0xf2, 0xf0, 0x38, 0xdb, 0x58, 0xa3, 0x45, 0x9e,
+ 0x7e, 0xce, 0xc4, 0x77, 0xaf, 0xe4, 0xcf, 0x05, 0x21, 0x07, 0xe4, 0xc4,
+ 0x15, 0x97, 0x16, 0xf3, 0xde, 0xe3, 0xd0, 0x91, 0x7e, 0x32, 0x28, 0x6d,
+ 0x27, 0x7b, 0x25, 0xf0, 0xad, 0x2e, 0x69, 0xff, 0xd6, 0x80, 0x18, 0xdf,
+ 0x62, 0x2d, 0x29, 0x1a, 0x39, 0xaa, 0xea, 0x58, 0x69, 0x39, 0x86, 0xf8,
+ 0xa5, 0x23, 0x16, 0x2b, 0x3b, 0x35, 0xb7, 0x8a, 0x81, 0xc4, 0x55, 0x7f,
+ 0xc1, 0x96, 0xaf, 0xef, 0xfc, 0x85, 0xaa, 0xa3, 0x26, 0x47, 0x70, 0xfd,
+ 0x72, 0x06, 0xd8, 0x44, 0x83, 0xad, 0x34, 0x32, 0xd7, 0x1e, 0xf5, 0x73,
+ 0xcb, 0x41, 0x55, 0x93, 0xff, 0xfa, 0x4e, 0x37, 0xb7, 0x9c, 0x45, 0x6e,
+ 0x99, 0x56, 0xb9, 0x25, 0xfc, 0x6b, 0x80, 0xfd, 0xb6, 0x8a, 0x8e, 0xb1,
+ 0x72, 0xc2, 0x5c, 0xfd, 0xa3, 0x62, 0x1f, 0xc0, 0xba, 0x38, 0x23, 0xf3,
+ 0x7a, 0x42, 0x53, 0x34, 0x8d, 0x17, 0xe8, 0xa7, 0xe8, 0xbf, 0x68, 0xe3,
+ 0xac, 0x69, 0xa1, 0xed, 0x65, 0xfa, 0x28, 0xd7, 0xb6, 0xc7, 0x5a, 0x7c,
+ 0xdd, 0x5c, 0xa9, 0x0e, 0x1d, 0x22, 0xa7, 0xb7, 0xda, 0x30, 0x7f, 0xc4,
+ 0x74, 0x8b, 0xd7, 0x9c, 0x3f, 0x7c, 0x67, 0x28, 0xa4, 0xae, 0x0b, 0x65,
+ 0xb7, 0x86, 0xe1, 0xd2, 0x67, 0xfe, 0x01, 0x1f, 0x53, 0x27, 0x1f, 0x1c,
+ 0xb7, 0x4f, 0x8c, 0x33, 0x21, 0x09, 0x9c, 0xa1, 0xfd, 0x45, 0x23, 0x69,
+ 0xc8, 0x6f, 0xce, 0x22, 0x06, 0x3c, 0x04, 0x6c, 0xf4, 0x88, 0xe8, 0xe7,
+ 0x06, 0xb1, 0x76, 0xa2, 0xe1, 0xb2, 0xc4, 0xc4, 0xa8, 0x04, 0xe5, 0x8d,
+ 0x53, 0xd1, 0x08, 0xed, 0xe5, 0x2c, 0xe2, 0xd5, 0x91, 0x7a, 0xe7, 0xed,
+ 0x86, 0xe2, 0x82, 0x6d, 0xdf, 0x08, 0x00, 0x3b, 0x0c, 0xda, 0x7a, 0xb7,
+ 0xdc, 0x80, 0xbe, 0xb3, 0xaa, 0xed, 0x11, 0xd0, 0x05, 0x0f, 0x67, 0x58,
+ 0x1b, 0x24, 0xdd, 0xa3, 0xa0, 0x49, 0xda, 0x8d, 0xcc, 0x32, 0x73, 0xd3,
+ 0x53, 0xb4, 0xdd, 0x5e, 0xd8, 0x1d, 0xae, 0xeb, 0xed, 0x92, 0x9d, 0x8c,
+ 0x88, 0x7e, 0x6a, 0x8f, 0xf4, 0xef, 0xd4, 0xdd, 0xf9, 0xa8, 0x39, 0xb2,
+ 0x8d, 0x35, 0xe7, 0x11, 0xb5, 0x1e, 0xf5, 0x25, 0xd8, 0xcc, 0x3e, 0xea,
+ 0x18, 0xb1, 0x1f, 0x71, 0x8c, 0x7e, 0xcc, 0x40, 0x1c, 0x4b, 0xd5, 0x5d,
+ 0xbd, 0x97, 0xf7, 0x6d, 0x95, 0x63, 0x67, 0x68, 0x4f, 0xb8, 0xb7, 0x6a,
+ 0x53, 0xfe, 0xde, 0x10, 0xef, 0x59, 0x72, 0xfc, 0x45, 0xe6, 0x1e, 0xcc,
+ 0x39, 0x98, 0x67, 0x45, 0xc3, 0xbb, 0x30, 0x1f, 0xfd, 0x31, 0xfa, 0x03,
+ 0x5d, 0xd9, 0x6e, 0x0e, 0x3e, 0xba, 0x50, 0xa7, 0xde, 0x86, 0xb9, 0x7f,
+ 0x66, 0x32, 0x5f, 0xb3, 0xc3, 0xae, 0xbc, 0x0b, 0x68, 0x9b, 0x85, 0xef,
+ 0x4f, 0x39, 0x6d, 0xb2, 0x32, 0x69, 0x43, 0xf7, 0x5f, 0x02, 0x5f, 0x07,
+ 0x3a, 0x59, 0x23, 0x58, 0x99, 0x4c, 0xe3, 0xfa, 0x80, 0xca, 0xd1, 0x8c,
+ 0xc7, 0x6c, 0xd0, 0xd8, 0xca, 0x75, 0xe4, 0xe9, 0x29, 0xae, 0x17, 0xe6,
+ 0x1f, 0xd3, 0x67, 0xe1, 0xb3, 0xc7, 0xe3, 0x8c, 0xf1, 0xdc, 0x4b, 0xe8,
+ 0x00, 0x1f, 0xdd, 0x0a, 0x57, 0xe8, 0xd6, 0x4e, 0xbd, 0x50, 0xa6, 0x9f,
+ 0xcf, 0x87, 0xdb, 0x85, 0x78, 0xc4, 0xd4, 0x2b, 0x16, 0x75, 0xa2, 0xc9,
+ 0x65, 0xb5, 0xef, 0x20, 0x92, 0x76, 0x0e, 0x61, 0xac, 0xb8, 0x5e, 0x2d,
+ 0xef, 0xd4, 0xf3, 0x65, 0x43, 0x56, 0x42, 0xe4, 0x3b, 0xa2, 0xf2, 0xf8,
+ 0x9d, 0xca, 0xd6, 0x8a, 0x88, 0x25, 0xb0, 0x99, 0xf8, 0x87, 0x31, 0xae,
+ 0x6a, 0x83, 0x4d, 0x51, 0xf7, 0xd4, 0xbb, 0xf2, 0x91, 0x9e, 0xee, 0x37,
+ 0x8a, 0x99, 0x45, 0xf8, 0x5f, 0xd6, 0x2f, 0x3a, 0xbc, 0x5a, 0xe3, 0x4b,
+ 0x5e, 0x3e, 0xf4, 0x8c, 0x30, 0x4f, 0x99, 0x2b, 0x91, 0x97, 0x22, 0xfc,
+ 0xe1, 0x46, 0xb6, 0x44, 0x39, 0xba, 0x3e, 0xe5, 0x10, 0xec, 0x42, 0x5f,
+ 0x32, 0x3d, 0x1b, 0xe0, 0xdf, 0x28, 0xee, 0x31, 0x06, 0xe0, 0xbb, 0xde,
+ 0x86, 0xf5, 0xbe, 0x17, 0x32, 0xa2, 0x6e, 0xa0, 0xbf, 0x25, 0xee, 0xbb,
+ 0x42, 0x7f, 0x4b, 0x57, 0xde, 0xb6, 0x7b, 0xe9, 0xf3, 0x46, 0xe4, 0x18,
+ 0xfc, 0xe8, 0xd1, 0x45, 0xf2, 0x93, 0xf6, 0x70, 0xd9, 0x30, 0x64, 0x42,
+ 0x1f, 0x3f, 0x2c, 0x6f, 0xd4, 0x7e, 0xa0, 0x70, 0xe0, 0xb6, 0x9d, 0x0d,
+ 0x99, 0x86, 0x7f, 0x98, 0x71, 0x20, 0x7f, 0x33, 0x82, 0xf5, 0x19, 0x56,
+ 0xfe, 0x71, 0xe6, 0xfd, 0xe5, 0x24, 0x01, 0x37, 0x66, 0x7f, 0xf6, 0x3e,
+ 0x63, 0xf6, 0x03, 0xc0, 0x61, 0xef, 0x8b, 0xbe, 0xe1, 0xd2, 0xff, 0x33,
+ 0xe8, 0xea, 0xd7, 0x55, 0xfd, 0x22, 0xb7, 0x73, 0x2b, 0x65, 0xfa, 0x5e,
+ 0xcf, 0xe9, 0xee, 0x73, 0x9f, 0xbb, 0x4f, 0xbe, 0x4c, 0xa9, 0x01, 0x2b,
+ 0xe4, 0x55, 0x1c, 0x65, 0xae, 0xd8, 0xe6, 0xe9, 0x6f, 0x10, 0x18, 0x9a,
+ 0x74, 0x7d, 0xdf, 0xdb, 0x21, 0xf9, 0x5e, 0x3f, 0xff, 0x84, 0xcf, 0x5e,
+ 0x6d, 0xf7, 0xf3, 0x59, 0x3e, 0xbf, 0x92, 0x41, 0xfe, 0x0c, 0x1b, 0x60,
+ 0x2c, 0x60, 0x5b, 0x5c, 0xf9, 0xa1, 0x77, 0xe7, 0x9b, 0xf5, 0x0b, 0xf2,
+ 0xbd, 0x5b, 0xf1, 0x9d, 0x56, 0x7c, 0xb3, 0x06, 0xb9, 0x5f, 0x4b, 0x9d,
+ 0x67, 0x1d, 0xd2, 0xaf, 0x3b, 0x92, 0x1e, 0xb0, 0x01, 0xf4, 0xfd, 0x63,
+ 0xd0, 0xfd, 0x11, 0xf4, 0xfa, 0xc3, 0x12, 0xb0, 0x41, 0x09, 0xd8, 0xa0,
+ 0x04, 0x6c, 0x50, 0x02, 0x36, 0x28, 0x85, 0xbd, 0x3a, 0x8b, 0x4d, 0x6c,
+ 0xff, 0x3e, 0x6d, 0xd7, 0xaf, 0x6d, 0xac, 0xb7, 0x4b, 0xb7, 0xb6, 0x99,
+ 0xaa, 0xfb, 0x18, 0x39, 0xc8, 0x5a, 0x2b, 0xb0, 0x9a, 0x5f, 0xf7, 0xf0,
+ 0x62, 0x44, 0x8d, 0xfb, 0x5e, 0x88, 0x11, 0x35, 0x1b, 0xeb, 0x66, 0x28,
+ 0x6c, 0x00, 0x1b, 0x1a, 0x12, 0xc6, 0x6f, 0x13, 0xbe, 0x17, 0xb4, 0x86,
+ 0xfb, 0xb1, 0x92, 0xda, 0x55, 0x5d, 0xef, 0x88, 0xaa, 0x3b, 0x58, 0x32,
+ 0x5b, 0xf6, 0x73, 0xb7, 0x98, 0x8c, 0xcd, 0x13, 0x6f, 0xca, 0x16, 0x3d,
+ 0x01, 0x1d, 0x38, 0xc4, 0x88, 0xdc, 0x27, 0xe4, 0xf8, 0xb1, 0xc1, 0x2a,
+ 0xc6, 0x2c, 0x58, 0x2e, 0x7f, 0x47, 0x9c, 0xbb, 0xcf, 0xec, 0x82, 0x7f,
+ 0xce, 0x14, 0x23, 0x32, 0x5e, 0x74, 0x31, 0x01, 0xf2, 0x9f, 0x75, 0xf5,
+ 0xe5, 0x5b, 0xd0, 0xc3, 0xad, 0xcc, 0x94, 0xb5, 0x6a, 0x1b, 0x91, 0xcb,
+ 0x71, 0xca, 0x98, 0xfa, 0xdf, 0xab, 0xf6, 0x29, 0x76, 0x55, 0xdd, 0xbd,
+ 0xa4, 0x71, 0x65, 0x0b, 0x01, 0xfa, 0x19, 0xd0, 0x89, 0xbb, 0x6b, 0x18,
+ 0x76, 0x91, 0x73, 0x7c, 0xb9, 0xb4, 0xe2, 0x91, 0x2f, 0x6a, 0x62, 0x6d,
+ 0xd4, 0xfe, 0x1b, 0x2d, 0xed, 0xab, 0xf7, 0x3d, 0x7e, 0xe1, 0xfb, 0x56,
+ 0x6b, 0x0d, 0xf4, 0x53, 0x77, 0xdb, 0x81, 0xdd, 0x24, 0xa0, 0xee, 0xc3,
+ 0x87, 0xd7, 0x42, 0x92, 0xaa, 0x59, 0x92, 0x2e, 0xb3, 0x1f, 0xeb, 0x17,
+ 0xf4, 0x47, 0x7f, 0x22, 0x29, 0xe4, 0xab, 0xd9, 0x50, 0x34, 0x6e, 0xcb,
+ 0x7f, 0x96, 0xe5, 0x85, 0x7c, 0x84, 0xe7, 0x0a, 0xf2, 0x13, 0x1a, 0x9e,
+ 0xfb, 0x19, 0xae, 0xc9, 0xb3, 0x25, 0x33, 0x45, 0xc6, 0x9d, 0xa1, 0x70,
+ 0x0d, 0xf7, 0xb2, 0x93, 0xac, 0xd9, 0x7c, 0x07, 0x36, 0x19, 0x8d, 0x94,
+ 0xa1, 0xef, 0x2b, 0x45, 0x8e, 0x07, 0x6c, 0x54, 0x64, 0x5d, 0xc7, 0xbf,
+ 0xff, 0x27, 0xc0, 0x81, 0xf0, 0xd5, 0x21, 0xaf, 0x8f, 0x9a, 0xab, 0x6d,
+ 0x06, 0x60, 0xe3, 0x0d, 0xcf, 0xdf, 0x56, 0x8a, 0x6e, 0x1d, 0xe5, 0x2c,
+ 0xf9, 0x70, 0xfe, 0x77, 0xb3, 0x11, 0x42, 0x0e, 0xb4, 0x3a, 0xc7, 0xab,
+ 0xa4, 0x6f, 0xc2, 0xdd, 0xca, 0x51, 0xc7, 0x97, 0x05, 0xef, 0xb3, 0x8d,
+ 0x67, 0x27, 0x9a, 0xcd, 0xb3, 0xd6, 0x07, 0xad, 0x99, 0xf5, 0x6d, 0x4f,
+ 0x5a, 0xf9, 0xdd, 0x15, 0x27, 0xef, 0xd5, 0xcc, 0xbe, 0xbd, 0xc3, 0xad,
+ 0x99, 0xd5, 0x76, 0xac, 0xad, 0x99, 0x59, 0xdb, 0xdd, 0x9a, 0xd9, 0xfc,
+ 0xee, 0x02, 0x3e, 0x6e, 0xcd, 0x2c, 0xbb, 0xdd, 0xad, 0x99, 0x95, 0xb7,
+ 0xbb, 0x35, 0x33, 0x67, 0x87, 0x5b, 0x33, 0xfb, 0xf9, 0xf6, 0xb5, 0x35,
+ 0xb3, 0x1f, 0xec, 0x58, 0x5b, 0x33, 0xbb, 0xb8, 0x3b, 0x87, 0xcf, 0xdd,
+ 0x9a, 0xd9, 0xcf, 0x76, 0xdc, 0xbb, 0x66, 0xf6, 0x9a, 0x8f, 0xd7, 0x31,
+ 0x9f, 0x11, 0xcc, 0x21, 0x0e, 0xbc, 0x3e, 0x0c, 0xbc, 0xfe, 0x6e, 0x75,
+ 0xfe, 0x00, 0xe6, 0x39, 0xe8, 0xc5, 0x83, 0x0f, 0x82, 0xdb, 0x47, 0xbc,
+ 0x67, 0x6d, 0xe4, 0xbb, 0x11, 0x2f, 0x57, 0x21, 0x76, 0xdf, 0xec, 0xe5,
+ 0x6c, 0xff, 0xa8, 0xf3, 0xee, 0xb9, 0x97, 0xd6, 0xef, 0x0f, 0x21, 0xf5,
+ 0xf6, 0xf1, 0x3c, 0xe7, 0x95, 0x47, 0xee, 0x47, 0x39, 0xd8, 0xe8, 0x3f,
+ 0xbf, 0xfb, 0x1b, 0x16, 0x31, 0xfe, 0x73, 0x58, 0xab, 0xf6, 0x16, 0x43,
+ 0x9d, 0x01, 0x60, 0x8c, 0x3a, 0x2e, 0x29, 0xf4, 0x4f, 0xa9, 0xfe, 0xd7,
+ 0x5a, 0xfa, 0xaf, 0xa0, 0x3f, 0xe9, 0x46, 0xff, 0x1d, 0x3e, 0x2f, 0x29,
+ 0xfb, 0xb6, 0x5c, 0x0c, 0x9f, 0x2e, 0xf9, 0x78, 0x2b, 0xe0, 0x61, 0xe7,
+ 0x46, 0xc6, 0x76, 0x3e, 0x8f, 0x67, 0xa2, 0x17, 0x6d, 0xb9, 0xa9, 0xf0,
+ 0xbb, 0x91, 0x88, 0x5e, 0xcc, 0xaa, 0x7c, 0xad, 0x91, 0xc9, 0x39, 0x7e,
+ 0xfe, 0x8d, 0x1c, 0x6a, 0x80, 0x39, 0x0c, 0xec, 0x7d, 0x69, 0x10, 0x71,
+ 0xac, 0x35, 0xc7, 0x66, 0x5e, 0xad, 0x7b, 0x79, 0xb5, 0x29, 0x9f, 0xd9,
+ 0xd9, 0x8a, 0xcd, 0x2f, 0xee, 0xfe, 0xc7, 0x0a, 0x9b, 0x6f, 0x42, 0x6e,
+ 0x4e, 0xec, 0x4d, 0x1c, 0x43, 0x0c, 0x41, 0x7c, 0xce, 0x7a, 0x01, 0xf3,
+ 0x19, 0xc6, 0x46, 0xe6, 0x37, 0x21, 0x7c, 0x78, 0x26, 0xc9, 0xc7, 0xe8,
+ 0xed, 0x9e, 0x7f, 0x67, 0x5e, 0xe4, 0x63, 0x95, 0xe4, 0x26, 0x37, 0x37,
+ 0xda, 0xa4, 0xb9, 0xf9, 0x67, 0xc4, 0xeb, 0x13, 0x58, 0xc5, 0xc2, 0x81,
+ 0x55, 0x2c, 0xbc, 0x66, 0x1f, 0x4b, 0xd4, 0xf9, 0x27, 0xb5, 0x1f, 0xc6,
+ 0xfd, 0xb1, 0x46, 0xe6, 0xca, 0x80, 0x68, 0x7a, 0x82, 0xfb, 0x64, 0xc0,
+ 0x3a, 0x16, 0xf7, 0xcd, 0xe8, 0x3b, 0xf7, 0x69, 0xa9, 0x2a, 0xe3, 0x0f,
+ 0xf1, 0x91, 0xbf, 0x17, 0xee, 0xeb, 0x89, 0xb2, 0x63, 0xdb, 0x1f, 0x6b,
+ 0xc8, 0x79, 0xe3, 0xed, 0xd6, 0x53, 0xe0, 0x25, 0x83, 0x6f, 0x5f, 0xa6,
+ 0x9f, 0x55, 0xb1, 0xaf, 0x03, 0xb6, 0x7b, 0xa4, 0x44, 0xec, 0xba, 0x59,
+ 0x6a, 0x1e, 0x7e, 0x3d, 0x37, 0xef, 0x62, 0xd7, 0xc0, 0x5a, 0xec, 0x1a,
+ 0x5f, 0x16, 0x97, 0xc7, 0x5d, 0x1b, 0xf2, 0x48, 0xbc, 0x4a, 0xfe, 0x18,
+ 0x77, 0xf6, 0xc2, 0xff, 0x35, 0x80, 0x69, 0x19, 0x73, 0x18, 0x6f, 0x22,
+ 0xc0, 0xf6, 0xf7, 0xe2, 0x4f, 0xb5, 0x1d, 0xea, 0xb0, 0x82, 0xf8, 0x4c,
+ 0xc3, 0x7f, 0x4c, 0xe0, 0x99, 0x8c, 0xcc, 0x9e, 0xfe, 0x1a, 0xe6, 0x36,
+ 0x2d, 0x57, 0xe6, 0x27, 0xc1, 0xdf, 0x73, 0x32, 0x17, 0xcf, 0xc3, 0x8f,
+ 0x70, 0xcf, 0x83, 0xb8, 0xad, 0xdf, 0xfb, 0x9e, 0xd6, 0xcf, 0x5a, 0x51,
+ 0xe2, 0x46, 0xa9, 0x16, 0xe9, 0x83, 0xb9, 0x67, 0xc8, 0xbd, 0x61, 0xda,
+ 0x0f, 0xeb, 0x27, 0xc8, 0x5d, 0x99, 0xc3, 0x9e, 0xe2, 0xf8, 0x6b, 0x75,
+ 0xb2, 0xec, 0x10, 0x7f, 0x35, 0x32, 0x8d, 0x25, 0xe2, 0xc7, 0xf7, 0x8b,
+ 0x25, 0xa9, 0x07, 0xe2, 0xc9, 0xfb, 0xc1, 0x91, 0xd1, 0x79, 0x60, 0xc8,
+ 0x57, 0x1a, 0x7a, 0x2b, 0x8e, 0x74, 0x31, 0x64, 0x72, 0x29, 0x0b, 0x9a,
+ 0x71, 0x85, 0x95, 0x91, 0xc7, 0xc1, 0xed, 0xf5, 0xe3, 0xd9, 0x7e, 0xe4,
+ 0xe4, 0x2e, 0x66, 0x4c, 0x01, 0x33, 0xfe, 0x06, 0x30, 0xe3, 0xac, 0x74,
+ 0x76, 0x11, 0x33, 0xda, 0x1e, 0x66, 0x4c, 0xc3, 0x9e, 0x73, 0x6b, 0xec,
+ 0x59, 0x53, 0xb5, 0x28, 0xde, 0xcb, 0x01, 0xf3, 0xa5, 0x4e, 0x45, 0xef,
+ 0x03, 0x27, 0x6a, 0x12, 0x52, 0xe7, 0x52, 0x02, 0x2d, 0x34, 0x7d, 0x3c,
+ 0xb8, 0x4d, 0xe1, 0xbc, 0xdd, 0xa5, 0x4d, 0xc8, 0x51, 0x14, 0xee, 0xf3,
+ 0xf6, 0x4b, 0x03, 0xeb, 0xf6, 0x90, 0x03, 0x2d, 0x7b, 0xc8, 0x77, 0xf1,
+ 0x21, 0x9e, 0xf3, 0x6a, 0x7d, 0x6d, 0xf0, 0x05, 0xff, 0x13, 0x3c, 0x71,
+ 0x7d, 0x71, 0x2d, 0x68, 0xee, 0x7a, 0x59, 0x83, 0x13, 0xff, 0x7a, 0x1d,
+ 0x4e, 0x44, 0xec, 0x3a, 0x17, 0x92, 0x24, 0x30, 0xa2, 0xbd, 0x44, 0x5a,
+ 0x5c, 0xd3, 0xc3, 0xd2, 0x8e, 0xf9, 0x75, 0x9c, 0xea, 0x05, 0x36, 0xea,
+ 0x92, 0x20, 0x30, 0x52, 0x9b, 0xc2, 0x48, 0x03, 0xc4, 0x32, 0x83, 0x33,
+ 0xc0, 0x36, 0xb5, 0x55, 0x9c, 0x14, 0x8d, 0xff, 0x01, 0xf4, 0xf2, 0x94,
+ 0xf2, 0x3d, 0x69, 0x39, 0x01, 0x5f, 0xda, 0xbe, 0x04, 0x7c, 0x77, 0xce,
+ 0xc5, 0x4f, 0x6d, 0xeb, 0xf0, 0xd3, 0xc1, 0x0d, 0xf1, 0x93, 0xaa, 0xdf,
+ 0x8f, 0x52, 0x26, 0x37, 0x1c, 0xb7, 0x7e, 0x7f, 0xdd, 0x71, 0xeb, 0xf7,
+ 0x37, 0x9c, 0xd6, 0xfa, 0xfd, 0x47, 0xa4, 0x60, 0x46, 0xed, 0x15, 0x59,
+ 0x57, 0xbf, 0x9f, 0x60, 0x3d, 0xdc, 0xe9, 0x72, 0xeb, 0xf4, 0x5d, 0x5e,
+ 0xfd, 0x3e, 0x2a, 0x85, 0x35, 0xed, 0xa6, 0xbc, 0x69, 0xf9, 0xf5, 0xfb,
+ 0xef, 0xa2, 0xad, 0x1b, 0x63, 0xac, 0xad, 0xdd, 0x5f, 0x77, 0x58, 0xbb,
+ 0x0f, 0xb1, 0x9f, 0x57, 0xbb, 0x67, 0x3f, 0xe4, 0xf2, 0x0e, 0xeb, 0xf6,
+ 0x8f, 0x40, 0x16, 0x5b, 0x21, 0x87, 0x5e, 0x69, 0x3f, 0x13, 0x66, 0x1f,
+ 0x55, 0xaf, 0x5f, 0x71, 0x42, 0x78, 0xce, 0xad, 0xab, 0xcf, 0xc0, 0xae,
+ 0x0e, 0xae, 0xd6, 0xeb, 0xdd, 0x31, 0x6e, 0x3a, 0x6b, 0xe9, 0xaf, 0xa5,
+ 0xd3, 0xe7, 0xd1, 0x09, 0x81, 0x4e, 0x78, 0x1d, 0x9d, 0xbb, 0xf5, 0xf9,
+ 0x9b, 0x8e, 0x5b, 0x9b, 0x4f, 0x9f, 0x16, 0xbb, 0x1d, 0xbe, 0xf9, 0xe2,
+ 0xc0, 0xc3, 0x1e, 0x8d, 0xd5, 0xda, 0x3c, 0x7d, 0x08, 0x70, 0x7b, 0x4c,
+ 0x9d, 0xbd, 0x9a, 0xf9, 0x7f, 0x50, 0x9b, 0x67, 0x5d, 0xde, 0xdd, 0x5f,
+ 0xe1, 0xfa, 0x04, 0x3e, 0x7f, 0xd1, 0xad, 0xc9, 0x8f, 0x95, 0xfc, 0x5a,
+ 0x3b, 0xf3, 0x47, 0xff, 0x5c, 0x54, 0x7f, 0xe4, 0x88, 0xd0, 0x56, 0xc8,
+ 0x1f, 0xe9, 0x76, 0xcb, 0x94, 0xc2, 0x47, 0xb0, 0xa9, 0xd8, 0xbd, 0x31,
+ 0x72, 0xe5, 0x94, 0x8f, 0x91, 0x43, 0x0a, 0x23, 0x57, 0x96, 0x7c, 0x8c,
+ 0x9c, 0xbc, 0x07, 0x46, 0x6e, 0x76, 0xb9, 0x71, 0x20, 0x28, 0x79, 0x85,
+ 0x91, 0xef, 0x75, 0x96, 0x8c, 0xf7, 0xba, 0x88, 0x07, 0xc4, 0x3d, 0x5f,
+ 0xd0, 0x7b, 0x8f, 0xb5, 0xe6, 0xe3, 0x66, 0xc6, 0xfe, 0xad, 0x32, 0x71,
+ 0xe6, 0x2e, 0x6e, 0x76, 0xb1, 0x71, 0x34, 0x72, 0x48, 0xc5, 0x44, 0xe0,
+ 0x84, 0x3a, 0xeb, 0xdf, 0xc4, 0xbe, 0x8c, 0x39, 0x01, 0x85, 0xcf, 0x72,
+ 0x45, 0xe6, 0x01, 0x6c, 0x23, 0x16, 0xee, 0xe4, 0x31, 0x2b, 0x2f, 0x26,
+ 0xf9, 0x58, 0xd3, 0x3f, 0xd7, 0xc2, 0x3d, 0x86, 0x37, 0x8d, 0xa4, 0x85,
+ 0x76, 0xc7, 0xcf, 0x15, 0xe2, 0xea, 0x3c, 0x50, 0x12, 0x58, 0x72, 0x6a,
+ 0x15, 0x4b, 0xd2, 0x57, 0xfc, 0xf4, 0x6d, 0xdb, 0xa4, 0x5f, 0xf3, 0xb1,
+ 0x22, 0x72, 0xa2, 0x12, 0xd7, 0xb6, 0x8f, 0x15, 0x5d, 0x9c, 0x98, 0x72,
+ 0x1a, 0xc0, 0xcb, 0x01, 0x19, 0x03, 0x4e, 0x6f, 0x7c, 0x89, 0x35, 0x28,
+ 0x1f, 0x1b, 0xd9, 0xf8, 0x6e, 0xad, 0x49, 0xf1, 0xba, 0x5d, 0xed, 0x05,
+ 0x5e, 0x1e, 0x08, 0xb6, 0xb4, 0x3f, 0x0b, 0xff, 0x8d, 0xfc, 0x08, 0xd8,
+ 0xc4, 0xc5, 0x44, 0x3b, 0xa0, 0x83, 0x91, 0x7b, 0x60, 0xa2, 0xf5, 0x31,
+ 0x8a, 0x31, 0xf3, 0x6e, 0x8c, 0x4a, 0xd7, 0xe9, 0xcf, 0xef, 0xc6, 0xa8,
+ 0x7b, 0xc7, 0x50, 0xb6, 0x61, 0x76, 0x56, 0x06, 0x9f, 0x69, 0x29, 0xac,
+ 0x8b, 0x51, 0x73, 0x1f, 0x20, 0x46, 0xb9, 0xf8, 0xc0, 0xe5, 0xfb, 0xf7,
+ 0x21, 0x9b, 0x1f, 0x43, 0xa6, 0x3f, 0x02, 0xe6, 0xfa, 0x21, 0xe6, 0xf5,
+ 0x03, 0xe0, 0xa1, 0xef, 0x97, 0xd6, 0x9f, 0x07, 0x19, 0x15, 0xe6, 0x87,
+ 0x2e, 0x66, 0x72, 0x31, 0xfd, 0x0c, 0x56, 0x57, 0xad, 0xd8, 0xc8, 0x4c,
+ 0x15, 0x87, 0xcc, 0x69, 0x77, 0x1f, 0x35, 0x92, 0x95, 0xa7, 0x3b, 0x53,
+ 0x8b, 0x8c, 0x19, 0xea, 0x3a, 0xcc, 0xfa, 0x25, 0xb1, 0x43, 0x55, 0xe5,
+ 0x99, 0x03, 0x52, 0xae, 0xb9, 0x78, 0x6b, 0x6e, 0xd1, 0xa5, 0x31, 0xe5,
+ 0xe1, 0xad, 0x9c, 0x87, 0xb7, 0xb2, 0xb5, 0xe5, 0x48, 0x00, 0xfd, 0xe7,
+ 0xe2, 0x6b, 0x31, 0xd6, 0x8c, 0x87, 0xb1, 0xa6, 0x3f, 0x20, 0xc6, 0xe2,
+ 0x58, 0x39, 0x3c, 0x33, 0x3e, 0x1f, 0x91, 0x5d, 0x90, 0xf3, 0x58, 0x91,
+ 0xfa, 0xe2, 0x19, 0xb2, 0xf7, 0xd2, 0x19, 0xf5, 0xe5, 0xea, 0x2a, 0x10,
+ 0xdb, 0xa7, 0x8d, 0x43, 0x57, 0x63, 0xef, 0xa9, 0x2b, 0x31, 0xdf, 0x18,
+ 0x09, 0xe2, 0xf3, 0xf7, 0xa5, 0x2b, 0xce, 0x83, 0xfa, 0x5a, 0x8f, 0xc5,
+ 0xee, 0x07, 0x93, 0xad, 0xc5, 0x63, 0xb6, 0xc2, 0x63, 0xed, 0x5e, 0x1f,
+ 0xd9, 0x33, 0x0e, 0x5d, 0xfe, 0x27, 0xf4, 0xf9, 0x99, 0xd5, 0x2d, 0x3f,
+ 0x85, 0xff, 0xfe, 0x43, 0xe8, 0xe4, 0x3f, 0x22, 0x57, 0x78, 0xcd, 0xea,
+ 0x93, 0x3f, 0x40, 0xdb, 0x5d, 0x9c, 0xc3, 0xfe, 0xc1, 0xc7, 0x92, 0xd6,
+ 0x35, 0xe0, 0x93, 0x6b, 0x1e, 0x3e, 0x79, 0x3a, 0x99, 0xb4, 0x26, 0x59,
+ 0x37, 0x87, 0x9c, 0x0f, 0xa4, 0xa6, 0x14, 0x36, 0xf1, 0x31, 0xc9, 0xed,
+ 0x34, 0xc7, 0x9f, 0x75, 0x56, 0x80, 0x7d, 0x56, 0x3c, 0xec, 0x73, 0x60,
+ 0xcc, 0xc5, 0x3e, 0xc1, 0xcf, 0x50, 0xff, 0x2e, 0xee, 0x59, 0xb1, 0x93,
+ 0x18, 0xa7, 0x0a, 0x4c, 0x52, 0x71, 0x0e, 0x48, 0xbe, 0xbe, 0x57, 0x7d,
+ 0x8e, 0x94, 0xec, 0x68, 0x1b, 0xe4, 0xc4, 0xda, 0xeb, 0x49, 0xae, 0x4a,
+ 0x27, 0x6a, 0x16, 0xf1, 0x9d, 0x75, 0xa2, 0xe1, 0xdf, 0xf1, 0xae, 0x9f,
+ 0xf7, 0xae, 0x4f, 0x78, 0xd7, 0xc7, 0x11, 0x87, 0x8f, 0xa9, 0x58, 0xca,
+ 0x76, 0xb6, 0x41, 0xc9, 0x0e, 0x68, 0x01, 0x7b, 0x9c, 0x1d, 0xfe, 0x8b,
+ 0x66, 0x59, 0xe9, 0x98, 0xf4, 0x27, 0xf0, 0x39, 0x8e, 0xcf, 0x34, 0x3e,
+ 0xfb, 0xf1, 0xc9, 0xe3, 0xb3, 0x2a, 0x53, 0x2d, 0x55, 0x9a, 0x84, 0x8d,
+ 0x0c, 0x4a, 0xaa, 0xfe, 0x12, 0xf4, 0xf8, 0x1c, 0x74, 0x7b, 0x58, 0x0a,
+ 0xd5, 0x3f, 0x95, 0xd9, 0x79, 0x4d, 0xba, 0x2c, 0xe8, 0xb4, 0x0a, 0x5b,
+ 0x9e, 0x77, 0xf7, 0x13, 0x3b, 0x13, 0x7b, 0xd1, 0xb7, 0x29, 0x4f, 0xc5,
+ 0x9f, 0x13, 0xfd, 0xb1, 0x39, 0xf4, 0x13, 0xbd, 0x30, 0xfc, 0x31, 0xb5,
+ 0x6f, 0x56, 0x8d, 0xbb, 0x32, 0xde, 0x65, 0xd9, 0x51, 0xe8, 0x7c, 0xf0,
+ 0x18, 0x68, 0x27, 0xd5, 0xd9, 0xd8, 0x8c, 0x1c, 0x3d, 0xbd, 0xbc, 0xc5,
+ 0xf5, 0xad, 0x51, 0xf3, 0x26, 0xf5, 0x8e, 0x79, 0xd8, 0xf0, 0x85, 0x19,
+ 0xd8, 0xfb, 0x41, 0x27, 0xa0, 0x8d, 0x21, 0xde, 0x8c, 0x39, 0x37, 0x55,
+ 0xbc, 0x81, 0xef, 0xca, 0xc4, 0x4e, 0x86, 0x70, 0xcd, 0xb3, 0x45, 0x88,
+ 0x8b, 0xea, 0x6c, 0xe5, 0x32, 0xf0, 0x8d, 0xa6, 0xea, 0x80, 0xb3, 0xab,
+ 0xfb, 0x43, 0x86, 0xf2, 0x5b, 0xb1, 0x98, 0x2e, 0xb9, 0x11, 0xe2, 0xdc,
+ 0xbd, 0x2a, 0x36, 0xd5, 0x8a, 0xf6, 0x43, 0xcc, 0x15, 0x6f, 0x08, 0xe3,
+ 0xdc, 0xe3, 0xe8, 0xd7, 0x07, 0x7f, 0x8c, 0x7b, 0x75, 0xda, 0x27, 0xe7,
+ 0xca, 0x67, 0xa6, 0xa5, 0x5a, 0x1e, 0xc5, 0x7c, 0xbd, 0x1c, 0x49, 0xe5,
+ 0x12, 0x11, 0xd8, 0xa3, 0xbf, 0x17, 0xe5, 0xd6, 0x4f, 0xaa, 0x8e, 0x8f,
+ 0x29, 0xba, 0xd1, 0x87, 0x79, 0x05, 0x64, 0xe4, 0xee, 0x9f, 0xa9, 0xbd,
+ 0xb3, 0x82, 0x33, 0x0a, 0x39, 0x25, 0xd1, 0xce, 0x5a, 0x35, 0x7e, 0x97,
+ 0x75, 0x55, 0x13, 0x58, 0x31, 0x66, 0xa4, 0x56, 0x6e, 0x82, 0x5f, 0xc4,
+ 0xdc, 0x2d, 0x33, 0x52, 0x29, 0x4f, 0xcb, 0x2b, 0xe5, 0x9f, 0x77, 0x03,
+ 0x53, 0x41, 0xa6, 0xe4, 0xbf, 0x5b, 0xee, 0x9e, 0xbf, 0xf5, 0xdb, 0x21,
+ 0xcf, 0xd3, 0xf9, 0xb0, 0x9b, 0xe7, 0xe6, 0x55, 0x2d, 0xc6, 0xfd, 0xb6,
+ 0xf5, 0x29, 0x2b, 0x1a, 0x9e, 0x45, 0xcf, 0x83, 0x0b, 0xb4, 0xcd, 0xfc,
+ 0xf8, 0x9c, 0xb5, 0x43, 0xae, 0xc6, 0x37, 0xcb, 0x72, 0x5c, 0xe5, 0xc5,
+ 0xc4, 0x0f, 0x58, 0xeb, 0x51, 0xb3, 0x21, 0x7b, 0xe4, 0x28, 0xd6, 0xed,
+ 0xd5, 0xf8, 0xd3, 0xb0, 0xd3, 0x67, 0x61, 0x0b, 0xac, 0x01, 0x1c, 0x62,
+ 0xae, 0x25, 0x0d, 0x55, 0x23, 0x6b, 0x36, 0xc7, 0xd5, 0x19, 0xee, 0x76,
+ 0x59, 0x56, 0x58, 0xcc, 0xad, 0x9d, 0x2f, 0x4f, 0xba, 0x6b, 0xc4, 0x50,
+ 0x76, 0xff, 0xc7, 0xe0, 0xc7, 0x84, 0xed, 0xb6, 0xa9, 0x3e, 0x46, 0xa2,
+ 0xc3, 0xeb, 0xa3, 0xf4, 0xdb, 0xd2, 0xe7, 0x95, 0x44, 0xd2, 0xda, 0xff,
+ 0x89, 0xa4, 0x75, 0x73, 0xb7, 0x5b, 0x6f, 0x89, 0x9a, 0xb6, 0xc6, 0xf7,
+ 0x52, 0xdc, 0xf5, 0x98, 0xc1, 0xba, 0xba, 0xb4, 0x8a, 0xa1, 0x61, 0xa4,
+ 0x2f, 0x5f, 0x81, 0x7e, 0x03, 0xd2, 0x7e, 0xb2, 0xf9, 0xf8, 0x54, 0x7c,
+ 0x28, 0x72, 0x50, 0x78, 0x02, 0x8b, 0x79, 0x75, 0x34, 0x9e, 0x95, 0x2b,
+ 0x88, 0x93, 0x77, 0x88, 0x1d, 0x06, 0x2f, 0xcb, 0x9d, 0xc7, 0x93, 0xf1,
+ 0x51, 0xad, 0x32, 0x89, 0xac, 0xe5, 0xe5, 0x49, 0xc6, 0xd9, 0x43, 0x22,
+ 0xc0, 0x97, 0x27, 0x47, 0x24, 0x5d, 0x54, 0xef, 0xa9, 0xf0, 0x9c, 0xad,
+ 0x36, 0x0d, 0xf9, 0xe1, 0xf9, 0x09, 0x06, 0x46, 0xdd, 0xea, 0x8f, 0xa4,
+ 0xe5, 0x69, 0xd6, 0xc0, 0x24, 0xb7, 0x20, 0xdb, 0x92, 0xf0, 0xab, 0xf6,
+ 0x44, 0xbb, 0x4c, 0xd7, 0x1a, 0x99, 0xfe, 0x53, 0xcf, 0x82, 0xc6, 0x14,
+ 0x68, 0xed, 0x45, 0x6e, 0x92, 0x45, 0xac, 0xa6, 0x7c, 0xe9, 0xbb, 0x9f,
+ 0x81, 0x8c, 0x3e, 0xc2, 0x3d, 0xe5, 0xd1, 0xac, 0x44, 0x27, 0xf2, 0x8a,
+ 0xee, 0x5b, 0x5a, 0x6e, 0xf8, 0x57, 0x10, 0xeb, 0x02, 0xb2, 0x2b, 0x26,
+ 0xfa, 0xde, 0x58, 0xe0, 0xed, 0x29, 0x8b, 0x6d, 0x41, 0xb6, 0xe9, 0x68,
+ 0x0b, 0xfc, 0x7a, 0x2c, 0xa8, 0x27, 0x63, 0xd1, 0x51, 0x9e, 0x8f, 0x36,
+ 0xac, 0x29, 0xee, 0x4d, 0x3c, 0x20, 0x5d, 0x7b, 0xa5, 0xe7, 0x42, 0x74,
+ 0xf4, 0x06, 0x78, 0x09, 0x28, 0x5f, 0x3f, 0x25, 0xba, 0xd7, 0xde, 0xbd,
+ 0xda, 0x1e, 0xf0, 0xda, 0xf7, 0x4a, 0xd7, 0x85, 0x21, 0xf3, 0x75, 0x99,
+ 0x01, 0x4d, 0x43, 0xae, 0x23, 0xd7, 0xb1, 0x06, 0xa6, 0x60, 0x8b, 0x4f,
+ 0x92, 0x97, 0xfd, 0xc0, 0x1a, 0x58, 0x1b, 0xc8, 0xbf, 0xad, 0x0f, 0xcb,
+ 0x57, 0xcd, 0x4e, 0xc9, 0xa9, 0x5c, 0x37, 0xe0, 0xd6, 0x52, 0x61, 0xef,
+ 0x8f, 0x0e, 0x1c, 0xec, 0x71, 0xeb, 0x05, 0xdc, 0xef, 0x18, 0x46, 0xdb,
+ 0x9d, 0xe6, 0x39, 0x8b, 0x6d, 0xbc, 0x77, 0xa7, 0x59, 0xb5, 0x86, 0xcc,
+ 0x94, 0x16, 0xf4, 0xf6, 0xbd, 0x0f, 0xa9, 0xb9, 0xe7, 0xcb, 0xfd, 0x66,
+ 0x45, 0x1e, 0xd5, 0x52, 0x0f, 0x22, 0x5e, 0x38, 0xd3, 0xe8, 0x7b, 0x87,
+ 0xe7, 0x29, 0x54, 0x7d, 0xbf, 0x22, 0xfe, 0x35, 0xe9, 0x0c, 0x99, 0xe3,
+ 0xea, 0xd9, 0x21, 0xf3, 0xa8, 0xd6, 0xfa, 0x6c, 0x58, 0x1b, 0x5f, 0xf3,
+ 0x6c, 0x97, 0x92, 0x91, 0x61, 0xb9, 0x7d, 0x66, 0xcb, 0x7b, 0xe5, 0x79,
+ 0x87, 0xfd, 0xee, 0x34, 0x53, 0xd6, 0x03, 0xda, 0xd1, 0x07, 0xe9, 0x0b,
+ 0xd9, 0xf7, 0xf6, 0xba, 0x71, 0x78, 0x7d, 0xaf, 0x31, 0x9a, 0xb2, 0x76,
+ 0x8c, 0x4d, 0xaa, 0xcf, 0x55, 0xd5, 0x27, 0xa0, 0x64, 0xbd, 0x76, 0x9c,
+ 0xbf, 0x91, 0xb5, 0xe3, 0x74, 0xad, 0xce, 0x79, 0x16, 0x34, 0x8f, 0xa1,
+ 0x6f, 0xd1, 0xe9, 0x0f, 0x57, 0xe5, 0x76, 0x33, 0x67, 0xbd, 0x29, 0x57,
+ 0x57, 0x69, 0xff, 0x12, 0xd7, 0xad, 0x3c, 0xfd, 0xd2, 0xe3, 0x91, 0xbf,
+ 0xd9, 0xf6, 0x2f, 0x95, 0xbc, 0x1f, 0xb0, 0xfa, 0xf7, 0x57, 0xb4, 0xe8,
+ 0xe8, 0x5f, 0x0a, 0x75, 0xf5, 0xcf, 0x94, 0xaf, 0xf9, 0x18, 0xf4, 0xb4,
+ 0xed, 0x05, 0xac, 0xdd, 0xe1, 0xa4, 0xea, 0x73, 0xdd, 0xda, 0x2b, 0xdb,
+ 0x4e, 0xf6, 0x9b, 0xd7, 0xe5, 0x33, 0x92, 0x0e, 0xf1, 0x1a, 0x39, 0x94,
+ 0xc5, 0xf7, 0x52, 0x3e, 0xc1, 0xbc, 0x00, 0xba, 0xec, 0x1f, 0xfc, 0x4b,
+ 0x79, 0x56, 0x8e, 0x96, 0xe6, 0xe0, 0x7b, 0xa6, 0x64, 0xf0, 0x05, 0xfa,
+ 0x9f, 0xbc, 0xe9, 0xd6, 0x6a, 0xdc, 0x98, 0x98, 0xf2, 0x62, 0xe2, 0x9c,
+ 0xf2, 0x73, 0xaf, 0x79, 0xe7, 0x22, 0xfa, 0x07, 0xcf, 0xe1, 0xd9, 0x57,
+ 0x94, 0x0f, 0xf8, 0x3d, 0xa9, 0x62, 0x2d, 0x44, 0x5e, 0xde, 0x2c, 0x0f,
+ 0x3c, 0x41, 0x9b, 0x44, 0x06, 0xf0, 0xb1, 0x36, 0xf5, 0x1e, 0x8c, 0x6e,
+ 0x75, 0x88, 0x6c, 0xa1, 0xfd, 0x5c, 0x86, 0xad, 0x4d, 0xb9, 0x7b, 0x5f,
+ 0x6b, 0xae, 0xa3, 0x13, 0x2b, 0xf2, 0x1f, 0x94, 0x1d, 0x7e, 0xfc, 0x82,
+ 0xfb, 0x3d, 0x7c, 0x01, 0xe9, 0x72, 0x6c, 0xaf, 0x6c, 0xbf, 0xe0, 0xda,
+ 0xdd, 0xec, 0xfc, 0xb3, 0x4a, 0xbe, 0x53, 0x4a, 0xbe, 0x4d, 0x99, 0x89,
+ 0x53, 0xf6, 0x9c, 0x13, 0xcf, 0x4f, 0xba, 0x32, 0xf9, 0x9c, 0x67, 0x47,
+ 0xfd, 0x2f, 0xf0, 0x3d, 0x35, 0xca, 0x88, 0x7c, 0xcf, 0xf4, 0x70, 0x3f,
+ 0x76, 0xdb, 0x05, 0xce, 0xb7, 0x6f, 0xcd, 0x7c, 0x4f, 0xc0, 0xc7, 0x0e,
+ 0x0c, 0xb8, 0x73, 0x7e, 0x6d, 0xfe, 0xfd, 0xcf, 0xf9, 0x77, 0x57, 0xe7,
+ 0x6c, 0x48, 0x55, 0xe5, 0xb9, 0xb1, 0xcd, 0xd2, 0x95, 0x93, 0x06, 0xec,
+ 0xe3, 0xcf, 0x85, 0x67, 0xc6, 0xc9, 0x8b, 0x3b, 0xee, 0xb2, 0x43, 0x9e,
+ 0xfc, 0x39, 0x90, 0xaf, 0x29, 0x4f, 0x7f, 0xe4, 0xe3, 0xd9, 0x0d, 0xef,
+ 0x5d, 0x97, 0x46, 0x66, 0x10, 0x6d, 0xba, 0xd2, 0xe1, 0x98, 0xb7, 0xde,
+ 0xf6, 0x8a, 0xae, 0x74, 0x98, 0x5c, 0xd5, 0xe1, 0x0d, 0xe8, 0xb0, 0x2a,
+ 0x9f, 0xc6, 0x9c, 0xb0, 0xbe, 0x5f, 0x18, 0x32, 0x67, 0x64, 0xab, 0xd2,
+ 0xbf, 0x35, 0x00, 0x9f, 0xea, 0xe9, 0xb2, 0xfd, 0x3e, 0x74, 0xf9, 0xba,
+ 0x28, 0x7d, 0xaa, 0x73, 0x44, 0x55, 0x45, 0x87, 0xbe, 0x8d, 0x73, 0x6b,
+ 0x57, 0x3e, 0x81, 0x3c, 0xaa, 0xb3, 0x01, 0x13, 0xae, 0x7e, 0xd5, 0x9a,
+ 0xf7, 0xf4, 0x9b, 0x9d, 0xa0, 0x0e, 0x7f, 0xad, 0xc7, 0xd5, 0x67, 0x87,
+ 0xea, 0x73, 0x2a, 0x36, 0xaa, 0xd6, 0xbb, 0x35, 0xf0, 0xe9, 0x1e, 0xea,
+ 0xf4, 0x79, 0xc7, 0xfd, 0x2e, 0x22, 0xce, 0x9d, 0x72, 0xde, 0x4b, 0xaf,
+ 0xae, 0x4e, 0xc7, 0xc4, 0x5d, 0x57, 0xeb, 0xf5, 0xa9, 0x5f, 0x08, 0x28,
+ 0x1b, 0x1e, 0x83, 0x0c, 0x8f, 0x97, 0x1e, 0xf4, 0xec, 0xde, 0x9d, 0xf3,
+ 0xc0, 0xfb, 0x9c, 0xf3, 0x91, 0x62, 0xbf, 0xf9, 0x26, 0xee, 0x8d, 0x63,
+ 0xce, 0x33, 0xd2, 0x26, 0x29, 0x6f, 0xce, 0x91, 0xd5, 0x39, 0xfb, 0x3c,
+ 0xba, 0xfd, 0x52, 0xcc, 0x63, 0x1d, 0xfa, 0xaf, 0x7f, 0xab, 0xde, 0x37,
+ 0xb9, 0x59, 0xa4, 0xdf, 0x06, 0x56, 0x0a, 0xf5, 0xca, 0xf5, 0x5a, 0x44,
+ 0xae, 0x13, 0x83, 0x8c, 0xe0, 0xdb, 0x99, 0xf3, 0x62, 0x78, 0x50, 0x5e,
+ 0x2f, 0x6e, 0xc4, 0xc7, 0xb0, 0xdc, 0x28, 0xfa, 0xbc, 0x10, 0x0b, 0x33,
+ 0x5f, 0x98, 0x92, 0x37, 0xe6, 0xfb, 0xa5, 0x31, 0x81, 0xb8, 0x3f, 0x40,
+ 0x99, 0x0c, 0x99, 0x7b, 0xd4, 0x7b, 0x48, 0x77, 0x9a, 0x97, 0x2d, 0xd0,
+ 0x5f, 0x68, 0xca, 0x41, 0xee, 0x67, 0xf3, 0x77, 0xed, 0x21, 0x69, 0x30,
+ 0xa7, 0x18, 0xe8, 0x95, 0xca, 0x02, 0xf2, 0xf9, 0x22, 0xe9, 0x53, 0x6e,
+ 0x7b, 0xd5, 0xef, 0x71, 0x8c, 0xf7, 0x39, 0xbe, 0x1f, 0x10, 0xa2, 0x6e,
+ 0xee, 0x34, 0x97, 0x2d, 0xee, 0x67, 0x4e, 0x49, 0x0d, 0xfa, 0xfb, 0xe7,
+ 0x31, 0xee, 0xb7, 0xe7, 0xd4, 0xf9, 0xdb, 0x4a, 0x6d, 0x02, 0xb9, 0xc3,
+ 0x9d, 0xe6, 0x9c, 0x75, 0x56, 0xe9, 0xad, 0x56, 0x7e, 0xc2, 0x6b, 0xe7,
+ 0x35, 0xef, 0x35, 0x32, 0xdb, 0x06, 0x98, 0xaf, 0x3e, 0x81, 0x7c, 0x81,
+ 0xb9, 0xea, 0x04, 0xf0, 0x1a, 0x65, 0x12, 0x91, 0xd9, 0x22, 0x69, 0x49,
+ 0x68, 0x13, 0xf2, 0xfb, 0x9c, 0x8c, 0x83, 0x9f, 0x08, 0x72, 0x7b, 0xc6,
+ 0x87, 0x47, 0x65, 0x39, 0xe4, 0xc6, 0x01, 0x9e, 0xfb, 0x5a, 0x46, 0x6c,
+ 0x58, 0x5e, 0x8d, 0x0d, 0x5b, 0x71, 0xdd, 0xc8, 0xc4, 0x07, 0xfe, 0x06,
+ 0xf4, 0x59, 0xb7, 0x61, 0x6c, 0x18, 0x45, 0x7f, 0xb6, 0xf5, 0xca, 0xec,
+ 0x02, 0x92, 0x08, 0xe4, 0x2c, 0x15, 0xe1, 0x99, 0x8e, 0xac, 0x9c, 0xaa,
+ 0xf5, 0x87, 0x2f, 0x6b, 0x69, 0x75, 0xf6, 0x23, 0x36, 0xc0, 0xf3, 0x2c,
+ 0xbd, 0x52, 0x5b, 0x90, 0x88, 0x91, 0x78, 0x52, 0x9c, 0x9a, 0x8b, 0xd9,
+ 0xe7, 0x34, 0x9e, 0x69, 0xb1, 0xa5, 0xb6, 0xb6, 0x8f, 0x89, 0xdc, 0x57,
+ 0xbe, 0xe3, 0xf5, 0x49, 0xab, 0x3e, 0x7f, 0xdd, 0xc3, 0x3d, 0xb4, 0x9a,
+ 0xd3, 0x03, 0x1e, 0xc8, 0xdb, 0xc3, 0xad, 0xe3, 0x46, 0xee, 0x8e, 0xcb,
+ 0x31, 0x91, 0xcd, 0x6c, 0xb1, 0x31, 0xee, 0x4d, 0x3c, 0xf3, 0x24, 0xf8,
+ 0xb8, 0x63, 0xe8, 0xd6, 0x93, 0x52, 0xa8, 0xad, 0x1f, 0xa3, 0x95, 0x07,
+ 0x3e, 0x43, 0xfa, 0x1c, 0xe7, 0x00, 0xf8, 0xbb, 0xa3, 0xe9, 0xd6, 0x01,
+ 0xc8, 0xd2, 0x1d, 0xc3, 0x38, 0x13, 0x35, 0x7f, 0x2a, 0x03, 0xa2, 0x9f,
+ 0xd3, 0x94, 0xfc, 0xf5, 0xca, 0x30, 0x16, 0x48, 0x46, 0xba, 0x96, 0x26,
+ 0xc5, 0x58, 0x62, 0x0d, 0xe1, 0xb5, 0xce, 0xb4, 0xda, 0xbf, 0xdd, 0x84,
+ 0xf5, 0x2d, 0x76, 0xc0, 0x62, 0xbd, 0x80, 0xf5, 0xe0, 0x9f, 0x6e, 0x96,
+ 0x1e, 0xd6, 0x0b, 0x98, 0x37, 0xec, 0xc7, 0x37, 0x73, 0x87, 0x4b, 0x4d,
+ 0xe4, 0x7a, 0x9b, 0x19, 0x5f, 0x73, 0x35, 0xde, 0x8f, 0x46, 0x44, 0x78,
+ 0x8f, 0x7e, 0xa3, 0x57, 0xda, 0xbe, 0x35, 0x08, 0x5f, 0xf1, 0x34, 0xb0,
+ 0x37, 0xe8, 0x9e, 0x1c, 0x90, 0x80, 0x7b, 0x66, 0x42, 0xd5, 0x5b, 0xde,
+ 0x58, 0x88, 0x7a, 0xef, 0x73, 0xc9, 0xb6, 0xcb, 0x71, 0xd6, 0x44, 0xfb,
+ 0x58, 0xf3, 0x41, 0x3f, 0xd1, 0x97, 0x91, 0x9f, 0x5e, 0xaf, 0x59, 0x9b,
+ 0x79, 0x7e, 0xf3, 0x86, 0x83, 0x6b, 0x62, 0xff, 0x90, 0xc2, 0x98, 0xde,
+ 0x3d, 0xfe, 0x46, 0xbe, 0xf4, 0x8e, 0x77, 0x13, 0x98, 0x4f, 0x4d, 0x7a,
+ 0x67, 0xe7, 0x1a, 0x99, 0xa3, 0x6b, 0x72, 0xaa, 0x41, 0x55, 0xef, 0x6d,
+ 0x38, 0x16, 0xfc, 0xe3, 0x08, 0xec, 0x93, 0x6b, 0xa0, 0xa9, 0x3d, 0x01,
+ 0x6c, 0x16, 0xe9, 0x55, 0x39, 0xd1, 0xf1, 0x27, 0xc4, 0xb5, 0x77, 0x58,
+ 0x99, 0xf2, 0x65, 0x8d, 0xb2, 0x9b, 0x83, 0x2c, 0x97, 0x33, 0xf2, 0x47,
+ 0xce, 0x15, 0x55, 0x6b, 0x9d, 0x47, 0x5e, 0x12, 0x38, 0xa5, 0x72, 0xb2,
+ 0x16, 0x7c, 0x0b, 0xbf, 0xf7, 0xe2, 0xd7, 0xb1, 0x16, 0xa3, 0xea, 0x8c,
+ 0x82, 0x7e, 0xae, 0xd9, 0x4c, 0xc1, 0x7f, 0xe8, 0x96, 0x65, 0x16, 0x10,
+ 0x0f, 0x53, 0xea, 0x9c, 0x0b, 0xd7, 0xf1, 0x6f, 0x2b, 0xff, 0x2c, 0x15,
+ 0xc8, 0xe6, 0x4c, 0x04, 0x74, 0x34, 0x65, 0x9f, 0x86, 0xd2, 0xc3, 0x13,
+ 0x0a, 0xf3, 0x1a, 0xe7, 0xe0, 0xb0, 0x96, 0x06, 0x44, 0xce, 0x65, 0x64,
+ 0x0e, 0x6b, 0x38, 0xb0, 0x44, 0x1d, 0x50, 0xb6, 0x93, 0xd2, 0x06, 0xd9,
+ 0x1f, 0x01, 0xf6, 0x30, 0x4e, 0x51, 0xc6, 0x61, 0xac, 0x8b, 0x5e, 0x09,
+ 0x9c, 0x81, 0x8c, 0x4f, 0x01, 0x23, 0x2c, 0xb4, 0xcb, 0xf7, 0x6a, 0xbe,
+ 0x4c, 0x2f, 0xf1, 0x5c, 0xbf, 0x3e, 0x35, 0xd2, 0x47, 0x1c, 0x25, 0xd5,
+ 0xda, 0x9c, 0xcc, 0x9d, 0x66, 0xce, 0x3e, 0xa9, 0xce, 0x0c, 0x04, 0xd4,
+ 0x99, 0x15, 0x37, 0x67, 0x76, 0xbf, 0x5d, 0x8c, 0x59, 0x15, 0xee, 0xb5,
+ 0x09, 0x6c, 0x67, 0x18, 0xe3, 0x6e, 0x24, 0x5f, 0x37, 0x57, 0x1d, 0x07,
+ 0xbf, 0x97, 0xe7, 0xa3, 0x99, 0xbc, 0xc4, 0x79, 0x76, 0x7a, 0xc2, 0xc6,
+ 0xfc, 0x97, 0xe1, 0x3f, 0xe7, 0x4a, 0x3c, 0x27, 0x5d, 0xc0, 0x0a, 0xcb,
+ 0xc8, 0xe5, 0x22, 0x73, 0xc6, 0x8f, 0x43, 0x6f, 0xbc, 0x2e, 0x8c, 0x1a,
+ 0xf0, 0x03, 0x2b, 0xea, 0xdd, 0xcf, 0xa8, 0xdd, 0x40, 0x0e, 0x1b, 0xd1,
+ 0xf6, 0x43, 0xd7, 0x79, 0xb3, 0xcd, 0xb3, 0x07, 0x9e, 0xc5, 0x3f, 0x0b,
+ 0x3f, 0x7a, 0x5e, 0xf8, 0x4e, 0xd6, 0xed, 0x26, 0xf3, 0xa5, 0xab, 0xf0,
+ 0x7b, 0x99, 0x58, 0x06, 0x36, 0x94, 0x0f, 0x77, 0x80, 0xe7, 0xdf, 0xc4,
+ 0xbd, 0x9c, 0xc3, 0x71, 0xa2, 0xf1, 0x15, 0x29, 0x44, 0x02, 0x32, 0x14,
+ 0xb9, 0x22, 0x9b, 0xe1, 0xc9, 0x34, 0x79, 0xdd, 0x8a, 0x8e, 0x8a, 0xa6,
+ 0xe8, 0x0d, 0xee, 0x86, 0x0d, 0xde, 0x84, 0xbf, 0x6b, 0xf7, 0x72, 0xfd,
+ 0x54, 0x91, 0x18, 0xea, 0x59, 0x75, 0xb6, 0xe0, 0xaa, 0xc5, 0x3a, 0x20,
+ 0xdf, 0xc5, 0xfe, 0x1f, 0x6a, 0x8c, 0xbb, 0x7b, 0x77, 0xac, 0x43, 0x93,
+ 0x3f, 0x77, 0x8e, 0xbb, 0x2c, 0x97, 0x47, 0xd2, 0x69, 0x6b, 0xa1, 0x73,
+ 0xd9, 0xa3, 0x73, 0xd6, 0xa3, 0x53, 0xf1, 0xe8, 0x5c, 0x5d, 0xa5, 0xb3,
+ 0x07, 0x76, 0xd0, 0x6c, 0x9e, 0x00, 0xde, 0x48, 0xc6, 0x9b, 0xcd, 0x34,
+ 0xf2, 0xb2, 0xd9, 0xe1, 0x69, 0xb5, 0xe7, 0xaa, 0x27, 0x46, 0xc7, 0x93,
+ 0x96, 0x2b, 0x7f, 0x58, 0x81, 0x4c, 0xc3, 0x1e, 0xf3, 0xe2, 0x62, 0x75,
+ 0xee, 0x07, 0xba, 0xfb, 0x85, 0x5d, 0xf0, 0x03, 0x4f, 0x23, 0x96, 0x5c,
+ 0x1c, 0x3f, 0x6f, 0x49, 0x7e, 0xdb, 0x27, 0x75, 0xd8, 0x7b, 0x0f, 0xdf,
+ 0x27, 0x35, 0xa5, 0xeb, 0xe2, 0x78, 0xb5, 0xf6, 0x34, 0xf2, 0x23, 0xf6,
+ 0xdf, 0x4e, 0x0c, 0xb6, 0xab, 0x52, 0x8b, 0xec, 0x3a, 0xcb, 0xfd, 0x21,
+ 0xf4, 0xab, 0xd4, 0xba, 0x21, 0xf7, 0x6e, 0x55, 0x57, 0xb9, 0x52, 0x0c,
+ 0x41, 0x8f, 0x26, 0x6c, 0x3e, 0x84, 0xb6, 0x30, 0xec, 0xa0, 0x0f, 0xed,
+ 0x3f, 0xc7, 0xda, 0x8e, 0xa0, 0x7d, 0xa5, 0x73, 0x5c, 0xe1, 0x58, 0x4b,
+ 0xce, 0x39, 0x37, 0x11, 0x73, 0xdf, 0x84, 0x1f, 0x1d, 0x44, 0x9f, 0x61,
+ 0xf4, 0xf9, 0x14, 0xc6, 0xe1, 0x3b, 0xcd, 0x1b, 0xf1, 0xd4, 0x00, 0x4f,
+ 0x7a, 0x0b, 0x4f, 0x0d, 0xf0, 0x03, 0xdf, 0x79, 0x92, 0x35, 0xe8, 0x61,
+ 0x39, 0x5a, 0xe4, 0x19, 0x29, 0xbe, 0x17, 0x6f, 0x4a, 0x00, 0x98, 0xb4,
+ 0xed, 0x64, 0x34, 0xdc, 0x50, 0xb5, 0x1e, 0xda, 0xd6, 0x50, 0xbc, 0x2a,
+ 0x2a, 0xce, 0x44, 0x8e, 0x22, 0x7e, 0xdd, 0x74, 0xba, 0xe5, 0x75, 0x6f,
+ 0xac, 0x15, 0xe1, 0xfe, 0xe5, 0xda, 0xb1, 0x8e, 0x95, 0xae, 0x8d, 0xbf,
+ 0x6a, 0x19, 0xde, 0xbc, 0x7a, 0x31, 0xd6, 0xaf, 0xa2, 0xef, 0xb5, 0xf1,
+ 0xcb, 0xb5, 0x8d, 0xfa, 0xde, 0x44, 0xdf, 0xb6, 0x96, 0xbe, 0x37, 0xd1,
+ 0xaf, 0x1b, 0x71, 0xb0, 0x5b, 0xcd, 0x69, 0x16, 0x7c, 0x5d, 0x2f, 0xaa,
+ 0xf7, 0xb4, 0x21, 0x77, 0x8e, 0x69, 0x12, 0x53, 0x67, 0xdc, 0x5a, 0x49,
+ 0xd4, 0x8c, 0x68, 0xef, 0xa8, 0xf7, 0x28, 0x1b, 0x18, 0xb3, 0x80, 0x7b,
+ 0xe7, 0x27, 0xb4, 0x54, 0x35, 0x87, 0x98, 0xf5, 0x30, 0xf1, 0x53, 0xdc,
+ 0x46, 0xcc, 0xac, 0x80, 0x5e, 0xad, 0xd8, 0xe0, 0x79, 0x6a, 0xd8, 0xc5,
+ 0x2d, 0xe2, 0xec, 0x87, 0x0d, 0x75, 0xae, 0x21, 0xad, 0x6a, 0x76, 0x95,
+ 0xa2, 0x98, 0xc9, 0x11, 0x9e, 0x65, 0xf8, 0x0c, 0xd6, 0xe5, 0x57, 0xd0,
+ 0x96, 0x44, 0x7c, 0x3c, 0xa0, 0x25, 0xcf, 0x8f, 0xe3, 0xfa, 0x49, 0x5c,
+ 0xc3, 0x1f, 0x2f, 0x64, 0x71, 0xff, 0x49, 0x5c, 0x4f, 0x6b, 0xa9, 0x7a,
+ 0x16, 0xd7, 0x4f, 0xe1, 0x7a, 0xca, 0x64, 0x9e, 0xf2, 0xaa, 0x95, 0xd1,
+ 0x6c, 0xd0, 0xb2, 0xcf, 0x8f, 0xe3, 0xd3, 0x4a, 0x8f, 0xf7, 0xa0, 0xa7,
+ 0x22, 0xf7, 0xda, 0x62, 0xe0, 0x69, 0x9f, 0x96, 0xae, 0x76, 0x81, 0xc6,
+ 0x00, 0x9e, 0xa7, 0x4d, 0xed, 0xf7, 0xc6, 0x67, 0xcd, 0xe9, 0x63, 0xaa,
+ 0xe6, 0x64, 0x24, 0x32, 0xc0, 0xc9, 0x87, 0x91, 0x07, 0x68, 0x92, 0xb6,
+ 0x9e, 0x93, 0x42, 0x1c, 0x7e, 0xa5, 0x6a, 0x48, 0x2a, 0x94, 0xc7, 0xef,
+ 0xbc, 0x24, 0x47, 0x71, 0xbf, 0x4a, 0x5b, 0x60, 0xbf, 0x3f, 0x95, 0x42,
+ 0x99, 0xb8, 0x9f, 0x75, 0x26, 0xd6, 0xa6, 0x58, 0x5f, 0xca, 0x41, 0x06,
+ 0x21, 0xda, 0xef, 0x06, 0x35, 0x31, 0xf7, 0x8c, 0x34, 0xe2, 0xb2, 0x96,
+ 0xac, 0x72, 0xdf, 0xaf, 0x91, 0xb9, 0x6c, 0xf1, 0xfd, 0xb1, 0x69, 0xee,
+ 0x23, 0x16, 0x8c, 0x04, 0xeb, 0x23, 0xaa, 0xbe, 0x1e, 0x77, 0xf7, 0x07,
+ 0x5b, 0xcf, 0xa4, 0xf8, 0xeb, 0x85, 0xe3, 0x7e, 0x0d, 0xcf, 0xbb, 0xf5,
+ 0xac, 0x54, 0xfd, 0x9d, 0xba, 0xe0, 0x3b, 0x00, 0xe7, 0xa0, 0x8b, 0xcb,
+ 0x2a, 0x37, 0xe6, 0x1e, 0xee, 0xbb, 0xe5, 0x54, 0xc8, 0x61, 0x8a, 0xac,
+ 0x91, 0xf9, 0xfb, 0x76, 0xbe, 0x1c, 0xd7, 0xf3, 0x4a, 0x3e, 0x67, 0x40,
+ 0x53, 0xe2, 0xf4, 0xbb, 0xd9, 0x10, 0xf7, 0xdf, 0xf8, 0x8c, 0x7c, 0xf3,
+ 0x2e, 0xdf, 0xe4, 0x99, 0xf2, 0x38, 0x0c, 0xff, 0xc9, 0xf7, 0x2b, 0x9e,
+ 0x93, 0x5c, 0x9c, 0x35, 0x1e, 0x03, 0xb1, 0x31, 0x8f, 0xdf, 0x77, 0xe5,
+ 0x37, 0xeb, 0xc9, 0x2f, 0x57, 0xfe, 0x2f, 0x4a, 0x87, 0x15, 0x8b, 0xe3,
+ 0xf9, 0xb5, 0x8f, 0xbd, 0x4a, 0x77, 0x15, 0x75, 0x7e, 0xd7, 0x97, 0x81,
+ 0x5f, 0xbf, 0xdb, 0xd8, 0xf6, 0xc6, 0x2d, 0xf2, 0xf6, 0x10, 0xcf, 0x43,
+ 0x0c, 0xda, 0x42, 0xfe, 0x39, 0x0f, 0xc6, 0x30, 0x7f, 0xaf, 0xd5, 0x9f,
+ 0x83, 0x3f, 0xcf, 0xfb, 0x95, 0x0f, 0xf9, 0xfd, 0xe4, 0x16, 0xe9, 0xca,
+ 0x98, 0x86, 0xc5, 0xd8, 0xf0, 0xb8, 0xb7, 0x3f, 0xf0, 0x7f, 0x43, 0xce,
+ 0xae, 0x2c, 0x02, 0x09, 0x99, 0xf5, 0xde, 0xbf, 0xde, 0xc0, 0x1e, 0xd6,
+ 0xef, 0x35, 0x37, 0x32, 0x67, 0xad, 0xbb, 0xf3, 0xae, 0x6c, 0x30, 0xef,
+ 0x8a, 0x37, 0xef, 0xea, 0x7d, 0xf2, 0x5b, 0x99, 0xb7, 0x31, 0x67, 0xda,
+ 0xdc, 0x46, 0xf6, 0x28, 0xea, 0xdd, 0xb0, 0x15, 0x23, 0x18, 0xb4, 0x9d,
+ 0x7b, 0xd5, 0x50, 0x99, 0x57, 0xbb, 0x76, 0x79, 0x16, 0xb1, 0xb0, 0x5c,
+ 0x76, 0x73, 0xec, 0xb2, 0xc3, 0x5a, 0xf6, 0xbb, 0xf1, 0xc0, 0x77, 0xb9,
+ 0xbe, 0xa8, 0xce, 0xbb, 0xcc, 0x3a, 0x6e, 0xdd, 0xab, 0x5c, 0x6e, 0x8d,
+ 0xa9, 0x0f, 0x32, 0x9e, 0x0e, 0xe6, 0x65, 0x82, 0xef, 0x94, 0xe3, 0xfa,
+ 0x11, 0xb9, 0xb2, 0xa0, 0xf6, 0xac, 0xbc, 0xbd, 0x21, 0xee, 0xf9, 0xa8,
+ 0xfd, 0x6f, 0xf8, 0xb5, 0x49, 0xe5, 0xd7, 0x97, 0x17, 0xd4, 0x3d, 0x17,
+ 0x2b, 0x39, 0x13, 0xf0, 0xfb, 0xc8, 0x25, 0xac, 0x07, 0xa4, 0x80, 0x9c,
+ 0xfb, 0xac, 0x75, 0x78, 0x0b, 0x71, 0x0e, 0x69, 0x2d, 0x83, 0xd6, 0xe5,
+ 0x05, 0xd9, 0xc2, 0x33, 0x25, 0x65, 0xb5, 0xcf, 0xe6, 0xd6, 0xc5, 0xa7,
+ 0xc5, 0xff, 0x7f, 0x1d, 0x41, 0x2f, 0x16, 0xf2, 0x5c, 0x0b, 0xdf, 0x73,
+ 0xa6, 0xaf, 0x40, 0x1e, 0x34, 0xc1, 0x7d, 0x9c, 0x66, 0xd3, 0xad, 0x9b,
+ 0x37, 0xb1, 0x2e, 0xda, 0xf8, 0x0e, 0x05, 0xfe, 0x0e, 0xc3, 0x7e, 0xb0,
+ 0x4e, 0x56, 0xdb, 0x79, 0xcd, 0xdc, 0xc3, 0xbf, 0x66, 0x60, 0xfb, 0x3f,
+ 0xe8, 0xf3, 0x49, 0x14, 0x38, 0x46, 0x00, 0x00, 0x00 };
+
+static const u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
0x00000000, 0x00000014, 0x00000014, 0x00000014, 0x00000014, 0x00000010,
0x00000030, 0x00000030, 0x00000000, 0x00000000, 0x00000000, 0x00000010,
0x00008000, 0x00000000, 0x00000000, 0x00000000, 0x00008002, 0x00000000,
@@ -4043,42 +4051,42 @@ static u32 bnx2_TXP_b09FwData[(0xd0/4) + 1] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000,
0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
-static u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
- 0x08003be8, 0x08003c14, 0x08003c5c, 0x08003c5c, 0x08003ae8, 0x08003b14,
- 0x08003b14, 0x08003c5c, 0x08003c5c, 0x08003c5c, 0x08003b7c, 0x00000000,
+static const u32 bnx2_TXP_b09FwRodata[(0x30/4) + 1] = {
+ 0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c,
+ 0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000,
0x00000000 };
-static u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b09FwSbss[(0x80/4) + 1] = { 0x0 };
+static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
+static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 };
static struct fw_info bnx2_txp_fw_09 = {
- .ver_major = 0x1,
- .ver_minor = 0x0,
- .ver_fix = 0x0,
+ .ver_major = 0x3,
+ .ver_minor = 0x4,
+ .ver_fix = 0x3,
.start_addr = 0x08000060,
.text_addr = 0x08000000,
- .text_len = 0x4194,
+ .text_len = 0x4634,
.text_index = 0x0,
.gz_text = bnx2_TXP_b09FwText,
.gz_text_len = sizeof(bnx2_TXP_b09FwText),
- .data_addr = 0x080041e0,
+ .data_addr = 0x08004680,
.data_len = 0xd0,
.data_index = 0x0,
.data = bnx2_TXP_b09FwData,
- .sbss_addr = 0x080042b0,
- .sbss_len = 0x80,
+ .sbss_addr = 0x08004750,
+ .sbss_len = 0x8c,
.sbss_index = 0x0,
.sbss = bnx2_TXP_b09FwSbss,
- .bss_addr = 0x08004330,
+ .bss_addr = 0x080047e0,
.bss_len = 0xa20,
.bss_index = 0x0,
.bss = bnx2_TXP_b09FwBss,
- .rodata_addr = 0x08004198,
+ .rodata_addr = 0x08004638,
.rodata_len = 0x30,
.rodata_index = 0x0,
.rodata = bnx2_TXP_b09FwRodata,
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index cea3783c92c..223517dcbcf 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1360,13 +1360,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
goto err_undo_flags;
}
- if (slave_dev->get_stats == NULL) {
- printk(KERN_NOTICE DRV_NAME
- ": %s: the driver for slave device %s does not provide "
- "get_stats function, network statistics will be "
- "inaccurate.\n", bond_dev->name, slave_dev->name);
- }
-
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
@@ -3468,7 +3461,7 @@ void bond_unregister_arp(struct bonding *bond)
/*---------------------------- Hashing Policies -----------------------------*/
/*
- * Hash for the the output device based upon layer 3 and layer 4 data. If
+ * Hash for the output device based upon layer 3 and layer 4 data. If
* the packet is a frag or not TCP or UDP, just use layer 3 data. If it is
* altogether not IP, mimic bond_xmit_hash_policy_l2()
*/
@@ -3641,33 +3634,31 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev)
bond_for_each_slave(bond, slave, i) {
sstats = slave->dev->get_stats(slave->dev);
- if (sstats) {
- stats->rx_packets += sstats->rx_packets;
- stats->rx_bytes += sstats->rx_bytes;
- stats->rx_errors += sstats->rx_errors;
- stats->rx_dropped += sstats->rx_dropped;
-
- stats->tx_packets += sstats->tx_packets;
- stats->tx_bytes += sstats->tx_bytes;
- stats->tx_errors += sstats->tx_errors;
- stats->tx_dropped += sstats->tx_dropped;
-
- stats->multicast += sstats->multicast;
- stats->collisions += sstats->collisions;
-
- stats->rx_length_errors += sstats->rx_length_errors;
- stats->rx_over_errors += sstats->rx_over_errors;
- stats->rx_crc_errors += sstats->rx_crc_errors;
- stats->rx_frame_errors += sstats->rx_frame_errors;
- stats->rx_fifo_errors += sstats->rx_fifo_errors;
- stats->rx_missed_errors += sstats->rx_missed_errors;
-
- stats->tx_aborted_errors += sstats->tx_aborted_errors;
- stats->tx_carrier_errors += sstats->tx_carrier_errors;
- stats->tx_fifo_errors += sstats->tx_fifo_errors;
- stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
- stats->tx_window_errors += sstats->tx_window_errors;
- }
+ stats->rx_packets += sstats->rx_packets;
+ stats->rx_bytes += sstats->rx_bytes;
+ stats->rx_errors += sstats->rx_errors;
+ stats->rx_dropped += sstats->rx_dropped;
+
+ stats->tx_packets += sstats->tx_packets;
+ stats->tx_bytes += sstats->tx_bytes;
+ stats->tx_errors += sstats->tx_errors;
+ stats->tx_dropped += sstats->tx_dropped;
+
+ stats->multicast += sstats->multicast;
+ stats->collisions += sstats->collisions;
+
+ stats->rx_length_errors += sstats->rx_length_errors;
+ stats->rx_over_errors += sstats->rx_over_errors;
+ stats->rx_crc_errors += sstats->rx_crc_errors;
+ stats->rx_frame_errors += sstats->rx_frame_errors;
+ stats->rx_fifo_errors += sstats->rx_fifo_errors;
+ stats->rx_missed_errors += sstats->rx_missed_errors;
+
+ stats->tx_aborted_errors += sstats->tx_aborted_errors;
+ stats->tx_carrier_errors += sstats->tx_carrier_errors;
+ stats->tx_fifo_errors += sstats->tx_fifo_errors;
+ stats->tx_heartbeat_errors += sstats->tx_heartbeat_errors;
+ stats->tx_window_errors += sstats->tx_window_errors;
}
read_unlock_bh(&bond->lock);
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 382d23f810a..743ad8b41b5 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,8 +4,6 @@
obj-$(CONFIG_CHELSIO_T1) += cxgb.o
-cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
mv88x201x.o my3126.o $(cxgb-y)
-
-
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 787f2f2820f..8ba702c8b56 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -322,9 +322,9 @@ struct board_info {
unsigned char mdio_mdiinv;
unsigned char mdio_mdc;
unsigned char mdio_phybaseaddr;
- struct gmac *gmac;
- struct gphy *gphy;
- struct mdio_ops *mdio_ops;
+ const struct gmac *gmac;
+ const struct gphy *gphy;
+ const struct mdio_ops *mdio_ops;
const char *desc;
};
diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h
index cf914349988..79d855e267e 100644
--- a/drivers/net/chelsio/cphy.h
+++ b/drivers/net/chelsio/cphy.h
@@ -100,7 +100,7 @@ struct cphy {
u32 elmer_gpo;
- struct cphy_ops *ops; /* PHY operations */
+ const struct cphy_ops *ops; /* PHY operations */
int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr,
int reg_addr, unsigned int *val);
int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr,
@@ -136,7 +136,7 @@ static inline int simple_mdio_write(struct cphy *cphy, int reg,
/* Convenience initializer */
static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
int phy_addr, struct cphy_ops *phy_ops,
- struct mdio_ops *mdio_ops)
+ const struct mdio_ops *mdio_ops)
{
phy->adapter = adapter;
phy->addr = phy_addr;
@@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter,
struct gphy {
/* Construct a PHY instance with the given PHY address */
struct cphy *(*create)(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops);
+ const struct mdio_ops *mdio_ops);
/*
* Reset the PHY chip. This resets the whole PHY chip, not individual
@@ -160,11 +160,9 @@ struct gphy {
int (*reset)(adapter_t *adapter);
};
-extern struct gphy t1_my3126_ops;
-extern struct gphy t1_mv88e1xxx_ops;
-extern struct gphy t1_vsc8244_ops;
-extern struct gphy t1_xpak_ops;
-extern struct gphy t1_mv88x201x_ops;
-extern struct gphy t1_dummy_phy_ops;
+extern const struct gphy t1_my3126_ops;
+extern const struct gphy t1_mv88e1xxx_ops;
+extern const struct gphy t1_vsc8244_ops;
+extern const struct gphy t1_mv88x201x_ops;
#endif /* _CXGB_CPHY_H_ */
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h
index 006a2eb2d36..d42337457cf 100644
--- a/drivers/net/chelsio/gmac.h
+++ b/drivers/net/chelsio/gmac.h
@@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_instance;
struct cmac {
struct cmac_statistics stats;
adapter_t *adapter;
- struct cmac_ops *ops;
+ const struct cmac_ops *ops;
cmac_instance *instance;
};
@@ -136,11 +136,7 @@ struct gmac {
int (*reset)(adapter_t *);
};
-extern struct gmac t1_pm3393_ops;
-extern struct gmac t1_chelsio_mac_ops;
-extern struct gmac t1_vsc7321_ops;
-extern struct gmac t1_vsc7326_ops;
-extern struct gmac t1_ixf1010_ops;
-extern struct gmac t1_dummy_mac_ops;
+extern const struct gmac t1_pm3393_ops;
+extern const struct gmac t1_vsc7326_ops;
#endif /* _CXGB_GMAC_H_ */
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c
deleted file mode 100644
index 10b2a9a1900..00000000000
--- a/drivers/net/chelsio/ixf1010.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */
-#include "gmac.h"
-#include "elmer0.h"
-
-/* Update fast changing statistics every 15 seconds */
-#define STATS_TICK_SECS 15
-/* 30 minutes for full statistics update */
-#define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS)
-
-/*
- * The IXF1010 can handle frames up to 16383 bytes but it's optimized for
- * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this.
- * This length includes ethernet header and FCS.
- */
-#define MAX_FRAME_SIZE 0x2667
-
-/* MAC registers */
-enum {
- /* Per-port registers */
- REG_MACADDR_LOW = 0,
- REG_MACADDR_HIGH = 0x4,
- REG_FDFC_TYPE = 0xC,
- REG_FC_TX_TIMER_VALUE = 0x1c,
- REG_IPG_RX_TIME1 = 0x28,
- REG_IPG_RX_TIME2 = 0x2c,
- REG_IPG_TX_TIME = 0x30,
- REG_PAUSE_THRES = 0x38,
- REG_MAX_FRAME_SIZE = 0x3c,
- REG_RGMII_SPEED = 0x40,
- REG_FC_ENABLE = 0x48,
- REG_DISCARD_CTRL_FRAMES = 0x54,
- REG_DIVERSE_CONFIG = 0x60,
- REG_RX_FILTER = 0x64,
- REG_MC_ADDR_LOW = 0x68,
- REG_MC_ADDR_HIGH = 0x6c,
-
- REG_RX_OCTETS_OK = 0x80,
- REG_RX_OCTETS_BAD = 0x84,
- REG_RX_UC_PKTS = 0x88,
- REG_RX_MC_PKTS = 0x8c,
- REG_RX_BC_PKTS = 0x90,
- REG_RX_FCS_ERR = 0xb0,
- REG_RX_TAGGED = 0xb4,
- REG_RX_DATA_ERR = 0xb8,
- REG_RX_ALIGN_ERR = 0xbc,
- REG_RX_LONG_ERR = 0xc0,
- REG_RX_JABBER_ERR = 0xc4,
- REG_RX_PAUSE_FRAMES = 0xc8,
- REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc,
- REG_RX_VERY_LONG_ERR = 0xd0,
- REG_RX_RUNT_ERR = 0xd4,
- REG_RX_SHORT_ERR = 0xd8,
- REG_RX_SYMBOL_ERR = 0xe4,
-
- REG_TX_OCTETS_OK = 0x100,
- REG_TX_OCTETS_BAD = 0x104,
- REG_TX_UC_PKTS = 0x108,
- REG_TX_MC_PKTS = 0x10c,
- REG_TX_BC_PKTS = 0x110,
- REG_TX_EXCESSIVE_LEN_DROP = 0x14c,
- REG_TX_UNDERRUN = 0x150,
- REG_TX_TAGGED = 0x154,
- REG_TX_PAUSE_FRAMES = 0x15C,
-
- /* Global registers */
- REG_PORT_ENABLE = 0x1400,
-
- REG_JTAG_ID = 0x1430,
-
- RX_FIFO_HIGH_WATERMARK_BASE = 0x1600,
- RX_FIFO_LOW_WATERMARK_BASE = 0x1628,
- RX_FIFO_FRAMES_REMOVED_BASE = 0x1650,
-
- REG_RX_ERR_DROP = 0x167c,
- REG_RX_FIFO_OVERFLOW_EVENT = 0x1680,
-
- TX_FIFO_HIGH_WATERMARK_BASE = 0x1800,
- TX_FIFO_LOW_WATERMARK_BASE = 0x1828,
- TX_FIFO_XFER_THRES_BASE = 0x1850,
-
- REG_TX_FIFO_OVERFLOW_EVENT = 0x1878,
- REG_TX_FIFO_OOS_EVENT = 0x1884,
-
- TX_FIFO_FRAMES_REMOVED_BASE = 0x1888,
-
- REG_SPI_RX_BURST = 0x1c00,
- REG_SPI_RX_TRAINING = 0x1c04,
- REG_SPI_RX_CALENDAR = 0x1c08,
- REG_SPI_TX_SYNC = 0x1c0c
-};
-
-enum { /* RMON registers */
- REG_RxOctetsTotalOK = 0x80,
- REG_RxOctetsBad = 0x84,
- REG_RxUCPkts = 0x88,
- REG_RxMCPkts = 0x8c,
- REG_RxBCPkts = 0x90,
- REG_RxJumboPkts = 0xac,
- REG_RxFCSErrors = 0xb0,
- REG_RxDataErrors = 0xb8,
- REG_RxAlignErrors = 0xbc,
- REG_RxLongErrors = 0xc0,
- REG_RxJabberErrors = 0xc4,
- REG_RxPauseMacControlCounter = 0xc8,
- REG_RxVeryLongErrors = 0xd0,
- REG_RxRuntErrors = 0xd4,
- REG_RxShortErrors = 0xd8,
- REG_RxSequenceErrors = 0xe0,
- REG_RxSymbolErrors = 0xe4,
-
- REG_TxOctetsTotalOK = 0x100,
- REG_TxOctetsBad = 0x104,
- REG_TxUCPkts = 0x108,
- REG_TxMCPkts = 0x10c,
- REG_TxBCPkts = 0x110,
- REG_TxJumboPkts = 0x12C,
- REG_TxTotalCollisions = 0x134,
- REG_TxExcessiveLengthDrop = 0x14c,
- REG_TxUnderrun = 0x150,
- REG_TxCRCErrors = 0x158,
- REG_TxPauseFrames = 0x15c
-};
-
-enum {
- DIVERSE_CONFIG_PAD_ENABLE = 0x80,
- DIVERSE_CONFIG_CRC_ADD = 0x40
-};
-
-#define MACREG_BASE 0
-#define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg))
-
-struct _cmac_instance {
- u32 mac_base;
- u32 index;
- u32 version;
- u32 ticks;
-};
-
-static void disable_port(struct cmac *mac)
-{
- u32 val;
-
- t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val);
- val &= ~(1 << mac->instance->index);
- t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
-}
-
-/*
- * Read the current values of the RMON counters and add them to the cumulative
- * port statistics. The HW RMON counters are cleared by this operation.
- */
-static void port_stats_update(struct cmac *mac)
-{
- static struct {
- unsigned int reg;
- unsigned int offset;
- } hw_stats[] = {
-
-#define HW_STAT(name, stat_name) \
- { REG_##name, \
- (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
-
- /* Rx stats */
- HW_STAT(RxOctetsTotalOK, RxOctetsOK),
- HW_STAT(RxOctetsBad, RxOctetsBad),
- HW_STAT(RxUCPkts, RxUnicastFramesOK),
- HW_STAT(RxMCPkts, RxMulticastFramesOK),
- HW_STAT(RxBCPkts, RxBroadcastFramesOK),
- HW_STAT(RxJumboPkts, RxJumboFramesOK),
- HW_STAT(RxFCSErrors, RxFCSErrors),
- HW_STAT(RxAlignErrors, RxAlignErrors),
- HW_STAT(RxLongErrors, RxFrameTooLongErrors),
- HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
- HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
- HW_STAT(RxDataErrors, RxDataErrors),
- HW_STAT(RxJabberErrors, RxJabberErrors),
- HW_STAT(RxRuntErrors, RxRuntErrors),
- HW_STAT(RxShortErrors, RxRuntErrors),
- HW_STAT(RxSequenceErrors, RxSequenceErrors),
- HW_STAT(RxSymbolErrors, RxSymbolErrors),
-
- /* Tx stats (skip collision stats as we are full-duplex only) */
- HW_STAT(TxOctetsTotalOK, TxOctetsOK),
- HW_STAT(TxOctetsBad, TxOctetsBad),
- HW_STAT(TxUCPkts, TxUnicastFramesOK),
- HW_STAT(TxMCPkts, TxMulticastFramesOK),
- HW_STAT(TxBCPkts, TxBroadcastFramesOK),
- HW_STAT(TxJumboPkts, TxJumboFramesOK),
- HW_STAT(TxPauseFrames, TxPauseFrames),
- HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
- HW_STAT(TxUnderrun, TxUnderrun),
- HW_STAT(TxCRCErrors, TxFCSErrors)
- }, *p = hw_stats;
- u64 *stats = (u64 *) &mac->stats;
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
- u32 val;
-
- t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
- stats[p->offset] += val;
- }
-}
-
-/* No-op interrupt operation as this MAC does not support interrupts */
-static int mac_intr_op(struct cmac *mac)
-{
- return 0;
-}
-
-/* Expect MAC address to be in network byte order. */
-static int mac_set_address(struct cmac *mac, u8 addr[6])
-{
- u32 addr_lo, addr_hi;
-
- addr_lo = addr[2];
- addr_lo = (addr_lo << 8) | addr[3];
- addr_lo = (addr_lo << 8) | addr[4];
- addr_lo = (addr_lo << 8) | addr[5];
-
- addr_hi = addr[0];
- addr_hi = (addr_hi << 8) | addr[1];
-
- t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo);
- t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi);
- return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
- u32 addr_lo, addr_hi;
-
- t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo);
- t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi);
-
- addr[0] = (u8) (addr_hi >> 8);
- addr[1] = (u8) addr_hi;
- addr[2] = (u8) (addr_lo >> 24);
- addr[3] = (u8) (addr_lo >> 16);
- addr[4] = (u8) (addr_lo >> 8);
- addr[5] = (u8) addr_lo;
- return 0;
-}
-
-/* This is intended to reset a port, not the whole MAC */
-static int mac_reset(struct cmac *mac)
-{
- return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
- u32 val, new_mode;
- adapter_t *adapter = mac->adapter;
- u32 addr_lo, addr_hi;
- u8 *addr;
-
- t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val);
- new_mode = val & ~7;
- if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0)
- new_mode |= 1; /* only set if version > 0 due to erratum */
- if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm)
- && t1_rx_mode_mc_cnt(rm) <= 1)
- new_mode |= 2;
- if (new_mode != val)
- t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode);
- switch (t1_rx_mode_mc_cnt(rm)) {
- case 0:
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0);
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0);
- break;
- case 1:
- addr = t1_get_next_mcaddr(rm);
- addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
- addr[5];
- addr_hi = (addr[0] << 8) | addr[1];
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo);
- t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi);
- break;
- default:
- break;
- }
- return 0;
-}
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
- /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
- if (mtu > (MAX_FRAME_SIZE - 14 - 4))
- return -EINVAL;
- t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
- mtu + 14 + 4);
- return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
- int fc)
-{
- u32 val;
-
- if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000)
- return -1;
- if (duplex >= 0 && duplex != DUPLEX_FULL)
- return -1;
-
- if (speed >= 0) {
- val = speed == SPEED_100 ? 1 : 2;
- t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val);
- }
-
- t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
- val &= ~3;
- if (fc & PAUSE_RX)
- val |= 1;
- if (fc & PAUSE_TX)
- val |= 2;
- t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val);
- return 0;
-}
-
-static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex,
- int *fc)
-{
- u32 val;
-
- if (duplex)
- *duplex = DUPLEX_FULL;
- if (speed) {
- t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED),
- &val);
- *speed = (val & 2) ? SPEED_1000 : SPEED_100;
- }
- if (fc) {
- t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val);
- *fc = 0;
- if (val & 1)
- *fc |= PAUSE_RX;
- if (val & 2)
- *fc |= PAUSE_TX;
- }
- return 0;
-}
-
-static void enable_port(struct cmac *mac)
-{
- u32 val;
- u32 index = mac->instance->index;
- adapter_t *adapter = mac->adapter;
-
- t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val);
- val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE;
- t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val);
- if (mac->instance->version > 0)
- t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3);
- else /* Don't enable unicast address filtering due to IXF1010 bug */
- t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2);
-
- t1_tpi_read(adapter, REG_RX_ERR_DROP, &val);
- val |= (1 << index);
- t1_tpi_write(adapter, REG_RX_ERR_DROP, val);
-
- /*
- * Clear the port RMON registers by adding their current values to the
- * cumulatice port stats and then clearing the stats. Really.
- */
- port_stats_update(mac);
- memset(&mac->stats, 0, sizeof(struct cmac_statistics));
- mac->instance->ticks = 0;
-
- t1_tpi_read(adapter, REG_PORT_ENABLE, &val);
- val |= (1 << index);
- t1_tpi_write(adapter, REG_PORT_ENABLE, val);
-
- index <<= 2;
- if (is_T2(adapter)) {
- /* T204: set the Fifo water level & threshold */
- t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
- t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
- t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600);
- t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0);
- t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100);
- } else {
- /*
- * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around
- * Underrun problem. Intel has blessed this solution.
- */
- t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400);
- }
-}
-
-/* IXF1010 ports do not have separate enables for TX and RX */
-static int mac_enable(struct cmac *mac, int which)
-{
- if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
- enable_port(mac);
- return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
- if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX))
- disable_port(mac);
- return 0;
-}
-
-#define RMON_UPDATE(mac, name, stat_name) \
- t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
- (mac)->stats.stat_name += val;
-
-/*
- * This function is called periodically to accumulate the current values of the
- * RMON counters into the port statistics. Since the counters are only 32 bits
- * some of them can overflow in less than a minute at GigE speeds, so this
- * function should be called every 30 seconds or so.
- *
- * To cut down on reading costs we update only the octet counters at each tick
- * and do a full update at major ticks, which can be every 30 minutes or more.
- */
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
- int flag)
-{
- if (flag == MAC_STATS_UPDATE_FULL ||
- MAJOR_UPDATE_TICKS <= mac->instance->ticks) {
- port_stats_update(mac);
- mac->instance->ticks = 0;
- } else {
- u32 val;
-
- RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
- RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
- mac->instance->ticks++;
- }
- return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
- kfree(mac);
-}
-
-static struct cmac_ops ixf1010_ops = {
- .destroy = mac_destroy,
- .reset = mac_reset,
- .interrupt_enable = mac_intr_op,
- .interrupt_disable = mac_intr_op,
- .interrupt_clear = mac_intr_op,
- .enable = mac_enable,
- .disable = mac_disable,
- .set_mtu = mac_set_mtu,
- .set_rx_mode = mac_set_rx_mode,
- .set_speed_duplex_fc = mac_set_speed_duplex_fc,
- .get_speed_duplex_fc = mac_get_speed_duplex_fc,
- .statistics_update = mac_update_statistics,
- .macaddress_get = mac_get_address,
- .macaddress_set = mac_set_address,
-};
-
-static int ixf1010_mac_reset(adapter_t *adapter)
-{
- u32 val;
-
- t1_tpi_read(adapter, A_ELMER0_GPO, &val);
- if ((val & 1) != 0) {
- val &= ~1;
- t1_tpi_write(adapter, A_ELMER0_GPO, val);
- udelay(2);
- }
- val |= 1;
- t1_tpi_write(adapter, A_ELMER0_GPO, val);
- udelay(2);
-
- t1_tpi_write(adapter, REG_PORT_ENABLE, 0);
- return 0;
-}
-
-static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
-{
- struct cmac *mac;
- u32 val;
-
- if (index > 9)
- return NULL;
-
- mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
- if (!mac)
- return NULL;
-
- mac->ops = &ixf1010_ops;
- mac->instance = (cmac_instance *)(mac + 1);
-
- mac->instance->mac_base = MACREG_BASE + (index * 0x200);
- mac->instance->index = index;
- mac->adapter = adapter;
- mac->instance->ticks = 0;
-
- t1_tpi_read(adapter, REG_JTAG_ID, &val);
- mac->instance->version = val >> 28;
- return mac;
-}
-
-struct gmac t1_ixf1010_ops = {
- STATS_TICK_SECS,
- ixf1010_mac_create,
- ixf1010_mac_reset
-};
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
index 6af39dc7045..1d972825eac 100644
--- a/drivers/net/chelsio/mac.c
+++ b/drivers/net/chelsio/mac.c
@@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t *adapter, int index)
return mac;
}
-struct gmac t1_chelsio_mac_ops = {
+const struct gmac t1_chelsio_mac_ops = {
.create = mac_create
};
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c
index 5867e3b0a88..0632be0d649 100644
--- a/drivers/net/chelsio/mv88e1xxx.c
+++ b/drivers/net/chelsio/mv88e1xxx.c
@@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = {
};
static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops)
+ const struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
@@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t* adapter)
return 0;
}
-struct gphy t1_mv88e1xxx_ops = {
- mv88e1xxx_phy_create,
- mv88e1xxx_phy_reset
+const struct gphy t1_mv88e1xxx_ops = {
+ .create = mv88e1xxx_phy_create,
+ .reset = mv88e1xxx_phy_reset
};
diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c
index c8e89480d90..cd856041af3 100644
--- a/drivers/net/chelsio/mv88x201x.c
+++ b/drivers/net/chelsio/mv88x201x.c
@@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = {
};
static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops)
+ const struct mdio_ops *mdio_ops)
{
u32 val;
struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
@@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t *adapter)
return 0;
}
-struct gphy t1_mv88x201x_ops = {
- mv88x201x_phy_create,
- mv88x201x_phy_reset
+const struct gphy t1_mv88x201x_ops = {
+ .create = mv88x201x_phy_create,
+ .reset = mv88x201x_phy_reset
};
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c
index 87dde3e6004..040acd29995 100644
--- a/drivers/net/chelsio/my3126.c
+++ b/drivers/net/chelsio/my3126.c
@@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = {
};
static struct cphy *my3126_phy_create(adapter_t *adapter,
- int phy_addr, struct mdio_ops *mdio_ops)
+ int phy_addr, const struct mdio_ops *mdio_ops)
{
struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL);
@@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * adapter)
return 0;
}
-struct gphy t1_my3126_ops = {
- my3126_phy_create,
- my3126_phy_reset
+const struct gphy t1_my3126_ops = {
+ .create = my3126_phy_create,
+ .reset = my3126_phy_reset
};
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c
index 69129edeefd..678778a8d13 100644
--- a/drivers/net/chelsio/pm3393.c
+++ b/drivers/net/chelsio/pm3393.c
@@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * adapter)
return successful_reset ? 0 : 1;
}
-struct gmac t1_pm3393_ops = {
- STATS_TICK_SECS,
- pm3393_mac_create,
- pm3393_mac_reset
+const struct gmac t1_pm3393_ops = {
+ .stats_update_period = STATS_TICK_SECS,
+ .create = pm3393_mac_create,
+ .reset = pm3393_mac_reset,
};
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index c2522cdfab3..7de9a611e1f 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr,
}
#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
-static struct mdio_ops mi1_mdio_ops = {
- mi1_mdio_init,
- mi1_mdio_read,
- mi1_mdio_write
+static const struct mdio_ops mi1_mdio_ops = {
+ .init = mi1_mdio_init,
+ .read = mi1_mdio_read,
+ .write = mi1_mdio_write
};
#endif
@@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
return 0;
}
-static struct mdio_ops mi1_mdio_ext_ops = {
- mi1_mdio_init,
- mi1_mdio_ext_read,
- mi1_mdio_ext_write
+static const struct mdio_ops mi1_mdio_ext_ops = {
+ .init = mi1_mdio_init,
+ .read = mi1_mdio_ext_read,
+ .write = mi1_mdio_ext_write
};
enum {
@@ -392,63 +392,136 @@ enum {
CH_BRD_N204_4CU,
};
-static struct board_info t1_board[] = {
-
-{ CHBT_BOARD_CHT110, 1/*ports#*/,
- SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1,
- CHBT_MAC_PM3393, CHBT_PHY_MY3126,
- 125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
- 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_my3126_ops, &mi1_mdio_ext_ops,
- "Chelsio T110 1x10GBase-CX4 TOE" },
-
-{ CHBT_BOARD_N110, 1/*ports#*/,
- SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1,
- CHBT_MAC_PM3393, CHBT_PHY_88X2010,
- 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
- "Chelsio N110 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_N210, 1/*ports#*/,
- SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2,
- CHBT_MAC_PM3393, CHBT_PHY_88X2010,
- 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
- "Chelsio N210 1x10GBaseX NIC" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
- SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
- CHBT_MAC_PM3393, CHBT_PHY_88X2010,
- 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_mv88x201x_ops, &mi1_mdio_ext_ops,
- "Chelsio T210 1x10GBaseX TOE" },
-
-{ CHBT_BOARD_CHT210, 1/*ports#*/,
- SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2,
- CHBT_MAC_PM3393, CHBT_PHY_MY3126,
- 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/,
- 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/,
- 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops,
- &t1_my3126_ops, &mi1_mdio_ext_ops,
- "Chelsio T210 1x10GBase-CX4 TOE" },
+static const struct board_info t1_board[] = {
+ {
+ .board = CHBT_BOARD_CHT110,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full,
+ .chip_term = CHBT_TERM_T1,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_MY3126,
+ .clock_core = 125000000,
+ .clock_mc3 = 150000000,
+ .clock_mc4 = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 1,
+ .mdio_mdiinv = 1,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 1,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_my3126_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio T110 1x10GBase-CX4 TOE",
+ },
+
+ {
+ .board = CHBT_BOARD_N110,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+ .chip_term = CHBT_TERM_T1,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_88X2010,
+ .clock_core = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 0,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_mv88x201x_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio N110 1x10GBaseX NIC",
+ },
+
+ {
+ .board = CHBT_BOARD_N210,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_88X2010,
+ .clock_core = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 0,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_mv88x201x_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio N210 1x10GBaseX NIC",
+ },
+
+ {
+ .board = CHBT_BOARD_CHT210,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_88X2010,
+ .clock_core = 125000000,
+ .clock_mc3 = 133000000,
+ .clock_mc4 = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 0,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_mv88x201x_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio T210 1x10GBaseX TOE",
+ },
+
+ {
+ .board = CHBT_BOARD_CHT210,
+ .port_number = 1,
+ .caps = SUPPORTED_10000baseT_Full,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_PM3393,
+ .chip_phy = CHBT_PHY_MY3126,
+ .clock_core = 125000000,
+ .clock_mc3 = 133000000,
+ .clock_mc4 = 125000000,
+ .espi_nports = 1,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 1,
+ .mdio_mdiinv = 1,
+ .mdio_mdc = 1,
+ .mdio_phybaseaddr = 1,
+ .gmac = &t1_pm3393_ops,
+ .gphy = &t1_my3126_ops,
+ .mdio_ops = &mi1_mdio_ext_ops,
+ .desc = "Chelsio T210 1x10GBase-CX4 TOE",
+ },
#ifdef CONFIG_CHELSIO_T1_1G
-{ CHBT_BOARD_CHN204, 4/*ports#*/,
- SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
- SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111,
- 100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/,
- 4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/,
- 0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops,
- &t1_mv88e1xxx_ops, &mi1_mdio_ops,
- "Chelsio N204 4x100/1000BaseT NIC" },
+ {
+ .board = CHBT_BOARD_CHN204,
+ .port_number = 4,
+ .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+ | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+ SUPPORTED_PAUSE | SUPPORTED_TP,
+ .chip_term = CHBT_TERM_T2,
+ .chip_mac = CHBT_MAC_VSC7321,
+ .chip_phy = CHBT_PHY_88E1111,
+ .clock_core = 100000000,
+ .espi_nports = 4,
+ .clock_elmer0 = 44,
+ .mdio_mdien = 0,
+ .mdio_mdiinv = 0,
+ .mdio_mdc = 0,
+ .mdio_phybaseaddr = 4,
+ .gmac = &t1_vsc7326_ops,
+ .gphy = &t1_mv88e1xxx_ops,
+ .mdio_ops = &mi1_mdio_ops,
+ .desc = "Chelsio N204 4x100/1000BaseT NIC",
+ },
#endif
};
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c
index 534ffa0f616..99b51f61fe7 100644
--- a/drivers/net/chelsio/vsc7326.c
+++ b/drivers/net/chelsio/vsc7326.c
@@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t *adapter)
return 0;
}
-struct gmac t1_vsc7326_ops = {
+const struct gmac t1_vsc7326_ops = {
.stats_update_period = STATS_TICK_SECS,
.create = vsc7326_mac_create,
.reset = vsc7326_mac_reset,
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c
deleted file mode 100644
index 251d4859c91..00000000000
--- a/drivers/net/chelsio/vsc8244.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * This file is part of the Chelsio T2 Ethernet driver.
- *
- * Copyright (C) 2005 Chelsio Communications. All rights reserved.
- *
- * 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 LICENSE file included in this
- * release for licensing terms and conditions.
- */
-
-#include "common.h"
-#include "cphy.h"
-#include "elmer0.h"
-
-#ifndef ADVERTISE_PAUSE_CAP
-# define ADVERTISE_PAUSE_CAP 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#ifndef MII_CTRL1000
-# define MII_CTRL1000 9
-#endif
-
-#ifndef ADVERTISE_1000FULL
-# define ADVERTISE_1000FULL 0x200
-# define ADVERTISE_1000HALF 0x100
-#endif
-
-/* VSC8244 PHY specific registers. */
-enum {
- VSC8244_INTR_ENABLE = 25,
- VSC8244_INTR_STATUS = 26,
- VSC8244_AUX_CTRL_STAT = 28,
-};
-
-enum {
- VSC_INTR_RX_ERR = 1 << 0,
- VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
- VSC_INTR_CABLE = 1 << 2, /* cable impairment */
- VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
- VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
- VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
- VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
- VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
- VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
- VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
- VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
- VSC_INTR_LINK_CHG = 1 << 13, /* link change */
- VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
-};
-
-#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
- VSC_INTR_NEG_DONE)
-#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
- VSC_INTR_ENABLE)
-
-/* PHY specific auxiliary control & status register fields */
-#define S_ACSR_ACTIPHY_TMR 0
-#define M_ACSR_ACTIPHY_TMR 0x3
-#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
-
-#define S_ACSR_SPEED 3
-#define M_ACSR_SPEED 0x3
-#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
-
-#define S_ACSR_DUPLEX 5
-#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
-
-#define S_ACSR_ACTIPHY 6
-#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
-
-/*
- * Reset the PHY. This PHY completes reset immediately so we never wait.
- */
-static int vsc8244_reset(struct cphy *cphy, int wait)
-{
- int err;
- unsigned int ctl;
-
- err = simple_mdio_read(cphy, MII_BMCR, &ctl);
- if (err)
- return err;
-
- ctl &= ~BMCR_PDOWN;
- ctl |= BMCR_RESET;
- return simple_mdio_write(cphy, MII_BMCR, ctl);
-}
-
-static int vsc8244_intr_enable(struct cphy *cphy)
-{
- simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
-
- /* Enable interrupts through Elmer */
- if (t1_is_asic(cphy->adapter)) {
- u32 elmer;
-
- t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
- elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter))
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
- }
-
- return 0;
-}
-
-static int vsc8244_intr_disable(struct cphy *cphy)
-{
- simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0);
-
- if (t1_is_asic(cphy->adapter)) {
- u32 elmer;
-
- t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
- elmer &= ~ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter))
- elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
- t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
- }
-
- return 0;
-}
-
-static int vsc8244_intr_clear(struct cphy *cphy)
-{
- u32 val;
- u32 elmer;
-
- /* Clear PHY interrupts by reading the register. */
- simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
-
- if (t1_is_asic(cphy->adapter)) {
- t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
- elmer |= ELMER0_GP_BIT1;
- if (is_T2(cphy->adapter))
- elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
- t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
- }
-
- return 0;
-}
-
-/*
- * Force the PHY speed and duplex. This also disables auto-negotiation, except
- * for 1Gb/s, where auto-negotiation is mandatory.
- */
-static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
-{
- int err;
- unsigned int ctl;
-
- err = simple_mdio_read(phy, MII_BMCR, &ctl);
- if (err)
- return err;
-
- if (speed >= 0) {
- ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
- if (speed == SPEED_100)
- ctl |= BMCR_SPEED100;
- else if (speed == SPEED_1000)
- ctl |= BMCR_SPEED1000;
- }
- if (duplex >= 0) {
- ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
- if (duplex == DUPLEX_FULL)
- ctl |= BMCR_FULLDPLX;
- }
- if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */
- ctl |= BMCR_ANENABLE;
- return simple_mdio_write(phy, MII_BMCR, ctl);
-}
-
-int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
-{
- int ret;
- unsigned int val;
-
- ret = mdio_read(phy, mmd, reg, &val);
- if (!ret)
- ret = mdio_write(phy, mmd, reg, val | bits);
- return ret;
-}
-
-static int vsc8244_autoneg_enable(struct cphy *cphy)
-{
- return t1_mdio_set_bits(cphy, 0, MII_BMCR,
- BMCR_ANENABLE | BMCR_ANRESTART);
-}
-
-static int vsc8244_autoneg_restart(struct cphy *cphy)
-{
- return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART);
-}
-
-static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
-{
- int err;
- unsigned int val = 0;
-
- err = simple_mdio_read(phy, MII_CTRL1000, &val);
- if (err)
- return err;
-
- val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
- if (advertise_map & ADVERTISED_1000baseT_Half)
- val |= ADVERTISE_1000HALF;
- if (advertise_map & ADVERTISED_1000baseT_Full)
- val |= ADVERTISE_1000FULL;
-
- err = simple_mdio_write(phy, MII_CTRL1000, val);
- if (err)
- return err;
-
- val = 1;
- if (advertise_map & ADVERTISED_10baseT_Half)
- val |= ADVERTISE_10HALF;
- if (advertise_map & ADVERTISED_10baseT_Full)
- val |= ADVERTISE_10FULL;
- if (advertise_map & ADVERTISED_100baseT_Half)
- val |= ADVERTISE_100HALF;
- if (advertise_map & ADVERTISED_100baseT_Full)
- val |= ADVERTISE_100FULL;
- if (advertise_map & ADVERTISED_PAUSE)
- val |= ADVERTISE_PAUSE_CAP;
- if (advertise_map & ADVERTISED_ASYM_PAUSE)
- val |= ADVERTISE_PAUSE_ASYM;
- return simple_mdio_write(phy, MII_ADVERTISE, val);
-}
-
-static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
- int *speed, int *duplex, int *fc)
-{
- unsigned int bmcr, status, lpa, adv;
- int err, sp = -1, dplx = -1, pause = 0;
-
- err = simple_mdio_read(cphy, MII_BMCR, &bmcr);
- if (!err)
- err = simple_mdio_read(cphy, MII_BMSR, &status);
- if (err)
- return err;
-
- if (link_ok) {
- /*
- * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
- * once more to get the current link state.
- */
- if (!(status & BMSR_LSTATUS))
- err = simple_mdio_read(cphy, MII_BMSR, &status);
- if (err)
- return err;
- *link_ok = (status & BMSR_LSTATUS) != 0;
- }
- if (!(bmcr & BMCR_ANENABLE)) {
- dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
- if (bmcr & BMCR_SPEED1000)
- sp = SPEED_1000;
- else if (bmcr & BMCR_SPEED100)
- sp = SPEED_100;
- else
- sp = SPEED_10;
- } else if (status & BMSR_ANEGCOMPLETE) {
- err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status);
- if (err)
- return err;
-
- dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
- sp = G_ACSR_SPEED(status);
- if (sp == 0)
- sp = SPEED_10;
- else if (sp == 1)
- sp = SPEED_100;
- else
- sp = SPEED_1000;
-
- if (fc && dplx == DUPLEX_FULL) {
- err = simple_mdio_read(cphy, MII_LPA, &lpa);
- if (!err)
- err = simple_mdio_read(cphy, MII_ADVERTISE,
- &adv);
- if (err)
- return err;
-
- if (lpa & adv & ADVERTISE_PAUSE_CAP)
- pause = PAUSE_RX | PAUSE_TX;
- else if ((lpa & ADVERTISE_PAUSE_CAP) &&
- (lpa & ADVERTISE_PAUSE_ASYM) &&
- (adv & ADVERTISE_PAUSE_ASYM))
- pause = PAUSE_TX;
- else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
- (adv & ADVERTISE_PAUSE_CAP))
- pause = PAUSE_RX;
- }
- }
- if (speed)
- *speed = sp;
- if (duplex)
- *duplex = dplx;
- if (fc)
- *fc = pause;
- return 0;
-}
-
-static int vsc8244_intr_handler(struct cphy *cphy)
-{
- unsigned int cause;
- int err, cphy_cause = 0;
-
- err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause);
- if (err)
- return err;
-
- cause &= INTR_MASK;
- if (cause & CFG_CHG_INTR_MASK)
- cphy_cause |= cphy_cause_link_change;
- if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
- cphy_cause |= cphy_cause_fifo_error;
- return cphy_cause;
-}
-
-static void vsc8244_destroy(struct cphy *cphy)
-{
- kfree(cphy);
-}
-
-static struct cphy_ops vsc8244_ops = {
- .destroy = vsc8244_destroy,
- .reset = vsc8244_reset,
- .interrupt_enable = vsc8244_intr_enable,
- .interrupt_disable = vsc8244_intr_disable,
- .interrupt_clear = vsc8244_intr_clear,
- .interrupt_handler = vsc8244_intr_handler,
- .autoneg_enable = vsc8244_autoneg_enable,
- .autoneg_restart = vsc8244_autoneg_restart,
- .advertise = vsc8244_advertise,
- .set_speed_duplex = vsc8244_set_speed_duplex,
- .get_link_status = vsc8244_get_link_status
-};
-
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
- struct mdio_ops *mdio_ops)
-{
- struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
-
- if (!cphy)
- return NULL;
-
- cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
-
- return cphy;
-}
-
-
-static int vsc8244_phy_reset(adapter_t* adapter)
-{
- return 0;
-}
-
-struct gphy t1_vsc8244_ops = {
- vsc8244_phy_create,
- vsc8244_phy_reset
-};
-
-
diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h
deleted file mode 100644
index d3c1829055c..00000000000
--- a/drivers/net/chelsio/vsc8244_reg.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */
-#ifndef CHELSIO_MV8E1XXX_H
-#define CHELSIO_MV8E1XXX_H
-
-#ifndef BMCR_SPEED1000
-# define BMCR_SPEED1000 0x40
-#endif
-
-#ifndef ADVERTISE_PAUSE
-# define ADVERTISE_PAUSE 0x400
-#endif
-#ifndef ADVERTISE_PAUSE_ASYM
-# define ADVERTISE_PAUSE_ASYM 0x800
-#endif
-
-/* Gigabit MII registers */
-#define MII_GBMR 1 /* 1000Base-T mode register */
-#define MII_GBCR 9 /* 1000Base-T control register */
-#define MII_GBSR 10 /* 1000Base-T status register */
-
-/* 1000Base-T control register fields */
-#define GBCR_ADV_1000HALF 0x100
-#define GBCR_ADV_1000FULL 0x200
-#define GBCR_PREFER_MASTER 0x400
-#define GBCR_MANUAL_AS_MASTER 0x800
-#define GBCR_MANUAL_CONFIG_ENABLE 0x1000
-
-/* 1000Base-T status register fields */
-#define GBSR_LP_1000HALF 0x400
-#define GBSR_LP_1000FULL 0x800
-#define GBSR_REMOTE_OK 0x1000
-#define GBSR_LOCAL_OK 0x2000
-#define GBSR_LOCAL_MASTER 0x4000
-#define GBSR_MASTER_FAULT 0x8000
-
-/* Vitesse PHY interrupt status bits. */
-#if 0
-#define VSC8244_INTR_JABBER 0x0001
-#define VSC8244_INTR_POLARITY_CHNG 0x0002
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-#define VSC8244_INTR_DOWNSHIFT 0x0020
-#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_FALSE_CARRIER 0x0100
-#define VSC8244_INTR_SYMBOL_ERROR 0x0200
-#define VSC8244_INTR_LINK_CHNG 0x0400
-#define VSC8244_INTR_AUTONEG_DONE 0x0800
-#define VSC8244_INTR_PAGE_RECV 0x1000
-#define VSC8244_INTR_DUPLEX_CHNG 0x2000
-#define VSC8244_INTR_SPEED_CHNG 0x4000
-#define VSC8244_INTR_AUTONEG_ERR 0x8000
-#else
-//#define VSC8244_INTR_JABBER 0x0001
-//#define VSC8244_INTR_POLARITY_CHNG 0x0002
-//#define VSC8244_INTR_BIT2 0x0004
-//#define VSC8244_INTR_BIT3 0x0008
-#define VSC8244_INTR_RX_ERR 0x0001
-#define VSC8244_INTR_MASTER_SLAVE 0x0002
-#define VSC8244_INTR_CABLE_IMPAIRED 0x0004
-#define VSC8244_INTR_FALSE_CARRIER 0x0008
-//#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010
-//#define VSC8244_INTR_DOWNSHIFT 0x0020
-//#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040
-//#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080
-#define VSC8244_INTR_BIT4 0x0010
-#define VSC8244_INTR_FIFO_RX 0x0020
-#define VSC8244_INTR_FIFO_OVER_UNDER 0x0040
-#define VSC8244_INTR_LOCK_LOST 0x0080
-//#define VSC8244_INTR_FALSE_CARRIER 0x0100
-//#define VSC8244_INTR_SYMBOL_ERROR 0x0200
-//#define VSC8244_INTR_LINK_CHNG 0x0400
-//#define VSC8244_INTR_AUTONEG_DONE 0x0800
-#define VSC8244_INTR_SYMBOL_ERROR 0x0100
-#define VSC8244_INTR_ENG_DETECT_CHNG 0x0200
-#define VSC8244_INTR_AUTONEG_DONE 0x0400
-#define VSC8244_INTR_AUTONEG_ERR 0x0800
-//#define VSC8244_INTR_PAGE_RECV 0x1000
-//#define VSC8244_INTR_DUPLEX_CHNG 0x2000
-//#define VSC8244_INTR_SPEED_CHNG 0x4000
-//#define VSC8244_INTR_AUTONEG_ERR 0x8000
-#define VSC8244_INTR_DUPLEX_CHNG 0x1000
-#define VSC8244_INTR_LINK_CHNG 0x2000
-#define VSC8244_INTR_SPEED_CHNG 0x4000
-#define VSC8244_INTR_STATUS 0x8000
-#endif
-
-
-/* Vitesse PHY specific registers. */
-#define VSC8244_SPECIFIC_CNTRL_REGISTER 16
-#define VSC8244_SPECIFIC_STATUS_REGISTER 0x1c
-#define VSC8244_INTERRUPT_ENABLE_REGISTER 0x19
-#define VSC8244_INTERRUPT_STATUS_REGISTER 0x1a
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20
-#define VSC8244_RECV_ERR_CNTR_REGISTER 21
-#define VSC8244_RES_REGISTER 22
-#define VSC8244_GLOBAL_STATUS_REGISTER 23
-#define VSC8244_LED_CONTROL_REGISTER 24
-#define VSC8244_MANUAL_LED_OVERRIDE_REGISTER 25
-#define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26
-#define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER 27
-#define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER 28
-#define VSC8244_EXTENDED_ADDR_REGISTER 29
-#define VSC8244_EXTENDED_REGISTER 30
-
-/* PHY specific control register fields */
-#define S_PSCR_MDI_XOVER_MODE 5
-#define M_PSCR_MDI_XOVER_MODE 0x3
-#define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE)
-#define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE)
-
-/* Extended PHY specific control register fields */
-#define S_DOWNSHIFT_ENABLE 8
-#define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE)
-
-#define S_DOWNSHIFT_CNT 9
-#define M_DOWNSHIFT_CNT 0x7
-#define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT)
-#define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT)
-
-/* PHY specific status register fields */
-#define S_PSSR_JABBER 0
-#define V_PSSR_JABBER (1 << S_PSSR_JABBER)
-
-#define S_PSSR_POLARITY 1
-#define V_PSSR_POLARITY (1 << S_PSSR_POLARITY)
-
-#define S_PSSR_RX_PAUSE 2
-#define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE)
-
-#define S_PSSR_TX_PAUSE 3
-#define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE)
-
-#define S_PSSR_ENERGY_DETECT 4
-#define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT)
-
-#define S_PSSR_DOWNSHIFT_STATUS 5
-#define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS)
-
-#define S_PSSR_MDI 6
-#define V_PSSR_MDI (1 << S_PSSR_MDI)
-
-#define S_PSSR_CABLE_LEN 7
-#define M_PSSR_CABLE_LEN 0x7
-#define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN)
-#define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN)
-
-//#define S_PSSR_LINK 10
-//#define S_PSSR_LINK 13
-#define S_PSSR_LINK 2
-#define V_PSSR_LINK (1 << S_PSSR_LINK)
-
-//#define S_PSSR_STATUS_RESOLVED 11
-//#define S_PSSR_STATUS_RESOLVED 10
-#define S_PSSR_STATUS_RESOLVED 15
-#define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED)
-
-#define S_PSSR_PAGE_RECEIVED 12
-#define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED)
-
-//#define S_PSSR_DUPLEX 13
-//#define S_PSSR_DUPLEX 12
-#define S_PSSR_DUPLEX 5
-#define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX)
-
-//#define S_PSSR_SPEED 14
-//#define S_PSSR_SPEED 14
-#define S_PSSR_SPEED 3
-#define M_PSSR_SPEED 0x3
-#define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED)
-#define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED)
-
-#endif
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 042e27e291c..b112317f033 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -38,7 +38,7 @@
#define DRV_VERSION "1.0-ko"
/* Firmware version */
-#define FW_VERSION_MAJOR 3
-#define FW_VERSION_MINOR 3
+#define FW_VERSION_MAJOR 4
+#define FW_VERSION_MINOR 0
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 8cc1174e7f6..264fa0e2e07 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -77,9 +77,6 @@
#define DM9000_PHY 0x40 /* PHY address 0x01 */
-#define TRUE 1
-#define FALSE 0
-
#define CARDNAME "dm9000"
#define PFX CARDNAME ": "
@@ -601,7 +598,7 @@ dm9000_probe(struct platform_device *pdev)
printk("%s: not found (%d).\n", CARDNAME, ret);
dm9000_release_board(pdev, db);
- kfree(ndev);
+ free_netdev(ndev);
return ret;
}
@@ -896,7 +893,7 @@ dm9000_rx(struct net_device *dev)
struct dm9000_rxhdr rxhdr;
struct sk_buff *skb;
u8 rxbyte, *rdptr;
- int GoodPacket;
+ bool GoodPacket;
int RxLen;
/* Check packet ready or not */
@@ -918,7 +915,7 @@ dm9000_rx(struct net_device *dev)
return;
/* A packet ready now & Get status/length */
- GoodPacket = TRUE;
+ GoodPacket = true;
writeb(DM9000_MRCMD, db->io_addr);
(db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));
@@ -927,7 +924,7 @@ dm9000_rx(struct net_device *dev)
/* Packet Status check */
if (RxLen < 0x40) {
- GoodPacket = FALSE;
+ GoodPacket = false;
PRINTK1("Bad Packet received (runt)\n");
}
@@ -936,7 +933,7 @@ dm9000_rx(struct net_device *dev)
}
if (rxhdr.RxStatus & 0xbf00) {
- GoodPacket = FALSE;
+ GoodPacket = false;
if (rxhdr.RxStatus & 0x100) {
PRINTK1("fifo error\n");
db->stats.rx_fifo_errors++;
@@ -1193,7 +1190,7 @@ dm9000_drv_remove(struct platform_device *pdev)
unregister_netdev(ndev);
dm9000_release_board(pdev, (board_info_t *) ndev->priv);
- kfree(ndev); /* free device structure */
+ free_netdev(ndev); /* free device structure */
PRINTK1("clean_module() exit\n");
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 4d0e0aea72b..61696637a21 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -159,7 +159,7 @@
#define DRV_NAME "e100"
#define DRV_EXT "-NAPI"
-#define DRV_VERSION "3.5.17-k2"DRV_EXT
+#define DRV_VERSION "3.5.17-k4"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
#define PFX DRV_NAME ": "
@@ -174,10 +174,13 @@ MODULE_VERSION(DRV_VERSION);
static int debug = 3;
static int eeprom_bad_csum_allow = 0;
+static int use_io = 0;
module_param(debug, int, 0);
module_param(eeprom_bad_csum_allow, int, 0);
+module_param(use_io, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
+MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
#define DPRINTK(nlevel, klevel, fmt, args...) \
(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -282,12 +285,6 @@ enum scb_status {
rus_mask = 0x3C,
};
-enum ru_state {
- RU_SUSPENDED = 0,
- RU_RUNNING = 1,
- RU_UNINITIALIZED = -1,
-};
-
enum scb_stat_ack {
stat_ack_not_ours = 0x00,
stat_ack_sw_gen = 0x04,
@@ -529,7 +526,6 @@ struct nic {
struct rx *rx_to_use;
struct rx *rx_to_clean;
struct rfd blank_rfd;
- enum ru_state ru_running;
spinlock_t cb_lock ____cacheline_aligned;
spinlock_t cmd_lock;
@@ -591,7 +587,7 @@ static inline void e100_write_flush(struct nic *nic)
{
/* Flush previous PCI writes through intermediate bridges
* by doing a benign read */
- (void)readb(&nic->csr->scb.status);
+ (void)ioread8(&nic->csr->scb.status);
}
static void e100_enable_irq(struct nic *nic)
@@ -599,7 +595,7 @@ static void e100_enable_irq(struct nic *nic)
unsigned long flags;
spin_lock_irqsave(&nic->cmd_lock, flags);
- writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+ iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi);
e100_write_flush(nic);
spin_unlock_irqrestore(&nic->cmd_lock, flags);
}
@@ -609,7 +605,7 @@ static void e100_disable_irq(struct nic *nic)
unsigned long flags;
spin_lock_irqsave(&nic->cmd_lock, flags);
- writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+ iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi);
e100_write_flush(nic);
spin_unlock_irqrestore(&nic->cmd_lock, flags);
}
@@ -618,11 +614,11 @@ static void e100_hw_reset(struct nic *nic)
{
/* Put CU and RU into idle with a selective reset to get
* device off of PCI bus */
- writel(selective_reset, &nic->csr->port);
+ iowrite32(selective_reset, &nic->csr->port);
e100_write_flush(nic); udelay(20);
/* Now fully reset device */
- writel(software_reset, &nic->csr->port);
+ iowrite32(software_reset, &nic->csr->port);
e100_write_flush(nic); udelay(20);
/* Mask off our interrupt line - it's unmasked after reset */
@@ -639,7 +635,7 @@ static int e100_self_test(struct nic *nic)
nic->mem->selftest.signature = 0;
nic->mem->selftest.result = 0xFFFFFFFF;
- writel(selftest | dma_addr, &nic->csr->port);
+ iowrite32(selftest | dma_addr, &nic->csr->port);
e100_write_flush(nic);
/* Wait 10 msec for self-test to complete */
msleep(10);
@@ -677,23 +673,23 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data)
for(j = 0; j < 3; j++) {
/* Chip select */
- writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
for(i = 31; i >= 0; i--) {
ctrl = (cmd_addr_data[j] & (1 << i)) ?
eecs | eedi : eecs;
- writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
- writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
}
/* Wait 10 msec for cmd to complete */
msleep(10);
/* Chip deselect */
- writeb(0, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(0, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
}
};
@@ -709,21 +705,21 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
/* Chip select */
- writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
/* Bit-bang to read word from eeprom */
for(i = 31; i >= 0; i--) {
ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
- writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
- writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
/* Eeprom drives a dummy zero to EEDO after receiving
* complete address. Use this to adjust addr_len. */
- ctrl = readb(&nic->csr->eeprom_ctrl_lo);
+ ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
if(!(ctrl & eedo) && i > 16) {
*addr_len -= (i - 16);
i = 17;
@@ -733,7 +729,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
}
/* Chip deselect */
- writeb(0, &nic->csr->eeprom_ctrl_lo);
+ iowrite8(0, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
return le16_to_cpu(data);
@@ -804,7 +800,7 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
/* Previous command is accepted when SCB clears */
for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
- if(likely(!readb(&nic->csr->scb.cmd_lo)))
+ if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
break;
cpu_relax();
if(unlikely(i > E100_WAIT_SCB_FAST))
@@ -816,8 +812,8 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
}
if(unlikely(cmd != cuc_resume))
- writel(dma_addr, &nic->csr->scb.gen_ptr);
- writeb(cmd, &nic->csr->scb.cmd_lo);
+ iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
+ iowrite8(cmd, &nic->csr->scb.cmd_lo);
err_unlock:
spin_unlock_irqrestore(&nic->cmd_lock, flags);
@@ -895,7 +891,7 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
*/
spin_lock_irqsave(&nic->mdio_lock, flags);
for (i = 100; i; --i) {
- if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
+ if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready)
break;
udelay(20);
}
@@ -905,11 +901,11 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
spin_unlock_irqrestore(&nic->mdio_lock, flags);
return 0; /* No way to indicate timeout error */
}
- writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
+ iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
for (i = 0; i < 100; i++) {
udelay(20);
- if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+ if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready)
break;
}
spin_unlock_irqrestore(&nic->mdio_lock, flags);
@@ -951,7 +947,7 @@ static void e100_get_defaults(struct nic *nic)
((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i));
/* Template for a freshly allocated RFD */
- nic->blank_rfd.command = cpu_to_le16(cb_el);
+ nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s);
nic->blank_rfd.rbd = 0xFFFFFFFF;
nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN);
@@ -1318,7 +1314,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb,
}
/* ack any interupts, something could have been set */
- writeb(~0, &nic->csr->scb.stat_ack);
+ iowrite8(~0, &nic->csr->scb.stat_ack);
/* if the command failed, or is not OK, notify and return */
if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
@@ -1580,7 +1576,7 @@ static void e100_watchdog(unsigned long data)
* accidentally, due to hardware that shares a register between the
* interrupt mask bit and the SW Interrupt generation bit */
spin_lock_irq(&nic->cmd_lock);
- writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
+ iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);
e100_write_flush(nic);
spin_unlock_irq(&nic->cmd_lock);
@@ -1746,19 +1742,11 @@ static int e100_alloc_cbs(struct nic *nic)
return 0;
}
-static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
+static inline void e100_start_receiver(struct nic *nic)
{
- if(!nic->rxs) return;
- if(RU_SUSPENDED != nic->ru_running) return;
-
- /* handle init time starts */
- if(!rx) rx = nic->rxs;
-
- /* (Re)start RU if suspended or idle and RFA is non-NULL */
- if(rx->skb) {
- e100_exec_cmd(nic, ruc_start, rx->dma_addr);
- nic->ru_running = RU_RUNNING;
- }
+ /* Start if RFA is non-NULL */
+ if(nic->rx_to_clean->skb)
+ e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr);
}
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
@@ -1787,7 +1775,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
put_unaligned(cpu_to_le32(rx->dma_addr),
(u32 *)&prev_rfd->link);
wmb();
- prev_rfd->command &= ~cpu_to_le16(cb_el);
+ prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s);
pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,
sizeof(struct rfd), PCI_DMA_TODEVICE);
}
@@ -1825,10 +1813,6 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
pci_unmap_single(nic->pdev, rx->dma_addr,
RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
- /* this allows for a fast restart without re-enabling interrupts */
- if(le16_to_cpu(rfd->command) & cb_el)
- nic->ru_running = RU_SUSPENDED;
-
/* Pull off the RFD and put the actual data (minus eth hdr) */
skb_reserve(skb, sizeof(struct rfd));
skb_put(skb, actual_size);
@@ -1859,45 +1843,18 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
unsigned int work_to_do)
{
struct rx *rx;
- int restart_required = 0;
- struct rx *rx_to_start = NULL;
-
- /* are we already rnr? then pay attention!!! this ensures that
- * the state machine progression never allows a start with a
- * partially cleaned list, avoiding a race between hardware
- * and rx_to_clean when in NAPI mode */
- if(RU_SUSPENDED == nic->ru_running)
- restart_required = 1;
/* Indicate newly arrived packets */
for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
- int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
- if(-EAGAIN == err) {
- /* hit quota so have more work to do, restart once
- * cleanup is complete */
- restart_required = 0;
- break;
- } else if(-ENODATA == err)
+ if(e100_rx_indicate(nic, rx, work_done, work_to_do))
break; /* No more to clean */
}
- /* save our starting point as the place we'll restart the receiver */
- if(restart_required)
- rx_to_start = nic->rx_to_clean;
-
/* Alloc new skbs to refill list */
for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
if(unlikely(e100_rx_alloc_skb(nic, rx)))
break; /* Better luck next time (see watchdog) */
}
-
- if(restart_required) {
- // ack the rnr?
- writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
- e100_start_receiver(nic, rx_to_start);
- if(work_done)
- (*work_done)++;
- }
}
static void e100_rx_clean_list(struct nic *nic)
@@ -1905,8 +1862,6 @@ static void e100_rx_clean_list(struct nic *nic)
struct rx *rx;
unsigned int i, count = nic->params.rfds.count;
- nic->ru_running = RU_UNINITIALIZED;
-
if(nic->rxs) {
for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
if(rx->skb) {
@@ -1928,7 +1883,6 @@ static int e100_rx_alloc_list(struct nic *nic)
unsigned int i, count = nic->params.rfds.count;
nic->rx_to_use = nic->rx_to_clean = NULL;
- nic->ru_running = RU_UNINITIALIZED;
if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
return -ENOMEM;
@@ -1943,7 +1897,6 @@ static int e100_rx_alloc_list(struct nic *nic)
}
nic->rx_to_use = nic->rx_to_clean = nic->rxs;
- nic->ru_running = RU_SUSPENDED;
return 0;
}
@@ -1952,7 +1905,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
{
struct net_device *netdev = dev_id;
struct nic *nic = netdev_priv(netdev);
- u8 stat_ack = readb(&nic->csr->scb.stat_ack);
+ u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
@@ -1961,11 +1914,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
return IRQ_NONE;
/* Ack interrupt(s) */
- writeb(stat_ack, &nic->csr->scb.stat_ack);
-
- /* We hit Receive No Resource (RNR); restart RU after cleaning */
- if(stat_ack & stat_ack_rnr)
- nic->ru_running = RU_SUSPENDED;
+ iowrite8(stat_ack, &nic->csr->scb.stat_ack);
if(likely(netif_rx_schedule_prep(netdev))) {
e100_disable_irq(nic);
@@ -2058,7 +2007,7 @@ static int e100_up(struct nic *nic)
if((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
- e100_start_receiver(nic, NULL);
+ e100_start_receiver(nic);
mod_timer(&nic->watchdog, jiffies);
if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)))
@@ -2107,7 +2056,7 @@ static void e100_tx_timeout_task(struct work_struct *work)
struct net_device *netdev = nic->netdev;
DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
- readb(&nic->csr->scb.status));
+ ioread8(&nic->csr->scb.status));
e100_down(netdev_priv(netdev));
e100_up(netdev_priv(netdev));
}
@@ -2139,7 +2088,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
BMCR_LOOPBACK);
- e100_start_receiver(nic, NULL);
+ e100_start_receiver(nic);
if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
err = -ENOMEM;
@@ -2230,9 +2179,9 @@ static void e100_get_regs(struct net_device *netdev,
int i;
regs->version = (1 << 24) | nic->rev_id;
- buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 |
- readb(&nic->csr->scb.cmd_lo) << 16 |
- readw(&nic->csr->scb.status);
+ buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
+ ioread8(&nic->csr->scb.cmd_lo) << 16 |
+ ioread16(&nic->csr->scb.status);
for(i = E100_PHY_REGS; i >= 0; i--)
buff[1 + E100_PHY_REGS - i] =
mdio_read(netdev, nic->mii.phy_id, i);
@@ -2604,7 +2553,10 @@ static int __devinit e100_probe(struct pci_dev *pdev,
SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
- nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr));
+ if (use_io)
+ DPRINTK(PROBE, INFO, "using i/o access mode\n");
+
+ nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
if(!nic->csr) {
DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
err = -ENOMEM;
@@ -2651,11 +2603,16 @@ static int __devinit e100_probe(struct pci_dev *pdev,
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN);
- if(!is_valid_ether_addr(netdev->perm_addr)) {
- DPRINTK(PROBE, ERR, "Invalid MAC address from "
- "EEPROM, aborting.\n");
- err = -EAGAIN;
- goto err_out_free;
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ if (!eeprom_bad_csum_allow) {
+ DPRINTK(PROBE, ERR, "Invalid MAC address from "
+ "EEPROM, aborting.\n");
+ err = -EAGAIN;
+ goto err_out_free;
+ } else {
+ DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, "
+ "you MUST configure one.\n");
+ }
}
/* Wol magic packet can be enabled from eeprom */
@@ -2676,7 +2633,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
- (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
+ (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
@@ -2685,7 +2642,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
err_out_free:
e100_free(nic);
err_out_iounmap:
- iounmap(nic->csr);
+ pci_iounmap(pdev, nic->csr);
err_out_free_res:
pci_release_regions(pdev);
err_out_disable_pdev:
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index dd4b728ac4b..a9ea67e75c1 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -155,9 +155,6 @@ struct e1000_adapter;
/* Number of packet split data buffers (not including the header buffer) */
#define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1
-/* only works for sizes that are powers of 2 */
-#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 6777887295f..bb08375b5f1 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -654,14 +654,11 @@ e1000_set_ringparam(struct net_device *netdev,
e1000_mac_type mac_type = adapter->hw.mac_type;
struct e1000_tx_ring *txdr, *tx_old;
struct e1000_rx_ring *rxdr, *rx_old;
- int i, err, tx_ring_size, rx_ring_size;
+ int i, err;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
- tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
- rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
-
while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
msleep(1);
@@ -672,11 +669,11 @@ e1000_set_ringparam(struct net_device *netdev,
rx_old = adapter->rx_ring;
err = -ENOMEM;
- txdr = kzalloc(tx_ring_size, GFP_KERNEL);
+ txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL);
if (!txdr)
goto err_alloc_tx;
- rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
+ rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL);
if (!rxdr)
goto err_alloc_rx;
@@ -686,12 +683,12 @@ e1000_set_ringparam(struct net_device *netdev,
rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
E1000_MAX_RXD : E1000_MAX_82544_RXD));
- E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+ rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE);
txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD);
txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ?
E1000_MAX_TXD : E1000_MAX_82544_TXD));
- E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+ txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE);
for (i = 0; i < adapter->num_tx_queues; i++)
txdr[i].count = txdr->count;
@@ -742,7 +739,7 @@ err_setup:
uint32_t pat, value; \
uint32_t test[] = \
{0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \
- for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \
+ for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \
E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
value = E1000_READ_REG(&adapter->hw, R); \
if (value != (test[pat] & W & M)) { \
@@ -1053,23 +1050,24 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter)
struct e1000_rx_ring *rxdr = &adapter->test_rx_ring;
struct pci_dev *pdev = adapter->pdev;
uint32_t rctl;
- int size, i, ret_val;
+ int i, ret_val;
/* Setup Tx descriptor ring and Tx buffers */
if (!txdr->count)
txdr->count = E1000_DEFAULT_TXD;
- size = txdr->count * sizeof(struct e1000_buffer);
- if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ if (!(txdr->buffer_info = kcalloc(txdr->count,
+ sizeof(struct e1000_buffer),
+ GFP_KERNEL))) {
ret_val = 1;
goto err_nomem;
}
- memset(txdr->buffer_info, 0, size);
txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
- E1000_ROUNDUP(txdr->size, 4096);
- if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) {
+ txdr->size = ALIGN(txdr->size, 4096);
+ if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size,
+ &txdr->dma))) {
ret_val = 2;
goto err_nomem;
}
@@ -1116,12 +1114,12 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter)
if (!rxdr->count)
rxdr->count = E1000_DEFAULT_RXD;
- size = rxdr->count * sizeof(struct e1000_buffer);
- if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) {
+ if (!(rxdr->buffer_info = kcalloc(rxdr->count,
+ sizeof(struct e1000_buffer),
+ GFP_KERNEL))) {
ret_val = 4;
goto err_nomem;
}
- memset(rxdr->buffer_info, 0, size);
rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) {
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 9267f16b1b3..637ae8f6879 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -748,9 +748,9 @@ e1000_reset(struct e1000_adapter *adapter)
VLAN_TAG_SIZE;
min_tx_space = min_rx_space;
min_tx_space *= 2;
- E1000_ROUNDUP(min_tx_space, 1024);
+ min_tx_space = ALIGN(min_tx_space, 1024);
min_tx_space >>= 10;
- E1000_ROUNDUP(min_rx_space, 1024);
+ min_rx_space = ALIGN(min_rx_space, 1024);
min_rx_space >>= 10;
/* If current Tx allocation is less than the min Tx FIFO size,
@@ -1214,7 +1214,7 @@ e1000_remove(struct pci_dev *pdev)
int i;
#endif
- flush_scheduled_work();
+ cancel_work_sync(&adapter->reset_task);
e1000_release_manageability(adapter);
@@ -1354,31 +1354,27 @@ e1000_sw_init(struct e1000_adapter *adapter)
static int __devinit
e1000_alloc_queues(struct e1000_adapter *adapter)
{
- int size;
-
- size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
- adapter->tx_ring = kmalloc(size, GFP_KERNEL);
+ adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+ sizeof(struct e1000_tx_ring), GFP_KERNEL);
if (!adapter->tx_ring)
return -ENOMEM;
- memset(adapter->tx_ring, 0, size);
- size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
- adapter->rx_ring = kmalloc(size, GFP_KERNEL);
+ adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+ sizeof(struct e1000_rx_ring), GFP_KERNEL);
if (!adapter->rx_ring) {
kfree(adapter->tx_ring);
return -ENOMEM;
}
- memset(adapter->rx_ring, 0, size);
#ifdef CONFIG_E1000_NAPI
- size = sizeof(struct net_device) * adapter->num_rx_queues;
- adapter->polling_netdev = kmalloc(size, GFP_KERNEL);
+ adapter->polling_netdev = kcalloc(adapter->num_rx_queues,
+ sizeof(struct net_device),
+ GFP_KERNEL);
if (!adapter->polling_netdev) {
kfree(adapter->tx_ring);
kfree(adapter->rx_ring);
return -ENOMEM;
}
- memset(adapter->polling_netdev, 0, size);
#endif
return E1000_SUCCESS;
@@ -1560,7 +1556,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
/* round up to nearest 4K */
txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
- E1000_ROUNDUP(txdr->size, 4096);
+ txdr->size = ALIGN(txdr->size, 4096);
txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
if (!txdr->desc) {
@@ -1774,18 +1770,18 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
}
memset(rxdr->buffer_info, 0, size);
- size = sizeof(struct e1000_ps_page) * rxdr->count;
- rxdr->ps_page = kmalloc(size, GFP_KERNEL);
+ rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page),
+ GFP_KERNEL);
if (!rxdr->ps_page) {
vfree(rxdr->buffer_info);
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
- memset(rxdr->ps_page, 0, size);
- size = sizeof(struct e1000_ps_page_dma) * rxdr->count;
- rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL);
+ rxdr->ps_page_dma = kcalloc(rxdr->count,
+ sizeof(struct e1000_ps_page_dma),
+ GFP_KERNEL);
if (!rxdr->ps_page_dma) {
vfree(rxdr->buffer_info);
kfree(rxdr->ps_page);
@@ -1793,7 +1789,6 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
"Unable to allocate memory for the receive descriptor ring\n");
return -ENOMEM;
}
- memset(rxdr->ps_page_dma, 0, size);
if (adapter->hw.mac_type <= e1000_82547_rev_2)
desc_len = sizeof(struct e1000_rx_desc);
@@ -1803,7 +1798,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
/* Round up to nearest 4K */
rxdr->size = rxdr->count * desc_len;
- E1000_ROUNDUP(rxdr->size, 4096);
+ rxdr->size = ALIGN(rxdr->size, 4096);
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
@@ -2667,7 +2662,7 @@ e1000_watchdog(unsigned long data)
netif_carrier_on(netdev);
netif_wake_queue(netdev);
- mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+ mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
adapter->smartspeed = 0;
} else {
/* make sure the receive unit is started */
@@ -2684,7 +2679,7 @@ e1000_watchdog(unsigned long data)
DPRINTK(LINK, INFO, "NIC Link is Down\n");
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+ mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ));
/* 80003ES2LAN workaround--
* For packet buffer work-around on link down event;
@@ -2736,7 +2731,7 @@ e1000_watchdog(unsigned long data)
e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
/* Reset the timer */
- mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+ mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
}
enum latency_range {
@@ -3175,7 +3170,7 @@ e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb)
uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head;
uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR;
- E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR);
+ skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR);
if (adapter->link_duplex != HALF_DUPLEX)
goto no_fifo_stall_required;
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index f8862e203ac..f485874a63f 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -305,7 +305,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_TxDescriptors > bd) {
tx_ring->count = TxDescriptors[bd];
e1000_validate_option(&tx_ring->count, &opt, adapter);
- E1000_ROUNDUP(tx_ring->count,
+ tx_ring->count = ALIGN(tx_ring->count,
REQ_TX_DESCRIPTOR_MULTIPLE);
} else {
tx_ring->count = opt.def;
@@ -331,7 +331,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_RxDescriptors > bd) {
rx_ring->count = RxDescriptors[bd];
e1000_validate_option(&rx_ring->count, &opt, adapter);
- E1000_ROUNDUP(rx_ring->count,
+ rx_ring->count = ALIGN(rx_ring->count,
REQ_RX_DESCRIPTOR_MULTIPLE);
} else {
rx_ring->count = opt.def;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 39654e1e2be..47680237f78 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1126,7 +1126,7 @@ static void eepro_tx_timeout (struct net_device *dev)
printk (KERN_ERR "%s: transmit timed out, %s?\n", dev->name,
"network cable problem");
/* This is not a duplicate. One message for the console,
- one for the the log file */
+ one for the log file */
printk (KERN_DEBUG "%s: transmit timed out, %s?\n", dev->name,
"network cable problem");
eepro_complete_selreset(ioaddr);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 6c267c38df9..9800341956a 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -28,7 +28,7 @@
*/
static const char * const version =
-"eepro100.c:v1.09j-t 9/29/99 Donald Becker http://www.scyld.com/network/eepro100.html\n"
+"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n"
"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
/* A few user-configurable values that apply to all boards.
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 8aaf5ec0c36..7934ea37f94 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -115,6 +115,7 @@
#include <linux/mca-legacy.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
+#include <linux/jiffies.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -556,7 +557,7 @@ static void unstick_cu(struct net_device *dev)
if (lp->started)
{
- if ((jiffies - dev->trans_start)>50)
+ if (time_after(jiffies, dev->trans_start + 50))
{
if (lp->tx_link==lp->last_tx_restart)
{
@@ -612,7 +613,7 @@ static void unstick_cu(struct net_device *dev)
}
else
{
- if ((jiffies-lp->init_time)>10)
+ if (time_after(jiffies, lp->init_time + 10))
{
unsigned short status = scb_status(dev);
printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n",
@@ -776,7 +777,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
static void eexp_cmd_clear(struct net_device *dev)
{
unsigned long int oldtime = jiffies;
- while (scb_rdcmd(dev) && ((jiffies-oldtime)<10));
+ while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10)));
if (scb_rdcmd(dev)) {
printk("%s: command didn't clear\n", dev->name);
}
@@ -1649,7 +1650,7 @@ eexp_set_multicast(struct net_device *dev)
#endif
oj = jiffies;
while ((SCB_CUstat(scb_status(dev)) == 2) &&
- ((jiffies-oj) < 2000));
+ (time_before(jiffies, oj + 2000)));
if (SCB_CUstat(scb_status(dev)) == 2)
printk("%s: warning, CU didn't stop\n", dev->name);
lp->started &= ~(STARTED_CU);
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 42295d61ecd..602872dbe15 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0046"
+#define DRV_VERSION "EHEA_0058"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -78,10 +78,7 @@
#define EHEA_RQ2_PKT_SIZE 1522
#define EHEA_L_PKT_SIZE 256 /* low latency */
-#define EHEA_POLL_MAX_RWQE 1000
-
/* Send completion signaling */
-#define EHEA_SIG_IV_LONG 1
/* Protection Domain Identifier */
#define EHEA_PD_ID 0xaabcdeff
@@ -108,11 +105,7 @@
#define EHEA_CACHE_LINE 128
/* Memory Regions */
-#define EHEA_MR_MAX_TX_PAGES 20
-#define EHEA_MR_TX_DATA_PN 3
#define EHEA_MR_ACC_CTRL 0x00800000
-#define EHEA_RWQES_PER_MR_RQ2 10
-#define EHEA_RWQES_PER_MR_RQ3 10
#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
@@ -311,6 +304,7 @@ struct ehea_cq {
* Memory Region
*/
struct ehea_mr {
+ struct ehea_adapter *adapter;
u64 handle;
u64 vaddr;
u32 lkey;
@@ -319,17 +313,12 @@ struct ehea_mr {
/*
* Port state information
*/
-struct port_state {
- int poll_max_processed;
+struct port_stats {
int poll_receive_errors;
- int ehea_poll;
int queue_stopped;
- int min_swqe_avail;
- u64 sqc_stop_sum;
- int pkt_send;
- int pkt_xmit;
- int send_tasklet;
- int nwqe;
+ int err_tcp_cksum;
+ int err_ip_cksum;
+ int err_frame_crc;
};
#define EHEA_IRQ_NAME_SIZE 20
@@ -348,6 +337,7 @@ struct ehea_q_skb_arr {
* Port resources
*/
struct ehea_port_res {
+ struct port_stats p_stats;
struct ehea_mr send_mr; /* send memory region */
struct ehea_mr recv_mr; /* receive memory region */
spinlock_t xmit_lock;
@@ -357,9 +347,8 @@ struct ehea_port_res {
struct ehea_qp *qp;
struct ehea_cq *send_cq;
struct ehea_cq *recv_cq;
- struct ehea_eq *send_eq;
- struct ehea_eq *recv_eq;
- spinlock_t send_lock;
+ struct ehea_eq *eq;
+ struct net_device *d_netdev;
struct ehea_q_skb_arr rq1_skba;
struct ehea_q_skb_arr rq2_skba;
struct ehea_q_skb_arr rq3_skba;
@@ -369,21 +358,18 @@ struct ehea_port_res {
int swqe_refill_th;
atomic_t swqe_avail;
int swqe_ll_count;
- int swqe_count;
u32 swqe_id_counter;
u64 tx_packets;
- struct tasklet_struct send_comp_task;
- spinlock_t recv_lock;
- struct port_state p_state;
u64 rx_packets;
u32 poll_counter;
};
+#define EHEA_MAX_PORTS 16
struct ehea_adapter {
u64 handle;
- u8 num_ports;
- struct ehea_port *port[16];
+ struct ibmebus_dev *ebus_dev;
+ struct ehea_port *port[EHEA_MAX_PORTS];
struct ehea_eq *neq; /* notification event queue */
struct workqueue_struct *ehea_wq;
struct tasklet_struct neq_tasklet;
@@ -406,7 +392,7 @@ struct ehea_port {
struct net_device *netdev;
struct net_device_stats stats;
struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
- struct device_node *of_dev_node; /* Open Firmware Device Node */
+ struct of_device ofdev; /* Open Firmware Device */
struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
struct vlan_group *vgrp;
struct ehea_eq *qp_eq;
@@ -415,7 +401,9 @@ struct ehea_port {
char int_aff_name[EHEA_IRQ_NAME_SIZE];
int allmulti; /* Indicates IFF_ALLMULTI state */
int promisc; /* Indicates IFF_PROMISC state */
+ int num_tx_qps;
int num_add_tx_qps;
+ int num_mcs;
int resets;
u64 mac_addr;
u32 logical_port_id;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index 9f57c2e78ce..decec8cfe96 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -144,8 +144,8 @@ static int ehea_nway_reset(struct net_device *dev)
static void ehea_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
- strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version));
}
static u32 ehea_get_msglevel(struct net_device *dev)
@@ -166,33 +166,23 @@ static u32 ehea_get_rx_csum(struct net_device *dev)
}
static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
- {"poll_max_processed"},
- {"queue_stopped"},
- {"min_swqe_avail"},
- {"poll_receive_err"},
- {"pkt_send"},
- {"pkt_xmit"},
- {"send_tasklet"},
- {"ehea_poll"},
- {"nwqe"},
- {"swqe_available_0"},
{"sig_comp_iv"},
{"swqe_refill_th"},
{"port resets"},
- {"rxo"},
- {"rx64"},
- {"rx65"},
- {"rx128"},
- {"rx256"},
- {"rx512"},
- {"rx1024"},
- {"txo"},
- {"tx64"},
- {"tx65"},
- {"tx128"},
- {"tx256"},
- {"tx512"},
- {"tx1024"},
+ {"Receive errors"},
+ {"TCP cksum errors"},
+ {"IP cksum errors"},
+ {"Frame cksum errors"},
+ {"num SQ stopped"},
+ {"SQ stopped"},
+ {"PR0 free_swqes"},
+ {"PR1 free_swqes"},
+ {"PR2 free_swqes"},
+ {"PR3 free_swqes"},
+ {"PR4 free_swqes"},
+ {"PR5 free_swqes"},
+ {"PR6 free_swqes"},
+ {"PR7 free_swqes"},
};
static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -211,63 +201,44 @@ static int ehea_get_stats_count(struct net_device *dev)
static void ehea_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
- u64 hret;
- int i;
+ int i, k, tmp;
struct ehea_port *port = netdev_priv(dev);
- struct ehea_adapter *adapter = port->adapter;
- struct ehea_port_res *pr = &port->port_res[0];
- struct port_state *p_state = &pr->p_state;
- struct hcp_ehea_port_cb6 *cb6;
for (i = 0; i < ehea_get_stats_count(dev); i++)
data[i] = 0;
-
i = 0;
- data[i++] = p_state->poll_max_processed;
- data[i++] = p_state->queue_stopped;
- data[i++] = p_state->min_swqe_avail;
- data[i++] = p_state->poll_receive_errors;
- data[i++] = p_state->pkt_send;
- data[i++] = p_state->pkt_xmit;
- data[i++] = p_state->send_tasklet;
- data[i++] = p_state->ehea_poll;
- data[i++] = p_state->nwqe;
- data[i++] = atomic_read(&port->port_res[0].swqe_avail);
data[i++] = port->sig_comp_iv;
data[i++] = port->port_res[0].swqe_refill_th;
data[i++] = port->resets;
- cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!cb6) {
- ehea_error("no mem for cb6");
- return;
- }
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.poll_receive_errors;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.err_tcp_cksum;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.err_ip_cksum;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.err_frame_crc;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp += port->port_res[k].p_stats.queue_stopped;
+ data[i++] = tmp;
+
+ for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+ tmp |= port->port_res[k].queue_stopped;
+ data[i++] = tmp;
+
+ for (k = 0; k < 8; k++)
+ data[i++] = atomic_read(&port->port_res[k].swqe_avail);
- hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
- H_PORT_CB6, H_PORT_CB6_ALL, cb6);
- if (netif_msg_hw(port))
- ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats");
-
- if (hret == H_SUCCESS) {
- data[i++] = cb6->rxo;
- data[i++] = cb6->rx64;
- data[i++] = cb6->rx65;
- data[i++] = cb6->rx128;
- data[i++] = cb6->rx256;
- data[i++] = cb6->rx512;
- data[i++] = cb6->rx1024;
- data[i++] = cb6->txo;
- data[i++] = cb6->tx64;
- data[i++] = cb6->tx65;
- data[i++] = cb6->tx128;
- data[i++] = cb6->tx256;
- data[i++] = cb6->tx512;
- data[i++] = cb6->tx1024;
- } else
- ehea_error("query_ehea_port failed");
-
- kfree(cb6);
}
const struct ethtool_ops ehea_ethtool_ops = {
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 58364a0ff37..f6e0cb1ada1 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -51,13 +51,18 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
static int sq_entries = EHEA_DEF_ENTRIES_SQ;
+static int use_mcs = 0;
+static int num_tx_qps = EHEA_NUM_TX_QP;
module_param(msg_level, int, 0);
module_param(rq1_entries, int, 0);
module_param(rq2_entries, int, 0);
module_param(rq3_entries, int, 0);
module_param(sq_entries, int, 0);
+module_param(use_mcs, int, 0);
+module_param(num_tx_qps, int, 0);
+MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
MODULE_PARM_DESC(msg_level, "msg_level");
MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
"[2^x - 1], x = [6..14]. Default = "
@@ -71,6 +76,29 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
"[2^x - 1], x = [6..14]. Default = "
__MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
+MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
+
+static int port_name_cnt = 0;
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+ const struct of_device_id *id);
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev);
+
+static struct of_device_id ehea_device_table[] = {
+ {
+ .name = "lhea",
+ .compatible = "IBM,lhea",
+ },
+ {},
+};
+
+static struct ibmebus_driver ehea_driver = {
+ .name = "ehea",
+ .id_table = ehea_device_table,
+ .probe = ehea_probe_adapter,
+ .remove = ehea_remove,
+};
void ehea_dump(void *adr, int len, char *msg) {
int x;
@@ -197,7 +225,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
if (!skb) {
ehea_error("%s: no mem for skb/%d wqes filled",
- dev->name, i);
+ pr->port->netdev->name, i);
q_skba->os_skbs = fill_wqes - i;
ret = -ENOMEM;
break;
@@ -321,6 +349,13 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
{
struct sk_buff *skb;
+ if (cqe->status & EHEA_CQE_STAT_ERR_TCP)
+ pr->p_stats.err_tcp_cksum++;
+ if (cqe->status & EHEA_CQE_STAT_ERR_IP)
+ pr->p_stats.err_ip_cksum++;
+ if (cqe->status & EHEA_CQE_STAT_ERR_CRC)
+ pr->p_stats.err_frame_crc++;
+
if (netif_msg_rx_err(pr->port)) {
ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr);
ehea_dump(cqe, sizeof(*cqe), "CQE");
@@ -345,10 +380,11 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
return 0;
}
-static int ehea_poll(struct net_device *dev, int *budget)
+static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
+ struct ehea_port_res *pr,
+ int *budget)
{
- struct ehea_port *port = netdev_priv(dev);
- struct ehea_port_res *pr = &port->port_res[0];
+ struct ehea_port *port = pr->port;
struct ehea_qp *qp = pr->qp;
struct ehea_cqe *cqe;
struct sk_buff *skb;
@@ -359,14 +395,12 @@ static int ehea_poll(struct net_device *dev, int *budget)
int skb_arr_rq2_len = pr->rq2_skba.len;
int skb_arr_rq3_len = pr->rq3_skba.len;
int processed, processed_rq1, processed_rq2, processed_rq3;
- int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset;
+ int wqe_index, last_wqe_index, rq, my_quota, port_reset;
processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
last_wqe_index = 0;
my_quota = min(*budget, dev->quota);
- my_quota = min(my_quota, EHEA_POLL_MAX_RWQE);
- /* rq0 is low latency RQ */
cqe = ehea_poll_rq1(qp, &wqe_index);
while ((my_quota > 0) && cqe) {
ehea_inc_rq1(qp);
@@ -386,7 +420,8 @@ static int ehea_poll(struct net_device *dev, int *budget)
if (unlikely(!skb)) {
if (netif_msg_rx_err(port))
ehea_error("LL rq1: skb=NULL");
- skb = netdev_alloc_skb(dev,
+
+ skb = netdev_alloc_skb(port->netdev,
EHEA_L_PKT_SIZE);
if (!skb)
break;
@@ -402,7 +437,7 @@ static int ehea_poll(struct net_device *dev, int *budget)
ehea_error("rq2: skb=NULL");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(port->netdev, skb, cqe);
processed_rq2++;
} else { /* RQ3 */
skb = get_skb_by_index(skb_arr_rq3,
@@ -412,7 +447,7 @@ static int ehea_poll(struct net_device *dev, int *budget)
ehea_error("rq3: skb=NULL");
break;
}
- ehea_fill_skb(dev, skb, cqe);
+ ehea_fill_skb(port->netdev, skb, cqe);
processed_rq3++;
}
@@ -421,9 +456,8 @@ static int ehea_poll(struct net_device *dev, int *budget)
cqe->vlan_tag);
else
netif_receive_skb(skb);
-
- } else { /* Error occured */
- pr->p_state.poll_receive_errors++;
+ } else {
+ pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
&processed_rq2,
&processed_rq3);
@@ -433,72 +467,32 @@ static int ehea_poll(struct net_device *dev, int *budget)
cqe = ehea_poll_rq1(qp, &wqe_index);
}
- dev->quota -= processed;
- *budget -= processed;
-
- pr->p_state.ehea_poll += 1;
pr->rx_packets += processed;
+ *budget -= processed;
ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
ehea_refill_rq2(pr, processed_rq2);
ehea_refill_rq3(pr, processed_rq3);
- intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
-
- if (!cqe || intreq) {
- netif_rx_complete(dev);
- ehea_reset_cq_ep(pr->recv_cq);
- ehea_reset_cq_n1(pr->recv_cq);
- cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
- if (!cqe || intreq)
- return 0;
- if (!netif_rx_reschedule(dev, my_quota))
- return 0;
- }
- return 1;
+ cqe = ehea_poll_rq1(qp, &wqe_index);
+ return cqe;
}
-void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
{
struct sk_buff *skb;
- int index, max_index_mask, i;
-
- index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
- max_index_mask = pr->sq_skba.len - 1;
- for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
- skb = pr->sq_skba.arr[index];
- if (likely(skb)) {
- dev_kfree_skb(skb);
- pr->sq_skba.arr[index] = NULL;
- } else {
- ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d",
- cqe->wr_id, i, index);
- }
- index--;
- index &= max_index_mask;
- }
-}
-
-#define MAX_SENDCOMP_QUOTA 400
-void ehea_send_irq_tasklet(unsigned long data)
-{
- struct ehea_port_res *pr = (struct ehea_port_res*)data;
struct ehea_cq *send_cq = pr->send_cq;
struct ehea_cqe *cqe;
- int quota = MAX_SENDCOMP_QUOTA;
+ int quota = my_quota;
int cqe_counter = 0;
int swqe_av = 0;
+ int index;
unsigned long flags;
- do {
- cqe = ehea_poll_cq(send_cq);
- if (!cqe) {
- ehea_reset_cq_ep(send_cq);
- ehea_reset_cq_n1(send_cq);
- cqe = ehea_poll_cq(send_cq);
- if (!cqe)
- break;
- }
+ cqe = ehea_poll_cq(send_cq);
+ while(cqe && (quota > 0)) {
+ ehea_inc_cq(send_cq);
+
cqe_counter++;
rmb();
if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
@@ -514,17 +508,25 @@ void ehea_send_irq_tasklet(unsigned long data)
ehea_dump(cqe, sizeof(*cqe), "CQE");
if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
- == EHEA_SWQE2_TYPE))
- free_sent_skbs(cqe, pr);
+ == EHEA_SWQE2_TYPE)) {
+
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+ skb = pr->sq_skba.arr[index];
+ dev_kfree_skb(skb);
+ pr->sq_skba.arr[index] = NULL;
+ }
swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
quota--;
- } while (quota > 0);
+
+ cqe = ehea_poll_cq(send_cq);
+ };
ehea_update_feca(send_cq, cqe_counter);
atomic_add(swqe_av, &pr->swqe_avail);
spin_lock_irqsave(&pr->netif_queue, flags);
+
if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
>= pr->swqe_refill_th)) {
netif_wake_queue(pr->port->netdev);
@@ -532,22 +534,55 @@ void ehea_send_irq_tasklet(unsigned long data)
}
spin_unlock_irqrestore(&pr->netif_queue, flags);
- if (unlikely(cqe))
- tasklet_hi_schedule(&pr->send_comp_task);
+ return cqe;
}
-static irqreturn_t ehea_send_irq_handler(int irq, void *param)
+#define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+
+static int ehea_poll(struct net_device *dev, int *budget)
{
- struct ehea_port_res *pr = param;
- tasklet_hi_schedule(&pr->send_comp_task);
- return IRQ_HANDLED;
+ struct ehea_port_res *pr = dev->priv;
+ struct ehea_cqe *cqe;
+ struct ehea_cqe *cqe_skb = NULL;
+ int force_irq, wqe_index;
+
+ cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+ cqe_skb = ehea_poll_cq(pr->send_cq);
+
+ force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+
+ if ((!cqe && !cqe_skb) || force_irq) {
+ pr->poll_counter = 0;
+ netif_rx_complete(dev);
+ ehea_reset_cq_ep(pr->recv_cq);
+ ehea_reset_cq_ep(pr->send_cq);
+ ehea_reset_cq_n1(pr->recv_cq);
+ ehea_reset_cq_n1(pr->send_cq);
+ cqe = ehea_poll_rq1(pr->qp, &wqe_index);
+ cqe_skb = ehea_poll_cq(pr->send_cq);
+
+ if (!cqe && !cqe_skb)
+ return 0;
+
+ if (!netif_rx_reschedule(dev, dev->quota))
+ return 0;
+ }
+
+ cqe = ehea_proc_rwqes(dev, pr, budget);
+ cqe_skb = ehea_proc_cqes(pr, 300);
+
+ if (cqe || cqe_skb)
+ pr->poll_counter++;
+
+ return 1;
}
static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
- struct ehea_port *port = pr->port;
- netif_rx_schedule(port->netdev);
+
+ netif_rx_schedule(pr->d_netdev);
+
return IRQ_HANDLED;
}
@@ -580,7 +615,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
{
int i;
- for (i = 0; i < adapter->num_ports; i++)
+ for (i = 0; i < EHEA_MAX_PORTS; i++)
if (adapter->port[i])
if (adapter->port[i]->logical_port_id == logical_port)
return adapter->port[i];
@@ -650,19 +685,25 @@ int ehea_sense_port_attr(struct ehea_port *port)
}
port->autoneg = 1;
+ port->num_mcs = cb0->num_default_qps;
/* Number of default QPs */
- port->num_def_qps = cb0->num_default_qps;
+ if (use_mcs)
+ port->num_def_qps = cb0->num_default_qps;
+ else
+ port->num_def_qps = 1;
if (!port->num_def_qps) {
ret = -EINVAL;
goto out_free;
}
- if (port->num_def_qps >= EHEA_NUM_TX_QP)
+ port->num_tx_qps = num_tx_qps;
+
+ if (port->num_def_qps >= port->num_tx_qps)
port->num_add_tx_qps = 0;
else
- port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+ port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps;
ret = 0;
out_free:
@@ -882,23 +923,6 @@ static int ehea_reg_interrupts(struct net_device *dev)
struct ehea_port_res *pr;
int i, ret;
- for (i = 0; i < port->num_def_qps; i++) {
- pr = &port->port_res[i];
- snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
- , "%s-recv%d", dev->name, i);
- ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
- ehea_recv_irq_handler,
- IRQF_DISABLED, pr->int_recv_name, pr);
- if (ret) {
- ehea_error("failed registering irq for ehea_recv_int:"
- "port_res_nr:%d, ist=%X", i,
- pr->recv_eq->attr.ist1);
- goto out_free_seq;
- }
- if (netif_msg_ifup(port))
- ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
- "registered", pr->recv_eq->attr.ist1, i);
- }
snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
dev->name);
@@ -916,41 +940,41 @@ static int ehea_reg_interrupts(struct net_device *dev)
ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
"registered", port->qp_eq->attr.ist1);
+
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
pr = &port->port_res[i];
snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
- "%s-send%d", dev->name, i);
- ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
- ehea_send_irq_handler,
+ "%s-queue%d", dev->name, i);
+ ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1,
+ ehea_recv_irq_handler,
IRQF_DISABLED, pr->int_send_name,
pr);
if (ret) {
- ehea_error("failed registering irq for ehea_send "
+ ehea_error("failed registering irq for ehea_queue "
"port_res_nr:%d, ist=%X", i,
- pr->send_eq->attr.ist1);
+ pr->eq->attr.ist1);
goto out_free_req;
}
if (netif_msg_ifup(port))
- ehea_info("irq_handle 0x%X for function ehea_send_int "
- "%d registered", pr->send_eq->attr.ist1, i);
+ ehea_info("irq_handle 0x%X for function ehea_queue_int "
+ "%d registered", pr->eq->attr.ist1, i);
}
out:
return ret;
+
out_free_req:
while (--i >= 0) {
- u32 ist = port->port_res[i].send_eq->attr.ist1;
+ u32 ist = port->port_res[i].eq->attr.ist1;
ibmebus_free_irq(NULL, ist, &port->port_res[i]);
}
+
out_free_qpeq:
ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
i = port->num_def_qps;
-out_free_seq:
- while (--i >= 0) {
- u32 ist = port->port_res[i].recv_eq->attr.ist1;
- ibmebus_free_irq(NULL, ist, &port->port_res[i]);
- }
+
goto out;
+
}
static void ehea_free_interrupts(struct net_device *dev)
@@ -960,21 +984,13 @@ static void ehea_free_interrupts(struct net_device *dev)
int i;
/* send */
+
for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
pr = &port->port_res[i];
- ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr);
+ ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr);
if (netif_msg_intr(port))
ehea_info("free send irq for res %d with handle 0x%X",
- i, pr->send_eq->attr.ist1);
- }
-
- /* receive */
- for (i = 0; i < port->num_def_qps; i++) {
- pr = &port->port_res[i];
- ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr);
- if (netif_msg_intr(port))
- ehea_info("free recv irq for res %d with handle 0x%X",
- i, pr->recv_eq->attr.ist1);
+ i, pr->eq->attr.ist1);
}
/* associated events */
@@ -1003,8 +1019,13 @@ static int ehea_configure_port(struct ehea_port *port)
PXLY_RC_VLAN_FILTER)
| EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
- for (i = 0; i < port->num_def_qps; i++)
- cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr;
+ for (i = 0; i < port->num_mcs; i++)
+ if (use_mcs)
+ cb0->default_qpn_arr[i] =
+ port->port_res[i].qp->init_attr.qp_nr;
+ else
+ cb0->default_qpn_arr[i] =
+ port->port_res[0].qp->init_attr.qp_nr;
if (netif_msg_ifup(port))
ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
@@ -1027,52 +1048,35 @@ out:
return ret;
}
-static int ehea_gen_smrs(struct ehea_port_res *pr)
+int ehea_gen_smrs(struct ehea_port_res *pr)
{
- u64 hret;
+ int ret;
struct ehea_adapter *adapter = pr->port->adapter;
- hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
- adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
- adapter->pd, &pr->send_mr);
- if (hret != H_SUCCESS)
+ ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr);
+ if (ret)
goto out;
- hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
- adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
- adapter->pd, &pr->recv_mr);
- if (hret != H_SUCCESS)
- goto out_freeres;
+ ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr);
+ if (ret)
+ goto out_free;
return 0;
-out_freeres:
- hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
- if (hret != H_SUCCESS)
- ehea_error("failed freeing SMR");
+out_free:
+ ehea_rem_mr(&pr->send_mr);
out:
+ ehea_error("Generating SMRS failed\n");
return -EIO;
}
-static int ehea_rem_smrs(struct ehea_port_res *pr)
+int ehea_rem_smrs(struct ehea_port_res *pr)
{
- struct ehea_adapter *adapter = pr->port->adapter;
- int ret = 0;
- u64 hret;
-
- hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
- if (hret != H_SUCCESS) {
- ret = -EIO;
- ehea_error("failed freeing send SMR for pr=%p", pr);
- }
-
- hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle);
- if (hret != H_SUCCESS) {
- ret = -EIO;
- ehea_error("failed freeing recv SMR for pr=%p", pr);
- }
-
- return ret;
+ if ((ehea_rem_mr(&pr->send_mr))
+ || (ehea_rem_mr(&pr->recv_mr)))
+ return -EIO;
+ else
+ return 0;
}
static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
@@ -1103,25 +1107,17 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
memset(pr, 0, sizeof(struct ehea_port_res));
pr->port = port;
- spin_lock_init(&pr->send_lock);
- spin_lock_init(&pr->recv_lock);
spin_lock_init(&pr->xmit_lock);
spin_lock_init(&pr->netif_queue);
- pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
- if (!pr->recv_eq) {
- ehea_error("create_eq failed (recv_eq)");
- goto out_free;
- }
-
- pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
- if (!pr->send_eq) {
- ehea_error("create_eq failed (send_eq)");
+ pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
+ if (!pr->eq) {
+ ehea_error("create_eq failed (eq)");
goto out_free;
}
pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
- pr->recv_eq->fw_handle,
+ pr->eq->fw_handle,
port->logical_port_id);
if (!pr->recv_cq) {
ehea_error("create_cq failed (cq_recv)");
@@ -1129,7 +1125,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
}
pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
- pr->send_eq->fw_handle,
+ pr->eq->fw_handle,
port->logical_port_id);
if (!pr->send_cq) {
ehea_error("create_cq failed (cq_send)");
@@ -1194,11 +1190,20 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
ret = -EIO;
goto out_free;
}
- tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
- (unsigned long)pr);
+
atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
kfree(init_attr);
+
+ pr->d_netdev = alloc_netdev(0, "", ether_setup);
+ if (!pr->d_netdev)
+ goto out_free;
+ pr->d_netdev->priv = pr;
+ pr->d_netdev->weight = 64;
+ pr->d_netdev->poll = ehea_poll;
+ set_bit(__LINK_STATE_START, &pr->d_netdev->state);
+ strcpy(pr->d_netdev->name, port->netdev->name);
+
ret = 0;
goto out;
@@ -1211,8 +1216,7 @@ out_free:
ehea_destroy_qp(pr->qp);
ehea_destroy_cq(pr->send_cq);
ehea_destroy_cq(pr->recv_cq);
- ehea_destroy_eq(pr->send_eq);
- ehea_destroy_eq(pr->recv_eq);
+ ehea_destroy_eq(pr->eq);
out:
return ret;
}
@@ -1221,13 +1225,14 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
{
int ret, i;
+ free_netdev(pr->d_netdev);
+
ret = ehea_destroy_qp(pr->qp);
if (!ret) {
ehea_destroy_cq(pr->send_cq);
ehea_destroy_cq(pr->recv_cq);
- ehea_destroy_eq(pr->send_eq);
- ehea_destroy_eq(pr->recv_eq);
+ ehea_destroy_eq(pr->eq);
for (i = 0; i < pr->rq1_skba.len; i++)
if (pr->rq1_skba.arr[i])
@@ -1792,6 +1797,22 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
dev_kfree_skb(skb);
}
+static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps)
+{
+ struct tcphdr *tcp;
+ u32 tmp;
+
+ if ((skb->protocol == htons(ETH_P_IP)) &&
+ (ip_hdr(skb)->protocol == IPPROTO_TCP)) {
+ tcp = (struct tcphdr*)(skb_network_header(skb) + (ip_hdr(skb)->ihl * 4));
+ tmp = (tcp->source + (tcp->dest << 16)) % 31;
+ tmp += ip_hdr(skb)->daddr % 31;
+ return tmp % num_qps;
+ }
+ else
+ return 0;
+}
+
static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
@@ -1799,9 +1820,17 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
u32 lkey;
int swqe_index;
- struct ehea_port_res *pr = &port->port_res[0];
+ struct ehea_port_res *pr;
+
+ pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)];
- spin_lock(&pr->xmit_lock);
+ if (!spin_trylock(&pr->xmit_lock))
+ return NETDEV_TX_BUSY;
+
+ if (pr->queue_stopped) {
+ spin_unlock(&pr->xmit_lock);
+ return NETDEV_TX_BUSY;
+ }
swqe = ehea_get_swqe(pr->qp, &swqe_index);
memset(swqe, 0, SWQE_HEADER_SIZE);
@@ -1824,6 +1853,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
swqe->wr_id =
EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
| EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
+ | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1)
| EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index);
pr->sq_skba.arr[pr->sq_skba.index] = skb;
@@ -1832,14 +1862,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
lkey = pr->send_mr.lkey;
ehea_xmit2(skb, dev, swqe, lkey);
-
- if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) {
- swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
- EHEA_SIG_IV_LONG);
- swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
- pr->swqe_count = 0;
- } else
- pr->swqe_count += 1;
+ swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
}
pr->swqe_id_counter += 1;
@@ -1859,6 +1882,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
spin_lock_irqsave(&pr->netif_queue, flags);
if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+ pr->p_stats.queue_stopped++;
netif_stop_queue(dev);
pr->queue_stopped = 1;
}
@@ -2060,7 +2084,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
}
pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
- pr_cfg.max_entries_scq = sq_entries;
+ pr_cfg.max_entries_scq = sq_entries * 2;
pr_cfg.max_entries_sq = sq_entries;
pr_cfg.max_entries_rq1 = rq1_entries;
pr_cfg.max_entries_rq2 = rq2_entries;
@@ -2109,6 +2133,28 @@ static int ehea_clean_all_portres(struct ehea_port *port)
return ret;
}
+static void ehea_remove_adapter_mr (struct ehea_adapter *adapter)
+{
+ int i;
+
+ for (i=0; i < EHEA_MAX_PORTS; i++)
+ if (adapter->port[i])
+ return;
+
+ ehea_rem_mr(&adapter->mr);
+}
+
+static int ehea_add_adapter_mr (struct ehea_adapter *adapter)
+{
+ int i;
+
+ for (i=0; i < EHEA_MAX_PORTS; i++)
+ if (adapter->port[i])
+ return 0;
+
+ return ehea_reg_kernel_mr(adapter, &adapter->mr);
+}
+
static int ehea_up(struct net_device *dev)
{
int ret, i;
@@ -2208,8 +2254,10 @@ static int ehea_down(struct net_device *dev)
ehea_drop_multicast_list(dev);
ehea_free_interrupts(dev);
- for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
- tasklet_kill(&port->port_res[i].send_comp_task);
+ for (i = 0; i < port->num_def_qps; i++)
+ while (test_bit(__LINK_STATE_RX_SCHED,
+ &port->port_res[i].d_netdev->state))
+ msleep(1);
ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
ret = ehea_clean_all_portres(port);
@@ -2276,8 +2324,6 @@ static void ehea_tx_watchdog(struct net_device *dev)
int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
{
struct hcp_query_ehea *cb;
- struct device_node *lhea_dn = NULL;
- struct device_node *eth_dn = NULL;
u64 hret;
int ret;
@@ -2294,18 +2340,6 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
goto out_herr;
}
- /* Determine the number of available logical ports
- * by counting the child nodes of the lhea OFDT entry
- */
- adapter->num_ports = 0;
- lhea_dn = of_find_node_by_name(lhea_dn, "lhea");
- do {
- eth_dn = of_get_next_child(lhea_dn, eth_dn);
- if (eth_dn)
- adapter->num_ports++;
- } while ( eth_dn );
- of_node_put(lhea_dn);
-
adapter->max_mc_mac = cb->max_mc_mac - 1;
ret = 0;
@@ -2315,79 +2349,188 @@ out:
return ret;
}
-static int ehea_setup_single_port(struct ehea_port *port,
- struct device_node *dn)
+int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo)
{
- int ret;
- u64 hret;
- struct net_device *dev = port->netdev;
- struct ehea_adapter *adapter = port->adapter;
struct hcp_ehea_port_cb4 *cb4;
- u32 *dn_log_port_id;
- int jumbo = 0;
-
- sema_init(&port->port_lock, 1);
- port->state = EHEA_PORT_DOWN;
- port->sig_comp_iv = sq_entries / 10;
-
- if (!dn) {
- ehea_error("bad device node: dn=%p", dn);
- ret = -EINVAL;
- goto out;
- }
-
- port->of_dev_node = dn;
-
- /* Determine logical port id */
- dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL);
-
- if (!dn_log_port_id) {
- ehea_error("bad device node: dn_log_port_id=%p",
- dn_log_port_id);
- ret = -EINVAL;
- goto out;
- }
- port->logical_port_id = *dn_log_port_id;
-
- port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
- if (!port->mc_list) {
- ret = -ENOMEM;
- goto out;
- }
-
- INIT_LIST_HEAD(&port->mc_list->list);
+ u64 hret;
+ int ret = 0;
- ret = ehea_sense_port_attr(port);
- if (ret)
- goto out;
+ *jumbo = 0;
- /* Enable Jumbo frames */
+ /* (Try to) enable *jumbo frames */
cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL);
if (!cb4) {
ehea_error("no mem for cb4");
+ ret = -ENOMEM;
+ goto out;
} else {
- hret = ehea_h_query_ehea_port(adapter->handle,
+ hret = ehea_h_query_ehea_port(port->adapter->handle,
port->logical_port_id,
H_PORT_CB4,
H_PORT_CB4_JUMBO, cb4);
-
if (hret == H_SUCCESS) {
if (cb4->jumbo_frame)
- jumbo = 1;
+ *jumbo = 1;
else {
cb4->jumbo_frame = 1;
- hret = ehea_h_modify_ehea_port(adapter->handle,
+ hret = ehea_h_modify_ehea_port(port->adapter->
+ handle,
port->
- logical_port_id,
+ logical_port_id,
H_PORT_CB4,
H_PORT_CB4_JUMBO,
cb4);
if (hret == H_SUCCESS)
- jumbo = 1;
+ *jumbo = 1;
}
- }
+ } else
+ ret = -EINVAL;
+
kfree(cb4);
}
+out:
+ return ret;
+}
+
+static ssize_t ehea_show_port_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
+ return sprintf(buf, "0x%X", port->logical_port_id);
+}
+
+static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
+ NULL);
+
+static void __devinit logical_port_release(struct device *dev)
+{
+ struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
+ of_node_put(port->ofdev.node);
+}
+
+static int ehea_driver_sysfs_add(struct device *dev,
+ struct device_driver *driver)
+{
+ int ret;
+
+ ret = sysfs_create_link(&driver->kobj, &dev->kobj,
+ kobject_name(&dev->kobj));
+ if (ret == 0) {
+ ret = sysfs_create_link(&dev->kobj, &driver->kobj,
+ "driver");
+ if (ret)
+ sysfs_remove_link(&driver->kobj,
+ kobject_name(&dev->kobj));
+ }
+ return ret;
+}
+
+static void ehea_driver_sysfs_remove(struct device *dev,
+ struct device_driver *driver)
+{
+ struct device_driver *drv = driver;
+
+ if (drv) {
+ sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
+ sysfs_remove_link(&dev->kobj, "driver");
+ }
+}
+
+static struct device *ehea_register_port(struct ehea_port *port,
+ struct device_node *dn)
+{
+ int ret;
+
+ port->ofdev.node = of_node_get(dn);
+ port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev;
+ port->ofdev.dev.bus = &ibmebus_bus_type;
+
+ sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++);
+ port->ofdev.dev.release = logical_port_release;
+
+ ret = of_device_register(&port->ofdev);
+ if (ret) {
+ ehea_error("failed to register device. ret=%d", ret);
+ goto out;
+ }
+
+ ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id);
+ if (ret) {
+ ehea_error("failed to register attributes, ret=%d", ret);
+ goto out_unreg_of_dev;
+ }
+
+ ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver);
+ if (ret) {
+ ehea_error("failed to register sysfs driver link");
+ goto out_rem_dev_file;
+ }
+
+ return &port->ofdev.dev;
+
+out_rem_dev_file:
+ device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
+out_unreg_of_dev:
+ of_device_unregister(&port->ofdev);
+out:
+ return NULL;
+}
+
+static void ehea_unregister_port(struct ehea_port *port)
+{
+ ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver);
+ device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id);
+ of_device_unregister(&port->ofdev);
+}
+
+struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
+ u32 logical_port_id,
+ struct device_node *dn)
+{
+ int ret;
+ struct net_device *dev;
+ struct ehea_port *port;
+ struct device *port_dev;
+ int jumbo;
+
+ /* allocate memory for the port structures */
+ dev = alloc_etherdev(sizeof(struct ehea_port));
+
+ if (!dev) {
+ ehea_error("no mem for net_device");
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
+ port = netdev_priv(dev);
+
+ sema_init(&port->port_lock, 1);
+ port->state = EHEA_PORT_DOWN;
+ port->sig_comp_iv = sq_entries / 10;
+
+ port->adapter = adapter;
+ port->netdev = dev;
+ port->logical_port_id = logical_port_id;
+
+ port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+
+ port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
+ if (!port->mc_list) {
+ ret = -ENOMEM;
+ goto out_free_ethdev;
+ }
+
+ INIT_LIST_HEAD(&port->mc_list->list);
+
+ ret = ehea_sense_port_attr(port);
+ if (ret)
+ goto out_free_mc_list;
+
+ port_dev = ehea_register_port(port, dn);
+ if (!port_dev)
+ goto out_free_mc_list;
+
+ SET_NETDEV_DEV(dev, port_dev);
/* initialize net_device structure */
SET_MODULE_OWNER(dev);
@@ -2420,84 +2563,224 @@ static int ehea_setup_single_port(struct ehea_port *port,
ret = register_netdev(dev);
if (ret) {
ehea_error("register_netdev failed. ret=%d", ret);
- goto out_free;
+ goto out_unreg_port;
}
+ ret = ehea_get_jumboframe_status(port, &jumbo);
+ if (ret)
+ ehea_error("failed determining jumbo frame status for %s",
+ port->netdev->name);
+
ehea_info("%s: Jumbo frames are %sabled", dev->name,
jumbo == 1 ? "en" : "dis");
- port->netdev = dev;
- ret = 0;
- goto out;
+ return port;
-out_free:
+out_unreg_port:
+ ehea_unregister_port(port);
+
+out_free_mc_list:
kfree(port->mc_list);
-out:
- return ret;
+
+out_free_ethdev:
+ free_netdev(dev);
+
+out_err:
+ ehea_error("setting up logical port with id=%d failed, ret=%d",
+ logical_port_id, ret);
+ return NULL;
+}
+
+static void ehea_shutdown_single_port(struct ehea_port *port)
+{
+ unregister_netdev(port->netdev);
+ ehea_unregister_port(port);
+ kfree(port->mc_list);
+ free_netdev(port->netdev);
}
static int ehea_setup_ports(struct ehea_adapter *adapter)
{
- int ret;
- int port_setup_ok = 0;
+ struct device_node *lhea_dn;
+ struct device_node *eth_dn = NULL;
+ const u32 *dn_log_port_id;
+ int i = 0;
+
+ lhea_dn = adapter->ebus_dev->ofdev.node;
+ while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
+
+ dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
+ NULL);
+ if (!dn_log_port_id) {
+ ehea_error("bad device node: eth_dn name=%s",
+ eth_dn->full_name);
+ continue;
+ }
+
+ if (ehea_add_adapter_mr(adapter)) {
+ ehea_error("creating MR failed");
+ of_node_put(eth_dn);
+ return -EIO;
+ }
+
+ adapter->port[i] = ehea_setup_single_port(adapter,
+ *dn_log_port_id,
+ eth_dn);
+ if (adapter->port[i])
+ ehea_info("%s -> logical port id #%d",
+ adapter->port[i]->netdev->name,
+ *dn_log_port_id);
+ else
+ ehea_remove_adapter_mr(adapter);
+
+ i++;
+ };
+
+ return 0;
+}
+
+static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter,
+ u32 logical_port_id)
+{
+ struct device_node *lhea_dn;
+ struct device_node *eth_dn = NULL;
+ const u32 *dn_log_port_id;
+
+ lhea_dn = adapter->ebus_dev->ofdev.node;
+ while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) {
+
+ dn_log_port_id = of_get_property(eth_dn, "ibm,hea-port-no",
+ NULL);
+ if (dn_log_port_id)
+ if (*dn_log_port_id == logical_port_id)
+ return eth_dn;
+ };
+
+ return NULL;
+}
+
+static ssize_t ehea_probe_port(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ehea_adapter *adapter = dev->driver_data;
struct ehea_port *port;
- struct device_node *dn = NULL;
- struct net_device *dev;
+ struct device_node *eth_dn = NULL;
int i;
- /* get port properties for all ports */
- for (i = 0; i < adapter->num_ports; i++) {
+ u32 logical_port_id;
- if (adapter->port[i])
- continue; /* port already up and running */
+ sscanf(buf, "%X", &logical_port_id);
- /* allocate memory for the port structures */
- dev = alloc_etherdev(sizeof(struct ehea_port));
+ port = ehea_get_port(adapter, logical_port_id);
- if (!dev) {
- ehea_error("no mem for net_device");
- break;
- }
+ if (port) {
+ ehea_info("adding port with logical port id=%d failed. port "
+ "already configured as %s.", logical_port_id,
+ port->netdev->name);
+ return -EINVAL;
+ }
- port = netdev_priv(dev);
- port->adapter = adapter;
- port->netdev = dev;
- adapter->port[i] = port;
- port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+ eth_dn = ehea_get_eth_dn(adapter, logical_port_id);
- dn = of_find_node_by_name(dn, "ethernet");
- ret = ehea_setup_single_port(port, dn);
- if (ret) {
- /* Free mem for this port struct. The others will be
- processed on rollback */
- free_netdev(dev);
- adapter->port[i] = NULL;
- ehea_error("eHEA port %d setup failed, ret=%d", i, ret);
- }
+ if (!eth_dn) {
+ ehea_info("no logical port with id %d found", logical_port_id);
+ return -EINVAL;
}
- of_node_put(dn);
+ if (ehea_add_adapter_mr(adapter)) {
+ ehea_error("creating MR failed");
+ return -EIO;
+ }
- /* Check for succesfully set up ports */
- for (i = 0; i < adapter->num_ports; i++)
- if (adapter->port[i])
- port_setup_ok++;
+ port = ehea_setup_single_port(adapter, logical_port_id, eth_dn);
- if (port_setup_ok)
- ret = 0; /* At least some ports are setup correctly */
- else
- ret = -EINVAL;
+ of_node_put(eth_dn);
+
+ if (port) {
+ for (i=0; i < EHEA_MAX_PORTS; i++)
+ if (!adapter->port[i]) {
+ adapter->port[i] = port;
+ break;
+ }
+
+ ehea_info("added %s (logical port id=%d)", port->netdev->name,
+ logical_port_id);
+ } else {
+ ehea_remove_adapter_mr(adapter);
+ return -EIO;
+ }
+
+ return (ssize_t) count;
+}
+
+static ssize_t ehea_remove_port(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ehea_adapter *adapter = dev->driver_data;
+ struct ehea_port *port;
+ int i;
+ u32 logical_port_id;
+
+ sscanf(buf, "%X", &logical_port_id);
+
+ port = ehea_get_port(adapter, logical_port_id);
+ if (port) {
+ ehea_info("removed %s (logical port id=%d)", port->netdev->name,
+ logical_port_id);
+
+ ehea_shutdown_single_port(port);
+
+ for (i=0; i < EHEA_MAX_PORTS; i++)
+ if (adapter->port[i] == port) {
+ adapter->port[i] = NULL;
+ break;
+ }
+ } else {
+ ehea_error("removing port with logical port id=%d failed. port "
+ "not configured.", logical_port_id);
+ return -EINVAL;
+ }
+
+ ehea_remove_adapter_mr(adapter);
+
+ return (ssize_t) count;
+}
+
+static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port);
+static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port);
+
+int ehea_create_device_sysfs(struct ibmebus_dev *dev)
+{
+ int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port);
+ if (ret)
+ goto out;
+
+ ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port);
+out:
return ret;
}
-static int __devinit ehea_probe(struct ibmebus_dev *dev,
- const struct of_device_id *id)
+void ehea_remove_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port);
+}
+
+static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
+ const struct of_device_id *id)
{
struct ehea_adapter *adapter;
- u64 *adapter_handle;
+ const u64 *adapter_handle;
int ret;
+ if (!dev || !dev->ofdev.node) {
+ ehea_error("Invalid ibmebus device probed");
+ return -EINVAL;
+ }
+
adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
if (!adapter) {
ret = -ENOMEM;
@@ -2505,7 +2788,9 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
goto out;
}
- adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
+ adapter->ebus_dev = dev;
+
+ adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
NULL);
if (adapter_handle)
adapter->handle = *adapter_handle;
@@ -2521,26 +2806,21 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
dev->ofdev.dev.driver_data = adapter;
- ret = ehea_reg_mr_adapter(adapter);
- if (ret) {
- dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n");
- goto out_free_ad;
- }
/* initialize adapter and ports */
/* get adapter properties */
ret = ehea_sense_adapter_attr(adapter);
if (ret) {
dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
- goto out_free_res;
+ goto out_free_ad;
}
- dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports);
adapter->neq = ehea_create_eq(adapter,
EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
if (!adapter->neq) {
+ ret = -EIO;
dev_err(&dev->ofdev.dev, "NEQ creation failed");
- goto out_free_res;
+ goto out_free_ad;
}
tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
@@ -2555,18 +2835,27 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev,
}
adapter->ehea_wq = create_workqueue("ehea_wq");
- if (!adapter->ehea_wq)
+ if (!adapter->ehea_wq) {
+ ret = -EIO;
goto out_free_irq;
+ }
+
+ ret = ehea_create_device_sysfs(dev);
+ if (ret)
+ goto out_kill_wq;
ret = ehea_setup_ports(adapter);
if (ret) {
dev_err(&dev->ofdev.dev, "setup_ports failed");
- goto out_kill_wq;
+ goto out_rem_dev_sysfs;
}
ret = 0;
goto out;
+out_rem_dev_sysfs:
+ ehea_remove_device_sysfs(dev);
+
out_kill_wq:
destroy_workqueue(adapter->ehea_wq);
@@ -2576,45 +2865,32 @@ out_free_irq:
out_kill_eq:
ehea_destroy_eq(adapter->neq);
-out_free_res:
- ehea_h_free_resource(adapter->handle, adapter->mr.handle);
-
out_free_ad:
kfree(adapter);
out:
return ret;
}
-static void ehea_shutdown_single_port(struct ehea_port *port)
-{
- unregister_netdev(port->netdev);
- kfree(port->mc_list);
- free_netdev(port->netdev);
-}
-
static int __devexit ehea_remove(struct ibmebus_dev *dev)
{
struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
- u64 hret;
int i;
- for (i = 0; i < adapter->num_ports; i++)
+ for (i = 0; i < EHEA_MAX_PORTS; i++)
if (adapter->port[i]) {
ehea_shutdown_single_port(adapter->port[i]);
adapter->port[i] = NULL;
}
+
+ ehea_remove_device_sysfs(dev);
+
destroy_workqueue(adapter->ehea_wq);
ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
tasklet_kill(&adapter->neq_tasklet);
ehea_destroy_eq(adapter->neq);
-
- hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle);
- if (hret) {
- dev_err(&dev->ofdev.dev, "free_resource_mr failed");
- return -EIO;
- }
+ ehea_remove_adapter_mr(adapter);
kfree(adapter);
return 0;
}
@@ -2647,21 +2923,6 @@ static int check_module_parm(void)
return ret;
}
-static struct of_device_id ehea_device_table[] = {
- {
- .name = "lhea",
- .compatible = "IBM,lhea",
- },
- {},
-};
-
-static struct ibmebus_driver ehea_driver = {
- .name = "ehea",
- .id_table = ehea_device_table,
- .probe = ehea_probe,
- .remove = ehea_remove,
-};
-
int __init ehea_module_init(void)
{
int ret;
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index bc3c0054726..95c4a7f9cc8 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -478,12 +478,14 @@ u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
0, 0, 0, 0, 0, 0); /* R7-R12 */
}
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+ u64 force_bit)
{
return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
adapter_handle, /* R4 */
res_handle, /* R5 */
- 0, 0, 0, 0, 0); /* R6-R10 */
+ force_bit,
+ 0, 0, 0, 0); /* R7-R10 */
}
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 90acddb068a..d17a45a7e71 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -414,7 +414,11 @@ u64 ehea_h_register_rpage(const u64 adapter_handle,
u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle);
-u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle);
+#define FORCE_FREE 1
+#define NORMAL_FREE 0
+
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle,
+ u64 force_bit);
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
const u64 length, const u32 access_ctrl,
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 96ff3b67999..f24a8862977 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -197,7 +197,7 @@ out_kill_hwq:
hw_queue_dtor(&cq->hw_queue);
out_freeres:
- ehea_h_free_resource(adapter->handle, cq->fw_handle);
+ ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE);
out_freemem:
kfree(cq);
@@ -206,25 +206,38 @@ out_nomem:
return NULL;
}
-int ehea_destroy_cq(struct ehea_cq *cq)
+u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force)
{
- u64 adapter_handle, hret;
+ u64 hret;
+ u64 adapter_handle = cq->adapter->handle;
+
+ /* deregister all previous registered pages */
+ hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force);
+ if (hret != H_SUCCESS)
+ return hret;
+
+ hw_queue_dtor(&cq->hw_queue);
+ kfree(cq);
+
+ return hret;
+}
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+ u64 hret;
if (!cq)
return 0;
- adapter_handle = cq->adapter->handle;
+ if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(cq->adapter, cq->fw_handle);
+ hret = ehea_destroy_cq_res(cq, FORCE_FREE);
+ }
- /* deregister all previous registered pages */
- hret = ehea_h_free_resource(adapter_handle, cq->fw_handle);
if (hret != H_SUCCESS) {
ehea_error("destroy CQ failed");
return -EIO;
}
- hw_queue_dtor(&cq->hw_queue);
- kfree(cq);
-
return 0;
}
@@ -297,7 +310,7 @@ out_kill_hwq:
hw_queue_dtor(&eq->hw_queue);
out_freeres:
- ehea_h_free_resource(adapter->handle, eq->fw_handle);
+ ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE);
out_freemem:
kfree(eq);
@@ -316,27 +329,41 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
return eqe;
}
-int ehea_destroy_eq(struct ehea_eq *eq)
+u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force)
{
u64 hret;
unsigned long flags;
- if (!eq)
- return 0;
-
spin_lock_irqsave(&eq->spinlock, flags);
- hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle);
+ hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force);
spin_unlock_irqrestore(&eq->spinlock, flags);
- if (hret != H_SUCCESS) {
- ehea_error("destroy_eq failed");
- return -EIO;
- }
+ if (hret != H_SUCCESS)
+ return hret;
hw_queue_dtor(&eq->hw_queue);
kfree(eq);
+ return hret;
+}
+
+int ehea_destroy_eq(struct ehea_eq *eq)
+{
+ u64 hret;
+ if (!eq)
+ return 0;
+
+ if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(eq->adapter, eq->fw_handle);
+ hret = ehea_destroy_eq_res(eq, FORCE_FREE);
+ }
+
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy EQ failed");
+ return -EIO;
+ }
+
return 0;
}
@@ -471,41 +498,56 @@ out_kill_hwsq:
out_freeres:
ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
- ehea_h_free_resource(adapter->handle, qp->fw_handle);
+ ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE);
out_freemem:
kfree(qp);
return NULL;
}
-int ehea_destroy_qp(struct ehea_qp *qp)
+u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force)
{
- u64 hret;
- struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+ u64 hret;
+ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
- if (!qp)
- return 0;
- ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
- hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
- if (hret != H_SUCCESS) {
- ehea_error("destroy_qp failed");
- return -EIO;
- }
+ ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle);
+ hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force);
+ if (hret != H_SUCCESS)
+ return hret;
- hw_queue_dtor(&qp->hw_squeue);
- hw_queue_dtor(&qp->hw_rqueue1);
+ hw_queue_dtor(&qp->hw_squeue);
+ hw_queue_dtor(&qp->hw_rqueue1);
- if (qp_attr->rq_count > 1)
- hw_queue_dtor(&qp->hw_rqueue2);
- if (qp_attr->rq_count > 2)
- hw_queue_dtor(&qp->hw_rqueue3);
- kfree(qp);
+ if (qp_attr->rq_count > 1)
+ hw_queue_dtor(&qp->hw_rqueue2);
+ if (qp_attr->rq_count > 2)
+ hw_queue_dtor(&qp->hw_rqueue3);
+ kfree(qp);
- return 0;
+ return hret;
}
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+ u64 hret;
+ if (!qp)
+ return 0;
+
+ if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
+ ehea_error_data(qp->adapter, qp->fw_handle);
+ hret = ehea_destroy_qp_res(qp, FORCE_FREE);
+ }
+
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy QP failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
{
int i, k, ret;
u64 hret, pt_abs, start, end, nr_pages;
@@ -526,14 +568,14 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
acc_ctrl, adapter->pd,
- &adapter->mr.handle, &adapter->mr.lkey);
+ &mr->handle, &mr->lkey);
if (hret != H_SUCCESS) {
ehea_error("alloc_resource_mr failed");
ret = -EIO;
goto out;
}
- adapter->mr.vaddr = KERNELBASE;
+ mr->vaddr = KERNELBASE;
k = 0;
while (nr_pages > 0) {
@@ -545,7 +587,7 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle,
- adapter->mr.handle, 0,
+ mr->handle, 0,
0, (u64)pt_abs,
num_pages);
nr_pages -= num_pages;
@@ -554,34 +596,68 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
(k * EHEA_PAGESIZE)));
hret = ehea_h_register_rpage_mr(adapter->handle,
- adapter->mr.handle, 0,
+ mr->handle, 0,
0, abs_adr,1);
nr_pages--;
}
if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
ehea_h_free_resource(adapter->handle,
- adapter->mr.handle);
- ehea_error("register_rpage_mr failed: hret = %lX",
- hret);
+ mr->handle, FORCE_FREE);
+ ehea_error("register_rpage_mr failed");
ret = -EIO;
goto out;
}
}
if (hret != H_SUCCESS) {
- ehea_h_free_resource(adapter->handle, adapter->mr.handle);
- ehea_error("register_rpage failed for last page: hret = %lX",
- hret);
+ ehea_h_free_resource(adapter->handle, mr->handle,
+ FORCE_FREE);
+ ehea_error("register_rpage failed for last page");
ret = -EIO;
goto out;
}
+
+ mr->adapter = adapter;
ret = 0;
out:
kfree(pt);
return ret;
}
+int ehea_rem_mr(struct ehea_mr *mr)
+{
+ u64 hret;
+
+ if (!mr || !mr->adapter)
+ return -EINVAL;
+
+ hret = ehea_h_free_resource(mr->adapter->handle, mr->handle,
+ FORCE_FREE);
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy MR failed");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+ struct ehea_mr *shared_mr)
+{
+ u64 hret;
+
+ hret = ehea_h_register_smr(adapter->handle, old_mr->handle,
+ old_mr->vaddr, EHEA_MR_ACC_CTRL,
+ adapter->pd, shared_mr);
+ if (hret != H_SUCCESS)
+ return -EIO;
+
+ shared_mr->adapter = adapter;
+
+ return 0;
+}
+
void print_error_data(u64 *data)
{
int length;
@@ -597,6 +673,14 @@ void print_error_data(u64 *data)
ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, "
"port=%lX", resource, data[6], data[12], data[22]);
+ if (type == 0x4) /* Completion Queue */
+ ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource,
+ data[6]);
+
+ if (type == 0x3) /* Event Queue */
+ ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource,
+ data[6]);
+
ehea_dump(data, length, "error data");
}
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 1ff60983504..c0eb3e03a10 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -142,6 +142,8 @@ struct ehea_rwqe {
#define EHEA_CQE_STAT_ERR_MASK 0x721F
#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
#define EHEA_CQE_STAT_ERR_TCP 0x4000
+#define EHEA_CQE_STAT_ERR_IP 0x2000
+#define EHEA_CQE_STAT_ERR_CRC 0x1000
struct ehea_cqe {
u64 wr_id; /* work request ID from WQE */
@@ -320,6 +322,11 @@ static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
return hw_qeit_get_valid(queue);
}
+static inline void ehea_inc_cq(struct ehea_cq *cq)
+{
+ hw_qeit_inc(&cq->hw_queue);
+}
+
static inline void ehea_inc_rq1(struct ehea_qp *qp)
{
hw_qeit_inc(&qp->hw_rqueue1);
@@ -327,7 +334,7 @@ static inline void ehea_inc_rq1(struct ehea_qp *qp)
static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
{
- return hw_qeit_get_inc_valid(&my_cq->hw_queue);
+ return hw_qeit_get_valid(&my_cq->hw_queue);
}
#define EHEA_CQ_REGISTER_ORIG 0
@@ -356,7 +363,12 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
int ehea_destroy_qp(struct ehea_qp *qp);
-int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr);
+
+int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr,
+ struct ehea_mr *shared_mr);
+
+int ehea_rem_mr(struct ehea_mr *mr);
void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 4e3f14c9c71..5e517946f46 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -93,8 +93,6 @@ static int rx_copybreak;
static char version[] __devinitdata =
DRV_NAME ".c:v1.11 1/7/2001 Written by Donald Becker <becker@scyld.com>\n";
static char version2[] __devinitdata =
-" http://www.scyld.com/network/epic100.html\n";
-static char version3[] __devinitdata =
" (unofficial 2.4.x kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -323,8 +321,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
#ifndef MODULE
static int printed_version;
if (!printed_version++)
- printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
- version, version2, version3);
+ printk (KERN_INFO "%s" KERN_INFO "%s",
+ version, version2);
#endif
card_idx++;
@@ -1596,8 +1594,8 @@ static int __init epic_init (void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
- printk (KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
- version, version2, version3);
+ printk (KERN_INFO "%s" KERN_INFO "%s",
+ version, version2);
#endif
return pci_register_driver(&epic_driver);
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index e824d5d231a..88efe9731ba 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -19,7 +19,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index e79700abf7b..b3fa0d6a159 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -19,7 +19,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index e2ddd617493..a4a2a0ea43d 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -24,7 +24,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 8545e84fc9a..5603121132c 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -21,7 +21,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index cdcfb96f360..04b4f80a1cd 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -21,7 +21,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 65925b5a224..d0f28981b55 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -21,7 +21,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index f91447837fd..d3840108ffb 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -22,7 +22,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 235b177fb9a..0a563a83016 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -21,7 +21,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig
index 6e90619b3b4..36d2c7d4f4d 100644
--- a/drivers/net/hamradio/Kconfig
+++ b/drivers/net/hamradio/Kconfig
@@ -140,7 +140,7 @@ config BAYCOM_SER_HDX
modems that connect to a serial interface. The driver supports the
ser12 design in half-duplex mode. This is the old driver. It is
still provided in case your serial interface chip does not work with
- the full-duplex driver. This driver is depreciated. To configure
+ the full-duplex driver. This driver is deprecated. To configure
the driver, use the sethdlc utility available in the standard ax25
utilities package. For information on the modems, see
<http://www.baycom.de/> and
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 30baf6ecfc6..17ac6975d70 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -415,11 +415,18 @@ static int ser12_open(struct net_device *dev)
if (!dev || !bc)
return -ENXIO;
- if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
- dev->irq < 2 || dev->irq > 15)
+ if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
+ dev->irq < 2 || dev->irq > NR_IRQS) {
+ printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
+ "or irq (2 <= irq <= %d)\n",
+ 0xffff-SER12_EXTENT, NR_IRQS);
return -ENXIO;
- if (bc->baud < 300 || bc->baud > 4800)
+ }
+ if (bc->baud < 300 || bc->baud > 4800) {
+ printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
+ "(300...4800)\n");
return -EINVAL;
+ }
if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n",
dev->base_addr);
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index 3d82d46f499..50035ebd4f5 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -27,7 +27,6 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 0573fcfcb2c..3bec0f733f0 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -93,7 +93,7 @@ static void ibmveth_proc_unregister_driver(void);
static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
static struct kobj_type ktype_veth_pool;
#ifdef CONFIG_PROC_FS
@@ -389,7 +389,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
}
}
-static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
+static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
{
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
@@ -953,14 +953,16 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n",
dev->unit_address);
- mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0);
+ mac_addr_p = (unsigned char *) vio_get_attribute(dev,
+ VETH_MAC_ADDR, NULL);
if(!mac_addr_p) {
printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR "
"attribute\n", __FILE__, __LINE__);
return 0;
}
- mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0);
+ mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev,
+ VETH_MCAST_FILTER_SIZE, NULL);
if(!mcastFilterSize_p) {
printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find "
"VETH_MCAST_FILTER_SIZE attribute\n",
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 2ab173d9a0e..1e67720f106 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -113,7 +113,7 @@
/* RxOver overflow in Recv FIFO */
/* SipRcv received serial gap (or other condition you set) */
/* Interrupts are enabled by writing a one to the IER register */
-/* Interrupts are cleared by writting a one to the ISR register */
+/* Interrupts are cleared by writing a one to the ISR register */
/* */
/* 6. The remaining registers: 0x6 and 0x3 appear to be */
/* reserved parts of 16 or 32 bit registersthe remainder */
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index fb196fd9185..55ff0fbe525 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -134,7 +134,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
DCSR(si->rxdma) &= ~DCSR_RUN;
/* disable FICP */
ICCR0 = 0;
- pxa_set_cken(CKEN13_FICP, 0);
+ pxa_set_cken(CKEN_FICP, 0);
/* set board transceiver to SIR mode */
si->pdata->transceiver_mode(si->dev, IR_SIRMODE);
@@ -144,7 +144,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
pxa_gpio_mode(GPIO47_STTXD_MD);
/* enable the STUART clock */
- pxa_set_cken(CKEN5_STUART, 1);
+ pxa_set_cken(CKEN_STUART, 1);
}
/* disable STUART first */
@@ -169,7 +169,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
/* disable STUART */
STIER = 0;
STISR = 0;
- pxa_set_cken(CKEN5_STUART, 0);
+ pxa_set_cken(CKEN_STUART, 0);
/* disable FICP first */
ICCR0 = 0;
@@ -182,7 +182,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
pxa_gpio_mode(GPIO47_ICPTXD_MD);
/* enable the FICP clock */
- pxa_set_cken(CKEN13_FICP, 1);
+ pxa_set_cken(CKEN_FICP, 1);
si->speed = speed;
pxa_irda_fir_dma_rx_start(si);
@@ -593,7 +593,7 @@ static void pxa_irda_shutdown(struct pxa_irda *si)
/* disable STUART SIR mode */
STISR = 0;
/* disable the STUART clock */
- pxa_set_cken(CKEN5_STUART, 0);
+ pxa_set_cken(CKEN_STUART, 0);
/* disable DMA */
DCSR(si->txdma) &= ~DCSR_RUN;
@@ -601,7 +601,7 @@ static void pxa_irda_shutdown(struct pxa_irda *si)
/* disable FICP */
ICCR0 = 0;
/* disable the FICP clock */
- pxa_set_cken(CKEN13_FICP, 0);
+ pxa_set_cken(CKEN_FICP, 0);
DRCMR17 = 0;
DRCMR18 = 0;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 17b0c3ab620..9d6c8f391b2 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <net/irda/irda.h>
diff --git a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c
index d7e32d9554f..25d5b8a96bd 100644
--- a/drivers/net/irda/sir_dongle.c
+++ b/drivers/net/irda/sir_dongle.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/kmod.h>
#include <linux/mutex.h>
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 198bf3bfa70..9043bf4aa49 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -79,11 +79,17 @@ MODULE_AUTHOR("Daniele Peri <peri@csai.unipa.it>");
MODULE_DESCRIPTION("SMC IrCC SIR/FIR controller driver");
MODULE_LICENSE("GPL");
-static int ircc_dma = 255;
+static int smsc_nopnp;
+module_param_named(nopnp, smsc_nopnp, bool, 0);
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
+
+#define DMA_INVAL 255
+static int ircc_dma = DMA_INVAL;
module_param(ircc_dma, int, 0);
MODULE_PARM_DESC(ircc_dma, "DMA channel");
-static int ircc_irq = 255;
+#define IRQ_INVAL 255
+static int ircc_irq = IRQ_INVAL;
module_param(ircc_irq, int, 0);
MODULE_PARM_DESC(ircc_irq, "IRQ line");
@@ -360,7 +366,6 @@ static inline void register_bank(int iobase, int bank)
iobase + IRCC_MASTER);
}
-#ifdef CONFIG_PNP
/* PNP hotplug support */
static const struct pnp_device_id smsc_ircc_pnp_table[] = {
{ .id = "SMCf010", .driver_data = 0 },
@@ -368,7 +373,35 @@ static const struct pnp_device_id smsc_ircc_pnp_table[] = {
{ }
};
MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
-#endif
+
+static int pnp_driver_registered;
+
+static int __init smsc_ircc_pnp_probe(struct pnp_dev *dev,
+ const struct pnp_device_id *dev_id)
+{
+ unsigned int firbase, sirbase;
+ u8 dma, irq;
+
+ if (!(pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
+ pnp_dma_valid(dev, 0) && pnp_irq_valid(dev, 0)))
+ return -EINVAL;
+
+ sirbase = pnp_port_start(dev, 0);
+ firbase = pnp_port_start(dev, 1);
+ dma = pnp_dma(dev, 0);
+ irq = pnp_irq(dev, 0);
+
+ if (smsc_ircc_open(firbase, sirbase, dma, irq))
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct pnp_driver smsc_ircc_pnp_driver = {
+ .name = "smsc-ircc2",
+ .id_table = smsc_ircc_pnp_table,
+ .probe = smsc_ircc_pnp_probe,
+};
/*******************************************************************************
@@ -379,6 +412,35 @@ MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
*
*******************************************************************************/
+static int __init smsc_ircc_legacy_probe(void)
+{
+ int ret = 0;
+
+ if (ircc_fir > 0 && ircc_sir > 0) {
+ IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
+ IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
+
+ if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
+ ret = -ENODEV;
+ } else {
+ ret = -ENODEV;
+
+ /* try user provided configuration register base address */
+ if (ircc_cfg > 0) {
+ IRDA_MESSAGE(" Overriding configuration address "
+ "0x%04x\n", ircc_cfg);
+ if (!smsc_superio_fdc(ircc_cfg))
+ ret = 0;
+ if (!smsc_superio_lpc(ircc_cfg))
+ ret = 0;
+ }
+
+ if (smsc_ircc_look_for_chips() > 0)
+ ret = 0;
+ }
+ return ret;
+}
+
/*
* Function smsc_ircc_init ()
*
@@ -406,31 +468,20 @@ static int __init smsc_ircc_init(void)
dev_count = 0;
- if (ircc_fir > 0 && ircc_sir > 0) {
- IRDA_MESSAGE(" Overriding FIR address 0x%04x\n", ircc_fir);
- IRDA_MESSAGE(" Overriding SIR address 0x%04x\n", ircc_sir);
-
- if (smsc_ircc_open(ircc_fir, ircc_sir, ircc_dma, ircc_irq))
- ret = -ENODEV;
+ if (smsc_nopnp || !pnp_platform_devices ||
+ ircc_cfg || ircc_fir || ircc_sir ||
+ ircc_dma != DMA_INVAL || ircc_irq != IRQ_INVAL) {
+ ret = smsc_ircc_legacy_probe();
} else {
- ret = -ENODEV;
-
- /* try user provided configuration register base address */
- if (ircc_cfg > 0) {
- IRDA_MESSAGE(" Overriding configuration address "
- "0x%04x\n", ircc_cfg);
- if (!smsc_superio_fdc(ircc_cfg))
- ret = 0;
- if (!smsc_superio_lpc(ircc_cfg))
- ret = 0;
- }
-
- if (smsc_ircc_look_for_chips() > 0)
- ret = 0;
+ if (pnp_register_driver(&smsc_ircc_pnp_driver) == 0)
+ pnp_driver_registered = 1;
}
- if (ret)
+ if (ret) {
+ if (pnp_driver_registered)
+ pnp_unregister_driver(&smsc_ircc_pnp_driver);
platform_driver_unregister(&smsc_ircc_driver);
+ }
return ret;
}
@@ -646,7 +697,7 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
self->io.fifo_size = SMSC_IRCC2_FIFO_SIZE;
self->io.speed = SMSC_IRCC2_C_IRDA_FALLBACK_SPEED;
- if (irq < 255) {
+ if (irq != IRQ_INVAL) {
if (irq != chip_irq)
IRDA_MESSAGE("%s, Overriding IRQ - chip says %d, using %d\n",
driver_name, chip_irq, irq);
@@ -654,7 +705,7 @@ static void smsc_ircc_setup_io(struct smsc_ircc_cb *self,
} else
self->io.irq = chip_irq;
- if (dma < 255) {
+ if (dma != DMA_INVAL) {
if (dma != chip_dma)
IRDA_MESSAGE("%s, Overriding DMA - chip says %d, using %d\n",
driver_name, chip_dma, dma);
@@ -1840,6 +1891,9 @@ static void __exit smsc_ircc_cleanup(void)
smsc_ircc_close(dev_self[i]);
}
+ if (pnp_driver_registered)
+ pnp_unregister_driver(&smsc_ircc_pnp_driver);
+
platform_driver_unregister(&smsc_ircc_driver);
}
@@ -2836,9 +2890,9 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
tmpconf.fir_io = ircc_fir;
if (ircc_sir != 0)
tmpconf.sir_io = ircc_sir;
- if (ircc_dma != 0xff)
+ if (ircc_dma != DMA_INVAL)
tmpconf.fir_dma = ircc_dma;
- if (ircc_irq != 0xff)
+ if (ircc_irq != IRQ_INVAL)
tmpconf.fir_irq = ircc_irq;
IRDA_MESSAGE("Detected unconfigured %s SMSC IrDA chip, pre-configuring device.\n", conf->name);
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index c4be973867a..bf78ef1120a 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -44,7 +44,6 @@ MODULE_LICENSE("GPL");
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index cf30a1059ce..c8e90861f86 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -111,9 +111,6 @@ struct ixgb_adapter;
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */
-/* only works for sizes that are powers of 2 */
-#define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
-
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgb_buffer {
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index f15aebde7b9..52c99d01d56 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -315,7 +315,7 @@ ixgb_wait_eeprom_command(struct ixgb_hw *hw)
* hw - Struct containing variables accessed by shared code
*
* Reads the first 64 16 bit words of the EEPROM and sums the values read.
- * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * If the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
* valid.
*
* Returns:
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index d6628bd9590..afde84868be 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -577,11 +577,11 @@ ixgb_set_ringparam(struct net_device *netdev,
rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD);
- IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
+ rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD);
txdr->count = min(txdr->count,(uint32_t)MAX_TXD);
- IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
+ txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
if(netif_running(adapter->netdev)) {
/* Try to get new resources before deleting old */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index dfde80e54ae..6d2b059371f 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -685,7 +685,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter)
/* round up to nearest 4K */
txdr->size = txdr->count * sizeof(struct ixgb_tx_desc);
- IXGB_ROUNDUP(txdr->size, 4096);
+ txdr->size = ALIGN(txdr->size, 4096);
txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
if(!txdr->desc) {
@@ -774,7 +774,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter)
/* Round up to nearest 4K */
rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc);
- IXGB_ROUNDUP(rxdr->size, 4096);
+ rxdr->size = ALIGN(rxdr->size, 4096);
rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
index 8434d752fd8..9e04a6b3ae0 100644
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ixgb/ixgb_osdep.h
@@ -34,7 +34,6 @@
#define _IXGB_OSDEP_H_
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/interrupt.h>
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index b27442a121f..5d5ddabf436 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -245,8 +245,6 @@ ixgb_validate_option(int *value, struct ixgb_option *opt)
return -1;
}
-#define LIST_LEN(l) (sizeof(l) / sizeof(l[0]))
-
/**
* ixgb_check_options - Range Checking for Command Line Parameters
* @adapter: board private structure
@@ -284,7 +282,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
tx_ring->count = opt.def;
}
- IXGB_ROUNDUP(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
+ tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Descriptor Count */
struct ixgb_option opt = {
@@ -303,7 +301,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
} else {
rx_ring->count = opt.def;
}
- IXGB_ROUNDUP(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
+ rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE);
}
{ /* Receive Checksum Offload Enable */
struct ixgb_option opt = {
@@ -335,7 +333,7 @@ ixgb_check_options(struct ixgb_adapter *adapter)
.name = "Flow Control",
.err = "reading default settings from EEPROM",
.def = ixgb_fc_tx_pause,
- .arg = { .l = { .nr = LIST_LEN(fc_list),
+ .arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index d34afb52ea7..75f6f441e87 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -88,6 +88,23 @@ static unsigned short known_revisions[] =
0xffff /* end of list */
};
+static int jazzsonic_open(struct net_device* dev)
+{
+ if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+ return sonic_open(dev);
+}
+
+static int jazzsonic_close(struct net_device* dev)
+{
+ int err;
+ err = sonic_close(dev);
+ free_irq(dev->irq, dev);
+ return err;
+}
+
static int __init sonic_probe1(struct net_device *dev)
{
static unsigned version_printed;
@@ -169,8 +186,8 @@ static int __init sonic_probe1(struct net_device *dev)
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
- dev->open = sonic_open;
- dev->stop = sonic_close;
+ dev->open = jazzsonic_open;
+ dev->stop = jazzsonic_close;
dev->hard_start_xmit = sonic_send_packet;
dev->get_stats = sonic_get_stats;
dev->set_multicast_list = &sonic_multicast_list;
@@ -260,8 +277,6 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
-#define SONIC_IRQ_FLAG IRQF_DISABLED
-
#include "sonic.c"
static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
@@ -269,11 +284,11 @@ static int __devexit jazz_sonic_device_remove (struct platform_device *pdev)
struct net_device *dev = platform_get_drvdata(pdev);
struct sonic_local* lp = netdev_priv(dev);
- unregister_netdev (dev);
+ unregister_netdev(dev);
dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
release_region (dev->base_addr, SONIC_MEM_SIZE);
- free_netdev (dev);
+ free_netdev(dev);
return 0;
}
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 0edcd125fd6..6b49fc4bd1a 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -81,7 +81,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/types.h>
#include <linux/bitops.h>
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index a12bb64e369..90b0c3ed4bb 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -14,6 +14,8 @@
/* 2001-05-15: support for Cabletron ported from old daynaport driver
* and fixed access to Sonic Sys card which masquerades as a Farallon
* by rayk@knightsmanor.org */
+/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */
+/* 2003-12-26: Make sure Asante cards always work. */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -61,25 +63,21 @@ static char version[] =
#define DAYNA_8390_BASE 0x80000
#define DAYNA_8390_MEM 0x00000
-#define KINETICS_8390_BASE 0x80000
-#define KINETICS_8390_MEM 0x00000
-
#define CABLETRON_8390_BASE 0x90000
#define CABLETRON_8390_MEM 0x00000
+#define INTERLAN_8390_BASE 0xE0000
+#define INTERLAN_8390_MEM 0xD0000
+
enum mac8390_type {
MAC8390_NONE = -1,
MAC8390_APPLE,
MAC8390_ASANTE,
- MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */
+ MAC8390_FARALLON,
MAC8390_CABLETRON,
MAC8390_DAYNA,
MAC8390_INTERLAN,
MAC8390_KINETICS,
- MAC8390_FOCUS,
- MAC8390_SONICSYS,
- MAC8390_DAYNA2,
- MAC8390_DAYNA3,
};
static const char * cardname[] = {
@@ -90,10 +88,6 @@ static const char * cardname[] = {
"dayna",
"interlan",
"kinetics",
- "focus",
- "sonic systems",
- "dayna2",
- "dayna_lc",
};
static int word16[] = {
@@ -104,10 +98,6 @@ static int word16[] = {
0, /* dayna */
1, /* interlan */
0, /* kinetics */
- 1, /* focus (??) */
- 1, /* sonic systems */
- 1, /* dayna2 */
- 1, /* dayna-lc */
};
/* on which cards do we use NuBus resources? */
@@ -119,10 +109,12 @@ static int useresources[] = {
0, /* dayna */
0, /* interlan */
0, /* kinetics */
- 0, /* focus (??) */
- 1, /* sonic systems */
- 1, /* dayna2 */
- 1, /* dayna-lc */
+};
+
+enum mac8390_access {
+ ACCESS_UNKNOWN = 0,
+ ACCESS_32,
+ ACCESS_16,
};
extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
@@ -134,8 +126,9 @@ static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev,
static int mac8390_open(struct net_device * dev);
static int mac8390_close(struct net_device * dev);
static void mac8390_no_reset(struct net_device *dev);
+static void interlan_reset(struct net_device *dev);
-/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/
+/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/
static void sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page);
static void sane_block_input(struct net_device * dev, int count,
@@ -172,23 +165,93 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count);
enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
{
- if (dev->dr_sw == NUBUS_DRSW_ASANTE)
- return MAC8390_ASANTE;
- if (dev->dr_sw == NUBUS_DRSW_FARALLON)
- return MAC8390_FARALLON;
- if (dev->dr_sw == NUBUS_DRSW_KINETICS)
- return MAC8390_KINETICS;
- if (dev->dr_sw == NUBUS_DRSW_DAYNA)
- return MAC8390_DAYNA;
- if (dev->dr_sw == NUBUS_DRSW_DAYNA2)
- return MAC8390_DAYNA2;
- if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC)
- return MAC8390_DAYNA3;
- if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
- return MAC8390_CABLETRON;
+ switch (dev->dr_sw) {
+ case NUBUS_DRSW_3COM:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_APPLE_SONIC_NB:
+ case NUBUS_DRHW_APPLE_SONIC_LC:
+ case NUBUS_DRHW_SONNET:
+ return MAC8390_NONE;
+ break;
+ default:
+ return MAC8390_APPLE;
+ break;
+ }
+ break;
+
+ case NUBUS_DRSW_APPLE:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_ASANTE_LC:
+ return MAC8390_NONE;
+ break;
+ case NUBUS_DRHW_CABLETRON:
+ return MAC8390_CABLETRON;
+ break;
+ default:
+ return MAC8390_APPLE;
+ break;
+ }
+ break;
+
+ case NUBUS_DRSW_ASANTE:
+ return MAC8390_ASANTE;
+ break;
+
+ case NUBUS_DRSW_TECHWORKS:
+ case NUBUS_DRSW_DAYNA2:
+ case NUBUS_DRSW_DAYNA_LC:
+ if (dev->dr_hw == NUBUS_DRHW_CABLETRON)
+ return MAC8390_CABLETRON;
+ else
+ return MAC8390_APPLE;
+ break;
+
+ case NUBUS_DRSW_FARALLON:
+ return MAC8390_FARALLON;
+ break;
+
+ case NUBUS_DRSW_KINETICS:
+ switch (dev->dr_hw) {
+ case NUBUS_DRHW_INTERLAN:
+ return MAC8390_INTERLAN;
+ break;
+ default:
+ return MAC8390_KINETICS;
+ break;
+ }
+ break;
+
+ case NUBUS_DRSW_DAYNA:
+ // These correspond to Dayna Sonic cards
+ // which use the macsonic driver
+ if (dev->dr_hw == NUBUS_DRHW_SMC9194 ||
+ dev->dr_hw == NUBUS_DRHW_INTERLAN )
+ return MAC8390_NONE;
+ else
+ return MAC8390_DAYNA;
+ break;
+ }
return MAC8390_NONE;
}
+enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
+{
+ unsigned long outdata = 0xA5A0B5B0;
+ unsigned long indata = 0x00000000;
+ /* Try writing 32 bits */
+ memcpy((char *)membase, (char *)&outdata, 4);
+ /* Now compare them */
+ if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
+ return ACCESS_32;
+ /* Write 16 bit output */
+ word_memcpy_tocard((char *)membase, (char *)&outdata, 4);
+ /* Now read it back */
+ word_memcpy_fromcard((char *)&indata, (char *)membase, 4);
+ if (outdata == indata)
+ return ACCESS_16;
+ return ACCESS_UNKNOWN;
+}
+
int __init mac8390_memsize(unsigned long membase)
{
unsigned long flags;
@@ -287,14 +350,6 @@ struct net_device * __init mac8390_probe(int unit)
continue;
} else {
nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
- /* Some Sonic Sys cards masquerade as Farallon */
- if (cardtype == MAC8390_FARALLON &&
- dev->dev_addr[0] == 0x0 &&
- dev->dev_addr[1] == 0x40 &&
- dev->dev_addr[2] == 0x10) {
- /* This is really Sonic Sys card */
- cardtype = MAC8390_SONICSYS;
- }
}
if (useresources[cardtype] == 1) {
@@ -334,6 +389,17 @@ struct net_device * __init mac8390_probe(int unit)
dev->mem_start +
mac8390_memsize(dev->mem_start);
break;
+ case MAC8390_INTERLAN:
+ dev->base_addr =
+ (int)(ndev->board->slot_addr +
+ INTERLAN_8390_BASE);
+ dev->mem_start =
+ (int)(ndev->board->slot_addr +
+ INTERLAN_8390_MEM);
+ dev->mem_end =
+ dev->mem_start +
+ mac8390_memsize(dev->mem_start);
+ break;
case MAC8390_CABLETRON:
dev->base_addr =
(int)(ndev->board->slot_addr +
@@ -356,8 +422,8 @@ struct net_device * __init mac8390_probe(int unit)
default:
printk(KERN_ERR "Card type %s is"
- " unsupported, sorry\n",
- cardname[cardtype]);
+ " unsupported, sorry\n",
+ ndev->board->name);
continue;
}
}
@@ -438,7 +504,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
24, 26, 28, 30
};
- int access_bitmode;
+ int access_bitmode = 0;
/* Now fill in our stuff */
dev->open = &mac8390_open;
@@ -468,29 +534,47 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
/* Fill in model-specific information and functions */
switch(type) {
- case MAC8390_SONICSYS:
- /* 16 bit card, register map is reversed */
- ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &slow_sane_block_input;
- ei_status.block_output = &slow_sane_block_output;
- ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
- ei_status.reg_offset = back4_offsets;
- access_bitmode = 0;
- break;
case MAC8390_FARALLON:
case MAC8390_APPLE:
+ switch(mac8390_testio(dev->mem_start)) {
+ case ACCESS_UNKNOWN:
+ printk("Don't know how to access card memory!\n");
+ return -ENODEV;
+ break;
+
+ case ACCESS_16:
+ /* 16 bit card, register map is reversed */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ break;
+
+ case ACCESS_32:
+ /* 32 bit card, register map is reversed */
+ ei_status.reset_8390 = &mac8390_no_reset;
+ ei_status.block_input = &sane_block_input;
+ ei_status.block_output = &sane_block_output;
+ ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.reg_offset = back4_offsets;
+ access_bitmode = 1;
+ break;
+ }
+ break;
+
case MAC8390_ASANTE:
- case MAC8390_DAYNA2:
- case MAC8390_DAYNA3:
- /* 32 bit card, register map is reversed */
- /* sane */
+ /* Some Asante cards pass the 32 bit test
+ * but overwrite system memory when run at 32 bit.
+ * so we run them all at 16 bit.
+ */
ei_status.reset_8390 = &mac8390_no_reset;
- ei_status.block_input = &sane_block_input;
- ei_status.block_output = &sane_block_output;
- ei_status.get_8390_hdr = &sane_get_8390_hdr;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
ei_status.reg_offset = back4_offsets;
- access_bitmode = 1;
break;
+
case MAC8390_CABLETRON:
/* 16 bit card, register map is short forward */
ei_status.reset_8390 = &mac8390_no_reset;
@@ -498,21 +582,30 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
ei_status.block_output = &slow_sane_block_output;
ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
ei_status.reg_offset = fwrd2_offsets;
- access_bitmode = 0;
break;
+
case MAC8390_DAYNA:
case MAC8390_KINETICS:
- /* 16 bit memory */
+ /* 16 bit memory, register map is forward */
/* dayna and similar */
ei_status.reset_8390 = &mac8390_no_reset;
ei_status.block_input = &dayna_block_input;
ei_status.block_output = &dayna_block_output;
ei_status.get_8390_hdr = &dayna_get_8390_hdr;
ei_status.reg_offset = fwrd4_offsets;
- access_bitmode = 0;
break;
+
+ case MAC8390_INTERLAN:
+ /* 16 bit memory, register map is forward */
+ ei_status.reset_8390 = &interlan_reset;
+ ei_status.block_input = &slow_sane_block_input;
+ ei_status.block_output = &slow_sane_block_output;
+ ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+ ei_status.reg_offset = fwrd4_offsets;
+ break;
+
default:
- printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
+ printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name);
return -ENODEV;
}
@@ -530,9 +623,9 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
printk(":");
}
}
- printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n",
- dev->irq, dev->mem_start, dev->mem_end-1,
- access_bitmode?32:16);
+ printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n",
+ dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4,
+ dev->mem_start, access_bitmode?32:16);
return 0;
}
@@ -561,6 +654,18 @@ static void mac8390_no_reset(struct net_device *dev)
return;
}
+static void interlan_reset(struct net_device *dev)
+{
+ unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq));
+ if (ei_debug > 1)
+ printk("Need to reset the NS8390 t=%lu...", jiffies);
+ ei_status.txing = 0;
+ target[0xC0000] = 0;
+ if (ei_debug > 1)
+ printk("reset complete\n");
+ return;
+}
+
/* dayna_memcpy_fromio/dayna_memcpy_toio */
/* directly from daynaport.c by Alan Cox */
static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count)
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 90e695d5326..26a3b45a4a3 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -128,7 +128,7 @@ struct net_local {
extern void reset_chip(struct net_device *dev);
#endif
static int net_open(struct net_device *dev);
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t net_interrupt(int irq, void *dev_id);
static void set_multicast_list(struct net_device *dev);
static void net_rx(struct net_device *dev);
@@ -374,56 +374,39 @@ net_open(struct net_device *dev)
static int
net_send_packet(struct sk_buff *skb, struct net_device *dev)
{
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
- /* Try to restart the adaptor. */
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-
- if (net_debug > 3)
- printk("%s: sent %d byte packet of type %x\n",
- dev->name, skb->len,
- (skb->data[ETH_ALEN+ETH_ALEN] << 8)
- | skb->data[ETH_ALEN+ETH_ALEN+1]);
-
- /* keep the upload from being interrupted, since we
- ask the chip to start transmitting before the
- whole packet has been completely uploaded. */
- local_irq_save(flags);
+ struct net_local *lp = netdev_priv(dev);
+ unsigned long flags;
- /* initiate a transmit sequence */
- writereg(dev, PP_TxCMD, lp->send_cmd);
- writereg(dev, PP_TxLength, skb->len);
+ if (net_debug > 3)
+ printk("%s: sent %d byte packet of type %x\n",
+ dev->name, skb->len,
+ (skb->data[ETH_ALEN+ETH_ALEN] << 8)
+ | skb->data[ETH_ALEN+ETH_ALEN+1]);
- /* Test to see if the chip has allocated memory for the packet */
- if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
- /* Gasp! It hasn't. But that shouldn't happen since
- we're waiting for TxOk, so return 1 and requeue this packet. */
- local_irq_restore(flags);
- return 1;
- }
+ /* keep the upload from being interrupted, since we
+ ask the chip to start transmitting before the
+ whole packet has been completely uploaded. */
+ local_irq_save(flags);
+ netif_stop_queue(dev);
- /* Write the contents of the packet */
- memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1);
+ /* initiate a transmit sequence */
+ writereg(dev, PP_TxCMD, lp->send_cmd);
+ writereg(dev, PP_TxLength, skb->len);
+ /* Test to see if the chip has allocated memory for the packet */
+ if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) {
+ /* Gasp! It hasn't. But that shouldn't happen since
+ we're waiting for TxOk, so return 1 and requeue this packet. */
local_irq_restore(flags);
- dev->trans_start = jiffies;
+ return 1;
}
+
+ /* Write the contents of the packet */
+ skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame),
+ skb->len+1);
+
+ local_irq_restore(flags);
+ dev->trans_start = jiffies;
dev_kfree_skb (skb);
return 0;
@@ -441,9 +424,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return IRQ_NONE;
}
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
@@ -464,8 +444,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
break;
case ISQ_TRANSMITTER_EVENT:
lp->stats.tx_packets++;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev);
if ((status & TX_OK) == 0) lp->stats.tx_errors++;
if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++;
if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++;
@@ -479,8 +458,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
That shouldn't happen since we only ever
load one packet. Shrug. Do the right
thing anyway. */
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev);
}
if (status & TX_UNDERRUN) {
if (net_debug > 0) printk("%s: transmit underrun\n", dev->name);
@@ -497,7 +475,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id)
break;
}
}
- dev->interrupt = 0;
return IRQ_HANDLED;
}
@@ -531,7 +508,8 @@ net_rx(struct net_device *dev)
}
skb_put(skb, length);
- memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length);
+ skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame),
+ length);
if (net_debug > 3)printk("%s: received %d byte packet of type %x\n",
dev->name, length,
@@ -610,8 +588,6 @@ static void set_multicast_list(struct net_device *dev)
static int set_mac_address(struct net_device *dev, void *addr)
{
int i;
- if (dev->start)
- return -EBUSY;
printk("%s: Setting MAC address to ", dev->name);
for (i = 0; i < 6; i++)
printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index b3bd6239495..52b9332810c 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -110,9 +110,9 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
return -ENODEV;
}
- addr = get_property(mace, "mac-address", NULL);
+ addr = of_get_property(mace, "mac-address", NULL);
if (addr == NULL) {
- addr = get_property(mace, "local-mac-address", NULL);
+ addr = of_get_property(mace, "local-mac-address", NULL);
if (addr == NULL) {
printk(KERN_ERR "Can't get mac-address for MACE %s\n",
mace->full_name);
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 27911c07558..fef3193121f 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -12,6 +12,11 @@
* Copyright (C) 1998 Alan Cox <alan@redhat.com>
*
* Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
+ *
+ * Copyright (C) 2007 Finn Thain
+ *
+ * Converted to DMA API, converted to unified driver model,
+ * sync'd some routines with mace.c and fixed various bugs.
*/
@@ -23,8 +28,9 @@
#include <linux/string.h>
#include <linux/crc32.h>
#include <linux/bitrev.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
-#include <asm/pgtable.h>
#include <asm/irq.h>
#include <asm/macintosh.h>
#include <asm/macints.h>
@@ -32,13 +38,20 @@
#include <asm/page.h>
#include "mace.h"
-#define N_TX_RING 1
-#define N_RX_RING 8
-#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE)
+static char mac_mace_string[] = "macmace";
+static struct platform_device *mac_mace_device;
+
+#define N_TX_BUFF_ORDER 0
+#define N_TX_RING (1 << N_TX_BUFF_ORDER)
+#define N_RX_BUFF_ORDER 3
+#define N_RX_RING (1 << N_RX_BUFF_ORDER)
+
#define TX_TIMEOUT HZ
-/* Bits in transmit DMA status */
-#define TX_DMA_ERR 0x80
+#define MACE_BUFF_SIZE 0x800
+
+/* Chip rev needs workaround on HW & multicast addr change */
+#define BROKEN_ADDRCHG_REV 0x0941
/* The MACE is simply wired down on a Mac68K box */
@@ -47,40 +60,46 @@
struct mace_data {
volatile struct mace *mace;
- volatile unsigned char *tx_ring;
- volatile unsigned char *tx_ring_phys;
- volatile unsigned char *rx_ring;
- volatile unsigned char *rx_ring_phys;
+ unsigned char *tx_ring;
+ dma_addr_t tx_ring_phys;
+ unsigned char *rx_ring;
+ dma_addr_t rx_ring_phys;
int dma_intr;
struct net_device_stats stats;
int rx_slot, rx_tail;
int tx_slot, tx_sloti, tx_count;
+ int chipid;
+ struct device *device;
};
struct mace_frame {
- u16 len;
- u16 status;
- u16 rntpc;
- u16 rcvcc;
- u32 pad1;
- u32 pad2;
+ u8 rcvcnt;
+ u8 pad1;
+ u8 rcvsts;
+ u8 pad2;
+ u8 rntpc;
+ u8 pad3;
+ u8 rcvcc;
+ u8 pad4;
+ u32 pad5;
+ u32 pad6;
u8 data[1];
/* And frame continues.. */
};
#define PRIV_BYTES sizeof(struct mace_data)
-extern void psc_debug_dump(void);
-
static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
+static void mace_reset(struct net_device *dev);
static irqreturn_t mace_interrupt(int irq, void *dev_id);
static irqreturn_t mace_dma_intr(int irq, void *dev_id);
static void mace_tx_timeout(struct net_device *dev);
+static void __mace_set_address(struct net_device *dev, void *addr);
/*
* Load a receive DMA channel with a base address and ring length
@@ -88,7 +107,7 @@ static void mace_tx_timeout(struct net_device *dev);
static void mace_load_rxdma_base(struct net_device *dev, int set)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
psc_write_word(PSC_ENETRD_CMD + set, 0x0100);
psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys);
@@ -103,7 +122,7 @@ static void mace_load_rxdma_base(struct net_device *dev, int set)
static void mace_rxdma_reset(struct net_device *dev)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mace = mp->mace;
u8 maccc = mace->maccc;
@@ -130,7 +149,7 @@ static void mace_rxdma_reset(struct net_device *dev)
static void mace_txdma_reset(struct net_device *dev)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mace = mp->mace;
u8 maccc;
@@ -168,7 +187,7 @@ static void mace_dma_off(struct net_device *dev)
* model of Macintrash has a MACE (AV macintoshes)
*/
-struct net_device *mace_probe(int unit)
+static int __devinit mace_probe(struct platform_device *pdev)
{
int j;
struct mace_data *mp;
@@ -179,24 +198,28 @@ struct net_device *mace_probe(int unit)
int err;
if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
found = 1; /* prevent 'finding' one on every device probe */
dev = alloc_etherdev(PRIV_BYTES);
if (!dev)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
- if (unit >= 0)
- sprintf(dev->name, "eth%d", unit);
+ mp = netdev_priv(dev);
+
+ mp->device = &pdev->dev;
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ SET_MODULE_OWNER(dev);
- mp = (struct mace_data *) dev->priv;
dev->base_addr = (u32)MACE_BASE;
mp->mace = (volatile struct mace *) MACE_BASE;
dev->irq = IRQ_MAC_MACE;
mp->dma_intr = IRQ_MAC_MACE_DMA;
+ mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo;
+
/*
* The PROM contains 8 bytes which total 0xFF when XOR'd
* together. Due to the usual peculiar apple brain damage
@@ -217,7 +240,7 @@ struct net_device *mace_probe(int unit)
if (checksum != 0xFF) {
free_netdev(dev);
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
}
memset(&mp->stats, 0, sizeof(mp->stats));
@@ -237,22 +260,98 @@ struct net_device *mace_probe(int unit)
err = register_netdev(dev);
if (!err)
- return dev;
+ return 0;
free_netdev(dev);
- return ERR_PTR(err);
+ return err;
+}
+
+/*
+ * Reset the chip.
+ */
+
+static void mace_reset(struct net_device *dev)
+{
+ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
+ int i;
+
+ /* soft-reset the chip */
+ i = 200;
+ while (--i) {
+ mb->biucc = SWRST;
+ if (mb->biucc & SWRST) {
+ udelay(10);
+ continue;
+ }
+ break;
+ }
+ if (!i) {
+ printk(KERN_ERR "macmace: cannot reset chip!\n");
+ return;
+ }
+
+ mb->maccc = 0; /* turn off tx, rx */
+ mb->imr = 0xFF; /* disable all intrs for now */
+ i = mb->ir;
+
+ mb->biucc = XMTSP_64;
+ mb->utr = RTRD;
+ mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU;
+
+ mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */
+ mb->rcvfc = 0;
+
+ /* load up the hardware address */
+ __mace_set_address(dev, dev->dev_addr);
+
+ /* clear the multicast filter */
+ if (mp->chipid == BROKEN_ADDRCHG_REV)
+ mb->iac = LOGADDR;
+ else {
+ mb->iac = ADDRCHG | LOGADDR;
+ while ((mb->iac & ADDRCHG) != 0)
+ ;
+ }
+ for (i = 0; i < 8; ++i)
+ mb->ladrf = 0;
+
+ /* done changing address */
+ if (mp->chipid != BROKEN_ADDRCHG_REV)
+ mb->iac = 0;
+
+ mb->plscc = PORTSEL_AUI;
}
/*
* Load the address on a mace controller.
*/
-static int mace_set_address(struct net_device *dev, void *addr)
+static void __mace_set_address(struct net_device *dev, void *addr)
{
- unsigned char *p = addr;
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
+ unsigned char *p = addr;
int i;
+
+ /* load up the hardware address */
+ if (mp->chipid == BROKEN_ADDRCHG_REV)
+ mb->iac = PHYADDR;
+ else {
+ mb->iac = ADDRCHG | PHYADDR;
+ while ((mb->iac & ADDRCHG) != 0)
+ ;
+ }
+ for (i = 0; i < 6; ++i)
+ mb->padr = dev->dev_addr[i] = p[i];
+ if (mp->chipid != BROKEN_ADDRCHG_REV)
+ mb->iac = 0;
+}
+
+static int mace_set_address(struct net_device *dev, void *addr)
+{
+ struct mace_data *mp = netdev_priv(dev);
+ volatile struct mace *mb = mp->mace;
unsigned long flags;
u8 maccc;
@@ -260,15 +359,10 @@ static int mace_set_address(struct net_device *dev, void *addr)
maccc = mb->maccc;
- /* load up the hardware address */
- mb->iac = ADDRCHG | PHYADDR;
- while ((mb->iac & ADDRCHG) != 0);
-
- for (i = 0; i < 6; ++i) {
- mb->padr = dev->dev_addr[i] = p[i];
- }
+ __mace_set_address(dev, addr);
mb->maccc = maccc;
+
local_irq_restore(flags);
return 0;
@@ -281,31 +375,11 @@ static int mace_set_address(struct net_device *dev, void *addr)
static int mace_open(struct net_device *dev)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
-#if 0
- int i;
- i = 200;
- while (--i) {
- mb->biucc = SWRST;
- if (mb->biucc & SWRST) {
- udelay(10);
- continue;
- }
- break;
- }
- if (!i) {
- printk(KERN_ERR "%s: software reset failed!!\n", dev->name);
- return -EAGAIN;
- }
-#endif
-
- mb->biucc = XMTSP_64;
- mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST;
- mb->xmtfc = AUTO_PAD_XMIT;
- mb->plscc = PORTSEL_AUI;
- /* mb->utr = RTRD; */
+ /* reset the chip */
+ mace_reset(dev);
if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) {
printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq);
@@ -319,25 +393,21 @@ static int mace_open(struct net_device *dev)
/* Allocate the DMA ring buffers */
- mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES);
- mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
-
- if (mp->tx_ring==NULL || mp->rx_ring==NULL) {
- if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES);
- if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0);
- free_irq(dev->irq, dev);
- free_irq(mp->dma_intr, dev);
- printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name);
- return -ENOMEM;
+ mp->tx_ring = dma_alloc_coherent(mp->device,
+ N_TX_RING * MACE_BUFF_SIZE,
+ &mp->tx_ring_phys, GFP_KERNEL);
+ if (mp->tx_ring == NULL) {
+ printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name);
+ goto out1;
}
- mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring);
- mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring);
-
- /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
-
- kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER);
- kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH);
+ mp->rx_ring = dma_alloc_coherent(mp->device,
+ N_RX_RING * MACE_BUFF_SIZE,
+ &mp->rx_ring_phys, GFP_KERNEL);
+ if (mp->rx_ring == NULL) {
+ printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name);
+ goto out2;
+ }
mace_dma_off(dev);
@@ -348,34 +418,22 @@ static int mace_open(struct net_device *dev)
psc_write_word(PSC_ENETWR_CTL, 0x0400);
psc_write_word(PSC_ENETRD_CTL, 0x0400);
-#if 0
- /* load up the hardware address */
-
- mb->iac = ADDRCHG | PHYADDR;
-
- while ((mb->iac & ADDRCHG) != 0);
-
- for (i = 0; i < 6; ++i)
- mb->padr = dev->dev_addr[i];
-
- /* clear the multicast filter */
- mb->iac = ADDRCHG | LOGADDR;
-
- while ((mb->iac & ADDRCHG) != 0);
-
- for (i = 0; i < 8; ++i)
- mb->ladrf = 0;
-
- mb->plscc = PORTSEL_GPSI + ENPLSIO;
-
- mb->maccc = ENXMT | ENRCV;
- mb->imr = RCVINT;
-#endif
-
mace_rxdma_reset(dev);
mace_txdma_reset(dev);
+ /* turn it on! */
+ mb->maccc = ENXMT | ENRCV;
+ /* enable all interrupts except receive interrupts */
+ mb->imr = RCVINT;
return 0;
+
+out2:
+ dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
+ mp->tx_ring, mp->tx_ring_phys);
+out1:
+ free_irq(dev->irq, dev);
+ free_irq(mp->dma_intr, dev);
+ return -ENOMEM;
}
/*
@@ -384,19 +442,13 @@ static int mace_open(struct net_device *dev)
static int mace_close(struct net_device *dev)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
mb->maccc = 0; /* disable rx and tx */
mb->imr = 0xFF; /* disable all irqs */
mace_dma_off(dev); /* disable rx and tx dma */
- free_irq(dev->irq, dev);
- free_irq(IRQ_MAC_MACE_DMA, dev);
-
- free_pages((u32) mp->rx_ring, N_RX_PAGES);
- free_pages((u32) mp->tx_ring, 0);
-
return 0;
}
@@ -406,15 +458,20 @@ static int mace_close(struct net_device *dev)
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
+ unsigned long flags;
- /* Stop the queue if the buffer is full */
+ /* Stop the queue since there's only the one buffer */
+ local_irq_save(flags);
+ netif_stop_queue(dev);
if (!mp->tx_count) {
- netif_stop_queue(dev);
- return 1;
+ printk(KERN_ERR "macmace: tx queue running but no free buffers.\n");
+ local_irq_restore(flags);
+ return NETDEV_TX_BUSY;
}
mp->tx_count--;
+ local_irq_restore(flags);
mp->stats.tx_packets++;
mp->stats.tx_bytes += skb->len;
@@ -432,23 +489,26 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
- return 0;
+ dev->trans_start = jiffies;
+ return NETDEV_TX_OK;
}
static struct net_device_stats *mace_stats(struct net_device *dev)
{
- struct mace_data *p = (struct mace_data *) dev->priv;
- return &p->stats;
+ struct mace_data *mp = netdev_priv(dev);
+ return &mp->stats;
}
static void mace_set_multicast(struct net_device *dev)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
int i, j;
u32 crc;
u8 maccc;
+ unsigned long flags;
+ local_irq_save(flags);
maccc = mb->maccc;
mb->maccc &= ~PROM;
@@ -473,116 +533,122 @@ static void mace_set_multicast(struct net_device *dev)
}
}
- mb->iac = ADDRCHG | LOGADDR;
- while (mb->iac & ADDRCHG);
-
- for (i = 0; i < 8; ++i) {
- mb->ladrf = multicast_filter[i];
+ if (mp->chipid == BROKEN_ADDRCHG_REV)
+ mb->iac = LOGADDR;
+ else {
+ mb->iac = ADDRCHG | LOGADDR;
+ while ((mb->iac & ADDRCHG) != 0)
+ ;
}
+ for (i = 0; i < 8; ++i)
+ mb->ladrf = multicast_filter[i];
+ if (mp->chipid != BROKEN_ADDRCHG_REV)
+ mb->iac = 0;
}
mb->maccc = maccc;
+ local_irq_restore(flags);
}
-/*
- * Miscellaneous interrupts are handled here. We may end up
- * having to bash the chip on the head for bad errors
- */
-
static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
{
volatile struct mace *mb = mp->mace;
static int mace_babbles, mace_jabbers;
- if (intr & MPCO) {
+ if (intr & MPCO)
mp->stats.rx_missed_errors += 256;
- }
- mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
-
- if (intr & RNTPCO) {
+ mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */
+ if (intr & RNTPCO)
mp->stats.rx_length_errors += 256;
- }
- mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
-
- if (intr & CERR) {
+ mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+ if (intr & CERR)
++mp->stats.tx_heartbeat_errors;
- }
- if (intr & BABBLE) {
- if (mace_babbles++ < 4) {
- printk(KERN_DEBUG "mace: babbling transmitter\n");
- }
- }
- if (intr & JABBER) {
- if (mace_jabbers++ < 4) {
- printk(KERN_DEBUG "mace: jabbering transceiver\n");
- }
- }
+ if (intr & BABBLE)
+ if (mace_babbles++ < 4)
+ printk(KERN_DEBUG "macmace: babbling transmitter\n");
+ if (intr & JABBER)
+ if (mace_jabbers++ < 4)
+ printk(KERN_DEBUG "macmace: jabbering transceiver\n");
}
-/*
- * A transmit error has occurred. (We kick the transmit side from
- * the DMA completion)
- */
-
-static void mace_xmit_error(struct net_device *dev)
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
- u8 xmtfs, xmtrc;
+ int intr, fs;
+ unsigned int flags;
- xmtfs = mb->xmtfs;
- xmtrc = mb->xmtrc;
+ /* don't want the dma interrupt handler to fire */
+ local_irq_save(flags);
- if (xmtfs & XMTSV) {
- if (xmtfs & UFLO) {
- printk("%s: DMA underrun.\n", dev->name);
- mp->stats.tx_errors++;
- mp->stats.tx_fifo_errors++;
- mace_txdma_reset(dev);
+ intr = mb->ir; /* read interrupt register */
+ mace_handle_misc_intrs(mp, intr);
+
+ if (intr & XMTINT) {
+ fs = mb->xmtfs;
+ if ((fs & XMTSV) == 0) {
+ printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs);
+ mace_reset(dev);
+ /*
+ * XXX mace likes to hang the machine after a xmtfs error.
+ * This is hard to reproduce, reseting *may* help
+ */
}
- if (xmtfs & RTRY) {
- mp->stats.collisions++;
+ /* dma should have finished */
+ if (!mp->tx_count) {
+ printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs);
+ }
+ /* Update stats */
+ if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+ ++mp->stats.tx_errors;
+ if (fs & LCAR)
+ ++mp->stats.tx_carrier_errors;
+ else if (fs & (UFLO|LCOL|RTRY)) {
+ ++mp->stats.tx_aborted_errors;
+ if (mb->xmtfs & UFLO) {
+ printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
+ mp->stats.tx_fifo_errors++;
+ mace_txdma_reset(dev);
+ }
+ }
}
}
-}
-/*
- * A receive interrupt occurred.
- */
+ if (mp->tx_count)
+ netif_wake_queue(dev);
-static void mace_recv_interrupt(struct net_device *dev)
-{
-/* struct mace_data *mp = (struct mace_data *) dev->priv; */
-// volatile struct mace *mb = mp->mace;
-}
+ local_irq_restore(flags);
-/*
- * Process the chip interrupt
- */
+ return IRQ_HANDLED;
+}
-static irqreturn_t mace_interrupt(int irq, void *dev_id)
+static void mace_tx_timeout(struct net_device *dev)
{
- struct net_device *dev = (struct net_device *) dev_id;
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
volatile struct mace *mb = mp->mace;
- u8 ir;
+ unsigned long flags;
- ir = mb->ir;
- mace_handle_misc_intrs(mp, ir);
+ local_irq_save(flags);
- if (ir & XMTINT) {
- mace_xmit_error(dev);
- }
- if (ir & RCVINT) {
- mace_recv_interrupt(dev);
- }
- return IRQ_HANDLED;
-}
+ /* turn off both tx and rx and reset the chip */
+ mb->maccc = 0;
+ printk(KERN_ERR "macmace: transmit timeout - resetting\n");
+ mace_txdma_reset(dev);
+ mace_reset(dev);
-static void mace_tx_timeout(struct net_device *dev)
-{
-/* struct mace_data *mp = (struct mace_data *) dev->priv; */
-// volatile struct mace *mb = mp->mace;
+ /* restart rx dma */
+ mace_rxdma_reset(dev);
+
+ mp->tx_count = N_TX_RING;
+ netif_wake_queue(dev);
+
+ /* turn it on! */
+ mb->maccc = ENXMT | ENRCV;
+ /* enable all interrupts except receive interrupts */
+ mb->imr = RCVINT;
+
+ local_irq_restore(flags);
}
/*
@@ -591,40 +657,39 @@ static void mace_tx_timeout(struct net_device *dev)
static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
{
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
struct sk_buff *skb;
+ unsigned int frame_status = mf->rcvsts;
- if (mf->status & RS_OFLO) {
- printk("%s: fifo overflow.\n", dev->name);
- mp->stats.rx_errors++;
- mp->stats.rx_fifo_errors++;
- }
- if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
+ if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
mp->stats.rx_errors++;
+ if (frame_status & RS_OFLO) {
+ printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
+ mp->stats.rx_fifo_errors++;
+ }
+ if (frame_status & RS_CLSN)
+ mp->stats.collisions++;
+ if (frame_status & RS_FRAMERR)
+ mp->stats.rx_frame_errors++;
+ if (frame_status & RS_FCSERR)
+ mp->stats.rx_crc_errors++;
+ } else {
+ unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
- if (mf->status&RS_CLSN) {
- mp->stats.collisions++;
- }
- if (mf->status&RS_FRAMERR) {
- mp->stats.rx_frame_errors++;
- }
- if (mf->status&RS_FCSERR) {
- mp->stats.rx_crc_errors++;
- }
-
- skb = dev_alloc_skb(mf->len+2);
- if (!skb) {
- mp->stats.rx_dropped++;
- return;
+ skb = dev_alloc_skb(frame_length + 2);
+ if (!skb) {
+ mp->stats.rx_dropped++;
+ return;
+ }
+ skb_reserve(skb, 2);
+ memcpy(skb_put(skb, frame_length), mf->data, frame_length);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->last_rx = jiffies;
+ mp->stats.rx_packets++;
+ mp->stats.rx_bytes += frame_length;
}
- skb_reserve(skb,2);
- memcpy(skb_put(skb, mf->len), mf->data, mf->len);
-
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- mp->stats.rx_packets++;
- mp->stats.rx_bytes += mf->len;
}
/*
@@ -634,7 +699,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
static irqreturn_t mace_dma_intr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
- struct mace_data *mp = (struct mace_data *) dev->priv;
+ struct mace_data *mp = netdev_priv(dev);
int left, head;
u16 status;
u32 baka;
@@ -661,7 +726,8 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id)
/* Loop through the ring buffer and process new packages */
while (mp->rx_tail < head) {
- mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800)));
+ mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring
+ + (mp->rx_tail * MACE_BUFF_SIZE)));
mp->rx_tail++;
}
@@ -688,9 +754,76 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id)
psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100);
mp->tx_sloti ^= 0x10;
mp->tx_count++;
- netif_wake_queue(dev);
}
return IRQ_HANDLED;
}
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Macintosh MACE ethernet driver");
+
+static int __devexit mac_mace_device_remove (struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct mace_data *mp = netdev_priv(dev);
+
+ unregister_netdev(dev);
+
+ free_irq(dev->irq, dev);
+ free_irq(IRQ_MAC_MACE_DMA, dev);
+
+ dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE,
+ mp->rx_ring, mp->rx_ring_phys);
+ dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE,
+ mp->tx_ring, mp->tx_ring_phys);
+
+ free_netdev(dev);
+
+ return 0;
+}
+
+static struct platform_driver mac_mace_driver = {
+ .probe = mace_probe,
+ .remove = __devexit_p(mac_mace_device_remove),
+ .driver = {
+ .name = mac_mace_string,
+ },
+};
+
+static int __init mac_mace_init_module(void)
+{
+ int err;
+
+ if ((err = platform_driver_register(&mac_mace_driver))) {
+ printk(KERN_ERR "Driver registration failed\n");
+ return err;
+ }
+
+ mac_mace_device = platform_device_alloc(mac_mace_string, 0);
+ if (!mac_mace_device)
+ goto out_unregister;
+
+ if (platform_device_add(mac_mace_device)) {
+ platform_device_put(mac_mace_device);
+ mac_mace_device = NULL;
+ }
+
+ return 0;
+
+out_unregister:
+ platform_driver_unregister(&mac_mace_driver);
+
+ return -ENOMEM;
+}
+
+static void __exit mac_mace_cleanup_module(void)
+{
+ platform_driver_unregister(&mac_mace_driver);
+
+ if (mac_mace_device) {
+ platform_device_unregister(mac_mace_device);
+ mac_mace_device = NULL;
+ }
+}
+
+module_init(mac_mace_init_module);
+module_exit(mac_mace_cleanup_module);
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index 8ca57a0a4c1..e9ecdbf352a 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -130,6 +130,46 @@ static inline void bit_reverse_addr(unsigned char addr[6])
addr[i] = bitrev8(addr[i]);
}
+static irqreturn_t macsonic_interrupt(int irq, void *dev_id)
+{
+ irqreturn_t result;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ result = sonic_interrupt(irq, dev_id);
+ local_irq_restore(flags);
+ return result;
+}
+
+static int macsonic_open(struct net_device* dev)
+{
+ if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
+ }
+ /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes
+ * in at priority level 3. However, we sometimes get the level 2 inter-
+ * rupt as well, which must prevent re-entrance of the sonic handler.
+ */
+ if (dev->irq == IRQ_AUTO_3)
+ if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) {
+ printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9);
+ free_irq(dev->irq, dev);
+ return -EAGAIN;
+ }
+ return sonic_open(dev);
+}
+
+static int macsonic_close(struct net_device* dev)
+{
+ int err;
+ err = sonic_close(dev);
+ free_irq(dev->irq, dev);
+ if (dev->irq == IRQ_AUTO_3)
+ free_irq(IRQ_NUBUS_9, dev);
+ return err;
+}
+
int __init macsonic_init(struct net_device* dev)
{
struct sonic_local* lp = netdev_priv(dev);
@@ -160,8 +200,8 @@ int __init macsonic_init(struct net_device* dev)
lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS
* SONIC_BUS_SCALE(lp->dma_bitmode));
- dev->open = sonic_open;
- dev->stop = sonic_close;
+ dev->open = macsonic_open;
+ dev->stop = macsonic_close;
dev->hard_start_xmit = sonic_send_packet;
dev->get_stats = sonic_get_stats;
dev->set_multicast_list = &sonic_multicast_list;
@@ -402,7 +442,7 @@ int __init macsonic_ident(struct nubus_dev* ndev)
ndev->dr_sw == NUBUS_DRSW_DAYNA)
return MACSONIC_DAYNA;
- if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
+ if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC &&
ndev->dr_sw == 0) { /* huh? */
return MACSONIC_APPLE16;
}
@@ -522,7 +562,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
return macsonic_init(dev);
}
-static int __init mac_sonic_probe(struct platform_device *device)
+static int __init mac_sonic_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct sonic_local *lp;
@@ -534,8 +574,8 @@ static int __init mac_sonic_probe(struct platform_device *device)
return -ENOMEM;
lp = netdev_priv(dev);
- lp->device = &device->dev;
- SET_NETDEV_DEV(dev, &device->dev);
+ lp->device = &pdev->dev;
+ SET_NETDEV_DEV(dev, &pdev->dev);
SET_MODULE_OWNER(dev);
/* This will catch fatal stuff like -ENOMEM as well as success */
@@ -572,19 +612,17 @@ MODULE_DESCRIPTION("Macintosh SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)");
-#define SONIC_IRQ_FLAG IRQ_FLG_FAST
-
#include "sonic.c"
-static int __devexit mac_sonic_device_remove (struct platform_device *device)
+static int __devexit mac_sonic_device_remove (struct platform_device *pdev)
{
- struct net_device *dev = platform_get_drvdata(device);
+ struct net_device *dev = platform_get_drvdata(pdev);
struct sonic_local* lp = netdev_priv(dev);
- unregister_netdev (dev);
+ unregister_netdev(dev);
dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode),
lp->descriptors, lp->descriptors_laddr);
- free_netdev (dev);
+ free_netdev(dev);
return 0;
}
@@ -607,9 +645,8 @@ static int __init mac_sonic_init_module(void)
}
mac_sonic_device = platform_device_alloc(mac_sonic_string, 0);
- if (!mac_sonic_device) {
+ if (!mac_sonic_device)
goto out_unregister;
- }
if (platform_device_add(mac_sonic_device)) {
platform_device_put(mac_sonic_device);
diff --git a/drivers/net/meth.h b/drivers/net/meth.h
index 84960dae2a2..ea3b8fc86d1 100644
--- a/drivers/net/meth.h
+++ b/drivers/net/meth.h
@@ -126,7 +126,7 @@ typedef struct rx_packet {
/* Note: when loopback is set this bit becomes collision control. Setting this bit will */
/* cause a collision to be reported. */
- /* Bits 5 and 6 are used to determine the the Destination address filter mode */
+ /* Bits 5 and 6 are used to determine the Destination address filter mode */
#define METH_ACCEPT_MY 0 /* 00: Accept PHY address only */
#define METH_ACCEPT_MCAST 0x20 /* 01: Accept physical, broadcast, and multicast filter matches only */
#define METH_ACCEPT_AMCAST 0x40 /* 10: Accept physical, broadcast, and all multicast packets */
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 2912a34f597..92056051f26 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -33,6 +33,13 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
+/**
+ * mii_ethtool_gset - get settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct net_device *dev = mii->dev;
@@ -114,6 +121,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return 0;
}
+/**
+ * mii_ethtool_sset - set settings that are specified in @ecmd
+ * @mii: MII interface
+ * @ecmd: requested ethtool_cmd
+ *
+ * Returns 0 for success, negative on error.
+ */
int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct net_device *dev = mii->dev;
@@ -207,6 +221,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return 0;
}
+/**
+ * mii_check_gmii_support - check if the MII supports Gb interfaces
+ * @mii: the MII interface
+ */
int mii_check_gmii_support(struct mii_if_info *mii)
{
int reg;
@@ -221,6 +239,12 @@ int mii_check_gmii_support(struct mii_if_info *mii)
return 0;
}
+/**
+ * mii_link_ok - is link status up/ok
+ * @mii: the MII interface
+ *
+ * Returns 1 if the MII reports link status up/ok, 0 otherwise.
+ */
int mii_link_ok (struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
@@ -230,6 +254,12 @@ int mii_link_ok (struct mii_if_info *mii)
return 0;
}
+/**
+ * mii_nway_restart - restart NWay (autonegotiation) for this interface
+ * @mii: the MII interface
+ *
+ * Returns 0 on success, negative on error.
+ */
int mii_nway_restart (struct mii_if_info *mii)
{
int bmcr;
@@ -247,6 +277,14 @@ int mii_nway_restart (struct mii_if_info *mii)
return r;
}
+/**
+ * mii_check_link - check MII link status
+ * @mii: MII interface
+ *
+ * If the link status changed (previous != current), call
+ * netif_carrier_on() if current link status is Up or call
+ * netif_carrier_off() if current link status is Down.
+ */
void mii_check_link (struct mii_if_info *mii)
{
int cur_link = mii_link_ok(mii);
@@ -258,6 +296,15 @@ void mii_check_link (struct mii_if_info *mii)
netif_carrier_off(mii->dev);
}
+/**
+ * mii_check_media - check the MII interface for a duplex change
+ * @mii: the MII interface
+ * @ok_to_print: OK to print link up/down messages
+ * @init_media: OK to save duplex mode in @mii
+ *
+ * Returns 1 if the duplex mode changed, 0 if not.
+ * If the media type is forced, always returns 0.
+ */
unsigned int mii_check_media (struct mii_if_info *mii,
unsigned int ok_to_print,
unsigned int init_media)
@@ -326,6 +373,16 @@ unsigned int mii_check_media (struct mii_if_info *mii,
return 0; /* duplex did not change */
}
+/**
+ * generic_mii_ioctl - main MII ioctl interface
+ * @mii_if: the MII interface
+ * @mii_data: MII ioctl data structure
+ * @cmd: MII ioctl command
+ * @duplex_chg_out: pointer to @duplex_changed status if there was no
+ * ioctl error
+ *
+ * Returns 0 on success, negative on error.
+ */
int generic_mii_ioctl(struct mii_if_info *mii_if,
struct mii_ioctl_data *mii_data, int cmd,
unsigned int *duplex_chg_out)
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 403f63afd20..638a279ec50 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -26,8 +26,6 @@ struct mipsnet_priv {
struct net_device_stats stats;
};
-static struct platform_device *mips_plat_dev;
-
static char mipsnet_string[] = "mipsnet";
/*
@@ -297,64 +295,17 @@ static struct device_driver mipsnet_driver = {
.remove = __devexit_p(mipsnet_device_remove),
};
-static void mipsnet_platform_release(struct device *device)
-{
- struct platform_device *pldev;
-
- /* free device */
- pldev = to_platform_device(device);
- kfree(pldev);
-}
-
static int __init mipsnet_init_module(void)
{
- struct platform_device *pldev;
int err;
printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. "
"(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION);
- if (driver_register(&mipsnet_driver)) {
+ err = driver_register(&mipsnet_driver);
+ if (err)
printk(KERN_ERR "Driver registration failed\n");
- err = -ENODEV;
- goto out;
- }
-
- if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) {
- err = -ENOMEM;
- goto out_unregister_driver;
- }
-
- memset (pldev, 0, sizeof (*pldev));
- pldev->name = mipsnet_string;
- pldev->id = 0;
- pldev->dev.release = mipsnet_platform_release;
- if (platform_device_register(pldev)) {
- err = -ENODEV;
- goto out_free_pldev;
- }
-
- if (!pldev->dev.driver) {
- /*
- * The driver was not bound to this device, there was
- * no hardware at this address. Unregister it, as the
- * release fuction will take care of freeing the
- * allocated structure
- */
- platform_device_unregister (pldev);
- }
-
- mips_plat_dev = pldev;
-
- return 0;
-
-out_free_pldev:
- kfree(pldev);
-
-out_unregister_driver:
- driver_unregister(&mipsnet_driver);
-out:
return err;
}
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index ab15ecd4b3d..1799eee88db 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -51,8 +51,8 @@
#include "mv643xx_eth.h"
/* Static function declarations */
-static void eth_port_uc_addr_get(struct net_device *dev,
- unsigned char *MacAddr);
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr);
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr);
static void eth_port_set_multicast_list(struct net_device *);
static void mv643xx_eth_port_enable_tx(unsigned int port_num,
unsigned int queues);
@@ -1381,7 +1381,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
port_num = mp->port_num = pd->port_number;
/* set default config values */
- eth_port_uc_addr_get(dev, dev->dev_addr);
+ eth_port_uc_addr_get(port_num, dev->dev_addr);
mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE;
mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE;
@@ -1839,26 +1839,9 @@ static void eth_port_start(struct net_device *dev)
}
/*
- * eth_port_uc_addr_set - This function Set the port Unicast address.
- *
- * DESCRIPTION:
- * This function Set the port Ethernet MAC address.
- *
- * INPUT:
- * unsigned int eth_port_num Port number.
- * char * p_addr Address to be set
- *
- * OUTPUT:
- * Set MAC address low and high registers. also calls
- * eth_port_set_filter_table_entry() to set the unicast
- * table with the proper information.
- *
- * RETURN:
- * N/A.
- *
+ * eth_port_uc_addr_set - Write a MAC address into the port's hw registers
*/
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
- unsigned char *p_addr)
+static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr)
{
unsigned int mac_h;
unsigned int mac_l;
@@ -1868,40 +1851,24 @@ static void eth_port_uc_addr_set(unsigned int eth_port_num,
mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) |
(p_addr[3] << 0);
- mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l);
- mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h);
+ mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l);
+ mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h);
- /* Accept frames of this address */
- table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num);
+ /* Accept frames with this address */
+ table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num);
eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f);
}
/*
- * eth_port_uc_addr_get - This function retrieves the port Unicast address
- * (MAC address) from the ethernet hw registers.
- *
- * DESCRIPTION:
- * This function retrieves the port Ethernet MAC address.
- *
- * INPUT:
- * unsigned int eth_port_num Port number.
- * char *MacAddr pointer where the MAC address is stored
- *
- * OUTPUT:
- * Copy the MAC address to the location pointed to by MacAddr
- *
- * RETURN:
- * N/A.
- *
+ * eth_port_uc_addr_get - Read the MAC address from the port's hw registers
*/
-static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr)
+static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr)
{
- struct mv643xx_private *mp = netdev_priv(dev);
unsigned int mac_h;
unsigned int mac_l;
- mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num));
- mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num));
+ mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num));
+ mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num));
p_addr[0] = (mac_h >> 24) & 0xff;
p_addr[1] = (mac_h >> 16) & 0xff;
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 7d4e90cf49e..82f8c0cbfb6 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -346,10 +346,6 @@ static void eth_port_init(struct mv643xx_private *mp);
static void eth_port_reset(unsigned int eth_port_num);
static void eth_port_start(struct net_device *dev);
-/* Port MAC address routines */
-static void eth_port_uc_addr_set(unsigned int eth_port_num,
- unsigned char *p_addr);
-
/* PHY and MIB routines */
static void ethernet_phy_reset(unsigned int eth_port_num);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 16e3c4315e8..5d14be7405a 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -290,6 +290,8 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");
#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)
+static void myri10ge_set_multicast_list(struct net_device *dev);
+
static inline void put_be32(__be32 val, __be32 __iomem * p)
{
__raw_writel((__force __u32) val, (__force void __iomem *)p);
@@ -353,6 +355,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
return 0;
} else if (result == MXGEFW_CMD_UNKNOWN) {
return -ENOSYS;
+ } else if (result == MXGEFW_CMD_ERROR_UNALIGNED) {
+ return -E2BIG;
} else {
dev_err(&mgp->pdev->dev,
"command %d failed, result = %d\n",
@@ -712,14 +716,78 @@ myri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic)
mgp->dev->name);
}
-static int myri10ge_reset(struct myri10ge_priv *mgp)
+static int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type)
{
struct myri10ge_cmd cmd;
int status;
- size_t bytes;
u32 len;
struct page *dmatest_page;
dma_addr_t dmatest_bus;
+ char *test = " ";
+
+ dmatest_page = alloc_page(GFP_KERNEL);
+ if (!dmatest_page)
+ return -ENOMEM;
+ dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+
+ /* Run a small DMA test.
+ * The magic multipliers to the length tell the firmware
+ * to do DMA read, write, or read+write tests. The
+ * results are returned in cmd.data0. The upper 16
+ * bits or the return is the number of transfers completed.
+ * The lower 16 bits is the time in 0.5us ticks that the
+ * transfers took to complete.
+ */
+
+ len = mgp->tx.boundary;
+
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
+ cmd.data2 = len * 0x10000;
+ status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);
+ if (status != 0) {
+ test = "read";
+ goto abort;
+ }
+ mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
+ cmd.data2 = len * 0x1;
+ status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);
+ if (status != 0) {
+ test = "write";
+ goto abort;
+ }
+ mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff);
+
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
+ cmd.data2 = len * 0x10001;
+ status = myri10ge_send_cmd(mgp, test_type, &cmd, 0);
+ if (status != 0) {
+ test = "read/write";
+ goto abort;
+ }
+ mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) /
+ (cmd.data0 & 0xffff);
+
+abort:
+ pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ put_page(dmatest_page);
+
+ if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST)
+ dev_warn(&mgp->pdev->dev, "DMA %s benchmark failed: %d\n",
+ test, status);
+
+ return status;
+}
+
+static int myri10ge_reset(struct myri10ge_priv *mgp)
+{
+ struct myri10ge_cmd cmd;
+ int status;
+ size_t bytes;
/* try to send a reset command to the card to see if it
* is alive */
@@ -729,11 +797,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
dev_err(&mgp->pdev->dev, "failed reset\n");
return -ENXIO;
}
- dmatest_page = alloc_page(GFP_KERNEL);
- if (!dmatest_page)
- return -ENOMEM;
- dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
+
+ (void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST);
/* Now exchange information about interrupts */
@@ -761,52 +826,6 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
}
put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr);
- /* Run a small DMA test.
- * The magic multipliers to the length tell the firmware
- * to do DMA read, write, or read+write tests. The
- * results are returned in cmd.data0. The upper 16
- * bits or the return is the number of transfers completed.
- * The lower 16 bits is the time in 0.5us ticks that the
- * transfers took to complete.
- */
-
- len = mgp->tx.boundary;
-
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
- cmd.data2 = len * 0x10000;
- status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
- if (status == 0)
- mgp->read_dma = ((cmd.data0 >> 16) * len * 2) /
- (cmd.data0 & 0xffff);
- else
- dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n",
- status);
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
- cmd.data2 = len * 0x1;
- status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
- if (status == 0)
- mgp->write_dma = ((cmd.data0 >> 16) * len * 2) /
- (cmd.data0 & 0xffff);
- else
- dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n",
- status);
-
- cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
- cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
- cmd.data2 = len * 0x10001;
- status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
- if (status == 0)
- mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) /
- (cmd.data0 & 0xffff);
- else
- dev_warn(&mgp->pdev->dev,
- "DMA read/write benchmark failed: %d\n", status);
-
- pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
- put_page(dmatest_page);
-
memset(mgp->rx_done.entry, 0, bytes);
/* reset mcp/driver shared state back to 0 */
@@ -820,10 +839,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
mgp->rx_done.cnt = 0;
mgp->link_changes = 0;
status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
- myri10ge_change_promisc(mgp, 0, 0);
myri10ge_change_pause(mgp, mgp->pause);
- if (mgp->adopted_rx_filter_bug)
- (void)myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
+ myri10ge_set_multicast_list(mgp->dev);
return status;
}
@@ -1355,7 +1372,9 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
"wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
"link_changes", "link_up", "dropped_link_overflow",
- "dropped_link_error_or_filtered", "dropped_multicast_filtered",
+ "dropped_link_error_or_filtered",
+ "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
+ "dropped_unicast_filtered", "dropped_multicast_filtered",
"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
"dropped_no_big_buffer"
};
@@ -1412,6 +1431,11 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
data[i++] =
(unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_pause);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_phy);
+ data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_bad_crc32);
+ data[i++] =
+ (unsigned int)ntohl(mgp->fw_stats->dropped_unicast_filtered);
data[i++] =
(unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
@@ -2276,7 +2300,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
/* This firmware is known to not support multicast */
- if (!mgp->fw_multicast_support || mgp->adopted_rx_filter_bug)
+ if (!mgp->fw_multicast_support)
return;
/* Disable multicast filtering */
@@ -2288,7 +2312,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
goto abort;
}
- if (dev->flags & IFF_ALLMULTI) {
+ if ((dev->flags & IFF_ALLMULTI) || mgp->adopted_rx_filter_bug) {
/* request to disable multicast filtering, so quit here */
return;
}
@@ -2461,8 +2485,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
err_cap |= PCI_ERR_CAP_ECRC_GENE;
pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap);
dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge));
- mgp->tx.boundary = 4096;
- mgp->fw_name = myri10ge_fw_aligned;
}
/*
@@ -2484,22 +2506,70 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
* firmware image, and set tx.boundary to 4KB.
*/
-#define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7
-#define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa
-#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1 0x3510
-#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4 0x351b
-#define PCI_DEVICE_ID_INTEL_E3000_PCIE 0x2779
-#define PCI_DEVICE_ID_INTEL_E3010_PCIE 0x277a
-#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST 0x140
-#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST 0x142
-
-static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
{
- struct pci_dev *bridge = mgp->pdev->bus->self;
+ struct pci_dev *pdev = mgp->pdev;
+ struct device *dev = &pdev->dev;
+ int cap, status;
+ u16 val;
+
+ mgp->tx.boundary = 4096;
+ /*
+ * Verify the max read request size was set to 4KB
+ * before trying the test with 4KB.
+ */
+ cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (cap < 64) {
+ dev_err(dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
+ goto abort;
+ }
+ status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
+ if (status != 0) {
+ dev_err(dev, "Couldn't read max read req size: %d\n", status);
+ goto abort;
+ }
+ if ((val & (5 << 12)) != (5 << 12)) {
+ dev_warn(dev, "Max Read Request size != 4096 (0x%x)\n", val);
+ mgp->tx.boundary = 2048;
+ }
+ /*
+ * load the optimized firmware (which assumes aligned PCIe
+ * completions) in order to see if it works on this host.
+ */
+ mgp->fw_name = myri10ge_fw_aligned;
+ status = myri10ge_load_firmware(mgp);
+ if (status != 0) {
+ goto abort;
+ }
+
+ /*
+ * Enable ECRC if possible
+ */
+ myri10ge_enable_ecrc(mgp);
+
+ /*
+ * Run a DMA test which watches for unaligned completions and
+ * aborts on the first one seen.
+ */
+ status = myri10ge_dma_test(mgp, MXGEFW_CMD_UNALIGNED_TEST);
+ if (status == 0)
+ return; /* keep the aligned firmware */
+
+ if (status != -E2BIG)
+ dev_warn(dev, "DMA test failed: %d\n", status);
+ if (status == -ENOSYS)
+ dev_warn(dev, "Falling back to ethp! "
+ "Please install up to date fw\n");
+abort:
+ /* fall back to using the unaligned firmware */
mgp->tx.boundary = 2048;
mgp->fw_name = myri10ge_fw_unaligned;
+}
+
+static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+{
if (myri10ge_force_firmware == 0) {
int link_width, exp_cap;
u16 lnk;
@@ -2508,8 +2578,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
pci_read_config_word(mgp->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
link_width = (lnk >> 4) & 0x3f;
- myri10ge_enable_ecrc(mgp);
-
/* Check to see if Link is less than 8 or if the
* upstream bridge is known to provide aligned
* completions */
@@ -2518,46 +2586,8 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
link_width);
mgp->tx.boundary = 4096;
mgp->fw_name = myri10ge_fw_aligned;
- } else if (bridge &&
- /* ServerWorks HT2000/HT1000 */
- ((bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
- && bridge->device ==
- PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE)
- /* ServerWorks HT2100 */
- || (bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
- && bridge->device >=
- PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST
- && bridge->device <=
- PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST)
- /* All Intel E3000/E3010 PCIE ports */
- || (bridge->vendor == PCI_VENDOR_ID_INTEL
- && (bridge->device ==
- PCI_DEVICE_ID_INTEL_E3000_PCIE
- || bridge->device ==
- PCI_DEVICE_ID_INTEL_E3010_PCIE))
- /* All Intel 6310/6311/6321ESB PCIE ports */
- || (bridge->vendor == PCI_VENDOR_ID_INTEL
- && bridge->device >=
- PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1
- && bridge->device <=
- PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4)
- /* All Intel E5000 PCIE ports */
- || (bridge->vendor == PCI_VENDOR_ID_INTEL
- && bridge->device >=
- PCI_DEVICE_ID_INTEL_E5000_PCIE23
- && bridge->device <=
- PCI_DEVICE_ID_INTEL_E5000_PCIE47))) {
- dev_info(&mgp->pdev->dev,
- "Assuming aligned completions (0x%x:0x%x)\n",
- bridge->vendor, bridge->device);
- mgp->tx.boundary = 4096;
- mgp->fw_name = myri10ge_fw_aligned;
- } else if (bridge &&
- bridge->vendor == PCI_VENDOR_ID_SGI &&
- bridge->device == 0x4002 /* TIOCE pcie-port */ ) {
- /* this pcie bridge does not support 4K rdma request */
- mgp->tx.boundary = 2048;
- mgp->fw_name = myri10ge_fw_aligned;
+ } else {
+ myri10ge_firmware_probe(mgp);
}
} else {
if (myri10ge_force_firmware == 1) {
@@ -2825,7 +2855,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
status = -ENODEV;
goto abort_with_netdev;
}
- myri10ge_select_firmware(mgp);
/* Find the vendor-specific cap so we can check
* the reboot register later on */
@@ -2919,6 +2948,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto abort_with_ioremap;
memset(mgp->rx_done.entry, 0, bytes);
+ myri10ge_select_firmware(mgp);
+
status = myri10ge_load_firmware(mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed to load firmware\n");
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 29463b301a8..a1d2a22296a 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -200,6 +200,13 @@ enum myri10ge_mcp_cmd_type {
/* data0, data1 = bus addr,
* data2 = sizeof(struct mcp_irq_data) from driver point of view, allows
* adding new stuff to mcp_irq_data without changing the ABI */
+
+ MXGEFW_CMD_UNALIGNED_TEST,
+ /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned
+ * chipset */
+
+ MXGEFW_CMD_UNALIGNED_STATUS
+ /* return data = boolean, true if the chipset is known to be unaligned */
};
enum myri10ge_mcp_cmd_status {
@@ -212,18 +219,27 @@ enum myri10ge_mcp_cmd_status {
MXGEFW_CMD_ERROR_HASH_ERROR,
MXGEFW_CMD_ERROR_BAD_PORT,
MXGEFW_CMD_ERROR_RESOURCES,
- MXGEFW_CMD_ERROR_MULTICAST
+ MXGEFW_CMD_ERROR_MULTICAST,
+ MXGEFW_CMD_ERROR_UNALIGNED
};
#define MXGEFW_OLD_IRQ_DATA_LEN 40
struct mcp_irq_data {
/* add new counters at the beginning */
- __be32 future_use[5];
+ __be32 future_use[1];
+ __be32 dropped_pause;
+ __be32 dropped_unicast_filtered;
+ __be32 dropped_bad_crc32;
+ __be32 dropped_bad_phy;
__be32 dropped_multicast_filtered;
/* 40 Bytes */
__be32 send_done_count;
+#define MXGEFW_LINK_DOWN 0
+#define MXGEFW_LINK_UP 1
+#define MXGEFW_LINK_MYRINET 2
+#define MXGEFW_LINK_UNKNOWN 3
__be32 link_up;
__be32 dropped_link_overflow;
__be32 dropped_link_error_or_filtered;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index a8d7ff2c96a..4cf0d3fcb51 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -81,6 +81,8 @@ static const int multicast_filter_limit = 100;
Setting to > 1518 effectively disables this feature. */
static int rx_copybreak;
+static int dspcfg_workaround = 1;
+
/* Used to pass the media type, etc.
Both 'options[]' and 'full_duplex[]' should exist for driver
interoperability.
@@ -129,7 +131,6 @@ static const char version[] __devinitdata =
KERN_INFO DRV_NAME " dp8381x driver, version "
DRV_VERSION ", " DRV_RELDATE "\n"
KERN_INFO " originally by Donald Becker <becker@scyld.com>\n"
- KERN_INFO " http://www.scyld.com/network/natsemi.html\n"
KERN_INFO " 2.4.x kernel port by Jeff Garzik, Tjeerd Mulder\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
@@ -139,12 +140,14 @@ MODULE_LICENSE("GPL");
module_param(mtu, int, 0);
module_param(debug, int, 0);
module_param(rx_copybreak, int, 0);
+module_param(dspcfg_workaround, int, 1);
module_param_array(options, int, NULL, 0);
module_param_array(full_duplex, int, NULL, 0);
MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
MODULE_PARM_DESC(debug, "DP8381x default debug level");
MODULE_PARM_DESC(rx_copybreak,
"DP8381x copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(dspcfg_workaround, "DP8381x: control DspCfg workaround");
MODULE_PARM_DESC(options,
"DP8381x: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
@@ -590,6 +593,7 @@ struct netdev_private {
u32 srr;
/* expected DSPCFG value */
u16 dspcfg;
+ int dspcfg_workaround;
/* parms saved in ethtool format */
u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */
u8 duplex; /* Duplex, half or full */
@@ -656,6 +660,56 @@ static int netdev_get_regs(struct net_device *dev, u8 *buf);
static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
static const struct ethtool_ops ethtool_ops;
+#define NATSEMI_ATTR(_name) \
+static ssize_t natsemi_show_##_name(struct device *dev, \
+ struct device_attribute *attr, char *buf); \
+ static ssize_t natsemi_set_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count); \
+ static DEVICE_ATTR(_name, 0644, natsemi_show_##_name, natsemi_set_##_name)
+
+#define NATSEMI_CREATE_FILE(_dev, _name) \
+ device_create_file(&_dev->dev, &dev_attr_##_name)
+#define NATSEMI_REMOVE_FILE(_dev, _name) \
+ device_create_file(&_dev->dev, &dev_attr_##_name)
+
+NATSEMI_ATTR(dspcfg_workaround);
+
+static ssize_t natsemi_show_dspcfg_workaround(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct netdev_private *np = netdev_priv(to_net_dev(dev));
+
+ return sprintf(buf, "%s\n", np->dspcfg_workaround ? "on" : "off");
+}
+
+static ssize_t natsemi_set_dspcfg_workaround(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct netdev_private *np = netdev_priv(to_net_dev(dev));
+ int new_setting;
+ u32 flags;
+
+ /* Find out the new setting */
+ if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1))
+ new_setting = 1;
+ else if (!strncmp("off", buf, count - 1)
+ || !strncmp("0", buf, count - 1))
+ new_setting = 0;
+ else
+ return count;
+
+ spin_lock_irqsave(&np->lock, flags);
+
+ np->dspcfg_workaround = new_setting;
+
+ spin_unlock_irqrestore(&np->lock, flags);
+
+ return count;
+}
+
static inline void __iomem *ns_ioaddr(struct net_device *dev)
{
return (void __iomem *) dev->base_addr;
@@ -820,6 +874,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np->ignore_phy = 1;
else
np->ignore_phy = 0;
+ np->dspcfg_workaround = dspcfg_workaround;
/* Initial port:
* - If configured to ignore the PHY set up for external.
@@ -899,6 +954,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
if (i)
goto err_register_netdev;
+ if (NATSEMI_CREATE_FILE(pdev, dspcfg_workaround))
+ goto err_create_file;
+
if (netif_msg_drv(np)) {
printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ",
dev->name, natsemi_pci_info[chip_idx].name, iostart,
@@ -915,6 +973,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
}
return 0;
+ err_create_file:
+ unregister_netdev(dev);
+
err_register_netdev:
iounmap(ioaddr);
@@ -1727,7 +1788,8 @@ static void init_registers(struct net_device *dev)
* It seems that a reference set for this chip went out with incorrect info,
* and there exist boards that aren't quite right. An unexpected voltage
* drop can cause the PHY to get itself in a weird state (basically reset).
- * NOTE: this only seems to affect revC chips.
+ * NOTE: this only seems to affect revC chips. The user can disable
+ * this check via dspcfg_workaround sysfs option.
* 3) check of death of the RX path due to OOM
*/
static void netdev_timer(unsigned long data)
@@ -1753,10 +1815,10 @@ static void netdev_timer(unsigned long data)
writew(1, ioaddr+PGSEL);
dspcfg = readw(ioaddr+DSPCFG);
writew(0, ioaddr+PGSEL);
- if (dspcfg != np->dspcfg) {
+ if (np->dspcfg_workaround && dspcfg != np->dspcfg) {
if (!netif_queue_stopped(dev)) {
spin_unlock_irq(&np->lock);
- if (netif_msg_hw(np))
+ if (netif_msg_drv(np))
printk(KERN_NOTICE "%s: possible phy reset: "
"re-initializing\n", dev->name);
disable_irq(dev->irq);
@@ -3157,6 +3219,7 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
void __iomem * ioaddr = ns_ioaddr(dev);
+ NATSEMI_REMOVE_FILE(pdev, dspcfg_workaround);
unregister_netdev (dev);
pci_release_regions (pdev);
iounmap(ioaddr);
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index a5c4199e275..c9f74bf5f49 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -51,14 +51,11 @@ static const char version2[] =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/jiffies.h>
+#include <linux/platform_device.h>
#include <asm/system.h>
#include <asm/io.h>
-#if defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
-#include <asm/tx4938/rbtx4938.h>
-#endif
-
#include "8390.h"
#define DRV_NAME "ne"
@@ -77,8 +74,13 @@ static const char version2[] =
/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
/* #define PACKETBUF_MEMSIZE 0x40 */
+#if !defined(MODULE) && (defined(CONFIG_ISA) || defined(CONFIG_M32R))
+/* Do we need a portlist for the ISA auto-probe ? */
+#define NEEDS_PORTLIST
+#endif
+
/* A zero-terminated list of I/O addresses to be probed at boot. */
-#ifndef MODULE
+#ifdef NEEDS_PORTLIST
static unsigned int netcard_portlist[] __initdata = {
0x300, 0x280, 0x320, 0x340, 0x360, 0x380, 0
};
@@ -146,7 +148,7 @@ bad_clone_list[] __initdata = {
# define DCR_VAL 0x49
#endif
-static int ne_probe1(struct net_device *dev, int ioaddr);
+static int ne_probe1(struct net_device *dev, unsigned long ioaddr);
static int ne_probe_isapnp(struct net_device *dev);
static int ne_open(struct net_device *dev);
@@ -184,8 +186,8 @@ static void ne_block_output(struct net_device *dev, const int count,
static int __init do_ne_probe(struct net_device *dev)
{
- unsigned int base_addr = dev->base_addr;
-#ifndef MODULE
+ unsigned long base_addr = dev->base_addr;
+#ifdef NEEDS_PORTLIST
int orig_irq = dev->irq;
#endif
@@ -201,7 +203,7 @@ static int __init do_ne_probe(struct net_device *dev)
if (isapnp_present() && (ne_probe_isapnp(dev) == 0))
return 0;
-#ifndef MODULE
+#ifdef NEEDS_PORTLIST
/* Last resort. The semi-risky ISA auto-probe. */
for (base_addr = 0; netcard_portlist[base_addr] != 0; base_addr++) {
int ioaddr = netcard_portlist[base_addr];
@@ -226,10 +228,6 @@ struct net_device * __init ne_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
-#ifdef CONFIG_TOSHIBA_RBTX4938
- dev->base_addr = RBTX4938_RTL_8019_BASE;
- dev->irq = RBTX4938_RTL_8019_IRQ;
-#endif
err = do_ne_probe(dev);
if (err)
goto out;
@@ -285,7 +283,7 @@ static int __init ne_probe_isapnp(struct net_device *dev)
return -ENODEV;
}
-static int __init ne_probe1(struct net_device *dev, int ioaddr)
+static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
{
int i;
unsigned char SA_prom[32];
@@ -324,7 +322,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
if (ei_debug && version_printed++ == 0)
printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
- printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
+ printk(KERN_INFO "NE*000 ethercard probe at %#3lx:", ioaddr);
/* A user with a poor card that fails to ack the reset, or that
does not have a valid 0x57,0x57 signature can still use this
@@ -516,8 +514,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
}
#endif
- printk("\n%s: %s found at %#x, using IRQ %d.\n",
- dev->name, name, ioaddr, dev->irq);
+ printk("\n");
ei_status.name = name;
ei_status.tx_start_page = start_page;
@@ -547,6 +544,8 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
ret = register_netdev(dev);
if (ret)
goto out_irq;
+ printk(KERN_INFO "%s: %s found at %#lx, using IRQ %d.\n",
+ dev->name, name, ioaddr, dev->irq);
return 0;
out_irq:
@@ -807,6 +806,87 @@ retry:
return;
}
+static int __init ne_drv_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct resource *res;
+ int err, irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || irq < 0)
+ return -ENODEV;
+
+ dev = alloc_ei_netdev();
+ if (!dev)
+ return -ENOMEM;
+ dev->irq = irq;
+ dev->base_addr = res->start;
+ err = do_ne_probe(dev);
+ if (err) {
+ free_netdev(dev);
+ return err;
+ }
+ platform_set_drvdata(pdev, dev);
+ return 0;
+}
+
+static int __exit ne_drv_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ unregister_netdev(dev);
+ free_irq(dev->irq, dev);
+ release_region(dev->base_addr, NE_IO_EXTENT);
+ free_netdev(dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ne_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ if (netif_running(dev))
+ netif_device_detach(dev);
+ return 0;
+}
+
+static int ne_drv_resume(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ if (netif_running(dev)) {
+ ne_reset_8390(dev);
+ NS8390_init(dev, 1);
+ netif_device_attach(dev);
+ }
+ return 0;
+}
+#else
+#define ne_drv_suspend NULL
+#define ne_drv_resume NULL
+#endif
+
+static struct platform_driver ne_driver = {
+ .remove = __exit_p(ne_drv_remove),
+ .suspend = ne_drv_suspend,
+ .resume = ne_drv_resume,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ne_init(void)
+{
+ return platform_driver_probe(&ne_driver, ne_drv_probe);
+}
+
+static void __exit ne_exit(void)
+{
+ platform_driver_unregister(&ne_driver);
+}
#ifdef MODULE
#define MAX_NE_CARDS 4 /* Max number of NE cards per module */
@@ -832,6 +912,7 @@ ISA device autoprobes on a running machine are not recommended anyway. */
int __init init_module(void)
{
int this_dev, found = 0;
+ int plat_found = !ne_init();
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
struct net_device *dev = alloc_ei_netdev();
@@ -845,7 +926,7 @@ int __init init_module(void)
continue;
}
free_netdev(dev);
- if (found)
+ if (found || plat_found)
break;
if (io[this_dev] != 0)
printk(KERN_WARNING "ne.c: No NE*000 card found at i/o = %#x\n", io[this_dev]);
@@ -853,7 +934,7 @@ int __init init_module(void)
printk(KERN_NOTICE "ne.c: You must supply \"io=0xNNN\" value(s) for ISA cards.\n");
return -ENXIO;
}
- if (found)
+ if (found || plat_found)
return 0;
return -ENODEV;
}
@@ -871,6 +952,7 @@ void __exit cleanup_module(void)
{
int this_dev;
+ ne_exit();
for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) {
struct net_device *dev = dev_ne[this_dev];
if (dev) {
@@ -880,4 +962,7 @@ void __exit cleanup_module(void)
}
}
}
+#else /* MODULE */
+module_init(ne_init);
+module_exit(ne_exit);
#endif /* MODULE */
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 589785d1e76..995c0a5d406 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -63,8 +63,7 @@ static int options[MAX_UNITS];
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n"
-KERN_INFO " http://www.scyld.com/network/ne2k-pci.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
#if defined(__powerpc__)
#define inl_le(addr) le32_to_cpu(inl(addr))
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index dd8ce35332f..ad6688eab26 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -64,9 +64,9 @@
#include "netxen_nic_hw.h"
#define _NETXEN_NIC_LINUX_MAJOR 3
-#define _NETXEN_NIC_LINUX_MINOR 3
-#define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID "3.3.3"
+#define _NETXEN_NIC_LINUX_MINOR 4
+#define _NETXEN_NIC_LINUX_SUBVERSION 2
+#define NETXEN_NIC_LINUX_VERSIONID "3.4.2"
#define NUM_FLASH_SECTORS (64)
#define FLASH_SECTOR_SIZE (64 * 1024)
@@ -131,8 +131,8 @@ extern struct workqueue_struct *netxen_workq;
#define FIRST_PAGE_GROUP_START 0
#define FIRST_PAGE_GROUP_END 0x100000
-#define SECOND_PAGE_GROUP_START 0x4000000
-#define SECOND_PAGE_GROUP_END 0x66BC000
+#define SECOND_PAGE_GROUP_START 0x6000000
+#define SECOND_PAGE_GROUP_END 0x68BC000
#define THIRD_PAGE_GROUP_START 0x70E4000
#define THIRD_PAGE_GROUP_END 0x8000000
@@ -205,6 +205,8 @@ enum {
#define MAX_CMD_DESCRIPTORS 1024
#define MAX_RCV_DESCRIPTORS 16384
+#define MAX_CMD_DESCRIPTORS_HOST (MAX_CMD_DESCRIPTORS / 4)
+#define MAX_RCV_DESCRIPTORS_1G (MAX_RCV_DESCRIPTORS / 4)
#define MAX_JUMBO_RCV_DESCRIPTORS 1024
#define MAX_LRO_RCV_DESCRIPTORS 64
#define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS
@@ -230,7 +232,9 @@ enum {
(((index) + (count)) & ((length) - 1))
#define MPORT_SINGLE_FUNCTION_MODE 0x1111
+#define MPORT_MULTI_FUNCTION_MODE 0x2222
+#include "netxen_nic_phan_reg.h"
extern unsigned long long netxen_dma_mask;
extern unsigned long last_schedule_time;
@@ -300,6 +304,8 @@ struct netxen_ring_ctx {
#define netxen_set_cmd_desc_port(cmd_desc, var) \
((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define netxen_set_cmd_desc_ctxid(cmd_desc, var) \
+ ((cmd_desc)->port_ctxid |= ((var) & 0xF0))
#define netxen_set_cmd_desc_flags(cmd_desc, val) \
((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \
@@ -442,7 +448,7 @@ struct status_desc {
/* Bit pattern: 0-6 lro_count indicates frag sequence,
7 last_frag indicates last frag */
u8 lro;
-} __attribute__ ((aligned(8)));
+} __attribute__ ((aligned(16)));
enum {
NETXEN_RCV_PEG_0 = 0,
@@ -703,10 +709,8 @@ extern char netxen_nic_driver_name[];
#else
#define DPRINTK(klevel, fmt, args...) do { \
printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\
- (adapter != NULL && \
- adapter->port[0] != NULL && \
- adapter->port[0]->netdev != NULL) ? \
- adapter->port[0]->netdev->name : NULL, \
+ (adapter != NULL && adapter->netdev != NULL) ? \
+ adapter->netdev->name : NULL, \
## args); } while(0)
#endif
@@ -722,6 +726,18 @@ struct netxen_skb_frag {
u32 length;
};
+#define _netxen_set_bits(config_word, start, bits, val) {\
+ unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\
+ unsigned long long __tvalue = (val); \
+ (config_word) &= ~__tmask; \
+ (config_word) |= (((__tvalue) << (start)) & __tmask); \
+}
+
+#define _netxen_clear_bits(config_word, start, bits) {\
+ unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \
+ (config_word) &= ~__tmask; \
+}
+
/* Following defines are for the state of the buffers */
#define NETXEN_BUFFER_FREE 0
#define NETXEN_BUFFER_BUSY 1
@@ -766,6 +782,8 @@ struct netxen_hardware_context {
void __iomem *pci_base0;
void __iomem *pci_base1;
void __iomem *pci_base2;
+ unsigned long first_page_group_end;
+ unsigned long first_page_group_start;
void __iomem *db_base;
unsigned long db_len;
@@ -780,6 +798,7 @@ struct netxen_hardware_context {
struct pci_dev *cmd_desc_pdev;
dma_addr_t cmd_desc_phys_addr;
struct netxen_adapter *adapter;
+ int pci_func;
};
#define RCV_RING_LRO RCV_DESC_LRO
@@ -788,17 +807,27 @@ struct netxen_hardware_context {
#define ETHERNET_FCS_SIZE 4
struct netxen_adapter_stats {
- u64 ints;
- u64 hostints;
- u64 otherints;
- u64 process_rcv;
- u64 process_xmit;
- u64 noxmitdone;
- u64 xmitcsummed;
- u64 post_called;
- u64 posted;
- u64 lastposted;
- u64 goodskbposts;
+ u64 rcvdbadskb;
+ u64 xmitcalled;
+ u64 xmitedframes;
+ u64 xmitfinished;
+ u64 badskblen;
+ u64 nocmddescriptor;
+ u64 polled;
+ u64 uphappy;
+ u64 updropped;
+ u64 uplcong;
+ u64 uphcong;
+ u64 upmcong;
+ u64 updunno;
+ u64 skbfreed;
+ u64 txdropped;
+ u64 txnullskb;
+ u64 csummed;
+ u64 no_rcv;
+ u64 rxbytes;
+ u64 txbytes;
+ u64 ints;
};
/*
@@ -846,13 +875,20 @@ struct netxen_dummy_dma {
struct netxen_adapter {
struct netxen_hardware_context ahw;
- int port_count; /* Number of configured ports */
- int active_ports; /* Number of open ports */
- struct netxen_port *port[NETXEN_MAX_PORTS]; /* ptr to each port */
+
+ struct netxen_adapter *master;
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+ struct net_device_stats net_stats;
+ unsigned char mac_addr[ETH_ALEN];
+ int mtu;
+ int portnum;
+
spinlock_t tx_lock;
spinlock_t lock;
struct work_struct watchdog_task;
struct timer_list watchdog_timer;
+ struct work_struct tx_timeout_task;
u32 curr_window;
@@ -875,6 +911,15 @@ struct netxen_adapter {
u32 temp;
struct netxen_adapter_stats stats;
+
+ u16 portno;
+ u16 link_speed;
+ u16 link_duplex;
+ u16 state;
+ u16 link_autoneg;
+ int rcsum;
+ int status;
+ spinlock_t stats_lock;
struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */
@@ -891,65 +936,23 @@ struct netxen_adapter {
struct netxen_ring_ctx *ctx_desc;
struct pci_dev *ctx_desc_pdev;
dma_addr_t ctx_desc_phys_addr;
- int (*enable_phy_interrupts) (struct netxen_adapter *, int);
- int (*disable_phy_interrupts) (struct netxen_adapter *, int);
+ int (*enable_phy_interrupts) (struct netxen_adapter *);
+ int (*disable_phy_interrupts) (struct netxen_adapter *);
void (*handle_phy_intr) (struct netxen_adapter *);
- int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t);
- int (*set_mtu) (struct netxen_port *, int);
- int (*set_promisc) (struct netxen_adapter *, int,
- netxen_niu_prom_mode_t);
- int (*unset_promisc) (struct netxen_adapter *, int,
- netxen_niu_prom_mode_t);
- int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *);
- int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val);
+ int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t);
+ int (*set_mtu) (struct netxen_adapter *, int);
+ int (*set_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+ int (*unset_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t);
+ int (*phy_read) (struct netxen_adapter *, long reg, u32 *);
+ int (*phy_write) (struct netxen_adapter *, long reg, u32 val);
int (*init_port) (struct netxen_adapter *, int);
void (*init_niu) (struct netxen_adapter *);
- int (*stop_port) (struct netxen_adapter *, int);
+ int (*stop_port) (struct netxen_adapter *);
}; /* netxen_adapter structure */
/* Max number of xmit producer threads that can run simultaneously */
#define MAX_XMIT_PRODUCERS 16
-struct netxen_port_stats {
- u64 rcvdbadskb;
- u64 xmitcalled;
- u64 xmitedframes;
- u64 xmitfinished;
- u64 badskblen;
- u64 nocmddescriptor;
- u64 polled;
- u64 uphappy;
- u64 updropped;
- u64 uplcong;
- u64 uphcong;
- u64 upmcong;
- u64 updunno;
- u64 skbfreed;
- u64 txdropped;
- u64 txnullskb;
- u64 csummed;
- u64 no_rcv;
- u64 rxbytes;
- u64 txbytes;
-};
-
-struct netxen_port {
- struct netxen_adapter *adapter;
-
- u16 portnum; /* GBE port number */
- u16 link_speed;
- u16 link_duplex;
- u16 link_autoneg;
-
- int flags;
-
- struct net_device *netdev;
- struct pci_dev *pdev;
- struct net_device_stats net_stats;
- struct netxen_port_stats stats;
- struct work_struct tx_timeout_task;
-};
-
#define PCI_OFFSET_FIRST_RANGE(adapter, off) \
((adapter)->ahw.pci_base0 + (off))
#define PCI_OFFSET_SECOND_RANGE(adapter, off) \
@@ -987,32 +990,26 @@ static inline void __iomem *pci_base(struct netxen_adapter *adapter,
return NULL;
}
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port);
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port);
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter);
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter);
void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter);
void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter);
void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port,
long enable);
void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port,
long enable);
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg,
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
__u32 * readval);
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy,
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
long reg, __u32 val);
/* Functions available from netxen_nic_hw.c */
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu);
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu);
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu);
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu);
void netxen_nic_init_niu_gb(struct netxen_adapter *adapter);
void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw);
void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val);
@@ -1027,6 +1024,7 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data,
int len);
void netxen_crb_writelit_adapter(struct netxen_adapter *adapter,
unsigned long off, int data);
+int netxen_nic_erase_pxe(struct netxen_adapter *adapter);
/* Functions from netxen_nic_init.c */
void netxen_free_adapter_offload(struct netxen_adapter *adapter);
@@ -1051,11 +1049,8 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
/* Functions from netxen_nic_isr.c */
void netxen_nic_isr_other(struct netxen_adapter *adapter);
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 port,
- u32 link);
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 port,
- u32 enable);
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter);
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link);
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable);
void netxen_initialize_adapter_sw(struct netxen_adapter *adapter);
void netxen_initialize_adapter_hw(struct netxen_adapter *adapter);
void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr,
@@ -1110,6 +1105,7 @@ static inline void netxen_nic_enable_int(struct netxen_adapter *adapter)
if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
mask = 0xbff;
+ writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
writel(mask, PCI_OFFSET_SECOND_RANGE(adapter,
ISR_INT_TARGET_MASK));
}
@@ -1174,4 +1170,5 @@ extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr,
extern struct ethtool_ops netxen_nic_ethtool_ops;
+extern int physical_port[]; /* physical port # from virtual port.*/
#endif /* __NETXEN_NIC_H_ */
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index ee1b5a24cbe..16fabb37748 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -40,8 +40,8 @@
#include <linux/ethtool.h>
#include <linux/version.h>
-#include "netxen_nic_hw.h"
#include "netxen_nic.h"
+#include "netxen_nic_hw.h"
#include "netxen_nic_phan_reg.h"
struct netxen_nic_stats {
@@ -50,8 +50,8 @@ struct netxen_nic_stats {
int stat_offset;
};
-#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_port *)0)->m), \
- offsetof(struct netxen_port, m)
+#define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \
+ offsetof(struct netxen_adapter, m)
#define NETXEN_NIC_PORT_WINDOW 0x10000
#define NETXEN_NIC_INVALID_DATA 0xDEADBEEF
@@ -100,8 +100,7 @@ static int netxen_nic_get_eeprom_len(struct net_device *dev)
static void
netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
u32 fw_major = 0;
u32 fw_minor = 0;
u32 fw_build = 0;
@@ -115,7 +114,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB));
sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
- strncpy(drvinfo->bus_info, pci_name(port->pdev), 32);
+ strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
@@ -125,8 +124,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
static int
netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg;
/* read which mode */
@@ -146,8 +144,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
if (netif_running(dev)) {
- ecmd->speed = port->link_speed;
- ecmd->duplex = port->link_duplex;
+ ecmd->speed = adapter->link_speed;
+ ecmd->duplex = adapter->link_duplex;
} else
return -EIO; /* link absent */
} else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
@@ -165,7 +163,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
} else
return -EIO;
- ecmd->phy_address = port->portnum;
+ ecmd->phy_address = adapter->portnum;
ecmd->transceiver = XCVR_EXTERNAL;
switch ((netxen_brdtype_t) boardinfo->board_type) {
@@ -179,7 +177,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
ecmd->autoneg = (boardinfo->board_type ==
NETXEN_BRDTYPE_P2_SB31_10G_CX4) ?
- (AUTONEG_DISABLE) : (port->link_autoneg);
+ (AUTONEG_DISABLE) : (adapter->link_autoneg);
break;
case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
@@ -206,23 +204,22 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
static int
netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 status;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
/* autonegotiation */
if (adapter->phy_write
- && adapter->phy_write(adapter, port->portnum,
+ && adapter->phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
ecmd->autoneg) != 0)
return -EIO;
else
- port->link_autoneg = ecmd->autoneg;
+ adapter->link_autoneg = ecmd->autoneg;
if (adapter->phy_read
- && adapter->phy_read(adapter, port->portnum,
+ && adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) != 0)
return -EIO;
@@ -245,13 +242,13 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (ecmd->duplex == DUPLEX_FULL)
netxen_set_phy_duplex(status);
if (adapter->phy_write
- && adapter->phy_write(adapter, port->portnum,
+ && adapter->phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
*((int *)&status)) != 0)
return -EIO;
else {
- port->link_speed = ecmd->speed;
- port->link_duplex = ecmd->duplex;
+ adapter->link_speed = ecmd->speed;
+ adapter->link_duplex = ecmd->duplex;
}
} else
return -EOPNOTSUPP;
@@ -360,15 +357,14 @@ static struct netxen_niu_regs niu_registers[] = {
static void
netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 mode, *regs_buff = p;
void __iomem *addr;
int i, window;
memset(p, 0, NETXEN_NIC_REGS_LEN);
regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) |
- (port->pdev)->device;
+ (adapter->pdev)->device;
/* which mode */
NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, &regs_buff[0]);
mode = regs_buff[0];
@@ -383,7 +379,8 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) {
/* GB: port specific registers */
if (mode == 0 && i >= 19)
- window = port->portnum * NETXEN_NIC_PORT_WINDOW;
+ window = physical_port[adapter->portnum] *
+ NETXEN_NIC_PORT_WINDOW;
NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode].
reg[i - 3] + window,
@@ -395,15 +392,14 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
static u32 netxen_nic_test_link(struct net_device *dev)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 status;
int val;
/* read which mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
if (adapter->phy_read
- && adapter->phy_read(adapter, port->portnum,
+ && adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) != 0)
return -EIO;
@@ -422,15 +418,15 @@ static int
netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 * bytes)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
int offset;
int ret;
if (eeprom->len == 0)
return -EINVAL;
- eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
+ eeprom->magic = (adapter->pdev)->vendor |
+ ((adapter->pdev)->device << 16);
offset = eeprom->offset;
ret = netxen_rom_fast_read_words(adapter, offset, bytes,
@@ -445,8 +441,7 @@ static int
netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u8 * bytes)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
int offset = eeprom->offset;
static int flash_start;
static int ready_to_flash;
@@ -516,8 +511,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
static void
netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
int i;
ring->rx_pending = 0;
@@ -541,19 +535,45 @@ static void
netxen_nic_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
+ int port = physical_port[adapter->portnum];
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return;
/* get flow control settings */
- netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- &val);
+ netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ &val);
pause->rx_pause = netxen_gb_get_rx_flowctl(val);
- pause->tx_pause = netxen_gb_get_tx_flowctl(val);
- /* get autoneg settings */
- pause->autoneg = port->link_autoneg;
+ netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+ switch (port) {
+ case 0:
+ pause->tx_pause = !(netxen_gb_get_gb0_mask(val));
+ break;
+ case 1:
+ pause->tx_pause = !(netxen_gb_get_gb1_mask(val));
+ break;
+ case 2:
+ pause->tx_pause = !(netxen_gb_get_gb2_mask(val));
+ break;
+ case 3:
+ default:
+ pause->tx_pause = !(netxen_gb_get_gb3_mask(val));
+ break;
+ }
+ } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
+ return;
+ pause->rx_pause = 1;
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+ if (port == 0)
+ pause->tx_pause = !(netxen_xg_get_xg0_mask(val));
+ else
+ pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
+ } else {
+ printk(KERN_ERR"%s: Unknown board type: %x\n",
+ netxen_nic_driver_name, adapter->ahw.board_type);
}
}
@@ -561,42 +581,76 @@ static int
netxen_nic_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *pause)
{
- struct netxen_port *port = netdev_priv(dev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(dev);
__u32 val;
- unsigned int autoneg;
-
+ int port = physical_port[adapter->portnum];
/* read mode */
if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return -EIO;
/* set flow control */
netxen_nic_read_w0(adapter,
- NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- (u32 *) & val);
- if (pause->tx_pause)
- netxen_gb_tx_flowctl(val);
- else
- netxen_gb_unset_tx_flowctl(val);
+ NETXEN_NIU_GB_MAC_CONFIG_0(port), &val);
+
if (pause->rx_pause)
netxen_gb_rx_flowctl(val);
else
netxen_gb_unset_rx_flowctl(val);
- netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum),
- *&val);
+ netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ val);
/* set autoneg */
- autoneg = pause->autoneg;
- if (adapter->phy_write
- && adapter->phy_write(adapter, port->portnum,
- NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
- autoneg) != 0)
+ netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val);
+ switch (port) {
+ case 0:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb0_mask(val);
+ else
+ netxen_gb_set_gb0_mask(val);
+ break;
+ case 1:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb1_mask(val);
+ else
+ netxen_gb_set_gb1_mask(val);
+ break;
+ case 2:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb2_mask(val);
+ else
+ netxen_gb_set_gb2_mask(val);
+ break;
+ case 3:
+ default:
+ if (pause->tx_pause)
+ netxen_gb_unset_gb3_mask(val);
+ else
+ netxen_gb_set_gb3_mask(val);
+ break;
+ }
+ netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
+ } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+ if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
return -EIO;
- else {
- port->link_autoneg = pause->autoneg;
- return 0;
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
+ if (port == 0) {
+ if (pause->tx_pause)
+ netxen_xg_unset_xg0_mask(val);
+ else
+ netxen_xg_set_xg0_mask(val);
+ } else {
+ if (pause->tx_pause)
+ netxen_xg_unset_xg1_mask(val);
+ else
+ netxen_xg_set_xg1_mask(val);
}
- } else
- return -EOPNOTSUPP;
+ netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val);
+ } else {
+ printk(KERN_ERR "%s: Unknown board type: %x\n",
+ netxen_nic_driver_name,
+ adapter->ahw.board_type);
+ }
+ return 0;
}
static int netxen_nic_reg_test(struct net_device *dev)
@@ -627,23 +681,12 @@ static void
netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
u64 * data)
{
- if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */
- /* link test */
- if ((data[1] = (u64) netxen_nic_test_link(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
- /* register tests */
- if ((data[0] = netxen_nic_reg_test(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
- } else { /* online tests */
- /* register tests */
- if((data[0] = netxen_nic_reg_test(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
-
- /* link test */
- if ((data[1] = (u64) netxen_nic_test_link(dev)))
- eth_test->flags |= ETH_TEST_FL_FAILED;
- }
+ memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN);
+ if ((data[0] = netxen_nic_reg_test(dev)))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ /* link test */
+ if ((data[1] = (u64) netxen_nic_test_link(dev)))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
}
static void
@@ -675,12 +718,13 @@ static void
netxen_nic_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 * data)
{
- struct netxen_port *port = netdev_priv(dev);
+ struct netxen_adapter *adapter = netdev_priv(dev);
int index;
for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) {
char *p =
- (char *)port + netxen_nic_gstrings_stats[index].stat_offset;
+ (char *)adapter +
+ netxen_nic_gstrings_stats[index].stat_offset;
data[index] =
(netxen_nic_gstrings_stats[index].sizeof_stat ==
sizeof(u64)) ? *(u64 *) p : *(u32 *) p;
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index fe8b675f9e7..608e37b349b 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -467,6 +467,8 @@ enum {
#define NETXEN_PCI_OCM1 (0x05100000UL)
#define NETXEN_PCI_OCM1_MAX (0x051fffffUL)
#define NETXEN_PCI_CRBSPACE (0x06000000UL)
+#define NETXEN_PCI_128MB_SIZE (0x08000000UL)
+#define NETXEN_PCI_32MB_SIZE (0x02000000UL)
#define NETXEN_CRB_CAM NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM)
@@ -484,6 +486,7 @@ enum {
/* 10 seconds before we give up */
#define NETXEN_NIU_PHY_WAITMAX 50
#define NETXEN_NIU_MAX_GBE_PORTS 4
+#define NETXEN_NIU_MAX_XG_PORTS 2
#define NETXEN_NIU_MODE (NETXEN_CRB_NIU + 0x00000)
@@ -527,6 +530,7 @@ enum {
#define NETXEN_NIU_XG_PAUSE_CTL (NETXEN_CRB_NIU + 0x00098)
#define NETXEN_NIU_XG_PAUSE_LEVEL (NETXEN_CRB_NIU + 0x000dc)
#define NETXEN_NIU_XG_SEL (NETXEN_CRB_NIU + 0x00128)
+#define NETXEN_NIU_GB_PAUSE_CTL (NETXEN_CRB_NIU + 0x0030c)
#define NETXEN_NIU_FULL_LEVEL_XG (NETXEN_CRB_NIU + 0x00450)
@@ -649,11 +653,19 @@ enum {
#define PCIX_MS_WINDOW (0x10204)
#define PCIX_SN_WINDOW (0x10208)
#define PCIX_CRB_WINDOW (0x10210)
+#define PCIX_CRB_WINDOW_F0 (0x10210)
+#define PCIX_CRB_WINDOW_F1 (0x10230)
+#define PCIX_CRB_WINDOW_F2 (0x10250)
+#define PCIX_CRB_WINDOW_F3 (0x10270)
#define PCIX_TARGET_STATUS (0x10118)
#define PCIX_TARGET_MASK (0x10128)
#define PCIX_MSI_F0 (0x13000)
+#define PCIX_MSI_F1 (0x13004)
+#define PCIX_MSI_F2 (0x13008)
+#define PCIX_MSI_F3 (0x1300c)
+#define PCIX_MSI_F(i) (0x13000+((i)*4))
#define PCIX_PS_MEM_SPACE (0x90000)
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 0fba8f19076..baff17a24d6 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -33,10 +33,225 @@
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
+#define DEFINE_GLOBAL_RECV_CRB
#include "netxen_nic_phan_reg.h"
+
#include <net/ip.h>
+struct netxen_recv_crb recv_crb_registers[] = {
+ /*
+ * Instance 0.
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x100),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x104),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x108),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x10c),
+
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x110),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x114),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x118),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x11c),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x120),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x124),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x128),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x12c),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x130),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x134),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x138),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x13c),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x140),
+
+ },
+ /*
+ * Instance 1,
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x144),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x148),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x14c),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x150),
+
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x154),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x158),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x15c),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x160),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x164),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x168),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x16c),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x170),
+ }
+
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x174),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x178),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x17c),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x180),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x184),
+ },
+ /*
+ * Instance 2,
+ */
+ {
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x1d8),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x1dc),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x1f0),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x1f4),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x1f8),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x1fc),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x200),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x204),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x208),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x20c),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x210),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x214),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x218),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x21c),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x220),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x224),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x228),
+ },
+ /*
+ * Instance 3,
+ */
+ {
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x22c),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x230),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x234),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x238),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x23c),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x240),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x244),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x248),
+ },
+ /* LRO */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x24c),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x250),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x254),
+ /* crb_rcv_ring_size */
+ NETXEN_NIC_REG(0x258),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x25c),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x260),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x264),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x268),
+ /* crb_status_ring_size */
+ NETXEN_NIC_REG(0x26c),
+ },
+};
+
+u64 ctx_addr_sig_regs[][3] = {
+ {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
+ {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
+ {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
+ {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
+};
+
+
/* PCI Windowing for DDR regions. */
#define ADDR_IN_RANGE(addr, low, high) \
@@ -70,8 +285,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter);
int netxen_nic_set_mac(struct net_device *netdev, void *p)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
if (netif_running(netdev))
@@ -84,7 +298,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
if (adapter->macaddr_set)
- adapter->macaddr_set(port, addr->sa_data);
+ adapter->macaddr_set(adapter, addr->sa_data);
return 0;
}
@@ -94,56 +308,19 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p)
*/
void netxen_nic_set_multi(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
struct dev_mc_list *mc_ptr;
- __u32 netxen_mac_addr_cntl_data = 0;
mc_ptr = netdev->mc_list;
if (netdev->flags & IFF_PROMISC) {
if (adapter->set_promisc)
adapter->set_promisc(adapter,
- port->portnum,
NETXEN_NIU_PROMISC_MODE);
} else {
- if (adapter->unset_promisc &&
- adapter->ahw.boardcfg.board_type
- != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+ if (adapter->unset_promisc)
adapter->unset_promisc(adapter,
- port->portnum,
NETXEN_NIU_NON_PROMISC_MODE);
}
- if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
- netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03);
- netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data);
- netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data);
- netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data);
- netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data);
- } else {
- netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00);
- netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01);
- netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02);
- netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03);
- }
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG));
- if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter,
- NETXEN_MULTICAST_ADDR_HI_0));
- } else {
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter,
- NETXEN_MULTICAST_ADDR_HI_1));
- }
- netxen_mac_addr_cntl_data = 0;
- writel(netxen_mac_addr_cntl_data,
- NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR));
}
/*
@@ -152,8 +329,7 @@ void netxen_nic_set_multi(struct net_device *netdev)
*/
int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE;
if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) {
@@ -163,7 +339,7 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
}
if (adapter->set_mtu)
- adapter->set_mtu(port, mtu);
+ adapter->set_mtu(adapter, mtu);
netdev->mtu = mtu;
return 0;
@@ -180,9 +356,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
void *addr;
int loops = 0, err = 0;
int ctx, ring;
- u32 card_cmdring = 0;
struct netxen_recv_context *recv_ctx;
struct netxen_rcv_desc_ctx *rcv_desc;
+ int func_id = adapter->portnum;
DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE,
PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE));
@@ -191,11 +367,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE,
pci_base_offset(adapter, NETXEN_CAM_RAM_BASE));
- /* Window 1 call */
- card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING));
-
- DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n",
- card_cmdring);
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n");
@@ -229,7 +400,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
(dma_addr_t *) & adapter->ctx_desc_phys_addr,
&adapter->ctx_desc_pdev);
- printk("ctx_desc_phys_addr: 0x%llx\n",
+ printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n",
(unsigned long long) adapter->ctx_desc_phys_addr);
if (addr == NULL) {
DPRINTK(ERR, "bad return from pci_alloc_consistent\n");
@@ -238,6 +409,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
}
memset(addr, 0, sizeof(struct netxen_ring_ctx));
adapter->ctx_desc = (struct netxen_ring_ctx *)addr;
+ adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum);
adapter->ctx_desc->cmd_consumer_offset =
cpu_to_le64(adapter->ctx_desc_phys_addr +
sizeof(struct netxen_ring_ctx));
@@ -249,7 +421,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
adapter->max_tx_desc_count,
(dma_addr_t *) & hw->cmd_desc_phys_addr,
&adapter->ahw.cmd_desc_pdev);
- printk("cmd_desc_phys_addr: 0x%llx\n",
+ printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n",
(unsigned long long) hw->cmd_desc_phys_addr);
if (addr == NULL) {
@@ -308,11 +480,11 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter)
/* Window = 1 */
writel(lower32(adapter->ctx_desc_phys_addr),
- NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO));
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO(func_id)));
writel(upper32(adapter->ctx_desc_phys_addr),
- NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI));
- writel(NETXEN_CTX_SIGNATURE,
- NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG));
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI(func_id)));
+ writel(NETXEN_CTX_SIGNATURE | func_id,
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG(func_id)));
return err;
}
@@ -339,10 +511,6 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
adapter->ahw.cmd_desc_phys_addr);
adapter->ahw.cmd_desc_head = NULL;
}
- /* Special handling: there are 2 ports on this board */
- if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
- adapter->ahw.max_ports = 2;
- }
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
recv_ctx = &adapter->recv_ctx[ctx];
@@ -385,7 +553,6 @@ void netxen_tso_check(struct netxen_adapter *adapter,
return;
}
}
- adapter->stats.xmitcsummed++;
desc->tcp_hdr_offset = skb_transport_offset(skb);
desc->ip_hdr_offset = skb_network_offset(skb);
}
@@ -475,7 +642,30 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
if (adapter->curr_window == wndw)
return;
-
+ switch(adapter->ahw.pci_func) {
+ case 0:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+ break;
+ case 1:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F1));
+ break;
+ case 2:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F2));
+ break;
+ case 3:
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3));
+ break;
+ default:
+ printk(KERN_INFO "Changing the window for PCI function"
+ "%d\n", adapter->ahw.pci_func);
+ offset = PCI_OFFSET_SECOND_RANGE(adapter,
+ NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
+ break;
+ }
/*
* Move the CRB window.
* We need to write to the "direct access" region of PCI
@@ -484,9 +674,6 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
* register address is received by PCI. The direct region bypasses
* the CRB bus.
*/
- offset =
- PCI_OFFSET_SECOND_RANGE(adapter,
- NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW));
if (wndw & 0x1)
wndw = NETXEN_WINDOW_ONE;
@@ -504,7 +691,10 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw)
count++;
}
- adapter->curr_window = wndw;
+ if (wndw == NETXEN_WINDOW_ONE)
+ adapter->curr_window = 1;
+ else
+ adapter->curr_window = 0;
}
void netxen_load_firmware(struct netxen_adapter *adapter)
@@ -749,6 +939,17 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter,
return addr;
}
+int
+netxen_nic_erase_pxe(struct netxen_adapter *adapter)
+{
+ if (netxen_rom_fast_write(adapter, PXE_START, 0) == -1) {
+ printk(KERN_ERR "%s: erase pxe failed\n",
+ netxen_nic_driver_name);
+ return -1;
+ }
+ return 0;
+}
+
int netxen_nic_get_board_info(struct netxen_adapter *adapter)
{
int rv = 0;
@@ -810,43 +1011,29 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
/* NIU access sections */
-int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu)
{
- struct netxen_adapter *adapter = port->adapter;
netxen_nic_write_w0(adapter,
- NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum),
- new_mtu);
+ NETXEN_NIU_GB_MAX_FRAME_SIZE(
+ physical_port[adapter->portnum]), new_mtu);
return 0;
}
-int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu)
+int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu)
{
- struct netxen_adapter *adapter = port->adapter;
new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE;
- if (port->portnum == 0)
- netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu);
- else if (port->portnum == 1)
- netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu);
+ if (physical_port[adapter->portnum] == 0)
+ netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE,
+ new_mtu);
+ else
+ netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE,
+ new_mtu);
return 0;
}
void netxen_nic_init_niu_gb(struct netxen_adapter *adapter)
{
- int portno;
- for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++)
- netxen_niu_gbe_init_port(adapter, portno);
-}
-
-void netxen_nic_stop_all_ports(struct netxen_adapter *adapter)
-{
- int port_nr;
- struct netxen_port *port;
-
- for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) {
- port = adapter->port[port_nr];
- if (adapter->stop_port)
- adapter->stop_port(adapter, port->portnum);
- }
+ netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]);
}
void
@@ -865,9 +1052,8 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off,
}
}
-void netxen_nic_set_link_parameters(struct netxen_port *port)
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
{
- struct netxen_adapter *adapter = port->adapter;
__u32 status;
__u32 autoneg;
__u32 mode;
@@ -876,47 +1062,47 @@ void netxen_nic_set_link_parameters(struct netxen_port *port)
if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */
if (adapter->phy_read
&& adapter->
- phy_read(adapter, port->portnum,
+ phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) == 0) {
if (netxen_get_phy_link(status)) {
switch (netxen_get_phy_speed(status)) {
case 0:
- port->link_speed = SPEED_10;
+ adapter->link_speed = SPEED_10;
break;
case 1:
- port->link_speed = SPEED_100;
+ adapter->link_speed = SPEED_100;
break;
case 2:
- port->link_speed = SPEED_1000;
+ adapter->link_speed = SPEED_1000;
break;
default:
- port->link_speed = -1;
+ adapter->link_speed = -1;
break;
}
switch (netxen_get_phy_duplex(status)) {
case 0:
- port->link_duplex = DUPLEX_HALF;
+ adapter->link_duplex = DUPLEX_HALF;
break;
case 1:
- port->link_duplex = DUPLEX_FULL;
+ adapter->link_duplex = DUPLEX_FULL;
break;
default:
- port->link_duplex = -1;
+ adapter->link_duplex = -1;
break;
}
if (adapter->phy_read
&& adapter->
- phy_read(adapter, port->portnum,
+ phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG,
&autoneg) != 0)
- port->link_autoneg = autoneg;
+ adapter->link_autoneg = autoneg;
} else
goto link_down;
} else {
link_down:
- port->link_speed = -1;
- port->link_duplex = -1;
+ adapter->link_speed = -1;
+ adapter->link_duplex = -1;
}
}
}
@@ -930,7 +1116,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
char brd_name[NETXEN_MAX_SHORT_NAME];
struct netxen_new_user_info user_info;
int i, addr = USER_START;
- u32 *ptr32;
+ __le32 *ptr32;
struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
if (board_info->magic != NETXEN_BDINFO_MAGIC) {
@@ -956,7 +1142,6 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
netxen_nic_driver_name);
return;
}
- *ptr32 = le32_to_cpu(*ptr32);
ptr32++;
addr += sizeof(u32);
}
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h
index ab1112eb1b0..245bf13c7ba 100644
--- a/drivers/net/netxen/netxen_nic_hw.h
+++ b/drivers/net/netxen/netxen_nic_hw.h
@@ -6,12 +6,12 @@
* 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., 59 Temple Place - Suite 330, Boston,
@@ -87,7 +87,7 @@ struct netxen_adapter;
*(u32 *)Y = readl((void __iomem*) addr);
struct netxen_port;
-void netxen_nic_set_link_parameters(struct netxen_port *port);
+void netxen_nic_set_link_parameters(struct netxen_adapter *adapter);
void netxen_nic_flash_print(struct netxen_adapter *adapter);
int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off,
void *data, int len);
@@ -220,6 +220,69 @@ typedef enum {
_netxen_crb_get_bit(config_word, 1)
#define netxen_get_gb_mii_mgmt_notvalid(config_word) \
_netxen_crb_get_bit(config_word, 2)
+/*
+ * NIU XG Pause Ctl Register
+ *
+ * Bit 0 : xg0_mask => 1:disable tx pause frames
+ * Bit 1 : xg0_request => 1:request single pause frame
+ * Bit 2 : xg0_on_off => 1:request is pause on, 0:off
+ * Bit 3 : xg1_mask => 1:disable tx pause frames
+ * Bit 4 : xg1_request => 1:request single pause frame
+ * Bit 5 : xg1_on_off => 1:request is pause on, 0:off
+ */
+
+#define netxen_xg_set_xg0_mask(config_word) \
+ ((config_word) |= 1 << 0)
+#define netxen_xg_set_xg1_mask(config_word) \
+ ((config_word) |= 1 << 3)
+
+#define netxen_xg_get_xg0_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 0)
+#define netxen_xg_get_xg1_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 3)
+
+#define netxen_xg_unset_xg0_mask(config_word) \
+ ((config_word) &= ~(1 << 0))
+#define netxen_xg_unset_xg1_mask(config_word) \
+ ((config_word) &= ~(1 << 3))
+
+/*
+ * NIU XG Pause Ctl Register
+ *
+ * Bit 0 : xg0_mask => 1:disable tx pause frames
+ * Bit 1 : xg0_request => 1:request single pause frame
+ * Bit 2 : xg0_on_off => 1:request is pause on, 0:off
+ * Bit 3 : xg1_mask => 1:disable tx pause frames
+ * Bit 4 : xg1_request => 1:request single pause frame
+ * Bit 5 : xg1_on_off => 1:request is pause on, 0:off
+ */
+#define netxen_gb_set_gb0_mask(config_word) \
+ ((config_word) |= 1 << 0)
+#define netxen_gb_set_gb1_mask(config_word) \
+ ((config_word) |= 1 << 2)
+#define netxen_gb_set_gb2_mask(config_word) \
+ ((config_word) |= 1 << 4)
+#define netxen_gb_set_gb3_mask(config_word) \
+ ((config_word) |= 1 << 6)
+
+#define netxen_gb_get_gb0_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 0)
+#define netxen_gb_get_gb1_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 2)
+#define netxen_gb_get_gb2_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 4)
+#define netxen_gb_get_gb3_mask(config_word) \
+ _netxen_crb_get_bit((config_word), 6)
+
+#define netxen_gb_unset_gb0_mask(config_word) \
+ ((config_word) &= ~(1 << 0))
+#define netxen_gb_unset_gb1_mask(config_word) \
+ ((config_word) &= ~(1 << 2))
+#define netxen_gb_unset_gb2_mask(config_word) \
+ ((config_word) &= ~(1 << 4))
+#define netxen_gb_unset_gb3_mask(config_word) \
+ ((config_word) &= ~(1 << 6))
+
/*
* PHY-Specific MII control/status registers.
@@ -452,21 +515,21 @@ typedef enum {
((config) |= (((val) & 0x0f) << 28))
/* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
netxen_niu_prom_mode_t mode);
int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
- int port, netxen_niu_prom_mode_t mode);
+ netxen_niu_prom_mode_t mode);
/* get/set the MAC address for a given MAC */
-int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr);
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr);
/* XG versons */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int port,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr);
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr);
/* Generic enable for GbE ports. Will detect the speed of the link. */
@@ -475,8 +538,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port);
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port);
/* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter);
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port);
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter);
#endif /* __NETXEN_NIC_HW_H_ */
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 5cd40562da7..cf0e96adfe4 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -139,7 +139,7 @@ int netxen_init_firmware(struct netxen_adapter *adapter)
return err;
}
/* Window 1 call */
- writel(MPORT_SINGLE_FUNCTION_MODE,
+ writel(MPORT_MULTI_FUNCTION_MODE,
NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE));
writel(PHAN_INITIALIZE_ACK,
NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
@@ -226,7 +226,6 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
adapter->unset_promisc = netxen_niu_set_promiscuous_mode;
adapter->phy_read = netxen_niu_gbe_phy_read;
adapter->phy_write = netxen_niu_gbe_phy_write;
- adapter->init_port = netxen_niu_gbe_init_port;
adapter->init_niu = netxen_nic_init_niu_gb;
adapter->stop_port = netxen_niu_disable_gbe_port;
break;
@@ -277,8 +276,8 @@ u32 netxen_decode_crb_addr(u32 addr)
return (pci_base + offset);
}
-static long rom_max_timeout = 10000;
-static long rom_lock_timeout = 1000000;
+static long rom_max_timeout = 100;
+static long rom_lock_timeout = 10000;
static long rom_write_timeout = 700;
static inline int rom_lock(struct netxen_adapter *adapter)
@@ -438,9 +437,9 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
for (addridx = addr; addridx < (addr + size); addridx += 4) {
ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
- *(int *)bytes = cpu_to_le32(*(int *)bytes);
if (ret != 0)
break;
+ *(int *)bytes = cpu_to_le32(*(int *)bytes);
bytes += 4;
}
@@ -499,7 +498,6 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter,
int data;
data = le32_to_cpu((*(u32*)bytes));
-
ret = do_rom_fast_write(adapter, addridx, data);
if (ret < 0)
return ret;
@@ -953,7 +951,8 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
if (!pegtune_val) {
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
+ while (val != PHAN_INITIALIZE_COMPLETE &&
+ val != PHAN_INITIALIZE_ACK && loops < 200000) {
udelay(100);
schedule();
val =
@@ -990,9 +989,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter)
static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
{
- int port_num;
- struct netxen_port *port;
- struct net_device *netdev;
+ struct net_device *netdev = adapter->netdev;
uint32_t temp, temp_state, temp_val;
int rv = 0;
@@ -1006,14 +1003,9 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
"%s: Device temperature %d degrees C exceeds"
" maximum allowed. Hardware has been shut down.\n",
netxen_nic_driver_name, temp_val);
- for (port_num = 0; port_num < adapter->ahw.max_ports;
- port_num++) {
- port = adapter->port[port_num];
- netdev = port->netdev;
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- }
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
rv = 1;
} else if (temp_state == NX_TEMP_WARN) {
if (adapter->temp == NX_TEMP_NORMAL) {
@@ -1037,29 +1029,23 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter)
void netxen_watchdog_task(struct work_struct *work)
{
- int port_num;
- struct netxen_port *port;
struct net_device *netdev;
struct netxen_adapter *adapter =
container_of(work, struct netxen_adapter, watchdog_task);
- if (netxen_nic_check_temp(adapter))
+ if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter))
return;
- for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
- port = adapter->port[port_num];
- netdev = port->netdev;
-
- if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
- printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
- netxen_nic_driver_name, port_num, netdev->name);
- netif_carrier_on(netdev);
- }
-
- if (netif_queue_stopped(netdev))
- netif_wake_queue(netdev);
+ netdev = adapter->netdev;
+ if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) {
+ printk(KERN_INFO "%s port %d, %s carrier is now ok\n",
+ netxen_nic_driver_name, adapter->portnum, netdev->name);
+ netif_carrier_on(netdev);
}
+ if (netif_queue_stopped(netdev))
+ netif_wake_queue(netdev);
+
if (adapter->handle_phy_intr)
adapter->handle_phy_intr(adapter);
mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
@@ -1074,9 +1060,8 @@ void
netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
struct status_desc *desc)
{
- struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)];
- struct pci_dev *pdev = port->pdev;
- struct net_device *netdev = port->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+ struct net_device *netdev = adapter->netdev;
int index = netxen_get_sts_refhandle(desc);
struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
struct netxen_rx_buffer *buffer;
@@ -1126,7 +1111,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
skb = (struct sk_buff *)buffer->skb;
if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
- port->stats.csummed++;
+ adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
if (desc_ctx == RCV_DESC_LRO_CTXID) {
@@ -1146,27 +1131,27 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
*/
switch (ret) {
case NET_RX_SUCCESS:
- port->stats.uphappy++;
+ adapter->stats.uphappy++;
break;
case NET_RX_CN_LOW:
- port->stats.uplcong++;
+ adapter->stats.uplcong++;
break;
case NET_RX_CN_MOD:
- port->stats.upmcong++;
+ adapter->stats.upmcong++;
break;
case NET_RX_CN_HIGH:
- port->stats.uphcong++;
+ adapter->stats.uphcong++;
break;
case NET_RX_DROP:
- port->stats.updropped++;
+ adapter->stats.updropped++;
break;
default:
- port->stats.updunno++;
+ adapter->stats.updunno++;
break;
}
@@ -1178,14 +1163,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
/*
* We just consumed one buffer so post a buffer.
*/
- adapter->stats.post_called++;
buffer->skb = NULL;
buffer->state = NETXEN_BUFFER_FREE;
buffer->lro_current_frags = 0;
buffer->lro_expected_frags = 0;
- port->stats.no_rcv++;
- port->stats.rxbytes += length;
+ adapter->stats.no_rcv++;
+ adapter->stats.rxbytes += length;
}
/* Process Receive status ring */
@@ -1226,7 +1210,6 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max)
/* update the consumer index in phantom */
if (count) {
- adapter->stats.process_rcv++;
recv_ctx->status_rx_consumer = consumer;
recv_ctx->status_rx_producer = producer;
@@ -1249,13 +1232,10 @@ int netxen_process_cmd_ring(unsigned long data)
int count1 = 0;
int count2 = 0;
struct netxen_cmd_buffer *buffer;
- struct netxen_port *port; /* port #1 */
- struct netxen_port *nport;
struct pci_dev *pdev;
struct netxen_skb_frag *frag;
u32 i;
struct sk_buff *skb = NULL;
- int p;
int done;
spin_lock(&adapter->tx_lock);
@@ -1276,7 +1256,6 @@ int netxen_process_cmd_ring(unsigned long data)
}
adapter->proc_cmd_buf_counter++;
- adapter->stats.process_xmit++;
/*
* Not needed - does not seem to be used anywhere.
* adapter->cmd_consumer = consumer;
@@ -1285,8 +1264,7 @@ int netxen_process_cmd_ring(unsigned long data)
while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) {
buffer = &adapter->cmd_buf_arr[last_consumer];
- port = adapter->port[buffer->port];
- pdev = port->pdev;
+ pdev = adapter->pdev;
frag = &buffer->frag_array[0];
skb = buffer->skb;
if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) {
@@ -1299,24 +1277,23 @@ int netxen_process_cmd_ring(unsigned long data)
PCI_DMA_TODEVICE);
}
- port->stats.skbfreed++;
+ adapter->stats.skbfreed++;
dev_kfree_skb_any(skb);
skb = NULL;
} else if (adapter->proc_cmd_buf_counter == 1) {
- port->stats.txnullskb++;
+ adapter->stats.txnullskb++;
}
- if (unlikely(netif_queue_stopped(port->netdev)
- && netif_carrier_ok(port->netdev))
- && ((jiffies - port->netdev->trans_start) >
- port->netdev->watchdog_timeo)) {
- SCHEDULE_WORK(&port->tx_timeout_task);
+ if (unlikely(netif_queue_stopped(adapter->netdev)
+ && netif_carrier_ok(adapter->netdev))
+ && ((jiffies - adapter->netdev->trans_start) >
+ adapter->netdev->watchdog_timeo)) {
+ SCHEDULE_WORK(&adapter->tx_timeout_task);
}
last_consumer = get_next_index(last_consumer,
adapter->max_tx_desc_count);
count1++;
}
- adapter->stats.noxmitdone += count1;
count2 = 0;
spin_lock(&adapter->tx_lock);
@@ -1336,13 +1313,10 @@ int netxen_process_cmd_ring(unsigned long data)
}
}
if (count1 || count2) {
- for (p = 0; p < adapter->ahw.max_ports; p++) {
- nport = adapter->port[p];
- if (netif_queue_stopped(nport->netdev)
- && (nport->flags & NETXEN_NETDEV_STATUS)) {
- netif_wake_queue(nport->netdev);
- nport->flags &= ~NETXEN_NETDEV_STATUS;
- }
+ if (netif_queue_stopped(adapter->netdev)
+ && (adapter->flags & NETXEN_NETDEV_STATUS)) {
+ netif_wake_queue(adapter->netdev);
+ adapter->flags &= ~NETXEN_NETDEV_STATUS;
}
}
/*
@@ -1388,7 +1362,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
netxen_ctx_msg msg = 0;
dma_addr_t dma;
- adapter->stats.post_called++;
rcv_desc = &recv_ctx->rcv_desc[ringid];
producer = rcv_desc->producer;
@@ -1441,8 +1414,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
if (count) {
rcv_desc->begin_alloc = index;
rcv_desc->rcv_pending += count;
- adapter->stats.lastposted = count;
- adapter->stats.posted += count;
rcv_desc->producer = producer;
if (rcv_desc->rcv_free >= 32) {
rcv_desc->rcv_free = 0;
@@ -1450,7 +1421,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
writel((producer - 1) &
(rcv_desc->max_rx_desc_count - 1),
NETXEN_CRB_NORMALIZE(adapter,
- recv_crb_registers[0].
+ recv_crb_registers[
+ adapter->portnum].
rcv_desc_crb[ringid].
crb_rcv_producer_offset));
/*
@@ -1463,7 +1435,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
((producer -
1) & (rcv_desc->
max_rx_desc_count - 1)));
- netxen_set_msg_ctxid(msg, 0);
+ netxen_set_msg_ctxid(msg, adapter->portnum);
netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
writel(msg,
DB_NORMALIZE(adapter,
@@ -1485,7 +1457,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
int count = 0;
int index = 0;
- adapter->stats.post_called++;
rcv_desc = &recv_ctx->rcv_desc[ringid];
producer = rcv_desc->producer;
@@ -1532,8 +1503,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
if (count) {
rcv_desc->begin_alloc = index;
rcv_desc->rcv_pending += count;
- adapter->stats.lastposted = count;
- adapter->stats.posted += count;
rcv_desc->producer = producer;
if (rcv_desc->rcv_free >= 32) {
rcv_desc->rcv_free = 0;
@@ -1541,7 +1510,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx,
writel((producer - 1) &
(rcv_desc->max_rx_desc_count - 1),
NETXEN_CRB_NORMALIZE(adapter,
- recv_crb_registers[0].
+ recv_crb_registers[
+ adapter->portnum].
rcv_desc_crb[ringid].
crb_rcv_producer_offset));
wmb();
@@ -1562,13 +1532,7 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter)
void netxen_nic_clear_stats(struct netxen_adapter *adapter)
{
- struct netxen_port *port;
- int port_num;
-
memset(&adapter->stats, 0, sizeof(adapter->stats));
- for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) {
- port = adapter->port[port_num];
- memset(&port->stats, 0, sizeof(port->stats));
- }
+ return;
}
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c
index be366e48007..b213b062eb5 100644
--- a/drivers/net/netxen/netxen_nic_isr.c
+++ b/drivers/net/netxen/netxen_nic_isr.c
@@ -6,12 +6,12 @@
* 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., 59 Temple Place - Suite 330, Boston,
@@ -40,35 +40,35 @@
*/
struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct net_device_stats *stats = &port->net_stats;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
+ struct net_device_stats *stats = &adapter->net_stats;
memset(stats, 0, sizeof(*stats));
/* total packets received */
- stats->rx_packets = port->stats.no_rcv;
+ stats->rx_packets = adapter->stats.no_rcv;
/* total packets transmitted */
- stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished;
+ stats->tx_packets = adapter->stats.xmitedframes +
+ adapter->stats.xmitfinished;
/* total bytes received */
- stats->rx_bytes = port->stats.rxbytes;
+ stats->rx_bytes = adapter->stats.rxbytes;
/* total bytes transmitted */
- stats->tx_bytes = port->stats.txbytes;
+ stats->tx_bytes = adapter->stats.txbytes;
/* bad packets received */
- stats->rx_errors = port->stats.rcvdbadskb;
+ stats->rx_errors = adapter->stats.rcvdbadskb;
/* packet transmit problems */
- stats->tx_errors = port->stats.nocmddescriptor;
+ stats->tx_errors = adapter->stats.nocmddescriptor;
/* no space in linux buffers */
- stats->rx_dropped = port->stats.updropped;
+ stats->rx_dropped = adapter->stats.updropped;
/* no space available in linux */
- stats->tx_dropped = port->stats.txdropped;
+ stats->tx_dropped = adapter->stats.txdropped;
return stats;
}
-void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
- u32 link)
+void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link)
{
- struct net_device *netdev = (adapter->port[portno])->netdev;
+ struct net_device *netdev = adapter->netdev;
if (link)
netif_carrier_on(netdev);
@@ -76,15 +76,13 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno,
netif_carrier_off(netdev);
}
-void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
- u32 enable)
+void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable)
{
__u32 int_src;
- struct netxen_port *port;
/* This should clear the interrupt source */
if (adapter->phy_read)
- adapter->phy_read(adapter, portno,
+ adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
&int_src);
if (int_src == 0) {
@@ -92,9 +90,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
return;
}
if (adapter->disable_phy_interrupts)
- adapter->disable_phy_interrupts(adapter, portno);
-
- port = adapter->port[portno];
+ adapter->disable_phy_interrupts(adapter);
if (netxen_get_phy_int_jabber(int_src))
DPRINTK(INFO, "Jabber interrupt \n");
@@ -115,64 +111,57 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno,
DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n");
if (adapter->phy_read
- && adapter->phy_read(adapter, portno,
+ && adapter->phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) == 0) {
if (netxen_get_phy_int_link_status_changed(int_src)) {
if (netxen_get_phy_link(status)) {
- netxen_niu_gbe_init_port(adapter,
- portno);
- printk("%s: %s Link UP\n",
+ printk(KERN_INFO "%s: %s Link UP\n",
netxen_nic_driver_name,
- port->netdev->name);
+ adapter->netdev->name);
} else {
- printk("%s: %s Link DOWN\n",
+ printk(KERN_INFO "%s: %s Link DOWN\n",
netxen_nic_driver_name,
- port->netdev->name);
+ adapter->netdev->name);
}
- netxen_indicate_link_status(adapter, portno,
+ netxen_indicate_link_status(adapter,
netxen_get_phy_link
(status));
}
}
}
if (adapter->enable_phy_interrupts)
- adapter->enable_phy_interrupts(adapter, portno);
+ adapter->enable_phy_interrupts(adapter);
}
void netxen_nic_isr_other(struct netxen_adapter *adapter)
{
- u32 portno;
+ int portno = adapter->portnum;
u32 val, linkup, qg_linksup;
/* verify the offset */
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+ val = val >> physical_port[adapter->portnum];
if (val == adapter->ahw.qg_linksup)
return;
qg_linksup = adapter->ahw.qg_linksup;
adapter->ahw.qg_linksup = val;
DPRINTK(INFO, "link update 0x%08x\n", val);
- for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) {
- linkup = val & 1;
- if (linkup != (qg_linksup & 1)) {
- printk(KERN_INFO "%s: %s PORT %d link %s\n",
- adapter->port[portno]->netdev->name,
- netxen_nic_driver_name, portno,
- ((linkup == 0) ? "down" : "up"));
- netxen_indicate_link_status(adapter, portno, linkup);
- if (linkup)
- netxen_nic_set_link_parameters(adapter->
- port[portno]);
- }
- val = val >> 1;
- qg_linksup = qg_linksup >> 1;
- }
+ linkup = val & 1;
- adapter->stats.otherints++;
+ if (linkup != (qg_linksup & 1)) {
+ printk(KERN_INFO "%s: %s PORT %d link %s\n",
+ adapter->netdev->name,
+ netxen_nic_driver_name, portno,
+ ((linkup == 0) ? "down" : "up"));
+ netxen_indicate_link_status(adapter, linkup);
+ if (linkup)
+ netxen_nic_set_link_parameters(adapter);
+ }
}
void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
@@ -182,26 +171,28 @@ void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter)
void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter)
{
- struct net_device *netdev = adapter->port[0]->netdev;
- u32 val;
+ struct net_device *netdev = adapter->netdev;
+ u32 val, val1;
/* WINDOW = 1 */
val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE));
+ val >>= (physical_port[adapter->portnum] * 8);
+ val1 = val & 0xff;
- if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) {
+ if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) {
printk(KERN_INFO "%s: %s NIC Link is down\n",
netxen_nic_driver_name, netdev->name);
adapter->ahw.xg_linkup = 0;
/* read twice to clear sticky bits */
/* WINDOW = 0 */
- netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
- netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val);
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
+ netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1);
if ((val & 0xffb) != 0xffb) {
printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n",
- netxen_nic_driver_name, val);
+ netxen_nic_driver_name, val1);
}
- } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) {
+ } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) {
printk(KERN_INFO "%s: %s NIC Link is up\n",
netxen_nic_driver_name, netdev->name);
adapter->ahw.xg_linkup = 1;
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index ab25c225a07..4e32bb678ea 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -36,7 +36,6 @@
#include "netxen_nic_hw.h"
#include "netxen_nic.h"
-#define DEFINE_GLOBAL_RECV_CRB
#include "netxen_nic_phan_reg.h"
#include <linux/dma-mapping.h>
@@ -77,6 +76,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev);
#endif
static irqreturn_t netxen_intr(int irq, void *data);
+int physical_port[] = {0, 1, 2, 3};
+
/* PCI Device ID Table */
static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
{PCI_DEVICE(0x4040, 0x0001)},
@@ -94,6 +95,67 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
struct workqueue_struct *netxen_workq;
static void netxen_watchdog(unsigned long);
+static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
+ uint32_t crb_producer)
+{
+ switch (adapter->portnum) {
+ case 0:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET));
+ return;
+ case 1:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET_1));
+ return;
+ case 2:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET_2));
+ return;
+ case 3:
+ writel(crb_producer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET_3));
+ return;
+ default:
+ printk(KERN_WARNING "We tried to update "
+ "CRB_CMD_PRODUCER_OFFSET for invalid "
+ "PCI function id %d\n",
+ adapter->portnum);
+ return;
+ }
+}
+
+static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
+ u32 crb_consumer)
+{
+ switch (adapter->portnum) {
+ case 0:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET));
+ return;
+ case 1:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET_1));
+ return;
+ case 2:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET_2));
+ return;
+ case 3:
+ writel(crb_consumer, NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_CONSUMER_OFFSET_3));
+ return;
+ default:
+ printk(KERN_WARNING "We tried to update "
+ "CRB_CMD_PRODUCER_OFFSET for invalid "
+ "PCI function id %d\n",
+ adapter->portnum);
+ return;
+ }
+}
+
+#define ADAPTER_LIST_SIZE 12
+int netxen_cards_found;
+
/*
* netxen_nic_probe()
*
@@ -111,26 +173,30 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct net_device *netdev = NULL;
struct netxen_adapter *adapter = NULL;
- struct netxen_port *port = NULL;
void __iomem *mem_ptr0 = NULL;
void __iomem *mem_ptr1 = NULL;
void __iomem *mem_ptr2 = NULL;
+ unsigned long first_page_group_end;
+ unsigned long first_page_group_start;
+
u8 __iomem *db_ptr = NULL;
unsigned long mem_base, mem_len, db_base, db_len;
- int pci_using_dac, i, err;
+ int pci_using_dac, i = 0, err;
int ring;
struct netxen_recv_context *recv_ctx = NULL;
struct netxen_rcv_desc_ctx *rcv_desc = NULL;
struct netxen_cmd_buffer *cmd_buf_arr = NULL;
u64 mac_addr[FLASH_NUM_PORTS + 1];
int valid_mac = 0;
+ u32 val;
+ int pci_func_id = PCI_FUNC(pdev->devfn);
printk(KERN_INFO "%s \n", netxen_nic_driver_string);
- /* In current scheme, we use only PCI function 0 */
- if (PCI_FUNC(pdev->devfn) != 0) {
- DPRINTK(ERR, "NetXen function %d will not be enabled.\n",
- PCI_FUNC(pdev->devfn));
+
+ if (pdev->class != 0x020000) {
+ printk(KERN_ERR"NetXen function %d, class %x will not"
+ "be enabled.\n",pci_func_id, pdev->class);
return -ENODEV;
}
if ((err = pci_enable_device(pdev)))
@@ -157,18 +223,52 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_using_dac = 0;
}
+
+ netdev = alloc_etherdev(sizeof(struct netxen_adapter));
+ if(!netdev) {
+ printk(KERN_ERR"%s: Failed to allocate memory for the "
+ "device block.Check system memory resource"
+ " usage.\n", netxen_nic_driver_name);
+ goto err_out_free_res;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+
+ adapter = netdev->priv;
+ memset(adapter, 0 , sizeof(struct netxen_adapter));
+
+ adapter->ahw.pdev = pdev;
+ adapter->ahw.pci_func = pci_func_id;
+ spin_lock_init(&adapter->tx_lock);
+ spin_lock_init(&adapter->lock);
+
/* remap phys address */
mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
mem_len = pci_resource_len(pdev, 0);
/* 128 Meg of memory */
- mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
- mem_ptr1 =
- ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE);
- mem_ptr2 =
- ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+ if (mem_len == NETXEN_PCI_128MB_SIZE) {
+ mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE);
+ mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START,
+ SECOND_PAGE_GROUP_SIZE);
+ mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
+ THIRD_PAGE_GROUP_SIZE);
+ first_page_group_start = FIRST_PAGE_GROUP_START;
+ first_page_group_end = FIRST_PAGE_GROUP_END;
+ } else if (mem_len == NETXEN_PCI_32MB_SIZE) {
+ mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
+ mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
+ SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
+ first_page_group_start = 0;
+ first_page_group_end = 0;
+ } else {
+ err = -EIO;
+ goto err_out_free_netdev;
+ }
- if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
+ if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||
+ (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
DPRINTK(ERR,
"Cannot remap adapter memory aborting.:"
"0 -> %p, 1 -> %p, 2 -> %p\n",
@@ -198,30 +298,87 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);
-/*
- * Allocate a adapter structure which will manage all the initialization
- * as well as the common resources for all ports...
- * all the ports will have pointer to this adapter as well as Adapter
- * will have pointers of all the ports structures.
- */
+ adapter->ahw.pci_base0 = mem_ptr0;
+ adapter->ahw.first_page_group_start = first_page_group_start;
+ adapter->ahw.first_page_group_end = first_page_group_end;
+ adapter->ahw.pci_base1 = mem_ptr1;
+ adapter->ahw.pci_base2 = mem_ptr2;
+ adapter->ahw.db_base = db_ptr;
+ adapter->ahw.db_len = db_len;
- /* One adapter structure for all 4 ports.... */
- adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL);
- if (adapter == NULL) {
- printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n",
- netxen_nic_driver_name,
- (int)sizeof(struct netxen_adapter));
- err = -ENOMEM;
- goto err_out_dbunmap;
- }
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+ adapter->portnum = pci_func_id;
+
+ netdev->open = netxen_nic_open;
+ netdev->stop = netxen_nic_close;
+ netdev->hard_start_xmit = netxen_nic_xmit_frame;
+ netdev->get_stats = netxen_nic_get_stats;
+ netdev->set_multicast_list = netxen_nic_set_multi;
+ netdev->set_mac_address = netxen_nic_set_mac;
+ netdev->change_mtu = netxen_nic_change_mtu;
+ netdev->tx_timeout = netxen_tx_timeout;
+ netdev->watchdog_timeo = HZ;
+
+ netxen_nic_change_mtu(netdev, netdev->mtu);
+
+ SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+ netdev->poll = netxen_nic_poll;
+ netdev->weight = NETXEN_NETDEV_WEIGHT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = netxen_nic_poll_controller;
+#endif
+ /* ScatterGather support */
+ netdev->features = NETIF_F_SG;
+ netdev->features |= NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_TSO;
+
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ if (pci_enable_msi(pdev)) {
+ adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
+ printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
+ " error\n", netxen_nic_driver_name);
+ } else
+ adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+
+ netdev->irq = pdev->irq;
+ INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
- adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS;
- adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
+ /*
+ * Set the CRB window to invalid. If any register in window 0 is
+ * accessed it should set the window to 0 and then reset it to 1.
+ */
+ adapter->curr_window = 255;
+
+ /* initialize the adapter */
+ netxen_initialize_adapter_hw(adapter);
+
+#ifdef CONFIG_PPC
+ if ((adapter->ahw.boardcfg.board_type ==
+ NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) &&
+ (pci_func_id == 2))
+ goto err_out_free_adapter;
+#endif /* CONFIG_PPC */
+
+ /*
+ * Adapter in our case is quad port so initialize it before
+ * initializing the ports
+ */
+
+ netxen_initialize_adapter_ops(adapter);
+
+ adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
+ if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) ||
+ (adapter->ahw.boardcfg.board_type ==
+ NETXEN_BRDTYPE_P2_SB31_2G))
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
+ else
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS;
- pci_set_drvdata(pdev, adapter);
-
cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE);
if (cmd_buf_arr == NULL) {
printk(KERN_ERR
@@ -231,6 +388,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_adapter;
}
memset(cmd_buf_arr, 0, TX_RINGSIZE);
+ adapter->cmd_buf_arr = cmd_buf_arr;
for (i = 0; i < MAX_RCV_CTX; ++i) {
recv_ctx = &adapter->recv_ctx[i];
@@ -278,33 +436,20 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
- adapter->cmd_buf_arr = cmd_buf_arr;
- adapter->ahw.pci_base0 = mem_ptr0;
- adapter->ahw.pci_base1 = mem_ptr1;
- adapter->ahw.pci_base2 = mem_ptr2;
- adapter->ahw.db_base = db_ptr;
- adapter->ahw.db_len = db_len;
- spin_lock_init(&adapter->tx_lock);
- spin_lock_init(&adapter->lock);
netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */
-#ifdef CONFIG_IA64
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
-#endif
- /*
- * Set the CRB window to invalid. If any register in window 0 is
- * accessed it should set the window to 0 and then reset it to 1.
- */
- adapter->curr_window = 255;
- /*
- * Adapter in our case is quad port so initialize it before
- * initializing the ports
- */
- netxen_initialize_adapter_hw(adapter); /* initialize the adapter */
+ /* Mezz cards have PCI function 0,2,3 enabled */
+ if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ)
+ && (pci_func_id >= 2))
+ adapter->portnum = pci_func_id - 2;
- netxen_initialize_adapter_ops(adapter);
+#ifdef CONFIG_IA64
+ if(adapter->portnum == 0) {
+ netxen_pinit_from_rom(adapter, 0);
+ udelay(500);
+ netxen_load_firmware(adapter);
+ }
+#endif
init_timer(&adapter->watchdog_timer);
adapter->ahw.xg_linkup = 0;
@@ -315,12 +460,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->proc_cmd_buf_counter = 0;
adapter->ahw.revision_id = nx_p2_id;
- if (pci_enable_msi(pdev)) {
- adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
- printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
- " error\n", netxen_nic_driver_name);
- } else
- adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+ /* make sure Window == 1 */
+ netxen_nic_pci_change_crbwindow(adapter, 1);
+
+ netxen_nic_update_cmd_producer(adapter, 0);
+ netxen_nic_update_cmd_consumer(adapter, 0);
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
if (netxen_is_flash_supported(adapter) == 0 &&
netxen_get_flash_mac_addr(adapter, mac_addr) == 0)
@@ -328,153 +473,118 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
else
valid_mac = 0;
- /*
- * Initialize all the CRB registers here.
- */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET));
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
-
- /* do this before waking up pegs so that we have valid dummy dma addr */
- err = netxen_initialize_adapter_offload(adapter);
- if (err) {
- goto err_out_free_dev;
+ if (valid_mac) {
+ unsigned char *p = (unsigned char *)&mac_addr[adapter->portnum];
+ netdev->dev_addr[0] = *(p + 5);
+ netdev->dev_addr[1] = *(p + 4);
+ netdev->dev_addr[2] = *(p + 3);
+ netdev->dev_addr[3] = *(p + 2);
+ netdev->dev_addr[4] = *(p + 1);
+ netdev->dev_addr[5] = *(p + 0);
+
+ memcpy(netdev->perm_addr, netdev->dev_addr,
+ netdev->addr_len);
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ printk(KERN_ERR "%s: Bad MAC address "
+ "%02x:%02x:%02x:%02x:%02x:%02x.\n",
+ netxen_nic_driver_name,
+ netdev->dev_addr[0],
+ netdev->dev_addr[1],
+ netdev->dev_addr[2],
+ netdev->dev_addr[3],
+ netdev->dev_addr[4],
+ netdev->dev_addr[5]);
+ } else {
+ if (adapter->macaddr_set)
+ adapter->macaddr_set(adapter,
+ netdev->dev_addr);
+ }
}
- /* Unlock the HW, prompting the boot sequence */
- writel(1,
- NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
-
- /* Handshake with the card before we register the devices. */
- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-
- /* initialize the all the ports */
- adapter->active_ports = 0;
-
- for (i = 0; i < adapter->ahw.max_ports; i++) {
- netdev = alloc_etherdev(sizeof(struct netxen_port));
- if (!netdev) {
- printk(KERN_ERR "%s: could not allocate netdev for port"
- " %d\n", netxen_nic_driver_name, i + 1);
+ if (adapter->portnum == 0) {
+ err = netxen_initialize_adapter_offload(adapter);
+ if (err)
+ goto err_out_free_rx_buffer;
+ val = readl(NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_CAM_RAM(0x1fc)));
+ if (val == 0x55555555) {
+ /* This is the first boot after power up */
+ val = readl(NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_ROMUSB_GLB_SW_RESET));
+ printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val);
+ if (val != 0x80000f) {
+ /* clear the register for future unloads/loads */
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_CAM_RAM(0x1fc)));
+ printk(KERN_ERR "ERROR in NetXen HW init sequence.\n");
+ err = -ENODEV;
goto err_out_free_dev;
- }
+ }
- SET_MODULE_OWNER(netdev);
- SET_NETDEV_DEV(netdev, &pdev->dev);
-
- port = netdev_priv(netdev);
- port->netdev = netdev;
- port->pdev = pdev;
- port->adapter = adapter;
- port->portnum = i; /* Gigabit port number from 0-3 */
-
- netdev->open = netxen_nic_open;
- netdev->stop = netxen_nic_close;
- netdev->hard_start_xmit = netxen_nic_xmit_frame;
- netdev->get_stats = netxen_nic_get_stats;
- netdev->set_multicast_list = netxen_nic_set_multi;
- netdev->set_mac_address = netxen_nic_set_mac;
- netdev->change_mtu = netxen_nic_change_mtu;
- netdev->tx_timeout = netxen_tx_timeout;
- netdev->watchdog_timeo = HZ;
-
- netxen_nic_change_mtu(netdev, netdev->mtu);
-
- SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
- netdev->poll = netxen_nic_poll;
- netdev->weight = NETXEN_NETDEV_WEIGHT;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- netdev->poll_controller = netxen_nic_poll_controller;
-#endif
- /* ScatterGather support */
- netdev->features = NETIF_F_SG;
- netdev->features |= NETIF_F_IP_CSUM;
- netdev->features |= NETIF_F_TSO;
-
- if (pci_using_dac)
- netdev->features |= NETIF_F_HIGHDMA;
-
- if (valid_mac) {
- unsigned char *p = (unsigned char *)&mac_addr[i];
- netdev->dev_addr[0] = *(p + 5);
- netdev->dev_addr[1] = *(p + 4);
- netdev->dev_addr[2] = *(p + 3);
- netdev->dev_addr[3] = *(p + 2);
- netdev->dev_addr[4] = *(p + 1);
- netdev->dev_addr[5] = *(p + 0);
-
- memcpy(netdev->perm_addr, netdev->dev_addr,
- netdev->addr_len);
- if (!is_valid_ether_addr(netdev->perm_addr)) {
- printk(KERN_ERR "%s: Bad MAC address "
- "%02x:%02x:%02x:%02x:%02x:%02x.\n",
- netxen_nic_driver_name,
- netdev->dev_addr[0],
- netdev->dev_addr[1],
- netdev->dev_addr[2],
- netdev->dev_addr[3],
- netdev->dev_addr[4],
- netdev->dev_addr[5]);
- } else {
- if (adapter->macaddr_set)
- adapter->macaddr_set(port,
- netdev->dev_addr);
- }
+ /* clear the register for future unloads/loads */
+ writel(0, NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_CAM_RAM(0x1fc)));
}
- INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task);
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
+ printk(KERN_INFO "State: 0x%0x\n",
+ readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
- if ((err = register_netdev(netdev))) {
- printk(KERN_ERR "%s: register_netdev failed port #%d"
- " aborting\n", netxen_nic_driver_name, i + 1);
- err = -EIO;
- free_netdev(netdev);
- goto err_out_free_dev;
- }
- adapter->port_count++;
- adapter->port[i] = port;
+ /*
+ * Tell the hardware our version number.
+ */
+ i = (_NETXEN_NIC_LINUX_MAJOR << 16)
+ | ((_NETXEN_NIC_LINUX_MINOR << 8))
+ | (_NETXEN_NIC_LINUX_SUBVERSION);
+ writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION));
+
+ /* Unlock the HW, prompting the boot sequence */
+ writel(1,
+ NETXEN_CRB_NORMALIZE(adapter,
+ NETXEN_ROMUSB_GLB_PEGTUNE_DONE));
+ /* Handshake with the card before we register the devices. */
+ netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
}
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
- netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+
/*
- * delay a while to ensure that the Pegs are up & running.
- * Otherwise, we might see some flaky behaviour.
+ * See if the firmware gave us a virtual-physical port mapping.
*/
- udelay(100);
+ i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum)));
+ if (i != 0x55555555)
+ physical_port[adapter->portnum] = i;
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ if ((err = register_netdev(netdev))) {
+ printk(KERN_ERR "%s: register_netdev failed port #%d"
+ " aborting\n", netxen_nic_driver_name,
+ adapter->portnum);
+ err = -EIO;
+ goto err_out_free_dev;
+ }
+
+ pci_set_drvdata(pdev, adapter);
switch (adapter->ahw.board_type) {
- case NETXEN_NIC_GBE:
- printk("%s: QUAD GbE board initialized\n",
- netxen_nic_driver_name);
- break;
+ case NETXEN_NIC_GBE:
+ printk(KERN_INFO "%s: QUAD GbE board initialized\n",
+ netxen_nic_driver_name);
+ break;
- case NETXEN_NIC_XGBE:
- printk("%s: XGbE board initialized\n", netxen_nic_driver_name);
- break;
+ case NETXEN_NIC_XGBE:
+ printk(KERN_INFO "%s: XGbE board initialized\n",
+ netxen_nic_driver_name);
+ break;
}
adapter->driver_mismatch = 0;
return 0;
- err_out_free_dev:
- if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
- pci_disable_msi(pdev);
- for (i = 0; i < adapter->port_count; i++) {
- port = adapter->port[i];
- if ((port) && (port->netdev)) {
- unregister_netdev(port->netdev);
- free_netdev(port->netdev);
- }
- }
+err_out_free_dev:
+ if (adapter->portnum == 0)
+ netxen_free_adapter_offload(adapter);
- netxen_free_adapter_offload(adapter);
-
- err_out_free_rx_buffer:
+err_out_free_rx_buffer:
for (i = 0; i < MAX_RCV_CTX; ++i) {
recv_ctx = &adapter->recv_ctx[i];
for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
@@ -487,15 +597,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
vfree(cmd_buf_arr);
- err_out_free_adapter:
+err_out_free_adapter:
+ if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+ pci_disable_msi(pdev);
+
pci_set_drvdata(pdev, NULL);
- kfree(adapter);
- err_out_dbunmap:
if (db_ptr)
iounmap(db_ptr);
- err_out_iounmap:
+err_out_iounmap:
if (mem_ptr0)
iounmap(mem_ptr0);
if (mem_ptr1)
@@ -503,9 +614,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (mem_ptr2)
iounmap(mem_ptr2);
- err_out_free_res:
+err_out_free_netdev:
+ free_netdev(netdev);
+
+err_out_free_res:
pci_release_regions(pdev);
- err_out_disable_pdev:
+
+err_out_disable_pdev:
pci_disable_device(pdev);
return err;
}
@@ -513,7 +628,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
static void __devexit netxen_nic_remove(struct pci_dev *pdev)
{
struct netxen_adapter *adapter;
- struct netxen_port *port;
+ struct net_device *netdev;
struct netxen_rx_buffer *buffer;
struct netxen_recv_context *recv_ctx;
struct netxen_rcv_desc_ctx *rcv_desc;
@@ -524,38 +639,34 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
if (adapter == NULL)
return;
+ netdev = adapter->netdev;
+
+ netxen_nic_disable_int(adapter);
if (adapter->irq)
free_irq(adapter->irq, adapter);
- netxen_nic_stop_all_ports(adapter);
- /* leave the hw in the same state as reboot */
- writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
- netxen_pinit_from_rom(adapter, 0);
- udelay(500);
- netxen_load_firmware(adapter);
- netxen_free_adapter_offload(adapter);
-
- mdelay(1000); /* Delay for a while to drain the DMA engines */
- for (i = 0; i < adapter->port_count; i++) {
- port = adapter->port[i];
- if ((port) && (port->netdev)) {
- unregister_netdev(port->netdev);
- free_netdev(port->netdev);
- }
- }
+
+ if (adapter->stop_port)
+ adapter->stop_port(adapter);
if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
pci_disable_msi(pdev);
- if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
- netxen_free_hw_resources(adapter);
- iounmap(adapter->ahw.db_base);
- iounmap(adapter->ahw.pci_base0);
- iounmap(adapter->ahw.pci_base1);
- iounmap(adapter->ahw.pci_base2);
+ if (adapter->portnum == 0)
+ netxen_free_adapter_offload(adapter);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- pci_set_drvdata(pdev, NULL);
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
+ if(adapter->portnum == 0) {
+ /* leave the hw in the same state as reboot */
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
+ netxen_pinit_from_rom(adapter, 0);
+ udelay(500);
+ netxen_load_firmware(adapter);
+ netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+ }
+
+ if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+ netxen_free_hw_resources(adapter);
for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
recv_ctx = &adapter->recv_ctx[ctxid];
@@ -575,8 +686,20 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
}
}
+ unregister_netdev(netdev);
+
vfree(adapter->cmd_buf_arr);
- kfree(adapter);
+
+ iounmap(adapter->ahw.db_base);
+ iounmap(adapter->ahw.pci_base0);
+ iounmap(adapter->ahw.pci_base1);
+ iounmap(adapter->ahw.pci_base2);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+
+ free_netdev(netdev);
}
/*
@@ -585,8 +708,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
*/
static int netxen_nic_open(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv;
int err = 0;
int ctx, ring;
@@ -597,8 +719,6 @@ static int netxen_nic_open(struct net_device *netdev)
return -EIO;
}
netxen_nic_flash_print(adapter);
- if (adapter->init_niu)
- adapter->init_niu(adapter);
/* setup all the resources for the Phantom... */
/* this include the descriptors for rcv, tx, and status */
@@ -609,21 +729,14 @@ static int netxen_nic_open(struct net_device *netdev)
err);
return err;
}
- if (adapter->init_port
- && adapter->init_port(adapter, port->portnum) != 0) {
- printk(KERN_ERR "%s: Failed to initialize port %d\n",
- netxen_nic_driver_name, port->portnum);
- netxen_free_hw_resources(adapter);
- return -EIO;
- }
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++)
netxen_post_rx_buffers(adapter, ctx, ring);
}
adapter->irq = adapter->ahw.pdev->irq;
- err = request_irq(adapter->ahw.pdev->irq, &netxen_intr,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM,
- netdev->name, adapter);
+ err = request_irq(adapter->ahw.pdev->irq, netxen_intr,
+ SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name,
+ adapter);
if (err) {
printk(KERN_ERR "request_irq failed with: %d\n", err);
netxen_free_hw_resources(adapter);
@@ -632,23 +745,28 @@ static int netxen_nic_open(struct net_device *netdev)
adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
}
- adapter->active_ports++;
- if (adapter->active_ports == 1) {
- if (!adapter->driver_mismatch)
- mod_timer(&adapter->watchdog_timer, jiffies);
+ if (!adapter->driver_mismatch)
+ mod_timer(&adapter->watchdog_timer, jiffies);
- netxen_nic_enable_int(adapter);
- }
+ netxen_nic_enable_int(adapter);
/* Done here again so that even if phantom sw overwrote it,
* we set it */
if (adapter->macaddr_set)
- adapter->macaddr_set(port, netdev->dev_addr);
- netxen_nic_set_link_parameters(port);
+ adapter->macaddr_set(adapter, netdev->dev_addr);
+ if (adapter->init_port
+ && adapter->init_port(adapter, adapter->portnum) != 0) {
+ del_timer_sync(&adapter->watchdog_timer);
+ printk(KERN_ERR "%s: Failed to initialize port %d\n",
+ netxen_nic_driver_name, adapter->portnum);
+ return -EIO;
+ }
+
+ netxen_nic_set_link_parameters(adapter);
netxen_nic_set_multi(netdev);
if (adapter->set_mtu)
- adapter->set_mtu(port, netdev->mtu);
+ adapter->set_mtu(adapter, netdev->mtu);
if (!adapter->driver_mismatch)
netif_start_queue(netdev);
@@ -661,8 +779,7 @@ static int netxen_nic_open(struct net_device *netdev)
*/
static int netxen_nic_close(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
int i, j;
struct netxen_cmd_buffer *cmd_buff;
struct netxen_skb_frag *buffrag;
@@ -670,47 +787,39 @@ static int netxen_nic_close(struct net_device *netdev)
netif_carrier_off(netdev);
netif_stop_queue(netdev);
- adapter->active_ports--;
-
- if (!adapter->active_ports) {
- netxen_nic_disable_int(adapter);
- cmd_buff = adapter->cmd_buf_arr;
- for (i = 0; i < adapter->max_tx_desc_count; i++) {
- buffrag = cmd_buff->frag_array;
+ cmd_buff = adapter->cmd_buf_arr;
+ for (i = 0; i < adapter->max_tx_desc_count; i++) {
+ buffrag = cmd_buff->frag_array;
+ if (buffrag->dma) {
+ pci_unmap_single(adapter->pdev, buffrag->dma,
+ buffrag->length, PCI_DMA_TODEVICE);
+ buffrag->dma = (u64) NULL;
+ }
+ for (j = 0; j < cmd_buff->frag_count; j++) {
+ buffrag++;
if (buffrag->dma) {
- pci_unmap_single(port->pdev, buffrag->dma,
- buffrag->length,
- PCI_DMA_TODEVICE);
+ pci_unmap_page(adapter->pdev, buffrag->dma,
+ buffrag->length,
+ PCI_DMA_TODEVICE);
buffrag->dma = (u64) NULL;
}
- for (j = 0; j < cmd_buff->frag_count; j++) {
- buffrag++;
- if (buffrag->dma) {
- pci_unmap_page(port->pdev,
- buffrag->dma,
- buffrag->length,
- PCI_DMA_TODEVICE);
- buffrag->dma = (u64) NULL;
- }
- }
- /* Free the skb we received in netxen_nic_xmit_frame */
- if (cmd_buff->skb) {
- dev_kfree_skb_any(cmd_buff->skb);
- cmd_buff->skb = NULL;
- }
- cmd_buff++;
}
- FLUSH_SCHEDULED_WORK();
- del_timer_sync(&adapter->watchdog_timer);
+ /* Free the skb we received in netxen_nic_xmit_frame */
+ if (cmd_buff->skb) {
+ dev_kfree_skb_any(cmd_buff->skb);
+ cmd_buff->skb = NULL;
+ }
+ cmd_buff++;
}
+ FLUSH_SCHEDULED_WORK();
+ del_timer_sync(&adapter->watchdog_timer);
return 0;
}
static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
struct netxen_hardware_context *hw = &adapter->ahw;
unsigned int first_seg_len = skb->len - skb->data_len;
struct netxen_skb_frag *buffrag;
@@ -728,12 +837,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
u32 last_cmd_consumer = 0;
int no_of_desc;
- port->stats.xmitcalled++;
+ adapter->stats.xmitcalled++;
frag_count = skb_shinfo(skb)->nr_frags + 1;
if (unlikely(skb->len <= 0)) {
dev_kfree_skb_any(skb);
- port->stats.badskblen++;
+ adapter->stats.badskblen++;
return NETDEV_TX_OK;
}
@@ -742,7 +851,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
"too large, can handle only %d frags\n",
netxen_nic_driver_name, netdev->name,
frag_count, MAX_BUFFERS_PER_CMD);
- port->stats.txdropped++;
+ adapter->stats.txdropped++;
if ((++dropped_packet & 0xff) == 0xff)
printk("%s: %s droppped packets = %d\n",
netxen_nic_driver_name, netdev->name,
@@ -759,7 +868,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
*/
retry_getting_window:
spin_lock_bh(&adapter->tx_lock);
- if (adapter->total_threads == MAX_XMIT_PRODUCERS) {
+ if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
spin_unlock_bh(&adapter->tx_lock);
/*
* Yield CPU
@@ -792,15 +901,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if ((k + no_of_desc) >=
((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
last_cmd_consumer)) {
- port->stats.nocmddescriptor++;
- DPRINTK(ERR, "No command descriptors available,"
- " producer = %d, consumer = %d count=%llu,"
- " dropping packet\n", producer,
- adapter->last_cmd_consumer,
- port->stats.nocmddescriptor);
-
netif_stop_queue(netdev);
- port->flags |= NETXEN_NETDEV_STATUS;
+ adapter->flags |= NETXEN_NETDEV_STATUS;
spin_unlock_bh(&adapter->tx_lock);
return NETDEV_TX_BUSY;
}
@@ -828,16 +930,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
pbuf->skb = skb;
pbuf->cmd = TX_ETHER_PKT;
pbuf->frag_count = frag_count;
- pbuf->port = port->portnum;
+ pbuf->port = adapter->portnum;
buffrag = &pbuf->frag_array[0];
- buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len,
+ buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len,
PCI_DMA_TODEVICE);
buffrag->length = first_seg_len;
netxen_set_cmd_desc_totallength(hwdesc, skb->len);
netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count);
netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT);
- netxen_set_cmd_desc_port(hwdesc, port->portnum);
+ netxen_set_cmd_desc_port(hwdesc, adapter->portnum);
+ netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum);
hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
@@ -860,7 +963,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
offset = frag->page_offset;
temp_len = len;
- temp_dma = pci_map_page(port->pdev, frag->page, offset,
+ temp_dma = pci_map_page(adapter->pdev, frag->page, offset,
len, PCI_DMA_TODEVICE);
buffrag++;
@@ -927,21 +1030,29 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
producer = get_next_index(producer, max_tx_desc_count);
}
}
+
+ i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+
+ hw->cmd_desc_head[saved_producer].flags_opcode =
+ cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode);
+ hw->cmd_desc_head[saved_producer].num_of_buffers_total_length =
+ cpu_to_le32(hw->cmd_desc_head[saved_producer].
+ num_of_buffers_total_length);
+
spin_lock_bh(&adapter->tx_lock);
- port->stats.txbytes +=
- netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
+ adapter->stats.txbytes += i;
+
/* Code to update the adapter considering how many producer threads
are currently working */
if ((--adapter->num_threads) == 0) {
/* This is the last thread */
u32 crb_producer = adapter->cmd_producer;
- writel(crb_producer,
- NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
+ netxen_nic_update_cmd_producer(adapter, crb_producer);
wmb();
adapter->total_threads = 0;
}
- port->stats.xmitfinished++;
+ adapter->stats.xmitfinished++;
spin_unlock_bh(&adapter->tx_lock);
netdev->trans_start = jiffies;
@@ -961,27 +1072,26 @@ static void netxen_watchdog(unsigned long v)
static void netxen_tx_timeout(struct net_device *netdev)
{
- struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
-
- SCHEDULE_WORK(&port->tx_timeout_task);
+ struct netxen_adapter *adapter = (struct netxen_adapter *)
+ netdev_priv(netdev);
+ SCHEDULE_WORK(&adapter->tx_timeout_task);
}
static void netxen_tx_timeout_task(struct work_struct *work)
{
- struct netxen_port *port =
- container_of(work, struct netxen_port, tx_timeout_task);
- struct net_device *netdev = port->netdev;
+ struct netxen_adapter *adapter =
+ container_of(work, struct netxen_adapter, tx_timeout_task);
unsigned long flags;
printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
- netxen_nic_driver_name, netdev->name);
-
- spin_lock_irqsave(&port->adapter->lock, flags);
- netxen_nic_close(netdev);
- netxen_nic_open(netdev);
- spin_unlock_irqrestore(&port->adapter->lock, flags);
- netdev->trans_start = jiffies;
- netif_wake_queue(netdev);
+ netxen_nic_driver_name, adapter->netdev->name);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ netxen_nic_close(adapter->netdev);
+ netxen_nic_open(adapter->netdev);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ adapter->netdev->trans_start = jiffies;
+ netif_wake_queue(adapter->netdev);
}
static int
@@ -990,17 +1100,16 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
u32 ret = 0;
DPRINTK(INFO, "Entered handle ISR\n");
-
adapter->stats.ints++;
if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
int count = 0;
u32 mask;
- mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR));
- if ((mask & 0x80) == 0) {
- /* not our interrupt */
+ u32 our_int = 0;
+ our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+ /* not our interrupt */
+ if ((our_int & (0x80 << adapter->portnum)) == 0)
return ret;
- }
netxen_nic_disable_int(adapter);
/* Window = 0 or 1 */
do {
@@ -1012,7 +1121,6 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
printk("Could not disable interrupt completely\n");
}
- adapter->stats.hostints++;
if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
if (netif_rx_schedule_prep(netdev)) {
@@ -1046,33 +1154,24 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
irqreturn_t netxen_intr(int irq, void *data)
{
struct netxen_adapter *adapter;
- struct netxen_port *port;
struct net_device *netdev;
- int i;
if (unlikely(!irq)) {
return IRQ_NONE; /* Not our interrupt */
}
adapter = (struct netxen_adapter *)data;
- for (i = 0; i < adapter->ahw.max_ports; i++) {
- port = adapter->port[i];
- netdev = port->netdev;
-
- /* process our status queue (for all 4 ports) */
- if (netif_running(netdev)) {
- netxen_handle_int(adapter, netdev);
- break;
- }
- }
+ netdev = adapter->netdev;
+ /* process our status queue (for all 4 ports) */
+ if (netif_running(netdev))
+ netxen_handle_int(adapter, netdev);
return IRQ_HANDLED;
}
static int netxen_nic_poll(struct net_device *netdev, int *budget)
{
- struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
int work_to_do = min(*budget, netdev->quota);
int done = 1;
int ctx;
@@ -1080,7 +1179,6 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
int work_done = 0;
DPRINTK(INFO, "polling for %d descriptors\n", *budget);
- port->stats.polled++;
work_done = 0;
for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
@@ -1124,8 +1222,7 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget)
#ifdef CONFIG_NET_POLL_CONTROLLER
static void netxen_nic_poll_controller(struct net_device *netdev)
{
- struct netxen_port *port = netdev_priv(netdev);
- struct netxen_adapter *adapter = port->adapter;
+ struct netxen_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->irq);
netxen_intr(adapter->irq, adapter);
enable_irq(adapter->irq);
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index d5d95074e56..cef90a78351 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -88,12 +88,13 @@ static inline int phy_unlock(struct netxen_adapter *adapter)
* -1 on error
*
*/
-int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
- long reg, __u32 * readval)
+int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg,
+ __u32 * readval)
{
long timeout = 0;
long result = 0;
long restore = 0;
+ long phy = physical_port[adapter->portnum];
__u32 address;
__u32 command;
__u32 status;
@@ -183,12 +184,13 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
* -1 on error
*
*/
-int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
- long phy, long reg, __u32 val)
+int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg,
+ __u32 val)
{
long timeout = 0;
long result = 0;
long restore = 0;
+ long phy = physical_port[adapter->portnum];
__u32 address;
__u32 command;
__u32 status;
@@ -258,15 +260,13 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
return result;
}
-int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter)
{
netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f);
return 0;
}
-int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter)
{
int result = 0;
__u32 enable = 0;
@@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
netxen_set_phy_int_speed_changed(enable);
if (0 !=
- netxen_niu_gbe_phy_write(adapter, port,
+ netxen_niu_gbe_phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,
enable))
result = -EIO;
@@ -283,38 +283,34 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
return result;
}
-int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter)
{
netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f);
return 0;
}
-int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter)
{
int result = 0;
if (0 !=
- netxen_niu_gbe_phy_write(adapter, port,
+ netxen_niu_gbe_phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0))
result = -EIO;
return result;
}
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter)
{
netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);
return 0;
}
-int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
- int port)
+int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
{
int result = 0;
if (0 !=
- netxen_niu_gbe_phy_write(adapter, port,
+ netxen_niu_gbe_phy_write(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
-EIO))
result = -EIO;
@@ -355,9 +351,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
0x5);
}
- if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
}
@@ -393,9 +389,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
0x5);
}
- if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
}
@@ -404,11 +400,11 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int result = 0;
__u32 status;
if (adapter->disable_phy_interrupts)
- adapter->disable_phy_interrupts(adapter, port);
+ adapter->disable_phy_interrupts(adapter);
mdelay(2);
if (0 ==
- netxen_niu_gbe_phy_read(adapter, port,
+ netxen_niu_gbe_phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status)) {
if (netxen_get_phy_link(status)) {
@@ -439,13 +435,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
| NETXEN_GB_MAC_ENABLE_TX_RX
|
NETXEN_GB_MAC_PAUSED_FRMS);
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX
"ERROR clearing PHY interrupts\n");
- if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter))
printk(KERN_ERR PFX
"ERROR enabling PHY interrupts\n");
- if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter))
printk(KERN_ERR PFX
"ERROR clearing PHY interrupts\n");
result = -1;
@@ -458,26 +454,18 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port)
int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
{
- u32 reg = 0, ret = 0;
+ u32 reg;
+ u32 portnum = physical_port[adapter->portnum];
- if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) {
- netxen_crb_writelit_adapter(adapter,
- NETXEN_NIU_XG1_CONFIG_0, 0x5);
- /* XXX hack for Mez cards: both ports in promisc mode */
- netxen_nic_hw_read_wx(adapter,
- NETXEN_NIU_XGE_CONFIG_1, &reg, 4);
- reg = (reg | 0x2000UL);
- netxen_crb_writelit_adapter(adapter,
- NETXEN_NIU_XGE_CONFIG_1, reg);
- reg = 0;
- netxen_nic_hw_read_wx(adapter,
- NETXEN_NIU_XG1_CONFIG_1, &reg, 4);
- reg = (reg | 0x2000UL);
- netxen_crb_writelit_adapter(adapter,
- NETXEN_NIU_XG1_CONFIG_1, reg);
- }
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5);
+ netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), &reg, 4);
+ reg = (reg & ~0x2000UL);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), reg);
- return ret;
+ return 0;
}
/*
@@ -498,7 +486,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
* The read of the PHY INT status will clear the pending
* interrupt status
*/
- if (netxen_niu_gbe_phy_read(adapter, port,
+ if (netxen_niu_gbe_phy_read(adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
&int_src) != 0)
result = -EINVAL;
@@ -535,7 +523,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
printk(KERN_INFO PFX
"speed_changed or link status changed");
if (netxen_niu_gbe_phy_read
- (adapter, port,
+ (adapter,
NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
&status) == 0) {
if (netxen_get_phy_speed(status) == 2) {
@@ -581,10 +569,11 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
* Note that the passed-in value must already be in network byte order.
*/
int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
- int phy, netxen_ethernet_macaddr_t * addr)
+ netxen_ethernet_macaddr_t * addr)
{
u32 stationhigh;
u32 stationlow;
+ int phy = physical_port[adapter->portnum];
u8 val[8];
if (addr == NULL)
@@ -610,13 +599,12 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
* Set the station MAC address.
* Note that the passed-in value must already be in network byte order.
*/
-int netxen_niu_macaddr_set(struct netxen_port *port,
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr)
{
u8 temp[4];
u32 val;
- struct netxen_adapter *adapter = port->adapter;
- int phy = port->portnum;
+ int phy = physical_port[adapter->portnum];
unsigned char mac_addr[6];
int i;
@@ -634,7 +622,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4))
return -2;
- netxen_niu_macaddr_get(adapter, phy,
+ netxen_niu_macaddr_get(adapter,
(netxen_ethernet_macaddr_t *) mac_addr);
if (memcmp(mac_addr, addr, 6) == 0)
break;
@@ -642,7 +630,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port,
if (i == 10) {
printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
- netxen_nic_driver_name, port->netdev->name);
+ netxen_nic_driver_name, adapter->netdev->name);
printk(KERN_ERR "MAC address set: "
"%02x:%02x:%02x:%02x:%02x:%02x.\n",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
@@ -735,13 +723,13 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
}
/* Disable a GbE interface */
-int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg0;
+ u32 port = physical_port[adapter->portnum];
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
-
mac_cfg0 = 0;
netxen_gb_soft_reset(mac_cfg0);
if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
@@ -751,13 +739,13 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port)
}
/* Disable an XG interface */
-int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
+int netxen_niu_disable_xg_port(struct netxen_adapter *adapter)
{
__u32 mac_cfg;
+ u32 port = physical_port[adapter->portnum];
if (port != 0)
return -EINVAL;
-
mac_cfg = 0;
netxen_xg_soft_reset(mac_cfg);
if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0,
@@ -767,10 +755,11 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port)
}
/* Set promiscuous mode for a GbE interface */
-int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
+int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter,
netxen_niu_prom_mode_t mode)
{
__u32 reg;
+ u32 port = physical_port[adapter->portnum];
if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
return -EINVAL;
@@ -824,25 +813,50 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port,
* Set the MAC address for an XG port
* Note that the passed-in value must already be in network byte order.
*/
-int netxen_niu_xg_macaddr_set(struct netxen_port *port,
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t addr)
{
+ int phy = physical_port[adapter->portnum];
u8 temp[4];
u32 val;
- struct netxen_adapter *adapter = port->adapter;
+
+ if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS))
+ return -EIO;
temp[0] = temp[1] = 0;
- memcpy(temp + 2, addr, 2);
- val = le32_to_cpu(*(__le32 *)temp);
- if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
- &val, 4))
+ switch (phy) {
+ case 0:
+ memcpy(temp + 2, addr, 2);
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
+ &val, 4))
return -EIO;
- memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
- val = le32_to_cpu(*(__le32 *)temp);
- if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
- &val, 4))
+ memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+ &val, 4))
+ return -EIO;
+ break;
+
+ case 1:
+ memcpy(temp + 2, addr, 2);
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1,
+ &val, 4))
+ return -EIO;
+
+ memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32));
+ val = le32_to_cpu(*(__le32 *)temp);
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI,
+ &val, 4))
return -EIO;
+ break;
+
+ default:
+ printk(KERN_ERR "Unknown port %d\n", phy);
+ break;
+ }
return 0;
}
@@ -851,9 +865,10 @@ int netxen_niu_xg_macaddr_set(struct netxen_port *port,
* Return the current station MAC address.
* Note that the passed-in value must already be in network byte order.
*/
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
netxen_ethernet_macaddr_t * addr)
{
+ int phy = physical_port[adapter->portnum];
u32 stationhigh;
u32 stationlow;
u8 val[8];
@@ -878,21 +893,24 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
}
int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
- int port, netxen_niu_prom_mode_t mode)
+ netxen_niu_prom_mode_t mode)
{
__u32 reg;
+ u32 port = physical_port[adapter->portnum];
- if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
return -EINVAL;
- if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, &reg, 4))
- return -EIO;
+ if (netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), &reg, 4))
+ return -EIO;
if (mode == NETXEN_NIU_PROMISC_MODE)
reg = (reg | 0x2000UL);
else
reg = (reg & ~0x2000UL);
- netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg);
return 0;
}
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h
index 0c7c94328b7..9457fc7249c 100644
--- a/drivers/net/netxen/netxen_nic_phan_reg.h
+++ b/drivers/net/netxen/netxen_nic_phan_reg.h
@@ -100,8 +100,21 @@
#define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac)
#define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0)
+#define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8)
+#define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc)
+
+// 1c0 to 1cc used for signature reg
+#define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0)
+#define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4)
#define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4)
+#define CRB_V2P_0 NETXEN_NIC_REG(0x290)
+#define CRB_V2P_1 NETXEN_NIC_REG(0x294)
+#define CRB_V2P_2 NETXEN_NIC_REG(0x298)
+#define CRB_V2P_3 NETXEN_NIC_REG(0x29c)
+#define CRB_V2P(port) (CRB_V2P_0+((port)*4))
+#define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0)
+
/* used for ethtool tests */
#define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280)
@@ -139,128 +152,13 @@ struct netxen_recv_crb {
};
#if defined(DEFINE_GLOBAL_RECV_CRB)
-struct netxen_recv_crb recv_crb_registers[] = {
- /*
- * Instance 0.
- */
- {
- /* rcv_desc_crb: */
- {
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x100),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x104),
- /* crb_gloablrcv_ring: */
- NETXEN_NIC_REG(0x108),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x10c),
-
- },
- /* Jumbo frames */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x110),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x114),
- /* crb_gloablrcv_ring: */
- NETXEN_NIC_REG(0x118),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x11c),
- },
- /* LRO */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x120),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x124),
- /* crb_gloablrcv_ring: */
- NETXEN_NIC_REG(0x128),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x12c),
- }
- },
- /* crb_rcvstatus_ring: */
- NETXEN_NIC_REG(0x130),
- /* crb_rcv_status_producer: */
- NETXEN_NIC_REG(0x134),
- /* crb_rcv_status_consumer: */
- NETXEN_NIC_REG(0x138),
- /* crb_rcvpeg_state: */
- NETXEN_NIC_REG(0x13c),
- /* crb_status_ring_size */
- NETXEN_NIC_REG(0x140),
-
- },
- /*
- * Instance 1,
- */
- {
- /* rcv_desc_crb: */
- {
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x144),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x148),
- /* crb_globalrcv_ring: */
- NETXEN_NIC_REG(0x14c),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x150),
-
- },
- /* Jumbo frames */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x154),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x158),
- /* crb_globalrcv_ring: */
- NETXEN_NIC_REG(0x15c),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x160),
- },
- /* LRO */
- {
- /* crb_rcv_producer_offset: */
- NETXEN_NIC_REG(0x164),
- /* crb_rcv_consumer_offset: */
- NETXEN_NIC_REG(0x168),
- /* crb_globalrcv_ring: */
- NETXEN_NIC_REG(0x16c),
- /* crb_rcv_ring_size */
- NETXEN_NIC_REG(0x170),
- }
-
- },
- /* crb_rcvstatus_ring: */
- NETXEN_NIC_REG(0x174),
- /* crb_rcv_status_producer: */
- NETXEN_NIC_REG(0x178),
- /* crb_rcv_status_consumer: */
- NETXEN_NIC_REG(0x17c),
- /* crb_rcvpeg_state: */
- NETXEN_NIC_REG(0x180),
- /* crb_status_ring_size */
- NETXEN_NIC_REG(0x184),
-
- },
-};
-
-u64 ctx_addr_sig_regs[][3] = {
- {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)},
- {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)},
- {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)},
- {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)}
-};
-
#else
extern struct netxen_recv_crb recv_crb_registers[];
extern u64 ctx_addr_sig_regs[][3];
-#define CRB_CTX_ADDR_REG_LO (ctx_addr_sig_regs[0][0])
-#define CRB_CTX_ADDR_REG_HI (ctx_addr_sig_regs[0][2])
-#define CRB_CTX_SIGNATURE_REG (ctx_addr_sig_regs[0][1])
#endif /* DEFINE_GLOBAL_RECEIVE_CRB */
+#define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0])
+#define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2])
+#define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1])
/*
* Temperature control.
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 6a32338623f..3439f8c649f 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -104,7 +104,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/workqueue.h>
#include <linux/init.h>
#include <linux/ip.h> /* for iph */
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 76fe9dd8e84..bc7f3dee6e5 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -33,6 +33,8 @@
#include <linux/tcp.h>
#include <net/checksum.h>
+#include <asm/irq.h>
+
#include "pasemi_mac.h"
@@ -51,6 +53,16 @@
#define RX_RING_SIZE 512
#define TX_RING_SIZE 512
+#define DEFAULT_MSG_ENABLE \
+ (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK | \
+ NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | \
+ NETIF_MSG_IFUP | \
+ NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR)
+
#define TX_DESC(mac, num) ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
#define RX_DESC(mac, num) ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
@@ -59,11 +71,13 @@
#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
-/* XXXOJN these should come out of the device tree some day */
-#define PAS_DMA_CAP_BASE 0xe00d0040
-#define PAS_DMA_CAP_SIZE 0x100
-#define PAS_DMA_COM_BASE 0xe00d0100
-#define PAS_DMA_COM_SIZE 0x100
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+static int debug = -1; /* -1 == use DEFAULT_MSG_ENABLE as value */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value");
static struct pasdma_status *dma_status;
@@ -80,7 +94,12 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
return -ENOENT;
}
- maddr = get_property(dn, "mac-address", NULL);
+ maddr = of_get_property(dn, "local-mac-address", NULL);
+
+ /* Fall back to mac-address for older firmware */
+ if (maddr == NULL)
+ maddr = of_get_property(dn, "mac-address", NULL);
+
if (maddr == NULL) {
dev_warn(&pdev->dev,
"no mac address in device tree, not configuring\n");
@@ -277,8 +296,8 @@ static void pasemi_mac_free_rx_resources(struct net_device *dev)
for (i = 0; i < RX_RING_SIZE; i++) {
info = &RX_DESC_INFO(mac, i);
dp = &RX_DESC(mac, i);
- if (info->dma) {
- if (info->skb) {
+ if (info->skb) {
+ if (info->dma) {
pci_unmap_single(mac->dma_pdev,
info->dma,
info->skb->len,
@@ -309,82 +328,120 @@ static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int i;
int start = mac->rx->next_to_fill;
- unsigned int count;
+ unsigned int limit, count;
- count = (mac->rx->next_to_clean + RX_RING_SIZE -
+ limit = (mac->rx->next_to_clean + RX_RING_SIZE -
mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
/* Check to see if we're doing first-time setup */
if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
- count = RX_RING_SIZE;
+ limit = RX_RING_SIZE;
- if (count <= 0)
+ if (limit <= 0)
return;
- for (i = start; i < start + count; i++) {
+ i = start;
+ for (count = limit; count; count--) {
struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
u64 *buff = &RX_BUFF(mac, i);
struct sk_buff *skb;
dma_addr_t dma;
- skb = dev_alloc_skb(BUF_SIZE);
+ /* skb might still be in there for recycle on short receives */
+ if (info->skb)
+ skb = info->skb;
+ else
+ skb = dev_alloc_skb(BUF_SIZE);
- if (!skb) {
- count = i - start;
+ if (unlikely(!skb))
break;
- }
dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
PCI_DMA_FROMDEVICE);
- if (dma_mapping_error(dma)) {
+ if (unlikely(dma_mapping_error(dma))) {
dev_kfree_skb_irq(info->skb);
- count = i - start;
break;
}
info->skb = skb;
info->dma = dma;
*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+ i++;
}
wmb();
pci_write_config_dword(mac->dma_pdev,
PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
- count);
+ limit - count);
pci_write_config_dword(mac->dma_pdev,
PAS_DMA_RXINT_INCR(mac->dma_if),
- count);
+ limit - count);
- mac->rx->next_to_fill += count;
+ mac->rx->next_to_fill += limit - count;
}
+static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
+{
+ unsigned int reg, stat;
+ /* Re-enable packet count interrupts: finally
+ * ack the packet count interrupt we got in rx_intr.
+ */
+
+ pci_read_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_RXCH_STAT(mac->dma_rxch),
+ &stat);
+
+ reg = PAS_IOB_DMA_RXCH_RESET_PCNT(stat & PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+ | PAS_IOB_DMA_RXCH_RESET_PINTC;
+
+ pci_write_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch),
+ reg);
+}
+
+static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
+{
+ unsigned int reg, stat;
+
+ /* Re-enable packet count interrupts */
+ pci_read_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_TXCH_STAT(mac->dma_txch), &stat);
+
+ reg = PAS_IOB_DMA_TXCH_RESET_PCNT(stat & PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+ | PAS_IOB_DMA_TXCH_RESET_PINTC;
+
+ pci_write_config_dword(mac->iob_pdev,
+ PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
+}
+
+
static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
{
- unsigned int i;
- int start, count;
+ unsigned int n;
+ int count;
+ struct pas_dma_xct_descr *dp;
+ struct pasemi_mac_buffer *info;
+ struct sk_buff *skb;
+ unsigned int i, len;
+ u64 macrx;
+ dma_addr_t dma;
spin_lock(&mac->rx->lock);
- start = mac->rx->next_to_clean;
- count = 0;
+ n = mac->rx->next_to_clean;
- for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
- struct pas_dma_xct_descr *dp;
- struct pasemi_mac_buffer *info;
- struct sk_buff *skb;
- unsigned int j, len;
- dma_addr_t dma;
+ for (count = limit; count; count--) {
rmb();
- dp = &RX_DESC(mac, i);
+ dp = &RX_DESC(mac, n);
+ macrx = dp->macrx;
- if (!(dp->macrx & XCT_MACRX_O))
+ if (!(macrx & XCT_MACRX_O))
break;
- count++;
info = NULL;
@@ -396,29 +453,42 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
*/
dma = (dp->ptr & XCT_PTR_ADDR_M);
- for (j = start; j < (start + RX_RING_SIZE); j++) {
- info = &RX_DESC_INFO(mac, j);
+ for (i = n; i < (n + RX_RING_SIZE); i++) {
+ info = &RX_DESC_INFO(mac, i);
if (info->dma == dma)
break;
}
- BUG_ON(!info);
- BUG_ON(info->dma != dma);
+ skb = info->skb;
+ info->dma = 0;
- pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+ pci_unmap_single(mac->dma_pdev, dma, skb->len,
PCI_DMA_FROMDEVICE);
- skb = info->skb;
-
- len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+ len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+ if (len < 256) {
+ struct sk_buff *new_skb =
+ netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN);
+ if (new_skb) {
+ skb_reserve(new_skb, NET_IP_ALIGN);
+ memcpy(new_skb->data - NET_IP_ALIGN,
+ skb->data - NET_IP_ALIGN,
+ len + NET_IP_ALIGN);
+ /* save the skb in buffer_info as good */
+ skb = new_skb;
+ }
+ /* else just continue with the old one */
+ } else
+ info->skb = NULL;
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, mac->netdev);
- if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+ if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
skb->ip_summed = CHECKSUM_COMPLETE;
- skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+ skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
XCT_MACRX_CSUM_S;
} else
skb->ip_summed = CHECKSUM_NONE;
@@ -428,13 +498,13 @@ static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
netif_receive_skb(skb);
- info->dma = 0;
- info->skb = NULL;
dp->ptr = 0;
dp->macrx = 0;
+
+ n++;
}
- mac->rx->next_to_clean += count;
+ mac->rx->next_to_clean += limit - count;
pasemi_mac_replenish_rx_ring(mac->netdev);
spin_unlock(&mac->rx->lock);
@@ -476,6 +546,8 @@ static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
mac->tx->next_to_clean += count;
spin_unlock_irqrestore(&mac->tx->lock, flags);
+ netif_wake_queue(mac->netdev);
+
return count;
}
@@ -486,18 +558,28 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int reg;
- if (!(*mac->rx_status & PAS_STATUS_INT))
+ if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
return IRQ_NONE;
- netif_rx_schedule(dev);
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
- PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+ if (*mac->rx_status & PAS_STATUS_ERROR)
+ printk("rx_status reported error\n");
+
+ /* Don't reset packet count so it won't fire again but clear
+ * all others.
+ */
+
+ pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), &reg);
- reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
- PAS_IOB_DMA_RXCH_RESET_DINTC;
+ reg = 0;
+ if (*mac->rx_status & PAS_STATUS_SOFT)
+ reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
+ if (*mac->rx_status & PAS_STATUS_ERROR)
+ reg |= PAS_IOB_DMA_RXCH_RESET_DINTC;
if (*mac->rx_status & PAS_STATUS_TIMER)
reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+ netif_rx_schedule(dev);
+
pci_write_config_dword(mac->iob_pdev,
PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
@@ -510,31 +592,137 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
struct net_device *dev = data;
struct pasemi_mac *mac = netdev_priv(dev);
unsigned int reg;
- int was_full;
- was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
-
- if (!(*mac->tx_status & PAS_STATUS_INT))
+ if (!(*mac->tx_status & PAS_STATUS_CAUSE_M))
return IRQ_NONE;
pasemi_mac_clean_tx(mac);
- reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
- if (*mac->tx_status & PAS_STATUS_TIMER)
- reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+ reg = PAS_IOB_DMA_TXCH_RESET_PINTC;
+
+ if (*mac->tx_status & PAS_STATUS_SOFT)
+ reg |= PAS_IOB_DMA_TXCH_RESET_SINTC;
+ if (*mac->tx_status & PAS_STATUS_ERROR)
+ reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
reg);
- if (was_full)
- netif_wake_queue(dev);
-
return IRQ_HANDLED;
}
+static void pasemi_adjust_link(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ int msg;
+ unsigned int flags;
+ unsigned int new_flags;
+
+ if (!mac->phydev->link) {
+ /* If no link, MAC speed settings don't matter. Just report
+ * link down and return.
+ */
+ if (mac->link && netif_msg_link(mac))
+ printk(KERN_INFO "%s: Link is down.\n", dev->name);
+
+ netif_carrier_off(dev);
+ mac->link = 0;
+
+ return;
+ } else
+ netif_carrier_on(dev);
+
+ pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+ new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
+ PAS_MAC_CFG_PCFG_TSR_M);
+
+ if (!mac->phydev->duplex)
+ new_flags |= PAS_MAC_CFG_PCFG_HD;
+
+ switch (mac->phydev->speed) {
+ case 1000:
+ new_flags |= PAS_MAC_CFG_PCFG_SPD_1G |
+ PAS_MAC_CFG_PCFG_TSR_1G;
+ break;
+ case 100:
+ new_flags |= PAS_MAC_CFG_PCFG_SPD_100M |
+ PAS_MAC_CFG_PCFG_TSR_100M;
+ break;
+ case 10:
+ new_flags |= PAS_MAC_CFG_PCFG_SPD_10M |
+ PAS_MAC_CFG_PCFG_TSR_10M;
+ break;
+ default:
+ printk("Unsupported speed %d\n", mac->phydev->speed);
+ }
+
+ /* Print on link or speed/duplex change */
+ msg = mac->link != mac->phydev->link || flags != new_flags;
+
+ mac->duplex = mac->phydev->duplex;
+ mac->speed = mac->phydev->speed;
+ mac->link = mac->phydev->link;
+
+ if (new_flags != flags)
+ pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags);
+
+ if (msg && netif_msg_link(mac))
+ printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n",
+ dev->name, mac->speed, mac->duplex ? "full" : "half");
+}
+
+static int pasemi_mac_phy_init(struct net_device *dev)
+{
+ struct pasemi_mac *mac = netdev_priv(dev);
+ struct device_node *dn, *phy_dn;
+ struct phy_device *phydev;
+ unsigned int phy_id;
+ const phandle *ph;
+ const unsigned int *prop;
+ struct resource r;
+ int ret;
+
+ dn = pci_device_to_OF_node(mac->pdev);
+ ph = of_get_property(dn, "phy-handle", NULL);
+ if (!ph)
+ return -ENODEV;
+ phy_dn = of_find_node_by_phandle(*ph);
+
+ prop = of_get_property(phy_dn, "reg", NULL);
+ ret = of_address_to_resource(phy_dn->parent, 0, &r);
+ if (ret)
+ goto err;
+
+ phy_id = *prop;
+ snprintf(mac->phy_id, BUS_ID_SIZE, PHY_ID_FMT, (int)r.start, phy_id);
+
+ of_node_put(phy_dn);
+
+ mac->link = 0;
+ mac->speed = 0;
+ mac->duplex = -1;
+
+ phydev = phy_connect(dev, mac->phy_id, &pasemi_adjust_link, 0, PHY_INTERFACE_MODE_SGMII);
+
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to phy\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ mac->phydev = phydev;
+
+ return 0;
+
+err:
+ of_node_put(phy_dn);
+ return -ENODEV;
+}
+
+
static int pasemi_mac_open(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
+ int base_irq;
unsigned int flags;
int ret;
@@ -558,10 +746,18 @@ static int pasemi_mac_open(struct net_device *dev)
flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
- PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+ PAS_IOB_DMA_RXCH_CFG_CNTTH(1));
+ pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
+ PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
+
+ /* Clear out any residual packet count state from firmware */
+ pasemi_mac_restart_rx_intr(mac);
+ pasemi_mac_restart_tx_intr(mac);
+
+ /* 0xffffff is max value, about 16ms */
pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
- PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+ PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
@@ -595,31 +791,50 @@ static int pasemi_mac_open(struct net_device *dev)
pasemi_mac_replenish_rx_ring(dev);
+ ret = pasemi_mac_phy_init(dev);
+ /* Some configs don't have PHYs (XAUI etc), so don't complain about
+ * failed init due to -ENODEV.
+ */
+ if (ret && ret != -ENODEV)
+ dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret);
+
netif_start_queue(dev);
netif_poll_enable(dev);
- ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
- &pasemi_mac_tx_intr, IRQF_DISABLED,
+ /* Interrupts are a bit different for our DMA controller: While
+ * it's got one a regular PCI device header, the interrupt there
+ * is really the base of the range it's using. Each tx and rx
+ * channel has it's own interrupt source.
+ */
+
+ base_irq = virq_to_hw(mac->dma_pdev->irq);
+
+ mac->tx_irq = irq_create_mapping(NULL, base_irq + mac->dma_txch);
+ mac->rx_irq = irq_create_mapping(NULL, base_irq + 20 + mac->dma_txch);
+
+ ret = request_irq(mac->tx_irq, &pasemi_mac_tx_intr, IRQF_DISABLED,
mac->tx->irq_name, dev);
if (ret) {
dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
- mac->dma_pdev->irq + mac->dma_txch, ret);
+ base_irq + mac->dma_txch, ret);
goto out_tx_int;
}
- ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
- &pasemi_mac_rx_intr, IRQF_DISABLED,
+ ret = request_irq(mac->rx_irq, &pasemi_mac_rx_intr, IRQF_DISABLED,
mac->rx->irq_name, dev);
if (ret) {
dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
- mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+ base_irq + 20 + mac->dma_rxch, ret);
goto out_rx_int;
}
+ if (mac->phydev)
+ phy_start(mac->phydev);
+
return 0;
out_rx_int:
- free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+ free_irq(mac->tx_irq, dev);
out_tx_int:
netif_poll_disable(dev);
netif_stop_queue(dev);
@@ -639,6 +854,11 @@ static int pasemi_mac_close(struct net_device *dev)
unsigned int stat;
int retries;
+ if (mac->phydev) {
+ phy_stop(mac->phydev);
+ phy_disconnect(mac->phydev);
+ }
+
netif_stop_queue(dev);
/* Clean out any pending buffers */
@@ -660,40 +880,37 @@ static int pasemi_mac_close(struct net_device *dev)
pci_read_config_dword(mac->dma_pdev,
PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
&stat);
- if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+ if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
break;
cond_resched();
}
- if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+ if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
- }
for (retries = 0; retries < MAX_RETRIES; retries++) {
pci_read_config_dword(mac->dma_pdev,
PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
&stat);
- if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+ if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT))
break;
cond_resched();
}
- if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+ if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
- }
for (retries = 0; retries < MAX_RETRIES; retries++) {
pci_read_config_dword(mac->dma_pdev,
PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
&stat);
- if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+ if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT))
break;
cond_resched();
}
- if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+ if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
- }
/* Then, disable the channel. This must be done separately from
* stopping, since you can't disable when active.
@@ -706,8 +923,8 @@ static int pasemi_mac_close(struct net_device *dev)
pci_write_config_dword(mac->dma_pdev,
PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
- free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
- free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+ free_irq(mac->tx_irq, dev);
+ free_irq(mac->rx_irq, dev);
/* Free resources */
pasemi_mac_free_rx_resources(dev);
@@ -802,6 +1019,7 @@ static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
return &mac->stats;
}
+
static void pasemi_mac_set_rx_mode(struct net_device *dev)
{
struct pasemi_mac *mac = netdev_priv(dev);
@@ -826,18 +1044,17 @@ static int pasemi_mac_poll(struct net_device *dev, int *budget)
pkts = pasemi_mac_clean_rx(mac, limit);
+ dev->quota -= pkts;
+ *budget -= pkts;
+
if (pkts < limit) {
/* all done, no more packets present */
netif_rx_complete(dev);
- /* re-enable receive interrupts */
- pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
- PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+ pasemi_mac_restart_rx_intr(mac);
return 0;
} else {
/* used up our quantum, so reschedule */
- dev->quota -= pkts;
- *budget -= pkts;
return 1;
}
}
@@ -937,6 +1154,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
+ mac->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);
+
+ /* Enable most messages by default */
+ mac->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
err = register_netdev(dev);
if (err) {
@@ -1011,9 +1233,5 @@ int pasemi_mac_init_module(void)
return pci_register_driver(&pasemi_mac_driver);
}
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
-MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
-
module_init(pasemi_mac_init_module);
module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index c3e37e46a18..8bc0cea8b14 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -24,6 +24,7 @@
#include <linux/ethtool.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
+#include <linux/phy.h>
struct pasemi_mac_txring {
spinlock_t lock;
@@ -54,6 +55,7 @@ struct pasemi_mac {
struct pci_dev *pdev;
struct pci_dev *dma_pdev;
struct pci_dev *iob_pdev;
+ struct phy_device *phydev;
struct net_device_stats stats;
/* Pointer to the cacheable per-channel status registers */
@@ -73,6 +75,14 @@ struct pasemi_mac {
struct pasemi_mac_txring *tx;
struct pasemi_mac_rxring *rx;
+ unsigned long tx_irq;
+ unsigned long rx_irq;
+ int link;
+ int speed;
+ int duplex;
+
+ unsigned int msg_enable;
+ char phy_id[BUS_ID_SIZE];
};
/* Software status descriptor (desc_info) */
@@ -193,11 +203,15 @@ enum {
#define PAS_DMA_RXINT_RCMDSTA(i) (0x200+(i)*_PAS_DMA_RXINT_STRIDE)
#define PAS_DMA_RXINT_RCMDSTA_EN 0x00000001
#define PAS_DMA_RXINT_RCMDSTA_ST 0x00000002
-#define PAS_DMA_RXINT_RCMDSTA_OO 0x00000100
-#define PAS_DMA_RXINT_RCMDSTA_BP 0x00000200
-#define PAS_DMA_RXINT_RCMDSTA_DR 0x00000400
+#define PAS_DMA_RXINT_RCMDSTA_MBT 0x00000008
+#define PAS_DMA_RXINT_RCMDSTA_MDR 0x00000010
+#define PAS_DMA_RXINT_RCMDSTA_MOO 0x00000020
+#define PAS_DMA_RXINT_RCMDSTA_MBP 0x00000040
#define PAS_DMA_RXINT_RCMDSTA_BT 0x00000800
-#define PAS_DMA_RXINT_RCMDSTA_TB 0x00001000
+#define PAS_DMA_RXINT_RCMDSTA_DR 0x00001000
+#define PAS_DMA_RXINT_RCMDSTA_OO 0x00002000
+#define PAS_DMA_RXINT_RCMDSTA_BP 0x00004000
+#define PAS_DMA_RXINT_RCMDSTA_TB 0x00008000
#define PAS_DMA_RXINT_RCMDSTA_ACT 0x00010000
#define PAS_DMA_RXINT_RCMDSTA_DROPS_M 0xfffe0000
#define PAS_DMA_RXINT_RCMDSTA_DROPS_S 17
@@ -297,6 +311,7 @@ enum {
#define PAS_STATUS_DCNT_S 16
#define PAS_STATUS_BPCNT_M 0x0000ffff00000000ull
#define PAS_STATUS_BPCNT_S 32
+#define PAS_STATUS_CAUSE_M 0xf000000000000000ull
#define PAS_STATUS_TIMER 0x1000000000000000ull
#define PAS_STATUS_ERROR 0x2000000000000000ull
#define PAS_STATUS_SOFT 0x4000000000000000ull
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 809ec440b8e..258d6f39618 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1420,7 +1420,7 @@ set_addresses(struct net_device *dev)
kio_addr_t ioaddr = dev->base_addr;
local_info_t *lp = netdev_priv(dev);
struct dev_mc_list *dmi = dev->mc_list;
- char *addr;
+ unsigned char *addr;
int i,j,k,n;
SelectPage(k=0x50);
@@ -1429,6 +1429,9 @@ set_addresses(struct net_device *dev)
if (++n > 9)
break;
i = 0;
+ if (n > 1 && n <= dev->mc_count && dmi) {
+ dmi = dmi->next;
+ }
}
if (j > 15) {
j = 8;
@@ -1436,10 +1439,9 @@ set_addresses(struct net_device *dev)
SelectPage(k);
}
- if (n && n <= dev->mc_count && dmi) {
+ if (n && n <= dev->mc_count && dmi)
addr = dmi->dmi_addr;
- dmi = dmi->next;
- } else
+ else
addr = dev->dev_addr;
if (lp->mohawk)
@@ -1465,10 +1467,10 @@ set_multicast_list(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* snoop */
PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */
} else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) {
- PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */
+ PutByte(XIRCREG42_SWC1, 0x02); /* set MPE */
} else if (dev->mc_count) {
/* the chip can filter 9 addresses perfectly */
- PutByte(XIRCREG42_SWC1, 0x00);
+ PutByte(XIRCREG42_SWC1, 0x01);
SelectPage(0x40);
PutByte(XIRCREG40_CMD0, Offline);
set_addresses(dev);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 0791360a6a6..9c171a7390e 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -253,12 +253,12 @@ struct pcnet32_access {
* so the structure should be allocated using pci_alloc_consistent().
*/
struct pcnet32_private {
- struct pcnet32_init_block init_block;
+ struct pcnet32_init_block *init_block;
/* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
struct pcnet32_rx_head *rx_ring;
struct pcnet32_tx_head *tx_ring;
- dma_addr_t dma_addr;/* DMA address of beginning of this
- object, returned by pci_alloc_consistent */
+ dma_addr_t init_dma_addr;/* DMA address of beginning of the init block,
+ returned by pci_alloc_consistent */
struct pci_dev *pci_dev;
const char *name;
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
@@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev,
static void pcnet32_purge_rx_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int i;
/* free all allocated skbuffs */
@@ -681,7 +681,7 @@ static void pcnet32_poll_controller(struct net_device *dev)
static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r = -EOPNOTSUPP;
@@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r = -EOPNOTSUPP;
@@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static void pcnet32_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
@@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct net_device *dev,
static u32 pcnet32_get_link(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r;
@@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_device *dev)
static u32 pcnet32_get_msglevel(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
return lp->msg_enable;
}
static void pcnet32_set_msglevel(struct net_device *dev, u32 value)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
lp->msg_enable = value;
}
static int pcnet32_nway_reset(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
int r = -EOPNOTSUPP;
@@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net_device *dev)
static void pcnet32_get_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
ering->tx_max_pending = TX_MAX_RING_SIZE;
ering->tx_pending = lp->tx_ring_size;
@@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct net_device *dev,
static int pcnet32_set_ringparam(struct net_device *dev,
struct ethtool_ringparam *ering)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
unsigned int size;
ulong ioaddr = dev->base_addr;
@@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struct net_device *dev)
static void pcnet32_ethtool_test(struct net_device *dev,
struct ethtool_test *test, u64 * data)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int rc;
if (test->flags == ETH_TEST_FL_OFFLINE) {
@@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct net_device *dev,
static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a; /* access to registers */
ulong ioaddr = dev->base_addr; /* card base I/O address */
struct sk_buff *skb; /* sk buff */
@@ -1047,7 +1047,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
static void pcnet32_led_blink_callback(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(struct net_device *dev)
static int pcnet32_phys_id(struct net_device *dev, u32 data)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
int can_sleep)
{
int csr5;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
int ticks;
@@ -1257,7 +1257,7 @@ static void pcnet32_rx_entry(struct net_device *dev,
static int pcnet32_rx(struct net_device *dev, int quota)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int entry = lp->cur_rx & lp->rx_mod_mask;
struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
int npackets = 0;
@@ -1282,7 +1282,7 @@ static int pcnet32_rx(struct net_device *dev, int quota)
static int pcnet32_tx(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned int dirty_tx = lp->dirty_tx;
int delta;
int must_restart = 0;
@@ -1381,7 +1381,7 @@ static int pcnet32_tx(struct net_device *dev)
#ifdef CONFIG_PCNET32_NAPI
static int pcnet32_poll(struct net_device *dev, int *budget)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int quota = min(dev->quota, *budget);
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
@@ -1428,7 +1428,7 @@ static int pcnet32_poll(struct net_device *dev, int *budget)
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int j = lp->phycount * PCNET32_REGS_PER_PHY;
return ((PCNET32_NUM_REGS + j) * sizeof(u16));
@@ -1439,7 +1439,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
{
int i, csr0;
u16 *buff = ptr;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
unsigned long flags;
@@ -1592,7 +1592,6 @@ static int __devinit
pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
{
struct pcnet32_private *lp;
- dma_addr_t lp_dma_addr;
int i, media;
int fdx, mii, fset, dxsuflo;
int chip_version;
@@ -1714,7 +1713,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dxsuflo = 1;
}
- dev = alloc_etherdev(0);
+ dev = alloc_etherdev(sizeof(*lp));
if (!dev) {
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_ERR PFX "Memory allocation failed.\n");
@@ -1805,25 +1804,22 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
}
dev->base_addr = ioaddr;
+ lp = netdev_priv(dev);
/* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */
- if ((lp =
- pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) {
+ if ((lp->init_block =
+ pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) {
if (pcnet32_debug & NETIF_MSG_PROBE)
printk(KERN_ERR PFX
"Consistent memory allocation failed.\n");
ret = -ENOMEM;
goto err_free_netdev;
}
-
- memset(lp, 0, sizeof(*lp));
- lp->dma_addr = lp_dma_addr;
lp->pci_dev = pdev;
spin_lock_init(&lp->lock);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- dev->priv = lp;
lp->name = chipname;
lp->shared_irq = shared;
lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */
@@ -1870,23 +1866,21 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
&& dev->dev_addr[2] == 0x75)
lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
- lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
- lp->init_block.tlen_rlen =
+ lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */
+ lp->init_block->tlen_rlen =
le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- lp->init_block.filter[0] = 0x00000000;
- lp->init_block.filter[1] = 0x00000000;
- lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->phys_addr[i] = dev->dev_addr[i];
+ lp->init_block->filter[0] = 0x00000000;
+ lp->init_block->filter[1] = 0x00000000;
+ lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
/* switch pcnet32 to 32bit mode */
a->write_bcr(ioaddr, 20, 2);
- a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private,
- init_block)) & 0xffff);
- a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private,
- init_block)) >> 16);
+ a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+ a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
if (pdev) { /* use the IRQ provided by PCI */
dev->irq = pdev->irq;
@@ -1992,7 +1986,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
err_free_ring:
pcnet32_free_ring(dev);
err_free_consistent:
- pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
+ lp->init_block, lp->init_dma_addr);
err_free_netdev:
free_netdev(dev);
err_release_region:
@@ -2003,7 +1998,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
/* if any allocation fails, caller must also call pcnet32_free_ring */
static int pcnet32_alloc_ring(struct net_device *dev, char *name)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
sizeof(struct pcnet32_tx_head) *
@@ -2070,7 +2065,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
static void pcnet32_free_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
kfree(lp->tx_skbuff);
lp->tx_skbuff = NULL;
@@ -2103,7 +2098,7 @@ static void pcnet32_free_ring(struct net_device *dev)
static int pcnet32_open(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 val;
int i;
@@ -2134,8 +2129,7 @@ static int pcnet32_open(struct net_device *dev)
"%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr),
(u32) (lp->rx_ring_dma_addr),
- (u32) (lp->dma_addr +
- offsetof(struct pcnet32_private, init_block)));
+ (u32) (lp->init_dma_addr));
/* set/reset autoselect bit */
val = lp->a.read_bcr(ioaddr, 2) & ~2;
@@ -2274,7 +2268,7 @@ static int pcnet32_open(struct net_device *dev)
}
#endif
- lp->init_block.mode =
+ lp->init_block->mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
pcnet32_load_multicast(dev);
@@ -2284,12 +2278,8 @@ static int pcnet32_open(struct net_device *dev)
}
/* Re-initialize the PCNET32, and start it when done. */
- lp->a.write_csr(ioaddr, 1, (lp->dma_addr +
- offsetof(struct pcnet32_private,
- init_block)) & 0xffff);
- lp->a.write_csr(ioaddr, 2,
- (lp->dma_addr +
- offsetof(struct pcnet32_private, init_block)) >> 16);
+ lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
+ lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
@@ -2316,8 +2306,7 @@ static int pcnet32_open(struct net_device *dev)
printk(KERN_DEBUG
"%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n",
dev->name, i,
- (u32) (lp->dma_addr +
- offsetof(struct pcnet32_private, init_block)),
+ (u32) (lp->init_dma_addr),
lp->a.read_csr(ioaddr, CSR0));
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2355,7 +2344,7 @@ static int pcnet32_open(struct net_device *dev)
static void pcnet32_purge_tx_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int i;
for (i = 0; i < lp->tx_ring_size; i++) {
@@ -2375,7 +2364,7 @@ static void pcnet32_purge_tx_ring(struct net_device *dev)
/* Initialize the PCNET32 Rx and Tx rings. */
static int pcnet32_init_ring(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int i;
lp->tx_full = 0;
@@ -2417,12 +2406,12 @@ static int pcnet32_init_ring(struct net_device *dev)
lp->tx_dma_addr[i] = 0;
}
- lp->init_block.tlen_rlen =
+ lp->init_block->tlen_rlen =
le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
for (i = 0; i < 6; i++)
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
- lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+ lp->init_block->phys_addr[i] = dev->dev_addr[i];
+ lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
+ lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
wmb(); /* Make sure all changes are visible */
return 0;
}
@@ -2433,7 +2422,7 @@ static int pcnet32_init_ring(struct net_device *dev)
*/
static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
int i;
@@ -2463,7 +2452,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
static void pcnet32_tx_timeout(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr, flags;
spin_lock_irqsave(&lp->lock, flags);
@@ -2504,7 +2493,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 status;
int entry;
@@ -2569,7 +2558,7 @@ pcnet32_interrupt(int irq, void *dev_id)
int boguscnt = max_interrupt_work;
ioaddr = dev->base_addr;
- lp = dev->priv;
+ lp = netdev_priv(dev);
spin_lock(&lp->lock);
@@ -2651,7 +2640,7 @@ pcnet32_interrupt(int irq, void *dev_id)
static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2692,7 +2681,7 @@ static int pcnet32_close(struct net_device *dev)
static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
unsigned long flags;
@@ -2706,8 +2695,8 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
/* taken from the sunlance driver, which it took from the depca driver */
static void pcnet32_load_multicast(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
- volatile struct pcnet32_init_block *ib = &lp->init_block;
+ struct pcnet32_private *lp = netdev_priv(dev);
+ volatile struct pcnet32_init_block *ib = lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
unsigned long ioaddr = dev->base_addr;
@@ -2756,7 +2745,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
static void pcnet32_set_multicast_list(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr, flags;
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
@@ -2767,12 +2756,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
if (netif_msg_hw(lp))
printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
dev->name);
- lp->init_block.mode =
+ lp->init_block->mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
- lp->init_block.mode =
+ lp->init_block->mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
@@ -2795,7 +2784,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
/* This routine assumes that the lp->lock is held */
static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
u16 val_out;
@@ -2811,7 +2800,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg_num)
/* This routine assumes that the lp->lock is held */
static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long ioaddr = dev->base_addr;
if (!lp->mii)
@@ -2823,7 +2812,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val)
static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int rc;
unsigned long flags;
@@ -2841,7 +2830,7 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int pcnet32_check_otherphy(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
struct mii_if_info mii = lp->mii_if;
u16 bmcr;
int i;
@@ -2888,7 +2877,7 @@ static int pcnet32_check_otherphy(struct net_device *dev)
static void pcnet32_check_media(struct net_device *dev, int verbose)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
int curr_link;
int prev_link = netif_carrier_ok(dev) ? 1 : 0;
u32 bcr9;
@@ -2944,7 +2933,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
static void pcnet32_watchdog(struct net_device *dev)
{
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unsigned long flags;
/* Print the link status if it has changed */
@@ -2960,12 +2949,13 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
if (dev) {
- struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_private *lp = netdev_priv(dev);
unregister_netdev(dev);
pcnet32_free_ring(dev);
release_region(dev->base_addr, PCNET32_TOTAL_SIZE);
- pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
+ lp->init_block, lp->init_dma_addr);
free_netdev(dev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
@@ -3040,12 +3030,13 @@ static void __exit pcnet32_cleanup_module(void)
struct net_device *next_dev;
while (pcnet32_dev) {
- struct pcnet32_private *lp = pcnet32_dev->priv;
+ struct pcnet32_private *lp = netdev_priv(pcnet32_dev);
next_dev = lp->next;
unregister_netdev(pcnet32_dev);
pcnet32_free_ring(pcnet32_dev);
release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
- pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr);
+ pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block),
+ lp->init_block, lp->init_dma_addr);
free_netdev(pcnet32_dev);
pcnet32_dev = next_dev;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index b31ce278bf3..fc4aee96cdf 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -35,10 +35,14 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-/* mdiobus_register
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
*
- * description: Called by a bus driver to bring up all the PHYs
- * on a given bus, and attach them to the bus
+ * Description: Called by a bus driver to bring up all the PHYs
+ * on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
*/
int mdiobus_register(struct mii_bus *bus)
{
@@ -114,10 +118,13 @@ void mdiobus_unregister(struct mii_bus *bus)
}
EXPORT_SYMBOL(mdiobus_unregister);
-/* mdio_bus_match
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
*
- * description: Given a PHY device, and a PHY driver, return 1 if
- * the driver supports the device. Otherwise, return 0
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ * the driver supports the device. Otherwise, return 0.
*/
static int mdio_bus_match(struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index c94a1fb3a4b..f71dab34766 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -39,7 +39,9 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-/* Convenience function to print out the current phy status
+/**
+ * phy_print_status - Convenience function to print out the current phy status
+ * @phydev: the phy_device struct
*/
void phy_print_status(struct phy_device *phydev)
{
@@ -55,10 +57,15 @@ void phy_print_status(struct phy_device *phydev)
EXPORT_SYMBOL(phy_print_status);
-/* Convenience functions for reading/writing a given PHY
- * register. They MUST NOT be called from interrupt context,
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ *
+ * NOTE: MUST NOT be called from interrupt context,
* because the bus read/write functions may wait for an interrupt
- * to conclude the operation. */
+ * to conclude the operation.
+ */
int phy_read(struct phy_device *phydev, u16 regnum)
{
int retval;
@@ -72,6 +79,16 @@ int phy_read(struct phy_device *phydev, u16 regnum)
}
EXPORT_SYMBOL(phy_read);
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ *
+ * NOTE: MUST NOT be called from interrupt context,
+ * because the bus read/write functions may wait for an interrupt
+ * to conclude the operation.
+ */
int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
{
int err;
@@ -85,7 +102,15 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val)
}
EXPORT_SYMBOL(phy_write);
-
+/**
+ * phy_clear_interrupt - Ack the phy device's interrupt
+ * @phydev: the phy_device struct
+ *
+ * If the @phydev driver has an ack_interrupt function, call it to
+ * ack and clear the phy device's interrupt.
+ *
+ * Returns 0 on success on < 0 on error.
+ */
int phy_clear_interrupt(struct phy_device *phydev)
{
int err = 0;
@@ -96,7 +121,13 @@ int phy_clear_interrupt(struct phy_device *phydev)
return err;
}
-
+/**
+ * phy_config_interrupt - configure the PHY device for the requested interrupts
+ * @phydev: the phy_device struct
+ * @interrupts: interrupt flags to configure for this @phydev
+ *
+ * Returns 0 on success on < 0 on error.
+ */
int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
{
int err = 0;
@@ -109,9 +140,11 @@ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts)
}
-/* phy_aneg_done
+/**
+ * phy_aneg_done - return auto-negotiation status
+ * @phydev: target phy_device struct
*
- * description: Reads the status register and returns 0 either if
+ * Description: Reads the status register and returns 0 either if
* auto-negotiation is incomplete, or if there was an error.
* Returns BMSR_ANEGCOMPLETE if auto-negotiation is done.
*/
@@ -173,9 +206,12 @@ static const struct phy_setting settings[] = {
#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
-/* phy_find_setting
+/**
+ * phy_find_setting - find a PHY settings array entry that matches speed & duplex
+ * @speed: speed to match
+ * @duplex: duplex to match
*
- * description: Searches the settings array for the setting which
+ * Description: Searches the settings array for the setting which
* matches the desired speed and duplex, and returns the index
* of that setting. Returns the index of the last setting if
* none of the others match.
@@ -192,11 +228,12 @@ static inline int phy_find_setting(int speed, int duplex)
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
-/* phy_find_valid
- * idx: The first index in settings[] to search
- * features: A mask of the valid settings
+/**
+ * phy_find_valid - find a PHY setting that matches the requested features mask
+ * @idx: The first index in settings[] to search
+ * @features: A mask of the valid settings
*
- * description: Returns the index of the first valid setting less
+ * Description: Returns the index of the first valid setting less
* than or equal to the one pointed to by idx, as determined by
* the mask in features. Returns the index of the last setting
* if nothing else matches.
@@ -209,11 +246,13 @@ static inline int phy_find_valid(int idx, u32 features)
return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
}
-/* phy_sanitize_settings
+/**
+ * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex
+ * @phydev: the target phy_device struct
*
- * description: Make sure the PHY is set to supported speeds and
+ * Description: Make sure the PHY is set to supported speeds and
* duplexes. Drop down by one in this order: 1000/FULL,
- * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF
+ * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
*/
void phy_sanitize_settings(struct phy_device *phydev)
{
@@ -232,16 +271,17 @@ void phy_sanitize_settings(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_sanitize_settings);
-/* phy_ethtool_sset:
- * A generic ethtool sset function. Handles all the details
+/**
+ * phy_ethtool_sset - generic ethtool sset function, handles all the details
+ * @phydev: target phy_device struct
+ * @cmd: ethtool_cmd
*
* A few notes about parameter checking:
* - We don't set port or transceiver, so we don't care what they
* were set to.
* - phy_start_aneg() will make sure forced settings are sane, and
* choose the next best ones from the ones selected, so we don't
- * care if ethtool tries to give us bad values
- *
+ * care if ethtool tries to give us bad values.
*/
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
@@ -304,9 +344,15 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
}
EXPORT_SYMBOL(phy_ethtool_gset);
-/* Note that this function is currently incompatible with the
+/**
+ * phy_mii_ioctl - generic PHY MII ioctl interface
+ * @phydev: the phy_device struct
+ * @mii_data: MII ioctl data
+ * @cmd: ioctl cmd to execute
+ *
+ * Note that this function is currently incompatible with the
* PHYCONTROL layer. It changes registers without regard to
- * current state. Use at own risk
+ * current state. Use at own risk.
*/
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd)
@@ -336,6 +382,12 @@ int phy_mii_ioctl(struct phy_device *phydev,
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
+ if ((!phydev->autoneg) &&
+ (val & BMCR_SPEED1000))
+ phydev->speed = SPEED_1000;
+ else if ((!phydev->autoneg) &&
+ (val & BMCR_SPEED100))
+ phydev->speed = SPEED_100;
break;
case MII_ADVERTISE:
phydev->advertising = val;
@@ -358,13 +410,14 @@ int phy_mii_ioctl(struct phy_device *phydev,
return 0;
}
-/* phy_start_aneg
+/**
+ * phy_start_aneg - start auto-negotiation for this PHY device
+ * @phydev: the phy_device struct
*
- * description: Sanitizes the settings (if we're not
- * autonegotiating them), and then calls the driver's
- * config_aneg function. If the PHYCONTROL Layer is operating,
- * we change the state to reflect the beginning of
- * Auto-negotiation or forcing.
+ * Description: Sanitizes the settings (if we're not autonegotiating
+ * them), and then calls the driver's config_aneg function.
+ * If the PHYCONTROL Layer is operating, we change the state to
+ * reflect the beginning of Auto-negotiation or forcing.
*/
int phy_start_aneg(struct phy_device *phydev)
{
@@ -400,15 +453,19 @@ EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
static void phy_timer(unsigned long data);
-/* phy_start_machine:
+/**
+ * phy_start_machine - start PHY state machine tracking
+ * @phydev: the phy_device struct
+ * @handler: callback function for state change notifications
*
- * description: The PHY infrastructure can run a state machine
+ * Description: The PHY infrastructure can run a state machine
* which tracks whether the PHY is starting up, negotiating,
* etc. This function starts the timer which tracks the state
- * of the PHY. If you want to be notified when the state
- * changes, pass in the callback, otherwise, pass NULL. If you
+ * of the PHY. If you want to be notified when the state changes,
+ * pass in the callback @handler, otherwise, pass NULL. If you
* want to maintain your own state machine, do not call this
- * function. */
+ * function.
+ */
void phy_start_machine(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
@@ -420,9 +477,11 @@ void phy_start_machine(struct phy_device *phydev,
mod_timer(&phydev->phy_timer, jiffies + HZ);
}
-/* phy_stop_machine
+/**
+ * phy_stop_machine - stop the PHY state machine tracking
+ * @phydev: target phy_device struct
*
- * description: Stops the state machine timer, sets the state to UP
+ * Description: Stops the state machine timer, sets the state to UP
* (unless it wasn't up yet). This function must be called BEFORE
* phy_detach.
*/
@@ -438,12 +497,14 @@ void phy_stop_machine(struct phy_device *phydev)
phydev->adjust_state = NULL;
}
-/* phy_force_reduction
+/**
+ * phy_force_reduction - reduce PHY speed/duplex settings by one step
+ * @phydev: target phy_device struct
*
- * description: Reduces the speed/duplex settings by
- * one notch. The order is so:
- * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF,
- * 10/FULL, 10/HALF. The function bottoms out at 10/HALF.
+ * Description: Reduces the speed/duplex settings by one notch,
+ * in this order--
+ * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF.
+ * The function bottoms out at 10/HALF.
*/
static void phy_force_reduction(struct phy_device *phydev)
{
@@ -464,7 +525,9 @@ static void phy_force_reduction(struct phy_device *phydev)
}
-/* phy_error:
+/**
+ * phy_error - enter HALTED state for this PHY device
+ * @phydev: target phy_device struct
*
* Moves the PHY to the HALTED state in response to a read
* or write error, and tells the controller the link is down.
@@ -478,9 +541,12 @@ void phy_error(struct phy_device *phydev)
spin_unlock(&phydev->lock);
}
-/* phy_interrupt
+/**
+ * phy_interrupt - PHY interrupt handler
+ * @irq: interrupt line
+ * @phy_dat: phy_device pointer
*
- * description: When a PHY interrupt occurs, the handler disables
+ * Description: When a PHY interrupt occurs, the handler disables
* interrupts, and schedules a work task to clear the interrupt.
*/
static irqreturn_t phy_interrupt(int irq, void *phy_dat)
@@ -501,7 +567,10 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
return IRQ_HANDLED;
}
-/* Enable the interrupts from the PHY side */
+/**
+ * phy_enable_interrupts - Enable the interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
int phy_enable_interrupts(struct phy_device *phydev)
{
int err;
@@ -517,7 +586,10 @@ int phy_enable_interrupts(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_enable_interrupts);
-/* Disable the PHY interrupts from the PHY side */
+/**
+ * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
int phy_disable_interrupts(struct phy_device *phydev)
{
int err;
@@ -543,13 +615,15 @@ phy_err:
}
EXPORT_SYMBOL(phy_disable_interrupts);
-/* phy_start_interrupts
+/**
+ * phy_start_interrupts - request and enable interrupts for a PHY device
+ * @phydev: target phy_device struct
*
- * description: Request the interrupt for the given PHY. If
- * this fails, then we set irq to PHY_POLL.
+ * Description: Request the interrupt for the given PHY.
+ * If this fails, then we set irq to PHY_POLL.
* Otherwise, we enable the interrupts in the PHY.
- * Returns 0 on success.
* This should only be called with a valid IRQ number.
+ * Returns 0 on success or < 0 on error.
*/
int phy_start_interrupts(struct phy_device *phydev)
{
@@ -574,6 +648,10 @@ int phy_start_interrupts(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_start_interrupts);
+/**
+ * phy_stop_interrupts - disable interrupts from a PHY device
+ * @phydev: target phy_device struct
+ */
int phy_stop_interrupts(struct phy_device *phydev)
{
int err;
@@ -584,10 +662,10 @@ int phy_stop_interrupts(struct phy_device *phydev)
phy_error(phydev);
/*
- * Finish any pending work; we might have been scheduled
- * to be called from keventd ourselves, though.
+ * Finish any pending work; we might have been scheduled to be called
+ * from keventd ourselves, but cancel_work_sync() handles that.
*/
- run_scheduled_work(&phydev->phy_queue);
+ cancel_work_sync(&phydev->phy_queue);
free_irq(phydev->irq, phydev);
@@ -596,7 +674,10 @@ int phy_stop_interrupts(struct phy_device *phydev)
EXPORT_SYMBOL(phy_stop_interrupts);
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+/**
+ * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
+ * @work: work_struct that describes the work to be done
+ */
static void phy_change(struct work_struct *work)
{
int err;
@@ -630,7 +711,10 @@ phy_err:
phy_error(phydev);
}
-/* Bring down the PHY link, and stop checking the status. */
+/**
+ * phy_stop - Bring down the PHY link, and stop checking the status
+ * @phydev: target phy_device struct
+ */
void phy_stop(struct phy_device *phydev)
{
spin_lock(&phydev->lock);
@@ -659,9 +743,11 @@ out_unlock:
}
-/* phy_start
+/**
+ * phy_start - start or restart a PHY device
+ * @phydev: target phy_device struct
*
- * description: Indicates the attached device's readiness to
+ * Description: Indicates the attached device's readiness to
* handle PHY-related work. Used during startup to start the
* PHY, and after a call to phy_stop() to resume operation.
* Also used to indicate the MDIO bus has cleared an error
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 8f01952c485..a8b74cdab1e 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -74,11 +74,13 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
}
EXPORT_SYMBOL(phy_device_create);
-/* get_phy_device
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
*
- * description: Reads the ID registers of the PHY at addr on the
- * bus, then allocates and returns the phy_device to
- * represent it.
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, then allocates and returns the phy_device to represent it.
*/
struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
{
@@ -112,23 +114,33 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
return dev;
}
-/* phy_prepare_link:
+/**
+ * phy_prepare_link - prepares the PHY layer to monitor link status
+ * @phydev: target phy_device struct
+ * @handler: callback function for link status change notifications
*
- * description: Tells the PHY infrastructure to handle the
+ * Description: Tells the PHY infrastructure to handle the
* gory details on monitoring link status (whether through
* polling or an interrupt), and to call back to the
* connected device driver when the link status changes.
* If you want to monitor your own link state, don't call
- * this function */
+ * this function.
+ */
void phy_prepare_link(struct phy_device *phydev,
void (*handler)(struct net_device *))
{
phydev->adjust_link = handler;
}
-/* phy_connect:
+/**
+ * phy_connect - connect an ethernet device to a PHY device
+ * @dev: the network device to connect
+ * @phy_id: the PHY device to connect
+ * @handler: callback function for state change notifications
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
*
- * description: Convenience function for connecting ethernet
+ * Description: Convenience function for connecting ethernet
* devices to PHY devices. The default behavior is for
* the PHY infrastructure to handle everything, and only notify
* the connected driver when the link status changes. If you
@@ -158,6 +170,10 @@ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
}
EXPORT_SYMBOL(phy_connect);
+/**
+ * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device
+ * @phydev: target phy_device struct
+ */
void phy_disconnect(struct phy_device *phydev)
{
if (phydev->irq > 0)
@@ -171,21 +187,25 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);
-/* phy_attach:
+static int phy_compare_id(struct device *dev, void *data)
+{
+ return strcmp((char *)data, dev->bus_id) ? 0 : 1;
+}
+
+/**
+ * phy_attach - attach a network device to a particular PHY device
+ * @dev: network device to attach
+ * @phy_id: PHY device to attach
+ * @flags: PHY device's dev_flags
+ * @interface: PHY device's interface
*
- * description: Called by drivers to attach to a particular PHY
+ * Description: Called by drivers to attach to a particular PHY
* device. The phy_device is found, and properly hooked up
* to the phy_driver. If no driver is attached, then the
* genphy_driver is used. The phy_device is given a ptr to
* the attaching device, and given a callback for link status
- * change. The phy_device is returned to the attaching
- * driver.
+ * change. The phy_device is returned to the attaching driver.
*/
-static int phy_compare_id(struct device *dev, void *data)
-{
- return strcmp((char *)data, dev->bus_id) ? 0 : 1;
-}
-
struct phy_device *phy_attach(struct net_device *dev,
const char *phy_id, u32 flags, phy_interface_t interface)
{
@@ -246,6 +266,10 @@ struct phy_device *phy_attach(struct net_device *dev,
}
EXPORT_SYMBOL(phy_attach);
+/**
+ * phy_detach - detach a PHY device from its network device
+ * @phydev: target phy_device struct
+ */
void phy_detach(struct phy_device *phydev)
{
phydev->attached_dev = NULL;
@@ -262,11 +286,13 @@ EXPORT_SYMBOL(phy_detach);
/* Generic PHY support and helper functions */
-/* genphy_config_advert
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotation parameters
+ * @phydev: target phy_device struct
*
- * description: Writes MII_ADVERTISE with the appropriate values,
+ * Description: Writes MII_ADVERTISE with the appropriate values,
* after sanitizing the values to make sure we only advertise
- * what is supported
+ * what is supported.
*/
int genphy_config_advert(struct phy_device *phydev)
{
@@ -328,11 +354,14 @@ int genphy_config_advert(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_config_advert);
-/* genphy_setup_forced
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
*
- * description: Configures MII_BMCR to force speed/duplex
+ * Description: Configures MII_BMCR to force speed/duplex
* to the values in phydev. Assumes that the values are valid.
- * Please see phy_sanitize_settings() */
+ * Please see phy_sanitize_settings().
+ */
int genphy_setup_forced(struct phy_device *phydev)
{
int ctl = BMCR_RESET;
@@ -361,7 +390,10 @@ int genphy_setup_forced(struct phy_device *phydev)
}
-/* Enable and Restart Autonegotiation */
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
int genphy_restart_aneg(struct phy_device *phydev)
{
int ctl;
@@ -382,11 +414,13 @@ int genphy_restart_aneg(struct phy_device *phydev)
}
-/* genphy_config_aneg
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
*
- * description: If auto-negotiation is enabled, we configure the
+ * Description: If auto-negotiation is enabled, we configure the
* advertising, and then restart auto-negotiation. If it is not
- * enabled, then we write the BMCR
+ * enabled, then we write the BMCR.
*/
int genphy_config_aneg(struct phy_device *phydev)
{
@@ -406,11 +440,13 @@ int genphy_config_aneg(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_config_aneg);
-/* genphy_update_link
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
*
- * description: Update the value in phydev->link to reflect the
+ * Description: Update the value in phydev->link to reflect the
* current link value. In order to do this, we need to read
- * the status register twice, keeping the second value
+ * the status register twice, keeping the second value.
*/
int genphy_update_link(struct phy_device *phydev)
{
@@ -437,9 +473,11 @@ int genphy_update_link(struct phy_device *phydev)
}
EXPORT_SYMBOL(genphy_update_link);
-/* genphy_read_status
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
*
- * description: Check the link, then figure out the current state
+ * Description: Check the link, then figure out the current state
* by comparing what we advertise with what the link partner
* advertises. Start by checking the gigabit possibilities,
* then move on to 10/100.
@@ -579,9 +617,11 @@ static int genphy_config_init(struct phy_device *phydev)
}
-/* phy_probe
+/**
+ * phy_probe - probe and init a PHY device
+ * @dev: device to probe and init
*
- * description: Take care of setting up the phy_device structure,
+ * Description: Take care of setting up the phy_device structure,
* set the state to READY (the driver's init function should
* set it to STARTING if needed).
*/
@@ -643,6 +683,10 @@ static int phy_remove(struct device *dev)
return 0;
}
+/**
+ * phy_driver_register - register a phy_driver with the PHY layer
+ * @new_driver: new phy_driver to register
+ */
int phy_driver_register(struct phy_driver *new_driver)
{
int retval;
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 6d596ca50cf..541168713f1 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -40,7 +40,6 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/rwsem.h>
#include <linux/stddef.h>
#include <linux/device.h>
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index 3f8115db4d5..f3e47d0c2b3 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -31,6 +31,7 @@
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
#include <linux/ppp_channel.h>
+#include <linux/kmod.h>
#include <net/sock.h>
@@ -114,6 +115,13 @@ static int pppox_create(struct socket *sock, int protocol)
goto out;
rc = -EPROTONOSUPPORT;
+#ifdef CONFIG_KMOD
+ if (!pppox_protos[protocol]) {
+ char buffer[32];
+ sprintf(buffer, "pppox-proto-%d", protocol);
+ request_module(buffer);
+ }
+#endif
if (!pppox_protos[protocol] ||
!try_module_get(pppox_protos[protocol]->owner))
goto out;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 7b80fb7a9d9..d8766c0e825 100755
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -39,7 +39,7 @@
#define DRV_NAME "qla3xxx"
#define DRV_STRING "QLogic ISP3XXX Network Driver"
-#define DRV_VERSION "v2.03.00-k3"
+#define DRV_VERSION "v2.03.00-k4"
#define PFX DRV_NAME " "
static const char ql3xxx_driver_name[] = DRV_NAME;
@@ -72,6 +72,30 @@ static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
/*
+ * These are the known PHY's which are used
+ */
+typedef enum {
+ PHY_TYPE_UNKNOWN = 0,
+ PHY_VITESSE_VSC8211,
+ PHY_AGERE_ET1011C,
+ MAX_PHY_DEV_TYPES
+} PHY_DEVICE_et;
+
+typedef struct {
+ PHY_DEVICE_et phyDevice;
+ u32 phyIdOUI;
+ u16 phyIdModel;
+ char *name;
+} PHY_DEVICE_INFO_t;
+
+static const PHY_DEVICE_INFO_t PHY_DEVICES[] =
+ {{PHY_TYPE_UNKNOWN, 0x000000, 0x0, "PHY_TYPE_UNKNOWN"},
+ {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"},
+ {PHY_AGERE_ET1011C, 0x00a0bc, 0x1, "PHY_AGERE_ET1011C"},
+};
+
+
+/*
* Caller must take hw_lock.
*/
static int ql_sem_spinlock(struct ql3_adapter *qdev,
@@ -662,7 +686,7 @@ static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
}
static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
- u16 regAddr, u16 value, u32 mac_index)
+ u16 regAddr, u16 value, u32 phyAddr)
{
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
@@ -680,7 +704,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
}
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
- PHYAddr[mac_index] | regAddr);
+ phyAddr | regAddr);
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
@@ -701,7 +725,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
}
static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
- u16 * value, u32 mac_index)
+ u16 * value, u32 phyAddr)
{
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
@@ -720,7 +744,7 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
}
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
- PHYAddr[mac_index] | regAddr);
+ phyAddr | regAddr);
ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
(MAC_MII_CONTROL_RC << 16));
@@ -850,28 +874,31 @@ static void ql_petbi_start_neg(struct ql3_adapter *qdev)
}
-static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev)
{
ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
- mac_index);
+ PHYAddr[qdev->mac_index]);
}
-static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev)
{
u16 reg;
/* Enable Auto-negotiation sense */
- ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
+ PHYAddr[qdev->mac_index]);
reg |= PETBI_TBI_AUTO_SENSE;
- ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
+ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
+ PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
- PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
+ PHYAddr[qdev->mac_index]);
ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
- mac_index);
+ PHYAddr[qdev->mac_index]);
}
static void ql_petbi_init(struct ql3_adapter *qdev)
@@ -880,10 +907,10 @@ static void ql_petbi_init(struct ql3_adapter *qdev)
ql_petbi_start_neg(qdev);
}
-static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_petbi_init_ex(struct ql3_adapter *qdev)
{
- ql_petbi_reset_ex(qdev, mac_index);
- ql_petbi_start_neg_ex(qdev, mac_index);
+ ql_petbi_reset_ex(qdev);
+ ql_petbi_start_neg_ex(qdev);
}
static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
@@ -896,33 +923,128 @@ static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
}
+static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr)
+{
+ printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name);
+ /* power down device bit 11 = 1 */
+ ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr);
+ /* enable diagnostic mode bit 2 = 1 */
+ ql_mii_write_reg_ex(qdev, 0x12, 0x840e, miiAddr);
+ /* 1000MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x8805, miiAddr);
+ /* 1000MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x11, 0xf03e, miiAddr);
+ /* 100MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x8806, miiAddr);
+ /* 100MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x11, 0x003e, miiAddr);
+ /* 10MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x8807, miiAddr);
+ /* 10MB amplitude adjust (see Agere errata) */
+ ql_mii_write_reg_ex(qdev, 0x11, 0x1f00, miiAddr);
+ /* point to hidden reg 0x2806 */
+ ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
+ /* Write new PHYAD w/bit 5 set */
+ ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
+ /*
+ * Disable diagnostic mode bit 2 = 0
+ * Power up device bit 11 = 0
+ * Link up (on) and activity (blink)
+ */
+ ql_mii_write_reg(qdev, 0x12, 0x840a);
+ ql_mii_write_reg(qdev, 0x00, 0x1140);
+ ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
+}
+
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
+ u16 phyIdReg0, u16 phyIdReg1)
+{
+ PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
+ u32 oui;
+ u16 model;
+ int i;
+
+ if (phyIdReg0 == 0xffff) {
+ return result;
+ }
+
+ if (phyIdReg1 == 0xffff) {
+ return result;
+ }
+
+ /* oui is split between two registers */
+ oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10);
+
+ model = (phyIdReg1 & PHY_MODEL_MASK) >> 4;
+
+ /* Scan table for this PHY */
+ for(i = 0; i < MAX_PHY_DEV_TYPES; i++) {
+ if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel))
+ {
+ result = PHY_DEVICES[i].phyDevice;
+
+ printk(KERN_INFO "%s: Phy: %s\n",
+ qdev->ndev->name, PHY_DEVICES[i].name);
+
+ break;
+ }
+ }
+
+ return result;
+}
+
static int ql_phy_get_speed(struct ql3_adapter *qdev)
{
u16 reg;
+ switch(qdev->phyType) {
+ case PHY_AGERE_ET1011C:
+ {
+ if (ql_mii_read_reg(qdev, 0x1A, &reg) < 0)
+ return 0;
+
+ reg = (reg >> 8) & 3;
+ break;
+ }
+ default:
if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
return 0;
reg = (((reg & 0x18) >> 3) & 3);
+ }
- if (reg == 2)
+ switch(reg) {
+ case 2:
return SPEED_1000;
- else if (reg == 1)
+ case 1:
return SPEED_100;
- else if (reg == 0)
+ case 0:
return SPEED_10;
- else
+ default:
return -1;
+ }
}
static int ql_is_full_dup(struct ql3_adapter *qdev)
{
u16 reg;
- if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
- return 0;
-
- return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+ switch(qdev->phyType) {
+ case PHY_AGERE_ET1011C:
+ {
+ if (ql_mii_read_reg(qdev, 0x1A, &reg))
+ return 0;
+
+ return ((reg & 0x0080) && (reg & 0x1000)) != 0;
+ }
+ case PHY_VITESSE_VSC8211:
+ default:
+ {
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
+ return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+ }
+ }
}
static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
@@ -935,6 +1057,73 @@ static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
return (reg & PHY_NEG_PAUSE) != 0;
}
+static int PHY_Setup(struct ql3_adapter *qdev)
+{
+ u16 reg1;
+ u16 reg2;
+ bool agereAddrChangeNeeded = false;
+ u32 miiAddr = 0;
+ int err;
+
+ /* Determine the PHY we are using by reading the ID's */
+ err = ql_mii_read_reg(qdev, PHY_ID_0_REG, &reg1);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ err = ql_mii_read_reg(qdev, PHY_ID_1_REG, &reg2);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ /* Check if we have a Agere PHY */
+ if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
+
+ /* Determine which MII address we should be using
+ determined by the index of the card */
+ if (qdev->mac_index == 0) {
+ miiAddr = MII_AGERE_ADDR_1;
+ } else {
+ miiAddr = MII_AGERE_ADDR_2;
+ }
+
+ err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
+ if(err != 0) {
+ printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
+ qdev->ndev->name);
+ return err;
+ }
+
+ /* We need to remember to initialize the Agere PHY */
+ agereAddrChangeNeeded = true;
+ }
+
+ /* Determine the particular PHY we have on board to apply
+ PHY specific initializations */
+ qdev->phyType = getPhyType(qdev, reg1, reg2);
+
+ if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
+ /* need this here so address gets changed */
+ phyAgereSpecificInit(qdev, miiAddr);
+ } else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
+ printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
+ return -EIO;
+ }
+
+ return 0;
+}
+
/*
* Caller holds hw_lock.
*/
@@ -1205,15 +1394,14 @@ static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
/*
* Caller holds hw_lock.
*/
-static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
- u32 mac_index)
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev)
{
struct ql3xxx_port_registers __iomem *port_regs =
qdev->mem_map_registers;
u32 bitToCheck = 0;
u32 temp;
- switch (mac_index) {
+ switch (qdev->mac_index) {
case 0:
bitToCheck = PORT_STATUS_F1_ENABLED;
break;
@@ -1238,27 +1426,96 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
}
}
-static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_reset_ex(struct ql3_adapter *qdev)
{
- ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
+ PHYAddr[qdev->mac_index]);
}
-static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev)
{
u16 reg;
+ u16 portConfiguration;
+
+ if(qdev->phyType == PHY_AGERE_ET1011C) {
+ /* turn off external loopback */
+ ql_mii_write_reg(qdev, 0x13, 0x0000);
+ }
+
+ if(qdev->mac_index == 0)
+ portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration;
+ else
+ portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration;
+
+ /* Some HBA's in the field are set to 0 and they need to
+ be reinterpreted with a default value */
+ if(portConfiguration == 0)
+ portConfiguration = PORT_CONFIG_DEFAULT;
+
+ /* Set the 1000 advertisements */
+ ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
+ PHYAddr[qdev->mac_index]);
+ reg &= ~PHY_GIG_ALL_PARAMS;
+
+ if(portConfiguration &
+ PORT_CONFIG_FULL_DUPLEX_ENABLED &
+ PORT_CONFIG_1000MB_SPEED) {
+ reg |= PHY_GIG_ADV_1000F;
+ }
+
+ if(portConfiguration &
+ PORT_CONFIG_HALF_DUPLEX_ENABLED &
+ PORT_CONFIG_1000MB_SPEED) {
+ reg |= PHY_GIG_ADV_1000H;
+ }
- ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
- PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+ ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
+ PHYAddr[qdev->mac_index]);
- ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
- ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
- mac_index);
+ /* Set the 10/100 & pause negotiation advertisements */
+ ql_mii_read_reg_ex(qdev, PHY_NEG_ADVER, &reg,
+ PHYAddr[qdev->mac_index]);
+ reg &= ~PHY_NEG_ALL_PARAMS;
+
+ if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED)
+ reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE;
+
+ if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
+ if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+ reg |= PHY_NEG_ADV_100F;
+
+ if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+ reg |= PHY_NEG_ADV_10F;
+ }
+
+ if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
+ if(portConfiguration & PORT_CONFIG_100MB_SPEED)
+ reg |= PHY_NEG_ADV_100H;
+
+ if(portConfiguration & PORT_CONFIG_10MB_SPEED)
+ reg |= PHY_NEG_ADV_10H;
+ }
+
+ if(portConfiguration &
+ PORT_CONFIG_1000MB_SPEED) {
+ reg |= 1;
+ }
+
+ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
+ PHYAddr[qdev->mac_index]);
+
+ ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
+
+ ql_mii_write_reg_ex(qdev, CONTROL_REG,
+ reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
+ PHYAddr[qdev->mac_index]);
}
-static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+static void ql_phy_init_ex(struct ql3_adapter *qdev)
{
- ql_phy_reset_ex(qdev, mac_index);
- ql_phy_start_neg_ex(qdev, mac_index);
+ ql_phy_reset_ex(qdev);
+ PHY_Setup(qdev);
+ ql_phy_start_neg_ex(qdev);
}
/*
@@ -1295,14 +1552,17 @@ static int ql_port_start(struct ql3_adapter *qdev)
{
if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
(QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
- 2) << 7))
+ 2) << 7)) {
+ printk(KERN_ERR "%s: Could not get hw lock for GIO\n",
+ qdev->ndev->name);
return -1;
+ }
if (ql_is_fiber(qdev)) {
ql_petbi_init(qdev);
} else {
/* Copper port */
- ql_phy_init_ex(qdev, qdev->mac_index);
+ ql_phy_init_ex(qdev);
}
ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
@@ -1453,7 +1713,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev)
*/
static void ql_get_phy_owner(struct ql3_adapter *qdev)
{
- if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ if (ql_this_adapter_controls_port(qdev))
set_bit(QL_LINK_MASTER,&qdev->flags);
else
clear_bit(QL_LINK_MASTER,&qdev->flags);
@@ -1467,11 +1727,11 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev)
ql_mii_enable_scan_mode(qdev);
if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
- if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
- ql_petbi_init_ex(qdev, qdev->mac_index);
+ if (ql_this_adapter_controls_port(qdev))
+ ql_petbi_init_ex(qdev);
} else {
- if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
- ql_phy_init_ex(qdev, qdev->mac_index);
+ if (ql_this_adapter_controls_port(qdev))
+ ql_phy_init_ex(qdev);
}
}
@@ -1624,6 +1884,23 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value)
qdev->msg_enable = value;
}
+static void ql_get_pauseparam(struct net_device *ndev,
+ struct ethtool_pauseparam *pause)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ u32 reg;
+ if(qdev->mac_index == 0)
+ reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg);
+ else
+ reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg);
+
+ pause->autoneg = ql_get_auto_cfg_status(qdev);
+ pause->rx_pause = (reg & MAC_CONFIG_REG_RF) >> 2;
+ pause->tx_pause = (reg & MAC_CONFIG_REG_TF) >> 1;
+}
+
static const struct ethtool_ops ql3xxx_ethtool_ops = {
.get_settings = ql_get_settings,
.get_drvinfo = ql_get_drvinfo,
@@ -1631,6 +1908,7 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel,
+ .get_pauseparam = ql_get_pauseparam,
};
static int ql_populate_free_queue(struct ql3_adapter *qdev)
@@ -1815,14 +2093,14 @@ invalid_seg_count:
atomic_inc(&qdev->tx_count);
}
-void ql_get_sbuf(struct ql3_adapter *qdev)
+static void ql_get_sbuf(struct ql3_adapter *qdev)
{
if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
qdev->small_buf_index = 0;
qdev->small_buf_release_cnt++;
}
-struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
+static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev)
{
struct ql_rcv_buf_cb *lrg_buf_cb = NULL;
lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index];
@@ -3074,6 +3352,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
goto out;
}
+ PHY_Setup(qdev);
ql_init_scan_mode(qdev);
ql_get_phy_owner(qdev);
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
index 0203f88f054..4a832c46c27 100755
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -293,6 +293,16 @@ struct net_rsp_iocb {
#define MII_SCAN_REGISTER 0x00000001
+#define PHY_ID_0_REG 2
+#define PHY_ID_1_REG 3
+
+#define PHY_OUI_1_MASK 0xfc00
+#define PHY_MODEL_MASK 0x03f0
+
+/* Address for the Agere Phy */
+#define MII_AGERE_ADDR_1 0x00001000
+#define MII_AGERE_ADDR_2 0x00001100
+
/* 32-bit ispControlStatus */
enum {
ISP_CONTROL_NP_MASK = 0x0003,
@@ -789,6 +799,7 @@ enum {
PHY_CTRL_LOOPBACK = 0x4000,
PETBI_CONTROL_REG = 0x00,
+ PETBI_CTRL_ALL_PARAMS = 0x7140,
PETBI_CTRL_SOFT_RESET = 0x8000,
PETBI_CTRL_AUTO_NEG = 0x1000,
PETBI_CTRL_RESTART_NEG = 0x0200,
@@ -811,6 +822,23 @@ enum {
PETBI_EXPANSION_REG = 0x06,
PETBI_EXP_PAGE_RX = 0x0002,
+ PHY_GIG_CONTROL = 9,
+ PHY_GIG_ENABLE_MAN = 0x1000, /* Enable Master/Slave Manual Config*/
+ PHY_GIG_SET_MASTER = 0x0800, /* Set Master (slave if clear)*/
+ PHY_GIG_ALL_PARAMS = 0x0300,
+ PHY_GIG_ADV_1000F = 0x0200,
+ PHY_GIG_ADV_1000H = 0x0100,
+
+ PHY_NEG_ADVER = 4,
+ PHY_NEG_ALL_PARAMS = 0x0fe0,
+ PHY_NEG_ASY_PAUSE = 0x0800,
+ PHY_NEG_SYM_PAUSE = 0x0400,
+ PHY_NEG_ADV_SPEED = 0x01e0,
+ PHY_NEG_ADV_100F = 0x0100,
+ PHY_NEG_ADV_100H = 0x0080,
+ PHY_NEG_ADV_10F = 0x0040,
+ PHY_NEG_ADV_10H = 0x0020,
+
PETBI_TBI_CTRL = 0x11,
PETBI_TBI_RESET = 0x8000,
PETBI_TBI_AUTO_SENSE = 0x0100,
@@ -826,8 +854,7 @@ enum {
PHY_AUX_RESET_STICK = 0x0002,
PHY_NEG_PAUSE = 0x0400,
PHY_CTRL_SOFT_RESET = 0x8000,
- PHY_NEG_ADVER = 4,
- PHY_NEG_ADV_SPEED = 0x01e0,
+ PHY_CTRL_AUTO_NEG = 0x1000,
PHY_CTRL_RESTART_NEG = 0x0200,
};
enum {
@@ -892,6 +919,7 @@ enum {EEPROM_SIZE = FM93C86A_SIZE_16,
u16 pauseThreshold_mac;
u16 resumeThreshold_mac;
u16 portConfiguration;
+#define PORT_CONFIG_DEFAULT 0xf700
#define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000
#define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000
#define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000
@@ -1259,6 +1287,7 @@ struct ql3_adapter {
struct delayed_work tx_timeout_work;
u32 max_frame_size;
u32 device_id;
+ u16 phyType;
};
#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 33fb7f3b704..4cb710bbe72 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -1,6 +1,6 @@
/************************************************************************
* regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 600d3ff347f..290e1c1f30c 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -1,6 +1,6 @@
/************************************************************************
* s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
@@ -84,7 +84,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.17.1"
+#define DRV_VERSION "2.0.22.1"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
}
/* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */
-int vlan_strip_flag;
+static int vlan_strip_flag;
/* Unregister the vlan */
static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
@@ -394,7 +394,6 @@ static const u64 fix_mac[] = {
END_SIGN
};
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
@@ -516,7 +515,7 @@ static int init_shared_mem(struct s2io_nic *nic)
mac_control->fifos[i].list_info = kmalloc(list_holder_size,
GFP_KERNEL);
if (!mac_control->fifos[i].list_info) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"Malloc failed for list_info\n");
return -ENOMEM;
}
@@ -542,9 +541,9 @@ static int init_shared_mem(struct s2io_nic *nic)
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
if (!tmp_v) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"pci_alloc_consistent ");
- DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ DBG_PRINT(INFO_DBG, "failed for TxDL\n");
return -ENOMEM;
}
/* If we got a zero DMA address(can happen on
@@ -561,9 +560,9 @@ static int init_shared_mem(struct s2io_nic *nic)
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
if (!tmp_v) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"pci_alloc_consistent ");
- DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+ DBG_PRINT(INFO_DBG, "failed for TxDL\n");
return -ENOMEM;
}
}
@@ -2187,7 +2186,7 @@ static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
/* skb_shinfo(skb)->frag_list will have L4 data payload */
skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
if (skb_shinfo(skb)->frag_list == NULL) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
return -ENOMEM ;
}
frag_list = skb_shinfo(skb)->frag_list;
@@ -2242,6 +2241,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
struct buffAdd *ba;
unsigned long flags;
struct RxD_t *first_rxdp = NULL;
+ u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
mac_control = &nic->mac_control;
config = &nic->config;
@@ -2313,8 +2313,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
- DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
@@ -2342,7 +2342,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* payload
*/
+ /* save the buffer pointers to avoid frequent dma mapping */
+ Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
+ Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
memset(rxdp, 0, sizeof(struct RxD3));
+ /* restore the buffer pointers for dma sync*/
+ ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
+ ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+
ba = &mac_control->rings[ring_no].ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
@@ -2573,8 +2580,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
@@ -2590,8 +2597,8 @@ no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Poll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
}
}
@@ -2640,8 +2647,8 @@ static void s2io_netpoll(struct net_device *dev)
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
}
}
@@ -3307,6 +3314,7 @@ static void s2io_reset(struct s2io_nic * sp)
u16 subid, pci_cmd;
int i;
u16 val16;
+ unsigned long long reset_cnt = 0;
DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
__FUNCTION__, sp->dev->name);
@@ -3372,6 +3380,11 @@ new_way:
/* Reset device statistics maintained by OS */
memset(&sp->stats, 0, sizeof (struct net_device_stats));
+ /* save reset count */
+ reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt;
+ memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
+ /* restore reset count */
+ sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt;
/* SXE-002: Configure link and activity LED to turn it off */
subid = sp->pdev->subsystem_device;
@@ -3659,7 +3672,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
GFP_KERNEL);
if (nic->entries == NULL) {
- DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
return -ENOMEM;
}
memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
@@ -3668,7 +3681,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
GFP_KERNEL);
if (nic->s2io_entries == NULL) {
- DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
+ DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__);
kfree(nic->entries);
return -ENOMEM;
}
@@ -4019,7 +4032,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
DBG_PRINT(INTR_DBG, "PANIC levels\n");
if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "Out of memory in %s",
+ DBG_PRINT(INFO_DBG, "Out of memory in %s",
__FUNCTION__);
clear_bit(0, (&sp->tasklet_status));
return -1;
@@ -4029,8 +4042,8 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
tasklet_schedule(&sp->task);
} else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
}
@@ -4279,9 +4292,7 @@ static void s2io_updt_stats(struct s2io_nic *sp)
if (cnt == 5)
break; /* Updt failed */
} while(1);
- } else {
- memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
- }
+ }
}
/**
@@ -5949,12 +5960,12 @@ static void s2io_tasklet(unsigned long dev_addr)
for (i = 0; i < config->rx_ring_num; i++) {
ret = fill_rx_buffers(sp, i);
if (ret == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s: Out of ",
+ DBG_PRINT(INFO_DBG, "%s: Out of ",
dev->name);
DBG_PRINT(ERR_DBG, "memory in tasklet\n");
break;
} else if (ret == -EFILL) {
- DBG_PRINT(ERR_DBG,
+ DBG_PRINT(INFO_DBG,
"%s: Rx Ring %d is full\n",
dev->name, i);
break;
@@ -6065,8 +6076,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
- DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+ DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
return -ENOMEM ;
}
/* storing the mapped addr in a temp variable
@@ -6088,7 +6099,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
dev->name);
return -ENOMEM;
}
@@ -6115,7 +6126,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
} else {
*skb = dev_alloc_skb(size);
if (!(*skb)) {
- DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
+ DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n",
dev->name);
return -ENOMEM;
}
@@ -6616,7 +6627,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
/* Updating statistics */
rxdp->Host_Control = 0;
- sp->rx_pkt_count++;
sp->stats.rx_packets++;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
@@ -7252,7 +7262,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
goto register_failed;
}
s2io_vpd_read(sp);
- DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
sp->product_name, get_xena_rev_id(sp->pdev));
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 803137ca4b6..a656d18b33d 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1,6 +1,6 @@
/************************************************************************
* s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
- * Copyright(c) 2002-2005 Neterion Inc.
+ * Copyright(c) 2002-2007 Neterion Inc.
* This software may be used and distributed according to the terms of
* the GNU General Public License (GPL), incorporated herein by reference.
@@ -760,7 +760,6 @@ struct s2io_nic {
#define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
- struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
struct net_device_stats stats;
int high_dma_flag;
@@ -794,11 +793,6 @@ struct s2io_nic {
u16 all_multi_pos;
u16 promisc_flg;
- u16 tx_pkt_count;
- u16 rx_pkt_count;
- u16 tx_err_count;
- u16 rx_err_count;
-
/* Id timer, used to blink NIC to physically identify NIC. */
struct timer_list id_timer;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index 0a3a379b634..132e2148b21 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -95,19 +95,28 @@ MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
#endif
#ifdef CONFIG_SBMAC_COALESCE
-static int int_pktcnt = 0;
-module_param(int_pktcnt, int, S_IRUGO);
-MODULE_PARM_DESC(int_pktcnt, "Packet count");
+static int int_pktcnt_tx = 255;
+module_param(int_pktcnt_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count");
-static int int_timeout = 0;
-module_param(int_timeout, int, S_IRUGO);
-MODULE_PARM_DESC(int_timeout, "Timeout value");
+static int int_timeout_tx = 255;
+module_param(int_timeout_tx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_tx, "TX timeout value");
+
+static int int_pktcnt_rx = 64;
+module_param(int_pktcnt_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count");
+
+static int int_timeout_rx = 64;
+module_param(int_timeout_rx, int, S_IRUGO);
+MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
#endif
#include <asm/sibyte/sb1250.h>
#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
#include <asm/sibyte/bcm1480_regs.h>
#include <asm/sibyte/bcm1480_int.h>
+#define R_MAC_DMA_OODPKTLOST_RX R_MAC_DMA_OODPKTLOST
#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_int.h>
@@ -155,8 +164,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
#define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES)
-#define SBMAC_MAX_TXDESCR 32
-#define SBMAC_MAX_RXDESCR 32
+#define SBMAC_MAX_TXDESCR 256
+#define SBMAC_MAX_RXDESCR 256
#define ETHER_ALIGN 2
#define ETHER_ADDR_LEN 6
@@ -185,10 +194,10 @@ typedef struct sbmacdma_s {
* associated with it.
*/
- struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
- int sbdma_channel; /* channel number */
+ struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */
+ int sbdma_channel; /* channel number */
int sbdma_txdir; /* direction (1=transmit) */
- int sbdma_maxdescr; /* total # of descriptors in ring */
+ int sbdma_maxdescr; /* total # of descriptors in ring */
#ifdef CONFIG_SBMAC_COALESCE
int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/
int sbdma_int_timeout; /* # usec rx/tx interrupt */
@@ -197,13 +206,16 @@ typedef struct sbmacdma_s {
volatile void __iomem *sbdma_config0; /* DMA config register 0 */
volatile void __iomem *sbdma_config1; /* DMA config register 1 */
volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */
- volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
+ volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */
volatile void __iomem *sbdma_curdscr; /* current descriptor address */
+ volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
+
/*
* This stuff is for maintenance of the ring
*/
+ sbdmadscr_t *sbdma_dscrtable_unaligned;
sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */
sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */
@@ -286,8 +298,8 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
static void sbdma_emptyring(sbmacdma_t *d);
static void sbdma_fillring(sbmacdma_t *d);
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d);
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d);
+static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll);
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
static int sbmac_initctx(struct sbmac_softc *s);
static void sbmac_channel_start(struct sbmac_softc *s);
static void sbmac_channel_stop(struct sbmac_softc *s);
@@ -308,6 +320,8 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
static void sbmac_set_rx_mode(struct net_device *dev);
static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int sbmac_close(struct net_device *dev);
+static int sbmac_poll(struct net_device *poll_dev, int *budget);
+
static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
static int sbmac_mii_probe(struct net_device *dev);
@@ -679,6 +693,10 @@ static void sbdma_initctx(sbmacdma_t *d,
int txrx,
int maxdescr)
{
+#ifdef CONFIG_SBMAC_COALESCE
+ int int_pktcnt, int_timeout;
+#endif
+
/*
* Save away interesting stuff in the structure
*/
@@ -728,6 +746,11 @@ static void sbdma_initctx(sbmacdma_t *d,
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT);
d->sbdma_curdscr =
s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR);
+ if (d->sbdma_txdir)
+ d->sbdma_oodpktlost = NULL;
+ else
+ d->sbdma_oodpktlost =
+ s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX);
/*
* Allocate memory for the ring
@@ -735,6 +758,7 @@ static void sbdma_initctx(sbmacdma_t *d,
d->sbdma_maxdescr = maxdescr;
+ d->sbdma_dscrtable_unaligned =
d->sbdma_dscrtable = (sbdmadscr_t *)
kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
@@ -765,12 +789,14 @@ static void sbdma_initctx(sbmacdma_t *d,
* Setup Rx/Tx DMA coalescing defaults
*/
+ int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx;
if ( int_pktcnt ) {
d->sbdma_int_pktcnt = int_pktcnt;
} else {
d->sbdma_int_pktcnt = 1;
}
+ int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx;
if ( int_timeout ) {
d->sbdma_int_timeout = int_timeout;
} else {
@@ -1125,32 +1151,63 @@ static void sbdma_fillring(sbmacdma_t *d)
}
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sbmac_netpoll(struct net_device *netdev)
+{
+ struct sbmac_softc *sc = netdev_priv(netdev);
+ int irq = sc->sbm_dev->irq;
+
+ __raw_writeq(0, sc->sbm_imr);
+
+ sbmac_intr(irq, netdev, NULL);
+
+#ifdef CONFIG_SBMAC_COALESCE
+ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
+ sc->sbm_imr);
+#else
+ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
+#endif
+}
+#endif
/**********************************************************************
- * SBDMA_RX_PROCESS(sc,d)
+ * SBDMA_RX_PROCESS(sc,d,work_to_do,poll)
*
* Process "completed" receive buffers on the specified DMA channel.
- * Note that this isn't really ideal for priority channels, since
- * it processes all of the packets on a given channel before
- * returning.
*
* Input parameters:
- * sc - softc structure
- * d - DMA channel context
+ * sc - softc structure
+ * d - DMA channel context
+ * work_to_do - no. of packets to process before enabling interrupt
+ * again (for NAPI)
+ * poll - 1: using polling (for NAPI)
*
* Return value:
* nothing
********************************************************************* */
-static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
+ int work_to_do, int poll)
{
int curidx;
int hwidx;
sbdmadscr_t *dsc;
struct sk_buff *sb;
int len;
+ int work_done = 0;
+ int dropped = 0;
- for (;;) {
+ prefetch(d);
+
+again:
+ /* Check if the HW dropped any frames */
+ sc->sbm_stats.rx_fifo_errors
+ += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
+ __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
+
+ while (work_to_do-- > 0) {
/*
* figure out where we are (as an index) and where
* the hardware is (also as an index)
@@ -1162,7 +1219,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* (sbdma_remptr) and the physical address (sbdma_curdscr CSR)
*/
- curidx = d->sbdma_remptr - d->sbdma_dscrtable;
+ dsc = d->sbdma_remptr;
+ curidx = dsc - d->sbdma_dscrtable;
+
+ prefetch(dsc);
+ prefetch(&d->sbdma_ctxtable[curidx]);
+
hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
@@ -1173,13 +1235,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
if (curidx == hwidx)
- break;
+ goto done;
/*
* Otherwise, get the packet's sk_buff ptr back
*/
- dsc = &(d->sbdma_dscrtable[curidx]);
sb = d->sbdma_ctxtable[curidx];
d->sbdma_ctxtable[curidx] = NULL;
@@ -1191,7 +1252,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* receive ring.
*/
- if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) {
+ if (likely (!(dsc->dscr_a & M_DMA_ETHRX_BAD))) {
/*
* Add a new buffer to replace the old one. If we fail
@@ -1199,9 +1260,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* packet and put it right back on the receive ring.
*/
- if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) {
- sc->sbm_stats.rx_dropped++;
+ if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
+ -ENOBUFS)) {
+ sc->sbm_stats.rx_dropped++;
sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
+ /* No point in continuing at the moment */
+ printk(KERN_ERR "dropped packet (1)\n");
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+ goto done;
} else {
/*
* Set length into the packet
@@ -1213,8 +1279,6 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* receive ring. Pass the buffer to
* the kernel
*/
- sc->sbm_stats.rx_bytes += len;
- sc->sbm_stats.rx_packets++;
sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev);
/* Check hw IPv4/TCP checksum if supported */
if (sc->rx_hw_checksum == ENABLE) {
@@ -1226,8 +1290,22 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
sb->ip_summed = CHECKSUM_NONE;
}
}
-
- netif_rx(sb);
+ prefetch(sb->data);
+ prefetch((const void *)(((char *)sb->data)+32));
+ if (poll)
+ dropped = netif_receive_skb(sb);
+ else
+ dropped = netif_rx(sb);
+
+ if (dropped == NET_RX_DROP) {
+ sc->sbm_stats.rx_dropped++;
+ d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+ goto done;
+ }
+ else {
+ sc->sbm_stats.rx_bytes += len;
+ sc->sbm_stats.rx_packets++;
+ }
}
} else {
/*
@@ -1244,12 +1322,16 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
-
+ work_done++;
}
+ if (!poll) {
+ work_to_do = 32;
+ goto again; /* collect fifo drop statistics again */
+ }
+done:
+ return work_done;
}
-
-
/**********************************************************************
* SBDMA_TX_PROCESS(sc,d)
*
@@ -1261,22 +1343,30 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*
* Input parameters:
* sc - softc structure
- * d - DMA channel context
+ * d - DMA channel context
+ * poll - 1: using polling (for NAPI)
*
* Return value:
* nothing
********************************************************************* */
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
+static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
{
int curidx;
int hwidx;
sbdmadscr_t *dsc;
struct sk_buff *sb;
unsigned long flags;
+ int packets_handled = 0;
spin_lock_irqsave(&(sc->sbm_lock), flags);
+ if (d->sbdma_remptr == d->sbdma_addptr)
+ goto end_unlock;
+
+ hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+ d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+
for (;;) {
/*
* figure out where we are (as an index) and where
@@ -1290,8 +1380,6 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
*/
curidx = d->sbdma_remptr - d->sbdma_dscrtable;
- hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
- d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
/*
* If they're the same, that means we've processed all
@@ -1329,6 +1417,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
+ packets_handled++;
+
}
/*
@@ -1337,8 +1427,10 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d)
* watermark on the transmit queue.
*/
- netif_wake_queue(d->sbdma_eth->sbm_dev);
+ if (packets_handled)
+ netif_wake_queue(d->sbdma_eth->sbm_dev);
+end_unlock:
spin_unlock_irqrestore(&(sc->sbm_lock), flags);
}
@@ -1412,9 +1504,9 @@ static int sbmac_initctx(struct sbmac_softc *s)
static void sbdma_uninitctx(struct sbmacdma_s *d)
{
- if (d->sbdma_dscrtable) {
- kfree(d->sbdma_dscrtable);
- d->sbdma_dscrtable = NULL;
+ if (d->sbdma_dscrtable_unaligned) {
+ kfree(d->sbdma_dscrtable_unaligned);
+ d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = NULL;
}
if (d->sbdma_ctxtable) {
@@ -1612,15 +1704,9 @@ static void sbmac_channel_start(struct sbmac_softc *s)
#endif
#ifdef CONFIG_SBMAC_COALESCE
- /*
- * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0
- */
__raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr);
#else
- /*
- * Accept any kind of interrupt on TX and RX DMA channel 0
- */
__raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
(M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr);
#endif
@@ -2053,57 +2139,46 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance)
uint64_t isr;
int handled = 0;
- for (;;) {
-
- /*
- * Read the ISR (this clears the bits in the real
- * register, except for counter addr)
- */
+ /*
+ * Read the ISR (this clears the bits in the real
+ * register, except for counter addr)
+ */
- isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
+ isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR;
- if (isr == 0)
- break;
+ if (isr == 0)
+ return IRQ_RETVAL(0);
+ handled = 1;
- handled = 1;
-
- /*
- * Transmits on channel 0
- */
+ /*
+ * Transmits on channel 0
+ */
- if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
- sbdma_tx_process(sc,&(sc->sbm_txdma));
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+ sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
+#ifdef CONFIG_NETPOLL_TRAP
+ if (netpoll_trap()) {
+ if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
+ __netif_schedule(dev);
}
+#endif
+ }
- /*
- * Receives on channel 0
- */
-
- /*
- * It's important to test all the bits (or at least the
- * EOP_SEEN bit) when deciding to do the RX process
- * particularly when coalescing, to make sure we
- * take care of the following:
- *
- * If you have some packets waiting (have been received
- * but no interrupt) and get a TX interrupt before
- * the RX timer or counter expires, reading the ISR
- * above will clear the timer and counter, and you
- * won't get another interrupt until a packet shows
- * up to start the timer again. Testing
- * EOP_SEEN here takes care of this case.
- * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0)
- */
-
-
- if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
- sbdma_rx_process(sc,&(sc->sbm_rxdma));
+ if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
+ if (netif_rx_schedule_prep(dev)) {
+ __raw_writeq(0, sc->sbm_imr);
+ __netif_rx_schedule(dev);
+ /* Depend on the exit from poll to reenable intr */
+ }
+ else {
+ /* may leave some packets behind */
+ sbdma_rx_process(sc,&(sc->sbm_rxdma),
+ SBMAC_MAX_RXDESCR * 2, 0);
}
}
return IRQ_RETVAL(handled);
}
-
/**********************************************************************
* SBMAC_START_TX(skb,dev)
*
@@ -2233,8 +2308,6 @@ static void sbmac_setmulti(struct sbmac_softc *sc)
}
}
-
-
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
/**********************************************************************
* SBMAC_PARSE_XDIGIT(str)
@@ -2397,8 +2470,13 @@ static int sbmac_init(struct net_device *dev, int idx)
dev->do_ioctl = sbmac_mii_ioctl;
dev->tx_timeout = sbmac_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ dev->poll = sbmac_poll;
+ dev->weight = 16;
dev->change_mtu = sb1250_change_mtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = sbmac_netpoll;
+#endif
/* This is needed for PASS2 for Rx H/W checksum feature */
sbmac_set_iphdr_offset(sc);
@@ -2796,7 +2874,39 @@ static int sbmac_close(struct net_device *dev)
return 0;
}
+static int sbmac_poll(struct net_device *dev, int *budget)
+{
+ int work_to_do;
+ int work_done;
+ struct sbmac_softc *sc = netdev_priv(dev);
+
+ work_to_do = min(*budget, dev->quota);
+ work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1);
+ if (work_done > work_to_do)
+ printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
+ sc->sbm_dev->name, *budget, dev->quota, work_done);
+
+ sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
+
+ *budget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done < work_to_do) {
+ netif_rx_complete(dev);
+
+#ifdef CONFIG_SBMAC_COALESCE
+ __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
+ ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0),
+ sc->sbm_imr);
+#else
+ __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) |
+ (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr);
+#endif
+ }
+
+ return (work_done >= work_to_do);
+}
#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
static void
@@ -2883,7 +2993,7 @@ sbmac_init_module(void)
/*
* The R_MAC_ETHERNET_ADDR register will be set to some nonzero
- * value for us by the firmware if we're going to use this MAC.
+ * value for us by the firmware if we are going to use this MAC.
* If we find a zero, skip this MAC.
*/
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index d8c9c5d66d4..1fc77300b05 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -624,7 +624,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs)
#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
-static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
+static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom)
{
struct sgiseeq_init_block *sr;
struct sgiseeq_private *sp;
@@ -650,7 +650,9 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
#define EADDR_NVOFS 250
for (i = 0; i < 3; i++) {
- unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
+ unsigned short tmp = has_eeprom ?
+ ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) :
+ ip22_nvram_read(EADDR_NVOFS / 2+i);
dev->dev_addr[2 * i] = tmp >> 8;
dev->dev_addr[2 * i + 1] = tmp & 0xff;
@@ -683,6 +685,11 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq)
sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+ /* Setup PIO and DMA transfer timing */
+ sp->hregs->pconfig = 0x161;
+ sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
+ HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026;
+
/* Reset the chip. */
hpc3_eth_reset(sp->hregs);
@@ -729,8 +736,23 @@ err_out:
static int __init sgiseeq_probe(void)
{
+ unsigned int tmp, ret1, ret2 = 0;
+
/* On board adapter on 1st HPC is always present */
- return sgiseeq_init(hpc3c0, SGI_ENET_IRQ);
+ ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0);
+ /* Let's see if second HPC is there */
+ if (!(ip22_is_fullhouse()) &&
+ get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) {
+ sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 |
+ SGIMC_GIOPAR_EXP164 |
+ SGIMC_GIOPAR_HPC264;
+ hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
+ /* interrupt/config register on Challenge S Mezz board */
+ hpc3c1->pbus_extregs[0][0] = 0x30;
+ ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1);
+ }
+
+ return (ret1 & ret2) ? ret1 : 0;
}
static void __exit sgiseeq_exit(void)
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index dea0126723d..2cb2e156c75 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1753,6 +1753,7 @@ static int sis900_rx(struct net_device *net_dev)
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
} else {
struct sk_buff * skb;
+ struct sk_buff * rx_skb;
pci_unmap_single(sis_priv->pci_dev,
sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
@@ -1786,10 +1787,10 @@ static int sis900_rx(struct net_device *net_dev)
}
/* give the socket buffer to upper layers */
- skb = sis_priv->rx_skbuff[entry];
- skb_put(skb, rx_size);
- skb->protocol = eth_type_trans(skb, net_dev);
- netif_rx(skb);
+ rx_skb = sis_priv->rx_skbuff[entry];
+ skb_put(rx_skb, rx_size);
+ rx_skb->protocol = eth_type_trans(rx_skb, net_dev);
+ netif_rx(rx_skb);
/* some network statistics */
if ((rx_status & BCAST) == MCAST)
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index e0a93005e6d..bf218621db1 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -5123,7 +5123,12 @@ static int skge_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ printk(KERN_WARNING "sk98lin: unable to enable device %s "
+ "in resume\n", dev->name);
+ goto err_out;
+ }
pci_set_master(pdev);
if (pAC->GIni.GIMacsFound == 2)
ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
@@ -5131,10 +5136,8 @@ static int skge_resume(struct pci_dev *pdev)
ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
if (ret) {
printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
- pAC->AllocFlag &= ~SK_ALLOC_IRQ;
- dev->irq = 0;
- pci_disable_device(pdev);
- return -EBUSY;
+ ret = -EBUSY;
+ goto err_out_disable_pdev;
}
netif_device_attach(dev);
@@ -5151,6 +5154,13 @@ static int skge_resume(struct pci_dev *pdev)
}
return 0;
+
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+err_out:
+ pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+ dev->irq = 0;
+ return ret;
}
#else
#define skge_suspend NULL
diff --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h
deleted file mode 100644
index c73dcd96a40..00000000000
--- a/drivers/net/skfp/h/lnkstat.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * 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 information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-/*
- * Definition of the Error Log Structure
- * This structure will be copied into the Error Log buffer
- * during the NDIS General Request ReadErrorLog by the MAC Driver
- */
-
-struct s_error_log {
-
- /*
- * place holder for token ring adapter error log (zeros)
- */
- u_char reserved_0 ; /* byte 0 inside Error Log */
- u_char reserved_1 ; /* byte 1 */
- u_char reserved_2 ; /* byte 2 */
- u_char reserved_3 ; /* byte 3 */
- u_char reserved_4 ; /* byte 4 */
- u_char reserved_5 ; /* byte 5 */
- u_char reserved_6 ; /* byte 6 */
- u_char reserved_7 ; /* byte 7 */
- u_char reserved_8 ; /* byte 8 */
- u_char reserved_9 ; /* byte 9 */
- u_char reserved_10 ; /* byte 10 */
- u_char reserved_11 ; /* byte 11 */
- u_char reserved_12 ; /* byte 12 */
- u_char reserved_13 ; /* byte 13 */
-
- /*
- * FDDI link statistics
- */
-/*
- * smt error low
- */
-#define SMT_ERL_AEB (1<<15) /* A elast. buffer */
-#define SMT_ERL_BLC (1<<14) /* B link error condition */
-#define SMT_ERL_ALC (1<<13) /* A link error condition */
-#define SMT_ERL_NCC (1<<12) /* not copied condition */
-#define SMT_ERL_FEC (1<<11) /* frame error condition */
-
-/*
- * smt event low
- */
-#define SMT_EVL_NCE (1<<5)
-
- u_short smt_error_low ; /* byte 14/15 */
- u_short smt_error_high ; /* byte 16/17 */
- u_short smt_event_low ; /* byte 18/19 */
- u_short smt_event_high ; /* byte 20/21 */
- u_short connection_policy_violation ; /* byte 22/23 */
- u_short port_event ; /* byte 24/25 */
- u_short set_count_low ; /* byte 26/27 */
- u_short set_count_high ; /* byte 28/29 */
- u_short aci_id_code ; /* byte 30/31 */
- u_short purge_frame_counter ; /* byte 32/33 */
-
- /*
- * CMT and RMT state machines
- */
- u_short ecm_state ; /* byte 34/35 */
- u_short pcm_a_state ; /* byte 36/37 */
- u_short pcm_b_state ; /* byte 38/39 */
- u_short cfm_state ; /* byte 40/41 */
- u_short rmt_state ; /* byte 42/43 */
-
- u_short not_used[30] ; /* byte 44-103 */
-
- u_short ucode_version_level ; /* byte 104/105 */
-
- u_short not_used_1 ; /* byte 106/107 */
- u_short not_used_2 ; /* byte 108/109 */
-} ;
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index f1a0e6c0fbd..b07da1054ad 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -42,7 +42,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.10"
+#define DRV_VERSION "1.11"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -135,10 +135,13 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
/* Wake on Lan only supported on Yukon chips with rev 1 or above */
static u32 wol_supported(const struct skge_hw *hw)
{
- if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
- return WAKE_MAGIC | WAKE_PHY;
- else
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ return 0;
+
+ if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)
return 0;
+
+ return WAKE_MAGIC | WAKE_PHY;
}
static u32 pci_wake_enabled(struct pci_dev *dev)
@@ -2621,6 +2624,7 @@ static int skge_down(struct net_device *dev)
static inline int skge_avail(const struct skge_ring *ring)
{
+ smp_mb();
return ((ring->to_clean > ring->to_use) ? 0 : ring->count)
+ (ring->to_clean - ring->to_use) - 1;
}
@@ -2709,6 +2713,8 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
dev->name, e - skge->tx_ring.start, skb->len);
skge->tx_ring.to_use = e->next;
+ smp_wmb();
+
if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) {
pr_debug("%s: transmit queue full\n", dev->name);
netif_stop_queue(dev);
@@ -2726,8 +2732,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
{
struct pci_dev *pdev = skge->hw->pdev;
- BUG_ON(!e->skb);
-
/* skb header vs. fragment */
if (control & BMU_STF)
pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr),
@@ -2745,7 +2749,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
dev_kfree_skb(e->skb);
}
- e->skb = NULL;
}
/* Free all buffers in transmit ring */
@@ -3017,21 +3020,29 @@ static void skge_tx_done(struct net_device *dev)
skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
- netif_tx_lock(dev);
for (e = ring->to_clean; e != ring->to_use; e = e->next) {
- struct skge_tx_desc *td = e->desc;
+ u32 control = ((const struct skge_tx_desc *) e->desc)->control;
- if (td->control & BMU_OWN)
+ if (control & BMU_OWN)
break;
- skge_tx_free(skge, e, td->control);
+ skge_tx_free(skge, e, control);
}
skge->tx_ring.to_clean = e;
- if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
- netif_wake_queue(dev);
+ /* Can run lockless until we need to synchronize to restart queue. */
+ smp_mb();
- netif_tx_unlock(dev);
+ if (unlikely(netif_queue_stopped(dev) &&
+ skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+ netif_tx_lock(dev);
+ if (unlikely(netif_queue_stopped(dev) &&
+ skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+ netif_wake_queue(dev);
+
+ }
+ netif_tx_unlock(dev);
+ }
}
static int skge_poll(struct net_device *dev, int *budget)
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 86467ae74d4..edd71468220 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -232,7 +232,6 @@ enum {
IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */
IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT
- | IS_NO_STAT_M1 | IS_NO_STAT_M2
| IS_RAM_RD_PAR | IS_RAM_WR_PAR
| IS_M1_PAR_ERR | IS_M2_PAR_ERR
| IS_R1_PAR_ERR | IS_R2_PAR_ERR,
@@ -2447,15 +2446,15 @@ enum pause_status {
struct skge_port {
- u32 msg_enable;
struct skge_hw *hw;
struct net_device *netdev;
int port;
+ u32 msg_enable;
struct skge_ring tx_ring;
- struct skge_ring rx_ring;
- struct net_device_stats net_stats;
+ struct skge_ring rx_ring ____cacheline_aligned_in_smp;
+ unsigned int rx_buf_size;
struct timer_list link_timer;
enum pause_control flow_control;
@@ -2471,7 +2470,8 @@ struct skge_port {
void *mem; /* PCI memory for rings */
dma_addr_t dma;
unsigned long mem_size;
- unsigned int rx_buf_size;
+
+ struct net_device_stats net_stats;
};
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 238c2ca34da..a307310f13f 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -124,10 +124,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
-#ifdef broken
- /* This device causes data corruption problems that are not resolved */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
-#endif
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
@@ -3581,10 +3578,21 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out;
}
+ /* Some Gigabyte motherboards have 88e8056 but cause problems
+ * There is some unresolved hardware related problem that causes
+ * descriptor errors and receive data corruption.
+ */
+ if (pdev->vendor == PCI_VENDOR_ID_MARVELL &&
+ pdev->device == 0x4364 && pdev->subsystem_vendor == 0x1458) {
+ dev_err(&pdev->dev,
+ "88E8056 on Gigabyte motherboards not supported\n");
+ goto err_out_disable;
+ }
+
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
dev_err(&pdev->dev, "cannot obtain PCI resources\n");
- goto err_out;
+ goto err_out_disable;
}
pci_set_master(pdev);
@@ -3721,6 +3729,7 @@ err_out_free_hw:
kfree(hw);
err_out_free_regions:
pci_release_regions(pdev);
+err_out_disable:
pci_disable_device(pdev);
err_out:
return err;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 8a2109a913b..81f24847c96 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -499,7 +499,7 @@ static inline void smc911x_rcv(struct net_device *dev)
SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_));
SMC_PULL_DATA(data, pkt_len+2+3);
- DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,);
+ DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name);
PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64);
dev->last_rx = jiffies;
skb->protocol = eth_type_trans(skb, dev);
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index d2767e6584a..111f23d0576 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -55,6 +55,53 @@
#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
+#elif defined(CONFIG_BFIN)
+
+#define SMC_IRQ_FLAGS IRQF_TRIGGER_HIGH
+
+# if defined (CONFIG_BFIN561_EZKIT)
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_IO_SHIFT 0
+#define SMC_NOWAIT 1
+#define SMC_USE_BFIN_DMA 0
+
+
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_outsl(a, r, p, l) outsl((unsigned long *)((a) + (r)), p, l)
+#define SMC_insl(a, r, p, l) insl ((unsigned long *)((a) + (r)), p, l)
+# else
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_IO_SHIFT 0
+#define SMC_NOWAIT 1
+#define SMC_USE_BFIN_DMA 0
+
+
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outsw(a, r, p, l) outsw((unsigned long *)((a) + (r)), p, l)
+#define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l)
+# endif
+/* check if the mac in reg is valid */
+#define SMC_GET_MAC_ADDR(addr) \
+ do { \
+ unsigned int __v; \
+ __v = SMC_inw(ioaddr, ADDR0_REG); \
+ addr[0] = __v; addr[1] = __v >> 8; \
+ __v = SMC_inw(ioaddr, ADDR1_REG); \
+ addr[2] = __v; addr[3] = __v >> 8; \
+ __v = SMC_inw(ioaddr, ADDR2_REG); \
+ addr[4] = __v; addr[5] = __v >> 8; \
+ if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \
+ random_ether_addr(addr); \
+ } \
+ } while (0)
#elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6)
/* We can only do 16-bit reads and writes in the static memory space. */
@@ -232,6 +279,40 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
+#elif defined(CONFIG_SUPERH)
+
+#if defined(CONFIG_SH_7780_SOLUTION_ENGINE) || defined(CONFIG_SH_7722_SOLUTION_ENGINE)
+#define SMC_CAN_USE_8BIT 0
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 0
+#define SMC_IO_SHIFT 0
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) (inw((a) + ((r)&~1)) >> (8*(r%2)))&0xff
+#define SMC_inw(a, r) inw((a) + (r))
+#define SMC_outb(v, a, r) outw(((inw((a)+((r)&~1))*(0xff<<8*(r%2)))) | ((v)<<(8*(r&2)))), (a) + ((r)&~1))
+
+#define SMC_outw(v, a, r) outw(v, (a) + (r))
+#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
+
+#else /* BOARDS */
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+
+#define SMC_inb(a, r) inb((a) + (r))
+#define SMC_inw(a, r) inw((a) + (r))
+#define SMC_outb(v, a, r) outb(v, (a) + (r))
+#define SMC_outw(v, a, r) outw(v, (a) + (r))
+#define SMC_insw(a, r, p, l) insw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l)
+
+#endif /* BOARDS */
+
+#define set_irq_type(irq, type) do {} while (0)
+
#elif defined(CONFIG_M32R)
#define SMC_CAN_USE_8BIT 0
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index c6320c71993..8069f3e32d8 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -50,29 +50,6 @@ static int sonic_open(struct net_device *dev)
if (sonic_debug > 2)
printk("sonic_open: initializing sonic driver.\n");
- /*
- * We don't need to deal with auto-irq stuff since we
- * hardwire the sonic interrupt.
- */
-/*
- * XXX Horrible work around: We install sonic_interrupt as fast interrupt.
- * This means that during execution of the handler interrupt are disabled
- * covering another bug otherwise corrupting data. This doesn't mean
- * this glue works ok under all situations.
- *
- * Note (dhd): this also appears to prevent lockups on the Macintrash
- * when more than one Ethernet card is installed (knock on wood)
- *
- * Note (fthain): whether the above is still true is anyones guess. Certainly
- * the buffer handling algorithms will not tolerate re-entrance without some
- * mutual exclusion added. Anyway, the memcpy has now been eliminated from the
- * rx code to make this a faster "fast interrupt".
- */
- if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) {
- printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq);
- return -EAGAIN;
- }
-
for (i = 0; i < SONIC_NUM_RRS; i++) {
struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2);
if (skb == NULL) {
@@ -169,8 +146,6 @@ static int sonic_close(struct net_device *dev)
}
}
- free_irq(dev->irq, dev); /* release the IRQ */
-
return 0;
}
@@ -178,8 +153,13 @@ static void sonic_tx_timeout(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int i;
- /* Stop the interrupts for this */
+ /*
+ * put the Sonic into software-reset mode and
+ * disable all interrupts before releasing DMA buffers
+ */
SONIC_WRITE(SONIC_IMR, 0);
+ SONIC_WRITE(SONIC_ISR, 0x7fff);
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
/* We could resend the original skbs. Easier to re-initialise. */
for (i = 0; i < SONIC_NUM_TDS; i++) {
if(lp->tx_laddr[i]) {
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 230da14b1b6..c15e97253ed 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -1830,7 +1830,7 @@ try_host_fw:
if (!dn)
goto out_err;
- fw_prop = get_property(dn, "firmware", &fw_size);
+ fw_prop = of_get_property(dn, "firmware", &fw_size);
if (!fw_prop)
goto out_err;
@@ -2236,7 +2236,7 @@ spider_net_setup_netdev(struct spider_net_card *card)
if (!dn)
return -EIO;
- mac = get_property(dn, "local-mac-address", NULL);
+ mac = of_get_property(dn, "local-mac-address", NULL);
if (!mac)
return -EIO;
memcpy(addr.sa_data, mac, ETH_ALEN);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 396c3d961f8..a123ea87893 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -1023,10 +1023,11 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev)
{
len = skb->len;
if (len < ETH_ZLEN) {
- memset((char *)p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
+ memset((void *)p->xmit_cbuffs[p->xmit_count], 0,
+ ETH_ZLEN);
len = ETH_ZLEN;
}
- skb_copy_from_linear_data(skb, p->xmit_cbuffs[p->xmit_count], skb->len);
+ skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len);
#if (NUM_XMIT_BUFFS == 1)
# ifdef NO_NOPCOMMANDS
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index f51ba31970a..e1f912d0404 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -110,8 +110,7 @@ static char *media[MAX_UNITS];
/* These identify the driver base version and may not be removed. */
static char version[] =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"
-KERN_INFO " http://www.scyld.com/network/sundance.html\n";
+KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 5da73212ac9..43280385503 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -2903,7 +2903,7 @@ static int __devinit gem_get_device_address(struct gem *gp)
struct net_device *dev = gp->dev;
const unsigned char *addr;
- addr = get_property(gp->of_node, "local-mac-address", NULL);
+ addr = of_get_property(gp->of_node, "local-mac-address", NULL);
if (addr == NULL) {
#ifdef CONFIG_SPARC
addr = idprom->id_ethaddr;
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 56a110ca5e6..61843fd5752 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -451,7 +451,7 @@ static int bcm5421_init(struct mii_phy* phy)
if (phy->platform_data) {
struct device_node *np = of_get_parent(phy->platform_data);
int can_low_power = 1;
- if (np == NULL || get_property(np, "no-autolowpower", NULL))
+ if (np == NULL || of_get_property(np, "no-autolowpower", NULL))
can_low_power = 0;
if (can_low_power) {
/* Enable automatic low-power */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index d7741e23f8d..463d600ed83 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1,35 +1,34 @@
-/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ahennessy@mvista.com
+/*
+ * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
*
* Based on skelton.c by Donald Becker.
- * Copyright (C) 2000-2001 Toshiba Corporation
*
- * 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 driver is a replacement of older and less maintained version.
+ * This is a header of the older version:
+ * -----<snip>-----
+ * Copyright 2001 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ * ahennessy@mvista.com
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ * static const char *version =
+ * "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+ * -----<snip>-----
*
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*
- * 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.
+ * (C) Copyright TOSHIBA CORPORATION 2004-2005
+ * All Rights Reserved.
*/
-static const char *version =
- "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n";
+#ifdef TC35815_NAPI
+#define DRV_VERSION "1.35-NAPI"
+#else
+#define DRV_VERSION "1.35"
+#endif
+static const char *version = "tc35815.c:v" DRV_VERSION "\n";
+#define MODNAME "tc35815"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -40,6 +39,7 @@ static const char *version =
#include <linux/in.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/netdevice.h>
@@ -47,36 +47,47 @@ static const char *version =
#include <linux/skbuff.h>
#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/bitops.h>
-
-#include <asm/system.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
#include <asm/io.h>
-#include <asm/dma.h>
#include <asm/byteorder.h>
-/*
- * The name of the card. Is used for messages and in the requests for
- * io regions, irqs and dma channels
- */
-static const char* cardname = "TC35815CF";
-#define TC35815_PROC_ENTRY "net/tc35815"
-
-#define TC35815_MODULE_NAME "TC35815CF"
-#define TX_TIMEOUT (4*HZ)
-
/* First, a few definitions that the brave might change. */
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef TC35815_DEBUG
-#define TC35815_DEBUG 1
-#endif
-static unsigned int tc35815_debug = TC35815_DEBUG;
-
#define GATHER_TXINT /* On-Demand Tx Interrupt */
+#define WORKAROUND_LOSTCAR
+#define WORKAROUND_100HALF_PROMISC
+/* #define TC35815_USE_PACKEDBUFFER */
+
+typedef enum {
+ TC35815CF = 0,
+ TC35815_NWU,
+ TC35815_TX4939,
+} board_t;
+
+/* indexed by board_t, above */
+static const struct {
+ const char *name;
+} board_info[] __devinitdata = {
+ { "TOSHIBA TC35815CF 10/100BaseTX" },
+ { "TOSHIBA TC35815 with Wake on LAN" },
+ { "TOSHIBA TC35815/TX4939" },
+};
+
+static const struct pci_device_id tc35815_pci_tbl[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF },
+ {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU },
+ {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 },
+ {0,}
+};
+MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
-#define vtonocache(p) KSEG1ADDR(virt_to_phys(p))
+/* see MODULE_PARM_DESC */
+static struct tc35815_options {
+ int speed;
+ int duplex;
+ int doforce;
+} options;
/*
* Registers
@@ -119,6 +130,11 @@ struct tc35815_regs {
* Bit assignments
*/
/* DMA_Ctl bit asign ------------------------------------------------------- */
+#define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */
+#define DMA_RxAlign_1 0x00400000
+#define DMA_RxAlign_2 0x00800000
+#define DMA_RxAlign_3 0x00c00000
+#define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */
#define DMA_IntMask 0x00040000 /* 1:Interupt mask */
#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */
#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */
@@ -269,42 +285,6 @@ struct tc35815_regs {
#define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */
-/* MII register offsets */
-#define MII_CONTROL 0x0000
-#define MII_STATUS 0x0001
-#define MII_PHY_ID0 0x0002
-#define MII_PHY_ID1 0x0003
-#define MII_ANAR 0x0004
-#define MII_ANLPAR 0x0005
-#define MII_ANER 0x0006
-/* MII Control register bit definitions. */
-#define MIICNTL_FDX 0x0100
-#define MIICNTL_RST_AUTO 0x0200
-#define MIICNTL_ISOLATE 0x0400
-#define MIICNTL_PWRDWN 0x0800
-#define MIICNTL_AUTO 0x1000
-#define MIICNTL_SPEED 0x2000
-#define MIICNTL_LPBK 0x4000
-#define MIICNTL_RESET 0x8000
-/* MII Status register bit significance. */
-#define MIISTAT_EXT 0x0001
-#define MIISTAT_JAB 0x0002
-#define MIISTAT_LINK 0x0004
-#define MIISTAT_CAN_AUTO 0x0008
-#define MIISTAT_FAULT 0x0010
-#define MIISTAT_AUTO_DONE 0x0020
-#define MIISTAT_CAN_T 0x0800
-#define MIISTAT_CAN_T_FDX 0x1000
-#define MIISTAT_CAN_TX 0x2000
-#define MIISTAT_CAN_TX_FDX 0x4000
-#define MIISTAT_CAN_T4 0x8000
-/* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */
-#define MII_AN_TX_FDX 0x0100
-#define MII_AN_TX_HDX 0x0080
-#define MII_AN_10_FDX 0x0040
-#define MII_AN_10_HDX 0x0020
-
-
/*
* Descriptors
*/
@@ -352,32 +332,51 @@ struct BDesc {
#ifdef NO_CHECK_CARRIER
#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
- Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
- Tx_En) /* maybe 0x7d01 */
+ Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7b01 */
#else
#define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \
- Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \
- Tx_En) /* maybe 0x7f01 */
+ Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \
+ Tx_En) /* maybe 0x7b01 */
#endif
#define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \
| Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */
-
#define INT_EN_CMD (Int_NRAbtEn | \
- Int_DParDEn | Int_DParErrEn | \
+ Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \
Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \
Int_STargAbtEn | \
Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/
+#define DMA_CTL_CMD DMA_BURST_SIZE
+#define HAVE_DMA_RXALIGN(lp) likely((lp)->boardtype != TC35815CF)
/* Tuning parameters */
#define DMA_BURST_SIZE 32
#define TX_THRESHOLD 1024
+#define TX_THRESHOLD_MAX 1536 /* used threshold with packet max byte for low pci transfer ability.*/
+#define TX_THRESHOLD_KEEP_LIMIT 10 /* setting threshold max value when overrun error occured this count. */
+/* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */
+#ifdef TC35815_USE_PACKEDBUFFER
#define FD_PAGE_NUM 2
-#define FD_PAGE_ORDER 1
-/* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */
-#define RX_BUF_PAGES 8 /* >= 2 */
+#define RX_BUF_NUM 8 /* >= 2 */
#define RX_FD_NUM 250 /* >= 32 */
#define TX_FD_NUM 128
+#define RX_BUF_SIZE PAGE_SIZE
+#else /* TC35815_USE_PACKEDBUFFER */
+#define FD_PAGE_NUM 4
+#define RX_BUF_NUM 128 /* < 256 */
+#define RX_FD_NUM 256 /* >= 32 */
+#define TX_FD_NUM 128
+#if RX_CTL_CMD & Rx_LongEn
+#define RX_BUF_SIZE PAGE_SIZE
+#elif RX_CTL_CMD & Rx_StripCRC
+#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */
+#else
+#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */
+#endif
+#endif /* TC35815_USE_PACKEDBUFFER */
+#define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */
+#define NAPI_WEIGHT 16
struct TxFD {
struct FDesc fd;
@@ -392,18 +391,27 @@ struct RxFD {
struct FrFD {
struct FDesc fd;
- struct BDesc bd[RX_BUF_PAGES];
+ struct BDesc bd[RX_BUF_NUM];
};
-extern unsigned long tc_readl(volatile __u32 *addr);
-extern void tc_writel(unsigned long data, volatile __u32 *addr);
+#define tc_readl(addr) readl(addr)
+#define tc_writel(d, addr) writel(d, addr)
+
+#define TC35815_TX_TIMEOUT msecs_to_jiffies(400)
-dma_addr_t priv_dma_handle;
+/* Timer state engine. */
+enum tc35815_timer_state {
+ arbwait = 0, /* Waiting for auto negotiation to complete. */
+ lupwait = 1, /* Auto-neg complete, awaiting link-up status. */
+ ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */
+ asleep = 3, /* Time inactive. */
+ lcheck = 4, /* Check link status. */
+};
/* Information that need to be kept for each board. */
struct tc35815_local {
- struct net_device *next_module;
+ struct pci_dev *pci_dev;
/* statistics */
struct net_device_stats stats;
@@ -411,216 +419,371 @@ struct tc35815_local {
int max_tx_qlen;
int tx_ints;
int rx_ints;
+ int tx_underrun;
} lstats;
- int tbusy;
- int option;
-#define TC35815_OPT_AUTO 0x00
-#define TC35815_OPT_10M 0x01
-#define TC35815_OPT_100M 0x02
-#define TC35815_OPT_FULLDUP 0x04
- int linkspeed; /* 10 or 100 */
+ /* Tx control lock. This protects the transmit buffer ring
+ * state along with the "tx full" state of the driver. This
+ * means all netif_queue flow control actions are protected
+ * by this lock as well.
+ */
+ spinlock_t lock;
+
+ int phy_addr;
int fullduplex;
+ unsigned short saved_lpa;
+ struct timer_list timer;
+ enum tc35815_timer_state timer_state; /* State of auto-neg timer. */
+ unsigned int timer_ticks; /* Number of clicks at each state */
/*
* Transmitting: Batch Mode.
* 1 BD in 1 TxFD.
- * Receiving: Packing Mode.
+ * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER)
* 1 circular FD for Free Buffer List.
- * RX_BUG_PAGES BD in Free Buffer FD.
+ * RX_BUF_NUM BD in Free Buffer FD.
* One Free Buffer BD has PAGE_SIZE data buffer.
+ * Or Non-Packing Mode.
+ * 1 circular FD for Free Buffer List.
+ * RX_BUF_NUM BD in Free Buffer FD.
+ * One Free Buffer BD has ETH_FRAME_LEN data buffer.
*/
- struct pci_dev *pdev;
- dma_addr_t fd_buf_dma_handle;
- void * fd_buf; /* for TxFD, TxFD, FrFD */
+ void * fd_buf; /* for TxFD, RxFD, FrFD */
+ dma_addr_t fd_buf_dma;
struct TxFD *tfd_base;
- int tfd_start;
- int tfd_end;
+ unsigned int tfd_start;
+ unsigned int tfd_end;
struct RxFD *rfd_base;
struct RxFD *rfd_limit;
struct RxFD *rfd_cur;
struct FrFD *fbl_ptr;
+#ifdef TC35815_USE_PACKEDBUFFER
unsigned char fbl_curid;
- dma_addr_t data_buf_dma_handle[RX_BUF_PAGES];
- void * data_buf[RX_BUF_PAGES]; /* packing */
- spinlock_t lock;
+ void * data_buf[RX_BUF_NUM]; /* packing */
+ dma_addr_t data_buf_dma[RX_BUF_NUM];
+ struct {
+ struct sk_buff *skb;
+ dma_addr_t skb_dma;
+ } tx_skbs[TX_FD_NUM];
+#else
+ unsigned int fbl_count;
+ struct {
+ struct sk_buff *skb;
+ dma_addr_t skb_dma;
+ } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM];
+#endif
+ struct mii_if_info mii;
+ unsigned short mii_id[2];
+ u32 msg_enable;
+ board_t boardtype;
};
-/* Index to functions, as function prototypes. */
+static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt)
+{
+ return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf);
+}
+#ifdef DEBUG
+static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+ return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma));
+}
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus)
+{
+ int i;
+ for (i = 0; i < RX_BUF_NUM; i++) {
+ if (bus >= lp->data_buf_dma[i] &&
+ bus < lp->data_buf_dma[i] + PAGE_SIZE)
+ return (void *)((u8 *)lp->data_buf[i] +
+ (bus - lp->data_buf_dma[i]));
+ }
+ return NULL;
+}
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq);
+#define TC35815_DMA_SYNC_ONDEMAND
+static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+ void *buf;
+ /* pci_map + pci_dma_sync will be more effective than
+ * pci_alloc_consistent on some archs. */
+ if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL)
+ return NULL;
+ *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(*dma_handle)) {
+ free_page((unsigned long)buf);
+ return NULL;
+ }
+ return buf;
+#else
+ return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle);
+#endif
+}
+
+static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle)
+{
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+ pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ free_page((unsigned long)buf);
+#else
+ pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle);
+#endif
+}
+#else /* TC35815_USE_PACKEDBUFFER */
+static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev,
+ struct pci_dev *hwdev,
+ dma_addr_t *dma_handle)
+{
+ struct sk_buff *skb;
+ skb = dev_alloc_skb(RX_BUF_SIZE);
+ if (!skb)
+ return NULL;
+ *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(*dma_handle)) {
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
+ skb_reserve(skb, 2); /* make IP header 4byte aligned */
+ return skb;
+}
+
+static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle)
+{
+ pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(skb);
+}
+#endif /* TC35815_USE_PACKEDBUFFER */
+
+/* Index to functions, as function prototypes. */
static int tc35815_open(struct net_device *dev);
static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void tc35815_tx_timeout(struct net_device *dev);
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
+#ifdef TC35815_NAPI
+static int tc35815_rx(struct net_device *dev, int limit);
+static int tc35815_poll(struct net_device *dev, int *budget);
+#else
static void tc35815_rx(struct net_device *dev);
+#endif
static void tc35815_txdone(struct net_device *dev);
static int tc35815_close(struct net_device *dev);
static struct net_device_stats *tc35815_get_stats(struct net_device *dev);
static void tc35815_set_multicast_list(struct net_device *dev);
+static void tc35815_tx_timeout(struct net_device *dev);
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev);
+#endif
+static const struct ethtool_ops tc35815_ethtool_ops;
+/* Example routines you must write ;->. */
static void tc35815_chip_reset(struct net_device *dev);
static void tc35815_chip_init(struct net_device *dev);
+static void tc35815_find_phy(struct net_device *dev);
static void tc35815_phy_chip_init(struct net_device *dev);
-/* A list of all installed tc35815 devices. */
-static struct net_device *root_tc35815_dev = NULL;
+#ifdef DEBUG
+static void panic_queues(struct net_device *dev);
+#endif
-/*
- * PCI device identifiers for "new style" Linux PCI Device Drivers
- */
-static struct pci_device_id tc35815_pci_tbl[] = {
- { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0, }
-};
+static void tc35815_timer(unsigned long data);
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+ struct ethtool_cmd *ep);
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location);
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+ int val);
-MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl);
+static void __devinit tc35815_init_dev_addr (struct net_device *dev)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int i;
-int
-tc35815_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ /* dev_addr will be overwritten on NETDEV_REGISTER event */
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ for (i = 0; i < 6; i += 2) {
+ unsigned short data;
+ tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
+ while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
+ ;
+ data = tc_readl(&tr->PROM_Data);
+ dev->dev_addr[i] = data & 0xff;
+ dev->dev_addr[i+1] = data >> 8;
+ }
+}
+
+static int __devinit tc35815_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
- int err = 0;
- int ret;
- unsigned long pci_memaddr;
- unsigned int pci_irq_line;
+ void __iomem *ioaddr = NULL;
+ struct net_device *dev;
+ struct tc35815_local *lp;
+ int rc;
+ unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
+
+ static int printed_version;
+ if (!printed_version++) {
+ printk(version);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "speed:%d duplex:%d doforce:%d\n",
+ options.speed, options.duplex, options.doforce);
+ }
- printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device);
+ if (!pdev->irq) {
+ dev_warn(&pdev->dev, "no IRQ assigned.\n");
+ return -ENODEV;
+ }
- err = pci_enable_device(pdev);
- if (err)
- return err;
+ /* dev zeroed in alloc_etherdev */
+ dev = alloc_etherdev (sizeof (*lp));
+ if (dev == NULL) {
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+ return -ENOMEM;
+ }
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ lp = dev->priv;
+
+ /* enable device (incl. PCI PM wakeup), and bus-mastering */
+ rc = pci_enable_device (pdev);
+ if (rc)
+ goto err_out;
- pci_memaddr = pci_resource_start (pdev, 1);
+ mmio_start = pci_resource_start (pdev, 1);
+ mmio_end = pci_resource_end (pdev, 1);
+ mmio_flags = pci_resource_flags (pdev, 1);
+ mmio_len = pci_resource_len (pdev, 1);
- printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0));
+ /* set this immediately, we need to know before
+ * we talk to the chip directly */
- if (!pci_memaddr) {
- printk(KERN_WARNING "no PCI MEM resources, aborting\n");
- ret = -ENODEV;
+ /* make sure PCI base addr 1 is MMIO */
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
+ rc = -ENODEV;
goto err_out;
}
- pci_irq_line = pdev->irq;
- /* irq disabled. */
- if (pci_irq_line == 0) {
- printk(KERN_WARNING "no PCI irq, aborting\n");
- ret = -ENODEV;
+
+ /* check for weird/broken PCI region reporting */
+ if ((mmio_len < sizeof(struct tc35815_regs))) {
+ dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
+ rc = -ENODEV;
goto err_out;
}
- ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line);
- if (ret)
+ rc = pci_request_regions (pdev, MODNAME);
+ if (rc)
goto err_out;
- pci_set_master(pdev);
-
- return 0;
+ pci_set_master (pdev);
-err_out:
- pci_disable_device(pdev);
- return ret;
-}
+ /* ioremap MMIO region */
+ ioaddr = ioremap (mmio_start, mmio_len);
+ if (ioaddr == NULL) {
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
+ rc = -EIO;
+ goto err_out_free_res;
+ }
-static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq)
-{
- static unsigned version_printed = 0;
- int i, ret;
- struct tc35815_local *lp;
- struct tc35815_regs *tr;
- struct net_device *dev;
+ /* Initialize the device structure. */
+ dev->open = tc35815_open;
+ dev->hard_start_xmit = tc35815_send_packet;
+ dev->stop = tc35815_close;
+ dev->get_stats = tc35815_get_stats;
+ dev->set_multicast_list = tc35815_set_multicast_list;
+ dev->do_ioctl = tc35815_ioctl;
+ dev->ethtool_ops = &tc35815_ethtool_ops;
+ dev->tx_timeout = tc35815_tx_timeout;
+ dev->watchdog_timeo = TC35815_TX_TIMEOUT;
+#ifdef TC35815_NAPI
+ dev->poll = tc35815_poll;
+ dev->weight = NAPI_WEIGHT;
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = tc35815_poll_controller;
+#endif
- /* Allocate a new 'dev' if needed. */
- dev = alloc_etherdev(sizeof(struct tc35815_local));
- if (dev == NULL)
- return -ENOMEM;
+ dev->irq = pdev->irq;
+ dev->base_addr = (unsigned long) ioaddr;
- /*
- * alloc_etherdev allocs and zeros dev->priv
- */
+ /* dev->priv/lp zeroed and aligned in alloc_etherdev */
lp = dev->priv;
+ spin_lock_init(&lp->lock);
+ lp->pci_dev = pdev;
+ lp->boardtype = ent->driver_data;
- if (tc35815_debug && version_printed++ == 0)
- printk(KERN_DEBUG "%s", version);
-
- /* Fill in the 'dev' fields. */
- dev->irq = irq;
- dev->base_addr = (unsigned long)ioremap(base_addr,
- sizeof(struct tc35815_regs));
- if (!dev->base_addr) {
- ret = -ENOMEM;
- goto err_out;
- }
- tr = (struct tc35815_regs*)dev->base_addr;
+ lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK;
+ pci_set_drvdata(pdev, dev);
+ /* Soft reset the chip. */
tc35815_chip_reset(dev);
- /* Retrieve and print the ethernet address. */
- while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
- ;
- for (i = 0; i < 6; i += 2) {
- unsigned short data;
- tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl);
- while (tc_readl(&tr->PROM_Ctl) & PROM_Busy)
- ;
- data = tc_readl(&tr->PROM_Data);
- dev->dev_addr[i] = data & 0xff;
- dev->dev_addr[i+1] = data >> 8;
- }
+ /* Retrieve the ethernet address. */
+ tc35815_init_dev_addr(dev);
+
+ rc = register_netdev (dev);
+ if (rc)
+ goto err_out_unmap;
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+ printk(KERN_INFO "%s: %s at 0x%lx, "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
+ "IRQ %d\n",
+ dev->name,
+ board_info[ent->driver_data].name,
+ dev->base_addr,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ dev->irq);
+
+ setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev);
+ lp->mii.dev = dev;
+ lp->mii.mdio_read = tc_mdio_read;
+ lp->mii.mdio_write = tc_mdio_write;
+ lp->mii.phy_id_mask = 0x1f;
+ lp->mii.reg_num_mask = 0x1f;
+ tc35815_find_phy(dev);
+ lp->mii.phy_id = lp->phy_addr;
+ lp->mii.full_duplex = 0;
+ lp->mii.force_media = 0;
- /* Initialize the device structure. */
- lp->pdev = pdev;
- lp->next_module = root_tc35815_dev;
- root_tc35815_dev = dev;
+ return 0;
- spin_lock_init(&lp->lock);
+err_out_unmap:
+ iounmap(ioaddr);
+err_out_free_res:
+ pci_release_regions (pdev);
+err_out:
+ free_netdev (dev);
+ return rc;
+}
- if (dev->mem_start > 0) {
- lp->option = dev->mem_start;
- if ((lp->option & TC35815_OPT_10M) &&
- (lp->option & TC35815_OPT_100M)) {
- /* if both speed speficied, auto select. */
- lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M);
- }
- }
- //XXX fixme
- lp->option |= TC35815_OPT_10M;
- /* do auto negotiation */
- tc35815_phy_chip_init(dev);
+static void __devexit tc35815_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata (pdev);
+ unsigned long mmio_addr;
- dev->open = tc35815_open;
- dev->stop = tc35815_close;
- dev->tx_timeout = tc35815_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
- dev->hard_start_xmit = tc35815_send_packet;
- dev->get_stats = tc35815_get_stats;
- dev->set_multicast_list = tc35815_set_multicast_list;
- SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
+ mmio_addr = dev->base_addr;
- ret = register_netdev(dev);
- if (ret)
- goto err_out_iounmap;
+ unregister_netdev (dev);
- printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC",
- dev->name, cardname, base_addr, irq);
- for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk("\n");
- printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n",
- dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half");
+ if (mmio_addr) {
+ iounmap ((void __iomem *)mmio_addr);
+ pci_release_regions (pdev);
+ }
- return 0;
+ free_netdev (dev);
-err_out_iounmap:
- iounmap((void *) dev->base_addr);
-err_out:
- free_netdev(dev);
- return ret;
+ pci_set_drvdata (pdev, NULL);
}
-
static int
tc35815_init_queues(struct net_device *dev)
{
@@ -629,44 +792,64 @@ tc35815_init_queues(struct net_device *dev)
unsigned long fd_addr;
if (!lp->fd_buf) {
- if (sizeof(struct FDesc) +
- sizeof(struct BDesc) * RX_BUF_PAGES +
- sizeof(struct FDesc) * RX_FD_NUM +
- sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) {
- printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name);
- return -ENOMEM;
- }
+ BUG_ON(sizeof(struct FDesc) +
+ sizeof(struct BDesc) * RX_BUF_NUM +
+ sizeof(struct FDesc) * RX_FD_NUM +
+ sizeof(struct TxFD) * TX_FD_NUM >
+ PAGE_SIZE * FD_PAGE_NUM);
- if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0)
+ if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0)
return -ENOMEM;
- for (i = 0; i < RX_BUF_PAGES; i++) {
- if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) {
+ for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+ if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) {
while (--i >= 0) {
- free_page((unsigned long)lp->data_buf[i]);
- lp->data_buf[i] = 0;
+ free_rxbuf_page(lp->pci_dev,
+ lp->data_buf[i],
+ lp->data_buf_dma[i]);
+ lp->data_buf[i] = NULL;
}
- free_page((unsigned long)lp->fd_buf);
- lp->fd_buf = 0;
+ pci_free_consistent(lp->pci_dev,
+ PAGE_SIZE * FD_PAGE_NUM,
+ lp->fd_buf,
+ lp->fd_buf_dma);
+ lp->fd_buf = NULL;
+ return -ENOMEM;
+ }
+#else
+ lp->rx_skbs[i].skb =
+ alloc_rxbuf_skb(dev, lp->pci_dev,
+ &lp->rx_skbs[i].skb_dma);
+ if (!lp->rx_skbs[i].skb) {
+ while (--i >= 0) {
+ free_rxbuf_skb(lp->pci_dev,
+ lp->rx_skbs[i].skb,
+ lp->rx_skbs[i].skb_dma);
+ lp->rx_skbs[i].skb = NULL;
+ }
+ pci_free_consistent(lp->pci_dev,
+ PAGE_SIZE * FD_PAGE_NUM,
+ lp->fd_buf,
+ lp->fd_buf_dma);
+ lp->fd_buf = NULL;
return -ENOMEM;
}
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM);
#endif
}
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
+ printk(KERN_DEBUG "%s: FD buf %p DataBuf",
+ dev->name, lp->fd_buf);
+#ifdef TC35815_USE_PACKEDBUFFER
+ printk(" DataBuf");
+ for (i = 0; i < RX_BUF_NUM; i++)
+ printk(" %p", lp->data_buf[i]);
#endif
+ printk("\n");
} else {
- memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM);
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM);
-#endif
+ for (i = 0; i < FD_PAGE_NUM; i++) {
+ clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE));
+ }
}
-#ifdef __mips__
- fd_addr = (unsigned long)vtonocache(lp->fd_buf);
-#else
fd_addr = (unsigned long)lp->fd_buf;
-#endif
/* Free Descriptors (for Receive) */
lp->rfd_base = (struct RxFD *)fd_addr;
@@ -675,34 +858,66 @@ tc35815_init_queues(struct net_device *dev)
lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD);
}
lp->rfd_cur = lp->rfd_base;
- lp->rfd_limit = (struct RxFD *)(fd_addr -
- sizeof(struct FDesc) -
- sizeof(struct BDesc) * 30);
+ lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1);
/* Transmit Descriptors */
lp->tfd_base = (struct TxFD *)fd_addr;
fd_addr += sizeof(struct TxFD) * TX_FD_NUM;
for (i = 0; i < TX_FD_NUM; i++) {
- lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1]));
- lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1]));
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0);
}
- lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0]));
+ lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0]));
lp->tfd_start = 0;
lp->tfd_end = 0;
/* Buffer List (for Receive) */
lp->fbl_ptr = (struct FrFD *)fd_addr;
- lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr));
- lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD);
- for (i = 0; i < RX_BUF_PAGES; i++) {
- lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i]));
+ lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr));
+ lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD);
+#ifndef TC35815_USE_PACKEDBUFFER
+ /*
+ * move all allocated skbs to head of rx_skbs[] array.
+ * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in
+ * tc35815_rx() had failed.
+ */
+ lp->fbl_count = 0;
+ for (i = 0; i < RX_BUF_NUM; i++) {
+ if (lp->rx_skbs[i].skb) {
+ if (i != lp->fbl_count) {
+ lp->rx_skbs[lp->fbl_count].skb =
+ lp->rx_skbs[i].skb;
+ lp->rx_skbs[lp->fbl_count].skb_dma =
+ lp->rx_skbs[i].skb_dma;
+ }
+ lp->fbl_count++;
+ }
+ }
+#endif
+ for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+ lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]);
+#else
+ if (i >= lp->fbl_count) {
+ lp->fbl_ptr->bd[i].BuffData = 0;
+ lp->fbl_ptr->bd[i].BDCtl = 0;
+ continue;
+ }
+ lp->fbl_ptr->bd[i].BuffData =
+ cpu_to_le32(lp->rx_skbs[i].skb_dma);
+#endif
/* BDID is index of FrFD.bd[] */
lp->fbl_ptr->bd[i].BDCtl =
- cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE);
+ cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) |
+ RX_BUF_SIZE);
}
+#ifdef TC35815_USE_PACKEDBUFFER
lp->fbl_curid = 0;
+#endif
+ printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n",
+ dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr);
return 0;
}
@@ -713,11 +928,25 @@ tc35815_clear_queues(struct net_device *dev)
int i;
for (i = 0; i < TX_FD_NUM; i++) {
- struct sk_buff *skb = (struct sk_buff *)
- le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
- if (skb)
+ u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+ struct sk_buff *skb =
+ fdsystem != 0xffffffff ?
+ lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+ if (lp->tx_skbs[i].skb != skb) {
+ printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+ panic_queues(dev);
+ }
+#else
+ BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+ if (skb) {
+ pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+ lp->tx_skbs[i].skb = NULL;
+ lp->tx_skbs[i].skb_dma = 0;
dev_kfree_skb_any(skb);
- lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ }
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
}
tc35815_init_queues(dev);
@@ -731,28 +960,53 @@ tc35815_free_queues(struct net_device *dev)
if (lp->tfd_base) {
for (i = 0; i < TX_FD_NUM; i++) {
- struct sk_buff *skb = (struct sk_buff *)
- le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
- if (skb)
- dev_kfree_skb_any(skb);
- lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0);
+ u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem);
+ struct sk_buff *skb =
+ fdsystem != 0xffffffff ?
+ lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+ if (lp->tx_skbs[i].skb != skb) {
+ printk("%s: tx_skbs mismatch(%d).\n", dev->name, i);
+ panic_queues(dev);
+ }
+#else
+ BUG_ON(lp->tx_skbs[i].skb != skb);
+#endif
+ if (skb) {
+ dev_kfree_skb(skb);
+ pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE);
+ lp->tx_skbs[i].skb = NULL;
+ lp->tx_skbs[i].skb_dma = 0;
+ }
+ lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff);
}
}
lp->rfd_base = NULL;
- lp->rfd_base = NULL;
lp->rfd_limit = NULL;
lp->rfd_cur = NULL;
lp->fbl_ptr = NULL;
- for (i = 0; i < RX_BUF_PAGES; i++) {
- if (lp->data_buf[i])
- free_page((unsigned long)lp->data_buf[i]);
- lp->data_buf[i] = 0;
+ for (i = 0; i < RX_BUF_NUM; i++) {
+#ifdef TC35815_USE_PACKEDBUFFER
+ if (lp->data_buf[i]) {
+ free_rxbuf_page(lp->pci_dev,
+ lp->data_buf[i], lp->data_buf_dma[i]);
+ lp->data_buf[i] = NULL;
+ }
+#else
+ if (lp->rx_skbs[i].skb) {
+ free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb,
+ lp->rx_skbs[i].skb_dma);
+ lp->rx_skbs[i].skb = NULL;
+ }
+#endif
+ }
+ if (lp->fd_buf) {
+ pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM,
+ lp->fd_buf, lp->fd_buf_dma);
+ lp->fd_buf = NULL;
}
- if (lp->fd_buf)
- __free_pages(lp->fd_buf, FD_PAGE_ORDER);
- lp->fd_buf = NULL;
}
static void
@@ -792,6 +1046,7 @@ dump_rxfd(struct RxFD *fd)
return bd_count;
}
+#if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER)
static void
dump_frfd(struct FrFD *fd)
{
@@ -802,20 +1057,22 @@ dump_frfd(struct FrFD *fd)
le32_to_cpu(fd->fd.FDStat),
le32_to_cpu(fd->fd.FDCtl));
printk("BD: ");
- for (i = 0; i < RX_BUF_PAGES; i++)
+ for (i = 0; i < RX_BUF_NUM; i++)
printk(" %08x %08x",
le32_to_cpu(fd->bd[i].BuffData),
le32_to_cpu(fd->bd[i].BDCtl));
printk("\n");
}
+#endif
+#ifdef DEBUG
static void
panic_queues(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
int i;
- printk("TxFD base %p, start %d, end %d\n",
+ printk("TxFD base %p, start %u, end %u\n",
lp->tfd_base, lp->tfd_start, lp->tfd_end);
printk("RxFD base %p limit %p cur %p\n",
lp->rfd_base, lp->rfd_limit, lp->rfd_cur);
@@ -829,31 +1086,13 @@ panic_queues(struct net_device *dev)
dump_frfd(lp->fbl_ptr);
panic("%s: Illegal queue state.", dev->name);
}
-
-#if 0
-static void print_buf(char *add, int length)
-{
- int i;
- int len = length;
-
- printk("print_buf(%08x)(%x)\n", (unsigned int) add,length);
-
- if (len > 100)
- len = 100;
- for (i = 0; i < len; i++) {
- printk(" %2.2X", (unsigned char) add[i]);
- if (!(i % 16))
- printk("\n");
- }
- printk("\n");
-}
#endif
static void print_eth(char *add)
{
int i;
- printk("print_eth(%08x)\n", (unsigned int) add);
+ printk("print_eth(%p)\n", add);
for (i = 0; i < 6; i++)
printk(" %2.2X", (unsigned char) add[i + 6]);
printk(" =>");
@@ -862,6 +1101,73 @@ static void print_eth(char *add)
printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]);
}
+static int tc35815_tx_full(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end);
+}
+
+static void tc35815_restart(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ int do_phy_reset = 1;
+ del_timer(&lp->timer); /* Kill if running */
+
+ if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) {
+ /* Resetting PHY cause problem on some chip... (SEEQ 80221) */
+ do_phy_reset = 0;
+ }
+ if (do_phy_reset) {
+ int timeout;
+ tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET);
+ timeout = 100;
+ while (--timeout) {
+ if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET))
+ break;
+ udelay(1);
+ }
+ if (!timeout)
+ printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name);
+ }
+
+ tc35815_chip_reset(dev);
+ tc35815_clear_queues(dev);
+ tc35815_chip_init(dev);
+ /* Reconfigure CAM again since tc35815_chip_init() initialize it. */
+ tc35815_set_multicast_list(dev);
+}
+
+static void tc35815_tx_timeout(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+
+ printk(KERN_WARNING "%s: transmit timed out, status %#x\n",
+ dev->name, tc_readl(&tr->Tx_Stat));
+
+ /* Try to restart the adaptor. */
+ spin_lock_irq(&lp->lock);
+ tc35815_restart(dev);
+ spin_unlock_irq(&lp->lock);
+
+ lp->stats.tx_errors++;
+
+ /* If we have space available to accept new transmit
+ * requests, wake up the queueing layer. This would
+ * be the case if the chipset_init() call above just
+ * flushes out the tx queue and empties it.
+ *
+ * If instead, the tx queue is retained then the
+ * netif_wake_queue() call should be placed in the
+ * TX completion interrupt handler of the driver instead
+ * of here.
+ */
+ if (!tc35815_tx_full(dev))
+ netif_wake_queue(dev);
+}
+
/*
* Open/initialize the board. This is called (in the current kernel)
* sometime after booting when the 'ifconfig' program is run.
@@ -874,16 +1180,16 @@ static int
tc35815_open(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
+
/*
* This is used if the interrupt line can turned off (shared).
* See 3c503.c for an example of selecting the IRQ at config-time.
*/
-
- if (dev->irq == 0 ||
- request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) {
+ if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) {
return -EAGAIN;
}
+ del_timer(&lp->timer); /* Kill if running */
tc35815_chip_reset(dev);
if (tc35815_init_queues(dev) != 0) {
@@ -892,138 +1198,119 @@ tc35815_open(struct net_device *dev)
}
/* Reset the hardware here. Don't forget to set the station address. */
+ spin_lock_irq(&lp->lock);
tc35815_chip_init(dev);
+ spin_unlock_irq(&lp->lock);
- lp->tbusy = 0;
+ /* We are now ready to accept transmit requeusts from
+ * the queueing layer of the networking.
+ */
netif_start_queue(dev);
return 0;
}
-static void tc35815_tx_timeout(struct net_device *dev)
-{
- struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&lp->lock, flags);
- printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
- dev->name, tc_readl(&tr->Tx_Stat));
- /* Try to restart the adaptor. */
- tc35815_chip_reset(dev);
- tc35815_clear_queues(dev);
- tc35815_chip_init(dev);
- lp->tbusy=0;
- spin_unlock_irqrestore(&lp->lock, flags);
- dev->trans_start = jiffies;
- netif_wake_queue(dev);
-}
-
+/* This will only be invoked if your driver is _not_ in XOFF state.
+ * What this means is that you need not check it, and that this
+ * invariant will hold if you make sure that the netif_*_queue()
+ * calls are done at the proper times.
+ */
static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr;
-
- if (netif_queue_stopped(dev)) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk(KERN_WARNING "%s: transmit timed out, status %#lx\n",
- dev->name, tc_readl(&tr->Tx_Stat));
- /* Try to restart the adaptor. */
- tc35815_chip_reset(dev);
- tc35815_clear_queues(dev);
- tc35815_chip_init(dev);
- lp->tbusy=0;
- dev->trans_start = jiffies;
- netif_wake_queue(dev);
- }
+ struct TxFD *txfd;
+ unsigned long flags;
- /*
- * Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, lp->tbusy), but set_bit() works as well.
+ /* If some error occurs while trying to transmit this
+ * packet, you should return '1' from this function.
+ * In such a case you _may not_ do anything to the
+ * SKB, it is still owned by the network queueing
+ * layer when an error is returned. This means you
+ * may not modify any SKB fields, you may not free
+ * the SKB, etc.
*/
- if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- dev_kfree_skb_any(skb);
- } else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
- struct TxFD *txfd = &lp->tfd_base[lp->tfd_start];
- unsigned long flags;
- lp->stats.tx_bytes += skb->len;
+ /* This is the most common case for modern hardware.
+ * The spinlock protects this code from the TX complete
+ * hardware interrupt handler. Queue flow control is
+ * thus managed under this lock as well.
+ */
+ spin_lock_irqsave(&lp->lock, flags);
-#ifdef __mips__
- dma_cache_wback_inv((unsigned long)buf, length);
+ /* failsafe... (handle txdone now if half of FDs are used) */
+ if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM >
+ TX_FD_NUM / 2)
+ tc35815_txdone(dev);
+
+ if (netif_msg_pktdata(lp))
+ print_eth(skb->data);
+#ifdef DEBUG
+ if (lp->tx_skbs[lp->tfd_start].skb) {
+ printk("%s: tx_skbs conflict.\n", dev->name);
+ panic_queues(dev);
+ }
+#else
+ BUG_ON(lp->tx_skbs[lp->tfd_start].skb);
#endif
-
- spin_lock_irqsave(&lp->lock, flags);
-
- /* failsafe... */
- if (lp->tfd_start != lp->tfd_end)
- tc35815_txdone(dev);
-
-
- txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf));
-
- txfd->bd.BDCtl = cpu_to_le32(length);
- txfd->fd.FDSystem = cpu_to_le32((__u32)skb);
- txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
-
- if (lp->tfd_start == lp->tfd_end) {
- /* Start DMA Transmitter. */
- txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
+ lp->tx_skbs[lp->tfd_start].skb = skb;
+ lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+ /*add to ring */
+ txfd = &lp->tfd_base[lp->tfd_start];
+ txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma);
+ txfd->bd.BDCtl = cpu_to_le32(skb->len);
+ txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start);
+ txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT));
+
+ if (lp->tfd_start == lp->tfd_end) {
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ /* Start DMA Transmitter. */
+ txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL);
#ifdef GATHER_TXINT
- txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
+ txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
#endif
- if (tc35815_debug > 2) {
- printk("%s: starting TxFD.\n", dev->name);
- dump_txfd(txfd);
- if (tc35815_debug > 3)
- print_eth(buf);
- }
- tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
- } else {
- txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
- if (tc35815_debug > 2) {
- printk("%s: queueing TxFD.\n", dev->name);
- dump_txfd(txfd);
- if (tc35815_debug > 3)
- print_eth(buf);
- }
+ if (netif_msg_tx_queued(lp)) {
+ printk("%s: starting TxFD.\n", dev->name);
+ dump_txfd(txfd);
}
- lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
+ tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
+ } else {
+ txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL);
+ if (netif_msg_tx_queued(lp)) {
+ printk("%s: queueing TxFD.\n", dev->name);
+ dump_txfd(txfd);
+ }
+ }
+ lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM;
- dev->trans_start = jiffies;
+ dev->trans_start = jiffies;
- if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) {
- /* we can send another packet */
- lp->tbusy = 0;
- netif_start_queue(dev);
- } else {
- netif_stop_queue(dev);
- if (tc35815_debug > 1)
- printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
- }
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* If we just used up the very last entry in the
+ * TX ring on this device, tell the queueing
+ * layer to send no more.
+ */
+ if (tc35815_tx_full(dev)) {
+ if (netif_msg_tx_queued(lp))
+ printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name);
+ netif_stop_queue(dev);
}
+ /* When the TX completion hw interrupt arrives, this
+ * is when the transmit statistics are updated.
+ */
+
+ spin_unlock_irqrestore(&lp->lock, flags);
return 0;
}
#define FATAL_ERROR_INT \
(Int_IntPCI | Int_DmParErr | Int_IntNRAbt)
-static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
+static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status)
{
static int count;
printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):",
dev->name, status);
-
if (status & Int_IntPCI)
printk(" IntPCI");
if (status & Int_DmParErr)
@@ -1033,110 +1320,170 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
printk("\n");
if (count++ > 100)
panic("%s: Too many fatal errors.", dev->name);
- printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname);
+ printk(KERN_WARNING "%s: Resetting ...\n", dev->name);
/* Try to restart the adaptor. */
- tc35815_chip_reset(dev);
- tc35815_clear_queues(dev);
- tc35815_chip_init(dev);
+ tc35815_restart(dev);
+}
+
+#ifdef TC35815_NAPI
+static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit)
+#else
+static int tc35815_do_interrupt(struct net_device *dev, u32 status)
+#endif
+{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int ret = -1;
+
+ /* Fatal errors... */
+ if (status & FATAL_ERROR_INT) {
+ tc35815_fatal_error_interrupt(dev, status);
+ return 0;
+ }
+ /* recoverable errors */
+ if (status & Int_IntFDAEx) {
+ /* disable FDAEx int. (until we make rooms...) */
+ tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
+ printk(KERN_WARNING
+ "%s: Free Descriptor Area Exhausted (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_dropped++;
+ ret = 0;
+ }
+ if (status & Int_IntBLEx) {
+ /* disable BLEx int. (until we make rooms...) */
+ tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
+ printk(KERN_WARNING
+ "%s: Buffer List Exhausted (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_dropped++;
+ ret = 0;
+ }
+ if (status & Int_IntExBD) {
+ printk(KERN_WARNING
+ "%s: Excessive Buffer Descriptiors (%#x).\n",
+ dev->name, status);
+ lp->stats.rx_length_errors++;
+ ret = 0;
+ }
+
+ /* normal notification */
+ if (status & Int_IntMacRx) {
+ /* Got a packet(s). */
+#ifdef TC35815_NAPI
+ ret = tc35815_rx(dev, limit);
+#else
+ tc35815_rx(dev);
+ ret = 0;
+#endif
+ lp->lstats.rx_ints++;
+ }
+ if (status & Int_IntMacTx) {
+ /* Transmit complete. */
+ lp->lstats.tx_ints++;
+ tc35815_txdone(dev);
+ netif_wake_queue(dev);
+ ret = 0;
+ }
+ return ret;
}
/*
* The typical workload of the driver:
- * Handle the network interface interrupts.
+ * Handle the network interface interrupts.
*/
static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
- struct tc35815_regs *tr;
- struct tc35815_local *lp;
- int status, boguscount = 0;
- int handled = 0;
-
- if (dev == NULL) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
- return IRQ_NONE;
- }
-
- tr = (struct tc35815_regs*)dev->base_addr;
- lp = dev->priv;
-
- do {
- status = tc_readl(&tr->Int_Src);
- if (status == 0)
- break;
- handled = 1;
- tc_writel(status, &tr->Int_Src); /* write to clear */
-
- /* Fatal errors... */
- if (status & FATAL_ERROR_INT) {
- tc35815_fatal_error_interrupt(dev, status);
- break;
- }
- /* recoverable errors */
- if (status & Int_IntFDAEx) {
- /* disable FDAEx int. (until we make rooms...) */
- tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En);
- printk(KERN_WARNING
- "%s: Free Descriptor Area Exhausted (%#x).\n",
- dev->name, status);
- lp->stats.rx_dropped++;
- }
- if (status & Int_IntBLEx) {
- /* disable BLEx int. (until we make rooms...) */
- tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En);
- printk(KERN_WARNING
- "%s: Buffer List Exhausted (%#x).\n",
- dev->name, status);
- lp->stats.rx_dropped++;
- }
- if (status & Int_IntExBD) {
- printk(KERN_WARNING
- "%s: Excessive Buffer Descriptiors (%#x).\n",
- dev->name, status);
- lp->stats.rx_length_errors++;
- }
- /* normal notification */
- if (status & Int_IntMacRx) {
- /* Got a packet(s). */
- lp->lstats.rx_ints++;
- tc35815_rx(dev);
- }
- if (status & Int_IntMacTx) {
- lp->lstats.tx_ints++;
- tc35815_txdone(dev);
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+#ifdef TC35815_NAPI
+ u32 dmactl = tc_readl(&tr->DMA_Ctl);
+
+ if (!(dmactl & DMA_IntMask)) {
+ /* disable interrupts */
+ tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
+ if (netif_rx_schedule_prep(dev))
+ __netif_rx_schedule(dev);
+ else {
+ printk(KERN_ERR "%s: interrupt taken in poll\n",
+ dev->name);
+ BUG();
}
- } while (++boguscount < 20) ;
+ (void)tc_readl(&tr->Int_Src); /* flush */
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+#else
+ struct tc35815_local *lp = dev->priv;
+ int handled;
+ u32 status;
+
+ spin_lock(&lp->lock);
+ status = tc_readl(&tr->Int_Src);
+ tc_writel(status, &tr->Int_Src); /* write to clear */
+ handled = tc35815_do_interrupt(dev, status);
+ (void)tc_readl(&tr->Int_Src); /* flush */
+ spin_unlock(&lp->lock);
+ return IRQ_RETVAL(handled >= 0);
+#endif /* TC35815_NAPI */
+}
- return IRQ_RETVAL(handled);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void tc35815_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ tc35815_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
}
+#endif
/* We have a good packet(s), get it/them out of the buffers. */
+#ifdef TC35815_NAPI
+static int
+tc35815_rx(struct net_device *dev, int limit)
+#else
static void
tc35815_rx(struct net_device *dev)
+#endif
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
unsigned int fdctl;
int i;
int buf_free_count = 0;
int fd_free_count = 0;
+#ifdef TC35815_NAPI
+ int received = 0;
+#endif
while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) {
int status = le32_to_cpu(lp->rfd_cur->fd.FDStat);
int pkt_len = fdctl & FD_FDLength_MASK;
- struct RxFD *next_rfd;
int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT;
+#ifdef DEBUG
+ struct RxFD *next_rfd;
+#endif
+#if (RX_CTL_CMD & Rx_StripCRC) == 0
+ pkt_len -= 4;
+#endif
- if (tc35815_debug > 2)
+ if (netif_msg_rx_status(lp))
dump_rxfd(lp->rfd_cur);
if (status & Rx_Good) {
- /* Malloc up new buffer. */
struct sk_buff *skb;
unsigned char *data;
- int cur_bd, offset;
-
- lp->stats.rx_bytes += pkt_len;
+ int cur_bd;
+#ifdef TC35815_USE_PACKEDBUFFER
+ int offset;
+#endif
+#ifdef TC35815_NAPI
+ if (--limit < 0)
+ break;
+#endif
+#ifdef TC35815_USE_PACKEDBUFFER
+ BUG_ON(bd_count > 2);
skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1154,25 +1501,69 @@ tc35815_rx(struct net_device *dev)
while (offset < pkt_len && cur_bd < bd_count) {
int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) &
BD_BuffLength_MASK;
- void *rxbuf =
- bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData));
-#ifdef __mips__
- dma_cache_inv((unsigned long)rxbuf, len);
+ dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData);
+ void *rxbuf = rxbuf_bus_to_virt(lp, dma);
+ if (offset + len > pkt_len)
+ len = pkt_len - offset;
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+ pci_dma_sync_single_for_cpu(lp->pci_dev,
+ dma, len,
+ PCI_DMA_FROMDEVICE);
#endif
memcpy(data + offset, rxbuf, len);
+#ifdef TC35815_DMA_SYNC_ONDEMAND
+ pci_dma_sync_single_for_device(lp->pci_dev,
+ dma, len,
+ PCI_DMA_FROMDEVICE);
+#endif
offset += len;
cur_bd++;
}
-#if 0
- print_buf(data,pkt_len);
+#else /* TC35815_USE_PACKEDBUFFER */
+ BUG_ON(bd_count > 1);
+ cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl)
+ & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
+#ifdef DEBUG
+ if (cur_bd >= RX_BUF_NUM) {
+ printk("%s: invalid BDID.\n", dev->name);
+ panic_queues(dev);
+ }
+ BUG_ON(lp->rx_skbs[cur_bd].skb_dma !=
+ (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3));
+ if (!lp->rx_skbs[cur_bd].skb) {
+ printk("%s: NULL skb.\n", dev->name);
+ panic_queues(dev);
+ }
+#else
+ BUG_ON(cur_bd >= RX_BUF_NUM);
#endif
- if (tc35815_debug > 3)
+ skb = lp->rx_skbs[cur_bd].skb;
+ prefetch(skb->data);
+ lp->rx_skbs[cur_bd].skb = NULL;
+ lp->fbl_count--;
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_skbs[cur_bd].skb_dma,
+ RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ if (!HAVE_DMA_RXALIGN(lp))
+ memmove(skb->data, skb->data - 2, pkt_len);
+ data = skb_put(skb, pkt_len);
+#endif /* TC35815_USE_PACKEDBUFFER */
+ if (netif_msg_pktdata(lp))
print_eth(data);
skb->protocol = eth_type_trans(skb, dev);
+#ifdef TC35815_NAPI
+ netif_receive_skb(skb);
+ received++;
+#else
netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
lp->stats.rx_packets++;
+ lp->stats.rx_bytes += pkt_len;
} else {
lp->stats.rx_errors++;
+ printk(KERN_DEBUG "%s: Rx error (status %x)\n",
+ dev->name, status & Rx_Stat_Mask);
/* WORKAROUND: LongErr and CRCErr means Overflow. */
if ((status & Rx_LongErr) && (status & Rx_CRCErr)) {
status &= ~(Rx_LongErr|Rx_CRCErr);
@@ -1189,63 +1580,150 @@ tc35815_rx(struct net_device *dev)
int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl);
unsigned char id =
(bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT;
- if (id >= RX_BUF_PAGES) {
+#ifdef DEBUG
+ if (id >= RX_BUF_NUM) {
printk("%s: invalid BDID.\n", dev->name);
panic_queues(dev);
}
+#else
+ BUG_ON(id >= RX_BUF_NUM);
+#endif
/* free old buffers */
- while (lp->fbl_curid != id) {
- bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl);
+#ifdef TC35815_USE_PACKEDBUFFER
+ while (lp->fbl_curid != id)
+#else
+ while (lp->fbl_count < RX_BUF_NUM)
+#endif
+ {
+#ifdef TC35815_USE_PACKEDBUFFER
+ unsigned char curid = lp->fbl_curid;
+#else
+ unsigned char curid =
+ (id + 1 + lp->fbl_count) % RX_BUF_NUM;
+#endif
+ struct BDesc *bd = &lp->fbl_ptr->bd[curid];
+#ifdef DEBUG
+ bdctl = le32_to_cpu(bd->BDCtl);
if (bdctl & BD_CownsBD) {
printk("%s: Freeing invalid BD.\n",
dev->name);
panic_queues(dev);
}
+#endif
/* pass BD to controler */
+#ifndef TC35815_USE_PACKEDBUFFER
+ if (!lp->rx_skbs[curid].skb) {
+ lp->rx_skbs[curid].skb =
+ alloc_rxbuf_skb(dev,
+ lp->pci_dev,
+ &lp->rx_skbs[curid].skb_dma);
+ if (!lp->rx_skbs[curid].skb)
+ break; /* try on next reception */
+ bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma);
+ }
+#endif /* TC35815_USE_PACKEDBUFFER */
/* Note: BDLength was modified by chip. */
- lp->fbl_ptr->bd[lp->fbl_curid].BDCtl =
- cpu_to_le32(BD_CownsBD |
- (lp->fbl_curid << BD_RxBDID_SHIFT) |
- PAGE_SIZE);
- lp->fbl_curid =
- (lp->fbl_curid + 1) % RX_BUF_PAGES;
- if (tc35815_debug > 2) {
+ bd->BDCtl = cpu_to_le32(BD_CownsBD |
+ (curid << BD_RxBDID_SHIFT) |
+ RX_BUF_SIZE);
+#ifdef TC35815_USE_PACKEDBUFFER
+ lp->fbl_curid = (curid + 1) % RX_BUF_NUM;
+ if (netif_msg_rx_status(lp)) {
printk("%s: Entering new FBD %d\n",
dev->name, lp->fbl_curid);
dump_frfd(lp->fbl_ptr);
}
+#else
+ lp->fbl_count++;
+#endif
buf_free_count++;
}
}
/* put RxFD back to controller */
- next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext));
-#ifdef __mips__
- next_rfd = (struct RxFD *)vtonocache(next_rfd);
-#endif
+#ifdef DEBUG
+ next_rfd = fd_bus_to_virt(lp,
+ le32_to_cpu(lp->rfd_cur->fd.FDNext));
if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) {
printk("%s: RxFD FDNext invalid.\n", dev->name);
panic_queues(dev);
}
+#endif
for (i = 0; i < (bd_count + 1) / 2 + 1; i++) {
/* pass FD to controler */
- lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */
+#ifdef DEBUG
+ lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead);
+#else
+ lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL);
+#endif
lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD);
lp->rfd_cur++;
fd_free_count++;
}
-
- lp->rfd_cur = next_rfd;
+ if (lp->rfd_cur > lp->rfd_limit)
+ lp->rfd_cur = lp->rfd_base;
+#ifdef DEBUG
+ if (lp->rfd_cur != next_rfd)
+ printk("rfd_cur = %p, next_rfd %p\n",
+ lp->rfd_cur, next_rfd);
+#endif
}
/* re-enable BL/FDA Exhaust interrupts. */
if (fd_free_count) {
- tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En);
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ u32 en, en_old = tc_readl(&tr->Int_En);
+ en = en_old | Int_FDAExEn;
if (buf_free_count)
- tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En);
+ en |= Int_BLExEn;
+ if (en != en_old)
+ tc_writel(en, &tr->Int_En);
}
+#ifdef TC35815_NAPI
+ return received;
+#endif
}
+#ifdef TC35815_NAPI
+static int
+tc35815_poll(struct net_device *dev, int *budget)
+{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int limit = min(*budget, dev->quota);
+ int received = 0, handled;
+ u32 status;
+
+ spin_lock(&lp->lock);
+ status = tc_readl(&tr->Int_Src);
+ do {
+ tc_writel(status, &tr->Int_Src); /* write to clear */
+
+ handled = tc35815_do_interrupt(dev, status, limit);
+ if (handled >= 0) {
+ received += handled;
+ limit -= handled;
+ if (limit <= 0)
+ break;
+ }
+ status = tc_readl(&tr->Int_Src);
+ } while (status);
+ spin_unlock(&lp->lock);
+
+ dev->quota -= received;
+ *budget -= received;
+ if (limit <= 0)
+ return 1;
+
+ netif_rx_complete(dev);
+ /* enable interrupts */
+ tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+ return 0;
+}
+#endif
+
#ifdef NO_CHECK_CARRIER
#define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr)
#else
@@ -1264,9 +1742,17 @@ tc35815_check_tx_stat(struct net_device *dev, int status)
if (status & Tx_TxColl_MASK)
lp->stats.collisions += status & Tx_TxColl_MASK;
+#ifndef NO_CHECK_CARRIER
+ /* TX4939 does not have NCarr */
+ if (lp->boardtype == TC35815_TX4939)
+ status &= ~Tx_NCarr;
+#ifdef WORKAROUND_LOSTCAR
/* WORKAROUND: ignore LostCrS in full duplex operation */
- if (lp->fullduplex)
+ if ((lp->timer_state != asleep && lp->timer_state != lcheck)
+ || lp->fullduplex)
status &= ~Tx_NCarr;
+#endif
+#endif
if (!(status & TX_STA_ERR)) {
/* no error. */
@@ -1282,6 +1768,15 @@ tc35815_check_tx_stat(struct net_device *dev, int status)
if (status & Tx_Under) {
lp->stats.tx_fifo_errors++;
msg = "Tx FIFO Underrun.";
+ if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) {
+ lp->lstats.tx_underrun++;
+ if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) {
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh);
+ msg = "Tx FIFO Underrun.Change Tx threshold to max.";
+ }
+ }
}
if (status & Tx_Defer) {
lp->stats.tx_fifo_errors++;
@@ -1305,18 +1800,19 @@ tc35815_check_tx_stat(struct net_device *dev, int status)
lp->stats.tx_heartbeat_errors++;
msg = "Signal Quality Error.";
}
- if (msg)
+ if (msg && netif_msg_tx_err(lp))
printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status);
}
+/* This handles TX complete events posted by the device
+ * via interrupts.
+ */
static void
tc35815_txdone(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
struct TxFD *txfd;
unsigned int fdctl;
- int num_done = 0;
txfd = &lp->tfd_base[lp->tfd_end];
while (lp->tfd_start != lp->tfd_end &&
@@ -1324,38 +1820,61 @@ tc35815_txdone(struct net_device *dev)
int status = le32_to_cpu(txfd->fd.FDStat);
struct sk_buff *skb;
unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext);
+ u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem);
- if (tc35815_debug > 2) {
+ if (netif_msg_tx_done(lp)) {
printk("%s: complete TxFD.\n", dev->name);
dump_txfd(txfd);
}
tc35815_check_tx_stat(dev, status);
- skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem);
+ skb = fdsystem != 0xffffffff ?
+ lp->tx_skbs[fdsystem].skb : NULL;
+#ifdef DEBUG
+ if (lp->tx_skbs[lp->tfd_end].skb != skb) {
+ printk("%s: tx_skbs mismatch.\n", dev->name);
+ panic_queues(dev);
+ }
+#else
+ BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb);
+#endif
if (skb) {
+ lp->stats.tx_bytes += skb->len;
+ pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE);
+ lp->tx_skbs[lp->tfd_end].skb = NULL;
+ lp->tx_skbs[lp->tfd_end].skb_dma = 0;
+#ifdef TC35815_NAPI
dev_kfree_skb_any(skb);
+#else
+ dev_kfree_skb_irq(skb);
+#endif
}
- txfd->fd.FDSystem = cpu_to_le32(0);
+ txfd->fd.FDSystem = cpu_to_le32(0xffffffff);
- num_done++;
lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM;
txfd = &lp->tfd_base[lp->tfd_end];
- if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) {
+#ifdef DEBUG
+ if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) {
printk("%s: TxFD FDNext invalid.\n", dev->name);
panic_queues(dev);
}
+#endif
if (fdnext & FD_Next_EOL) {
/* DMA Transmitter has been stopping... */
if (lp->tfd_end != lp->tfd_start) {
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM;
struct TxFD* txhead = &lp->tfd_base[head];
int qlen = (lp->tfd_start + TX_FD_NUM
- lp->tfd_end) % TX_FD_NUM;
+#ifdef DEBUG
if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) {
printk("%s: TxFD FDCtl invalid.\n", dev->name);
panic_queues(dev);
}
+#endif
/* log max queue length */
if (lp->lstats.max_tx_qlen < qlen)
lp->lstats.max_tx_qlen = qlen;
@@ -1366,21 +1885,23 @@ tc35815_txdone(struct net_device *dev)
#ifdef GATHER_TXINT
txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx);
#endif
- if (tc35815_debug > 2) {
+ if (netif_msg_tx_queued(lp)) {
printk("%s: start TxFD on queue.\n",
dev->name);
dump_txfd(txfd);
}
- tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr);
+ tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr);
}
break;
}
}
- if (num_done > 0 && lp->tbusy) {
- lp->tbusy = 0;
- netif_start_queue(dev);
- }
+ /* If we had stopped the queue due to a "tx full"
+ * condition, and space has now been made available,
+ * wake up the queue.
+ */
+ if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev))
+ netif_wake_queue(dev);
}
/* The inverse routine to tc35815_open(). */
@@ -1388,18 +1909,18 @@ static int
tc35815_close(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
-
- lp->tbusy = 1;
netif_stop_queue(dev);
/* Flush the Tx and disable Rx here. */
+ del_timer(&lp->timer); /* Kill if running */
tc35815_chip_reset(dev);
free_irq(dev->irq, dev);
tc35815_free_queues(dev);
return 0;
+
}
/*
@@ -1409,29 +1930,29 @@ tc35815_close(struct net_device *dev)
static struct net_device_stats *tc35815_get_stats(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
- unsigned long flags;
-
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
if (netif_running(dev)) {
- spin_lock_irqsave(&lp->lock, flags);
/* Update the statistics from the device registers. */
lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt);
- spin_unlock_irqrestore(&lp->lock, flags);
}
return &lp->stats;
}
-static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr)
+static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr)
{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
int cam_index = index * 6;
- unsigned long cam_data;
- unsigned long saved_addr;
+ u32 cam_data;
+ u32 saved_addr;
saved_addr = tc_readl(&tr->CAM_Adr);
- if (tc35815_debug > 1) {
+ if (netif_msg_hw(lp)) {
int i;
- printk(KERN_DEBUG "%s: CAM %d:", cardname, index);
+ printk(KERN_DEBUG "%s: CAM %d:", dev->name, index);
for (i = 0; i < 6; i++)
printk(" %02x", addr[i]);
printk("\n");
@@ -1458,14 +1979,6 @@ static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned c
tc_writel(cam_data, &tr->CAM_Data);
}
- if (tc35815_debug > 2) {
- int i;
- for (i = cam_index / 4; i < cam_index / 4 + 2; i++) {
- tc_writel(i * 4, &tr->CAM_Adr);
- printk("CAM 0x%x: %08lx",
- i * 4, tc_readl(&tr->CAM_Data));
- }
- }
tc_writel(saved_addr, &tr->CAM_Adr);
}
@@ -1480,10 +1993,19 @@ static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned c
static void
tc35815_set_multicast_list(struct net_device *dev)
{
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
if (dev->flags&IFF_PROMISC)
{
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* With some (all?) 100MHalf HUB, controller will hang
+ * if we enabled promiscuous mode before linkup... */
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS))
+ return;
+#endif
/* Enable promiscuous mode */
tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl);
}
@@ -1505,7 +2027,7 @@ tc35815_set_multicast_list(struct net_device *dev)
if (!cur_addr)
break;
/* entry 0,1 is reserved. */
- tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr);
+ tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
ena_bits |= CAM_Ena_Bit(i + 2);
}
tc_writel(ena_bits, &tr->CAM_Ena);
@@ -1517,122 +2039,753 @@ tc35815_set_multicast_list(struct net_device *dev)
}
}
-static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg)
+static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct tc35815_local *lp = dev->priv;
- unsigned long data;
- unsigned long flags;
+ strcpy(info->driver, MODNAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->bus_info, pci_name(lp->pci_dev));
+}
- spin_lock_irqsave(&lp->lock, flags);
+static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct tc35815_local *lp = dev->priv;
+ spin_lock_irq(&lp->lock);
+ mii_ethtool_gset(&lp->mii, cmd);
+ spin_unlock_irq(&lp->lock);
+ return 0;
+}
- tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
+static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+#if 1 /* use our negotiation method... */
+ /* Verify the settings we care about. */
+ if (cmd->autoneg != AUTONEG_ENABLE &&
+ cmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (cmd->autoneg == AUTONEG_DISABLE &&
+ ((cmd->speed != SPEED_100 &&
+ cmd->speed != SPEED_10) ||
+ (cmd->duplex != DUPLEX_HALF &&
+ cmd->duplex != DUPLEX_FULL)))
+ return -EINVAL;
+
+ /* Ok, do it to it. */
+ spin_lock_irq(&lp->lock);
+ del_timer(&lp->timer);
+ tc35815_start_auto_negotiation(dev, cmd);
+ spin_unlock_irq(&lp->lock);
+ rc = 0;
+#else
+ spin_lock_irq(&lp->lock);
+ rc = mii_ethtool_sset(&lp->mii, cmd);
+ spin_unlock_irq(&lp->lock);
+#endif
+ return rc;
+}
+
+static int tc35815_nway_reset(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+ spin_lock_irq(&lp->lock);
+ rc = mii_nway_restart(&lp->mii);
+ spin_unlock_irq(&lp->lock);
+ return rc;
+}
+
+static u32 tc35815_get_link(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+ spin_lock_irq(&lp->lock);
+ rc = mii_link_ok(&lp->mii);
+ spin_unlock_irq(&lp->lock);
+ return rc;
+}
+
+static u32 tc35815_get_msglevel(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ return lp->msg_enable;
+}
+
+static void tc35815_set_msglevel(struct net_device *dev, u32 datum)
+{
+ struct tc35815_local *lp = dev->priv;
+ lp->msg_enable = datum;
+}
+
+static int tc35815_get_stats_count(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ return sizeof(lp->lstats) / sizeof(int);
+}
+
+static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
+{
+ struct tc35815_local *lp = dev->priv;
+ data[0] = lp->lstats.max_tx_qlen;
+ data[1] = lp->lstats.tx_ints;
+ data[2] = lp->lstats.rx_ints;
+ data[3] = lp->lstats.tx_underrun;
+}
+
+static struct {
+ const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "max_tx_qlen" },
+ { "tx_ints" },
+ { "rx_ints" },
+ { "tx_underrun" },
+};
+
+static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+static const struct ethtool_ops tc35815_ethtool_ops = {
+ .get_drvinfo = tc35815_get_drvinfo,
+ .get_settings = tc35815_get_settings,
+ .set_settings = tc35815_set_settings,
+ .nway_reset = tc35815_nway_reset,
+ .get_link = tc35815_get_link,
+ .get_msglevel = tc35815_get_msglevel,
+ .set_msglevel = tc35815_set_msglevel,
+ .get_strings = tc35815_get_strings,
+ .get_stats_count = tc35815_get_stats_count,
+ .get_ethtool_stats = tc35815_get_ethtool_stats,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+};
+
+static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct tc35815_local *lp = dev->priv;
+ int rc;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ spin_lock_irq(&lp->lock);
+ rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL);
+ spin_unlock_irq(&lp->lock);
+
+ return rc;
+}
+
+static int tc_mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ u32 data;
+ tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA);
while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
;
data = tc_readl(&tr->MD_Data);
- spin_unlock_irqrestore(&lp->lock, flags);
- return data;
+ return data & 0xffff;
+}
+
+static void tc_mdio_write(struct net_device *dev, int phy_id, int location,
+ int val)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ tc_writel(val, &tr->MD_Data);
+ tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA);
+ while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
+ ;
}
-static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg)
+/* Auto negotiation. The scheme is very simple. We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen. For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for. The priority for link configurations, highest first
+ * is:
+ * 100 Base-T Full Duplex
+ * 100 Base-T Half Duplex
+ * 10 Base-T Full Duplex
+ * 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected. This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840. When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+/* Note: Above comments are come from sunhme driver. */
+
+static int tc35815_try_next_permutation(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- unsigned long flags;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
- spin_lock_irqsave(&lp->lock, flags);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
- tc_writel(d, &tr->MD_Data);
- tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA);
- while (tc_readl(&tr->MD_CA) & MD_CA_Busy)
- ;
- spin_unlock_irqrestore(&lp->lock, flags);
+ /* Downgrade from full to half duplex. Only possible via ethtool. */
+ if (bmcr & BMCR_FULLDPLX) {
+ bmcr &= ~BMCR_FULLDPLX;
+ printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+ return 0;
+ }
+
+ /* Downgrade from 100 to 10. */
+ if (bmcr & BMCR_SPEED100) {
+ bmcr &= ~BMCR_SPEED100;
+ printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr);
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+ return 0;
+ }
+
+ /* We've tried everything. */
+ return -1;
}
-static void tc35815_phy_chip_init(struct net_device *dev)
+static void
+tc35815_display_link_mode(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
- static int first = 1;
- unsigned short ctl;
-
- if (first) {
- unsigned short id0, id1;
- int count;
- first = 0;
-
- /* first data written to the PHY will be an ID number */
- tc_phy_write(dev, 0, tr, 0, MII_CONTROL); /* ID:0 */
-#if 0
- tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL);
- printk(KERN_INFO "%s: Resetting PHY...", dev->name);
- while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET)
- ;
- printk("\n");
- tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0,
- MII_CONTROL);
-#endif
- id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0);
- id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1);
- printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name,
- id0, id1);
- if (lp->option & TC35815_OPT_10M) {
- lp->linkspeed = 10;
- lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
- } else if (lp->option & TC35815_OPT_100M) {
- lp->linkspeed = 100;
- lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0;
+ int pid = lp->phy_addr;
+ unsigned short lpa, bmcr;
+ char *speed = "", *duplex = "";
+
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+ speed = "100Mb/s";
+ else
+ speed = "10Mb/s";
+ if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+ duplex = "Full Duplex";
+ else
+ duplex = "Half Duplex";
+
+ if (netif_msg_link(lp))
+ printk(KERN_INFO "%s: Link is up at %s, %s.\n",
+ dev->name, speed, duplex);
+ printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+ dev->name,
+ bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+}
+
+static void tc35815_display_forced_link_mode(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
+ char *speed = "", *duplex = "";
+
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_SPEED100)
+ speed = "100Mb/s";
+ else
+ speed = "10Mb/s";
+ if (bmcr & BMCR_FULLDPLX)
+ duplex = "Full Duplex.\n";
+ else
+ duplex = "Half Duplex.\n";
+
+ if (netif_msg_link(lp))
+ printk(KERN_INFO "%s: Link has been forced up at %s, %s",
+ dev->name, speed, duplex);
+}
+
+static void tc35815_set_link_modes(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int pid = lp->phy_addr;
+ unsigned short bmcr, lpa;
+ int speed;
+
+ if (lp->timer_state == arbwait) {
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n",
+ dev->name,
+ bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa);
+ if (!(lpa & (LPA_10HALF | LPA_10FULL |
+ LPA_100HALF | LPA_100FULL))) {
+ /* fall back to 10HALF */
+ printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n",
+ dev->name, lpa);
+ lpa = LPA_10HALF;
+ }
+ if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL)))
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL)))
+ speed = 100;
+ else
+ speed = 10;
+ } else {
+ /* Forcing a link mode. */
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_FULLDPLX)
+ lp->fullduplex = 1;
+ else
+ lp->fullduplex = 0;
+ if (bmcr & BMCR_SPEED100)
+ speed = 100;
+ else
+ speed = 10;
+ }
+
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl);
+ if (lp->fullduplex) {
+ tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+ } else {
+ tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl);
+ }
+ tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl);
+
+ /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */
+
+#ifndef NO_CHECK_CARRIER
+ /* TX4939 does not have EnLCarr */
+ if (lp->boardtype != TC35815_TX4939) {
+#ifdef WORKAROUND_LOSTCAR
+ /* WORKAROUND: enable LostCrS only if half duplex operation */
+ if (!lp->fullduplex && lp->boardtype != TC35815_TX4939)
+ tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl);
+#endif
+ }
+#endif
+ lp->mii.full_duplex = lp->fullduplex;
+}
+
+static void tc35815_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmsr, bmcr, lpa;
+ int restart_timer = 0;
+
+ spin_lock_irq(&lp->lock);
+
+ lp->timer_ticks++;
+ switch (lp->timer_state) {
+ case arbwait:
+ /*
+ * Only allow for 5 ticks, thats 10 seconds and much too
+ * long to wait for arbitration to complete.
+ */
+ /* TC35815 need more times... */
+ if (lp->timer_ticks >= 10) {
+ /* Enter force mode. */
+ if (!options.doforce) {
+ printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+ " cable probblem?\n", dev->name);
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
+ }
+ printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful,"
+ " trying force link mode\n", dev->name);
+ printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name,
+ tc_mdio_read(dev, pid, MII_BMCR),
+ tc_mdio_read(dev, pid, MII_BMSR));
+ bmcr = BMCR_SPEED100;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /*
+ * OK, seems we need do disable the transceiver
+ * for the first tick to make sure we get an
+ * accurate link state at the second tick.
+ */
+
+ lp->timer_state = ltrywait;
+ lp->timer_ticks = 0;
+ restart_timer = 1;
} else {
- /* auto negotiation */
- unsigned long neg_result;
- tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL);
- printk(KERN_INFO "%s: Auto Negotiation...", dev->name);
- count = 0;
- while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) {
- if (count++ > 5000) {
- printk(" failed. Assume 10Mbps\n");
- lp->linkspeed = 10;
- lp->fullduplex = 0;
- goto done;
+ /* Anything interesting happen? */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ if (bmsr & BMSR_ANEGCOMPLETE) {
+ /* Just what we've been waiting for... */
+ tc35815_set_link_modes(dev);
+
+ /*
+ * Success, at least so far, advance our state
+ * engine.
+ */
+ lp->timer_state = lupwait;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case lupwait:
+ /*
+ * Auto negotiation was successful and we are awaiting a
+ * link up status. I have decided to let this timer run
+ * forever until some sort of error is signalled, reporting
+ * a message to the user at 10 second intervals.
+ */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ if (bmsr & BMSR_LSTATUS) {
+ /*
+ * Wheee, it's up, display the link mode in use and put
+ * the timer to sleep.
+ */
+ tc35815_display_link_mode(dev);
+ netif_carrier_on(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* delayed promiscuous enabling */
+ if (dev->flags & IFF_PROMISC)
+ tc35815_set_multicast_list(dev);
+#endif
+#if 1
+ lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+ lp->timer_state = lcheck;
+ restart_timer = 1;
+#else
+ lp->timer_state = asleep;
+ restart_timer = 0;
+#endif
+ } else {
+ if (lp->timer_ticks >= 10) {
+ printk(KERN_NOTICE "%s: Auto negotiation successful, link still "
+ "not completely up.\n", dev->name);
+ lp->timer_ticks = 0;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case ltrywait:
+ /*
+ * Making the timeout here too long can make it take
+ * annoyingly long to attempt all of the link mode
+ * permutations, but then again this is essentially
+ * error recovery code for the most part.
+ */
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (lp->timer_ticks == 1) {
+ /*
+ * Re-enable transceiver, we'll re-enable the
+ * transceiver next tick, then check link state
+ * on the following tick.
+ */
+ restart_timer = 1;
+ break;
+ }
+ if (lp->timer_ticks == 2) {
+ restart_timer = 1;
+ break;
+ }
+ if (bmsr & BMSR_LSTATUS) {
+ /* Force mode selection success. */
+ tc35815_display_forced_link_mode(dev);
+ netif_carrier_on(dev);
+ tc35815_set_link_modes(dev);
+#ifdef WORKAROUND_100HALF_PROMISC
+ /* delayed promiscuous enabling */
+ if (dev->flags & IFF_PROMISC)
+ tc35815_set_multicast_list(dev);
+#endif
+#if 1
+ lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA);
+ lp->timer_state = lcheck;
+ restart_timer = 1;
+#else
+ lp->timer_state = asleep;
+ restart_timer = 0;
+#endif
+ } else {
+ if (lp->timer_ticks >= 4) { /* 6 seconds or so... */
+ int ret;
+
+ ret = tc35815_try_next_permutation(dev);
+ if (ret == -1) {
+ /*
+ * Aieee, tried them all, reset the
+ * chip and try all over again.
+ */
+ printk(KERN_NOTICE "%s: Link down, "
+ "cable problem?\n",
+ dev->name);
+
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
}
- if (count % 512 == 0)
- printk(".");
- mdelay(1);
+ lp->timer_ticks = 0;
+ restart_timer = 1;
+ } else {
+ restart_timer = 1;
+ }
+ }
+ break;
+
+ case lcheck:
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ lpa = tc_mdio_read(dev, pid, MII_LPA);
+ if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) {
+ printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name,
+ bmcr);
+ } else if ((lp->saved_lpa ^ lpa) &
+ (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) {
+ printk(KERN_NOTICE "%s: link status changed"
+ " (BMCR %x LPA %x->%x)\n", dev->name,
+ bmcr, lp->saved_lpa, lpa);
+ } else {
+ /* go on */
+ restart_timer = 1;
+ break;
+ }
+ /* Try to restart the adaptor. */
+ tc35815_restart(dev);
+ goto out;
+
+ case asleep:
+ default:
+ /* Can't happens.... */
+ printk(KERN_ERR "%s: Aieee, link timer is asleep but we got "
+ "one anyways!\n", dev->name);
+ restart_timer = 0;
+ lp->timer_ticks = 0;
+ lp->timer_state = asleep; /* foo on you */
+ break;
+ }
+
+ if (restart_timer) {
+ lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+ add_timer(&lp->timer);
+ }
+out:
+ spin_unlock_irq(&lp->lock);
+}
+
+static void tc35815_start_auto_negotiation(struct net_device *dev,
+ struct ethtool_cmd *ep)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmsr, bmcr, advertize;
+ int timeout;
+
+ netif_carrier_off(dev);
+ bmsr = tc_mdio_read(dev, pid, MII_BMSR);
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ advertize = tc_mdio_read(dev, pid, MII_ADVERTISE);
+
+ if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+ if (options.speed || options.duplex) {
+ /* Advertise only specified configuration. */
+ advertize &= ~(ADVERTISE_10HALF |
+ ADVERTISE_10FULL |
+ ADVERTISE_100HALF |
+ ADVERTISE_100FULL);
+ if (options.speed != 10) {
+ if (options.duplex != 1)
+ advertize |= ADVERTISE_100FULL;
+ if (options.duplex != 2)
+ advertize |= ADVERTISE_100HALF;
+ }
+ if (options.speed != 100) {
+ if (options.duplex != 1)
+ advertize |= ADVERTISE_10FULL;
+ if (options.duplex != 2)
+ advertize |= ADVERTISE_10HALF;
}
- printk(" done.\n");
- neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR);
- if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX))
- lp->linkspeed = 100;
+ if (options.speed == 100)
+ bmcr |= BMCR_SPEED100;
+ else if (options.speed == 10)
+ bmcr &= ~BMCR_SPEED100;
+ if (options.duplex == 2)
+ bmcr |= BMCR_FULLDPLX;
+ else if (options.duplex == 1)
+ bmcr &= ~BMCR_FULLDPLX;
+ } else {
+ /* Advertise everything we can support. */
+ if (bmsr & BMSR_10HALF)
+ advertize |= ADVERTISE_10HALF;
else
- lp->linkspeed = 10;
- if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX))
- lp->fullduplex = 1;
+ advertize &= ~ADVERTISE_10HALF;
+ if (bmsr & BMSR_10FULL)
+ advertize |= ADVERTISE_10FULL;
else
- lp->fullduplex = 0;
- done:
- ;
+ advertize &= ~ADVERTISE_10FULL;
+ if (bmsr & BMSR_100HALF)
+ advertize |= ADVERTISE_100HALF;
+ else
+ advertize &= ~ADVERTISE_100HALF;
+ if (bmsr & BMSR_100FULL)
+ advertize |= ADVERTISE_100FULL;
+ else
+ advertize &= ~ADVERTISE_100FULL;
+ }
+
+ tc_mdio_write(dev, pid, MII_ADVERTISE, advertize);
+
+ /* Enable Auto-Negotiation, this is usually on already... */
+ bmcr |= BMCR_ANENABLE;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /* Restart it to make sure it is going. */
+ bmcr |= BMCR_ANRESTART;
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+ printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr);
+
+ /* BMCR_ANRESTART self clears when the process has begun. */
+ timeout = 64; /* More than enough. */
+ while (--timeout) {
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (!(bmcr & BMCR_ANRESTART))
+ break; /* got it. */
+ udelay(10);
}
+ if (!timeout) {
+ printk(KERN_ERR "%s: TC35815 would not start auto "
+ "negotiation BMCR=0x%04x\n",
+ dev->name, bmcr);
+ printk(KERN_NOTICE "%s: Performing force link "
+ "detection.\n", dev->name);
+ goto force_link;
+ } else {
+ printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name);
+ lp->timer_state = arbwait;
+ }
+ } else {
+force_link:
+ /* Force the link up, trying first a particular mode.
+ * Either we are here at the request of ethtool or
+ * because the Happy Meal would not start to autoneg.
+ */
+
+ /* Disable auto-negotiation in BMCR, enable the duplex and
+ * speed setting, init the timer state machine, and fire it off.
+ */
+ if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
+ bmcr = BMCR_SPEED100;
+ } else {
+ if (ep->speed == SPEED_100)
+ bmcr = BMCR_SPEED100;
+ else
+ bmcr = 0;
+ if (ep->duplex == DUPLEX_FULL)
+ bmcr |= BMCR_FULLDPLX;
+ }
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr);
+
+ /* OK, seems we need do disable the transceiver for the first
+ * tick to make sure we get an accurate link state at the
+ * second tick.
+ */
+ lp->timer_state = ltrywait;
}
- ctl = 0;
- if (lp->linkspeed == 100)
- ctl |= MIICNTL_SPEED;
- if (lp->fullduplex)
- ctl |= MIICNTL_FDX;
- tc_phy_write(dev, ctl, tr, 0, MII_CONTROL);
+ del_timer(&lp->timer);
+ lp->timer_ticks = 0;
+ lp->timer.expires = jiffies + msecs_to_jiffies(1200);
+ add_timer(&lp->timer);
+}
- if (lp->fullduplex) {
- tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl);
+static void tc35815_find_phy(struct net_device *dev)
+{
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short id0;
+
+ /* find MII phy */
+ for (pid = 31; pid >= 0; pid--) {
+ id0 = tc_mdio_read(dev, pid, MII_BMSR);
+ if (id0 != 0xffff && id0 != 0x0000 &&
+ (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */
+ ) {
+ lp->phy_addr = pid;
+ break;
+ }
}
+ if (pid < 0) {
+ printk(KERN_ERR "%s: No MII Phy found.\n",
+ dev->name);
+ lp->phy_addr = pid = 0;
+ }
+
+ lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1);
+ lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2);
+ if (netif_msg_hw(lp))
+ printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name,
+ pid, lp->mii_id[0], lp->mii_id[1]);
}
-static void tc35815_chip_reset(struct net_device *dev)
+static void tc35815_phy_chip_init(struct net_device *dev)
{
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
+ struct tc35815_local *lp = dev->priv;
+ int pid = lp->phy_addr;
+ unsigned short bmcr;
+ struct ethtool_cmd ecmd, *ep;
+
+ /* dis-isolate if needed. */
+ bmcr = tc_mdio_read(dev, pid, MII_BMCR);
+ if (bmcr & BMCR_ISOLATE) {
+ int count = 32;
+ printk(KERN_DEBUG "%s: unisolating...", dev->name);
+ tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE);
+ while (--count) {
+ if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE))
+ break;
+ udelay(20);
+ }
+ printk(" %s.\n", count ? "done" : "failed");
+ }
+
+ if (options.speed && options.duplex) {
+ ecmd.autoneg = AUTONEG_DISABLE;
+ ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100;
+ ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL;
+ ep = &ecmd;
+ } else {
+ ep = NULL;
+ }
+ tc35815_start_auto_negotiation(dev, ep);
+}
+static void tc35815_chip_reset(struct net_device *dev)
+{
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
+ int i;
/* reset the controller */
tc_writel(MAC_Reset, &tr->MAC_Ctl);
- while (tc_readl(&tr->MAC_Ctl) & MAC_Reset)
- ;
-
+ udelay(4); /* 3200ns */
+ i = 0;
+ while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) {
+ if (i++ > 100) {
+ printk(KERN_ERR "%s: MAC reset failed.\n", dev->name);
+ break;
+ }
+ mdelay(1);
+ }
tc_writel(0, &tr->MAC_Ctl);
/* initialize registers to default value */
@@ -1650,90 +2803,142 @@ static void tc35815_chip_reset(struct net_device *dev)
tc_writel(0, &tr->CAM_Ena);
(void)tc_readl(&tr->Miss_Cnt); /* Read to clear */
+ /* initialize internal SRAM */
+ tc_writel(DMA_TestMode, &tr->DMA_Ctl);
+ for (i = 0; i < 0x1000; i += 4) {
+ tc_writel(i, &tr->CAM_Adr);
+ tc_writel(0, &tr->CAM_Data);
+ }
+ tc_writel(0, &tr->DMA_Ctl);
}
static void tc35815_chip_init(struct net_device *dev)
{
struct tc35815_local *lp = dev->priv;
- struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr;
- unsigned long flags;
+ struct tc35815_regs __iomem *tr =
+ (struct tc35815_regs __iomem *)dev->base_addr;
unsigned long txctl = TX_CTL_CMD;
tc35815_phy_chip_init(dev);
/* load station address to CAM */
- tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr);
+ tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr);
/* Enable CAM (broadcast and unicast) */
tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena);
tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
- spin_lock_irqsave(&lp->lock, flags);
-
- tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
-
+ /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */
+ if (HAVE_DMA_RXALIGN(lp))
+ tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl);
+ else
+ tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl);
+#ifdef TC35815_USE_PACKEDBUFFER
tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */
+#else
+ tc_writel(ETH_ZLEN, &tr->RxFragSize);
+#endif
tc_writel(0, &tr->TxPollCtr); /* Batch mode */
tc_writel(TX_THRESHOLD, &tr->TxThrsh);
tc_writel(INT_EN_CMD, &tr->Int_En);
/* set queues */
- tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas);
+ tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas);
tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base,
&tr->FDA_Lim);
/*
* Activation method:
- * First, enable eht MAC Transmitter and the DMA Receive circuits.
+ * First, enable the MAC Transmitter and the DMA Receive circuits.
* Then enable the DMA Transmitter and the MAC Receive circuits.
*/
- tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */
+ tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */
tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */
+
/* start MAC transmitter */
+#ifndef NO_CHECK_CARRIER
+ /* TX4939 does not have EnLCarr */
+ if (lp->boardtype == TC35815_TX4939)
+ txctl &= ~Tx_EnLCarr;
+#ifdef WORKAROUND_LOSTCAR
/* WORKAROUND: ignore LostCrS in full duplex operation */
- if (lp->fullduplex)
- txctl = TX_CTL_CMD & ~Tx_EnLCarr;
+ if ((lp->timer_state != asleep && lp->timer_state != lcheck) ||
+ lp->fullduplex)
+ txctl &= ~Tx_EnLCarr;
+#endif
+#endif /* !NO_CHECK_CARRIER */
#ifdef GATHER_TXINT
txctl &= ~Tx_EnComp; /* disable global tx completion int. */
#endif
tc_writel(txctl, &tr->Tx_Ctl);
-#if 0 /* No need to polling */
- tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */
-#endif
+}
+
+#ifdef CONFIG_PM
+static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct tc35815_local *lp = dev->priv;
+ unsigned long flags;
+
+ pci_save_state(pdev);
+ if (!netif_running(dev))
+ return 0;
+ netif_device_detach(dev);
+ spin_lock_irqsave(&lp->lock, flags);
+ del_timer(&lp->timer); /* Kill if running */
+ tc35815_chip_reset(dev);
spin_unlock_irqrestore(&lp->lock, flags);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
}
-static struct pci_driver tc35815_driver = {
- .name = TC35815_MODULE_NAME,
- .probe = tc35815_probe,
- .remove = NULL,
- .id_table = tc35815_pci_tbl,
+static int tc35815_resume(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct tc35815_local *lp = dev->priv;
+ unsigned long flags;
+
+ pci_restore_state(pdev);
+ if (!netif_running(dev))
+ return 0;
+ pci_set_power_state(pdev, PCI_D0);
+ spin_lock_irqsave(&lp->lock, flags);
+ tc35815_restart(dev);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ netif_device_attach(dev);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver tc35815_pci_driver = {
+ .name = MODNAME,
+ .id_table = tc35815_pci_tbl,
+ .probe = tc35815_init_one,
+ .remove = __devexit_p(tc35815_remove_one),
+#ifdef CONFIG_PM
+ .suspend = tc35815_suspend,
+ .resume = tc35815_resume,
+#endif
};
+module_param_named(speed, options.speed, int, 0);
+MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps");
+module_param_named(duplex, options.duplex, int, 0);
+MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full");
+module_param_named(doforce, options.doforce, int, 0);
+MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed");
+
static int __init tc35815_init_module(void)
{
- return pci_register_driver(&tc35815_driver);
+ return pci_register_driver(&tc35815_pci_driver);
}
static void __exit tc35815_cleanup_module(void)
{
- struct net_device *next_dev;
-
- /*
- * TODO: implement a tc35815_driver.remove hook, and
- * move this code into that function. Then, delete
- * all root_tc35815_dev list handling code.
- */
- while (root_tc35815_dev) {
- struct net_device *dev = root_tc35815_dev;
- next_dev = ((struct tc35815_local *)dev->priv)->next_module;
- iounmap((void *)(dev->base_addr));
- unregister_netdev(dev);
- free_netdev(dev);
- root_tc35815_dev = next_dev;
- }
-
- pci_unregister_driver(&tc35815_driver);
+ pci_unregister_driver(&tc35815_pci_driver);
}
module_init(tc35815_init_module);
module_exit(tc35815_cleanup_module);
+
+MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 9488f49ea56..923b9c725cc 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.75"
-#define DRV_MODULE_RELDATE "March 23, 2007"
+#define DRV_MODULE_VERSION "3.76"
+#define DRV_MODULE_RELDATE "May 5, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -1300,9 +1300,11 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
msleep(1);
}
}
- tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE |
- WOL_DRV_STATE_SHUTDOWN |
- WOL_DRV_WOL | WOL_SET_MAGIC_PKT);
+ if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+ tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE |
+ WOL_DRV_STATE_SHUTDOWN |
+ WOL_DRV_WOL |
+ WOL_SET_MAGIC_PKT);
pci_read_config_word(tp->pdev, pm + PCI_PM_PMC, &power_caps);
@@ -2593,10 +2595,8 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
{
int current_link_up = 0;
- if (!(mac_status & MAC_STATUS_PCS_SYNCED)) {
- tp->tg3_flags &= ~TG3_FLAG_GOT_SERDES_FLOWCTL;
+ if (!(mac_status & MAC_STATUS_PCS_SYNCED))
goto out;
- }
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 flags;
@@ -2614,7 +2614,6 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
tg3_setup_flow_control(tp, local_adv, remote_adv);
- tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
current_link_up = 1;
}
for (i = 0; i < 30; i++) {
@@ -2637,7 +2636,6 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
} else {
/* Forcing 1000FD link up. */
current_link_up = 1;
- tp->tg3_flags |= TG3_FLAG_GOT_SERDES_FLOWCTL;
tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS));
udelay(40);
@@ -3021,6 +3019,16 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
}
}
+ if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) {
+ u32 val = tr32(PCIE_PWR_MGMT_THRESH);
+ if (!netif_carrier_ok(tp->dev))
+ val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) |
+ tp->pwrmgmt_thresh;
+ else
+ val |= PCIE_PWR_MGMT_L1_THRESH_MSK;
+ tw32(PCIE_PWR_MGMT_THRESH, val);
+ }
+
return err;
}
@@ -3582,8 +3590,12 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
* Writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
+ *
+ * Flush the mailbox to de-assert the IRQ immediately to prevent
+ * spurious interrupts. The flush impacts performance but
+ * excessive spurious interrupts can be worse in some cases.
*/
- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+ tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (tg3_irq_sync(tp))
goto out;
sblk->status &= ~SD_STATUS_UPDATED;
@@ -3627,8 +3639,12 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
* writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
+ *
+ * Flush the mailbox to de-assert the IRQ immediately to prevent
+ * spurious interrupts. The flush impacts performance but
+ * excessive spurious interrupts can be worse in some cases.
*/
- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
+ tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (tg3_irq_sync(tp))
goto out;
if (netif_rx_schedule_prep(dev)) {
@@ -3700,10 +3716,8 @@ static void tg3_reset_task(struct work_struct *work)
unsigned int restart_timer;
tg3_full_lock(tp, 0);
- tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
if (!netif_running(tp->dev)) {
- tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
tg3_full_unlock(tp);
return;
}
@@ -3734,8 +3748,6 @@ static void tg3_reset_task(struct work_struct *work)
mod_timer(&tp->timer, jiffies + 1);
out:
- tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
-
tg3_full_unlock(tp);
}
@@ -3895,8 +3907,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->tx_prod;
base_flags = 0;
mss = 0;
- if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->gso_size) != 0) {
+ if ((mss = skb_shinfo(skb)->gso_size) != 0) {
int tcp_opt_len, ip_tcp_len;
if (skb_header_cloned(skb) &&
@@ -4053,8 +4064,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
mss = 0;
- if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
- (mss = skb_shinfo(skb)->gso_size) != 0) {
+ if ((mss = skb_shinfo(skb)->gso_size) != 0) {
struct iphdr *iph;
int tcp_opt_len, ip_tcp_len, hdr_len;
@@ -5934,7 +5944,7 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
/* tp->lock is held. */
-static void __tg3_set_mac_addr(struct tg3 *tp)
+static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
{
u32 addr_high, addr_low;
int i;
@@ -5946,6 +5956,8 @@ static void __tg3_set_mac_addr(struct tg3 *tp)
(tp->dev->dev_addr[4] << 8) |
(tp->dev->dev_addr[5] << 0));
for (i = 0; i < 4; i++) {
+ if (i == 1 && skip_mac_1)
+ continue;
tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high);
tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
}
@@ -5972,7 +5984,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
{
struct tg3 *tp = netdev_priv(dev);
struct sockaddr *addr = p;
- int err = 0;
+ int err = 0, skip_mac_1 = 0;
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
@@ -5983,22 +5995,21 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
return 0;
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
- /* Reset chip so that ASF can re-init any MAC addresses it
- * needs.
- */
- tg3_netif_stop(tp);
- tg3_full_lock(tp, 1);
+ u32 addr0_high, addr0_low, addr1_high, addr1_low;
- tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- err = tg3_restart_hw(tp, 0);
- if (!err)
- tg3_netif_start(tp);
- tg3_full_unlock(tp);
- } else {
- spin_lock_bh(&tp->lock);
- __tg3_set_mac_addr(tp);
- spin_unlock_bh(&tp->lock);
+ addr0_high = tr32(MAC_ADDR_0_HIGH);
+ addr0_low = tr32(MAC_ADDR_0_LOW);
+ addr1_high = tr32(MAC_ADDR_1_HIGH);
+ addr1_low = tr32(MAC_ADDR_1_LOW);
+
+ /* Skip MAC addr 1 if ASF is using it. */
+ if ((addr0_high != addr1_high || addr0_low != addr1_low) &&
+ !(addr1_high == 0 && addr1_low == 0))
+ skip_mac_1 = 1;
}
+ spin_lock_bh(&tp->lock);
+ __tg3_set_mac_addr(tp, skip_mac_1);
+ spin_unlock_bh(&tp->lock);
return err;
}
@@ -6315,7 +6326,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->rx_jumbo_ptr);
/* Initialize MAC address and backoff seed. */
- __tg3_set_mac_addr(tp);
+ __tg3_set_mac_addr(tp, 0);
/* MTU + ethernet header + FCS + optional VLAN tag */
tw32(MAC_RX_MTU_SIZE, tp->dev->mtu + ETH_HLEN + 8);
@@ -6346,8 +6357,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)) {
if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE &&
- (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 ||
- tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
!(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
@@ -6457,6 +6467,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL;
+ tp->grc_local_ctrl &= ~gpio_mask;
tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask;
/* GPIO1 must be driven high for eeprom write protect */
@@ -7036,11 +7047,7 @@ static int tg3_open(struct net_device *dev)
if (err)
return err;
- if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
- (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) &&
- (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX) &&
- !((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) &&
- (tp->pdev_peer == tp->pdev))) {
+ if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) {
/* All MSI supporting chips should support tagged
* status. Assert that this is the case.
*/
@@ -7379,12 +7386,7 @@ static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
- /* Calling flush_scheduled_work() may deadlock because
- * linkwatch_event() may be on the workqueue and it will try to get
- * the rtnl_lock which we are holding.
- */
- while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
- msleep(1);
+ cancel_work_sync(&tp->reset_task);
netif_stop_queue(dev);
@@ -7399,9 +7401,7 @@ static int tg3_close(struct net_device *dev)
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
- tp->tg3_flags &=
- ~(TG3_FLAG_INIT_COMPLETE |
- TG3_FLAG_GOT_SERDES_FLOWCTL);
+ tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_full_unlock(tp);
@@ -8036,7 +8036,10 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tg3 *tp = netdev_priv(dev);
- wol->supported = WAKE_MAGIC;
+ if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+ wol->supported = WAKE_MAGIC;
+ else
+ wol->supported = 0;
wol->wolopts = 0;
if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
wol->wolopts = WAKE_MAGIC;
@@ -8050,8 +8053,7 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
if ((wol->wolopts & WAKE_MAGIC) &&
- tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
- !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+ !(tp->tg3_flags & TG3_FLAG_WOL_CAP))
return -EINVAL;
spin_lock_bh(&tp->lock);
@@ -9289,7 +9291,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
return;
}
}
- tp->nvram_size = 0x20000;
+ tp->nvram_size = 0x80000;
}
static void __devinit tg3_get_nvram_info(struct tg3 *tp)
@@ -9408,33 +9410,31 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp)
static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
{
- u32 nvcfg1;
+ u32 nvcfg1, protect = 0;
nvcfg1 = tr32(NVRAM_CFG1);
/* NVRAM protection for TPM */
- if (nvcfg1 & (1 << 27))
+ if (nvcfg1 & (1 << 27)) {
tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM;
+ protect = 1;
+ }
- switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
- case FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ:
- case FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ:
- tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
-
- nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
- tw32(NVRAM_CFG1, nvcfg1);
- break;
- case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
+ nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK;
+ switch (nvcfg1) {
case FLASH_5755VENDOR_ATMEL_FLASH_1:
case FLASH_5755VENDOR_ATMEL_FLASH_2:
case FLASH_5755VENDOR_ATMEL_FLASH_3:
- case FLASH_5755VENDOR_ATMEL_FLASH_4:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 264;
+ if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1)
+ tp->nvram_size = (protect ? 0x3e200 : 0x80000);
+ else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2)
+ tp->nvram_size = (protect ? 0x1f200 : 0x40000);
+ else
+ tp->nvram_size = (protect ? 0x1f200 : 0x20000);
break;
case FLASH_5752VENDOR_ST_M45PE10:
case FLASH_5752VENDOR_ST_M45PE20:
@@ -9443,6 +9443,12 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 256;
+ if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10)
+ tp->nvram_size = (protect ? 0x10000 : 0x20000);
+ else if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE20)
+ tp->nvram_size = (protect ? 0x10000 : 0x40000);
+ else
+ tp->nvram_size = (protect ? 0x20000 : 0x80000);
break;
}
}
@@ -9518,6 +9524,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
}
tg3_enable_nvram_access(tp);
+ tp->nvram_size = 0;
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
tg3_get_5752_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
@@ -9529,7 +9537,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
else
tg3_get_nvram_info(tp);
- tg3_get_nvram_size(tp);
+ if (tp->nvram_size == 0)
+ tg3_get_nvram_size(tp);
tg3_disable_nvram_access(tp);
tg3_nvram_unlock(tp);
@@ -9996,14 +10005,16 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->phy_id = PHY_ID_INVALID;
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
- /* Assume an onboard device by default. */
- tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+ /* Assume an onboard device and WOL capable by default. */
+ tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT | TG3_FLAG_WOL_CAP;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) {
tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
}
+ if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC)
+ tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
return;
}
@@ -10120,8 +10131,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
}
- if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
- tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
+ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
+ !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
+ tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
if (cfg2 & (1 << 17))
tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
@@ -10130,6 +10142,14 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
/* bootcode if bit 18 is set */
if (cfg2 & (1 << 18))
tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
+
+ if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ u32 cfg3;
+
+ tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
+ if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
+ tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+ }
}
}
@@ -10399,6 +10419,8 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
}
}
+static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
+
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
static struct pci_device_id write_reorder_chipsets[] = {
@@ -10554,6 +10576,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff;
tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff;
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
+ tp->pdev_peer = tg3_find_peer(tp);
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
@@ -10567,6 +10593,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+ tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI;
+ if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX ||
+ GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 &&
+ tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 &&
+ tp->pdev_peer == tp->pdev))
+ tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI;
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
@@ -10668,17 +10702,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX)
tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
- /* Back to back register writes can cause problems on this chip,
- * the workaround is to read back all reg writes except those to
- * mailbox regs. See tg3_write_indirect_reg32().
- *
- * PCI Express 5750_A0 rev chips need this workaround too.
- */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
- ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
- tp->pci_chip_rev_id == CHIPREV_ID_5750_A0))
- tp->tg3_flags |= TG3_FLAG_5701_REG_WRITE_BUG;
-
if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
@@ -10702,8 +10725,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Various workaround register access methods */
if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
tp->write32 = tg3_write_indirect_reg32;
- else if (tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG)
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
+ ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+ tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) {
+ /*
+ * Back to back register writes can cause problems on these
+ * chips, the workaround is to read back all reg writes
+ * except those to mailbox regs.
+ *
+ * See tg3_write_indirect_reg32().
+ */
tp->write32 = tg3_write_flush_reg32;
+ }
+
if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
@@ -10983,6 +11017,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+ if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
+ tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
+ PCIE_PWR_MGMT_L1_THRESH_MSK;
+
return err;
}
@@ -11892,10 +11930,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tp->rx_pending = 63;
}
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714))
- tp->pdev_peer = tg3_find_peer(tp);
-
err = tg3_get_device_address(tp);
if (err) {
printk(KERN_ERR PFX "Could not obtain valid ethernet address, "
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index d515ed23841..bd9f4f428e5 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -131,6 +131,7 @@
#define CHIPREV_ID_5752_A0_HW 0x5000
#define CHIPREV_ID_5752_A0 0x6000
#define CHIPREV_ID_5752_A1 0x6001
+#define CHIPREV_ID_5714_A2 0x9002
#define CHIPREV_ID_5906_A1 0xc001
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
@@ -1149,6 +1150,9 @@
#define VCPU_STATUS_INIT_DONE 0x04000000
#define VCPU_STATUS_DRV_RESET 0x08000000
+#define VCPU_CFGSHDW 0x00005104
+#define VCPU_CFGSHDW_ASPM_DBNC 0x00001000
+
/* Mailboxes */
#define GRCMBOX_BASE 0x00005600
#define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */
@@ -1506,6 +1510,8 @@
#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000
#define PCIE_TRANS_CFG_LOM 0x00000020
+#define PCIE_PWR_MGMT_THRESH 0x00007d28
+#define PCIE_PWR_MGMT_L1_THRESH_MSK 0x0000ff00
#define TG3_EEPROM_MAGIC 0x669955aa
#define TG3_EEPROM_MAGIC_FW 0xa5000000
@@ -1592,6 +1598,9 @@
#define SHASTA_EXT_LED_MAC 0x00010000
#define SHASTA_EXT_LED_COMBO 0x00018000
+#define NIC_SRAM_DATA_CFG_3 0x00000d3c
+#define NIC_SRAM_ASPM_DEBOUNCE 0x00000002
+
#define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000
#define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000
@@ -2199,7 +2208,7 @@ struct tg3 {
#define TG3_FLAG_USE_LINKCHG_REG 0x00000008
#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010
#define TG3_FLAG_ENABLE_ASF 0x00000020
-#define TG3_FLAG_5701_REG_WRITE_BUG 0x00000040
+#define TG3_FLAG_ASPM_WORKAROUND 0x00000040
#define TG3_FLAG_POLL_SERDES 0x00000080
#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
@@ -2215,14 +2224,14 @@ struct tg3 {
#define TG3_FLAG_PCI_32BIT 0x00080000
#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000
#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000
-#define TG3_FLAG_SERDES_WOL_CAP 0x00400000
+#define TG3_FLAG_WOL_CAP 0x00400000
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
-#define TG3_FLAG_IN_RESET_TASK 0x04000000
+
#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
-#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
+#define TG3_FLAG_SUPPORT_MSI 0x20000000
#define TG3_FLAG_CHIP_RESETTING 0x40000000
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2;
@@ -2288,6 +2297,7 @@ struct tg3 {
u32 grc_local_ctrl;
u32 dma_rwctrl;
u32 coalesce_mode;
+ u32 pwrmgmt_thresh;
/* PCI block */
u16 pci_chip_rev_id;
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index ed274d6909d..f8f4d74f01f 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -23,7 +23,6 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n";
#include <linux/mca.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/trdevice.h>
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 9bbea5c8acf..58d7e5d452f 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -41,7 +41,6 @@
#include <linux/time.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/mca-legacy.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 0bfc2c9c1c0..1aabc91f645 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -82,6 +82,7 @@ struct tsi108_prv_data {
unsigned int phy; /* Index of PHY for this interface */
unsigned int irq_num;
unsigned int id;
+ unsigned int phy_type;
struct timer_list timer;/* Timer that triggers the check phy function */
unsigned int rxtail; /* Next entry in rxring to read */
@@ -1256,11 +1257,11 @@ static void tsi108_init_phy(struct net_device *dev)
if (i == 0)
printk(KERN_ERR "%s function time out \n", __FUNCTION__);
-#if (TSI108_PHY_TYPE == PHY_BCM54XX) /* Broadcom BCM54xx PHY */
- tsi108_write_mii(data, 0x09, 0x0300);
- tsi108_write_mii(data, 0x10, 0x1020);
- tsi108_write_mii(data, 0x1c, 0x8c00);
-#endif
+ if (data->phy_type == TSI108_PHY_BCM54XX) {
+ tsi108_write_mii(data, 0x09, 0x0300);
+ tsi108_write_mii(data, 0x10, 0x1020);
+ tsi108_write_mii(data, 0x1c, 0x8c00);
+ }
tsi108_write_mii(data,
MII_BMCR,
@@ -1587,6 +1588,7 @@ tsi108_init_one(struct platform_device *pdev)
data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if);
data->phy = einfo->phy;
+ data->phy_type = einfo->phy_type;
data->irq_num = einfo->irq_num;
data->id = pdev->id;
dev->open = tsi108_open;
diff --git a/drivers/net/tsi108_eth.h b/drivers/net/tsi108_eth.h
index 77a769df228..5a77ae6c5f3 100644
--- a/drivers/net/tsi108_eth.h
+++ b/drivers/net/tsi108_eth.h
@@ -43,15 +43,6 @@
in_be32((data->phyregs + (offset)))
/*
- * PHY Configuration Options
- *
- * NOTE: Enable set of definitions corresponding to your board type
- */
-#define PHY_MV88E 1 /* Marvel 88Exxxx PHY */
-#define PHY_BCM54XX 2 /* Broardcom BCM54xx PHY */
-#define TSI108_PHY_TYPE PHY_MV88E
-
-/*
* TSI108 GIGE port registers
*/
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 942b839ccc5..6c400ccd38b 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -14,7 +14,6 @@
*/
-#include <linux/pci.h>
#include <linux/delay.h>
#include "tulip.h"
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index b3a64ca9863..4ed67ff0e81 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -55,9 +55,6 @@
TODO
- Implement pci_driver::suspend() and pci_driver::resume()
- power management methods.
-
Check on 64 bit boxes.
Check and fix on big endian boxes.
@@ -125,6 +122,11 @@
#define DM9801_NOISE_FLOOR 8
#define DM9802_NOISE_FLOOR 5
+#define DMFE_WOL_LINKCHANGE 0x20000000
+#define DMFE_WOL_SAMPLEPACKET 0x10000000
+#define DMFE_WOL_MAGICPACKET 0x08000000
+
+
#define DMFE_10MHF 0
#define DMFE_100MHF 1
#define DMFE_10MFD 4
@@ -251,6 +253,7 @@ struct dmfe_board_info {
u8 wait_reset; /* Hardware failed, need to reset */
u8 dm910x_chk_mode; /* Operating mode check */
u8 first_in_callback; /* Flag to record state */
+ u8 wol_mode; /* user WOL settings */
struct timer_list timer;
/* System defined statistic counter */
@@ -431,6 +434,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
db->chip_id = ent->driver_data;
db->ioaddr = pci_resource_start(pdev, 0);
db->chip_revision = dev_rev;
+ db->wol_mode = 0;
db->pdev = pdev;
@@ -1065,7 +1069,11 @@ static void dmfe_set_filter_mode(struct DEVICE * dev)
spin_unlock_irqrestore(&db->lock, flags);
}
-static void netdev_get_drvinfo(struct net_device *dev,
+/*
+ * Ethtool interace
+ */
+
+static void dmfe_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct dmfe_board_info *np = netdev_priv(dev);
@@ -1079,9 +1087,35 @@ static void netdev_get_drvinfo(struct net_device *dev,
dev->base_addr, dev->irq);
}
+static int dmfe_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct dmfe_board_info *db = netdev_priv(dev);
+
+ if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
+ WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+
+ db->wol_mode = wolinfo->wolopts;
+ return 0;
+}
+
+static void dmfe_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct dmfe_board_info *db = netdev_priv(dev);
+
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+ wolinfo->wolopts = db->wol_mode;
+ return;
+}
+
+
static const struct ethtool_ops netdev_ethtool_ops = {
- .get_drvinfo = netdev_get_drvinfo,
+ .get_drvinfo = dmfe_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
+ .set_wol = dmfe_ethtool_set_wol,
+ .get_wol = dmfe_ethtool_get_wol,
};
/*
@@ -2050,11 +2084,85 @@ static struct pci_device_id dmfe_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
+#ifdef CONFIG_PM
+static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ struct dmfe_board_info *db = netdev_priv(dev);
+ u32 tmp;
+
+ /* Disable upper layer interface */
+ netif_device_detach(dev);
+
+ /* Disable Tx/Rx */
+ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);
+ update_cr6(db->cr6_data, dev->base_addr);
+
+ /* Disable Interrupt */
+ outl(0, dev->base_addr + DCR7);
+ outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5);
+
+ /* Fre RX buffers */
+ dmfe_free_rxbuffer(db);
+
+ /* Enable WOL */
+ pci_read_config_dword(pci_dev, 0x40, &tmp);
+ tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET);
+
+ if (db->wol_mode & WAKE_PHY)
+ tmp |= DMFE_WOL_LINKCHANGE;
+ if (db->wol_mode & WAKE_MAGIC)
+ tmp |= DMFE_WOL_MAGICPACKET;
+
+ pci_write_config_dword(pci_dev, 0x40, tmp);
+
+ pci_enable_wake(pci_dev, PCI_D3hot, 1);
+ pci_enable_wake(pci_dev, PCI_D3cold, 1);
+
+ /* Power down device*/
+ pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state));
+ pci_save_state(pci_dev);
+
+ return 0;
+}
+
+static int dmfe_resume(struct pci_dev *pci_dev)
+{
+ struct net_device *dev = pci_get_drvdata(pci_dev);
+ u32 tmp;
+
+ pci_restore_state(pci_dev);
+ pci_set_power_state(pci_dev, PCI_D0);
+
+ /* Re-initilize DM910X board */
+ dmfe_init_dm910x(dev);
+
+ /* Disable WOL */
+ pci_read_config_dword(pci_dev, 0x40, &tmp);
+
+ tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET);
+ pci_write_config_dword(pci_dev, 0x40, tmp);
+
+ pci_enable_wake(pci_dev, PCI_D3hot, 0);
+ pci_enable_wake(pci_dev, PCI_D3cold, 0);
+
+ /* Restart upper layer interface */
+ netif_device_attach(dev);
+
+ return 0;
+}
+#else
+#define dmfe_suspend NULL
+#define dmfe_resume NULL
+#endif
+
static struct pci_driver dmfe_driver = {
.name = "dmfe",
.id_table = dmfe_pci_tbl,
.probe = dmfe_init_one,
.remove = __devexit_p(dmfe_remove_one),
+ .suspend = dmfe_suspend,
+ .resume = dmfe_resume
};
MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index e86df07769a..ea896777bca 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -269,7 +269,7 @@ done:
This would turn on IM for devices that is not contributing
to backlog congestion with unnecessary latency.
- We monitor the the device RX-ring and have:
+ We monitor the device RX-ring and have:
HW Interrupt Mitigation either ON or OFF.
@@ -673,7 +673,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
if (tp->link_change)
(tp->link_change)(dev, csr5);
}
- if (csr5 & SytemError) {
+ if (csr5 & SystemError) {
int error = (csr5 >> 23) & 7;
/* oops, we hit a PCI error. The code produced corresponds
* to the reason:
@@ -743,7 +743,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
TxFIFOUnderflow |
TxJabber |
TPLnkFail |
- SytemError )) != 0);
+ SystemError )) != 0);
#else
} while ((csr5 & (NormalIntr|AbnormalIntr)) != 0);
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index 20bd52b8699..b5625663654 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -44,8 +44,10 @@ static const unsigned char comet_miireg2offset[32] = {
/* MII transceiver control section.
Read and write the MII registers using software-generated serial
- MDIO protocol. See the MII specifications or DP83840A data sheet
- for details. */
+ MDIO protocol.
+ See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions")
+ or DP83840A data sheet for more details.
+ */
int tulip_mdio_read(struct net_device *dev, int phy_id, int location)
{
@@ -261,24 +263,56 @@ void tulip_select_media(struct net_device *dev, int startup)
u16 *reset_sequence = &((u16*)(p+3))[init_length];
int reset_length = p[2 + init_length*2];
misc_info = reset_sequence + reset_length;
- if (startup)
+ if (startup) {
+ int timeout = 10; /* max 1 ms */
for (i = 0; i < reset_length; i++)
iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+
+ /* flush posted writes */
+ ioread32(ioaddr + CSR15);
+
+ /* Sect 3.10.3 in DP83840A.pdf (p39) */
+ udelay(500);
+
+ /* Section 4.2 in DP83840A.pdf (p43) */
+ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
+ while (timeout-- &&
+ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+ udelay(100);
+ }
for (i = 0; i < init_length; i++)
iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+
+ ioread32(ioaddr + CSR15); /* flush posted writes */
} else {
u8 *init_sequence = p + 2;
u8 *reset_sequence = p + 3 + init_length;
int reset_length = p[2 + init_length];
misc_info = (u16*)(reset_sequence + reset_length);
if (startup) {
+ int timeout = 10; /* max 1 ms */
iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
for (i = 0; i < reset_length; i++)
iowrite32(reset_sequence[i], ioaddr + CSR12);
+
+ /* flush posted writes */
+ ioread32(ioaddr + CSR12);
+
+ /* Sect 3.10.3 in DP83840A.pdf (p39) */
+ udelay(500);
+
+ /* Section 4.2 in DP83840A.pdf (p43) */
+ /* and IEEE 802.3 "22.2.4.1.1 Reset" */
+ while (timeout-- &&
+ (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET))
+ udelay(100);
}
for (i = 0; i < init_length; i++)
iowrite32(init_sequence[i], ioaddr + CSR12);
+
+ ioread32(ioaddr + CSR12); /* flush posted writes */
}
+
tmp_info = get_u16(&misc_info[1]);
if (tmp_info)
tp->advertising[phy_num] = tmp_info | 1;
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index 85a521e0d05..be82a2effee 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -15,7 +15,6 @@
*/
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <linux/jiffies.h>
#include "tulip.h"
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index c31be0e377a..4e4a879c3fa 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -76,7 +76,6 @@
-#include <linux/pci.h>
#include "tulip.h"
#include <linux/delay.h>
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index df326fe1cc8..d2c1f42109b 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -14,7 +14,6 @@
*/
-#include <linux/pci.h>
#include "tulip.h"
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 25f25da7691..16f26a8364f 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -22,6 +22,7 @@
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <linux/delay.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -132,7 +133,7 @@ enum pci_cfg_driver_reg {
/* The bits in the CSR5 status registers, mostly interrupt sources. */
enum status_bits {
TimerInt = 0x800,
- SytemError = 0x2000,
+ SystemError = 0x2000,
TPLnkFail = 0x1000,
TPLnkPass = 0x10,
NormalIntr = 0x10000,
@@ -482,8 +483,11 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp)
udelay(10);
if (!i)
- printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n",
- pci_name(tp->pdev));
+ printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed"
+ " (CSR5 0x%x CSR6 0x%x)\n",
+ pci_name(tp->pdev),
+ ioread32(ioaddr + CSR5),
+ ioread32(ioaddr + CSR6));
}
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index e9bf526ec53..041af63f281 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -17,11 +17,11 @@
#define DRV_NAME "tulip"
#ifdef CONFIG_TULIP_NAPI
-#define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */
+#define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */
#else
-#define DRV_VERSION "1.1.14"
+#define DRV_VERSION "1.1.15"
#endif
-#define DRV_RELDATE "May 11, 2002"
+#define DRV_RELDATE "Feb 27, 2007"
#include <linux/module.h>
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 5b71ac78bca..38f3b99716b 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1021,7 +1021,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->tx_ring[entry].length |= DescEndRing;
/* Now acquire the irq spinlock.
- * The difficult race is the the ordering between
+ * The difficult race is the ordering between
* increasing np->cur_tx and setting DescOwned:
* - if np->cur_tx is increased first the interrupt
* handler could consider the packet as transmitted
@@ -1147,7 +1147,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
}
/* Abnormal error summary/uncommon events handlers. */
- if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
+ if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError |
TimerInt | TxDied))
netdev_error(dev, intr_status);
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 985a1810ca5..2470b1ee33c 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -1043,7 +1043,7 @@ static int enable_promisc(struct xircom_private *card)
/*
-link_status() checks the the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
+link_status() checks the links status and will return 0 for no link, 10 for 10mbit link and 100 for.. guess what.
Must be called in locked state with interrupts disabled
*/
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index f2dd7763cd0..f7257359412 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -639,7 +639,7 @@ typhoon_issue_command(struct typhoon *tp, int num_cmd, struct cmd_desc *cmd,
typhoon_inc_cmd_index(&ring->lastWrite, num_cmd);
- /* "I feel a presence... another warrior is on the the mesa."
+ /* "I feel a presence... another warrior is on the mesa."
*/
wmb();
iowrite32(ring->lastWrite, tp->ioaddr + TYPHOON_REG_CMD_READY);
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 639e1e6913b..d7aff818937 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -29,6 +29,7 @@
#include <linux/fsl_devices.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <linux/workqueue.h>
#include <asm/of_platform.h>
@@ -41,12 +42,13 @@
#include <asm/ucc_fast.h>
#include "ucc_geth.h"
-#include "ucc_geth_phy.h"
+#include "ucc_geth_mii.h"
#undef DEBUG
-#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006"
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
#define DRV_NAME "ucc_geth"
+#define DRV_VERSION "1.1"
#define ugeth_printk(level, format, arg...) \
printk(level format "\n", ## arg)
@@ -73,22 +75,13 @@ static struct ucc_geth_info ugeth_primary_info = {
.bd_mem_part = MEM_PART_SYSTEM,
.rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
.max_rx_buf_length = 1536,
-/* FIXME: should be changed in run time for 1G and 100M */
-#ifdef CONFIG_UGETH_HAS_GIGA
- .urfs = UCC_GETH_URFS_GIGA_INIT,
- .urfet = UCC_GETH_URFET_GIGA_INIT,
- .urfset = UCC_GETH_URFSET_GIGA_INIT,
- .utfs = UCC_GETH_UTFS_GIGA_INIT,
- .utfet = UCC_GETH_UTFET_GIGA_INIT,
- .utftt = UCC_GETH_UTFTT_GIGA_INIT,
-#else
+ /* adjusted at startup if max-speed 1000 */
.urfs = UCC_GETH_URFS_INIT,
.urfet = UCC_GETH_URFET_INIT,
.urfset = UCC_GETH_URFSET_INIT,
.utfs = UCC_GETH_UTFS_INIT,
.utfet = UCC_GETH_UTFET_INIT,
.utftt = UCC_GETH_UTFTT_INIT,
-#endif
.ufpt = 256,
.mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
.ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
@@ -217,70 +210,6 @@ static struct list_head *dequeue(struct list_head *lh)
}
}
-static int get_interface_details(enum enet_interface enet_interface,
- enum enet_speed *speed,
- int *r10m,
- int *rmm,
- int *rpm,
- int *tbi, int *limited_to_full_duplex)
-{
- /* Analyze enet_interface according to Interface Mode
- Configuration table */
- switch (enet_interface) {
- case ENET_10_MII:
- *speed = ENET_SPEED_10BT;
- break;
- case ENET_10_RMII:
- *speed = ENET_SPEED_10BT;
- *r10m = 1;
- *rmm = 1;
- break;
- case ENET_10_RGMII:
- *speed = ENET_SPEED_10BT;
- *rpm = 1;
- *r10m = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_100_MII:
- *speed = ENET_SPEED_100BT;
- break;
- case ENET_100_RMII:
- *speed = ENET_SPEED_100BT;
- *rmm = 1;
- break;
- case ENET_100_RGMII:
- *speed = ENET_SPEED_100BT;
- *rpm = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_GMII:
- *speed = ENET_SPEED_1000BT;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_RGMII:
- *speed = ENET_SPEED_1000BT;
- *rpm = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_TBI:
- *speed = ENET_SPEED_1000BT;
- *tbi = 1;
- *limited_to_full_duplex = 1;
- break;
- case ENET_1000_RTBI:
- *speed = ENET_SPEED_1000BT;
- *rpm = 1;
- *tbi = 1;
- *limited_to_full_duplex = 1;
- break;
- default:
- return -EINVAL;
- break;
- }
-
- return 0;
-}
-
static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd)
{
struct sk_buff *skb = NULL;
@@ -758,24 +687,6 @@ static void dump_regs(struct ucc_geth_private *ugeth)
ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x",
(u32) & ugeth->ug_regs->hafdup,
in_be32(&ugeth->ug_regs->hafdup));
- ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimcfg,
- in_be32(&ugeth->ug_regs->miimng.miimcfg));
- ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimcom,
- in_be32(&ugeth->ug_regs->miimng.miimcom));
- ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimadd,
- in_be32(&ugeth->ug_regs->miimng.miimadd));
- ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimcon,
- in_be32(&ugeth->ug_regs->miimng.miimcon));
- ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimstat,
- in_be32(&ugeth->ug_regs->miimng.miimstat));
- ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x",
- (u32) & ugeth->ug_regs->miimng.miimind,
- in_be32(&ugeth->ug_regs->miimng.miimind));
ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x",
(u32) & ugeth->ug_regs->ifctl,
in_be32(&ugeth->ug_regs->ifctl));
@@ -1425,27 +1336,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0,
return 0;
}
-static int init_mac_duplex_mode(int full_duplex,
- int limited_to_full_duplex,
- volatile u32 *maccfg2_register)
-{
- u32 value = 0;
-
- /* some interfaces must work in full duplex mode */
- if ((full_duplex == 0) && (limited_to_full_duplex == 1))
- return -EINVAL;
-
- value = in_be32(maccfg2_register);
-
- if (full_duplex)
- value |= MACCFG2_FDX;
- else
- value &= ~MACCFG2_FDX;
-
- out_be32(maccfg2_register, value);
- return 0;
-}
-
static int init_check_frame_length_mode(int length_check,
volatile u32 *maccfg2_register)
{
@@ -1477,40 +1367,6 @@ static int init_preamble_length(u8 preamble_length,
return 0;
}
-static int init_mii_management_configuration(int reset_mgmt,
- int preamble_supress,
- volatile u32 *miimcfg_register,
- volatile u32 *miimind_register)
-{
- unsigned int timeout = PHY_INIT_TIMEOUT;
- u32 value = 0;
-
- value = in_be32(miimcfg_register);
- if (reset_mgmt) {
- value |= MIIMCFG_RESET_MANAGEMENT;
- out_be32(miimcfg_register, value);
- }
-
- value = 0;
-
- if (preamble_supress)
- value |= MIIMCFG_NO_PREAMBLE;
-
- value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
- out_be32(miimcfg_register, value);
-
- /* Wait until the bus is free */
- while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
- cpu_relax();
-
- if (timeout <= 0) {
- ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
static int init_rx_parameters(int reject_broadcast,
int receive_short_frames,
int promiscuous, volatile u32 *upsmr_register)
@@ -1570,10 +1426,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
struct ucc_geth_info *ug_info;
struct ucc_geth *ug_regs;
struct ucc_fast *uf_regs;
- enum enet_speed speed;
- int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
- 0, limited_to_full_duplex = 0;
- u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+ int ret_val;
+ u32 upsmr, maccfg2, tbiBaseAddress;
u16 value;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -1582,24 +1436,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
ug_regs = ugeth->ug_regs;
uf_regs = ugeth->uccf->uf_regs;
- /* Analyze enet_interface according to Interface Mode Configuration
- table */
- ret_val =
- get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm,
- &rpm, &tbi, &limited_to_full_duplex);
- if (ret_val != 0) {
- ugeth_err
- ("%s: half duplex not supported in requested configuration.",
- __FUNCTION__);
- return ret_val;
- }
-
/* Set MACCFG2 */
maccfg2 = in_be32(&ug_regs->maccfg2);
maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
- if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
+ if ((ugeth->max_speed == SPEED_10) ||
+ (ugeth->max_speed == SPEED_100))
maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
- else if (speed == ENET_SPEED_1000BT)
+ else if (ugeth->max_speed == SPEED_1000)
maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
maccfg2 |= ug_info->padAndCrc;
out_be32(&ug_regs->maccfg2, maccfg2);
@@ -1607,54 +1450,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
/* Set UPSMR */
upsmr = in_be32(&uf_regs->upsmr);
upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
- if (rpm)
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
upsmr |= UPSMR_RPM;
- if (r10m)
- upsmr |= UPSMR_R10M;
- if (tbi)
+ switch (ugeth->max_speed) {
+ case SPEED_10:
+ upsmr |= UPSMR_R10M;
+ /* FALLTHROUGH */
+ case SPEED_100:
+ if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
+ upsmr |= UPSMR_RMM;
+ }
+ }
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
upsmr |= UPSMR_TBIM;
- if (rmm)
- upsmr |= UPSMR_RMM;
+ }
out_be32(&uf_regs->upsmr, upsmr);
- /* Set UTBIPAR */
- utbipar = in_be32(&ug_regs->utbipar);
- utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
- if (tbi)
- utbipar |=
- (ug_info->phy_address +
- ugeth->ug_info->uf_info.
- ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
- else
- utbipar |=
- (0x10 +
- ugeth->ug_info->uf_info.
- ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
- out_be32(&ug_regs->utbipar, utbipar);
-
/* Disable autonegotiation in tbi mode, because by default it
comes up in autonegotiation mode. */
/* Note that this depends on proper setting in utbipar register. */
- if (tbi) {
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
tbiBaseAddress = in_be32(&ug_regs->utbipar);
tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
- value =
- ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress,
- ENET_TBI_MII_CR);
+ value = ugeth->phydev->bus->read(ugeth->phydev->bus,
+ (u8) tbiBaseAddress, ENET_TBI_MII_CR);
value &= ~0x1000; /* Turn off autonegotiation */
- ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress,
- ENET_TBI_MII_CR, value);
- }
-
- ret_val = init_mac_duplex_mode(1,
- limited_to_full_duplex,
- &ug_regs->maccfg2);
- if (ret_val != 0) {
- ugeth_err
- ("%s: half duplex not supported in requested configuration.",
- __FUNCTION__);
- return ret_val;
+ ugeth->phydev->bus->write(ugeth->phydev->bus,
+ (u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
}
init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
@@ -1676,76 +1504,88 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth)
* function converts those variables into the appropriate
* register values, and can bring down the device if needed.
*/
+
static void adjust_link(struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
struct ucc_geth *ug_regs;
- u32 tempval;
- struct ugeth_mii_info *mii_info = ugeth->mii_info;
+ struct ucc_fast *uf_regs;
+ struct phy_device *phydev = ugeth->phydev;
+ unsigned long flags;
+ int new_state = 0;
ug_regs = ugeth->ug_regs;
+ uf_regs = ugeth->uccf->uf_regs;
- if (mii_info->link) {
+ spin_lock_irqsave(&ugeth->lock, flags);
+
+ if (phydev->link) {
+ u32 tempval = in_be32(&ug_regs->maccfg2);
+ u32 upsmr = in_be32(&uf_regs->upsmr);
/* Now we make sure that we can be in full duplex mode.
* If not, we operate in half-duplex mode. */
- if (mii_info->duplex != ugeth->oldduplex) {
- if (!(mii_info->duplex)) {
- tempval = in_be32(&ug_regs->maccfg2);
+ if (phydev->duplex != ugeth->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
tempval &= ~(MACCFG2_FDX);
- out_be32(&ug_regs->maccfg2, tempval);
-
- ugeth_info("%s: Half Duplex", dev->name);
- } else {
- tempval = in_be32(&ug_regs->maccfg2);
+ else
tempval |= MACCFG2_FDX;
- out_be32(&ug_regs->maccfg2, tempval);
-
- ugeth_info("%s: Full Duplex", dev->name);
- }
-
- ugeth->oldduplex = mii_info->duplex;
+ ugeth->oldduplex = phydev->duplex;
}
- if (mii_info->speed != ugeth->oldspeed) {
- switch (mii_info->speed) {
- case 1000:
- ugeth->ug_info->enet_interface = ENET_1000_RGMII;
+ if (phydev->speed != ugeth->oldspeed) {
+ new_state = 1;
+ switch (phydev->speed) {
+ case SPEED_1000:
+ tempval = ((tempval &
+ ~(MACCFG2_INTERFACE_MODE_MASK)) |
+ MACCFG2_INTERFACE_MODE_BYTE);
break;
- case 100:
- ugeth->ug_info->enet_interface = ENET_100_RGMII;
- break;
- case 10:
- ugeth->ug_info->enet_interface = ENET_10_RGMII;
+ case SPEED_100:
+ case SPEED_10:
+ tempval = ((tempval &
+ ~(MACCFG2_INTERFACE_MODE_MASK)) |
+ MACCFG2_INTERFACE_MODE_NIBBLE);
+ /* if reduced mode, re-set UPSMR.R10M */
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+ if (phydev->speed == SPEED_10)
+ upsmr |= UPSMR_R10M;
+ else
+ upsmr &= ~(UPSMR_R10M);
+ }
break;
default:
- ugeth_warn
- ("%s: Ack! Speed (%d) is not 10/100/1000!",
- dev->name, mii_info->speed);
+ if (netif_msg_link(ugeth))
+ ugeth_warn(
+ "%s: Ack! Speed (%d) is not 10/100/1000!",
+ dev->name, phydev->speed);
break;
}
- adjust_enet_interface(ugeth);
-
- ugeth_info("%s: Speed %dBT", dev->name,
- mii_info->speed);
-
- ugeth->oldspeed = mii_info->speed;
+ ugeth->oldspeed = phydev->speed;
}
+ out_be32(&ug_regs->maccfg2, tempval);
+ out_be32(&uf_regs->upsmr, upsmr);
+
if (!ugeth->oldlink) {
- ugeth_info("%s: Link is up", dev->name);
+ new_state = 1;
ugeth->oldlink = 1;
- netif_carrier_on(dev);
netif_schedule(dev);
}
- } else {
- if (ugeth->oldlink) {
- ugeth_info("%s: Link is down", dev->name);
+ } else if (ugeth->oldlink) {
+ new_state = 1;
ugeth->oldlink = 0;
ugeth->oldspeed = 0;
ugeth->oldduplex = -1;
- netif_carrier_off(dev);
- }
}
+
+ if (new_state && netif_msg_link(ugeth))
+ phy_print_status(phydev);
+
+ spin_unlock_irqrestore(&ugeth->lock, flags);
}
/* Configure the PHY for dev.
@@ -1753,102 +1593,40 @@ static void adjust_link(struct net_device *dev)
*/
static int init_phy(struct net_device *dev)
{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct phy_info *curphy;
- struct ucc_mii_mng *mii_regs;
- struct ugeth_mii_info *mii_info;
- int err;
+ struct ucc_geth_private *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE];
- mii_regs = &ugeth->ug_regs->miimng;
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
- ugeth->oldlink = 0;
- ugeth->oldspeed = 0;
- ugeth->oldduplex = -1;
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus,
+ priv->ug_info->phy_address);
- mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+ phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
- if (NULL == mii_info) {
- ugeth_err("%s: Could not allocate mii_info", dev->name);
- return -ENOMEM;
+ if (IS_ERR(phydev)) {
+ printk("%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
}
- mii_info->mii_regs = mii_regs;
- mii_info->speed = SPEED_1000;
- mii_info->duplex = DUPLEX_FULL;
- mii_info->pause = 0;
- mii_info->link = 0;
-
- mii_info->advertising = (ADVERTISED_10baseT_Half |
+ phydev->supported &= (ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Full);
- mii_info->autoneg = 1;
+ ADVERTISED_100baseT_Full);
- mii_info->mii_id = ugeth->ug_info->phy_address;
+ if (priv->max_speed == SPEED_1000)
+ phydev->supported |= ADVERTISED_1000baseT_Full;
- mii_info->dev = dev;
+ phydev->advertising = phydev->supported;
- mii_info->mdio_read = &read_phy_reg;
- mii_info->mdio_write = &write_phy_reg;
-
- spin_lock_init(&mii_info->mdio_lock);
-
- ugeth->mii_info = mii_info;
-
- spin_lock_irq(&ugeth->lock);
-
- /* Set this UCC to be the master of the MII managment */
- ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
- if (init_mii_management_configuration(1,
- ugeth->ug_info->
- miiPreambleSupress,
- &mii_regs->miimcfg,
- &mii_regs->miimind)) {
- ugeth_err("%s: The MII Bus is stuck!", dev->name);
- err = -1;
- goto bus_fail;
- }
-
- spin_unlock_irq(&ugeth->lock);
-
- /* get info for this PHY */
- curphy = get_phy_info(ugeth->mii_info);
-
- if (curphy == NULL) {
- ugeth_err("%s: No PHY found", dev->name);
- err = -1;
- goto no_phy;
- }
-
- mii_info->phyinfo = curphy;
-
- /* Run the commands which initialize the PHY */
- if (curphy->init) {
- err = curphy->init(ugeth->mii_info);
- if (err)
- goto phy_init_fail;
- }
+ priv->phydev = phydev;
return 0;
-
- phy_init_fail:
- no_phy:
- bus_fail:
- kfree(mii_info);
-
- return err;
}
-#ifdef CONFIG_UGETH_TX_ON_DEMOND
-static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth)
-{
- struct ucc_fastransmit_on_demand(ugeth->uccf);
- return 0;
-}
-#endif
static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
{
@@ -2356,6 +2134,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth)
}
for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
bd = ugeth->p_tx_bd_ring[i];
+ if (!bd)
+ continue;
for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
if (ugeth->tx_skbuff[i][j]) {
dma_unmap_single(NULL,
@@ -2487,6 +2267,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
static void ucc_geth_stop(struct ucc_geth_private *ugeth)
{
struct ucc_geth *ug_regs = ugeth->ug_regs;
+ struct phy_device *phydev = ugeth->phydev;
u32 tempval;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -2495,8 +2276,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
/* Tell the kernel the link is down */
- ugeth->mii_info->link = 0;
- adjust_link(ugeth->dev);
+ phy_stop(phydev);
/* Mask all interrupts */
out_be32(ugeth->uccf->p_ucce, 0x00000000);
@@ -2509,50 +2289,24 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
out_be32(&ug_regs->maccfg1, tempval);
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- /* Clear any pending interrupts */
- mii_clear_phy_interrupt(ugeth->mii_info);
-
- /* Disable PHY Interrupts */
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_DISABLED);
- }
-
free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
- } else {
- del_timer_sync(&ugeth->phy_info_timer);
- }
-
ucc_geth_memclean(ugeth);
}
-static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+static int ucc_struct_init(struct ucc_geth_private *ugeth)
{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
- struct ucc_geth_init_pram *p_init_enet_pram;
- struct ucc_fast_private *uccf;
struct ucc_geth_info *ug_info;
struct ucc_fast_info *uf_info;
- struct ucc_fast *uf_regs;
- struct ucc_geth *ug_regs;
- int ret_val = -EINVAL;
- u32 remoder = UCC_GETH_REMODER_INIT;
- u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
- u32 ifstat, i, j, size, l2qt, l3qt, length;
- u16 temoder = UCC_GETH_TEMODER_INIT;
- u16 test;
- u8 function_code = 0;
- u8 *bd, *endOfRing;
- u8 numThreadsRxNumerical, numThreadsTxNumerical;
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
+ int i;
ug_info = ugeth->ug_info;
uf_info = &ug_info->uf_info;
+ /* Create CQs for hash tables */
+ INIT_LIST_HEAD(&ugeth->group_hash_q);
+ INIT_LIST_HEAD(&ugeth->ind_hash_q);
+
if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
(uf_info->bd_mem_part == MEM_PART_MURAM))) {
ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
@@ -2647,12 +2401,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
for (i = 0; i < ug_info->numQueuesTx; i++)
uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
/* Initialize the general fast UCC block. */
- if (ucc_fast_init(uf_info, &uccf)) {
+ if (ucc_fast_init(uf_info, &ugeth->uccf)) {
ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
ucc_geth_memclean(ugeth);
return -ENOMEM;
}
- ugeth->uccf = uccf;
+
+ ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth));
+
+ return 0;
+}
+
+static int ucc_geth_startup(struct ucc_geth_private *ugeth)
+{
+ struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
+ struct ucc_geth_init_pram *p_init_enet_pram;
+ struct ucc_fast_private *uccf;
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_info *uf_info;
+ struct ucc_fast *uf_regs;
+ struct ucc_geth *ug_regs;
+ int ret_val = -EINVAL;
+ u32 remoder = UCC_GETH_REMODER_INIT;
+ u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+ u32 ifstat, i, j, size, l2qt, l3qt, length;
+ u16 temoder = UCC_GETH_TEMODER_INIT;
+ u16 test;
+ u8 function_code = 0;
+ u8 *bd, *endOfRing;
+ u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+ uccf = ugeth->uccf;
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+ uf_regs = uccf->uf_regs;
+ ug_regs = ugeth->ug_regs;
switch (ug_info->numThreadsRx) {
case UCC_GETH_NUM_OF_THREADS_1:
@@ -2711,10 +2495,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
|| (ug_info->vlanOperationNonTagged !=
UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
- uf_regs = uccf->uf_regs;
- ug_regs = (struct ucc_geth *) (uccf->uf_regs);
- ugeth->ug_regs = ug_regs;
-
init_default_reg_vals(&uf_regs->upsmr,
&ug_regs->maccfg1, &ug_regs->maccfg2);
@@ -3177,8 +2957,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
/* Size varies with number of Rx queues */
ugeth->rx_irq_coalescing_tbl_offset =
qe_muram_alloc(ug_info->numQueuesRx *
- sizeof(struct ucc_geth_rx_interrupt_coalescing_entry),
- UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+ sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+ + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for"
@@ -3359,13 +3139,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
for (j = 0; j < NUM_OF_PADDRS; j++)
ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j);
- /* Create CQs for hash tables */
- if (ug_info->maxGroupAddrInHash > 0) {
- INIT_LIST_HEAD(&ugeth->group_hash_q);
- }
- if (ug_info->maxIndAddrInHash > 0) {
- INIT_LIST_HEAD(&ugeth->ind_hash_q);
- }
p_82xx_addr_filt =
(struct ucc_geth_82xx_address_filtering_pram *) ugeth->
p_rx_glbl_pram->addressfiltering;
@@ -3562,6 +3335,9 @@ static void ucc_geth_timeout(struct net_device *dev)
static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ struct ucc_fast_private *uccf;
+#endif
u8 *bd; /* BD pointer */
u32 bd_status;
u8 txQ = 0;
@@ -3620,6 +3396,10 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
}
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ uccf = ugeth->uccf;
+ out_be16(uccf->p_utodr, UCC_FAST_TOD);
+#endif
spin_unlock_irq(&ugeth->lock);
return 0;
@@ -3635,7 +3415,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
ugeth_vdbg("%s: IN", __FUNCTION__);
- spin_lock(&ugeth->lock);
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
@@ -3683,7 +3462,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
skb = get_new_skb(ugeth, bd);
if (!skb) {
ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
- spin_unlock(&ugeth->lock);
ugeth->stats.rx_dropped++;
break;
}
@@ -3704,7 +3482,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
}
ugeth->rxBd[rxQ] = bd;
- spin_unlock(&ugeth->lock);
return howmany;
}
@@ -3756,23 +3533,38 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
static int ucc_geth_poll(struct net_device *dev, int *budget)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth_info *ug_info;
+ struct ucc_fast_private *uccf;
int howmany;
- int rx_work_limit = *budget;
- u8 rxQ = 0;
+ u8 i;
+ int rx_work_limit;
+ register u32 uccm;
+
+ ug_info = ugeth->ug_info;
+ rx_work_limit = *budget;
if (rx_work_limit > dev->quota)
rx_work_limit = dev->quota;
- howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit);
+ howmany = 0;
+
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
+ }
dev->quota -= howmany;
rx_work_limit -= howmany;
*budget -= howmany;
- if (rx_work_limit >= 0)
+ if (rx_work_limit > 0) {
netif_rx_complete(dev);
+ uccf = ugeth->uccf;
+ uccm = in_be32(uccf->p_uccm);
+ uccm |= UCCE_RX_EVENTS;
+ out_be32(uccf->p_uccm, uccm);
+ }
- return (rx_work_limit < 0) ? 1 : 0;
+ return (rx_work_limit > 0) ? 0 : 1;
}
#endif /* CONFIG_UGETH_NAPI */
@@ -3782,10 +3574,13 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
struct ucc_geth_private *ugeth = netdev_priv(dev);
struct ucc_fast_private *uccf;
struct ucc_geth_info *ug_info;
- register u32 ucce = 0;
- register u32 bit_mask = UCCE_RXBF_SINGLE_MASK;
- register u32 tx_mask = UCCE_TXBF_SINGLE_MASK;
- register u8 i;
+ register u32 ucce;
+ register u32 uccm;
+#ifndef CONFIG_UGETH_NAPI
+ register u32 rx_mask;
+#endif
+ register u32 tx_mask;
+ u8 i;
ugeth_vdbg("%s: IN", __FUNCTION__);
@@ -3795,174 +3590,57 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
uccf = ugeth->uccf;
ug_info = ugeth->ug_info;
- do {
- ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm));
-
- /* clear event bits for next time */
- /* Side effect here is to mask ucce variable
- for future processing below. */
- out_be32(uccf->p_ucce, ucce); /* Clear with ones,
- but only bits in UCCM */
-
- /* We ignore Tx interrupts because Tx confirmation is
- done inside Tx routine */
+ /* read and clear events */
+ ucce = (u32) in_be32(uccf->p_ucce);
+ uccm = (u32) in_be32(uccf->p_uccm);
+ ucce &= uccm;
+ out_be32(uccf->p_ucce, ucce);
+ /* check for receive events that require processing */
+ if (ucce & UCCE_RX_EVENTS) {
+#ifdef CONFIG_UGETH_NAPI
+ if (netif_rx_schedule_prep(dev)) {
+ uccm &= ~UCCE_RX_EVENTS;
+ out_be32(uccf->p_uccm, uccm);
+ __netif_rx_schedule(dev);
+ }
+#else
+ rx_mask = UCCE_RXBF_SINGLE_MASK;
for (i = 0; i < ug_info->numQueuesRx; i++) {
- if (ucce & bit_mask)
- ucc_geth_rx(ugeth, i,
- (int)ugeth->ug_info->
- bdRingLenRx[i]);
- ucce &= ~bit_mask;
- bit_mask <<= 1;
+ if (ucce & rx_mask)
+ ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]);
+ ucce &= ~rx_mask;
+ rx_mask <<= 1;
}
+#endif /* CONFIG_UGETH_NAPI */
+ }
+ /* Tx event processing */
+ if (ucce & UCCE_TX_EVENTS) {
+ spin_lock(&ugeth->lock);
+ tx_mask = UCCE_TXBF_SINGLE_MASK;
for (i = 0; i < ug_info->numQueuesTx; i++) {
if (ucce & tx_mask)
ucc_geth_tx(dev, i);
ucce &= ~tx_mask;
tx_mask <<= 1;
}
+ spin_unlock(&ugeth->lock);
+ }
- /* Exceptions */
+ /* Errors and other events */
+ if (ucce & UCCE_OTHER) {
if (ucce & UCCE_BSY) {
- ugeth_vdbg("Got BUSY irq!!!!");
ugeth->stats.rx_errors++;
- ucce &= ~UCCE_BSY;
}
- if (ucce & UCCE_OTHER) {
- ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!",
- ucce);
- ugeth->stats.rx_errors++;
- ucce &= ~ucce;
+ if (ucce & UCCE_TXE) {
+ ugeth->stats.tx_errors++;
}
}
- while (ucce);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t phy_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupt */
- mii_clear_phy_interrupt(ugeth->mii_info);
-
- /* Disable PHY interrupts */
- mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
-
- /* Schedule the phy change */
- schedule_work(&ugeth->tq);
return IRQ_HANDLED;
}
-/* Scheduled by the phy_interrupt/timer to handle PHY changes */
-static void ugeth_phy_change(struct work_struct *work)
-{
- struct ucc_geth_private *ugeth =
- container_of(work, struct ucc_geth_private, tq);
- struct net_device *dev = ugeth->dev;
- struct ucc_geth *ug_regs;
- int result = 0;
-
- ugeth_vdbg("%s: IN", __FUNCTION__);
-
- ug_regs = ugeth->ug_regs;
-
- /* Delay to give the PHY a chance to change the
- * register state */
- msleep(1);
-
- /* Update the link, speed, duplex */
- result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
-
- /* Adjust the known status as long as the link
- * isn't still coming up */
- if ((0 == result) || (ugeth->mii_info->link == 0))
- adjust_link(dev);
-
- /* Reenable interrupts, if needed */
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_ENABLED);
-}
-
-/* Called every so often on systems that don't interrupt
- * the core for PHY changes */
-static void ugeth_phy_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- schedule_work(&ugeth->tq);
-
- mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
-/* Keep trying aneg for some time
- * If, after GFAR_AN_TIMEOUT seconds, it has not
- * finished, we switch to forced.
- * Either way, once the process has completed, we either
- * request the interrupt, or switch the timer over to
- * using ugeth_phy_timer to check status */
-static void ugeth_phy_startup_timer(unsigned long data)
-{
- struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
- struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev);
- static int secondary = UGETH_AN_TIMEOUT;
- int result;
-
- /* Configure the Auto-negotiation */
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* If autonegotiation failed to start, and
- * we haven't timed out, reset the timer, and return */
- if (result && secondary--) {
- mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
- return;
- } else if (result) {
- /* Couldn't start autonegotiation.
- * Try switching to forced */
- mii_info->autoneg = 0;
- result = mii_info->phyinfo->config_aneg(mii_info);
-
- /* Forcing failed! Give up */
- if (result) {
- ugeth_err("%s: Forcing failed!", mii_info->dev->name);
- return;
- }
- }
-
- /* Kill the timer so it can be restarted */
- del_timer_sync(&ugeth->phy_info_timer);
-
- /* Grab the PHY interrupt, if necessary/possible */
- if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
- if (request_irq(ugeth->ug_info->phy_interrupt,
- phy_interrupt, IRQF_SHARED,
- "phy_interrupt", mii_info->dev) < 0) {
- ugeth_err("%s: Can't get IRQ %d (PHY)",
- mii_info->dev->name,
- ugeth->ug_info->phy_interrupt);
- } else {
- mii_configure_phy_interrupt(ugeth->mii_info,
- MII_INTERRUPT_ENABLED);
- return;
- }
- }
-
- /* Start the timer again, this time in order to
- * handle a change in status */
- init_timer(&ugeth->phy_info_timer);
- ugeth->phy_info_timer.function = &ugeth_phy_timer;
- ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
- mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
-}
-
/* Called when something needs to use the ethernet device */
/* Returns 0 for success. */
static int ucc_geth_open(struct net_device *dev)
@@ -3979,6 +3657,12 @@ static int ucc_geth_open(struct net_device *dev)
return -EINVAL;
}
+ err = ucc_struct_init(ugeth);
+ if (err) {
+ ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+ return err;
+ }
+
err = ucc_geth_startup(ugeth);
if (err) {
ugeth_err("%s: Cannot configure net device, aborting.",
@@ -4006,10 +3690,12 @@ static int ucc_geth_open(struct net_device *dev)
err = init_phy(dev);
if (err) {
- ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name);
+ ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
return err;
}
-#ifndef CONFIG_UGETH_NAPI
+
+ phy_start(ugeth->phydev);
+
err =
request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
"UCC Geth", dev);
@@ -4019,15 +3705,6 @@ static int ucc_geth_open(struct net_device *dev)
ucc_geth_stop(ugeth);
return err;
}
-#endif /* CONFIG_UGETH_NAPI */
-
- /* Set up the PHY change work queue */
- INIT_WORK(&ugeth->tq, ugeth_phy_change);
-
- init_timer(&ugeth->phy_info_timer);
- ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
- ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info;
- mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
if (err) {
@@ -4050,11 +3727,8 @@ static int ucc_geth_close(struct net_device *dev)
ucc_geth_stop(ugeth);
- /* Shutdown the PHY */
- if (ugeth->mii_info->phyinfo->close)
- ugeth->mii_info->phyinfo->close(ugeth->mii_info);
-
- kfree(ugeth->mii_info);
+ phy_disconnect(ugeth->phydev);
+ ugeth->phydev = NULL;
netif_stop_queue(dev);
@@ -4063,33 +3737,67 @@ static int ucc_geth_close(struct net_device *dev)
const struct ethtool_ops ucc_geth_ethtool_ops = { };
+static phy_interface_t to_phy_interface(const char *interface_type)
+{
+ if (strcasecmp(interface_type, "mii") == 0)
+ return PHY_INTERFACE_MODE_MII;
+ if (strcasecmp(interface_type, "gmii") == 0)
+ return PHY_INTERFACE_MODE_GMII;
+ if (strcasecmp(interface_type, "tbi") == 0)
+ return PHY_INTERFACE_MODE_TBI;
+ if (strcasecmp(interface_type, "rmii") == 0)
+ return PHY_INTERFACE_MODE_RMII;
+ if (strcasecmp(interface_type, "rgmii") == 0)
+ return PHY_INTERFACE_MODE_RGMII;
+ if (strcasecmp(interface_type, "rgmii-id") == 0)
+ return PHY_INTERFACE_MODE_RGMII_ID;
+ if (strcasecmp(interface_type, "rtbi") == 0)
+ return PHY_INTERFACE_MODE_RTBI;
+
+ return PHY_INTERFACE_MODE_MII;
+}
+
static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
{
struct device *device = &ofdev->dev;
struct device_node *np = ofdev->node;
+ struct device_node *mdio;
struct net_device *dev = NULL;
struct ucc_geth_private *ugeth = NULL;
struct ucc_geth_info *ug_info;
struct resource res;
struct device_node *phy;
- int err, ucc_num, phy_interface;
- static int mii_mng_configured = 0;
+ int err, ucc_num, max_speed = 0;
const phandle *ph;
const unsigned int *prop;
const void *mac_addr;
+ phy_interface_t phy_interface;
+ static const int enet_to_speed[] = {
+ SPEED_10, SPEED_10, SPEED_10,
+ SPEED_100, SPEED_100, SPEED_100,
+ SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000,
+ };
+ static const phy_interface_t enet_to_phy_interface[] = {
+ PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII,
+ PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII,
+ PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
+ PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
+ PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+ };
ugeth_vdbg("%s: IN", __FUNCTION__);
- prop = get_property(np, "device-id", NULL);
+ prop = of_get_property(np, "device-id", NULL);
ucc_num = *prop - 1;
if ((ucc_num < 0) || (ucc_num > 7))
return -ENODEV;
ug_info = &ugeth_info[ucc_num];
ug_info->uf_info.ucc_num = ucc_num;
- prop = get_property(np, "rx-clock", NULL);
+
+ prop = of_get_property(np, "rx-clock", NULL);
ug_info->uf_info.rx_clock = *prop;
- prop = get_property(np, "tx-clock", NULL);
+ prop = of_get_property(np, "tx-clock", NULL);
ug_info->uf_info.tx_clock = *prop;
err = of_address_to_resource(np, 0, &res);
if (err)
@@ -4098,19 +3806,78 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
ug_info->uf_info.regs = res.start;
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
- ph = get_property(np, "phy-handle", NULL);
+ ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
if (phy == NULL)
return -ENODEV;
- prop = get_property(phy, "reg", NULL);
+ /* set the PHY address */
+ prop = of_get_property(phy, "reg", NULL);
+ if (prop == NULL)
+ return -1;
ug_info->phy_address = *prop;
- prop = get_property(phy, "interface", NULL);
- ug_info->enet_interface = *prop;
- ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0);
- ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)?
- 0:FSL_UGETH_BRD_HAS_PHY_INTR;
+
+ /* get the phy interface type, or default to MII */
+ prop = of_get_property(np, "interface-type", NULL);
+ if (!prop) {
+ /* handle interface property present in old trees */
+ prop = of_get_property(phy, "interface", NULL);
+ if (prop != NULL)
+ phy_interface = enet_to_phy_interface[*prop];
+ else
+ phy_interface = PHY_INTERFACE_MODE_MII;
+ } else {
+ phy_interface = to_phy_interface((const char *)prop);
+ }
+
+ /* get speed, or derive from interface */
+ prop = of_get_property(np, "max-speed", NULL);
+ if (!prop) {
+ /* handle interface property present in old trees */
+ prop = of_get_property(phy, "interface", NULL);
+ if (prop != NULL)
+ max_speed = enet_to_speed[*prop];
+ } else {
+ max_speed = *prop;
+ }
+ if (!max_speed) {
+ switch (phy_interface) {
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_TBI:
+ case PHY_INTERFACE_MODE_RTBI:
+ max_speed = SPEED_1000;
+ break;
+ default:
+ max_speed = SPEED_100;
+ break;
+ }
+ }
+
+ if (max_speed == SPEED_1000) {
+ ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
+ ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
+ ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT;
+ ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT;
+ ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT;
+ ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
+ }
+
+ /* Set the bus id */
+ mdio = of_get_parent(phy);
+
+ if (mdio == NULL)
+ return -1;
+
+ err = of_address_to_resource(mdio, 0, &res);
+ of_node_put(mdio);
+
+ if (err)
+ return -1;
+
+ ug_info->mdio_bus = res.start;
printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
@@ -4122,43 +3889,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
return -ENODEV;
}
- /* FIXME: Work around for early chip rev. */
- /* There's a bug in initial chip rev(s) in the RGMII ac */
- /* timing. */
- /* The following compensates by writing to the reserved */
- /* QE Port Output Hold Registers (CPOH1?). */
- prop = get_property(phy, "interface", NULL);
- phy_interface = *prop;
- if ((phy_interface == ENET_1000_RGMII) ||
- (phy_interface == ENET_100_RGMII) ||
- (phy_interface == ENET_10_RGMII)) {
- struct device_node *soc;
- phys_addr_t immrbase = -1;
- u32 *tmp_reg;
- u32 tmp_val;
-
- soc = of_find_node_by_type(NULL, "soc");
- if (soc) {
- unsigned int size;
- const void *prop = get_property(soc, "reg", &size);
- immrbase = of_translate_address(soc, prop);
- of_node_put(soc);
- };
-
- tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4);
- tmp_val = in_be32(tmp_reg);
- if (ucc_num == 1)
- out_be32(tmp_reg, tmp_val | 0x00003000);
- else if (ucc_num == 2)
- out_be32(tmp_reg, tmp_val | 0x0c000000);
- iounmap(tmp_reg);
- }
-
- if (!mii_mng_configured) {
- ucc_set_qe_mux_mii_mng(ucc_num);
- mii_mng_configured = 1;
- }
-
/* Create an ethernet device instance */
dev = alloc_etherdev(sizeof(*ugeth));
@@ -4192,6 +3922,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
dev->set_multicast_list = ucc_geth_set_multi;
dev->ethtool_ops = &ucc_geth_ethtool_ops;
+ ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+ ugeth->phy_interface = phy_interface;
+ ugeth->max_speed = max_speed;
+
err = register_netdev(dev);
if (err) {
ugeth_err("%s: Cannot register net device, aborting.",
@@ -4200,13 +3934,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
return err;
}
- ugeth->ug_info = ug_info;
- ugeth->dev = dev;
-
mac_addr = of_get_mac_address(np);
if (mac_addr)
memcpy(dev->dev_addr, mac_addr, 6);
+ ugeth->ug_info = ug_info;
+ ugeth->dev = dev;
+
return 0;
}
@@ -4242,19 +3976,30 @@ static struct of_platform_driver ucc_geth_driver = {
static int __init ucc_geth_init(void)
{
- int i;
+ int i, ret;
+
+ ret = uec_mdio_init();
+
+ if (ret)
+ return ret;
printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
for (i = 0; i < 8; i++)
memcpy(&(ugeth_info[i]), &ugeth_primary_info,
sizeof(ugeth_primary_info));
- return of_register_platform_driver(&ucc_geth_driver);
+ ret = of_register_platform_driver(&ucc_geth_driver);
+
+ if (ret)
+ uec_mdio_exit();
+
+ return ret;
}
static void __exit ucc_geth_exit(void)
{
of_unregister_platform_driver(&ucc_geth_driver);
+ uec_mdio_exit();
}
module_init(ucc_geth_init);
@@ -4262,4 +4007,5 @@ module_exit(ucc_geth_exit);
MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION(DRV_DESC);
+MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index a6656125359..a29e1c3ca4b 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -28,6 +28,8 @@
#include <asm/ucc.h>
#include <asm/ucc_fast.h>
+#include "ucc_geth_mii.h"
+
#define NUM_TX_QUEUES 8
#define NUM_RX_QUEUES 8
#define NUM_BDS_IN_PREFETCHED_BDS 4
@@ -36,15 +38,6 @@
#define ENET_INIT_PARAM_MAX_ENTRIES_RX 9
#define ENET_INIT_PARAM_MAX_ENTRIES_TX 8
-struct ucc_mii_mng {
- u32 miimcfg; /* MII management configuration reg */
- u32 miimcom; /* MII management command reg */
- u32 miimadd; /* MII management address reg */
- u32 miimcon; /* MII management control reg */
- u32 miimstat; /* MII management status reg */
- u32 miimind; /* MII management indication reg */
-} __attribute__ ((packed));
-
struct ucc_geth {
struct ucc_fast uccf;
@@ -53,7 +46,7 @@ struct ucc_geth {
u32 ipgifg; /* interframe gap reg. */
u32 hafdup; /* half-duplex reg. */
u8 res1[0x10];
- struct ucc_mii_mng miimng; /* MII management structure */
+ u8 miimng[0x18]; /* MII management structure moved to _mii.h */
u32 ifctl; /* interface control reg */
u32 ifstat; /* interface statux reg */
u32 macstnaddr1; /* mac station address part 1 reg */
@@ -212,6 +205,9 @@ struct ucc_geth {
#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\
UCCE_RXC | UCCE_TXC | UCCE_TXE)
+#define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY)
+#define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE)
+
/* UCC GETH UPSMR (Protocol Specific Mode Register) */
#define UPSMR_ECM 0x04000000 /* Enable CAM
Miss or
@@ -381,66 +377,6 @@ struct ucc_geth {
#define UCCS_MPD 0x01 /* Magic Packet
Detected */
-/* UCC GETH MIIMCFG (MII Management Configuration Register) */
-#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset
- management */
-#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble
- suppress */
-#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide
- << shift */
-#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80
- */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by
- 112 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by
- 160 */
-#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by
- 224 */
-
-/* UCC GETH MIIMCOM (MII Management Command Register) */
-#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */
-#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */
-
-/* UCC GETH MIIMADD (MII Management Address Register) */
-#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address
- << shift */
-#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register
- << shift */
-
-/* UCC GETH MIIMCON (MII Management Control Register) */
-#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control
- << shift */
-#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status
- << shift */
-
-/* UCC GETH MIIMIND (MII Management Indicator Register) */
-#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */
-#define MIIMIND_SCAN 0x00000002 /* Scan in
- progress */
-#define MIIMIND_BUSY 0x00000001
-
/* UCC GETH IFSTAT (Interface Status Register) */
#define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive
transmission
@@ -931,8 +867,7 @@ struct ucc_geth_hardware_statistics {
#define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */
#define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */
#define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */
-#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a
- guess */
+#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 64
#define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */
#define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */
#define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This
@@ -1009,15 +944,6 @@ struct ucc_geth_hardware_statistics {
register */
#define UCC_GETH_MACCFG1_INIT 0
#define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1)
-#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \
- (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
-
-/* Ethernet speed */
-enum enet_speed {
- ENET_SPEED_10BT, /* 10 Base T */
- ENET_SPEED_100BT, /* 100 Base T */
- ENET_SPEED_1000BT /* 1000 Base T */
-};
/* Ethernet Address Type. */
enum enet_addr_type {
@@ -1026,22 +952,6 @@ enum enet_addr_type {
ENET_ADDR_TYPE_BROADCAST
};
-/* TBI / MII Set Register */
-enum enet_tbi_mii_reg {
- ENET_TBI_MII_CR = 0x00, /* Control (CR ) */
- ENET_TBI_MII_SR = 0x01, /* Status (SR ) */
- ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */
- ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability
- (ANLPBPA) */
- ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */
- ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */
- ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page
- (ANLPANP) */
- ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */
- ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */
- ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */
-};
-
/* UCC GETH 82xx Ethernet Address Recognition Location */
enum ucc_geth_enet_address_recognition_location {
UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
@@ -1239,8 +1149,7 @@ struct ucc_geth_info {
u16 pausePeriod;
u16 extensionField;
u8 phy_address;
- u32 board_flags;
- u32 phy_interrupt;
+ u32 mdio_bus;
u8 weightfactor[NUM_TX_QUEUES];
u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
@@ -1249,7 +1158,6 @@ struct ucc_geth_info {
u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
u16 bdRingLenTx[NUM_TX_QUEUES];
u16 bdRingLenRx[NUM_RX_QUEUES];
- enum enet_interface enet_interface;
enum ucc_geth_num_of_station_addresses numStationAddresses;
enum qe_fltr_largest_external_tbl_lookup_key_size
largestexternallookupkeysize;
@@ -1326,9 +1234,11 @@ struct ucc_geth_private {
/* index of the first skb which hasn't been transmitted yet. */
u16 skb_dirtytx[NUM_TX_QUEUES];
- struct work_struct tq;
- struct timer_list phy_info_timer;
struct ugeth_mii_info *mii_info;
+ struct phy_device *phydev;
+ phy_interface_t phy_interface;
+ int max_speed;
+ uint32_t msg_enable;
int oldspeed;
int oldduplex;
int oldlink;
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
new file mode 100644
index 00000000000..27a1ef3b7b0
--- /dev/null
+++ b/drivers/net/ucc_geth_mii.c
@@ -0,0 +1,279 @@
+/*
+ * drivers/net/ucc_geth_mii.c
+ *
+ * Gianfar Ethernet Driver -- MIIM bus implementation
+ * Provides Bus interface for MIIM regs
+ *
+ * Author: Li Yang
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <asm/ocp.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/ucc.h>
+
+#include "ucc_geth_mii.h"
+#include "ucc_geth.h"
+
+#define DEBUG
+#ifdef DEBUG
+#define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg)
+#else
+#define vdbg(format, arg...) do {} while(0)
+#endif
+
+#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
+#define DRV_NAME "fsl-uec_mdio"
+
+/* Write value to the PHY for this device to the register at regnum, */
+/* waiting until the write is done before it returns. All PHY */
+/* configuration has to be done through the master UEC MIIM regs */
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
+{
+ struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+
+ /* Setting up the MII Mangement Address Register */
+ out_be32(&regs->miimadd,
+ (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+ /* Setting up the MII Mangement Control Register with the value */
+ out_be32(&regs->miimcon, value);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) & MIIMIND_BUSY)
+ cpu_relax();
+
+ return 0;
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value. Clears miimcom first. All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+ u16 value;
+
+ /* Setting up the MII Mangement Address Register */
+ out_be32(&regs->miimadd,
+ (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum);
+
+ /* Clear miimcom, perform an MII management read cycle */
+ out_be32(&regs->miimcom, 0);
+ out_be32(&regs->miimcom, MIIMCOM_READ_CYCLE);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&regs->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID))
+ cpu_relax();
+
+ /* Read MII management status */
+ value = in_be32(&regs->miimstat);
+
+ return value;
+}
+
+/* Reset the MIIM registers, and wait for the bus to free */
+int uec_mdio_reset(struct mii_bus *bus)
+{
+ struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv;
+ unsigned int timeout = PHY_INIT_TIMEOUT;
+
+ spin_lock_bh(&bus->mdio_lock);
+
+ /* Reset the management interface */
+ out_be32(&regs->miimcfg, MIIMCFG_RESET_MANAGEMENT);
+
+ /* Setup the MII Mgmt clock speed */
+ out_be32(&regs->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112);
+
+ /* Wait until the bus is free */
+ while ((in_be32(&regs->miimind) & MIIMIND_BUSY) && timeout--)
+ cpu_relax();
+
+ spin_unlock_bh(&bus->mdio_lock);
+
+ if (timeout <= 0) {
+ printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match)
+{
+ struct device *device = &ofdev->dev;
+ struct device_node *np = ofdev->node, *tempnp = NULL;
+ struct device_node *child = NULL;
+ struct ucc_mii_mng __iomem *regs;
+ struct mii_bus *new_bus;
+ struct resource res;
+ int k, err = 0;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus)
+ return -ENOMEM;
+
+ new_bus->name = "UCC Ethernet Controller MII Bus";
+ new_bus->read = &uec_mdio_read;
+ new_bus->write = &uec_mdio_write;
+ new_bus->reset = &uec_mdio_reset;
+
+ memset(&res, 0, sizeof(res));
+
+ err = of_address_to_resource(np, 0, &res);
+ if (err)
+ goto reg_map_fail;
+
+ new_bus->id = res.start;
+
+ new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL);
+
+ if (NULL == new_bus->irq) {
+ err = -ENOMEM;
+ goto reg_map_fail;
+ }
+
+ for (k = 0; k < 32; k++)
+ new_bus->irq[k] = PHY_POLL;
+
+ while ((child = of_get_next_child(np, child)) != NULL) {
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = of_get_property(child, "reg", NULL);
+ new_bus->irq[*id] = irq;
+ }
+ }
+
+ /* Set the base address */
+ regs = ioremap(res.start, sizeof(struct ucc_mii_mng));
+
+ if (NULL == regs) {
+ err = -ENOMEM;
+ goto ioremap_fail;
+ }
+
+ new_bus->priv = (void __force *)regs;
+
+ new_bus->dev = device;
+ dev_set_drvdata(device, new_bus);
+
+ /* Read MII management master from device tree */
+ while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth"))
+ != NULL) {
+ struct resource tempres;
+
+ err = of_address_to_resource(tempnp, 0, &tempres);
+ if (err)
+ goto bus_register_fail;
+
+ /* if our mdio regs fall within this UCC regs range */
+ if ((res.start >= tempres.start) &&
+ (res.end <= tempres.end)) {
+ /* set this UCC to be the MII master */
+ const u32 *id = of_get_property(tempnp, "device-id", NULL);
+ if (id == NULL)
+ goto bus_register_fail;
+
+ ucc_set_qe_mux_mii_mng(*id - 1);
+
+ /* assign the TBI an address which won't
+ * conflict with the PHYs */
+ out_be32(&regs->utbipar, UTBIPAR_INIT_TBIPA);
+ break;
+ }
+ }
+
+ err = mdiobus_register(new_bus);
+ if (0 != err) {
+ printk(KERN_ERR "%s: Cannot register as MDIO bus\n",
+ new_bus->name);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ iounmap(regs);
+ioremap_fail:
+ kfree(new_bus->irq);
+reg_map_fail:
+ kfree(new_bus);
+
+ return err;
+}
+
+int uec_mdio_remove(struct of_device *ofdev)
+{
+ struct device *device = &ofdev->dev;
+ struct mii_bus *bus = dev_get_drvdata(device);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(device, NULL);
+
+ iounmap((void __iomem *)bus->priv);
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct of_device_id uec_mdio_match[] = {
+ {
+ .type = "mdio",
+ .compatible = "ucc_geth_phy",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, uec_mdio_match);
+
+static struct of_platform_driver uec_mdio_driver = {
+ .name = DRV_NAME,
+ .probe = uec_mdio_probe,
+ .remove = uec_mdio_remove,
+ .match_table = uec_mdio_match,
+};
+
+int __init uec_mdio_init(void)
+{
+ return of_register_platform_driver(&uec_mdio_driver);
+}
+
+void __exit uec_mdio_exit(void)
+{
+ of_unregister_platform_driver(&uec_mdio_driver);
+}
diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h
new file mode 100644
index 00000000000..98430fe0bfc
--- /dev/null
+++ b/drivers/net/ucc_geth_mii.h
@@ -0,0 +1,100 @@
+/*
+ * drivers/net/ucc_geth_mii.h
+ *
+ * Gianfar Ethernet Driver -- MII Management Bus Implementation
+ * Driver for the MDIO bus controller in the Gianfar register space
+ *
+ * Author: Andy Fleming
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __UEC_MII_H
+#define __UEC_MII_H
+
+/* UCC GETH MIIMCFG (MII Management Configuration Register) */
+#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset
+ management */
+#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble
+ suppress */
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide
+ << shift */
+#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f
+
+/* UCC GETH MIIMCOM (MII Management Command Register) */
+#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */
+#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */
+
+/* UCC GETH MIIMADD (MII Management Address Register) */
+#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address
+ << shift */
+#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register
+ << shift */
+
+/* UCC GETH MIIMCON (MII Management Control Register) */
+#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control
+ << shift */
+#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status
+ << shift */
+
+/* UCC GETH MIIMIND (MII Management Indicator Register) */
+#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */
+#define MIIMIND_SCAN 0x00000002 /* Scan in
+ progress */
+#define MIIMIND_BUSY 0x00000001
+
+/* Initial TBI Physical Address */
+#define UTBIPAR_INIT_TBIPA 0x1f
+
+struct ucc_mii_mng {
+ u32 miimcfg; /* MII management configuration reg */
+ u32 miimcom; /* MII management command reg */
+ u32 miimadd; /* MII management address reg */
+ u32 miimcon; /* MII management control reg */
+ u32 miimstat; /* MII management status reg */
+ u32 miimind; /* MII management indication reg */
+ u8 notcare[28]; /* Space holder */
+ u32 utbipar; /* TBI phy address reg */
+} __attribute__ ((packed));
+
+/* TBI / MII Set Register */
+enum enet_tbi_mii_reg {
+ ENET_TBI_MII_CR = 0x00, /* Control */
+ ENET_TBI_MII_SR = 0x01, /* Status */
+ ENET_TBI_MII_ANA = 0x04, /* AN advertisement */
+ ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */
+ ENET_TBI_MII_ANEX = 0x06, /* AN expansion */
+ ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */
+ ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */
+ ENET_TBI_MII_EXST = 0x0F, /* Extended status */
+ ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */
+ ENET_TBI_MII_TBICON = 0x11 /* TBI control */
+};
+
+int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
+int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int __init uec_mdio_init(void);
+void __exit uec_mdio_exit(void);
+#endif /* __UEC_MII_H */
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
deleted file mode 100644
index 9373d895b9e..00000000000
--- a/drivers/net/ucc_geth_phy.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
- * - Rearrange code and style fixes
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "ucc_geth.h"
-#include "ucc_geth_phy.h"
-
-#define ugphy_printk(level, format, arg...) \
- printk(level format "\n", ## arg)
-
-#define ugphy_dbg(format, arg...) \
- ugphy_printk(KERN_DEBUG, format , ## arg)
-#define ugphy_err(format, arg...) \
- ugphy_printk(KERN_ERR, format , ## arg)
-#define ugphy_info(format, arg...) \
- ugphy_printk(KERN_INFO, format , ## arg)
-#define ugphy_warn(format, arg...) \
- ugphy_printk(KERN_WARNING, format , ## arg)
-
-#ifdef UGETH_VERBOSE_DEBUG
-#define ugphy_vdbg ugphy_dbg
-#else
-#define ugphy_vdbg(fmt, args...) do { } while (0)
-#endif /* UGETH_VERBOSE_DEBUG */
-
-static void config_genmii_advert(struct ugeth_mii_info *mii_info);
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
-static int genmii_update_link(struct ugeth_mii_info *mii_info);
-static int genmii_read_status(struct ugeth_mii_info *mii_info);
-
-static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
-{
- u16 retval;
- unsigned long flags;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-
- return retval;
-}
-
-static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
-{
- unsigned long flags;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irqsave(&mii_info->mdio_lock, flags);
- mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
- spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
-}
-
-/* Write value to the PHY for this device to the register at regnum, */
-/* waiting until the write is done before it returns. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct ucc_mii_mng *mii_regs;
- enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
- u32 tmp_reg;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irq(&ugeth->lock);
-
- mii_regs = ugeth->mii_info->mii_regs;
-
- /* Set this UCC to be the master of the MII managment */
- ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
-
- /* Stop the MII management read cycle */
- out_be32(&mii_regs->miimcom, 0);
- /* Setting up the MII Mangement Address Register */
- tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
- out_be32(&mii_regs->miimadd, tmp_reg);
-
- /* Setting up the MII Mangement Control Register with the value */
- out_be32(&mii_regs->miimcon, (u32) value);
-
- /* Wait till MII management write is complete */
- while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
- cpu_relax();
-
- spin_unlock_irq(&ugeth->lock);
-
- udelay(10000);
-}
-
-/* Reads from register regnum in the PHY for device dev, */
-/* returning the value. Clears miimcom first. All PHY */
-/* configuration has to be done through the TSEC1 MIIM regs */
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct ucc_mii_mng *mii_regs;
- enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum;
- u32 tmp_reg;
- u16 value;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- spin_lock_irq(&ugeth->lock);
-
- mii_regs = ugeth->mii_info->mii_regs;
-
- /* Setting up the MII Mangement Address Register */
- tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
- out_be32(&mii_regs->miimadd, tmp_reg);
-
- /* Perform an MII management read cycle */
- out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
-
- /* Wait till MII management write is complete */
- while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
- cpu_relax();
-
- udelay(10000);
-
- /* Read MII management status */
- value = (u16) in_be32(&mii_regs->miimstat);
- out_be32(&mii_regs->miimcom, 0);
- if (value == 0xffff)
- ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x",
- mii_id, mii_reg, (u32) & (mii_regs->miimcfg));
-
- spin_unlock_irq(&ugeth->lock);
-
- return (value);
-}
-
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->phyinfo->ack_interrupt)
- mii_info->phyinfo->ack_interrupt(mii_info);
-}
-
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
- u32 interrupts)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- mii_info->interrupts = interrupts;
- if (mii_info->phyinfo->config_intr)
- mii_info->phyinfo->config_intr(mii_info);
-}
-
-/* Writes MII_ADVERTISE with the appropriate values, after
- * sanitizing advertise to make sure only supported features
- * are advertised
- */
-static void config_genmii_advert(struct ugeth_mii_info *mii_info)
-{
- u32 advertise;
- u16 adv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Only allow advertising what this PHY supports */
- mii_info->advertising &= mii_info->phyinfo->features;
- advertise = mii_info->advertising;
-
- /* Setup standard advertisement */
- adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE);
- adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (advertise & ADVERTISED_10baseT_Half)
- adv |= ADVERTISE_10HALF;
- if (advertise & ADVERTISED_10baseT_Full)
- adv |= ADVERTISE_10FULL;
- if (advertise & ADVERTISED_100baseT_Half)
- adv |= ADVERTISE_100HALF;
- if (advertise & ADVERTISED_100baseT_Full)
- adv |= ADVERTISE_100FULL;
- ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv);
-}
-
-static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
-{
- u16 ctrl;
- u32 features = mii_info->phyinfo->features;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ctrl = ucc_geth_phy_read(mii_info, MII_BMCR);
-
- ctrl &=
- ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
- ctrl |= BMCR_RESET;
-
- switch (mii_info->speed) {
- case SPEED_1000:
- if (features & (SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full)) {
- ctrl |= BMCR_SPEED1000;
- break;
- }
- mii_info->speed = SPEED_100;
- case SPEED_100:
- if (features & (SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full)) {
- ctrl |= BMCR_SPEED100;
- break;
- }
- mii_info->speed = SPEED_10;
- case SPEED_10:
- if (features & (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full))
- break;
- default: /* Unsupported speed! */
- ugphy_err("%s: Bad speed!", mii_info->dev->name);
- break;
- }
-
- ucc_geth_phy_write(mii_info, MII_BMCR, ctrl);
-}
-
-/* Enable and Restart Autonegotiation */
-static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
-{
- u16 ctl;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ctl = ucc_geth_phy_read(mii_info, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- ucc_geth_phy_write(mii_info, MII_BMCR, ctl);
-}
-
-static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
-{
- u16 adv;
- u32 advertise;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->autoneg) {
- /* Configure the ADVERTISE register */
- config_genmii_advert(mii_info);
- advertise = mii_info->advertising;
-
- adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL);
- adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
- MII_1000BASETCONTROL_HALFDUPLEXCAP);
- if (advertise & SUPPORTED_1000baseT_Half)
- adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
- if (advertise & SUPPORTED_1000baseT_Full)
- adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
- ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv);
-
- /* Start/Restart aneg */
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->autoneg) {
- config_genmii_advert(mii_info);
- genmii_restart_aneg(mii_info);
- } else
- genmii_setup_forced(mii_info);
-
- return 0;
-}
-
-static int genmii_update_link(struct ugeth_mii_info *mii_info)
-{
- u16 status;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Do a fake read */
- ucc_geth_phy_read(mii_info, MII_BMSR);
-
- /* Read link and autonegotiation status */
- status = ucc_geth_phy_read(mii_info, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- mii_info->link = 0;
- else
- mii_info->link = 1;
-
- /* If we are autonegotiating, and not done,
- * return an error */
- if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return -EAGAIN;
-
- return 0;
-}
-
-static int genmii_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- if (mii_info->autoneg) {
- status = ucc_geth_phy_read(mii_info, MII_LPA);
-
- if (status & (LPA_10FULL | LPA_100FULL))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- if (status & (LPA_100FULL | LPA_100HALF))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
- mii_info->pause = 0;
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-static int marvell_init(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ucc_geth_phy_write(mii_info, 0x14, 0x0cd2);
- ucc_geth_phy_write(mii_info, 0x1b,
- (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b);
- ucc_geth_phy_write(mii_info, MII_BMCR,
- ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
- msleep(4000);
-
- return 0;
-}
-
-static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* The Marvell PHY has an errata which requires
- * that certain registers get written in order
- * to restart autonegotiation */
- ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET);
-
- ucc_geth_phy_write(mii_info, 0x1d, 0x1f);
- ucc_geth_phy_write(mii_info, 0x1e, 0x200c);
- ucc_geth_phy_write(mii_info, 0x1d, 0x5);
- ucc_geth_phy_write(mii_info, 0x1e, 0);
- ucc_geth_phy_write(mii_info, 0x1e, 0x100);
-
- gbit_config_aneg(mii_info);
-
- return 0;
-}
-
-static int marvell_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
- status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
-
- /* Get the duplexity */
- if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- /* Get the speed */
- speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
- switch (speed) {
- case MII_M1011_PHY_SPEC_STATUS_1000:
- mii_info->speed = SPEED_1000;
- break;
- case MII_M1011_PHY_SPEC_STATUS_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- mii_info->pause = 0;
- }
-
- return 0;
-}
-
-static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupts by reading the reg */
- ucc_geth_phy_read(mii_info, MII_M1011_IEVENT);
-
- return 0;
-}
-
-static int marvell_config_intr(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
- else
- ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
-
- return 0;
-}
-
-static int cis820x_init(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
- MII_CIS8201_AUXCONSTAT_INIT);
- ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
-
- return 0;
-}
-
-static int cis820x_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- int speed;
-
- status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
- if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
-
- speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
-
- switch (speed) {
- case MII_CIS8201_AUXCONSTAT_GBIT:
- mii_info->speed = SPEED_1000;
- break;
- case MII_CIS8201_AUXCONSTAT_100:
- mii_info->speed = SPEED_100;
- break;
- default:
- mii_info->speed = SPEED_10;
- break;
- }
- }
-
- return 0;
-}
-
-static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT);
-
- return 0;
-}
-
-static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
- else
- ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0);
-
- return 0;
-}
-
-#define DM9161_DELAY 10
-
-static int dm9161_read_status(struct ugeth_mii_info *mii_info)
-{
- u16 status;
- int err;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Update the link, but return if there
- * was an error */
- err = genmii_update_link(mii_info);
- if (err)
- return err;
-
- /* If the link is up, read the speed and duplex */
- /* If we aren't autonegotiating, assume speeds
- * are as set */
- if (mii_info->autoneg && mii_info->link) {
- status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR);
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
- mii_info->speed = SPEED_100;
- else
- mii_info->speed = SPEED_10;
-
- if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
- mii_info->duplex = DUPLEX_FULL;
- else
- mii_info->duplex = DUPLEX_HALF;
- }
-
- return 0;
-}
-
-static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (0 == priv->resetdone)
- return -EAGAIN;
-
- return 0;
-}
-
-static void dm9161_timer(unsigned long data)
-{
- struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
- struct dm9161_private *priv = mii_info->priv;
- u16 status = ucc_geth_phy_read(mii_info, MII_BMSR);
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (status & BMSR_ANEGCOMPLETE) {
- priv->resetdone = 1;
- } else
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-}
-
-static int dm9161_init(struct ugeth_mii_info *mii_info)
-{
- struct dm9161_private *priv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Allocate the private data structure */
- priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
-
- if (NULL == priv)
- return -ENOMEM;
-
- mii_info->priv = priv;
-
- /* Reset is not done yet */
- priv->resetdone = 0;
-
- ucc_geth_phy_write(mii_info, MII_BMCR,
- ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET);
-
- ucc_geth_phy_write(mii_info, MII_BMCR,
- ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
-
- config_genmii_advert(mii_info);
- /* Start/Restart aneg */
- genmii_config_aneg(mii_info);
-
- /* Start a timer for DM9161_DELAY seconds to wait
- * for the PHY to be ready */
- init_timer(&priv->timer);
- priv->timer.function = &dm9161_timer;
- priv->timer.data = (unsigned long)mii_info;
- mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
-
- return 0;
-}
-
-static void dm9161_close(struct ugeth_mii_info *mii_info)
-{
- struct dm9161_private *priv = mii_info->priv;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- del_timer_sync(&priv->timer);
- kfree(priv);
-}
-
-static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Clear the interrupts by reading the reg */
- ucc_geth_phy_read(mii_info, MII_DM9161_INTR);
-
-
- return 0;
-}
-
-static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
-{
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
- ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
- else
- ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
-
- return 0;
-}
-
-/* Cicada 820x */
-static struct phy_info phy_info_cis820x = {
- .phy_id = 0x000fc440,
- .name = "Cicada Cis8204",
- .phy_id_mask = 0x000fffc0,
- .features = MII_GBIT_FEATURES,
- .init = &cis820x_init,
- .config_aneg = &gbit_config_aneg,
- .read_status = &cis820x_read_status,
- .ack_interrupt = &cis820x_ack_interrupt,
- .config_intr = &cis820x_config_intr,
-};
-
-static struct phy_info phy_info_dm9161 = {
- .phy_id = 0x0181b880,
- .phy_id_mask = 0x0ffffff0,
- .name = "Davicom DM9161E",
- .init = dm9161_init,
- .config_aneg = dm9161_config_aneg,
- .read_status = dm9161_read_status,
- .close = dm9161_close,
-};
-
-static struct phy_info phy_info_dm9161a = {
- .phy_id = 0x0181b8a0,
- .phy_id_mask = 0x0ffffff0,
- .name = "Davicom DM9161A",
- .features = MII_BASIC_FEATURES,
- .init = dm9161_init,
- .config_aneg = dm9161_config_aneg,
- .read_status = dm9161_read_status,
- .ack_interrupt = dm9161_ack_interrupt,
- .config_intr = dm9161_config_intr,
- .close = dm9161_close,
-};
-
-static struct phy_info phy_info_marvell = {
- .phy_id = 0x01410c00,
- .phy_id_mask = 0xffffff00,
- .name = "Marvell 88E11x1",
- .features = MII_GBIT_FEATURES,
- .init = &marvell_init,
- .config_aneg = &marvell_config_aneg,
- .read_status = &marvell_read_status,
- .ack_interrupt = &marvell_ack_interrupt,
- .config_intr = &marvell_config_intr,
-};
-
-static struct phy_info phy_info_genmii = {
- .phy_id = 0x00000000,
- .phy_id_mask = 0x00000000,
- .name = "Generic MII",
- .features = MII_BASIC_FEATURES,
- .config_aneg = genmii_config_aneg,
- .read_status = genmii_read_status,
-};
-
-static struct phy_info *phy_info[] = {
- &phy_info_cis820x,
- &phy_info_marvell,
- &phy_info_dm9161,
- &phy_info_dm9161a,
- &phy_info_genmii,
- NULL
-};
-
-/* Use the PHY ID registers to determine what type of PHY is attached
- * to device dev. return a struct phy_info structure describing that PHY
- */
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
-{
- u16 phy_reg;
- u32 phy_ID;
- int i;
- struct phy_info *theInfo = NULL;
- struct net_device *dev = mii_info->dev;
-
- ugphy_vdbg("%s: IN", __FUNCTION__);
-
- /* Grab the bits from PHYIR1, and put them in the upper half */
- phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1);
- phy_ID = (phy_reg & 0xffff) << 16;
-
- /* Grab the bits from PHYIR2, and put them in the lower half */
- phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2);
- phy_ID |= (phy_reg & 0xffff);
-
- /* loop through all the known PHY types, and find one that */
- /* matches the ID we read from the PHY. */
- for (i = 0; phy_info[i]; i++)
- if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){
- theInfo = phy_info[i];
- break;
- }
-
- /* This shouldn't happen, as we have generic PHY support */
- if (theInfo == NULL) {
- ugphy_info("%s: PHY id %x is not supported!", dev->name,
- phy_ID);
- return NULL;
- } else {
- ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name,
- phy_ID);
- }
-
- return theInfo;
-}
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
deleted file mode 100644
index f5740783670..00000000000
--- a/drivers/net/ucc_geth_phy.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
- *
- * Author: Shlomi Gridish <gridish@freescale.com>
- *
- * Description:
- * UCC GETH Driver -- PHY handling
- *
- * Changelog:
- * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
- * - Rearrange code and style fixes
- *
- * 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.
- *
- */
-#ifndef __UCC_GETH_PHY_H__
-#define __UCC_GETH_PHY_H__
-
-#define MII_end ((u32)-2)
-#define MII_read ((u32)-1)
-
-#define MIIMIND_BUSY 0x00000001
-#define MIIMIND_NOTVALID 0x00000004
-
-#define UGETH_AN_TIMEOUT 2000
-
-/* 1000BT control (Marvell & BCM54xx at least) */
-#define MII_1000BASETCONTROL 0x09
-#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200
-#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100
-
-/* Cicada Extended Control Register 1 */
-#define MII_CIS8201_EXT_CON1 0x17
-#define MII_CIS8201_EXTCON1_INIT 0x0000
-
-/* Cicada Interrupt Mask Register */
-#define MII_CIS8201_IMASK 0x19
-#define MII_CIS8201_IMASK_IEN 0x8000
-#define MII_CIS8201_IMASK_SPEED 0x4000
-#define MII_CIS8201_IMASK_LINK 0x2000
-#define MII_CIS8201_IMASK_DUPLEX 0x1000
-#define MII_CIS8201_IMASK_MASK 0xf000
-
-/* Cicada Interrupt Status Register */
-#define MII_CIS8201_ISTAT 0x1a
-#define MII_CIS8201_ISTAT_STATUS 0x8000
-#define MII_CIS8201_ISTAT_SPEED 0x4000
-#define MII_CIS8201_ISTAT_LINK 0x2000
-#define MII_CIS8201_ISTAT_DUPLEX 0x1000
-
-/* Cicada Auxiliary Control/Status Register */
-#define MII_CIS8201_AUX_CONSTAT 0x1c
-#define MII_CIS8201_AUXCONSTAT_INIT 0x0004
-#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020
-#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018
-#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
-#define MII_CIS8201_AUXCONSTAT_100 0x0008
-
-/* 88E1011 PHY Status Register */
-#define MII_M1011_PHY_SPEC_STATUS 0x11
-#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000
-#define MII_M1011_PHY_SPEC_STATUS_100 0x4000
-#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000
-#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000
-#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800
-#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400
-
-#define MII_M1011_IEVENT 0x13
-#define MII_M1011_IEVENT_CLEAR 0x0000
-
-#define MII_M1011_IMASK 0x12
-#define MII_M1011_IMASK_INIT 0x6400
-#define MII_M1011_IMASK_CLEAR 0x0000
-
-#define MII_DM9161_SCR 0x10
-#define MII_DM9161_SCR_INIT 0x0610
-
-/* DM9161 Specified Configuration and Status Register */
-#define MII_DM9161_SCSR 0x11
-#define MII_DM9161_SCSR_100F 0x8000
-#define MII_DM9161_SCSR_100H 0x4000
-#define MII_DM9161_SCSR_10F 0x2000
-#define MII_DM9161_SCSR_10H 0x1000
-
-/* DM9161 Interrupt Register */
-#define MII_DM9161_INTR 0x15
-#define MII_DM9161_INTR_PEND 0x8000
-#define MII_DM9161_INTR_DPLX_MASK 0x0800
-#define MII_DM9161_INTR_SPD_MASK 0x0400
-#define MII_DM9161_INTR_LINK_MASK 0x0200
-#define MII_DM9161_INTR_MASK 0x0100
-#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
-#define MII_DM9161_INTR_SPD_CHANGE 0x0008
-#define MII_DM9161_INTR_LINK_CHANGE 0x0004
-#define MII_DM9161_INTR_INIT 0x0000
-#define MII_DM9161_INTR_STOP \
-(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
- | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
-
-/* DM9161 10BT Configuration/Status */
-#define MII_DM9161_10BTCSR 0x12
-#define MII_DM9161_10BTCSR_INIT 0x7800
-
-#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
- SUPPORTED_10baseT_Full | \
- SUPPORTED_100baseT_Half | \
- SUPPORTED_100baseT_Full | \
- SUPPORTED_Autoneg | \
- SUPPORTED_TP | \
- SUPPORTED_MII)
-
-#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
- SUPPORTED_1000baseT_Half | \
- SUPPORTED_1000baseT_Full)
-
-#define MII_READ_COMMAND 0x00000001
-
-#define MII_INTERRUPT_DISABLED 0x0
-#define MII_INTERRUPT_ENABLED 0x1
-/* Taken from mii_if_info and sungem_phy.h */
-struct ugeth_mii_info {
- /* Information about the PHY type */
- /* And management functions */
- struct phy_info *phyinfo;
-
- struct ucc_mii_mng *mii_regs;
-
- /* forced speed & duplex (no autoneg)
- * partner speed & duplex & pause (autoneg)
- */
- int speed;
- int duplex;
- int pause;
-
- /* The most recently read link state */
- int link;
-
- /* Enabled Interrupts */
- u32 interrupts;
-
- u32 advertising;
- int autoneg;
- int mii_id;
-
- /* private data pointer */
- /* For use by PHYs to maintain extra state */
- void *priv;
-
- /* Provided by host chip */
- struct net_device *dev;
-
- /* A lock to ensure that only one thing can read/write
- * the MDIO bus at a time */
- spinlock_t mdio_lock;
-
- /* Provided by ethernet driver */
- int (*mdio_read) (struct net_device * dev, int mii_id, int reg);
- void (*mdio_write) (struct net_device * dev, int mii_id, int reg,
- int val);
-};
-
-/* struct phy_info: a structure which defines attributes for a PHY
- *
- * id will contain a number which represents the PHY. During
- * startup, the driver will poll the PHY to find out what its
- * UID--as defined by registers 2 and 3--is. The 32-bit result
- * gotten from the PHY will be ANDed with phy_id_mask to
- * discard any bits which may change based on revision numbers
- * unimportant to functionality
- *
- * There are 6 commands which take a ugeth_mii_info structure.
- * Each PHY must declare config_aneg, and read_status.
- */
-struct phy_info {
- u32 phy_id;
- char *name;
- unsigned int phy_id_mask;
- u32 features;
-
- /* Called to initialize the PHY */
- int (*init) (struct ugeth_mii_info * mii_info);
-
- /* Called to suspend the PHY for power */
- int (*suspend) (struct ugeth_mii_info * mii_info);
-
- /* Reconfigures autonegotiation (or disables it) */
- int (*config_aneg) (struct ugeth_mii_info * mii_info);
-
- /* Determines the negotiated speed and duplex */
- int (*read_status) (struct ugeth_mii_info * mii_info);
-
- /* Clears any pending interrupts */
- int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
-
- /* Enables or disables interrupts */
- int (*config_intr) (struct ugeth_mii_info * mii_info);
-
- /* Clears up any memory if needed */
- void (*close) (struct ugeth_mii_info * mii_info);
-};
-
-struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
-void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
-int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
-void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
-void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
- u32 interrupts);
-
-struct dm9161_private {
- struct timer_list timer;
- int resetdone;
-};
-
-#endif /* __UCC_GETH_PHY_H__ */
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 23464735fa8..9ef49ce148b 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -90,7 +90,6 @@
#include <linux/ioport.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#undef COSA_SLOW_IO /* for testing purposes only */
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 00e0aaadabc..9ec6cf2e510 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -37,16 +37,16 @@
struct hdlc_header {
u8 address;
u8 control;
- u16 protocol;
+ __be16 protocol;
}__attribute__ ((packed));
struct cisco_packet {
- u32 type; /* code */
- u32 par1;
- u32 par2;
- u16 rel; /* reliability */
- u32 time;
+ __be32 type; /* code */
+ __be32 par1;
+ __be32 par2;
+ __be16 rel; /* reliability */
+ __be32 time;
}__attribute__ ((packed));
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
@@ -97,7 +97,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
static void cisco_keepalive_send(struct net_device *dev, u32 type,
- u32 par1, u32 par2)
+ __be32 par1, __be32 par2)
{
struct sk_buff *skb;
struct cisco_packet *data;
@@ -115,9 +115,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
data = (struct cisco_packet*)(skb->data + 4);
data->type = htonl(type);
- data->par1 = htonl(par1);
- data->par2 = htonl(par2);
- data->rel = 0xFFFF;
+ data->par1 = par1;
+ data->par2 = par2;
+ data->rel = __constant_htons(0xFFFF);
/* we will need do_div here if 1000 % HZ != 0 */
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
@@ -193,7 +193,7 @@ static int cisco_rx(struct sk_buff *skb)
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
in_dev = dev->ip_ptr;
addr = 0;
- mask = ~0; /* is the mask correct? */
+ mask = __constant_htonl(~0); /* is the mask correct? */
if (in_dev != NULL) {
struct in_ifaddr **ifap = &in_dev->ifa_list;
@@ -245,7 +245,7 @@ static int cisco_rx(struct sk_buff *skb)
} /* switch(protocol) */
printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
- data->protocol);
+ ntohs(data->protocol));
dev_kfree_skb_any(skb);
return NET_RX_DROP;
@@ -270,8 +270,9 @@ static void cisco_timer(unsigned long arg)
netif_dormant_on(dev);
}
- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
- state(hdlc)->rxseq);
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
+ htonl(++state(hdlc)->txseq),
+ htonl(state(hdlc)->rxseq));
state(hdlc)->request_sent = 1;
state(hdlc)->timer.expires = jiffies +
state(hdlc)->settings.interval * HZ;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index aeb2789adf2..15b6e07a438 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -288,31 +288,31 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
struct sk_buff *skb = *skb_p;
switch (skb->protocol) {
- case __constant_ntohs(NLPID_CCITT_ANSI_LMI):
+ case __constant_htons(NLPID_CCITT_ANSI_LMI):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_CCITT_ANSI_LMI;
break;
- case __constant_ntohs(NLPID_CISCO_LMI):
+ case __constant_htons(NLPID_CISCO_LMI):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_CISCO_LMI;
break;
- case __constant_ntohs(ETH_P_IP):
+ case __constant_htons(ETH_P_IP):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_IP;
break;
- case __constant_ntohs(ETH_P_IPV6):
+ case __constant_htons(ETH_P_IPV6):
head_len = 4;
skb_push(skb, head_len);
skb->data[3] = NLPID_IPV6;
break;
- case __constant_ntohs(ETH_P_802_3):
+ case __constant_htons(ETH_P_802_3):
head_len = 10;
if (skb_headroom(skb) < head_len) {
struct sk_buff *skb2 = skb_realloc_headroom(skb,
@@ -340,7 +340,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci)
skb->data[5] = FR_PAD;
skb->data[6] = FR_PAD;
skb->data[7] = FR_PAD;
- *(u16*)(skb->data + 8) = skb->protocol;
+ *(__be16*)(skb->data + 8) = skb->protocol;
}
dlci_to_q922(skb->data, dlci);
@@ -974,8 +974,8 @@ static int fr_rx(struct sk_buff *skb)
} else if (skb->len > 10 && data[3] == FR_PAD &&
data[4] == NLPID_SNAP && data[5] == FR_PAD) {
- u16 oui = ntohs(*(u16*)(data + 6));
- u16 pid = ntohs(*(u16*)(data + 8));
+ u16 oui = ntohs(*(__be16*)(data + 6));
+ u16 pid = ntohs(*(__be16*)(data + 8));
skb_pull(skb, 10);
switch ((((u32)oui) << 16) | pid) {
@@ -1127,7 +1127,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
memcpy(dev->dev_addr, "\x00\x01", 2);
get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
} else {
- *(u16*)dev->dev_addr = htons(dlci);
+ *(__be16*)dev->dev_addr = htons(dlci);
dlci_to_q922(dev->broadcast, dlci);
}
dev->hard_start_xmit = pvc_xmit;
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
index ae01555d24c..574737b55f3 100644
--- a/drivers/net/wan/lmc/lmc_media.c
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -8,7 +8,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index 74876c0073e..31e1799571a 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -27,7 +27,6 @@
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 07dbdfbfc15..e24a7b095dd 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -38,7 +38,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 4426841b2be..e273347dc60 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -153,8 +153,8 @@ config IPW2100
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt>. The module
- will be called ipw2100.ko.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
+ The module will be called ipw2100.ko.
config IPW2100_MONITOR
bool "Enable promiscuous mode"
@@ -208,8 +208,8 @@ config IPW2200
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt>. The module
- will be called ipw2200.ko.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
+ The module will be called ipw2200.ko.
config IPW2200_MONITOR
bool "Enable promiscuous mode"
@@ -265,6 +265,19 @@ config IPW2200_DEBUG
If you are not sure, say N here.
+config LIBERTAS_USB
+ tristate "Marvell Libertas 8388 802.11a/b/g cards"
+ depends on USB && WLAN_80211
+ select FW_LOADER
+ ---help---
+ A driver for Marvell Libertas 8388 USB devices.
+
+config LIBERTAS_USB_DEBUG
+ bool "Enable full debugging output in the Libertas USB module."
+ depends on LIBERTAS_USB
+ ---help---
+ Debugging support.
+
config AIRO
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN)
@@ -504,8 +517,8 @@ config PRISM54
If you want to compile the driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt>. The module
- will be called prism54.ko.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
+ The module will be called prism54.ko.
config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index c613af17a15..d2124602263 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -43,3 +43,4 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
obj-$(CONFIG_USB_ZD1201) += zd1201.o
+obj-$(CONFIG_LIBERTAS_USB) += libertas/
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README
deleted file mode 100644
index 0c274bf6d45..00000000000
--- a/drivers/net/wireless/README
+++ /dev/null
@@ -1,25 +0,0 @@
- README
- ------
-
- This directory is mostly for Wireless LAN drivers, in their
-various incarnations (ISA, PCI, Pcmcia...).
- This separate directory is needed because a lot of driver work
-on different bus (typically PCI + Pcmcia) and share 95% of the
-code. This allow the code and the config options to be in one single
-place instead of scattered all over the driver tree, which is never
-100% satisfactory.
-
- Note : if you want more info on the topic of Wireless LANs,
-you are kindly invited to have a look at the Wireless Howto :
- http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
- Some Wireless LAN drivers, like orinoco_cs, require the use of
-Wireless Tools to be configured :
- http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
-
- Special notes for distribution maintainers :
- 1) wvlan_cs will be discontinued soon in favor of orinoco_cs
- 2) Please add Wireless Tools support in your scripts
-
- Have fun...
-
- Jean
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 7fe0a61091a..2d3a180dada 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -25,7 +25,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
@@ -1145,6 +1144,7 @@ static void airo_networks_free(struct airo_info *ai);
struct airo_info {
struct net_device_stats stats;
struct net_device *dev;
+ struct list_head dev_list;
/* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
use the high bit to mark whether it is in use. */
#define MAX_FIDS 6
@@ -2360,6 +2360,21 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static LIST_HEAD(airo_devices);
+
+static void add_airo_dev(struct airo_info *ai)
+{
+ /* Upper layers already keep track of PCI devices,
+ * so we only need to remember our non-PCI cards. */
+ if (!ai->pci)
+ list_add_tail(&ai->dev_list, &airo_devices);
+}
+
+static void del_airo_dev(struct airo_info *ai)
+{
+ if (!ai->pci)
+ list_del(&ai->dev_list);
+}
static int airo_close(struct net_device *dev) {
struct airo_info *ai = dev->priv;
@@ -2381,8 +2396,6 @@ static int airo_close(struct net_device *dev) {
return 0;
}
-static void del_airo_dev( struct net_device *dev );
-
void stop_airo_card( struct net_device *dev, int freeres )
{
struct airo_info *ai = dev->priv;
@@ -2434,14 +2447,12 @@ void stop_airo_card( struct net_device *dev, int freeres )
}
}
crypto_free_cipher(ai->tfm);
- del_airo_dev( dev );
+ del_airo_dev(ai);
free_netdev( dev );
}
EXPORT_SYMBOL(stop_airo_card);
-static int add_airo_dev( struct net_device *dev );
-
static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
{
memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
@@ -2740,8 +2751,6 @@ static int airo_networks_allocate(struct airo_info *ai)
static void airo_networks_free(struct airo_info *ai)
{
- if (!ai->networks)
- return;
kfree(ai->networks);
ai->networks = NULL;
}
@@ -2816,12 +2825,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
if (IS_ERR(ai->airo_thread_task))
goto err_out_free;
ai->tfm = NULL;
- rc = add_airo_dev( dev );
- if (rc)
- goto err_out_thr;
+ add_airo_dev(ai);
if (airo_networks_allocate (ai))
- goto err_out_unlink;
+ goto err_out_thr;
airo_networks_initialize (ai);
/* The Airo-specific entries in the device structure. */
@@ -2937,9 +2944,8 @@ err_out_irq:
free_irq(dev->irq, dev);
err_out_nets:
airo_networks_free(ai);
-err_out_unlink:
- del_airo_dev(dev);
err_out_thr:
+ del_airo_dev(ai);
set_bit(JOB_DIE, &ai->jobs);
kthread_stop(ai->airo_thread_task);
err_out_free:
@@ -5535,11 +5541,6 @@ static int proc_close( struct inode *inode, struct file *file )
return 0;
}
-static struct net_device_list {
- struct net_device *dev;
- struct net_device_list *next;
-} *airo_devices;
-
/* Since the card doesn't automatically switch to the right WEP mode,
we will make it do it. If the card isn't associated, every secs we
will switch WEP modes to see if that will help. If the card is
@@ -5582,26 +5583,6 @@ static void timer_func( struct net_device *dev ) {
apriv->expires = RUN_AT(HZ*3);
}
-static int add_airo_dev( struct net_device *dev ) {
- struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL );
- if ( !node )
- return -ENOMEM;
-
- node->dev = dev;
- node->next = airo_devices;
- airo_devices = node;
-
- return 0;
-}
-
-static void del_airo_dev( struct net_device *dev ) {
- struct net_device_list **p = &airo_devices;
- while( *p && ( (*p)->dev != dev ) )
- p = &(*p)->next;
- if ( *p && (*p)->dev == dev )
- *p = (*p)->next;
-}
-
#ifdef CONFIG_PCI
static int __devinit airo_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pent)
@@ -5625,6 +5606,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
static void __devexit airo_pci_remove(struct pci_dev *pdev)
{
+ struct net_device *dev = pci_get_drvdata(pdev);
+
+ airo_print_info(dev->name, "Unregistering...");
+ stop_airo_card(dev, 1);
}
static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -5750,9 +5735,11 @@ static int __init airo_init_module( void )
static void __exit airo_cleanup_module( void )
{
- while( airo_devices ) {
- airo_print_info(airo_devices->dev->name, "Unregistering...\n");
- stop_airo_card( airo_devices->dev, 1 );
+ struct airo_info *ai;
+ while(!list_empty(&airo_devices)) {
+ ai = list_entry(airo_devices.next, struct airo_info, dev_list);
+ airo_print_info(ai->dev->name, "Unregistering...");
+ stop_airo_card(ai->dev, 1);
}
#ifdef CONFIG_PCI
pci_unregister_driver(&airo_driver);
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 38fac3bbcd8..7d5b8c2cc61 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -149,7 +149,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
/* Vitally important. If we don't do this it seems we get an
* interrupt somewhere during the power cycle, since
* hw_unavailable is already set it doesn't get ACKed, we get
- * into an interrupt loop and the the PMU decides to turn us
+ * into an interrupt loop and the PMU decides to turn us
* off. */
disable_irq(dev->irq);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 95ff175d8f3..f8483c179e4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -277,11 +277,14 @@
#define BCM43xx_SBTMSTATELOW_REJECT 0x02
#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000
#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
+#define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000
/* sbtmstatehigh state flags */
#define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001
#define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004
#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020
+#define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000
+#define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000
#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000
#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
index c947025d655..d2df6a0100a 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -32,7 +32,7 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/string.h>
-#include <linux/utsrelease.h>
+#include <linux/utsname.h>
static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *
struct bcm43xx_private *bcm = bcm43xx_priv(dev);
strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- strncpy(info->version, UTS_RELEASE, sizeof(info->version));
+ strncpy(info->version, utsname()->release, sizeof(info->version));
strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index a38e7eec0e6..5e96bca6730 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1407,7 +1407,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
& ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002));
} else {
if (connect_phy)
- flags |= 0x20000000;
+ flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_phy_connect(bcm, connect_phy);
bcm43xx_core_enable(bcm, flags);
bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3604,7 +3604,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
u32 sbtmstatelow;
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow |= 0x20000000;
+ sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
}
err = wireless_core_up(bcm, 1);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index 72529a440f1..b37f1e34870 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect)
flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
if (connect) {
- if (!(flags & 0x00010000))
+ if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL))
return -ENODEV;
flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- flags |= (0x800 << 18);
+ flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
} else {
- if (!(flags & 0x00020000))
+ if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL))
return -ENODEV;
flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- flags &= ~(0x800 << 18);
+ flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags);
}
out:
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm)
if (phy->rev > 2) {
bcm43xx_phy_write(bcm, 0x0422, 0x287A);
- bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000);
+ bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420)
+ & 0x0FFF) | 0x3000);
}
- bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874);
+ bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080)
+ | 0x7874);
bcm43xx_phy_write(bcm, 0x048E, 0x1C00);
if (phy->rev == 1) {
- bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600);
+ bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB)
+ & 0xF0FF) | 0x0600);
bcm43xx_phy_write(bcm, 0x048B, 0x005E);
- bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E);
+ bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C)
+ & 0xFF00) | 0x001E);
bcm43xx_phy_write(bcm, 0x048D, 0x0002);
}
@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev == 1) {
bcm43xx_phy_write(bcm, 0x0406, 0x4F19);
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
- (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340);
+ (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+ & 0xFC3F) | 0x0340);
bcm43xx_phy_write(bcm, 0x042C, 0x005A);
bcm43xx_phy_write(bcm, 0x0427, 0x001A);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
index 1f321ef42be..73118364b55 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h
@@ -48,6 +48,10 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm);
local_irq_restore(flags); \
} while (0)
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+ (((phy)->rev > 1) || ((phy)->connected))
+
u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset);
void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 4025dd0089d..6a109f4a1b7 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm)
return ret;
}
+#define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd)
+{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+ u16 loop_or = 0;
+ u16 adj_loopback_gain = phy->loopback_gain[0];
+ u8 loop;
+ u16 extern_lna_control;
+
+ if (!phy->connected)
+ return 0;
+ if (!has_loopback_gain(phy)) {
+ if (phy->rev < 7 || !(bcm->sprom.boardflags
+ & BCM43xx_BFL_EXTLNA)) {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0FB2;
+ case LPD(0, 0, 1):
+ return 0x00B2;
+ case LPD(1, 0, 1):
+ return 0x30B2;
+ case LPD(1, 0, 0):
+ return 0x30B3;
+ default:
+ assert(0);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8FB2;
+ case LPD(0, 0, 1):
+ return 0x80B2;
+ case LPD(1, 0, 1):
+ return 0x20B2;
+ case LPD(1, 0, 0):
+ return 0x20B3;
+ default:
+ assert(0);
+ }
+ }
+ } else {
+ if (radio->revision == 8)
+ adj_loopback_gain += 0x003E;
+ else
+ adj_loopback_gain += 0x0026;
+ if (adj_loopback_gain >= 0x46) {
+ adj_loopback_gain -= 0x46;
+ extern_lna_control = 0x3000;
+ } else if (adj_loopback_gain >= 0x3A) {
+ adj_loopback_gain -= 0x3A;
+ extern_lna_control = 0x2000;
+ } else if (adj_loopback_gain >= 0x2E) {
+ adj_loopback_gain -= 0x2E;
+ extern_lna_control = 0x1000;
+ } else {
+ adj_loopback_gain -= 0x10;
+ extern_lna_control = 0x0000;
+ }
+ for (loop = 0; loop < 16; loop++) {
+ u16 tmp = adj_loopback_gain - 6 * loop;
+ if (tmp < 6)
+ break;
+ }
+
+ loop_or = (loop << 8) | extern_lna_control;
+ if (phy->rev >= 7 && bcm->sprom.boardflags
+ & BCM43xx_BFL_EXTLNA) {
+ if (extern_lna_control)
+ loop_or |= 0x8000;
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x8F92;
+ case LPD(0, 0, 1):
+ return (0x8092 | loop_or);
+ case LPD(1, 0, 1):
+ return (0x2092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x2093 | loop_or);
+ default:
+ assert(0);
+ }
+ } else {
+ switch (lpd) {
+ case LPD(0, 1, 1):
+ return 0x0F92;
+ case LPD(0, 0, 1):
+ case LPD(1, 0, 1):
+ return (0x0092 | loop_or);
+ case LPD(1, 0, 0):
+ return (0x0093 | loop_or);
+ default:
+ assert(0);
+ }
+ }
+ }
+ return 0;
+}
+
u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
- u16 backup[19] = { 0 };
+ u16 backup[21] = { 0 };
u16 ret;
u16 i, j;
u32 tmp1 = 0, tmp2 = 0;
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS);
backup[9] = bcm43xx_phy_read(bcm, 0x0802);
bcm43xx_phy_write(bcm, 0x0814,
- (bcm43xx_phy_read(bcm, 0x0814) | 0x0003));
+ (bcm43xx_phy_read(bcm, 0x0814)
+ | 0x0003));
bcm43xx_phy_write(bcm, 0x0815,
- (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC));
+ (bcm43xx_phy_read(bcm, 0x0815)
+ & 0xFFFC));
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS,
- (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF));
+ (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)
+ & 0x7FFF));
bcm43xx_phy_write(bcm, 0x0802,
(bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC));
- bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
- bcm43xx_phy_write(bcm, 0x0812, 0x0FB2);
+ if (phy->rev > 1) { /* loopback gain enabled */
+ backup[19] = bcm43xx_phy_read(bcm, 0x080F);
+ backup[20] = bcm43xx_phy_read(bcm, 0x0810);
+ if (phy->rev >= 3)
+ bcm43xx_phy_write(bcm, 0x080F, 0xC020);
+ else
+ bcm43xx_phy_write(bcm, 0x080F, 0x8020);
+ bcm43xx_phy_write(bcm, 0x0810, 0x0000);
+ }
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
+ if (phy->rev < 7 || !(bcm->sprom.boardflags
+ & BCM43xx_BFL_EXTLNA))
+ bcm43xx_phy_write(bcm, 0x0811, 0x01B3);
+ else
+ bcm43xx_phy_write(bcm, 0x0811, 0x09B3);
}
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
}
+ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+ (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000));
backup[10] = bcm43xx_phy_read(bcm, 0x0035);
bcm43xx_phy_write(bcm, 0x0035,
(bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F));
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_write16(bcm, 0x03E6, 0x0122);
} else {
if (phy->analog >= 2)
- bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003)
- & 0xFFBF) | 0x0040);
+ bcm43xx_phy_write(bcm, 0x0003,
+ (bcm43xx_phy_read(bcm, 0x0003)
+ & 0xFFBF) | 0x0040);
bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000));
+ (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT)
+ | 0x2000));
}
ret = bcm43xx_radio_calibrationvalue(bcm);
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
if (phy->type == BCM43xx_PHYTYPE_B)
bcm43xx_radio_write16(bcm, 0x0078, 0x0026);
+ if (phy->connected)
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(0, 1, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xBFAF);
bcm43xx_phy_write(bcm, 0x002B, 0x1403);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x00B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(0, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xBFA0);
bcm43xx_radio_write16(bcm, 0x0051,
(bcm43xx_radio_read16(bcm, 0x0051) | 0x0004));
- bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
- bcm43xx_radio_write16(bcm, 0x0043,
- (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009);
+ if (radio->revision == 8)
+ bcm43xx_radio_write16(bcm, 0x0043, 0x001F);
+ else {
+ bcm43xx_radio_write16(bcm, 0x0052, 0x0000);
+ bcm43xx_radio_write16(bcm, 0x0043,
+ (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0)
+ | 0x0009);
+ }
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
for (i = 0; i < 16; i++) {
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 0)));
bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
- udelay(10);
+ udelay(20);
tmp1 += bcm43xx_phy_read(bcm, 0x002D);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm, LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
}
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0059, 0xC810);
bcm43xx_phy_write(bcm, 0x0058, 0x000D);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xEFB0);
udelay(10);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 0)));
bcm43xx_phy_write(bcm, 0x0015, 0xFFF0);
udelay(10);
tmp2 += bcm43xx_phy_read(bcm, 0x002D);
bcm43xx_phy_write(bcm, 0x0058, 0x0000);
if (phy->connected)
- bcm43xx_phy_write(bcm, 0x0812, 0x30B2);
+ bcm43xx_phy_write(bcm, 0x0812,
+ bcm43xx_get_812_value(bcm,
+ LPD(1, 0, 1)));
bcm43xx_phy_write(bcm, 0x0015, 0xAFB0);
}
tmp2++;
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0030, backup[2]);
bcm43xx_write16(bcm, 0x03EC, backup[3]);
} else {
- bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
- (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
if (phy->connected) {
+ bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO,
+ (bcm43xx_read16(bcm,
+ BCM43xx_MMIO_PHY_RADIO) & 0x7FFF));
bcm43xx_phy_write(bcm, 0x0811, backup[4]);
bcm43xx_phy_write(bcm, 0x0812, backup[5]);
bcm43xx_phy_write(bcm, 0x0814, backup[6]);
bcm43xx_phy_write(bcm, 0x0815, backup[7]);
bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]);
bcm43xx_phy_write(bcm, 0x0802, backup[9]);
+ if (phy->rev > 1) {
+ bcm43xx_phy_write(bcm, 0x080F, backup[19]);
+ bcm43xx_phy_write(bcm, 0x0810, backup[20]);
+ }
}
}
if (i >= 15)
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 4ca8a27b8c5..5b3abd54d0e 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -1,8 +1,8 @@
/*
* Intersil Prism2 driver with Host AP (software access point) support
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This file is to be included into hostap.c when S/W AP functionality is
* compiled.
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 01624005d80..b31e6a05f23 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -368,9 +368,9 @@ enum {
#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
#define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+offsetof(struct prism2_hostapd_param, u.rid.data)
#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+offsetof(struct prism2_hostapd_param, u.generic_elem.data)
/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
*/
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 8d8f4b9b8b0..ee1532b62e4 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -22,7 +22,7 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static dev_info_t dev_info = "hostap_cs";
MODULE_AUTHOR("Jouni Malinen");
@@ -838,6 +838,8 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
+ 0x2d858104),
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
0x74c5e40d),
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
@@ -848,6 +850,11 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
"Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P",
"Eval-RevA",
0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e),
+ /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */
+ PCMCIA_DEVICE_PROD_ID1234(
+ "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10",
+ "A3",
+ 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52),
PCMCIA_DEVICE_PROD_ID123(
"Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
0xe6ec52ce, 0x08649af2, 0x4b74baa0),
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index fb01fb95a9f..959887b70ca 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -3,8 +3,8 @@
* Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* 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
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index cb08bc5db2b..cdea7f71b9e 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1,7 +1,6 @@
/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/ethtool.h>
#include <net/ieee80211_crypt.h>
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 1f9edd91565..4743426cf6a 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -3,8 +3,8 @@
* Intersil Prism2/2.5/3 - hostap.o module, common routines
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* 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
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index c4f6020baa9..db4899ed4bb 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -20,7 +20,7 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static char *dev_info = "hostap_pci";
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index e235e064789..f0fd5ecdb24 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -23,7 +23,7 @@
#include "hostap_wlan.h"
-static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)";
+static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)";
static char *dev_info = "hostap_plx";
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 9137a4dd02e..d51daf87450 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -28,8 +28,8 @@
Portions of this file are based on the Host AP project,
Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 4839a45098c..7cb2052a55a 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO,
show_net_stats, store_net_stats);
+static ssize_t show_channels(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipw_priv *priv = dev_get_drvdata(d);
+ const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee);
+ int len = 0, i;
+
+ len = sprintf(&buf[len],
+ "Displaying %d channels in 2.4Ghz band "
+ "(802.11bg):\n", geo->bg_channels);
+
+ for (i = 0; i < geo->bg_channels; i++) {
+ len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
+ geo->bg[i].channel,
+ geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ?
+ " (radar spectrum)" : "",
+ ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) ||
+ (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT))
+ ? "" : ", IBSS",
+ geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+ "passive only" : "active/passive",
+ geo->bg[i].flags & IEEE80211_CH_B_ONLY ?
+ "B" : "B/G");
+ }
+
+ len += sprintf(&buf[len],
+ "Displaying %d channels in 5.2Ghz band "
+ "(802.11a):\n", geo->a_channels);
+ for (i = 0; i < geo->a_channels; i++) {
+ len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
+ geo->a[i].channel,
+ geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ?
+ " (radar spectrum)" : "",
+ ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) ||
+ (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT))
+ ? "" : ", IBSS",
+ geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ?
+ "passive only" : "active/passive");
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
static void notify_wx_assoc_event(struct ipw_priv *priv)
{
union iwreq_data wrqu;
@@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entries[] = {
&dev_attr_led.attr,
&dev_attr_speed_scan.attr,
&dev_attr_net_stats.attr,
+ &dev_attr_channels.attr,
#ifdef CONFIG_IPW2200_PROMISCUOUS
&dev_attr_rtap_iface.attr,
&dev_attr_rtap_filter.attr,
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
new file mode 100644
index 00000000000..e0ecc4d483b
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.c
@@ -0,0 +1,754 @@
+/**
+ * This file contains functions for 802.11D.
+ */
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/wireless.h>
+
+#include "host.h"
+#include "decl.h"
+#include "11d.h"
+#include "dev.h"
+#include "wext.h"
+
+#define TX_PWR_DEFAULT 10
+
+static struct region_code_mapping region_code_mapping[] = {
+ {"US ", 0x10}, /* US FCC */
+ {"CA ", 0x10}, /* IC Canada */
+ {"SG ", 0x10}, /* Singapore */
+ {"EU ", 0x30}, /* ETSI */
+ {"AU ", 0x30}, /* Australia */
+ {"KR ", 0x30}, /* Republic Of Korea */
+ {"ES ", 0x31}, /* Spain */
+ {"FR ", 0x32}, /* France */
+ {"JP ", 0x40}, /* Japan */
+};
+
+/* Following 2 structure defines the supported channels */
+static struct chan_freq_power channel_freq_power_UN_BG[] = {
+ {1, 2412, TX_PWR_DEFAULT},
+ {2, 2417, TX_PWR_DEFAULT},
+ {3, 2422, TX_PWR_DEFAULT},
+ {4, 2427, TX_PWR_DEFAULT},
+ {5, 2432, TX_PWR_DEFAULT},
+ {6, 2437, TX_PWR_DEFAULT},
+ {7, 2442, TX_PWR_DEFAULT},
+ {8, 2447, TX_PWR_DEFAULT},
+ {9, 2452, TX_PWR_DEFAULT},
+ {10, 2457, TX_PWR_DEFAULT},
+ {11, 2462, TX_PWR_DEFAULT},
+ {12, 2467, TX_PWR_DEFAULT},
+ {13, 2472, TX_PWR_DEFAULT},
+ {14, 2484, TX_PWR_DEFAULT}
+};
+
+static u8 wlan_region_2_code(u8 * region)
+{
+ u8 i;
+ u8 size = sizeof(region_code_mapping)/
+ sizeof(struct region_code_mapping);
+
+ for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++)
+ region[i] = toupper(region[i]);
+
+ for (i = 0; i < size; i++) {
+ if (!memcmp(region, region_code_mapping[i].region,
+ COUNTRY_CODE_LEN))
+ return (region_code_mapping[i].code);
+ }
+
+ /* default is US */
+ return (region_code_mapping[0].code);
+}
+
+static u8 *wlan_code_2_region(u8 code)
+{
+ u8 i;
+ u8 size = sizeof(region_code_mapping)
+ / sizeof(struct region_code_mapping);
+ for (i = 0; i < size; i++) {
+ if (region_code_mapping[i].code == code)
+ return (region_code_mapping[i].region);
+ }
+ /* default is US */
+ return (region_code_mapping[0].region);
+}
+
+/**
+ * @brief This function finds the nrchan-th chan after the firstchan
+ * @param band band
+ * @param firstchan first channel number
+ * @param nrchan number of channels
+ * @return the nrchan-th chan number
+*/
+static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan)
+/*find the nrchan-th chan after the firstchan*/
+{
+ u8 i;
+ struct chan_freq_power *cfp;
+ u8 cfp_no;
+
+ cfp = channel_freq_power_UN_BG;
+ cfp_no = sizeof(channel_freq_power_UN_BG) /
+ sizeof(struct chan_freq_power);
+
+ for (i = 0; i < cfp_no; i++) {
+ if ((cfp + i)->channel == firstchan) {
+ lbs_pr_debug(1, "firstchan found\n");
+ break;
+ }
+ }
+
+ if (i < cfp_no) {
+ /*if beyond the boundary */
+ if (i + nrchan < cfp_no) {
+ *chan = (cfp + i + nrchan)->channel;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * @brief This function Checks if chan txpwr is learned from AP/IBSS
+ * @param chan chan number
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return TRUE; FALSE
+*/
+static u8 wlan_channel_known_11d(u8 chan,
+ struct parsed_region_chan_11d * parsed_region_chan)
+{
+ struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr;
+ u8 nr_chan = parsed_region_chan->nr_chan;
+ u8 i = 0;
+
+ lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+ sizeof(struct chan_power_11d) * nr_chan);
+
+ for (i = 0; i < nr_chan; i++) {
+ if (chan == chanpwr[i].chan) {
+ lbs_pr_debug(1, "11D: Found Chan:%d\n", chan);
+ return 1;
+ }
+ }
+
+ lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan);
+ return 0;
+}
+
+u32 libertas_chan_2_freq(u8 chan, u8 band)
+{
+ struct chan_freq_power *cf;
+ u16 cnt;
+ u16 i;
+ u32 freq = 0;
+
+ cf = channel_freq_power_UN_BG;
+ cnt =
+ sizeof(channel_freq_power_UN_BG) /
+ sizeof(struct chan_freq_power);
+
+ for (i = 0; i < cnt; i++) {
+ if (chan == cf[i].channel)
+ freq = cf[i].freq;
+ }
+
+ return freq;
+}
+
+static int generate_domain_info_11d(struct parsed_region_chan_11d
+ *parsed_region_chan,
+ struct wlan_802_11d_domain_reg * domaininfo)
+{
+ u8 nr_subband = 0;
+
+ u8 nr_chan = parsed_region_chan->nr_chan;
+ u8 nr_parsedchan = 0;
+
+ u8 firstchan = 0, nextchan = 0, maxpwr = 0;
+
+ u8 i, flag = 0;
+
+ memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
+ COUNTRY_CODE_LEN);
+
+ lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan);
+ lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+ sizeof(struct parsed_region_chan_11d));
+
+ for (i = 0; i < nr_chan; i++) {
+ if (!flag) {
+ flag = 1;
+ nextchan = firstchan =
+ parsed_region_chan->chanpwr[i].chan;
+ maxpwr = parsed_region_chan->chanpwr[i].pwr;
+ nr_parsedchan = 1;
+ continue;
+ }
+
+ if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 &&
+ parsed_region_chan->chanpwr[i].pwr == maxpwr) {
+ nextchan++;
+ nr_parsedchan++;
+ } else {
+ domaininfo->subband[nr_subband].firstchan = firstchan;
+ domaininfo->subband[nr_subband].nrchan =
+ nr_parsedchan;
+ domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+ nr_subband++;
+ nextchan = firstchan =
+ parsed_region_chan->chanpwr[i].chan;
+ maxpwr = parsed_region_chan->chanpwr[i].pwr;
+ }
+ }
+
+ if (flag) {
+ domaininfo->subband[nr_subband].firstchan = firstchan;
+ domaininfo->subband[nr_subband].nrchan = nr_parsedchan;
+ domaininfo->subband[nr_subband].maxtxpwr = maxpwr;
+ nr_subband++;
+ }
+ domaininfo->nr_subband = nr_subband;
+
+ lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband);
+ lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+ COUNTRY_CODE_LEN + 1 +
+ sizeof(struct ieeetypes_subbandset) * nr_subband);
+ return 0;
+}
+
+/**
+ * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS
+ * @param region_chan pointer to struct region_channel
+ * @param *parsed_region_chan pointer to parsed_region_chan_11d
+ * @return N/A
+*/
+static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan,
+ struct parsed_region_chan_11d *
+ parsed_region_chan)
+{
+ u8 i;
+ struct chan_freq_power *cfp;
+
+ if (region_chan == NULL) {
+ lbs_pr_debug(1, "11D: region_chan is NULL\n");
+ return;
+ }
+
+ cfp = region_chan->CFP;
+ if (cfp == NULL) {
+ lbs_pr_debug(1, "11D: cfp equal NULL \n");
+ return;
+ }
+
+ parsed_region_chan->band = region_chan->band;
+ parsed_region_chan->region = region_chan->region;
+ memcpy(parsed_region_chan->countrycode,
+ wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
+
+ lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+ parsed_region_chan->band);
+
+ for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
+ parsed_region_chan->chanpwr[i].chan = cfp->channel;
+ parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
+ lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n",
+ parsed_region_chan->chanpwr[i].chan,
+ parsed_region_chan->chanpwr[i].pwr);
+ }
+ parsed_region_chan->nr_chan = region_chan->nrcfp;
+
+ lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+
+ return;
+}
+
+/**
+ * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS
+ * @param region region ID
+ * @param band band
+ * @param chan chan
+ * @return TRUE;FALSE
+*/
+static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan)
+{
+ struct chan_freq_power *cfp;
+ int cfp_no;
+ u8 idx;
+
+ ENTER();
+
+ cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+ if (cfp == NULL)
+ return 0;
+
+ for (idx = 0; idx < cfp_no; idx++) {
+ if (chan == (cfp + idx)->channel) {
+ /* If Mrvl Chip Supported? */
+ if ((cfp + idx)->unsupported) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ }
+
+ /*chan is not in the region table */
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function checks if chan txpwr is learned from AP/IBSS
+ * @param chan chan number
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return 0
+*/
+static int parse_domain_info_11d(struct ieeetypes_countryinfofullset*
+ countryinfo,
+ u8 band,
+ struct parsed_region_chan_11d *
+ parsed_region_chan)
+{
+ u8 nr_subband, nrchan;
+ u8 lastchan, firstchan;
+ u8 region;
+ u8 curchan = 0;
+
+ u8 idx = 0; /*chan index in parsed_region_chan */
+
+ u8 j, i;
+
+ ENTER();
+
+ /*validation Rules:
+ 1. valid region Code
+ 2. First Chan increment
+ 3. channel range no overlap
+ 4. channel is valid?
+ 5. channel is supported by region?
+ 6. Others
+ */
+
+ lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+
+ if ((*(countryinfo->countrycode)) == 0
+ || (countryinfo->len <= COUNTRY_CODE_LEN)) {
+ /* No region Info or Wrong region info: treat as No 11D info */
+ LEAVE();
+ return 0;
+ }
+
+ /*Step1: check region_code */
+ parsed_region_chan->region = region =
+ wlan_region_2_code(countryinfo->countrycode);
+
+ lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region);
+ lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+ COUNTRY_CODE_LEN);
+
+ parsed_region_chan->band = band;
+
+ memcpy(parsed_region_chan->countrycode, countryinfo->countrycode,
+ COUNTRY_CODE_LEN);
+
+ nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) /
+ sizeof(struct ieeetypes_subbandset);
+
+ for (j = 0, lastchan = 0; j < nr_subband; j++) {
+
+ if (countryinfo->subband[j].firstchan <= lastchan) {
+ /*Step2&3. Check First Chan Num increment and no overlap */
+ lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n",
+ countryinfo->subband[j].firstchan, lastchan);
+ continue;
+ }
+
+ firstchan = countryinfo->subband[j].firstchan;
+ nrchan = countryinfo->subband[j].nrchan;
+
+ for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) {
+ /*step4: channel is supported? */
+
+ if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) {
+ /* Chan is not found in UN table */
+ lbs_pr_debug(1, "chan is not supported: %d \n", i);
+ break;
+ }
+
+ lastchan = curchan;
+
+ if (wlan_region_chan_supported_11d
+ (region, band, curchan)) {
+ /*step5: Check if curchan is supported by mrvl in region */
+ parsed_region_chan->chanpwr[idx].chan = curchan;
+ parsed_region_chan->chanpwr[idx].pwr =
+ countryinfo->subband[j].maxtxpwr;
+ idx++;
+ } else {
+ /*not supported and ignore the chan */
+ lbs_pr_debug(1,
+ "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+ i, curchan, region, band);
+ }
+ }
+
+ /*Step6: Add other checking if any */
+
+ }
+
+ parsed_region_chan->nr_chan = idx;
+
+ lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan);
+ lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+ 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function calculates the scan type for channels
+ * @param chan chan number
+ * @param parsed_region_chan pointer to parsed_region_chan_11d
+ * @return PASSIVE if chan is unknown; ACTIVE if chan is known
+*/
+u8 libertas_get_scan_type_11d(u8 chan,
+ struct parsed_region_chan_11d * parsed_region_chan)
+{
+ u8 scan_type = cmd_scan_type_passive;
+
+ ENTER();
+
+ if (wlan_channel_known_11d(chan, parsed_region_chan)) {
+ lbs_pr_debug(1, "11D: Found and do Active Scan\n");
+ scan_type = cmd_scan_type_active;
+ } else {
+ lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n");
+ }
+
+ LEAVE();
+ return scan_type;
+
+}
+
+void libertas_init_11d(wlan_private * priv)
+{
+ priv->adapter->enable11d = 0;
+ memset(&(priv->adapter->parsed_region_chan), 0,
+ sizeof(struct parsed_region_chan_11d));
+ return;
+}
+
+static int wlan_enable_11d(wlan_private * priv, u8 flag)
+{
+ int ret;
+
+ priv->adapter->enable11d = flag;
+
+ /* send cmd to FW to enable/disable 11D function in FW */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ OID_802_11D_ENABLE,
+ &priv->adapter->enable11d);
+ if (ret)
+ lbs_pr_debug(1, "11D: Fail to enable 11D \n");
+
+ return 0;
+}
+
+/**
+ * @brief This function sets DOMAIN INFO to FW
+ * @param priv pointer to wlan_private
+ * @return 0; -1
+*/
+static int set_domain_info_11d(wlan_private * priv)
+{
+ int ret;
+
+ if (!priv->adapter->enable11d) {
+ lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n");
+ return 0;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+ if (ret)
+ lbs_pr_debug(1, "11D: Fail to dnld domain Info\n");
+
+ return ret;
+}
+
+/**
+ * @brief This function setups scan channels
+ * @param priv pointer to wlan_private
+ * @param band band
+ * @return 0
+*/
+int libertas_set_universaltable(wlan_private * priv, u8 band)
+{
+ wlan_adapter *adapter = priv->adapter;
+ u16 size = sizeof(struct chan_freq_power);
+ u16 i = 0;
+
+ memset(adapter->universal_channel, 0,
+ sizeof(adapter->universal_channel));
+
+ adapter->universal_channel[i].nrcfp =
+ sizeof(channel_freq_power_UN_BG) / size;
+ lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n",
+ adapter->universal_channel[i].nrcfp);
+
+ adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
+ adapter->universal_channel[i].valid = 1;
+ adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE;
+ adapter->universal_channel[i].band = band;
+ i++;
+
+ return 0;
+}
+
+/**
+ * @brief This function implements command CMD_802_11D_DOMAIN_INFO
+ * @param priv pointer to wlan_private
+ * @param cmd pointer to cmd buffer
+ * @param cmdno cmd ID
+ * @param cmdOption cmd action
+ * @return 0
+*/
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *cmd, u16 cmdno,
+ u16 cmdoption)
+{
+ struct cmd_ds_802_11d_domain_info *pdomaininfo =
+ &cmd->params.domaininfo;
+ struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain;
+ wlan_adapter *adapter = priv->adapter;
+ u8 nr_subband = adapter->domainreg.nr_subband;
+
+ ENTER();
+
+ lbs_pr_debug(1, "nr_subband=%x\n", nr_subband);
+
+ cmd->command = cpu_to_le16(cmdno);
+ pdomaininfo->action = cpu_to_le16(cmdoption);
+ if (cmdoption == cmd_act_get) {
+ cmd->size =
+ cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+ lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+ (int)(cmd->size));
+ LEAVE();
+ return 0;
+ }
+
+ domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
+ memcpy(domain->countrycode, adapter->domainreg.countrycode,
+ sizeof(domain->countrycode));
+
+ domain->header.len =
+ cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) +
+ sizeof(domain->countrycode));
+
+ if (nr_subband) {
+ memcpy(domain->subband, adapter->domainreg.subband,
+ nr_subband * sizeof(struct ieeetypes_subbandset));
+
+ cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
+ domain->header.len +
+ sizeof(struct mrvlietypesheader) +
+ S_DS_GEN);
+ } else {
+ cmd->size =
+ cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
+ }
+
+ lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size));
+
+ LEAVE();
+
+ return 0;
+}
+
+/**
+ * @brief This function implements private cmd: enable/disable 11D
+ * @param priv pointer to wlan_private
+ * @param wrq pointer to user data
+ * @return 0 or -1
+ */
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
+{
+ int data = 0;
+ int *val;
+
+ ENTER();
+ data = SUBCMD_DATA(wrq);
+
+ lbs_pr_debug(1, "enable 11D: %s\n",
+ (data == 1) ? "enable" : "Disable");
+
+ wlan_enable_11d(priv, data);
+ val = (int *)wrq->u.name;
+ *val = priv->adapter->enable11d;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function parses countryinfo from AP and download country info to FW
+ * @param priv pointer to wlan_private
+ * @param resp pointer to command response buffer
+ * @return 0; -1
+ */
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11d_domain_info
+ *domaininfo = &resp->params.domaininforesp;
+ struct mrvlietypes_domainparamset *domain = &domaininfo->domain;
+ u16 action = le16_to_cpu(domaininfo->action);
+ s16 ret = 0;
+ u8 nr_subband = 0;
+
+ ENTER();
+
+ lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+ (int)le16_to_cpu(resp->size));
+
+ nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset);
+ /* countrycode 3 bytes */
+
+ lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+
+ if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
+ lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n");
+ return -1;
+ }
+
+ switch (action) {
+ case cmd_act_set: /*Proc Set action */
+ break;
+
+ case cmd_act_get:
+ break;
+ default:
+ lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action);
+ ret = -1;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function parses countryinfo from AP and download country info to FW
+ * @param priv pointer to wlan_private
+ * @return 0; -1
+ */
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv)
+{
+ int ret;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+ if (priv->adapter->enable11d) {
+ memset(&adapter->parsed_region_chan, 0,
+ sizeof(struct parsed_region_chan_11d));
+ ret = parse_domain_info_11d(&adapter->pattemptedbssdesc->
+ countryinfo, 0,
+ &adapter->parsed_region_chan);
+
+ if (ret == -1) {
+ lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n");
+ LEAVE();
+ return ret;
+ }
+
+ memset(&adapter->domainreg, 0,
+ sizeof(struct wlan_802_11d_domain_reg));
+ generate_domain_info_11d(&adapter->parsed_region_chan,
+ &adapter->domainreg);
+
+ ret = set_domain_info_11d(priv);
+
+ if (ret) {
+ lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+ LEAVE();
+ return ret;
+ }
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function generates 11D info from user specified regioncode and download to FW
+ * @param priv pointer to wlan_private
+ * @return 0; -1
+ */
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv)
+{
+ int ret;
+ wlan_adapter *adapter = priv->adapter;
+ struct region_channel *region_chan;
+ u8 j;
+
+ ENTER();
+ lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+
+ if (priv->adapter->enable11d) {
+ /* update parsed_region_chan_11; dnld domaininf to FW */
+
+ for (j = 0; j < sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0]); j++) {
+ region_chan = &adapter->region_channel[j];
+
+ lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j,
+ region_chan->band);
+
+ if (!region_chan || !region_chan->valid
+ || !region_chan->CFP)
+ continue;
+ if (region_chan->band != adapter->curbssparams.band)
+ continue;
+ break;
+ }
+
+ if (j >= sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0])) {
+ lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n",
+ adapter->curbssparams.band);
+ LEAVE();
+ return -1;
+ }
+
+ memset(&adapter->parsed_region_chan, 0,
+ sizeof(struct parsed_region_chan_11d));
+ wlan_generate_parsed_region_chan_11d(region_chan,
+ &adapter->
+ parsed_region_chan);
+
+ memset(&adapter->domainreg, 0,
+ sizeof(struct wlan_802_11d_domain_reg));
+ generate_domain_info_11d(&adapter->parsed_region_chan,
+ &adapter->domainreg);
+
+ ret = set_domain_info_11d(priv);
+
+ if (ret) {
+ lbs_pr_debug(1, "11D: Err set domainInfo to FW\n");
+ LEAVE();
+ return ret;
+ }
+
+ }
+
+ LEAVE();
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
new file mode 100644
index 00000000000..db2ebea9f23
--- /dev/null
+++ b/drivers/net/wireless/libertas/11d.h
@@ -0,0 +1,105 @@
+/**
+ * This header file contains data structures and
+ * function declarations of 802.11d
+ */
+#ifndef _WLAN_11D_
+#define _WLAN_11D_
+
+#include "types.h"
+#include "defs.h"
+
+#define UNIVERSAL_REGION_CODE 0xff
+
+/** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr)
+ */
+#define MRVDRV_MAX_SUBBAND_802_11D 83
+
+#define COUNTRY_CODE_LEN 3
+#define MAX_NO_OF_CHAN 40
+
+struct cmd_ds_command;
+
+/** Data structure for Country IE*/
+struct ieeetypes_subbandset {
+ u8 firstchan;
+ u8 nrchan;
+ u8 maxtxpwr;
+} __attribute__ ((packed));
+
+struct ieeetypes_countryinfoset {
+ u8 element_id;
+ u8 len;
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieeetypes_subbandset subband[1];
+};
+
+struct ieeetypes_countryinfofullset {
+ u8 element_id;
+ u8 len;
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+} __attribute__ ((packed));
+
+struct mrvlietypes_domainparamset {
+ struct mrvlietypesheader header;
+ u8 countrycode[COUNTRY_CODE_LEN];
+ struct ieeetypes_subbandset subband[1];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11d_domain_info {
+ u16 action;
+ struct mrvlietypes_domainparamset domain;
+} __attribute__ ((packed));
+
+/** domain regulatory information */
+struct wlan_802_11d_domain_reg {
+ /** country Code*/
+ u8 countrycode[COUNTRY_CODE_LEN];
+ /** No. of subband*/
+ u8 nr_subband;
+ struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D];
+};
+
+struct chan_power_11d {
+ u8 chan;
+ u8 pwr;
+} __attribute__ ((packed));
+
+struct parsed_region_chan_11d {
+ u8 band;
+ u8 region;
+ s8 countrycode[COUNTRY_CODE_LEN];
+ struct chan_power_11d chanpwr[MAX_NO_OF_CHAN];
+ u8 nr_chan;
+} __attribute__ ((packed));
+
+struct region_code_mapping {
+ u8 region[COUNTRY_CODE_LEN];
+ u8 code;
+};
+
+u8 libertas_get_scan_type_11d(u8 chan,
+ struct parsed_region_chan_11d *parsed_region_chan);
+
+u32 libertas_chan_2_freq(u8 chan, u8 band);
+
+enum state_11d libertas_get_state_11d(wlan_private * priv);
+
+void libertas_init_11d(wlan_private * priv);
+
+int libertas_set_universaltable(wlan_private * priv, u8 band);
+
+int libertas_cmd_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *cmd, u16 cmdno,
+ u16 cmdOption);
+
+int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
+
+int libertas_ret_802_11d_domain_info(wlan_private * priv,
+ struct cmd_ds_command *resp);
+
+int libertas_parse_dnld_countryinfo_11d(wlan_private * priv);
+
+int libertas_create_dnld_countryinfo_11d(wlan_private * priv);
+
+#endif /* _WLAN_11D_ */
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE
new file mode 100644
index 00000000000..8862742213b
--- /dev/null
+++ b/drivers/net/wireless/libertas/LICENSE
@@ -0,0 +1,16 @@
+ Copyright (c) 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ 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., 59
+ Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
new file mode 100644
index 00000000000..19c935071d8
--- /dev/null
+++ b/drivers/net/wireless/libertas/Makefile
@@ -0,0 +1,21 @@
+# EXTRA_CFLAGS += -Wpacked
+
+usb8xxx-objs := main.o fw.o wext.o \
+ rx.o tx.o cmd.o \
+ cmdresp.o scan.o \
+ join.o 11d.o \
+ ioctl.o debugfs.o \
+ ethtool.o assoc.o
+
+ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y)
+EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG
+endif
+
+
+# This is needed to support the newer boot2 bootloader (v >= 3104)
+EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND
+usb8xxx-objs += if_bootcmd.o
+usb8xxx-objs += if_usb.o
+
+obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README
new file mode 100644
index 00000000000..688da4c784b
--- /dev/null
+++ b/drivers/net/wireless/libertas/README
@@ -0,0 +1,1044 @@
+================================================================================
+ README for USB8388
+
+ (c) Copyright © 2003-2006, Marvell International Ltd.
+ All Rights Reserved
+
+ This software file (the "File") is distributed by Marvell International
+ Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ (the "License"). You may use, redistribute and/or modify this File in
+ accordance with the terms and conditions of the License, a copy of which
+ is available along with the File in the license.txt file or by writing to
+ the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
+
+ THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ this warranty disclaimer.
+================================================================================
+
+=====================
+DRIVER LOADING
+=====================
+
+ o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/
+
+ o. Load driver by using the following command:
+
+ insmod usb8388.ko [fw_name=usb8388.bin]
+
+=====================
+IWPRIV COMMAND
+=====================
+
+NAME
+ This manual describes the usage of private commands used in Marvell WLAN
+ Linux Driver. All the commands available in Wlanconfig will not be available
+ in the iwpriv.
+
+SYNOPSIS
+ iwpriv <ethX> <command> [sub-command] ...
+
+ iwpriv ethX version
+ iwpriv ethX scantype [sub-command]
+ iwpriv ethX getSNR <n>
+ iwpriv ethX getNF <n>
+ iwpriv ethX getRSSI <n>
+ iwpriv ethX setrxant <n>
+ iwpriv ethX getrxant
+ iwpriv ethX settxant <n>
+ iwpriv ethX gettxant
+ iwpriv ethX authalgs <n>
+ iwpriv ethX pre-TBTT <n>
+ iwpriv ethX 8021xauthalgs <n>
+ iwpriv ethX encryptionmode <n>
+ iwpriv ethX setregioncode <n>
+ iwpriv ethX getregioncode
+ iwpriv ethX setbcnavg <n>
+ iwpriv ethX getbcnavg
+ iwpriv ethX setdataavg <n>
+ iwpriv ethX setlisteninter <n>
+ iwpriv ethX getlisteninter
+ iwpriv ethX setmultipledtim <n>
+ iwpriv ethX getmultipledtim
+ iwpriv ethX atimwindow <n>
+ iwpriv ethX deauth
+ iwpriv ethX adhocstop
+ iwpriv ethX radioon
+ iwpriv ethX radiooff
+ iwpriv ethX reasso-on
+ iwpriv ethX reasso-off
+ iwpriv ethX scanmode [sub-command]
+ iwpriv ethX setwpaie <n>
+ iwpriv ethX wlanidle-off
+ iwpriv ethX wlanidle-on
+ iwpriv ethX getcis
+ iwpriv ethX getlog
+ iwpriv ethX getadhocstatus
+ iwpriv ethX adhocgrate <n>
+
+Version 4 Command:
+ iwpriv ethX inactvityto <n>
+ iwpriv ethX sleeppd <n>
+ iwpriv ethX enable11d <n>
+ iwpriv ethX tpccfg <n>
+ iwpriv ethX powercfg <n>
+ iwpriv ethX setafc <n>
+ iwpriv ethX getafc
+
+Version 5 Command:
+ iwpriv ethX ledgpio <n>
+ iwpriv ethX scanprobes <n>
+ iwpriv ethX lolisteninter <n>
+ iwpriv ethX rateadapt <n> <m>
+ iwpriv ethX txcontrol <n>
+ iwpriv ethX psnullinterval <n>
+ iwpriv ethX prescan <n>
+ iwpriv ethX getrxinfo
+ iwpriv ethX gettxrate
+ iwpriv ethX beaconinterval
+
+BT Commands:
+ The blinding table (BT) contains a list of mac addresses that should be
+ ignored by the firmware. It is primarily used for debugging and
+ testing networks. It can be edited and inspected with the following
+ commands:
+
+ iwpriv ethX bt_reset
+ iwpriv ethX bt_add <mac_address>
+ iwpriv ethX bt_del <mac_address>
+ iwpriv ethX bt_list <id>
+
+FWT Commands:
+ The forwarding table (FWT) is a feature used to manage mesh network
+ routing in the firmware. The FWT is essentially a routing table that
+ associates a destination mac address (da) with a next hop receiver
+ address (ra). The FWT can be inspected and edited with the following
+ iwpriv commands, which are described in greater detail below.
+ Eventually, the table will be automatically maintained by a custom
+ routing protocol.
+
+ NOTE: FWT commands replace the previous DFT commands. What were the DFT
+ commands?, you might ask. They were an earlier API to the firmware that
+ implemented a simple MAC-layer forwarding mechanism. In the unlikely
+ event that you were using these commands, you must migrate to the new
+ FWT commands which can be used to achieve the same functionality.
+
+ iwpriv ethX fwt_add [parameters]
+ iwpriv ethX fwt_del [parameters]
+ iwpriv ethX fwt_lookup [parameters]
+ iwpriv ethX fwt_list [parameters]
+ iwpriv ethX fwt_list_route [parameters]
+ iwpriv ethX fwt_list_neigh [parameters]
+ iwpriv ethX fwt_reset [parameters]
+ iwpriv ethX fwt_cleanup
+ iwpriv ethX fwt_time
+
+MESH Commands:
+
+ The MESH commands are used to configure various features of the mesh
+ routing protocol. The following commands are supported:
+
+ iwpriv ethX mesh_get_ttl
+ iwpriv ethX mesh_set_ttl ttl
+
+DESCRIPTION
+ Those commands are used to send additional commands to the Marvell WLAN
+ card via the Linux device driver.
+
+ The ethX parameter specifies the network device that is to be used to
+ perform this command on. it could be eth0, eth1 etc.
+
+version
+ This is used to get the current version of the driver and the firmware.
+
+scantype
+ This command is used to set the scan type to be used by the driver in
+ the scan command. This setting will not be used while performing a scan
+ for a specific SSID, as it is always done with scan type being active.
+
+ where the sub-commands are: -
+ active -- to set the scan type to active
+ passive -- to set the scan type to passive
+ get -- to get the scan type set in the driver
+
+getSNR
+ This command gets the average and non average value of Signal to Noise
+ Ratio of Beacon and Data.
+
+ where value is:-
+ 0 -- Beacon non-average.
+ 1 -- Beacon average.
+ 2 -- Data non-average.
+ 3 -- Data average.
+
+ If no value is given, all four values are returned in the order mentioned
+ above.
+
+ Note: This command is available only when STA is connected.
+
+getRSSI
+ This command gets the average and non average value os Receive Signal
+ Strength of Beacon and Data.
+
+ where value is:-
+ 0 -- Beacon non-average.
+ 1 -- Beacon average.
+ 2 -- Data non-average.
+ 3 -- Data average.
+
+ Note: This command is available only when STA is connected.
+
+getNF
+ This command gets the average and non average value of Noise Floor of
+ Beacon and Data.
+
+ where value is:-
+ 0 -- Beacon non-average.
+ 1 -- Beacon average.
+ 2 -- Data non-average.
+ 3 -- Data average.
+
+ Note: This command is available only when STA is connected.
+
+setrxant
+ This command is used to set the mode for Rx antenna.
+
+ The options that can be sent are:-
+ 1 -- Antenna 1.
+ 2 -- Antenna 2.
+ 0xFFFF -- Diversity.
+
+ Usage:
+ iwpriv ethX setrxant 0x01: select Antenna 1.
+
+getrxant
+ This command is used to get the mode for Rx antenna.
+
+
+settxant
+ This command is used to set the mode for Tx antenna.
+ The options that can be sent are:-
+ 1 -- Antenna 1.
+ 2 -- Antenna 2.
+ 0xFFFF -- Diversity.
+ Usage:
+ iwpriv ethX settxant 0x01: select Antenna 1.
+
+gettxant
+ This command is used to get the mode for Tx antenna.
+
+authalgs
+ This command is used by the WPA supplicant to set the authentication
+ algorithms in the station.
+
+8021xauthalgs
+ This command is used by the WPA supplicant to set the 8021.x authentication algorithm type
+ station.
+
+ where values can be:-
+ 1 -- None
+ 2 -- LEAP
+ 4 -- TLS
+ 8 -- TTLs
+ 16 -- MD5
+
+
+encryptionmode
+ This command is used by the WPA supplicant to set the encryption algorithm.
+
+ where values can be:-
+ 0 -- NONE
+ 1 -- WEP40
+ 2 -- TKIP
+ 3 -- CCMP
+ 4 -- WEP104
+
+pre-TBTT
+ This command is used to set pre-TBTT time period where value is in microseconds.
+
+setregioncode
+ This command is used to set the region code in the station.
+ where value is 'region code' for various regions like
+ USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ...
+
+ Usage:
+ iwpriv ethX setregioncode 0x10: set region code to USA (0x10).
+
+getregioncode
+ This command is used to get the region code information set in the
+ station.
+
+setbcnavg
+ Set the weighting factor for calculating RSSI.
+
+getbcnavg
+ Get weighting factor for calculating RSSI.
+
+setdataavg
+ Set the weighting factor for calculating SNR.
+
+setlisteninter
+ This command is used to set the listen interval in the
+ station.
+
+ where the value ranges between 1 - 255
+
+getlisteninter
+ This command is used to get the listen interval value set in the
+ station.
+
+setmultipledtim
+ This command is used to set the multiple dtim value in the
+ station.
+ where the value is 1,2,3,4,5,0xfffe
+ 0xfffe means the firmware will use listen interval in association
+ command for waking up
+
+getmultipledtim
+ This command is used to get the multiple dtim value set in the station.
+
+atimwindow
+ This command is used to set the atim value in the
+ station.
+
+ where the value ranges between 0 - 50
+
+deauth
+ This command is used to send the de-authentication to the AP with which
+ the station is associated. This command is valid only when
+ station is in Infrastructure mode.
+
+ Note: This command is available only when STA is connected.
+
+adhocstop
+ This command is used to stop beacon transmission from the station and
+ go into idle state in ad-hoc mode.
+
+ Note: This command is available only when STA is connected.
+
+radioon
+ This command is used to turn on the RF antenna.
+
+radiooff
+ This command is sued to turn off the RF antenna.
+
+scanmode
+ This command is used to set the station to scan for either IBSS
+ networks or BSS networks or both BSS and IBSS networks. This
+ command can be used with sub commands,
+
+ where the value for
+ bss -- Scan All the BSS networks.
+ ibss -- Scan All the IBSS networks.
+ any -- Scan both BSS and IBSS networks.
+
+
+
+setwpaie
+ This command is used by WPA supplicant to send the WPA-IE to the driver.
+
+wlanidle-off
+ This command is used to get into idle state.
+
+ Note: This command is available only when STA is connected.
+
+wlanidle-on
+ This command is used to get off the idle state.
+
+ Note: This command is available only when STA is connected.
+
+
+getlog
+ This command is used to get the 802.11 statistics available in the
+ station.
+
+ Note: This command is available only when STA is connected.
+
+getadhocstatus
+ This command is used to get the ad-hoc Network Status.
+
+ The various status codes are:
+ AdhocStarted
+ AdhocJoined
+ AdhocIdle
+ InfraMode
+ AutoUnknownMode
+
+ Note: This command is available only when STA is connected.
+
+adhocgrate
+ This command is used to enable(1) g_rate, Disable(0) g_rate
+ and request(2) the status which g_rate is disabled/enabled,
+ for Ad-hoc creator.
+
+ where value is:-
+ 0 -- Disabled
+ 1 -- Enabled
+ 2 -- Get
+
+ledgpio
+ This command is used to set/get LEDs.
+
+ iwpriv ethX ledgpio <LEDs>
+ will set the corresponding LED for the GPIO Line.
+
+ iwpriv ethX ledgpio
+ will give u which LEDs are Enabled.
+
+ Usage:
+ iwpriv eth1 ledgpio 1 0 2 1 3 4
+ will enable
+ LED 1 -> GPIO 0
+ LED 2 -> GPIO 1
+ LED 3 -> GPIO 4
+
+ iwpriv eth1 ledgpio
+ shows LED information in the format as mentioned above.
+
+ Note: LED0 is invalid
+ Note: Maximum Number of LEDs are 16.
+
+inactivityto
+ This command is used by the host to set/get the inactivity timeout value,
+ which specifies when WLAN device is put to sleep.
+
+ Usage:
+ iwpriv ethX inactivityto [<timeout>]
+
+ where the parameter are:
+ timeout: timeout value in milliseconds.
+
+ Example:
+ iwpriv eth1 inactivityto
+ "get the timeout value"
+
+ iwpriv eth1 inactivityto X
+ "set timeout value to X ms"
+
+
+sleeppd
+ This command is used to configure the sleep period of the WLAN device.
+
+ Usage:
+ iwpriv ethX sleeppd [<sleep period>]
+
+ where the parameter are:
+ Period: sleep period in milliseconds. Range 10~60.
+
+ Example:
+ iwpriv eth1 sleeppd 10
+ "set period as 10 ms"
+ iwpriv eth1 sleeppd
+ "get the sleep period configuration"
+
+enable11d
+ This command is used to control 11d
+ where value is:-
+ 1 -- Enabled
+ 0 -- Disabled
+ 2 -- Get
+
+
+
+
+tpccfg
+ Enables or disables automatic transmit power control.
+
+ The first parameter turns this feature on (1) or off (0). When turning
+ on, the user must also supply four more parameters in the following
+ order:
+ -UseSNR (Use SNR (in addition to PER) for TPC algorithm),
+ -P0 (P0 power level for TPC),
+ -P1 (P1 power level for TPC),
+ -P2 (P2 power level for TPC).
+
+ Usage:
+ iwpriv ethX tpccfg: Get current configuration
+ iwpriv ethX tpccfg 0: disable auto TPC
+ iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR;
+ P0=0x05; P1=0x0a; P2=0x0d;
+ iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR;
+ P0=0x05; P1=0x0a; P2=0x0d.
+
+powercfg
+ Enables or disables power adaptation.
+
+ The first parameter turns this feature on (1) or off (0). When turning
+ on, the user must also supply three more parameters in the following
+ order:
+ -P0 (P0 power level for Power Adaptation),
+ -P1 (P1 power level for Power Adaptation),
+ -P2 (P2 power level for Power Adaptation).
+
+ Usage:
+ iwpriv ethX powercfg: Get current configuration
+ iwpriv ethX powercfg 0: disable power adaptation
+ iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation;
+ P0=0x0d; P1=0x0f; P2=0x12.
+
+getafc
+ This command returns automatic frequency control parameters. It returns
+ three integers:
+ -P0: automatic is on (1), or off (0),
+ -P1: current timing offset in PPM (part per million), and
+ -P2: current frequency offset in PPM.
+
+setafc
+ Set automatic frequency control options.
+
+ The first parameter turns automatic on (1) or off (0).
+ The user must supply two more parameters in either case, in the following
+ order:
+
+ When auto is on:
+
+ -P0 (automatic adjustment frequency threshold in PPM),
+ -P1 (automatic adjustment period in beacon period),
+
+ When auto is off:
+
+ -P0 (manual adjustment timing offset in PPM), and
+ -P1 (manual adjustment frequency offset in PPM).
+
+ Usage:
+ iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy
+ offset are 10 PPM.
+
+ iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment,
+ frequency threshold 10 PPM, for every 10 beacon periods.
+
+
+
+scanprobes
+ This command sets number of probe requests per channel.
+
+ Usage:
+ iwpriv ethX scanprobes 3 (set scan probes to 3)
+ iwpriv ethX scanprobes (get scan probes)
+
+lolisteninter
+ This command sets the value of listen interval.
+
+ Usage:
+ iwpriv ethX lolisteninter 234 (set the lolisteninter to 234)
+ iwpriv ethX lolisteninter (get the lolisteninter value)
+
+rateadapt
+ This command sets the data rates bitmap.
+ Where <n>
+ 0: Disable auto rate adapt
+ 1: Enable auto rate adapt
+
+ <m>
+ data rate bitmap
+ Bit Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 Reserved
+ 5 6 Mbps
+ 6 9 Mbps
+ 7 12 Mbps
+ 8 18 Mbps
+ 9 24 Mbps
+ 10 36 Mbps
+ 11 48 Mbps
+ 12 54 Mbps
+ 12-15 Reserved
+
+ Usage:
+ iwpriv ethX rateadapt
+ read the currect data rate setting
+ iwpriv ethX rateadapt 1 0x07
+ enable auto data rate adapt and
+ data rates are 1Mbps, 2Mbsp and 5.5Mbps
+
+
+txcontrol
+ This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis.
+
+ Where value <n> is:
+ if bit[4] == 1:
+ bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16
+ Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv
+
+ bit[12:8]
+ if bit[12] == 1, bit[11:8] specifies the Tx retry limit.
+
+ bit[14:13] specifies per packet ack policy:
+ bit[14:13]
+ 1 0 use immediate ack policy for this packet
+ 1 1 use no ack policy for this packet
+ 0 x use the per-packet ack policy setting
+
+ Usage:
+ iwpriv ethX txcontrol 0x7513
+ Use no-ack policy, 5 retires for Tx, 11Mbps rate
+
+
+
+psnullinterval
+ This command is used to set/request NULL package interval for Power Save
+ under infrastructure mode.
+
+ where value is:-
+ -1 -- Disabled
+ n>0 -- Set interval as n (seconds)
+
+prescan
+ This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap
+
+ where value is:-
+ 0 -- Disabled
+ 1 -- Enabled
+ 2 -- Get
+
+getrxinfo
+ This command gets non average value of Signal to Noise Ratio of Data and rate index.
+
+ The following table shows RateIndex and Rate
+
+ RateIndex Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 Reserved
+ 5 6 Mbps
+ 6 9 Mbps
+ 7 12 Mbps
+ 8 18 Mbps
+ 9 24 Mbps
+ 10 36 Mbps
+ 11 48 Mbps
+ 12 54 Mbps
+ 13-15 Reserved
+
+gettxrate
+ This command gets current Tx rate index of the first packet associated with Rate Adaptation.
+
+ The following table shows RateIndex and Rate
+
+ RateIndex Data rate
+ 0 1 Mbps
+ 1 2 Mbps
+ 2 5.5 Mbps
+ 3 11 Mbps
+ 4 Reserved
+ 5 6 Mbps
+ 6 9 Mbps
+ 7 12 Mbps
+ 8 18 Mbps
+ 9 24 Mbps
+ 10 36 Mbps
+ 11 48 Mbps
+ 12 54 Mbps
+ 13-15 Reserved
+
+bcninterval
+ This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc
+ beacon interval when no argument is given. The valid beacon interval is between 20 - 1000,
+ default beacon interval is 100.
+
+ Usage:
+ iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100)
+ iwpriv ethX bcninterval (get adhoc beacon interval)
+
+fwt_add
+ This command is used to insert an entry into the FWT table. The list of
+ parameters must follow the following structure:
+
+ iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr]
+
+ The parameters between brackets are optional, but they must appear in
+ the order specified. For example, if you want to specify the metric,
+ you must also specify the dir, ssn, and dsn but you need not specify the
+ hopcount, expiration, sleepmode, or snr. Any unspecified parameters
+ will be assigned the defaults specified below.
+
+ The different parameters are:-
+ da -- DA MAC address in the form 00:11:22:33:44:55
+ ra -- RA MAC address in the form 00:11:22:33:44:55
+ metric -- route metric (cost: smaller-metric routes are
+ preferred, default is 0)
+ dir -- direction (1 for direct, 0 for reverse,
+ default is 1)
+ ssn -- Source Sequence Number (time at the RA for
+ reverse routes. Default is 0)
+ dsn -- Destination Sequence Number (time at the DA
+ for direct routes. Default is 0)
+ hopcount -- hop count (currently unused, default is 0)
+ ttl -- TTL (Only used in reverse entries)
+ expiration -- entry expiration (in ticks, where a tick is
+ 1024us, or ~ 1ms. Use 0 for an indefinite
+ entry, default is 0)
+ sleepmode -- RA's sleep mode (currently unused, default is
+ 0)
+ snr -- SNR in the link to RA (currently unused,
+ default is 0)
+
+ The command does not return anything.
+
+fwt_del
+ This command is used to remove an entry to the FWT table. The list of
+ parameters must follow the following structure:
+
+ iwpriv ethX fwt_del da ra [dir]
+
+ where the different parameters are:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+ ra -- RA MAC address (in the form "00:11:22:33:44:55")
+ dir -- direction (1 for direct, 0 for reverse,
+ default is 1)
+
+ The command does not return anything.
+
+fwt_lookup
+ This command is used to get the best route in the FWT table to a given
+ host. The only parameter is the MAC address of the host that is being
+ looked for.
+
+ iwpriv ethX fwt_lookup da
+
+ where:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+
+ The command returns an output string identical to the one returned by
+ fwt_list described below.
+
+
+fwt_list
+ This command is used to list a route from the FWT table. The only
+ parameter is the index into the table. If you want to list all the
+ routes in a table, start with index=0, and keep listing until you get a
+ "(null)" string. Note that the indicies may change as the fwt is
+ updated. It is expected that most users will not use fwt_list directly,
+ but that a utility similar to the traditional route command will be used
+ to invoke fwt_list over and over.
+
+ iwpriv ethX fwt_list index
+
+ The output is a string of the following form:
+
+ da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr
+
+ where the different fields are:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+ ra -- RA MAC address (in the form "00:11:22:33:44:55")
+ metric -- route metric (cost: smaller-metric routes are preferred)
+ dir -- direction (1 for direct, 0 for reverse)
+ ssn -- Source Sequence Number (time at the RA for reverse routes)
+ dsn -- Destination Sequence Number (time at the DA for direct routes)
+ hopcount -- hop count (currently unused)
+ ttl -- TTL (only used in reverse entries)
+ expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+ sleepmode -- RA's sleep mode (currently unused)
+ snr -- SNR in the link to RA (currently unused)
+
+fwt_list_route
+ This command is used to list a route from the FWT table. The only
+ parameter is the route ID. If you want to list all the routes in a
+ table, start with rid=0, and keep incrementing rid until you get a
+ "(null)" string. This function is similar to fwt_list. The only
+ difference is the output format. Also note that this command is meant
+ for debugging. It is expected that users will use fwt_lookup and
+ fwt_list. One important reason for this is that the route id may change
+ as the route table is altered.
+
+ iwpriv ethX fwt_list_route rid
+
+ The output is a string of the following form:
+
+ da metric dir nid ssn dsn hopcount ttl expiration
+
+ where the different fields are:-
+ da -- DA MAC address (in the form "00:11:22:33:44:55")
+ metric -- route metric (cost: smaller-metric routes are preferred)
+ dir -- direction (1 for direct, 0 for reverse)
+ nid -- Next-hop (neighbor) host ID (nid)
+ ssn -- Source Sequence Number (time at the RA for reverse routes)
+ dsn -- Destination Sequence Number (time at the DA for direct routes)
+ hopcount -- hop count (currently unused)
+ ttl -- TTL count (only used in reverse entries)
+ expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry)
+
+fwt_list_neigh
+ This command is used to list a neighbor from the FWT table. The only
+ parameter is the neighbor ID. If you want to list all the neighbors in a
+ table, start with nid=0, and keep incrementing nid until you get a
+ "(null)" string. Note that the nid from a fwt_list_route command can be
+ used as an input to this command. Also note that this command is meant
+ mostly for debugging. It is expected that users will use fwt_lookup.
+ One important reason for this is that the neighbor id may change as the
+ neighbor table is altered.
+
+ iwpriv ethX fwt_list_neigh nid
+
+ The output is a string of the following form:
+
+ ra sleepmode snr references
+
+ where the different fields are:-
+ ra -- RA MAC address (in the form "00:11:22:33:44:55")
+ sleepmode -- RA's sleep mode (currently unused)
+ snr -- SNR in the link to RA (currently unused)
+ references -- RA's reference counter
+
+fwt_reset
+ This command is used to reset the FWT table, getting rid of all the
+ entries. There are no input parameters.
+
+ iwpriv ethX fwt_reset
+
+ The command does not return anything.
+
+fwt_cleanup
+ This command is used to perform user-based garbage recollection. The
+ FWT table is checked, and all the entries that are expired or invalid
+ are cleaned. Note that this is exported to the driver for debugging
+ purposes, as garbage collection is also fired by the firmware when in
+ space problems. There are no input parameters.
+
+ iwpriv ethX fwt_cleanup
+
+ The command does returns the number of invalid/expired routes deleted.
+
+fwt_time
+ This command returns a card's internal time representation. It is this
+ time that is used to represent the expiration times of FWT entries. The
+ number is not consistent from card to card; it is simply a timer count.
+ The fwt_time command is used to inspect the timer so that expiration
+ times reported by fwt_list can be properly interpreted.
+
+ iwpriv ethX fwt_time
+
+mesh_get_ttl
+
+ The mesh ttl is the number of hops a mesh packet can traverse before it
+ is dropped. This parameter is used to prevent infinite loops in the
+ mesh network. The value returned by this function is the ttl assigned
+ to all mesh packets. Currently there is no way to control the ttl on a
+ per packet or per socket basis.
+
+ iwpriv ethX mesh_get_ttl
+
+mesh_set_ttl ttl
+
+ Set the ttl. The argument must be between 0 and 255.
+
+ iwpriv ethX mesh_set_ttl <ttl>
+
+=========================
+ETHTOOL
+=========================
+
+
+Use the -i option to retrieve version information from the driver.
+
+# ethtool -i eth0
+driver: libertas
+version: COMM-USB8388-318.p4
+firmware-version: 5.110.7
+bus-info:
+
+Use the -e option to read the EEPROM contents of the card.
+
+ Usage:
+ ethtool -e ethX [raw on|off] [offset N] [length N]
+
+ -e retrieves and prints an EEPROM dump for the specified ethernet
+ device. When raw is enabled, then it dumps the raw EEPROM data
+ to stdout. The length and offset parameters allow dumping cer-
+ tain portions of the EEPROM. Default is to dump the entire EEP-
+ ROM.
+
+# ethtool -e eth0 offset 0 length 16
+Offset Values
+------ ------
+0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00
+
+========================
+DEBUGFS COMMANDS
+========================
+
+those commands are used via debugfs interface
+
+===========
+rdmac
+rdbbp
+rdrf
+ These commands are used to read the MAC, BBP and RF registers from the
+ card. These commands take one parameter that specifies the offset
+ location that is to be read. This parameter must be specified in
+ hexadecimal (its possible to preceed preceding the number with a "0x").
+
+ Path: /debugfs/libertas_wireless/ethX/registers/
+
+ Usage:
+ echo "0xa123" > rdmac ; cat rdmac
+ echo "0xa123" > rdbbp ; cat rdbbp
+ echo "0xa123" > rdrf ; cat rdrf
+wrmac
+wrbbp
+wrrf
+ These commands are used to write the MAC, BBP and RF registers in the
+ card. These commands take two parameters that specify the offset
+ location and the value that is to be written. This parameters must
+ be specified in hexadecimal (its possible to preceed the number
+ with a "0x").
+
+ Usage:
+ echo "0xa123 0xaa" > wrmac
+ echo "0xa123 0xaa" > wrbbp
+ echo "0xa123 0xaa" > wrrf
+
+sleepparams
+ This command is used to set the sleepclock configurations
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage:
+ cat sleepparams: reads the current sleepclock configuration
+
+ echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration.
+
+ where:
+ p1 is Sleep clock error in ppm (0-65535)
+ p2 is Wakeup offset in usec (0-65535)
+ p3 is Clock stabilization time in usec (0-65535)
+ p4 is Control periodic calibration (0-2)
+ p5 is Control the use of external sleep clock (0-2)
+ p6 is reserved for debug (0-65535)
+
+subscribed_events
+
+ The subscribed_events directory contains the interface for the
+ subscribed events API.
+
+ Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+
+ Each event is represented by a filename. Each filename consists of the
+ following three fields:
+ Value Frequency Subscribed
+
+ To read the current values for a given event, do:
+ cat event
+ To set the current values, do:
+ echo "60 2 1" > event
+
+ Frequency field specifies the reporting frequency for this event.
+ If it is set to 0, then the event is reported only once, and then
+ automatically unsubscribed. If it is set to 1, then the event is
+ reported every time it occurs. If it is set to N, then the event is
+ reported every Nth time it occurs.
+
+ beacon_missed
+ Value field specifies the number of consecutive missing beacons which
+ triggers the LINK_LOSS event. This event is generated only once after
+ which the firmware resets its state. At initialization, the LINK_LOSS
+ event is subscribed by default. The default value of MissedBeacons is
+ 60.
+
+ failure_count
+ Value field specifies the consecutive failure count threshold which
+ triggers the generation of the MAX_FAIL event. Once this event is
+ generated, the consecutive failure count is reset to 0.
+ At initialization, the MAX_FAIL event is NOT subscribed by
+ default.
+
+ high_rssi
+ This event is generated when the average received RSSI in beacons goes
+ above a threshold, specified by Value.
+
+ low_rssi
+ This event is generated when the average received RSSI in beacons goes
+ below a threshold, specified by Value.
+
+ high_snr
+ This event is generated when the average received SNR in beacons goes
+ above a threshold, specified by Value.
+
+ low_snr
+ This event is generated when the average received SNR in beacons goes
+ below a threshold, specified by Value.
+
+extscan
+ This command is used to do a specific scan.
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage: echo "SSID" > extscan
+
+ Example:
+ echo "LINKSYS-AP" > extscan
+
+ To see the results of use getscantable command.
+
+getscantable
+
+ Display the current contents of the driver scan table (ie. get the
+ scan results).
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage:
+ cat getscantable
+
+setuserscan
+ Initiate a customized scan and retrieve the results
+
+
+ Path: /debugfs/libertas_wireless/ethX/
+
+ Usage:
+ echo "[ARGS]" > setuserscan
+
+ where [ARGS]:
+
+ chan=[chan#][band][mode] where band is [a,b,g] and mode is
+ blank for active or 'p' for passive
+ bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan
+ ssid="[SSID]" specify a SSID filter for the scan
+ keep=[0 or 1] keep the previous scan results (1), discard (0)
+ dur=[scan time] time to scan for each channel in milliseconds
+ probes=[#] number of probe requests to send on each chan
+ type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any)
+
+ Any combination of the above arguments can be supplied on the command line.
+ If the chan token is absent, a full channel scan will be completed by
+ the driver. If the dur or probes tokens are absent, the driver default
+ setting will be used. The bssid and ssid fields, if blank,
+ will produce an unfiltered scan. The type field will default to 3 (Any)
+ and the keep field will default to 0 (Discard).
+
+ Examples:
+ 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band:
+ echo "chan=1g,6g,11g" > setuserscan
+
+ 2) Perform a passive scan on channel 11 for 20 ms:
+ echo "chan=11gp dur=20" > setuserscan
+
+ 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on
+ channel 36 in the 'a' band:
+
+ echo "chan=1g,6g,11g,36ap" > setuserscan
+
+ 4) Perform an active scan on channel 6 and 36 for a specific SSID:
+ echo "chan=6g,36a ssid="TestAP"" > setuserscan
+
+ 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep
+ the current scan table intact, update existing or append new scan data:
+ echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan
+
+ 6) Scan channel 6, for all infrastructure networks, sending two probe
+ requests. Keep the previous scan table intact. Update any duplicate
+ BSSID/SSID matches with the new scan data:
+ echo "chan=6g type=1 probes=2 keep=1" > setuserscan
+
+ All entries in the scan table (not just the new scan data when keep=1)
+ will be displayed upon completion by use of the getscantable ioctl.
+
+==============================================================================
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
new file mode 100644
index 00000000000..b55c7f57aca
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -0,0 +1,588 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#include <linux/bitops.h>
+#include <net/ieee80211.h>
+
+#include "assoc.h"
+#include "join.h"
+#include "decl.h"
+#include "hostcmd.h"
+#include "host.h"
+
+
+static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+static int assoc_helper_essid(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ int i;
+
+ ENTER();
+
+ lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid);
+ if (assoc_req->mode == wlan802_11infrastructure) {
+ if (adapter->prescan) {
+ libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1);
+ }
+
+ i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid,
+ NULL, wlan802_11infrastructure);
+ if (i >= 0) {
+ lbs_pr_debug(1,
+ "SSID found in scan list ... associating...\n");
+
+ ret = wlan_associate(priv, &adapter->scantable[i]);
+ if (ret == 0) {
+ memcpy(&assoc_req->bssid,
+ &adapter->scantable[i].macaddress,
+ ETH_ALEN);
+ }
+ } else {
+ lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n",
+ assoc_req->ssid.ssid);
+ }
+ } else if (assoc_req->mode == wlan802_11ibss) {
+ /* Scan for the network, do not save previous results. Stale
+ * scan data will cause us to join a non-existant adhoc network
+ */
+ libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0);
+
+ /* Search for the requested SSID in the scan table */
+ i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL,
+ wlan802_11ibss);
+ if (i >= 0) {
+ lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret);
+ libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+ } else {
+ /* else send START command */
+ lbs_pr_debug(1, "SSID not found in list, so creating adhoc"
+ " with SSID '%s'\n", assoc_req->ssid.ssid);
+ libertas_start_adhoc_network(priv, &assoc_req->ssid);
+ }
+ memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_bssid(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i, ret = 0;
+
+ ENTER();
+
+ lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n",
+ MAC_ARG(assoc_req->bssid));
+
+ /* Search for index position in list for requested MAC */
+ i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid,
+ assoc_req->mode);
+ if (i < 0) {
+ lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, "
+ "cannot associate.\n", MAC_ARG(assoc_req->bssid));
+ goto out;
+ }
+
+ if (assoc_req->mode == wlan802_11infrastructure) {
+ ret = wlan_associate(priv, &adapter->scantable[i]);
+ lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret);
+ } else if (assoc_req->mode == wlan802_11ibss) {
+ libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+ }
+ memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid,
+ sizeof(struct WLAN_802_11_SSID));
+
+out:
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_associate(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ int ret = 0, done = 0;
+
+ /* If we're given and 'any' BSSID, try associating based on SSID */
+
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN)
+ && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) {
+ ret = assoc_helper_bssid(priv, assoc_req);
+ done = 1;
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+ }
+ }
+ }
+
+ if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ ret = assoc_helper_essid(priv, assoc_req);
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret);
+ }
+ }
+
+ return ret;
+}
+
+
+static int assoc_helper_mode(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ if (assoc_req->mode == adapter->inframode) {
+ LEAVE();
+ return 0;
+ }
+
+ if (assoc_req->mode == wlan802_11infrastructure) {
+ if (adapter->psstate != PS_STATE_FULL_POWER)
+ libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ adapter->psmode = wlan802_11powermodecam;
+ }
+
+ adapter->inframode = assoc_req->mode;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ 0, cmd_option_waitforrsp,
+ OID_802_11_INFRASTRUCTURE_MODE,
+ (void *) assoc_req->mode);
+
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_wep_keys(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+ int ret = 0;
+
+ ENTER();
+
+ /* Set or remove WEP keys */
+ if ( assoc_req->wep_keys[0].len
+ || assoc_req->wep_keys[1].len
+ || assoc_req->wep_keys[2].len
+ || assoc_req->wep_keys[3].len) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_wep,
+ cmd_act_add,
+ cmd_option_waitforrsp,
+ 0, assoc_req);
+ } else {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_wep,
+ cmd_act_remove,
+ cmd_option_waitforrsp,
+ 0, NULL);
+ }
+
+ if (ret)
+ goto out;
+
+ /* enable/disable the MAC's WEP packet filter */
+ if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled)
+ adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+ else
+ adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+ ret = libertas_set_mac_packet_filter(priv);
+ if (ret)
+ goto out;
+
+ mutex_lock(&adapter->lock);
+
+ /* Copy WEP keys into adapter wep key fields */
+ for (i = 0; i < 4; i++) {
+ memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
+ sizeof(struct WLAN_802_11_KEY));
+ }
+ adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
+
+ mutex_unlock(&adapter->lock);
+
+out:
+ LEAVE();
+ return ret;
+}
+
+static int assoc_helper_secinfo(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ memcpy(&adapter->secinfo, &assoc_req->secinfo,
+ sizeof(struct wlan_802_11_security));
+
+ ret = libertas_set_mac_packet_filter(priv);
+
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_wpa_keys(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ int ret = 0;
+
+ ENTER();
+
+ /* enable/Disable RSN */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_enable_rsn,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ 0, assoc_req);
+ if (ret)
+ goto out;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_key_material,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ 0, assoc_req);
+
+out:
+ LEAVE();
+ return ret;
+}
+
+
+static int assoc_helper_wpa_ie(wlan_private *priv,
+ struct assoc_request * assoc_req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
+ memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len);
+ adapter->wpa_ie_len = assoc_req->wpa_ie_len;
+ } else {
+ memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN);
+ adapter->wpa_ie_len = 0;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+
+static int should_deauth_infrastructure(wlan_adapter *adapter,
+ struct assoc_request * assoc_req)
+{
+ if (adapter->connect_status != libertas_connected)
+ return 0;
+
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ lbs_pr_debug(1, "Deauthenticating due to new SSID in "
+ " configuration request.\n");
+ return 1;
+ }
+
+ if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ if (adapter->secinfo.authmode !=
+ assoc_req->secinfo.authmode) {
+ lbs_pr_debug(1, "Deauthenticating due to updated security "
+ "info in configuration request.\n");
+ return 1;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ lbs_pr_debug(1, "Deauthenticating due to new BSSID in "
+ " configuration request.\n");
+ return 1;
+ }
+
+ /* FIXME: deal with 'auto' mode somehow */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ if (assoc_req->mode != wlan802_11infrastructure)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int should_stop_adhoc(wlan_adapter *adapter,
+ struct assoc_request * assoc_req)
+{
+ if (adapter->connect_status != libertas_connected)
+ return 0;
+
+ if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength)
+ return 1;
+ if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid,
+ sizeof(struct WLAN_802_11_SSID)))
+ return 1;
+
+ /* FIXME: deal with 'auto' mode somehow */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ if (assoc_req->mode != wlan802_11ibss)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void wlan_association_worker(struct work_struct *work)
+{
+ wlan_private *priv = container_of(work, wlan_private, assoc_work.work);
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req = NULL;
+ int ret = 0;
+ int find_any_ssid = 0;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = adapter->assoc_req;
+ adapter->assoc_req = NULL;
+ mutex_unlock(&adapter->lock);
+
+ if (!assoc_req) {
+ LEAVE();
+ return;
+ }
+
+ lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n",
+ assoc_req->flags);
+
+ /* If 'any' SSID was specified, find an SSID to associate with */
+ if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)
+ && !assoc_req->ssid.ssidlength)
+ find_any_ssid = 1;
+
+ /* But don't use 'any' SSID if there's a valid locked BSSID to use */
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN)
+ && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN))
+ find_any_ssid = 0;
+ }
+
+ if (find_any_ssid) {
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+ ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid,
+ assoc_req->mode, &new_mode);
+ if (ret) {
+ lbs_pr_debug(1, "Could not find best network\n");
+ ret = -ENETUNREACH;
+ goto out;
+ }
+
+ /* Ensure we switch to the mode of the AP */
+ if (assoc_req->mode == wlan802_11autounknown) {
+ set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+ assoc_req->mode = new_mode;
+ }
+ }
+
+ /*
+ * Check if the attributes being changing require deauthentication
+ * from the currently associated infrastructure access point.
+ */
+ if (adapter->inframode == wlan802_11infrastructure) {
+ if (should_deauth_infrastructure(adapter, assoc_req)) {
+ ret = libertas_send_deauthentication(priv);
+ if (ret) {
+ lbs_pr_debug(1, "Deauthentication due to new "
+ "configuration request failed: %d\n",
+ ret);
+ }
+ }
+ } else if (adapter->inframode == wlan802_11ibss) {
+ if (should_stop_adhoc(adapter, assoc_req)) {
+ ret = libertas_stop_adhoc_network(priv);
+ if (ret) {
+ lbs_pr_debug(1, "Teardown of AdHoc network due to "
+ "new configuration request failed: %d\n",
+ ret);
+ }
+
+ }
+ }
+
+ /* Send the various configuration bits to the firmware */
+ if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
+ ret = assoc_helper_mode(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
+ ret = assoc_helper_wep_keys(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ ret = assoc_helper_secinfo(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+ ret = assoc_helper_wpa_ie(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ ret = assoc_helper_wpa_keys(priv, assoc_req);
+ if (ret) {
+lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+ goto out;
+ }
+ }
+
+ /* SSID/BSSID should be the _last_ config option set, because they
+ * trigger the association attempt.
+ */
+ if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)
+ || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ int success = 1;
+
+ ret = assoc_helper_associate(priv, assoc_req);
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n",
+ ret);
+ success = 0;
+ }
+
+ if (adapter->connect_status != libertas_connected) {
+ lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, "
+ "not connected.\n");
+ success = 0;
+ }
+
+ if (success) {
+ lbs_pr_debug(1, "ASSOC: association attempt successful. "
+ "Associated to '%s' (" MAC_FMT ")\n",
+ assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid));
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0, cmd_option_waitforrsp, 0, NULL);
+
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_get_log,
+ 0, cmd_option_waitforrsp, 0, NULL);
+ } else {
+
+ ret = -1;
+ }
+ }
+
+out:
+ if (ret) {
+ lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n",
+ ret);
+ }
+ kfree(assoc_req);
+ LEAVE();
+}
+
+
+/*
+ * Caller MUST hold any necessary locks
+ */
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter)
+{
+ struct assoc_request * assoc_req;
+
+ if (!adapter->assoc_req) {
+ adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL);
+ if (!adapter->assoc_req) {
+ lbs_pr_info("Not enough memory to allocate association"
+ " request!\n");
+ return NULL;
+ }
+ }
+
+ /* Copy current configuration attributes to the association request,
+ * but don't overwrite any that are already set.
+ */
+ assoc_req = adapter->assoc_req;
+ if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
+ memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid,
+ adapter->curbssparams.ssid.ssidlength);
+ }
+
+ if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags))
+ assoc_req->channel = adapter->curbssparams.channel;
+
+ if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags))
+ assoc_req->mode = adapter->inframode;
+
+ if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) {
+ memcpy(&assoc_req->bssid, adapter->curbssparams.bssid,
+ ETH_ALEN);
+ }
+
+ if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) {
+ int i;
+ for (i = 0; i < 4; i++) {
+ memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
+ sizeof(struct WLAN_802_11_KEY));
+ }
+ }
+
+ if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags))
+ assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx;
+
+ if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+ memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
+ sizeof(struct WLAN_802_11_KEY));
+ }
+
+ if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+ memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
+ sizeof(struct WLAN_802_11_KEY));
+ }
+
+ if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
+ memcpy(&assoc_req->secinfo, &adapter->secinfo,
+ sizeof(struct wlan_802_11_security));
+ }
+
+ if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
+ memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie,
+ MAX_WPA_IE_LEN);
+ assoc_req->wpa_ie_len = adapter->wpa_ie_len;
+ }
+
+ return assoc_req;
+}
+
+
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
new file mode 100644
index 00000000000..2ffd82d99b3
--- /dev/null
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -0,0 +1,30 @@
+/* Copyright (C) 2006, Red Hat, Inc. */
+
+#ifndef _WLAN_ASSOC_H_
+#define _WLAN_ASSOC_H_
+
+#include "dev.h"
+
+void wlan_association_worker(struct work_struct *work);
+
+struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
+
+#define ASSOC_DELAY (HZ / 2)
+static inline void wlan_postpone_association_work(wlan_private *priv)
+{
+ if (priv->adapter->surpriseremoved)
+ return;
+ cancel_delayed_work(&priv->assoc_work);
+ queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+}
+
+static inline void wlan_cancel_association_work(wlan_private *priv)
+{
+ cancel_delayed_work(&priv->assoc_work);
+ if (priv->adapter->assoc_req) {
+ kfree(priv->adapter->assoc_req);
+ priv->adapter->assoc_req = NULL;
+ }
+}
+
+#endif /* _WLAN_ASSOC_H */
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
new file mode 100644
index 00000000000..bfdac58b5c0
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -0,0 +1,1958 @@
+/**
+ * This file contains the handling of command.
+ * It prepares command and sends it to firmware when it is ready.
+ */
+
+#include <net/iw_handler.h>
+#include "host.h"
+#include "hostcmd.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
+
+static u16 commands_allowed_in_ps[] = {
+ cmd_802_11_rssi,
+};
+
+/**
+ * @brief This function checks if the commans is allowed
+ * in PS mode not.
+ *
+ * @param command the command ID
+ * @return TRUE or FALSE
+ */
+static u8 is_command_allowed_in_ps(u16 command)
+{
+ int count = sizeof(commands_allowed_in_ps)
+ / sizeof(commands_allowed_in_ps[0]);
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (command == cpu_to_le16(commands_allowed_in_ps[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd)
+{
+ struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_get_hw_spec);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
+ memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_ps_mode(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
+ u16 action = cmd_action;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
+ S_DS_GEN);
+ psm->action = cpu_to_le16(cmd_action);
+ psm->multipledtim = 0;
+ switch (action) {
+ case cmd_subcmd_enter_ps:
+ lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n");
+ lbs_pr_debug(1, "locallisteninterval = %d\n",
+ adapter->locallisteninterval);
+
+ psm->locallisteninterval =
+ cpu_to_le16(adapter->locallisteninterval);
+ psm->nullpktinterval =
+ cpu_to_le16(adapter->nullpktinterval);
+ psm->multipledtim =
+ cpu_to_le16(priv->adapter->multipledtim);
+ break;
+
+ case cmd_subcmd_exit_ps:
+ lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n");
+ break;
+
+ case cmd_subcmd_sleep_confirmed:
+ lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n");
+ break;
+
+ default:
+ break;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ u16 *timeout = pdata_buf;
+
+ cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
+ + S_DS_GEN);
+
+ cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action)
+ cmd->params.inactivity_timeout.timeout =
+ cpu_to_le16(*timeout);
+ else
+ cmd->params.inactivity_timeout.timeout = 0;
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_sleep_params(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+
+ if (cmd_action == cmd_act_get) {
+ memset(&adapter->sp, 0, sizeof(struct sleep_params));
+ memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
+ sp->action = cpu_to_le16(cmd_action);
+ } else if (cmd_action == cmd_act_set) {
+ sp->action = cpu_to_le16(cmd_action);
+ sp->error = cpu_to_le16(adapter->sp.sp_error);
+ sp->offset = cpu_to_le16(adapter->sp.sp_offset);
+ sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime);
+ sp->calcontrol = (u8) adapter->sp.sp_calcontrol;
+ sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk;
+ sp->reserved = cpu_to_le16(adapter->sp.sp_reserved);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_set_wep(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u32 cmd_act,
+ void * pdata_buf)
+{
+ struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct assoc_request * assoc_req = pdata_buf;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+ cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep))
+ + S_DS_GEN);
+
+ if (cmd_act == cmd_act_add) {
+ int i;
+
+ if (!assoc_req) {
+ lbs_pr_debug(1, "Invalid association request!");
+ ret = -1;
+ goto done;
+ }
+
+ wep->action = cpu_to_le16(cmd_act_add);
+
+ /* default tx key index */
+ wep->keyindex = cpu_to_le16((u16)
+ (assoc_req->wep_tx_keyidx &
+ (u32)cmd_WEP_KEY_INDEX_MASK));
+
+ lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex);
+
+ /* Copy key types and material to host command structure */
+ for (i = 0; i < 4; i++) {
+ struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+
+ switch (pkey->len) {
+ case KEY_LEN_WEP_40:
+ wep->keytype[i] = cmd_type_wep_40_bit;
+ memmove(&wep->keymaterial[i], pkey->key,
+ pkey->len);
+ break;
+ case KEY_LEN_WEP_104:
+ wep->keytype[i] = cmd_type_wep_104_bit;
+ memmove(&wep->keymaterial[i], pkey->key,
+ pkey->len);
+ break;
+ case 0:
+ break;
+ default:
+ lbs_pr_debug(1, "Invalid WEP key %d length of %d\n",
+ i, pkey->len);
+ ret = -1;
+ goto done;
+ break;
+ }
+ }
+ } else if (cmd_act == cmd_act_remove) {
+ /* ACT_REMOVE clears _all_ WEP keys */
+ wep->action = cpu_to_le16(cmd_act_remove);
+
+ /* default tx key index */
+ wep->keyindex = cpu_to_le16((u16)
+ (adapter->wep_tx_keyidx &
+ (u32)cmd_WEP_KEY_INDEX_MASK));
+ }
+
+ ret = 0;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn;
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) +
+ S_DS_GEN);
+ penableRSN->action = cpu_to_le16(cmd_action);
+ if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+ penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+ } else {
+ penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+ }
+
+ return 0;
+}
+
+
+static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
+ struct WLAN_802_11_KEY * pkey)
+{
+ pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+
+ if (pkey->flags & KEY_INFO_WPA_ENABLED) {
+ pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED);
+ } else {
+ pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED);
+ }
+
+ if (pkey->flags & KEY_INFO_WPA_UNICAST) {
+ pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST);
+ } else if (pkey->flags & KEY_INFO_WPA_MCAST) {
+ pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST);
+ }
+
+ pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ pkeyparamset->keylen = cpu_to_le16(pkey->len);
+ memcpy(pkeyparamset->key, pkey->key, pkey->len);
+ pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid)
+ + sizeof(pkeyparamset->keyinfo)
+ + sizeof(pkeyparamset->keylen)
+ + sizeof(pkeyparamset->key));
+}
+
+static int wlan_cmd_802_11_key_material(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action,
+ u32 cmd_oid, void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_key_material *pkeymaterial =
+ &cmd->params.keymaterial;
+ int ret = 0;
+ int index = 0;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_key_material);
+ pkeymaterial->action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == cmd_act_get) {
+ cmd->size = cpu_to_le16( S_DS_GEN
+ + sizeof (pkeymaterial->action));
+ ret = 0;
+ goto done;
+ }
+
+ memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet));
+
+ if (adapter->wpa_unicast_key.len) {
+ set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+ &adapter->wpa_unicast_key);
+ index++;
+ }
+
+ if (adapter->wpa_mcast_key.len) {
+ set_one_wpa_key(&pkeymaterial->keyParamSet[index],
+ &adapter->wpa_mcast_key);
+ index++;
+ }
+
+ cmd->size = cpu_to_le16( S_DS_GEN
+ + sizeof (pkeymaterial->action)
+ + index * sizeof(struct MrvlIEtype_keyParamSet));
+
+ ret = 0;
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_cmd_802_11_reset(wlan_private * priv,
+ struct cmd_ds_command *cmd, int cmd_action)
+{
+ struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
+
+ cmd->command = cpu_to_le16(cmd_802_11_reset);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
+ reset->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_get_log(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(cmd_802_11_get_log);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_get_stat(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) +
+ S_DS_GEN);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_snmp_mib(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action,
+ int cmd_oid, void *pdata_buf)
+{
+ struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib;
+ wlan_adapter *adapter = priv->adapter;
+ u8 ucTemp;
+
+ ENTER();
+
+ lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+
+ cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) +
+ S_DS_GEN);
+
+ switch (cmd_oid) {
+ case OID_802_11_INFRASTRUCTURE_MODE:
+ {
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode =
+ (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf;
+ pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+ pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+ pSNMPMIB->bufsize = sizeof(u8);
+ if (mode == wlan802_11infrastructure)
+ ucTemp = SNMP_MIB_VALUE_INFRA;
+ else
+ ucTemp = SNMP_MIB_VALUE_ADHOC;
+
+ memmove(pSNMPMIB->value, &ucTemp, sizeof(u8));
+
+ break;
+ }
+
+ case OID_802_11D_ENABLE:
+ {
+ u32 ulTemp;
+
+ pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+
+ if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype = cmd_act_set;
+ pSNMPMIB->bufsize = sizeof(u16);
+ ulTemp = *(u32 *)pdata_buf;
+ *((unsigned short *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) ulTemp);
+ }
+ break;
+ }
+
+ case OID_802_11_FRAGMENTATION_THRESHOLD:
+ {
+ u32 ulTemp;
+
+ pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+
+ if (cmd_action == cmd_act_get) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_get);
+ } else if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_set);
+ pSNMPMIB->bufsize =
+ cpu_to_le16(sizeof(u16));
+ ulTemp = *((u32 *) pdata_buf);
+ *((unsigned short *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) ulTemp);
+
+ }
+
+ break;
+ }
+
+ case OID_802_11_RTS_THRESHOLD:
+ {
+
+ u32 ulTemp;
+ pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+
+ if (cmd_action == cmd_act_get) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_get);
+ } else if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_set);
+ pSNMPMIB->bufsize =
+ cpu_to_le16(sizeof(u16));
+ ulTemp = *((u32 *)
+ pdata_buf);
+ *(unsigned short *)(pSNMPMIB->value) =
+ cpu_to_le16((u16) ulTemp);
+
+ }
+ break;
+ }
+ case OID_802_11_TX_RETRYCOUNT:
+ pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+
+ if (cmd_action == cmd_act_get) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_get);
+ } else if (cmd_action == cmd_act_set) {
+ pSNMPMIB->querytype =
+ cpu_to_le16(cmd_act_set);
+ pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
+ *((unsigned short *)(pSNMPMIB->value)) =
+ cpu_to_le16((u16) adapter->txretrycount);
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ lbs_pr_debug(1,
+ "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n",
+ cmd->command, cmd->size, cmd->seqnum, cmd->result);
+
+ lbs_pr_debug(1,
+ "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+ pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize,
+ *(u16 *) pSNMPMIB->value);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_radio_control(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_radio_control *pradiocontrol =
+ &cmd->params.radio;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+
+ pradiocontrol->action = cpu_to_le16(cmd_action);
+
+ switch (adapter->preamble) {
+ case cmd_type_short_preamble:
+ pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
+ break;
+
+ case cmd_type_long_preamble:
+ pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
+ break;
+
+ case cmd_type_auto_preamble:
+ default:
+ pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
+ break;
+ }
+
+ if (adapter->radioon)
+ pradiocontrol->control |= cpu_to_le16(TURN_ON_RF);
+ else
+ pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+
+ struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+ prtp->action = cmd_action;
+
+ lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size,
+ cmd->command, prtp->action);
+
+ switch (cmd_action) {
+ case cmd_act_tx_power_opt_get:
+ prtp->action = cpu_to_le16(cmd_act_get);
+ prtp->currentlevel = 0;
+ break;
+
+ case cmd_act_tx_power_opt_set_high:
+ prtp->action = cpu_to_le16(cmd_act_set);
+ prtp->currentlevel =
+ cpu_to_le16(cmd_act_tx_power_index_high);
+ break;
+
+ case cmd_act_tx_power_opt_set_mid:
+ prtp->action = cpu_to_le16(cmd_act_set);
+ prtp->currentlevel =
+ cpu_to_le16(cmd_act_tx_power_index_mid);
+ break;
+
+ case cmd_act_tx_power_opt_set_low:
+ prtp->action = cpu_to_le16(cmd_act_set);
+ prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
+ break;
+ }
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+
+ cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
+ S_DS_GEN);
+
+ rant->action = cpu_to_le16(cmd_action);
+ if ((cmd_action == cmd_act_set_rx) ||
+ (cmd_action == cmd_act_set_tx)) {
+ rant->antennamode =
+ cpu_to_le16((u16) (*(u32 *) pdata_buf));
+ }
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset
+ *rateadapt = &cmd->params.rateset;
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
+ + S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
+
+ ENTER();
+
+ rateadapt->action = cmd_action;
+ rateadapt->enablehwauto = adapter->enablehwauto;
+ rateadapt->bitmap = adapter->ratebitmap;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_data_rate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = cmd_action;
+
+ ENTER();
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
+ S_DS_GEN);
+
+ cmd->command = cpu_to_le16(cmd_802_11_data_rate);
+
+ memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
+
+ pdatarate->action = cpu_to_le16(cmd_action);
+
+ if (action == cmd_act_set_tx_fix_rate) {
+ pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
+ lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n",
+ adapter->datarate);
+ } else if (action == cmd_act_set_tx_auto) {
+ lbs_pr_debug(1, "Setting FW for AUTO rate\n");
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_mac_multicast_adr(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+
+ pMCastAdr->action = cpu_to_le16(cmd_action);
+ pMCastAdr->nr_of_adrs =
+ cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
+ memcpy(pMCastAdr->maclist, adapter->multicastlist,
+ adapter->nr_of_multicastmacaddr * ETH_ALEN);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_rf_channel(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int option, void *pdata_buf)
+{
+ struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
+
+ cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel)
+ + S_DS_GEN);
+
+ if (option == cmd_opt_802_11_rf_channel_set) {
+ rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
+ }
+
+ rfchan->action = cpu_to_le16(option);
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_rssi(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->command = cpu_to_le16(cmd_802_11_rssi);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
+ cmd->params.rssi.N = priv->adapter->bcn_avg_factor;
+
+ /* reset Beacon SNR/NF/RSSI values */
+ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
+ adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0;
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0;
+ adapter->NF[TYPE_BEACON][TYPE_AVG] = 0;
+ adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
+ adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
+
+ return 0;
+}
+
+static int wlan_cmd_reg_access(wlan_private * priv,
+ struct cmd_ds_command *cmdptr,
+ u8 cmd_action, void *pdata_buf)
+{
+ struct wlan_offset_value *offval;
+
+ ENTER();
+
+ offval = (struct wlan_offset_value *)pdata_buf;
+
+ switch (cmdptr->command) {
+ case cmd_mac_reg_access:
+ {
+ struct cmd_ds_mac_reg_access *macreg;
+
+ cmdptr->size =
+ cpu_to_le16(sizeof
+ (struct cmd_ds_mac_reg_access)
+ + S_DS_GEN);
+ macreg =
+ (struct cmd_ds_mac_reg_access *)&cmdptr->params.
+ macreg;
+
+ macreg->action = cpu_to_le16(cmd_action);
+ macreg->offset = cpu_to_le16((u16) offval->offset);
+ macreg->value = cpu_to_le32(offval->value);
+
+ break;
+ }
+
+ case cmd_bbp_reg_access:
+ {
+ struct cmd_ds_bbp_reg_access *bbpreg;
+
+ cmdptr->size =
+ cpu_to_le16(sizeof
+ (struct cmd_ds_bbp_reg_access)
+ + S_DS_GEN);
+ bbpreg =
+ (struct cmd_ds_bbp_reg_access *)&cmdptr->params.
+ bbpreg;
+
+ bbpreg->action = cpu_to_le16(cmd_action);
+ bbpreg->offset = cpu_to_le16((u16) offval->offset);
+ bbpreg->value = (u8) offval->value;
+
+ break;
+ }
+
+ case cmd_rf_reg_access:
+ {
+ struct cmd_ds_rf_reg_access *rfreg;
+
+ cmdptr->size =
+ cpu_to_le16(sizeof
+ (struct cmd_ds_rf_reg_access) +
+ S_DS_GEN);
+ rfreg =
+ (struct cmd_ds_rf_reg_access *)&cmdptr->params.
+ rfreg;
+
+ rfreg->action = cpu_to_le16(cmd_action);
+ rfreg->offset = cpu_to_le16((u16) offval->offset);
+ rfreg->value = (u8) offval->value;
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_cmd_802_11_mac_address(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.macadd.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == cmd_act_set) {
+ memcpy(cmd->params.macadd.macadd,
+ adapter->current_addr, ETH_ALEN);
+ lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+ }
+
+ return 0;
+}
+
+static int wlan_cmd_802_11_eeprom_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ int cmd_action, void *pdata_buf)
+{
+ struct wlan_ioctl_regrdwr *ea = pdata_buf;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.rdeeprom.action = cpu_to_le16(ea->action);
+ cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset);
+ cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
+ cmd->params.rdeeprom.value = 0;
+
+ return 0;
+}
+
+static int wlan_cmd_bt_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
+ lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action);
+
+ cmd->command = cpu_to_le16(cmd_bt_access);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access)
+ + S_DS_GEN);
+ cmd->result = 0;
+ bt_access->action = cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case cmd_act_bt_access_add:
+ memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
+ lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+ break;
+ case cmd_act_bt_access_del:
+ memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
+ lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+ break;
+ case cmd_act_bt_access_list:
+ bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
+ break;
+ case cmd_act_bt_access_reset:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int wlan_cmd_fwt_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
+ lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+ cmd->command = cpu_to_le16(cmd_fwt_access);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ if (pdata_buf)
+ memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
+ else
+ memset(fwt_access, 0, sizeof(*fwt_access));
+
+ fwt_access->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
+static int wlan_cmd_mesh_access(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ u16 cmd_action, void *pdata_buf)
+{
+ struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
+ lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action);
+
+ cmd->command = cpu_to_le16(cmd_mesh_access);
+ cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access)
+ + S_DS_GEN);
+ cmd->result = 0;
+
+ if (pdata_buf)
+ memcpy(mesh_access, pdata_buf, sizeof(*mesh_access));
+ else
+ memset(mesh_access, 0, sizeof(*mesh_access));
+
+ mesh_access->action = cpu_to_le16(cmd_action);
+
+ return 0;
+}
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail)
+{
+ unsigned long flags;
+ struct cmd_ds_command *cmdptr;
+
+ ENTER();
+
+ if (!cmdnode) {
+ lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n");
+ goto done;
+ }
+
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+ if (!cmdptr) {
+ lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n");
+ goto done;
+ }
+
+ /* Exit_PS command needs to be queued in the header always. */
+ if (cmdptr->command == cmd_802_11_ps_mode) {
+ struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
+ if (psm->action == cmd_subcmd_exit_ps) {
+ if (adapter->psstate != PS_STATE_FULL_POWER)
+ addtail = 0;
+ }
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (addtail)
+ list_add_tail((struct list_head *)cmdnode,
+ &adapter->cmdpendingq);
+ else
+ list_add((struct list_head *)cmdnode, &adapter->cmdpendingq);
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n",
+ (u32) cmdnode,
+ ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command);
+
+done:
+ LEAVE();
+ return;
+}
+
+/*
+ * TODO: Fix the issue when DownloadcommandToStation is being called the
+ * second time when the command timesout. All the cmdptr->xxx are in little
+ * endian and therefore all the comparissions will fail.
+ * For now - we are not performing the endian conversion the second time - but
+ * for PS and DEEP_SLEEP we need to worry
+ */
+static int DownloadcommandToStation(wlan_private * priv,
+ struct cmd_ctrl_node *cmdnode)
+{
+ unsigned long flags;
+ struct cmd_ds_command *cmdptr;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 cmdsize;
+ u16 command;
+
+ ENTER();
+
+ if (!adapter || !cmdnode) {
+ lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n",
+ (int)adapter, (int)cmdnode);
+ if (cmdnode) {
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ }
+ ret = -1;
+ goto done;
+ }
+
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (!cmdptr || !cmdptr->size) {
+ lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, "
+ "Not sending\n");
+ __libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ adapter->cur_cmd = cmdnode;
+ adapter->cur_cmd_retcode = 0;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n",
+ cmdptr->size);
+
+ cmdsize = cmdptr->size;
+
+ command = cpu_to_le16(cmdptr->command);
+
+ cmdnode->cmdwaitqwoken = 0;
+ cmdsize = cpu_to_le16(cmdsize);
+
+ ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
+
+ if (ret != 0) {
+ lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n");
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
+ lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+
+ /* Setup the timer after transmit command */
+ if (command == cmd_802_11_scan
+ || command == cmd_802_11_authenticate
+ || command == cmd_802_11_associate)
+ mod_timer(&adapter->command_timer, jiffies + (10*HZ));
+ else
+ mod_timer(&adapter->command_timer, jiffies + (5*HZ));
+
+ ret = 0;
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_cmd_mac_control(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ struct cmd_ds_mac_control *mac = &cmd->params.macctrl;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_mac_control);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
+ mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
+
+ lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n",
+ mac->action, cmd->size);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * This function inserts command node to cmdfreeq
+ * after cleans it. Requires adapter->driver_lock held.
+ */
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!ptempcmd)
+ goto done;
+
+ cleanup_cmdnode(ptempcmd);
+ list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
+done:
+ return;
+}
+
+void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+ __libertas_cleanup_and_insert_cmd(priv, ptempcmd);
+ spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+int libertas_set_radio_control(wlan_private * priv)
+{
+ int ret = 0;
+
+ ENTER();
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_radio_control,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+
+ lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+ priv->adapter->radioon, priv->adapter->preamble);
+
+ LEAVE();
+ return ret;
+}
+
+int libertas_set_mac_packet_filter(wlan_private * priv)
+{
+ int ret = 0;
+
+ ENTER();
+
+ lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n",
+ priv->adapter->currentpacketfilter);
+
+ /* Send MAC control command to station */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_mac_control, 0, 0, 0, NULL);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function prepare the command before send to firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param cmd_no command number
+ * @param cmd_action command action: GET or SET
+ * @param wait_option wait option: wait response or not
+ * @param cmd_oid cmd oid: treated as sub command
+ * @param pdata_buf A pointer to informaion buffer
+ * @return 0 or -1
+ */
+int libertas_prepare_and_send_command(wlan_private * priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmdnode;
+ struct cmd_ds_command *cmdptr;
+ unsigned long flags;
+
+ ENTER();
+
+ if (!adapter) {
+ lbs_pr_debug(1, "PREP_CMD: adapter is Null\n");
+ ret = -1;
+ goto done;
+ }
+
+ if (adapter->surpriseremoved) {
+ lbs_pr_debug(1, "PREP_CMD: Card is Removed\n");
+ ret = -1;
+ goto done;
+ }
+
+ cmdnode = libertas_get_free_cmd_ctrl_node(priv);
+
+ if (cmdnode == NULL) {
+ lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n");
+
+ /* Wake up main thread to execute next command */
+ wake_up_interruptible(&priv->mainthread.waitq);
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf);
+
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+ lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n",
+ (u32) cmdptr, cmd_no);
+
+ if (!cmdptr) {
+ lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ ret = -1;
+ goto done;
+ }
+
+ /* Set sequence number, command and INT option */
+ adapter->seqnum++;
+ cmdptr->seqnum = cpu_to_le16(adapter->seqnum);
+
+ cmdptr->command = cmd_no;
+ cmdptr->result = 0;
+
+ switch (cmd_no) {
+ case cmd_get_hw_spec:
+ ret = wlan_cmd_hw_spec(priv, cmdptr);
+ break;
+ case cmd_802_11_ps_mode:
+ ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_scan:
+ ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_mac_control:
+ ret = wlan_cmd_mac_control(priv, cmdptr);
+ break;
+
+ case cmd_802_11_associate:
+ case cmd_802_11_reassociate:
+ ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_802_11_deauthenticate:
+ ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
+ break;
+
+ case cmd_802_11_set_wep:
+ ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_ad_hoc_start:
+ ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
+ break;
+ case cmd_code_dnld:
+ break;
+
+ case cmd_802_11_reset:
+ ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_get_log:
+ ret = wlan_cmd_802_11_get_log(priv, cmdptr);
+ break;
+
+ case cmd_802_11_authenticate:
+ ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_802_11_get_stat:
+ ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
+ break;
+
+ case cmd_802_11_snmp_mib:
+ ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
+ cmd_action, cmd_oid, pdata_buf);
+ break;
+
+ case cmd_mac_reg_access:
+ case cmd_bbp_reg_access:
+ case cmd_rf_reg_access:
+ ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_rf_channel:
+ ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_rf_tx_power:
+ ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_radio_control:
+ ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_rf_antenna:
+ ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_data_rate:
+ ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
+ break;
+ case cmd_802_11_rate_adapt_rateset:
+ ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
+ cmdptr, cmd_action);
+ break;
+
+ case cmd_mac_multicast_adr:
+ ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_ad_hoc_join:
+ ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
+ break;
+
+ case cmd_802_11_rssi:
+ ret = wlan_cmd_802_11_rssi(priv, cmdptr);
+ break;
+
+ case cmd_802_11_ad_hoc_stop:
+ ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
+ break;
+
+ case cmd_802_11_enable_rsn:
+ ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_key_material:
+ ret = wlan_cmd_802_11_key_material(priv, cmdptr,
+ cmd_action, cmd_oid,
+ pdata_buf);
+ break;
+
+ case cmd_802_11_pairwise_tsc:
+ break;
+ case cmd_802_11_group_tsc:
+ break;
+
+ case cmd_802_11_mac_address:
+ ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
+ break;
+
+ case cmd_802_11_eeprom_access:
+ ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
+ cmd_action, pdata_buf);
+ break;
+
+ case cmd_802_11_set_afc:
+ case cmd_802_11_get_afc:
+
+ cmdptr->command = cpu_to_le16(cmd_no);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
+ S_DS_GEN);
+
+ memmove(&cmdptr->params.afc,
+ pdata_buf, sizeof(struct cmd_ds_802_11_afc));
+
+ ret = 0;
+ goto done;
+
+ case cmd_802_11d_domain_info:
+ ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
+ cmd_no, cmd_action);
+ break;
+
+ case cmd_802_11_sleep_params:
+ ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
+ break;
+ case cmd_802_11_inactivity_timeout:
+ ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
+ cmd_action, pdata_buf);
+ libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
+ break;
+
+ case cmd_802_11_tpc_cfg:
+ cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
+ S_DS_GEN);
+
+ memmove(&cmdptr->params.tpccfg,
+ pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg));
+
+ ret = 0;
+ break;
+ case cmd_802_11_led_gpio_ctrl:
+ {
+ struct mrvlietypes_ledgpio *gpio =
+ (struct mrvlietypes_ledgpio*)
+ cmdptr->params.ledgpio.data;
+
+ memmove(&cmdptr->params.ledgpio,
+ pdata_buf,
+ sizeof(struct cmd_ds_802_11_led_ctrl));
+
+ cmdptr->command =
+ cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+
+#define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
+ cmdptr->size =
+ cpu_to_le16(gpio->header.len + S_DS_GEN +
+ ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN);
+ gpio->header.len = cpu_to_le16(gpio->header.len);
+
+ ret = 0;
+ break;
+ }
+ case cmd_802_11_pwr_cfg:
+ cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
+ S_DS_GEN);
+ memmove(&cmdptr->params.pwrcfg, pdata_buf,
+ sizeof(struct cmd_ds_802_11_pwr_cfg));
+
+ ret = 0;
+ break;
+ case cmd_bt_access:
+ ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_fwt_access:
+ ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_mesh_access:
+ ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
+ break;
+
+ case cmd_get_tsf:
+ cmdptr->command = cpu_to_le16(cmd_get_tsf);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_get_tsf)
+ + S_DS_GEN);
+ ret = 0;
+ break;
+ case cmd_802_11_tx_rate_query:
+ cmdptr->command =
+ cpu_to_le16(cmd_802_11_tx_rate_query);
+ cmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
+ S_DS_GEN);
+ adapter->txrate = 0;
+ ret = 0;
+ break;
+ default:
+ lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no);
+ ret = -1;
+ break;
+ }
+
+ /* return error, since the command preparation failed */
+ if (ret != 0) {
+ lbs_pr_debug(1, "PREP_CMD: command preparation failed\n");
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ ret = -1;
+ goto done;
+ }
+
+ cmdnode->cmdwaitqwoken = 0;
+
+ libertas_queue_cmd(adapter, cmdnode, 1);
+ adapter->nr_cmd_pending++;
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ if (wait_option & cmd_option_waitforrsp) {
+ lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n");
+ might_sleep();
+ wait_event_interruptible(cmdnode->cmdwait_q,
+ cmdnode->cmdwaitqwoken);
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd_retcode) {
+ lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n",
+ adapter->cur_cmd_retcode);
+ adapter->cur_cmd_retcode = 0;
+ ret = -1;
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function allocates the command buffer and link
+ * it to command free queue.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+int libertas_allocate_cmd_buffer(wlan_private * priv)
+{
+ int ret = 0;
+ u32 ulbufsize;
+ u32 i;
+ struct cmd_ctrl_node *tempcmd_array;
+ u8 *ptempvirtualaddr;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* Allocate and initialize cmdCtrlNode */
+ ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
+
+ if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) {
+ lbs_pr_debug(1,
+ "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+ ret = -1;
+ goto done;
+ }
+
+ adapter->cmd_array = tempcmd_array;
+ memset(adapter->cmd_array, 0, ulbufsize);
+
+ /* Allocate and initialize command buffers */
+ ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) {
+ lbs_pr_debug(1,
+ "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+ ret = -1;
+ goto done;
+ }
+
+ memset(ptempvirtualaddr, 0, ulbufsize);
+
+ /* Update command buffer virtual */
+ tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr;
+ }
+
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ init_waitqueue_head(&tempcmd_array[i].cmdwait_q);
+ libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]);
+ }
+
+ ret = 0;
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function frees the command buffer.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+int libertas_free_cmd_buffer(wlan_private * priv)
+{
+ u32 ulbufsize;
+ unsigned int i;
+ struct cmd_ctrl_node *tempcmd_array;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* need to check if cmd array is allocated or not */
+ if (adapter->cmd_array == NULL) {
+ lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n");
+ goto done;
+ }
+
+ tempcmd_array = adapter->cmd_array;
+
+ /* Release shared memory buffers */
+ ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
+ for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
+ if (tempcmd_array[i].bufvirtualaddr) {
+ lbs_pr_debug(1, "Free all the array\n");
+ kfree(tempcmd_array[i].bufvirtualaddr);
+ tempcmd_array[i].bufvirtualaddr = NULL;
+ }
+ }
+
+ /* Release cmd_ctrl_node */
+ if (adapter->cmd_array) {
+ lbs_pr_debug(1, "Free cmd_array\n");
+ kfree(adapter->cmd_array);
+ adapter->cmd_array = NULL;
+ }
+
+done:
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function gets a free command node if available in
+ * command free queue.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ */
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv)
+{
+ struct cmd_ctrl_node *tempnode;
+ wlan_adapter *adapter = priv->adapter;
+ unsigned long flags;
+
+ if (!adapter)
+ return NULL;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (!list_empty(&adapter->cmdfreeq)) {
+ tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
+ list_del((struct list_head *)tempnode);
+ } else {
+ lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n");
+ tempnode = NULL;
+ }
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (tempnode) {
+ lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
+ lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
+ tempnode);
+ cleanup_cmdnode(tempnode);
+ }
+
+ return tempnode;
+}
+
+/**
+ * @brief This function cleans command node.
+ *
+ * @param ptempnode A pointer to cmdCtrlNode structure
+ * @return n/a
+ */
+static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
+{
+ if (!ptempnode)
+ return;
+ ptempnode->cmdwaitqwoken = 1;
+ wake_up_interruptible(&ptempnode->cmdwait_q);
+ ptempnode->status = 0;
+ ptempnode->cmd_oid = (u32) 0;
+ ptempnode->wait_option = 0;
+ ptempnode->pdata_buf = NULL;
+
+ if (ptempnode->bufvirtualaddr != NULL)
+ memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
+ return;
+}
+
+/**
+ * @brief This function initializes the command node.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param ptempnode A pointer to cmd_ctrl_node structure
+ * @param cmd_oid cmd oid: treated as sub command
+ * @param wait_option wait option: wait response or not
+ * @param pdata_buf A pointer to informaion buffer
+ * @return 0 or -1
+ */
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+ struct cmd_ctrl_node *ptempnode,
+ u32 cmd_oid, u16 wait_option, void *pdata_buf)
+{
+ ENTER();
+
+ if (!ptempnode)
+ return;
+
+ ptempnode->cmd_oid = cmd_oid;
+ ptempnode->wait_option = wait_option;
+ ptempnode->pdata_buf = pdata_buf;
+
+ LEAVE();
+}
+
+/**
+ * @brief This function executes next command in command
+ * pending queue. It will put fimware back to PS mode
+ * if applicable.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+int libertas_execute_next_command(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmdnode = NULL;
+ struct cmd_ds_command *cmdptr;
+ unsigned long flags;
+ int ret = 0;
+
+ lbs_pr_debug(1, "libertas_execute_next_command\n");
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (adapter->cur_cmd) {
+ lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ if (!list_empty(&adapter->cmdpendingq)) {
+ cmdnode = (struct cmd_ctrl_node *)
+ adapter->cmdpendingq.next;
+ }
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (cmdnode) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
+ cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
+
+ if (is_command_allowed_in_ps(cmdptr->command)) {
+ if ((adapter->psstate == PS_STATE_SLEEP)
+ || (adapter->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+ cmdptr->command, adapter->psstate);
+ ret = -1;
+ goto done;
+ }
+ lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command "
+ "0x%x in psstate %d\n",
+ cmdptr->command, adapter->psstate);
+ } else if (adapter->psstate != PS_STATE_FULL_POWER) {
+ /*
+ * 1. Non-PS command:
+ * Queue it. set needtowakeup to TRUE if current state
+ * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS.
+ * 2. PS command but not Exit_PS:
+ * Ignore it.
+ * 3. PS command Exit_PS:
+ * Set needtowakeup to TRUE if current state is SLEEP,
+ * otherwise send this command down to firmware
+ * immediately.
+ */
+ if (cmdptr->command !=
+ cpu_to_le16(cmd_802_11_ps_mode)) {
+ /* Prepare to send Exit PS,
+ * this non PS command will be sent later */
+ if ((adapter->psstate == PS_STATE_SLEEP)
+ || (adapter->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ /* w/ new scheme, it will not reach here.
+ since it is blocked in main_thread. */
+ adapter->needtowakeup = 1;
+ } else
+ libertas_ps_wakeup(priv, 0);
+
+ ret = 0;
+ goto done;
+ } else {
+ /*
+ * PS command. Ignore it if it is not Exit_PS.
+ * otherwise send it down immediately.
+ */
+ struct cmd_ds_802_11_ps_mode *psm =
+ &cmdptr->params.psmode;
+
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+ psm->action);
+ if (psm->action !=
+ cpu_to_le16(cmd_subcmd_exit_ps)) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+ list_del((struct list_head *)cmdnode);
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+
+ ret = 0;
+ goto done;
+ }
+
+ if ((adapter->psstate == PS_STATE_SLEEP)
+ || (adapter->psstate == PS_STATE_PRE_SLEEP)
+ ) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+ list_del((struct list_head *)cmdnode);
+ libertas_cleanup_and_insert_cmd(priv, cmdnode);
+ adapter->needtowakeup = 1;
+
+ ret = 0;
+ goto done;
+ }
+
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+ }
+ }
+ list_del((struct list_head *)cmdnode);
+ lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n",
+ cmdptr->command);
+ DownloadcommandToStation(priv, cmdnode);
+ } else {
+ /*
+ * check if in power save mode, if yes, put the device back
+ * to PS mode
+ */
+ if ((adapter->psmode != wlan802_11powermodecam) &&
+ (adapter->psstate == PS_STATE_FULL_POWER) &&
+ (adapter->connect_status == libertas_connected)) {
+ if (adapter->secinfo.WPAenabled
+ || adapter->secinfo.WPA2enabled) {
+ /* check for valid WPA group keys */
+ if (adapter->wpa_mcast_key.len
+ || adapter->wpa_unicast_key.len) {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
+ " go back to PS_SLEEP");
+ libertas_ps_sleep(priv, 0);
+ }
+ } else {
+ lbs_pr_debug(1,
+ "EXEC_NEXT_CMD: command PendQ is empty,"
+ " go back to PS_SLEEP");
+ libertas_ps_sleep(priv, 0);
+ }
+ }
+ }
+
+ ret = 0;
+done:
+ return ret;
+}
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str)
+{
+ union iwreq_data iwrq;
+ u8 buf[50];
+
+ ENTER();
+
+ memset(&iwrq, 0, sizeof(union iwreq_data));
+ memset(buf, 0, sizeof(buf));
+
+ snprintf(buf, sizeof(buf) - 1, "%s", str);
+
+ iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
+
+ /* Send Event to upper layer */
+ lbs_pr_debug(1, "Event Indication string = %s\n",
+ (char *)buf);
+ lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length);
+
+ lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str);
+ wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf);
+
+ LEAVE();
+ return;
+}
+
+static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
+{
+ unsigned long flags;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+ size);
+
+ lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+
+ ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size);
+ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->intcounter || adapter->currenttxskb)
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+ adapter->intcounter, adapter->currenttxskb);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (ret) {
+ lbs_pr_alert(
+ "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n");
+ } else {
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (!adapter->intcounter) {
+ adapter->psstate = PS_STATE_SLEEP;
+ } else {
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+ adapter->intcounter);
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
+ lbs_pr_debug(1, "+");
+ }
+
+ LEAVE();
+ return ret;
+}
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option)
+{
+
+ ENTER();
+
+ /*
+ * PS is currently supported only in Infrastructure mode
+ * Remove this check if it is to be supported in IBSS mode also
+ */
+
+ libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+ cmd_subcmd_enter_ps, wait_option, 0, NULL);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function sends Eixt_PS command to firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wait_option wait response or not
+ * @return n/a
+ */
+void libertas_ps_wakeup(wlan_private * priv, int wait_option)
+{
+ enum WLAN_802_11_POWER_MODE Localpsmode;
+
+ ENTER();
+
+ Localpsmode = wlan802_11powermodecam;
+
+ lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode);
+
+ libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
+ cmd_subcmd_exit_ps,
+ wait_option, 0, &Localpsmode);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function checks condition and prepares to
+ * send sleep confirm command to firmware if ok.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param psmode Power Saving mode
+ * @return n/a
+ */
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode)
+{
+ unsigned long flags =0;
+ wlan_adapter *adapter = priv->adapter;
+ u8 allowed = 1;
+
+ ENTER();
+
+ if (priv->wlan_dev.dnld_sent) {
+ allowed = 0;
+ lbs_pr_debug(1, "D");
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd) {
+ allowed = 0;
+ lbs_pr_debug(1, "C");
+ }
+ if (adapter->intcounter > 0) {
+ allowed = 0;
+ lbs_pr_debug(1, "I%d", adapter->intcounter);
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ if (allowed) {
+ lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n");
+ sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
+ sizeof(struct PS_CMD_ConfirmSleep));
+ } else {
+ lbs_pr_debug(1, "Sleep Confirm has been delayed\n");
+ }
+
+ LEAVE();
+}
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
new file mode 100644
index 00000000000..cdb012c7e9c
--- /dev/null
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -0,0 +1,1031 @@
+/**
+ * This file contains the handling of command
+ * responses as well as events generated by firmware.
+ */
+#include <linux/delay.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+/**
+ * @brief This function handles disconnect event. it
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return n/a
+ */
+void libertas_mac_event_disconnected(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ union iwreq_data wrqu;
+
+ if (adapter->connect_status != libertas_connected)
+ return;
+
+ lbs_pr_debug(1, "Handles disconnect event.\n");
+
+ memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /*
+ * Cisco AP sends EAP failure and de-auth in less than 0.5 ms.
+ * It causes problem in the Supplicant
+ */
+
+ msleep_interruptible(1000);
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+ /* Free Tx and Rx packets */
+ kfree_skb(priv->adapter->currenttxskb);
+ priv->adapter->currenttxskb = NULL;
+
+ /* report disconnect to upper layer */
+ netif_stop_queue(priv->wlan_dev.netdev);
+ netif_carrier_off(priv->wlan_dev.netdev);
+
+ /* reset SNR/NF/RSSI values */
+ memset(adapter->SNR, 0x00, sizeof(adapter->SNR));
+ memset(adapter->NF, 0x00, sizeof(adapter->NF));
+ memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI));
+ memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+ memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+ adapter->nextSNRNF = 0;
+ adapter->numSNRNF = 0;
+ adapter->rxpd_rate = 0;
+ lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n",
+ adapter->curbssparams.ssid.ssid,
+ adapter->curbssparams.ssid.ssidlength);
+ lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n",
+ adapter->previousssid.ssid, adapter->previousssid.ssidlength);
+
+ /* reset internal flags */
+ adapter->secinfo.WPAenabled = 0;
+ adapter->secinfo.WPA2enabled = 0;
+ adapter->wpa_ie_len = 0;
+ adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+ adapter->secinfo.Encryptionmode = CIPHER_NONE;
+
+ adapter->connect_status = libertas_disconnected;
+
+ /*
+ * memorize the previous SSID and BSSID
+ * it could be used for re-assoc
+ */
+ memcpy(&adapter->previousssid,
+ &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID));
+ memcpy(adapter->previousbssid,
+ adapter->curbssparams.bssid, ETH_ALEN);
+
+ /* need to erase the current SSID and BSSID info */
+ adapter->pattemptedbssdesc = NULL;
+ memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+ if (adapter->psstate != PS_STATE_FULL_POWER) {
+ /* make firmware to exit PS mode */
+ lbs_pr_debug(1, "Disconnected, so exit PS mode.\n");
+ libertas_ps_wakeup(priv, 0);
+ }
+}
+
+/**
+ * @brief This function handles MIC failure event.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @para event the event id
+ * @return n/a
+ */
+static void handle_mic_failureevent(wlan_private * priv, u32 event)
+{
+ char buf[50];
+
+ memset(buf, 0, sizeof(buf));
+
+ sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
+
+ if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) {
+ strcat(buf, "unicast ");
+ } else {
+ strcat(buf, "multicast ");
+ }
+
+ libertas_send_iwevcustom_event(priv, buf);
+}
+
+static int wlan_ret_reg_access(wlan_private * priv,
+ u16 type, struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ switch (type) {
+ case cmd_ret_mac_reg_access:
+ {
+ struct cmd_ds_mac_reg_access *reg;
+
+ reg =
+ (struct cmd_ds_mac_reg_access *)&resp->params.
+ macreg;
+
+ adapter->offsetvalue.offset = reg->offset;
+ adapter->offsetvalue.value = reg->value;
+ break;
+ }
+
+ case cmd_ret_bbp_reg_access:
+ {
+ struct cmd_ds_bbp_reg_access *reg;
+ reg =
+ (struct cmd_ds_bbp_reg_access *)&resp->params.
+ bbpreg;
+
+ adapter->offsetvalue.offset = reg->offset;
+ adapter->offsetvalue.value = reg->value;
+ break;
+ }
+
+ case cmd_ret_rf_reg_access:
+ {
+ struct cmd_ds_rf_reg_access *reg;
+ reg =
+ (struct cmd_ds_rf_reg_access *)&resp->params.
+ rfreg;
+
+ adapter->offsetvalue.offset = reg->offset;
+ adapter->offsetvalue.value = reg->value;
+ break;
+ }
+
+ default:
+ LEAVE();
+ return -1;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_get_hw_spec(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ u32 i;
+ struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo);
+
+ adapter->fwreleasenumber = hwspec->fwreleasenumber;
+
+ lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n",
+ adapter->fwreleasenumber);
+ lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
+ hwspec->permanentaddr[0], hwspec->permanentaddr[1],
+ hwspec->permanentaddr[2], hwspec->permanentaddr[3],
+ hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
+ lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X version=0x%X\n",
+ hwspec->hwifversion, hwspec->version);
+
+ adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ /* use the region code to search for the index */
+ if (adapter->regioncode == libertas_region_code_to_index[i]) {
+ adapter->regiontableindex = (u16) i;
+ break;
+ }
+ }
+
+ /* if it's unidentified region code, use the default (USA) */
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ adapter->regioncode = 0x10;
+ adapter->regiontableindex = 0;
+ lbs_pr_info(
+ "unidentified region code, use the default (USA)\n");
+ }
+
+ if (adapter->current_addr[0] == 0xff) {
+ memmove(adapter->current_addr, hwspec->permanentaddr,
+ ETH_ALEN);
+ }
+
+ memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN);
+ memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+ if (libertas_set_regiontable(priv, adapter->regioncode, 0)) {
+ ret = -1;
+ goto done;
+ }
+
+ if (libertas_set_universaltable(priv, 0)) {
+ ret = -1;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_ret_802_11_sleep_params(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n"
+ " extsleepclk=%x\n", sp->error, sp->offset,
+ sp->stabletime, sp->calcontrol, sp->externalsleepclk);
+ adapter->sp.sp_error = le16_to_cpu(sp->error);
+ adapter->sp.sp_offset = le16_to_cpu(sp->offset);
+ adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime);
+ adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol);
+ adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk);
+ adapter->sp.sp_reserved = le16_to_cpu(sp->reserved);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_stat(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+/* currently adapter->wlan802_11Stat is unused
+
+ struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
+ wlan_adapter *adapter = priv->adapter;
+
+ // TODO Convert it to Big endian befor copy
+ memcpy(&adapter->wlan802_11Stat,
+ p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
+*/
+ return 0;
+}
+
+static int wlan_ret_802_11_snmp_mib(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+ u16 oid = le16_to_cpu(smib->oid);
+ u16 querytype = le16_to_cpu(smib->querytype);
+
+ ENTER();
+
+ lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+ querytype);
+ lbs_pr_debug(1, "SNMP_RESP: Buf size = %x\n",
+ le16_to_cpu(smib->bufsize));
+
+ if (querytype == cmd_act_get) {
+ switch (oid) {
+ case fragthresh_i:
+ priv->adapter->fragthsd =
+ le16_to_cpu(*
+ ((unsigned short *)(smib->value)));
+ lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n",
+ priv->adapter->fragthsd);
+ break;
+ case rtsthresh_i:
+ priv->adapter->rtsthsd =
+ le16_to_cpu(*
+ ((unsigned short *)(smib->value)));
+ lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n",
+ priv->adapter->rtsthsd);
+ break;
+ case short_retrylim_i:
+ priv->adapter->txretrycount =
+ le16_to_cpu(*
+ ((unsigned short *)(smib->value)));
+ lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n",
+ priv->adapter->rtsthsd);
+ break;
+ default:
+ break;
+ }
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_key_material(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_key_material *pkeymaterial =
+ &resp->params.keymaterial;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(pkeymaterial->action);
+
+ ENTER();
+
+ /* Copy the returned key to driver private data */
+ if (action == cmd_act_get) {
+ u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
+ u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
+
+ while (buf_ptr < resp_end) {
+ struct MrvlIEtype_keyParamSet * pkeyparamset =
+ (struct MrvlIEtype_keyParamSet *) buf_ptr;
+ struct WLAN_802_11_KEY * pkey;
+ u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+ u16 param_set_len = le16_to_cpu(pkeyparamset->length);
+ u8 * end;
+ u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+
+ end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
+ + sizeof (pkeyparamset->length)
+ + param_set_len;
+ /* Make sure we don't access past the end of the IEs */
+ if (end > resp_end)
+ break;
+
+ if (key_info & KEY_INFO_WPA_UNICAST)
+ pkey = &adapter->wpa_unicast_key;
+ else if (key_info & KEY_INFO_WPA_MCAST)
+ pkey = &adapter->wpa_mcast_key;
+ else
+ break;
+
+ /* Copy returned key into driver */
+ memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ if (key_len > sizeof(pkey->key))
+ break;
+ pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
+ pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
+ pkey->len = le16_to_cpu(pkeyparamset->keylen);
+ memcpy(pkey->key, pkeyparamset->key, pkey->len);
+
+ buf_ptr = end + 1;
+ }
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_mac_address(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rf_tx_power(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
+
+ lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(pAntenna->action);
+
+ if (action == cmd_act_get_rx)
+ adapter->rxantennamode =
+ le16_to_cpu(pAntenna->antennamode);
+
+ if (action == cmd_act_get_tx)
+ adapter->txantennamode =
+ le16_to_cpu(pAntenna->antennamode);
+
+ lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
+ action, le16_to_cpu(pAntenna->antennamode));
+
+ return 0;
+}
+
+static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rate_adapt_rateset *rates =
+ &resp->params.rateset;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (rates->action == cmd_act_get) {
+ adapter->enablehwauto = rates->enablehwauto;
+ adapter->ratebitmap = rates->bitmap;
+ }
+
+ LEAVE();
+
+ return 0;
+}
+
+static int wlan_ret_802_11_data_rate(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
+ wlan_adapter *adapter = priv->adapter;
+ u8 dot11datarate;
+
+ ENTER();
+
+ lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
+ (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+
+ dot11datarate = pdatarate->datarate[0];
+ if (pdatarate->action == cmd_act_get_tx_rate) {
+ memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
+ sizeof(adapter->libertas_supported_rates));
+ }
+ adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rf_channel(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rf_channel *rfchannel =
+ &resp->params.rfchannel;
+ wlan_adapter *adapter = priv->adapter;
+ u16 action = le16_to_cpu(rfchannel->action);
+ u16 newchannel = le16_to_cpu(rfchannel->currentchannel);
+
+ ENTER();
+
+ if (action == cmd_opt_802_11_rf_channel_get
+ && adapter->curbssparams.channel != newchannel) {
+ lbs_pr_debug(1, "channel Switch: %d to %d\n",
+ adapter->curbssparams.channel, newchannel);
+
+ /* Update the channel again */
+ adapter->curbssparams.channel = newchannel;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_ret_802_11_rssi(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
+ wlan_adapter *adapter = priv->adapter;
+
+ /* store the non average value */
+ adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG] =
+ le16_to_cpu(rssirsp->noisefloor);
+
+ adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR);
+ adapter->NF[TYPE_BEACON][TYPE_AVG] =
+ le16_to_cpu(rssirsp->avgnoisefloor);
+
+ adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] =
+ CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+ adapter->RSSI[TYPE_BEACON][TYPE_AVG] =
+ CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
+
+ lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n",
+ adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
+
+ return 0;
+}
+
+static int wlan_ret_802_11_eeprom_access(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_ioctl_regrdwr *pbuf;
+ pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
+
+ lbs_pr_debug(1, "eeprom read len=%x\n",
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
+ pbuf->NOB = 0;
+ lbs_pr_debug(1, "eeprom read return length is too big\n");
+ return -1;
+ }
+ pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
+ if (pbuf->NOB > 0) {
+
+ memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ lbs_dbg_hex("adapter", (char *)&pbuf->value,
+ le16_to_cpu(resp->params.rdeeprom.bytecount));
+ }
+ return 0;
+}
+
+static int wlan_ret_get_log(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ struct cmd_ds_802_11_get_log *logmessage =
+ (struct cmd_ds_802_11_get_log *)&resp->params.glog;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* TODO Convert it to Big Endian before copy */
+ memcpy(&adapter->logmsg, logmessage,
+ sizeof(struct cmd_ds_802_11_get_log));
+
+ LEAVE();
+ return 0;
+}
+
+static inline int handle_cmd_response(u16 respcmd,
+ struct cmd_ds_command *resp,
+ wlan_private *priv)
+{
+ int ret = 0;
+ unsigned long flags;
+ wlan_adapter *adapter = priv->adapter;
+
+ switch (respcmd) {
+ case cmd_ret_mac_reg_access:
+ case cmd_ret_bbp_reg_access:
+ case cmd_ret_rf_reg_access:
+ ret = wlan_ret_reg_access(priv, respcmd, resp);
+ break;
+
+ case cmd_ret_hw_spec_info:
+ ret = wlan_ret_get_hw_spec(priv, resp);
+ break;
+
+ case cmd_ret_802_11_scan:
+ ret = libertas_ret_80211_scan(priv, resp);
+ break;
+
+ case cmd_ret_802_11_get_log:
+ ret = wlan_ret_get_log(priv, resp);
+ break;
+
+ case cmd_ret_802_11_associate:
+ case cmd_ret_802_11_reassociate:
+ ret = libertas_ret_80211_associate(priv, resp);
+ break;
+
+ case cmd_ret_802_11_disassociate:
+ case cmd_ret_802_11_deauthenticate:
+ ret = libertas_ret_80211_disassociate(priv, resp);
+ break;
+
+ case cmd_ret_802_11_ad_hoc_start:
+ case cmd_ret_802_11_ad_hoc_join:
+ ret = libertas_ret_80211_ad_hoc_start(priv, resp);
+ break;
+
+ case cmd_ret_802_11_stat:
+ ret = wlan_ret_802_11_stat(priv, resp);
+ break;
+
+ case cmd_ret_802_11_snmp_mib:
+ ret = wlan_ret_802_11_snmp_mib(priv, resp);
+ break;
+
+ case cmd_ret_802_11_rf_tx_power:
+ ret = wlan_ret_802_11_rf_tx_power(priv, resp);
+ break;
+
+ case cmd_ret_802_11_set_afc:
+ case cmd_ret_802_11_get_afc:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.afc,
+ sizeof(struct cmd_ds_802_11_afc));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ break;
+ case cmd_ret_802_11_rf_antenna:
+ ret = wlan_ret_802_11_rf_antenna(priv, resp);
+ break;
+
+ case cmd_ret_mac_multicast_adr:
+ case cmd_ret_mac_control:
+ case cmd_ret_802_11_set_wep:
+ case cmd_ret_802_11_reset:
+ case cmd_ret_802_11_authenticate:
+ case cmd_ret_802_11_radio_control:
+ case cmd_ret_802_11_beacon_stop:
+ case cmd_ret_802_11_enable_rsn:
+ break;
+
+ case cmd_ret_802_11_data_rate:
+ ret = wlan_ret_802_11_data_rate(priv, resp);
+ break;
+ case cmd_ret_802_11_rate_adapt_rateset:
+ ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
+ break;
+ case cmd_ret_802_11_rf_channel:
+ ret = wlan_ret_802_11_rf_channel(priv, resp);
+ break;
+
+ case cmd_ret_802_11_rssi:
+ ret = wlan_ret_802_11_rssi(priv, resp);
+ break;
+
+ case cmd_ret_802_11_mac_address:
+ ret = wlan_ret_802_11_mac_address(priv, resp);
+ break;
+
+ case cmd_ret_802_11_ad_hoc_stop:
+ ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
+ break;
+
+ case cmd_ret_802_11_key_material:
+ lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n");
+ ret = wlan_ret_802_11_key_material(priv, resp);
+ break;
+
+ case cmd_ret_802_11_eeprom_access:
+ ret = wlan_ret_802_11_eeprom_access(priv, resp);
+ break;
+
+ case cmd_ret_802_11d_domain_info:
+ ret = libertas_ret_802_11d_domain_info(priv, resp);
+ break;
+
+ case cmd_ret_802_11_sleep_params:
+ ret = wlan_ret_802_11_sleep_params(priv, resp);
+ break;
+ case cmd_ret_802_11_inactivity_timeout:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ *((u16 *) adapter->cur_cmd->pdata_buf) =
+ le16_to_cpu(resp->params.inactivity_timeout.timeout);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+
+ case cmd_ret_802_11_tpc_cfg:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.tpccfg,
+ sizeof(struct cmd_ds_802_11_tpc_cfg));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_802_11_led_gpio_ctrl:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.ledgpio,
+ sizeof(struct cmd_ds_802_11_led_ctrl));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_802_11_pwr_cfg:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memmove(adapter->cur_cmd->pdata_buf,
+ &resp->params.pwrcfg,
+ sizeof(struct cmd_ds_802_11_pwr_cfg));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ break;
+
+ case cmd_ret_get_tsf:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ memcpy(priv->adapter->cur_cmd->pdata_buf,
+ &resp->params.gettsf.tsfvalue, sizeof(u64));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_bt_access:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd->pdata_buf)
+ memcpy(adapter->cur_cmd->pdata_buf,
+ &resp->params.bt.addr1, 2 * ETH_ALEN);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_fwt_access:
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd->pdata_buf)
+ memcpy(adapter->cur_cmd->pdata_buf,
+ &resp->params.fwt,
+ sizeof(resp->params.fwt));
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ break;
+ case cmd_ret_mesh_access:
+ if (adapter->cur_cmd->pdata_buf)
+ memcpy(adapter->cur_cmd->pdata_buf,
+ &resp->params.mesh,
+ sizeof(resp->params.mesh));
+ break;
+ case cmd_rte_802_11_tx_rate_query:
+ priv->adapter->txrate = resp->params.txrate.txrate;
+ break;
+ default:
+ lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n",
+ resp->command);
+ break;
+ }
+ return ret;
+}
+
+int libertas_process_rx_command(wlan_private * priv)
+{
+ u16 respcmd;
+ struct cmd_ds_command *resp;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ ulong flags;
+ u16 result;
+
+ ENTER();
+
+ lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies);
+
+ /* Now we got response from FW, cancel the command timer */
+ del_timer(&adapter->command_timer);
+
+ mutex_lock(&adapter->lock);
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+
+ if (!adapter->cur_cmd) {
+ lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+ ret = -1;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ goto done;
+ }
+ resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
+
+ lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
+ priv->wlan_dev.upld_len);
+
+ respcmd = le16_to_cpu(resp->command);
+
+ result = le16_to_cpu(resp->result);
+
+ lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd,
+ result, priv->wlan_dev.upld_len);
+
+ if (!(respcmd & 0x8000)) {
+ lbs_pr_debug(1, "Invalid response to command!");
+ adapter->cur_cmd_retcode = -1;
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ ret = -1;
+ goto done;
+ }
+
+ /* Store the response code to cur_cmd_retcode. */
+ adapter->cur_cmd_retcode = le16_to_cpu(resp->result);
+
+ if (respcmd == cmd_ret_802_11_ps_mode) {
+ struct cmd_ds_802_11_ps_mode *psmode;
+
+ psmode = &resp->params.psmode;
+ lbs_pr_debug(1,
+ "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+ resp->result, psmode->action);
+ psmode->action = cpu_to_le16(psmode->action);
+
+ if (result) {
+ lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n",
+ resp->result);
+ if (adapter->inframode == wlan802_11ibss) {
+ /*
+ * We should not re-try enter-ps command in
+ * ad-hoc mode. It takes place in
+ * libertas_execute_next_command().
+ */
+ if (psmode->action == cmd_subcmd_enter_ps)
+ adapter->psmode =
+ wlan802_11powermodecam;
+ }
+ } else if (psmode->action == cmd_subcmd_enter_ps) {
+ adapter->needtowakeup = 0;
+ adapter->psstate = PS_STATE_AWAKE;
+
+ lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n");
+ if (adapter->connect_status != libertas_connected) {
+ /*
+ * When Deauth Event received before Enter_PS command
+ * response, We need to wake up the firmware.
+ */
+ lbs_pr_debug(1,
+ "Disconnected, Going to invoke libertas_ps_wakeup\n");
+
+ mutex_unlock(&adapter->lock);
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+ libertas_ps_wakeup(priv, 0);
+ mutex_lock(&adapter->lock);
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ }
+ } else if (psmode->action == cmd_subcmd_exit_ps) {
+ adapter->needtowakeup = 0;
+ adapter->psstate = PS_STATE_FULL_POWER;
+ lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n");
+ } else {
+ lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n",
+ psmode->action);
+ }
+
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ ret = 0;
+ goto done;
+ }
+
+ if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
+ /* Copy the response back to response buffer */
+ memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
+
+ adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
+ }
+
+ /* If the command is not successful, cleanup and return failure */
+ if ((result != 0 || !(respcmd & 0x8000))) {
+ lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n",
+ resp->command, resp->result);
+ /*
+ * Handling errors here
+ */
+ switch (respcmd) {
+ case cmd_ret_hw_spec_info:
+ case cmd_ret_802_11_reset:
+ lbs_pr_debug(1, "CMD_RESP: Reset command failed\n");
+ break;
+
+ }
+
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ ret = -1;
+ goto done;
+ }
+
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ ret = handle_cmd_response(respcmd, resp, priv);
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ if (adapter->cur_cmd) {
+ /* Clean up and Put current command back to cmdfreeq */
+ __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+ adapter->nr_cmd_pending--;
+ WARN_ON(adapter->nr_cmd_pending > 128);
+ adapter->cur_cmd = NULL;
+ }
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+done:
+ mutex_unlock(&adapter->lock);
+ LEAVE();
+ return ret;
+}
+
+int libertas_process_event(wlan_private * priv)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ u32 eventcause;
+
+ spin_lock_irq(&adapter->driver_lock);
+ eventcause = adapter->eventcause;
+ spin_unlock_irq(&adapter->driver_lock);
+
+ ENTER();
+
+ lbs_pr_debug(1, "EVENT Cause %x\n", eventcause);
+
+ switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
+ case MACREG_INT_CODE_LINK_SENSED:
+ lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n");
+ break;
+
+ case MACREG_INT_CODE_DEAUTHENTICATED:
+ lbs_pr_debug(1, "EVENT: Deauthenticated\n");
+ libertas_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_DISASSOCIATED:
+ lbs_pr_debug(1, "EVENT: Disassociated\n");
+ libertas_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
+ lbs_pr_debug(1, "EVENT: Link lost\n");
+ libertas_mac_event_disconnected(priv);
+ break;
+
+ case MACREG_INT_CODE_PS_SLEEP:
+ lbs_pr_debug(1, "EVENT: SLEEP\n");
+ lbs_pr_debug(1, "_");
+
+ /* handle unexpected PS SLEEP event */
+ if (adapter->psstate == PS_STATE_FULL_POWER) {
+ lbs_pr_debug(1,
+ "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+ break;
+ }
+ adapter->psstate = PS_STATE_PRE_SLEEP;
+
+ libertas_ps_confirm_sleep(priv, (u16) adapter->psmode);
+
+ break;
+
+ case MACREG_INT_CODE_PS_AWAKE:
+ lbs_pr_debug(1, "EVENT: AWAKE \n");
+ lbs_pr_debug(1, "|");
+
+ /* handle unexpected PS AWAKE event */
+ if (adapter->psstate == PS_STATE_FULL_POWER) {
+ lbs_pr_debug(1,
+ "EVENT: In FULL POWER mode - ignore PS AWAKE\n");
+ break;
+ }
+
+ adapter->psstate = PS_STATE_AWAKE;
+
+ if (adapter->needtowakeup) {
+ /*
+ * wait for the command processing to finish
+ * before resuming sending
+ * adapter->needtowakeup will be set to FALSE
+ * in libertas_ps_wakeup()
+ */
+ lbs_pr_debug(1, "Waking up...\n");
+ libertas_ps_wakeup(priv, 0);
+ }
+ break;
+
+ case MACREG_INT_CODE_MIC_ERR_UNICAST:
+ lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n");
+ handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST);
+ break;
+
+ case MACREG_INT_CODE_MIC_ERR_MULTICAST:
+ lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n");
+ handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST);
+ break;
+ case MACREG_INT_CODE_MIB_CHANGED:
+ case MACREG_INT_CODE_INIT_DONE:
+ break;
+
+ case MACREG_INT_CODE_ADHOC_BCN_LOST:
+ lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n");
+ break;
+
+ case MACREG_INT_CODE_RSSI_LOW:
+ lbs_pr_alert( "EVENT: RSSI_LOW\n");
+ break;
+ case MACREG_INT_CODE_SNR_LOW:
+ lbs_pr_alert( "EVENT: SNR_LOW\n");
+ break;
+ case MACREG_INT_CODE_MAX_FAIL:
+ lbs_pr_alert( "EVENT: MAX_FAIL\n");
+ break;
+ case MACREG_INT_CODE_RSSI_HIGH:
+ lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+ break;
+ case MACREG_INT_CODE_SNR_HIGH:
+ lbs_pr_alert( "EVENT: SNR_HIGH\n");
+ break;
+
+ default:
+ lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+ eventcause >> SBI_EVENT_CAUSE_SHIFT);
+ break;
+ }
+
+ spin_lock_irq(&adapter->driver_lock);
+ adapter->eventcause = 0;
+ spin_unlock_irq(&adapter->driver_lock);
+ LEAVE();
+ return ret;
+}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
new file mode 100644
index 00000000000..51dfd202f55
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -0,0 +1,1935 @@
+#include <linux/module.h>
+#include <linux/dcache.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <net/iw_handler.h>
+#include "dev.h"
+#include "decl.h"
+#include "host.h"
+
+static struct dentry *libertas_dir = NULL;
+static char *szStates[] = {
+ "Connected",
+ "Disconnected"
+};
+
+void libertas_debug_init(wlan_private * priv, struct net_device *dev);
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return -EINVAL;
+}
+
+static const size_t len = PAGE_SIZE;
+
+static ssize_t libertas_dev_info(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+ ssize_t res;
+
+ pos += snprintf(buf+pos, len-pos, "state = %s\n",
+ szStates[priv->adapter->connect_status]);
+ pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
+ (u32) priv->adapter->regioncode);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+
+static ssize_t libertas_getscantable(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ size_t pos = 0;
+ int numscansdone = 0, res;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------");
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------\n");
+ pos += snprintf(buf+pos, len-pos,
+ "# | ch | ss | bssid | cap | TSF | Qual | SSID \n");
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------");
+ pos += snprintf(buf+pos, len-pos,
+ "---------------------------------------\n");
+
+ while (numscansdone < priv->adapter->numinscantable) {
+ struct bss_descriptor *pbssinfo;
+ u16 cap;
+
+ pbssinfo = &priv->adapter->scantable[numscansdone];
+ memcpy(&cap, &pbssinfo->cap, sizeof(cap));
+ pos += snprintf(buf+pos, len-pos,
+ "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |",
+ numscansdone, pbssinfo->channel, pbssinfo->rssi,
+ pbssinfo->macaddress[0], pbssinfo->macaddress[1],
+ pbssinfo->macaddress[2], pbssinfo->macaddress[3],
+ pbssinfo->macaddress[4], pbssinfo->macaddress[5]);
+ pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+ pos += snprintf(buf+pos, len-pos, "%c%c%c |",
+ pbssinfo->cap.ibss ? 'A' : 'I',
+ pbssinfo->cap.privacy ? 'P' : ' ',
+ pbssinfo->cap.spectrummgmt ? 'S' : ' ');
+ pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf);
+ pos += snprintf(buf+pos, len-pos, " %d |",
+ SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi));
+
+ pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid);
+
+ numscansdone++;
+ }
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_sleepparams_write(struct file *file,
+ const char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t buf_size, res;
+ int p1, p2, p3, p4, p5, p6;
+ struct sleep_params sp;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, user_buf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
+ if (res != 6) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ sp.sp_error = p1;
+ sp.sp_offset = p2;
+ sp.sp_stabletime = p3;
+ sp.sp_calcontrol = p4;
+ sp.sp_extsleepclk = p5;
+ sp.sp_reserved = p6;
+
+ memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params));
+
+ res = libertas_prepare_and_send_command(priv,
+ cmd_802_11_sleep_params,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (!res)
+ res = count;
+ else
+ res = -EINVAL;
+
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res;
+ size_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_prepare_and_send_command(priv,
+ cmd_802_11_sleep_params,
+ cmd_act_get,
+ cmd_option_waitforrsp, 0, NULL);
+ if (res) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error,
+ adapter->sp.sp_offset, adapter->sp.sp_stabletime,
+ adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk,
+ adapter->sp.sp_reserved);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_extscan(struct file *file, const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ struct WLAN_802_11_SSID extscan_ssid;
+ union iwreq_data wrqu;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1);
+ extscan_ssid.ssidlength = strlen(buf)-1;
+
+ libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1);
+
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+ free_page(addr);
+ return count;
+}
+
+static int libertas_parse_chan(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur)
+{
+ char *start, *end, *hold, *str;
+ int i = 0;
+
+ start = strstr(buf, "chan=");
+ if (!start)
+ return -EINVAL;
+ start += 5;
+ end = strstr(start, " ");
+ if (!end)
+ end = buf + count;
+ hold = kzalloc((end - start)+1, GFP_KERNEL);
+ if (!hold)
+ return -ENOMEM;
+ strncpy(hold, start, end - start);
+ hold[(end-start)+1] = '\0';
+ while(hold && (str = strsep(&hold, ","))) {
+ int chan;
+ char band, passive = 0;
+ sscanf(str, "%d%c%c", &chan, &band, &passive);
+ scan_cfg->chanlist[i].channumber = chan;
+ scan_cfg->chanlist[i].scantype = passive ? 1 : 0;
+ if (band == 'b' || band == 'g')
+ scan_cfg->chanlist[i].radiotype = 0;
+ else if (band == 'a')
+ scan_cfg->chanlist[i].radiotype = 1;
+
+ scan_cfg->chanlist[i].scantime = dur;
+ i++;
+ }
+
+ kfree(hold);
+ return i;
+}
+
+static void libertas_parse_bssid(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ unsigned int mac[ETH_ALEN];
+ int i;
+
+ hold = strstr(buf, "bssid=");
+ if (!hold)
+ return;
+ hold += 6;
+ sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3,
+ mac+4, mac+5);
+ for(i=0;i<ETH_ALEN;i++)
+ scan_cfg->specificBSSID[i] = mac[i];
+}
+
+static void libertas_parse_ssid(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold, *end;
+ ssize_t size;
+
+ hold = strstr(buf, "ssid=");
+ if (!hold)
+ return;
+ hold += 5;
+ end = strstr(hold, " ");
+ if (!end)
+ end = buf + count - 1;
+
+ size = min(IW_ESSID_MAX_SIZE, end - hold);
+ strncpy(scan_cfg->specificSSID, hold, size);
+
+ return;
+}
+
+static void libertas_parse_keep(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "keep=");
+ if (!hold)
+ return;
+ hold += 5;
+ sscanf(hold, "%d", &val);
+
+ if (val != 0)
+ val = 1;
+
+ scan_cfg->keeppreviousscan = val;
+ return;
+}
+
+static int libertas_parse_dur(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "dur=");
+ if (!hold)
+ return 0;
+ hold += 4;
+ sscanf(hold, "%d", &val);
+
+ return val;
+}
+
+static void libertas_parse_probes(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "probes=");
+ if (!hold)
+ return;
+ hold += 7;
+ sscanf(hold, "%d", &val);
+
+ scan_cfg->numprobes = val;
+
+ return;
+}
+
+static void libertas_parse_type(char *buf, size_t count,
+ struct wlan_ioctl_user_scan_cfg *scan_cfg)
+{
+ char *hold;
+ int val;
+
+ hold = strstr(buf, "type=");
+ if (!hold)
+ return;
+ hold += 5;
+ sscanf(hold, "%d", &val);
+
+ /* type=1,2 or 3 */
+ if (val < 1 || val > 3)
+ return;
+
+ scan_cfg->bsstype = val;
+
+ return;
+}
+
+static ssize_t libertas_setuserscan(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ struct wlan_ioctl_user_scan_cfg *scan_cfg;
+ union iwreq_data wrqu;
+ int dur;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL);
+ if (!scan_cfg)
+ return -ENOMEM;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY;
+
+ dur = libertas_parse_dur(buf, count, scan_cfg);
+ libertas_parse_chan(buf, count, scan_cfg, dur);
+ libertas_parse_bssid(buf, count, scan_cfg);
+ libertas_parse_ssid(buf, count, scan_cfg);
+ libertas_parse_keep(buf, count, scan_cfg);
+ libertas_parse_probes(buf, count, scan_cfg);
+ libertas_parse_type(buf, count, scan_cfg);
+
+ wlan_scan_networks(priv, scan_cfg);
+ wait_event_interruptible(priv->adapter->cmd_pending,
+ !priv->adapter->nr_cmd_pending);
+
+ memset(&wrqu, 0x00, sizeof(union iwreq_data));
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL);
+
+out_unlock:
+ free_page(addr);
+ kfree(scan_cfg);
+ return count;
+}
+
+static int libertas_event_initcmd(wlan_private *priv, void **response_buf,
+ struct cmd_ctrl_node **cmdnode,
+ struct cmd_ds_command **cmd)
+{
+ u16 wait_option = cmd_option_waitforrsp;
+
+ if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
+ lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n");
+ return -ENOMEM;
+ }
+ if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) {
+ lbs_pr_debug(1, "failed to allocate response buffer!\n");
+ return -ENOMEM;
+ }
+ libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL);
+ init_waitqueue_head(&(*cmdnode)->cmdwait_q);
+ (*cmdnode)->pdata_buf = *response_buf;
+ (*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
+ (*cmdnode)->cmdwaitqwoken = 0;
+ *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
+ (*cmd)->command = cmd_802_11_subscribe_event;
+ (*cmd)->seqnum = ++priv->adapter->seqnum;
+ (*cmd)->result = 0;
+ return 0;
+}
+
+static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_rssithreshold *Lowrssi;
+ case TLV_TYPE_RSSI_LOW:
+ Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ Lowrssi->rssivalue,
+ Lowrssi->rssifreq,
+ (event->events & 0x0001)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static u16 libertas_get_events_bitmap(wlan_private *priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res;
+ u16 event_bitmap;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ return res;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ return 0;
+ }
+
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ event_bitmap = event->events;
+ kfree(response_buf);
+ return event_bitmap;
+}
+
+static ssize_t libertas_lowrssi_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_rssithreshold *rssi_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_rssithreshold));
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+ rssi_threshold->header.type = cpu_to_le16(0x0104);
+ rssi_threshold->header.len = 2;
+ rssi_threshold->rssivalue = cpu_to_le16(value);
+ rssi_threshold->rssifreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0001 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_snrthreshold *LowSnr;
+ case TLV_TYPE_SNR_LOW:
+ LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ LowSnr->snrvalue,
+ LowSnr->snrfreq,
+ (event->events & 0x0002)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_lowsnr_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_snrthreshold *snr_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_snrthreshold));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+ snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW);
+ snr_threshold->header.len = 2;
+ snr_threshold->snrvalue = cpu_to_le16(value);
+ snr_threshold->snrfreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0002 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_failurecount *failcount;
+ case TLV_TYPE_FAILCOUNT:
+ failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ failcount->failvalue,
+ failcount->Failfreq,
+ (event->events & 0x0004)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_failurecount);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_failcount_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_failurecount *failcount;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_failurecount));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ failcount = (struct mrvlietypes_failurecount *)(ptr);
+ failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT);
+ failcount->header.len = 2;
+ failcount->failvalue = cpu_to_le16(value);
+ failcount->Failfreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0004 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = (struct cmd_ds_command *)response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ free_page(addr);
+ kfree(response_buf);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ free_page(addr);
+ kfree(response_buf);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_beaconsmissed *bcnmiss;
+ case TLV_TYPE_BCNMISS:
+ bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d N/A %d\n",
+ bcnmiss->beaconmissed,
+ (event->events & 0x0008)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_beaconsmissed);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_bcnmiss_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_beaconsmissed *bcnmiss;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_beaconsmissed));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr);
+ bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS);
+ bcnmiss->header.len = 2;
+ bcnmiss->beaconmissed = cpu_to_le16(value);
+ event_bitmap |= subscribed ? 0x0008 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ free_page(addr);
+ kfree(response_buf);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_rssithreshold *Highrssi;
+ case TLV_TYPE_RSSI_HIGH:
+ Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ Highrssi->rssivalue,
+ Highrssi->rssifreq,
+ (event->events & 0x0010)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highrssi_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_rssithreshold *rssi_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_rssithreshold));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr);
+ rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH);
+ rssi_threshold->header.len = 2;
+ rssi_threshold->rssivalue = cpu_to_le16(value);
+ rssi_threshold->rssifreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0010 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ void *response_buf;
+ int res, cmd_len;
+ ssize_t pos = 0;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0) {
+ free_page(addr);
+ return res;
+ }
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_get;
+ pcmdptr->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN);
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN);
+ while (cmd_len < pcmdptr->size) {
+ struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len);
+ switch(header->type) {
+ struct mrvlietypes_snrthreshold *HighSnr;
+ case TLV_TYPE_SNR_HIGH:
+ HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len);
+ pos += snprintf(buf+pos, len-pos, "%d %d %d\n",
+ HighSnr->snrvalue,
+ HighSnr->snrfreq,
+ (event->events & 0x0020)?1:0);
+ default:
+ cmd_len += sizeof(struct mrvlietypes_snrthreshold);
+ break;
+ }
+ }
+
+ kfree(response_buf);
+
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_highsnr_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ ssize_t res, buf_size;
+ int value, freq, subscribed, cmd_len;
+ struct cmd_ctrl_node *pcmdnode;
+ struct cmd_ds_command *pcmdptr;
+ struct cmd_ds_802_11_subscribe_event *event;
+ struct mrvlietypes_snrthreshold *snr_threshold;
+ void *response_buf;
+ u16 event_bitmap;
+ u8 *ptr;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed);
+ if (res != 3) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ event_bitmap = libertas_get_events_bitmap(priv);
+
+ res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr);
+ if (res < 0)
+ goto out_unlock;
+
+ event = &pcmdptr->params.subscribe_event;
+ event->action = cmd_act_set;
+ pcmdptr->size = cpu_to_le16(S_DS_GEN +
+ sizeof(struct cmd_ds_802_11_subscribe_event) +
+ sizeof(struct mrvlietypes_snrthreshold));
+ cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event);
+ ptr = (u8*) pcmdptr+cmd_len;
+ snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr);
+ snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH);
+ snr_threshold->header.len = 2;
+ snr_threshold->snrvalue = cpu_to_le16(value);
+ snr_threshold->snrfreq = cpu_to_le16(freq);
+ event_bitmap |= subscribed ? 0x0020 : 0x0;
+ event->events = event_bitmap;
+
+ libertas_queue_cmd(adapter, pcmdnode, 1);
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ /* Sleep until response is generated by FW */
+ wait_event_interruptible(pcmdnode->cmdwait_q,
+ pcmdnode->cmdwaitqwoken);
+
+ pcmdptr = response_buf;
+
+ if (pcmdptr->result) {
+ lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__,
+ pcmdptr->result);
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+ lbs_pr_err("command response incorrect!\n");
+ kfree(response_buf);
+ free_page(addr);
+ return 0;
+ }
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ offval.offset = priv->mac_offset;
+ offval.value = 0;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_mac_reg_access, 0,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
+ priv->mac_offset, adapter->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+ return ret;
+}
+
+static ssize_t libertas_rdmac_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ priv->mac_offset = simple_strtoul((char *)buf, NULL, 16);
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_wrmac_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+ struct wlan_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%x %x", &offset, &value);
+ if (res != 2) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ offval.offset = offset;
+ offval.value = value;
+ res = libertas_prepare_and_send_command(priv,
+ cmd_mac_reg_access, 1,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ offval.offset = priv->bbp_offset;
+ offval.value = 0;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_bbp_reg_access, 0,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
+ priv->bbp_offset, adapter->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+
+ return ret;
+}
+
+static ssize_t libertas_rdbbp_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16);
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_wrbbp_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+ struct wlan_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%x %x", &offset, &value);
+ if (res != 2) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ offval.offset = offset;
+ offval.value = value;
+ res = libertas_prepare_and_send_command(priv,
+ cmd_bbp_reg_access, 1,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_offset_value offval;
+ ssize_t pos = 0;
+ int ret;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ offval.offset = priv->rf_offset;
+ offval.value = 0;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_rf_reg_access, 0,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+ pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
+ priv->rf_offset, adapter->offsetvalue.value);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
+ free_page(addr);
+
+ return ret;
+}
+
+static ssize_t libertas_rdrf_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ priv->rf_offset = simple_strtoul((char *)buf, NULL, 16);
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+static ssize_t libertas_wrrf_write(struct file *file,
+ const char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+
+ wlan_private *priv = file->private_data;
+ ssize_t res, buf_size;
+ u32 offset, value;
+ struct wlan_offset_value offval;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ buf_size = min(count, len - 1);
+ if (copy_from_user(buf, userbuf, buf_size)) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ res = sscanf(buf, "%x %x", &offset, &value);
+ if (res != 2) {
+ res = -EFAULT;
+ goto out_unlock;
+ }
+
+ offval.offset = offset;
+ offval.value = value;
+ res = libertas_prepare_and_send_command(priv,
+ cmd_rf_reg_access, 1,
+ cmd_option_waitforrsp, 0, &offval);
+ mdelay(10);
+
+ res = count;
+out_unlock:
+ free_page(addr);
+ return res;
+}
+
+#define FOPS(fread, fwrite) { \
+ .owner = THIS_MODULE, \
+ .open = open_file_generic, \
+ .read = (fread), \
+ .write = (fwrite), \
+}
+
+struct libertas_debugfs_files {
+ char *name;
+ int perm;
+ struct file_operations fops;
+};
+
+struct libertas_debugfs_files debugfs_files[] = {
+ { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), },
+ { "getscantable", 0444, FOPS(libertas_getscantable,
+ write_file_dummy), },
+ { "sleepparams", 0644, FOPS(libertas_sleepparams_read,
+ libertas_sleepparams_write), },
+ { "extscan", 0600, FOPS(NULL, libertas_extscan), },
+ { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), },
+};
+
+struct libertas_debugfs_files debugfs_events_files[] = {
+ {"low_rssi", 0644, FOPS(libertas_lowrssi_read,
+ libertas_lowrssi_write), },
+ {"low_snr", 0644, FOPS(libertas_lowsnr_read,
+ libertas_lowsnr_write), },
+ {"failure_count", 0644, FOPS(libertas_failcount_read,
+ libertas_failcount_write), },
+ {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read,
+ libertas_bcnmiss_write), },
+ {"high_rssi", 0644, FOPS(libertas_highrssi_read,
+ libertas_highrssi_write), },
+ {"high_snr", 0644, FOPS(libertas_highsnr_read,
+ libertas_highsnr_write), },
+};
+
+struct libertas_debugfs_files debugfs_regs_files[] = {
+ {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), },
+ {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), },
+ {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), },
+ {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), },
+ {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), },
+ {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), },
+};
+
+void libertas_debugfs_init(void)
+{
+ if (!libertas_dir)
+ libertas_dir = debugfs_create_dir("libertas_wireless", NULL);
+
+ return;
+}
+
+void libertas_debugfs_remove(void)
+{
+ if (libertas_dir)
+ debugfs_remove(libertas_dir);
+ return;
+}
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev)
+{
+ int i;
+ struct libertas_debugfs_files *files;
+ if (!libertas_dir)
+ goto exit;
+
+ priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir);
+ if (!priv->debugfs_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
+ files = &debugfs_files[i];
+ priv->debugfs_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->debugfs_dir,
+ priv,
+ &files->fops);
+ }
+
+ priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
+ if (!priv->events_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
+ files = &debugfs_events_files[i];
+ priv->debugfs_events_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->events_dir,
+ priv,
+ &files->fops);
+ }
+
+ priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
+ if (!priv->regs_dir)
+ goto exit;
+
+ for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
+ files = &debugfs_regs_files[i];
+ priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
+ files->perm,
+ priv->regs_dir,
+ priv,
+ &files->fops);
+ }
+
+#ifdef PROC_DEBUG
+ libertas_debug_init(priv, dev);
+#endif
+exit:
+ return;
+}
+
+void libertas_debugfs_remove_one(wlan_private *priv)
+{
+ int i;
+
+ for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
+ debugfs_remove(priv->debugfs_regs_files[i]);
+
+ debugfs_remove(priv->regs_dir);
+
+ for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+ debugfs_remove(priv->debugfs_events_files[i]);
+
+ debugfs_remove(priv->events_dir);
+#ifdef PROC_DEBUG
+ debugfs_remove(priv->debugfs_debug);
+#endif
+ for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
+ debugfs_remove(priv->debugfs_files[i]);
+}
+
+/* debug entry */
+
+#define item_size(n) (FIELD_SIZEOF(wlan_adapter, n))
+#define item_addr(n) (offsetof(wlan_adapter, n))
+
+struct debug_data {
+ char name[32];
+ u32 size;
+ u32 addr;
+};
+
+/* To debug any member of wlan_adapter, simply add one line here.
+ */
+static struct debug_data items[] = {
+ {"intcounter", item_size(intcounter), item_addr(intcounter)},
+ {"psmode", item_size(psmode), item_addr(psmode)},
+ {"psstate", item_size(psstate), item_addr(psstate)},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/**
+ * @brief proc read function
+ *
+ * @param page pointer to buffer
+ * @param s read data starting position
+ * @param off offset
+ * @param cnt counter
+ * @param eof end of file flag
+ * @param data data to output
+ * @return number of output data
+ */
+static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ int val = 0;
+ size_t pos = 0;
+ ssize_t res;
+ char *p;
+ int i;
+ struct debug_data *d;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *)addr;
+
+ p = buf;
+
+ d = (struct debug_data *)file->private_data;
+
+ for (i = 0; i < num_of_items; i++) {
+ if (d[i].size == 1)
+ val = *((u8 *) d[i].addr);
+ else if (d[i].size == 2)
+ val = *((u16 *) d[i].addr);
+ else if (d[i].size == 4)
+ val = *((u32 *) d[i].addr);
+
+ pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
+ }
+
+ res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
+
+ free_page(addr);
+ return res;
+}
+
+/**
+ * @brief proc write function
+ *
+ * @param f file pointer
+ * @param buf pointer to data buffer
+ * @param cnt data number to write
+ * @param data data to write
+ * @return number of data
+ */
+static int wlan_debugfs_write(struct file *f, const char __user *buf,
+ size_t cnt, loff_t *ppos)
+{
+ int r, i;
+ char *pdata;
+ char *p;
+ char *p0;
+ char *p1;
+ char *p2;
+ struct debug_data *d = (struct debug_data *)f->private_data;
+
+ pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+ if (pdata == NULL)
+ return 0;
+
+ if (copy_from_user(pdata, buf, cnt)) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ kfree(pdata);
+ return 0;
+ }
+
+ p0 = pdata;
+ for (i = 0; i < num_of_items; i++) {
+ do {
+ p = strstr(p0, d[i].name);
+ if (p == NULL)
+ break;
+ p1 = strchr(p, '\n');
+ if (p1 == NULL)
+ break;
+ p0 = p1++;
+ p2 = strchr(p, '=');
+ if (!p2)
+ break;
+ p2++;
+ r = simple_strtoul(p2, NULL, 0);
+ if (d[i].size == 1)
+ *((u8 *) d[i].addr) = (u8) r;
+ else if (d[i].size == 2)
+ *((u16 *) d[i].addr) = (u16) r;
+ else if (d[i].size == 4)
+ *((u32 *) d[i].addr) = (u32) r;
+ break;
+ } while (1);
+ }
+ kfree(pdata);
+
+ return cnt;
+}
+
+static struct file_operations libertas_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = open_file_generic,
+ .write = wlan_debugfs_write,
+ .read = wlan_debugfs_read,
+};
+
+/**
+ * @brief create debug proc file
+ *
+ * @param priv pointer wlan_private
+ * @param dev pointer net_device
+ * @return N/A
+ */
+void libertas_debug_init(wlan_private * priv, struct net_device *dev)
+{
+ int i;
+
+ if (!priv->debugfs_dir)
+ return;
+
+ for (i = 0; i < num_of_items; i++)
+ items[i].addr += (u32) priv->adapter;
+
+ priv->debugfs_debug = debugfs_create_file("debug", 0644,
+ priv->debugfs_dir, &items[0],
+ &libertas_debug_fops);
+}
+
+/**
+ * @brief remove proc file
+ *
+ * @param priv pointer wlan_private
+ * @return N/A
+ */
+void libertas_debug_remove(wlan_private * priv)
+{
+ debugfs_remove(priv->debugfs_debug);
+}
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h
new file mode 100644
index 00000000000..880a11b95d2
--- /dev/null
+++ b/drivers/net/wireless/libertas/debugfs.h
@@ -0,0 +1,6 @@
+void libertas_debugfs_init(void);
+void libertas_debugfs_remove(void);
+
+void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev);
+void libertas_debugfs_remove_one(wlan_private *priv);
+
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
new file mode 100644
index 00000000000..606bdd002be
--- /dev/null
+++ b/drivers/net/wireless/libertas/decl.h
@@ -0,0 +1,83 @@
+/**
+ * This file contains declaration referring to
+ * functions defined in other source files
+ */
+
+#ifndef _WLAN_DECL_H_
+#define _WLAN_DECL_H_
+
+#include "defs.h"
+
+/** Function Prototype Declaration */
+struct wlan_private;
+struct sk_buff;
+struct net_device;
+
+extern char *libertas_fw_name;
+
+void libertas_free_adapter(wlan_private * priv);
+int libertas_set_mac_packet_filter(wlan_private * priv);
+
+int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
+void libertas_send_tx_feedback(wlan_private * priv);
+u8 libertas_check_last_packet_indication(wlan_private * priv);
+
+int libertas_free_cmd_buffer(wlan_private * priv);
+struct cmd_ctrl_node;
+struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv);
+
+void libertas_set_cmd_ctrl_node(wlan_private * priv,
+ struct cmd_ctrl_node *ptempnode,
+ u32 cmd_oid, u16 wait_option, void *pdata_buf);
+
+int libertas_prepare_and_send_command(wlan_private * priv,
+ u16 cmd_no,
+ u16 cmd_action,
+ u16 wait_option, u32 cmd_oid, void *pdata_buf);
+
+void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail);
+
+int libertas_allocate_cmd_buffer(wlan_private * priv);
+int libertas_execute_next_command(wlan_private * priv);
+int libertas_process_event(wlan_private * priv);
+void libertas_interrupt(struct net_device *);
+int libertas_set_radio_control(wlan_private * priv);
+u32 libertas_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_index(u32 rate);
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
+
+/** The proc fs interface */
+int libertas_process_rx_command(wlan_private * priv);
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
+void libertas_cleanup_and_insert_cmd(wlan_private * priv,
+ struct cmd_ctrl_node *ptempcmd);
+void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
+ struct cmd_ctrl_node *ptempcmd);
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band);
+
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *);
+
+void libertas_ps_sleep(wlan_private * priv, int wait_option);
+void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode);
+void libertas_ps_wakeup(wlan_private * priv, int wait_option);
+
+void libertas_tx_runqueue(wlan_private *priv);
+
+extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel(
+ wlan_adapter * adapter, u8 band, u16 channel);
+
+extern void libertas_mac_event_disconnected(wlan_private * priv);
+
+void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
+
+int reset_device(wlan_private *priv);
+/* main.c */
+extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
+ int *cfp_no);
+wlan_private *wlan_add_card(void *card);
+int wlan_remove_card(void *card);
+
+#endif /* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
new file mode 100644
index 00000000000..fb1478c1b87
--- /dev/null
+++ b/drivers/net/wireless/libertas/defs.h
@@ -0,0 +1,369 @@
+/**
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
+#ifndef _WLAN_DEFS_H_
+#define _WLAN_DEFS_H_
+
+#include <linux/spinlock.h>
+
+extern unsigned int libertas_debug;
+
+#define DRV_NAME "usb8xxx"
+
+#define lbs_pr_info(format, args...) \
+ printk(KERN_INFO DRV_NAME": " format, ## args)
+#define lbs_pr_err(format, args...) \
+ printk(KERN_ERR DRV_NAME": " format, ## args)
+#define lbs_pr_alert(format, args...) \
+ printk(KERN_ALERT DRV_NAME": " format, ## args)
+
+#ifdef DEBUG
+#define lbs_pr_debug(level, format, args...) \
+ do { if (libertas_debug >= level) \
+ printk(KERN_INFO DRV_NAME": " format, ##args); } while (0)
+#define lbs_dev_dbg(level, device, format, args...) \
+ lbs_pr_debug(level, "%s: " format, \
+ (device)->bus_id , ## args)
+
+static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+{
+ int i = 0;
+
+ if (!libertas_debug)
+ return;
+
+ printk(KERN_DEBUG "%s: ", prompt);
+ for (i = 1; i <= len; i++) {
+ printk(KERN_DEBUG "%02x ", (u8) * buf);
+ buf++;
+ }
+ printk("\n");
+}
+#else
+#define lbs_pr_debug(level, format, args...) do {} while (0)
+#define lbs_dev_dbg(level, device, format, args...) do {} while (0)
+#define lbs_dbg_hex(x,y,z) do {} while (0)
+#endif
+
+#define ENTER() lbs_pr_debug(1, "Enter: %s, %s:%i\n", \
+ __FUNCTION__, __FILE__, __LINE__)
+#define LEAVE() lbs_pr_debug(1, "Leave: %s, %s:%i\n", \
+ __FUNCTION__, __FILE__, __LINE__)
+
+/** Buffer Constants */
+
+/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
+* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+* driver has more local TxPDs. Each TxPD on the host memory is associated
+* with a Tx control node. The driver maintains 8 RxPD descriptors for
+* station firmware to store Rx packet information.
+*
+* Current version of MAC has a 32x6 multicast address buffer.
+*
+* 802.11b can have up to 14 channels, the driver keeps the
+* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+*/
+
+#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
+#define MRVDRV_NUM_OF_CMD_BUFFER 10
+#define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024)
+#define MRVDRV_MAX_CHANNEL_SIZE 14
+#define MRVDRV_MAX_BSSID_LIST 64
+#define MRVDRV_ASSOCIATION_TIME_OUT 255
+#define MRVDRV_SNAP_HEADER_LEN 8
+
+#define WLAN_UPLD_SIZE 2312
+#define DEV_NAME_LEN 32
+
+/** Misc constants */
+/* This section defines 802.11 specific contants */
+
+#define MRVDRV_MAX_BSS_DESCRIPTS 16
+#define MRVDRV_MAX_REGION_CODE 6
+
+#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe
+#define MRVDRV_MIN_MULTIPLE_DTIM 1
+#define MRVDRV_MAX_MULTIPLE_DTIM 5
+#define MRVDRV_DEFAULT_MULTIPLE_DTIM 1
+
+#define MRVDRV_DEFAULT_LISTEN_INTERVAL 10
+
+#define MRVDRV_CHANNELS_PER_SCAN 4
+#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
+
+#define MRVDRV_DEBUG_RX_PATH 0x00000001
+#define MRVDRV_DEBUG_TX_PATH 0x00000002
+
+#define MRVDRV_MIN_BEACON_INTERVAL 20
+#define MRVDRV_MAX_BEACON_INTERVAL 1000
+#define MRVDRV_BEACON_INTERVAL 100
+
+/** TxPD status */
+
+/* Station firmware use TxPD status field to report final Tx transmit
+* result, Bit masks are used to present combined situations.
+*/
+
+#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+/** Tx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define TxPD_CONTROL_WDS_FRAME (1<<17)
+#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
+
+/** RxPD status */
+
+#define MRVDRV_RXPD_STATUS_OK 0x0001
+
+/** RxPD status - Received packet types */
+/** Rx mesh flag */
+/* Currently we are using normal WDS flag as mesh flag.
+ * TODO: change to proper mesh flag when MAC understands it.
+ */
+#define RxPD_CONTROL_WDS_FRAME (0x40)
+#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
+
+/** RSSI-related defines */
+/* RSSI constants are used to implement 802.11 RSSI threshold
+* indication. if the Rx packet signal got too weak for 5 consecutive
+* times, miniport driver (driver) will report this event to wrapper
+*/
+
+#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
+
+/** RTS/FRAG related defines */
+#define MRVDRV_RTS_MIN_VALUE 0
+#define MRVDRV_RTS_MAX_VALUE 2347
+#define MRVDRV_FRAG_MIN_VALUE 256
+#define MRVDRV_FRAG_MAX_VALUE 2346
+
+/* This is for firmware specific length */
+#define EXTRA_LEN 36
+
+#define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \
+ (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN)
+
+#define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \
+ (ETH_FRAME_LEN + sizeof(struct rxpd) \
+ + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN)
+
+#define CMD_F_HOSTCMD (1 << 0)
+#define FW_CAPINFO_WPA (1 << 0)
+
+/** WPA key LENGTH*/
+#define MRVL_MAX_KEY_WPA_KEY_LENGTH 32
+
+#define KEY_LEN_WPA_AES 16
+#define KEY_LEN_WPA_TKIP 32
+#define KEY_LEN_WEP_104 13
+#define KEY_LEN_WEP_40 5
+
+#define RF_ANTENNA_1 0x1
+#define RF_ANTENNA_2 0x2
+#define RF_ANTENNA_AUTO 0xFFFF
+
+#define BAND_B (0x01)
+#define BAND_G (0x02)
+#define ALL_802_11_BANDS (BAND_B | BAND_G)
+
+/** MACRO DEFINITIONS */
+#define CAL_NF(NF) ((s32)(-(s32)(NF)))
+#define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF)))
+#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
+
+#define DEFAULT_BCN_AVG_FACTOR 8
+#define DEFAULT_DATA_AVG_FACTOR 8
+#define AVG_SCALE 100
+#define CAL_AVG_SNR_NF(AVG, SNRNF, N) \
+ (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \
+ ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
+ AVG_SCALE)) / N))
+
+#define B_SUPPORTED_RATES 8
+#define G_SUPPORTED_RATES 14
+
+#define WLAN_SUPPORTED_RATES 14
+
+#define MAX_LEDS 8
+
+#define IS_MESH_FRAME(x) (x->cb[6])
+#define SET_MESH_FRAME(x) (x->cb[6]=1)
+#define UNSET_MESH_FRAME(x) (x->cb[6]=0)
+
+/** Global Variable Declaration */
+typedef struct _wlan_private wlan_private;
+typedef struct _wlan_adapter wlan_adapter;
+extern const char libertas_driver_version[];
+extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
+
+extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES];
+
+extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
+
+extern u8 libertas_adhoc_rates_b[4];
+
+/** ENUM definition*/
+/** SNRNF_TYPE */
+enum SNRNF_TYPE {
+ TYPE_BEACON = 0,
+ TYPE_RXPD,
+ MAX_TYPE_B
+};
+
+/** SNRNF_DATA*/
+enum SNRNF_DATA {
+ TYPE_NOAVG = 0,
+ TYPE_AVG,
+ MAX_TYPE_AVG
+};
+
+/** WLAN_802_11_AUTH_ALG*/
+enum WLAN_802_11_AUTH_ALG {
+ AUTH_ALG_OPEN_SYSTEM = 1,
+ AUTH_ALG_SHARED_KEY = 2,
+ AUTH_ALG_NETWORK_EAP = 8,
+};
+
+/** WLAN_802_1X_AUTH_ALG */
+enum WLAN_802_1X_AUTH_ALG {
+ WLAN_1X_AUTH_ALG_NONE = 1,
+ WLAN_1X_AUTH_ALG_LEAP = 2,
+ WLAN_1X_AUTH_ALG_TLS = 4,
+ WLAN_1X_AUTH_ALG_TTLS = 8,
+ WLAN_1X_AUTH_ALG_MD5 = 16,
+};
+
+/** WLAN_802_11_ENCRYPTION_MODE */
+enum WLAN_802_11_ENCRYPTION_MODE {
+ CIPHER_NONE,
+ CIPHER_WEP40,
+ CIPHER_TKIP,
+ CIPHER_CCMP,
+ CIPHER_WEP104,
+};
+
+/** WLAN_802_11_POWER_MODE */
+enum WLAN_802_11_POWER_MODE {
+ wlan802_11powermodecam,
+ wlan802_11powermodemax_psp,
+ wlan802_11Powermodefast_psp,
+ /*not a real mode, defined as an upper bound */
+ wlan802_11powemodemax
+};
+
+/** PS_STATE */
+enum PS_STATE {
+ PS_STATE_FULL_POWER,
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP
+};
+
+/** DNLD_STATE */
+enum DNLD_STATE {
+ DNLD_RES_RECEIVED,
+ DNLD_DATA_SENT,
+ DNLD_CMD_SENT
+};
+
+/** WLAN_MEDIA_STATE */
+enum WLAN_MEDIA_STATE {
+ libertas_connected,
+ libertas_disconnected
+};
+
+/** WLAN_802_11_PRIVACY_FILTER */
+enum WLAN_802_11_PRIVACY_FILTER {
+ wlan802_11privfilteracceptall,
+ wlan802_11privfilter8021xWEP
+};
+
+/** mv_ms_type */
+enum mv_ms_type {
+ MVMS_DAT = 0,
+ MVMS_CMD = 1,
+ MVMS_TXDONE = 2,
+ MVMS_EVENT
+};
+
+/** WLAN_802_11_NETWORK_INFRASTRUCTURE */
+enum WLAN_802_11_NETWORK_INFRASTRUCTURE {
+ wlan802_11ibss,
+ wlan802_11infrastructure,
+ wlan802_11autounknown,
+ /*defined as upper bound */
+ wlan802_11infrastructuremax
+};
+
+/** WLAN_802_11_AUTHENTICATION_MODE */
+enum WLAN_802_11_AUTHENTICATION_MODE {
+ wlan802_11authmodeopen = 0x00,
+ wlan802_11authmodeshared = 0x01,
+ wlan802_11authmodenetworkEAP = 0x80,
+};
+
+/** WLAN_802_11_WEP_STATUS */
+enum WLAN_802_11_WEP_STATUS {
+ wlan802_11WEPenabled,
+ wlan802_11WEPdisabled,
+};
+
+/** SNMP_MIB_INDEX_e */
+enum SNMP_MIB_INDEX_e {
+ desired_bsstype_i = 0,
+ op_rateset_i,
+ bcnperiod_i,
+ dtimperiod_i,
+ assocrsp_timeout_i,
+ rtsthresh_i,
+ short_retrylim_i,
+ long_retrylim_i,
+ fragthresh_i,
+ dot11d_i,
+ dot11h_i,
+ manufid_i,
+ prodID_i,
+ manuf_oui_i,
+ manuf_name_i,
+ manuf_prodname_i,
+ manuf_prodver_i,
+};
+
+/** KEY_TYPE_ID */
+enum KEY_TYPE_ID {
+ KEY_TYPE_ID_WEP = 0,
+ KEY_TYPE_ID_TKIP,
+ KEY_TYPE_ID_AES
+};
+
+/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+enum KEY_INFO_WPA {
+ KEY_INFO_WPA_MCAST = 0x01,
+ KEY_INFO_WPA_UNICAST = 0x02,
+ KEY_INFO_WPA_ENABLED = 0x04
+};
+
+/** SNMP_MIB_VALUE_e */
+enum SNMP_MIB_VALUE_e {
+ SNMP_MIB_VALUE_INFRA = 1,
+ SNMP_MIB_VALUE_ADHOC
+};
+
+/* Default values for fwt commands. */
+#define FWT_DEFAULT_METRIC 0
+#define FWT_DEFAULT_DIR 1
+#define FWT_DEFAULT_SSN 0xffffffff
+#define FWT_DEFAULT_DSN 0
+#define FWT_DEFAULT_HOPCOUNT 0
+#define FWT_DEFAULT_TTL 0
+#define FWT_DEFAULT_EXPIRATION 0
+#define FWT_DEFAULT_SLEEPMODE 0
+#define FWT_DEFAULT_SNR 0
+
+#endif /* _WLAN_DEFS_H_ */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
new file mode 100644
index 00000000000..b1f876f9693
--- /dev/null
+++ b/drivers/net/wireless/libertas/dev.h
@@ -0,0 +1,403 @@
+/**
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure wlan_adapter.
+ */
+#ifndef _WLAN_DEV_H_
+#define _WLAN_DEV_H_
+
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/ethtool.h>
+#include <linux/debugfs.h>
+
+#include "defs.h"
+#include "scan.h"
+#include "thread.h"
+
+extern struct ethtool_ops libertas_ethtool_ops;
+
+#define MAX_BSSID_PER_CHANNEL 16
+
+#define NR_TX_QUEUE 3
+
+/* For the extended Scan */
+#define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \
+ MRVDRV_MAX_CHANNEL_SIZE + 1
+
+#define MAX_REGION_CHANNEL_NUM 2
+
+/** Chan-freq-TxPower mapping table*/
+struct chan_freq_power {
+ /** channel Number */
+ u16 channel;
+ /** frequency of this channel */
+ u32 freq;
+ /** Max allowed Tx power level */
+ u16 maxtxpower;
+ /** TRUE:channel unsupported; FLASE:supported*/
+ u8 unsupported;
+};
+
+/** region-band mapping table*/
+struct region_channel {
+ /** TRUE if this entry is valid */
+ u8 valid;
+ /** region code for US, Japan ... */
+ u8 region;
+ /** band B/G/A, used for BAND_CONFIG cmd */
+ u8 band;
+ /** Actual No. of elements in the array below */
+ u8 nrcfp;
+ /** chan-freq-txpower mapping table*/
+ struct chan_freq_power *CFP;
+};
+
+struct wlan_802_11_security {
+ u8 WPAenabled;
+ u8 WPA2enabled;
+ enum WLAN_802_11_WEP_STATUS WEPstatus;
+ enum WLAN_802_11_AUTHENTICATION_MODE authmode;
+ enum WLAN_802_1X_AUTH_ALG auth1xalg;
+ enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode;
+};
+
+/** Current Basic Service Set State Structure */
+struct current_bss_params {
+ struct bss_descriptor bssdescriptor;
+ /** bssid */
+ u8 bssid[ETH_ALEN];
+ /** ssid */
+ struct WLAN_802_11_SSID ssid;
+
+ /** band */
+ u8 band;
+ /** channel */
+ u8 channel;
+ /** number of rates supported */
+ int numofrates;
+ /** supported rates*/
+ u8 datarates[WLAN_SUPPORTED_RATES];
+};
+
+/** sleep_params */
+struct sleep_params {
+ u16 sp_error;
+ u16 sp_offset;
+ u16 sp_stabletime;
+ u8 sp_calcontrol;
+ u8 sp_extsleepclk;
+ u16 sp_reserved;
+};
+
+/** Data structure for the Marvell WLAN device */
+typedef struct _wlan_dev {
+ /** device name */
+ char name[DEV_NAME_LEN];
+ /** card pointer */
+ void *card;
+ /** IO port */
+ u32 ioport;
+ /** Upload received */
+ u32 upld_rcv;
+ /** Upload type */
+ u32 upld_typ;
+ /** Upload length */
+ u32 upld_len;
+ /** netdev pointer */
+ struct net_device *netdev;
+ /* Upload buffer */
+ u8 upld_buf[WLAN_UPLD_SIZE];
+ /* Download sent:
+ bit0 1/0=data_sent/data_tx_done,
+ bit1 1/0=cmd_sent/cmd_tx_done,
+ all other bits reserved 0 */
+ u8 dnld_sent;
+} wlan_dev_t, *pwlan_dev_t;
+
+/* Mesh statistics */
+struct wlan_mesh_stats {
+ u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */
+ u32 fwd_unicast_cnt; /* Fwd: Unicast counter */
+ u32 fwd_drop_ttl; /* Fwd: TTL zero */
+ u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */
+ u32 fwd_drop_noroute; /* Fwd: No route to Destination */
+ u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */
+ u32 drop_blind; /* Rx: Dropped by blinding table */
+};
+
+/** Private structure for the MV device */
+struct _wlan_private {
+ int open;
+ int mesh_open;
+ int infra_open;
+
+ wlan_adapter *adapter;
+ wlan_dev_t wlan_dev;
+
+ struct net_device_stats stats;
+ struct net_device *mesh_dev ; /* Virtual device */
+
+ struct iw_statistics wstats;
+ struct wlan_mesh_stats mstats;
+ struct dentry *debugfs_dir;
+ struct dentry *debugfs_debug;
+ struct dentry *debugfs_files[6];
+
+ struct dentry *events_dir;
+ struct dentry *debugfs_events_files[6];
+
+ struct dentry *regs_dir;
+ struct dentry *debugfs_regs_files[6];
+
+ u32 mac_offset;
+ u32 bbp_offset;
+ u32 rf_offset;
+
+ const struct firmware *firmware;
+ struct device *hotplug_device;
+
+ /** thread to service interrupts */
+ struct wlan_thread mainthread;
+
+ struct delayed_work assoc_work;
+ struct workqueue_struct *assoc_thread;
+};
+
+/** Association request
+ *
+ * Encapsulates all the options that describe a specific assocation request
+ * or configuration of the wireless card's radio, mode, and security settings.
+ */
+struct assoc_request {
+#define ASSOC_FLAG_SSID 1
+#define ASSOC_FLAG_CHANNEL 2
+#define ASSOC_FLAG_MODE 3
+#define ASSOC_FLAG_BSSID 4
+#define ASSOC_FLAG_WEP_KEYS 5
+#define ASSOC_FLAG_WEP_TX_KEYIDX 6
+#define ASSOC_FLAG_WPA_MCAST_KEY 7
+#define ASSOC_FLAG_WPA_UCAST_KEY 8
+#define ASSOC_FLAG_SECINFO 9
+#define ASSOC_FLAG_WPA_IE 10
+ unsigned long flags;
+
+ struct WLAN_802_11_SSID ssid;
+ u8 channel;
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode;
+ u8 bssid[ETH_ALEN];
+
+ /** WEP keys */
+ struct WLAN_802_11_KEY wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+ struct WLAN_802_11_KEY wpa_mcast_key;
+ struct WLAN_802_11_KEY wpa_unicast_key;
+
+ struct wlan_802_11_security secinfo;
+
+ /** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+};
+
+/** Wlan adapter data structure*/
+struct _wlan_adapter {
+ /** STATUS variables */
+ u32 fwreleasenumber;
+ u32 fwcapinfo;
+ /* protected with big lock */
+
+ struct mutex lock;
+
+ u8 tmptxbuf[WLAN_UPLD_SIZE];
+ /* protected by hard_start_xmit serialization */
+
+ /** command-related variables */
+ u16 seqnum;
+ /* protected by big lock */
+
+ struct cmd_ctrl_node *cmd_array;
+ /** Current command */
+ struct cmd_ctrl_node *cur_cmd;
+ int cur_cmd_retcode;
+ /** command Queues */
+ /** Free command buffers */
+ struct list_head cmdfreeq;
+ /** Pending command buffers */
+ struct list_head cmdpendingq;
+
+ wait_queue_head_t cmd_pending;
+ u8 nr_cmd_pending;
+ /* command related variables protected by adapter->driver_lock */
+
+ /** Async and Sync Event variables */
+ u32 intcounter;
+ u32 eventcause;
+ u8 nodename[16]; /* nickname */
+
+ /** spin locks */
+ spinlock_t driver_lock;
+
+ /** Timers */
+ struct timer_list command_timer;
+
+ /* TX queue used in PS mode */
+ spinlock_t txqueue_lock;
+ struct sk_buff *tx_queue_ps[NR_TX_QUEUE];
+ unsigned int tx_queue_idx;
+
+ u8 hisregcpy;
+
+ /** current ssid/bssid related parameters*/
+ struct current_bss_params curbssparams;
+
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+
+ struct bss_descriptor *pattemptedbssdesc;
+
+ struct WLAN_802_11_SSID previousssid;
+ u8 previousbssid[ETH_ALEN];
+
+ struct bss_descriptor *scantable;
+ u32 numinscantable;
+
+ u8 scantype;
+ u32 scanmode;
+
+ u16 beaconperiod;
+ u8 adhoccreate;
+
+ /** capability Info used in Association, start, join */
+ struct ieeetypes_capinfo capinfo;
+
+ /** MAC address information */
+ u8 current_addr[ETH_ALEN];
+ u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+ u32 nr_of_multicastmacaddr;
+
+ /** 802.11 statistics */
+// struct cmd_DS_802_11_GET_STAT wlan802_11Stat;
+
+ u16 enablehwauto;
+ u16 ratebitmap;
+ /** control G rates */
+ u8 adhoc_grate_enabled;
+
+ u32 txantenna;
+ u32 rxantenna;
+
+ u8 adhocchannel;
+ u32 fragthsd;
+ u32 rtsthsd;
+
+ u32 datarate;
+ u8 is_datarate_auto;
+
+ u16 listeninterval;
+ u16 prescan;
+ u8 txretrycount;
+
+ /** Tx-related variables (for single packet tx) */
+ struct sk_buff *currenttxskb;
+ u16 TxLockFlag;
+
+ /** NIC Operation characteristics */
+ u16 currentpacketfilter;
+ u32 connect_status;
+ u16 regioncode;
+ u16 regiontableindex;
+ u16 txpowerlevel;
+
+ /** POWER MANAGEMENT AND PnP SUPPORT */
+ u8 surpriseremoved;
+ u16 atimwindow;
+
+ u16 psmode; /* Wlan802_11PowermodeCAM=disable
+ Wlan802_11PowermodeMAX_PSP=enable */
+ u16 multipledtim;
+ u32 psstate;
+ u8 needtowakeup;
+
+ struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
+ u16 locallisteninterval;
+ u16 nullpktinterval;
+
+ struct assoc_request * assoc_req;
+
+ /** Encryption parameter */
+ struct wlan_802_11_security secinfo;
+
+ /** WEP keys */
+ struct WLAN_802_11_KEY wep_keys[4];
+ u16 wep_tx_keyidx;
+
+ /** WPA keys */
+ struct WLAN_802_11_KEY wpa_mcast_key;
+ struct WLAN_802_11_KEY wpa_unicast_key;
+
+ /** WPA Information Elements*/
+#define MAX_WPA_IE_LEN 64
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ u8 wpa_ie_len;
+
+ u16 rxantennamode;
+ u16 txantennamode;
+
+ /** Requested Signal Strength*/
+ u16 bcn_avg_factor;
+ u16 data_avg_factor;
+ u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
+ u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
+ u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
+ u8 rawSNR[DEFAULT_DATA_AVG_FACTOR];
+ u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
+ u16 nextSNRNF;
+ u16 numSNRNF;
+ u16 rxpd_rate;
+
+ u8 radioon;
+ u32 preamble;
+
+ /** Multi bands Parameter*/
+ u8 libertas_supported_rates[G_SUPPORTED_RATES];
+
+ /** Blue Tooth Co-existence Arbitration */
+
+ /** sleep_params */
+ struct sleep_params sp;
+
+ /** RF calibration data */
+
+#define MAX_REGION_CHANNEL_NUM 2
+ /** region channel data */
+ struct region_channel region_channel[MAX_REGION_CHANNEL_NUM];
+
+ struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM];
+
+ /** 11D and Domain Regulatory Data */
+ struct wlan_802_11d_domain_reg domainreg;
+ struct parsed_region_chan_11d parsed_region_chan;
+
+ /** FSM variable for 11d support */
+ u32 enable11d;
+
+ /** MISCELLANEOUS */
+ u8 *prdeeprom;
+ struct wlan_offset_value offsetvalue;
+
+ struct cmd_ds_802_11_get_log logmsg;
+ u16 scanprobes;
+
+ u32 pkttxctrl;
+
+ u16 txrate;
+ u32 linkmode;
+ u32 radiomode;
+ u32 debugmode;
+ u8 fw_ready;
+};
+
+#endif /* _WLAN_DEV_H_ */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
new file mode 100644
index 00000000000..0064de54296
--- /dev/null
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -0,0 +1,184 @@
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+static const char * mesh_stat_strings[]= {
+ "drop_duplicate_bcast",
+ "drop_ttl_zero",
+ "drop_no_fwd_route",
+ "drop_no_buffers",
+ "fwded_unicast_cnt",
+ "fwded_bcast_cnt",
+ "drop_blind_table"
+};
+
+static void libertas_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+ char fwver[32];
+
+ libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1);
+
+ strcpy(info->driver, "libertas");
+ strcpy(info->version, libertas_driver_version);
+ strcpy(info->fw_version, fwver);
+}
+
+/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+ * In case that changes this needs fixing.
+ */
+#define LIBERTAS_EEPROM_LEN 16384
+
+static int libertas_ethtool_get_eeprom_len(struct net_device *dev)
+{
+ return LIBERTAS_EEPROM_LEN;
+}
+
+static int libertas_ethtool_get_eeprom(struct net_device *dev,
+ struct ethtool_eeprom *eeprom, u8 * bytes)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_ioctl_regrdwr regctrl;
+ char *ptr;
+ int ret;
+
+ regctrl.action = 0;
+ regctrl.offset = eeprom->offset;
+ regctrl.NOB = eeprom->len;
+
+ if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN)
+ return -EINVAL;
+
+// mutex_lock(&priv->mutex);
+
+ adapter->prdeeprom =
+ (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+ if (!adapter->prdeeprom)
+ return -ENOMEM;
+ memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
+
+ /* +14 is for action, offset, and NOB in
+ * response */
+ lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n",
+ regctrl.action, regctrl.offset, regctrl.NOB);
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_eeprom_access,
+ regctrl.action,
+ cmd_option_waitforrsp, 0,
+ &regctrl);
+
+ if (ret) {
+ if (adapter->prdeeprom)
+ kfree(adapter->prdeeprom);
+ LEAVE();
+ return ret;
+ }
+
+ mdelay(10);
+
+ ptr = (char *)adapter->prdeeprom;
+
+ /* skip the command header, but include the "value" u32 variable */
+ ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4;
+
+ /*
+ * Return the result back to the user
+ */
+ memcpy(bytes, ptr, eeprom->len);
+
+ if (adapter->prdeeprom)
+ kfree(adapter->prdeeprom);
+// mutex_unlock(&priv->mutex);
+
+ return 0;
+}
+
+static void libertas_ethtool_get_stats(struct net_device * dev,
+ struct ethtool_stats * stats, u64 * data)
+{
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ stats->cmd = ETHTOOL_GSTATS;
+ BUG_ON(stats->n_stats != MESH_STATS_NUM);
+
+ data[0] = priv->mstats.fwd_drop_rbt;
+ data[1] = priv->mstats.fwd_drop_ttl;
+ data[2] = priv->mstats.fwd_drop_noroute;
+ data[3] = priv->mstats.fwd_drop_nobuf;
+ data[4] = priv->mstats.fwd_unicast_cnt;
+ data[5] = priv->mstats.fwd_bcast_cnt;
+ data[6] = priv->mstats.drop_blind;
+
+ LEAVE();
+}
+
+static int libertas_ethtool_get_stats_count(struct net_device * dev)
+{
+ int ret;
+ wlan_private *priv = dev->priv;
+ struct cmd_ds_mesh_access mesh_access;
+
+ ENTER();
+ /* Get Mesh Statistics */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_mesh_access, cmd_act_mesh_get_stats,
+ cmd_option_waitforrsp, 0, &mesh_access);
+
+ if (ret) {
+ LEAVE();
+ return 0;
+ }
+
+ priv->mstats.fwd_drop_rbt = mesh_access.data[0];
+ priv->mstats.fwd_drop_ttl = mesh_access.data[1];
+ priv->mstats.fwd_drop_noroute = mesh_access.data[2];
+ priv->mstats.fwd_drop_nobuf = mesh_access.data[3];
+ priv->mstats.fwd_unicast_cnt = mesh_access.data[4];
+ priv->mstats.fwd_bcast_cnt = mesh_access.data[5];
+ priv->mstats.drop_blind = mesh_access.data[6];
+
+ LEAVE();
+ return MESH_STATS_NUM;
+}
+
+static void libertas_ethtool_get_strings (struct net_device * dev,
+ u32 stringset,
+ u8 * s)
+{
+ int i;
+
+ ENTER();
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i=0; i < MESH_STATS_NUM; i++) {
+ memcpy(s + i * ETH_GSTRING_LEN,
+ mesh_stat_strings[i],
+ ETH_GSTRING_LEN);
+ }
+ break;
+ }
+ LEAVE();
+}
+
+struct ethtool_ops libertas_ethtool_ops = {
+ .get_drvinfo = libertas_ethtool_get_drvinfo,
+ .get_eeprom = libertas_ethtool_get_eeprom,
+ .get_eeprom_len = libertas_ethtool_get_eeprom_len,
+ .get_stats_count = libertas_ethtool_get_stats_count,
+ .get_ethtool_stats = libertas_ethtool_get_stats,
+ .get_strings = libertas_ethtool_get_strings,
+};
+
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
new file mode 100644
index 00000000000..b194a457079
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.c
@@ -0,0 +1,361 @@
+/**
+ * This file contains the initialization for FW and HW
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/vmalloc.h>
+#include <linux/firmware.h>
+#include <linux/version.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "defs.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "if_usb.h"
+
+char *libertas_fw_name = NULL;
+module_param_named(fw_name, libertas_fw_name, charp, 0644);
+
+unsigned int libertas_debug = 0;
+module_param(libertas_debug, int, 0);
+
+/**
+ * @brief This function checks the validity of Boot2/FW image.
+ *
+ * @param data pointer to image
+ * len image length
+ * @return 0 or -1
+ */
+static int check_fwfile_format(u8 *data, u32 totlen)
+{
+ u8 bincmd, exit;
+ u32 blksize, offset, len;
+ int ret;
+
+ ret = 1;
+ exit = len = 0;
+
+ do {
+ bincmd = *data;
+ blksize = *(u32*)(data + offsetof(struct fwheader, datalength));
+ switch (bincmd) {
+ case FW_HAS_DATA_TO_RECV:
+ offset = sizeof(struct fwheader) + blksize;
+ data += offset;
+ len += offset;
+ if (len >= totlen)
+ exit = 1;
+ break;
+ case FW_HAS_LAST_BLOCK:
+ exit = 1;
+ ret = 0;
+ break;
+ default:
+ exit = 1;
+ break;
+ }
+ } while (!exit);
+
+ if (ret)
+ lbs_pr_err("bin file format check FAIL...\n");
+ else
+ lbs_pr_debug(1, "bin file format check PASS...\n");
+
+ return ret;
+}
+
+/**
+ * @brief This function downloads firmware image, gets
+ * HW spec from firmware and set basic parameters to
+ * firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 or -1
+ */
+static int wlan_setup_station_hw(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if ((ret = request_firmware(&priv->firmware, libertas_fw_name,
+ priv->hotplug_device)) < 0) {
+ lbs_pr_err("request_firmware() failed, error code = %#x\n",
+ ret);
+ lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name);
+ goto done;
+ }
+
+ if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
+ release_firmware(priv->firmware);
+ goto done;
+ }
+
+ ret = libertas_sbi_prog_firmware(priv);
+
+ release_firmware(priv->firmware);
+
+ if (ret) {
+ lbs_pr_debug(1, "Bootloader in invalid state!\n");
+ ret = -1;
+ goto done;
+ }
+
+ /*
+ * Read MAC address from HW
+ */
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
+ 0, cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ libertas_set_mac_packet_filter(priv);
+
+ /* Get the supported Data rates */
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+ cmd_act_get_tx_rate,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+done:
+ LEAVE();
+
+ return (ret);
+}
+
+static int wlan_allocate_adapter(wlan_private * priv)
+{
+ u32 ulbufsize;
+ wlan_adapter *adapter = priv->adapter;
+
+ struct bss_descriptor *ptempscantable;
+
+ /* Allocate buffer to store the BSSID list */
+ ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST;
+ if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) {
+ libertas_free_adapter(priv);
+ return -1;
+ }
+
+ adapter->scantable = ptempscantable;
+ memset(adapter->scantable, 0, ulbufsize);
+
+ /* Allocate the command buffers */
+ libertas_allocate_cmd_buffer(priv);
+
+ memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+ adapter->libertas_ps_confirm_sleep.command =
+ cpu_to_le16(cmd_802_11_ps_mode);
+ adapter->libertas_ps_confirm_sleep.size =
+ cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+ adapter->libertas_ps_confirm_sleep.result = 0;
+ adapter->libertas_ps_confirm_sleep.action =
+ cpu_to_le16(cmd_subcmd_sleep_confirmed);
+
+ return 0;
+}
+
+static void wlan_init_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+
+ adapter->scanprobes = 0;
+
+ adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ /* ATIM params */
+ adapter->atimwindow = 0;
+
+ adapter->connect_status = libertas_disconnected;
+ memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+ /* scan type */
+ adapter->scantype = cmd_scan_type_active;
+
+ /* scan mode */
+ adapter->scanmode = cmd_bss_type_any;
+
+ /* 802.11 specific */
+ adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
+ i++)
+ memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
+ adapter->wep_tx_keyidx = 0;
+ adapter->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ adapter->secinfo.authmode = wlan802_11authmodeopen;
+ adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE;
+ adapter->secinfo.Encryptionmode = CIPHER_NONE;
+ adapter->inframode = wlan802_11infrastructure;
+
+ adapter->assoc_req = NULL;
+
+ adapter->numinscantable = 0;
+ adapter->pattemptedbssdesc = NULL;
+ mutex_init(&adapter->lock);
+
+ adapter->prescan = 1;
+
+ memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
+
+ /* PnP and power profile */
+ adapter->surpriseremoved = 0;
+
+ adapter->currentpacketfilter =
+ cmd_act_mac_rx_on | cmd_act_mac_tx_on;
+
+ adapter->radioon = RADIO_ON;
+ adapter->txantenna = RF_ANTENNA_2;
+ adapter->rxantenna = RF_ANTENNA_AUTO;
+
+ adapter->is_datarate_auto = 1;
+ adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
+
+ // set default value of capinfo.
+#define SHORT_PREAMBLE_ALLOWED 1
+ memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
+ adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
+
+ adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+
+ adapter->psmode = wlan802_11powermodecam;
+ adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
+
+ adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
+
+ adapter->psstate = PS_STATE_FULL_POWER;
+ adapter->needtowakeup = 0;
+ adapter->locallisteninterval = 0; /* default value in firmware will be used */
+
+ adapter->datarate = 0; // Initially indicate the rate as auto
+
+ adapter->adhoc_grate_enabled = 0;
+
+ adapter->intcounter = 0;
+
+ adapter->currenttxskb = NULL;
+ adapter->pkttxctrl = 0;
+
+ memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+ adapter->tx_queue_idx = 0;
+ spin_lock_init(&adapter->txqueue_lock);
+
+ return;
+}
+
+static void command_timer_fn(unsigned long data);
+
+int libertas_init_fw(wlan_private * priv)
+{
+ int ret = -1;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* Allocate adapter structure */
+ if ((ret = wlan_allocate_adapter(priv)) != 0)
+ goto done;
+
+ /* init adapter structure */
+ wlan_init_adapter(priv);
+
+ /* init timer etc. */
+ setup_timer(&adapter->command_timer, command_timer_fn,
+ (unsigned long)priv);
+
+ /* download fimrware etc. */
+ if ((ret = wlan_setup_station_hw(priv)) != 0) {
+ del_timer_sync(&adapter->command_timer);
+ goto done;
+ }
+
+ /* init 802.11d */
+ libertas_init_11d(priv);
+
+ ret = 0;
+done:
+ LEAVE();
+ return ret;
+}
+
+void libertas_free_adapter(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ if (!adapter) {
+ lbs_pr_debug(1, "Why double free adapter?:)\n");
+ return;
+ }
+
+ lbs_pr_debug(1, "Free command buffer\n");
+ libertas_free_cmd_buffer(priv);
+
+ lbs_pr_debug(1, "Free commandTimer\n");
+ del_timer(&adapter->command_timer);
+
+ lbs_pr_debug(1, "Free scantable\n");
+ if (adapter->scantable) {
+ kfree(adapter->scantable);
+ adapter->scantable = NULL;
+ }
+
+ lbs_pr_debug(1, "Free adapter\n");
+
+ /* Free the adapter object itself */
+ kfree(adapter);
+ priv->adapter = NULL;
+}
+
+/**
+ * This function handles the timeout of command sending.
+ * It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+ wlan_private *priv = (wlan_private *)data;
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *ptempnode;
+ struct cmd_ds_command *cmd;
+ unsigned long flags;
+
+ ptempnode = adapter->cur_cmd;
+ cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+
+ lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command);
+
+ if (!adapter->fw_ready)
+ return;
+
+ if (ptempnode == NULL) {
+ lbs_pr_debug(1, "PTempnode Empty\n");
+ return;
+ }
+
+ spin_lock_irqsave(&adapter->driver_lock, flags);
+ adapter->cur_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+ lbs_pr_debug(1, "Re-sending same command as it timeout...!\n");
+ libertas_queue_cmd(adapter, ptempnode, 0);
+
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ return;
+}
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h
new file mode 100644
index 00000000000..1f9ae267a9e
--- /dev/null
+++ b/drivers/net/wireless/libertas/fw.h
@@ -0,0 +1,13 @@
+/**
+ * This header file contains FW interface related definitions.
+ */
+#ifndef _WLAN_FW_H_
+#define _WLAN_FW_H_
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+int libertas_init_fw(wlan_private * priv);
+
+#endif /* _WLAN_FW_H_ */
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
new file mode 100644
index 00000000000..c0faaecaf5b
--- /dev/null
+++ b/drivers/net/wireless/libertas/host.h
@@ -0,0 +1,338 @@
+/**
+ * This file contains definitions of WLAN commands.
+ */
+
+#ifndef _HOST_H_
+#define _HOST_H_
+
+/** PUBLIC DEFINITIONS */
+#define DEFAULT_AD_HOC_CHANNEL 6
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+/** IEEE 802.11 oids */
+#define OID_802_11_SSID 0x00008002
+#define OID_802_11_INFRASTRUCTURE_MODE 0x00008008
+#define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009
+#define OID_802_11_RTS_THRESHOLD 0x0000800A
+#define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D
+#define OID_802_11_SUPPORTED_RATES 0x0000800E
+#define OID_802_11_STATISTICS 0x00008012
+#define OID_802_11_TX_RETRYCOUNT 0x0000801D
+#define OID_802_11D_ENABLE 0x00008020
+
+#define cmd_option_waitforrsp 0x0002
+
+/** Host command ID */
+#define cmd_code_dnld 0x0002
+#define cmd_get_hw_spec 0x0003
+#define cmd_eeprom_update 0x0004
+#define cmd_802_11_reset 0x0005
+#define cmd_802_11_scan 0x0006
+#define cmd_802_11_get_log 0x000b
+#define cmd_mac_multicast_adr 0x0010
+#define cmd_802_11_authenticate 0x0011
+#define cmd_802_11_eeprom_access 0x0059
+#define cmd_802_11_associate 0x0050
+#define cmd_802_11_set_wep 0x0013
+#define cmd_802_11_get_stat 0x0014
+#define cmd_802_3_get_stat 0x0015
+#define cmd_802_11_snmp_mib 0x0016
+#define cmd_mac_reg_map 0x0017
+#define cmd_bbp_reg_map 0x0018
+#define cmd_mac_reg_access 0x0019
+#define cmd_bbp_reg_access 0x001a
+#define cmd_rf_reg_access 0x001b
+#define cmd_802_11_radio_control 0x001c
+#define cmd_802_11_rf_channel 0x001d
+#define cmd_802_11_rf_tx_power 0x001e
+#define cmd_802_11_rssi 0x001f
+#define cmd_802_11_rf_antenna 0x0020
+
+#define cmd_802_11_ps_mode 0x0021
+
+#define cmd_802_11_data_rate 0x0022
+#define cmd_rf_reg_map 0x0023
+#define cmd_802_11_deauthenticate 0x0024
+#define cmd_802_11_reassociate 0x0025
+#define cmd_802_11_disassociate 0x0026
+#define cmd_mac_control 0x0028
+#define cmd_802_11_ad_hoc_start 0x002b
+#define cmd_802_11_ad_hoc_join 0x002c
+
+#define cmd_802_11_query_tkip_reply_cntrs 0x002e
+#define cmd_802_11_enable_rsn 0x002f
+#define cmd_802_11_pairwise_tsc 0x0036
+#define cmd_802_11_group_tsc 0x0037
+#define cmd_802_11_key_material 0x005e
+
+#define cmd_802_11_set_afc 0x003c
+#define cmd_802_11_get_afc 0x003d
+
+#define cmd_802_11_ad_hoc_stop 0x0040
+
+#define cmd_802_11_beacon_stop 0x0049
+
+#define cmd_802_11_mac_address 0x004D
+#define cmd_802_11_eeprom_access 0x0059
+
+#define cmd_802_11_band_config 0x0058
+
+#define cmd_802_11d_domain_info 0x005b
+
+#define cmd_802_11_sleep_params 0x0066
+
+#define cmd_802_11_inactivity_timeout 0x0067
+
+#define cmd_802_11_tpc_cfg 0x0072
+#define cmd_802_11_pwr_cfg 0x0073
+
+#define cmd_802_11_led_gpio_ctrl 0x004e
+
+#define cmd_802_11_subscribe_event 0x0075
+
+#define cmd_802_11_rate_adapt_rateset 0x0076
+
+#define cmd_802_11_tx_rate_query 0x007f
+
+#define cmd_get_tsf 0x0080
+
+#define cmd_bt_access 0x0087
+#define cmd_ret_bt_access 0x8087
+
+#define cmd_fwt_access 0x0088
+#define cmd_ret_fwt_access 0x8088
+
+#define cmd_mesh_access 0x0090
+#define cmd_ret_mesh_access 0x8090
+
+/* For the IEEE Power Save */
+#define cmd_subcmd_enter_ps 0x0030
+#define cmd_subcmd_exit_ps 0x0031
+#define cmd_subcmd_sleep_confirmed 0x0034
+#define cmd_subcmd_full_powerdown 0x0035
+#define cmd_subcmd_full_powerup 0x0036
+
+/* command RET code, MSB is set to 1 */
+#define cmd_ret_hw_spec_info 0x8003
+#define cmd_ret_eeprom_update 0x8004
+#define cmd_ret_802_11_reset 0x8005
+#define cmd_ret_802_11_scan 0x8006
+#define cmd_ret_802_11_get_log 0x800b
+#define cmd_ret_mac_control 0x8028
+#define cmd_ret_mac_multicast_adr 0x8010
+#define cmd_ret_802_11_authenticate 0x8011
+#define cmd_ret_802_11_deauthenticate 0x8024
+#define cmd_ret_802_11_associate 0x8012
+#define cmd_ret_802_11_reassociate 0x8025
+#define cmd_ret_802_11_disassociate 0x8026
+#define cmd_ret_802_11_set_wep 0x8013
+#define cmd_ret_802_11_stat 0x8014
+#define cmd_ret_802_3_stat 0x8015
+#define cmd_ret_802_11_snmp_mib 0x8016
+#define cmd_ret_mac_reg_map 0x8017
+#define cmd_ret_bbp_reg_map 0x8018
+#define cmd_ret_rf_reg_map 0x8023
+#define cmd_ret_mac_reg_access 0x8019
+#define cmd_ret_bbp_reg_access 0x801a
+#define cmd_ret_rf_reg_access 0x801b
+#define cmd_ret_802_11_radio_control 0x801c
+#define cmd_ret_802_11_rf_channel 0x801d
+#define cmd_ret_802_11_rssi 0x801f
+#define cmd_ret_802_11_rf_tx_power 0x801e
+#define cmd_ret_802_11_rf_antenna 0x8020
+#define cmd_ret_802_11_ps_mode 0x8021
+#define cmd_ret_802_11_data_rate 0x8022
+
+#define cmd_ret_802_11_ad_hoc_start 0x802B
+#define cmd_ret_802_11_ad_hoc_join 0x802C
+
+#define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e
+#define cmd_ret_802_11_enable_rsn 0x802f
+#define cmd_ret_802_11_pairwise_tsc 0x8036
+#define cmd_ret_802_11_group_tsc 0x8037
+#define cmd_ret_802_11_key_material 0x805e
+
+#define cmd_enable_rsn 0x0001
+#define cmd_disable_rsn 0x0000
+
+#define cmd_act_set 0x0001
+#define cmd_act_get 0x0000
+
+#define cmd_act_get_AES (cmd_act_get + 2)
+#define cmd_act_set_AES (cmd_act_set + 2)
+#define cmd_act_remove_aes (cmd_act_set + 3)
+
+#define cmd_ret_802_11_set_afc 0x803c
+#define cmd_ret_802_11_get_afc 0x803d
+
+#define cmd_ret_802_11_ad_hoc_stop 0x8040
+
+#define cmd_ret_802_11_beacon_stop 0x8049
+
+#define cmd_ret_802_11_mac_address 0x804D
+#define cmd_ret_802_11_eeprom_access 0x8059
+
+#define cmd_ret_802_11_band_config 0x8058
+
+#define cmd_ret_802_11_sleep_params 0x8066
+
+#define cmd_ret_802_11_inactivity_timeout 0x8067
+
+#define cmd_ret_802_11d_domain_info (0x8000 | \
+ cmd_802_11d_domain_info)
+
+#define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000)
+#define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000)
+
+#define cmd_ret_802_11_led_gpio_ctrl 0x804e
+
+#define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000)
+
+#define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000)
+
+#define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000)
+
+#define cmd_ret_get_tsf 0x8080
+
+/* Define action or option for cmd_802_11_set_wep */
+#define cmd_act_add 0x0002
+#define cmd_act_remove 0x0004
+#define cmd_act_use_default 0x0008
+
+#define cmd_type_wep_40_bit 0x0001
+#define cmd_type_wep_104_bit 0x0002
+
+#define cmd_NUM_OF_WEP_KEYS 4
+
+#define cmd_WEP_KEY_INDEX_MASK 0x3fff
+
+/* Define action or option for cmd_802_11_reset */
+#define cmd_act_halt 0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_bss_type_bss 0x0001
+#define cmd_bss_type_ibss 0x0002
+#define cmd_bss_type_any 0x0003
+
+/* Define action or option for cmd_802_11_scan */
+#define cmd_scan_type_active 0x0000
+#define cmd_scan_type_passive 0x0001
+
+#define cmd_scan_radio_type_bg 0
+
+#define cmd_scan_probe_delay_time 0
+
+/* Define action or option for cmd_mac_control */
+#define cmd_act_mac_rx_on 0x0001
+#define cmd_act_mac_tx_on 0x0002
+#define cmd_act_mac_loopback_on 0x0004
+#define cmd_act_mac_wep_enable 0x0008
+#define cmd_act_mac_int_enable 0x0010
+#define cmd_act_mac_multicast_enable 0x0020
+#define cmd_act_mac_broadcast_enable 0x0040
+#define cmd_act_mac_promiscuous_enable 0x0080
+#define cmd_act_mac_all_multicast_enable 0x0100
+#define cmd_act_mac_strict_protection_enable 0x0400
+
+/* Define action or option for cmd_802_11_radio_control */
+#define cmd_type_auto_preamble 0x0001
+#define cmd_type_short_preamble 0x0002
+#define cmd_type_long_preamble 0x0003
+
+#define TURN_ON_RF 0x01
+#define RADIO_ON 0x01
+#define RADIO_OFF 0x00
+
+#define SET_AUTO_PREAMBLE 0x05
+#define SET_SHORT_PREAMBLE 0x03
+#define SET_LONG_PREAMBLE 0x01
+
+/* Define action or option for CMD_802_11_RF_CHANNEL */
+#define cmd_opt_802_11_rf_channel_get 0x00
+#define cmd_opt_802_11_rf_channel_set 0x01
+
+/* Define action or option for cmd_802_11_rf_tx_power */
+#define cmd_act_tx_power_opt_get 0x0000
+#define cmd_act_tx_power_opt_set_high 0x8007
+#define cmd_act_tx_power_opt_set_mid 0x8004
+#define cmd_act_tx_power_opt_set_low 0x8000
+
+#define cmd_act_tx_power_index_high 0x0007
+#define cmd_act_tx_power_index_mid 0x0004
+#define cmd_act_tx_power_index_low 0x0000
+
+/* Define action or option for cmd_802_11_data_rate */
+#define cmd_act_set_tx_auto 0x0000
+#define cmd_act_set_tx_fix_rate 0x0001
+#define cmd_act_get_tx_rate 0x0002
+
+#define cmd_act_set_rx 0x0001
+#define cmd_act_set_tx 0x0002
+#define cmd_act_set_both 0x0003
+#define cmd_act_get_rx 0x0004
+#define cmd_act_get_tx 0x0008
+#define cmd_act_get_both 0x000c
+
+/* Define action or option for cmd_802_11_ps_mode */
+#define cmd_type_cam 0x0000
+#define cmd_type_max_psp 0x0001
+#define cmd_type_fast_psp 0x0002
+
+/* Define action or option for cmd_bt_access */
+enum cmd_bt_access_opts {
+ /* The bt commands start at 5 instead of 1 because the old dft commands
+ * are mapped to 1-4. These old commands are no longer maintained and
+ * should not be called.
+ */
+ cmd_act_bt_access_add = 5,
+ cmd_act_bt_access_del,
+ cmd_act_bt_access_list,
+ cmd_act_bt_access_reset
+};
+
+/* Define action or option for cmd_fwt_access */
+enum cmd_fwt_access_opts {
+ cmd_act_fwt_access_add = 1,
+ cmd_act_fwt_access_del,
+ cmd_act_fwt_access_lookup,
+ cmd_act_fwt_access_list,
+ cmd_act_fwt_access_list_route,
+ cmd_act_fwt_access_list_neighbor,
+ cmd_act_fwt_access_reset,
+ cmd_act_fwt_access_cleanup,
+ cmd_act_fwt_access_time,
+};
+
+/* Define action or option for cmd_mesh_access */
+enum cmd_mesh_access_opts {
+ cmd_act_mesh_get_ttl = 1,
+ cmd_act_mesh_set_ttl,
+ cmd_act_mesh_get_stats,
+ cmd_act_mesh_get_mpp,
+ cmd_act_mesh_set_mpp,
+};
+
+/** Card Event definition */
+#define MACREG_INT_CODE_TX_PPA_FREE 0x00000000
+#define MACREG_INT_CODE_TX_DMA_DONE 0x00000001
+#define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002
+#define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003
+#define MACREG_INT_CODE_LINK_SENSED 0x00000004
+#define MACREG_INT_CODE_CMD_FINISHED 0x00000005
+#define MACREG_INT_CODE_MIB_CHANGED 0x00000006
+#define MACREG_INT_CODE_INIT_DONE 0x00000007
+#define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008
+#define MACREG_INT_CODE_DISASSOCIATED 0x00000009
+#define MACREG_INT_CODE_PS_AWAKE 0x0000000a
+#define MACREG_INT_CODE_PS_SLEEP 0x0000000b
+#define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d
+#define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e
+#define MACREG_INT_CODE_WM_AWAKE 0x0000000f
+#define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011
+#define MACREG_INT_CODE_RSSI_LOW 0x00000019
+#define MACREG_INT_CODE_SNR_LOW 0x0000001a
+#define MACREG_INT_CODE_MAX_FAIL 0x0000001b
+#define MACREG_INT_CODE_RSSI_HIGH 0x0000001c
+#define MACREG_INT_CODE_SNR_HIGH 0x0000001d
+
+#endif /* _HOST_H_ */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
new file mode 100644
index 00000000000..f239e5d2435
--- /dev/null
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -0,0 +1,693 @@
+/*
+ * This file contains the function prototypes, data structure
+ * and defines for all the host/station commands
+ */
+#ifndef __HOSTCMD__H
+#define __HOSTCMD__H
+
+#include <linux/wireless.h>
+#include "11d.h"
+#include "types.h"
+
+/* 802.11-related definitions */
+
+/* TxPD descriptor */
+struct txpd {
+ /* Current Tx packet status */
+ u32 tx_status;
+ /* Tx control */
+ u32 tx_control;
+ u32 tx_packet_location;
+ /* Tx packet length */
+ u16 tx_packet_length;
+ /* First 2 byte of destination MAC address */
+ u8 tx_dest_addr_high[2];
+ /* Last 4 byte of destination MAC address */
+ u8 tx_dest_addr_low[4];
+ /* Pkt Priority */
+ u8 priority;
+ /* Pkt Trasnit Power control */
+ u8 powermgmt;
+ /* Amount of time the packet has been queued in the driver (units = 2ms) */
+ u8 pktdelay_2ms;
+ /* reserved */
+ u8 reserved1;
+};
+
+/* RxPD Descriptor */
+struct rxpd {
+ /* Current Rx packet status */
+ u16 status;
+
+ /* SNR */
+ u8 snr;
+
+ /* Tx control */
+ u8 rx_control;
+
+ /* Pkt length */
+ u16 pkt_len;
+
+ /* Noise Floor */
+ u8 nf;
+
+ /* Rx Packet Rate */
+ u8 rx_rate;
+
+ /* Pkt addr */
+ u32 pkt_ptr;
+
+ /* Next Rx RxPD addr */
+ u32 next_rxpd_ptr;
+
+ /* Pkt Priority */
+ u8 priority;
+ u8 reserved[3];
+};
+
+struct cmd_ctrl_node {
+ /* CMD link list */
+ struct list_head list;
+ u32 status;
+ /* CMD ID */
+ u32 cmd_oid;
+ /*CMD wait option: wait for finish or no wait */
+ u16 wait_option;
+ /* command parameter */
+ void *pdata_buf;
+ /*command data */
+ u8 *bufvirtualaddr;
+ u16 cmdflags;
+ /* wait queue */
+ u16 cmdwaitqwoken;
+ wait_queue_head_t cmdwait_q;
+};
+
+/* WLAN_802_11_KEY
+ *
+ * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES)
+ * is determined from the keylength field.
+ */
+struct WLAN_802_11_KEY {
+ u32 len;
+ u32 flags; /* KEY_INFO_* from wlan_defs.h */
+ u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
+ u16 type; /* KEY_TYPE_* from wlan_defs.h */
+};
+
+struct IE_WPA {
+ u8 elementid;
+ u8 len;
+ u8 oui[4];
+ u16 version;
+};
+
+struct WLAN_802_11_SSID {
+ /* SSID length */
+ u32 ssidlength;
+
+ /* SSID information field */
+ u8 ssid[IW_ESSID_MAX_SIZE];
+};
+
+struct WPA_SUPPLICANT {
+ u8 wpa_ie[256];
+ u8 wpa_ie_len;
+};
+
+/* wlan_offset_value */
+struct wlan_offset_value {
+ u32 offset;
+ u32 value;
+};
+
+struct WLAN_802_11_FIXED_IEs {
+ u8 timestamp[8];
+ u16 beaconinterval;
+ u16 capabilities;
+};
+
+struct WLAN_802_11_VARIABLE_IEs {
+ u8 elementid;
+ u8 length;
+ u8 data[1];
+};
+
+/* Define general data structure */
+/* cmd_DS_GEN */
+struct cmd_ds_gen {
+ u16 command;
+ u16 size;
+ u16 seqnum;
+ u16 result;
+};
+
+#define S_DS_GEN sizeof(struct cmd_ds_gen)
+/*
+ * Define data structure for cmd_get_hw_spec
+ * This structure defines the response for the GET_HW_SPEC command
+ */
+struct cmd_ds_get_hw_spec {
+ /* HW Interface version number */
+ u16 hwifversion;
+ /* HW version number */
+ u16 version;
+ /* Max number of TxPD FW can handle */
+ u16 nr_txpd;
+ /* Max no of Multicast address */
+ u16 nr_mcast_adr;
+ /* MAC address */
+ u8 permanentaddr[6];
+
+ /* region Code */
+ u16 regioncode;
+
+ /* Number of antenna used */
+ u16 nr_antenna;
+
+ /* FW release number, example 0x1234=1.2.3.4 */
+ u32 fwreleasenumber;
+
+ /* Base Address of TxPD queue */
+ u32 wcb_base;
+ /* Read Pointer of RxPd queue */
+ u32 rxpd_rdptr;
+
+ /* Write Pointer of RxPd queue */
+ u32 rxpd_wrptr;
+
+ /*FW/HW capability */
+ u32 fwcapinfo;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_reset {
+ u16 action;
+};
+
+struct cmd_ds_802_11_subscribe_event {
+ u16 action;
+ u16 events;
+};
+
+/*
+ * This scan handle Country Information IE(802.11d compliant)
+ * Define data structure for cmd_802_11_scan
+ */
+struct cmd_ds_802_11_scan {
+ u8 bsstype;
+ u8 BSSID[ETH_ALEN];
+ u8 tlvbuffer[1];
+#if 0
+ mrvlietypes_ssidparamset_t ssidParamSet;
+ mrvlietypes_chanlistparamset_t ChanListParamSet;
+ mrvlietypes_ratesparamset_t OpRateSet;
+#endif
+};
+
+struct cmd_ds_802_11_scan_rsp {
+ u16 bssdescriptsize;
+ u8 nr_sets;
+ u8 bssdesc_and_tlvbuffer[1];
+};
+
+struct cmd_ds_802_11_get_log {
+ u32 mcasttxframe;
+ u32 failed;
+ u32 retry;
+ u32 multiretry;
+ u32 framedup;
+ u32 rtssuccess;
+ u32 rtsfailure;
+ u32 ackfailure;
+ u32 rxfrag;
+ u32 mcastrxframe;
+ u32 fcserror;
+ u32 txframe;
+ u32 wepundecryptable;
+};
+
+struct cmd_ds_mac_control {
+ u16 action;
+ u16 reserved;
+};
+
+struct cmd_ds_mac_multicast_adr {
+ u16 action;
+ u16 nr_of_adrs;
+ u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
+};
+
+struct cmd_ds_802_11_authenticate {
+ u8 macaddr[ETH_ALEN];
+ u8 authtype;
+ u8 reserved[10];
+};
+
+struct cmd_ds_802_11_deauthenticate {
+ u8 macaddr[6];
+ u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate {
+ u8 peerstaaddr[6];
+ struct ieeetypes_capinfo capinfo;
+ u16 listeninterval;
+ u16 bcnperiod;
+ u8 dtimperiod;
+
+#if 0
+ mrvlietypes_ssidparamset_t ssidParamSet;
+ mrvlietypes_phyparamset_t phyparamset;
+ mrvlietypes_ssparamset_t ssparamset;
+ mrvlietypes_ratesparamset_t ratesParamSet;
+#endif
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_disassociate {
+ u8 destmacaddr[6];
+ u16 reasoncode;
+};
+
+struct cmd_ds_802_11_associate_rsp {
+ struct ieeetypes_assocrsp assocRsp;
+};
+
+struct cmd_ds_802_11_ad_hoc_result {
+ u8 PAD[3];
+ u8 BSSID[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_set_wep {
+ /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */
+ u16 action;
+
+ /* key Index selected for Tx */
+ u16 keyindex;
+
+ /* 40, 128bit or TXWEP */
+ u8 keytype[4];
+ u8 keymaterial[4][16];
+};
+
+struct cmd_ds_802_3_get_stat {
+ u32 xmitok;
+ u32 rcvok;
+ u32 xmiterror;
+ u32 rcverror;
+ u32 rcvnobuffer;
+ u32 rcvcrcerror;
+};
+
+struct cmd_ds_802_11_get_stat {
+ u32 txfragmentcnt;
+ u32 mcasttxframecnt;
+ u32 failedcnt;
+ u32 retrycnt;
+ u32 Multipleretrycnt;
+ u32 rtssuccesscnt;
+ u32 rtsfailurecnt;
+ u32 ackfailurecnt;
+ u32 frameduplicatecnt;
+ u32 rxfragmentcnt;
+ u32 mcastrxframecnt;
+ u32 fcserrorcnt;
+ u32 bcasttxframecnt;
+ u32 bcastrxframecnt;
+ u32 txbeacon;
+ u32 rxbeacon;
+ u32 wepundecryptable;
+};
+
+struct cmd_ds_802_11_snmp_mib {
+ u16 querytype;
+ u16 oid;
+ u16 bufsize;
+ u8 value[128];
+};
+
+struct cmd_ds_mac_reg_map {
+ u16 buffersize;
+ u8 regmap[128];
+ u16 reserved;
+};
+
+struct cmd_ds_bbp_reg_map {
+ u16 buffersize;
+ u8 regmap[128];
+ u16 reserved;
+};
+
+struct cmd_ds_rf_reg_map {
+ u16 buffersize;
+ u8 regmap[64];
+ u16 reserved;
+};
+
+struct cmd_ds_mac_reg_access {
+ u16 action;
+ u16 offset;
+ u32 value;
+};
+
+struct cmd_ds_bbp_reg_access {
+ u16 action;
+ u16 offset;
+ u8 value;
+ u8 reserved[3];
+};
+
+struct cmd_ds_rf_reg_access {
+ u16 action;
+ u16 offset;
+ u8 value;
+ u8 reserved[3];
+};
+
+struct cmd_ds_802_11_radio_control {
+ u16 action;
+ u16 control;
+};
+
+struct cmd_ds_802_11_sleep_params {
+ /* ACT_GET/ACT_SET */
+ u16 action;
+
+ /* Sleep clock error in ppm */
+ u16 error;
+
+ /* Wakeup offset in usec */
+ u16 offset;
+
+ /* Clock stabilization time in usec */
+ u16 stabletime;
+
+ /* control periodic calibration */
+ u8 calcontrol;
+
+ /* control the use of external sleep clock */
+ u8 externalsleepclk;
+
+ /* reserved field, should be set to zero */
+ u16 reserved;
+};
+
+struct cmd_ds_802_11_inactivity_timeout {
+ /* ACT_GET/ACT_SET */
+ u16 action;
+
+ /* Inactivity timeout in msec */
+ u16 timeout;
+};
+
+struct cmd_ds_802_11_rf_channel {
+ u16 action;
+ u16 currentchannel;
+ u16 rftype;
+ u16 reserved;
+ u8 channellist[32];
+};
+
+struct cmd_ds_802_11_rssi {
+ /* weighting factor */
+ u16 N;
+
+ u16 reserved_0;
+ u16 reserved_1;
+ u16 reserved_2;
+};
+
+struct cmd_ds_802_11_rssi_rsp {
+ u16 SNR;
+ u16 noisefloor;
+ u16 avgSNR;
+ u16 avgnoisefloor;
+};
+
+struct cmd_ds_802_11_mac_address {
+ u16 action;
+ u8 macadd[ETH_ALEN];
+};
+
+struct cmd_ds_802_11_rf_tx_power {
+ u16 action;
+ u16 currentlevel;
+};
+
+struct cmd_ds_802_11_rf_antenna {
+ u16 action;
+
+ /* Number of antennas or 0xffff(diversity) */
+ u16 antennamode;
+
+};
+
+struct cmd_ds_802_11_ps_mode {
+ u16 action;
+ u16 nullpktinterval;
+ u16 multipledtim;
+ u16 reserved;
+ u16 locallisteninterval;
+};
+
+struct PS_CMD_ConfirmSleep {
+ u16 command;
+ u16 size;
+ u16 seqnum;
+ u16 result;
+
+ u16 action;
+ u16 reserved1;
+ u16 multipledtim;
+ u16 reserved;
+ u16 locallisteninterval;
+};
+
+struct cmd_ds_802_11_data_rate {
+ u16 action;
+ u16 reserverd;
+ u8 datarate[G_SUPPORTED_RATES];
+};
+
+struct cmd_ds_802_11_rate_adapt_rateset {
+ u16 action;
+ u16 enablehwauto;
+ u16 bitmap;
+};
+
+struct cmd_ds_802_11_ad_hoc_start {
+ u8 SSID[IW_ESSID_MAX_SIZE];
+ u8 bsstype;
+ u16 beaconperiod;
+ u8 dtimperiod;
+ union IEEEtypes_ssparamset ssparamset;
+ union ieeetypes_phyparamset phyparamset;
+ u16 probedelay;
+ struct ieeetypes_capinfo cap;
+ u8 datarate[G_SUPPORTED_RATES];
+ u8 tlv_memory_size_pad[100];
+} __attribute__ ((packed));
+
+struct adhoc_bssdesc {
+ u8 BSSID[6];
+ u8 SSID[32];
+ u8 bsstype;
+ u16 beaconperiod;
+ u8 dtimperiod;
+ u8 timestamp[8];
+ u8 localtime[8];
+ union ieeetypes_phyparamset phyparamset;
+ union IEEEtypes_ssparamset ssparamset;
+ struct ieeetypes_capinfo cap;
+ u8 datarates[G_SUPPORTED_RATES];
+
+ /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+ * Adhoc join command and will cause a binary layout mismatch with
+ * the firmware
+ */
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_ad_hoc_join {
+ struct adhoc_bssdesc bssdescriptor;
+ u16 failtimeout;
+ u16 probedelay;
+
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_enable_rsn {
+ u16 action;
+ u16 enable;
+};
+
+struct MrvlIEtype_keyParamSet {
+ /* type ID */
+ u16 type;
+
+ /* length of Payload */
+ u16 length;
+
+ /* type of key: WEP=0, TKIP=1, AES=2 */
+ u16 keytypeid;
+
+ /* key control Info specific to a keytypeid */
+ u16 keyinfo;
+
+ /* length of key */
+ u16 keylen;
+
+ /* key material of size keylen */
+ u8 key[32];
+};
+
+struct cmd_ds_802_11_key_material {
+ u16 action;
+ struct MrvlIEtype_keyParamSet keyParamSet[2];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_eeprom_access {
+ u16 action;
+
+ /* multiple 4 */
+ u16 offset;
+ u16 bytecount;
+ u8 value;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_tpc_cfg {
+ u16 action;
+ u8 enable;
+ s8 P0;
+ s8 P1;
+ s8 P2;
+ u8 usesnr;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_led_ctrl {
+ u16 action;
+ u16 numled;
+ u8 data[256];
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_pwr_cfg {
+ u16 action;
+ u8 enable;
+ s8 PA_P0;
+ s8 PA_P1;
+ s8 PA_P2;
+} __attribute__ ((packed));
+
+struct cmd_ds_802_11_afc {
+ u16 afc_auto;
+ union {
+ struct {
+ u16 threshold;
+ u16 period;
+ };
+ struct {
+ s16 timing_offset;
+ s16 carrier_offset;
+ };
+ };
+} __attribute__ ((packed));
+
+struct cmd_tx_rate_query {
+ u16 txrate;
+} __attribute__ ((packed));
+
+struct cmd_ds_get_tsf {
+ __le64 tsfvalue;
+} __attribute__ ((packed));
+
+struct cmd_ds_bt_access {
+ u16 action;
+ u32 id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct cmd_ds_fwt_access {
+ u16 action;
+ u32 id;
+ u8 da[ETH_ALEN];
+ u8 dir;
+ u8 ra[ETH_ALEN];
+ u32 ssn;
+ u32 dsn;
+ u32 metric;
+ u8 hopcount;
+ u8 ttl;
+ u32 expiration;
+ u8 sleepmode;
+ u32 snr;
+ u32 references;
+} __attribute__ ((packed));
+
+#define MESH_STATS_NUM 7
+struct cmd_ds_mesh_access {
+ u16 action;
+ u32 data[MESH_STATS_NUM + 1]; /* last position reserved */
+} __attribute__ ((packed));
+
+struct cmd_ds_command {
+ /* command header */
+ u16 command;
+ u16 size;
+ u16 seqnum;
+ u16 result;
+
+ /* command Body */
+ union {
+ struct cmd_ds_get_hw_spec hwspec;
+ struct cmd_ds_802_11_ps_mode psmode;
+ struct cmd_ds_802_11_scan scan;
+ struct cmd_ds_802_11_scan_rsp scanresp;
+ struct cmd_ds_mac_control macctrl;
+ struct cmd_ds_802_11_associate associate;
+ struct cmd_ds_802_11_deauthenticate deauth;
+ struct cmd_ds_802_11_set_wep wep;
+ struct cmd_ds_802_11_ad_hoc_start ads;
+ struct cmd_ds_802_11_reset reset;
+ struct cmd_ds_802_11_ad_hoc_result result;
+ struct cmd_ds_802_11_get_log glog;
+ struct cmd_ds_802_11_authenticate auth;
+ struct cmd_ds_802_11_get_stat gstat;
+ struct cmd_ds_802_3_get_stat gstat_8023;
+ struct cmd_ds_802_11_snmp_mib smib;
+ struct cmd_ds_802_11_rf_tx_power txp;
+ struct cmd_ds_802_11_rf_antenna rant;
+ struct cmd_ds_802_11_data_rate drate;
+ struct cmd_ds_802_11_rate_adapt_rateset rateset;
+ struct cmd_ds_mac_multicast_adr madr;
+ struct cmd_ds_802_11_ad_hoc_join adj;
+ struct cmd_ds_802_11_radio_control radio;
+ struct cmd_ds_802_11_rf_channel rfchannel;
+ struct cmd_ds_802_11_rssi rssi;
+ struct cmd_ds_802_11_rssi_rsp rssirsp;
+ struct cmd_ds_802_11_disassociate dassociate;
+ struct cmd_ds_802_11_mac_address macadd;
+ struct cmd_ds_802_11_enable_rsn enbrsn;
+ struct cmd_ds_802_11_key_material keymaterial;
+ struct cmd_ds_mac_reg_access macreg;
+ struct cmd_ds_bbp_reg_access bbpreg;
+ struct cmd_ds_rf_reg_access rfreg;
+ struct cmd_ds_802_11_eeprom_access rdeeprom;
+
+ struct cmd_ds_802_11d_domain_info domaininfo;
+ struct cmd_ds_802_11d_domain_info domaininforesp;
+
+ struct cmd_ds_802_11_sleep_params sleep_params;
+ struct cmd_ds_802_11_inactivity_timeout inactivity_timeout;
+ struct cmd_ds_802_11_tpc_cfg tpccfg;
+ struct cmd_ds_802_11_pwr_cfg pwrcfg;
+ struct cmd_ds_802_11_afc afc;
+ struct cmd_ds_802_11_led_ctrl ledgpio;
+
+ struct cmd_tx_rate_query txrate;
+ struct cmd_ds_bt_access bt;
+ struct cmd_ds_fwt_access fwt;
+ struct cmd_ds_mesh_access mesh;
+ struct cmd_ds_get_tsf gettsf;
+ struct cmd_ds_802_11_subscribe_event subscribe_event;
+ } params;
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
new file mode 100644
index 00000000000..567000c3e87
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_bootcmd.c
@@ -0,0 +1,38 @@
+/**
+ * This file contains functions used in USB Boot command
+ * and Boot2/FW update
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+/**
+ * @brief This function issues Boot command to the Boot2 code
+ * @param ivalue 1:Boot from FW by USB-Download
+ * 2:Boot from FW in EEPROM
+ * @return 0
+ */
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ struct bootcmdstr sbootcmd;
+ int i;
+
+ /* Prepare command */
+ sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER;
+ sbootcmd.u8cmd_tag = ivalue;
+ for (i=0; i<11; i++)
+ sbootcmd.au8dumy[i]=0x00;
+ memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
+
+ /* Issue command */
+ usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
+
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
new file mode 100644
index 00000000000..695fb6a66ff
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -0,0 +1,952 @@
+/**
+ * This file contains functions used in USB interface module.
+ */
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "if_usb.h"
+
+#define MESSAGE_HEADER_LEN 4
+
+static const char usbdriver_name[] = "usb8xxx";
+
+static struct usb_device_id if_usb_table[] = {
+ /* Enter the device signature inside */
+ {
+ USB_DEVICE(USB8388_VID_1, USB8388_PID_1),
+ },
+ {
+ USB_DEVICE(USB8388_VID_2, USB8388_PID_2),
+ },
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, if_usb_table);
+
+static void if_usb_receive(struct urb *urb);
+static void if_usb_receive_fwload(struct urb *urb);
+
+/**
+ * @brief call back function to handle the status of the URB
+ * @param urb pointer to urb structure
+ * @return N/A
+ */
+static void if_usb_write_bulk_callback(struct urb *urb)
+{
+ wlan_private *priv = (wlan_private *) (urb->context);
+ wlan_adapter *adapter = priv->adapter;
+ struct net_device *dev = priv->wlan_dev.netdev;
+
+ /* handle the transmission complete validations */
+
+ if (urb->status != 0) {
+ /* print the failure status number for debug */
+ lbs_pr_info("URB in failure status\n");
+ } else {
+ lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n");
+ lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n",
+ urb->actual_length);
+ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+ /* Wake main thread if commands are pending */
+ if (!adapter->cur_cmd)
+ wake_up_interruptible(&priv->mainthread.waitq);
+ if ((adapter->connect_status == libertas_connected))
+ netif_wake_queue(dev);
+ }
+
+ return;
+}
+
+/**
+ * @brief free tx/rx urb, skb and rx buffer
+ * @param cardp pointer usb_card_rec
+ * @return N/A
+ */
+void if_usb_free(struct usb_card_rec *cardp)
+{
+ ENTER();
+
+ /* Unlink tx & rx urb */
+ usb_kill_urb(cardp->tx_urb);
+ usb_kill_urb(cardp->rx_urb);
+
+ usb_free_urb(cardp->tx_urb);
+ cardp->tx_urb = NULL;
+
+ usb_free_urb(cardp->rx_urb);
+ cardp->rx_urb = NULL;
+
+ kfree(cardp->bulk_out_buffer);
+ cardp->bulk_out_buffer = NULL;
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief sets the configuration values
+ * @param ifnum interface number
+ * @param id pointer to usb_device_id
+ * @return 0 on success, error code on failure
+ */
+static int if_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ wlan_private *pwlanpriv;
+ struct usb_card_rec *usb_cardp;
+ int i;
+
+ udev = interface_to_usbdev(intf);
+
+ usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL);
+ if (!usb_cardp) {
+ lbs_pr_err("Out of memory allocating private data.\n");
+ goto error;
+ }
+
+ usb_cardp->udev = udev;
+ iface_desc = intf->cur_altsetting;
+
+ lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X"
+ " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n",
+ udev->descriptor.bcdUSB,
+ udev->descriptor.bDeviceClass,
+ udev->descriptor.bDeviceSubClass,
+ udev->descriptor.bDeviceProtocol);
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ /* we found a bulk in endpoint */
+ lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n",
+ endpoint->wMaxPacketSize);
+ if (!
+ (usb_cardp->rx_urb =
+ usb_alloc_urb(0, GFP_KERNEL))) {
+ lbs_dev_dbg(1, &udev->dev,
+ "Rx URB allocation failed\n");
+ goto dealloc;
+ }
+ usb_cardp->rx_urb_recall = 0;
+
+ usb_cardp->bulk_in_size =
+ endpoint->wMaxPacketSize;
+ usb_cardp->bulk_in_endpointAddr =
+ (endpoint->
+ bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n",
+ endpoint->bEndpointAddress);
+ }
+
+ if (((endpoint->
+ bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+ USB_DIR_OUT)
+ && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ /* We found bulk out endpoint */
+ if (!
+ (usb_cardp->tx_urb =
+ usb_alloc_urb(0, GFP_KERNEL))) {
+ lbs_dev_dbg(1,&udev->dev,
+ "Tx URB allocation failed\n");
+ goto dealloc;
+ }
+
+ usb_cardp->bulk_out_size =
+ endpoint->wMaxPacketSize;
+ lbs_dev_dbg(1, &udev->dev,
+ "Bulk out size is %d\n",
+ endpoint->wMaxPacketSize);
+ usb_cardp->bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n",
+ endpoint->bEndpointAddress);
+ usb_cardp->bulk_out_buffer =
+ kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE,
+ GFP_KERNEL);
+
+ if (!usb_cardp->bulk_out_buffer) {
+ lbs_dev_dbg(1, &udev->dev,
+ "Could not allocate buffer\n");
+ goto dealloc;
+ }
+ }
+ }
+
+
+ /* At this point wlan_add_card() will be called. Don't worry
+ * about keeping pwlanpriv around since it will be set on our
+ * usb device data in -> add() -> libertas_sbi_register_dev().
+ */
+ if (!(pwlanpriv = wlan_add_card(usb_cardp)))
+ goto dealloc;
+
+ usb_get_dev(udev);
+ usb_set_intfdata(intf, usb_cardp);
+
+ /*
+ * return card structure, which can be got back in the
+ * diconnect function as the ptr
+ * argument.
+ */
+ return 0;
+
+dealloc:
+ if_usb_free(usb_cardp);
+
+error:
+ return -ENOMEM;
+}
+
+/**
+ * @brief free resource and cleanup
+ * @param udev pointer to usb_device
+ * @param ptr pointer to usb_cardp
+ * @return N/A
+ */
+static void if_usb_disconnect(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ wlan_private *priv = (wlan_private *) cardp->priv;
+ wlan_adapter *adapter = NULL;
+
+ adapter = priv->adapter;
+
+ /*
+ * Update Surprise removed to TRUE
+ */
+ adapter->surpriseremoved = 1;
+
+ /* card is removed and we can call wlan_remove_card */
+ lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n");
+ wlan_remove_card(cardp);
+
+ /* Unlink and free urb */
+ if_usb_free(cardp);
+
+ usb_set_intfdata(intf, NULL);
+ usb_put_dev(interface_to_usbdev(intf));
+
+ return;
+}
+
+/**
+ * @brief This function download FW
+ * @param priv pointer to wlan_private
+ * @return 0
+ */
+static int if_prog_firmware(wlan_private * priv)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ struct FWData *fwdata;
+ struct fwheader *fwheader;
+ u8 *firmware = priv->firmware->data;
+
+ fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
+
+ if (!fwdata)
+ return -1;
+
+ fwheader = &fwdata->fwheader;
+
+ if (!cardp->CRC_OK) {
+ cardp->totalbytes = cardp->fwlastblksent;
+ cardp->fwseqnum = cardp->lastseqnum - 1;
+ }
+
+ lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n",
+ cardp->totalbytes);
+
+ memcpy(fwheader, &firmware[cardp->totalbytes],
+ sizeof(struct fwheader));
+
+ cardp->fwlastblksent = cardp->totalbytes;
+ cardp->totalbytes += sizeof(struct fwheader);
+
+ lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n");
+ memcpy(fwdata->data, &firmware[cardp->totalbytes],
+ fwdata->fwheader.datalength);
+
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "Data length = %d\n", fwdata->fwheader.datalength);
+
+ cardp->fwseqnum = cardp->fwseqnum + 1;
+
+ fwdata->seqnum = cardp->fwseqnum;
+ cardp->lastseqnum = fwdata->seqnum;
+ cardp->totalbytes += fwdata->fwheader.datalength;
+
+ if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) {
+ lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n");
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "seqnum = %d totalbytes = %d\n", cardp->fwseqnum,
+ cardp->totalbytes);
+ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+ usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+
+ } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) {
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "Host has finished FW downloading\n");
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "Donwloading FW JUMP BLOCK\n");
+ memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
+ usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+ cardp->fwfinalblk = 1;
+ }
+
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "The firmware download is done size is %d\n",
+ cardp->totalbytes);
+
+ kfree(fwdata);
+
+ return 0;
+}
+
+static int libertas_do_reset(wlan_private *priv)
+{
+ int ret;
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+ ret = usb_reset_device(cardp->udev);
+ if (!ret) {
+ msleep(10);
+ reset_device(priv);
+ msleep(10);
+ }
+ return ret;
+}
+
+/**
+ * @brief This function transfer the data to the device.
+ * @param priv pointer to wlan_private
+ * @param payload pointer to payload data
+ * @param nb data length
+ * @return 0 or -1
+ */
+int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+{
+ /* pointer to card structure */
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ int ret = -1;
+
+ /* check if device is removed */
+ if (priv->adapter->surpriseremoved) {
+ lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n");
+ goto tx_ret;
+ }
+
+ usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
+ usb_sndbulkpipe(cardp->udev,
+ cardp->bulk_out_endpointAddr),
+ payload, nb, if_usb_write_bulk_callback, priv);
+
+ cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) {
+ /* transfer failed */
+ lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n");
+ ret = -1;
+ } else {
+ lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n");
+ ret = 0;
+ }
+
+tx_ret:
+ return ret;
+}
+
+static int __if_usb_submit_rx_urb(wlan_private * priv,
+ void (*callbackfn)
+ (struct urb *urb))
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ struct sk_buff *skb;
+ struct read_cb_info *rinfo = &cardp->rinfo;
+ int ret = -1;
+
+ if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
+ lbs_pr_err("No free skb\n");
+ goto rx_ret;
+ }
+
+ rinfo->skb = skb;
+
+ /* Fill the receive configuration URB and initialise the Rx call back */
+ usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
+ usb_rcvbulkpipe(cardp->udev,
+ cardp->bulk_in_endpointAddr),
+ skb->tail + IPFIELD_ALIGN_OFFSET,
+ MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
+ rinfo);
+
+ cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET;
+
+ lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb);
+ if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) {
+ /* handle failure conditions */
+ lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n");
+ ret = -1;
+ } else {
+ lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n");
+ ret = 0;
+ }
+
+rx_ret:
+ return ret;
+}
+
+static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+{
+ return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+}
+
+static inline int if_usb_submit_rx_urb(wlan_private * priv)
+{
+ return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+}
+
+static void if_usb_receive_fwload(struct urb *urb)
+{
+ struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+ wlan_private *priv = rinfo->priv;
+ struct sk_buff *skb = rinfo->skb;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+ struct fwsyncheader *syncfwheader;
+ struct bootcmdrespStr bootcmdresp;
+
+ if (urb->status) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "URB status is failed during fw load\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ if (cardp->bootcmdresp == 0) {
+ memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(bootcmdresp));
+ if (cardp->udev->descriptor.bcdDevice < 0x3106) {
+ kfree_skb(skb);
+ if_usb_submit_rx_urb_fwload(priv);
+ cardp->bootcmdresp = 1;
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Received valid boot command response\n");
+ return;
+ }
+ if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) {
+ lbs_pr_info(
+ "boot cmd response wrong magic number (0x%x)\n",
+ bootcmdresp.u32magicnumber);
+ } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) {
+ lbs_pr_info(
+ "boot cmd response cmd_tag error (%d)\n",
+ bootcmdresp.u8cmd_tag);
+ } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) {
+ lbs_pr_info(
+ "boot cmd response result error (%d)\n",
+ bootcmdresp.u8result);
+ } else {
+ cardp->bootcmdresp = 1;
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Received valid boot command response\n");
+ }
+ kfree_skb(skb);
+ if_usb_submit_rx_urb_fwload(priv);
+ return;
+ }
+
+ syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+ if (!syncfwheader) {
+ lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(struct fwsyncheader));
+
+ if (!syncfwheader->cmd) {
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "FW received Blk with correct CRC\n");
+ lbs_dev_dbg(2, &cardp->udev->dev,
+ "FW received Blk seqnum = %d\n",
+ syncfwheader->seqnum);
+ cardp->CRC_OK = 1;
+ } else {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "FW received Blk with CRC error\n");
+ cardp->CRC_OK = 0;
+ }
+
+ kfree_skb(skb);
+
+ if (cardp->fwfinalblk) {
+ cardp->fwdnldover = 1;
+ goto exit;
+ }
+
+ if_prog_firmware(priv);
+
+ if_usb_submit_rx_urb_fwload(priv);
+exit:
+ kfree(syncfwheader);
+
+ return;
+
+}
+
+#define MRVDRV_MIN_PKT_LEN 30
+
+static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb,
+ struct usb_card_rec *cardp,
+ wlan_private *priv)
+{
+ if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE +
+ MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Packet length is Invalid\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
+ skb_put(skb, recvlength);
+ skb_pull(skb, MESSAGE_HEADER_LEN);
+ libertas_process_rxed_packet(priv, skb);
+ priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+}
+
+static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
+ struct sk_buff *skb,
+ struct usb_card_rec *cardp,
+ wlan_private *priv)
+{
+ u8 *cmdbuf;
+ if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "The receive buffer is too large\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ if (!in_interrupt())
+ BUG();
+
+ spin_lock(&priv->adapter->driver_lock);
+ /* take care of cur_cmd = NULL case by reading the
+ * data to clear the interrupt */
+ if (!priv->adapter->cur_cmd) {
+ cmdbuf = priv->wlan_dev.upld_buf;
+ priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+ } else
+ cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+
+ cardp->usb_int_cause |= his_cmdupldrdy;
+ priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN);
+ memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
+ priv->wlan_dev.upld_len);
+
+ kfree_skb(skb);
+ libertas_interrupt(priv->wlan_dev.netdev);
+ spin_unlock(&priv->adapter->driver_lock);
+
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Wake up main thread to handle cmd response\n");
+
+ return;
+}
+
+/**
+ * @brief This function reads of the packet into the upload buff,
+ * wake up the main thread and initialise the Rx callack.
+ *
+ * @param urb pointer to struct urb
+ * @return N/A
+ */
+static void if_usb_receive(struct urb *urb)
+{
+ struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
+ wlan_private *priv = rinfo->priv;
+ struct sk_buff *skb = rinfo->skb;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+ int recvlength = urb->actual_length;
+ u8 *recvbuff = NULL;
+ u32 recvtype;
+
+ ENTER();
+
+ if (recvlength) {
+ if (urb->status) {
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "URB status is failed\n");
+ kfree_skb(skb);
+ goto setup_for_next;
+ }
+
+ recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
+ memcpy(&recvtype, recvbuff, sizeof(u32));
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Recv length = 0x%x\n", recvlength);
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Receive type = 0x%X\n", recvtype);
+ recvtype = le32_to_cpu(recvtype);
+ lbs_dev_dbg(1, &cardp->udev->dev,
+ "Receive type after = 0x%X\n", recvtype);
+ } else if (urb->status)
+ goto rx_exit;
+
+
+ switch (recvtype) {
+ case CMD_TYPE_DATA:
+ process_cmdtypedata(recvlength, skb, cardp, priv);
+ break;
+
+ case CMD_TYPE_REQUEST:
+ process_cmdrequest(recvlength, recvbuff, skb, cardp, priv);
+ break;
+
+ case CMD_TYPE_INDICATION:
+ /* Event cause handling */
+ spin_lock(&priv->adapter->driver_lock);
+ cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN);
+ lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n",
+ cardp->usb_event_cause);
+ if (cardp->usb_event_cause & 0xffff0000) {
+ libertas_send_tx_feedback(priv);
+ break;
+ }
+ cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3;
+ cardp->usb_int_cause |= his_cardevent;
+ kfree_skb(skb);
+ libertas_interrupt(priv->wlan_dev.netdev);
+ spin_unlock(&priv->adapter->driver_lock);
+ goto rx_exit;
+ default:
+ kfree_skb(skb);
+ break;
+ }
+
+setup_for_next:
+ if_usb_submit_rx_urb(priv);
+rx_exit:
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief This function downloads data to FW
+ * @param priv pointer to wlan_private structure
+ * @param type type of data
+ * @param buf pointer to data buffer
+ * @param len number of bytes
+ * @return 0 or -1
+ */
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
+{
+ int ret = -1;
+ u32 tmp;
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+
+ lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type);
+ lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb);
+
+ if (type == MVMS_CMD) {
+ tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+ priv->wlan_dev.dnld_sent = DNLD_CMD_SENT;
+ memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+ MESSAGE_HEADER_LEN);
+
+ } else {
+ tmp = cpu_to_le32(CMD_TYPE_DATA);
+ priv->wlan_dev.dnld_sent = DNLD_DATA_SENT;
+ memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
+ MESSAGE_HEADER_LEN);
+ }
+
+ memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
+
+ ret =
+ usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
+
+ return ret;
+}
+
+/* called with adapter->driver_lock held */
+int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+
+ *ireg = cardp->usb_int_cause;
+ cardp->usb_int_cause = 0;
+
+ lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg);
+
+ return 0;
+}
+
+int libertas_sbi_read_event_cause(wlan_private * priv)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ priv->adapter->eventcause = cardp->usb_event_cause;
+ /* Re-submit rx urb here to avoid event lost issue */
+ if_usb_submit_rx_urb(priv);
+ return 0;
+}
+
+int reset_device(wlan_private *priv)
+{
+ int ret;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
+ cmd_act_halt, 0, 0, NULL);
+ msleep_interruptible(10);
+
+ return ret;
+}
+
+int libertas_sbi_unregister_dev(wlan_private * priv)
+{
+ int ret = 0;
+
+ /* Need to send a Reset command to device before USB resources freed
+ * and wlan_remove_card() called, then device can handle FW download
+ * again.
+ */
+ if (priv)
+ reset_device(priv);
+
+ return ret;
+}
+
+
+/**
+ * @brief This function register usb device and initialize parameter
+ * @param priv pointer to wlan_private
+ * @return 0 or -1
+ */
+int libertas_sbi_register_dev(wlan_private * priv)
+{
+
+ struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card;
+ ENTER();
+
+ cardp->priv = priv;
+ cardp->eth_dev = priv->wlan_dev.netdev;
+ priv->hotplug_device = &(cardp->udev->dev);
+
+ SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev));
+
+ lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n",
+ cardp->udev);
+
+ LEAVE();
+ return 0;
+}
+
+
+
+int libertas_sbi_prog_firmware(wlan_private * priv)
+{
+ struct usb_card_rec *cardp = priv->wlan_dev.card;
+ int i = 0;
+ static int reset_count = 10;
+
+ ENTER();
+
+ cardp->rinfo.priv = priv;
+
+restart:
+ if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+ lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n");
+ LEAVE();
+ return -1;
+ }
+
+#ifdef SUPPORT_BOOT_COMMAND
+ cardp->bootcmdresp = 0;
+ do {
+ int j = 0;
+ i++;
+ /* Issue Boot command = 1, Boot from Download-FW */
+ if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+ /* wait for command response */
+ do {
+ j++;
+ msleep_interruptible(100);
+ } while (cardp->bootcmdresp == 0 && j < 10);
+ } while (cardp->bootcmdresp == 0 && i < 5);
+
+ if (cardp->bootcmdresp == 0) {
+ if (--reset_count >= 0) {
+ libertas_do_reset(priv);
+ goto restart;
+ }
+ return -1;
+ }
+#endif
+
+ i = 0;
+ priv->adapter->fw_ready = 0;
+
+ cardp->totalbytes = 0;
+ cardp->fwlastblksent = 0;
+ cardp->CRC_OK = 1;
+ cardp->fwdnldover = 0;
+ cardp->fwseqnum = -1;
+ cardp->totalbytes = 0;
+ cardp->fwfinalblk = 0;
+
+ if_prog_firmware(priv);
+
+ do {
+ lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n");
+ i++;
+ msleep_interruptible(100);
+ if (priv->adapter->surpriseremoved || i >= 20)
+ break;
+ } while (!cardp->fwdnldover);
+
+ if (!cardp->fwdnldover) {
+ lbs_pr_info("failed to load fw, resetting device!\n");
+ if (--reset_count >= 0) {
+ libertas_do_reset(priv);
+ goto restart;
+ }
+
+ lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+ LEAVE();
+ return -1;
+ }
+
+ if_usb_submit_rx_urb(priv);
+
+ /* Delay 200 ms to waiting for the FW ready */
+ msleep_interruptible(200);
+
+ priv->adapter->fw_ready = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Given a usb_card_rec return its wlan_private
+ * @param card pointer to a usb_card_rec
+ * @return pointer to wlan_private
+ */
+wlan_private *libertas_sbi_get_priv(void *card)
+{
+ struct usb_card_rec *cardp = card;
+ return cardp->priv;
+}
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private * priv)
+{
+ return 0;
+}
+
+int libertas_sbi_resume(wlan_private * priv)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+ wlan_private *priv = cardp->priv;
+
+ ENTER();
+
+ if (priv->adapter->psstate != PS_STATE_FULL_POWER)
+ return -1;
+
+ netif_device_detach(cardp->eth_dev);
+
+ /* Unlink tx & rx urb */
+ usb_kill_urb(cardp->tx_urb);
+ usb_kill_urb(cardp->rx_urb);
+
+ cardp->rx_urb_recall = 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int if_usb_resume(struct usb_interface *intf)
+{
+ struct usb_card_rec *cardp = usb_get_intfdata(intf);
+
+ ENTER();
+
+ cardp->rx_urb_recall = 0;
+
+ if_usb_submit_rx_urb(cardp->priv);
+
+ netif_device_attach(cardp->eth_dev);
+
+ LEAVE();
+ return 0;
+}
+#else
+#define if_usb_suspend NULL
+#define if_usb_resume NULL
+#endif
+
+static struct usb_driver if_usb_driver = {
+ /* driver name */
+ .name = usbdriver_name,
+ /* probe function name */
+ .probe = if_usb_probe,
+ /* disconnect function name */
+ .disconnect = if_usb_disconnect,
+ /* device signature table */
+ .id_table = if_usb_table,
+ .suspend = if_usb_suspend,
+ .resume = if_usb_resume,
+};
+
+/**
+ * @brief This function registers driver.
+ * @param add pointer to add_card callback function
+ * @param remove pointer to remove card callback function
+ * @param arg pointer to call back function parameter
+ * @return dummy success variable
+ */
+int libertas_sbi_register(void)
+{
+ /*
+ * API registers the Marvell USB driver
+ * to the USB system
+ */
+ usb_register(&if_usb_driver);
+
+ /* Return success to wlan layer */
+ return 0;
+}
+
+/**
+ * @brief This function removes usb driver.
+ * @return N/A
+ */
+void libertas_sbi_unregister(void)
+{
+ /* API unregisters the driver from USB subsystem */
+ usb_deregister(&if_usb_driver);
+ return;
+}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
new file mode 100644
index 00000000000..785116720bc
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -0,0 +1,109 @@
+/**
+ * This file contains definition for USB interface.
+ */
+#define CMD_TYPE_REQUEST 0xF00DFACE
+#define CMD_TYPE_DATA 0xBEADC0DE
+#define CMD_TYPE_INDICATION 0xBEEFFACE
+
+#define IPFIELD_ALIGN_OFFSET 2
+
+#define USB8388_VID_1 0x1286
+#define USB8388_PID_1 0x2001
+#define USB8388_VID_2 0x05a3
+#define USB8388_PID_2 0x8388
+
+#ifdef SUPPORT_BOOT_COMMAND
+#define BOOT_CMD_FW_BY_USB 0x01
+#define BOOT_CMD_FW_IN_EEPROM 0x02
+#define BOOT_CMD_UPDATE_BOOT2 0x03
+#define BOOT_CMD_UPDATE_FW 0x04
+#define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */
+
+struct bootcmdstr
+{
+ u32 u32magicnumber;
+ u8 u8cmd_tag;
+ u8 au8dumy[11];
+};
+
+#define BOOT_CMD_RESP_OK 0x0001
+#define BOOT_CMD_RESP_FAIL 0x0000
+
+struct bootcmdrespStr
+{
+ u32 u32magicnumber;
+ u8 u8cmd_tag;
+ u8 u8result;
+ u8 au8dumy[2];
+};
+#endif /* SUPPORT_BOOT_COMMAND */
+
+/* read callback private data */
+struct read_cb_info {
+ wlan_private *priv;
+ struct sk_buff *skb;
+};
+
+/** USB card description structure*/
+struct usb_card_rec {
+ struct net_device *eth_dev;
+ struct usb_device *udev;
+ struct urb *rx_urb, *tx_urb;
+ void *priv;
+ struct read_cb_info rinfo;
+
+ int bulk_in_size;
+ u8 bulk_in_endpointAddr;
+
+ u8 *bulk_out_buffer;
+ int bulk_out_size;
+ u8 bulk_out_endpointAddr;
+
+ u8 CRC_OK;
+ u32 fwseqnum;
+ u32 lastseqnum;
+ u32 totalbytes;
+ u32 fwlastblksent;
+ u8 fwdnldover;
+ u8 fwfinalblk;
+
+ u32 usb_event_cause;
+ u8 usb_int_cause;
+
+ u8 rx_urb_recall;
+
+ u8 bootcmdresp;
+};
+
+/** fwheader */
+struct fwheader {
+ u32 dnldcmd;
+ u32 baseaddr;
+ u32 datalength;
+ u32 CRC;
+};
+
+#define FW_MAX_DATA_BLK_SIZE 600
+/** FWData */
+struct FWData {
+ struct fwheader fwheader;
+ u32 seqnum;
+ u8 data[FW_MAX_DATA_BLK_SIZE];
+};
+
+/** fwsyncheader */
+struct fwsyncheader {
+ u32 cmd;
+ u32 seqnum;
+};
+
+#define FW_HAS_DATA_TO_RECV 0x00000001
+#define FW_HAS_LAST_BLOCK 0x00000004
+
+#define FW_DATA_XMIT_SIZE \
+ sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32)
+
+int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
+void if_usb_free(struct usb_card_rec *cardp);
+int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
+
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c
new file mode 100644
index 00000000000..82b39642423
--- /dev/null
+++ b/drivers/net/wireless/libertas/ioctl.c
@@ -0,0 +1,2500 @@
+/**
+ * This file contains ioctl functions
+ */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "wext.h"
+
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
+ IW_ESSID_MAX_SIZE + \
+ IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
+ IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
+ IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
+
+#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
+
+static int setrxantenna(wlan_private * priv, int mode)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2
+ && mode != RF_ANTENNA_AUTO) {
+ return -EINVAL;
+ }
+
+ adapter->rxantennamode = mode;
+
+ lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_set_rx,
+ cmd_option_waitforrsp, 0,
+ &adapter->rxantennamode);
+ return ret;
+}
+
+static int settxantenna(wlan_private * priv, int mode)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2)
+ && (mode != RF_ANTENNA_AUTO)) {
+ return -EINVAL;
+ }
+
+ adapter->txantennamode = mode;
+
+ lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_set_tx,
+ cmd_option_waitforrsp, 0,
+ &adapter->txantennamode);
+
+ return ret;
+}
+
+static int getrxantenna(wlan_private * priv, char *buf)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ // clear it, so we will know if the value
+ // returned below is correct or not.
+ adapter->rxantennamode = 0;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_get_rx,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode);
+
+ return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1;
+}
+
+static int gettxantenna(wlan_private * priv, char *buf)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ // clear it, so we will know if the value
+ // returned below is correct or not.
+ adapter->txantennamode = 0;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna,
+ cmd_act_get_tx,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode);
+
+ return sprintf(buf, "0x%04x", adapter->txantennamode) + 1;
+}
+
+static int wlan_set_region(wlan_private * priv, u16 region_code)
+{
+ int i;
+
+ for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
+ // use the region code to search for the index
+ if (region_code == libertas_region_code_to_index[i]) {
+ priv->adapter->regiontableindex = (u16) i;
+ priv->adapter->regioncode = region_code;
+ break;
+ }
+ }
+
+ // if it's unidentified region code
+ if (i >= MRVDRV_MAX_REGION_CODE) {
+ lbs_pr_debug(1, "region Code not identified\n");
+ LEAVE();
+ return -1;
+ }
+
+ if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Get/Set Firmware wakeup method
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to user data
+ * @return 0--success, otherwise fail
+ */
+static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data;
+ ENTER();
+
+ if ((int)wrq->u.data.length == 0) {
+ if (copy_to_user
+ (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) {
+ lbs_pr_alert("copy_to_user failed!\n");
+ return -EFAULT;
+ }
+ } else {
+ if ((int)wrq->u.data.length > 1) {
+ lbs_pr_alert("ioctl too many args!\n");
+ return -EFAULT;
+ }
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_alert("Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->pkttxctrl = (u32) data;
+ }
+
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Get/Set NULL Package generation interval
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to user data
+ * @return 0--success, otherwise fail
+ */
+static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data;
+ ENTER();
+
+ if ((int)wrq->u.data.length == 0) {
+ data = adapter->nullpktinterval;
+
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ lbs_pr_alert( "copy_to_user failed!\n");
+ return -EFAULT;
+ }
+ } else {
+ if ((int)wrq->u.data.length > 1) {
+ lbs_pr_alert( "ioctl too many args!\n");
+ return -EFAULT;
+ }
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->nullpktinterval = data;
+ }
+
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data[2];
+ ENTER();
+ data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+ data[1] = adapter->rxpd_rate;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+ wrq->u.data.length = 2;
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ int data[4];
+
+ ENTER();
+ memset(data, 0, sizeof(data));
+ if (wrq->u.data.length) {
+ if (copy_from_user(data, wrq->u.data.pointer,
+ min_t(size_t, wrq->u.data.length, 4) * sizeof(int)))
+ return -EFAULT;
+ }
+ if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) {
+ if (adapter->connect_status == libertas_connected) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0,
+ cmd_option_waitforrsp,
+ 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+ }
+
+ if (wrq->u.data.length == 0) {
+ data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+ data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+ data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+ data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4))
+ return -EFAULT;
+ wrq->u.data.length = 4;
+ } else if (data[0] == 0) {
+ data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG];
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else if (data[0] == 1) {
+ data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG];
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else if (data[0] == 2) {
+ data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG];
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else if (data[0] == 3) {
+ data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int)))
+ return -EFAULT;
+ wrq->u.data.length = 1;
+ } else
+ return -ENOTSUPP;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq)
+{
+ int data;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (wrq->u.data.length > 0) {
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int)))
+ return -EFAULT;
+
+ lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data);
+ if ((data > MRVDRV_MAX_BEACON_INTERVAL)
+ || (data < MRVDRV_MIN_BEACON_INTERVAL))
+ return -ENOTSUPP;
+ adapter->beaconperiod = data;
+ }
+ data = adapter->beaconperiod;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int)))
+ return -EFAULT;
+
+ wrq->u.data.length = 1;
+
+ return 0;
+}
+
+static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ int temp;
+ int data = 0;
+ int *val;
+
+ ENTER();
+ data = SUBCMD_DATA(wrq);
+ if ((data == 0) || (data == 1)) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0, cmd_option_waitforrsp,
+ 0, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+
+ switch (data) {
+ case 0:
+
+ temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+ break;
+ case 1:
+ temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG],
+ adapter->NF[TYPE_BEACON][TYPE_AVG]);
+ break;
+ case 2:
+ temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+ adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+ break;
+ case 3:
+ temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ val = (int *)wrq->u.name;
+ *val = temp;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+ int temp;
+ int data = 0;
+ int *val;
+
+ data = SUBCMD_DATA(wrq);
+ if ((data == 0) || (data == 1)) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0, cmd_option_waitforrsp,
+ 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ }
+
+ switch (data) {
+ case 0:
+ temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG];
+ break;
+ case 1:
+ temp = adapter->NF[TYPE_BEACON][TYPE_AVG];
+ break;
+ case 2:
+ temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG];
+ break;
+ case 3:
+ temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ temp = CAL_NF(temp);
+
+ lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp);
+ val = (int *)wrq->u.name;
+ *val = temp;
+ return 0;
+}
+
+static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int *pdata;
+ struct iwreq *wrq = (struct iwreq *)req;
+ int ret = 0;
+ adapter->txrate = 0;
+ lbs_pr_debug(1, "wlan_get_txrate_ioctl\n");
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query,
+ cmd_act_get, cmd_option_waitforrsp,
+ 0, NULL);
+ if (ret)
+ return ret;
+
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->txrate;
+ return 0;
+}
+
+static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ char status[64];
+ wlan_adapter *adapter = priv->adapter;
+
+ memset(status, 0, sizeof(status));
+
+ switch (adapter->inframode) {
+ case wlan802_11ibss:
+ if (adapter->connect_status == libertas_connected) {
+ if (adapter->adhoccreate)
+ memcpy(&status, "AdhocStarted", sizeof(status));
+ else
+ memcpy(&status, "AdhocJoined", sizeof(status));
+ } else {
+ memcpy(&status, "AdhocIdle", sizeof(status));
+ }
+ break;
+ case wlan802_11infrastructure:
+ memcpy(&status, "Inframode", sizeof(status));
+ break;
+ default:
+ memcpy(&status, "AutoUnknownmode", sizeof(status));
+ break;
+ }
+
+ lbs_pr_debug(1, "status = %s\n", status);
+ wrq->u.data.length = strlen(status) + 1;
+
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer,
+ &status, wrq->u.data.length))
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set/Get WPA IE
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+
+ if (wrq->u.data.length) {
+ if (wrq->u.data.length > sizeof(adapter->wpa_ie)) {
+ lbs_pr_debug(1, "failed to copy WPA IE, too big \n");
+ return -EFAULT;
+ }
+ if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "failed to copy WPA IE \n");
+ return -EFAULT;
+ }
+ adapter->wpa_ie_len = wrq->u.data.length;
+ lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len,
+ adapter->wpa_ie[0]);
+ lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len);
+ if (adapter->wpa_ie[0] == WPA_IE)
+ adapter->secinfo.WPAenabled = 1;
+ else if (adapter->wpa_ie[0] == WPA2_IE)
+ adapter->secinfo.WPA2enabled = 1;
+ else {
+ adapter->secinfo.WPAenabled = 0;
+ adapter->secinfo.WPA2enabled = 0;
+ }
+ } else {
+ memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie));
+ adapter->wpa_ie_len = wrq->u.data.length;
+ lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n",
+ adapter->wpa_ie_len, adapter->wpa_ie[0]);
+ adapter->secinfo.WPAenabled = 0;
+ adapter->secinfo.WPA2enabled = 0;
+ }
+
+ // enable/disable RSN in firmware if WPA is enabled/disabled
+ // depending on variable adapter->secinfo.WPAenabled is set or not
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn,
+ cmd_act_set, cmd_option_waitforrsp,
+ 0, NULL);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Auto prescan
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ int data;
+ wlan_adapter *adapter = priv->adapter;
+ int *val;
+
+ data = SUBCMD_DATA(wrq);
+ lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data);
+ adapter->prescan = data;
+
+ val = (int *)wrq->u.name;
+ *val = data;
+ return 0;
+}
+
+static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ u32 mdtim;
+ int idata;
+ int ret = -EINVAL;
+
+ ENTER();
+
+ idata = SUBCMD_DATA(wrq);
+ mdtim = (u32) idata;
+ if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM)
+ && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM))
+ || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) {
+ priv->adapter->multipledtim = mdtim;
+ ret = 0;
+ }
+ if (ret)
+ lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n");
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set authentication mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int alg;
+ struct iwreq *wrq = (struct iwreq *)req;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (wrq->u.data.flags == 0) {
+ //from iwpriv subcmd
+ alg = SUBCMD_DATA(wrq);
+ } else {
+ //from wpa_supplicant subcmd
+ if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ }
+
+ lbs_pr_debug(1, "auth alg is %#x\n", alg);
+
+ switch (alg) {
+ case AUTH_ALG_SHARED_KEY:
+ adapter->secinfo.authmode = wlan802_11authmodeshared;
+ break;
+ case AUTH_ALG_NETWORK_EAP:
+ adapter->secinfo.authmode =
+ wlan802_11authmodenetworkEAP;
+ break;
+ case AUTH_ALG_OPEN_SYSTEM:
+ default:
+ adapter->secinfo.authmode = wlan802_11authmodeopen;
+ break;
+ }
+ return 0;
+}
+
+/**
+ * @brief Set 802.1x authentication mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int alg;
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ if (wrq->u.data.flags == 0) {
+ //from iwpriv subcmd
+ alg = SUBCMD_DATA(wrq);
+ } else {
+ //from wpa_supplicant subcmd
+ if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ }
+ lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg);
+ priv->adapter->secinfo.auth1xalg = alg;
+ return 0;
+}
+
+static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int mode;
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ ENTER();
+
+ if (wrq->u.data.flags == 0) {
+ //from iwpriv subcmd
+ mode = SUBCMD_DATA(wrq);
+ } else {
+ //from wpa_supplicant subcmd
+ if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ }
+ lbs_pr_debug(1, "encryption mode is %#x\n", mode);
+ priv->adapter->secinfo.Encryptionmode = mode;
+
+ LEAVE();
+ return 0;
+}
+
+static void adjust_mtu(wlan_private * priv)
+{
+ int mtu_increment = 0;
+
+ if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ mtu_increment += sizeof(struct ieee80211_hdr_4addr);
+
+ if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP)
+ mtu_increment += max(sizeof(struct tx_radiotap_hdr),
+ sizeof(struct rx_radiotap_hdr));
+ priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN
+ - sizeof(struct ethhdr)
+ + mtu_increment;
+}
+
+/**
+ * @brief Set Link-Layer Layer mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int mode;
+
+ mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+ switch (mode) {
+ case WLAN_LINKMODE_802_3:
+ priv->adapter->linkmode = mode;
+ break;
+ case WLAN_LINKMODE_802_11:
+ priv->adapter->linkmode = mode;
+ break;
+ default:
+ lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n",
+ mode);
+ return -EINVAL;
+ break;
+ }
+ lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode);
+
+ adjust_mtu(priv);
+
+ return 0;
+}
+
+/**
+ * @brief Set Radio header mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int mode;
+
+ mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data;
+
+ switch (mode) {
+ case WLAN_RADIOMODE_NONE:
+ priv->adapter->radiomode = mode;
+ break;
+ case WLAN_RADIOMODE_RADIOTAP:
+ priv->adapter->radiomode = mode;
+ break;
+ default:
+ lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n",
+ mode);
+ return -EINVAL;
+ }
+ lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode);
+
+ adjust_mtu(priv);
+ return 0;
+}
+
+/**
+ * @brief Set Debug header mode
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ priv->adapter->debugmode = (int)((struct ifreq *)
+ ((u8 *) req + 4))->ifr_data;
+ return 0;
+}
+
+static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv,
+ struct ifreq *req)
+{
+ int len;
+ char buf[8];
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n");
+ len = getrxantenna(priv, buf);
+
+ wrq->u.data.length = len;
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+ lbs_pr_debug(1, "CopyToUser failed\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv,
+ struct ifreq *req)
+{
+ int len;
+ char buf[8];
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n");
+ len = gettxantenna(priv, buf);
+
+ wrq->u.data.length = len;
+ if (wrq->u.data.pointer) {
+ if (copy_to_user(wrq->u.data.pointer, &buf, len)) {
+ lbs_pr_debug(1, "CopyToUser failed\n");
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief Get the MAC TSF value from the firmware
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure containing buffer
+ * space to store a TSF value retrieved from the firmware
+ *
+ * @return 0 if successful; IOCTL error code otherwise
+ */
+static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ u64 tsfval;
+ int ret;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_get_tsf,
+ 0, cmd_option_waitforrsp, 0, &tsfval);
+
+ lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval);
+
+ if (ret != 0) {
+ lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n");
+ ret = -EFAULT;
+ } else {
+ if (copy_to_user(wrq->u.data.pointer,
+ &tsfval,
+ min_t(size_t, wrq->u.data.length,
+ sizeof(tsfval))) != 0) {
+
+ lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n");
+ ret = -EFAULT;
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/**
+ * @brief Get/Set adapt rate
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret;
+ wlan_adapter *adapter = priv->adapter;
+ int data[2];
+
+ memset(data, 0, sizeof(data));
+ if (!wrq->u.data.length) {
+ lbs_pr_debug(1, "Get ADAPT RATE SET\n");
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rate_adapt_rateset,
+ cmd_act_get,
+ cmd_option_waitforrsp, 0, NULL);
+ data[0] = adapter->enablehwauto;
+ data[1] = adapter->ratebitmap;
+ if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+#define GET_TWO_INT 2
+ wrq->u.data.length = GET_TWO_INT;
+ } else {
+ lbs_pr_debug(1, "Set ADAPT RATE SET\n");
+ if (wrq->u.data.length > 2)
+ return -EINVAL;
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->enablehwauto = data[0];
+ adapter->ratebitmap = data[1];
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rate_adapt_rateset,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+ }
+ return ret;
+}
+
+/**
+ * @brief Get/Set inactivity timeout
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to iwreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret;
+ int data = 0;
+ u16 timeout = 0;
+
+ ENTER();
+ if (wrq->u.data.length > 1)
+ return -ENOTSUPP;
+
+ if (wrq->u.data.length == 0) {
+ /* Get */
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_inactivity_timeout,
+ cmd_act_get,
+ cmd_option_waitforrsp, 0,
+ &timeout);
+ data = timeout;
+ if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+ } else {
+ /* Set */
+ if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ timeout = data;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_inactivity_timeout,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0,
+ &timeout);
+ }
+
+ wrq->u.data.length = 1;
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ int ret;
+ char buf[GETLOG_BUFSIZE - 1];
+ wlan_adapter *adapter = priv->adapter;
+
+ lbs_pr_debug(1, " GET STATS\n");
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log,
+ 0, cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ return ret;
+ }
+
+ if (wrq->u.data.pointer) {
+ sprintf(buf, "\n mcasttxframe %u failed %u retry %u "
+ "multiretry %u framedup %u "
+ "rtssuccess %u rtsfailure %u ackfailure %u\n"
+ "rxfrag %u mcastrxframe %u fcserror %u "
+ "txframe %u wepundecryptable %u ",
+ adapter->logmsg.mcasttxframe,
+ adapter->logmsg.failed,
+ adapter->logmsg.retry,
+ adapter->logmsg.multiretry,
+ adapter->logmsg.framedup,
+ adapter->logmsg.rtssuccess,
+ adapter->logmsg.rtsfailure,
+ adapter->logmsg.ackfailure,
+ adapter->logmsg.rxfrag,
+ adapter->logmsg.mcastrxframe,
+ adapter->logmsg.fcserror,
+ adapter->logmsg.txframe,
+ adapter->logmsg.wepundecryptable);
+ wrq->u.data.length = strlen(buf) + 1;
+ if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ u8 buf[12];
+ u8 *option[] = { "active", "passive", "get", };
+ int i, max_options = (sizeof(option) / sizeof(option[0]));
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ if (priv->adapter->enable11d) {
+ lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n");
+ return -EFAULT;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+ wrq->u.data.length)))
+ return -EFAULT;
+
+ lbs_pr_debug(1, "Scan type Option = %s\n", buf);
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ for (i = 0; i < max_options; i++) {
+ if (!strcmp(buf, option[i]))
+ break;
+ }
+
+ switch (i) {
+ case 0:
+ adapter->scantype = cmd_scan_type_active;
+ break;
+ case 1:
+ adapter->scantype = cmd_scan_type_passive;
+ break;
+ case 2:
+ wrq->u.data.length = strlen(option[adapter->scantype]) + 1;
+
+ if (copy_to_user(wrq->u.data.pointer,
+ option[adapter->scantype],
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+
+ break;
+ default:
+ lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ u8 buf[12];
+ u8 *option[] = { "bss", "ibss", "any", "get" };
+ int i, max_options = (sizeof(option) / sizeof(option[0]));
+ int ret = 0;
+
+ ENTER();
+
+ memset(buf, 0, sizeof(buf));
+
+ if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf),
+ wrq->u.data.length))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ lbs_pr_debug(1, "Scan mode Option = %s\n", buf);
+
+ buf[sizeof(buf) - 1] = '\0';
+
+ for (i = 0; i < max_options; i++) {
+ if (!strcmp(buf, option[i]))
+ break;
+ }
+
+ switch (i) {
+
+ case 0:
+ adapter->scanmode = cmd_bss_type_bss;
+ break;
+ case 1:
+ adapter->scanmode = cmd_bss_type_ibss;
+ break;
+ case 2:
+ adapter->scanmode = cmd_bss_type_any;
+ break;
+ case 3:
+
+ wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1;
+
+ lbs_pr_debug(1, "Get Scan mode Option = %s\n",
+ option[adapter->scanmode - 1]);
+
+ lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length);
+
+ if (copy_to_user(wrq->u.data.pointer,
+ option[adapter->scanmode - 1],
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ lbs_pr_debug(1, "GET Scan type Option after copy = %s\n",
+ (char *)wrq->u.data.pointer);
+
+ break;
+
+ default:
+ lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get/Set Adhoc G Rate
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param wrq A pointer to user data
+ * @return 0--success, otherwise fail
+ */
+static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int data, data1;
+ int *val;
+
+ ENTER();
+
+ data1 = SUBCMD_DATA(wrq);
+ switch (data1) {
+ case 0:
+ adapter->adhoc_grate_enabled = 0;
+ break;
+ case 1:
+ adapter->adhoc_grate_enabled = 1;
+ break;
+ case 2:
+ break;
+ default:
+ return -EINVAL;
+ }
+ data = adapter->adhoc_grate_enabled;
+ val = (int *)wrq->u.name;
+ *val = data;
+ LEAVE();
+ return 0;
+}
+
+static inline int hex2int(char c)
+{
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ if (c >= 'A' && c <= 'F')
+ return (c - 'A' + 10);
+ return -1;
+}
+
+/* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
+ into binary format (6 bytes).
+
+ This function expects that each byte is represented with 2 characters
+ (e.g., 11:2:11:11:11:11 is invalid)
+
+ */
+static char *eth_str2addr(char *ethstr, u8 * addr)
+{
+ int i, val, val2;
+ char *pos = ethstr;
+
+ /* get rid of initial blanks */
+ while (*pos == ' ' || *pos == '\t')
+ ++pos;
+
+ for (i = 0; i < 6; i++) {
+ val = hex2int(*pos++);
+ if (val < 0)
+ return NULL;
+ val2 = hex2int(*pos++);
+ if (val2 < 0)
+ return NULL;
+ addr[i] = (val * 16 + val2) & 0xff;
+
+ if (i < 5 && *pos++ != ':')
+ return NULL;
+ }
+ return pos;
+}
+
+/* this writes xx:xx:xx:xx:xx:xx into ethstr
+ (ethstr must have space for 18 chars) */
+static int eth_addr2str(u8 * addr, char *ethstr)
+{
+ int i;
+ char *pos = ethstr;
+
+ for (i = 0; i < 6; i++) {
+ sprintf(pos, "%02x", addr[i] & 0xff);
+ pos += 2;
+ if (i < 5)
+ *pos++ = ':';
+ }
+ return 17;
+}
+
+/**
+ * @brief Add an entry to the BT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char ethaddrs_str[18];
+ char *pos;
+ u8 ethaddr[ETH_ALEN];
+
+ ENTER();
+ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+ sizeof(ethaddrs_str)))
+ return -EFAULT;
+
+ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+ lbs_pr_info("BT_ADD: Invalid MAC address\n");
+ return -EINVAL;
+ }
+
+ lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
+ LEAVE();
+ return (libertas_prepare_and_send_command(priv, cmd_bt_access,
+ cmd_act_bt_access_add,
+ cmd_option_waitforrsp, 0, ethaddr));
+}
+
+/**
+ * @brief Delete an entry from the BT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char ethaddrs_str[18];
+ u8 ethaddr[ETH_ALEN];
+ char *pos;
+
+ ENTER();
+ if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
+ sizeof(ethaddrs_str)))
+ return -EFAULT;
+
+ if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
+ lbs_pr_info("Invalid MAC address\n");
+ return -EINVAL;
+ }
+
+ lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
+
+ return (libertas_prepare_and_send_command(priv,
+ cmd_bt_access,
+ cmd_act_bt_access_del,
+ cmd_option_waitforrsp, 0, ethaddr));
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Reset all entries from the BT table
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_reset_ioctl(wlan_private * priv)
+{
+ ENTER();
+
+ lbs_pr_alert( "BT: resetting\n");
+
+ return (libertas_prepare_and_send_command(priv,
+ cmd_bt_access,
+ cmd_act_bt_access_reset,
+ cmd_option_waitforrsp, 0, NULL));
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief List an entry from the BT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ int pos;
+ char *addr1;
+ struct iwreq *wrq = (struct iwreq *)req;
+ /* used to pass id and store the bt entry returned by the FW */
+ union {
+ int id;
+ char addr1addr2[2 * ETH_ALEN];
+ } param;
+ static char outstr[64];
+ char *pbuf = outstr;
+ int ret;
+
+ ENTER();
+
+ if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -1;
+ }
+ param.id = simple_strtoul(outstr, NULL, 10);
+ pos = sprintf(pbuf, "%d: ", param.id);
+ pbuf += pos;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
+ cmd_act_bt_access_list,
+ cmd_option_waitforrsp, 0,
+ (char *)&param);
+
+ if (ret == 0) {
+ addr1 = param.addr1addr2;
+
+ pos = sprintf(pbuf, "ignoring traffic from ");
+ pbuf += pos;
+ pos = eth_addr2str(addr1, pbuf);
+ pbuf += pos;
+ } else {
+ sprintf(pbuf, "(null)");
+ pbuf += pos;
+ }
+
+ wrq->u.data.length = strlen(outstr);
+ if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Find the next parameter in an input string
+ * @param ptr A pointer to the input parameter string
+ * @return A pointer to the next parameter, or 0 if no parameters left.
+ */
+static char * next_param(char * ptr)
+{
+ if (!ptr) return NULL;
+ while (*ptr == ' ' || *ptr == '\t') ++ptr;
+ return (*ptr == '\0') ? NULL : ptr;
+}
+
+/**
+ * @brief Add an entry to the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[128];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+ lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+ lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.metric =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.metric = FWT_DEFAULT_METRIC;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.dir = FWT_DEFAULT_DIR;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.ssn =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.ssn = FWT_DEFAULT_SSN;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.dsn =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.dsn = FWT_DEFAULT_DSN;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.ttl = FWT_DEFAULT_TTL;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.expiration =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.snr =
+ cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+ else
+ fwt_access.snr = FWT_DEFAULT_SNR;
+
+#ifdef DEBUG
+ {
+ char ethaddr1_str[18], ethaddr2_str[18];
+ eth_addr2str(fwt_access.da, ethaddr1_str);
+ eth_addr2str(fwt_access.ra, ethaddr2_str);
+ lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
+ fwt_access.dir, ethaddr2_str);
+ lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
+ fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
+ fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
+ fwt_access.sleepmode, fwt_access.snr);
+ }
+#endif
+
+ LEAVE();
+ return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_add,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access));
+}
+
+/**
+ * @brief Delete an entry from the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[64];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+ lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
+ lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
+ return -EINVAL;
+ }
+
+ if ((ptr = next_param(ptr)))
+ fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
+ else
+ fwt_access.dir = FWT_DEFAULT_DIR;
+
+#ifdef DEBUG
+ {
+ char ethaddr1_str[18], ethaddr2_str[18];
+ lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
+ eth_addr2str(fwt_access.da, ethaddr1_str);
+ eth_addr2str(fwt_access.ra, ethaddr2_str);
+ lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
+ ethaddr2_str, fwt_access.dir);
+ }
+#endif
+
+ LEAVE();
+ return (libertas_prepare_and_send_command(priv,
+ cmd_fwt_access,
+ cmd_act_fwt_access_del,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access));
+}
+
+
+/**
+ * @brief Print route parameters
+ * @param fwt_access struct cmd_ds_fwt_access with route info
+ * @param buf destination buffer for route info
+ */
+static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
+{
+ buf += sprintf(buf, " ");
+ buf += eth_addr2str(fwt_access.da, buf);
+ buf += sprintf(buf, " ");
+ buf += eth_addr2str(fwt_access.ra, buf);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
+ buf += sprintf(buf, " %u", fwt_access.dir);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
+ buf += sprintf(buf, " %u", fwt_access.hopcount);
+ buf += sprintf(buf, " %u", fwt_access.ttl);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
+ buf += sprintf(buf, " %u", fwt_access.sleepmode);
+ buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
+}
+
+/**
+ * @brief Lookup an entry in the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[64];
+ char *ptr;
+ static struct cmd_ds_fwt_access fwt_access;
+ static char out_str[128];
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
+ lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
+ return -EINVAL;
+ }
+
+#ifdef DEBUG
+ {
+ char ethaddr1_str[18];
+ lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
+ eth_addr2str(fwt_access.da, ethaddr1_str);
+ lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_fwt_access,
+ cmd_act_fwt_access_lookup,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0)
+ print_route(fwt_access, out_str);
+ else
+ sprintf(out_str, "(null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Reset all entries from the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_reset_ioctl(wlan_private * priv)
+{
+ lbs_pr_debug(1, "FWT: resetting\n");
+
+ return (libertas_prepare_and_send_command(priv,
+ cmd_fwt_access,
+ cmd_act_fwt_access_reset,
+ cmd_option_waitforrsp, 0, NULL));
+}
+
+/**
+ * @brief List an entry from the FWT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[8];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr = in_str;
+ static char out_str[128];
+ char *pbuf = out_str;
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+ {
+ lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
+ lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_list,
+ cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+ if (ret == 0)
+ print_route(fwt_access, pbuf);
+ else
+ pbuf += sprintf(pbuf, " (null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief List an entry from the FRT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[64];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr = in_str;
+ static char out_str[128];
+ char *pbuf = out_str;
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+ {
+ lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
+ lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_list_route,
+ cmd_option_waitforrsp, 0, (void *)&fwt_access);
+
+ if (ret == 0) {
+ pbuf += sprintf(pbuf, " ");
+ pbuf += eth_addr2str(fwt_access.da, pbuf);
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
+ pbuf += sprintf(pbuf, " %u", fwt_access.dir);
+ /* note that the firmware returns the nid in the id field */
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
+ pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount);
+ pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl);
+ pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
+ } else
+ pbuf += sprintf(pbuf, " (null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief List an entry from the FNT table
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct iwreq *wrq = (struct iwreq *)req;
+ char in_str[8];
+ static struct cmd_ds_fwt_access fwt_access;
+ char *ptr = in_str;
+ static char out_str[128];
+ char *pbuf = out_str;
+ int ret;
+
+ ENTER();
+ if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
+ return -EFAULT;
+
+ memset(&fwt_access, 0, sizeof(fwt_access));
+ fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
+
+#ifdef DEBUG
+ {
+ lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
+ lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
+ }
+#endif
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_list_neighbor,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0) {
+ pbuf += sprintf(pbuf, " ra ");
+ pbuf += eth_addr2str(fwt_access.ra, pbuf);
+ pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
+ pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
+ pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
+ } else
+ pbuf += sprintf(pbuf, " (null)");
+
+ wrq->u.data.length = strlen(out_str);
+ if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
+ wrq->u.data.length)) {
+ lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
+ return -EFAULT;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Cleans up the route (FRT) and neighbor (FNT) tables
+ * (Garbage Collection)
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ static struct cmd_ds_fwt_access fwt_access;
+ int ret;
+
+ ENTER();
+
+ lbs_pr_debug(1, "FWT: cleaning up\n");
+
+ memset(&fwt_access, 0, sizeof(fwt_access));
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_cleanup,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0)
+ req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+ else
+ return -EFAULT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Gets firmware internal time (debug purposes)
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ static struct cmd_ds_fwt_access fwt_access;
+ int ret;
+
+ ENTER();
+
+ lbs_pr_debug(1, "FWT: getting time\n");
+
+ memset(&fwt_access, 0, sizeof(fwt_access));
+
+ ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
+ cmd_act_fwt_access_time,
+ cmd_option_waitforrsp, 0,
+ (void *)&fwt_access);
+
+ if (ret == 0)
+ req->ifr_data = (char *)(le32_to_cpu(fwt_access.references));
+ else
+ return -EFAULT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Gets mesh ttl from firmware
+ * @param priv A pointer to wlan_private structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+
+ ENTER();
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+
+ ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+ cmd_act_mesh_get_ttl,
+ cmd_option_waitforrsp, 0,
+ (void *)&mesh_access);
+
+ if (ret == 0) {
+ req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0]));
+ }
+ else
+ return -EFAULT;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Gets mesh ttl from firmware
+ * @param priv A pointer to wlan_private structure
+ * @param ttl New ttl value
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
+{
+ struct cmd_ds_mesh_access mesh_access;
+ int ret;
+
+ ENTER();
+
+ if( (ttl > 0xff) || (ttl < 0) )
+ return -EINVAL;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ mesh_access.data[0] = ttl;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
+ cmd_act_mesh_set_ttl,
+ cmd_option_waitforrsp, 0,
+ (void *)&mesh_access);
+
+ if (ret != 0)
+ ret = -EFAULT;
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd command
+ * @return 0--success, otherwise fail
+ */
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int subcmd = 0;
+ int idata = 0;
+ int *pdata;
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iwreq *wrq = (struct iwreq *)req;
+
+ ENTER();
+
+ lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case WLANSCAN_TYPE:
+ lbs_pr_debug(1, "Scan type Ioctl\n");
+ ret = wlan_scan_type_ioctl(priv, wrq);
+ break;
+
+ case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
+ switch (wrq->u.data.flags) {
+ case WLANDEAUTH:
+ lbs_pr_debug(1, "Deauth\n");
+ libertas_send_deauth(priv);
+ break;
+
+ case WLANADHOCSTOP:
+ lbs_pr_debug(1, "Adhoc stop\n");
+ ret = libertas_do_adhocstop_ioctl(priv);
+ break;
+
+ case WLANRADIOON:
+ wlan_radio_ioctl(priv, 1);
+ break;
+
+ case WLANRADIOOFF:
+ wlan_radio_ioctl(priv, 0);
+ break;
+ case WLANWLANIDLEON:
+ libertas_idle_on(priv);
+ break;
+ case WLANWLANIDLEOFF:
+ libertas_idle_off(priv);
+ break;
+ case WLAN_SUBCMD_BT_RESET: /* bt_reset */
+ wlan_bt_reset_ioctl(priv);
+ break;
+ case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */
+ wlan_fwt_reset_ioctl(priv);
+ break;
+ } /* End of switch */
+ break;
+
+ case WLANSETWPAIE:
+ ret = wlan_setwpaie_ioctl(priv, req);
+ break;
+ case WLAN_SETINT_GETINT:
+ /* The first 4 bytes of req->ifr_data is sub-ioctl number
+ * after 4 bytes sits the payload.
+ */
+ subcmd = (int)req->ifr_data; //from iwpriv subcmd
+ switch (subcmd) {
+ case WLANNF:
+ ret = wlan_get_nf(priv, wrq);
+ break;
+ case WLANRSSI:
+ ret = wlan_get_rssi(priv, wrq);
+ break;
+ case WLANENABLE11D:
+ ret = libertas_cmd_enable_11d(priv, wrq);
+ break;
+ case WLANADHOCGRATE:
+ ret = wlan_do_set_grate_ioctl(priv, wrq);
+ break;
+ case WLAN_SUBCMD_SET_PRESCAN:
+ ret = wlan_subcmd_setprescan_ioctl(priv, wrq);
+ break;
+ }
+ break;
+
+ case WLAN_SETONEINT_GETONEINT:
+ switch (wrq->u.data.flags) {
+ case WLAN_BEACON_INTERVAL:
+ ret = wlan_beacon_interval(priv, wrq);
+ break;
+
+ case WLAN_LISTENINTRVL:
+ if (!wrq->u.data.length) {
+ int data;
+ lbs_pr_debug(1, "Get locallisteninterval value\n");
+#define GET_ONE_INT 1
+ data = adapter->locallisteninterval;
+ if (copy_to_user(wrq->u.data.pointer,
+ &data, sizeof(int))) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = GET_ONE_INT;
+ } else {
+ int data;
+ if (copy_from_user
+ (&data, wrq->u.data.pointer, sizeof(int))) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ lbs_pr_debug(1, "Set locallisteninterval = %d\n",
+ data);
+#define MAX_U16_VAL 65535
+ if (data > MAX_U16_VAL) {
+ lbs_pr_debug(1, "Exceeds U16 value\n");
+ return -EINVAL;
+ }
+ adapter->locallisteninterval = data;
+ }
+ break;
+ case WLAN_TXCONTROL:
+ ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl
+ break;
+
+ case WLAN_NULLPKTINTERVAL:
+ ret = wlan_null_pkt_interval(priv, wrq);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ break;
+
+ case WLAN_SETONEINT_GETNONE:
+ /* The first 4 bytes of req->ifr_data is sub-ioctl number
+ * after 4 bytes sits the payload.
+ */
+ subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd
+
+ if (!subcmd)
+ subcmd = (int)req->ifr_data; //from iwpriv subcmd
+
+ switch (subcmd) {
+ case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */
+ idata = SUBCMD_DATA(wrq);
+ ret = setrxantenna(priv, idata);
+ break;
+ case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */
+ idata = SUBCMD_DATA(wrq);
+ ret = settxantenna(priv, idata);
+ break;
+ case WLAN_SET_ATIM_WINDOW:
+ adapter->atimwindow = SUBCMD_DATA(wrq);
+ adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50);
+ break;
+ case WLANSETBCNAVG:
+ adapter->bcn_avg_factor = SUBCMD_DATA(wrq);
+ if (adapter->bcn_avg_factor == 0)
+ adapter->bcn_avg_factor =
+ DEFAULT_BCN_AVG_FACTOR;
+ if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR)
+ adapter->bcn_avg_factor =
+ DEFAULT_BCN_AVG_FACTOR;
+ break;
+ case WLANSETDATAAVG:
+ adapter->data_avg_factor = SUBCMD_DATA(wrq);
+ if (adapter->data_avg_factor == 0)
+ adapter->data_avg_factor =
+ DEFAULT_DATA_AVG_FACTOR;
+ if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR)
+ adapter->data_avg_factor =
+ DEFAULT_DATA_AVG_FACTOR;
+ break;
+ case WLANSETREGION:
+ idata = SUBCMD_DATA(wrq);
+ ret = wlan_set_region(priv, (u16) idata);
+ break;
+
+ case WLAN_SET_LISTEN_INTERVAL:
+ idata = SUBCMD_DATA(wrq);
+ adapter->listeninterval = (u16) idata;
+ break;
+
+ case WLAN_SET_MULTIPLE_DTIM:
+ ret = wlan_set_multiple_dtim_ioctl(priv, req);
+ break;
+
+ case WLANSETAUTHALG:
+ ret = wlan_setauthalg_ioctl(priv, req);
+ break;
+
+ case WLANSET8021XAUTHALG:
+ ret = wlan_set8021xauthalg_ioctl(priv, req);
+ break;
+
+ case WLANSETENCRYPTIONMODE:
+ ret = wlan_setencryptionmode_ioctl(priv, req);
+ break;
+
+ case WLAN_SET_LINKMODE:
+ ret = wlan_set_linkmode_ioctl(priv, req);
+ break;
+
+ case WLAN_SET_RADIOMODE:
+ ret = wlan_set_radiomode_ioctl(priv, req);
+ break;
+
+ case WLAN_SET_DEBUGMODE:
+ ret = wlan_set_debugmode_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_MESH_SET_TTL:
+ idata = SUBCMD_DATA(wrq);
+ ret = wlan_mesh_set_ttl_ioctl(priv, idata);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ break;
+
+ case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */
+ /*
+ * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is
+ * in flags of iwreq structure, otherwise it will be in
+ * mode member of iwreq structure.
+ */
+ switch ((int)wrq->u.data.flags) {
+ case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */
+ ret = wlan_subcmd_getrxantenna_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */
+ ret = wlan_subcmd_gettxantenna_ioctl(priv, req);
+ break;
+
+ case WLAN_GET_TSF:
+ ret = wlan_get_tsf_ioctl(priv, wrq);
+ break;
+ }
+ break;
+
+ case WLAN_SET128CHAR_GET128CHAR:
+ switch ((int)wrq->u.data.flags) {
+
+ case WLANSCAN_MODE:
+ lbs_pr_debug(1, "Scan mode Ioctl\n");
+ ret = wlan_scan_mode_ioctl(priv, wrq);
+ break;
+
+ case WLAN_GET_ADHOC_STATUS:
+ ret = wlan_get_adhoc_status_ioctl(priv, wrq);
+ break;
+ case WLAN_SUBCMD_BT_ADD:
+ ret = wlan_bt_add_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_BT_DEL:
+ ret = wlan_bt_del_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_BT_LIST:
+ ret = wlan_bt_list_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_ADD:
+ ret = wlan_fwt_add_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_DEL:
+ ret = wlan_fwt_del_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LOOKUP:
+ ret = wlan_fwt_lookup_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
+ ret = wlan_fwt_list_neighbor_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LIST:
+ ret = wlan_fwt_list_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_LIST_ROUTE:
+ ret = wlan_fwt_list_route_ioctl(priv, req);
+ break;
+ }
+ break;
+
+ case WLAN_SETNONE_GETONEINT:
+ switch ((int)req->ifr_data) {
+ case WLANGETBCNAVG:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->bcn_avg_factor;
+ break;
+
+ case WLANGETREGION:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->regioncode;
+ break;
+
+ case WLAN_GET_LISTEN_INTERVAL:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->listeninterval;
+ break;
+
+ case WLAN_GET_LINKMODE:
+ req->ifr_data = (char *)((u32) adapter->linkmode);
+ break;
+
+ case WLAN_GET_RADIOMODE:
+ req->ifr_data = (char *)((u32) adapter->radiomode);
+ break;
+
+ case WLAN_GET_DEBUGMODE:
+ req->ifr_data = (char *)((u32) adapter->debugmode);
+ break;
+
+ case WLAN_GET_MULTIPLE_DTIM:
+ pdata = (int *)wrq->u.name;
+ *pdata = (int)adapter->multipledtim;
+ break;
+ case WLAN_GET_TX_RATE:
+ ret = wlan_get_txrate_ioctl(priv, req);
+ break;
+ case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */
+ ret = wlan_fwt_cleanup_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_FWT_TIME: /* fwt_time */
+ ret = wlan_fwt_time_ioctl(priv, req);
+ break;
+
+ case WLAN_SUBCMD_MESH_GET_TTL:
+ ret = wlan_mesh_get_ttl_ioctl(priv, req);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+
+ }
+
+ break;
+
+ case WLANGETLOG:
+ ret = wlan_do_getlog_ioctl(priv, wrq);
+ break;
+
+ case WLAN_SET_GET_SIXTEEN_INT:
+ switch ((int)wrq->u.data.flags) {
+ case WLAN_TPCCFG:
+ {
+ int data[5];
+ struct cmd_ds_802_11_tpc_cfg cfg;
+ memset(&cfg, 0, sizeof(cfg));
+ if ((wrq->u.data.length > 1)
+ && (wrq->u.data.length != 5))
+ return -1;
+
+ if (wrq->u.data.length == 0) {
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_get);
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * 5)) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_set);
+ cfg.enable = data[0];
+ cfg.usesnr = data[1];
+ cfg.P0 = data[2];
+ cfg.P1 = data[3];
+ cfg.P2 = data[4];
+ }
+
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_tpc_cfg,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&cfg);
+
+ data[0] = cfg.enable;
+ data[1] = cfg.usesnr;
+ data[2] = cfg.P0;
+ data[3] = cfg.P1;
+ data[4] = cfg.P2;
+ if (copy_to_user
+ (wrq->u.data.pointer, data,
+ sizeof(int) * 5)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = 5;
+ }
+ break;
+
+ case WLAN_POWERCFG:
+ {
+ int data[4];
+ struct cmd_ds_802_11_pwr_cfg cfg;
+ memset(&cfg, 0, sizeof(cfg));
+ if ((wrq->u.data.length > 1)
+ && (wrq->u.data.length != 4))
+ return -1;
+ if (wrq->u.data.length == 0) {
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_get);
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * 4)) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ cfg.action =
+ cpu_to_le16
+ (cmd_act_set);
+ cfg.enable = data[0];
+ cfg.PA_P0 = data[1];
+ cfg.PA_P1 = data[2];
+ cfg.PA_P2 = data[3];
+ }
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_pwr_cfg,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&cfg);
+ data[0] = cfg.enable;
+ data[1] = cfg.PA_P0;
+ data[2] = cfg.PA_P1;
+ data[3] = cfg.PA_P2;
+ if (copy_to_user
+ (wrq->u.data.pointer, data,
+ sizeof(int) * 4)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = 4;
+ }
+ break;
+ case WLAN_AUTO_FREQ_SET:
+ {
+ int data[3];
+ struct cmd_ds_802_11_afc afc;
+ memset(&afc, 0, sizeof(afc));
+ if (wrq->u.data.length != 3)
+ return -1;
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) * 3)) {
+ lbs_pr_debug(1, "Copy from user failed\n");
+ return -EFAULT;
+ }
+ afc.afc_auto = data[0];
+
+ if (afc.afc_auto != 0) {
+ afc.threshold = data[1];
+ afc.period = data[2];
+ } else {
+ afc.timing_offset = data[1];
+ afc.carrier_offset = data[2];
+ }
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_afc,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&afc);
+ }
+ break;
+ case WLAN_AUTO_FREQ_GET:
+ {
+ int data[3];
+ struct cmd_ds_802_11_afc afc;
+ memset(&afc, 0, sizeof(afc));
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_get_afc,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&afc);
+ data[0] = afc.afc_auto;
+ data[1] = afc.timing_offset;
+ data[2] = afc.carrier_offset;
+ if (copy_to_user
+ (wrq->u.data.pointer, data,
+ sizeof(int) * 3)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = 3;
+ }
+ break;
+ case WLAN_SCANPROBES:
+ {
+ int data;
+ if (wrq->u.data.length > 0) {
+ if (copy_from_user
+ (&data, wrq->u.data.pointer,
+ sizeof(int))) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ adapter->scanprobes = data;
+ } else {
+ data = adapter->scanprobes;
+ if (copy_to_user
+ (wrq->u.data.pointer, &data,
+ sizeof(int))) {
+ lbs_pr_debug(1,
+ "Copy to user failed\n");
+ return -EFAULT;
+ }
+ }
+ wrq->u.data.length = 1;
+ }
+ break;
+ case WLAN_LED_GPIO_CTRL:
+ {
+ int i;
+ int data[16];
+
+ struct cmd_ds_802_11_led_ctrl ctrl;
+ struct mrvlietypes_ledgpio *gpio =
+ (struct mrvlietypes_ledgpio *) ctrl.data;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ if (wrq->u.data.length > MAX_LEDS * 2)
+ return -ENOTSUPP;
+ if ((wrq->u.data.length % 2) != 0)
+ return -ENOTSUPP;
+ if (wrq->u.data.length == 0) {
+ ctrl.action =
+ cpu_to_le16
+ (cmd_act_get);
+ } else {
+ if (copy_from_user
+ (data, wrq->u.data.pointer,
+ sizeof(int) *
+ wrq->u.data.length)) {
+ lbs_pr_debug(1,
+ "Copy from user failed\n");
+ return -EFAULT;
+ }
+
+ ctrl.action =
+ cpu_to_le16
+ (cmd_act_set);
+ ctrl.numled = cpu_to_le16(0);
+ gpio->header.type =
+ cpu_to_le16(TLV_TYPE_LED_GPIO);
+ gpio->header.len = wrq->u.data.length;
+ for (i = 0; i < wrq->u.data.length;
+ i += 2) {
+ gpio->ledpin[i / 2].led =
+ data[i];
+ gpio->ledpin[i / 2].pin =
+ data[i + 1];
+ }
+ }
+ ret =
+ libertas_prepare_and_send_command(priv,
+ cmd_802_11_led_gpio_ctrl,
+ 0,
+ cmd_option_waitforrsp,
+ 0, (void *)&ctrl);
+ for (i = 0; i < gpio->header.len; i += 2) {
+ data[i] = gpio->ledpin[i / 2].led;
+ data[i + 1] = gpio->ledpin[i / 2].pin;
+ }
+ if (copy_to_user(wrq->u.data.pointer, data,
+ sizeof(int) *
+ gpio->header.len)) {
+ lbs_pr_debug(1, "Copy to user failed\n");
+ return -EFAULT;
+ }
+
+ wrq->u.data.length = gpio->header.len;
+ }
+ break;
+ case WLAN_ADAPT_RATESET:
+ ret = wlan_adapt_rateset(priv, wrq);
+ break;
+ case WLAN_INACTIVITY_TIMEOUT:
+ ret = wlan_inactivity_timeout(priv, wrq);
+ break;
+ case WLANSNR:
+ ret = wlan_get_snr(priv, wrq);
+ break;
+ case WLAN_GET_RXINFO:
+ ret = wlan_get_rxinfo(priv, wrq);
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ LEAVE();
+ return ret;
+}
+
+
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
new file mode 100644
index 00000000000..11682cbe752
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.c
@@ -0,0 +1,1055 @@
+/**
+ * Functions implementing wlan infrastructure and adhoc join routines,
+ * IOCTL handlers as well as command preperation and response routines
+ * for sending adhoc start, adhoc join, and association commands
+ * to the firmware.
+ */
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "join.h"
+#include "dev.h"
+
+/**
+ * @brief This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates need to be taken
+ * care, either before or after calling this function
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param rate1 the buffer which keeps input and output
+ * @param rate1_size the size of rate1 buffer
+ * @param rate2 the buffer which keeps rate2
+ * @param rate2_size the size of rate2 buffer.
+ *
+ * @return 0 or -1
+ */
+static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
+ int rate1_size, u8 * rate2, int rate2_size)
+{
+ u8 *ptr = rate1;
+ int ret = 0;
+ u8 tmp[30];
+ int i;
+
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
+ memset(rate1, 0, rate1_size);
+
+ /* Mask the top bit of the original values */
+ for (i = 0; tmp[i] && i < sizeof(tmp); i++)
+ tmp[i] &= 0x7F;
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ /* Check for Card Rate in tmp, excluding the top bit */
+ if (strchr(tmp, rate2[i] & 0x7F)) {
+ /* values match, so copy the Card Rate to rate1 */
+ *rate1++ = rate2[i];
+ }
+ }
+
+ lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
+ lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
+ lbs_dbg_hex("Common rates:", ptr, rate1_size);
+ lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate);
+
+ if (!adapter->is_datarate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == adapter->datarate) {
+ ret = 0;
+ goto done;
+ }
+ ptr++;
+ }
+ lbs_pr_alert( "Previously set fixed data rate %#x isn't "
+ "compatible with the network.\n", adapter->datarate);
+
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+done:
+ return ret;
+}
+
+int libertas_send_deauth(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ if (adapter->inframode == wlan802_11infrastructure &&
+ adapter->connect_status == libertas_connected)
+ ret = libertas_send_deauthentication(priv);
+ else
+ ret = -ENOTSUPP;
+
+ return ret;
+}
+
+int libertas_do_adhocstop_ioctl(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ if (adapter->inframode == wlan802_11ibss &&
+ adapter->connect_status == libertas_connected)
+ ret = libertas_stop_adhoc_network(priv);
+ else
+ ret = -ENOTSUPP;
+
+ return ret;
+}
+
+/**
+ * @brief Associate to a specific BSS discovered in a scan
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param pbssdesc Pointer to the BSS descriptor to associate with.
+ *
+ * @return 0-success, otherwise fail
+ */
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret;
+
+ ENTER();
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
+ 0, cmd_option_waitforrsp,
+ 0, pbssdesc->macaddress);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ /* set preamble to firmware */
+ if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble)
+ adapter->preamble = cmd_type_short_preamble;
+ else
+ adapter->preamble = cmd_type_long_preamble;
+
+ libertas_set_radio_control(priv);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
+ 0, cmd_option_waitforrsp, 0, pbssdesc);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Start an Adhoc Network
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param adhocssid The ssid of the Adhoc Network
+ * @return 0--success, -1--fail
+ */
+int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ adapter->adhoccreate = 1;
+
+ if (!adapter->capinfo.shortpreamble) {
+ lbs_pr_debug(1, "AdhocStart: Long preamble\n");
+ adapter->preamble = cmd_type_long_preamble;
+ } else {
+ lbs_pr_debug(1, "AdhocStart: Short preamble\n");
+ adapter->preamble = cmd_type_short_preamble;
+ }
+
+ libertas_set_radio_control(priv);
+
+ lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel);
+ lbs_pr_debug(1, "curbssparams.channel = %d\n",
+ adapter->curbssparams.channel);
+ lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
+ 0, cmd_option_waitforrsp, 0, adhocssid);
+
+ return ret;
+}
+
+/**
+ * @brief Join an adhoc network found in a previous scan
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param pbssdesc Pointer to a BSS descriptor found in a previous scan
+ * to attempt to join
+ *
+ * @return 0--success, -1--fail
+ */
+int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n",
+ adapter->curbssparams.ssid.ssid);
+ lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n",
+ adapter->curbssparams.ssid.ssidlength);
+ lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid);
+ lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n",
+ pbssdesc->ssid.ssidlength);
+
+ /* check if the requested SSID is already joined */
+ if (adapter->curbssparams.ssid.ssidlength
+ && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid)
+ && (adapter->curbssparams.bssdescriptor.inframode ==
+ wlan802_11ibss)) {
+
+ lbs_pr_debug(1,
+ "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
+ "not attempting to re-join");
+
+ return -1;
+ }
+
+ /*Use shortpreamble only when both creator and card supports
+ short preamble */
+ if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+ lbs_pr_debug(1, "AdhocJoin: Long preamble\n");
+ adapter->preamble = cmd_type_long_preamble;
+ } else {
+ lbs_pr_debug(1, "AdhocJoin: Short preamble\n");
+ adapter->preamble = cmd_type_short_preamble;
+ }
+
+ libertas_set_radio_control(priv);
+
+ lbs_pr_debug(1, "curbssparams.channel = %d\n",
+ adapter->curbssparams.channel);
+ lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band);
+
+ adapter->adhoccreate = 0;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
+ 0, cmd_option_waitforrsp,
+ OID_802_11_SSID, pbssdesc);
+
+ return ret;
+}
+
+int libertas_stop_adhoc_network(wlan_private * priv)
+{
+ return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
+ 0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ * @brief Send Deauthentication Request
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0--success, -1--fail
+ */
+int libertas_send_deauthentication(wlan_private * priv)
+{
+ return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
+ 0, cmd_option_waitforrsp, 0, NULL);
+}
+
+/**
+ * @brief Set Idle Off
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+int libertas_idle_off(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 };
+ int i;
+
+ ENTER();
+
+ if (adapter->connect_status == libertas_disconnected) {
+ if (adapter->inframode == wlan802_11infrastructure) {
+ if (memcmp(adapter->previousbssid, zeromac,
+ sizeof(zeromac)) != 0) {
+
+ lbs_pr_debug(1, "Previous SSID = %s\n",
+ adapter->previousssid.ssid);
+ lbs_pr_debug(1, "Previous BSSID = "
+ "%02x:%02x:%02x:%02x:%02x:%02x:\n",
+ adapter->previousbssid[0],
+ adapter->previousbssid[1],
+ adapter->previousbssid[2],
+ adapter->previousbssid[3],
+ adapter->previousbssid[4],
+ adapter->previousbssid[5]);
+
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->previousssid,
+ adapter->previousbssid,
+ adapter->inframode);
+
+ if (i < 0) {
+ libertas_send_specific_BSSID_scan(priv,
+ adapter->
+ previousbssid,
+ 1);
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->
+ previousssid,
+ adapter->
+ previousbssid,
+ adapter->
+ inframode);
+ }
+
+ if (i < 0) {
+ /* If the BSSID could not be found, try just the SSID */
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->
+ previousssid, NULL,
+ adapter->
+ inframode);
+ }
+
+ if (i < 0) {
+ libertas_send_specific_SSID_scan(priv,
+ &adapter->
+ previousssid,
+ 1);
+ i = libertas_find_SSID_in_list(adapter,
+ &adapter->
+ previousssid, NULL,
+ adapter->
+ inframode);
+ }
+
+ if (i >= 0) {
+ ret =
+ wlan_associate(priv,
+ &adapter->
+ scantable[i]);
+ }
+ }
+ } else if (adapter->inframode == wlan802_11ibss) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_ad_hoc_start,
+ 0,
+ cmd_option_waitforrsp,
+ 0, &adapter->previousssid);
+ }
+ }
+ /* else it is connected */
+
+ lbs_pr_debug(1, "\nwlanidle is off");
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Idle On
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return 0 --success, otherwise fail
+ */
+int libertas_idle_on(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ if (adapter->connect_status == libertas_connected) {
+ if (adapter->inframode == wlan802_11infrastructure) {
+ lbs_pr_debug(1, "Previous SSID = %s\n",
+ adapter->previousssid.ssid);
+ memmove(&adapter->previousssid,
+ &adapter->curbssparams.ssid,
+ sizeof(struct WLAN_802_11_SSID));
+ libertas_send_deauth(priv);
+
+ } else if (adapter->inframode == wlan802_11ibss) {
+ ret = libertas_stop_adhoc_network(priv);
+ }
+
+ }
+
+ lbs_pr_debug(1, "\nwlanidle is on");
+
+ return ret;
+}
+
+/**
+ * @brief This function prepares command of authenticate.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param cmd A pointer to cmd_ds_command structure
+ * @param pdata_buf Void cast of pointer to a BSSID to authenticate with
+ *
+ * @return 0 or -1
+ */
+int libertas_cmd_80211_authenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_authenticate *pauthenticate =
+ &cmd->params.auth;
+ u8 *bssid = pdata_buf;
+
+ cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
+ + S_DS_GEN);
+
+ pauthenticate->authtype = adapter->secinfo.authmode;
+ memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
+
+ lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+
+ return 0;
+}
+
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth;
+
+ ENTER();
+
+ cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
+ S_DS_GEN);
+
+ /* set AP MAC address */
+ memmove(dauth->macaddr, adapter->curbssparams.bssid,
+ ETH_ALEN);
+
+ /* Reason code 3 = Station is leaving */
+#define REASON_CODE_STA_LEAVING 3
+ dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING);
+
+ LEAVE();
+ return 0;
+}
+
+int libertas_cmd_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_associate *passo = &cmd->params.associate;
+ int ret = 0;
+ struct bss_descriptor *pbssdesc;
+ u8 *card_rates;
+ u8 *pos;
+ int card_rates_size;
+ u16 tmpcap;
+ struct mrvlietypes_ssidparamset *ssid;
+ struct mrvlietypes_phyparamset *phy;
+ struct mrvlietypes_ssparamset *ss;
+ struct mrvlietypes_ratesparamset *rates;
+ struct mrvlietypes_rsnparamset *rsn;
+
+ ENTER();
+
+ pbssdesc = pdata_buf;
+ pos = (u8 *) passo;
+
+ if (!adapter) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->command = cpu_to_le16(cmd_802_11_associate);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ adapter->pattemptedbssdesc = pbssdesc;
+
+ memcpy(passo->peerstaaddr,
+ pbssdesc->macaddress, sizeof(passo->peerstaaddr));
+ pos += sizeof(passo->peerstaaddr);
+
+ /* set the listen interval */
+ passo->listeninterval = adapter->listeninterval;
+
+ pos += sizeof(passo->capinfo);
+ pos += sizeof(passo->listeninterval);
+ pos += sizeof(passo->bcnperiod);
+ pos += sizeof(passo->dtimperiod);
+
+ ssid = (struct mrvlietypes_ssidparamset *) pos;
+ ssid->header.type = cpu_to_le16(TLV_TYPE_SSID);
+ ssid->header.len = pbssdesc->ssid.ssidlength;
+ memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len);
+ pos += sizeof(ssid->header) + ssid->header.len;
+ ssid->header.len = cpu_to_le16(ssid->header.len);
+
+ phy = (struct mrvlietypes_phyparamset *) pos;
+ phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS);
+ phy->header.len = sizeof(phy->fh_ds.dsparamset);
+ memcpy(&phy->fh_ds.dsparamset,
+ &pbssdesc->phyparamset.dsparamset.currentchan,
+ sizeof(phy->fh_ds.dsparamset));
+ pos += sizeof(phy->header) + phy->header.len;
+ phy->header.len = cpu_to_le16(phy->header.len);
+
+ ss = (struct mrvlietypes_ssparamset *) pos;
+ ss->header.type = cpu_to_le16(TLV_TYPE_CF);
+ ss->header.len = sizeof(ss->cf_ibss.cfparamset);
+ pos += sizeof(ss->header) + ss->header.len;
+ ss->header.len = cpu_to_le16(ss->header.len);
+
+ rates = (struct mrvlietypes_ratesparamset *) pos;
+ rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
+
+ memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES);
+
+ card_rates = libertas_supported_rates;
+ card_rates_size = sizeof(libertas_supported_rates);
+
+ if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ ret = -1;
+ goto done;
+ }
+
+ rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
+ adapter->curbssparams.numofrates = rates->header.len;
+
+ pos += sizeof(rates->header) + rates->header.len;
+ rates->header.len = cpu_to_le16(rates->header.len);
+
+ if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+ rsn = (struct mrvlietypes_rsnparamset *) pos;
+ rsn->header.type = (u16) adapter->wpa_ie[0]; /* WPA_IE or WPA2_IE */
+ rsn->header.type = cpu_to_le16(rsn->header.type);
+ rsn->header.len = (u16) adapter->wpa_ie[1];
+ memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len);
+ lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+ sizeof(rsn->header) + rsn->header.len);
+ pos += sizeof(rsn->header) + rsn->header.len;
+ rsn->header.len = cpu_to_le16(rsn->header.len);
+ }
+
+ /* update curbssparams */
+ adapter->curbssparams.channel =
+ (pbssdesc->phyparamset.dsparamset.currentchan);
+
+ /* Copy the infra. association rates into Current BSS state structure */
+ memcpy(&adapter->curbssparams.datarates, &rates->rates,
+ min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len));
+
+ lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len);
+
+ /* set IBSS field */
+ if (pbssdesc->inframode == wlan802_11infrastructure) {
+#define CAPINFO_ESS_MODE 1
+ passo->capinfo.ess = CAPINFO_ESS_MODE;
+ }
+
+ if (libertas_parse_dnld_countryinfo_11d(priv)) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
+
+ /* set the capability info at last */
+ memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo));
+ tmpcap &= CAPINFO_MASK;
+ lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+ tmpcap, CAPINFO_MASK);
+ tmpcap = cpu_to_le16(tmpcap);
+ memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pssid)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
+ int ret = 0;
+ int cmdappendsize = 0;
+ int i;
+ u16 tmpcap;
+ struct bss_descriptor *pbssdesc;
+ struct WLAN_802_11_SSID *ssid = pssid;
+
+ ENTER();
+
+ if (!adapter) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+
+ pbssdesc = &adapter->curbssparams.bssdescriptor;
+ adapter->pattemptedbssdesc = pbssdesc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. cmd_ds_802_11_ad_hoc_start command
+ * 2. adapter->scantable[i]
+ *
+ * Driver will fill up SSID, bsstype,IBSS param, Physical Param,
+ * probe delay, and cap info.
+ *
+ * Firmware will fill up beacon period, DTIM, Basic rates
+ * and operational rates.
+ */
+
+ memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
+
+ memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID);
+
+ memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE);
+ memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength);
+
+ pbssdesc->ssid.ssidlength = ssid->ssidlength;
+
+ /* set the BSS type */
+ adhs->bsstype = cmd_bss_type_ibss;
+ pbssdesc->inframode = wlan802_11ibss;
+ adhs->beaconperiod = adapter->beaconperiod;
+
+ /* set Physical param set */
+#define DS_PARA_IE_ID 3
+#define DS_PARA_IE_LEN 1
+
+ adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID;
+ adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN;
+
+ WARN_ON(!adapter->adhocchannel);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n",
+ adapter->adhocchannel);
+
+ adapter->curbssparams.channel = adapter->adhocchannel;
+
+ pbssdesc->channel = adapter->adhocchannel;
+ adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel;
+
+ memcpy(&pbssdesc->phyparamset,
+ &adhs->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+ /* set IBSS param set */
+#define IBSS_PARA_IE_ID 6
+#define IBSS_PARA_IE_LEN 2
+
+ adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
+ adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
+ adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow;
+ memcpy(&pbssdesc->ssparamset,
+ &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+ /* set capability info */
+ adhs->cap.ess = 0;
+ adhs->cap.ibss = 1;
+ pbssdesc->cap.ibss = 1;
+
+ /* probedelay */
+ adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
+
+ /* set up privacy in adapter->scantable[i] */
+ if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+
+#define AD_HOC_CAP_PRIVACY_ON 1
+ lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n");
+ pbssdesc->privacy = wlan802_11privfilter8021xWEP;
+ adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ } else {
+ lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting "
+ "privacy to ACCEPT ALL\n");
+ pbssdesc->privacy = wlan802_11privfilteracceptall;
+ }
+
+ memset(adhs->datarate, 0, sizeof(adhs->datarate));
+
+ if (adapter->adhoc_grate_enabled) {
+ memcpy(adhs->datarate, libertas_adhoc_rates_g,
+ min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
+ } else {
+ memcpy(adhs->datarate, libertas_adhoc_rates_b,
+ min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
+ }
+
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
+
+ adapter->curbssparams.numofrates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS state structure */
+ memcpy(&adapter->curbssparams.datarates,
+ &adhs->datarate, adapter->curbssparams.numofrates);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
+ adhs->datarate[0], adhs->datarate[1],
+ adhs->datarate[2], adhs->datarate[3]);
+
+ lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n");
+
+ if (libertas_create_dnld_countryinfo_11d(priv)) {
+ lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n");
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start)
+ + S_DS_GEN + cmdappendsize);
+
+ memcpy(&tmpcap, &adhs->cap, sizeof(u16));
+ tmpcap = cpu_to_le16(tmpcap);
+ memcpy(&adhs->cap, &tmpcap, sizeof(u16));
+
+ ret = 0;
+done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+
+ return 0;
+}
+
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+ struct bss_descriptor *pbssdesc = pdata_buf;
+ int cmdappendsize = 0;
+ int ret = 0;
+ u8 *card_rates;
+ int card_rates_size;
+ u16 tmpcap;
+ int i;
+
+ ENTER();
+
+ adapter->pattemptedbssdesc = pbssdesc;
+
+ cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+
+ padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+
+ padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod;
+
+ memcpy(&padhocjoin->bssdescriptor.BSSID,
+ &pbssdesc->macaddress, ETH_ALEN);
+
+ memcpy(&padhocjoin->bssdescriptor.SSID,
+ &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength);
+
+ memcpy(&padhocjoin->bssdescriptor.phyparamset,
+ &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset));
+
+ memcpy(&padhocjoin->bssdescriptor.ssparamset,
+ &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset));
+
+ memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo));
+ tmpcap &= CAPINFO_MASK;
+
+ lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+ tmpcap, CAPINFO_MASK);
+ memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
+ sizeof(struct ieeetypes_capinfo));
+
+ /* information on BSSID descriptor passed to FW */
+ lbs_pr_debug(1,
+ "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n",
+ padhocjoin->bssdescriptor.BSSID[0],
+ padhocjoin->bssdescriptor.BSSID[1],
+ padhocjoin->bssdescriptor.BSSID[2],
+ padhocjoin->bssdescriptor.BSSID[3],
+ padhocjoin->bssdescriptor.BSSID[4],
+ padhocjoin->bssdescriptor.BSSID[5],
+ padhocjoin->bssdescriptor.SSID);
+
+ lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n",
+ (u32) padhocjoin->bssdescriptor.datarates);
+
+ /* failtimeout */
+ padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+
+ /* probedelay */
+ padhocjoin->probedelay =
+ cpu_to_le16(cmd_scan_probe_delay_time);
+
+ /* Copy Data rates from the rates recorded in scan response */
+ memset(padhocjoin->bssdescriptor.datarates, 0,
+ sizeof(padhocjoin->bssdescriptor.datarates));
+ memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates,
+ min(sizeof(padhocjoin->bssdescriptor.datarates),
+ sizeof(pbssdesc->datarates)));
+
+ card_rates = libertas_supported_rates;
+ card_rates_size = sizeof(libertas_supported_rates);
+
+ adapter->curbssparams.channel = pbssdesc->channel;
+
+ if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
+ sizeof(padhocjoin->bssdescriptor.datarates),
+ card_rates, card_rates_size)) {
+ lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n");
+ ret = -1;
+ goto done;
+ }
+
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
+ && padhocjoin->bssdescriptor.datarates[i]; i++) ;
+
+ adapter->curbssparams.numofrates = i;
+
+ /*
+ * Copy the adhoc joining rates to Current BSS State structure
+ */
+ memcpy(adapter->curbssparams.datarates,
+ padhocjoin->bssdescriptor.datarates,
+ adapter->curbssparams.numofrates);
+
+ padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+ cpu_to_le16(pbssdesc->atimwindow);
+
+ if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) {
+ padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+ }
+
+ if (adapter->psmode == wlan802_11powermodemax_psp) {
+ /* wake up first */
+ enum WLAN_802_11_POWER_MODE Localpsmode;
+
+ Localpsmode = wlan802_11powermodecam;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_ps_mode,
+ cmd_act_set,
+ 0, 0, &Localpsmode);
+
+ if (ret) {
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (libertas_parse_dnld_countryinfo_11d(priv)) {
+ ret = -1;
+ goto done;
+ }
+
+ cmd->size =
+ cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join)
+ + S_DS_GEN + cmdappendsize);
+
+ memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap,
+ sizeof(struct ieeetypes_capinfo));
+ tmpcap = cpu_to_le16(tmpcap);
+
+ memcpy(&padhocjoin->bssdescriptor.cap,
+ &tmpcap, sizeof(struct ieeetypes_capinfo));
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_ret_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ union iwreq_data wrqu;
+ struct ieeetypes_assocrsp *passocrsp;
+ struct bss_descriptor *pbssdesc;
+
+ ENTER();
+
+ passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
+
+ if (passocrsp->statuscode) {
+
+ libertas_mac_event_disconnected(priv);
+
+ lbs_pr_debug(1,
+ "ASSOC_RESP: Association failed, status code = %d\n",
+ passocrsp->statuscode);
+
+ ret = -1;
+ goto done;
+ }
+
+ lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+ le16_to_cpu(resp->size) - S_DS_GEN);
+
+ /* Send a Media Connected event, according to the Spec */
+ adapter->connect_status = libertas_connected;
+
+ /* Set the attempted BSSID Index to current */
+ pbssdesc = adapter->pattemptedbssdesc;
+
+ lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid);
+
+ /* Set the new SSID to current SSID */
+ memcpy(&adapter->curbssparams.ssid,
+ &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+ /* Set the new BSSID (AP's MAC address) to current BSSID */
+ memcpy(adapter->curbssparams.bssid,
+ pbssdesc->macaddress, ETH_ALEN);
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&adapter->curbssparams.bssdescriptor,
+ pbssdesc, sizeof(struct bss_descriptor));
+
+ lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n",
+ adapter->currentpacketfilter);
+
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0;
+ adapter->NF[TYPE_RXPD][TYPE_AVG] = 0;
+
+ memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR));
+ memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
+ adapter->nextSNRNF = 0;
+ adapter->numSNRNF = 0;
+
+ netif_carrier_on(priv->wlan_dev.netdev);
+ netif_wake_queue(priv->wlan_dev.netdev);
+
+ lbs_pr_debug(1, "ASSOC_RESP: Associated \n");
+
+ memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+int libertas_ret_80211_disassociate(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ ENTER();
+
+ libertas_mac_event_disconnected(priv);
+
+ LEAVE();
+ return 0;
+}
+
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u16 command = le16_to_cpu(resp->command);
+ u16 result = le16_to_cpu(resp->result);
+ struct cmd_ds_802_11_ad_hoc_result *padhocresult;
+ union iwreq_data wrqu;
+ struct bss_descriptor *pbssdesc;
+
+ ENTER();
+
+ padhocresult = &resp->params.result;
+
+ lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size));
+ lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command);
+ lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result);
+
+ pbssdesc = adapter->pattemptedbssdesc;
+
+ /*
+ * Join result code 0 --> SUCCESS
+ */
+ if (result) {
+ lbs_pr_debug(1, "ADHOC_RESP failed\n");
+ if (adapter->connect_status == libertas_connected) {
+ libertas_mac_event_disconnected(priv);
+ }
+
+ memset(&adapter->curbssparams.bssdescriptor,
+ 0x00, sizeof(adapter->curbssparams.bssdescriptor));
+
+ LEAVE();
+ return -1;
+ }
+
+ /*
+ * Now the join cmd should be successful
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ lbs_pr_debug(1, "ADHOC_J_RESP %s\n", pbssdesc->ssid.ssid);
+
+ /* Send a Media Connected event, according to the Spec */
+ adapter->connect_status = libertas_connected;
+
+ if (command == cmd_ret_802_11_ad_hoc_start) {
+ /* Update the created network descriptor with the new BSSID */
+ memcpy(pbssdesc->macaddress,
+ padhocresult->BSSID, ETH_ALEN);
+ } else {
+
+ /* Make a copy of current BSSID descriptor, only needed for join since
+ * the current descriptor is already being used for adhoc start
+ */
+ memmove(&adapter->curbssparams.bssdescriptor,
+ pbssdesc, sizeof(struct bss_descriptor));
+ }
+
+ /* Set the BSSID from the joined/started descriptor */
+ memcpy(&adapter->curbssparams.bssid,
+ pbssdesc->macaddress, ETH_ALEN);
+
+ /* Set the new SSID to current SSID */
+ memcpy(&adapter->curbssparams.ssid,
+ &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID));
+
+ netif_carrier_on(priv->wlan_dev.netdev);
+ netif_wake_queue(priv->wlan_dev.netdev);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+ lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n");
+ lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel);
+ lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ padhocresult->BSSID[0], padhocresult->BSSID[1],
+ padhocresult->BSSID[2], padhocresult->BSSID[3],
+ padhocresult->BSSID[4], padhocresult->BSSID[5]);
+
+ LEAVE();
+ return ret;
+}
+
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *resp)
+{
+ ENTER();
+
+ libertas_mac_event_disconnected(priv);
+
+ LEAVE();
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
new file mode 100644
index 00000000000..8efa2455af9
--- /dev/null
+++ b/drivers/net/wireless/libertas/join.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+ * Interface for the wlan infrastructure and adhoc join routines
+ *
+ * Driver interface functions and type declarations for the join module
+ * implemented in wlan_join.c. Process all start/join requests for
+ * both adhoc and infrastructure networks
+ */
+#ifndef _WLAN_JOIN_H
+#define _WLAN_JOIN_H
+
+#include "defs.h"
+
+struct cmd_ds_command;
+extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pssid);
+extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+ struct cmd_ds_command *cmd);
+extern int libertas_cmd_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+
+extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+ struct cmd_ds_command *resp);
+extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+ struct cmd_ds_command *resp);
+extern int libertas_ret_80211_disassociate(wlan_private * priv,
+ struct cmd_ds_command *resp);
+extern int libertas_ret_80211_associate(wlan_private * priv,
+ struct cmd_ds_command *resp);
+
+extern int libertas_idle_on(wlan_private * priv);
+extern int libertas_idle_off(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+extern int libertas_reassociation_thread(void *data);
+
+struct WLAN_802_11_SSID;
+struct bss_descriptor;
+
+extern int libertas_start_adhoc_network(wlan_private * priv,
+ struct WLAN_802_11_SSID *adhocssid);
+extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc);
+extern int libertas_stop_adhoc_network(wlan_private * priv);
+
+extern int libertas_send_deauthentication(wlan_private * priv);
+extern int libertas_send_deauth(wlan_private * priv);
+
+extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+
+int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc);
+
+#endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
new file mode 100644
index 00000000000..dcbf102a057
--- /dev/null
+++ b/drivers/net/wireless/libertas/main.c
@@ -0,0 +1,1258 @@
+/**
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/etherdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "sbi.h"
+#include "decl.h"
+#include "dev.h"
+#include "fw.h"
+#include "wext.h"
+#include "debugfs.h"
+#include "assoc.h"
+
+#ifdef ENABLE_PM
+static struct pm_dev *wlan_pm_dev = NULL;
+#endif
+
+#define WLAN_TX_PWR_DEFAULT 20 /*100mW */
+#define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */
+#define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */
+#define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */
+#define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */
+
+/* Format { channel, frequency (MHz), maxtxpower } */
+/* band: 'B/G', region: USA FCC/Canada IC */
+static struct chan_freq_power channel_freq_power_US_BG[] = {
+ {1, 2412, WLAN_TX_PWR_US_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_US_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_US_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_US_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_US_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_US_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_US_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_US_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_US_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_US_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_US_DEFAULT}
+};
+
+/* band: 'B/G', region: Europe ETSI */
+static struct chan_freq_power channel_freq_power_EU_BG[] = {
+ {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT}
+};
+
+/* band: 'B/G', region: Spain */
+static struct chan_freq_power channel_freq_power_SPN_BG[] = {
+ {10, 2457, WLAN_TX_PWR_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_DEFAULT}
+};
+
+/* band: 'B/G', region: France */
+static struct chan_freq_power channel_freq_power_FR_BG[] = {
+ {10, 2457, WLAN_TX_PWR_FR_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_FR_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_FR_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_FR_DEFAULT}
+};
+
+/* band: 'B/G', region: Japan */
+static struct chan_freq_power channel_freq_power_JPN_BG[] = {
+ {1, 2412, WLAN_TX_PWR_JP_DEFAULT},
+ {2, 2417, WLAN_TX_PWR_JP_DEFAULT},
+ {3, 2422, WLAN_TX_PWR_JP_DEFAULT},
+ {4, 2427, WLAN_TX_PWR_JP_DEFAULT},
+ {5, 2432, WLAN_TX_PWR_JP_DEFAULT},
+ {6, 2437, WLAN_TX_PWR_JP_DEFAULT},
+ {7, 2442, WLAN_TX_PWR_JP_DEFAULT},
+ {8, 2447, WLAN_TX_PWR_JP_DEFAULT},
+ {9, 2452, WLAN_TX_PWR_JP_DEFAULT},
+ {10, 2457, WLAN_TX_PWR_JP_DEFAULT},
+ {11, 2462, WLAN_TX_PWR_JP_DEFAULT},
+ {12, 2467, WLAN_TX_PWR_JP_DEFAULT},
+ {13, 2472, WLAN_TX_PWR_JP_DEFAULT},
+ {14, 2484, WLAN_TX_PWR_JP_DEFAULT}
+};
+
+/**
+ * the structure for channel, frequency and power
+ */
+struct region_cfp_table {
+ u8 region;
+ struct chan_freq_power *cfp_BG;
+ int cfp_no_BG;
+};
+
+/**
+ * the structure for the mapping between region and CFP
+ */
+static struct region_cfp_table region_cfp_table[] = {
+ {0x10, /*US FCC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x20, /*CANADA IC */
+ channel_freq_power_US_BG,
+ sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x30, /*EU*/ channel_freq_power_EU_BG,
+ sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
+ sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x32, /*FRANCE*/ channel_freq_power_FR_BG,
+ sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+ {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
+ sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+ }
+ ,
+/*Add new region here */
+};
+
+/**
+ * the rates supported by the card
+ */
+u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
+ { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+ 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ * the rates supported
+ */
+u8 libertas_supported_rates[G_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc G mode
+ */
+u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
+ { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0 };
+
+/**
+ * the rates supported for ad-hoc B mode
+ */
+u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
+
+/**
+ * the global variable of a pointer to wlan_private
+ * structure variable
+ */
+static wlan_private *wlanpriv = NULL;
+
+#define MAX_DEVS 5
+static struct net_device *libertas_devs[MAX_DEVS];
+static int libertas_found = 0;
+
+/**
+ * the table to keep region code
+ */
+u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
+ { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
+
+static u8 *default_fw_name = "usb8388.bin";
+
+/**
+ * Attributes exported through sysfs
+ */
+
+/**
+ * @brief Get function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_get(struct device * dev,
+ struct device_attribute *attr, char * buf) {
+ struct cmd_ds_mesh_access mesh_access;
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+ cmd_mesh_access,
+ cmd_act_mesh_get_mpp,
+ cmd_option_waitforrsp, 0, (void *)&mesh_access);
+
+ return snprintf(buf, 3, "%d\n", mesh_access.data[0]);
+}
+
+/**
+ * @brief Set function for sysfs attribute libertas_mpp
+ */
+static ssize_t libertas_mpp_set(struct device * dev,
+ struct device_attribute *attr, const char * buf, size_t count) {
+ struct cmd_ds_mesh_access mesh_access;
+
+
+ memset(&mesh_access, 0, sizeof(mesh_access));
+ sscanf(buf, "%d", &(mesh_access.data[0]));
+ libertas_prepare_and_send_command((to_net_dev(dev))->priv,
+ cmd_mesh_access,
+ cmd_act_mesh_set_mpp,
+ cmd_option_waitforrsp, 0, (void *)&mesh_access);
+ return strlen(buf);
+}
+
+/**
+ * libertas_mpp attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-mpp)
+ */
+static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get,
+ libertas_mpp_set );
+
+/**
+ * @brief Check if the device can be open and wait if necessary.
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ *
+ * For USB adapter, on some systems the device open handler will be
+ * called before FW ready. Use the following flag check and wait
+ * function to work around the issue.
+ *
+ */
+static int pre_open_check(struct net_device *dev) {
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int i = 0;
+
+ while (!adapter->fw_ready && i < 20) {
+ i++;
+ msleep_interruptible(100);
+ }
+ if (!adapter->fw_ready) {
+ lbs_pr_info("FW not ready, pre_open_check() return failure\n");
+ LEAVE();
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief This function opens the device
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int wlan_dev_open(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+
+ priv->open = 1;
+
+ if (adapter->connect_status == libertas_connected) {
+ netif_carrier_on(priv->wlan_dev.netdev);
+ } else
+ netif_carrier_off(priv->wlan_dev.netdev);
+
+ LEAVE();
+ return 0;
+}
+/**
+ * @brief This function opens the mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int mesh_open(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv ;
+
+ if(pre_open_check(dev) == -1)
+ return -1;
+ priv->mesh_open = 1 ;
+ netif_start_queue(priv->mesh_dev);
+ if (priv->infra_open == 0)
+ return wlan_dev_open(priv->wlan_dev.netdev) ;
+ return 0;
+}
+
+/**
+ * @brief This function opens the ethX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int wlan_open(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv ;
+
+ if(pre_open_check(dev) == -1)
+ return -1;
+ priv->infra_open = 1 ;
+ netif_wake_queue(priv->wlan_dev.netdev);
+ if (priv->open == 0)
+ return wlan_dev_open(priv->wlan_dev.netdev) ;
+ return 0;
+}
+
+static int wlan_dev_close(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ netif_carrier_off(priv->wlan_dev.netdev);
+ priv->open = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function closes the mshX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int mesh_close(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) (dev->priv);
+
+ priv->mesh_open = 0;
+ netif_stop_queue(priv->mesh_dev);
+ if (priv->infra_open == 0)
+ return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+ else
+ return 0;
+}
+
+/**
+ * @brief This function closes the ethX interface
+ *
+ * @param dev A pointer to net_device structure
+ * @return 0
+ */
+static int wlan_close(struct net_device *dev) {
+ wlan_private *priv = (wlan_private *) dev->priv;
+
+ netif_stop_queue(priv->wlan_dev.netdev);
+ priv->infra_open = 0;
+ if (priv->mesh_open == 0)
+ return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ;
+ else
+ return 0;
+}
+
+
+#ifdef ENABLE_PM
+
+/**
+ * @brief This function is a callback function. it is called by
+ * kernel to enter or exit power saving mode.
+ *
+ * @param pmdev A pointer to pm_dev
+ * @param pmreq pm_request_t
+ * @param pmdata A pointer to pmdata
+ * @return 0 or -1
+ */
+static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq,
+ void *pmdata)
+{
+ wlan_private *priv = wlanpriv;
+ wlan_adapter *adapter = priv->adapter;
+ struct net_device *dev = priv->wlan_dev.netdev;
+
+ lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq);
+
+ switch (pmreq) {
+ case PM_SUSPEND:
+ lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n");
+
+ /* in associated mode */
+ if (adapter->connect_status == libertas_connected) {
+ if ((adapter->psstate != PS_STATE_SLEEP)
+ ) {
+ lbs_pr_debug(1,
+ "wlan_pm_callback: can't enter sleep mode\n");
+ return -1;
+ } else {
+
+ /*
+ * Detach the network interface
+ * if the network is running
+ */
+ if (netif_running(dev)) {
+ netif_device_detach(dev);
+ lbs_pr_debug(1,
+ "netif_device_detach().\n");
+ }
+ libertas_sbi_suspend(priv);
+ }
+ break;
+ }
+
+ /* in non associated mode */
+
+ /*
+ * Detach the network interface
+ * if the network is running
+ */
+ if (netif_running(dev))
+ netif_device_detach(dev);
+
+ /*
+ * Storing and restoring of the regs be taken care
+ * at the driver rest will be done at wlan driver
+ * this makes driver independent of the card
+ */
+
+ libertas_sbi_suspend(priv);
+
+ break;
+
+ case PM_RESUME:
+ /* in associated mode */
+ if (adapter->connect_status == libertas_connected) {
+ {
+ /*
+ * Bring the inteface up first
+ * This case should not happen still ...
+ */
+ libertas_sbi_resume(priv);
+
+ /*
+ * Attach the network interface
+ * if the network is running
+ */
+ if (netif_running(dev)) {
+ netif_device_attach(dev);
+ lbs_pr_debug(1,
+ "after netif_device_attach().\n");
+ }
+ lbs_pr_debug(1,
+ "After netif attach, in associated mode.\n");
+ }
+ break;
+ }
+
+ /* in non associated mode */
+
+ /*
+ * Bring the inteface up first
+ * This case should not happen still ...
+ */
+
+ libertas_sbi_resume(priv);
+
+ if (netif_running(dev))
+ netif_device_attach(dev);
+
+ lbs_pr_debug(1, "after netif attach, in NON associated mode.\n");
+ break;
+ }
+
+ return 0;
+}
+#endif /* ENABLE_PM */
+
+static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) {
+ priv->stats.tx_dropped++;
+ goto done;
+ }
+
+ netif_stop_queue(priv->wlan_dev.netdev);
+
+ if (libertas_process_tx(priv, skb) == 0)
+ dev->trans_start = jiffies;
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+ ENTER();
+ SET_MESH_FRAME(skb);
+ LEAVE();
+
+ return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev);
+}
+
+/**
+ * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ *
+ */
+static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+ ENTER();
+ UNSET_MESH_FRAME(skb);
+ LEAVE();
+ return wlan_hard_start_xmit(skb, dev);
+}
+
+static void wlan_tx_timeout(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+
+ ENTER();
+
+ lbs_pr_err("tx watch dog timeout!\n");
+
+ priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED;
+ dev->trans_start = jiffies;
+
+ if (priv->adapter->currenttxskb) {
+ if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ /* If we are here, we have not received feedback from
+ the previous packet. Assume TX_FAIL and move on. */
+ priv->adapter->eventcause = 0x01000000;
+ libertas_send_tx_feedback(priv);
+ } else
+ wake_up_interruptible(&priv->mainthread.waitq);
+ } else if (priv->adapter->connect_status == libertas_connected)
+ netif_wake_queue(priv->wlan_dev.netdev);
+
+ LEAVE();
+}
+
+/**
+ * @brief This function returns the network statistics
+ *
+ * @param dev A pointer to wlan_private structure
+ * @return A pointer to net_device_stats structure
+ */
+static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+{
+ wlan_private *priv = (wlan_private *) dev->priv;
+
+ return &priv->stats;
+}
+
+static int wlan_set_mac_address(struct net_device *dev, void *addr)
+{
+ int ret = 0;
+ wlan_private *priv = (wlan_private *) dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct sockaddr *phwaddr = addr;
+
+ ENTER();
+
+ memset(adapter->current_addr, 0, ETH_ALEN);
+
+ /* dev->dev_addr is 8 bytes */
+ lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+
+ lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+ memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ lbs_pr_debug(1, "set mac address failed.\n");
+ ret = -1;
+ goto done;
+ }
+
+ lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+ memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
+ memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static int wlan_copy_multicast_address(wlan_adapter * adapter,
+ struct net_device *dev)
+{
+ int i = 0;
+ struct dev_mc_list *mcptr = dev->mc_list;
+
+ for (i = 0; i < dev->mc_count; i++) {
+ memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN);
+ mcptr = mcptr->next;
+ }
+
+ return i;
+
+}
+
+static void wlan_set_multicast_list(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int oldpacketfilter;
+
+ ENTER();
+
+ oldpacketfilter = adapter->currentpacketfilter;
+
+ if (dev->flags & IFF_PROMISC) {
+ lbs_pr_debug(1, "enable Promiscuous mode\n");
+ adapter->currentpacketfilter |=
+ cmd_act_mac_promiscuous_enable;
+ adapter->currentpacketfilter &=
+ ~(cmd_act_mac_all_multicast_enable |
+ cmd_act_mac_multicast_enable);
+ } else {
+ /* Multicast */
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_promiscuous_enable;
+
+ if (dev->flags & IFF_ALLMULTI || dev->mc_count >
+ MRVDRV_MAX_MULTICAST_LIST_SIZE) {
+ lbs_pr_debug(1, "Enabling All Multicast!\n");
+ adapter->currentpacketfilter |=
+ cmd_act_mac_all_multicast_enable;
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_multicast_enable;
+ } else {
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_all_multicast_enable;
+
+ if (!dev->mc_count) {
+ lbs_pr_debug(1, "No multicast addresses - "
+ "disabling multicast!\n");
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_multicast_enable;
+ } else {
+ int i;
+
+ adapter->currentpacketfilter |=
+ cmd_act_mac_multicast_enable;
+
+ adapter->nr_of_multicastmacaddr =
+ wlan_copy_multicast_address(adapter, dev);
+
+ lbs_pr_debug(1, "Multicast addresses: %d\n",
+ dev->mc_count);
+
+ for (i = 0; i < dev->mc_count; i++) {
+ lbs_pr_debug(1, "Multicast address %d:"
+ "%x %x %x %x %x %x\n", i,
+ adapter->multicastlist[i][0],
+ adapter->multicastlist[i][1],
+ adapter->multicastlist[i][2],
+ adapter->multicastlist[i][3],
+ adapter->multicastlist[i][4],
+ adapter->multicastlist[i][5]);
+ }
+ /* set multicast addresses to firmware */
+ libertas_prepare_and_send_command(priv,
+ cmd_mac_multicast_adr,
+ cmd_act_set, 0, 0,
+ NULL);
+ }
+ }
+ }
+
+ if (adapter->currentpacketfilter != oldpacketfilter) {
+ libertas_set_mac_packet_filter(priv);
+ }
+
+ LEAVE();
+}
+
+/**
+ * @brief This function hanldes the major job in WLAN driver.
+ * it handles the event generated by firmware, rx data received
+ * from firmware and tx data sent from kernel.
+ *
+ * @param data A pointer to wlan_thread structure
+ * @return 0
+ */
+static int wlan_service_main_thread(void *data)
+{
+ struct wlan_thread *thread = data;
+ wlan_private *priv = thread->priv;
+ wlan_adapter *adapter = priv->adapter;
+ wait_queue_t wait;
+ u8 ireg = 0;
+
+ ENTER();
+
+ wlan_activate_thread(thread);
+
+ init_waitqueue_entry(&wait, current);
+
+ for (;;) {
+ lbs_pr_debug(1, "main-thread 111: intcounter=%d "
+ "currenttxskb=%p dnld_sent=%d\n",
+ adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ add_wait_queue(&thread->waitq, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ spin_lock_irq(&adapter->driver_lock);
+ if ((adapter->psstate == PS_STATE_SLEEP) ||
+ (!adapter->intcounter
+ && (priv->wlan_dev.dnld_sent || adapter->cur_cmd ||
+ list_empty(&adapter->cmdpendingq)))) {
+ lbs_pr_debug(1,
+ "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n",
+ adapter->connect_status, adapter->intcounter,
+ adapter->psmode, adapter->psstate);
+ spin_unlock_irq(&adapter->driver_lock);
+ schedule();
+ } else
+ spin_unlock_irq(&adapter->driver_lock);
+
+
+ lbs_pr_debug(1,
+ "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d\n", adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&thread->waitq, &wait);
+ try_to_freeze();
+
+ lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d\n",
+ adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ if (kthread_should_stop()
+ || adapter->surpriseremoved) {
+ lbs_pr_debug(1,
+ "main-thread: break from main thread: surpriseremoved=0x%x\n",
+ adapter->surpriseremoved);
+ break;
+ }
+
+
+ spin_lock_irq(&adapter->driver_lock);
+ if (adapter->intcounter) {
+ u8 int_status;
+ adapter->intcounter = 0;
+ int_status = libertas_sbi_get_int_status(priv, &ireg);
+
+ if (int_status) {
+ lbs_pr_debug(1,
+ "main-thread: reading HOST_INT_STATUS_REG failed\n");
+ spin_unlock_irq(&adapter->driver_lock);
+ continue;
+ }
+ adapter->hisregcpy |= ireg;
+ }
+
+ lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d\n",
+ adapter->intcounter,
+ adapter->currenttxskb, priv->wlan_dev.dnld_sent);
+
+ /* command response? */
+ if (adapter->hisregcpy & his_cmdupldrdy) {
+ lbs_pr_debug(1, "main-thread: cmd response ready.\n");
+
+ adapter->hisregcpy &= ~his_cmdupldrdy;
+ spin_unlock_irq(&adapter->driver_lock);
+ libertas_process_rx_command(priv);
+ spin_lock_irq(&adapter->driver_lock);
+ }
+
+ /* Any Card Event */
+ if (adapter->hisregcpy & his_cardevent) {
+ lbs_pr_debug(1, "main-thread: Card Event Activity.\n");
+
+ adapter->hisregcpy &= ~his_cardevent;
+
+ if (libertas_sbi_read_event_cause(priv)) {
+ lbs_pr_alert(
+ "main-thread: libertas_sbi_read_event_cause failed.\n");
+ spin_unlock_irq(&adapter->driver_lock);
+ continue;
+ }
+ spin_unlock_irq(&adapter->driver_lock);
+ libertas_process_event(priv);
+ } else
+ spin_unlock_irq(&adapter->driver_lock);
+
+ /* Check if we need to confirm Sleep Request received previously */
+ if (adapter->psstate == PS_STATE_PRE_SLEEP) {
+ if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) {
+ if (adapter->connect_status ==
+ libertas_connected) {
+ lbs_pr_debug(1,
+ "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
+ "dnld_sent=%d cur_cmd=%p, confirm now\n",
+ adapter->intcounter,
+ adapter->currenttxskb,
+ priv->wlan_dev.dnld_sent,
+ adapter->cur_cmd);
+
+ libertas_ps_confirm_sleep(priv,
+ (u16) adapter->psmode);
+ } else {
+ /* workaround for firmware sending
+ * deauth/linkloss event immediately
+ * after sleep request, remove this
+ * after firmware fixes it
+ */
+ adapter->psstate = PS_STATE_AWAKE;
+ lbs_pr_alert(
+ "main-thread: ignore PS_SleepConfirm in non-connected state\n");
+ }
+ }
+ }
+
+ /* The PS state is changed during processing of Sleep Request
+ * event above
+ */
+ if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+ (priv->adapter->psstate == PS_STATE_PRE_SLEEP))
+ continue;
+
+ /* Execute the next command */
+ if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd)
+ libertas_execute_next_command(priv);
+
+ /* Wake-up command waiters which can't sleep in
+ * libertas_prepare_and_send_command
+ */
+ if (!adapter->nr_cmd_pending)
+ wake_up_all(&adapter->cmd_pending);
+
+ libertas_tx_runqueue(priv);
+ }
+
+ del_timer(&adapter->command_timer);
+ adapter->nr_cmd_pending = 0;
+ wake_up_all(&adapter->cmd_pending);
+ wlan_deactivate_thread(thread);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function adds the card. it will probe the
+ * card, allocate the wlan_priv and initialize the device.
+ *
+ * @param card A pointer to card
+ * @return A pointer to wlan_private structure
+ */
+wlan_private *wlan_add_card(void *card)
+{
+ struct net_device *dev = NULL;
+ struct net_device *mesh_dev = NULL;
+ wlan_private *priv = NULL;
+
+ ENTER();
+
+ /* Allocate an Ethernet device and register it */
+ if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
+ lbs_pr_alert( "Init ethernet device failed!\n");
+ return NULL;
+ }
+
+ priv = dev->priv;
+
+ /* allocate buffer for wlan_adapter */
+ if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) {
+ lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n");
+ goto err_kmalloc;
+ }
+
+ /* Allocate a virtual mesh device */
+ if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) {
+ lbs_pr_debug(1, "Init ethernet device failed!\n");
+ return NULL;
+ }
+
+ /* Both intervaces share the priv structure */
+ mesh_dev->priv = priv;
+
+ /* init wlan_adapter */
+ memset(priv->adapter, 0, sizeof(wlan_adapter));
+
+ priv->wlan_dev.netdev = dev;
+ priv->wlan_dev.card = card;
+ priv->mesh_open = 0;
+ priv->infra_open = 0;
+ priv->mesh_dev = mesh_dev;
+ wlanpriv = priv;
+
+ SET_MODULE_OWNER(dev);
+ SET_MODULE_OWNER(mesh_dev);
+
+ /* Setup the OS Interface to our functions */
+ dev->open = wlan_open;
+ dev->hard_start_xmit = wlan_pre_start_xmit;
+ dev->stop = wlan_close;
+ dev->do_ioctl = libertas_do_ioctl;
+ dev->set_mac_address = wlan_set_mac_address;
+ mesh_dev->open = mesh_open;
+ mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
+ mesh_dev->stop = mesh_close;
+ mesh_dev->do_ioctl = libertas_do_ioctl;
+ memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr,
+ sizeof(wlanpriv->wlan_dev.netdev->dev_addr));
+
+#define WLAN_WATCHDOG_TIMEOUT (5 * HZ)
+
+ dev->tx_timeout = wlan_tx_timeout;
+ dev->get_stats = wlan_get_stats;
+ dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT;
+ dev->ethtool_ops = &libertas_ethtool_ops;
+ mesh_dev->get_stats = wlan_get_stats;
+ mesh_dev->ethtool_ops = &libertas_ethtool_ops;
+
+#ifdef WIRELESS_EXT
+ dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+ mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def;
+#endif
+#define NETIF_F_DYNALLOC 16
+ dev->features |= NETIF_F_DYNALLOC;
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ dev->set_multicast_list = wlan_set_multicast_list;
+
+ INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
+ INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+
+ spin_lock_init(&priv->adapter->driver_lock);
+ init_waitqueue_head(&priv->adapter->cmd_pending);
+ priv->adapter->nr_cmd_pending = 0;
+
+ lbs_pr_debug(1, "Starting kthread...\n");
+ priv->mainthread.priv = priv;
+ wlan_create_thread(wlan_service_main_thread,
+ &priv->mainthread, "wlan_main_service");
+
+ priv->assoc_thread =
+ create_singlethread_workqueue("libertas_assoc");
+ INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker);
+
+ /*
+ * Register the device. Fillup the private data structure with
+ * relevant information from the card and request for the required
+ * IRQ.
+ */
+ if (libertas_sbi_register_dev(priv) < 0) {
+ lbs_pr_info("failed to register wlan device!\n");
+ goto err_registerdev;
+ }
+
+ /* init FW and HW */
+ if (libertas_init_fw(priv)) {
+ lbs_pr_debug(1, "Firmware Init failed\n");
+ goto err_registerdev;
+ }
+
+ if (register_netdev(dev)) {
+ lbs_pr_err("Cannot register network device!\n");
+ goto err_init_fw;
+ }
+
+ /* Register virtual mesh interface */
+ if (register_netdev(mesh_dev)) {
+ lbs_pr_info("Cannot register mesh virtual interface!\n");
+ goto err_init_fw;
+ }
+
+ lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name);
+
+ libertas_debugfs_init_one(priv, dev);
+
+ if (libertas_found == MAX_DEVS)
+ goto err_init_fw;
+ libertas_devs[libertas_found] = dev;
+ libertas_found++;
+#ifdef ENABLE_PM
+ if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback)))
+ lbs_pr_alert( "failed to register PM callback\n");
+#endif
+ if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp))
+ goto err_create_file;
+
+ LEAVE();
+ return priv;
+
+err_create_file:
+ device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+err_init_fw:
+ libertas_sbi_unregister_dev(priv);
+err_registerdev:
+ destroy_workqueue(priv->assoc_thread);
+ /* Stop the thread servicing the interrupts */
+ wake_up_interruptible(&priv->mainthread.waitq);
+ wlan_terminate_thread(&priv->mainthread);
+ kfree(priv->adapter);
+err_kmalloc:
+ free_netdev(dev);
+ free_netdev(mesh_dev);
+ wlanpriv = NULL;
+
+ LEAVE();
+ return NULL;
+}
+
+static void wake_pending_cmdnodes(wlan_private *priv)
+{
+ struct cmd_ctrl_node *cmdnode;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+ list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+ cmdnode->cmdwaitqwoken = 1;
+ wake_up_interruptible(&cmdnode->cmdwait_q);
+ }
+ spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+}
+
+
+int wlan_remove_card(void *card)
+{
+ wlan_private *priv = libertas_sbi_get_priv(card);
+ wlan_adapter *adapter;
+ struct net_device *dev;
+ struct net_device *mesh_dev;
+ union iwreq_data wrqu;
+ int i;
+
+ ENTER();
+
+ if (!priv) {
+ LEAVE();
+ return 0;
+ }
+
+ adapter = priv->adapter;
+
+ if (!adapter) {
+ LEAVE();
+ return 0;
+ }
+
+ dev = priv->wlan_dev.netdev;
+ mesh_dev = priv->mesh_dev;
+
+ netif_stop_queue(mesh_dev);
+ netif_stop_queue(priv->wlan_dev.netdev);
+ netif_carrier_off(priv->wlan_dev.netdev);
+
+ wake_pending_cmdnodes(priv);
+
+ device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp);
+ unregister_netdev(mesh_dev);
+ unregister_netdev(dev);
+
+ cancel_delayed_work(&priv->assoc_work);
+ destroy_workqueue(priv->assoc_thread);
+
+ if (adapter->psmode == wlan802_11powermodemax_psp) {
+ adapter->psmode = wlan802_11powermodecam;
+ libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ }
+
+ memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL);
+
+#ifdef ENABLE_PM
+ pm_unregister(wlan_pm_dev);
+#endif
+
+ adapter->surpriseremoved = 1;
+
+ /* Stop the thread servicing the interrupts */
+ wlan_terminate_thread(&priv->mainthread);
+
+ libertas_debugfs_remove_one(priv);
+
+ lbs_pr_debug(1, "Free adapter\n");
+ libertas_free_adapter(priv);
+
+ for (i = 0; i<libertas_found; i++) {
+ if (libertas_devs[i]==priv->wlan_dev.netdev) {
+ libertas_devs[i] = libertas_devs[--libertas_found];
+ libertas_devs[libertas_found] = NULL ;
+ break ;
+ }
+ }
+
+ lbs_pr_debug(1, "Unregister finish\n");
+
+ priv->wlan_dev.netdev = NULL;
+ priv->mesh_dev = NULL ;
+ free_netdev(mesh_dev);
+ free_netdev(dev);
+ wlanpriv = NULL;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function finds the CFP in
+ * region_cfp_table based on region and band parameter.
+ *
+ * @param region The region code
+ * @param band The band
+ * @param cfp_no A pointer to CFP number
+ * @return A pointer to CFP
+ */
+struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no)
+{
+ int i, end;
+
+ ENTER();
+
+ end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+
+ for (i = 0; i < end ; i++) {
+ lbs_pr_debug(1, "region_cfp_table[i].region=%d\n",
+ region_cfp_table[i].region);
+ if (region_cfp_table[i].region == region) {
+ *cfp_no = region_cfp_table[i].cfp_no_BG;
+ LEAVE();
+ return region_cfp_table[i].cfp_BG;
+ }
+ }
+
+ LEAVE();
+ return NULL;
+}
+
+int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i = 0;
+
+ struct chan_freq_power *cfp;
+ int cfp_no;
+
+ ENTER();
+
+ memset(adapter->region_channel, 0, sizeof(adapter->region_channel));
+
+ {
+ cfp = libertas_get_region_cfp_table(region, band, &cfp_no);
+ if (cfp != NULL) {
+ adapter->region_channel[i].nrcfp = cfp_no;
+ adapter->region_channel[i].CFP = cfp;
+ } else {
+ lbs_pr_debug(1, "wrong region code %#x in band B-G\n",
+ region);
+ return -1;
+ }
+ adapter->region_channel[i].valid = 1;
+ adapter->region_channel[i].region = region;
+ adapter->region_channel[i].band = band;
+ i++;
+ }
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function handles the interrupt. it will change PS
+ * state if applicable. it will wake up main_thread to handle
+ * the interrupt event as well.
+ *
+ * @param dev A pointer to net_device structure
+ * @return n/a
+ */
+void libertas_interrupt(struct net_device *dev)
+{
+ wlan_private *priv = dev->priv;
+
+ ENTER();
+
+ lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n",
+ priv->adapter->intcounter);
+
+ priv->adapter->intcounter++;
+
+ if (priv->adapter->psstate == PS_STATE_SLEEP) {
+ priv->adapter->psstate = PS_STATE_AWAKE;
+ netif_wake_queue(dev);
+ }
+
+ wake_up_interruptible(&priv->mainthread.waitq);
+
+ LEAVE();
+}
+
+static int wlan_init_module(void)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (libertas_fw_name == NULL) {
+ libertas_fw_name = default_fw_name;
+ }
+
+ libertas_debugfs_init();
+
+ if (libertas_sbi_register()) {
+ ret = -1;
+ libertas_debugfs_remove();
+ goto done;
+ }
+
+done:
+ LEAVE();
+ return ret;
+}
+
+static void wlan_cleanup_module(void)
+{
+ int i;
+
+ ENTER();
+
+ for (i = 0; i<libertas_found; i++) {
+ wlan_private *priv = libertas_devs[i]->priv;
+ reset_device(priv);
+ }
+
+ libertas_sbi_unregister();
+ libertas_debugfs_remove();
+
+ LEAVE();
+}
+
+module_init(wlan_init_module);
+module_exit(wlan_cleanup_module);
+
+MODULE_DESCRIPTION("M-WLAN Driver");
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
new file mode 100644
index 00000000000..5d118f40cfb
--- /dev/null
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -0,0 +1,57 @@
+#include <net/ieee80211_radiotap.h>
+
+struct tx_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 rate;
+ u8 txpower;
+ u8 rts_retries;
+ u8 data_retries;
+#if 0
+ u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12];
+#endif
+} __attribute__ ((packed));
+
+#define TX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
+ (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \
+ (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \
+ 0)
+
+#define IEEE80211_FC_VERSION_MASK 0x0003
+#define IEEE80211_FC_TYPE_MASK 0x000c
+#define IEEE80211_FC_TYPE_MGT 0x0000
+#define IEEE80211_FC_TYPE_CTL 0x0004
+#define IEEE80211_FC_TYPE_DATA 0x0008
+#define IEEE80211_FC_SUBTYPE_MASK 0x00f0
+#define IEEE80211_FC_TOFROMDS_MASK 0x0300
+#define IEEE80211_FC_TODS_MASK 0x0100
+#define IEEE80211_FC_FROMDS_MASK 0x0200
+#define IEEE80211_FC_NODS 0x0000
+#define IEEE80211_FC_TODS 0x0100
+#define IEEE80211_FC_FROMDS 0x0200
+#define IEEE80211_FC_DSTODS 0x0300
+
+struct rx_radiotap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 flags;
+ u8 rate;
+ u16 chan_freq;
+ u16 chan_flags;
+ u8 antenna;
+ u8 antsignal;
+ u16 rx_flags;
+#if 0
+ u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18];
+#endif
+} __attribute__ ((packed));
+
+#define RX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\
+ (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \
+ 0)
+
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
new file mode 100644
index 00000000000..7e3f78f092d
--- /dev/null
+++ b/drivers/net/wireless/libertas/rx.c
@@ -0,0 +1,459 @@
+/**
+ * This file contains the handling of RX in wlan driver.
+ */
+#include <linux/etherdevice.h>
+#include <linux/types.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "dev.h"
+#include "wext.h"
+
+struct eth803hdr {
+ u8 dest_addr[6];
+ u8 src_addr[6];
+ u16 h803_len;
+} __attribute__ ((packed));
+
+struct rfc1042hdr {
+ u8 llc_dsap;
+ u8 llc_ssap;
+ u8 llc_ctrl;
+ u8 snap_oui[3];
+ u16 snap_type;
+} __attribute__ ((packed));
+
+struct rxpackethdr {
+ struct rxpd rx_pd;
+ struct eth803hdr eth803_hdr;
+ struct rfc1042hdr rfc1042_hdr;
+} __attribute__ ((packed));
+
+struct rx80211packethdr {
+ struct rxpd rx_pd;
+ void *eth80211_hdr;
+} __attribute__ ((packed));
+
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb);
+
+/**
+ * @brief This function computes the avgSNR .
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return avgSNR
+ */
+static u8 wlan_getavgsnr(wlan_private * priv)
+{
+ u8 i;
+ u16 temp = 0;
+ wlan_adapter *adapter = priv->adapter;
+ if (adapter->numSNRNF == 0)
+ return 0;
+ for (i = 0; i < adapter->numSNRNF; i++)
+ temp += adapter->rawSNR[i];
+ return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ * @brief This function computes the AvgNF
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return AvgNF
+ */
+static u8 wlan_getavgnf(wlan_private * priv)
+{
+ u8 i;
+ u16 temp = 0;
+ wlan_adapter *adapter = priv->adapter;
+ if (adapter->numSNRNF == 0)
+ return 0;
+ for (i = 0; i < adapter->numSNRNF; i++)
+ temp += adapter->rawNF[i];
+ return (u8) (temp / adapter->numSNRNF);
+
+}
+
+/**
+ * @brief This function save the raw SNR/NF to our internel buffer
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param prxpd A pointer to rxpd structure of received packet
+ * @return n/a
+ */
+static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+ wlan_adapter *adapter = priv->adapter;
+ if (adapter->numSNRNF < adapter->data_avg_factor)
+ adapter->numSNRNF++;
+ adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
+ adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
+ adapter->nextSNRNF++;
+ if (adapter->nextSNRNF >= adapter->data_avg_factor)
+ adapter->nextSNRNF = 0;
+ return;
+}
+
+/**
+ * @brief This function computes the RSSI in received packet.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param prxpd A pointer to rxpd structure of received packet
+ * @return n/a
+ */
+static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf);
+ lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n",
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;
+ adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
+ wlan_save_rawSNRNF(priv, p_rx_pd);
+
+ adapter->rxpd_rate = p_rx_pd->rx_rate;
+
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
+ adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
+ lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n",
+ adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] =
+ CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG],
+ adapter->NF[TYPE_RXPD][TYPE_NOAVG]);
+
+ adapter->RSSI[TYPE_RXPD][TYPE_AVG] =
+ CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);
+
+ LEAVE();
+}
+
+int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb)
+{
+ lbs_pr_debug(1, "skb->data=%p\n", skb->data);
+
+ if(IS_MESH_FRAME(skb))
+ skb->dev = priv->mesh_dev;
+ else
+ skb->dev = priv->wlan_dev.netdev;
+ skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netif_rx(skb);
+
+ return 0;
+}
+
+/**
+ * @brief This function processes received packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param priv A pointer to wlan_private
+ * @param skb A pointer to skb which includes the received packet
+ * @return 0 or -1
+ */
+int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ struct rxpackethdr *p_rx_pkt;
+ struct rxpd *p_rx_pd;
+
+ int hdrchop;
+ struct ethhdr *p_ethhdr;
+
+ const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ ENTER();
+
+ if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
+ lbs_dbg_hex("RX packet: ", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ return process_rxed_802_11_packet(priv, skb);
+
+ p_rx_pkt = (struct rxpackethdr *) skb->data;
+ p_rx_pd = &p_rx_pkt->rx_pd;
+ if (p_rx_pd->rx_control & RxPD_MESH_FRAME)
+ SET_MESH_FRAME(skb);
+ else
+ UNSET_MESH_FRAME(skb);
+
+ lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+ lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+ priv->stats.rx_length_errors++;
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Check rxpd status and update 802.3 stat,
+ */
+ if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) {
+ lbs_pr_debug(1, "RX error: frame received with bad status\n");
+ lbs_pr_alert("rxpd Not OK\n");
+ priv->stats.rx_errors++;
+ ret = 0;
+ goto done;
+ }
+
+ lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+ skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+ lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+ sizeof(p_rx_pkt->eth803_hdr.dest_addr));
+ lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+ sizeof(p_rx_pkt->eth803_hdr.src_addr));
+
+ if (memcmp(&p_rx_pkt->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type (ethertype)
+ *
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ *
+ * To create the Ethernet II, just move the src, dst address right
+ * before the snap_type.
+ */
+ p_ethhdr = (struct ethhdr *)
+ ((u8 *) & p_rx_pkt->eth803_hdr
+ + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr)
+ - sizeof(p_rx_pkt->eth803_hdr.dest_addr)
+ - sizeof(p_rx_pkt->eth803_hdr.src_addr)
+ - sizeof(p_rx_pkt->rfc1042_hdr.snap_type));
+
+ memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr,
+ sizeof(p_ethhdr->h_source));
+ memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr,
+ sizeof(p_ethhdr->h_dest));
+
+ /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header
+ * that was removed
+ */
+ hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
+ } else {
+ lbs_dbg_hex("RX Data: LLC/SNAP",
+ (u8 *) & p_rx_pkt->rfc1042_hdr,
+ sizeof(p_rx_pkt->rfc1042_hdr));
+
+ /* Chop off the rxpd */
+ hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt;
+ }
+
+ /* Chop off the leading header bytes so the skb points to the start of
+ * either the reconstructed EthII frame or the 802.2/llc/snap frame
+ */
+ skb_pull(skb, hdrchop);
+
+ /* Take the data rate from the rxpd structure
+ * only if the rate is auto
+ */
+ if (adapter->is_datarate_auto)
+ adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+
+ wlan_compute_rssi(priv, p_rx_pd);
+
+ lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+ if (libertas_upload_rx_packet(priv, skb)) {
+ lbs_pr_debug(1, "RX error: libertas_upload_rx_packet"
+ " returns failure\n");
+ ret = -1;
+ goto done;
+ }
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+ ret = 0;
+done:
+ LEAVE();
+
+ return ret;
+}
+
+/**
+ * @brief This function converts Tx/Rx rates from the Marvell WLAN format
+ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ *
+ * @param rate Input rate
+ * @return Output Rate (0 if invalid)
+ */
+static u8 convert_mv_rate_to_radiotap(u8 rate)
+{
+ switch (rate) {
+ case 0: /* 1 Mbps */
+ return 2;
+ case 1: /* 2 Mbps */
+ return 4;
+ case 2: /* 5.5 Mbps */
+ return 11;
+ case 3: /* 11 Mbps */
+ return 22;
+ case 4: /* 6 Mbps */
+ return 12;
+ case 5: /* 9 Mbps */
+ return 18;
+ case 6: /* 12 Mbps */
+ return 24;
+ case 7: /* 18 Mbps */
+ return 36;
+ case 8: /* 24 Mbps */
+ return 48;
+ case 9: /* 36 Mbps */
+ return 72;
+ case 10: /* 48 Mbps */
+ return 96;
+ case 11: /* 54 Mbps */
+ return 108;
+ }
+ lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate);
+ return 0;
+}
+
+/**
+ * @brief This function processes a received 802.11 packet and forwards it
+ * to kernel/upper layer
+ *
+ * @param priv A pointer to wlan_private
+ * @param skb A pointer to skb which includes the received packet
+ * @return 0 or -1
+ */
+static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ struct rx80211packethdr *p_rx_pkt;
+ struct rxpd *prxpd;
+ struct rx_radiotap_hdr radiotap_hdr;
+ struct rx_radiotap_hdr *pradiotap_hdr;
+
+ ENTER();
+
+ p_rx_pkt = (struct rx80211packethdr *) skb->data;
+ prxpd = &p_rx_pkt->rx_pd;
+
+ // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+
+ if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
+ lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n");
+ priv->stats.rx_length_errors++;
+ ret = 0;
+ goto done;
+ }
+
+ /*
+ * Check rxpd status and update 802.3 stat,
+ */
+ if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) {
+ //lbs_pr_debug(1, "RX error: frame received with bad status\n");
+ priv->stats.rx_errors++;
+ }
+
+ lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n",
+ skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
+
+ /* create the exported radio header */
+ switch (priv->adapter->radiomode) {
+ case WLAN_RADIOMODE_NONE:
+ /* no radio header */
+ /* chop the rxpd */
+ skb_pull(skb, sizeof(struct rxpd));
+ break;
+
+ case WLAN_RADIOMODE_RADIOTAP:
+ /* radiotap header */
+ radiotap_hdr.hdr.it_version = 0;
+ /* XXX must check this value for pad */
+ radiotap_hdr.hdr.it_pad = 0;
+ radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
+ radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+ /* unknown values */
+ radiotap_hdr.flags = 0;
+ radiotap_hdr.chan_freq = 0;
+ radiotap_hdr.chan_flags = 0;
+ radiotap_hdr.antenna = 0;
+ /* known values */
+ radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
+ /* XXX must check no carryout */
+ radiotap_hdr.antsignal = prxpd->snr + prxpd->nf;
+ radiotap_hdr.rx_flags = 0;
+ if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK))
+ radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
+ //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
+
+ // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
+
+ /* chop the rxpd */
+ skb_pull(skb, sizeof(struct rxpd));
+
+ /* add space for the new radio header */
+ if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
+ pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0,
+ GFP_ATOMIC)) {
+ lbs_pr_alert( "%s: couldn't pskb_expand_head\n",
+ __func__);
+ }
+
+ pradiotap_hdr =
+ (struct rx_radiotap_hdr *)skb_push(skb,
+ sizeof(struct
+ rx_radiotap_hdr));
+ memcpy(pradiotap_hdr, &radiotap_hdr,
+ sizeof(struct rx_radiotap_hdr));
+ //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
+ break;
+
+ default:
+ /* unknown header */
+ lbs_pr_alert( "Unknown radiomode (%i)\n",
+ priv->adapter->radiomode);
+ /* don't export any header */
+ /* chop the rxpd */
+ skb_pull(skb, sizeof(struct rxpd));
+ break;
+ }
+
+ /* Take the data rate from the rxpd structure
+ * only if the rate is auto
+ */
+ if (adapter->is_datarate_auto) {
+ adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
+ }
+
+ wlan_compute_rssi(priv, prxpd);
+
+ lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len);
+
+ if (libertas_upload_rx_packet(priv, skb)) {
+ lbs_pr_debug(1, "RX error: libertas_upload_rx_packet "
+ "returns failure\n");
+ ret = -1;
+ goto done;
+ }
+
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+
+ ret = 0;
+done:
+ LEAVE();
+
+ skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
+
+ return (ret);
+}
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h
new file mode 100644
index 00000000000..59d3a59ccef
--- /dev/null
+++ b/drivers/net/wireless/libertas/sbi.h
@@ -0,0 +1,40 @@
+/**
+ * This file contains IF layer definitions.
+ */
+
+#ifndef _SBI_H_
+#define _SBI_H_
+
+#include <linux/interrupt.h>
+
+#include "defs.h"
+
+/** INT status Bit Definition*/
+#define his_cmddnldrdy 0x01
+#define his_cardevent 0x02
+#define his_cmdupldrdy 0x04
+
+#ifndef DEV_NAME_LEN
+#define DEV_NAME_LEN 32
+#endif
+
+#define SBI_EVENT_CAUSE_SHIFT 3
+
+/* Probe and Check if the card is present*/
+int libertas_sbi_register_dev(wlan_private * priv);
+int libertas_sbi_unregister_dev(wlan_private *);
+int libertas_sbi_get_int_status(wlan_private * priv, u8 *);
+int libertas_sbi_register(void);
+void libertas_sbi_unregister(void);
+int libertas_sbi_prog_firmware(wlan_private *);
+
+int libertas_sbi_read_event_cause(wlan_private *);
+int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
+wlan_private *libertas_sbi_get_priv(void *card);
+
+#ifdef ENABLE_PM
+int libertas_sbi_suspend(wlan_private *);
+int libertas_sbi_resume(wlan_private *);
+#endif
+
+#endif /* _SBI_H */
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
new file mode 100644
index 00000000000..e1870623895
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.c
@@ -0,0 +1,2044 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+ * Functions implementing wlan scan IOCTL and firmware command APIs
+ *
+ * IOCTL handlers as well as command preperation and response routines
+ * for sending scan commands to the firmware.
+ */
+#include <linux/ctype.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "decl.h"
+#include "dev.h"
+#include "scan.h"
+
+//! Approximate amount of data needed to pass a scan result back to iwlist
+#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \
+ + IW_ESSID_MAX_SIZE \
+ + IW_EV_UINT_LEN \
+ + IW_EV_FREQ_LEN \
+ + IW_EV_QUAL_LEN \
+ + IW_ESSID_MAX_SIZE \
+ + IW_EV_PARAM_LEN \
+ + 40) /* 40 for WPAIE */
+
+//! Memory needed to store a max sized channel List TLV for a firmware scan
+#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \
+ + (MRVDRV_MAX_CHANNELS_PER_SCAN \
+ * sizeof(struct chanscanparamset)))
+
+//! Memory needed to store a max number/size SSID TLV for a firmware scan
+#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset))
+
+//! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \
+ + sizeof(struct mrvlietypes_numprobes) \
+ + CHAN_TLV_MAX_SIZE \
+ + SSID_TLV_MAX_SIZE)
+
+//! The maximum number of channels the firmware can scan per command
+#define MRVDRV_MAX_CHANNELS_PER_SCAN 14
+
+/**
+ * @brief Number of channels to scan per firmware scan command issuance.
+ *
+ * Number restricted to prevent hitting the limit on the amount of scan data
+ * returned in a single firmware scan command.
+ */
+#define MRVDRV_CHANNELS_PER_SCAN_CMD 4
+
+//! Scan time specified in the channel TLV for each channel for passive scans
+#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100
+
+//! Scan time specified in the channel TLV for each channel for active scans
+#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100
+
+//! Macro to enable/disable SSID checking before storing a scan table
+#ifdef DISCARD_BAD_SSID
+#define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid)
+#else
+#define CHECK_SSID_IS_VALID(x) 1
+#endif
+
+/**
+ * @brief Check if a scanned network compatible with the driver settings
+ *
+ * WEP WPA WPA2 ad-hoc encrypt Network
+ * enabled enabled enabled AES mode privacy WPA WPA2 Compatible
+ * 0 0 0 0 NONE 0 0 0 yes No security
+ * 1 0 0 0 NONE 1 0 0 yes Static WEP
+ * 0 1 0 0 x 1x 1 x yes WPA
+ * 0 0 1 0 x 1x x 1 yes WPA2
+ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ *
+ * @param adapter A pointer to wlan_adapter
+ * @param index Index in scantable to check against current driver settings
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return Index in scantable, or error code if negative
+ */
+static int is_network_compatible(wlan_adapter * adapter, int index, int mode)
+{
+ ENTER();
+
+ if (adapter->scantable[index].inframode == mode) {
+ if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && adapter->scantable[index].wpa_supplicant.wpa_ie[0] !=
+ WPA_IE
+ && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] !=
+ WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE
+ && !adapter->scantable[index].privacy) {
+ /* no security */
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && adapter->scantable[index].privacy) {
+ /* static WEP enabled */
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && (adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0]
+ == WPA_IE)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+ && adapter->scantable[index].privacy */
+ ) {
+ /* WPA enabled */
+ lbs_pr_debug(1,
+ "is_network_compatible() WPA: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+ "privacy=%#x\n", index,
+ adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0],
+ (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) ? "e" : "d",
+ (adapter->secinfo.WPAenabled) ? "e" : "d",
+ (adapter->secinfo.WPA2enabled) ? "e" : "d",
+ adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && !adapter->secinfo.WPAenabled
+ && adapter->secinfo.WPA2enabled
+ && (adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0]
+ == WPA2_IE)
+ /* privacy bit may NOT be set in some APs like LinkSys WRT54G
+ && adapter->scantable[index].privacy */
+ ) {
+ /* WPA2 enabled */
+ lbs_pr_debug(1,
+ "is_network_compatible() WPA2: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x "
+ "privacy=%#x\n", index,
+ adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0],
+ (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) ? "e" : "d",
+ (adapter->secinfo.WPAenabled) ? "e" : "d",
+ (adapter->secinfo.WPA2enabled) ? "e" : "d",
+ adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return index;
+ } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled
+ && (adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0]
+ != WPA_IE)
+ && (adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0]
+ != WPA2_IE)
+ && adapter->secinfo.Encryptionmode != CIPHER_NONE
+ && adapter->scantable[index].privacy) {
+ /* dynamic WEP enabled */
+ lbs_pr_debug(1,
+ "is_network_compatible() dynamic WEP: index=%d "
+ "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n",
+ index,
+ adapter->scantable[index].wpa_supplicant.
+ wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.
+ wpa_ie[0], adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return index;
+ }
+
+ /* security doesn't match */
+ lbs_pr_debug(1,
+ "is_network_compatible() FAILED: index=%d wpa_ie=%#x "
+ "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n",
+ index,
+ adapter->scantable[index].wpa_supplicant.wpa_ie[0],
+ adapter->scantable[index].wpa2_supplicant.wpa_ie[0],
+ (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) ? "e" : "d",
+ (adapter->secinfo.WPAenabled) ? "e" : "d",
+ (adapter->secinfo.WPA2enabled) ? "e" : "d",
+ adapter->secinfo.Encryptionmode,
+ adapter->scantable[index].privacy);
+ LEAVE();
+ return -ECONNREFUSED;
+ }
+
+ /* mode doesn't match */
+ LEAVE();
+ return -ENETUNREACH;
+}
+
+/**
+ * @brief This function validates a SSID as being able to be printed
+ *
+ * @param pssid SSID structure to validate
+ *
+ * @return TRUE or FALSE
+ */
+static u8 ssid_valid(struct WLAN_802_11_SSID *pssid)
+{
+ int ssididx;
+
+ for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) {
+ if (!isprint(pssid->ssid[ssididx])) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * @brief Post process the scan table after a new scan command has completed
+ *
+ * Inspect each entry of the scan table and try to find an entry that
+ * matches our current associated/joined network from the scan. If
+ * one is found, update the stored copy of the bssdescriptor for our
+ * current network.
+ *
+ * Debug dump the current scan table contents if compiled accordingly.
+ *
+ * @param priv A pointer to wlan_private structure
+ *
+ * @return void
+ */
+static void wlan_scan_process_results(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int foundcurrent;
+ int i;
+
+ foundcurrent = 0;
+
+ if (adapter->connect_status == libertas_connected) {
+ /* try to find the current BSSID in the new scan list */
+ for (i = 0; i < adapter->numinscantable; i++) {
+ if (!libertas_SSID_cmp(&adapter->scantable[i].ssid,
+ &adapter->curbssparams.ssid) &&
+ !memcmp(adapter->curbssparams.bssid,
+ adapter->scantable[i].macaddress,
+ ETH_ALEN)) {
+ foundcurrent = 1;
+ }
+ }
+
+ if (foundcurrent) {
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&adapter->curbssparams.bssdescriptor,
+ &adapter->scantable[i],
+ sizeof(adapter->curbssparams.bssdescriptor));
+ }
+ }
+
+ for (i = 0; i < adapter->numinscantable; i++) {
+ lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, "
+ "RSSI[%03d], SSID[%s]\n",
+ i,
+ adapter->scantable[i].macaddress[0],
+ adapter->scantable[i].macaddress[1],
+ adapter->scantable[i].macaddress[2],
+ adapter->scantable[i].macaddress[3],
+ adapter->scantable[i].macaddress[4],
+ adapter->scantable[i].macaddress[5],
+ (s32) adapter->scantable[i].rssi,
+ adapter->scantable[i].ssid.ssid);
+ }
+}
+
+/**
+ * @brief Create a channel list for the driver to scan based on region info
+ *
+ * Use the driver region/band information to construct a comprehensive list
+ * of channels to scan. This routine is used for any scan that is not
+ * provided a specific channel list to scan.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param scanchanlist Output parameter: resulting channel list to scan
+ * @param filteredscan Flag indicating whether or not a BSSID or SSID filter
+ * is being sent in the command to firmware. Used to
+ * increase the number of channels sent in a scan
+ * command and to disable the firmware channel scan
+ * filter.
+ *
+ * @return void
+ */
+static void wlan_scan_create_channel_list(wlan_private * priv,
+ struct chanscanparamset * scanchanlist,
+ u8 filteredscan)
+{
+
+ wlan_adapter *adapter = priv->adapter;
+ struct region_channel *scanregion;
+ struct chan_freq_power *cfp;
+ int rgnidx;
+ int chanidx;
+ int nextchan;
+ u8 scantype;
+
+ chanidx = 0;
+
+ /* Set the default scan type to the user specified type, will later
+ * be changed to passive on a per channel basis if restricted by
+ * regulatory requirements (11d or 11h)
+ */
+ scantype = adapter->scantype;
+
+ for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
+ if (priv->adapter->enable11d &&
+ adapter->connect_status != libertas_connected) {
+ /* Scan all the supported chan for the first scan */
+ if (!adapter->universal_channel[rgnidx].valid)
+ continue;
+ scanregion = &adapter->universal_channel[rgnidx];
+
+ /* clear the parsed_region_chan for the first scan */
+ memset(&adapter->parsed_region_chan, 0x00,
+ sizeof(adapter->parsed_region_chan));
+ } else {
+ if (!adapter->region_channel[rgnidx].valid)
+ continue;
+ scanregion = &adapter->region_channel[rgnidx];
+ }
+
+ for (nextchan = 0;
+ nextchan < scanregion->nrcfp; nextchan++, chanidx++) {
+
+ cfp = scanregion->CFP + nextchan;
+
+ if (priv->adapter->enable11d) {
+ scantype =
+ libertas_get_scan_type_11d(cfp->channel,
+ &adapter->
+ parsed_region_chan);
+ }
+
+ switch (scanregion->band) {
+ case BAND_B:
+ case BAND_G:
+ default:
+ scanchanlist[chanidx].radiotype =
+ cmd_scan_radio_type_bg;
+ break;
+ }
+
+ if (scantype == cmd_scan_type_passive) {
+ scanchanlist[chanidx].maxscantime =
+ cpu_to_le16
+ (MRVDRV_PASSIVE_SCAN_CHAN_TIME);
+ scanchanlist[chanidx].chanscanmode.passivescan =
+ 1;
+ } else {
+ scanchanlist[chanidx].maxscantime =
+ cpu_to_le16
+ (MRVDRV_ACTIVE_SCAN_CHAN_TIME);
+ scanchanlist[chanidx].chanscanmode.passivescan =
+ 0;
+ }
+
+ scanchanlist[chanidx].channumber = cfp->channel;
+
+ if (filteredscan) {
+ scanchanlist[chanidx].chanscanmode.
+ disablechanfilt = 1;
+ }
+ }
+ }
+}
+
+/**
+ * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
+ *
+ * Application layer or other functions can invoke wlan_scan_networks
+ * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct.
+ * This structure is used as the basis of one or many wlan_scan_cmd_config
+ * commands that are sent to the command processing module and sent to
+ * firmware.
+ *
+ * Create a wlan_scan_cmd_config based on the following user supplied
+ * parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - channel list
+ *
+ * If the SSID or BSSID filter is not present, disable/clear the filter.
+ * If the number of probes is not set, use the adapter default setting
+ * Qualify the channel
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param puserscanin NULL or pointer to scan configuration parameters
+ * @param ppchantlvout Output parameter: Pointer to the start of the
+ * channel TLV portion of the output scan config
+ * @param pscanchanlist Output parameter: Pointer to the resulting channel
+ * list to scan
+ * @param pmaxchanperscan Output parameter: Number of channels to scan for
+ * each issuance of the firmware scan command
+ * @param pfilteredscan Output parameter: Flag indicating whether or not
+ * a BSSID or SSID filter is being sent in the
+ * command to firmware. Used to increase the number
+ * of channels sent in a scan command and to
+ * disable the firmware channel scan filter.
+ * @param pscancurrentonly Output parameter: Flag indicating whether or not
+ * we are only scanning our current active channel
+ *
+ * @return resulting scan configuration
+ */
+static struct wlan_scan_cmd_config *
+wlan_scan_setup_scan_config(wlan_private * priv,
+ const struct wlan_ioctl_user_scan_cfg * puserscanin,
+ struct mrvlietypes_chanlistparamset ** ppchantlvout,
+ struct chanscanparamset * pscanchanlist,
+ int *pmaxchanperscan,
+ u8 * pfilteredscan,
+ u8 * pscancurrentonly)
+{
+ wlan_adapter *adapter = priv->adapter;
+ const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ struct mrvlietypes_numprobes *pnumprobestlv;
+ struct mrvlietypes_ssidparamset *pssidtlv;
+ struct wlan_scan_cmd_config * pscancfgout = NULL;
+ u8 *ptlvpos;
+ u16 numprobes;
+ u16 ssidlen;
+ int chanidx;
+ int scantype;
+ int scandur;
+ int channel;
+ int radiotype;
+
+ pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
+ if (pscancfgout == NULL)
+ goto out;
+
+ /* The tlvbufferlen is calculated for each scan command. The TLVs added
+ * in this routine will be preserved since the routine that sends
+ * the command will append channelTLVs at *ppchantlvout. The difference
+ * between the *ppchantlvout and the tlvbuffer start will be used
+ * to calculate the size of anything we add in this routine.
+ */
+ pscancfgout->tlvbufferlen = 0;
+
+ /* Running tlv pointer. Assigned to ppchantlvout at end of function
+ * so later routines know where channels can be added to the command buf
+ */
+ ptlvpos = pscancfgout->tlvbuffer;
+
+ /*
+ * Set the initial scan paramters for progressive scanning. If a specific
+ * BSSID or SSID is used, the number of channels in the scan command
+ * will be increased to the absolute maximum
+ */
+ *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD;
+
+ /* Initialize the scan as un-filtered by firmware, set to TRUE below if
+ * a SSID or BSSID filter is sent in the command
+ */
+ *pfilteredscan = 0;
+
+ /* Initialize the scan as not being only on the current channel. If
+ * the channel list is customized, only contains one channel, and
+ * is the active channel, this is set true and data flow is not halted.
+ */
+ *pscancurrentonly = 0;
+
+ if (puserscanin) {
+
+ /* Set the bss type scan filter, use adapter setting if unset */
+ pscancfgout->bsstype =
+ (puserscanin->bsstype ? puserscanin->bsstype : adapter->
+ scanmode);
+
+ /* Set the number of probes to send, use adapter setting if unset */
+ numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
+ adapter->scanprobes);
+
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled (all zeros).
+ */
+ memcpy(pscancfgout->specificBSSID,
+ puserscanin->specificBSSID,
+ sizeof(pscancfgout->specificBSSID));
+
+ ssidlen = strlen(puserscanin->specificSSID);
+
+ if (ssidlen) {
+ pssidtlv =
+ (struct mrvlietypes_ssidparamset *) pscancfgout->
+ tlvbuffer;
+ pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID);
+ pssidtlv->header.len = cpu_to_le16(ssidlen);
+ memcpy(pssidtlv->ssid, puserscanin->specificSSID,
+ ssidlen);
+ ptlvpos += sizeof(pssidtlv->header) + ssidlen;
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not truncate
+ * scan results. That is not an issue with an SSID or BSSID
+ * filter applied to the scan results in the firmware.
+ */
+ if (ssidlen || (memcmp(pscancfgout->specificBSSID,
+ &zeromac, sizeof(zeromac)) != 0)) {
+ *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN;
+ *pfilteredscan = 1;
+ }
+ } else {
+ pscancfgout->bsstype = adapter->scanmode;
+ numprobes = adapter->scanprobes;
+ }
+
+ /* If the input config or adapter has the number of Probes set, add tlv */
+ if (numprobes) {
+ pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos;
+ pnumprobestlv->header.type =
+ cpu_to_le16(TLV_TYPE_NUMPROBES);
+ pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes);
+ pnumprobestlv->numprobes = cpu_to_le16(numprobes);
+
+ ptlvpos +=
+ sizeof(pnumprobestlv->header) + pnumprobestlv->header.len;
+
+ pnumprobestlv->header.len =
+ cpu_to_le16(pnumprobestlv->header.len);
+ }
+
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this fuction (SSID, numprobes).
+ * channel TLVs will be added past this for each scan command, preserving
+ * the TLVs that were previously added.
+ */
+ *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
+
+ if (puserscanin && puserscanin->chanlist[0].channumber) {
+
+ lbs_pr_debug(1, "Scan: Using supplied channel list\n");
+
+ for (chanidx = 0;
+ chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+ && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+
+ channel = puserscanin->chanlist[chanidx].channumber;
+ (pscanchanlist + chanidx)->channumber = channel;
+
+ radiotype = puserscanin->chanlist[chanidx].radiotype;
+ (pscanchanlist + chanidx)->radiotype = radiotype;
+
+ scantype = puserscanin->chanlist[chanidx].scantype;
+
+ if (scantype == cmd_scan_type_passive) {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 1;
+ } else {
+ (pscanchanlist +
+ chanidx)->chanscanmode.passivescan = 0;
+ }
+
+ if (puserscanin->chanlist[chanidx].scantime) {
+ scandur =
+ puserscanin->chanlist[chanidx].scantime;
+ } else {
+ if (scantype == cmd_scan_type_passive) {
+ scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+ } else {
+ scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+ }
+ }
+
+ (pscanchanlist + chanidx)->minscantime =
+ cpu_to_le16(scandur);
+ (pscanchanlist + chanidx)->maxscantime =
+ cpu_to_le16(scandur);
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
+ ==
+ priv->adapter->curbssparams.channel)) {
+ *pscancurrentonly = 1;
+ lbs_pr_debug(1, "Scan: Scanning current channel only");
+ }
+
+ } else {
+ lbs_pr_debug(1, "Scan: Creating full region channel list\n");
+ wlan_scan_create_channel_list(priv, pscanchanlist,
+ *pfilteredscan);
+ }
+
+out:
+ return pscancfgout;
+}
+
+/**
+ * @brief Construct and send multiple scan config commands to the firmware
+ *
+ * Previous routines have created a wlan_scan_cmd_config with any requested
+ * TLVs. This function splits the channel TLV into maxchanperscan lists
+ * and sends the portion of the channel TLV along with the other TLVs
+ * to the wlan_cmd routines for execution in the firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param maxchanperscan Maximum number channels to be included in each
+ * scan command sent to firmware
+ * @param filteredscan Flag indicating whether or not a BSSID or SSID
+ * filter is being used for the firmware command
+ * scan command sent to firmware
+ * @param pscancfgout Scan configuration used for this scan.
+ * @param pchantlvout Pointer in the pscancfgout where the channel TLV
+ * should start. This is past any other TLVs that
+ * must be sent down in each firmware command.
+ * @param pscanchanlist List of channels to scan in maxchanperscan segments
+ *
+ * @return 0 or error return otherwise
+ */
+static int wlan_scan_channel_list(wlan_private * priv,
+ int maxchanperscan,
+ u8 filteredscan,
+ struct wlan_scan_cmd_config * pscancfgout,
+ struct mrvlietypes_chanlistparamset * pchantlvout,
+ struct chanscanparamset * pscanchanlist)
+{
+ struct chanscanparamset *ptmpchan;
+ struct chanscanparamset *pstartchan;
+ u8 scanband;
+ int doneearly;
+ int tlvidx;
+ int ret = 0;
+
+ ENTER();
+
+ if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
+ lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n",
+ pscancfgout, pchantlvout, pscanchanlist);
+ return -1;
+ }
+
+ pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired list */
+ ptmpchan = pscanchanlist;
+
+ /* Loop through the desired channel list, sending a new firmware scan
+ * commands for each maxchanperscan channels (or for 1,6,11 individually
+ * if configured accordingly)
+ */
+ while (ptmpchan->channumber) {
+
+ tlvidx = 0;
+ pchantlvout->header.len = 0;
+ scanband = ptmpchan->radiotype;
+ pstartchan = ptmpchan;
+ doneearly = 0;
+
+ /* Construct the channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlvidx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired channel list)
+ * - doneearly is set (controlling individual scanning of 1,6,11)
+ */
+ while (tlvidx < maxchanperscan && ptmpchan->channumber
+ && !doneearly) {
+
+ lbs_pr_debug(1,
+ "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
+ ptmpchan->channumber, ptmpchan->radiotype,
+ ptmpchan->chanscanmode.passivescan,
+ ptmpchan->chanscanmode.disablechanfilt,
+ ptmpchan->maxscantime);
+
+ /* Copy the current channel TLV to the command being prepared */
+ memcpy(pchantlvout->chanscanparam + tlvidx,
+ ptmpchan, sizeof(pchantlvout->chanscanparam));
+
+ /* Increment the TLV header length by the size appended */
+ pchantlvout->header.len +=
+ sizeof(pchantlvout->chanscanparam);
+
+ /*
+ * The tlv buffer length is set to the number of bytes of the
+ * between the channel tlv pointer and the start of the
+ * tlv buffer. This compensates for any TLVs that were appended
+ * before the channel list.
+ */
+ pscancfgout->tlvbufferlen = ((u8 *) pchantlvout
+ - pscancfgout->tlvbuffer);
+
+ /* Add the size of the channel tlv header and the data length */
+ pscancfgout->tlvbufferlen +=
+ (sizeof(pchantlvout->header)
+ + pchantlvout->header.len);
+
+ /* Increment the index to the channel tlv we are constructing */
+ tlvidx++;
+
+ doneearly = 0;
+
+ /* Stop the loop if the *current* channel is in the 1,6,11 set
+ * and we are not filtering on a BSSID or SSID.
+ */
+ if (!filteredscan && (ptmpchan->channumber == 1
+ || ptmpchan->channumber == 6
+ || ptmpchan->channumber == 11)) {
+ doneearly = 1;
+ }
+
+ /* Increment the tmp pointer to the next channel to be scanned */
+ ptmpchan++;
+
+ /* Stop the loop if the *next* channel is in the 1,6,11 set.
+ * This will cause it to be the only channel scanned on the next
+ * interation
+ */
+ if (!filteredscan && (ptmpchan->channumber == 1
+ || ptmpchan->channumber == 6
+ || ptmpchan->channumber == 11)) {
+ doneearly = 1;
+ }
+ }
+
+ /* Send the scan command to the firmware with the specified cfg */
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+ 0, 0, pscancfgout);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Internal function used to start a scan based on an input config
+ *
+ * Use the input user scan configuration information when provided in
+ * order to send the appropriate scan commands to firmware to populate or
+ * update the internal driver scan table
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param puserscanin Pointer to the input configuration for the requested
+ * scan.
+ *
+ * @return 0 or < 0 if error
+ */
+int wlan_scan_networks(wlan_private * priv,
+ const struct wlan_ioctl_user_scan_cfg * puserscanin)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct mrvlietypes_chanlistparamset *pchantlvout;
+ struct chanscanparamset * scan_chan_list = NULL;
+ struct wlan_scan_cmd_config * scan_cfg = NULL;
+ u8 keeppreviousscan;
+ u8 filteredscan;
+ u8 scancurrentchanonly;
+ int maxchanperscan;
+ int ret;
+
+ ENTER();
+
+ scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
+ WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
+ if (scan_chan_list == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ scan_cfg = wlan_scan_setup_scan_config(priv,
+ puserscanin,
+ &pchantlvout,
+ scan_chan_list,
+ &maxchanperscan,
+ &filteredscan,
+ &scancurrentchanonly);
+ if (scan_cfg == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ keeppreviousscan = 0;
+
+ if (puserscanin) {
+ keeppreviousscan = puserscanin->keeppreviousscan;
+ }
+
+ if (!keeppreviousscan) {
+ memset(adapter->scantable, 0x00,
+ sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST);
+ adapter->numinscantable = 0;
+ }
+
+ /* Keep the data path active if we are only scanning our current channel */
+ if (!scancurrentchanonly) {
+ netif_stop_queue(priv->wlan_dev.netdev);
+ netif_carrier_off(priv->wlan_dev.netdev);
+ }
+
+ ret = wlan_scan_channel_list(priv,
+ maxchanperscan,
+ filteredscan,
+ scan_cfg,
+ pchantlvout,
+ scan_chan_list);
+
+ /* Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ wlan_scan_process_results(priv);
+
+ if (priv->adapter->connect_status == libertas_connected) {
+ netif_carrier_on(priv->wlan_dev.netdev);
+ netif_wake_queue(priv->wlan_dev.netdev);
+ }
+
+out:
+ if (scan_cfg)
+ kfree(scan_cfg);
+
+ if (scan_chan_list)
+ kfree(scan_chan_list);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Inspect the scan response buffer for pointers to expected TLVs
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ * Parse the data in the buffer for pointers to TLVs that can potentially
+ * be passed back in the response
+ *
+ * @param ptlv Pointer to the start of the TLV buffer to parse
+ * @param tlvbufsize size of the TLV buffer
+ * @param ptsftlv Output parameter: Pointer to the TSF TLV if found
+ *
+ * @return void
+ */
+static
+void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
+ int tlvbufsize,
+ struct mrvlietypes_tsftimestamp ** ptsftlv)
+{
+ struct mrvlietypes_data *pcurrenttlv;
+ int tlvbufleft;
+ u16 tlvtype;
+ u16 tlvlen;
+
+ pcurrenttlv = ptlv;
+ tlvbufleft = tlvbufsize;
+ *ptsftlv = NULL;
+
+ lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
+ lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
+
+ while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
+ tlvtype = le16_to_cpu(pcurrenttlv->header.type);
+ tlvlen = le16_to_cpu(pcurrenttlv->header.len);
+
+ switch (tlvtype) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
+ break;
+
+ default:
+ lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n",
+ tlvtype);
+ /* Give up, this seems corrupted */
+ return;
+ } /* switch */
+
+ tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
+ pcurrenttlv =
+ (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
+ } /* while */
+}
+
+/**
+ * @brief Interpret a BSS scan response returned from the firmware
+ *
+ * Parse the various fixed fields and IEs passed back for a a BSS probe
+ * response or beacon from the scan command. Record information as needed
+ * in the scan table struct bss_descriptor for that entry.
+ *
+ * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry
+ *
+ * @return 0 or -1
+ */
+static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry,
+ u8 ** pbeaconinfo, int *bytesleft)
+{
+ enum ieeetypes_elementid elemID;
+ struct ieeetypes_fhparamset *pFH;
+ struct ieeetypes_dsparamset *pDS;
+ struct ieeetypes_cfparamset *pCF;
+ struct ieeetypes_ibssparamset *pibss;
+ struct ieeetypes_capinfo *pcap;
+ struct WLAN_802_11_FIXED_IEs fixedie;
+ u8 *pcurrentptr;
+ u8 *pRate;
+ u8 elemlen;
+ u8 bytestocopy;
+ u8 ratesize;
+ u16 beaconsize;
+ u8 founddatarateie;
+ int bytesleftforcurrentbeacon;
+
+ struct WPA_SUPPLICANT *pwpa_supplicant;
+ struct WPA_SUPPLICANT *pwpa2_supplicant;
+ struct IE_WPA *pIe;
+ const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
+
+ struct ieeetypes_countryinfoset *pcountryinfo;
+
+ ENTER();
+
+ founddatarateie = 0;
+ ratesize = 0;
+ beaconsize = 0;
+
+ if (*bytesleft >= sizeof(beaconsize)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize));
+ beaconsize = le16_to_cpu(beaconsize);
+ *bytesleft -= sizeof(beaconsize);
+ *pbeaconinfo += sizeof(beaconsize);
+ }
+
+ if (beaconsize == 0 || beaconsize > *bytesleft) {
+
+ *pbeaconinfo += *bytesleft;
+ *bytesleft = 0;
+
+ return -1;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS iteration */
+ pcurrentptr = *pbeaconinfo;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *pbeaconinfo += beaconsize;
+ *bytesleft -= beaconsize;
+
+ bytesleftforcurrentbeacon = beaconsize;
+
+ pwpa_supplicant = &pBSSEntry->wpa_supplicant;
+ pwpa2_supplicant = &pBSSEntry->wpa2_supplicant;
+
+ memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN);
+ lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n",
+ pBSSEntry->macaddress[0], pBSSEntry->macaddress[1],
+ pBSSEntry->macaddress[2], pBSSEntry->macaddress[3],
+ pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]);
+
+ pcurrentptr += ETH_ALEN;
+ bytesleftforcurrentbeacon -= ETH_ALEN;
+
+ if (bytesleftforcurrentbeacon < 12) {
+ lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n");
+ return -1;
+ }
+
+ /*
+ * next 4 fields are RSSI, time stamp, beacon interval,
+ * and capability information
+ */
+
+ /* RSSI is 1 byte long */
+ pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr));
+ lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr);
+ pcurrentptr += 1;
+ bytesleftforcurrentbeacon -= 1;
+
+ /* time stamp is 8 bytes long */
+ memcpy(fixedie.timestamp, pcurrentptr, 8);
+ memcpy(pBSSEntry->timestamp, pcurrentptr, 8);
+ pcurrentptr += 8;
+ bytesleftforcurrentbeacon -= 8;
+
+ /* beacon interval is 2 bytes long */
+ memcpy(&fixedie.beaconinterval, pcurrentptr, 2);
+ pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval);
+ pcurrentptr += 2;
+ bytesleftforcurrentbeacon -= 2;
+
+ /* capability information is 2 bytes long */
+ memcpy(&fixedie.capabilities, pcurrentptr, 2);
+ lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n",
+ fixedie.capabilities);
+ fixedie.capabilities = le16_to_cpu(fixedie.capabilities);
+ pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
+ memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo));
+ pcurrentptr += 2;
+ bytesleftforcurrentbeacon -= 2;
+
+ /* rest of the current buffer are IE's */
+ lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n",
+ bytesleftforcurrentbeacon);
+
+ lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr,
+ bytesleftforcurrentbeacon);
+
+ if (pcap->privacy) {
+ lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n");
+ pBSSEntry->privacy = wlan802_11privfilter8021xWEP;
+ } else {
+ pBSSEntry->privacy = wlan802_11privfilteracceptall;
+ }
+
+ if (pcap->ibss == 1) {
+ pBSSEntry->inframode = wlan802_11ibss;
+ } else {
+ pBSSEntry->inframode = wlan802_11infrastructure;
+ }
+
+ /* process variable IE */
+ while (bytesleftforcurrentbeacon >= 2) {
+ elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
+ elemlen = *((u8 *) pcurrentptr + 1);
+
+ if (bytesleftforcurrentbeacon < elemlen) {
+ lbs_pr_debug(1, "InterpretIE: error in processing IE, "
+ "bytes left < IE length\n");
+ bytesleftforcurrentbeacon = 0;
+ continue;
+ }
+
+ switch (elemID) {
+
+ case SSID:
+ pBSSEntry->ssid.ssidlength = elemlen;
+ memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2),
+ elemlen);
+ lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid);
+ break;
+
+ case SUPPORTED_RATES:
+ memcpy(pBSSEntry->datarates, (pcurrentptr + 2),
+ elemlen);
+ memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2),
+ elemlen);
+ ratesize = elemlen;
+ founddatarateie = 1;
+ break;
+
+ case EXTRA_IE:
+ lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n");
+ pBSSEntry->extra_ie = 1;
+ break;
+
+ case FH_PARAM_SET:
+ pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+ memmove(&pBSSEntry->phyparamset.fhparamset, pFH,
+ sizeof(struct ieeetypes_fhparamset));
+ pBSSEntry->phyparamset.fhparamset.dwelltime
+ =
+ le16_to_cpu(pBSSEntry->phyparamset.fhparamset.
+ dwelltime);
+ break;
+
+ case DS_PARAM_SET:
+ pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+
+ pBSSEntry->channel = pDS->currentchan;
+
+ memcpy(&pBSSEntry->phyparamset.dsparamset, pDS,
+ sizeof(struct ieeetypes_dsparamset));
+ break;
+
+ case CF_PARAM_SET:
+ pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+
+ memcpy(&pBSSEntry->ssparamset.cfparamset, pCF,
+ sizeof(struct ieeetypes_cfparamset));
+ break;
+
+ case IBSS_PARAM_SET:
+ pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+ pBSSEntry->atimwindow =
+ le32_to_cpu(pibss->atimwindow);
+
+ memmove(&pBSSEntry->ssparamset.ibssparamset, pibss,
+ sizeof(struct ieeetypes_ibssparamset));
+
+ pBSSEntry->ssparamset.ibssparamset.atimwindow
+ =
+ le16_to_cpu(pBSSEntry->ssparamset.ibssparamset.
+ atimwindow);
+ break;
+
+ /* Handle Country Info IE */
+ case COUNTRY_INFO:
+ pcountryinfo =
+ (struct ieeetypes_countryinfoset *) pcurrentptr;
+
+ if (pcountryinfo->len <
+ sizeof(pcountryinfo->countrycode)
+ || pcountryinfo->len > 254) {
+ lbs_pr_debug(1, "InterpretIE: 11D- Err "
+ "CountryInfo len =%d min=%d max=254\n",
+ pcountryinfo->len,
+ sizeof(pcountryinfo->countrycode));
+ LEAVE();
+ return -1;
+ }
+
+ memcpy(&pBSSEntry->countryinfo,
+ pcountryinfo, pcountryinfo->len + 2);
+ lbs_dbg_hex("InterpretIE: 11D- CountryInfo:",
+ (u8 *) pcountryinfo,
+ (u32) (pcountryinfo->len + 2));
+ break;
+
+ case EXTENDED_SUPPORTED_RATES:
+ /*
+ * only process extended supported rate
+ * if data rate is already found.
+ * data rate IE should come before
+ * extended supported rate IE
+ */
+ if (founddatarateie) {
+ if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
+ bytestocopy =
+ (WLAN_SUPPORTED_RATES - ratesize);
+ } else {
+ bytestocopy = elemlen;
+ }
+
+ pRate = (u8 *) pBSSEntry->datarates;
+ pRate += ratesize;
+ memmove(pRate, (pcurrentptr + 2), bytestocopy);
+
+ pRate = (u8 *) pBSSEntry->libertas_supported_rates;
+
+ pRate += ratesize;
+ memmove(pRate, (pcurrentptr + 2), bytestocopy);
+ }
+ break;
+
+ case VENDOR_SPECIFIC_221:
+#define IE_ID_LEN_FIELDS_BYTES 2
+ pIe = (struct IE_WPA *)pcurrentptr;
+
+ if (!memcmp(pIe->oui, oui01, sizeof(oui01))) {
+ pwpa_supplicant->wpa_ie_len
+ = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+ sizeof(pwpa_supplicant->wpa_ie));
+ memcpy(pwpa_supplicant->wpa_ie,
+ pcurrentptr,
+ pwpa_supplicant->wpa_ie_len);
+ lbs_dbg_hex("InterpretIE: Resp WPA_IE",
+ pwpa_supplicant->wpa_ie, elemlen);
+ }
+ break;
+ case WPA2_IE:
+ pIe = (struct IE_WPA *)pcurrentptr;
+ pwpa2_supplicant->wpa_ie_len
+ = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES,
+ sizeof(pwpa2_supplicant->wpa_ie));
+ memcpy(pwpa2_supplicant->wpa_ie,
+ pcurrentptr, pwpa2_supplicant->wpa_ie_len);
+
+ lbs_dbg_hex("InterpretIE: Resp WPA2_IE",
+ pwpa2_supplicant->wpa_ie, elemlen);
+ break;
+ case TIM:
+ break;
+
+ case CHALLENGE_TEXT:
+ break;
+ }
+
+ pcurrentptr += elemlen + 2;
+
+ /* need to account for IE ID and IE len */
+ bytesleftforcurrentbeacon -= (elemlen + 2);
+
+ } /* while (bytesleftforcurrentbeacon > 2) */
+
+ return 0;
+}
+
+/**
+ * @brief Compare two SSIDs
+ *
+ * @param ssid1 A pointer to ssid to compare
+ * @param ssid2 A pointer to ssid to compare
+ *
+ * @return 0--ssid is same, otherwise is different
+ */
+int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2)
+{
+ if (!ssid1 || !ssid2)
+ return -1;
+
+ if (ssid1->ssidlength != ssid2->ssidlength)
+ return -1;
+
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength);
+}
+
+/**
+ * @brief This function finds a specific compatible BSSID in the scan list
+ *
+ * @param adapter A pointer to wlan_adapter
+ * @param bssid BSSID to find in the scan list
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list, or error return code (< 0)
+ */
+int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode)
+{
+ int ret = -ENETUNREACH;
+ int i;
+
+ if (!bssid)
+ return -EFAULT;
+
+ lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n",
+ adapter->numinscantable);
+
+ /* Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. The loop will continue
+ * past a matched bssid that is not compatible in case there is an
+ * AP with multiple SSIDs assigned to the same BSSID
+ */
+ for (i = 0; ret < 0 && i < adapter->numinscantable; i++) {
+ if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) {
+ switch (mode) {
+ case wlan802_11infrastructure:
+ case wlan802_11ibss:
+ ret = is_network_compatible(adapter, i, mode);
+ break;
+ default:
+ ret = i;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * @brief This function finds ssid in ssid list.
+ *
+ * @param adapter A pointer to wlan_adapter
+ * @param ssid SSID to find in the list
+ * @param bssid BSSID to qualify the SSID selection (if provided)
+ * @param mode Network mode: Infrastructure or IBSS
+ *
+ * @return index in BSSID list
+ */
+int libertas_find_SSID_in_list(wlan_adapter * adapter,
+ struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode)
+{
+ int net = -ENETUNREACH;
+ u8 bestrssi = 0;
+ int i;
+ int j;
+
+ lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable);
+
+ for (i = 0; i < adapter->numinscantable; i++) {
+ if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) &&
+ (!bssid ||
+ !memcmp(adapter->scantable[i].
+ macaddress, bssid, ETH_ALEN))) {
+ switch (mode) {
+ case wlan802_11infrastructure:
+ case wlan802_11ibss:
+ j = is_network_compatible(adapter, i, mode);
+
+ if (j >= 0) {
+ if (bssid) {
+ return i;
+ }
+
+ if (SCAN_RSSI
+ (adapter->scantable[i].rssi)
+ > bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->
+ scantable[i].
+ rssi);
+ net = i;
+ }
+ } else {
+ if (net == -ENETUNREACH) {
+ net = j;
+ }
+ }
+ break;
+ case wlan802_11autounknown:
+ default:
+ if (SCAN_RSSI(adapter->scantable[i].rssi)
+ > bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->scantable[i].
+ rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ return net;
+}
+
+/**
+ * @brief This function finds the best SSID in the Scan List
+ *
+ * Search the scan table for the best SSID that also matches the current
+ * adapter network preference (infrastructure or adhoc)
+ *
+ * @param adapter A pointer to wlan_adapter
+ *
+ * @return index in BSSID list
+ */
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode)
+{
+ int bestnet = -ENETUNREACH;
+ u8 bestrssi = 0;
+ int i;
+
+ ENTER();
+
+ lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable);
+
+ for (i = 0; i < adapter->numinscantable; i++) {
+ switch (mode) {
+ case wlan802_11infrastructure:
+ case wlan802_11ibss:
+ if (is_network_compatible(adapter, i, mode) >= 0) {
+ if (SCAN_RSSI(adapter->scantable[i].rssi) >
+ bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->scantable[i].
+ rssi);
+ bestnet = i;
+ }
+ }
+ break;
+ case wlan802_11autounknown:
+ default:
+ if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) {
+ bestrssi =
+ SCAN_RSSI(adapter->scantable[i].rssi);
+ bestnet = i;
+ }
+ break;
+ }
+ }
+
+ LEAVE();
+ return bestnet;
+}
+
+/**
+ * @brief Find the AP with specific ssid in the scan list
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param pSSID A pointer to AP's ssid
+ *
+ * @return 0--success, otherwise--fail
+ */
+int libertas_find_best_network_SSID(wlan_private * priv,
+ struct WLAN_802_11_SSID *pSSID,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct bss_descriptor *preqbssid;
+ int i;
+
+ ENTER();
+
+ memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID));
+
+ wlan_scan_networks(priv, NULL);
+ if (adapter->surpriseremoved)
+ return -1;
+ wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+ i = libertas_find_best_SSID_in_list(adapter, preferred_mode);
+ if (i < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ preqbssid = &adapter->scantable[i];
+ memcpy(pSSID, &preqbssid->ssid,
+ sizeof(struct WLAN_802_11_SSID));
+ *out_mode = preqbssid->inframode;
+
+ if (!pSSID->ssidlength) {
+ ret = -1;
+ }
+
+out:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Scan Network
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ union iwreq_data wrqu;
+
+ ENTER();
+
+ if (!wlan_scan_networks(priv, NULL)) {
+ memset(&wrqu, 0, sizeof(union iwreq_data));
+ wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu,
+ NULL);
+ }
+
+ if (adapter->surpriseremoved)
+ return -1;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Send a scan command for all available channels filtered on a spec
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param prequestedssid A pointer to AP's ssid
+ * @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ * @return 0-success, otherwise fail
+ */
+int libertas_send_specific_SSID_scan(wlan_private * priv,
+ struct WLAN_802_11_SSID *prequestedssid,
+ u8 keeppreviousscan)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct wlan_ioctl_user_scan_cfg scancfg;
+
+ ENTER();
+
+ if (prequestedssid == NULL) {
+ return -1;
+ }
+
+ memset(&scancfg, 0x00, sizeof(scancfg));
+
+ memcpy(scancfg.specificSSID, prequestedssid->ssid,
+ prequestedssid->ssidlength);
+ scancfg.keeppreviousscan = keeppreviousscan;
+
+ wlan_scan_networks(priv, &scancfg);
+ if (adapter->surpriseremoved)
+ return -1;
+ wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief scan an AP with specific BSSID
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param bssid A pointer to AP's bssid
+ * @param keeppreviousscan Flag used to save/clear scan table before scan
+ *
+ * @return 0-success, otherwise fail
+ */
+int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan)
+{
+ struct wlan_ioctl_user_scan_cfg scancfg;
+
+ ENTER();
+
+ if (bssid == NULL) {
+ return -1;
+ }
+
+ memset(&scancfg, 0x00, sizeof(scancfg));
+ memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID));
+ scancfg.keeppreviousscan = keeppreviousscan;
+
+ wlan_scan_networks(priv, &scancfg);
+ if (priv->adapter->surpriseremoved)
+ return -1;
+ wait_event_interruptible(priv->adapter->cmd_pending,
+ !priv->adapter->nr_cmd_pending);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Retrieve the scan table entries via wireless tools IOCTL call
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param dwrq A pointer to iw_point structure
+ * @param extra A pointer to extra data buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ char *current_ev = extra;
+ char *end_buf = extra + IW_SCAN_MAX_DATA;
+ struct chan_freq_power *cfp;
+ struct bss_descriptor *pscantable;
+ char *current_val; /* For rates */
+ struct iw_event iwe; /* Temporary buffer */
+ int i;
+ int j;
+ int rate;
+#define PERFECT_RSSI ((u8)50)
+#define WORST_RSSI ((u8)0)
+#define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI))
+ u8 rssi;
+
+ u8 buf[16 + 256 * 2];
+ u8 *ptr;
+
+ ENTER();
+
+ /*
+ * if there's either commands in the queue or one being
+ * processed return -EAGAIN for iwlist to retry later.
+ */
+ if (adapter->nr_cmd_pending)
+ return -EAGAIN;
+
+ if (adapter->connect_status == libertas_connected)
+ lbs_pr_debug(1, "Current ssid: %32s\n",
+ adapter->curbssparams.ssid.ssid);
+
+ lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n",
+ adapter->numinscantable);
+
+ /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP.
+ * The new API using SIOCGIWSCAN is only limited by buffer size
+ * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes
+ * which is 4096.
+ */
+ for (i = 0; i < adapter->numinscantable; i++) {
+ if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) {
+ lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p "
+ "MAX_SCAN_CELL_SIZE=%d\n",
+ i, current_ev, end_buf, MAX_SCAN_CELL_SIZE);
+ break;
+ }
+
+ pscantable = &adapter->scantable[i];
+
+ lbs_pr_debug(1, "i=%d ssid: %32s\n", i, pscantable->ssid.ssid);
+
+ cfp =
+ libertas_find_cfp_by_band_and_channel(adapter, 0,
+ pscantable->channel);
+ if (!cfp) {
+ lbs_pr_debug(1, "Invalid channel number %d\n",
+ pscantable->channel);
+ continue;
+ }
+
+ if (!ssid_valid(&adapter->scantable[i].ssid)) {
+ continue;
+ }
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data,
+ &adapter->scantable[i].macaddress, ETH_ALEN);
+
+ iwe.len = IW_EV_ADDR_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ //Add the ESSID
+ iwe.u.data.length = adapter->scantable[i].ssid.ssidlength;
+
+ if (iwe.u.data.length > 32) {
+ iwe.u.data.length = 32;
+ }
+
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ adapter->scantable[i].ssid.
+ ssid);
+
+ //Add mode
+ iwe.cmd = SIOCGIWMODE;
+ iwe.u.mode = adapter->scantable[i].inframode + 1;
+ iwe.len = IW_EV_UINT_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ //frequency
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = (long)cfp->freq * 100000;
+ iwe.u.freq.e = 1;
+ iwe.len = IW_EV_FREQ_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;
+ iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi);
+
+ rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ iwe.u.qual.qual =
+ (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *
+ (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /
+ (RSSI_DIFF * RSSI_DIFF);
+ if (iwe.u.qual.qual > 100)
+ iwe.u.qual.qual = 100;
+ else if (iwe.u.qual.qual < 1)
+ iwe.u.qual.qual = 0;
+
+ if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+ iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ iwe.u.qual.noise =
+ CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+ }
+ if ((adapter->inframode == wlan802_11ibss) &&
+ !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+ &adapter->scantable[i].ssid)
+ && adapter->adhoccreate) {
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rssi,
+ 0,
+ cmd_option_waitforrsp,
+ 0, NULL);
+
+ if (!ret) {
+ iwe.u.qual.level =
+ CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] /
+ AVG_SCALE,
+ adapter->NF[TYPE_RXPD][TYPE_AVG] /
+ AVG_SCALE);
+ }
+ }
+ iwe.len = IW_EV_QUAL_LEN;
+ current_ev =
+ iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len);
+
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (adapter->scantable[i].privacy) {
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ } else {
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ }
+ iwe.u.data.length = 0;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ adapter->scantable->ssid.
+ ssid);
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ iwe.cmd = SIOCGIWRATE;
+
+ iwe.u.bitrate.fixed = 0;
+ iwe.u.bitrate.disabled = 0;
+ iwe.u.bitrate.value = 0;
+
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates);
+ j++) {
+ if (adapter->scantable[i].libertas_supported_rates[j] == 0) {
+ break;
+ }
+ rate =
+ (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) *
+ 500000;
+ if (rate > iwe.u.bitrate.value) {
+ iwe.u.bitrate.value = rate;
+ }
+
+ iwe.u.bitrate.value =
+ (adapter->scantable[i].libertas_supported_rates[j]
+ & 0x7f) * 500000;
+ iwe.len = IW_EV_PARAM_LEN;
+ current_ev =
+ iwe_stream_add_value(current_ev, current_val,
+ end_buf, &iwe, iwe.len);
+
+ }
+ if ((adapter->scantable[i].inframode == wlan802_11ibss)
+ && !libertas_SSID_cmp(&adapter->curbssparams.ssid,
+ &adapter->scantable[i].ssid)
+ && adapter->adhoccreate) {
+ iwe.u.bitrate.value = 22 * 500000;
+ }
+ iwe.len = IW_EV_PARAM_LEN;
+ current_ev =
+ iwe_stream_add_value(current_ev, current_val, end_buf, &iwe,
+ iwe.len);
+
+ /* Add new value to event */
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) {
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, adapter->scantable[i].
+ wpa2_supplicant.wpa_ie,
+ adapter->scantable[i].wpa2_supplicant.
+ wpa_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = adapter->scantable[i].
+ wpa2_supplicant.wpa_ie_len;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ }
+ if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) {
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, adapter->scantable[i].
+ wpa_supplicant.wpa_ie,
+ adapter->scantable[i].wpa_supplicant.
+ wpa_ie_len);
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = adapter->scantable[i].
+ wpa_supplicant.wpa_ie_len;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ }
+
+
+ if (adapter->scantable[i].extra_ie != 0) {
+ memset(&iwe, 0, sizeof(iwe));
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+ ptr += sprintf(ptr, "extra_ie");
+ iwe.u.data.length = strlen(buf);
+
+ lbs_pr_debug(1, "iwe.u.data.length %d\n",
+ iwe.u.data.length);
+ lbs_pr_debug(1, "BUF: %s \n", buf);
+
+ iwe.cmd = IWEVCUSTOM;
+ iwe.len = IW_EV_POINT_LEN + iwe.u.data.length;
+ current_ev =
+ iwe_stream_add_point(current_ev, end_buf, &iwe,
+ buf);
+ }
+
+ current_val = current_ev + IW_EV_LCP_LEN;
+
+ /*
+ * Check if we added any event
+ */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
+
+ dwrq->length = (current_ev - extra);
+ dwrq->flags = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Prepare a scan command to be sent to the firmware
+ *
+ * Use the wlan_scan_cmd_config sent to the command processing module in
+ * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
+ * struct to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param cmd A pointer to cmd_ds_command structure to be sent to
+ * firmware with the cmd_DS_801_11_SCAN structure
+ * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used
+ * to set the fields/TLVs for the command sent to firmware
+ *
+ * @return 0 or -1
+ *
+ * @sa wlan_scan_create_channel_list
+ */
+int libertas_cmd_80211_scan(wlan_private * priv,
+ struct cmd_ds_command *cmd, void *pdata_buf)
+{
+ struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
+ struct wlan_scan_cmd_config *pscancfg;
+
+ ENTER();
+
+ pscancfg = pdata_buf;
+
+ /* Set fixed field variables in scan command */
+ pscan->bsstype = pscancfg->bsstype;
+ memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID));
+ memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
+
+ cmd->command = cpu_to_le16(cmd_802_11_scan);
+
+ /* size is equal to the sizeof(fixed portions) + the TLV len + header */
+ cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
+ + sizeof(pscan->BSSID)
+ + pscancfg->tlvbufferlen + S_DS_GEN);
+
+ lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+ cmd->command, cmd->size, cmd->seqnum);
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief This function handles the command response of scan
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-----------------------------------------------------------.
+ * | header (4 * sizeof(u16)): Standard command response hdr |
+ * .-----------------------------------------------------------.
+ * | bufsize (u16) : sizeof the BSS Description data |
+ * .-----------------------------------------------------------.
+ * | NumOfSet (u8) : Number of BSS Descs returned |
+ * .-----------------------------------------------------------.
+ * | BSSDescription data (variable, size given in bufsize) |
+ * .-----------------------------------------------------------.
+ * | TLV data (variable, size calculated using header->size, |
+ * | bufsize and sizeof the fixed fields above) |
+ * .-----------------------------------------------------------.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param resp A pointer to cmd_ds_command
+ *
+ * @return 0 or -1
+ */
+int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct cmd_ds_802_11_scan_rsp *pscan;
+ struct bss_descriptor newbssentry;
+ struct mrvlietypes_data *ptlv;
+ struct mrvlietypes_tsftimestamp *ptsftlv;
+ u8 *pbssinfo;
+ u16 scanrespsize;
+ int bytesleft;
+ int numintable;
+ int bssIdx;
+ int idx;
+ int tlvbufsize;
+ u64 tsfval;
+
+ ENTER();
+
+ pscan = &resp->params.scanresp;
+
+ if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) {
+ lbs_pr_debug(1,
+ "SCAN_RESP: Invalid number of AP returned (%d)!!\n",
+ pscan->nr_sets);
+ LEAVE();
+ return -1;
+ }
+
+ bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+ lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft);
+
+ scanrespsize = le16_to_cpu(resp->size);
+ lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n",
+ pscan->nr_sets);
+
+ numintable = adapter->numinscantable;
+ pbssinfo = pscan->bssdesc_and_tlvbuffer;
+
+ /* The size of the TLV buffer is equal to the entire command response
+ * size (scanrespsize) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bssdescriptsize as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize)
+ + sizeof(pscan->nr_sets)
+ + S_DS_GEN);
+
+ ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
+
+ /* Search the TLV buffer space in the scan response for any valid TLVs */
+ wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
+
+ /*
+ * Process each scan response returned (pscan->nr_sets). Save
+ * the information in the newbssentry and then insert into the
+ * driver scan table either as an update to an existing entry
+ * or as an addition at the end of the table
+ */
+ for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) {
+ /* Zero out the newbssentry we are about to store info in */
+ memset(&newbssentry, 0x00, sizeof(newbssentry));
+
+ /* Process the data fields and IEs returned for this BSS */
+ if ((InterpretBSSDescriptionWithIE(&newbssentry,
+ &pbssinfo,
+ &bytesleft) ==
+ 0)
+ && CHECK_SSID_IS_VALID(&newbssentry.ssid)) {
+
+ lbs_pr_debug(1,
+ "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ newbssentry.macaddress[0],
+ newbssentry.macaddress[1],
+ newbssentry.macaddress[2],
+ newbssentry.macaddress[3],
+ newbssentry.macaddress[4],
+ newbssentry.macaddress[5]);
+
+ /*
+ * Search the scan table for the same bssid
+ */
+ for (bssIdx = 0; bssIdx < numintable; bssIdx++) {
+ if (memcmp(newbssentry.macaddress,
+ adapter->scantable[bssIdx].
+ macaddress,
+ sizeof(newbssentry.macaddress)) ==
+ 0) {
+ /*
+ * If the SSID matches as well, it is a duplicate of
+ * this entry. Keep the bssIdx set to this
+ * entry so we replace the old contents in the table
+ */
+ if ((newbssentry.ssid.ssidlength ==
+ adapter->scantable[bssIdx].ssid.
+ ssidlength)
+ &&
+ (memcmp
+ (newbssentry.ssid.ssid,
+ adapter->scantable[bssIdx].ssid.
+ ssid,
+ newbssentry.ssid.ssidlength) ==
+ 0)) {
+ lbs_pr_debug(1,
+ "SCAN_RESP: Duplicate of index: %d\n",
+ bssIdx);
+ break;
+ }
+ }
+ }
+ /*
+ * If the bssIdx is equal to the number of entries in the table,
+ * the new entry was not a duplicate; append it to the scan
+ * table
+ */
+ if (bssIdx == numintable) {
+ /* Range check the bssIdx, keep it limited to the last entry */
+ if (bssIdx == MRVDRV_MAX_BSSID_LIST) {
+ bssIdx--;
+ } else {
+ numintable++;
+ }
+ }
+
+ /*
+ * If the TSF TLV was appended to the scan results, save the
+ * this entries TSF value in the networktsf field. The
+ * networktsf is the firmware's TSF value at the time the
+ * beacon or probe response was received.
+ */
+ if (ptsftlv) {
+ memcpy(&tsfval, &ptsftlv->tsftable[idx],
+ sizeof(tsfval));
+ tsfval = le64_to_cpu(tsfval);
+
+ memcpy(&newbssentry.networktsf,
+ &tsfval, sizeof(newbssentry.networktsf));
+ }
+
+ /* Copy the locally created newbssentry to the scan table */
+ memcpy(&adapter->scantable[bssIdx],
+ &newbssentry,
+ sizeof(adapter->scantable[bssIdx]));
+
+ } else {
+
+ /* error parsing/interpreting the scan response, skipped */
+ lbs_pr_debug(1, "SCAN_RESP: "
+ "InterpretBSSDescriptionWithIE returned ERROR\n");
+ }
+ }
+
+ lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ pscan->nr_sets, numintable - adapter->numinscantable,
+ numintable);
+
+ /* Update the total number of BSSIDs in the scan table */
+ adapter->numinscantable = numintable;
+
+ LEAVE();
+ return 0;
+}
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
new file mode 100644
index 00000000000..d93aa7fa44f
--- /dev/null
+++ b/drivers/net/wireless/libertas/scan.h
@@ -0,0 +1,216 @@
+/* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
+/* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */
+
+/**
+ * Interface for the wlan network scan routines
+ *
+ * Driver interface functions and type declarations for the scan module
+ * implemented in wlan_scan.c.
+ */
+#ifndef _WLAN_SCAN_H
+#define _WLAN_SCAN_H
+
+#include "hostcmd.h"
+
+/**
+ * @brief Maximum number of channels that can be sent in a setuserscan ioctl
+ *
+ * @sa wlan_ioctl_user_scan_cfg
+ */
+#define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50
+
+//! Infrastructure BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_BSS 1
+
+//! Adhoc BSS scan type in wlan_scan_cmd_config
+#define WLAN_SCAN_BSS_TYPE_IBSS 2
+
+//! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter
+#define WLAN_SCAN_BSS_TYPE_ANY 3
+
+/**
+ * @brief Structure used internally in the wlan driver to configure a scan.
+ *
+ * Sent to the command processing module to configure the firmware
+ * scan command prepared by libertas_cmd_80211_scan.
+ *
+ * @sa wlan_scan_networks
+ *
+ */
+struct wlan_scan_cmd_config {
+ /**
+ * @brief BSS type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. valid settings are:
+ *
+ * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
+ * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+ * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ u8 bsstype;
+
+ /**
+ * @brief Specific BSSID used to filter scan results in the firmware
+ */
+ u8 specificBSSID[ETH_ALEN];
+
+ /**
+ * @brief length of TLVs sent in command starting at tlvBuffer
+ */
+ int tlvbufferlen;
+
+ /**
+ * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t
+ * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t
+ */
+ u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here
+};
+
+/**
+ * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg
+ *
+ * Multiple instances of this structure are included in the IOCTL command
+ * to configure a instance of a scan on the specific channel.
+ */
+struct wlan_ioctl_user_scan_chan {
+ u8 channumber; //!< channel Number to scan
+ u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1
+ u8 scantype; //!< Scan type: Active = 0, Passive = 1
+ u16 scantime; //!< Scan duration in milliseconds; if 0 default used
+};
+
+/**
+ * @brief IOCTL input structure to configure an immediate scan cmd to firmware
+ *
+ * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies
+ * a number of parameters to be used in general for the scan as well
+ * as a channel list (wlan_ioctl_user_scan_chan) for each scan period
+ * desired.
+ *
+ * @sa libertas_set_user_scan_ioctl
+ */
+struct wlan_ioctl_user_scan_cfg {
+
+ /**
+ * @brief Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ u8 keeppreviousscan; //!< Do not erase the existing scan results
+
+ /**
+ * @brief BSS type to be sent in the firmware command
+ *
+ * Field can be used to restrict the types of networks returned in the
+ * scan. valid settings are:
+ *
+ * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure)
+ * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc)
+ * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure)
+ */
+ u8 bsstype;
+
+ /**
+ * @brief Configure the number of probe requests for active chan scans
+ */
+ u8 numprobes;
+
+ /**
+ * @brief BSSID filter sent in the firmware command to limit the results
+ */
+ u8 specificBSSID[ETH_ALEN];
+
+ /**
+ * @brief SSID filter sent in the firmware command to limit the results
+ */
+ char specificSSID[IW_ESSID_MAX_SIZE + 1];
+
+ /**
+ * @brief Variable number (fixed maximum) of channels to scan up
+ */
+ struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX];
+};
+
+/**
+ * @brief Structure used to store information for each beacon/probe response
+ */
+struct bss_descriptor {
+ u8 macaddress[ETH_ALEN];
+
+ struct WLAN_802_11_SSID ssid;
+
+ /* WEP encryption requirement */
+ u32 privacy;
+
+ /* receive signal strength in dBm */
+ long rssi;
+
+ u32 channel;
+
+ u16 beaconperiod;
+
+ u32 atimwindow;
+
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode;
+ u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
+
+ int extra_ie;
+
+ u8 timestamp[8]; //!< TSF value included in the beacon/probe response
+ union ieeetypes_phyparamset phyparamset;
+ union IEEEtypes_ssparamset ssparamset;
+ struct ieeetypes_capinfo cap;
+ u8 datarates[WLAN_SUPPORTED_RATES];
+
+ __le64 networktsf; //!< TSF timestamp from the current firmware TSF
+
+ struct ieeetypes_countryinfofullset countryinfo;
+
+ struct WPA_SUPPLICANT wpa_supplicant;
+ struct WPA_SUPPLICANT wpa2_supplicant;
+
+};
+
+extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1,
+ struct WLAN_802_11_SSID *ssid2);
+extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid,
+ u8 * bssid, int mode);
+int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode);
+extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode);
+
+int libertas_find_best_network_SSID(wlan_private * priv,
+ struct WLAN_802_11_SSID *pSSID,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode,
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode);
+
+extern int libertas_send_specific_SSID_scan(wlan_private * priv,
+ struct WLAN_802_11_SSID *prequestedssid,
+ u8 keeppreviousscan);
+extern int libertas_send_specific_BSSID_scan(wlan_private * priv,
+ u8 * bssid, u8 keeppreviousscan);
+
+extern int libertas_cmd_80211_scan(wlan_private * priv,
+ struct cmd_ds_command *cmd,
+ void *pdata_buf);
+
+extern int libertas_ret_80211_scan(wlan_private * priv,
+ struct cmd_ds_command *resp);
+
+int wlan_scan_networks(wlan_private * priv,
+ const struct wlan_ioctl_user_scan_cfg * puserscanin);
+
+struct ifreq;
+
+struct iw_point;
+struct iw_param;
+struct iw_request_info;
+extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra);
+extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra);
+
+#endif /* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
new file mode 100644
index 00000000000..207b8a6cc33
--- /dev/null
+++ b/drivers/net/wireless/libertas/thread.h
@@ -0,0 +1,52 @@
+#ifndef __WLAN_THREAD_H_
+#define __WLAN_THREAD_H_
+
+#include <linux/kthread.h>
+
+struct wlan_thread {
+ struct task_struct *task;
+ wait_queue_head_t waitq;
+ pid_t pid;
+ void *priv;
+};
+
+static inline void wlan_activate_thread(struct wlan_thread * thr)
+{
+ /** Record the thread pid */
+ thr->pid = current->pid;
+
+ /** Initialize the wait queue */
+ init_waitqueue_head(&thr->waitq);
+}
+
+static inline void wlan_deactivate_thread(struct wlan_thread * thr)
+{
+ ENTER();
+
+ thr->pid = 0;
+
+ LEAVE();
+}
+
+static inline void wlan_create_thread(int (*wlanfunc) (void *),
+ struct wlan_thread * thr, char *name)
+{
+ thr->task = kthread_run(wlanfunc, thr, "%s", name);
+}
+
+static inline int wlan_terminate_thread(struct wlan_thread * thr)
+{
+ ENTER();
+
+ /* Check if the thread is active or not */
+ if (!thr->pid) {
+ printk(KERN_ERR "Thread does not exist\n");
+ return -1;
+ }
+ kthread_stop(thr->task);
+
+ LEAVE();
+ return 0;
+}
+
+#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
new file mode 100644
index 00000000000..82d06223043
--- /dev/null
+++ b/drivers/net/wireless/libertas/tx.c
@@ -0,0 +1,285 @@
+/**
+ * This file contains the handling of TX in wlan driver.
+ */
+#include <linux/netdevice.h>
+
+#include "hostcmd.h"
+#include "radiotap.h"
+#include "sbi.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "wext.h"
+
+/**
+ * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ *
+ * @param rate Input rate
+ * @return Output Rate (0 if invalid)
+ */
+static u32 convert_radiotap_rate_to_mv(u8 rate)
+{
+ switch (rate) {
+ case 2: /* 1 Mbps */
+ return 0 | (1 << 4);
+ case 4: /* 2 Mbps */
+ return 1 | (1 << 4);
+ case 11: /* 5.5 Mbps */
+ return 2 | (1 << 4);
+ case 22: /* 11 Mbps */
+ return 3 | (1 << 4);
+ case 12: /* 6 Mbps */
+ return 4 | (1 << 4);
+ case 18: /* 9 Mbps */
+ return 5 | (1 << 4);
+ case 24: /* 12 Mbps */
+ return 6 | (1 << 4);
+ case 36: /* 18 Mbps */
+ return 7 | (1 << 4);
+ case 48: /* 24 Mbps */
+ return 8 | (1 << 4);
+ case 72: /* 36 Mbps */
+ return 9 | (1 << 4);
+ case 96: /* 48 Mbps */
+ return 10 | (1 << 4);
+ case 108: /* 54 Mbps */
+ return 11 | (1 << 4);
+ }
+ return 0;
+}
+
+/**
+ * @brief This function processes a single packet and sends
+ * to IF layer
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param skb A pointer to skb which includes TX packet
+ * @return 0 or -1
+ */
+static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct txpd localtxpd;
+ struct txpd *plocaltxpd = &localtxpd;
+ u8 *p802x_hdr;
+ struct tx_radiotap_hdr *pradiotap_hdr;
+ u32 new_rate;
+ u8 *ptr = priv->adapter->tmptxbuf;
+
+ ENTER();
+
+ if (priv->adapter->surpriseremoved)
+ return -1;
+
+ if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+ lbs_dbg_hex("TX packet: ", skb->data,
+ min_t(unsigned int, skb->len, 100));
+
+ if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
+ lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n",
+ skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
+ ret = -1;
+ goto done;
+ }
+
+ memset(plocaltxpd, 0, sizeof(struct txpd));
+
+ plocaltxpd->tx_packet_length = skb->len;
+
+ /* offset of actual data */
+ plocaltxpd->tx_packet_location = sizeof(struct txpd);
+
+ /* TxCtrl set by user or default */
+ plocaltxpd->tx_control = adapter->pkttxctrl;
+
+ p802x_hdr = skb->data;
+ if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+
+ /* locate radiotap header */
+ pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
+
+ /* set txpd fields from the radiotap header */
+ new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
+ if (new_rate != 0) {
+ /* erase tx_control[4:0] */
+ plocaltxpd->tx_control &= ~0x1f;
+ /* write new tx_control[4:0] */
+ plocaltxpd->tx_control |= new_rate;
+ }
+
+ /* skip the radiotap header */
+ p802x_hdr += sizeof(struct tx_radiotap_hdr);
+ plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr);
+
+ }
+ /* copy destination address from 802.3 or 802.11 header */
+ if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+ memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
+ else
+ memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
+
+ lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+
+ if (IS_MESH_FRAME(skb)) {
+ plocaltxpd->tx_control |= TxPD_MESH_FRAME;
+ }
+
+ memcpy(ptr, plocaltxpd, sizeof(struct txpd));
+
+ ptr += sizeof(struct txpd);
+
+ lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length);
+ memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length);
+ ret = libertas_sbi_host_to_card(priv, MVMS_DAT,
+ priv->adapter->tmptxbuf,
+ plocaltxpd->tx_packet_length +
+ sizeof(struct txpd));
+
+ if (ret) {
+ lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret);
+ goto done;
+ }
+
+ lbs_pr_debug(1, "SendSinglePacket succeeds\n");
+
+ done:
+ if (!ret) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ } else {
+ priv->stats.tx_dropped++;
+ priv->stats.tx_errors++;
+ }
+
+ if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+ /* Keep the skb to echo it back once Tx feedback is
+ received from FW */
+ skb_orphan(skb);
+ /* stop processing outgoing pkts */
+ netif_stop_queue(priv->wlan_dev.netdev);
+ /* freeze any packets already in our queues */
+ priv->adapter->TxLockFlag = 1;
+ } else {
+ dev_kfree_skb_any(skb);
+ priv->adapter->currenttxskb = NULL;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+
+void libertas_tx_runqueue(wlan_private *priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ int i;
+
+ spin_lock(&adapter->txqueue_lock);
+ for (i = 0; i < adapter->tx_queue_idx; i++) {
+ struct sk_buff *skb = adapter->tx_queue_ps[i];
+ spin_unlock(&adapter->txqueue_lock);
+ SendSinglePacket(priv, skb);
+ spin_lock(&adapter->txqueue_lock);
+ }
+ adapter->tx_queue_idx = 0;
+ spin_unlock(&adapter->txqueue_lock);
+}
+
+static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb)
+{
+ wlan_adapter *adapter = priv->adapter;
+
+ spin_lock(&adapter->txqueue_lock);
+
+ WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE);
+ adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
+ if (adapter->tx_queue_idx == NR_TX_QUEUE)
+ netif_stop_queue(priv->wlan_dev.netdev);
+ else
+ netif_start_queue(priv->wlan_dev.netdev);
+
+ spin_unlock(&adapter->txqueue_lock);
+}
+
+/**
+ * @brief This function checks the conditions and sends packet to IF
+ * layer if everything is ok.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @return n/a
+ */
+int libertas_process_tx(wlan_private * priv, struct sk_buff *skb)
+{
+ int ret = -1;
+
+ ENTER();
+
+ lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+
+ if (priv->wlan_dev.dnld_sent) {
+ lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
+ priv->wlan_dev.dnld_sent);
+ goto done;
+ }
+
+ if ((priv->adapter->psstate == PS_STATE_SLEEP) ||
+ (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) {
+ wlan_tx_queue(priv, skb);
+ return ret;
+ }
+
+ priv->adapter->currenttxskb = skb;
+
+ ret = SendSinglePacket(priv, skb);
+done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
+ *
+ * @param priv A pointer to wlan_private structure
+ * @param status A 32 bit value containing transmission status.
+ *
+ * @returns void
+ */
+void libertas_send_tx_feedback(wlan_private * priv)
+{
+ wlan_adapter *adapter = priv->adapter;
+ struct tx_radiotap_hdr *radiotap_hdr;
+ u32 status = adapter->eventcause;
+ int txfail;
+ int try_count;
+
+ if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+ adapter->currenttxskb == NULL)
+ return;
+
+ radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
+
+ if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
+ lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
+ min_t(unsigned int, adapter->currenttxskb->len, 100));
+
+ txfail = (status >> 24);
+
+#if 0
+ /* The version of roofnet that we've tested does not use this yet
+ * But it may be used in the future.
+ */
+ if (txfail)
+ radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL;
+#endif
+ try_count = (status >> 16) & 0xff;
+ radiotap_hdr->data_retries = (try_count) ?
+ (1 + adapter->txretrycount - try_count) : 0;
+ libertas_upload_rx_packet(priv, adapter->currenttxskb);
+ adapter->currenttxskb = NULL;
+ priv->adapter->TxLockFlag = 0;
+ if (priv->adapter->connect_status == libertas_connected)
+ netif_wake_queue(priv->wlan_dev.netdev);
+}
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
new file mode 100644
index 00000000000..09d62f8b1a1
--- /dev/null
+++ b/drivers/net/wireless/libertas/types.h
@@ -0,0 +1,289 @@
+/**
+ * This header file contains definition for global types
+ */
+#ifndef _WLAN_TYPES_
+#define _WLAN_TYPES_
+
+#include <linux/if_ether.h>
+
+/** IEEE type definitions */
+enum ieeetypes_elementid {
+ SSID = 0,
+ SUPPORTED_RATES,
+ FH_PARAM_SET,
+ DS_PARAM_SET,
+ CF_PARAM_SET,
+ TIM,
+ IBSS_PARAM_SET,
+ COUNTRY_INFO = 7,
+
+ CHALLENGE_TEXT = 16,
+
+ EXTENDED_SUPPORTED_RATES = 50,
+
+ VENDOR_SPECIFIC_221 = 221,
+
+ WPA_IE = 221,
+ WPA2_IE = 48,
+
+ EXTRA_IE = 133,
+} __attribute__ ((packed));
+
+#define CAPINFO_MASK (~(0xda00))
+
+struct ieeetypes_capinfo {
+ u8 ess:1;
+ u8 ibss:1;
+ u8 cfpollable:1;
+ u8 cfpollrqst:1;
+ u8 privacy:1;
+ u8 shortpreamble:1;
+ u8 pbcc:1;
+ u8 chanagility:1;
+ u8 spectrummgmt:1;
+ u8 rsrvd3:1;
+ u8 shortslottime:1;
+ u8 apsd:1;
+ u8 rsvrd2:1;
+ u8 dsssofdm:1;
+ u8 rsrvd1:2;
+} __attribute__ ((packed));
+
+struct ieeetypes_cfparamset {
+ u8 elementid;
+ u8 len;
+ u8 cfpcnt;
+ u8 cfpperiod;
+ u16 cfpmaxduration;
+ u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+
+struct ieeetypes_ibssparamset {
+ u8 elementid;
+ u8 len;
+ u16 atimwindow;
+} __attribute__ ((packed));
+
+union IEEEtypes_ssparamset {
+ struct ieeetypes_cfparamset cfparamset;
+ struct ieeetypes_ibssparamset ibssparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_fhparamset {
+ u8 elementid;
+ u8 len;
+ u16 dwelltime;
+ u8 hopset;
+ u8 hoppattern;
+ u8 hopindex;
+} __attribute__ ((packed));
+
+struct ieeetypes_dsparamset {
+ u8 elementid;
+ u8 len;
+ u8 currentchan;
+} __attribute__ ((packed));
+
+union ieeetypes_phyparamset {
+ struct ieeetypes_fhparamset fhparamset;
+ struct ieeetypes_dsparamset dsparamset;
+} __attribute__ ((packed));
+
+struct ieeetypes_assocrsp {
+ struct ieeetypes_capinfo capability;
+ u16 statuscode;
+ u16 aid;
+ u8 iebuffer[1];
+} __attribute__ ((packed));
+
+/** TLV type ID definition */
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+
+/* Terminating TLV type */
+#define MRVL_TERMINATE_TLV_ID 0xffff
+
+#define TLV_TYPE_SSID 0x0000
+#define TLV_TYPE_RATES 0x0001
+#define TLV_TYPE_PHY_FH 0x0002
+#define TLV_TYPE_PHY_DS 0x0003
+#define TLV_TYPE_CF 0x0004
+#define TLV_TYPE_IBSS 0x0006
+
+#define TLV_TYPE_DOMAIN 0x0007
+
+#define TLV_TYPE_POWER_CAPABILITY 0x0021
+
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4)
+#define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5)
+#define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6)
+#define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7)
+#define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8)
+#define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9)
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11)
+#define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12)
+#define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13)
+#define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14)
+#define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15)
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17)
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23)
+
+/** TLV related data structures*/
+struct mrvlietypesheader {
+ u16 type;
+ u16 len;
+} __attribute__ ((packed));
+
+struct mrvlietypes_data {
+ struct mrvlietypesheader header;
+ u8 Data[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ratesparamset {
+ struct mrvlietypesheader header;
+ u8 rates[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssidparamset {
+ struct mrvlietypesheader header;
+ u8 ssid[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_wildcardssidparamset {
+ struct mrvlietypesheader header;
+ u8 MaxSsidlength;
+ u8 ssid[1];
+} __attribute__ ((packed));
+
+struct chanscanmode {
+ u8 passivescan:1;
+ u8 disablechanfilt:1;
+ u8 reserved_2_7:6;
+} __attribute__ ((packed));
+
+struct chanscanparamset {
+ u8 radiotype;
+ u8 channumber;
+ struct chanscanmode chanscanmode;
+ u16 minscantime;
+ u16 maxscantime;
+} __attribute__ ((packed));
+
+struct mrvlietypes_chanlistparamset {
+ struct mrvlietypesheader header;
+ struct chanscanparamset chanscanparam[1];
+} __attribute__ ((packed));
+
+struct cfparamset {
+ u8 cfpcnt;
+ u8 cfpperiod;
+ u16 cfpmaxduration;
+ u16 cfpdurationremaining;
+} __attribute__ ((packed));
+
+struct ibssparamset {
+ u16 atimwindow;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ssparamset {
+ struct mrvlietypesheader header;
+ union {
+ struct cfparamset cfparamset[1];
+ struct ibssparamset ibssparamset[1];
+ } cf_ibss;
+} __attribute__ ((packed));
+
+struct fhparamset {
+ u16 dwelltime;
+ u8 hopset;
+ u8 hoppattern;
+ u8 hopindex;
+} __attribute__ ((packed));
+
+struct dsparamset {
+ u8 currentchan;
+} __attribute__ ((packed));
+
+struct mrvlietypes_phyparamset {
+ struct mrvlietypesheader header;
+ union {
+ struct fhparamset fhparamset[1];
+ struct dsparamset dsparamset[1];
+ } fh_ds;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rsnparamset {
+ struct mrvlietypesheader header;
+ u8 rsnie[1];
+} __attribute__ ((packed));
+
+struct mrvlietypes_tsftimestamp {
+ struct mrvlietypesheader header;
+ __le64 tsftable[1];
+} __attribute__ ((packed));
+
+/** Local Power capability */
+struct mrvlietypes_powercapability {
+ struct mrvlietypesheader header;
+ s8 minpower;
+ s8 maxpower;
+} __attribute__ ((packed));
+
+struct mrvlietypes_rssithreshold {
+ struct mrvlietypesheader header;
+ u8 rssivalue;
+ u8 rssifreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_snrthreshold {
+ struct mrvlietypesheader header;
+ u8 snrvalue;
+ u8 snrfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_failurecount {
+ struct mrvlietypesheader header;
+ u8 failvalue;
+ u8 Failfreq;
+} __attribute__ ((packed));
+
+struct mrvlietypes_beaconsmissed {
+ struct mrvlietypesheader header;
+ u8 beaconmissed;
+ u8 reserved;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numprobes {
+ struct mrvlietypesheader header;
+ u16 numprobes;
+} __attribute__ ((packed));
+
+struct mrvlietypes_bcastprobe {
+ struct mrvlietypesheader header;
+ u16 bcastprobe;
+} __attribute__ ((packed));
+
+struct mrvlietypes_numssidprobe {
+ struct mrvlietypesheader header;
+ u16 numssidprobe;
+} __attribute__ ((packed));
+
+struct led_pin {
+ u8 led;
+ u8 pin;
+} __attribute__ ((packed));
+
+struct mrvlietypes_ledgpio {
+ struct mrvlietypesheader header;
+ struct led_pin ledpin[1];
+} __attribute__ ((packed));
+
+#endif /* _WLAN_TYPES_ */
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
new file mode 100644
index 00000000000..e86f65ae79b
--- /dev/null
+++ b/drivers/net/wireless/libertas/version.h
@@ -0,0 +1,8 @@
+#define DRIVER_RELEASE_VERSION "320.p0"
+const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
+#ifdef DEBUG
+ "-dbg"
+#endif
+ "";
+
+
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
new file mode 100644
index 00000000000..4a52336bc0f
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.c
@@ -0,0 +1,2769 @@
+/**
+ * This file contains ioctl functions
+ */
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/bitops.h>
+
+#include <net/ieee80211.h>
+#include <net/iw_handler.h>
+
+#include "host.h"
+#include "radiotap.h"
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+#include "join.h"
+#include "version.h"
+#include "wext.h"
+#include "assoc.h"
+
+
+/**
+ * @brief Convert mw value to dbm value
+ *
+ * @param mw the value of mw
+ * @return the value of dbm
+ */
+static int mw_to_dbm(int mw)
+{
+ if (mw < 2)
+ return 0;
+ else if (mw < 3)
+ return 3;
+ else if (mw < 4)
+ return 5;
+ else if (mw < 6)
+ return 7;
+ else if (mw < 7)
+ return 8;
+ else if (mw < 8)
+ return 9;
+ else if (mw < 10)
+ return 10;
+ else if (mw < 13)
+ return 11;
+ else if (mw < 16)
+ return 12;
+ else if (mw < 20)
+ return 13;
+ else if (mw < 25)
+ return 14;
+ else if (mw < 32)
+ return 15;
+ else if (mw < 40)
+ return 16;
+ else if (mw < 50)
+ return 17;
+ else if (mw < 63)
+ return 18;
+ else if (mw < 79)
+ return 19;
+ else if (mw < 100)
+ return 20;
+ else
+ return 21;
+}
+
+/**
+ * @brief Find the channel frequency power info with specific channel
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param band it can be BAND_A, BAND_G or BAND_B
+ * @param channel the channel for looking
+ * @return A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter,
+ u8 band, u16 channel)
+{
+ struct chan_freq_power *cfp = NULL;
+ struct region_channel *rc;
+ int count = sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0]);
+ int i, j;
+
+ for (j = 0; !cfp && (j < count); j++) {
+ rc = &adapter->region_channel[j];
+
+ if (adapter->enable11d)
+ rc = &adapter->universal_channel[j];
+ if (!rc->valid || !rc->CFP)
+ continue;
+ if (rc->band != band)
+ continue;
+ for (i = 0; i < rc->nrcfp; i++) {
+ if (rc->CFP[i].channel == channel) {
+ cfp = &rc->CFP[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && channel)
+ lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find "
+ "cfp by band %d & channel %d\n", band, channel);
+
+ return cfp;
+}
+
+/**
+ * @brief Find the channel frequency power info with specific frequency
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param band it can be BAND_A, BAND_G or BAND_B
+ * @param freq the frequency for looking
+ * @return A pointer to struct chan_freq_power structure or NULL if not find.
+ */
+static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter,
+ u8 band, u32 freq)
+{
+ struct chan_freq_power *cfp = NULL;
+ struct region_channel *rc;
+ int count = sizeof(adapter->region_channel) /
+ sizeof(adapter->region_channel[0]);
+ int i, j;
+
+ for (j = 0; !cfp && (j < count); j++) {
+ rc = &adapter->region_channel[j];
+
+ if (adapter->enable11d)
+ rc = &adapter->universal_channel[j];
+ if (!rc->valid || !rc->CFP)
+ continue;
+ if (rc->band != band)
+ continue;
+ for (i = 0; i < rc->nrcfp; i++) {
+ if (rc->CFP[i].freq == freq) {
+ cfp = &rc->CFP[i];
+ break;
+ }
+ }
+ }
+
+ if (!cfp && freq)
+ lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by "
+ "band %d & freq %d\n", band, freq);
+
+ return cfp;
+}
+
+static int updatecurrentchannel(wlan_private * priv)
+{
+ int ret;
+
+ /*
+ ** the channel in f/w could be out of sync, get the current channel
+ */
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+ cmd_opt_802_11_rf_channel_get,
+ cmd_option_waitforrsp, 0, NULL);
+
+ lbs_pr_debug(1, "Current channel = %d\n",
+ priv->adapter->curbssparams.channel);
+
+ return ret;
+}
+
+static int setcurrentchannel(wlan_private * priv, int channel)
+{
+ lbs_pr_debug(1, "Set channel = %d\n", channel);
+
+ /*
+ ** Current channel is not set to adhocchannel requested, set channel
+ */
+ return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
+ cmd_opt_802_11_rf_channel_set,
+ cmd_option_waitforrsp, 0, &channel));
+}
+
+static int changeadhocchannel(wlan_private * priv, int channel)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ adapter->adhocchannel = channel;
+
+ updatecurrentchannel(priv);
+
+ if (adapter->curbssparams.channel == adapter->adhocchannel) {
+ /* adhocchannel is set to the current channel already */
+ LEAVE();
+ return 0;
+ }
+
+ lbs_pr_debug(1, "Updating channel from %d to %d\n",
+ adapter->curbssparams.channel, adapter->adhocchannel);
+
+ setcurrentchannel(priv, adapter->adhocchannel);
+
+ updatecurrentchannel(priv);
+
+ if (adapter->curbssparams.channel != adapter->adhocchannel) {
+ lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n",
+ adapter->adhocchannel, adapter->curbssparams.channel);
+ LEAVE();
+ return -1;
+ }
+
+ if (adapter->connect_status == libertas_connected) {
+ int i;
+ struct WLAN_802_11_SSID curadhocssid;
+
+ lbs_pr_debug(1, "channel Changed while in an IBSS\n");
+
+ /* Copy the current ssid */
+ memcpy(&curadhocssid, &adapter->curbssparams.ssid,
+ sizeof(struct WLAN_802_11_SSID));
+
+ /* Exit Adhoc mode */
+ lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n");
+ ret = libertas_stop_adhoc_network(priv);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ /* Scan for the network, do not save previous results. Stale
+ * scan data will cause us to join a non-existant adhoc network
+ */
+ libertas_send_specific_SSID_scan(priv, &curadhocssid, 0);
+
+ // find out the BSSID that matches the current SSID
+ i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL,
+ wlan802_11ibss);
+
+ if (i >= 0) {
+ lbs_pr_debug(1, "SSID found at %d in List,"
+ "so join\n", i);
+ libertas_join_adhoc_network(priv, &adapter->scantable[i]);
+ } else {
+ // else send START command
+ lbs_pr_debug(1, "SSID not found in list, "
+ "so creating adhoc with ssid = %s\n",
+ curadhocssid.ssid);
+ libertas_start_adhoc_network(priv, &curadhocssid);
+ } // end of else (START command)
+ }
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set Radio On/OFF
+ *
+ * @param priv A pointer to wlan_private structure
+ * @option Radio Option
+ * @return 0 --success, otherwise fail
+ */
+int wlan_radio_ioctl(wlan_private * priv, u8 option)
+{
+ int ret = 0;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->radioon != option) {
+ lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off");
+ adapter->radioon = option;
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_radio_control,
+ cmd_act_set,
+ cmd_option_waitforrsp, 0, NULL);
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Copy rates
+ *
+ * @param dest A pointer to Dest Buf
+ * @param src A pointer to Src Buf
+ * @param len The len of Src Buf
+ * @return Number of rates copyed
+ */
+static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/**
+ * @brief Get active data rates
+ *
+ * @param adapter A pointer to wlan_adapter structure
+ * @param rate The buf to return the active rates
+ * @return The number of rates
+ */
+static int get_active_data_rates(wlan_adapter * adapter,
+ u8* rates)
+{
+ int k = 0;
+
+ ENTER();
+
+ if (adapter->connect_status != libertas_connected) {
+ if (adapter->inframode == wlan802_11infrastructure) {
+ //Infra. mode
+ lbs_pr_debug(1, "Infra\n");
+ k = copyrates(rates, k, libertas_supported_rates,
+ sizeof(libertas_supported_rates));
+ } else {
+ //ad-hoc mode
+ lbs_pr_debug(1, "Adhoc G\n");
+ k = copyrates(rates, k, libertas_adhoc_rates_g,
+ sizeof(libertas_adhoc_rates_g));
+ }
+ } else {
+ k = copyrates(rates, 0, adapter->curbssparams.datarates,
+ adapter->curbssparams.numofrates);
+ }
+
+ LEAVE();
+
+ return k;
+}
+
+static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
+ char *cwrq, char *extra)
+{
+ const char *cp;
+ char comm[6] = { "COMM-" };
+ char mrvl[6] = { "MRVL-" };
+ int cnt;
+
+ ENTER();
+
+ strcpy(cwrq, mrvl);
+
+ cp = strstr(libertas_driver_version, comm);
+ if (cp == libertas_driver_version) //skip leading "COMM-"
+ cp = libertas_driver_version + strlen(comm);
+ else
+ cp = libertas_driver_version;
+
+ cnt = strlen(mrvl);
+ cwrq += cnt;
+ while (cnt < 16 && (*cp != '-')) {
+ *cwrq++ = toupper(*cp++);
+ cnt++;
+ }
+ *cwrq = '\0';
+
+ LEAVE();
+
+ return 0;
+}
+
+static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct chan_freq_power *cfp;
+
+ ENTER();
+
+ cfp = libertas_find_cfp_by_band_and_channel(adapter, 0,
+ adapter->curbssparams.channel);
+
+ if (!cfp) {
+ if (adapter->curbssparams.channel)
+ lbs_pr_debug(1, "Invalid channel=%d\n",
+ adapter->curbssparams.channel);
+ return -EINVAL;
+ }
+
+ fwrq->m = (long)cfp->freq * 100000;
+ fwrq->e = 1;
+
+ lbs_pr_debug(1, "freq=%u\n", fwrq->m);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->connect_status == libertas_connected) {
+ memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
+ } else {
+ memset(awrq->sa_data, 0, ETH_ALEN);
+ }
+ awrq->sa_family = ARPHRD_ETHER;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /*
+ * Check the size of the string
+ */
+
+ if (dwrq->length > 16) {
+ return -E2BIG;
+ }
+
+ mutex_lock(&adapter->lock);
+ memset(adapter->nodename, 0, sizeof(adapter->nodename));
+ memcpy(adapter->nodename, extra, dwrq->length);
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /*
+ * Get the Nick Name saved
+ */
+
+ mutex_lock(&adapter->lock);
+ strncpy(extra, adapter->nodename, 16);
+ mutex_unlock(&adapter->lock);
+
+ extra[16] = '\0';
+
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /*
+ * Push it out !
+ */
+ dwrq->length = strlen(extra) + 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int rthr = vwrq->value;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE;
+ } else {
+ if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE)
+ return -EINVAL;
+ adapter->rtsthsd = rthr;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_set, cmd_option_waitforrsp,
+ OID_802_11_RTS_THRESHOLD, &rthr);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ adapter->rtsthsd = 0;
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_get, cmd_option_waitforrsp,
+ OID_802_11_RTS_THRESHOLD, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ vwrq->value = adapter->rtsthsd;
+ vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE)
+ || (vwrq->value > MRVDRV_RTS_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ int fthr = vwrq->value;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE;
+ } else {
+ if (fthr < MRVDRV_FRAG_MIN_VALUE
+ || fthr > MRVDRV_FRAG_MAX_VALUE)
+ return -EINVAL;
+ adapter->fragthsd = fthr;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_set, cmd_option_waitforrsp,
+ OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ adapter->fragthsd = 0;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ cmd_act_get, cmd_option_waitforrsp,
+ OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ vwrq->value = adapter->fragthsd;
+ vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE)
+ || (vwrq->value > MRVDRV_FRAG_MAX_VALUE));
+ vwrq->fixed = 1;
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ switch (adapter->inframode) {
+ case wlan802_11ibss:
+ *uwrq = IW_MODE_ADHOC;
+ break;
+
+ case wlan802_11infrastructure:
+ *uwrq = IW_MODE_INFRA;
+ break;
+
+ default:
+ case wlan802_11autounknown:
+ *uwrq = IW_MODE_AUTO;
+ break;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_txpow(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rf_tx_power,
+ cmd_act_tx_power_opt_get,
+ cmd_option_waitforrsp, 0, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel);
+ vwrq->value = adapter->txpowerlevel;
+ vwrq->fixed = 1;
+ if (adapter->radioon) {
+ vwrq->disabled = 0;
+ vwrq->flags = IW_TXPOW_DBM;
+ } else {
+ vwrq->disabled = 1;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (vwrq->flags == IW_RETRY_LIMIT) {
+ /* The MAC has a 4-bit Total_Tx_Count register
+ Total_Tx_Count = 1 + Tx_Retry_Count */
+#define TX_RETRY_MIN 0
+#define TX_RETRY_MAX 14
+ if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)
+ return -EINVAL;
+
+ /* Adding 1 to convert retry count to try count */
+ adapter->txretrycount = vwrq->value + 1;
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
+ cmd_act_set,
+ cmd_option_waitforrsp,
+ OID_802_11_TX_RETRYCOUNT, NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+
+ ENTER();
+ adapter->txretrycount = 0;
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_snmp_mib,
+ cmd_act_get, cmd_option_waitforrsp,
+ OID_802_11_TX_RETRYCOUNT, NULL);
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+ vwrq->disabled = 0;
+ if (!vwrq->flags) {
+ vwrq->flags = IW_RETRY_LIMIT;
+ /* Subtract 1 to convert try count to retry count */
+ vwrq->value = adapter->txretrycount - 1;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static inline void sort_channels(struct iw_freq *freq, int num)
+{
+ int i, j;
+ struct iw_freq temp;
+
+ for (i = 0; i < num; i++)
+ for (j = i + 1; j < num; j++)
+ if (freq[i].i > freq[j].i) {
+ temp.i = freq[i].i;
+ temp.m = freq[i].m;
+
+ freq[i].i = freq[j].i;
+ freq[i].m = freq[j].m;
+
+ freq[j].i = temp.i;
+ freq[j].m = temp.m;
+ }
+}
+
+/* data rate listing
+ MULTI_BANDS:
+ abg a b b/g
+ Infra G(12) A(8) B(4) G(12)
+ Adhoc A+B(12) A(8) B(4) B(4)
+
+ non-MULTI_BANDS:
+ b b/g
+ Infra B(4) G(12)
+ Adhoc B(4) B(4)
+ */
+/**
+ * @brief Get Range Info
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_get_range(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int i, j;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iw_range *range = (struct iw_range *)extra;
+ struct chan_freq_power *cfp;
+ u8 rates[WLAN_SUPPORTED_RATES];
+
+ u8 flag = 0;
+
+ ENTER();
+
+ dwrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->min_nwid = 0;
+ range->max_nwid = 0;
+
+ memset(rates, 0, sizeof(rates));
+ range->num_bitrates = get_active_data_rates(adapter, rates);
+
+ for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
+ i++) {
+ range->bitrate[i] = (rates[i] & 0x7f) * 500000;
+ }
+ range->num_bitrates = i;
+ lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
+ range->num_bitrates);
+
+ range->num_frequency = 0;
+ if (priv->adapter->enable11d &&
+ adapter->connect_status == libertas_connected) {
+ u8 chan_no;
+ u8 band;
+
+ struct parsed_region_chan_11d *parsed_region_chan =
+ &adapter->parsed_region_chan;
+
+ if (parsed_region_chan == NULL) {
+ lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n");
+ LEAVE();
+ return 0;
+ }
+ band = parsed_region_chan->band;
+ lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band,
+ parsed_region_chan->nr_chan);
+
+ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (i < parsed_region_chan->nr_chan); i++) {
+ chan_no = parsed_region_chan->chanpwr[i].chan;
+ lbs_pr_debug(1, "chan_no=%d\n", chan_no);
+ range->freq[range->num_frequency].i = (long)chan_no;
+ range->freq[range->num_frequency].m =
+ (long)libertas_chan_2_freq(chan_no, band) * 100000;
+ range->freq[range->num_frequency].e = 1;
+ range->num_frequency++;
+ }
+ flag = 1;
+ }
+ if (!flag) {
+ for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && (j < sizeof(adapter->region_channel)
+ / sizeof(adapter->region_channel[0])); j++) {
+ cfp = adapter->region_channel[j].CFP;
+ for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)
+ && adapter->region_channel[j].valid
+ && cfp
+ && (i < adapter->region_channel[j].nrcfp); i++) {
+ range->freq[range->num_frequency].i =
+ (long)cfp->channel;
+ range->freq[range->num_frequency].m =
+ (long)cfp->freq * 100000;
+ range->freq[range->num_frequency].e = 1;
+ cfp++;
+ range->num_frequency++;
+ }
+ }
+ }
+
+ lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
+ IW_MAX_FREQUENCIES, range->num_frequency);
+
+ range->num_channels = range->num_frequency;
+
+ sort_channels(&range->freq[0], range->num_frequency);
+
+ /*
+ * Set an indication of the max TCP throughput in bit/s that we can
+ * expect using this interface
+ */
+ if (i > 2)
+ range->throughput = 5000 * 1000;
+ else
+ range->throughput = 1500 * 1000;
+
+ range->min_rts = MRVDRV_RTS_MIN_VALUE;
+ range->max_rts = MRVDRV_RTS_MAX_VALUE;
+ range->min_frag = MRVDRV_FRAG_MIN_VALUE;
+ range->max_frag = MRVDRV_FRAG_MAX_VALUE;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = 4;
+
+ range->min_pmp = 1000000;
+ range->max_pmp = 120000000;
+ range->min_pmt = 1000;
+ range->max_pmt = 1000000;
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
+
+ /*
+ * Minimum version we recommend
+ */
+ range->we_version_source = 15;
+
+ /*
+ * Version we are compiled with
+ */
+ range->we_version_compiled = WIRELESS_EXT;
+
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+
+ range->min_retry = TX_RETRY_MIN;
+ range->max_retry = TX_RETRY_MAX;
+
+ /*
+ * Set the qual, level and noise range values
+ */
+ range->max_qual.qual = 100;
+ range->max_qual.level = 0;
+ range->max_qual.noise = 0;
+ range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+ range->avg_qual.qual = 70;
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+
+ range->sensitivity = 0;
+
+ /*
+ * Setup the supported power level ranges
+ */
+ memset(range->txpower, 0, sizeof(range->txpower));
+ range->txpower[0] = 5;
+ range->txpower[1] = 7;
+ range->txpower[2] = 9;
+ range->txpower[3] = 11;
+ range->txpower[4] = 13;
+ range->txpower[5] = 15;
+ range->txpower[6] = 17;
+ range->txpower[7] = 19;
+
+ range->num_txpower = 8;
+ range->txpower_capa = IW_TXPOW_DBM;
+ range->txpower_capa |= IW_TXPOW_RANGE;
+
+ range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+ IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+ IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+ range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
+ if (adapter->fwcapinfo & FW_CAPINFO_WPA) {
+ range->enc_capa = IW_ENC_CAPA_WPA
+ | IW_ENC_CAPA_WPA2
+ | IW_ENC_CAPA_CIPHER_TKIP
+ | IW_ENC_CAPA_CIPHER_CCMP;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ /* PS is currently supported only in Infrastructure mode
+ * Remove this check if it is to be supported in IBSS mode also
+ */
+
+ if (vwrq->disabled) {
+ adapter->psmode = wlan802_11powermodecam;
+ if (adapter->psstate != PS_STATE_FULL_POWER) {
+ libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+ }
+
+ return 0;
+ }
+
+ if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
+ lbs_pr_debug(1,
+ "Setting power timeout command is not supported\n");
+ return -EINVAL;
+ } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
+ lbs_pr_debug(1, "Setting power period command is not supported\n");
+ return -EINVAL;
+ }
+
+ if (adapter->psmode != wlan802_11powermodecam) {
+ return 0;
+ }
+
+ adapter->psmode = wlan802_11powermodemax_psp;
+
+ if (adapter->connect_status == libertas_connected) {
+ libertas_ps_sleep(priv, cmd_option_waitforrsp);
+ }
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_get_power(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int mode;
+
+ ENTER();
+
+ mode = adapter->psmode;
+
+ if ((vwrq->disabled = (mode == wlan802_11powermodecam))
+ || adapter->connect_status == libertas_disconnected) {
+ LEAVE();
+ return 0;
+ }
+
+ vwrq->value = 0;
+
+ LEAVE();
+ return 0;
+}
+
+/*
+ * iwpriv settable callbacks
+ */
+
+static const iw_handler wlan_private_handler[] = {
+ NULL, /* SIOCIWFIRSTPRIV */
+};
+
+static const struct iw_priv_args wlan_private_args[] = {
+ /*
+ * { cmd, set_args, get_args, name }
+ */
+ {
+ WLANSCAN_TYPE,
+ IW_PRIV_TYPE_CHAR | 8,
+ IW_PRIV_TYPE_CHAR | 8,
+ "scantype"},
+
+ {
+ WLAN_SETINT_GETINT,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ ""},
+ {
+ WLANNF,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getNF"},
+ {
+ WLANRSSI,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getRSSI"},
+ {
+ WLANENABLE11D,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "enable11d"},
+ {
+ WLANADHOCGRATE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "adhocgrate"},
+
+ {
+ WLAN_SUBCMD_SET_PRESCAN,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "prescan"},
+ {
+ WLAN_SETONEINT_GETONEINT,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ ""},
+ {
+ WLAN_BEACON_INTERVAL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "bcninterval"},
+ {
+ WLAN_LISTENINTRVL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "lolisteninter"},
+ {
+ WLAN_TXCONTROL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "txcontrol"},
+ {
+ WLAN_NULLPKTINTERVAL,
+ IW_PRIV_TYPE_INT | 1,
+ IW_PRIV_TYPE_INT | 1,
+ "psnullinterval"},
+ /* Using iwpriv sub-command feature */
+ {
+ WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ ""},
+
+ {
+ WLAN_SUBCMD_SETRXANTENNA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setrxant"},
+ {
+ WLAN_SUBCMD_SETTXANTENNA,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "settxant"},
+ {
+ WLANSETAUTHALG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "authalgs",
+ },
+ {
+ WLANSET8021XAUTHALG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "8021xauthalgs",
+ },
+ {
+ WLANSETENCRYPTIONMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "encryptionmode",
+ },
+ {
+ WLANSETREGION,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setregioncode"},
+ {
+ WLAN_SET_LISTEN_INTERVAL,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setlisteninter"},
+ {
+ WLAN_SET_MULTIPLE_DTIM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setmultipledtim"},
+ {
+ WLAN_SET_ATIM_WINDOW,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "atimwindow"},
+ {
+ WLANSETBCNAVG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setbcnavg"},
+ {
+ WLANSETDATAAVG,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "setdataavg"},
+ {
+ WLAN_SET_LINKMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "linkmode"},
+ {
+ WLAN_SET_RADIOMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "radiomode"},
+ {
+ WLAN_SET_DEBUGMODE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "debugmode"},
+ {
+ WLAN_SUBCMD_MESH_SET_TTL,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_NONE,
+ "mesh_set_ttl"},
+ {
+ WLAN_SETNONE_GETONEINT,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ ""},
+ {
+ WLANGETREGION,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getregioncode"},
+ {
+ WLAN_GET_LISTEN_INTERVAL,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getlisteninter"},
+ {
+ WLAN_GET_MULTIPLE_DTIM,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getmultipledtim"},
+ {
+ WLAN_GET_TX_RATE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "gettxrate"},
+ {
+ WLANGETBCNAVG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "getbcnavg"},
+ {
+ WLAN_GET_LINKMODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_linkmode"},
+ {
+ WLAN_GET_RADIOMODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_radiomode"},
+ {
+ WLAN_GET_DEBUGMODE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_debugmode"},
+ {
+ WLAN_SUBCMD_FWT_CLEANUP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "fwt_cleanup"},
+ {
+ WLAN_SUBCMD_FWT_TIME,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "fwt_time"},
+ {
+ WLAN_SUBCMD_MESH_GET_TTL,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "mesh_get_ttl"},
+ {
+ WLAN_SETNONE_GETTWELVE_CHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ ""},
+ {
+ WLAN_SUBCMD_GETRXANTENNA,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "getrxant"},
+ {
+ WLAN_SUBCMD_GETTXANTENNA,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "gettxant"},
+ {
+ WLAN_GET_TSF,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 12,
+ "gettsf"},
+ {
+ WLAN_SETNONE_GETNONE,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ ""},
+ {
+ WLANDEAUTH,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "deauth"},
+ {
+ WLANADHOCSTOP,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "adhocstop"},
+ {
+ WLANRADIOON,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "radioon"},
+ {
+ WLANRADIOOFF,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "radiooff"},
+ {
+ WLANWLANIDLEON,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "wlanidle-on"},
+ {
+ WLANWLANIDLEOFF,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "wlanidle-off"},
+ {
+ WLAN_SUBCMD_FWT_RESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "fwt_reset"},
+ {
+ WLAN_SUBCMD_BT_RESET,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_NONE,
+ "bt_reset"},
+ {
+ WLAN_SET128CHAR_GET128CHAR,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ /* BT Management */
+ {
+ WLAN_SUBCMD_BT_ADD,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "bt_add"},
+ {
+ WLAN_SUBCMD_BT_DEL,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "bt_del"},
+ {
+ WLAN_SUBCMD_BT_LIST,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "bt_list"},
+ /* FWT Management */
+ {
+ WLAN_SUBCMD_FWT_ADD,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_add"},
+ {
+ WLAN_SUBCMD_FWT_DEL,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_del"},
+ {
+ WLAN_SUBCMD_FWT_LOOKUP,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_lookup"},
+ {
+ WLAN_SUBCMD_FWT_LIST_NEIGHBOR,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_list_neigh"},
+ {
+ WLAN_SUBCMD_FWT_LIST,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_list"},
+ {
+ WLAN_SUBCMD_FWT_LIST_ROUTE,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "fwt_list_route"},
+ {
+ WLANSCAN_MODE,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "scanmode"},
+ {
+ WLAN_GET_ADHOC_STATUS,
+ IW_PRIV_TYPE_CHAR | 128,
+ IW_PRIV_TYPE_CHAR | 128,
+ "getadhocstatus"},
+ {
+ WLAN_SETNONE_GETWORDCHAR,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | 128,
+ ""},
+ {
+ WLANSETWPAIE,
+ IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24,
+ IW_PRIV_TYPE_NONE,
+ "setwpaie"},
+ {
+ WLANGETLOG,
+ IW_PRIV_TYPE_NONE,
+ IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE,
+ "getlog"},
+ {
+ WLAN_SET_GET_SIXTEEN_INT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ ""},
+ {
+ WLAN_TPCCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "tpccfg"},
+ {
+ WLAN_POWERCFG,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "powercfg"},
+ {
+ WLAN_AUTO_FREQ_SET,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "setafc"},
+ {
+ WLAN_AUTO_FREQ_GET,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getafc"},
+ {
+ WLAN_SCANPROBES,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "scanprobes"},
+ {
+ WLAN_LED_GPIO_CTRL,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "ledgpio"},
+ {
+ WLAN_ADAPT_RATESET,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "rateadapt"},
+ {
+ WLAN_INACTIVITY_TIMEOUT,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "inactivityto"},
+ {
+ WLANSNR,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getSNR"},
+ {
+ WLAN_GET_RATE,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getrate"},
+ {
+ WLAN_GET_RXINFO,
+ IW_PRIV_TYPE_INT | 16,
+ IW_PRIV_TYPE_INT | 16,
+ "getrxinfo"},
+};
+
+static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev)
+{
+ enum {
+ POOR = 30,
+ FAIR = 60,
+ GOOD = 80,
+ VERY_GOOD = 90,
+ EXCELLENT = 95,
+ PERFECT = 100
+ };
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ u32 rssi_qual;
+ u32 tx_qual;
+ u32 quality = 0;
+ int stats_valid = 0;
+ u8 rssi;
+ u32 tx_retries;
+
+ ENTER();
+
+ priv->wstats.status = adapter->inframode;
+
+ /* If we're not associated, all quality values are meaningless */
+ if (adapter->connect_status != libertas_connected)
+ goto out;
+
+ /* Quality by RSSI */
+ priv->wstats.qual.level =
+ CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG],
+ adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+
+ if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {
+ priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;
+ } else {
+ priv->wstats.qual.noise =
+ CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]);
+ }
+
+ lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level);
+ lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise);
+
+ rssi = priv->wstats.qual.level - priv->wstats.qual.noise;
+ if (rssi < 15)
+ rssi_qual = rssi * POOR / 10;
+ else if (rssi < 20)
+ rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;
+ else if (rssi < 30)
+ rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;
+ else if (rssi < 40)
+ rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /
+ 10 + GOOD;
+ else
+ rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /
+ 10 + VERY_GOOD;
+ quality = rssi_qual;
+
+ /* Quality by TX errors */
+ priv->wstats.discard.retries = priv->stats.tx_errors;
+
+ tx_retries = adapter->logmsg.retry;
+
+ if (tx_retries > 75)
+ tx_qual = (90 - tx_retries) * POOR / 15;
+ else if (tx_retries > 70)
+ tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
+ else if (tx_retries > 65)
+ tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
+ else if (tx_retries > 50)
+ tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
+ 15 + GOOD;
+ else
+ tx_qual = (50 - tx_retries) *
+ (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
+ quality = min(quality, tx_qual);
+
+ priv->wstats.discard.code = adapter->logmsg.wepundecryptable;
+ priv->wstats.discard.fragment = adapter->logmsg.fcserror;
+ priv->wstats.discard.retries = tx_retries;
+ priv->wstats.discard.misc = adapter->logmsg.ackfailure;
+
+ /* Calculate quality */
+ priv->wstats.qual.qual = max(quality, (u32)100);
+ priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
+ stats_valid = 1;
+
+ /* update stats asynchronously for future calls */
+ libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+ 0, 0, NULL);
+ libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+ 0, 0, NULL);
+out:
+ if (!stats_valid) {
+ priv->wstats.miss.beacon = 0;
+ priv->wstats.discard.retries = 0;
+ priv->wstats.qual.qual = 0;
+ priv->wstats.qual.level = 0;
+ priv->wstats.qual.noise = 0;
+ priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;
+ priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |
+ IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ }
+
+ LEAVE ();
+ return &priv->wstats;
+
+
+}
+
+static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
+ struct iw_freq *fwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int rc = -EINPROGRESS; /* Call commit handler */
+ struct chan_freq_power *cfp;
+
+ ENTER();
+
+ /*
+ * If setting by frequency, convert to a channel
+ */
+ if (fwrq->e == 1) {
+
+ long f = fwrq->m / 100000;
+ int c = 0;
+
+ cfp = find_cfp_by_band_and_freq(adapter, 0, f);
+ if (!cfp) {
+ lbs_pr_debug(1, "Invalid freq=%ld\n", f);
+ return -EINVAL;
+ }
+
+ c = (int)cfp->channel;
+
+ if (c < 0)
+ return -EINVAL;
+
+ fwrq->e = 0;
+ fwrq->m = c;
+ }
+
+ /*
+ * Setting by channel number
+ */
+ if (fwrq->m > 1000 || fwrq->e > 0) {
+ rc = -EOPNOTSUPP;
+ } else {
+ int channel = fwrq->m;
+
+ cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel);
+ if (!cfp) {
+ rc = -EINVAL;
+ } else {
+ if (adapter->inframode == wlan802_11ibss) {
+ rc = changeadhocchannel(priv, channel);
+ /* If station is WEP enabled, send the
+ * command to set WEP in firmware
+ */
+ if (adapter->secinfo.WEPstatus ==
+ wlan802_11WEPenabled) {
+ lbs_pr_debug(1, "set_freq: WEP enabled\n");
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_set_wep,
+ cmd_act_add,
+ cmd_option_waitforrsp,
+ 0,
+ NULL);
+
+ if (ret) {
+ LEAVE();
+ return ret;
+ }
+
+ adapter->currentpacketfilter |=
+ cmd_act_mac_wep_enable;
+
+ libertas_set_mac_packet_filter(priv);
+ }
+ } else {
+ rc = -EOPNOTSUPP;
+ }
+ }
+ }
+
+ LEAVE();
+ return rc;
+}
+
+/**
+ * @brief use index to get the data rate
+ *
+ * @param index The index of data rate
+ * @return data rate or 0
+ */
+u32 libertas_index_to_data_rate(u8 index)
+{
+ if (index >= sizeof(libertas_wlan_data_rates))
+ index = 0;
+
+ return libertas_wlan_data_rates[index];
+}
+
+/**
+ * @brief use rate to get the index
+ *
+ * @param rate data rate
+ * @return index or 0
+ */
+u8 libertas_data_rate_to_index(u32 rate)
+{
+ u8 *ptr;
+
+ if (rate)
+ if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
+ sizeof(libertas_wlan_data_rates))))
+ return (ptr - libertas_wlan_data_rates);
+
+ return 0;
+}
+
+static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ u32 data_rate;
+ u16 action;
+ int ret = 0;
+ u8 rates[WLAN_SUPPORTED_RATES];
+ u8 *rate;
+
+ ENTER();
+
+ lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value);
+
+ if (vwrq->value == -1) {
+ action = cmd_act_set_tx_auto; // Auto
+ adapter->is_datarate_auto = 1;
+ adapter->datarate = 0;
+ } else {
+ if (vwrq->value % 100000) {
+ return -EINVAL;
+ }
+
+ data_rate = vwrq->value / 500000;
+
+ memset(rates, 0, sizeof(rates));
+ get_active_data_rates(adapter, rates);
+ rate = rates;
+ while (*rate) {
+ lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate,
+ data_rate);
+ if ((*rate & 0x7f) == (data_rate & 0x7f))
+ break;
+ rate++;
+ }
+ if (!*rate) {
+ lbs_pr_alert( "The fixed data rate 0x%X is out "
+ "of range.\n", data_rate);
+ return -EINVAL;
+ }
+
+ adapter->datarate = data_rate;
+ action = cmd_act_set_tx_fix_rate;
+ adapter->is_datarate_auto = 0;
+ }
+
+ ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
+ action, cmd_option_waitforrsp, 0, NULL);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->is_datarate_auto) {
+ vwrq->fixed = 0;
+ } else {
+ vwrq->fixed = 1;
+ }
+
+ vwrq->value = adapter->datarate * 500000;
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_mode(struct net_device *dev,
+ struct iw_request_info *info, u32 * uwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode;
+
+ ENTER();
+
+ switch (*uwrq) {
+ case IW_MODE_ADHOC:
+ lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n",
+ adapter->datarate);
+ new_mode = wlan802_11ibss;
+ adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL;
+ break;
+
+ case IW_MODE_INFRA:
+ lbs_pr_debug(1, "Wanted mode is Infrastructure\n");
+ new_mode = wlan802_11infrastructure;
+ break;
+
+ case IW_MODE_AUTO:
+ lbs_pr_debug(1, "Wanted mode is Auto\n");
+ new_mode = wlan802_11autounknown;
+ break;
+
+ default:
+ lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq);
+ return -EINVAL;
+ }
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ } else {
+ assoc_req->mode = new_mode;
+ }
+
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+
+/**
+ * @brief Get Encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_get_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, u8 * extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
+
+ ENTER();
+
+ lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n",
+ dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx);
+
+ dwrq->flags = 0;
+
+ /* Authentication method */
+ switch (adapter->secinfo.authmode) {
+ case wlan802_11authmodeopen:
+ dwrq->flags = IW_ENCODE_OPEN;
+ break;
+
+ case wlan802_11authmodeshared:
+ case wlan802_11authmodenetworkEAP:
+ dwrq->flags = IW_ENCODE_RESTRICTED;
+ break;
+ default:
+ dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
+ break;
+ }
+
+ if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+ || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) {
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ }
+
+ memset(extra, 0, 16);
+
+ mutex_lock(&adapter->lock);
+
+ /* Default to returning current transmit key */
+ if (index < 0)
+ index = adapter->wep_tx_keyidx;
+
+ if ((adapter->wep_keys[index].len) &&
+ (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) {
+ memcpy(extra, adapter->wep_keys[index].key,
+ adapter->wep_keys[index].len);
+ dwrq->length = adapter->wep_keys[index].len;
+
+ dwrq->flags |= (index + 1);
+ /* Return WEP enabled */
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else if ((adapter->secinfo.WPAenabled)
+ || (adapter->secinfo.WPA2enabled)) {
+ /* return WPA enabled */
+ dwrq->flags &= ~IW_ENCODE_DISABLED;
+ } else {
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ }
+
+ mutex_unlock(&adapter->lock);
+
+ dwrq->flags |= IW_ENCODE_NOKEY;
+
+ lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n",
+ extra[0], extra[1], extra[2],
+ extra[3], extra[4], extra[5], dwrq->length);
+
+ lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags);
+
+ LEAVE();
+ return 0;
+}
+
+/**
+ * @brief Set Encryption key (internal)
+ *
+ * @param priv A pointer to private card structure
+ * @param key_material A pointer to key material
+ * @param key_length length of key material
+ * @param index key index to set
+ * @param set_tx_key Force set TX key (1 = yes, 0 = no)
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_wep_key(struct assoc_request *assoc_req,
+ const char *key_material,
+ u16 key_length,
+ u16 index,
+ int set_tx_key)
+{
+ struct WLAN_802_11_KEY *pkey;
+
+ ENTER();
+
+ /* Paranoid validation of key index */
+ if (index > 3) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ /* validate max key length */
+ if (key_length > KEY_LEN_WEP_104) {
+ LEAVE();
+ return -EINVAL;
+ }
+
+ pkey = &assoc_req->wep_keys[index];
+
+ if (key_length > 0) {
+ memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+ pkey->type = KEY_TYPE_ID_WEP;
+
+ /* Standardize the key length */
+ pkey->len = (key_length > KEY_LEN_WEP_40) ?
+ KEY_LEN_WEP_104 : KEY_LEN_WEP_40;
+ memcpy(pkey->key, key_material, key_length);
+ }
+
+ if (set_tx_key) {
+ /* Ensure the chosen key is valid */
+ if (!pkey->len) {
+ lbs_pr_debug(1, "key not set, so cannot enable it\n");
+ LEAVE();
+ return -EINVAL;
+ }
+ assoc_req->wep_tx_keyidx = index;
+ }
+
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled;
+
+ LEAVE();
+ return 0;
+}
+
+static int validate_key_index(u16 def_index, u16 raw_index,
+ u16 *out_index, u16 *is_default)
+{
+ if (!out_index || !is_default)
+ return -EINVAL;
+
+ /* Verify index if present, otherwise use default TX key index */
+ if (raw_index > 0) {
+ if (raw_index > 4)
+ return -EINVAL;
+ *out_index = raw_index - 1;
+ } else {
+ *out_index = def_index;
+ *is_default = 1;
+ }
+ return 0;
+}
+
+static void disable_wep(struct assoc_request *assoc_req)
+{
+ int i;
+
+ /* Set Open System auth mode */
+ assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+
+ /* Clear WEP keys and mark WEP as disabled */
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ for (i = 0; i < 4; i++)
+ assoc_req->wep_keys[i].len = 0;
+
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+}
+
+/**
+ * @brief Set Encryption key
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_encode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ u16 is_default = 0, index = 0, set_tx_key = 0;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (dwrq->flags & IW_ENCODE_DISABLED) {
+ disable_wep (assoc_req);
+ goto out;
+ }
+
+ ret = validate_key_index(assoc_req->wep_tx_keyidx,
+ (dwrq->flags & IW_ENCODE_INDEX),
+ &index, &is_default);
+ if (ret) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* If WEP isn't enabled, or if there is no key data but a valid
+ * index, set the TX key.
+ */
+ if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+ || (dwrq->length == 0 && !is_default))
+ set_tx_key = 1;
+
+ ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);
+ if (ret)
+ goto out;
+
+ if (dwrq->length)
+ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+ if (set_tx_key)
+ set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+ if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+ assoc_req->secinfo.authmode = wlan802_11authmodeshared;
+ } else if (dwrq->flags & IW_ENCODE_OPEN) {
+ assoc_req->secinfo.authmode = wlan802_11authmodeopen;
+ }
+
+out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get Extended Encryption key (WPA/802.1x and WEP)
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 on success, otherwise failure
+ */
+static int wlan_get_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ int ret = -EINVAL;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int index, max_key_len;
+
+ ENTER();
+
+ max_key_len = dwrq->length - sizeof(*ext);
+ if (max_key_len < 0)
+ goto out;
+
+ index = dwrq->flags & IW_ENCODE_INDEX;
+ if (index) {
+ if (index < 1 || index > 4)
+ goto out;
+ index--;
+ } else {
+ index = adapter->wep_tx_keyidx;
+ }
+
+ if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY &&
+ ext->alg != IW_ENCODE_ALG_WEP) {
+ if (index != 0 || adapter->inframode != wlan802_11infrastructure)
+ goto out;
+ }
+
+ dwrq->flags = index + 1;
+ memset(ext, 0, sizeof(*ext));
+
+ if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled)
+ && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) {
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ dwrq->flags |= IW_ENCODE_DISABLED;
+ } else {
+ u8 *key = NULL;
+
+ if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled)
+ && !adapter->secinfo.WPAenabled
+ && !adapter->secinfo.WPA2enabled) {
+ ext->alg = IW_ENCODE_ALG_WEP;
+ ext->key_len = adapter->wep_keys[index].len;
+ key = &adapter->wep_keys[index].key[0];
+ } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) &&
+ (adapter->secinfo.WPAenabled ||
+ adapter->secinfo.WPA2enabled)) {
+ /* WPA */
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ ext->key_len = 0;
+ } else {
+ goto out;
+ }
+
+ if (ext->key_len > max_key_len) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ if (ext->key_len)
+ memcpy(ext->key, key, ext->key_len);
+ else
+ dwrq->flags |= IW_ENCODE_NOKEY;
+ dwrq->flags |= IW_ENCODE_ENABLED;
+ }
+ ret = 0;
+
+out:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Encryption key Extended (WPA/802.1x and WEP)
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param vwrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_encodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int alg = ext->alg;
+ struct assoc_request * assoc_req;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {
+ disable_wep (assoc_req);
+ } else if (alg == IW_ENCODE_ALG_WEP) {
+ u16 is_default = 0, index, set_tx_key = 0;
+
+ ret = validate_key_index(assoc_req->wep_tx_keyidx,
+ (dwrq->flags & IW_ENCODE_INDEX),
+ &index, &is_default);
+ if (ret)
+ goto out;
+
+ /* If WEP isn't enabled, or if there is no key data but a valid
+ * index, or if the set-TX-key flag was passed, set the TX key.
+ */
+ if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled)
+ || (dwrq->length == 0 && !is_default)
+ || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))
+ set_tx_key = 1;
+
+ /* Copy key to driver */
+ ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index,
+ set_tx_key);
+ if (ret)
+ goto out;
+
+ if (dwrq->flags & IW_ENCODE_RESTRICTED) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeshared;
+ } else if (dwrq->flags & IW_ENCODE_OPEN) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+
+ /* Mark the various WEP bits as modified */
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ if (dwrq->length)
+ set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);
+ if (set_tx_key)
+ set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
+
+ } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
+ struct WLAN_802_11_KEY * pkey;
+
+ /* validate key length */
+ if (((alg == IW_ENCODE_ALG_TKIP)
+ && (ext->key_len != KEY_LEN_WPA_TKIP))
+ || ((alg == IW_ENCODE_ALG_CCMP)
+ && (ext->key_len != KEY_LEN_WPA_AES))) {
+ lbs_pr_debug(1, "Invalid size %d for key of alg"
+ "type %d.\n",
+ ext->key_len,
+ alg);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
+ pkey = &assoc_req->wpa_mcast_key;
+ else
+ pkey = &assoc_req->wpa_unicast_key;
+
+ memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+ memcpy(pkey->key, ext->key, ext->key_len);
+ pkey->len = ext->key_len;
+ pkey->flags = KEY_INFO_WPA_ENABLED;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
+ pkey->flags |= KEY_INFO_WPA_MCAST;
+ set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+ } else {
+ pkey->flags |= KEY_INFO_WPA_UNICAST;
+ set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+ }
+
+ if (alg == IW_ENCODE_ALG_TKIP)
+ pkey->type = KEY_TYPE_ID_TKIP;
+ else if (alg == IW_ENCODE_ALG_CCMP)
+ pkey->type = KEY_TYPE_ID_AES;
+
+ /* If WPA isn't enabled yet, do that now */
+ if ( assoc_req->secinfo.WPAenabled == 0
+ && assoc_req->secinfo.WPA2enabled == 0) {
+ assoc_req->secinfo.WPAenabled = 1;
+ assoc_req->secinfo.WPA2enabled = 1;
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ }
+
+ disable_wep (assoc_req);
+ }
+
+out:
+ if (ret == 0) {
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+
+static int wlan_set_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct assoc_request * assoc_req;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (dwrq->length > MAX_WPA_IE_LEN ||
+ (dwrq->length && extra == NULL)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (dwrq->length) {
+ memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);
+ assoc_req->wpa_ie_len = dwrq->length;
+ } else {
+ memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie));
+ assoc_req->wpa_ie_len = 0;
+ }
+
+out:
+ if (ret == 0) {
+ set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_genie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ if (adapter->wpa_ie_len == 0) {
+ dwrq->length = 0;
+ LEAVE();
+ return 0;
+ }
+
+ if (dwrq->length < adapter->wpa_ie_len) {
+ LEAVE();
+ return -E2BIG;
+ }
+
+ dwrq->length = adapter->wpa_ie_len;
+ memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len);
+
+ LEAVE();
+ return 0;
+}
+
+
+static int wlan_set_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ int ret = 0;
+ int updated = 0;
+
+ ENTER();
+
+ mutex_lock(&adapter->lock);
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_TKIP_COUNTERMEASURES:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ /*
+ * libertas does not use these parameters
+ */
+ break;
+
+ case IW_AUTH_WPA_VERSION:
+ if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {
+ assoc_req->secinfo.WPAenabled = 0;
+ assoc_req->secinfo.WPA2enabled = 0;
+ }
+ if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {
+ assoc_req->secinfo.WPAenabled = 1;
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+ if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {
+ assoc_req->secinfo.WPA2enabled = 1;
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ if (dwrq->value) {
+ adapter->currentpacketfilter |=
+ cmd_act_mac_strict_protection_enable;
+ } else {
+ adapter->currentpacketfilter &=
+ ~cmd_act_mac_strict_protection_enable;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeshared;
+ } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ } else if (dwrq->value & IW_AUTH_ALG_LEAP) {
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodenetworkEAP;
+ } else {
+ ret = -EINVAL;
+ }
+ updated = 1;
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ if (dwrq->value) {
+ if (!assoc_req->secinfo.WPAenabled &&
+ !assoc_req->secinfo.WPA2enabled) {
+ assoc_req->secinfo.WPAenabled = 1;
+ assoc_req->secinfo.WPA2enabled = 1;
+ assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled;
+ assoc_req->secinfo.authmode =
+ wlan802_11authmodeopen;
+ }
+ } else {
+ assoc_req->secinfo.WPAenabled = 0;
+ assoc_req->secinfo.WPA2enabled = 0;
+ }
+ updated = 1;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+out:
+ if (ret == 0) {
+ if (updated)
+ set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ } else if (ret != -EOPNOTSUPP) {
+ wlan_cancel_association_work(priv);
+ }
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_auth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *dwrq,
+ char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+
+ switch (dwrq->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ dwrq->value = 0;
+ if (adapter->secinfo.WPAenabled)
+ dwrq->value |= IW_AUTH_WPA_VERSION_WPA;
+ if (adapter->secinfo.WPA2enabled)
+ dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;
+ if (!dwrq->value)
+ dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ dwrq->value = 0;
+ if (adapter->currentpacketfilter &
+ cmd_act_mac_strict_protection_enable)
+ dwrq->value = 1;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ switch (adapter->secinfo.authmode) {
+ case wlan802_11authmodeshared:
+ dwrq->value = IW_AUTH_ALG_SHARED_KEY;
+ break;
+ case wlan802_11authmodeopen:
+ dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case wlan802_11authmodenetworkEAP:
+ dwrq->value = IW_AUTH_ALG_LEAP;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled)
+ dwrq->value = 1;
+ break;
+
+ default:
+ LEAVE();
+ return -EOPNOTSUPP;
+ }
+
+ LEAVE();
+ return 0;
+}
+
+
+static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info,
+ struct iw_param *vwrq, char *extra)
+{
+ int ret = 0;
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ u16 dbm;
+
+ ENTER();
+
+ if (vwrq->disabled) {
+ wlan_radio_ioctl(priv, RADIO_OFF);
+ return 0;
+ }
+
+ adapter->preamble = cmd_type_auto_preamble;
+
+ wlan_radio_ioctl(priv, RADIO_ON);
+
+ if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
+ dbm = (u16) mw_to_dbm(vwrq->value);
+ } else
+ dbm = (u16) vwrq->value;
+
+ /* auto tx power control */
+
+ if (vwrq->fixed == 0)
+ dbm = 0xffff;
+
+ lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm);
+
+ ret = libertas_prepare_and_send_command(priv,
+ cmd_802_11_rf_tx_power,
+ cmd_act_tx_power_opt_set_low,
+ cmd_option_waitforrsp, 0, (void *)&dbm);
+
+ LEAVE();
+ return ret;
+}
+
+static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+
+ ENTER();
+ /*
+ * Note : if dwrq->flags != 0, we should get the relevant SSID from
+ * the SSID list...
+ */
+
+ /*
+ * Get the current SSID
+ */
+ if (adapter->connect_status == libertas_connected) {
+ memcpy(extra, adapter->curbssparams.ssid.ssid,
+ adapter->curbssparams.ssid.ssidlength);
+ extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+ } else {
+ memset(extra, 0, 32);
+ extra[adapter->curbssparams.ssid.ssidlength] = '\0';
+ }
+ /*
+ * If none, we may want to get the one that was set
+ */
+
+ /* To make the driver backward compatible with WPA supplicant v0.2.4 */
+ if (dwrq->length == 32) /* check with WPA supplicant buffer size */
+ dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength,
+ IW_ESSID_MAX_SIZE);
+ else
+ dwrq->length = adapter->curbssparams.ssid.ssidlength + 1;
+
+ dwrq->flags = 1; /* active */
+
+ LEAVE();
+ return 0;
+}
+
+static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info,
+ struct iw_point *dwrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct WLAN_802_11_SSID ssid;
+ struct assoc_request * assoc_req;
+ int ssid_len = dwrq->length;
+
+ ENTER();
+
+ /*
+ * WE-20 and earlier NULL pad the end of the SSID and increment
+ * SSID length so it can be used like a string. WE-21 and later don't,
+ * but some userspace tools aren't able to cope with the change.
+ */
+ if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0'))
+ ssid_len--;
+
+ /* Check the size of the string */
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ ret = -E2BIG;
+ goto out;
+ }
+
+ memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID));
+
+ if (!dwrq->flags || !ssid_len) {
+ /* "any" SSID requested; leave SSID blank */
+ } else {
+ /* Specific SSID requested */
+ memcpy(&ssid.ssid, extra, ssid_len);
+ ssid.ssidlength = ssid_len;
+ }
+
+ lbs_pr_debug(1, "Requested new SSID = %s\n",
+ (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any");
+
+out:
+ mutex_lock(&adapter->lock);
+ if (ret == 0) {
+ /* Get or create the current association request */
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ ret = -ENOMEM;
+ } else {
+ /* Copy the SSID to the association request */
+ memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID));
+ set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ }
+ }
+
+ /* Cancel the association request if there was an error */
+ if (ret != 0) {
+ wlan_cancel_association_work(priv);
+ }
+
+ mutex_unlock(&adapter->lock);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Connect to the AP or Ad-hoc Network with specific bssid
+ *
+ * @param dev A pointer to net_device structure
+ * @param info A pointer to iw_request_info structure
+ * @param awrq A pointer to iw_param structure
+ * @param extra A pointer to extra data buf
+ * @return 0 --success, otherwise fail
+ */
+static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
+ struct sockaddr *awrq, char *extra)
+{
+ wlan_private *priv = dev->priv;
+ wlan_adapter *adapter = priv->adapter;
+ struct assoc_request * assoc_req;
+ int ret = 0;
+
+ ENTER();
+
+ if (awrq->sa_family != ARPHRD_ETHER)
+ return -EINVAL;
+
+ lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+
+ mutex_lock(&adapter->lock);
+
+ /* Get or create the current association request */
+ assoc_req = wlan_get_association_request(adapter);
+ if (!assoc_req) {
+ wlan_cancel_association_work(priv);
+ ret = -ENOMEM;
+ } else {
+ /* Copy the BSSID to the association request */
+ memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
+ set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
+ wlan_postpone_association_work(priv);
+ }
+
+ mutex_unlock(&adapter->lock);
+
+ return ret;
+}
+
+void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen)
+{
+ union {
+ u32 l;
+ u8 c[4];
+ } ver;
+ char fwver[32];
+
+ mutex_lock(&adapter->lock);
+ ver.l = adapter->fwreleasenumber;
+ mutex_unlock(&adapter->lock);
+
+ if (ver.c[3] == 0)
+ sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]);
+ else
+ sprintf(fwver, "%u.%u.%u.p%u",
+ ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+ snprintf(fwversion, maxlen, fwver);
+}
+
+
+/*
+ * iwconfig settable callbacks
+ */
+static const iw_handler wlan_handler[] = {
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+ (iw_handler) wlan_get_name, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */
+ (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */
+ (iw_handler) wlan_set_mode, /* SIOCSIWMODE */
+ (iw_handler) wlan_get_mode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL, /* SIOCSIWRANGE */
+ (iw_handler) wlan_get_range, /* SIOCGIWRANGE */
+ (iw_handler) NULL, /* SIOCSIWPRIV */
+ (iw_handler) NULL, /* SIOCGIWPRIV */
+ (iw_handler) NULL, /* SIOCSIWSTATS */
+ (iw_handler) NULL, /* SIOCGIWSTATS */
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+ (iw_handler) wlan_set_wap, /* SIOCSIWAP */
+ (iw_handler) wlan_get_wap, /* SIOCGIWAP */
+ (iw_handler) NULL, /* SIOCSIWMLME */
+ (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */
+ (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */
+ (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */
+ (iw_handler) wlan_set_essid, /* SIOCSIWESSID */
+ (iw_handler) wlan_get_essid, /* SIOCGIWESSID */
+ (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */
+ (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wlan_set_rate, /* SIOCSIWRATE */
+ (iw_handler) wlan_get_rate, /* SIOCGIWRATE */
+ (iw_handler) wlan_set_rts, /* SIOCSIWRTS */
+ (iw_handler) wlan_get_rts, /* SIOCGIWRTS */
+ (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */
+ (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */
+ (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */
+ (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */
+ (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */
+ (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */
+ (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */
+ (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */
+ (iw_handler) wlan_set_power, /* SIOCSIWPOWER */
+ (iw_handler) wlan_get_power, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */
+ (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */
+ (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */
+ (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCSIWPMKSA */
+};
+
+struct iw_handler_def libertas_handler_def = {
+ .num_standard = sizeof(wlan_handler) / sizeof(iw_handler),
+ .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler),
+ .num_private_args = sizeof(wlan_private_args) /
+ sizeof(struct iw_priv_args),
+ .standard = (iw_handler *) wlan_handler,
+ .private = (iw_handler *) wlan_private_handler,
+ .private_args = (struct iw_priv_args *)wlan_private_args,
+ .get_wireless_stats = wlan_get_wireless_stats,
+};
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
new file mode 100644
index 00000000000..39f367c38d9
--- /dev/null
+++ b/drivers/net/wireless/libertas/wext.h
@@ -0,0 +1,147 @@
+/**
+ * This file contains definition for IOCTL call.
+ */
+#ifndef _WLAN_WEXT_H_
+#define _WLAN_WEXT_H_
+
+#define SUBCMD_OFFSET 4
+#define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET))
+
+/** PRIVATE CMD ID */
+#define WLANIOCTL SIOCIWFIRSTPRIV
+
+#define WLANSETWPAIE (WLANIOCTL + 0)
+
+#define WLAN_SETINT_GETINT (WLANIOCTL + 7)
+#define WLANNF 1
+#define WLANRSSI 2
+#define WLANENABLE11D 5
+#define WLANADHOCGRATE 6
+#define WLAN_SUBCMD_SET_PRESCAN 11
+
+#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8)
+#define WLANDEAUTH 1
+#define WLANRADIOON 2
+#define WLANRADIOOFF 3
+#define WLANREMOVEADHOCAES 4
+#define WLANADHOCSTOP 5
+#define WLANCIPHERTEST 6
+#define WLANCRYPTOTEST 7
+
+#define WLANWLANIDLEON 10
+#define WLANWLANIDLEOFF 11
+#define WLAN_SUBCMD_BT_RESET 13
+#define WLAN_SUBCMD_FWT_RESET 14
+
+#define WLANGETLOG (WLANIOCTL + 9)
+#define GETLOG_BUFSIZE 300
+
+#define WLANSCAN_TYPE (WLANIOCTL + 11)
+
+#define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15)
+#define WLANGETREGION 1
+#define WLAN_GET_LISTEN_INTERVAL 2
+#define WLAN_GET_MULTIPLE_DTIM 3
+#define WLAN_GET_TX_RATE 4
+#define WLANGETBCNAVG 5
+
+#define WLAN_GET_LINKMODE 6
+#define WLAN_GET_RADIOMODE 7
+#define WLAN_GET_DEBUGMODE 8
+#define WLAN_SUBCMD_FWT_CLEANUP 15
+#define WLAN_SUBCMD_FWT_TIME 16
+#define WLAN_SUBCMD_MESH_GET_TTL 17
+
+#define WLANREGCFRDWR (WLANIOCTL + 18)
+
+#define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19)
+#define WLAN_SUBCMD_GETRXANTENNA 1
+#define WLAN_SUBCMD_GETTXANTENNA 2
+#define WLAN_GET_TSF 3
+
+#define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21)
+#define WLANGETADHOCAES 1
+
+#define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23)
+#define WLAN_BEACON_INTERVAL 1
+#define WLAN_LISTENINTRVL 4
+
+#define WLAN_TXCONTROL 6
+#define WLAN_NULLPKTINTERVAL 7
+
+#define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24)
+#define WLAN_SUBCMD_SETRXANTENNA 1
+#define WLAN_SUBCMD_SETTXANTENNA 2
+#define WLANSETAUTHALG 5
+#define WLANSET8021XAUTHALG 6
+#define WLANSETENCRYPTIONMODE 7
+#define WLANSETREGION 8
+#define WLAN_SET_LISTEN_INTERVAL 9
+
+#define WLAN_SET_MULTIPLE_DTIM 10
+#define WLAN_SET_ATIM_WINDOW 11
+#define WLANSETBCNAVG 13
+#define WLANSETDATAAVG 14
+#define WLAN_SET_LINKMODE 15
+#define WLAN_SET_RADIOMODE 16
+#define WLAN_SET_DEBUGMODE 17
+#define WLAN_SUBCMD_MESH_SET_TTL 18
+
+#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25)
+#define WLANSCAN_MODE 6
+
+#define WLAN_GET_ADHOC_STATUS 9
+
+#define WLAN_SUBCMD_BT_ADD 18
+#define WLAN_SUBCMD_BT_DEL 19
+#define WLAN_SUBCMD_BT_LIST 20
+#define WLAN_SUBCMD_FWT_ADD 21
+#define WLAN_SUBCMD_FWT_DEL 22
+#define WLAN_SUBCMD_FWT_LOOKUP 23
+#define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24
+#define WLAN_SUBCMD_FWT_LIST 25
+#define WLAN_SUBCMD_FWT_LIST_ROUTE 26
+
+#define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29)
+#define WLAN_TPCCFG 1
+#define WLAN_POWERCFG 2
+
+#define WLAN_AUTO_FREQ_SET 3
+#define WLAN_AUTO_FREQ_GET 4
+#define WLAN_LED_GPIO_CTRL 5
+#define WLAN_SCANPROBES 6
+#define WLAN_ADAPT_RATESET 8
+#define WLAN_INACTIVITY_TIMEOUT 9
+#define WLANSNR 10
+#define WLAN_GET_RATE 11
+#define WLAN_GET_RXINFO 12
+
+#define WLANCMD52RDWR (WLANIOCTL + 30)
+#define WLANCMD53RDWR (WLANIOCTL + 31)
+#define CMD53BUFLEN 32
+
+#define REG_MAC 0x19
+#define REG_BBP 0x1a
+#define REG_RF 0x1b
+#define REG_EEPROM 0x59
+#define WLAN_LINKMODE_802_3 0
+#define WLAN_LINKMODE_802_11 2
+#define WLAN_RADIOMODE_NONE 0
+#define WLAN_RADIOMODE_RADIOTAP 2
+
+/** wlan_ioctl_regrdwr */
+struct wlan_ioctl_regrdwr {
+ /** Which register to access */
+ u16 whichreg;
+ /** Read or Write */
+ u16 action;
+ u32 offset;
+ u16 NOB;
+ u32 value;
+};
+
+extern struct iw_handler_def libertas_handler_def;
+int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i);
+int wlan_radio_ioctl(wlan_private * priv, u8 option);
+
+#endif /* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 841b3c136ad..283be4a7052 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -3054,7 +3054,7 @@ static const iw_handler prism54_handler[] = {
(iw_handler) prism54_set_wap, /* SIOCSIWAP */
(iw_handler) prism54_get_wap, /* SIOCGIWAP */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */
+ (iw_handler) NULL, /* SIOCGIWAPLIST deprecated */
(iw_handler) prism54_set_scan, /* SIOCSIWSCAN */
(iw_handler) prism54_get_scan, /* SIOCGIWSCAN */
(iw_handler) prism54_set_essid, /* SIOCSIWESSID */
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index a037b11dac9..084795355b7 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -115,7 +115,7 @@ isl_upload_firmware(islpci_private *priv)
ISL38XX_MEMORY_WINDOW_SIZE : fw_len;
u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;
- /* set the cards base address for writting the data */
+ /* set the card's base address for writing the data */
isl38xx_w32_flush(device_base, reg,
ISL38XX_DIR_MEM_BASE_REG);
wmb(); /* be paranoid */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 2a299a0676a..ef32a5c1e81 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1971,8 +1971,7 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
sizeof(zero_address))) {
struct net_device *dev;
read_lock_bh(&dev_base_lock);
- dev = dev_base;
- while (dev) {
+ for_each_netdev(dev) {
if (dev->type == strip_info->dev->type &&
!memcmp(dev->dev_addr,
&strip_info->true_dev_addr,
@@ -1983,7 +1982,6 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
read_unlock_bh(&dev_base_lock);
return (dev);
}
- dev = dev->next;
}
read_unlock_bh(&dev_base_lock);
}
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt
deleted file mode 100644
index 32234018de7..00000000000
--- a/drivers/net/wireless/todo.txt
+++ /dev/null
@@ -1,15 +0,0 @@
- Wireless Todo
- -------------
-
-1) Bring other kernel Wireless LAN drivers here
- Completed
-
-2) Bring new Wireless LAN driver not yet in the kernel there
- See my web page for details
- In particular : HostAP
-
-3) Misc
- o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete
- o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete
-
- Jean II
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 67b867f837c..5740d4d4267 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -176,7 +176,7 @@ psa_write(struct net_device * dev,
volatile u_char __iomem *verify = lp->mem + PSA_ADDR +
(psaoff(0, psa_comp_number) << 1);
- /* Authorize writting to PSA */
+ /* Authorize writing to PSA */
hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
while(n-- > 0)
@@ -1676,7 +1676,7 @@ wv_set_frequency(u_long base, /* i/o port of the card */
fee_write(base, 0x60,
dac, 2);
- /* We now should verify here that the EEprom writting was ok */
+ /* We now should verify here that the EEprom writing was ok */
/* ReRead the first area */
fee_read(base, 0x00,
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index 4d1c4905c74..4b9de0093a7 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -120,7 +120,7 @@
* the Wavelan itself (NCR -> AT&T -> Lucent).
*
* All started with Anders Klemets <klemets@paul.rutgers.edu>,
- * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * writing a Wavelan ISA driver for the MACH microkernel. Girish
* Welling <welling@paul.rutgers.edu> had also worked on it.
* Keith Moore modify this for the Pcmcia hardware.
*
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 87ee3ee020f..95b4a2a2670 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -67,11 +67,12 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
- i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
+ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
chip->patch_cck_gain ? 'g' : '-',
chip->patch_cr157 ? '7' : '-',
chip->patch_6m_band_edge ? '6' : '-',
- chip->new_phy_layout ? 'N' : '-');
+ chip->new_phy_layout ? 'N' : '-',
+ chip->al2230s_bit ? 'S' : '-');
return i;
}
@@ -114,7 +115,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
- GFP_NOFS);
+ GFP_KERNEL);
if (!a16) {
dev_dbg_f(zd_chip_dev(chip),
"error ENOMEM in allocation of a16\n");
@@ -163,7 +164,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
/* Allocate a single memory block for values and addresses. */
count16 = 2*count;
- ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+ ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL);
if (!ioreqs16) {
r = -ENOMEM;
dev_dbg_f(zd_chip_dev(chip),
@@ -614,16 +615,24 @@ static int patch_cr157(struct zd_chip *chip)
* Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
* bit (for AL2230, AL2230S)
*/
-static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+static int patch_6m_band_edge(struct zd_chip *chip, u8 channel)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ if (!chip->patch_6m_band_edge)
+ return 0;
+
+ return zd_rf_patch_6m_band_edge(&chip->rf, channel);
+}
+
+/* Generic implementation of 6M band edge patching, used by most RFs via
+ * zd_rf_generic_patch_6m() */
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
{
struct zd_ioreq16 ioreqs[] = {
{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
{ CR47, 0x1e },
};
- if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
- return 0;
-
/* FIXME: Channel 11 is not the edge for all regulatory domains. */
if (channel == 1 || channel == 11)
ioreqs[0].value = 0x12;
@@ -683,17 +692,17 @@ static int zd1211_hw_reset_phy(struct zd_chip *chip)
{ CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
{ CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
{ CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
- { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
- { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
- { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
- { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
- { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
- { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
- { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
- { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
- { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+ { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 },
+ { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C },
+ { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 },
+ { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 },
+ { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c },
+ { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 },
+ { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe },
+ { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+ { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+ { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+ { CR170, 0xba }, { CR171, 0xba },
/* Note: CR204 must lead the CR203 */
{ CR204, 0x7d },
{ },
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index e57ed75d942..ce0a5f6da0d 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -833,6 +833,7 @@ int zd_chip_enable_rx(struct zd_chip *chip);
void zd_chip_disable_rx(struct zd_chip *chip);
int zd_chip_enable_hwint(struct zd_chip *chip);
int zd_chip_disable_hwint(struct zd_chip *chip);
+int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel);
int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip,
u8 rts_rate, int preamble);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 4c5f78eac34..6753d240c16 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -156,17 +156,8 @@ void zd_mac_clear(struct zd_mac *mac)
static int reset_mode(struct zd_mac *mac)
{
struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
- struct zd_ioreq32 ioreqs[] = {
- { CR_RX_FILTER, STA_RX_FILTER },
- { CR_SNIFFER_ON, 0U },
- };
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- ioreqs[0].value = 0xffffffff;
- ioreqs[1].value = 0x1;
- }
-
- return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs));
+ u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
+ return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
}
int zd_mac_open(struct net_device *netdev)
@@ -974,14 +965,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
switch (ieee->iw_mode) {
case IW_MODE_ADHOC:
if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
- memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+ compare_ether_addr(hdr->addr3, ieee->bssid) != 0)
return 0;
break;
case IW_MODE_AUTO:
case IW_MODE_INFRA:
if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
IEEE80211_FCTL_FROMDS ||
- memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+ compare_ether_addr(hdr->addr2, ieee->bssid) != 0)
return 0;
break;
default:
@@ -989,9 +980,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee,
return 0;
}
- return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+ return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 ||
(is_multicast_ether_addr(hdr->addr1) &&
- memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) ||
+ compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) ||
(netdev->flags & IFF_PROMISC);
}
@@ -1047,7 +1038,7 @@ static void update_qual_rssi(struct zd_mac *mac,
hdr = (struct ieee80211_hdr_3addr *)buffer;
if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
return;
- if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+ if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0)
return;
spin_lock_irqsave(&mac->lock, flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index f50cff3db91..549c23bcd6c 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -23,7 +23,7 @@
#include "zd_ieee80211.h"
#include "zd_chip.h"
-static const char *rfs[] = {
+static const char * const rfs[] = {
[0] = "unknown RF0",
[1] = "unknown RF1",
[UW2451_RF] = "UW2451_RF",
@@ -34,7 +34,7 @@ static const char *rfs[] = {
[AL2210_RF] = "AL2210_RF",
[MAXIM_NEW_RF] = "MAXIM_NEW_RF",
[UW2453_RF] = "UW2453_RF",
- [AL2230S_RF] = "AL2230S_RF",
+ [UNKNOWN_A_RF] = "UNKNOWN_A_RF",
[RALINK_RF] = "RALINK_RF",
[INTERSIL_RF] = "INTERSIL_RF",
[RF2959_RF] = "RF2959_RF",
@@ -154,3 +154,17 @@ int zd_switch_radio_off(struct zd_rf *rf)
r = t;
return r;
}
+
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel)
+{
+ if (!rf->patch_6m_band_edge)
+ return 0;
+
+ return rf->patch_6m_band_edge(rf, channel);
+}
+
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel)
+{
+ return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel);
+}
+
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index a57732eb69e..aa9cc105ce6 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -26,7 +26,7 @@
#define AL2210_RF 0x7
#define MAXIM_NEW_RF 0x8
#define UW2453_RF 0x9
-#define AL2230S_RF 0xa
+#define UNKNOWN_A_RF 0xa
#define RALINK_RF 0xb
#define INTERSIL_RF 0xc
#define RF2959_RF 0xd
@@ -47,17 +47,13 @@ struct zd_rf {
u8 type;
u8 channel;
- /*
- * Whether this RF should patch the 6M band edge
- * (assuming E2P_POD agrees)
- */
- u8 patch_6m_band_edge:1;
/* RF-specific functions */
int (*init_hw)(struct zd_rf *rf);
int (*set_channel)(struct zd_rf *rf, u8 channel);
int (*switch_radio_on)(struct zd_rf *rf);
int (*switch_radio_off)(struct zd_rf *rf);
+ int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel);
};
const char *zd_rf_name(u8 type);
@@ -72,6 +68,9 @@ int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
int zd_switch_radio_on(struct zd_rf *rf);
int zd_switch_radio_off(struct zd_rf *rf);
+int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel);
+int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel);
+
/* Functions for individual RF chips */
int zd_rf_init_rf2959(struct zd_rf *rf);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 5235a7827ac..511392acfed 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
{ CR240, 0x57 }, { CR9, 0xe0 },
};
+static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
+ { CR47, 0x1e }, /* MARK_002 */
+ { CR106, 0x22 },
+ { CR107, 0x2a }, /* MARK_002 */
+ { CR109, 0x13 }, /* MARK_002 */
+ { CR118, 0xf8 }, /* MARK_002 */
+ { CR119, 0x12 }, { CR122, 0xe0 },
+ { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */
+ { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */
+ { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */
+};
+
static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
{
int r;
@@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
int r;
struct zd_chip *chip = zd_rf_to_chip(rf);
- static const struct zd_ioreq16 ioreqs[] = {
+ static const struct zd_ioreq16 ioreqs_init[] = {
{ CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
{ CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
{ CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
@@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
{ CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
{ CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
{ CR253, 0xff },
+ };
- /* These following happen separately in the vendor driver */
- { },
-
+ static const struct zd_ioreq16 ioreqs_pll[] = {
/* shdnb(PLL_ON)=0 */
{ CR251, 0x2f },
/* shdnb(PLL_ON)=1 */
@@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
{ CR138, 0x28 }, { CR203, 0x06 },
};
- static const u32 rv[] = {
+ static const u32 rv1[] = {
/* Channel 1 */
0x03f790,
0x033331,
@@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x0b3331,
0x03b812,
0x00fff3,
+ };
+
+ static const u32 rv2[] = {
0x000da4,
0x0f4dc5, /* fix freq shift, 0x04edc5 */
0x0805b6,
@@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x0bdffc,
0x00000d,
0x00500f,
+ };
- /* These writes happen separately in the vendor driver */
+ static const u32 rv3[] = {
0x00d00f,
0x004c0f,
0x00540f,
@@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x00500f,
};
- r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init));
if (r)
return r;
- r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+ if (chip->al2230s_bit) {
+ r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+ ARRAY_SIZE(ioreqs_init_al2230s));
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS);
+ if (r)
+ return r;
+
+ /* improve band edge for AL2230S */
+ if (chip->al2230s_bit)
+ r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
+ else
+ r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS);
if (r)
return r;
@@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
0x481dc0,
0xcfff00,
0x25a000,
+ };
+ static const u32 rv2[] = {
/* To improve AL2230 yield, improve phase noise, 4713 */
0x25a000,
0xa3b2f0,
@@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
{ CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
};
- static const u32 rv2[] = {
+ static const u32 rv3[] = {
/* To improve AL2230 yield, 4713 */
0xf01b00,
0xf01e00,
@@ -269,18 +313,37 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
if (r)
return r;
+
+ if (chip->al2230s_bit) {
+ r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
+ ARRAY_SIZE(ioreqs_init_al2230s));
+ if (r)
+ return r;
+ }
+
r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
if (r)
return r;
r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
if (r)
return r;
- r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+
+ if (chip->al2230s_bit)
+ r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
+ else
+ r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
if (r)
return r;
+
r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
if (r)
return r;
+ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3));
+ if (r)
+ return r;
r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
if (r)
return r;
@@ -358,12 +421,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
- if (chip->al2230s_bit) {
- dev_err(zd_chip_dev(chip), "AL2230S devices are not yet "
- "supported by this driver.\n");
- return -ENODEV;
- }
-
rf->switch_radio_off = al2230_switch_radio_off;
if (chip->is_zd1211b) {
rf->init_hw = zd1211b_al2230_init_hw;
@@ -374,6 +431,6 @@ int zd_rf_init_al2230(struct zd_rf *rf)
rf->set_channel = zd1211_al2230_set_channel;
rf->switch_radio_on = zd1211_al2230_switch_radio_on;
}
- rf->patch_6m_band_edge = 1;
+ rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index a289f95187e..5e5e9ddc6a7 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -51,9 +51,52 @@ static const u32 std_rv[] = {
0xd8c010,
};
-static int al7230b_init_hw(struct zd_rf *rf)
+static const u32 rv_init1[] = {
+ 0x3c9000,
+ 0xbfffff,
+ 0x700000,
+ 0xf15d58,
+};
+
+static const u32 rv_init2[] = {
+ 0xf15d59,
+ 0xf15d5c,
+ 0xf15d58,
+};
+
+static const struct zd_ioreq16 ioreqs_sw[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+};
+
+static int zd1211b_al7230b_finalize(struct zd_chip *chip)
{
- int i, r;
+ int r;
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
+ { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
+ { CR203, 0x04 },
+ { },
+ { CR240, 0x80 },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ if (chip->new_phy_layout) {
+ /* antenna selection? */
+ r = zd_iowrite16_locked(chip, 0xe5, CR9);
+ if (r)
+ return r;
+ }
+
+ return zd_iowrite16_locked(chip, 0x04, CR203);
+}
+
+static int zd1211_al7230b_init_hw(struct zd_rf *rf)
+{
+ int r;
struct zd_chip *chip = zd_rf_to_chip(rf);
/* All of these writes are identical to AL2230 unless otherwise
@@ -117,39 +160,136 @@ static int al7230b_init_hw(struct zd_rf *rf)
};
static const struct zd_ioreq16 ioreqs_2[] = {
- /* PLL_ON */
- { CR251, 0x3f },
+ { CR251, 0x3f }, /* PLL_ON */
{ CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
+ { CR38, 0x38 }, { CR136, 0xdf },
};
r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+ r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
if (r)
return r;
- for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
- r = zd_rfwrite_cr_locked(chip, std_rv[i]);
- if (r)
- return r;
- }
+ r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
+ if (r)
+ return r;
- r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+
+ r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0x700000);
+
+ r = zd_iowrite16_locked(chip, 0x06, CR203);
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ r = zd_iowrite16_locked(chip, 0x80, CR240);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int zd1211b_al7230b_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs_1[] = {
+ { CR240, 0x57 }, { CR9, 0x9 },
+ { },
+ { CR10, 0x8b }, { CR15, 0x20 },
+ { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */
+ { CR20, 0x10 }, /* 4N25->Stone Request */
+ { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
+ { CR28, 0x3e }, { CR29, 0x00 },
+ { CR33, 0x28 }, /* 5613 */
+ { CR34, 0x30 },
+ { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */
+ { CR41, 0x24 }, { CR44, 0x32 },
+ { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */
+ { CR47, 0x1e },
+
+ /* ZD1215 5610 */
+ { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
+ { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
+ { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
+ { CR69, 0x28 },
+
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR87, 0x0A }, { CR89, 0x04 },
+ { CR90, 0x58 }, /* 5112 */
+ { CR91, 0x00 }, /* 5613 */
+ { CR92, 0x0a },
+ { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 },
+ { CR102, 0x27 },
+ { CR106, 0x20 }, /* change to 0x24 for AL7230B */
+ { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { CR112, 0x1f },
+ };
+
+ static const struct zd_ioreq16 ioreqs_new_phy[] = {
+ { CR107, 0x28 },
+ { CR110, 0x1f }, /* 5127, 0x13->0x1f */
+ { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
+ { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 },
+ { CR121, 0x6c }, /* 5613 */
+ };
+
+ static const struct zd_ioreq16 ioreqs_old_phy[] = {
+ { CR107, 0x24 },
+ { CR110, 0x13 }, /* 5127, 0x13->0x1f */
+ { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
+ { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 },
+ { CR121, 0x6a }, /* 5613 */
+ };
+
+ static const struct zd_ioreq16 ioreqs_2[] = {
+ { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 },
+ { CR117, 0xfa }, { CR120, 0x4f },
+ { CR122, 0xfc }, /* E0->FCh at 4901 */
+ { CR123, 0x57 }, /* 5613 */
+ { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { CR126, 0x6c }, /* 5613 */
+ { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { CR130, 0x10 },
+ { CR131, 0x00 }, /* 5112 */
+ { CR137, 0x50 }, /* 5613 */
+ { CR138, 0xa8 }, /* 5112 */
+ { CR144, 0xac }, /* 5613 */
+ { CR148, 0x40 }, /* 5112 */
+ { CR149, 0x40 }, /* 4O07, 50->40 */
+ { CR150, 0x1a }, /* 5112, 0C->1A */
+ { CR252, 0x34 }, { CR253, 0x34 },
+ { CR251, 0x2f }, /* PLL_OFF */
+ };
+
+ static const struct zd_ioreq16 ioreqs_3[] = {
+ { CR251, 0x7f }, /* PLL_ON */
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ if (r)
+ return r;
+
+ if (chip->new_phy_layout)
+ r = zd_iowrite16a_locked(chip, ioreqs_new_phy,
+ ARRAY_SIZE(ioreqs_new_phy));
+ else
+ r = zd_iowrite16a_locked(chip, ioreqs_old_phy,
+ ARRAY_SIZE(ioreqs_old_phy));
if (r)
return r;
@@ -157,38 +297,36 @@ static int al7230b_init_hw(struct zd_rf *rf)
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+ r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0]));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
if (r)
return r;
- r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+
+ r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1));
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x06, CR203);
+ r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3));
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x80, CR240);
+
+ r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2));
if (r)
return r;
- return 0;
+ return zd1211b_al7230b_finalize(chip);
}
-static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel)
{
- int i, r;
+ int r;
const u32 *rv = chan_rv[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
- struct zd_ioreq16 ioreqs_1[] = {
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
- };
-
- struct zd_ioreq16 ioreqs_2[] = {
+ static const struct zd_ioreq16 ioreqs[] = {
/* PLL_ON */
{ CR251, 0x3f },
{ CR203, 0x06 }, { CR240, 0x08 },
@@ -203,11 +341,9 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
if (r)
return r;
- for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
- r = zd_rfwrite_cr_locked(chip, std_rv[i]);
- if (r)
- return r;
- }
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+ if (r)
+ return r;
r = zd_rfwrite_cr_locked(chip, 0x3c9000);
if (r)
@@ -216,24 +352,69 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
if (r)
return r;
- r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
if (r)
return r;
- for (i = 0; i < 2; i++) {
- r = zd_rfwrite_cr_locked(chip, rv[i]);
- if (r)
- return r;
- }
+ r = zd_rfwritev_cr_locked(chip, rv, 2);
+ if (r)
+ return r;
r = zd_rfwrite_cr_locked(chip, 0x3c9000);
if (r)
return r;
- return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
-static int al7230b_switch_radio_on(struct zd_rf *rf)
+static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = chan_rv[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ r = zd_iowrite16_locked(chip, 0x57, CR240);
+ if (r)
+ return r;
+ r = zd_iowrite16_locked(chip, 0xe4, CR9);
+ if (r)
+ return r;
+
+ /* PLL_OFF */
+ r = zd_iowrite16_locked(chip, 0x2f, CR251);
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_cr_locked(chip, rv, 2);
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+
+ r = zd_iowrite16_locked(chip, 0x7f, CR251);
+ if (r)
+ return r;
+
+ return zd1211b_al7230b_finalize(chip);
+}
+
+static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
@@ -244,6 +425,17 @@ static int al7230b_switch_radio_on(struct zd_rf *rf)
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
+static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x7f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
static int al7230b_switch_radio_off(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -255,20 +447,45 @@ static int al7230b_switch_radio_off(struct zd_rf *rf)
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
+/* ZD1211B+AL7230B 6m band edge patching differs slightly from other
+ * configurations */
+static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ struct zd_ioreq16 ioreqs[] = {
+ { CR128, 0x14 }, { CR129, 0x12 },
+ };
+
+ /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+ if (channel == 1) {
+ ioreqs[0].value = 0x0e;
+ ioreqs[1].value = 0x10;
+ } else if (channel == 11) {
+ ioreqs[0].value = 0x10;
+ ioreqs[1].value = 0x10;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
int zd_rf_init_al7230b(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
if (chip->is_zd1211b) {
- dev_err(zd_chip_dev(chip), "AL7230B is currently not "
- "supported for ZD1211B devices\n");
- return -ENODEV;
+ rf->init_hw = zd1211b_al7230b_init_hw;
+ rf->switch_radio_on = zd1211b_al7230b_switch_radio_on;
+ rf->set_channel = zd1211b_al7230b_set_channel;
+ rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m;
+ } else {
+ rf->init_hw = zd1211_al7230b_init_hw;
+ rf->switch_radio_on = zd1211_al7230b_switch_radio_on;
+ rf->set_channel = zd1211_al7230b_set_channel;
+ rf->patch_6m_band_edge = zd_rf_generic_patch_6m;
}
- rf->init_hw = al7230b_init_hw;
- rf->set_channel = al7230b_set_channel;
- rf->switch_radio_on = al7230b_switch_radio_on;
rf->switch_radio_off = al7230b_switch_radio_off;
- rf->patch_6m_band_edge = 1;
+
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index 58247271cc2..2d736bdf707 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -21,7 +21,7 @@
#include "zd_usb.h"
#include "zd_chip.h"
-static u32 rf2959_table[][2] = {
+static const u32 rf2959_table[][2] = {
RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
@@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *rf)
static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
{
int i, r;
- u32 *rv = rf2959_table[channel-1];
+ const u32 *rv = rf2959_table[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
for (i = 0; i < 2; i++) {
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index edaaad2f648..e04cffc8adf 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -52,6 +52,7 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 },
{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
/* ZD1211B */
{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -62,7 +63,10 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{}
@@ -413,7 +417,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
dev_dbg_f(zd_usb_dev(usb), "\n");
- urb = usb_alloc_urb(0, GFP_NOFS);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
r = -ENOMEM;
goto out;
@@ -431,7 +435,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
/* TODO: make it a DMA buffer */
r = -ENOMEM;
- transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+ transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL);
if (!transfer_buffer) {
dev_dbg_f(zd_usb_dev(usb),
"couldn't allocate transfer_buffer\n");
@@ -445,7 +449,7 @@ int zd_usb_enable_int(struct zd_usb *usb)
intr->interval);
dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
- r = usb_submit_urb(urb, GFP_NOFS);
+ r = usb_submit_urb(urb, GFP_KERNEL);
if (r) {
dev_dbg_f(zd_usb_dev(usb),
"Couldn't submit urb. Error number %d\n", r);
@@ -594,10 +598,10 @@ static struct urb *alloc_urb(struct zd_usb *usb)
struct urb *urb;
void *buffer;
- urb = usb_alloc_urb(0, GFP_NOFS);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return NULL;
- buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+ buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
&urb->transfer_dma);
if (!buffer) {
usb_free_urb(urb);
@@ -630,7 +634,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
dev_dbg_f(zd_usb_dev(usb), "\n");
r = -ENOMEM;
- urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+ urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL);
if (!urbs)
goto error;
for (i = 0; i < URBS_COUNT; i++) {
@@ -651,7 +655,7 @@ int zd_usb_enable_rx(struct zd_usb *usb)
spin_unlock_irq(&rx->lock);
for (i = 0; i < URBS_COUNT; i++) {
- r = usb_submit_urb(urbs[i], GFP_NOFS);
+ r = usb_submit_urb(urbs[i], GFP_KERNEL);
if (r)
goto error_submit;
}
@@ -1157,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
}
req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
- req = kmalloc(req_len, GFP_NOFS);
+ req = kmalloc(req_len, GFP_KERNEL);
if (!req)
return -ENOMEM;
req->id = cpu_to_le16(USB_REQ_READ_REGS);
@@ -1220,7 +1224,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
req_len = sizeof(struct usb_req_write_regs) +
count * sizeof(struct reg_data);
- req = kmalloc(req_len, GFP_NOFS);
+ req = kmalloc(req_len, GFP_KERNEL);
if (!req)
return -ENOMEM;
@@ -1300,7 +1304,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
- req = kmalloc(req_len, GFP_NOFS);
+ req = kmalloc(req_len, GFP_KERNEL);
if (!req)
return -ENOMEM;
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 3f4a7cf9efe..f2a90a7fa2d 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -109,7 +109,6 @@ static int gx_fix;
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
KERN_INFO DRV_NAME ".c:v1.05 1/09/2001 Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO " http://www.scyld.com/network/yellowfin.html\n"
KERN_INFO " (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 9bb4db552f3..a68b3b3761a 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -22,8 +22,6 @@
#include <asm/hardware.h>
#include <asm/parisc-device.h>
-#include <linux/pci.h>
-
struct hppb_card {
unsigned long hpa;
struct resource mmio_region;
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 21c4c299b3d..5b86ee5c1ee 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -38,7 +38,6 @@
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <asm/byteorder.h>
#include <asm/pdc.h>
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 453e6829756..98be2880757 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -365,7 +365,7 @@ static __inline__ int led_get_net_activity(void)
* for reading should be OK */
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
struct net_device_stats *stats;
struct in_device *in_dev = __in_dev_get_rcu(dev);
if (!in_dev || !in_dev->ifa_list)
@@ -373,8 +373,6 @@ static __inline__ int led_get_net_activity(void)
if (LOOPBACK(in_dev->ifa_list->ifa_local))
continue;
stats = dev->get_stats(dev);
- if (!stats)
- continue;
rx_total += stats->rx_packets;
tx_total += stats->tx_packets;
}
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index ea1b7a63598..815e445c312 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -520,17 +520,17 @@ static struct pdcspath_entry *pdcspath_entries[] = {
/**
* pdcs_size_read - Stable Storage size output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*/
static ssize_t
-pdcs_size_read(struct subsystem *entry, char *buf)
+pdcs_size_read(struct kset *kset, char *buf)
{
char *out = buf;
-
- if (!entry || !buf)
+
+ if (!kset || !buf)
return -EINVAL;
-
+
/* show the size of the stable storage */
out += sprintf(out, "%ld\n", pdcs_size);
@@ -539,17 +539,17 @@ pdcs_size_read(struct subsystem *entry, char *buf)
/**
* pdcs_auto_read - Stable Storage autoboot/search flag output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
* @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
*/
static ssize_t
-pdcs_auto_read(struct subsystem *entry, char *buf, int knob)
+pdcs_auto_read(struct kset *kset, char *buf, int knob)
{
char *out = buf;
struct pdcspath_entry *pathentry;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
/* Current flags are stored in primary boot path entry */
@@ -565,40 +565,40 @@ pdcs_auto_read(struct subsystem *entry, char *buf, int knob)
/**
* pdcs_autoboot_read - Stable Storage autoboot flag output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*/
static inline ssize_t
-pdcs_autoboot_read(struct subsystem *entry, char *buf)
+pdcs_autoboot_read(struct kset *kset, char *buf)
{
- return pdcs_auto_read(entry, buf, PF_AUTOBOOT);
+ return pdcs_auto_read(kset, buf, PF_AUTOBOOT);
}
/**
* pdcs_autosearch_read - Stable Storage autoboot flag output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*/
static inline ssize_t
-pdcs_autosearch_read(struct subsystem *entry, char *buf)
+pdcs_autosearch_read(struct kset *kset, char *buf)
{
- return pdcs_auto_read(entry, buf, PF_AUTOSEARCH);
+ return pdcs_auto_read(kset, buf, PF_AUTOSEARCH);
}
/**
* pdcs_timer_read - Stable Storage timer count output (in seconds).
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*
* The value of the timer field correponds to a number of seconds in powers of 2.
*/
static ssize_t
-pdcs_timer_read(struct subsystem *entry, char *buf)
+pdcs_timer_read(struct kset *kset, char *buf)
{
char *out = buf;
struct pdcspath_entry *pathentry;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
/* Current flags are stored in primary boot path entry */
@@ -615,15 +615,15 @@ pdcs_timer_read(struct subsystem *entry, char *buf)
/**
* pdcs_osid_read - Stable Storage OS ID register output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*/
static ssize_t
-pdcs_osid_read(struct subsystem *entry, char *buf)
+pdcs_osid_read(struct kset *kset, char *buf)
{
char *out = buf;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
out += sprintf(out, "%s dependent data (0x%.4x)\n",
@@ -634,18 +634,18 @@ pdcs_osid_read(struct subsystem *entry, char *buf)
/**
* pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*
* This can hold 16 bytes of OS-Dependent data.
*/
static ssize_t
-pdcs_osdep1_read(struct subsystem *entry, char *buf)
+pdcs_osdep1_read(struct kset *kset, char *buf)
{
char *out = buf;
u32 result[4];
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
@@ -661,18 +661,18 @@ pdcs_osdep1_read(struct subsystem *entry, char *buf)
/**
* pdcs_diagnostic_read - Stable Storage Diagnostic register output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*
* I have NFC how to interpret the content of that register ;-).
*/
static ssize_t
-pdcs_diagnostic_read(struct subsystem *entry, char *buf)
+pdcs_diagnostic_read(struct kset *kset, char *buf)
{
char *out = buf;
u32 result;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
/* get diagnostic */
@@ -686,18 +686,18 @@ pdcs_diagnostic_read(struct subsystem *entry, char *buf)
/**
* pdcs_fastsize_read - Stable Storage FastSize register output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*
* This register holds the amount of system RAM to be tested during boot sequence.
*/
static ssize_t
-pdcs_fastsize_read(struct subsystem *entry, char *buf)
+pdcs_fastsize_read(struct kset *kset, char *buf)
{
char *out = buf;
u32 result;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
/* get fast-size */
@@ -715,13 +715,13 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf)
/**
* pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The output buffer to write to.
*
* This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
*/
static ssize_t
-pdcs_osdep2_read(struct subsystem *entry, char *buf)
+pdcs_osdep2_read(struct kset *kset, char *buf)
{
char *out = buf;
unsigned long size;
@@ -733,7 +733,7 @@ pdcs_osdep2_read(struct subsystem *entry, char *buf)
size = pdcs_size - 224;
- if (!entry || !buf)
+ if (!kset || !buf)
return -EINVAL;
for (i=0; i<size; i+=4) {
@@ -748,7 +748,7 @@ pdcs_osdep2_read(struct subsystem *entry, char *buf)
/**
* pdcs_auto_write - This function handles autoboot/search flag modifying.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
* @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
@@ -758,7 +758,7 @@ pdcs_osdep2_read(struct subsystem *entry, char *buf)
* \"n\" (n == 0 or 1) to toggle AutoBoot Off or On
*/
static ssize_t
-pdcs_auto_write(struct subsystem *entry, const char *buf, size_t count, int knob)
+pdcs_auto_write(struct kset *kset, const char *buf, size_t count, int knob)
{
struct pdcspath_entry *pathentry;
unsigned char flags;
@@ -768,7 +768,7 @@ pdcs_auto_write(struct subsystem *entry, const char *buf, size_t count, int knob
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (!entry || !buf || !count)
+ if (!kset || !buf || !count)
return -EINVAL;
/* We'll use a local copy of buf */
@@ -823,7 +823,7 @@ parse_error:
/**
* pdcs_autoboot_write - This function handles autoboot flag modifying.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -832,14 +832,14 @@ parse_error:
* \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
*/
static inline ssize_t
-pdcs_autoboot_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_autoboot_write(struct kset *kset, const char *buf, size_t count)
{
- return pdcs_auto_write(entry, buf, count, PF_AUTOBOOT);
+ return pdcs_auto_write(kset, buf, count, PF_AUTOBOOT);
}
/**
* pdcs_autosearch_write - This function handles autosearch flag modifying.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -848,14 +848,14 @@ pdcs_autoboot_write(struct subsystem *entry, const char *buf, size_t count)
* \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
*/
static inline ssize_t
-pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_autosearch_write(struct kset *kset, const char *buf, size_t count)
{
- return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
+ return pdcs_auto_write(kset, buf, count, PF_AUTOSEARCH);
}
/**
* pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -864,14 +864,14 @@ pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
* its input buffer.
*/
static ssize_t
-pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_osdep1_write(struct kset *kset, const char *buf, size_t count)
{
u8 in[16];
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (!entry || !buf || !count)
+ if (!kset || !buf || !count)
return -EINVAL;
if (unlikely(pdcs_osid != OS_ID_LINUX))
@@ -892,7 +892,7 @@ pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
/**
* pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
- * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @kset: An allocated and populated struct kset. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -901,7 +901,7 @@ pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
* constructing its input buffer.
*/
static ssize_t
-pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_osdep2_write(struct kset *kset, const char *buf, size_t count)
{
unsigned long size;
unsigned short i;
@@ -910,7 +910,7 @@ pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- if (!entry || !buf || !count)
+ if (!kset || !buf || !count)
return -EINVAL;
if (unlikely(pdcs_size <= 224))
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 316c06f4423..8b7d84eca05 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -201,7 +201,7 @@ static int parport_config(struct pcmcia_device *link)
p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
link->irq.AssignedIRQ, PARPORT_DMA_NONE,
- NULL);
+ &link->dev);
if (p == NULL) {
printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
"0x%3x, irq %u failed\n", link->io.BasePort1,
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index e5b0a544de4..77726fc4976 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -356,6 +356,7 @@ static int __init parport_mfc3_init(void)
if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, IRQF_SHARED, p->name, &pp_mfc3_ops))
goto out_irq;
}
+ p->dev = &z->dev;
this_port[pias++] = p;
printk(KERN_INFO "%s: Multiface III port using irq\n", p->name);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 3de2623afa1..02c0d52c9f7 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -53,6 +53,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pnp.h>
+#include <linux/platform_device.h>
#include <linux/sysctl.h>
#include <asm/io.h>
@@ -620,6 +621,7 @@ static size_t parport_pc_fifo_write_block_dma (struct parport *port,
unsigned long dmaflag;
size_t left = length;
const struct parport_pc_private *priv = port->physport->private_data;
+ struct device *dev = port->physport->dev;
dma_addr_t dma_addr, dma_handle;
size_t maxlen = 0x10000; /* max 64k per DMA transfer */
unsigned long start = (unsigned long) buf;
@@ -631,8 +633,8 @@ dump_parport_state ("enter fifo_write_block_dma", port);
if ((start ^ end) & ~0xffffUL)
maxlen = 0x10000 - (start & 0xffff);
- dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length,
- PCI_DMA_TODEVICE);
+ dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length,
+ DMA_TO_DEVICE);
} else {
/* above 16 MB we use a bounce buffer as ISA-DMA is not possible */
maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */
@@ -728,9 +730,9 @@ dump_parport_state ("enter fifo_write_block_dma", port);
/* Turn off DMA mode */
frob_econtrol (port, 1<<3, 0);
-
+
if (dma_handle)
- pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE);
+ dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE);
dump_parport_state ("leave fifo_write_block_dma", port);
return length - left;
@@ -2146,7 +2148,7 @@ static DEFINE_SPINLOCK(ports_lock);
struct parport *parport_pc_probe_port (unsigned long int base,
unsigned long int base_hi,
int irq, int dma,
- struct pci_dev *dev)
+ struct device *dev)
{
struct parport_pc_private *priv;
struct parport_operations *ops;
@@ -2155,6 +2157,17 @@ struct parport *parport_pc_probe_port (unsigned long int base,
struct resource *base_res;
struct resource *ECR_res = NULL;
struct resource *EPP_res = NULL;
+ struct platform_device *pdev = NULL;
+
+ if (!dev) {
+ /* We need a physical device to attach to, but none was
+ * provided. Create our own. */
+ pdev = platform_device_register_simple("parport_pc",
+ base, NULL, 0);
+ if (IS_ERR(pdev))
+ return NULL;
+ dev = &pdev->dev;
+ }
ops = kmalloc(sizeof (struct parport_operations), GFP_KERNEL);
if (!ops)
@@ -2180,9 +2193,10 @@ struct parport *parport_pc_probe_port (unsigned long int base,
priv->fifo_depth = 0;
priv->dma_buf = NULL;
priv->dma_handle = 0;
- priv->dev = dev;
INIT_LIST_HEAD(&priv->list);
priv->port = p;
+
+ p->dev = dev;
p->base_hi = base_hi;
p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
p->private_data = priv;
@@ -2305,9 +2319,10 @@ struct parport *parport_pc_probe_port (unsigned long int base,
p->dma = PARPORT_DMA_NONE;
} else {
priv->dma_buf =
- pci_alloc_consistent(priv->dev,
+ dma_alloc_coherent(dev,
PAGE_SIZE,
- &priv->dma_handle);
+ &priv->dma_handle,
+ GFP_KERNEL);
if (! priv->dma_buf) {
printk (KERN_WARNING "%s: "
"cannot get buffer for DMA, "
@@ -2356,6 +2371,8 @@ out3:
out2:
kfree (ops);
out1:
+ if (pdev)
+ platform_device_unregister(pdev);
return NULL;
}
@@ -2383,7 +2400,7 @@ void parport_pc_unregister_port (struct parport *p)
release_region(p->base_hi, 3);
#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA)
if (priv->dma_buf)
- pci_free_consistent(priv->dev, PAGE_SIZE,
+ dma_free_coherent(p->physport->dev, PAGE_SIZE,
priv->dma_buf,
priv->dma_handle);
#endif
@@ -2489,7 +2506,7 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
*/
release_resource(base_res);
if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi,
- irq, PARPORT_DMA_NONE, NULL)) {
+ irq, PARPORT_DMA_NONE, &pdev->dev)) {
printk (KERN_INFO
"parport_pc: ITE 8872 parallel port: io=0x%X",
ite8872_lpt);
@@ -2672,7 +2689,7 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq,
}
/* finally, do the probe with values obtained */
- if (parport_pc_probe_port (port1, port2, irq, dma, NULL)) {
+ if (parport_pc_probe_port (port1, port2, irq, dma, &pdev->dev)) {
printk (KERN_INFO
"parport_pc: VIA parallel port: io=0x%X", port1);
if (irq != PARPORT_IRQ_NONE)
@@ -2970,7 +2987,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev,
parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi);
data->ports[count] =
parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, dev);
+ PARPORT_DMA_NONE, &dev->dev);
if (data->ports[count])
count++;
}
@@ -3077,8 +3094,8 @@ static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id
} else
dma = PARPORT_DMA_NONE;
- printk(KERN_INFO "parport: PnPBIOS parport detected.\n");
- if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, NULL)))
+ dev_info(&dev->dev, "reported by %s\n", dev->protocol->name);
+ if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, &dev->dev)))
return -ENODEV;
pnp_set_drvdata(dev,pdata);
@@ -3103,6 +3120,21 @@ static struct pnp_driver parport_pc_pnp_driver = {
};
+static int __devinit parport_pc_platform_probe(struct platform_device *pdev)
+{
+ /* Always succeed, the actual probing is done in
+ * parport_pc_probe_port(). */
+ return 0;
+}
+
+static struct platform_driver parport_pc_platform_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "parport_pc",
+ },
+ .probe = parport_pc_platform_probe,
+};
+
/* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */
static int __devinit __attribute__((unused))
parport_pc_find_isa_ports (int autoirq, int autodma)
@@ -3378,9 +3410,15 @@ __setup("parport_init_mode=",parport_init_mode_setup);
static int __init parport_pc_init(void)
{
+ int err;
+
if (parse_parport_params())
return -EINVAL;
+ err = platform_driver_register(&parport_pc_platform_driver);
+ if (err)
+ return err;
+
if (io[0]) {
int i;
/* Only probe the ports we were given. */
@@ -3405,6 +3443,7 @@ static void __exit parport_pc_exit(void)
pci_unregister_driver (&parport_pc_pci_driver);
if (pnp_registered_parport)
pnp_unregister_driver (&parport_pc_pnp_driver);
+ platform_driver_unregister(&parport_pc_platform_driver);
spin_lock(&ports_lock);
while (!list_empty(&ports_list)) {
@@ -3413,6 +3452,9 @@ static void __exit parport_pc_exit(void)
priv = list_entry(ports_list.next,
struct parport_pc_private, list);
port = priv->port;
+ if (port->dev && port->dev->bus == &platform_bus_type)
+ platform_device_unregister(
+ to_platform_device(port->dev));
spin_unlock(&ports_lock);
parport_pc_unregister_port(port);
spin_lock(&ports_lock);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 78c0a269a2b..90ea3b8b99b 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -305,7 +305,7 @@ static int __devinit parport_register (struct pci_dev *dev,
dev_dbg(&dev->dev, "PCI parallel port detected: I/O at "
"%#lx(%#lx)\n", io_lo, io_hi);
port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, dev);
+ PARPORT_DMA_NONE, &dev->dev);
if (port) {
priv->port[priv->num_par++] = port;
success = 1;
@@ -392,6 +392,7 @@ static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state)
static int parport_serial_pci_resume(struct pci_dev *dev)
{
struct parport_serial_private *priv = pci_get_drvdata(dev);
+ int err;
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
@@ -399,7 +400,12 @@ static int parport_serial_pci_resume(struct pci_dev *dev)
/*
* The device may have been disabled. Re-enable it.
*/
- pci_enable_device(dev);
+ err = pci_enable_device(dev);
+ if (err) {
+ printk(KERN_ERR "parport_serial: %s: error enabling "
+ "device for resume (%d)\n", pci_name(dev), err);
+ return err;
+ }
if (priv->serial)
pciserial_resume_ports(priv->serial);
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 400bb90084c..d27019c2f86 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -322,6 +322,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev)
goto out_free_ops;
p->size = size;
+ p->dev = &sdev->ofdev.dev;
if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
IRQF_SHARED, p->name, p)) != 0) {
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index fd9129e424f..cd66442acfe 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -365,6 +365,11 @@ void parport_announce_port (struct parport *port)
parport_daisy_init(port);
#endif
+ if (!port->dev)
+ printk(KERN_WARNING "%s: fix this legacy "
+ "no-device port driver!\n",
+ port->name);
+
parport_proc_register(port);
mutex_lock(&registration_lock);
spin_lock_irq(&parportlist_lock);
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 5ea5bc70cb8..7a1d6d51283 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -1,10 +1,14 @@
#
# PCI configuration
#
+config ARCH_SUPPORTS_MSI
+ bool
+ default n
+
config PCI_MSI
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
- depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64 || SPARC64
+ depends on ARCH_SUPPORTS_MSI
help
This allows device drivers to enable MSI (Message Signaled
Interrupts). Message Signaled Interrupts enable a device to
@@ -17,31 +21,6 @@ config PCI_MSI
If you don't know what to do here, say N.
-config PCI_MULTITHREAD_PROBE
- bool "PCI Multi-threaded probe (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL && BROKEN
- help
- Say Y here if you want the PCI core to spawn a new thread for
- every PCI device that is probed. This can cause a huge
- speedup in boot times on multiprocessor machines, and even a
- smaller speedup on single processor machines.
-
- But it can also cause lots of bad things to happen. A number
- of PCI drivers cannot properly handle running in this way,
- some will just not work properly at all, while others might
- decide to blow up power supplies with a huge load all at once,
- so use this option at your own risk.
-
- It is very unwise to use this option if you are not using a
- boot process that can handle devices being created in any
- order. A program that can create persistent block and network
- device names (like udev) is a good idea if you wish to use
- this option.
-
- Again, use this option at your own risk, you have been warned!
-
- When in doubt, say N.
-
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index aadaa3c8096..9e5ea074ad2 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -77,7 +77,7 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
* This adds a single pci device to the global
* device list and adds sysfs and procfs entries
*/
-int __devinit pci_bus_add_device(struct pci_dev *dev)
+int pci_bus_add_device(struct pci_dev *dev)
{
int retval;
retval = device_add(&dev->dev);
@@ -105,7 +105,7 @@ int __devinit pci_bus_add_device(struct pci_dev *dev)
*
* Call hotplug for each new devices.
*/
-void __devinit pci_bus_add_devices(struct pci_bus *bus)
+void pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
int retval;
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index be92695a783..63d62752fb9 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -2,9 +2,7 @@
# PCI Hotplug support
#
-menu "PCI Hotplug Support"
-
-config HOTPLUG_PCI
+menuconfig HOTPLUG_PCI
tristate "Support for PCI Hotplug (EXPERIMENTAL)"
depends on PCI && EXPERIMENTAL && HOTPLUG
---help---
@@ -17,9 +15,10 @@ config HOTPLUG_PCI
When in doubt, say N.
+if HOTPLUG_PCI
+
config HOTPLUG_PCI_FAKE
tristate "Fake PCI Hotplug driver"
- depends on HOTPLUG_PCI
help
Say Y here if you want to use the fake PCI hotplug driver. It can
be used to simulate PCI hotplug events if even if your system is
@@ -42,7 +41,7 @@ config HOTPLUG_PCI_FAKE
config HOTPLUG_PCI_COMPAQ
tristate "Compaq PCI Hotplug driver"
- depends on HOTPLUG_PCI && X86 && PCI_BIOS
+ depends on X86 && PCI_BIOS
help
Say Y here if you have a motherboard with a Compaq PCI Hotplug
controller.
@@ -64,7 +63,7 @@ config HOTPLUG_PCI_COMPAQ_NVRAM
config HOTPLUG_PCI_IBM
tristate "IBM PCI Hotplug driver"
- depends on HOTPLUG_PCI && X86_IO_APIC && X86 && PCI_BIOS
+ depends on X86_IO_APIC && X86 && PCI_BIOS
help
Say Y here if you have a motherboard with a IBM PCI Hotplug
controller.
@@ -76,7 +75,6 @@ config HOTPLUG_PCI_IBM
config HOTPLUG_PCI_ACPI
tristate "ACPI PCI Hotplug driver"
- depends on HOTPLUG_PCI
depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
help
Say Y here if you have a system that supports PCI Hotplug using
@@ -101,7 +99,6 @@ config HOTPLUG_PCI_ACPI_IBM
config HOTPLUG_PCI_CPCI
bool "CompactPCI Hotplug driver"
- depends on HOTPLUG_PCI
help
Say Y here if you have a CompactPCI system card with CompactPCI
hotswap support per the PICMG 2.1 specification.
@@ -110,7 +107,7 @@ config HOTPLUG_PCI_CPCI
config HOTPLUG_PCI_CPCI_ZT5550
tristate "Ziatech ZT5550 CompactPCI Hotplug driver"
- depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86
+ depends on HOTPLUG_PCI_CPCI && X86
help
Say Y here if you have an Performance Technologies (formerly Intel,
formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
@@ -122,7 +119,7 @@ config HOTPLUG_PCI_CPCI_ZT5550
config HOTPLUG_PCI_CPCI_GENERIC
tristate "Generic port I/O CompactPCI Hotplug driver"
- depends on HOTPLUG_PCI && HOTPLUG_PCI_CPCI && X86
+ depends on HOTPLUG_PCI_CPCI && X86
help
Say Y here if you have a CompactPCI system card that exposes the #ENUM
hotswap signal as a bit in a system register that can be read through
@@ -135,7 +132,6 @@ config HOTPLUG_PCI_CPCI_GENERIC
config HOTPLUG_PCI_SHPC
tristate "SHPC PCI Hotplug driver"
- depends on HOTPLUG_PCI
help
Say Y here if you have a motherboard with a SHPC PCI Hotplug
controller.
@@ -147,7 +143,7 @@ config HOTPLUG_PCI_SHPC
config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
- depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
+ depends on PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
help
Say Y here if you have a RPA system that supports PCI Hotplug.
@@ -170,12 +166,11 @@ config HOTPLUG_PCI_RPA_DLPAR
config HOTPLUG_PCI_SGI
tristate "SGI PCI Hotplug Support"
- depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC)
+ depends on IA64_SGI_SN2 || IA64_GENERIC
help
Say Y here if you want to use the SGI Altix Hotplug
Driver for PCI devices.
When in doubt, say N.
-endmenu
-
+endif # HOTPLUG_PCI
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 40c79b03c7e..fa5c0197d57 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -40,7 +40,6 @@
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include "acpiphp.h"
#define MY_NAME "acpiphp"
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index fca978fb158..9ef4e989afc 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -46,7 +46,6 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include "../pci.h"
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 7f03881a8b6..e7322c25d37 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -424,7 +424,7 @@ static int __init ibm_acpiphp_init(void)
int retval = 0;
acpi_status status;
struct acpi_device *device;
- struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+ struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
dbg("%s\n", __FUNCTION__);
@@ -471,7 +471,7 @@ init_return:
static void __exit ibm_acpiphp_exit(void)
{
acpi_status status;
- struct kobject *sysdir = &pci_hotplug_slots_subsys.kset.kobj;
+ struct kobject *sysdir = &pci_hotplug_slots_subsys.kobj;
dbg("%s\n", __FUNCTION__);
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c
index 1c12e917109..41f6a8d79c8 100644
--- a/drivers/pci/hotplug/cpcihp_zt5550.c
+++ b/drivers/pci/hotplug/cpcihp_zt5550.c
@@ -296,13 +296,17 @@ static struct pci_driver zt5550_hc_driver = {
static int __init zt5550_init(void)
{
struct resource* r;
+ int rc;
info(DRIVER_DESC " version: " DRIVER_VERSION);
r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register");
if(!r)
return -EBUSY;
- return pci_register_driver(&zt5550_hc_driver);
+ rc = pci_register_driver(&zt5550_hc_driver);
+ if(rc < 0)
+ release_region(ENUM_PORT, 1);
+ return rc;
}
static void __exit
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index e27907c91d9..027f6865d7e 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -238,7 +238,7 @@ static void pci_rescan_bus(const struct pci_bus *bus)
{
unsigned int devfn;
struct pci_dev *dev;
- dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ dev = alloc_pci_dev();
if (!dev)
return;
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 59392946c2b..0316eeaaeb2 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -34,7 +34,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/wait.h>
-#include <linux/smp_lock.h>
#include "../pci.h"
#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */
#include "ibmphp.h"
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index f55ac3885cb..46abaa8c41f 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -32,7 +32,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/mutex.h>
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index f5d632e7232..bd433ef6bfc 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -34,7 +34,6 @@
#include <linux/sysfs.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/mount.h>
#include <linux/namei.h>
@@ -62,7 +61,7 @@ static int debug;
static LIST_HEAD(pci_hotplug_slot_list);
-struct subsystem pci_hotplug_slots_subsys;
+struct kset pci_hotplug_slots_subsys;
static ssize_t hotplug_slot_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
@@ -764,7 +763,7 @@ static int __init pci_hotplug_init (void)
{
int result;
- kset_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
+ kobj_set_kset_s(&pci_hotplug_slots_subsys, pci_bus_type.subsys);
result = subsystem_register(&pci_hotplug_slots_subsys);
if (result) {
err("Register subsys with error %d\n", result);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index d19fcae8a7c..ccc57627201 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -43,6 +43,7 @@ extern int pciehp_poll_mode;
extern int pciehp_poll_time;
extern int pciehp_debug;
extern int pciehp_force;
+extern struct workqueue_struct *pciehp_wq;
#define dbg(format, arg...) \
do { \
@@ -70,14 +71,16 @@ struct slot {
struct list_head slot_list;
char name[SLOT_NAME_SIZE];
unsigned long last_emi_toggle;
+ struct delayed_work work; /* work for button event */
+ struct mutex lock;
};
struct event_info {
u32 event_type;
- u8 hp_slot;
+ struct slot *p_slot;
+ struct work_struct work;
};
-#define MAX_EVENTS 10
struct controller {
struct controller *next;
struct mutex crit_sect; /* critical section mutex */
@@ -86,11 +89,9 @@ struct controller {
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
struct list_head slot_list;
- struct event_info event_queue[MAX_EVENTS];
struct slot *slot;
struct hpc_ops *hpc_ops;
wait_queue_head_t queue; /* sleep & wake process */
- u8 next_event;
u8 bus;
u8 device;
u8 function;
@@ -149,21 +150,17 @@ struct controller {
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
#define EMI(cap) (cap & EMI_PRSN)
-extern int pciehp_event_start_thread(void);
-extern void pciehp_event_stop_thread(void);
-extern int pciehp_enable_slot(struct slot *slot);
-extern int pciehp_disable_slot(struct slot *slot);
+extern int pciehp_sysfs_enable_slot(struct slot *slot);
+extern int pciehp_sysfs_disable_slot(struct slot *slot);
extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
extern int pciehp_configure_device(struct slot *p_slot);
extern int pciehp_unconfigure_device(struct slot *p_slot);
+extern void pciehp_queue_pushbutton_work(struct work_struct *work);
int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-/* Global variables */
-extern struct controller *pciehp_ctrl_list;
-
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
struct slot *slot;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index a92eda6e02f..e5d3f0b4f45 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -41,7 +41,7 @@ int pciehp_debug;
int pciehp_poll_mode;
int pciehp_poll_time;
int pciehp_force;
-struct controller *pciehp_ctrl_list;
+struct workqueue_struct *pciehp_wq;
#define DRIVER_VERSION "0.4"
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>, Dely Sy <dely.l.sy@intel.com>"
@@ -62,7 +62,6 @@ MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"
#define PCIE_MODULE_NAME "pciehp"
-static int pcie_start_thread (void);
static int set_attention_status (struct hotplug_slot *slot, u8 value);
static int enable_slot (struct hotplug_slot *slot);
static int disable_slot (struct hotplug_slot *slot);
@@ -229,6 +228,8 @@ static int init_slots(struct controller *ctrl)
slot->device = ctrl->slot_device_offset + i;
slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
+ mutex_init(&slot->lock);
+ INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
@@ -286,6 +287,9 @@ static void cleanup_slots(struct controller *ctrl)
if (EMI(ctrl->ctrlcap))
sysfs_remove_file(&slot->hotplug_slot->kobj,
&hotplug_slot_attr_lock.attr);
+ cancel_delayed_work(&slot->work);
+ flush_scheduled_work();
+ flush_workqueue(pciehp_wq);
pci_hp_deregister(slot->hotplug_slot);
}
}
@@ -314,7 +318,7 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
- return pciehp_enable_slot(slot);
+ return pciehp_sysfs_enable_slot(slot);
}
@@ -324,7 +328,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
- return pciehp_disable_slot(slot);
+ return pciehp_sysfs_disable_slot(slot);
}
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 *value)
@@ -466,17 +470,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
- /* Finish setting up the hot plug ctrl device */
- ctrl->next_event = 0;
-
- if (!pciehp_ctrl_list) {
- pciehp_ctrl_list = ctrl;
- ctrl->next = NULL;
- } else {
- ctrl->next = pciehp_ctrl_list;
- pciehp_ctrl_list = ctrl;
- }
-
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
@@ -496,48 +489,14 @@ err_out_none:
return -ENODEV;
}
-
-static int pcie_start_thread(void)
+static void pciehp_remove (struct pcie_device *dev)
{
- int retval = 0;
-
- dbg("Initialize + Start the notification/polling mechanism \n");
-
- retval = pciehp_event_start_thread();
- if (retval) {
- dbg("pciehp_event_start_thread() failed\n");
- return retval;
- }
-
- return retval;
-}
-
-static void __exit unload_pciehpd(void)
-{
- struct controller *ctrl;
- struct controller *tctrl;
-
- ctrl = pciehp_ctrl_list;
-
- while (ctrl) {
- cleanup_slots(ctrl);
+ struct pci_dev *pdev = dev->port;
+ struct controller *ctrl = pci_get_drvdata(pdev);
- ctrl->hpc_ops->release_ctlr(ctrl);
-
- tctrl = ctrl;
- ctrl = ctrl->next;
-
- kfree(tctrl);
- }
-
- /* Stop the notification mechanism */
- pciehp_event_stop_thread();
-
-}
-
-static void pciehp_remove (struct pcie_device *device)
-{
- /* XXX - Needs to be adapted to device driver model */
+ cleanup_slots(ctrl);
+ ctrl->hpc_ops->release_ctlr(ctrl);
+ kfree(ctrl);
}
#ifdef CONFIG_PM
@@ -585,31 +544,18 @@ static int __init pcied_init(void)
pciehp_poll_mode = 1;
#endif
- retval = pcie_start_thread();
- if (retval)
- goto error_hpc_init;
-
retval = pcie_port_service_register(&hpdriver_portdrv);
dbg("pcie_port_service_register = %d\n", retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
if (retval)
dbg("%s: Failure to register service\n", __FUNCTION__);
-
-error_hpc_init:
- if (retval) {
- pciehp_event_stop_thread();
- };
-
return retval;
}
static void __exit pcied_cleanup(void)
{
dbg("unload_pciehpd()\n");
- unload_pciehpd();
-
pcie_port_service_unregister(&hpdriver_portdrv);
-
info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
}
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 4283ef56dbd..7f22caa7017 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -32,92 +32,61 @@
#include <linux/types.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
+#include <linux/workqueue.h>
#include "../pci.h"
#include "pciehp.h"
-static void interrupt_event_handler(struct controller *ctrl);
+static void interrupt_event_handler(struct work_struct *work);
+static int pciehp_enable_slot(struct slot *p_slot);
+static int pciehp_disable_slot(struct slot *p_slot);
-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
-static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending; /* = 0 */
-static unsigned long surprise_rm_pending; /* = 0 */
-
-static inline char *slot_name(struct slot *p_slot)
+static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
{
- return p_slot->hotplug_slot->name;
+ struct event_info *info;
+
+ info = kmalloc(sizeof(*info), GFP_ATOMIC);
+ if (!info)
+ return -ENOMEM;
+
+ info->event_type = event_type;
+ info->p_slot = p_slot;
+ INIT_WORK(&info->work, interrupt_event_handler);
+
+ schedule_work(&info->work);
+
+ return 0;
}
u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
struct slot *p_slot;
- u8 rc = 0;
- u8 getstatus;
- struct event_info *taskInfo;
+ u32 event_type;
/* Attention Button Change */
dbg("pciehp: Attention button interrupt received.\n");
-
- /* This is the structure that tells the worker thread what to do */
- taskInfo = &(ctrl->event_queue[ctrl->next_event]);
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
- p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
-
- ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
- taskInfo->hp_slot = hp_slot;
- rc++;
+ p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
/*
* Button pressed - See if need to TAKE ACTION!!!
*/
- info("Button pressed on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_BUTTON_PRESS;
-
- if ((p_slot->state == BLINKINGON_STATE)
- || (p_slot->state == BLINKINGOFF_STATE)) {
- /* Cancel if we are still blinking; this means that we press the
- * attention again before the 5 sec. limit expires to cancel hot-add
- * or hot-remove
- */
- taskInfo->event_type = INT_BUTTON_CANCEL;
- info("Button cancel on Slot(%s)\n", slot_name(p_slot));
- } else if ((p_slot->state == POWERON_STATE)
- || (p_slot->state == POWEROFF_STATE)) {
- /* Ignore if the slot is on power-on or power-off state; this
- * means that the previous attention button action to hot-add or
- * hot-remove is undergoing
- */
- taskInfo->event_type = INT_BUTTON_IGNORE;
- info("Button ignore on Slot(%s)\n", slot_name(p_slot));
- }
+ info("Button pressed on Slot(%s)\n", p_slot->name);
+ event_type = INT_BUTTON_PRESS;
- if (rc)
- up(&event_semaphore); /* signal event thread that new event is posted */
+ queue_interrupt_event(p_slot, event_type);
return 0;
-
}
u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
struct slot *p_slot;
- u8 rc = 0;
u8 getstatus;
- struct event_info *taskInfo;
+ u32 event_type;
/* Switch Change */
dbg("pciehp: Switch interrupt received.\n");
- /* This is the structure that tells the worker thread
- * what to do
- */
- taskInfo = &(ctrl->event_queue[ctrl->next_event]);
- ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
- taskInfo->hp_slot = hp_slot;
-
- rc++;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
@@ -125,39 +94,30 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
/*
* Switch opened
*/
- info("Latch open on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_SWITCH_OPEN;
+ info("Latch open on Slot(%s)\n", p_slot->name);
+ event_type = INT_SWITCH_OPEN;
} else {
/*
* Switch closed
*/
- info("Latch close on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_SWITCH_CLOSE;
+ info("Latch close on Slot(%s)\n", p_slot->name);
+ event_type = INT_SWITCH_CLOSE;
}
- if (rc)
- up(&event_semaphore); /* signal event thread that new event is posted */
+ queue_interrupt_event(p_slot, event_type);
- return rc;
+ return 1;
}
u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
struct slot *p_slot;
- u8 presence_save, rc = 0;
- struct event_info *taskInfo;
+ u32 event_type;
+ u8 presence_save;
/* Presence Change */
dbg("pciehp: Presence/Notify input change.\n");
- /* This is the structure that tells the worker thread
- * what to do
- */
- taskInfo = &(ctrl->event_queue[ctrl->next_event]);
- ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
- taskInfo->hp_slot = hp_slot;
-
- rc++;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
/* Switch is open, assume a presence change
@@ -168,59 +128,49 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
/*
* Card Present
*/
- info("Card present on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_PRESENCE_ON;
+ info("Card present on Slot(%s)\n", p_slot->name);
+ event_type = INT_PRESENCE_ON;
} else {
/*
* Not Present
*/
- info("Card not present on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_PRESENCE_OFF;
+ info("Card not present on Slot(%s)\n", p_slot->name);
+ event_type = INT_PRESENCE_OFF;
}
- if (rc)
- up(&event_semaphore); /* signal event thread that new event is posted */
+ queue_interrupt_event(p_slot, event_type);
- return rc;
+ return 1;
}
u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
struct slot *p_slot;
- u8 rc = 0;
- struct event_info *taskInfo;
+ u32 event_type;
/* power fault */
dbg("pciehp: Power fault interrupt received.\n");
- /* this is the structure that tells the worker thread
- * what to do
- */
- taskInfo = &(ctrl->event_queue[ctrl->next_event]);
- ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
- taskInfo->hp_slot = hp_slot;
-
- rc++;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
/*
* power fault Cleared
*/
- info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_POWER_FAULT_CLEAR;
+ info("Power fault cleared on Slot(%s)\n", p_slot->name);
+ event_type = INT_POWER_FAULT_CLEAR;
} else {
/*
* power fault
*/
- info("Power fault on Slot(%s)\n", slot_name(p_slot));
- taskInfo->event_type = INT_POWER_FAULT;
+ info("Power fault on Slot(%s)\n", p_slot->name);
+ event_type = INT_POWER_FAULT;
info("power fault bit %x set\n", hp_slot);
}
- if (rc)
- up(&event_semaphore); /* signal event thread that new event is posted */
- return rc;
+ queue_interrupt_event(p_slot, event_type);
+
+ return 1;
}
/* The following routines constitute the bulk of the
@@ -357,13 +307,10 @@ static int remove_board(struct slot *p_slot)
return 0;
}
-
-static void pushbutton_helper_thread(unsigned long data)
-{
- pushbutton_pending = data;
-
- up(&event_semaphore);
-}
+struct power_work_info {
+ struct slot *p_slot;
+ struct work_struct work;
+};
/**
* pciehp_pushbutton_thread
@@ -372,276 +319,214 @@ static void pushbutton_helper_thread(unsigned long data)
* Handles all pending events and exits.
*
*/
-static void pciehp_pushbutton_thread(unsigned long slot)
+static void pciehp_power_thread(struct work_struct *work)
{
- struct slot *p_slot = (struct slot *) slot;
- u8 getstatus;
-
- pushbutton_pending = 0;
-
- if (!p_slot) {
- dbg("%s: Error! slot NULL\n", __FUNCTION__);
- return;
- }
-
- p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
- if (getstatus) {
- p_slot->state = POWEROFF_STATE;
- dbg("%s: disabling bus:device(%x:%x)\n", __FUNCTION__,
- p_slot->bus, p_slot->device);
-
+ struct power_work_info *info =
+ container_of(work, struct power_work_info, work);
+ struct slot *p_slot = info->p_slot;
+
+ mutex_lock(&p_slot->lock);
+ switch (p_slot->state) {
+ case POWEROFF_STATE:
+ mutex_unlock(&p_slot->lock);
+ dbg("%s: disabling bus:device(%x:%x)\n",
+ __FUNCTION__, p_slot->bus, p_slot->device);
pciehp_disable_slot(p_slot);
+ mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
- } else {
- p_slot->state = POWERON_STATE;
- dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
- p_slot->bus, p_slot->device);
-
+ break;
+ case POWERON_STATE:
+ mutex_unlock(&p_slot->lock);
if (pciehp_enable_slot(p_slot) &&
PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
-
+ mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
+ break;
+ default:
+ break;
}
+ mutex_unlock(&p_slot->lock);
- return;
+ kfree(info);
}
-/**
- * pciehp_surprise_rm_thread
- *
- * Scheduled procedure to handle blocking stuff for the surprise removal
- * Handles all pending events and exits.
- *
- */
-static void pciehp_surprise_rm_thread(unsigned long slot)
+void pciehp_queue_pushbutton_work(struct work_struct *work)
{
- struct slot *p_slot = (struct slot *) slot;
- u8 getstatus;
-
- surprise_rm_pending = 0;
+ struct slot *p_slot = container_of(work, struct slot, work.work);
+ struct power_work_info *info;
- if (!p_slot) {
- dbg("%s: Error! slot NULL\n", __FUNCTION__);
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ err("%s: Cannot allocate memory\n", __FUNCTION__);
return;
}
+ info->p_slot = p_slot;
+ INIT_WORK(&info->work, pciehp_power_thread);
- p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
- if (!getstatus) {
+ mutex_lock(&p_slot->lock);
+ switch (p_slot->state) {
+ case BLINKINGOFF_STATE:
p_slot->state = POWEROFF_STATE;
- dbg("%s: removing bus:device(%x:%x)\n",
- __FUNCTION__, p_slot->bus, p_slot->device);
-
- pciehp_disable_slot(p_slot);
- p_slot->state = STATIC_STATE;
- } else {
+ break;
+ case BLINKINGON_STATE:
p_slot->state = POWERON_STATE;
- dbg("%s: adding bus:device(%x:%x)\n",
- __FUNCTION__, p_slot->bus, p_slot->device);
-
- if (pciehp_enable_slot(p_slot) &&
- PWR_LED(p_slot->ctrl->ctrlcap))
- p_slot->hpc_ops->green_led_off(p_slot);
-
- p_slot->state = STATIC_STATE;
+ break;
+ default:
+ goto out;
}
-
- return;
+ queue_work(pciehp_wq, &info->work);
+ out:
+ mutex_unlock(&p_slot->lock);
}
-
-
-/* this is the main worker thread */
-static int event_thread(void* data)
-{
- struct controller *ctrl;
- lock_kernel();
- daemonize("pciehpd_event");
-
- unlock_kernel();
-
- while (1) {
- dbg("!!!!event_thread sleeping\n");
- down_interruptible (&event_semaphore);
- dbg("event_thread woken finished = %d\n", event_finished);
- if (event_finished || signal_pending(current))
- break;
- /* Do stuff here */
- if (pushbutton_pending)
- pciehp_pushbutton_thread(pushbutton_pending);
- else if (surprise_rm_pending)
- pciehp_surprise_rm_thread(surprise_rm_pending);
- else
- for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next)
- interrupt_event_handler(ctrl);
- }
- dbg("event_thread signals exit\n");
- up(&event_exit);
- return 0;
-}
-
-int pciehp_event_start_thread(void)
-{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX_LOCKED(&event_exit);
- event_finished=0;
-
- init_MUTEX_LOCKED(&event_semaphore);
- pid = kernel_thread(event_thread, NULL, 0);
-
- if (pid < 0) {
- err ("Can't start up our event thread\n");
- return -1;
- }
- return 0;
-}
-
-
-void pciehp_event_stop_thread(void)
-{
- event_finished = 1;
- up(&event_semaphore);
- down(&event_exit);
-}
-
-
static int update_slot_info(struct slot *slot)
{
struct hotplug_slot_info *info;
- /* char buffer[SLOT_NAME_SIZE]; */
int result;
- info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- /* make_slot_name (&buffer[0], SLOT_NAME_SIZE, slot); */
-
slot->hpc_ops->get_power_status(slot, &(info->power_status));
slot->hpc_ops->get_attention_status(slot, &(info->attention_status));
slot->hpc_ops->get_latch_status(slot, &(info->latch_status));
slot->hpc_ops->get_adapter_status(slot, &(info->adapter_status));
- /* result = pci_hp_change_slot_info(buffer, info); */
result = pci_hp_change_slot_info(slot->hotplug_slot, info);
kfree (info);
return result;
}
-static void interrupt_event_handler(struct controller *ctrl)
+/*
+ * Note: This function must be called with slot->lock held
+ */
+static void handle_button_press_event(struct slot *p_slot)
{
- int loop = 0;
- int change = 1;
- u8 hp_slot;
+ struct controller *ctrl = p_slot->ctrl;
u8 getstatus;
- struct slot *p_slot;
- while (change) {
- change = 0;
-
- for (loop = 0; loop < MAX_EVENTS; loop++) {
- if (ctrl->event_queue[loop].event_type != 0) {
- hp_slot = ctrl->event_queue[loop].hp_slot;
-
- p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
-
- if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
- dbg("button cancel\n");
- del_timer(&p_slot->task_event);
-
- switch (p_slot->state) {
- case BLINKINGOFF_STATE:
- if (PWR_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->green_led_on(p_slot);
-
- if (ATTN_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- break;
- case BLINKINGON_STATE:
- if (PWR_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->green_led_off(p_slot);
-
- if (ATTN_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- break;
- default:
- warn("Not a valid state\n");
- return;
- }
- info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
- p_slot->state = STATIC_STATE;
- }
- /* ***********Button Pressed (No action on 1st press...) */
- else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
-
- if (ATTN_BUTTN(ctrl->ctrlcap)) {
- dbg("Button pressed\n");
- p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
- if (getstatus) {
- /* slot is on */
- dbg("slot is on\n");
- p_slot->state = BLINKINGOFF_STATE;
- info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
- } else {
- /* slot is off */
- dbg("slot is off\n");
- p_slot->state = BLINKINGON_STATE;
- info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
- }
-
- /* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->green_led_blink(p_slot);
-
- if (ATTN_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
-
- init_timer(&p_slot->task_event);
- p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
- p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
- p_slot->task_event.data = (unsigned long) p_slot;
-
- add_timer(&p_slot->task_event);
- }
- }
- /***********POWER FAULT********************/
- else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
- if (POWER_CTRL(ctrl->ctrlcap)) {
- dbg("power fault\n");
- if (ATTN_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->set_attention_status(p_slot, 1);
-
- if (PWR_LED(ctrl->ctrlcap))
- p_slot->hpc_ops->green_led_off(p_slot);
- }
- }
- /***********SURPRISE REMOVAL********************/
- else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) ||
- (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
- if (HP_SUPR_RM(ctrl->ctrlcap)) {
- dbg("Surprise Removal\n");
- if (p_slot) {
- surprise_rm_pending = (unsigned long) p_slot;
- up(&event_semaphore);
- update_slot_info(p_slot);
- }
- }
- } else {
- /* refresh notification */
- if (p_slot)
- update_slot_info(p_slot);
- }
-
- ctrl->event_queue[loop].event_type = 0;
-
- change = 1;
- }
- } /* End of FOR loop */
+ switch (p_slot->state) {
+ case STATIC_STATE:
+ p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
+ if (getstatus) {
+ p_slot->state = BLINKINGOFF_STATE;
+ info("PCI slot #%s - powering off due to button "
+ "press.\n", p_slot->name);
+ } else {
+ p_slot->state = BLINKINGON_STATE;
+ info("PCI slot #%s - powering on due to button "
+ "press.\n", p_slot->name);
+ }
+ /* blink green LED and turn off amber */
+ if (PWR_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->green_led_blink(p_slot);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
+
+ schedule_delayed_work(&p_slot->work, 5*HZ);
+ break;
+ case BLINKINGOFF_STATE:
+ case BLINKINGON_STATE:
+ /*
+ * Cancel if we are still blinking; this means that we
+ * press the attention again before the 5 sec. limit
+ * expires to cancel hot-add or hot-remove
+ */
+ info("Button cancel on Slot(%s)\n", p_slot->name);
+ dbg("%s: button cancel\n", __FUNCTION__);
+ cancel_delayed_work(&p_slot->work);
+ if (p_slot->state == BLINKINGOFF_STATE) {
+ if (PWR_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->green_led_on(p_slot);
+ } else {
+ if (PWR_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->green_led_off(p_slot);
+ }
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
+ info("PCI slot #%s - action canceled due to button press\n",
+ p_slot->name);
+ p_slot->state = STATIC_STATE;
+ break;
+ case POWEROFF_STATE:
+ case POWERON_STATE:
+ /*
+ * Ignore if the slot is on power-on or power-off state;
+ * this means that the previous attention button action
+ * to hot-add or hot-remove is undergoing
+ */
+ info("Button ignore on Slot(%s)\n", p_slot->name);
+ update_slot_info(p_slot);
+ break;
+ default:
+ warn("Not a valid state\n");
+ break;
}
}
+/*
+ * Note: This function must be called with slot->lock held
+ */
+static void handle_surprise_event(struct slot *p_slot)
+{
+ u8 getstatus;
+ struct power_work_info *info;
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ err("%s: Cannot allocate memory\n", __FUNCTION__);
+ return;
+ }
+ info->p_slot = p_slot;
+ INIT_WORK(&info->work, pciehp_power_thread);
+
+ p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
+ if (!getstatus)
+ p_slot->state = POWEROFF_STATE;
+ else
+ p_slot->state = POWERON_STATE;
+
+ queue_work(pciehp_wq, &info->work);
+}
+
+static void interrupt_event_handler(struct work_struct *work)
+{
+ struct event_info *info = container_of(work, struct event_info, work);
+ struct slot *p_slot = info->p_slot;
+ struct controller *ctrl = p_slot->ctrl;
+
+ mutex_lock(&p_slot->lock);
+ switch (info->event_type) {
+ case INT_BUTTON_PRESS:
+ handle_button_press_event(p_slot);
+ break;
+ case INT_POWER_FAULT:
+ if (!POWER_CTRL(ctrl->ctrlcap))
+ break;
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 1);
+ if (PWR_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->green_led_off(p_slot);
+ break;
+ case INT_PRESENCE_ON:
+ case INT_PRESENCE_OFF:
+ if (!HP_SUPR_RM(ctrl->ctrlcap))
+ break;
+ dbg("Surprise Removal\n");
+ update_slot_info(p_slot);
+ handle_surprise_event(p_slot);
+ break;
+ default:
+ update_slot_info(p_slot);
+ break;
+ }
+ mutex_unlock(&p_slot->lock);
+
+ kfree(info);
+}
+
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
@@ -653,7 +538,7 @@ int pciehp_enable_slot(struct slot *p_slot)
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) {
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
- slot_name(p_slot));
+ p_slot->name);
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -661,7 +546,7 @@ int pciehp_enable_slot(struct slot *p_slot)
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
- slot_name(p_slot));
+ p_slot->name);
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -671,7 +556,7 @@ int pciehp_enable_slot(struct slot *p_slot)
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%s)\n", __FUNCTION__,
- slot_name(p_slot));
+ p_slot->name);
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
@@ -706,7 +591,7 @@ int pciehp_disable_slot(struct slot *p_slot)
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%s)\n", __FUNCTION__,
- slot_name(p_slot));
+ p_slot->name);
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -716,7 +601,7 @@ int pciehp_disable_slot(struct slot *p_slot)
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%s)\n", __FUNCTION__,
- slot_name(p_slot));
+ p_slot->name);
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
@@ -726,7 +611,7 @@ int pciehp_disable_slot(struct slot *p_slot)
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%s)\n", __FUNCTION__,
- slot_name(p_slot));
+ p_slot->name);
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
@@ -739,3 +624,66 @@ int pciehp_disable_slot(struct slot *p_slot)
return ret;
}
+int pciehp_sysfs_enable_slot(struct slot *p_slot)
+{
+ int retval = -ENODEV;
+
+ mutex_lock(&p_slot->lock);
+ switch (p_slot->state) {
+ case BLINKINGON_STATE:
+ cancel_delayed_work(&p_slot->work);
+ case STATIC_STATE:
+ p_slot->state = POWERON_STATE;
+ mutex_unlock(&p_slot->lock);
+ retval = pciehp_enable_slot(p_slot);
+ mutex_lock(&p_slot->lock);
+ p_slot->state = STATIC_STATE;
+ break;
+ case POWERON_STATE:
+ info("Slot %s is already in powering on state\n",
+ p_slot->name);
+ break;
+ case BLINKINGOFF_STATE:
+ case POWEROFF_STATE:
+ info("Already enabled on slot %s\n", p_slot->name);
+ break;
+ default:
+ err("Not a valid state on slot %s\n", p_slot->name);
+ break;
+ }
+ mutex_unlock(&p_slot->lock);
+
+ return retval;
+}
+
+int pciehp_sysfs_disable_slot(struct slot *p_slot)
+{
+ int retval = -ENODEV;
+
+ mutex_lock(&p_slot->lock);
+ switch (p_slot->state) {
+ case BLINKINGOFF_STATE:
+ cancel_delayed_work(&p_slot->work);
+ case STATIC_STATE:
+ p_slot->state = POWEROFF_STATE;
+ mutex_unlock(&p_slot->lock);
+ retval = pciehp_disable_slot(p_slot);
+ mutex_lock(&p_slot->lock);
+ p_slot->state = STATIC_STATE;
+ break;
+ case POWEROFF_STATE:
+ info("Slot %s is already in powering off state\n",
+ p_slot->name);
+ break;
+ case BLINKINGON_STATE:
+ case POWERON_STATE:
+ info("Already disabled on slot %s\n", p_slot->name);
+ break;
+ default:
+ err("Not a valid state on slot %s\n", p_slot->name);
+ break;
+ }
+ mutex_unlock(&p_slot->lock);
+
+ return retval;
+}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index fbc64aa2dd6..9aac6a87eb5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -71,6 +71,8 @@
#define DBG_LEAVE_ROUTINE
#endif /* DEBUG */
+static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
+
struct ctrl_reg {
u8 cap_id;
u8 nxt_ptr;
@@ -219,10 +221,7 @@ static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
#define EMI_STATE 0x0080
#define EMI_STATUS_BIT 7
-static spinlock_t hpc_event_lock;
-
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-static int ctlr_seq_num = 0; /* Controller sequence # */
static irqreturn_t pcie_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct controller *ctrl, int sec);
@@ -656,6 +655,13 @@ static void hpc_release_ctlr(struct controller *ctrl)
else
free_irq(ctrl->pci_dev->irq, ctrl);
+ /*
+ * If this is the last controller to be released, destroy the
+ * pciehp work queue
+ */
+ if (atomic_dec_and_test(&pciehp_num_controllers))
+ destroy_workqueue(pciehp_wq);
+
DBG_LEAVE_ROUTINE
}
@@ -1152,7 +1158,6 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
int rc;
- static int first = 1;
u16 temp_word;
u16 cap_reg;
u16 intr_enable = 0;
@@ -1221,11 +1226,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
- if (first) {
- spin_lock_init(&hpc_event_lock);
- first = 0;
- }
-
for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
if (pci_resource_len(pdev, rc) > 0)
dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
@@ -1286,7 +1286,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
MY_NAME, (void *)ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n",
- __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
+ __FUNCTION__, ctrl->pci_dev->irq,
+ atomic_read(&pciehp_num_controllers), rc);
if (rc) {
err("Can't get irq %d for the hotplug controller\n",
ctrl->pci_dev->irq);
@@ -1296,6 +1297,18 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
+ /*
+ * If this is the first controller to be initialized,
+ * initialize the pciehp work queue
+ */
+ if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
+ pciehp_wq = create_singlethread_workqueue("pciehpd");
+ if (!pciehp_wq) {
+ rc = -ENOMEM;
+ goto abort_free_irq;
+ }
+ }
+
rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
@@ -1349,7 +1362,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_disable_intr;
}
- ctlr_seq_num++;
ctrl->hpc_ops = &pciehp_hpc_ops;
DBG_LEAVE_ROUTINE
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index 72383467a0d..bb3c101c2c5 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -98,7 +98,15 @@ static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
return NULL;
}
-static struct slot *find_slot(struct device_node *dn)
+/**
+ * find_php_slot - return hotplug slot structure for device node
+ *
+ * This routine will return the hotplug slot structure
+ * for a given device node. Note that built-in PCI slots
+ * may be dlpar-able, but not hot-pluggable, so this routine
+ * will return NULL for built-in PCI slots.
+ */
+static struct slot *find_php_slot(struct device_node *dn)
{
struct list_head *tmp, *n;
struct slot *slot;
@@ -224,9 +232,9 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)
if (!pcibios_find_pci_bus(dn))
return -EINVAL;
- slot = find_slot(dn);
+ /* If pci slot is hotplugable, use hotplug to remove it */
+ slot = find_php_slot(dn);
if (slot) {
- /* Remove hotplug slot */
if (rpaphp_deregister_slot(slot)) {
printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n",
@@ -370,22 +378,17 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
if (!bus)
return -EINVAL;
- slot = find_slot(dn);
+ /* If pci slot is hotplugable, use hotplug to remove it */
+ slot = find_php_slot(dn);
if (slot) {
- /* Remove hotplug slot */
if (rpaphp_deregister_slot(slot)) {
printk(KERN_ERR
"%s: unable to remove hotplug slot %s\n",
__FUNCTION__, drc_name);
return -EIO;
}
- } else {
- struct pci_dev *dev, *tmp;
- list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
- eeh_remove_bus_device(dev);
- pci_remove_bus_device(dev);
- }
- }
+ } else
+ pcibios_remove_pci_devices(bus);
if (unmap_bus_range(bus)) {
printk(KERN_ERR "%s: failed to unmap bus range\n",
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index 2e7accf0f73..c822a779653 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -83,19 +83,15 @@ struct slot {
extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
extern struct list_head rpaphp_slot_head;
-extern int num_slots;
/* function prototypes */
/* rpaphp_pci.c */
-extern int rpaphp_enable_pci_slot(struct slot *slot);
-extern int rpaphp_register_pci_slot(struct slot *slot);
-extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);
+extern int rpaphp_enable_slot(struct slot *slot);
extern int rpaphp_get_sensor_state(struct slot *slot, int *state);
/* rpaphp_core.c */
extern int rpaphp_add_slot(struct device_node *dn);
-extern int rpaphp_remove_slot(struct slot *slot);
extern int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
char **drc_name, char **drc_type, int *drc_power_domain);
@@ -104,7 +100,5 @@ extern void dealloc_slot_struct(struct slot *slot);
extern struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name, int power_domain);
extern int rpaphp_register_slot(struct slot *slot);
extern int rpaphp_deregister_slot(struct slot *slot);
-extern int rpaphp_get_power_status(struct slot *slot, u8 * value);
-extern int rpaphp_set_attention_status(struct slot *slot, u8 status);
#endif /* _PPC64PHP_H */
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 71a2cb8baa4..458c08ef265 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -29,7 +29,6 @@
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/eeh.h> /* for eeh_add_device() */
#include <asm/rtas.h> /* rtas_call */
@@ -39,9 +38,7 @@
#include "rpaphp.h"
int debug;
-static struct semaphore rpaphp_sem;
LIST_HEAD(rpaphp_slot_head);
-int num_slots;
#define DRIVER_VERSION "0.1"
#define DRIVER_AUTHOR "Linda Xie <lxie@us.ibm.com>"
@@ -55,11 +52,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, 0644);
-static int rpaphp_get_attention_status(struct slot *slot)
-{
- return slot->hotplug_slot->info->attention_status;
-}
-
/**
* set_attention_status - set attention LED
* echo 0 > attention -- set LED OFF
@@ -69,79 +61,75 @@ static int rpaphp_get_attention_status(struct slot *slot)
*/
static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 value)
{
- int retval = 0;
+ int rc;
struct slot *slot = (struct slot *)hotplug_slot->private;
- down(&rpaphp_sem);
switch (value) {
case 0:
- retval = rpaphp_set_attention_status(slot, LED_OFF);
- hotplug_slot->info->attention_status = 0;
- break;
case 1:
- default:
- retval = rpaphp_set_attention_status(slot, LED_ON);
- hotplug_slot->info->attention_status = 1;
- break;
case 2:
- retval = rpaphp_set_attention_status(slot, LED_ID);
- hotplug_slot->info->attention_status = 2;
+ break;
+ default:
+ value = 1;
break;
}
- up(&rpaphp_sem);
- return retval;
+
+ rc = rtas_set_indicator(DR_INDICATOR, slot->index, value);
+ if (!rc)
+ hotplug_slot->info->attention_status = value;
+
+ return rc;
}
/**
* get_power_status - get power status of a slot
* @hotplug_slot: slot to get status
* @value: pointer to store status
- *
- *
*/
static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
- int retval;
+ int retval, level;
struct slot *slot = (struct slot *)hotplug_slot->private;
- down(&rpaphp_sem);
- retval = rpaphp_get_power_status(slot, value);
- up(&rpaphp_sem);
+ retval = rtas_get_power_level (slot->power_domain, &level);
+ if (!retval)
+ *value = level;
return retval;
}
/**
* get_attention_status - get attention LED status
- *
- *
*/
static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
- int retval = 0;
struct slot *slot = (struct slot *)hotplug_slot->private;
-
- down(&rpaphp_sem);
- *value = rpaphp_get_attention_status(slot);
- up(&rpaphp_sem);
- return retval;
+ *value = slot->hotplug_slot->info->attention_status;
+ return 0;
}
static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
{
struct slot *slot = (struct slot *)hotplug_slot->private;
- int retval = 0;
+ int rc, state;
- down(&rpaphp_sem);
- retval = rpaphp_get_pci_adapter_status(slot, 0, value);
- up(&rpaphp_sem);
- return retval;
+ rc = rpaphp_get_sensor_state(slot, &state);
+
+ *value = NOT_VALID;
+ if (rc)
+ return rc;
+
+ if (state == EMPTY)
+ *value = EMPTY;
+ else if (state == PRESENT)
+ *value = slot->state;
+
+ return 0;
}
static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
struct slot *slot = (struct slot *)hotplug_slot->private;
- down(&rpaphp_sem);
switch (slot->type) {
case 1:
case 2:
@@ -172,7 +160,6 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
break;
}
- up(&rpaphp_sem);
return 0;
}
@@ -182,10 +169,10 @@ static int get_children_props(struct device_node *dn, const int **drc_indexes,
{
const int *indexes, *names, *types, *domains;
- indexes = get_property(dn, "ibm,drc-indexes", NULL);
- names = get_property(dn, "ibm,drc-names", NULL);
- types = get_property(dn, "ibm,drc-types", NULL);
- domains = get_property(dn, "ibm,drc-power-domains", NULL);
+ indexes = of_get_property(dn, "ibm,drc-indexes", NULL);
+ names = of_get_property(dn, "ibm,drc-names", NULL);
+ types = of_get_property(dn, "ibm,drc-types", NULL);
+ domains = of_get_property(dn, "ibm,drc-power-domains", NULL);
if (!indexes || !names || !types || !domains) {
/* Slot does not have dynamically-removable children */
@@ -218,7 +205,7 @@ int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
char *name_tmp, *type_tmp;
int i, rc;
- my_index = get_property(dn, "ibm,my-drc-index", NULL);
+ my_index = of_get_property(dn, "ibm,my-drc-index", NULL);
if (!my_index) {
/* Node isn't DLPAR/hotplug capable */
return -EINVAL;
@@ -265,6 +252,14 @@ static int is_php_type(char *drc_type)
return 1;
}
+/**
+ * is_php_dn() - return 1 if this is a hotpluggable pci slot, else 0
+ *
+ * This routine will return true only if the device node is
+ * a hotpluggable slot. This routine will return false
+ * for built-in pci slots (even when the built-in slots are
+ * dlparable.)
+ */
static int is_php_dn(struct device_node *dn, const int **indexes,
const int **names, const int **types, const int **power_domains)
{
@@ -272,24 +267,31 @@ static int is_php_dn(struct device_node *dn, const int **indexes,
int rc;
rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
- if (rc >= 0) {
- if (is_php_type((char *) &drc_types[1])) {
- *types = drc_types;
- return 1;
- }
- }
+ if (rc < 0)
+ return 0;
- return 0;
+ if (!is_php_type((char *) &drc_types[1]))
+ return 0;
+
+ *types = drc_types;
+ return 1;
}
/**
- * rpaphp_add_slot -- add hotplug or dlpar slot
+ * rpaphp_add_slot -- declare a hotplug slot to the hotplug subsystem.
+ * @dn device node of slot
+ *
+ * This subroutine will register a hotplugable slot with the
+ * PCI hotplug infrastructure. This routine is typicaly called
+ * during boot time, if the hotplug slots are present at boot time,
+ * or is called later, by the dlpar add code, if the slot is
+ * being dynamically added during runtime.
+ *
+ * If the device node points at an embedded (built-in) slot, this
+ * routine will just return without doing anything, since embedded
+ * slots cannot be hotplugged.
*
- * rpaphp not only registers PCI hotplug slots(HOTPLUG),
- * but also logical DR slots(EMBEDDED).
- * HOTPLUG slot: An adapter can be physically added/removed.
- * EMBEDDED slot: An adapter can be logically removed/added
- * from/to a partition with the slot.
+ * To remove a slot, it suffices to call rpaphp_deregister_slot()
*/
int rpaphp_add_slot(struct device_node *dn)
{
@@ -299,34 +301,42 @@ int rpaphp_add_slot(struct device_node *dn)
const int *indexes, *names, *types, *power_domains;
char *name, *type;
+ if (!dn->name || strcmp(dn->name, "pci"))
+ return 0;
+
+ /* If this is not a hotplug slot, return without doing anything. */
+ if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
+ return 0;
+
dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
/* register PCI devices */
- if (dn->name != 0 && strcmp(dn->name, "pci") == 0) {
- if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
- goto exit;
-
- name = (char *) &names[1];
- type = (char *) &types[1];
- for (i = 0; i < indexes[0]; i++,
- name += (strlen(name) + 1), type += (strlen(type) + 1)) {
-
- if (!(slot = alloc_slot_struct(dn, indexes[i + 1], name,
- power_domains[i + 1]))) {
- retval = -ENOMEM;
- goto exit;
- }
- slot->type = simple_strtoul(type, NULL, 10);
+ name = (char *) &names[1];
+ type = (char *) &types[1];
+ for (i = 0; i < indexes[0]; i++) {
+
+ slot = alloc_slot_struct(dn, indexes[i + 1], name, power_domains[i + 1]);
+ if (!slot)
+ return -ENOMEM;
+
+ slot->type = simple_strtoul(type, NULL, 10);
- dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
- indexes[i + 1], name, type);
+ dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
+ indexes[i + 1], name, type);
- retval = rpaphp_register_pci_slot(slot);
- }
+ retval = rpaphp_enable_slot(slot);
+ if (!retval)
+ retval = rpaphp_register_slot(slot);
+
+ if (retval)
+ dealloc_slot_struct(slot);
+
+ name += strlen(name) + 1;
+ type += strlen(type) + 1;
}
-exit:
- dbg("%s - Exit: num_slots=%d rc[%d]\n",
- __FUNCTION__, num_slots, retval);
+ dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
+
+ /* XXX FIXME: reports a failure only if last entry in loop failed */
return retval;
}
@@ -354,7 +364,6 @@ static int __init rpaphp_init(void)
struct device_node *dn = NULL;
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
- init_MUTEX(&rpaphp_sem);
while ((dn = of_find_node_by_name(dn, "pci")))
rpaphp_add_slot(dn);
@@ -367,8 +376,9 @@ static void __exit rpaphp_exit(void)
cleanup_slots();
}
-static int __enable_slot(struct slot *slot)
+static int enable_slot(struct hotplug_slot *hotplug_slot)
{
+ struct slot *slot = (struct slot *)hotplug_slot->private;
int state;
int retval;
@@ -392,46 +402,17 @@ static int __enable_slot(struct slot *slot)
return 0;
}
-static int enable_slot(struct hotplug_slot *hotplug_slot)
+static int disable_slot(struct hotplug_slot *hotplug_slot)
{
- int retval;
struct slot *slot = (struct slot *)hotplug_slot->private;
-
- down(&rpaphp_sem);
- retval = __enable_slot(slot);
- up(&rpaphp_sem);
-
- return retval;
-}
-
-static int __disable_slot(struct slot *slot)
-{
- struct pci_dev *dev, *tmp;
-
if (slot->state == NOT_CONFIGURED)
return -EINVAL;
- list_for_each_entry_safe(dev, tmp, &slot->bus->devices, bus_list) {
- eeh_remove_bus_device(dev);
- pci_remove_bus_device(dev);
- }
-
+ pcibios_remove_pci_devices(slot->bus);
slot->state = NOT_CONFIGURED;
return 0;
}
-static int disable_slot(struct hotplug_slot *hotplug_slot)
-{
- struct slot *slot = (struct slot *)hotplug_slot->private;
- int retval;
-
- down(&rpaphp_sem);
- retval = __disable_slot (slot);
- up(&rpaphp_sem);
-
- return retval;
-}
-
struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
.owner = THIS_MODULE,
.enable_slot = enable_slot,
diff --git a/drivers/pci/hotplug/rpaphp_pci.c b/drivers/pci/hotplug/rpaphp_pci.c
index 6f6cbede513..54ca8650d51 100644
--- a/drivers/pci/hotplug/rpaphp_pci.c
+++ b/drivers/pci/hotplug/rpaphp_pci.c
@@ -64,75 +64,6 @@ int rpaphp_get_sensor_state(struct slot *slot, int *state)
return rc;
}
-/**
- * get_pci_adapter_status - get the status of a slot
- *
- * 0-- slot is empty
- * 1-- adapter is configured
- * 2-- adapter is not configured
- * 3-- not valid
- */
-int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value)
-{
- struct pci_bus *bus;
- int state, rc;
-
- *value = NOT_VALID;
- rc = rpaphp_get_sensor_state(slot, &state);
- if (rc)
- goto exit;
-
- if (state == EMPTY)
- *value = EMPTY;
- else if (state == PRESENT) {
- if (!is_init) {
- /* at run-time slot->state can be changed by */
- /* config/unconfig adapter */
- *value = slot->state;
- } else {
- bus = pcibios_find_pci_bus(slot->dn);
- if (bus && !list_empty(&bus->devices))
- *value = CONFIGURED;
- else
- *value = NOT_CONFIGURED;
- }
- }
-exit:
- return rc;
-}
-
-static void print_slot_pci_funcs(struct pci_bus *bus)
-{
- struct device_node *dn;
- struct pci_dev *dev;
-
- dn = pci_bus_to_OF_node(bus);
- if (!dn)
- return;
-
- dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, dn->full_name);
- list_for_each_entry (dev, &bus->devices, bus_list)
- dbg("\t%s\n", pci_name(dev));
- return;
-}
-
-static int setup_pci_hotplug_slot_info(struct slot *slot)
-{
- struct hotplug_slot_info *hotplug_slot_info = slot->hotplug_slot->info;
-
- dbg("%s Initilize the PCI slot's hotplug->info structure ...\n",
- __FUNCTION__);
- rpaphp_get_power_status(slot, &hotplug_slot_info->power_status);
- rpaphp_get_pci_adapter_status(slot, 1,
- &hotplug_slot_info->adapter_status);
- if (hotplug_slot_info->adapter_status == NOT_VALID) {
- err("%s: NOT_VALID: skip dn->full_name=%s\n",
- __FUNCTION__, slot->dn->full_name);
- return -EINVAL;
- }
- return 0;
-}
-
static void set_slot_name(struct slot *slot)
{
struct pci_bus *bus = slot->bus;
@@ -146,69 +77,73 @@ static void set_slot_name(struct slot *slot)
bus->number);
}
-static int setup_pci_slot(struct slot *slot)
+/**
+ * rpaphp_enable_slot - record slot state, config pci device
+ *
+ * Initialize values in the slot, and the hotplug_slot info
+ * structures to indicate if there is a pci card plugged into
+ * the slot. If the slot is not empty, run the pcibios routine
+ * to get pcibios stuff correctly set up.
+ */
+int rpaphp_enable_slot(struct slot *slot)
{
- struct device_node *dn = slot->dn;
+ int rc, level, state;
struct pci_bus *bus;
+ struct hotplug_slot_info *info = slot->hotplug_slot->info;
+
+ info->adapter_status = NOT_VALID;
+ slot->state = EMPTY;
+
+ /* Find out if the power is turned on for the slot */
+ rc = rtas_get_power_level(slot->power_domain, &level);
+ if (rc)
+ return rc;
+ info->power_status = level;
+
+ /* Figure out if there is an adapter in the slot */
+ rc = rpaphp_get_sensor_state(slot, &state);
+ if (rc)
+ return rc;
- BUG_ON(!dn);
- bus = pcibios_find_pci_bus(dn);
+ bus = pcibios_find_pci_bus(slot->dn);
if (!bus) {
- err("%s: no pci_bus for dn %s\n", __FUNCTION__, dn->full_name);
- goto exit_rc;
+ err("%s: no pci_bus for dn %s\n", __FUNCTION__, slot->dn->full_name);
+ return -EINVAL;
}
+ info->adapter_status = EMPTY;
slot->bus = bus;
slot->pci_devs = &bus->devices;
set_slot_name(slot);
- /* find slot's pci_dev if it's not empty */
- if (slot->hotplug_slot->info->adapter_status == EMPTY) {
- slot->state = EMPTY; /* slot is empty */
- } else {
- /* slot is occupied */
- if (!dn->child) {
- /* non-empty slot has to have child */
- err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
- __FUNCTION__, slot->name);
- goto exit_rc;
+ /* if there's an adapter in the slot, go add the pci devices */
+ if (state == PRESENT) {
+ info->adapter_status = NOT_CONFIGURED;
+ slot->state = NOT_CONFIGURED;
+
+ /* non-empty slot has to have child */
+ if (!slot->dn->child) {
+ err("%s: slot[%s]'s device_node doesn't have child for adapter\n",
+ __FUNCTION__, slot->name);
+ return -EINVAL;
}
- if (slot->hotplug_slot->info->adapter_status == NOT_CONFIGURED) {
- dbg("%s CONFIGURING pci adapter in slot[%s]\n",
- __FUNCTION__, slot->name);
- pcibios_add_pci_devices(slot->bus);
+ if (list_empty(&bus->devices))
+ pcibios_add_pci_devices(bus);
- } else if (slot->hotplug_slot->info->adapter_status != CONFIGURED) {
- err("%s: slot[%s]'s adapter_status is NOT_VALID.\n",
- __FUNCTION__, slot->name);
- goto exit_rc;
- }
- print_slot_pci_funcs(slot->bus);
- if (!list_empty(slot->pci_devs)) {
+ if (!list_empty(&bus->devices)) {
+ info->adapter_status = CONFIGURED;
slot->state = CONFIGURED;
- } else {
- /* DLPAR add as opposed to
- * boot time */
- slot->state = NOT_CONFIGURED;
+ }
+
+ if (debug) {
+ struct pci_dev *dev;
+ dbg("%s: pci_devs of slot[%s]\n", __FUNCTION__, slot->dn->full_name);
+ list_for_each_entry (dev, &bus->devices, bus_list)
+ dbg("\t%s\n", pci_name(dev));
}
}
- return 0;
-exit_rc:
- dealloc_slot_struct(slot);
- return -EINVAL;
-}
-int rpaphp_register_pci_slot(struct slot *slot)
-{
- int rc = -EINVAL;
-
- if (setup_pci_hotplug_slot_info(slot))
- goto exit_rc;
- if (setup_pci_slot(slot))
- goto exit_rc;
- rc = rpaphp_register_slot(slot);
-exit_rc:
- return rc;
+ return 0;
}
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index 3009193f005..d4ee8723fcb 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -56,7 +56,6 @@ static struct hotplug_slot_attribute php_attr_location = {
static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = (struct slot *) hotplug_slot->private;
-
dealloc_slot_struct(slot);
}
@@ -65,12 +64,12 @@ void dealloc_slot_struct(struct slot *slot)
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
+ kfree(slot->location);
kfree(slot);
- return;
}
-struct slot *alloc_slot_struct(struct device_node *dn, int drc_index, char *drc_name,
- int power_domain)
+struct slot *alloc_slot_struct(struct device_node *dn,
+ int drc_index, char *drc_name, int power_domain)
{
struct slot *slot;
@@ -115,7 +114,7 @@ error_nomem:
static int is_registered(struct slot *slot)
{
- struct slot *tmp_slot;
+ struct slot *tmp_slot;
list_for_each_entry(tmp_slot, &rpaphp_slot_head, rpaphp_slot_list) {
if (!strcmp(tmp_slot->name, slot->name))
@@ -140,8 +139,6 @@ int rpaphp_deregister_slot(struct slot *slot)
retval = pci_hp_deregister(php_slot);
if (retval)
err("Problem unregistering a slot %s\n", slot->name);
- else
- num_slots--;
dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
return retval;
@@ -160,14 +157,13 @@ int rpaphp_register_slot(struct slot *slot)
/* should not try to register the same slot twice */
if (is_registered(slot)) {
err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
- retval = -EAGAIN;
- goto register_fail;
+ return -EAGAIN;
}
retval = pci_hp_register(php_slot);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
- goto register_fail;
+ return retval;
}
/* create "phy_location" file */
@@ -181,43 +177,10 @@ int rpaphp_register_slot(struct slot *slot)
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
info("Slot [%s](PCI location=%s) registered\n", slot->name,
slot->location);
- num_slots++;
return 0;
sysfs_fail:
pci_hp_deregister(php_slot);
-register_fail:
- rpaphp_release_slot(php_slot);
return retval;
}
-int rpaphp_get_power_status(struct slot *slot, u8 * value)
-{
- int rc = 0, level;
-
- rc = rtas_get_power_level(slot->power_domain, &level);
- if (rc < 0) {
- err("failed to get power-level for slot(%s), rc=0x%x\n",
- slot->location, rc);
- return rc;
- }
-
- dbg("%s the power level of slot %s(pwd-domain:0x%x) is %d\n",
- __FUNCTION__, slot->name, slot->power_domain, level);
- *value = level;
-
- return rc;
-}
-
-int rpaphp_set_attention_status(struct slot *slot, u8 status)
-{
- int rc;
-
- /* status: LED_OFF or LED_ON */
- rc = rtas_set_indicator(DR_INDICATOR, slot->index, status);
- if (rc < 0)
- err("slot(name=%s location=%s index=0x%x) set attention-status(%d) failed! rc=0x%x\n",
- slot->name, slot->location, slot->index, status, rc);
-
- return rc;
-}
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 01d31a1f697..37ed0884b97 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -166,7 +166,7 @@ extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
extern int shpchp_configure_device(struct slot *p_slot);
extern int shpchp_unconfigure_device(struct slot *p_slot);
extern void cleanup_slots(struct controller *ctrl);
-extern void queue_pushbutton_work(struct work_struct *work);
+extern void shpchp_queue_pushbutton_work(struct work_struct *work);
extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
#ifdef CONFIG_ACPI
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 5f4bc08a633..80dec9796b3 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -136,7 +136,7 @@ static int init_slots(struct controller *ctrl)
slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
mutex_init(&slot->lock);
- INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work);
+ INIT_DELAYED_WORK(&slot->work, shpchp_queue_pushbutton_work);
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index b746bd265bc..d2fc35598cd 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -30,7 +30,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/workqueue.h>
#include "../pci.h"
@@ -433,7 +432,7 @@ static void shpchp_pushbutton_thread(struct work_struct *work)
kfree(info);
}
-void queue_pushbutton_work(struct work_struct *work)
+void shpchp_queue_pushbutton_work(struct work_struct *work)
{
struct slot *p_slot = container_of(work, struct slot, work.work);
struct pushbutton_work_info *info;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 435c1958a7b..e6740d1a082 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -12,7 +12,6 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/msi.h>
@@ -24,20 +23,8 @@
#include "pci.h"
#include "msi.h"
-static struct kmem_cache* msi_cachep;
-
static int pci_msi_enable = 1;
-static int msi_cache_init(void)
-{
- msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
- if (!msi_cachep)
- return -ENOMEM;
-
- return 0;
-}
-
static void msi_set_enable(struct pci_dev *dev, int enable)
{
int pos;
@@ -68,6 +55,29 @@ static void msix_set_enable(struct pci_dev *dev, int enable)
}
}
+static void msix_flush_writes(unsigned int irq)
+{
+ struct msi_desc *entry;
+
+ entry = get_irq_msi(irq);
+ BUG_ON(!entry || !entry->dev);
+ switch (entry->msi_attrib.type) {
+ case PCI_CAP_ID_MSI:
+ /* nothing to do */
+ break;
+ case PCI_CAP_ID_MSIX:
+ {
+ int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
+ readl(entry->mask_base + offset);
+ break;
+ }
+ default:
+ BUG();
+ break;
+ }
+}
+
static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
@@ -187,41 +197,28 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
void mask_msi_irq(unsigned int irq)
{
msi_set_mask_bit(irq, 1);
+ msix_flush_writes(irq);
}
void unmask_msi_irq(unsigned int irq)
{
msi_set_mask_bit(irq, 0);
+ msix_flush_writes(irq);
}
-static int msi_free_irq(struct pci_dev* dev, int irq);
-
-static int msi_init(void)
-{
- static int status = -ENOMEM;
-
- if (!status)
- return status;
+static int msi_free_irqs(struct pci_dev* dev);
- status = msi_cache_init();
- if (status < 0) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: MSI cache init failed\n");
- return status;
- }
-
- return status;
-}
static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
- entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL);
+ entry = kzalloc(sizeof(struct msi_desc), GFP_KERNEL);
if (!entry)
return NULL;
- entry->link.tail = entry->link.head = 0; /* single message */
+ INIT_LIST_HEAD(&entry->list);
+ entry->irq = 0;
entry->dev = NULL;
return entry;
@@ -256,7 +253,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
static void __pci_restore_msix_state(struct pci_dev *dev)
{
int pos;
- int irq, head, tail = 0;
struct msi_desc *entry;
u16 control;
@@ -266,18 +262,15 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
/* route the table */
pci_intx(dev, 0); /* disable intx */
msix_set_enable(dev, 0);
- irq = head = dev->first_msi_irq;
- entry = get_irq_msi(irq);
- pos = entry->msi_attrib.pos;
- while (head != tail) {
- entry = get_irq_msi(irq);
- write_msi_msg(irq, &entry->msg);
- msi_set_mask_bit(irq, entry->msi_attrib.masked);
- tail = entry->link.tail;
- irq = tail;
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ write_msi_msg(entry->irq, &entry->msg);
+ msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
}
+ BUG_ON(list_empty(&dev->msi_list));
+ entry = list_entry(dev->msi_list.next, struct msi_desc, list);
+ pos = entry->msi_attrib.pos;
pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
control &= ~PCI_MSIX_FLAGS_MASKALL;
control |= PCI_MSIX_FLAGS_ENABLE;
@@ -303,7 +296,7 @@ void pci_restore_msi_state(struct pci_dev *dev)
static int msi_capability_init(struct pci_dev *dev)
{
struct msi_desc *entry;
- int pos, irq;
+ int pos, ret;
u16 control;
msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
@@ -340,23 +333,21 @@ static int msi_capability_init(struct pci_dev *dev)
msi_mask_bits_reg(pos, is_64bit_address(control)),
maskbits);
}
+ list_add(&entry->list, &dev->msi_list);
+
/* Configure MSI capability structure */
- irq = arch_setup_msi_irq(dev, entry);
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- return irq;
+ ret = arch_setup_msi_irqs(dev, 1, PCI_CAP_ID_MSI);
+ if (ret) {
+ msi_free_irqs(dev);
+ return ret;
}
- entry->link.head = irq;
- entry->link.tail = irq;
- dev->first_msi_irq = irq;
- set_irq_msi(irq, entry);
/* Set MSI enabled bits */
pci_intx(dev, 0); /* disable intx */
msi_set_enable(dev, 1);
dev->msi_enabled = 1;
- dev->irq = irq;
+ dev->irq = entry->irq;
return 0;
}
@@ -373,8 +364,8 @@ static int msi_capability_init(struct pci_dev *dev)
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
- struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- int irq, pos, i, j, nr_entries, temp = 0;
+ struct msi_desc *entry;
+ int pos, i, j, nr_entries, ret;
unsigned long phys_addr;
u32 table_offset;
u16 control;
@@ -413,44 +404,34 @@ static int msix_capability_init(struct pci_dev *dev,
entry->dev = dev;
entry->mask_base = base;
- /* Configure MSI-X capability structure */
- irq = arch_setup_msi_irq(dev, entry);
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- break;
- }
- entries[i].vector = irq;
- if (!head) {
- entry->link.head = irq;
- entry->link.tail = irq;
- head = entry;
- } else {
- entry->link.head = temp;
- entry->link.tail = tail->link.tail;
- tail->link.tail = irq;
- head->link.head = irq;
- }
- temp = irq;
- tail = entry;
-
- set_irq_msi(irq, entry);
+ list_add(&entry->list, &dev->msi_list);
}
- if (i != nvec) {
- int avail = i - 1;
- i--;
- for (; i >= 0; i--) {
- irq = (entries + i)->vector;
- msi_free_irq(dev, irq);
- (entries + i)->vector = 0;
+
+ ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
+ if (ret) {
+ int avail = 0;
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq != 0) {
+ avail++;
+ }
}
+
+ msi_free_irqs(dev);
+
/* If we had some success report the number of irqs
* we succeeded in setting up.
*/
- if (avail <= 0)
- avail = -EBUSY;
+ if (avail == 0)
+ avail = ret;
return avail;
}
- dev->first_msi_irq = entries[0].vector;
+
+ i = 0;
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ entries[i].vector = entry->irq;
+ set_irq_msi(entry->irq, entry);
+ i++;
+ }
/* Set MSI-X enabled bits */
pci_intx(dev, 0); /* disable intx */
msix_set_enable(dev, 1);
@@ -460,21 +441,32 @@ static int msix_capability_init(struct pci_dev *dev,
}
/**
- * pci_msi_supported - check whether MSI may be enabled on device
+ * pci_msi_check_device - check whether MSI may be enabled on a device
* @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: how many MSIs have been requested ?
+ * @type: are we checking for MSI or MSI-X ?
*
* Look at global flags, the device itself, and its parent busses
- * to return 0 if MSI are supported for the device.
+ * to determine if MSI/-X are supported for the device. If MSI/-X is
+ * supported return 0, else return an error code.
**/
-static
-int pci_msi_supported(struct pci_dev * dev)
+static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
{
struct pci_bus *bus;
+ int ret;
/* MSI must be globally enabled and supported by the device */
if (!pci_msi_enable || !dev || dev->no_msi)
return -EINVAL;
+ /*
+ * You can't ask to have 0 or less MSIs configured.
+ * a) it's stupid ..
+ * b) the list manipulation code assumes nvec >= 1.
+ */
+ if (nvec < 1)
+ return -ERANGE;
+
/* Any bridge which does NOT route MSI transactions from it's
* secondary bus to it's primary bus must set NO_MSI flag on
* the secondary pci_bus.
@@ -485,6 +477,13 @@ int pci_msi_supported(struct pci_dev * dev)
if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
return -EINVAL;
+ ret = arch_msi_check_device(dev, nvec, type);
+ if (ret)
+ return ret;
+
+ if (!pci_find_capability(dev, type))
+ return -EINVAL;
+
return 0;
}
@@ -500,19 +499,12 @@ int pci_msi_supported(struct pci_dev * dev)
**/
int pci_enable_msi(struct pci_dev* dev)
{
- int pos, status;
-
- if (pci_msi_supported(dev) < 0)
- return -EINVAL;
+ int status;
- status = msi_init();
- if (status < 0)
+ status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
+ if (status)
return status;
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (!pos)
- return -EINVAL;
-
WARN_ON(!!dev->msi_enabled);
/* Check whether driver already requested for MSI-X irqs */
@@ -525,69 +517,54 @@ int pci_enable_msi(struct pci_dev* dev)
status = msi_capability_init(dev);
return status;
}
+EXPORT_SYMBOL(pci_enable_msi);
void pci_disable_msi(struct pci_dev* dev)
{
struct msi_desc *entry;
int default_irq;
- if (!pci_msi_enable)
- return;
- if (!dev)
- return;
-
- if (!dev->msi_enabled)
+ if (!pci_msi_enable || !dev || !dev->msi_enabled)
return;
msi_set_enable(dev, 0);
pci_intx(dev, 1); /* enable intx */
dev->msi_enabled = 0;
- entry = get_irq_msi(dev->first_msi_irq);
- if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
+ BUG_ON(list_empty(&dev->msi_list));
+ entry = list_entry(dev->msi_list.next, struct msi_desc, list);
+ if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
return;
}
- if (irq_has_action(dev->first_msi_irq)) {
- printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
- "free_irq() on MSI irq %d\n",
- pci_name(dev), dev->first_msi_irq);
- BUG_ON(irq_has_action(dev->first_msi_irq));
- } else {
- default_irq = entry->msi_attrib.default_irq;
- msi_free_irq(dev, dev->first_msi_irq);
-
- /* Restore dev->irq to its default pin-assertion irq */
- dev->irq = default_irq;
- }
- dev->first_msi_irq = 0;
+
+ default_irq = entry->msi_attrib.default_irq;
+ msi_free_irqs(dev);
+
+ /* Restore dev->irq to its default pin-assertion irq */
+ dev->irq = default_irq;
}
+EXPORT_SYMBOL(pci_disable_msi);
-static int msi_free_irq(struct pci_dev* dev, int irq)
+static int msi_free_irqs(struct pci_dev* dev)
{
- struct msi_desc *entry;
- int head, entry_nr, type;
- void __iomem *base;
+ struct msi_desc *entry, *tmp;
- entry = get_irq_msi(irq);
- if (!entry || entry->dev != dev) {
- return -EINVAL;
- }
- type = entry->msi_attrib.type;
- entry_nr = entry->msi_attrib.entry_nr;
- head = entry->link.head;
- base = entry->mask_base;
- get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
- get_irq_msi(entry->link.tail)->link.head = entry->link.head;
-
- arch_teardown_msi_irq(irq);
- kmem_cache_free(msi_cachep, entry);
-
- if (type == PCI_CAP_ID_MSIX) {
- writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
-
- if (head == irq)
- iounmap(base);
+ list_for_each_entry(entry, &dev->msi_list, list)
+ BUG_ON(irq_has_action(entry->irq));
+
+ arch_teardown_msi_irqs(dev);
+
+ list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
+ if (entry->msi_attrib.type == PCI_CAP_ID_MSIX) {
+ if (list_is_last(&entry->list, &dev->msi_list))
+ iounmap(entry->mask_base);
+
+ writel(1, entry->mask_base + entry->msi_attrib.entry_nr
+ * PCI_MSIX_ENTRY_SIZE
+ + PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+ }
+ list_del(&entry->list);
+ kfree(entry);
}
return 0;
@@ -614,17 +591,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
int i, j;
u16 control;
- if (!entries || pci_msi_supported(dev) < 0)
+ if (!entries)
return -EINVAL;
- status = msi_init();
- if (status < 0)
+ status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
+ if (status)
return status;
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (!pos)
- return -EINVAL;
-
pci_read_config_word(dev, msi_control_reg(pos), &control);
nr_entries = multi_msix_capable(control);
if (nvec > nr_entries)
@@ -651,41 +625,25 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
status = msix_capability_init(dev, entries, nvec);
return status;
}
+EXPORT_SYMBOL(pci_enable_msix);
-void pci_disable_msix(struct pci_dev* dev)
+static void msix_free_all_irqs(struct pci_dev *dev)
{
- int irq, head, tail = 0, warning = 0;
-
- if (!pci_msi_enable)
- return;
- if (!dev)
- return;
+ msi_free_irqs(dev);
+}
- if (!dev->msix_enabled)
+void pci_disable_msix(struct pci_dev* dev)
+{
+ if (!pci_msi_enable || !dev || !dev->msix_enabled)
return;
msix_set_enable(dev, 0);
pci_intx(dev, 1); /* enable intx */
dev->msix_enabled = 0;
- irq = head = dev->first_msi_irq;
- while (head != tail) {
- tail = get_irq_msi(irq)->link.tail;
- if (irq_has_action(irq))
- warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
- if (warning) {
- printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X irqs\n",
- pci_name(dev));
- BUG_ON(warning > 0);
- }
- dev->first_msi_irq = 0;
+ msix_free_all_irqs(dev);
}
+EXPORT_SYMBOL(pci_disable_msix);
/**
* msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
@@ -701,38 +659,11 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
if (!pci_msi_enable || !dev)
return;
- if (dev->msi_enabled) {
- if (irq_has_action(dev->first_msi_irq)) {
- printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on MSI irq %d\n",
- pci_name(dev), dev->first_msi_irq);
- BUG_ON(irq_has_action(dev->first_msi_irq));
- } else /* Release MSI irq assigned to this device */
- msi_free_irq(dev, dev->first_msi_irq);
- }
- if (dev->msix_enabled) {
- int irq, head, tail = 0, warning = 0;
- void __iomem *base = NULL;
-
- irq = head = dev->first_msi_irq;
- while (head != tail) {
- tail = get_irq_msi(irq)->link.tail;
- base = get_irq_msi(irq)->mask_base;
- if (irq_has_action(irq))
- warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
- if (warning) {
- iounmap(base);
- printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on all MSI-X irqs\n",
- pci_name(dev));
- BUG_ON(warning > 0);
- }
- }
+ if (dev->msi_enabled)
+ msi_free_irqs(dev);
+
+ if (dev->msix_enabled)
+ msix_free_all_irqs(dev);
}
void pci_no_msi(void)
@@ -740,7 +671,53 @@ void pci_no_msi(void)
pci_msi_enable = 0;
}
-EXPORT_SYMBOL(pci_enable_msi);
-EXPORT_SYMBOL(pci_disable_msi);
-EXPORT_SYMBOL(pci_enable_msix);
-EXPORT_SYMBOL(pci_disable_msix);
+void pci_msi_init_pci_dev(struct pci_dev *dev)
+{
+ INIT_LIST_HEAD(&dev->msi_list);
+}
+
+
+/* Arch hooks */
+
+int __attribute__ ((weak))
+arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
+{
+ return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *entry)
+{
+ return 0;
+}
+
+int __attribute__ ((weak))
+arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ struct msi_desc *entry;
+ int ret;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ ret = arch_setup_msi_irq(dev, entry);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+void __attribute__ ((weak)) arch_teardown_msi_irq(unsigned int irq)
+{
+ return;
+}
+
+void __attribute__ ((weak))
+arch_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq != 0)
+ arch_teardown_msi_irq(entry->irq);
+ }
+}
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index a064f36a080..b5ac810404c 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -317,6 +317,10 @@ static int __init acpi_pci_init(void)
{
int ret;
+ if (acpi_gbl_FADT.boot_flags & BAF_MSI_NOT_SUPPORTED) {
+ printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n");
+ pci_no_msi();
+ }
ret = register_acpi_bus_type(&acpi_pci_bus);
if (ret)
return 0;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 39e80fcef4b..8e58ea3d95c 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -14,20 +14,6 @@
#include "pci.h"
/*
- * Registration of PCI drivers and handling of hot-pluggable devices.
- */
-
-/* multithreaded probe logic */
-static int pci_multithread_probe =
-#ifdef CONFIG_PCI_MULTITHREAD_PROBE
- 1;
-#else
- 0;
-#endif
-__module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644);
-
-
-/*
* Dynamic device IDs are disabled for !CONFIG_HOTPLUG
*/
@@ -52,7 +38,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
{
struct pci_dynid *dynid;
struct pci_driver *pdrv = to_pci_driver(driver);
- __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID,
+ __u32 vendor, device, subvendor=PCI_ANY_ID,
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
@@ -61,7 +47,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
fields = sscanf(buf, "%x %x %x %x %x %x %lux",
&vendor, &device, &subvendor, &subdevice,
&class, &class_mask, &driver_data);
- if (fields < 0)
+ if (fields < 2)
return -EINVAL;
dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
@@ -133,7 +119,7 @@ static inline int pci_create_newid_file(struct pci_driver *drv)
* system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
*
- * Depreciated, don't use this as it will not catch any dynamic ids
+ * Deprecated, don't use this as it will not catch any dynamic ids
* that a driver might want to check for.
*/
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
@@ -569,7 +555,6 @@ struct bus_type pci_bus_type = {
static int __init pci_driver_init(void)
{
- pci_bus_type.multithread_probe = pci_multithread_probe;
return bus_register(&pci_bus_type);
}
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index cd913a2a416..284e83a527f 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -620,7 +620,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
goto err_bin_file;
/* If the device has a ROM, try to expose it in sysfs. */
- if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
+ if (pci_resource_len(pdev, PCI_ROM_RESOURCE) ||
+ (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)) {
rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
if (rom_attr) {
pdev->rom_attr = rom_attr;
@@ -635,7 +636,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
goto err_rom;
} else {
retval = -ENOMEM;
- goto err_bin_file;
+ goto err_resource_files;
}
}
/* add platform-specific attributes */
@@ -645,6 +646,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
err_rom:
kfree(rom_attr);
+err_resource_files:
+ pci_remove_resource_files(pdev);
err_bin_file:
if (pdev->cfg_size < 4096)
sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
@@ -695,4 +698,4 @@ static int __init pci_sysfs_init(void)
return 0;
}
-__initcall(pci_sysfs_init);
+late_initcall(pci_sysfs_init);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2a458279327..fd47ac0c473 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -35,8 +35,7 @@ unsigned long pci_cardbus_mem_size = DEFAULT_CARDBUS_MEM_SIZE;
* Given a PCI bus, returns the highest PCI bus number present in the set
* including the given PCI bus and its list of child PCI buses.
*/
-unsigned char __devinit
-pci_bus_max_busnr(struct pci_bus* bus)
+unsigned char pci_bus_max_busnr(struct pci_bus* bus)
{
struct list_head *tmp;
unsigned char max, n;
@@ -892,6 +891,34 @@ pci_disable_device(struct pci_dev *dev)
}
/**
+ * pcibios_set_pcie_reset_state - set reset state for device dev
+ * @dev: the PCI-E device reset
+ * @state: Reset state to enter into
+ *
+ *
+ * Sets the PCI-E reset state for the device. This is the default
+ * implementation. Architecture implementations can override this.
+ */
+int __attribute__ ((weak)) pcibios_set_pcie_reset_state(struct pci_dev *dev,
+ enum pcie_reset_state state)
+{
+ return -EINVAL;
+}
+
+/**
+ * pci_set_pcie_reset_state - set reset state for device dev
+ * @dev: the PCI-E device reset
+ * @state: Reset state to enter into
+ *
+ *
+ * Sets the PCI reset state for the device.
+ */
+int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
+{
+ return pcibios_set_pcie_reset_state(dev, state);
+}
+
+/**
* pci_enable_wake - enable PCI device as wakeup event source
* @dev: PCI device affected
* @state: PCI state from which device will issue wakeup events
@@ -1295,7 +1322,7 @@ pci_intx(struct pci_dev *pdev, int enable)
/**
* pci_msi_off - disables any msi or msix capabilities
- * @pdev: the PCI device to operate on
+ * @dev: the PCI device to operate on
*
* If you want to use msi see pci_enable_msi and friends.
* This is a lower level primitive that allows us to disable
@@ -1427,4 +1454,5 @@ EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
+EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 62ea04c8af6..3fec13d3add 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -47,8 +47,10 @@ extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
void pci_no_msi(void);
+extern void pci_msi_init_pci_dev(struct pci_dev *dev);
#else
static inline void pci_no_msi(void) { }
+static inline void pci_msi_init_pci_dev(struct pci_dev *dev) { }
#endif
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 2fe1d690eb1..e48fcf08962 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -364,7 +364,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
}
}
-static struct pci_bus * __devinit pci_alloc_bus(void)
+static struct pci_bus * pci_alloc_bus(void)
{
struct pci_bus *b;
@@ -432,7 +432,7 @@ error_register:
return NULL;
}
-struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{
struct pci_bus *child;
@@ -461,7 +461,7 @@ static void pci_enable_crs(struct pci_dev *dev)
pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl);
}
-static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
+static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
{
struct pci_bus *parent = child->parent;
@@ -477,7 +477,7 @@ static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child,
}
}
-unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
+unsigned int pci_scan_child_bus(struct pci_bus *bus);
/*
* If it's a bridge, configure it and scan the bus behind it.
@@ -489,7 +489,7 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
* them, we proceed to assigning numbers to the remaining buses in
* order to avoid overlaps between old and new bus numbers.
*/
-int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
{
struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
@@ -846,6 +846,23 @@ static void pci_release_bus_bridge_dev(struct device *dev)
kfree(dev);
}
+struct pci_dev *alloc_pci_dev(void)
+{
+ struct pci_dev *dev;
+
+ dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ INIT_LIST_HEAD(&dev->global_list);
+ INIT_LIST_HEAD(&dev->bus_list);
+
+ pci_msi_init_pci_dev(dev);
+
+ return dev;
+}
+EXPORT_SYMBOL(alloc_pci_dev);
+
/*
* Read the config data for a PCI device, sanity-check it
* and fill in the dev structure...
@@ -885,7 +902,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
return NULL;
- dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ dev = alloc_pci_dev();
if (!dev)
return NULL;
@@ -912,7 +929,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
return dev;
}
-void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
+void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
device_initialize(&dev->dev);
dev->dev.release = pci_release_dev;
@@ -935,8 +952,7 @@ void __devinit pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
up_write(&pci_bus_sem);
}
-struct pci_dev * __devinit
-pci_scan_single_device(struct pci_bus *bus, int devfn)
+struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
@@ -958,7 +974,7 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
* discovered devices to the @bus->devices list. New devices
* will have an empty dev->global_list head.
*/
-int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
+int pci_scan_slot(struct pci_bus *bus, int devfn)
{
int func, nr = 0;
int scan_all_fns;
@@ -991,7 +1007,7 @@ int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
return nr;
}
-unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
+unsigned int pci_scan_child_bus(struct pci_bus *bus)
{
unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev;
@@ -1041,7 +1057,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
return max;
}
-struct pci_bus * __devinit pci_create_bus(struct device *parent,
+struct pci_bus * pci_create_bus(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
int error;
@@ -1119,7 +1135,7 @@ err_out:
}
EXPORT_SYMBOL_GPL(pci_create_bus);
-struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent,
+struct pci_bus *pci_scan_bus_parented(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
struct pci_bus *b;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index ed87aa59f0b..0425a7b7350 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -11,7 +11,6 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 65d6f23ead4..147d86f8edb 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1303,119 +1303,6 @@ static void __init quirk_alder_ioapic(struct pci_dev *pdev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic );
#endif
-enum ide_combined_type { COMBINED = 0, IDE = 1, LIBATA = 2 };
-/* Defaults to combined */
-static enum ide_combined_type combined_mode;
-
-static int __init combined_setup(char *str)
-{
- if (!strncmp(str, "ide", 3))
- combined_mode = IDE;
- else if (!strncmp(str, "libata", 6))
- combined_mode = LIBATA;
- else /* "combined" or anything else defaults to old behavior */
- combined_mode = COMBINED;
-
- return 1;
-}
-__setup("combined_mode=", combined_setup);
-
-#ifdef CONFIG_SATA_INTEL_COMBINED
-static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
-{
- u8 prog, comb, tmp;
- int ich = 0;
-
- /*
- * Narrow down to Intel SATA PCI devices.
- */
- switch (pdev->device) {
- /* PCI ids taken from drivers/scsi/ata_piix.c */
- case 0x24d1:
- case 0x24df:
- case 0x25a3:
- case 0x25b0:
- ich = 5;
- break;
- case 0x2651:
- case 0x2652:
- case 0x2653:
- case 0x2680: /* ESB2 */
- ich = 6;
- break;
- case 0x27c0:
- case 0x27c4:
- ich = 7;
- break;
- case 0x2828: /* ICH8M */
- ich = 8;
- break;
- default:
- /* we do not handle this PCI device */
- return;
- }
-
- /*
- * Read combined mode register.
- */
- pci_read_config_byte(pdev, 0x90, &tmp); /* combined mode reg */
-
- if (ich == 5) {
- tmp &= 0x6; /* interesting bits 2:1, PATA primary/secondary */
- if (tmp == 0x4) /* bits 10x */
- comb = (1 << 0); /* SATA port 0, PATA port 1 */
- else if (tmp == 0x6) /* bits 11x */
- comb = (1 << 2); /* PATA port 0, SATA port 1 */
- else
- return; /* not in combined mode */
- } else {
- WARN_ON((ich != 6) && (ich != 7) && (ich != 8));
- tmp &= 0x3; /* interesting bits 1:0 */
- if (tmp & (1 << 0))
- comb = (1 << 2); /* PATA port 0, SATA port 1 */
- else if (tmp & (1 << 1))
- comb = (1 << 0); /* SATA port 0, PATA port 1 */
- else
- return; /* not in combined mode */
- }
-
- /*
- * Read programming interface register.
- * (Tells us if it's legacy or native mode)
- */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog);
-
- /* if SATA port is in native mode, we're ok. */
- if (prog & comb)
- return;
-
- /* Don't reserve any so the IDE driver can get them (but only if
- * combined_mode=ide).
- */
- if (combined_mode == IDE)
- return;
-
- /* Grab them both for libata if combined_mode=libata. */
- if (combined_mode == LIBATA) {
- request_region(0x1f0, 8, "libata"); /* port 0 */
- request_region(0x170, 8, "libata"); /* port 1 */
- return;
- }
-
- /* SATA port is in legacy mode. Reserve port so that
- * IDE driver does not attempt to use it. If request_region
- * fails, it will be obvious at boot time, so we don't bother
- * checking return values.
- */
- if (comb == (1 << 0))
- request_region(0x1f0, 8, "libata"); /* port 0 */
- else
- request_region(0x170, 8, "libata"); /* port 1 */
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined );
-#endif /* CONFIG_SATA_INTEL_COMBINED */
-
-
int pcie_mch_quirk;
EXPORT_SYMBOL(pcie_mch_quirk);
@@ -1761,6 +1648,8 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_msi);
/* Go through the list of Hypertransport capabilities and
* return 1 if a HT MSI capability is found and enabled */
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 2dd8681d6b3..b137a27472c 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -15,8 +15,7 @@
DECLARE_RWSEM(pci_bus_sem);
-static struct pci_bus *
-pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
+static struct pci_bus *pci_do_find_bus(struct pci_bus *bus, unsigned char busnr)
{
struct pci_bus* child;
struct list_head *tmp;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 3554f394881..5ec297d7a5b 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -36,8 +36,7 @@
#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-static void __devinit
-pbus_assign_resources_sorted(struct pci_bus *bus)
+static void pbus_assign_resources_sorted(struct pci_bus *bus)
{
struct pci_dev *dev;
struct resource *res;
@@ -220,8 +219,7 @@ pci_setup_bridge(struct pci_bus *bus)
/* Check whether the bridge supports optional I/O and
prefetchable memory ranges. If not, the respective
base/limit registers must be read-only and read as 0. */
-static void __devinit
-pci_bridge_check_ranges(struct pci_bus *bus)
+static void pci_bridge_check_ranges(struct pci_bus *bus)
{
u16 io;
u32 pmem;
@@ -259,8 +257,7 @@ pci_bridge_check_ranges(struct pci_bus *bus)
bus resource of a given type. Note: we intentionally skip
the bus resources which have already been assigned (that is,
have non-NULL parent resource). */
-static struct resource * __devinit
-find_free_bus_resource(struct pci_bus *bus, unsigned long type)
+static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type)
{
int i;
struct resource *r;
@@ -281,8 +278,7 @@ find_free_bus_resource(struct pci_bus *bus, unsigned long type)
since these windows have 4K granularity and the IO ranges
of non-bridge PCI devices are limited to 256 bytes.
We must be careful with the ISA aliasing though. */
-static void __devinit
-pbus_size_io(struct pci_bus *bus)
+static void pbus_size_io(struct pci_bus *bus)
{
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -326,8 +322,7 @@ pbus_size_io(struct pci_bus *bus)
/* Calculate the size of the bus and minimal alignment which
guarantees that all child resources fit in this size. */
-static int __devinit
-pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
+static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
{
struct pci_dev *dev;
unsigned long min_align, align, size;
@@ -447,8 +442,7 @@ pci_bus_size_cardbus(struct pci_bus *bus)
}
}
-void __devinit
-pci_bus_size_bridges(struct pci_bus *bus)
+void pci_bus_size_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
unsigned long mask, prefmask;
@@ -498,8 +492,7 @@ pci_bus_size_bridges(struct pci_bus *bus)
}
EXPORT_SYMBOL(pci_bus_size_bridges);
-void __devinit
-pci_bus_assign_resources(struct pci_bus *bus)
+void pci_bus_assign_resources(struct pci_bus *bus)
{
struct pci_bus *b;
struct pci_dev *dev;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index cb4ced3560e..6dfd86167e3 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -101,8 +101,7 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
new & ~PCI_REGION_FLAG_MASK);
}
-int __devinit
-pci_claim_resource(struct pci_dev *dev, int resource)
+int pci_claim_resource(struct pci_dev *dev, int resource)
{
struct resource *res = &dev->resource[resource];
struct resource *root = NULL;
@@ -212,8 +211,7 @@ EXPORT_SYMBOL_GPL(pci_assign_resource_fixed);
#endif
/* Sort resources by alignment */
-void __devinit
-pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
+void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
{
int i;
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 99baabc2359..948efc775a7 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -360,7 +360,6 @@ static struct platform_driver at91_cf_driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
},
- .probe = at91_cf_probe,
.remove = __exit_p(at91_cf_remove),
.suspend = at91_cf_suspend,
.resume = at91_cf_resume,
@@ -370,7 +369,7 @@ static struct platform_driver at91_cf_driver = {
static int __init at91_cf_init(void)
{
- return platform_driver_register(&at91_cf_driver);
+ return platform_driver_probe(&at91_cf_driver, at91_cf_probe);
}
module_init(at91_cf_init);
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index ac004248324..50cad3a59a6 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -26,7 +26,6 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/pci.h>
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 18e111e1233..143c6efc478 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -234,6 +234,89 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
/*======================================================================*/
+struct pcmcia_dynid {
+ struct list_head node;
+ struct pcmcia_device_id id;
+};
+
+/**
+ * pcmcia_store_new_id - add a new PCMCIA device ID to this driver and re-probe devices
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Adds a new dynamic PCMCIA device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static ssize_t
+pcmcia_store_new_id(struct device_driver *driver, const char *buf, size_t count)
+{
+ struct pcmcia_dynid *dynid;
+ struct pcmcia_driver *pdrv = to_pcmcia_drv(driver);
+ __u16 match_flags, manf_id, card_id;
+ __u8 func_id, function, device_no;
+ __u32 prod_id_hash[4] = {0, 0, 0, 0};
+ int fields=0;
+ int retval = 0;
+
+ fields = sscanf(buf, "%hx %hx %hx %hhx %hhx %hhx %x %x %x %x",
+ &match_flags, &manf_id, &card_id, &func_id, &function, &device_no,
+ &prod_id_hash[0], &prod_id_hash[1], &prod_id_hash[2], &prod_id_hash[3]);
+ if (fields < 6)
+ return -EINVAL;
+
+ dynid = kzalloc(sizeof(struct pcmcia_dynid), GFP_KERNEL);
+ if (!dynid)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&dynid->node);
+ dynid->id.match_flags = match_flags;
+ dynid->id.manf_id = manf_id;
+ dynid->id.card_id = card_id;
+ dynid->id.func_id = func_id;
+ dynid->id.function = function;
+ dynid->id.device_no = device_no;
+ memcpy(dynid->id.prod_id_hash, prod_id_hash, sizeof(__u32) * 4);
+
+ spin_lock(&pdrv->dynids.lock);
+ list_add_tail(&pdrv->dynids.list, &dynid->node);
+ spin_unlock(&pdrv->dynids.lock);
+
+ if (get_driver(&pdrv->drv)) {
+ retval = driver_attach(&pdrv->drv);
+ put_driver(&pdrv->drv);
+ }
+
+ if (retval)
+ return retval;
+ return count;
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, pcmcia_store_new_id);
+
+static void
+pcmcia_free_dynids(struct pcmcia_driver *drv)
+{
+ struct pcmcia_dynid *dynid, *n;
+
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+ list_del(&dynid->node);
+ kfree(dynid);
+ }
+ spin_unlock(&drv->dynids.lock);
+}
+
+static int
+pcmcia_create_newid_file(struct pcmcia_driver *drv)
+{
+ int error = 0;
+ if (drv->probe != NULL)
+ error = sysfs_create_file(&drv->drv.kobj,
+ &driver_attr_new_id.attr);
+ return error;
+}
+
+
/**
* pcmcia_register_driver - register a PCMCIA driver with the bus core
*
@@ -241,6 +324,8 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
*/
int pcmcia_register_driver(struct pcmcia_driver *driver)
{
+ int error;
+
if (!driver)
return -EINVAL;
@@ -249,10 +334,20 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
/* initialize common fields */
driver->drv.bus = &pcmcia_bus_type;
driver->drv.owner = driver->owner;
+ spin_lock_init(&driver->dynids.lock);
+ INIT_LIST_HEAD(&driver->dynids.list);
ds_dbg(3, "registering driver %s\n", driver->drv.name);
- return driver_register(&driver->drv);
+ error = driver_register(&driver->drv);
+ if (error < 0)
+ return error;
+
+ error = pcmcia_create_newid_file(driver);
+ if (error)
+ driver_unregister(&driver->drv);
+
+ return error;
}
EXPORT_SYMBOL(pcmcia_register_driver);
@@ -263,6 +358,7 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver)
{
ds_dbg(3, "unregistering driver %s\n", driver->drv.name);
driver_unregister(&driver->drv);
+ pcmcia_free_dynids(driver);
}
EXPORT_SYMBOL(pcmcia_unregister_driver);
@@ -927,6 +1023,21 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
struct pcmcia_device_id *did = p_drv->id_table;
+ struct pcmcia_dynid *dynid;
+
+ /* match dynamic devices first */
+ spin_lock(&p_drv->dynids.lock);
+ list_for_each_entry(dynid, &p_drv->dynids.list, node) {
+ ds_dbg(3, "trying to match %s to %s\n", dev->bus_id,
+ drv->name);
+ if (pcmcia_devmatch(p_dev, &dynid->id)) {
+ ds_dbg(0, "matched %s to %s\n", dev->bus_id,
+ drv->name);
+ spin_unlock(&p_drv->dynids.lock);
+ return 1;
+ }
+ }
+ spin_unlock(&p_drv->dynids.lock);
#ifdef CONFIG_PCMCIA_IOCTL
/* matching by cardmgr */
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index fda06941e73..383107ba4bd 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,6 +175,7 @@ static int __init mst_pcmcia_init(void)
if (!mst_pcmcia_device)
return -ENOMEM;
+ mst_pcmcia_device->dev.uevent_suppress = 0;
mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
ret = platform_device_add(mst_pcmcia_device);
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index b7b9e149c5b..a2daa3f531b 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,6 +261,7 @@ static int __init sharpsl_pcmcia_init(void)
if (!sharpsl_pcmcia_device)
return -ENOMEM;
+ sharpsl_pcmcia_device->dev.uevent_suppress = 0;
sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index ea5765c3bdc..a2bb46526b5 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -22,7 +22,6 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/pm.h>
-#include <linux/pci.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <asm/system.h>
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index aec83ec5ea2..3e20b1cc777 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -14,6 +14,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
+#include <linux/dma-mapping.h>
#include "base.h"
@@ -22,6 +23,14 @@ static LIST_HEAD(pnp_protocols);
LIST_HEAD(pnp_global);
DEFINE_SPINLOCK(pnp_lock);
+/*
+ * ACPI or PNPBIOS should tell us about all platform devices, so we can
+ * skip some blind probes. ISAPNP typically enumerates only plug-in ISA
+ * devices, not built-in things like COM ports.
+ */
+int pnp_platform_devices;
+EXPORT_SYMBOL(pnp_platform_devices);
+
void *pnp_alloc(long size)
{
void *result;
@@ -114,6 +123,8 @@ int __pnp_add_device(struct pnp_dev *dev)
int ret;
pnp_fixup_device(dev);
dev->dev.bus = &pnp_bus_type;
+ dev->dev.dma_mask = &dev->dma_mask;
+ dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK;
dev->dev.release = &pnp_release_device;
dev->status = PNP_READY;
spin_lock(&pnp_lock);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index 62eda5d5902..a00548799e9 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2004 Matthieu Castet <castet.matthieu@free.fr>
* Copyright (c) 2004 Li Shaohua <shaohua.li@intel.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, or (at your option) any
@@ -18,7 +18,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
+
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <acpi/acpi_bus.h>
@@ -82,7 +82,7 @@ static void __init pnpidacpi_to_pnpid(char *id, char *str)
static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
{
acpi_status status;
- status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
+ status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
&dev->res);
return ACPI_FAILURE(status) ? -ENODEV : 0;
}
@@ -112,9 +112,9 @@ static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table
static int pnpacpi_disable_resources(struct pnp_dev *dev)
{
acpi_status status;
-
+
/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
- status = acpi_evaluate_object((acpi_handle)dev->data,
+ status = acpi_evaluate_object((acpi_handle)dev->data,
"_DIS", NULL, NULL);
return ACPI_FAILURE(status) ? -ENODEV : 0;
}
@@ -167,7 +167,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
dev->number = num;
-
+
/* set the initial values for the PnP device */
dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
if (!dev_id)
@@ -185,14 +185,14 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
}
if(dev->capabilities & PNP_CONFIGURABLE) {
- status = pnpacpi_parse_resource_option_data(device->handle,
+ status = pnpacpi_parse_resource_option_data(device->handle,
dev);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
goto err1;
}
}
-
+
/* parse compatible ids */
if (device->flags.compatible_ids) {
struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
@@ -236,6 +236,42 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
return AE_OK;
}
+static int __init acpi_pnp_match(struct device *dev, void *_pnp)
+{
+ struct acpi_device *acpi = to_acpi_device(dev);
+ struct pnp_dev *pnp = _pnp;
+
+ /* true means it matched */
+ return acpi->flags.hardware_id
+ && !acpi_get_physical_device(acpi->handle)
+ && compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
+}
+
+static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct device *adev;
+ struct acpi_device *acpi;
+
+ adev = bus_find_device(&acpi_bus_type, NULL,
+ to_pnp_dev(dev),
+ acpi_pnp_match);
+ if (!adev)
+ return -ENODEV;
+
+ acpi = to_acpi_device(adev);
+ *handle = acpi->handle;
+ put_device(adev);
+ return 0;
+}
+
+/* complete initialization of a PNPACPI device includes having
+ * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling.
+ */
+static struct acpi_bus_type __initdata acpi_pnp_bus = {
+ .bus = &pnp_bus_type,
+ .find_device = acpi_pnp_find_device,
+};
+
int pnpacpi_disabled __initdata;
static int __init pnpacpi_init(void)
{
@@ -245,8 +281,11 @@ static int __init pnpacpi_init(void)
}
pnp_info("PnP ACPI init");
pnp_register_protocol(&pnpacpi_protocol);
+ register_acpi_bus_type(&acpi_pnp_bus);
acpi_get_devices(NULL, pnpacpi_add_device_handler, NULL, NULL);
pnp_info("PnP ACPI: found %d devices", num);
+ unregister_acpi_bus_type(&acpi_pnp_bus);
+ pnp_platform_devices = 1;
return 0;
}
subsys_initcall(pnpacpi_init);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 95738dbd5d4..3a201b77b96 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -62,6 +62,7 @@
#include <linux/delay.h>
#include <linux/acpi.h>
#include <linux/freezer.h>
+#include <linux/kthread.h>
#include <asm/page.h>
#include <asm/desc.h>
@@ -159,9 +160,7 @@ static int pnp_dock_thread(void * unused)
{
static struct pnp_docking_station_info now;
int docked = -1, d = 0;
- daemonize("kpnpbiosd");
- allow_signal(SIGKILL);
- while(!unloading && !signal_pending(current))
+ while (!unloading)
{
int status;
@@ -170,11 +169,8 @@ static int pnp_dock_thread(void * unused)
*/
msleep_interruptible(2000);
- if(signal_pending(current)) {
- if (try_to_freeze())
- continue;
- break;
- }
+ if (try_to_freeze())
+ continue;
status = pnp_bios_dock_station_info(&now);
@@ -574,6 +570,7 @@ static int __init pnpbios_init(void)
/* scan for pnpbios devices */
build_devlist();
+ pnp_platform_devices = 1;
return 0;
}
@@ -581,6 +578,7 @@ subsys_initcall(pnpbios_init);
static int __init pnpbios_thread_init(void)
{
+ struct task_struct *task;
#if defined(CONFIG_PPC_MERGE)
if (check_legacy_ioport(PNPBIOS_BASE))
return 0;
@@ -589,7 +587,8 @@ static int __init pnpbios_thread_init(void)
return 0;
#ifdef CONFIG_HOTPLUG
init_completion(&unload_sem);
- if (kernel_thread(pnp_dock_thread, NULL, CLONE_KERNEL) > 0)
+ task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd");
+ if (!IS_ERR(task))
unloading = 0;
#endif
return 0;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e97ecefe858..277df50c89a 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/pnp.h>
+#include <linux/io.h>
#include "base.h"
@@ -106,6 +107,34 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
return;
}
+static void quirk_smc_enable(struct pnp_dev *dev)
+{
+ unsigned int firbase;
+
+ if (!dev->active || !pnp_port_valid(dev, 1))
+ return;
+
+ /*
+ * On the HP/Compaq nw8240 (and probably other similar machines),
+ * there is an SMCF010 device with two I/O port regions:
+ *
+ * 0x3e8-0x3ef SIR
+ * 0x100-0x10f FIR
+ *
+ * _STA reports the device is enabled, but in fact, the BIOS
+ * neglects to enable the FIR range. Fortunately, it does fully
+ * enable the device if we call _SRS.
+ */
+ firbase = pnp_port_start(dev, 1);
+ if (inb(firbase + 0x7 /* IRCC_MASTER */) == 0xff) {
+ pnp_err("%s (%s) enabled but not responding, disabling and "
+ "re-enabling", dev->dev.bus_id, pnp_dev_name(dev));
+ pnp_disable_dev(dev);
+ pnp_activate_dev(dev);
+ }
+}
+
+
/*
* PnP Quirks
* Cards or devices that need some tweaking due to incomplete resource info
@@ -126,6 +155,7 @@ static struct pnp_fixup pnp_fixups[] = {
{ "CTL0043", quirk_sb16audio_resources },
{ "CTL0044", quirk_sb16audio_resources },
{ "CTL0045", quirk_sb16audio_resources },
+ { "SMCf010", quirk_smc_enable },
{ "" }
};
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index d21e04ccb02..1393e64335f 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -38,7 +38,24 @@
static int timeout = 5000; /* in msec ( 5 sec ) */
module_param(timeout, int, 0644);
-static struct ps3av ps3av;
+static struct ps3av {
+ int available;
+ struct mutex mutex;
+ struct work_struct work;
+ struct completion done;
+ struct workqueue_struct *wq;
+ int open_count;
+ struct ps3_vuart_port_device *dev;
+
+ int region;
+ struct ps3av_pkt_av_get_hw_conf av_hw_conf;
+ u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX];
+ u32 opt_port[PS3AV_OPT_PORT_MAX];
+ u32 head[PS3AV_HEAD_MAX];
+ u32 audio_port;
+ int ps3av_mode;
+ int ps3av_mode_old;
+} ps3av;
static struct ps3_vuart_port_device ps3av_dev = {
.match_id = PS3_MATCH_ID_AV_SETTINGS
@@ -159,7 +176,7 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
else
printk(KERN_ERR
"%s: failed event packet, cid:%08x size:%d\n",
- __FUNCTION__, hdr->cid, hdr->size);
+ __func__, hdr->cid, hdr->size);
return 1; /* receive event packet */
}
return 0;
@@ -181,7 +198,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
if (res < 0) {
dev_dbg(&ps3av_dev.core,
"%s: ps3av_vuart_write() failed (result=%d)\n",
- __FUNCTION__, res);
+ __func__, res);
return res;
}
@@ -194,7 +211,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
if (res != PS3AV_HDR_SIZE) {
dev_dbg(&ps3av_dev.core,
"%s: ps3av_vuart_read() failed (result=%d)\n",
- __FUNCTION__, res);
+ __func__, res);
return res;
}
@@ -204,7 +221,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
if (res < 0) {
dev_dbg(&ps3av_dev.core,
"%s: ps3av_vuart_read() failed (result=%d)\n",
- __FUNCTION__, res);
+ __func__, res);
return res;
}
res += PS3AV_HDR_SIZE; /* total len */
@@ -214,7 +231,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n",
- __FUNCTION__, recv_buf->cid);
+ __func__, recv_buf->cid);
return -EINVAL;
}
@@ -250,7 +267,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
struct ps3av_send_hdr *buf)
{
int res = 0;
- union {
+ static union {
struct ps3av_reply_hdr reply_hdr;
u8 raw[PS3AV_BUF_SIZE];
} recv_buf;
@@ -259,8 +276,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
BUG_ON(!ps3av.available);
- if (down_interruptible(&ps3av.sem))
- return -ERESTARTSYS;
+ mutex_lock(&ps3av.mutex);
table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
BUG_ON(!table);
@@ -277,7 +293,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
if (res < 0) {
printk(KERN_ERR
"%s: ps3av_send_cmd_pkt() failed (result=%d)\n",
- __FUNCTION__, res);
+ __func__, res);
goto err;
}
@@ -286,16 +302,16 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
usr_buf_size);
if (res < 0) {
printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
- __FUNCTION__, res);
+ __func__, res);
goto err;
}
- up(&ps3av.sem);
+ mutex_unlock(&ps3av.mutex);
return 0;
err:
- up(&ps3av.sem);
- printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res);
+ mutex_unlock(&ps3av.mutex);
+ printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
return res;
}
@@ -440,7 +456,7 @@ static int ps3av_set_videomode(void)
ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
/* wake up ps3avd to do the actual video mode setting */
- up(&ps3av.ping);
+ queue_work(ps3av.wq, &ps3av.work);
return 0;
}
@@ -506,7 +522,7 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
if (res == PS3AV_STATUS_NO_SYNC_HEAD)
printk(KERN_WARNING
"%s: Command failed. Please try your request again. \n",
- __FUNCTION__);
+ __func__);
else if (res)
dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
@@ -515,18 +531,10 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF);
}
-static int ps3avd(void *p)
+static void ps3avd(struct work_struct *work)
{
- struct ps3av *info = p;
-
- daemonize("ps3avd");
- while (1) {
- down(&info->ping);
- ps3av_set_videomode_cont(info->ps3av_mode,
- info->ps3av_mode_old);
- up(&info->pong);
- }
- return 0;
+ ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old);
+ complete(&ps3av.done);
}
static int ps3av_vid2table_id(int vid)
@@ -707,8 +715,7 @@ int ps3av_set_video_mode(u32 id, int boot)
size = ARRAY_SIZE(video_mode_table);
if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
- dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__,
- id);
+ dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id);
return -EINVAL;
}
@@ -717,15 +724,14 @@ int ps3av_set_video_mode(u32 id, int boot)
if ((id & PS3AV_MODE_MASK) == 0) {
id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
if (id < 1) {
- printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__,
- id);
+ printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
return -EINVAL;
}
id |= option;
}
/* set videomode */
- down(&ps3av.pong);
+ wait_for_completion(&ps3av.done);
ps3av.ps3av_mode_old = ps3av.ps3av_mode;
ps3av.ps3av_mode = id;
if (ps3av_set_videomode())
@@ -736,6 +742,13 @@ int ps3av_set_video_mode(u32 id, int boot)
EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
+int ps3av_get_auto_mode(int boot)
+{
+ return ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
+}
+
+EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
+
int ps3av_set_mode(u32 id, int boot)
{
int res;
@@ -771,7 +784,7 @@ int ps3av_get_scanmode(int id)
id = id & PS3AV_MODE_MASK;
size = ARRAY_SIZE(video_mode_table);
if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+ printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
return -EINVAL;
}
return video_mode_table[id].interlace;
@@ -786,7 +799,7 @@ int ps3av_get_refresh_rate(int id)
id = id & PS3AV_MODE_MASK;
size = ARRAY_SIZE(video_mode_table);
if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+ printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
return -EINVAL;
}
return video_mode_table[id].freq;
@@ -802,7 +815,7 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
id = id & PS3AV_MODE_MASK;
size = ARRAY_SIZE(video_mode_table);
if (id > size - 1 || id < 0) {
- printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id);
+ printk(KERN_ERR "%s: invalid mode %d\n", __func__, id);
return -EINVAL;
}
*xres = video_mode_table[id].x;
@@ -838,7 +851,7 @@ int ps3av_dev_open(void)
status = lv1_gpu_open(0);
if (status) {
printk(KERN_ERR "%s: lv1_gpu_open failed %d\n",
- __FUNCTION__, status);
+ __func__, status);
ps3av.open_count--;
}
}
@@ -855,13 +868,13 @@ int ps3av_dev_close(void)
mutex_lock(&ps3av.mutex);
if (ps3av.open_count <= 0) {
- printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__);
+ printk(KERN_ERR "%s: GPU already closed\n", __func__);
status = -1;
} else if (!--ps3av.open_count) {
status = lv1_gpu_close();
if (status)
printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n",
- __FUNCTION__, status);
+ __func__, status);
}
mutex_unlock(&ps3av.mutex);
@@ -880,13 +893,16 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev)
memset(&ps3av, 0, sizeof(ps3av));
- init_MUTEX(&ps3av.sem);
- init_MUTEX_LOCKED(&ps3av.ping);
- init_MUTEX(&ps3av.pong);
mutex_init(&ps3av.mutex);
ps3av.ps3av_mode = 0;
ps3av.dev = dev;
- kernel_thread(ps3avd, &ps3av, CLONE_KERNEL);
+
+ INIT_WORK(&ps3av.work, ps3avd);
+ init_completion(&ps3av.done);
+ complete(&ps3av.done);
+ ps3av.wq = create_singlethread_workqueue("ps3avd");
+ if (!ps3av.wq)
+ return -ENOMEM;
ps3av.available = 1;
switch (ps3_os_area_get_av_multi_out()) {
@@ -908,7 +924,7 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev)
/* init avsetting modules */
res = ps3av_cmd_init();
if (res < 0)
- printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__,
+ printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__,
res);
ps3av_get_hw_conf(&ps3av);
@@ -926,6 +942,8 @@ static int ps3av_remove(struct ps3_vuart_port_device *dev)
{
if (ps3av.available) {
ps3av_cmd_fin();
+ if (ps3av.wq)
+ destroy_workqueue(ps3av.wq);
ps3av.available = 0;
}
@@ -958,7 +976,7 @@ static int ps3av_module_init(void)
if (error) {
printk(KERN_ERR
"%s: ps3_vuart_port_driver_register failed %d\n",
- __FUNCTION__, error);
+ __func__, error);
return error;
}
@@ -966,7 +984,7 @@ static int ps3av_module_init(void)
if (error)
printk(KERN_ERR
"%s: ps3_vuart_port_device_register failed %d\n",
- __FUNCTION__, error);
+ __func__, error);
return error;
}
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index bc70e81f8cb..0145ea173c4 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -395,7 +395,7 @@ u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt,
video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;
pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",
- __FUNCTION__, video_vid, video_mode->width, video_mode->height,
+ __func__, video_vid, video_mode->width, video_mode->height,
video_mode->pitch, video_mode->video_out_format,
video_mode->video_format, video_mode->video_order);
return sizeof(*video_mode);
@@ -477,7 +477,7 @@ static u8 ps3av_cnv_mclk(u32 fs)
if (ps3av_cnv_mclk_table[i].fs == fs)
return ps3av_cnv_mclk_table[i].mclk;
- printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
+ printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);
return 0;
}
@@ -526,13 +526,12 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid)
d = 4;
break;
default:
- printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__,
- video_vid);
+ printk(KERN_ERR "%s failed, vid:%x\n", __func__, video_vid);
break;
}
if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K)
- printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs);
+ printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs);
else
ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d];
@@ -555,8 +554,7 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable)
ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) |
0x01;
} else
- printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__,
- source);
+ printk(KERN_ERR "%s failed, source:%x\n", __func__, source);
return ret;
}
@@ -585,7 +583,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits)
ret = PS3AV_CMD_AV_INPUTLEN_24;
break;
default:
- printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__,
+ printk(KERN_ERR "%s failed, word_bits:%x\n", __func__,
word_bits);
break;
}
@@ -595,7 +593,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits)
static u8 ps3av_cnv_layout(u32 num_of_ch)
{
if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) {
- printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__,
+ printk(KERN_ERR "%s failed, num_of_ch:%x\n", __func__,
num_of_ch);
return 0;
}
@@ -864,7 +862,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
res = get_status(avb);
if (res)
- pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__,
+ pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __func__,
res);
out:
@@ -1013,7 +1011,7 @@ int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
return size;
if (error != -EAGAIN) {
printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
- __FUNCTION__, error);
+ __func__, error);
return error;
}
msleep(POLLING_INTERVAL);
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index 6c12744eeb9..ec2d36a1bc6 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -82,14 +82,6 @@ struct ports_bmp {
u64 unused[3];
} __attribute__ ((aligned (32)));
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
- const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
static void __attribute__ ((unused)) _dump_ports_bmp(
const struct ports_bmp* bmp, const char* func, int line)
@@ -894,12 +886,12 @@ static int ps3_vuart_probe(struct device *_dev)
if (++vuart_bus_priv.use_count == 1) {
- result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY,
+ result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY,
(void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq);
if (result) {
dev_dbg(&dev->core,
- "%s:%d: ps3_alloc_vuart_irq failed (%d)\n",
+ "%s:%d: ps3_vuart_irq_setup failed (%d)\n",
__func__, __LINE__, result);
result = -EPERM;
goto fail_alloc_irq;
@@ -945,7 +937,7 @@ static int ps3_vuart_probe(struct device *_dev)
fail_probe:
ps3_vuart_set_interrupt_mask(dev, 0);
fail_request_irq:
- ps3_free_vuart_irq(vuart_bus_priv.virq);
+ ps3_vuart_irq_destroy(vuart_bus_priv.virq);
vuart_bus_priv.virq = NO_IRQ;
fail_alloc_irq:
--vuart_bus_priv.use_count;
@@ -983,7 +975,7 @@ static int ps3_vuart_remove(struct device *_dev)
if (--vuart_bus_priv.use_count == 0) {
BUG();
free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
- ps3_free_vuart_irq(vuart_bus_priv.virq);
+ ps3_vuart_irq_destroy(vuart_bus_priv.virq);
vuart_bus_priv.virq = NO_IRQ;
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 95826b92ca4..76422eded36 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -21,21 +21,31 @@ config RTC_CLASS
will be called rtc-class.
config RTC_HCTOSYS
- bool "Set system time from RTC on startup"
+ bool "Set system time from RTC on startup and resume"
depends on RTC_CLASS = y
default y
help
- If you say yes here, the system time will be set using
- the value read from the specified RTC device. This is useful
- in order to avoid unnecessary fsck runs.
+ If you say yes here, the system time (wall clock) will be set using
+ the value read from a specified RTC device. This is useful to avoid
+ unnecessary fsck runs at boot time, and to network better.
config RTC_HCTOSYS_DEVICE
- string "The RTC to read the time from"
+ string "RTC used to set the system time"
depends on RTC_HCTOSYS = y
default "rtc0"
help
- The RTC device that will be used as the source for
- the system time, usually rtc0.
+ The RTC device that will be used to (re)initialize the system
+ clock, usually rtc0. Initialization is done when the system
+ starts up, and when it resumes from a low power state.
+
+ This clock should be battery-backed, so that it reads the correct
+ time when the system boots from a power-off state. Otherwise, your
+ system will need an external clock source (like an NTP server).
+
+ If the clock you specify here is not battery backed, it may still
+ be useful to reinitialize system time when resuming from system
+ sleep states. Do not specify an RTC here unless it stays powered
+ during all this system's supported sleep states.
config RTC_DEBUG
bool "RTC debug support"
@@ -48,7 +58,7 @@ comment "RTC interfaces"
depends on RTC_CLASS
config RTC_INTF_SYSFS
- tristate "sysfs"
+ boolean "sysfs"
depends on RTC_CLASS && SYSFS
default RTC_CLASS
help
@@ -59,7 +69,7 @@ config RTC_INTF_SYSFS
will be called rtc-sysfs.
config RTC_INTF_PROC
- tristate "proc"
+ boolean "proc"
depends on RTC_CLASS && PROC_FS
default RTC_CLASS
help
@@ -71,7 +81,7 @@ config RTC_INTF_PROC
will be called rtc-proc.
config RTC_INTF_DEV
- tristate "dev"
+ boolean "dev"
depends on RTC_CLASS
default RTC_CLASS
help
@@ -88,48 +98,30 @@ config RTC_INTF_DEV_UIE_EMUL
bool "RTC UIE emulation on dev interface"
depends on RTC_INTF_DEV
help
- Provides an emulation for RTC_UIE if the underlaying rtc chip
+ Provides an emulation for RTC_UIE if the underlying rtc chip
driver does not expose RTC_UIE ioctls. Those requests generate
once-per-second update interrupts, used for synchronization.
-comment "RTC drivers"
+config RTC_DRV_TEST
+ tristate "Test driver/device"
depends on RTC_CLASS
-
-# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
-# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
-# global rtc_lock ... it's not yet just another platform_device.
-
-config RTC_DRV_CMOS
- tristate "PC-style 'CMOS' real time clock"
- depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
- || M32R || ATARI || POWERPC)
- help
- Say "yes" here to get direct support for the real time clock
- found in every PC or ACPI-based system, and some other boards.
- Specifically the original MC146818, compatibles like those in
- PC south bridges, the DS12887 or M48T86, some multifunction
- or LPC bus chips, and so on.
-
- Your system will need to define the platform device used by
- this driver, otherwise it won't be accessible. This means
- you can safely enable this driver if you don't know whether
- or not your board has this kind of hardware.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-cmos.
-
-config RTC_DRV_X1205
- tristate "Xicor/Intersil X1205"
- depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
- Xicor/Intersil X1205 RTC chip.
+ RTC test driver. It's a software RTC which can be
+ used to test the RTC subsystem APIs. It gets
+ the time from the system clock.
+ You want this driver only if you are doing development
+ on the RTC subsystem. Please read the source code
+ for further details.
This driver can also be built as a module. If so, the module
- will be called rtc-x1205.
+ will be called rtc-test.
+
+comment "I2C RTC drivers"
+ depends on RTC_CLASS
config RTC_DRV_DS1307
- tristate "Dallas/Maxim DS1307 and similar I2C RTC chips"
+ tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for various compatible RTC
@@ -146,53 +138,55 @@ config RTC_DRV_DS1307
This driver can also be built as a module. If so, the module
will be called rtc-ds1307.
-config RTC_DRV_DS1553
- tristate "Dallas DS1553"
- depends on RTC_CLASS
+config RTC_DRV_DS1672
+ tristate "Dallas/Maxim DS1672"
+ depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
- Dallas DS1553 timekeeping chip.
+ Dallas/Maxim DS1672 timekeeping chip.
This driver can also be built as a module. If so, the module
- will be called rtc-ds1553.
+ will be called rtc-ds1672.
-config RTC_DRV_ISL1208
- tristate "Intersil 1208"
+config RTC_DRV_MAX6900
+ tristate "Maxim 6900"
depends on RTC_CLASS && I2C
help
- If you say yes here you get support for the
- Intersil 1208 RTC chip.
+ If you say yes here you will get support for the
+ Maxim MAX6900 I2C RTC chip.
This driver can also be built as a module. If so, the module
- will be called rtc-isl1208.
+ will be called rtc-max6900.
-config RTC_DRV_DS1672
- tristate "Dallas/Maxim DS1672"
+config RTC_DRV_RS5C372
+ tristate "Ricoh RS5C372A/B"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
- Dallas/Maxim DS1672 timekeeping chip.
+ Ricoh RS5C372A and RS5C372B RTC chips.
This driver can also be built as a module. If so, the module
- will be called rtc-ds1672.
+ will be called rtc-rs5c372.
-config RTC_DRV_DS1742
- tristate "Dallas DS1742/1743"
- depends on RTC_CLASS
+config RTC_DRV_ISL1208
+ tristate "Intersil 1208"
+ depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
- Dallas DS1742/1743 timekeeping chip.
+ Intersil 1208 RTC chip.
This driver can also be built as a module. If so, the module
- will be called rtc-ds1742.
+ will be called rtc-isl1208.
-config RTC_DRV_OMAP
- tristate "TI OMAP1"
- depends on RTC_CLASS && ( \
- ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+config RTC_DRV_X1205
+ tristate "Xicor/Intersil X1205"
+ depends on RTC_CLASS && I2C
help
- Say "yes" here to support the real time clock on TI OMAP1 chips.
- This driver can also be built as a module called rtc-omap.
+ If you say yes here you get support for the
+ Xicor/Intersil X1205 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-x1205.
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
@@ -207,16 +201,20 @@ config RTC_DRV_PCF8563
config RTC_DRV_PCF8583
tristate "Philips PCF8583"
- depends on RTC_CLASS && I2C && ARCH_RPC
+ depends on RTC_CLASS && I2C
help
If you say yes here you get support for the Philips PCF8583
- RTC chip found on Acorn RiscPCs. This driver supports the
+ RTC chip found on Acorn RiscPCs. This driver supports the
platform specific method of retrieving the current year from
- the RTC's SRAM.
+ the RTC's SRAM. It will work on other platforms with the same
+ chip, but the year will probably have to be tweaked.
This driver can also be built as a module. If so, the module
will be called rtc-pcf8583.
+comment "SPI RTC drivers"
+ depends on RTC_CLASS
+
config RTC_DRV_RS5C348
tristate "Ricoh RS5C348A/B"
depends on RTC_CLASS && SPI
@@ -227,15 +225,92 @@ config RTC_DRV_RS5C348
This driver can also be built as a module. If so, the module
will be called rtc-rs5c348.
-config RTC_DRV_RS5C372
- tristate "Ricoh RS5C372A/B"
- depends on RTC_CLASS && I2C
+config RTC_DRV_MAX6902
+ tristate "Maxim 6902"
+ depends on RTC_CLASS && SPI
+ help
+ If you say yes here you will get support for the
+ Maxim MAX6902 SPI RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max6902.
+
+comment "Platform RTC drivers"
+ depends on RTC_CLASS
+
+# this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
+# requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
+# global rtc_lock ... it's not yet just another platform_device.
+
+config RTC_DRV_CMOS
+ tristate "PC-style 'CMOS'"
+ depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
+ || M32R || ATARI || POWERPC)
+ help
+ Say "yes" here to get direct support for the real time clock
+ found in every PC or ACPI-based system, and some other boards.
+ Specifically the original MC146818, compatibles like those in
+ PC south bridges, the DS12887 or M48T86, some multifunction
+ or LPC bus chips, and so on.
+
+ Your system will need to define the platform device used by
+ this driver, otherwise it won't be accessible. This means
+ you can safely enable this driver if you don't know whether
+ or not your board has this kind of hardware.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-cmos.
+
+config RTC_DRV_DS1553
+ tristate "Dallas DS1553"
+ depends on RTC_CLASS
help
If you say yes here you get support for the
- Ricoh RS5C372A and RS5C372B RTC chips.
+ Dallas DS1553 timekeeping chip.
This driver can also be built as a module. If so, the module
- will be called rtc-rs5c372.
+ will be called rtc-ds1553.
+
+config RTC_DRV_DS1742
+ tristate "Dallas DS1742/1743"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Dallas DS1742/1743 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1742.
+
+config RTC_DRV_M48T86
+ tristate "ST M48T86/Dallas DS12887"
+ depends on RTC_CLASS
+ help
+ If you say Y here you will get support for the
+ ST M48T86 and Dallas DS12887 RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-m48t86.
+
+config RTC_DRV_V3020
+ tristate "EM Microelectronic V3020"
+ depends on RTC_CLASS
+ help
+ If you say yes here you will get support for the
+ EM Microelectronic v3020 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-v3020.
+
+comment "on-CPU RTC drivers"
+ depends on RTC_CLASS
+
+config RTC_DRV_OMAP
+ tristate "TI OMAP1"
+ depends on RTC_CLASS && ( \
+ ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+ help
+ Say "yes" here to support the real time clock on TI OMAP1 chips.
+ This driver can also be built as a module called rtc-omap.
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
@@ -253,16 +328,6 @@ config RTC_DRV_S3C
This driver can also be build as a module. If so, the module
will be called rtc-s3c.
-config RTC_DRV_M48T86
- tristate "ST M48T86/Dallas DS12887"
- depends on RTC_CLASS
- help
- If you say Y here you will get support for the
- ST M48T86 and Dallas DS12887 RTC chips.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-m48t86.
-
config RTC_DRV_EP93XX
tristate "Cirrus Logic EP93XX"
depends on RTC_CLASS && ARCH_EP93XX
@@ -308,7 +373,7 @@ config RTC_DRV_PL031
depends on RTC_CLASS && ARM_AMBA
help
If you say Y here you will get access to ARM AMBA
- PrimeCell PL031 UART found on certain ARM SOCs.
+ PrimeCell PL031 RTC found on certain ARM SOCs.
To compile this driver as a module, choose M here: the
module will be called rtc-pl031.
@@ -319,39 +384,20 @@ config RTC_DRV_AT91RM9200
help
Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
-config RTC_DRV_TEST
- tristate "Test driver/device"
- depends on RTC_CLASS
- help
- If you say yes here you get support for the
- RTC test driver. It's a software RTC which can be
- used to test the RTC subsystem APIs. It gets
- the time from the system clock.
- You want this driver only if you are doing development
- on the RTC subsystem. Please read the source code
- for further details.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-test.
-
-config RTC_DRV_MAX6902
- tristate "Maxim 6902"
- depends on RTC_CLASS && SPI
+config RTC_DRV_BFIN
+ tristate "Blackfin On-Chip RTC"
+ depends on RTC_CLASS && BFIN
help
If you say yes here you will get support for the
- Maxim MAX6902 spi RTC chip.
+ Blackfin On-Chip Real Time Clock.
This driver can also be built as a module. If so, the module
- will be called rtc-max6902.
+ will be called rtc-bfin.
-config RTC_DRV_V3020
- tristate "EM Microelectronic V3020"
- depends on RTC_CLASS
+config RTC_DRV_RS5C313
+ tristate "Ricoh RS5C313"
+ depends on RTC_CLASS && BROKEN
help
- If you say yes here you will get support for the
- EM Microelectronic v3020 RTC chip.
-
- This driver can also be built as a module. If so, the module
- will be called rtc-v3020.
+ If you say yes here you get support for the Ricoh RS5C313 RTC chips.
endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 92bfe1b3a5f..a1afbc23607 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -11,9 +11,9 @@ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
-obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
-obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
-obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
+rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
+rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
+rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
@@ -30,11 +30,14 @@ obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
+obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
+obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 04aaa634723..8b3cd31d6a6 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -16,19 +16,94 @@
#include <linux/kdev_t.h>
#include <linux/idr.h>
+#include "rtc-core.h"
+
+
static DEFINE_IDR(rtc_idr);
static DEFINE_MUTEX(idr_lock);
struct class *rtc_class;
-static void rtc_device_release(struct class_device *class_dev)
+static void rtc_device_release(struct device *dev)
{
- struct rtc_device *rtc = to_rtc_device(class_dev);
+ struct rtc_device *rtc = to_rtc_device(dev);
mutex_lock(&idr_lock);
idr_remove(&rtc_idr, rtc->id);
mutex_unlock(&idr_lock);
kfree(rtc);
}
+#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
+
+/*
+ * On suspend(), measure the delta between one RTC and the
+ * system's wall clock; restore it on resume().
+ */
+
+static struct timespec delta;
+static time_t oldtime;
+
+static int rtc_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct rtc_device *rtc = to_rtc_device(dev);
+ struct rtc_time tm;
+
+ if (strncmp(rtc->dev.bus_id,
+ CONFIG_RTC_HCTOSYS_DEVICE,
+ BUS_ID_SIZE) != 0)
+ return 0;
+
+ rtc_read_time(rtc, &tm);
+ rtc_tm_to_time(&tm, &oldtime);
+
+ /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
+ set_normalized_timespec(&delta,
+ xtime.tv_sec - oldtime,
+ xtime.tv_nsec - (NSEC_PER_SEC >> 1));
+
+ return 0;
+}
+
+static int rtc_resume(struct device *dev)
+{
+ struct rtc_device *rtc = to_rtc_device(dev);
+ struct rtc_time tm;
+ time_t newtime;
+ struct timespec time;
+
+ if (strncmp(rtc->dev.bus_id,
+ CONFIG_RTC_HCTOSYS_DEVICE,
+ BUS_ID_SIZE) != 0)
+ return 0;
+
+ rtc_read_time(rtc, &tm);
+ if (rtc_valid_tm(&tm) != 0) {
+ pr_debug("%s: bogus resume time\n", rtc->dev.bus_id);
+ return 0;
+ }
+ rtc_tm_to_time(&tm, &newtime);
+ if (newtime <= oldtime) {
+ if (newtime < oldtime)
+ pr_debug("%s: time travel!\n", rtc->dev.bus_id);
+ return 0;
+ }
+
+ /* restore wall clock using delta against this RTC;
+ * adjust again for avg 1/2 second RTC sampling error
+ */
+ set_normalized_timespec(&time,
+ newtime + delta.tv_sec,
+ (NSEC_PER_SEC >> 1) + delta.tv_nsec);
+ do_settimeofday(&time);
+
+ return 0;
+}
+
+#else
+#define rtc_suspend NULL
+#define rtc_resume NULL
+#endif
+
+
/**
* rtc_device_register - register w/ RTC class
* @dev: the device to register
@@ -70,23 +145,29 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
rtc->ops = ops;
rtc->owner = owner;
rtc->max_user_freq = 64;
- rtc->class_dev.dev = dev;
- rtc->class_dev.class = rtc_class;
- rtc->class_dev.release = rtc_device_release;
+ rtc->dev.parent = dev;
+ rtc->dev.class = rtc_class;
+ rtc->dev.release = rtc_device_release;
mutex_init(&rtc->ops_lock);
spin_lock_init(&rtc->irq_lock);
spin_lock_init(&rtc->irq_task_lock);
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
- snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
+ snprintf(rtc->dev.bus_id, BUS_ID_SIZE, "rtc%d", id);
- err = class_device_register(&rtc->class_dev);
+ rtc_dev_prepare(rtc);
+
+ err = device_register(&rtc->dev);
if (err)
goto exit_kfree;
+ rtc_dev_add_device(rtc);
+ rtc_sysfs_add_device(rtc);
+ rtc_proc_add_device(rtc);
+
dev_info(dev, "rtc core: registered %s as %s\n",
- rtc->name, rtc->class_dev.class_id);
+ rtc->name, rtc->dev.bus_id);
return rtc;
@@ -113,26 +194,22 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
*/
void rtc_device_unregister(struct rtc_device *rtc)
{
- if (class_device_get(&rtc->class_dev) != NULL) {
+ if (get_device(&rtc->dev) != NULL) {
mutex_lock(&rtc->ops_lock);
/* remove innards of this RTC, then disable it, before
* letting any rtc_class_open() users access it again
*/
- class_device_unregister(&rtc->class_dev);
+ rtc_sysfs_del_device(rtc);
+ rtc_dev_del_device(rtc);
+ rtc_proc_del_device(rtc);
+ device_unregister(&rtc->dev);
rtc->ops = NULL;
mutex_unlock(&rtc->ops_lock);
- class_device_put(&rtc->class_dev);
+ put_device(&rtc->dev);
}
}
EXPORT_SYMBOL_GPL(rtc_device_unregister);
-int rtc_interface_register(struct class_interface *intf)
-{
- intf->class = rtc_class;
- return class_interface_register(intf);
-}
-EXPORT_SYMBOL_GPL(rtc_interface_register);
-
static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
@@ -140,11 +217,16 @@ static int __init rtc_init(void)
printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
return PTR_ERR(rtc_class);
}
+ rtc_class->suspend = rtc_suspend;
+ rtc_class->resume = rtc_resume;
+ rtc_dev_init();
+ rtc_sysfs_init(rtc_class);
return 0;
}
static void __exit rtc_exit(void)
{
+ rtc_dev_exit();
class_destroy(rtc_class);
}
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index d02fe9a0001..178527252c6 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -26,15 +26,15 @@ static int __init rtc_hctosys(void)
{
int err;
struct rtc_time tm;
- struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+ struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
- if (class_dev == NULL) {
+ if (rtc == NULL) {
printk("%s: unable to open rtc device (%s)\n",
__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
return -ENODEV;
}
- err = rtc_read_time(class_dev, &tm);
+ err = rtc_read_time(rtc, &tm);
if (err == 0) {
err = rtc_valid_tm(&tm);
if (err == 0) {
@@ -46,7 +46,7 @@ static int __init rtc_hctosys(void)
do_settimeofday(&tv);
- dev_info(class_dev->dev,
+ dev_info(rtc->dev.parent,
"setting the system clock to "
"%d-%02d-%02d %02d:%02d:%02d (%u)\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
@@ -54,14 +54,14 @@ static int __init rtc_hctosys(void)
(unsigned int) tv.tv_sec);
}
else
- dev_err(class_dev->dev,
+ dev_err(rtc->dev.parent,
"hctosys: invalid date/time\n");
}
else
- dev_err(class_dev->dev,
+ dev_err(rtc->dev.parent,
"hctosys: unable to read the hardware clock\n");
- rtc_class_close(class_dev);
+ rtc_class_close(rtc);
return 0;
}
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index ef40df0f169..ad66c6ecf36 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -13,10 +13,9 @@
#include <linux/rtc.h>
-int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
+int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
- struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
@@ -28,7 +27,7 @@ int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
err = -EINVAL;
else {
memset(tm, 0, sizeof(struct rtc_time));
- err = rtc->ops->read_time(class_dev->dev, tm);
+ err = rtc->ops->read_time(rtc->dev.parent, tm);
}
mutex_unlock(&rtc->ops_lock);
@@ -36,10 +35,9 @@ int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
}
EXPORT_SYMBOL_GPL(rtc_read_time);
-int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
+int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
- struct rtc_device *rtc = to_rtc_device(class_dev);
err = rtc_valid_tm(tm);
if (err != 0)
@@ -54,17 +52,16 @@ int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
else if (!rtc->ops->set_time)
err = -EINVAL;
else
- err = rtc->ops->set_time(class_dev->dev, tm);
+ err = rtc->ops->set_time(rtc->dev.parent, tm);
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);
-int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
+int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
{
int err;
- struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
@@ -73,11 +70,11 @@ int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
if (!rtc->ops)
err = -ENODEV;
else if (rtc->ops->set_mmss)
- err = rtc->ops->set_mmss(class_dev->dev, secs);
+ err = rtc->ops->set_mmss(rtc->dev.parent, secs);
else if (rtc->ops->read_time && rtc->ops->set_time) {
struct rtc_time new, old;
- err = rtc->ops->read_time(class_dev->dev, &old);
+ err = rtc->ops->read_time(rtc->dev.parent, &old);
if (err == 0) {
rtc_time_to_tm(secs, &new);
@@ -89,7 +86,8 @@ int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
*/
if (!((old.tm_hour == 23 && old.tm_min == 59) ||
(new.tm_hour == 23 && new.tm_min == 59)))
- err = rtc->ops->set_time(class_dev->dev, &new);
+ err = rtc->ops->set_time(rtc->dev.parent,
+ &new);
}
}
else
@@ -101,10 +99,9 @@ int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);
-int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
- struct rtc_device *rtc = to_rtc_device(class_dev);
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
@@ -116,7 +113,7 @@ int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
err = -EINVAL;
else {
memset(alarm, 0, sizeof(struct rtc_wkalrm));
- err = rtc->ops->read_alarm(class_dev->dev, alarm);
+ err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
}
mutex_unlock(&rtc->ops_lock);
@@ -124,10 +121,13 @@ int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
}
EXPORT_SYMBOL_GPL(rtc_read_alarm);
-int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
- struct rtc_device *rtc = to_rtc_device(class_dev);
+
+ err = rtc_valid_tm(&alarm->time);
+ if (err != 0)
+ return err;
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
@@ -138,7 +138,7 @@ int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
else if (!rtc->ops->set_alarm)
err = -EINVAL;
else
- err = rtc->ops->set_alarm(class_dev->dev, alarm);
+ err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
mutex_unlock(&rtc->ops_lock);
return err;
@@ -147,16 +147,14 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm);
/**
* rtc_update_irq - report RTC periodic, alarm, and/or update irqs
- * @class_dev: the rtc's class device
+ * @rtc: the rtc device
* @num: how many irqs are being reported (usually one)
* @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
* Context: in_interrupt(), irqs blocked
*/
-void rtc_update_irq(struct class_device *class_dev,
+void rtc_update_irq(struct rtc_device *rtc,
unsigned long num, unsigned long events)
{
- struct rtc_device *rtc = to_rtc_device(class_dev);
-
spin_lock(&rtc->irq_lock);
rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
spin_unlock(&rtc->irq_lock);
@@ -171,40 +169,43 @@ void rtc_update_irq(struct class_device *class_dev,
}
EXPORT_SYMBOL_GPL(rtc_update_irq);
-struct class_device *rtc_class_open(char *name)
+struct rtc_device *rtc_class_open(char *name)
{
- struct class_device *class_dev = NULL,
- *class_dev_tmp;
+ struct device *dev;
+ struct rtc_device *rtc = NULL;
down(&rtc_class->sem);
- list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
- if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
- class_dev = class_device_get(class_dev_tmp);
+ list_for_each_entry(dev, &rtc_class->devices, node) {
+ if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
+ dev = get_device(dev);
+ if (dev)
+ rtc = to_rtc_device(dev);
break;
}
}
- if (class_dev) {
- if (!try_module_get(to_rtc_device(class_dev)->owner))
- class_dev = NULL;
+ if (rtc) {
+ if (!try_module_get(rtc->owner)) {
+ put_device(dev);
+ rtc = NULL;
+ }
}
up(&rtc_class->sem);
- return class_dev;
+ return rtc;
}
EXPORT_SYMBOL_GPL(rtc_class_open);
-void rtc_class_close(struct class_device *class_dev)
+void rtc_class_close(struct rtc_device *rtc)
{
- module_put(to_rtc_device(class_dev)->owner);
- class_device_put(class_dev);
+ module_put(rtc->owner);
+ put_device(&rtc->dev);
}
EXPORT_SYMBOL_GPL(rtc_class_close);
-int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
+int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
{
int retval = -EBUSY;
- struct rtc_device *rtc = to_rtc_device(class_dev);
if (task == NULL || task->func == NULL)
return -EINVAL;
@@ -220,9 +221,8 @@ int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
}
EXPORT_SYMBOL_GPL(rtc_irq_register);
-void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
+void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
{
- struct rtc_device *rtc = to_rtc_device(class_dev);
spin_lock_irq(&rtc->irq_task_lock);
if (rtc->irq_task == task)
@@ -231,11 +231,10 @@ void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
-int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
+int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
{
int err = 0;
unsigned long flags;
- struct rtc_device *rtc = to_rtc_device(class_dev);
if (rtc->ops->irq_set_state == NULL)
return -ENXIO;
@@ -246,17 +245,16 @@ int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0)
- err = rtc->ops->irq_set_state(class_dev->dev, enabled);
+ err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
-int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
+int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
{
int err = 0;
unsigned long flags;
- struct rtc_device *rtc = to_rtc_device(class_dev);
if (rtc->ops->irq_set_freq == NULL)
return -ENXIO;
@@ -267,7 +265,7 @@ int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0) {
- err = rtc->ops->irq_set_freq(class_dev->dev, freq);
+ err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
if (err == 0)
rtc->irq_freq = freq;
}
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index ac0e68e2f02..33795e5a559 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -263,7 +263,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
at91_sys_write(AT91_RTC_SCCR, rtsr); /* clear status reg */
- rtc_update_irq(&rtc->class_dev, 1, events);
+ rtc_update_irq(rtc, 1, events);
pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
events >> 8, events & 0x000000FF);
@@ -348,21 +348,10 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
/* AT91RM9200 RTC Power management control */
-static struct timespec at91_rtc_delta;
static u32 at91_rtc_imr;
static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
- /* calculate time delta for suspend */
- at91_rtc_readtime(&pdev->dev, &tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- save_time_delta(&at91_rtc_delta, &time);
-
/* this IRQ is shared with DBGU and other hardware which isn't
* necessarily doing PM like we are...
*/
@@ -374,36 +363,17 @@ static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
else
at91_sys_write(AT91_RTC_IDR, at91_rtc_imr);
}
-
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
- 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
-
return 0;
}
static int at91_rtc_resume(struct platform_device *pdev)
{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
- at91_rtc_readtime(&pdev->dev, &tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- restore_time_delta(&at91_rtc_delta, &time);
-
if (at91_rtc_imr) {
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(AT91_ID_SYS);
else
at91_sys_write(AT91_RTC_IER, at91_rtc_imr);
}
-
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
- 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec);
-
return 0;
}
#else
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
new file mode 100644
index 00000000000..260ead95991
--- /dev/null
+++ b/drivers/rtc/rtc-bfin.c
@@ -0,0 +1,445 @@
+/*
+ * Blackfin On-Chip Real Time Clock Driver
+ * Supports BF531/BF532/BF533/BF534/BF536/BF537
+ *
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* The biggest issue we deal with in this driver is that register writes are
+ * synced to the RTC frequency of 1Hz. So if you write to a register and
+ * attempt to write again before the first write has completed, the new write
+ * is simply discarded. This can easily be troublesome if userspace disables
+ * one event (say periodic) and then right after enables an event (say alarm).
+ * Since all events are maintained in the same interrupt mask register, if
+ * we wrote to it to disable the first event and then wrote to it again to
+ * enable the second event, that second event would not be enabled as the
+ * write would be discarded and things quickly fall apart.
+ *
+ * To keep this delay from significantly degrading performance (we, in theory,
+ * would have to sleep for up to 1 second everytime we wanted to write a
+ * register), we only check the write pending status before we start to issue
+ * a new write. We bank on the idea that it doesnt matter when the sync
+ * happens so long as we don't attempt another write before it does. The only
+ * time userspace would take this penalty is when they try and do multiple
+ * operations right after another ... but in this case, they need to take the
+ * sync penalty, so we should be OK.
+ *
+ * Also note that the RTC_ISTAT register does not suffer this penalty; its
+ * writes to clear status registers complete immediately.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+
+#include <asm/blackfin.h>
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
+#define stampit() stamp("here i am")
+
+struct bfin_rtc {
+ struct rtc_device *rtc_dev;
+ struct rtc_time rtc_alarm;
+ spinlock_t lock;
+};
+
+/* Bit values for the ISTAT / ICTL registers */
+#define RTC_ISTAT_WRITE_COMPLETE 0x8000
+#define RTC_ISTAT_WRITE_PENDING 0x4000
+#define RTC_ISTAT_ALARM_DAY 0x0040
+#define RTC_ISTAT_24HR 0x0020
+#define RTC_ISTAT_HOUR 0x0010
+#define RTC_ISTAT_MIN 0x0008
+#define RTC_ISTAT_SEC 0x0004
+#define RTC_ISTAT_ALARM 0x0002
+#define RTC_ISTAT_STOPWATCH 0x0001
+
+/* Shift values for RTC_STAT register */
+#define DAY_BITS_OFF 17
+#define HOUR_BITS_OFF 12
+#define MIN_BITS_OFF 6
+#define SEC_BITS_OFF 0
+
+/* Some helper functions to convert between the common RTC notion of time
+ * and the internal Blackfin notion that is stored in 32bits.
+ */
+static inline u32 rtc_time_to_bfin(unsigned long now)
+{
+ u32 sec = (now % 60);
+ u32 min = (now % (60 * 60)) / 60;
+ u32 hour = (now % (60 * 60 * 24)) / (60 * 60);
+ u32 days = (now / (60 * 60 * 24));
+ return (sec << SEC_BITS_OFF) +
+ (min << MIN_BITS_OFF) +
+ (hour << HOUR_BITS_OFF) +
+ (days << DAY_BITS_OFF);
+}
+static inline unsigned long rtc_bfin_to_time(u32 rtc_bfin)
+{
+ return (((rtc_bfin >> SEC_BITS_OFF) & 0x003F)) +
+ (((rtc_bfin >> MIN_BITS_OFF) & 0x003F) * 60) +
+ (((rtc_bfin >> HOUR_BITS_OFF) & 0x001F) * 60 * 60) +
+ (((rtc_bfin >> DAY_BITS_OFF) & 0x7FFF) * 60 * 60 * 24);
+}
+static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
+{
+ rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
+}
+
+/* Wait for the previous write to a RTC register to complete.
+ * Unfortunately, we can't sleep here as that introduces a race condition when
+ * turning on interrupt events. Consider this:
+ * - process sets alarm
+ * - process enables alarm
+ * - process sleeps while waiting for rtc write to sync
+ * - interrupt fires while process is sleeping
+ * - interrupt acks the event by writing to ISTAT
+ * - interrupt sets the WRITE PENDING bit
+ * - interrupt handler finishes
+ * - process wakes up, sees WRITE PENDING bit set, goes to sleep
+ * - interrupt fires while process is sleeping
+ * If anyone can point out the obvious solution here, i'm listening :). This
+ * shouldn't be an issue on an SMP or preempt system as this function should
+ * only be called with the rtc lock held.
+ */
+static void rtc_bfin_sync_pending(void)
+{
+ stampit();
+ while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
+ if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
+ break;
+ }
+ bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
+}
+
+static void rtc_bfin_reset(struct bfin_rtc *rtc)
+{
+ /* Initialize the RTC. Enable pre-scaler to scale RTC clock
+ * to 1Hz and clear interrupt/status registers. */
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_PREN(0x1);
+ bfin_write_RTC_ICTL(0);
+ bfin_write_RTC_SWCNT(0);
+ bfin_write_RTC_ALARM(0);
+ bfin_write_RTC_ISTAT(0xFFFF);
+ spin_unlock_irq(&rtc->lock);
+}
+
+static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = to_platform_device(dev_id);
+ struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned long events = 0;
+ u16 rtc_istat;
+
+ stampit();
+
+ spin_lock_irq(&rtc->lock);
+
+ rtc_istat = bfin_read_RTC_ISTAT();
+
+ if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
+ events |= RTC_AF | RTC_IRQF;
+ }
+
+ if (rtc_istat & RTC_ISTAT_STOPWATCH) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+ events |= RTC_PF | RTC_IRQF;
+ bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+ }
+
+ if (rtc_istat & RTC_ISTAT_SEC) {
+ bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+ events |= RTC_UF | RTC_IRQF;
+ }
+
+ rtc_update_irq(rtc->rtc_dev, 1, events);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int bfin_rtc_open(struct device *dev)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+
+ stampit();
+
+ ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request RTC IRQ failed with %d\n", ret);
+ return ret;
+ }
+
+ rtc_bfin_reset(rtc);
+
+ return ret;
+}
+
+static void bfin_rtc_release(struct device *dev)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ stampit();
+ rtc_bfin_reset(rtc);
+ free_irq(IRQ_RTC, dev);
+}
+
+static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+
+ stampit();
+
+ switch (cmd) {
+ case RTC_PIE_ON:
+ stampit();
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
+ bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+ case RTC_PIE_OFF:
+ stampit();
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_SWCNT(0);
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+
+ case RTC_UIE_ON:
+ stampit();
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+ case RTC_UIE_OFF:
+ stampit();
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+
+ case RTC_AIE_ON: {
+ unsigned long rtc_alarm;
+ u16 which_alarm;
+ int ret = 0;
+
+ stampit();
+
+ spin_lock_irq(&rtc->lock);
+
+ rtc_bfin_sync_pending();
+ if (rtc->rtc_alarm.tm_yday == -1) {
+ struct rtc_time now;
+ rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
+ now.tm_sec = rtc->rtc_alarm.tm_sec;
+ now.tm_min = rtc->rtc_alarm.tm_min;
+ now.tm_hour = rtc->rtc_alarm.tm_hour;
+ ret = rtc_tm_to_time(&now, &rtc_alarm);
+ which_alarm = RTC_ISTAT_ALARM;
+ } else {
+ ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
+ which_alarm = RTC_ISTAT_ALARM_DAY;
+ }
+ if (ret == 0) {
+ bfin_write_RTC_ISTAT(which_alarm);
+ bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
+ }
+
+ spin_unlock_irq(&rtc->lock);
+
+ return ret;
+ }
+ case RTC_AIE_OFF:
+ stampit();
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+ spin_unlock_irq(&rtc->lock);
+ return 0;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+
+ stampit();
+
+ spin_lock_irq(&rtc->lock);
+ rtc_bfin_sync_pending();
+ rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+ unsigned long now;
+
+ stampit();
+
+ spin_lock_irq(&rtc->lock);
+
+ ret = rtc_tm_to_time(tm, &now);
+ if (ret == 0) {
+ rtc_bfin_sync_pending();
+ bfin_write_RTC_STAT(rtc_time_to_bfin(now));
+ }
+
+ spin_unlock_irq(&rtc->lock);
+
+ return ret;
+}
+
+static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ stampit();
+ memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
+ alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
+ return 0;
+}
+
+static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ stampit();
+ memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+ return 0;
+}
+
+static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+#define yesno(x) (x ? "yes" : "no")
+ u16 ictl = bfin_read_RTC_ICTL();
+ stampit();
+ seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
+ seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
+ seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
+ seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
+#ifdef DEBUG
+ seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
+ seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
+ seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
+ seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
+ seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
+ seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
+#endif
+ return 0;
+}
+
+static int bfin_irq_set_freq(struct device *dev, int freq)
+{
+ struct bfin_rtc *rtc = dev_get_drvdata(dev);
+ stampit();
+ rtc->rtc_dev->irq_freq = freq;
+ return 0;
+}
+
+static struct rtc_class_ops bfin_rtc_ops = {
+ .open = bfin_rtc_open,
+ .release = bfin_rtc_release,
+ .ioctl = bfin_rtc_ioctl,
+ .read_time = bfin_rtc_read_time,
+ .set_time = bfin_rtc_set_time,
+ .read_alarm = bfin_rtc_read_alarm,
+ .set_alarm = bfin_rtc_set_alarm,
+ .proc = bfin_rtc_proc,
+ .irq_set_freq = bfin_irq_set_freq,
+};
+
+static int __devinit bfin_rtc_probe(struct platform_device *pdev)
+{
+ struct bfin_rtc *rtc;
+ int ret = 0;
+
+ stampit();
+
+ rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ if (unlikely(!rtc))
+ return -ENOMEM;
+
+ spin_lock_init(&rtc->lock);
+
+ rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
+ if (unlikely(IS_ERR(rtc))) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err;
+ }
+ rtc->rtc_dev->irq_freq = 0;
+ rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
+
+ platform_set_drvdata(pdev, rtc);
+
+ return 0;
+
+err:
+ kfree(rtc);
+ return ret;
+}
+
+static int __devexit bfin_rtc_remove(struct platform_device *pdev)
+{
+ struct bfin_rtc *rtc = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(rtc->rtc_dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(rtc);
+
+ return 0;
+}
+
+static struct platform_driver bfin_rtc_driver = {
+ .driver = {
+ .name = "rtc-bfin",
+ .owner = THIS_MODULE,
+ },
+ .probe = bfin_rtc_probe,
+ .remove = __devexit_p(bfin_rtc_remove),
+};
+
+static int __init bfin_rtc_init(void)
+{
+ stampit();
+ return platform_driver_register(&bfin_rtc_driver);
+}
+
+static void __exit bfin_rtc_exit(void)
+{
+ platform_driver_unregister(&bfin_rtc_driver);
+}
+
+module_init(bfin_rtc_init);
+module_exit(bfin_rtc_exit);
+
+MODULE_DESCRIPTION("Blackfin On-Chip Real Time Clock Driver");
+MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 7c0d6091007..6085261aa2c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -46,6 +46,10 @@ struct cmos_rtc {
int irq;
struct resource *iomem;
+ void (*wake_on)(struct device *);
+ void (*wake_off)(struct device *);
+
+ u8 enabled_wake;
u8 suspend_ctrl;
/* newer hardware extends the original register set */
@@ -203,7 +207,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
- rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+ rtc_update_irq(cmos->rtc, 1, rtc_intr);
/* update alarm */
CMOS_WRITE(hrs, RTC_HOURS_ALARM);
@@ -223,7 +227,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
- rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+ rtc_update_irq(cmos->rtc, 1, rtc_intr);
}
spin_unlock_irq(&rtc_lock);
@@ -304,7 +308,7 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(rtc_intr))
- rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+ rtc_update_irq(cmos->rtc, 1, rtc_intr);
spin_unlock_irqrestore(&rtc_lock, flags);
return 0;
}
@@ -379,12 +383,12 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
return IRQ_NONE;
}
-#ifdef CONFIG_PNPACPI
-#define is_pnpacpi() 1
+#ifdef CONFIG_PNP
+#define is_pnp() 1
#define INITSECTION
#else
-#define is_pnpacpi() 0
+#define is_pnp() 0
#define INITSECTION __init
#endif
@@ -405,13 +409,20 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
cmos_rtc.irq = rtc_irq;
cmos_rtc.iomem = ports;
- /* For ACPI systems the info comes from the FADT. On others,
- * board specific setup provides it as appropriate.
+ /* For ACPI systems extension info comes from the FADT. On others,
+ * board specific setup provides it as appropriate. Systems where
+ * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
+ * some almost-clones) can provide hooks to make that behave.
*/
if (info) {
cmos_rtc.day_alrm = info->rtc_day_alarm;
cmos_rtc.mon_alrm = info->rtc_mon_alarm;
cmos_rtc.century = info->rtc_century;
+
+ if (info->wake_on && info->wake_off) {
+ cmos_rtc.wake_on = info->wake_on;
+ cmos_rtc.wake_off = info->wake_off;
+ }
}
cmos_rtc.rtc = rtc_device_register(driver_name, dev,
@@ -427,14 +438,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* REVISIT for non-x86 systems we may need to handle io memory
* resources: ioremap them, and request_mem_region().
*/
- if (is_pnpacpi()) {
+ if (is_pnp()) {
retval = request_resource(&ioport_resource, ports);
if (retval < 0) {
dev_dbg(dev, "i/o registers already in use\n");
goto cleanup0;
}
}
- rename_region(ports, cmos_rtc.rtc->class_dev.class_id);
+ rename_region(ports, cmos_rtc.rtc->dev.bus_id);
spin_lock_irq(&rtc_lock);
@@ -470,8 +481,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
if (is_valid_irq(rtc_irq))
retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
- cmos_rtc.rtc->class_dev.class_id,
- &cmos_rtc.rtc->class_dev);
+ cmos_rtc.rtc->dev.bus_id,
+ cmos_rtc.rtc);
if (retval < 0) {
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
goto cleanup1;
@@ -483,7 +494,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
*/
pr_info("%s: alarms up to one %s%s\n",
- cmos_rtc.rtc->class_dev.class_id,
+ cmos_rtc.rtc->dev.bus_id,
is_valid_irq(rtc_irq)
? (cmos_rtc.mon_alrm
? "year"
@@ -520,12 +531,12 @@ static void __exit cmos_do_remove(struct device *dev)
cmos_do_shutdown();
- if (is_pnpacpi())
+ if (is_pnp())
release_resource(cmos->iomem);
rename_region(cmos->iomem, NULL);
if (is_valid_irq(cmos->irq))
- free_irq(cmos->irq, &cmos_rtc.rtc->class_dev);
+ free_irq(cmos->irq, cmos_rtc.rtc);
rtc_device_unregister(cmos_rtc.rtc);
@@ -555,16 +566,20 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)
irqstat = CMOS_READ(RTC_INTR_FLAGS);
irqstat &= (tmp & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(irqstat))
- rtc_update_irq(&cmos->rtc->class_dev, 1, irqstat);
+ rtc_update_irq(cmos->rtc, 1, irqstat);
}
spin_unlock_irq(&rtc_lock);
- /* ACPI HOOK: enable ACPI_EVENT_RTC when (tmp & RTC_AIE)
- * ... it'd be best if we could do that under rtc_lock.
- */
+ if (tmp & RTC_AIE) {
+ cmos->enabled_wake = 1;
+ if (cmos->wake_on)
+ cmos->wake_on(dev);
+ else
+ enable_irq_wake(cmos->irq);
+ }
pr_debug("%s: suspend%s, ctrl %02x\n",
- cmos_rtc.rtc->class_dev.class_id,
+ cmos_rtc.rtc->dev.bus_id,
(tmp & RTC_AIE) ? ", alarm may wake" : "",
tmp);
@@ -576,26 +591,28 @@ static int cmos_resume(struct device *dev)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char tmp = cmos->suspend_ctrl;
- /* REVISIT: a mechanism to resync the system clock (jiffies)
- * on resume should be portable between platforms ...
- */
-
/* re-enable any irqs previously active */
if (tmp & (RTC_PIE|RTC_AIE|RTC_UIE)) {
- /* ACPI HOOK: disable ACPI_EVENT_RTC when (tmp & RTC_AIE) */
+ if (cmos->enabled_wake) {
+ if (cmos->wake_off)
+ cmos->wake_off(dev);
+ else
+ disable_irq_wake(cmos->irq);
+ cmos->enabled_wake = 0;
+ }
spin_lock_irq(&rtc_lock);
CMOS_WRITE(tmp, RTC_CONTROL);
tmp = CMOS_READ(RTC_INTR_FLAGS);
tmp &= (cmos->suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
if (is_intr(tmp))
- rtc_update_irq(&cmos->rtc->class_dev, 1, tmp);
+ rtc_update_irq(cmos->rtc, 1, tmp);
spin_unlock_irq(&rtc_lock);
}
pr_debug("%s: resume, ctrl %02x\n",
- cmos_rtc.rtc->class_dev.class_id,
+ cmos_rtc.rtc->dev.bus_id,
cmos->suspend_ctrl);
@@ -613,7 +630,7 @@ static int cmos_resume(struct device *dev)
* the device node will always be created as a PNPACPI device.
*/
-#ifdef CONFIG_PNPACPI
+#ifdef CONFIG_PNP
#include <linux/pnp.h>
@@ -684,11 +701,11 @@ static void __exit cmos_exit(void)
}
module_exit(cmos_exit);
-#else /* no PNPACPI */
+#else /* no PNP */
/*----------------------------------------------------------------*/
-/* Platform setup should have set up an RTC device, when PNPACPI is
+/* Platform setup should have set up an RTC device, when PNP is
* unavailable ... this could happen even on (older) PCs.
*/
@@ -734,7 +751,7 @@ static void __exit cmos_exit(void)
module_exit(cmos_exit);
-#endif /* !PNPACPI */
+#endif /* !PNP */
MODULE_AUTHOR("David Brownell");
MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");
diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h
new file mode 100644
index 00000000000..5f9df7430a2
--- /dev/null
+++ b/drivers/rtc/rtc-core.h
@@ -0,0 +1,70 @@
+#ifdef CONFIG_RTC_INTF_DEV
+
+extern void __init rtc_dev_init(void);
+extern void __exit rtc_dev_exit(void);
+extern void rtc_dev_prepare(struct rtc_device *rtc);
+extern void rtc_dev_add_device(struct rtc_device *rtc);
+extern void rtc_dev_del_device(struct rtc_device *rtc);
+
+#else
+
+static inline void rtc_dev_init(void)
+{
+}
+
+static inline void rtc_dev_exit(void)
+{
+}
+
+static inline void rtc_dev_prepare(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_dev_add_device(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_dev_del_device(struct rtc_device *rtc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_RTC_INTF_PROC
+
+extern void rtc_proc_add_device(struct rtc_device *rtc);
+extern void rtc_proc_del_device(struct rtc_device *rtc);
+
+#else
+
+static inline void rtc_proc_add_device(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_proc_del_device(struct rtc_device *rtc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_RTC_INTF_SYSFS
+
+extern void __init rtc_sysfs_init(struct class *);
+extern void rtc_sysfs_add_device(struct rtc_device *rtc);
+extern void rtc_sysfs_del_device(struct rtc_device *rtc);
+
+#else
+
+static inline void rtc_sysfs_init(struct class *rtc)
+{
+}
+
+static inline void rtc_sysfs_add_device(struct rtc_device *rtc)
+{
+}
+
+static inline void rtc_sysfs_del_device(struct rtc_device *rtc)
+{
+}
+
+#endif
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 137330b8636..f4e5f0040ff 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -13,8 +13,8 @@
#include <linux/module.h>
#include <linux/rtc.h>
+#include "rtc-core.h"
-static struct class *rtc_dev_class;
static dev_t rtc_devt;
#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
@@ -32,9 +32,9 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
if (!(mutex_trylock(&rtc->char_lock)))
return -EBUSY;
- file->private_data = &rtc->class_dev;
+ file->private_data = rtc;
- err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
+ err = ops->open ? ops->open(rtc->dev.parent) : 0;
if (err == 0) {
spin_lock_irq(&rtc->irq_lock);
rtc->irq_data = 0;
@@ -61,7 +61,7 @@ static void rtc_uie_task(struct work_struct *work)
int num = 0;
int err;
- err = rtc_read_time(&rtc->class_dev, &tm);
+ err = rtc_read_time(rtc, &tm);
local_irq_disable();
spin_lock(&rtc->irq_lock);
@@ -79,7 +79,7 @@ static void rtc_uie_task(struct work_struct *work)
}
spin_unlock(&rtc->irq_lock);
if (num)
- rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF);
+ rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
local_irq_enable();
}
static void rtc_uie_timer(unsigned long data)
@@ -121,7 +121,7 @@ static int set_uie(struct rtc_device *rtc)
struct rtc_time tm;
int err;
- err = rtc_read_time(&rtc->class_dev, &tm);
+ err = rtc_read_time(rtc, &tm);
if (err)
return err;
spin_lock_irq(&rtc->irq_lock);
@@ -180,7 +180,7 @@ rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if (ret == 0) {
/* Check for any data updates */
if (rtc->ops->read_callback)
- data = rtc->ops->read_callback(rtc->class_dev.dev,
+ data = rtc->ops->read_callback(rtc->dev.parent,
data);
if (sizeof(int) != sizeof(long) &&
@@ -210,8 +210,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int err = 0;
- struct class_device *class_dev = file->private_data;
- struct rtc_device *rtc = to_rtc_device(class_dev);
+ struct rtc_device *rtc = file->private_data;
const struct rtc_class_ops *ops = rtc->ops;
struct rtc_time tm;
struct rtc_wkalrm alarm;
@@ -252,7 +251,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
/* try the driver's ioctl interface */
if (ops->ioctl) {
- err = ops->ioctl(class_dev->dev, cmd, arg);
+ err = ops->ioctl(rtc->dev.parent, cmd, arg);
if (err != -ENOIOCTLCMD)
return err;
}
@@ -264,7 +263,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case RTC_ALM_READ:
- err = rtc_read_alarm(class_dev, &alarm);
+ err = rtc_read_alarm(rtc, &alarm);
if (err < 0)
return err;
@@ -278,17 +277,53 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
alarm.enabled = 0;
alarm.pending = 0;
- alarm.time.tm_mday = -1;
- alarm.time.tm_mon = -1;
- alarm.time.tm_year = -1;
alarm.time.tm_wday = -1;
alarm.time.tm_yday = -1;
alarm.time.tm_isdst = -1;
- err = rtc_set_alarm(class_dev, &alarm);
+
+ /* RTC_ALM_SET alarms may be up to 24 hours in the future.
+ * Rather than expecting every RTC to implement "don't care"
+ * for day/month/year fields, just force the alarm to have
+ * the right values for those fields.
+ *
+ * RTC_WKALM_SET should be used instead. Not only does it
+ * eliminate the need for a separate RTC_AIE_ON call, it
+ * doesn't have the "alarm 23:59:59 in the future" race.
+ *
+ * NOTE: some legacy code may have used invalid fields as
+ * wildcards, exposing hardware "periodic alarm" capabilities.
+ * Not supported here.
+ */
+ {
+ unsigned long now, then;
+
+ err = rtc_read_time(rtc, &tm);
+ if (err < 0)
+ return err;
+ rtc_tm_to_time(&tm, &now);
+
+ alarm.time.tm_mday = tm.tm_mday;
+ alarm.time.tm_mon = tm.tm_mon;
+ alarm.time.tm_year = tm.tm_year;
+ err = rtc_valid_tm(&alarm.time);
+ if (err < 0)
+ return err;
+ rtc_tm_to_time(&alarm.time, &then);
+
+ /* alarm may need to wrap into tomorrow */
+ if (then < now) {
+ rtc_time_to_tm(now + 24 * 60 * 60, &tm);
+ alarm.time.tm_mday = tm.tm_mday;
+ alarm.time.tm_mon = tm.tm_mon;
+ alarm.time.tm_year = tm.tm_year;
+ }
+ }
+
+ err = rtc_set_alarm(rtc, &alarm);
break;
case RTC_RD_TIME:
- err = rtc_read_time(class_dev, &tm);
+ err = rtc_read_time(rtc, &tm);
if (err < 0)
return err;
@@ -300,7 +335,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&tm, uarg, sizeof(tm)))
return -EFAULT;
- err = rtc_set_time(class_dev, &tm);
+ err = rtc_set_time(rtc, &tm);
break;
case RTC_IRQP_READ:
@@ -310,7 +345,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
case RTC_IRQP_SET:
if (ops->irq_set_freq)
- err = rtc_irq_set_freq(class_dev, rtc->irq_task, arg);
+ err = rtc_irq_set_freq(rtc, rtc->irq_task, arg);
break;
#if 0
@@ -336,11 +371,11 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
if (copy_from_user(&alarm, uarg, sizeof(alarm)))
return -EFAULT;
- err = rtc_set_alarm(class_dev, &alarm);
+ err = rtc_set_alarm(rtc, &alarm);
break;
case RTC_WKALM_RD:
- err = rtc_read_alarm(class_dev, &alarm);
+ err = rtc_read_alarm(rtc, &alarm);
if (err < 0)
return err;
@@ -372,7 +407,7 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
clear_uie(rtc);
#endif
if (rtc->ops->release)
- rtc->ops->release(rtc->class_dev.dev);
+ rtc->ops->release(rtc->dev.parent);
mutex_unlock(&rtc->char_lock);
return 0;
@@ -397,17 +432,18 @@ static const struct file_operations rtc_dev_fops = {
/* insertion/removal hooks */
-static int rtc_dev_add_device(struct class_device *class_dev,
- struct class_interface *class_intf)
+void rtc_dev_prepare(struct rtc_device *rtc)
{
- int err = 0;
- struct rtc_device *rtc = to_rtc_device(class_dev);
+ if (!rtc_devt)
+ return;
if (rtc->id >= RTC_DEV_MAX) {
- dev_err(class_dev->dev, "too many RTCs\n");
- return -EINVAL;
+ pr_debug("%s: too many RTC devices\n", rtc->name);
+ return;
}
+ rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
+
mutex_init(&rtc->char_lock);
spin_lock_init(&rtc->irq_lock);
init_waitqueue_head(&rtc->irq_queue);
@@ -418,100 +454,36 @@ static int rtc_dev_add_device(struct class_device *class_dev,
cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner;
+}
- if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
- dev_err(class_dev->dev,
- "failed to add char device %d:%d\n",
+void rtc_dev_add_device(struct rtc_device *rtc)
+{
+ if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
+ printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
+ rtc->name, MAJOR(rtc_devt), rtc->id);
+ else
+ pr_debug("%s: dev (%d:%d)\n", rtc->name,
MAJOR(rtc_devt), rtc->id);
- return -ENODEV;
- }
-
- rtc->rtc_dev = class_device_create(rtc_dev_class, NULL,
- MKDEV(MAJOR(rtc_devt), rtc->id),
- class_dev->dev, "rtc%d", rtc->id);
- if (IS_ERR(rtc->rtc_dev)) {
- dev_err(class_dev->dev, "cannot create rtc_dev device\n");
- err = PTR_ERR(rtc->rtc_dev);
- goto err_cdev_del;
- }
-
- dev_dbg(class_dev->dev, "rtc intf: dev (%d:%d)\n",
- MAJOR(rtc->rtc_dev->devt),
- MINOR(rtc->rtc_dev->devt));
-
- return 0;
-
-err_cdev_del:
-
- cdev_del(&rtc->char_dev);
- return err;
}
-static void rtc_dev_remove_device(struct class_device *class_dev,
- struct class_interface *class_intf)
+void rtc_dev_del_device(struct rtc_device *rtc)
{
- struct rtc_device *rtc = to_rtc_device(class_dev);
-
- if (rtc->rtc_dev) {
- dev_dbg(class_dev->dev, "removing char %d:%d\n",
- MAJOR(rtc->rtc_dev->devt),
- MINOR(rtc->rtc_dev->devt));
-
- class_device_unregister(rtc->rtc_dev);
+ if (rtc->dev.devt)
cdev_del(&rtc->char_dev);
- }
}
-/* interface registration */
-
-static struct class_interface rtc_dev_interface = {
- .add = &rtc_dev_add_device,
- .remove = &rtc_dev_remove_device,
-};
-
-static int __init rtc_dev_init(void)
+void __init rtc_dev_init(void)
{
int err;
- rtc_dev_class = class_create(THIS_MODULE, "rtc-dev");
- if (IS_ERR(rtc_dev_class))
- return PTR_ERR(rtc_dev_class);
-
err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
- if (err < 0) {
+ if (err < 0)
printk(KERN_ERR "%s: failed to allocate char dev region\n",
__FILE__);
- goto err_destroy_class;
- }
-
- err = rtc_interface_register(&rtc_dev_interface);
- if (err < 0) {
- printk(KERN_ERR "%s: failed to register the interface\n",
- __FILE__);
- goto err_unregister_chrdev;
- }
-
- return 0;
-
-err_unregister_chrdev:
- unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
-
-err_destroy_class:
- class_destroy(rtc_dev_class);
-
- return err;
}
-static void __exit rtc_dev_exit(void)
+void __exit rtc_dev_exit(void)
{
- class_interface_unregister(&rtc_dev_interface);
- class_destroy(rtc_dev_class);
- unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+ if (rtc_devt)
+ unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
}
-
-subsys_initcall(rtc_dev_init);
-module_exit(rtc_dev_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class dev interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index e27176c0e18..afa64c7fa2e 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -203,7 +203,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
events |= RTC_UF;
else
events |= RTC_AF;
- rtc_update_irq(&pdata->rtc->class_dev, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 7bbc26a34bd..ba795a4db1e 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -117,85 +117,4 @@ int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
}
EXPORT_SYMBOL(rtc_tm_to_time);
-
-/* Merge the valid (i.e. non-negative) fields of alarm into the current
- * time. If the valid alarm fields are earlier than the equivalent
- * fields in the time, carry one into the least significant invalid
- * field, so that the alarm expiry is in the future. It assumes that the
- * least significant invalid field is more significant than the most
- * significant valid field, and that the seconds field is valid.
- *
- * This is used by alarms that take relative (rather than absolute)
- * times, and/or have a simple binary second counter instead of
- * day/hour/minute/sec registers.
- */
-void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm)
-{
- int *alarmp = &alarm->tm_sec;
- int *timep = &now->tm_sec;
- int carry_into, i;
-
- /* Ignore everything past the 6th element (tm_year). */
- for (i = 5; i > 0; i--) {
- if (alarmp[i] < 0)
- alarmp[i] = timep[i];
- else
- break;
- }
-
- /* No carry needed if all fields are valid. */
- if (i == 5)
- return;
-
- for (carry_into = i + 1; i >= 0; i--) {
- if (alarmp[i] < timep[i])
- break;
-
- if (alarmp[i] > timep[i])
- return;
- }
-
- switch (carry_into) {
- case 1:
- alarm->tm_min++;
-
- if (alarm->tm_min < 60)
- return;
-
- alarm->tm_min = 0;
- /* fall-through */
-
- case 2:
- alarm->tm_hour++;
-
- if (alarm->tm_hour < 60)
- return;
-
- alarm->tm_hour = 0;
- /* fall-through */
-
- case 3:
- alarm->tm_mday++;
-
- if (alarm->tm_mday <= rtc_days_in_month[alarm->tm_mon])
- return;
-
- alarm->tm_mday = 1;
- /* fall-through */
-
- case 4:
- alarm->tm_mon++;
-
- if (alarm->tm_mon <= 12)
- return;
-
- alarm->tm_mon = 1;
- /* fall-through */
-
- case 5:
- alarm->tm_year++;
- }
-}
-EXPORT_SYMBOL(rtc_merge_alarm);
-
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
new file mode 100644
index 00000000000..eee4ee5bb75
--- /dev/null
+++ b/drivers/rtc/rtc-max6900.c
@@ -0,0 +1,311 @@
+/*
+ * rtc class driver for the Maxim MAX6900 chip
+ *
+ * Author: Dale Farnsworth <dale@farnsworth.org>
+ *
+ * based on previously existing rtc class drivers
+ *
+ * 2007 (c) MontaVista, Software, Inc. 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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+
+#define DRV_NAME "max6900"
+#define DRV_VERSION "0.1"
+
+/*
+ * register indices
+ */
+#define MAX6900_REG_SC 0 /* seconds 00-59 */
+#define MAX6900_REG_MN 1 /* minutes 00-59 */
+#define MAX6900_REG_HR 2 /* hours 00-23 */
+#define MAX6900_REG_DT 3 /* day of month 00-31 */
+#define MAX6900_REG_MO 4 /* month 01-12 */
+#define MAX6900_REG_DW 5 /* day of week 1-7 */
+#define MAX6900_REG_YR 6 /* year 00-99 */
+#define MAX6900_REG_CT 7 /* control */
+#define MAX6900_REG_LEN 8
+
+#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */
+
+/*
+ * register read/write commands
+ */
+#define MAX6900_REG_CONTROL_WRITE 0x8e
+#define MAX6900_REG_BURST_READ 0xbf
+#define MAX6900_REG_BURST_WRITE 0xbe
+#define MAX6900_REG_RESERVED_READ 0x96
+
+#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */
+
+#define MAX6900_I2C_ADDR 0xa0
+
+static unsigned short normal_i2c[] = {
+ MAX6900_I2C_ADDR >> 1,
+ I2C_CLIENT_END
+};
+
+I2C_CLIENT_INSMOD; /* defines addr_data */
+
+static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
+
+static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
+{
+ u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(reg_addr),
+ .buf = reg_addr
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = MAX6900_REG_LEN,
+ .buf = buf
+ }
+ };
+ int rc;
+
+ rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (rc != ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "%s: register read failed\n",
+ __FUNCTION__);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
+{
+ u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+ struct i2c_msg msgs[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = MAX6900_REG_LEN + 1,
+ .buf = i2c_buf
+ }
+ };
+ int rc;
+
+ memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
+
+ rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (rc != ARRAY_SIZE(msgs)) {
+ dev_err(&client->dev, "%s: register write failed\n",
+ __FUNCTION__);
+ return -EIO;
+ }
+ msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+ return 0;
+}
+
+static int max6900_i2c_validate_client(struct i2c_client *client)
+{
+ u8 regs[MAX6900_REG_LEN];
+ u8 zero_mask[MAX6900_REG_LEN] = {
+ 0x80, /* seconds */
+ 0x80, /* minutes */
+ 0x40, /* hours */
+ 0xc0, /* day of month */
+ 0xe0, /* month */
+ 0xf8, /* day of week */
+ 0x00, /* year */
+ 0x7f, /* control */
+ };
+ int i;
+ int rc;
+ int reserved;
+
+ reserved = i2c_smbus_read_byte_data(client, MAX6900_REG_RESERVED_READ);
+ if (reserved != 0x07)
+ return -ENODEV;
+
+ rc = max6900_i2c_read_regs(client, regs);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0; i < MAX6900_REG_LEN; ++i) {
+ if (regs[i] & zero_mask[i])
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
+{
+ int rc;
+ u8 regs[MAX6900_REG_LEN];
+
+ rc = max6900_i2c_read_regs(client, regs);
+ if (rc < 0)
+ return rc;
+
+ tm->tm_sec = BCD2BIN(regs[MAX6900_REG_SC]);
+ tm->tm_min = BCD2BIN(regs[MAX6900_REG_MN]);
+ tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
+ tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
+ tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
+ tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+ tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
+
+ return 0;
+}
+
+static int max6900_i2c_clear_write_protect(struct i2c_client *client)
+{
+ int rc;
+ rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0);
+ if (rc < 0) {
+ dev_err(&client->dev, "%s: control register write failed\n",
+ __FUNCTION__);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int max6900_i2c_set_time(struct i2c_client *client,
+ struct rtc_time const *tm)
+{
+ u8 regs[MAX6900_REG_LEN];
+ int rc;
+
+ rc = max6900_i2c_clear_write_protect(client);
+ if (rc < 0)
+ return rc;
+
+ regs[MAX6900_REG_SC] = BIN2BCD(tm->tm_sec);
+ regs[MAX6900_REG_MN] = BIN2BCD(tm->tm_min);
+ regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
+ regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
+ regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+ regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
+ regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
+ regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */
+
+ rc = max6900_i2c_write_regs(client, regs);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int max6900_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return max6900_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return max6900_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static int max6900_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, max6900_probe);
+}
+
+static int max6900_detach_client(struct i2c_client *client)
+{
+ struct rtc_device *const rtc = i2c_get_clientdata(client);
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ return i2c_detach_client(client);
+}
+
+static struct i2c_driver max6900_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .id = I2C_DRIVERID_MAX6900,
+ .attach_adapter = max6900_attach_adapter,
+ .detach_client = max6900_detach_client,
+};
+
+static const struct rtc_class_ops max6900_rtc_ops = {
+ .read_time = max6900_rtc_read_time,
+ .set_time = max6900_rtc_set_time,
+};
+
+static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind)
+{
+ int rc = 0;
+ struct i2c_client *client = NULL;
+ struct rtc_device *rtc = NULL;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+ rc = -ENODEV;
+ goto failout;
+ }
+
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == NULL) {
+ rc = -ENOMEM;
+ goto failout;
+ }
+
+ client->addr = addr;
+ client->adapter = adapter;
+ client->driver = &max6900_driver;
+ strlcpy(client->name, DRV_NAME, I2C_NAME_SIZE);
+
+ if (kind < 0) {
+ rc = max6900_i2c_validate_client(client);
+ if (rc < 0)
+ goto failout;
+ }
+
+ rc = i2c_attach_client(client);
+ if (rc < 0)
+ goto failout;
+
+ dev_info(&client->dev,
+ "chip found, driver version " DRV_VERSION "\n");
+
+ rtc = rtc_device_register(max6900_driver.driver.name,
+ &client->dev,
+ &max6900_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ rc = PTR_ERR(rtc);
+ goto failout_detach;
+ }
+
+ i2c_set_clientdata(client, rtc);
+
+ return 0;
+
+failout_detach:
+ i2c_detach_client(client);
+failout:
+ kfree(client);
+ return rc;
+}
+
+static int __init max6900_init(void)
+{
+ return i2c_add_driver(&max6900_driver);
+}
+
+static void __exit max6900_exit(void)
+{
+ i2c_del_driver(&max6900_driver);
+}
+
+MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(max6900_init);
+module_exit(max6900_exit);
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 9de8d67f4f8..60a8a4bb8bd 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -124,7 +124,7 @@ static void rtc_wait_not_busy(void)
/* now we have ~15 usec to read/write various registers */
}
-static irqreturn_t rtc_irq(int irq, void *class_dev)
+static irqreturn_t rtc_irq(int irq, void *rtc)
{
unsigned long events = 0;
u8 irq_data;
@@ -141,7 +141,7 @@ static irqreturn_t rtc_irq(int irq, void *class_dev)
if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
events |= RTC_IRQF | RTC_UF;
- rtc_update_irq(class_dev, 1, events);
+ rtc_update_irq(rtc, 1, events);
return IRQ_HANDLED;
}
@@ -289,34 +289,6 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
u8 reg;
- /* Much userspace code uses RTC_ALM_SET, thus "don't care" for
- * day/month/year specifies alarms up to 24 hours in the future.
- * So we need to handle that ... but let's ignore the "don't care"
- * values for hours/minutes/seconds.
- */
- if (alm->time.tm_mday <= 0
- && alm->time.tm_mon < 0
- && alm->time.tm_year < 0) {
- struct rtc_time tm;
- unsigned long now, then;
-
- omap_rtc_read_time(dev, &tm);
- rtc_tm_to_time(&tm, &now);
-
- alm->time.tm_mday = tm.tm_mday;
- alm->time.tm_mon = tm.tm_mon;
- alm->time.tm_year = tm.tm_year;
- rtc_tm_to_time(&alm->time, &then);
-
- /* sometimes the alarm wraps into tomorrow */
- if (then < now) {
- rtc_time_to_tm(now + 24 * 60 * 60, &tm);
- alm->time.tm_mday = tm.tm_mday;
- alm->time.tm_mon = tm.tm_mon;
- alm->time.tm_year = tm.tm_year;
- }
- }
-
if (tm2bcd(&alm->time) < 0)
return -EINVAL;
@@ -399,7 +371,7 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev)
goto fail;
}
platform_set_drvdata(pdev, rtc);
- class_set_devdata(&rtc->class_dev, mem);
+ dev_set_devdata(&rtc->dev, mem);
/* clear pending irqs, and set 1/second periodic,
* which we'll use instead of update irqs
@@ -418,13 +390,13 @@ static int __devinit omap_rtc_probe(struct platform_device *pdev)
/* handle periodic and alarm irqs */
if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,
- rtc->class_dev.class_id, &rtc->class_dev)) {
+ rtc->dev.bus_id, rtc)) {
pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
pdev->name, omap_rtc_timer);
goto fail0;
}
if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,
- rtc->class_dev.class_id, &rtc->class_dev)) {
+ rtc->dev.bus_id, rtc)) {
pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
pdev->name, omap_rtc_alarm);
goto fail1;
@@ -481,26 +453,17 @@ static int __devexit omap_rtc_remove(struct platform_device *pdev)
free_irq(omap_rtc_timer, rtc);
free_irq(omap_rtc_alarm, rtc);
- release_resource(class_get_devdata(&rtc->class_dev));
+ release_resource(dev_get_devdata(&rtc->dev));
rtc_device_unregister(rtc);
return 0;
}
#ifdef CONFIG_PM
-static struct timespec rtc_delta;
static u8 irqstat;
static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct rtc_time rtc_tm;
- struct timespec time;
-
- time.tv_nsec = 0;
- omap_rtc_read_time(NULL, &rtc_tm);
- rtc_tm_to_time(&rtc_tm, &time.tv_sec);
-
- save_time_delta(&rtc_delta, &time);
irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
/* FIXME the RTC alarm is not currently acting as a wakeup event
@@ -517,14 +480,6 @@ static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
static int omap_rtc_resume(struct platform_device *pdev)
{
- struct rtc_time rtc_tm;
- struct timespec time;
-
- time.tv_nsec = 0;
- omap_rtc_read_time(NULL, &rtc_tm);
- rtc_tm_to_time(&rtc_tm, &time.tv_sec);
-
- restore_time_delta(&rtc_delta, &time);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(omap_rtc_alarm);
else
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index f13daa9feca..e4bf68ca96f 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -51,7 +51,7 @@ static irqreturn_t pl031_interrupt(int irq, void *dev_id)
{
struct rtc_device *rtc = dev_id;
- rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+ rtc_update_irq(rtc, 1, RTC_AF);
return IRQ_HANDLED;
}
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index 1bd624fc685..8d300e6d0d9 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -16,18 +16,18 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-static struct class_device *rtc_dev = NULL;
-static DEFINE_MUTEX(rtc_lock);
+#include "rtc-core.h"
+
static int rtc_proc_show(struct seq_file *seq, void *offset)
{
int err;
- struct class_device *class_dev = seq->private;
- const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+ struct rtc_device *rtc = seq->private;
+ const struct rtc_class_ops *ops = rtc->ops;
struct rtc_wkalrm alrm;
struct rtc_time tm;
- err = rtc_read_time(class_dev, &tm);
+ err = rtc_read_time(rtc, &tm);
if (err == 0) {
seq_printf(seq,
"rtc_time\t: %02d:%02d:%02d\n"
@@ -36,7 +36,7 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
}
- err = rtc_read_alarm(class_dev, &alrm);
+ err = rtc_read_alarm(rtc, &alrm);
if (err == 0) {
seq_printf(seq, "alrm_time\t: ");
if ((unsigned int)alrm.time.tm_hour <= 24)
@@ -74,19 +74,19 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
seq_printf(seq, "24hr\t\t: yes\n");
if (ops->proc)
- ops->proc(class_dev->dev, seq);
+ ops->proc(rtc->dev.parent, seq);
return 0;
}
static int rtc_proc_open(struct inode *inode, struct file *file)
{
- struct class_device *class_dev = PDE(inode)->data;
+ struct rtc_device *rtc = PDE(inode)->data;
if (!try_module_get(THIS_MODULE))
return -ENODEV;
- return single_open(file, rtc_proc_show, class_dev);
+ return single_open(file, rtc_proc_show, rtc);
}
static int rtc_proc_release(struct inode *inode, struct file *file)
@@ -103,62 +103,22 @@ static const struct file_operations rtc_proc_fops = {
.release = rtc_proc_release,
};
-static int rtc_proc_add_device(struct class_device *class_dev,
- struct class_interface *class_intf)
+void rtc_proc_add_device(struct rtc_device *rtc)
{
- mutex_lock(&rtc_lock);
- if (rtc_dev == NULL) {
+ if (rtc->id == 0) {
struct proc_dir_entry *ent;
- rtc_dev = class_dev;
-
ent = create_proc_entry("driver/rtc", 0, NULL);
if (ent) {
- struct rtc_device *rtc = to_rtc_device(class_dev);
-
ent->proc_fops = &rtc_proc_fops;
ent->owner = rtc->owner;
- ent->data = class_dev;
-
- dev_dbg(class_dev->dev, "rtc intf: proc\n");
+ ent->data = rtc;
}
- else
- rtc_dev = NULL;
}
- mutex_unlock(&rtc_lock);
-
- return 0;
}
-static void rtc_proc_remove_device(struct class_device *class_dev,
- struct class_interface *class_intf)
+void rtc_proc_del_device(struct rtc_device *rtc)
{
- mutex_lock(&rtc_lock);
- if (rtc_dev == class_dev) {
+ if (rtc->id == 0)
remove_proc_entry("driver/rtc", NULL);
- rtc_dev = NULL;
- }
- mutex_unlock(&rtc_lock);
-}
-
-static struct class_interface rtc_proc_interface = {
- .add = &rtc_proc_add_device,
- .remove = &rtc_proc_remove_device,
-};
-
-static int __init rtc_proc_init(void)
-{
- return rtc_interface_register(&rtc_proc_interface);
}
-
-static void __exit rtc_proc_exit(void)
-{
- class_interface_unregister(&rtc_proc_interface);
-}
-
-subsys_initcall(rtc_proc_init);
-module_exit(rtc_proc_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class proc interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
new file mode 100644
index 00000000000..9d6de371495
--- /dev/null
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -0,0 +1,405 @@
+/*
+ * Ricoh RS5C313 RTC device/driver
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * 2005-09-19 modifed by kogiidena
+ *
+ * Based on the old drivers/char/rs5c313_rtc.c by:
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ *
+ * Based on code written by Paul Gortmaker.
+ * Copyright (C) 1996 Paul Gortmaker
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Based on other minimal char device drivers, like Alan's
+ * watchdog, Ted's random, etc. etc.
+ *
+ * 1.07 Paul Gortmaker.
+ * 1.08 Miquel van Smoorenburg: disallow certain things on the
+ * DEC Alpha as the CMOS clock is also used for other things.
+ * 1.09 Nikita Schmidt: epoch support and some Alpha cleanup.
+ * 1.09a Pete Zaitcev: Sun SPARC
+ * 1.09b Jeff Garzik: Modularize, init cleanup
+ * 1.09c Jeff Garzik: SMP cleanup
+ * 1.10 Paul Barton-Davis: add support for async I/O
+ * 1.10a Andrea Arcangeli: Alpha updates
+ * 1.10b Andrew Morton: SMP lock fix
+ * 1.10c Cesar Barros: SMP locking fixes and cleanup
+ * 1.10d Paul Gortmaker: delete paranoia check in rtc_exit
+ * 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness.
+ * 1.11 Takashi Iwai: Kernel access functions
+ * rtc_register/rtc_unregister/rtc_control
+ * 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
+ * 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
+ * CONFIG_HPET_EMULATE_RTC
+ * 1.13 Nobuhiro Iwamatsu: Updata driver.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#define DRV_NAME "rs5c313"
+#define DRV_VERSION "1.13"
+
+#ifdef CONFIG_SH_LANDISK
+/*****************************************************/
+/* LANDISK dependence part of RS5C313 */
+/*****************************************************/
+
+#define SCSMR1 0xFFE00000
+#define SCSCR1 0xFFE00008
+#define SCSMR1_CA 0x80
+#define SCSCR1_CKE 0x03
+#define SCSPTR1 0xFFE0001C
+#define SCSPTR1_EIO 0x80
+#define SCSPTR1_SPB1IO 0x08
+#define SCSPTR1_SPB1DT 0x04
+#define SCSPTR1_SPB0IO 0x02
+#define SCSPTR1_SPB0DT 0x01
+
+#define SDA_OEN SCSPTR1_SPB1IO
+#define SDA SCSPTR1_SPB1DT
+#define SCL_OEN SCSPTR1_SPB0IO
+#define SCL SCSPTR1_SPB0DT
+
+/* RICOH RS5C313 CE port */
+#define RS5C313_CE 0xB0000003
+
+/* RICOH RS5C313 CE port bit */
+#define RS5C313_CE_RTCCE 0x02
+
+/* SCSPTR1 data */
+unsigned char scsptr1_data;
+
+#define RS5C313_CEENABLE ctrl_outb(RS5C313_CE_RTCCE, RS5C313_CE);
+#define RS5C313_CEDISABLE ctrl_outb(0x00, RS5C313_CE)
+#define RS5C313_MISCOP ctrl_outb(0x02, 0xB0000008)
+
+static void rs5c313_init_port(void)
+{
+ /* Set SCK as I/O port and Initialize SCSPTR1 data & I/O port. */
+ ctrl_outb(ctrl_inb(SCSMR1) & ~SCSMR1_CA, SCSMR1);
+ ctrl_outb(ctrl_inb(SCSCR1) & ~SCSCR1_CKE, SCSCR1);
+
+ /* And Initialize SCL for RS5C313 clock */
+ scsptr1_data = ctrl_inb(SCSPTR1) | SCL; /* SCL:H */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ scsptr1_data = ctrl_inb(SCSPTR1) | SCL_OEN; /* SCL output enable */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ RS5C313_CEDISABLE; /* CE:L */
+}
+
+static void rs5c313_write_data(unsigned char data)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ /* SDA:Write Data */
+ scsptr1_data = (scsptr1_data & ~SDA) |
+ ((((0x80 >> i) & data) >> (7 - i)) << 2);
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ if (i == 0) {
+ scsptr1_data |= SDA_OEN; /* SDA:output enable */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ }
+ ndelay(700);
+ scsptr1_data &= ~SCL; /* SCL:L */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ ndelay(700);
+ scsptr1_data |= SCL; /* SCL:H */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ }
+
+ scsptr1_data &= ~SDA_OEN; /* SDA:output disable */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+}
+
+static unsigned char rs5c313_read_data(void)
+{
+ int i;
+ unsigned char data;
+
+ for (i = 0; i < 8; i++) {
+ ndelay(700);
+ /* SDA:Read Data */
+ data |= ((ctrl_inb(SCSPTR1) & SDA) >> 2) << (7 - i);
+ scsptr1_data &= ~SCL; /* SCL:L */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ ndelay(700);
+ scsptr1_data |= SCL; /* SCL:H */
+ ctrl_outb(scsptr1_data, SCSPTR1);
+ }
+ return data & 0x0F;
+}
+
+#endif /* CONFIG_SH_LANDISK */
+
+/*****************************************************/
+/* machine independence part of RS5C313 */
+/*****************************************************/
+
+/* RICOH RS5C313 address */
+#define RS5C313_ADDR_SEC 0x00
+#define RS5C313_ADDR_SEC10 0x01
+#define RS5C313_ADDR_MIN 0x02
+#define RS5C313_ADDR_MIN10 0x03
+#define RS5C313_ADDR_HOUR 0x04
+#define RS5C313_ADDR_HOUR10 0x05
+#define RS5C313_ADDR_WEEK 0x06
+#define RS5C313_ADDR_INTINTVREG 0x07
+#define RS5C313_ADDR_DAY 0x08
+#define RS5C313_ADDR_DAY10 0x09
+#define RS5C313_ADDR_MON 0x0A
+#define RS5C313_ADDR_MON10 0x0B
+#define RS5C313_ADDR_YEAR 0x0C
+#define RS5C313_ADDR_YEAR10 0x0D
+#define RS5C313_ADDR_CNTREG 0x0E
+#define RS5C313_ADDR_TESTREG 0x0F
+
+/* RICOH RS5C313 control register */
+#define RS5C313_CNTREG_ADJ_BSY 0x01
+#define RS5C313_CNTREG_WTEN_XSTP 0x02
+#define RS5C313_CNTREG_12_24 0x04
+#define RS5C313_CNTREG_CTFG 0x08
+
+/* RICOH RS5C313 test register */
+#define RS5C313_TESTREG_TEST 0x01
+
+/* RICOH RS5C313 control bit */
+#define RS5C313_CNTBIT_READ 0x40
+#define RS5C313_CNTBIT_AD 0x20
+#define RS5C313_CNTBIT_DT 0x10
+
+static unsigned char rs5c313_read_reg(unsigned char addr)
+{
+
+ rs5c313_write_data(addr | RS5C313_CNTBIT_READ | RS5C313_CNTBIT_AD);
+ return rs5c313_read_data();
+}
+
+static void rs5c313_write_reg(unsigned char addr, unsigned char data)
+{
+ data &= 0x0f;
+ rs5c313_write_data(addr | RS5C313_CNTBIT_AD);
+ rs5c313_write_data(data | RS5C313_CNTBIT_DT);
+ return;
+}
+
+static inline unsigned char rs5c313_read_cntreg(unsigned char addr)
+{
+ return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
+}
+
+static inline void rs5c313_write_cntreg(unsigned char data)
+{
+ rs5c313_write_reg(RS5C313_ADDR_CNTREG, data);
+}
+
+static inline void rs5c313_write_intintvreg(unsigned char data)
+{
+ rs5c313_write_reg(RS5C313_ADDR_INTINTVREG, data);
+}
+
+static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ int data;
+
+ while (1) {
+ RS5C313_CEENABLE; /* CE:H */
+
+ /* Initialize control reg. 24 hour */
+ rs5c313_write_cntreg(0x04);
+
+ if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+ break;
+
+ RS5C313_CEDISABLE;
+ ndelay(700); /* CE:L */
+
+ }
+
+ data = rs5c313_read_reg(RS5C313_ADDR_SEC);
+ data |= (rs5c313_read_reg(RS5C313_ADDR_SEC10) << 4);
+ tm->tm_sec = BCD2BIN(data);
+
+ data = rs5c313_read_reg(RS5C313_ADDR_MIN);
+ data |= (rs5c313_read_reg(RS5C313_ADDR_MIN10) << 4);
+ tm->tm_min = BCD2BIN(data);
+
+ data = rs5c313_read_reg(RS5C313_ADDR_HOUR);
+ data |= (rs5c313_read_reg(RS5C313_ADDR_HOUR10) << 4);
+ tm->tm_hour = BCD2BIN(data);
+
+ data = rs5c313_read_reg(RS5C313_ADDR_DAY);
+ data |= (rs5c313_read_reg(RS5C313_ADDR_DAY10) << 4);
+ tm->tm_mday = BCD2BIN(data);
+
+ data = rs5c313_read_reg(RS5C313_ADDR_MON);
+ data |= (rs5c313_read_reg(RS5C313_ADDR_MON10) << 4);
+ tm->tm_mon = BCD2BIN(data) - 1;
+
+ data = rs5c313_read_reg(RS5C313_ADDR_YEAR);
+ data |= (rs5c313_read_reg(RS5C313_ADDR_YEAR10) << 4);
+ tm->tm_year = BCD2BIN(data);
+
+ if (tm->tm_year < 70)
+ tm->tm_year += 100;
+
+ data = rs5c313_read_reg(RS5C313_ADDR_WEEK);
+ tm->tm_wday = BCD2BIN(data);
+
+ RS5C313_CEDISABLE;
+ ndelay(700); /* CE:L */
+
+ return 0;
+}
+
+static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ int data;
+
+ /* busy check. */
+ while (1) {
+ RS5C313_CEENABLE; /* CE:H */
+
+ /* Initiatlize control reg. 24 hour */
+ rs5c313_write_cntreg(0x04);
+
+ if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+ break;
+ RS5C313_MISCOP;
+ RS5C313_CEDISABLE;
+ ndelay(700); /* CE:L */
+ }
+
+ data = BIN2BCD(tm->tm_sec);
+ rs5c313_write_reg(RS5C313_ADDR_SEC, data);
+ rs5c313_write_reg(RS5C313_ADDR_SEC10, (data >> 4));
+
+ data = BIN2BCD(tm->tm_min);
+ rs5c313_write_reg(RS5C313_ADDR_MIN, data );
+ rs5c313_write_reg(RS5C313_ADDR_MIN10, (data >> 4));
+
+ data = BIN2BCD(tm->tm_hour);
+ rs5c313_write_reg(RS5C313_ADDR_HOUR, data);
+ rs5c313_write_reg(RS5C313_ADDR_HOUR10, (data >> 4));
+
+ data = BIN2BCD(tm->tm_mday);
+ rs5c313_write_reg(RS5C313_ADDR_DAY, data);
+ rs5c313_write_reg(RS5C313_ADDR_DAY10, (data>> 4));
+
+ data = BIN2BCD(tm->tm_mon + 1);
+ rs5c313_write_reg(RS5C313_ADDR_MON, data);
+ rs5c313_write_reg(RS5C313_ADDR_MON10, (data >> 4));
+
+ data = BIN2BCD(tm->tm_year % 100);
+ rs5c313_write_reg(RS5C313_ADDR_YEAR, data);
+ rs5c313_write_reg(RS5C313_ADDR_YEAR10, (data >> 4));
+
+ data = BIN2BCD(tm->tm_wday);
+ rs5c313_write_reg(RS5C313_ADDR_WEEK, data);
+
+ RS5C313_CEDISABLE; /* CE:H */
+ ndelay(700);
+
+ return 0;
+}
+
+static void rs5c313_check_xstp_bit(void)
+{
+ struct rtc_time tm;
+
+ RS5C313_CEENABLE; /* CE:H */
+ if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
+ /* INT interval reg. OFF */
+ rs5c313_write_intintvreg(0x00);
+ /* Initialize control reg. 24 hour & adjust */
+ rs5c313_write_cntreg(0x07);
+
+ /* busy check. */
+ while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)
+ RS5C313_MISCOP;
+
+ memset(&tm, 0, sizeof(struct rtc_time));
+ tm.tm_mday = 1;
+ tm.tm_mon = 1;
+
+ rs5c313_rtc_set_time(NULL, &tm);
+ printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
+ "1 Jan 2000\n");
+ }
+ RS5C313_CEDISABLE;
+ ndelay(700); /* CE:L */
+}
+
+static const struct rtc_class_ops rs5c313_rtc_ops = {
+ .read_time = rs5c313_rtc_read_time,
+ .set_time = rs5c313_rtc_set_time,
+};
+
+static int rs5c313_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = rtc_device_register("rs5c313", &pdev->dev,
+ &rs5c313_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ platform_set_drvdata(pdev, rtc);
+
+ return err;
+}
+
+static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata( pdev );
+
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+static struct platform_driver rs5c313_rtc_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = rs5c313_rtc_probe,
+ .remove = __devexit_p( rs5c313_rtc_remove ),
+};
+
+static int __init rs5c313_rtc_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&rs5c313_rtc_platform_driver);
+ if (err)
+ return err;
+
+ rs5c313_init_port();
+ rs5c313_check_xstp_bit();
+
+ return 0;
+}
+
+static void __exit rs5c313_rtc_exit(void)
+{
+ platform_driver_unregister( &rs5c313_rtc_platform_driver );
+}
+
+module_init(rs5c313_rtc_init);
+module_exit(rs5c313_rtc_exit);
+
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("kogiidena , Nobuhiro Iwamatsu <iwamatsu@nigauri.org>");
+MODULE_DESCRIPTION("Ricoh RS5C313 RTC device driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 9a79a24a748..54b61305346 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -50,7 +50,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
{
struct rtc_device *rdev = id;
- rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF);
+ rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
@@ -58,7 +58,7 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
{
struct rtc_device *rdev = id;
- rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF);
+ rtc_update_irq(rdev, tick_count++, RTC_PF | RTC_IRQF);
return IRQ_HANDLED;
}
@@ -548,37 +548,15 @@ static int ticnt_save;
static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
/* save TICNT for anyone using periodic interrupts */
-
ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
-
- /* calculate time delta for suspend */
-
- s3c_rtc_gettime(&pdev->dev, &tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- save_time_delta(&s3c_rtc_delta, &time);
s3c_rtc_enable(pdev, 0);
-
return 0;
}
static int s3c_rtc_resume(struct platform_device *pdev)
{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
s3c_rtc_enable(pdev, 1);
- s3c_rtc_gettime(&pdev->dev, &tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- restore_time_delta(&s3c_rtc_delta, &time);
-
writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
return 0;
}
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index 677bae820dc..0918b787c4d 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -93,7 +93,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
if (rtsr & RTSR_HZ)
events |= RTC_UF | RTC_IRQF;
- rtc_update_irq(&rtc->class_dev, 1, events);
+ rtc_update_irq(rtc, 1, events);
if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
rtc_update_alarm(&rtc_alarm);
@@ -119,7 +119,7 @@ static irqreturn_t timer1_interrupt(int irq, void *dev_id)
*/
OSSR = OSSR_M1; /* clear match on timer1 */
- rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF);
+ rtc_update_irq(rtc, rtc_timer1_count, RTC_PF | RTC_IRQF);
if (rtc_timer1_count == 1)
rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 198b9f22fbf..e0f91dfce0f 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -104,7 +104,7 @@ static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
writeb(tmp, rtc->regbase + RCR1);
- rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+ rtc_update_irq(rtc->rtc_dev, 1, events);
spin_unlock(&rtc->lock);
@@ -139,7 +139,7 @@ static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
rtc->rearm_aie = 1;
- rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+ rtc_update_irq(rtc->rtc_dev, 1, events);
}
spin_unlock(&rtc->lock);
@@ -153,7 +153,7 @@ static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
spin_lock(&rtc->lock);
- rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF);
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
spin_unlock(&rtc->lock);
@@ -341,7 +341,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_sec--;
#endif
- dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
__FUNCTION__,
tm->tm_sec, tm->tm_min, tm->tm_hour,
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 899ab8c514f..69df94b4484 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -12,20 +12,26 @@
#include <linux/module.h>
#include <linux/rtc.h>
+#include "rtc-core.h"
+
+
/* device attributes */
-static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
}
-static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
-static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
ssize_t retval;
struct rtc_time tm;
- retval = rtc_read_time(dev, &tm);
+ retval = rtc_read_time(to_rtc_device(dev), &tm);
if (retval == 0) {
retval = sprintf(buf, "%04d-%02d-%02d\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
@@ -33,14 +39,15 @@ static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
return retval;
}
-static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
-static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
ssize_t retval;
struct rtc_time tm;
- retval = rtc_read_time(dev, &tm);
+ retval = rtc_read_time(to_rtc_device(dev), &tm);
if (retval == 0) {
retval = sprintf(buf, "%02d:%02d:%02d\n",
tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -48,14 +55,15 @@ static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
return retval;
}
-static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
-static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
+static ssize_t
+rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
ssize_t retval;
struct rtc_time tm;
- retval = rtc_read_time(dev, &tm);
+ retval = rtc_read_time(to_rtc_device(dev), &tm);
if (retval == 0) {
unsigned long time;
rtc_tm_to_time(&tm, &time);
@@ -64,23 +72,18 @@ static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
return retval;
}
-static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
-
-static struct attribute *rtc_attrs[] = {
- &class_device_attr_name.attr,
- &class_device_attr_date.attr,
- &class_device_attr_time.attr,
- &class_device_attr_since_epoch.attr,
- NULL,
-};
-static struct attribute_group rtc_attr_group = {
- .attrs = rtc_attrs,
+static struct device_attribute rtc_attrs[] = {
+ __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
+ __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
+ __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
+ __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
+ { },
};
-
static ssize_t
-rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
+rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
ssize_t retval;
unsigned long alarm;
@@ -94,7 +97,7 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
* REVISIT maybe we should require RTC implementations to
* disable the RTC alarm after it triggers, for uniformity.
*/
- retval = rtc_read_alarm(dev, &alm);
+ retval = rtc_read_alarm(to_rtc_device(dev), &alm);
if (retval == 0 && alm.enabled) {
rtc_tm_to_time(&alm.time, &alarm);
retval = sprintf(buf, "%lu\n", alarm);
@@ -104,16 +107,18 @@ rtc_sysfs_show_wakealarm(struct class_device *dev, char *buf)
}
static ssize_t
-rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
+rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
{
ssize_t retval;
unsigned long now, alarm;
struct rtc_wkalrm alm;
+ struct rtc_device *rtc = to_rtc_device(dev);
/* Only request alarms that trigger in the future. Disable them
* by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
*/
- retval = rtc_read_time(dev, &alm.time);
+ retval = rtc_read_time(rtc, &alm.time);
if (retval < 0)
return retval;
rtc_tm_to_time(&alm.time, &now);
@@ -124,7 +129,7 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
* entirely prevent that here, without even the minimal
* locking from the /dev/rtcN api.
*/
- retval = rtc_read_alarm(dev, &alm);
+ retval = rtc_read_alarm(rtc, &alm);
if (retval < 0)
return retval;
if (alm.enabled)
@@ -141,10 +146,10 @@ rtc_sysfs_set_wakealarm(struct class_device *dev, const char *buf, size_t n)
}
rtc_time_to_tm(alarm, &alm.time);
- retval = rtc_set_alarm(dev, &alm);
+ retval = rtc_set_alarm(rtc, &alm);
return (retval < 0) ? retval : n;
}
-static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
@@ -153,71 +158,37 @@ static const CLASS_DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
* suspend-to-disk. So: no attribute unless that side effect is possible.
* (Userspace may disable that mechanism later.)
*/
-static inline int rtc_does_wakealarm(struct class_device *class_dev)
+static inline int rtc_does_wakealarm(struct rtc_device *rtc)
{
- struct rtc_device *rtc;
-
- if (!device_can_wakeup(class_dev->dev))
+ if (!device_can_wakeup(rtc->dev.parent))
return 0;
- rtc = to_rtc_device(class_dev);
return rtc->ops->set_alarm != NULL;
}
-static int rtc_sysfs_add_device(struct class_device *class_dev,
- struct class_interface *class_intf)
+void rtc_sysfs_add_device(struct rtc_device *rtc)
{
int err;
- dev_dbg(class_dev->dev, "rtc intf: sysfs\n");
+ /* not all RTCs support both alarms and wakeup */
+ if (!rtc_does_wakealarm(rtc))
+ return;
- err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group);
+ err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
if (err)
- dev_err(class_dev->dev, "failed to create %s\n",
- "sysfs attributes");
- else if (rtc_does_wakealarm(class_dev)) {
- /* not all RTCs support both alarms and wakeup */
- err = class_device_create_file(class_dev,
- &class_device_attr_wakealarm);
- if (err) {
- dev_err(class_dev->dev, "failed to create %s\n",
- "alarm attribute");
- sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
- }
- }
-
- return err;
+ dev_err(rtc->dev.parent, "failed to create "
+ "alarm attribute, %d",
+ err);
}
-static void rtc_sysfs_remove_device(struct class_device *class_dev,
- struct class_interface *class_intf)
+void rtc_sysfs_del_device(struct rtc_device *rtc)
{
- if (rtc_does_wakealarm(class_dev))
- class_device_remove_file(class_dev,
- &class_device_attr_wakealarm);
- sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
+ /* REVISIT did we add it successfully? */
+ if (rtc_does_wakealarm(rtc))
+ device_remove_file(&rtc->dev, &dev_attr_wakealarm);
}
-/* interface registration */
-
-static struct class_interface rtc_sysfs_interface = {
- .add = &rtc_sysfs_add_device,
- .remove = &rtc_sysfs_remove_device,
-};
-
-static int __init rtc_sysfs_init(void)
+void __init rtc_sysfs_init(struct class *rtc_class)
{
- return rtc_interface_register(&rtc_sysfs_interface);
+ rtc_class->dev_attrs = rtc_attrs;
}
-
-static void __exit rtc_sysfs_exit(void)
-{
- class_interface_unregister(&rtc_sysfs_interface);
-}
-
-subsys_initcall(rtc_sysfs_init);
-module_exit(rtc_sysfs_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("RTC class sysfs interface");
-MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index f50a1b8e160..254c9fce27d 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -101,11 +101,11 @@ static ssize_t test_irq_store(struct device *dev,
retval = count;
local_irq_disable();
if (strncmp(buf, "tick", 4) == 0)
- rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF);
+ rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);
else if (strncmp(buf, "alarm", 5) == 0)
- rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF);
+ rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
else if (strncmp(buf, "update", 6) == 0)
- rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF);
+ rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);
else
retval = -EINVAL;
local_irq_enable();
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index e40322b7193..af7596ef29e 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -97,6 +97,7 @@ static DEFINE_SPINLOCK(rtc_lock);
static char rtc_name[] = "RTC";
static unsigned long periodic_frequency;
static unsigned long periodic_count;
+static unsigned int alarm_enabled;
struct resource rtc_resource[2] = {
{ .name = rtc_name,
@@ -188,6 +189,7 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
low = rtc1_read(ECMPLREG);
mid = rtc1_read(ECMPMREG);
high = rtc1_read(ECMPHREG);
+ wkalrm->enabled = alarm_enabled;
spin_unlock_irq(&rtc_lock);
@@ -206,10 +208,18 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
spin_lock_irq(&rtc_lock);
+ if (alarm_enabled)
+ disable_irq(ELAPSEDTIME_IRQ);
+
rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
+ if (wkalrm->enabled)
+ enable_irq(ELAPSEDTIME_IRQ);
+
+ alarm_enabled = wkalrm->enabled;
+
spin_unlock_irq(&rtc_lock);
return 0;
@@ -221,10 +231,24 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
switch (cmd) {
case RTC_AIE_ON:
- enable_irq(ELAPSEDTIME_IRQ);
+ spin_lock_irq(&rtc_lock);
+
+ if (!alarm_enabled) {
+ enable_irq(ELAPSEDTIME_IRQ);
+ alarm_enabled = 1;
+ }
+
+ spin_unlock_irq(&rtc_lock);
break;
case RTC_AIE_OFF:
- disable_irq(ELAPSEDTIME_IRQ);
+ spin_lock_irq(&rtc_lock);
+
+ if (alarm_enabled) {
+ disable_irq(ELAPSEDTIME_IRQ);
+ alarm_enabled = 0;
+ }
+
+ spin_unlock_irq(&rtc_lock);
break;
case RTC_PIE_ON:
enable_irq(RTCLONG1_IRQ);
@@ -275,7 +299,7 @@ static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
rtc2_write(RTCINTREG, ELAPSEDTIME_INT);
- rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+ rtc_update_irq(rtc, 1, RTC_AF);
return IRQ_HANDLED;
}
@@ -291,7 +315,7 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
rtc1_write(RTCL1LREG, count);
rtc1_write(RTCL1HREG, count >> 16);
- rtc_update_irq(&rtc->class_dev, 1, RTC_PF);
+ rtc_update_irq(rtc, 1, RTC_PF);
return IRQ_HANDLED;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index e71929db8b0..977521013fe 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2174,6 +2174,51 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
return ret;
}
+struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device,
+ void *rdc_buffer,
+ int rdc_buffer_size, char *magic)
+{
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+
+ cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);
+
+ if (IS_ERR(cqr)) {
+ DEV_MESSAGE(KERN_WARNING, device, "%s",
+ "Could not allocate RDC request");
+ return cqr;
+ }
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = CCW_CMD_RDC;
+ ccw->cda = (__u32)(addr_t)rdc_buffer;
+ ccw->count = rdc_buffer_size;
+
+ cqr->device = device;
+ cqr->expires = 10*HZ;
+ clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ cqr->retries = 2;
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+ return cqr;
+}
+
+
+int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic,
+ void **rdc_buffer, int rdc_buffer_size)
+{
+ int ret;
+ struct dasd_ccw_req *cqr;
+
+ cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size,
+ magic);
+ if (IS_ERR(cqr))
+ return PTR_ERR(cqr);
+
+ ret = dasd_sleep_on(cqr);
+ dasd_sfree_request(cqr, cqr->device);
+ return ret;
+}
static int __init
dasd_init(void)
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index cecab2274a6..c9583fbc2a7 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -450,6 +450,81 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
return 0;
}
+struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device,
+ void *rcd_buffer,
+ struct ciw *ciw, __u8 lpm)
+{
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+
+ cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device);
+
+ if (IS_ERR(cqr)) {
+ DEV_MESSAGE(KERN_WARNING, device, "%s",
+ "Could not allocate RCD request");
+ return cqr;
+ }
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = ciw->cmd;
+ ccw->cda = (__u32)(addr_t)rcd_buffer;
+ ccw->count = ciw->count;
+
+ cqr->device = device;
+ cqr->expires = 10*HZ;
+ cqr->lpm = lpm;
+ clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+ cqr->retries = 2;
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+ return cqr;
+}
+
+static int dasd_eckd_read_conf_lpm(struct dasd_device *device,
+ void **rcd_buffer,
+ int *rcd_buffer_size, __u8 lpm)
+{
+ struct ciw *ciw;
+ char *rcd_buf = NULL;
+ int ret;
+ struct dasd_ccw_req *cqr;
+
+ /*
+ * scan for RCD command in extended SenseID data
+ */
+ ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD);
+ if (!ciw || ciw->cmd == 0) {
+ ret = -EOPNOTSUPP;
+ goto out_error;
+ }
+ rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+ if (!rcd_buf) {
+ ret = -ENOMEM;
+ goto out_error;
+ }
+ cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm);
+ if (IS_ERR(cqr)) {
+ ret = PTR_ERR(cqr);
+ goto out_error;
+ }
+ ret = dasd_sleep_on(cqr);
+ /*
+ * on success we update the user input parms
+ */
+ dasd_sfree_request(cqr, cqr->device);
+ if (ret)
+ goto out_error;
+
+ *rcd_buffer_size = ciw->count;
+ *rcd_buffer = rcd_buf;
+ return 0;
+out_error:
+ kfree(rcd_buf);
+ *rcd_buffer = NULL;
+ *rcd_buffer_size = 0;
+ return ret;
+}
+
static int
dasd_eckd_read_conf(struct dasd_device *device)
{
@@ -469,8 +544,8 @@ dasd_eckd_read_conf(struct dasd_device *device)
/* get configuration data per operational path */
for (lpm = 0x80; lpm; lpm>>= 1) {
if (lpm & path_data->opm){
- rc = read_conf_data_lpm(device->cdev, &conf_data,
- &conf_len, lpm);
+ rc = dasd_eckd_read_conf_lpm(device, &conf_data,
+ &conf_len, lpm);
if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */
MESSAGE(KERN_WARNING,
"Read configuration data returned "
@@ -639,7 +714,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
/* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data);
memset(rdc_data, 0, sizeof(rdc_data));
- rc = read_dev_chars(device->cdev, &rdc_data, 64);
+ rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64);
if (rc)
DEV_MESSAGE(KERN_WARNING, device,
"Read device characteristics returned "
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index be0909e3922..da16ead8aff 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -135,7 +135,7 @@ dasd_fba_check_characteristics(struct dasd_device *device)
}
/* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data);
- rc = read_dev_chars(device->cdev, &rdc_data, 32);
+ rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32);
if (rc) {
DEV_MESSAGE(KERN_WARNING, device,
"Read device characteristics returned error %d",
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index a2cc69e1141..241294cba41 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -509,6 +509,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
+int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int);
+
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
extern int dasd_probeonly;
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index bbd5b8b66f4..d6b06ab8118 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -23,7 +23,7 @@
/*
* The room for the SCCB (only for writing) is not equal to a pages size
- * (as it is specified as the maximum size in the the SCLP documentation)
+ * (as it is specified as the maximum size in the SCLP documentation)
* because of the additional data structure described above.
*/
#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index bb4ff537729..3b52f5c1dbe 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -103,6 +103,7 @@ enum tape_op {
TO_CRYPT_OFF, /* Disable encrpytion */
TO_KEKL_SET, /* Set KEK label */
TO_KEKL_QUERY, /* Query KEK label */
+ TO_RDC, /* Read device characteristics */
TO_SIZE, /* #entries in tape_op_t */
};
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 50f5edab83d..7e2b2ab4926 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -788,6 +788,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
case TO_SIZE:
case TO_KEKL_SET:
case TO_KEKL_QUERY:
+ case TO_RDC:
break;
}
return TAPE_IO_SUCCESS;
@@ -1549,6 +1550,26 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request,
return TAPE_IO_STOP;
}
+
+static int tape_3590_read_dev_chars(struct tape_device *device,
+ struct tape_3590_rdc_data *rdc_data)
+{
+ int rc;
+ struct tape_request *request;
+
+ request = tape_alloc_request(1, sizeof(*rdc_data));
+ if (IS_ERR(request))
+ return PTR_ERR(request);
+ request->op = TO_RDC;
+ tape_ccw_end(request->cpaddr, CCW_CMD_RDC, sizeof(*rdc_data),
+ request->cpdata);
+ rc = tape_do_io(device, request);
+ if (rc == 0)
+ memcpy(rdc_data, request->cpdata, sizeof(*rdc_data));
+ tape_free_request(request);
+ return rc;
+}
+
/*
* Setup device function
*/
@@ -1557,7 +1578,7 @@ tape_3590_setup_device(struct tape_device *device)
{
int rc;
struct tape_3590_disc_data *data;
- char *rdc_data;
+ struct tape_3590_rdc_data *rdc_data;
DBF_EVENT(6, "3590 device setup\n");
data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
@@ -1566,12 +1587,12 @@ tape_3590_setup_device(struct tape_device *device)
data->read_back_op = READ_PREVIOUS;
device->discdata = data;
- rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+ rdc_data = kmalloc(sizeof(*rdc_data), GFP_KERNEL | GFP_DMA);
if (!rdc_data) {
rc = -ENOMEM;
goto fail_kmalloc;
}
- rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+ rc = tape_3590_read_dev_chars(device, rdc_data);
if (rc) {
DBF_LH(3, "Read device characteristics failed!\n");
goto fail_kmalloc;
@@ -1579,7 +1600,7 @@ tape_3590_setup_device(struct tape_device *device)
rc = tape_std_assign(device);
if (rc)
goto fail_rdc_data;
- if (rdc_data[31] == 0x13) {
+ if (rdc_data->data[31] == 0x13) {
PRINT_INFO("Device has crypto support\n");
data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
tape_3592_disable_crypt(device);
diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h
index aa5138807af..4534055f137 100644
--- a/drivers/s390/char/tape_3590.h
+++ b/drivers/s390/char/tape_3590.h
@@ -129,6 +129,10 @@ struct tape_3590_med_sense {
char pad2[116];
} __attribute__ ((packed));
+struct tape_3590_rdc_data {
+ char data[64];
+} __attribute__ ((packed));
+
/* Datastructures for 3592 encryption support */
struct tape3592_kekl {
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index e2a8a1a04ba..2fae6338ee1 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -73,7 +73,7 @@ const char *tape_op_verbose[TO_SIZE] =
[TO_DIS] = "DIS", [TO_ASSIGN] = "ASS",
[TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON",
[TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
- [TO_KEKL_QUERY] = "KLQ",
+ [TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC",
};
static int
@@ -911,6 +911,7 @@ __tape_start_request(struct tape_device *device, struct tape_request *request)
case TO_ASSIGN:
case TO_UNASSIGN:
case TO_READ_ATTMSG:
+ case TO_RDC:
if (device->tape_state == TS_INIT)
break;
if (device->tape_state == TS_UNUSED)
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 05fac0733f3..f770018fe1d 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -69,7 +69,6 @@ static const char version[] = "QDIO base support version 2";
static int qdio_performance_stats = 0;
static int proc_perf_file_registration;
-static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
static struct qdio_perf_stats perf_stats;
static int hydra_thinints;
@@ -111,6 +110,31 @@ qdio_min(int a,int b)
}
/***************** SCRUBBER HELPER ROUTINES **********************/
+#ifdef CONFIG_64BIT
+static inline void qdio_perf_stat_inc(atomic64_t *count)
+{
+ if (qdio_performance_stats)
+ atomic64_inc(count);
+}
+
+static inline void qdio_perf_stat_dec(atomic64_t *count)
+{
+ if (qdio_performance_stats)
+ atomic64_dec(count);
+}
+#else /* CONFIG_64BIT */
+static inline void qdio_perf_stat_inc(atomic_t *count)
+{
+ if (qdio_performance_stats)
+ atomic_inc(count);
+}
+
+static inline void qdio_perf_stat_dec(atomic_t *count)
+{
+ if (qdio_performance_stats)
+ atomic_dec(count);
+}
+#endif /* CONFIG_64BIT */
static inline __u64
qdio_get_micros(void)
@@ -277,8 +301,7 @@ qdio_siga_sync(struct qdio_q *q, unsigned int gpr2,
QDIO_DBF_TEXT4(0,trace,"sigasync");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
- if (qdio_performance_stats)
- perf_stats.siga_syncs++;
+ qdio_perf_stat_inc(&perf_stats.siga_syncs);
cc = do_siga_sync(q->schid, gpr2, gpr3);
if (cc)
@@ -323,8 +346,7 @@ qdio_siga_output(struct qdio_q *q)
__u32 busy_bit;
__u64 start_time=0;
- if (qdio_performance_stats)
- perf_stats.siga_outs++;
+ qdio_perf_stat_inc(&perf_stats.siga_outs);
QDIO_DBF_TEXT4(0,trace,"sigaout");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
@@ -358,8 +380,7 @@ qdio_siga_input(struct qdio_q *q)
QDIO_DBF_TEXT4(0,trace,"sigain");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
- if (qdio_performance_stats)
- perf_stats.siga_ins++;
+ qdio_perf_stat_inc(&perf_stats.siga_ins);
cc = do_siga_input(q->schid, q->mask);
@@ -953,8 +974,7 @@ __qdio_outbound_processing(struct qdio_q *q)
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
- if (qdio_performance_stats)
- o_p_c++;
+ qdio_perf_stat_inc(&perf_stats.outbound_tl_runs_resched);
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
@@ -962,10 +982,8 @@ __qdio_outbound_processing(struct qdio_q *q)
}
return;
}
- if (qdio_performance_stats) {
- o_p_nc++;
- perf_stats.tl_runs++;
- }
+ qdio_perf_stat_inc(&perf_stats.outbound_tl_runs);
+ qdio_perf_stat_inc(&perf_stats.tl_runs);
/* see comment in qdio_kick_outbound_q */
siga_attempts=atomic_read(&q->busy_siga_counter);
@@ -978,18 +996,25 @@ __qdio_outbound_processing(struct qdio_q *q)
if (qdio_has_outbound_q_moved(q))
qdio_kick_outbound_handler(q);
- if (q->is_iqdio_q) {
+ if (q->queue_type == QDIO_ZFCP_QFMT) {
+ if ((!q->hydra_gives_outbound_pcis) &&
+ (!qdio_is_outbound_q_done(q)))
+ qdio_mark_q(q);
+ }
+ else if (((!q->is_iqdio_q) && (!q->is_pci_out)) ||
+ (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH)) {
/*
- * for asynchronous queues, we better check, if the sent
- * buffer is already switched from PRIMED to EMPTY.
+ * make sure buffer switch from PRIMED to EMPTY is noticed
+ * and outbound_handler is called
*/
- if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) &&
- !qdio_is_outbound_q_done(q))
- qdio_mark_q(q);
-
- } else if (!q->hydra_gives_outbound_pcis)
- if (!qdio_is_outbound_q_done(q))
- qdio_mark_q(q);
+ if (qdio_is_outbound_q_done(q)) {
+ del_timer(&q->timer);
+ } else {
+ if (!timer_pending(&q->timer))
+ mod_timer(&q->timer, jiffies +
+ QDIO_FORCE_CHECK_TIMEOUT);
+ }
+ }
qdio_release_q(q);
}
@@ -1139,17 +1164,6 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
{
int i;
- static int old_pcis=0;
- static int old_thinints=0;
-
- if (qdio_performance_stats) {
- if ((old_pcis==perf_stats.pcis)&&
- (old_thinints==perf_stats.thinints))
- perf_stats.start_time_inbound=NOW;
- else
- old_pcis=perf_stats.pcis;
- }
-
i=qdio_get_inbound_buffer_frontier(q);
if ( (i!=GET_SAVED_FRONTIER(q)) ||
(q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {
@@ -1337,10 +1351,7 @@ qdio_kick_inbound_handler(struct qdio_q *q)
q->siga_error=0;
q->error_status_flags=0;
- if (qdio_performance_stats) {
- perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
- perf_stats.inbound_cnt++;
- }
+ qdio_perf_stat_inc(&perf_stats.inbound_cnt);
}
static void
@@ -1360,8 +1371,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
*/
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
- if (qdio_performance_stats)
- ii_p_c++;
+ qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched);
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
@@ -1369,8 +1379,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
tiqdio_sched_tl();
return;
}
- if (qdio_performance_stats)
- ii_p_nc++;
+ qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs);
if (unlikely(atomic_read(&q->is_in_shutdown))) {
qdio_unmark_q(q);
goto out;
@@ -1412,8 +1421,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
for (i=0;i<irq_ptr->no_output_qs;i++) {
oq = irq_ptr->output_qs[i];
if (!qdio_is_outbound_q_done(oq)) {
- if (qdio_performance_stats)
- perf_stats.tl_runs--;
+ qdio_perf_stat_dec(&perf_stats.tl_runs);
__qdio_outbound_processing(oq);
}
}
@@ -1452,8 +1460,7 @@ __qdio_inbound_processing(struct qdio_q *q)
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
- if (qdio_performance_stats)
- i_p_c++;
+ qdio_perf_stat_inc(&perf_stats.inbound_tl_runs_resched);
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
@@ -1461,10 +1468,8 @@ __qdio_inbound_processing(struct qdio_q *q)
}
return;
}
- if (qdio_performance_stats) {
- i_p_nc++;
- perf_stats.tl_runs++;
- }
+ qdio_perf_stat_inc(&perf_stats.inbound_tl_runs);
+ qdio_perf_stat_inc(&perf_stats.tl_runs);
again:
if (qdio_has_inbound_q_moved(q)) {
@@ -1510,8 +1515,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
- if (qdio_performance_stats)
- ii_p_c++;
+ qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched);
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
@@ -1602,8 +1606,7 @@ tiqdio_tl(unsigned long data)
{
QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
- if (qdio_performance_stats)
- perf_stats.tl_runs++;
+ qdio_perf_stat_inc(&perf_stats.tl_runs);
tiqdio_inbound_checks();
}
@@ -1830,6 +1833,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->queue_type = QDIO_IQDIO_QFMT_ASYNCH;
q->int_parm=int_parm;
q->is_input_q=0;
+ q->is_pci_out = 0;
q->schid = irq_ptr->schid;
q->cdev = cdev;
q->irq_ptr = irq_ptr;
@@ -1842,6 +1846,10 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
q->tasklet.data=(unsigned long)q;
q->tasklet.func=(void(*)(unsigned long))
&qdio_outbound_processing;
+ q->timer.function=(void(*)(unsigned long))
+ &qdio_outbound_processing;
+ q->timer.data = (long)q;
+ init_timer(&q->timer);
atomic_set(&q->busy_siga_counter,0);
q->timing.busy_start=0;
@@ -1914,10 +1922,7 @@ tiqdio_thinint_handler(void)
{
QDIO_DBF_TEXT4(0,trace,"thin_int");
- if (qdio_performance_stats) {
- perf_stats.thinints++;
- perf_stats.start_time_inbound=NOW;
- }
+ qdio_perf_stat_inc(&perf_stats.thinints);
/* SVS only when needed:
* issue SVS to benefit from iqdio interrupt avoidance
@@ -1972,17 +1977,12 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
int i;
struct qdio_q *q;
- if (qdio_performance_stats) {
- perf_stats.pcis++;
- perf_stats.start_time_inbound=NOW;
- }
+ qdio_perf_stat_inc(&perf_stats.pcis);
for (i=0;i<irq_ptr->no_input_qs;i++) {
q=irq_ptr->input_qs[i];
if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
qdio_mark_q(q);
else {
- if (qdio_performance_stats)
- perf_stats.tl_runs--;
__qdio_inbound_processing(q);
}
}
@@ -1992,8 +1992,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
q=irq_ptr->output_qs[i];
if (qdio_is_outbound_q_done(q))
continue;
- if (qdio_performance_stats)
- perf_stats.tl_runs--;
+ qdio_perf_stat_dec(&perf_stats.tl_runs);
if (!irq_ptr->sync_done_on_outb_pcis)
SYNC_MEMORY;
__qdio_outbound_processing(q);
@@ -2648,6 +2647,7 @@ qdio_shutdown(struct ccw_device *cdev, int how)
for (i=0;i<irq_ptr->no_output_qs;i++) {
tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
+ del_timer(&irq_ptr->output_qs[i]->timer);
wait_event_interruptible_timeout(cdev->private->wait_q,
!atomic_read(&irq_ptr->
output_qs[i]->
@@ -3463,20 +3463,18 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
/* This is the outbound handling of queues */
- if (qdio_performance_stats)
- perf_stats.start_time_outbound=NOW;
-
qdio_do_qdio_fill_output(q,qidx,count,buffers);
used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
if (callflags&QDIO_FLAG_DONT_SIGA) {
- if (qdio_performance_stats) {
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
- }
+ qdio_perf_stat_inc(&perf_stats.outbound_cnt);
return;
}
+ if (callflags & QDIO_FLAG_PCI_OUT)
+ q->is_pci_out = 1;
+ else
+ q->is_pci_out = 0;
if (q->is_iqdio_q) {
/* one siga for every sbal */
while (count--)
@@ -3504,8 +3502,7 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
qdio_kick_outbound_q(q);
} else {
QDIO_DBF_TEXT3(0,trace, "fast-req");
- if (qdio_performance_stats)
- perf_stats.fast_reqs++;
+ qdio_perf_stat_inc(&perf_stats.fast_reqs);
}
}
/*
@@ -3516,10 +3513,7 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
__qdio_outbound_processing(q);
}
- if (qdio_performance_stats) {
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
- }
+ qdio_perf_stat_inc(&perf_stats.outbound_cnt);
}
/* count must be 1 in iqdio */
@@ -3589,33 +3583,67 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
return 0;
#define _OUTP_IT(x...) c+=sprintf(buffer+c,x)
- _OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
- _OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
- _OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
- _OUTP_IT("Number of tasklet runs (total) : %lu\n",
- perf_stats.tl_runs);
+#ifdef CONFIG_64BIT
+ _OUTP_IT("Number of tasklet runs (total) : %li\n",
+ (long)atomic64_read(&perf_stats.tl_runs));
+ _OUTP_IT("Inbound tasklet runs tried/retried : %li/%li\n",
+ (long)atomic64_read(&perf_stats.inbound_tl_runs),
+ (long)atomic64_read(&perf_stats.inbound_tl_runs_resched));
+ _OUTP_IT("Inbound-thin tasklet runs tried/retried : %li/%li\n",
+ (long)atomic64_read(&perf_stats.inbound_thin_tl_runs),
+ (long)atomic64_read(&perf_stats.inbound_thin_tl_runs_resched));
+ _OUTP_IT("Outbound tasklet runs tried/retried : %li/%li\n",
+ (long)atomic64_read(&perf_stats.outbound_tl_runs),
+ (long)atomic64_read(&perf_stats.outbound_tl_runs_resched));
+ _OUTP_IT("\n");
+ _OUTP_IT("Number of SIGA sync's issued : %li\n",
+ (long)atomic64_read(&perf_stats.siga_syncs));
+ _OUTP_IT("Number of SIGA in's issued : %li\n",
+ (long)atomic64_read(&perf_stats.siga_ins));
+ _OUTP_IT("Number of SIGA out's issued : %li\n",
+ (long)atomic64_read(&perf_stats.siga_outs));
+ _OUTP_IT("Number of PCIs caught : %li\n",
+ (long)atomic64_read(&perf_stats.pcis));
+ _OUTP_IT("Number of adapter interrupts caught : %li\n",
+ (long)atomic64_read(&perf_stats.thinints));
+ _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %li\n",
+ (long)atomic64_read(&perf_stats.fast_reqs));
_OUTP_IT("\n");
- _OUTP_IT("Number of SIGA sync's issued : %lu\n",
- perf_stats.siga_syncs);
- _OUTP_IT("Number of SIGA in's issued : %lu\n",
- perf_stats.siga_ins);
- _OUTP_IT("Number of SIGA out's issued : %lu\n",
- perf_stats.siga_outs);
- _OUTP_IT("Number of PCIs caught : %lu\n",
- perf_stats.pcis);
- _OUTP_IT("Number of adapter interrupts caught : %lu\n",
- perf_stats.thinints);
- _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %lu\n",
- perf_stats.fast_reqs);
+ _OUTP_IT("Number of inbound transfers : %li\n",
+ (long)atomic64_read(&perf_stats.inbound_cnt));
+ _OUTP_IT("Number of do_QDIOs outbound : %li\n",
+ (long)atomic64_read(&perf_stats.outbound_cnt));
+#else /* CONFIG_64BIT */
+ _OUTP_IT("Number of tasklet runs (total) : %i\n",
+ atomic_read(&perf_stats.tl_runs));
+ _OUTP_IT("Inbound tasklet runs tried/retried : %i/%i\n",
+ atomic_read(&perf_stats.inbound_tl_runs),
+ atomic_read(&perf_stats.inbound_tl_runs_resched));
+ _OUTP_IT("Inbound-thin tasklet runs tried/retried : %i/%i\n",
+ atomic_read(&perf_stats.inbound_thin_tl_runs),
+ atomic_read(&perf_stats.inbound_thin_tl_runs_resched));
+ _OUTP_IT("Outbound tasklet runs tried/retried : %i/%i\n",
+ atomic_read(&perf_stats.outbound_tl_runs),
+ atomic_read(&perf_stats.outbound_tl_runs_resched));
_OUTP_IT("\n");
- _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n",
- perf_stats.inbound_time);
- _OUTP_IT("Number of inbound transfers : %lu\n",
- perf_stats.inbound_cnt);
- _OUTP_IT("Total time of all outbound do_QDIOs (us) : %lu\n",
- perf_stats.outbound_time);
- _OUTP_IT("Number of do_QDIOs outbound : %lu\n",
- perf_stats.outbound_cnt);
+ _OUTP_IT("Number of SIGA sync's issued : %i\n",
+ atomic_read(&perf_stats.siga_syncs));
+ _OUTP_IT("Number of SIGA in's issued : %i\n",
+ atomic_read(&perf_stats.siga_ins));
+ _OUTP_IT("Number of SIGA out's issued : %i\n",
+ atomic_read(&perf_stats.siga_outs));
+ _OUTP_IT("Number of PCIs caught : %i\n",
+ atomic_read(&perf_stats.pcis));
+ _OUTP_IT("Number of adapter interrupts caught : %i\n",
+ atomic_read(&perf_stats.thinints));
+ _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %i\n",
+ atomic_read(&perf_stats.fast_reqs));
+ _OUTP_IT("\n");
+ _OUTP_IT("Number of inbound transfers : %i\n",
+ atomic_read(&perf_stats.inbound_cnt));
+ _OUTP_IT("Number of do_QDIOs outbound : %i\n",
+ atomic_read(&perf_stats.outbound_cnt));
+#endif /* CONFIG_64BIT */
_OUTP_IT("\n");
return c;
@@ -3642,8 +3670,6 @@ qdio_add_procfs_entry(void)
static void
qdio_remove_procfs_entry(void)
{
- perf_stats.tl_runs=0;
-
if (!proc_perf_file_registration) /* means if it went ok earlier */
remove_proc_entry(QDIO_PERF,&proc_root);
}
@@ -3671,13 +3697,38 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count
qdio_performance_stats = i;
if (i==0) {
/* reset perf. stat. info */
- i_p_nc = 0;
- i_p_c = 0;
- ii_p_nc = 0;
- ii_p_c = 0;
- o_p_nc = 0;
- o_p_c = 0;
- memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
+#ifdef CONFIG_64BIT
+ atomic64_set(&perf_stats.tl_runs, 0);
+ atomic64_set(&perf_stats.outbound_tl_runs, 0);
+ atomic64_set(&perf_stats.inbound_tl_runs, 0);
+ atomic64_set(&perf_stats.inbound_tl_runs_resched, 0);
+ atomic64_set(&perf_stats.inbound_thin_tl_runs, 0);
+ atomic64_set(&perf_stats.inbound_thin_tl_runs_resched,
+ 0);
+ atomic64_set(&perf_stats.siga_outs, 0);
+ atomic64_set(&perf_stats.siga_ins, 0);
+ atomic64_set(&perf_stats.siga_syncs, 0);
+ atomic64_set(&perf_stats.pcis, 0);
+ atomic64_set(&perf_stats.thinints, 0);
+ atomic64_set(&perf_stats.fast_reqs, 0);
+ atomic64_set(&perf_stats.outbound_cnt, 0);
+ atomic64_set(&perf_stats.inbound_cnt, 0);
+#else /* CONFIG_64BIT */
+ atomic_set(&perf_stats.tl_runs, 0);
+ atomic_set(&perf_stats.outbound_tl_runs, 0);
+ atomic_set(&perf_stats.inbound_tl_runs, 0);
+ atomic_set(&perf_stats.inbound_tl_runs_resched, 0);
+ atomic_set(&perf_stats.inbound_thin_tl_runs, 0);
+ atomic_set(&perf_stats.inbound_thin_tl_runs_resched, 0);
+ atomic_set(&perf_stats.siga_outs, 0);
+ atomic_set(&perf_stats.siga_ins, 0);
+ atomic_set(&perf_stats.siga_syncs, 0);
+ atomic_set(&perf_stats.pcis, 0);
+ atomic_set(&perf_stats.thinints, 0);
+ atomic_set(&perf_stats.fast_reqs, 0);
+ atomic_set(&perf_stats.outbound_cnt, 0);
+ atomic_set(&perf_stats.inbound_cnt, 0);
+#endif /* CONFIG_64BIT */
}
} else {
QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index ec9af72b2af..6d7aad18f6f 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -60,6 +60,7 @@
#define QDIO_ACTIVATE_TIMEOUT ((5*HZ)>>10)
#define QDIO_CLEANUP_CLEAR_TIMEOUT (20*HZ)
#define QDIO_CLEANUP_HALT_TIMEOUT (10*HZ)
+#define QDIO_FORCE_CHECK_TIMEOUT (10*HZ)
enum qdio_irq_states {
QDIO_IRQ_STATE_INACTIVE,
@@ -406,21 +407,43 @@ do_clear_global_summary(void)
#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
struct qdio_perf_stats {
- unsigned long tl_runs;
-
- unsigned long siga_outs;
- unsigned long siga_ins;
- unsigned long siga_syncs;
- unsigned long pcis;
- unsigned long thinints;
- unsigned long fast_reqs;
-
- __u64 start_time_outbound;
- unsigned long outbound_cnt;
- unsigned long outbound_time;
- __u64 start_time_inbound;
- unsigned long inbound_cnt;
- unsigned long inbound_time;
+#ifdef CONFIG_64BIT
+ atomic64_t tl_runs;
+ atomic64_t outbound_tl_runs;
+ atomic64_t outbound_tl_runs_resched;
+ atomic64_t inbound_tl_runs;
+ atomic64_t inbound_tl_runs_resched;
+ atomic64_t inbound_thin_tl_runs;
+ atomic64_t inbound_thin_tl_runs_resched;
+
+ atomic64_t siga_outs;
+ atomic64_t siga_ins;
+ atomic64_t siga_syncs;
+ atomic64_t pcis;
+ atomic64_t thinints;
+ atomic64_t fast_reqs;
+
+ atomic64_t outbound_cnt;
+ atomic64_t inbound_cnt;
+#else /* CONFIG_64BIT */
+ atomic_t tl_runs;
+ atomic_t outbound_tl_runs;
+ atomic_t outbound_tl_runs_resched;
+ atomic_t inbound_tl_runs;
+ atomic_t inbound_tl_runs_resched;
+ atomic_t inbound_thin_tl_runs;
+ atomic_t inbound_thin_tl_runs_resched;
+
+ atomic_t siga_outs;
+ atomic_t siga_ins;
+ atomic_t siga_syncs;
+ atomic_t pcis;
+ atomic_t thinints;
+ atomic_t fast_reqs;
+
+ atomic_t outbound_cnt;
+ atomic_t inbound_cnt;
+#endif /* CONFIG_64BIT */
};
/* unlikely as the later the better */
@@ -489,8 +512,8 @@ struct qdio_q {
void *irq_ptr;
-#ifdef QDIO_USE_TIMERS_FOR_POLLING
struct timer_list timer;
+#ifdef QDIO_USE_TIMERS_FOR_POLLING
atomic_t timer_already_set;
spinlock_t timer_lock;
#else /* QDIO_USE_TIMERS_FOR_POLLING */
@@ -536,6 +559,7 @@ struct qdio_q {
} timing;
atomic_t busy_siga_counter;
unsigned int queue_type;
+ unsigned int is_pci_out;
/* leave this member at the end. won't be cleared in qdio_fill_qs */
struct slib *slib; /* a page is allocated under this pointer,
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index e10e85e85c8..c358764f326 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1862,12 +1862,14 @@ static void netiucv_remove_connection(struct iucv_connection *conn)
write_lock_bh(&iucv_connection_rwlock);
list_del_init(&conn->list);
write_unlock_bh(&iucv_connection_rwlock);
+ fsm_deltimer(&conn->timer);
+ netiucv_purge_skb_queue(&conn->collect_queue);
if (conn->path) {
iucv_path_sever(conn->path, iucvMagic);
kfree(conn->path);
conn->path = NULL;
}
- fsm_deltimer(&conn->timer);
+ netiucv_purge_skb_queue(&conn->commit_queue);
kfree_fsm(conn->fsm);
kfree_skb(conn->rx_buff);
kfree_skb(conn->tx_buff);
@@ -2115,7 +2117,6 @@ static void __exit netiucv_exit(void)
while (!list_empty(&iucv_connection_list)) {
cp = list_entry(iucv_connection_list.next,
struct iucv_connection, list);
- list_del(&cp->list);
ndev = cp->netdev;
priv = netdev_priv(ndev);
dev = priv->dev;
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 84b108d7c7f..b34eb82edd9 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -288,6 +288,7 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
*/
#define IF_NAME_LEN 16
#define QETH_TX_TIMEOUT 100 * HZ
+#define QETH_RCD_TIMEOUT 60 * HZ
#define QETH_HEADER_SIZE 32
#define MAX_PORTNO 15
#define QETH_FAKE_LL_LEN_ETH ETH_HLEN
@@ -582,6 +583,8 @@ enum qeth_channel_states {
CH_STATE_ACTIVATING,
CH_STATE_HALTED,
CH_STATE_STOPPED,
+ CH_STATE_RCD,
+ CH_STATE_RCD_DONE,
};
/**
* card state machine
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index dd7034fbfff..4640f32daae 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -620,10 +620,10 @@ qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
struct qeth_eddp_context *
qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_hdr *qhdr)
+ struct qeth_hdr *qhdr, unsigned char sk_protocol)
{
QETH_DBF_TEXT(trace, 5, "creddpc");
- switch (skb->sk->sk_protocol){
+ switch (sk_protocol) {
case IPPROTO_TCP:
return qeth_eddp_create_context_tcp(card, skb, qhdr);
default:
diff --git a/drivers/s390/net/qeth_eddp.h b/drivers/s390/net/qeth_eddp.h
index 103768d3bab..52910c9252c 100644
--- a/drivers/s390/net/qeth_eddp.h
+++ b/drivers/s390/net/qeth_eddp.h
@@ -34,7 +34,8 @@ struct qeth_eddp_context_reference {
};
extern struct qeth_eddp_context *
-qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,struct qeth_hdr *);
+qeth_eddp_create_context(struct qeth_card *,struct sk_buff *,
+ struct qeth_hdr *, unsigned char);
extern void
qeth_eddp_put_context(struct qeth_eddp_context *);
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index ad7792dc1a0..0b96d49dd63 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -315,7 +315,8 @@ qeth_alloc_card(void)
}
static long
-__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
+__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm,
+ struct irb *irb)
{
if (!IS_ERR(irb))
return 0;
@@ -330,6 +331,14 @@ __qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
QETH_DBF_TEXT(trace, 2, "ckirberr");
QETH_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT);
+ if (intparm == QETH_RCD_PARM) {
+ struct qeth_card *card = CARD_FROM_CDEV(cdev);
+
+ if (card && (card->data.ccwdev == cdev)) {
+ card->data.state = CH_STATE_DOWN;
+ wake_up(&card->wait_q);
+ }
+ }
break;
default:
PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
@@ -401,7 +410,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
QETH_DBF_TEXT(trace,5,"irq");
- if (__qeth_check_irb_error(cdev, irb))
+ if (__qeth_check_irb_error(cdev, intparm, irb))
return;
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
@@ -429,7 +438,8 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
channel->state = CH_STATE_HALTED;
/*let's wake up immediately on data channel*/
- if ((channel == &card->data) && (intparm != 0))
+ if ((channel == &card->data) && (intparm != 0) &&
+ (intparm != QETH_RCD_PARM))
goto out;
if (intparm == QETH_CLEAR_CHANNEL_PARM) {
@@ -453,6 +463,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
HEXDUMP16(WARN,"irb: ",irb);
HEXDUMP16(WARN,"sense data: ",irb->ecw);
}
+ if (intparm == QETH_RCD_PARM) {
+ channel->state = CH_STATE_DOWN;
+ goto out;
+ }
rc = qeth_get_problem(cdev,irb);
if (rc) {
qeth_schedule_recovery(card);
@@ -460,6 +474,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
}
}
+ if (intparm == QETH_RCD_PARM) {
+ channel->state = CH_STATE_RCD_DONE;
+ goto out;
+ }
if (intparm) {
buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
buffer->state = BUF_STATE_PROCESSED;
@@ -1204,6 +1222,54 @@ qeth_probe_device(struct ccwgroup_device *gdev)
}
+static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
+ int *length)
+{
+ struct ciw *ciw;
+ char *rcd_buf;
+ int ret;
+ struct qeth_channel *channel = &card->data;
+ unsigned long flags;
+
+ /*
+ * scan for RCD command in extended SenseID data
+ */
+ ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD);
+ if (!ciw || ciw->cmd == 0)
+ return -EOPNOTSUPP;
+ rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+ if (!rcd_buf)
+ return -ENOMEM;
+
+ channel->ccw.cmd_code = ciw->cmd;
+ channel->ccw.cda = (__u32) __pa (rcd_buf);
+ channel->ccw.count = ciw->count;
+ channel->ccw.flags = CCW_FLAG_SLI;
+ channel->state = CH_STATE_RCD;
+ spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+ QETH_RCD_PARM, LPM_ANYPATH, 0,
+ QETH_RCD_TIMEOUT);
+ spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ if (!ret)
+ wait_event(card->wait_q,
+ (channel->state == CH_STATE_RCD_DONE ||
+ channel->state == CH_STATE_DOWN));
+ if (channel->state == CH_STATE_DOWN)
+ ret = -EIO;
+ else
+ channel->state = CH_STATE_DOWN;
+ if (ret) {
+ kfree(rcd_buf);
+ *buffer = NULL;
+ *length = 0;
+ } else {
+ *length = ciw->count;
+ *buffer = rcd_buf;
+ }
+ return ret;
+}
+
static int
qeth_get_unitaddr(struct qeth_card *card)
{
@@ -1212,9 +1278,9 @@ qeth_get_unitaddr(struct qeth_card *card)
int rc;
QETH_DBF_TEXT(setup, 2, "getunit");
- rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length);
+ rc = qeth_read_conf_data(card, (void **) &prcd, &length);
if (rc) {
- PRINT_ERR("read_conf_data for device %s returned %i\n",
+ PRINT_ERR("qeth_read_conf_data for device %s returned %i\n",
CARD_DDEV_ID(card), rc);
return rc;
}
@@ -1223,6 +1289,7 @@ qeth_get_unitaddr(struct qeth_card *card)
card->info.cula = prcd[63];
card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
(prcd[0x11] == _ascebc['M']));
+ kfree(prcd);
return 0;
}
@@ -1615,6 +1682,21 @@ qeth_put_reply(struct qeth_reply *reply)
kfree(reply);
}
+static void
+qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, struct qeth_card *card)
+{
+ int rc;
+ int com;
+ char * ipa_name;
+
+ com = cmd->hdr.command;
+ rc = cmd->hdr.return_code;
+ ipa_name = qeth_get_ipa_cmd_name(com);
+
+ PRINT_ERR("%s(x%X) for %s returned x%X \"%s\"\n", ipa_name, com,
+ QETH_CARD_IFNAME(card), rc, qeth_get_ipa_msg(rc));
+}
+
static struct qeth_ipa_cmd *
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
{
@@ -1623,8 +1705,11 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
QETH_DBF_TEXT(trace,5,"chkipad");
if (IS_IPA(iob->data)){
cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
- if (IS_IPA_REPLY(cmd))
+ if (IS_IPA_REPLY(cmd)) {
+ if (cmd->hdr.return_code)
+ qeth_issue_ipa_msg(cmd, card);
return cmd;
+ }
else {
switch (cmd->hdr.command) {
case IPA_CMD_STOPLAN:
@@ -2749,6 +2834,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
struct qeth_qdio_out_buffer *buf;
int rc;
int i;
+ unsigned int qdio_flags;
QETH_DBF_TEXT(trace, 6, "flushbuf");
@@ -2774,7 +2860,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
if (!atomic_read(&queue->set_pci_flags_count)){
/*
* there's no outstanding PCI any more, so we
- * have to request a PCI to be sure the the PCI
+ * have to request a PCI to be sure that the PCI
* will wake at some time in the future then we
* can flush packed buffers that might still be
* hanging around, which can happen if no
@@ -2792,13 +2878,13 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
queue->card->perf_stats.outbound_do_qdio_start_time =
qeth_get_micros();
}
+ qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
if (under_int)
- rc = do_QDIO(CARD_DDEV(queue->card),
- QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT,
- queue->queue_no, index, count, NULL);
- else
- rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT,
- queue->queue_no, index, count, NULL);
+ qdio_flags |= QDIO_FLAG_UNDER_INTERRUPT;
+ if (atomic_read(&queue->set_pci_flags_count))
+ qdio_flags |= QDIO_FLAG_PCI_OUT;
+ rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
+ queue->queue_no, index, count, NULL);
if (queue->card->options.performance_stats)
queue->card->perf_stats.outbound_do_qdio_time +=
qeth_get_micros() -
@@ -4423,7 +4509,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
qeth_fill_header(card, hdr, new_skb, ipv, cast_type);
}
if (large_send == QETH_LARGE_SEND_EDDP) {
- ctx = qeth_eddp_create_context(card, new_skb, hdr);
+ ctx = qeth_eddp_create_context(card, new_skb, hdr,
+ skb->sk->sk_protocol);
if (ctx == NULL) {
__qeth_free_new_skb(skb, new_skb);
PRINT_WARN("could not create eddp context\n");
@@ -5881,9 +5968,6 @@ qeth_layer2_send_setmac_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
QETH_DBF_TEXT_(trace, 2, "L2er%x", cmd->hdr.return_code);
- PRINT_WARN("Error in registering MAC address on " \
- "device %s: x%x\n", CARD_BUS_ID(card),
- cmd->hdr.return_code);
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
cmd->hdr.return_code = -EIO;
} else {
@@ -5918,9 +6002,6 @@ qeth_layer2_send_delmac_cb(struct qeth_card *card,
QETH_DBF_TEXT(trace, 2, "L2Dmaccb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
- PRINT_WARN("Error in deregistering MAC address on " \
- "device %s: x%x\n", CARD_BUS_ID(card),
- cmd->hdr.return_code);
QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code);
cmd->hdr.return_code = -EIO;
return 0;
@@ -6584,7 +6665,7 @@ qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
QETH_DBF_TEXT(trace,4,"chgmaccb");
cmd = (struct qeth_ipa_cmd *) data;
- if (!card->options.layer2 || card->info.guestlan ||
+ if (!card->options.layer2 ||
!(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
memcpy(card->dev->dev_addr,
&cmd->data.setadapterparms.data.change_addr.addr,
@@ -8430,6 +8511,7 @@ __qeth_reboot_event_card(struct device *dev, void *data)
card = (struct qeth_card *) dev->driver_data;
qeth_clear_ip_list(card, 0, 0);
qeth_qdio_clear_card(card, 0);
+ qeth_clear_qdio_buffers(card);
return 0;
}
diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c
index 77c83209d70..f54fdfdbf06 100644
--- a/drivers/s390/net/qeth_mpc.c
+++ b/drivers/s390/net/qeth_mpc.c
@@ -157,12 +157,113 @@ unsigned char READ_CCW[]={
};
+struct ipa_rc_msg {
+ enum qeth_ipa_return_codes rc;
+ char *msg;
+};
+struct ipa_rc_msg qeth_ipa_rc_msg[] = {
+ {IPA_RC_SUCCESS, "success"},
+ {IPA_RC_NOTSUPP, "Command not supported"},
+ {IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"},
+ {IPA_RC_UNKNOWN_ERROR, "IPA command failed - reason unknown"},
+ {IPA_RC_UNSUPPORTED_COMMAND, "Command not supported"},
+ {IPA_RC_DUP_IPV6_REMOTE,"ipv6 address already registered remote"},
+ {IPA_RC_DUP_IPV6_HOME, "ipv6 address already registered"},
+ {IPA_RC_UNREGISTERED_ADDR, "Address not registered"},
+ {IPA_RC_NO_ID_AVAILABLE, "No identifiers available"},
+ {IPA_RC_ID_NOT_FOUND, "Identifier not found"},
+ {IPA_RC_INVALID_IP_VERSION, "IP version incorrect"},
+ {IPA_RC_LAN_FRAME_MISMATCH, "LAN and frame mismatch"},
+ {IPA_RC_L2_UNSUPPORTED_CMD, "Unsupported layer 2 command"},
+ {IPA_RC_L2_DUP_MAC, "Duplicate MAC address"},
+ {IPA_RC_L2_ADDR_TABLE_FULL, "Layer2 address table full"},
+ {IPA_RC_L2_DUP_LAYER3_MAC, "Duplicate with layer 3 MAC"},
+ {IPA_RC_L2_GMAC_NOT_FOUND, "GMAC not found"},
+ {IPA_RC_L2_MAC_NOT_FOUND, "L2 mac address not found"},
+ {IPA_RC_L2_INVALID_VLAN_ID, "L2 invalid vlan id"},
+ {IPA_RC_L2_DUP_VLAN_ID, "L2 duplicate vlan id"},
+ {IPA_RC_L2_VLAN_ID_NOT_FOUND, "L2 vlan id not found"},
+ {IPA_RC_DATA_MISMATCH, "Data field mismatch (v4/v6 mixed)"},
+ {IPA_RC_INVALID_MTU_SIZE, "Invalid MTU size"},
+ {IPA_RC_INVALID_LANTYPE, "Invalid LAN type"},
+ {IPA_RC_INVALID_LANNUM, "Invalid LAN num"},
+ {IPA_RC_DUPLICATE_IP_ADDRESS, "Address already registered"},
+ {IPA_RC_IP_ADDR_TABLE_FULL, "IP address table full"},
+ {IPA_RC_LAN_PORT_STATE_ERROR, "LAN port state error"},
+ {IPA_RC_SETIP_NO_STARTLAN, "Setip no startlan received"},
+ {IPA_RC_SETIP_ALREADY_RECEIVED, "Setip already received"},
+ {IPA_RC_IP_ADDR_ALREADY_USED, "IP address already in use on LAN"},
+ {IPA_RC_MULTICAST_FULL, "No task available, multicast full"},
+ {IPA_RC_SETIP_INVALID_VERSION, "SETIP invalid IP version"},
+ {IPA_RC_UNSUPPORTED_SUBCMD, "Unsupported assist subcommand"},
+ {IPA_RC_ARP_ASSIST_NO_ENABLE, "Only partial success, no enable"},
+ {IPA_RC_PRIMARY_ALREADY_DEFINED,"Primary already defined"},
+ {IPA_RC_SECOND_ALREADY_DEFINED, "Secondary already defined"},
+ {IPA_RC_INVALID_SETRTG_INDICATOR,"Invalid SETRTG indicator"},
+ {IPA_RC_MC_ADDR_ALREADY_DEFINED,"Multicast address already defined"},
+ {IPA_RC_LAN_OFFLINE, "STRTLAN_LAN_DISABLED - LAN offline"},
+ {IPA_RC_INVALID_IP_VERSION2, "Invalid IP version"},
+ {IPA_RC_FFFF, "Unknown Error"}
+};
+char *
+qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
+{
+ int x = 0;
+ qeth_ipa_rc_msg[sizeof(qeth_ipa_rc_msg) /
+ sizeof(struct ipa_rc_msg) - 1].rc = rc;
+ while(qeth_ipa_rc_msg[x].rc != rc)
+ x++;
+ return qeth_ipa_rc_msg[x].msg;
+}
+struct ipa_cmd_names {
+ enum qeth_ipa_cmds cmd;
+ char *name;
+};
+
+struct ipa_cmd_names qeth_ipa_cmd_names[] = {
+ {IPA_CMD_STARTLAN, "startlan"},
+ {IPA_CMD_STOPLAN, "stoplan"},
+ {IPA_CMD_SETVMAC, "setvmac"},
+ {IPA_CMD_DELVMAC, "delvmca"},
+ {IPA_CMD_SETGMAC, "setgmac"},
+ {IPA_CMD_DELGMAC, "delgmac"},
+ {IPA_CMD_SETVLAN, "setvlan"},
+ {IPA_CMD_DELVLAN, "delvlan"},
+ {IPA_CMD_SETCCID, "setccid"},
+ {IPA_CMD_DELCCID, "delccid"},
+ {IPA_CMD_MODCCID, "setip"},
+ {IPA_CMD_SETIP, "setip"},
+ {IPA_CMD_QIPASSIST, "qipassist"},
+ {IPA_CMD_SETASSPARMS, "setassparms"},
+ {IPA_CMD_SETIPM, "setipm"},
+ {IPA_CMD_DELIPM, "delipm"},
+ {IPA_CMD_SETRTG, "setrtg"},
+ {IPA_CMD_DELIP, "delip"},
+ {IPA_CMD_SETADAPTERPARMS, "setadapterparms"},
+ {IPA_CMD_SET_DIAG_ASS, "set_diag_ass"},
+ {IPA_CMD_CREATE_ADDR, "create_addr"},
+ {IPA_CMD_DESTROY_ADDR, "destroy_addr"},
+ {IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"},
+ {IPA_CMD_UNREGISTER_LOCAL_ADDR, "unregister_local_addr"},
+ {IPA_CMD_UNKNOWN, "unknown"},
+};
+char *
+qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd)
+{
+ int x = 0;
+ qeth_ipa_cmd_names[
+ sizeof(qeth_ipa_cmd_names)/
+ sizeof(struct ipa_cmd_names)-1].cmd = cmd;
+ while(qeth_ipa_cmd_names[x].cmd != cmd)
+ x++;
+ return qeth_ipa_cmd_names[x].name;
+}
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 0477c47471c..1d8083c9176 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -25,18 +25,19 @@ extern unsigned char IPA_PDU_HEADER[];
#define IPA_CMD_LENGTH (IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
-#define QETH_SEQ_NO_LENGTH 4
-#define QETH_MPC_TOKEN_LENGTH 4
+#define QETH_SEQ_NO_LENGTH 4
+#define QETH_MPC_TOKEN_LENGTH 4
#define QETH_MCL_LENGTH 4
#define OSA_ADDR_LEN 6
-#define QETH_TIMEOUT (10 * HZ)
-#define QETH_IPA_TIMEOUT (45 * HZ)
-#define QETH_IDX_COMMAND_SEQNO 0xffff0000
+#define QETH_TIMEOUT (10 * HZ)
+#define QETH_IPA_TIMEOUT (45 * HZ)
+#define QETH_IDX_COMMAND_SEQNO 0xffff0000
#define SR_INFO_LEN 16
#define QETH_CLEAR_CHANNEL_PARM -10
#define QETH_HALT_CHANNEL_PARM -11
+#define QETH_RCD_PARM -12
/*****************************************************************************/
/* IP Assist related definitions */
@@ -92,79 +93,107 @@ enum qeth_checksum_types {
*/
#define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */
enum qeth_routing_types {
- NO_ROUTER = 0, /* TODO: set to bit flag used in IPA Command */
- PRIMARY_ROUTER = 1,
- SECONDARY_ROUTER = 2,
- MULTICAST_ROUTER = 3,
- PRIMARY_CONNECTOR = 4,
- SECONDARY_CONNECTOR = 5,
+ NO_ROUTER = 0, /* TODO: set to bit flag used in IPA Command */
+ PRIMARY_ROUTER = 1,
+ SECONDARY_ROUTER = 2,
+ MULTICAST_ROUTER = 3,
+ PRIMARY_CONNECTOR = 4,
+ SECONDARY_CONNECTOR = 5,
};
-
/* IPA Commands */
enum qeth_ipa_cmds {
- IPA_CMD_STARTLAN = 0x01,
- IPA_CMD_STOPLAN = 0x02,
- IPA_CMD_SETVMAC = 0x21,
- IPA_CMD_DELVMAC = 0x22,
- IPA_CMD_SETGMAC = 0x23,
- IPA_CMD_DELGMAC = 0x24,
- IPA_CMD_SETVLAN = 0x25,
- IPA_CMD_DELVLAN = 0x26,
- IPA_CMD_SETCCID = 0x41,
- IPA_CMD_DELCCID = 0x42,
- IPA_CMD_MODCCID = 0x43,
- IPA_CMD_SETIP = 0xb1,
- IPA_CMD_DELIP = 0xb7,
- IPA_CMD_QIPASSIST = 0xb2,
- IPA_CMD_SETASSPARMS = 0xb3,
- IPA_CMD_SETIPM = 0xb4,
- IPA_CMD_DELIPM = 0xb5,
- IPA_CMD_SETRTG = 0xb6,
- IPA_CMD_SETADAPTERPARMS = 0xb8,
- IPA_CMD_IPFRAME = 0xb9,
- IPA_CMD_ADD_ADDR_ENTRY = 0xc1,
- IPA_CMD_DELETE_ADDR_ENTRY = 0xc2,
- IPA_CMD_CREATE_ADDR = 0xc3,
- IPA_CMD_DESTROY_ADDR = 0xc4,
- IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
- IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2,
+ IPA_CMD_STARTLAN = 0x01,
+ IPA_CMD_STOPLAN = 0x02,
+ IPA_CMD_SETVMAC = 0x21,
+ IPA_CMD_DELVMAC = 0x22,
+ IPA_CMD_SETGMAC = 0x23,
+ IPA_CMD_DELGMAC = 0x24,
+ IPA_CMD_SETVLAN = 0x25,
+ IPA_CMD_DELVLAN = 0x26,
+ IPA_CMD_SETCCID = 0x41,
+ IPA_CMD_DELCCID = 0x42,
+ IPA_CMD_MODCCID = 0x43,
+ IPA_CMD_SETIP = 0xb1,
+ IPA_CMD_QIPASSIST = 0xb2,
+ IPA_CMD_SETASSPARMS = 0xb3,
+ IPA_CMD_SETIPM = 0xb4,
+ IPA_CMD_DELIPM = 0xb5,
+ IPA_CMD_SETRTG = 0xb6,
+ IPA_CMD_DELIP = 0xb7,
+ IPA_CMD_SETADAPTERPARMS = 0xb8,
+ IPA_CMD_SET_DIAG_ASS = 0xb9,
+ IPA_CMD_CREATE_ADDR = 0xc3,
+ IPA_CMD_DESTROY_ADDR = 0xc4,
+ IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
+ IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2,
+ IPA_CMD_UNKNOWN = 0x00
};
enum qeth_ip_ass_cmds {
IPA_CMD_ASS_START = 0x0001,
IPA_CMD_ASS_STOP = 0x0002,
- IPA_CMD_ASS_CONFIGURE = 0x0003,
- IPA_CMD_ASS_ENABLE = 0x0004,
+ IPA_CMD_ASS_CONFIGURE = 0x0003,
+ IPA_CMD_ASS_ENABLE = 0x0004,
};
enum qeth_arp_process_subcmds {
- IPA_CMD_ASS_ARP_SET_NO_ENTRIES = 0x0003,
- IPA_CMD_ASS_ARP_QUERY_CACHE = 0x0004,
- IPA_CMD_ASS_ARP_ADD_ENTRY = 0x0005,
- IPA_CMD_ASS_ARP_REMOVE_ENTRY = 0x0006,
- IPA_CMD_ASS_ARP_FLUSH_CACHE = 0x0007,
- IPA_CMD_ASS_ARP_QUERY_INFO = 0x0104,
- IPA_CMD_ASS_ARP_QUERY_STATS = 0x0204,
+ IPA_CMD_ASS_ARP_SET_NO_ENTRIES = 0x0003,
+ IPA_CMD_ASS_ARP_QUERY_CACHE = 0x0004,
+ IPA_CMD_ASS_ARP_ADD_ENTRY = 0x0005,
+ IPA_CMD_ASS_ARP_REMOVE_ENTRY = 0x0006,
+ IPA_CMD_ASS_ARP_FLUSH_CACHE = 0x0007,
+ IPA_CMD_ASS_ARP_QUERY_INFO = 0x0104,
+ IPA_CMD_ASS_ARP_QUERY_STATS = 0x0204,
};
-/* Return Codes for IPA Commands */
+
+/* Return Codes for IPA Commands
+ * according to OSA card Specs */
+
enum qeth_ipa_return_codes {
- IPA_RC_SUCCESS = 0x0000,
- IPA_RC_NOTSUPP = 0x0001,
- IPA_RC_NO_ACCESS = 0x0002,
- IPA_RC_FAILED = 0x0003,
- IPA_RC_DATA_MISMATCH = 0xe001,
- IPA_RC_INVALID_LAN_TYPE = 0xe003,
- IPA_RC_INVALID_LAN_NO = 0xe004,
- IPA_RC_IPADDR_ALREADY_REG = 0xe005,
- IPA_RC_IPADDR_TABLE_FULL = 0xe006,
- IPA_RC_IPADDR_ALREADY_USED = 0xe00a,
- IPA_RC_ASSNO_NOT_SUPP = 0xe00d,
- IPA_RC_ASSCMD_START_FAILED = 0xe00e,
- IPA_RC_ASSCMD_PART_SUCCESS = 0xe00f,
- IPA_RC_IPADDR_NOT_DEFINED = 0xe010,
- IPA_RC_LAN_OFFLINE = 0xe080,
+ IPA_RC_SUCCESS = 0x0000,
+ IPA_RC_NOTSUPP = 0x0001,
+ IPA_RC_IP_TABLE_FULL = 0x0002,
+ IPA_RC_UNKNOWN_ERROR = 0x0003,
+ IPA_RC_UNSUPPORTED_COMMAND = 0x0004,
+ IPA_RC_DUP_IPV6_REMOTE = 0x0008,
+ IPA_RC_DUP_IPV6_HOME = 0x0010,
+ IPA_RC_UNREGISTERED_ADDR = 0x0011,
+ IPA_RC_NO_ID_AVAILABLE = 0x0012,
+ IPA_RC_ID_NOT_FOUND = 0x0013,
+ IPA_RC_INVALID_IP_VERSION = 0x0020,
+ IPA_RC_LAN_FRAME_MISMATCH = 0x0040,
+ IPA_RC_L2_UNSUPPORTED_CMD = 0x2003,
+ IPA_RC_L2_DUP_MAC = 0x2005,
+ IPA_RC_L2_ADDR_TABLE_FULL = 0x2006,
+ IPA_RC_L2_DUP_LAYER3_MAC = 0x200a,
+ IPA_RC_L2_GMAC_NOT_FOUND = 0x200b,
+ IPA_RC_L2_MAC_NOT_FOUND = 0x2010,
+ IPA_RC_L2_INVALID_VLAN_ID = 0x2015,
+ IPA_RC_L2_DUP_VLAN_ID = 0x2016,
+ IPA_RC_L2_VLAN_ID_NOT_FOUND = 0x2017,
+ IPA_RC_DATA_MISMATCH = 0xe001,
+ IPA_RC_INVALID_MTU_SIZE = 0xe002,
+ IPA_RC_INVALID_LANTYPE = 0xe003,
+ IPA_RC_INVALID_LANNUM = 0xe004,
+ IPA_RC_DUPLICATE_IP_ADDRESS = 0xe005,
+ IPA_RC_IP_ADDR_TABLE_FULL = 0xe006,
+ IPA_RC_LAN_PORT_STATE_ERROR = 0xe007,
+ IPA_RC_SETIP_NO_STARTLAN = 0xe008,
+ IPA_RC_SETIP_ALREADY_RECEIVED = 0xe009,
+ IPA_RC_IP_ADDR_ALREADY_USED = 0xe00a,
+ IPA_RC_MULTICAST_FULL = 0xe00b,
+ IPA_RC_SETIP_INVALID_VERSION = 0xe00d,
+ IPA_RC_UNSUPPORTED_SUBCMD = 0xe00e,
+ IPA_RC_ARP_ASSIST_NO_ENABLE = 0xe00f,
+ IPA_RC_PRIMARY_ALREADY_DEFINED = 0xe010,
+ IPA_RC_SECOND_ALREADY_DEFINED = 0xe011,
+ IPA_RC_INVALID_SETRTG_INDICATOR = 0xe012,
+ IPA_RC_MC_ADDR_ALREADY_DEFINED = 0xe013,
+ IPA_RC_LAN_OFFLINE = 0xe080,
+ IPA_RC_INVALID_IP_VERSION2 = 0xf001,
+ IPA_RC_FFFF = 0xffff
};
/* IPA function flags; each flag marks availability of respective function */
@@ -182,7 +211,9 @@ enum qeth_ipa_funcs {
IPA_SETADAPTERPARMS = 0x00000400L,
IPA_VLAN_PRIO = 0x00000800L,
IPA_PASSTHRU = 0x00001000L,
+ IPA_FLUSH_ARP_SUPPORT = 0x00002000L,
IPA_FULL_VLAN = 0x00004000L,
+ IPA_INBOUND_PASSTHRU = 0x00008000L,
IPA_SOURCE_MAC = 0x00010000L,
IPA_OSA_MC_ROUTER = 0x00020000L,
IPA_QUERY_ARP_ASSIST = 0x00040000L,
@@ -203,31 +234,30 @@ enum qeth_ipa_setdelip_flags {
/* SETADAPTER IPA Command: ****************************************************/
enum qeth_ipa_setadp_cmd {
IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x01,
- IPA_SETADP_ALTER_MAC_ADDRESS = 0x02,
- IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x04,
- IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x08,
- IPA_SETADP_SET_ADDRESSING_MODE = 0x10,
- IPA_SETADP_SET_CONFIG_PARMS = 0x20,
- IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x40,
- IPA_SETADP_SET_BROADCAST_MODE = 0x80,
- IPA_SETADP_SEND_OSA_MESSAGE = 0x0100,
- IPA_SETADP_SET_SNMP_CONTROL = 0x0200,
- IPA_SETADP_READ_SNMP_PARMS = 0x0400,
+ IPA_SETADP_ALTER_MAC_ADDRESS = 0x02,
+ IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x04,
+ IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x08,
+ IPA_SETADP_SET_ADDRESSING_MODE = 0x10,
+ IPA_SETADP_SET_CONFIG_PARMS = 0x20,
+ IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x40,
+ IPA_SETADP_SET_BROADCAST_MODE = 0x80,
+ IPA_SETADP_SEND_OSA_MESSAGE = 0x0100,
+ IPA_SETADP_SET_SNMP_CONTROL = 0x0200,
+ IPA_SETADP_QUERY_CARD_INFO = 0x0400,
IPA_SETADP_SET_PROMISC_MODE = 0x0800,
- IPA_SETADP_QUERY_CARD_INFO = 0x1000,
};
enum qeth_ipa_mac_ops {
- CHANGE_ADDR_READ_MAC = 0,
- CHANGE_ADDR_REPLACE_MAC = 1,
- CHANGE_ADDR_ADD_MAC = 2,
- CHANGE_ADDR_DEL_MAC = 4,
- CHANGE_ADDR_RESET_MAC = 8,
+ CHANGE_ADDR_READ_MAC = 0,
+ CHANGE_ADDR_REPLACE_MAC = 1,
+ CHANGE_ADDR_ADD_MAC = 2,
+ CHANGE_ADDR_DEL_MAC = 4,
+ CHANGE_ADDR_RESET_MAC = 8,
};
enum qeth_ipa_addr_ops {
- CHANGE_ADDR_READ_ADDR = 0,
- CHANGE_ADDR_ADD_ADDR = 1,
- CHANGE_ADDR_DEL_ADDR = 2,
- CHANGE_ADDR_FLUSH_ADDR_TABLE = 4,
+ CHANGE_ADDR_READ_ADDR = 0,
+ CHANGE_ADDR_ADD_ADDR = 1,
+ CHANGE_ADDR_DEL_ADDR = 2,
+ CHANGE_ADDR_FLUSH_ADDR_TABLE = 4,
};
enum qeth_ipa_promisc_modes {
SET_PROMISC_MODE_OFF = 0,
@@ -406,15 +436,15 @@ struct qeth_ipacmd_hdr {
struct qeth_ipa_cmd {
struct qeth_ipacmd_hdr hdr;
union {
- struct qeth_ipacmd_setdelip4 setdelip4;
- struct qeth_ipacmd_setdelip6 setdelip6;
+ struct qeth_ipacmd_setdelip4 setdelip4;
+ struct qeth_ipacmd_setdelip6 setdelip6;
struct qeth_ipacmd_setdelipm setdelipm;
- struct qeth_ipacmd_setassparms setassparms;
- struct qeth_ipacmd_layer2setdelmac setdelmac;
- struct qeth_ipacmd_layer2setdelvlan setdelvlan;
- struct qeth_create_destroy_address create_destroy_addr;
- struct qeth_ipacmd_setadpparms setadapterparms;
- struct qeth_set_routing setrtg;
+ struct qeth_ipacmd_setassparms setassparms;
+ struct qeth_ipacmd_layer2setdelmac setdelmac;
+ struct qeth_ipacmd_layer2setdelvlan setdelvlan;
+ struct qeth_create_destroy_address create_destroy_addr;
+ struct qeth_ipacmd_setadpparms setadapterparms;
+ struct qeth_set_routing setrtg;
} data;
} __attribute__ ((packed));
@@ -432,6 +462,12 @@ enum qeth_ipa_arp_return_codes {
QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008,
};
+
+extern char *
+qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
+extern char *
+qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
+
#define QETH_SETASS_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setassparms_hdr))
#define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \
@@ -520,7 +556,7 @@ extern unsigned char DM_ACT[];
extern unsigned char IDX_ACTIVATE_READ[];
extern unsigned char IDX_ACTIVATE_WRITE[];
-#define IDX_ACTIVATE_SIZE 0x22
+#define IDX_ACTIVATE_SIZE 0x22
#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index d518419cd0c..65ffc21afc3 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -384,8 +384,6 @@ qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
route->type = PRIMARY_CONNECTOR;
} else if (!strcmp(tmp, "secondary_connector")) {
route->type = SECONDARY_CONNECTOR;
- } else if (!strcmp(tmp, "multicast_router")) {
- route->type = MULTICAST_ROUTER;
} else if (!strcmp(tmp, "primary_router")) {
route->type = PRIMARY_ROUTER;
} else if (!strcmp(tmp, "secondary_router")) {
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 1f9554e0801..324899c96ef 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -118,97 +118,32 @@ _zfcp_hex_dump(char *addr, int count)
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF
-static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
+static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter)
{
- int i;
+ int idx;
adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
GFP_KERNEL);
-
if (!adapter->req_list)
return -ENOMEM;
- for (i=0; i<REQUEST_LIST_SIZE; i++)
- INIT_LIST_HEAD(&adapter->req_list[i]);
-
+ for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+ INIT_LIST_HEAD(&adapter->req_list[idx]);
return 0;
}
static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
{
- struct zfcp_fsf_req *request, *tmp;
- unsigned int i;
-
- for (i=0; i<REQUEST_LIST_SIZE; i++) {
- if (list_empty(&adapter->req_list[i]))
- continue;
-
- list_for_each_entry_safe(request, tmp,
- &adapter->req_list[i], list)
- list_del(&request->list);
- }
-
kfree(adapter->req_list);
}
-void zfcp_reqlist_add(struct zfcp_adapter *adapter,
- struct zfcp_fsf_req *fsf_req)
-{
- unsigned int i;
-
- i = fsf_req->req_id % REQUEST_LIST_SIZE;
- list_add_tail(&fsf_req->list, &adapter->req_list[i]);
-}
-
-void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
-{
- struct zfcp_fsf_req *request, *tmp;
- unsigned int i, counter;
- u64 dbg_tmp[2];
-
- i = req_id % REQUEST_LIST_SIZE;
- BUG_ON(list_empty(&adapter->req_list[i]));
-
- counter = 0;
- list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
- if (request->req_id == req_id) {
- dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
- dbg_tmp[1] = (u64) counter;
- debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
- list_del(&request->list);
- break;
- }
- counter++;
- }
-}
-
-struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
- unsigned long req_id)
-{
- struct zfcp_fsf_req *request, *tmp;
- unsigned int i;
-
- /* 0 is reserved as an invalid req_id */
- if (req_id == 0)
- return NULL;
-
- i = req_id % REQUEST_LIST_SIZE;
-
- list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
- if (request->req_id == req_id)
- return request;
-
- return NULL;
-}
-
int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
{
- unsigned int i;
+ unsigned int idx;
- for (i=0; i<REQUEST_LIST_SIZE; i++)
- if (!list_empty(&adapter->req_list[i]))
+ for (idx = 0; idx < REQUEST_LIST_SIZE; idx++)
+ if (!list_empty(&adapter->req_list[idx]))
return 0;
-
return 1;
}
@@ -913,6 +848,8 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
unit->sysfs_device.release = zfcp_sysfs_unit_release;
dev_set_drvdata(&unit->sysfs_device, unit);
+ init_waitqueue_head(&unit->scsi_scan_wq);
+
/* mark unit unusable as long as sysfs registration is not complete */
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
@@ -1104,7 +1041,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* initialize list of fsf requests */
spin_lock_init(&adapter->req_list_lock);
- retval = zfcp_reqlist_init(adapter);
+ retval = zfcp_reqlist_alloc(adapter);
if (retval) {
ZFCP_LOG_INFO("request list initialization failed\n");
goto failed_low_mem_buffers;
@@ -1165,6 +1102,7 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
sysfs_failed:
dev_set_drvdata(&ccw_device->dev, NULL);
+ zfcp_reqlist_free(adapter);
failed_low_mem_buffers:
zfcp_free_low_mem_buffers(adapter);
if (qdio_free(ccw_device) != 0)
@@ -1497,7 +1435,7 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter,
if (!port || (port->wwpn != (*(wwn_t *) &els_plogi->serv_param.wwpn))) {
ZFCP_LOG_DEBUG("ignored incoming PLOGI for nonexisting port "
- "with d_id 0x%08x on adapter %s\n",
+ "with d_id 0x%06x on adapter %s\n",
status_buffer->d_id,
zfcp_get_busid_by_adapter(adapter));
} else {
@@ -1522,7 +1460,7 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter,
if (!port || (port->wwpn != els_logo->nport_wwpn)) {
ZFCP_LOG_DEBUG("ignored incoming LOGO for nonexisting port "
- "with d_id 0x%08x on adapter %s\n",
+ "with d_id 0x%06x on adapter %s\n",
status_buffer->d_id,
zfcp_get_busid_by_adapter(adapter));
} else {
@@ -1704,7 +1642,7 @@ static void zfcp_ns_gid_pn_handler(unsigned long data)
/* looks like a valid d_id */
port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK;
atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status);
- ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%08x\n",
+ ZFCP_LOG_DEBUG("adapter %s: wwpn=0x%016Lx ---> d_id=0x%06x\n",
zfcp_get_busid_by_port(port), port->wwpn, port->d_id);
goto out;
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 32933ed54b8..22649639230 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -637,6 +637,7 @@ do { \
#define ZFCP_STATUS_UNIT_SHARED 0x00000004
#define ZFCP_STATUS_UNIT_READONLY 0x00000008
#define ZFCP_STATUS_UNIT_REGISTERED 0x00000010
+#define ZFCP_STATUS_UNIT_SCSI_WORK_PENDING 0x00000020
/* FSF request status (this does not have a common part) */
#define ZFCP_STATUS_FSFREQ_NOT_INIT 0x00000000
@@ -980,6 +981,10 @@ struct zfcp_unit {
struct scsi_device *device; /* scsi device struct pointer */
struct zfcp_erp_action erp_action; /* pending error recovery */
atomic_t erp_counter;
+ wait_queue_head_t scsi_scan_wq; /* can be used to wait until
+ all scsi_scan_target
+ requests have been
+ completed. */
};
/* FSF request */
@@ -1085,6 +1090,42 @@ extern void _zfcp_hex_dump(char *, int);
#define zfcp_get_busid_by_unit(unit) (zfcp_get_busid_by_port(unit->port))
/*
+ * Helper functions for request ID management.
+ */
+static inline int zfcp_reqlist_hash(unsigned long req_id)
+{
+ return req_id % REQUEST_LIST_SIZE;
+}
+
+static inline void zfcp_reqlist_add(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *fsf_req)
+{
+ unsigned int idx;
+
+ idx = zfcp_reqlist_hash(fsf_req->req_id);
+ list_add_tail(&fsf_req->list, &adapter->req_list[idx]);
+}
+
+static inline void zfcp_reqlist_remove(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *fsf_req)
+{
+ list_del(&fsf_req->list);
+}
+
+static inline struct zfcp_fsf_req *
+zfcp_reqlist_find(struct zfcp_adapter *adapter, unsigned long req_id)
+{
+ struct zfcp_fsf_req *request;
+ unsigned int idx;
+
+ idx = zfcp_reqlist_hash(req_id);
+ list_for_each_entry(request, &adapter->req_list[idx], list)
+ if (request->req_id == req_id)
+ return request;
+ return NULL;
+}
+
+/*
* functions needed for reference/usage counting
*/
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 421da1e7c0e..aef66bc2b6c 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -179,14 +179,14 @@ static void zfcp_close_fsf(struct zfcp_adapter *adapter)
static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
- zfcp_erp_adapter_reopen(adapter, 0);
+ zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
}
void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
{
fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
fsf_req->timer.data = (unsigned long) fsf_req->adapter;
- fsf_req->timer.expires = timeout;
+ fsf_req->timer.expires = jiffies + timeout;
add_timer(&fsf_req->timer);
}
@@ -342,9 +342,9 @@ zfcp_erp_adisc(struct zfcp_port *port)
adisc->wwpn = fc_host_port_name(adapter->scsi_host);
adisc->wwnn = fc_host_node_name(adapter->scsi_host);
adisc->nport_id = fc_host_port_id(adapter->scsi_host);
- ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x "
+ ZFCP_LOG_INFO("ADISC request from s_id 0x%06x to d_id 0x%06x "
"(wwpn=0x%016Lx, wwnn=0x%016Lx, "
- "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+ "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn,
(wwn_t) adisc->wwnn, adisc->hard_nport_id,
adisc->nport_id);
@@ -352,7 +352,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
retval = zfcp_fsf_send_els(send_els);
if (retval != 0) {
ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
- "0x%08x on adapter %s\n", send_els->d_id,
+ "0x%06x on adapter %s\n", send_els->d_id,
zfcp_get_busid_by_adapter(adapter));
goto freemem;
}
@@ -398,7 +398,7 @@ zfcp_erp_adisc_handler(unsigned long data)
if (send_els->status != 0) {
ZFCP_LOG_NORMAL("ELS request rejected/timed out, "
"force physical port reopen "
- "(adapter %s, port d_id=0x%08x)\n",
+ "(adapter %s, port d_id=0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
debug_text_event(adapter->erp_dbf, 3, "forcreop");
if (zfcp_erp_port_forced_reopen(port, 0))
@@ -411,9 +411,9 @@ zfcp_erp_adisc_handler(unsigned long data)
adisc = zfcp_sg_to_address(send_els->resp);
- ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id "
- "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
- "hard_nport_id=0x%08x, nport_id=0x%08x)\n",
+ ZFCP_LOG_INFO("ADISC response from d_id 0x%06x to s_id "
+ "0x%06x (wwpn=0x%016Lx, wwnn=0x%016Lx, "
+ "hard_nport_id=0x%06x, nport_id=0x%06x)\n",
d_id, fc_host_port_id(adapter->scsi_host),
(wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn,
adisc->hard_nport_id, adisc->nport_id);
@@ -847,8 +847,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
if (erp_action->fsf_req) {
/* take lock to ensure that request is not deleted meanwhile */
spin_lock(&adapter->req_list_lock);
- if (zfcp_reqlist_ismember(adapter,
- erp_action->fsf_req->req_id)) {
+ if (zfcp_reqlist_find(adapter, erp_action->fsf_req->req_id)) {
/* fsf_req still exists */
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
debug_event(adapter->erp_dbf, 3, &erp_action->fsf_req,
@@ -1377,7 +1376,7 @@ zfcp_erp_port_failed(struct zfcp_port *port)
if (atomic_test_mask(ZFCP_STATUS_PORT_WKA, &port->status))
ZFCP_LOG_NORMAL("port erp failed (adapter %s, "
- "port d_id=0x%08x)\n",
+ "port d_id=0x%06x)\n",
zfcp_get_busid_by_port(port), port->d_id);
else
ZFCP_LOG_NORMAL("port erp failed (adapter %s, wwpn=0x%016Lx)\n",
@@ -1591,6 +1590,62 @@ zfcp_erp_strategy_check_adapter(struct zfcp_adapter *adapter, int result)
return result;
}
+struct zfcp_erp_add_work {
+ struct zfcp_unit *unit;
+ struct work_struct work;
+};
+
+/**
+ * zfcp_erp_scsi_scan
+ * @data: pointer to a struct zfcp_erp_add_work
+ *
+ * Registers a logical unit with the SCSI stack.
+ */
+static void zfcp_erp_scsi_scan(struct work_struct *work)
+{
+ struct zfcp_erp_add_work *p =
+ container_of(work, struct zfcp_erp_add_work, work);
+ struct zfcp_unit *unit = p->unit;
+ struct fc_rport *rport = unit->port->rport;
+ scsi_scan_target(&rport->dev, 0, rport->scsi_target_id,
+ unit->scsi_lun, 0);
+ atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+ wake_up(&unit->scsi_scan_wq);
+ zfcp_unit_put(unit);
+ kfree(p);
+}
+
+/**
+ * zfcp_erp_schedule_work
+ * @unit: pointer to unit which should be registered with SCSI stack
+ *
+ * Schedules work which registers a unit with the SCSI stack
+ */
+static void
+zfcp_erp_schedule_work(struct zfcp_unit *unit)
+{
+ struct zfcp_erp_add_work *p;
+
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
+ "the FCP-LUN 0x%Lx connected to "
+ "the port with WWPN 0x%Lx connected to "
+ "the adapter %s with the SCSI stack.\n",
+ unit->fcp_lun,
+ unit->port->wwpn,
+ zfcp_get_busid_by_unit(unit));
+ return;
+ }
+
+ zfcp_unit_get(unit);
+ memset(p, 0, sizeof(*p));
+ atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
+ INIT_WORK(&p->work, zfcp_erp_scsi_scan);
+ p->unit = unit;
+ schedule_work(&p->work);
+}
+
/*
* function:
*
@@ -2401,7 +2456,7 @@ zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *erp_action)
retval = ZFCP_ERP_FAILED;
}
} else {
- ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> "
+ ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> "
"trying open\n", port->wwpn, port->d_id);
retval = zfcp_erp_port_strategy_open_port(erp_action);
}
@@ -2441,7 +2496,7 @@ zfcp_erp_port_strategy_open_nameserver(struct zfcp_erp_action *erp_action)
case ZFCP_ERP_STEP_UNINITIALIZED:
case ZFCP_ERP_STEP_PHYS_PORT_CLOSING:
case ZFCP_ERP_STEP_PORT_CLOSING:
- ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%08x -> trying open\n",
+ ZFCP_LOG_DEBUG("port 0x%016Lx has d_id=0x%06x -> trying open\n",
port->wwpn, port->d_id);
retval = zfcp_erp_port_strategy_open_port(erp_action);
break;
@@ -3092,9 +3147,9 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
&& port->rport) {
atomic_set_mask(ZFCP_STATUS_UNIT_REGISTERED,
&unit->status);
- scsi_scan_target(&port->rport->dev, 0,
- port->rport->scsi_target_id,
- unit->scsi_lun, 0);
+ if (atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+ &unit->status) == 0)
+ zfcp_erp_schedule_work(unit);
}
zfcp_unit_put(unit);
break;
@@ -3121,7 +3176,7 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
zfcp_get_busid_by_port(port),
port->wwpn);
else {
- scsi_flush_work(adapter->scsi_host);
+ scsi_target_unblock(&port->rport->dev);
port->rport->maxframe_size = port->maxframe_size;
port->rport->supported_classes =
port->supported_classes;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 01386ac688a..991d45667a4 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -184,10 +184,6 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
unsigned long);
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
struct scsi_cmnd *);
-extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
-extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
-extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
- unsigned long);
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
#endif /* ZFCP_EXT_H */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index ef16f7ca4bb..a8b02542ac2 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -299,9 +299,10 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
}
/* log additional information provided by FSF (if any) */
- if (unlikely(qtcb->header.log_length)) {
+ if (likely(qtcb->header.log_length)) {
/* do not trust them ;-) */
- if (qtcb->header.log_start > sizeof(struct fsf_qtcb)) {
+ if (unlikely(qtcb->header.log_start >
+ sizeof(struct fsf_qtcb))) {
ZFCP_LOG_NORMAL
("bug: ULP (FSF logging) log data starts "
"beyond end of packet header. Ignored. "
@@ -310,8 +311,9 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req)
sizeof(struct fsf_qtcb));
goto forget_log;
}
- if ((size_t) (qtcb->header.log_start + qtcb->header.log_length)
- > sizeof(struct fsf_qtcb)) {
+ if (unlikely((size_t) (qtcb->header.log_start +
+ qtcb->header.log_length) >
+ sizeof(struct fsf_qtcb))) {
ZFCP_LOG_NORMAL("bug: ULP (FSF logging) log data ends "
"beyond end of packet header. Ignored. "
"(start=%i, length=%i, size=%li)\n",
@@ -826,7 +828,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
if (!port || (port->d_id != (status_buffer->d_id & ZFCP_DID_MASK))) {
ZFCP_LOG_NORMAL("bug: Reopen port indication received for"
- "nonexisting port with d_id 0x%08x on "
+ "nonexisting port with d_id 0x%06x on "
"adapter %s. Ignored.\n",
status_buffer->d_id & ZFCP_DID_MASK,
zfcp_get_busid_by_adapter(adapter));
@@ -851,7 +853,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req)
&status_buffer->status_subtype, sizeof (u32));
ZFCP_LOG_NORMAL("bug: Undefined status subtype received "
"for a reopen indication on port with "
- "d_id 0x%08x on the adapter %s. "
+ "d_id 0x%06x on the adapter %s. "
"Ignored. (debug info 0x%x)\n",
status_buffer->d_id,
zfcp_get_busid_by_adapter(adapter),
@@ -1154,7 +1156,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
}
ZFCP_LOG_DEBUG("Abort FCP Command request initiated "
- "(adapter%s, port d_id=0x%08x, "
+ "(adapter%s, port d_id=0x%06x, "
"unit x%016Lx, old_req_id=0x%lx)\n",
zfcp_get_busid_by_adapter(adapter),
unit->port->d_id,
@@ -1552,7 +1554,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
case FSF_ACCESS_DENIED:
ZFCP_LOG_NORMAL("access denied, cannot send generic service "
- "command (adapter %s, port d_id=0x%08x)\n",
+ "command (adapter %s, port d_id=0x%06x)\n",
zfcp_get_busid_by_port(port), port->d_id);
for (counter = 0; counter < 2; counter++) {
subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -1574,7 +1576,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
case FSF_GENERIC_COMMAND_REJECTED:
ZFCP_LOG_INFO("generic service command rejected "
- "(adapter %s, port d_id=0x%08x)\n",
+ "(adapter %s, port d_id=0x%06x)\n",
zfcp_get_busid_by_port(port), port->d_id);
ZFCP_LOG_INFO("status qualifier:\n");
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_INFO,
@@ -1600,7 +1602,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req)
case FSF_PORT_BOXED:
ZFCP_LOG_INFO("port needs to be reopened "
- "(adapter %s, port d_id=0x%08x)\n",
+ "(adapter %s, port d_id=0x%06x)\n",
zfcp_get_busid_by_port(port), port->d_id);
debug_text_event(adapter->erp_dbf, 2, "fsf_s_pboxed");
zfcp_erp_port_boxed(port);
@@ -1681,7 +1683,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
NULL, &lock_flags, &fsf_req);
if (ret < 0) {
ZFCP_LOG_INFO("error: creation of ELS request failed "
- "(adapter %s, port d_id: 0x%08x)\n",
+ "(adapter %s, port d_id: 0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
goto failed_req;
}
@@ -1706,7 +1708,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
ZFCP_MAX_SBALS_PER_ELS_REQ);
if (bytes <= 0) {
ZFCP_LOG_INFO("error: creation of ELS request failed "
- "(adapter %s, port d_id: 0x%08x)\n",
+ "(adapter %s, port d_id: 0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
if (bytes == 0) {
ret = -ENOMEM;
@@ -1723,7 +1725,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
ZFCP_MAX_SBALS_PER_ELS_REQ);
if (bytes <= 0) {
ZFCP_LOG_INFO("error: creation of ELS request failed "
- "(adapter %s, port d_id: 0x%08x)\n",
+ "(adapter %s, port d_id: 0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
if (bytes == 0) {
ret = -ENOMEM;
@@ -1737,7 +1739,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
/* reject request */
ZFCP_LOG_INFO("error: microcode does not support chained SBALs"
", ELS request too big (adapter %s, "
- "port d_id: 0x%08x)\n",
+ "port d_id: 0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
ret = -EOPNOTSUPP;
goto failed_send;
@@ -1758,13 +1760,13 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
ret = zfcp_fsf_req_send(fsf_req);
if (ret) {
ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
- "(adapter %s, port d_id: 0x%08x)\n",
+ "(adapter %s, port d_id: 0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
goto failed_send;
}
ZFCP_LOG_DEBUG("ELS request initiated (adapter %s, port d_id: "
- "0x%08x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
+ "0x%06x)\n", zfcp_get_busid_by_adapter(adapter), d_id);
goto out;
failed_send:
@@ -1857,7 +1859,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
case FSF_ELS_COMMAND_REJECTED:
ZFCP_LOG_INFO("ELS has been rejected because command filter "
"prohibited sending "
- "(adapter: %s, port d_id: 0x%08x)\n",
+ "(adapter: %s, port d_id: 0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
break;
@@ -1905,7 +1907,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
case FSF_ACCESS_DENIED:
ZFCP_LOG_NORMAL("access denied, cannot send ELS command "
- "(adapter %s, port d_id=0x%08x)\n",
+ "(adapter %s, port d_id=0x%06x)\n",
zfcp_get_busid_by_adapter(adapter), d_id);
for (counter = 0; counter < 2; counter++) {
subtable = header->fsf_status_qual.halfword[counter * 2];
@@ -2068,7 +2070,7 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok)
ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n"
"WWNN 0x%016Lx, "
"WWPN 0x%016Lx, "
- "S_ID 0x%08x,\n"
+ "S_ID 0x%06x,\n"
"adapter version 0x%x, "
"LIC version 0x%x, "
"FC link speed %d Gb/s\n",
@@ -3041,6 +3043,7 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req)
queue_designator = &header->fsf_status_qual.fsf_queue_designator;
atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
+ ZFCP_STATUS_COMMON_ACCESS_BOXED |
ZFCP_STATUS_UNIT_SHARED |
ZFCP_STATUS_UNIT_READONLY,
&unit->status);
@@ -4643,23 +4646,22 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
fsf_req->adapter = adapter;
fsf_req->fsf_command = fsf_cmd;
INIT_LIST_HEAD(&fsf_req->list);
-
- /* this is serialized (we are holding req_queue-lock of adapter */
- if (adapter->req_no == 0)
- adapter->req_no++;
- fsf_req->req_id = adapter->req_no++;
-
init_timer(&fsf_req->timer);
- zfcp_fsf_req_qtcb_init(fsf_req);
/* initialize waitqueue which may be used to wait on
this request completion */
init_waitqueue_head(&fsf_req->completion_wq);
ret = zfcp_fsf_req_sbal_get(adapter, req_flags, lock_flags);
- if(ret < 0) {
+ if (ret < 0)
goto failed_sbals;
- }
+
+ /* this is serialized (we are holding req_queue-lock of adapter) */
+ if (adapter->req_no == 0)
+ adapter->req_no++;
+ fsf_req->req_id = adapter->req_no++;
+
+ zfcp_fsf_req_qtcb_init(fsf_req);
/*
* We hold queue_lock here. Check if QDIOUP is set and let request fail
@@ -4786,7 +4788,7 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
retval = -EIO;
del_timer(&fsf_req->timer);
spin_lock(&adapter->req_list_lock);
- zfcp_reqlist_remove(adapter, fsf_req->req_id);
+ zfcp_reqlist_remove(adapter, fsf_req);
spin_unlock(&adapter->req_list_lock);
/* undo changes in request queue made for this request */
zfcp_qdio_zero_sbals(req_queue->buffer,
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 1e12a78e8ed..bdf5782b8a7 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -222,7 +222,7 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
* Since we have been using this adapter, it is save to assume
* that it is not failed but recoverable. The card seems to
* report link-up events by self-initiated queue shutdown.
- * That is why we need to clear the the link-down flag
+ * That is why we need to clear the link-down flag
* which is set again in case we have missed by a mile.
*/
zfcp_erp_adapter_reopen(
@@ -283,10 +283,10 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
}
/**
- * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status
+ * zfcp_qdio_reqid_check - checks for valid reqids.
*/
-static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
- unsigned long req_id)
+static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
+ unsigned long req_id)
{
struct zfcp_fsf_req *fsf_req;
unsigned long flags;
@@ -294,23 +294,22 @@ static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
debug_long_event(adapter->erp_dbf, 4, req_id);
spin_lock_irqsave(&adapter->req_list_lock, flags);
- fsf_req = zfcp_reqlist_ismember(adapter, req_id);
+ fsf_req = zfcp_reqlist_find(adapter, req_id);
- if (!fsf_req) {
- spin_unlock_irqrestore(&adapter->req_list_lock, flags);
- ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id);
- zfcp_erp_adapter_reopen(adapter, 0);
- return -EINVAL;
- }
+ if (!fsf_req)
+ /*
+ * Unknown request means that we have potentially memory
+ * corruption and must stop the machine immediatly.
+ */
+ panic("error: unknown request id (%ld) on adapter %s.\n",
+ req_id, zfcp_get_busid_by_adapter(adapter));
- zfcp_reqlist_remove(adapter, req_id);
+ zfcp_reqlist_remove(adapter, fsf_req);
atomic_dec(&adapter->reqs_active);
spin_unlock_irqrestore(&adapter->req_list_lock, flags);
/* finish the FSF request */
zfcp_fsf_req_complete(fsf_req);
-
- return 0;
}
/*
@@ -374,27 +373,9 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
/* look for QDIO request identifiers in SB */
buffere = &buffer->element[buffere_index];
- retval = zfcp_qdio_reqid_check(adapter,
- (unsigned long) buffere->addr);
-
- if (retval) {
- ZFCP_LOG_NORMAL("bug: unexpected inbound "
- "packet on adapter %s "
- "(reqid=0x%lx, "
- "first_element=%d, "
- "elements_processed=%d)\n",
- zfcp_get_busid_by_adapter(adapter),
- (unsigned long) buffere->addr,
- first_element,
- elements_processed);
- ZFCP_LOG_NORMAL("hex dump of inbound buffer "
- "at address %p "
- "(buffer_index=%d, "
- "buffere_index=%d)\n", buffer,
- buffer_index, buffere_index);
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) buffer, SBAL_SIZE);
- }
+ zfcp_qdio_reqid_check(adapter,
+ (unsigned long) buffere->addr);
+
/*
* A single used SBALE per inbound SBALE has been
* implemented by QDIO so far. Hope they will
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 99db02062c3..16e2d64658a 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -22,6 +22,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_SCSI
#include "zfcp_ext.h"
+#include <asm/atomic.h>
static void zfcp_scsi_slave_destroy(struct scsi_device *sdp);
static int zfcp_scsi_slave_alloc(struct scsi_device *sdp);
@@ -179,6 +180,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
if (unit) {
+ zfcp_erp_wait(unit->port->adapter);
+ wait_event(unit->scsi_scan_wq,
+ atomic_test_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING,
+ &unit->status) == 0);
atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
sdpnt->hostdata = NULL;
unit->device = NULL;
@@ -402,8 +407,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
/* Check whether corresponding fsf_req is still pending */
spin_lock(&adapter->req_list_lock);
- fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
- scpnt->host_scribble);
+ fsf_req = zfcp_reqlist_find(adapter,
+ (unsigned long) scpnt->host_scribble);
spin_unlock(&adapter->req_list_lock);
if (!fsf_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index a39ee80c971..4fab0c23814 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -15,7 +15,6 @@
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/ioport.h>
@@ -157,7 +156,7 @@ static unsigned short get_pins(unsigned minor)
#define BPP_ICR 0x18
#define BPP_SIZE 0x1A
-/* BPP_CSR. Bits of type RW1 are cleared with writting '1'. */
+/* 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. */
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
index 94d18582911..18d18f1a114 100644
--- a/drivers/sbus/char/rtc.c
+++ b/drivers/sbus/char/rtc.c
@@ -19,7 +19,6 @@
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/mostek.h>
#include <asm/system.h>
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index c3135e2fbd5..6afc7e5df0d 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index eee590a51d8..002643392d4 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -6,7 +6,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/device.h>
#include <asm/system.h>
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index e874b894487..96f4cab0761 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -579,17 +579,17 @@ static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapt
/*
Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
*/
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330)
BusLogic_AppendProbeAddressISA(0x330);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334)
BusLogic_AppendProbeAddressISA(0x334);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230)
BusLogic_AppendProbeAddressISA(0x230);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234)
BusLogic_AppendProbeAddressISA(0x234);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130)
BusLogic_AppendProbeAddressISA(0x130);
- if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+ if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134)
BusLogic_AppendProbeAddressISA(0x134);
}
@@ -795,7 +795,9 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
host adapters are probed.
*/
if (!BusLogic_ProbeOptions.NoProbeISA)
- if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) {
+ if (PrimaryProbeInfo->IO_Address == 0 &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe330)) {
PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
PrimaryProbeInfo->IO_Address = 0x330;
@@ -805,15 +807,25 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
omitting the Primary I/O Address which has already been handled.
*/
if (!BusLogic_ProbeOptions.NoProbeISA) {
- if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[1] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe334))
BusLogic_AppendProbeAddressISA(0x334);
- if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[2] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe230))
BusLogic_AppendProbeAddressISA(0x230);
- if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[3] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe234))
BusLogic_AppendProbeAddressISA(0x234);
- if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[4] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe130))
BusLogic_AppendProbeAddressISA(0x130);
- if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+ if (!StandardAddressSeen[5] &&
+ (!BusLogic_ProbeOptions.LimitedProbeISA ||
+ BusLogic_ProbeOptions.Probe134))
BusLogic_AppendProbeAddressISA(0x134);
}
/*
@@ -2220,22 +2232,35 @@ static int __init BusLogic_init(void)
HostAdapter->PCI_Device = ProbeInfo->PCI_Device;
HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
+
+ /*
+ Make sure region is free prior to probing.
+ */
+ if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount,
+ "BusLogic"))
+ continue;
/*
Probe the Host Adapter. If unsuccessful, abort further initialization.
*/
- if (!BusLogic_ProbeHostAdapter(HostAdapter))
+ if (!BusLogic_ProbeHostAdapter(HostAdapter)) {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
continue;
+ }
/*
Hard Reset the Host Adapter. If unsuccessful, abort further
initialization.
*/
- if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true))
+ if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
continue;
+ }
/*
Check the Host Adapter. If unsuccessful, abort further initialization.
*/
- if (!BusLogic_CheckHostAdapter(HostAdapter))
+ if (!BusLogic_CheckHostAdapter(HostAdapter)) {
+ release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
continue;
+ }
/*
Initialize the Driver Options field if provided.
*/
@@ -2247,16 +2272,6 @@ static int __init BusLogic_init(void)
*/
BusLogic_AnnounceDriver(HostAdapter);
/*
- Register usage of the I/O Address range. From this point onward, any
- failure will be assumed to be due to a problem with the Host Adapter,
- rather than due to having mistakenly identified this port as belonging
- to a BusLogic Host Adapter. The I/O Address range will not be
- released, thereby preventing it from being incorrectly identified as
- any other type of Host Adapter.
- */
- if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic"))
- continue;
- /*
Register the SCSI Host structure.
*/
@@ -2280,6 +2295,12 @@ static int __init BusLogic_init(void)
Acquire the System Resources necessary to use the Host Adapter, then
Create the Initial CCBs, Initialize the Host Adapter, and finally
perform Target Device Inquiry.
+
+ From this point onward, any failure will be assumed to be due to a
+ problem with the Host Adapter, rather than due to having mistakenly
+ identified this port as belonging to a BusLogic Host Adapter. The
+ I/O Address range will not be released, thereby preventing it from
+ being incorrectly identified as any other type of Host Adapter.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
@@ -3598,6 +3619,7 @@ static void __exit BusLogic_exit(void)
__setup("BusLogic=", BusLogic_Setup);
+#ifdef MODULE
static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -3607,6 +3629,7 @@ static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
+#endif
MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl);
module_init(BusLogic_init);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index fcc4cb6c7f4..e62d23f6518 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -170,7 +170,7 @@ config CHR_DEV_SCH
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
- say M here and read <file:Documentation/modules.txt> and
+ say M here and read <file:Documentation/kbuild/modules.txt> and
<file:Documentation/scsi.txt>. The module will be called ch.o.
If unsure, say N.
@@ -241,6 +241,12 @@ config SCSI_SCAN_ASYNC
You can override this choice by specifying "scsi_mod.scan=sync"
or async on the kernel's command line.
+config SCSI_WAIT_SCAN
+ tristate
+ default m
+ depends on SCSI
+ depends on MODULES
+
menu "SCSI Transports"
depends on SCSI
@@ -1194,17 +1200,6 @@ config SCSI_NCR53C8XX_SYNC
There is no safe option other than using good cabling, right
terminations and SCSI conformant devices.
-config SCSI_NCR53C8XX_PROFILE
- bool "enable profiling"
- depends on SCSI_ZALON || SCSI_NCR_Q720
- help
- This option allows you to enable profiling information gathering.
- These statistics are not very accurate due to the low frequency
- of the kernel clock (100 Hz on i386) and have performance impact
- on systems that use very fast devices.
-
- The normal answer therefore is N.
-
config SCSI_NCR53C8XX_NO_DISCONNECT
bool "not allow targets to disconnect"
depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
@@ -1334,11 +1329,6 @@ config SCSI_SIM710
It currently supports Compaq EISA cards and NCR MCA cards
-config 53C700_IO_MAPPED
- bool
- depends on SCSI_SIM710
- default y
-
config SCSI_SYM53C416
tristate "Symbios 53c416 SCSI support"
depends on ISA && SCSI
@@ -1649,7 +1639,7 @@ config OKTAGON_SCSI
config ATARI_SCSI
tristate "Atari native SCSI support"
- depends on ATARI && SCSI && BROKEN
+ depends on ATARI && SCSI
select SCSI_SPI_ATTRS
---help---
If you have an Atari with built-in NCR5380 SCSI controller (TT,
@@ -1793,7 +1783,7 @@ config ZFCP
This driver is also available as a module. This module will be
called zfcp. If you want to compile it as a module, say M here
- and read <file:Documentation/modules.txt>.
+ and read <file:Documentation/kbuild/modules.txt>.
config SCSI_SRP
tristate "SCSI RDMA Protocol helper library"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 70cff4c599d..51e884fa10b 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -146,7 +146,7 @@ obj-$(CONFIG_CHR_DEV_SCH) += ch.o
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
-obj-$(CONFIG_SCSI) += scsi_wait_scan.o
+obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o
scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index d789e61bdc4..1e82c69b36b 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -172,6 +172,30 @@ MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size.
int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
+
+
+static inline int aac_valid_context(struct scsi_cmnd *scsicmd,
+ struct fib *fibptr) {
+ struct scsi_device *device;
+
+ if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
+ dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"))
+;
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ return 0;
+ }
+ scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+ device = scsicmd->device;
+ if (unlikely(!device || !scsi_device_online(device))) {
+ dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n"));
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ return 0;
+ }
+ return 1;
+}
+
/**
* aac_get_config_status - check the adapter configuration
* @common: adapter to query
@@ -258,13 +282,10 @@ int aac_get_containers(struct aac_dev *dev)
u32 index;
int status = 0;
struct fib * fibptr;
- unsigned instance;
struct aac_get_container_count *dinfo;
struct aac_get_container_count_resp *dresp;
int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- instance = dev->scsi_host_ptr->unique_id;
-
if (!(fibptr = aac_fib_alloc(dev)))
return -ENOMEM;
@@ -284,88 +305,35 @@ int aac_get_containers(struct aac_dev *dev)
maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
aac_fib_complete(fibptr);
}
+ aac_fib_free(fibptr);
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- fsa_dev_ptr = kmalloc(
- sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
- if (!fsa_dev_ptr) {
- aac_fib_free(fibptr);
+ fsa_dev_ptr = kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
+ GFP_KERNEL);
+ if (!fsa_dev_ptr)
return -ENOMEM;
- }
memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
dev->fsa_dev = fsa_dev_ptr;
dev->maximum_num_containers = maximum_num_containers;
- for (index = 0; index < dev->maximum_num_containers; index++) {
- struct aac_query_mount *dinfo;
- struct aac_mount *dresp;
-
+ for (index = 0; index < dev->maximum_num_containers; ) {
fsa_dev_ptr[index].devname[0] = '\0';
- aac_fib_init(fibptr);
- dinfo = (struct aac_query_mount *) fib_data(fibptr);
-
- dinfo->command = cpu_to_le32(VM_NameServe);
- dinfo->count = cpu_to_le32(index);
- dinfo->type = cpu_to_le32(FT_FILESYS);
+ status = aac_probe_container(dev, index);
- status = aac_fib_send(ContainerCommand,
- fibptr,
- sizeof (struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL);
- if (status < 0 ) {
+ if (status < 0) {
printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
break;
}
- dresp = (struct aac_mount *)fib_data(fibptr);
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
- dinfo->command = cpu_to_le32(VM_NameServe64);
- dinfo->count = cpu_to_le32(index);
- dinfo->type = cpu_to_le32(FT_FILESYS);
-
- if (aac_fib_send(ContainerCommand,
- fibptr,
- sizeof(struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL) < 0)
- continue;
- } else
- dresp->mnt[0].capacityhigh = 0;
-
- dprintk ((KERN_DEBUG
- "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n",
- (int)index, (int)le32_to_cpu(dresp->status),
- (int)le32_to_cpu(dresp->mnt[0].vol),
- (int)le32_to_cpu(dresp->mnt[0].state),
- ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
- (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32)));
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
- (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
- fsa_dev_ptr[index].valid = 1;
- fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
- fsa_dev_ptr[index].size
- = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
- (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
- if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
- fsa_dev_ptr[index].ro = 1;
- }
- aac_fib_complete(fibptr);
/*
* If there are no more containers, then stop asking.
*/
- if ((index + 1) >= le32_to_cpu(dresp->count)){
+ if (++index >= status)
break;
- }
}
- aac_fib_free(fibptr);
return status;
}
@@ -382,8 +350,9 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
buf = scsicmd->request_buffer;
transfer_len = min(scsicmd->request_bufflen, len + offset);
}
-
- memcpy(buf + offset, data, transfer_len - offset);
+ transfer_len -= offset;
+ if (buf && transfer_len)
+ memcpy(buf + offset, data, transfer_len);
if (scsicmd->use_sg)
kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -396,7 +365,9 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
struct scsi_cmnd * scsicmd;
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
BUG_ON(fibptr == NULL);
@@ -431,7 +402,7 @@ static void get_container_name_callback(void *context, struct fib * fibptr)
/**
* aac_get_container_name - get container name, none blocking.
*/
-static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
+static int aac_get_container_name(struct scsi_cmnd * scsicmd)
{
int status;
struct aac_get_name *dinfo;
@@ -448,7 +419,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
dinfo->command = cpu_to_le32(VM_ContainerConfig);
dinfo->type = cpu_to_le32(CT_READ_NAME);
- dinfo->cid = cpu_to_le32(cid);
+ dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
status = aac_fib_send(ContainerCommand,
@@ -473,85 +444,192 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
return -1;
}
-/**
- * aac_probe_container - query a logical volume
- * @dev: device to query
- * @cid: container identifier
- *
- * Queries the controller about the given volume. The volume information
- * is updated in the struct fsa_dev_info structure rather than returned.
- */
-
-int aac_probe_container(struct aac_dev *dev, int cid)
+static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
+{
+ struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+
+ if (fsa_dev_ptr[scmd_id(scsicmd)].valid)
+ return aac_scsi_cmd(scsicmd);
+
+ scsicmd->result = DID_NO_CONNECT << 16;
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+}
+
+static int _aac_probe_container2(void * context, struct fib * fibptr)
{
struct fsa_dev_info *fsa_dev_ptr;
- int status;
+ int (*callback)(struct scsi_cmnd *);
+ struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return 0;
+
+ fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+
+ scsicmd->SCp.Status = 0;
+ if (fsa_dev_ptr) {
+ struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
+ fsa_dev_ptr += scmd_id(scsicmd);
+
+ if ((le32_to_cpu(dresp->status) == ST_OK) &&
+ (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+ (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
+ fsa_dev_ptr->valid = 1;
+ fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
+ fsa_dev_ptr->size
+ = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+ (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
+ fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0);
+ }
+ if ((fsa_dev_ptr->valid & 1) == 0)
+ fsa_dev_ptr->valid = 0;
+ scsicmd->SCp.Status = le32_to_cpu(dresp->count);
+ }
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
+ scsicmd->SCp.ptr = NULL;
+ return (*callback)(scsicmd);
+}
+
+static int _aac_probe_container1(void * context, struct fib * fibptr)
+{
+ struct scsi_cmnd * scsicmd;
+ struct aac_mount * dresp;
struct aac_query_mount *dinfo;
- struct aac_mount *dresp;
- struct fib * fibptr;
- unsigned instance;
+ int status;
- fsa_dev_ptr = dev->fsa_dev;
- if (!fsa_dev_ptr)
- return -ENOMEM;
- instance = dev->scsi_host_ptr->unique_id;
+ dresp = (struct aac_mount *) fib_data(fibptr);
+ dresp->mnt[0].capacityhigh = 0;
+ if ((le32_to_cpu(dresp->status) != ST_OK) ||
+ (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE))
+ return _aac_probe_container2(context, fibptr);
+ scsicmd = (struct scsi_cmnd *) context;
+ scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
- if (!(fibptr = aac_fib_alloc(dev)))
- return -ENOMEM;
+ if (!aac_valid_context(scsicmd, fibptr))
+ return 0;
aac_fib_init(fibptr);
dinfo = (struct aac_query_mount *)fib_data(fibptr);
- dinfo->command = cpu_to_le32(VM_NameServe);
- dinfo->count = cpu_to_le32(cid);
+ dinfo->command = cpu_to_le32(VM_NameServe64);
+ dinfo->count = cpu_to_le32(scmd_id(scsicmd));
dinfo->type = cpu_to_le32(FT_FILESYS);
status = aac_fib_send(ContainerCommand,
- fibptr,
- sizeof(struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL);
+ fibptr,
+ sizeof(struct aac_query_mount),
+ FsaNormal,
+ 0, 1,
+ (fib_callback) _aac_probe_container2,
+ (void *) scsicmd);
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
if (status < 0) {
- printk(KERN_WARNING "aacraid: aac_probe_container query failed.\n");
- goto error;
+ /* Inherit results from VM_NameServe, if any */
+ dresp->status = cpu_to_le32(ST_OK);
+ return _aac_probe_container2(context, fibptr);
}
+ return 0;
+}
- dresp = (struct aac_mount *) fib_data(fibptr);
+static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
+{
+ struct fib * fibptr;
+ int status = -ENOMEM;
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
- dinfo->command = cpu_to_le32(VM_NameServe64);
- dinfo->count = cpu_to_le32(cid);
- dinfo->type = cpu_to_le32(FT_FILESYS);
+ if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) {
+ struct aac_query_mount *dinfo;
- if (aac_fib_send(ContainerCommand,
- fibptr,
- sizeof(struct aac_query_mount),
- FsaNormal,
- 1, 1,
- NULL, NULL) < 0)
- goto error;
- } else
- dresp->mnt[0].capacityhigh = 0;
+ aac_fib_init(fibptr);
+
+ dinfo = (struct aac_query_mount *)fib_data(fibptr);
+
+ dinfo->command = cpu_to_le32(VM_NameServe);
+ dinfo->count = cpu_to_le32(scmd_id(scsicmd));
+ dinfo->type = cpu_to_le32(FT_FILESYS);
+ scsicmd->SCp.ptr = (char *)callback;
- if ((le32_to_cpu(dresp->status) == ST_OK) &&
- (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
- (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
- fsa_dev_ptr[cid].valid = 1;
- fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
- fsa_dev_ptr[cid].size
- = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
- (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
- if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
- fsa_dev_ptr[cid].ro = 1;
+ status = aac_fib_send(ContainerCommand,
+ fibptr,
+ sizeof(struct aac_query_mount),
+ FsaNormal,
+ 0, 1,
+ (fib_callback) _aac_probe_container1,
+ (void *) scsicmd);
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+ if (status < 0) {
+ scsicmd->SCp.ptr = NULL;
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ }
}
+ if (status < 0) {
+ struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+ if (fsa_dev_ptr) {
+ fsa_dev_ptr += scmd_id(scsicmd);
+ if ((fsa_dev_ptr->valid & 1) == 0) {
+ fsa_dev_ptr->valid = 0;
+ return (*callback)(scsicmd);
+ }
+ }
+ }
+ return status;
+}
-error:
- aac_fib_complete(fibptr);
- aac_fib_free(fibptr);
+/**
+ * aac_probe_container - query a logical volume
+ * @dev: device to query
+ * @cid: container identifier
+ *
+ * Queries the controller about the given volume. The volume information
+ * is updated in the struct fsa_dev_info structure rather than returned.
+ */
+static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd)
+{
+ scsicmd->device = NULL;
+ return 0;
+}
+
+int aac_probe_container(struct aac_dev *dev, int cid)
+{
+ struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL);
+ struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL);
+ int status;
+ if (!scsicmd || !scsidev) {
+ kfree(scsicmd);
+ kfree(scsidev);
+ return -ENOMEM;
+ }
+ scsicmd->list.next = NULL;
+ scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1;
+
+ scsicmd->device = scsidev;
+ scsidev->sdev_state = 0;
+ scsidev->id = cid;
+ scsidev->host = dev->scsi_host_ptr;
+
+ if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0)
+ while (scsicmd->device == scsidev)
+ schedule();
+ kfree(scsidev);
+ status = scsicmd->SCp.Status;
+ kfree(scsicmd);
return status;
}
@@ -1115,6 +1193,12 @@ int aac_get_adapter_info(struct aac_dev* dev)
printk(KERN_INFO "%s%d: serial %x\n",
dev->name, dev->id,
le32_to_cpu(dev->adapter_info.serial[0]));
+ if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
+ printk(KERN_INFO "%s%d: TSID %.*s\n",
+ dev->name, dev->id,
+ (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
+ dev->supplement_adapter_info.VpdInfo.Tsid);
+ }
}
dev->nondasd_support = 0;
@@ -1241,7 +1325,9 @@ static void io_callback(void *context, struct fib * fibptr)
u32 cid;
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
cid = scmd_id(scsicmd);
@@ -1317,7 +1403,7 @@ static void io_callback(void *context, struct fib * fibptr)
scsicmd->scsi_done(scsicmd);
}
-static int aac_read(struct scsi_cmnd * scsicmd, int cid)
+static int aac_read(struct scsi_cmnd * scsicmd)
{
u64 lba;
u32 count;
@@ -1331,7 +1417,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
*/
switch (scsicmd->cmnd[0]) {
case READ_6:
- dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd)));
lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
@@ -1341,7 +1427,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
count = 256;
break;
case READ_16:
- dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 56) |
((u64)scsicmd->cmnd[3] << 48) |
@@ -1355,7 +1441,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
break;
case READ_12:
- dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) |
(scsicmd->cmnd[3] << 16) |
@@ -1365,7 +1451,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
break;
default:
- dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) |
(scsicmd->cmnd[3] << 16) |
@@ -1405,7 +1491,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid)
return 0;
}
-static int aac_write(struct scsi_cmnd * scsicmd, int cid)
+static int aac_write(struct scsi_cmnd * scsicmd)
{
u64 lba;
u32 count;
@@ -1424,7 +1510,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
if (count == 0)
count = 256;
} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
- dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 56) |
((u64)scsicmd->cmnd[3] << 48) |
@@ -1436,14 +1522,14 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid)
count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
- dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
| (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
| (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
} else {
- dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
+ dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
}
@@ -1488,7 +1574,9 @@ static void synchronize_callback(void *context, struct fib *fibptr)
struct scsi_cmnd *cmd;
cmd = context;
- cmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(cmd, fibptr))
+ return;
dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
smp_processor_id(), jiffies));
@@ -1523,7 +1611,7 @@ static void synchronize_callback(void *context, struct fib *fibptr)
cmd->scsi_done(cmd);
}
-static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+static int aac_synchronize(struct scsi_cmnd *scsicmd)
{
int status;
struct fib *cmd_fibcontext;
@@ -1568,7 +1656,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
synchronizecmd = fib_data(cmd_fibcontext);
synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
- synchronizecmd->cid = cpu_to_le32(cid);
+ synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
synchronizecmd->count =
cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
@@ -1646,29 +1734,12 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case TEST_UNIT_READY:
if (dev->in_reset)
return -1;
- spin_unlock_irq(host->host_lock);
- aac_probe_container(dev, cid);
- if ((fsa_dev_ptr[cid].valid & 1) == 0)
- fsa_dev_ptr[cid].valid = 0;
- spin_lock_irq(host->host_lock);
- if (fsa_dev_ptr[cid].valid == 0) {
- scsicmd->result = DID_NO_CONNECT << 16;
- scsicmd->scsi_done(scsicmd);
- return 0;
- }
+ return _aac_probe_container(scsicmd,
+ aac_probe_container_callback2);
default:
break;
}
}
- /*
- * If the target container still doesn't exist,
- * return failure
- */
- if (fsa_dev_ptr[cid].valid == 0) {
- scsicmd->result = DID_BAD_TARGET << 16;
- scsicmd->scsi_done(scsicmd);
- return 0;
- }
} else { /* check for physical non-dasd devices */
if ((dev->nondasd_support == 1) || expose_physicals) {
if (dev->in_reset)
@@ -1733,7 +1804,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
- return aac_get_container_name(scsicmd, cid);
+ return aac_get_container_name(scsicmd);
}
case SERVICE_ACTION_IN:
if (!(dev->raw_io_interface) ||
@@ -1899,7 +1970,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
min(sizeof(fsa_dev_ptr[cid].devname),
sizeof(scsicmd->request->rq_disk->disk_name) + 1));
- return aac_read(scsicmd, cid);
+ return aac_read(scsicmd);
case WRITE_6:
case WRITE_10:
@@ -1907,11 +1978,11 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case WRITE_16:
if (dev->in_reset)
return -1;
- return aac_write(scsicmd, cid);
+ return aac_write(scsicmd);
case SYNCHRONIZE_CACHE:
/* Issue FIB to tell Firmware to flush it's cache */
- return aac_synchronize(scsicmd, cid);
+ return aac_synchronize(scsicmd);
default:
/*
@@ -2058,7 +2129,10 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
struct scsi_cmnd *scsicmd;
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
BUG_ON(fibptr == NULL);
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 39ecd0d22eb..45ca3e80161 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,8 +12,8 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2423
-# define AAC_DRIVER_BRANCH "-mh3"
+# define AAC_DRIVER_BUILD 2437
+# define AAC_DRIVER_BRANCH "-mh4"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -48,49 +48,13 @@ struct diskparm
/*
- * DON'T CHANGE THE ORDER, this is set by the firmware
+ * Firmware constants
*/
#define CT_NONE 0
-#define CT_VOLUME 1
-#define CT_MIRROR 2
-#define CT_STRIPE 3
-#define CT_RAID5 4
-#define CT_SSRW 5
-#define CT_SSRO 6
-#define CT_MORPH 7
-#define CT_PASSTHRU 8
-#define CT_RAID4 9
-#define CT_RAID10 10 /* stripe of mirror */
-#define CT_RAID00 11 /* stripe of stripe */
-#define CT_VOLUME_OF_MIRRORS 12 /* volume of mirror */
-#define CT_PSEUDO_RAID 13 /* really raid4 */
-#define CT_LAST_VOLUME_TYPE 14
#define CT_OK 218
-
-/*
- * Types of objects addressable in some fashion by the client.
- * This is a superset of those objects handled just by the filesystem
- * and includes "raw" objects that an administrator would use to
- * configure containers and filesystems.
- */
-
-#define FT_REG 1 /* regular file */
-#define FT_DIR 2 /* directory */
-#define FT_BLK 3 /* "block" device - reserved */
-#define FT_CHR 4 /* "character special" device - reserved */
-#define FT_LNK 5 /* symbolic link */
-#define FT_SOCK 6 /* socket */
-#define FT_FIFO 7 /* fifo */
#define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */
#define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/id/lun */
-#define FT_SLICE 10 /* virtual disk - raw volume - slice */
-#define FT_PARTITION 11 /* FSA partition - carved out of a slice - building block for containers */
-#define FT_VOLUME 12 /* Container - Volume Set */
-#define FT_STRIPE 13 /* Container - Stripe Set */
-#define FT_MIRROR 14 /* Container - Mirror Set */
-#define FT_RAID5 15 /* Container - Raid 5 Set */
-#define FT_DATABASE 16 /* Storage object with "foreign" content manager */
/*
* Host side memory scatter gather list
@@ -497,6 +461,7 @@ struct adapter_ops
void (*adapter_enable_int)(struct aac_dev *dev);
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
+ int (*adapter_restart)(struct aac_dev *dev, int bled);
/* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
irqreturn_t (*adapter_intr)(int irq, void *dev_id);
@@ -833,7 +798,7 @@ struct fib {
*/
struct list_head fiblink;
void *data;
- struct hw_fib *hw_fib; /* Actual shared object */
+ struct hw_fib *hw_fib_va; /* Actual shared object */
dma_addr_t hw_fib_pa; /* physical address of hw_fib*/
};
@@ -878,10 +843,25 @@ struct aac_supplement_adapter_info
__le32 Version;
__le32 FeatureBits;
u8 SlotNumber;
- u8 ReservedPad0[0];
+ u8 ReservedPad0[3];
u8 BuildDate[12];
__le32 CurrentNumberPorts;
- __le32 ReservedGrowth[24];
+ struct {
+ u8 AssemblyPn[8];
+ u8 FruPn[8];
+ u8 BatteryFruPn[8];
+ u8 EcVersionString[8];
+ u8 Tsid[12];
+ } VpdInfo;
+ __le32 FlashFirmwareRevision;
+ __le32 FlashFirmwareBuild;
+ __le32 RaidTypeMorphOptions;
+ __le32 FlashFirmwareBootRevision;
+ __le32 FlashFirmwareBootBuild;
+ u8 MfgPcbaSerialNo[12];
+ u8 MfgWWNName[8];
+ __le32 MoreFeatureBits;
+ __le32 ReservedGrowth[1];
};
#define AAC_FEATURE_FALCON 0x00000010
#define AAC_SIS_VERSION_V3 3
@@ -970,7 +950,6 @@ struct aac_dev
struct fib *fibs;
struct fib *free_fib;
- struct fib *timeout_fib;
spinlock_t fib_lock;
struct aac_queue_block *queues;
@@ -1060,6 +1039,9 @@ struct aac_dev
#define aac_adapter_check_health(dev) \
(dev)->a_ops.adapter_check_health(dev)
+#define aac_adapter_restart(dev,bled) \
+ (dev)->a_ops.adapter_restart(dev,bled)
+
#define aac_adapter_ioremap(dev, size) \
(dev)->a_ops.adapter_ioremap(dev, size)
@@ -1516,8 +1498,7 @@ struct aac_mntent {
struct creation_info create_info; /* if applicable */
__le32 capacity;
__le32 vol; /* substrate structure */
- __le32 obj; /* FT_FILESYS,
- FT_DATABASE, etc. */
+ __le32 obj; /* FT_FILESYS, etc. */
__le32 state; /* unready for mounting,
readonly, etc. */
union aac_contentinfo fileinfo; /* Info specific to content
@@ -1817,7 +1798,7 @@ int aac_fib_send(u16 command, struct fib * context, unsigned long size, int prio
int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context);
-#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
+#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev);
int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
@@ -1840,8 +1821,11 @@ struct aac_driver_ident* aac_get_driver_ident(int devtype);
int aac_get_adapter_info(struct aac_dev* dev);
int aac_send_shutdown(struct aac_dev *dev);
int aac_probe_container(struct aac_dev *dev, int cid);
+int _aac_rx_init(struct aac_dev *dev);
+int aac_rx_select_comm(struct aac_dev *dev, int comm);
extern int numacb;
extern int acbsize;
extern char aac_driver_version[];
extern int startup_timeout;
extern int aif_timeout;
+extern int expose_physicals;
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index e21070f4eac..72b0393b459 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -64,12 +64,15 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
unsigned size;
int retval;
+ if (dev->in_reset) {
+ return -EBUSY;
+ }
fibptr = aac_fib_alloc(dev);
if(fibptr == NULL) {
return -ENOMEM;
}
- kfib = fibptr->hw_fib;
+ kfib = fibptr->hw_fib_va;
/*
* First copy in the header so that we can check the size field.
*/
@@ -91,9 +94,9 @@ static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
goto cleanup;
}
/* Highjack the hw_fib */
- hw_fib = fibptr->hw_fib;
+ hw_fib = fibptr->hw_fib_va;
hw_fib_pa = fibptr->hw_fib_pa;
- fibptr->hw_fib = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
+ fibptr->hw_fib_va = kfib = pci_alloc_consistent(dev->pdev, size, &fibptr->hw_fib_pa);
memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size);
memcpy(kfib, hw_fib, dev->max_fib_size);
}
@@ -137,7 +140,7 @@ cleanup:
if (hw_fib) {
pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa);
fibptr->hw_fib_pa = hw_fib_pa;
- fibptr->hw_fib = hw_fib;
+ fibptr->hw_fib_va = hw_fib;
}
if (retval != -EINTR)
aac_fib_free(fibptr);
@@ -282,15 +285,15 @@ return_fib:
fib = list_entry(entry, struct fib, fiblink);
fibctx->count--;
spin_unlock_irqrestore(&dev->fib_lock, flags);
- if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
- kfree(fib->hw_fib);
+ if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) {
+ kfree(fib->hw_fib_va);
kfree(fib);
return -EFAULT;
}
/*
* Free the space occupied by this copy of the fib.
*/
- kfree(fib->hw_fib);
+ kfree(fib->hw_fib_va);
kfree(fib);
status = 0;
} else {
@@ -340,7 +343,7 @@ int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
/*
* Free the space occupied by this copy of the fib.
*/
- kfree(fib->hw_fib);
+ kfree(fib->hw_fib_va);
kfree(fib);
}
/*
@@ -388,10 +391,8 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
/*
* Extract the fibctx from the input parameters
*/
- if (fibctx->unique == (u32)(unsigned long)arg) {
- /* We found a winner */
+ if (fibctx->unique == (u32)(ptrdiff_t)arg) /* We found a winner */
break;
- }
entry = entry->next;
fibctx = NULL;
}
@@ -465,16 +466,20 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
void *sg_list[32];
u32 sg_indx = 0;
u32 byte_count = 0;
- u32 actual_fibsize = 0;
+ u32 actual_fibsize64, actual_fibsize = 0;
int i;
+ if (dev->in_reset) {
+ dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n"));
+ return -EBUSY;
+ }
if (!capable(CAP_SYS_ADMIN)){
dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n"));
return -EPERM;
}
/*
- * Allocate and initialize a Fib then setup a BlockWrite command
+ * Allocate and initialize a Fib then setup a SRB command
*/
if (!(srbfib = aac_fib_alloc(dev))) {
return -ENOMEM;
@@ -541,129 +546,183 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
rcode = -EINVAL;
goto cleanup;
}
- if (dev->dac_support == 1) {
+ actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) +
+ ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry));
+ actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) *
+ (sizeof(struct sgentry64) - sizeof(struct sgentry));
+ /* User made a mistake - should not continue */
+ if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) {
+ dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
+ "Raw SRB command calculated fibsize=%lu;%lu "
+ "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu "
+ "issued fibsize=%d\n",
+ actual_fibsize, actual_fibsize64, user_srbcmd->sg.count,
+ sizeof(struct aac_srb), sizeof(struct sgentry),
+ sizeof(struct sgentry64), fibsize));
+ rcode = -EINVAL;
+ goto cleanup;
+ }
+ if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) {
+ dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
+ rcode = -EINVAL;
+ goto cleanup;
+ }
+ byte_count = 0;
+ if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) {
struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg;
struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
- struct user_sgmap* usg;
- byte_count = 0;
/*
* This should also catch if user used the 32 bit sgmap
*/
- actual_fibsize = sizeof(struct aac_srb) -
- sizeof(struct sgentry) +
- ((upsg->count & 0xff) *
- sizeof(struct sgentry));
- if(actual_fibsize != fibsize){ // User made a mistake - should not continue
- dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
- rcode = -EINVAL;
- goto cleanup;
- }
- usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
- + sizeof(struct sgmap), GFP_KERNEL);
- if (!usg) {
- dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
- rcode = -ENOMEM;
- goto cleanup;
- }
- memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
- + sizeof(struct sgmap));
- actual_fibsize = sizeof(struct aac_srb) -
- sizeof(struct sgentry) + ((usg->count & 0xff) *
- sizeof(struct sgentry64));
- if ((data_dir == DMA_NONE) && upsg->count) {
- kfree (usg);
- dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
- rcode = -EINVAL;
- goto cleanup;
- }
+ if (actual_fibsize64 == fibsize) {
+ actual_fibsize = actual_fibsize64;
+ for (i = 0; i < upsg->count; i++) {
+ u64 addr;
+ void* p;
+ /* Does this really need to be GFP_DMA? */
+ p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+ if(p == 0) {
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ upsg->sg[i].count,i,upsg->count));
+ rcode = -ENOMEM;
+ goto cleanup;
+ }
+ addr = (u64)upsg->sg[i].addr[0];
+ addr += ((u64)upsg->sg[i].addr[1]) << 32;
+ sg_user[i] = (void __user *)(ptrdiff_t)addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir);
- for (i = 0; i < usg->count; i++) {
- u64 addr;
- void* p;
- /* Does this really need to be GFP_DMA? */
- p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
- if(p == 0) {
- kfree (usg);
- dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- usg->sg[i].count,i,usg->count));
+ psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+ psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+ byte_count += upsg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+ }
+ } else {
+ struct user_sgmap* usg;
+ usg = kmalloc(actual_fibsize - sizeof(struct aac_srb)
+ + sizeof(struct sgmap), GFP_KERNEL);
+ if (!usg) {
+ dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n"));
rcode = -ENOMEM;
goto cleanup;
}
- sg_user[i] = (void __user *)(long)usg->sg[i].addr;
- sg_list[i] = p; // save so we can clean up later
- sg_indx = i;
-
- if( flags & SRB_DataOut ){
- if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb)
+ + sizeof(struct sgmap));
+ actual_fibsize = actual_fibsize64;
+
+ for (i = 0; i < usg->count; i++) {
+ u64 addr;
+ void* p;
+ /* Does this really need to be GFP_DMA? */
+ p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+ if(p == 0) {
kfree (usg);
- dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
- rcode = -EFAULT;
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ usg->sg[i].count,i,usg->count));
+ rcode = -ENOMEM;
goto cleanup;
}
- }
- addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+ sg_user[i] = (void __user *)(ptrdiff_t)usg->sg[i].addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){
+ kfree (usg);
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
- psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
- psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
- psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
- byte_count += usg->sg[i].count;
+ psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
+ psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
+ byte_count += usg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
+ }
+ kfree (usg);
}
- kfree (usg);
-
srbcmd->count = cpu_to_le32(byte_count);
psg->count = cpu_to_le32(sg_indx+1);
status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
} else {
struct user_sgmap* upsg = &user_srbcmd->sg;
struct sgmap* psg = &srbcmd->sg;
- byte_count = 0;
-
- actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
- if(actual_fibsize != fibsize){ // User made a mistake - should not continue
- dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
- "Raw SRB command calculated fibsize=%d "
- "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
- "issued fibsize=%d\n",
- actual_fibsize, user_srbcmd->sg.count,
- sizeof(struct aac_srb), sizeof(struct sgentry),
- fibsize));
- rcode = -EINVAL;
- goto cleanup;
- }
- if ((data_dir == DMA_NONE) && upsg->count) {
- dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n"));
- rcode = -EINVAL;
- goto cleanup;
- }
- for (i = 0; i < upsg->count; i++) {
- dma_addr_t addr;
- void* p;
- p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
- if(p == 0) {
- dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
- upsg->sg[i].count, i, upsg->count));
- rcode = -ENOMEM;
- goto cleanup;
- }
- sg_user[i] = (void __user *)(long)upsg->sg[i].addr;
- sg_list[i] = p; // save so we can clean up later
- sg_indx = i;
-
- if( flags & SRB_DataOut ){
- if(copy_from_user(p, sg_user[i],
- upsg->sg[i].count)) {
- dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
- rcode = -EFAULT;
+
+ if (actual_fibsize64 == fibsize) {
+ struct user_sgmap64* usg = (struct user_sgmap64 *)upsg;
+ for (i = 0; i < upsg->count; i++) {
+ u64 addr;
+ void* p;
+ /* Does this really need to be GFP_DMA? */
+ p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+ if(p == 0) {
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ usg->sg[i].count,i,usg->count));
+ rcode = -ENOMEM;
goto cleanup;
}
+ addr = (u64)usg->sg[i].addr[0];
+ addr += ((u64)usg->sg[i].addr[1]) << 32;
+ sg_user[i] = (void __user *)(ptrdiff_t)addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p,sg_user[i],usg->sg[i].count)){
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir);
+
+ psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff);
+ byte_count += usg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(usg->sg[i].count);
}
- addr = pci_map_single(dev->pdev, p,
- upsg->sg[i].count, data_dir);
+ } else {
+ for (i = 0; i < upsg->count; i++) {
+ dma_addr_t addr;
+ void* p;
+ p = kmalloc(upsg->sg[i].count, GFP_KERNEL);
+ if(p == 0) {
+ dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+ upsg->sg[i].count, i, upsg->count));
+ rcode = -ENOMEM;
+ goto cleanup;
+ }
+ sg_user[i] = (void __user *)(ptrdiff_t)upsg->sg[i].addr;
+ sg_list[i] = p; // save so we can clean up later
+ sg_indx = i;
+
+ if( flags & SRB_DataOut ){
+ if(copy_from_user(p, sg_user[i],
+ upsg->sg[i].count)) {
+ dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n"));
+ rcode = -EFAULT;
+ goto cleanup;
+ }
+ }
+ addr = pci_map_single(dev->pdev, p,
+ upsg->sg[i].count, data_dir);
- psg->sg[i].addr = cpu_to_le32(addr);
- psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
- byte_count += upsg->sg[i].count;
+ psg->sg[i].addr = cpu_to_le32(addr);
+ byte_count += upsg->sg[i].count;
+ psg->sg[i].count = cpu_to_le32(upsg->sg[i].count);
+ }
}
srbcmd->count = cpu_to_le32(byte_count);
psg->count = cpu_to_le32(sg_indx+1);
@@ -682,7 +741,8 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
if( flags & SRB_DataIn ) {
for(i = 0 ; i <= sg_indx; i++){
- byte_count = le32_to_cpu((dev->dac_support == 1)
+ byte_count = le32_to_cpu(
+ (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)
? ((struct sgmap64*)&srbcmd->sg)->sg[i].count
: srbcmd->sg.sg[i].count);
if(copy_to_user(sg_user[i], sg_list[i], byte_count)){
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index ae34768987a..3009ad8c407 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -110,7 +110,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
/*
* Align the beginning of Headers to commalign
*/
- align = (commalign - ((unsigned long)(base) & (commalign - 1)));
+ align = (commalign - ((ptrdiff_t)(base) & (commalign - 1)));
base = base + align;
phys = phys + align;
/*
@@ -387,12 +387,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
* Ok now init the communication subsystem
*/
- dev->queues = kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+ dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
if (dev->queues == NULL) {
printk(KERN_ERR "Error could not allocate comm region.\n");
return NULL;
}
- memset(dev->queues, 0, sizeof(struct aac_queue_block));
if (aac_comm_init(dev)<0){
kfree(dev->queues);
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 1b97f60652b..9aca57eda94 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -94,7 +94,7 @@ void aac_fib_map_free(struct aac_dev *dev)
int aac_fib_setup(struct aac_dev * dev)
{
struct fib *fibptr;
- struct hw_fib *hw_fib_va;
+ struct hw_fib *hw_fib;
dma_addr_t hw_fib_pa;
int i;
@@ -106,24 +106,24 @@ int aac_fib_setup(struct aac_dev * dev)
if (i<0)
return -ENOMEM;
- hw_fib_va = dev->hw_fib_va;
+ hw_fib = dev->hw_fib_va;
hw_fib_pa = dev->hw_fib_pa;
- memset(hw_fib_va, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
+ memset(hw_fib, 0, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB));
/*
* Initialise the fibs
*/
for (i = 0, fibptr = &dev->fibs[i]; i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); i++, fibptr++)
{
fibptr->dev = dev;
- fibptr->hw_fib = hw_fib_va;
- fibptr->data = (void *) fibptr->hw_fib->data;
+ fibptr->hw_fib_va = hw_fib;
+ fibptr->data = (void *) fibptr->hw_fib_va->data;
fibptr->next = fibptr+1; /* Forward chain the fibs */
init_MUTEX_LOCKED(&fibptr->event_wait);
spin_lock_init(&fibptr->event_lock);
- hw_fib_va->header.XferState = cpu_to_le32(0xffffffff);
- hw_fib_va->header.SenderSize = cpu_to_le16(dev->max_fib_size);
+ hw_fib->header.XferState = cpu_to_le32(0xffffffff);
+ hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size);
fibptr->hw_fib_pa = hw_fib_pa;
- hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + dev->max_fib_size);
+ hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + dev->max_fib_size);
hw_fib_pa = hw_fib_pa + dev->max_fib_size;
}
/*
@@ -166,7 +166,7 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
* Null out fields that depend on being zero at the start of
* each I/O
*/
- fibptr->hw_fib->header.XferState = 0;
+ fibptr->hw_fib_va->header.XferState = 0;
fibptr->callback = NULL;
fibptr->callback_data = NULL;
@@ -178,7 +178,6 @@ struct fib *aac_fib_alloc(struct aac_dev *dev)
* @fibptr: fib to free up
*
* Frees up a fib and places it on the appropriate queue
- * (either free or timed out)
*/
void aac_fib_free(struct fib *fibptr)
@@ -186,19 +185,15 @@ void aac_fib_free(struct fib *fibptr)
unsigned long flags;
spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
- if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+ if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
aac_config.fib_timeouts++;
- fibptr->next = fibptr->dev->timeout_fib;
- fibptr->dev->timeout_fib = fibptr;
- } else {
- if (fibptr->hw_fib->header.XferState != 0) {
- printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
- (void*)fibptr,
- le32_to_cpu(fibptr->hw_fib->header.XferState));
- }
- fibptr->next = fibptr->dev->free_fib;
- fibptr->dev->free_fib = fibptr;
- }
+ if (fibptr->hw_fib_va->header.XferState != 0) {
+ printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n",
+ (void*)fibptr,
+ le32_to_cpu(fibptr->hw_fib_va->header.XferState));
+ }
+ fibptr->next = fibptr->dev->free_fib;
+ fibptr->dev->free_fib = fibptr;
spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags);
}
@@ -211,7 +206,7 @@ void aac_fib_free(struct fib *fibptr)
void aac_fib_init(struct fib *fibptr)
{
- struct hw_fib *hw_fib = fibptr->hw_fib;
+ struct hw_fib *hw_fib = fibptr->hw_fib_va;
hw_fib->header.StructType = FIB_MAGIC;
hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size);
@@ -231,7 +226,7 @@ void aac_fib_init(struct fib *fibptr)
static void fib_dealloc(struct fib * fibptr)
{
- struct hw_fib *hw_fib = fibptr->hw_fib;
+ struct hw_fib *hw_fib = fibptr->hw_fib_va;
BUG_ON(hw_fib->header.StructType != FIB_MAGIC);
hw_fib->header.XferState = 0;
}
@@ -386,7 +381,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
void *callback_data)
{
struct aac_dev * dev = fibptr->dev;
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
unsigned long flags = 0;
unsigned long qflags;
@@ -430,7 +425,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
*/
hw_fib->header.Command = cpu_to_le16(command);
hw_fib->header.XferState |= cpu_to_le32(SentFromHost);
- fibptr->hw_fib->header.Flags = 0; /* 0 the flags field - internal only*/
+ fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/
/*
* Set the size of the Fib we want to send to the adapter
*/
@@ -462,7 +457,7 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
dprintk((KERN_DEBUG " Command = %d.\n", le32_to_cpu(hw_fib->header.Command)));
dprintk((KERN_DEBUG " SubCommand = %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command)));
dprintk((KERN_DEBUG " XferState = %x.\n", le32_to_cpu(hw_fib->header.XferState)));
- dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib));
+ dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib_va));
dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr));
@@ -513,22 +508,20 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
- } else if (down_interruptible(&fibptr->event_wait)) {
- spin_lock_irqsave(&fibptr->event_lock, flags);
- if (fibptr->done == 0) {
- fibptr->done = 2; /* Tell interrupt we aborted */
- spin_unlock_irqrestore(&fibptr->event_lock, flags);
- return -EINTR;
- }
+ } else
+ (void)down_interruptible(&fibptr->event_wait);
+ spin_lock_irqsave(&fibptr->event_lock, flags);
+ if (fibptr->done == 0) {
+ fibptr->done = 2; /* Tell interrupt we aborted */
spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ return -EINTR;
}
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
BUG_ON(fibptr->done == 0);
- if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
+ if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
return -ETIMEDOUT;
- } else {
- return 0;
- }
+ return 0;
}
/*
* If the user does not want a response than return success otherwise
@@ -624,7 +617,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
{
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
struct aac_dev * dev = fibptr->dev;
struct aac_queue * q;
unsigned long nointr = 0;
@@ -688,7 +681,7 @@ int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size)
int aac_fib_complete(struct fib *fibptr)
{
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
/*
* Check for a fib which has already been completed
@@ -774,9 +767,8 @@ void aac_printf(struct aac_dev *dev, u32 val)
#define AIF_SNIFF_TIMEOUT (30*HZ)
static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
{
- struct hw_fib * hw_fib = fibptr->hw_fib;
+ struct hw_fib * hw_fib = fibptr->hw_fib_va;
struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
- int busy;
u32 container;
struct scsi_device *device;
enum {
@@ -988,9 +980,6 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
* behind you.
*/
- busy = 0;
-
-
/*
* Find the scsi_device associated with the SCSI address,
* and mark it as changed, invalidating the cache. This deals
@@ -1035,7 +1024,6 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
static int _aac_reset_adapter(struct aac_dev *aac)
{
int index, quirks;
- u32 ret;
int retval;
struct Scsi_Host *host;
struct scsi_device *dev;
@@ -1059,35 +1047,29 @@ static int _aac_reset_adapter(struct aac_dev *aac)
* If a positive health, means in a known DEAD PANIC
* state and the adapter could be reset to `try again'.
*/
- retval = aac_adapter_check_health(aac);
- if (retval == 0)
- retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS,
- 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
- if (retval)
- retval = aac_adapter_sync_cmd(aac, IOP_RESET,
- 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+ retval = aac_adapter_restart(aac, aac_adapter_check_health(aac));
if (retval)
goto out;
- if (ret != 0x00000001) {
- retval = -ENODEV;
- goto out;
- }
/*
* Loop through the fibs, close the synchronous FIBS
*/
- for (index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
+ for (retval = 1, index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) {
struct fib *fib = &aac->fibs[index];
- if (!(fib->hw_fib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
- (fib->hw_fib->header.XferState & cpu_to_le32(ResponseExpected))) {
+ if (!(fib->hw_fib_va->header.XferState & cpu_to_le32(NoResponseExpected | Async)) &&
+ (fib->hw_fib_va->header.XferState & cpu_to_le32(ResponseExpected))) {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
schedule();
+ retval = 0;
}
}
+ /* Give some extra time for ioctls to complete. */
+ if (retval == 0)
+ ssleep(2);
index = aac->cardtype;
/*
@@ -1241,14 +1223,12 @@ int aac_check_health(struct aac_dev * aac)
* Warning: no sleep allowed while
* holding spinlock
*/
- hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
- fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+ hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+ fib = kzalloc(sizeof(struct fib), GFP_ATOMIC);
if (fib && hw_fib) {
struct aac_aifcmd * aif;
- memset(hw_fib, 0, sizeof(struct hw_fib));
- memset(fib, 0, sizeof(struct fib));
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->dev = aac;
aac_fib_init(fib);
fib->type = FSAFS_NTC_FIB_CONTEXT;
@@ -1354,11 +1334,11 @@ int aac_command_thread(void *data)
* do anything at this point since we don't have
* anything defined for this thread to do.
*/
- hw_fib = fib->hw_fib;
+ hw_fib = fib->hw_fib_va;
memset(fib, 0, sizeof(struct fib));
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof( struct fib );
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
/*
@@ -1485,7 +1465,7 @@ int aac_command_thread(void *data)
*/
memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
memcpy(newfib, fib, sizeof(struct fib));
- newfib->hw_fib = hw_newfib;
+ newfib->hw_fib_va = hw_newfib;
/*
* Put the FIB onto the
* fibctx's fibs
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index d38b628be1a..fcd25f7d0bc 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -32,7 +32,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/completion.h>
@@ -73,7 +72,7 @@ unsigned int aac_response_normal(struct aac_queue * q)
u32 index = le32_to_cpu(entry->addr);
fast = index & 0x01;
fib = &dev->fibs[index >> 2];
- hwfib = fib->hw_fib;
+ hwfib = fib->hw_fib_va;
aac_consumer_free(dev, q, HostNormRespQueue);
/*
@@ -84,11 +83,13 @@ unsigned int aac_response_normal(struct aac_queue * q)
* continue. The caller has already been notified that
* the fib timed out.
*/
- if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
- dev->queues->queue[AdapNormCmdQueue].numpending--;
- else {
- printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
- printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+ dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+ if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+ spin_unlock_irqrestore(q->lock, flags);
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ spin_lock_irqsave(q->lock, flags);
continue;
}
spin_unlock_irqrestore(q->lock, flags);
@@ -193,7 +194,7 @@ unsigned int aac_command_normal(struct aac_queue *q)
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof(struct fib);
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
@@ -247,19 +248,18 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
* manage the linked lists.
*/
if ((!dev->aif_thread)
- || (!(fib = kmalloc(sizeof(struct fib),GFP_ATOMIC))))
+ || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC))))
return 1;
- if (!(hw_fib = kmalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
+ if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) {
kfree (fib);
return 1;
}
- memset(hw_fib, 0, sizeof(struct hw_fib));
- memcpy(hw_fib, (struct hw_fib *)(((unsigned long)(dev->regs.sa)) + (index & ~0x00000002L)), sizeof(struct hw_fib));
- memset(fib, 0, sizeof(struct fib));
+ memcpy(hw_fib, (struct hw_fib *)(((ptrdiff_t)(dev->regs.sa)) +
+ (index & ~0x00000002L)), sizeof(struct hw_fib));
INIT_LIST_HEAD(&fib->fiblink);
fib->type = FSAFS_NTC_FIB_CONTEXT;
fib->size = sizeof(struct fib);
- fib->hw_fib = hw_fib;
+ fib->hw_fib_va = hw_fib;
fib->data = hw_fib->data;
fib->dev = dev;
@@ -271,7 +271,7 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
} else {
int fast = index & 0x01;
struct fib * fib = &dev->fibs[index >> 2];
- struct hw_fib * hwfib = fib->hw_fib;
+ struct hw_fib * hwfib = fib->hw_fib_va;
/*
* Remove this fib from the Outstanding I/O queue.
@@ -281,14 +281,14 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
* continue. The caller has already been notified that
* the fib timed out.
*/
- if ((fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
- printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
- printk(KERN_DEBUG"aacraid: hwfib=%p index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+ dev->queues->queue[AdapNormCmdQueue].numpending--;
+
+ if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
return 0;
}
- dev->queues->queue[AdapNormCmdQueue].numpending--;
-
if (fast) {
/*
* Doctor the fib
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 0f948c2fb60..350ea7feb61 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -82,8 +82,6 @@ static LIST_HEAD(aac_devices);
static int aac_cfg_major = -1;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
-extern int expose_physicals;
-
/*
* Because of the way Linux names scsi devices, the order in this table has
* become important. Check for on-board Raid first, add-in cards second.
@@ -247,7 +245,19 @@ static struct aac_driver_ident aac_drivers[] = {
static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
+ struct Scsi_Host *host = cmd->device->host;
+ struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+ u32 count = 0;
cmd->scsi_done = done;
+ for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ struct fib * fib = &dev->fibs[count];
+ struct scsi_cmnd * command;
+ if (fib->hw_fib_va->header.XferState &&
+ ((command = fib->callback_data)) &&
+ (command == cmd) &&
+ (cmd->SCp.phase == AAC_OWNER_FIRMWARE))
+ return 0; /* Already owned by Adapter */
+ }
cmd->SCp.phase = AAC_OWNER_LOWLEVEL;
return (aac_scsi_cmd(cmd) ? FAILED : 0);
}
@@ -446,6 +456,40 @@ static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
return aac_do_ioctl(dev, cmd, arg);
}
+static int aac_eh_abort(struct scsi_cmnd* cmd)
+{
+ struct scsi_device * dev = cmd->device;
+ struct Scsi_Host * host = dev->host;
+ struct aac_dev * aac = (struct aac_dev *)host->hostdata;
+ int count;
+ int ret = FAILED;
+
+ printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n",
+ AAC_DRIVERNAME,
+ host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun);
+ switch (cmd->cmnd[0]) {
+ case SERVICE_ACTION_IN:
+ if (!(aac->raw_io_interface) ||
+ !(aac->raw_io_64) ||
+ ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+ break;
+ case INQUIRY:
+ case READ_CAPACITY:
+ case TEST_UNIT_READY:
+ /* Mark associated FIB to not complete, eh handler does this */
+ for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ struct fib * fib = &aac->fibs[count];
+ if (fib->hw_fib_va->header.XferState &&
+ (fib->callback_data == cmd)) {
+ fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+ cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ ret = SUCCESS;
+ }
+ }
+ }
+ return ret;
+}
+
/*
* aac_eh_reset - Reset command handling
* @scsi_cmd: SCSI command block causing the reset
@@ -457,12 +501,20 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
struct Scsi_Host * host = dev->host;
struct scsi_cmnd * command;
int count;
- struct aac_dev * aac;
+ struct aac_dev * aac = (struct aac_dev *)host->hostdata;
unsigned long flags;
+ /* Mark the associated FIB to not complete, eh handler does this */
+ for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) {
+ struct fib * fib = &aac->fibs[count];
+ if (fib->hw_fib_va->header.XferState &&
+ (fib->callback_data == cmd)) {
+ fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT;
+ cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ }
+ }
printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
AAC_DRIVERNAME);
- aac = (struct aac_dev *)host->hostdata;
if ((count = aac_check_health(aac)))
return count;
@@ -496,7 +548,7 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
ssleep(1);
}
printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
- return -ETIMEDOUT;
+ return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
}
/**
@@ -796,6 +848,7 @@ static struct scsi_host_template aac_driver_template = {
.bios_param = aac_biosparm,
.shost_attrs = aac_attrs,
.slave_configure = aac_slave_configure,
+ .eh_abort_handler = aac_eh_abort,
.eh_host_reset_handler = aac_eh_reset,
.can_queue = AAC_NUM_IO_FIB,
.this_id = MAXIMUM_NUM_CONTAINERS,
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
index c76b611b6af..a8ace567781 100644
--- a/drivers/scsi/aacraid/nark.c
+++ b/drivers/scsi/aacraid/nark.c
@@ -74,9 +74,6 @@ static int aac_nark_ioremap(struct aac_dev * dev, u32 size)
int aac_nark_init(struct aac_dev * dev)
{
- extern int _aac_rx_init(struct aac_dev *dev);
- extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
-
/*
* Fill in the function dispatch table.
*/
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index d953c3fe998..9c5fcfb398c 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -45,7 +45,6 @@
static int aac_rkt_select_comm(struct aac_dev *dev, int comm)
{
int retval;
- extern int aac_rx_select_comm(struct aac_dev *dev, int comm);
retval = aac_rx_select_comm(dev, comm);
if (comm == AAC_COMM_MESSAGE) {
/*
@@ -97,8 +96,6 @@ static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
int aac_rkt_init(struct aac_dev *dev)
{
- extern int _aac_rx_init(struct aac_dev *dev);
-
/*
* Fill in the function dispatch table.
*/
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index d242e2611d6..291cd14f4e9 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -5,7 +5,7 @@
* based on the old aacraid driver that is..
* Adaptec aacraid device driver for Linux.
*
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
@@ -57,25 +57,25 @@ static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id)
* been enabled.
* Check to see if this is our interrupt. If it isn't just return
*/
- if (intstat & ~(dev->OIMR)) {
+ if (likely(intstat & ~(dev->OIMR))) {
bellbits = rx_readl(dev, OutboundDoorbellReg);
- if (bellbits & DoorBellPrintfReady) {
+ if (unlikely(bellbits & DoorBellPrintfReady)) {
aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
}
- else if (bellbits & DoorBellAdapterNormCmdReady) {
+ else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
}
- else if (bellbits & DoorBellAdapterNormRespReady) {
+ else if (likely(bellbits & DoorBellAdapterNormRespReady)) {
rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
}
- else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+ else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
}
- else if (bellbits & DoorBellAdapterNormRespNotFull) {
+ else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) {
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
}
@@ -88,11 +88,11 @@ static irqreturn_t aac_rx_intr_message(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
u32 Index = rx_readl(dev, MUnit.OutboundQueue);
- if (Index == 0xFFFFFFFFL)
+ if (unlikely(Index == 0xFFFFFFFFL))
Index = rx_readl(dev, MUnit.OutboundQueue);
- if (Index != 0xFFFFFFFFL) {
+ if (likely(Index != 0xFFFFFFFFL)) {
do {
- if (aac_intr_normal(dev, Index)) {
+ if (unlikely(aac_intr_normal(dev, Index))) {
rx_writel(dev, MUnit.OutboundQueue, Index);
rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
}
@@ -204,7 +204,7 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
*/
msleep(1);
}
- if (ok != 1) {
+ if (unlikely(ok != 1)) {
/*
* Restore interrupt mask even though we timed out
*/
@@ -294,7 +294,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
* Start up processing on an i960 based AAC adapter
*/
-void aac_rx_start_adapter(struct aac_dev *dev)
+static void aac_rx_start_adapter(struct aac_dev *dev)
{
struct aac_init *init;
@@ -319,12 +319,12 @@ static int aac_rx_check_health(struct aac_dev *dev)
/*
* Check to see if the board failed any self tests.
*/
- if (status & SELF_TEST_FAILED)
+ if (unlikely(status & SELF_TEST_FAILED))
return -1;
/*
* Check to see if the board panic'd.
*/
- if (status & KERNEL_PANIC) {
+ if (unlikely(status & KERNEL_PANIC)) {
char * buffer;
struct POSTSTATUS {
__le32 Post_Command;
@@ -333,15 +333,15 @@ static int aac_rx_check_health(struct aac_dev *dev)
dma_addr_t paddr, baddr;
int ret;
- if ((status & 0xFF000000L) == 0xBC000000L)
+ if (likely((status & 0xFF000000L) == 0xBC000000L))
return (status >> 16) & 0xFF;
buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
ret = -2;
- if (buffer == NULL)
+ if (unlikely(buffer == NULL))
return ret;
post = pci_alloc_consistent(dev->pdev,
sizeof(struct POSTSTATUS), &paddr);
- if (post == NULL) {
+ if (unlikely(post == NULL)) {
pci_free_consistent(dev->pdev, 512, buffer, baddr);
return ret;
}
@@ -353,7 +353,7 @@ static int aac_rx_check_health(struct aac_dev *dev)
NULL, NULL, NULL, NULL, NULL);
pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
post, paddr);
- if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
+ if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) {
ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
ret <<= 4;
ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
@@ -364,7 +364,7 @@ static int aac_rx_check_health(struct aac_dev *dev)
/*
* Wait for the adapter to be up and running.
*/
- if (!(status & KERNEL_UP_AND_RUNNING))
+ if (unlikely(!(status & KERNEL_UP_AND_RUNNING)))
return -3;
/*
* Everything is OK
@@ -387,7 +387,7 @@ static int aac_rx_deliver_producer(struct fib * fib)
unsigned long nointr = 0;
spin_lock_irqsave(q->lock, qflags);
- aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib, 1, fib, &nointr);
+ aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr);
q->numpending++;
*(q->headers.producer) = cpu_to_le32(Index + 1);
@@ -419,9 +419,9 @@ static int aac_rx_deliver_message(struct fib * fib)
spin_unlock_irqrestore(q->lock, qflags);
for(;;) {
Index = rx_readl(dev, MUnit.InboundQueue);
- if (Index == 0xFFFFFFFFL)
+ if (unlikely(Index == 0xFFFFFFFFL))
Index = rx_readl(dev, MUnit.InboundQueue);
- if (Index != 0xFFFFFFFFL)
+ if (likely(Index != 0xFFFFFFFFL))
break;
if (--count == 0) {
spin_lock_irqsave(q->lock, qflags);
@@ -437,7 +437,7 @@ static int aac_rx_deliver_message(struct fib * fib)
device += sizeof(u32);
writel((u32)(addr >> 32), device);
device += sizeof(u32);
- writel(le16_to_cpu(fib->hw_fib->header.Size), device);
+ writel(le16_to_cpu(fib->hw_fib_va->header.Size), device);
rx_writel(dev, MUnit.InboundQueue, Index);
return 0;
}
@@ -460,22 +460,34 @@ static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
return 0;
}
-static int aac_rx_restart_adapter(struct aac_dev *dev)
+static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
{
u32 var;
- printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
- dev->name, dev->id);
-
- if (aac_rx_check_health(dev) <= 0)
- return 1;
- if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
- &var, NULL, NULL, NULL, NULL))
- return 1;
+ if (bled)
+ printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+ dev->name, dev->id, bled);
+ else {
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+ if (!bled && (var != 0x00000001))
+ bled = -EINVAL;
+ }
+ if (bled && (bled != -ETIMEDOUT))
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+
+ if (bled && (bled != -ETIMEDOUT))
+ return -EINVAL;
+ if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
+ rx_writel(dev, MUnit.reserved2, 3);
+ msleep(5000); /* Delay 5 seconds */
+ var = 0x00000001;
+ }
if (var != 0x00000001)
- return 1;
+ return -EINVAL;
if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
- return 1;
+ return -ENODEV;
return 0;
}
@@ -517,24 +529,31 @@ int _aac_rx_init(struct aac_dev *dev)
{
unsigned long start;
unsigned long status;
- int instance;
- const char * name;
-
- instance = dev->id;
- name = dev->name;
+ int restart = 0;
+ int instance = dev->id;
+ const char * name = dev->name;
if (aac_adapter_ioremap(dev, dev->base_size)) {
printk(KERN_WARNING "%s: unable to map adapter.\n", name);
goto error_iounmap;
}
+ /* Failure to reset here is an option ... */
+ dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+ dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt;
+ dev->OIMR = status = rx_readb (dev, MUnit.OIMR);
+ if ((((status & 0x0c) != 0x0c) || reset_devices) &&
+ !aac_rx_restart_adapter(dev, 0))
+ ++restart;
/*
* Check to see if the board panic'd while booting.
*/
status = rx_readl(dev, MUnit.OMRx[0]);
- if (status & KERNEL_PANIC)
- if (aac_rx_restart_adapter(dev))
+ if (status & KERNEL_PANIC) {
+ if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))
goto error_iounmap;
+ ++restart;
+ }
/*
* Check to see if the board failed any self tests.
*/
@@ -556,12 +575,23 @@ int _aac_rx_init(struct aac_dev *dev)
*/
while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
{
- if(time_after(jiffies, start+startup_timeout*HZ))
- {
+ if ((restart &&
+ (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) ||
+ time_after(jiffies, start+HZ*startup_timeout)) {
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
dev->name, instance, status);
goto error_iounmap;
}
+ if (!restart &&
+ ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) ||
+ time_after(jiffies, start + HZ *
+ ((startup_timeout > 60)
+ ? (startup_timeout - 60)
+ : (startup_timeout / 2))))) {
+ if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev))))
+ start = jiffies;
+ ++restart;
+ }
msleep(1);
}
/*
@@ -572,6 +602,7 @@ int _aac_rx_init(struct aac_dev *dev)
dev->a_ops.adapter_notify = aac_rx_notify_adapter;
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
+ dev->a_ops.adapter_restart = aac_rx_restart_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 6f1a1780efc..f4b5e9742ab 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -31,7 +31,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/pci.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 1d239f6c010..cbbfbc9f3e0 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -35,7 +35,6 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <linux/pci.h>
#include <linux/isapnp.h>
#include <linux/blkdev.h>
#include <linux/mca.h>
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 911ea1756e5..5e6620f8dab 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -57,18 +57,6 @@ config AIC79XX_BUILD_FIRMWARE
or modify the assembler Makefile or the files it includes if your
build environment is different than that of the author.
-config AIC79XX_ENABLE_RD_STRM
- bool "Enable Read Streaming for All Targets"
- depends on SCSI_AIC79XX
- default n
- help
- Read Streaming is a U320 protocol option that should enhance
- performance. Early U320 drive firmware actually performs slower
- with read streaming enabled so it is disabled by default. Read
- Streaming can be configured in much the same way as tagged queueing
- using the "rd_strm" command line option. See
- drivers/scsi/aic7xxx/README.aic79xx for details.
-
config AIC79XX_DEBUG_ENABLE
bool "Compile in Debugging Code"
depends on SCSI_AIC79XX
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index cd93f9a8611..88da670a791 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -50,16 +50,6 @@ config AIC7XXX_RESET_DELAY_MS
Default: 5000 (5 seconds)
-config AIC7XXX_PROBE_EISA_VL
- bool "Probe for EISA and VL AIC7XXX Adapters"
- depends on SCSI_AIC7XXX && EISA
- help
- Probe for EISA and VLB Aic7xxx controllers. In many newer systems,
- the invasive probes necessary to detect these controllers can cause
- other devices to fail. For this reason, the non-PCI probe code is
- disabled by default. The current value of this option can be "toggled"
- via the no_probe kernel command line option.
-
config AIC7XXX_BUILD_FIRMWARE
bool "Build Adapter Firmware with Kernel Build"
depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 2be03e975d9..6054881f21f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -363,6 +363,8 @@ static int ahd_linux_run_command(struct ahd_softc*,
struct scsi_cmnd *);
static void ahd_linux_setup_tag_info_global(char *p);
static int aic79xx_setup(char *c);
+static void ahd_freeze_simq(struct ahd_softc *ahd);
+static void ahd_release_simq(struct ahd_softc *ahd);
static int ahd_linux_unit;
@@ -2016,13 +2018,13 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
cmd->scsi_done(cmd);
}
-void
+static void
ahd_freeze_simq(struct ahd_softc *ahd)
{
scsi_block_requests(ahd->platform_data->host);
}
-void
+static void
ahd_release_simq(struct ahd_softc *ahd)
{
scsi_unblock_requests(ahd->platform_data->host);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 147c83c456a..ad9761b237d 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -47,7 +47,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -837,8 +836,6 @@ int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg);
void ahd_platform_free(struct ahd_softc *ahd);
void ahd_platform_init(struct ahd_softc *ahd);
void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
-void ahd_freeze_simq(struct ahd_softc *ahd);
-void ahd_release_simq(struct ahd_softc *ahd);
static __inline void
ahd_freeze_scb(struct scb *scb)
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
index 8d72bbae96a..0bada0028aa 100644
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -966,7 +966,7 @@ ahd_aic790X_setup(struct ahd_softc *ahd)
| AHD_BUSFREEREV_BUG;
ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
- /* If the user requested the the SLOWCRC bit to be set. */
+ /* If the user requested that the SLOWCRC bit to be set. */
if (aic79xx_slowcrc)
ahd->features |= AHD_AIC79XXB_SLOWCRC;
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
index 954c7c24501..e1bd57b9f23 100644
--- a/drivers/scsi/aic7xxx/aic7xxx.h
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -1278,11 +1278,6 @@ typedef enum {
AHC_QUEUE_TAGGED
} ahc_queue_alg;
-void ahc_set_tags(struct ahc_softc *ahc,
- struct scsi_cmnd *cmd,
- struct ahc_devinfo *devinfo,
- ahc_queue_alg alg);
-
/**************************** Target Mode *************************************/
#ifdef AHC_TARGET_MODE
void ahc_send_lstate_events(struct ahc_softc *,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 50ef785224d..75733b09f27 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -2073,7 +2073,7 @@ ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
/*
* Update the current state of tagged queuing for a given target.
*/
-void
+static void
ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
struct ahc_devinfo *devinfo, ahc_queue_alg alg)
{
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 85ae5d836fa..8fee7edc6eb 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -64,7 +64,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
index e6b70123940..e78ce0fa44d 100644
--- a/drivers/scsi/aic94xx/Makefile
+++ b/drivers/scsi/aic94xx/Makefile
@@ -6,7 +6,7 @@
#
# This file is licensed under GPLv2.
#
-# This file is part of the the aic94xx driver.
+# This file is part of the aic94xx driver.
#
# The aic94xx driver is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
index 8f43ff772f2..db6ab1a3b81 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -24,7 +24,6 @@
*
*/
-#include <linux/pci.h>
#include <scsi/scsi_host.h>
#include "aic94xx.h"
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 12497da5529..03bfed61bff 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -49,7 +49,6 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
-#include <linux/pci.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 0f920c84ac0..eff846ae0af 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1,19 +1,19 @@
-/*
+/*
* NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
* architecture.
*
* Note that these routines also work with NR53c400 family chips.
*
* Copyright 1993, Drew Eckhardt
- * Visionary Computing
+ * Visionary Computing
* (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
+ * drew@colorado.edu
* +1 (303) 666-5836
*
- * DISTRIBUTION RELEASE 6.
+ * DISTRIBUTION RELEASE 6.
*
- * For more information, please consult
+ * For more information, please consult
*
* NCR 5380 Family
* SCSI Protocol Controller
@@ -57,7 +57,7 @@
* - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
* and USLEEP, because these were messing up readability and will never be
* needed for Atari SCSI.
- *
+ *
* - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
* stuff), and 'main' is executed in a bottom half if awoken by an
* interrupt.
@@ -69,21 +69,29 @@
*/
/*
- * Further development / testing that should be done :
- * 1. Test linked command handling code after Eric is ready with
+ * Further development / testing that should be done :
+ * 1. Test linked command handling code after Eric is ready with
* the high level code.
*/
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_transport_spi.h>
#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) \
- { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
- if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) \
- { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \
- (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
- if ((x)==(y)) udelay(5); }
+#define LIST(x, y) \
+ do { \
+ printk("LINE:%d Adding %p to %p\n", \
+ __LINE__, (void*)(x), (void*)(y)); \
+ if ((x) == (y)) \
+ udelay(5); \
+ } while (0)
+#define REMOVE(w, x, y, z) \
+ do { \
+ printk("LINE:%d Removing: %p->%p %p->%p \n", \
+ __LINE__, (void*)(w), (void*)(x), \
+ (void*)(y), (void*)(z)); \
+ if ((x) == (y)) \
+ udelay(5); \
+ } while (0)
#else
#define LIST(x,y)
#define REMOVE(w,x,y,z)
@@ -103,62 +111,62 @@
* more difficult than it has to be.
*
* Also, many of the SCSI drivers were written before the command queuing
- * routines were implemented, meaning their implementations of queued
+ * routines were implemented, meaning their implementations of queued
* commands were hacked on rather than designed in from the start.
*
- * When I designed the Linux SCSI drivers I figured that
+ * When I designed the Linux SCSI drivers I figured that
* while having two different SCSI boards in a system might be useful
* for debugging things, two of the same type wouldn't be used.
* Well, I was wrong and a number of users have mailed me about running
* multiple high-performance SCSI boards in a server.
*
- * Finally, when I get questions from users, I have no idea what
+ * Finally, when I get questions from users, I have no idea what
* revision of my driver they are running.
*
* This driver attempts to address these problems :
- * This is a generic 5380 driver. To use it on a different platform,
+ * This is a generic 5380 driver. To use it on a different platform,
* one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use
+ * transfer - some PC's will use the I/O bus, 68K's must use
* memory mapped) and drops this file in their 'C' wrapper.
*
- * As far as command queueing, two queues are maintained for
+ * As far as command queueing, two queues are maintained for
* each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing. This means that an
- * unlimited number of commands may be queued, letting
- * more commands propagate from the higher driver levels giving higher
- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
- * allowing multiple commands to propagate all the way to a SCSI-II device
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propagate from the higher driver levels giving higher
+ * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propagate all the way to a SCSI-II device
* while a command is already executing.
*
- * To solve the multiple-boards-in-the-same-system problem,
+ * To solve the multiple-boards-in-the-same-system problem,
* there is a separate instance structure for each instance
* of a 5380 in the system. So, multiple NCR5380 drivers will
* be able to coexist with appropriate changes to the high level
- * SCSI code.
+ * SCSI code.
*
* A NCR5380_PUBLIC_REVISION macro is provided, with the release
- * number (updated for each public release) printed by the
- * NCR5380_print_options command, which should be called from the
+ * number (updated for each public release) printed by the
+ * NCR5380_print_options command, which should be called from the
* wrapper detect function, so that I know what release of the driver
* users are using.
*
- * Issues specific to the NCR5380 :
+ * Issues specific to the NCR5380 :
*
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
- * piece of hardware that requires you to sit in a loop polling for
- * the REQ signal as long as you are connected. Some devices are
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
* while doing long seek operations.
- *
+ *
* The workaround for this is to keep track of devices that have
* disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
+ * should disconnect, we do something like
*
* while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
+ *
+ * Some tweaking of N and M needs to be done. An algorithm based
* on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
+ * to datas (ie, on the same track) were considered, however these
* broken devices are the exception rather than the rule and I'd rather
* spend my time optimizing for the normal case.
*
@@ -167,9 +175,9 @@
* At the heart of the design is a coroutine, NCR5380_main,
* which is started when not running by the interrupt handler,
* timer, and queue command function. It attempts to establish
- * I_T_L or I_T_L_Q nexuses by removing the commands from the
- * issue queue and calling NCR5380_select() if a nexus
- * is not established.
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the
+ * issue queue and calling NCR5380_select() if a nexus
+ * is not established.
*
* Once a nexus is established, the NCR5380_information_transfer()
* phase goes through the various phases as instructed by the target.
@@ -183,10 +191,10 @@
* calling NCR5380_intr() which will in turn call NCR5380_reselect
* to reestablish a nexus. This will run main if necessary.
*
- * On command termination, the done function will be called as
+ * On command termination, the done function will be called as
* appropriate.
*
- * SCSI pointers are maintained in the SCp field of SCSI command
+ * SCSI pointers are maintained in the SCp field of SCSI command
* structures, being initialized after the command is connected
* in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
* Note that in violation of the standard, an implicit SAVE POINTERS operation
@@ -196,12 +204,12 @@
/*
* Using this file :
* This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips. To use it, you write an architecture specific functions
+ * of chips. To use it, you write an architecture specific functions
* and macros and include this file in your driver.
*
- * These macros control options :
+ * These macros control options :
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
+ * for commands that return with a CHECK CONDITION status.
*
* LINKED - if defined, linked commands are supported.
*
@@ -210,18 +218,18 @@
* SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
*
* These macros MUST be defined :
- *
+ *
* NCR5380_read(register) - read from the specified register
*
- * NCR5380_write(register, value) - write to the specific register
+ * NCR5380_write(register, value) - write to the specific register
*
* Either real DMA *or* pseudo DMA may be implemented
- * REAL functions :
+ * REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes
+ * Note that the DMA setup functions should return the number of bytes
* that they were able to program the controller for.
*
- * Also note that generic i386/PC versions of these macros are
+ * Also note that generic i386/PC versions of these macros are
* available as NCR5380_i386_dma_write_setup,
* NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
*
@@ -234,14 +242,14 @@
* NCR5380_pread(instance, dst, count);
*
* If nothing specific to this implementation needs doing (ie, with external
- * hardware), you must also define
- *
+ * hardware), you must also define
+ *
* NCR5380_queue_command
* NCR5380_reset
* NCR5380_abort
* NCR5380_proc_info
*
- * to be the global entry points into the specific driver, ie
+ * to be the global entry points into the specific driver, ie
* #define NCR5380_queue_command t128_queue_command.
*
* If this is not done, the routines will be defined as static functions
@@ -249,7 +257,7 @@
* accessible wrapper function.
*
* The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID. If the
+ * after setting the appropriate host specific fields and ID. If the
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
* possible) function may be used. Before the specific driver initialization
* code finishes, NCR5380_print_options should be called.
@@ -264,8 +272,9 @@ static struct scsi_host_template *the_template = NULL;
(struct NCR5380_hostdata *)(in)->hostdata
#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble))
-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble))
+#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble)
+#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
+#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble)
#define HOSTNO instance->host_no
#define H_NO(cmd) (cmd)->device->host->host_no
@@ -312,34 +321,34 @@ static struct scsi_host_template *the_template = NULL;
#define TAG_NONE 0xff
typedef struct {
- DECLARE_BITMAP(allocated, MAX_TAGS);
- int nr_allocated;
- int queue_size;
+ DECLARE_BITMAP(allocated, MAX_TAGS);
+ int nr_allocated;
+ int queue_size;
} TAG_ALLOC;
-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
-static void __init init_tags( void )
+static void __init init_tags(void)
{
- int target, lun;
- TAG_ALLOC *ta;
-
- if (!setup_use_tagged_queuing)
- return;
-
- for( target = 0; target < 8; ++target ) {
- for( lun = 0; lun < 8; ++lun ) {
- ta = &TagAlloc[target][lun];
- bitmap_zero(ta->allocated, MAX_TAGS);
- ta->nr_allocated = 0;
- /* At the beginning, assume the maximum queue size we could
- * support (MAX_TAGS). This value will be decreased if the target
- * returns QUEUE_FULL status.
- */
- ta->queue_size = MAX_TAGS;
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for (target = 0; target < 8; ++target) {
+ for (lun = 0; lun < 8; ++lun) {
+ ta = &TagAlloc[target][lun];
+ bitmap_zero(ta->allocated, MAX_TAGS);
+ ta->nr_allocated = 0;
+ /* At the beginning, assume the maximum queue size we could
+ * support (MAX_TAGS). This value will be decreased if the target
+ * returns QUEUE_FULL status.
+ */
+ ta->queue_size = MAX_TAGS;
+ }
}
- }
}
@@ -348,24 +357,24 @@ static void __init init_tags( void )
* check that there is a free tag and the target's queue won't overflow. This
* function should be called with interrupts disabled to avoid race
* conditions.
- */
+ */
-static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
{
- SETUP_HOSTDATA(cmd->device->host);
-
- if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
- return( 1 );
- if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported)
- return( 0 );
- if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
- TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
- TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun );
- return( 1 );
- }
- return( 0 );
+ SETUP_HOSTDATA(cmd->device->host);
+
+ if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
+ return 1;
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+ return 0;
+ if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+ TagAlloc[cmd->device->id][cmd->device->lun].queue_size) {
+ TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ return 1;
+ }
+ return 0;
}
@@ -374,31 +383,30 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
* untagged.
*/
-static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged)
{
- SETUP_HOSTDATA(cmd->device->host);
-
- /* If we or the target don't support tagged queuing, allocate the LUN for
- * an untagged command.
- */
- if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
- cmd->tag = TAG_NONE;
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
- }
- else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
-
- cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
- set_bit( cmd->tag, ta->allocated );
- ta->nr_allocated++;
- TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
- "(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
- ta->nr_allocated );
- }
+ SETUP_HOSTDATA(cmd->device->host);
+
+ /* If we or the target don't support tagged queuing, allocate the LUN for
+ * an untagged command.
+ */
+ if (!should_be_tagged ||
+ !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+ cmd->tag = TAG_NONE;
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+ TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged "
+ "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun);
+ } else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+
+ cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
+ set_bit(cmd->tag, ta->allocated);
+ ta->nr_allocated++;
+ TAG_PRINTK("scsi%d: using tag %d for target %d lun %d "
+ "(now %d tags in use)\n",
+ H_NO(cmd), cmd->tag, cmd->device->id,
+ cmd->device->lun, ta->nr_allocated);
+ }
}
@@ -406,44 +414,42 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
* unlock the LUN.
*/
-static void cmd_free_tag( Scsi_Cmnd *cmd )
+static void cmd_free_tag(Scsi_Cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
-
- if (cmd->tag == TAG_NONE) {
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
- TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun );
- }
- else if (cmd->tag >= MAX_TAGS) {
- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
- H_NO(cmd), cmd->tag );
- }
- else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
- clear_bit( cmd->tag, ta->allocated );
- ta->nr_allocated--;
- TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
- }
+ SETUP_HOSTDATA(cmd->device->host);
+
+ if (cmd->tag == TAG_NONE) {
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ } else if (cmd->tag >= MAX_TAGS) {
+ printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+ H_NO(cmd), cmd->tag);
+ } else {
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+ clear_bit(cmd->tag, ta->allocated);
+ ta->nr_allocated--;
+ TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n",
+ H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun);
+ }
}
-static void free_all_tags( void )
+static void free_all_tags(void)
{
- int target, lun;
- TAG_ALLOC *ta;
-
- if (!setup_use_tagged_queuing)
- return;
-
- for( target = 0; target < 8; ++target ) {
- for( lun = 0; lun < 8; ++lun ) {
- ta = &TagAlloc[target][lun];
- bitmap_zero(ta->allocated, MAX_TAGS);
- ta->nr_allocated = 0;
+ int target, lun;
+ TAG_ALLOC *ta;
+
+ if (!setup_use_tagged_queuing)
+ return;
+
+ for (target = 0; target < 8; ++target) {
+ for (lun = 0; lun < 8; ++lun) {
+ ta = &TagAlloc[target][lun];
+ bitmap_zero(ta->allocated, MAX_TAGS);
+ ta->nr_allocated = 0;
+ }
}
- }
}
#endif /* SUPPORT_TAGS */
@@ -461,89 +467,94 @@ static void free_all_tags( void )
* assumed to be already transfered into ptr/this_residual.
*/
-static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
{
- unsigned long endaddr;
+ unsigned long endaddr;
#if (NDEBUG & NDEBUG_MERGING)
- unsigned long oldlen = cmd->SCp.this_residual;
- int cnt = 1;
+ unsigned long oldlen = cmd->SCp.this_residual;
+ int cnt = 1;
#endif
- for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
- cmd->SCp.buffers_residual &&
- virt_to_phys(page_address(cmd->SCp.buffer[1].page)+
- cmd->SCp.buffer[1].offset) == endaddr; ) {
- MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
- cmd->SCp.buffer[1].address, endaddr);
+ for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+ cmd->SCp.buffers_residual &&
+ virt_to_phys(page_address(cmd->SCp.buffer[1].page) +
+ cmd->SCp.buffer[1].offset) == endaddr;) {
+ MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+ page_address(cmd->SCp.buffer[1].page), endaddr);
#if (NDEBUG & NDEBUG_MERGING)
- ++cnt;
+ ++cnt;
#endif
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual += cmd->SCp.buffer->length;
- endaddr += cmd->SCp.buffer->length;
- }
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual += cmd->SCp.buffer->length;
+ endaddr += cmd->SCp.buffer->length;
+ }
#if (NDEBUG & NDEBUG_MERGING)
- if (oldlen != cmd->SCp.this_residual)
- MER_PRINTK("merged %d buffers from %p, new length %08x\n",
- cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+ if (oldlen != cmd->SCp.this_residual)
+ MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+ cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
#endif
}
/*
* Function : void initialize_SCp(Scsi_Cmnd *cmd)
*
- * Purpose : initialize the saved data pointers for cmd to point to the
+ * Purpose : initialize the saved data pointers for cmd to point to the
* start of the buffer.
*
* Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
*/
-static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+static inline void initialize_SCp(Scsi_Cmnd *cmd)
{
- /*
- * Initialize the Scsi Pointer field so that all of the commands in the
- * various queues are valid.
- */
-
- if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
- cmd->SCp.buffers_residual = cmd->use_sg - 1;
- cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
- cmd->SCp.buffer->offset;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- /* ++roman: Try to merge some scatter-buffers if they are at
- * contiguous physical addresses.
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
+ * various queues are valid.
*/
- merge_contiguous_buffers( cmd );
- } else {
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = (char *) cmd->request_buffer;
- cmd->SCp.this_residual = cmd->request_bufflen;
- }
+
+ if (cmd->use_sg) {
+ cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer;
+ cmd->SCp.buffers_residual = cmd->use_sg - 1;
+ cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) +
+ cmd->SCp.buffer->offset;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ /* ++roman: Try to merge some scatter-buffers if they are at
+ * contiguous physical addresses.
+ */
+ merge_contiguous_buffers(cmd);
+ } else {
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ cmd->SCp.ptr = (char *)cmd->request_buffer;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ }
}
#include <linux/delay.h>
#if NDEBUG
static struct {
- unsigned char mask;
- const char * name;}
-signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
- { SR_SEL, "SEL" }, {0, NULL}},
-basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
-icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
- {0, NULL}},
-mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
- {MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
- {0, NULL}};
+ unsigned char mask;
+ const char *name;
+} signals[] = {
+ { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
+ { SR_SEL, "SEL" }, {0, NULL}
+}, basrs[] = {
+ {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}
+}, icrs[] = {
+ {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}
+}, mrs[] = {
+ {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+ "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+ {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {0, NULL}
+};
/*
* Function : void NCR5380_print(struct Scsi_Host *instance)
@@ -553,45 +564,47 @@ mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
* Input : instance - which NCR5380
*/
-static void NCR5380_print(struct Scsi_Host *instance) {
- unsigned char status, data, basr, mr, icr, i;
- unsigned long flags;
-
- local_irq_save(flags);
- data = NCR5380_read(CURRENT_SCSI_DATA_REG);
- status = NCR5380_read(STATUS_REG);
- mr = NCR5380_read(MODE_REG);
- icr = NCR5380_read(INITIATOR_COMMAND_REG);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- local_irq_restore(flags);
- printk("STATUS_REG: %02x ", status);
- for (i = 0; signals[i].mask ; ++i)
- if (status & signals[i].mask)
- printk(",%s", signals[i].name);
- printk("\nBASR: %02x ", basr);
- for (i = 0; basrs[i].mask ; ++i)
- if (basr & basrs[i].mask)
- printk(",%s", basrs[i].name);
- printk("\nICR: %02x ", icr);
- for (i = 0; icrs[i].mask; ++i)
- if (icr & icrs[i].mask)
- printk(",%s", icrs[i].name);
- printk("\nMODE: %02x ", mr);
- for (i = 0; mrs[i].mask; ++i)
- if (mr & mrs[i].mask)
- printk(",%s", mrs[i].name);
- printk("\n");
+static void NCR5380_print(struct Scsi_Host *instance)
+{
+ unsigned char status, data, basr, mr, icr, i;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ status = NCR5380_read(STATUS_REG);
+ mr = NCR5380_read(MODE_REG);
+ icr = NCR5380_read(INITIATOR_COMMAND_REG);
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ local_irq_restore(flags);
+ printk("STATUS_REG: %02x ", status);
+ for (i = 0; signals[i].mask; ++i)
+ if (status & signals[i].mask)
+ printk(",%s", signals[i].name);
+ printk("\nBASR: %02x ", basr);
+ for (i = 0; basrs[i].mask; ++i)
+ if (basr & basrs[i].mask)
+ printk(",%s", basrs[i].name);
+ printk("\nICR: %02x ", icr);
+ for (i = 0; icrs[i].mask; ++i)
+ if (icr & icrs[i].mask)
+ printk(",%s", icrs[i].name);
+ printk("\nMODE: %02x ", mr);
+ for (i = 0; mrs[i].mask; ++i)
+ if (mr & mrs[i].mask)
+ printk(",%s", mrs[i].name);
+ printk("\n");
}
static struct {
- unsigned char value;
- const char *name;
+ unsigned char value;
+ const char *name;
} phases[] = {
- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
- {PHASE_UNKNOWN, "UNKNOWN"}};
+ {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+ {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+ {PHASE_UNKNOWN, "UNKNOWN"}
+};
-/*
+/*
* Function : void NCR5380_print_phase(struct Scsi_Host *instance)
*
* Purpose : print the current SCSI phase for debugging purposes
@@ -601,30 +614,35 @@ static struct {
static void NCR5380_print_phase(struct Scsi_Host *instance)
{
- unsigned char status;
- int i;
-
- status = NCR5380_read(STATUS_REG);
- if (!(status & SR_REQ))
- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
- else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
- (phases[i].value != (status & PHASE_MASK)); ++i);
- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
- }
+ unsigned char status;
+ int i;
+
+ status = NCR5380_read(STATUS_REG);
+ if (!(status & SR_REQ))
+ printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+ else {
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i)
+ ;
+ printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+ }
}
#else /* !NDEBUG */
/* dummies... */
-__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
-__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+static inline void NCR5380_print(struct Scsi_Host *instance)
+{
+};
+static inline void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+};
#endif
/*
* ++roman: New scheme of calling NCR5380_main()
- *
+ *
* If we're not in an interrupt, we can call our main directly, it cannot be
* already running. Else, we queue it on a task queue, if not 'main_running'
* tells us that a lower level is already executing it. This way,
@@ -638,33 +656,33 @@ __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-static volatile int main_running = 0;
-static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
+static volatile int main_running;
+static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
-static __inline__ void queue_main(void)
+static inline void queue_main(void)
{
- if (!main_running) {
- /* If in interrupt and NCR5380_main() not already running,
- queue it on the 'immediate' task queue, to be processed
- immediately after the current interrupt processing has
- finished. */
- schedule_work(&NCR5380_tqueue);
- }
- /* else: nothing to do: the running NCR5380_main() will pick up
- any newly queued command. */
+ if (!main_running) {
+ /* If in interrupt and NCR5380_main() not already running,
+ queue it on the 'immediate' task queue, to be processed
+ immediately after the current interrupt processing has
+ finished. */
+ schedule_work(&NCR5380_tqueue);
+ }
+ /* else: nothing to do: the running NCR5380_main() will pick up
+ any newly queued command. */
}
-static inline void NCR5380_all_init (void)
+static inline void NCR5380_all_init(void)
{
- static int done = 0;
- if (!done) {
- INI_PRINTK("scsi : NCR5380_all_init()\n");
- done = 1;
- }
+ static int done = 0;
+ if (!done) {
+ INI_PRINTK("scsi : NCR5380_all_init()\n");
+ done = 1;
+ }
}
-
+
/*
* Function : void NCR58380_print_options (struct Scsi_Host *instance)
*
@@ -674,23 +692,23 @@ static inline void NCR5380_all_init (void)
* Inputs : instance, pointer to this instance. Unused.
*/
-static void __init NCR5380_print_options (struct Scsi_Host *instance)
+static void __init NCR5380_print_options(struct Scsi_Host *instance)
{
- printk(" generic options"
-#ifdef AUTOSENSE
- " AUTOSENSE"
+ printk(" generic options"
+#ifdef AUTOSENSE
+ " AUTOSENSE"
#endif
#ifdef REAL_DMA
- " REAL DMA"
+ " REAL DMA"
#endif
#ifdef PARITY
- " PARITY"
+ " PARITY"
#endif
#ifdef SUPPORT_TAGS
- " SCSI-2 TAGGED QUEUING"
+ " SCSI-2 TAGGED QUEUING"
#endif
- );
- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+ );
+ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
}
/*
@@ -699,27 +717,27 @@ static void __init NCR5380_print_options (struct Scsi_Host *instance)
* Purpose : print commands in the various queues, called from
* NCR5380_abort and NCR5380_debug to aid debugging.
*
- * Inputs : instance, pointer to this instance.
+ * Inputs : instance, pointer to this instance.
*/
-static void NCR5380_print_status (struct Scsi_Host *instance)
+static void NCR5380_print_status(struct Scsi_Host *instance)
{
- char *pr_bfr;
- char *start;
- int len;
-
- NCR_PRINT(NDEBUG_ANY);
- NCR_PRINT_PHASE(NDEBUG_ANY);
-
- pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
- if (!pr_bfr) {
- printk("NCR5380_print_status: no memory for print buffer\n");
- return;
- }
- len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
- pr_bfr[len] = 0;
- printk("\n%s\n", pr_bfr);
- free_page((unsigned long) pr_bfr);
+ char *pr_bfr;
+ char *start;
+ int len;
+
+ NCR_PRINT(NDEBUG_ANY);
+ NCR_PRINT_PHASE(NDEBUG_ANY);
+
+ pr_bfr = (char *)__get_free_page(GFP_ATOMIC);
+ if (!pr_bfr) {
+ printk("NCR5380_print_status: no memory for print buffer\n");
+ return;
+ }
+ len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+ pr_bfr[len] = 0;
+ printk("\n%s\n", pr_bfr);
+ free_page((unsigned long)pr_bfr);
}
@@ -738,443 +756,478 @@ static void NCR5380_print_status (struct Scsi_Host *instance)
*/
#undef SPRINTF
-#define SPRINTF(fmt,args...) \
- do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
- pos += sprintf(pos, fmt , ## args); } while(0)
-static
-char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
-
-static
-int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
- int length, int inout)
+#define SPRINTF(fmt,args...) \
+ do { \
+ if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+ pos += sprintf(pos, fmt , ## args); \
+ } while(0)
+static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer,
+ char **start, off_t offset, int length, int inout)
{
- char *pos = buffer;
- struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
- unsigned long flags;
- off_t begin = 0;
-#define check_offset() \
- do { \
- if (pos - buffer < offset - begin) { \
- begin += pos - buffer; \
- pos = buffer; \
- } \
- } while (0)
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- if (inout) { /* Has data been written to the file ? */
- return(-ENOSYS); /* Currently this is a no-op */
- }
- SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
- check_offset();
- local_irq_save(flags);
- SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
- check_offset();
- if (!hostdata->connected)
- SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
- else
- pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
- pos, buffer, length);
- SPRINTF("scsi%d: issue_queue\n", HOSTNO);
- check_offset();
- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ char *pos = buffer;
+ struct NCR5380_hostdata *hostdata;
+ Scsi_Cmnd *ptr;
+ unsigned long flags;
+ off_t begin = 0;
+#define check_offset() \
+ do { \
+ if (pos - buffer < offset - begin) { \
+ begin += pos - buffer; \
+ pos = buffer; \
+ } \
+ } while (0)
+
+ hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+ if (inout) /* Has data been written to the file ? */
+ return -ENOSYS; /* Currently this is a no-op */
+ SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
check_offset();
- }
+ local_irq_save(flags);
+ SPRINTF("NCR5380: coroutine is%s running.\n",
+ main_running ? "" : "n't");
+ check_offset();
+ if (!hostdata->connected)
+ SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+ else
+ pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected,
+ pos, buffer, length);
+ SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+ check_offset();
+ for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+ check_offset();
+ }
- SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
- check_offset();
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr)) {
- pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+ SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
check_offset();
- }
+ for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ ptr = NEXT(ptr)) {
+ pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+ check_offset();
+ }
- local_irq_restore(flags);
- *start = buffer + (offset - begin);
- if (pos - buffer < offset - begin)
- return 0;
- else if (pos - buffer - (offset - begin) < length)
- return pos - buffer - (offset - begin);
- return length;
+ local_irq_restore(flags);
+ *start = buffer + (offset - begin);
+ if (pos - buffer < offset - begin)
+ return 0;
+ else if (pos - buffer - (offset - begin) < length)
+ return pos - buffer - (offset - begin);
+ return length;
}
-static char *
-lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
{
- int i, s;
- unsigned char *command;
- SPRINTF("scsi%d: destination target %d, lun %d\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- SPRINTF(" command = ");
- command = cmd->cmnd;
- SPRINTF("%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- SPRINTF(" %02x", command[i]);
- SPRINTF("\n");
- return pos;
+ int i, s;
+ unsigned char *command;
+ SPRINTF("scsi%d: destination target %d, lun %d\n",
+ H_NO(cmd), cmd->device->id, cmd->device->lun);
+ SPRINTF(" command = ");
+ command = cmd->cmnd;
+ SPRINTF("%2d (0x%02x)", command[0], command[0]);
+ for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ SPRINTF(" %02x", command[i]);
+ SPRINTF("\n");
+ return pos;
}
-/*
+/*
* Function : void NCR5380_init (struct Scsi_Host *instance)
*
* Purpose : initializes *instance and corresponding 5380 chip.
*
- * Inputs : instance - instantiation of the 5380 driver.
+ * Inputs : instance - instantiation of the 5380 driver.
*
* Notes : I assume that the host, hostno, and id bits have been
- * set correctly. I don't care about the irq and other fields.
- *
+ * set correctly. I don't care about the irq and other fields.
+ *
*/
-static int NCR5380_init (struct Scsi_Host *instance, int flags)
+static int NCR5380_init(struct Scsi_Host *instance, int flags)
{
- int i;
- SETUP_HOSTDATA(instance);
-
- NCR5380_all_init();
-
- hostdata->aborted = 0;
- hostdata->id_mask = 1 << instance->this_id;
- hostdata->id_higher_mask = 0;
- for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
- if (i > hostdata->id_mask)
- hostdata->id_higher_mask |= i;
- for (i = 0; i < 8; ++i)
- hostdata->busy[i] = 0;
+ int i;
+ SETUP_HOSTDATA(instance);
+
+ NCR5380_all_init();
+
+ hostdata->aborted = 0;
+ hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
+ for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+ if (i > hostdata->id_mask)
+ hostdata->id_higher_mask |= i;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
#ifdef SUPPORT_TAGS
- init_tags();
+ init_tags();
#endif
#if defined (REAL_DMA)
- hostdata->dma_len = 0;
+ hostdata->dma_len = 0;
#endif
- hostdata->targets_present = 0;
- hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
-
- if (!the_template) {
- the_template = instance->hostt;
- first_instance = instance;
- }
-
+ hostdata->targets_present = 0;
+ hostdata->connected = NULL;
+ hostdata->issue_queue = NULL;
+ hostdata->disconnected_queue = NULL;
+ hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+ if (!the_template) {
+ the_template = instance->hostt;
+ first_instance = instance;
+ }
#ifndef AUTOSENSE
- if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
- printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
- " without AUTOSENSE option, contingent allegiance conditions may\n"
- " be incorrectly cleared.\n", HOSTNO);
+ if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+ printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+ " without AUTOSENSE option, contingent allegiance conditions may\n"
+ " be incorrectly cleared.\n", HOSTNO);
#endif /* def AUTOSENSE */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
- return 0;
+ return 0;
}
-/*
- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
- * void (*done)(Scsi_Cmnd *))
+/*
+ * our own old-style timeout update
+ */
+/*
+ * The strategy is to cause the timer code to call scsi_times_out()
+ * when the soonest timeout is pending.
+ * The arguments are used when we are queueing a new command, because
+ * we do not want to subtract the time used from this time, but when we
+ * set the timer, we want to take this value into account.
+ */
+
+int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout)
+{
+ int rtn;
+
+ /*
+ * We are using the new error handling code to actually register/deregister
+ * timers for timeout.
+ */
+
+ if (!timer_pending(&SCset->eh_timeout))
+ rtn = 0;
+ else
+ rtn = SCset->eh_timeout.expires - jiffies;
+
+ if (timeout == 0) {
+ del_timer(&SCset->eh_timeout);
+ SCset->eh_timeout.data = (unsigned long)NULL;
+ SCset->eh_timeout.expires = 0;
+ } else {
+ if (SCset->eh_timeout.data != (unsigned long)NULL)
+ del_timer(&SCset->eh_timeout);
+ SCset->eh_timeout.data = (unsigned long)SCset;
+ SCset->eh_timeout.expires = jiffies + timeout;
+ add_timer(&SCset->eh_timeout);
+ }
+ return rtn;
+}
+
+/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
*
* Purpose : enqueues a SCSI command
*
* Inputs : cmd - SCSI command, done - function called on completion, with
* a pointer to the command descriptor.
- *
+ *
* Returns : 0
*
- * Side effects :
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
+ * Side effects :
+ * cmd is added to the per instance issue_queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
* main coroutine is not running, it is restarted.
*
*/
-static
-int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
- SETUP_HOSTDATA(cmd->device->host);
- Scsi_Cmnd *tmp;
- int oldto;
- unsigned long flags;
- extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+ SETUP_HOSTDATA(cmd->device->host);
+ Scsi_Cmnd *tmp;
+ int oldto;
+ unsigned long flags;
+ // extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
#if (NDEBUG & NDEBUG_NO_WRITE)
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
- H_NO(cmd));
- cmd->result = (DID_ERROR << 16);
- done(cmd);
- return 0;
- }
+ switch (cmd->cmnd[0]) {
+ case WRITE_6:
+ case WRITE_10:
+ printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+ H_NO(cmd));
+ cmd->result = (DID_ERROR << 16);
+ done(cmd);
+ return 0;
+ }
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-
#ifdef NCR5380_STATS
# if 0
- if (!hostdata->connected && !hostdata->issue_queue &&
- !hostdata->disconnected_queue) {
- hostdata->timebase = jiffies;
- }
+ if (!hostdata->connected && !hostdata->issue_queue &&
+ !hostdata->disconnected_queue) {
+ hostdata->timebase = jiffies;
+ }
# endif
# ifdef NCR5380_STAT_LIMIT
- if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
# endif
- switch (cmd->cmnd[0])
- {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
- hostdata->pendingw++;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
- hostdata->pendingr++;
- break;
- }
+ switch (cmd->cmnd[0]) {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+ hostdata->pendingw++;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+ hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+ hostdata->pendingr++;
+ break;
+ }
#endif
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
-
- NEXT(cmd) = NULL;
- cmd->scsi_done = done;
-
- cmd->result = 0;
-
-
- /*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
- * commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
- * sense data is only guaranteed to be valid while the condition exists.
- */
-
- local_irq_save(flags);
- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
- * Otherwise a running NCR5380_main may steal the lock.
- * Lock before actually inserting due to fairness reasons explained in
- * atari_scsi.c. If we insert first, then it's impossible for this driver
- * to release the lock.
- * Stop timer for this command while waiting for the lock, or timeouts
- * may happen (and they really do), and it's no good if the command doesn't
- * appear in any of the queues.
- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
- * because also a timer int can trigger an abort or reset, which would
- * alter queues and touch the lock.
- */
- if (!IS_A_TT()) {
- oldto = update_timeout(cmd, 0);
- falcon_get_lock();
- update_timeout(cmd, oldto);
- }
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- NEXT(cmd) = hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
- NEXT(tmp); tmp = NEXT(tmp))
- ;
- LIST(cmd, tmp);
- NEXT(tmp) = cmd;
- }
- local_irq_restore(flags);
-
- QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-
- /* If queue_command() is called from an interrupt (real one or bottom
- * half), we let queue_main() do the job of taking care about main. If it
- * is already running, this is a no-op, else main will be queued.
- *
- * If we're not in an interrupt, we can call NCR5380_main()
- * unconditionally, because it cannot be already running.
- */
- if (in_interrupt() || ((flags >> 8) & 7) >= 6)
- queue_main();
- else
- NCR5380_main(NULL);
- return 0;
+ /*
+ * We use the host_scribble field as a pointer to the next command
+ * in a queue
+ */
+
+ SET_NEXT(cmd, NULL);
+ cmd->scsi_done = done;
+
+ cmd->result = 0;
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ * commands are added to the head of the queue since any command will
+ * clear the contingent allegiance condition that exists and the
+ * sense data is only guaranteed to be valid while the condition exists.
+ */
+
+ local_irq_save(flags);
+ /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+ * Otherwise a running NCR5380_main may steal the lock.
+ * Lock before actually inserting due to fairness reasons explained in
+ * atari_scsi.c. If we insert first, then it's impossible for this driver
+ * to release the lock.
+ * Stop timer for this command while waiting for the lock, or timeouts
+ * may happen (and they really do), and it's no good if the command doesn't
+ * appear in any of the queues.
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which would
+ * alter queues and touch the lock.
+ */
+ if (!IS_A_TT()) {
+ oldto = atari_scsi_update_timeout(cmd, 0);
+ falcon_get_lock();
+ atari_scsi_update_timeout(cmd, oldto);
+ }
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ LIST(cmd, hostdata->issue_queue);
+ SET_NEXT(cmd, hostdata->issue_queue);
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ NEXT(tmp); tmp = NEXT(tmp))
+ ;
+ LIST(cmd, tmp);
+ SET_NEXT(tmp, cmd);
+ }
+ local_irq_restore(flags);
+
+ QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+ /* If queue_command() is called from an interrupt (real one or bottom
+ * half), we let queue_main() do the job of taking care about main. If it
+ * is already running, this is a no-op, else main will be queued.
+ *
+ * If we're not in an interrupt, we can call NCR5380_main()
+ * unconditionally, because it cannot be already running.
+ */
+ if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+ queue_main();
+ else
+ NCR5380_main(NULL);
+ return 0;
}
/*
- * Function : NCR5380_main (void)
+ * Function : NCR5380_main (void)
*
- * Purpose : NCR5380_main is a coroutine that runs as long as more work can
- * be done on the NCR5380 host adapters in a system. Both
- * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
* in case it is not running.
- *
- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
+ *
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
* reenable them. This prevents reentrancy and kernel stack overflow.
- */
-
-static void NCR5380_main (void *bl)
+ */
+
+static void NCR5380_main(struct work_struct *work)
{
- Scsi_Cmnd *tmp, *prev;
- struct Scsi_Host *instance = first_instance;
- struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
- int done;
- unsigned long flags;
-
- /*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set main_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- * this should prevent any race conditions.
- *
- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
- * because also a timer int can trigger an abort or reset, which can
- * alter queues and touch the Falcon lock.
- */
-
- /* Tell int handlers main() is now already executing. Note that
- no races are possible here. If an int comes in before
- 'main_running' is set here, and queues/executes main via the
- task queue, it doesn't do any harm, just this instance of main
- won't find any work left to do. */
- if (main_running)
- return;
- main_running = 1;
-
- local_save_flags(flags);
- do {
- local_irq_disable(); /* Freeze request queues */
- done = 1;
-
- if (!hostdata->connected) {
- MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *instance = first_instance;
+ struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+ int done;
+ unsigned long flags;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set main_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ * this should prevent any race conditions.
+ *
+ * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+ * because also a timer int can trigger an abort or reset, which can
+ * alter queues and touch the Falcon lock.
+ */
+
+ /* Tell int handlers main() is now already executing. Note that
+ no races are possible here. If an int comes in before
+ 'main_running' is set here, and queues/executes main via the
+ task queue, it doesn't do any harm, just this instance of main
+ won't find any work left to do. */
+ if (main_running)
+ return;
+ main_running = 1;
+
+ local_save_flags(flags);
+ do {
+ local_irq_disable(); /* Freeze request queues */
+ done = 1;
+
+ if (!hostdata->connected) {
+ MAIN_PRINTK("scsi%d: not connected\n", HOSTNO);
+ /*
+ * Search through the issue_queue for a command destined
+ * for a target that's not busy.
+ */
#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
- ;
- /*printk("%p ", tmp);*/
- if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+ tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+ ;
+ /*printk("%p ", tmp);*/
+ if ((tmp == prev) && tmp)
+ printk(" LOOP\n");
+ /* else printk("\n"); */
#endif
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
#if (NDEBUG & NDEBUG_LISTS)
- if (prev != tmp)
- printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
- tmp, tmp->device->id, hostdata->busy[tmp->device->id],
- tmp->device->lun);
+ if (prev != tmp)
+ printk("MAIN tmp=%p target=%d busy=%d lun=%d\n",
+ tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+ tmp->device->lun);
#endif
- /* When we find one, remove it from the issue queue. */
- /* ++guenther: possible race with Falcon locking */
- if (
+ /* When we find one, remove it from the issue queue. */
+ /* ++guenther: possible race with Falcon locking */
+ if (
#ifdef SUPPORT_TAGS
- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+ !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
#else
- !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
+ !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
#endif
- ) {
- /* ++guenther: just to be sure, this must be atomic */
- local_irq_disable();
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- NEXT(prev) = NEXT(tmp);
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
- hostdata->issue_queue = NEXT(tmp);
- }
- NEXT(tmp) = NULL;
- falcon_dont_release++;
-
- /* reenable interrupts after finding one */
- local_irq_restore(flags);
-
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- MAIN_PRINTK("scsi%d: main(): command for target %d "
- "lun %d removed from issue_queue\n",
- HOSTNO, tmp->device->id, tmp->device->lun);
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
- /* ++roman: ...and the standard also requires that
- * REQUEST SENSE command are untagged.
- */
-
+ ) {
+ /* ++guenther: just to be sure, this must be atomic */
+ local_irq_disable();
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ SET_NEXT(prev, NEXT(tmp));
+ } else {
+ REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+ hostdata->issue_queue = NEXT(tmp);
+ }
+ SET_NEXT(tmp, NULL);
+ falcon_dont_release++;
+
+ /* reenable interrupts after finding one */
+ local_irq_restore(flags);
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+ MAIN_PRINTK("scsi%d: main(): command for target %d "
+ "lun %d removed from issue_queue\n",
+ HOSTNO, tmp->device->id, tmp->device->lun);
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+ /* ++roman: ...and the standard also requires that
+ * REQUEST SENSE command are untagged.
+ */
+
#ifdef SUPPORT_TAGS
- cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+ cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
#endif
- if (!NCR5380_select(instance, tmp,
- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
- TAG_NEXT)) {
- falcon_dont_release--;
- /* release if target did not response! */
- falcon_release_lock_if_possible( hostdata );
- break;
- } else {
- local_irq_disable();
- LIST(tmp, hostdata->issue_queue);
- NEXT(tmp) = hostdata->issue_queue;
- hostdata->issue_queue = tmp;
+ if (!NCR5380_select(instance, tmp,
+ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+ TAG_NEXT)) {
+ falcon_dont_release--;
+ /* release if target did not response! */
+ falcon_release_lock_if_possible(hostdata);
+ break;
+ } else {
+ local_irq_disable();
+ LIST(tmp, hostdata->issue_queue);
+ SET_NEXT(tmp, hostdata->issue_queue);
+ hostdata->issue_queue = tmp;
#ifdef SUPPORT_TAGS
- cmd_free_tag( tmp );
+ cmd_free_tag(tmp);
#endif
- falcon_dont_release--;
- local_irq_restore(flags);
- MAIN_PRINTK("scsi%d: main(): select() failed, "
- "returned to issue_queue\n", HOSTNO);
- if (hostdata->connected)
- break;
- }
- } /* if target/lun/target queue is not busy */
- } /* for issue_queue */
- } /* if (!hostdata->connected) */
-
- if (hostdata->connected
+ falcon_dont_release--;
+ local_irq_restore(flags);
+ MAIN_PRINTK("scsi%d: main(): select() failed, "
+ "returned to issue_queue\n", HOSTNO);
+ if (hostdata->connected)
+ break;
+ }
+ } /* if target/lun/target queue is not busy */
+ } /* for issue_queue */
+ } /* if (!hostdata->connected) */
+
+ if (hostdata->connected
#ifdef REAL_DMA
- && !hostdata->dma_len
+ && !hostdata->dma_len
#endif
- ) {
- local_irq_restore(flags);
- MAIN_PRINTK("scsi%d: main: performing information transfer\n",
- HOSTNO);
- NCR5380_information_transfer(instance);
- MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
- done = 0;
- }
- } while (!done);
+ ) {
+ local_irq_restore(flags);
+ MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+ HOSTNO);
+ NCR5380_information_transfer(instance);
+ MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+ done = 0;
+ }
+ } while (!done);
- /* Better allow ints _after_ 'main_running' has been cleared, else
- an interrupt could believe we'll pick up the work it left for
- us, but we won't see it anymore here... */
- main_running = 0;
- local_irq_restore(flags);
+ /* Better allow ints _after_ 'main_running' has been cleared, else
+ an interrupt could believe we'll pick up the work it left for
+ us, but we won't see it anymore here... */
+ main_running = 0;
+ local_irq_restore(flags);
}
@@ -1183,1441 +1236,1439 @@ static void NCR5380_main (void *bl)
* Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
*
* Purpose : Called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
+ * mismatch occurs (which would finish the DMA transfer).
*
* Inputs : instance - this instance of the NCR5380.
*
*/
-static void NCR5380_dma_complete( struct Scsi_Host *instance )
+static void NCR5380_dma_complete(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
- unsigned char **data, p;
- volatile int *count;
-
- if (!hostdata->connected) {
- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
- "no connected cmd\n", HOSTNO);
- return;
- }
-
- if (atari_read_overruns) {
- p = hostdata->connected->SCp.phase;
- if (p & SR_IO) {
- udelay(10);
- if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
- (BASR_PHASE_MATCH|BASR_ACK)) ==
- (BASR_PHASE_MATCH|BASR_ACK))) {
- saved_data = NCR5380_read(INPUT_DATA_REG);
- overrun = 1;
- DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
- }
+ SETUP_HOSTDATA(instance);
+ int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+ unsigned char **data, p;
+ volatile int *count;
+
+ if (!hostdata->connected) {
+ printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+ "no connected cmd\n", HOSTNO);
+ return;
}
- }
-
- DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
-
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
- hostdata->dma_len = 0;
-
- data = (unsigned char **) &(hostdata->connected->SCp.ptr);
- count = &(hostdata->connected->SCp.this_residual);
- *data += transfered;
- *count -= transfered;
-
- if (atari_read_overruns) {
- if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
- cnt = toPIO = atari_read_overruns;
- if (overrun) {
- DMA_PRINTK("Got an input overrun, using saved byte\n");
- *(*data)++ = saved_data;
- (*count)--;
- cnt--;
- toPIO--;
- }
- DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
- NCR5380_transfer_pio(instance, &p, &cnt, data);
- *count -= toPIO - cnt;
+
+ if (atari_read_overruns) {
+ p = hostdata->connected->SCp.phase;
+ if (p & SR_IO) {
+ udelay(10);
+ if ((NCR5380_read(BUS_AND_STATUS_REG) &
+ (BASR_PHASE_MATCH|BASR_ACK)) ==
+ (BASR_PHASE_MATCH|BASR_ACK)) {
+ saved_data = NCR5380_read(INPUT_DATA_REG);
+ overrun = 1;
+ DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
+ }
+ }
+ }
+
+ DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+ HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
+
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+ hostdata->dma_len = 0;
+
+ data = (unsigned char **)&hostdata->connected->SCp.ptr;
+ count = &hostdata->connected->SCp.this_residual;
+ *data += transfered;
+ *count -= transfered;
+
+ if (atari_read_overruns) {
+ if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+ cnt = toPIO = atari_read_overruns;
+ if (overrun) {
+ DMA_PRINTK("Got an input overrun, using saved byte\n");
+ *(*data)++ = saved_data;
+ (*count)--;
+ cnt--;
+ toPIO--;
+ }
+ DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
+ NCR5380_transfer_pio(instance, &p, &cnt, data);
+ *count -= toPIO - cnt;
+ }
}
- }
}
#endif /* REAL_DMA */
/*
* Function : void NCR5380_intr (int irq)
- *
+ *
* Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- * from the disconnected queue, and restarting NCR5380_main()
+ * from the disconnected queue, and restarting NCR5380_main()
* as required.
*
* Inputs : int irq, irq that caused this interrupt.
*
*/
-static irqreturn_t NCR5380_intr (int irq, void *dev_id)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
- struct Scsi_Host *instance = first_instance;
- int done = 1, handled = 0;
- unsigned char basr;
-
- INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
-
- /* Look for pending interrupts */
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
- /* dispatch to appropriate routine if found and done=0 */
- if (basr & BASR_IRQ) {
- NCR_PRINT(NDEBUG_INTR);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
- done = 0;
- ENABLE_IRQ();
- INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
- NCR5380_reselect(instance);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else if (basr & BASR_PARITY_ERROR) {
- INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else {
- /*
- * The rest of the interrupt conditions can occur only during a
- * DMA transfer
- */
+ struct Scsi_Host *instance = first_instance;
+ int done = 1, handled = 0;
+ unsigned char basr;
+
+ INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+ /* Look for pending interrupts */
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+ /* dispatch to appropriate routine if found and done=0 */
+ if (basr & BASR_IRQ) {
+ NCR_PRINT(NDEBUG_INTR);
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+ done = 0;
+ ENABLE_IRQ();
+ INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+ NCR5380_reselect(instance);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else if (basr & BASR_PARITY_ERROR) {
+ INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+ INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else {
+ /*
+ * The rest of the interrupt conditions can occur only during a
+ * DMA transfer
+ */
#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts if we have
- * DMA enabled, so do a sanity check based on the current setting
- * of the MODE register.
- */
-
- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
- ((basr & BASR_END_DMA_TRANSFER) ||
- !(basr & BASR_PHASE_MATCH))) {
-
- INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
- NCR5380_dma_complete( instance );
- done = 0;
- ENABLE_IRQ();
- } else
+ /*
+ * We should only get PHASE MISMATCH and EOP interrupts if we have
+ * DMA enabled, so do a sanity check based on the current setting
+ * of the MODE register.
+ */
+
+ if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+ ((basr & BASR_END_DMA_TRANSFER) ||
+ !(basr & BASR_PHASE_MATCH))) {
+
+ INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+ NCR5380_dma_complete( instance );
+ done = 0;
+ ENABLE_IRQ();
+ } else
#endif /* REAL_DMA */
- {
+ {
/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
- if (basr & BASR_PHASE_MATCH)
- printk(KERN_NOTICE "scsi%d: unknown interrupt, "
- "BASR 0x%x, MR 0x%x, SR 0x%x\n",
- HOSTNO, basr, NCR5380_read(MODE_REG),
- NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- } /* if !(SELECTION || PARITY) */
- handled = 1;
- } /* BASR & IRQ */
- else {
- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
-
- if (!done) {
- INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
- /* Put a call to NCR5380_main() on the queue... */
- queue_main();
- }
- return IRQ_RETVAL(handled);
+ if (basr & BASR_PHASE_MATCH)
+ printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+ "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+ HOSTNO, basr, NCR5380_read(MODE_REG),
+ NCR5380_read(STATUS_REG));
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+ } /* if !(SELECTION || PARITY) */
+ handled = 1;
+ } /* BASR & IRQ */ else {
+ printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+ "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+ NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ }
+
+ if (!done) {
+ INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+ /* Put a call to NCR5380_main() on the queue... */
+ queue_main();
+ }
+ return IRQ_RETVAL(handled);
}
#ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
{
# ifdef NCR5380_STAT_LIMIT
- if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+ if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
# endif
- switch (cmd->cmnd[0])
- {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
- hostdata->pendingw--;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
- hostdata->pendingr--;
- break;
- }
+ switch (cmd->cmnd[0]) {
+ case WRITE:
+ case WRITE_6:
+ case WRITE_10:
+ hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+ hostdata->pendingw--;
+ break;
+ case READ:
+ case READ_6:
+ case READ_10:
+ hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+ /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+ hostdata->pendingr--;
+ break;
+ }
}
#endif
-/*
- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+/*
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
* int tag);
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
*
- * Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
* the command that is presently connected.
- *
+ *
* Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
+ * 0 if selection succeeded or failed because the target
+ * did not respond.
*
- * Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
* with registers as they should have been on entry - ie
* SELECT_ENABLE will be set appropriately, the NCR5380
* will cease to drive any SCSI bus signals.
*
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
*
- * If failed (no target) : cmd->scsi_done() will be called, and the
+ * If failed (no target) : cmd->scsi_done() will be called, and the
* cmd->result host byte set to DID_BAD_TARGET.
*/
-static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
{
- SETUP_HOSTDATA(instance);
- unsigned char tmp[3], phase;
- unsigned char *data;
- int len;
- unsigned long timeout;
- unsigned long flags;
-
- hostdata->restart_select = 0;
- NCR_PRINT(NDEBUG_ARBITRATION);
- ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
- instance->this_id);
-
- /*
- * Set the phase bits to 0, otherwise the NCR5380 won't drive the
- * data bus during SELECTION.
- */
-
- local_irq_save(flags);
- if (hostdata->connected) {
+ SETUP_HOSTDATA(instance);
+ unsigned char tmp[3], phase;
+ unsigned char *data;
+ int len;
+ unsigned long timeout;
+ unsigned long flags;
+
+ hostdata->restart_select = 0;
+ NCR_PRINT(NDEBUG_ARBITRATION);
+ ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+ instance->this_id);
+
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ * data bus during SELECTION.
+ */
+
+ local_irq_save(flags);
+ if (hostdata->connected) {
+ local_irq_restore(flags);
+ return -1;
+ }
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /*
+ * Start arbitration.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+ NCR5380_write(MODE_REG, MR_ARBITRATE);
+
local_irq_restore(flags);
- return -1;
- }
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
-
- /*
- * Start arbitration.
- */
-
- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
- NCR5380_write(MODE_REG, MR_ARBITRATE);
-
- local_irq_restore(flags);
-
- /* Wait for arbitration logic to complete */
-#if NCR_TIMEOUT
- {
- unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
-
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && time_before(jiffies, timeout) && !hostdata->connected)
- ;
- if (time_after_eq(jiffies, timeout))
- {
- printk("scsi : arbitration timeout at %d\n", __LINE__);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- }
+
+ /* Wait for arbitration logic to complete */
+#if defined(NCR_TIMEOUT)
+ {
+ unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
+ time_before(jiffies, timeout) && !hostdata->connected)
+ ;
+ if (time_after_eq(jiffies, timeout)) {
+ printk("scsi : arbitration timeout at %d\n", __LINE__);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ }
#else /* NCR_TIMEOUT */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && !hostdata->connected);
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) &&
+ !hostdata->connected)
+ ;
#endif
- ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
-
- if (hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- return -1;
- }
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
-
- udelay(3);
-
- /* Check for lost arbitration */
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
- HOSTNO);
- return -1;
- }
-
- /* after/during arbitration, BSY should be asserted.
- IBM DPES-31080 Version S31Q works now */
- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
- ICR_ASSERT_BSY ) ;
-
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
- HOSTNO);
- return -1;
- }
+ ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
- /*
- * Again, bus clear + bus settle time is 1.2us, however, this is
- * a minimum so we'll udelay ceil(1.2)
- */
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ return -1;
+ }
+ /*
+ * The arbitration delay is 2.2us, but this is a minimum and there is
+ * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+ * the integral nature of udelay().
+ *
+ */
+
+ udelay(3);
+
+ /* Check for lost arbitration */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /* after/during arbitration, BSY should be asserted.
+ IBM DPES-31080 Version S31Q works now */
+ /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+ NCR5380_write(INITIATOR_COMMAND_REG,
+ ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY);
+
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+ HOSTNO);
+ return -1;
+ }
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
+ * a minimum so we'll udelay ceil(1.2)
+ */
#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
- /* ++roman: But some targets (see above :-) seem to need a bit more... */
- udelay(15);
+ /* ++roman: But some targets (see above :-) seem to need a bit more... */
+ udelay(15);
#else
- udelay(2);
+ udelay(2);
#endif
-
- if (hostdata->connected) {
+
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
+ ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
+ * the host and target ID's on the SCSI bus.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+
+ /*
+ * Raise ATN while SEL is true before BSY goes false from arbitration,
+ * since this is the only way to guarantee that we'll get a MESSAGE OUT
+ * phase immediately after selection.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
- ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+ /*
+ * Reselect interrupts must be turned off prior to the dropping of BSY,
+ * otherwise we will trigger an interrupt.
+ */
+
+ if (hostdata->connected) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
- /*
- * Now that we have won arbitration, start Selection process, asserting
- * the host and target ID's on the SCSI bus.
- */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /*
+ * The initiator shall then wait at least two deskew delays and release
+ * the BSY signal.
+ */
+ udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
+
+ /* Reset BSY */
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+ /*
+ * Something weird happens when we cease to drive BSY - looks
+ * like the board/chip is letting us do another read before the
+ * appropriate propagation delay has expired, and we're confusing
+ * a BSY signal from ourselves as the target's response to SELECTION.
+ *
+ * A small delay (the 'C++' frontend breaks the pipeline with an
+ * unnecessary jump, making it work on my 386-33/Trantor T128, the
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
+ * work there.
+ *
+ * wingel suggests that this could be due to failing to wait
+ * one deskew delay.
+ */
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+ udelay(1);
- /*
- * Raise ATN while SEL is true before BSY goes false from arbitration,
- * since this is the only way to guarantee that we'll get a MESSAGE OUT
- * phase immediately after selection.
- */
+ SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
- NCR5380_write(MODE_REG, MR_BASE);
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
+ * selection.
+ */
- /*
- * Reselect interrupts must be turned off prior to the dropping of BSY,
- * otherwise we will trigger an interrupt.
- */
+ timeout = jiffies + 25;
- if (hostdata->connected) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
-
- NCR5380_write(SELECT_ENABLE_REG, 0);
-
- /*
- * The initiator shall then wait at least two deskew delays and release
- * the BSY signal.
- */
- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
-
- /* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
- ICR_ASSERT_ATN | ICR_ASSERT_SEL));
-
- /*
- * Something weird happens when we cease to drive BSY - looks
- * like the board/chip is letting us do another read before the
- * appropriate propagation delay has expired, and we're confusing
- * a BSY signal from ourselves as the target's response to SELECTION.
- *
- * A small delay (the 'C++' frontend breaks the pipeline with an
- * unnecessary jump, making it work on my 386-33/Trantor T128, the
- * tighter 'C' code breaks and requires this) solves the problem -
- * the 1 us delay is arbitrary, and only used because this delay will
- * be the same on other platforms and since it works here, it should
- * work there.
- *
- * wingel suggests that this could be due to failing to wait
- * one deskew delay.
- */
-
- udelay(1);
-
- SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
-
- /*
- * The SCSI specification calls for a 250 ms timeout for the actual
- * selection.
- */
-
- timeout = jiffies + 25;
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
+ /*
+ * XXX very interesting - we're seeing a bounce where the BSY we
+ * asserted is being reflected / still asserted (propagation delay?)
+ * and it's detecting as true. Sigh.
+ */
#if 0
- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
- * IO while SEL is true. But again, there are some disks out the in the
- * world that do that nevertheless. (Somebody claimed that this announces
- * reselection capability of the target.) So we better skip that test and
- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
- */
-
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
- (SR_BSY | SR_IO)));
-
- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
- (SR_SEL | SR_IO)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_reselect(instance);
- printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
- HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
+ /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+ * IO while SEL is true. But again, there are some disks out the in the
+ * world that do that nevertheless. (Somebody claimed that this announces
+ * reselection capability of the target.) So we better skip that test and
+ * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+ */
+
+ while (time_before(jiffies, timeout) &&
+ !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO)))
+ ;
+
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_reselect(instance);
+ printk(KERN_ERR "scsi%d: reselection after won arbitration?\n",
+ HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
#else
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+ while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY))
+ ;
#endif
- /*
- * No less than two deskew delays after the initiator detects the
- * BSY signal is true, it shall release the SEL signal and may
- * change the DATA BUS. -wingel
- */
+ /*
+ * No less than two deskew delays after the initiator detects the
+ * BSY signal is true, it shall release the SEL signal and may
+ * change the DATA BUS. -wingel
+ */
- udelay(1);
+ udelay(1);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->device->id)) {
- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
- if (hostdata->restart_select)
- printk(KERN_NOTICE "\trestart select\n");
- NCR_PRINT(NDEBUG_ANY);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
+ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ if (hostdata->targets_present & (1 << cmd->device->id)) {
+ printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+ if (hostdata->restart_select)
+ printk(KERN_NOTICE "\trestart select\n");
+ NCR_PRINT(NDEBUG_ANY);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return -1;
+ }
+ cmd->result = DID_BAD_TARGET << 16;
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
+ cmd_free_tag(cmd);
#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
-
- hostdata->targets_present |= (1 << cmd->device->id);
-
- /*
- * Since we followed the SCSI spec, and raised ATN while SEL
- * was true but before BSY was false during selection, the information
- * transfer phase should be a MESSAGE OUT phase so that we can send the
- * IDENTIFY message.
- *
- * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
- * message (2 bytes) with a tag ID that we increment with every command
- * until it wraps back to 0.
- *
- * XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
- */
-
- /* Wait for start of REQ/ACK handshake */
- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
- SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->device->id);
- tmp[0] = IDENTIFY(1, cmd->device->lun);
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return 0;
+ }
+
+ hostdata->targets_present |= (1 << cmd->device->id);
+
+ /*
+ * Since we followed the SCSI spec, and raised ATN while SEL
+ * was true but before BSY was false during selection, the information
+ * transfer phase should be a MESSAGE OUT phase so that we can send the
+ * IDENTIFY message.
+ *
+ * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+ * message (2 bytes) with a tag ID that we increment with every command
+ * until it wraps back to 0.
+ *
+ * XXX - it turns out that there are some broken SCSI-II devices,
+ * which claim to support tagged queuing but fail when more than
+ * some number of commands are issued at once.
+ */
+
+ /* Wait for start of REQ/ACK handshake */
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ))
+ ;
+
+ SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+ HOSTNO, cmd->device->id);
+ tmp[0] = IDENTIFY(1, cmd->device->lun);
#ifdef SUPPORT_TAGS
- if (cmd->tag != TAG_NONE) {
- tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
- tmp[2] = cmd->tag;
- len = 3;
- } else
- len = 1;
+ if (cmd->tag != TAG_NONE) {
+ tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+ tmp[2] = cmd->tag;
+ len = 3;
+ } else
+ len = 1;
#else
- len = 1;
- cmd->tag=0;
+ len = 1;
+ cmd->tag = 0;
#endif /* SUPPORT_TAGS */
- /* Send message(s) */
- data = tmp;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
- /* XXX need to handle errors here */
- hostdata->connected = cmd;
+ /* Send message(s) */
+ data = tmp;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+ /* XXX need to handle errors here */
+ hostdata->connected = cmd;
#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-#endif
-
- initialize_SCp(cmd);
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+#endif
+ initialize_SCp(cmd);
- return 0;
+ return 0;
}
-/*
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
* unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using polled I/O
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
* bytes to transfer, **data - pointer to data pointer.
- *
+ *
* Returns : -1 when different phase is entered without transferring
* maximum number of bytes, 0 if all bytes are transfered or exit
* is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
* XXX Note : handling for bus free may be useful.
*/
/*
- * Note : this code is not as quick as it could be, however it
+ * Note : this code is not as quick as it could be, however it
* IS 100% reliable, and for the actual data transfer where speed
* counts, we will always do a pseudo DMA or DMA transfer.
*/
-static int NCR5380_transfer_pio( struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
+static int NCR5380_transfer_pio(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
{
- register unsigned char p = *phase, tmp;
- register int c = *count;
- register unsigned char *d = *data;
-
- /*
- * The NCR5380 chip will only drive the SCSI bus when the
- * phase specified in the appropriate bits of the TARGET COMMAND
- * REGISTER match the STATUS REGISTER
- */
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
- do {
- /*
- * Wait for assertion of REQ, after which the phase bits will be
- * valid
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
+ * phase specified in the appropriate bits of the TARGET COMMAND
+ * REGISTER match the STATUS REGISTER
*/
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
- HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
- /* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
- NCR_PRINT_PHASE(NDEBUG_PIO);
- break;
- }
+ do {
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
+ */
+ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ))
+ ;
- /* Do actual transfer from SCSI bus to / from memory */
- if (!(p & SR_IO))
- NCR5380_write(OUTPUT_DATA_REG, *d);
- else
- *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
- ++d;
+ /* Check for phase mismatch */
+ if ((tmp & PHASE_MASK) != p) {
+ PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+ NCR_PRINT_PHASE(NDEBUG_PIO);
+ break;
+ }
- /*
- * The SCSI standard suggests that in MSGOUT phase, the initiator
- * should drop ATN on the last byte of the message phase
- * after REQ has been asserted for the handshake but before
- * the initiator raises ACK.
- */
+ /* Do actual transfer from SCSI bus to / from memory */
+ if (!(p & SR_IO))
+ NCR5380_write(OUTPUT_DATA_REG, *d);
+ else
+ *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
- if (!(p & SR_IO)) {
- if (!((p & SR_MSG) && c > 1)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA);
- NCR_PRINT(NDEBUG_PIO);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
- } else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
- NCR_PRINT(NDEBUG_PIO);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- }
- } else {
- NCR_PRINT(NDEBUG_PIO);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
- }
+ ++d;
- while (NCR5380_read(STATUS_REG) & SR_REQ);
+ /*
+ * The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ */
- HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+ if (!(p & SR_IO)) {
+ if (!((p & SR_MSG) && c > 1)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ } else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ }
+ } else {
+ NCR_PRINT(NDEBUG_PIO);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ }
-/*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
- *
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
- *
- * 3. ACK and ATN are clear and the target may proceed as normal.
- */
- if (!(p == PHASE_MSGIN && c == 1)) {
- if (p == PHASE_MSGOUT && c > 1)
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- else
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- }
- } while (--c);
-
- PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
-
- *count = c;
- *data = d;
- tmp = NCR5380_read(STATUS_REG);
- /* The phase read from the bus is valid if either REQ is (already)
- * asserted or if ACK hasn't been released yet. The latter is the case if
- * we're in MSGIN and all wanted bytes have been received. */
- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
- *phase = tmp & PHASE_MASK;
- else
- *phase = PHASE_UNKNOWN;
-
- if (!c || (*phase == p))
- return 0;
- else
- return -1;
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+
+ HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+ /*
+ * We have several special cases to consider during REQ/ACK handshaking :
+ * 1. We were in MSGOUT phase, and we are on the last byte of the
+ * message. ATN must be dropped as ACK is dropped.
+ *
+ * 2. We are in a MSGIN phase, and we are on the last byte of the
+ * message. We must exit with ACK asserted, so that the calling
+ * code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3. ACK and ATN are clear and the target may proceed as normal.
+ */
+ if (!(p == PHASE_MSGIN && c == 1)) {
+ if (p == PHASE_MSGOUT && c > 1)
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ else
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ }
+ } while (--c);
+
+ PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+ *count = c;
+ *data = d;
+ tmp = NCR5380_read(STATUS_REG);
+ /* The phase read from the bus is valid if either REQ is (already)
+ * asserted or if ACK hasn't been released yet. The latter is the case if
+ * we're in MSGIN and all wanted bytes have been received.
+ */
+ if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+ *phase = tmp & PHASE_MASK;
+ else
+ *phase = PHASE_UNKNOWN;
+
+ if (!c || (*phase == p))
+ return 0;
+ else
+ return -1;
}
/*
* Function : do_abort (Scsi_Host *host)
- *
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
- *
+ *
+ * Purpose : abort the currently established nexus. Should only be
+ * called from a routine which can drop into a
+ *
* Returns : 0 on success, -1 on failure.
*/
-static int do_abort (struct Scsi_Host *host)
+static int do_abort(struct Scsi_Host *host)
{
- unsigned char tmp, *msgptr, phase;
- int len;
-
- /* Request message out phase */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
- /*
- * Wait for the target to indicate a valid phase by asserting
- * REQ. Once this happens, we'll have either a MSGOUT phase
- * and can immediately send the ABORT message, or we'll have some
- * other phase and will have to source/sink data.
- *
- * We really don't care what value was on the bus or what value
- * the target sees, so we just handshake.
- */
-
- while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
+ unsigned char tmp, *msgptr, phase;
+ int len;
+
+ /* Request message out phase */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- }
-
- tmp = ABORT;
- msgptr = &tmp;
- len = 1;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio (host, &phase, &len, &msgptr);
-
- /*
- * If we got here, and the command completed successfully,
- * we're about to go into bus free state.
- */
-
- return len ? -1 : 0;
+
+ /*
+ * Wait for the target to indicate a valid phase by asserting
+ * REQ. Once this happens, we'll have either a MSGOUT phase
+ * and can immediately send the ABORT message, or we'll have some
+ * other phase and will have to source/sink data.
+ *
+ * We really don't care what value was on the bus or what value
+ * the target sees, so we just handshake.
+ */
+
+ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
+ ;
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ }
+
+ tmp = ABORT;
+ msgptr = &tmp;
+ len = 1;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+
+ /*
+ * If we got here, and the command completed successfully,
+ * we're about to go into bus free state.
+ */
+
+ return len ? -1 : 0;
}
#if defined(REAL_DMA)
-/*
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
* unsigned char *phase, int *count, unsigned char **data)
*
* Purpose : transfers data in given phase using either real
* or pseudo DMA.
*
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
* bytes to transfer, **data - pointer to data pointer.
- *
+ *
* Returns : -1 when different phase is entered without transferring
* maximum number of bytes, 0 if all bytes or transfered or exit
* is in same phase.
*
- * Also, *phase, *count, *data are modified in place.
+ * Also, *phase, *count, *data are modified in place.
*
*/
-static int NCR5380_transfer_dma( struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
+static int NCR5380_transfer_dma(struct Scsi_Host *instance,
+ unsigned char *phase, int *count,
+ unsigned char **data)
{
- SETUP_HOSTDATA(instance);
- register int c = *count;
- register unsigned char p = *phase;
- register unsigned char *d = *data;
- unsigned char tmp;
- unsigned long flags;
-
- if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
- *phase = tmp;
- return -1;
- }
+ SETUP_HOSTDATA(instance);
+ register int c = *count;
+ register unsigned char p = *phase;
+ register unsigned char *d = *data;
+ unsigned char tmp;
+ unsigned long flags;
+
+ if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+ *phase = tmp;
+ return -1;
+ }
- if (atari_read_overruns && (p & SR_IO)) {
- c -= atari_read_overruns;
- }
+ if (atari_read_overruns && (p & SR_IO))
+ c -= atari_read_overruns;
- DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- HOSTNO, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", d);
+ DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+ HOSTNO, (p & SR_IO) ? "reading" : "writing",
+ c, (p & SR_IO) ? "to" : "from", d);
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
#ifdef REAL_DMA
- NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
#endif /* def REAL_DMA */
- if (IS_A_TT()) {
- /* On the Medusa, it is a must to initialize the DMA before
- * starting the NCR. This is also the cleaner way for the TT.
- */
- local_irq_save(flags);
- hostdata->dma_len = (p & SR_IO) ?
- NCR5380_dma_read_setup(instance, d, c) :
- NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
- }
-
- if (p & SR_IO)
- NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
- else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
- NCR5380_write(START_DMA_SEND_REG, 0);
- }
-
- if (!IS_A_TT()) {
- /* On the Falcon, the DMA setup must be done after the last */
- /* NCR access, else the DMA setup gets trashed!
- */
- local_irq_save(flags);
- hostdata->dma_len = (p & SR_IO) ?
- NCR5380_dma_read_setup(instance, d, c) :
- NCR5380_dma_write_setup(instance, d, c);
- local_irq_restore(flags);
- }
- return 0;
+ if (IS_A_TT()) {
+ /* On the Medusa, it is a must to initialize the DMA before
+ * starting the NCR. This is also the cleaner way for the TT.
+ */
+ local_irq_save(flags);
+ hostdata->dma_len = (p & SR_IO) ?
+ NCR5380_dma_read_setup(instance, d, c) :
+ NCR5380_dma_write_setup(instance, d, c);
+ local_irq_restore(flags);
+ }
+
+ if (p & SR_IO)
+ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+ else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+ NCR5380_write(START_DMA_SEND_REG, 0);
+ }
+
+ if (!IS_A_TT()) {
+ /* On the Falcon, the DMA setup must be done after the last */
+ /* NCR access, else the DMA setup gets trashed!
+ */
+ local_irq_save(flags);
+ hostdata->dma_len = (p & SR_IO) ?
+ NCR5380_dma_read_setup(instance, d, c) :
+ NCR5380_dma_write_setup(instance, d, c);
+ local_irq_restore(flags);
+ }
+ return 0;
}
#endif /* defined(REAL_DMA) */
/*
* Function : NCR5380_information_transfer (struct Scsi_Host *instance)
*
- * Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
* instance->connected.
*
* Inputs : instance, instance for which we are doing commands
*
- * Side effects : SCSI things happen, the disconnected queue will be
+ * Side effects : SCSI things happen, the disconnected queue will be
* modified if a command disconnects, *instance->connected will
* change.
*
- * XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
*/
-
-static void NCR5380_information_transfer (struct Scsi_Host *instance)
+
+static void NCR5380_information_transfer(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- unsigned long flags;
- unsigned char msgout = NOP;
- int sink = 0;
- int len;
+ SETUP_HOSTDATA(instance);
+ unsigned long flags;
+ unsigned char msgout = NOP;
+ int sink = 0;
+ int len;
#if defined(REAL_DMA)
- int transfersize;
+ int transfersize;
#endif
- unsigned char *data;
- unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+ unsigned char *data;
+ unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
+ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+ while (1) {
+ tmp = NCR5380_read(STATUS_REG);
+ /* We only have a valid SCSI phase when REQ is asserted */
+ if (tmp & SR_REQ) {
+ phase = (tmp & PHASE_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+ NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+ }
- while (1) {
- tmp = NCR5380_read(STATUS_REG);
- /* We only have a valid SCSI phase when REQ is asserted */
- if (tmp & SR_REQ) {
- phase = (tmp & PHASE_MASK);
- if (phase != old_phase) {
- old_phase = phase;
- NCR_PRINT_PHASE(NDEBUG_INFORMATION);
- }
-
- if (sink && (phase != PHASE_MSGOUT)) {
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 0;
- continue;
- }
-
- switch (phase) {
- case PHASE_DATAOUT:
+ if (sink && (phase != PHASE_MSGOUT)) {
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
+ ICR_ASSERT_ACK);
+ while (NCR5380_read(STATUS_REG) & SR_REQ)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 0;
+ continue;
+ }
+
+ switch (phase) {
+ case PHASE_DATAOUT:
#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
- "aborted\n", HOSTNO);
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
- return;
+ printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+ "aborted\n", HOSTNO);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ return;
#endif
- case PHASE_DATAIN:
- /*
- * If there is no room left in the current buffer in the
- * scatter-gather list, move onto the next one.
- */
-
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
- cmd->SCp.buffer->offset;
- /* ++roman: Try to merge some scatter-buffers if
- * they are at contiguous physical addresses.
- */
- merge_contiguous_buffers( cmd );
- INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
- HOSTNO, cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
- }
-
- /*
- * The preferred transfer method is going to be
- * PSEUDO-DMA for systems that are strictly PIO,
- * since we can let the hardware do the handshaking.
- *
- * For this to work, we need to know the transfersize
- * ahead of time, since the pseudo-DMA code will sit
- * in an unconditional loop.
- */
-
-/* ++roman: I suggest, this should be
- * #if def(REAL_DMA)
- * instead of leaving REAL_DMA out.
- */
+ case PHASE_DATAIN:
+ /*
+ * If there is no room left in the current buffer in the
+ * scatter-gather list, move onto the next one.
+ */
+
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
+ cmd->SCp.buffer->offset;
+ /* ++roman: Try to merge some scatter-buffers if
+ * they are at contiguous physical addresses.
+ */
+ merge_contiguous_buffers(cmd);
+ INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+ HOSTNO, cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
+ }
+
+ /*
+ * The preferred transfer method is going to be
+ * PSEUDO-DMA for systems that are strictly PIO,
+ * since we can let the hardware do the handshaking.
+ *
+ * For this to work, we need to know the transfersize
+ * ahead of time, since the pseudo-DMA code will sit
+ * in an unconditional loop.
+ */
+
+ /* ++roman: I suggest, this should be
+ * #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
#if defined(REAL_DMA)
- if (!cmd->device->borken &&
- (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
- len = transfersize;
- cmd->SCp.phase = phase;
- if (NCR5380_transfer_dma(instance, &phase,
- &len, (unsigned char **) &cmd->SCp.ptr)) {
- /*
- * If the watchdog timer fires, all future
- * accesses to this device will use the
- * polled-IO. */
- printk(KERN_NOTICE "scsi%d: switching target %d "
- "lun %d to slow handshake\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
- cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- cmd->done(cmd);
- /* XXX - need to source or sink data here, as appropriate */
- } else {
+ if (!cmd->device->borken &&
+ (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+ len = transfersize;
+ cmd->SCp.phase = phase;
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **)&cmd->SCp.ptr)) {
+ /*
+ * If the watchdog timer fires, all future
+ * accesses to this device will use the
+ * polled-IO. */
+ printk(KERN_NOTICE "scsi%d: switching target %d "
+ "lun %d to slow handshake\n", HOSTNO,
+ cmd->device->id, cmd->device->lun);
+ cmd->device->borken = 1;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ sink = 1;
+ do_abort(instance);
+ cmd->result = DID_ERROR << 16;
+ cmd->done(cmd);
+ /* XXX - need to source or sink data here, as appropriate */
+ } else {
#ifdef REAL_DMA
- /* ++roman: When using real DMA,
- * information_transfer() should return after
- * starting DMA since it has nothing more to
- * do.
- */
- return;
-#else
- cmd->SCp.this_residual -= transfersize - len;
+ /* ++roman: When using real DMA,
+ * information_transfer() should return after
+ * starting DMA since it has nothing more to
+ * do.
+ */
+ return;
+#else
+ cmd->SCp.this_residual -= transfersize - len;
#endif
- }
- } else
+ }
+ } else
#endif /* defined(REAL_DMA) */
- NCR5380_transfer_pio(instance, &phase,
- (int *) &cmd->SCp.this_residual, (unsigned char **)
- &cmd->SCp.ptr);
- break;
- case PHASE_MSGIN:
- len = 1;
- data = &tmp;
- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- cmd->SCp.Message = tmp;
-
- switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
+ NCR5380_transfer_pio(instance, &phase,
+ (int *)&cmd->SCp.this_residual,
+ (unsigned char **)&cmd->SCp.ptr);
+ break;
+ case PHASE_MSGIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Message = tmp;
+
+ switch (tmp) {
+ /*
+ * Linking lets us reduce the time required to get the
+ * next command out to the device, hopefully this will
+ * mean we don't waste another revolution due to the delays
+ * required by ARBITRATION and another SELECTION.
+ *
+ * In the current implementation proposal, low level drivers
+ * merely have to start the next command, pointed to by
+ * next_link, done() is called as with unlinked commands.
+ */
#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- LNK_PRINTK("scsi%d: target %d lun %d linked command "
- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Sanity check : A linked command should only terminate
- * with one of these messages if there are more linked
- * commands available.
- */
-
- if (!cmd->next_link) {
- printk(KERN_NOTICE "scsi%d: target %d lun %d "
- "linked command complete, no next_link\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort (instance);
- return;
- }
-
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process; copy it
- * and don't free it! */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- LNK_PRINTK("scsi%d: target %d lun %d linked request "
- "done, calling scsi_done().\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
+ case LINKED_CMD_COMPLETE:
+ case LINKED_FLG_CMD_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ LNK_PRINTK("scsi%d: target %d lun %d linked command "
+ "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Sanity check : A linked command should only terminate
+ * with one of these messages if there are more linked
+ * commands available.
+ */
+
+ if (!cmd->next_link) {
+ printk(KERN_NOTICE "scsi%d: target %d lun %d "
+ "linked command complete, no next_link\n",
+ HOSTNO, cmd->device->id, cmd->device->lun);
+ sink = 1;
+ do_abort(instance);
+ return;
+ }
+
+ initialize_SCp(cmd->next_link);
+ /* The next command is still part of this process; copy it
+ * and don't free it! */
+ cmd->next_link->tag = cmd->tag;
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ LNK_PRINTK("scsi%d: target %d lun %d linked request "
+ "done, calling scsi_done().\n",
+ HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
+ cmd->scsi_done(cmd);
+ cmd = hostdata->connected;
+ break;
#endif /* def LINKED */
- case ABORT:
- case COMMAND_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* ++guenther: possible race with Falcon locking */
- falcon_dont_release++;
- hostdata->connected = NULL;
- QU_PRINTK("scsi%d: command for target %d, lun %d "
- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+ case ABORT:
+ case COMMAND_COMPLETE:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* ++guenther: possible race with Falcon locking */
+ falcon_dont_release++;
+ hostdata->connected = NULL;
+ QU_PRINTK("scsi%d: command for target %d, lun %d "
+ "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
- if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
- /* Turn a QUEUE FULL status into BUSY, I think the
- * mid level cannot handle QUEUE FULL :-( (The
- * command is retried after BUSY). Also update our
- * queue size to the number of currently issued
- * commands now.
- */
- /* ++Andreas: the mid level code knows about
- QUEUE_FULL now. */
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
- TAG_PRINTK("scsi%d: target %d lun %d returned "
- "QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->device->id, cmd->device->lun,
- ta->nr_allocated);
- if (ta->queue_size > ta->nr_allocated)
- ta->nr_allocated = ta->queue_size;
- }
+ cmd_free_tag(cmd);
+ if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+ /* Turn a QUEUE FULL status into BUSY, I think the
+ * mid level cannot handle QUEUE FULL :-( (The
+ * command is retried after BUSY). Also update our
+ * queue size to the number of currently issued
+ * commands now.
+ */
+ /* ++Andreas: the mid level code knows about
+ QUEUE_FULL now. */
+ TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+ TAG_PRINTK("scsi%d: target %d lun %d returned "
+ "QUEUE_FULL after %d commands\n",
+ HOSTNO, cmd->device->id, cmd->device->lun,
+ ta->nr_allocated);
+ if (ta->queue_size > ta->nr_allocated)
+ ta->nr_allocated = ta->queue_size;
+ }
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way to
- * differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the
- * result code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
-#ifdef AUTOSENSE
- if ((cmd->cmnd[0] != REQUEST_SENSE) &&
- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- ASEN_PRINTK("scsi%d: performing request sense\n",
- HOSTNO);
- cmd->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[1] &= 0xe0;
- cmd->cmnd[2] = 0;
- cmd->cmnd[3] = 0;
- cmd->cmnd[4] = sizeof(cmd->sense_buffer);
- cmd->cmnd[5] = 0;
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- cmd->use_sg = 0;
- /* this is initialized from initialize_SCp
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- */
- cmd->request_buffer = (char *) cmd->sense_buffer;
- cmd->request_bufflen = sizeof(cmd->sense_buffer);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+ /*
+ * I'm not sure what the correct thing to do here is :
+ *
+ * If the command that just executed is NOT a request
+ * sense, the obvious thing to do is to set the result
+ * code to the values of the stored parameters.
+ *
+ * If it was a REQUEST SENSE command, we need some way to
+ * differentiate between the failure code of the original
+ * and the failure code of the REQUEST sense - the obvious
+ * case is success, where we fall through and leave the
+ * result code unchanged.
+ *
+ * The non-obvious place is where the REQUEST SENSE failed
+ */
+
+ if (cmd->cmnd[0] != REQUEST_SENSE)
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ else if (status_byte(cmd->SCp.Status) != GOOD)
+ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
- local_irq_save(flags);
- LIST(cmd,hostdata->issue_queue);
- NEXT(cmd) = hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- local_irq_restore(flags);
- QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
- "issue queue\n", H_NO(cmd));
- } else
+#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+ (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+ ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO);
+ cmd->cmnd[0] = REQUEST_SENSE;
+ cmd->cmnd[1] &= 0xe0;
+ cmd->cmnd[2] = 0;
+ cmd->cmnd[3] = 0;
+ cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+ cmd->cmnd[5] = 0;
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+ cmd->use_sg = 0;
+ /* this is initialized from initialize_SCp
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ */
+ cmd->request_buffer = (char *) cmd->sense_buffer;
+ cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+ local_irq_save(flags);
+ LIST(cmd,hostdata->issue_queue);
+ SET_NEXT(cmd, hostdata->issue_queue);
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ local_irq_restore(flags);
+ QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+ "issue queue\n", H_NO(cmd));
+ } else
#endif /* def AUTOSENSE */
- {
+ {
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
- cmd->scsi_done(cmd);
- }
-
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
-
- falcon_dont_release--;
- /* ++roman: For Falcon SCSI, release the lock on the
- * ST-DMA here if no other commands are waiting on the
- * disconnected queue.
- */
- falcon_release_lock_if_possible( hostdata );
- return;
- case MESSAGE_REJECT:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- switch (hostdata->last_message) {
- case HEAD_OF_QUEUE_TAG:
- case ORDERED_QUEUE_TAG:
- case SIMPLE_QUEUE_TAG:
- /* The target obviously doesn't support tagged
- * queuing, even though it announced this ability in
- * its INQUIRY data ?!? (maybe only this LUN?) Ok,
- * clear 'tagged_supported' and lock the LUN, since
- * the command is treated as untagged further on.
- */
- cmd->device->tagged_supported = 0;
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- cmd->tag = TAG_NONE;
- TAG_PRINTK("scsi%d: target %d lun %d rejected "
- "QUEUE_TAG message; tagged queuing "
- "disabled\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- break;
- }
- break;
- case DISCONNECT:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- local_irq_save(flags);
- cmd->device->disconnect = 1;
- LIST(cmd,hostdata->disconnected_queue);
- NEXT(cmd) = hostdata->disconnected_queue;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- local_irq_restore(flags);
- QU_PRINTK("scsi%d: command for target %d lun %d was "
- "moved from connected to the "
- "disconnected_queue\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
- return;
- /*
- * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
- * operation, in violation of the SCSI spec so we can safely
- * ignore SAVE/RESTORE pointers calls.
- *
- * Unfortunately, some disks violate the SCSI spec and
- * don't issue the required SAVE_POINTERS message before
- * disconnecting, and we have to break spec to remain
- * compatible.
- */
- case SAVE_POINTERS:
- case RESTORE_POINTERS:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- break;
- case EXTENDED_MESSAGE:
-/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.
- */
- extended_msg[0] = EXTENDED_MESSAGE;
- /* Accept first byte by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
-
- len = 2;
- data = extended_msg + 1;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
- (int)extended_msg[1], (int)extended_msg[2]);
-
- if (!len && extended_msg[1] <=
- (sizeof (extended_msg) - 1)) {
- /* Accept third byte by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- len = extended_msg[1] - 1;
- data = extended_msg + 3;
- phase = PHASE_MSGIN;
-
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- EXT_PRINTK("scsi%d: message received, residual %d\n",
- HOSTNO, len);
-
- switch (extended_msg[2]) {
- case EXTENDED_SDTR:
- case EXTENDED_WDTR:
- case EXTENDED_MODIFY_DATA_POINTER:
- case EXTENDED_EXTENDED_IDENTIFY:
- tmp = 0;
- }
- } else if (len) {
- printk(KERN_NOTICE "scsi%d: error receiving "
- "extended message\n", HOSTNO);
- tmp = 0;
- } else {
- printk(KERN_NOTICE "scsi%d: extended message "
- "code %02x length %d is too long\n",
- HOSTNO, extended_msg[2], extended_msg[1]);
- tmp = 0;
- }
- /* Fall through to reject message */
-
- /*
- * If we get something weird that we aren't expecting,
- * reject it.
- */
- default:
- if (!tmp) {
- printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
- spi_print_msg(extended_msg);
- printk("\n");
- } else if (tmp != EXTENDED_MESSAGE)
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "message %02x from target %d, lun %d\n",
- HOSTNO, tmp, cmd->device->id, cmd->device->lun);
- else
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "extended message "
- "code %02x, length %d from target %d, lun %d\n",
- HOSTNO, extended_msg[1], extended_msg[0],
- cmd->device->id, cmd->device->lun);
-
-
- msgout = MESSAGE_REJECT;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- break;
- } /* switch (tmp) */
- break;
- case PHASE_MSGOUT:
- len = 1;
- data = &msgout;
- hostdata->last_message = msgout;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- if (msgout == ABORT) {
+ cmd->scsi_done(cmd);
+ }
+
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+
+ falcon_dont_release--;
+ /* ++roman: For Falcon SCSI, release the lock on the
+ * ST-DMA here if no other commands are waiting on the
+ * disconnected queue.
+ */
+ falcon_release_lock_if_possible(hostdata);
+ return;
+ case MESSAGE_REJECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ switch (hostdata->last_message) {
+ case HEAD_OF_QUEUE_TAG:
+ case ORDERED_QUEUE_TAG:
+ case SIMPLE_QUEUE_TAG:
+ /* The target obviously doesn't support tagged
+ * queuing, even though it announced this ability in
+ * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+ * clear 'tagged_supported' and lock the LUN, since
+ * the command is treated as untagged further on.
+ */
+ cmd->device->tagged_supported = 0;
+ hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+ cmd->tag = TAG_NONE;
+ TAG_PRINTK("scsi%d: target %d lun %d rejected "
+ "QUEUE_TAG message; tagged queuing "
+ "disabled\n",
+ HOSTNO, cmd->device->id, cmd->device->lun);
+ break;
+ }
+ break;
+ case DISCONNECT:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ local_irq_save(flags);
+ cmd->device->disconnect = 1;
+ LIST(cmd,hostdata->disconnected_queue);
+ SET_NEXT(cmd, hostdata->disconnected_queue);
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = cmd;
+ local_irq_restore(flags);
+ QU_PRINTK("scsi%d: command for target %d lun %d was "
+ "moved from connected to the "
+ "disconnected_queue\n", HOSTNO,
+ cmd->device->id, cmd->device->lun);
+ /*
+ * Restore phase bits to 0 so an interrupted selection,
+ * arbitration can resume.
+ */
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ /* Wait for bus free to avoid nasty timeouts */
+ while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+ barrier();
+ return;
+ /*
+ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+ * operation, in violation of the SCSI spec so we can safely
+ * ignore SAVE/RESTORE pointers calls.
+ *
+ * Unfortunately, some disks violate the SCSI spec and
+ * don't issue the required SAVE_POINTERS message before
+ * disconnecting, and we have to break spec to remain
+ * compatible.
+ */
+ case SAVE_POINTERS:
+ case RESTORE_POINTERS:
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Enable reselect interrupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ break;
+ case EXTENDED_MESSAGE:
+ /*
+ * Extended messages are sent in the following format :
+ * Byte
+ * 0 EXTENDED_MESSAGE == 1
+ * 1 length (includes one byte for code, doesn't
+ * include first two bytes)
+ * 2 code
+ * 3..length+1 arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since spi_print_msg() wants the whole thing.
+ */
+ extended_msg[0] = EXTENDED_MESSAGE;
+ /* Accept first byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+ len = 2;
+ data = extended_msg + 1;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+ (int)extended_msg[1], (int)extended_msg[2]);
+
+ if (!len && extended_msg[1] <=
+ (sizeof(extended_msg) - 1)) {
+ /* Accept third byte by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = extended_msg[1] - 1;
+ data = extended_msg + 3;
+ phase = PHASE_MSGIN;
+
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ EXT_PRINTK("scsi%d: message received, residual %d\n",
+ HOSTNO, len);
+
+ switch (extended_msg[2]) {
+ case EXTENDED_SDTR:
+ case EXTENDED_WDTR:
+ case EXTENDED_MODIFY_DATA_POINTER:
+ case EXTENDED_EXTENDED_IDENTIFY:
+ tmp = 0;
+ }
+ } else if (len) {
+ printk(KERN_NOTICE "scsi%d: error receiving "
+ "extended message\n", HOSTNO);
+ tmp = 0;
+ } else {
+ printk(KERN_NOTICE "scsi%d: extended message "
+ "code %02x length %d is too long\n",
+ HOSTNO, extended_msg[2], extended_msg[1]);
+ tmp = 0;
+ }
+ /* Fall through to reject message */
+
+ /*
+ * If we get something weird that we aren't expecting,
+ * reject it.
+ */
+ default:
+ if (!tmp) {
+ printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+ spi_print_msg(extended_msg);
+ printk("\n");
+ } else if (tmp != EXTENDED_MESSAGE)
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "message %02x from target %d, lun %d\n",
+ HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+ else
+ printk(KERN_DEBUG "scsi%d: rejecting unknown "
+ "extended message "
+ "code %02x, length %d from target %d, lun %d\n",
+ HOSTNO, extended_msg[1], extended_msg[0],
+ cmd->device->id, cmd->device->lun);
+
+
+ msgout = MESSAGE_REJECT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ break;
+ } /* switch (tmp) */
+ break;
+ case PHASE_MSGOUT:
+ len = 1;
+ data = &msgout;
+ hostdata->last_message = msgout;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (msgout == ABORT) {
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
+ cmd_free_tag(cmd);
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- hostdata->connected = NULL;
- cmd->result = DID_ERROR << 16;
+ hostdata->connected = NULL;
+ cmd->result = DID_ERROR << 16;
#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
+ collect_stats(hostdata, cmd);
#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- falcon_release_lock_if_possible( hostdata );
- return;
- }
- msgout = NOP;
- break;
- case PHASE_CMDOUT:
- len = cmd->cmd_len;
- data = cmd->cmnd;
- /*
- * XXX for performance reasons, on machines with a
- * PSEUDO-DMA architecture we should probably
- * use the dma transfer function.
- */
- NCR5380_transfer_pio(instance, &phase, &len,
- &data);
- break;
- case PHASE_STATIN:
- len = 1;
- data = &tmp;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- cmd->SCp.Status = tmp;
- break;
- default:
- printk("scsi%d: unknown phase\n", HOSTNO);
- NCR_PRINT(NDEBUG_ANY);
- } /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- } /* while (1) */
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ falcon_release_lock_if_possible(hostdata);
+ return;
+ }
+ msgout = NOP;
+ break;
+ case PHASE_CMDOUT:
+ len = cmd->cmd_len;
+ data = cmd->cmnd;
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
+ */
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ break;
+ case PHASE_STATIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Status = tmp;
+ break;
+ default:
+ printk("scsi%d: unknown phase\n", HOSTNO);
+ NCR_PRINT(NDEBUG_ANY);
+ } /* switch(phase) */
+ } /* if (tmp * SR_REQ) */
+ } /* while (1) */
}
/*
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
- * Purpose : does reselection, initializing the instance->connected
- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
* nexus has been reestablished,
- *
+ *
* Inputs : instance - this instance of the NCR5380.
*
*/
-static void NCR5380_reselect (struct Scsi_Host *instance)
+static void NCR5380_reselect(struct Scsi_Host *instance)
{
- SETUP_HOSTDATA(instance);
- unsigned char target_mask;
- unsigned char lun, phase;
- int len;
+ SETUP_HOSTDATA(instance);
+ unsigned char target_mask;
+ unsigned char lun, phase;
+ int len;
#ifdef SUPPORT_TAGS
- unsigned char tag;
+ unsigned char tag;
#endif
- unsigned char msg[3];
- unsigned char *data;
- Scsi_Cmnd *tmp = NULL, *prev;
-/* unsigned long flags; */
-
- /*
- * Disable arbitration, etc. since the host adapter obviously
- * lost, and tell an interrupted NCR5380_select() to restart.
- */
-
- NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
-
- target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
-
- RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
-
- /*
- * At this point, we have detected that our SCSI ID is on the bus,
- * SEL is true and BSY was false for at least one bus settle delay
- * (400 ns).
- *
- * We must assert BSY ourselves, until the target drops the SEL
- * signal.
- */
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- while (NCR5380_read(STATUS_REG) & SR_SEL);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- /*
- * Wait for target to go into MSGIN.
- */
-
- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
- len = 1;
- data = msg;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
-
- if (!(msg[0] & 0x80)) {
- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
- spi_print_msg(msg);
- do_abort(instance);
- return;
- }
- lun = (msg[0] & 0x07);
+ unsigned char msg[3];
+ unsigned char *data;
+ Scsi_Cmnd *tmp = NULL, *prev;
+/* unsigned long flags; */
+
+ /*
+ * Disable arbitration, etc. since the host adapter obviously
+ * lost, and tell an interrupted NCR5380_select() to restart.
+ */
+
+ NCR5380_write(MODE_REG, MR_BASE);
+ hostdata->restart_select = 1;
+
+ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+ RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+ /*
+ * At this point, we have detected that our SCSI ID is on the bus,
+ * SEL is true and BSY was false for at least one bus settle delay
+ * (400 ns).
+ *
+ * We must assert BSY ourselves, until the target drops the SEL
+ * signal.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+
+ while (NCR5380_read(STATUS_REG) & SR_SEL)
+ ;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ /*
+ * Wait for target to go into MSGIN.
+ */
+
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ))
+ ;
+
+ len = 1;
+ data = msg;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+ if (!(msg[0] & 0x80)) {
+ printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+ spi_print_msg(msg);
+ do_abort(instance);
+ return;
+ }
+ lun = (msg[0] & 0x07);
#ifdef SUPPORT_TAGS
- /* If the phase is still MSGIN, the target wants to send some more
- * messages. In case it supports tagged queuing, this is probably a
- * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
- */
- tag = TAG_NONE;
- if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
- /* Accept previous IDENTIFY message by clearing ACK */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- len = 2;
- data = msg+1;
- if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
- msg[1] == SIMPLE_QUEUE_TAG)
- tag = msg[2];
- TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
- "reselection\n", HOSTNO, target_mask, lun, tag);
- }
+ /* If the phase is still MSGIN, the target wants to send some more
+ * messages. In case it supports tagged queuing, this is probably a
+ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+ */
+ tag = TAG_NONE;
+ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+ /* Accept previous IDENTIFY message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = 2;
+ data = msg + 1;
+ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+ msg[1] == SIMPLE_QUEUE_TAG)
+ tag = msg[2];
+ TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+ "reselection\n", HOSTNO, target_mask, lun, tag);
+ }
#endif
-
- /*
- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
- * just reestablished, and remove it from the disconnected queue.
- */
-
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
- tmp; prev = tmp, tmp = NEXT(tmp) ) {
- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just reestablished, and remove it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ tmp; prev = tmp, tmp = NEXT(tmp)) {
+ if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
#ifdef SUPPORT_TAGS
- && (tag == tmp->tag)
+ && (tag == tmp->tag)
#endif
- ) {
- /* ++guenther: prevent race with falcon_release_lock */
- falcon_dont_release++;
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- NEXT(prev) = NEXT(tmp);
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
- hostdata->disconnected_queue = NEXT(tmp);
- }
- NEXT(tmp) = NULL;
- break;
+ ) {
+ /* ++guenther: prevent race with falcon_release_lock */
+ falcon_dont_release++;
+ if (prev) {
+ REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+ SET_NEXT(prev, NEXT(tmp));
+ } else {
+ REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+ hostdata->disconnected_queue = NEXT(tmp);
+ }
+ SET_NEXT(tmp, NULL);
+ break;
+ }
}
- }
-
- if (!tmp) {
- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+
+ if (!tmp) {
+ printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
#ifdef SUPPORT_TAGS
- "tag %d "
+ "tag %d "
#endif
- "not in disconnected_queue.\n",
- HOSTNO, target_mask, lun
+ "not in disconnected_queue.\n",
+ HOSTNO, target_mask, lun
#ifdef SUPPORT_TAGS
- , tag
+ , tag
#endif
- );
- /*
- * Since we have an established nexus that we can't do anything
- * with, we must abort it.
- */
- do_abort(instance);
- return;
- }
+ );
+ /*
+ * Since we have an established nexus that we can't do anything
+ * with, we must abort it.
+ */
+ do_abort(instance);
+ return;
+ }
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ /* Accept message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = tmp;
- RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
- falcon_dont_release--;
+ hostdata->connected = tmp;
+ RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+ HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+ falcon_dont_release--;
}
@@ -2626,362 +2677,361 @@ static void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : abort a command
*
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
* used.
*
* Returns : 0 - success, -1 on failure.
*
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
+ * XXX - there is no way to abort the command that is currently
+ * connected, you have to wait for it to complete. If this is
* a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
+ * called where the loop started in NCR5380_main().
*/
static
-int NCR5380_abort (Scsi_Cmnd *cmd)
+int NCR5380_abort(Scsi_Cmnd *cmd)
{
- struct Scsi_Host *instance = cmd->device->host;
- SETUP_HOSTDATA(instance);
- Scsi_Cmnd *tmp, **prev;
- unsigned long flags;
+ struct Scsi_Host *instance = cmd->device->host;
+ SETUP_HOSTDATA(instance);
+ Scsi_Cmnd *tmp, **prev;
+ unsigned long flags;
+
+ printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+ scsi_print_command(cmd);
- printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
- scsi_print_command(cmd);
+ NCR5380_print_status(instance);
- NCR5380_print_status (instance);
+ local_irq_save(flags);
- local_irq_save(flags);
-
- if (!IS_A_TT() && !falcon_got_lock)
- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
- HOSTNO);
+ if (!IS_A_TT() && !falcon_got_lock)
+ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+ HOSTNO);
- ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
- NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
+ ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+ NCR5380_read(BUS_AND_STATUS_REG),
+ NCR5380_read(STATUS_REG));
#if 1
-/*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
- */
+ /*
+ * Case 1 : If the command is the currently executing command,
+ * we'll set the aborted flag and return control so that
+ * information transfer routine can exit cleanly.
+ */
- if (hostdata->connected == cmd) {
+ if (hostdata->connected == cmd) {
- ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
+ ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+ /*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
-/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
-/*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
+ /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+ /*
+ * Since we can't change phases until we've completed the current
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
-/*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
+ /*
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */
- if (do_abort(instance) == 0) {
- hostdata->aborted = 1;
- hostdata->connected = NULL;
- cmd->result = DID_ABORT << 16;
+ if (do_abort(instance) == 0) {
+ hostdata->aborted = 1;
+ hostdata->connected = NULL;
+ cmd->result = DID_ABORT << 16;
#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
+ cmd_free_tag(cmd);
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
- falcon_release_lock_if_possible( hostdata );
- return SCSI_ABORT_SUCCESS;
- } else {
-/* local_irq_restore(flags); */
- printk("scsi%d: abort of connected command failed!\n", HOSTNO);
- return SCSI_ABORT_ERROR;
- }
- }
+ local_irq_restore(flags);
+ cmd->scsi_done(cmd);
+ falcon_release_lock_if_possible(hostdata);
+ return SCSI_ABORT_SUCCESS;
+ } else {
+/* local_irq_restore(flags); */
+ printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+ return SCSI_ABORT_ERROR;
+ }
+ }
#endif
-/*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
- for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- (*prev) = NEXT(tmp);
- NEXT(tmp) = NULL;
- tmp->result = DID_ABORT << 16;
- local_irq_restore(flags);
- ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
- HOSTNO);
- /* Tagged queuing note: no tag to free here, hasn't been assigned
- * yet... */
- tmp->scsi_done(tmp);
- falcon_release_lock_if_possible( hostdata );
- return SCSI_ABORT_SUCCESS;
+ /*
+ * Case 2 : If the command hasn't been issued yet, we simply remove it
+ * from the issue queue.
+ */
+ for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue),
+ tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ (*prev) = NEXT(tmp);
+ SET_NEXT(tmp, NULL);
+ tmp->result = DID_ABORT << 16;
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+ HOSTNO);
+ /* Tagged queuing note: no tag to free here, hasn't been assigned
+ * yet... */
+ tmp->scsi_done(tmp);
+ falcon_release_lock_if_possible(hostdata);
+ return SCSI_ABORT_SUCCESS;
+ }
}
-/*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
+ /*
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or
+ * issue a reset.
+ *
+ * Timeouts, and therefore aborted commands, will be highly unlikely
+ * and handling them cleanly in this situation would make the common
+ * case of noresets less efficient, and would pollute our code. So,
+ * we fail.
+ */
- if (hostdata->connected) {
- local_irq_restore(flags);
- ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
- return SCSI_ABORT_SNOOZE;
- }
+ if (hostdata->connected) {
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+ return SCSI_ABORT_SNOOZE;
+ }
-/*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
+ /*
+ * Case 4: If the command is currently disconnected from the bus, and
+ * there are no connected commands, we reconnect the I_T_L or
+ * I_T_L_Q nexus associated with it, go into message out, and send
+ * an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select(). The easiest way to implement this
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that
+ * device reselected.
+ *
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ tmp = NEXT(tmp)) {
+ if (cmd == tmp) {
+ local_irq_restore(flags);
+ ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
- tmp = NEXT(tmp))
- if (cmd == tmp) {
- local_irq_restore(flags);
- ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
-
- if (NCR5380_select (instance, cmd, (int) cmd->tag))
- return SCSI_ABORT_BUSY;
-
- ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
-
- do_abort (instance);
-
- local_irq_save(flags);
- for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
- tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- *prev = NEXT(tmp);
- NEXT(tmp) = NULL;
- tmp->result = DID_ABORT << 16;
- /* We must unlock the tag/LUN immediately here, since the
- * target goes to BUS FREE and doesn't send us another
- * message (COMMAND_COMPLETE or the like)
- */
+ if (NCR5380_select(instance, cmd, (int)cmd->tag))
+ return SCSI_ABORT_BUSY;
+
+ ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+ do_abort(instance);
+
+ local_irq_save(flags);
+ for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue),
+ tmp = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
+ if (cmd == tmp) {
+ REMOVE(5, *prev, tmp, NEXT(tmp));
+ *prev = NEXT(tmp);
+ SET_NEXT(tmp, NULL);
+ tmp->result = DID_ABORT << 16;
+ /* We must unlock the tag/LUN immediately here, since the
+ * target goes to BUS FREE and doesn't send us another
+ * message (COMMAND_COMPLETE or the like)
+ */
#ifdef SUPPORT_TAGS
- cmd_free_tag( tmp );
+ cmd_free_tag(tmp);
#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+ hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
- local_irq_restore(flags);
- tmp->scsi_done(tmp);
- falcon_release_lock_if_possible( hostdata );
- return SCSI_ABORT_SUCCESS;
+ local_irq_restore(flags);
+ tmp->scsi_done(tmp);
+ falcon_release_lock_if_possible(hostdata);
+ return SCSI_ABORT_SUCCESS;
+ }
+ }
}
}
-/*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
+ /*
+ * Case 5 : If we reached this point, the command was not found in any of
+ * the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
- local_irq_restore(flags);
- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
- KERN_INFO " before abortion\n", HOSTNO);
+ local_irq_restore(flags);
+ printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+ KERN_INFO " before abortion\n", HOSTNO);
-/* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
- falcon_release_lock_if_possible( hostdata );
+ /* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+ falcon_release_lock_if_possible(hostdata);
- return SCSI_ABORT_NOT_RUNNING;
+ return SCSI_ABORT_NOT_RUNNING;
}
-/*
+/*
* Function : int NCR5380_reset (Scsi_Cmnd *cmd)
- *
+ *
* Purpose : reset the SCSI bus.
*
* Returns : SCSI_RESET_WAKEUP
*
- */
+ */
-static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
+static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
- int i;
- unsigned long flags;
+ SETUP_HOSTDATA(cmd->device->host);
+ int i;
+ unsigned long flags;
#if 1
- Scsi_Cmnd *connected, *disconnected_queue;
+ Scsi_Cmnd *connected, *disconnected_queue;
#endif
- if (!IS_A_TT() && !falcon_got_lock)
- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
- H_NO(cmd) );
-
- NCR5380_print_status (cmd->device->host);
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
- udelay (40);
- /* reset NCR registers */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_write( MODE_REG, MR_BASE );
- NCR5380_write( TARGET_COMMAND_REG, 0 );
- NCR5380_write( SELECT_ENABLE_REG, 0 );
- /* ++roman: reset interrupt condition! otherwise no interrupts don't get
- * through anymore ... */
- (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
-#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
- /* XXX see below XXX */
-
- /* MSch: old-style reset: actually abort all command processing here */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; to avoid problems with re-inserting the commands
- * into the issue_queue (via scsi_done()), the aborted commands are
- * remembered in local variables first.
- */
- local_irq_save(flags);
- connected = (Scsi_Cmnd *)hostdata->connected;
- hostdata->connected = NULL;
- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
- hostdata->disconnected_queue = NULL;
+ if (!IS_A_TT() && !falcon_got_lock)
+ printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+ H_NO(cmd));
+
+ NCR5380_print_status(cmd->device->host);
+
+ /* get in phase */
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
+ /* assert RST */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+ udelay(40);
+ /* reset NCR registers */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+ * through anymore ... */
+ (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+ /* XXX see below XXX */
+
+ /* MSch: old-style reset: actually abort all command processing here */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; to avoid problems with re-inserting the commands
+ * into the issue_queue (via scsi_done()), the aborted commands are
+ * remembered in local variables first.
+ */
+ local_irq_save(flags);
+ connected = (Scsi_Cmnd *)hostdata->connected;
+ hostdata->connected = NULL;
+ disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
- free_all_tags();
+ free_all_tags();
#endif
- for( i = 0; i < 8; ++i )
- hostdata->busy[i] = 0;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
#ifdef REAL_DMA
- hostdata->dma_len = 0;
+ hostdata->dma_len = 0;
#endif
- local_irq_restore(flags);
-
- /* In order to tell the mid-level code which commands were aborted,
- * set the command status to DID_RESET and call scsi_done() !!!
- * This ultimately aborts processing of these commands in the mid-level.
- */
-
- if ((cmd = connected)) {
- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done( cmd );
- }
-
- for (i = 0; (cmd = disconnected_queue); ++i) {
- disconnected_queue = NEXT(cmd);
- NEXT(cmd) = NULL;
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done( cmd );
- }
- if (i > 0)
- ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
-
-/* The Falcon lock should be released after a reset...
- */
-/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
- * unlocking and enabling dma interrupt.
- */
-/* falcon_release_lock_if_possible( hostdata );*/
+ local_irq_restore(flags);
+
+ /* In order to tell the mid-level code which commands were aborted,
+ * set the command status to DID_RESET and call scsi_done() !!!
+ * This ultimately aborts processing of these commands in the mid-level.
+ */
+
+ if ((cmd = connected)) {
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
- /* since all commands have been explicitly terminated, we need to tell
- * the midlevel code that the reset was SUCCESSFUL, and there is no
- * need to 'wake up' the commands by a request_sense
- */
- return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+ for (i = 0; (cmd = disconnected_queue); ++i) {
+ disconnected_queue = NEXT(cmd);
+ SET_NEXT(cmd, NULL);
+ cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+ cmd->scsi_done(cmd);
+ }
+ if (i > 0)
+ ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+ /* The Falcon lock should be released after a reset...
+ */
+ /* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+ * unlocking and enabling dma interrupt.
+ */
+/* falcon_release_lock_if_possible( hostdata );*/
+
+ /* since all commands have been explicitly terminated, we need to tell
+ * the midlevel code that the reset was SUCCESSFUL, and there is no
+ * need to 'wake up' the commands by a request_sense
+ */
+ return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
#else /* 1 */
- /* MSch: new-style reset handling: let the mid-level do what it can */
-
- /* ++guenther: MID-LEVEL IS STILL BROKEN.
- * Mid-level is supposed to requeue all commands that were active on the
- * various low-level queues. In fact it does this, but that's not enough
- * because all these commands are subject to timeout. And if a timeout
- * happens for any removed command, *_abort() is called but all queues
- * are now empty. Abort then gives up the falcon lock, which is fatal,
- * since the mid-level will queue more commands and must have the lock
- * (it's all happening inside timer interrupt handler!!).
- * Even worse, abort will return NOT_RUNNING for all those commands not
- * on any queue, so they won't be retried ...
- *
- * Conclusion: either scsi.c disables timeout for all resetted commands
- * immediately, or we lose! As of linux-2.0.20 it doesn't.
- */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; so clear the low-level status here to avoid
- * conflicts when the mid-level code tries to wake up the affected
- * commands!
- */
-
- if (hostdata->issue_queue)
- ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
- if (hostdata->connected)
- ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
- if (hostdata->disconnected_queue)
- ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
-
- local_irq_save(flags);
- hostdata->issue_queue = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = NULL;
+ /* MSch: new-style reset handling: let the mid-level do what it can */
+
+ /* ++guenther: MID-LEVEL IS STILL BROKEN.
+ * Mid-level is supposed to requeue all commands that were active on the
+ * various low-level queues. In fact it does this, but that's not enough
+ * because all these commands are subject to timeout. And if a timeout
+ * happens for any removed command, *_abort() is called but all queues
+ * are now empty. Abort then gives up the falcon lock, which is fatal,
+ * since the mid-level will queue more commands and must have the lock
+ * (it's all happening inside timer interrupt handler!!).
+ * Even worse, abort will return NOT_RUNNING for all those commands not
+ * on any queue, so they won't be retried ...
+ *
+ * Conclusion: either scsi.c disables timeout for all resetted commands
+ * immediately, or we lose! As of linux-2.0.20 it doesn't.
+ */
+
+ /* After the reset, there are no more connected or disconnected commands
+ * and no busy units; so clear the low-level status here to avoid
+ * conflicts when the mid-level code tries to wake up the affected
+ * commands!
+ */
+
+ if (hostdata->issue_queue)
+ ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+ if (hostdata->connected)
+ ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+ if (hostdata->disconnected_queue)
+ ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+ local_irq_save(flags);
+ hostdata->issue_queue = NULL;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
- free_all_tags();
+ free_all_tags();
#endif
- for( i = 0; i < 8; ++i )
- hostdata->busy[i] = 0;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
#ifdef REAL_DMA
- hostdata->dma_len = 0;
+ hostdata->dma_len = 0;
#endif
- local_irq_restore(flags);
+ local_irq_restore(flags);
- /* we did no complete reset of all commands, so a wakeup is required */
- return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+ /* we did no complete reset of all commands, so a wakeup is required */
+ return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
#endif /* 1 */
}
-
-/* Local Variables: */
-/* tab-width: 8 */
-/* End: */
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 642de7b2b7a..6f8403b82ba 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -69,9 +69,9 @@
#define NDEBUG (0)
-#define NDEBUG_ABORT 0x800000
-#define NDEBUG_TAGS 0x1000000
-#define NDEBUG_MERGING 0x2000000
+#define NDEBUG_ABORT 0x00100000
+#define NDEBUG_TAGS 0x00200000
+#define NDEBUG_MERGING 0x00400000
#define AUTOSENSE
/* For the Atari version, use only polled IO or REAL_DMA */
@@ -186,38 +186,37 @@ static inline void DISABLE_IRQ(void)
/***************************** Prototypes *****************************/
#ifdef REAL_DMA
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
-static void atari_scsi_fetch_restbytes( void );
-static long atari_scsi_dma_residual( struct Scsi_Host *instance );
-static int falcon_classify_cmd( Scsi_Cmnd *cmd );
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
- Scsi_Cmnd *cmd, int write_flag );
+static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
+static void atari_scsi_fetch_restbytes(void);
+static long atari_scsi_dma_residual(struct Scsi_Host *instance);
+static int falcon_classify_cmd(Scsi_Cmnd *cmd);
+static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
+ Scsi_Cmnd *cmd, int write_flag);
#endif
-static irqreturn_t scsi_tt_intr( int irq, void *dummy);
-static irqreturn_t scsi_falcon_intr( int irq, void *dummy);
-static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
- hostdata );
-static void falcon_get_lock( void );
+static irqreturn_t scsi_tt_intr(int irq, void *dummy);
+static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
+static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
+static void falcon_get_lock(void);
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void atari_scsi_reset_boot( void );
+static void atari_scsi_reset_boot(void);
#endif
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value );
+static unsigned char atari_scsi_tt_reg_read(unsigned char reg);
+static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value);
+static unsigned char atari_scsi_falcon_reg_read(unsigned char reg);
+static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value);
/************************* End of Prototypes **************************/
-static struct Scsi_Host *atari_scsi_host = NULL;
-static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
-static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
+static struct Scsi_Host *atari_scsi_host;
+static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
+static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value);
#ifdef REAL_DMA
static unsigned long atari_dma_residual, atari_dma_startaddr;
static short atari_dma_active;
/* pointer to the dribble buffer */
-static char *atari_dma_buffer = NULL;
+static char *atari_dma_buffer;
/* precalculated physical address of the dribble buffer */
static unsigned long atari_dma_phys_buffer;
/* != 0 tells the Falcon int handler to copy data from the dribble buffer */
@@ -233,7 +232,7 @@ static char *atari_dma_orig_addr;
static unsigned long atari_dma_stram_mask;
#define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0)
/* number of bytes to cut from a transfer to handle NCR overruns */
-static int atari_read_overruns = 0;
+static int atari_read_overruns;
#endif
static int setup_can_queue = -1;
@@ -256,10 +255,10 @@ module_param(setup_hostid, int, 0);
#if defined(REAL_DMA)
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
{
int i;
- unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
+ unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr;
if (dma_stat & 0x01) {
@@ -267,15 +266,14 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
* physical memory chunk (DMA prefetch!), but that doesn't hurt.
* Check for this case:
*/
-
- for( i = 0; i < m68k_num_memory; ++i ) {
- end_addr = m68k_memory[i].addr +
- m68k_memory[i].size;
+
+ for (i = 0; i < m68k_num_memory; ++i) {
+ end_addr = m68k_memory[i].addr + m68k_memory[i].size;
if (end_addr <= addr && addr <= end_addr + 4)
- return( 1 );
+ return 1;
}
}
- return( 0 );
+ return 0;
}
@@ -284,28 +282,27 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
* end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
* to clear the DMA int pending bit before it allows other level 6 interrupts.
*/
-static void scsi_dma_buserr (int irq, void *dummy)
+static void scsi_dma_buserr(int irq, void *dummy)
{
- unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
+ unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
/* Don't do anything if a NCR interrupt is pending. Probably it's just
* masked... */
- if (atari_irq_pending( IRQ_TT_MFP_SCSI ))
+ if (atari_irq_pending(IRQ_TT_MFP_SCSI))
return;
-
+
printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
if (dma_stat & 0x80) {
- if (!scsi_dma_is_ignored_buserr( dma_stat ))
- printk( "SCSI DMA bus error -- bad DMA programming!\n" );
- }
- else {
+ if (!scsi_dma_is_ignored_buserr(dma_stat))
+ printk("SCSI DMA bus error -- bad DMA programming!\n");
+ } else {
/* Under normal circumstances we never should get to this point,
* since both interrupts are triggered simultaneously and the 5380
* int has higher priority. When this irq is handled, that DMA
* interrupt is cleared. So a warning message is printed here.
*/
- printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+ printk("SCSI DMA intr ?? -- this shouldn't happen!\n");
}
}
#endif
@@ -313,7 +310,7 @@ static void scsi_dma_buserr (int irq, void *dummy)
#endif
-static irqreturn_t scsi_tt_intr (int irq, void *dummy)
+static irqreturn_t scsi_tt_intr(int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
@@ -327,7 +324,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
* is that a bus error occurred...
*/
if (dma_stat & 0x80) {
- if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+ if (!scsi_dma_is_ignored_buserr(dma_stat)) {
printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
SCSI_DMA_READ_P(dma_addr));
printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
@@ -344,8 +341,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
* data reg!
*/
if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
- atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
- atari_dma_startaddr);
+ atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr);
DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
@@ -353,28 +349,30 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
if ((signed int)atari_dma_residual < 0)
atari_dma_residual = 0;
if ((dma_stat & 1) == 0) {
- /* After read operations, we maybe have to
- transport some rest bytes */
+ /*
+ * After read operations, we maybe have to
+ * transport some rest bytes
+ */
atari_scsi_fetch_restbytes();
- }
- else {
- /* There seems to be a nasty bug in some SCSI-DMA/NCR
- combinations: If a target disconnects while a write
- operation is going on, the address register of the
- DMA may be a few bytes farer than it actually read.
- This is probably due to DMA prefetching and a delay
- between DMA and NCR. Experiments showed that the
- dma_addr is 9 bytes to high, but this could vary.
- The problem is, that the residual is thus calculated
- wrong and the next transfer will start behind where
- it should. So we round up the residual to the next
- multiple of a sector size, if it isn't already a
- multiple and the originally expected transfer size
- was. The latter condition is there to ensure that
- the correction is taken only for "real" data
- transfers and not for, e.g., the parameters of some
- other command. These shouldn't disconnect anyway.
- */
+ } else {
+ /*
+ * There seems to be a nasty bug in some SCSI-DMA/NCR
+ * combinations: If a target disconnects while a write
+ * operation is going on, the address register of the
+ * DMA may be a few bytes farer than it actually read.
+ * This is probably due to DMA prefetching and a delay
+ * between DMA and NCR. Experiments showed that the
+ * dma_addr is 9 bytes to high, but this could vary.
+ * The problem is, that the residual is thus calculated
+ * wrong and the next transfer will start behind where
+ * it should. So we round up the residual to the next
+ * multiple of a sector size, if it isn't already a
+ * multiple and the originally expected transfer size
+ * was. The latter condition is there to ensure that
+ * the correction is taken only for "real" data
+ * transfers and not for, e.g., the parameters of some
+ * other command. These shouldn't disconnect anyway.
+ */
if (atari_dma_residual & 0x1ff) {
DMA_PRINTK("SCSI DMA: DMA bug corrected, "
"difference %ld bytes\n",
@@ -394,18 +392,18 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy)
}
#endif /* REAL_DMA */
-
- NCR5380_intr (0, 0, 0);
+
+ NCR5380_intr(0, 0);
#if 0
/* To be sure the int is not masked */
- atari_enable_irq( IRQ_TT_MFP_SCSI );
+ atari_enable_irq(IRQ_TT_MFP_SCSI);
#endif
return IRQ_HANDLED;
}
-static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
+static irqreturn_t scsi_falcon_intr(int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
@@ -430,7 +428,7 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
* bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
*/
if (atari_dma_active && (dma_stat & 0x02)) {
- unsigned long transferred;
+ unsigned long transferred;
transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
/* The ST-DMA address is incremented in 2-byte steps, but the
@@ -445,8 +443,7 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
atari_dma_residual = HOSTDATA_DMALEN - transferred;
DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
atari_dma_residual);
- }
- else
+ } else
atari_dma_residual = 0;
atari_dma_active = 0;
@@ -461,13 +458,13 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
#endif /* REAL_DMA */
- NCR5380_intr (0, 0, 0);
+ NCR5380_intr(0, 0);
return IRQ_HANDLED;
}
#ifdef REAL_DMA
-static void atari_scsi_fetch_restbytes( void )
+static void atari_scsi_fetch_restbytes(void)
{
int nr;
char *src, *dst;
@@ -505,19 +502,17 @@ static int falcon_dont_release = 0;
* again (but others waiting longer more probably will win).
*/
-static void
-falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
+static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
{
unsigned long flags;
-
- if (IS_A_TT()) return;
-
+
+ if (IS_A_TT())
+ return;
+
local_irq_save(flags);
- if (falcon_got_lock &&
- !hostdata->disconnected_queue &&
- !hostdata->issue_queue &&
- !hostdata->connected) {
+ if (falcon_got_lock && !hostdata->disconnected_queue &&
+ !hostdata->issue_queue && !hostdata->connected) {
if (falcon_dont_release) {
#if 0
@@ -528,7 +523,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
}
falcon_got_lock = 0;
stdma_release();
- wake_up( &falcon_fairness_wait );
+ wake_up(&falcon_fairness_wait);
}
local_irq_restore(flags);
@@ -549,31 +544,31 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
* Complicated, complicated.... Sigh...
*/
-static void falcon_get_lock( void )
+static void falcon_get_lock(void)
{
unsigned long flags;
- if (IS_A_TT()) return;
+ if (IS_A_TT())
+ return;
local_irq_save(flags);
- while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
- sleep_on( &falcon_fairness_wait );
+ while (!in_irq() && falcon_got_lock && stdma_others_waiting())
+ sleep_on(&falcon_fairness_wait);
while (!falcon_got_lock) {
- if (in_interrupt())
- panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+ if (in_irq())
+ panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
if (!falcon_trying_lock) {
falcon_trying_lock = 1;
stdma_lock(scsi_falcon_intr, NULL);
falcon_got_lock = 1;
falcon_trying_lock = 0;
- wake_up( &falcon_try_wait );
- }
- else {
- sleep_on( &falcon_try_wait );
+ wake_up(&falcon_try_wait);
+ } else {
+ sleep_on(&falcon_try_wait);
}
- }
+ }
local_irq_restore(flags);
if (!falcon_got_lock)
@@ -587,18 +582,18 @@ static void falcon_get_lock( void )
*/
#if 0
-int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
{
/* falcon_get_lock();
* ++guenther: moved to NCR5380_queue_command() to prevent
* race condition, see there for an explanation.
*/
- return( NCR5380_queue_command( cmd, done ) );
+ return NCR5380_queue_command(cmd, done);
}
#endif
-int atari_scsi_detect (struct scsi_host_template *host)
+int atari_scsi_detect(struct scsi_host_template *host)
{
static int called = 0;
struct Scsi_Host *instance;
@@ -606,7 +601,7 @@ int atari_scsi_detect (struct scsi_host_template *host)
if (!MACH_IS_ATARI ||
(!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
called)
- return( 0 );
+ return 0;
host->proc_name = "Atari";
@@ -655,32 +650,33 @@ int atari_scsi_detect (struct scsi_host_template *host)
!ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
if (!atari_dma_buffer) {
- printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
- "double buffer\n" );
- return( 0 );
+ printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
+ "double buffer\n");
+ return 0;
}
- atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer );
+ atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer);
atari_dma_orig_addr = 0;
}
#endif
- instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
- if(instance == NULL)
- {
+ instance = scsi_register(host, sizeof(struct NCR5380_hostdata));
+ if (instance == NULL) {
atari_stram_free(atari_dma_buffer);
atari_dma_buffer = 0;
return 0;
}
atari_scsi_host = instance;
- /* Set irq to 0, to avoid that the mid-level code disables our interrupt
- * during queue_command calls. This is completely unnecessary, and even
- * worse causes bad problems on the Falcon, where the int is shared with
- * IDE and floppy! */
+ /*
+ * Set irq to 0, to avoid that the mid-level code disables our interrupt
+ * during queue_command calls. This is completely unnecessary, and even
+ * worse causes bad problems on the Falcon, where the int is shared with
+ * IDE and floppy!
+ */
instance->irq = 0;
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
atari_scsi_reset_boot();
#endif
- NCR5380_init (instance, 0);
+ NCR5380_init(instance, 0);
if (IS_A_TT()) {
@@ -727,11 +723,10 @@ int atari_scsi_detect (struct scsi_host_template *host)
* the rest data bug is fixed, this can be lowered to 1.
*/
atari_read_overruns = 4;
- }
+ }
#endif /*REAL_DMA*/
- }
- else { /* ! IS_A_TT */
-
+ } else { /* ! IS_A_TT */
+
/* Nothing to do for the interrupt: the ST-DMA is initialized
* already by atari_init_INTS()
*/
@@ -756,23 +751,21 @@ int atari_scsi_detect (struct scsi_host_template *host)
setup_use_tagged_queuing ? "yes" : "no",
#endif
instance->hostt->this_id );
- NCR5380_print_options (instance);
- printk ("\n");
+ NCR5380_print_options(instance);
+ printk("\n");
called = 1;
- return( 1 );
+ return 1;
}
-#ifdef MODULE
-int atari_scsi_release (struct Scsi_Host *sh)
+int atari_scsi_release(struct Scsi_Host *sh)
{
if (IS_A_TT())
free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
if (atari_dma_buffer)
- atari_stram_free (atari_dma_buffer);
+ atari_stram_free(atari_dma_buffer);
return 1;
}
-#endif
void __init atari_scsi_setup(char *str, int *ints)
{
@@ -781,9 +774,9 @@ void __init atari_scsi_setup(char *str, int *ints)
* Defaults depend on TT or Falcon, hostid determined at run time.
* Negative values mean don't change.
*/
-
+
if (ints[0] < 1) {
- printk( "atari_scsi_setup: no arguments!\n" );
+ printk("atari_scsi_setup: no arguments!\n");
return;
}
@@ -809,7 +802,7 @@ void __init atari_scsi_setup(char *str, int *ints)
if (ints[4] >= 0 && ints[4] <= 7)
setup_hostid = ints[4];
else if (ints[4] > 7)
- printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] );
+ printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]);
}
#ifdef SUPPORT_TAGS
if (ints[0] >= 5) {
@@ -821,7 +814,7 @@ void __init atari_scsi_setup(char *str, int *ints)
int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
{
- int rv;
+ int rv;
struct NCR5380_hostdata *hostdata =
(struct NCR5380_hostdata *)cmd->device->host->hostdata;
@@ -831,13 +824,12 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
*/
/* And abort a maybe active DMA transfer */
if (IS_A_TT()) {
- atari_turnoff_irq( IRQ_TT_MFP_SCSI );
+ atari_turnoff_irq(IRQ_TT_MFP_SCSI);
#ifdef REAL_DMA
tt_scsi_dma.dma_ctrl = 0;
#endif /* REAL_DMA */
- }
- else {
- atari_turnoff_irq( IRQ_MFP_FSCSI );
+ } else {
+ atari_turnoff_irq(IRQ_MFP_FSCSI);
#ifdef REAL_DMA
st_dma.dma_mode_status = 0x90;
atari_dma_active = 0;
@@ -849,52 +841,51 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
/* Re-enable ints */
if (IS_A_TT()) {
- atari_turnon_irq( IRQ_TT_MFP_SCSI );
- }
- else {
- atari_turnon_irq( IRQ_MFP_FSCSI );
+ atari_turnon_irq(IRQ_TT_MFP_SCSI);
+ } else {
+ atari_turnon_irq(IRQ_MFP_FSCSI);
}
if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS)
falcon_release_lock_if_possible(hostdata);
- return( rv );
+ return rv;
}
-
+
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
static void __init atari_scsi_reset_boot(void)
{
unsigned long end;
-
+
/*
* Do a SCSI reset to clean up the bus during initialization. No messing
* with the queues, interrupts, or locks necessary here.
*/
- printk( "Atari SCSI: resetting the SCSI bus..." );
+ printk("Atari SCSI: resetting the SCSI bus...");
/* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+ NCR5380_write(TARGET_COMMAND_REG,
+ PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG)));
/* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
/* The min. reset hold time is 25us, so 40us should be enough */
- udelay( 50 );
+ udelay(50);
/* reset RST and interrupt */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
end = jiffies + AFTER_RESET_DELAY;
while (time_before(jiffies, end))
barrier();
- printk( " done\n" );
+ printk(" done\n");
}
#endif
-const char * atari_scsi_info (struct Scsi_Host *host)
+const char *atari_scsi_info(struct Scsi_Host *host)
{
/* atari_scsi_detect() is verbose enough... */
static const char string[] = "Atari native SCSI";
@@ -904,10 +895,10 @@ const char * atari_scsi_info (struct Scsi_Host *host)
#if defined(REAL_DMA)
-unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
- unsigned long count, int dir )
+unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data,
+ unsigned long count, int dir)
{
- unsigned long addr = virt_to_phys( data );
+ unsigned long addr = virt_to_phys(data);
DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
"dir = %d\n", instance->host_no, data, addr, count, dir);
@@ -919,38 +910,37 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
* wanted address.
*/
if (dir)
- memcpy( atari_dma_buffer, data, count );
+ memcpy(atari_dma_buffer, data, count);
else
atari_dma_orig_addr = data;
addr = atari_dma_phys_buffer;
}
-
+
atari_dma_startaddr = addr; /* Needed for calculating residual later. */
-
+
/* Cache cleanup stuff: On writes, push any dirty cache out before sending
* it to the peripheral. (Must be done before DMA setup, since at least
* the ST-DMA begins to fill internal buffers right after setup. For
* reads, invalidate any cache, may be altered after DMA without CPU
* knowledge.
- *
+ *
* ++roman: For the Medusa, there's no need at all for that cache stuff,
* because the hardware does bus snooping (fine!).
*/
- dma_cache_maintenance( addr, count, dir );
+ dma_cache_maintenance(addr, count, dir);
if (count == 0)
printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
if (IS_A_TT()) {
tt_scsi_dma.dma_ctrl = dir;
- SCSI_DMA_WRITE_P( dma_addr, addr );
- SCSI_DMA_WRITE_P( dma_cnt, count );
+ SCSI_DMA_WRITE_P(dma_addr, addr);
+ SCSI_DMA_WRITE_P(dma_cnt, count);
tt_scsi_dma.dma_ctrl = dir | 2;
- }
- else { /* ! IS_A_TT */
-
+ } else { /* ! IS_A_TT */
+
/* set address */
- SCSI_DMA_SETADR( addr );
+ SCSI_DMA_SETADR(addr);
/* toggle direction bit to clear FIFO and set DMA direction */
dir <<= 8;
@@ -968,13 +958,13 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
atari_dma_active = 1;
}
- return( count );
+ return count;
}
-static long atari_scsi_dma_residual( struct Scsi_Host *instance )
+static long atari_scsi_dma_residual(struct Scsi_Host *instance)
{
- return( atari_dma_residual );
+ return atari_dma_residual;
}
@@ -982,13 +972,13 @@ static long atari_scsi_dma_residual( struct Scsi_Host *instance )
#define CMD_SURELY_BYTE_MODE 1
#define CMD_MODE_UNKNOWN 2
-static int falcon_classify_cmd( Scsi_Cmnd *cmd )
+static int falcon_classify_cmd(Scsi_Cmnd *cmd)
{
unsigned char opcode = cmd->cmnd[0];
-
+
if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
- opcode == READ_BUFFER)
- return( CMD_SURELY_BYTE_MODE );
+ opcode == READ_BUFFER)
+ return CMD_SURELY_BYTE_MODE;
else if (opcode == READ_6 || opcode == READ_10 ||
opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
opcode == RECOVER_BUFFERED_DATA) {
@@ -996,12 +986,11 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd )
* needed here: The transfer is block-mode only if the 'fixed' bit is
* set! */
if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
- return( CMD_SURELY_BYTE_MODE );
+ return CMD_SURELY_BYTE_MODE;
else
- return( CMD_SURELY_BLOCK_MODE );
- }
- else
- return( CMD_MODE_UNKNOWN );
+ return CMD_SURELY_BLOCK_MODE;
+ } else
+ return CMD_MODE_UNKNOWN;
}
@@ -1014,19 +1003,18 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd )
* the overrun problem, so this question is academic :-)
*/
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
- Scsi_Cmnd *cmd,
- int write_flag )
+static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
+ Scsi_Cmnd *cmd, int write_flag)
{
unsigned long possible_len, limit;
#ifndef CONFIG_TT_DMA_EMUL
if (MACH_IS_HADES)
/* Hades has no SCSI DMA at all :-( Always force use of PIO */
- return( 0 );
-#endif
+ return 0;
+#endif
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
- return( wanted_len );
+ return wanted_len;
/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
* 255*512 bytes, but this should be enough)
@@ -1062,8 +1050,7 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
* this).
*/
possible_len = wanted_len;
- }
- else {
+ } else {
/* Read operations: if the wanted transfer length is not a multiple of
* 512, we cannot use DMA, since the ST-DMA cannot split transfers
* (no interrupt on DMA finished!)
@@ -1073,15 +1060,15 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
else {
/* Now classify the command (see above) and decide whether it is
* allowed to do DMA at all */
- switch( falcon_classify_cmd( cmd )) {
- case CMD_SURELY_BLOCK_MODE:
+ switch (falcon_classify_cmd(cmd)) {
+ case CMD_SURELY_BLOCK_MODE:
possible_len = wanted_len;
break;
- case CMD_SURELY_BYTE_MODE:
+ case CMD_SURELY_BYTE_MODE:
possible_len = 0; /* DMA prohibited */
break;
- case CMD_MODE_UNKNOWN:
- default:
+ case CMD_MODE_UNKNOWN:
+ default:
/* For unknown commands assume block transfers if the transfer
* size/allocation length is >= 1024 */
possible_len = (wanted_len < 1024) ? 0 : wanted_len;
@@ -1089,9 +1076,9 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
}
}
}
-
+
/* Last step: apply the hard limit on DMA transfers */
- limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ?
+ limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ?
STRAM_BUFFER_SIZE : 255*512;
if (possible_len > limit)
possible_len = limit;
@@ -1100,7 +1087,7 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes "
"instead of %ld\n", possible_len, wanted_len);
- return( possible_len );
+ return possible_len;
}
@@ -1114,23 +1101,23 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
* NCR5380_write call these functions via function pointers.
*/
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
+static unsigned char atari_scsi_tt_reg_read(unsigned char reg)
{
- return( tt_scsi_regp[reg * 2] );
+ return tt_scsi_regp[reg * 2];
}
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
+static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value)
{
tt_scsi_regp[reg * 2] = value;
}
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
+static unsigned char atari_scsi_falcon_reg_read(unsigned char reg)
{
dma_wd.dma_mode_status= (u_short)(0x88 + reg);
- return( (u_char)dma_wd.fdc_acces_seccount );
+ return (u_char)dma_wd.fdc_acces_seccount;
}
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
+static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
{
dma_wd.dma_mode_status = (u_short)(0x88 + reg);
dma_wd.fdc_acces_seccount = (u_short)value;
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index f917bdd09b4..efadb8d567c 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -21,11 +21,7 @@
int atari_scsi_detect (struct scsi_host_template *);
const char *atari_scsi_info (struct Scsi_Host *);
int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
-#ifdef MODULE
int atari_scsi_release (struct Scsi_Host *);
-#else
-#define atari_scsi_release NULL
-#endif
/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
* values should work, too; try it! (but cmd_per_lun costs memory!) */
@@ -63,6 +59,32 @@ int atari_scsi_release (struct Scsi_Host *);
#define NCR5380_dma_xfer_len(i,cmd,phase) \
atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+/* former generic SCSI error handling stuff */
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS 0x01
+#define SCSI_RESET_ASYNCHRONOUS 0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET 0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET 0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#define SCSI_RESET_HOST_RESET 0x200
+#define SCSI_RESET_ACTION 0xff
+
/* Debugging printk definitions:
*
* ARB -> arbitration
@@ -91,144 +113,58 @@ int atari_scsi_release (struct Scsi_Host *);
*
*/
-#if NDEBUG & NDEBUG_ARBITRATION
+#define dprint(flg, format...) \
+({ \
+ if (NDEBUG & (flg)) \
+ printk(KERN_DEBUG format); \
+})
+
#define ARB_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define ARB_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_AUTOSENSE
+ dprint(NDEBUG_ARBITRATION, format , ## args)
#define ASEN_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define ASEN_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_DMA
+ dprint(NDEBUG_AUTOSENSE, format , ## args)
#define DMA_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define DMA_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_HANDSHAKE
+ dprint(NDEBUG_DMA, format , ## args)
#define HSH_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define HSH_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INFORMATION
+ dprint(NDEBUG_HANDSHAKE, format , ## args)
#define INF_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define INF_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INIT
+ dprint(NDEBUG_INFORMATION, format , ## args)
#define INI_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define INI_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_INTR
+ dprint(NDEBUG_INIT, format , ## args)
#define INT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define INT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_LINKED
+ dprint(NDEBUG_INTR, format , ## args)
#define LNK_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define LNK_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_MAIN
+ dprint(NDEBUG_LINKED, format , ## args)
#define MAIN_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define MAIN_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_NO_DATAOUT
+ dprint(NDEBUG_MAIN, format , ## args)
#define NDAT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define NDAT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_NO_WRITE
+ dprint(NDEBUG_NO_DATAOUT, format , ## args)
#define NWR_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define NWR_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_PIO
+ dprint(NDEBUG_NO_WRITE, format , ## args)
#define PIO_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define PIO_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_PSEUDO_DMA
+ dprint(NDEBUG_PIO, format , ## args)
#define PDMA_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define PDMA_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_QUEUES
+ dprint(NDEBUG_PSEUDO_DMA, format , ## args)
#define QU_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define QU_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_RESELECTION
+ dprint(NDEBUG_QUEUES, format , ## args)
#define RSL_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define RSL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_SELECTION
+ dprint(NDEBUG_RESELECTION, format , ## args)
#define SEL_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define SEL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_USLEEP
+ dprint(NDEBUG_SELECTION, format , ## args)
#define USL_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define USL_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+ dprint(NDEBUG_USLEEP, format , ## args)
#define LBS_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define LBS_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_RESTART_SELECT
+ dprint(NDEBUG_LAST_BYTE_SENT, format , ## args)
#define RSS_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define RSS_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_EXTENDED
+ dprint(NDEBUG_RESTART_SELECT, format , ## args)
#define EXT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define EXT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_ABORT
+ dprint(NDEBUG_EXTENDED, format , ## args)
#define ABRT_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define ABRT_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_TAGS
+ dprint(NDEBUG_ABORT, format , ## args)
#define TAG_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define TAG_PRINTK(format, args...)
-#endif
-#if NDEBUG & NDEBUG_MERGING
+ dprint(NDEBUG_TAGS, format , ## args)
#define MER_PRINTK(format, args...) \
- printk(KERN_DEBUG format , ## args)
-#else
-#define MER_PRINTK(format, args...)
-#endif
+ dprint(NDEBUG_MERGING, format , ## args)
/* conditional macros for NCR5380_print_{,phase,status} */
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 2a2cc6cf118..2311019304c 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -319,10 +319,9 @@ ch_readconfig(scsi_changer *ch)
int result,id,lun,i;
u_int elem;
- buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+ buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
if (!buffer)
return -ENOMEM;
- memset(buffer,0,512);
memset(cmd,0,sizeof(cmd));
cmd[0] = MODE_SENSE;
@@ -530,10 +529,9 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
u_char *buffer;
int result;
- buffer = kmalloc(512, GFP_KERNEL);
+ buffer = kzalloc(512, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
- memset(buffer,0,512);
dprintk("%s %s voltag: 0x%x => \"%s\"\n",
clear ? "clear" : "set",
@@ -922,11 +920,10 @@ static int ch_probe(struct device *dev)
if (sd->type != TYPE_MEDIUM_CHANGER)
return -ENODEV;
- ch = kmalloc(sizeof(*ch), GFP_KERNEL);
+ ch = kzalloc(sizeof(*ch), GFP_KERNEL);
if (NULL == ch)
return -ENOMEM;
- memset(ch,0,sizeof(*ch));
ch->minor = ch_devcount;
sprintf(ch->name,"ch%d",ch->minor);
mutex_init(&ch->lock);
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 61f6024b61b..2a458d66b6f 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -202,31 +202,29 @@ static const char * get_sa_name(const struct value_name_pair * arr,
}
/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
-static void print_opcode_name(unsigned char * cdbp, int cdb_len,
- int start_of_line)
+static void print_opcode_name(unsigned char * cdbp, int cdb_len)
{
int sa, len, cdb0;
const char * name;
- const char * leadin = start_of_line ? KERN_INFO : "";
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
len = cdbp[7] + 8;
if (len < 10) {
- printk("%sshort variable length command, "
- "len=%d ext_len=%d", leadin, len, cdb_len);
+ printk("short variable length command, "
+ "len=%d ext_len=%d", len, cdb_len);
break;
}
sa = (cdbp[8] << 8) + cdbp[9];
name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
if (name) {
- printk("%s%s", leadin, name);
+ printk("%s", name);
if ((cdb_len > 0) && (len != cdb_len))
printk(", in_cdb_len=%d, ext_len=%d",
len, cdb_len);
} else {
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
if ((cdb_len > 0) && (len != cdb_len))
printk(", in_cdb_len=%d, ext_len=%d",
len, cdb_len);
@@ -236,83 +234,80 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len,
sa = cdbp[1] & 0x1f;
name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case MAINTENANCE_OUT:
sa = cdbp[1] & 0x1f;
name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_IN_12:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_OUT_12:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_IN_16:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
case SERVICE_ACTION_OUT_16:
sa = cdbp[1] & 0x1f;
name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
default:
if (cdb0 < 0xc0) {
name = cdb_byte0_names[cdb0];
if (name)
- printk("%s%s", leadin, name);
+ printk("%s", name);
else
- printk("%scdb[0]=0x%x (reserved)",
- leadin, cdb0);
+ printk("cdb[0]=0x%x (reserved)", cdb0);
} else
- printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+ printk("cdb[0]=0x%x (vendor)", cdb0);
break;
}
}
#else /* ifndef CONFIG_SCSI_CONSTANTS */
-static void print_opcode_name(unsigned char * cdbp, int cdb_len,
- int start_of_line)
+static void print_opcode_name(unsigned char * cdbp, int cdb_len)
{
int sa, len, cdb0;
- const char * leadin = start_of_line ? KERN_INFO : "";
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
len = cdbp[7] + 8;
if (len < 10) {
- printk("%sshort opcode=0x%x command, len=%d "
- "ext_len=%d", leadin, cdb0, len, cdb_len);
+ printk("short opcode=0x%x command, len=%d "
+ "ext_len=%d", cdb0, len, cdb_len);
break;
}
sa = (cdbp[8] << 8) + cdbp[9];
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
if (len != cdb_len)
printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
break;
@@ -323,49 +318,48 @@ static void print_opcode_name(unsigned char * cdbp, int cdb_len,
case SERVICE_ACTION_IN_16:
case SERVICE_ACTION_OUT_16:
sa = cdbp[1] & 0x1f;
- printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
break;
default:
if (cdb0 < 0xc0)
- printk("%scdb[0]=0x%x", leadin, cdb0);
+ printk("cdb[0]=0x%x", cdb0);
else
- printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+ printk("cdb[0]=0x%x (vendor)", cdb0);
break;
}
}
#endif
-void __scsi_print_command(unsigned char *command)
+void __scsi_print_command(unsigned char *cdb)
{
int k, len;
- print_opcode_name(command, 0, 1);
- if (VARIABLE_LENGTH_CMD == command[0])
- len = command[7] + 8;
+ print_opcode_name(cdb, 0);
+ if (VARIABLE_LENGTH_CMD == cdb[0])
+ len = cdb[7] + 8;
else
- len = COMMAND_SIZE(command[0]);
+ len = COMMAND_SIZE(cdb[0]);
/* print out all bytes in cdb */
for (k = 0; k < len; ++k)
- printk(" %02x", command[k]);
+ printk(" %02x", cdb[k]);
printk("\n");
}
EXPORT_SYMBOL(__scsi_print_command);
-/* This function (perhaps with the addition of peripheral device type)
- * is more approriate than __scsi_print_command(). Perhaps that static
- * can be dropped later if it replaces the __scsi_print_command version.
- */
-static void scsi_print_cdb(unsigned char *cdb, int cdb_len, int start_of_line)
+void scsi_print_command(struct scsi_cmnd *cmd)
{
int k;
- print_opcode_name(cdb, cdb_len, start_of_line);
+ scmd_printk(KERN_INFO, cmd, "CDB: ");
+ print_opcode_name(cmd->cmnd, cmd->cmd_len);
+
/* print out all bytes in cdb */
printk(":");
- for (k = 0; k < cdb_len; ++k)
- printk(" %02x", cdb[k]);
+ for (k = 0; k < cmd->cmd_len; ++k)
+ printk(" %02x", cmd->cmnd[k]);
printk("\n");
}
+EXPORT_SYMBOL(scsi_print_command);
/**
*
@@ -410,7 +404,11 @@ struct error_info {
const char * text;
};
-static struct error_info additional[] =
+/*
+ * The canonical list of T10 Additional Sense Codes is available at:
+ * http://www.t10.org/lists/asc-num.txt
+ */
+static const struct error_info additional[] =
{
{0x0000, "No additional sense information"},
{0x0001, "Filemark detected"},
@@ -714,6 +712,7 @@ static struct error_info additional[] =
{0x2F00, "Commands cleared by another initiator"},
{0x2F01, "Commands cleared by power loss notification"},
+ {0x2F02, "Commands cleared by device server"},
{0x3000, "Incompatible medium installed"},
{0x3001, "Cannot read medium - unknown format"},
@@ -1176,67 +1175,77 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
}
EXPORT_SYMBOL(scsi_extd_sense_format);
-/* Print extended sense information; no leadin, no linefeed */
-static void
+void
scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
{
- const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
+ const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
if (extd_sense_fmt) {
if (strstr(extd_sense_fmt, "%x")) {
- printk("Additional sense: ");
+ printk("Add. Sense: ");
printk(extd_sense_fmt, ascq);
} else
- printk("Additional sense: %s", extd_sense_fmt);
+ printk("Add. Sense: %s", extd_sense_fmt);
} else {
if (asc >= 0x80)
- printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc, ascq);
+ printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc,
+ ascq);
if (ascq >= 0x80)
- printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc, ascq);
+ printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc,
+ ascq);
else
printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
}
+
+ printk("\n");
}
+EXPORT_SYMBOL(scsi_show_extd_sense);
void
-scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr)
{
const char *sense_txt;
- /* An example of deferred is when an earlier write to disk cache
- * succeeded, but now the disk discovers that it cannot write the
- * data to the magnetic media.
- */
- const char *error = scsi_sense_is_deferred(sshdr) ?
- "<<DEFERRED>>" : "Current";
- printk(KERN_INFO "%s: %s", name, error);
- if (sshdr->response_code >= 0x72)
- printk(" [descriptor]");
sense_txt = scsi_sense_key_string(sshdr->sense_key);
if (sense_txt)
- printk(": sense key: %s\n", sense_txt);
+ printk("Sense Key : %s ", sense_txt);
else
- printk(": sense key=0x%x\n", sshdr->sense_key);
- printk(KERN_INFO " ");
- scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+ printk("Sense Key : 0x%x ", sshdr->sense_key);
+
+ printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " :
+ "[current] ");
+
+ if (sshdr->response_code >= 0x72)
+ printk("[descriptor]");
+
printk("\n");
}
+EXPORT_SYMBOL(scsi_show_sense_hdr);
+
+/*
+ * Print normalized SCSI sense header with a prefix.
+ */
+void
+scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+{
+ printk(KERN_INFO "%s: ", name);
+ scsi_show_sense_hdr(sshdr);
+ printk(KERN_INFO "%s: ", name);
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
EXPORT_SYMBOL(scsi_print_sense_hdr);
-/* Print sense information */
void
-__scsi_print_sense(const char *name, const unsigned char *sense_buffer,
- int sense_len)
+scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
+ struct scsi_sense_hdr *sshdr)
{
int k, num, res;
- unsigned int info;
- struct scsi_sense_hdr ssh;
- res = scsi_normalize_sense(sense_buffer, sense_len, &ssh);
+ res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
if (0 == res) {
/* this may be SCSI-1 sense data */
num = (sense_len < 32) ? sense_len : 32;
- printk(KERN_INFO "Unrecognized sense data (in hex):");
+ printk("Unrecognized sense data (in hex):");
for (k = 0; k < num; ++k) {
if (0 == (k % 16)) {
printk("\n");
@@ -1247,11 +1256,20 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
printk("\n");
return;
}
- scsi_print_sense_hdr(name, &ssh);
- if (ssh.response_code < 0x72) {
+}
+
+void
+scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
+ struct scsi_sense_hdr *sshdr)
+{
+ int k, num, res;
+
+ if (sshdr->response_code < 0x72)
+ {
/* only decode extras for "fixed" format now */
char buff[80];
int blen, fixed_valid;
+ unsigned int info;
fixed_valid = sense_buffer[0] & 0x80;
info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
@@ -1281,13 +1299,13 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
res += snprintf(buff + res, blen - res, "ILI");
}
if (res > 0)
- printk(KERN_INFO "%s\n", buff);
- } else if (ssh.additional_length > 0) {
+ printk("%s\n", buff);
+ } else if (sshdr->additional_length > 0) {
/* descriptor format with sense descriptors */
- num = 8 + ssh.additional_length;
+ num = 8 + sshdr->additional_length;
num = (sense_len < num) ? sense_len : num;
- printk(KERN_INFO "Descriptor sense data with sense "
- "descriptors (in hex):");
+ printk("Descriptor sense data with sense descriptors "
+ "(in hex):");
for (k = 0; k < num; ++k) {
if (0 == (k % 16)) {
printk("\n");
@@ -1295,29 +1313,42 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
}
printk("%02x ", sense_buffer[k]);
}
+
printk("\n");
}
+
}
-EXPORT_SYMBOL(__scsi_print_sense);
-void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd)
+/* Normalize and print sense buffer with name prefix */
+void __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
+ int sense_len)
{
- const char *name = devclass;
-
- if (cmd->request->rq_disk)
- name = cmd->request->rq_disk->disk_name;
- __scsi_print_sense(name, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+ struct scsi_sense_hdr sshdr;
+
+ printk(KERN_INFO "%s: ", name);
+ scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr);
+ scsi_show_sense_hdr(&sshdr);
+ scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr);
+ printk(KERN_INFO "%s: ", name);
+ scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
}
-EXPORT_SYMBOL(scsi_print_sense);
+EXPORT_SYMBOL(__scsi_print_sense);
-void scsi_print_command(struct scsi_cmnd *cmd)
+/* Normalize and print sense buffer in SCSI command */
+void scsi_print_sense(char *name, struct scsi_cmnd *cmd)
{
- /* Assume appended output (i.e. not at start of line) */
- sdev_printk("", cmd->device, "\n");
- printk(KERN_INFO " command: ");
- scsi_print_cdb(cmd->cmnd, cmd->cmd_len, 0);
+ struct scsi_sense_hdr sshdr;
+
+ scmd_printk(KERN_INFO, cmd, "");
+ scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+ scsi_show_sense_hdr(&sshdr);
+ scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+ scmd_printk(KERN_INFO, cmd, "");
+ scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
}
-EXPORT_SYMBOL(scsi_print_command);
+EXPORT_SYMBOL(scsi_print_sense);
#ifdef CONFIG_SCSI_CONSTANTS
@@ -1327,25 +1358,6 @@ static const char * const hostbyte_table[]={
"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
#define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
-void scsi_print_hostbyte(int scsiresult)
-{
- int hb = host_byte(scsiresult);
-
- printk("Hostbyte=0x%02x", hb);
- if (hb < NUM_HOSTBYTE_STRS)
- printk("(%s) ", hostbyte_table[hb]);
- else
- printk("is invalid ");
-}
-#else
-void scsi_print_hostbyte(int scsiresult)
-{
- printk("Hostbyte=0x%02x ", host_byte(scsiresult));
-}
-#endif
-
-#ifdef CONFIG_SCSI_CONSTANTS
-
static const char * const driverbyte_table[]={
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
@@ -1356,19 +1368,35 @@ static const char * const driversuggest_table[]={"SUGGEST_OK",
"SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"};
#define NUM_SUGGEST_STRS ARRAY_SIZE(driversuggest_table)
-void scsi_print_driverbyte(int scsiresult)
+void scsi_show_result(int result)
{
- int dr = (driver_byte(scsiresult) & DRIVER_MASK);
- int su = ((driver_byte(scsiresult) & SUGGEST_MASK) >> 4);
+ int hb = host_byte(result);
+ int db = (driver_byte(result) & DRIVER_MASK);
+ int su = ((driver_byte(result) & SUGGEST_MASK) >> 4);
- printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
- printk("(%s,%s) ",
- (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"),
+ printk("Result: hostbyte=%s driverbyte=%s,%s\n",
+ (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"),
+ (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"),
(su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid"));
}
+
#else
-void scsi_print_driverbyte(int scsiresult)
+
+void scsi_show_result(int result)
{
- printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
+ printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n",
+ host_byte(result), driver_byte(result));
}
+
#endif
+EXPORT_SYMBOL(scsi_show_result);
+
+
+void scsi_print_result(struct scsi_cmnd *cmd)
+{
+ scmd_printk(KERN_INFO, cmd, "");
+ scsi_show_result(cmd->result);
+}
+EXPORT_SYMBOL(scsi_print_result);
+
+
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index a965ed3548d..564ea90ed3a 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -541,7 +541,7 @@ static struct ParameterData __devinitdata cfg_data[] = {
/*
- * Safe settings. If set to zero the the BIOS/default values with
+ * Safe settings. If set to zero the BIOS/default values with
* command line overrides will be used. If set to 1 then safe and
* slow settings will be used.
*/
@@ -617,7 +617,7 @@ static void __devinit fix_settings(void)
/*
* Mapping from the eeprom delay index value (index into this array)
- * to the the number of actual seconds that the delay should be for.
+ * to the number of actual seconds that the delay should be for.
*/
static char __devinitdata eeprom_index_to_delay_map[] =
{ 1, 3, 5, 10, 16, 30, 60, 120 };
@@ -4136,7 +4136,7 @@ static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long
* @io_port: base I/O address
* @addr: offset into SEEPROM
*
- * Returns the the byte read.
+ * Returns the byte read.
**/
static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
{
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index 5a49216fe4c..100b49baca7 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -31,7 +31,7 @@
* Tunable parameters first
*/
-/* How many different OSM's are we allowing */
+/* How many different OSM's are we allowing */
#define MAX_I2O_MODULES 64
#define I2O_EVT_CAPABILITY_OTHER 0x01
@@ -63,7 +63,7 @@ struct i2o_message
u16 size;
u32 target_tid:12;
u32 init_tid:12;
- u32 function:8;
+ u32 function:8;
u32 initiator_context;
/* List follows */
};
@@ -77,7 +77,7 @@ struct i2o_device
char dev_name[8]; /* linux /dev name if available */
i2o_lct_entry lct_data;/* Device LCT information */
- u32 flags;
+ u32 flags;
struct proc_dir_entry* proc_entry; /* /proc dir */
struct adpt_device *owner;
struct _adpt_hba *controller; /* Controlling IOP */
@@ -86,7 +86,7 @@ struct i2o_device
/*
* Each I2O controller has one of these objects
*/
-
+
struct i2o_controller
{
char name[16];
@@ -111,9 +111,9 @@ struct i2o_sys_tbl_entry
u32 iop_id:12;
u32 reserved2:20;
u16 seg_num:12;
- u16 i2o_version:4;
- u8 iop_state;
- u8 msg_type;
+ u16 i2o_version:4;
+ u8 iop_state;
+ u8 msg_type;
u16 frame_size;
u16 reserved3;
u32 last_changed;
@@ -124,14 +124,14 @@ struct i2o_sys_tbl_entry
struct i2o_sys_tbl
{
- u8 num_entries;
- u8 version;
- u16 reserved1;
+ u8 num_entries;
+ u8 version;
+ u16 reserved1;
u32 change_ind;
u32 reserved2;
u32 reserved3;
struct i2o_sys_tbl_entry iops[0];
-};
+};
/*
* I2O classes / subclasses
@@ -146,7 +146,7 @@ struct i2o_sys_tbl
/* Class code names
* (from v1.5 Table 6-1 Class Code Assignments.)
*/
-
+
#define I2O_CLASS_EXECUTIVE 0x000
#define I2O_CLASS_DDM 0x001
#define I2O_CLASS_RANDOM_BLOCK_STORAGE 0x010
@@ -166,7 +166,7 @@ struct i2o_sys_tbl
/* Rest of 0x092 - 0x09f reserved for peer-to-peer classes
*/
-
+
#define I2O_CLASS_MATCH_ANYCLASS 0xffffffff
/* Subclasses
@@ -175,7 +175,7 @@ struct i2o_sys_tbl
#define I2O_SUBCLASS_i960 0x001
#define I2O_SUBCLASS_HDM 0x020
#define I2O_SUBCLASS_ISM 0x021
-
+
/* Operation functions */
#define I2O_PARAMS_FIELD_GET 0x0001
@@ -219,7 +219,7 @@ struct i2o_sys_tbl
/*
* Messaging API values
*/
-
+
#define I2O_CMD_ADAPTER_ASSIGN 0xB3
#define I2O_CMD_ADAPTER_READ 0xB2
#define I2O_CMD_ADAPTER_RELEASE 0xB5
@@ -284,16 +284,16 @@ struct i2o_sys_tbl
#define I2O_PRIVATE_MSG 0xFF
/*
- * Init Outbound Q status
+ * Init Outbound Q status
*/
-
+
#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01
#define I2O_CMD_OUTBOUND_INIT_REJECTED 0x02
#define I2O_CMD_OUTBOUND_INIT_FAILED 0x03
#define I2O_CMD_OUTBOUND_INIT_COMPLETE 0x04
/*
- * I2O Get Status State values
+ * I2O Get Status State values
*/
#define ADAPTER_STATE_INITIALIZING 0x01
@@ -303,7 +303,7 @@ struct i2o_sys_tbl
#define ADAPTER_STATE_OPERATIONAL 0x08
#define ADAPTER_STATE_FAILED 0x10
#define ADAPTER_STATE_FAULTED 0x11
-
+
/* I2O API function return values */
#define I2O_RTN_NO_ERROR 0
@@ -321,9 +321,9 @@ struct i2o_sys_tbl
/* Reply message status defines for all messages */
-#define I2O_REPLY_STATUS_SUCCESS 0x00
-#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
-#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define I2O_REPLY_STATUS_SUCCESS 0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
@@ -338,7 +338,7 @@ struct i2o_sys_tbl
#define I2O_PARAMS_STATUS_SUCCESS 0x00
#define I2O_PARAMS_STATUS_BAD_KEY_ABORT 0x01
-#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02
#define I2O_PARAMS_STATUS_BUFFER_FULL 0x03
#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL 0x04
#define I2O_PARAMS_STATUS_FIELD_UNREADABLE 0x05
@@ -390,7 +390,7 @@ struct i2o_sys_tbl
#define I2O_CLAIM_MANAGEMENT 0x02000000
#define I2O_CLAIM_AUTHORIZED 0x03000000
#define I2O_CLAIM_SECONDARY 0x04000000
-
+
/* Message header defines for VersionOffset */
#define I2OVER15 0x0001
#define I2OVER20 0x0002
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index 82d24864be0..cc784e8f6e9 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -99,7 +99,7 @@ typedef struct {
uCHAR eataVersion; /* EATA Version */
uLONG cpLength; /* EATA Command Packet Length */
uLONG spLength; /* EATA Status Packet Length */
- uCHAR drqNum; /* DRQ Index (0,5,6,7) */
+ uCHAR drqNum; /* DRQ Index (0,5,6,7) */
uCHAR flag1; /* EATA Flags 1 (Byte 9) */
uCHAR flag2; /* EATA Flags 2 (Byte 30) */
} CtrlInfo;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 4bf44779212..94bc894d120 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -145,8 +145,8 @@ typedef unsigned long sigLONG;
#define FT_LOGGER 12 /* Event Logger */
#define FT_INSTALL 13 /* An Install Program */
#define FT_LIBRARY 14 /* Storage Manager Real-Mode Calls */
-#define FT_RESOURCE 15 /* Storage Manager Resource File */
-#define FT_MODEM_DB 16 /* Storage Manager Modem Database */
+#define FT_RESOURCE 15 /* Storage Manager Resource File */
+#define FT_MODEM_DB 16 /* Storage Manager Modem Database */
/* Filetype flags - sigBYTE dsFiletypeFlags; FLAG BITS */
/* ------------------------------------------------------------------ */
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index cd36e81b2d9..8c7d2bbf9b1 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -55,7 +55,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
#include <linux/sched.h>
#include <linux/reboot.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/dma-mapping.h>
#include <linux/timer.h>
@@ -195,8 +194,6 @@ static int adpt_detect(struct scsi_host_template* sht)
pci_dev_get(pDev);
}
}
- if (pDev)
- pci_dev_put(pDev);
/* In INIT state, Activate IOPs */
for (pHba = hba_chain; pHba; pHba = pHba->next) {
@@ -1311,13 +1308,12 @@ static s32 adpt_i2o_reset_hba(adpt_hba* pHba)
schedule_timeout_uninterruptible(1);
} while (m == EMPTY_QUEUE);
- status = kmalloc(4, GFP_KERNEL|ADDR32);
+ status = kzalloc(4, GFP_KERNEL|ADDR32);
if(status == NULL) {
adpt_send_nop(pHba, m);
printk(KERN_ERR"IOP reset failed - no free memory.\n");
return -ENOMEM;
}
- memset(status,0,4);
msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1507,21 +1503,19 @@ static int adpt_i2o_parse_lct(adpt_hba* pHba)
continue;
}
if( pHba->channel[bus_no].device[scsi_id] == NULL){
- pDev = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
if(pDev == NULL) {
return -ENOMEM;
}
pHba->channel[bus_no].device[scsi_id] = pDev;
- memset(pDev,0,sizeof(struct adpt_device));
} else {
for( pDev = pHba->channel[bus_no].device[scsi_id];
pDev->next_lun; pDev = pDev->next_lun){
}
- pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
if(pDev->next_lun == NULL) {
return -ENOMEM;
}
- memset(pDev->next_lun,0,sizeof(struct adpt_device));
pDev = pDev->next_lun;
}
pDev->tid = tid;
@@ -1670,12 +1664,11 @@ static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
reply_size = REPLY_FRAME_SIZE;
}
reply_size *= 4;
- reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
+ reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
if(reply == NULL) {
printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name);
return -ENOMEM;
}
- memset(reply,0,REPLY_FRAME_SIZE*4);
sg_offset = (msg[0]>>4)&0xf;
msg[2] = 0x40000000; // IOCTL context
msg[3] = (u32)reply;
@@ -2447,7 +2440,7 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
}
pDev = pHba->channel[bus_no].device[scsi_id];
if( pDev == NULL){
- pDev = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
if(pDev == NULL) {
return -ENOMEM;
}
@@ -2456,12 +2449,11 @@ static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
while (pDev->next_lun) {
pDev = pDev->next_lun;
}
- pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+ pDev = pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL);
if(pDev == NULL) {
return -ENOMEM;
}
}
- memset(pDev,0,sizeof(struct adpt_device));
pDev->tid = d->lct_data.tid;
pDev->scsi_channel = bus_no;
pDev->scsi_id = scsi_id;
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
index 635c14861f8..5016af5cf86 100644
--- a/drivers/scsi/eata_generic.h
+++ b/drivers/scsi/eata_generic.h
@@ -18,13 +18,6 @@
* Misc. definitions *
*********************************************/
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
#define R_LIMIT 0x20000
#define MAXISA 4
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 3cd5bf723da..ec71061aef6 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
+#include <linux/irqreturn.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -1706,17 +1707,17 @@ again:
if (!dma_len) {
printk(KERN_ERR PFX "esp%d: DMA length is zero!\n",
esp->host->unique_id);
- printk(KERN_ERR PFX "esp%d: cur adr[%08x] len[%08x]\n",
+ printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n",
esp->host->unique_id,
- esp_cur_dma_addr(ent, cmd),
+ (unsigned long long)esp_cur_dma_addr(ent, cmd),
esp_cur_dma_len(ent, cmd));
esp_schedule_reset(esp);
return 0;
}
- esp_log_datastart("ESP: start data addr[%08x] len[%u] "
+ esp_log_datastart("ESP: start data addr[%08llx] len[%u] "
"write(%d)\n",
- dma_addr, dma_len, write);
+ (unsigned long long)dma_addr, dma_len, write);
esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
write, ESP_CMD_DMA | ESP_CMD_TI);
@@ -2211,7 +2212,7 @@ static void __devinit esp_init_swstate(struct esp *esp)
}
/* This places the ESP into a known state at boot time. */
-static void __devinit esp_bootup_reset(struct esp *esp)
+static void esp_bootup_reset(struct esp *esp)
{
u8 val;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index fbc1d5c3b0a..b10eefe735c 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -85,7 +85,7 @@
static int max_id = 64;
static int max_channel = 3;
static int init_timeout = 5;
-static int max_requests = 50;
+static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT;
#define IBMVSCSI_VERSION "1.5.8"
@@ -538,7 +538,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
int request_status;
int rc;
- /* If we have exhausted our request limit, just fail this request.
+ /* If we have exhausted our request limit, just fail this request,
+ * unless it is for a reset or abort.
* Note that there are rare cases involving driver generated requests
* (such as task management requests) that the mid layer may think we
* can handle more requests (can_queue) when we actually can't
@@ -551,9 +552,30 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
*/
if (request_status < -1)
goto send_error;
- /* Otherwise, if we have run out of requests */
- else if (request_status < 0)
- goto send_busy;
+ /* Otherwise, we may have run out of requests. */
+ /* Abort and reset calls should make it through.
+ * Nothing except abort and reset should use the last two
+ * slots unless we had two or less to begin with.
+ */
+ else if (request_status < 2 &&
+ evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) {
+ /* In the case that we have less than two requests
+ * available, check the server limit as a combination
+ * of the request limit and the number of requests
+ * in-flight (the size of the send list). If the
+ * server limit is greater than 2, return busy so
+ * that the last two are reserved for reset and abort.
+ */
+ int server_limit = request_status;
+ struct srp_event_struct *tmp_evt;
+
+ list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+ server_limit++;
+ }
+
+ if (server_limit > 2)
+ goto send_busy;
+ }
}
/* Copy the IU into the transfer area */
@@ -572,6 +594,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
printk(KERN_ERR "ibmvscsi: send error %d\n",
rc);
+ atomic_inc(&hostdata->request_limit);
goto send_error;
}
@@ -581,7 +604,8 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
- return SCSI_MLQUEUE_HOST_BUSY;
+ atomic_inc(&hostdata->request_limit);
+ return SCSI_MLQUEUE_HOST_BUSY;
send_error:
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
@@ -831,23 +855,16 @@ static void login_rsp(struct srp_event_struct *evt_struct)
printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
- if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta >
- (max_requests - 2))
- evt_struct->xfer_iu->srp.login_rsp.req_lim_delta =
- max_requests - 2;
+ if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
+ printk(KERN_ERR "ibmvscsi: Invalid request_limit.\n");
- /* Now we know what the real request-limit is */
+ /* Now we know what the real request-limit is.
+ * This value is set rather than added to request_limit because
+ * request_limit could have been set to -1 by this client.
+ */
atomic_set(&hostdata->request_limit,
evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
- hostdata->host->can_queue =
- evt_struct->xfer_iu->srp.login_rsp.req_lim_delta - 2;
-
- if (hostdata->host->can_queue < 1) {
- printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
- return;
- }
-
/* If we had any pending I/Os, kick them */
scsi_unblock_requests(hostdata->host);
@@ -1337,6 +1354,27 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
return rc;
}
+/**
+ * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk.
+ * @sdev: struct scsi_device device to configure
+ *
+ * Enable allow_restart for a device if it is a disk. Adjust the
+ * queue_depth here also as is required by the documentation for
+ * struct scsi_host_template.
+ */
+static int ibmvscsi_slave_configure(struct scsi_device *sdev)
+{
+ struct Scsi_Host *shost = sdev->host;
+ unsigned long lock_flags = 0;
+
+ spin_lock_irqsave(shost->host_lock, lock_flags);
+ if (sdev->type == TYPE_DISK)
+ sdev->allow_restart = 1;
+ scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
+ spin_unlock_irqrestore(shost->host_lock, lock_flags);
+ return 0;
+}
+
/* ------------------------------------------------------------
* sysfs attributes
*/
@@ -1482,8 +1520,9 @@ static struct scsi_host_template driver_template = {
.queuecommand = ibmvscsi_queuecommand,
.eh_abort_handler = ibmvscsi_eh_abort_handler,
.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+ .slave_configure = ibmvscsi_slave_configure,
.cmd_per_lun = 16,
- .can_queue = 1, /* Updated after SRP_LOGIN */
+ .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
.this_id = -1,
.sg_tablesize = SG_ALL,
.use_clustering = ENABLE_CLUSTERING,
@@ -1503,6 +1542,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
vdev->dev.driver_data = NULL;
+ driver_template.can_queue = max_requests;
host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
if (!host) {
printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 5c6d9358292..77cc1d40f5b 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -44,6 +44,8 @@ struct Scsi_Host;
*/
#define MAX_INDIRECT_BUFS 10
+#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
+
/* ------------------------------------------------------------
* Data Structures
*/
diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c
index 4368ca0e827..8ba7dd09d01 100644
--- a/drivers/scsi/ibmvscsi/ibmvstgt.c
+++ b/drivers/scsi/ibmvscsi/ibmvstgt.c
@@ -35,7 +35,7 @@
#include "ibmvscsi.h"
#define INITIAL_SRP_LIMIT 16
-#define DEFAULT_MAX_SECTORS 512
+#define DEFAULT_MAX_SECTORS 256
#define TGT_NAME "ibmvstgt"
@@ -248,8 +248,8 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
md[i].va + mdone);
if (err != H_SUCCESS) {
- eprintk("rdma error %d %d\n", dir, slen);
- goto out;
+ eprintk("rdma error %d %d %ld\n", dir, slen, err);
+ return -EIO;
}
mlen -= slen;
@@ -265,45 +265,35 @@ static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg,
if (sidx > nsg) {
eprintk("out of sg %p %d %d\n",
iue, sidx, nsg);
- goto out;
+ return -EIO;
}
}
};
rest -= mlen;
}
-out:
-
return 0;
}
-static int ibmvstgt_transfer_data(struct scsi_cmnd *sc,
- void (*done)(struct scsi_cmnd *))
-{
- struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
- int err;
-
- err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
-
- done(sc);
-
- return err;
-}
-
static int ibmvstgt_cmd_done(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *))
{
unsigned long flags;
struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr;
struct srp_target *target = iue->target;
+ int err = 0;
- dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]);
+ dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0],
+ cmd->usg_sg);
+
+ if (sc->use_sg)
+ err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1);
spin_lock_irqsave(&target->lock, flags);
list_del(&iue->ilist);
spin_unlock_irqrestore(&target->lock, flags);
- if (sc->result != SAM_STAT_GOOD) {
+ if (err|| sc->result != SAM_STAT_GOOD) {
eprintk("operation failed %p %d %x\n",
iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]);
send_rsp(iue, sc, HARDWARE_ERROR, 0x00);
@@ -503,7 +493,8 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
{
struct vio_port *vport = target_to_port(target);
struct iu_entry *iue;
- long err, done;
+ long err;
+ int done = 1;
iue = srp_iu_get(target);
if (!iue) {
@@ -518,7 +509,6 @@ static void process_iu(struct viosrp_crq *crq, struct srp_target *target)
if (err != H_SUCCESS) {
eprintk("%ld transferring data error %p\n", err, iue);
- done = 1;
goto out;
}
@@ -794,7 +784,6 @@ static struct scsi_host_template ibmvstgt_sht = {
.use_clustering = DISABLE_CLUSTERING,
.max_sectors = DEFAULT_MAX_SECTORS,
.transfer_response = ibmvstgt_cmd_done,
- .transfer_data = ibmvstgt_transfer_data,
.eh_abort_handler = ibmvstgt_eh_abort_handler,
.tsk_mgmt_response = ibmvstgt_tsk_mgmt_response,
.shost_attrs = ibmvstgt_attrs,
@@ -897,25 +886,26 @@ static int get_system_info(void)
{
struct device_node *rootdn;
const char *id, *model, *name;
- unsigned int *num;
+ const unsigned int *num;
- rootdn = find_path_device("/");
+ rootdn = of_find_node_by_path("/");
if (!rootdn)
return -ENOENT;
- model = get_property(rootdn, "model", NULL);
- id = get_property(rootdn, "system-id", NULL);
+ model = of_get_property(rootdn, "model", NULL);
+ id = of_get_property(rootdn, "system-id", NULL);
if (model && id)
snprintf(system_id, sizeof(system_id), "%s-%s", model, id);
- name = get_property(rootdn, "ibm,partition-name", NULL);
+ name = of_get_property(rootdn, "ibm,partition-name", NULL);
if (name)
strncpy(partition_name, name, sizeof(partition_name));
- num = (unsigned int *) get_property(rootdn, "ibm,partition-no", NULL);
+ num = of_get_property(rootdn, "ibm,partition-no", NULL);
if (num)
partition_number = *num;
+ of_node_put(rootdn);
return 0;
}
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 227c0f2f4d7..d8700aaa611 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -157,18 +157,19 @@ static void gather_partition_info(void)
const unsigned int *p_number_ptr;
/* Retrieve information about this partition */
- rootdn = find_path_device("/");
+ rootdn = of_find_node_by_path("/");
if (!rootdn) {
return;
}
- ppartition_name = get_property(rootdn, "ibm,partition-name", NULL);
+ ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL);
if (ppartition_name)
strncpy(partition_name, ppartition_name,
sizeof(partition_name));
- p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
+ p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL);
if (p_number_ptr)
partition_number = *p_number_ptr;
+ of_node_put(rootdn);
}
static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 95045e33710..4baa79e6867 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -89,10 +89,10 @@ static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
static unsigned int ipr_max_speed = 1;
static int ipr_testmode = 0;
static unsigned int ipr_fastfail = 0;
-static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+static unsigned int ipr_transop_timeout = 0;
static unsigned int ipr_enable_cache = 1;
static unsigned int ipr_debug = 0;
-static int ipr_auto_create = 1;
+static unsigned int ipr_dual_ioa_raid = 1;
static DEFINE_SPINLOCK(ipr_driver_lock);
/* This table describes the differences between DMA controller chips */
@@ -159,15 +159,15 @@ module_param_named(enable_cache, ipr_enable_cache, int, 0);
MODULE_PARM_DESC(enable_cache, "Enable adapter's non-volatile write cache (default: 1)");
module_param_named(debug, ipr_debug, int, 0);
MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
-module_param_named(auto_create, ipr_auto_create, int, 0);
-MODULE_PARM_DESC(auto_create, "Auto-create single device RAID 0 arrays when initialized (default: 1)");
+module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
+MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
MODULE_LICENSE("GPL");
MODULE_VERSION(IPR_DRIVER_VERSION);
/* A constant array of IOASCs/URCs/Error Messages */
static const
struct ipr_error_table_t ipr_error_table[] = {
- {0x00000000, 1, 1,
+ {0x00000000, 1, IPR_DEFAULT_LOG_LEVEL,
"8155: An unknown error was received"},
{0x00330000, 0, 0,
"Soft underlength error"},
@@ -175,125 +175,127 @@ struct ipr_error_table_t ipr_error_table[] = {
"Command to be cancelled not found"},
{0x00808000, 0, 0,
"Qualified success"},
- {0x01080000, 1, 1,
+ {0x01080000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFFE: Soft device bus error recovered by the IOA"},
- {0x01088100, 0, 1,
+ {0x01088100, 0, IPR_DEFAULT_LOG_LEVEL,
"4101: Soft device bus fabric error"},
- {0x01170600, 0, 1,
+ {0x01170600, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF9: Device sector reassign successful"},
- {0x01170900, 0, 1,
+ {0x01170900, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF7: Media error recovered by device rewrite procedures"},
- {0x01180200, 0, 1,
+ {0x01180200, 0, IPR_DEFAULT_LOG_LEVEL,
"7001: IOA sector reassignment successful"},
- {0x01180500, 0, 1,
+ {0x01180500, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF9: Soft media error. Sector reassignment recommended"},
- {0x01180600, 0, 1,
+ {0x01180600, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF7: Media error recovered by IOA rewrite procedures"},
- {0x01418000, 0, 1,
+ {0x01418000, 0, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Soft PCI bus error recovered by the IOA"},
- {0x01440000, 1, 1,
+ {0x01440000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device hardware error recovered by the IOA"},
- {0x01448100, 0, 1,
+ {0x01448100, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device hardware error recovered by the device"},
- {0x01448200, 1, 1,
+ {0x01448200, 1, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Soft IOA error recovered by the IOA"},
- {0x01448300, 0, 1,
+ {0x01448300, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFA: Undefined device response recovered by the IOA"},
- {0x014A0000, 1, 1,
+ {0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device bus error, message or command phase"},
- {0x014A8000, 0, 1,
+ {0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFE: Task Management Function failed"},
- {0x015D0000, 0, 1,
+ {0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Failure prediction threshold exceeded"},
- {0x015D9200, 0, 1,
+ {0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL,
"8009: Impending cache battery pack failure"},
{0x02040400, 0, 0,
"34FF: Disk device format in progress"},
+ {0x02048000, 0, IPR_DEFAULT_LOG_LEVEL,
+ "9070: IOA requested reset"},
{0x023F0000, 0, 0,
"Synchronization required"},
{0x024E0000, 0, 0,
"No ready, IOA shutdown"},
{0x025A0000, 0, 0,
"Not ready, IOA has been shutdown"},
- {0x02670100, 0, 1,
+ {0x02670100, 0, IPR_DEFAULT_LOG_LEVEL,
"3020: Storage subsystem configuration error"},
{0x03110B00, 0, 0,
"FFF5: Medium error, data unreadable, recommend reassign"},
{0x03110C00, 0, 0,
"7000: Medium error, data unreadable, do not reassign"},
- {0x03310000, 0, 1,
+ {0x03310000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF3: Disk media format bad"},
- {0x04050000, 0, 1,
+ {0x04050000, 0, IPR_DEFAULT_LOG_LEVEL,
"3002: Addressed device failed to respond to selection"},
- {0x04080000, 1, 1,
+ {0x04080000, 1, IPR_DEFAULT_LOG_LEVEL,
"3100: Device bus error"},
- {0x04080100, 0, 1,
+ {0x04080100, 0, IPR_DEFAULT_LOG_LEVEL,
"3109: IOA timed out a device command"},
{0x04088000, 0, 0,
"3120: SCSI bus is not operational"},
- {0x04088100, 0, 1,
+ {0x04088100, 0, IPR_DEFAULT_LOG_LEVEL,
"4100: Hard device bus fabric error"},
- {0x04118000, 0, 1,
+ {0x04118000, 0, IPR_DEFAULT_LOG_LEVEL,
"9000: IOA reserved area data check"},
- {0x04118100, 0, 1,
+ {0x04118100, 0, IPR_DEFAULT_LOG_LEVEL,
"9001: IOA reserved area invalid data pattern"},
- {0x04118200, 0, 1,
+ {0x04118200, 0, IPR_DEFAULT_LOG_LEVEL,
"9002: IOA reserved area LRC error"},
- {0x04320000, 0, 1,
+ {0x04320000, 0, IPR_DEFAULT_LOG_LEVEL,
"102E: Out of alternate sectors for disk storage"},
- {0x04330000, 1, 1,
+ {0x04330000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Data transfer underlength error"},
- {0x04338000, 1, 1,
+ {0x04338000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Data transfer overlength error"},
- {0x043E0100, 0, 1,
+ {0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL,
"3400: Logical unit failure"},
- {0x04408500, 0, 1,
+ {0x04408500, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Device microcode is corrupt"},
- {0x04418000, 1, 1,
+ {0x04418000, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: PCI bus error"},
{0x04430000, 1, 0,
"Unsupported device bus message received"},
- {0x04440000, 1, 1,
+ {0x04440000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Disk device problem"},
- {0x04448200, 1, 1,
+ {0x04448200, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: Permanent IOA failure"},
- {0x04448300, 0, 1,
+ {0x04448300, 0, IPR_DEFAULT_LOG_LEVEL,
"3010: Disk device returned wrong response to IOA"},
- {0x04448400, 0, 1,
+ {0x04448400, 0, IPR_DEFAULT_LOG_LEVEL,
"8151: IOA microcode error"},
{0x04448500, 0, 0,
"Device bus status error"},
- {0x04448600, 0, 1,
+ {0x04448600, 0, IPR_DEFAULT_LOG_LEVEL,
"8157: IOA error requiring IOA reset to recover"},
{0x04448700, 0, 0,
"ATA device status error"},
{0x04490000, 0, 0,
"Message reject received from the device"},
- {0x04449200, 0, 1,
+ {0x04449200, 0, IPR_DEFAULT_LOG_LEVEL,
"8008: A permanent cache battery pack failure occurred"},
- {0x0444A000, 0, 1,
+ {0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL,
"9090: Disk unit has been modified after the last known status"},
- {0x0444A200, 0, 1,
+ {0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL,
"9081: IOA detected device error"},
- {0x0444A300, 0, 1,
+ {0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL,
"9082: IOA detected device error"},
- {0x044A0000, 1, 1,
+ {0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL,
"3110: Device bus error, message or command phase"},
- {0x044A8000, 1, 1,
+ {0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL,
"3110: SAS Command / Task Management Function failed"},
- {0x04670400, 0, 1,
+ {0x04670400, 0, IPR_DEFAULT_LOG_LEVEL,
"9091: Incorrect hardware configuration change has been detected"},
- {0x04678000, 0, 1,
+ {0x04678000, 0, IPR_DEFAULT_LOG_LEVEL,
"9073: Invalid multi-adapter configuration"},
- {0x04678100, 0, 1,
+ {0x04678100, 0, IPR_DEFAULT_LOG_LEVEL,
"4010: Incorrect connection between cascaded expanders"},
- {0x04678200, 0, 1,
+ {0x04678200, 0, IPR_DEFAULT_LOG_LEVEL,
"4020: Connections exceed IOA design limits"},
- {0x04678300, 0, 1,
+ {0x04678300, 0, IPR_DEFAULT_LOG_LEVEL,
"4030: Incorrect multipath connection"},
- {0x04679000, 0, 1,
+ {0x04679000, 0, IPR_DEFAULT_LOG_LEVEL,
"4110: Unsupported enclosure function"},
- {0x046E0000, 0, 1,
+ {0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Command to logical unit failed"},
{0x05240000, 1, 0,
"Illegal request, invalid request type or request packet"},
@@ -313,101 +315,103 @@ struct ipr_error_table_t ipr_error_table[] = {
"Illegal request, command sequence error"},
{0x052C8000, 1, 0,
"Illegal request, dual adapter support not enabled"},
- {0x06040500, 0, 1,
+ {0x06040500, 0, IPR_DEFAULT_LOG_LEVEL,
"9031: Array protection temporarily suspended, protection resuming"},
- {0x06040600, 0, 1,
+ {0x06040600, 0, IPR_DEFAULT_LOG_LEVEL,
"9040: Array protection temporarily suspended, protection resuming"},
- {0x06288000, 0, 1,
+ {0x06288000, 0, IPR_DEFAULT_LOG_LEVEL,
"3140: Device bus not ready to ready transition"},
- {0x06290000, 0, 1,
+ {0x06290000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFB: SCSI bus was reset"},
{0x06290500, 0, 0,
"FFFE: SCSI bus transition to single ended"},
{0x06290600, 0, 0,
"FFFE: SCSI bus transition to LVD"},
- {0x06298000, 0, 1,
+ {0x06298000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFB: SCSI bus was reset by another initiator"},
- {0x063F0300, 0, 1,
+ {0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL,
"3029: A device replacement has occurred"},
- {0x064C8000, 0, 1,
+ {0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL,
"9051: IOA cache data exists for a missing or failed device"},
- {0x064C8100, 0, 1,
+ {0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL,
"9055: Auxiliary cache IOA contains cache data needed by the primary IOA"},
- {0x06670100, 0, 1,
+ {0x06670100, 0, IPR_DEFAULT_LOG_LEVEL,
"9025: Disk unit is not supported at its physical location"},
- {0x06670600, 0, 1,
+ {0x06670600, 0, IPR_DEFAULT_LOG_LEVEL,
"3020: IOA detected a SCSI bus configuration error"},
- {0x06678000, 0, 1,
+ {0x06678000, 0, IPR_DEFAULT_LOG_LEVEL,
"3150: SCSI bus configuration error"},
- {0x06678100, 0, 1,
+ {0x06678100, 0, IPR_DEFAULT_LOG_LEVEL,
"9074: Asymmetric advanced function disk configuration"},
- {0x06678300, 0, 1,
+ {0x06678300, 0, IPR_DEFAULT_LOG_LEVEL,
"4040: Incomplete multipath connection between IOA and enclosure"},
- {0x06678400, 0, 1,
+ {0x06678400, 0, IPR_DEFAULT_LOG_LEVEL,
"4041: Incomplete multipath connection between enclosure and device"},
- {0x06678500, 0, 1,
+ {0x06678500, 0, IPR_DEFAULT_LOG_LEVEL,
"9075: Incomplete multipath connection between IOA and remote IOA"},
- {0x06678600, 0, 1,
+ {0x06678600, 0, IPR_DEFAULT_LOG_LEVEL,
"9076: Configuration error, missing remote IOA"},
- {0x06679100, 0, 1,
+ {0x06679100, 0, IPR_DEFAULT_LOG_LEVEL,
"4050: Enclosure does not support a required multipath function"},
- {0x06690200, 0, 1,
+ {0x06690200, 0, IPR_DEFAULT_LOG_LEVEL,
"9041: Array protection temporarily suspended"},
- {0x06698200, 0, 1,
+ {0x06698200, 0, IPR_DEFAULT_LOG_LEVEL,
"9042: Corrupt array parity detected on specified device"},
- {0x066B0200, 0, 1,
+ {0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL,
"9030: Array no longer protected due to missing or failed disk unit"},
- {0x066B8000, 0, 1,
+ {0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL,
"9071: Link operational transition"},
- {0x066B8100, 0, 1,
+ {0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL,
"9072: Link not operational transition"},
- {0x066B8200, 0, 1,
+ {0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL,
"9032: Array exposed but still protected"},
- {0x066B9100, 0, 1,
+ {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1,
+ "70DD: Device forced failed by disrupt device command"},
+ {0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL,
"4061: Multipath redundancy level got better"},
- {0x066B9200, 0, 1,
+ {0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL,
"4060: Multipath redundancy level got worse"},
{0x07270000, 0, 0,
"Failure due to other device"},
- {0x07278000, 0, 1,
+ {0x07278000, 0, IPR_DEFAULT_LOG_LEVEL,
"9008: IOA does not support functions expected by devices"},
- {0x07278100, 0, 1,
+ {0x07278100, 0, IPR_DEFAULT_LOG_LEVEL,
"9010: Cache data associated with attached devices cannot be found"},
- {0x07278200, 0, 1,
+ {0x07278200, 0, IPR_DEFAULT_LOG_LEVEL,
"9011: Cache data belongs to devices other than those attached"},
- {0x07278400, 0, 1,
+ {0x07278400, 0, IPR_DEFAULT_LOG_LEVEL,
"9020: Array missing 2 or more devices with only 1 device present"},
- {0x07278500, 0, 1,
+ {0x07278500, 0, IPR_DEFAULT_LOG_LEVEL,
"9021: Array missing 2 or more devices with 2 or more devices present"},
- {0x07278600, 0, 1,
+ {0x07278600, 0, IPR_DEFAULT_LOG_LEVEL,
"9022: Exposed array is missing a required device"},
- {0x07278700, 0, 1,
+ {0x07278700, 0, IPR_DEFAULT_LOG_LEVEL,
"9023: Array member(s) not at required physical locations"},
- {0x07278800, 0, 1,
+ {0x07278800, 0, IPR_DEFAULT_LOG_LEVEL,
"9024: Array not functional due to present hardware configuration"},
- {0x07278900, 0, 1,
+ {0x07278900, 0, IPR_DEFAULT_LOG_LEVEL,
"9026: Array not functional due to present hardware configuration"},
- {0x07278A00, 0, 1,
+ {0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL,
"9027: Array is missing a device and parity is out of sync"},
- {0x07278B00, 0, 1,
+ {0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL,
"9028: Maximum number of arrays already exist"},
- {0x07278C00, 0, 1,
+ {0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL,
"9050: Required cache data cannot be located for a disk unit"},
- {0x07278D00, 0, 1,
+ {0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL,
"9052: Cache data exists for a device that has been modified"},
- {0x07278F00, 0, 1,
+ {0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL,
"9054: IOA resources not available due to previous problems"},
- {0x07279100, 0, 1,
+ {0x07279100, 0, IPR_DEFAULT_LOG_LEVEL,
"9092: Disk unit requires initialization before use"},
- {0x07279200, 0, 1,
+ {0x07279200, 0, IPR_DEFAULT_LOG_LEVEL,
"9029: Incorrect hardware configuration change has been detected"},
- {0x07279600, 0, 1,
+ {0x07279600, 0, IPR_DEFAULT_LOG_LEVEL,
"9060: One or more disk pairs are missing from an array"},
- {0x07279700, 0, 1,
+ {0x07279700, 0, IPR_DEFAULT_LOG_LEVEL,
"9061: One or more disks are missing from an array"},
- {0x07279800, 0, 1,
+ {0x07279800, 0, IPR_DEFAULT_LOG_LEVEL,
"9062: One or more disks are missing from an array"},
- {0x07279900, 0, 1,
+ {0x07279900, 0, IPR_DEFAULT_LOG_LEVEL,
"9063: Maximum number of functional arrays has been exceeded"},
{0x0B260000, 0, 0,
"Aborted command, invalid descriptor"},
@@ -481,12 +485,16 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+ dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
ioarcb->write_data_transfer_length = 0;
ioarcb->read_data_transfer_length = 0;
ioarcb->write_ioadl_len = 0;
ioarcb->read_ioadl_len = 0;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
ioasa->ioasc = 0;
ioasa->residual_data_len = 0;
ioasa->u.gata.status = 0;
@@ -948,6 +956,53 @@ static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
}
/**
+ * strip_and_pad_whitespace - Strip and pad trailing whitespace.
+ * @i: index into buffer
+ * @buf: string to modify
+ *
+ * This function will strip all trailing whitespace, pad the end
+ * of the string with a single space, and NULL terminate the string.
+ *
+ * Return value:
+ * new length of string
+ **/
+static int strip_and_pad_whitespace(int i, char *buf)
+{
+ while (i && buf[i] == ' ')
+ i--;
+ buf[i+1] = ' ';
+ buf[i+2] = '\0';
+ return i + 2;
+}
+
+/**
+ * ipr_log_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix: string to print at start of printk
+ * @hostrcb: hostrcb pointer
+ * @vpd: vendor/product id/sn struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+ struct ipr_vpd *vpd)
+{
+ char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3];
+ int i = 0;
+
+ memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN);
+ i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer);
+
+ memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN);
+ i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer);
+
+ memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN);
+ buffer[IPR_SERIAL_NUM_LEN + i] = '\0';
+
+ ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer);
+}
+
+/**
* ipr_log_vpd - Log the passed VPD to the error log.
* @vpd: vendor/product id/sn struct
*
@@ -971,6 +1026,23 @@ static void ipr_log_vpd(struct ipr_vpd *vpd)
}
/**
+ * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly.
+ * @prefix: string to print at start of printk
+ * @hostrcb: hostrcb pointer
+ * @vpd: vendor/product id/sn/wwn struct
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb,
+ struct ipr_ext_vpd *vpd)
+{
+ ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd);
+ ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix,
+ be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1]));
+}
+
+/**
* ipr_log_ext_vpd - Log the passed extended VPD to the error log.
* @vpd: vendor/product id/sn/wwn struct
*
@@ -1284,10 +1356,11 @@ static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
error = &hostrcb->hcam.u.error.u.type_17_error;
error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+ strstrip(error->failure_reason);
- ipr_err("%s\n", error->failure_reason);
- ipr_err("Remote Adapter VPD:\n");
- ipr_log_ext_vpd(&error->vpd);
+ ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+ be32_to_cpu(hostrcb->hcam.u.error.prc));
+ ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd);
ipr_log_hex_data(ioa_cfg, error->data,
be32_to_cpu(hostrcb->hcam.length) -
(offsetof(struct ipr_hostrcb_error, u) +
@@ -1309,10 +1382,11 @@ static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg,
error = &hostrcb->hcam.u.error.u.type_07_error;
error->failure_reason[sizeof(error->failure_reason) - 1] = '\0';
+ strstrip(error->failure_reason);
- ipr_err("%s\n", error->failure_reason);
- ipr_err("Remote Adapter VPD:\n");
- ipr_log_vpd(&error->vpd);
+ ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason,
+ be32_to_cpu(hostrcb->hcam.u.error.prc));
+ ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd);
ipr_log_hex_data(ioa_cfg, error->data,
be32_to_cpu(hostrcb->hcam.length) -
(offsetof(struct ipr_hostrcb_error, u) +
@@ -1610,7 +1684,7 @@ static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
/* Set indication we have logged an error */
ioa_cfg->errors_logged++;
- if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
+ if (ioa_cfg->log_level < ipr_error_table[error_index].log_hcam)
return;
if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw))
hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw));
@@ -1669,12 +1743,15 @@ static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+ u32 fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
list_del(&hostrcb->queue);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
if (!ioasc) {
ipr_handle_log_data(ioa_cfg, hostrcb);
+ if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED)
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV);
} else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {
dev_err(&ioa_cfg->pdev->dev,
"Host RCB failed with IOASC: 0x%08X\n", ioasc);
@@ -2632,8 +2709,13 @@ static ssize_t ipr_store_diagnostics(struct class_device *class_dev,
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
- wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ }
+
ioa_cfg->errors_logged = 0;
ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
@@ -2955,6 +3037,11 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg,
unsigned long lock_flags;
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ }
if (ioa_cfg->ucode_sglist) {
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -3770,7 +3857,8 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
* Return value:
* 0 on success / non-zero on failure
**/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
+static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline)
{
struct ipr_sata_port *sata_port = ap->private_data;
struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
@@ -3849,6 +3937,8 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
if (ipr_cmd->scsi_cmd)
ipr_cmd->done = ipr_scsi_eh_done;
+ if (ipr_cmd->qc)
+ ipr_cmd->done = ipr_sata_eh_done;
if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) {
ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
@@ -4229,6 +4319,14 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
sglist = scsi_cmd->request_buffer;
+ if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
+ ioadl = ioarcb->add_data.u.ioadl;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+ offsetof(struct ipr_ioarcb, add_data));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+ }
+
for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
ioadl[i].flags_and_data_len =
cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
@@ -4259,6 +4357,11 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
scsi_cmd->sc_data_direction);
if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) {
+ ioadl = ioarcb->add_data.u.ioadl;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+ offsetof(struct ipr_ioarcb, add_data));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
ipr_cmd->dma_use_sg = 1;
ioadl[0].flags_and_data_len =
cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST);
@@ -4345,11 +4448,9 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
**/
static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
{
- struct ipr_ioarcb *ioarcb;
- struct ipr_ioasa *ioasa;
-
- ioarcb = &ipr_cmd->ioarcb;
- ioasa = &ipr_cmd->ioasa;
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+ struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+ dma_addr_t dma_addr = be32_to_cpu(ioarcb->ioarcb_host_pci_addr);
memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
ioarcb->write_data_transfer_length = 0;
@@ -4358,6 +4459,9 @@ static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
ioarcb->read_ioadl_len = 0;
ioasa->ioasc = 0;
ioasa->residual_data_len = 0;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
}
/**
@@ -4456,12 +4560,13 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
{
int i;
u16 data_len;
- u32 ioasc;
+ u32 ioasc, fd_ioasc;
struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
__be32 *ioasa_data = (__be32 *)ioasa;
int error_index;
ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK;
+ fd_ioasc = be32_to_cpu(ioasa->fd_ioasc) & IPR_IOASC_IOASC_MASK;
if (0 == ioasc)
return;
@@ -4469,13 +4574,19 @@ static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
return;
- error_index = ipr_get_error(ioasc);
+ if (ioasc == IPR_IOASC_BUS_WAS_RESET && fd_ioasc)
+ error_index = ipr_get_error(fd_ioasc);
+ else
+ error_index = ipr_get_error(ioasc);
if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) {
/* Don't log an error if the IOA already logged one */
if (ioasa->ilid != 0)
return;
+ if (!ipr_is_gscsi(res))
+ return;
+
if (ipr_error_table[error_index].log_ioasa == 0)
return;
}
@@ -4629,18 +4740,19 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+ u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK;
if (!res) {
ipr_scsi_eh_done(ipr_cmd);
return;
}
- if (ipr_is_gscsi(res))
- ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
- else
+ if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS)
ipr_gen_sense(ipr_cmd);
- switch (ioasc & IPR_IOASC_IOASC_MASK) {
+ ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
+
+ switch (masked_ioasc) {
case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
if (ipr_is_naca_model(res))
scsi_cmd->result |= (DID_ABORT << 16);
@@ -5120,7 +5232,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
struct ipr_ioarcb_ata_regs *regs;
if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
- return -EIO;
+ return AC_ERR_SYSTEM;
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
@@ -5165,7 +5277,7 @@ static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
default:
WARN_ON(1);
- return -1;
+ return AC_ERR_INVALID;
}
mb();
@@ -5336,6 +5448,7 @@ static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
}
+ scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS);
dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n");
ioa_cfg->reset_retries = 0;
@@ -5772,6 +5885,94 @@ static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd)
}
/**
+ * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA
+ * @ipr_cmd: ipr command struct
+ *
+ * This function enables dual IOA RAID support if possible.
+ *
+ * Return value:
+ * IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages;
+ struct ipr_mode_page24 *mode_page;
+ int length;
+
+ ENTER;
+ mode_page = ipr_get_mode_page(mode_pages, 0x24,
+ sizeof(struct ipr_mode_page24));
+
+ if (mode_page)
+ mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF;
+
+ length = mode_pages->hdr.length + 1;
+ mode_pages->hdr.length = 0;
+
+ ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11,
+ ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
+ length);
+
+ ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+ ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense
+ * @ipr_cmd: ipr command struct
+ *
+ * This function handles the failure of a Mode Sense to the IOAFP.
+ * Some adapters do not handle all mode pages.
+ *
+ * Return value:
+ * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd)
+{
+ u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+ if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) {
+ ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+ return IPR_RC_JOB_CONTINUE;
+ }
+
+ return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+/**
+ * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA
+ * @ipr_cmd: ipr command struct
+ *
+ * This function send a mode sense to the IOA to retrieve
+ * the IOA Advanced Function Control mode page.
+ *
+ * Return value:
+ * IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+ ENTER;
+ ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE),
+ 0x24, ioa_cfg->vpd_cbs_dma +
+ offsetof(struct ipr_misc_cbs, mode_pages),
+ sizeof(struct ipr_mode_pages));
+
+ ipr_cmd->job_step = ipr_ioafp_mode_select_page24;
+ ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed;
+
+ ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
+/**
* ipr_init_res_table - Initialize the resource table
* @ipr_cmd: ipr command struct
*
@@ -5839,7 +6040,10 @@ static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
}
}
- ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+ if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+ ipr_cmd->job_step = ipr_ioafp_mode_sense_page24;
+ else
+ ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
LEAVE;
return IPR_RC_JOB_CONTINUE;
@@ -5861,8 +6065,11 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+ struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
ENTER;
+ if (cap->cap & IPR_CAP_DUAL_IOA_RAID)
+ ioa_cfg->dual_raid = 1;
dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n",
ucode_vpd->major_release, ucode_vpd->card_type,
ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]);
@@ -5946,6 +6153,37 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page)
}
/**
+ * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter.
+ * @ipr_cmd: ipr command struct
+ *
+ * This function sends a Page 0xD0 inquiry to the adapter
+ * to retrieve adapter capabilities.
+ *
+ * Return value:
+ * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+ struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
+
+ ENTER;
+ ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+ memset(cap, 0, sizeof(*cap));
+
+ if (ipr_inquiry_page_supported(page0, 0xD0)) {
+ ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0,
+ ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap),
+ sizeof(struct ipr_inquiry_cap));
+ return IPR_RC_JOB_RETURN;
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_CONTINUE;
+}
+
+/**
* ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter.
* @ipr_cmd: ipr command struct
*
@@ -5965,7 +6203,7 @@ static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd)
if (!ipr_inquiry_page_supported(page0, 1))
ioa_cfg->cache_state = CACHE_NONE;
- ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+ ipr_cmd->job_step = ipr_ioafp_cap_inquiry;
ipr_ioafp_inquiry(ipr_cmd, 1, 3,
ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
@@ -6187,7 +6425,7 @@ static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");
ipr_cmd->timer.data = (unsigned long) ipr_cmd;
- ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ);
+ ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ);
ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
ipr_cmd->done = ipr_reset_ioa_job;
add_timer(&ipr_cmd->timer);
@@ -6251,6 +6489,7 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
struct ipr_hostrcb *hostrcb;
struct ipr_uc_sdt sdt;
int rc, length;
+ u32 ioasc;
mailbox = readl(ioa_cfg->ioa_mailbox);
@@ -6283,9 +6522,13 @@ static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
(__be32 *)&hostrcb->hcam,
min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
- if (!rc)
+ if (!rc) {
ipr_handle_log_data(ioa_cfg, hostrcb);
- else
+ ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+ if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED &&
+ ioa_cfg->sdt_state == GET_DUMP)
+ ioa_cfg->sdt_state = WAIT_FOR_DUMP;
+ } else
ipr_unit_check_no_data(ioa_cfg);
list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
@@ -6384,6 +6627,7 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
if (rc != PCIBIOS_SUCCESSFUL) {
+ pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev);
ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
rc = IPR_RC_JOB_CONTINUE;
} else {
@@ -6397,6 +6641,48 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
}
/**
+ * ipr_reset_slot_reset_done - Clear PCI reset to the adapter
+ * @ipr_cmd: ipr command struct
+ *
+ * Description: This clears PCI reset to the adapter and delays two seconds.
+ *
+ * Return value:
+ * IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd)
+{
+ ENTER;
+ pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset);
+ ipr_cmd->job_step = ipr_reset_bist_done;
+ ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_slot_reset - Reset the PCI slot of the adapter.
+ * @ipr_cmd: ipr command struct
+ *
+ * Description: This asserts PCI reset to the adapter.
+ *
+ * Return value:
+ * IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct pci_dev *pdev = ioa_cfg->pdev;
+
+ ENTER;
+ pci_block_user_cfg_access(pdev);
+ pci_set_pcie_reset_state(pdev, pcie_warm_reset);
+ ipr_cmd->job_step = ipr_reset_slot_reset_done;
+ ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
+/**
* ipr_reset_allowed - Query whether or not IOA can be reset
* @ioa_cfg: ioa config struct
*
@@ -6435,7 +6721,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
} else {
- ipr_cmd->job_step = ipr_reset_start_bist;
+ ipr_cmd->job_step = ioa_cfg->reset;
rc = IPR_RC_JOB_CONTINUE;
}
@@ -6468,7 +6754,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
} else {
- ipr_cmd->job_step = ipr_reset_start_bist;
+ ipr_cmd->job_step = ioa_cfg->reset;
}
ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
@@ -6563,12 +6849,14 @@ static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd)
ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type;
- if (shutdown_type == IPR_SHUTDOWN_ABBREV)
- timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
+ if (shutdown_type == IPR_SHUTDOWN_NORMAL)
+ timeout = IPR_SHUTDOWN_TIMEOUT;
else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL)
timeout = IPR_INTERNAL_TIMEOUT;
+ else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid)
+ timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO;
else
- timeout = IPR_SHUTDOWN_TIMEOUT;
+ timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout);
@@ -6748,8 +7036,11 @@ static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev)
struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
- _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
- IPR_SHUTDOWN_NONE);
+ if (ioa_cfg->needs_warm_reset)
+ ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+ else
+ _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space,
+ IPR_SHUTDOWN_NONE);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
return PCI_ERS_RESULT_RECOVERED;
}
@@ -7116,8 +7407,6 @@ static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
ioa_cfg->pdev = pdev;
ioa_cfg->log_level = ipr_log_level;
ioa_cfg->doorbell = IPR_DOORBELL;
- if (!ipr_auto_create)
- ioa_cfg->doorbell |= IPR_RUNTIME_RESET;
sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER);
sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL);
sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL);
@@ -7200,7 +7489,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
unsigned long ipr_regs_pci;
void __iomem *ipr_regs;
int rc = PCIBIOS_SUCCESSFUL;
- volatile u32 mask, uproc;
+ volatile u32 mask, uproc, interrupts;
ENTER;
@@ -7232,6 +7521,21 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
goto out_scsi_host_put;
}
+ if (ipr_transop_timeout)
+ ioa_cfg->transop_timeout = ipr_transop_timeout;
+ else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT)
+ ioa_cfg->transop_timeout = IPR_LONG_OPERATIONAL_TIMEOUT;
+ else
+ ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+
+ rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &ioa_cfg->revid);
+
+ if (rc != PCIBIOS_SUCCESSFUL) {
+ dev_err(&pdev->dev, "Failed to read PCI revision ID\n");
+ rc = -EIO;
+ goto out_scsi_host_put;
+ }
+
ipr_regs_pci = pci_resource_start(pdev, 0);
rc = pci_request_regions(pdev, IPR_NAME);
@@ -7300,9 +7604,14 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
* the card is in an unknown state and needs a hard reset
*/
mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+ interrupts = readl(ioa_cfg->regs.sense_interrupt_reg);
uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT))
ioa_cfg->needs_hard_reset = 1;
+ if (interrupts & IPR_PCII_ERROR_INTERRUPTS)
+ ioa_cfg->needs_hard_reset = 1;
+ if (interrupts & IPR_PCII_IOA_UNIT_CHECKED)
+ ioa_cfg->ioa_unit_checked = 1;
ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
@@ -7313,6 +7622,13 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
goto cleanup_nolog;
}
+ if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) ||
+ (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) {
+ ioa_cfg->needs_warm_reset = 1;
+ ioa_cfg->reset = ipr_reset_slot_reset;
+ } else
+ ioa_cfg->reset = ipr_reset_start_bist;
+
spin_lock(&ipr_driver_lock);
list_add_tail(&ioa_cfg->queue, &ipr_ioa_head);
spin_unlock(&ipr_driver_lock);
@@ -7395,6 +7711,12 @@ static void __ipr_remove(struct pci_dev *pdev)
ENTER;
spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+ }
+
ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
@@ -7518,6 +7840,12 @@ static void ipr_shutdown(struct pci_dev *pdev)
unsigned long lock_flags = 0;
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ }
+
ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
@@ -7539,29 +7867,48 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT},
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575D, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
- PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, 0 },
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
+ { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SCAMP_E,
+ PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0,
+ IPR_USE_LONG_TRANSOP_TIMEOUT },
{ }
};
MODULE_DEVICE_TABLE(pci, ipr_pci_table);
@@ -7578,6 +7925,7 @@ static struct pci_driver ipr_driver = {
.remove = ipr_remove,
.shutdown = ipr_shutdown,
.err_handler = &ipr_err_handler,
+ .dynids.use_driver_data = 1
};
/**
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 88f285de97b..d93156671e9 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -37,8 +37,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.3.1"
-#define IPR_DRIVER_DATE "(January 23, 2007)"
+#define IPR_DRIVER_VERSION "2.4.1"
+#define IPR_DRIVER_DATE "(April 24, 2007)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -55,6 +55,7 @@
#define IPR_NUM_BASE_CMD_BLKS 100
#define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339
+#define PCI_DEVICE_ID_IBM_SCAMP_E 0x034A
#define IPR_SUBS_DEV_ID_2780 0x0264
#define IPR_SUBS_DEV_ID_5702 0x0266
@@ -69,8 +70,12 @@
#define IPR_SUBS_DEV_ID_572A 0x02C1
#define IPR_SUBS_DEV_ID_572B 0x02C2
#define IPR_SUBS_DEV_ID_572F 0x02C3
+#define IPR_SUBS_DEV_ID_574D 0x030B
+#define IPR_SUBS_DEV_ID_574E 0x030A
#define IPR_SUBS_DEV_ID_575B 0x030D
#define IPR_SUBS_DEV_ID_575C 0x0338
+#define IPR_SUBS_DEV_ID_575D 0x033E
+#define IPR_SUBS_DEV_ID_57B3 0x033A
#define IPR_SUBS_DEV_ID_57B7 0x0360
#define IPR_SUBS_DEV_ID_57B8 0x02C2
@@ -86,6 +91,7 @@
* IOASCs
*/
#define IPR_IOASC_NR_INIT_CMD_REQUIRED 0x02040200
+#define IPR_IOASC_NR_IOA_RESET_REQUIRED 0x02048000
#define IPR_IOASC_SYNC_REQUIRED 0x023f0000
#define IPR_IOASC_MED_DO_NOT_REALLOC 0x03110C00
#define IPR_IOASC_HW_SEL_TIMEOUT 0x04050000
@@ -104,6 +110,10 @@
#define IPR_IOASC_IOA_WAS_RESET 0x10000001
#define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002
+/* Driver data flags */
+#define IPR_USE_LONG_TRANSOP_TIMEOUT 0x00000001
+#define IPR_USE_PCI_WARM_RESET 0x00000002
+
#define IPR_DEFAULT_MAX_ERROR_DUMP 984
#define IPR_NUM_LOG_HCAMS 2
#define IPR_NUM_CFG_CHG_HCAMS 2
@@ -171,6 +181,7 @@
#define IPR_SHUTDOWN_TIMEOUT (ipr_fastfail ? 60 * HZ : 10 * 60 * HZ)
#define IPR_VSET_RW_TIMEOUT (ipr_fastfail ? 30 * HZ : 2 * 60 * HZ)
#define IPR_ABBREV_SHUTDOWN_TIMEOUT (10 * HZ)
+#define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO (2 * 60 * HZ)
#define IPR_DEVICE_RESET_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ)
#define IPR_CANCEL_ALL_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ)
#define IPR_ABORT_TASK_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ)
@@ -179,9 +190,11 @@
#define IPR_SET_SUP_DEVICE_TIMEOUT (2 * 60 * HZ)
#define IPR_REQUEST_SENSE_TIMEOUT (10 * HZ)
#define IPR_OPERATIONAL_TIMEOUT (5 * 60)
+#define IPR_LONG_OPERATIONAL_TIMEOUT (12 * 60)
#define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ)
#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10)
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
+#define IPR_PCI_RESET_TIMEOUT (HZ / 2)
#define IPR_DUMP_TIMEOUT (15 * HZ)
/*
@@ -413,9 +426,25 @@ struct ipr_ioarcb_ata_regs {
u8 ctl;
}__attribute__ ((packed, aligned(4)));
+struct ipr_ioadl_desc {
+ __be32 flags_and_data_len;
+#define IPR_IOADL_FLAGS_MASK 0xff000000
+#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
+#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff
+#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
+#define IPR_IOADL_FLAGS_READ 0x48000000
+#define IPR_IOADL_FLAGS_READ_LAST 0x49000000
+#define IPR_IOADL_FLAGS_WRITE 0x68000000
+#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000
+#define IPR_IOADL_FLAGS_LAST 0x01000000
+
+ __be32 address;
+}__attribute__((packed, aligned (8)));
+
struct ipr_ioarcb_add_data {
union {
struct ipr_ioarcb_ata_regs regs;
+ struct ipr_ioadl_desc ioadl[5];
__be32 add_cmd_parms[10];
}u;
}__attribute__ ((packed, aligned(4)));
@@ -447,21 +476,6 @@ struct ipr_ioarcb {
struct ipr_ioarcb_add_data add_data;
}__attribute__((packed, aligned (4)));
-struct ipr_ioadl_desc {
- __be32 flags_and_data_len;
-#define IPR_IOADL_FLAGS_MASK 0xff000000
-#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
-#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff
-#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
-#define IPR_IOADL_FLAGS_READ 0x48000000
-#define IPR_IOADL_FLAGS_READ_LAST 0x49000000
-#define IPR_IOADL_FLAGS_WRITE 0x68000000
-#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000
-#define IPR_IOADL_FLAGS_LAST 0x01000000
-
- __be32 address;
-}__attribute__((packed, aligned (8)));
-
struct ipr_ioasa_vset {
__be32 failing_lba_hi;
__be32 failing_lba_lo;
@@ -592,6 +606,12 @@ struct ipr_mode_page28 {
struct ipr_dev_bus_entry bus[0];
}__attribute__((packed));
+struct ipr_mode_page24 {
+ struct ipr_mode_page_hdr hdr;
+ u8 flags;
+#define IPR_ENABLE_DUAL_IOA_AF 0x80
+}__attribute__((packed));
+
struct ipr_ioa_vpd {
struct ipr_std_inq_data std_inq_data;
u8 ascii_part_num[12];
@@ -614,6 +634,19 @@ struct ipr_inquiry_page3 {
u8 patch_number[4];
}__attribute__((packed));
+struct ipr_inquiry_cap {
+ u8 peri_qual_dev_type;
+ u8 page_code;
+ u8 reserved1;
+ u8 page_length;
+ u8 ascii_len;
+ u8 reserved2;
+ u8 sis_version[2];
+ u8 cap;
+#define IPR_CAP_DUAL_IOA_RAID 0x80
+ u8 reserved3[15];
+}__attribute__((packed));
+
#define IPR_INQUIRY_PAGE0_ENTRIES 20
struct ipr_inquiry_page0 {
u8 peri_qual_dev_type;
@@ -952,6 +985,7 @@ struct ipr_misc_cbs {
struct ipr_ioa_vpd ioa_vpd;
struct ipr_inquiry_page0 page0_data;
struct ipr_inquiry_page3 page3_data;
+ struct ipr_inquiry_cap cap;
struct ipr_mode_pages mode_pages;
struct ipr_supported_device supp_dev;
};
@@ -1058,6 +1092,10 @@ struct ipr_ioa_cfg {
u8 allow_cmds:1;
u8 allow_ml_add_del:1;
u8 needs_hard_reset:1;
+ u8 dual_raid:1;
+ u8 needs_warm_reset:1;
+
+ u8 revid;
enum ipr_cache_state cache_state;
u16 type; /* CCIN of the card */
@@ -1119,6 +1157,7 @@ struct ipr_ioa_cfg {
struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
+ unsigned int transop_timeout;
const struct ipr_chip_cfg_t *chip_cfg;
void __iomem *hdw_dma_regs; /* iomapped PCI memory space */
@@ -1150,6 +1189,7 @@ struct ipr_ioa_cfg {
struct pci_pool *ipr_cmd_pool;
struct ipr_cmnd *reset_cmd;
+ int (*reset) (struct ipr_cmnd *);
struct ata_host ata_host;
char ipr_cmd_label[8];
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 8f55e143143..c9a3abf9e7b 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -527,12 +527,12 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
* than 8K, but there are no targets that currently do this.
* For now we fail until we find a vendor that needs it
*/
- if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH <
+ if (ISCSI_DEF_MAX_RECV_SEG_LEN <
tcp_conn->in.datalen) {
printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
"but conn buffer is only %u (opcode %0x)\n",
tcp_conn->in.datalen,
- DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode);
+ ISCSI_DEF_MAX_RECV_SEG_LEN, opcode);
rc = ISCSI_ERR_PROTO;
break;
}
@@ -1762,7 +1762,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
* due to strange issues with iser these are not set
* in iscsi_conn_setup
*/
- conn->max_recv_dlength = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+ conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN;
tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL);
if (!tcp_conn)
@@ -1777,14 +1777,24 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->tx_hash.flags = 0;
- if (IS_ERR(tcp_conn->tx_hash.tfm))
+ if (IS_ERR(tcp_conn->tx_hash.tfm)) {
+ printk(KERN_ERR "Could not create connection due to crc32c "
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->tx_hash.tfm));
goto free_tcp_conn;
+ }
tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
CRYPTO_ALG_ASYNC);
tcp_conn->rx_hash.flags = 0;
- if (IS_ERR(tcp_conn->rx_hash.tfm))
+ if (IS_ERR(tcp_conn->rx_hash.tfm)) {
+ printk(KERN_ERR "Could not create connection due to crc32c "
+ "loading error %ld. Make sure the crc32c module is "
+ "built as a module or into the kernel\n",
+ PTR_ERR(tcp_conn->rx_hash.tfm));
goto free_tx_tfm;
+ }
return cls_conn;
@@ -2138,6 +2148,7 @@ static struct scsi_host_template iscsi_sht = {
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_SG_TABLESIZE,
+ .max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
.eh_host_reset_handler = iscsi_eh_host_reset,
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 7c75771c77f..3f5b9b445b2 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -25,6 +25,7 @@
#include <linux/mutex.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
+#include <asm/unaligned.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -269,14 +270,14 @@ invalid_datalen:
goto out;
}
- senselen = be16_to_cpu(*(__be16 *)data);
+ senselen = be16_to_cpu(get_unaligned((__be16 *) data));
if (datalen < senselen)
goto invalid_datalen;
memcpy(sc->sense_buffer, data + 2,
min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
debug_scsi("copied %d bytes of sense\n",
- min(senselen, SCSI_SENSE_BUFFERSIZE));
+ min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
}
if (sc->sc_data_direction == DMA_TO_DEVICE)
@@ -577,7 +578,7 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
}
EXPORT_SYMBOL_GPL(iscsi_conn_failure);
-static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
+static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{
struct iscsi_hdr *hdr = conn->mtask->hdr;
int rc, was_logout = 0;
@@ -591,6 +592,9 @@ static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
if (rc)
return rc;
+ /* done with this in-progress mtask */
+ conn->mtask = NULL;
+
if (was_logout) {
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
return -ENODATA;
@@ -643,11 +647,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
conn->ctask = NULL;
}
if (conn->mtask) {
- rc = iscsi_xmit_imm_task(conn);
+ rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
- /* done with this in-progress mtask */
- conn->mtask = NULL;
}
/* process immediate first */
@@ -658,12 +660,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
- rc = iscsi_xmit_imm_task(conn);
+ rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
}
- /* done with this mtask */
- conn->mtask = NULL;
}
/* process command queue */
@@ -701,12 +701,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
list_add_tail(&conn->mtask->running,
&conn->mgmt_run_list);
spin_unlock_bh(&conn->session->lock);
- rc = tt->xmit_mgmt_task(conn, conn->mtask);
- if (rc)
+ rc = iscsi_xmit_mtask(conn);
+ if (rc)
goto again;
}
- /* done with this mtask */
- conn->mtask = NULL;
}
return -ENODATA;
@@ -1523,7 +1521,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
}
spin_unlock_bh(&session->lock);
- data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
+ data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
if (!data)
goto login_mtask_data_alloc_fail;
conn->login_mtask->data = conn->data = data;
@@ -1597,6 +1595,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
wake_up(&conn->ehwait);
}
+ /* flush queued up work because we free the connection below */
+ scsi_flush_work(session->host);
+
spin_lock_bh(&session->lock);
kfree(conn->data);
kfree(conn->persistent_address);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index dc70c180e11..e34442e405e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/pci.h>
#include <linux/scatterlist.h>
#include "sas_internal.h"
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 897a5e2c55e..b4b52694497 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -23,6 +23,8 @@
*
*/
+#include <linux/kthread.h>
+
#include "sas_internal.h"
#include <scsi/scsi_host.h>
@@ -184,7 +186,7 @@ static int sas_queue_up(struct sas_task *task)
list_add_tail(&task->list, &core->task_queue);
core->task_queue_size += 1;
spin_unlock_irqrestore(&core->task_queue_lock, flags);
- up(&core->queue_thread_sema);
+ wake_up_process(core->queue_thread);
return 0;
}
@@ -819,7 +821,7 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
struct sas_internal *i = to_sas_internal(core->shost->transportt);
spin_lock_irqsave(&core->task_queue_lock, flags);
- while (!core->queue_thread_kill &&
+ while (!kthread_should_stop() &&
!list_empty(&core->task_queue)) {
can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
@@ -858,8 +860,6 @@ static void sas_queue(struct sas_ha_struct *sas_ha)
spin_unlock_irqrestore(&core->task_queue_lock, flags);
}
-static DECLARE_COMPLETION(queue_th_comp);
-
/**
* sas_queue_thread -- The Task Collector thread
* @_sas_ha: pointer to struct sas_ha
@@ -867,40 +867,33 @@ static DECLARE_COMPLETION(queue_th_comp);
static int sas_queue_thread(void *_sas_ha)
{
struct sas_ha_struct *sas_ha = _sas_ha;
- struct scsi_core *core = &sas_ha->core;
- daemonize("sas_queue_%d", core->shost->host_no);
current->flags |= PF_NOFREEZE;
- complete(&queue_th_comp);
-
while (1) {
- down_interruptible(&core->queue_thread_sema);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
sas_queue(sas_ha);
- if (core->queue_thread_kill)
+ if (kthread_should_stop())
break;
}
- complete(&queue_th_comp);
-
return 0;
}
int sas_init_queue(struct sas_ha_struct *sas_ha)
{
- int res;
struct scsi_core *core = &sas_ha->core;
spin_lock_init(&core->task_queue_lock);
core->task_queue_size = 0;
INIT_LIST_HEAD(&core->task_queue);
- init_MUTEX_LOCKED(&core->queue_thread_sema);
- res = kernel_thread(sas_queue_thread, sas_ha, 0);
- if (res >= 0)
- wait_for_completion(&queue_th_comp);
-
- return res < 0 ? res : 0;
+ core->queue_thread = kthread_run(sas_queue_thread, sas_ha,
+ "sas_queue_%d", core->shost->host_no);
+ if (IS_ERR(core->queue_thread))
+ return PTR_ERR(core->queue_thread);
+ return 0;
}
void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
@@ -909,10 +902,7 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
struct scsi_core *core = &sas_ha->core;
struct sas_task *task, *n;
- init_completion(&queue_th_comp);
- core->queue_thread_kill = 1;
- up(&core->queue_thread_sema);
- wait_for_completion(&queue_th_comp);
+ kthread_stop(core->queue_thread);
if (!list_empty(&core->task_queue))
SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c
index 89403b00e04..5631c199a8e 100644
--- a/drivers/scsi/libsrp.c
+++ b/drivers/scsi/libsrp.c
@@ -22,7 +22,6 @@
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
#include <linux/dma-mapping.h>
-#include <linux/pci.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_tcq.h>
@@ -225,8 +224,7 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
struct srp_direct_buf *md = NULL;
struct scatterlist dummy, *sg = NULL;
dma_addr_t token = 0;
- long err;
- unsigned int done = 0;
+ int err = 0;
int nmd, nsg = 0, len;
if (dma_map || ext_desc) {
@@ -258,8 +256,8 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
sg_dma_address(&dummy) = token;
err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE,
id->table_desc.len);
- if (err < 0) {
- eprintk("Error copying indirect table %ld\n", err);
+ if (err) {
+ eprintk("Error copying indirect table %d\n", err);
goto free_mem;
}
} else {
@@ -272,6 +270,7 @@ rdma:
nsg = dma_map_sg(iue->target->dev, sg, sc->use_sg, DMA_BIDIRECTIONAL);
if (!nsg) {
eprintk("fail to map %p %d\n", iue, sc->use_sg);
+ err = -EIO;
goto free_mem;
}
len = min(sc->request_bufflen, id->len);
@@ -287,7 +286,7 @@ free_mem:
if (token && dma_map)
dma_free_coherent(iue->target->dev, id->table_desc.len, md, token);
- return done;
+ return err;
}
static int data_out_desc_size(struct srp_cmd *cmd)
@@ -352,7 +351,7 @@ int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd,
break;
default:
eprintk("Unknown format %d %x\n", dir, format);
- break;
+ err = -EINVAL;
}
return err;
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index a7de0bca5bd..82e8f90c461 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -27,10 +27,6 @@ struct lpfc_sli2_slim;
requests */
#define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact
the NameServer before giving up. */
-#define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */
-#define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */
-#define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */
-
#define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */
#define LPFC_SG_SEG_CNT 64 /* sg element count per scsi cmnd */
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
@@ -244,28 +240,23 @@ struct lpfc_hba {
#define FC_FABRIC 0x100 /* We are fabric attached */
#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */
#define FC_RSCN_DISCOVERY 0x400 /* Authenticate all devices after RSCN*/
+#define FC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */
#define FC_LOADING 0x1000 /* HBA in process of loading drvr */
#define FC_UNLOADING 0x2000 /* HBA in process of unloading drvr */
#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
+#define FC_LOOPBACK_MODE 0x40000 /* NPort is in Loopback mode */
+ /* This flag is set while issuing */
+ /* INIT_LINK mailbox command */
+#define FC_IGNORE_ERATT 0x80000 /* intr handler should ignore ERATT */
uint32_t fc_topology; /* link topology, from LINK INIT */
struct lpfc_stats fc_stat;
- /* These are the head/tail pointers for the bind, plogi, adisc, unmap,
- * and map lists. Their counters are immediately following.
- */
- struct list_head fc_plogi_list;
- struct list_head fc_adisc_list;
- struct list_head fc_reglogin_list;
- struct list_head fc_prli_list;
- struct list_head fc_nlpunmap_list;
- struct list_head fc_nlpmap_list;
- struct list_head fc_npr_list;
- struct list_head fc_unused_list;
+ struct list_head fc_nodes;
/* Keep counters for the number of entries in each list. */
uint16_t fc_plogi_cnt;
@@ -387,13 +378,17 @@ struct lpfc_hba {
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
- struct list_head freebufList;
- struct list_head ctrspbuflist;
- struct list_head rnidrspbuflist;
struct fc_host_statistics link_stats;
};
+static inline void
+lpfc_set_loopback_flag(struct lpfc_hba *phba) {
+ if (phba->cfg_topology == FLAGS_LOCAL_LB)
+ phba->fc_flag |= FC_LOOPBACK_MODE;
+ else
+ phba->fc_flag &= ~FC_LOOPBACK_MODE;
+}
struct rnidrsp {
void *buf;
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index f247e786af9..95fe77e816f 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -20,6 +20,7 @@
*******************************************************************/
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -213,6 +214,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
int mbxstatus = MBXERR_ERROR;
if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
(phba->hba_state != LPFC_HBA_READY))
return -EPERM;
@@ -235,6 +237,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
phba->fc_ratov * 2);
}
+ lpfc_set_loopback_flag(phba);
if (mbxstatus == MBX_TIMEOUT)
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
else
@@ -247,19 +250,62 @@ lpfc_issue_lip(struct Scsi_Host *host)
}
static int
-lpfc_selective_reset(struct lpfc_hba *phba)
+lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
{
struct completion online_compl;
+ struct lpfc_sli_ring *pring;
+ struct lpfc_sli *psli;
int status = 0;
+ int cnt = 0;
+ int i;
init_completion(&online_compl);
lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_OFFLINE);
+ LPFC_EVT_OFFLINE_PREP);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ psli = &phba->sli;
+
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ /* The linkdown event takes 30 seconds to timeout. */
+ while (pring->txcmplq_cnt) {
+ msleep(10);
+ if (cnt++ > 3000) {
+ lpfc_printf_log(phba,
+ KERN_WARNING, LOG_INIT,
+ "%d:0466 Outstanding IO when "
+ "bringing Adapter offline\n",
+ phba->brd_no);
+ break;
+ }
+ }
+ }
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl, type);
wait_for_completion(&online_compl);
if (status != 0)
return -EIO;
+ return 0;
+}
+
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
+{
+ struct completion online_compl;
+ int status = 0;
+
+ status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
+
+ if (status != 0)
+ return status;
+
init_completion(&online_compl);
lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_ONLINE);
@@ -324,23 +370,19 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
init_completion(&online_compl);
- if(strncmp(buf, "online", sizeof("online") - 1) == 0)
+ if(strncmp(buf, "online", sizeof("online") - 1) == 0) {
lpfc_workq_post_event(phba, &status, &online_compl,
LPFC_EVT_ONLINE);
- else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+ } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
+ status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_WARM_START);
- else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_KILL);
+ status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
+ else if (strncmp(buf, "error", sizeof("error") - 1) == 0)
+ status = lpfc_do_offline(phba, LPFC_EVT_KILL);
else
return -EINVAL;
- wait_for_completion(&online_compl);
-
if (!status)
return strlen(buf);
else
@@ -645,9 +687,7 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
dev_printk(KERN_NOTICE, &phba->pcidev->dev,
"lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
- init_completion(&online_compl);
- lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
- wait_for_completion(&online_compl);
+ stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
if (stat1)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
@@ -789,6 +829,18 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
return -EINVAL;
}
+static void
+lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+{
+ struct lpfc_nodelist *ndlp;
+
+ spin_lock_irq(phba->host->host_lock);
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp)
+ if (ndlp->rport)
+ ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+ spin_unlock_irq(phba->host->host_lock);
+}
+
static int
lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
{
@@ -804,6 +856,7 @@ lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
phba->cfg_nodev_tmo = val;
phba->cfg_devloss_tmo = val;
+ lpfc_update_rport_devloss_tmo(phba);
return 0;
}
@@ -839,6 +892,7 @@ lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
phba->cfg_nodev_tmo = val;
phba->cfg_devloss_tmo = val;
phba->dev_loss_tmo_changed = 1;
+ lpfc_update_rport_devloss_tmo(phba);
return 0;
}
@@ -931,9 +985,10 @@ LPFC_ATTR_RW(topology, 0, 0, 6, "Select Fibre Channel topology");
# 1 = 1 Gigabaud
# 2 = 2 Gigabaud
# 4 = 4 Gigabaud
-# Value range is [0,4]. Default value is 0.
+# 8 = 8 Gigabaud
+# Value range is [0,8]. Default value is 0.
*/
-LPFC_ATTR_R(link_speed, 0, 0, 4, "Select link speed");
+LPFC_ATTR_R(link_speed, 0, 0, 8, "Select link speed");
/*
# lpfc_fcp_class: Determines FC class to use for the FCP protocol.
@@ -958,7 +1013,7 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
/*
# lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing
# cr_delay (msec) or cr_count outstanding commands. cr_delay can take
-# value [0,63]. cr_count can take value [0,255]. Default value of cr_delay
+# value [0,63]. cr_count can take value [1,255]. Default value of cr_delay
# is 0. Default value of cr_count is 1. The cr_count feature is disabled if
# cr_delay is set to 0.
*/
@@ -1227,11 +1282,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
int rc;
- if (off > sizeof(MAILBOX_t))
+ if (off > MAILBOX_CMD_SIZE)
return -ERANGE;
- if ((count + off) > sizeof(MAILBOX_t))
- count = sizeof(MAILBOX_t) - off;
+ if ((count + off) > MAILBOX_CMD_SIZE)
+ count = MAILBOX_CMD_SIZE - off;
if (off % 4 || count % 4 || (unsigned long)buf % 4)
return -EINVAL;
@@ -1307,6 +1362,12 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
return -EPERM;
}
+ if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
+ sysfs_mbox_idle(phba);
+ spin_unlock_irq(host->host_lock);
+ return -EAGAIN;
+ }
+
if ((phba->fc_flag & FC_OFFLINE_MODE) ||
(!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
@@ -1326,6 +1387,11 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
}
if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT) {
+ phba->sysfs_mbox.mbox->mbox_cmpl =
+ lpfc_sli_def_mbox_cmpl;
+ phba->sysfs_mbox.mbox = NULL;
+ }
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
@@ -1344,7 +1410,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
phba->sysfs_mbox.offset = off + count;
- if (phba->sysfs_mbox.offset == sizeof(MAILBOX_t))
+ if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE)
sysfs_mbox_idle(phba);
spin_unlock_irq(phba->host->host_lock);
@@ -1358,7 +1424,7 @@ static struct bin_attribute sysfs_mbox_attr = {
.mode = S_IRUSR | S_IWUSR,
.owner = THIS_MODULE,
},
- .size = sizeof(MAILBOX_t),
+ .size = MAILBOX_CMD_SIZE,
.read = sysfs_mbox_read,
.write = sysfs_mbox_write,
};
@@ -1494,6 +1560,9 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
case LA_4GHZ_LINK:
fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
break;
+ case LA_8GHZ_LINK:
+ fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+ break;
default:
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
break;
@@ -1546,6 +1615,9 @@ lpfc_get_stats(struct Scsi_Host *shost)
unsigned long seconds;
int rc = 0;
+ if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+ return NULL;
+
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmboxq)
return NULL;
@@ -1631,6 +1703,8 @@ lpfc_get_stats(struct Scsi_Host *shost)
else
hs->seconds_since_last_reset = seconds - psli->stats_start;
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+
return hs;
}
@@ -1644,6 +1718,9 @@ lpfc_reset_stats(struct Scsi_Host *shost)
MAILBOX_t *pmb;
int rc = 0;
+ if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+ return;
+
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmboxq)
return;
@@ -1699,6 +1776,8 @@ lpfc_reset_stats(struct Scsi_Host *shost)
psli->stats_start = get_seconds();
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+
return;
}
@@ -1706,67 +1785,51 @@ lpfc_reset_stats(struct Scsi_Host *shost)
* The LPFC driver treats linkdown handling as target loss events so there
* are no sysfs handlers for link_down_tmo.
*/
-static void
-lpfc_get_starget_port_id(struct scsi_target *starget)
+
+static struct lpfc_nodelist *
+lpfc_get_node_by_target(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
- uint32_t did = -1;
- struct lpfc_nodelist *ndlp = NULL;
+ struct lpfc_nodelist *ndlp;
spin_lock_irq(shost->host_lock);
- /* Search the mapped list for this target ID */
- list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
- if (starget->id == ndlp->nlp_sid) {
- did = ndlp->nlp_DID;
- break;
+ /* Search for this, mapped, target ID */
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+ starget->id == ndlp->nlp_sid) {
+ spin_unlock_irq(shost->host_lock);
+ return ndlp;
}
}
spin_unlock_irq(shost->host_lock);
+ return NULL;
+}
+
+static void
+lpfc_get_starget_port_id(struct scsi_target *starget)
+{
+ struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
- fc_starget_port_id(starget) = did;
+ fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1;
}
static void
lpfc_get_starget_node_name(struct scsi_target *starget)
{
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
- u64 node_name = 0;
- struct lpfc_nodelist *ndlp = NULL;
-
- spin_lock_irq(shost->host_lock);
- /* Search the mapped list for this target ID */
- list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
- if (starget->id == ndlp->nlp_sid) {
- node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
- break;
- }
- }
- spin_unlock_irq(shost->host_lock);
+ struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
- fc_starget_node_name(starget) = node_name;
+ fc_starget_node_name(starget) =
+ ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0;
}
static void
lpfc_get_starget_port_name(struct scsi_target *starget)
{
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
- u64 port_name = 0;
- struct lpfc_nodelist *ndlp = NULL;
-
- spin_lock_irq(shost->host_lock);
- /* Search the mapped list for this target ID */
- list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
- if (starget->id == ndlp->nlp_sid) {
- port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
- break;
- }
- }
- spin_unlock_irq(shost->host_lock);
+ struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget);
- fc_starget_port_name(starget) = port_name;
+ fc_starget_port_name(starget) =
+ ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0;
}
static void
@@ -1895,25 +1958,8 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
sizeof(struct fcp_rsp) +
(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
- switch (phba->pcidev->device) {
- case PCI_DEVICE_ID_LP101:
- case PCI_DEVICE_ID_BSMB:
- case PCI_DEVICE_ID_ZSMB:
- phba->cfg_hba_queue_depth = LPFC_LP101_HBA_Q_DEPTH;
- break;
- case PCI_DEVICE_ID_RFLY:
- case PCI_DEVICE_ID_PFLY:
- case PCI_DEVICE_ID_BMID:
- case PCI_DEVICE_ID_ZMID:
- case PCI_DEVICE_ID_TFLY:
- phba->cfg_hba_queue_depth = LPFC_LC_HBA_Q_DEPTH;
- break;
- default:
- phba->cfg_hba_queue_depth = LPFC_DFT_HBA_Q_DEPTH;
- }
- if (phba->cfg_hba_queue_depth > lpfc_hba_queue_depth)
- lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+ lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
return;
}
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 1251788ce2a..b8c2a8862d8 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -18,6 +18,8 @@
* included with this package. *
*******************************************************************/
+typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
+
struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -43,20 +45,24 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int);
+void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_set_disctmo(struct lpfc_hba *);
int lpfc_can_disctmo(struct lpfc_hba *);
int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *, struct lpfc_nodelist *);
-int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
+int lpfc_nlp_put(struct lpfc_nodelist *);
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
void lpfc_disc_list_loopmap(struct lpfc_hba *);
void lpfc_disc_start(struct lpfc_hba *);
void lpfc_disc_flush_list(struct lpfc_hba *);
void lpfc_disc_timeout(unsigned long);
+struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
@@ -66,8 +72,7 @@ int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t);
-int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
- int);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp);
int lpfc_els_abort_flogi(struct lpfc_hba *);
int lpfc_initial_flogi(struct lpfc_hba *);
int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
@@ -113,7 +118,10 @@ void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
int lpfc_online(struct lpfc_hba *);
-int lpfc_offline(struct lpfc_hba *);
+void lpfc_block_mgmt_io(struct lpfc_hba *);
+void lpfc_unblock_mgmt_io(struct lpfc_hba *);
+void lpfc_offline_prep(struct lpfc_hba *);
+void lpfc_offline(struct lpfc_hba *);
int lpfc_sli_setup(struct lpfc_hba *);
int lpfc_sli_queue_setup(struct lpfc_hba *);
@@ -162,8 +170,8 @@ int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
struct lpfc_sli_ring *,
dma_addr_t);
-int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
- struct lpfc_iocbq *);
+int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
+ struct lpfc_iocbq *);
int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
uint64_t, lpfc_ctx_cmd);
int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
@@ -172,9 +180,8 @@ int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
void lpfc_mbox_timeout(unsigned long);
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t,
- struct lpfc_name *);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
uint32_t timeout);
@@ -193,6 +200,9 @@ void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
/* Function prototypes. */
const char* lpfc_info(struct Scsi_Host *);
+void lpfc_scan_start(struct Scsi_Host *);
+int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
+
void lpfc_get_cfgparam(struct lpfc_hba *);
int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
void lpfc_free_sysfs_attr(struct lpfc_hba *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index a51a41b7f15..34a9e3bb261 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -334,21 +334,22 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
lpfc_set_disctmo(phba);
- Cnt = Size > FCELSSIZE ? FCELSSIZE : Size;
list_add_tail(&head, &mp->list);
list_for_each_entry_safe(mp, next_mp, &head, list) {
mlast = mp;
+ Cnt = Size > FCELSSIZE ? FCELSSIZE : Size;
+
Size -= Cnt;
- if (!ctptr)
+ if (!ctptr) {
ctptr = (uint32_t *) mlast->virt;
- else
+ } else
Cnt -= 16; /* subtract length of CT header */
/* Loop through entire NameServer list of DIDs */
- while (Cnt) {
+ while (Cnt >= sizeof (uint32_t)) {
/* Get next DID from NameServer List */
CTentry = *ctptr++;
@@ -442,10 +443,8 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
phba->fc_ns_retry++;
/* CT command is being retried */
- ndlp =
- lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
- NameServer_DID);
- if (ndlp) {
+ ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
0) {
goto out;
@@ -729,7 +728,7 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+ ndlp = lpfc_findnode_did(phba, FDMI_DID);
if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
lpfc_printf_log(phba,
@@ -1039,6 +1038,9 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
case LA_4GHZ_LINK:
ae->un.PortSpeed = HBA_PORTSPEED_4GBIT;
break;
+ case LA_8GHZ_LINK:
+ ae->un.PortSpeed = HBA_PORTSPEED_8GBIT;
+ break;
default:
ae->un.PortSpeed =
HBA_PORTSPEED_UNKNOWN;
@@ -1161,7 +1163,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
{
struct lpfc_nodelist *ndlp;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
+ ndlp = lpfc_findnode_did(phba, FDMI_DID);
if (ndlp) {
if (init_utsname()->nodename[0] != '\0') {
lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 9766f909c9c..498059f3f7f 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -31,6 +31,7 @@
/* worker thread events */
enum lpfc_work_type {
LPFC_EVT_ONLINE,
+ LPFC_EVT_OFFLINE_PREP,
LPFC_EVT_OFFLINE,
LPFC_EVT_WARM_START,
LPFC_EVT_KILL,
@@ -68,7 +69,6 @@ struct lpfc_nodelist {
uint16_t nlp_maxframe; /* Max RCV frame size */
uint8_t nlp_class_sup; /* Supported Classes */
uint8_t nlp_retry; /* used for ELS retries */
- uint8_t nlp_disc_refcnt; /* used for DSM */
uint8_t nlp_fcp_info; /* class info, bits 0-3 */
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
@@ -79,20 +79,10 @@ struct lpfc_nodelist {
struct lpfc_work_evt els_retry_evt;
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
unsigned long last_q_full_time; /* jiffy of last queue full */
+ struct kref kref;
};
/* Defines for nlp_flag (uint32) */
-#define NLP_NO_LIST 0x0 /* Indicates immediately free node */
-#define NLP_UNUSED_LIST 0x1 /* Flg to indicate node will be freed */
-#define NLP_PLOGI_LIST 0x2 /* Flg to indicate sent PLOGI */
-#define NLP_ADISC_LIST 0x3 /* Flg to indicate sent ADISC */
-#define NLP_REGLOGIN_LIST 0x4 /* Flg to indicate sent REG_LOGIN */
-#define NLP_PRLI_LIST 0x5 /* Flg to indicate sent PRLI */
-#define NLP_UNMAPPED_LIST 0x6 /* Node is now unmapped */
-#define NLP_MAPPED_LIST 0x7 /* Node is now mapped */
-#define NLP_NPR_LIST 0x8 /* Node is in NPort Recovery state */
-#define NLP_JUST_DQ 0x9 /* just deque ndlp in lpfc_nlp_list */
-#define NLP_LIST_MASK 0xf /* mask to see what list node is on */
#define NLP_PLOGI_SND 0x20 /* sent PLOGI request for this entry */
#define NLP_PRLI_SND 0x40 /* sent PRLI request for this entry */
#define NLP_ADISC_SND 0x80 /* sent ADISC request for this entry */
@@ -108,20 +98,8 @@ struct lpfc_nodelist {
ACC */
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
NPR list */
-#define NLP_DELAY_REMOVE 0x4000000 /* Defer removal till end of DSM */
#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
-/* Defines for list searchs */
-#define NLP_SEARCH_MAPPED 0x1 /* search mapped */
-#define NLP_SEARCH_UNMAPPED 0x2 /* search unmapped */
-#define NLP_SEARCH_PLOGI 0x4 /* search plogi */
-#define NLP_SEARCH_ADISC 0x8 /* search adisc */
-#define NLP_SEARCH_REGLOGIN 0x10 /* search reglogin */
-#define NLP_SEARCH_PRLI 0x20 /* search prli */
-#define NLP_SEARCH_NPR 0x40 /* search npr */
-#define NLP_SEARCH_UNUSED 0x80 /* search mapped */
-#define NLP_SEARCH_ALL 0xff /* search all lists */
-
/* There are 4 different double linked lists nodelist entries can reside on.
* The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
* when Link Up discovery or Registered State Change Notification (RSCN)
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index a5f33a0dd4e..638b3cd677b 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -182,6 +182,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
icmd->un.elsreq64.remoteID = did; /* DID */
icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
+ icmd->ulpTimeout = phba->fc_ratov * 2;
} else {
icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
@@ -208,9 +209,9 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
}
/* Save for completion so we can release these resources */
- elsiocb->context1 = (uint8_t *) ndlp;
- elsiocb->context2 = (uint8_t *) pcmd;
- elsiocb->context3 = (uint8_t *) pbuflist;
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
+ elsiocb->context2 = pcmd;
+ elsiocb->context3 = pbuflist;
elsiocb->retry = retry;
elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
@@ -222,16 +223,16 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
/* Xmit ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
"%d:0116 Xmit ELS command x%x to remote "
- "NPORT x%x Data: x%x x%x\n",
+ "NPORT x%x I/O tag: x%x, HBA state: x%x\n",
phba->brd_no, elscmd,
- did, icmd->ulpIoTag, phba->hba_state);
+ did, elsiocb->iotag, phba->hba_state);
} else {
/* Xmit ELS response <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
"%d:0117 Xmit ELS response x%x to remote "
- "NPORT x%x Data: x%x x%x\n",
+ "NPORT x%x I/O tag: x%x, size: x%x\n",
phba->brd_no, elscmd,
- ndlp->nlp_DID, icmd->ulpIoTag, cmdSize);
+ ndlp->nlp_DID, elsiocb->iotag, cmdSize);
}
return elsiocb;
@@ -304,7 +305,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
goto fail_free_mbox;
mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
- mbox->context2 = ndlp;
+ mbox->context2 = lpfc_nlp_get(ndlp);
rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
if (rc == MBX_NOT_FINISHED)
@@ -313,6 +314,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
return 0;
fail_issue_reg_login:
+ lpfc_nlp_put(ndlp);
mp = (struct lpfc_dmabuf *) mbox->context1;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -368,9 +370,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
- mempool_free(ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, PT2PT_RemoteID);
+ ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID);
if (!ndlp) {
/*
* Cannot find existing Fabric ndlp, so allocate a
@@ -387,12 +389,11 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
sizeof(struct lpfc_name));
memcpy(&ndlp->nlp_nodename, &sp->nodeName,
sizeof(struct lpfc_name));
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
} else {
/* This side will wait for the PLOGI */
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
}
spin_lock_irq(phba->host->host_lock);
@@ -407,8 +408,8 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
}
static void
-lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_nodelist *ndlp = cmdiocb->context1;
@@ -418,7 +419,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
/* Check to see if link went down during discovery */
if (lpfc_els_chk_latt(phba)) {
- lpfc_nlp_remove(phba, ndlp);
+ lpfc_nlp_put(ndlp);
goto out;
}
@@ -433,13 +434,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
spin_unlock_irq(phba->host->host_lock);
- /* If private loop, then allow max outstandting els to be
+ /* If private loop, then allow max outstanding els to be
* LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
* alpa map would take too long otherwise.
*/
if (phba->alpa_map[0] == 0) {
- phba->cfg_discovery_threads =
- LPFC_MAX_DISC_THREADS;
+ phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
}
/* FLOGI failure */
@@ -484,7 +484,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba * phba,
}
flogifail:
- lpfc_nlp_remove(phba, ndlp);
+ lpfc_nlp_put(ndlp);
if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
(irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
@@ -582,24 +582,8 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
icmd = &iocb->iocb;
if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
ndlp = (struct lpfc_nodelist *)(iocb->context1);
- if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
- list_del(&iocb->list);
- pring->txcmplq_cnt--;
-
- if ((icmd->un.elsreq64.bdl.ulpIoTag32)) {
- lpfc_sli_issue_abort_iotag32
- (phba, pring, iocb);
- }
- if (iocb->iocb_cmpl) {
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] =
- IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
- }
+ if (ndlp && (ndlp->nlp_DID == Fabric_DID))
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
}
}
spin_unlock_irq(phba->host->host_lock);
@@ -608,12 +592,12 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
}
int
-lpfc_initial_flogi(struct lpfc_hba * phba)
+lpfc_initial_flogi(struct lpfc_hba *phba)
{
struct lpfc_nodelist *ndlp;
/* First look for the Fabric ndlp */
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, Fabric_DID);
+ ndlp = lpfc_findnode_did(phba, Fabric_DID);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -621,10 +605,10 @@ lpfc_initial_flogi(struct lpfc_hba * phba)
return 0;
lpfc_nlp_init(phba, ndlp, Fabric_DID);
} else {
- lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
+ lpfc_dequeue_node(phba, ndlp);
}
if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
}
return 1;
}
@@ -653,7 +637,7 @@ lpfc_more_plogi(struct lpfc_hba * phba)
}
static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
+lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
struct lpfc_nodelist *ndlp)
{
struct lpfc_nodelist *new_ndlp;
@@ -670,12 +654,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
- memset(name, 0, sizeof (struct lpfc_name));
+ memset(name, 0, sizeof(struct lpfc_name));
- /* Now we to find out if the NPort we are logging into, matches the WWPN
+ /* Now we find out if the NPort we are logging into, matches the WWPN
* we have for that ndlp. If not, we have some work to do.
*/
- new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
+ new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName);
if (new_ndlp == ndlp)
return ndlp;
@@ -695,18 +679,15 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
lpfc_unreg_rpi(phba, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
- new_ndlp->nlp_state = ndlp->nlp_state;
- lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
+ lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state);
/* Move this back to NPR list */
- if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
+ lpfc_drop_node(phba, ndlp);
else {
lpfc_unreg_rpi(phba, ndlp);
ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
}
return new_ndlp;
}
@@ -720,13 +701,11 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
struct lpfc_dmabuf *prsp;
int disc, rc, did, type;
-
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
irsp = &rspiocb->iocb;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL,
- irsp->un.elsreq64.remoteID);
+ ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID);
if (!ndlp)
goto out;
@@ -1354,7 +1333,7 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_SCR);
if (!elsiocb) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
return 1;
}
@@ -1373,12 +1352,12 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
spin_unlock_irq(phba->host->host_lock);
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
spin_unlock_irq(phba->host->host_lock);
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
return 0;
}
@@ -1407,7 +1386,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
ndlp->nlp_DID, ELS_CMD_RNID);
if (!elsiocb) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
return 1;
}
@@ -1428,7 +1407,7 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- if ((ondlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, nportid))) {
+ if ((ondlp = lpfc_findnode_did(phba, nportid))) {
memcpy(&fp->OportName, &ondlp->nlp_portname,
sizeof (struct lpfc_name));
memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
@@ -1440,12 +1419,12 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
spin_unlock_irq(phba->host->host_lock);
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
spin_unlock_irq(phba->host->host_lock);
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_put(ndlp);
return 0;
}
@@ -1554,29 +1533,25 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
case ELS_CMD_PLOGI:
if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
}
break;
case ELS_CMD_ADISC:
if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
}
break;
case ELS_CMD_PRLI:
if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
}
break;
case ELS_CMD_LOGO:
if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
}
break;
}
@@ -1614,12 +1589,12 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
cmd = *elscmd++;
}
- if(ndlp)
+ if (ndlp)
did = ndlp->nlp_DID;
else {
/* We should only hit this case for retrying PLOGI */
did = irsp->un.elsreq64.remoteID;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+ ndlp = lpfc_findnode_did(phba, did);
if (!ndlp && (cmd != ELS_CMD_PLOGI))
return 1;
}
@@ -1746,8 +1721,7 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
ndlp->nlp_flag |= NLP_DELAY_TMO;
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
ndlp->nlp_last_elscmd = cmd;
return 1;
@@ -1759,27 +1733,24 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
case ELS_CMD_PLOGI:
if (ndlp) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp,
+ NLP_STE_PLOGI_ISSUE);
}
lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
return 1;
case ELS_CMD_ADISC:
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_PRLI:
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_LOGO:
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
return 1;
}
@@ -1796,10 +1767,14 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
int
-lpfc_els_free_iocb(struct lpfc_hba * phba, struct lpfc_iocbq * elsiocb)
+lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
{
struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
+ if (elsiocb->context1) {
+ lpfc_nlp_put(elsiocb->context1);
+ elsiocb->context1 = NULL;
+ }
/* context2 = cmd, context2->next = rsp, context3 = bpl */
if (elsiocb->context2) {
buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
@@ -1843,7 +1818,7 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
switch (ndlp->nlp_state) {
case NLP_STE_UNUSED_NODE: /* node is just allocated */
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
break;
case NLP_STE_NPR_NODE: /* NPort Recovery mode */
lpfc_unreg_rpi(phba, ndlp);
@@ -1856,8 +1831,8 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
static void
-lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
@@ -1872,14 +1847,14 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
/* Check to see if link went down during discovery */
- if ((lpfc_els_chk_latt(phba)) || !ndlp) {
+ if (lpfc_els_chk_latt(phba) || !ndlp) {
if (mbox) {
mp = (struct lpfc_dmabuf *) mbox->context1;
if (mp) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
- mempool_free( mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
}
goto out;
}
@@ -1899,15 +1874,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
lpfc_unreg_rpi(phba, ndlp);
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
- mbox->context2 = ndlp;
+ mbox->context2 = lpfc_nlp_get(ndlp);
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_REGLOGIN_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
if (lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB))
!= MBX_NOT_FINISHED) {
goto out;
}
+ lpfc_nlp_put(ndlp);
/* NOTE: we should have messages for unsuccessful
reglogin */
} else {
@@ -1917,7 +1892,7 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
(irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
(irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
ndlp = NULL;
}
}
@@ -2012,15 +1987,16 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
return 1;
}
- if (newnode)
+ if (newnode) {
+ lpfc_nlp_put(ndlp);
elsiocb->context1 = NULL;
+ }
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS ACC response tag x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- elsiocb->iocb.ulpIoTag,
+ "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+ "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+ phba->brd_no, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
@@ -2077,10 +2053,9 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
/* Xmit ELS RJT <err> response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0129 Xmit ELS RJT x%x response tag x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- rejectError, elsiocb->iocb.ulpIoTag,
+ "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ phba->brd_no, rejectError, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
@@ -2119,18 +2094,18 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
if (!elsiocb)
return 1;
+ icmd = &elsiocb->iocb;
+ oldcmd = &oldiocb->iocb;
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+
/* Xmit ADISC ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0130 Xmit ADISC ACC response tag x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- elsiocb->iocb.ulpIoTag,
+ "%d:0130 Xmit ADISC ACC response iotag x%x xri: "
+ "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
+ phba->brd_no, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- icmd = &elsiocb->iocb;
- oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2155,8 +2130,8 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
}
int
-lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
+ struct lpfc_nodelist *ndlp)
{
PRLI *npr;
lpfc_vpd_t *vpd;
@@ -2178,18 +2153,18 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
if (!elsiocb)
return 1;
+ icmd = &elsiocb->iocb;
+ oldcmd = &oldiocb->iocb;
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+
/* Xmit PRLI ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0131 Xmit PRLI ACC response tag x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- elsiocb->iocb.ulpIoTag,
+ "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ phba->brd_no, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- icmd = &elsiocb->iocb;
- oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
@@ -2232,9 +2207,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba * phba,
}
static int
-lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
- uint8_t format,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
{
RNID *rn;
IOCB_t *icmd;
@@ -2259,17 +2233,17 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
if (!elsiocb)
return 1;
+ icmd = &elsiocb->iocb;
+ oldcmd = &oldiocb->iocb;
+ icmd->ulpContext = oldcmd->ulpContext; /* Xri */
+
/* Xmit RNID ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
"%d:0132 Xmit RNID ACC response tag x%x "
- "Data: x%x\n",
- phba->brd_no,
- elsiocb->iocb.ulpIoTag,
+ "xri x%x\n",
+ phba->brd_no, elsiocb->iotag,
elsiocb->iocb.ulpContext);
- icmd = &elsiocb->iocb;
- oldcmd = &oldiocb->iocb;
- icmd->ulpContext = oldcmd->ulpContext; /* Xri */
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2301,6 +2275,7 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
phba->fc_stat.elsXmitACC++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ lpfc_nlp_put(ndlp);
elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
* it could be freed */
@@ -2315,32 +2290,31 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba * phba,
}
int
-lpfc_els_disc_adisc(struct lpfc_hba * phba)
+lpfc_els_disc_adisc(struct lpfc_hba *phba)
{
int sentadisc;
struct lpfc_nodelist *ndlp, *next_ndlp;
sentadisc = 0;
- /* go thru NPR list and issue any remaining ELS ADISCs */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
- if (ndlp->nlp_flag & NLP_NPR_ADISC) {
- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_list(phba, ndlp,
- NLP_ADISC_LIST);
- lpfc_issue_els_adisc(phba, ndlp, 0);
- sentadisc++;
- phba->num_disc_nodes++;
- if (phba->num_disc_nodes >=
- phba->cfg_discovery_threads) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
- break;
- }
+ /* go thru NPR nodes and issue any remaining ELS ADISCs */
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+ (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+ (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
+ spin_lock_irq(phba->host->host_lock);
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+ spin_unlock_irq(phba->host->host_lock);
+ ndlp->nlp_prev_state = ndlp->nlp_state;
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(phba, ndlp, 0);
+ sentadisc++;
+ phba->num_disc_nodes++;
+ if (phba->num_disc_nodes >=
+ phba->cfg_discovery_threads) {
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag |= FC_NLP_MORE;
+ spin_unlock_irq(phba->host->host_lock);
+ break;
}
}
}
@@ -2360,24 +2334,22 @@ lpfc_els_disc_plogi(struct lpfc_hba * phba)
sentplogi = 0;
/* go thru NPR list and issue any remaining ELS PLOGIs */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- if ((ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
- (!(ndlp->nlp_flag & NLP_DELAY_TMO))) {
- if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
- sentplogi++;
- phba->num_disc_nodes++;
- if (phba->num_disc_nodes >=
- phba->cfg_discovery_threads) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
- break;
- }
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+ (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+ (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
+ (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
+ ndlp->nlp_prev_state = ndlp->nlp_state;
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ sentplogi++;
+ phba->num_disc_nodes++;
+ if (phba->num_disc_nodes >=
+ phba->cfg_discovery_threads) {
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag |= FC_NLP_MORE;
+ spin_unlock_irq(phba->host->host_lock);
+ break;
}
}
}
@@ -2479,42 +2451,30 @@ lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
}
static int
-lpfc_rscn_recovery_check(struct lpfc_hba * phba)
+lpfc_rscn_recovery_check(struct lpfc_hba *phba)
{
- struct lpfc_nodelist *ndlp = NULL, *next_ndlp;
- struct list_head *listp;
- struct list_head *node_list[7];
- int i;
+ struct lpfc_nodelist *ndlp = NULL;
/* Look at all nodes effected by pending RSCNs and move
- * them to NPR list.
+ * them to NPR state.
*/
- node_list[0] = &phba->fc_npr_list; /* MUST do this list first */
- node_list[1] = &phba->fc_nlpmap_list;
- node_list[2] = &phba->fc_nlpunmap_list;
- node_list[3] = &phba->fc_prli_list;
- node_list[4] = &phba->fc_reglogin_list;
- node_list[5] = &phba->fc_adisc_list;
- node_list[6] = &phba->fc_plogi_list;
- for (i = 0; i < 7; i++) {
- listp = node_list[i];
- if (list_empty(listp))
- continue;
- list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
- if (!(lpfc_rscn_payload_check(phba, ndlp->nlp_DID)))
- continue;
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
+ lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0)
+ continue;
- lpfc_disc_state_machine(phba, ndlp, NULL,
+ lpfc_disc_state_machine(phba, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
- /* Make sure NLP_DELAY_TMO is NOT running
- * after a device recovery event.
- */
- if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
- }
+ /*
+ * Make sure NLP_DELAY_TMO is NOT running after a device
+ * recovery event.
+ */
+ if (ndlp->nlp_flag & NLP_DELAY_TMO)
+ lpfc_cancel_retry_delay_tmo(phba, ndlp);
}
+
return 0;
}
@@ -2639,8 +2599,8 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
/* To process RSCN, first compare RSCN data with NameServer */
phba->fc_ns_retry = 0;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED, NameServer_DID);
- if (ndlp) {
+ ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
/* Good ndlp, issue CT Request to NameServer */
if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
/* Wait for NameServer query cmpl before we can
@@ -2650,7 +2610,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
} else {
/* If login to NameServer does not exist, issue one */
/* Good status, issue PLOGI to NameServer */
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+ ndlp = lpfc_findnode_did(phba, NameServer_DID);
if (ndlp) {
/* Wait for NameServer login cmpl before we can
continue */
@@ -2664,8 +2624,7 @@ lpfc_els_handle_rscn(struct lpfc_hba * phba)
lpfc_nlp_init(phba, ndlp, NameServer_DID);
ndlp->nlp_type |= NLP_FABRIC;
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, NameServer_DID, 0);
/* Wait for NameServer login cmpl before we can
continue */
@@ -2734,8 +2693,9 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox
(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+ lpfc_set_loopback_flag(phba);
if (rc == MBX_NOT_FINISHED) {
- mempool_free( mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
}
return 1;
} else if (rc > 0) { /* greater than */
@@ -2800,8 +2760,8 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
}
static int
-lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct ls_rjt stat;
@@ -2815,7 +2775,7 @@ lpfc_els_rcv_lirr(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
static void
-lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
@@ -2838,14 +2798,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
pmb->context2 = NULL;
if (mb->mbxStatus) {
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
ndlp->nlp_DID, ELS_CMD_ACC);
+ lpfc_nlp_put(ndlp);
if (!elsiocb)
return;
@@ -2875,15 +2836,15 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* Xmit ELS RPS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0118 Xmit ELS RPS ACC response tag x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- elsiocb->iocb.ulpIoTag,
+ "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ phba->brd_no, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
phba->fc_stat.elsXmitACC++;
+
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
}
@@ -2923,13 +2884,14 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
lpfc_read_lnk_stat(phba, mbox);
mbox->context1 =
(void *)((unsigned long)cmdiocb->iocb.ulpContext);
- mbox->context2 = ndlp;
+ mbox->context2 = lpfc_nlp_get(ndlp);
mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
if (lpfc_sli_issue_mbox (phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
/* Mbox completion will send ELS Response */
return 0;
}
+ lpfc_nlp_put(ndlp);
mempool_free(mbox, phba->mbox_mem_pool);
}
}
@@ -2984,10 +2946,9 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
/* Xmit ELS RPL ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0120 Xmit ELS RPL ACC response tag x%x "
- "Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- elsiocb->iocb.ulpIoTag,
+ "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
+ "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+ phba->brd_no, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
@@ -3091,8 +3052,8 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
/* Log back into the node before sending the FARP. */
if (fp->Rflags & FARP_REQUEST_PLOGI) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp,
+ NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
}
@@ -3169,14 +3130,15 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
*/
list_for_each_entry_safe(ndlp, next_ndlp,
- &phba->fc_npr_list, nlp_listp) {
-
+ &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+ continue;
if (ndlp->nlp_type & NLP_FABRIC) {
/*
* Clean up old Fabric, Nameserver and
* other NLP_FABRIC logins
*/
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding I/O now since this
* device is marked for PLOGI
@@ -3193,20 +3155,22 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
/* Discovery not needed,
* move the nodes to their original state.
*/
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ nlp_listp) {
+ if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+ continue;
switch (ndlp->nlp_prev_state) {
case NLP_STE_UNMAPPED_NODE:
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp,
+ NLP_STE_UNMAPPED_NODE);
break;
case NLP_STE_MAPPED_NODE:
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_MAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp,
+ NLP_STE_MAPPED_NODE);
break;
default:
@@ -3246,9 +3210,8 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
struct lpfc_dmabuf *pcmd;
- struct list_head *dlp;
uint32_t *elscmd;
- uint32_t els_command;
+ uint32_t els_command=0;
uint32_t timeout;
uint32_t remote_ID;
@@ -3263,17 +3226,20 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
- dlp = &pring->txcmplq;
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
cmd = &piocb->iocb;
- if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
+ if ((piocb->iocb_flag & LPFC_IO_LIBDFC) ||
+ (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) ||
+ (piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) {
continue;
}
pcmd = (struct lpfc_dmabuf *) piocb->context2;
- elscmd = (uint32_t *) (pcmd->virt);
- els_command = *elscmd;
+ if (pcmd) {
+ elscmd = (uint32_t *) (pcmd->virt);
+ els_command = *elscmd;
+ }
if ((els_command == ELS_CMD_FARP)
|| (els_command == ELS_CMD_FARPR)) {
@@ -3289,19 +3255,10 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
continue;
}
- list_del(&piocb->list);
- pring->txcmplq_cnt--;
-
if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
struct lpfc_nodelist *ndlp;
- spin_unlock_irq(phba->host->host_lock);
- ndlp = lpfc_findnode_rpi(phba, cmd->ulpContext);
- spin_lock_irq(phba->host->host_lock);
+ ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
remote_ID = ndlp->nlp_DID;
- if (cmd->un.elsreq64.bdl.ulpIoTag32) {
- lpfc_sli_issue_abort_iotag32(phba,
- pring, piocb);
- }
} else {
remote_ID = cmd->un.elsreq64.remoteID;
}
@@ -3313,17 +3270,7 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
phba->brd_no, els_command,
remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
- /*
- * The iocb has timed out; abort it.
- */
- if (piocb->iocb_cmpl) {
- cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (piocb->iocb_cmpl) (phba, piocb, piocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, piocb);
+ lpfc_sli_issue_abort_iotag(phba, pring, piocb);
}
if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
@@ -3332,16 +3279,13 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
}
void
-lpfc_els_flush_cmd(struct lpfc_hba * phba)
+lpfc_els_flush_cmd(struct lpfc_hba *phba)
{
- struct lpfc_sli_ring *pring;
+ LIST_HEAD(completions);
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
- struct lpfc_dmabuf *pcmd;
- uint32_t *elscmd;
- uint32_t els_command;
- pring = &phba->sli.ring[LPFC_ELS_RING];
spin_lock_irq(phba->host->host_lock);
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
cmd = &piocb->iocb;
@@ -3351,29 +3295,15 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
}
/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
- if ((cmd->ulpCommand == CMD_QUE_RING_BUF_CN) ||
- (cmd->ulpCommand == CMD_QUE_RING_BUF64_CN) ||
- (cmd->ulpCommand == CMD_CLOSE_XRI_CN) ||
- (cmd->ulpCommand == CMD_ABORT_XRI_CN)) {
+ if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
+ cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
+ cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+ cmd->ulpCommand == CMD_ABORT_XRI_CN)
continue;
- }
- pcmd = (struct lpfc_dmabuf *) piocb->context2;
- elscmd = (uint32_t *) (pcmd->virt);
- els_command = *elscmd;
+ list_move_tail(&piocb->list, &completions);
+ pring->txq_cnt--;
- list_del(&piocb->list);
- pring->txcmplq_cnt--;
-
- cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
-
- if (piocb->iocb_cmpl) {
- spin_unlock_irq(phba->host->host_lock);
- (piocb->iocb_cmpl) (phba, piocb, piocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, piocb);
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
@@ -3382,24 +3312,24 @@ lpfc_els_flush_cmd(struct lpfc_hba * phba)
if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
continue;
}
- pcmd = (struct lpfc_dmabuf *) piocb->context2;
- elscmd = (uint32_t *) (pcmd->virt);
- els_command = *elscmd;
- list_del(&piocb->list);
- pring->txcmplq_cnt--;
+ lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+ }
+ spin_unlock_irq(phba->host->host_lock);
- cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ while(!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ cmd = &piocb->iocb;
+ list_del(&piocb->list);
if (piocb->iocb_cmpl) {
- spin_unlock_irq(phba->host->host_lock);
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(piocb->iocb_cmpl) (phba, piocb, piocb);
- spin_lock_irq(phba->host->host_lock);
} else
lpfc_sli_release_iocbq(phba, piocb);
}
- spin_unlock_irq(phba->host->host_lock);
+
return;
}
@@ -3468,7 +3398,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
}
did = icmd->un.rcvels.remoteID;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+ ndlp = lpfc_findnode_did(phba, did);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
@@ -3484,12 +3414,13 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
ndlp->nlp_type |= NLP_FABRIC;
}
- ndlp->nlp_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
}
phba->fc_stat.elsRcvFrame++;
- elsiocb->context1 = ndlp;
+ if (elsiocb->context1)
+ lpfc_nlp_put(elsiocb->context1);
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
elsiocb->context2 = mp;
if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
@@ -3513,9 +3444,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
case ELS_CMD_FLOGI:
phba->fc_stat.elsRcvFLOGI++;
lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
case ELS_CMD_LOGO:
phba->fc_stat.elsRcvLOGO++;
@@ -3536,9 +3466,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
case ELS_CMD_RSCN:
phba->fc_stat.elsRcvRSCN++;
lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
case ELS_CMD_ADISC:
phba->fc_stat.elsRcvADISC++;
@@ -3579,30 +3508,26 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
case ELS_CMD_LIRR:
phba->fc_stat.elsRcvLIRR++;
lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
case ELS_CMD_RPS:
phba->fc_stat.elsRcvRPS++;
lpfc_els_rcv_rps(phba, elsiocb, ndlp);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
case ELS_CMD_RPL:
phba->fc_stat.elsRcvRPL++;
lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
case ELS_CMD_RNID:
phba->fc_stat.elsRcvRNID++;
lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
default:
/* Unsupported ELS command, reject */
@@ -3612,9 +3537,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
"%d:0115 Unknown ELS command x%x received from "
"NPORT x%x\n", phba->brd_no, cmd, did);
- if (newnode) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
+ if (newnode)
+ lpfc_drop_node(phba, ndlp);
break;
}
@@ -3627,6 +3551,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
}
+ lpfc_nlp_put(elsiocb->context1);
+ elsiocb->context1 = NULL;
if (elsiocb->context2) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index c39564e85e9..61caa8d379e 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -109,6 +109,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
return;
}
+ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ return;
+
name = (uint8_t *)&ndlp->nlp_portname;
phba = ndlp->nlp_phba;
@@ -147,11 +150,17 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
ndlp->nlp_state, ndlp->nlp_rpi);
}
- ndlp->rport = NULL;
- rdata->pnode = NULL;
-
- if (!(phba->fc_flag & FC_UNLOADING))
+ if (!(phba->fc_flag & FC_UNLOADING) &&
+ !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+ !(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
+ (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+ else {
+ rdata->pnode = NULL;
+ ndlp->rport = NULL;
+ lpfc_nlp_put(ndlp);
+ put_device(&rport->dev);
+ }
return;
}
@@ -182,29 +191,35 @@ lpfc_work_list_done(struct lpfc_hba * phba)
*(int *)(evtp->evt_arg1) = 0;
complete((struct completion *)(evtp->evt_arg2));
break;
- case LPFC_EVT_OFFLINE:
+ case LPFC_EVT_OFFLINE_PREP:
if (phba->hba_state >= LPFC_LINK_DOWN)
- lpfc_offline(phba);
+ lpfc_offline_prep(phba);
+ *(int *)(evtp->evt_arg1) = 0;
+ complete((struct completion *)(evtp->evt_arg2));
+ break;
+ case LPFC_EVT_OFFLINE:
+ lpfc_offline(phba);
lpfc_sli_brdrestart(phba);
*(int *)(evtp->evt_arg1) =
- lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY);
+ lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY);
+ lpfc_unblock_mgmt_io(phba);
complete((struct completion *)(evtp->evt_arg2));
break;
case LPFC_EVT_WARM_START:
- if (phba->hba_state >= LPFC_LINK_DOWN)
- lpfc_offline(phba);
+ lpfc_offline(phba);
lpfc_reset_barrier(phba);
lpfc_sli_brdreset(phba);
lpfc_hba_down_post(phba);
*(int *)(evtp->evt_arg1) =
lpfc_sli_brdready(phba, HS_MBRDY);
+ lpfc_unblock_mgmt_io(phba);
complete((struct completion *)(evtp->evt_arg2));
break;
case LPFC_EVT_KILL:
- if (phba->hba_state >= LPFC_LINK_DOWN)
- lpfc_offline(phba);
+ lpfc_offline(phba);
*(int *)(evtp->evt_arg1)
= (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
+ lpfc_unblock_mgmt_io(phba);
complete((struct completion *)(evtp->evt_arg2));
break;
}
@@ -359,13 +374,12 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
}
int
-lpfc_linkdown(struct lpfc_hba * phba)
+lpfc_linkdown(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp, *next_ndlp;
- struct list_head *listp, *node_list[7];
- LPFC_MBOXQ_t *mb;
- int rc, i;
+ LPFC_MBOXQ_t *mb;
+ int rc;
psli = &phba->sli;
/* sysfs or selective reset may call this routine to clean up */
@@ -397,31 +411,16 @@ lpfc_linkdown(struct lpfc_hba * phba)
/* Cleanup any outstanding ELS commands */
lpfc_els_flush_cmd(phba);
- /* Issue a LINK DOWN event to all nodes */
- node_list[0] = &phba->fc_npr_list; /* MUST do this list first */
- node_list[1] = &phba->fc_nlpmap_list;
- node_list[2] = &phba->fc_nlpunmap_list;
- node_list[3] = &phba->fc_prli_list;
- node_list[4] = &phba->fc_reglogin_list;
- node_list[5] = &phba->fc_adisc_list;
- node_list[6] = &phba->fc_plogi_list;
- for (i = 0; i < 7; i++) {
- listp = node_list[i];
- if (list_empty(listp))
- continue;
-
- list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
-
+ /*
+ * Issue a LINK DOWN event to all nodes.
+ */
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ /* free any ndlp's on unused list */
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ lpfc_drop_node(phba, ndlp);
+ else /* otherwise, force node recovery. */
rc = lpfc_disc_state_machine(phba, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
-
- }
- }
-
- /* free any ndlp's on unused list */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
- nlp_listp) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ NLP_EVT_DEVICE_RECOVERY);
}
/* Setup myDID for link up if we are in pt2pt mode */
@@ -452,11 +451,9 @@ lpfc_linkdown(struct lpfc_hba * phba)
}
static int
-lpfc_linkup(struct lpfc_hba * phba)
+lpfc_linkup(struct lpfc_hba *phba)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
- struct list_head *listp, *node_list[7];
- int i;
fc_host_post_event(phba->host, fc_get_event_number(),
FCH_EVT_LINKUP, 0);
@@ -470,29 +467,20 @@ lpfc_linkup(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
- node_list[0] = &phba->fc_plogi_list;
- node_list[1] = &phba->fc_adisc_list;
- node_list[2] = &phba->fc_reglogin_list;
- node_list[3] = &phba->fc_prli_list;
- node_list[4] = &phba->fc_nlpunmap_list;
- node_list[5] = &phba->fc_nlpmap_list;
- node_list[6] = &phba->fc_npr_list;
- for (i = 0; i < 7; i++) {
- listp = node_list[i];
- if (list_empty(listp))
- continue;
-
- list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) {
- if (phba->fc_flag & FC_LBIT) {
+ if (phba->fc_flag & FC_LBIT) {
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) {
if (ndlp->nlp_type & NLP_FABRIC) {
- /* On Linkup its safe to clean up the
+ /*
+ * On Linkup its safe to clean up the
* ndlp from Fabric connections.
*/
- lpfc_nlp_list(phba, ndlp,
- NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp,
+ NLP_STE_UNUSED_NODE);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- /* Fail outstanding IO now since device
- * is marked for PLOGI.
+ /*
+ * Fail outstanding IO now since
+ * device is marked for PLOGI.
*/
lpfc_unreg_rpi(phba, ndlp);
}
@@ -501,9 +489,10 @@ lpfc_linkup(struct lpfc_hba * phba)
}
/* free any ndlp's on unused list */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
- nlp_listp) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ lpfc_drop_node(phba, ndlp);
}
return 0;
@@ -734,6 +723,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
case LA_4GHZ_LINK:
phba->fc_linkspeed = LA_4GHZ_LINK;
break;
+ case LA_8GHZ_LINK:
+ phba->fc_linkspeed = LA_8GHZ_LINK;
+ break;
default:
phba->fc_linkspeed = LA_UNKNW_LINK;
break;
@@ -889,12 +881,21 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
if (la->attType == AT_LINK_UP) {
phba->fc_stat.LinkUp++;
- lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
+ if (phba->fc_flag & FC_LOOPBACK_MODE) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
+ "%d:1306 Link Up Event in loop back mode "
+ "x%x received Data: x%x x%x x%x x%x\n",
+ phba->brd_no, la->eventTag, phba->fc_eventTag,
+ la->granted_AL_PA, la->UlnkSpeed,
+ phba->alpa_map[0]);
+ } else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"%d:1303 Link Up Event x%x received "
"Data: x%x x%x x%x x%x\n",
phba->brd_no, la->eventTag, phba->fc_eventTag,
la->granted_AL_PA, la->UlnkSpeed,
phba->alpa_map[0]);
+ }
lpfc_mbx_process_link_up(phba, la);
} else {
phba->fc_stat.LinkDown++;
@@ -940,6 +941,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free( pmb, phba->mbox_mem_pool);
+ lpfc_nlp_put(ndlp);
return;
}
@@ -966,11 +968,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
ndlp = (struct lpfc_nodelist *) pmb->context2;
mp = (struct lpfc_dmabuf *) (pmb->context1);
+ pmb->context1 = NULL;
+ pmb->context2 = NULL;
+
if (mb->mbxStatus) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
- mempool_free( ndlp, phba->nlp_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_nlp_put(ndlp);
/* FLOGI failed, so just use loop map to make discovery list */
lpfc_disc_list_loopmap(phba);
@@ -980,12 +985,11 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
return;
}
- pmb->context1 = NULL;
-
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+
+ lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */
if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
/* This NPort has been assigned an NPort_ID by the fabric as a
@@ -996,7 +1000,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
*/
lpfc_issue_els_scr(phba, SCR_DID, 0);
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+ ndlp = lpfc_findnode_did(phba, NameServer_DID);
if (!ndlp) {
/* Allocate a new node instance. If the pool is empty,
* start the discovery process and skip the Nameserver
@@ -1008,15 +1012,14 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
lpfc_disc_start(phba);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
} else {
lpfc_nlp_init(phba, ndlp, NameServer_DID);
ndlp->nlp_type |= NLP_FABRIC;
}
}
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, NameServer_DID, 0);
if (phba->cfg_fdmi_on) {
ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
@@ -1032,7 +1035,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
@@ -1057,10 +1060,11 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mp = (struct lpfc_dmabuf *) (pmb->context1);
if (mb->mbxStatus) {
+ lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_drop_node(phba, ndlp);
/* RegLogin failed, so just use loop map to make discovery
list */
@@ -1075,8 +1079,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
if (phba->hba_state < LPFC_HBA_READY) {
/* Link up discovery requires Fabrib registration. */
@@ -1093,6 +1096,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
lpfc_disc_start(phba);
}
+ lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free( pmb, phba->mbox_mem_pool);
@@ -1101,8 +1105,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
}
static void
-lpfc_register_remote_port(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp)
+lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct fc_rport *rport;
struct lpfc_rport_data *rdata;
@@ -1114,8 +1117,19 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
rport_ids.port_id = ndlp->nlp_DID;
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
+ /*
+ * We leave our node pointer in rport->dd_data when we unregister a
+ * FCP target port. But fc_remote_port_add zeros the space to which
+ * rport->dd_data points. So, if we're reusing a previously
+ * registered port, drop the reference that we took the last time we
+ * registered the port.
+ */
+ if (ndlp->rport && ndlp->rport->dd_data &&
+ *(struct lpfc_rport_data **) ndlp->rport->dd_data) {
+ lpfc_nlp_put(ndlp);
+ }
ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
- if (!rport) {
+ if (!rport || !get_device(&rport->dev)) {
dev_printk(KERN_WARNING, &phba->pcidev->dev,
"Warning: fc_remote_port_add failed\n");
return;
@@ -1125,7 +1139,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
rport->maxframe_size = ndlp->nlp_maxframe;
rport->supported_classes = ndlp->nlp_class_sup;
rdata = rport->dd_data;
- rdata->pnode = ndlp;
+ rdata->pnode = lpfc_nlp_get(ndlp);
if (ndlp->nlp_type & NLP_FCP_TARGET)
rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
@@ -1145,8 +1159,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
}
static void
-lpfc_unregister_remote_port(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp)
+lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
struct fc_rport *rport = ndlp->rport;
struct lpfc_rport_data *rdata = rport->dd_data;
@@ -1154,6 +1167,8 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
if (rport->scsi_target_id == -1) {
ndlp->rport = NULL;
rdata->pnode = NULL;
+ lpfc_nlp_put(ndlp);
+ put_device(&rport->dev);
}
fc_remote_port_delete(rport);
@@ -1161,178 +1176,70 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
return;
}
-int
-lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
+static void
+lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count)
{
- enum { none, unmapped, mapped } rport_add = none, rport_del = none;
- struct lpfc_sli *psli;
-
- psli = &phba->sli;
- /* Sanity check to ensure we are not moving to / from the same list */
- if ((nlp->nlp_flag & NLP_LIST_MASK) == list)
- if (list != NLP_NO_LIST)
- return 0;
-
spin_lock_irq(phba->host->host_lock);
- switch (nlp->nlp_flag & NLP_LIST_MASK) {
- case NLP_NO_LIST: /* Not on any list */
+ switch (state) {
+ case NLP_STE_UNUSED_NODE:
+ phba->fc_unused_cnt += count;
break;
- case NLP_UNUSED_LIST:
- phba->fc_unused_cnt--;
- list_del(&nlp->nlp_listp);
+ case NLP_STE_PLOGI_ISSUE:
+ phba->fc_plogi_cnt += count;
break;
- case NLP_PLOGI_LIST:
- phba->fc_plogi_cnt--;
- list_del(&nlp->nlp_listp);
+ case NLP_STE_ADISC_ISSUE:
+ phba->fc_adisc_cnt += count;
break;
- case NLP_ADISC_LIST:
- phba->fc_adisc_cnt--;
- list_del(&nlp->nlp_listp);
+ case NLP_STE_REG_LOGIN_ISSUE:
+ phba->fc_reglogin_cnt += count;
break;
- case NLP_REGLOGIN_LIST:
- phba->fc_reglogin_cnt--;
- list_del(&nlp->nlp_listp);
+ case NLP_STE_PRLI_ISSUE:
+ phba->fc_prli_cnt += count;
break;
- case NLP_PRLI_LIST:
- phba->fc_prli_cnt--;
- list_del(&nlp->nlp_listp);
+ case NLP_STE_UNMAPPED_NODE:
+ phba->fc_unmap_cnt += count;
break;
- case NLP_UNMAPPED_LIST:
- phba->fc_unmap_cnt--;
- list_del(&nlp->nlp_listp);
- nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
- nlp->nlp_type &= ~NLP_FC_NODE;
- phba->nport_event_cnt++;
- if (nlp->rport)
- rport_del = unmapped;
+ case NLP_STE_MAPPED_NODE:
+ phba->fc_map_cnt += count;
break;
- case NLP_MAPPED_LIST:
- phba->fc_map_cnt--;
- list_del(&nlp->nlp_listp);
- phba->nport_event_cnt++;
- if (nlp->rport)
- rport_del = mapped;
- break;
- case NLP_NPR_LIST:
- phba->fc_npr_cnt--;
- list_del(&nlp->nlp_listp);
- /* Stop delay tmo if taking node off NPR list */
- if ((nlp->nlp_flag & NLP_DELAY_TMO) &&
- (list != NLP_NPR_LIST)) {
- spin_unlock_irq(phba->host->host_lock);
- lpfc_cancel_retry_delay_tmo(phba, nlp);
- spin_lock_irq(phba->host->host_lock);
- }
+ case NLP_STE_NPR_NODE:
+ phba->fc_npr_cnt += count;
break;
}
+ spin_unlock_irq(phba->host->host_lock);
+}
- nlp->nlp_flag &= ~NLP_LIST_MASK;
-
- /* Add NPort <did> to <num> list */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_NODE,
- "%d:0904 Add NPort x%x to %d list Data: x%x\n",
- phba->brd_no,
- nlp->nlp_DID, list, nlp->nlp_flag);
-
- switch (list) {
- case NLP_NO_LIST: /* No list, just remove it */
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_remove(phba, nlp);
- spin_lock_irq(phba->host->host_lock);
- /* as node removed - stop further transport calls */
- rport_del = none;
- break;
- case NLP_UNUSED_LIST:
- nlp->nlp_flag |= list;
- /* Put it at the end of the unused list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list);
- phba->fc_unused_cnt++;
- break;
- case NLP_PLOGI_LIST:
- nlp->nlp_flag |= list;
- /* Put it at the end of the plogi list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list);
- phba->fc_plogi_cnt++;
- break;
- case NLP_ADISC_LIST:
- nlp->nlp_flag |= list;
- /* Put it at the end of the adisc list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list);
- phba->fc_adisc_cnt++;
- break;
- case NLP_REGLOGIN_LIST:
- nlp->nlp_flag |= list;
- /* Put it at the end of the reglogin list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list);
- phba->fc_reglogin_cnt++;
- break;
- case NLP_PRLI_LIST:
- nlp->nlp_flag |= list;
- /* Put it at the end of the prli list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list);
- phba->fc_prli_cnt++;
- break;
- case NLP_UNMAPPED_LIST:
- rport_add = unmapped;
- /* ensure all vestiges of "mapped" significance are gone */
- nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
- nlp->nlp_flag |= list;
- /* Put it at the end of the unmap list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
- phba->fc_unmap_cnt++;
- phba->nport_event_cnt++;
- nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
- nlp->nlp_type |= NLP_FC_NODE;
- break;
- case NLP_MAPPED_LIST:
- rport_add = mapped;
- nlp->nlp_flag |= list;
- /* Put it at the end of the map list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
- phba->fc_map_cnt++;
+static void
+lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ int old_state, int new_state)
+{
+ if (new_state == NLP_STE_UNMAPPED_NODE) {
+ ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
+ ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+ ndlp->nlp_type |= NLP_FC_NODE;
+ }
+ if (new_state == NLP_STE_MAPPED_NODE)
+ ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
+ if (new_state == NLP_STE_NPR_NODE)
+ ndlp->nlp_flag &= ~NLP_RCV_PLOGI;
+
+ /* Transport interface */
+ if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
+ old_state == NLP_STE_UNMAPPED_NODE)) {
phba->nport_event_cnt++;
- nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
- break;
- case NLP_NPR_LIST:
- nlp->nlp_flag |= list;
- /* Put it at the end of the npr list */
- list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
- phba->fc_npr_cnt++;
-
- nlp->nlp_flag &= ~NLP_RCV_PLOGI;
- break;
- case NLP_JUST_DQ:
- break;
+ lpfc_unregister_remote_port(phba, ndlp);
}
- spin_unlock_irq(phba->host->host_lock);
-
- /*
- * We make all the calls into the transport after we have
- * moved the node between lists. This so that we don't
- * release the lock while in-between lists.
- */
-
- /* Don't upcall midlayer if we're unloading */
- if (!(phba->fc_flag & FC_UNLOADING)) {
- /*
- * We revalidate the rport pointer as the "add" function
- * may have removed the remote port.
- */
- if ((rport_del != none) && nlp->rport)
- lpfc_unregister_remote_port(phba, nlp);
-
- if (rport_add != none) {
+ if (new_state == NLP_STE_MAPPED_NODE ||
+ new_state == NLP_STE_UNMAPPED_NODE) {
+ phba->nport_event_cnt++;
/*
* Tell the fc transport about the port, if we haven't
* already. If we have, and it's a scsi entity, be
* sure to unblock any attached scsi devices
*/
- if ((!nlp->rport) || (nlp->rport->port_state ==
- FC_PORTSTATE_BLOCKED))
- lpfc_register_remote_port(phba, nlp);
+ lpfc_register_remote_port(phba, ndlp);
+ }
/*
* if we added to Mapped list, but the remote port
@@ -1340,19 +1247,95 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
* our presentable range - move the node to the
* Unmapped List
*/
- if ((rport_add == mapped) &&
- ((!nlp->rport) ||
- (nlp->rport->scsi_target_id == -1) ||
- (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
- nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- spin_lock_irq(phba->host->host_lock);
- nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_list(phba, nlp, NLP_UNMAPPED_LIST);
- }
- }
+ if (new_state == NLP_STE_MAPPED_NODE &&
+ (!ndlp->rport ||
+ ndlp->rport->scsi_target_id == -1 ||
+ ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
+ spin_lock_irq(phba->host->host_lock);
+ ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
+ spin_unlock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
}
- return 0;
+}
+
+static char *
+lpfc_nlp_state_name(char *buffer, size_t size, int state)
+{
+ static char *states[] = {
+ [NLP_STE_UNUSED_NODE] = "UNUSED",
+ [NLP_STE_PLOGI_ISSUE] = "PLOGI",
+ [NLP_STE_ADISC_ISSUE] = "ADISC",
+ [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN",
+ [NLP_STE_PRLI_ISSUE] = "PRLI",
+ [NLP_STE_UNMAPPED_NODE] = "UNMAPPED",
+ [NLP_STE_MAPPED_NODE] = "MAPPED",
+ [NLP_STE_NPR_NODE] = "NPR",
+ };
+
+ if (state < ARRAY_SIZE(states) && states[state])
+ strlcpy(buffer, states[state], size);
+ else
+ snprintf(buffer, size, "unknown (%d)", state);
+ return buffer;
+}
+
+void
+lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state)
+{
+ int old_state = ndlp->nlp_state;
+ char name1[16], name2[16];
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+ "%d:0904 NPort state transition x%06x, %s -> %s\n",
+ phba->brd_no,
+ ndlp->nlp_DID,
+ lpfc_nlp_state_name(name1, sizeof(name1), old_state),
+ lpfc_nlp_state_name(name2, sizeof(name2), state));
+ if (old_state == NLP_STE_NPR_NODE &&
+ (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
+ state != NLP_STE_NPR_NODE)
+ lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ if (old_state == NLP_STE_UNMAPPED_NODE) {
+ ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
+ ndlp->nlp_type &= ~NLP_FC_NODE;
+ }
+
+ if (list_empty(&ndlp->nlp_listp)) {
+ spin_lock_irq(phba->host->host_lock);
+ list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes);
+ spin_unlock_irq(phba->host->host_lock);
+ } else if (old_state)
+ lpfc_nlp_counters(phba, old_state, -1);
+
+ ndlp->nlp_state = state;
+ lpfc_nlp_counters(phba, state, 1);
+ lpfc_nlp_state_cleanup(phba, ndlp, old_state, state);
+}
+
+void
+lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+ if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+ lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+ lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+ spin_lock_irq(phba->host->host_lock);
+ list_del_init(&ndlp->nlp_listp);
+ spin_unlock_irq(phba->host->host_lock);
+ lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0);
+}
+
+void
+lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+{
+ if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
+ lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
+ lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
+ spin_lock_irq(phba->host->host_lock);
+ list_del_init(&ndlp->nlp_listp);
+ spin_unlock_irq(phba->host->host_lock);
+ lpfc_nlp_put(ndlp);
}
/*
@@ -1464,6 +1447,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
static int
lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
+ LIST_HEAD(completions);
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *iocb, *next_iocb;
@@ -1492,29 +1476,29 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
(phba, pring, iocb, ndlp))) {
/* It matches, so deque and call compl
with an error */
- list_del(&iocb->list);
+ list_move_tail(&iocb->list,
+ &completions);
pring->txq_cnt--;
- if (iocb->iocb_cmpl) {
- icmd = &iocb->iocb;
- icmd->ulpStatus =
- IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] =
- IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->
- host_lock);
- (iocb->iocb_cmpl) (phba,
- iocb, iocb);
- spin_lock_irq(phba->host->
- host_lock);
- } else
- lpfc_sli_release_iocbq(phba,
- iocb);
}
}
spin_unlock_irq(phba->host->host_lock);
}
}
+
+ while (!list_empty(&completions)) {
+ iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del(&iocb->list);
+
+ if (iocb->iocb_cmpl) {
+ icmd = &iocb->iocb;
+ icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (iocb->iocb_cmpl) (phba, iocb, iocb);
+ } else
+ lpfc_sli_release_iocbq(phba, iocb);
+ }
+
return 0;
}
@@ -1554,7 +1538,7 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
* so it can be freed.
*/
static int
-lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
LPFC_MBOXQ_t *mb;
LPFC_MBOXQ_t *nextmb;
@@ -1567,17 +1551,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
- lpfc_nlp_list(phba, ndlp, NLP_JUST_DQ);
-
- /*
- * if unloading the driver - just leave the remote port in place.
- * The driver unload will force the attached devices to detach
- * and flush cache's w/o generating flush errors.
- */
- if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
- lpfc_unregister_remote_port(phba, ndlp);
- ndlp->nlp_sid = NLP_NO_SID;
- }
+ lpfc_dequeue_node(phba, ndlp);
/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
if ((mb = phba->sli.mbox_active)) {
@@ -1599,11 +1573,12 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
}
list_del(&mb->list);
mempool_free(mb, phba->mbox_mem_pool);
+ lpfc_nlp_put(ndlp);
}
}
spin_unlock_irq(phba->host->host_lock);
- lpfc_els_abort(phba,ndlp,0);
+ lpfc_els_abort(phba,ndlp);
spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~NLP_DELAY_TMO;
spin_unlock_irq(phba->host->host_lock);
@@ -1624,27 +1599,27 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
* If we are in the middle of using the nlp in the discovery state
* machine, defer the free till we reach the end of the state machine.
*/
-int
-lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+static void
+lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
+ struct lpfc_rport_data *rdata;
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
lpfc_cancel_retry_delay_tmo(phba, ndlp);
}
- if (ndlp->nlp_disc_refcnt) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag |= NLP_DELAY_REMOVE;
- spin_unlock_irq(phba->host->host_lock);
- } else {
- lpfc_freenode(phba, ndlp);
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_cleanup_node(phba, ndlp);
+
+ if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
+ put_device(&ndlp->rport->dev);
+ rdata = ndlp->rport->dd_data;
+ rdata->pnode = NULL;
+ ndlp->rport = NULL;
}
- return 0;
}
static int
-lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
+lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
{
D_ID mydid;
D_ID ndlpdid;
@@ -1693,57 +1668,36 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did)
return 0;
}
-/* Search for a nodelist entry on a specific list */
+/* Search for a nodelist entry */
struct lpfc_nodelist *
-lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
+lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did)
{
struct lpfc_nodelist *ndlp;
- struct list_head *lists[]={&phba->fc_nlpunmap_list,
- &phba->fc_nlpmap_list,
- &phba->fc_plogi_list,
- &phba->fc_adisc_list,
- &phba->fc_reglogin_list,
- &phba->fc_prli_list,
- &phba->fc_npr_list,
- &phba->fc_unused_list};
- uint32_t search[]={NLP_SEARCH_UNMAPPED,
- NLP_SEARCH_MAPPED,
- NLP_SEARCH_PLOGI,
- NLP_SEARCH_ADISC,
- NLP_SEARCH_REGLOGIN,
- NLP_SEARCH_PRLI,
- NLP_SEARCH_NPR,
- NLP_SEARCH_UNUSED};
- int i;
uint32_t data1;
spin_lock_irq(phba->host->host_lock);
- for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
- if (!(order & search[i]))
- continue;
- list_for_each_entry(ndlp, lists[i], nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
- data1 = (((uint32_t) ndlp->nlp_state << 24) |
- ((uint32_t) ndlp->nlp_xri << 16) |
- ((uint32_t) ndlp->nlp_type << 8) |
- ((uint32_t) ndlp->nlp_rpi & 0xff));
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0929 FIND node DID "
- " Data: x%p x%x x%x x%x\n",
- phba->brd_no,
- ndlp, ndlp->nlp_DID,
- ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ if (lpfc_matchdid(phba, ndlp, did)) {
+ data1 = (((uint32_t) ndlp->nlp_state << 24) |
+ ((uint32_t) ndlp->nlp_xri << 16) |
+ ((uint32_t) ndlp->nlp_type << 8) |
+ ((uint32_t) ndlp->nlp_rpi & 0xff));
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+ "%d:0929 FIND node DID "
+ " Data: x%p x%x x%x x%x\n",
+ phba->brd_no,
+ ndlp, ndlp->nlp_DID,
+ ndlp->nlp_flag, data1);
+ spin_unlock_irq(phba->host->host_lock);
+ return ndlp;
}
}
spin_unlock_irq(phba->host->host_lock);
/* FIND node did <did> NOT FOUND */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n",
- phba->brd_no, did, order);
+ "%d:0932 FIND node did x%x NOT FOUND.\n",
+ phba->brd_no, did);
return NULL;
}
@@ -1751,9 +1705,8 @@ struct lpfc_nodelist *
lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
{
struct lpfc_nodelist *ndlp;
- uint32_t flg;
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did);
+ ndlp = lpfc_findnode_did(phba, did);
if (!ndlp) {
if ((phba->fc_flag & FC_RSCN_MODE) &&
((lpfc_rscn_payload_check(phba, did) == 0)))
@@ -1763,8 +1716,7 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
if (!ndlp)
return NULL;
lpfc_nlp_init(phba, ndlp, did);
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
return ndlp;
}
@@ -1780,11 +1732,10 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
} else
ndlp = NULL;
} else {
- flg = ndlp->nlp_flag & NLP_LIST_MASK;
- if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST))
+ if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
+ ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
return NULL;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
}
return ndlp;
@@ -1842,8 +1793,9 @@ lpfc_disc_start(struct lpfc_hba * phba)
struct lpfc_sli *psli;
LPFC_MBOXQ_t *mbox;
struct lpfc_nodelist *ndlp, *next_ndlp;
- uint32_t did_changed, num_sent;
+ uint32_t num_sent;
uint32_t clear_la_pending;
+ int did_changed;
int rc;
psli = &phba->sli;
@@ -1877,14 +1829,13 @@ lpfc_disc_start(struct lpfc_hba * phba)
phba->fc_plogi_cnt, phba->fc_adisc_cnt);
/* If our did changed, we MUST do PLOGI */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
- if (did_changed) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
- }
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
+ (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
+ did_changed) {
+ spin_lock_irq(phba->host->host_lock);
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+ spin_unlock_irq(phba->host->host_lock);
}
}
@@ -1944,11 +1895,11 @@ lpfc_disc_start(struct lpfc_hba * phba)
static void
lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
+ LIST_HEAD(completions);
struct lpfc_sli *psli;
IOCB_t *icmd;
struct lpfc_iocbq *iocb, *next_iocb;
struct lpfc_sli_ring *pring;
- struct lpfc_dmabuf *mp;
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING];
@@ -1956,6 +1907,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
/* Error matching iocb on txq or txcmplq
* First check the txq.
*/
+ spin_lock_irq(phba->host->host_lock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
if (iocb->context1 != ndlp) {
continue;
@@ -1964,9 +1916,8 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
(icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
- list_del(&iocb->list);
+ list_move_tail(&iocb->list, &completions);
pring->txq_cnt--;
- lpfc_els_free_iocb(phba, iocb);
}
}
@@ -1978,43 +1929,22 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
icmd = &iocb->iocb;
if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
(icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
+ }
+ spin_unlock_irq(phba->host->host_lock);
- iocb->iocb_cmpl = NULL;
- /* context2 = cmd, context2->next = rsp, context3 =
- bpl */
- if (iocb->context2) {
- /* Free the response IOCB before handling the
- command. */
-
- mp = (struct lpfc_dmabuf *) (iocb->context2);
- mp = list_get_first(&mp->list,
- struct lpfc_dmabuf,
- list);
- if (mp) {
- /* Delay before releasing rsp buffer to
- * give UNREG mbox a chance to take
- * effect.
- */
- list_add(&mp->list,
- &phba->freebufList);
- }
- lpfc_mbuf_free(phba,
- ((struct lpfc_dmabuf *)
- iocb->context2)->virt,
- ((struct lpfc_dmabuf *)
- iocb->context2)->phys);
- kfree(iocb->context2);
- }
+ while (!list_empty(&completions)) {
+ iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del(&iocb->list);
- if (iocb->context3) {
- lpfc_mbuf_free(phba,
- ((struct lpfc_dmabuf *)
- iocb->context3)->virt,
- ((struct lpfc_dmabuf *)
- iocb->context3)->phys);
- kfree(iocb->context3);
- }
- }
+ if (iocb->iocb_cmpl) {
+ icmd = &iocb->iocb;
+ icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (iocb->iocb_cmpl) (phba, iocb, iocb);
+ } else
+ lpfc_sli_release_iocbq(phba, iocb);
}
return;
@@ -2025,21 +1955,16 @@ lpfc_disc_flush_list(struct lpfc_hba * phba)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
- if (phba->fc_plogi_cnt) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
- nlp_listp) {
- lpfc_free_tx(phba, ndlp);
- lpfc_nlp_remove(phba, ndlp);
- }
- }
- if (phba->fc_adisc_cnt) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
- nlp_listp) {
- lpfc_free_tx(phba, ndlp);
- lpfc_nlp_remove(phba, ndlp);
+ if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
+ ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
+ lpfc_free_tx(phba, ndlp);
+ lpfc_nlp_put(ndlp);
+ }
}
}
- return;
}
/*****************************************************************************/
@@ -2108,11 +2033,13 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
phba->brd_no);
/* Start discovery by sending FLOGI, clean up old rpis */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ nlp_listp) {
+ if (ndlp->nlp_state != NLP_STE_NPR_NODE)
+ continue;
if (ndlp->nlp_type & NLP_FABRIC) {
/* Clean up the ndlp on Fabric connections */
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding IO now since device
* is marked for PLOGI.
@@ -2153,9 +2080,9 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
"login\n", phba->brd_no);
/* Next look for NameServer ndlp */
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID);
+ ndlp = lpfc_findnode_did(phba, NameServer_DID);
if (ndlp)
- lpfc_nlp_remove(phba, ndlp);
+ lpfc_nlp_put(ndlp);
/* Start discovery */
lpfc_disc_start(phba);
break;
@@ -2168,9 +2095,8 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
phba->brd_no,
phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
- ndlp = lpfc_findnode_did(phba, NLP_SEARCH_UNMAPPED,
- NameServer_DID);
- if (ndlp) {
+ ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
/* Try it one more time */
rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
@@ -2220,6 +2146,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
(MBX_NOWAIT | MBX_STOP_IOCB));
+ lpfc_set_loopback_flag(phba);
if (rc == MBX_NOT_FINISHED)
mempool_free(initlinkmbox, phba->mbox_mem_pool);
@@ -2317,8 +2244,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
/* Start issuing Fabric-Device Management Interface (FDMI)
* command to 0xfffffa (FDMI well known port)
@@ -2333,87 +2259,100 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
}
+ /* Mailbox took a reference to the node */
+ lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
+static int
+lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param)
+{
+ uint16_t *rpi = param;
+
+ return ndlp->nlp_rpi == *rpi;
+}
+
+static int
+lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
+{
+ return memcmp(&ndlp->nlp_portname, param,
+ sizeof(ndlp->nlp_portname)) == 0;
+}
+
+/*
+ * Search node lists for a remote port matching filter criteria
+ * Caller needs to hold host_lock before calling this routine.
+ */
+struct lpfc_nodelist *
+__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+{
+ struct lpfc_nodelist *ndlp;
+
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
+ filter(ndlp, param))
+ return ndlp;
+ }
+ return NULL;
+}
+
/*
- * This routine looks up the ndlp lists
- * for the given RPI. If rpi found
- * it return the node list pointer
- * else return NULL.
+ * Search node lists for a remote port matching filter criteria
+ * This routine is used when the caller does NOT have host_lock.
*/
struct lpfc_nodelist *
+lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+{
+ struct lpfc_nodelist *ndlp;
+
+ spin_lock_irq(phba->host->host_lock);
+ ndlp = __lpfc_find_node(phba, filter, param);
+ spin_unlock_irq(phba->host->host_lock);
+ return ndlp;
+}
+
+/*
+ * This routine looks up the ndlp lists for the given RPI. If rpi found it
+ * returns the node list pointer else return NULL.
+ */
+struct lpfc_nodelist *
+__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi)
+{
+ return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi);
+}
+
+struct lpfc_nodelist *
lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
{
struct lpfc_nodelist *ndlp;
- struct list_head * lists[]={&phba->fc_nlpunmap_list,
- &phba->fc_nlpmap_list,
- &phba->fc_plogi_list,
- &phba->fc_adisc_list,
- &phba->fc_reglogin_list};
- int i;
spin_lock_irq(phba->host->host_lock);
- for (i = 0; i < ARRAY_SIZE(lists); i++ )
- list_for_each_entry(ndlp, lists[i], nlp_listp)
- if (ndlp->nlp_rpi == rpi) {
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
+ ndlp = __lpfc_findnode_rpi(phba, rpi);
spin_unlock_irq(phba->host->host_lock);
- return NULL;
+ return ndlp;
}
/*
- * This routine looks up the ndlp lists
- * for the given WWPN. If WWPN found
- * it return the node list pointer
- * else return NULL.
+ * This routine looks up the ndlp lists for the given WWPN. If WWPN found it
+ * returns the node list pointer else return NULL.
*/
struct lpfc_nodelist *
-lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order,
- struct lpfc_name * wwpn)
+lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn)
{
struct lpfc_nodelist *ndlp;
- struct list_head * lists[]={&phba->fc_nlpunmap_list,
- &phba->fc_nlpmap_list,
- &phba->fc_npr_list,
- &phba->fc_plogi_list,
- &phba->fc_adisc_list,
- &phba->fc_reglogin_list,
- &phba->fc_prli_list};
- uint32_t search[]={NLP_SEARCH_UNMAPPED,
- NLP_SEARCH_MAPPED,
- NLP_SEARCH_NPR,
- NLP_SEARCH_PLOGI,
- NLP_SEARCH_ADISC,
- NLP_SEARCH_REGLOGIN,
- NLP_SEARCH_PRLI};
- int i;
spin_lock_irq(phba->host->host_lock);
- for (i = 0; i < ARRAY_SIZE(lists); i++ ) {
- if (!(order & search[i]))
- continue;
- list_for_each_entry(ndlp, lists[i], nlp_listp) {
- if (memcmp(&ndlp->nlp_portname, wwpn,
- sizeof(struct lpfc_name)) == 0) {
- spin_unlock_irq(phba->host->host_lock);
- return ndlp;
- }
- }
- }
+ ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn);
spin_unlock_irq(phba->host->host_lock);
return NULL;
}
void
-lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
- uint32_t did)
+lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
{
memset(ndlp, 0, sizeof (struct lpfc_nodelist));
INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
@@ -2423,5 +2362,30 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
ndlp->nlp_DID = did;
ndlp->nlp_phba = phba;
ndlp->nlp_sid = NLP_NO_SID;
+ INIT_LIST_HEAD(&ndlp->nlp_listp);
+ kref_init(&ndlp->kref);
return;
}
+
+void
+lpfc_nlp_release(struct kref *kref)
+{
+ struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
+ kref);
+ lpfc_nlp_remove(ndlp->nlp_phba, ndlp);
+ mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool);
+}
+
+struct lpfc_nodelist *
+lpfc_nlp_get(struct lpfc_nodelist *ndlp)
+{
+ if (ndlp)
+ kref_get(&ndlp->kref);
+ return ndlp;
+}
+
+int
+lpfc_nlp_put(struct lpfc_nodelist *ndlp)
+{
+ return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0;
+}
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index f79cb613690..2623a9bc777 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -1078,6 +1078,8 @@ typedef struct {
/* Start FireFly Register definitions */
#define PCI_VENDOR_ID_EMULEX 0x10df
#define PCI_DEVICE_ID_FIREFLY 0x1ae5
+#define PCI_DEVICE_ID_SAT_SMB 0xf011
+#define PCI_DEVICE_ID_SAT_MID 0xf015
#define PCI_DEVICE_ID_RFLY 0xf095
#define PCI_DEVICE_ID_PFLY 0xf098
#define PCI_DEVICE_ID_LP101 0xf0a1
@@ -1089,6 +1091,9 @@ typedef struct {
#define PCI_DEVICE_ID_NEPTUNE 0xf0f5
#define PCI_DEVICE_ID_NEPTUNE_SCSP 0xf0f6
#define PCI_DEVICE_ID_NEPTUNE_DCSP 0xf0f7
+#define PCI_DEVICE_ID_SAT 0xf100
+#define PCI_DEVICE_ID_SAT_SCSP 0xf111
+#define PCI_DEVICE_ID_SAT_DCSP 0xf112
#define PCI_DEVICE_ID_SUPERFLY 0xf700
#define PCI_DEVICE_ID_DRAGONFLY 0xf800
#define PCI_DEVICE_ID_CENTAUR 0xf900
@@ -1098,6 +1103,7 @@ typedef struct {
#define PCI_DEVICE_ID_LP10000S 0xfc00
#define PCI_DEVICE_ID_LP11000S 0xfc10
#define PCI_DEVICE_ID_LPE11000S 0xfc20
+#define PCI_DEVICE_ID_SAT_S 0xfc40
#define PCI_DEVICE_ID_HELIOS 0xfd00
#define PCI_DEVICE_ID_HELIOS_SCSP 0xfd11
#define PCI_DEVICE_ID_HELIOS_DCSP 0xfd12
@@ -1118,6 +1124,7 @@ typedef struct {
#define HELIOS_JEDEC_ID 0x0364
#define ZEPHYR_JEDEC_ID 0x0577
#define VIPER_JEDEC_ID 0x4838
+#define SATURN_JEDEC_ID 0x1004
#define JEDEC_ID_MASK 0x0FFFF000
#define JEDEC_ID_SHIFT 12
@@ -1565,7 +1572,7 @@ typedef struct {
#define LINK_SPEED_1G 1 /* 1 Gigabaud */
#define LINK_SPEED_2G 2 /* 2 Gigabaud */
#define LINK_SPEED_4G 4 /* 4 Gigabaud */
-#define LINK_SPEED_8G 8 /* 4 Gigabaud */
+#define LINK_SPEED_8G 8 /* 8 Gigabaud */
#define LINK_SPEED_10G 16 /* 10 Gigabaud */
} INIT_LINK_VAR;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 057fd7e0e37..dcb4ba0ecee 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -386,12 +386,12 @@ lpfc_config_port_post(struct lpfc_hba * phba)
* Setup the ring 0 (els) timeout handler
*/
timeout = phba->fc_ratov << 1;
- phba->els_tmofunc.expires = jiffies + HZ * timeout;
- add_timer(&phba->els_tmofunc);
+ mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ lpfc_set_loopback_flag(phba);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba,
KERN_ERR,
@@ -418,33 +418,6 @@ lpfc_config_port_post(struct lpfc_hba * phba)
return (0);
}
-static int
-lpfc_discovery_wait(struct lpfc_hba *phba)
-{
- int i = 0;
-
- while ((phba->hba_state != LPFC_HBA_READY) ||
- (phba->num_disc_nodes) || (phba->fc_prli_sent) ||
- ((phba->fc_map_cnt == 0) && (i<2)) ||
- (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
- /* Check every second for 30 retries. */
- i++;
- if (i > 30) {
- return -ETIMEDOUT;
- }
- if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
- /* The link is down. Set linkdown timeout */
- return -ETIMEDOUT;
- }
-
- /* Delay for 1 second to give discovery time to complete. */
- msleep(1000);
-
- }
-
- return 0;
-}
-
/************************************************************************/
/* */
/* lpfc_hba_down_prep */
@@ -550,12 +523,15 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
* There was a firmware error. Take the hba offline and then
* attempt to restart it.
*/
+ lpfc_offline_prep(phba);
lpfc_offline(phba);
lpfc_sli_brdrestart(phba);
if (lpfc_online(phba) == 0) { /* Initialize the HBA */
mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+ lpfc_unblock_mgmt_io(phba);
return;
}
+ lpfc_unblock_mgmt_io(phba);
} else {
/* The if clause above forces this code path when the status
* failure is a value other than FFER6. Do not call the offline
@@ -573,7 +549,9 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ lpfc_offline_prep(phba);
lpfc_offline(phba);
+ lpfc_unblock_mgmt_io(phba);
phba->hba_state = LPFC_HBA_ERROR;
lpfc_hba_down_post(phba);
}
@@ -633,7 +611,7 @@ lpfc_handle_latt_free_mbuf:
lpfc_handle_latt_free_mp:
kfree(mp);
lpfc_handle_latt_free_pmb:
- kfree(pmb);
+ mempool_free(pmb, phba->mbox_mem_pool);
lpfc_handle_latt_err_exit:
/* Enable Link attention interrupts */
spin_lock_irq(phba->host->host_lock);
@@ -671,7 +649,7 @@ static int
lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
{
uint8_t lenlo, lenhi;
- uint32_t Length;
+ int Length;
int i, j;
int finished = 0;
int index = 0;
@@ -925,6 +903,24 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
m = (typeof(m)){"LPe11000-S", max_speed,
"PCIe"};
break;
+ case PCI_DEVICE_ID_SAT:
+ m = (typeof(m)){"LPe12000", max_speed, "PCIe"};
+ break;
+ case PCI_DEVICE_ID_SAT_MID:
+ m = (typeof(m)){"LPe1250", max_speed, "PCIe"};
+ break;
+ case PCI_DEVICE_ID_SAT_SMB:
+ m = (typeof(m)){"LPe121", max_speed, "PCIe"};
+ break;
+ case PCI_DEVICE_ID_SAT_DCSP:
+ m = (typeof(m)){"LPe12002-SP", max_speed, "PCIe"};
+ break;
+ case PCI_DEVICE_ID_SAT_SCSP:
+ m = (typeof(m)){"LPe12000-SP", max_speed, "PCIe"};
+ break;
+ case PCI_DEVICE_ID_SAT_S:
+ m = (typeof(m)){"LPe12000-S", max_speed, "PCIe"};
+ break;
default:
m = (typeof(m)){ NULL };
break;
@@ -1174,69 +1170,17 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
}
static void
-lpfc_cleanup(struct lpfc_hba * phba, uint32_t save_bind)
+lpfc_cleanup(struct lpfc_hba * phba)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
/* clean up phba - lpfc specific */
lpfc_can_disctmo(phba);
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+ lpfc_nlp_put(ndlp);
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
-
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_unused_list,
- nlp_listp) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- }
-
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
-
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
-
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_reglogin_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
+ INIT_LIST_HEAD(&phba->fc_nodes);
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
-
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- lpfc_nlp_remove(phba, ndlp);
- }
-
- INIT_LIST_HEAD(&phba->fc_nlpmap_list);
- INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
- INIT_LIST_HEAD(&phba->fc_unused_list);
- INIT_LIST_HEAD(&phba->fc_plogi_list);
- INIT_LIST_HEAD(&phba->fc_adisc_list);
- INIT_LIST_HEAD(&phba->fc_reglogin_list);
- INIT_LIST_HEAD(&phba->fc_prli_list);
- INIT_LIST_HEAD(&phba->fc_npr_list);
-
- phba->fc_map_cnt = 0;
- phba->fc_unmap_cnt = 0;
- phba->fc_plogi_cnt = 0;
- phba->fc_adisc_cnt = 0;
- phba->fc_reglogin_cnt = 0;
- phba->fc_prli_cnt = 0;
- phba->fc_npr_cnt = 0;
- phba->fc_unused_cnt= 0;
return;
}
@@ -1262,21 +1206,6 @@ lpfc_stop_timer(struct lpfc_hba * phba)
{
struct lpfc_sli *psli = &phba->sli;
- /* Instead of a timer, this has been converted to a
- * deferred procedding list.
- */
- while (!list_empty(&phba->freebufList)) {
-
- struct lpfc_dmabuf *mp = NULL;
-
- list_remove_head((&phba->freebufList), mp,
- struct lpfc_dmabuf, list);
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- }
-
del_timer_sync(&phba->fcp_poll_timer);
del_timer_sync(&phba->fc_estabtmo);
del_timer_sync(&phba->fc_disctmo);
@@ -1302,60 +1231,76 @@ lpfc_online(struct lpfc_hba * phba)
"%d:0458 Bring Adapter online\n",
phba->brd_no);
- if (!lpfc_sli_queue_setup(phba))
+ lpfc_block_mgmt_io(phba);
+
+ if (!lpfc_sli_queue_setup(phba)) {
+ lpfc_unblock_mgmt_io(phba);
return 1;
+ }
- if (lpfc_sli_hba_setup(phba)) /* Initialize the HBA */
+ if (lpfc_sli_hba_setup(phba)) { /* Initialize the HBA */
+ lpfc_unblock_mgmt_io(phba);
return 1;
+ }
spin_lock_irq(phba->host->host_lock);
phba->fc_flag &= ~FC_OFFLINE_MODE;
spin_unlock_irq(phba->host->host_lock);
+ lpfc_unblock_mgmt_io(phba);
return 0;
}
-int
-lpfc_offline(struct lpfc_hba * phba)
+void
+lpfc_block_mgmt_io(struct lpfc_hba * phba)
{
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
unsigned long iflag;
- int i;
- int cnt = 0;
- if (!phba)
- return 0;
+ spin_lock_irqsave(phba->host->host_lock, iflag);
+ phba->fc_flag |= FC_BLOCK_MGMT_IO;
+ spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
+{
+ unsigned long iflag;
+
+ spin_lock_irqsave(phba->host->host_lock, iflag);
+ phba->fc_flag &= ~FC_BLOCK_MGMT_IO;
+ spin_unlock_irqrestore(phba->host->host_lock, iflag);
+}
+
+void
+lpfc_offline_prep(struct lpfc_hba * phba)
+{
+ struct lpfc_nodelist *ndlp, *next_ndlp;
if (phba->fc_flag & FC_OFFLINE_MODE)
- return 0;
+ return;
- psli = &phba->sli;
+ lpfc_block_mgmt_io(phba);
lpfc_linkdown(phba);
+
+ /* Issue an unreg_login to all nodes */
+ list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+ if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
+ lpfc_unreg_rpi(phba, ndlp);
+
lpfc_sli_flush_mbox_queue(phba);
+}
- for (i = 0; i < psli->num_rings; i++) {
- pring = &psli->ring[i];
- /* The linkdown event takes 30 seconds to timeout. */
- while (pring->txcmplq_cnt) {
- mdelay(10);
- if (cnt++ > 3000) {
- lpfc_printf_log(phba,
- KERN_WARNING, LOG_INIT,
- "%d:0466 Outstanding IO when "
- "bringing Adapter offline\n",
- phba->brd_no);
- break;
- }
- }
- }
+void
+lpfc_offline(struct lpfc_hba * phba)
+{
+ unsigned long iflag;
+ if (phba->fc_flag & FC_OFFLINE_MODE)
+ return;
/* stop all timers associated with this hba */
lpfc_stop_timer(phba);
- phba->work_hba_events = 0;
- phba->work_ha = 0;
lpfc_printf_log(phba,
KERN_WARNING,
@@ -1366,11 +1311,12 @@ lpfc_offline(struct lpfc_hba * phba)
/* Bring down the SLI Layer and cleanup. The HBA is offline
now. */
lpfc_sli_hba_down(phba);
- lpfc_cleanup(phba, 1);
+ lpfc_cleanup(phba);
spin_lock_irqsave(phba->host->host_lock, iflag);
+ phba->work_hba_events = 0;
+ phba->work_ha = 0;
phba->fc_flag |= FC_OFFLINE_MODE;
spin_unlock_irqrestore(phba->host->host_lock, iflag);
- return 0;
}
/******************************************************************************
@@ -1407,6 +1353,156 @@ lpfc_scsi_free(struct lpfc_hba * phba)
return 0;
}
+void lpfc_remove_device(struct lpfc_hba *phba)
+{
+ unsigned long iflag;
+
+ lpfc_free_sysfs_attr(phba);
+
+ spin_lock_irqsave(phba->host->host_lock, iflag);
+ phba->fc_flag |= FC_UNLOADING;
+
+ spin_unlock_irqrestore(phba->host->host_lock, iflag);
+
+ fc_remove_host(phba->host);
+ scsi_remove_host(phba->host);
+
+ kthread_stop(phba->worker_thread);
+
+ /*
+ * Bring down the SLI Layer. This step disable all interrupts,
+ * clears the rings, discards all mailbox commands, and resets
+ * the HBA.
+ */
+ lpfc_sli_hba_down(phba);
+ lpfc_sli_brdrestart(phba);
+
+ /* Release the irq reservation */
+ free_irq(phba->pcidev->irq, phba);
+ pci_disable_msi(phba->pcidev);
+
+ lpfc_cleanup(phba);
+ lpfc_stop_timer(phba);
+ phba->work_hba_events = 0;
+
+ /*
+ * Call scsi_free before mem_free since scsi bufs are released to their
+ * corresponding pools here.
+ */
+ lpfc_scsi_free(phba);
+ lpfc_mem_free(phba);
+
+ /* Free resources associated with SLI2 interface */
+ dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
+ phba->slim2p, phba->slim2p_mapping);
+
+ /* unmap adapter SLIM and Control Registers */
+ iounmap(phba->ctrl_regs_memmap_p);
+ iounmap(phba->slim_memmap_p);
+
+ pci_release_regions(phba->pcidev);
+ pci_disable_device(phba->pcidev);
+
+ idr_remove(&lpfc_hba_index, phba->brd_no);
+ scsi_host_put(phba->host);
+}
+
+void lpfc_scan_start(struct Scsi_Host *host)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+
+ if (lpfc_alloc_sysfs_attr(phba))
+ goto error;
+
+ phba->MBslimaddr = phba->slim_memmap_p;
+ phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+ phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+ phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+ phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+ if (lpfc_sli_hba_setup(phba))
+ goto error;
+
+ /*
+ * hba setup may have changed the hba_queue_depth so we need to adjust
+ * the value of can_queue.
+ */
+ host->can_queue = phba->cfg_hba_queue_depth - 10;
+ return;
+
+error:
+ lpfc_remove_device(phba);
+}
+
+int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+
+ if (!phba->host)
+ return 1;
+ if (time >= 30 * HZ)
+ goto finished;
+
+ if (phba->hba_state != LPFC_HBA_READY)
+ return 0;
+ if (phba->num_disc_nodes || phba->fc_prli_sent)
+ return 0;
+ if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
+ return 0;
+ if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
+ return 0;
+ if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
+ return 0;
+
+finished:
+ if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+ spin_lock_irq(shost->host_lock);
+ lpfc_poll_start_timer(phba);
+ spin_unlock_irq(shost->host_lock);
+ }
+
+ /*
+ * set fixed host attributes
+ * Must done after lpfc_sli_hba_setup()
+ */
+
+ fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
+ fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
+ fc_host_supported_classes(shost) = FC_COS_CLASS3;
+
+ memset(fc_host_supported_fc4s(shost), 0,
+ sizeof(fc_host_supported_fc4s(shost)));
+ fc_host_supported_fc4s(shost)[2] = 1;
+ fc_host_supported_fc4s(shost)[7] = 1;
+
+ lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+
+ fc_host_supported_speeds(shost) = 0;
+ if (phba->lmt & LMT_10Gb)
+ fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT;
+ if (phba->lmt & LMT_4Gb)
+ fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT;
+ if (phba->lmt & LMT_2Gb)
+ fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT;
+ if (phba->lmt & LMT_1Gb)
+ fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
+
+ fc_host_maxframe_size(shost) =
+ ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+ (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+
+ /* This value is also unchanging */
+ memset(fc_host_active_fc4s(shost), 0,
+ sizeof(fc_host_active_fc4s(shost)));
+ fc_host_active_fc4s(shost)[2] = 1;
+ fc_host_active_fc4s(shost)[7] = 1;
+
+ spin_lock_irq(shost->host_lock);
+ phba->fc_flag &= ~FC_LOADING;
+ spin_unlock_irq(shost->host_lock);
+
+ return 1;
+}
static int __devinit
lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
@@ -1445,9 +1541,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_put_host;
host->unique_id = phba->brd_no;
- INIT_LIST_HEAD(&phba->ctrspbuflist);
- INIT_LIST_HEAD(&phba->rnidrspbuflist);
- INIT_LIST_HEAD(&phba->freebufList);
/* Initialize timers used by driver */
init_timer(&phba->fc_estabtmo);
@@ -1482,16 +1575,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
host->max_lun = phba->cfg_max_luns;
host->this_id = -1;
- /* Initialize all internally managed lists. */
- INIT_LIST_HEAD(&phba->fc_nlpmap_list);
- INIT_LIST_HEAD(&phba->fc_nlpunmap_list);
- INIT_LIST_HEAD(&phba->fc_unused_list);
- INIT_LIST_HEAD(&phba->fc_plogi_list);
- INIT_LIST_HEAD(&phba->fc_adisc_list);
- INIT_LIST_HEAD(&phba->fc_reglogin_list);
- INIT_LIST_HEAD(&phba->fc_prli_list);
- INIT_LIST_HEAD(&phba->fc_npr_list);
-
+ INIT_LIST_HEAD(&phba->fc_nodes);
pci_set_master(pdev);
retval = pci_set_mwi(pdev);
@@ -1609,13 +1693,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
host->transportt = lpfc_transport_template;
pci_set_drvdata(pdev, host);
- error = scsi_add_host(host, &pdev->dev);
- if (error)
- goto out_kthread_stop;
-
- error = lpfc_alloc_sysfs_attr(phba);
- if (error)
- goto out_remove_host;
if (phba->cfg_use_msi) {
error = pci_enable_msi(phba->pcidev);
@@ -1631,73 +1708,15 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0451 Enable interrupt handler failed\n",
phba->brd_no);
- goto out_free_sysfs_attr;
+ goto out_kthread_stop;
}
- phba->MBslimaddr = phba->slim_memmap_p;
- phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
- phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
- phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
- phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
- error = lpfc_sli_hba_setup(phba);
- if (error) {
- error = -ENODEV;
+ error = scsi_add_host(host, &pdev->dev);
+ if (error)
goto out_free_irq;
- }
-
- /*
- * hba setup may have changed the hba_queue_depth so we need to adjust
- * the value of can_queue.
- */
- host->can_queue = phba->cfg_hba_queue_depth - 10;
-
- lpfc_discovery_wait(phba);
- if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
- spin_lock_irq(phba->host->host_lock);
- lpfc_poll_start_timer(phba);
- spin_unlock_irq(phba->host->host_lock);
- }
+ scsi_scan_host(host);
- /*
- * set fixed host attributes
- * Must done after lpfc_sli_hba_setup()
- */
-
- fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn);
- fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn);
- fc_host_supported_classes(host) = FC_COS_CLASS3;
-
- memset(fc_host_supported_fc4s(host), 0,
- sizeof(fc_host_supported_fc4s(host)));
- fc_host_supported_fc4s(host)[2] = 1;
- fc_host_supported_fc4s(host)[7] = 1;
-
- lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(host));
-
- fc_host_supported_speeds(host) = 0;
- if (phba->lmt & LMT_10Gb)
- fc_host_supported_speeds(host) |= FC_PORTSPEED_10GBIT;
- if (phba->lmt & LMT_4Gb)
- fc_host_supported_speeds(host) |= FC_PORTSPEED_4GBIT;
- if (phba->lmt & LMT_2Gb)
- fc_host_supported_speeds(host) |= FC_PORTSPEED_2GBIT;
- if (phba->lmt & LMT_1Gb)
- fc_host_supported_speeds(host) |= FC_PORTSPEED_1GBIT;
-
- fc_host_maxframe_size(host) =
- ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
- (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
-
- /* This value is also unchanging */
- memset(fc_host_active_fc4s(host), 0,
- sizeof(fc_host_active_fc4s(host)));
- fc_host_active_fc4s(host)[2] = 1;
- fc_host_active_fc4s(host)[7] = 1;
-
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_LOADING;
- spin_unlock_irq(phba->host->host_lock);
return 0;
out_free_irq:
@@ -1705,11 +1724,6 @@ out_free_irq:
phba->work_hba_events = 0;
free_irq(phba->pcidev->irq, phba);
pci_disable_msi(phba->pcidev);
-out_free_sysfs_attr:
- lpfc_free_sysfs_attr(phba);
-out_remove_host:
- fc_remove_host(phba->host);
- scsi_remove_host(phba->host);
out_kthread_stop:
kthread_stop(phba->worker_thread);
out_free_iocbq:
@@ -1747,56 +1761,8 @@ lpfc_pci_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
- unsigned long iflag;
-
- lpfc_free_sysfs_attr(phba);
-
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag |= FC_UNLOADING;
-
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
- fc_remove_host(phba->host);
- scsi_remove_host(phba->host);
-
- kthread_stop(phba->worker_thread);
-
- /*
- * Bring down the SLI Layer. This step disable all interrupts,
- * clears the rings, discards all mailbox commands, and resets
- * the HBA.
- */
- lpfc_sli_hba_down(phba);
- lpfc_sli_brdrestart(phba);
-
- /* Release the irq reservation */
- free_irq(phba->pcidev->irq, phba);
- pci_disable_msi(phba->pcidev);
-
- lpfc_cleanup(phba, 0);
- lpfc_stop_timer(phba);
- phba->work_hba_events = 0;
-
- /*
- * Call scsi_free before mem_free since scsi bufs are released to their
- * corresponding pools here.
- */
- lpfc_scsi_free(phba);
- lpfc_mem_free(phba);
-
- /* Free resources associated with SLI2 interface */
- dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
- phba->slim2p, phba->slim2p_mapping);
-
- /* unmap adapter SLIM and Control Registers */
- iounmap(phba->ctrl_regs_memmap_p);
- iounmap(phba->slim_memmap_p);
-
- pci_release_regions(phba->pcidev);
- pci_disable_device(phba->pcidev);
-
- idr_remove(&lpfc_hba_index, phba->brd_no);
- scsi_host_put(phba->host);
+ lpfc_remove_device(phba);
pci_set_drvdata(pdev, NULL);
}
@@ -1941,6 +1907,18 @@ static struct pci_device_id lpfc_id_table[] = {
PCI_ANY_ID, PCI_ANY_ID, },
{PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S,
PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S,
+ PCI_ANY_ID, PCI_ANY_ID, },
{ 0 }
};
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 4d016c2a1b2..8041c3f06f7 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -212,6 +212,7 @@ lpfc_init_link(struct lpfc_hba * phba,
case LINK_SPEED_1G:
case LINK_SPEED_2G:
case LINK_SPEED_4G:
+ case LINK_SPEED_8G:
mb->un.varInitLnk.link_flags |=
FLAGS_LINK_SPEED;
mb->un.varInitLnk.link_speed = linkspeed;
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 0c7e731dc45..b309841e384 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -168,14 +168,13 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
* routine effectively results in a "software abort".
*/
int
-lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
- int send_abts)
+lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
+ LIST_HEAD(completions);
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *iocb, *next_iocb;
- IOCB_t *icmd;
- int found = 0;
+ IOCB_t *cmd;
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
@@ -188,75 +187,39 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
pring = &psli->ring[LPFC_ELS_RING];
/* First check the txq */
- do {
- found = 0;
- spin_lock_irq(phba->host->host_lock);
- list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- /* Check to see if iocb matches the nport we are looking
- for */
- if ((lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))) {
- found = 1;
- /* It matches, so deque and call compl with an
- error */
- list_del(&iocb->list);
- pring->txq_cnt--;
- if (iocb->iocb_cmpl) {
- icmd = &iocb->iocb;
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
- break;
- }
+ spin_lock_irq(phba->host->host_lock);
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+ /* Check to see if iocb matches the nport we are looking
+ for */
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
+ /* It matches, so deque and call compl with an
+ error */
+ list_move_tail(&iocb->list, &completions);
+ pring->txq_cnt--;
}
- spin_unlock_irq(phba->host->host_lock);
- } while (found);
+ }
- /* Everything on txcmplq will be returned by firmware
- * with a no rpi / linkdown / abort error. For ring 0,
- * ELS discovery, we want to get rid of it right here.
- */
/* Next check the txcmplq */
- do {
- found = 0;
- spin_lock_irq(phba->host->host_lock);
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
- list) {
- /* Check to see if iocb matches the nport we are looking
- for */
- if ((lpfc_check_sli_ndlp (phba, pring, iocb, ndlp))) {
- found = 1;
- /* It matches, so deque and call compl with an
- error */
- list_del(&iocb->list);
- pring->txcmplq_cnt--;
-
- icmd = &iocb->iocb;
- /* If the driver is completing an ELS
- * command early, flush it out of the firmware.
- */
- if (send_abts &&
- (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) &&
- (icmd->un.elsreq64.bdl.ulpIoTag32)) {
- lpfc_sli_issue_abort_iotag32(phba,
- pring, iocb);
- }
- if (iocb->iocb_cmpl) {
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
- break;
- }
- }
- spin_unlock_irq(phba->host->host_lock);
- } while(found);
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
+ /* Check to see if iocb matches the nport we are looking
+ for */
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
+ spin_unlock_irq(phba->host->host_lock);
+
+ while (!list_empty(&completions)) {
+ iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ cmd = &iocb->iocb;
+ list_del(&iocb->list);
+
+ if (iocb->iocb_cmpl) {
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (iocb->iocb_cmpl) (phba, iocb, iocb);
+ } else
+ lpfc_sli_release_iocbq(phba, iocb);
+ }
/* If we are delaying issuing an ELS command, cancel it */
if (ndlp->nlp_flag & NLP_DELAY_TMO)
@@ -390,7 +353,10 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
* queue this mbox command to be processed later.
*/
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
- mbox->context2 = ndlp;
+ /*
+ * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
+ * command issued in lpfc_cmpl_els_acc().
+ */
ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
/*
@@ -404,7 +370,7 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
*/
if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
}
lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
@@ -471,8 +437,7 @@ lpfc_rcv_padisc(struct lpfc_hba * phba,
spin_unlock_irq(phba->host->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
return 0;
}
@@ -502,12 +467,10 @@ lpfc_rcv_logo(struct lpfc_hba * phba,
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
} else {
ndlp->nlp_prev_state = ndlp->nlp_state;
- ndlp->nlp_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
}
spin_lock_irq(phba->host->host_lock);
@@ -601,11 +564,10 @@ lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba,
if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
- ndlp->nlp_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
@@ -614,7 +576,7 @@ lpfc_rcv_els_unused_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
lpfc_issue_els_logo(phba, ndlp, 0);
- lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
@@ -630,7 +592,7 @@ lpfc_rcv_logo_unused_node(struct lpfc_hba * phba,
ndlp->nlp_flag |= NLP_LOGO_ACC;
spin_unlock_irq(phba->host->host_lock);
lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
- lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
@@ -639,7 +601,7 @@ static uint32_t
lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
@@ -647,7 +609,7 @@ static uint32_t
lpfc_device_rm_unused_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
@@ -697,7 +659,7 @@ lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
@@ -712,7 +674,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
if (evt == NLP_EVT_RCV_LOGO) {
lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
@@ -727,8 +689,7 @@ lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
spin_unlock_irq(phba->host->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state;
}
@@ -803,32 +764,26 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
goto out;
lpfc_unreg_rpi(phba, ndlp);
- if (lpfc_reg_login
- (phba, irsp->un.elsreq64.remoteID,
- (uint8_t *) sp, mbox, 0) == 0) {
+ if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
+ mbox, 0) == 0) {
switch (ndlp->nlp_DID) {
case NameServer_DID:
- mbox->mbox_cmpl =
- lpfc_mbx_cmpl_ns_reg_login;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
break;
case FDMI_DID:
- mbox->mbox_cmpl =
- lpfc_mbx_cmpl_fdmi_reg_login;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login;
break;
default:
- mbox->mbox_cmpl =
- lpfc_mbx_cmpl_reg_login;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
}
- mbox->context2 = ndlp;
+ mbox->context2 = lpfc_nlp_get(ndlp);
if (lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB))
!= MBX_NOT_FINISHED) {
- ndlp->nlp_state =
- NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_list(phba, ndlp,
- NLP_REGLOGIN_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
return ndlp->nlp_state;
}
+ lpfc_nlp_put(ndlp);
mp = (struct lpfc_dmabuf *)mbox->context1;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@@ -841,7 +796,7 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
out:
/* Free this node since the driver cannot login or has the wrong
sparm */
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
@@ -855,9 +810,9 @@ lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
}
else {
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -868,11 +823,10 @@ lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
uint32_t evt)
{
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
@@ -888,7 +842,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
struct lpfc_iocbq *cmdiocb;
/* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
cmdiocb = (struct lpfc_iocbq *) arg;
@@ -896,8 +850,7 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
return ndlp->nlp_state;
}
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
return ndlp->nlp_state;
@@ -926,7 +879,7 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
/* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp, 0);
+ lpfc_els_abort(phba, ndlp);
lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
@@ -987,20 +940,17 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
lpfc_unreg_rpi(phba, ndlp);
return ndlp->nlp_state;
}
if (ndlp->nlp_type & NLP_FCP_TARGET) {
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- ndlp->nlp_state = NLP_STE_MAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
} else {
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
}
return ndlp->nlp_state;
}
@@ -1016,9 +966,9 @@ lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
}
else {
/* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -1029,11 +979,10 @@ lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
uint32_t evt)
{
/* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
ndlp->nlp_flag |= NLP_NPR_ADISC;
@@ -1074,9 +1023,36 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
+ LPFC_MBOXQ_t *mb;
+ LPFC_MBOXQ_t *nextmb;
+ struct lpfc_dmabuf *mp;
cmdiocb = (struct lpfc_iocbq *) arg;
+ /* cleanup any ndlp on mbox q waiting for reglogin cmpl */
+ if ((mb = phba->sli.mbox_active)) {
+ if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+ (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ mb->context2 = NULL;
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ }
+ }
+
+ spin_lock_irq(phba->host->host_lock);
+ list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
+ if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+ (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ mp = (struct lpfc_dmabuf *) (mb->context1);
+ if (mp) {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ list_del(&mb->list);
+ mempool_free(mb, phba->mbox_mem_pool);
+ }
+ }
+ spin_unlock_irq(phba->host->host_lock);
+
lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
@@ -1133,8 +1109,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
*/
if (mb->mbxStatus == MBXERR_RPI_FULL) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
- ndlp->nlp_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
@@ -1147,8 +1122,7 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
lpfc_issue_els_logo(phba, ndlp, 0);
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state;
}
@@ -1157,13 +1131,11 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
/* Only if we are not a fabric nport do we issue PRLI */
if (!(ndlp->nlp_type & NLP_FABRIC)) {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- ndlp->nlp_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PRLI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
lpfc_issue_els_prli(phba, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
}
return ndlp->nlp_state;
}
@@ -1178,7 +1150,7 @@ lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
return ndlp->nlp_state;
}
else {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -1189,8 +1161,7 @@ lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
uint32_t evt)
{
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
@@ -1230,7 +1201,7 @@ lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
/* Software abort outstanding PRLI before sending acc */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
@@ -1279,8 +1250,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- ndlp->nlp_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state;
}
@@ -1298,8 +1268,7 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
}
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- ndlp->nlp_state = NLP_STE_MAPPED_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_MAPPED_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
return ndlp->nlp_state;
}
@@ -1330,9 +1299,9 @@ lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
}
else {
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -1359,11 +1328,10 @@ lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
/* software abort outstanding PRLI */
- lpfc_els_abort(phba, ndlp, 1);
+ lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
@@ -1436,8 +1404,7 @@ lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
{
ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
lpfc_disc_set_adisc(phba, ndlp);
@@ -1518,8 +1485,7 @@ lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
uint32_t evt)
{
ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
spin_unlock_irq(phba->host->host_lock);
@@ -1551,8 +1517,7 @@ lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba,
/* send PLOGI immediately, move to PLOGI issue state */
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
}
@@ -1580,16 +1545,13 @@ lpfc_rcv_prli_npr_node(struct lpfc_hba * phba,
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
spin_unlock_irq(phba->host->host_lock);
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
lpfc_issue_els_adisc(phba, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
}
-
}
return ndlp->nlp_state;
}
@@ -1627,13 +1589,11 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
!(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_ADISC_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
lpfc_issue_els_adisc(phba, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST);
+ lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
}
}
@@ -1682,7 +1642,7 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
@@ -1700,7 +1660,7 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
@@ -1728,7 +1688,7 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
@@ -1749,7 +1709,7 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
ndlp->nlp_rpi = mb->un.varWords[0];
else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -1765,7 +1725,7 @@ lpfc_device_rm_npr_node(struct lpfc_hba * phba,
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
return ndlp->nlp_state;
}
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ lpfc_drop_node(phba, ndlp);
return NLP_STE_FREED_NODE;
}
@@ -1964,7 +1924,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba,
uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
uint32_t);
- ndlp->nlp_disc_refcnt++;
+ lpfc_nlp_get(ndlp);
cur_state = ndlp->nlp_state;
/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
@@ -1987,18 +1947,7 @@ lpfc_disc_state_machine(struct lpfc_hba * phba,
phba->brd_no,
rc, ndlp->nlp_DID, ndlp->nlp_flag);
- ndlp->nlp_disc_refcnt--;
+ lpfc_nlp_put(ndlp);
- /* Check to see if ndlp removal is deferred */
- if ((ndlp->nlp_disc_refcnt == 0)
- && (ndlp->nlp_flag & NLP_DELAY_REMOVE)) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_DELAY_REMOVE;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_remove(phba, ndlp);
- return NLP_STE_FREED_NODE;
- }
- if (rc == NLP_STE_FREED_NODE)
- return NLP_STE_FREED_NODE;
return rc;
}
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index c3e68e0d8f7..9a12d05e99e 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -146,6 +146,10 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list);
+ if (lpfc_cmd) {
+ lpfc_cmd->seg_cnt = 0;
+ lpfc_cmd->nonsg_phys = 0;
+ }
spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag);
return lpfc_cmd;
}
@@ -288,13 +292,13 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
}
static void
-lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
+lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
{
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
- uint32_t fcpi_parm = lpfc_cmd->cur_iocbq.iocb.un.fcpi.fcpi_parm;
+ uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
uint32_t resp_info = fcprsp->rspStatus2;
uint32_t scsi_status = fcprsp->rspStatus3;
uint32_t *lp;
@@ -356,6 +360,24 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
/*
+ * If there is an under run check if under run reported by
+ * storage array is same as the under run reported by HBA.
+ * If this is not same, there is a dropped frame.
+ */
+ if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
+ fcpi_parm &&
+ (cmnd->resid != fcpi_parm)) {
+ lpfc_printf_log(phba, KERN_WARNING,
+ LOG_FCP | LOG_FCP_ERROR,
+ "%d:0735 FCP Read Check Error and Underrun "
+ "Data: x%x x%x x%x x%x\n", phba->brd_no,
+ be32_to_cpu(fcpcmd->fcpDl),
+ cmnd->resid,
+ fcpi_parm, cmnd->cmnd[0]);
+ cmnd->resid = cmnd->request_bufflen;
+ host_status = DID_ERROR;
+ }
+ /*
* The cmnd->underflow is the minimum number of bytes that must
* be transfered for this command. Provided a sense condition
* is not present, make sure the actual amount transferred is at
@@ -435,7 +457,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
switch (lpfc_cmd->status) {
case IOSTAT_FCP_RSP_ERROR:
/* Call FCP RSP handler to determine result */
- lpfc_handle_fcp_err(lpfc_cmd);
+ lpfc_handle_fcp_err(lpfc_cmd,pIocbOut);
break;
case IOSTAT_NPORT_BSY:
case IOSTAT_FABRIC_BSY:
@@ -466,10 +488,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
result = cmd->result;
sdev = cmd->device;
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
cmd->scsi_done(cmd);
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
- lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
return;
}
@@ -527,7 +549,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
}
- lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
@@ -670,6 +691,18 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
return (1);
}
+static void
+lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
+ struct lpfc_iocbq *cmdiocbq,
+ struct lpfc_iocbq *rspiocbq)
+{
+ struct lpfc_scsi_buf *lpfc_cmd =
+ (struct lpfc_scsi_buf *) cmdiocbq->context1;
+ if (lpfc_cmd)
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+ return;
+}
+
static int
lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
unsigned tgt_id, unsigned int lun,
@@ -706,8 +739,9 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
if (ret != IOCB_SUCCESS) {
+ if (ret == IOCB_TIMEDOUT)
+ iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
lpfc_cmd->status = IOSTAT_DRIVER_REJECT;
- ret = FAILED;
} else {
ret = SUCCESS;
lpfc_cmd->result = iocbqrsp->iocb.un.ulpWord[4];
@@ -974,7 +1008,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
}
static int
-lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
+lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -984,6 +1018,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
struct lpfc_nodelist *pnode = rdata->pnode;
uint32_t cmd_result = 0, cmd_status = 0;
int ret = FAILED;
+ int iocb_status = IOCB_SUCCESS;
int cnt, loopcnt;
lpfc_block_error_handler(cmnd);
@@ -995,7 +1030,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
*/
while ( 1 ) {
if (!pnode)
- return FAILED;
+ goto out;
if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
spin_unlock_irq(phba->host->host_lock);
@@ -1013,7 +1048,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
}
pnode = rdata->pnode;
if (!pnode)
- return FAILED;
+ goto out;
}
if (pnode->nlp_state == NLP_STE_MAPPED_NODE)
break;
@@ -1028,7 +1063,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
lpfc_cmd->rdata = rdata;
ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
- FCP_LUN_RESET);
+ FCP_TARGET_RESET);
if (!ret)
goto out_free_scsi_buf;
@@ -1040,16 +1075,21 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
goto out_free_scsi_buf;
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0703 Issue LUN Reset to TGT %d LUN %d "
- "Data: x%x x%x\n", phba->brd_no, cmnd->device->id,
+ "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
+ "nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
- ret = lpfc_sli_issue_iocb_wait(phba,
+ iocb_status = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
iocbq, iocbqrsp, lpfc_cmd->timeout);
- if (ret == IOCB_SUCCESS)
- ret = SUCCESS;
+ if (iocb_status == IOCB_TIMEDOUT)
+ iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl;
+
+ if (iocb_status == IOCB_SUCCESS)
+ ret = SUCCESS;
+ else
+ ret = iocb_status;
cmd_result = iocbqrsp->iocb.un.ulpWord[4];
cmd_status = iocbqrsp->iocb.ulpStatus;
@@ -1087,18 +1127,19 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0719 LUN Reset I/O flush failure: cnt x%x\n",
+ "%d:0719 device reset I/O flush failure: cnt x%x\n",
phba->brd_no, cnt);
ret = FAILED;
}
out_free_scsi_buf:
- lpfc_release_scsi_buf(phba, lpfc_cmd);
-
+ if (iocb_status != IOCB_TIMEDOUT) {
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+ }
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0713 SCSI layer issued LUN reset (%d, %d) "
- "Data: x%x x%x x%x\n",
- phba->brd_no, cmnd->device->id,cmnd->device->lun,
+ "%d:0713 SCSI layer issued device reset (%d, %d) "
+ "return x%x status x%x result x%x\n",
+ phba->brd_no, cmnd->device->id, cmnd->device->lun,
ret, cmd_status, cmd_result);
out:
@@ -1107,7 +1148,7 @@ out:
}
static int
-lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
+lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
{
struct Scsi_Host *shost = cmnd->device->host;
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
@@ -1134,10 +1175,12 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
* fail, this routine returns failure to the midlayer.
*/
for (i = 0; i < LPFC_MAX_TARGET; i++) {
- /* Search the mapped list for this target ID */
+ /* Search for mapped node by target ID */
match = 0;
- list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
- if ((i == ndlp->nlp_sid) && ndlp->rport) {
+ list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
+ i == ndlp->nlp_sid &&
+ ndlp->rport) {
match = 1;
break;
}
@@ -1152,13 +1195,17 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
"%d:0700 Bus Reset on target %d failed\n",
phba->brd_no, i);
err_count++;
+ break;
}
}
+ if (ret != IOCB_TIMEDOUT)
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+
if (err_count == 0)
ret = SUCCESS;
-
- lpfc_release_scsi_buf(phba, lpfc_cmd);
+ else
+ ret = FAILED;
/*
* All outstanding txcmplq I/Os should have been aborted by
@@ -1299,11 +1346,13 @@ struct scsi_host_template lpfc_template = {
.info = lpfc_info,
.queuecommand = lpfc_queuecommand,
.eh_abort_handler = lpfc_abort_handler,
- .eh_device_reset_handler= lpfc_reset_lun_handler,
- .eh_bus_reset_handler = lpfc_reset_bus_handler,
+ .eh_device_reset_handler= lpfc_device_reset_handler,
+ .eh_bus_reset_handler = lpfc_bus_reset_handler,
.slave_alloc = lpfc_slave_alloc,
.slave_configure = lpfc_slave_configure,
.slave_destroy = lpfc_slave_destroy,
+ .scan_finished = lpfc_scan_finished,
+ .scan_start = lpfc_scan_start,
.this_id = -1,
.sg_tablesize = LPFC_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN,
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 9fb6960a8ad..a1e721459e2 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -528,6 +528,7 @@ lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
* If pdone_q is empty, the driver thread gave up waiting and
* continued running.
*/
+ pmboxq->mbox_flag |= LPFC_MBX_WAKE;
pdone_q = (wait_queue_head_t *) pmboxq->context1;
if (pdone_q)
wake_up_interruptible(pdone_q);
@@ -538,11 +539,32 @@ void
lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
struct lpfc_dmabuf *mp;
+ uint16_t rpi;
+ int rc;
+
mp = (struct lpfc_dmabuf *) (pmb->context1);
+
if (mp) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
+
+ /*
+ * If a REG_LOGIN succeeded after node is destroyed or node
+ * is in re-discovery driver need to cleanup the RPI.
+ */
+ if (!(phba->fc_flag & FC_UNLOADING) &&
+ (pmb->mb.mbxCommand == MBX_REG_LOGIN64) &&
+ (!pmb->mb.mbxStatus)) {
+
+ rpi = pmb->mb.un.varWords[0];
+ lpfc_unreg_login(phba, rpi, pmb);
+ pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc != MBX_NOT_FINISHED)
+ return;
+ }
+
mempool_free( pmb, phba->mbox_mem_pool);
return;
}
@@ -693,25 +715,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
} else {
spin_unlock_irq(phba->host->host_lock);
/* Turn on IOCB processing */
- for (i = 0; i < phba->sli.num_rings; i++) {
+ for (i = 0; i < phba->sli.num_rings; i++)
lpfc_sli_turn_on_ring(phba, i);
- }
-
- /* Free any lpfc_dmabuf's waiting for mbox cmd cmpls */
- while (!list_empty(&phba->freebufList)) {
- struct lpfc_dmabuf *mp;
-
- mp = NULL;
- list_remove_head((&phba->freebufList),
- mp,
- struct lpfc_dmabuf,
- list);
- if (mp) {
- lpfc_mbuf_free(phba, mp->virt,
- mp->phys);
- kfree(mp);
- }
- }
}
} while (process_next);
@@ -833,6 +838,14 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
* All other are passed to the completion callback.
*/
if (pring->ringno == LPFC_ELS_RING) {
+ if (cmdiocbp->iocb_flag & LPFC_DRIVER_ABORTED) {
+ cmdiocbp->iocb_flag &=
+ ~LPFC_DRIVER_ABORTED;
+ saveq->iocb.ulpStatus =
+ IOSTAT_LOCAL_REJECT;
+ saveq->iocb.un.ulpWord[4] =
+ IOERR_SLI_ABORTED;
+ }
spin_unlock_irqrestore(phba->host->host_lock,
iflag);
(cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
@@ -1464,8 +1477,9 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
int
lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
+ LIST_HEAD(completions);
struct lpfc_iocbq *iocb, *next_iocb;
- IOCB_t *icmd = NULL, *cmd = NULL;
+ IOCB_t *cmd = NULL;
int errcnt;
errcnt = 0;
@@ -1474,46 +1488,28 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
* First do the txq.
*/
spin_lock_irq(phba->host->host_lock);
- list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
- icmd = &iocb->iocb;
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
- }
+ list_splice_init(&pring->txq, &completions);
pring->txq_cnt = 0;
- INIT_LIST_HEAD(&(pring->txq));
/* Next issue ABTS for everything on the txcmplq */
- list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- cmd = &iocb->iocb;
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
- /*
- * Imediate abort of IOCB, deque and call compl
- */
+ spin_unlock_irq(phba->host->host_lock);
- list_del_init(&iocb->list);
- pring->txcmplq_cnt--;
+ while (!list_empty(&completions)) {
+ iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ cmd = &iocb->iocb;
+ list_del(&iocb->list);
if (iocb->iocb_cmpl) {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
(iocb->iocb_cmpl) (phba, iocb, iocb);
- spin_lock_irq(phba->host->host_lock);
} else
lpfc_sli_release_iocbq(phba, iocb);
}
- INIT_LIST_HEAD(&pring->txcmplq);
- pring->txcmplq_cnt = 0;
- spin_unlock_irq(phba->host->host_lock);
-
return errcnt;
}
@@ -1588,6 +1584,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
hc_copy = readl(phba->HCregaddr);
writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
+ phba->fc_flag |= FC_IGNORE_ERATT;
if (readl(phba->HAregaddr) & HA_ERATT) {
/* Clear Chip error bit */
@@ -1630,6 +1627,7 @@ clear_errat:
}
restore_hc:
+ phba->fc_flag &= ~FC_IGNORE_ERATT;
writel(hc_copy, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
@@ -1665,6 +1663,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
status &= ~HC_ERINT_ENA;
writel(status, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
+ phba->fc_flag |= FC_IGNORE_ERATT;
spin_unlock_irq(phba->host->host_lock);
lpfc_kill_board(phba, pmb);
@@ -1674,6 +1673,9 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
if (retval != MBX_SUCCESS) {
if (retval != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
+ spin_lock_irq(phba->host->host_lock);
+ phba->fc_flag &= ~FC_IGNORE_ERATT;
+ spin_unlock_irq(phba->host->host_lock);
return 1;
}
@@ -1700,6 +1702,7 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
}
spin_lock_irq(phba->host->host_lock);
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+ phba->fc_flag &= ~FC_IGNORE_ERATT;
spin_unlock_irq(phba->host->host_lock);
psli->mbox_active = NULL;
@@ -1985,42 +1988,6 @@ lpfc_sli_hba_setup_exit:
return rc;
}
-static void
-lpfc_mbox_abort(struct lpfc_hba * phba)
-{
- LPFC_MBOXQ_t *pmbox;
- MAILBOX_t *mb;
-
- if (phba->sli.mbox_active) {
- del_timer_sync(&phba->sli.mbox_tmo);
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
- pmbox = phba->sli.mbox_active;
- mb = &pmbox->mb;
- phba->sli.mbox_active = NULL;
- if (pmbox->mbox_cmpl) {
- mb->mbxStatus = MBX_NOT_FINISHED;
- (pmbox->mbox_cmpl) (phba, pmbox);
- }
- phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- }
-
- /* Abort all the non active mailbox commands. */
- spin_lock_irq(phba->host->host_lock);
- pmbox = lpfc_mbox_get(phba);
- while (pmbox) {
- mb = &pmbox->mb;
- if (pmbox->mbox_cmpl) {
- mb->mbxStatus = MBX_NOT_FINISHED;
- spin_unlock_irq(phba->host->host_lock);
- (pmbox->mbox_cmpl) (phba, pmbox);
- spin_lock_irq(phba->host->host_lock);
- }
- pmbox = lpfc_mbox_get(phba);
- }
- spin_unlock_irq(phba->host->host_lock);
- return;
-}
-
/*! lpfc_mbox_timeout
*
* \pre
@@ -2055,6 +2022,8 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *pmbox;
MAILBOX_t *mb;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
spin_lock_irq(phba->host->host_lock);
if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
@@ -2062,8 +2031,6 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
return;
}
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
-
pmbox = phba->sli.mbox_active;
mb = &pmbox->mb;
@@ -2078,17 +2045,32 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
phba->sli.sli_flag,
phba->sli.mbox_active);
- phba->sli.mbox_active = NULL;
- if (pmbox->mbox_cmpl) {
- mb->mbxStatus = MBX_NOT_FINISHED;
- spin_unlock_irq(phba->host->host_lock);
- (pmbox->mbox_cmpl) (phba, pmbox);
- spin_lock_irq(phba->host->host_lock);
- }
- phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-
+ /* Setting state unknown so lpfc_sli_abort_iocb_ring
+ * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
+ * it to fail all oustanding SCSI IO.
+ */
+ phba->hba_state = LPFC_STATE_UNKNOWN;
+ phba->work_hba_events &= ~WORKER_MBOX_TMO;
+ phba->fc_flag |= FC_ESTABLISH_LINK;
+ psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
spin_unlock_irq(phba->host->host_lock);
- lpfc_mbox_abort(phba);
+
+ pring = &psli->ring[psli->fcp_ring];
+ lpfc_sli_abort_iocb_ring(phba, pring);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "%d:0316 Resetting board due to mailbox timeout\n",
+ phba->brd_no);
+ /*
+ * lpfc_offline calls lpfc_sli_hba_down which will clean up
+ * on oustanding mailbox commands.
+ */
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ lpfc_sli_brdrestart(phba);
+ if (lpfc_online(phba) == 0) /* Initialize the HBA */
+ mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
+ lpfc_unblock_mgmt_io(phba);
return;
}
@@ -2320,9 +2302,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
spin_unlock_irqrestore(phba->host->host_lock,
drvr_flag);
- /* Can be in interrupt context, do not sleep */
- /* (or might be called with interrupts disabled) */
- mdelay(1);
+ msleep(1);
spin_lock_irqsave(phba->host->host_lock, drvr_flag);
@@ -2430,7 +2410,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
/*
- * Only CREATE_XRI, CLOSE_XRI, ABORT_XRI, and QUE_RING_BUF
+ * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
* can be issued if the link is not up.
*/
switch (piocb->iocb.ulpCommand) {
@@ -2444,6 +2424,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
piocb->iocb_cmpl = NULL;
/*FALLTHROUGH*/
case CMD_CREATE_XRI_CR:
+ case CMD_CLOSE_XRI_CN:
+ case CMD_CLOSE_XRI_CX:
break;
default:
goto iocb_busy;
@@ -2637,11 +2619,12 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
int
lpfc_sli_hba_down(struct lpfc_hba * phba)
{
+ LIST_HEAD(completions);
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
LPFC_MBOXQ_t *pmb;
- struct lpfc_iocbq *iocb, *next_iocb;
- IOCB_t *icmd = NULL;
+ struct lpfc_iocbq *iocb;
+ IOCB_t *cmd = NULL;
int i;
unsigned long flags = 0;
@@ -2649,7 +2632,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
lpfc_hba_down_prep(phba);
spin_lock_irqsave(phba->host->host_lock, flags);
-
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
pring->flag |= LPFC_DEFERRED_RING_EVENT;
@@ -2658,28 +2640,25 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
* Error everything on the txq since these iocbs have not been
* given to the FW yet.
*/
+ list_splice_init(&pring->txq, &completions);
pring->txq_cnt = 0;
- list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
- icmd = &iocb->iocb;
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] = IOERR_SLI_DOWN;
- spin_unlock_irqrestore(phba->host->host_lock,
- flags);
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- spin_lock_irqsave(phba->host->host_lock, flags);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
- }
+ }
+ spin_unlock_irqrestore(phba->host->host_lock, flags);
- INIT_LIST_HEAD(&(pring->txq));
+ while (!list_empty(&completions)) {
+ iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ cmd = &iocb->iocb;
+ list_del(&iocb->list);
+ if (iocb->iocb_cmpl) {
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
+ (iocb->iocb_cmpl) (phba, iocb, iocb);
+ } else
+ lpfc_sli_release_iocbq(phba, iocb);
}
- spin_unlock_irqrestore(phba->host->host_lock, flags);
-
/* Return any active mbox cmds */
del_timer_sync(&psli->mbox_tmo);
spin_lock_irqsave(phba->host->host_lock, flags);
@@ -2768,85 +2747,138 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
static void
-lpfc_sli_abort_elsreq_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+ struct lpfc_iocbq * rspiocb)
{
- struct lpfc_dmabuf *buf_ptr, *buf_ptr1;
- /* Free the resources associated with the ELS_REQUEST64 IOCB the driver
- * just aborted.
- * In this case, context2 = cmd, context2->next = rsp, context3 = bpl
- */
- if (cmdiocb->context2) {
- buf_ptr1 = (struct lpfc_dmabuf *) cmdiocb->context2;
-
- /* Free the response IOCB before completing the abort
- command. */
- buf_ptr = NULL;
- list_remove_head((&buf_ptr1->list), buf_ptr,
- struct lpfc_dmabuf, list);
- if (buf_ptr) {
- lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
- kfree(buf_ptr);
- }
- lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys);
- kfree(buf_ptr1);
- }
+ IOCB_t *irsp;
+ uint16_t abort_iotag, abort_context;
+ struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+
+ abort_iocb = NULL;
+ irsp = &rspiocb->iocb;
+
+ spin_lock_irq(phba->host->host_lock);
- if (cmdiocb->context3) {
- buf_ptr = (struct lpfc_dmabuf *) cmdiocb->context3;
- lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
- kfree(buf_ptr);
+ if (irsp->ulpStatus) {
+ abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
+ abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+
+ if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
+ abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "%d:0327 Cannot abort els iocb %p"
+ " with tag %x context %x\n",
+ phba->brd_no, abort_iocb,
+ abort_iotag, abort_context);
+
+ /*
+ * make sure we have the right iocbq before taking it
+ * off the txcmplq and try to call completion routine.
+ */
+ if (abort_iocb &&
+ abort_iocb->iocb.ulpContext == abort_context &&
+ abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
+ list_del(&abort_iocb->list);
+ pring->txcmplq_cnt--;
+
+ rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
+ if (rsp_ab_iocb == NULL)
+ lpfc_sli_release_iocbq(phba, abort_iocb);
+ else {
+ abort_iocb->iocb_flag &=
+ ~LPFC_DRIVER_ABORTED;
+ rsp_ab_iocb->iocb.ulpStatus =
+ IOSTAT_LOCAL_REJECT;
+ rsp_ab_iocb->iocb.un.ulpWord[4] =
+ IOERR_SLI_ABORTED;
+ spin_unlock_irq(phba->host->host_lock);
+ (abort_iocb->iocb_cmpl)
+ (phba, abort_iocb, rsp_ab_iocb);
+ spin_lock_irq(phba->host->host_lock);
+ lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
+ }
+ }
}
lpfc_sli_release_iocbq(phba, cmdiocb);
+ spin_unlock_irq(phba->host->host_lock);
return;
}
int
-lpfc_sli_issue_abort_iotag32(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * cmdiocb)
+lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
+ struct lpfc_sli_ring * pring,
+ struct lpfc_iocbq * cmdiocb)
{
struct lpfc_iocbq *abtsiocbp;
IOCB_t *icmd = NULL;
IOCB_t *iabt = NULL;
+ int retval = IOCB_ERROR;
+
+ /* There are certain command types we don't want
+ * to abort.
+ */
+ icmd = &cmdiocb->iocb;
+ if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
+ (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
+ return 0;
+
+ /* If we're unloading, interrupts are disabled so we
+ * need to cleanup the iocb here.
+ */
+ if (phba->fc_flag & FC_UNLOADING)
+ goto abort_iotag_exit;
/* issue ABTS for this IOCB based on iotag */
abtsiocbp = lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
return 0;
+ /* This signals the response to set the correct status
+ * before calling the completion handler.
+ */
+ cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED;
+
iabt = &abtsiocbp->iocb;
- icmd = &cmdiocb->iocb;
- switch (icmd->ulpCommand) {
- case CMD_ELS_REQUEST64_CR:
- /* Even though we abort the ELS command, the firmware may access
- * the BPL or other resources before it processes our
- * ABORT_MXRI64. Thus we must delay reusing the cmdiocb
- * resources till the actual abort request completes.
- */
- abtsiocbp->context1 = (void *)((unsigned long)icmd->ulpCommand);
- abtsiocbp->context2 = cmdiocb->context2;
- abtsiocbp->context3 = cmdiocb->context3;
- cmdiocb->context2 = NULL;
- cmdiocb->context3 = NULL;
- abtsiocbp->iocb_cmpl = lpfc_sli_abort_elsreq_cmpl;
- break;
- default:
- lpfc_sli_release_iocbq(phba, abtsiocbp);
- return 0;
- }
+ iabt->un.acxri.abortType = ABORT_TYPE_ABTS;
+ iabt->un.acxri.abortContextTag = icmd->ulpContext;
+ iabt->un.acxri.abortIoTag = icmd->ulpIoTag;
+ iabt->ulpLe = 1;
+ iabt->ulpClass = icmd->ulpClass;
- iabt->un.amxri.abortType = ABORT_TYPE_ABTS;
- iabt->un.amxri.iotag32 = icmd->un.elsreq64.bdl.ulpIoTag32;
+ if (phba->hba_state >= LPFC_LINK_UP)
+ iabt->ulpCommand = CMD_ABORT_XRI_CN;
+ else
+ iabt->ulpCommand = CMD_CLOSE_XRI_CN;
- iabt->ulpLe = 1;
- iabt->ulpClass = CLASS3;
- iabt->ulpCommand = CMD_ABORT_MXRI64_CN;
+ abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
- if (lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0) == IOCB_ERROR) {
- lpfc_sli_release_iocbq(phba, abtsiocbp);
- return 0;
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0339 Abort xri x%x, original iotag x%x, abort "
+ "cmd iotag x%x\n",
+ phba->brd_no, iabt->un.acxri.abortContextTag,
+ iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+ retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+
+abort_iotag_exit:
+
+ /* If we could not issue an abort dequeue the iocb and handle
+ * the completion here.
+ */
+ if (retval == IOCB_ERROR) {
+ list_del(&cmdiocb->list);
+ pring->txcmplq_cnt--;
+
+ if (cmdiocb->iocb_cmpl) {
+ icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ spin_unlock_irq(phba->host->host_lock);
+ (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
+ spin_lock_irq(phba->host->host_lock);
+ } else
+ lpfc_sli_release_iocbq(phba, cmdiocb);
}
return 1;
@@ -2918,9 +2950,11 @@ void
lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
struct lpfc_iocbq * rspiocb)
{
- spin_lock_irq(phba->host->host_lock);
+ unsigned long iflags;
+
+ spin_lock_irqsave(phba->host->host_lock, iflags);
lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irqrestore(phba->host->host_lock, iflags);
return;
}
@@ -3043,22 +3077,22 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
timeout_req);
spin_lock_irq(phba->host->host_lock);
- if (timeleft == 0) {
+ if (piocb->iocb_flag & LPFC_IO_WAKE) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0331 IOCB wake signaled\n",
+ phba->brd_no);
+ } else if (timeleft == 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"%d:0338 IOCB wait timeout error - no "
"wake response Data x%x\n",
phba->brd_no, timeout);
retval = IOCB_TIMEDOUT;
- } else if (!(piocb->iocb_flag & LPFC_IO_WAKE)) {
+ } else {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"%d:0330 IOCB wake NOT set, "
"Data x%x x%lx\n", phba->brd_no,
timeout, (timeleft / jiffies));
retval = IOCB_TIMEDOUT;
- } else {
- lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0331 IOCB wake signaled\n",
- phba->brd_no);
}
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3087,8 +3121,6 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
uint32_t timeout)
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
- DECLARE_WAITQUEUE(wq_entry, current);
- uint32_t timeleft = 0;
int retval;
/* The caller must leave context1 empty. */
@@ -3101,27 +3133,25 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
/* setup context field to pass wait_queue pointer to wake function */
pmboxq->context1 = &done_q;
- /* start to sleep before we wait, to avoid races */
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&done_q, &wq_entry);
-
/* now issue the command */
retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
if (retval == MBX_BUSY || retval == MBX_SUCCESS) {
- timeleft = schedule_timeout(timeout * HZ);
+ wait_event_interruptible_timeout(done_q,
+ pmboxq->mbox_flag & LPFC_MBX_WAKE,
+ timeout * HZ);
+
pmboxq->context1 = NULL;
- /* if schedule_timeout returns 0, we timed out and were not
- woken up */
- if ((timeleft == 0) || signal_pending(current))
- retval = MBX_TIMEOUT;
- else
+ /*
+ * if LPFC_MBX_WAKE flag is set the mailbox is completed
+ * else do not free the resources.
+ */
+ if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
retval = MBX_SUCCESS;
+ else
+ retval = MBX_TIMEOUT;
}
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&done_q, &wq_entry);
return retval;
}
@@ -3184,6 +3214,11 @@ lpfc_intr_handler(int irq, void *dev_id)
*/
spin_lock(phba->host->host_lock);
ha_copy = readl(phba->HAregaddr);
+ /* If somebody is waiting to handle an eratt don't process it
+ * here. The brdkill function will do this.
+ */
+ if (phba->fc_flag & FC_IGNORE_ERATT)
+ ha_copy &= ~HA_ERATT;
writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
spin_unlock(phba->host->host_lock);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index a43549959dc..41c38d324ab 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -39,9 +39,10 @@ struct lpfc_iocbq {
IOCB_t iocb; /* IOCB cmd */
uint8_t retry; /* retry counter for IOCB cmd - if needed */
uint8_t iocb_flag;
-#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
-#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
-#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
+#define LPFC_IO_LIBDFC 1 /* libdfc iocb */
+#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
+#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
+#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
uint8_t abort_count;
uint8_t rsvd2;
@@ -67,6 +68,8 @@ struct lpfc_iocbq {
#define IOCB_ERROR 2
#define IOCB_TIMEDOUT 3
+#define LPFC_MBX_WAKE 1
+
typedef struct lpfcMboxq {
/* MBOXQs are used in single linked lists */
struct list_head list; /* ptr to next mailbox command */
@@ -75,6 +78,7 @@ typedef struct lpfcMboxq {
void *context2; /* caller context information */
void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *);
+ uint8_t mbox_flag;
} LPFC_MBOXQ_t;
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index a61ef3d1e7f..92a9107019d 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2007 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -18,12 +18,12 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.1.11"
+#define LPFC_DRIVER_VERSION "8.1.12"
#define LPFC_DRIVER_NAME "lpfc"
#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
LPFC_DRIVER_VERSION
-#define LPFC_COPYRIGHT "Copyright(c) 2004-2006 Emulex. All rights reserved."
+#define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex. All rights reserved."
#define DFC_API_VERSION "0.0.0"
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 753d88306cd..5806ede120a 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -471,7 +471,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
goto out_free;
}
- clkprop = get_property(node, "clock-frequency", &proplen);
+ clkprop = of_get_property(node, "clock-frequency", &proplen);
if (clkprop == NULL || proplen != sizeof(int)) {
printk(KERN_ERR "%s: can't get clock frequency, "
"assuming 25MHz\n", node->full_name);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 0aa3304f6b9..3cce75d7026 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1754,7 +1754,8 @@ __mega_busywait_mbox (adapter_t *adapter)
for (counter = 0; counter < 10000; counter++) {
if (!mbox->m_in.busy)
return 0;
- udelay(100); yield();
+ udelay(100);
+ cond_resched();
}
return -1; /* give up after 1 second */
}
@@ -2088,7 +2089,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
static inline int
make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
{
- *pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ *pdev = alloc_pci_dev();
if( *pdev == NULL ) return -1;
@@ -3177,7 +3178,10 @@ proc_rdrv(adapter_t *adapter, char *page, int start, int end )
return len;
}
-
+#else
+static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+}
#endif
@@ -4342,7 +4346,7 @@ mega_support_cluster(adapter_t *adapter)
return 0;
}
-
+#ifdef CONFIG_PROC_FS
/**
* mega_adapinq()
* @adapter - pointer to our soft state
@@ -4447,7 +4451,7 @@ mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
return rval;
}
-
+#endif
/**
* mega_internal_command()
@@ -4965,7 +4969,6 @@ megaraid_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *host = pci_get_drvdata(pdev);
adapter_t *adapter = (adapter_t *)host->hostdata;
- char buf[12] = { 0 };
scsi_remove_host(host);
@@ -5011,8 +5014,11 @@ megaraid_remove_one(struct pci_dev *pdev)
remove_proc_entry("raiddrives-30-39",
adapter->controller_proc_dir_entry);
#endif
- sprintf(buf, "hba%d", adapter->host->host_no);
- remove_proc_entry(buf, mega_proc_dir_entry);
+ {
+ char buf[12] = { 0 };
+ sprintf(buf, "hba%d", adapter->host->host_no);
+ remove_proc_entry(buf, mega_proc_dir_entry);
+ }
}
#endif
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index c6e74643abe..ee70bd4ae4b 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -1002,7 +1002,6 @@ static int megaraid_reset(Scsi_Cmnd *);
static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
static int megaraid_biosparam(struct scsi_device *, struct block_device *,
sector_t, int []);
-static int mega_print_inquiry(char *, char *);
static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
u32 *buffer, u32 *length);
@@ -1024,6 +1023,7 @@ static int mega_init_scb (adapter_t *);
static int mega_is_bios_enabled (adapter_t *);
#ifdef CONFIG_PROC_FS
+static int mega_print_inquiry(char *, char *);
static void mega_create_proc_entry(int, struct proc_dir_entry *);
static int proc_read_config(char *, char **, off_t, int, int *, void *);
static int proc_read_stat(char *, char **, off_t, int, int *, void *);
@@ -1040,10 +1040,10 @@ static int proc_rdrv_20(char *, char **, off_t, int, int *, void *);
static int proc_rdrv_30(char *, char **, off_t, int, int *, void *);
static int proc_rdrv_40(char *, char **, off_t, int, int *, void *);
static int proc_rdrv(adapter_t *, char *, int, int);
-#endif
static int mega_adapinq(adapter_t *, dma_addr_t);
static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
+#endif
static int mega_support_ext_cdb(adapter_t *);
static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *,
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index f33a678f089..e075a52ac10 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -60,7 +60,7 @@ EXPORT_SYMBOL(mraid_mm_unregister_adp);
EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
static int majorno;
-static uint32_t drvr_ver = 0x02200206;
+static uint32_t drvr_ver = 0x02200207;
static int adapters_count_g;
static struct list_head adapters_list_g;
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 1fd3c7590d3..e64d1a19d8d 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -185,7 +185,7 @@ struct mesh_state {
* Driver is too messy, we need a few prototypes...
*/
static void mesh_done(struct mesh_state *ms, int start_next);
-static void mesh_interrupt(int irq, void *dev_id);
+static void mesh_interrupt(struct mesh_state *ms);
static void cmd_complete(struct mesh_state *ms);
static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
static void halt_dma(struct mesh_state *ms);
@@ -466,7 +466,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
MKWORD(mr->interrupt, mr->exception,
mr->error, mr->fifo_count));
- mesh_interrupt(0, (void *)ms);
+ mesh_interrupt(ms);
if (ms->phase != arbitrating)
return;
}
@@ -504,7 +504,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
MKWORD(mr->interrupt, mr->exception,
mr->error, mr->fifo_count));
- mesh_interrupt(0, (void *)ms);
+ mesh_interrupt(ms);
if (ms->phase != arbitrating)
return;
dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -1018,10 +1018,11 @@ static void handle_reset(struct mesh_state *ms)
static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
{
unsigned long flags;
- struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
+ struct mesh_state *ms = dev_id;
+ struct Scsi_Host *dev = ms->host;
spin_lock_irqsave(dev->host_lock, flags);
- mesh_interrupt(irq, dev_id);
+ mesh_interrupt(ms);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
@@ -1661,9 +1662,8 @@ static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* handler (do_mesh_interrupt) or by other functions in
* exceptional circumstances
*/
-static void mesh_interrupt(int irq, void *dev_id)
+static void mesh_interrupt(struct mesh_state *ms)
{
- struct mesh_state *ms = (struct mesh_state *) dev_id;
volatile struct mesh_regs __iomem *mr = ms->mesh;
int intr;
@@ -1947,7 +1947,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
ms->tgts[tgt].current_req = NULL;
}
- if ((cfp = get_property(mesh, "clock-frequency", NULL)))
+ if ((cfp = of_get_property(mesh, "clock-frequency", NULL)))
ms->clk_freq = *cfp;
else {
printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index a967fadb743..08060fb478b 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -87,6 +87,7 @@ MODULE_AUTHOR("Willem Riede");
MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
module_param(max_dev, int, 0444);
MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
deleted file mode 100644
index 0ebd8ce9e1d..00000000000
--- a/drivers/scsi/pci2000.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/****************************************************************************
- * Perceptive Solutions, Inc. PCI-2000 device driver for Linux.
- *
- * pci2000.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters
- *
- * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * Technical updates and product information at:
- * http://www.psidisk.com
- *
- * Please send questions, comments, bug reports to:
- * tech@psidisk.com Technical Support
- *
- ****************************************************************************/
-#ifndef _PCI2000_H
-#define _PCI2000_H
-
-#include <linux/types.h>
-
-#ifndef PSI_EIDE_SCSIOP
-#define PSI_EIDE_SCSIOP 1
-
-#define LINUXVERSION(v,p,s) (((v)<<16) + ((p)<<8) + (s))
-
-/************************************************/
-/* definition of standard data types */
-/************************************************/
-#define CHAR char
-#define UCHAR unsigned char
-#define SHORT short
-#define USHORT unsigned short
-#define BOOL long
-#define LONG long
-#define ULONG unsigned long
-#define VOID void
-
-typedef CHAR *PCHAR;
-typedef UCHAR *PUCHAR;
-typedef SHORT *PSHORT;
-typedef USHORT *PUSHORT;
-typedef BOOL *PBOOL;
-typedef LONG *PLONG;
-typedef ULONG *PULONG;
-typedef VOID *PVOID;
-
-
-/************************************************/
-/* Misc. macros */
-/************************************************/
-#define ANY2SCSI(up, p) \
-((UCHAR *)up)[0] = (((ULONG)(p)) >> 8); \
-((UCHAR *)up)[1] = ((ULONG)(p));
-
-#define SCSI2LONG(up) \
-( (((long)*(((UCHAR *)up))) << 16) \
-+ (((long)(((UCHAR *)up)[1])) << 8) \
-+ ((long)(((UCHAR *)up)[2])) )
-
-#define XANY2SCSI(up, p) \
-((UCHAR *)up)[0] = ((long)(p)) >> 24; \
-((UCHAR *)up)[1] = ((long)(p)) >> 16; \
-((UCHAR *)up)[2] = ((long)(p)) >> 8; \
-((UCHAR *)up)[3] = ((long)(p));
-
-#define XSCSI2LONG(up) \
-( (((long)(((UCHAR *)up)[0])) << 24) \
-+ (((long)(((UCHAR *)up)[1])) << 16) \
-+ (((long)(((UCHAR *)up)[2])) << 8) \
-+ ((long)(((UCHAR *)up)[3])) )
-
-/************************************************/
-/* SCSI CDB operation codes */
-/************************************************/
-#define SCSIOP_TEST_UNIT_READY 0x00
-#define SCSIOP_REZERO_UNIT 0x01
-#define SCSIOP_REWIND 0x01
-#define SCSIOP_REQUEST_BLOCK_ADDR 0x02
-#define SCSIOP_REQUEST_SENSE 0x03
-#define SCSIOP_FORMAT_UNIT 0x04
-#define SCSIOP_READ_BLOCK_LIMITS 0x05
-#define SCSIOP_REASSIGN_BLOCKS 0x07
-#define SCSIOP_READ6 0x08
-#define SCSIOP_RECEIVE 0x08
-#define SCSIOP_WRITE6 0x0A
-#define SCSIOP_PRINT 0x0A
-#define SCSIOP_SEND 0x0A
-#define SCSIOP_SEEK6 0x0B
-#define SCSIOP_TRACK_SELECT 0x0B
-#define SCSIOP_SLEW_PRINT 0x0B
-#define SCSIOP_SEEK_BLOCK 0x0C
-#define SCSIOP_PARTITION 0x0D
-#define SCSIOP_READ_REVERSE 0x0F
-#define SCSIOP_WRITE_FILEMARKS 0x10
-#define SCSIOP_FLUSH_BUFFER 0x10
-#define SCSIOP_SPACE 0x11
-#define SCSIOP_INQUIRY 0x12
-#define SCSIOP_VERIFY6 0x13
-#define SCSIOP_RECOVER_BUF_DATA 0x14
-#define SCSIOP_MODE_SELECT 0x15
-#define SCSIOP_RESERVE_UNIT 0x16
-#define SCSIOP_RELEASE_UNIT 0x17
-#define SCSIOP_COPY 0x18
-#define SCSIOP_ERASE 0x19
-#define SCSIOP_MODE_SENSE 0x1A
-#define SCSIOP_START_STOP_UNIT 0x1B
-#define SCSIOP_STOP_PRINT 0x1B
-#define SCSIOP_LOAD_UNLOAD 0x1B
-#define SCSIOP_RECEIVE_DIAGNOSTIC 0x1C
-#define SCSIOP_SEND_DIAGNOSTIC 0x1D
-#define SCSIOP_MEDIUM_REMOVAL 0x1E
-#define SCSIOP_READ_CAPACITY 0x25
-#define SCSIOP_READ 0x28
-#define SCSIOP_WRITE 0x2A
-#define SCSIOP_SEEK 0x2B
-#define SCSIOP_LOCATE 0x2B
-#define SCSIOP_WRITE_VERIFY 0x2E
-#define SCSIOP_VERIFY 0x2F
-#define SCSIOP_SEARCH_DATA_HIGH 0x30
-#define SCSIOP_SEARCH_DATA_EQUAL 0x31
-#define SCSIOP_SEARCH_DATA_LOW 0x32
-#define SCSIOP_SET_LIMITS 0x33
-#define SCSIOP_READ_POSITION 0x34
-#define SCSIOP_SYNCHRONIZE_CACHE 0x35
-#define SCSIOP_COMPARE 0x39
-#define SCSIOP_COPY_COMPARE 0x3A
-#define SCSIOP_WRITE_DATA_BUFF 0x3B
-#define SCSIOP_READ_DATA_BUFF 0x3C
-#define SCSIOP_CHANGE_DEFINITION 0x40
-#define SCSIOP_READ_SUB_CHANNEL 0x42
-#define SCSIOP_READ_TOC 0x43
-#define SCSIOP_READ_HEADER 0x44
-#define SCSIOP_PLAY_AUDIO 0x45
-#define SCSIOP_PLAY_AUDIO_MSF 0x47
-#define SCSIOP_PLAY_TRACK_INDEX 0x48
-#define SCSIOP_PLAY_TRACK_RELATIVE 0x49
-#define SCSIOP_PAUSE_RESUME 0x4B
-#define SCSIOP_LOG_SELECT 0x4C
-#define SCSIOP_LOG_SENSE 0x4D
-#define SCSIOP_MODE_SELECT10 0x55
-#define SCSIOP_MODE_SENSE10 0x5A
-#define SCSIOP_LOAD_UNLOAD_SLOT 0xA6
-#define SCSIOP_MECHANISM_STATUS 0xBD
-#define SCSIOP_READ_CD 0xBE
-
-// SCSI read capacity structure
-typedef struct _READ_CAPACITY_DATA
- {
- ULONG blks; /* total blocks (converted to little endian) */
- ULONG blksiz; /* size of each (converted to little endian) */
- } READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
-
-// SCSI inquiry data
-typedef struct _INQUIRYDATA
- {
- UCHAR DeviceType :5;
- UCHAR DeviceTypeQualifier :3;
- UCHAR DeviceTypeModifier :7;
- UCHAR RemovableMedia :1;
- UCHAR Versions;
- UCHAR ResponseDataFormat;
- UCHAR AdditionalLength;
- UCHAR Reserved[2];
- UCHAR SoftReset :1;
- UCHAR CommandQueue :1;
- UCHAR Reserved2 :1;
- UCHAR LinkedCommands :1;
- UCHAR Synchronous :1;
- UCHAR Wide16Bit :1;
- UCHAR Wide32Bit :1;
- UCHAR RelativeAddressing :1;
- UCHAR VendorId[8];
- UCHAR ProductId[16];
- UCHAR ProductRevisionLevel[4];
- UCHAR VendorSpecific[20];
- UCHAR Reserved3[40];
- } INQUIRYDATA, *PINQUIRYDATA;
-
-#endif
-
-// function prototypes
-int Pci2000_Detect (struct scsi_host_template *tpnt);
-int Pci2000_Command (Scsi_Cmnd *SCpnt);
-int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-int Pci2000_Abort (Scsi_Cmnd *SCpnt);
-int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags);
-int Pci2000_Release (struct Scsi_Host *pshost);
-int Pci2000_BiosParam (struct scsi_device *sdev,
- struct block_device *bdev,
- sector_t capacity, int geom[]);
-
-#endif
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index eac8e179cff..7dd787f6ab2 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -3,11 +3,11 @@
#
menu "PCMCIA SCSI adapter support"
- depends on SCSI!=n && PCMCIA!=n && MODULES
+ depends on SCSI!=n && PCMCIA!=n
config PCMCIA_AHA152X
tristate "Adaptec AHA152X PCMCIA support"
- depends on m && !64BIT
+ depends on !64BIT
select SCSI_SPI_ATTRS
help
Say Y here if you intend to attach this type of PCMCIA SCSI host
@@ -18,7 +18,6 @@ config PCMCIA_AHA152X
config PCMCIA_FDOMAIN
tristate "Future Domain PCMCIA support"
- depends on m
help
Say Y here if you intend to attach this type of PCMCIA SCSI host
adapter to your computer.
@@ -28,7 +27,7 @@ config PCMCIA_FDOMAIN
config PCMCIA_NINJA_SCSI
tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
- depends on m && !64BIT
+ depends on !64BIT
help
If you intend to attach this type of PCMCIA SCSI host adapter to
your computer, say Y here and read
@@ -62,7 +61,6 @@ config PCMCIA_NINJA_SCSI
config PCMCIA_QLOGIC
tristate "Qlogic PCMCIA support"
- depends on m
help
Say Y here if you intend to attach this type of PCMCIA SCSI host
adapter to your computer.
@@ -72,7 +70,6 @@ config PCMCIA_QLOGIC
config PCMCIA_SYM53C500
tristate "Symbios 53c500 PCMCIA support"
- depends on m
help
Say Y here if you have a New Media Bus Toaster or other PCMCIA
SCSI adapter based on the Symbios 53c500 controller.
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 6777e8a6915..54d8bdf8685 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -4293,7 +4293,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->devnum = devnum; /* specifies microcode load address */
#ifdef QLA_64BIT_PTR
- if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
+ if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
if (pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "scsi(%li): Unable to set a "
"suitable DMA mask - aborting\n", ha->host_no);
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 05f4f2a378e..e8948b679f5 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1478,14 +1478,17 @@ typedef union {
uint32_t b24 : 24;
struct {
- uint8_t d_id[3];
- uint8_t rsvd_1;
- } r;
-
- struct {
+#ifdef __BIG_ENDIAN
+ uint8_t domain;
+ uint8_t area;
+ uint8_t al_pa;
+#elif __LITTLE_ENDIAN
uint8_t al_pa;
uint8_t area;
uint8_t domain;
+#else
+#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined!"
+#endif
uint8_t rsvd_1;
} b;
} port_id_t;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 98c01cd5e1a..2a45aec4ff2 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -11,6 +11,10 @@
#include "qla_devtbl.h"
+#ifdef CONFIG_SPARC
+#include <asm/prom.h>
+#endif
+
/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
#ifndef EXT_IS_LUN_BIT_SET
#define EXT_IS_LUN_BIT_SET(P,L) \
@@ -88,12 +92,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
- rval = ha->isp_ops.nvram_config(ha);
- if (rval) {
- DEBUG2(printk("scsi(%ld): Unable to verify NVRAM data.\n",
- ha->host_no));
- return rval;
- }
+ ha->isp_ops.nvram_config(ha);
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
@@ -130,18 +129,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
int
qla2100_pci_config(scsi_qla_host_t *ha)
{
- uint16_t w, mwi;
+ int ret;
+ uint16_t w;
uint32_t d;
unsigned long flags;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ ret = pci_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
/* Reset expansion ROM address decode enable */
@@ -166,22 +164,22 @@ qla2100_pci_config(scsi_qla_host_t *ha)
int
qla2300_pci_config(scsi_qla_host_t *ha)
{
- uint16_t w, mwi;
+ int ret;
+ uint16_t w;
uint32_t d;
unsigned long flags = 0;
uint32_t cnt;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ ret = pci_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
if (IS_QLA2322(ha) || IS_QLA6322(ha))
w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
/*
* If this is a 2300 card and not 2312, reset the
@@ -210,7 +208,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
ha->fb_rev = RD_FB_CMD_REG(ha, reg);
if (ha->fb_rev == FPM_2300)
- w &= ~PCI_COMMAND_INVALIDATE;
+ pci_clear_mwi(ha->pdev);
/* Deselect FPM registers. */
WRT_REG_WORD(&reg->ctrl_status, 0x0);
@@ -227,7 +225,6 @@ qla2300_pci_config(scsi_qla_host_t *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
- pci_write_config_word(ha->pdev, PCI_COMMAND, w);
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
@@ -253,19 +250,18 @@ qla2300_pci_config(scsi_qla_host_t *ha)
int
qla24xx_pci_config(scsi_qla_host_t *ha)
{
- uint16_t w, mwi;
+ int ret;
+ uint16_t w;
uint32_t d;
unsigned long flags = 0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
int pcix_cmd_reg, pcie_dctl_reg;
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ ret = pci_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
@@ -1393,6 +1389,27 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
}
}
+/* On sparc systems, obtain port and node WWN from firmware
+ * properties.
+ */
+static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv)
+{
+#ifdef CONFIG_SPARC
+ struct pci_dev *pdev = ha->pdev;
+ struct device_node *dp = pci_device_to_OF_node(pdev);
+ const u8 *val;
+ int len;
+
+ val = of_get_property(dp, "port-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->port_name, val, WWN_SIZE);
+
+ val = of_get_property(dp, "node-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->node_name, val, WWN_SIZE);
+#endif
+}
+
/*
* NVRAM configuration for ISP 2xxx
*
@@ -1409,6 +1426,7 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de
int
qla2x00_nvram_config(scsi_qla_host_t *ha)
{
+ int rval;
uint8_t chksum = 0;
uint16_t cnt;
uint8_t *dptr1, *dptr2;
@@ -1417,6 +1435,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
uint8_t *ptr = (uint8_t *)ha->request_ring;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+ rval = QLA_SUCCESS;
+
/* Determine NVRAM starting address. */
ha->nvram_size = sizeof(nvram_t);
ha->nvram_base = 0;
@@ -1440,7 +1460,57 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
nv->nvram_version);
- return QLA_FUNCTION_FAILED;
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\n");
+
+ /*
+ * Set default initialization control block.
+ */
+ memset(nv, 0, ha->nvram_size);
+ nv->parameter_block_version = ICB_VERSION;
+
+ if (IS_QLA23XX(ha)) {
+ nv->firmware_options[0] = BIT_2 | BIT_1;
+ nv->firmware_options[1] = BIT_7 | BIT_5;
+ nv->add_firmware_options[0] = BIT_5;
+ nv->add_firmware_options[1] = BIT_5 | BIT_4;
+ nv->frame_payload_size = __constant_cpu_to_le16(2048);
+ nv->special_options[1] = BIT_7;
+ } else if (IS_QLA2200(ha)) {
+ nv->firmware_options[0] = BIT_2 | BIT_1;
+ nv->firmware_options[1] = BIT_7 | BIT_5;
+ nv->add_firmware_options[0] = BIT_5;
+ nv->add_firmware_options[1] = BIT_5 | BIT_4;
+ nv->frame_payload_size = __constant_cpu_to_le16(1024);
+ } else if (IS_QLA2100(ha)) {
+ nv->firmware_options[0] = BIT_3 | BIT_1;
+ nv->firmware_options[1] = BIT_5;
+ nv->frame_payload_size = __constant_cpu_to_le16(1024);
+ }
+
+ nv->max_iocb_allocation = __constant_cpu_to_le16(256);
+ nv->execution_throttle = __constant_cpu_to_le16(16);
+ nv->retry_count = 8;
+ nv->retry_delay = 1;
+
+ nv->port_name[0] = 33;
+ nv->port_name[3] = 224;
+ nv->port_name[4] = 139;
+
+ qla2xxx_nvram_wwn_from_ofw(ha, nv);
+
+ nv->login_timeout = 4;
+
+ /*
+ * Set default host adapter parameters
+ */
+ nv->host_p[1] = BIT_2;
+ nv->reset_delay = 5;
+ nv->port_down_retry_count = 8;
+ nv->max_luns_per_target = __constant_cpu_to_le16(8);
+ nv->link_down_timeout = 60;
+
+ rval = 1;
}
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
@@ -1653,7 +1723,11 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
}
}
- return QLA_SUCCESS;
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+ }
+ return (rval);
}
static void
@@ -3071,9 +3145,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->isp_ops.get_flash_version(ha, ha->request_ring);
- rval = ha->isp_ops.nvram_config(ha);
- if (rval)
- goto isp_abort_retry;
+ ha->isp_ops.nvram_config(ha);
if (!qla2x00_restart_isp(ha)) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3103,7 +3175,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
}
}
} else { /* failed the ISP abort */
-isp_abort_retry:
ha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
if (ha->isp_abort_cnt == 0) {
@@ -3290,9 +3361,31 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
+/* On sparc systems, obtain port and node WWN from firmware
+ * properties.
+ */
+static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *nv)
+{
+#ifdef CONFIG_SPARC
+ struct pci_dev *pdev = ha->pdev;
+ struct device_node *dp = pci_device_to_OF_node(pdev);
+ const u8 *val;
+ int len;
+
+ val = of_get_property(dp, "port-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->port_name, val, WWN_SIZE);
+
+ val = of_get_property(dp, "node-wwn", &len);
+ if (val && len >= WWN_SIZE)
+ memcpy(nv->node_name, val, WWN_SIZE);
+#endif
+}
+
int
qla24xx_nvram_config(scsi_qla_host_t *ha)
{
+ int rval;
struct init_cb_24xx *icb;
struct nvram_24xx *nv;
uint32_t *dptr;
@@ -3300,6 +3393,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
uint32_t chksum;
uint16_t cnt;
+ rval = QLA_SUCCESS;
icb = (struct init_cb_24xx *)ha->init_cb;
nv = (struct nvram_24xx *)ha->request_ring;
@@ -3332,7 +3426,52 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
le16_to_cpu(nv->nvram_version));
- return QLA_FUNCTION_FAILED;
+ qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+ "invalid -- WWPN) defaults.\n");
+
+ /*
+ * Set default initialization control block.
+ */
+ memset(nv, 0, ha->nvram_size);
+ nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
+ nv->version = __constant_cpu_to_le16(ICB_VERSION);
+ nv->frame_payload_size = __constant_cpu_to_le16(2048);
+ nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+ nv->exchange_count = __constant_cpu_to_le16(0);
+ nv->hard_address = __constant_cpu_to_le16(124);
+ nv->port_name[0] = 0x21;
+ nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
+ nv->port_name[2] = 0x00;
+ nv->port_name[3] = 0xe0;
+ nv->port_name[4] = 0x8b;
+ nv->port_name[5] = 0x1c;
+ nv->port_name[6] = 0x55;
+ nv->port_name[7] = 0x86;
+ nv->node_name[0] = 0x20;
+ nv->node_name[1] = 0x00;
+ nv->node_name[2] = 0x00;
+ nv->node_name[3] = 0xe0;
+ nv->node_name[4] = 0x8b;
+ nv->node_name[5] = 0x1c;
+ nv->node_name[6] = 0x55;
+ nv->node_name[7] = 0x86;
+ qla24xx_nvram_wwn_from_ofw(ha, nv);
+ nv->login_retry_count = __constant_cpu_to_le16(8);
+ nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
+ nv->login_timeout = __constant_cpu_to_le16(0);
+ nv->firmware_options_1 =
+ __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
+ nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
+ nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
+ nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
+ nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
+ nv->efi_parameters = __constant_cpu_to_le32(0);
+ nv->reset_delay = 5;
+ nv->max_luns_per_target = __constant_cpu_to_le16(128);
+ nv->port_down_retry_count = __constant_cpu_to_le16(30);
+ nv->link_down_timeout = __constant_cpu_to_le16(30);
+
+ rval = 1;
}
/* Reset Initialization control block */
@@ -3479,7 +3618,11 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
ha->flags.process_response_queue = 1;
}
- return QLA_SUCCESS;
+ if (rval) {
+ DEBUG2_3(printk(KERN_WARNING
+ "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+ }
+ return (rval);
}
static int
@@ -3782,6 +3925,8 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
return;
+ if (!ha->fw_major_version)
+ return;
ret = qla2x00_stop_firmware(ha);
for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index d4885616cd3..ca463469063 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -1726,6 +1726,17 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
qla_printk(KERN_WARNING, ha,
"MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
+
+ if (!IS_QLA24XX(ha))
+ goto skip_msi;
+
+ ret = pci_enable_msi(ha->pdev);
+ if (!ret) {
+ DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
+ ha->flags.msi_enabled = 1;
+ }
+skip_msi:
+
ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
if (!ret) {
@@ -1746,6 +1757,8 @@ qla2x00_free_irqs(scsi_qla_host_t *ha)
if (ha->flags.msix_enabled)
qla24xx_disable_msix(ha);
- else if (ha->flags.inta_enabled)
+ else if (ha->flags.inta_enabled) {
free_irq(ha->host->irq, ha);
+ pci_disable_msi(ha->pdev);
+ }
}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 83376f6ac3d..71e32a24852 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -1280,14 +1280,14 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
} else {
if (name != NULL) {
/* This function returns name in big endian. */
- name[0] = LSB(mcp->mb[2]);
- name[1] = MSB(mcp->mb[2]);
- name[2] = LSB(mcp->mb[3]);
- name[3] = MSB(mcp->mb[3]);
- name[4] = LSB(mcp->mb[6]);
- name[5] = MSB(mcp->mb[6]);
- name[6] = LSB(mcp->mb[7]);
- name[7] = MSB(mcp->mb[7]);
+ name[0] = MSB(mcp->mb[2]);
+ name[1] = LSB(mcp->mb[2]);
+ name[2] = MSB(mcp->mb[3]);
+ name[3] = LSB(mcp->mb[3]);
+ name[4] = MSB(mcp->mb[6]);
+ name[5] = LSB(mcp->mb[6]);
+ name[6] = MSB(mcp->mb[7]);
+ name[7] = LSB(mcp->mb[7]);
}
DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 68f5d24b938..dd076da86a4 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -36,7 +36,7 @@ module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xlogintimeout,
"Login timeout value in seconds.");
-int qlport_down_retry = 30;
+int qlport_down_retry;
module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(qlport_down_retry,
"Maximum number of command retries to a port that returns "
@@ -62,7 +62,7 @@ MODULE_PARM_DESC(ql2xallocfwdump,
"vary by ISP type. Default is 1 - allocate memory.");
int ql2xextended_error_logging;
-module_param(ql2xextended_error_logging, int, S_IRUGO|S_IRUSR);
+module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xextended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging. 1 - log errors.");
@@ -157,6 +157,8 @@ static struct scsi_host_template qla24xx_driver_template = {
.slave_alloc = qla2xxx_slave_alloc,
.slave_destroy = qla2xxx_slave_destroy,
+ .scan_finished = qla2xxx_scan_finished,
+ .scan_start = qla2xxx_scan_start,
.change_queue_depth = qla2x00_change_queue_depth,
.change_queue_type = qla2x00_change_queue_type,
.this_id = -1,
@@ -1575,9 +1577,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto probe_failed;
}
- if (qla2x00_initialize_adapter(ha) &&
- !(ha->device_flags & DFLG_NO_CABLE)) {
-
+ if (qla2x00_initialize_adapter(ha)) {
qla_printk(KERN_WARNING, ha,
"Failed to initialize adapter\n");
@@ -1705,6 +1705,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
scsi_host_put(ha->host);
+ pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -1747,8 +1748,6 @@ qla2x00_free_device(scsi_qla_host_t *ha)
if (ha->iobase)
iounmap(ha->iobase);
pci_release_regions(ha->pdev);
-
- pci_disable_device(ha->pdev);
}
static inline void
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index ff1dd4175a7..206bda093da 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -466,6 +466,7 @@ qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr)
udelay(10);
else
rval = QLA_FUNCTION_TIMEOUT;
+ cond_resched();
}
/* TODO: What happens if we time out? */
@@ -508,6 +509,7 @@ qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data)
udelay(10);
else
rval = QLA_FUNCTION_TIMEOUT;
+ cond_resched();
}
return rval;
}
@@ -1255,6 +1257,7 @@ qla2x00_poll_flash(scsi_qla_host_t *ha, uint32_t addr, uint8_t poll_data,
}
udelay(10);
barrier();
+ cond_resched();
}
return status;
}
@@ -1403,6 +1406,7 @@ qla2x00_read_flash_data(scsi_qla_host_t *ha, uint8_t *tmp_buf, uint32_t saddr,
if (saddr % 100)
udelay(10);
*tmp_buf = data;
+ cond_resched();
}
}
@@ -1449,7 +1453,6 @@ uint8_t *
qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
uint32_t offset, uint32_t length)
{
- unsigned long flags;
uint32_t addr, midpoint;
uint8_t *data;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
@@ -1458,7 +1461,6 @@ qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
qla2x00_suspend_hba(ha);
/* Go with read. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
midpoint = ha->optrom_size / 2;
qla2x00_flash_enable(ha);
@@ -1473,7 +1475,6 @@ qla2x00_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
*data = qla2x00_read_flash_byte(ha, addr);
}
qla2x00_flash_disable(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Resume HBA. */
qla2x00_resume_hba(ha);
@@ -1487,7 +1488,6 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
{
int rval;
- unsigned long flags;
uint8_t man_id, flash_id, sec_number, data;
uint16_t wd;
uint32_t addr, liter, sec_mask, rest_addr;
@@ -1500,7 +1500,6 @@ qla2x00_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
sec_number = 0;
/* Reset ISP chip. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
@@ -1689,10 +1688,10 @@ update_flash:
rval = QLA_FUNCTION_FAILED;
break;
}
+ cond_resched();
}
} while (0);
qla2x00_flash_disable(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Resume HBA. */
qla2x00_resume_hba(ha);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 61347aee55c..c375a4efbc7 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k5"
+#define QLA2XXX_VERSION "8.01.07-k7"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index 7b4e077a39c..6437d024b0d 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -8,6 +8,8 @@
#include "ql4_def.h"
#include <scsi/scsi_dbg.h>
+#if 0
+
static void qla4xxx_print_srb_info(struct srb * srb)
{
printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
@@ -195,3 +197,5 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
if (cnt % 16)
printk(KERN_DEBUG "\n");
}
+
+#endif /* 0 */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index e021eb5db2b..5b00cb04e7c 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -43,8 +43,6 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
uint16_t *tcp_source_port_num,
uint16_t *connection_id);
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host * ha,
- uint32_t fw_ddb_index);
int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
dma_addr_t fw_ddb_entry_dma);
@@ -55,18 +53,11 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha);
struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha);
int qla4xxx_add_sess(struct ddb_entry *);
void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry);
-int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index,
- uint16_t connection_id,
- uint16_t option);
-int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index);
int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha);
int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
uint32_t intr_status);
int qla4xxx_init_rings(struct scsi_qla_host * ha);
-void qla4xxx_dump_buffer(void *b, uint32_t size);
struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index b907b06d72a..6365df26861 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -7,9 +7,8 @@
#include "ql4_def.h"
-/*
- * QLogic ISP4xxx Hardware Support Function Prototypes.
- */
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index);
static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
{
@@ -48,7 +47,8 @@ static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
* This routine deallocates and unlinks the specified ddb_entry from the
* adapter's
**/
-void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry)
+static void qla4xxx_free_ddb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
{
/* Remove device entry from list */
list_del_init(&ddb_entry->list);
@@ -370,9 +370,9 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
* must be initialized prior to calling this routine
*
**/
-int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
- struct ddb_entry *ddb_entry,
- uint32_t fw_ddb_index)
+static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry,
+ uint32_t fw_ddb_index)
{
struct dev_db_entry *fw_ddb_entry = NULL;
dma_addr_t fw_ddb_entry_dma;
@@ -450,8 +450,8 @@ int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
* This routine allocates a ddb_entry, ititializes some values, and
* inserts it into the ddb list.
**/
-struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
- uint32_t fw_ddb_index)
+static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index)
{
struct ddb_entry *ddb_entry;
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index d41ce380eed..a216a1781af 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -19,8 +19,8 @@
* - advances the request_in pointer
* - checks for queue full
**/
-int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
- struct queue_entry **queue_entry)
+static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+ struct queue_entry **queue_entry)
{
uint16_t request_in;
uint8_t status = QLA_SUCCESS;
@@ -62,8 +62,8 @@ int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
*
* This routine issues a marker IOCB.
**/
-int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
- struct ddb_entry *ddb_entry, int lun)
+static int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry, int lun)
{
struct marker_entry *marker_entry;
unsigned long flags = 0;
@@ -96,7 +96,7 @@ exit_send_marker:
return status;
}
-struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
+static struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
struct scsi_qla_host *ha)
{
struct continuation_t1_entry *cont_entry;
@@ -120,7 +120,7 @@ struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
return cont_entry;
}
-uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
+static uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
{
uint16_t iocbs;
@@ -133,9 +133,9 @@ uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
return iocbs;
}
-void qla4xxx_build_scsi_iocbs(struct srb *srb,
- struct command_t3_entry *cmd_entry,
- uint16_t tot_dsds)
+static void qla4xxx_build_scsi_iocbs(struct srb *srb,
+ struct command_t3_entry *cmd_entry,
+ uint16_t tot_dsds)
{
struct scsi_qla_host *ha;
uint16_t avail_dsds;
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 7f28657eef3..f116ff91723 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -20,9 +20,9 @@
* If outCount is 0, this routine completes successfully WITHOUT waiting
* for the mailbox command to complete.
**/
-int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
- uint8_t outCount, uint32_t *mbx_cmd,
- uint32_t *mbx_sts)
+static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
+ uint8_t outCount, uint32_t *mbx_cmd,
+ uint32_t *mbx_sts)
{
int status = QLA_ERROR;
uint8_t i;
@@ -170,6 +170,8 @@ mbox_exit:
}
+#if 0
+
/**
* qla4xxx_issue_iocb - issue mailbox iocb command
* @ha: adapter state pointer.
@@ -243,6 +245,8 @@ int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
return QLA_SUCCESS;
}
+#endif /* 0 */
+
/**
* qla4xxx_initialize_fw_cb - initializes firmware control block.
* @ha: Pointer to host adapter structure.
@@ -570,6 +574,7 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
}
+#if 0
int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
uint16_t fw_ddb_index)
{
@@ -594,6 +599,7 @@ int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
return status;
}
+#endif /* 0 */
/**
* qla4xxx_get_crash_record - retrieves crash record.
@@ -649,6 +655,7 @@ exit_get_crash_record:
crash_record, crash_record_dma);
}
+#if 0
/**
* qla4xxx_get_conn_event_log - retrieves connection event log
* @ha: Pointer to host adapter structure.
@@ -738,6 +745,7 @@ exit_get_event_log:
dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
event_log_dma);
}
+#endif /* 0 */
/**
* qla4xxx_reset_lun - issues LUN Reset
@@ -834,7 +842,8 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
return QLA_SUCCESS;
}
-int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
+static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+ dma_addr_t dma_addr)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -855,7 +864,7 @@ int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, dma_addr_t dma_addr)
return QLA_SUCCESS;
}
-int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
+static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
{
uint32_t mbox_cmd[MBOX_REG_COUNT];
uint32_t mbox_sts[MBOX_REG_COUNT];
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 0bfddf893ed..da21f5fbbf8 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -14,7 +14,7 @@
/*
* Driver version
*/
-char qla4xxx_version_str[40];
+static char qla4xxx_version_str[40];
/*
* SRB allocation cache
@@ -45,8 +45,7 @@ int ql4_mod_unload = 0;
/*
* SCSI host template entry points
*/
-
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
/*
* iSCSI template entry points
@@ -1352,7 +1351,7 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
* At exit, the @ha's flags.enable_64bit_addressing set to indicated
* supported addressing method.
*/
-void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
+static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha)
{
int retval;
@@ -1627,7 +1626,7 @@ static struct pci_device_id qla4xxx_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
-struct pci_driver qla4xxx_pci_driver = {
+static struct pci_driver qla4xxx_pci_driver = {
.name = DRIVER_NAME,
.id_table = qla4xxx_pci_tbl,
.probe = qla4xxx_probe_adapter,
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 1c89ee3e69b..4c1e3133476 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -344,7 +344,6 @@ void scsi_destroy_command_freelist(struct Scsi_Host *shost)
void scsi_log_send(struct scsi_cmnd *cmd)
{
unsigned int level;
- struct scsi_device *sdev;
/*
* If ML QUEUE log level is greater than or equal to:
@@ -361,22 +360,17 @@ void scsi_log_send(struct scsi_cmnd *cmd)
level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT,
SCSI_LOG_MLQUEUE_BITS);
if (level > 1) {
- sdev = cmd->device;
- sdev_printk(KERN_INFO, sdev, "send ");
+ scmd_printk(KERN_INFO, cmd, "Send: ");
if (level > 2)
printk("0x%p ", cmd);
- /*
- * spaces to match disposition and cmd->result
- * output in scsi_log_completion.
- */
- printk(" ");
+ printk("\n");
scsi_print_command(cmd);
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
cmd->request_buffer, cmd->request_bufflen,
cmd->done,
- sdev->host->hostt->queuecommand);
+ cmd->device->host->hostt->queuecommand);
}
}
@@ -386,7 +380,6 @@ void scsi_log_send(struct scsi_cmnd *cmd)
void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
{
unsigned int level;
- struct scsi_device *sdev;
/*
* If ML COMPLETE log level is greater than or equal to:
@@ -405,8 +398,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
SCSI_LOG_MLCOMPLETE_BITS);
if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||
(level > 1)) {
- sdev = cmd->device;
- sdev_printk(KERN_INFO, sdev, "done ");
+ scmd_printk(KERN_INFO, cmd, "Done: ");
if (level > 2)
printk("0x%p ", cmd);
/*
@@ -415,40 +407,35 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
*/
switch (disposition) {
case SUCCESS:
- printk("SUCCESS");
+ printk("SUCCESS\n");
break;
case NEEDS_RETRY:
- printk("RETRY ");
+ printk("RETRY\n");
break;
case ADD_TO_MLQUEUE:
- printk("MLQUEUE");
+ printk("MLQUEUE\n");
break;
case FAILED:
- printk("FAILED ");
+ printk("FAILED\n");
break;
case TIMEOUT_ERROR:
/*
* If called via scsi_times_out.
*/
- printk("TIMEOUT");
+ printk("TIMEOUT\n");
break;
default:
- printk("UNKNOWN");
+ printk("UNKNOWN\n");
}
- printk(" %8x ", cmd->result);
+ scsi_print_result(cmd);
scsi_print_command(cmd);
- if (status_byte(cmd->result) & CHECK_CONDITION) {
- /*
- * XXX The scsi_print_sense formatting/prefix
- * doesn't match this function.
- */
+ if (status_byte(cmd->result) & CHECK_CONDITION)
scsi_print_sense("", cmd);
- }
- if (level > 3) {
- printk(KERN_INFO "scsi host busy %d failed %d\n",
- sdev->host->host_busy,
- sdev->host->host_failed);
- }
+ if (level > 3)
+ scmd_printk(KERN_INFO, cmd,
+ "scsi host busy %d failed %d\n",
+ cmd->device->host->host_busy,
+ cmd->device->host->host_failed);
}
}
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 3e2930b7ee2..06229f225ee 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -36,7 +36,6 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 918bb601954..e8350c562d2 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -38,7 +38,6 @@
#include "scsi_logging.h"
#define SENSE_TIMEOUT (10*HZ)
-#define START_UNIT_TIMEOUT (30*HZ)
/*
* These should *probably* be handled by the host itself.
@@ -184,10 +183,19 @@ int scsi_delete_timer(struct scsi_cmnd *scmd)
**/
void scsi_times_out(struct scsi_cmnd *scmd)
{
+ enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
scsi_log_completion(scmd, TIMEOUT_ERROR);
if (scmd->device->host->transportt->eh_timed_out)
- switch (scmd->device->host->transportt->eh_timed_out(scmd)) {
+ eh_timed_out = scmd->device->host->transportt->eh_timed_out;
+ else if (scmd->device->host->hostt->eh_timed_out)
+ eh_timed_out = scmd->device->host->hostt->eh_timed_out;
+ else
+ eh_timed_out = NULL;
+
+ if (eh_timed_out)
+ switch (eh_timed_out(scmd)) {
case EH_HANDLED:
__scsi_done(scmd);
return;
@@ -923,10 +931,12 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
if (scmd->device->allow_restart) {
- int rtn;
+ int i, rtn = NEEDS_RETRY;
+
+ for (i = 0; rtn == NEEDS_RETRY && i < 2; i++)
+ rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
+ scmd->device->timeout, 0);
- rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
- START_UNIT_TIMEOUT, 0);
if (rtn == SUCCESS)
return 0;
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9f7482d0b59..1f5a07bf2a7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -31,7 +31,7 @@
#define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools)
-#define SG_MEMPOOL_SIZE 32
+#define SG_MEMPOOL_SIZE 2
struct scsi_host_sg_pool {
size_t size;
@@ -173,7 +173,7 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
* @retries: number of times to retry request
* @flags: or into request flags;
*
- * returns the req->errors value which is the the scsi_cmnd result
+ * returns the req->errors value which is the scsi_cmnd result
* field.
**/
int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
@@ -848,8 +848,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
memcpy(req->sense, cmd->sense_buffer, len);
req->sense_len = len;
}
- } else
- req->data_len = cmd->resid;
+ }
+ req->data_len = cmd->resid;
}
/*
@@ -968,9 +968,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
if (result) {
if (!(req->cmd_flags & REQ_QUIET)) {
- scmd_printk(KERN_INFO, cmd,
- "SCSI error: return code = 0x%08x\n",
- result);
+ scsi_print_result(cmd);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0949145304e..a67f315244d 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -181,10 +181,8 @@ int scsi_complete_async_scans(void)
return 0;
}
-#ifdef MODULE
/* Only exported for the benefit of scsi_wait_scan */
EXPORT_SYMBOL_GPL(scsi_complete_async_scans);
-#endif
/**
* scsi_unlock_floptical - unlock device via a special MODE SENSE command
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 939de0de18b..67a38a1409b 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -276,8 +276,22 @@ static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
}
+static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ int i = 0;
+ int length = 0;
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
+ envp[i] = NULL;
+ return 0;
+}
+
static int scsi_bus_suspend(struct device * dev, pm_message_t state)
{
+ struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_host_template *sht = sdev->host->hostt;
int err;
@@ -286,28 +300,51 @@ static int scsi_bus_suspend(struct device * dev, pm_message_t state)
if (err)
return err;
- if (sht->suspend)
+ /* call HLD suspend first */
+ if (drv && drv->suspend) {
+ err = drv->suspend(dev, state);
+ if (err)
+ return err;
+ }
+
+ /* then, call host suspend */
+ if (sht->suspend) {
err = sht->suspend(sdev, state);
+ if (err) {
+ if (drv && drv->resume)
+ drv->resume(dev);
+ return err;
+ }
+ }
- return err;
+ return 0;
}
static int scsi_bus_resume(struct device * dev)
{
+ struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_host_template *sht = sdev->host->hostt;
- int err = 0;
+ int err = 0, err2 = 0;
+ /* call host resume first */
if (sht->resume)
err = sht->resume(sdev);
+ /* then, call HLD resume */
+ if (drv && drv->resume)
+ err2 = drv->resume(dev);
+
scsi_device_resume(sdev);
- return err;
+
+ /* favor LLD failure */
+ return err ? err : err2;;
}
struct bus_type scsi_bus_type = {
.name = "scsi",
.match = scsi_bus_match,
+ .uevent = scsi_bus_uevent,
.suspend = scsi_bus_suspend,
.resume = scsi_bus_resume,
};
@@ -547,6 +584,14 @@ show_sdev_iostat(iorequest_cnt);
show_sdev_iostat(iodone_cnt);
show_sdev_iostat(ioerr_cnt);
+static ssize_t
+sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct scsi_device *sdev;
+ sdev = to_scsi_device(dev);
+ return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type);
+}
+static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);
/* Default template for device attributes. May NOT be modified */
static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
@@ -566,6 +611,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_iorequest_cnt,
&dev_attr_iodone_cnt,
&dev_attr_ioerr_cnt,
+ &dev_attr_modalias,
NULL
};
diff --git a/drivers/scsi/scsi_tgt_if.c b/drivers/scsi/scsi_tgt_if.c
index 0e08817fdec..ca22ddf8174 100644
--- a/drivers/scsi/scsi_tgt_if.c
+++ b/drivers/scsi/scsi_tgt_if.c
@@ -179,10 +179,12 @@ static int event_recv_msg(struct tgt_event *ev)
switch (ev->hdr.type) {
case TGT_UEVENT_CMD_RSP:
err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no,
- ev->p.cmd_rsp.tag,
ev->p.cmd_rsp.result,
- ev->p.cmd_rsp.len,
+ ev->p.cmd_rsp.tag,
ev->p.cmd_rsp.uaddr,
+ ev->p.cmd_rsp.len,
+ ev->p.cmd_rsp.sense_uaddr,
+ ev->p.cmd_rsp.sense_len,
ev->p.cmd_rsp.rw);
break;
case TGT_UEVENT_TSK_MGMT_RSP:
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index d402aff5f31..2570f48a69c 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -28,7 +28,6 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tgt.h>
-#include <../drivers/md/dm-bio-list.h>
#include "scsi_tgt_priv.h"
@@ -42,16 +41,12 @@ static struct kmem_cache *scsi_tgt_cmd_cache;
struct scsi_tgt_cmd {
/* TODO replace work with James b's code */
struct work_struct work;
- /* TODO replace the lists with a large bio */
- struct bio_list xfer_done_list;
- struct bio_list xfer_list;
+ /* TODO fix limits of some drivers */
+ struct bio *bio;
struct list_head hash_list;
struct request *rq;
u64 tag;
-
- void *buffer;
- unsigned bufflen;
};
#define TGT_HASH_ORDER 4
@@ -93,7 +88,12 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
if (!tcmd)
goto put_dev;
- rq = blk_get_request(shost->uspace_req_q, write, gfp_mask);
+ /*
+ * The blk helpers are used to the READ/WRITE requests
+ * transfering data from a initiator point of view. Since
+ * we are in target mode we want the opposite.
+ */
+ rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask);
if (!rq)
goto free_tcmd;
@@ -111,8 +111,6 @@ struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost,
rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
rq->end_io_data = tcmd;
- bio_list_init(&tcmd->xfer_list);
- bio_list_init(&tcmd->xfer_done_list);
tcmd->rq = rq;
return cmd;
@@ -157,22 +155,6 @@ void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL_GPL(scsi_host_put_command);
-static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
-{
- struct bio *bio;
-
- /* must call bio_endio in case bio was bounced */
- while ((bio = bio_list_pop(&tcmd->xfer_done_list))) {
- bio_endio(bio, bio->bi_size, 0);
- bio_unmap_user(bio);
- }
-
- while ((bio = bio_list_pop(&tcmd->xfer_list))) {
- bio_endio(bio, bio->bi_size, 0);
- bio_unmap_user(bio);
- }
-}
-
static void cmd_hashlist_del(struct scsi_cmnd *cmd)
{
struct request_queue *q = cmd->request->q;
@@ -185,6 +167,11 @@ static void cmd_hashlist_del(struct scsi_cmnd *cmd)
spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
}
+static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd)
+{
+ blk_rq_unmap_user(tcmd->bio);
+}
+
static void scsi_tgt_cmd_destroy(struct work_struct *work)
{
struct scsi_tgt_cmd *tcmd =
@@ -193,16 +180,6 @@ static void scsi_tgt_cmd_destroy(struct work_struct *work)
dprintk("cmd %p %d %lu\n", cmd, cmd->sc_data_direction,
rq_data_dir(cmd->request));
- /*
- * We fix rq->cmd_flags here since when we told bio_map_user
- * to write vm for WRITE commands, blk_rq_bio_prep set
- * rq_data_dir the flags to READ.
- */
- if (cmd->sc_data_direction == DMA_TO_DEVICE)
- cmd->request->cmd_flags |= REQ_RW;
- else
- cmd->request->cmd_flags &= ~REQ_RW;
-
scsi_unmap_user_pages(tcmd);
scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd);
}
@@ -215,6 +192,7 @@ static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd,
struct list_head *head;
tcmd->tag = tag;
+ tcmd->bio = NULL;
INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy);
spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
head = &qdata->cmd_hash[cmd_hashfn(tag)];
@@ -349,10 +327,14 @@ static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd)
dprintk("cmd %p %lu\n", cmd, rq_data_dir(cmd->request));
scsi_tgt_uspace_send_status(cmd, tcmd->tag);
+
+ if (cmd->request_buffer)
+ scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+
queue_work(scsi_tgtd, &tcmd->work);
}
-static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
+static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
{
struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd);
int err;
@@ -365,30 +347,12 @@ static int __scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
case SCSI_MLQUEUE_DEVICE_BUSY:
return -EAGAIN;
}
-
return 0;
}
-static void scsi_tgt_transfer_response(struct scsi_cmnd *cmd)
-{
- struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
- int err;
-
- err = __scsi_tgt_transfer_response(cmd);
- if (!err)
- return;
-
- cmd->result = DID_BUS_BUSY << 16;
- err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
- if (err <= 0)
- /* the eh will have to pick this up */
- printk(KERN_ERR "Could not send cmd %p status\n", cmd);
-}
-
static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
{
struct request *rq = cmd->request;
- struct scsi_tgt_cmd *tcmd = rq->end_io_data;
int count;
cmd->use_sg = rq->nr_phys_segments;
@@ -398,143 +362,54 @@ static int scsi_tgt_init_cmd(struct scsi_cmnd *cmd, gfp_t gfp_mask)
cmd->request_bufflen = rq->data_len;
- dprintk("cmd %p addr %p cnt %d %lu\n", cmd, tcmd->buffer, cmd->use_sg,
- rq_data_dir(rq));
+ dprintk("cmd %p cnt %d %lu\n", cmd, cmd->use_sg, rq_data_dir(rq));
count = blk_rq_map_sg(rq->q, rq, cmd->request_buffer);
if (likely(count <= cmd->use_sg)) {
cmd->use_sg = count;
return 0;
}
- eprintk("cmd %p addr %p cnt %d\n", cmd, tcmd->buffer, cmd->use_sg);
+ eprintk("cmd %p cnt %d\n", cmd, cmd->use_sg);
scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
return -EINVAL;
}
/* TODO: test this crap and replace bio_map_user with new interface maybe */
static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd,
- int rw)
+ unsigned long uaddr, unsigned int len, int rw)
{
struct request_queue *q = cmd->request->q;
struct request *rq = cmd->request;
- void *uaddr = tcmd->buffer;
- unsigned int len = tcmd->bufflen;
- struct bio *bio;
int err;
- while (len > 0) {
- dprintk("%lx %u\n", (unsigned long) uaddr, len);
- bio = bio_map_user(q, NULL, (unsigned long) uaddr, len, rw);
- if (IS_ERR(bio)) {
- err = PTR_ERR(bio);
- dprintk("fail to map %lx %u %d %x\n",
- (unsigned long) uaddr, len, err, cmd->cmnd[0]);
- goto unmap_bios;
- }
-
- uaddr += bio->bi_size;
- len -= bio->bi_size;
-
+ dprintk("%lx %u\n", uaddr, len);
+ err = blk_rq_map_user(q, rq, (void *)uaddr, len);
+ if (err) {
/*
- * The first bio is added and merged. We could probably
- * try to add others using scsi_merge_bio() but for now
- * we keep it simple. The first bio should be pretty large
- * (either hitting the 1 MB bio pages limit or a queue limit)
- * already but for really large IO we may want to try and
- * merge these.
+ * TODO: need to fixup sg_tablesize, max_segment_size,
+ * max_sectors, etc for modern HW and software drivers
+ * where this value is bogus.
+ *
+ * TODO2: we can alloc a reserve buffer of max size
+ * we can handle and do the slow copy path for really large
+ * IO.
*/
- if (!rq->bio) {
- blk_rq_bio_prep(q, rq, bio);
- rq->data_len = bio->bi_size;
- } else
- /* put list of bios to transfer in next go around */
- bio_list_add(&tcmd->xfer_list, bio);
+ eprintk("Could not handle request of size %u.\n", len);
+ return err;
}
- cmd->offset = 0;
+ tcmd->bio = rq->bio;
err = scsi_tgt_init_cmd(cmd, GFP_KERNEL);
if (err)
- goto unmap_bios;
+ goto unmap_rq;
return 0;
-unmap_bios:
- if (rq->bio) {
- bio_unmap_user(rq->bio);
- while ((bio = bio_list_pop(&tcmd->xfer_list)))
- bio_unmap_user(bio);
- }
-
+unmap_rq:
+ scsi_unmap_user_pages(tcmd);
return err;
}
-static int scsi_tgt_transfer_data(struct scsi_cmnd *);
-
-static void scsi_tgt_data_transfer_done(struct scsi_cmnd *cmd)
-{
- struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data;
- struct bio *bio;
- int err;
-
- /* should we free resources here on error ? */
- if (cmd->result) {
-send_uspace_err:
- err = scsi_tgt_uspace_send_status(cmd, tcmd->tag);
- if (err <= 0)
- /* the tgt uspace eh will have to pick this up */
- printk(KERN_ERR "Could not send cmd %p status\n", cmd);
- return;
- }
-
- dprintk("cmd %p request_bufflen %u bufflen %u\n",
- cmd, cmd->request_bufflen, tcmd->bufflen);
-
- scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
- bio_list_add(&tcmd->xfer_done_list, cmd->request->bio);
-
- tcmd->buffer += cmd->request_bufflen;
- cmd->offset += cmd->request_bufflen;
-
- if (!tcmd->xfer_list.head) {
- scsi_tgt_transfer_response(cmd);
- return;
- }
-
- dprintk("cmd2 %p request_bufflen %u bufflen %u\n",
- cmd, cmd->request_bufflen, tcmd->bufflen);
-
- bio = bio_list_pop(&tcmd->xfer_list);
- BUG_ON(!bio);
-
- blk_rq_bio_prep(cmd->request->q, cmd->request, bio);
- cmd->request->data_len = bio->bi_size;
- err = scsi_tgt_init_cmd(cmd, GFP_ATOMIC);
- if (err) {
- cmd->result = DID_ERROR << 16;
- goto send_uspace_err;
- }
-
- if (scsi_tgt_transfer_data(cmd)) {
- cmd->result = DID_NO_CONNECT << 16;
- goto send_uspace_err;
- }
-}
-
-static int scsi_tgt_transfer_data(struct scsi_cmnd *cmd)
-{
- int err;
- struct Scsi_Host *host = scsi_tgt_cmd_to_host(cmd);
-
- err = host->hostt->transfer_data(cmd, scsi_tgt_data_transfer_done);
- switch (err) {
- case SCSI_MLQUEUE_HOST_BUSY:
- case SCSI_MLQUEUE_DEVICE_BUSY:
- return -EAGAIN;
- default:
- return 0;
- }
-}
-
static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr,
unsigned len)
{
@@ -584,8 +459,9 @@ static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag)
return rq;
}
-int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
- unsigned long uaddr, u8 rw)
+int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+ unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+ u32 sense_len, u8 rw)
{
struct Scsi_Host *shost;
struct scsi_cmnd *cmd;
@@ -617,8 +493,9 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
}
cmd = rq->special;
- dprintk("cmd %p result %d len %d bufflen %u %lu %x\n", cmd,
- result, len, cmd->request_bufflen, rq_data_dir(rq), cmd->cmnd[0]);
+ dprintk("cmd %p scb %x result %d len %d bufflen %u %lu %x\n",
+ cmd, cmd->cmnd[0], result, len, cmd->request_bufflen,
+ rq_data_dir(rq), cmd->cmnd[0]);
if (result == TASK_ABORTED) {
scsi_tgt_abort_cmd(shost, cmd);
@@ -629,36 +506,36 @@ int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
* in the request_* values
*/
tcmd = cmd->request->end_io_data;
- tcmd->buffer = (void *)uaddr;
- tcmd->bufflen = len;
cmd->result = result;
- if (!tcmd->bufflen || cmd->request_buffer) {
- err = __scsi_tgt_transfer_response(cmd);
- goto done;
- }
+ if (cmd->result == SAM_STAT_CHECK_CONDITION)
+ scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len);
- /*
- * TODO: Do we need to handle case where request does not
- * align with LLD.
- */
- err = scsi_map_user_pages(rq->end_io_data, cmd, rw);
- if (err) {
- eprintk("%p %d\n", cmd, err);
- err = -EAGAIN;
- goto done;
- }
+ if (len) {
+ err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw);
+ if (err) {
+ /*
+ * user-space daemon bugs or OOM
+ * TODO: we can do better for OOM.
+ */
+ struct scsi_tgt_queuedata *qdata;
+ struct list_head *head;
+ unsigned long flags;
- /* userspace failure */
- if (cmd->result) {
- if (status_byte(cmd->result) == CHECK_CONDITION)
- scsi_tgt_copy_sense(cmd, uaddr, len);
- err = __scsi_tgt_transfer_response(cmd);
- goto done;
- }
- /* ask the target LLD to transfer the data to the buffer */
- err = scsi_tgt_transfer_data(cmd);
+ eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n",
+ cmd, err, uaddr, len, rw);
+
+ qdata = shost->uspace_req_q->queuedata;
+ head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)];
+
+ spin_lock_irqsave(&qdata->cmd_hash_lock, flags);
+ list_add(&tcmd->hash_list, head);
+ spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags);
+ goto done;
+ }
+ }
+ err = scsi_tgt_transfer_response(cmd);
done:
scsi_host_put(shost);
return err;
diff --git a/drivers/scsi/scsi_tgt_priv.h b/drivers/scsi/scsi_tgt_priv.h
index 84488c51ff6..e9e6db1c417 100644
--- a/drivers/scsi/scsi_tgt_priv.h
+++ b/drivers/scsi/scsi_tgt_priv.h
@@ -18,8 +18,9 @@ extern int scsi_tgt_if_init(void);
extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, struct scsi_lun *lun,
u64 tag);
extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 tag);
-extern int scsi_tgt_kspace_exec(int host_no, u64 tag, int result, u32 len,
- unsigned long uaddr, u8 rw);
+extern int scsi_tgt_kspace_exec(int host_no, int result, u64 tag,
+ unsigned long uaddr, u32 len, unsigned long sense_uaddr,
+ u32 sense_len, u8 rw);
extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, int function, u64 tag,
struct scsi_lun *scsilun, void *data);
extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 mid, int result);
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 58afdb40170..b4d1ece46f7 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -200,6 +200,8 @@ static const struct {
{ FC_PORTSPEED_2GBIT, "2 Gbit" },
{ FC_PORTSPEED_4GBIT, "4 Gbit" },
{ FC_PORTSPEED_10GBIT, "10 Gbit" },
+ { FC_PORTSPEED_8GBIT, "8 Gbit" },
+ { FC_PORTSPEED_16GBIT, "16 Gbit" },
{ FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" },
};
fc_bitfield_name_search(port_speed, fc_port_speed_names)
@@ -1716,31 +1718,12 @@ fc_starget_delete(struct work_struct *work)
struct fc_rport *rport =
container_of(work, struct fc_rport, stgt_delete_work);
struct Scsi_Host *shost = rport_to_shost(rport);
- unsigned long flags;
struct fc_internal *i = to_fc_internal(shost->transportt);
- /*
- * Involve the LLDD if possible. All io on the rport is to
- * be terminated, either as part of the dev_loss_tmo callback
- * processing, or via the terminate_rport_io function.
- */
- if (i->f->dev_loss_tmo_callbk)
- i->f->dev_loss_tmo_callbk(rport);
- else if (i->f->terminate_rport_io)
+ /* Involve the LLDD if possible to terminate all io on the rport. */
+ if (i->f->terminate_rport_io)
i->f->terminate_rport_io(rport);
- spin_lock_irqsave(shost->host_lock, flags);
- if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
- spin_unlock_irqrestore(shost->host_lock, flags);
- if (!cancel_delayed_work(&rport->fail_io_work))
- fc_flush_devloss(shost);
- if (!cancel_delayed_work(&rport->dev_loss_work))
- fc_flush_devloss(shost);
- spin_lock_irqsave(shost->host_lock, flags);
- rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
- }
- spin_unlock_irqrestore(shost->host_lock, flags);
-
scsi_remove_target(&rport->dev);
}
@@ -1758,6 +1741,7 @@ fc_rport_final_delete(struct work_struct *work)
struct device *dev = &rport->dev;
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
+ unsigned long flags;
/*
* if a scan is pending, flush the SCSI Host work_q so that
@@ -1766,13 +1750,37 @@ fc_rport_final_delete(struct work_struct *work)
if (rport->flags & FC_RPORT_SCAN_PENDING)
scsi_flush_work(shost);
+ /* involve the LLDD to terminate all pending i/o */
+ if (i->f->terminate_rport_io)
+ i->f->terminate_rport_io(rport);
+
+ /*
+ * Cancel any outstanding timers. These should really exist
+ * only when rmmod'ing the LLDD and we're asking for
+ * immediate termination of the rports
+ */
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
+ if (!cancel_delayed_work(&rport->dev_loss_work))
+ fc_flush_devloss(shost);
+ spin_lock_irqsave(shost->host_lock, flags);
+ rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
/* Delete SCSI target and sdevs */
if (rport->scsi_target_id != -1)
fc_starget_delete(&rport->stgt_delete_work);
- else if (i->f->dev_loss_tmo_callbk)
+
+ /*
+ * Notify the driver that the rport is now dead. The LLDD will
+ * also guarantee that any communication to the rport is terminated
+ */
+ if (i->f->dev_loss_tmo_callbk)
i->f->dev_loss_tmo_callbk(rport);
- else if (i->f->terminate_rport_io)
- i->f->terminate_rport_io(rport);
transport_remove_device(dev);
device_del(dev);
@@ -1961,8 +1969,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
}
if (match) {
- struct delayed_work *work =
- &rport->dev_loss_work;
memcpy(&rport->node_name, &ids->node_name,
sizeof(rport->node_name));
@@ -1980,46 +1986,61 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
fci->f->dd_fcrport_size);
/*
- * If we were blocked, we were a target.
- * If no longer a target, we leave the timer
- * running in case the port changes roles
- * prior to the timer expiring. If the timer
- * fires, the target will be torn down.
+ * If we were not a target, cancel the
+ * io terminate and rport timers, and
+ * we're done.
+ *
+ * If we were a target, but our new role
+ * doesn't indicate a target, leave the
+ * timers running expecting the role to
+ * change as the target fully logs in. If
+ * it doesn't, the target will be torn down.
+ *
+ * If we were a target, and our role shows
+ * we're still a target, cancel the timers
+ * and kick off a scan.
*/
- if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET))
- return rport;
- /* restart the target */
+ /* was a target, not in roles */
+ if ((rport->scsi_target_id != -1) &&
+ (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)))
+ return rport;
/*
- * Stop the target timers first. Take no action
- * on the del_timer failure as the state
- * machine state change will validate the
- * transaction.
+ * Stop the fail io and dev_loss timers.
+ * If they flush, the port_state will
+ * be checked and will NOOP the function.
*/
if (!cancel_delayed_work(&rport->fail_io_work))
fc_flush_devloss(shost);
- if (!cancel_delayed_work(work))
+ if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);
spin_lock_irqsave(shost->host_lock, flags);
rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
- /* initiate a scan of the target */
- rport->flags |= FC_RPORT_SCAN_PENDING;
- scsi_queue_work(shost, &rport->scan_work);
-
- spin_unlock_irqrestore(shost->host_lock, flags);
-
- scsi_target_unblock(&rport->dev);
+ /* if target, initiate a scan */
+ if (rport->scsi_target_id != -1) {
+ rport->flags |= FC_RPORT_SCAN_PENDING;
+ scsi_queue_work(shost,
+ &rport->scan_work);
+ spin_unlock_irqrestore(shost->host_lock,
+ flags);
+ scsi_target_unblock(&rport->dev);
+ } else
+ spin_unlock_irqrestore(shost->host_lock,
+ flags);
return rport;
}
}
}
- /* Search the bindings array */
+ /*
+ * Search the bindings array
+ * Note: if never a FCP target, you won't be on this list
+ */
if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) {
/* search for a matching consistent binding */
@@ -2156,15 +2177,24 @@ fc_remote_port_delete(struct fc_rport *rport)
spin_lock_irqsave(shost->host_lock, flags);
- /* If no scsi target id mapping, delete it */
- if (rport->scsi_target_id == -1) {
- list_del(&rport->peers);
- rport->port_state = FC_PORTSTATE_DELETED;
- fc_queue_work(shost, &rport->rport_delete_work);
+ if (rport->port_state != FC_PORTSTATE_ONLINE) {
spin_unlock_irqrestore(shost->host_lock, flags);
return;
}
+ /*
+ * In the past, we if this was not an FCP-Target, we would
+ * unconditionally just jump to deleting the rport.
+ * However, rports can be used as node containers by the LLDD,
+ * and its not appropriate to just terminate the rport at the
+ * first sign of a loss in connectivity. The LLDD may want to
+ * send ELS traffic to re-validate the login. If the rport is
+ * immediately deleted, it makes it inappropriate for a node
+ * container.
+ * So... we now unconditionally wait dev_loss_tmo before
+ * destroying an rport.
+ */
+
rport->port_state = FC_PORTSTATE_BLOCKED;
rport->flags |= FC_RPORT_DEVLOSS_PENDING;
@@ -2261,11 +2291,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
EXPORT_SYMBOL(fc_remote_port_rolechg);
/**
- * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that
- * was a SCSI target (thus was blocked), and failed
- * to return in the alloted time.
+ * fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
+ * which we blocked, and has now failed to return
+ * in the allotted time.
*
- * @work: rport target that failed to reappear in the alloted time.
+ * @work: rport target that failed to reappear in the allotted time.
**/
static void
fc_timeout_deleted_rport(struct work_struct *work)
@@ -2281,10 +2311,12 @@ fc_timeout_deleted_rport(struct work_struct *work)
rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
/*
- * If the port is ONLINE, then it came back. Validate it's still an
- * FCP target. If not, tear down the scsi_target on it.
+ * If the port is ONLINE, then it came back. If it was a SCSI
+ * target, validate it still is. If not, tear down the
+ * scsi_target on it.
*/
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
+ (rport->scsi_target_id != -1) &&
!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: no longer"
@@ -2295,18 +2327,24 @@ fc_timeout_deleted_rport(struct work_struct *work)
return;
}
+ /* NOOP state - we're flushing workq's */
if (rport->port_state != FC_PORTSTATE_BLOCKED) {
spin_unlock_irqrestore(shost->host_lock, flags);
dev_printk(KERN_ERR, &rport->dev,
- "blocked FC remote port time out: leaving target alone\n");
+ "blocked FC remote port time out: leaving"
+ " rport%s alone\n",
+ (rport->scsi_target_id != -1) ? " and starget" : "");
return;
}
- if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) {
+ if ((fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) ||
+ (rport->scsi_target_id == -1)) {
list_del(&rport->peers);
rport->port_state = FC_PORTSTATE_DELETED;
dev_printk(KERN_ERR, &rport->dev,
- "blocked FC remote port time out: removing target\n");
+ "blocked FC remote port time out: removing"
+ " rport%s\n",
+ (rport->scsi_target_id != -1) ? " and starget" : "");
fc_queue_work(shost, &rport->rport_delete_work);
spin_unlock_irqrestore(shost->host_lock, flags);
return;
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index aabaa0576ab..caf1836bbec 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -49,7 +49,7 @@ struct iscsi_internal {
struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
};
-static int iscsi_session_nr; /* sysfs session id for next new session */
+static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
/*
* list of registered transports and lock that must
@@ -300,7 +300,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
int err;
ihost = shost->shost_data;
- session->sid = iscsi_session_nr++;
+ session->sid = atomic_add_return(1, &iscsi_session_nr);
session->target_id = target_id;
snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
@@ -1419,6 +1419,8 @@ static __init int iscsi_transport_init(void)
printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
ISCSI_TRANSPORT_VERSION);
+ atomic_set(&iscsi_session_nr, 0);
+
err = class_register(&iscsi_transport_class);
if (err)
return err;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5a8f55fea5f..00e46662296 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -58,16 +58,10 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsicam.h>
+#include <scsi/sd.h>
#include "scsi_logging.h"
-/*
- * More than enough for everybody ;) The huge number of majors
- * is a leftover from 16bit dev_t days, we don't really need that
- * much numberspace.
- */
-#define SD_MAJORS 16
-
MODULE_AUTHOR("Eric Youngdale");
MODULE_DESCRIPTION("SCSI disk (sd) driver");
MODULE_LICENSE("GPL");
@@ -88,45 +82,9 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
-
-/*
- * This is limited by the naming scheme enforced in sd_probe,
- * add another character to it if you really need more disks.
- */
-#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
-
-/*
- * Time out in seconds for disks and Magneto-opticals (which are slower).
- */
-#define SD_TIMEOUT (30 * HZ)
-#define SD_MOD_TIMEOUT (75 * HZ)
-
-/*
- * Number of allowed retries
- */
-#define SD_MAX_RETRIES 5
-#define SD_PASSTHROUGH_RETRIES 1
-
-/*
- * Size of the initial data buffer for mode and read capacity data
- */
-#define SD_BUF_SIZE 512
-
-struct scsi_disk {
- struct scsi_driver *driver; /* always &sd_template */
- struct scsi_device *device;
- struct class_device cdev;
- struct gendisk *disk;
- unsigned int openers; /* protected by BKL for now, yuck */
- sector_t capacity; /* size in 512-byte sectors */
- u32 index;
- u8 media_present;
- u8 write_prot;
- unsigned WCE : 1; /* state of disk WCE bit */
- unsigned RCD : 1; /* state of disk RCD bit, unused */
- unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
-};
-#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
+MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
static DEFINE_IDR(sd_index_idr);
static DEFINE_SPINLOCK(sd_index_lock);
@@ -136,20 +94,6 @@ static DEFINE_SPINLOCK(sd_index_lock);
* object after last put) */
static DEFINE_MUTEX(sd_ref_mutex);
-static int sd_revalidate_disk(struct gendisk *disk);
-static void sd_rw_intr(struct scsi_cmnd * SCpnt);
-
-static int sd_probe(struct device *);
-static int sd_remove(struct device *);
-static void sd_shutdown(struct device *dev);
-static void sd_rescan(struct device *);
-static int sd_init_command(struct scsi_cmnd *);
-static int sd_issue_flush(struct device *, sector_t *);
-static void sd_prepare_flush(request_queue_t *, struct request *);
-static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer);
-static void scsi_disk_release(struct class_device *cdev);
-
static const char *sd_cache_types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
@@ -199,13 +143,27 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
SD_MAX_RETRIES, &data, &sshdr)) {
if (scsi_sense_valid(&sshdr))
- scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr);
+ sd_print_sense_hdr(sdkp, &sshdr);
return -EINVAL;
}
sd_revalidate_disk(sdkp->disk);
return count;
}
+static ssize_t sd_store_manage_start_stop(struct class_device *cdev,
+ const char *buf, size_t count)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+ struct scsi_device *sdp = sdkp->device;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ sdp->manage_start_stop = simple_strtoul(buf, NULL, 10);
+
+ return count;
+}
+
static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
size_t count)
{
@@ -238,6 +196,14 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
}
+static ssize_t sd_show_manage_start_stop(struct class_device *cdev, char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+ struct scsi_device *sdp = sdkp->device;
+
+ return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);
+}
+
static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(cdev);
@@ -251,6 +217,8 @@ static struct class_device_attribute sd_disk_attrs[] = {
__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
__ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
sd_store_allow_restart),
+ __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,
+ sd_store_manage_start_stop),
__ATTR_NULL,
};
@@ -267,6 +235,8 @@ static struct scsi_driver sd_template = {
.name = "sd",
.probe = sd_probe,
.remove = sd_remove,
+ .suspend = sd_suspend,
+ .resume = sd_resume,
.shutdown = sd_shutdown,
},
.rescan = sd_rescan,
@@ -371,15 +341,19 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
unsigned int this_count = SCpnt->request_bufflen >> 9;
unsigned int timeout = sdp->timeout;
- SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "
- "count=%d\n", disk->disk_name,
- (unsigned long long)block, this_count));
+ SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,
+ "sd_init_command: block=%llu, "
+ "count=%d\n",
+ (unsigned long long)block,
+ this_count));
if (!sdp || !scsi_device_online(sdp) ||
block + rq->nr_sectors > get_capacity(disk)) {
- SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
- rq->nr_sectors));
- SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+ "Finishing %ld sectors\n",
+ rq->nr_sectors));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+ "Retry with 0x%p\n", SCpnt));
return 0;
}
@@ -391,8 +365,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
return 0;
}
- SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
- disk->disk_name, (unsigned long long)block));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",
+ (unsigned long long)block));
/*
* If we have a 1K hardware sectorsize, prevent access to single
@@ -407,7 +381,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
*/
if (sdp->sector_size == 1024) {
if ((block & 1) || (rq->nr_sectors & 1)) {
- printk(KERN_ERR "sd: Bad block number requested");
+ scmd_printk(KERN_ERR, SCpnt,
+ "Bad block number requested\n");
return 0;
} else {
block = block >> 1;
@@ -416,7 +391,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (sdp->sector_size == 2048) {
if ((block & 3) || (rq->nr_sectors & 3)) {
- printk(KERN_ERR "sd: Bad block number requested");
+ scmd_printk(KERN_ERR, SCpnt,
+ "Bad block number requested\n");
return 0;
} else {
block = block >> 2;
@@ -425,7 +401,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
}
if (sdp->sector_size == 4096) {
if ((block & 7) || (rq->nr_sectors & 7)) {
- printk(KERN_ERR "sd: Bad block number requested");
+ scmd_printk(KERN_ERR, SCpnt,
+ "Bad block number requested\n");
return 0;
} else {
block = block >> 3;
@@ -442,13 +419,15 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[0] = READ_6;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags);
+ scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);
return 0;
}
- SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
- disk->disk_name, (rq_data_dir(rq) == WRITE) ?
- "writing" : "reading", this_count, rq->nr_sectors));
+ SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,
+ "%s %d/%ld 512 byte blocks.\n",
+ (rq_data_dir(rq) == WRITE) ?
+ "writing" : "reading", this_count,
+ rq->nr_sectors));
SCpnt->cmnd[1] = 0;
@@ -490,7 +469,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
* during operation and thus turned off
* use_10_for_rw.
*/
- printk(KERN_ERR "sd: FUA write on READ/WRITE(6) drive\n");
+ scmd_printk(KERN_ERR, SCpnt,
+ "FUA write on READ/WRITE(6) drive\n");
return 0;
}
@@ -549,7 +529,7 @@ static int sd_open(struct inode *inode, struct file *filp)
return -ENXIO;
- SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n"));
sdev = sdkp->device;
@@ -619,7 +599,7 @@ static int sd_release(struct inode *inode, struct file *filp)
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdev = sdkp->device;
- SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n"));
if (!--sdkp->openers && sdev->removable) {
if (scsi_block_when_processing_errors(sdev))
@@ -732,8 +712,7 @@ static int sd_media_changed(struct gendisk *disk)
struct scsi_device *sdp = sdkp->device;
int retval;
- SCSI_LOG_HLQUEUE(3, printk("sd_media_changed: disk=%s\n",
- disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));
if (!sdp->removable)
return 0;
@@ -786,9 +765,10 @@ not_present:
return 1;
}
-static int sd_sync_cache(struct scsi_device *sdp)
+static int sd_sync_cache(struct scsi_disk *sdkp)
{
int retries, res;
+ struct scsi_device *sdp = sdkp->device;
struct scsi_sense_hdr sshdr;
if (!scsi_device_online(sdp))
@@ -809,28 +789,27 @@ static int sd_sync_cache(struct scsi_device *sdp)
break;
}
- if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
- "host = %d, driver = %02x\n ",
- status_byte(res), msg_byte(res),
- host_byte(res), driver_byte(res));
- if (driver_byte(res) & DRIVER_SENSE)
- scsi_print_sense_hdr("sd", &sshdr);
+ if (res) {
+ sd_print_result(sdkp, res);
+ if (driver_byte(res) & DRIVER_SENSE)
+ sd_print_sense_hdr(sdkp, &sshdr);
}
- return res;
+ if (res)
+ return -EIO;
+ return 0;
}
static int sd_issue_flush(struct device *dev, sector_t *error_sector)
{
int ret = 0;
- struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (!sdkp)
return -ENODEV;
if (sdkp->WCE)
- ret = sd_sync_cache(sdp);
+ ret = sd_sync_cache(sdkp);
scsi_disk_put(sdkp);
return ret;
}
@@ -928,12 +907,14 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
#ifdef CONFIG_SCSI_LOGGING
- SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
- SCpnt->request->rq_disk->disk_name, result));
+ SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
if (sense_valid) {
- SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
- "ascq]=%x,%x,%x,%x\n", sshdr.response_code,
- sshdr.sense_key, sshdr.asc, sshdr.ascq));
+ SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
+ "sd_rw_intr: sb[respc,sk,asc,"
+ "ascq]=%x,%x,%x,%x\n",
+ sshdr.response_code,
+ sshdr.sense_key, sshdr.asc,
+ sshdr.ascq));
}
#endif
if (driver_byte(result) != DRIVER_SENSE &&
@@ -1025,7 +1006,7 @@ static int media_not_present(struct scsi_disk *sdkp,
* spinup disk - called only in sd_revalidate_disk()
*/
static void
-sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
+sd_spinup_disk(struct scsi_disk *sdkp)
{
unsigned char cmd[10];
unsigned long spintime_expire = 0;
@@ -1069,9 +1050,10 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
/* no sense, TUR either succeeded or failed
* with a status error */
- if(!spintime && !scsi_status_is_good(the_result))
- printk(KERN_NOTICE "%s: Unit Not Ready, "
- "error = 0x%x\n", diskname, the_result);
+ if(!spintime && !scsi_status_is_good(the_result)) {
+ sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
+ sd_print_result(sdkp, the_result);
+ }
break;
}
@@ -1096,8 +1078,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
*/
} else if (sense_valid && sshdr.sense_key == NOT_READY) {
if (!spintime) {
- printk(KERN_NOTICE "%s: Spinning up disk...",
- diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Spinning up disk...");
cmd[0] = START_STOP;
cmd[1] = 1; /* Return immediately */
memset((void *) &cmd[2], 0, 8);
@@ -1130,9 +1111,8 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
/* we don't understand the sense code, so it's
* probably pointless to loop */
if(!spintime) {
- printk(KERN_NOTICE "%s: Unit Not Ready, "
- "sense:\n", diskname);
- scsi_print_sense_hdr("", &sshdr);
+ sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
+ sd_print_sense_hdr(sdkp, &sshdr);
}
break;
}
@@ -1151,8 +1131,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname)
* read disk capacity
*/
static void
-sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer)
+sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
{
unsigned char cmd[16];
int the_result, retries;
@@ -1191,18 +1170,12 @@ repeat:
} while (the_result && retries);
if (the_result && !longrc) {
- printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
- "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
- diskname, diskname,
- status_byte(the_result),
- msg_byte(the_result),
- host_byte(the_result),
- driver_byte(the_result));
-
+ sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n");
+ sd_print_result(sdkp, the_result);
if (driver_byte(the_result) & DRIVER_SENSE)
- scsi_print_sense_hdr("sd", &sshdr);
+ sd_print_sense_hdr(sdkp, &sshdr);
else
- printk("%s : sense not available. \n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n");
/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */
@@ -1218,16 +1191,10 @@ repeat:
return;
} else if (the_result && longrc) {
/* READ CAPACITY(16) has been failed */
- printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n"
- "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
- diskname, diskname,
- status_byte(the_result),
- msg_byte(the_result),
- host_byte(the_result),
- driver_byte(the_result));
- printk(KERN_NOTICE "%s : use 0xffffffff as device size\n",
- diskname);
-
+ sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
+ sd_print_result(sdkp, the_result);
+ sd_printk(KERN_NOTICE, sdkp, "Use 0xffffffff as device size\n");
+
sdkp->capacity = 1 + (sector_t) 0xffffffff;
goto got_data;
}
@@ -1238,14 +1205,14 @@ repeat:
if (buffer[0] == 0xff && buffer[1] == 0xff &&
buffer[2] == 0xff && buffer[3] == 0xff) {
if(sizeof(sdkp->capacity) > 4) {
- printk(KERN_NOTICE "%s : very big device. try to use"
- " READ CAPACITY(16).\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Very big device. "
+ "Trying to use READ CAPACITY(16).\n");
longrc = 1;
goto repeat;
}
- printk(KERN_ERR "%s: too big for this kernel. Use a "
- "kernel compiled with support for large block "
- "devices.\n", diskname);
+ sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use "
+ "a kernel compiled with support for large "
+ "block devices.\n");
sdkp->capacity = 0;
goto got_data;
}
@@ -1284,8 +1251,8 @@ repeat:
got_data:
if (sector_size == 0) {
sector_size = 512;
- printk(KERN_NOTICE "%s : sector size 0 reported, "
- "assuming 512.\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, "
+ "assuming 512.\n");
}
if (sector_size != 512 &&
@@ -1293,8 +1260,8 @@ got_data:
sector_size != 2048 &&
sector_size != 4096 &&
sector_size != 256) {
- printk(KERN_NOTICE "%s : unsupported sector size "
- "%d.\n", diskname, sector_size);
+ sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n",
+ sector_size);
/*
* The user might want to re-format the drive with
* a supported sectorsize. Once this happens, it
@@ -1327,10 +1294,10 @@ got_data:
mb -= sz - 974;
sector_div(mb, 1950);
- printk(KERN_NOTICE "SCSI device %s: "
- "%llu %d-byte hdwr sectors (%llu MB)\n",
- diskname, (unsigned long long)sdkp->capacity,
- hard_sector, (unsigned long long)mb);
+ sd_printk(KERN_NOTICE, sdkp,
+ "%llu %d-byte hardware sectors (%llu MB)\n",
+ (unsigned long long)sdkp->capacity,
+ hard_sector, (unsigned long long)mb);
}
/* Rescale capacity to 512-byte units */
@@ -1362,8 +1329,7 @@ sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage,
* called with buffer of length SD_BUF_SIZE
*/
static void
-sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer)
+sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
{
int res;
struct scsi_device *sdp = sdkp->device;
@@ -1371,7 +1337,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
set_disk_ro(sdkp->disk, 0);
if (sdp->skip_ms_page_3f) {
- printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n");
return;
}
@@ -1403,15 +1369,16 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
}
if (!scsi_status_is_good(res)) {
- printk(KERN_WARNING
- "%s: test WP failed, assume Write Enabled\n", diskname);
+ sd_printk(KERN_WARNING, sdkp,
+ "Test WP failed, assume Write Enabled\n");
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
set_disk_ro(sdkp->disk, sdkp->write_prot);
- printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
- sdkp->write_prot ? "on" : "off");
- printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n",
- diskname, buffer[0], buffer[1], buffer[2], buffer[3]);
+ sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
+ sdkp->write_prot ? "on" : "off");
+ sd_printk(KERN_DEBUG, sdkp,
+ "Mode Sense: %02x %02x %02x %02x\n",
+ buffer[0], buffer[1], buffer[2], buffer[3]);
}
}
@@ -1420,8 +1387,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
* called with buffer of length SD_BUF_SIZE
*/
static void
-sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
- unsigned char *buffer)
+sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
{
int len = 0, res;
struct scsi_device *sdp = sdkp->device;
@@ -1450,8 +1416,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
if (!data.header_length) {
modepage = 6;
- printk(KERN_ERR "%s: missing header in MODE_SENSE response\n",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n");
}
/* that went OK, now ask for the proper length */
@@ -1478,13 +1443,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
int offset = data.header_length + data.block_descriptor_length;
if (offset >= SD_BUF_SIZE - 2) {
- printk(KERN_ERR "%s: malformed MODE SENSE response",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n");
goto defaults;
}
if ((buffer[offset] & 0x3f) != modepage) {
- printk(KERN_ERR "%s: got wrong page\n", diskname);
+ sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
goto defaults;
}
@@ -1498,14 +1462,13 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
sdkp->DPOFUA = (data.device_specific & 0x10) != 0;
if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
- printk(KERN_NOTICE "SCSI device %s: uses "
- "READ/WRITE(6), disabling FUA\n", diskname);
+ sd_printk(KERN_NOTICE, sdkp,
+ "Uses READ/WRITE(6), disabling FUA\n");
sdkp->DPOFUA = 0;
}
- printk(KERN_NOTICE "SCSI device %s: "
- "write cache: %s, read cache: %s, %s\n",
- diskname,
+ sd_printk(KERN_NOTICE, sdkp,
+ "Write cache: %s, read cache: %s, %s\n",
sdkp->WCE ? "enabled" : "disabled",
sdkp->RCD ? "disabled" : "enabled",
sdkp->DPOFUA ? "supports DPO and FUA"
@@ -1518,15 +1481,13 @@ bad_sense:
if (scsi_sense_valid(&sshdr) &&
sshdr.sense_key == ILLEGAL_REQUEST &&
sshdr.asc == 0x24 && sshdr.ascq == 0x0)
- printk(KERN_NOTICE "%s: cache data unavailable\n",
- diskname); /* Invalid field in CDB */
+ /* Invalid field in CDB */
+ sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n");
else
- printk(KERN_ERR "%s: asking for cache data failed\n",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n");
defaults:
- printk(KERN_ERR "%s: assuming drive cache: write through\n",
- diskname);
+ sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n");
sdkp->WCE = 0;
sdkp->RCD = 0;
sdkp->DPOFUA = 0;
@@ -1544,7 +1505,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
unsigned char *buffer;
unsigned ordered;
- SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
+ SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
+ "sd_revalidate_disk\n"));
/*
* If the device is offline, don't try and read capacity or any
@@ -1555,8 +1517,8 @@ static int sd_revalidate_disk(struct gendisk *disk)
buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA);
if (!buffer) {
- printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
- "failure.\n");
+ sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory "
+ "allocation failure.\n");
goto out;
}
@@ -1568,16 +1530,16 @@ static int sd_revalidate_disk(struct gendisk *disk)
sdkp->WCE = 0;
sdkp->RCD = 0;
- sd_spinup_disk(sdkp, disk->disk_name);
+ sd_spinup_disk(sdkp);
/*
* Without media there is no reason to ask; moreover, some devices
* react badly if we do.
*/
if (sdkp->media_present) {
- sd_read_capacity(sdkp, disk->disk_name, buffer);
- sd_read_write_protect_flag(sdkp, disk->disk_name, buffer);
- sd_read_cache_type(sdkp, disk->disk_name, buffer);
+ sd_read_capacity(sdkp, buffer);
+ sd_read_write_protect_flag(sdkp, buffer);
+ sd_read_cache_type(sdkp, buffer);
}
/*
@@ -1709,8 +1671,8 @@ static int sd_probe(struct device *dev)
dev_set_drvdata(dev, sdkp);
add_disk(gd);
- sdev_printk(KERN_NOTICE, sdp, "Attached scsi %sdisk %s\n",
- sdp->removable ? "removable " : "", gd->disk_name);
+ sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
+ sdp->removable ? "removable " : "");
return 0;
@@ -1774,6 +1736,31 @@ static void scsi_disk_release(struct class_device *cdev)
kfree(sdkp);
}
+static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
+{
+ unsigned char cmd[6] = { START_STOP }; /* START_VALID */
+ struct scsi_sense_hdr sshdr;
+ struct scsi_device *sdp = sdkp->device;
+ int res;
+
+ if (start)
+ cmd[4] |= 1; /* START */
+
+ if (!scsi_device_online(sdp))
+ return -ENODEV;
+
+ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
+ SD_TIMEOUT, SD_MAX_RETRIES);
+ if (res) {
+ sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
+ sd_print_result(sdkp, res);
+ if (driver_byte(res) & DRIVER_SENSE)
+ sd_print_sense_hdr(sdkp, &sshdr);
+ }
+
+ return res;
+}
+
/*
* Send a SYNCHRONIZE CACHE instruction down to the device through
* the normal SCSI command structure. Wait for the command to
@@ -1781,20 +1768,62 @@ static void scsi_disk_release(struct class_device *cdev)
*/
static void sd_shutdown(struct device *dev)
{
- struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
if (!sdkp)
return; /* this can happen */
if (sdkp->WCE) {
- printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
- sdkp->disk->disk_name);
- sd_sync_cache(sdp);
+ sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
+ sd_sync_cache(sdkp);
+ }
+
+ if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) {
+ sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+ sd_start_stop_device(sdkp, 0);
}
+
scsi_disk_put(sdkp);
}
+static int sd_suspend(struct device *dev, pm_message_t mesg)
+{
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+ int ret;
+
+ if (!sdkp)
+ return 0; /* this can happen */
+
+ if (sdkp->WCE) {
+ sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
+ ret = sd_sync_cache(sdkp);
+ if (ret)
+ return ret;
+ }
+
+ if (mesg.event == PM_EVENT_SUSPEND &&
+ sdkp->device->manage_start_stop) {
+ sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
+ ret = sd_start_stop_device(sdkp, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sd_resume(struct device *dev)
+{
+ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+
+ if (!sdkp->device->manage_start_stop)
+ return 0;
+
+ sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
+
+ return sd_start_stop_device(sdkp, 1);
+}
+
/**
* init_sd - entry point for this driver (both when built in or when
* a module).
@@ -1852,3 +1881,19 @@ static void __exit exit_sd(void)
module_init(init_sd);
module_exit(exit_sd);
+
+static void sd_print_sense_hdr(struct scsi_disk *sdkp,
+ struct scsi_sense_hdr *sshdr)
+{
+ sd_printk(KERN_INFO, sdkp, "");
+ scsi_show_sense_hdr(sshdr);
+ sd_printk(KERN_INFO, sdkp, "");
+ scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+}
+
+static void sd_print_result(struct scsi_disk *sdkp, int result)
+{
+ sd_printk(KERN_INFO, sdkp, "");
+ scsi_show_result(result);
+}
+
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 81e3bc7b02a..0c691a60a75 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -41,7 +41,6 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/seq_file.h>
@@ -917,6 +916,8 @@ sg_ioctl(struct inode *inode, struct file *filp,
return result;
if (val < 0)
return -EINVAL;
+ val = min_t(int, val,
+ sdp->device->request_queue->max_sectors * 512);
if (val != sfp->reserve.bufflen) {
if (sg_res_in_use(sfp) || sfp->mmap_called)
return -EBUSY;
@@ -925,7 +926,8 @@ sg_ioctl(struct inode *inode, struct file *filp,
}
return 0;
case SG_GET_RESERVED_SIZE:
- val = (int) sfp->reserve.bufflen;
+ val = min_t(int, sfp->reserve.bufflen,
+ sdp->device->request_queue->max_sectors * 512);
return put_user(val, ip);
case SG_SET_COMMAND_Q:
result = get_user(val, ip);
@@ -1061,6 +1063,9 @@ sg_ioctl(struct inode *inode, struct file *filp,
if (sdp->detached)
return -ENODEV;
return scsi_ioctl(sdp->device, cmd_in, p);
+ case BLKSECTGET:
+ return put_user(sdp->device->request_queue->max_sectors * 512,
+ ip);
default:
if (read_only)
return -EPERM; /* don't know so take safe approach */
@@ -2339,6 +2344,7 @@ sg_add_sfp(Sg_device * sdp, int dev)
{
Sg_fd *sfp;
unsigned long iflags;
+ int bufflen;
sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN);
if (!sfp)
@@ -2369,7 +2375,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
if (unlikely(sg_big_buff != def_reserved_size))
sg_big_buff = def_reserved_size;
- sg_build_reserve(sfp, sg_big_buff);
+ bufflen = min_t(int, sg_big_buff,
+ sdp->device->request_queue->max_sectors * 512);
+ sg_build_reserve(sfp, bufflen);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
sfp->reserve.bufflen, sfp->reserve.k_use_sg));
return sfp;
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index 6bc50511584..a7dfb65fb84 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -98,7 +98,7 @@ static int __init snirm710_probe(struct platform_device *dev)
host->this_id = 7;
host->base = base;
host->irq = platform_get_irq(dev, 0);
- if(request_irq(host->irq, NCR_700_intr, SA_SHIRQ, "snirm710", host)) {
+ if(request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "snirm710", host)) {
printk(KERN_ERR "snirm710: request_irq failed!\n");
goto out_put_host;
}
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 1857d68e719..f9a52af7f5b 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -62,6 +62,8 @@
MODULE_DESCRIPTION("SCSI cdrom (sr) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM);
#define SR_DISKS 256
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 98d8411bbcc..55bfeccf68a 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -89,6 +89,7 @@ MODULE_AUTHOR("Kai Makisara");
MODULE_DESCRIPTION("SCSI tape (st) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR);
+MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE);
/* Set 'perm' (4th argument) to 0 to disable module_param's definition
* of sysfs parameters (which module_param doesn't yet support).
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index 8c766bcd109..bbeb2451d32 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index a583e89238f..e7b85e832eb 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -351,6 +351,27 @@ static u8 dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
* (DCBs, SRBs, Queueing)
*
**********************************************************************/
+static void inline dc390_start_segment(struct dc390_srb* pSRB)
+{
+ struct scatterlist *psgl = pSRB->pSegmentList;
+
+ /* start new sg segment */
+ pSRB->SGBusAddr = sg_dma_address(psgl);
+ pSRB->SGToBeXferLen = sg_dma_len(psgl);
+}
+
+static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue)
+{
+ unsigned long xfer = pSRB->SGToBeXferLen - residue;
+
+ /* xfer more bytes transferred */
+ pSRB->SGBusAddr += xfer;
+ pSRB->TotalXferredLen += xfer;
+ pSRB->SGToBeXferLen = residue;
+
+ return xfer;
+}
+
static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun)
{
struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL;
@@ -625,70 +646,6 @@ dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_sr
return 0;
}
-//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
-#define DMA_INT 0
-
-#if DMA_INT
-/* This is similar to AM53C974.c ... */
-static u8
-dc390_dma_intr (struct dc390_acb* pACB)
-{
- struct dc390_srb* pSRB;
- u8 dstate;
- DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev);
-
- DEBUG0(pci_read_config_word(pdev, PCI_STATUS, &pstate));
- DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
- { printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
- pci_write_config_word(pdev, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));});
-
- dstate = DC390_read8 (DMA_Status);
-
- if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
- else pSRB = pACB->pActiveDCB->pActiveSRB;
-
- if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
- {
- printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
- return dstate;
- }
- if (dstate & DMA_XFER_DONE)
- {
- u32 residual, xferCnt; int ctr = 6000000;
- if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
- {
- do
- {
- DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n"));
- dstate = DC390_read8 (DMA_Status);
- residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
- DC390_read8 (CtcReg_High) << 16;
- residual += DC390_read8 (Current_Fifo) & 0x1f;
- } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
- if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
- /* residual = ... */
- }
- else
- residual = 0;
-
- /* ??? */
-
- xferCnt = pSRB->SGToBeXferLen - residual;
- pSRB->SGBusAddr += xferCnt;
- pSRB->TotalXferredLen += xferCnt;
- pSRB->SGToBeXferLen = residual;
-# ifdef DC390_DEBUG0
- printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n",
- (unsigned int)residual, (unsigned int)xferCnt);
-# endif
-
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
- }
- dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
- return dstate;
-}
-#endif
-
static void __inline__
dc390_InvalidCmd(struct dc390_acb* pACB)
@@ -708,9 +665,6 @@ DC390_Interrupt(void *dev_id)
u8 phase;
void (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *);
u8 istate, istatus;
-#if DMA_INT
- u8 dstatus;
-#endif
sstatus = DC390_read8 (Scsi_Status);
if( !(sstatus & INTERRUPT) )
@@ -718,22 +672,9 @@ DC390_Interrupt(void *dev_id)
DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
-#if DMA_INT
- spin_lock_irq(pACB->pScsiHost->host_lock);
- dstatus = dc390_dma_intr (pACB);
- spin_unlock_irq(pACB->pScsiHost->host_lock);
-
- DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));
- if (! (dstatus & SCSI_INTERRUPT))
- {
- DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
- return IRQ_NONE;
- }
-#else
//DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
//dstatus = DC390_read8 (DMA_Status);
//DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-#endif
spin_lock_irq(pACB->pScsiHost->host_lock);
@@ -821,11 +762,10 @@ static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
}
static void
-dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
{
u8 sstatus;
- struct scatterlist *psgl;
- u32 ResidCnt, xferCnt;
+ u32 ResidCnt;
u8 dstate = 0;
sstatus = *psstatus;
@@ -856,42 +796,35 @@ dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
if( pSRB->SGIndex < pSRB->SGcount )
{
pSRB->pSegmentList++;
- psgl = pSRB->pSegmentList;
- pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
- pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+ dc390_start_segment(pSRB);
}
else
pSRB->SGToBeXferLen = 0;
}
else
{
- ResidCnt = (u32) DC390_read8 (Current_Fifo) & 0x1f;
- ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16;
- ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8;
- ResidCnt += (u32) DC390_read8 (CtcReg_Low);
-
- xferCnt = pSRB->SGToBeXferLen - ResidCnt;
- pSRB->SGBusAddr += xferCnt;
- pSRB->TotalXferredLen += xferCnt;
- pSRB->SGToBeXferLen = ResidCnt;
+ ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) +
+ (((u32) DC390_read8 (CtcReg_High) << 16) |
+ ((u32) DC390_read8 (CtcReg_Mid) << 8) |
+ (u32) DC390_read8 (CtcReg_Low));
+
+ dc390_advance_segment(pSRB, ResidCnt);
}
}
if ((*psstatus & 7) != SCSI_DATA_OUT)
{
- DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+ DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD);
DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
}
}
static void
-dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
{
u8 sstatus, residual, bval;
- struct scatterlist *psgl;
- u32 ResidCnt, i;
+ u32 ResidCnt, i;
unsigned long xferCnt;
- u8 *ptr;
sstatus = *psstatus;
@@ -922,19 +855,17 @@ dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \
+ ((unsigned long) DC390_read8 (CtcReg_Mid) << 8) \
+ ((unsigned long) DC390_read8 (CtcReg_Low)));
- DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen));
+ DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen));
- DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+ DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
pSRB->SGIndex++;
if( pSRB->SGIndex < pSRB->SGcount )
{
pSRB->pSegmentList++;
- psgl = pSRB->pSegmentList;
- pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
- pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+ dc390_start_segment(pSRB);
}
else
pSRB->SGToBeXferLen = 0;
@@ -973,47 +904,45 @@ din_1:
}
/* It seems a DMA Blast abort isn't that bad ... */
if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
- //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
- dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
+ //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
+ dc390_laststatus &= ~0xff000000;
+ dc390_laststatus |= bval << 24;
DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
- ResidCnt = (u32) DC390_read8 (CtcReg_High);
- ResidCnt <<= 8;
- ResidCnt |= (u32) DC390_read8 (CtcReg_Mid);
- ResidCnt <<= 8;
- ResidCnt |= (u32) DC390_read8 (CtcReg_Low);
-
- xferCnt = pSRB->SGToBeXferLen - ResidCnt;
- pSRB->SGBusAddr += xferCnt;
- pSRB->TotalXferredLen += xferCnt;
- pSRB->SGToBeXferLen = ResidCnt;
-
- if( residual )
- {
- static int feedback_requested;
+ ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) |
+ ((u32) DC390_read8 (CtcReg_Mid) << 8)) |
+ (u32) DC390_read8 (CtcReg_Low);
+
+ xferCnt = dc390_advance_segment(pSRB, ResidCnt);
+
+ if (residual) {
+ size_t count = 1;
+ size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList);
+ unsigned long flags;
+ u8 *ptr;
+
bval = DC390_read8 (ScsiFifo); /* get one residual byte */
- if (!feedback_requested) {
- feedback_requested = 1;
- printk(KERN_WARNING "%s: Please, contact <linux-scsi@vger.kernel.org> "
- "to help improve support for your system.\n", __FILE__);
+ local_irq_save(flags);
+ ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count);
+ if (likely(ptr)) {
+ *(ptr + offset) = bval;
+ scsi_kunmap_atomic_sg(ptr);
}
+ local_irq_restore(flags);
+ WARN_ON(!ptr);
- ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr );
- *ptr = bval;
- pSRB->SGBusAddr++; xferCnt++;
- pSRB->TotalXferredLen++;
- pSRB->SGToBeXferLen--;
+ /* 1 more byte read */
+ xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1);
}
- DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+ DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\
pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
-
}
}
if ((*psstatus & 7) != SCSI_DATA_IN)
{
DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+ DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
}
}
@@ -1216,7 +1145,7 @@ dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB)
/* handle RESTORE_PTR */
-/* I presume, this command is already mapped, so, have to remap. */
+/* This doesn't look very healthy... to-be-fixed */
static void
dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
{
@@ -1225,6 +1154,7 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
pSRB->TotalXferredLen = 0;
pSRB->SGIndex = 0;
if (pcmd->use_sg) {
+ size_t saved;
pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
psgl = pSRB->pSegmentList;
//dc390_pci_sync(pSRB);
@@ -1236,15 +1166,16 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
if( pSRB->SGIndex < pSRB->SGcount )
{
pSRB->pSegmentList++;
- psgl = pSRB->pSegmentList;
- pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
- pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+
+ dc390_start_segment(pSRB);
}
else
pSRB->SGToBeXferLen = 0;
}
- pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
- pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+
+ saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen;
+ pSRB->SGToBeXferLen -= saved;
+ pSRB->SGBusAddr += saved;
printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
@@ -1365,7 +1296,6 @@ dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
static void
dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
{
- struct scatterlist *psgl;
unsigned long lval;
struct dc390_dcb* pDCB = pACB->pActiveDCB;
@@ -1391,12 +1321,11 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
if( pSRB->SGIndex < pSRB->SGcount )
{
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
if( !pSRB->SGToBeXferLen )
{
- psgl = pSRB->pSegmentList;
- pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
- pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+ dc390_start_segment(pSRB);
+
DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
}
lval = pSRB->SGToBeXferLen;
@@ -1410,12 +1339,12 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+ //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
pSRB->SRBState = SRB_DATA_XFER;
DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
- DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+ DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
@@ -1436,8 +1365,8 @@ dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
pSRB->SRBState |= SRB_XFERPAD;
DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
/*
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
- DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
+ DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
*/
}
}
@@ -2680,7 +2609,7 @@ static int __init dc390_module_init(void)
printk (KERN_INFO "DC390: Using safe settings.\n");
}
- return pci_module_init(&dc390_driver);
+ return pci_register_driver(&dc390_driver);
}
static void __exit dc390_module_exit(void)
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index 9b66fa8d38d..c3d8c80cfb3 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -19,14 +19,6 @@
#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
-#define pci_dma_lo32(a) (a & 0xffffffff)
-
-typedef u8 UCHAR; /* 8 bits */
-typedef u16 USHORT; /* 16 bits */
-typedef u32 UINT; /* 32 bits */
-typedef unsigned long ULONG; /* 32/64 bits */
-
-
/*
;-----------------------------------------------------------------------
; SCSI Request Block
@@ -43,7 +35,9 @@ struct scatterlist *pSegmentList;
struct scatterlist Segmentx; /* make a one entry of S/G list table */
-unsigned long SGBusAddr; /*;a segment starting address as seen by AM53C974A*/
+unsigned long SGBusAddr; /*;a segment starting address as seen by AM53C974A
+ in CPU endianness. We're only getting 32-bit bus
+ addresses by default */
unsigned long SGToBeXferLen; /*; to be xfer length */
unsigned long TotalXferredLen;
unsigned long SavedTotXLen;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 90621c3312b..48e259a0167 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -251,9 +251,16 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_UUE,
},
+ [PORT_RM9000] = {
+ .name = "RM9000",
+ .fifo_size = 16,
+ .tx_loadsz = 16,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .flags = UART_CAP_FIFO,
+ },
};
-#ifdef CONFIG_SERIAL_8250_AU1X00
+#if defined (CONFIG_SERIAL_8250_AU1X00)
/* Au1x00 UART hardware has a weird register layout */
static const u8 au_io_in_map[] = {
@@ -289,6 +296,44 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
return au_io_out_map[offset];
}
+#elif defined (CONFIG_SERIAL_8250_RM9K)
+
+static const u8
+ regmap_in[8] = {
+ [UART_RX] = 0x00,
+ [UART_IER] = 0x0c,
+ [UART_IIR] = 0x14,
+ [UART_LCR] = 0x1c,
+ [UART_MCR] = 0x20,
+ [UART_LSR] = 0x24,
+ [UART_MSR] = 0x28,
+ [UART_SCR] = 0x2c
+ },
+ regmap_out[8] = {
+ [UART_TX] = 0x04,
+ [UART_IER] = 0x0c,
+ [UART_FCR] = 0x18,
+ [UART_LCR] = 0x1c,
+ [UART_MCR] = 0x20,
+ [UART_LSR] = 0x24,
+ [UART_MSR] = 0x28,
+ [UART_SCR] = 0x2c
+ };
+
+static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+{
+ if (up->port.iotype != UPIO_RM9000)
+ return offset;
+ return regmap_in[offset];
+}
+
+static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+{
+ if (up->port.iotype != UPIO_RM9000)
+ return offset;
+ return regmap_out[offset];
+}
+
#else
/* sane hardware needs no mapping */
@@ -308,8 +353,10 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset)
return inb(up->port.iobase + 1);
case UPIO_MEM:
+ case UPIO_DWAPB:
return readb(up->port.membase + offset);
+ case UPIO_RM9000:
case UPIO_MEM32:
return readl(up->port.membase + offset);
@@ -333,6 +380,8 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset)
static void
serial_out(struct uart_8250_port *up, int offset, int value)
{
+ /* Save the offset before it's remapped */
+ int save_offset = offset;
offset = map_8250_out_reg(up, offset) << up->port.regshift;
switch (up->port.iotype) {
@@ -345,6 +394,7 @@ serial_out(struct uart_8250_port *up, int offset, int value)
writeb(value, up->port.membase + offset);
break;
+ case UPIO_RM9000:
case UPIO_MEM32:
writel(value, up->port.membase + offset);
break;
@@ -359,6 +409,18 @@ serial_out(struct uart_8250_port *up, int offset, int value)
writeb(value, up->port.membase + offset);
break;
+ case UPIO_DWAPB:
+ /* Save the LCR value so it can be re-written when a
+ * Busy Detect interrupt occurs. */
+ if (save_offset == UART_LCR)
+ up->lcr = value;
+ writeb(value, up->port.membase + offset);
+ /* Read the IER to ensure any interrupt is cleared before
+ * returning from ISR. */
+ if (save_offset == UART_TX || save_offset == UART_IER)
+ value = serial_in(up, UART_IER);
+ break;
+
default:
outb(value, up->port.iobase + offset);
}
@@ -373,6 +435,7 @@ serial_out_sync(struct uart_8250_port *up, int offset, int value)
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
#endif
+ case UPIO_DWAPB:
serial_out(up, offset, value);
serial_in(up, UART_LCR); /* safe, no side-effects */
break;
@@ -403,7 +466,7 @@ static inline void _serial_dl_write(struct uart_8250_port *up, int value)
serial_outp(up, UART_DLM, value >> 8 & 0xff);
}
-#ifdef CONFIG_SERIAL_8250_AU1X00
+#if defined (CONFIG_SERIAL_8250_AU1X00)
/* Au1x00 haven't got a standard divisor latch */
static int serial_dl_read(struct uart_8250_port *up)
{
@@ -420,6 +483,24 @@ static void serial_dl_write(struct uart_8250_port *up, int value)
else
_serial_dl_write(up, value);
}
+#elif defined (CONFIG_SERIAL_8250_RM9K)
+static int serial_dl_read(struct uart_8250_port *up)
+{
+ return (up->port.iotype == UPIO_RM9000) ?
+ (((__raw_readl(up->port.membase + 0x10) << 8) |
+ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
+ _serial_dl_read(up);
+}
+
+static void serial_dl_write(struct uart_8250_port *up, int value)
+{
+ if (up->port.iotype == UPIO_RM9000) {
+ __raw_writel(value, up->port.membase + 0x08);
+ __raw_writel(value >> 8, up->port.membase + 0x10);
+ } else {
+ _serial_dl_write(up, value);
+ }
+}
#else
#define serial_dl_read(up) _serial_dl_read(up)
#define serial_dl_write(up, value) _serial_dl_write(up, value)
@@ -621,7 +702,7 @@ static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p)
* its clones. (We treat the broken original StarTech 16650 V1 as a
* 16550, and why not? Startech doesn't seem to even acknowledge its
* existence.)
- *
+ *
* What evil have men's minds wrought...
*/
static void autoconfig_has_efr(struct uart_8250_port *up)
@@ -674,7 +755,7 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
up->bugs |= UART_BUG_QUOT;
return;
}
-
+
/*
* We check for a XR16C850 by setting DLL and DLM to 0, and then
* reading back DLL and DLM. The chip type depends on the DLM
@@ -817,7 +898,7 @@ static void autoconfig_16550a(struct uart_8250_port *up)
status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
status1 |= 0x10; /* 1.625 divisor for baud_base --> 921600 */
serial_outp(up, 0x04, status1);
-
+
serial_dl_write(up, quot);
serial_outp(up, UART_LCR, 0);
@@ -913,7 +994,6 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
* be frobbing the chips IRQ enable register to see if it exists.
*/
spin_lock_irqsave(&up->port.lock, flags);
-// save_flags(flags); cli();
up->capabilities = 0;
up->bugs = 0;
@@ -922,7 +1002,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
/*
* Do a simple existence test first; if we fail this,
* there's no point trying anything else.
- *
+ *
* 0x80 is used as a nonsense port to prevent against
* false positives due to ISA bus float. The
* assumption is that 0x80 is a non-existent port;
@@ -961,7 +1041,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
save_mcr = serial_in(up, UART_MCR);
save_lcr = serial_in(up, UART_LCR);
- /*
+ /*
* Check to see if a UART is really there. Certain broken
* internal modems based on the Rockwell chipset fail this
* test, because they apparently don't implement the loopback
@@ -1068,9 +1148,8 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
else
serial_outp(up, UART_IER, 0);
- out:
+ out:
spin_unlock_irqrestore(&up->port.lock, flags);
-// restore_flags(flags);
DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
}
@@ -1094,7 +1173,7 @@ static void autoconfig_irq(struct uart_8250_port *up)
save_mcr = serial_inp(up, UART_MCR);
save_ier = serial_inp(up, UART_IER);
serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
-
+
irqs = probe_irq_on();
serial_outp(up, UART_MCR, 0);
udelay (10);
@@ -1159,8 +1238,11 @@ static void serial8250_start_tx(struct uart_port *port)
if (up->bugs & UART_BUG_TXEN) {
unsigned char lsr, iir;
lsr = serial_in(up, UART_LSR);
- iir = serial_in(up, UART_IIR);
- if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)
+ iir = serial_in(up, UART_IIR) & 0x0f;
+ if ((up->port.type == PORT_RM9000) ?
+ (lsr & UART_LSR_THRE &&
+ (iir == UART_IIR_NO_INT || iir == UART_IIR_THRI)) :
+ (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT))
transmit_chars(up);
}
}
@@ -1389,6 +1471,19 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
handled = 1;
end = NULL;
+ } else if (up->port.iotype == UPIO_DWAPB &&
+ (iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
+ /* The DesignWare APB UART has an Busy Detect (0x07)
+ * interrupt meaning an LCR write attempt occured while the
+ * UART was busy. The interrupt must be cleared by reading
+ * the UART status register (USR) and the LCR re-written. */
+ unsigned int status;
+ status = *(volatile u32 *)up->port.private_data;
+ serial_out(up, UART_LCR, up->lcr);
+
+ handled = 1;
+
+ end = NULL;
} else if (end == NULL)
end = l;
@@ -1928,7 +2023,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = serial8250_get_divisor(port, baud);
/*
@@ -2090,6 +2185,7 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM:
+ case UPIO_DWAPB:
if (!up->port.mapbase)
break;
@@ -2127,6 +2223,7 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_TSI:
case UPIO_MEM32:
case UPIO_MEM:
+ case UPIO_DWAPB:
if (!up->port.mapbase)
break;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ad9f321968e..e8efe938c4e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -73,17 +73,21 @@ config SERIAL_8250_PCI
depends on SERIAL_8250 && PCI
default SERIAL_8250
help
- This builds standard PCI serial support. You may be able to
- disable this feature if you only need legacy serial support.
- Saves about 9K.
+ Say Y here if you have PCI serial ports.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_pci.
config SERIAL_8250_PNP
tristate "8250/16550 PNP device support" if EMBEDDED
depends on SERIAL_8250 && PNP
default SERIAL_8250
help
- This builds standard PNP serial support. You may be able to
- disable this feature if you only need legacy serial support.
+ Say Y here if you have serial ports described by PNPBIOS or ACPI.
+ These are typically ports built into the system board.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_pnp.
config SERIAL_8250_HP300
tristate
@@ -254,6 +258,15 @@ config SERIAL_8250_AU1X00
to this option. The driver can handle 1 or 2 serial ports.
If unsure, say N.
+config SERIAL_8250_RM9K
+ bool "Support for MIPS RM9xxx integrated serial port"
+ depends on SERIAL_8250 != n && SERIAL_RM9000
+ select SERIAL_8250_SHARE_IRQ
+ help
+ Selecting this option will add support for the integrated serial
+ port hardware found on MIPS RM9122 and similar processors.
+ If unsure, say N.
+
comment "Non-8250 serial port support"
config SERIAL_AMBA_PL010
@@ -499,6 +512,100 @@ config SERIAL_SA1100_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_BFIN
+ tristate "Blackfin serial port support"
+ depends on BFIN
+ select SERIAL_CORE
+ select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561)
+ help
+ Add support for the built-in UARTs on the Blackfin.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_5xx.
+
+config SERIAL_BFIN_CONSOLE
+ bool "Console on Blackfin serial port"
+ depends on SERIAL_BFIN
+ select SERIAL_CORE_CONSOLE
+
+choice
+ prompt "UART Mode"
+ depends on SERIAL_BFIN
+ default SERIAL_BFIN_DMA
+ help
+ This driver supports the built-in serial ports of the Blackfin family
+ of CPUs
+
+config SERIAL_BFIN_DMA
+ bool "DMA mode"
+ depends on DMA_UNCACHED_1M
+ help
+ This driver works under DMA mode. If this option is selected, the
+ blackfin simple dma driver is also enabled.
+
+config SERIAL_BFIN_PIO
+ bool "PIO mode"
+ help
+ This driver works under PIO mode.
+
+endchoice
+
+config SERIAL_BFIN_UART0
+ bool "Enable UART0"
+ depends on SERIAL_BFIN
+ help
+ Enable UART0
+
+config BFIN_UART0_CTSRTS
+ bool "Enable UART0 hardware flow control"
+ depends on SERIAL_BFIN_UART0
+ help
+ Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
+ signal.
+
+config UART0_CTS_PIN
+ int "UART0 CTS pin"
+ depends on BFIN_UART0_CTSRTS
+ default 23
+ help
+ The default pin is GPIO_GP7.
+ Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config UART0_RTS_PIN
+ int "UART0 RTS pin"
+ depends on BFIN_UART0_CTSRTS
+ default 22
+ help
+ The default pin is GPIO_GP6.
+ Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config SERIAL_BFIN_UART1
+ bool "Enable UART1"
+ depends on SERIAL_BFIN && (BF534 || BF536 || BF537)
+ help
+ Enable UART1
+
+config BFIN_UART1_CTSRTS
+ bool "Enable UART1 hardware flow control"
+ depends on SERIAL_BFIN_UART1
+ help
+ Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
+ signal.
+
+config UART1_CTS_PIN
+ int "UART1 CTS pin"
+ depends on BFIN_UART1_CTSRTS
+ default -1
+ help
+ Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config UART1_RTS_PIN
+ int "UART1 RTS pin"
+ depends on BFIN_UART1_CTSRTS
+ default -1
+ help
+ Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
config SERIAL_IMX
bool "IMX serial port support"
depends on ARM && ARCH_IMX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 6b3560c5749..4959bcb8d1e 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
obj-$(CONFIG_SERIAL_PXA) += pxa.o
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
+obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index f69bd097166..1a9a24b8263 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -48,6 +48,7 @@
#include <linux/serial.h>
#include <linux/amba/bus.h>
#include <linux/amba/serial.h>
+#include <linux/clk.h>
#include <asm/io.h>
@@ -70,6 +71,7 @@
*/
struct uart_amba_port {
struct uart_port port;
+ struct clk *clk;
struct amba_device *dev;
struct amba_pl010_data *data;
unsigned int old_status;
@@ -77,73 +79,77 @@ struct uart_amba_port {
static void pl010_stop_tx(struct uart_port *port)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
- cr = readb(port->membase + UART010_CR);
+ cr = readb(uap->port.membase + UART010_CR);
cr &= ~UART010_CR_TIE;
- writel(cr, port->membase + UART010_CR);
+ writel(cr, uap->port.membase + UART010_CR);
}
static void pl010_start_tx(struct uart_port *port)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
- cr = readb(port->membase + UART010_CR);
+ cr = readb(uap->port.membase + UART010_CR);
cr |= UART010_CR_TIE;
- writel(cr, port->membase + UART010_CR);
+ writel(cr, uap->port.membase + UART010_CR);
}
static void pl010_stop_rx(struct uart_port *port)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
- cr = readb(port->membase + UART010_CR);
+ cr = readb(uap->port.membase + UART010_CR);
cr &= ~(UART010_CR_RIE | UART010_CR_RTIE);
- writel(cr, port->membase + UART010_CR);
+ writel(cr, uap->port.membase + UART010_CR);
}
static void pl010_enable_ms(struct uart_port *port)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
- cr = readb(port->membase + UART010_CR);
+ cr = readb(uap->port.membase + UART010_CR);
cr |= UART010_CR_MSIE;
- writel(cr, port->membase + UART010_CR);
+ writel(cr, uap->port.membase + UART010_CR);
}
-static void pl010_rx_chars(struct uart_port *port)
+static void pl010_rx_chars(struct uart_amba_port *uap)
{
- struct tty_struct *tty = port->info->tty;
+ struct tty_struct *tty = uap->port.info->tty;
unsigned int status, ch, flag, rsr, max_count = 256;
- status = readb(port->membase + UART01x_FR);
+ status = readb(uap->port.membase + UART01x_FR);
while (UART_RX_DATA(status) && max_count--) {
- ch = readb(port->membase + UART01x_DR);
+ ch = readb(uap->port.membase + UART01x_DR);
flag = TTY_NORMAL;
- port->icount.rx++;
+ uap->port.icount.rx++;
/*
* Note that the error handling code is
* out of the main execution path
*/
- rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
+ rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX;
if (unlikely(rsr & UART01x_RSR_ANY)) {
- writel(0, port->membase + UART01x_ECR);
+ writel(0, uap->port.membase + UART01x_ECR);
if (rsr & UART01x_RSR_BE) {
rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE);
- port->icount.brk++;
- if (uart_handle_break(port))
+ uap->port.icount.brk++;
+ if (uart_handle_break(&uap->port))
goto ignore_char;
} else if (rsr & UART01x_RSR_PE)
- port->icount.parity++;
+ uap->port.icount.parity++;
else if (rsr & UART01x_RSR_FE)
- port->icount.frame++;
+ uap->port.icount.frame++;
if (rsr & UART01x_RSR_OE)
- port->icount.overrun++;
+ uap->port.icount.overrun++;
- rsr &= port->read_status_mask;
+ rsr &= uap->port.read_status_mask;
if (rsr & UART01x_RSR_BE)
flag = TTY_BREAK;
@@ -153,53 +159,52 @@ static void pl010_rx_chars(struct uart_port *port)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(port, ch))
+ if (uart_handle_sysrq_char(&uap->port, ch))
goto ignore_char;
- uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
+ uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag);
ignore_char:
- status = readb(port->membase + UART01x_FR);
+ status = readb(uap->port.membase + UART01x_FR);
}
tty_flip_buffer_push(tty);
return;
}
-static void pl010_tx_chars(struct uart_port *port)
+static void pl010_tx_chars(struct uart_amba_port *uap)
{
- struct circ_buf *xmit = &port->info->xmit;
+ struct circ_buf *xmit = &uap->port.info->xmit;
int count;
- if (port->x_char) {
- writel(port->x_char, port->membase + UART01x_DR);
- port->icount.tx++;
- port->x_char = 0;
+ if (uap->port.x_char) {
+ writel(uap->port.x_char, uap->port.membase + UART01x_DR);
+ uap->port.icount.tx++;
+ uap->port.x_char = 0;
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- pl010_stop_tx(port);
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+ pl010_stop_tx(&uap->port);
return;
}
- count = port->fifosize >> 1;
+ count = uap->port.fifosize >> 1;
do {
- writel(xmit->buf[xmit->tail], port->membase + UART01x_DR);
+ writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
+ uap->port.icount.tx++;
if (uart_circ_empty(xmit))
break;
} while (--count > 0);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
+ uart_write_wakeup(&uap->port);
if (uart_circ_empty(xmit))
- pl010_stop_tx(port);
+ pl010_stop_tx(&uap->port);
}
-static void pl010_modem_status(struct uart_port *port)
+static void pl010_modem_status(struct uart_amba_port *uap)
{
- struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status, delta;
writel(0, uap->port.membase + UART010_ICR);
@@ -226,47 +231,50 @@ static void pl010_modem_status(struct uart_port *port)
static irqreturn_t pl010_int(int irq, void *dev_id)
{
- struct uart_port *port = dev_id;
+ struct uart_amba_port *uap = dev_id;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
- spin_lock(&port->lock);
+ spin_lock(&uap->port.lock);
- status = readb(port->membase + UART010_IIR);
+ status = readb(uap->port.membase + UART010_IIR);
if (status) {
do {
if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
- pl010_rx_chars(port);
+ pl010_rx_chars(uap);
if (status & UART010_IIR_MIS)
- pl010_modem_status(port);
+ pl010_modem_status(uap);
if (status & UART010_IIR_TIS)
- pl010_tx_chars(port);
+ pl010_tx_chars(uap);
if (pass_counter-- == 0)
break;
- status = readb(port->membase + UART010_IIR);
+ status = readb(uap->port.membase + UART010_IIR);
} while (status & (UART010_IIR_RTIS | UART010_IIR_RIS |
UART010_IIR_TIS));
handled = 1;
}
- spin_unlock(&port->lock);
+ spin_unlock(&uap->port.lock);
return IRQ_RETVAL(handled);
}
static unsigned int pl010_tx_empty(struct uart_port *port)
{
- return readb(port->membase + UART01x_FR) & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+ unsigned int status = readb(uap->port.membase + UART01x_FR);
+ return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT;
}
static unsigned int pl010_get_mctrl(struct uart_port *port)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int result = 0;
unsigned int status;
- status = readb(port->membase + UART01x_FR);
+ status = readb(uap->port.membase + UART01x_FR);
if (status & UART01x_FR_DCD)
result |= TIOCM_CAR;
if (status & UART01x_FR_DSR)
@@ -287,17 +295,18 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void pl010_break_ctl(struct uart_port *port, int break_state)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned long flags;
unsigned int lcr_h;
- spin_lock_irqsave(&port->lock, flags);
- lcr_h = readb(port->membase + UART010_LCRH);
+ spin_lock_irqsave(&uap->port.lock, flags);
+ lcr_h = readb(uap->port.membase + UART010_LCRH);
if (break_state == -1)
lcr_h |= UART01x_LCRH_BRK;
else
lcr_h &= ~UART01x_LCRH_BRK;
- writel(lcr_h, port->membase + UART010_LCRH);
- spin_unlock_irqrestore(&port->lock, flags);
+ writel(lcr_h, uap->port.membase + UART010_LCRH);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
}
static int pl010_startup(struct uart_port *port)
@@ -306,48 +315,70 @@ static int pl010_startup(struct uart_port *port)
int retval;
/*
+ * Try to enable the clock producer.
+ */
+ retval = clk_enable(uap->clk);
+ if (retval)
+ goto out;
+
+ uap->port.uartclk = clk_get_rate(uap->clk);
+
+ /*
* Allocate the IRQ
*/
- retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", port);
+ retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap);
if (retval)
- return retval;
+ goto clk_dis;
/*
* initialise the old status of the modem signals
*/
- uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
+ uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY;
/*
* Finally, enable interrupts
*/
writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE,
- port->membase + UART010_CR);
+ uap->port.membase + UART010_CR);
return 0;
+
+ clk_dis:
+ clk_disable(uap->clk);
+ out:
+ return retval;
}
static void pl010_shutdown(struct uart_port *port)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
+
/*
* Free the interrupt
*/
- free_irq(port->irq, port);
+ free_irq(uap->port.irq, uap);
/*
* disable all interrupts, disable the port
*/
- writel(0, port->membase + UART010_CR);
+ writel(0, uap->port.membase + UART010_CR);
/* disable break condition and fifos */
- writel(readb(port->membase + UART010_LCRH) &
+ writel(readb(uap->port.membase + UART010_LCRH) &
~(UART01x_LCRH_BRK | UART01x_LCRH_FEN),
- port->membase + UART010_LCRH);
+ uap->port.membase + UART010_LCRH);
+
+ /*
+ * Shut down the clock producer
+ */
+ clk_disable(uap->clk);
}
static void
pl010_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int lcr_h, old_cr;
unsigned long flags;
unsigned int baud, quot;
@@ -355,7 +386,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
/*
* Ask the core to calculate the divisor for us.
*/
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
@@ -379,66 +410,66 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios,
if (!(termios->c_cflag & PARODD))
lcr_h |= UART01x_LCRH_EPS;
}
- if (port->fifosize > 1)
+ if (uap->port.fifosize > 1)
lcr_h |= UART01x_LCRH_FEN;
- spin_lock_irqsave(&port->lock, flags);
+ spin_lock_irqsave(&uap->port.lock, flags);
/*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
- port->read_status_mask = UART01x_RSR_OE;
+ uap->port.read_status_mask = UART01x_RSR_OE;
if (termios->c_iflag & INPCK)
- port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+ uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
if (termios->c_iflag & (BRKINT | PARMRK))
- port->read_status_mask |= UART01x_RSR_BE;
+ uap->port.read_status_mask |= UART01x_RSR_BE;
/*
* Characters to ignore
*/
- port->ignore_status_mask = 0;
+ uap->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
+ uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE;
if (termios->c_iflag & IGNBRK) {
- port->ignore_status_mask |= UART01x_RSR_BE;
+ uap->port.ignore_status_mask |= UART01x_RSR_BE;
/*
* If we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART01x_RSR_OE;
+ uap->port.ignore_status_mask |= UART01x_RSR_OE;
}
/*
* Ignore all characters if CREAD is not set.
*/
if ((termios->c_cflag & CREAD) == 0)
- port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+ uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX;
/* first, disable everything */
- old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE;
+ old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE;
if (UART_ENABLE_MS(port, termios->c_cflag))
old_cr |= UART010_CR_MSIE;
- writel(0, port->membase + UART010_CR);
+ writel(0, uap->port.membase + UART010_CR);
/* Set baud rate */
quot -= 1;
- writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM);
- writel(quot & 0xff, port->membase + UART010_LCRL);
+ writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM);
+ writel(quot & 0xff, uap->port.membase + UART010_LCRL);
/*
* ----------v----------v----------v----------v-----
* NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
* ----------^----------^----------^----------^-----
*/
- writel(lcr_h, port->membase + UART010_LCRH);
- writel(old_cr, port->membase + UART010_CR);
+ writel(lcr_h, uap->port.membase + UART010_LCRH);
+ writel(old_cr, uap->port.membase + UART010_CR);
- spin_unlock_irqrestore(&port->lock, flags);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
}
static const char *pl010_type(struct uart_port *port)
@@ -514,47 +545,52 @@ static struct uart_amba_port *amba_ports[UART_NR];
static void pl010_console_putchar(struct uart_port *port, int ch)
{
+ struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int status;
do {
- status = readb(port->membase + UART01x_FR);
+ status = readb(uap->port.membase + UART01x_FR);
barrier();
} while (!UART_TX_READY(status));
- writel(ch, port->membase + UART01x_DR);
+ writel(ch, uap->port.membase + UART01x_DR);
}
static void
pl010_console_write(struct console *co, const char *s, unsigned int count)
{
- struct uart_port *port = &amba_ports[co->index]->port;
+ struct uart_amba_port *uap = amba_ports[co->index];
unsigned int status, old_cr;
+ clk_enable(uap->clk);
+
/*
* First save the CR then disable the interrupts
*/
- old_cr = readb(port->membase + UART010_CR);
- writel(UART01x_CR_UARTEN, port->membase + UART010_CR);
+ old_cr = readb(uap->port.membase + UART010_CR);
+ writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR);
- uart_console_write(port, s, count, pl010_console_putchar);
+ uart_console_write(&uap->port, s, count, pl010_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore the TCR
*/
do {
- status = readb(port->membase + UART01x_FR);
+ status = readb(uap->port.membase + UART01x_FR);
barrier();
} while (status & UART01x_FR_BUSY);
- writel(old_cr, port->membase + UART010_CR);
+ writel(old_cr, uap->port.membase + UART010_CR);
+
+ clk_disable(uap->clk);
}
static void __init
-pl010_console_get_options(struct uart_port *port, int *baud,
+pl010_console_get_options(struct uart_amba_port *uap, int *baud,
int *parity, int *bits)
{
- if (readb(port->membase + UART010_CR) & UART01x_CR_UARTEN) {
+ if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) {
unsigned int lcr_h, quot;
- lcr_h = readb(port->membase + UART010_LCRH);
+ lcr_h = readb(uap->port.membase + UART010_LCRH);
*parity = 'n';
if (lcr_h & UART01x_LCRH_PEN) {
@@ -569,14 +605,15 @@ pl010_console_get_options(struct uart_port *port, int *baud,
else
*bits = 8;
- quot = readb(port->membase + UART010_LCRL) | readb(port->membase + UART010_LCRM) << 8;
- *baud = port->uartclk / (16 * (quot + 1));
+ quot = readb(uap->port.membase + UART010_LCRL) |
+ readb(uap->port.membase + UART010_LCRM) << 8;
+ *baud = uap->port.uartclk / (16 * (quot + 1));
}
}
static int __init pl010_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
+ struct uart_amba_port *uap;
int baud = 38400;
int bits = 8;
int parity = 'n';
@@ -589,16 +626,18 @@ static int __init pl010_console_setup(struct console *co, char *options)
*/
if (co->index >= UART_NR)
co->index = 0;
- if (!amba_ports[co->index])
+ uap = amba_ports[co->index];
+ if (!uap)
return -ENODEV;
- port = &amba_ports[co->index]->port;
+
+ uap->port.uartclk = clk_get_rate(uap->clk);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- pl010_console_get_options(port, &baud, &parity, &bits);
+ pl010_console_get_options(uap, &baud, &parity, &bits);
- return uart_set_options(port, co, baud, parity, bits, flow);
+ return uart_set_options(&uap->port, co, baud, parity, bits, flow);
}
static struct uart_driver amba_reg;
@@ -629,7 +668,7 @@ static struct uart_driver amba_reg = {
static int pl010_probe(struct amba_device *dev, void *id)
{
- struct uart_amba_port *port;
+ struct uart_amba_port *uap;
void __iomem *base;
int i, ret;
@@ -642,8 +681,8 @@ static int pl010_probe(struct amba_device *dev, void *id)
goto out;
}
- port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
- if (!port) {
+ uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+ if (!uap) {
ret = -ENOMEM;
goto out;
}
@@ -654,51 +693,57 @@ static int pl010_probe(struct amba_device *dev, void *id)
goto free;
}
- port->port.dev = &dev->dev;
- port->port.mapbase = dev->res.start;
- port->port.membase = base;
- port->port.iotype = UPIO_MEM;
- port->port.irq = dev->irq[0];
- port->port.uartclk = 14745600;
- port->port.fifosize = 16;
- port->port.ops = &amba_pl010_pops;
- port->port.flags = UPF_BOOT_AUTOCONF;
- port->port.line = i;
- port->dev = dev;
- port->data = dev->dev.platform_data;
-
- amba_ports[i] = port;
-
- amba_set_drvdata(dev, port);
- ret = uart_add_one_port(&amba_reg, &port->port);
+ uap->clk = clk_get(&dev->dev, "UARTCLK");
+ if (IS_ERR(uap->clk)) {
+ ret = PTR_ERR(uap->clk);
+ goto unmap;
+ }
+
+ uap->port.dev = &dev->dev;
+ uap->port.mapbase = dev->res.start;
+ uap->port.membase = base;
+ uap->port.iotype = UPIO_MEM;
+ uap->port.irq = dev->irq[0];
+ uap->port.fifosize = 16;
+ uap->port.ops = &amba_pl010_pops;
+ uap->port.flags = UPF_BOOT_AUTOCONF;
+ uap->port.line = i;
+ uap->dev = dev;
+ uap->data = dev->dev.platform_data;
+
+ amba_ports[i] = uap;
+
+ amba_set_drvdata(dev, uap);
+ ret = uart_add_one_port(&amba_reg, &uap->port);
if (ret) {
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
+ clk_put(uap->clk);
+ unmap:
iounmap(base);
free:
- kfree(port);
+ kfree(uap);
}
-
out:
return ret;
}
static int pl010_remove(struct amba_device *dev)
{
- struct uart_amba_port *port = amba_get_drvdata(dev);
+ struct uart_amba_port *uap = amba_get_drvdata(dev);
int i;
amba_set_drvdata(dev, NULL);
- uart_remove_one_port(&amba_reg, &port->port);
+ uart_remove_one_port(&amba_reg, &uap->port);
for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
- if (amba_ports[i] == port)
+ if (amba_ports[i] == uap)
amba_ports[i] = NULL;
- iounmap(port->port.membase);
- kfree(port);
-
+ iounmap(uap->port.membase);
+ clk_put(uap->clk);
+ kfree(uap);
return 0;
}
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 935f48fa501..3320bcd92c0 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -484,11 +484,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios,
unsigned long flags;
unsigned int mode, imr, quot, baud;
+ /* Get current mode register */
+ mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
- /* Get current mode register */
- mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+ if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */
+ quot /= 8;
+ mode |= ATMEL_US_USCLKS_MCK_DIV8;
+ }
/* byte size */
switch (termios->c_cflag & CSIZE) {
diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
index 11b44360e10..e0141776517 100644
--- a/drivers/serial/atmel_serial.h
+++ b/drivers/serial/atmel_serial.h
@@ -46,6 +46,9 @@
#define ATMEL_US_USMODE_ISO7816_T1 6
#define ATMEL_US_USMODE_IRDA 8
#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */
+#define ATMEL_US_USCLKS_MCK (0 << 4)
+#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4)
+#define ATMEL_US_USCLKS_SCK (3 << 4)
#define ATMEL_US_CHRL (3 << 6) /* Character Length */
#define ATMEL_US_CHRL_5 (0 << 6)
#define ATMEL_US_CHRL_6 (1 << 6)
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
new file mode 100644
index 00000000000..408390f93db
--- /dev/null
+++ b/drivers/serial/bfin_5xx.c
@@ -0,0 +1,1012 @@
+/*
+ * File: drivers/serial/bfin_5xx.c
+ * Based on: Based on drivers/serial/sa1100.c
+ * Author: Aubrey Li <aubrey.li@analog.com>
+ *
+ * Created:
+ * Description: Driver for blackfin 5xx serial ports
+ *
+ * Rev: $Id: bfin_5xx.c,v 1.19 2006/09/24 02:33:53 aubrey Exp $
+ *
+ * Modified:
+ * Copyright 2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/gpio.h>
+#include <asm/mach/bfin_serial_5xx.h>
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+#include <linux/dma-mapping.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/cacheflush.h>
+#endif
+
+/* UART name and device definitions */
+#define BFIN_SERIAL_NAME "ttyBF"
+#define BFIN_SERIAL_MAJOR 204
+#define BFIN_SERIAL_MINOR 64
+
+/*
+ * Setup for console. Argument comes from the menuconfig
+ */
+#define DMA_RX_XCOUNT 512
+#define DMA_RX_YCOUNT (PAGE_SIZE / DMA_RX_XCOUNT)
+
+#define DMA_RX_FLUSH_JIFFIES 5
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart);
+#else
+static void bfin_serial_do_work(struct work_struct *work);
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
+static void local_put_char(struct bfin_serial_port *uart, char ch);
+#endif
+
+static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
+
+/*
+ * interrupts are disabled on entry
+ */
+static void bfin_serial_stop_tx(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ disable_dma(uart->tx_dma_channel);
+#else
+ unsigned short ier;
+
+ ier = UART_GET_IER(uart);
+ ier &= ~ETBEI;
+ UART_PUT_IER(uart, ier);
+#endif
+}
+
+/*
+ * port is locked and interrupts are disabled
+ */
+static void bfin_serial_start_tx(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ bfin_serial_dma_tx_chars(uart);
+#else
+ unsigned short ier;
+ ier = UART_GET_IER(uart);
+ ier |= ETBEI;
+ UART_PUT_IER(uart, ier);
+ bfin_serial_tx_chars(uart);
+#endif
+}
+
+/*
+ * Interrupts are enabled
+ */
+static void bfin_serial_stop_rx(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ unsigned short ier;
+
+ ier = UART_GET_IER(uart);
+ ier &= ~ERBFI;
+ UART_PUT_IER(uart, ier);
+}
+
+/*
+ * Set the modem control timer to fire immediately.
+ */
+static void bfin_serial_enable_ms(struct uart_port *port)
+{
+}
+
+#ifdef CONFIG_SERIAL_BFIN_PIO
+static void local_put_char(struct bfin_serial_port *uart, char ch)
+{
+ unsigned short status;
+ int flags = 0;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+
+ do {
+ status = UART_GET_LSR(uart);
+ } while (!(status & THRE));
+
+ UART_PUT_CHAR(uart, ch);
+ SSYNC();
+
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
+{
+ struct tty_struct *tty = uart->port.info?uart->port.info->tty:0;
+ unsigned int status, ch, flg;
+#ifdef BF533_FAMILY
+ static int in_break = 0;
+#endif
+
+ status = UART_GET_LSR(uart);
+ ch = UART_GET_CHAR(uart);
+ uart->port.icount.rx++;
+
+#ifdef BF533_FAMILY
+ /* The BF533 family of processors have a nice misbehavior where
+ * they continuously generate characters for a "single" break.
+ * We have to basically ignore this flood until the "next" valid
+ * character comes across. All other Blackfin families operate
+ * properly though.
+ */
+ if (in_break) {
+ if (ch != 0) {
+ in_break = 0;
+ ch = UART_GET_CHAR(uart);
+ }
+ return;
+ }
+#endif
+
+ if (status & BI) {
+#ifdef BF533_FAMILY
+ in_break = 1;
+#endif
+ uart->port.icount.brk++;
+ if (uart_handle_break(&uart->port))
+ goto ignore_char;
+ flg = TTY_BREAK;
+ } else if (status & PE) {
+ flg = TTY_PARITY;
+ uart->port.icount.parity++;
+ } else if (status & OE) {
+ flg = TTY_OVERRUN;
+ uart->port.icount.overrun++;
+ } else if (status & FE) {
+ flg = TTY_FRAME;
+ uart->port.icount.frame++;
+ } else
+ flg = TTY_NORMAL;
+
+ if (uart_handle_sysrq_char(&uart->port, ch))
+ goto ignore_char;
+ if (tty)
+ uart_insert_char(&uart->port, status, 2, ch, flg);
+
+ignore_char:
+ if (tty)
+ tty_flip_buffer_push(tty);
+}
+
+static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
+{
+ struct circ_buf *xmit = &uart->port.info->xmit;
+
+ if (uart->port.x_char) {
+ UART_PUT_CHAR(uart, uart->port.x_char);
+ uart->port.icount.tx++;
+ uart->port.x_char = 0;
+ return;
+ }
+ /*
+ * Check the modem control lines before
+ * transmitting anything.
+ */
+ bfin_serial_mctrl_check(uart);
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+ bfin_serial_stop_tx(&uart->port);
+ return;
+ }
+
+ local_put_char(uart, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ uart->port.icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&uart->port);
+
+ if (uart_circ_empty(xmit))
+ bfin_serial_stop_tx(&uart->port);
+}
+
+static irqreturn_t bfin_serial_int(int irq, void *dev_id)
+{
+ struct bfin_serial_port *uart = dev_id;
+ unsigned short status;
+
+ spin_lock(&uart->port.lock);
+ status = UART_GET_IIR(uart);
+ do {
+ if ((status & IIR_STATUS) == IIR_TX_READY)
+ bfin_serial_tx_chars(uart);
+ if ((status & IIR_STATUS) == IIR_RX_READY)
+ bfin_serial_rx_chars(uart);
+ status = UART_GET_IIR(uart);
+ } while (status & (IIR_TX_READY | IIR_RX_READY));
+ spin_unlock(&uart->port.lock);
+ return IRQ_HANDLED;
+}
+
+static void bfin_serial_do_work(struct work_struct *work)
+{
+ struct bfin_serial_port *uart = container_of(work, struct bfin_serial_port, cts_workqueue);
+
+ bfin_serial_mctrl_check(uart);
+}
+
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
+{
+ struct circ_buf *xmit = &uart->port.info->xmit;
+ unsigned short ier;
+ int flags = 0;
+
+ if (!uart->tx_done)
+ return;
+
+ uart->tx_done = 0;
+
+ if (uart->port.x_char) {
+ UART_PUT_CHAR(uart, uart->port.x_char);
+ uart->port.icount.tx++;
+ uart->port.x_char = 0;
+ uart->tx_done = 1;
+ return;
+ }
+ /*
+ * Check the modem control lines before
+ * transmitting anything.
+ */
+ bfin_serial_mctrl_check(uart);
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
+ bfin_serial_stop_tx(&uart->port);
+ uart->tx_done = 1;
+ return;
+ }
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ uart->tx_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ if (uart->tx_count > (UART_XMIT_SIZE - xmit->tail))
+ uart->tx_count = UART_XMIT_SIZE - xmit->tail;
+ blackfin_dcache_flush_range((unsigned long)(xmit->buf+xmit->tail),
+ (unsigned long)(xmit->buf+xmit->tail+uart->tx_count));
+ set_dma_config(uart->tx_dma_channel,
+ set_bfin_dma_config(DIR_READ, DMA_FLOW_STOP,
+ INTR_ON_BUF,
+ DIMENSION_LINEAR,
+ DATA_SIZE_8));
+ set_dma_start_addr(uart->tx_dma_channel, (unsigned long)(xmit->buf+xmit->tail));
+ set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
+ set_dma_x_modify(uart->tx_dma_channel, 1);
+ enable_dma(uart->tx_dma_channel);
+ ier = UART_GET_IER(uart);
+ ier |= ETBEI;
+ UART_PUT_IER(uart, ier);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static void bfin_serial_dma_rx_chars(struct bfin_serial_port * uart)
+{
+ struct tty_struct *tty = uart->port.info->tty;
+ int i, flg, status;
+
+ status = UART_GET_LSR(uart);
+ uart->port.icount.rx += CIRC_CNT(uart->rx_dma_buf.head, uart->rx_dma_buf.tail, UART_XMIT_SIZE);;
+
+ if (status & BI) {
+ uart->port.icount.brk++;
+ if (uart_handle_break(&uart->port))
+ goto dma_ignore_char;
+ flg = TTY_BREAK;
+ } else if (status & PE) {
+ flg = TTY_PARITY;
+ uart->port.icount.parity++;
+ } else if (status & OE) {
+ flg = TTY_OVERRUN;
+ uart->port.icount.overrun++;
+ } else if (status & FE) {
+ flg = TTY_FRAME;
+ uart->port.icount.frame++;
+ } else
+ flg = TTY_NORMAL;
+
+ for (i = uart->rx_dma_buf.head; i < uart->rx_dma_buf.tail; i++) {
+ if (uart_handle_sysrq_char(&uart->port, uart->rx_dma_buf.buf[i]))
+ goto dma_ignore_char;
+ uart_insert_char(&uart->port, status, 2, uart->rx_dma_buf.buf[i], flg);
+ }
+dma_ignore_char:
+ tty_flip_buffer_push(tty);
+}
+
+void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
+{
+ int x_pos, pos;
+ int flags = 0;
+
+ bfin_serial_dma_tx_chars(uart);
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ x_pos = DMA_RX_XCOUNT - get_dma_curr_xcount(uart->rx_dma_channel);
+ if (x_pos == DMA_RX_XCOUNT)
+ x_pos = 0;
+
+ pos = uart->rx_dma_nrows * DMA_RX_XCOUNT + x_pos;
+
+ if (pos>uart->rx_dma_buf.tail) {
+ uart->rx_dma_buf.tail = pos;
+ bfin_serial_dma_rx_chars(uart);
+ uart->rx_dma_buf.head = uart->rx_dma_buf.tail;
+ }
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+ uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
+ add_timer(&(uart->rx_dma_timer));
+}
+
+static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
+{
+ struct bfin_serial_port *uart = dev_id;
+ struct circ_buf *xmit = &uart->port.info->xmit;
+ unsigned short ier;
+
+ spin_lock(&uart->port.lock);
+ if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
+ clear_dma_irqstat(uart->tx_dma_channel);
+ disable_dma(uart->tx_dma_channel);
+ ier = UART_GET_IER(uart);
+ ier &= ~ETBEI;
+ UART_PUT_IER(uart, ier);
+ xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1);
+ uart->port.icount.tx+=uart->tx_count;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&uart->port);
+
+ if (uart_circ_empty(xmit))
+ bfin_serial_stop_tx(&uart->port);
+ uart->tx_done = 1;
+ }
+
+ spin_unlock(&uart->port.lock);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
+{
+ struct bfin_serial_port *uart = dev_id;
+ unsigned short irqstat;
+
+ uart->rx_dma_nrows++;
+ if (uart->rx_dma_nrows == DMA_RX_YCOUNT) {
+ uart->rx_dma_nrows = 0;
+ uart->rx_dma_buf.tail = DMA_RX_XCOUNT*DMA_RX_YCOUNT;
+ bfin_serial_dma_rx_chars(uart);
+ uart->rx_dma_buf.head = uart->rx_dma_buf.tail = 0;
+ }
+ spin_lock(&uart->port.lock);
+ irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
+ clear_dma_irqstat(uart->rx_dma_channel);
+
+ spin_unlock(&uart->port.lock);
+ return IRQ_HANDLED;
+}
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter is not busy.
+ */
+static unsigned int bfin_serial_tx_empty(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ unsigned short lsr;
+
+ lsr = UART_GET_LSR(uart);
+ if (lsr & TEMT)
+ return TIOCSER_TEMT;
+ else
+ return 0;
+}
+
+static unsigned int bfin_serial_get_mctrl(struct uart_port *port)
+{
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ if (uart->cts_pin < 0)
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+ if (gpio_get_value(uart->cts_pin))
+ return TIOCM_DSR | TIOCM_CAR;
+ else
+#endif
+ return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+}
+
+static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ if (uart->rts_pin < 0)
+ return;
+
+ if (mctrl & TIOCM_RTS)
+ gpio_set_value(uart->rts_pin, 0);
+ else
+ gpio_set_value(uart->rts_pin, 1);
+#endif
+}
+
+/*
+ * Handle any change of modem status signal since we were last called.
+ */
+static void bfin_serial_mctrl_check(struct bfin_serial_port *uart)
+{
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ unsigned int status;
+# ifdef CONFIG_SERIAL_BFIN_DMA
+ struct uart_info *info = uart->port.info;
+ struct tty_struct *tty = info->tty;
+
+ status = bfin_serial_get_mctrl(&uart->port);
+ if (!(status & TIOCM_CTS)) {
+ tty->hw_stopped = 1;
+ } else {
+ tty->hw_stopped = 0;
+ }
+# else
+ status = bfin_serial_get_mctrl(&uart->port);
+ uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
+ if (!(status & TIOCM_CTS))
+ schedule_work(&uart->cts_workqueue);
+# endif
+#endif
+}
+
+/*
+ * Interrupts are always disabled.
+ */
+static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static int bfin_serial_startup(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ dma_addr_t dma_handle;
+
+ if (request_dma(uart->rx_dma_channel, "BFIN_UART_RX") < 0) {
+ printk(KERN_NOTICE "Unable to attach Blackfin UART RX DMA channel\n");
+ return -EBUSY;
+ }
+
+ if (request_dma(uart->tx_dma_channel, "BFIN_UART_TX") < 0) {
+ printk(KERN_NOTICE "Unable to attach Blackfin UART TX DMA channel\n");
+ free_dma(uart->rx_dma_channel);
+ return -EBUSY;
+ }
+
+ set_dma_callback(uart->rx_dma_channel, bfin_serial_dma_rx_int, uart);
+ set_dma_callback(uart->tx_dma_channel, bfin_serial_dma_tx_int, uart);
+
+ uart->rx_dma_buf.buf = (unsigned char *)dma_alloc_coherent(NULL, PAGE_SIZE, &dma_handle, GFP_DMA);
+ uart->rx_dma_buf.head = 0;
+ uart->rx_dma_buf.tail = 0;
+ uart->rx_dma_nrows = 0;
+
+ set_dma_config(uart->rx_dma_channel,
+ set_bfin_dma_config(DIR_WRITE, DMA_FLOW_AUTO,
+ INTR_ON_ROW, DIMENSION_2D,
+ DATA_SIZE_8));
+ set_dma_x_count(uart->rx_dma_channel, DMA_RX_XCOUNT);
+ set_dma_x_modify(uart->rx_dma_channel, 1);
+ set_dma_y_count(uart->rx_dma_channel, DMA_RX_YCOUNT);
+ set_dma_y_modify(uart->rx_dma_channel, 1);
+ set_dma_start_addr(uart->rx_dma_channel, (unsigned long)uart->rx_dma_buf.buf);
+ enable_dma(uart->rx_dma_channel);
+
+ uart->rx_dma_timer.data = (unsigned long)(uart);
+ uart->rx_dma_timer.function = (void *)bfin_serial_rx_dma_timeout;
+ uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
+ add_timer(&(uart->rx_dma_timer));
+#else
+ if (request_irq
+ (uart->port.irq, bfin_serial_int, IRQF_DISABLED,
+ "BFIN_UART_RX", uart)) {
+ printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
+ return -EBUSY;
+ }
+
+ if (request_irq
+ (uart->port.irq+1, bfin_serial_int, IRQF_DISABLED,
+ "BFIN_UART_TX", uart)) {
+ printk(KERN_NOTICE "Unable to attach BlackFin UART TX interrupt\n");
+ free_irq(uart->port.irq, uart);
+ return -EBUSY;
+ }
+#endif
+ UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
+ return 0;
+}
+
+static void bfin_serial_shutdown(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ disable_dma(uart->tx_dma_channel);
+ free_dma(uart->tx_dma_channel);
+ disable_dma(uart->rx_dma_channel);
+ free_dma(uart->rx_dma_channel);
+ del_timer(&(uart->rx_dma_timer));
+#else
+ free_irq(uart->port.irq, uart);
+ free_irq(uart->port.irq+1, uart);
+#endif
+}
+
+static void
+bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ unsigned long flags;
+ unsigned int baud, quot;
+ unsigned short val, ier, lsr, lcr = 0;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS8:
+ lcr = WLS(8);
+ break;
+ case CS7:
+ lcr = WLS(7);
+ break;
+ case CS6:
+ lcr = WLS(6);
+ break;
+ case CS5:
+ lcr = WLS(5);
+ break;
+ default:
+ printk(KERN_ERR "%s: word lengh not supported\n",
+ __FUNCTION__);
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ lcr |= STB;
+ if (termios->c_cflag & PARENB) {
+ lcr |= PEN;
+ if (!(termios->c_cflag & PARODD))
+ lcr |= EPS;
+ }
+
+ /* These controls are not implemented for this port */
+ termios->c_iflag |= INPCK | BRKINT | PARMRK;
+ termios->c_iflag &= ~(IGNPAR | IGNBRK);
+
+ /* These controls are not implemented for this port */
+ termios->c_iflag |= INPCK | BRKINT | PARMRK;
+ termios->c_iflag &= ~(IGNPAR | IGNBRK);
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
+ spin_lock_irqsave(&uart->port.lock, flags);
+
+ do {
+ lsr = UART_GET_LSR(uart);
+ } while (!(lsr & TEMT));
+
+ /* Disable UART */
+ ier = UART_GET_IER(uart);
+ UART_PUT_IER(uart, 0);
+
+ /* Set DLAB in LCR to Access DLL and DLH */
+ val = UART_GET_LCR(uart);
+ val |= DLAB;
+ UART_PUT_LCR(uart, val);
+ SSYNC();
+
+ UART_PUT_DLL(uart, quot & 0xFF);
+ SSYNC();
+ UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+ SSYNC();
+
+ /* Clear DLAB in LCR to Access THR RBR IER */
+ val = UART_GET_LCR(uart);
+ val &= ~DLAB;
+ UART_PUT_LCR(uart, val);
+ SSYNC();
+
+ UART_PUT_LCR(uart, lcr);
+
+ /* Enable UART */
+ UART_PUT_IER(uart, ier);
+
+ val = UART_GET_GCTL(uart);
+ val |= UCEN;
+ UART_PUT_GCTL(uart, val);
+
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+}
+
+static const char *bfin_serial_type(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ return uart->port.type == PORT_BFIN ? "BFIN-UART" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void bfin_serial_release_port(struct uart_port *port)
+{
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int bfin_serial_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void bfin_serial_config_port(struct uart_port *port, int flags)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ if (flags & UART_CONFIG_TYPE &&
+ bfin_serial_request_port(&uart->port) == 0)
+ uart->port.type = PORT_BFIN;
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ * The only change we allow are to the flags and type, and
+ * even then only between PORT_BFIN and PORT_UNKNOWN
+ */
+static int
+bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ return 0;
+}
+
+static struct uart_ops bfin_serial_pops = {
+ .tx_empty = bfin_serial_tx_empty,
+ .set_mctrl = bfin_serial_set_mctrl,
+ .get_mctrl = bfin_serial_get_mctrl,
+ .stop_tx = bfin_serial_stop_tx,
+ .start_tx = bfin_serial_start_tx,
+ .stop_rx = bfin_serial_stop_rx,
+ .enable_ms = bfin_serial_enable_ms,
+ .break_ctl = bfin_serial_break_ctl,
+ .startup = bfin_serial_startup,
+ .shutdown = bfin_serial_shutdown,
+ .set_termios = bfin_serial_set_termios,
+ .type = bfin_serial_type,
+ .release_port = bfin_serial_release_port,
+ .request_port = bfin_serial_request_port,
+ .config_port = bfin_serial_config_port,
+ .verify_port = bfin_serial_verify_port,
+};
+
+static void __init bfin_serial_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+ first = 0;
+
+ for (i = 0; i < nr_ports; i++) {
+ bfin_serial_ports[i].port.uartclk = get_sclk();
+ bfin_serial_ports[i].port.ops = &bfin_serial_pops;
+ bfin_serial_ports[i].port.line = i;
+ bfin_serial_ports[i].port.iotype = UPIO_MEM;
+ bfin_serial_ports[i].port.membase =
+ (void __iomem *)bfin_serial_resource[i].uart_base_addr;
+ bfin_serial_ports[i].port.mapbase =
+ bfin_serial_resource[i].uart_base_addr;
+ bfin_serial_ports[i].port.irq =
+ bfin_serial_resource[i].uart_irq;
+ bfin_serial_ports[i].port.flags = UPF_BOOT_AUTOCONF;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ bfin_serial_ports[i].tx_done = 1;
+ bfin_serial_ports[i].tx_count = 0;
+ bfin_serial_ports[i].tx_dma_channel =
+ bfin_serial_resource[i].uart_tx_dma_channel;
+ bfin_serial_ports[i].rx_dma_channel =
+ bfin_serial_resource[i].uart_rx_dma_channel;
+ init_timer(&(bfin_serial_ports[i].rx_dma_timer));
+#else
+ INIT_WORK(&bfin_serial_ports[i].cts_workqueue, bfin_serial_do_work);
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ bfin_serial_ports[i].cts_pin =
+ bfin_serial_resource[i].uart_cts_pin;
+ bfin_serial_ports[i].rts_pin =
+ bfin_serial_resource[i].uart_rts_pin;
+#endif
+ bfin_serial_hw_init(&bfin_serial_ports[i]);
+
+ }
+}
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ while (!(UART_GET_LSR(uart)))
+ barrier();
+ UART_PUT_CHAR(uart, ch);
+ SSYNC();
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+ int flags = 0;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
+ uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
+ int *parity, int *bits)
+{
+ unsigned short status;
+
+ status = UART_GET_IER(uart) & (ERBFI | ETBEI);
+ if (status == (ERBFI | ETBEI)) {
+ /* ok, the port was enabled */
+ unsigned short lcr, val;
+ unsigned short dlh, dll;
+
+ lcr = UART_GET_LCR(uart);
+
+ *parity = 'n';
+ if (lcr & PEN) {
+ if (lcr & EPS)
+ *parity = 'e';
+ else
+ *parity = 'o';
+ }
+ switch (lcr & 0x03) {
+ case 0: *bits = 5; break;
+ case 1: *bits = 6; break;
+ case 2: *bits = 7; break;
+ case 3: *bits = 8; break;
+ }
+ /* Set DLAB in LCR to Access DLL and DLH */
+ val = UART_GET_LCR(uart);
+ val |= DLAB;
+ UART_PUT_LCR(uart, val);
+
+ dll = UART_GET_DLL(uart);
+ dlh = UART_GET_DLH(uart);
+
+ /* Clear DLAB in LCR to Access THR RBR IER */
+ val = UART_GET_LCR(uart);
+ val &= ~DLAB;
+ UART_PUT_LCR(uart, val);
+
+ *baud = get_sclk() / (16*(dll | dlh << 8));
+ }
+ pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
+}
+
+static int __init
+bfin_serial_console_setup(struct console *co, char *options)
+{
+ struct bfin_serial_port *uart;
+ int baud = 57600;
+ int bits = 8;
+ int parity = 'n';
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int flow = 'r';
+#else
+ int flow = 'n';
+#endif
+
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index == -1 || co->index >= nr_ports)
+ co->index = 0;
+ uart = &bfin_serial_ports[co->index];
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ bfin_serial_console_get_options(uart, &baud, &parity, &bits);
+
+ return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver bfin_serial_reg;
+static struct console bfin_serial_console = {
+ .name = BFIN_SERIAL_NAME,
+ .write = bfin_serial_console_write,
+ .device = uart_console_device,
+ .setup = bfin_serial_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &bfin_serial_reg,
+};
+
+static int __init bfin_serial_rs_console_init(void)
+{
+ bfin_serial_init_ports();
+ register_console(&bfin_serial_console);
+ return 0;
+}
+console_initcall(bfin_serial_rs_console_init);
+
+#define BFIN_SERIAL_CONSOLE &bfin_serial_console
+#else
+#define BFIN_SERIAL_CONSOLE NULL
+#endif
+
+static struct uart_driver bfin_serial_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "bfin-uart",
+ .dev_name = BFIN_SERIAL_NAME,
+ .major = BFIN_SERIAL_MAJOR,
+ .minor = BFIN_SERIAL_MINOR,
+ .nr = NR_PORTS,
+ .cons = BFIN_SERIAL_CONSOLE,
+};
+
+static int bfin_serial_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct bfin_serial_port *uart = platform_get_drvdata(dev);
+
+ if (uart)
+ uart_suspend_port(&bfin_serial_reg, &uart->port);
+
+ return 0;
+}
+
+static int bfin_serial_resume(struct platform_device *dev)
+{
+ struct bfin_serial_port *uart = platform_get_drvdata(dev);
+
+ if (uart)
+ uart_resume_port(&bfin_serial_reg, &uart->port);
+
+ return 0;
+}
+
+static int bfin_serial_probe(struct platform_device *dev)
+{
+ struct resource *res = dev->resource;
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++, res++)
+ if (res->flags & IORESOURCE_MEM)
+ break;
+
+ if (i < dev->num_resources) {
+ for (i = 0; i < nr_ports; i++, res++) {
+ if (bfin_serial_ports[i].port.mapbase != res->start)
+ continue;
+ bfin_serial_ports[i].port.dev = &dev->dev;
+ uart_add_one_port(&bfin_serial_reg, &bfin_serial_ports[i].port);
+ platform_set_drvdata(dev, &bfin_serial_ports[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int bfin_serial_remove(struct platform_device *pdev)
+{
+ struct bfin_serial_port *uart = platform_get_drvdata(pdev);
+
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ gpio_free(uart->cts_pin);
+ gpio_free(uart->rts_pin);
+#endif
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (uart)
+ uart_remove_one_port(&bfin_serial_reg, &uart->port);
+
+ return 0;
+}
+
+static struct platform_driver bfin_serial_driver = {
+ .probe = bfin_serial_probe,
+ .remove = bfin_serial_remove,
+ .suspend = bfin_serial_suspend,
+ .resume = bfin_serial_resume,
+ .driver = {
+ .name = "bfin-uart",
+ },
+};
+
+static int __init bfin_serial_init(void)
+{
+ int ret;
+
+ pr_info("Serial: Blackfin serial driver\n");
+
+ bfin_serial_init_ports();
+
+ ret = uart_register_driver(&bfin_serial_reg);
+ if (ret == 0) {
+ ret = platform_driver_register(&bfin_serial_driver);
+ if (ret) {
+ pr_debug("uart register failed\n");
+ uart_unregister_driver(&bfin_serial_reg);
+ }
+ }
+ return ret;
+}
+
+static void __exit bfin_serial_exit(void)
+{
+ platform_driver_unregister(&bfin_serial_driver);
+ uart_unregister_driver(&bfin_serial_reg);
+}
+
+module_init(bfin_serial_init);
+module_exit(bfin_serial_exit);
+
+MODULE_AUTHOR("Aubrey.Li <aubrey.li@analog.com>");
+MODULE_DESCRIPTION("Blackfin generic serial port driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_CHARDEV_MAJOR(BFIN_SERIAL_MAJOR);
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 7a3b97fdf8d..f23972bc00c 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -934,7 +934,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SMC1_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC1].port.lock),
},
.flags = FLAG_SMC,
.tx_nrfifos = TX_NUM_FIFO,
@@ -948,7 +948,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SMC2_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SMC2].port.lock),
},
.flags = FLAG_SMC,
.tx_nrfifos = TX_NUM_FIFO,
@@ -965,7 +965,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC1_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC1].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
@@ -979,7 +979,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC2_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC2].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
@@ -993,7 +993,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC3_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC3].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
@@ -1007,7 +1007,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = {
.irq = SCC4_IRQ,
.ops = &cpm_uart_pops,
.iotype = UPIO_MEM,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(cpm_uart_ports[UART_SCC4].port.lock),
},
.tx_nrfifos = TX_NUM_FIFO,
.tx_fifosize = TX_BUF_SIZE,
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
deleted file mode 100644
index 4a23340663a..00000000000
--- a/drivers/serial/crisv10.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * serial.h: Arch-dep definitions for the Etrax100 serial driver.
- *
- * Copyright (C) 1998, 1999, 2000 Axis Communications AB
- */
-
-#ifndef _ETRAX_SERIAL_H
-#define _ETRAX_SERIAL_H
-
-#include <linux/circ_buf.h>
-#include <asm/termios.h>
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-#define SERIAL_RECV_DESCRIPTORS 8
-
-struct etrax_recv_buffer {
- struct etrax_recv_buffer *next;
- unsigned short length;
- unsigned char error;
- unsigned char pad;
-
- unsigned char buffer[0];
-};
-
-struct e100_serial {
- int baud;
- volatile u8 *port; /* R_SERIALx_CTRL */
- u32 irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */
-
- /* Output registers */
- volatile u8 *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
- volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */
- volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */
- const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */
-
- /* Input registers */
- volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
- volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */
- volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
- volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
-
- int flags; /* defined in tty.h */
-
- u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
- u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
- u8 iseteop; /* bit number for R_SET_EOP for the input dma */
- int enabled; /* Set to 1 if the port is enabled in HW config */
-
- u8 dma_out_enabled:1; /* Set to 1 if DMA should be used */
- u8 dma_in_enabled:1; /* Set to 1 if DMA should be used */
-
- /* end of fields defined in rs_table[] in .c-file */
- u8 uses_dma_in; /* Set to 1 if DMA is used */
- u8 uses_dma_out; /* Set to 1 if DMA is used */
- u8 forced_eop; /* a fifo eop has been forced */
- int baud_base; /* For special baudrates */
- int custom_divisor; /* For special baudrates */
- struct etrax_dma_descr tr_descr;
- struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS];
- int cur_rec_descr;
-
- volatile int tr_running; /* 1 if output is running */
-
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int type; /* PORT_ETRAX */
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- struct circ_buf xmit;
- struct etrax_recv_buffer *first_recv_buffer;
- struct etrax_recv_buffer *last_recv_buffer;
- unsigned int recv_cnt;
- unsigned int max_recv_cnt;
-
- struct work_struct work;
- struct async_icount icount; /* error-statistics etc.*/
- struct ktermios normal_termios;
- struct ktermios callout_termios;
-#ifdef DECLARE_WAITQUEUE
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-#else
- struct wait_queue *open_wait;
- struct wait_queue *close_wait;
-#endif
-
- unsigned long char_time_usec; /* The time for 1 char, in usecs */
- unsigned long flush_time_usec; /* How often we should flush */
- unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */
- unsigned long last_tx_active; /* Last tx time in jiffies */
- unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */
- unsigned long last_rx_active; /* Last rx time in jiffies */
-
- int break_detected_cnt;
- int errorcode;
-
-#ifdef CONFIG_ETRAX_RS485
- struct rs485_control rs485; /* RS-485 support */
-#endif
-};
-
-/* this PORT is not in the standard serial.h. it's not actually used for
- * anything since we only have one type of async serial-port anyway in this
- * system.
- */
-
-#define PORT_ETRAX 1
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-#endif /* __KERNEL__ */
-
-#endif /* !_ETRAX_SERIAL_H */
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 246c5572667..6202995e821 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -47,7 +47,6 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/kobject.h>
#include <linux/firmware.h>
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 04cc88cc528..e42faa4e428 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -46,6 +46,122 @@
#include <asm/hardware.h>
#include <asm/arch/imx-uart.h>
+/* Register definitions */
+#define URXD0 0x0 /* Receiver Register */
+#define URTX0 0x40 /* Transmitter Register */
+#define UCR1 0x80 /* Control Register 1 */
+#define UCR2 0x84 /* Control Register 2 */
+#define UCR3 0x88 /* Control Register 3 */
+#define UCR4 0x8c /* Control Register 4 */
+#define UFCR 0x90 /* FIFO Control Register */
+#define USR1 0x94 /* Status Register 1 */
+#define USR2 0x98 /* Status Register 2 */
+#define UESC 0x9c /* Escape Character Register */
+#define UTIM 0xa0 /* Escape Timer Register */
+#define UBIR 0xa4 /* BRM Incremental Register */
+#define UBMR 0xa8 /* BRM Modulator Register */
+#define UBRC 0xac /* Baud Rate Count Register */
+#define BIPR1 0xb0 /* Incremental Preset Register 1 */
+#define BIPR2 0xb4 /* Incremental Preset Register 2 */
+#define BIPR3 0xb8 /* Incremental Preset Register 3 */
+#define BIPR4 0xbc /* Incremental Preset Register 4 */
+#define BMPR1 0xc0 /* BRM Modulator Register 1 */
+#define BMPR2 0xc4 /* BRM Modulator Register 2 */
+#define BMPR3 0xc8 /* BRM Modulator Register 3 */
+#define BMPR4 0xcc /* BRM Modulator Register 4 */
+#define UTS 0xd0 /* UART Test Register */
+
+/* UART Control Register Bit Fields.*/
+#define URXD_CHARRDY (1<<15)
+#define URXD_ERR (1<<14)
+#define URXD_OVRRUN (1<<13)
+#define URXD_FRMERR (1<<12)
+#define URXD_BRK (1<<11)
+#define URXD_PRERR (1<<10)
+#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
+#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
+#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
+#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
+#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
+#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
+#define UCR1_IREN (1<<7) /* Infrared interface enable */
+#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
+#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
+#define UCR1_SNDBRK (1<<4) /* Send break */
+#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
+#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
+#define UCR1_DOZE (1<<1) /* Doze */
+#define UCR1_UARTEN (1<<0) /* UART enabled */
+#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
+#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
+#define UCR2_CTSC (1<<13) /* CTS pin control */
+#define UCR2_CTS (1<<12) /* Clear to send */
+#define UCR2_ESCEN (1<<11) /* Escape enable */
+#define UCR2_PREN (1<<8) /* Parity enable */
+#define UCR2_PROE (1<<7) /* Parity odd/even */
+#define UCR2_STPB (1<<6) /* Stop */
+#define UCR2_WS (1<<5) /* Word size */
+#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
+#define UCR2_TXEN (1<<2) /* Transmitter enabled */
+#define UCR2_RXEN (1<<1) /* Receiver enabled */
+#define UCR2_SRST (1<<0) /* SW reset */
+#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
+#define UCR3_PARERREN (1<<12) /* Parity enable */
+#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
+#define UCR3_DSR (1<<10) /* Data set ready */
+#define UCR3_DCD (1<<9) /* Data carrier detect */
+#define UCR3_RI (1<<8) /* Ring indicator */
+#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
+#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
+#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
+#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
+#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */
+#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */
+#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
+#define UCR3_BPEN (1<<0) /* Preset registers enable */
+#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
+#define UCR4_INVR (1<<9) /* Inverted infrared reception */
+#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
+#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
+#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
+#define UCR4_IRSC (1<<5) /* IR special case */
+#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
+#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
+#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
+#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
+#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
+#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
+#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
+#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
+#define USR1_RTSS (1<<14) /* RTS pin status */
+#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
+#define USR1_RTSD (1<<12) /* RTS delta */
+#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
+#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
+#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
+#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
+#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
+#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
+#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
+#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
+#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
+#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
+#define USR2_IDLE (1<<12) /* Idle condition */
+#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
+#define USR2_WAKE (1<<7) /* Wake */
+#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
+#define USR2_TXDC (1<<3) /* Transmitter complete */
+#define USR2_BRCD (1<<2) /* Break condition */
+#define USR2_ORE (1<<1) /* Overrun error */
+#define USR2_RDR (1<<0) /* Recv data ready */
+#define UTS_FRCPERR (1<<13) /* Force parity error */
+#define UTS_LOOP (1<<12) /* Loop tx and rx */
+#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
+#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
+#define UTS_TXFULL (1<<4) /* TxFIFO full */
+#define UTS_RXFULL (1<<3) /* RxFIFO full */
+#define UTS_SOFTRST (1<<0) /* Software reset */
+
/* We've been assigned a range on the "Low-density serial ports" major */
#define SERIAL_IMX_MAJOR 204
#define MINOR_START 41
@@ -128,7 +244,10 @@ static void imx_timeout(unsigned long data)
static void imx_stop_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- UCR1((u32)sport->port.membase) &= ~UCR1_TXMPTYEN;
+ unsigned long temp;
+
+ temp = readl(sport->port.membase + UCR1);
+ writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
}
/*
@@ -137,7 +256,10 @@ static void imx_stop_tx(struct uart_port *port)
static void imx_stop_rx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- UCR2((u32)sport->port.membase) &= ~UCR2_RXEN;
+ unsigned long temp;
+
+ temp = readl(sport->port.membase + UCR2);
+ writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
}
/*
@@ -154,10 +276,10 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.info->xmit;
- while (!(UTS((u32)sport->port.membase) & UTS_TXFULL)) {
+ while (!(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
* out the port here */
- URTX0((u32)sport->port.membase) = xmit->buf[xmit->tail];
+ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
xmit->tail = (xmit->tail + 1) &
(UART_XMIT_SIZE - 1);
sport->port.icount.tx++;
@@ -175,21 +297,24 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
static void imx_start_tx(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
+ unsigned long temp;
- UCR1((u32)sport->port.membase) |= UCR1_TXMPTYEN;
+ temp = readl(sport->port.membase + UCR1);
+ writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
- imx_transmit_buffer(sport);
+ if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+ imx_transmit_buffer(sport);
}
static irqreturn_t imx_rtsint(int irq, void *dev_id)
{
struct imx_port *sport = (struct imx_port *)dev_id;
- unsigned int val = USR1((u32)sport->port.membase)&USR1_RTSS;
+ unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
- USR1((u32)sport->port.membase) = USR1_RTSD;
+ writel(USR1_RTSD, sport->port.membase + USR1);
uart_handle_cts_change(&sport->port, !!val);
wake_up_interruptible(&sport->port.info->delta_msr_wait);
@@ -207,7 +332,7 @@ static irqreturn_t imx_txint(int irq, void *dev_id)
if (sport->port.x_char)
{
/* Send next char */
- URTX0((u32)sport->port.membase) = sport->port.x_char;
+ writel(sport->port.x_char, sport->port.membase + URTX0);
goto out;
}
@@ -231,17 +356,18 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
struct imx_port *sport = dev_id;
unsigned int rx,flg,ignored = 0;
struct tty_struct *tty = sport->port.info->tty;
- unsigned long flags;
+ unsigned long flags, temp;
- rx = URXD0((u32)sport->port.membase);
+ rx = readl(sport->port.membase + URXD0);
spin_lock_irqsave(&sport->port.lock,flags);
do {
flg = TTY_NORMAL;
sport->port.icount.rx++;
- if( USR2((u32)sport->port.membase) & USR2_BRCD ) {
- USR2((u32)sport->port.membase) |= USR2_BRCD;
+ temp = readl(sport->port.membase + USR2);
+ if( temp & USR2_BRCD ) {
+ writel(temp | USR2_BRCD, sport->port.membase + USR2);
if(uart_handle_break(&sport->port))
goto ignore_char;
}
@@ -257,7 +383,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
tty_insert_flip_char(tty, rx, flg);
ignore_char:
- rx = URXD0((u32)sport->port.membase);
+ rx = readl(sport->port.membase + URXD0);
} while(rx & URXD_CHARRDY);
out:
@@ -301,7 +427,7 @@ static unsigned int imx_tx_empty(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
- return USR2((u32)sport->port.membase) & USR2_TXDC ? TIOCSER_TEMT : 0;
+ return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0;
}
/*
@@ -312,10 +438,10 @@ static unsigned int imx_get_mctrl(struct uart_port *port)
struct imx_port *sport = (struct imx_port *)port;
unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
- if (USR1((u32)sport->port.membase) & USR1_RTSS)
+ if (readl(sport->port.membase + USR1) & USR1_RTSS)
tmp |= TIOCM_CTS;
- if (UCR2((u32)sport->port.membase) & UCR2_CTS)
+ if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS;
return tmp;
@@ -324,11 +450,14 @@ static unsigned int imx_get_mctrl(struct uart_port *port)
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct imx_port *sport = (struct imx_port *)port;
+ unsigned long temp;
+
+ temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
if (mctrl & TIOCM_RTS)
- UCR2((u32)sport->port.membase) |= UCR2_CTS;
- else
- UCR2((u32)sport->port.membase) &= ~UCR2_CTS;
+ temp |= UCR2_CTS;
+
+ writel(temp, sport->port.membase + UCR2);
}
/*
@@ -337,14 +466,16 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void imx_break_ctl(struct uart_port *port, int break_state)
{
struct imx_port *sport = (struct imx_port *)port;
- unsigned long flags;
+ unsigned long flags, temp;
spin_lock_irqsave(&sport->port.lock, flags);
+ temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
+
if ( break_state != 0 )
- UCR1((u32)sport->port.membase) |= UCR1_SNDBRK;
- else
- UCR1((u32)sport->port.membase) &= ~UCR1_SNDBRK;
+ temp |= UCR1_SNDBRK;
+
+ writel(temp, sport->port.membase + UCR1);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
@@ -360,7 +491,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
/* set receiver / transmitter trigger level.
* RFDIV is set such way to satisfy requested uartclk value
*/
- val = TXTL<<10 | RXTL;
+ val = TXTL << 10 | RXTL;
ufcr_rfdiv = (imx_get_perclk1() + sport->port.uartclk / 2) / sport->port.uartclk;
if(!ufcr_rfdiv)
@@ -373,7 +504,7 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
- UFCR((u32)sport->port.membase) = val;
+ writel(val, sport->port.membase + UFCR);
return 0;
}
@@ -382,14 +513,15 @@ static int imx_startup(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
int retval;
- unsigned long flags;
+ unsigned long flags, temp;
imx_setup_ufcr(sport, 0);
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
*/
- UCR4((u32)sport->port.membase) &= ~UCR4_DREN;
+ temp = readl(sport->port.membase + UCR4);
+ writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
/*
* Allocate the IRQ
@@ -411,12 +543,16 @@ static int imx_startup(struct uart_port *port)
/*
* Finally, clear and enable interrupts
*/
+ writel(USR1_RTSD, sport->port.membase + USR1);
+
+ temp = readl(sport->port.membase + UCR1);
+ temp |= (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+ writel(temp, sport->port.membase + UCR1);
- USR1((u32)sport->port.membase) = USR1_RTSD;
- UCR1((u32)sport->port.membase) |=
- (UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+ temp = readl(sport->port.membase + UCR2);
+ temp |= (UCR2_RXEN | UCR2_TXEN);
+ writel(temp, sport->port.membase + UCR2);
- UCR2((u32)sport->port.membase) |= (UCR2_RXEN | UCR2_TXEN);
/*
* Enable modem status interrupts
*/
@@ -437,6 +573,7 @@ error_out1:
static void imx_shutdown(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
+ unsigned long temp;
/*
* Stop our timer.
@@ -454,8 +591,9 @@ static void imx_shutdown(struct uart_port *port)
* Disable all interrupts, port and break condition.
*/
- UCR1((u32)sport->port.membase) &=
- ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+ writel(temp, sport->port.membase + UCR1);
}
static void
@@ -548,18 +686,18 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
/*
* disable interrupts and drain transmitter
*/
- old_ucr1 = UCR1((u32)sport->port.membase);
- UCR1((u32)sport->port.membase) &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
+ old_ucr1 = readl(sport->port.membase + UCR1);
+ writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+ sport->port.membase + UCR1);
- while ( !(USR2((u32)sport->port.membase) & USR2_TXDC))
+ while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
barrier();
/* then, disable everything */
- old_txrxen = UCR2((u32)sport->port.membase) & ( UCR2_TXEN | UCR2_RXEN );
- UCR2((u32)sport->port.membase) &= ~( UCR2_TXEN | UCR2_RXEN);
-
- /* set the parity, stop bits and data size */
- UCR2((u32)sport->port.membase) = ucr2;
+ old_txrxen = readl(sport->port.membase + UCR2);
+ writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
+ sport->port.membase + UCR2);
+ old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
/* set the baud rate. We assume uartclk = 16 MHz
*
@@ -567,11 +705,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
* --------- = --------
* uartclk UBMR - 1
*/
- UBIR((u32)sport->port.membase) = (baud / 100) - 1;
- UBMR((u32)sport->port.membase) = 10000 - 1;
+ writel((baud / 100) - 1, sport->port.membase + UBIR);
+ writel(10000 - 1, sport->port.membase + UBMR);
+
+ writel(old_ucr1, sport->port.membase + UCR1);
- UCR1((u32)sport->port.membase) = old_ucr1;
- UCR2((u32)sport->port.membase) |= old_txrxen;
+ /* set the parity, stop bits and data size */
+ writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_enable_ms(&sport->port);
@@ -730,9 +870,11 @@ static void __init imx_init_ports(void)
static void imx_console_putchar(struct uart_port *port, int ch)
{
struct imx_port *sport = (struct imx_port *)port;
- while ((UTS((u32)sport->port.membase) & UTS_TXFULL))
+
+ while (readl(sport->port.membase + UTS) & UTS_TXFULL)
barrier();
- URTX0((u32)sport->port.membase) = ch;
+
+ writel(ch, sport->port.membase + URTX0);
}
/*
@@ -747,13 +889,14 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
/*
* First, save UCR1/2 and then disable interrupts
*/
- old_ucr1 = UCR1((u32)sport->port.membase);
- old_ucr2 = UCR2((u32)sport->port.membase);
+ old_ucr1 = readl(sport->port.membase + UCR1);
+ old_ucr2 = readl(sport->port.membase + UCR2);
- UCR1((u32)sport->port.membase) =
- (old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN)
- & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN);
- UCR2((u32)sport->port.membase) = old_ucr2 | UCR2_TXEN;
+ writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) &
+ ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+ sport->port.membase + UCR1);
+
+ writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
uart_console_write(&sport->port, s, count, imx_console_putchar);
@@ -761,10 +904,10 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
* Finally, wait for transmitter to become empty
* and restore UCR1/2
*/
- while (!(USR2((u32)sport->port.membase) & USR2_TXDC));
+ while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
- UCR1((u32)sport->port.membase) = old_ucr1;
- UCR2((u32)sport->port.membase) = old_ucr2;
+ writel(old_ucr1, sport->port.membase + UCR1);
+ writel(old_ucr2, sport->port.membase + UCR2);
}
/*
@@ -776,13 +919,13 @@ imx_console_get_options(struct imx_port *sport, int *baud,
int *parity, int *bits)
{
- if ( UCR1((u32)sport->port.membase) | UCR1_UARTEN ) {
+ if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) {
/* ok, the port was enabled */
unsigned int ucr2, ubir,ubmr, uartclk;
unsigned int baud_raw;
unsigned int ucfr_rfdiv;
- ucr2 = UCR2((u32)sport->port.membase);
+ ucr2 = readl(sport->port.membase + UCR2);
*parity = 'n';
if (ucr2 & UCR2_PREN) {
@@ -797,11 +940,10 @@ imx_console_get_options(struct imx_port *sport, int *baud,
else
*bits = 7;
- ubir = UBIR((u32)sport->port.membase) & 0xffff;
- ubmr = UBMR((u32)sport->port.membase) & 0xffff;
-
+ ubir = readl(sport->port.membase + UBIR) & 0xffff;
+ ubmr = readl(sport->port.membase + UBMR) & 0xffff;
- ucfr_rfdiv = (UFCR((u32)sport->port.membase) & UFCR_RFDIV) >> 7;
+ ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
if (ucfr_rfdiv == 6)
ucfr_rfdiv = 7;
else
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index 8be8da37f62..b2d6f5b1a7c 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -581,8 +581,13 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals)
return;
/* Scrub off lower bits. They signify delta's, which I don't care about */
- msignals &= 0xf0;
+ /* Keep DDCD and DDSR though */
+ msignals &= 0xf8;
+ if (msignals & UART_MSR_DDCD)
+ uart_handle_dcd_change(&ch->uart_port, msignals & UART_MSR_DCD);
+ if (msignals & UART_MSR_DDSR)
+ uart_handle_cts_change(&ch->uart_port, msignals & UART_MSR_CTS);
if (msignals & UART_MSR_DCD)
ch->ch_mistat |= UART_MSR_DCD;
else
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index be22bbdbc8e..281f23a371b 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -448,6 +448,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
continue;
brd->channels[i]->uart_port.irq = brd->irq;
+ brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
brd->channels[i]->uart_port.iotype = UPIO_MEM;
brd->channels[i]->uart_port.membase = brd->re_map_membase;
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 8d24cd52105..35f8b86cc78 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -257,9 +257,10 @@ mpc52xx_uart_shutdown(struct uart_port *port)
{
struct mpc52xx_psc __iomem *psc = PSC(port);
- /* Shut down the port, interrupt and all */
+ /* Shut down the port. Leave TX active if on a console port */
out_8(&psc->command,MPC52xx_PSC_RST_RX);
- out_8(&psc->command,MPC52xx_PSC_RST_TX);
+ if (!uart_console(port))
+ out_8(&psc->command,MPC52xx_PSC_RST_TX);
port->read_status_mask = 0;
out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);
@@ -1069,7 +1070,7 @@ mpc52xx_uart_of_enumerate(void)
continue;
/* Is a particular device number requested? */
- devno = get_property(np, "port-number", NULL);
+ devno = of_get_property(np, "port-number", NULL);
mpc52xx_uart_of_assign(of_node_get(np), devno ? *devno : -1);
}
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 3d2fcc57b1c..d09f2097d5b 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -183,6 +183,7 @@ struct mpsc_port_info {
u8 *txb_p; /* Phys addr of txb */
int txr_head; /* Where new data goes */
int txr_tail; /* Where sent data comes off */
+ spinlock_t tx_lock; /* transmit lock */
/* Mirrored values of regs we can't read (if 'mirror_regs' set) */
u32 MPSC_MPCR_m;
@@ -1212,6 +1213,9 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
{
struct mpsc_tx_desc *txre;
int rc = 0;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&pi->tx_lock, iflags);
if (!mpsc_sdma_tx_active(pi)) {
txre = (struct mpsc_tx_desc *)(pi->txr +
@@ -1248,6 +1252,7 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
mpsc_sdma_start_tx(pi); /* start next desc if ready */
}
+ spin_unlock_irqrestore(&pi->tx_lock, iflags);
return rc;
}
@@ -1338,11 +1343,16 @@ static void
mpsc_start_tx(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&pi->tx_lock, iflags);
mpsc_unfreeze(pi);
mpsc_copy_tx_data(pi);
mpsc_sdma_start_tx(pi);
+ spin_unlock_irqrestore(&pi->tx_lock, iflags);
+
pr_debug("mpsc_start_tx[%d]\n", port->line);
return;
}
@@ -1625,6 +1635,16 @@ mpsc_console_write(struct console *co, const char *s, uint count)
struct mpsc_port_info *pi = &mpsc_ports[co->index];
u8 *bp, *dp, add_cr = 0;
int i;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&pi->tx_lock, iflags);
+
+ while (pi->txr_head != pi->txr_tail) {
+ while (mpsc_sdma_tx_active(pi))
+ udelay(100);
+ mpsc_sdma_intr_ack(pi);
+ mpsc_tx_intr(pi);
+ }
while (mpsc_sdma_tx_active(pi))
udelay(100);
@@ -1668,6 +1688,7 @@ mpsc_console_write(struct console *co, const char *s, uint count)
pi->txr_tail = (pi->txr_tail + 1) & (MPSC_TXR_ENTRIES - 1);
}
+ spin_unlock_irqrestore(&pi->tx_lock, iflags);
return;
}
@@ -2005,7 +2026,8 @@ mpsc_drv_probe(struct platform_device *dev)
if (!(rc = mpsc_drv_map_regs(pi, dev))) {
mpsc_drv_get_platform_data(pi, dev, dev->id);
- if (!(rc = mpsc_make_ready(pi)))
+ if (!(rc = mpsc_make_ready(pi))) {
+ spin_lock_init(&pi->tx_lock);
if (!(rc = uart_add_one_port(&mpsc_reg,
&pi->port)))
rc = 0;
@@ -2014,6 +2036,7 @@ mpsc_drv_probe(struct platform_device *dev)
(struct uart_port *)pi);
mpsc_drv_unmap_regs(pi);
}
+ }
else
mpsc_drv_unmap_regs(pi);
}
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 09b0b736a75..7ffdaeaf054 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -29,8 +29,8 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
int ret;
memset(port, 0, sizeof *port);
- spd = get_property(np, "current-speed", NULL);
- clk = get_property(np, "clock-frequency", NULL);
+ spd = of_get_property(np, "current-speed", NULL);
+ clk = of_get_property(np, "clock-frequency", NULL);
if (!clk) {
dev_warn(&ofdev->dev, "no clock-frequency property set\n");
return -ENODEV;
@@ -48,7 +48,8 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
port->iotype = UPIO_MEM;
port->type = type;
port->uartclk = *clk;
- port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+ port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
+ | UPF_FIXED_PORT;
port->dev = &ofdev->dev;
port->custom_divisor = *clk / (16 * (*spd));
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 752ef07516b..0fa9f676176 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -1450,14 +1450,14 @@ no_dma:
/*
* Detect port type
*/
- if (device_is_compatible(np, "cobalt"))
+ if (of_device_is_compatible(np, "cobalt"))
uap->flags |= PMACZILOG_FLAG_IS_INTMODEM;
- conn = get_property(np, "AAPL,connector", &len);
+ conn = of_get_property(np, "AAPL,connector", &len);
if (conn && (strcmp(conn, "infrared") == 0))
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
uap->port_type = PMAC_SCC_ASYNC;
/* 1999 Powerbook G3 has slot-names property instead */
- slots = get_property(np, "slot-names", &len);
+ slots = of_get_property(np, "slot-names", &len);
if (slots && slots->count > 0) {
if (strcmp(slots->name, "IrDA") == 0)
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
@@ -1467,10 +1467,11 @@ no_dma:
if (ZS_IS_IRDA(uap))
uap->port_type = PMAC_SCC_IRDA;
if (ZS_IS_INTMODEM(uap)) {
- struct device_node* i2c_modem = find_devices("i2c-modem");
+ struct device_node* i2c_modem =
+ of_find_node_by_name(NULL, "i2c-modem");
if (i2c_modem) {
const char* mid =
- get_property(i2c_modem, "modem-id", NULL);
+ of_get_property(i2c_modem, "modem-id", NULL);
if (mid) switch(*mid) {
case 0x04 :
case 0x05 :
@@ -1482,6 +1483,7 @@ no_dma:
}
printk(KERN_INFO "pmac_zilog: i2c-modem detected, id: %d\n",
mid ? (*mid) : 0);
+ of_node_put(i2c_modem);
} else {
printk(KERN_INFO "pmac_zilog: serial modem detected\n");
}
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index d403aaa5509..e9c6cb391a2 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -717,7 +717,7 @@ struct uart_ops serial_pxa_pops = {
static struct uart_pxa_port serial_pxa_ports[] = {
{ /* FFUART */
.name = "FFUART",
- .cken = CKEN6_FFUART,
+ .cken = CKEN_FFUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
@@ -731,7 +731,7 @@ static struct uart_pxa_port serial_pxa_ports[] = {
},
}, { /* BTUART */
.name = "BTUART",
- .cken = CKEN7_BTUART,
+ .cken = CKEN_BTUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
@@ -745,7 +745,7 @@ static struct uart_pxa_port serial_pxa_ports[] = {
},
}, { /* STUART */
.name = "STUART",
- .cken = CKEN5_STUART,
+ .cken = CKEN_STUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
@@ -759,7 +759,7 @@ static struct uart_pxa_port serial_pxa_ports[] = {
},
}, { /* HWUART */
.name = "HWUART",
- .cken = CKEN4_HWUART,
+ .cken = CKEN_HWUART,
.port = {
.type = PORT_PXA,
.iotype = UPIO_MEM,
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 3ba9208ebd0..10bc0209cd6 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -957,7 +957,7 @@ static struct uart_driver s3c24xx_uart_drv = {
static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
[0] = {
.port = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX0,
.uartclk = 0,
@@ -969,7 +969,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
},
[1] = {
.port = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
@@ -983,7 +983,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
[2] = {
.port = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 0422c0f1f85..326020f86f7 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -37,13 +37,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-#undef DEBUG
-#ifdef DEBUG
-#define DPRINTK(x...) printk(x)
-#else
-#define DPRINTK(x...) do { } while (0)
-#endif
-
/*
* This is used to lock changes in serial line configuration.
*/
@@ -552,7 +545,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
return;
}
- DPRINTK("uart_flush_buffer(%d) called\n", tty->index);
+ pr_debug("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
uart_circ_clear(&state->info->xmit);
@@ -672,19 +665,21 @@ static int uart_set_info(struct uart_state *state,
*/
mutex_lock(&state->mutex);
- change_irq = new_serial.irq != port->irq;
+ change_irq = !(port->flags & UPF_FIXED_PORT)
+ && new_serial.irq != port->irq;
/*
* Since changing the 'type' of the port changes its resource
* allocations, we should treat type changes the same as
* IO port changes.
*/
- change_port = new_port != port->iobase ||
- (unsigned long)new_serial.iomem_base != port->mapbase ||
- new_serial.hub6 != port->hub6 ||
- new_serial.io_type != port->iotype ||
- new_serial.iomem_reg_shift != port->regshift ||
- new_serial.type != port->type;
+ change_port = !(port->flags & UPF_FIXED_PORT)
+ && (new_port != port->iobase ||
+ (unsigned long)new_serial.iomem_base != port->mapbase ||
+ new_serial.hub6 != port->hub6 ||
+ new_serial.io_type != port->iotype ||
+ new_serial.iomem_reg_shift != port->regshift ||
+ new_serial.type != port->type);
old_flags = port->flags;
new_flags = new_serial.flags;
@@ -796,8 +791,10 @@ static int uart_set_info(struct uart_state *state,
}
}
- port->irq = new_serial.irq;
- port->uartclk = new_serial.baud_base * 16;
+ if (change_irq)
+ port->irq = new_serial.irq;
+ if (!(port->flags & UPF_FIXED_PORT))
+ port->uartclk = new_serial.baud_base * 16;
port->flags = (port->flags & ~UPF_CHANGE_MASK) |
(new_flags & UPF_CHANGE_MASK);
port->custom_divisor = new_serial.custom_divisor;
@@ -1220,7 +1217,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
port = state->port;
- DPRINTK("uart_close(%d) called\n", port->line);
+ pr_debug("uart_close(%d) called\n", port->line);
mutex_lock(&state->mutex);
@@ -1339,7 +1336,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
expire = jiffies + timeout;
- DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+ pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
port->line, jiffies, expire);
/*
@@ -1368,7 +1365,7 @@ static void uart_hangup(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
BUG_ON(!kernel_locked());
- DPRINTK("uart_hangup(%d)\n", state->port->line);
+ pr_debug("uart_hangup(%d)\n", state->port->line);
mutex_lock(&state->mutex);
if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
@@ -1566,7 +1563,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
int retval, line = tty->index;
BUG_ON(!kernel_locked());
- DPRINTK("uart_open(%d) called\n", line);
+ pr_debug("uart_open(%d) called\n", line);
/*
* tty->driver->num won't change, so we won't fail here with
@@ -2064,6 +2061,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
+ case UPIO_DWAPB:
snprintf(address, sizeof(address),
"MMIO 0x%lx", port->mapbase);
break;
@@ -2409,6 +2407,7 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
case UPIO_MEM32:
case UPIO_AU:
case UPIO_TSI:
+ case UPIO_DWAPB:
return (port1->mapbase == port2->mapbase);
}
return 0;
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 509ace7e688..1deb5764326 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -15,31 +15,6 @@
* published by the Free Software Foundation.
*
* Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
- *
- * Revision History:
- * 0.30 Initial revision. (Renamed from serial_txx927.c)
- * 0.31 Use save_flags instead of local_irq_save.
- * 0.32 Support SCLK.
- * 0.33 Switch TXX9_TTY_NAME by CONFIG_SERIAL_TXX9_STDSERIAL.
- * Support TIOCSERGETLSR.
- * 0.34 Support slow baudrate.
- * 0.40 Merge codes from mainstream kernel (2.4.22).
- * 0.41 Fix console checking in rs_shutdown_port().
- * Disable flow-control in serial_console_write().
- * 0.42 Fix minor compiler warning.
- * 1.00 Kernel 2.6. Converted to new serial core (based on 8250.c).
- * 1.01 Set fifosize to make tx_empry called properly.
- * Use standard uart_get_divisor.
- * 1.02 Cleanup. (import 8250.c changes)
- * 1.03 Fix low-latency mode. (import 8250.c changes)
- * 1.04 Remove usage of deprecated functions, cleanup.
- * 1.05 More strict check in verify_port. Cleanup.
- * 1.06 Do not insert a char caused previous overrun.
- * Fix some spin_locks.
- * Do not call uart_add_one_port for absent ports.
- * 1.07 Use CONFIG_SERIAL_TXX9_NR_UARTS. Cleanup.
- * 1.08 Use platform_device.
- * Fix and cleanup suspend/resume/initialization codes.
*/
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -62,7 +37,7 @@
#include <asm/io.h>
-static char *serial_version = "1.08";
+static char *serial_version = "1.09";
static char *serial_name = "TX39/49 Serial driver";
#define PASS_LIMIT 256
@@ -70,13 +45,14 @@ static char *serial_name = "TX39/49 Serial driver";
#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
/* "ttyS" is used for standard serial driver */
#define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_MINOR_START (64 + 64) /* ttyTX0(128), ttyTX1(129) */
+#define TXX9_TTY_MINOR_START 196
+#define TXX9_TTY_MAJOR 204
#else
/* acts like standard serial driver */
#define TXX9_TTY_NAME "ttyS"
#define TXX9_TTY_MINOR_START 64
-#endif
#define TXX9_TTY_MAJOR TTY_MAJOR
+#endif
/* flag aliases */
#define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 46c40bbc4bc..1f89496d530 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -46,6 +46,7 @@
#endif
#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+#include <linux/ctype.h>
#include <asm/clock.h>
#include <asm/sh_bios.h>
#include <asm/kgdb.h>
@@ -61,7 +62,7 @@ struct sci_port {
unsigned int type;
/* Port IRQs: ERI, RXI, TXI, BRI (optional) */
- unsigned int irqs[SCIx_NR_IRQS];
+ unsigned int irqs[SCIx_NR_IRQS];
/* Port pin configuration */
void (*init_pins)(struct uart_port *port,
@@ -76,6 +77,11 @@ struct sci_port {
/* Break timer */
struct timer_list break_timer;
int break_flag;
+
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ /* Port clock */
+ struct clk *clk;
+#endif
};
#ifdef CONFIG_SH_KGDB
@@ -163,7 +169,7 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
usegdb |= sh_bios_in_gdb_mode();
#endif
#ifdef CONFIG_SH_KGDB
- usegdb |= (kgdb_in_gdb_mode && (port == kgdb_sci_port));
+ usegdb |= (kgdb_in_gdb_mode && (sci_port == kgdb_sci_port));
#endif
if (usegdb) {
@@ -204,7 +210,7 @@ static int kgdb_sci_getchar(void)
int c;
/* Keep trying to read a character, this could be neater */
- while ((c = get_char(kgdb_sci_port)) < 0)
+ while ((c = get_char(&kgdb_sci_port->port)) < 0)
cpu_relax();
return c;
@@ -212,7 +218,7 @@ static int kgdb_sci_getchar(void)
static inline void kgdb_sci_putchar(int c)
{
- put_char(kgdb_sci_port, c);
+ put_char(&kgdb_sci_port->port, c);
}
#endif /* CONFIG_SH_KGDB */
@@ -283,12 +289,23 @@ static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
#endif
#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300)
/* SH7300 doesn't use RTS/CTS */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
sci_out(port, SCFCR, 0);
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+
+ set_sh771x_scif_pfc(port);
+ if (cflag & CRTSCTS) {
+ fcr_val |= SCFCR_MCE;
+ }
+ sci_out(port, SCFCR, fcr_val);
+}
#elif defined(CONFIG_CPU_SH3)
/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
@@ -350,7 +367,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
} else {
#ifdef CONFIG_CPU_SUBTYPE_SH7343
/* Nothing */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
#else
ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
@@ -360,7 +377,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
}
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
static inline int scif_txroom(struct uart_port *port)
{
return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
@@ -735,12 +754,6 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
/* Handle BREAKs */
sci_handle_breaks(port);
-
-#ifdef CONFIG_SH_KGDB
- /* Break into the debugger if a break is detected */
- BREAKPOINT();
-#endif
-
sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
@@ -947,6 +960,10 @@ static int sci_startup(struct uart_port *port)
if (s->enable)
s->enable(port);
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ s->clk = clk_get(NULL, "module_clk");
+#endif
+
sci_request_irq(s);
sci_start_tx(port);
sci_start_rx(port, 1);
@@ -964,6 +981,11 @@ static void sci_shutdown(struct uart_port *port)
if (s->disable)
s->disable(port);
+
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ clk_put(s->clk);
+ s->clk = NULL;
+#endif
}
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
@@ -971,7 +993,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct sci_port *s = &sci_ports[port->line];
unsigned int status, baud, smr_val;
- unsigned long flags;
int t;
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
@@ -983,18 +1004,14 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
default:
{
#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
- struct clk *clk = clk_get(NULL, "module_clk");
- t = SCBRR_VALUE(baud, clk_get_rate(clk));
- clk_put(clk);
+ t = SCBRR_VALUE(baud, clk_get_rate(s->clk));
#else
t = SCBRR_VALUE(baud);
#endif
- }
break;
+ }
}
- spin_lock_irqsave(&port->lock, flags);
-
do {
status = sci_in(port, SCxSR);
} while (!(status & SCxSR_TEND(port)));
@@ -1038,8 +1055,6 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
if ((termios->c_cflag & CREAD) != 0)
sci_start_rx(port,0);
-
- spin_unlock_irqrestore(&port->lock, flags);
}
static const char *sci_type(struct uart_port *port)
@@ -1220,10 +1235,13 @@ static int __init serial_console_setup(struct console *co, char *options)
if (!port->membase || !port->mapbase)
return -ENODEV;
- spin_lock_init(&port->lock);
-
port->type = serial_console_port->type;
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ if (!serial_console_port->clk)
+ serial_console_port->clk = clk_get(NULL, "module_clk");
+#endif
+
if (port->flags & UPF_IOREMAP)
sci_config_port(port, 0);
@@ -1247,7 +1265,7 @@ static struct console serial_console = {
.device = uart_console_device,
.write = serial_console_write,
.setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER,
.index = -1,
.data = &sci_uart_driver,
};
@@ -1292,11 +1310,23 @@ int __init kgdb_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
- spin_lock_init(&port->lock);
-
if (co->index != kgdb_portnum)
co->index = kgdb_portnum;
+ kgdb_sci_port = &sci_ports[co->index];
+ port = &kgdb_sci_port->port;
+
+ /*
+ * Also need to check port->type, we don't actually have any
+ * UPIO_PORT ports, but uart_report_port() handily misreports
+ * it anyways if we don't have a port available by the time this is
+ * called.
+ */
+ if (!port->type)
+ return -ENODEV;
+ if (!port->membase || !port->mapbase)
+ return -ENODEV;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
@@ -1311,11 +1341,12 @@ int __init kgdb_console_setup(struct console *co, char *options)
#ifdef CONFIG_SH_KGDB_CONSOLE
static struct console kgdb_console = {
- .name = "ttySC",
- .write = kgdb_console_write,
- .setup = kgdb_console_setup,
- .flags = CON_PRINTBUFFER | CON_ENABLED,
- .index = -1,
+ .name = "ttySC",
+ .device = uart_console_device,
+ .write = kgdb_console_write,
+ .setup = kgdb_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
.data = &sci_uart_driver,
};
@@ -1361,9 +1392,19 @@ static int __devinit sci_probe(struct platform_device *dev)
struct plat_sci_port *p = dev->dev.platform_data;
int i;
- for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) {
+ for (i = 0; p && p->flags != 0; p++, i++) {
struct sci_port *sciport = &sci_ports[i];
+ /* Sanity check */
+ if (unlikely(i == SCI_NPORTS)) {
+ dev_notice(&dev->dev, "Attempting to register port "
+ "%d when only %d are available.\n",
+ i+1, SCI_NPORTS);
+ dev_notice(&dev->dev, "Consider bumping "
+ "CONFIG_SERIAL_SH_SCI_NR_UARTS!\n");
+ break;
+ }
+
sciport->port.mapbase = p->mapbase;
/*
@@ -1386,6 +1427,12 @@ static int __devinit sci_probe(struct platform_device *dev)
uart_add_one_port(&sci_uart_driver, &sciport->port);
}
+#if defined(CONFIG_SH_KGDB) && !defined(CONFIG_SH_KGDB_CONSOLE)
+ kgdb_sci_port = &sci_ports[kgdb_portnum];
+ kgdb_getchar = kgdb_sci_getchar;
+ kgdb_putchar = kgdb_sci_putchar;
+#endif
+
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 77f7d6351ab..fb04fb5f984 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -73,9 +73,13 @@
# define SCPDR 0xA4050136 /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
-# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_NPORTS 2
+# define SCIF_ORER 0x0001 /* overrun error bit */
+# define PACR 0xa4050100
+# define PBCR 0xa4050102
+# define SCSCR_INIT(port) 0x3B
# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
# define SCPDR 0xA4050138 /* 16 bit SCIF */
@@ -140,6 +144,16 @@
# define SCIF_ORER 0x0001 /* Overrun error bit */
# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+# define SCSPTR0 0xffea0024 /* 16 bit SCIF */
+# define SCSPTR1 0xffeb0024 /* 16 bit SCIF */
+# define SCSPTR2 0xffec0024 /* 16 bit SCIF */
+# define SCSPTR3 0xffed0024 /* 16 bit SCIF */
+# define SCSPTR4 0xffee0024 /* 16 bit SCIF */
+# define SCSPTR5 0xffef0024 /* 16 bit SCIF */
+# define SCIF_OPER 0x0001 /* Overrun error bit */
+# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
# define SCSPTR0 0xfffe8020 /* 16 bit SCIF */
# define SCSPTR1 0xfffe8820 /* 16 bit SCIF */
@@ -163,7 +177,10 @@
#define SCI_CTRL_FLAGS_RIE 0x40 /* all */
#define SCI_CTRL_FLAGS_TE 0x20 /* all */
#define SCI_CTRL_FLAGS_RE 0x10 /* all */
-#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
#else
#define SCI_CTRL_FLAGS_REIE 0
@@ -333,9 +350,15 @@
}
#ifdef CONFIG_CPU_SH3
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH7705) || \
- defined(CONFIG_CPU_SUBTYPE_SH7710)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+ h8_sci_offset, h8_sci_size) \
+ CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -362,8 +385,8 @@
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH7705) || \
- defined(CONFIG_CPU_SUBTYPE_SH7710)
+ defined(CONFIG_CPU_SUBTYPE_SH7705)
+
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
SCIF_FNS(SCSCR, 0x08, 16)
@@ -385,7 +408,9 @@ SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8)
SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8)
SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8)
SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCTFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCRFDR, 0x0e, 16, 0x20, 16)
@@ -471,13 +496,24 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
static inline int sci_rxd_in(struct uart_port *port)
{
- if (port->mapbase == SCSPTR0)
- return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0;
- return 1;
+ return sci_in(port,SCxSR)&0x0010 ? 1 : 0;
+}
+static inline void set_sh771x_scif_pfc(struct uart_port *port)
+{
+ if (port->mapbase == 0xA4400000){
+ ctrl_outw(ctrl_inw(PACR)&0xffc0,PACR);
+ ctrl_outw(ctrl_inw(PBCR)&0x0fff,PBCR);
+ return;
+ }
+ if (port->mapbase == 0xA4410000){
+ ctrl_outw(ctrl_inw(PBCR)&0xf003,PBCR);
+ return;
+ }
}
+
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH4_202)
@@ -576,6 +612,23 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xffea0000)
+ return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffeb0000)
+ return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffec0000)
+ return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffed0000)
+ return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffee0000)
+ return ctrl_inw(SCSPTR4) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffef0000)
+ return ctrl_inw(SCSPTR5) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -634,7 +687,9 @@ static inline int sci_rxd_in(struct uart_port *port)
* -- Mitch Davis - 15 Jul 2000
*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
#define SCBRR_VALUE(bps, clk) (((clk*2)+16*bps)/(32*bps)-1)
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index bfd44177a21..2a63cdba320 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1312,7 +1312,7 @@ static void sunsu_console_write(struct console *co, const char *s,
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
*/
-static int sunsu_console_setup(struct console *co, char *options)
+static int __init sunsu_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
@@ -1343,7 +1343,7 @@ static int sunsu_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-static struct console sunsu_cons = {
+static struct console sunsu_console = {
.name = "ttyS",
.write = sunsu_console_write,
.device = uart_console_device,
@@ -1373,9 +1373,9 @@ static inline struct console *SUNSU_CONSOLE(int num_uart)
if (i == num_uart)
return NULL;
- sunsu_cons.index = i;
+ sunsu_console.index = i;
- return &sunsu_cons;
+ return &sunsu_console;
}
#else
#define SUNSU_CONSOLE(num_uart) (NULL)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 7e54e48efd5..07c587ec71b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -58,6 +58,23 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.
+config SPI_BFIN
+ tristate "SPI controller driver for ADI Blackfin5xx"
+ depends on SPI_MASTER && BFIN
+ help
+ This is the SPI controller master driver for Blackfin 5xx processor.
+
+config SPI_AU1550
+ tristate "Au1550/Au12x0 SPI Controller"
+ depends on SPI_MASTER && (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ If you say yes to this option, support will be included for the
+ Au1550 SPI controller (may also work with Au1200,Au1210,Au1250).
+
+ This driver can also be built as a module. If so, the module
+ will be called au1550_spi.
+
config SPI_BITBANG
tristate "Bitbanging SPI master"
depends on SPI_MASTER && EXPERIMENTAL
@@ -153,11 +170,19 @@ config SPI_AT25
This driver can also be built as a module. If so, the module
will be called at25.
+config SPI_SPIDEV
+ tristate "User mode SPI device driver support"
+ depends on SPI_MASTER && EXPERIMENTAL
+ help
+ This supports user mode SPI protocol drivers.
+
+ Note that this application programming interface is EXPERIMENTAL
+ and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
+
#
# Add new SPI protocol masters in alphabetical order above this line
#
-
# (slave support would go here)
endmenu # "SPI support"
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3c280ad8920..624b6363f49 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -11,8 +11,10 @@ endif
obj-$(CONFIG_SPI_MASTER) += spi.o
# SPI master controller drivers (bus)
-obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
+obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
+obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
+obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
@@ -24,6 +26,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
# SPI protocol drivers (device/link on bus)
obj-$(CONFIG_SPI_AT25) += at25.o
+obj-$(CONFIG_SPI_SPIDEV) += spidev.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 66e7bc98579..1d8a2f6bb8e 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -22,10 +22,7 @@
#include <asm/io.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
-
-#ifdef CONFIG_ARCH_AT91
#include <asm/arch/cpu.h>
-#endif
#include "atmel_spi.h"
@@ -552,10 +549,8 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
goto out_free_buffer;
as->irq = irq;
as->clk = clk;
-#ifdef CONFIG_ARCH_AT91
if (!cpu_is_at91rm9200())
as->new_1 = 1;
-#endif
ret = request_irq(irq, atmel_spi_interrupt, 0,
pdev->dev.bus_id, master);
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
new file mode 100644
index 00000000000..ae2b1af0dba
--- /dev/null
+++ b/drivers/spi/au1550_spi.c
@@ -0,0 +1,974 @@
+/*
+ * au1550_spi.c - au1550 psc spi controller driver
+ * may work also with au1200, au1210, au1250
+ * will not work on au1000, au1100 and au1500 (no full spi controller there)
+ *
+ * Copyright (c) 2006 ATRON electronic GmbH
+ * Author: Jan Nikitenko <jan.nikitenko@gmail.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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-au1x00/au1xxx_psc.h>
+#include <asm/mach-au1x00/au1xxx_dbdma.h>
+
+#include <asm/mach-au1x00/au1550_spi.h>
+
+static unsigned usedma = 1;
+module_param(usedma, uint, 0644);
+
+/*
+#define AU1550_SPI_DEBUG_LOOPBACK
+*/
+
+
+#define AU1550_SPI_DBDMA_DESCRIPTORS 1
+#define AU1550_SPI_DMA_RXTMP_MINSIZE 2048U
+
+struct au1550_spi {
+ struct spi_bitbang bitbang;
+
+ volatile psc_spi_t __iomem *regs;
+ int irq;
+ unsigned freq_max;
+ unsigned freq_min;
+
+ unsigned len;
+ unsigned tx_count;
+ unsigned rx_count;
+ const u8 *tx;
+ u8 *rx;
+
+ void (*rx_word)(struct au1550_spi *hw);
+ void (*tx_word)(struct au1550_spi *hw);
+ int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);
+ irqreturn_t (*irq_callback)(struct au1550_spi *hw);
+
+ struct completion master_done;
+
+ unsigned usedma;
+ u32 dma_tx_id;
+ u32 dma_rx_id;
+ u32 dma_tx_ch;
+ u32 dma_rx_ch;
+
+ u8 *dma_rx_tmpbuf;
+ unsigned dma_rx_tmpbuf_size;
+ u32 dma_rx_tmpbuf_addr;
+
+ struct spi_master *master;
+ struct device *dev;
+ struct au1550_spi_info *pdata;
+};
+
+
+/* we use an 8-bit memory device for dma transfers to/from spi fifo */
+static dbdev_tab_t au1550_spi_mem_dbdev =
+{
+ .dev_id = DBDMA_MEM_CHAN,
+ .dev_flags = DEV_FLAGS_ANYUSE|DEV_FLAGS_SYNC,
+ .dev_tsize = 0,
+ .dev_devwidth = 8,
+ .dev_physaddr = 0x00000000,
+ .dev_intlevel = 0,
+ .dev_intpolarity = 0
+};
+
+static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw);
+
+
+/**
+ * compute BRG and DIV bits to setup spi clock based on main input clock rate
+ * that was specified in platform data structure
+ * according to au1550 datasheet:
+ * psc_tempclk = psc_mainclk / (2 << DIV)
+ * spiclk = psc_tempclk / (2 * (BRG + 1))
+ * BRG valid range is 4..63
+ * DIV valid range is 0..3
+ */
+static u32 au1550_spi_baudcfg(struct au1550_spi *hw, unsigned speed_hz)
+{
+ u32 mainclk_hz = hw->pdata->mainclk_hz;
+ u32 div, brg;
+
+ for (div = 0; div < 4; div++) {
+ brg = mainclk_hz / speed_hz / (4 << div);
+ /* now we have BRG+1 in brg, so count with that */
+ if (brg < (4 + 1)) {
+ brg = (4 + 1); /* speed_hz too big */
+ break; /* set lowest brg (div is == 0) */
+ }
+ if (brg <= (63 + 1))
+ break; /* we have valid brg and div */
+ }
+ if (div == 4) {
+ div = 3; /* speed_hz too small */
+ brg = (63 + 1); /* set highest brg and div */
+ }
+ brg--;
+ return PSC_SPICFG_SET_BAUD(brg) | PSC_SPICFG_SET_DIV(div);
+}
+
+static inline void au1550_spi_mask_ack_all(struct au1550_spi *hw)
+{
+ hw->regs->psc_spimsk =
+ PSC_SPIMSK_MM | PSC_SPIMSK_RR | PSC_SPIMSK_RO
+ | PSC_SPIMSK_RU | PSC_SPIMSK_TR | PSC_SPIMSK_TO
+ | PSC_SPIMSK_TU | PSC_SPIMSK_SD | PSC_SPIMSK_MD;
+ au_sync();
+
+ hw->regs->psc_spievent =
+ PSC_SPIEVNT_MM | PSC_SPIEVNT_RR | PSC_SPIEVNT_RO
+ | PSC_SPIEVNT_RU | PSC_SPIEVNT_TR | PSC_SPIEVNT_TO
+ | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD | PSC_SPIEVNT_MD;
+ au_sync();
+}
+
+static void au1550_spi_reset_fifos(struct au1550_spi *hw)
+{
+ u32 pcr;
+
+ hw->regs->psc_spipcr = PSC_SPIPCR_RC | PSC_SPIPCR_TC;
+ au_sync();
+ do {
+ pcr = hw->regs->psc_spipcr;
+ au_sync();
+ } while (pcr != 0);
+}
+
+/*
+ * dma transfers are used for the most common spi word size of 8-bits
+ * we cannot easily change already set up dma channels' width, so if we wanted
+ * dma support for more than 8-bit words (up to 24 bits), we would need to
+ * setup dma channels from scratch on each spi transfer, based on bits_per_word
+ * instead we have pre set up 8 bit dma channels supporting spi 4 to 8 bits
+ * transfers, and 9 to 24 bits spi transfers will be done in pio irq based mode
+ * callbacks to handle dma or pio are set up in au1550_spi_bits_handlers_set()
+ */
+static void au1550_spi_chipsel(struct spi_device *spi, int value)
+{
+ struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ unsigned cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
+ u32 cfg, stat;
+
+ switch (value) {
+ case BITBANG_CS_INACTIVE:
+ if (hw->pdata->deactivate_cs)
+ hw->pdata->deactivate_cs(hw->pdata, spi->chip_select,
+ cspol);
+ break;
+
+ case BITBANG_CS_ACTIVE:
+ au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
+
+ cfg = hw->regs->psc_spicfg;
+ au_sync();
+ hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE;
+ au_sync();
+
+ if (spi->mode & SPI_CPOL)
+ cfg |= PSC_SPICFG_BI;
+ else
+ cfg &= ~PSC_SPICFG_BI;
+ if (spi->mode & SPI_CPHA)
+ cfg &= ~PSC_SPICFG_CDE;
+ else
+ cfg |= PSC_SPICFG_CDE;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ cfg |= PSC_SPICFG_MLF;
+ else
+ cfg &= ~PSC_SPICFG_MLF;
+
+ if (hw->usedma && spi->bits_per_word <= 8)
+ cfg &= ~PSC_SPICFG_DD_DISABLE;
+ else
+ cfg |= PSC_SPICFG_DD_DISABLE;
+ cfg = PSC_SPICFG_CLR_LEN(cfg);
+ cfg |= PSC_SPICFG_SET_LEN(spi->bits_per_word);
+
+ cfg = PSC_SPICFG_CLR_BAUD(cfg);
+ cfg &= ~PSC_SPICFG_SET_DIV(3);
+ cfg |= au1550_spi_baudcfg(hw, spi->max_speed_hz);
+
+ hw->regs->psc_spicfg = cfg | PSC_SPICFG_DE_ENABLE;
+ au_sync();
+ do {
+ stat = hw->regs->psc_spistat;
+ au_sync();
+ } while ((stat & PSC_SPISTAT_DR) == 0);
+
+ if (hw->pdata->activate_cs)
+ hw->pdata->activate_cs(hw->pdata, spi->chip_select,
+ cspol);
+ break;
+ }
+}
+
+static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ unsigned bpw, hz;
+ u32 cfg, stat;
+
+ bpw = t ? t->bits_per_word : spi->bits_per_word;
+ hz = t ? t->speed_hz : spi->max_speed_hz;
+
+ if (bpw < 4 || bpw > 24) {
+ dev_err(&spi->dev, "setupxfer: invalid bits_per_word=%d\n",
+ bpw);
+ return -EINVAL;
+ }
+ if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
+ dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n",
+ hz);
+ return -EINVAL;
+ }
+
+ au1550_spi_bits_handlers_set(hw, spi->bits_per_word);
+
+ cfg = hw->regs->psc_spicfg;
+ au_sync();
+ hw->regs->psc_spicfg = cfg & ~PSC_SPICFG_DE_ENABLE;
+ au_sync();
+
+ if (hw->usedma && bpw <= 8)
+ cfg &= ~PSC_SPICFG_DD_DISABLE;
+ else
+ cfg |= PSC_SPICFG_DD_DISABLE;
+ cfg = PSC_SPICFG_CLR_LEN(cfg);
+ cfg |= PSC_SPICFG_SET_LEN(bpw);
+
+ cfg = PSC_SPICFG_CLR_BAUD(cfg);
+ cfg &= ~PSC_SPICFG_SET_DIV(3);
+ cfg |= au1550_spi_baudcfg(hw, hz);
+
+ hw->regs->psc_spicfg = cfg;
+ au_sync();
+
+ if (cfg & PSC_SPICFG_DE_ENABLE) {
+ do {
+ stat = hw->regs->psc_spistat;
+ au_sync();
+ } while ((stat & PSC_SPISTAT_DR) == 0);
+ }
+
+ au1550_spi_reset_fifos(hw);
+ au1550_spi_mask_ack_all(hw);
+ return 0;
+}
+
+static int au1550_spi_setup(struct spi_device *spi)
+{
+ struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+
+ if (spi->bits_per_word == 0)
+ spi->bits_per_word = 8;
+ if (spi->bits_per_word < 4 || spi->bits_per_word > 24) {
+ dev_err(&spi->dev, "setup: invalid bits_per_word=%d\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ if (spi->max_speed_hz == 0)
+ spi->max_speed_hz = hw->freq_max;
+ if (spi->max_speed_hz > hw->freq_max
+ || spi->max_speed_hz < hw->freq_min)
+ return -EINVAL;
+ /*
+ * NOTE: cannot change speed and other hw settings immediately,
+ * otherwise sharing of spi bus is not possible,
+ * so do not call setupxfer(spi, NULL) here
+ */
+ return 0;
+}
+
+/*
+ * for dma spi transfers, we have to setup rx channel, otherwise there is
+ * no reliable way how to recognize that spi transfer is done
+ * dma complete callbacks are called before real spi transfer is finished
+ * and if only tx dma channel is set up (and rx fifo overflow event masked)
+ * spi master done event irq is not generated unless rx fifo is empty (emptied)
+ * so we need rx tmp buffer to use for rx dma if user does not provide one
+ */
+static int au1550_spi_dma_rxtmp_alloc(struct au1550_spi *hw, unsigned size)
+{
+ hw->dma_rx_tmpbuf = kmalloc(size, GFP_KERNEL);
+ if (!hw->dma_rx_tmpbuf)
+ return -ENOMEM;
+ hw->dma_rx_tmpbuf_size = size;
+ hw->dma_rx_tmpbuf_addr = dma_map_single(hw->dev, hw->dma_rx_tmpbuf,
+ size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(hw->dma_rx_tmpbuf_addr)) {
+ kfree(hw->dma_rx_tmpbuf);
+ hw->dma_rx_tmpbuf = 0;
+ hw->dma_rx_tmpbuf_size = 0;
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static void au1550_spi_dma_rxtmp_free(struct au1550_spi *hw)
+{
+ dma_unmap_single(hw->dev, hw->dma_rx_tmpbuf_addr,
+ hw->dma_rx_tmpbuf_size, DMA_FROM_DEVICE);
+ kfree(hw->dma_rx_tmpbuf);
+ hw->dma_rx_tmpbuf = 0;
+ hw->dma_rx_tmpbuf_size = 0;
+}
+
+static int au1550_spi_dma_txrxb(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ dma_addr_t dma_tx_addr;
+ dma_addr_t dma_rx_addr;
+ u32 res;
+
+ hw->len = t->len;
+ hw->tx_count = 0;
+ hw->rx_count = 0;
+
+ hw->tx = t->tx_buf;
+ hw->rx = t->rx_buf;
+ dma_tx_addr = t->tx_dma;
+ dma_rx_addr = t->rx_dma;
+
+ /*
+ * check if buffers are already dma mapped, map them otherwise
+ * use rx buffer in place of tx if tx buffer was not provided
+ * use temp rx buffer (preallocated or realloc to fit) for rx dma
+ */
+ if (t->rx_buf) {
+ if (t->rx_dma == 0) { /* if DMA_ADDR_INVALID, map it */
+ dma_rx_addr = dma_map_single(hw->dev,
+ (void *)t->rx_buf,
+ t->len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dma_rx_addr))
+ dev_err(hw->dev, "rx dma map error\n");
+ }
+ } else {
+ if (t->len > hw->dma_rx_tmpbuf_size) {
+ int ret;
+
+ au1550_spi_dma_rxtmp_free(hw);
+ ret = au1550_spi_dma_rxtmp_alloc(hw, max(t->len,
+ AU1550_SPI_DMA_RXTMP_MINSIZE));
+ if (ret < 0)
+ return ret;
+ }
+ hw->rx = hw->dma_rx_tmpbuf;
+ dma_rx_addr = hw->dma_rx_tmpbuf_addr;
+ dma_sync_single_for_device(hw->dev, dma_rx_addr,
+ t->len, DMA_FROM_DEVICE);
+ }
+ if (t->tx_buf) {
+ if (t->tx_dma == 0) { /* if DMA_ADDR_INVALID, map it */
+ dma_tx_addr = dma_map_single(hw->dev,
+ (void *)t->tx_buf,
+ t->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dma_tx_addr))
+ dev_err(hw->dev, "tx dma map error\n");
+ }
+ } else {
+ dma_sync_single_for_device(hw->dev, dma_rx_addr,
+ t->len, DMA_BIDIRECTIONAL);
+ hw->tx = hw->rx;
+ }
+
+ /* put buffers on the ring */
+ res = au1xxx_dbdma_put_dest(hw->dma_rx_ch, hw->rx, t->len);
+ if (!res)
+ dev_err(hw->dev, "rx dma put dest error\n");
+
+ res = au1xxx_dbdma_put_source(hw->dma_tx_ch, (void *)hw->tx, t->len);
+ if (!res)
+ dev_err(hw->dev, "tx dma put source error\n");
+
+ au1xxx_dbdma_start(hw->dma_rx_ch);
+ au1xxx_dbdma_start(hw->dma_tx_ch);
+
+ /* by default enable nearly all events interrupt */
+ hw->regs->psc_spimsk = PSC_SPIMSK_SD;
+ au_sync();
+
+ /* start the transfer */
+ hw->regs->psc_spipcr = PSC_SPIPCR_MS;
+ au_sync();
+
+ wait_for_completion(&hw->master_done);
+
+ au1xxx_dbdma_stop(hw->dma_tx_ch);
+ au1xxx_dbdma_stop(hw->dma_rx_ch);
+
+ if (!t->rx_buf) {
+ /* using the temporal preallocated and premapped buffer */
+ dma_sync_single_for_cpu(hw->dev, dma_rx_addr, t->len,
+ DMA_FROM_DEVICE);
+ }
+ /* unmap buffers if mapped above */
+ if (t->rx_buf && t->rx_dma == 0 )
+ dma_unmap_single(hw->dev, dma_rx_addr, t->len,
+ DMA_FROM_DEVICE);
+ if (t->tx_buf && t->tx_dma == 0 )
+ dma_unmap_single(hw->dev, dma_tx_addr, t->len,
+ DMA_TO_DEVICE);
+
+ return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;
+}
+
+static irqreturn_t au1550_spi_dma_irq_callback(struct au1550_spi *hw)
+{
+ u32 stat, evnt;
+
+ stat = hw->regs->psc_spistat;
+ evnt = hw->regs->psc_spievent;
+ au_sync();
+ if ((stat & PSC_SPISTAT_DI) == 0) {
+ dev_err(hw->dev, "Unexpected IRQ!\n");
+ return IRQ_NONE;
+ }
+
+ if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
+ | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
+ | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))
+ != 0) {
+ /*
+ * due to an spi error we consider transfer as done,
+ * so mask all events until before next transfer start
+ * and stop the possibly running dma immediatelly
+ */
+ au1550_spi_mask_ack_all(hw);
+ au1xxx_dbdma_stop(hw->dma_rx_ch);
+ au1xxx_dbdma_stop(hw->dma_tx_ch);
+
+ /* get number of transfered bytes */
+ hw->rx_count = hw->len - au1xxx_get_dma_residue(hw->dma_rx_ch);
+ hw->tx_count = hw->len - au1xxx_get_dma_residue(hw->dma_tx_ch);
+
+ au1xxx_dbdma_reset(hw->dma_rx_ch);
+ au1xxx_dbdma_reset(hw->dma_tx_ch);
+ au1550_spi_reset_fifos(hw);
+
+ dev_err(hw->dev,
+ "Unexpected SPI error: event=0x%x stat=0x%x!\n",
+ evnt, stat);
+
+ complete(&hw->master_done);
+ return IRQ_HANDLED;
+ }
+
+ if ((evnt & PSC_SPIEVNT_MD) != 0) {
+ /* transfer completed successfully */
+ au1550_spi_mask_ack_all(hw);
+ hw->rx_count = hw->len;
+ hw->tx_count = hw->len;
+ complete(&hw->master_done);
+ }
+ return IRQ_HANDLED;
+}
+
+
+/* routines to handle different word sizes in pio mode */
+#define AU1550_SPI_RX_WORD(size, mask) \
+static void au1550_spi_rx_word_##size(struct au1550_spi *hw) \
+{ \
+ u32 fifoword = hw->regs->psc_spitxrx & (u32)(mask); \
+ au_sync(); \
+ if (hw->rx) { \
+ *(u##size *)hw->rx = (u##size)fifoword; \
+ hw->rx += (size) / 8; \
+ } \
+ hw->rx_count += (size) / 8; \
+}
+
+#define AU1550_SPI_TX_WORD(size, mask) \
+static void au1550_spi_tx_word_##size(struct au1550_spi *hw) \
+{ \
+ u32 fifoword = 0; \
+ if (hw->tx) { \
+ fifoword = *(u##size *)hw->tx & (u32)(mask); \
+ hw->tx += (size) / 8; \
+ } \
+ hw->tx_count += (size) / 8; \
+ if (hw->tx_count >= hw->len) \
+ fifoword |= PSC_SPITXRX_LC; \
+ hw->regs->psc_spitxrx = fifoword; \
+ au_sync(); \
+}
+
+AU1550_SPI_RX_WORD(8,0xff)
+AU1550_SPI_RX_WORD(16,0xffff)
+AU1550_SPI_RX_WORD(32,0xffffff)
+AU1550_SPI_TX_WORD(8,0xff)
+AU1550_SPI_TX_WORD(16,0xffff)
+AU1550_SPI_TX_WORD(32,0xffffff)
+
+static int au1550_spi_pio_txrxb(struct spi_device *spi, struct spi_transfer *t)
+{
+ u32 stat, mask;
+ struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+
+ hw->tx = t->tx_buf;
+ hw->rx = t->rx_buf;
+ hw->len = t->len;
+ hw->tx_count = 0;
+ hw->rx_count = 0;
+
+ /* by default enable nearly all events after filling tx fifo */
+ mask = PSC_SPIMSK_SD;
+
+ /* fill the transmit FIFO */
+ while (hw->tx_count < hw->len) {
+
+ hw->tx_word(hw);
+
+ if (hw->tx_count >= hw->len) {
+ /* mask tx fifo request interrupt as we are done */
+ mask |= PSC_SPIMSK_TR;
+ }
+
+ stat = hw->regs->psc_spistat;
+ au_sync();
+ if (stat & PSC_SPISTAT_TF)
+ break;
+ }
+
+ /* enable event interrupts */
+ hw->regs->psc_spimsk = mask;
+ au_sync();
+
+ /* start the transfer */
+ hw->regs->psc_spipcr = PSC_SPIPCR_MS;
+ au_sync();
+
+ wait_for_completion(&hw->master_done);
+
+ return hw->rx_count < hw->tx_count ? hw->rx_count : hw->tx_count;
+}
+
+static irqreturn_t au1550_spi_pio_irq_callback(struct au1550_spi *hw)
+{
+ int busy;
+ u32 stat, evnt;
+
+ stat = hw->regs->psc_spistat;
+ evnt = hw->regs->psc_spievent;
+ au_sync();
+ if ((stat & PSC_SPISTAT_DI) == 0) {
+ dev_err(hw->dev, "Unexpected IRQ!\n");
+ return IRQ_NONE;
+ }
+
+ if ((evnt & (PSC_SPIEVNT_MM | PSC_SPIEVNT_RO
+ | PSC_SPIEVNT_RU | PSC_SPIEVNT_TO
+ | PSC_SPIEVNT_TU | PSC_SPIEVNT_SD))
+ != 0) {
+ dev_err(hw->dev,
+ "Unexpected SPI error: event=0x%x stat=0x%x!\n",
+ evnt, stat);
+ /*
+ * due to an error we consider transfer as done,
+ * so mask all events until before next transfer start
+ */
+ au1550_spi_mask_ack_all(hw);
+ au1550_spi_reset_fifos(hw);
+ complete(&hw->master_done);
+ return IRQ_HANDLED;
+ }
+
+ /*
+ * while there is something to read from rx fifo
+ * or there is a space to write to tx fifo:
+ */
+ do {
+ busy = 0;
+ stat = hw->regs->psc_spistat;
+ au_sync();
+
+ if ((stat & PSC_SPISTAT_RE) == 0 && hw->rx_count < hw->len) {
+ hw->rx_word(hw);
+ /* ack the receive request event */
+ hw->regs->psc_spievent = PSC_SPIEVNT_RR;
+ au_sync();
+ busy = 1;
+ }
+
+ if ((stat & PSC_SPISTAT_TF) == 0 && hw->tx_count < hw->len) {
+ hw->tx_word(hw);
+ /* ack the transmit request event */
+ hw->regs->psc_spievent = PSC_SPIEVNT_TR;
+ au_sync();
+ busy = 1;
+ }
+ } while (busy);
+
+ evnt = hw->regs->psc_spievent;
+ au_sync();
+
+ if (hw->rx_count >= hw->len || (evnt & PSC_SPIEVNT_MD) != 0) {
+ /* transfer completed successfully */
+ au1550_spi_mask_ack_all(hw);
+ complete(&hw->master_done);
+ }
+ return IRQ_HANDLED;
+}
+
+static int au1550_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct au1550_spi *hw = spi_master_get_devdata(spi->master);
+ return hw->txrx_bufs(spi, t);
+}
+
+static irqreturn_t au1550_spi_irq(int irq, void *dev, struct pt_regs *regs)
+{
+ struct au1550_spi *hw = dev;
+ return hw->irq_callback(hw);
+}
+
+static void au1550_spi_bits_handlers_set(struct au1550_spi *hw, int bpw)
+{
+ if (bpw <= 8) {
+ if (hw->usedma) {
+ hw->txrx_bufs = &au1550_spi_dma_txrxb;
+ hw->irq_callback = &au1550_spi_dma_irq_callback;
+ } else {
+ hw->rx_word = &au1550_spi_rx_word_8;
+ hw->tx_word = &au1550_spi_tx_word_8;
+ hw->txrx_bufs = &au1550_spi_pio_txrxb;
+ hw->irq_callback = &au1550_spi_pio_irq_callback;
+ }
+ } else if (bpw <= 16) {
+ hw->rx_word = &au1550_spi_rx_word_16;
+ hw->tx_word = &au1550_spi_tx_word_16;
+ hw->txrx_bufs = &au1550_spi_pio_txrxb;
+ hw->irq_callback = &au1550_spi_pio_irq_callback;
+ } else {
+ hw->rx_word = &au1550_spi_rx_word_32;
+ hw->tx_word = &au1550_spi_tx_word_32;
+ hw->txrx_bufs = &au1550_spi_pio_txrxb;
+ hw->irq_callback = &au1550_spi_pio_irq_callback;
+ }
+}
+
+static void __init au1550_spi_setup_psc_as_spi(struct au1550_spi *hw)
+{
+ u32 stat, cfg;
+
+ /* set up the PSC for SPI mode */
+ hw->regs->psc_ctrl = PSC_CTRL_DISABLE;
+ au_sync();
+ hw->regs->psc_sel = PSC_SEL_PS_SPIMODE;
+ au_sync();
+
+ hw->regs->psc_spicfg = 0;
+ au_sync();
+
+ hw->regs->psc_ctrl = PSC_CTRL_ENABLE;
+ au_sync();
+
+ do {
+ stat = hw->regs->psc_spistat;
+ au_sync();
+ } while ((stat & PSC_SPISTAT_SR) == 0);
+
+
+ cfg = hw->usedma ? 0 : PSC_SPICFG_DD_DISABLE;
+ cfg |= PSC_SPICFG_SET_LEN(8);
+ cfg |= PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8;
+ /* use minimal allowed brg and div values as initial setting: */
+ cfg |= PSC_SPICFG_SET_BAUD(4) | PSC_SPICFG_SET_DIV(0);
+
+#ifdef AU1550_SPI_DEBUG_LOOPBACK
+ cfg |= PSC_SPICFG_LB;
+#endif
+
+ hw->regs->psc_spicfg = cfg;
+ au_sync();
+
+ au1550_spi_mask_ack_all(hw);
+
+ hw->regs->psc_spicfg |= PSC_SPICFG_DE_ENABLE;
+ au_sync();
+
+ do {
+ stat = hw->regs->psc_spistat;
+ au_sync();
+ } while ((stat & PSC_SPISTAT_DR) == 0);
+}
+
+
+static int __init au1550_spi_probe(struct platform_device *pdev)
+{
+ struct au1550_spi *hw;
+ struct spi_master *master;
+ int err = 0;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct au1550_spi));
+ if (master == NULL) {
+ dev_err(&pdev->dev, "No memory for spi_master\n");
+ err = -ENOMEM;
+ goto err_nomem;
+ }
+
+ hw = spi_master_get_devdata(master);
+
+ hw->master = spi_master_get(master);
+ hw->pdata = pdev->dev.platform_data;
+ hw->dev = &pdev->dev;
+
+ if (hw->pdata == NULL) {
+ dev_err(&pdev->dev, "No platform data supplied\n");
+ err = -ENOENT;
+ goto err_no_pdata;
+ }
+
+ platform_set_drvdata(pdev, hw);
+
+ init_completion(&hw->master_done);
+
+ hw->bitbang.master = hw->master;
+ hw->bitbang.setup_transfer = au1550_spi_setupxfer;
+ hw->bitbang.chipselect = au1550_spi_chipsel;
+ hw->bitbang.master->setup = au1550_spi_setup;
+ hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs;
+
+ switch (hw->pdata->bus_num) {
+ case 0:
+ hw->irq = AU1550_PSC0_INT;
+ hw->regs = (volatile psc_spi_t *)PSC0_BASE_ADDR;
+ hw->dma_rx_id = DSCR_CMD0_PSC0_RX;
+ hw->dma_tx_id = DSCR_CMD0_PSC0_TX;
+ break;
+ case 1:
+ hw->irq = AU1550_PSC1_INT;
+ hw->regs = (volatile psc_spi_t *)PSC1_BASE_ADDR;
+ hw->dma_rx_id = DSCR_CMD0_PSC1_RX;
+ hw->dma_tx_id = DSCR_CMD0_PSC1_TX;
+ break;
+ case 2:
+ hw->irq = AU1550_PSC2_INT;
+ hw->regs = (volatile psc_spi_t *)PSC2_BASE_ADDR;
+ hw->dma_rx_id = DSCR_CMD0_PSC2_RX;
+ hw->dma_tx_id = DSCR_CMD0_PSC2_TX;
+ break;
+ case 3:
+ hw->irq = AU1550_PSC3_INT;
+ hw->regs = (volatile psc_spi_t *)PSC3_BASE_ADDR;
+ hw->dma_rx_id = DSCR_CMD0_PSC3_RX;
+ hw->dma_tx_id = DSCR_CMD0_PSC3_TX;
+ break;
+ default:
+ dev_err(&pdev->dev, "Wrong bus_num of SPI\n");
+ err = -ENOENT;
+ goto err_no_pdata;
+ }
+
+ if (request_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t),
+ pdev->name) == NULL) {
+ dev_err(&pdev->dev, "Cannot reserve iomem region\n");
+ err = -ENXIO;
+ goto err_no_iores;
+ }
+
+
+ if (usedma) {
+ if (pdev->dev.dma_mask == NULL)
+ dev_warn(&pdev->dev, "no dma mask\n");
+ else
+ hw->usedma = 1;
+ }
+
+ if (hw->usedma) {
+ /*
+ * create memory device with 8 bits dev_devwidth
+ * needed for proper byte ordering to spi fifo
+ */
+ int memid = au1xxx_ddma_add_device(&au1550_spi_mem_dbdev);
+ if (!memid) {
+ dev_err(&pdev->dev,
+ "Cannot create dma 8 bit mem device\n");
+ err = -ENXIO;
+ goto err_dma_add_dev;
+ }
+
+ hw->dma_tx_ch = au1xxx_dbdma_chan_alloc(memid,
+ hw->dma_tx_id, NULL, (void *)hw);
+ if (hw->dma_tx_ch == 0) {
+ dev_err(&pdev->dev,
+ "Cannot allocate tx dma channel\n");
+ err = -ENXIO;
+ goto err_no_txdma;
+ }
+ au1xxx_dbdma_set_devwidth(hw->dma_tx_ch, 8);
+ if (au1xxx_dbdma_ring_alloc(hw->dma_tx_ch,
+ AU1550_SPI_DBDMA_DESCRIPTORS) == 0) {
+ dev_err(&pdev->dev,
+ "Cannot allocate tx dma descriptors\n");
+ err = -ENXIO;
+ goto err_no_txdma_descr;
+ }
+
+
+ hw->dma_rx_ch = au1xxx_dbdma_chan_alloc(hw->dma_rx_id,
+ memid, NULL, (void *)hw);
+ if (hw->dma_rx_ch == 0) {
+ dev_err(&pdev->dev,
+ "Cannot allocate rx dma channel\n");
+ err = -ENXIO;
+ goto err_no_rxdma;
+ }
+ au1xxx_dbdma_set_devwidth(hw->dma_rx_ch, 8);
+ if (au1xxx_dbdma_ring_alloc(hw->dma_rx_ch,
+ AU1550_SPI_DBDMA_DESCRIPTORS) == 0) {
+ dev_err(&pdev->dev,
+ "Cannot allocate rx dma descriptors\n");
+ err = -ENXIO;
+ goto err_no_rxdma_descr;
+ }
+
+ err = au1550_spi_dma_rxtmp_alloc(hw,
+ AU1550_SPI_DMA_RXTMP_MINSIZE);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Cannot allocate initial rx dma tmp buffer\n");
+ goto err_dma_rxtmp_alloc;
+ }
+ }
+
+ au1550_spi_bits_handlers_set(hw, 8);
+
+ err = request_irq(hw->irq, au1550_spi_irq, 0, pdev->name, hw);
+ if (err) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto err_no_irq;
+ }
+
+ master->bus_num = hw->pdata->bus_num;
+ master->num_chipselect = hw->pdata->num_chipselect;
+
+ /*
+ * precompute valid range for spi freq - from au1550 datasheet:
+ * psc_tempclk = psc_mainclk / (2 << DIV)
+ * spiclk = psc_tempclk / (2 * (BRG + 1))
+ * BRG valid range is 4..63
+ * DIV valid range is 0..3
+ * round the min and max frequencies to values that would still
+ * produce valid brg and div
+ */
+ {
+ int min_div = (2 << 0) * (2 * (4 + 1));
+ int max_div = (2 << 3) * (2 * (63 + 1));
+ hw->freq_max = hw->pdata->mainclk_hz / min_div;
+ hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1;
+ }
+
+ au1550_spi_setup_psc_as_spi(hw);
+
+ err = spi_bitbang_start(&hw->bitbang);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register SPI master\n");
+ goto err_register;
+ }
+
+ dev_info(&pdev->dev,
+ "spi master registered: bus_num=%d num_chipselect=%d\n",
+ master->bus_num, master->num_chipselect);
+
+ return 0;
+
+err_register:
+ free_irq(hw->irq, hw);
+
+err_no_irq:
+ au1550_spi_dma_rxtmp_free(hw);
+
+err_dma_rxtmp_alloc:
+err_no_rxdma_descr:
+ if (hw->usedma)
+ au1xxx_dbdma_chan_free(hw->dma_rx_ch);
+
+err_no_rxdma:
+err_no_txdma_descr:
+ if (hw->usedma)
+ au1xxx_dbdma_chan_free(hw->dma_tx_ch);
+
+err_no_txdma:
+err_dma_add_dev:
+ release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));
+
+err_no_iores:
+err_no_pdata:
+ spi_master_put(hw->master);
+
+err_nomem:
+ return err;
+}
+
+static int __exit au1550_spi_remove(struct platform_device *pdev)
+{
+ struct au1550_spi *hw = platform_get_drvdata(pdev);
+
+ dev_info(&pdev->dev, "spi master remove: bus_num=%d\n",
+ hw->master->bus_num);
+
+ spi_bitbang_stop(&hw->bitbang);
+ free_irq(hw->irq, hw);
+ release_mem_region((unsigned long)hw->regs, sizeof(psc_spi_t));
+
+ if (hw->usedma) {
+ au1550_spi_dma_rxtmp_free(hw);
+ au1xxx_dbdma_chan_free(hw->dma_rx_ch);
+ au1xxx_dbdma_chan_free(hw->dma_tx_ch);
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ spi_master_put(hw->master);
+ return 0;
+}
+
+static struct platform_driver au1550_spi_drv = {
+ .remove = __exit_p(au1550_spi_remove),
+ .driver = {
+ .name = "au1550-spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init au1550_spi_init(void)
+{
+ return platform_driver_probe(&au1550_spi_drv, au1550_spi_probe);
+}
+module_init(au1550_spi_init);
+
+static void __exit au1550_spi_exit(void)
+{
+ platform_driver_unregister(&au1550_spi_drv);
+}
+module_exit(au1550_spi_exit);
+
+MODULE_DESCRIPTION("Au1550 PSC SPI Driver");
+MODULE_AUTHOR("Jan Nikitenko <jan.nikitenko@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 6657331eed9..c3219b29b5a 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -152,6 +152,11 @@ static void spi_drv_shutdown(struct device *dev)
sdrv->shutdown(to_spi_device(dev));
}
+/**
+ * spi_register_driver - register a SPI driver
+ * @sdrv: the driver to register
+ * Context: can sleep
+ */
int spi_register_driver(struct spi_driver *sdrv)
{
sdrv->driver.bus = &spi_bus_type;
@@ -183,7 +188,13 @@ static LIST_HEAD(board_list);
static DECLARE_MUTEX(board_lock);
-/* On typical mainboards, this is purely internal; and it's not needed
+/**
+ * spi_new_device - instantiate one new SPI device
+ * @master: Controller to which device is connected
+ * @chip: Describes the SPI device
+ * Context: can sleep
+ *
+ * On typical mainboards, this is purely internal; and it's not needed
* after board init creates the hard-wired devices. Some development
* platforms may not be able to use spi_register_board_info though, and
* this is exported so that for example a USB or parport based adapter
@@ -251,7 +262,12 @@ fail:
}
EXPORT_SYMBOL_GPL(spi_new_device);
-/*
+/**
+ * spi_register_board_info - register SPI devices for a given board
+ * @info: array of chip descriptors
+ * @n: how many descriptors are provided
+ * Context: can sleep
+ *
* Board-specific early init code calls this (probably during arch_initcall)
* with segments of the SPI device table. Any device nodes are created later,
* after the relevant parent SPI controller (bus_num) is defined. We keep
@@ -337,9 +353,10 @@ static struct class spi_master_class = {
/**
* spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus
- * @size: how much driver-private data to preallocate; the pointer to this
+ * @size: how much zeroed driver-private data to allocate; the pointer to this
* memory is in the class_data field of the returned class_device,
* accessible with spi_master_get_devdata().
+ * Context: can sleep
*
* This call is used only by SPI master controller drivers, which are the
* only ones directly touching chip registers. It's how they allocate
@@ -375,6 +392,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master);
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
+ * Context: can sleep
*
* SPI master controllers connect to their drivers using some non-SPI bus,
* such as the platform bus. The final stage of probe() in that code
@@ -437,6 +455,7 @@ static int __unregister(struct device *dev, void *unused)
/**
* spi_unregister_master - unregister SPI master controller
* @master: the master being unregistered
+ * Context: can sleep
*
* This call is used only by SPI master controller drivers, which are the
* only ones directly touching chip registers.
@@ -455,6 +474,7 @@ EXPORT_SYMBOL_GPL(spi_unregister_master);
/**
* spi_busnum_to_master - look up master associated with bus_num
* @bus_num: the master's bus number
+ * Context: can sleep
*
* This call may be used with devices that are registered after
* arch init time. It returns a refcounted pointer to the relevant
@@ -492,6 +512,7 @@ static void spi_complete(void *arg)
* spi_sync - blocking/synchronous SPI data transfers
* @spi: device with which data will be exchanged
* @message: describes the data transfers
+ * Context: can sleep
*
* This call may only be used from a context that may sleep. The sleep
* is non-interruptible, and has no timeout. Low-overhead controller
@@ -508,7 +529,7 @@ static void spi_complete(void *arg)
*
* The return value is a negative error code if the message could not be
* submitted, else zero. When the value is zero, then message->status is
- * also defined: it's the completion code for the transfer, either zero
+ * also defined; it's the completion code for the transfer, either zero
* or a negative error code from the controller driver.
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
@@ -538,6 +559,7 @@ static u8 *buf;
* @n_tx: size of txbuf, in bytes
* @rxbuf: buffer into which data will be read
* @n_rx: size of rxbuf, in bytes (need not be dma-safe)
+ * Context: can sleep
*
* This performs a half duplex MicroWire style transaction with the
* device, sending txbuf and then reading rxbuf. The return value
@@ -545,7 +567,8 @@ static u8 *buf;
* This call may only be used from a context that may sleep.
*
* Parameters to this routine are always copied using a small buffer;
- * performance-sensitive or bulk transfer code should instead use
+ * portable code should never use this for more than 32 bytes.
+ * Performance-sensitive or bulk transfer code should instead use
* spi_{async,sync}() calls with dma-safe buffers.
*/
int spi_write_then_read(struct spi_device *spi,
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
new file mode 100644
index 00000000000..ce3c0ce2316
--- /dev/null
+++ b/drivers/spi/spi_bfin5xx.c
@@ -0,0 +1,1313 @@
+/*
+ * File: drivers/spi/bfin5xx_spi.c
+ * Based on: N/A
+ * Author: Luke Yang (Analog Devices Inc.)
+ *
+ * Created: March. 10th 2006
+ * Description: SPI controller driver for Blackfin 5xx
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Modified:
+ * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang)
+ * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang)
+ *
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * 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, 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 ; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/spi/spi.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/dma.h>
+
+#include <asm/bfin5xx_spi.h>
+
+MODULE_AUTHOR("Luke Yang");
+MODULE_DESCRIPTION("Blackfin 5xx SPI Contoller");
+MODULE_LICENSE("GPL");
+
+#define IS_DMA_ALIGNED(x) (((u32)(x)&0x07)==0)
+
+#define DEFINE_SPI_REG(reg, off) \
+static inline u16 read_##reg(void) \
+ { return *(volatile unsigned short*)(SPI0_REGBASE + off); } \
+static inline void write_##reg(u16 v) \
+ {*(volatile unsigned short*)(SPI0_REGBASE + off) = v;\
+ SSYNC();}
+
+DEFINE_SPI_REG(CTRL, 0x00)
+DEFINE_SPI_REG(FLAG, 0x04)
+DEFINE_SPI_REG(STAT, 0x08)
+DEFINE_SPI_REG(TDBR, 0x0C)
+DEFINE_SPI_REG(RDBR, 0x10)
+DEFINE_SPI_REG(BAUD, 0x14)
+DEFINE_SPI_REG(SHAW, 0x18)
+#define START_STATE ((void*)0)
+#define RUNNING_STATE ((void*)1)
+#define DONE_STATE ((void*)2)
+#define ERROR_STATE ((void*)-1)
+#define QUEUE_RUNNING 0
+#define QUEUE_STOPPED 1
+int dma_requested;
+
+struct driver_data {
+ /* Driver model hookup */
+ struct platform_device *pdev;
+
+ /* SPI framework hookup */
+ struct spi_master *master;
+
+ /* BFIN hookup */
+ struct bfin5xx_spi_master *master_info;
+
+ /* Driver message queue */
+ struct workqueue_struct *workqueue;
+ struct work_struct pump_messages;
+ spinlock_t lock;
+ struct list_head queue;
+ int busy;
+ int run;
+
+ /* Message Transfer pump */
+ struct tasklet_struct pump_transfers;
+
+ /* Current message transfer state info */
+ struct spi_message *cur_msg;
+ struct spi_transfer *cur_transfer;
+ struct chip_data *cur_chip;
+ size_t len_in_bytes;
+ size_t len;
+ void *tx;
+ void *tx_end;
+ void *rx;
+ void *rx_end;
+ int dma_mapped;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma;
+ size_t rx_map_len;
+ size_t tx_map_len;
+ u8 n_bytes;
+ void (*write) (struct driver_data *);
+ void (*read) (struct driver_data *);
+ void (*duplex) (struct driver_data *);
+};
+
+struct chip_data {
+ u16 ctl_reg;
+ u16 baud;
+ u16 flag;
+
+ u8 chip_select_num;
+ u8 n_bytes;
+ u32 width; /* 0 or 1 */
+ u8 enable_dma;
+ u8 bits_per_word; /* 8 or 16 */
+ u8 cs_change_per_word;
+ u8 cs_chg_udelay;
+ void (*write) (struct driver_data *);
+ void (*read) (struct driver_data *);
+ void (*duplex) (struct driver_data *);
+};
+
+void bfin_spi_enable(struct driver_data *drv_data)
+{
+ u16 cr;
+
+ cr = read_CTRL();
+ write_CTRL(cr | BIT_CTL_ENABLE);
+ SSYNC();
+}
+
+void bfin_spi_disable(struct driver_data *drv_data)
+{
+ u16 cr;
+
+ cr = read_CTRL();
+ write_CTRL(cr & (~BIT_CTL_ENABLE));
+ SSYNC();
+}
+
+/* Caculate the SPI_BAUD register value based on input HZ */
+static u16 hz_to_spi_baud(u32 speed_hz)
+{
+ u_long sclk = get_sclk();
+ u16 spi_baud = (sclk / (2 * speed_hz));
+
+ if ((sclk % (2 * speed_hz)) > 0)
+ spi_baud++;
+
+ pr_debug("sclk = %ld, speed_hz = %d, spi_baud = %d\n", sclk, speed_hz,
+ spi_baud);
+
+ return spi_baud;
+}
+
+static int flush(struct driver_data *drv_data)
+{
+ unsigned long limit = loops_per_jiffy << 1;
+
+ /* wait for stop and clear stat */
+ while (!(read_STAT() & BIT_STAT_SPIF) && limit--)
+ continue;
+
+ write_STAT(BIT_STAT_CLR);
+
+ return limit;
+}
+
+/* stop controller and re-config current chip*/
+static void restore_state(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ /* Clear status and disable clock */
+ write_STAT(BIT_STAT_CLR);
+ bfin_spi_disable(drv_data);
+ pr_debug("restoring spi ctl state\n");
+
+#if defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537)
+ pr_debug("chip select number is %d\n", chip->chip_select_num);
+
+ switch (chip->chip_select_num) {
+ case 1:
+ bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3c00);
+ SSYNC();
+ break;
+
+ case 2:
+ case 3:
+ bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJSE_SPI);
+ SSYNC();
+ bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
+ SSYNC();
+ break;
+
+ case 4:
+ bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS4E_SPI);
+ SSYNC();
+ bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3840);
+ SSYNC();
+ break;
+
+ case 5:
+ bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS5E_SPI);
+ SSYNC();
+ bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3820);
+ SSYNC();
+ break;
+
+ case 6:
+ bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PFS6E_SPI);
+ SSYNC();
+ bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3810);
+ SSYNC();
+ break;
+
+ case 7:
+ bfin_write_PORT_MUX(bfin_read_PORT_MUX() | PJCE_SPI);
+ SSYNC();
+ bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0x3800);
+ SSYNC();
+ break;
+ }
+#endif
+
+ /* Load the registers */
+ write_CTRL(chip->ctl_reg);
+ write_BAUD(chip->baud);
+ write_FLAG(chip->flag);
+}
+
+/* used to kick off transfer in rx mode */
+static unsigned short dummy_read(void)
+{
+ unsigned short tmp;
+ tmp = read_RDBR();
+ return tmp;
+}
+
+static void null_writer(struct driver_data *drv_data)
+{
+ u8 n_bytes = drv_data->n_bytes;
+
+ while (drv_data->tx < drv_data->tx_end) {
+ write_TDBR(0);
+ while ((read_STAT() & BIT_STAT_TXS))
+ continue;
+ drv_data->tx += n_bytes;
+ }
+}
+
+static void null_reader(struct driver_data *drv_data)
+{
+ u8 n_bytes = drv_data->n_bytes;
+ dummy_read();
+
+ while (drv_data->rx < drv_data->rx_end) {
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ dummy_read();
+ drv_data->rx += n_bytes;
+ }
+}
+
+static void u8_writer(struct driver_data *drv_data)
+{
+ pr_debug("cr8-s is 0x%x\n", read_STAT());
+ while (drv_data->tx < drv_data->tx_end) {
+ write_TDBR(*(u8 *) (drv_data->tx));
+ while (read_STAT() & BIT_STAT_TXS)
+ continue;
+ ++drv_data->tx;
+ }
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+}
+
+static void u8_cs_chg_writer(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ while (drv_data->tx < drv_data->tx_end) {
+ write_FLAG(chip->flag);
+ SSYNC();
+
+ write_TDBR(*(u8 *) (drv_data->tx));
+ while (read_STAT() & BIT_STAT_TXS)
+ continue;
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ write_FLAG(0xFF00 | chip->flag);
+ SSYNC();
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+ ++drv_data->tx;
+ }
+ write_FLAG(0xFF00);
+ SSYNC();
+}
+
+static void u8_reader(struct driver_data *drv_data)
+{
+ pr_debug("cr-8 is 0x%x\n", read_STAT());
+
+ /* clear TDBR buffer before read(else it will be shifted out) */
+ write_TDBR(0xFFFF);
+
+ dummy_read();
+
+ while (drv_data->rx < drv_data->rx_end - 1) {
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u8 *) (drv_data->rx) = read_RDBR();
+ ++drv_data->rx;
+ }
+
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u8 *) (drv_data->rx) = read_SHAW();
+ ++drv_data->rx;
+}
+
+static void u8_cs_chg_reader(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ while (drv_data->rx < drv_data->rx_end) {
+ write_FLAG(chip->flag);
+ SSYNC();
+
+ read_RDBR(); /* kick off */
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ *(u8 *) (drv_data->rx) = read_SHAW();
+ write_FLAG(0xFF00 | chip->flag);
+ SSYNC();
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+ ++drv_data->rx;
+ }
+ write_FLAG(0xFF00);
+ SSYNC();
+}
+
+static void u8_duplex(struct driver_data *drv_data)
+{
+ /* in duplex mode, clk is triggered by writing of TDBR */
+ while (drv_data->rx < drv_data->rx_end) {
+ write_TDBR(*(u8 *) (drv_data->tx));
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u8 *) (drv_data->rx) = read_RDBR();
+ ++drv_data->rx;
+ ++drv_data->tx;
+ }
+}
+
+static void u8_cs_chg_duplex(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ while (drv_data->rx < drv_data->rx_end) {
+ write_FLAG(chip->flag);
+ SSYNC();
+
+ write_TDBR(*(u8 *) (drv_data->tx));
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u8 *) (drv_data->rx) = read_RDBR();
+ write_FLAG(0xFF00 | chip->flag);
+ SSYNC();
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+ ++drv_data->rx;
+ ++drv_data->tx;
+ }
+ write_FLAG(0xFF00);
+ SSYNC();
+}
+
+static void u16_writer(struct driver_data *drv_data)
+{
+ pr_debug("cr16 is 0x%x\n", read_STAT());
+ while (drv_data->tx < drv_data->tx_end) {
+ write_TDBR(*(u16 *) (drv_data->tx));
+ while ((read_STAT() & BIT_STAT_TXS))
+ continue;
+ drv_data->tx += 2;
+ }
+
+ /* poll for SPI completion before returning */
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+}
+
+static void u16_cs_chg_writer(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ while (drv_data->tx < drv_data->tx_end) {
+ write_FLAG(chip->flag);
+ SSYNC();
+
+ write_TDBR(*(u16 *) (drv_data->tx));
+ while ((read_STAT() & BIT_STAT_TXS))
+ continue;
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ write_FLAG(0xFF00 | chip->flag);
+ SSYNC();
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+ drv_data->tx += 2;
+ }
+ write_FLAG(0xFF00);
+ SSYNC();
+}
+
+static void u16_reader(struct driver_data *drv_data)
+{
+ pr_debug("cr-16 is 0x%x\n", read_STAT());
+ dummy_read();
+
+ while (drv_data->rx < (drv_data->rx_end - 2)) {
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u16 *) (drv_data->rx) = read_RDBR();
+ drv_data->rx += 2;
+ }
+
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u16 *) (drv_data->rx) = read_SHAW();
+ drv_data->rx += 2;
+}
+
+static void u16_cs_chg_reader(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ while (drv_data->rx < drv_data->rx_end) {
+ write_FLAG(chip->flag);
+ SSYNC();
+
+ read_RDBR(); /* kick off */
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ *(u16 *) (drv_data->rx) = read_SHAW();
+ write_FLAG(0xFF00 | chip->flag);
+ SSYNC();
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+ drv_data->rx += 2;
+ }
+ write_FLAG(0xFF00);
+ SSYNC();
+}
+
+static void u16_duplex(struct driver_data *drv_data)
+{
+ /* in duplex mode, clk is triggered by writing of TDBR */
+ while (drv_data->tx < drv_data->tx_end) {
+ write_TDBR(*(u16 *) (drv_data->tx));
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u16 *) (drv_data->rx) = read_RDBR();
+ drv_data->rx += 2;
+ drv_data->tx += 2;
+ }
+}
+
+static void u16_cs_chg_duplex(struct driver_data *drv_data)
+{
+ struct chip_data *chip = drv_data->cur_chip;
+
+ while (drv_data->tx < drv_data->tx_end) {
+ write_FLAG(chip->flag);
+ SSYNC();
+
+ write_TDBR(*(u16 *) (drv_data->tx));
+ while (!(read_STAT() & BIT_STAT_SPIF))
+ continue;
+ while (!(read_STAT() & BIT_STAT_RXS))
+ continue;
+ *(u16 *) (drv_data->rx) = read_RDBR();
+ write_FLAG(0xFF00 | chip->flag);
+ SSYNC();
+ if (chip->cs_chg_udelay)
+ udelay(chip->cs_chg_udelay);
+ drv_data->rx += 2;
+ drv_data->tx += 2;
+ }
+ write_FLAG(0xFF00);
+ SSYNC();
+}
+
+/* test if ther is more transfer to be done */
+static void *next_transfer(struct driver_data *drv_data)
+{
+ struct spi_message *msg = drv_data->cur_msg;
+ struct spi_transfer *trans = drv_data->cur_transfer;
+
+ /* Move to next transfer */
+ if (trans->transfer_list.next != &msg->transfers) {
+ drv_data->cur_transfer =
+ list_entry(trans->transfer_list.next,
+ struct spi_transfer, transfer_list);
+ return RUNNING_STATE;
+ } else
+ return DONE_STATE;
+}
+
+/*
+ * caller already set message->status;
+ * dma and pio irqs are blocked give finished message back
+ */
+static void giveback(struct driver_data *drv_data)
+{
+ struct spi_transfer *last_transfer;
+ unsigned long flags;
+ struct spi_message *msg;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+ msg = drv_data->cur_msg;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ last_transfer = list_entry(msg->transfers.prev,
+ struct spi_transfer, transfer_list);
+
+ msg->state = NULL;
+
+ /* disable chip select signal. And not stop spi in autobuffer mode */
+ if (drv_data->tx_dma != 0xFFFF) {
+ write_FLAG(0xFF00);
+ bfin_spi_disable(drv_data);
+ }
+
+ if (msg->complete)
+ msg->complete(msg->context);
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct driver_data *drv_data = (struct driver_data *)dev_id;
+ struct spi_message *msg = drv_data->cur_msg;
+
+ pr_debug("in dma_irq_handler\n");
+ clear_dma_irqstat(CH_SPI);
+
+ /*
+ * wait for the last transaction shifted out. yes, these two
+ * while loops are supposed to be the same (see the HRM).
+ */
+ if (drv_data->tx != NULL) {
+ while (bfin_read_SPI_STAT() & TXS)
+ continue;
+ while (bfin_read_SPI_STAT() & TXS)
+ continue;
+ }
+
+ while (!(bfin_read_SPI_STAT() & SPIF))
+ continue;
+
+ bfin_spi_disable(drv_data);
+
+ msg->actual_length += drv_data->len_in_bytes;
+
+ /* Move to next transfer */
+ msg->state = next_transfer(drv_data);
+
+ /* Schedule transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ /* free the irq handler before next transfer */
+ pr_debug("disable dma channel irq%d\n", CH_SPI);
+ dma_disable_irq(CH_SPI);
+
+ return IRQ_HANDLED;
+}
+
+static void pump_transfers(unsigned long data)
+{
+ struct driver_data *drv_data = (struct driver_data *)data;
+ struct spi_message *message = NULL;
+ struct spi_transfer *transfer = NULL;
+ struct spi_transfer *previous = NULL;
+ struct chip_data *chip = NULL;
+ u16 cr, width, dma_width, dma_config;
+ u32 tranf_success = 1;
+
+ /* Get current state information */
+ message = drv_data->cur_msg;
+ transfer = drv_data->cur_transfer;
+ chip = drv_data->cur_chip;
+
+ /*
+ * if msg is error or done, report it back using complete() callback
+ */
+
+ /* Handle for abort */
+ if (message->state == ERROR_STATE) {
+ message->status = -EIO;
+ giveback(drv_data);
+ return;
+ }
+
+ /* Handle end of message */
+ if (message->state == DONE_STATE) {
+ message->status = 0;
+ giveback(drv_data);
+ return;
+ }
+
+ /* Delay if requested at end of transfer */
+ if (message->state == RUNNING_STATE) {
+ previous = list_entry(transfer->transfer_list.prev,
+ struct spi_transfer, transfer_list);
+ if (previous->delay_usecs)
+ udelay(previous->delay_usecs);
+ }
+
+ /* Setup the transfer state based on the type of transfer */
+ if (flush(drv_data) == 0) {
+ dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
+ message->status = -EIO;
+ giveback(drv_data);
+ return;
+ }
+
+ if (transfer->tx_buf != NULL) {
+ drv_data->tx = (void *)transfer->tx_buf;
+ drv_data->tx_end = drv_data->tx + transfer->len;
+ pr_debug("tx_buf is %p, tx_end is %p\n", transfer->tx_buf,
+ drv_data->tx_end);
+ } else {
+ drv_data->tx = NULL;
+ }
+
+ if (transfer->rx_buf != NULL) {
+ drv_data->rx = transfer->rx_buf;
+ drv_data->rx_end = drv_data->rx + transfer->len;
+ pr_debug("rx_buf is %p, rx_end is %p\n", transfer->rx_buf,
+ drv_data->rx_end);
+ } else {
+ drv_data->rx = NULL;
+ }
+
+ drv_data->rx_dma = transfer->rx_dma;
+ drv_data->tx_dma = transfer->tx_dma;
+ drv_data->len_in_bytes = transfer->len;
+
+ width = chip->width;
+ if (width == CFG_SPI_WORDSIZE16) {
+ drv_data->len = (transfer->len) >> 1;
+ } else {
+ drv_data->len = transfer->len;
+ }
+ drv_data->write = drv_data->tx ? chip->write : null_writer;
+ drv_data->read = drv_data->rx ? chip->read : null_reader;
+ drv_data->duplex = chip->duplex ? chip->duplex : null_writer;
+ pr_debug
+ ("transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
+ drv_data->write, chip->write, null_writer);
+
+ /* speed and width has been set on per message */
+ message->state = RUNNING_STATE;
+ dma_config = 0;
+
+ /* restore spi status for each spi transfer */
+ if (transfer->speed_hz) {
+ write_BAUD(hz_to_spi_baud(transfer->speed_hz));
+ } else {
+ write_BAUD(chip->baud);
+ }
+ write_FLAG(chip->flag);
+
+ pr_debug("now pumping a transfer: width is %d, len is %d\n", width,
+ transfer->len);
+
+ /*
+ * Try to map dma buffer and do a dma transfer if
+ * successful use different way to r/w according to
+ * drv_data->cur_chip->enable_dma
+ */
+ if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+
+ write_STAT(BIT_STAT_CLR);
+ disable_dma(CH_SPI);
+ clear_dma_irqstat(CH_SPI);
+ bfin_spi_disable(drv_data);
+
+ /* config dma channel */
+ pr_debug("doing dma transfer\n");
+ if (width == CFG_SPI_WORDSIZE16) {
+ set_dma_x_count(CH_SPI, drv_data->len);
+ set_dma_x_modify(CH_SPI, 2);
+ dma_width = WDSIZE_16;
+ } else {
+ set_dma_x_count(CH_SPI, drv_data->len);
+ set_dma_x_modify(CH_SPI, 1);
+ dma_width = WDSIZE_8;
+ }
+
+ /* set transfer width,direction. And enable spi */
+ cr = (read_CTRL() & (~BIT_CTL_TIMOD));
+
+ /* dirty hack for autobuffer DMA mode */
+ if (drv_data->tx_dma == 0xFFFF) {
+ pr_debug("doing autobuffer DMA out.\n");
+
+ /* no irq in autobuffer mode */
+ dma_config =
+ (DMAFLOW_AUTO | RESTART | dma_width | DI_EN);
+ set_dma_config(CH_SPI, dma_config);
+ set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
+ enable_dma(CH_SPI);
+ write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
+ (CFG_SPI_ENABLE << 14));
+
+ /* just return here, there can only be one transfer in this mode */
+ message->status = 0;
+ giveback(drv_data);
+ return;
+ }
+
+ /* In dma mode, rx or tx must be NULL in one transfer */
+ if (drv_data->rx != NULL) {
+ /* set transfer mode, and enable SPI */
+ pr_debug("doing DMA in.\n");
+
+ /* disable SPI before write to TDBR */
+ write_CTRL(cr & ~BIT_CTL_ENABLE);
+
+ /* clear tx reg soformer data is not shifted out */
+ write_TDBR(0xFF);
+
+ set_dma_x_count(CH_SPI, drv_data->len);
+
+ /* start dma */
+ dma_enable_irq(CH_SPI);
+ dma_config = (WNR | RESTART | dma_width | DI_EN);
+ set_dma_config(CH_SPI, dma_config);
+ set_dma_start_addr(CH_SPI, (unsigned long)drv_data->rx);
+ enable_dma(CH_SPI);
+
+ cr |=
+ CFG_SPI_DMAREAD | (width << 8) | (CFG_SPI_ENABLE <<
+ 14);
+ /* set transfer mode, and enable SPI */
+ write_CTRL(cr);
+ } else if (drv_data->tx != NULL) {
+ pr_debug("doing DMA out.\n");
+
+ /* start dma */
+ dma_enable_irq(CH_SPI);
+ dma_config = (RESTART | dma_width | DI_EN);
+ set_dma_config(CH_SPI, dma_config);
+ set_dma_start_addr(CH_SPI, (unsigned long)drv_data->tx);
+ enable_dma(CH_SPI);
+
+ write_CTRL(cr | CFG_SPI_DMAWRITE | (width << 8) |
+ (CFG_SPI_ENABLE << 14));
+
+ }
+ } else {
+ /* IO mode write then read */
+ pr_debug("doing IO transfer\n");
+
+ write_STAT(BIT_STAT_CLR);
+
+ if (drv_data->tx != NULL && drv_data->rx != NULL) {
+ /* full duplex mode */
+ BUG_ON((drv_data->tx_end - drv_data->tx) !=
+ (drv_data->rx_end - drv_data->rx));
+ cr = (read_CTRL() & (~BIT_CTL_TIMOD)); /* clear the TIMOD bits */
+ cr |=
+ CFG_SPI_WRITE | (width << 8) | (CFG_SPI_ENABLE <<
+ 14);
+ pr_debug("IO duplex: cr is 0x%x\n", cr);
+
+ write_CTRL(cr);
+ SSYNC();
+
+ drv_data->duplex(drv_data);
+
+ if (drv_data->tx != drv_data->tx_end)
+ tranf_success = 0;
+ } else if (drv_data->tx != NULL) {
+ /* write only half duplex */
+ cr = (read_CTRL() & (~BIT_CTL_TIMOD)); /* clear the TIMOD bits */
+ cr |=
+ CFG_SPI_WRITE | (width << 8) | (CFG_SPI_ENABLE <<
+ 14);
+ pr_debug("IO write: cr is 0x%x\n", cr);
+
+ write_CTRL(cr);
+ SSYNC();
+
+ drv_data->write(drv_data);
+
+ if (drv_data->tx != drv_data->tx_end)
+ tranf_success = 0;
+ } else if (drv_data->rx != NULL) {
+ /* read only half duplex */
+ cr = (read_CTRL() & (~BIT_CTL_TIMOD)); /* cleare the TIMOD bits */
+ cr |=
+ CFG_SPI_READ | (width << 8) | (CFG_SPI_ENABLE <<
+ 14);
+ pr_debug("IO read: cr is 0x%x\n", cr);
+
+ write_CTRL(cr);
+ SSYNC();
+
+ drv_data->read(drv_data);
+ if (drv_data->rx != drv_data->rx_end)
+ tranf_success = 0;
+ }
+
+ if (!tranf_success) {
+ pr_debug("IO write error!\n");
+ message->state = ERROR_STATE;
+ } else {
+ /* Update total byte transfered */
+ message->actual_length += drv_data->len;
+
+ /* Move to next transfer of this msg */
+ message->state = next_transfer(drv_data);
+ }
+
+ /* Schedule next transfer tasklet */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ }
+}
+
+/* pop a msg from queue and kick off real transfer */
+static void pump_messages(struct work_struct *work)
+{
+ struct driver_data *drv_data = container_of(work, struct driver_data, pump_messages);
+ unsigned long flags;
+
+ /* Lock queue and check for queue work */
+ spin_lock_irqsave(&drv_data->lock, flags);
+ if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+ /* pumper kicked off but no work to do */
+ drv_data->busy = 0;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ /* Make sure we are not already running a message */
+ if (drv_data->cur_msg) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return;
+ }
+
+ /* Extract head of queue */
+ drv_data->cur_msg = list_entry(drv_data->queue.next,
+ struct spi_message, queue);
+ list_del_init(&drv_data->cur_msg->queue);
+
+ /* Initial message state */
+ drv_data->cur_msg->state = START_STATE;
+ drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,
+ struct spi_transfer, transfer_list);
+
+ /* Setup the SSP using the per chip configuration */
+ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);
+ restore_state(drv_data);
+ pr_debug
+ ("got a message to pump, state is set to: baud %d, flag 0x%x, ctl 0x%x\n",
+ drv_data->cur_chip->baud, drv_data->cur_chip->flag,
+ drv_data->cur_chip->ctl_reg);
+ pr_debug("the first transfer len is %d\n", drv_data->cur_transfer->len);
+
+ /* Mark as busy and launch transfers */
+ tasklet_schedule(&drv_data->pump_transfers);
+
+ drv_data->busy = 1;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+}
+
+/*
+ * got a msg to transfer, queue it in drv_data->queue.
+ * And kick off message pumper
+ */
+static int transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->run == QUEUE_STOPPED) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -ESHUTDOWN;
+ }
+
+ msg->actual_length = 0;
+ msg->status = -EINPROGRESS;
+ msg->state = START_STATE;
+
+ pr_debug("adding an msg in transfer() \n");
+ list_add_tail(&msg->queue, &drv_data->queue);
+
+ if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return 0;
+}
+
+/* first setup for new devices */
+static int setup(struct spi_device *spi)
+{
+ struct bfin5xx_spi_chip *chip_info = NULL;
+ struct chip_data *chip;
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+ u8 spi_flg;
+
+ /* Abort device setup if requested features are not supported */
+ if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
+ dev_err(&spi->dev, "requested mode not fully supported\n");
+ return -EINVAL;
+ }
+
+ /* Zero (the default) here means 8 bits */
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
+ return -EINVAL;
+
+ /* Only alloc (or use chip_info) on first setup */
+ chip = spi_get_ctldata(spi);
+ if (chip == NULL) {
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->enable_dma = 0;
+ chip_info = spi->controller_data;
+ }
+
+ /* chip_info isn't always needed */
+ if (chip_info) {
+ chip->enable_dma = chip_info->enable_dma != 0
+ && drv_data->master_info->enable_dma;
+ chip->ctl_reg = chip_info->ctl_reg;
+ chip->bits_per_word = chip_info->bits_per_word;
+ chip->cs_change_per_word = chip_info->cs_change_per_word;
+ chip->cs_chg_udelay = chip_info->cs_chg_udelay;
+ }
+
+ /* translate common spi framework into our register */
+ if (spi->mode & SPI_CPOL)
+ chip->ctl_reg |= CPOL;
+ if (spi->mode & SPI_CPHA)
+ chip->ctl_reg |= CPHA;
+ if (spi->mode & SPI_LSB_FIRST)
+ chip->ctl_reg |= LSBF;
+ /* we dont support running in slave mode (yet?) */
+ chip->ctl_reg |= MSTR;
+
+ /*
+ * if any one SPI chip is registered and wants DMA, request the
+ * DMA channel for it
+ */
+ if (chip->enable_dma && !dma_requested) {
+ /* register dma irq handler */
+ if (request_dma(CH_SPI, "BF53x_SPI_DMA") < 0) {
+ pr_debug
+ ("Unable to request BlackFin SPI DMA channel\n");
+ return -ENODEV;
+ }
+ if (set_dma_callback(CH_SPI, (void *)dma_irq_handler, drv_data)
+ < 0) {
+ pr_debug("Unable to set dma callback\n");
+ return -EPERM;
+ }
+ dma_disable_irq(CH_SPI);
+ dma_requested = 1;
+ }
+
+ /*
+ * Notice: for blackfin, the speed_hz is the value of register
+ * SPI_BAUD, not the real baudrate
+ */
+ chip->baud = hz_to_spi_baud(spi->max_speed_hz);
+ spi_flg = ~(1 << (spi->chip_select));
+ chip->flag = ((u16) spi_flg << 8) | (1 << (spi->chip_select));
+ chip->chip_select_num = spi->chip_select;
+
+ switch (chip->bits_per_word) {
+ case 8:
+ chip->n_bytes = 1;
+ chip->width = CFG_SPI_WORDSIZE8;
+ chip->read = chip->cs_change_per_word ?
+ u8_cs_chg_reader : u8_reader;
+ chip->write = chip->cs_change_per_word ?
+ u8_cs_chg_writer : u8_writer;
+ chip->duplex = chip->cs_change_per_word ?
+ u8_cs_chg_duplex : u8_duplex;
+ break;
+
+ case 16:
+ chip->n_bytes = 2;
+ chip->width = CFG_SPI_WORDSIZE16;
+ chip->read = chip->cs_change_per_word ?
+ u16_cs_chg_reader : u16_reader;
+ chip->write = chip->cs_change_per_word ?
+ u16_cs_chg_writer : u16_writer;
+ chip->duplex = chip->cs_change_per_word ?
+ u16_cs_chg_duplex : u16_duplex;
+ break;
+
+ default:
+ dev_err(&spi->dev, "%d bits_per_word is not supported\n",
+ chip->bits_per_word);
+ kfree(chip);
+ return -ENODEV;
+ }
+
+ pr_debug("setup spi chip %s, width is %d, dma is %d,",
+ spi->modalias, chip->width, chip->enable_dma);
+ pr_debug("ctl_reg is 0x%x, flag_reg is 0x%x\n",
+ chip->ctl_reg, chip->flag);
+
+ spi_set_ctldata(spi, chip);
+
+ return 0;
+}
+
+/*
+ * callback for spi framework.
+ * clean driver specific data
+ */
+static void cleanup(const struct spi_device *spi)
+{
+ struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
+
+ kfree(chip);
+}
+
+static inline int init_queue(struct driver_data *drv_data)
+{
+ INIT_LIST_HEAD(&drv_data->queue);
+ spin_lock_init(&drv_data->lock);
+
+ drv_data->run = QUEUE_STOPPED;
+ drv_data->busy = 0;
+
+ /* init transfer tasklet */
+ tasklet_init(&drv_data->pump_transfers,
+ pump_transfers, (unsigned long)drv_data);
+
+ /* init messages workqueue */
+ INIT_WORK(&drv_data->pump_messages, pump_messages);
+ drv_data->workqueue =
+ create_singlethread_workqueue(drv_data->master->cdev.dev->bus_id);
+ if (drv_data->workqueue == NULL)
+ return -EBUSY;
+
+ return 0;
+}
+
+static inline int start_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ return -EBUSY;
+ }
+
+ drv_data->run = QUEUE_RUNNING;
+ drv_data->cur_msg = NULL;
+ drv_data->cur_transfer = NULL;
+ drv_data->cur_chip = NULL;
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ queue_work(drv_data->workqueue, &drv_data->pump_messages);
+
+ return 0;
+}
+
+static inline int stop_queue(struct driver_data *drv_data)
+{
+ unsigned long flags;
+ unsigned limit = 500;
+ int status = 0;
+
+ spin_lock_irqsave(&drv_data->lock, flags);
+
+ /*
+ * This is a bit lame, but is optimized for the common execution path.
+ * A wait_queue on the drv_data->busy could be used, but then the common
+ * execution path (pump_messages) would be required to call wake_up or
+ * friends on every SPI message. Do this instead
+ */
+ drv_data->run = QUEUE_STOPPED;
+ while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+ msleep(10);
+ spin_lock_irqsave(&drv_data->lock, flags);
+ }
+
+ if (!list_empty(&drv_data->queue) || drv_data->busy)
+ status = -EBUSY;
+
+ spin_unlock_irqrestore(&drv_data->lock, flags);
+
+ return status;
+}
+
+static inline int destroy_queue(struct driver_data *drv_data)
+{
+ int status;
+
+ status = stop_queue(drv_data);
+ if (status != 0)
+ return status;
+
+ destroy_workqueue(drv_data->workqueue);
+
+ return 0;
+}
+
+static int __init bfin5xx_spi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bfin5xx_spi_master *platform_info;
+ struct spi_master *master;
+ struct driver_data *drv_data = 0;
+ int status = 0;
+
+ platform_info = dev->platform_data;
+
+ /* Allocate master with space for drv_data */
+ master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+ if (!master) {
+ dev_err(&pdev->dev, "can not alloc spi_master\n");
+ return -ENOMEM;
+ }
+ drv_data = spi_master_get_devdata(master);
+ drv_data->master = master;
+ drv_data->master_info = platform_info;
+ drv_data->pdev = pdev;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = platform_info->num_chipselect;
+ master->cleanup = cleanup;
+ master->setup = setup;
+ master->transfer = transfer;
+
+ /* Initial and start queue */
+ status = init_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem initializing queue\n");
+ goto out_error_queue_alloc;
+ }
+ status = start_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem starting queue\n");
+ goto out_error_queue_alloc;
+ }
+
+ /* Register with the SPI framework */
+ platform_set_drvdata(pdev, drv_data);
+ status = spi_register_master(master);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem registering spi master\n");
+ goto out_error_queue_alloc;
+ }
+ pr_debug("controller probe successfully\n");
+ return status;
+
+ out_error_queue_alloc:
+ destroy_queue(drv_data);
+ spi_master_put(master);
+ return status;
+}
+
+/* stop hardware and remove the driver */
+static int __devexit bfin5xx_spi_remove(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ if (!drv_data)
+ return 0;
+
+ /* Remove the queue */
+ status = destroy_queue(drv_data);
+ if (status != 0)
+ return status;
+
+ /* Disable the SSP at the peripheral and SOC level */
+ bfin_spi_disable(drv_data);
+
+ /* Release DMA */
+ if (drv_data->master_info->enable_dma) {
+ if (dma_channel_active(CH_SPI))
+ free_dma(CH_SPI);
+ }
+
+ /* Disconnect from the SPI framework */
+ spi_unregister_master(drv_data->master);
+
+ /* Prevent double remove */
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin5xx_spi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ status = stop_queue(drv_data);
+ if (status != 0)
+ return status;
+
+ /* stop hardware */
+ bfin_spi_disable(drv_data);
+
+ return 0;
+}
+
+static int bfin5xx_spi_resume(struct platform_device *pdev)
+{
+ struct driver_data *drv_data = platform_get_drvdata(pdev);
+ int status = 0;
+
+ /* Enable the SPI interface */
+ bfin_spi_enable(drv_data);
+
+ /* Start the queue running */
+ status = start_queue(drv_data);
+ if (status != 0) {
+ dev_err(&pdev->dev, "problem starting queue (%d)\n", status);
+ return status;
+ }
+
+ return 0;
+}
+#else
+#define bfin5xx_spi_suspend NULL
+#define bfin5xx_spi_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver bfin5xx_spi_driver = {
+ .driver = {
+ .name = "bfin-spi-master",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = bfin5xx_spi_probe,
+ .remove = __devexit_p(bfin5xx_spi_remove),
+ .suspend = bfin5xx_spi_suspend,
+ .resume = bfin5xx_spi_resume,
+};
+
+static int __init bfin5xx_spi_init(void)
+{
+ return platform_driver_register(&bfin5xx_spi_driver);
+}
+
+module_init(bfin5xx_spi_init);
+
+static void __exit bfin5xx_spi_exit(void)
+{
+ platform_driver_unregister(&bfin5xx_spi_driver);
+}
+
+module_exit(bfin5xx_spi_exit);
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
index 312987a0321..0ee2b209025 100644
--- a/drivers/spi/spi_butterfly.c
+++ b/drivers/spi/spi_butterfly.c
@@ -20,7 +20,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/platform_device.h>
+#include <linux/device.h>
#include <linux/parport.h>
#include <linux/sched.h>
@@ -40,8 +40,6 @@
* and use this custom parallel port cable.
*/
-#undef HAVE_USI /* nyet */
-
/* DATA output bits (pins 2..9 == D0..D7) */
#define butterfly_nreset (1 << 1) /* pin 3 */
@@ -49,19 +47,13 @@
#define spi_sck_bit (1 << 0) /* pin 2 */
#define spi_mosi_bit (1 << 7) /* pin 9 */
-#define usi_sck_bit (1 << 3) /* pin 5 */
-#define usi_mosi_bit (1 << 4) /* pin 6 */
-
#define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */
/* STATUS input bits */
#define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */
-#define usi_miso_bit PARPORT_STATUS_PAPEROUT /* pin 12 */
-
/* CONTROL output bits */
#define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */
-/* USI uses no chipselect */
@@ -70,15 +62,6 @@ static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
return spi->controller_data;
}
-static inline int is_usidev(struct spi_device *spi)
-{
-#ifdef HAVE_USI
- return spi->chip_select != 1;
-#else
- return 0;
-#endif
-}
-
struct butterfly {
/* REVISIT ... for now, this must be first */
@@ -97,23 +80,13 @@ struct butterfly {
/*----------------------------------------------------------------------*/
-/*
- * these routines may be slower than necessary because they're hiding
- * the fact that there are two different SPI busses on this cable: one
- * to the DataFlash chip (or AVR SPI controller), the other to the
- * AVR USI controller.
- */
-
static inline void
setsck(struct spi_device *spi, int is_on)
{
struct butterfly *pp = spidev_to_pp(spi);
u8 bit, byte = pp->lastbyte;
- if (is_usidev(spi))
- bit = usi_sck_bit;
- else
- bit = spi_sck_bit;
+ bit = spi_sck_bit;
if (is_on)
byte |= bit;
@@ -129,10 +102,7 @@ setmosi(struct spi_device *spi, int is_on)
struct butterfly *pp = spidev_to_pp(spi);
u8 bit, byte = pp->lastbyte;
- if (is_usidev(spi))
- bit = usi_mosi_bit;
- else
- bit = spi_mosi_bit;
+ bit = spi_mosi_bit;
if (is_on)
byte |= bit;
@@ -148,10 +118,7 @@ static inline int getmiso(struct spi_device *spi)
int value;
u8 bit;
- if (is_usidev(spi))
- bit = usi_miso_bit;
- else
- bit = spi_miso_bit;
+ bit = spi_miso_bit;
/* only STATUS_BUSY is NOT negated */
value = !(parport_read_status(pp->port) & bit);
@@ -166,10 +133,6 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
if (value != BITBANG_CS_INACTIVE)
setsck(spi, spi->mode & SPI_CPOL);
- /* no chipselect on this USI link config */
- if (is_usidev(spi))
- return;
-
/* here, value == "activate or not";
* most PARPORT_CONTROL_* bits are negated, so we must
* morph it to value == "bit value to write in control register"
@@ -237,24 +200,16 @@ static void butterfly_attach(struct parport *p)
int status;
struct butterfly *pp;
struct spi_master *master;
- struct platform_device *pdev;
+ struct device *dev = p->physport->dev;
- if (butterfly)
+ if (butterfly || !dev)
return;
/* REVISIT: this just _assumes_ a butterfly is there ... no probe,
* and no way to be selective about what it binds to.
*/
- /* FIXME where should master->cdev.dev come from?
- * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc
- * setting up a platform device like this is an ugly kluge...
- */
- pdev = platform_device_register_simple("butterfly", -1, NULL, 0);
- if (IS_ERR(pdev))
- return;
-
- master = spi_alloc_master(&pdev->dev, sizeof *pp);
+ master = spi_alloc_master(dev, sizeof *pp);
if (!master) {
status = -ENOMEM;
goto done;
@@ -300,7 +255,7 @@ static void butterfly_attach(struct parport *p)
parport_frob_control(pp->port, spi_cs_bit, 0);
/* stabilize power with chip in reset (nRESET), and
- * both spi_sck_bit and usi_sck_bit clear (CPOL=0)
+ * spi_sck_bit clear (CPOL=0)
*/
pp->lastbyte |= vcc_bits;
parport_write_data(pp->port, pp->lastbyte);
@@ -334,23 +289,6 @@ static void butterfly_attach(struct parport *p)
pr_debug("%s: dataflash at %s\n", p->name,
pp->dataflash->dev.bus_id);
-#ifdef HAVE_USI
- /* Bus 2 is only for talking to the AVR, and it can work no
- * matter who masters bus 1; needs appropriate AVR firmware.
- */
- pp->info[1].max_speed_hz = 10 /* ?? */ * 1000 * 1000;
- strcpy(pp->info[1].modalias, "butterfly");
- // pp->info[1].platform_data = ... TBD ... ;
- pp->info[1].chip_select = 2,
- pp->info[1].controller_data = pp;
- pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[1]);
- if (pp->butterfly)
- pr_debug("%s: butterfly at %s\n", p->name,
- pp->butterfly->dev.bus_id);
-
- /* FIXME setup ACK for the IRQ line ... */
-#endif
-
// dev_info(_what?_, ...)
pr_info("%s: AVR Butterfly\n", p->name);
butterfly = pp;
@@ -366,14 +304,12 @@ clean1:
clean0:
(void) spi_master_put(pp->bitbang.master);
done:
- platform_device_unregister(pdev);
pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
}
static void butterfly_detach(struct parport *p)
{
struct butterfly *pp;
- struct platform_device *pdev;
int status;
/* FIXME this global is ugly ... but, how to quickly get from
@@ -386,7 +322,6 @@ static void butterfly_detach(struct parport *p)
butterfly = NULL;
/* stop() unregisters child devices too */
- pdev = to_platform_device(pp->bitbang.master->cdev.dev);
status = spi_bitbang_stop(&pp->bitbang);
/* turn off VCC */
@@ -397,8 +332,6 @@ static void butterfly_detach(struct parport *p)
parport_unregister_device(pp->pd);
(void) spi_master_put(pp->bitbang.master);
-
- platform_device_unregister(pdev);
}
static struct parport_driver butterfly_driver = {
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index b10211c420e..d5a710f6e44 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -342,8 +342,6 @@ static int s3c24xx_spi_probe(struct platform_device *pdev)
goto err_register;
}
- dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown);
-
/* register all the devices associated */
bi = &hw->pdata->board_info[0];
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
new file mode 100644
index 00000000000..c0a6dce800a
--- /dev/null
+++ b/drivers/spi/spidev.c
@@ -0,0 +1,584 @@
+/*
+ * spidev.c -- simple synchronous userspace interface to SPI devices
+ *
+ * Copyright (C) 2006 SWAPP
+ * Andrea Paterniani <a.paterniani@swapp-eng.it>
+ * Copyright (C) 2007 David Brownell (simplification, cleanup)
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spidev.h>
+
+#include <asm/uaccess.h>
+
+
+/*
+ * This supports acccess to SPI devices using normal userspace I/O calls.
+ * Note that while traditional UNIX/POSIX I/O semantics are half duplex,
+ * and often mask message boundaries, full SPI support requires full duplex
+ * transfers. There are several kinds of of internal message boundaries to
+ * handle chipselect management and other protocol options.
+ *
+ * SPI has a character major number assigned. We allocate minor numbers
+ * dynamically using a bitmask. You must use hotplug tools, such as udev
+ * (or mdev with busybox) to create and destroy the /dev/spidevB.C device
+ * nodes, since there is no fixed association of minor numbers with any
+ * particular SPI bus or device.
+ */
+#define SPIDEV_MAJOR 153 /* assigned */
+#define N_SPI_MINORS 32 /* ... up to 256 */
+
+static unsigned long minors[N_SPI_MINORS / BITS_PER_LONG];
+
+
+/* Bit masks for spi_device.mode management */
+#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL)
+
+
+struct spidev_data {
+ struct device dev;
+ struct spi_device *spi;
+ struct list_head device_entry;
+
+ struct mutex buf_lock;
+ unsigned users;
+ u8 *buffer;
+};
+
+static LIST_HEAD(device_list);
+static DEFINE_MUTEX(device_list_lock);
+
+static unsigned bufsiz = 4096;
+module_param(bufsiz, uint, S_IRUGO);
+MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");
+
+/*-------------------------------------------------------------------------*/
+
+/* Read-only message with current device setup */
+static ssize_t
+spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
+{
+ struct spidev_data *spidev;
+ struct spi_device *spi;
+ ssize_t status = 0;
+
+ /* chipselect only toggles at start or end of operation */
+ if (count > bufsiz)
+ return -EMSGSIZE;
+
+ spidev = filp->private_data;
+ spi = spidev->spi;
+
+ mutex_lock(&spidev->buf_lock);
+ status = spi_read(spi, spidev->buffer, count);
+ if (status == 0) {
+ unsigned long missing;
+
+ missing = copy_to_user(buf, spidev->buffer, count);
+ if (count && missing == count)
+ status = -EFAULT;
+ else
+ status = count - missing;
+ }
+ mutex_unlock(&spidev->buf_lock);
+
+ return status;
+}
+
+/* Write-only message with current device setup */
+static ssize_t
+spidev_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct spidev_data *spidev;
+ struct spi_device *spi;
+ ssize_t status = 0;
+ unsigned long missing;
+
+ /* chipselect only toggles at start or end of operation */
+ if (count > bufsiz)
+ return -EMSGSIZE;
+
+ spidev = filp->private_data;
+ spi = spidev->spi;
+
+ mutex_lock(&spidev->buf_lock);
+ missing = copy_from_user(spidev->buffer, buf, count);
+ if (missing == 0) {
+ status = spi_write(spi, spidev->buffer, count);
+ if (status == 0)
+ status = count;
+ } else
+ status = -EFAULT;
+ mutex_unlock(&spidev->buf_lock);
+
+ return status;
+}
+
+static int spidev_message(struct spidev_data *spidev,
+ struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
+{
+ struct spi_message msg;
+ struct spi_transfer *k_xfers;
+ struct spi_transfer *k_tmp;
+ struct spi_ioc_transfer *u_tmp;
+ struct spi_device *spi = spidev->spi;
+ unsigned n, total;
+ u8 *buf;
+ int status = -EFAULT;
+
+ spi_message_init(&msg);
+ k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
+ if (k_xfers == NULL)
+ return -ENOMEM;
+
+ /* Construct spi_message, copying any tx data to bounce buffer.
+ * We walk the array of user-provided transfers, using each one
+ * to initialize a kernel version of the same transfer.
+ */
+ mutex_lock(&spidev->buf_lock);
+ buf = spidev->buffer;
+ total = 0;
+ for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
+ n;
+ n--, k_tmp++, u_tmp++) {
+ k_tmp->len = u_tmp->len;
+
+ if (u_tmp->rx_buf) {
+ k_tmp->rx_buf = buf;
+ if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len))
+ goto done;
+ }
+ if (u_tmp->tx_buf) {
+ k_tmp->tx_buf = buf;
+ if (copy_from_user(buf, (const u8 __user *)u_tmp->tx_buf,
+ u_tmp->len))
+ goto done;
+ }
+
+ total += k_tmp->len;
+ if (total > bufsiz) {
+ status = -EMSGSIZE;
+ goto done;
+ }
+ buf += k_tmp->len;
+
+ k_tmp->cs_change = !!u_tmp->cs_change;
+ k_tmp->bits_per_word = u_tmp->bits_per_word;
+ k_tmp->delay_usecs = u_tmp->delay_usecs;
+ k_tmp->speed_hz = u_tmp->speed_hz;
+#ifdef VERBOSE
+ dev_dbg(&spi->dev,
+ " xfer len %zd %s%s%s%dbits %u usec %uHz\n",
+ u_tmp->len,
+ u_tmp->rx_buf ? "rx " : "",
+ u_tmp->tx_buf ? "tx " : "",
+ u_tmp->cs_change ? "cs " : "",
+ u_tmp->bits_per_word ? : spi->bits_per_word,
+ u_tmp->delay_usecs,
+ u_tmp->speed_hz ? : spi->max_speed_hz);
+#endif
+ spi_message_add_tail(k_tmp, &msg);
+ }
+
+ status = spi_sync(spi, &msg);
+ if (status < 0)
+ goto done;
+
+ /* copy any rx data out of bounce buffer */
+ buf = spidev->buffer;
+ for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
+ if (u_tmp->rx_buf) {
+ if (__copy_to_user((u8 __user *)u_tmp->rx_buf, buf,
+ u_tmp->len)) {
+ status = -EFAULT;
+ goto done;
+ }
+ }
+ buf += u_tmp->len;
+ }
+ status = total;
+
+done:
+ mutex_unlock(&spidev->buf_lock);
+ kfree(k_xfers);
+ return status;
+}
+
+static int
+spidev_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ int retval = 0;
+ struct spidev_data *spidev;
+ struct spi_device *spi;
+ u32 tmp;
+ unsigned n_ioc;
+ struct spi_ioc_transfer *ioc;
+
+ /* Check type and command number */
+ if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
+ return -ENOTTY;
+
+ /* Check access direction once here; don't repeat below.
+ * IOC_DIR is from the user perspective, while access_ok is
+ * from the kernel perspective; so they look reversed.
+ */
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ err = !access_ok(VERIFY_WRITE,
+ (void __user *)arg, _IOC_SIZE(cmd));
+ if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
+ err = !access_ok(VERIFY_READ,
+ (void __user *)arg, _IOC_SIZE(cmd));
+ if (err)
+ return -EFAULT;
+
+ spidev = filp->private_data;
+ spi = spidev->spi;
+
+ switch (cmd) {
+ /* read requests */
+ case SPI_IOC_RD_MODE:
+ retval = __put_user(spi->mode & SPI_MODE_MASK,
+ (__u8 __user *)arg);
+ break;
+ case SPI_IOC_RD_LSB_FIRST:
+ retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
+ (__u8 __user *)arg);
+ break;
+ case SPI_IOC_RD_BITS_PER_WORD:
+ retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
+ break;
+ case SPI_IOC_RD_MAX_SPEED_HZ:
+ retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
+ break;
+
+ /* write requests */
+ case SPI_IOC_WR_MODE:
+ retval = __get_user(tmp, (u8 __user *)arg);
+ if (retval == 0) {
+ u8 save = spi->mode;
+
+ if (tmp & ~SPI_MODE_MASK) {
+ retval = -EINVAL;
+ break;
+ }
+
+ tmp |= spi->mode & ~SPI_MODE_MASK;
+ spi->mode = (u8)tmp;
+ retval = spi_setup(spi);
+ if (retval < 0)
+ spi->mode = save;
+ else
+ dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
+ }
+ break;
+ case SPI_IOC_WR_LSB_FIRST:
+ retval = __get_user(tmp, (__u8 __user *)arg);
+ if (retval == 0) {
+ u8 save = spi->mode;
+
+ if (tmp)
+ spi->mode |= SPI_LSB_FIRST;
+ else
+ spi->mode &= ~SPI_LSB_FIRST;
+ retval = spi_setup(spi);
+ if (retval < 0)
+ spi->mode = save;
+ else
+ dev_dbg(&spi->dev, "%csb first\n",
+ tmp ? 'l' : 'm');
+ }
+ break;
+ case SPI_IOC_WR_BITS_PER_WORD:
+ retval = __get_user(tmp, (__u8 __user *)arg);
+ if (retval == 0) {
+ u8 save = spi->bits_per_word;
+
+ spi->bits_per_word = tmp;
+ retval = spi_setup(spi);
+ if (retval < 0)
+ spi->bits_per_word = save;
+ else
+ dev_dbg(&spi->dev, "%d bits per word\n", tmp);
+ }
+ break;
+ case SPI_IOC_WR_MAX_SPEED_HZ:
+ retval = __get_user(tmp, (__u32 __user *)arg);
+ if (retval == 0) {
+ u32 save = spi->max_speed_hz;
+
+ spi->max_speed_hz = tmp;
+ retval = spi_setup(spi);
+ if (retval < 0)
+ spi->max_speed_hz = save;
+ else
+ dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
+ }
+ break;
+
+ default:
+ /* segmented and/or full-duplex I/O request */
+ if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
+ || _IOC_DIR(cmd) != _IOC_WRITE)
+ return -ENOTTY;
+
+ tmp = _IOC_SIZE(cmd);
+ if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
+ retval = -EINVAL;
+ break;
+ }
+ n_ioc = tmp / sizeof(struct spi_ioc_transfer);
+ if (n_ioc == 0)
+ break;
+
+ /* copy into scratch area */
+ ioc = kmalloc(tmp, GFP_KERNEL);
+ if (!ioc) {
+ retval = -ENOMEM;
+ break;
+ }
+ if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
+ retval = -EFAULT;
+ break;
+ }
+
+ /* translate to spi_message, execute */
+ retval = spidev_message(spidev, ioc, n_ioc);
+ kfree(ioc);
+ break;
+ }
+ return retval;
+}
+
+static int spidev_open(struct inode *inode, struct file *filp)
+{
+ struct spidev_data *spidev;
+ int status = -ENXIO;
+
+ mutex_lock(&device_list_lock);
+
+ list_for_each_entry(spidev, &device_list, device_entry) {
+ if (spidev->dev.devt == inode->i_rdev) {
+ status = 0;
+ break;
+ }
+ }
+ if (status == 0) {
+ if (!spidev->buffer) {
+ spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
+ if (!spidev->buffer) {
+ dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
+ status = -ENOMEM;
+ }
+ }
+ if (status == 0) {
+ spidev->users++;
+ filp->private_data = spidev;
+ nonseekable_open(inode, filp);
+ }
+ } else
+ pr_debug("spidev: nothing for minor %d\n", iminor(inode));
+
+ mutex_unlock(&device_list_lock);
+ return status;
+}
+
+static int spidev_release(struct inode *inode, struct file *filp)
+{
+ struct spidev_data *spidev;
+ int status = 0;
+
+ mutex_lock(&device_list_lock);
+ spidev = filp->private_data;
+ filp->private_data = NULL;
+ spidev->users--;
+ if (!spidev->users) {
+ kfree(spidev->buffer);
+ spidev->buffer = NULL;
+ }
+ mutex_unlock(&device_list_lock);
+
+ return status;
+}
+
+static struct file_operations spidev_fops = {
+ .owner = THIS_MODULE,
+ /* REVISIT switch to aio primitives, so that userspace
+ * gets more complete API coverage. It'll simplify things
+ * too, except for the locking.
+ */
+ .write = spidev_write,
+ .read = spidev_read,
+ .ioctl = spidev_ioctl,
+ .open = spidev_open,
+ .release = spidev_release,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* The main reason to have this class is to make mdev/udev create the
+ * /dev/spidevB.C character device nodes exposing our userspace API.
+ * It also simplifies memory management.
+ */
+
+static void spidev_classdev_release(struct device *dev)
+{
+ struct spidev_data *spidev;
+
+ spidev = container_of(dev, struct spidev_data, dev);
+ kfree(spidev);
+}
+
+static struct class spidev_class = {
+ .name = "spidev",
+ .owner = THIS_MODULE,
+ .dev_release = spidev_classdev_release,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int spidev_probe(struct spi_device *spi)
+{
+ struct spidev_data *spidev;
+ int status;
+ unsigned long minor;
+
+ /* Allocate driver data */
+ spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
+ if (!spidev)
+ return -ENOMEM;
+
+ /* Initialize the driver data */
+ spidev->spi = spi;
+ mutex_init(&spidev->buf_lock);
+
+ INIT_LIST_HEAD(&spidev->device_entry);
+
+ /* If we can allocate a minor number, hook up this device.
+ * Reusing minors is fine so long as udev or mdev is working.
+ */
+ mutex_lock(&device_list_lock);
+ minor = find_first_zero_bit(minors, ARRAY_SIZE(minors));
+ if (minor < N_SPI_MINORS) {
+ spidev->dev.parent = &spi->dev;
+ spidev->dev.class = &spidev_class;
+ spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor);
+ snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id,
+ "spidev%d.%d",
+ spi->master->bus_num, spi->chip_select);
+ status = device_register(&spidev->dev);
+ } else {
+ dev_dbg(&spi->dev, "no minor number available!\n");
+ status = -ENODEV;
+ }
+ if (status == 0) {
+ set_bit(minor, minors);
+ dev_set_drvdata(&spi->dev, spidev);
+ list_add(&spidev->device_entry, &device_list);
+ }
+ mutex_unlock(&device_list_lock);
+
+ if (status != 0)
+ kfree(spidev);
+
+ return status;
+}
+
+static int spidev_remove(struct spi_device *spi)
+{
+ struct spidev_data *spidev = dev_get_drvdata(&spi->dev);
+
+ mutex_lock(&device_list_lock);
+
+ list_del(&spidev->device_entry);
+ dev_set_drvdata(&spi->dev, NULL);
+ clear_bit(MINOR(spidev->dev.devt), minors);
+ device_unregister(&spidev->dev);
+
+ mutex_unlock(&device_list_lock);
+
+ return 0;
+}
+
+static struct spi_driver spidev_spi = {
+ .driver = {
+ .name = "spidev",
+ .owner = THIS_MODULE,
+ },
+ .probe = spidev_probe,
+ .remove = __devexit_p(spidev_remove),
+
+ /* NOTE: suspend/resume methods are not necessary here.
+ * We don't do anything except pass the requests to/from
+ * the underlying controller. The refrigerator handles
+ * most issues; the controller driver handles the rest.
+ */
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init spidev_init(void)
+{
+ int status;
+
+ /* Claim our 256 reserved device numbers. Then register a class
+ * that will key udev/mdev to add/remove /dev nodes. Last, register
+ * the driver which manages those device numbers.
+ */
+ BUILD_BUG_ON(N_SPI_MINORS > 256);
+ status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
+ if (status < 0)
+ return status;
+
+ status = class_register(&spidev_class);
+ if (status < 0) {
+ unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+ return status;
+ }
+
+ status = spi_register_driver(&spidev_spi);
+ if (status < 0) {
+ class_unregister(&spidev_class);
+ unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+ }
+ return status;
+}
+module_init(spidev_init);
+
+static void __exit spidev_exit(void)
+{
+ spi_unregister_driver(&spidev_spi);
+ class_unregister(&spidev_class);
+ unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
+}
+module_exit(spidev_exit);
+
+MODULE_AUTHOR("Andrea Paterniani, <a.paterniani@swapp-eng.it>");
+MODULE_DESCRIPTION("User mode SPI device interface");
+MODULE_LICENSE("GPL");
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 71cb64e41a1..c7b0a357b04 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -7692,7 +7692,7 @@ static int __init ixj_probe_pci(int *cnt)
IXJ *j = NULL;
for (i = 0; i < IXJMAX - *cnt; i++) {
- pci = pci_find_device(PCI_VENDOR_ID_QUICKNET,
+ pci = pci_get_device(PCI_VENDOR_ID_QUICKNET,
PCI_DEVICE_ID_QUICKNET_XJ, pci);
if (!pci)
break;
@@ -7712,6 +7712,7 @@ static int __init ixj_probe_pci(int *cnt)
printk(KERN_INFO "ixj: found Internet PhoneJACK PCI at 0x%x\n", j->DSPbase);
++*cnt;
}
+ pci_dev_put(pci);
return probe;
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 9980a4ddfed..b847bbc8b0e 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -85,8 +85,6 @@ source "drivers/usb/class/Kconfig"
source "drivers/usb/storage/Kconfig"
-source "drivers/usb/input/Kconfig"
-
source "drivers/usb/image/Kconfig"
source "drivers/usb/net/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c1b0affae29..0ef090b1b37 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -23,18 +23,6 @@ obj-$(CONFIG_USB_PRINTER) += class/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-$(CONFIG_USB) += storage/
-obj-$(CONFIG_USB_ACECAD) += input/
-obj-$(CONFIG_USB_AIPTEK) += input/
-obj-$(CONFIG_USB_ATI_REMOTE) += input/
-obj-$(CONFIG_USB_HID) += input/
-obj-$(CONFIG_USB_KBD) += input/
-obj-$(CONFIG_USB_KBTAB) += input/
-obj-$(CONFIG_USB_MOUSE) += input/
-obj-$(CONFIG_USB_MTOUCH) += input/
-obj-$(CONFIG_USB_POWERMATE) += input/
-obj-$(CONFIG_USB_WACOM) += input/
-obj-$(CONFIG_USB_XPAD) += input/
-
obj-$(CONFIG_USB_CATC) += net/
obj-$(CONFIG_USB_KAWETH) += net/
obj-$(CONFIG_USB_PEGASUS) += net/
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index b3f779f5933..11e9b15ca45 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -77,7 +77,6 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/wait.h>
@@ -1034,7 +1033,7 @@ static int usbatm_do_heavy_init(void *arg)
static int usbatm_heavy_init(struct usbatm_data *instance)
{
- int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+ int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_FS | CLONE_FILES);
if (ret < 0) {
usb_err(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 14de3b1b6a2..0081c1d1268 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -59,7 +59,6 @@
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6584cf00f7f..15e740e3a5c 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -49,7 +49,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/init.h>
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index bde29ab2b50..f6b74a678de 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -16,7 +16,6 @@
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index cddfc62c461..cd4f1115728 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -36,7 +36,6 @@
#include <linux/usb.h>
#include <linux/namei.h>
#include <linux/usbdevice_fs.h>
-#include <linux/smp_lock.h>
#include <linux/parser.h>
#include <linux/notifier.h>
#include <asm/byteorder.h>
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index dfd1b5c87ca..18ddc5e67e3 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -31,7 +31,6 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 2a6e3163d94..ba163f35bf2 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/list.h>
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 7d7909cf255..fcb5526cb08 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -41,7 +41,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 1dd8b57f442..325bf7cfb83 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -28,7 +28,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 65c91d3735d..ae931af05ce 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -30,7 +30,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 49d737725f7..52779c52b56 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -54,7 +54,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 2c043a1ea15..84392e835d5 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -1483,7 +1483,7 @@ static void udc_disable(struct pxa2xx_udc *dev)
#ifdef CONFIG_ARCH_PXA
/* Disable clock for USB device */
- pxa_set_cken(CKEN11_USB, 0);
+ pxa_set_cken(CKEN_USB, 0);
#endif
ep0_idle (dev);
@@ -1529,7 +1529,7 @@ static void udc_enable (struct pxa2xx_udc *dev)
#ifdef CONFIG_ARCH_PXA
/* Enable clock for USB device */
- pxa_set_cken(CKEN11_USB, 1);
+ pxa_set_cken(CKEN_USB, 1);
udelay(5);
#endif
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index e552668d36b..f847c3414be 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -22,7 +22,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 8c85e33f74a..7078374d0b7 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -67,7 +67,6 @@
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c7458f7e56c..099aff64f53 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -24,7 +24,6 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 4d781a2a980..37b83ba0996 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -73,13 +73,6 @@ static const struct hc_driver ps3_ehci_hc_driver = {
#endif
};
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
- const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
-
static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
{
int result;
@@ -104,7 +97,7 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
__LINE__, dev->m_region->lpar_addr);
- result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+ result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
@@ -162,7 +155,7 @@ fail_add_hcd:
fail_ioremap:
usb_put_hcd(hcd);
fail_create_hcd:
- ps3_free_io_irq(virq);
+ ps3_io_irq_destroy(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
fail_mmio:
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index e8bbe8bc259..a66637e725f 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -26,7 +26,6 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 08e237c7bc4..c43b66acd4d 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -97,8 +97,8 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
return -ENODEV;
is_bigendian =
- device_is_compatible(dn, "ohci-bigendian") ||
- device_is_compatible(dn, "ohci-be");
+ of_device_is_compatible(dn, "ohci-bigendian") ||
+ of_device_is_compatible(dn, "ohci-be");
dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 62283a3926d..d7cf07288b0 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -75,14 +75,6 @@ static const struct hc_driver ps3_ohci_hc_driver = {
#endif
};
-/* redefine dev_dbg to do a syntax check */
-
-#if !defined(DEBUG)
-#undef dev_dbg
-static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
- const struct device *_dev, const char *fmt, ...) {return 0;}
-#endif
-
static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
{
int result;
@@ -107,7 +99,7 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
__LINE__, dev->m_region->lpar_addr);
- result = ps3_alloc_io_irq(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
+ result = ps3_io_irq_setup(PS3_BINDING_CPU_ANY, dev->interrupt_id, &virq);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
@@ -165,7 +157,7 @@ fail_add_hcd:
fail_ioremap:
usb_put_hcd(hcd);
fail_create_hcd:
- ps3_free_io_irq(virq);
+ ps3_io_irq_destroy(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
fail_mmio:
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index f1563dc319d..23d2fe5a62f 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -80,7 +80,7 @@ static int pxa27x_start_hc(struct device *dev)
inf = dev->platform_data;
- pxa_set_cken(CKEN10_USBHOST, 1);
+ pxa_set_cken(CKEN_USBHOST, 1);
UHCHR |= UHCHR_FHR;
udelay(11);
@@ -123,7 +123,7 @@ static void pxa27x_stop_hc(struct device *dev)
UHCCOMS |= 1;
udelay(10);
- pxa_set_cken(CKEN10_USBHOST, 0);
+ pxa_set_cken(CKEN_USBHOST, 0);
}
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 5fa5647ea09..4cfa3ff2c99 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -38,7 +38,6 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index a7fa0d75567..ff0dba01f1c 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -43,7 +43,6 @@
#include <linux/pci_ids.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index d308afd0693..36502a06f73 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -94,7 +94,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include <linux/mutex.h>
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 896cb2b7102..51bd80d2b8c 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -128,7 +128,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/proc_fs.h>
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
deleted file mode 100644
index 69a9f3b6d0a..00000000000
--- a/drivers/usb/input/Kconfig
+++ /dev/null
@@ -1,370 +0,0 @@
-#
-# USB Input driver configuration
-#
-comment "USB Input Devices"
- depends on USB
-
-config USB_HID
- tristate "USB Human Interface Device (full HID) support"
- default y
- depends on USB && INPUT
- select HID
- ---help---
- Say Y here if you want full HID support to connect USB keyboards,
- mice, joysticks, graphic tablets, or any other HID based devices
- to your computer via USB, as well as Uninterruptible Power Supply
- (UPS) and monitor control devices.
-
- You can't use this driver and the HIDBP (Boot Protocol) keyboard
- and mouse drivers at the same time. More information is available:
- <file:Documentation/input/input.txt>.
-
- If unsure, say Y.
-
- To compile this driver as a module, choose M here: the
- module will be called usbhid.
-
-comment "Input core support is needed for USB HID input layer or HIDBP support"
- depends on USB_HID && INPUT=n
-
-config USB_HIDINPUT_POWERBOOK
- bool "Enable support for iBook/PowerBook special keys"
- default n
- depends on USB_HID
- help
- Say Y here if you want support for the special keys (Fn, Numlock) on
- Apple iBooks and PowerBooks.
-
- If unsure, say N.
-
-config HID_FF
- bool "Force feedback support (EXPERIMENTAL)"
- depends on USB_HID && EXPERIMENTAL
- help
- Say Y here is you want force feedback support for a few HID devices.
- See below for a list of supported devices.
-
- See <file:Documentation/input/ff.txt> for a description of the force
- feedback API.
-
- If unsure, say N.
-
-config HID_PID
- bool "PID device support"
- depends on HID_FF
- help
- Say Y here if you have a PID-compliant device and wish to enable force
- feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
- devices.
-
-config LOGITECH_FF
- bool "Logitech devices support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have one of these devices:
- - Logitech WingMan Cordless RumblePad
- - Logitech WingMan Cordless RumblePad 2
- - Logitech WingMan Force 3D
- - Logitech Formula Force EX
- - Logitech MOMO Force wheel
-
- and if you want to enable force feedback for them.
- Note: if you say N here, this device will still be supported, but without
- force feedback.
-
-config PANTHERLORD_FF
- bool "PantherLord USB/PS2 2in1 Adapter support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
- to enable force feedback support for it.
-
-config THRUSTMASTER_FF
- bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
- depends on HID_FF && EXPERIMENTAL
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
- and want to enable force feedback support for it.
- Note: if you say N here, this device will still be supported, but without
- force feedback.
-
-config ZEROPLUS_FF
- bool "Zeroplus based game controller support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have a Zeroplus based game controller and want to
- enable force feedback for it.
-
-config USB_HIDDEV
- bool "/dev/hiddev raw HID device support"
- depends on USB_HID
- help
- Say Y here if you want to support HID devices (from the USB
- specification standpoint) that aren't strictly user interface
- devices, like monitor controls and Uninterruptable Power Supplies.
-
- This module supports these devices separately using a separate
- event interface on /dev/usb/hiddevX (char 180:96 to 180:111).
-
- If unsure, say Y.
-
-menu "USB HID Boot Protocol drivers"
- depends on USB!=n && USB_HID!=y
-
-config USB_KBD
- tristate "USB HIDBP Keyboard (simple Boot) support"
- depends on USB && INPUT
- ---help---
- Say Y here only if you are absolutely sure that you don't want
- to use the generic HID driver for your USB keyboard and prefer
- to use the keyboard in its limited Boot Protocol mode instead.
-
- This is almost certainly not what you want. This is mostly
- useful for embedded applications or simple keyboards.
-
- To compile this driver as a module, choose M here: the
- module will be called usbkbd.
-
- If even remotely unsure, say N.
-
-config USB_MOUSE
- tristate "USB HIDBP Mouse (simple Boot) support"
- depends on USB && INPUT
- ---help---
- Say Y here only if you are absolutely sure that you don't want
- to use the generic HID driver for your USB mouse and prefer
- to use the mouse in its limited Boot Protocol mode instead.
-
- This is almost certainly not what you want. This is mostly
- useful for embedded applications or simple mice.
-
- To compile this driver as a module, choose M here: the
- module will be called usbmouse.
-
- If even remotely unsure, say N.
-
-endmenu
-
-config USB_AIPTEK
- tristate "Aiptek 6000U/8000U tablet support"
- depends on USB && INPUT
- help
- Say Y here if you want to use the USB version of the Aiptek 6000U
- or Aiptek 8000U tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
-
- To compile this driver as a module, choose M here: the
- module will be called aiptek.
-
-config USB_WACOM
- tristate "Wacom Intuos/Graphire tablet support"
- depends on USB && INPUT
- help
- Say Y here if you want to use the USB version of the Wacom Intuos
- or Graphire tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
-
- To compile this driver as a module, choose M here: the
- module will be called wacom.
-
-config USB_ACECAD
- tristate "Acecad Flair tablet support"
- depends on USB && INPUT
- help
- Say Y here if you want to use the USB version of the Acecad Flair
- tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
-
- To compile this driver as a module, choose M here: the
- module will be called acecad.
-
-config USB_KBTAB
- tristate "KB Gear JamStudio tablet support"
- depends on USB && INPUT
- help
- Say Y here if you want to use the USB version of the KB Gear
- JamStudio tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
-
- To compile this driver as a module, choose M here: the
- module will be called kbtab.
-
-config USB_POWERMATE
- tristate "Griffin PowerMate and Contour Jog support"
- depends on USB && INPUT
- ---help---
- Say Y here if you want to use Griffin PowerMate or Contour Jog devices.
- These are aluminum dials which can measure clockwise and anticlockwise
- rotation. The dial also acts as a pushbutton. The base contains an LED
- which can be instructed to pulse or to switch to a particular intensity.
-
- You can download userspace tools from
- <http://sowerbutts.com/powermate/>.
-
- To compile this driver as a module, choose M here: the
- module will be called powermate.
-
-config USB_TOUCHSCREEN
- tristate "USB Touchscreen Driver"
- depends on USB && INPUT
- ---help---
- USB Touchscreen driver for:
- - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
- - PanJit TouchSet USB
- - 3M MicroTouch USB (EX II series)
- - ITM
- - some other eTurboTouch
- - Gunze AHL61
- - DMC TSC-10/25
-
- Have a look at <http://linux.chapter7.ch/touchkit/> for
- a usage description and the required user-space stuff.
-
- To compile this driver as a module, choose M here: the
- module will be called usbtouchscreen.
-
-config USB_TOUCHSCREEN_EGALAX
- default y
- bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_PANJIT
- default y
- bool "PanJit device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_3M
- default y
- bool "3M/Microtouch EX II series device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_ITM
- default y
- bool "ITM device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_ETURBO
- default y
- bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_GUNZE
- default y
- bool "Gunze AHL61 device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_TOUCHSCREEN_DMC_TSC10
- default y
- bool "DMC TSC-10/25 device support" if EMBEDDED
- depends on USB_TOUCHSCREEN
-
-config USB_YEALINK
- tristate "Yealink usb-p1k voip phone"
- depends on USB && INPUT && EXPERIMENTAL
- ---help---
- Say Y here if you want to enable keyboard and LCD functions of the
- Yealink usb-p1k usb phones. The audio part is enabled by the generic
- usb sound driver, so you might want to enable that as well.
-
- For information about how to use these additional functions, see
- <file:Documentation/input/yealink.txt>.
-
- To compile this driver as a module, choose M here: the module will be
- called yealink.
-
-config USB_XPAD
- tristate "X-Box gamepad support"
- depends on USB && INPUT
- ---help---
- Say Y here if you want to use the X-Box pad with your computer.
- Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV)
- and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well.
-
- For information about how to connect the X-Box pad to USB, see
- <file:Documentation/input/xpad.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called xpad.
-
-config USB_ATI_REMOTE
- tristate "ATI / X10 USB RF remote control"
- depends on USB && INPUT
- ---help---
- Say Y here if you want to use an ATI or X10 "Lola" USB remote control.
- These are RF remotes with USB receivers.
- The ATI remote comes with many of ATI's All-In-Wonder video cards.
- The X10 "Lola" remote is available at:
- <http://www.x10.com/products/lola_sg1.htm>
- This driver provides mouse pointer, left and right mouse buttons,
- and maps all the other remote buttons to keypress events.
-
- To compile this driver as a module, choose M here: the module will be
- called ati_remote.
-
-config USB_ATI_REMOTE2
- tristate "ATI / Philips USB RF remote control"
- depends on USB && INPUT
- ---help---
- Say Y here if you want to use an ATI or Philips USB RF remote control.
- These are RF remotes with USB receivers.
- ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
- and is also available as a separate product.
- This driver provides mouse pointer, left and right mouse buttons,
- and maps all the other remote buttons to keypress events.
-
- To compile this driver as a module, choose M here: the module will be
- called ati_remote2.
-
-config USB_KEYSPAN_REMOTE
- tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
- depends on USB && INPUT && EXPERIMENTAL
- ---help---
- Say Y here if you want to use a Keyspan DMR USB remote control.
- Currently only the UIA-11 type of receiver has been tested. The tag
- on the receiver that connects to the USB port should have a P/N that
- will tell you what type of DMR you have. The UIA-10 type is not
- supported at this time. This driver maps all buttons to keypress
- events.
-
- To compile this driver as a module, choose M here: the module will
- be called keyspan_remote.
-
-config USB_APPLETOUCH
- tristate "Apple USB Touchpad support"
- depends on USB && INPUT
- ---help---
- Say Y here if you want to use an Apple USB Touchpad.
-
- These are the touchpads that can be found on post-February 2005
- Apple Powerbooks (prior models have a Synaptics touchpad connected
- to the ADB bus).
-
- This driver provides a basic mouse driver but can be interfaced
- with the synaptics X11 driver to provide acceleration and
- scrolling in X11.
-
- For further information, see
- <file:Documentation/input/appletouch.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called appletouch.
-
-config USB_GTCO
- tristate "GTCO CalComp/InterWrite USB Support"
- depends on USB && INPUT
- ---help---
- Say Y here if you want to use the USB version of the GTCO
- CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
- (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
- (CONFIG_INPUT_EVDEV) as well.
-
- To compile this driver as a module, choose M here: the
- module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
deleted file mode 100644
index a9d206c945e..00000000000
--- a/drivers/usb/input/Makefile
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Makefile for the USB input drivers
-#
-
-# Multipart objects.
-wacom-objs := wacom_wac.o wacom_sys.o
-usbhid-objs := hid-core.o
-
-# Optional parts of multipart objects.
-
-ifeq ($(CONFIG_USB_HIDDEV),y)
- usbhid-objs += hiddev.o
-endif
-ifeq ($(CONFIG_HID_PID),y)
- usbhid-objs += hid-pidff.o
-endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
- usbhid-objs += hid-lgff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
- usbhid-objs += hid-plff.o
-endif
-ifeq ($(CONFIG_THRUSTMASTER_FF),y)
- usbhid-objs += hid-tmff.o
-endif
-ifeq ($(CONFIG_ZEROPLUS_FF),y)
- usbhid-objs += hid-zpff.o
-endif
-ifeq ($(CONFIG_HID_FF),y)
- usbhid-objs += hid-ff.o
-endif
-
-obj-$(CONFIG_USB_AIPTEK) += aiptek.o
-obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o
-obj-$(CONFIG_USB_ATI_REMOTE2) += ati_remote2.o
-obj-$(CONFIG_USB_HID) += usbhid.o
-obj-$(CONFIG_USB_KBD) += usbkbd.o
-obj-$(CONFIG_USB_KBTAB) += kbtab.o
-obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o
-obj-$(CONFIG_USB_MOUSE) += usbmouse.o
-obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o
-obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o
-obj-$(CONFIG_USB_EGALAX) += touchkitusb.o
-obj-$(CONFIG_USB_TOUCHSCREEN) += usbtouchscreen.o
-obj-$(CONFIG_USB_POWERMATE) += powermate.o
-obj-$(CONFIG_USB_WACOM) += wacom.o
-obj-$(CONFIG_USB_ACECAD) += acecad.o
-obj-$(CONFIG_USB_YEALINK) += yealink.o
-obj-$(CONFIG_USB_XPAD) += xpad.o
-obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
-obj-$(CONFIG_USB_GTCO) += gtco.o
-
-ifeq ($(CONFIG_USB_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
deleted file mode 100644
index aac968aab86..00000000000
--- a/drivers/usb/input/itmtouch.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/******************************************************************************
- * itmtouch.c -- Driver for ITM touchscreen panel
- *
- * 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.
- *
- * Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>.
- *
- * Kudos to ITM for providing me with the datasheet for the panel,
- * even though it was a day later than I had finished writing this
- * driver.
- *
- * It has meant that I've been able to correct my interpretation of the
- * protocol packets however.
- *
- * CC -- 2003/9/29
- *
- * History
- * 1.0 & 1.1 2003 (CC) vojtech@suse.cz
- * Original version for 2.4.x kernels
- *
- * 1.2 02/03/2005 (HCE) hc@mivu.no
- * Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints.
- * Unfortunately no calibration support at this time.
- *
- * 1.2.1 09/03/2005 (HCE) hc@mivu.no
- * Code cleanup and adjusting syntax to start matching kernel standards
- *
- * 1.2.2 10/05/2006 (MJA) massad@gmail.com
- * Flag for detecting if the screen was being touch was incorrectly
- * inverted, so no touch events were being detected.
- *
- *****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-/* only an 8 byte buffer necessary for a single packet */
-#define ITM_BUFSIZE 8
-#define PATH_SIZE 64
-
-#define USB_VENDOR_ID_ITMINC 0x0403
-#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9
-
-#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
-#define DRIVER_VERSION "v1.2.2"
-#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE( DRIVER_LICENSE );
-
-struct itmtouch_dev {
- struct usb_device *usbdev; /* usb device */
- struct input_dev *inputdev; /* input device */
- struct urb *readurb; /* urb */
- char rbuf[ITM_BUFSIZE]; /* data */
- int users;
- char name[128];
- char phys[64];
-};
-
-static struct usb_device_id itmtouch_ids [] = {
- { USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) },
- { }
-};
-
-static void itmtouch_irq(struct urb *urb)
-{
- struct itmtouch_dev *itmtouch = urb->context;
- unsigned char *data = urb->transfer_buffer;
- struct input_dev *dev = itmtouch->inputdev;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ETIME:
- /* this urb is timing out */
- dbg("%s - urb timed out - was the device unplugged?",
- __FUNCTION__);
- return;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
- goto exit;
- }
-
- /* if pressure has been released, then don't report X/Y */
- if (!(data[7] & 0x20)) {
- input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
- input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
- }
-
- input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F));
- input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20);
- input_sync(dev);
-
-exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- printk(KERN_ERR "%s - usb_submit_urb failed with result: %d",
- __FUNCTION__, retval);
-}
-
-static int itmtouch_open(struct input_dev *input)
-{
- struct itmtouch_dev *itmtouch = input->private;
-
- itmtouch->readurb->dev = itmtouch->usbdev;
-
- if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL))
- return -EIO;
-
- return 0;
-}
-
-static void itmtouch_close(struct input_dev *input)
-{
- struct itmtouch_dev *itmtouch = input->private;
-
- usb_kill_urb(itmtouch->readurb);
-}
-
-static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct itmtouch_dev *itmtouch;
- struct input_dev *input_dev;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev = interface_to_usbdev(intf);
- unsigned int pipe;
- unsigned int maxp;
-
- interface = intf->cur_altsetting;
- endpoint = &interface->endpoint[0].desc;
-
- itmtouch = kzalloc(sizeof(struct itmtouch_dev), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!itmtouch || !input_dev) {
- err("%s - Out of memory.", __FUNCTION__);
- goto fail;
- }
-
- itmtouch->usbdev = udev;
- itmtouch->inputdev = input_dev;
-
- if (udev->manufacturer)
- strlcpy(itmtouch->name, udev->manufacturer, sizeof(itmtouch->name));
-
- if (udev->product) {
- if (udev->manufacturer)
- strlcat(itmtouch->name, " ", sizeof(itmtouch->name));
- strlcat(itmtouch->name, udev->product, sizeof(itmtouch->name));
- }
-
- if (!strlen(itmtouch->name))
- sprintf(itmtouch->name, "USB ITM touchscreen");
-
- usb_make_path(udev, itmtouch->phys, sizeof(itmtouch->phys));
- strlcpy(itmtouch->phys, "/input0", sizeof(itmtouch->phys));
-
- input_dev->name = itmtouch->name;
- input_dev->phys = itmtouch->phys;
- usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = itmtouch;
-
- input_dev->open = itmtouch_open;
- input_dev->close = itmtouch_close;
-
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-
- /* device limits */
- /* as specified by the ITM datasheet, X and Y are 12bit,
- * Z (pressure) is 8 bit. However, the fields are defined up
- * to 14 bits for future possible expansion.
- */
- input_set_abs_params(input_dev, ABS_X, 0, 0x0FFF, 2, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, 0x0FFF, 2, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFF, 2, 0);
-
- /* initialise the URB so we can read from the transport stream */
- pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress);
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
-
- if (maxp > ITM_BUFSIZE)
- maxp = ITM_BUFSIZE;
-
- itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!itmtouch->readurb) {
- dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__);
- goto fail;
- }
-
- usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf,
- maxp, itmtouch_irq, itmtouch, endpoint->bInterval);
-
- input_register_device(itmtouch->inputdev);
-
- usb_set_intfdata(intf, itmtouch);
-
- return 0;
-
- fail: input_free_device(input_dev);
- kfree(itmtouch);
- return -ENOMEM;
-}
-
-static void itmtouch_disconnect(struct usb_interface *intf)
-{
- struct itmtouch_dev *itmtouch = usb_get_intfdata(intf);
-
- usb_set_intfdata(intf, NULL);
-
- if (itmtouch) {
- input_unregister_device(itmtouch->inputdev);
- usb_kill_urb(itmtouch->readurb);
- usb_free_urb(itmtouch->readurb);
- kfree(itmtouch);
- }
-}
-
-MODULE_DEVICE_TABLE(usb, itmtouch_ids);
-
-static struct usb_driver itmtouch_driver = {
- .name = "itmtouch",
- .probe = itmtouch_probe,
- .disconnect = itmtouch_disconnect,
- .id_table = itmtouch_ids,
-};
-
-static int __init itmtouch_init(void)
-{
- info(DRIVER_DESC " " DRIVER_VERSION);
- info(DRIVER_AUTHOR);
- return usb_register(&itmtouch_driver);
-}
-
-static void __exit itmtouch_exit(void)
-{
- usb_deregister(&itmtouch_driver);
-}
-
-module_init(itmtouch_init);
-module_exit(itmtouch_exit);
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
deleted file mode 100644
index 92c4e07da4c..00000000000
--- a/drivers/usb/input/mtouchusb.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/******************************************************************************
- * mtouchusb.c -- Driver for Microtouch (Now 3M) USB Touchscreens
- *
- * 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.
- *
- * Based upon original work by Radoslaw Garbacz (usb-support@ite.pl)
- * (http://freshmeat.net/projects/3mtouchscreendriver)
- *
- * History
- *
- * 0.3 & 0.4 2002 (TEJ) tejohnson@yahoo.com
- * Updated to 2.4.18, then 2.4.19
- * Old version still relied on stealing a minor
- *
- * 0.5 02/26/2004 (TEJ) tejohnson@yahoo.com
- * Complete rewrite using Linux Input in 2.6.3
- * Unfortunately no calibration support at this time
- *
- * 1.4 04/25/2004 (TEJ) tejohnson@yahoo.com
- * Changed reset from standard USB dev reset to vendor reset
- * Changed data sent to host from compensated to raw coordinates
- * Eliminated vendor/product module params
- * Performed multiple successful tests with an EXII-5010UC
- *
- * 1.5 02/27/2005 ddstreet@ieee.org
- * Added module parameter to select raw or hw-calibrated coordinate reporting
- *
- *****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-#define MTOUCHUSB_MIN_XC 0x0
-#define MTOUCHUSB_MAX_RAW_XC 0x4000
-#define MTOUCHUSB_MAX_CALIB_XC 0xffff
-#define MTOUCHUSB_XC_FUZZ 0x0
-#define MTOUCHUSB_XC_FLAT 0x0
-#define MTOUCHUSB_MIN_YC 0x0
-#define MTOUCHUSB_MAX_RAW_YC 0x4000
-#define MTOUCHUSB_MAX_CALIB_YC 0xffff
-#define MTOUCHUSB_YC_FUZZ 0x0
-#define MTOUCHUSB_YC_FLAT 0x0
-
-#define MTOUCHUSB_ASYNC_REPORT 1
-#define MTOUCHUSB_RESET 7
-#define MTOUCHUSB_REPORT_DATA_SIZE 11
-#define MTOUCHUSB_REQ_CTRLLR_ID 10
-
-#define MTOUCHUSB_GET_RAW_XC(data) (data[8]<<8 | data[7])
-#define MTOUCHUSB_GET_CALIB_XC(data) (data[4]<<8 | data[3])
-#define MTOUCHUSB_GET_RAW_YC(data) (data[10]<<8 | data[9])
-#define MTOUCHUSB_GET_CALIB_YC(data) (data[6]<<8 | data[5])
-#define MTOUCHUSB_GET_XC(data) (raw_coordinates ? \
- MTOUCHUSB_GET_RAW_XC(data) : \
- MTOUCHUSB_GET_CALIB_XC(data))
-#define MTOUCHUSB_GET_YC(data) (raw_coordinates ? \
- MTOUCHUSB_GET_RAW_YC(data) : \
- MTOUCHUSB_GET_CALIB_YC(data))
-#define MTOUCHUSB_GET_TOUCHED(data) ((data[2] & 0x40) ? 1:0)
-
-#define DRIVER_VERSION "v1.5"
-#define DRIVER_AUTHOR "Todd E. Johnson, tejohnson@yahoo.com"
-#define DRIVER_DESC "3M USB Touchscreen Driver"
-#define DRIVER_LICENSE "GPL"
-
-static int raw_coordinates = 1;
-
-module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
-
-struct mtouch_usb {
- unsigned char *data;
- dma_addr_t data_dma;
- struct urb *irq;
- struct usb_device *udev;
- struct input_dev *input;
- char name[128];
- char phys[64];
-};
-
-static struct usb_device_id mtouchusb_devices[] = {
- { USB_DEVICE(0x0596, 0x0001) },
- { }
-};
-
-static void mtouchusb_irq(struct urb *urb)
-{
- struct mtouch_usb *mtouch = urb->context;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ETIME:
- /* this urb is timing out */
- dbg("%s - urb timed out - was the device unplugged?",
- __FUNCTION__);
- return;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
- goto exit;
- }
-
- input_report_key(mtouch->input, BTN_TOUCH,
- MTOUCHUSB_GET_TOUCHED(mtouch->data));
- input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
- input_report_abs(mtouch->input, ABS_Y,
- (raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
- - MTOUCHUSB_GET_YC(mtouch->data));
- input_sync(mtouch->input);
-
-exit:
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- err("%s - usb_submit_urb failed with result: %d",
- __FUNCTION__, retval);
-}
-
-static int mtouchusb_open(struct input_dev *input)
-{
- struct mtouch_usb *mtouch = input->private;
-
- mtouch->irq->dev = mtouch->udev;
-
- if (usb_submit_urb(mtouch->irq, GFP_ATOMIC))
- return -EIO;
-
- return 0;
-}
-
-static void mtouchusb_close(struct input_dev *input)
-{
- struct mtouch_usb *mtouch = input->private;
-
- usb_kill_urb(mtouch->irq);
-}
-
-static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
-{
- dbg("%s - called", __FUNCTION__);
-
- mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
- GFP_ATOMIC, &mtouch->data_dma);
-
- if (!mtouch->data)
- return -1;
-
- return 0;
-}
-
-static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
-{
- dbg("%s - called", __FUNCTION__);
-
- if (mtouch->data)
- usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
- mtouch->data, mtouch->data_dma);
-}
-
-static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct mtouch_usb *mtouch;
- struct input_dev *input_dev;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev = interface_to_usbdev(intf);
- int nRet;
-
- dbg("%s - called", __FUNCTION__);
-
- dbg("%s - setting interface", __FUNCTION__);
- interface = intf->cur_altsetting;
-
- dbg("%s - setting endpoint", __FUNCTION__);
- endpoint = &interface->endpoint[0].desc;
-
- mtouch = kzalloc(sizeof(struct mtouch_usb), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!mtouch || !input_dev) {
- err("%s - Out of memory.", __FUNCTION__);
- goto fail1;
- }
-
- dbg("%s - allocating buffers", __FUNCTION__);
- if (mtouchusb_alloc_buffers(udev, mtouch))
- goto fail2;
-
- mtouch->udev = udev;
- mtouch->input = input_dev;
-
- if (udev->manufacturer)
- strlcpy(mtouch->name, udev->manufacturer, sizeof(mtouch->name));
-
- if (udev->product) {
- if (udev->manufacturer)
- strlcat(mtouch->name, " ", sizeof(mtouch->name));
- strlcat(mtouch->name, udev->product, sizeof(mtouch->name));
- }
-
- if (!strlen(mtouch->name))
- snprintf(mtouch->name, sizeof(mtouch->name),
- "USB Touchscreen %04x:%04x",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- usb_make_path(udev, mtouch->phys, sizeof(mtouch->phys));
- strlcpy(mtouch->phys, "/input0", sizeof(mtouch->phys));
-
- input_dev->name = mtouch->name;
- input_dev->phys = mtouch->phys;
- usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = mtouch;
-
- input_dev->open = mtouchusb_open;
- input_dev->close = mtouchusb_close;
-
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, MTOUCHUSB_MIN_XC,
- raw_coordinates ? MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC,
- MTOUCHUSB_XC_FUZZ, MTOUCHUSB_XC_FLAT);
- input_set_abs_params(input_dev, ABS_Y, MTOUCHUSB_MIN_YC,
- raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC,
- MTOUCHUSB_YC_FUZZ, MTOUCHUSB_YC_FLAT);
-
- nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
- MTOUCHUSB_RESET,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
- __FUNCTION__, nRet);
-
- dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
- mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!mtouch->irq) {
- dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
- goto fail2;
- }
-
- dbg("%s - usb_fill_int_urb", __FUNCTION__);
- usb_fill_int_urb(mtouch->irq, mtouch->udev,
- usb_rcvintpipe(mtouch->udev, 0x81),
- mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE,
- mtouchusb_irq, mtouch, endpoint->bInterval);
-
- dbg("%s - input_register_device", __FUNCTION__);
- input_register_device(mtouch->input);
-
- nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
- MTOUCHUSB_ASYNC_REPORT,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
- __FUNCTION__, nRet);
-
- usb_set_intfdata(intf, mtouch);
- return 0;
-
-fail2: mtouchusb_free_buffers(udev, mtouch);
-fail1: input_free_device(input_dev);
- kfree(mtouch);
- return -ENOMEM;
-}
-
-static void mtouchusb_disconnect(struct usb_interface *intf)
-{
- struct mtouch_usb *mtouch = usb_get_intfdata(intf);
-
- dbg("%s - called", __FUNCTION__);
- usb_set_intfdata(intf, NULL);
- if (mtouch) {
- dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
- usb_kill_urb(mtouch->irq);
- input_unregister_device(mtouch->input);
- usb_free_urb(mtouch->irq);
- mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
- kfree(mtouch);
- }
-}
-
-MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
-
-static struct usb_driver mtouchusb_driver = {
- .name = "mtouchusb",
- .probe = mtouchusb_probe,
- .disconnect = mtouchusb_disconnect,
- .id_table = mtouchusb_devices,
-};
-
-static int __init mtouchusb_init(void)
-{
- dbg("%s - called", __FUNCTION__);
- return usb_register(&mtouchusb_driver);
-}
-
-static void __exit mtouchusb_cleanup(void)
-{
- dbg("%s - called", __FUNCTION__);
- usb_deregister(&mtouchusb_driver);
-}
-
-module_init(mtouchusb_init);
-module_exit(mtouchusb_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
deleted file mode 100644
index 2a314b06592..00000000000
--- a/drivers/usb/input/touchkitusb.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/******************************************************************************
- * touchkitusb.c -- Driver for eGalax TouchKit USB Touchscreens
- *
- * Copyright (C) 2004-2005 by Daniel Ritz <daniel.ritz@gmx.ch>
- * Copyright (C) by Todd E. Johnson (mtouchusb.c)
- *
- * 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.
- *
- * Based upon mtouchusb.c
- *
- *****************************************************************************/
-
-//#define DEBUG
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-
-#define TOUCHKIT_MIN_XC 0x0
-#define TOUCHKIT_MAX_XC 0x07ff
-#define TOUCHKIT_XC_FUZZ 0x0
-#define TOUCHKIT_XC_FLAT 0x0
-#define TOUCHKIT_MIN_YC 0x0
-#define TOUCHKIT_MAX_YC 0x07ff
-#define TOUCHKIT_YC_FUZZ 0x0
-#define TOUCHKIT_YC_FLAT 0x0
-#define TOUCHKIT_REPORT_DATA_SIZE 16
-
-#define TOUCHKIT_DOWN 0x01
-
-#define TOUCHKIT_PKT_TYPE_MASK 0xFE
-#define TOUCHKIT_PKT_TYPE_REPT 0x80
-#define TOUCHKIT_PKT_TYPE_DIAG 0x0A
-
-#define DRIVER_VERSION "v0.1"
-#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>"
-#define DRIVER_DESC "eGalax TouchKit USB HID Touchscreen Driver"
-
-static int swap_xy;
-module_param(swap_xy, bool, 0644);
-MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
-
-struct touchkit_usb {
- unsigned char *data;
- dma_addr_t data_dma;
- char buffer[TOUCHKIT_REPORT_DATA_SIZE];
- int buf_len;
- struct urb *irq;
- struct usb_device *udev;
- struct input_dev *input;
- char name[128];
- char phys[64];
-};
-
-static struct usb_device_id touchkit_devices[] = {
- {USB_DEVICE(0x3823, 0x0001)},
- {USB_DEVICE(0x0123, 0x0001)},
- {USB_DEVICE(0x0eef, 0x0001)},
- {USB_DEVICE(0x0eef, 0x0002)},
- {}
-};
-
-/* helpers to read the data */
-static inline int touchkit_get_touched(char *data)
-{
- return (data[0] & TOUCHKIT_DOWN) ? 1 : 0;
-}
-
-static inline int touchkit_get_x(char *data)
-{
- return ((data[3] & 0x0F) << 7) | (data[4] & 0x7F);
-}
-
-static inline int touchkit_get_y(char *data)
-{
- return ((data[1] & 0x0F) << 7) | (data[2] & 0x7F);
-}
-
-
-/* processes one input packet. */
-static void touchkit_process_pkt(struct touchkit_usb *touchkit, char *pkt)
-{
- int x, y;
-
- /* only process report packets */
- if ((pkt[0] & TOUCHKIT_PKT_TYPE_MASK) != TOUCHKIT_PKT_TYPE_REPT)
- return;
-
- if (swap_xy) {
- y = touchkit_get_x(pkt);
- x = touchkit_get_y(pkt);
- } else {
- x = touchkit_get_x(pkt);
- y = touchkit_get_y(pkt);
- }
-
- input_report_key(touchkit->input, BTN_TOUCH, touchkit_get_touched(pkt));
- input_report_abs(touchkit->input, ABS_X, x);
- input_report_abs(touchkit->input, ABS_Y, y);
- input_sync(touchkit->input);
-}
-
-
-static int touchkit_get_pkt_len(char *buf)
-{
- switch (buf[0] & TOUCHKIT_PKT_TYPE_MASK) {
- case TOUCHKIT_PKT_TYPE_REPT:
- return 5;
-
- case TOUCHKIT_PKT_TYPE_DIAG:
- return buf[1] + 2;
- }
-
- return 0;
-}
-
-static void touchkit_process(struct touchkit_usb *touchkit, int len)
-{
- char *buffer;
- int pkt_len, buf_len, pos;
-
- /* if the buffer contains data, append */
- if (unlikely(touchkit->buf_len)) {
- int tmp;
-
- /* if only 1 byte in buffer, add another one to get length */
- if (touchkit->buf_len == 1)
- touchkit->buffer[1] = touchkit->data[0];
-
- pkt_len = touchkit_get_pkt_len(touchkit->buffer);
-
- /* unknown packet: drop everything */
- if (!pkt_len)
- return;
-
- /* append, process */
- tmp = pkt_len - touchkit->buf_len;
- memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp);
- touchkit_process_pkt(touchkit, touchkit->buffer);
-
- buffer = touchkit->data + tmp;
- buf_len = len - tmp;
- } else {
- buffer = touchkit->data;
- buf_len = len;
- }
-
- /* only one byte left in buffer */
- if (unlikely(buf_len == 1)) {
- touchkit->buffer[0] = buffer[0];
- touchkit->buf_len = 1;
- return;
- }
-
- /* loop over the buffer */
- pos = 0;
- while (pos < buf_len) {
- /* get packet len */
- pkt_len = touchkit_get_pkt_len(buffer + pos);
-
- /* unknown packet: drop everything */
- if (unlikely(!pkt_len))
- return;
-
- /* full packet: process */
- if (likely(pkt_len <= buf_len)) {
- touchkit_process_pkt(touchkit, buffer + pos);
- } else {
- /* incomplete packet: save in buffer */
- memcpy(touchkit->buffer, buffer + pos, buf_len - pos);
- touchkit->buf_len = buf_len - pos;
- }
- pos += pkt_len;
- }
-}
-
-
-static void touchkit_irq(struct urb *urb)
-{
- struct touchkit_usb *touchkit = urb->context;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ETIME:
- /* this urb is timing out */
- dbg("%s - urb timed out - was the device unplugged?",
- __FUNCTION__);
- return;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
- goto exit;
- }
-
- touchkit_process(touchkit, urb->actual_length);
-
-exit:
- retval = usb_submit_urb(urb, GFP_ATOMIC);
- if (retval)
- err("%s - usb_submit_urb failed with result: %d",
- __FUNCTION__, retval);
-}
-
-static int touchkit_open(struct input_dev *input)
-{
- struct touchkit_usb *touchkit = input->private;
-
- touchkit->irq->dev = touchkit->udev;
-
- if (usb_submit_urb(touchkit->irq, GFP_ATOMIC))
- return -EIO;
-
- return 0;
-}
-
-static void touchkit_close(struct input_dev *input)
-{
- struct touchkit_usb *touchkit = input->private;
-
- usb_kill_urb(touchkit->irq);
-}
-
-static int touchkit_alloc_buffers(struct usb_device *udev,
- struct touchkit_usb *touchkit)
-{
- touchkit->data = usb_buffer_alloc(udev, TOUCHKIT_REPORT_DATA_SIZE,
- GFP_ATOMIC, &touchkit->data_dma);
-
- if (!touchkit->data)
- return -1;
-
- return 0;
-}
-
-static void touchkit_free_buffers(struct usb_device *udev,
- struct touchkit_usb *touchkit)
-{
- if (touchkit->data)
- usb_buffer_free(udev, TOUCHKIT_REPORT_DATA_SIZE,
- touchkit->data, touchkit->data_dma);
-}
-
-static int touchkit_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct touchkit_usb *touchkit;
- struct input_dev *input_dev;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev = interface_to_usbdev(intf);
-
- interface = intf->cur_altsetting;
- endpoint = &interface->endpoint[0].desc;
-
- touchkit = kzalloc(sizeof(struct touchkit_usb), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!touchkit || !input_dev)
- goto out_free;
-
- if (touchkit_alloc_buffers(udev, touchkit))
- goto out_free;
-
- touchkit->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!touchkit->irq) {
- dbg("%s - usb_alloc_urb failed: touchkit->irq", __FUNCTION__);
- goto out_free_buffers;
- }
-
- touchkit->udev = udev;
- touchkit->input = input_dev;
-
- if (udev->manufacturer)
- strlcpy(touchkit->name, udev->manufacturer, sizeof(touchkit->name));
-
- if (udev->product) {
- if (udev->manufacturer)
- strlcat(touchkit->name, " ", sizeof(touchkit->name));
- strlcat(touchkit->name, udev->product, sizeof(touchkit->name));
- }
-
- if (!strlen(touchkit->name))
- snprintf(touchkit->name, sizeof(touchkit->name),
- "USB Touchscreen %04x:%04x",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- usb_make_path(udev, touchkit->phys, sizeof(touchkit->phys));
- strlcpy(touchkit->phys, "/input0", sizeof(touchkit->phys));
-
- input_dev->name = touchkit->name;
- input_dev->phys = touchkit->phys;
- usb_to_input_id(udev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = touchkit;
- input_dev->open = touchkit_open;
- input_dev->close = touchkit_close;
-
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X, TOUCHKIT_MIN_XC, TOUCHKIT_MAX_XC,
- TOUCHKIT_XC_FUZZ, TOUCHKIT_XC_FLAT);
- input_set_abs_params(input_dev, ABS_Y, TOUCHKIT_MIN_YC, TOUCHKIT_MAX_YC,
- TOUCHKIT_YC_FUZZ, TOUCHKIT_YC_FLAT);
-
- usb_fill_int_urb(touchkit->irq, touchkit->udev,
- usb_rcvintpipe(touchkit->udev, 0x81),
- touchkit->data, TOUCHKIT_REPORT_DATA_SIZE,
- touchkit_irq, touchkit, endpoint->bInterval);
-
- touchkit->irq->transfer_dma = touchkit->data_dma;
- touchkit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- input_register_device(touchkit->input);
-
- usb_set_intfdata(intf, touchkit);
- return 0;
-
-out_free_buffers:
- touchkit_free_buffers(udev, touchkit);
-out_free:
- input_free_device(input_dev);
- kfree(touchkit);
- return -ENOMEM;
-}
-
-static void touchkit_disconnect(struct usb_interface *intf)
-{
- struct touchkit_usb *touchkit = usb_get_intfdata(intf);
-
- dbg("%s - called", __FUNCTION__);
-
- if (!touchkit)
- return;
-
- dbg("%s - touchkit is initialized, cleaning up", __FUNCTION__);
- usb_set_intfdata(intf, NULL);
- usb_kill_urb(touchkit->irq);
- input_unregister_device(touchkit->input);
- usb_free_urb(touchkit->irq);
- touchkit_free_buffers(interface_to_usbdev(intf), touchkit);
- kfree(touchkit);
-}
-
-MODULE_DEVICE_TABLE(usb, touchkit_devices);
-
-static struct usb_driver touchkit_driver = {
- .name = "touchkitusb",
- .probe = touchkit_probe,
- .disconnect = touchkit_disconnect,
- .id_table = touchkit_devices,
-};
-
-static int __init touchkit_init(void)
-{
- return usb_register(&touchkit_driver);
-}
-
-static void __exit touchkit_cleanup(void)
-{
- usb_deregister(&touchkit_driver);
-}
-
-module_init(touchkit_init);
-module_exit(touchkit_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index b5332e679c4..88fb56d5db8 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1307,7 +1307,7 @@ static int auerswald_addservice (pauerswald_t cp, pauerscon_t scp)
}
-/* remove a service from the the device
+/* remove a service from the device
scp->id must be set! */
static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp)
{
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 15c70bd048c..8d0e360636e 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 5dce797bddb..1713e19a789 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -80,7 +80,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index fdf68479a16..88f6abe7362 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -39,7 +39,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/wait.h>
#include "rio500_usb.h"
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 1730d8642a4..5947afb0017 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -62,7 +62,6 @@
#include <linux/selection.h>
#include <linux/spinlock.h>
#include <linux/kref.h>
-#include <linux/smp_lock.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/vmalloc.h>
@@ -322,7 +321,7 @@ sisusbcon_deinit(struct vc_data *c)
/* interface routine */
static u8
sisusbcon_build_attr(struct vc_data *c, u8 color, u8 intensity,
- u8 blink, u8 underline, u8 reverse)
+ u8 blink, u8 underline, u8 reverse, u8 unused)
{
u8 attr = color;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 8a1df2c9c73..8977ec0d0f9 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index a0cc05d21a6..60d29440f31 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -55,7 +55,6 @@
#include <linux/usb.h>
#include <linux/types.h>
#include <linux/ethtool.h>
-#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 1ad4ee54b18..a05fd97e5bc 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -847,16 +847,6 @@ static void intr_callback(struct urb *urb)
* d[0].NO_CARRIER kicks in only with failed TX.
* ... so monitoring with MII may be safest.
*/
- if (pegasus->features & TRUST_LINK_STATUS) {
- if (d[5] & LINK_STATUS)
- netif_carrier_on(net);
- else
- netif_carrier_off(net);
- } else {
- /* Never set carrier _on_ based on ! NO_CARRIER */
- if (d[0] & NO_CARRIER)
- netif_carrier_off(net);
- }
/* bytes 3-4 == rx_lostpkt, reg 2E/2F */
pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index c7aadb413e8..c7467823cd1 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -11,7 +11,6 @@
#define PEGASUS_II 0x80000000
#define HAS_HOME_PNA 0x40000000
-#define TRUST_LINK_STATUS 0x20000000
#define PEGASUS_MTU 1536
#define RX_SKBS 4
@@ -204,7 +203,7 @@ PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
- DEFAULT_GPIO_RESET | PEGASUS_II | TRUST_LINK_STATUS )
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Billionton USBLP-100", VENDOR_BILLIONTON, 0x0987,
diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h
index cbb53e065d6..82db5a8e528 100644
--- a/drivers/usb/net/usbnet.h
+++ b/drivers/usb/net/usbnet.h
@@ -129,7 +129,7 @@ extern void usbnet_disconnect(struct usb_interface *);
/* Drivers that reuse some of the standard USB CDC infrastructure
- * (notably, using multiple interfaces according to the the CDC
+ * (notably, using multiple interfaces according to the CDC
* union descriptor) get some helper code.
*/
struct cdc_state {
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index ba5d1dc0303..3efe67092f1 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -558,7 +558,7 @@ config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
depends on USB_SERIAL
help
- Say Y here if you have a USB debugging device used to recieve
+ Say Y here if you have a USB debugging device used to receive
debugging data from another machine. The most common of these
devices is the NetChip TurboCONNECT device.
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index b675735bfbe..fbc8c27d5d9 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -9,7 +9,7 @@
* The device works as an standard CDC device, it has 2 interfaces, the first
* one is for firmware access and the second is the serial one.
* The protocol is very simply, there are two posibilities reading or writing.
- * When writting the first urb must have a Header that starts with 0x20 0x29 the
+ * When writing the first urb must have a Header that starts with 0x20 0x29 the
* next two bytes must say how much data will be sended.
* When reading the process is almost equal except that the header starts with
* 0x00 0x20.
@@ -18,7 +18,7 @@
* buffer: The First and Second byte is used for a Header, the Third and Fourth
* tells the device the amount of information the package holds.
* Packages are 60 bytes long Header Stuff.
- * When writting to the device the first two bytes of the header are 0x20 0x29
+ * When writing to the device the first two bytes of the header are 0x20 0x29
* When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange
* situation, when too much data arrives to the device because it sends the data
* but with out the header. I will use a simply hack to override this situation,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 18f74ac7656..4807f960150 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2465,7 +2465,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
((edge_serial->is_epic) &&
(!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
(regNum == MCR))) {
- dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+ dbg("SendCmdWriteUartReg - Not writing to MCR Register");
return 0;
}
@@ -2473,7 +2473,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
((edge_serial->is_epic) &&
(!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
(regNum == LCR))) {
- dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+ dbg ("SendCmdWriteUartReg - Not writing to LCR Register");
return 0;
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 7639022cdf8..87f378806db 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -28,7 +28,6 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 21f3ddbc908..6dac1ffdde8 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -47,7 +47,6 @@
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/blkdev.h>
-#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <scsi/scsi_host.h>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8372ace4a0d..9a256d2ff9d 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,6 +5,11 @@
menu "Graphics support"
source "drivers/video/backlight/Kconfig"
+source "drivers/video/display/Kconfig"
+
+config VGASTATE
+ tristate
+ default n
config FB
tristate "Support for frame buffer devices"
@@ -90,6 +95,43 @@ config FB_CFB_IMAGEBLIT
blitting. This is used by drivers that don't provide their own
(accelerated) version.
+config FB_SYS_FILLRECT
+ tristate
+ depends on FB
+ default n
+ ---help---
+ Include the sys_fillrect function for generic software rectangle
+ filling. This is used by drivers that don't provide their own
+ (accelerated) version and the framebuffer is in system RAM.
+
+config FB_SYS_COPYAREA
+ tristate
+ depends on FB
+ default n
+ ---help---
+ Include the sys_copyarea function for generic software area copying.
+ This is used by drivers that don't provide their own (accelerated)
+ version and the framebuffer is in system RAM.
+
+config FB_SYS_IMAGEBLIT
+ tristate
+ depends on FB
+ default n
+ ---help---
+ Include the sys_imageblit function for generic software image
+ blitting. This is used by drivers that don't provide their own
+ (accelerated) version and the framebuffer is in system RAM.
+
+config FB_SYS_FOPS
+ tristate
+ depends on FB
+ default n
+
+config FB_DEFERRED_IO
+ bool
+ depends on FB
+ default y
+
config FB_SVGALIB
tristate
depends on FB
@@ -191,7 +233,7 @@ config FB_ARMCLCD
If you want to compile this as a module (=code which can be
inserted into and removed from the running kernel), say M
- here and read <file:Documentation/modules.txt>. The module
+ here and read <file:Documentation/kbuild/modules.txt>. The module
will be called amba-clcd.
choice
@@ -375,9 +417,10 @@ config FB_FM2
config FB_ARC
tristate "Arc Monochrome LCD board support"
depends on FB && X86
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
help
This enables support for the Arc Monochrome LCD board. The board
is based on the KS-108 lcd controller and is typically a matrix
@@ -389,14 +432,17 @@ config FB_ARC
config FB_ATARI
bool "Atari native chipset support"
- depends on (FB = y) && ATARI && BROKEN
+ depends on (FB = y) && ATARI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
help
This is the frame buffer device driver for the builtin graphics
chipset found in Ataris.
config FB_OF
bool "Open Firmware frame buffer device support"
- depends on (FB = y) && (PPC64 || PPC_OF)
+ depends on (FB = y) && (PPC64 || PPC_OF) && (!PPC_PSERIES || PCI)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -472,6 +518,8 @@ config FB_VGA16
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
help
This is the frame buffer device driver for VGA 16 color graphic
cards. Say Y if you have such a card.
@@ -516,15 +564,25 @@ config FB_HP300
default y
config FB_TGA
- tristate "TGA framebuffer support"
- depends on FB && ALPHA
+ tristate "TGA/SFB+ framebuffer support"
+ depends on FB && (ALPHA || TC)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select BITREVERSE
- help
- This is the frame buffer device driver for generic TGA graphic
- cards. Say Y if you have one of those.
+ ---help---
+ This is the frame buffer device driver for generic TGA and SFB+
+ graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards,
+ also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3
+ TURBOchannel cards, also known as PMAGD-A, -B and -C.
+
+ Due to hardware limitations ZLX-E2 and E3 cards are not supported
+ for DECstation 5000/200 systems. Additionally due to firmware
+ limitations these cards may cause troubles with booting DECstation
+ 5000/240 and /260 systems, but are fully supported under Linux if
+ you manage to get it going. ;-)
+
+ Say Y if you have one of those.
config FB_VESA
bool "VESA VGA graphics support"
@@ -548,6 +606,21 @@ config FB_IMAC
help
This is the frame buffer device driver for the Intel-based Macintosh
+config FB_HECUBA
+ tristate "Hecuba board support"
+ depends on FB && X86 && MMU
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
+ help
+ This enables support for the Hecuba board. This driver was tested
+ with an E-Ink 800x600 display and x86 SBCs through a 16 bit GPIO
+ interface (8 bit data, 4 bit control). If you anticpate using
+ this driver, say Y or M; otherwise say N. You must specify the
+ GPIO IO address to be used for setting control and data.
+
config FB_HGA
tristate "Hercules mono graphics support"
depends on FB && X86
@@ -683,6 +756,7 @@ config FB_NVIDIA
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select BITREVERSE
+ select VGASTATE
help
This driver supports graphics boards with the nVidia chips, TNT
and newer. For very old chipsets, such as the RIVA128, then use
@@ -721,6 +795,7 @@ config FB_RIVA
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select BITREVERSE
+ select VGASTATE
help
This driver supports graphics boards with the nVidia Riva/Geforce
chips.
@@ -767,6 +842,7 @@ config FB_I810
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VGASTATE
help
This driver supports the on-board graphics built in to the Intel 810
and 815 chipsets. Say Y if you have and plan to use such a board.
@@ -806,6 +882,22 @@ config FB_I810_I2C
select FB_DDC
help
+config FB_LE80578
+ tristate "Intel LE80578 (Vermilion) support"
+ depends on FB && PCI && X86
+ select FB_MODE_HELPERS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This driver supports the LE80578 (Vermilion Range) chipset
+
+config FB_CARILLO_RANCH
+ tristate "Intel Carillo Ranch support"
+ depends on FB_LE80578 && FB && PCI && X86
+ help
+ This driver supports the LE80578 (Carillo Ranch) board
+
config FB_INTEL
tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)"
depends on FB && EXPERIMENTAL && PCI && X86
@@ -1117,6 +1209,8 @@ config FB_S3
select FB_CFB_IMAGEBLIT
select FB_TILEBLITTING
select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
---help---
Driver for graphics boards with S3 Trio / S3 Virge chip.
@@ -1127,6 +1221,7 @@ config FB_SAVAGE
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VGASTATE
help
This driver supports notebooks and computers with S3 Savage PCI/AGP
chips.
@@ -1193,6 +1288,7 @@ config FB_NEOMAGIC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select VGASTATE
help
This driver supports notebooks with NeoMagic PCI chips.
Say Y if you have such a graphics card.
@@ -1252,6 +1348,20 @@ config FB_VOODOO1
Please read the <file:Documentation/fb/README-sstfb.txt> for supported
options and other important info support.
+config FB_VT8623
+ tristate "VIA VT8623 support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
+ ---help---
+ Driver for CastleRock integrated graphics core in the
+ VIA VT8623 [Apollo CLE266] chipset.
+
config FB_CYBLA
tristate "Cyberblade/i1 support"
depends on FB && PCI && X86_32 && !64BIT
@@ -1305,6 +1415,20 @@ config FB_TRIDENT_ACCEL
This will compile the Trident frame buffer device with
acceleration functions.
+config FB_ARK
+ tristate "ARK 2000PV support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_TILEBLITTING
+ select FB_SVGALIB
+ select VGASTATE
+ select FONT_8x16 if FRAMEBUFFER_CONSOLE
+ ---help---
+ Driver for PCI graphics boards with ARK 2000PV chip
+ and ICS 5342 RAMDAC.
+
config FB_PM3
tristate "Permedia3 support"
depends on FB && PCI && BROKEN
@@ -1380,6 +1504,32 @@ config FB_LEO
This is the frame buffer device driver for the SBUS-based Sun ZX
(leo) frame buffer cards.
+config FB_XVR500
+ bool "Sun XVR-500 3DLABS Wildcat support"
+ depends on FB && PCI && SPARC64
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the framebuffer device for the Sun XVR-500 and similar
+ graphics cards based upon the 3DLABS Wildcat chipset. The driver
+ only works on sparc64 systems where the system firwmare has
+ mostly initialized the card already. It is treated as a
+ completely dumb framebuffer device.
+
+config FB_XVR2500
+ bool "Sun XVR-2500 3DLABS Wildcat support"
+ depends on FB && PCI && SPARC64
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the framebuffer device for the Sun XVR-2500 and similar
+ graphics cards based upon the 3DLABS Wildcat chipset. The driver
+ only works on sparc64 systems where the system firwmare has
+ mostly initialized the card already. It is treated as a
+ completely dumb framebuffer device.
+
config FB_PCI
bool "PCI framebuffers"
depends on (FB = y) && PCI && SPARC
@@ -1491,7 +1641,7 @@ config FB_PXA
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called pxafb. If you want to compile it as a module,
- say M here and read <file:Documentation/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
If unsure, say N.
@@ -1544,7 +1694,7 @@ config FB_W100
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called w100fb. If you want to compile it as a module,
- say M here and read <file:Documentation/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
If unsure, say N.
@@ -1561,7 +1711,7 @@ config FB_S3C2410
This driver is also available as a module ( = code which can be
inserted and removed from the running kernel whenever you want). The
module will be called s3c2410fb. If you want to compile it as a module,
- say M here and read <file:Documentation/modules.txt>.
+ say M here and read <file:Documentation/kbuild/modules.txt>.
If unsure, say N.
config FB_S3C2410_DEBUG
@@ -1633,13 +1783,25 @@ config FB_PS3_DEFAULT_SIZE_M
The default value can be overridden on the kernel command line
using the "ps3fb" option (e.g. "ps3fb=9M");
-config FB_VIRTUAL
- tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
- depends on FB
+config FB_XILINX
+ tristate "Xilinx frame buffer support"
+ depends on FB && XILINX_VIRTEX
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
+ Include support for the Xilinx ML300/ML403 reference design
+ framebuffer. ML300 carries a 640*480 LCD display on the board,
+ ML403 uses a standard DB15 VGA connector.
+
+config FB_VIRTUAL
+ tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
+ depends on FB
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ ---help---
This is a `virtual' frame buffer device. It operates on a chunk of
unswappable kernel memory instead of on the memory of a graphics
board. This means you cannot see any output sent to this frame
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 760305c8a84..0b70567458f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,6 +4,7 @@
# Each configuration option enables a list of files.
+obj-$(CONFIG_VGASTATE) += vgastate.o
obj-y += fb_notify.o
obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
@@ -12,14 +13,19 @@ fb-objs := $(fb-y)
obj-$(CONFIG_VT) += console/
obj-$(CONFIG_LOGO) += logo/
-obj-y += backlight/
+obj-y += backlight/ display/
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o
+obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o
+obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o
+obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o
obj-$(CONFIG_FB_SVGALIB) += svgalib.o
obj-$(CONFIG_FB_MACMODES) += macmodes.o
obj-$(CONFIG_FB_DDC) += fb_ddc.o
+obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o
# Hardware specific drivers go first
obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o
@@ -30,7 +36,7 @@ obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o
obj-$(CONFIG_FB_MATROX) += matrox/
-obj-$(CONFIG_FB_RIVA) += riva/ vgastate.o
+obj-$(CONFIG_FB_RIVA) += riva/
obj-$(CONFIG_FB_NVIDIA) += nvidia/
obj-$(CONFIG_FB_ATY) += aty/ macmodes.o
obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o
@@ -40,8 +46,7 @@ obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
obj-$(CONFIG_FB_MBX) += mbx/
-obj-$(CONFIG_FB_I810) += vgastate.o
-obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o
+obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
obj-$(CONFIG_FB_3DFX) += tdfxfb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o
obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
@@ -49,9 +54,12 @@ obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_IMSTT) += imsttfb.o
obj-$(CONFIG_FB_FM2) += fm2fb.o
+obj-$(CONFIG_FB_VT8623) += vt8623fb.o
obj-$(CONFIG_FB_CYBLA) += cyblafb.o
obj-$(CONFIG_FB_TRIDENT) += tridentfb.o
-obj-$(CONFIG_FB_S3) += s3fb.o vgastate.o
+obj-$(CONFIG_FB_LE80578) += vermilion/
+obj-$(CONFIG_FB_S3) += s3fb.o
+obj-$(CONFIG_FB_ARK) += arkfb.o
obj-$(CONFIG_FB_STI) += stifb.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o
obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o
@@ -63,9 +71,13 @@ obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o
obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o
obj-$(CONFIG_FB_SGIVW) += sgivwfb.o
obj-$(CONFIG_FB_ACORN) += acornfb.o
-obj-$(CONFIG_FB_ATARI) += atafb.o
+obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \
+ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
obj-$(CONFIG_FB_MAC) += macfb.o
+obj-$(CONFIG_FB_HECUBA) += hecubafb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
+obj-$(CONFIG_FB_XVR500) += sunxvr500.o
+obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o
obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_Q40) += q40fb.o
@@ -99,11 +111,12 @@ obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
+obj-$(CONFIG_FB_XILINX) += xilinxfb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
obj-$(CONFIG_FB_IMAC) += imacfb.o
-obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
+obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
# the test framebuffer is last
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index 30a8369757e..db15baca3f7 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -262,7 +262,8 @@ static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper,
ks108_set_yaddr(par, chipindex, upper/8);
linesize = par->info->var.xres/8;
- src = par->info->screen_base + (left/8) + (upper * linesize);
+ src = (unsigned char __force *) par->info->screen_base + (left/8) +
+ (upper * linesize);
ks108_set_xaddr(par, chipindex, left);
bitmask=1;
@@ -368,7 +369,7 @@ static void arcfb_fillrect(struct fb_info *info,
{
struct arcfb_par *par = info->par;
- cfb_fillrect(info, rect);
+ sys_fillrect(info, rect);
/* update the physical lcd */
arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height);
@@ -379,7 +380,7 @@ static void arcfb_copyarea(struct fb_info *info,
{
struct arcfb_par *par = info->par;
- cfb_copyarea(info, area);
+ sys_copyarea(info, area);
/* update the physical lcd */
arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height);
@@ -389,7 +390,7 @@ static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct arcfb_par *par = info->par;
- cfb_imageblit(info, image);
+ sys_imageblit(info, image);
/* update the physical lcd */
arcfb_lcd_update(par, image->dx, image->dy, image->width,
@@ -439,14 +440,11 @@ static int arcfb_ioctl(struct fb_info *info,
* the fb. it's inefficient for them to do anything less than 64*8
* writes since we update the lcd in each write() anyway.
*/
-static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t count,
- loff_t *ppos)
+static ssize_t arcfb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
{
/* modded from epson 1355 */
- struct inode *inode;
- int fbidx;
- struct fb_info *info;
unsigned long p;
int err=-EINVAL;
unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount;
@@ -454,13 +452,6 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou
unsigned int xres;
p = *ppos;
- inode = file->f_path.dentry->d_inode;
- fbidx = iminor(inode);
- info = registered_fb[fbidx];
-
- if (!info || !info->screen_base)
- return -ENODEV;
-
par = info->par;
xres = info->var.xres;
fbmemlength = (xres * info->var.yres)/8;
@@ -477,7 +468,7 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou
if (count) {
char *base_addr;
- base_addr = info->screen_base;
+ base_addr = (char __force *)info->screen_base;
count -= copy_from_user(base_addr + p, buf, count);
*ppos += count;
err = -EFAULT;
@@ -503,6 +494,7 @@ static ssize_t arcfb_write(struct file *file, const char __user *buf, size_t cou
static struct fb_ops arcfb_ops = {
.owner = THIS_MODULE,
.fb_open = arcfb_open,
+ .fb_read = fb_sys_read,
.fb_write = arcfb_write,
.fb_release = arcfb_release,
.fb_pan_display = arcfb_pan_display,
@@ -603,7 +595,7 @@ static int arcfb_remove(struct platform_device *dev)
if (info) {
unregister_framebuffer(info);
- vfree(info->screen_base);
+ vfree((void __force *)info->screen_base);
framebuffer_release(info);
}
return 0;
diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c
new file mode 100644
index 00000000000..ba6fede5c46
--- /dev/null
+++ b/drivers/video/arkfb.c
@@ -0,0 +1,1200 @@
+/*
+ * linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV
+ * with ICS 5342 dac (it is easy to add support for different dacs).
+ *
+ * Copyright (c) 2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct arkfb_info {
+ int mclk_freq;
+ int mtrr_reg;
+
+ struct dac_info *dac;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static const struct svga_fb_format arkfb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+ {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {24, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 8, 8},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
+ SVGA_FORMAT_END
+};
+
+
+/* CRT timing register sets */
+
+static const struct vga_regset ark_h_total_regs[] = {{0x00, 0, 7}, {0x41, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_h_display_regs[] = {{0x01, 0, 7}, {0x41, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_start_regs[] = {{0x02, 0, 7}, {0x41, 5, 5}, VGA_REGSET_END};
+static const struct vga_regset ark_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7 }, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_start_regs[] = {{0x04, 0, 7}, {0x41, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static const struct vga_regset ark_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x40, 7, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x40, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x40, 5, 5}, VGA_REGSET_END};
+// const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x40, 4, 4}, VGA_REGSET_END};
+static const struct vga_regset ark_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static const struct vga_regset ark_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, VGA_REGSET_END};
+static const struct vga_regset ark_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x40, 0, 2}, VGA_REGSET_END};
+static const struct vga_regset ark_offset_regs[] = {{0x13, 0, 7}, {0x41, 3, 3}, VGA_REGSET_END};
+
+static const struct svga_timing_regs ark_timing_regs = {
+ ark_h_total_regs, ark_h_display_regs, ark_h_blank_start_regs,
+ ark_h_blank_end_regs, ark_h_sync_start_regs, ark_h_sync_end_regs,
+ ark_v_total_regs, ark_v_display_regs, ark_v_blank_start_regs,
+ ark_v_blank_end_regs, ark_v_sync_start_regs, ark_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2007 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for ARK 2000PV");
+
+module_param(mode, charp, 0444);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+static int threshold = 4;
+
+module_param(threshold, int, 0644);
+MODULE_PARM_DESC(threshold, "FIFO threshold");
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void arkfb_settile(struct fb_info *info, struct fb_tilemap *map)
+{
+ const u8 *font = map->data;
+ u8 __iomem *fb = (u8 __iomem *)info->screen_base;
+ int i, c;
+
+ if ((map->width != 8) || (map->height != 16) ||
+ (map->depth != 1) || (map->length != 256)) {
+ printk(KERN_ERR "fb%d: unsupported font parameters: width %d, "
+ "height %d, depth %d, length %d\n", info->node,
+ map->width, map->height, map->depth, map->length);
+ return;
+ }
+
+ fb += 2;
+ for (c = 0; c < map->length; c++) {
+ for (i = 0; i < map->height; i++) {
+ fb_writeb(font[i], &fb[i * 4]);
+ fb_writeb(font[i], &fb[i * 4 + (128 * 8)]);
+ }
+ fb += 128;
+
+ if ((c % 8) == 7)
+ fb += 128*8;
+
+ font += map->height;
+ }
+}
+
+static struct fb_tile_ops arkfb_tile_ops = {
+ .fb_settile = arkfb_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* arkfb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+/* arkfb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* arkfb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void arkfb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+
+}
+
+static void arkfb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ arkfb_iplan_imageblit(info, image);
+ else
+ arkfb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void arkfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ arkfb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+enum
+{
+ DAC_PSEUDO8_8,
+ DAC_RGB1555_8,
+ DAC_RGB0565_8,
+ DAC_RGB0888_8,
+ DAC_RGB8888_8,
+ DAC_PSEUDO8_16,
+ DAC_RGB1555_16,
+ DAC_RGB0565_16,
+ DAC_RGB0888_16,
+ DAC_RGB8888_16,
+ DAC_MAX
+};
+
+struct dac_ops {
+ int (*dac_get_mode)(struct dac_info *info);
+ int (*dac_set_mode)(struct dac_info *info, int mode);
+ int (*dac_get_freq)(struct dac_info *info, int channel);
+ int (*dac_set_freq)(struct dac_info *info, int channel, u32 freq);
+ void (*dac_release)(struct dac_info *info);
+};
+
+typedef void (*dac_read_regs_t)(void *data, u8 *code, int count);
+typedef void (*dac_write_regs_t)(void *data, u8 *code, int count);
+
+struct dac_info
+{
+ struct dac_ops *dacops;
+ dac_read_regs_t dac_read_regs;
+ dac_write_regs_t dac_write_regs;
+ void *data;
+};
+
+
+static inline u8 dac_read_reg(struct dac_info *info, u8 reg)
+{
+ u8 code[2] = {reg, 0};
+ info->dac_read_regs(info->data, code, 1);
+ return code[1];
+}
+
+static inline void dac_read_regs(struct dac_info *info, u8 *code, int count)
+{
+ info->dac_read_regs(info->data, code, count);
+}
+
+static inline void dac_write_reg(struct dac_info *info, u8 reg, u8 val)
+{
+ u8 code[2] = {reg, val};
+ info->dac_write_regs(info->data, code, 1);
+}
+
+static inline void dac_write_regs(struct dac_info *info, u8 *code, int count)
+{
+ info->dac_write_regs(info->data, code, count);
+}
+
+static inline int dac_set_mode(struct dac_info *info, int mode)
+{
+ return info->dacops->dac_set_mode(info, mode);
+}
+
+static inline int dac_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+ return info->dacops->dac_set_freq(info, channel, freq);
+}
+
+static inline void dac_release(struct dac_info *info)
+{
+ info->dacops->dac_release(info);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* ICS5342 DAC */
+
+struct ics5342_info
+{
+ struct dac_info dac;
+ u8 mode;
+};
+
+#define DAC_PAR(info) ((struct ics5342_info *) info)
+
+/* LSB is set to distinguish unused slots */
+static const u8 ics5342_mode_table[DAC_MAX] = {
+ [DAC_PSEUDO8_8] = 0x01, [DAC_RGB1555_8] = 0x21, [DAC_RGB0565_8] = 0x61,
+ [DAC_RGB0888_8] = 0x41, [DAC_PSEUDO8_16] = 0x11, [DAC_RGB1555_16] = 0x31,
+ [DAC_RGB0565_16] = 0x51, [DAC_RGB0888_16] = 0x91, [DAC_RGB8888_16] = 0x71
+};
+
+static int ics5342_set_mode(struct dac_info *info, int mode)
+{
+ u8 code;
+
+ if (mode >= DAC_MAX)
+ return -EINVAL;
+
+ code = ics5342_mode_table[mode];
+
+ if (! code)
+ return -EINVAL;
+
+ dac_write_reg(info, 6, code & 0xF0);
+ DAC_PAR(info)->mode = mode;
+
+ return 0;
+}
+
+static const struct svga_pll ics5342_pll = {3, 129, 3, 33, 0, 3,
+ 60000, 250000, 14318};
+
+/* pd4 - allow only posdivider 4 (r=2) */
+static const struct svga_pll ics5342_pll_pd4 = {3, 129, 3, 33, 2, 2,
+ 60000, 335000, 14318};
+
+/* 270 MHz should be upper bound for VCO clock according to specs,
+ but that is too restrictive in pd4 case */
+
+static int ics5342_set_freq(struct dac_info *info, int channel, u32 freq)
+{
+ u16 m, n, r;
+
+ /* only postdivider 4 (r=2) is valid in mode DAC_PSEUDO8_16 */
+ int rv = svga_compute_pll((DAC_PAR(info)->mode == DAC_PSEUDO8_16)
+ ? &ics5342_pll_pd4 : &ics5342_pll,
+ freq, &m, &n, &r, 0);
+
+ if (rv < 0) {
+ return -EINVAL;
+ } else {
+ u8 code[6] = {4, 3, 5, m-2, 5, (n-2) | (r << 5)};
+ dac_write_regs(info, code, 3);
+ return 0;
+ }
+}
+
+static void ics5342_release(struct dac_info *info)
+{
+ ics5342_set_mode(info, DAC_PSEUDO8_8);
+ kfree(info);
+}
+
+static struct dac_ops ics5342_ops = {
+ .dac_set_mode = ics5342_set_mode,
+ .dac_set_freq = ics5342_set_freq,
+ .dac_release = ics5342_release
+};
+
+
+static struct dac_info * ics5342_init(dac_read_regs_t drr, dac_write_regs_t dwr, void *data)
+{
+ struct dac_info *info = kzalloc(sizeof(struct ics5342_info), GFP_KERNEL);
+
+ if (! info)
+ return NULL;
+
+ info->dacops = &ics5342_ops;
+ info->dac_read_regs = drr;
+ info->dac_write_regs = dwr;
+ info->data = data;
+ DAC_PAR(info)->mode = DAC_PSEUDO8_8; /* estimation */
+ return info;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static unsigned short dac_regs[4] = {0x3c8, 0x3c9, 0x3c6, 0x3c7};
+
+static void ark_dac_read_regs(void *data, u8 *code, int count)
+{
+ u8 regval = vga_rseq(NULL, 0x1C);
+
+ while (count != 0)
+ {
+ vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+ code[1] = vga_r(NULL, dac_regs[code[0] & 3]);
+ count--;
+ code += 2;
+ }
+
+ vga_wseq(NULL, 0x1C, regval);
+}
+
+static void ark_dac_write_regs(void *data, u8 *code, int count)
+{
+ u8 regval = vga_rseq(NULL, 0x1C);
+
+ while (count != 0)
+ {
+ vga_wseq(NULL, 0x1C, regval | (code[0] & 4) ? 0x80 : 0);
+ vga_w(NULL, dac_regs[code[0] & 3], code[1]);
+ count--;
+ code += 2;
+ }
+
+ vga_wseq(NULL, 0x1C, regval);
+}
+
+
+static void ark_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ struct arkfb_info *par = info->par;
+ u8 regval;
+
+ int rv = dac_set_freq(par->dac, 0, 1000000000 / pixclock);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+}
+
+
+/* Open framebuffer */
+
+static int arkfb_open(struct fb_info *info, int user)
+{
+ struct arkfb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0x60;
+ par->state.num_seq = 0x30;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Close framebuffer */
+
+static int arkfb_release(struct fb_info *info, int user)
+{
+ struct arkfb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1) {
+ restore_vga(&(par->state));
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ }
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+/* Validate passed in var */
+
+static int arkfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (arkfb_formats, var, NULL);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = arkfb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&ark_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ /* Interlaced mode is broken */
+ if (var->vmode & FB_VMODE_INTERLACED)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* Set video mode from par */
+
+static int arkfb_set_par(struct fb_info *info)
+{
+ struct arkfb_info *par = info->par;
+ u32 value, mode, hmul, hdiv, offset_value, screen_size;
+ u32 bpp = info->var.bits_per_pixel;
+ u8 regval;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = &arkfb_tile_ops;
+
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
+ offset_value = info->var.xres_virtual / 16;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+
+ /* Blank screen and turn off sync */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(ark_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(ark_start_address_regs, 0);
+
+ /* ARK specific initialization */
+ svga_wseq_mask(0x10, 0x1F, 0x1F); /* enable linear framebuffer and full memory access */
+ svga_wseq_mask(0x12, 0x03, 0x03); /* 4 MB linear framebuffer size */
+
+ vga_wseq(NULL, 0x13, info->fix.smem_start >> 16);
+ vga_wseq(NULL, 0x14, info->fix.smem_start >> 24);
+ vga_wseq(NULL, 0x15, 0);
+ vga_wseq(NULL, 0x16, 0);
+
+ /* Set the FIFO threshold register */
+ /* It is fascinating way to store 5-bit value in 8-bit register */
+ regval = 0x10 | ((threshold & 0x0E) >> 1) | (threshold & 0x01) << 7 | (threshold & 0x10) << 1;
+ vga_wseq(NULL, 0x18, regval);
+
+ /* Set the offset register */
+ pr_debug("fb%d: offset register : %d\n", info->node, offset_value);
+ svga_wcrt_multi(ark_offset_regs, offset_value);
+
+ /* fix for hi-res textmode */
+ svga_wcrt_mask(0x40, 0x08, 0x08);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ if (info->var.vmode & FB_VMODE_INTERLACED)
+ svga_wcrt_mask(0x44, 0x04, 0x04);
+ else
+ svga_wcrt_mask(0x44, 0x00, 0x04);
+
+ hmul = 1;
+ hdiv = 1;
+ mode = svga_match_format(arkfb_formats, &(info->var), &(info->fix));
+
+ /* Set mode-specific register values */
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x10); /* basic VGA mode */
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode */
+
+ if (info->var.pixclock > 20000) {
+ pr_debug("fb%d: not using multiplex\n", info->node);
+ svga_wcrt_mask(0x46, 0x00, 0x04); /* 8bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_8);
+ } else {
+ pr_debug("fb%d: using multiplex\n", info->node);
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_PSEUDO8_16);
+ hdiv = 2;
+ }
+ break;
+ case 4:
+ pr_debug("fb%d: 5/5/5 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB1555_16);
+ break;
+ case 5:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1A); /* 16bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB0565_16);
+ break;
+ case 6:
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x16); /* 8bpp accel mode ??? */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB0888_16);
+ hmul = 3;
+ hdiv = 2;
+ break;
+ case 7:
+ pr_debug("fb%d: 8/8/8/8 truecolor\n", info->node);
+
+ vga_wseq(NULL, 0x11, 0x1E); /* 32bpp accel mode */
+ svga_wcrt_mask(0x46, 0x04, 0x04); /* 16bit pixel path */
+ dac_set_mode(par->dac, DAC_RGB8888_16);
+ hmul = 2;
+ break;
+ default:
+ printk(KERN_ERR "fb%d: unsupported mode - bug\n", info->node);
+ return -EINVAL;
+ }
+
+ ark_set_pixclock(info, (hdiv * info->var.pixclock) / hmul);
+ svga_set_timings(&ark_timing_regs, &(info->var), hmul, hdiv,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1,
+ (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
+ hmul, info->node);
+
+ /* Set interlaced mode start/end register */
+ value = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
+ value = ((value * hmul / hdiv) / 8) - 5;
+ vga_wcrt(NULL, 0x42, (value + 1) / 2);
+
+ memset_io(info->screen_base, 0x00, screen_size);
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+/* Set a colour register */
+
+static int arkfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ if ((fb->var.bits_per_pixel == 4) &&
+ (fb->var.nonstd == 0)) {
+ outb(0xF0, VGA_PEL_MSK);
+ outb(regno*16, VGA_PEL_IW);
+ } else {
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ }
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return 0;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else
+ return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return 0;
+
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Set the display blanking state */
+
+static int arkfb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ break;
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: sync down\n", info->node);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+ break;
+ }
+ return 0;
+}
+
+
+/* Pan the display */
+
+static int arkfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned int offset;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
+ offset = offset >> 2;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 3);
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(ark_start_address_regs, offset);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops arkfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = arkfb_open,
+ .fb_release = arkfb_release,
+ .fb_check_var = arkfb_check_var,
+ .fb_set_par = arkfb_set_par,
+ .fb_setcolreg = arkfb_setcolreg,
+ .fb_blank = arkfb_blank,
+ .fb_pan_display = arkfb_pan_display,
+ .fb_fillrect = arkfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = arkfb_imageblit,
+ .fb_get_caps = svga_get_caps,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* PCI probe */
+static int __devinit ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct arkfb_info *par;
+ int rc;
+ u8 regval;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct arkfb_info), NULL);
+ if (! info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &arkfb_ops;
+
+ /* Prepare PCI device */
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "arkfb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+ par->dac = ics5342_init(ark_dac_read_regs, ark_dac_write_regs, info);
+ if (! par->dac) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "RAMDAC initialization failed\n");
+ goto err_dac;
+ }
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap;
+ }
+
+ /* FIXME get memsize */
+ regval = vga_rseq(NULL, 0x10);
+ info->screen_size = (1 << (regval >> 6)) << 20;
+ info->fix.smem_len = info->screen_size;
+
+ strcpy(info->fix.id, "ARK 2000PV");
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*) (par->pseudo_palette);
+
+ /* Prepare startup mode */
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebugger\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20);
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, info->screen_base);
+err_iomap:
+ dac_release(par->dac);
+err_dac:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+/* PCI remove */
+
+static void __devexit ark_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ if (info) {
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ dac_release(par->dac);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int ark_pci_suspend (struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int ark_pci_resume (struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct arkfb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
+ pci_set_master(dev);
+
+ arkfb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+fail:
+ release_console_sem();
+ return 0;
+}
+#else
+#define ark_pci_suspend NULL
+#define ark_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id ark_devices[] __devinitdata = {
+ {PCI_DEVICE(0xEDD8, 0xA099)},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+
+MODULE_DEVICE_TABLE(pci, ark_devices);
+
+static struct pci_driver arkfb_pci_driver = {
+ .name = "arkfb",
+ .id_table = ark_devices,
+ .probe = ark_pci_probe,
+ .remove = __devexit_p(ark_pci_remove),
+ .suspend = ark_pci_suspend,
+ .resume = ark_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit arkfb_cleanup(void)
+{
+ pr_debug("arkfb: cleaning up\n");
+ pci_unregister_driver(&arkfb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+static int __init arkfb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("arkfb", &option))
+ return -ENODEV;
+
+ if (option && *option)
+ mode = option;
+#endif
+
+ pr_debug("arkfb: initializing\n");
+ return pci_register_driver(&arkfb_pci_driver);
+}
+
+module_init(arkfb_init);
+module_exit(arkfb_cleanup);
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index bffe2b94634..0038a0541c7 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2,7 +2,7 @@
* linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device
*
* Copyright (C) 1994 Martin Schaller & Roman Hodek
- *
+ *
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
@@ -70,14 +70,8 @@
#include <linux/fb.h>
#include <asm/atarikb.h>
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-iplan2p2.h>
-#include <video/fbcon-iplan2p4.h>
-#include <video/fbcon-iplan2p8.h>
-#include <video/fbcon-mfb.h>
-
+#include "c2p.h"
+#include "atafb.h"
#define SWITCH_ACIA 0x01 /* modes for switch on OverScan */
#define SWITCH_SND6 0x40
@@ -87,22 +81,48 @@
#define up(x, r) (((x) + (r) - 1) & ~((r)-1))
+ /*
+ * Interface to the world
+ */
+
+static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+static int atafb_set_par(struct fb_info *info);
+static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
+ unsigned int blue, unsigned int transp,
+ struct fb_info *info);
+static int atafb_blank(int blank, struct fb_info *info);
+static int atafb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static void atafb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect);
+static void atafb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *region);
+static void atafb_imageblit(struct fb_info *info, const struct fb_image *image);
+static int atafb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+
-static int default_par=0; /* default resolution (0=none) */
+static int default_par; /* default resolution (0=none) */
-static unsigned long default_mem_req=0;
+static unsigned long default_mem_req;
-static int hwscroll=-1;
+static int hwscroll = -1;
static int use_hwscroll = 1;
-static int sttt_xres=640,st_yres=400,tt_yres=480;
-static int sttt_xres_virtual=640,sttt_yres_virtual=400;
-static int ovsc_offset=0, ovsc_addlen=0;
+static int sttt_xres = 640, st_yres = 400, tt_yres = 480;
+static int sttt_xres_virtual = 640, sttt_yres_virtual = 400;
+static int ovsc_offset, ovsc_addlen;
+
+ /*
+ * Hardware parameters for current mode
+ */
static struct atafb_par {
void *screen_base;
int yres_virtual;
+ u_long next_line;
+ u_long next_plane;
#if defined ATAFB_TT || defined ATAFB_STE
union {
struct {
@@ -138,7 +158,7 @@ static struct atafb_par {
/* Don't calculate an own resolution, and thus don't change the one found when
* booting (currently used for the Falcon to keep settings for internal video
* hardware extensions (e.g. ScreenBlaster) */
-static int DontCalcRes = 0;
+static int DontCalcRes = 0;
#ifdef ATAFB_FALCON
#define HHT hw.falcon.hht
@@ -163,83 +183,84 @@ static int DontCalcRes = 0;
#define VMO_PREMASK 0x0c
#endif
-static struct fb_info fb_info;
+static struct fb_info fb_info = {
+ .fix = {
+ .id = "Atari ",
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .accel = FB_ACCEL_NONE,
+ }
+};
static void *screen_base; /* base address of screen */
static void *real_screen_base; /* (only for Overscan) */
static int screen_len;
-static int current_par_valid=0;
+static int current_par_valid;
-static int mono_moni=0;
-
-static struct display disp;
+static int mono_moni;
#ifdef ATAFB_EXT
-/* external video handling */
-static unsigned external_xres;
-static unsigned external_xres_virtual;
-static unsigned external_yres;
-/* not needed - atafb will never support panning/hardwarescroll with external
- * static unsigned external_yres_virtual;
-*/
+/* external video handling */
+static unsigned int external_xres;
+static unsigned int external_xres_virtual;
+static unsigned int external_yres;
-static unsigned external_depth;
-static int external_pmode;
-static void *external_addr = 0;
-static unsigned long external_len;
-static unsigned long external_vgaiobase = 0;
-static unsigned int external_bitspercol = 6;
-
-/*
-JOE <joe@amber.dinoco.de>:
-added card type for external driver, is only needed for
-colormap handling.
-*/
+/*
+ * not needed - atafb will never support panning/hardwarescroll with external
+ * static unsigned int external_yres_virtual;
+ */
+static unsigned int external_depth;
+static int external_pmode;
+static void *external_addr;
+static unsigned long external_len;
+static unsigned long external_vgaiobase;
+static unsigned int external_bitspercol = 6;
+/*
+ * JOE <joe@amber.dinoco.de>:
+ * added card type for external driver, is only needed for
+ * colormap handling.
+ */
enum cardtype { IS_VGA, IS_MV300 };
static enum cardtype external_card_type = IS_VGA;
/*
-The MV300 mixes the color registers. So we need an array of munged
-indices in order to access the correct reg.
-*/
-static int MV300_reg_1bit[2]={0,1};
-static int MV300_reg_4bit[16]={
-0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 };
-static int MV300_reg_8bit[256]={
-0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
-8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
-4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
-12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
-2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
-10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
-6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
-14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
-1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
-9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
-5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
-13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
-3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
-11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
-7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
-15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 };
+ * The MV300 mixes the color registers. So we need an array of munged
+ * indices in order to access the correct reg.
+ */
+static int MV300_reg_1bit[2] = {
+ 0, 1
+};
+static int MV300_reg_4bit[16] = {
+ 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
+};
+static int MV300_reg_8bit[256] = {
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
+};
static int *MV300_reg = MV300_reg_8bit;
-
-/*
-And on the MV300 it's difficult to read out the hardware palette. So we
-just keep track of the set colors in our own array here, and use that!
-*/
-
-static struct { unsigned char red,green,blue,pad; } ext_color[256];
#endif /* ATAFB_EXT */
-static int inverse=0;
+static int inverse;
extern int fontheight_8x8;
extern int fontwidth_8x8;
@@ -249,96 +270,154 @@ extern int fontheight_8x16;
extern int fontwidth_8x16;
extern unsigned char fontdata_8x16[];
+/*
+ * struct fb_ops {
+ * * open/release and usage marking
+ * struct module *owner;
+ * int (*fb_open)(struct fb_info *info, int user);
+ * int (*fb_release)(struct fb_info *info, int user);
+ *
+ * * For framebuffers with strange non linear layouts or that do not
+ * * work with normal memory mapped access
+ * ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
+ * ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
+ *
+ * * checks var and eventually tweaks it to something supported,
+ * * DOES NOT MODIFY PAR *
+ * int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
+ *
+ * * set the video mode according to info->var *
+ * int (*fb_set_par)(struct fb_info *info);
+ *
+ * * set color register *
+ * int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green,
+ * unsigned int blue, unsigned int transp, struct fb_info *info);
+ *
+ * * set color registers in batch *
+ * int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
+ *
+ * * blank display *
+ * int (*fb_blank)(int blank, struct fb_info *info);
+ *
+ * * pan display *
+ * int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
+ *
+ * *** The meat of the drawing engine ***
+ * * Draws a rectangle *
+ * void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
+ * * Copy data from area to another *
+ * void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
+ * * Draws a image to the display *
+ * void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
+ *
+ * * Draws cursor *
+ * int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
+ *
+ * * Rotates the display *
+ * void (*fb_rotate)(struct fb_info *info, int angle);
+ *
+ * * wait for blit idle, optional *
+ * int (*fb_sync)(struct fb_info *info);
+ *
+ * * perform fb specific ioctl (optional) *
+ * int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
+ * unsigned long arg);
+ *
+ * * Handle 32bit compat ioctl (optional) *
+ * int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd,
+ * unsigned long arg);
+ *
+ * * perform fb specific mmap *
+ * int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
+ *
+ * * save current hardware state *
+ * void (*fb_save_state)(struct fb_info *info);
+ *
+ * * restore saved state *
+ * void (*fb_restore_state)(struct fb_info *info);
+ * } ;
+ */
+
+
/* ++roman: This structure abstracts from the underlying hardware (ST(e),
* TT, or Falcon.
*
- * int (*detect)( void )
+ * int (*detect)(void)
* This function should detect the current video mode settings and
* store them in atafb_predefined[0] for later reference by the
* user. Return the index+1 of an equivalent predefined mode or 0
* if there is no such.
- *
- * int (*encode_fix)( struct fb_fix_screeninfo *fix,
- * struct atafb_par *par )
+ *
+ * int (*encode_fix)(struct fb_fix_screeninfo *fix,
+ * struct atafb_par *par)
* This function should fill in the 'fix' structure based on the
* values in the 'par' structure.
- *
- * int (*decode_var)( struct fb_var_screeninfo *var,
- * struct atafb_par *par )
+ * !!! Obsolete, perhaps !!!
+ *
+ * int (*decode_var)(struct fb_var_screeninfo *var,
+ * struct atafb_par *par)
* Get the video params out of 'var'. If a value doesn't fit, round
* it up, if it's too big, return EINVAL.
- * Round up in the following order: bits_per_pixel, xres, yres,
- * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
+ * Round up in the following order: bits_per_pixel, xres, yres,
+ * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
* horizontal timing, vertical timing.
*
- * int (*encode_var)( struct fb_var_screeninfo *var,
- * struct atafb_par *par );
+ * int (*encode_var)(struct fb_var_screeninfo *var,
+ * struct atafb_par *par);
* Fill the 'var' structure based on the values in 'par' and maybe
* other values read out of the hardware.
- *
- * void (*get_par)( struct atafb_par *par )
+ *
+ * void (*get_par)(struct atafb_par *par)
* Fill the hardware's 'par' structure.
- *
- * void (*set_par)( struct atafb_par *par )
+ * !!! Used only by detect() !!!
+ *
+ * void (*set_par)(struct atafb_par *par)
* Set the hardware according to 'par'.
- *
- * int (*getcolreg)( unsigned regno, unsigned *red,
- * unsigned *green, unsigned *blue,
- * unsigned *transp, struct fb_info *info )
- * Read a single color register and split it into
- * colors/transparent. Return != 0 for invalid regno.
*
* void (*set_screen_base)(void *s_base)
* Set the base address of the displayed frame buffer. Only called
* if yres_virtual > yres or xres_virtual > xres.
*
- * int (*blank)( int blank_mode )
- * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then
+ * int (*blank)(int blank_mode)
+ * Blank the screen if blank_mode != 0, else unblank. If blank == NULL then
* the caller blanks by setting the CLUT to all black. Return 0 if blanking
* succeeded, !=0 if un-/blanking failed due to e.g. a video mode which
* doesn't support it. Implements VESA suspend and powerdown modes on
* hardware that supports disabling hsync/vsync:
- * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown.
+ * blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown.
*/
static struct fb_hwswitch {
- int (*detect)( void );
- int (*encode_fix)( struct fb_fix_screeninfo *fix,
- struct atafb_par *par );
- int (*decode_var)( struct fb_var_screeninfo *var,
- struct atafb_par *par );
- int (*encode_var)( struct fb_var_screeninfo *var,
- struct atafb_par *par );
- void (*get_par)( struct atafb_par *par );
- void (*set_par)( struct atafb_par *par );
- int (*getcolreg)( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *info );
+ int (*detect)(void);
+ int (*encode_fix)(struct fb_fix_screeninfo *fix,
+ struct atafb_par *par);
+ int (*decode_var)(struct fb_var_screeninfo *var,
+ struct atafb_par *par);
+ int (*encode_var)(struct fb_var_screeninfo *var,
+ struct atafb_par *par);
+ void (*get_par)(struct atafb_par *par);
+ void (*set_par)(struct atafb_par *par);
void (*set_screen_base)(void *s_base);
- int (*blank)( int blank_mode );
- int (*pan_display)( struct fb_var_screeninfo *var,
- struct atafb_par *par);
+ int (*blank)(int blank_mode);
+ int (*pan_display)(struct fb_var_screeninfo *var,
+ struct fb_info *info);
} *fbhw;
-static char *autodetect_names[] = {"autodetect", NULL};
-static char *stlow_names[] = {"stlow", NULL};
-static char *stmid_names[] = {"stmid", "default5", NULL};
-static char *sthigh_names[] = {"sthigh", "default4", NULL};
-static char *ttlow_names[] = {"ttlow", NULL};
-static char *ttmid_names[]= {"ttmid", "default1", NULL};
-static char *tthigh_names[]= {"tthigh", "default2", NULL};
-static char *vga2_names[] = {"vga2", NULL};
-static char *vga4_names[] = {"vga4", NULL};
-static char *vga16_names[] = {"vga16", "default3", NULL};
-static char *vga256_names[] = {"vga256", NULL};
-static char *falh2_names[] = {"falh2", NULL};
-static char *falh16_names[] = {"falh16", NULL};
+static char *autodetect_names[] = { "autodetect", NULL };
+static char *stlow_names[] = { "stlow", NULL };
+static char *stmid_names[] = { "stmid", "default5", NULL };
+static char *sthigh_names[] = { "sthigh", "default4", NULL };
+static char *ttlow_names[] = { "ttlow", NULL };
+static char *ttmid_names[] = { "ttmid", "default1", NULL };
+static char *tthigh_names[] = { "tthigh", "default2", NULL };
+static char *vga2_names[] = { "vga2", NULL };
+static char *vga4_names[] = { "vga4", NULL };
+static char *vga16_names[] = { "vga16", "default3", NULL };
+static char *vga256_names[] = { "vga256", NULL };
+static char *falh2_names[] = { "falh2", NULL };
+static char *falh16_names[] = { "falh16", NULL };
static char **fb_var_names[] = {
- /* Writing the name arrays directly in this array (via "(char *[]){...}")
- * crashes gcc 2.5.8 (sigsegv) if the inner array
- * contains more than two items. I've also seen that all elements
- * were identical to the last (my cross-gcc) :-(*/
autodetect_names,
stlow_names,
stmid_names,
@@ -353,18 +432,17 @@ static char **fb_var_names[] = {
falh2_names,
falh16_names,
NULL
- /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */
};
static struct fb_var_screeninfo atafb_predefined[] = {
- /*
- * yres_virtual==0 means use hw-scrolling if possible, else yres
- */
- { /* autodetect */
- 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
- {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
+ /*
+ * yres_virtual == 0 means use hw-scrolling if possible, else yres
+ */
+ { /* autodetect */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */
+ {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/
0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
- { /* st low */
+ { /* st low */
320, 200, 320, 0, 0, 0, 4, 0,
{0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0},
0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
@@ -414,27 +492,100 @@ static struct fb_var_screeninfo atafb_predefined[] = {
0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 },
};
-static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined);
+static int num_atafb_predefined = ARRAY_SIZE(atafb_predefined);
+static struct fb_videomode atafb_modedb[] __initdata = {
+ /*
+ * Atari Video Modes
+ *
+ * If you change these, make sure to update DEFMODE_* as well!
+ */
-static int
-get_video_mode(char *vname)
+ /*
+ * ST/TT Video Modes
+ */
+
+ {
+ /* 320x200, 15 kHz, 60 Hz (ST low) */
+ "st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }, {
+ /* 640x200, 15 kHz, 60 Hz (ST medium) */
+ "st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }, {
+ /* 640x400, 30.25 kHz, 63.5 Hz (ST high) */
+ "st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }, {
+ /* 320x480, 15 kHz, 60 Hz (TT low) */
+ "tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }, {
+ /* 640x480, 29 kHz, 57 Hz (TT medium) */
+ "tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }, {
+ /* 1280x960, 29 kHz, 60 Hz (TT high) */
+ "tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ },
+
+ /*
+ * VGA Video Modes
+ */
+
+ {
+ /* 640x480, 31 kHz, 60 Hz (VGA) */
+ "vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ }, {
+ /* 640x400, 31 kHz, 70 Hz (VGA) */
+ "vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3,
+ FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ },
+
+ /*
+ * Falcon HiRes Video Modes
+ */
+
+ {
+ /* 896x608, 31 kHz, 60 Hz (Falcon High) */
+ "falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3,
+ 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP
+ },
+};
+
+#define NUM_TOTAL_MODES ARRAY_SIZE(atafb_modedb)
+
+static char *mode_option __initdata = NULL;
+
+ /* default modes */
+
+#define DEFMODE_TT 5 /* "tt-high" for TT */
+#define DEFMODE_F30 7 /* "vga70" for Falcon */
+#define DEFMODE_STE 2 /* "st-high" for ST/E */
+#define DEFMODE_EXT 6 /* "vga" for external */
+
+
+static int get_video_mode(char *vname)
{
- char ***name_list;
- char **name;
- int i;
- name_list=fb_var_names;
- for (i = 0 ; i < num_atafb_predefined ; i++) {
- name=*(name_list++);
- if (! name || ! *name)
- break;
- while (*name) {
- if (! strcmp(vname, *name))
- return i+1;
- name++;
+ char ***name_list;
+ char **name;
+ int i;
+
+ name_list = fb_var_names;
+ for (i = 0; i < num_atafb_predefined; i++) {
+ name = *name_list++;
+ if (!name || !*name)
+ break;
+ while (*name) {
+ if (!strcmp(vname, *name))
+ return i + 1;
+ name++;
+ }
}
- }
- return 0;
+ return 0;
}
@@ -443,93 +594,84 @@ get_video_mode(char *vname)
#ifdef ATAFB_TT
-static int tt_encode_fix( struct fb_fix_screeninfo *fix,
- struct atafb_par *par )
-
+static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
{
int mode;
- strcpy(fix->id,"Atari Builtin");
+ strcpy(fix->id, "Atari Builtin");
fix->smem_start = (unsigned long)real_screen_base;
fix->smem_len = screen_len;
- fix->type=FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux=2;
- fix->visual=FB_VISUAL_PSEUDOCOLOR;
+ fix->type = FB_TYPE_INTERLEAVED_PLANES;
+ fix->type_aux = 2;
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK;
if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) {
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->type_aux=0;
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
if (mode == TT_SHIFTER_TTHIGH)
- fix->visual=FB_VISUAL_MONO01;
+ fix->visual = FB_VISUAL_MONO01;
}
- fix->xpanstep=0;
- fix->ypanstep=1;
- fix->ywrapstep=0;
+ fix->xpanstep = 0;
+ fix->ypanstep = 1;
+ fix->ywrapstep = 0;
fix->line_length = 0;
fix->accel = FB_ACCEL_ATARIBLITT;
return 0;
}
-
-static int tt_decode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
{
- int xres=var->xres;
- int yres=var->yres;
- int bpp=var->bits_per_pixel;
+ int xres = var->xres;
+ int yres = var->yres;
+ int bpp = var->bits_per_pixel;
int linelen;
int yres_virtual = var->yres_virtual;
if (mono_moni) {
- if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2)
+ if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2)
return -EINVAL;
- par->hw.tt.mode=TT_SHIFTER_TTHIGH;
- xres=sttt_xres*2;
- yres=tt_yres*2;
- bpp=1;
+ par->hw.tt.mode = TT_SHIFTER_TTHIGH;
+ xres = sttt_xres * 2;
+ yres = tt_yres * 2;
+ bpp = 1;
} else {
if (bpp > 8 || xres > sttt_xres || yres > tt_yres)
return -EINVAL;
if (bpp > 4) {
- if (xres > sttt_xres/2 || yres > tt_yres)
+ if (xres > sttt_xres / 2 || yres > tt_yres)
return -EINVAL;
- par->hw.tt.mode=TT_SHIFTER_TTLOW;
- xres=sttt_xres/2;
- yres=tt_yres;
- bpp=8;
- }
- else if (bpp > 2) {
+ par->hw.tt.mode = TT_SHIFTER_TTLOW;
+ xres = sttt_xres / 2;
+ yres = tt_yres;
+ bpp = 8;
+ } else if (bpp > 2) {
if (xres > sttt_xres || yres > tt_yres)
return -EINVAL;
- if (xres > sttt_xres/2 || yres > st_yres/2) {
- par->hw.tt.mode=TT_SHIFTER_TTMID;
- xres=sttt_xres;
- yres=tt_yres;
- bpp=4;
- }
- else {
- par->hw.tt.mode=TT_SHIFTER_STLOW;
- xres=sttt_xres/2;
- yres=st_yres/2;
- bpp=4;
+ if (xres > sttt_xres / 2 || yres > st_yres / 2) {
+ par->hw.tt.mode = TT_SHIFTER_TTMID;
+ xres = sttt_xres;
+ yres = tt_yres;
+ bpp = 4;
+ } else {
+ par->hw.tt.mode = TT_SHIFTER_STLOW;
+ xres = sttt_xres / 2;
+ yres = st_yres / 2;
+ bpp = 4;
}
- }
- else if (bpp > 1) {
- if (xres > sttt_xres || yres > st_yres/2)
+ } else if (bpp > 1) {
+ if (xres > sttt_xres || yres > st_yres / 2)
return -EINVAL;
- par->hw.tt.mode=TT_SHIFTER_STMID;
- xres=sttt_xres;
- yres=st_yres/2;
- bpp=2;
- }
- else if (var->xres > sttt_xres || var->yres > st_yres) {
+ par->hw.tt.mode = TT_SHIFTER_STMID;
+ xres = sttt_xres;
+ yres = st_yres / 2;
+ bpp = 2;
+ } else if (var->xres > sttt_xres || var->yres > st_yres) {
return -EINVAL;
- }
- else {
- par->hw.tt.mode=TT_SHIFTER_STHIGH;
- xres=sttt_xres;
- yres=st_yres;
- bpp=1;
+ } else {
+ par->hw.tt.mode = TT_SHIFTER_STHIGH;
+ xres = sttt_xres;
+ yres = st_yres;
+ bpp = 1;
}
}
if (yres_virtual <= 0)
@@ -537,10 +679,10 @@ static int tt_decode_var( struct fb_var_screeninfo *var,
else if (yres_virtual < yres)
yres_virtual = yres;
if (var->sync & FB_SYNC_EXT)
- par->hw.tt.sync=0;
+ par->hw.tt.sync = 0;
else
- par->hw.tt.sync=1;
- linelen=xres*bpp/8;
+ par->hw.tt.sync = 1;
+ linelen = xres * bpp / 8;
if (yres_virtual * linelen > screen_len && screen_len)
return -EINVAL;
if (yres * linelen > screen_len && screen_len)
@@ -552,154 +694,123 @@ static int tt_decode_var( struct fb_var_screeninfo *var,
return 0;
}
-static int tt_encode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
{
int linelen;
memset(var, 0, sizeof(struct fb_var_screeninfo));
- var->red.offset=0;
- var->red.length=4;
- var->red.msb_right=0;
- var->grayscale=0;
-
- var->pixclock=31041;
- var->left_margin=120; /* these may be incorrect */
- var->right_margin=100;
- var->upper_margin=8;
- var->lower_margin=16;
- var->hsync_len=140;
- var->vsync_len=30;
-
- var->height=-1;
- var->width=-1;
+ var->red.offset = 0;
+ var->red.length = 4;
+ var->red.msb_right = 0;
+ var->grayscale = 0;
+
+ var->pixclock = 31041;
+ var->left_margin = 120; /* these may be incorrect */
+ var->right_margin = 100;
+ var->upper_margin = 8;
+ var->lower_margin = 16;
+ var->hsync_len = 140;
+ var->vsync_len = 30;
+
+ var->height = -1;
+ var->width = -1;
if (par->hw.tt.sync & 1)
- var->sync=0;
+ var->sync = 0;
else
- var->sync=FB_SYNC_EXT;
+ var->sync = FB_SYNC_EXT;
switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) {
case TT_SHIFTER_STLOW:
- var->xres=sttt_xres/2;
- var->xres_virtual=sttt_xres_virtual/2;
- var->yres=st_yres/2;
- var->bits_per_pixel=4;
+ var->xres = sttt_xres / 2;
+ var->xres_virtual = sttt_xres_virtual / 2;
+ var->yres = st_yres / 2;
+ var->bits_per_pixel = 4;
break;
case TT_SHIFTER_STMID:
- var->xres=sttt_xres;
- var->xres_virtual=sttt_xres_virtual;
- var->yres=st_yres/2;
- var->bits_per_pixel=2;
+ var->xres = sttt_xres;
+ var->xres_virtual = sttt_xres_virtual;
+ var->yres = st_yres / 2;
+ var->bits_per_pixel = 2;
break;
case TT_SHIFTER_STHIGH:
- var->xres=sttt_xres;
- var->xres_virtual=sttt_xres_virtual;
- var->yres=st_yres;
- var->bits_per_pixel=1;
+ var->xres = sttt_xres;
+ var->xres_virtual = sttt_xres_virtual;
+ var->yres = st_yres;
+ var->bits_per_pixel = 1;
break;
case TT_SHIFTER_TTLOW:
- var->xres=sttt_xres/2;
- var->xres_virtual=sttt_xres_virtual/2;
- var->yres=tt_yres;
- var->bits_per_pixel=8;
+ var->xres = sttt_xres / 2;
+ var->xres_virtual = sttt_xres_virtual / 2;
+ var->yres = tt_yres;
+ var->bits_per_pixel = 8;
break;
case TT_SHIFTER_TTMID:
- var->xres=sttt_xres;
- var->xres_virtual=sttt_xres_virtual;
- var->yres=tt_yres;
- var->bits_per_pixel=4;
+ var->xres = sttt_xres;
+ var->xres_virtual = sttt_xres_virtual;
+ var->yres = tt_yres;
+ var->bits_per_pixel = 4;
break;
case TT_SHIFTER_TTHIGH:
- var->red.length=0;
- var->xres=sttt_xres*2;
- var->xres_virtual=sttt_xres_virtual*2;
- var->yres=tt_yres*2;
- var->bits_per_pixel=1;
+ var->red.length = 0;
+ var->xres = sttt_xres * 2;
+ var->xres_virtual = sttt_xres_virtual * 2;
+ var->yres = tt_yres * 2;
+ var->bits_per_pixel = 1;
break;
- }
- var->blue=var->green=var->red;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- linelen=var->xres_virtual * var->bits_per_pixel / 8;
- if (! use_hwscroll)
- var->yres_virtual=var->yres;
+ }
+ var->blue = var->green = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ linelen = var->xres_virtual * var->bits_per_pixel / 8;
+ if (!use_hwscroll)
+ var->yres_virtual = var->yres;
else if (screen_len) {
if (par->yres_virtual)
var->yres_virtual = par->yres_virtual;
else
- /* yres_virtual==0 means use maximum */
+ /* yres_virtual == 0 means use maximum */
var->yres_virtual = screen_len / linelen;
} else {
if (hwscroll < 0)
var->yres_virtual = 2 * var->yres;
else
- var->yres_virtual=var->yres+hwscroll * 16;
+ var->yres_virtual = var->yres + hwscroll * 16;
}
- var->xoffset=0;
+ var->xoffset = 0;
if (screen_base)
- var->yoffset=(par->screen_base - screen_base)/linelen;
+ var->yoffset = (par->screen_base - screen_base) / linelen;
else
- var->yoffset=0;
- var->nonstd=0;
- var->activate=0;
- var->vmode=FB_VMODE_NONINTERLACED;
+ var->yoffset = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
return 0;
}
-
-static void tt_get_par( struct atafb_par *par )
+static void tt_get_par(struct atafb_par *par)
{
unsigned long addr;
- par->hw.tt.mode=shifter_tt.tt_shiftmode;
- par->hw.tt.sync=shifter.syncmode;
+ par->hw.tt.mode = shifter_tt.tt_shiftmode;
+ par->hw.tt.sync = shifter.syncmode;
addr = ((shifter.bas_hi & 0xff) << 16) |
((shifter.bas_md & 0xff) << 8) |
((shifter.bas_lo & 0xff));
par->screen_base = phys_to_virt(addr);
}
-static void tt_set_par( struct atafb_par *par )
+static void tt_set_par(struct atafb_par *par)
{
- shifter_tt.tt_shiftmode=par->hw.tt.mode;
- shifter.syncmode=par->hw.tt.sync;
+ shifter_tt.tt_shiftmode = par->hw.tt.mode;
+ shifter.syncmode = par->hw.tt.sync;
/* only set screen_base if really necessary */
if (current_par.screen_base != par->screen_base)
fbhw->set_screen_base(par->screen_base);
}
-
-static int tt_getcolreg(unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *info)
-{
- int t, col;
-
- if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
- regno += 254;
- if (regno > 255)
- return 1;
- t = tt_palette[regno];
- col = t & 15;
- col |= col << 4;
- col |= col << 8;
- *blue = col;
- col = (t >> 4) & 15;
- col |= col << 4;
- col |= col << 8;
- *green = col;
- col = (t >> 8) & 15;
- col |= col << 4;
- col |= col << 8;
- *red = col;
- *transp = 0;
- return 0;
-}
-
-
-static int tt_setcolreg(unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp, struct fb_info *info)
+static int tt_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
{
if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH)
regno += 254;
@@ -708,15 +819,14 @@ static int tt_setcolreg(unsigned regno, unsigned red,
tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) |
(blue >> 12));
if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) ==
- TT_SHIFTER_STHIGH && regno == 254)
+ TT_SHIFTER_STHIGH && regno == 254)
tt_palette[0] = 0;
return 0;
}
-
-static int tt_detect( void )
-
-{ struct atafb_par par;
+static int tt_detect(void)
+{
+ struct atafb_par par;
/* Determine the connected monitor: The DMA sound must be
* disabled before reading the MFP GPIP, because the Sound
@@ -726,9 +836,9 @@ static int tt_detect( void )
* announced that the Eagle is TT compatible, but only the PCM is
* missing...
*/
- if (ATARIHW_PRESENT(PCM_8BIT)) {
+ if (ATARIHW_PRESENT(PCM_8BIT)) {
tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- udelay(20); /* wait a while for things to settle down */
+ udelay(20); /* wait a while for things to settle down */
}
mono_moni = (mfp.par_dt_reg & 0x80) == 0;
@@ -755,19 +865,24 @@ static struct pixel_clock {
unsigned long f; /* f/[Hz] */
unsigned long t; /* t/[ps] (=1/f) */
int right, hsync, left; /* standard timing in clock cycles, not pixel */
- /* hsync initialized in falcon_detect() */
+ /* hsync initialized in falcon_detect() */
int sync_mask; /* or-mask for hw.falcon.sync to set this clock */
int control_mask; /* ditto, for hw.falcon.vid_control */
-}
-f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25},
-f32 = {32000000, 31250, 18, 0, 42, 0x0, 0},
-fext = { 0, 0, 18, 0, 42, 0x1, 0};
+} f25 = {
+ 25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25
+}, f32 = {
+ 32000000, 31250, 18, 0, 42, 0x0, 0
+}, fext = {
+ 0, 0, 18, 0, 42, 0x1, 0
+};
/* VIDEL-prescale values [mon_type][pixel_length from VCO] */
-static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}};
+static int vdl_prescale[4][3] = {
+ { 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 }
+};
/* Default hsync timing [mon_type] in picoseconds */
-static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000};
+static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 };
#ifdef FBCON_HAS_CFB16
static u16 fbcon_cfb16_cmap[16];
@@ -775,12 +890,12 @@ static u16 fbcon_cfb16_cmap[16];
static inline int hxx_prescale(struct falcon_hw *hw)
{
- return hw->ste_mode ? 16 :
- vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
+ return hw->ste_mode ? 16
+ : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3];
}
-static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
- struct atafb_par *par )
+static int falcon_encode_fix(struct fb_fix_screeninfo *fix,
+ struct atafb_par *par)
{
strcpy(fix->id, "Atari Builtin");
fix->smem_start = (unsigned long)real_screen_base;
@@ -796,8 +911,7 @@ static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
fix->type_aux = 0;
/* no smooth scrolling with longword aligned video mem */
fix->xpanstep = 32;
- }
- else if (par->hw.falcon.f_shift & 0x100) {
+ } else if (par->hw.falcon.f_shift & 0x100) {
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
/* Is this ok or should it be DIRECTCOLOR? */
@@ -809,9 +923,8 @@ static int falcon_encode_fix( struct fb_fix_screeninfo *fix,
return 0;
}
-
-static int falcon_decode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int falcon_decode_var(struct fb_var_screeninfo *var,
+ struct atafb_par *par)
{
int bpp = var->bits_per_pixel;
int xres = var->xres;
@@ -823,17 +936,19 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
int linelen;
int interlace = 0, doubleline = 0;
struct pixel_clock *pclock;
- int plen; /* width of pixel in clock cycles */
+ int plen; /* width of pixel in clock cycles */
int xstretch;
int prescale;
int longoffset = 0;
int hfreq, vfreq;
+ int hdb_off, hde_off, base_off;
+ int gstart, gend1, gend2, align;
/*
Get the video params out of 'var'. If a value doesn't fit, round
it up, if it's too big, return EINVAL.
- Round up in the following order: bits_per_pixel, xres, yres,
- xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
+ Round up in the following order: bits_per_pixel, xres, yres,
+ xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields,
horizontal timing, vertical timing.
There is a maximum of screen resolution determined by pixelclock
@@ -843,11 +958,11 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
Frequency range for multisync monitors is given via command line.
For TV and SM124 both frequencies are fixed.
- X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0)
+ X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0)
Y % 16 == 0 to fit 8x16 font
Y % 8 == 0 if Y<400
- Currently interlace and doubleline mode in var are ignored.
+ Currently interlace and doubleline mode in var are ignored.
On SM124 and TV only the standard resolutions can be used.
*/
@@ -855,43 +970,38 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
if (!xres || !yres || !bpp)
return -EINVAL;
- if (mon_type == F_MON_SM && bpp != 1) {
+ if (mon_type == F_MON_SM && bpp != 1)
return -EINVAL;
- }
- else if (bpp <= 1) {
+
+ if (bpp <= 1) {
bpp = 1;
par->hw.falcon.f_shift = 0x400;
par->hw.falcon.st_shift = 0x200;
- }
- else if (bpp <= 2) {
+ } else if (bpp <= 2) {
bpp = 2;
par->hw.falcon.f_shift = 0x000;
par->hw.falcon.st_shift = 0x100;
- }
- else if (bpp <= 4) {
+ } else if (bpp <= 4) {
bpp = 4;
par->hw.falcon.f_shift = 0x000;
par->hw.falcon.st_shift = 0x000;
- }
- else if (bpp <= 8) {
+ } else if (bpp <= 8) {
bpp = 8;
par->hw.falcon.f_shift = 0x010;
- }
- else if (bpp <= 16) {
- bpp = 16; /* packed pixel mode */
- par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
- }
- else
+ } else if (bpp <= 16) {
+ bpp = 16; /* packed pixel mode */
+ par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */
+ } else
return -EINVAL;
par->hw.falcon.bpp = bpp;
if (mon_type == F_MON_SM || DontCalcRes) {
/* Skip all calculations. VGA/TV/SC1224 only supported. */
struct fb_var_screeninfo *myvar = &atafb_predefined[0];
-
+
if (bpp > myvar->bits_per_pixel ||
- var->xres > myvar->xres ||
- var->yres > myvar->yres)
+ var->xres > myvar->xres ||
+ var->yres > myvar->yres)
return -EINVAL;
fbhw->get_par(par); /* Current par will be new par */
goto set_screen_base; /* Don't forget this */
@@ -910,8 +1020,8 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
yres = 400;
/* 2 planes must use STE compatibility mode */
- par->hw.falcon.ste_mode = bpp==2;
- par->hw.falcon.mono = bpp==1;
+ par->hw.falcon.ste_mode = bpp == 2;
+ par->hw.falcon.mono = bpp == 1;
/* Total and visible scanline length must be a multiple of one longword,
* this and the console fontwidth yields the alignment for xres and
@@ -967,8 +1077,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
left_margin = hsync_len = 128 / plen;
right_margin = 0;
/* TODO set all margins */
- }
- else
+ } else
#endif
if (mon_type == F_MON_SC || mon_type == F_MON_TV) {
plen = 2 * xstretch;
@@ -1002,26 +1111,24 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
vsync_len *= 2;
}
}
- }
- else
- { /* F_MON_VGA */
+ } else { /* F_MON_VGA */
if (bpp == 16)
- xstretch = 2; /* Double pixel width only for hicolor */
+ xstretch = 2; /* Double pixel width only for hicolor */
/* Default values are used for vert./hor. timing if no pixelclock given. */
if (var->pixclock == 0) {
int linesize;
/* Choose master pixelclock depending on hor. timing */
plen = 1 * xstretch;
- if ((plen * xres + f25.right+f25.hsync+f25.left) *
+ if ((plen * xres + f25.right + f25.hsync + f25.left) *
fb_info.monspecs.hfmin < f25.f)
pclock = &f25;
- else if ((plen * xres + f32.right+f32.hsync+f32.left) *
- fb_info.monspecs.hfmin < f32.f)
+ else if ((plen * xres + f32.right + f32.hsync +
+ f32.left) * fb_info.monspecs.hfmin < f32.f)
pclock = &f32;
- else if ((plen * xres + fext.right+fext.hsync+fext.left) *
- fb_info.monspecs.hfmin < fext.f
- && fext.f)
+ else if ((plen * xres + fext.right + fext.hsync +
+ fext.left) * fb_info.monspecs.hfmin < fext.f &&
+ fext.f)
pclock = &fext;
else
return -EINVAL;
@@ -1033,22 +1140,24 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
upper_margin = 31;
lower_margin = 11;
vsync_len = 3;
- }
- else {
+ } else {
/* Choose largest pixelclock <= wanted clock */
int i;
unsigned long pcl = ULONG_MAX;
pclock = 0;
- for (i=1; i <= 4; i *= 2) {
- if (f25.t*i >= var->pixclock && f25.t*i < pcl) {
+ for (i = 1; i <= 4; i *= 2) {
+ if (f25.t * i >= var->pixclock &&
+ f25.t * i < pcl) {
pcl = f25.t * i;
pclock = &f25;
}
- if (f32.t*i >= var->pixclock && f32.t*i < pcl) {
+ if (f32.t * i >= var->pixclock &&
+ f32.t * i < pcl) {
pcl = f32.t * i;
pclock = &f32;
}
- if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) {
+ if (fext.t && fext.t * i >= var->pixclock &&
+ fext.t * i < pcl) {
pcl = fext.t * i;
pclock = &fext;
}
@@ -1070,8 +1179,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
upper_margin = (upper_margin + 1) / 2;
lower_margin = (lower_margin + 1) / 2;
vsync_len = (vsync_len + 1) / 2;
- }
- else if (var->vmode & FB_VMODE_DOUBLE) {
+ } else if (var->vmode & FB_VMODE_DOUBLE) {
/* External unit is [double lines per frame] */
upper_margin *= 2;
lower_margin *= 2;
@@ -1079,7 +1187,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
}
}
if (pclock == &fext)
- longoffset = 1; /* VIDEL doesn't synchronize on short offset */
+ longoffset = 1; /* VIDEL doesn't synchronize on short offset */
}
/* Is video bus bandwidth (32MB/s) too low for this resolution? */
/* this is definitely wrong if bus clock != 32MHz */
@@ -1098,7 +1206,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
* between interlace and non-interlace without messing around
* with these.
*/
- again:
+again:
/* Set base_offset 128 and video bus width */
par->hw.falcon.vid_control = mon_type | f030_bus_width;
if (!longoffset)
@@ -1112,37 +1220,34 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
/* External or internal clock */
par->hw.falcon.sync = pclock->sync_mask | 0x2;
/* Pixellength and prescale */
- par->hw.falcon.vid_mode = (2/plen) << 2;
+ par->hw.falcon.vid_mode = (2 / plen) << 2;
if (doubleline)
par->hw.falcon.vid_mode |= VMO_DOUBLE;
if (interlace)
par->hw.falcon.vid_mode |= VMO_INTER;
/*********************
- Horizontal timing: unit = [master clock cycles]
- unit of hxx-registers: [master clock cycles * prescale]
- Hxx-registers are 9 bit wide
-
- 1 line = ((hht + 2) * 2 * prescale) clock cycles
-
- graphic output = hdb & 0x200 ?
- ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff:
- ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
- (this must be a multiple of plen*128/bpp, on VGA pixels
- to the right may be cut off with a bigger right margin)
-
- start of graphics relative to start of 1st halfline = hdb & 0x200 ?
- (hdb - hht - 2) * prescale + hdboff :
- hdb * prescale + hdboff
-
- end of graphics relative to start of 1st halfline =
- (hde + hht + 2) * prescale + hdeoff
- *********************/
+ * Horizontal timing: unit = [master clock cycles]
+ * unit of hxx-registers: [master clock cycles * prescale]
+ * Hxx-registers are 9 bit wide
+ *
+ * 1 line = ((hht + 2) * 2 * prescale) clock cycles
+ *
+ * graphic output = hdb & 0x200 ?
+ * ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff:
+ * (hht + 2 - hdb + hde) * prescale - hdboff + hdeoff
+ * (this must be a multiple of plen*128/bpp, on VGA pixels
+ * to the right may be cut off with a bigger right margin)
+ *
+ * start of graphics relative to start of 1st halfline = hdb & 0x200 ?
+ * (hdb - hht - 2) * prescale + hdboff :
+ * hdb * prescale + hdboff
+ *
+ * end of graphics relative to start of 1st halfline =
+ * (hde + hht + 2) * prescale + hdeoff
+ *********************/
/* Calculate VIDEL registers */
- {
- int hdb_off, hde_off, base_off;
- int gstart, gend1, gend2, align;
-
+{
prescale = hxx_prescale(&par->hw.falcon);
base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128;
@@ -1154,8 +1259,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
align = 1;
hde_off = 0;
hdb_off = (base_off + 16 * plen) + prescale;
- }
- else {
+ } else {
align = 128 / bpp;
hde_off = ((128 / bpp + 2) * plen);
if (par->hw.falcon.ste_mode)
@@ -1164,23 +1268,24 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale;
}
- gstart = (prescale/2 + plen * left_margin) / prescale;
+ gstart = (prescale / 2 + plen * left_margin) / prescale;
/* gend1 is for hde (gend-gstart multiple of align), shifter's xres */
- gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale;
+ gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale;
/* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */
gend2 = gstart + xres * plen / prescale;
par->HHT = plen * (left_margin + xres + right_margin) /
(2 * prescale) - 2;
/* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/
- par->HDB = gstart - hdb_off/prescale;
+ par->HDB = gstart - hdb_off / prescale;
par->HBE = gstart;
- if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200;
- par->HDE = gend1 - par->HHT - 2 - hde_off/prescale;
+ if (par->HDB < 0)
+ par->HDB += par->HHT + 2 + 0x200;
+ par->HDE = gend1 - par->HHT - 2 - hde_off / prescale;
par->HBB = gend2 - par->HHT - 2;
#if 0
/* One more Videl constraint: data fetch of two lines must not overlap */
- if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
+ if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) {
/* if this happens increase margins, decrease hfreq. */
}
#endif
@@ -1189,11 +1294,11 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
par->HSS = par->HHT + 2 - plen * hsync_len / prescale;
if (par->HSS < par->HBB)
par->HSS = par->HBB;
- }
+}
/* check hor. frequency */
- hfreq = pclock->f / ((par->HHT+2)*prescale*2);
- if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) {
+ hfreq = pclock->f / ((par->HHT + 2) * prescale * 2);
+ if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) {
/* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */
/* Too high -> enlarge margin */
left_margin += 1;
@@ -1213,12 +1318,14 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */
par->VDB = par->VBE;
par->VDE = yres;
- if (!interlace) par->VDE <<= 1;
- if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */
+ if (!interlace)
+ par->VDE <<= 1;
+ if (doubleline)
+ par->VDE <<= 1; /* VDE now half lines per (half-)frame */
par->VDE += par->VDB;
par->VBB = par->VDE;
par->VFT = par->VBB + (lower_margin * 2 - 1) - 1;
- par->VSS = par->VFT+1 - (vsync_len * 2 - 1);
+ par->VSS = par->VFT + 1 - (vsync_len * 2 - 1);
/* vbb,vss,vft must be even in interlace mode */
if (interlace) {
par->VBB++;
@@ -1229,55 +1336,53 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
/* V-frequency check, hope I didn't create any loop here. */
/* Interlace and doubleline are mutually exclusive. */
vfreq = (hfreq * 2) / (par->VFT + 1);
- if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
+ if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) {
/* Too high -> try again with doubleline */
doubleline = 1;
goto again;
- }
- else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
+ } else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) {
/* Too low -> try again with interlace */
interlace = 1;
goto again;
- }
- else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
+ } else if (vfreq < fb_info.monspecs.vfmin && doubleline) {
/* Doubleline too low -> clear doubleline and enlarge margins */
int lines;
doubleline = 0;
- for (lines=0;
- (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax;
+ for (lines = 0;
+ (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) >
+ fb_info.monspecs.vfmax;
lines++)
;
upper_margin += lines;
lower_margin += lines;
goto again;
- }
- else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
+ } else if (vfreq > fb_info.monspecs.vfmax && doubleline) {
/* Doubleline too high -> enlarge margins */
int lines;
- for (lines=0;
- (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
- lines+=2)
+ for (lines = 0;
+ (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
+ fb_info.monspecs.vfmax;
+ lines += 2)
;
upper_margin += lines;
lower_margin += lines;
goto again;
- }
- else if (vfreq > fb_info.monspecs.vfmax && interlace) {
+ } else if (vfreq > fb_info.monspecs.vfmax && interlace) {
/* Interlace, too high -> enlarge margins */
int lines;
- for (lines=0;
- (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax;
+ for (lines = 0;
+ (hfreq * 2) / (par->VFT + 1 + 4 * lines) >
+ fb_info.monspecs.vfmax;
lines++)
;
upper_margin += lines;
lower_margin += lines;
goto again;
- }
- else if (vfreq < fb_info.monspecs.vfmin ||
- vfreq > fb_info.monspecs.vfmax)
+ } else if (vfreq < fb_info.monspecs.vfmin ||
+ vfreq > fb_info.monspecs.vfmax)
return -EINVAL;
- set_screen_base:
+set_screen_base:
linelen = xres_virtual * bpp / 8;
if (yres_virtual * linelen > screen_len && screen_len)
return -EINVAL;
@@ -1289,11 +1394,20 @@ static int falcon_decode_var( struct fb_var_screeninfo *var,
par->screen_base = screen_base + var->yoffset * linelen;
par->hw.falcon.xoffset = 0;
+ // FIXME!!! sort of works, no crash
+ //par->next_line = linelen;
+ //par->next_plane = yres_virtual * linelen;
+ par->next_line = linelen;
+ par->next_plane = 2;
+ // crashes
+ //par->next_plane = linelen;
+ //par->next_line = yres_virtual * linelen;
+
return 0;
}
-static int falcon_encode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int falcon_encode_var(struct fb_var_screeninfo *var,
+ struct atafb_par *par)
{
/* !!! only for VGA !!! */
int linelen;
@@ -1306,10 +1420,10 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->pixclock = hw->sync & 0x1 ? fext.t :
hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t;
- var->height=-1;
- var->width=-1;
+ var->height = -1;
+ var->width = -1;
- var->sync=0;
+ var->sync = 0;
if (hw->vid_control & VCO_HSYPOS)
var->sync |= FB_SYNC_HOR_HIGH_ACT;
if (hw->vid_control & VCO_VSYPOS)
@@ -1320,7 +1434,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->vmode |= FB_VMODE_INTERLACED;
if (hw->vid_mode & VMO_DOUBLE)
var->vmode |= FB_VMODE_DOUBLE;
-
+
/* visible y resolution:
* Graphics display starts at line VDB and ends at line
* VDE. If interlace mode off unit of VC-registers is
@@ -1332,14 +1446,15 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
if (var->vmode & FB_VMODE_DOUBLE)
var->yres >>= 1;
- /* to get bpp, we must examine f_shift and st_shift.
+ /*
+ * to get bpp, we must examine f_shift and st_shift.
* f_shift is valid if any of bits no. 10, 8 or 4
* is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e.
* if bit 10 set then bit 8 and bit 4 don't care...
* If all these bits are 0 get display depth from st_shift
* (as for ST and STE)
*/
- if (hw->f_shift & 0x400) /* 2 colors */
+ if (hw->f_shift & 0x400) /* 2 colors */
var->bits_per_pixel = 1;
else if (hw->f_shift & 0x100) /* hicolor */
var->bits_per_pixel = 16;
@@ -1349,7 +1464,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->bits_per_pixel = 4;
else if (hw->st_shift == 0x100)
var->bits_per_pixel = 2;
- else /* if (hw->st_shift == 0x200) */
+ else /* if (hw->st_shift == 0x200) */
var->bits_per_pixel = 1;
var->xres = hw->line_width * 16 / var->bits_per_pixel;
@@ -1358,42 +1473,42 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->xres_virtual += 16;
if (var->bits_per_pixel == 16) {
- var->red.offset=11;
- var->red.length=5;
- var->red.msb_right=0;
- var->green.offset=5;
- var->green.length=6;
- var->green.msb_right=0;
- var->blue.offset=0;
- var->blue.length=5;
- var->blue.msb_right=0;
- }
- else {
- var->red.offset=0;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->red.msb_right = 0;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->green.msb_right = 0;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->blue.msb_right = 0;
+ } else {
+ var->red.offset = 0;
var->red.length = hw->ste_mode ? 4 : 6;
- var->red.msb_right=0;
- var->grayscale=0;
- var->blue=var->green=var->red;
+ if (var->red.length > var->bits_per_pixel)
+ var->red.length = var->bits_per_pixel;
+ var->red.msb_right = 0;
+ var->grayscale = 0;
+ var->blue = var->green = var->red;
}
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
linelen = var->xres_virtual * var->bits_per_pixel / 8;
if (screen_len) {
if (par->yres_virtual)
var->yres_virtual = par->yres_virtual;
else
- /* yres_virtual==0 means use maximum */
+ /* yres_virtual == 0 means use maximum */
var->yres_virtual = screen_len / linelen;
- }
- else {
+ } else {
if (hwscroll < 0)
var->yres_virtual = 2 * var->yres;
else
- var->yres_virtual=var->yres+hwscroll * 16;
+ var->yres_virtual = var->yres + hwscroll * 16;
}
- var->xoffset=0; /* TODO change this */
+ var->xoffset = 0; /* TODO change this */
/* hdX-offsets */
prescale = hxx_prescale(hw);
@@ -1402,8 +1517,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
if (hw->f_shift & 0x100) {
hde_off = 0;
hdb_off = (base_off + 16 * plen) + prescale;
- }
- else {
+ } else {
hde_off = ((128 / var->bits_per_pixel + 2) * plen);
if (hw->ste_mode)
hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen)
@@ -1415,8 +1529,8 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
/* Right margin includes hsync */
var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) -
- (hw->hdb & 0x200 ? 2+hw->hht : 0));
- if (hw->ste_mode || mon_type!=F_MON_VGA)
+ (hw->hdb & 0x200 ? 2 + hw->hht : 0));
+ if (hw->ste_mode || mon_type != F_MON_VGA)
var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off;
else
/* can't use this in ste_mode, because hbb is +1 off */
@@ -1424,15 +1538,14 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->hsync_len = prescale * (hw->hht + 2 - hw->hss);
/* Lower margin includes vsync */
- var->upper_margin = hw->vdb / 2 ; /* round down to full lines */
- var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */
- var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */
+ var->upper_margin = hw->vdb / 2; /* round down to full lines */
+ var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2; /* round up */
+ var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2; /* round up */
if (var->vmode & FB_VMODE_INTERLACED) {
var->upper_margin *= 2;
var->lower_margin *= 2;
var->vsync_len *= 2;
- }
- else if (var->vmode & FB_VMODE_DOUBLE) {
+ } else if (var->vmode & FB_VMODE_DOUBLE) {
var->upper_margin = (var->upper_margin + 1) / 2;
var->lower_margin = (var->lower_margin + 1) / 2;
var->vsync_len = (var->vsync_len + 1) / 2;
@@ -1447,20 +1560,19 @@ static int falcon_encode_var( struct fb_var_screeninfo *var,
var->lower_margin -= var->vsync_len;
if (screen_base)
- var->yoffset=(par->screen_base - screen_base)/linelen;
+ var->yoffset = (par->screen_base - screen_base) / linelen;
else
- var->yoffset=0;
- var->nonstd=0; /* what is this for? */
- var->activate=0;
+ var->yoffset = 0;
+ var->nonstd = 0; /* what is this for? */
+ var->activate = 0;
return 0;
}
-
-static int f_change_mode = 0;
+static int f_change_mode;
static struct falcon_hw f_new_mode;
-static int f_pan_display = 0;
+static int f_pan_display;
-static void falcon_get_par( struct atafb_par *par )
+static void falcon_get_par(struct atafb_par *par)
{
unsigned long addr;
struct falcon_hw *hw = &par->hw.falcon;
@@ -1492,12 +1604,12 @@ static void falcon_get_par( struct atafb_par *par )
par->screen_base = phys_to_virt(addr);
/* derived parameters */
- hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100;
+ hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100;
hw->mono = (hw->f_shift & 0x400) ||
- ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200);
+ ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200);
}
-static void falcon_set_par( struct atafb_par *par )
+static void falcon_set_par(struct atafb_par *par)
{
f_change_mode = 0;
@@ -1519,8 +1631,7 @@ static void falcon_set_par( struct atafb_par *par )
f_change_mode = 1;
}
-
-static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
+static irqreturn_t falcon_vbl_switcher(int irq, void *dummy)
{
struct falcon_hw *hw = &f_new_mode;
@@ -1529,11 +1640,10 @@ static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
if (hw->sync & 0x1) {
/* Enable external pixelclock. This code only for ScreenWonder */
- *(volatile unsigned short*)0xffff9202 = 0xffbf;
- }
- else {
+ *(volatile unsigned short *)0xffff9202 = 0xffbf;
+ } else {
/* Turn off external clocks. Read sets all output bits to 1. */
- *(volatile unsigned short*)0xffff9202;
+ *(volatile unsigned short *)0xffff9202;
}
shifter.syncmode = hw->sync;
@@ -1550,15 +1660,14 @@ static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
videl.vde = hw->vde;
videl.vss = hw->vss;
- videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
+ videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */
if (hw->ste_mode) {
- videl.st_shift = hw->st_shift; /* write enables STE palette */
- }
- else {
+ videl.st_shift = hw->st_shift; /* write enables STE palette */
+ } else {
/* IMPORTANT:
- * set st_shift 0, so we can tell the screen-depth if f_shift==0.
+ * set st_shift 0, so we can tell the screen-depth if f_shift == 0.
* Writing 0 to f_shift enables 4 plane Falcon mode but
- * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible
+ * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible
* with Falcon palette.
*/
videl.st_shift = 0;
@@ -1580,12 +1689,13 @@ static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
return IRQ_HANDLED;
}
-
-static int falcon_pan_display( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int falcon_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
+ struct atafb_par *par = (struct atafb_par *)info->par;
+
int xoffset;
- int bpp = fb_display[fb_info.currcon].var.bits_per_pixel;
+ int bpp = info->var.bits_per_pixel;
if (bpp == 1)
var->xoffset = up(var->xoffset, 32);
@@ -1596,45 +1706,24 @@ static int falcon_pan_display( struct fb_var_screeninfo *var,
var->xoffset = up(var->xoffset, 2);
}
par->hw.falcon.line_offset = bpp *
- (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16;
+ (info->var.xres_virtual - info->var.xres) / 16;
if (par->hw.falcon.xoffset)
par->hw.falcon.line_offset -= bpp;
xoffset = var->xoffset - par->hw.falcon.xoffset;
par->screen_base = screen_base +
- (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8;
+ (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8;
if (fbhw->set_screen_base)
- fbhw->set_screen_base (par->screen_base);
+ fbhw->set_screen_base(par->screen_base);
else
- return -EINVAL; /* shouldn't happen */
+ return -EINVAL; /* shouldn't happen */
f_pan_display = 1;
return 0;
}
-
-static int falcon_getcolreg( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *info )
-{ unsigned long col;
-
- if (regno > 255)
- return 1;
- /* This works in STE-mode (with 4bit/color) since f030_col-registers
- * hold up to 6bit/color.
- * Even with hicolor r/g/b=5/6/5 bit!
- */
- col = f030_col[regno];
- *red = (col >> 16) & 0xff00;
- *green = (col >> 8) & 0xff00;
- *blue = (col << 8) & 0xff00;
- *transp = 0;
- return 0;
-}
-
-
-static int falcon_setcolreg( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp, struct fb_info *info )
+static int falcon_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
{
if (regno > 255)
return 1;
@@ -1655,13 +1744,12 @@ static int falcon_setcolreg( unsigned regno, unsigned red,
return 0;
}
-
-static int falcon_blank( int blank_mode )
+static int falcon_blank(int blank_mode)
{
-/* ++guenther: we can switch off graphics by changing VDB and VDE,
- * so VIDEL doesn't hog the bus while saving.
- * (this may affect usleep()).
- */
+ /* ++guenther: we can switch off graphics by changing VDB and VDE,
+ * so VIDEL doesn't hog the bus while saving.
+ * (this may affect usleep()).
+ */
int vdb, vss, hbe, hss;
if (mon_type == F_MON_SM) /* this doesn't work on SM124 */
@@ -1694,14 +1782,13 @@ static int falcon_blank( int blank_mode )
return 0;
}
-
-static int falcon_detect( void )
+static int falcon_detect(void)
{
struct atafb_par par;
unsigned char fhw;
/* Determine connected monitor and set monitor parameters */
- fhw = *(unsigned char*)0xffff8006;
+ fhw = *(unsigned char *)0xffff8006;
mon_type = fhw >> 6 & 0x3;
/* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */
f030_bus_width = fhw << 6 & 0x80;
@@ -1715,7 +1802,7 @@ static int falcon_detect( void )
case F_MON_SC:
case F_MON_TV:
/* PAL...NTSC */
- fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
+ fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */
fb_info.monspecs.vfmax = 60;
fb_info.monspecs.hfmin = 15620;
fb_info.monspecs.hfmax = 15755;
@@ -1740,13 +1827,12 @@ static int falcon_detect( void )
#ifdef ATAFB_STE
-static int stste_encode_fix( struct fb_fix_screeninfo *fix,
- struct atafb_par *par )
-
+static int stste_encode_fix(struct fb_fix_screeninfo *fix,
+ struct atafb_par *par)
{
int mode;
- strcpy(fix->id,"Atari Builtin");
+ strcpy(fix->id, "Atari Builtin");
fix->smem_start = (unsigned long)real_screen_base;
fix->smem_len = screen_len;
fix->type = FB_TYPE_INTERLEAVED_PLANES;
@@ -1771,43 +1857,40 @@ static int stste_encode_fix( struct fb_fix_screeninfo *fix,
return 0;
}
-
-static int stste_decode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int stste_decode_var(struct fb_var_screeninfo *var,
+ struct atafb_par *par)
{
- int xres=var->xres;
- int yres=var->yres;
- int bpp=var->bits_per_pixel;
+ int xres = var->xres;
+ int yres = var->yres;
+ int bpp = var->bits_per_pixel;
int linelen;
int yres_virtual = var->yres_virtual;
if (mono_moni) {
if (bpp > 1 || xres > sttt_xres || yres > st_yres)
return -EINVAL;
- par->hw.st.mode=ST_HIGH;
- xres=sttt_xres;
- yres=st_yres;
- bpp=1;
+ par->hw.st.mode = ST_HIGH;
+ xres = sttt_xres;
+ yres = st_yres;
+ bpp = 1;
} else {
if (bpp > 4 || xres > sttt_xres || yres > st_yres)
return -EINVAL;
if (bpp > 2) {
- if (xres > sttt_xres/2 || yres > st_yres/2)
+ if (xres > sttt_xres / 2 || yres > st_yres / 2)
return -EINVAL;
- par->hw.st.mode=ST_LOW;
- xres=sttt_xres/2;
- yres=st_yres/2;
- bpp=4;
- }
- else if (bpp > 1) {
- if (xres > sttt_xres || yres > st_yres/2)
+ par->hw.st.mode = ST_LOW;
+ xres = sttt_xres / 2;
+ yres = st_yres / 2;
+ bpp = 4;
+ } else if (bpp > 1) {
+ if (xres > sttt_xres || yres > st_yres / 2)
return -EINVAL;
- par->hw.st.mode=ST_MID;
- xres=sttt_xres;
- yres=st_yres/2;
- bpp=2;
- }
- else
+ par->hw.st.mode = ST_MID;
+ xres = sttt_xres;
+ yres = st_yres / 2;
+ bpp = 2;
+ } else
return -EINVAL;
}
if (yres_virtual <= 0)
@@ -1815,10 +1898,10 @@ static int stste_decode_var( struct fb_var_screeninfo *var,
else if (yres_virtual < yres)
yres_virtual = yres;
if (var->sync & FB_SYNC_EXT)
- par->hw.st.sync=(par->hw.st.sync & ~1) | 1;
+ par->hw.st.sync = (par->hw.st.sync & ~1) | 1;
else
- par->hw.st.sync=(par->hw.st.sync & ~1);
- linelen=xres*bpp/8;
+ par->hw.st.sync = (par->hw.st.sync & ~1);
+ linelen = xres * bpp / 8;
if (yres_virtual * linelen > screen_len && screen_len)
return -EINVAL;
if (yres * linelen > screen_len && screen_len)
@@ -1826,93 +1909,91 @@ static int stste_decode_var( struct fb_var_screeninfo *var,
if (var->yoffset + yres > yres_virtual && yres_virtual)
return -EINVAL;
par->yres_virtual = yres_virtual;
- par->screen_base=screen_base+ var->yoffset*linelen;
+ par->screen_base = screen_base + var->yoffset * linelen;
return 0;
}
-static int stste_encode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int stste_encode_var(struct fb_var_screeninfo *var,
+ struct atafb_par *par)
{
int linelen;
memset(var, 0, sizeof(struct fb_var_screeninfo));
- var->red.offset=0;
+ var->red.offset = 0;
var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3;
- var->red.msb_right=0;
- var->grayscale=0;
+ var->red.msb_right = 0;
+ var->grayscale = 0;
- var->pixclock=31041;
- var->left_margin=120; /* these are incorrect */
- var->right_margin=100;
- var->upper_margin=8;
- var->lower_margin=16;
- var->hsync_len=140;
- var->vsync_len=30;
+ var->pixclock = 31041;
+ var->left_margin = 120; /* these are incorrect */
+ var->right_margin = 100;
+ var->upper_margin = 8;
+ var->lower_margin = 16;
+ var->hsync_len = 140;
+ var->vsync_len = 30;
- var->height=-1;
- var->width=-1;
+ var->height = -1;
+ var->width = -1;
if (!(par->hw.st.sync & 1))
- var->sync=0;
+ var->sync = 0;
else
- var->sync=FB_SYNC_EXT;
+ var->sync = FB_SYNC_EXT;
switch (par->hw.st.mode & 3) {
case ST_LOW:
- var->xres=sttt_xres/2;
- var->yres=st_yres/2;
- var->bits_per_pixel=4;
+ var->xres = sttt_xres / 2;
+ var->yres = st_yres / 2;
+ var->bits_per_pixel = 4;
break;
case ST_MID:
- var->xres=sttt_xres;
- var->yres=st_yres/2;
- var->bits_per_pixel=2;
+ var->xres = sttt_xres;
+ var->yres = st_yres / 2;
+ var->bits_per_pixel = 2;
break;
case ST_HIGH:
- var->xres=sttt_xres;
- var->yres=st_yres;
- var->bits_per_pixel=1;
+ var->xres = sttt_xres;
+ var->yres = st_yres;
+ var->bits_per_pixel = 1;
break;
- }
- var->blue=var->green=var->red;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- var->xres_virtual=sttt_xres_virtual;
- linelen=var->xres_virtual * var->bits_per_pixel / 8;
- ovsc_addlen=linelen*(sttt_yres_virtual - st_yres);
-
- if (! use_hwscroll)
- var->yres_virtual=var->yres;
+ }
+ var->blue = var->green = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->xres_virtual = sttt_xres_virtual;
+ linelen = var->xres_virtual * var->bits_per_pixel / 8;
+ ovsc_addlen = linelen * (sttt_yres_virtual - st_yres);
+
+ if (!use_hwscroll)
+ var->yres_virtual = var->yres;
else if (screen_len) {
if (par->yres_virtual)
var->yres_virtual = par->yres_virtual;
else
- /* yres_virtual==0 means use maximum */
+ /* yres_virtual == 0 means use maximum */
var->yres_virtual = screen_len / linelen;
- }
- else {
+ } else {
if (hwscroll < 0)
var->yres_virtual = 2 * var->yres;
else
- var->yres_virtual=var->yres+hwscroll * 16;
+ var->yres_virtual = var->yres + hwscroll * 16;
}
- var->xoffset=0;
+ var->xoffset = 0;
if (screen_base)
- var->yoffset=(par->screen_base - screen_base)/linelen;
+ var->yoffset = (par->screen_base - screen_base) / linelen;
else
- var->yoffset=0;
- var->nonstd=0;
- var->activate=0;
- var->vmode=FB_VMODE_NONINTERLACED;
+ var->yoffset = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
return 0;
}
-
-static void stste_get_par( struct atafb_par *par )
+static void stste_get_par(struct atafb_par *par)
{
unsigned long addr;
- par->hw.st.mode=shifter_tt.st_shiftmode;
- par->hw.st.sync=shifter.syncmode;
+ par->hw.st.mode = shifter_tt.st_shiftmode;
+ par->hw.st.sync = shifter.syncmode;
addr = ((shifter.bas_hi & 0xff) << 16) |
((shifter.bas_md & 0xff) << 8);
if (ATARIHW_PRESENT(EXTD_SHIFTER))
@@ -1920,55 +2001,18 @@ static void stste_get_par( struct atafb_par *par )
par->screen_base = phys_to_virt(addr);
}
-static void stste_set_par( struct atafb_par *par )
+static void stste_set_par(struct atafb_par *par)
{
- shifter_tt.st_shiftmode=par->hw.st.mode;
- shifter.syncmode=par->hw.st.sync;
+ shifter_tt.st_shiftmode = par->hw.st.mode;
+ shifter.syncmode = par->hw.st.sync;
/* only set screen_base if really necessary */
if (current_par.screen_base != par->screen_base)
fbhw->set_screen_base(par->screen_base);
}
-
-static int stste_getcolreg(unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *info)
-{
- unsigned col, t;
-
- if (regno > 15)
- return 1;
- col = shifter_tt.color_reg[regno];
- if (ATARIHW_PRESENT(EXTD_SHIFTER)) {
- t = ((col >> 7) & 0xe) | ((col >> 11) & 1);
- t |= t << 4;
- *red = t | (t << 8);
- t = ((col >> 3) & 0xe) | ((col >> 7) & 1);
- t |= t << 4;
- *green = t | (t << 8);
- t = ((col << 1) & 0xe) | ((col >> 3) & 1);
- t |= t << 4;
- *blue = t | (t << 8);
- }
- else {
- t = (col >> 7) & 0xe;
- t |= t << 4;
- *red = t | (t << 8);
- t = (col >> 3) & 0xe;
- t |= t << 4;
- *green = t | (t << 8);
- t = (col << 1) & 0xe;
- t |= t << 4;
- *blue = t | (t << 8);
- }
- *transp = 0;
- return 0;
-}
-
-
-static int stste_setcolreg(unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp, struct fb_info *info)
+static int stste_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
{
if (regno > 15)
return 1;
@@ -1988,10 +2032,9 @@ static int stste_setcolreg(unsigned regno, unsigned red,
return 0;
}
-
-static int stste_detect( void )
-
-{ struct atafb_par par;
+static int stste_detect(void)
+{
+ struct atafb_par par;
/* Determine the connected monitor: The DMA sound must be
* disabled before reading the MFP GPIP, because the Sound
@@ -1999,7 +2042,7 @@ static int stste_detect( void )
*/
if (ATARIHW_PRESENT(PCM_8BIT)) {
tt_dmasnd.ctrl = DMASND_CTRL_OFF;
- udelay(20); /* wait a while for things to settle down */
+ udelay(20); /* wait a while for things to settle down */
}
mono_moni = (mfp.par_dt_reg & 0x80) == 0;
@@ -2014,12 +2057,12 @@ static int stste_detect( void )
static void stste_set_screen_base(void *s_base)
{
unsigned long addr;
- addr= virt_to_phys(s_base);
+ addr = virt_to_phys(s_base);
/* Setup Screen Memory */
- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
+ shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
+ shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
if (ATARIHW_PRESENT(EXTD_SHIFTER))
- shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
+ shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
}
#endif /* ATAFB_STE */
@@ -2045,51 +2088,49 @@ static void stste_set_screen_base(void *s_base)
/* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */
static void st_ovsc_switch(void)
{
- unsigned long flags;
- register unsigned char old, new;
+ unsigned long flags;
+ register unsigned char old, new;
- if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
- return;
- local_irq_save(flags);
-
- mfp.tim_ct_b = 0x10;
- mfp.active_edge |= 8;
- mfp.tim_ct_b = 0;
- mfp.tim_dt_b = 0xf0;
- mfp.tim_ct_b = 8;
- while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
- ;
- new = mfp.tim_dt_b;
- do {
- udelay(LINE_DELAY);
- old = new;
+ if (!(atari_switches & ATARI_SWITCH_OVSC_MASK))
+ return;
+ local_irq_save(flags);
+
+ mfp.tim_ct_b = 0x10;
+ mfp.active_edge |= 8;
+ mfp.tim_ct_b = 0;
+ mfp.tim_dt_b = 0xf0;
+ mfp.tim_ct_b = 8;
+ while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */
+ ;
new = mfp.tim_dt_b;
- } while (old != new);
- mfp.tim_ct_b = 0x10;
- udelay(SYNC_DELAY);
-
- if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
- acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
- if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
- acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
- if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
- sound_ym.rd_data_reg_sel = 14;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel |
- ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
- ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
- }
- local_irq_restore(flags);
+ do {
+ udelay(LINE_DELAY);
+ old = new;
+ new = mfp.tim_dt_b;
+ } while (old != new);
+ mfp.tim_ct_b = 0x10;
+ udelay(SYNC_DELAY);
+
+ if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
+ acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE;
+ if (atari_switches & ATARI_SWITCH_OVSC_MIDI)
+ acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID;
+ if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) {
+ sound_ym.rd_data_reg_sel = 14;
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel |
+ ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) |
+ ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0);
+ }
+ local_irq_restore(flags);
}
/* ------------------- External Video ---------------------- */
#ifdef ATAFB_EXT
-static int ext_encode_fix( struct fb_fix_screeninfo *fix,
- struct atafb_par *par )
-
+static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par)
{
- strcpy(fix->id,"Unknown Extern");
+ strcpy(fix->id, "Unknown Extern");
fix->smem_start = (unsigned long)external_addr;
fix->smem_len = PAGE_ALIGN(external_len);
if (external_depth == 1) {
@@ -2099,31 +2140,29 @@ static int ext_encode_fix( struct fb_fix_screeninfo *fix,
fix->visual =
(external_pmode == FB_TYPE_INTERLEAVED_PLANES ||
external_pmode == FB_TYPE_PACKED_PIXELS) ?
- FB_VISUAL_MONO10 :
- FB_VISUAL_MONO01;
- }
- else {
+ FB_VISUAL_MONO10 : FB_VISUAL_MONO01;
+ } else {
/* Use STATIC if we don't know how to access color registers */
int visual = external_vgaiobase ?
FB_VISUAL_PSEUDOCOLOR :
FB_VISUAL_STATIC_PSEUDOCOLOR;
switch (external_pmode) {
- case -1: /* truecolor */
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->visual=FB_VISUAL_TRUECOLOR;
+ case -1: /* truecolor */
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = FB_VISUAL_TRUECOLOR;
break;
- case FB_TYPE_PACKED_PIXELS:
- fix->type=FB_TYPE_PACKED_PIXELS;
- fix->visual=visual;
+ case FB_TYPE_PACKED_PIXELS:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->visual = visual;
break;
- case FB_TYPE_PLANES:
- fix->type=FB_TYPE_PLANES;
- fix->visual=visual;
+ case FB_TYPE_PLANES:
+ fix->type = FB_TYPE_PLANES;
+ fix->visual = visual;
break;
- case FB_TYPE_INTERLEAVED_PLANES:
- fix->type=FB_TYPE_INTERLEAVED_PLANES;
- fix->type_aux=2;
- fix->visual=visual;
+ case FB_TYPE_INTERLEAVED_PLANES:
+ fix->type = FB_TYPE_INTERLEAVED_PLANES;
+ fix->type_aux = 2;
+ fix->visual = visual;
break;
}
}
@@ -2134,137 +2173,112 @@ static int ext_encode_fix( struct fb_fix_screeninfo *fix,
return 0;
}
-
-static int ext_decode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
{
struct fb_var_screeninfo *myvar = &atafb_predefined[0];
-
+
if (var->bits_per_pixel > myvar->bits_per_pixel ||
- var->xres > myvar->xres ||
- var->xres_virtual > myvar->xres_virtual ||
- var->yres > myvar->yres ||
- var->xoffset > 0 ||
- var->yoffset > 0)
+ var->xres > myvar->xres ||
+ var->xres_virtual > myvar->xres_virtual ||
+ var->yres > myvar->yres ||
+ var->xoffset > 0 ||
+ var->yoffset > 0)
return -EINVAL;
return 0;
}
-
-static int ext_encode_var( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par)
{
memset(var, 0, sizeof(struct fb_var_screeninfo));
- var->red.offset=0;
- var->red.length=(external_pmode == -1) ? external_depth/3 :
+ var->red.offset = 0;
+ var->red.length = (external_pmode == -1) ? external_depth / 3 :
(external_vgaiobase ? external_bitspercol : 0);
- var->red.msb_right=0;
- var->grayscale=0;
+ var->red.msb_right = 0;
+ var->grayscale = 0;
- var->pixclock=31041;
- var->left_margin=120; /* these are surely incorrect */
- var->right_margin=100;
- var->upper_margin=8;
- var->lower_margin=16;
- var->hsync_len=140;
- var->vsync_len=30;
+ var->pixclock = 31041;
+ var->left_margin = 120; /* these are surely incorrect */
+ var->right_margin = 100;
+ var->upper_margin = 8;
+ var->lower_margin = 16;
+ var->hsync_len = 140;
+ var->vsync_len = 30;
- var->height=-1;
- var->width=-1;
+ var->height = -1;
+ var->width = -1;
- var->sync=0;
+ var->sync = 0;
var->xres = external_xres;
var->yres = external_yres;
var->xres_virtual = external_xres_virtual;
var->bits_per_pixel = external_depth;
-
- var->blue=var->green=var->red;
- var->transp.offset=0;
- var->transp.length=0;
- var->transp.msb_right=0;
- var->yres_virtual=var->yres;
- var->xoffset=0;
- var->yoffset=0;
- var->nonstd=0;
- var->activate=0;
- var->vmode=FB_VMODE_NONINTERLACED;
+
+ var->blue = var->green = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
+ var->yres_virtual = var->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->nonstd = 0;
+ var->activate = 0;
+ var->vmode = FB_VMODE_NONINTERLACED;
return 0;
}
-
-static void ext_get_par( struct atafb_par *par )
+static void ext_get_par(struct atafb_par *par)
{
par->screen_base = external_addr;
}
-static void ext_set_par( struct atafb_par *par )
+static void ext_set_par(struct atafb_par *par)
{
}
#define OUTB(port,val) \
- *((unsigned volatile char *) ((port)+external_vgaiobase))=(val)
+ *((unsigned volatile char *) ((port)+external_vgaiobase)) = (val)
#define INB(port) \
(*((unsigned volatile char *) ((port)+external_vgaiobase)))
-#define DACDelay \
+#define DACDelay \
do { \
- unsigned char tmp=INB(0x3da); \
- tmp=INB(0x3da); \
+ unsigned char tmp = INB(0x3da); \
+ tmp = INB(0x3da); \
} while (0)
-static int ext_getcolreg( unsigned regno, unsigned *red,
- unsigned *green, unsigned *blue,
- unsigned *transp, struct fb_info *info )
+static int ext_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
{
- if (! external_vgaiobase)
+ unsigned char colmask = (1 << external_bitspercol) - 1;
+
+ if (!external_vgaiobase)
return 1;
- *red = ext_color[regno].red;
- *green = ext_color[regno].green;
- *blue = ext_color[regno].blue;
- *transp=0;
- return 0;
-}
-
-static int ext_setcolreg( unsigned regno, unsigned red,
- unsigned green, unsigned blue,
- unsigned transp, struct fb_info *info )
+ switch (external_card_type) {
+ case IS_VGA:
+ OUTB(0x3c8, regno);
+ DACDelay;
+ OUTB(0x3c9, red & colmask);
+ DACDelay;
+ OUTB(0x3c9, green & colmask);
+ DACDelay;
+ OUTB(0x3c9, blue & colmask);
+ DACDelay;
+ return 0;
-{ unsigned char colmask = (1 << external_bitspercol) - 1;
+ case IS_MV300:
+ OUTB((MV300_reg[regno] << 2) + 1, red);
+ OUTB((MV300_reg[regno] << 2) + 1, green);
+ OUTB((MV300_reg[regno] << 2) + 1, blue);
+ return 0;
- if (! external_vgaiobase)
+ default:
return 1;
-
- ext_color[regno].red = red;
- ext_color[regno].green = green;
- ext_color[regno].blue = blue;
-
- switch (external_card_type) {
- case IS_VGA:
- OUTB(0x3c8, regno);
- DACDelay;
- OUTB(0x3c9, red & colmask);
- DACDelay;
- OUTB(0x3c9, green & colmask);
- DACDelay;
- OUTB(0x3c9, blue & colmask);
- DACDelay;
- return 0;
-
- case IS_MV300:
- OUTB((MV300_reg[regno] << 2)+1, red);
- OUTB((MV300_reg[regno] << 2)+1, green);
- OUTB((MV300_reg[regno] << 2)+1, blue);
- return 0;
-
- default:
- return 1;
- }
+ }
}
-
-
-static int ext_detect( void )
+static int ext_detect(void)
{
struct fb_var_screeninfo *myvar = &atafb_predefined[0];
struct atafb_par dummy_par;
@@ -2284,213 +2298,182 @@ static int ext_detect( void )
static void set_screen_base(void *s_base)
{
unsigned long addr;
- addr= virt_to_phys(s_base);
+
+ addr = virt_to_phys(s_base);
/* Setup Screen Memory */
- shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16);
- shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8);
- shifter.bas_lo=(unsigned char) (addr & 0x0000ff);
+ shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16);
+ shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8);
+ shifter.bas_lo = (unsigned char)(addr & 0x0000ff);
}
-
-static int pan_display( struct fb_var_screeninfo *var,
- struct atafb_par *par )
+static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
+ struct atafb_par *par = (struct atafb_par *)info->par;
+
if (!fbhw->set_screen_base ||
- (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
+ (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset))
return -EINVAL;
var->xoffset = up(var->xoffset, 16);
par->screen_base = screen_base +
- (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset)
- * fb_display[fb_info.currcon].var.bits_per_pixel / 8;
- fbhw->set_screen_base (par->screen_base);
+ (var->yoffset * info->var.xres_virtual + var->xoffset)
+ * info->var.bits_per_pixel / 8;
+ fbhw->set_screen_base(par->screen_base);
return 0;
}
-
/* ------------ Interfaces to hardware functions ------------ */
-
#ifdef ATAFB_TT
static struct fb_hwswitch tt_switch = {
- tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var,
- tt_get_par, tt_set_par, tt_getcolreg,
- set_screen_base, NULL, pan_display
+ .detect = tt_detect,
+ .encode_fix = tt_encode_fix,
+ .decode_var = tt_decode_var,
+ .encode_var = tt_encode_var,
+ .get_par = tt_get_par,
+ .set_par = tt_set_par,
+ .set_screen_base = set_screen_base,
+ .pan_display = pan_display,
};
#endif
#ifdef ATAFB_FALCON
static struct fb_hwswitch falcon_switch = {
- falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var,
- falcon_get_par, falcon_set_par, falcon_getcolreg,
- set_screen_base, falcon_blank, falcon_pan_display
+ .detect = falcon_detect,
+ .encode_fix = falcon_encode_fix,
+ .decode_var = falcon_decode_var,
+ .encode_var = falcon_encode_var,
+ .get_par = falcon_get_par,
+ .set_par = falcon_set_par,
+ .set_screen_base = set_screen_base,
+ .blank = falcon_blank,
+ .pan_display = falcon_pan_display,
};
#endif
#ifdef ATAFB_STE
static struct fb_hwswitch st_switch = {
- stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var,
- stste_get_par, stste_set_par, stste_getcolreg,
- stste_set_screen_base, NULL, pan_display
+ .detect = stste_detect,
+ .encode_fix = stste_encode_fix,
+ .decode_var = stste_decode_var,
+ .encode_var = stste_encode_var,
+ .get_par = stste_get_par,
+ .set_par = stste_set_par,
+ .set_screen_base = stste_set_screen_base,
+ .pan_display = pan_display
};
#endif
#ifdef ATAFB_EXT
static struct fb_hwswitch ext_switch = {
- ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var,
- ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL
+ .detect = ext_detect,
+ .encode_fix = ext_encode_fix,
+ .decode_var = ext_decode_var,
+ .encode_var = ext_encode_var,
+ .get_par = ext_get_par,
+ .set_par = ext_set_par,
};
#endif
-
-
-static void atafb_get_par( struct atafb_par *par )
+static void ata_get_par(struct atafb_par *par)
{
- if (current_par_valid) {
- *par=current_par;
- }
+ if (current_par_valid)
+ *par = current_par;
else
fbhw->get_par(par);
}
-
-static void atafb_set_par( struct atafb_par *par )
+static void ata_set_par(struct atafb_par *par)
{
fbhw->set_par(par);
- current_par=*par;
- current_par_valid=1;
+ current_par = *par;
+ current_par_valid = 1;
}
-
/* =========================================================== */
/* ============== Hardware Independent Functions ============= */
/* =========================================================== */
-
/* used for hardware scrolling */
-static int
-fb_update_var(int con, struct fb_info *info)
-{
- int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual*
- fb_display[con].var.bits_per_pixel>>3;
-
- current_par.screen_base=screen_base + off;
-
- if (fbhw->set_screen_base)
- fbhw->set_screen_base(current_par.screen_base);
- return 0;
-}
-
-static int
-do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
+static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive)
{
- int err,activate;
+ int err, activate;
struct atafb_par par;
- if ((err=fbhw->decode_var(var, &par)))
+
+ err = fbhw->decode_var(var, &par);
+ if (err)
return err;
- activate=var->activate;
+ activate = var->activate;
if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive)
- atafb_set_par(&par);
+ ata_set_par(&par);
fbhw->encode_var(var, &par);
- var->activate=activate;
+ var->activate = activate;
return 0;
}
-static int
-atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
{
struct atafb_par par;
- if (con == -1)
- atafb_get_par(&par);
- else {
- int err;
- if ((err=fbhw->decode_var(&fb_display[con].var,&par)))
- return err;
- }
+ int err;
+ // Get fix directly (case con == -1 before)??
+ err = fbhw->decode_var(&info->var, &par);
+ if (err)
+ return err;
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
return fbhw->encode_fix(fix, &par);
}
-
-static int
-atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+
+static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct atafb_par par;
- if (con == -1) {
- atafb_get_par(&par);
- fbhw->encode_var(var, &par);
- }
- else
- *var=fb_display[con].var;
+
+ ata_get_par(&par);
+ fbhw->encode_var(var, &par);
+
return 0;
}
-static void
-atafb_set_disp(int con, struct fb_info *info)
+// No longer called by fbcon!
+// Still called by set_var internally
+
+static void atafb_set_disp(struct fb_info *info)
{
- struct fb_fix_screeninfo fix;
- struct fb_var_screeninfo var;
- struct display *display;
+ atafb_get_var(&info->var, info);
+ atafb_get_fix(&info->fix, info);
- if (con >= 0)
- display = &fb_display[con];
- else
- display = &disp; /* used during initialization */
-
- atafb_get_fix(&fix, con, info);
- atafb_get_var(&var, con, info);
- if (con == -1)
- con=0;
- info->screen_base = (void *)fix.smem_start;
- display->visual = fix.visual;
- display->type = fix.type;
- display->type_aux = fix.type_aux;
- display->ypanstep = fix.ypanstep;
- display->ywrapstep = fix.ywrapstep;
- display->line_length = fix.line_length;
- if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
- fix.visual != FB_VISUAL_DIRECTCOLOR)
- display->can_soft_blank = 0;
- else
- display->can_soft_blank = 1;
- display->inverse =
- (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse);
- switch (fix.type) {
- case FB_TYPE_INTERLEAVED_PLANES:
- switch (var.bits_per_pixel) {
-#ifdef FBCON_HAS_IPLAN2P2
- case 2:
- display->dispsw = &fbcon_iplan2p2;
+ info->screen_base = (void *)info->fix.smem_start;
+
+ switch (info->fix.type) {
+ case FB_TYPE_INTERLEAVED_PLANES:
+ switch (info->var.bits_per_pixel) {
+ case 2:
+ // display->dispsw = &fbcon_iplan2p2;
break;
-#endif
-#ifdef FBCON_HAS_IPLAN2P4
- case 4:
- display->dispsw = &fbcon_iplan2p4;
+ case 4:
+ // display->dispsw = &fbcon_iplan2p4;
break;
-#endif
-#ifdef FBCON_HAS_IPLAN2P8
- case 8:
- display->dispsw = &fbcon_iplan2p8;
+ case 8:
+ // display->dispsw = &fbcon_iplan2p8;
break;
-#endif
}
break;
- case FB_TYPE_PACKED_PIXELS:
- switch (var.bits_per_pixel) {
+ case FB_TYPE_PACKED_PIXELS:
+ switch (info->var.bits_per_pixel) {
#ifdef FBCON_HAS_MFB
- case 1:
- display->dispsw = &fbcon_mfb;
+ case 1:
+ // display->dispsw = &fbcon_mfb;
break;
#endif
#ifdef FBCON_HAS_CFB8
- case 8:
- display->dispsw = &fbcon_cfb8;
+ case 8:
+ // display->dispsw = &fbcon_cfb8;
break;
#endif
#ifdef FBCON_HAS_CFB16
- case 16:
- display->dispsw = &fbcon_cfb16;
- display->dispsw_data = fbcon_cfb16_cmap;
+ case 16:
+ // display->dispsw = &fbcon_cfb16;
+ // display->dispsw_data = fbcon_cfb16_cmap;
break;
#endif
}
@@ -2498,74 +2481,203 @@ atafb_set_disp(int con, struct fb_info *info)
}
}
+static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info);
+}
+
static int
-atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
{
- int err,oldxres,oldyres,oldbpp,oldxres_virtual,
- oldyres_virtual,oldyoffset;
- if ((err=do_fb_set_var(var, con==info->currcon)))
- return err;
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- oldxres=fb_display[con].var.xres;
- oldyres=fb_display[con].var.yres;
- oldxres_virtual=fb_display[con].var.xres_virtual;
- oldyres_virtual=fb_display[con].var.yres_virtual;
- oldbpp=fb_display[con].var.bits_per_pixel;
- oldyoffset=fb_display[con].var.yoffset;
- fb_display[con].var=*var;
- if (oldxres != var->xres || oldyres != var->yres
- || oldxres_virtual != var->xres_virtual
- || oldyres_virtual != var->yres_virtual
- || oldbpp != var->bits_per_pixel
- || oldyoffset != var->yoffset) {
- atafb_set_disp(con, info);
- (*fb_info.changevar)(con);
- fb_alloc_cmap(&fb_display[con].cmap, 0, 0);
- do_install_cmap(con, info);
- }
+ int xoffset = var->xoffset;
+ int yoffset = var->yoffset;
+ int err;
+
+ if (var->vmode & FB_VMODE_YWRAP) {
+ if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset)
+ return -EINVAL;
+ } else {
+ if (xoffset + info->var.xres > info->var.xres_virtual ||
+ yoffset + info->var.yres > info->var.yres_virtual)
+ return -EINVAL;
}
- var->activate=0;
+
+ if (fbhw->pan_display) {
+ err = fbhw->pan_display(var, info);
+ if (err)
+ return err;
+ } else
+ return -EINVAL;
+
+ info->var.xoffset = xoffset;
+ info->var.yoffset = yoffset;
+
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
return 0;
}
+/*
+ * generic drawing routines; imageblit needs updating for image depth > 1
+ */
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG 4
+#define SHIFT_PER_LONG 5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG 8
+#define SHIFT_PER_LONG 6
+#else
+#define Please update me
+#endif
-static int
-atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+
+static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
- if (con == info->currcon) /* current console ? */
- return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info);
+ struct atafb_par *par = (struct atafb_par *)info->par;
+ int x2, y2;
+ u32 width, height;
+
+ if (!rect->width || !rect->height)
+ return;
+
+ /*
+ * We could use hardware clipping but on many cards you get around
+ * hardware clipping by writing to framebuffer directly.
+ * */
+ x2 = rect->dx + rect->width;
+ y2 = rect->dy + rect->height;
+ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+ width = x2 - rect->dx;
+ height = y2 - rect->dy;
+
+ if (info->var.bits_per_pixel == 1)
+ atafb_mfb_fillrect(info, par->next_line, rect->color,
+ rect->dy, rect->dx, height, width);
+ else if (info->var.bits_per_pixel == 2)
+ atafb_iplan2p2_fillrect(info, par->next_line, rect->color,
+ rect->dy, rect->dx, height, width);
+ else if (info->var.bits_per_pixel == 4)
+ atafb_iplan2p4_fillrect(info, par->next_line, rect->color,
+ rect->dy, rect->dx, height, width);
else
- if (fb_display[con].cmap.len) /* non default colormap ? */
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
- cmap, kspc ? 0 : 2);
- return 0;
+ atafb_iplan2p8_fillrect(info, par->next_line, rect->color,
+ rect->dy, rect->dx, height, width);
+
+ return;
}
-static int
-atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
- int xoffset = var->xoffset;
- int yoffset = var->yoffset;
- int err;
+ struct atafb_par *par = (struct atafb_par *)info->par;
+ int x2, y2;
+ u32 dx, dy, sx, sy, width, height;
+ int rev_copy = 0;
+
+ /* clip the destination */
+ x2 = area->dx + area->width;
+ y2 = area->dy + area->height;
+ dx = area->dx > 0 ? area->dx : 0;
+ dy = area->dy > 0 ? area->dy : 0;
+ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+ width = x2 - dx;
+ height = y2 - dy;
+
+ /* update sx,sy */
+ sx = area->sx + (dx - area->dx);
+ sy = area->sy + (dy - area->dy);
+
+ /* the source must be completely inside the virtual screen */
+ if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual ||
+ (sy + height) > info->var.yres_virtual)
+ return;
- if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual
- || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual)
- return -EINVAL;
+ if (dy > sy || (dy == sy && dx > sx)) {
+ dy += height;
+ sy += height;
+ rev_copy = 1;
+ }
+
+ if (info->var.bits_per_pixel == 1)
+ atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
+ else if (info->var.bits_per_pixel == 2)
+ atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
+ else if (info->var.bits_per_pixel == 4)
+ atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
+ else
+ atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width);
- if (con == info->currcon) {
- if (fbhw->pan_display) {
- if ((err = fbhw->pan_display(var, &current_par)))
- return err;
+ return;
+}
+
+static void atafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct atafb_par *par = (struct atafb_par *)info->par;
+ int x2, y2;
+ unsigned long *dst;
+ int dst_idx;
+ const char *src;
+ u32 dx, dy, width, height, pitch;
+
+ /*
+ * We could use hardware clipping but on many cards you get around
+ * hardware clipping by writing to framebuffer directly like we are
+ * doing here.
+ */
+ x2 = image->dx + image->width;
+ y2 = image->dy + image->height;
+ dx = image->dx;
+ dy = image->dy;
+ x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+ y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+ width = x2 - dx;
+ height = y2 - dy;
+
+ if (image->depth == 1) {
+ // used for font data
+ dst = (unsigned long *)
+ ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1));
+ dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8;
+ dst_idx += dy * par->next_line * 8 + dx;
+ src = image->data;
+ pitch = (image->width + 7) / 8;
+ while (height--) {
+
+ if (info->var.bits_per_pixel == 1)
+ atafb_mfb_linefill(info, par->next_line,
+ dy, dx, width, src,
+ image->bg_color, image->fg_color);
+ else if (info->var.bits_per_pixel == 2)
+ atafb_iplan2p2_linefill(info, par->next_line,
+ dy, dx, width, src,
+ image->bg_color, image->fg_color);
+ else if (info->var.bits_per_pixel == 4)
+ atafb_iplan2p4_linefill(info, par->next_line,
+ dy, dx, width, src,
+ image->bg_color, image->fg_color);
+ else
+ atafb_iplan2p8_linefill(info, par->next_line,
+ dy, dx, width, src,
+ image->bg_color, image->fg_color);
+ dy++;
+ src += pitch;
}
- else
- return -EINVAL;
+ } else {
+ // only used for logo; broken
+ c2p(info->screen_base, image->data, dx, dy, width, height,
+ par->next_line, par->next_plane, image->width,
+ info->var.bits_per_pixel);
}
- fb_display[con].var.xoffset = var->xoffset;
- fb_display[con].var.yoffset = var->yoffset;
- return 0;
}
static int
@@ -2584,7 +2696,7 @@ atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
if (copy_from_user((void *)&current_par, (void *)arg,
sizeof(struct atafb_par)))
return -EFAULT;
- atafb_set_par(&current_par);
+ ata_set_par(&current_par);
return 0;
#endif
}
@@ -2598,42 +2710,82 @@ atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* 3 = suspend hsync
* 4 = off
*/
-static int
-atafb_blank(int blank, struct fb_info *info)
+static int atafb_blank(int blank, struct fb_info *info)
{
unsigned short black[16];
struct fb_cmap cmap;
if (fbhw->blank && !fbhw->blank(blank))
return 1;
if (blank) {
- memset(black, 0, 16*sizeof(unsigned short));
- cmap.red=black;
- cmap.green=black;
- cmap.blue=black;
- cmap.transp=NULL;
- cmap.start=0;
- cmap.len=16;
- fb_set_cmap(&cmap, 1, info);
+ memset(black, 0, 16 * sizeof(unsigned short));
+ cmap.red = black;
+ cmap.green = black;
+ cmap.blue = black;
+ cmap.transp = NULL;
+ cmap.start = 0;
+ cmap.len = 16;
+ fb_set_cmap(&cmap, info);
}
+#if 0
else
- do_install_cmap(info->currcon, info);
+ do_install_cmap(info);
+#endif
+ return 0;
+}
+
+ /*
+ * New fbcon interface ...
+ */
+
+ /* check var by decoding var into hw par, rounding if necessary,
+ * then encoding hw par back into new, validated var */
+static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int err;
+ struct atafb_par par;
+
+ /* Validate wanted screen parameters */
+ // if ((err = ata_decode_var(var, &par)))
+ err = fbhw->decode_var(var, &par);
+ if (err)
+ return err;
+
+ /* Encode (possibly rounded) screen parameters */
+ fbhw->encode_var(var, &par);
+ return 0;
+}
+
+ /* actually set hw par by decoding var, then setting hardware from
+ * hw par just decoded */
+static int atafb_set_par(struct fb_info *info)
+{
+ struct atafb_par *par = (struct atafb_par *)info->par;
+
+ /* Decode wanted screen parameters */
+ fbhw->decode_var(&info->var, par);
+ fbhw->encode_fix(&info->fix, par);
+
+ /* Set new videomode */
+ ata_set_par(par);
+
return 0;
}
+
static struct fb_ops atafb_ops = {
.owner = THIS_MODULE,
- .fb_get_fix = atafb_get_fix,
- .fb_get_var = atafb_get_var,
- .fb_set_var = atafb_set_var,
- .fb_get_cmap = atafb_get_cmap,
- .fb_set_cmap = gen_set_cmap,
- .fb_pan_display =atafb_pan_display,
+ .fb_check_var = atafb_check_var,
+ .fb_set_par = atafb_set_par,
+ .fb_setcolreg = atafb_setcolreg,
.fb_blank = atafb_blank,
+ .fb_pan_display = atafb_pan_display,
+ .fb_fillrect = atafb_fillrect,
+ .fb_copyarea = atafb_copyarea,
+ .fb_imageblit = atafb_imageblit,
.fb_ioctl = atafb_ioctl,
};
-static void
-check_default_par( int detected_mode )
+static void check_default_par(int detected_mode)
{
char default_name[10];
int i;
@@ -2642,199 +2794,41 @@ check_default_par( int detected_mode )
/* First try the user supplied mode */
if (default_par) {
- var=atafb_predefined[default_par-1];
+ var = atafb_predefined[default_par - 1];
var.activate = FB_ACTIVATE_TEST;
- if (do_fb_set_var(&var,1))
- default_par=0; /* failed */
+ if (do_fb_set_var(&var, 1))
+ default_par = 0; /* failed */
}
/* Next is the autodetected one */
- if (! default_par) {
- var=atafb_predefined[detected_mode-1]; /* autodetect */
+ if (!default_par) {
+ var = atafb_predefined[detected_mode - 1]; /* autodetect */
var.activate = FB_ACTIVATE_TEST;
- if (!do_fb_set_var(&var,1))
- default_par=detected_mode;
+ if (!do_fb_set_var(&var, 1))
+ default_par = detected_mode;
}
/* If that also failed, try some default modes... */
- if (! default_par) {
+ if (!default_par) {
/* try default1, default2... */
- for (i=1 ; i < 10 ; i++) {
- sprintf(default_name,"default%d",i);
- default_par=get_video_mode(default_name);
- if (! default_par)
+ for (i = 1; i < 10; i++) {
+ sprintf(default_name,"default%d", i);
+ default_par = get_video_mode(default_name);
+ if (!default_par)
panic("can't set default video mode");
- var=atafb_predefined[default_par-1];
+ var = atafb_predefined[default_par - 1];
var.activate = FB_ACTIVATE_TEST;
- if (! do_fb_set_var(&var,1))
+ if (!do_fb_set_var(&var,1))
break; /* ok */
}
}
- min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8;
+ min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8;
if (default_mem_req < min_mem)
- default_mem_req=min_mem;
-}
-
-static int
-atafb_switch(int con, struct fb_info *info)
-{
- /* Do we have to save the colormap ? */
- if (fb_display[info->currcon].cmap.len)
- fb_get_cmap(&fb_display[info->currcon].cmap, 1, fbhw->getcolreg,
- info);
- do_fb_set_var(&fb_display[con].var,1);
- info->currcon=con;
- /* Install new colormap */
- do_install_cmap(con, info);
- return 0;
-}
-
-int __init atafb_init(void)
-{
- int pad;
- int detected_mode;
- unsigned long mem_req;
-
- if (!MACH_IS_ATARI)
- return -ENXIO;
-
- do {
-#ifdef ATAFB_EXT
- if (external_addr) {
- fbhw = &ext_switch;
- atafb_ops.fb_setcolreg = &ext_setcolreg;
- break;
- }
-#endif
-#ifdef ATAFB_TT
- if (ATARIHW_PRESENT(TT_SHIFTER)) {
- fbhw = &tt_switch;
- atafb_ops.fb_setcolreg = &tt_setcolreg;
- break;
- }
-#endif
-#ifdef ATAFB_FALCON
- if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
- fbhw = &falcon_switch;
- atafb_ops.fb_setcolreg = &falcon_setcolreg;
- request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
- "framebuffer/modeswitch", falcon_vbl_switcher);
- break;
- }
-#endif
-#ifdef ATAFB_STE
- if (ATARIHW_PRESENT(STND_SHIFTER) ||
- ATARIHW_PRESENT(EXTD_SHIFTER)) {
- fbhw = &st_switch;
- atafb_ops.fb_setcolreg = &stste_setcolreg;
- break;
- }
- fbhw = &st_switch;
- atafb_ops.fb_setcolreg = &stste_setcolreg;
- printk("Cannot determine video hardware; defaulting to ST(e)\n");
-#else /* ATAFB_STE */
- /* no default driver included */
- /* Nobody will ever see this message :-) */
- panic("Cannot initialize video hardware");
-#endif
- } while (0);
-
- /* Multisync monitor capabilities */
- /* Atari-TOS defaults if no boot option present */
- if (fb_info.monspecs.hfmin == 0) {
- fb_info.monspecs.hfmin = 31000;
- fb_info.monspecs.hfmax = 32000;
- fb_info.monspecs.vfmin = 58;
- fb_info.monspecs.vfmax = 62;
- }
-
- detected_mode = fbhw->detect();
- check_default_par(detected_mode);
-#ifdef ATAFB_EXT
- if (!external_addr) {
-#endif /* ATAFB_EXT */
- mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
- mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
- screen_base = atari_stram_alloc(mem_req, "atafb");
- if (!screen_base)
- panic("Cannot allocate screen memory");
- memset(screen_base, 0, mem_req);
- pad = -(unsigned long)screen_base & (PAGE_SIZE-1);
- screen_base+=pad;
- real_screen_base=screen_base+ovsc_offset;
- screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
- st_ovsc_switch();
- if (CPU_IS_040_OR_060) {
- /* On a '040+, the cache mode of video RAM must be set to
- * write-through also for internal video hardware! */
- cache_push(virt_to_phys(screen_base), screen_len);
- kernel_set_cachemode(screen_base, screen_len,
- IOMAP_WRITETHROUGH);
- }
-#ifdef ATAFB_EXT
- }
- else {
- /* Map the video memory (physical address given) to somewhere
- * in the kernel address space.
- */
- external_addr =
- ioremap_writethrough((unsigned long)external_addr,
- external_len);
- if (external_vgaiobase)
- external_vgaiobase =
- (unsigned long)ioremap(external_vgaiobase, 0x10000);
- screen_base =
- real_screen_base = external_addr;
- screen_len = external_len & PAGE_MASK;
- memset (screen_base, 0, external_len);
- }
-#endif /* ATAFB_EXT */
-
- strcpy(fb_info.modename, "Atari Builtin ");
- fb_info.changevar = NULL;
- fb_info.fbops = &atafb_ops;
- fb_info.disp = &disp;
- fb_info.currcon = -1;
- fb_info.switch_con = &atafb_switch;
- fb_info.updatevar = &fb_update_var;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
- do_fb_set_var(&atafb_predefined[default_par-1], 1);
- strcat(fb_info.modename, fb_var_names[default_par-1][0]);
-
- atafb_get_var(&disp.var, -1, &fb_info);
- atafb_set_disp(-1, &fb_info);
- do_install_cmap(0, &fb_info);
-
- if (register_framebuffer(&fb_info) < 0) {
-#ifdef ATAFB_EXT
- if (external_addr) {
- iounmap(external_addr);
- external_addr = NULL;
- }
- if (external_vgaiobase) {
- iounmap((void*)external_vgaiobase);
- external_vgaiobase = 0;
- }
-#endif
- return -EINVAL;
- }
-
- printk("Determined %dx%d, depth %d\n",
- disp.var.xres, disp.var.yres, disp.var.bits_per_pixel);
- if ((disp.var.xres != disp.var.xres_virtual) ||
- (disp.var.yres != disp.var.yres_virtual))
- printk(" virtual %dx%d\n",
- disp.var.xres_virtual, disp.var.yres_virtual);
- printk("fb%d: %s frame buffer device, using %dK of video memory\n",
- fb_info.node, fb_info.modename, screen_len>>10);
-
- /* TODO: This driver cannot be unloaded yet */
- return 0;
+ default_mem_req = min_mem;
}
-
#ifdef ATAFB_EXT
static void __init atafb_setup_ext(char *spec)
{
- int xres, xres_virtual, yres, depth, planes;
+ int xres, xres_virtual, yres, depth, planes;
unsigned long addr, len;
char *p;
@@ -2848,27 +2842,31 @@ static void __init atafb_setup_ext(char *spec)
*
* Even xres_virtual is available, we neither support panning nor hw-scrolling!
*/
- if (!(p = strsep(&spec, ";")) || !*p)
- return;
+ p = strsep(&spec, ";");
+ if (!p || !*p)
+ return;
xres_virtual = xres = simple_strtoul(p, NULL, 10);
if (xres <= 0)
- return;
+ return;
- if (!(p = strsep(&spec, ";")) || !*p)
- return;
+ p = strsep(&spec, ";");
+ if (!p || !*p)
+ return;
yres = simple_strtoul(p, NULL, 10);
if (yres <= 0)
- return;
+ return;
- if (!(p = strsep(&spec, ";")) || !*p)
- return;
+ p = strsep(&spec, ";");
+ if (!p || !*p)
+ return;
depth = simple_strtoul(p, NULL, 10);
if (depth != 1 && depth != 2 && depth != 4 && depth != 8 &&
- depth != 16 && depth != 24)
- return;
+ depth != 16 && depth != 24)
+ return;
- if (!(p = strsep(&spec, ";")) || !*p)
- return;
+ p = strsep(&spec, ";");
+ if (!p || !*p)
+ return;
if (*p == 'i')
planes = FB_TYPE_INTERLEAVED_PLANES;
else if (*p == 'p')
@@ -2876,25 +2874,27 @@ static void __init atafb_setup_ext(char *spec)
else if (*p == 'n')
planes = FB_TYPE_PLANES;
else if (*p == 't')
- planes = -1; /* true color */
+ planes = -1; /* true color */
else
return;
-
- if (!(p = strsep(&spec, ";")) || !*p)
+ p = strsep(&spec, ";");
+ if (!p || !*p)
return;
addr = simple_strtoul(p, NULL, 0);
- if (!(p = strsep(&spec, ";")) || !*p)
- len = xres*yres*depth/8;
+ p = strsep(&spec, ";");
+ if (!p || !*p)
+ len = xres * yres * depth / 8;
else
len = simple_strtoul(p, NULL, 0);
- if ((p = strsep(&spec, ";")) && *p) {
- external_vgaiobase=simple_strtoul(p, NULL, 0);
- }
+ p = strsep(&spec, ";");
+ if (p && *p)
+ external_vgaiobase = simple_strtoul(p, NULL, 0);
- if ((p = strsep(&spec, ";")) && *p) {
+ p = strsep(&spec, ";");
+ if (p && *p) {
external_bitspercol = simple_strtoul(p, NULL, 0);
if (external_bitspercol > 8)
external_bitspercol = 8;
@@ -2902,59 +2902,61 @@ static void __init atafb_setup_ext(char *spec)
external_bitspercol = 1;
}
- if ((p = strsep(&spec, ";")) && *p) {
+ p = strsep(&spec, ";");
+ if (p && *p) {
if (!strcmp(p, "vga"))
external_card_type = IS_VGA;
if (!strcmp(p, "mv300"))
external_card_type = IS_MV300;
}
- if ((p = strsep(&spec, ";")) && *p) {
+ p = strsep(&spec, ";");
+ if (p && *p) {
xres_virtual = simple_strtoul(p, NULL, 10);
if (xres_virtual < xres)
xres_virtual = xres;
- if (xres_virtual*yres*depth/8 > len)
- len=xres_virtual*yres*depth/8;
+ if (xres_virtual * yres * depth / 8 > len)
+ len = xres_virtual * yres * depth / 8;
}
- external_xres = xres;
- external_xres_virtual = xres_virtual;
- external_yres = yres;
+ external_xres = xres;
+ external_xres_virtual = xres_virtual;
+ external_yres = yres;
external_depth = depth;
external_pmode = planes;
- external_addr = (void *)addr;
- external_len = len;
-
- if (external_card_type == IS_MV300)
- switch (external_depth) {
- case 1:
- MV300_reg = MV300_reg_1bit;
- break;
- case 4:
- MV300_reg = MV300_reg_4bit;
- break;
- case 8:
- MV300_reg = MV300_reg_8bit;
- break;
- }
+ external_addr = (void *)addr;
+ external_len = len;
+
+ if (external_card_type == IS_MV300) {
+ switch (external_depth) {
+ case 1:
+ MV300_reg = MV300_reg_1bit;
+ break;
+ case 4:
+ MV300_reg = MV300_reg_4bit;
+ break;
+ case 8:
+ MV300_reg = MV300_reg_8bit;
+ break;
+ }
+ }
}
#endif /* ATAFB_EXT */
-
static void __init atafb_setup_int(char *spec)
{
/* Format to config extended internal video hardware like OverScan:
- "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
- Explanation:
- <xres>: x-resolution
- <yres>: y-resolution
- The following are only needed if you have an overscan which
- needs a black border:
- <xres_max>: max. length of a line in pixels your OverScan hardware would allow
- <yres_max>: max. number of lines your OverScan hardware would allow
- <offset>: Offset from physical beginning to visible beginning
- of screen in bytes
- */
+ * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>"
+ * Explanation:
+ * <xres>: x-resolution
+ * <yres>: y-resolution
+ * The following are only needed if you have an overscan which
+ * needs a black border:
+ * <xres_max>: max. length of a line in pixels your OverScan hardware would allow
+ * <yres_max>: max. number of lines your OverScan hardware would allow
+ * <offset>: Offset from physical beginning to visible beginning
+ * of screen in bytes
+ */
int xres;
char *p;
@@ -2963,23 +2965,19 @@ static void __init atafb_setup_int(char *spec)
xres = simple_strtoul(p, NULL, 10);
if (!(p = strsep(&spec, ";")) || !*p)
return;
- sttt_xres=xres;
- tt_yres=st_yres=simple_strtoul(p, NULL, 10);
- if ((p=strsep(&spec, ";")) && *p) {
- sttt_xres_virtual=simple_strtoul(p, NULL, 10);
- }
- if ((p=strsep(&spec, ";")) && *p) {
- sttt_yres_virtual=simple_strtoul(p, NULL, 0);
- }
- if ((p=strsep(&spec, ";")) && *p) {
- ovsc_offset=simple_strtoul(p, NULL, 0);
- }
+ sttt_xres = xres;
+ tt_yres = st_yres = simple_strtoul(p, NULL, 10);
+ if ((p = strsep(&spec, ";")) && *p)
+ sttt_xres_virtual = simple_strtoul(p, NULL, 10);
+ if ((p = strsep(&spec, ";")) && *p)
+ sttt_yres_virtual = simple_strtoul(p, NULL, 0);
+ if ((p = strsep(&spec, ";")) && *p)
+ ovsc_offset = simple_strtoul(p, NULL, 0);
if (ovsc_offset || (sttt_yres_virtual != st_yres))
- use_hwscroll=0;
+ use_hwscroll = 0;
}
-
#ifdef ATAFB_FALCON
static void __init atafb_setup_mcap(char *spec)
{
@@ -3018,7 +3016,6 @@ static void __init atafb_setup_mcap(char *spec)
}
#endif /* ATAFB_FALCON */
-
static void __init atafb_setup_user(char *spec)
{
/* Format of user defined video mode is: <xres>;<yres>;<depth>
@@ -3026,81 +3023,257 @@ static void __init atafb_setup_user(char *spec)
char *p;
int xres, yres, depth, temp;
- if (!(p = strsep(&spec, ";")) || !*p)
+ p = strsep(&spec, ";");
+ if (!p || !*p)
return;
xres = simple_strtoul(p, NULL, 10);
- if (!(p = strsep(&spec, ";")) || !*p)
+ p = strsep(&spec, ";");
+ if (!p || !*p)
return;
yres = simple_strtoul(p, NULL, 10);
- if (!(p = strsep(&spec, "")) || !*p)
+ p = strsep(&spec, "");
+ if (!p || !*p)
return;
depth = simple_strtoul(p, NULL, 10);
- if ((temp=get_video_mode("user0"))) {
- default_par=temp;
- atafb_predefined[default_par-1].xres = xres;
- atafb_predefined[default_par-1].yres = yres;
- atafb_predefined[default_par-1].bits_per_pixel = depth;
+ temp = get_video_mode("user0");
+ if (temp) {
+ default_par = temp;
+ atafb_predefined[default_par - 1].xres = xres;
+ atafb_predefined[default_par - 1].yres = yres;
+ atafb_predefined[default_par - 1].bits_per_pixel = depth;
}
}
-int __init atafb_setup( char *options )
+int __init atafb_setup(char *options)
{
- char *this_opt;
- int temp;
-
- fb_info.fontname[0] = '\0';
+ char *this_opt;
+ int temp;
- if (!options || !*options)
+ if (!options || !*options)
return 0;
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) continue;
- if ((temp=get_video_mode(this_opt)))
- default_par=temp;
- else if (! strcmp(this_opt, "inverse"))
- inverse=1;
- else if (!strncmp(this_opt, "font:", 5))
- strcpy(fb_info.fontname, this_opt+5);
- else if (! strncmp(this_opt, "hwscroll_",9)) {
- hwscroll=simple_strtoul(this_opt+9, NULL, 10);
- if (hwscroll < 0)
- hwscroll = 0;
- if (hwscroll > 200)
- hwscroll = 200;
- }
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+ if ((temp = get_video_mode(this_opt))) {
+ default_par = temp;
+ mode_option = this_opt;
+ } else if (!strcmp(this_opt, "inverse"))
+ inverse = 1;
+ else if (!strncmp(this_opt, "hwscroll_", 9)) {
+ hwscroll = simple_strtoul(this_opt + 9, NULL, 10);
+ if (hwscroll < 0)
+ hwscroll = 0;
+ if (hwscroll > 200)
+ hwscroll = 200;
+ }
#ifdef ATAFB_EXT
- else if (!strcmp(this_opt,"mv300")) {
- external_bitspercol = 8;
- external_card_type = IS_MV300;
+ else if (!strcmp(this_opt, "mv300")) {
+ external_bitspercol = 8;
+ external_card_type = IS_MV300;
+ } else if (!strncmp(this_opt, "external:", 9))
+ atafb_setup_ext(this_opt + 9);
+#endif
+ else if (!strncmp(this_opt, "internal:", 9))
+ atafb_setup_int(this_opt + 9);
+#ifdef ATAFB_FALCON
+ else if (!strncmp(this_opt, "eclock:", 7)) {
+ fext.f = simple_strtoul(this_opt + 7, NULL, 10);
+ /* external pixelclock in kHz --> ps */
+ fext.t = 1000000000 / fext.f;
+ fext.f *= 1000;
+ } else if (!strncmp(this_opt, "monitorcap:", 11))
+ atafb_setup_mcap(this_opt + 11);
+#endif
+ else if (!strcmp(this_opt, "keep"))
+ DontCalcRes = 1;
+ else if (!strncmp(this_opt, "R", 1))
+ atafb_setup_user(this_opt + 1);
}
- else if (!strncmp(this_opt,"external:",9))
- atafb_setup_ext(this_opt+9);
+ return 0;
+}
+
+int __init atafb_init(void)
+{
+ int pad;
+ int detected_mode;
+ unsigned int defmode = 0;
+ unsigned long mem_req;
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("atafb", &option))
+ return -ENODEV;
+ atafb_setup(option);
+#endif
+ printk("atafb_init: start\n");
+
+ if (!MACH_IS_ATARI)
+ return -ENXIO;
+
+ do {
+#ifdef ATAFB_EXT
+ if (external_addr) {
+ printk("atafb_init: initializing external hw\n");
+ fbhw = &ext_switch;
+ atafb_ops.fb_setcolreg = &ext_setcolreg;
+ defmode = DEFMODE_EXT;
+ break;
+ }
+#endif
+#ifdef ATAFB_TT
+ if (ATARIHW_PRESENT(TT_SHIFTER)) {
+ printk("atafb_init: initializing TT hw\n");
+ fbhw = &tt_switch;
+ atafb_ops.fb_setcolreg = &tt_setcolreg;
+ defmode = DEFMODE_TT;
+ break;
+ }
#endif
- else if (!strncmp(this_opt,"internal:",9))
- atafb_setup_int(this_opt+9);
#ifdef ATAFB_FALCON
- else if (!strncmp(this_opt, "eclock:", 7)) {
- fext.f = simple_strtoul(this_opt+7, NULL, 10);
- /* external pixelclock in kHz --> ps */
- fext.t = 1000000000/fext.f;
- fext.f *= 1000;
+ if (ATARIHW_PRESENT(VIDEL_SHIFTER)) {
+ printk("atafb_init: initializing Falcon hw\n");
+ fbhw = &falcon_switch;
+ atafb_ops.fb_setcolreg = &falcon_setcolreg;
+ request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO,
+ "framebuffer/modeswitch", falcon_vbl_switcher);
+ defmode = DEFMODE_F30;
+ break;
+ }
+#endif
+#ifdef ATAFB_STE
+ if (ATARIHW_PRESENT(STND_SHIFTER) ||
+ ATARIHW_PRESENT(EXTD_SHIFTER)) {
+ printk("atafb_init: initializing ST/E hw\n");
+ fbhw = &st_switch;
+ atafb_ops.fb_setcolreg = &stste_setcolreg;
+ defmode = DEFMODE_STE;
+ break;
+ }
+ fbhw = &st_switch;
+ atafb_ops.fb_setcolreg = &stste_setcolreg;
+ printk("Cannot determine video hardware; defaulting to ST(e)\n");
+#else /* ATAFB_STE */
+ /* no default driver included */
+ /* Nobody will ever see this message :-) */
+ panic("Cannot initialize video hardware");
+#endif
+ } while (0);
+
+ /* Multisync monitor capabilities */
+ /* Atari-TOS defaults if no boot option present */
+ if (fb_info.monspecs.hfmin == 0) {
+ fb_info.monspecs.hfmin = 31000;
+ fb_info.monspecs.hfmax = 32000;
+ fb_info.monspecs.vfmin = 58;
+ fb_info.monspecs.vfmax = 62;
}
- else if (!strncmp(this_opt, "monitorcap:", 11))
- atafb_setup_mcap(this_opt+11);
+
+ detected_mode = fbhw->detect();
+ check_default_par(detected_mode);
+#ifdef ATAFB_EXT
+ if (!external_addr) {
+#endif /* ATAFB_EXT */
+ mem_req = default_mem_req + ovsc_offset + ovsc_addlen;
+ mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE;
+ screen_base = atari_stram_alloc(mem_req, "atafb");
+ if (!screen_base)
+ panic("Cannot allocate screen memory");
+ memset(screen_base, 0, mem_req);
+ pad = -(unsigned long)screen_base & (PAGE_SIZE - 1);
+ screen_base += pad;
+ real_screen_base = screen_base + ovsc_offset;
+ screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK;
+ st_ovsc_switch();
+ if (CPU_IS_040_OR_060) {
+ /* On a '040+, the cache mode of video RAM must be set to
+ * write-through also for internal video hardware! */
+ cache_push(virt_to_phys(screen_base), screen_len);
+ kernel_set_cachemode(screen_base, screen_len,
+ IOMAP_WRITETHROUGH);
+ }
+ printk("atafb: screen_base %p real_screen_base %p screen_len %d\n",
+ screen_base, real_screen_base, screen_len);
+#ifdef ATAFB_EXT
+ } else {
+ /* Map the video memory (physical address given) to somewhere
+ * in the kernel address space.
+ */
+ external_addr = ioremap_writethrough((unsigned long)external_addr,
+ external_len);
+ if (external_vgaiobase)
+ external_vgaiobase =
+ (unsigned long)ioremap(external_vgaiobase, 0x10000);
+ screen_base =
+ real_screen_base = external_addr;
+ screen_len = external_len & PAGE_MASK;
+ memset (screen_base, 0, external_len);
+ }
+#endif /* ATAFB_EXT */
+
+// strcpy(fb_info.mode->name, "Atari Builtin ");
+ fb_info.fbops = &atafb_ops;
+ // try to set default (detected; requested) var
+ do_fb_set_var(&atafb_predefined[default_par - 1], 1);
+ // reads hw state into current par, which may not be sane yet
+ ata_get_par(&current_par);
+ fb_info.par = &current_par;
+ // tries to read from HW which may not be initialized yet
+ // so set sane var first, then call atafb_set_par
+ atafb_get_var(&fb_info.var, &fb_info);
+ fb_info.flags = FBINFO_FLAG_DEFAULT;
+
+ if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb,
+ NUM_TOTAL_MODES, &atafb_modedb[defmode],
+ fb_info.var.bits_per_pixel)) {
+ return -EINVAL;
+ }
+
+ atafb_set_disp(&fb_info);
+
+ fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0);
+
+
+ printk("Determined %dx%d, depth %d\n",
+ fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel);
+ if ((fb_info.var.xres != fb_info.var.xres_virtual) ||
+ (fb_info.var.yres != fb_info.var.yres_virtual))
+ printk(" virtual %dx%d\n", fb_info.var.xres_virtual,
+ fb_info.var.yres_virtual);
+
+ if (register_framebuffer(&fb_info) < 0) {
+#ifdef ATAFB_EXT
+ if (external_addr) {
+ iounmap(external_addr);
+ external_addr = NULL;
+ }
+ if (external_vgaiobase) {
+ iounmap((void*)external_vgaiobase);
+ external_vgaiobase = 0;
+ }
#endif
- else if (!strcmp(this_opt, "keep"))
- DontCalcRes = 1;
- else if (!strncmp(this_opt, "R", 1))
- atafb_setup_user(this_opt+1);
- }
- return 0;
+ return -EINVAL;
+ }
+
+ // FIXME: mode needs setting!
+ //printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+ // fb_info.node, fb_info.mode->name, screen_len>>10);
+ printk("fb%d: frame buffer device, using %dK of video memory\n",
+ fb_info.node, screen_len >> 10);
+
+ /* TODO: This driver cannot be unloaded yet */
+ return 0;
}
+module_init(atafb_init);
+
#ifdef MODULE
MODULE_LICENSE("GPL");
-int init_module(void)
+int cleanup_module(void)
{
- return atafb_init();
+ unregister_framebuffer(&fb_info);
+ return atafb_deinit();
}
#endif /* MODULE */
diff --git a/drivers/video/atafb.h b/drivers/video/atafb.h
new file mode 100644
index 00000000000..014e05906cb
--- /dev/null
+++ b/drivers/video/atafb.h
@@ -0,0 +1,36 @@
+#ifndef _VIDEO_ATAFB_H
+#define _VIDEO_ATAFB_H
+
+void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+ int dx, int height, int width);
+void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width);
+void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor);
+
+void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+ int dx, int height, int width);
+void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width);
+void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor);
+
+void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+ int dx, int height, int width);
+void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width);
+void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor);
+
+void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy,
+ int dx, int height, int width);
+void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width);
+void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor);
+
+#endif /* _VIDEO_ATAFB_H */
diff --git a/drivers/video/atafb_iplan2p2.c b/drivers/video/atafb_iplan2p2.c
new file mode 100644
index 00000000000..8cc9c50379d
--- /dev/null
+++ b/drivers/video/atafb_iplan2p2.c
@@ -0,0 +1,293 @@
+/*
+ * linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for
+ * interleaved bitplanes à la Atari (2
+ * planes, 2 bytes interleave)
+ *
+ * Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+
+#include "atafb.h"
+
+#define BPL 2
+#include "atafb_utils.h"
+
+void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line,
+ int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ /* bmove() has to distinguish two major cases: If both, source and
+ * destination, start at even addresses or both are at odd
+ * addresses, just the first odd and last even column (if present)
+ * require special treatment (memmove_col()). The rest between
+ * then can be copied by normal operations, because all adjacent
+ * bytes are affected and are to be stored in the same order.
+ * The pathological case is when the move should go from an odd
+ * address to an even or vice versa. Since the bytes in the plane
+ * words must be assembled in new order, it seems wisest to make
+ * all movements by memmove_col().
+ */
+
+ u8 *src, *dst;
+ u32 *s, *d;
+ int w, l , i, j;
+ u_int colsize;
+ u_int upwards = (dy < sy) || (dy == sy && dx < sx);
+
+ colsize = height;
+ if (!((sx ^ dx) & 15)) {
+ /* odd->odd or even->even */
+
+ if (upwards) {
+ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+ if (sx & 15) {
+ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
+ src += BPL * 2;
+ dst += BPL * 2;
+ width -= 8;
+ }
+ w = width >> 4;
+ if (w) {
+ s = (u32 *)src;
+ d = (u32 *)dst;
+ w *= BPL / 2;
+ l = next_line - w * 4;
+ for (j = height; j > 0; j--) {
+ for (i = w; i > 0; i--)
+ *d++ = *s++;
+ s = (u32 *)((u8 *)s + l);
+ d = (u32 *)((u8 *)d + l);
+ }
+ }
+ if (width & 15)
+ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
+ 0xff00ff00, height, next_line - BPL * 2);
+ } else {
+ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+ if ((sx + width) & 15) {
+ src -= BPL * 2;
+ dst -= BPL * 2;
+ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
+ width -= 8;
+ }
+ w = width >> 4;
+ if (w) {
+ s = (u32 *)src;
+ d = (u32 *)dst;
+ w *= BPL / 2;
+ l = next_line - w * 4;
+ for (j = height; j > 0; j--) {
+ for (i = w; i > 0; i--)
+ *--d = *--s;
+ s = (u32 *)((u8 *)s - l);
+ d = (u32 *)((u8 *)d - l);
+ }
+ }
+ if (sx & 15)
+ memmove32_col(dst - (width - 16) / (8 / BPL),
+ src - (width - 16) / (8 / BPL),
+ 0xff00ff, colsize, -next_line - BPL * 2);
+ }
+ } else {
+ /* odd->even or even->odd */
+ if (upwards) {
+ u32 *src32, *dst32;
+ u32 pval[4], v, v1, mask;
+ int i, j, w, f;
+
+ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+
+ mask = 0xff00ff00;
+ f = 0;
+ w = width;
+ if (sx & 15) {
+ f = 1;
+ w += 8;
+ }
+ if ((sx + width) & 15)
+ f |= 2;
+ w >>= 4;
+ for (i = height; i; i--) {
+ src32 = (u32 *)src;
+ dst32 = (u32 *)dst;
+
+ if (f & 1) {
+ pval[0] = (*src32++ << 8) & mask;
+ } else {
+ pval[0] = dst32[0] & mask;
+ }
+
+ for (j = w; j > 0; j--) {
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[0] | (v1 >> 8);
+ pval[0] = (v ^ v1) << 8;
+ }
+
+ if (f & 2) {
+ dst32[0] = (dst32[0] & mask) | pval[0];
+ }
+
+ src += next_line;
+ dst += next_line;
+ }
+ } else {
+ u32 *src32, *dst32;
+ u32 pval[4], v, v1, mask;
+ int i, j, w, f;
+
+ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+ mask = 0xff00ff;
+ f = 0;
+ w = width;
+ if ((dx + width) & 15)
+ f = 1;
+ if (sx & 15) {
+ f |= 2;
+ w += 8;
+ }
+ w >>= 4;
+ for (i = height; i; i--) {
+ src32 = (u32 *)src;
+ dst32 = (u32 *)dst;
+
+ if (f & 1) {
+ pval[0] = dst32[-1] & mask;
+ } else {
+ pval[0] = (*--src32 >> 8) & mask;
+ }
+
+ for (j = w; j > 0; j--) {
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[0] | (v1 << 8);
+ pval[0] = (v ^ v1) >> 8;
+ }
+
+ if (!(f & 2)) {
+ dst32[-1] = (dst32[-1] & mask) | pval[0];
+ }
+
+ src -= next_line;
+ dst -= next_line;
+ }
+ }
+ }
+}
+
+void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width)
+{
+ u32 *dest;
+ int rows, i;
+ u32 cval[4];
+
+ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
+ if (sx & 15) {
+ u8 *dest8 = (u8 *)dest + 1;
+
+ expand8_col2mask(color, cval);
+
+ for (i = height; i; i--) {
+ fill8_col(dest8, cval);
+ dest8 += next_line;
+ }
+ dest += BPL / 2;
+ width -= 8;
+ }
+
+ expand16_col2mask(color, cval);
+ rows = width >> 4;
+ if (rows) {
+ u32 *d = dest;
+ u32 off = next_line - rows * BPL * 2;
+ for (i = height; i; i--) {
+ d = fill16_col(d, rows, cval);
+ d = (u32 *)((long)d + off);
+ }
+ dest += rows * BPL / 2;
+ width &= 15;
+ }
+
+ if (width) {
+ u8 *dest8 = (u8 *)dest;
+
+ expand8_col2mask(color, cval);
+
+ for (i = height; i; i--) {
+ fill8_col(dest8, cval);
+ dest8 += next_line;
+ }
+ }
+}
+
+void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+ u32 *dest;
+ const u16 *data16;
+ int rows;
+ u32 fgm[4], bgm[4], m;
+
+ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
+ if (dx & 15) {
+ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
+ dest += BPL / 2;
+ width -= 8;
+ }
+
+ if (width >= 16) {
+ data16 = (const u16 *)data;
+ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
+
+ for (rows = width / 16; rows; rows--) {
+ u16 d = *data16++;
+ m = d | ((u32)d << 16);
+ *dest++ = (m & fgm[0]) ^ bgm[0];
+ }
+
+ data = (const u8 *)data16;
+ width &= 15;
+ }
+
+ if (width)
+ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(atafb_iplan2p2_copyarea);
+EXPORT_SYMBOL(atafb_iplan2p2_fillrect);
+EXPORT_SYMBOL(atafb_iplan2p2_linefill);
diff --git a/drivers/video/atafb_iplan2p4.c b/drivers/video/atafb_iplan2p4.c
new file mode 100644
index 00000000000..bee0d89463f
--- /dev/null
+++ b/drivers/video/atafb_iplan2p4.c
@@ -0,0 +1,308 @@
+/*
+ * linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for
+ * interleaved bitplanes à la Atari (4
+ * planes, 2 bytes interleave)
+ *
+ * Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+
+#include "atafb.h"
+
+#define BPL 4
+#include "atafb_utils.h"
+
+void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line,
+ int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ /* bmove() has to distinguish two major cases: If both, source and
+ * destination, start at even addresses or both are at odd
+ * addresses, just the first odd and last even column (if present)
+ * require special treatment (memmove_col()). The rest between
+ * then can be copied by normal operations, because all adjacent
+ * bytes are affected and are to be stored in the same order.
+ * The pathological case is when the move should go from an odd
+ * address to an even or vice versa. Since the bytes in the plane
+ * words must be assembled in new order, it seems wisest to make
+ * all movements by memmove_col().
+ */
+
+ u8 *src, *dst;
+ u32 *s, *d;
+ int w, l , i, j;
+ u_int colsize;
+ u_int upwards = (dy < sy) || (dy == sy && dx < sx);
+
+ colsize = height;
+ if (!((sx ^ dx) & 15)) {
+ /* odd->odd or even->even */
+
+ if (upwards) {
+ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+ if (sx & 15) {
+ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
+ src += BPL * 2;
+ dst += BPL * 2;
+ width -= 8;
+ }
+ w = width >> 4;
+ if (w) {
+ s = (u32 *)src;
+ d = (u32 *)dst;
+ w *= BPL / 2;
+ l = next_line - w * 4;
+ for (j = height; j > 0; j--) {
+ for (i = w; i > 0; i--)
+ *d++ = *s++;
+ s = (u32 *)((u8 *)s + l);
+ d = (u32 *)((u8 *)d + l);
+ }
+ }
+ if (width & 15)
+ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
+ 0xff00ff00, height, next_line - BPL * 2);
+ } else {
+ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+ if ((sx + width) & 15) {
+ src -= BPL * 2;
+ dst -= BPL * 2;
+ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
+ width -= 8;
+ }
+ w = width >> 4;
+ if (w) {
+ s = (u32 *)src;
+ d = (u32 *)dst;
+ w *= BPL / 2;
+ l = next_line - w * 4;
+ for (j = height; j > 0; j--) {
+ for (i = w; i > 0; i--)
+ *--d = *--s;
+ s = (u32 *)((u8 *)s - l);
+ d = (u32 *)((u8 *)d - l);
+ }
+ }
+ if (sx & 15)
+ memmove32_col(dst - (width - 16) / (8 / BPL),
+ src - (width - 16) / (8 / BPL),
+ 0xff00ff, colsize, -next_line - BPL * 2);
+ }
+ } else {
+ /* odd->even or even->odd */
+ if (upwards) {
+ u32 *src32, *dst32;
+ u32 pval[4], v, v1, mask;
+ int i, j, w, f;
+
+ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+
+ mask = 0xff00ff00;
+ f = 0;
+ w = width;
+ if (sx & 15) {
+ f = 1;
+ w += 8;
+ }
+ if ((sx + width) & 15)
+ f |= 2;
+ w >>= 4;
+ for (i = height; i; i--) {
+ src32 = (u32 *)src;
+ dst32 = (u32 *)dst;
+
+ if (f & 1) {
+ pval[0] = (*src32++ << 8) & mask;
+ pval[1] = (*src32++ << 8) & mask;
+ } else {
+ pval[0] = dst32[0] & mask;
+ pval[1] = dst32[1] & mask;
+ }
+
+ for (j = w; j > 0; j--) {
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[0] | (v1 >> 8);
+ pval[0] = (v ^ v1) << 8;
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[1] | (v1 >> 8);
+ pval[1] = (v ^ v1) << 8;
+ }
+
+ if (f & 2) {
+ dst32[0] = (dst32[0] & mask) | pval[0];
+ dst32[1] = (dst32[1] & mask) | pval[1];
+ }
+
+ src += next_line;
+ dst += next_line;
+ }
+ } else {
+ u32 *src32, *dst32;
+ u32 pval[4], v, v1, mask;
+ int i, j, w, f;
+
+ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+ mask = 0xff00ff;
+ f = 0;
+ w = width;
+ if ((dx + width) & 15)
+ f = 1;
+ if (sx & 15) {
+ f |= 2;
+ w += 8;
+ }
+ w >>= 4;
+ for (i = height; i; i--) {
+ src32 = (u32 *)src;
+ dst32 = (u32 *)dst;
+
+ if (f & 1) {
+ pval[0] = dst32[-1] & mask;
+ pval[1] = dst32[-2] & mask;
+ } else {
+ pval[0] = (*--src32 >> 8) & mask;
+ pval[1] = (*--src32 >> 8) & mask;
+ }
+
+ for (j = w; j > 0; j--) {
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[0] | (v1 << 8);
+ pval[0] = (v ^ v1) >> 8;
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[1] | (v1 << 8);
+ pval[1] = (v ^ v1) >> 8;
+ }
+
+ if (!(f & 2)) {
+ dst32[-1] = (dst32[-1] & mask) | pval[0];
+ dst32[-2] = (dst32[-2] & mask) | pval[1];
+ }
+
+ src -= next_line;
+ dst -= next_line;
+ }
+ }
+ }
+}
+
+void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width)
+{
+ u32 *dest;
+ int rows, i;
+ u32 cval[4];
+
+ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
+ if (sx & 15) {
+ u8 *dest8 = (u8 *)dest + 1;
+
+ expand8_col2mask(color, cval);
+
+ for (i = height; i; i--) {
+ fill8_col(dest8, cval);
+ dest8 += next_line;
+ }
+ dest += BPL / 2;
+ width -= 8;
+ }
+
+ expand16_col2mask(color, cval);
+ rows = width >> 4;
+ if (rows) {
+ u32 *d = dest;
+ u32 off = next_line - rows * BPL * 2;
+ for (i = height; i; i--) {
+ d = fill16_col(d, rows, cval);
+ d = (u32 *)((long)d + off);
+ }
+ dest += rows * BPL / 2;
+ width &= 15;
+ }
+
+ if (width) {
+ u8 *dest8 = (u8 *)dest;
+
+ expand8_col2mask(color, cval);
+
+ for (i = height; i; i--) {
+ fill8_col(dest8, cval);
+ dest8 += next_line;
+ }
+ }
+}
+
+void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+ u32 *dest;
+ const u16 *data16;
+ int rows;
+ u32 fgm[4], bgm[4], m;
+
+ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
+ if (dx & 15) {
+ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
+ dest += BPL / 2;
+ width -= 8;
+ }
+
+ if (width >= 16) {
+ data16 = (const u16 *)data;
+ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
+
+ for (rows = width / 16; rows; rows--) {
+ u16 d = *data16++;
+ m = d | ((u32)d << 16);
+ *dest++ = (m & fgm[0]) ^ bgm[0];
+ *dest++ = (m & fgm[1]) ^ bgm[1];
+ }
+
+ data = (const u8 *)data16;
+ width &= 15;
+ }
+
+ if (width)
+ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(atafb_iplan2p4_copyarea);
+EXPORT_SYMBOL(atafb_iplan2p4_fillrect);
+EXPORT_SYMBOL(atafb_iplan2p4_linefill);
diff --git a/drivers/video/atafb_iplan2p8.c b/drivers/video/atafb_iplan2p8.c
new file mode 100644
index 00000000000..356fb52ce44
--- /dev/null
+++ b/drivers/video/atafb_iplan2p8.c
@@ -0,0 +1,345 @@
+/*
+ * linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for
+ * interleaved bitplanes à la Atari (8
+ * planes, 2 bytes interleave)
+ *
+ * Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include <asm/setup.h>
+
+#include "atafb.h"
+
+#define BPL 8
+#include "atafb_utils.h"
+
+
+/* Copies a 8 plane column from 's', height 'h', to 'd'. */
+
+/* This expands a 8 bit color into two longs for two movepl (8 plane)
+ * operations.
+ */
+
+void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line,
+ int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ /* bmove() has to distinguish two major cases: If both, source and
+ * destination, start at even addresses or both are at odd
+ * addresses, just the first odd and last even column (if present)
+ * require special treatment (memmove_col()). The rest between
+ * then can be copied by normal operations, because all adjacent
+ * bytes are affected and are to be stored in the same order.
+ * The pathological case is when the move should go from an odd
+ * address to an even or vice versa. Since the bytes in the plane
+ * words must be assembled in new order, it seems wisest to make
+ * all movements by memmove_col().
+ */
+
+ u8 *src, *dst;
+ u32 *s, *d;
+ int w, l , i, j;
+ u_int colsize;
+ u_int upwards = (dy < sy) || (dy == sy && dx < sx);
+
+ colsize = height;
+ if (!((sx ^ dx) & 15)) {
+ /* odd->odd or even->even */
+
+ if (upwards) {
+ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+ if (sx & 15) {
+ memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2);
+ src += BPL * 2;
+ dst += BPL * 2;
+ width -= 8;
+ }
+ w = width >> 4;
+ if (w) {
+ s = (u32 *)src;
+ d = (u32 *)dst;
+ w *= BPL / 2;
+ l = next_line - w * 4;
+ for (j = height; j > 0; j--) {
+ for (i = w; i > 0; i--)
+ *d++ = *s++;
+ s = (u32 *)((u8 *)s + l);
+ d = (u32 *)((u8 *)d + l);
+ }
+ }
+ if (width & 15)
+ memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL),
+ 0xff00ff00, height, next_line - BPL * 2);
+ } else {
+ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+ if ((sx + width) & 15) {
+ src -= BPL * 2;
+ dst -= BPL * 2;
+ memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2);
+ width -= 8;
+ }
+ w = width >> 4;
+ if (w) {
+ s = (u32 *)src;
+ d = (u32 *)dst;
+ w *= BPL / 2;
+ l = next_line - w * 4;
+ for (j = height; j > 0; j--) {
+ for (i = w; i > 0; i--)
+ *--d = *--s;
+ s = (u32 *)((u8 *)s - l);
+ d = (u32 *)((u8 *)d - l);
+ }
+ }
+ if (sx & 15)
+ memmove32_col(dst - (width - 16) / (8 / BPL),
+ src - (width - 16) / (8 / BPL),
+ 0xff00ff, colsize, -next_line - BPL * 2);
+ }
+ } else {
+ /* odd->even or even->odd */
+ if (upwards) {
+ u32 *src32, *dst32;
+ u32 pval[4], v, v1, mask;
+ int i, j, w, f;
+
+ src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL);
+
+ mask = 0xff00ff00;
+ f = 0;
+ w = width;
+ if (sx & 15) {
+ f = 1;
+ w += 8;
+ }
+ if ((sx + width) & 15)
+ f |= 2;
+ w >>= 4;
+ for (i = height; i; i--) {
+ src32 = (u32 *)src;
+ dst32 = (u32 *)dst;
+
+ if (f & 1) {
+ pval[0] = (*src32++ << 8) & mask;
+ pval[1] = (*src32++ << 8) & mask;
+ pval[2] = (*src32++ << 8) & mask;
+ pval[3] = (*src32++ << 8) & mask;
+ } else {
+ pval[0] = dst32[0] & mask;
+ pval[1] = dst32[1] & mask;
+ pval[2] = dst32[2] & mask;
+ pval[3] = dst32[3] & mask;
+ }
+
+ for (j = w; j > 0; j--) {
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[0] | (v1 >> 8);
+ pval[0] = (v ^ v1) << 8;
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[1] | (v1 >> 8);
+ pval[1] = (v ^ v1) << 8;
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[2] | (v1 >> 8);
+ pval[2] = (v ^ v1) << 8;
+ v = *src32++;
+ v1 = v & mask;
+ *dst32++ = pval[3] | (v1 >> 8);
+ pval[3] = (v ^ v1) << 8;
+ }
+
+ if (f & 2) {
+ dst32[0] = (dst32[0] & mask) | pval[0];
+ dst32[1] = (dst32[1] & mask) | pval[1];
+ dst32[2] = (dst32[2] & mask) | pval[2];
+ dst32[3] = (dst32[3] & mask) | pval[3];
+ }
+
+ src += next_line;
+ dst += next_line;
+ }
+ } else {
+ u32 *src32, *dst32;
+ u32 pval[4], v, v1, mask;
+ int i, j, w, f;
+
+ src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL);
+ dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL);
+
+ mask = 0xff00ff;
+ f = 0;
+ w = width;
+ if ((dx + width) & 15)
+ f = 1;
+ if (sx & 15) {
+ f |= 2;
+ w += 8;
+ }
+ w >>= 4;
+ for (i = height; i; i--) {
+ src32 = (u32 *)src;
+ dst32 = (u32 *)dst;
+
+ if (f & 1) {
+ pval[0] = dst32[-1] & mask;
+ pval[1] = dst32[-2] & mask;
+ pval[2] = dst32[-3] & mask;
+ pval[3] = dst32[-4] & mask;
+ } else {
+ pval[0] = (*--src32 >> 8) & mask;
+ pval[1] = (*--src32 >> 8) & mask;
+ pval[2] = (*--src32 >> 8) & mask;
+ pval[3] = (*--src32 >> 8) & mask;
+ }
+
+ for (j = w; j > 0; j--) {
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[0] | (v1 << 8);
+ pval[0] = (v ^ v1) >> 8;
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[1] | (v1 << 8);
+ pval[1] = (v ^ v1) >> 8;
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[2] | (v1 << 8);
+ pval[2] = (v ^ v1) >> 8;
+ v = *--src32;
+ v1 = v & mask;
+ *--dst32 = pval[3] | (v1 << 8);
+ pval[3] = (v ^ v1) >> 8;
+ }
+
+ if (!(f & 2)) {
+ dst32[-1] = (dst32[-1] & mask) | pval[0];
+ dst32[-2] = (dst32[-2] & mask) | pval[1];
+ dst32[-3] = (dst32[-3] & mask) | pval[2];
+ dst32[-4] = (dst32[-4] & mask) | pval[3];
+ }
+
+ src -= next_line;
+ dst -= next_line;
+ }
+ }
+ }
+}
+
+void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width)
+{
+ u32 *dest;
+ int rows, i;
+ u32 cval[4];
+
+ dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL));
+ if (sx & 15) {
+ u8 *dest8 = (u8 *)dest + 1;
+
+ expand8_col2mask(color, cval);
+
+ for (i = height; i; i--) {
+ fill8_col(dest8, cval);
+ dest8 += next_line;
+ }
+ dest += BPL / 2;
+ width -= 8;
+ }
+
+ expand16_col2mask(color, cval);
+ rows = width >> 4;
+ if (rows) {
+ u32 *d = dest;
+ u32 off = next_line - rows * BPL * 2;
+ for (i = height; i; i--) {
+ d = fill16_col(d, rows, cval);
+ d = (u32 *)((long)d + off);
+ }
+ dest += rows * BPL / 2;
+ width &= 15;
+ }
+
+ if (width) {
+ u8 *dest8 = (u8 *)dest;
+
+ expand8_col2mask(color, cval);
+
+ for (i = height; i; i--) {
+ fill8_col(dest8, cval);
+ dest8 += next_line;
+ }
+ }
+}
+
+void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+ u32 *dest;
+ const u16 *data16;
+ int rows;
+ u32 fgm[4], bgm[4], m;
+
+ dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL));
+ if (dx & 15) {
+ fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++);
+ dest += BPL / 2;
+ width -= 8;
+ }
+
+ if (width >= 16) {
+ data16 = (const u16 *)data;
+ expand16_2col2mask(fgcolor, bgcolor, fgm, bgm);
+
+ for (rows = width / 16; rows; rows--) {
+ u16 d = *data16++;
+ m = d | ((u32)d << 16);
+ *dest++ = (m & fgm[0]) ^ bgm[0];
+ *dest++ = (m & fgm[1]) ^ bgm[1];
+ *dest++ = (m & fgm[2]) ^ bgm[2];
+ *dest++ = (m & fgm[3]) ^ bgm[3];
+ }
+
+ data = (const u8 *)data16;
+ width &= 15;
+ }
+
+ if (width)
+ fill8_2col((u8 *)dest, fgcolor, bgcolor, *data);
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(atafb_iplan2p8_copyarea);
+EXPORT_SYMBOL(atafb_iplan2p8_fillrect);
+EXPORT_SYMBOL(atafb_iplan2p8_linefill);
diff --git a/drivers/video/atafb_mfb.c b/drivers/video/atafb_mfb.c
new file mode 100644
index 00000000000..6a352d62eec
--- /dev/null
+++ b/drivers/video/atafb_mfb.c
@@ -0,0 +1,112 @@
+/*
+ * linux/drivers/video/mfb.c -- Low level frame buffer operations for
+ * monochrome
+ *
+ * Created 5 Apr 1997 by Geert Uytterhoeven
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+
+#include "atafb.h"
+#include "atafb_utils.h"
+
+
+ /*
+ * Monochrome
+ */
+
+void atafb_mfb_copyarea(struct fb_info *info, u_long next_line,
+ int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ u8 *src, *dest;
+ u_int rows;
+
+ if (sx == 0 && dx == 0 && width == next_line) {
+ src = (u8 *)info->screen_base + sy * (width >> 3);
+ dest = (u8 *)info->screen_base + dy * (width >> 3);
+ fb_memmove(dest, src, height * (width >> 3));
+ } else if (dy <= sy) {
+ src = (u8 *)info->screen_base + sy * next_line + (sx >> 3);
+ dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3);
+ for (rows = height; rows--;) {
+ fb_memmove(dest, src, width >> 3);
+ src += next_line;
+ dest += next_line;
+ }
+ } else {
+ src = (u8 *)info->screen_base + (sy + height - 1) * next_line + (sx >> 3);
+ dest = (u8 *)info->screen_base + (dy + height - 1) * next_line + (dx >> 3);
+ for (rows = height; rows--;) {
+ fb_memmove(dest, src, width >> 3);
+ src -= next_line;
+ dest -= next_line;
+ }
+ }
+}
+
+void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color,
+ int sy, int sx, int height, int width)
+{
+ u8 *dest;
+ u_int rows;
+
+ dest = (u8 *)info->screen_base + sy * next_line + (sx >> 3);
+
+ if (sx == 0 && width == next_line) {
+ if (color)
+ fb_memset255(dest, height * (width >> 3));
+ else
+ fb_memclear(dest, height * (width >> 3));
+ } else {
+ for (rows = height; rows--; dest += next_line) {
+ if (color)
+ fb_memset255(dest, width >> 3);
+ else
+ fb_memclear_small(dest, width >> 3);
+ }
+ }
+}
+
+void atafb_mfb_linefill(struct fb_info *info, u_long next_line,
+ int dy, int dx, u32 width,
+ const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+ u8 *dest;
+ u_int rows;
+
+ dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3);
+
+ for (rows = width / 8; rows--; /* check margins */ ) {
+ // use fast_memmove or fb_memmove
+ *dest++ = *data++;
+ }
+}
+
+#ifdef MODULE
+MODULE_LICENSE("GPL");
+
+int init_module(void)
+{
+ return 0;
+}
+
+void cleanup_module(void)
+{
+}
+#endif /* MODULE */
+
+
+ /*
+ * Visible symbols for modules
+ */
+
+EXPORT_SYMBOL(atafb_mfb_copyarea);
+EXPORT_SYMBOL(atafb_mfb_fillrect);
+EXPORT_SYMBOL(atafb_mfb_linefill);
diff --git a/drivers/video/atafb_utils.h b/drivers/video/atafb_utils.h
new file mode 100644
index 00000000000..ac9e19dc505
--- /dev/null
+++ b/drivers/video/atafb_utils.h
@@ -0,0 +1,400 @@
+#ifndef _VIDEO_ATAFB_UTILS_H
+#define _VIDEO_ATAFB_UTILS_H
+
+/* ================================================================= */
+/* Utility Assembler Functions */
+/* ================================================================= */
+
+/* ====================================================================== */
+
+/* Those of a delicate disposition might like to skip the next couple of
+ * pages.
+ *
+ * These functions are drop in replacements for memmove and
+ * memset(_, 0, _). However their five instances add at least a kilobyte
+ * to the object file. You have been warned.
+ *
+ * Not a great fan of assembler for the sake of it, but I think
+ * that these routines are at least 10 times faster than their C
+ * equivalents for large blits, and that's important to the lowest level of
+ * a graphics driver. Question is whether some scheme with the blitter
+ * would be faster. I suspect not for simple text system - not much
+ * asynchrony.
+ *
+ * Code is very simple, just gruesome expansion. Basic strategy is to
+ * increase data moved/cleared at each step to 16 bytes to reduce
+ * instruction per data move overhead. movem might be faster still
+ * For more than 15 bytes, we try to align the write direction on a
+ * longword boundary to get maximum speed. This is even more gruesome.
+ * Unaligned read/write used requires 68020+ - think this is a problem?
+ *
+ * Sorry!
+ */
+
+
+/* ++roman: I've optimized Robert's original versions in some minor
+ * aspects, e.g. moveq instead of movel, let gcc choose the registers,
+ * use movem in some places...
+ * For other modes than 1 plane, lots of more such assembler functions
+ * were needed (e.g. the ones using movep or expanding color values).
+ */
+
+/* ++andreas: more optimizations:
+ subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc
+ addal is faster than addaw
+ movep is rather expensive compared to ordinary move's
+ some functions rewritten in C for clarity, no speed loss */
+
+static inline void *fb_memclear_small(void *s, size_t count)
+{
+ if (!count)
+ return 0;
+
+ asm volatile ("\n"
+ " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n"
+ "1:"
+ : "=a" (s), "=d" (count)
+ : "d" (0), "0" ((char *)s + count), "1" (count));
+ asm volatile ("\n"
+ " subq.l #1,%1\n"
+ " jcs 3f\n"
+ " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n"
+ "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n"
+ " dbra %1,2b\n"
+ "3:"
+ : "=a" (s), "=d" (count)
+ : "d" (0), "0" (s), "1" (count)
+ : "d4", "d5", "d6"
+ );
+
+ return 0;
+}
+
+
+static inline void *fb_memclear(void *s, size_t count)
+{
+ if (!count)
+ return 0;
+
+ if (count < 16) {
+ asm volatile ("\n"
+ " lsr.l #1,%1 ; jcc 1f ; clr.b (%0)+\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; clr.w (%0)+\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+ ; clr.l (%0)+\n"
+ "1:"
+ : "=a" (s), "=d" (count)
+ : "0" (s), "1" (count));
+ } else {
+ long tmp;
+ asm volatile ("\n"
+ " move.l %1,%2\n"
+ " lsr.l #1,%2 ; jcc 1f ; clr.b (%0)+ ; subq.w #1,%1\n"
+ " lsr.l #1,%2 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/
+ " clr.w (%0)+ ; subq.w #2,%1 ; jra 2f\n"
+ "1: lsr.l #1,%2 ; jcc 2f\n"
+ " clr.w (%0)+ ; subq.w #2,%1\n"
+ "2: move.w %1,%2; lsr.l #2,%1 ; jeq 6f\n"
+ " lsr.l #1,%1 ; jcc 3f ; clr.l (%0)+\n"
+ "3: lsr.l #1,%1 ; jcc 4f ; clr.l (%0)+ ; clr.l (%0)+\n"
+ "4: subq.l #1,%1 ; jcs 6f\n"
+ "5: clr.l (%0)+; clr.l (%0)+ ; clr.l (%0)+ ; clr.l (%0)+\n"
+ " dbra %1,5b ; clr.w %1; subq.l #1,%1; jcc 5b\n"
+ "6: move.w %2,%1; btst #1,%1 ; jeq 7f ; clr.w (%0)+\n"
+ "7: btst #0,%1 ; jeq 8f ; clr.b (%0)+\n"
+ "8:"
+ : "=a" (s), "=d" (count), "=d" (tmp)
+ : "0" (s), "1" (count));
+ }
+
+ return 0;
+}
+
+
+static inline void *fb_memset255(void *s, size_t count)
+{
+ if (!count)
+ return 0;
+
+ asm volatile ("\n"
+ " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n"
+ "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n"
+ "1:"
+ : "=a" (s), "=d" (count)
+ : "d" (-1), "0" ((char *)s+count), "1" (count));
+ asm volatile ("\n"
+ " subq.l #1,%1 ; jcs 3f\n"
+ " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n"
+ "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n"
+ " dbra %1,2b\n"
+ "3:"
+ : "=a" (s), "=d" (count)
+ : "d" (-1), "0" (s), "1" (count)
+ : "d4", "d5", "d6");
+
+ return 0;
+}
+
+
+static inline void *fb_memmove(void *d, const void *s, size_t count)
+{
+ if (d < s) {
+ if (count < 16) {
+ asm volatile ("\n"
+ " lsr.l #1,%2 ; jcc 1f ; move.b (%1)+,(%0)+\n"
+ "1: lsr.l #1,%2 ; jcc 1f ; move.w (%1)+,(%0)+\n"
+ "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+\n"
+ "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n"
+ "1:"
+ : "=a" (d), "=a" (s), "=d" (count)
+ : "0" (d), "1" (s), "2" (count));
+ } else {
+ long tmp;
+ asm volatile ("\n"
+ " move.l %0,%3\n"
+ " lsr.l #1,%3 ; jcc 1f ; move.b (%1)+,(%0)+ ; subqw #1,%2\n"
+ " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/
+ " move.w (%1)+,(%0)+ ; subqw #2,%2 ; jra 2f\n"
+ "1: lsr.l #1,%3 ; jcc 2f\n"
+ " move.w (%1)+,(%0)+ ; subqw #2,%2\n"
+ "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n"
+ " lsr.l #1,%2 ; jcc 3f ; move.l (%1)+,(%0)+\n"
+ "3: lsr.l #1,%2 ; jcc 4f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n"
+ "4: subq.l #1,%2 ; jcs 6f\n"
+ "5: move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n"
+ " move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n"
+ " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n"
+ "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w (%1)+,(%0)+\n"
+ "7: btst #0,%2 ; jeq 8f ; move.b (%1)+,(%0)+\n"
+ "8:"
+ : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
+ : "0" (d), "1" (s), "2" (count));
+ }
+ } else {
+ if (count < 16) {
+ asm volatile ("\n"
+ " lsr.l #1,%2 ; jcc 1f ; move.b -(%1),-(%0)\n"
+ "1: lsr.l #1,%2 ; jcc 1f ; move.w -(%1),-(%0)\n"
+ "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0)\n"
+ "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n"
+ "1:"
+ : "=a" (d), "=a" (s), "=d" (count)
+ : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count));
+ } else {
+ long tmp;
+
+ asm volatile ("\n"
+ " move.l %0,%3\n"
+ " lsr.l #1,%3 ; jcc 1f ; move.b -(%1),-(%0) ; subqw #1,%2\n"
+ " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/
+ " move.w -(%1),-(%0) ; subqw #2,%2 ; jra 2f\n"
+ "1: lsr.l #1,%3 ; jcc 2f\n"
+ " move.w -(%1),-(%0) ; subqw #2,%2\n"
+ "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n"
+ " lsr.l #1,%2 ; jcc 3f ; move.l -(%1),-(%0)\n"
+ "3: lsr.l #1,%2 ; jcc 4f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n"
+ "4: subq.l #1,%2 ; jcs 6f\n"
+ "5: move.l -(%1),-(%0); move.l -(%1),-(%0)\n"
+ " move.l -(%1),-(%0); move.l -(%1),-(%0)\n"
+ " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n"
+ "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w -(%1),-(%0)\n"
+ "7: btst #0,%2 ; jeq 8f ; move.b -(%1),-(%0)\n"
+ "8:"
+ : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp)
+ : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count));
+ }
+ }
+
+ return 0;
+}
+
+
+/* ++andreas: Simple and fast version of memmove, assumes size is
+ divisible by 16, suitable for moving the whole screen bitplane */
+static inline void fast_memmove(char *dst, const char *src, size_t size)
+{
+ if (!size)
+ return;
+ if (dst < src)
+ asm volatile ("\n"
+ "1: movem.l (%0)+,%%d0/%%d1/%%a0/%%a1\n"
+ " movem.l %%d0/%%d1/%%a0/%%a1,%1@\n"
+ " addq.l #8,%1; addq.l #8,%1\n"
+ " dbra %2,1b\n"
+ " clr.w %2; subq.l #1,%2\n"
+ " jcc 1b"
+ : "=a" (src), "=a" (dst), "=d" (size)
+ : "0" (src), "1" (dst), "2" (size / 16 - 1)
+ : "d0", "d1", "a0", "a1", "memory");
+ else
+ asm volatile ("\n"
+ "1: subq.l #8,%0; subq.l #8,%0\n"
+ " movem.l %0@,%%d0/%%d1/%%a0/%%a1\n"
+ " movem.l %%d0/%%d1/%%a0/%%a1,-(%1)\n"
+ " dbra %2,1b\n"
+ " clr.w %2; subq.l #1,%2\n"
+ " jcc 1b"
+ : "=a" (src), "=a" (dst), "=d" (size)
+ : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1)
+ : "d0", "d1", "a0", "a1", "memory");
+}
+
+#ifdef BPL
+
+/*
+ * This expands a up to 8 bit color into two longs
+ * for movel operations.
+ */
+static const u32 four2long[] = {
+ 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
+ 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
+ 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
+ 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff,
+};
+
+static inline void expand8_col2mask(u8 c, u32 m[])
+{
+ m[0] = four2long[c & 15];
+#if BPL > 4
+ m[1] = four2long[c >> 4];
+#endif
+}
+
+static inline void expand8_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[])
+{
+ fgm[0] = four2long[fg & 15] ^ (bgm[0] = four2long[bg & 15]);
+#if BPL > 4
+ fgm[1] = four2long[fg >> 4] ^ (bgm[1] = four2long[bg >> 4]);
+#endif
+}
+
+/*
+ * set an 8bit value to a color
+ */
+static inline void fill8_col(u8 *dst, u32 m[])
+{
+ u32 tmp = m[0];
+ dst[0] = tmp;
+ dst[2] = (tmp >>= 8);
+#if BPL > 2
+ dst[4] = (tmp >>= 8);
+ dst[6] = tmp >> 8;
+#endif
+#if BPL > 4
+ tmp = m[1];
+ dst[8] = tmp;
+ dst[10] = (tmp >>= 8);
+ dst[12] = (tmp >>= 8);
+ dst[14] = tmp >> 8;
+#endif
+}
+
+/*
+ * set an 8bit value according to foreground/background color
+ */
+static inline void fill8_2col(u8 *dst, u8 fg, u8 bg, u32 mask)
+{
+ u32 fgm[2], bgm[2], tmp;
+
+ expand8_2col2mask(fg, bg, fgm, bgm);
+
+ mask |= mask << 8;
+#if BPL > 2
+ mask |= mask << 16;
+#endif
+ tmp = (mask & fgm[0]) ^ bgm[0];
+ dst[0] = tmp;
+ dst[2] = (tmp >>= 8);
+#if BPL > 2
+ dst[4] = (tmp >>= 8);
+ dst[6] = tmp >> 8;
+#endif
+#if BPL > 4
+ tmp = (mask & fgm[1]) ^ bgm[1];
+ dst[8] = tmp;
+ dst[10] = (tmp >>= 8);
+ dst[12] = (tmp >>= 8);
+ dst[14] = tmp >> 8;
+#endif
+}
+
+static const u32 two2word[] = {
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+};
+
+static inline void expand16_col2mask(u8 c, u32 m[])
+{
+ m[0] = two2word[c & 3];
+#if BPL > 2
+ m[1] = two2word[(c >> 2) & 3];
+#endif
+#if BPL > 4
+ m[2] = two2word[(c >> 4) & 3];
+ m[3] = two2word[c >> 6];
+#endif
+}
+
+static inline void expand16_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[])
+{
+ bgm[0] = two2word[bg & 3];
+ fgm[0] = two2word[fg & 3] ^ bgm[0];
+#if BPL > 2
+ bgm[1] = two2word[(bg >> 2) & 3];
+ fgm[1] = two2word[(fg >> 2) & 3] ^ bgm[1];
+#endif
+#if BPL > 4
+ bgm[2] = two2word[(bg >> 4) & 3];
+ fgm[2] = two2word[(fg >> 4) & 3] ^ bgm[2];
+ bgm[3] = two2word[bg >> 6];
+ fgm[3] = two2word[fg >> 6] ^ bgm[3];
+#endif
+}
+
+static inline u32 *fill16_col(u32 *dst, int rows, u32 m[])
+{
+ while (rows) {
+ *dst++ = m[0];
+#if BPL > 2
+ *dst++ = m[1];
+#endif
+#if BPL > 4
+ *dst++ = m[2];
+ *dst++ = m[3];
+#endif
+ rows--;
+ }
+ return dst;
+}
+
+static inline void memmove32_col(void *dst, void *src, u32 mask, u32 h, u32 bytes)
+{
+ u32 *s, *d, v;
+
+ s = src;
+ d = dst;
+ do {
+ v = (*s++ & mask) | (*d & ~mask);
+ *d++ = v;
+#if BPL > 2
+ v = (*s++ & mask) | (*d & ~mask);
+ *d++ = v;
+#endif
+#if BPL > 4
+ v = (*s++ & mask) | (*d & ~mask);
+ *d++ = v;
+ v = (*s++ & mask) | (*d & ~mask);
+ *d++ = v;
+#endif
+ d = (u32 *)((u8 *)d + bytes);
+ s = (u32 *)((u8 *)s + bytes);
+ } while (--h);
+}
+
+#endif
+
+#endif /* _VIDEO_ATAFB_UTILS_H */
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index 39ab483fc25..90e7df22f50 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -209,4 +209,4 @@
#define PCI_CHIP_R423_5D57 0x5D57
#define PCI_CHIP_RS350_7834 0x7834
#define PCI_CHIP_RS350_7835 0x7835
-
+#define PCI_CHIP_RS480_5955 0x5955
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index e86d7e0c982..7fea4d8ae8e 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -2165,18 +2165,29 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
static int aty128fb_blank(int blank, struct fb_info *fb)
{
struct aty128fb_par *par = fb->par;
- u8 state = 0;
+ u8 state;
if (par->lock_blank || par->asleep)
return 0;
- if (blank & FB_BLANK_VSYNC_SUSPEND)
- state |= 2;
- if (blank & FB_BLANK_HSYNC_SUSPEND)
- state |= 1;
- if (blank & FB_BLANK_POWERDOWN)
- state |= 4;
-
+ switch (blank) {
+ case FB_BLANK_NORMAL:
+ state = 4;
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ state = 6;
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ state = 5;
+ break;
+ case FB_BLANK_POWERDOWN:
+ state = 7;
+ break;
+ case FB_BLANK_UNBLANK:
+ default:
+ state = 0;
+ break;
+ }
aty_st_8(CRTC_EXT_CNTL+1, state);
if (par->chip_gen == rage_M3) {
@@ -2430,7 +2441,7 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state)
wait_for_idle(par);
/* Blank display and LCD */
- aty128fb_blank(VESA_POWERDOWN, info);
+ aty128fb_blank(FB_BLANK_POWERDOWN, info);
/* Sleep */
par->asleep = 1;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 8514f2a6f06..8d3455da663 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -80,8 +80,9 @@
#include "../macmodes.h"
#endif
#ifdef __sparc__
-#include <asm/pbm.h>
#include <asm/fbio.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
#endif
#ifdef CONFIG_ADB_PMU
@@ -2297,20 +2298,6 @@ static int __devinit aty_init(struct fb_info *info)
par->pll_limits.xclk = 53;
}
#endif
- if (pll)
- par->pll_limits.pll_max = pll;
- if (mclk)
- par->pll_limits.mclk = mclk;
- if (xclk)
- par->pll_limits.xclk = xclk;
-
- aty_calc_mem_refresh(par, par->pll_limits.xclk);
- par->pll_per = 1000000/par->pll_limits.pll_max;
- par->mclk_per = 1000000/par->pll_limits.mclk;
- par->xclk_per = 1000000/par->pll_limits.xclk;
-
- par->ref_clk_per = 1000000000000ULL / 14318180;
- xtal = "14.31818";
#ifdef CONFIG_FB_ATY_GX
if (!M64_HAS(INTEGRATED)) {
@@ -2338,6 +2325,7 @@ static int __devinit aty_init(struct fb_info *info)
case DAC_IBMRGB514:
par->dac_ops = &aty_dac_ibm514;
break;
+#ifdef CONFIG_ATARI
case DAC_ATI68860_B:
case DAC_ATI68860_C:
par->dac_ops = &aty_dac_ati68860b;
@@ -2346,6 +2334,7 @@ static int __devinit aty_init(struct fb_info *info)
case DAC_ATT21C498:
par->dac_ops = &aty_dac_att21c498;
break;
+#endif
default:
PRINTKI("aty_init: DAC type not implemented yet!\n");
par->dac_ops = &aty_dac_unsupported;
@@ -2389,8 +2378,29 @@ static int __devinit aty_init(struct fb_info *info)
/* for many chips, the mclk is 67 MHz for SDRAM, 63 MHz otherwise */
if (par->pll_limits.mclk == 67 && par->ram_type < SDRAM)
par->pll_limits.mclk = 63;
+ /* Mobility + 32bit memory interface need halved XCLK. */
+ if (M64_HAS(MOBIL_BUS) && par->ram_type == SDRAM32)
+ par->pll_limits.xclk = (par->pll_limits.xclk + 1) >> 1;
}
+#endif
+ /* Allow command line to override clocks. */
+ if (pll)
+ par->pll_limits.pll_max = pll;
+ if (mclk)
+ par->pll_limits.mclk = mclk;
+ if (xclk)
+ par->pll_limits.xclk = xclk;
+
+ aty_calc_mem_refresh(par, par->pll_limits.xclk);
+ par->pll_per = 1000000/par->pll_limits.pll_max;
+ par->mclk_per = 1000000/par->pll_limits.mclk;
+ par->xclk_per = 1000000/par->pll_limits.xclk;
+
+ par->ref_clk_per = 1000000000000ULL / 14318180;
+ xtal = "14.31818";
+
+#ifdef CONFIG_FB_ATY_CT
if (M64_HAS(GTB_DSP)) {
u8 pll_ref_div = aty_ld_pll_ct(PLL_REF_DIV, par);
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index 1fdcfdbf669..cc9e9779b75 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -608,12 +608,10 @@ static void aty_resume_pll_ct(const struct fb_info *info,
aty_st_pll_ct(SCLK_FB_DIV, pll->ct.sclk_fb_div, par);
aty_st_pll_ct(SPLL_CNTL2, pll->ct.spll_cntl2, par);
/*
- * The sclk has been started. However, I believe the first clock
- * ticks it generates are not very stable. Hope this primitive loop
- * helps for Rage Mobilities that sometimes crash when
- * we switch to sclk. (Daniel Mantione, 13-05-2003)
+ * SCLK has been started. Wait for the PLL to lock. 5 ms
+ * should be enough according to mach64 programmer's guide.
*/
- udelay(500);
+ mdelay(5);
}
aty_st_pll_ct(PLL_REF_DIV, pll->ct.pll_ref_div, par);
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
index 2a7f381c330..fe2c6ad01a8 100644
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -11,7 +11,6 @@
#include <asm/uaccess.h>
#ifdef __sparc__
-#include <asm/pbm.h>
#include <asm/fbio.h>
#endif
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index a4b3fd185de..2ce05019301 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -100,6 +100,8 @@
{ PCI_VENDOR_ID_ATI, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (flags) | (CHIP_FAMILY_##family) }
static struct pci_device_id radeonfb_pci_table[] = {
+ /* Radeon Xpress 200m */
+ CHIP_DEF(PCI_CHIP_RS480_5955, RS480, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* Mobility M6 */
CHIP_DEF(PCI_CHIP_RADEON_LY, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RADEON_LZ, RV100, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
@@ -422,7 +424,7 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
if (dp == NULL)
return -ENODEV;
- val = get_property(dp, "ATY,RefCLK", NULL);
+ val = of_get_property(dp, "ATY,RefCLK", NULL);
if (!val || !*val) {
printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
return -EINVAL;
@@ -430,11 +432,11 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
rinfo->pll.ref_clk = (*val) / 10;
- val = get_property(dp, "ATY,SCLK", NULL);
+ val = of_get_property(dp, "ATY,SCLK", NULL);
if (val && *val)
rinfo->pll.sclk = (*val) / 10;
- val = get_property(dp, "ATY,MCLK", NULL);
+ val = of_get_property(dp, "ATY,MCLK", NULL);
if (val && *val)
rinfo->pll.mclk = (*val) / 10;
@@ -1994,7 +1996,8 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
/* framebuffer size */
if ((rinfo->family == CHIP_FAMILY_RS100) ||
(rinfo->family == CHIP_FAMILY_RS200) ||
- (rinfo->family == CHIP_FAMILY_RS300)) {
+ (rinfo->family == CHIP_FAMILY_RS300) ||
+ (rinfo->family == CHIP_FAMILY_RS480) ) {
u32 tom = INREG(NB_TOM);
tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 50847992070..7db9de68171 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -1,7 +1,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
-#include <linux/pci.h>
#include <linux/fb.h>
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 737b5c09dbd..2030ed81342 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -70,7 +70,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
int i, mt = MT_NONE;
RTRACE("analyzing OF properties...\n");
- pmt = get_property(dp, "display-type", NULL);
+ pmt = of_get_property(dp, "display-type", NULL);
if (!pmt)
return MT_NONE;
RTRACE("display-type: %s\n", pmt);
@@ -89,7 +89,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
}
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = get_property(dp, propnames[i], NULL);
+ pedid = of_get_property(dp, propnames[i], NULL);
if (pedid != NULL)
break;
}
@@ -98,9 +98,10 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
* single-head cards have hdno == -1 and skip this step
*/
if (pedid == NULL && dp->parent && (hdno != -1))
- pedid = get_property(dp->parent, (hdno == 0) ? "EDID1" : "EDID2", NULL);
+ pedid = of_get_property(dp->parent,
+ (hdno == 0) ? "EDID1" : "EDID2", NULL);
if (pedid == NULL && dp->parent && (hdno == 0))
- pedid = get_property(dp->parent, "EDID", NULL);
+ pedid = of_get_property(dp->parent, "EDID", NULL);
if (pedid == NULL)
return mt;
@@ -130,7 +131,7 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
do {
if (!dp)
return MT_NONE;
- pname = get_property(dp, "name", NULL);
+ pname = of_get_property(dp, "name", NULL);
if (!pname)
return MT_NONE;
len = strlen(pname);
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 9a2b0d69b0a..be1d57bf9dc 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -1262,7 +1262,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
/* This is the code for the Aluminium PowerBooks M10 / iBooks M11 */
if (rinfo->family == CHIP_FAMILY_RV350) {
u32 sdram_mode_reg = rinfo->save_regs[35];
- static u32 default_mrtable[] =
+ static const u32 default_mrtable[] =
{ 0x21320032,
0x21321000, 0xa1321000, 0x21321000, 0xffffffff,
0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
@@ -1290,7 +1290,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
if (rinfo->of_node != NULL) {
int size;
- mrtable = get_property(rinfo->of_node, "ATY,MRT", &size);
+ mrtable = of_get_property(rinfo->of_node, "ATY,MRT", &size);
if (mrtable)
mrtable_size = size >> 2;
else
@@ -2826,11 +2826,15 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlis
rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
/* Enable/Disable dynamic clocks: TODO add sysfs access */
- rinfo->dynclk = dynclk;
- if (dynclk == 1) {
+ if (rinfo->family == CHIP_FAMILY_RS480)
+ rinfo->dynclk = -1;
+ else
+ rinfo->dynclk = dynclk;
+
+ if (rinfo->dynclk == 1) {
radeon_pm_enable_dynamic_mode(rinfo);
printk("radeonfb: Dynamic Clock Power Management enabled\n");
- } else if (dynclk == 0) {
+ } else if (rinfo->dynclk == 0) {
radeon_pm_disable_dynamic_mode(rinfo);
printk("radeonfb: Dynamic Clock Power Management disabled\n");
}
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 31900036028..7ebffcdfd1e 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -48,6 +48,7 @@ enum radeon_family {
CHIP_FAMILY_RV350,
CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */
CHIP_FAMILY_R420, /* R420/R423/M18 */
+ CHIP_FAMILY_RS480,
CHIP_FAMILY_LAST,
};
@@ -64,7 +65,8 @@ enum radeon_family {
((rinfo)->family == CHIP_FAMILY_RV350) || \
((rinfo)->family == CHIP_FAMILY_R350) || \
((rinfo)->family == CHIP_FAMILY_RV380) || \
- ((rinfo)->family == CHIP_FAMILY_R420))
+ ((rinfo)->family == CHIP_FAMILY_R420) || \
+ ((rinfo)->family == CHIP_FAMILY_RS480) )
/*
* Chip flags
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 47d15b5d985..fbef663fc05 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -63,3 +63,11 @@ config BACKLIGHT_PROGEAR
help
If you have a Frontpath ProGear say Y to enable the
backlight driver.
+
+config BACKLIGHT_CARILLO_RANCH
+ tristate "Intel Carillo Ranch Backlight Driver"
+ depends on BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
+ default n
+ help
+ If you have a Intel LE80578 (Carillo Ranch) say Y to enable the
+ backlight driver.
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 0c3ce46f509..c6e2266f63e 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
+obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
new file mode 100644
index 00000000000..e9bbc3455c9
--- /dev/null
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Carillo Ranch video subsystem driver.
+ * The Carillo Ranch video subsystem driver 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 Carillo Ranch video subsystem driver 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 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+#include <linux/pci.h>
+#include <asm/uaccess.h>
+
+/* The LVDS- and panel power controls sits on the
+ * GPIO port of the ISA bridge.
+ */
+
+#define CRVML_DEVICE_LPC 0x27B8
+#define CRVML_REG_GPIOBAR 0x48
+#define CRVML_REG_GPIOEN 0x4C
+#define CRVML_GPIOEN_BIT (1 << 4)
+#define CRVML_PANEL_PORT 0x38
+#define CRVML_LVDS_ON 0x00000001
+#define CRVML_PANEL_ON 0x00000002
+#define CRVML_BACKLIGHT_OFF 0x00000004
+
+/* The PLL Clock register sits on Host bridge */
+#define CRVML_DEVICE_MCH 0x5001
+#define CRVML_REG_MCHBAR 0x44
+#define CRVML_REG_MCHEN 0x54
+#define CRVML_MCHEN_BIT (1 << 28)
+#define CRVML_MCHMAP_SIZE 4096
+#define CRVML_REG_CLOCK 0xc3c
+#define CRVML_CLOCK_SHIFT 8
+#define CRVML_CLOCK_MASK 0x00000f00
+
+static struct pci_dev *lpc_dev;
+static u32 gpio_bar;
+
+struct cr_panel {
+ struct backlight_device *cr_backlight_device;
+ struct lcd_device *cr_lcd_device;
+};
+
+static int cr_backlight_set_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props.brightness;
+ u32 addr = gpio_bar + CRVML_PANEL_PORT;
+ u32 cur = inl(addr);
+
+ if (bd->props.power == FB_BLANK_UNBLANK)
+ intensity = FB_BLANK_UNBLANK;
+ if (bd->props.fb_blank == FB_BLANK_UNBLANK)
+ intensity = FB_BLANK_UNBLANK;
+ if (bd->props.power == FB_BLANK_POWERDOWN)
+ intensity = FB_BLANK_POWERDOWN;
+ if (bd->props.fb_blank == FB_BLANK_POWERDOWN)
+ intensity = FB_BLANK_POWERDOWN;
+
+ if (intensity == FB_BLANK_UNBLANK) { /* FULL ON */
+ cur &= ~CRVML_BACKLIGHT_OFF;
+ outl(cur, addr);
+ } else if (intensity == FB_BLANK_POWERDOWN) { /* OFF */
+ cur |= CRVML_BACKLIGHT_OFF;
+ outl(cur, addr);
+ } /* anything else, don't bother */
+
+ return 0;
+}
+
+static int cr_backlight_get_intensity(struct backlight_device *bd)
+{
+ u32 addr = gpio_bar + CRVML_PANEL_PORT;
+ u32 cur = inl(addr);
+ u8 intensity;
+
+ if (cur & CRVML_BACKLIGHT_OFF)
+ intensity = FB_BLANK_POWERDOWN;
+ else
+ intensity = FB_BLANK_UNBLANK;
+
+ return intensity;
+}
+
+static struct backlight_ops cr_backlight_ops = {
+ .get_brightness = cr_backlight_get_intensity,
+ .update_status = cr_backlight_set_intensity,
+};
+
+static void cr_panel_on(void)
+{
+ u32 addr = gpio_bar + CRVML_PANEL_PORT;
+ u32 cur = inl(addr);
+
+ if (!(cur & CRVML_PANEL_ON)) {
+ /* Make sure LVDS controller is down. */
+ if (cur & 0x00000001) {
+ cur &= ~CRVML_LVDS_ON;
+ outl(cur, addr);
+ }
+ /* Power up Panel */
+ schedule_timeout(HZ / 10);
+ cur |= CRVML_PANEL_ON;
+ outl(cur, addr);
+ }
+
+ /* Power up LVDS controller */
+
+ if (!(cur & CRVML_LVDS_ON)) {
+ schedule_timeout(HZ / 10);
+ outl(cur | CRVML_LVDS_ON, addr);
+ }
+}
+
+static void cr_panel_off(void)
+{
+ u32 addr = gpio_bar + CRVML_PANEL_PORT;
+ u32 cur = inl(addr);
+
+ /* Power down LVDS controller first to avoid high currents */
+ if (cur & CRVML_LVDS_ON) {
+ cur &= ~CRVML_LVDS_ON;
+ outl(cur, addr);
+ }
+ if (cur & CRVML_PANEL_ON) {
+ schedule_timeout(HZ / 10);
+ outl(cur & ~CRVML_PANEL_ON, addr);
+ }
+}
+
+static int cr_lcd_set_power(struct lcd_device *ld, int power)
+{
+ if (power == FB_BLANK_UNBLANK)
+ cr_panel_on();
+ if (power == FB_BLANK_POWERDOWN)
+ cr_panel_off();
+
+ return 0;
+}
+
+static struct lcd_ops cr_lcd_ops = {
+ .set_power = cr_lcd_set_power,
+};
+
+static int cr_backlight_probe(struct platform_device *pdev)
+{
+ struct cr_panel *crp;
+ u8 dev_en;
+
+ crp = kzalloc(sizeof(crp), GFP_KERNEL);
+ if (crp == NULL)
+ return -ENOMEM;
+
+ lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ CRVML_DEVICE_LPC, NULL);
+ if (!lpc_dev) {
+ printk("INTEL CARILLO RANCH LPC not found.\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_byte(lpc_dev, CRVML_REG_GPIOEN, &dev_en);
+ if (!(dev_en & CRVML_GPIOEN_BIT)) {
+ printk(KERN_ERR
+ "Carillo Ranch GPIO device was not enabled.\n");
+ pci_dev_put(lpc_dev);
+ return -ENODEV;
+ }
+
+ crp->cr_backlight_device = backlight_device_register("cr-backlight",
+ &pdev->dev, NULL,
+ &cr_backlight_ops);
+ if (IS_ERR(crp->cr_backlight_device)) {
+ pci_dev_put(lpc_dev);
+ return PTR_ERR(crp->cr_backlight_device);
+ }
+
+ crp->cr_lcd_device = lcd_device_register("cr-lcd",
+ &pdev->dev,
+ &cr_lcd_ops);
+
+ if (IS_ERR(crp->cr_lcd_device)) {
+ pci_dev_put(lpc_dev);
+ return PTR_ERR(crp->cr_backlight_device);
+ }
+
+ pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
+ &gpio_bar);
+ gpio_bar &= ~0x3F;
+
+ crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
+ crp->cr_backlight_device->props.brightness = 0;
+ crp->cr_backlight_device->props.max_brightness = 0;
+ cr_backlight_set_intensity(crp->cr_backlight_device);
+
+ cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_UNBLANK);
+
+ platform_set_drvdata(pdev, crp);
+
+ return 0;
+}
+
+static int cr_backlight_remove(struct platform_device *pdev)
+{
+ struct cr_panel *crp = platform_get_drvdata(pdev);
+ crp->cr_backlight_device->props.power = FB_BLANK_POWERDOWN;
+ crp->cr_backlight_device->props.brightness = 0;
+ crp->cr_backlight_device->props.max_brightness = 0;
+ cr_backlight_set_intensity(crp->cr_backlight_device);
+ cr_lcd_set_power(crp->cr_lcd_device, FB_BLANK_POWERDOWN);
+ backlight_device_unregister(crp->cr_backlight_device);
+ lcd_device_unregister(crp->cr_lcd_device);
+ pci_dev_put(lpc_dev);
+
+ return 0;
+}
+
+static struct platform_driver cr_backlight_driver = {
+ .probe = cr_backlight_probe,
+ .remove = cr_backlight_remove,
+ .driver = {
+ .name = "cr_backlight",
+ },
+};
+
+static struct platform_device *crp;
+
+static int __init cr_backlight_init(void)
+{
+ int ret = platform_driver_register(&cr_backlight_driver);
+
+ if (!ret) {
+ crp = platform_device_alloc("cr_backlight", -1);
+ if (!crp)
+ return -ENOMEM;
+
+ ret = platform_device_add(crp);
+
+ if (ret) {
+ platform_device_put(crp);
+ platform_driver_unregister(&cr_backlight_driver);
+ }
+ }
+
+ printk("Carillo Ranch Backlight Driver Initialized.\n");
+
+ return ret;
+}
+
+static void __exit cr_backlight_exit(void)
+{
+ platform_device_unregister(crp);
+ platform_driver_unregister(&cr_backlight_driver);
+}
+
+module_init(cr_backlight_init);
+module_exit(cr_backlight_exit);
+
+MODULE_AUTHOR("Tungsten Graphics Inc.");
+MODULE_DESCRIPTION("Carillo Ranch Backlight Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 6faea4034e3..032210f45be 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -22,8 +22,6 @@
* help moving some redundant computations and branches out of the loop, too.
*/
-
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -31,6 +29,7 @@
#include <linux/slab.h>
#include <asm/types.h>
#include <asm/io.h>
+#include "fb_draw.h"
#if BITS_PER_LONG == 32
# define FB_WRITEL fb_writel
@@ -41,17 +40,6 @@
#endif
/*
- * Compose two values, using a bitmask as decision value
- * This is equivalent to (a & mask) | (b & ~mask)
- */
-
-static inline unsigned long
-comp(unsigned long a, unsigned long b, unsigned long mask)
-{
- return ((a ^ b) & mask) ^ b;
-}
-
- /*
* Generic bitwise copy algorithm
*/
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index f00b50aab60..71623b4f8ca 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/fb.h>
#include <asm/types.h>
+#include "fb_draw.h"
#if BITS_PER_LONG == 32
# define FB_WRITEL fb_writel
@@ -31,73 +32,6 @@
#endif
/*
- * Compose two values, using a bitmask as decision value
- * This is equivalent to (a & mask) | (b & ~mask)
- */
-
-static inline unsigned long
-comp(unsigned long a, unsigned long b, unsigned long mask)
-{
- return ((a ^ b) & mask) ^ b;
-}
-
- /*
- * Create a pattern with the given pixel's color
- */
-
-#if BITS_PER_LONG == 64
-static inline unsigned long
-pixel_to_pat( u32 bpp, u32 pixel)
-{
- switch (bpp) {
- case 1:
- return 0xfffffffffffffffful*pixel;
- case 2:
- return 0x5555555555555555ul*pixel;
- case 4:
- return 0x1111111111111111ul*pixel;
- case 8:
- return 0x0101010101010101ul*pixel;
- case 12:
- return 0x0001001001001001ul*pixel;
- case 16:
- return 0x0001000100010001ul*pixel;
- case 24:
- return 0x0000000001000001ul*pixel;
- case 32:
- return 0x0000000100000001ul*pixel;
- default:
- panic("pixel_to_pat(): unsupported pixelformat\n");
- }
-}
-#else
-static inline unsigned long
-pixel_to_pat( u32 bpp, u32 pixel)
-{
- switch (bpp) {
- case 1:
- return 0xfffffffful*pixel;
- case 2:
- return 0x55555555ul*pixel;
- case 4:
- return 0x11111111ul*pixel;
- case 8:
- return 0x01010101ul*pixel;
- case 12:
- return 0x00001001ul*pixel;
- case 16:
- return 0x00010001ul*pixel;
- case 24:
- return 0x00000001ul*pixel;
- case 32:
- return 0x00000001ul*pixel;
- default:
- panic("pixel_to_pat(): unsupported pixelformat\n");
- }
-}
-#endif
-
- /*
* Aligned pattern fill using 32/64-bit memory accesses
*/
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 2c4bc620573..8269d704ab2 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -98,15 +98,6 @@
#define assert(expr)
#endif
-#ifdef TRUE
-#undef TRUE
-#endif
-#ifdef FALSE
-#undef FALSE
-#endif
-#define TRUE 1
-#define FALSE 0
-
#define MB_ (1024*1024)
#define KB_ (1024)
@@ -146,9 +137,9 @@ static const struct cirrusfb_board_info_rec {
char *name; /* ASCII name of chipset */
long maxclock[5]; /* maximum video clock */
/* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
- unsigned init_sr07 : 1; /* init SR07 during init_vgachip() */
- unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
- unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
+ bool init_sr07 : 1; /* init SR07 during init_vgachip() */
+ bool init_sr1f : 1; /* write SR1F during init_vgachip() */
+ bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
/* initial SR07 value, then for each mode */
unsigned char sr07;
@@ -166,9 +157,9 @@ static const struct cirrusfb_board_info_rec {
/* the SD64/P4 have a higher max. videoclock */
140000, 140000, 140000, 140000, 140000,
},
- .init_sr07 = TRUE,
- .init_sr1f = TRUE,
- .scrn_start_bit19 = TRUE,
+ .init_sr07 = true,
+ .init_sr1f = true,
+ .scrn_start_bit19 = true,
.sr07 = 0xF0,
.sr07_1bpp = 0xF0,
.sr07_8bpp = 0xF1,
@@ -180,9 +171,9 @@ static const struct cirrusfb_board_info_rec {
/* guess */
90000, 90000, 90000, 90000, 90000
},
- .init_sr07 = TRUE,
- .init_sr1f = TRUE,
- .scrn_start_bit19 = FALSE,
+ .init_sr07 = true,
+ .init_sr1f = true,
+ .scrn_start_bit19 = false,
.sr07 = 0x80,
.sr07_1bpp = 0x80,
.sr07_8bpp = 0x81,
@@ -194,9 +185,9 @@ static const struct cirrusfb_board_info_rec {
/* guess */
90000, 90000, 90000, 90000, 90000
},
- .init_sr07 = TRUE,
- .init_sr1f = TRUE,
- .scrn_start_bit19 = FALSE,
+ .init_sr07 = true,
+ .init_sr1f = true,
+ .scrn_start_bit19 = false,
.sr07 = 0x20,
.sr07_1bpp = 0x20,
.sr07_8bpp = 0x21,
@@ -208,9 +199,9 @@ static const struct cirrusfb_board_info_rec {
/* guess */
90000, 90000, 90000, 90000, 90000
},
- .init_sr07 = TRUE,
- .init_sr1f = TRUE,
- .scrn_start_bit19 = FALSE,
+ .init_sr07 = true,
+ .init_sr1f = true,
+ .scrn_start_bit19 = false,
.sr07 = 0x80,
.sr07_1bpp = 0x80,
.sr07_8bpp = 0x81,
@@ -221,9 +212,9 @@ static const struct cirrusfb_board_info_rec {
.maxclock = {
135100, 135100, 85500, 85500, 0
},
- .init_sr07 = TRUE,
- .init_sr1f = FALSE,
- .scrn_start_bit19 = TRUE,
+ .init_sr07 = true,
+ .init_sr1f = false,
+ .scrn_start_bit19 = true,
.sr07 = 0x20,
.sr07_1bpp = 0x20,
.sr07_8bpp = 0x21,
@@ -235,9 +226,9 @@ static const struct cirrusfb_board_info_rec {
/* for the GD5430. GD5446 can do more... */
85500, 85500, 50000, 28500, 0
},
- .init_sr07 = TRUE,
- .init_sr1f = TRUE,
- .scrn_start_bit19 = TRUE,
+ .init_sr07 = true,
+ .init_sr1f = true,
+ .scrn_start_bit19 = true,
.sr07 = 0xA0,
.sr07_1bpp = 0xA1,
.sr07_1bpp_mux = 0xA7,
@@ -250,9 +241,9 @@ static const struct cirrusfb_board_info_rec {
.maxclock = {
135100, 200000, 200000, 135100, 135100
},
- .init_sr07 = TRUE,
- .init_sr1f = TRUE,
- .scrn_start_bit19 = TRUE,
+ .init_sr07 = true,
+ .init_sr1f = true,
+ .scrn_start_bit19 = true,
.sr07 = 0x10,
.sr07_1bpp = 0x11,
.sr07_8bpp = 0x11,
@@ -264,9 +255,9 @@ static const struct cirrusfb_board_info_rec {
/* guess */
135100, 135100, 135100, 135100, 135100,
},
- .init_sr07 = FALSE,
- .init_sr1f = FALSE,
- .scrn_start_bit19 = TRUE,
+ .init_sr07 = false,
+ .init_sr1f = false,
+ .scrn_start_bit19 = true,
}
};
@@ -815,7 +806,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
default:
DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
- assert (FALSE);
+ assert(false);
/* should never occur */
break;
}
@@ -886,7 +877,7 @@ static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
default:
DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
- assert (FALSE);
+ assert(false);
/* should never occur */
break;
}
@@ -3203,7 +3194,7 @@ void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_clas
break;
default:
/* should never occur */
- assert (FALSE);
+ assert(false);
break;
}
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 0429fd2cece..73813c60d03 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -107,7 +107,9 @@ static struct display fb_display[MAX_NR_CONSOLES];
static signed char con2fb_map[MAX_NR_CONSOLES];
static signed char con2fb_map_boot[MAX_NR_CONSOLES];
+#ifndef MODULE
static int logo_height;
+#endif
static int logo_lines;
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
enums. */
@@ -576,6 +578,13 @@ static int fbcon_takeover(int show_logo)
return err;
}
+#ifdef MODULE
+static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
+ int cols, int rows, int new_cols, int new_rows)
+{
+ logo_shown = FBCON_LOGO_DONTSHOW;
+}
+#else
static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
int cols, int rows, int new_cols, int new_rows)
{
@@ -584,6 +593,11 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
int cnt, erase = vc->vc_video_erase_char, step;
unsigned short *save = NULL, *r, *q;
+ if (info->flags & FBINFO_MODULE) {
+ logo_shown = FBCON_LOGO_DONTSHOW;
+ return;
+ }
+
/*
* remove underline attribute from erase character
* if black and white framebuffer.
@@ -618,8 +632,13 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
r -= cols;
}
if (!save) {
- vc->vc_y += logo_lines;
- vc->vc_pos += logo_lines * vc->vc_size_row;
+ int lines;
+ if (vc->vc_y + logo_lines >= rows)
+ lines = rows - vc->vc_y - 1;
+ else
+ lines = logo_lines;
+ vc->vc_y += lines;
+ vc->vc_pos += lines * vc->vc_size_row;
}
}
scr_memsetw((unsigned short *) vc->vc_origin,
@@ -650,6 +669,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
vc->vc_top = logo_lines;
}
}
+#endif /* MODULE */
#ifdef CONFIG_FB_TILEBLITTING
static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
@@ -665,6 +685,17 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
fbcon_set_bitops(ops);
}
}
+
+static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+{
+ int err = 0;
+
+ if (info->flags & FBINFO_MISC_TILEBLITTING &&
+ info->tileops->fb_get_tilemax(info) < charcount)
+ err = 1;
+
+ return err;
+}
#else
static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
{
@@ -675,6 +706,12 @@ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
fbcon_set_rotation(info);
fbcon_set_bitops(ops);
}
+
+static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+{
+ return 0;
+}
+
#endif /* CONFIG_MISC_TILEBLITTING */
@@ -968,7 +1005,9 @@ static const char *fbcon_startup(void)
if (!p->fontdata) {
if (!fontname[0] || !(font = find_font(fontname)))
font = get_default_font(info->var.xres,
- info->var.yres);
+ info->var.yres,
+ info->pixmap.blit_x,
+ info->pixmap.blit_y);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
vc->vc_font.data = (void *)(p->fontdata = font->data);
@@ -1088,7 +1127,9 @@ static void fbcon_init(struct vc_data *vc, int init)
if (!fontname[0] || !(font = find_font(fontname)))
font = get_default_font(info->var.xres,
- info->var.yres);
+ info->var.yres,
+ info->pixmap.blit_x,
+ info->pixmap.blit_y);
vc->vc_font.width = font->width;
vc->vc_font.height = font->height;
vc->vc_font.data = (void *)(p->fontdata = font->data);
@@ -1305,7 +1346,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
int y;
int c = scr_readw((u16 *) vc->vc_pos);
- if (fbcon_is_inactive(vc, info))
+ if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
return;
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
@@ -2475,6 +2516,7 @@ static int fbcon_copy_font(struct vc_data *vc, int con)
static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigned flags)
{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
unsigned charcount = font->charcount;
int w = font->width;
int h = font->height;
@@ -2488,6 +2530,15 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
if (charcount != 256 && charcount != 512)
return -EINVAL;
+ /* Make sure drawing engine can handle the font */
+ if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
+ !(info->pixmap.blit_y & (1 << (font->height - 1))))
+ return -EINVAL;
+
+ /* Make sure driver can handle the font length */
+ if (fbcon_invalid_charcount(info, charcount))
+ return -EINVAL;
+
size = h * pitch * charcount;
new_data = kmalloc(FONT_EXTRA_WORDS * sizeof(int) + size, GFP_USER);
@@ -2532,7 +2583,8 @@ static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, cha
const struct font_desc *f;
if (!name)
- f = get_default_font(info->var.xres, info->var.yres);
+ f = get_default_font(info->var.xres, info->var.yres,
+ info->pixmap.blit_x, info->pixmap.blit_y);
else if (!(f = find_font(name)))
return -ENOENT;
@@ -2829,7 +2881,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
struct fbcon_ops *ops = info->fbcon_par;
struct vc_data *vc;
struct display *p;
- int i, rows, cols;
+ int i, rows, cols, fg = -1;
if (!ops || ops->currcon < 0)
return;
@@ -2840,34 +2892,23 @@ static void fbcon_set_all_vcs(struct fb_info *info)
registered_fb[con2fb_map[i]] != info)
continue;
+ if (CON_IS_VISIBLE(vc)) {
+ fg = i;
+ continue;
+ }
+
p = &fb_display[vc->vc_num];
set_blitting_type(vc, info);
var_to_display(p, &info->var, info);
- cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
- rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+ cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres);
cols /= vc->vc_font.width;
rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
-
- if (CON_IS_VISIBLE(vc)) {
- updatescrollmode(p, info, vc);
- scrollback_max = 0;
- scrollback_current = 0;
-
- if (!fbcon_is_inactive(vc, info)) {
- ops->var.xoffset = ops->var.yoffset =
- p->yscroll = 0;
- ops->update_start(info);
- }
-
- fbcon_set_palette(vc, color_table);
- update_screen(vc);
- if (softback_buf)
- fbcon_update_softback(vc);
- }
}
- ops->p = &fb_display[ops->currcon];
+ if (fg != -1)
+ fbcon_modechanged(info);
}
static int fbcon_mode_deleted(struct fb_info *info,
@@ -3002,6 +3043,42 @@ static void fbcon_new_modelist(struct fb_info *info)
}
}
+static void fbcon_get_requirement(struct fb_info *info,
+ struct fb_blit_caps *caps)
+{
+ struct vc_data *vc;
+ struct display *p;
+
+ if (caps->flags) {
+ int i, charcnt;
+
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ vc = vc_cons[i].d;
+ if (vc && vc->vc_mode == KD_TEXT &&
+ info->node == con2fb_map[i]) {
+ p = &fb_display[i];
+ caps->x |= 1 << (vc->vc_font.width - 1);
+ caps->y |= 1 << (vc->vc_font.height - 1);
+ charcnt = (p->userfont) ?
+ FNTCHARCNT(p->fontdata) : 256;
+ if (caps->len < charcnt)
+ caps->len = charcnt;
+ }
+ }
+ } else {
+ vc = vc_cons[fg_console].d;
+
+ if (vc && vc->vc_mode == KD_TEXT &&
+ info->node == con2fb_map[fg_console]) {
+ p = &fb_display[fg_console];
+ caps->x = 1 << (vc->vc_font.width - 1);
+ caps->y = 1 << (vc->vc_font.height - 1);
+ caps->len = (p->userfont) ?
+ FNTCHARCNT(p->fontdata) : 256;
+ }
+ }
+}
+
static int fbcon_event_notify(struct notifier_block *self,
unsigned long action, void *data)
{
@@ -3009,6 +3086,7 @@ static int fbcon_event_notify(struct notifier_block *self,
struct fb_info *info = event->info;
struct fb_videomode *mode;
struct fb_con2fbmap *con2fb;
+ struct fb_blit_caps *caps;
int ret = 0;
/*
@@ -3057,6 +3135,10 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_NEW_MODELIST:
fbcon_new_modelist(info);
break;
+ case FB_EVENT_GET_REQ:
+ caps = event->data;
+ fbcon_get_requirement(info, caps);
+ break;
}
done:
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index c960728b7e8..a6828d0a4c5 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -98,6 +98,8 @@ const struct font_desc *find_font(const char *name)
* get_default_font - get default font
* @xres: screen size of X
* @yres: screen size of Y
+ * @font_w: bit array of supported widths (1 - 32)
+ * @font_h: bit array of supported heights (1 - 32)
*
* Get the default font for a specified screen size.
* Dimensions are in pixels.
@@ -107,7 +109,8 @@ const struct font_desc *find_font(const char *name)
*
*/
-const struct font_desc *get_default_font(int xres, int yres)
+const struct font_desc *get_default_font(int xres, int yres, u32 font_w,
+ u32 font_h)
{
int i, c, cc;
const struct font_desc *f, *g;
@@ -129,6 +132,11 @@ const struct font_desc *get_default_font(int xres, int yres)
#endif
if ((yres < 400) == (f->height <= 8))
c += 1000;
+
+ if (!(font_w & (1 << (f->width - 1))) ||
+ !(font_w & (1 << (f->height - 1))))
+ c += 1000;
+
if (c > cc) {
cc = c;
g = f;
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 124ecbe6f88..bd8d995fe25 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -384,7 +384,7 @@ static inline u16 mda_convert_attr(u16 ch)
}
static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
- u8 blink, u8 underline, u8 reverse)
+ u8 blink, u8 underline, u8 reverse, u8 italic)
{
/* The attribute is just a bit vector:
*
@@ -397,6 +397,7 @@ static u8 mdacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
return (intensity & 3) |
((underline & 1) << 2) |
((reverse & 1) << 3) |
+ (!!italic << 4) |
((blink & 1) << 7);
}
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
index b78eac63459..ae02e4eb18e 100644
--- a/drivers/video/console/promcon.c
+++ b/drivers/video/console/promcon.c
@@ -548,7 +548,8 @@ promcon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
}
#if !(PROMCON_COLOR)
-static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 promcon_build_attr(struct vc_data *conp, u8 _color, u8 _intensity,
+ u8 _blink, u8 _underline, u8 _reverse, u8 _italic)
{
return (_reverse) ? 0xf : 0x7;
}
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index f577bd80e02..03cfb7ac573 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/video/softcursor.c
+ * linux/drivers/video/console/softcursor.c
*
* Generic software cursor for frame buffer devices
*
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 57b21e53303..67a682d6cc7 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -314,7 +314,7 @@ static unsigned long sticon_getxy(struct vc_data *conp, unsigned long pos,
}
static u8 sticon_build_attr(struct vc_data *conp, u8 color, u8 intens,
- u8 blink, u8 underline, u8 reverse)
+ u8 blink, u8 underline, u8 reverse, u8 italic)
{
u8 attr = ((color & 0x70) >> 1) | ((color & 7));
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 88e7038eab8..717b360d041 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -495,7 +495,7 @@ sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
return NULL;
fbfont = find_font(fbfont_name);
if (!fbfont)
- fbfont = get_default_font(1024,768);
+ fbfont = get_default_font(1024,768, ~(u32)0, ~(u32)0);
if (!fbfont)
return NULL;
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 91a20785108..2460b82a1d9 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -86,8 +86,6 @@ static int vgacon_set_origin(struct vc_data *c);
static void vgacon_save_screen(struct vc_data *c);
static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
int lines);
-static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
- u8 blink, u8 underline, u8 reverse);
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
static unsigned long vgacon_uni_pagedir[2];
@@ -371,7 +369,8 @@ static const char *vgacon_startup(void)
}
/* VGA16 modes are not handled by VGACON */
- if ((ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */
+ if ((ORIG_VIDEO_MODE == 0x00) || /* SCREEN_INFO not initialized */
+ (ORIG_VIDEO_MODE == 0x0D) || /* 320x200/4 */
(ORIG_VIDEO_MODE == 0x0E) || /* 640x200/4 */
(ORIG_VIDEO_MODE == 0x10) || /* 640x350/4 */
(ORIG_VIDEO_MODE == 0x12) || /* 640x480/4 */
@@ -577,12 +576,14 @@ static void vgacon_deinit(struct vc_data *c)
}
static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
- u8 blink, u8 underline, u8 reverse)
+ u8 blink, u8 underline, u8 reverse, u8 italic)
{
u8 attr = color;
if (vga_can_do_color) {
- if (underline)
+ if (italic)
+ attr = (attr & 0xF0) | c->vc_itcolor;
+ else if (underline)
attr = (attr & 0xf0) | c->vc_ulcolor;
else if (intensity == 0)
attr = (attr & 0xf0) | c->vc_halfcolor;
@@ -596,7 +597,9 @@ static u8 vgacon_build_attr(struct vc_data *c, u8 color, u8 intensity,
if (intensity == 2)
attr ^= 0x08;
if (!vga_can_do_color) {
- if (underline)
+ if (italic)
+ attr = (attr & 0xF8) | 0x02;
+ else if (underline)
attr = (attr & 0xf8) | 0x01;
else if (intensity == 0)
attr = (attr & 0xf0) | 0x08;
@@ -657,6 +660,9 @@ static void vgacon_set_cursor_size(int xpos, int from, int to)
static void vgacon_cursor(struct vc_data *c, int mode)
{
+ if (c->vc_mode != KD_TEXT)
+ return;
+
vgacon_restore_screen(c);
switch (mode) {
@@ -1315,7 +1321,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
unsigned long oldo;
unsigned int delta;
- if (t || b != c->vc_rows || vga_is_gfx)
+ if (t || b != c->vc_rows || vga_is_gfx || c->vc_mode != KD_TEXT)
return 0;
if (!vga_hardscroll_enabled || lines >= c->vc_rows / 2)
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index fd60dba294d..8b762739b1e 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -179,12 +179,14 @@ MODULE_LICENSE("GPL");
int init_module(void)
{
struct device_node *dp;
+ int ret = -ENXIO;
- dp = find_devices("control");
+ dp = of_find_node_by_name(NULL, "control");
if (dp != 0 && !control_of_init(dp))
- return 0;
+ ret = 0;
+ of_node_put(dp);
- return -ENXIO;
+ return ret;
}
void cleanup_module(void)
@@ -589,16 +591,18 @@ static int __init control_init(void)
{
struct device_node *dp;
char *option = NULL;
+ int ret = -ENXIO;
if (fb_get_options("controlfb", &option))
return -ENODEV;
control_setup(option);
- dp = find_devices("control");
+ dp = of_find_node_by_name(NULL, "control");
if (dp != 0 && !control_of_init(dp))
- return 0;
+ ret = 0;
+ of_node_put(dp);
- return -ENXIO;
+ return ret;
}
module_init(control_init);
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig
new file mode 100644
index 00000000000..f99af931d4f
--- /dev/null
+++ b/drivers/video/display/Kconfig
@@ -0,0 +1,24 @@
+#
+# Display drivers configuration
+#
+
+menu "Display device support"
+
+config DISPLAY_SUPPORT
+ tristate "Display panel/monitor support"
+ ---help---
+ This framework adds support for low-level control of a display.
+ This includes support for power.
+
+ Enable this to be able to choose the drivers for controlling the
+ physical display panel/monitor on some platforms. This not only
+ covers LCD displays for PDAs but also other types of displays
+ such as CRT, TVout etc.
+
+ To have support for your specific display panel you will have to
+ select the proper drivers which depend on this option.
+
+comment "Display hardware drivers"
+ depends on DISPLAY_SUPPORT
+
+endmenu
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile
new file mode 100644
index 00000000000..c0ea832bf17
--- /dev/null
+++ b/drivers/video/display/Makefile
@@ -0,0 +1,6 @@
+# Display drivers
+
+display-objs := display-sysfs.o
+
+obj-$(CONFIG_DISPLAY_SUPPORT) += display.o
+
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c
new file mode 100644
index 00000000000..35477177bef
--- /dev/null
+++ b/drivers/video/display/display-sysfs.c
@@ -0,0 +1,217 @@
+/*
+ * display-sysfs.c - Display output driver sysfs interface
+ *
+ * Copyright (C) 2007 James Simmons <jsimmons@infradead.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/display.h>
+#include <linux/ctype.h>
+#include <linux/idr.h>
+#include <linux/err.h>
+
+static ssize_t display_show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name);
+}
+
+static ssize_t display_show_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type);
+}
+
+static ssize_t display_show_contrast(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+ ssize_t rc = -ENXIO;
+
+ mutex_lock(&dsp->lock);
+ if (likely(dsp->driver) && dsp->driver->get_contrast)
+ rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp));
+ mutex_unlock(&dsp->lock);
+ return rc;
+}
+
+static ssize_t display_store_contrast(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+ ssize_t ret = -EINVAL, size;
+ int contrast;
+ char *endp;
+
+ contrast = simple_strtoul(buf, &endp, 0);
+ size = endp - buf;
+
+ if (*endp && isspace(*endp))
+ size++;
+
+ if (size != count)
+ return ret;
+
+ mutex_lock(&dsp->lock);
+ if (likely(dsp->driver && dsp->driver->set_contrast)) {
+ pr_debug("display: set contrast to %d\n", contrast);
+ dsp->driver->set_contrast(dsp, contrast);
+ ret = count;
+ }
+ mutex_unlock(&dsp->lock);
+ return ret;
+}
+
+static ssize_t display_show_max_contrast(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+ ssize_t rc = -ENXIO;
+
+ mutex_lock(&dsp->lock);
+ if (likely(dsp->driver))
+ rc = sprintf(buf, "%d\n", dsp->driver->max_contrast);
+ mutex_unlock(&dsp->lock);
+ return rc;
+}
+
+static struct device_attribute display_attrs[] = {
+ __ATTR(name, S_IRUGO, display_show_name, NULL),
+ __ATTR(type, S_IRUGO, display_show_type, NULL),
+ __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast),
+ __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL),
+};
+
+static int display_suspend(struct device *dev, pm_message_t state)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+
+ mutex_lock(&dsp->lock);
+ if (likely(dsp->driver->suspend))
+ dsp->driver->suspend(dsp, state);
+ mutex_unlock(&dsp->lock);
+ return 0;
+};
+
+static int display_resume(struct device *dev)
+{
+ struct display_device *dsp = dev_get_drvdata(dev);
+
+ mutex_lock(&dsp->lock);
+ if (likely(dsp->driver->resume))
+ dsp->driver->resume(dsp);
+ mutex_unlock(&dsp->lock);
+ return 0;
+};
+
+static struct mutex allocated_dsp_lock;
+static DEFINE_IDR(allocated_dsp);
+static struct class *display_class;
+
+struct display_device *display_device_register(struct display_driver *driver,
+ struct device *parent, void *devdata)
+{
+ struct display_device *new_dev = NULL;
+ int ret = -EINVAL;
+
+ if (unlikely(!driver))
+ return ERR_PTR(ret);
+
+ mutex_lock(&allocated_dsp_lock);
+ ret = idr_pre_get(&allocated_dsp, GFP_KERNEL);
+ mutex_unlock(&allocated_dsp_lock);
+ if (!ret)
+ return ERR_PTR(ret);
+
+ new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL);
+ if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) {
+ // Reserve the index for this display
+ mutex_lock(&allocated_dsp_lock);
+ ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx);
+ mutex_unlock(&allocated_dsp_lock);
+
+ if (!ret) {
+ new_dev->dev = device_create(display_class, parent, 0,
+ "display%d", new_dev->idx);
+ if (!IS_ERR(new_dev->dev)) {
+ dev_set_drvdata(new_dev->dev, new_dev);
+ new_dev->parent = parent;
+ new_dev->driver = driver;
+ mutex_init(&new_dev->lock);
+ return new_dev;
+ }
+ mutex_lock(&allocated_dsp_lock);
+ idr_remove(&allocated_dsp, new_dev->idx);
+ mutex_unlock(&allocated_dsp_lock);
+ ret = -EINVAL;
+ }
+ }
+ kfree(new_dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(display_device_register);
+
+void display_device_unregister(struct display_device *ddev)
+{
+ if (!ddev)
+ return;
+ // Free device
+ mutex_lock(&ddev->lock);
+ device_unregister(ddev->dev);
+ mutex_unlock(&ddev->lock);
+ // Mark device index as avaliable
+ mutex_lock(&allocated_dsp_lock);
+ idr_remove(&allocated_dsp, ddev->idx);
+ mutex_unlock(&allocated_dsp_lock);
+ kfree(ddev);
+}
+EXPORT_SYMBOL(display_device_unregister);
+
+static int __init display_class_init(void)
+{
+ display_class = class_create(THIS_MODULE, "display");
+ if (IS_ERR(display_class)) {
+ printk(KERN_ERR "Failed to create display class\n");
+ display_class = NULL;
+ return -EINVAL;
+ }
+ display_class->dev_attrs = display_attrs;
+ display_class->suspend = display_suspend;
+ display_class->resume = display_resume;
+ mutex_init(&allocated_dsp_lock);
+ return 0;
+}
+
+static void __exit display_class_exit(void)
+{
+ class_destroy(display_class);
+}
+
+module_init(display_class_init);
+module_exit(display_class_exit);
+
+MODULE_DESCRIPTION("Display Hardware handling");
+MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 29e07c10988..ca2c54ce508 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -403,17 +403,10 @@ static inline unsigned long copy_to_user16(void *to, const void *from,
static ssize_t
-epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
+epson1355fb_read(struct fb_info *info, char *buf, size_t count, loff_t * ppos)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
unsigned long p = *ppos;
- /* from fbmem.c except for our own copy_*_user */
- if (!info || !info->screen_base)
- return -ENODEV;
-
if (p >= info->fix.smem_len)
return 0;
if (count >= info->fix.smem_len)
@@ -434,20 +427,13 @@ epson1355fb_read(struct file *file, char *buf, size_t count, loff_t * ppos)
}
static ssize_t
-epson1355fb_write(struct file *file, const char *buf,
+epson1355fb_write(struct fb_info *info, const char *buf,
size_t count, loff_t * ppos)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- int fbidx = iminor(inode);
- struct fb_info *info = registered_fb[fbidx];
unsigned long p = *ppos;
int err;
/* from fbmem.c except for our own copy_*_user */
- if (!info || !info->screen_base)
- return -ENODEV;
-
- /* from fbmem.c except for our own copy_*_user */
if (p > info->fix.smem_len)
return -ENOSPC;
if (count >= info->fix.smem_len)
@@ -650,9 +636,10 @@ int __init epson1355fb_probe(struct platform_device *dev)
}
info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev);
- if (!info)
+ if (!info) {
rc = -ENOMEM;
goto bail;
+ }
default_par = info->par;
default_par->reg_addr = (unsigned long) ioremap(EPSON1355FB_REGS_PHYS, EPSON1355FB_REGS_LEN);
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
new file mode 100644
index 00000000000..1a8643f053d
--- /dev/null
+++ b/drivers/video/fb_defio.c
@@ -0,0 +1,151 @@
+/*
+ * linux/drivers/video/fb_defio.c
+ *
+ * Copyright (C) 2006 Jaya Kumar
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+
+/* to support deferred IO */
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
+
+/* this is to find and return the vmalloc-ed fb pages */
+static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma,
+ unsigned long vaddr, int *type)
+{
+ unsigned long offset;
+ struct page *page;
+ struct fb_info *info = vma->vm_private_data;
+ /* info->screen_base is in System RAM */
+ void *screen_base = (void __force *) info->screen_base;
+
+ offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+ if (offset >= info->fix.smem_len)
+ return NOPAGE_SIGBUS;
+
+ page = vmalloc_to_page(screen_base + offset);
+ if (!page)
+ return NOPAGE_OOM;
+
+ get_page(page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return page;
+}
+
+int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct fb_info *info = file->private_data;
+
+ /* Kill off the delayed work */
+ cancel_rearming_delayed_work(&info->deferred_work);
+
+ /* Run it immediately */
+ return schedule_delayed_work(&info->deferred_work, 0);
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
+
+/* vm_ops->page_mkwrite handler */
+static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
+ struct page *page)
+{
+ struct fb_info *info = vma->vm_private_data;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ /* this is a callback we get when userspace first tries to
+ write to the page. we schedule a workqueue. that workqueue
+ will eventually mkclean the touched pages and execute the
+ deferred framebuffer IO. then if userspace touches a page
+ again, we repeat the same scheme */
+
+ /* protect against the workqueue changing the page list */
+ mutex_lock(&fbdefio->lock);
+ list_add(&page->lru, &fbdefio->pagelist);
+ mutex_unlock(&fbdefio->lock);
+
+ /* come back after delay to process the deferred IO */
+ schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+ return 0;
+}
+
+static struct vm_operations_struct fb_deferred_io_vm_ops = {
+ .nopage = fb_deferred_io_nopage,
+ .page_mkwrite = fb_deferred_io_mkwrite,
+};
+
+static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ vma->vm_ops = &fb_deferred_io_vm_ops;
+ vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND );
+ vma->vm_private_data = info;
+ return 0;
+}
+
+/* workqueue callback */
+static void fb_deferred_io_work(struct work_struct *work)
+{
+ struct fb_info *info = container_of(work, struct fb_info,
+ deferred_work.work);
+ struct list_head *node, *next;
+ struct page *cur;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ /* here we mkclean the pages, then do all deferred IO */
+ mutex_lock(&fbdefio->lock);
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ lock_page(cur);
+ page_mkclean(cur);
+ unlock_page(cur);
+ }
+
+ /* driver's callback with pagelist */
+ fbdefio->deferred_io(info, &fbdefio->pagelist);
+
+ /* clear the list */
+ list_for_each_safe(node, next, &fbdefio->pagelist) {
+ list_del(node);
+ }
+ mutex_unlock(&fbdefio->lock);
+}
+
+void fb_deferred_io_init(struct fb_info *info)
+{
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ BUG_ON(!fbdefio);
+ mutex_init(&fbdefio->lock);
+ info->fbops->fb_mmap = fb_deferred_io_mmap;
+ INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work);
+ INIT_LIST_HEAD(&fbdefio->pagelist);
+ if (fbdefio->delay == 0) /* set a default of 1 s */
+ fbdefio->delay = HZ;
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_init);
+
+void fb_deferred_io_cleanup(struct fb_info *info)
+{
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ BUG_ON(!fbdefio);
+ cancel_delayed_work(&info->deferred_work);
+ flush_scheduled_work();
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h
new file mode 100644
index 00000000000..c5c45203833
--- /dev/null
+++ b/drivers/video/fb_draw.h
@@ -0,0 +1,72 @@
+#ifndef _FB_DRAW_H
+#define _FB_DRAW_H
+
+#include <asm/types.h>
+
+ /*
+ * Compose two values, using a bitmask as decision value
+ * This is equivalent to (a & mask) | (b & ~mask)
+ */
+
+static inline unsigned long
+comp(unsigned long a, unsigned long b, unsigned long mask)
+{
+ return ((a ^ b) & mask) ^ b;
+}
+
+ /*
+ * Create a pattern with the given pixel's color
+ */
+
+#if BITS_PER_LONG == 64
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+ switch (bpp) {
+ case 1:
+ return 0xfffffffffffffffful*pixel;
+ case 2:
+ return 0x5555555555555555ul*pixel;
+ case 4:
+ return 0x1111111111111111ul*pixel;
+ case 8:
+ return 0x0101010101010101ul*pixel;
+ case 12:
+ return 0x0001001001001001ul*pixel;
+ case 16:
+ return 0x0001000100010001ul*pixel;
+ case 24:
+ return 0x0000000001000001ul*pixel;
+ case 32:
+ return 0x0000000100000001ul*pixel;
+ default:
+ panic("pixel_to_pat(): unsupported pixelformat\n");
+ }
+}
+#else
+static inline unsigned long
+pixel_to_pat( u32 bpp, u32 pixel)
+{
+ switch (bpp) {
+ case 1:
+ return 0xfffffffful*pixel;
+ case 2:
+ return 0x55555555ul*pixel;
+ case 4:
+ return 0x11111111ul*pixel;
+ case 8:
+ return 0x01010101ul*pixel;
+ case 12:
+ return 0x00001001ul*pixel;
+ case 16:
+ return 0x00010001ul*pixel;
+ case 24:
+ return 0x00000001ul*pixel;
+ case 32:
+ return 0x00000001ul*pixel;
+ default:
+ panic("pixel_to_pat(): unsupported pixelformat\n");
+ }
+}
+#endif
+#endif /* FB_DRAW_H */
diff --git a/drivers/video/fb_sys_fops.c b/drivers/video/fb_sys_fops.c
new file mode 100644
index 00000000000..cf2538d669c
--- /dev/null
+++ b/drivers/video/fb_sys_fops.c
@@ -0,0 +1,104 @@
+/*
+ * linux/drivers/video/fb_sys_read.c - Generic file operations where
+ * framebuffer is in system RAM
+ *
+ * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/fb.h>
+#include <linux/module.h>
+#include <asm/uaccess.h>
+
+ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *src;
+ int err = 0;
+ unsigned long total_size;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p >= total_size)
+ return 0;
+
+ if (count >= total_size)
+ count = total_size;
+
+ if (count + p > total_size)
+ count = total_size - p;
+
+ src = (void __force *)(info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ if (copy_to_user(buf, src, count))
+ err = -EFAULT;
+
+ if (!err)
+ *ppos += count;
+
+ return (err) ? err : count;
+}
+EXPORT_SYMBOL_GPL(fb_sys_read);
+
+ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ void *dst;
+ int err = 0;
+ unsigned long total_size;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
+
+ count = total_size - p;
+ }
+
+ dst = (void __force *) (info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ if (copy_from_user(dst, buf, count))
+ err = -EFAULT;
+
+ if (!err)
+ *ppos += count;
+
+ return (err) ? err : count;
+}
+EXPORT_SYMBOL_GPL(fb_sys_write);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic file read (fb in system RAM)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 28225265159..38c2e2558f5 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -354,59 +354,59 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst,
if (rotate == FB_ROTATE_UD) {
fb_rotate_logo_ud(image->data, dst, image->width,
image->height);
- image->dx = info->var.xres - image->width;
- image->dy = info->var.yres - image->height;
+ image->dx = info->var.xres - image->width - image->dx;
+ image->dy = info->var.yres - image->height - image->dy;
} else if (rotate == FB_ROTATE_CW) {
fb_rotate_logo_cw(image->data, dst, image->width,
image->height);
tmp = image->width;
image->width = image->height;
image->height = tmp;
- image->dx = info->var.xres - image->width;
+ tmp = image->dy;
+ image->dy = image->dx;
+ image->dx = info->var.xres - image->width - tmp;
} else if (rotate == FB_ROTATE_CCW) {
fb_rotate_logo_ccw(image->data, dst, image->width,
image->height);
tmp = image->width;
image->width = image->height;
image->height = tmp;
- image->dy = info->var.yres - image->height;
+ tmp = image->dx;
+ image->dx = image->dy;
+ image->dy = info->var.yres - image->height - tmp;
}
image->data = dst;
}
static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
- int rotate)
+ int rotate, unsigned int num)
{
- int x;
+ unsigned int x;
if (rotate == FB_ROTATE_UR) {
- for (x = 0; x < num_online_cpus() &&
- x * (fb_logo.logo->width + 8) <=
- info->var.xres - fb_logo.logo->width; x++) {
+ for (x = 0;
+ x < num && image->dx + image->width <= info->var.xres;
+ x++) {
info->fbops->fb_imageblit(info, image);
- image->dx += fb_logo.logo->width + 8;
+ image->dx += image->width + 8;
}
} else if (rotate == FB_ROTATE_UD) {
- for (x = 0; x < num_online_cpus() &&
- x * (fb_logo.logo->width + 8) <=
- info->var.xres - fb_logo.logo->width; x++) {
+ for (x = 0; x < num && image->dx >= 0; x++) {
info->fbops->fb_imageblit(info, image);
- image->dx -= fb_logo.logo->width + 8;
+ image->dx -= image->width + 8;
}
} else if (rotate == FB_ROTATE_CW) {
- for (x = 0; x < num_online_cpus() &&
- x * (fb_logo.logo->width + 8) <=
- info->var.yres - fb_logo.logo->width; x++) {
+ for (x = 0;
+ x < num && image->dy + image->height <= info->var.yres;
+ x++) {
info->fbops->fb_imageblit(info, image);
- image->dy += fb_logo.logo->width + 8;
+ image->dy += image->height + 8;
}
} else if (rotate == FB_ROTATE_CCW) {
- for (x = 0; x < num_online_cpus() &&
- x * (fb_logo.logo->width + 8) <=
- info->var.yres - fb_logo.logo->width; x++) {
+ for (x = 0; x < num && image->dy >= 0; x++) {
info->fbops->fb_imageblit(info, image);
- image->dy -= fb_logo.logo->width + 8;
+ image->dy -= image->height + 8;
}
}
}
@@ -418,7 +418,8 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
memset(&fb_logo, 0, sizeof(struct logo_data));
- if (info->flags & FBINFO_MISC_TILEBLITTING)
+ if (info->flags & FBINFO_MISC_TILEBLITTING ||
+ info->flags & FBINFO_MODULE)
return 0;
if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
@@ -483,7 +484,8 @@ int fb_show_logo(struct fb_info *info, int rotate)
struct fb_image image;
/* Return if the frame buffer is not mapped or suspended */
- if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
+ if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING ||
+ info->flags & FBINFO_MODULE)
return 0;
image.depth = 8;
@@ -532,7 +534,7 @@ int fb_show_logo(struct fb_info *info, int rotate)
fb_rotate_logo(info, logo_rotate, &image, rotate);
}
- fb_do_show_logo(info, &image, rotate);
+ fb_do_show_logo(info, &image, rotate, num_online_cpus());
kfree(palette);
if (saved_pseudo_palette != NULL)
@@ -586,7 +588,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
return -EPERM;
if (info->fbops->fb_read)
- return info->fbops->fb_read(file, buf, count, ppos);
+ return info->fbops->fb_read(info, buf, count, ppos);
total_size = info->screen_size;
@@ -661,7 +663,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
return -EPERM;
if (info->fbops->fb_write)
- return info->fbops->fb_write(file, buf, count, ppos);
+ return info->fbops->fb_write(info, buf, count, ppos);
total_size = info->screen_size;
@@ -771,14 +773,37 @@ fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)
return 0;
}
+static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var,
+ u32 activate)
+{
+ struct fb_event event;
+ struct fb_blit_caps caps, fbcaps;
+ int err = 0;
+
+ memset(&caps, 0, sizeof(caps));
+ memset(&fbcaps, 0, sizeof(fbcaps));
+ caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0;
+ event.info = info;
+ event.data = &caps;
+ fb_notifier_call_chain(FB_EVENT_GET_REQ, &event);
+ info->fbops->fb_get_caps(info, &fbcaps, var);
+
+ if (((fbcaps.x ^ caps.x) & caps.x) ||
+ ((fbcaps.y ^ caps.y) & caps.y) ||
+ (fbcaps.len < caps.len))
+ err = -EINVAL;
+
+ return err;
+}
+
int
fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
- int err, flags = info->flags;
+ int flags = info->flags;
+ int ret = 0;
if (var->activate & FB_ACTIVATE_INV_MODE) {
struct fb_videomode mode1, mode2;
- int ret = 0;
fb_var_to_videomode(&mode1, var);
fb_var_to_videomode(&mode2, &info->var);
@@ -796,40 +821,51 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
if (!ret)
fb_delete_videomode(&mode1, &info->modelist);
- return ret;
+
+ ret = (ret) ? -EINVAL : 0;
+ goto done;
}
if ((var->activate & FB_ACTIVATE_FORCE) ||
memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
+ u32 activate = var->activate;
+
if (!info->fbops->fb_check_var) {
*var = info->var;
- return 0;
+ goto done;
}
- if ((err = info->fbops->fb_check_var(var, info)))
- return err;
+ ret = info->fbops->fb_check_var(var, info);
+
+ if (ret)
+ goto done;
if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
struct fb_videomode mode;
- int err = 0;
+
+ if (info->fbops->fb_get_caps) {
+ ret = fb_check_caps(info, var, activate);
+
+ if (ret)
+ goto done;
+ }
info->var = *var;
+
if (info->fbops->fb_set_par)
info->fbops->fb_set_par(info);
fb_pan_display(info, &info->var);
-
fb_set_cmap(&info->cmap, info);
-
fb_var_to_videomode(&mode, &info->var);
if (info->modelist.prev && info->modelist.next &&
!list_empty(&info->modelist))
- err = fb_add_videomode(&mode, &info->modelist);
+ ret = fb_add_videomode(&mode, &info->modelist);
- if (!err && (flags & FBINFO_MISC_USEREVENT)) {
+ if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
struct fb_event event;
- int evnt = (var->activate & FB_ACTIVATE_ALL) ?
+ int evnt = (activate & FB_ACTIVATE_ALL) ?
FB_EVENT_MODE_CHANGE_ALL :
FB_EVENT_MODE_CHANGE;
@@ -839,7 +875,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
}
}
}
- return 0;
+
+ done:
+ return ret;
}
int
@@ -1198,6 +1236,10 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
#elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#elif defined(__avr32__)
+ vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+ & ~_PAGE_CACHABLE)
+ | (_PAGE_BUFFER | _PAGE_DIRTY));
#elif defined(__ia64__)
if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
@@ -1266,6 +1308,9 @@ static const struct file_operations fb_fops = {
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
.get_unmapped_area = get_fb_unmapped_area,
#endif
+#ifdef CONFIG_FB_DEFERRED_IO
+ .fsync = fb_deferred_io_fsync,
+#endif
};
struct class *fb_class;
@@ -1316,6 +1361,12 @@ register_framebuffer(struct fb_info *fb_info)
}
fb_info->pixmap.offset = 0;
+ if (!fb_info->pixmap.blit_x)
+ fb_info->pixmap.blit_x = ~(u32)0;
+
+ if (!fb_info->pixmap.blit_y)
+ fb_info->pixmap.blit_y = ~(u32)0;
+
if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 6b385c39b8b..438b9411905 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -48,8 +48,9 @@
#define DPRINTK(fmt, args...)
#endif
-#define FBMON_FIX_HEADER 1
-#define FBMON_FIX_INPUT 2
+#define FBMON_FIX_HEADER 1
+#define FBMON_FIX_INPUT 2
+#define FBMON_FIX_TIMINGS 3
#ifdef CONFIG_FB_MODE_HELPERS
struct broken_edid {
@@ -71,6 +72,12 @@ static const struct broken_edid brokendb[] = {
.model = 0x5a44,
.fix = FBMON_FIX_INPUT,
},
+ /* Sharp UXGA? */
+ {
+ .manufacturer = "SHP",
+ .model = 0x138e,
+ .fix = FBMON_FIX_TIMINGS,
+ },
};
static const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff,
@@ -87,6 +94,55 @@ static void copy_string(unsigned char *c, unsigned char *s)
while (i-- && (*--s == 0x20)) *s = 0;
}
+static int edid_is_serial_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) &&
+ (block[2] == 0x00) && (block[3] == 0xff) &&
+ (block[4] == 0x00))
+ return 1;
+ else
+ return 0;
+}
+
+static int edid_is_ascii_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) &&
+ (block[2] == 0x00) && (block[3] == 0xfe) &&
+ (block[4] == 0x00))
+ return 1;
+ else
+ return 0;
+}
+
+static int edid_is_limits_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) &&
+ (block[2] == 0x00) && (block[3] == 0xfd) &&
+ (block[4] == 0x00))
+ return 1;
+ else
+ return 0;
+}
+
+static int edid_is_monitor_block(unsigned char *block)
+{
+ if ((block[0] == 0x00) && (block[1] == 0x00) &&
+ (block[2] == 0x00) && (block[3] == 0xfc) &&
+ (block[4] == 0x00))
+ return 1;
+ else
+ return 0;
+}
+
+static int edid_is_timing_block(unsigned char *block)
+{
+ if ((block[0] != 0x00) || (block[1] != 0x00) ||
+ (block[2] != 0x00) || (block[4] != 0x00))
+ return 1;
+ else
+ return 0;
+}
+
static int check_edid(unsigned char *edid)
{
unsigned char *block = edid + ID_MANUFACTURER_NAME, manufacturer[4];
@@ -104,9 +160,6 @@ static int check_edid(unsigned char *edid)
for (i = 0; i < ARRAY_SIZE(brokendb); i++) {
if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) &&
brokendb[i].model == model) {
- printk("fbmon: The EDID Block of "
- "Manufacturer: %s Model: 0x%x is known to "
- "be broken,\n", manufacturer, model);
fix = brokendb[i].fix;
break;
}
@@ -115,8 +168,10 @@ static int check_edid(unsigned char *edid)
switch (fix) {
case FBMON_FIX_HEADER:
for (i = 0; i < 8; i++) {
- if (edid[i] != edid_v1_header[i])
+ if (edid[i] != edid_v1_header[i]) {
ret = fix;
+ break;
+ }
}
break;
case FBMON_FIX_INPUT:
@@ -126,14 +181,34 @@ static int check_edid(unsigned char *edid)
if (b[4] & 0x01 && b[0] & 0x80)
ret = fix;
break;
+ case FBMON_FIX_TIMINGS:
+ b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+ ret = fix;
+
+ for (i = 0; i < 4; i++) {
+ if (edid_is_limits_block(b)) {
+ ret = 0;
+ break;
+ }
+
+ b += DETAILED_TIMING_DESCRIPTION_SIZE;
+ }
+
+ break;
}
+ if (ret)
+ printk("fbmon: The EDID Block of "
+ "Manufacturer: %s Model: 0x%x is known to "
+ "be broken,\n", manufacturer, model);
+
return ret;
}
static void fix_edid(unsigned char *edid, int fix)
{
- unsigned char *b;
+ int i;
+ unsigned char *b, csum = 0;
switch (fix) {
case FBMON_FIX_HEADER:
@@ -145,6 +220,37 @@ static void fix_edid(unsigned char *edid, int fix)
b = edid + EDID_STRUCT_DISPLAY;
b[0] &= ~0x80;
edid[127] += 0x80;
+ break;
+ case FBMON_FIX_TIMINGS:
+ printk("fbmon: trying to fix monitor timings\n");
+ b = edid + DETAILED_TIMING_DESCRIPTIONS_START;
+ for (i = 0; i < 4; i++) {
+ if (!(edid_is_serial_block(b) ||
+ edid_is_ascii_block(b) ||
+ edid_is_monitor_block(b) ||
+ edid_is_timing_block(b))) {
+ b[0] = 0x00;
+ b[1] = 0x00;
+ b[2] = 0x00;
+ b[3] = 0xfd;
+ b[4] = 0x00;
+ b[5] = 60; /* vfmin */
+ b[6] = 60; /* vfmax */
+ b[7] = 30; /* hfmin */
+ b[8] = 75; /* hfmax */
+ b[9] = 17; /* pixclock - 170 MHz*/
+ b[10] = 0; /* GTF */
+ break;
+ }
+
+ b += DETAILED_TIMING_DESCRIPTION_SIZE;
+ }
+
+ for (i = 0; i < EDID_LENGTH - 1; i++)
+ csum += edid[i];
+
+ edid[127] = 256 - csum;
+ break;
}
}
@@ -273,46 +379,6 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs)
DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey);
}
-static int edid_is_serial_block(unsigned char *block)
-{
- if ((block[0] == 0x00) && (block[1] == 0x00) &&
- (block[2] == 0x00) && (block[3] == 0xff) &&
- (block[4] == 0x00))
- return 1;
- else
- return 0;
-}
-
-static int edid_is_ascii_block(unsigned char *block)
-{
- if ((block[0] == 0x00) && (block[1] == 0x00) &&
- (block[2] == 0x00) && (block[3] == 0xfe) &&
- (block[4] == 0x00))
- return 1;
- else
- return 0;
-}
-
-static int edid_is_limits_block(unsigned char *block)
-{
- if ((block[0] == 0x00) && (block[1] == 0x00) &&
- (block[2] == 0x00) && (block[3] == 0xfd) &&
- (block[4] == 0x00))
- return 1;
- else
- return 0;
-}
-
-static int edid_is_monitor_block(unsigned char *block)
-{
- if ((block[0] == 0x00) && (block[1] == 0x00) &&
- (block[2] == 0x00) && (block[3] == 0xfc) &&
- (block[4] == 0x00))
- return 1;
- else
- return 0;
-}
-
static void calc_mode_timings(int xres, int yres, int refresh,
struct fb_videomode *mode)
{
@@ -795,15 +861,6 @@ static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs)
}
}
-static int edid_is_timing_block(unsigned char *block)
-{
- if ((block[0] != 0x00) || (block[1] != 0x00) ||
- (block[2] != 0x00) || (block[4] != 0x00))
- return 1;
- else
- return 0;
-}
-
int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var)
{
int i;
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 40c80c8190e..d4a2c11d980 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -376,7 +376,7 @@ static ssize_t show_pan(struct device *device,
{
struct fb_info *fb_info = dev_get_drvdata(device);
return snprintf(buf, PAGE_SIZE, "%d,%d\n", fb_info->var.xoffset,
- fb_info->var.xoffset);
+ fb_info->var.yoffset);
}
static ssize_t show_name(struct device *device,
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index ca93a75f299..b7655c05da5 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -26,7 +26,6 @@
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <asm/io.h>
#include <asm/jazz.h>
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c
new file mode 100644
index 00000000000..abfcb50364c
--- /dev/null
+++ b/drivers/video/hecubafb.c
@@ -0,0 +1,471 @@
+/*
+ * linux/drivers/video/hecubafb.c -- FB driver for Hecuba controller
+ *
+ * Copyright (C) 2006, Jaya Kumar
+ * This work was sponsored by CIS(M) Sdn Bhd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
+ * This work was possible because of apollo display code from E-Ink's website
+ * http://support.eink.com/community
+ * All information used to write this code is from public material made
+ * available by E-Ink on its support site. Some commands such as 0xA4
+ * were found by looping through cmd=0x00 thru 0xFF and supplying random
+ * values. There are other commands that the display is capable of,
+ * beyond the 5 used here but they are more complex.
+ *
+ * This driver is written to be used with the Hecuba display controller
+ * board, and tested with the EInk 800x600 display in 1 bit mode.
+ * The interface between Hecuba and the host is TTL based GPIO. The
+ * GPIO requirements are 8 writable data lines and 6 lines for control.
+ * Only 4 of the controls are actually used here but 6 for future use.
+ * The driver requires the IO addresses for data and control GPIO at
+ * load time. It is also possible to use this display with a standard
+ * PC parallel port.
+ *
+ * General notes:
+ * - User must set hecubafb_enable=1 to enable it
+ * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR c2io_addr=0xIOADDR
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+
+/* Apollo controller specific defines */
+#define APOLLO_START_NEW_IMG 0xA0
+#define APOLLO_STOP_IMG_DATA 0xA1
+#define APOLLO_DISPLAY_IMG 0xA2
+#define APOLLO_ERASE_DISPLAY 0xA3
+#define APOLLO_INIT_DISPLAY 0xA4
+
+/* Hecuba interface specific defines */
+/* WUP is inverted, CD is inverted, DS is inverted */
+#define HCB_NWUP_BIT 0x01
+#define HCB_NDS_BIT 0x02
+#define HCB_RW_BIT 0x04
+#define HCB_NCD_BIT 0x08
+#define HCB_ACK_BIT 0x80
+
+/* Display specific information */
+#define DPY_W 600
+#define DPY_H 800
+
+struct hecubafb_par {
+ unsigned long dio_addr;
+ unsigned long cio_addr;
+ unsigned long c2io_addr;
+ unsigned char ctl;
+ struct fb_info *info;
+ unsigned int irq;
+};
+
+static struct fb_fix_screeninfo hecubafb_fix __devinitdata = {
+ .id = "hecubafb",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_MONO01,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo hecubafb_var __devinitdata = {
+ .xres = DPY_W,
+ .yres = DPY_H,
+ .xres_virtual = DPY_W,
+ .yres_virtual = DPY_H,
+ .bits_per_pixel = 1,
+ .nonstd = 1,
+};
+
+static unsigned long dio_addr;
+static unsigned long cio_addr;
+static unsigned long c2io_addr;
+static unsigned long splashval;
+static unsigned int nosplash;
+static unsigned int hecubafb_enable;
+static unsigned int irq;
+
+static DECLARE_WAIT_QUEUE_HEAD(hecubafb_waitq);
+
+static void hcb_set_ctl(struct hecubafb_par *par)
+{
+ outb(par->ctl, par->cio_addr);
+}
+
+static unsigned char hcb_get_ctl(struct hecubafb_par *par)
+{
+ return inb(par->c2io_addr);
+}
+
+static void hcb_set_data(struct hecubafb_par *par, unsigned char value)
+{
+ outb(value, par->dio_addr);
+}
+
+static int __devinit apollo_init_control(struct hecubafb_par *par)
+{
+ unsigned char ctl;
+ /* for init, we want the following setup to be set:
+ WUP = lo
+ ACK = hi
+ DS = hi
+ RW = hi
+ CD = lo
+ */
+
+ /* write WUP to lo, DS to hi, RW to hi, CD to lo */
+ par->ctl = HCB_NWUP_BIT | HCB_RW_BIT | HCB_NCD_BIT ;
+ par->ctl &= ~HCB_NDS_BIT;
+ hcb_set_ctl(par);
+
+ /* check ACK is not lo */
+ ctl = hcb_get_ctl(par);
+ if ((ctl & HCB_ACK_BIT)) {
+ printk(KERN_ERR "Fail because ACK is already low\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void hcb_wait_for_ack(struct hecubafb_par *par)
+{
+
+ int timeout;
+ unsigned char ctl;
+
+ timeout=500;
+ do {
+ ctl = hcb_get_ctl(par);
+ if ((ctl & HCB_ACK_BIT))
+ return;
+ udelay(1);
+ } while (timeout--);
+ printk(KERN_ERR "timed out waiting for ack\n");
+}
+
+static void hcb_wait_for_ack_clear(struct hecubafb_par *par)
+{
+
+ int timeout;
+ unsigned char ctl;
+
+ timeout=500;
+ do {
+ ctl = hcb_get_ctl(par);
+ if (!(ctl & HCB_ACK_BIT))
+ return;
+ udelay(1);
+ } while (timeout--);
+ printk(KERN_ERR "timed out waiting for clear\n");
+}
+
+static void apollo_send_data(struct hecubafb_par *par, unsigned char data)
+{
+ /* set data */
+ hcb_set_data(par, data);
+
+ /* set DS low */
+ par->ctl |= HCB_NDS_BIT;
+ hcb_set_ctl(par);
+
+ hcb_wait_for_ack(par);
+
+ /* set DS hi */
+ par->ctl &= ~(HCB_NDS_BIT);
+ hcb_set_ctl(par);
+
+ hcb_wait_for_ack_clear(par);
+}
+
+static void apollo_send_command(struct hecubafb_par *par, unsigned char data)
+{
+ /* command so set CD to high */
+ par->ctl &= ~(HCB_NCD_BIT);
+ hcb_set_ctl(par);
+
+ /* actually strobe with command */
+ apollo_send_data(par, data);
+
+ /* clear CD back to low */
+ par->ctl |= (HCB_NCD_BIT);
+ hcb_set_ctl(par);
+}
+
+/* main hecubafb functions */
+
+static void hecubafb_dpy_update(struct hecubafb_par *par)
+{
+ int i;
+ unsigned char *buf = (unsigned char __force *)par->info->screen_base;
+
+ apollo_send_command(par, 0xA0);
+
+ for (i=0; i < (DPY_W*DPY_H/8); i++) {
+ apollo_send_data(par, *(buf++));
+ }
+
+ apollo_send_command(par, 0xA1);
+ apollo_send_command(par, 0xA2);
+}
+
+/* this is called back from the deferred io workqueue */
+static void hecubafb_dpy_deferred_io(struct fb_info *info,
+ struct list_head *pagelist)
+{
+ hecubafb_dpy_update(info->par);
+}
+
+static void hecubafb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct hecubafb_par *par = info->par;
+
+ sys_fillrect(info, rect);
+
+ hecubafb_dpy_update(par);
+}
+
+static void hecubafb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct hecubafb_par *par = info->par;
+
+ sys_copyarea(info, area);
+
+ hecubafb_dpy_update(par);
+}
+
+static void hecubafb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct hecubafb_par *par = info->par;
+
+ sys_imageblit(info, image);
+
+ hecubafb_dpy_update(par);
+}
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t hecubafb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long p;
+ int err=-EINVAL;
+ struct hecubafb_par *par;
+ unsigned int xres;
+ unsigned int fbmemlength;
+
+ p = *ppos;
+ par = info->par;
+ xres = info->var.xres;
+ fbmemlength = (xres * info->var.yres)/8;
+
+ if (p > fbmemlength)
+ return -ENOSPC;
+
+ err = 0;
+ if ((count + p) > fbmemlength) {
+ count = fbmemlength - p;
+ err = -ENOSPC;
+ }
+
+ if (count) {
+ char *base_addr;
+
+ base_addr = (char __force *)info->screen_base;
+ count -= copy_from_user(base_addr + p, buf, count);
+ *ppos += count;
+ err = -EFAULT;
+ }
+
+ hecubafb_dpy_update(par);
+
+ if (count)
+ return count;
+
+ return err;
+}
+
+static struct fb_ops hecubafb_ops = {
+ .owner = THIS_MODULE,
+ .fb_read = fb_sys_read,
+ .fb_write = hecubafb_write,
+ .fb_fillrect = hecubafb_fillrect,
+ .fb_copyarea = hecubafb_copyarea,
+ .fb_imageblit = hecubafb_imageblit,
+};
+
+static struct fb_deferred_io hecubafb_defio = {
+ .delay = HZ,
+ .deferred_io = hecubafb_dpy_deferred_io,
+};
+
+static int __devinit hecubafb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int retval = -ENOMEM;
+ int videomemorysize;
+ unsigned char *videomemory;
+ struct hecubafb_par *par;
+
+ videomemorysize = (DPY_W*DPY_H)/8;
+
+ if (!(videomemory = vmalloc(videomemorysize)))
+ return retval;
+
+ memset(videomemory, 0, videomemorysize);
+
+ info = framebuffer_alloc(sizeof(struct hecubafb_par), &dev->dev);
+ if (!info)
+ goto err;
+
+ info->screen_base = (char __iomem *) videomemory;
+ info->fbops = &hecubafb_ops;
+
+ info->var = hecubafb_var;
+ info->fix = hecubafb_fix;
+ info->fix.smem_len = videomemorysize;
+ par = info->par;
+ par->info = info;
+
+ if (!dio_addr || !cio_addr || !c2io_addr) {
+ printk(KERN_WARNING "no IO addresses supplied\n");
+ goto err1;
+ }
+ par->dio_addr = dio_addr;
+ par->cio_addr = cio_addr;
+ par->c2io_addr = c2io_addr;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ info->fbdefio = &hecubafb_defio;
+ fb_deferred_io_init(info);
+
+ retval = register_framebuffer(info);
+ if (retval < 0)
+ goto err1;
+ platform_set_drvdata(dev, info);
+
+ printk(KERN_INFO
+ "fb%d: Hecuba frame buffer device, using %dK of video memory\n",
+ info->node, videomemorysize >> 10);
+
+ /* this inits the dpy */
+ apollo_init_control(par);
+
+ apollo_send_command(par, APOLLO_INIT_DISPLAY);
+ apollo_send_data(par, 0x81);
+
+ /* have to wait while display resets */
+ udelay(1000);
+
+ /* if we were told to splash the screen, we just clear it */
+ if (!nosplash) {
+ apollo_send_command(par, APOLLO_ERASE_DISPLAY);
+ apollo_send_data(par, splashval);
+ }
+
+ return 0;
+err1:
+ framebuffer_release(info);
+err:
+ vfree(videomemory);
+ return retval;
+}
+
+static int __devexit hecubafb_remove(struct platform_device *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+
+ if (info) {
+ fb_deferred_io_cleanup(info);
+ unregister_framebuffer(info);
+ vfree((void __force *)info->screen_base);
+ framebuffer_release(info);
+ }
+ return 0;
+}
+
+static struct platform_driver hecubafb_driver = {
+ .probe = hecubafb_probe,
+ .remove = hecubafb_remove,
+ .driver = {
+ .name = "hecubafb",
+ },
+};
+
+static struct platform_device *hecubafb_device;
+
+static int __init hecubafb_init(void)
+{
+ int ret;
+
+ if (!hecubafb_enable) {
+ printk(KERN_ERR "Use hecubafb_enable to enable the device\n");
+ return -ENXIO;
+ }
+
+ ret = platform_driver_register(&hecubafb_driver);
+ if (!ret) {
+ hecubafb_device = platform_device_alloc("hecubafb", 0);
+ if (hecubafb_device)
+ ret = platform_device_add(hecubafb_device);
+ else
+ ret = -ENOMEM;
+
+ if (ret) {
+ platform_device_put(hecubafb_device);
+ platform_driver_unregister(&hecubafb_driver);
+ }
+ }
+ return ret;
+
+}
+
+static void __exit hecubafb_exit(void)
+{
+ platform_device_unregister(hecubafb_device);
+ platform_driver_unregister(&hecubafb_driver);
+}
+
+module_param(nosplash, uint, 0);
+MODULE_PARM_DESC(nosplash, "Disable doing the splash screen");
+module_param(hecubafb_enable, uint, 0);
+MODULE_PARM_DESC(hecubafb_enable, "Enable communication with Hecuba board");
+module_param(dio_addr, ulong, 0);
+MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480");
+module_param(cio_addr, ulong, 0);
+MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400");
+module_param(c2io_addr, ulong, 0);
+MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408");
+module_param(splashval, ulong, 0);
+MODULE_PARM_DESC(splashval, "Splash pattern: 0x00 is black, 0x01 is white");
+module_param(irq, uint, 0);
+MODULE_PARM_DESC(irq, "IRQ for the Hecuba board");
+
+module_init(hecubafb_init);
+module_exit(hecubafb_exit);
+
+MODULE_DESCRIPTION("fbdev driver for Hecuba board");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
index aa65ffce915..889e4ea5edc 100644
--- a/drivers/video/i810/i810.h
+++ b/drivers/video/i810/i810.h
@@ -133,7 +133,7 @@
/* Masks (AND ops) and OR's */
#define FB_START_MASK (0x3f << (32 - 6))
#define MMIO_ADDR_MASK (0x1FFF << (32 - 13))
-#define FREQ_MASK 0x1EF
+#define FREQ_MASK (1 << 4)
#define SCR_OFF 0x20
#define DRAM_ON 0x08
#define DRAM_OFF 0xE7
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 7e760197cf2..1a7d7789d87 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1717,7 +1717,7 @@ static int __devinit i810_alloc_agp_mem(struct fb_info *info)
* @info: pointer to device specific info structure
*
* DESCRIPTION:
- * Sets the the user monitor's horizontal and vertical
+ * Sets the user monitor's horizontal and vertical
* frequency limits
*/
static void __devinit i810_init_monspecs(struct fb_info *info)
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index f4ede5f6b58..61e4c8759b2 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -104,7 +104,8 @@ static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
chan->dinfo = dinfo;
chan->reg = reg;
- snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name);
+ snprintf(chan->adapter.name, sizeof(chan->adapter.name),
+ "intelfb %s", name);
chan->adapter.owner = THIS_MODULE;
chan->adapter.id = I2C_HW_B_INTELFB;
chan->adapter.algo_data = &chan->algo;
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index c1eb18bf088..16bc8d75e36 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -1428,6 +1428,24 @@ static void refresh_ring(struct intelfb_info *dinfo);
static void reset_state(struct intelfb_info *dinfo);
static void do_flush(struct intelfb_info *dinfo);
+static u32 get_ring_space(struct intelfb_info *dinfo)
+{
+ u32 ring_space;
+
+ if (dinfo->ring_tail >= dinfo->ring_head)
+ ring_space = dinfo->ring.size -
+ (dinfo->ring_tail - dinfo->ring_head);
+ else
+ ring_space = dinfo->ring_head - dinfo->ring_tail;
+
+ if (ring_space > RING_MIN_FREE)
+ ring_space -= RING_MIN_FREE;
+ else
+ ring_space = 0;
+
+ return ring_space;
+}
+
static int
wait_ring(struct intelfb_info *dinfo, int n)
{
@@ -1442,13 +1460,8 @@ wait_ring(struct intelfb_info *dinfo, int n)
end = jiffies + (HZ * 3);
while (dinfo->ring_space < n) {
dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
- if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head)
- dinfo->ring_space = dinfo->ring_head
- - (dinfo->ring_tail + RING_MIN_FREE);
- else
- dinfo->ring_space = (dinfo->ring.size +
- dinfo->ring_head)
- - (dinfo->ring_tail + RING_MIN_FREE);
+ dinfo->ring_space = get_ring_space(dinfo);
+
if (dinfo->ring_head != last_head) {
end = jiffies + (HZ * 3);
last_head = dinfo->ring_head;
@@ -1513,12 +1526,7 @@ refresh_ring(struct intelfb_info *dinfo)
dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;
dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;
- if (dinfo->ring_tail + RING_MIN_FREE < dinfo->ring_head)
- dinfo->ring_space = dinfo->ring_head
- - (dinfo->ring_tail + RING_MIN_FREE);
- else
- dinfo->ring_space = (dinfo->ring.size + dinfo->ring_head)
- - (dinfo->ring_tail + RING_MIN_FREE);
+ dinfo->ring_space = get_ring_space(dinfo);
}
static void
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index f0e6512c87f..9397bcef301 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -2,73 +2,69 @@
# Logo configuration
#
-menu "Logo configuration"
-
-config LOGO
+menuconfig LOGO
bool "Bootup logo"
depends on FB || SGI_NEWPORT_CONSOLE
help
Enable and select frame buffer bootup logos.
+if LOGO
+
config LOGO_LINUX_MONO
bool "Standard black and white Linux logo"
- depends on LOGO
default y
config LOGO_LINUX_VGA16
bool "Standard 16-color Linux logo"
- depends on LOGO
default y
config LOGO_LINUX_CLUT224
bool "Standard 224-color Linux logo"
- depends on LOGO
default y
config LOGO_DEC_CLUT224
bool "224-color Digital Equipment Corporation Linux logo"
- depends on LOGO && (MACH_DECSTATION || ALPHA)
+ depends on MACH_DECSTATION || ALPHA
default y
config LOGO_MAC_CLUT224
bool "224-color Macintosh Linux logo"
- depends on LOGO && MAC
+ depends on MAC
default y
config LOGO_PARISC_CLUT224
bool "224-color PA-RISC Linux logo"
- depends on LOGO && PARISC
+ depends on PARISC
default y
config LOGO_SGI_CLUT224
bool "224-color SGI Linux logo"
- depends on LOGO && (SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS)
+ depends on SGI_IP22 || SGI_IP27 || SGI_IP32 || X86_VISWS
default y
config LOGO_SUN_CLUT224
bool "224-color Sun Linux logo"
- depends on LOGO && SPARC
+ depends on SPARC
default y
config LOGO_SUPERH_MONO
bool "Black and white SuperH Linux logo"
- depends on LOGO && SUPERH
+ depends on SUPERH
default y
config LOGO_SUPERH_VGA16
bool "16-color SuperH Linux logo"
- depends on LOGO && SUPERH
+ depends on SUPERH
default y
config LOGO_SUPERH_CLUT224
bool "224-color SuperH Linux logo"
- depends on LOGO && SUPERH
+ depends on SUPERH
default y
config LOGO_M32R_CLUT224
bool "224-color M32R Linux logo"
- depends on LOGO && M32R
+ depends on M32R
default y
-endmenu
-
+endif # LOGO
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index 5ec718a5fe2..4baab7be58d 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -111,7 +111,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
b->mask.data = data;
b->mask.clock = clock;
b->adapter = matrox_i2c_adapter_template;
- snprintf(b->adapter.name, I2C_NAME_SIZE, name,
+ snprintf(b->adapter.name, sizeof(b->adapter.name), name,
minfo->fbcon.node);
i2c_set_adapdata(&b->adapter, b);
b->adapter.algo_data = &b->bac;
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index a5690a5f29d..9445cdb759b 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -72,7 +72,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
index a5c825d9946..c57aaadf410 100644
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -70,7 +70,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index cb2aa402ddf..c8559a756b7 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -93,7 +93,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 18886b629cb..5948e54b9ef 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -78,7 +78,7 @@
* (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
*
* (following author is not in any relation with this code, but his ideas
- * were used when writting this driver)
+ * were used when writing this driver)
*
* FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
*
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 3e517940c5a..3741ad72940 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -395,7 +395,7 @@ static int my_atoi(const char *name)
for (;; name++) {
switch (*name) {
- case '0'...'9':
+ case '0' ... '9':
val = 10*val+(*name-'0');
break;
default:
@@ -548,7 +548,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
} else
goto done;
break;
- case '0'...'9':
+ case '0' ... '9':
break;
case 'M':
if (!yres_specified)
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 395ccedde9a..bd30aba242d 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -665,6 +665,7 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
switch (var->bits_per_pixel) {
case 8: /* PSEUDOCOLOUR, 256 */
diff --git a/drivers/video/nvidia/nv_accel.c b/drivers/video/nvidia/nv_accel.c
index 9efb8a3854e..fa4821c5572 100644
--- a/drivers/video/nvidia/nv_accel.c
+++ b/drivers/video/nvidia/nv_accel.c
@@ -69,27 +69,38 @@ static const int NVCopyROP_PM[16] = {
0x5A, /* invert */
};
-static inline void NVFlush(struct nvidia_par *par)
+static inline void nvidiafb_safe_mode(struct fb_info *info)
{
+ struct nvidia_par *par = info->par;
+
+ touch_softlockup_watchdog();
+ info->pixmap.scan_align = 1;
+ par->lockup = 1;
+}
+
+static inline void NVFlush(struct fb_info *info)
+{
+ struct nvidia_par *par = info->par;
int count = 1000000000;
while (--count && READ_GET(par) != par->dmaPut) ;
if (!count) {
printk("nvidiafb: DMA Flush lockup\n");
- par->lockup = 1;
+ nvidiafb_safe_mode(info);
}
}
-static inline void NVSync(struct nvidia_par *par)
+static inline void NVSync(struct fb_info *info)
{
+ struct nvidia_par *par = info->par;
int count = 1000000000;
while (--count && NV_RD32(par->PGRAPH, 0x0700)) ;
if (!count) {
printk("nvidiafb: DMA Sync lockup\n");
- par->lockup = 1;
+ nvidiafb_safe_mode(info);
}
}
@@ -101,8 +112,9 @@ static void NVDmaKickoff(struct nvidia_par *par)
}
}
-static void NVDmaWait(struct nvidia_par *par, int size)
+static void NVDmaWait(struct fb_info *info, int size)
{
+ struct nvidia_par *par = info->par;
int dmaGet;
int count = 1000000000, cnt;
size++;
@@ -135,34 +147,38 @@ static void NVDmaWait(struct nvidia_par *par, int size)
}
if (!count) {
- printk("DMA Wait Lockup\n");
- par->lockup = 1;
+ printk("nvidiafb: DMA Wait Lockup\n");
+ nvidiafb_safe_mode(info);
}
}
-static void NVSetPattern(struct nvidia_par *par, u32 clr0, u32 clr1,
+static void NVSetPattern(struct fb_info *info, u32 clr0, u32 clr1,
u32 pat0, u32 pat1)
{
- NVDmaStart(par, PATTERN_COLOR_0, 4);
+ struct nvidia_par *par = info->par;
+
+ NVDmaStart(info, par, PATTERN_COLOR_0, 4);
NVDmaNext(par, clr0);
NVDmaNext(par, clr1);
NVDmaNext(par, pat0);
NVDmaNext(par, pat1);
}
-static void NVSetRopSolid(struct nvidia_par *par, u32 rop, u32 planemask)
+static void NVSetRopSolid(struct fb_info *info, u32 rop, u32 planemask)
{
+ struct nvidia_par *par = info->par;
+
if (planemask != ~0) {
- NVSetPattern(par, 0, planemask, ~0, ~0);
+ NVSetPattern(info, 0, planemask, ~0, ~0);
if (par->currentRop != (rop + 32)) {
- NVDmaStart(par, ROP_SET, 1);
+ NVDmaStart(info, par, ROP_SET, 1);
NVDmaNext(par, NVCopyROP_PM[rop]);
par->currentRop = rop + 32;
}
} else if (par->currentRop != rop) {
if (par->currentRop >= 16)
- NVSetPattern(par, ~0, ~0, ~0, ~0);
- NVDmaStart(par, ROP_SET, 1);
+ NVSetPattern(info, ~0, ~0, ~0, ~0);
+ NVDmaStart(info, par, ROP_SET, 1);
NVDmaNext(par, NVCopyROP[rop]);
par->currentRop = rop;
}
@@ -175,7 +191,7 @@ static void NVSetClippingRectangle(struct fb_info *info, int x1, int y1,
int h = y2 - y1 + 1;
int w = x2 - x1 + 1;
- NVDmaStart(par, CLIP_POINT, 2);
+ NVDmaStart(info, par, CLIP_POINT, 2);
NVDmaNext(par, (y1 << 16) | x1);
NVDmaNext(par, (h << 16) | w);
}
@@ -237,23 +253,23 @@ void NVResetGraphics(struct fb_info *info)
break;
}
- NVDmaStart(par, SURFACE_FORMAT, 4);
+ NVDmaStart(info, par, SURFACE_FORMAT, 4);
NVDmaNext(par, surfaceFormat);
NVDmaNext(par, pitch | (pitch << 16));
NVDmaNext(par, 0);
NVDmaNext(par, 0);
- NVDmaStart(par, PATTERN_FORMAT, 1);
+ NVDmaStart(info, par, PATTERN_FORMAT, 1);
NVDmaNext(par, patternFormat);
- NVDmaStart(par, RECT_FORMAT, 1);
+ NVDmaStart(info, par, RECT_FORMAT, 1);
NVDmaNext(par, rectFormat);
- NVDmaStart(par, LINE_FORMAT, 1);
+ NVDmaStart(info, par, LINE_FORMAT, 1);
NVDmaNext(par, lineFormat);
par->currentRop = ~0; /* set to something invalid */
- NVSetRopSolid(par, ROP_COPY, ~0);
+ NVSetRopSolid(info, ROP_COPY, ~0);
NVSetClippingRectangle(info, 0, 0, info->var.xres_virtual,
info->var.yres_virtual);
@@ -269,10 +285,10 @@ int nvidiafb_sync(struct fb_info *info)
return 0;
if (!par->lockup)
- NVFlush(par);
+ NVFlush(info);
if (!par->lockup)
- NVSync(par);
+ NVSync(info);
return 0;
}
@@ -287,7 +303,7 @@ void nvidiafb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
if (par->lockup)
return cfb_copyarea(info, region);
- NVDmaStart(par, BLIT_POINT_SRC, 3);
+ NVDmaStart(info, par, BLIT_POINT_SRC, 3);
NVDmaNext(par, (region->sy << 16) | region->sx);
NVDmaNext(par, (region->dy << 16) | region->dx);
NVDmaNext(par, (region->height << 16) | region->width);
@@ -312,19 +328,19 @@ void nvidiafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
color = ((u32 *) info->pseudo_palette)[rect->color];
if (rect->rop != ROP_COPY)
- NVSetRopSolid(par, rect->rop, ~0);
+ NVSetRopSolid(info, rect->rop, ~0);
- NVDmaStart(par, RECT_SOLID_COLOR, 1);
+ NVDmaStart(info, par, RECT_SOLID_COLOR, 1);
NVDmaNext(par, color);
- NVDmaStart(par, RECT_SOLID_RECTS(0), 2);
+ NVDmaStart(info, par, RECT_SOLID_RECTS(0), 2);
NVDmaNext(par, (rect->dx << 16) | rect->dy);
NVDmaNext(par, (rect->width << 16) | rect->height);
NVDmaKickoff(par);
if (rect->rop != ROP_COPY)
- NVSetRopSolid(par, ROP_COPY, ~0);
+ NVSetRopSolid(info, ROP_COPY, ~0);
}
static void nvidiafb_mono_color_expand(struct fb_info *info,
@@ -346,7 +362,7 @@ static void nvidiafb_mono_color_expand(struct fb_info *info,
bg = ((u32 *) info->pseudo_palette)[image->bg_color] | mask;
}
- NVDmaStart(par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
+ NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_CLIP, 7);
NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
NVDmaNext(par, ((image->dy + image->height) << 16) |
((image->dx + image->width) & 0xffff));
@@ -357,7 +373,7 @@ static void nvidiafb_mono_color_expand(struct fb_info *info,
NVDmaNext(par, (image->dy << 16) | (image->dx & 0xffff));
while (dsize >= RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS) {
- NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0),
+ NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_DATA(0),
RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS);
for (j = RECT_EXPAND_TWO_COLOR_DATA_MAX_DWORDS; j--;) {
@@ -370,7 +386,7 @@ static void nvidiafb_mono_color_expand(struct fb_info *info,
}
if (dsize) {
- NVDmaStart(par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
+ NVDmaStart(info, par, RECT_EXPAND_TWO_COLOR_DATA(0), dsize);
for (j = dsize; j--;) {
tmp = data[k++];
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index ea426115c6f..c627955aa12 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -149,8 +149,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
pll = NV_RD32(par->PMC, 0x4024);
M = pll & 0xFF;
N = (pll >> 8) & 0xFF;
- if (((par->Chipset & 0xfff0) == 0x0290) ||
- ((par->Chipset & 0xfff0) == 0x0390)) {
+ if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) {
MB = 1;
NB = 1;
} else {
@@ -686,7 +685,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk,
if ((par->Chipset & 0x0FF0) == 0x01A0) {
unsigned int uMClkPostDiv;
- dev = pci_find_slot(0, 3);
+ dev = pci_get_bus_and_slot(0, 3);
pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
@@ -694,11 +693,11 @@ static void nForceUpdateArbitrationSettings(unsigned VClk,
uMClkPostDiv = 4;
MClk = 400000 / uMClkPostDiv;
} else {
- dev = pci_find_slot(0, 5);
+ dev = pci_get_bus_and_slot(0, 5);
pci_read_config_dword(dev, 0x4c, &MClk);
MClk /= 1000;
}
-
+ pci_dev_put(dev);
pll = NV_RD32(par->PRAMDAC0, 0x0500);
M = (pll >> 0) & 0xFF;
N = (pll >> 8) & 0xFF;
@@ -707,19 +706,21 @@ static void nForceUpdateArbitrationSettings(unsigned VClk,
sim_data.pix_bpp = (char)pixelDepth;
sim_data.enable_video = 0;
sim_data.enable_mp = 0;
- pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+ pci_dev_put(dev);
sim_data.memory_type = (sim_data.memory_type >> 12) & 1;
sim_data.memory_width = 64;
- dev = pci_find_slot(0, 3);
+ dev = pci_get_bus_and_slot(0, 3);
pci_read_config_dword(dev, 0, &memctrl);
+ pci_dev_put(dev);
memctrl >>= 16;
if ((memctrl == 0x1A9) || (memctrl == 0x1AB) || (memctrl == 0x1ED)) {
int dimm[3];
- pci_find_slot(0, 2);
+ dev = pci_get_bus_and_slot(0, 2);
pci_read_config_dword(dev, 0x40, &dimm[0]);
dimm[0] = (dimm[0] >> 8) & 0x4f;
pci_read_config_dword(dev, 0x44, &dimm[1]);
@@ -731,6 +732,7 @@ static void nForceUpdateArbitrationSettings(unsigned VClk,
printk("nvidiafb: your nForce DIMMs are not arranged "
"in optimal banks!\n");
}
+ pci_dev_put(dev);
}
sim_data.mem_latency = 3;
@@ -960,6 +962,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
+ ((par->Chipset & 0xfff0) == 0x02E0) ||
((par->Chipset & 0xfff0) == 0x0290))
regions = 15;
for(i = 0; i < regions; i++) {
@@ -1272,6 +1275,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
0x00100000);
break;
case 0x0090:
+ case 0x02E0:
case 0x0290:
NV_WR32(par->PRAMDAC, 0x0608,
NV_RD32(par->PRAMDAC, 0x0608) |
@@ -1349,6 +1353,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
+ ((par->Chipset & 0xfff0) == 0x02E0) ||
((par->Chipset & 0xfff0) == 0x0290)) {
for (i = 0; i < 60; i++) {
NV_WR32(par->PGRAPH,
@@ -1400,6 +1405,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if ((par->Chipset & 0xfff0) == 0x0090 ||
(par->Chipset & 0xfff0) == 0x01D0 ||
+ (par->Chipset & 0xfff0) == 0x02E0 ||
(par->Chipset & 0xfff0) == 0x0290) {
NV_WR32(par->PGRAPH, 0x0DF0,
NV_RD32(par->PFB, 0x0200));
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index b8588973e40..afe4567e1ff 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -30,16 +30,14 @@ static void nvidia_gpio_setscl(void *data, int state)
struct nvidia_par *par = chan->par;
u32 val;
- VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
- val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+ val = NVReadCrtc(par, chan->ddc_base + 1) & 0xf0;
if (state)
val |= 0x20;
else
val &= ~0x20;
- VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
- VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+ NVWriteCrtc(par, chan->ddc_base + 1, val | 0x01);
}
static void nvidia_gpio_setsda(void *data, int state)
@@ -48,16 +46,14 @@ static void nvidia_gpio_setsda(void *data, int state)
struct nvidia_par *par = chan->par;
u32 val;
- VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
- val = VGA_RD08(par->PCIO, 0x3d5) & 0xf0;
+ val = NVReadCrtc(par, chan->ddc_base + 1) & 0xf0;
if (state)
val |= 0x10;
else
val &= ~0x10;
- VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base + 1);
- VGA_WR08(par->PCIO, 0x3d5, val | 0x1);
+ NVWriteCrtc(par, chan->ddc_base + 1, val | 0x01);
}
static int nvidia_gpio_getscl(void *data)
@@ -66,12 +62,9 @@ static int nvidia_gpio_getscl(void *data)
struct nvidia_par *par = chan->par;
u32 val = 0;
- VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
- if (VGA_RD08(par->PCIO, 0x3d5) & 0x04)
+ if (NVReadCrtc(par, chan->ddc_base) & 0x04)
val = 1;
- val = VGA_RD08(par->PCIO, 0x3d5);
-
return val;
}
@@ -81,20 +74,21 @@ static int nvidia_gpio_getsda(void *data)
struct nvidia_par *par = chan->par;
u32 val = 0;
- VGA_WR08(par->PCIO, 0x3d4, chan->ddc_base);
- if (VGA_RD08(par->PCIO, 0x3d5) & 0x08)
+ if (NVReadCrtc(par, chan->ddc_base) & 0x08)
val = 1;
return val;
}
-static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
+static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name,
+ unsigned int i2c_class)
{
int rc;
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
chan->adapter.id = I2C_HW_B_NVIDIA;
+ chan->adapter.class = i2c_class;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pci_dev->dev;
chan->algo.setsda = nvidia_gpio_setsda;
@@ -127,83 +121,39 @@ static int nvidia_setup_i2c_bus(struct nvidia_i2c_chan *chan, const char *name)
void nvidia_create_i2c_busses(struct nvidia_par *par)
{
- par->bus = 3;
-
par->chan[0].par = par;
par->chan[1].par = par;
par->chan[2].par = par;
- par->chan[0].ddc_base = 0x3e;
- nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0");
+ par->chan[0].ddc_base = 0x36;
+ nvidia_setup_i2c_bus(&par->chan[0], "nvidia #0", I2C_CLASS_HWMON);
- par->chan[1].ddc_base = 0x36;
- nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1");
+ par->chan[1].ddc_base = 0x3e;
+ nvidia_setup_i2c_bus(&par->chan[1], "nvidia #1", 0);
par->chan[2].ddc_base = 0x50;
- nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2");
+ nvidia_setup_i2c_bus(&par->chan[2], "nvidia #2", 0);
}
void nvidia_delete_i2c_busses(struct nvidia_par *par)
{
- if (par->chan[0].par)
- i2c_del_adapter(&par->chan[0].adapter);
- par->chan[0].par = NULL;
-
- if (par->chan[1].par)
- i2c_del_adapter(&par->chan[1].adapter);
- par->chan[1].par = NULL;
-
- if (par->chan[2].par)
- i2c_del_adapter(&par->chan[2].adapter);
- par->chan[2].par = NULL;
-
-}
+ int i;
-static u8 *nvidia_do_probe_i2c_edid(struct nvidia_i2c_chan *chan)
-{
- u8 start = 0x0;
- struct i2c_msg msgs[] = {
- {
- .addr = 0x50,
- .len = 1,
- .buf = &start,
- }, {
- .addr = 0x50,
- .flags = I2C_M_RD,
- .len = EDID_LENGTH,
- },
- };
- u8 *buf;
-
- if (!chan->par)
- return NULL;
-
- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (!buf) {
- dev_warn(&chan->par->pci_dev->dev, "Out of memory!\n");
- return NULL;
+ for (i = 0; i < 3; i++) {
+ if (!par->chan[i].par)
+ continue;
+ i2c_del_adapter(&par->chan[i].adapter);
+ par->chan[i].par = NULL;
}
- msgs[1].buf = buf;
-
- if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
- return buf;
- dev_dbg(&chan->par->pci_dev->dev, "Unable to read EDID block.\n");
- kfree(buf);
- return NULL;
}
int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid)
{
struct nvidia_par *par = info->par;
u8 *edid = NULL;
- int i;
- for (i = 0; i < 3; i++) {
- /* Do the real work */
- edid = nvidia_do_probe_i2c_edid(&par->chan[conn - 1]);
- if (edid)
- break;
- }
+ if (par->chan[conn - 1].par)
+ edid = fb_ddc_read(&par->chan[conn - 1].adapter);
if (!edid && conn == 1) {
/* try to get from firmware */
diff --git a/drivers/video/nvidia/nv_local.h b/drivers/video/nvidia/nv_local.h
index e009d242ea1..68e508daa41 100644
--- a/drivers/video/nvidia/nv_local.h
+++ b/drivers/video/nvidia/nv_local.h
@@ -73,9 +73,9 @@
#define NVDmaNext(par, data) \
NV_WR32(&(par)->dmaBase[(par)->dmaCurrent++], 0, (data))
-#define NVDmaStart(par, tag, size) { \
+#define NVDmaStart(info, par, tag, size) { \
if((par)->dmaFree <= (size)) \
- NVDmaWait(par, size); \
+ NVDmaWait(info, size); \
NVDmaNext(par, ((size) << 18) | (tag)); \
(par)->dmaFree -= ((size) + 1); \
}
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
index 163a774a1b3..73afd7eb997 100644
--- a/drivers/video/nvidia/nv_of.c
+++ b/drivers/video/nvidia/nv_of.c
@@ -46,15 +46,15 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
for (dp = NULL;
(dp = of_get_next_child(parent, dp)) != NULL;) {
- pname = get_property(dp, "name", NULL);
+ pname = of_get_property(dp, "name", NULL);
if (!pname)
continue;
len = strlen(pname);
if ((pname[len-1] == 'A' && conn == 1) ||
(pname[len-1] == 'B' && conn == 2)) {
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = get_property(dp, propnames[i],
- NULL);
+ pedid = of_get_property(dp,
+ propnames[i], NULL);
if (pedid != NULL)
break;
}
@@ -65,7 +65,7 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
}
if (pedid == NULL) {
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = get_property(parent, propnames[i], NULL);
+ pedid = of_get_property(parent, propnames[i], NULL);
if (pedid != NULL)
break;
}
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
index eab3e282a4d..707e2c8a13e 100644
--- a/drivers/video/nvidia/nv_setup.c
+++ b/drivers/video/nvidia/nv_setup.c
@@ -261,7 +261,7 @@ static void nv10GetConfig(struct nvidia_par *par)
}
#endif
- dev = pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
if ((par->Chipset & 0xffff) == 0x01a0) {
int amt = 0;
@@ -276,6 +276,7 @@ static void nv10GetConfig(struct nvidia_par *par)
par->RamAmountKBytes =
(NV_RD32(par->PFB, 0x020C) & 0xFFF00000) >> 10;
}
+ pci_dev_put(dev);
par->CrystalFreqKHz = (NV_RD32(par->PEXTDEV, 0x0000) & (1 << 6)) ?
14318 : 13500;
@@ -656,7 +657,7 @@ int NVCommonSetup(struct fb_info *info)
par->LVDS = 0;
if (par->FlatPanel && par->twoHeads) {
NV_WR32(par->PRAMDAC0, 0x08B0, 0x00010004);
- if (par->PRAMDAC0[0x08b4] & 1)
+ if (NV_RD32(par->PRAMDAC0, 0x08b4) & 1)
par->LVDS = 1;
printk("nvidiafb: Panel is %s\n", par->LVDS ? "LVDS" : "TMDS");
}
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
index 86e65dea60d..38f7cc0a233 100644
--- a/drivers/video/nvidia/nv_type.h
+++ b/drivers/video/nvidia/nv_type.h
@@ -4,8 +4,9 @@
#include <linux/fb.h>
#include <linux/types.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/mutex.h>
+#include <video/vga.h>
#define NV_ARCH_04 0x04
#define NV_ARCH_10 0x10
@@ -94,13 +95,15 @@ struct riva_regs {
struct nvidia_par {
RIVA_HW_STATE SavedReg;
RIVA_HW_STATE ModeReg;
+ RIVA_HW_STATE initial_state;
RIVA_HW_STATE *CurrentState;
+ struct vgastate vgastate;
+ struct mutex open_lock;
u32 pseudo_palette[16];
struct pci_dev *pci_dev;
u32 Architecture;
u32 CursorStart;
int Chipset;
- int bus;
unsigned long FbAddress;
u8 __iomem *FbStart;
u32 FbMapSize;
@@ -143,6 +146,7 @@ struct nvidia_par {
int BlendingPossible;
u32 paletteEnabled;
u32 forceCRTC;
+ u32 open_count;
u8 DDCBase;
#ifdef CONFIG_MTRR
struct {
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index b97ec690126..f85edf084da 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -200,7 +200,7 @@ static int nvidia_panel_tweak(struct nvidia_par *par,
return tweak;
}
-static void nvidia_vga_protect(struct nvidia_par *par, int on)
+static void nvidia_screen_off(struct nvidia_par *par, int on)
{
unsigned char tmp;
@@ -649,7 +649,7 @@ static int nvidiafb_set_par(struct fb_info *info)
NVLockUnlock(par, 0);
}
- nvidia_vga_protect(par, 1);
+ nvidia_screen_off(par, 1);
nvidia_write_regs(par, &par->ModeReg);
NVSetStartAddress(par, 0);
@@ -687,7 +687,7 @@ static int nvidiafb_set_par(struct fb_info *info)
par->cursor_reset = 1;
- nvidia_vga_protect(par, 0);
+ nvidia_screen_off(par, 0);
#ifdef CONFIG_BOOTX_TEXT
/* Update debug text engine */
@@ -696,6 +696,7 @@ static int nvidiafb_set_par(struct fb_info *info)
info->var.bits_per_pixel, info->fix.line_length);
#endif
+ NVLockUnlock(par, 0);
NVTRACE_LEAVE();
return 0;
}
@@ -948,8 +949,80 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
return 0;
}
+/*
+ * Because the VGA registers are not mapped linearly in its MMIO space,
+ * restrict VGA register saving and restore to x86 only, where legacy VGA IO
+ * access is legal. Consequently, we must also check if the device is the
+ * primary display.
+ */
+#ifdef CONFIG_X86
+static void save_vga_x86(struct nvidia_par *par)
+{
+ struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
+
+ if (res && res->flags & IORESOURCE_ROM_SHADOW) {
+ memset(&par->vgastate, 0, sizeof(par->vgastate));
+ par->vgastate.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS |
+ VGA_SAVE_CMAP;
+ save_vga(&par->vgastate);
+ }
+}
+
+static void restore_vga_x86(struct nvidia_par *par)
+{
+ struct resource *res= &par->pci_dev->resource[PCI_ROM_RESOURCE];
+
+ if (res && res->flags & IORESOURCE_ROM_SHADOW)
+ restore_vga(&par->vgastate);
+}
+#else
+#define save_vga_x86(x) do {} while (0)
+#define restore_vga_x86(x) do {} while (0)
+#endif /* X86 */
+
+static int nvidiafb_open(struct fb_info *info, int user)
+{
+ struct nvidia_par *par = info->par;
+
+ mutex_lock(&par->open_lock);
+
+ if (!par->open_count) {
+ save_vga_x86(par);
+ nvidia_save_vga(par, &par->initial_state);
+ }
+
+ par->open_count++;
+ mutex_unlock(&par->open_lock);
+ return 0;
+}
+
+static int nvidiafb_release(struct fb_info *info, int user)
+{
+ struct nvidia_par *par = info->par;
+ int err = 0;
+
+ mutex_lock(&par->open_lock);
+
+ if (!par->open_count) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ if (par->open_count == 1) {
+ nvidia_write_regs(par, &par->initial_state);
+ restore_vga_x86(par);
+ }
+
+ par->open_count--;
+done:
+ mutex_unlock(&par->open_lock);
+ return err;
+}
+
static struct fb_ops nvidia_fb_ops = {
.owner = THIS_MODULE,
+ .fb_open = nvidiafb_open,
+ .fb_release = nvidiafb_release,
.fb_check_var = nvidiafb_check_var,
.fb_set_par = nvidiafb_set_par,
.fb_setcolreg = nvidiafb_setcolreg,
@@ -1170,6 +1243,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
case 0x0140: /* GeForce 6600 */
case 0x0160: /* GeForce 6200 */
case 0x01D0: /* GeForce 7200, 7300, 7400 */
+ case 0x02E0: /* GeForce 7300 GT */
case 0x0090: /* GeForce 7800 */
case 0x0210: /* GeForce 6800 */
case 0x0220: /* GeForce 6200 */
@@ -1207,7 +1281,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
par = info->par;
par->pci_dev = pd;
-
+ mutex_init(&par->open_lock);
info->pixmap.addr = kzalloc(8 * 1024, GFP_KERNEL);
if (info->pixmap.addr == NULL)
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 9576a55eaf1..885b42836cb 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -322,8 +322,8 @@ static void __init offb_init_fb(const char *name, const char *full_name,
ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
par->cmap_data = par->cmap_adr + 1;
par->cmap_type = cmap_m64;
- } else if (dp && (device_is_compatible(dp, "pci1014,b7") ||
- device_is_compatible(dp, "pci1014,21c"))) {
+ } else if (dp && (of_device_is_compatible(dp, "pci1014,b7") ||
+ of_device_is_compatible(dp, "pci1014,21c"))) {
par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
if (par->cmap_adr)
par->cmap_type = cmap_gxt2000;
@@ -425,27 +425,27 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
const u32 *pp, *addrp, *up;
u64 asize;
- pp = get_property(dp, "linux,bootx-depth", &len);
+ pp = of_get_property(dp, "linux,bootx-depth", &len);
if (pp == NULL)
- pp = get_property(dp, "depth", &len);
+ pp = of_get_property(dp, "depth", &len);
if (pp && len == sizeof(u32))
depth = *pp;
- pp = get_property(dp, "linux,bootx-width", &len);
+ pp = of_get_property(dp, "linux,bootx-width", &len);
if (pp == NULL)
- pp = get_property(dp, "width", &len);
+ pp = of_get_property(dp, "width", &len);
if (pp && len == sizeof(u32))
width = *pp;
- pp = get_property(dp, "linux,bootx-height", &len);
+ pp = of_get_property(dp, "linux,bootx-height", &len);
if (pp == NULL)
- pp = get_property(dp, "height", &len);
+ pp = of_get_property(dp, "height", &len);
if (pp && len == sizeof(u32))
height = *pp;
- pp = get_property(dp, "linux,bootx-linebytes", &len);
+ pp = of_get_property(dp, "linux,bootx-linebytes", &len);
if (pp == NULL)
- pp = get_property(dp, "linebytes", &len);
+ pp = of_get_property(dp, "linebytes", &len);
if (pp && len == sizeof(u32) && (*pp != 0xffffffffu))
pitch = *pp;
else
@@ -463,9 +463,9 @@ static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
* ranges and pick one that is both big enough and if possible encloses
* the "address" property. If none match, we pick the biggest
*/
- up = get_property(dp, "linux,bootx-addr", &len);
+ up = of_get_property(dp, "linux,bootx-addr", &len);
if (up == NULL)
- up = get_property(dp, "address", &len);
+ up = of_get_property(dp, "address", &len);
if (up && len == sizeof(u32))
addr_prop = *up;
@@ -521,7 +521,7 @@ static int __init offb_init(void)
return -ENODEV;
/* Check if we have a MacOS display without a node spec */
- if (get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
+ if (of_get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
/* The old code tried to work out which node was the MacOS
* display based on the address. I'm dropping that since the
* lack of a node spec only happens with old BootX versions
@@ -532,14 +532,14 @@ static int __init offb_init(void)
}
for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
- if (get_property(dp, "linux,opened", NULL) &&
- get_property(dp, "linux,boot-display", NULL)) {
+ if (of_get_property(dp, "linux,opened", NULL) &&
+ of_get_property(dp, "linux,boot-display", NULL)) {
boot_disp = dp;
offb_init_nodriver(dp, 0);
}
}
for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
- if (get_property(dp, "linux,opened", NULL) &&
+ if (of_get_property(dp, "linux,opened", NULL) &&
dp != boot_disp)
offb_init_nodriver(dp, 0);
}
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 23387165582..e64f8b5d005 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -28,7 +28,6 @@
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/nvram.h>
#include <asm/io.h>
#include <asm/prom.h>
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index a560a222382..1ac5264bb2c 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -81,8 +81,6 @@ static int lowvsync;
struct pm2fb_par
{
pm2type_t type; /* Board type */
- u32 fb_size; /* framebuffer memory size */
- unsigned char __iomem *v_fb; /* virtual address of frame buffer */
unsigned char __iomem *v_regs;/* virtual address of p_regs */
u32 memclock; /* memclock */
u32 video; /* video flags before blanking */
@@ -103,7 +101,7 @@ static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
.xpanstep = 1,
.ypanstep = 1,
.ywrapstep = 0,
- .accel = FB_ACCEL_NONE,
+ .accel = FB_ACCEL_3DLABS_PERMEDIA2,
};
/*
@@ -206,6 +204,17 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
}
#endif
+static void wait_pm2(struct pm2fb_par* par) {
+
+ WAIT_FIFO(par, 1);
+ pm2_WR(par, PM2R_SYNC, 0);
+ mb();
+ do {
+ while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
+ rmb();
+ } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+}
+
/*
* partial products for the supported horizontal resolutions.
*/
@@ -302,10 +311,10 @@ static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
s32 delta = 1000;
*mm = *nn = *pp = 0;
- for (n = 1; n; n++) {
- for ( m = 1; m; m++) {
+ for ( m = 1; m < 128; m++) {
+ for (n = 2 * m + 1; n; n++) {
for ( p = 0; p < 2; p++) {
- f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1)));
+ f = ( PM2_REFERENCE_CLOCK >> ( p + 1 )) * n / m;
if ( clk > f - delta && clk < f + delta ) {
delta = ( clk > f ) ? clk - f : f - clk;
*mm=m;
@@ -462,21 +471,43 @@ static void set_memclock(struct pm2fb_par* par, u32 clk)
int i;
unsigned char m, n, p;
- pm2_mnp(clk, &m, &n, &p);
- WAIT_FIFO(par, 10);
- pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
- wmb();
- pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
- pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
- wmb();
- pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
- wmb();
- pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
- rmb();
- for (i = 256;
- i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
- i--)
- ;
+ switch (par->type) {
+ case PM2_TYPE_PERMEDIA2V:
+ pm2v_mnp(clk/2, &m, &n, &p);
+ WAIT_FIFO(par, 8);
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
+ pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
+ wmb();
+ pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
+ pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n);
+ pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
+ wmb();
+ pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
+ rmb();
+ for (i = 256;
+ i && !(pm2_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2);
+ i--)
+ ;
+ pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
+ break;
+ case PM2_TYPE_PERMEDIA2:
+ pm2_mnp(clk, &m, &n, &p);
+ WAIT_FIFO(par, 10);
+ pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
+ wmb();
+ pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
+ pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
+ wmb();
+ pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
+ wmb();
+ pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
+ rmb();
+ for (i = 256;
+ i && !(pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED);
+ i--)
+ ;
+ break;
+ }
}
static void set_pixclock(struct pm2fb_par* par, u32 clk)
@@ -623,6 +654,8 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
return -EINVAL;
}
+ var->transp.offset = 0;
+ var->transp.length = 0;
switch(var->bits_per_pixel) {
case 8:
var->red.length = var->green.length = var->blue.length = 8;
@@ -1017,6 +1050,117 @@ static int pm2fb_blank(int blank_mode, struct fb_info *info)
return 0;
}
+/*
+ * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
+ */
+static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+ s32 xsrc, s32 ysrc,
+ s32 x, s32 y, s32 w, s32 h,
+ u32 color) {
+
+ if (!w || !h)
+ return;
+ WAIT_FIFO(par, 6);
+ pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
+ PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
+ pm2_WR(par, PM2R_FB_PIXEL_OFFSET, 0);
+ if (copy)
+ pm2_WR(par, PM2R_FB_SOURCE_DELTA,
+ ((ysrc-y) & 0xfff) << 16 | ((xsrc-x) & 0xfff));
+ else
+ pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
+ pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x);
+ pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w);
+ wmb();
+ pm2_WR(par, PM2R_RENDER,PM2F_RENDER_RECTANGLE |
+ (x<xsrc ? PM2F_INCREASE_X : 0) |
+ (y<ysrc ? PM2F_INCREASE_Y : 0) |
+ (copy ? 0 : PM2F_RENDER_FASTFILL));
+ wait_pm2(par);
+}
+
+static void pm2fb_fillrect (struct fb_info *info,
+ const struct fb_fillrect *region)
+{
+ struct pm2fb_par *par = info->par;
+ struct fb_fillrect modded;
+ int vxres, vyres;
+ u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
+ ((u32*)info->pseudo_palette)[region->color] : region->color;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
+ region->rop != ROP_COPY ) {
+ cfb_fillrect(info, region);
+ return;
+ }
+
+ vxres = info->var.xres_virtual;
+ vyres = info->var.yres_virtual;
+
+ memcpy(&modded, region, sizeof(struct fb_fillrect));
+
+ if(!modded.width || !modded.height ||
+ modded.dx >= vxres || modded.dy >= vyres)
+ return;
+
+ if(modded.dx + modded.width > vxres)
+ modded.width = vxres - modded.dx;
+ if(modded.dy + modded.height > vyres)
+ modded.height = vyres - modded.dy;
+
+ if(info->var.bits_per_pixel == 8)
+ color |= color << 8;
+ if(info->var.bits_per_pixel <= 16)
+ color |= color << 16;
+
+ if(info->var.bits_per_pixel != 24)
+ pm2fb_block_op(par, 0, 0, 0,
+ modded.dx, modded.dy,
+ modded.width, modded.height, color);
+ else
+ cfb_fillrect(info, region);
+}
+
+static void pm2fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct pm2fb_par *par = info->par;
+ struct fb_copyarea modded;
+ u32 vxres, vyres;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if (info->flags & FBINFO_HWACCEL_DISABLED) {
+ cfb_copyarea(info, area);
+ return;
+ }
+
+ memcpy(&modded, area, sizeof(struct fb_copyarea));
+
+ vxres = info->var.xres_virtual;
+ vyres = info->var.yres_virtual;
+
+ if(!modded.width || !modded.height ||
+ modded.sx >= vxres || modded.sy >= vyres ||
+ modded.dx >= vxres || modded.dy >= vyres)
+ return;
+
+ if(modded.sx + modded.width > vxres)
+ modded.width = vxres - modded.sx;
+ if(modded.dx + modded.width > vxres)
+ modded.width = vxres - modded.dx;
+ if(modded.sy + modded.height > vyres)
+ modded.height = vyres - modded.sy;
+ if(modded.dy + modded.height > vyres)
+ modded.height = vyres - modded.dy;
+
+ pm2fb_block_op(par, 1, modded.sx, modded.sy,
+ modded.dx, modded.dy,
+ modded.width, modded.height, 0);
+}
+
/* ------------ Hardware Independent Functions ------------ */
/*
@@ -1030,8 +1174,8 @@ static struct fb_ops pm2fb_ops = {
.fb_setcolreg = pm2fb_setcolreg,
.fb_blank = pm2fb_blank,
.fb_pan_display = pm2fb_pan_display,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
+ .fb_fillrect = pm2fb_fillrect,
+ .fb_copyarea = pm2fb_copyarea,
.fb_imageblit = cfb_imageblit,
};
@@ -1119,38 +1263,47 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
if(default_par->mem_control == 0 &&
default_par->boot_address == 0x31 &&
- default_par->mem_config == 0x259fffff &&
- pdev->subsystem_vendor == 0x1048 &&
- pdev->subsystem_device == 0x0a31) {
- DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
- pdev->subsystem_vendor, pdev->subsystem_device);
- DPRINTK("We have not been initialized by VGA BIOS "
- "and are running on an Elsa Winner 2000 Office\n");
- DPRINTK("Initializing card timings manually...\n");
+ default_par->mem_config == 0x259fffff) {
+ default_par->memclock = CVPPC_MEMCLOCK;
default_par->mem_control=0;
default_par->boot_address=0x20;
default_par->mem_config=0xe6002021;
- default_par->memclock=100000;
+ if (pdev->subsystem_vendor == 0x1048 &&
+ pdev->subsystem_device == 0x0a31) {
+ DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
+ pdev->subsystem_vendor, pdev->subsystem_device);
+ DPRINTK("We have not been initialized by VGA BIOS "
+ "and are running on an Elsa Winner 2000 Office\n");
+ DPRINTK("Initializing card timings manually...\n");
+ default_par->memclock=70000;
+ }
+ if (pdev->subsystem_vendor == 0x3d3d &&
+ pdev->subsystem_device == 0x0100) {
+ DPRINTK("subsystem_vendor: %04x, subsystem_device: %04x\n",
+ pdev->subsystem_vendor, pdev->subsystem_device);
+ DPRINTK("We have not been initialized by VGA BIOS "
+ "and are running on an 3dlabs reference board\n");
+ DPRINTK("Initializing card timings manually...\n");
+ default_par->memclock=74894;
+ }
}
/* Now work out how big lfb is going to be. */
switch(default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
case PM2F_MEM_BANKS_1:
- default_par->fb_size=0x200000;
+ pm2fb_fix.smem_len=0x200000;
break;
case PM2F_MEM_BANKS_2:
- default_par->fb_size=0x400000;
+ pm2fb_fix.smem_len=0x400000;
break;
case PM2F_MEM_BANKS_3:
- default_par->fb_size=0x600000;
+ pm2fb_fix.smem_len=0x600000;
break;
case PM2F_MEM_BANKS_4:
- default_par->fb_size=0x800000;
+ pm2fb_fix.smem_len=0x800000;
break;
}
- default_par->memclock = CVPPC_MEMCLOCK;
pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
- pm2fb_fix.smem_len = default_par->fb_size;
/* Linear frame buffer - request region and map it. */
if ( !request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
@@ -1158,9 +1311,9 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
printk(KERN_WARNING "pm2fb: Can't reserve smem.\n");
goto err_exit_mmio;
}
- info->screen_base = default_par->v_fb =
+ info->screen_base =
ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
- if ( !default_par->v_fb ) {
+ if ( !info->screen_base ) {
printk(KERN_WARNING "pm2fb: Can't ioremap smem area.\n");
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
goto err_exit_mmio;
@@ -1170,7 +1323,9 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
info->fix = pm2fb_fix;
info->pseudo_palette = default_par->palette;
info->flags = FBINFO_DEFAULT |
- FBINFO_HWACCEL_YPAN;
+ FBINFO_HWACCEL_YPAN |
+ FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_FILLRECT;
if (!mode)
mode = "640x480@60";
@@ -1180,13 +1335,13 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
info->var = pm2fb_var;
if (fb_alloc_cmap(&info->cmap, 256, 0) < 0)
- goto err_exit_all;
+ goto err_exit_both;
if (register_framebuffer(info) < 0)
- goto err_exit_both;
+ goto err_exit_all;
printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.\n",
- info->node, info->fix.id, default_par->fb_size / 1024);
+ info->node, info->fix.id, pm2fb_fix.smem_len / 1024);
/*
* Our driver data
@@ -1242,6 +1397,9 @@ static struct pci_device_id pm2fb_id_table[] = {
{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
0xff0000, 0 },
+ { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NOT_DEFINED_VGA << 8,
+ 0xff00, 0 },
{ 0, }
};
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 81e43cda7d8..9756a728b74 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -32,6 +32,8 @@
#include <linux/ioctl.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <asm/uaccess.h>
#include <linux/fb.h>
@@ -45,7 +47,7 @@
#include <asm/ps3.h>
#ifdef PS3FB_DEBUG
-#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
#else
#define DPRINTK(fmt, args...)
#endif
@@ -129,7 +131,6 @@ struct ps3fb_priv {
u64 context_handle, memory_handle;
void *xdr_ea;
struct gpu_driver_info *dinfo;
- struct semaphore sem;
u32 res_index;
u64 vblank_count; /* frame count */
@@ -139,6 +140,8 @@ struct ps3fb_priv {
atomic_t ext_flip; /* on/off flip with vsync */
atomic_t f_count; /* fb_open count */
int is_blanked;
+ int is_kicked;
+ struct task_struct *task;
};
static struct ps3fb_priv ps3fb;
@@ -294,10 +297,10 @@ static const struct fb_videomode ps3fb_modedb[] = {
#define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
-static int ps3fb_mode = 0;
+static int ps3fb_mode;
module_param(ps3fb_mode, bool, 0);
-static char *mode_option __initdata = NULL;
+static char *mode_option __initdata;
static int ps3fb_get_res_table(u32 xres, u32 yres)
@@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame)
if (frame > ps3fb.num_frames - 1) {
printk(KERN_WARNING "%s: invalid frame number (%u)\n",
- __FUNCTION__, frame);
+ __func__, frame);
return -EINVAL;
}
offset = xres * yres * BPP * frame;
@@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame)
(xres << 16) | yres,
xres * BPP); /* line_length */
if (status)
- printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
- __FUNCTION__, status);
+ printk(KERN_ERR
+ "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+ __func__, status);
#ifdef HEAD_A
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
0, offset, 0, 0);
if (status)
- printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
- __FUNCTION__, status);
+ printk(KERN_ERR
+ "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+ __func__, status);
#endif
#ifdef HEAD_B
status = lv1_gpu_context_attribute(ps3fb.context_handle,
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
1, offset, 0, 0);
if (status)
- printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
- __FUNCTION__, status);
+ printk(KERN_ERR
+ "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+ __func__, status);
#endif
return 0;
}
@@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct fb_info *info)
{
int retval;
- DPRINTK("%s: blank:%d\n", __FUNCTION__, blank);
+ DPRINTK("%s: blank:%d\n", __func__, blank);
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_HSYNC_SUSPEND:
@@ -677,13 +683,10 @@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
void ps3fb_flip_ctl(int on)
{
- if (on) {
- if (atomic_read(&ps3fb.ext_flip) > 0) {
- atomic_dec(&ps3fb.ext_flip);
- }
- } else {
+ if (on)
+ atomic_dec_if_positive(&ps3fb.ext_flip);
+ else
atomic_inc(&ps3fb.ext_flip);
- }
}
EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
@@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
if (copy_from_user(&val, argp, sizeof(val)))
break;
+ if (!(val & PS3AV_MODE_MASK)) {
+ u32 id = ps3av_get_auto_mode(0);
+ if (id > 0)
+ val = (val & ~PS3AV_MODE_MASK) | id;
+ }
DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
retval = -EINVAL;
old_mode = ps3fb_mode;
@@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
case PS3FB_IOCTL_OFF:
DPRINTK("PS3FB_IOCTL_OFF:\n");
- if (atomic_read(&ps3fb.ext_flip) > 0)
- atomic_dec(&ps3fb.ext_flip);
+ atomic_dec_if_positive(&ps3fb.ext_flip);
retval = 0;
break;
@@ -805,11 +812,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
static int ps3fbd(void *arg)
{
- daemonize("ps3fbd");
- for (;;) {
- down(&ps3fb.sem);
- if (atomic_read(&ps3fb.ext_flip) == 0)
+ while (!kthread_should_stop()) {
+ try_to_freeze();
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (ps3fb.is_kicked) {
+ ps3fb.is_kicked = 0;
ps3fb_sync(0); /* single buffer */
+ }
+ schedule();
}
return 0;
}
@@ -823,15 +833,18 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
if (status) {
printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
- __FUNCTION__, status);
+ __func__, status);
return IRQ_NONE;
}
if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
/* VSYNC */
ps3fb.vblank_count = head->vblank_count;
- if (!ps3fb.is_blanked)
- up(&ps3fb.sem);
+ if (ps3fb.task && !ps3fb.is_blanked &&
+ !atomic_read(&ps3fb.ext_flip)) {
+ ps3fb.is_kicked = 1;
+ wake_up_process(ps3fb.task);
+ }
wake_up_interruptible(&ps3fb.wait_vsync);
}
@@ -879,16 +892,16 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
- printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__,
+ printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
dinfo->version_driver);
return -EINVAL;
}
ps3fb.dev = dev;
- error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
- &ps3fb.irq_no);
+ error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+ &ps3fb.irq_no);
if (error) {
- printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__,
+ printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
error);
return error;
}
@@ -896,9 +909,9 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
"ps3fb vsync", ps3fb.dev);
if (error) {
- printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__,
+ printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
error);
- ps3_free_irq(ps3fb.irq_no);
+ ps3_irq_plug_destroy(ps3fb.irq_no);
return error;
}
@@ -915,7 +928,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
xdr_lpar, ps3fb_videomemory.size, 0);
if (status) {
printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
- __FUNCTION__, status);
+ __func__, status);
return -ENXIO;
}
DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
@@ -927,8 +940,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
xdr_lpar, ps3fb_videomemory.size,
GPU_IOIF, 0);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
- __FUNCTION__, status);
+ printk(KERN_ERR
+ "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+ __func__, status);
return -ENXIO;
}
return 0;
@@ -968,13 +982,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
u64 xdr_lpar;
int status;
unsigned long offset;
+ struct task_struct *task;
/* get gpu context handle */
status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
&ps3fb.memory_handle, &ddr_lpar);
if (status) {
printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
- __FUNCTION__, status);
+ __func__, status);
goto err;
}
DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
@@ -985,14 +1000,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
&lpar_reports, &lpar_reports_size);
if (status) {
printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
- __FUNCTION__, status);
+ __func__, status);
goto err_gpu_memory_free;
}
/* vsync interrupt */
ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
if (!ps3fb.dinfo) {
- printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__);
+ printk(KERN_ERR "%s: ioremap failed\n", __func__);
goto err_gpu_context_free;
}
@@ -1050,16 +1065,25 @@ static int __init ps3fb_probe(struct platform_device *dev)
"fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
info->node, ps3fb_videomemory.size >> 10);
- kernel_thread(ps3fbd, info, CLONE_KERNEL);
+ task = kthread_run(ps3fbd, info, "ps3fbd");
+ if (IS_ERR(task)) {
+ retval = PTR_ERR(task);
+ goto err_unregister_framebuffer;
+ }
+
+ ps3fb.task = task;
+
return 0;
+err_unregister_framebuffer:
+ unregister_framebuffer(info);
err_fb_dealloc:
fb_dealloc_cmap(&info->cmap);
err_framebuffer_release:
framebuffer_release(info);
err_free_irq:
free_irq(ps3fb.irq_no, ps3fb.dev);
- ps3_free_irq(ps3fb.irq_no);
+ ps3_irq_plug_destroy(ps3fb.irq_no);
err_iounmap_dinfo:
iounmap((u8 __iomem *)ps3fb.dinfo);
err_gpu_context_free:
@@ -1075,7 +1099,7 @@ static void ps3fb_shutdown(struct platform_device *dev)
ps3fb_flip_ctl(0); /* flip off */
ps3fb.dinfo->irq.mask = 0;
free_irq(ps3fb.irq_no, ps3fb.dev);
- ps3_free_irq(ps3fb.irq_no);
+ ps3_irq_plug_destroy(ps3fb.irq_no);
iounmap((u8 __iomem *)ps3fb.dinfo);
}
@@ -1083,9 +1107,14 @@ void ps3fb_cleanup(void)
{
int status;
+ if (ps3fb.task) {
+ struct task_struct *task = ps3fb.task;
+ ps3fb.task = NULL;
+ kthread_stop(task);
+ }
if (ps3fb.irq_no) {
free_irq(ps3fb.irq_no, ps3fb.dev);
- ps3_free_irq(ps3fb.irq_no);
+ ps3_irq_plug_destroy(ps3fb.irq_no);
}
iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1137,8 +1166,9 @@ int ps3fb_set_sync(void)
L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
- __FUNCTION__, status);
+ printk(KERN_ERR
+ "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
+ __func__, status);
return -1;
}
#endif
@@ -1148,8 +1178,9 @@ int ps3fb_set_sync(void)
1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
if (status) {
- printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
- __FUNCTION__, status);
+ printk(KERN_ERR
+ "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
+ __func__, status);
return -1;
}
#endif
@@ -1174,7 +1205,7 @@ static int __init ps3fb_init(void)
error = ps3av_dev_open();
if (error) {
- printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__);
+ printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
goto err;
}
@@ -1195,7 +1226,6 @@ static int __init ps3fb_init(void)
atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
- init_MUTEX(&ps3fb.sem);
init_waitqueue_head(&ps3fb.wait_vsync);
ps3fb.num_frames = 1;
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index a93618bc9d2..df2909ae704 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -214,7 +214,7 @@ static int pvr2_init_cable(void);
static int pvr2_get_param(const struct pvr2_params *p, const char *s,
int val, int size);
#ifdef CONFIG_SH_DMA
-static ssize_t pvr2fb_write(struct file *file, const char *buf,
+static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
size_t count, loff_t *ppos);
#endif
@@ -674,7 +674,7 @@ static int pvr2_init_cable(void)
}
#ifdef CONFIG_SH_DMA
-static ssize_t pvr2fb_write(struct file *file, const char *buf,
+static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
size_t count, loff_t *ppos)
{
unsigned long dst, start, end, len;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index b4947c81070..81e571d59b5 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -803,7 +803,7 @@ static void pxafb_enable_controller(struct pxafb_info *fbi)
pr_debug("reg_lccr3 0x%08x\n", (unsigned int) fbi->reg_lccr3);
/* enable LCD controller clock */
- pxa_set_cken(CKEN16_LCD, 1);
+ pxa_set_cken(CKEN_LCD, 1);
/* Sequence from 11.7.10 */
LCCR3 = fbi->reg_lccr3;
@@ -840,7 +840,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
remove_wait_queue(&fbi->ctrlr_wait, &wait);
/* disable LCD controller clock */
- pxa_set_cken(CKEN16_LCD, 0);
+ pxa_set_cken(CKEN_LCD, 0);
}
/*
@@ -1203,7 +1203,7 @@ static int __init pxafb_parse_options(struct device *dev, char *options)
} else
goto done;
break;
- case '0'...'9':
+ case '0' ... '9':
break;
default:
goto done;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index d7ece8d17a2..0fe547842c6 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -317,15 +317,15 @@ static int riva_bl_update_status(struct backlight_device *bd)
else
level = bd->props.brightness;
- tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
- tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+ tmp_pmc = NV_RD32(par->riva.PMC, 0x10F0) & 0x0000FFFF;
+ tmp_pcrt = NV_RD32(par->riva.PCRTC0, 0x081C) & 0xFFFFFFFC;
if(level > 0) {
tmp_pcrt |= 0x1;
tmp_pmc |= (1 << 31); /* backlight bit */
tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
}
- par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
- par->riva.PMC[0x10F0/4] = tmp_pmc;
+ NV_WR32(par->riva.PCRTC0, 0x081C, tmp_pcrt);
+ NV_WR32(par->riva.PMC, 0x10F0, tmp_pmc);
return 0;
}
@@ -1760,13 +1760,13 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
NVTRACE_ENTER();
dp = pci_device_to_OF_node(pd);
for (; dp != NULL; dp = dp->child) {
- disptype = get_property(dp, "display-type", NULL);
+ disptype = of_get_property(dp, "display-type", NULL);
if (disptype == NULL)
continue;
if (strncmp(disptype, "LCD", 3) != 0)
continue;
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = get_property(dp, propnames[i], NULL);
+ pedid = of_get_property(dp, propnames[i], NULL);
if (pedid != NULL) {
par->EDID = (unsigned char *)pedid;
NVTRACE("LCD found.\n");
@@ -1788,8 +1788,10 @@ static int __devinit riva_get_EDID_i2c(struct fb_info *info)
NVTRACE_ENTER();
riva_create_i2c_busses(par);
- for (i = 0; i < par->bus; i++) {
- riva_probe_i2c_connector(par, i+1, &par->EDID);
+ for (i = 0; i < 3; i++) {
+ if (!par->chan[i].par)
+ continue;
+ riva_probe_i2c_connector(par, i, &par->EDID);
if (par->EDID && !fb_parse_edid(par->EDID, &var)) {
printk(PFX "Found EDID Block from BUS %i\n", i);
break;
@@ -2104,7 +2106,7 @@ err_ret:
return ret;
}
-static void __exit rivafb_remove(struct pci_dev *pd)
+static void __devexit rivafb_remove(struct pci_dev *pd)
{
struct fb_info *info = pci_get_drvdata(pd);
struct riva_par *par = info->par;
@@ -2185,7 +2187,7 @@ static struct pci_driver rivafb_driver = {
.name = "rivafb",
.id_table = rivafb_pci_tbl,
.probe = rivafb_probe,
- .remove = __exit_p(rivafb_remove),
+ .remove = __devexit_p(rivafb_remove),
};
diff --git a/drivers/video/riva/nv4ref.h b/drivers/video/riva/nv4ref.h
deleted file mode 100644
index 3b5f9117c37..00000000000
--- a/drivers/video/riva/nv4ref.h
+++ /dev/null
@@ -1,2445 +0,0 @@
- /***************************************************************************\
-|* *|
-|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
-|* *|
-|* NOTICE TO USER: The source code is copyrighted under U.S. and *|
-|* international laws. Users and possessors of this source code are *|
-|* hereby granted a nonexclusive, royalty-free copyright license to *|
-|* use this code in individual and commercial software. *|
-|* *|
-|* Any use of this source code must include, in the user documenta- *|
-|* tion and internal comments to the code, notices to the end user *|
-|* as follows: *|
-|* *|
-|* Copyright 1993-1998 NVIDIA, Corporation. All rights reserved. *|
-|* *|
-|* NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY *|
-|* OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" *|
-|* WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPOR- *|
-|* ATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, *|
-|* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGE- *|
-|* MENT, AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL *|
-|* NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCI- *|
-|* DENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RE- *|
-|* SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION *|
-|* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *|
-|* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOURCE CODE. *|
-|* *|
-|* U.S. Government End Users. This source code is a "commercial *|
-|* item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995), *|
-|* consisting of "commercial computer software" and "commercial *|
-|* computer software documentation," as such terms are used in *|
-|* 48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Govern- *|
-|* ment only as a commercial end item. Consistent with 48 C.F.R. *|
-|* 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), *|
-|* all U.S. Government End Users acquire the source code with only *|
-|* those rights set forth herein. *|
-|* *|
- \***************************************************************************/
-
-/*
- * GPL licensing note -- nVidia is allowing a liberal interpretation of
- * the documentation restriction above, to merely say that this nVidia's
- * copyright and disclaimer should be included with all code derived
- * from this source. -- Jeff Garzik <jgarzik@pobox.com>, 01/Nov/99
- */
-
- /***************************************************************************\
-|* Modified 1999 by Fredrik Reite (fredrik@reite.com) *|
- \***************************************************************************/
-
-
-#ifndef __NV4REF_H__
-#define __NV4REF_H__
-
-/* Magic values to lock/unlock extended regs */
-#define NV_CIO_SR_LOCK_INDEX 0x0000001F /* */
-#define NV_CIO_SR_UNLOCK_RW_VALUE 0x00000057 /* */
-#define NV_CIO_SR_UNLOCK_RO_VALUE 0x00000075 /* */
-#define NV_CIO_SR_LOCK_VALUE 0x00000099 /* */
-
-#define UNLOCK_EXT_MAGIC 0x57
-#define LOCK_EXT_MAGIC 0x99 /* Any value other than 0x57 will do */
-
-#define LOCK_EXT_INDEX 0x6
-
-#define NV_PCRTC_HORIZ_TOTAL 0x00
-#define NV_PCRTC_HORIZ_DISPLAY_END 0x01
-#define NV_PCRTC_HORIZ_BLANK_START 0x02
-
-#define NV_PCRTC_HORIZ_BLANK_END 0x03
-#define NV_PCRTC_HORIZ_BLANK_END_EVRA 7:7
-#define NV_PCRTC_HORIZ_BLANK_END_DISPLAY_END_SKEW 6:5
-#define NV_PCRTC_HORIZ_BLANK_END_HORIZ_BLANK_END 4:0
-
-#define NV_PCRTC_HORIZ_RETRACE_START 0x04
-
-#define NV_PCRTC_HORIZ_RETRACE_END 0x05
-#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_BLANK_END_5 7:7
-#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_SKEW 6:5
-#define NV_PCRTC_HORIZ_RETRACE_END_HORIZ_RETRACE_END 4:0
-
-#define NV_PCRTC_VERT_TOTAL 0x06
-
-#define NV_PCRTC_OVERFLOW 0x07
-#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_9 7:7
-#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_9 6:6
-#define NV_PCRTC_OVERFLOW_VERT_TOTAL_9 5:5
-#define NV_PCRTC_OVERFLOW_LINE_COMPARE_8 4:4
-#define NV_PCRTC_OVERFLOW_VERT_BLANK_START_8 3:3
-#define NV_PCRTC_OVERFLOW_VERT_RETRACE_START_8 2:2
-#define NV_PCRTC_OVERFLOW_VERT_DISPLAY_END_8 1:1
-#define NV_PCRTC_OVERFLOW_VERT_TOTAL_8 0:0
-
-#define NV_PCRTC_PRESET_ROW_SCAN 0x08
-
-#define NV_PCRTC_MAX_SCAN_LINE 0x09
-#define NV_PCRTC_MAX_SCAN_LINE_DOUBLE_SCAN 7:7
-#define NV_PCRTC_MAX_SCAN_LINE_LINE_COMPARE_9 6:6
-#define NV_PCRTC_MAX_SCAN_LINE_VERT_BLANK_START_9 5:5
-#define NV_PCRTC_MAX_SCAN_LINE_MAX_SCAN_LINE 4:0
-
-#define NV_PCRTC_CURSOR_START 0x0A
-#define NV_PCRTC_CURSOR_END 0x0B
-#define NV_PCRTC_START_ADDR_HIGH 0x0C
-#define NV_PCRTC_START_ADDR_LOW 0x0D
-#define NV_PCRTC_CURSOR_LOCATION_HIGH 0x0E
-#define NV_PCRTC_CURSOR_LOCATION_LOW 0x0F
-
-#define NV_PCRTC_VERT_RETRACE_START 0x10
-#define NV_PCRTC_VERT_RETRACE_END 0x11
-#define NV_PCRTC_VERT_DISPLAY_END 0x12
-#define NV_PCRTC_OFFSET 0x13
-#define NV_PCRTC_UNDERLINE_LOCATION 0x14
-#define NV_PCRTC_VERT_BLANK_START 0x15
-#define NV_PCRTC_VERT_BLANK_END 0x16
-#define NV_PCRTC_MODE_CONTROL 0x17
-#define NV_PCRTC_LINE_COMPARE 0x18
-
-/* Extended offset and start address */
-#define NV_PCRTC_REPAINT0 0x19
-#define NV_PCRTC_REPAINT0_OFFSET_10_8 7:5
-#define NV_PCRTC_REPAINT0_START_ADDR_20_16 4:0
-
-/* Horizonal extended bits */
-#define NV_PCRTC_HORIZ_EXTRA 0x2d
-#define NV_PCRTC_HORIZ_EXTRA_INTER_HALF_START_8 4:4
-#define NV_PCRTC_HORIZ_EXTRA_HORIZ_RETRACE_START_8 3:3
-#define NV_PCRTC_HORIZ_EXTRA_HORIZ_BLANK_START_8 2:2
-#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_END_8 1:1
-#define NV_PCRTC_HORIZ_EXTRA_DISPLAY_TOTAL_8 0:0
-
-/* Assorted extra bits */
-#define NV_PCRTC_EXTRA 0x25
-#define NV_PCRTC_EXTRA_OFFSET_11 5:5
-#define NV_PCRTC_EXTRA_HORIZ_BLANK_END_6 4:4
-#define NV_PCRTC_EXTRA_VERT_BLANK_START_10 3:3
-#define NV_PCRTC_EXTRA_VERT_RETRACE_START_10 2:2
-#define NV_PCRTC_EXTRA_VERT_DISPLAY_END_10 1:1
-#define NV_PCRTC_EXTRA_VERT_TOTAL_10 0:0
-
-/* Controls how much data the refresh fifo requests */
-#define NV_PCRTC_FIFO_CONTROL 0x1b
-#define NV_PCRTC_FIFO_CONTROL_UNDERFLOW_WARN 7:7
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH 2:0
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_8 0x0
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_32 0x1
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_64 0x2
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_128 0x3
-#define NV_PCRTC_FIFO_CONTROL_BURST_LENGTH_256 0x4
-
-/* When the fifo occupancy falls below *twice* the watermark,
- * the refresh fifo will start to be refilled. If this value is
- * too low, you will get junk on the screen. Too high, and performance
- * will suffer. Watermark in units of 8 bytes
- */
-#define NV_PCRTC_FIFO 0x20
-#define NV_PCRTC_FIFO_RESET 7:7
-#define NV_PCRTC_FIFO_WATERMARK 5:0
-
-/* Various flags */
-#define NV_PCRTC_REPAINT1 0x1a
-#define NV_PCRTC_REPAINT1_HSYNC 7:7
-#define NV_PCRTC_REPAINT1_HYSNC_DISABLE 0x01
-#define NV_PCRTC_REPAINT1_HYSNC_ENABLE 0x00
-#define NV_PCRTC_REPAINT1_VSYNC 6:6
-#define NV_PCRTC_REPAINT1_VYSNC_DISABLE 0x01
-#define NV_PCRTC_REPAINT1_VYSNC_ENABLE 0x00
-#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT 4:4
-#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_ENABLE 0x01
-#define NV_PCRTC_REPAINT1_COMPATIBLE_TEXT_DISABLE 0x00
-#define NV_PCRTC_REPAINT1_LARGE_SCREEN 2:2
-#define NV_PCRTC_REPAINT1_LARGE_SCREEN_DISABLE 0x01
-#define NV_PCRTC_REPAINT1_LARGE_SCREEN_ENABLE 0x00 /* >=1280 */
-#define NV_PCRTC_REPAINT1_PALETTE_WIDTH 1:1
-#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_8BITS 0x00
-#define NV_PCRTC_REPAINT1_PALETTE_WIDTH_6BITS 0x01
-
-#define NV_PCRTC_GRCURSOR0 0x30
-#define NV_PCRTC_GRCURSOR0_START_ADDR_21_16 5:0
-
-#define NV_PCRTC_GRCURSOR1 0x31
-#define NV_PCRTC_GRCURSOR1_START_ADDR_15_11 7:3
-#define NV_PCRTC_GRCURSOR1_SCAN_DBL 1:1
-#define NV_PCRTC_GRCURSOR1_SCAN_DBL_DISABLE 0
-#define NV_PCRTC_GRCURSOR1_SCAN_DBL_ENABLE 1
-#define NV_PCRTC_GRCURSOR1_CURSOR 0:0
-#define NV_PCRTC_GRCURSOR1_CURSOR_DISABLE 0
-#define NV_PCRTC_GRCURSOR1_CURSOR_ENABLE 1
-
-/* Controls what the format of the framebuffer is */
-#define NV_PCRTC_PIXEL 0x28
-#define NV_PCRTC_PIXEL_MODE 7:7
-#define NV_PCRTC_PIXEL_MODE_TV 0x01
-#define NV_PCRTC_PIXEL_MODE_VGA 0x00
-#define NV_PCRTC_PIXEL_TV_MODE 6:6
-#define NV_PCRTC_PIXEL_TV_MODE_NTSC 0x00
-#define NV_PCRTC_PIXEL_TV_MODE_PAL 0x01
-#define NV_PCRTC_PIXEL_TV_HORIZ_ADJUST 5:3
-#define NV_PCRTC_PIXEL_FORMAT 1:0
-#define NV_PCRTC_PIXEL_FORMAT_VGA 0x00
-#define NV_PCRTC_PIXEL_FORMAT_8BPP 0x01
-#define NV_PCRTC_PIXEL_FORMAT_16BPP 0x02
-#define NV_PCRTC_PIXEL_FORMAT_32BPP 0x03
-
-/* RAMDAC registers and fields */
-#define NV_PRAMDAC 0x00680FFF:0x00680000 /* RW--D */
-#define NV_PRAMDAC_GRCURSOR_START_POS 0x00680300 /* RW-4R */
-#define NV_PRAMDAC_GRCURSOR_START_POS_X 11:0 /* RWXSF */
-#define NV_PRAMDAC_GRCURSOR_START_POS_Y 27:16 /* RWXSF */
-#define NV_PRAMDAC_NVPLL_COEFF 0x00680500 /* RW-4R */
-#define NV_PRAMDAC_NVPLL_COEFF_MDIV 7:0 /* RWIUF */
-#define NV_PRAMDAC_NVPLL_COEFF_NDIV 15:8 /* RWIUF */
-#define NV_PRAMDAC_NVPLL_COEFF_PDIV 18:16 /* RWIVF */
-#define NV_PRAMDAC_MPLL_COEFF 0x00680504 /* RW-4R */
-#define NV_PRAMDAC_MPLL_COEFF_MDIV 7:0 /* RWIUF */
-#define NV_PRAMDAC_MPLL_COEFF_NDIV 15:8 /* RWIUF */
-#define NV_PRAMDAC_MPLL_COEFF_PDIV 18:16 /* RWIVF */
-#define NV_PRAMDAC_VPLL_COEFF 0x00680508 /* RW-4R */
-#define NV_PRAMDAC_VPLL_COEFF_MDIV 7:0 /* RWIUF */
-#define NV_PRAMDAC_VPLL_COEFF_NDIV 15:8 /* RWIUF */
-#define NV_PRAMDAC_VPLL_COEFF_PDIV 18:16 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT 0x0068050C /* RW-4R */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS 4:4 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_FALSE 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_DLL_BYPASS_TRUE 0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE 8:8 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_SOURCE_PROG 0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS 12:12 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_FALSE 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_MPLL_BYPASS_TRUE 0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE 16:16 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_SOURCE_PROG 0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS 20:20 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_FALSE 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VPLL_BYPASS_TRUE 0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE 25:24 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VPLL 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_VIP 0x00000001 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_PCLK_SOURCE_XTALOSC 0x00000002 /* RW--V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO 28:28 /* RWIVF */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB1 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_PLL_COEFF_SELECT_VCLK_RATIO_DB2 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL 0x00680600 /* RW-4R */
-#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF 1:0 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_FF_COEFF_DEF 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE 4:4 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_GAMMA 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_IDC_MODE_INDEX 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE 8:8 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_NOTSE 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE 12:12 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_NOTSEL 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_565_MODE_SEL 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL 16:16 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_OFF 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BLK_PEDSTL_ON 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION 17:17 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_37OHM 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_TERMINATION_75OHM 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BPC 20:20 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_BPC_6BITS 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP 24:24 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_DIS 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_DAC_SLEEP_EN 0x00000001 /* RW--V */
-#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK 28:28 /* RWIVF */
-#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_EN 0x00000000 /* RWI-V */
-#define NV_PRAMDAC_GENERAL_CONTROL_PALETTE_CLK_DIS 0x00000001 /* RW--V */
-
-/* Master Control */
-#define NV_PMC 0x00000FFF:0x00000000 /* RW--D */
-#define NV_PMC_BOOT_0 0x00000000 /* R--4R */
-#define NV_PMC_BOOT_0_MINOR_REVISION 3:0 /* C--VF */
-#define NV_PMC_BOOT_0_MINOR_REVISION_0 0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MAJOR_REVISION 7:4 /* C--VF */
-#define NV_PMC_BOOT_0_MAJOR_REVISION_A 0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MAJOR_REVISION_B 0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_IMPLEMENTATION 11:8 /* C--VF */
-#define NV_PMC_BOOT_0_IMPLEMENTATION_NV4_0 0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_ARCHITECTURE 15:12 /* C--VF */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV0 0x00000000 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV1 0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV2 0x00000002 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV3 0x00000003 /* ----V */
-#define NV_PMC_BOOT_0_ARCHITECTURE_NV4 0x00000004 /* C---V */
-#define NV_PMC_BOOT_0_FIB_REVISION 19:16 /* C--VF */
-#define NV_PMC_BOOT_0_FIB_REVISION_0 0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MASK_REVISION 23:20 /* C--VF */
-#define NV_PMC_BOOT_0_MASK_REVISION_A 0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_MASK_REVISION_B 0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_MANUFACTURER 27:24 /* C--UF */
-#define NV_PMC_BOOT_0_MANUFACTURER_NVIDIA 0x00000000 /* C---V */
-#define NV_PMC_BOOT_0_FOUNDRY 31:28 /* C--VF */
-#define NV_PMC_BOOT_0_FOUNDRY_SGS 0x00000000 /* ----V */
-#define NV_PMC_BOOT_0_FOUNDRY_HELIOS 0x00000001 /* ----V */
-#define NV_PMC_BOOT_0_FOUNDRY_TSMC 0x00000002 /* C---V */
-#define NV_PMC_INTR_0 0x00000100 /* RW-4R */
-#define NV_PMC_INTR_0_PMEDIA 4:4 /* R--VF */
-#define NV_PMC_INTR_0_PMEDIA_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PMEDIA_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PFIFO 8:8 /* R--VF */
-#define NV_PMC_INTR_0_PFIFO_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PFIFO_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PGRAPH 12:12 /* R--VF */
-#define NV_PMC_INTR_0_PGRAPH_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PGRAPH_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PVIDEO 16:16 /* R--VF */
-#define NV_PMC_INTR_0_PVIDEO_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PVIDEO_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PTIMER 20:20 /* R--VF */
-#define NV_PMC_INTR_0_PTIMER_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PTIMER_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PCRTC 24:24 /* R--VF */
-#define NV_PMC_INTR_0_PCRTC_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PCRTC_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_PBUS 28:28 /* R--VF */
-#define NV_PMC_INTR_0_PBUS_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PMC_INTR_0_PBUS_PENDING 0x00000001 /* R---V */
-#define NV_PMC_INTR_0_SOFTWARE 31:31 /* RWIVF */
-#define NV_PMC_INTR_0_SOFTWARE_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PMC_INTR_0_SOFTWARE_PENDING 0x00000001 /* RW--V */
-#define NV_PMC_INTR_EN_0 0x00000140 /* RW-4R */
-#define NV_PMC_INTR_EN_0_INTA 1:0 /* RWIVF */
-#define NV_PMC_INTR_EN_0_INTA_DISABLED 0x00000000 /* RWI-V */
-#define NV_PMC_INTR_EN_0_INTA_HARDWARE 0x00000001 /* RW--V */
-#define NV_PMC_INTR_EN_0_INTA_SOFTWARE 0x00000002 /* RW--V */
-#define NV_PMC_INTR_READ_0 0x00000160 /* R--4R */
-#define NV_PMC_INTR_READ_0_INTA 0:0 /* R--VF */
-#define NV_PMC_INTR_READ_0_INTA_LOW 0x00000000 /* R---V */
-#define NV_PMC_INTR_READ_0_INTA_HIGH 0x00000001 /* R---V */
-#define NV_PMC_ENABLE 0x00000200 /* RW-4R */
-#define NV_PMC_ENABLE_PMEDIA 4:4 /* RWIVF */
-#define NV_PMC_ENABLE_PMEDIA_DISABLED 0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PMEDIA_ENABLED 0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PFIFO 8:8 /* RWIVF */
-#define NV_PMC_ENABLE_PFIFO_DISABLED 0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PFIFO_ENABLED 0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PGRAPH 12:12 /* RWIVF */
-#define NV_PMC_ENABLE_PGRAPH_DISABLED 0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PGRAPH_ENABLED 0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PPMI 16:16 /* RWIVF */
-#define NV_PMC_ENABLE_PPMI_DISABLED 0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PPMI_ENABLED 0x00000001 /* RW--V */
-#define NV_PMC_ENABLE_PFB 20:20 /* RWIVF */
-#define NV_PMC_ENABLE_PFB_DISABLED 0x00000000 /* RW--V */
-#define NV_PMC_ENABLE_PFB_ENABLED 0x00000001 /* RWI-V */
-#define NV_PMC_ENABLE_PCRTC 24:24 /* RWIVF */
-#define NV_PMC_ENABLE_PCRTC_DISABLED 0x00000000 /* RW--V */
-#define NV_PMC_ENABLE_PCRTC_ENABLED 0x00000001 /* RWI-V */
-#define NV_PMC_ENABLE_PVIDEO 28:28 /* RWIVF */
-#define NV_PMC_ENABLE_PVIDEO_DISABLED 0x00000000 /* RWI-V */
-#define NV_PMC_ENABLE_PVIDEO_ENABLED 0x00000001 /* RW--V */
-
-/* dev_timer.ref */
-#define NV_PTIMER 0x00009FFF:0x00009000 /* RW--D */
-#define NV_PTIMER_INTR_0 0x00009100 /* RW-4R */
-#define NV_PTIMER_INTR_0_ALARM 0:0 /* RWXVF */
-#define NV_PTIMER_INTR_0_ALARM_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PTIMER_INTR_0_ALARM_PENDING 0x00000001 /* R---V */
-#define NV_PTIMER_INTR_0_ALARM_RESET 0x00000001 /* -W--V */
-#define NV_PTIMER_INTR_EN_0 0x00009140 /* RW-4R */
-#define NV_PTIMER_INTR_EN_0_ALARM 0:0 /* RWIVF */
-#define NV_PTIMER_INTR_EN_0_ALARM_DISABLED 0x00000000 /* RWI-V */
-#define NV_PTIMER_INTR_EN_0_ALARM_ENABLED 0x00000001 /* RW--V */
-#define NV_PTIMER_NUMERATOR 0x00009200 /* RW-4R */
-#define NV_PTIMER_NUMERATOR_VALUE 15:0 /* RWIUF */
-#define NV_PTIMER_NUMERATOR_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PTIMER_DENOMINATOR 0x00009210 /* RW-4R */
-#define NV_PTIMER_DENOMINATOR_VALUE 15:0 /* RWIUF */
-#define NV_PTIMER_DENOMINATOR_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PTIMER_TIME_0 0x00009400 /* RW-4R */
-#define NV_PTIMER_TIME_0_NSEC 31:5 /* RWXUF */
-#define NV_PTIMER_TIME_1 0x00009410 /* RW-4R */
-#define NV_PTIMER_TIME_1_NSEC 28:0 /* RWXUF */
-#define NV_PTIMER_ALARM_0 0x00009420 /* RW-4R */
-#define NV_PTIMER_ALARM_0_NSEC 31:5 /* RWXUF */
-
-/* dev_fifo.ref */
-#define NV_PFIFO 0x00003FFF:0x00002000 /* RW--D */
-#define NV_PFIFO_DELAY_0 0x00002040 /* RW-4R */
-#define NV_PFIFO_DELAY_0_WAIT_RETRY 9:0 /* RWIUF */
-#define NV_PFIFO_DELAY_0_WAIT_RETRY_0 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_TIMESLICE 0x00002044 /* RW-4R */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT 16:0 /* RWIUF */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_1 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_16K 0x00003fff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_32K 0x00007fff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_64K 0x0000ffff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_SELECT_128K 0x0001ffff /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT 24:24 /* RWIUF */
-#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_DISABLED 0x00000000 /* RW--V */
-#define NV_PFIFO_DMA_TIMESLICE_TIMEOUT_ENABLED 0x00000001 /* RWI-V */
-#define NV_PFIFO_PIO_TIMESLICE 0x00002048 /* RW-4R */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT 16:0 /* RWIUF */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_1 0x00000000 /* RWI-V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_16K 0x00003fff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_32K 0x00007fff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_64K 0x0000ffff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_SELECT_128K 0x0001ffff /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT 24:24 /* RWIUF */
-#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_DISABLED 0x00000000 /* RW--V */
-#define NV_PFIFO_PIO_TIMESLICE_TIMEOUT_ENABLED 0x00000001 /* RWI-V */
-#define NV_PFIFO_TIMESLICE 0x0000204C /* RW-4R */
-#define NV_PFIFO_TIMESLICE_TIMER 17:0 /* RWIUF */
-#define NV_PFIFO_TIMESLICE_TIMER_EXPIRED 0x0003FFFF /* RWI-V */
-#define NV_PFIFO_NEXT_CHANNEL 0x00002050 /* RW-4R */
-#define NV_PFIFO_NEXT_CHANNEL_CHID 3:0 /* RWXUF */
-#define NV_PFIFO_NEXT_CHANNEL_MODE 8:8 /* RWXVF */
-#define NV_PFIFO_NEXT_CHANNEL_MODE_PIO 0x00000000 /* RW--V */
-#define NV_PFIFO_NEXT_CHANNEL_MODE_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_NEXT_CHANNEL_SWITCH 12:12 /* RWIVF */
-#define NV_PFIFO_NEXT_CHANNEL_SWITCH_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_NEXT_CHANNEL_SWITCH_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DEBUG_0 0x00002080 /* R--4R */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR0 0:0 /* R-XVF */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR0_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR1 4:4 /* R-XVF */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_DEBUG_0_CACHE_ERROR1_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0 0x00002100 /* RW-4R */
-#define NV_PFIFO_INTR_0_CACHE_ERROR 0:0 /* RWXVF */
-#define NV_PFIFO_INTR_0_CACHE_ERROR_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_CACHE_ERROR_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_CACHE_ERROR_RESET 0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_RUNOUT 4:4 /* RWXVF */
-#define NV_PFIFO_INTR_0_RUNOUT_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_RESET 0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW 8:8 /* RWXVF */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_RUNOUT_OVERFLOW_RESET 0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_DMA_PUSHER 12:12 /* RWXVF */
-#define NV_PFIFO_INTR_0_DMA_PUSHER_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PUSHER_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PUSHER_RESET 0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_0_DMA_PT 16:16 /* RWXVF */
-#define NV_PFIFO_INTR_0_DMA_PT_NOT_PENDING 0x00000000 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PT_PENDING 0x00000001 /* R---V */
-#define NV_PFIFO_INTR_0_DMA_PT_RESET 0x00000001 /* -W--V */
-#define NV_PFIFO_INTR_EN_0 0x00002140 /* RW-4R */
-#define NV_PFIFO_INTR_EN_0_CACHE_ERROR 0:0 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_CACHE_ERROR_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT 4:4 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW 8:8 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_RUNOUT_OVERFLOW_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_DMA_PUSHER 12:12 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_DMA_PUSHER_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_INTR_EN_0_DMA_PT 16:16 /* RWIVF */
-#define NV_PFIFO_INTR_EN_0_DMA_PT_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_INTR_EN_0_DMA_PT_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_RAMHT 0x00002210 /* RW-4R */
-#define NV_PFIFO_RAMHT_BASE_ADDRESS 8:4 /* RWIUF */
-#define NV_PFIFO_RAMHT_BASE_ADDRESS_10000 0x00000010 /* RWI-V */
-#define NV_PFIFO_RAMHT_SIZE 17:16 /* RWIUF */
-#define NV_PFIFO_RAMHT_SIZE_4K 0x00000000 /* RWI-V */
-#define NV_PFIFO_RAMHT_SIZE_8K 0x00000001 /* RW--V */
-#define NV_PFIFO_RAMHT_SIZE_16K 0x00000002 /* RW--V */
-#define NV_PFIFO_RAMHT_SIZE_32K 0x00000003 /* RW--V */
-#define NV_PFIFO_RAMHT_SEARCH 25:24 /* RWIUF */
-#define NV_PFIFO_RAMHT_SEARCH_16 0x00000000 /* RWI-V */
-#define NV_PFIFO_RAMHT_SEARCH_32 0x00000001 /* RW--V */
-#define NV_PFIFO_RAMHT_SEARCH_64 0x00000002 /* RW--V */
-#define NV_PFIFO_RAMHT_SEARCH_128 0x00000003 /* RW--V */
-#define NV_PFIFO_RAMFC 0x00002214 /* RW-4R */
-#define NV_PFIFO_RAMFC_BASE_ADDRESS 8:1 /* RWIUF */
-#define NV_PFIFO_RAMFC_BASE_ADDRESS_11000 0x00000088 /* RWI-V */
-#define NV_PFIFO_RAMRO 0x00002218 /* RW-4R */
-#define NV_PFIFO_RAMRO_BASE_ADDRESS 8:1 /* RWIUF */
-#define NV_PFIFO_RAMRO_BASE_ADDRESS_11200 0x00000089 /* RWI-V */
-#define NV_PFIFO_RAMRO_BASE_ADDRESS_12000 0x00000090 /* RW--V */
-#define NV_PFIFO_RAMRO_SIZE 16:16 /* RWIVF */
-#define NV_PFIFO_RAMRO_SIZE_512 0x00000000 /* RWI-V */
-#define NV_PFIFO_RAMRO_SIZE_8K 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHES 0x00002500 /* RW-4R */
-#define NV_PFIFO_CACHES_REASSIGN 0:0 /* RWIVF */
-#define NV_PFIFO_CACHES_REASSIGN_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHES_REASSIGN_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHES_DMA_SUSPEND 4:4 /* R--VF */
-#define NV_PFIFO_CACHES_DMA_SUSPEND_IDLE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHES_DMA_SUSPEND_BUSY 0x00000001 /* R---V */
-#define NV_PFIFO_MODE 0x00002504 /* RW-4R */
-#define NV_PFIFO_MODE_CHANNEL_0 0:0 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_0_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_0_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_1 1:1 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_1_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_1_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_2 2:2 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_2_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_2_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_3 3:3 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_3_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_3_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_4 4:4 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_4_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_4_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_5 5:5 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_5_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_5_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_6 6:6 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_6_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_6_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_7 7:7 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_7_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_7_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_8 8:8 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_8_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_8_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_9 9:9 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_9_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_9_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_10 10:10 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_10_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_10_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_11 11:11 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_11_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_11_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_12 12:12 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_12_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_12_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_13 13:13 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_13_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_13_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_14 14:14 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_14_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_14_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_MODE_CHANNEL_15 15:15 /* RWIVF */
-#define NV_PFIFO_MODE_CHANNEL_15_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_MODE_CHANNEL_15_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA 0x00002508 /* RW-4R */
-#define NV_PFIFO_DMA_CHANNEL_0 0:0 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_0_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_0_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_1 1:1 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_1_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_1_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_2 2:2 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_2_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_2_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_3 3:3 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_3_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_3_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_4 4:4 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_4_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_4_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_5 5:5 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_5_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_5_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_6 6:6 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_6_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_6_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_7 7:7 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_7_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_7_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_8 8:8 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_8_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_8_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_9 9:9 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_9_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_9_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_10 10:10 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_10_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_10_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_11 11:11 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_11_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_11_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_12 12:12 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_12_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_12_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_13 13:13 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_13_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_13_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_14 14:14 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_14_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_14_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_DMA_CHANNEL_15 15:15 /* RWIVF */
-#define NV_PFIFO_DMA_CHANNEL_15_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PFIFO_DMA_CHANNEL_15_PENDING 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE 0x0000250C /* RW-4R */
-#define NV_PFIFO_SIZE_CHANNEL_0 0:0 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_0_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_0_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_1 1:1 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_1_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_1_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_2 2:2 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_2_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_2_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_3 3:3 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_3_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_3_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_4 4:4 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_4_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_4_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_5 5:5 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_5_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_5_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_6 6:6 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_6_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_6_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_7 7:7 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_7_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_7_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_8 8:8 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_8_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_8_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_9 9:9 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_9_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_9_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_10 10:10 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_10_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_10_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_11 11:11 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_11_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_11_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_12 12:12 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_12_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_12_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_13 13:13 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_13_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_13_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_14 14:14 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_14_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_14_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_SIZE_CHANNEL_15 15:15 /* RWIVF */
-#define NV_PFIFO_SIZE_CHANNEL_15_124_BYTES 0x00000000 /* RWI-V */
-#define NV_PFIFO_SIZE_CHANNEL_15_512_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PUSH0 0x00003000 /* RW-4R */
-#define NV_PFIFO_CACHE0_PUSH0_ACCESS 0:0 /* RWIVF */
-#define NV_PFIFO_CACHE0_PUSH0_ACCESS_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE0_PUSH0_ACCESS_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_PUSH0 0x00003200 /* RW-4R */
-#define NV_PFIFO_CACHE1_PUSH0_ACCESS 0:0 /* RWIVF */
-#define NV_PFIFO_CACHE1_PUSH0_ACCESS_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_PUSH0_ACCESS_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PUSH1 0x00003004 /* RW-4R */
-#define NV_PFIFO_CACHE0_PUSH1_CHID 3:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_PUSH1 0x00003204 /* RW-4R */
-#define NV_PFIFO_CACHE1_PUSH1_CHID 3:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_PUSH1_MODE 8:8 /* RWIVF */
-#define NV_PFIFO_CACHE1_PUSH1_MODE_PIO 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_PUSH1_MODE_DMA 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_PUSH 0x00003220 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS 0:0 /* RWIVF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_ACCESS_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATE 4:4 /* R--VF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_IDLE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATE_BUSY 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER 8:8 /* R--VF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_NOT_EMPTY 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_BUFFER_EMPTY 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS 12:12 /* RWIVF */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_RUNNING 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_PUSH_STATUS_SUSPENDED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH 0x00003224 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG 7:3 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000004 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000005 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000006 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000007 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000008 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000009 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x0000000A /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x0000000B /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x0000000C /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x0000000D /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x0000000E /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x0000000F /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000010 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000011 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000012 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000013 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x00000014 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x00000015 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x00000016 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x00000017 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x00000018 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x00000019 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x0000001A /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x0000001B /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x0000001C /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x0000001D /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x0000001E /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x0000001F /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 15:13 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00000003 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00000004 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x00000005 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x00000006 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x00000007 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 19:16 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00000004 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00000005 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00000006 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00000007 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00000008 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00000009 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x0000000A /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x0000000B /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x0000000C /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x0000000D /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x0000000E /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x0000000F /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_PUT 0x00003240 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_PUT_OFFSET 28:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_GET 0x00003244 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_GET_OFFSET 28:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE 0x00003228 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_STATE_METHOD 12:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_SUBCHANNEL 15:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT 28:18 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_METHOD_COUNT_0 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR 31:30 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NONE 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_NON_CACHE 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_RESERVED_CMD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_STATE_ERROR_PROTECTION 0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_INSTANCE 0x0000322C /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_INSTANCE_ADDRESS 15:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL 0x00003230 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_CTL_ADJUST 11:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE 12:12 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_NOT_PRESENT 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_TABLE_PRESENT 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY 13:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_NOT_LINEAR 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_PAGE_ENTRY_LINEAR 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE 17:16 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_PCI 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_TARGET_NODE_AGP 0x00000003 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO 31:31 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_INVALID 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_CTL_AT_INFO_VALID 0x00000001 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_LIMIT 0x00003234 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_LIMIT_OFFSET 28:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG 0x00003238 /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_ADDRESS 28:12 /* RWXUF */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE 0:0 /* RWIUF */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_INVALID 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_DMA_TLB_TAG_STATE_VALID 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_DMA_TLB_PTE 0x0000323C /* RW-4R */
-#define NV_PFIFO_CACHE1_DMA_TLB_PTE_FRAME_ADDRESS 31:12 /* RWXUF */
-#define NV_PFIFO_CACHE0_PULL0 0x00003050 /* RW-4R */
-#define NV_PFIFO_CACHE0_PULL0_ACCESS 0:0 /* RWIVF */
-#define NV_PFIFO_CACHE0_PULL0_ACCESS_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE0_PULL0_ACCESS_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PULL0_HASH 4:4 /* R-XVF */
-#define NV_PFIFO_CACHE0_PULL0_HASH_SUCCEEDED 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_HASH_FAILED 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_DEVICE 8:8 /* R-XVF */
-#define NV_PFIFO_CACHE0_PULL0_DEVICE_HARDWARE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_DEVICE_SOFTWARE 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_HASH_STATE 12:12 /* R-XVF */
-#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_IDLE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_PULL0_HASH_STATE_BUSY 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0 0x00003250 /* RW-4R */
-#define NV_PFIFO_CACHE1_PULL0_ACCESS 0:0 /* RWIVF */
-#define NV_PFIFO_CACHE1_PULL0_ACCESS_DISABLED 0x00000000 /* RWI-V */
-#define NV_PFIFO_CACHE1_PULL0_ACCESS_ENABLED 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL0_HASH 4:4 /* R-XVF */
-#define NV_PFIFO_CACHE1_PULL0_HASH_SUCCEEDED 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_DEVICE 8:8 /* R-XVF */
-#define NV_PFIFO_CACHE1_PULL0_DEVICE_HARDWARE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_DEVICE_SOFTWARE 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_HASH_STATE 12:12 /* R-XVF */
-#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_IDLE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_PULL0_HASH_STATE_BUSY 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PULL1 0x00003054 /* RW-4R */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE 1:0 /* RWXUF */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_PULL1_ENGINE_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL1 0x00003254 /* RW-4R */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE 1:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_PULL1_ENGINE_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_HASH 0x00003058 /* RW-4R */
-#define NV_PFIFO_CACHE0_HASH_INSTANCE 15:0 /* RWXUF */
-#define NV_PFIFO_CACHE0_HASH_VALID 16:16 /* RWXVF */
-#define NV_PFIFO_CACHE1_HASH 0x00003258 /* RW-4R */
-#define NV_PFIFO_CACHE1_HASH_INSTANCE 15:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_HASH_VALID 16:16 /* RWXVF */
-#define NV_PFIFO_CACHE0_STATUS 0x00003014 /* R--4R */
-#define NV_PFIFO_CACHE0_STATUS_LOW_MARK 4:4 /* R--VF */
-#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_NOT_EMPTY 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_STATUS_LOW_MARK_EMPTY 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK 8:8 /* R--VF */
-#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_NOT_FULL 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE0_STATUS_HIGH_MARK_FULL 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS 0x00003214 /* R--4R */
-#define NV_PFIFO_CACHE1_STATUS_LOW_MARK 4:4 /* R--VF */
-#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_NOT_EMPTY 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS_LOW_MARK_EMPTY 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK 8:8 /* R--VF */
-#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_NOT_FULL 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS_HIGH_MARK_FULL 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS1 0x00003218 /* R--4R */
-#define NV_PFIFO_CACHE1_STATUS1_RANOUT 0:0 /* R-XVF */
-#define NV_PFIFO_CACHE1_STATUS1_RANOUT_FALSE 0x00000000 /* R---V */
-#define NV_PFIFO_CACHE1_STATUS1_RANOUT_TRUE 0x00000001 /* R---V */
-#define NV_PFIFO_CACHE0_PUT 0x00003010 /* RW-4R */
-#define NV_PFIFO_CACHE0_PUT_ADDRESS 2:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_PUT 0x00003210 /* RW-4R */
-#define NV_PFIFO_CACHE1_PUT_ADDRESS 9:2 /* RWXUF */
-#define NV_PFIFO_CACHE0_GET 0x00003070 /* RW-4R */
-#define NV_PFIFO_CACHE0_GET_ADDRESS 2:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_GET 0x00003270 /* RW-4R */
-#define NV_PFIFO_CACHE1_GET_ADDRESS 9:2 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE 0x00003080 /* RW-4R */
-#define NV_PFIFO_CACHE0_ENGINE_0 1:0 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_0_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_0_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_0_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_1 5:4 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_1_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_1_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_1_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_2 9:8 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_2_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_2_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_2_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_3 13:12 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_3_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_3_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_3_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_4 17:16 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_4_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_4_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_4_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_5 21:20 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_5_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_5_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_5_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_6 25:24 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_6_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_6_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_6_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_7 29:28 /* RWXUF */
-#define NV_PFIFO_CACHE0_ENGINE_7_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_7_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE0_ENGINE_7_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE 0x00003280 /* RW-4R */
-#define NV_PFIFO_CACHE1_ENGINE_0 1:0 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_0_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_0_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_0_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_1 5:4 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_1_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_1_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_1_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_2 9:8 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_2_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_2_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_2_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_3 13:12 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_3_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_3_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_3_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_4 17:16 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_4_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_4_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_4_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_5 21:20 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_5_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_5_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_5_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_6 25:24 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_6_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_6_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_6_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_7 29:28 /* RWXUF */
-#define NV_PFIFO_CACHE1_ENGINE_7_SW 0x00000000 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_7_GRAPHICS 0x00000001 /* RW--V */
-#define NV_PFIFO_CACHE1_ENGINE_7_DVD 0x00000002 /* RW--V */
-#define NV_PFIFO_CACHE0_METHOD(i) (0x00003100+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE0_METHOD__SIZE_1 1 /* */
-#define NV_PFIFO_CACHE0_METHOD_ADDRESS 12:2 /* RWXUF */
-#define NV_PFIFO_CACHE0_METHOD_SUBCHANNEL 15:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_METHOD(i) (0x00003800+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_METHOD__SIZE_1 128 /* */
-#define NV_PFIFO_CACHE1_METHOD_ADDRESS 12:2 /* RWXUF */
-#define NV_PFIFO_CACHE1_METHOD_SUBCHANNEL 15:13 /* RWXUF */
-#define NV_PFIFO_CACHE1_METHOD_ALIAS(i) (0x00003C00+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_METHOD_ALIAS__SIZE_1 128 /* */
-#define NV_PFIFO_CACHE0_DATA(i) (0x00003104+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE0_DATA__SIZE_1 1 /* */
-#define NV_PFIFO_CACHE0_DATA_VALUE 31:0 /* RWXVF */
-#define NV_PFIFO_CACHE1_DATA(i) (0x00003804+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_DATA__SIZE_1 128 /* */
-#define NV_PFIFO_CACHE1_DATA_VALUE 31:0 /* RWXVF */
-#define NV_PFIFO_CACHE1_DATA_ALIAS(i) (0x00003C04+(i)*8) /* RW-4A */
-#define NV_PFIFO_CACHE1_DATA_ALIAS__SIZE_1 128 /* */
-#define NV_PFIFO_DEVICE(i) (0x00002800+(i)*4) /* R--4A */
-#define NV_PFIFO_DEVICE__SIZE_1 128 /* */
-#define NV_PFIFO_DEVICE_CHID 3:0 /* R--UF */
-#define NV_PFIFO_DEVICE_SWITCH 24:24 /* R--VF */
-#define NV_PFIFO_DEVICE_SWITCH_UNAVAILABLE 0x00000000 /* R---V */
-#define NV_PFIFO_DEVICE_SWITCH_AVAILABLE 0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS 0x00002400 /* R--4R */
-#define NV_PFIFO_RUNOUT_STATUS_RANOUT 0:0 /* R--VF */
-#define NV_PFIFO_RUNOUT_STATUS_RANOUT_FALSE 0x00000000 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_RANOUT_TRUE 0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK 4:4 /* R--VF */
-#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_NOT_EMPTY 0x00000000 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_LOW_MARK_EMPTY 0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK 8:8 /* R--VF */
-#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_NOT_FULL 0x00000000 /* R---V */
-#define NV_PFIFO_RUNOUT_STATUS_HIGH_MARK_FULL 0x00000001 /* R---V */
-#define NV_PFIFO_RUNOUT_PUT 0x00002410 /* RW-4R */
-#define NV_PFIFO_RUNOUT_PUT_ADDRESS 12:3 /* RWXUF */
-#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_0 8:3 /* RWXUF */
-#define NV_PFIFO_RUNOUT_PUT_ADDRESS__SIZE_1 12:3 /* RWXUF */
-#define NV_PFIFO_RUNOUT_GET 0x00002420 /* RW-4R */
-#define NV_PFIFO_RUNOUT_GET_ADDRESS 13:3 /* RWXUF */
-/* dev_graphics.ref */
-#define NV_PGRAPH 0x00401FFF:0x00400000 /* RW--D */
-#define NV_PGRAPH_DEBUG_0 0x00400080 /* RW-4R */
-#define NV_PGRAPH_DEBUG_1 0x00400084 /* RW-4R */
-#define NV_PGRAPH_DEBUG_2 0x00400088 /* RW-4R */
-#define NV_PGRAPH_DEBUG_3 0x0040008C /* RW-4R */
-#define NV_PGRAPH_INTR 0x00400100 /* RW-4R */
-#define NV_PGRAPH_INTR_NOTIFY 0:0 /* RWIVF */
-#define NV_PGRAPH_INTR_NOTIFY_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_NOTIFY_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_NOTIFY_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_MISSING_HW 4:4 /* RWIVF */
-#define NV_PGRAPH_INTR_MISSING_HW_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_MISSING_HW_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_MISSING_HW_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A 8:8 /* RWIVF */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_A_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B 9:9 /* RWIVF */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_TLB_PRESENT_B_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH 12:12 /* RWIVF */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_CONTEXT_SWITCH_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY 16:16 /* RWIVF */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_BUFFER_NOTIFY_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_NSTATUS 0x00400104 /* RW-4R */
-#define NV_PGRAPH_NSTATUS_STATE_IN_USE 11:11 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_STATE_IN_USE_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_STATE_IN_USE_PENDING 0x00000001 /* RW--V */
-#define NV_PGRAPH_NSTATUS_INVALID_STATE 12:12 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_INVALID_STATE_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_INVALID_STATE_PENDING 0x00000001 /* RW--V */
-#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT 13:13 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_BAD_ARGUMENT_PENDING 0x00000001 /* RW--V */
-#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT 14:14 /* RWIVF */
-#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NSTATUS_PROTECTION_FAULT_PENDING 0x00000001 /* RW--V */
-#define NV_PGRAPH_NSOURCE 0x00400108 /* R--4R */
-#define NV_PGRAPH_NSOURCE_NOTIFICATION 0:0 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_NOTIFICATION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_NOTIFICATION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DATA_ERROR 1:1 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DATA_ERROR_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DATA_ERROR_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR 2:2 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_PROTECTION_ERROR_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION 3:3 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_RANGE_EXCEPTION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_LIMIT_COLOR 4:4 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_LIMIT_COLOR_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_ 5:5 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_LIMIT_ZETA_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD 6:6 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_ILLEGAL_MTHD_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION 7:7 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DMA_R_PROTECTION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION 8:8 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DMA_W_PROTECTION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION 9:9 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_FORMAT_EXCEPTION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION 10:10 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_PATCH_EXCEPTION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_STATE_INVALID 11:11 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_STATE_INVALID_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_STATE_INVALID_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY 12:12 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_DOUBLE_NOTIFY_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE 13:13 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_NOTIFY_IN_USE_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_METHOD_CNT 14:14 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_METHOD_CNT_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_METHOD_CNT_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION 15:15 /* R-IVF */
-#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_NSOURCE_BFR_NOTIFICATION_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_INTR_EN 0x00400140 /* RW-4R */
-#define NV_PGRAPH_INTR_EN_NOTIFY 0:0 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_NOTIFY_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_NOTIFY_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_MISSING_HW 4:4 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_MISSING_HW_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_MISSING_HW_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A 8:8 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_A_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B 9:9 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_TLB_PRESENT_B_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH 12:12 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_CONTEXT_SWITCH_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY 16:16 /* RWIVF */
-#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_INTR_EN_BUFFER_NOTIFY_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1 0x00400160 /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH1_GRCLASS 7:0 /* RWXVF */
-#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY 12:12 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_DISABLE 0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_CHROMA_KEY_ENABLE 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP 13:13 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_DISABLE 0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_USER_CLIP_ENABLE 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE 14:14 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_DISABLE 0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_SWIZZLE_ENABLE 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG 17:15 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_AND 0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_ROP_AND 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_AND 0x00000002 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY 0x00000003 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_SRCCOPY_PRE 0x00000004 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_CONFIG_BLEND_PRE 0x00000005 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS 24:24 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_INVALID 0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_PATCH_STATUS_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE 25:25 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_INVALID 0x00000000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_CONTEXT_SURFACE_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET 31:31 /* CWIVF */
-#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_IGNORE 0x00000000 /* CWI-V */
-#define NV_PGRAPH_CTX_SWITCH1_VOLATILE_RESET_ENABLED 0x00000001 /* -W--T */
-#define NV_PGRAPH_CTX_SWITCH2 0x00400164 /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT 1:0 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_INVALID 0x00 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_CGA6_M1 0x01 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_MONO_FORMAT_LE_M1 0x02 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT 13:8 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_INVALID 0x00 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y8 0x01 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A8Y8 0x02 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X24Y8 0x03 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A1R5G5B5 0x06 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X1R5G5B5 0x07 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16A1R5G5B5 0x08 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X17R5G5B5 0x09 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_R5G6B5 0x0A /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16R5G6B5 0x0B /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16R5G6B5 0x0C /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A8R8G8B8 0x0D /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X8R8G8B8 0x0E /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y16 0x0F /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_A16Y16 0x10 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_X16Y16 0x11 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_V8YB8U8YA8 0x12 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_YB8V8YA8U8 0x13 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_COLOR_FORMAT_LE_Y32 0x14 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE 31:16 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH2_NOTIFY_INSTANCE_INVALID 0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH3 0x00400168 /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0 15:0 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_0_INVALID 0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1 31:16 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH3_DMA_INSTANCE_1_INVALID 0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_SWITCH4 0x0040016C /* RW-4R */
-#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE 15:0 /* RWXUF */
-#define NV_PGRAPH_CTX_SWITCH4_USER_INSTANCE_INVALID 0x0000 /* RW--V */
-#define NV_PGRAPH_CTX_CACHE1(i) (0x00400180+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE1__SIZE_1 8 /* */
-#define NV_PGRAPH_CTX_CACHE1_GRCLASS 7:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_CHROMA_KEY 12:12 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_USER_CLIP 13:13 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_SWIZZLE 14:14 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_PATCH_CONFIG 19:15 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_SPARE1 20:20 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_PATCH_STATUS 24:24 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE1_CONTEXT_SURFACE 25:25 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE2(i) (0x004001a0+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE2__SIZE_1 8 /* */
-#define NV_PGRAPH_CTX_CACHE2_MONO_FORMAT 1:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE2_COLOR_FORMAT 13:8 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE2_NOTIFY_INSTANCE 31:16 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE3(i) (0x004001c0+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE3__SIZE_1 8 /* */
-#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_0 15:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE3_DMA_INSTANCE_1 31:16 /* RWXVF */
-#define NV_PGRAPH_CTX_CACHE4(i) (0x004001e0+(i)*4) /* RW-4A */
-#define NV_PGRAPH_CTX_CACHE4__SIZE_1 8 /* */
-#define NV_PGRAPH_CTX_CACHE4_USER_INSTANCE 15:0 /* RWXVF */
-#define NV_PGRAPH_CTX_CONTROL 0x00400170 /* RW-4R */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME 1:0 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_33US 0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_262US 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_2MS 0x00000002 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_MINIMUM_TIME_17MS 0x00000003 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_TIME 8:8 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_TIME_EXPIRED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_TIME_NOT_EXPIRED 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_CHID 16:16 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_CHID_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_CHID_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_CHANGE 20:20 /* R--VF */
-#define NV_PGRAPH_CTX_CONTROL_CHANGE_UNAVAILABLE 0x00000000 /* R---V */
-#define NV_PGRAPH_CTX_CONTROL_CHANGE_AVAILABLE 0x00000001 /* R---V */
-#define NV_PGRAPH_CTX_CONTROL_SWITCHING 24:24 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_SWITCHING_IDLE 0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_SWITCHING_BUSY 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_CONTROL_DEVICE 28:28 /* RWIVF */
-#define NV_PGRAPH_CTX_CONTROL_DEVICE_DISABLED 0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_CONTROL_DEVICE_ENABLED 0x00000001 /* RW--V */
-#define NV_PGRAPH_CTX_USER 0x00400174 /* RW-4R */
-#define NV_PGRAPH_CTX_USER_SUBCH 15:13 /* RWIVF */
-#define NV_PGRAPH_CTX_USER_SUBCH_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_CTX_USER_CHID 27:24 /* RWIVF */
-#define NV_PGRAPH_CTX_USER_CHID_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FIFO 0x00400720 /* RW-4R */
-#define NV_PGRAPH_FIFO_ACCESS 0:0 /* RWIVF */
-#define NV_PGRAPH_FIFO_ACCESS_DISABLED 0x00000000 /* RW--V */
-#define NV_PGRAPH_FIFO_ACCESS_ENABLED 0x00000001 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_FIFO_0(i) (0x00400730+(i)*4) /* RW-4A */
-#define NV_PGRAPH_FFINTFC_FIFO_0__SIZE_1 4 /* */
-#define NV_PGRAPH_FFINTFC_FIFO_0_TAG 0:0 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_MTHD 0x00000000 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_TAG_CHSW 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH 3:1 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_0 0x00000000 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_1 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_2 0x00000002 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_3 0x00000003 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_4 0x00000004 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_5 0x00000005 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_6 0x00000006 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_SUBCH_7 0x00000007 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD 14:4 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_0_MTHD_CTX_SWITCH 0x00000000 /* RW--V */
-#define NV_PGRAPH_FFINTFC_FIFO_1(i) (0x00400740+(i)*4) /* RW-4A */
-#define NV_PGRAPH_FFINTFC_FIFO_1__SIZE_1 4 /* */
-#define NV_PGRAPH_FFINTFC_FIFO_1_ARGUMENT 31:0 /* RWXVF */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR 0x00400750 /* RW-4R */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE 2:0 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_WRITE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ 6:4 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_FIFO_PTR_READ_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2 0x00400754 /* RW-4R */
-#define NV_PGRAPH_FFINTFC_ST2_STATUS 0:0 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_STATUS_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_STATUS_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_MTHD 11:1 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_MTHD_CTX_SWITCH 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH 14:12 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_1 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_2 0x00000002 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_3 0x00000003 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_4 0x00000004 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_5 0x00000005 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_6 0x00000006 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_SUBCH_7 0x00000007 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID 18:15 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_1 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_2 0x00000002 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_3 0x00000003 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_4 0x00000004 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_5 0x00000005 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_6 0x00000006 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_7 0x00000007 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_8 0x00000008 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_9 0x00000009 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_10 0x0000000A /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_11 0x0000000B /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_12 0x0000000C /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_13 0x0000000D /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_14 0x0000000E /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_15 0x0000000F /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS 19:19 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FFINTFC_ST2_CHID_STATUS_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_FFINTFC_ST2_D 0x00400758 /* RW-4R */
-#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT 31:0 /* RWIVF */
-#define NV_PGRAPH_FFINTFC_ST2_D_ARGUMENT_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATUS 0x00400700 /* R--4R */
-#define NV_PGRAPH_STATUS_STATE 0:0 /* R-IVF */
-#define NV_PGRAPH_STATUS_STATE_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_STATE_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_XY_LOGIC 4:4 /* R-IVF */
-#define NV_PGRAPH_STATUS_XY_LOGIC_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_XY_LOGIC_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_FE 5:5 /* R-IVF */
-#define NV_PGRAPH_STATUS_FE_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_FE_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_RASTERIZER 6:6 /* R-IVF */
-#define NV_PGRAPH_STATUS_RASTERIZER_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_RASTERIZER_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_NOTIFY 8:8 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_NOTIFY_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_NOTIFY_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_REGISTER 12:12 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_REGISTER_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_REGISTER_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_DMA 16:16 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_DMA_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_DMA_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_DMA_ENGINE 17:17 /* R-IVF */
-#define NV_PGRAPH_STATUS_DMA_ENGINE_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_DMA_ENGINE_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_DMA_NOTIFY 20:20 /* R-IVF */
-#define NV_PGRAPH_STATUS_DMA_NOTIFY_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_DMA_NOTIFY_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY 21:21 /* R-IVF */
-#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_DMA_BUFFER_NOTIFY_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_D3D 24:24 /* R-IVF */
-#define NV_PGRAPH_STATUS_D3D_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_D3D_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_CACHE 25:25 /* R-IVF */
-#define NV_PGRAPH_STATUS_CACHE_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_CACHE_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_LIGHTING 26:26 /* R-IVF */
-#define NV_PGRAPH_STATUS_LIGHTING_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_LIGHTING_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PREROP 27:27 /* R-IVF */
-#define NV_PGRAPH_STATUS_PREROP_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PREROP_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_ROP 28:28 /* R-IVF */
-#define NV_PGRAPH_STATUS_ROP_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_ROP_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_STATUS_PORT_USER 29:29 /* R-IVF */
-#define NV_PGRAPH_STATUS_PORT_USER_IDLE 0x00000000 /* R-I-V */
-#define NV_PGRAPH_STATUS_PORT_USER_BUSY 0x00000001 /* R---V */
-#define NV_PGRAPH_TRAPPED_ADDR 0x00400704 /* R--4R */
-#define NV_PGRAPH_TRAPPED_ADDR_MTHD 12:2 /* R-XUF */
-#define NV_PGRAPH_TRAPPED_ADDR_SUBCH 15:13 /* R-XUF */
-#define NV_PGRAPH_TRAPPED_ADDR_CHID 27:24 /* R-XUF */
-#define NV_PGRAPH_TRAPPED_DATA 0x00400708 /* R--4R */
-#define NV_PGRAPH_TRAPPED_DATA_VALUE 31:0 /* R-XVF */
-#define NV_PGRAPH_SURFACE 0x0040070C /* RW-4R */
-#define NV_PGRAPH_SURFACE_TYPE 1:0 /* RWIVF */
-#define NV_PGRAPH_SURFACE_TYPE_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_SURFACE_TYPE_NON_SWIZZLE 0x00000001 /* RW--V */
-#define NV_PGRAPH_SURFACE_TYPE_SWIZZLE 0x00000002 /* RW--V */
-#define NV_PGRAPH_NOTIFY 0x00400714 /* RW-4R */
-#define NV_PGRAPH_NOTIFY_BUFFER_REQ 0:0 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_BUFFER_REQ_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_BUFFER_REQ_PENDING 0x00000001 /* RW--V */
-#define NV_PGRAPH_NOTIFY_BUFFER_STYLE 8:8 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_ONLY 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_BUFFER_STYLE_WRITE_THEN_AWAKEN 0x00000001 /* RW--V */
-#define NV_PGRAPH_NOTIFY_REQ 16:16 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_REQ_NOT_PENDING 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_REQ_PENDING 0x00000001 /* RW--V */
-#define NV_PGRAPH_NOTIFY_STYLE 20:20 /* RWIVF */
-#define NV_PGRAPH_NOTIFY_STYLE_WRITE_ONLY 0x00000000 /* RWI-V */
-#define NV_PGRAPH_NOTIFY_STYLE_WRITE_THEN_AWAKEN 0x00000001 /* RW--V */
-#define NV_PGRAPH_BOFFSET(i) (0x00400640+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BOFFSET__SIZE_1 6 /* */
-#define NV_PGRAPH_BOFFSET_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET0 0x00400640 /* RW-4R */
-#define NV_PGRAPH_BOFFSET0__ALIAS_1 NV_PGRAPH_BOFFSET(0) /* */
-#define NV_PGRAPH_BOFFSET0_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET0_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET1 0x00400644 /* RW-4R */
-#define NV_PGRAPH_BOFFSET1__ALIAS_1 NV_PGRAPH_BOFFSET(1) /* */
-#define NV_PGRAPH_BOFFSET1_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET1_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET2 0x00400648 /* RW-4R */
-#define NV_PGRAPH_BOFFSET2__ALIAS_1 NV_PGRAPH_BOFFSET(2) /* */
-#define NV_PGRAPH_BOFFSET2_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET2_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET3 0x0040064C /* RW-4R */
-#define NV_PGRAPH_BOFFSET3__ALIAS_1 NV_PGRAPH_BOFFSET(3) /* */
-#define NV_PGRAPH_BOFFSET3_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET3_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET4 0x00400650 /* RW-4R */
-#define NV_PGRAPH_BOFFSET4__ALIAS_1 NV_PGRAPH_BOFFSET(4) /* */
-#define NV_PGRAPH_BOFFSET4_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET4_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BOFFSET5 0x00400654 /* RW-4R */
-#define NV_PGRAPH_BOFFSET5__ALIAS_1 NV_PGRAPH_BOFFSET(5) /* */
-#define NV_PGRAPH_BOFFSET5_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BOFFSET5_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE(i) (0x00400658+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BBASE__SIZE_1 6 /* */
-#define NV_PGRAPH_BBASE_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE0 0x00400658 /* RW-4R */
-#define NV_PGRAPH_BBASE0__ALIAS_1 NV_PGRAPH_BBASE(0) /* */
-#define NV_PGRAPH_BBASE0_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE0_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE1 0x0040065c /* RW-4R */
-#define NV_PGRAPH_BBASE1__ALIAS_1 NV_PGRAPH_BBASE(1) /* */
-#define NV_PGRAPH_BBASE1_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE1_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE2 0x00400660 /* RW-4R */
-#define NV_PGRAPH_BBASE2__ALIAS_1 NV_PGRAPH_BBASE(2) /* */
-#define NV_PGRAPH_BBASE2_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE2_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE3 0x00400664 /* RW-4R */
-#define NV_PGRAPH_BBASE3__ALIAS_1 NV_PGRAPH_BBASE(3) /* */
-#define NV_PGRAPH_BBASE3_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE3_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE4 0x00400668 /* RW-4R */
-#define NV_PGRAPH_BBASE4__ALIAS_1 NV_PGRAPH_BBASE(4) /* */
-#define NV_PGRAPH_BBASE4_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE4_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BBASE5 0x0040066C /* RW-4R */
-#define NV_PGRAPH_BBASE5__ALIAS_1 NV_PGRAPH_BBASE(5) /* */
-#define NV_PGRAPH_BBASE5_LINADRS 23:0 /* RWIUF */
-#define NV_PGRAPH_BBASE5_LINADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH(i) (0x00400670+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BPITCH__SIZE_1 5 /* */
-#define NV_PGRAPH_BPITCH_VALUE 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH0 0x00400670 /* RW-4R */
-#define NV_PGRAPH_BPITCH0__ALIAS_1 NV_PGRAPH_BPITCH(0) /* */
-#define NV_PGRAPH_BPITCH0_VALUE 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH0_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH1 0x00400674 /* RW-4R */
-#define NV_PGRAPH_BPITCH1__ALIAS_1 NV_PGRAPH_BPITCH(1) /* */
-#define NV_PGRAPH_BPITCH1_VALUE 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH1_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH2 0x00400678 /* RW-4R */
-#define NV_PGRAPH_BPITCH2__ALIAS_1 NV_PGRAPH_BPITCH(2) /* */
-#define NV_PGRAPH_BPITCH2_VALUE 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH2_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH3 0x0040067C /* RW-4R */
-#define NV_PGRAPH_BPITCH3__ALIAS_1 NV_PGRAPH_BPITCH(3) /* */
-#define NV_PGRAPH_BPITCH3_VALUE 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH3_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPITCH4 0x00400680 /* RW-4R */
-#define NV_PGRAPH_BPITCH4__ALIAS_1 NV_PGRAPH_BPITCH(4) /* */
-#define NV_PGRAPH_BPITCH4_VALUE 12:0 /* RWIUF */
-#define NV_PGRAPH_BPITCH4_VALUE_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BLIMIT(i) (0x00400684+(i)*4) /* RW-4A */
-#define NV_PGRAPH_BLIMIT__SIZE_1 6 /* */
-#define NV_PGRAPH_BLIMIT_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT0 0x00400684 /* RW-4R */
-#define NV_PGRAPH_BLIMIT0__ALIAS_1 NV_PGRAPH_BLIMIT(0) /* */
-#define NV_PGRAPH_BLIMIT0_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT0_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT0_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT0_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT1 0x00400688 /* RW-4R */
-#define NV_PGRAPH_BLIMIT1__ALIAS_1 NV_PGRAPH_BLIMIT(1) /* */
-#define NV_PGRAPH_BLIMIT1_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT1_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT1_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT1_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT2 0x0040068c /* RW-4R */
-#define NV_PGRAPH_BLIMIT2__ALIAS_1 NV_PGRAPH_BLIMIT(2) /* */
-#define NV_PGRAPH_BLIMIT2_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT2_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT2_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT2_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT3 0x00400690 /* RW-4R */
-#define NV_PGRAPH_BLIMIT3__ALIAS_1 NV_PGRAPH_BLIMIT(3) /* */
-#define NV_PGRAPH_BLIMIT3_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT3_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT3_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT3_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT4 0x00400694 /* RW-4R */
-#define NV_PGRAPH_BLIMIT4__ALIAS_1 NV_PGRAPH_BLIMIT(4) /* */
-#define NV_PGRAPH_BLIMIT4_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT4_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT4_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT4_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BLIMIT5 0x00400698 /* RW-4R */
-#define NV_PGRAPH_BLIMIT5__ALIAS_1 NV_PGRAPH_BLIMIT(5) /* */
-#define NV_PGRAPH_BLIMIT5_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_BLIMIT5_TYPE 31:31 /* RWIVF */
-#define NV_PGRAPH_BLIMIT5_TYPE_IN_MEMORY 0x00000000 /* RW--V */
-#define NV_PGRAPH_BLIMIT5_TYPE_NULL 0x00000001 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE2 0x0040069c /* RW-4R */
-#define NV_PGRAPH_BSWIZZLE2_WIDTH 19:16 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE2_WIDTH_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE2_HEIGHT 27:24 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE2_HEIGHT_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE5 0x004006a0 /* RW-4R */
-#define NV_PGRAPH_BSWIZZLE5_WIDTH 19:16 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE5_WIDTH_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BSWIZZLE5_HEIGHT 27:24 /* RWIUF */
-#define NV_PGRAPH_BSWIZZLE5_HEIGHT_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL 0x00400724 /* RW-4R */
-#define NV_PGRAPH_BPIXEL_DEPTH0 3:0 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH0_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH0_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1 7:4 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH1_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH1_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2 11:8 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH2_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH2_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3 15:12 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH3_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH3_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4 19:16 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH4_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH4_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5 23:20 /* RWIVF */
-#define NV_PGRAPH_BPIXEL_DEPTH5_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_BPIXEL_DEPTH5_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX 0x00400610 /* RW-4R */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS 23:0 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_ADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT 29:29 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_NO_VIOL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_BLIT_VIOL 0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT 30:30 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_NO_VIOL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_LIMIT_VIOL 0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW 31:31 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_NO_VIOL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_PIX_OVRFLW_VIOL 0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_Z 0x00400614 /* RW-4R */
-#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS 23:0 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_Z_ADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT 30:30 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_NO_VIOL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_LIMIT_VIOL 0x00000001 /* RW--V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW 31:31 /* RWIVF */
-#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_NO_VIOL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_LIMIT_VIOL_Z_OVRFLW_VIOL 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE 0x00400710 /* RW-4R */
-#define NV_PGRAPH_STATE_BUFFER_0 0:0 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_0_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_0_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_1 1:1 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_1_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_1_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_2 2:2 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_2_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_2_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_3 3:3 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_3_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_3_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_4 4:4 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_4_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_4_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_BUFFER_5 5:5 /* RWIVF */
-#define NV_PGRAPH_STATE_BUFFER_5_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_BUFFER_5_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_0 8:8 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_0_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_0_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_1 9:9 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_1_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_1_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_2 10:10 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_2_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_2_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_3 11:11 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_3_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_3_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PITCH_4 12:12 /* RWIVF */
-#define NV_PGRAPH_STATE_PITCH_4_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PITCH_4_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CHROMA_COLOR 16:16 /* RWIVF */
-#define NV_PGRAPH_STATE_CHROMA_COLOR_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CHROMA_COLOR_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CHROMA_COLORFMT 17:17 /* RWIVF */
-#define NV_PGRAPH_STATE_CHROMA_COLORFMT_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CHROMA_COLORFMT_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CPATTERN_COLORFMT 20:20 /* RWIVF */
-#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CPATTERN_COLORFMT_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CPATTERN_MONOFMT 21:21 /* RWIVF */
-#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CPATTERN_MONOFMT_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_CPATTERN_SELECT 22:22 /* RWIVF */
-#define NV_PGRAPH_STATE_CPATTERN_SELECT_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_CPATTERN_SELECT_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR0 24:24 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_COLOR0_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR0_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR1 25:25 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_COLOR1_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_COLOR1_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_PATT0 26:26 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_PATT0_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_PATT0_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_STATE_PATTERN_PATT1 27:27 /* RWIVF */
-#define NV_PGRAPH_STATE_PATTERN_PATT1_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_STATE_PATTERN_PATT1_VALID 0x00000001 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX 0x00400728 /* RW-4R */
-#define NV_PGRAPH_CACHE_INDEX_BANK 2:2 /* RWXVF */
-#define NV_PGRAPH_CACHE_INDEX_BANK_10 0x00000000 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_BANK_32 0x00000001 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_ADRS 12:3 /* RWXVF */
-#define NV_PGRAPH_CACHE_INDEX_ADRS_0 0x00000000 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_ADRS_1024 0x00000400 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_OP 14:13 /* RWXVF */
-#define NV_PGRAPH_CACHE_INDEX_OP_WR_CACHE 0x00000000 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_OP_RD_CACHE 0x00000001 /* RW--V */
-#define NV_PGRAPH_CACHE_INDEX_OP_RD_INDEX 0x00000002 /* RW--V */
-#define NV_PGRAPH_CACHE_RAM 0x0040072c /* RW-4R */
-#define NV_PGRAPH_CACHE_RAM_VALUE 31:0 /* RWXVF */
-#define NV_PGRAPH_DMA_PITCH 0x00400760 /* RW-4R */
-#define NV_PGRAPH_DMA_PITCH_S0 15:0 /* RWXSF */
-#define NV_PGRAPH_DMA_PITCH_S1 31:16 /* RWXSF */
-#define NV_PGRAPH_DVD_COLORFMT 0x00400764 /* RW-4R */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE 5:0 /* RWNVF */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_INVALID 0x00 /* RWN-V */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_V8YB8U8YA8 0x12 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_IMAGE_FORMAT_LE_YB8V8YA8U8 0x13 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY 9:8 /* RWNVF */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_INVALID 0x00 /* RWN-V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A8Y8U8V8 0x01 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_LE_A4V6YB6A4U6YA6 0x02 /* RW--V */
-#define NV_PGRAPH_DVD_COLORFMT_OVLY_FORMAT_TRANSPARENT 0x03 /* RW--V */
-#define NV_PGRAPH_SCALED_FORMAT 0x00400768 /* RW-4R */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN 17:16 /* RWIVF */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CENTER 0x00000001 /* RW--V */
-#define NV_PGRAPH_SCALED_FORMAT_ORIGIN_CORNER 0x00000002 /* RW--V */
-#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR 24:24 /* RWIVF */
-#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_ZOH 0x00000000 /* RWI-V */
-#define NV_PGRAPH_SCALED_FORMAT_INTERPOLATOR_FOH 0x00000001 /* RW--V */
-#define NV_PGRAPH_PATT_COLOR0 0x00400800 /* RW-4R */
-#define NV_PGRAPH_PATT_COLOR0_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_PATT_COLOR1 0x00400804 /* RW-4R */
-#define NV_PGRAPH_PATT_COLOR1_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_PATT_COLORRAM(i) (0x00400900+(i)*4) /* R--4A */
-#define NV_PGRAPH_PATT_COLORRAM__SIZE_1 64 /* */
-#define NV_PGRAPH_PATT_COLORRAM_VALUE 23:0 /* R--UF */
-#define NV_PGRAPH_PATTERN(i) (0x00400808+(i)*4) /* RW-4A */
-#define NV_PGRAPH_PATTERN__SIZE_1 2 /* */
-#define NV_PGRAPH_PATTERN_BITMAP 31:0 /* RWXVF */
-#define NV_PGRAPH_PATTERN_SHAPE 0x00400810 /* RW-4R */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE 1:0 /* RWXVF */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE_8X_8Y 0x00000000 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE_64X_1Y 0x00000001 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_VALUE_1X_64Y 0x00000002 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_SELECT 4:4 /* RWXVF */
-#define NV_PGRAPH_PATTERN_SHAPE_SELECT_2COLOR 0x00000000 /* RW--V */
-#define NV_PGRAPH_PATTERN_SHAPE_SELECT_FULLCOLOR 0x00000001 /* RW--V */
-#define NV_PGRAPH_MONO_COLOR0 0x00400600 /* RW-4R */
-#define NV_PGRAPH_MONO_COLOR0_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_ROP3 0x00400604 /* RW-4R */
-#define NV_PGRAPH_ROP3_VALUE 7:0 /* RWXVF */
-#define NV_PGRAPH_CHROMA 0x00400814 /* RW-4R */
-#define NV_PGRAPH_CHROMA_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_BETA_AND 0x00400608 /* RW-4R */
-#define NV_PGRAPH_BETA_AND_VALUE_FRACTION 30:23 /* RWXUF */
-#define NV_PGRAPH_BETA_PREMULT 0x0040060c /* RW-4R */
-#define NV_PGRAPH_BETA_PREMULT_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_CONTROL0 0x00400818 /* RW-4R */
-#define NV_PGRAPH_CONTROL1 0x0040081c /* RW-4R */
-#define NV_PGRAPH_CONTROL2 0x00400820 /* RW-4R */
-#define NV_PGRAPH_BLEND 0x00400824 /* RW-4R */
-#define NV_PGRAPH_DPRAM_INDEX 0x00400828 /* RW-4R */
-#define NV_PGRAPH_DPRAM_INDEX_ADRS 6:0 /* RWIVF */
-#define NV_PGRAPH_DPRAM_INDEX_ADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT 10:8 /* RWIVF */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_0 0x00000000 /* RWI-V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ADRS_1 0x00000001 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_0 0x00000002 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_DATA_1 0x00000003 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_0 0x00000004 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_WE_1 0x00000005 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_0 0x00000006 /* RW--V */
-#define NV_PGRAPH_DPRAM_INDEX_SELECT_ALPHA_1 0x00000007 /* RW--V */
-#define NV_PGRAPH_DPRAM_DATA 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_DATA_VALUE 31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ADRS_0 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ADRS_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_ADRS_0_VALUE 19:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ADRS_1 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ADRS_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_ADRS_1_VALUE 19:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_DATA_0 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_DATA_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_DATA_0_VALUE 31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_DATA_1 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_DATA_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_DATA_1_VALUE 31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_WE_0 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_WE_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_WE_0_VALUE 23:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_WE_1 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_WE_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_WE_1_VALUE 23:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ALPHA_0 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ALPHA_0__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_ALPHA_0_VALUE 31:0 /* RWXVF */
-#define NV_PGRAPH_DPRAM_ALPHA_1 0x0040082c /* RW-4R */
-#define NV_PGRAPH_DPRAM_ALPHA_1__ALIAS_1 NV_PGRAPH_DPRAM_DATA /* */
-#define NV_PGRAPH_DPRAM_ALPHA_1_VALUE 31:0 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT 0x00400830 /* RW-4R */
-#define NV_PGRAPH_STORED_FMT_MONO0 5:0 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT_PATT0 13:8 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT_PATT1 21:16 /* RWXVF */
-#define NV_PGRAPH_STORED_FMT_CHROMA 29:24 /* RWXVF */
-#define NV_PGRAPH_FORMATS 0x00400618 /* RW-4R */
-#define NV_PGRAPH_FORMATS_ROP 2:0 /* R-XVF */
-#define NV_PGRAPH_FORMATS_ROP_Y8 0x00000000 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB15 0x00000001 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB16 0x00000002 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_Y16 0x00000003 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_INVALID 0x00000004 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB24 0x00000005 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_RGB30 0x00000006 /* -W--V */
-#define NV_PGRAPH_FORMATS_ROP_Y32 0x00000007 /* -W--V */
-#define NV_PGRAPH_FORMATS_SRC 9:4 /* R-XVF */
-#define NV_PGRAPH_FORMATS_SRC_INVALID 0x00000000 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16A8Y8 0x00000002 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X24Y8 0x00000003 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A1R5G5B5 0x00000006 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X1R5G5B5 0x00000007 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16A1R5G5B5 0x00000008 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X17R5G5B5 0x00000009 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_R5G6B5 0x0000000A /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A16R5G6B5 0x0000000B /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16R5G6B5 0x0000000C /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A8R8G8B8 0x0000000D /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X8R8G8B8 0x0000000E /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_Y16 0x0000000F /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_A16Y16 0x00000010 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_X16Y16 0x00000011 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_V8YB8U8YA8 0x00000012 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_YB8V8YA8U8 0x00000013 /* RW--V */
-#define NV_PGRAPH_FORMATS_SRC_LE_Y32 0x00000014 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB 15:12 /* R-XVF */
-#define NV_PGRAPH_FORMATS_FB_INVALID 0x00000000 /* RWI-V */
-#define NV_PGRAPH_FORMATS_FB_Y8 0x00000001 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_Z1R5G5B5 0x00000002 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1R5G5B5_O1R5G5B5 0x00000003 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_A1R5G5B5 0x00000004 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_R5G6B5 0x00000005 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_Y16 0x00000006 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_Z8R8G8B8 0x00000007 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O1Z7R8G8B8 0x00000008 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_Z1A7R8G8B8 0x00000009 /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X1A7R8G8B8_O1A7R8G8B8 0x0000000a /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_X8R8G8B8_O8R8G8B8 0x0000000b /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_A8R8G8B8 0x0000000c /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_Y32 0x0000000d /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_V8YB8U8YA8 0x0000000e /* RW--V */
-#define NV_PGRAPH_FORMATS_FB_YB8V8YA8U8 0x0000000f /* RW--V */
-#define NV_PGRAPH_ABS_X_RAM(i) (0x00400400+(i)*4) /* RW-4A */
-#define NV_PGRAPH_ABS_X_RAM__SIZE_1 32 /* */
-#define NV_PGRAPH_ABS_X_RAM_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_X_RAM_BPORT(i) (0x00400c00+(i)*4) /* R--4A */
-#define NV_PGRAPH_X_RAM_BPORT__SIZE_1 32 /* */
-#define NV_PGRAPH_X_RAM_BPORT_VALUE 31:0 /* R--UF */
-#define NV_PGRAPH_ABS_Y_RAM(i) (0x00400480+(i)*4) /* RW-4A */
-#define NV_PGRAPH_ABS_Y_RAM__SIZE_1 32 /* */
-#define NV_PGRAPH_ABS_Y_RAM_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_Y_RAM_BPORT(i) (0x00400c80+(i)*4) /* R--4A */
-#define NV_PGRAPH_Y_RAM_BPORT__SIZE_1 32 /* */
-#define NV_PGRAPH_Y_RAM_BPORT_VALUE 31:0 /* R--UF */
-#define NV_PGRAPH_XY_LOGIC_MISC0 0x00400514 /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER 17:0 /* RWBUF */
-#define NV_PGRAPH_XY_LOGIC_MISC0_COUNTER_0 0x00000000 /* RWB-V */
-#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION 20:20 /* RWVVF */
-#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_NONZERO 0x00000000 /* RWV-V */
-#define NV_PGRAPH_XY_LOGIC_MISC0_DIMENSION_ZERO 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX 31:28 /* RWBUF */
-#define NV_PGRAPH_XY_LOGIC_MISC0_INDEX_0 0x00000000 /* RWB-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1 0x00400518 /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL 0:0 /* RWNVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_NEEDED 0x00000000 /* RWN-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_INITIAL_DONE 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX 4:4 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NOTNULL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPX_NULL 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY 5:5 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NOTNULL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_XTRACLIPY_NULL 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX 12:12 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_UUMAX 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XIMAX_IMAGEMAX 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX 16:16 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_UUMAX 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_YIMAX_IMAGEMAX 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA 20:20 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_CLIPMAX 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC1_SEL_XXTRA_IMAGEMAX 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2 0x0040051C /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF 0:0 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_DISABLE 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_HANDOFF_ENABLE 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX 4:4 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NOTNULL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPX_NULL 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY 5:5 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NOTNULL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_XTRACLIPY_NULL 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX 12:12 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_UCMAX 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XIMAX_IMAGEMAX 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX 16:16 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_UCMAX 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_YIMAX_IMAGEMAX 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA 20:20 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_CLIPMAX 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC2_SEL_XXTRA_IMAGEMAX 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3 0x00400520 /* RW-4R */
-#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0 0:0 /* RWXVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_NULL 0x00000000 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_WDIMY_EQ_0_TRUE 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY 4:4 /* RWXVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_NULL 0x00000000 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WDIMY_TRUE 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX 8:8 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_NULL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_RELOAD_WX_TRUE 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG 12:12 /* RWIVF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_NULL 0x00000000 /* RWI-V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_ALG_TRUE 0x00000001 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX 22:16 /* RWXUF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_DIMX_0 0x00000000 /* RW--V */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX 30:24 /* RWXUF */
-#define NV_PGRAPH_XY_LOGIC_MISC3_TEXT_WDIMX_0 0x00000000 /* RW--V */
-#define NV_PGRAPH_X_MISC 0x00400500 /* RW-4R */
-#define NV_PGRAPH_X_MISC_BIT33_0 0:0 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_0_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_BIT33_1 1:1 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_1_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_BIT33_2 2:2 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_2_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_BIT33_3 3:3 /* RWNVF */
-#define NV_PGRAPH_X_MISC_BIT33_3_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_0 4:4 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_0_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_1 5:5 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_1_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_2 6:6 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_2_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_RANGE_3 7:7 /* RWNVF */
-#define NV_PGRAPH_X_MISC_RANGE_3_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT 29:28 /* RWXVF */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_EQ_0 0x00000000 /* RW--V */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_LT_0 0x00000001 /* RW--V */
-#define NV_PGRAPH_X_MISC_ADDER_OUTPUT_GT_0 0x00000002 /* RW--V */
-#define NV_PGRAPH_Y_MISC 0x00400504 /* RW-4R */
-#define NV_PGRAPH_Y_MISC_BIT33_0 0:0 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_0_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_BIT33_1 1:1 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_1_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_BIT33_2 2:2 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_2_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_BIT33_3 3:3 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_BIT33_3_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_0 4:4 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_0_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_1 5:5 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_1_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_2 6:6 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_2_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_RANGE_3 7:7 /* RWNVF */
-#define NV_PGRAPH_Y_MISC_RANGE_3_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT 29:28 /* RWXVF */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_EQ_0 0x00000000 /* RW--V */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_LT_0 0x00000001 /* RW--V */
-#define NV_PGRAPH_Y_MISC_ADDER_OUTPUT_GT_0 0x00000002 /* RW--V */
-#define NV_PGRAPH_ABS_UCLIP_XMIN 0x0040053C /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_XMIN_VALUE 15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIP_XMAX 0x00400544 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_XMAX_VALUE 17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIP_YMIN 0x00400540 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_YMIN_VALUE 15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIP_YMAX 0x00400548 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIP_YMAX_VALUE 17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_XMIN 0x00400560 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_XMIN_VALUE 15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_XMAX 0x00400568 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_XMAX_VALUE 17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_YMIN 0x00400564 /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_YMIN_VALUE 15:0 /* RWXSF */
-#define NV_PGRAPH_ABS_UCLIPA_YMAX 0x0040056C /* RW-4R */
-#define NV_PGRAPH_ABS_UCLIPA_YMAX_VALUE 17:0 /* RWXSF */
-#define NV_PGRAPH_SOURCE_COLOR 0x0040050C /* RW-4R */
-#define NV_PGRAPH_SOURCE_COLOR_VALUE 31:0 /* RWNVF */
-#define NV_PGRAPH_SOURCE_COLOR_VALUE_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_VALID1 0x00400508 /* RW-4R */
-#define NV_PGRAPH_VALID1_VLD 22:0 /* RWNVF */
-#define NV_PGRAPH_VALID1_VLD_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_VALID1_CLIP_MIN 28:28 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIP_MIN_NO_ERROR 0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIP_MIN_ONLY 0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID1_CLIPA_MIN 29:29 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIPA_MIN_NO_ERROR 0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIPA_MIN_ONLY 0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID1_CLIP_MAX 30:30 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIP_MAX_NO_ERROR 0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIP_MAX_ONLY 0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID1_CLIPA_MAX 31:31 /* RWIVF */
-#define NV_PGRAPH_VALID1_CLIPA_MAX_NO_ERROR 0x00000000 /* RWI-V */
-#define NV_PGRAPH_VALID1_CLIPA_MAX_ONLY 0x00000001 /* RW--V */
-#define NV_PGRAPH_VALID2 0x00400578 /* RW-4R */
-#define NV_PGRAPH_VALID2_VLD2 28:0 /* RWNVF */
-#define NV_PGRAPH_VALID2_VLD2_0 0x00000000 /* RWN-V */
-#define NV_PGRAPH_ABS_ICLIP_XMAX 0x00400534 /* RW-4R */
-#define NV_PGRAPH_ABS_ICLIP_XMAX_VALUE 17:0 /* RWXSF */
-#define NV_PGRAPH_ABS_ICLIP_YMAX 0x00400538 /* RW-4R */
-#define NV_PGRAPH_ABS_ICLIP_YMAX_VALUE 17:0 /* RWXSF */
-#define NV_PGRAPH_CLIPX_0 0x00400524 /* RW-4R */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN 1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX 3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP0_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN 5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX 7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP1_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN 9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX 11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP2_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN 13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX 15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP3_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN 17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX 19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP4_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN 21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX 23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP5_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN 25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX 27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP6_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN 29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX 31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_0_CLIP7_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1 0x00400528 /* RW-4R */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN 1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX 3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP8_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN 5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX 7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP9_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN 9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX 11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP10_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MIN 13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP11MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX 15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP11_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN 17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX 19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP12_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN 21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX 23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP13_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN 25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX 27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP14_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN 29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX 31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPX_1_CLIP15_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0 0x0040052c /* RW-4R */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN 1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX 3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP0_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN 5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX 7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP1_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN 9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX 11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP2_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN 13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX 15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP3_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN 17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX 19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP4_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN 21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX 23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP5_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN 25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX 27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP6_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN 29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX 31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_0_CLIP7_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1 0x00400530 /* RW-4R */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN 1:0 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX 3:2 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP8_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN 5:4 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX 7:6 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP9_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN 9:8 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX 11:10 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP10_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MIN 13:12 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP11MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX 15:14 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP11_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN 17:16 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX 19:18 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP12_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN 21:20 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX 23:22 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP13_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN 25:24 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX 27:26 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP14_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN 29:28 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_GT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_LT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MIN_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX 31:30 /* RWNVF */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_LT 0x00000000 /* RW--V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_GT 0x00000001 /* RWN-V */
-#define NV_PGRAPH_CLIPY_1_CLIP15_MAX_EQ 0x00000002 /* RW--V */
-#define NV_PGRAPH_MISC24_0 0x00400510 /* RW-4R */
-#define NV_PGRAPH_MISC24_0_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_MISC24_1 0x00400570 /* RW-4R */
-#define NV_PGRAPH_MISC24_1_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_MISC24_2 0x00400574 /* RW-4R */
-#define NV_PGRAPH_MISC24_2_VALUE 23:0 /* RWXUF */
-#define NV_PGRAPH_PASSTHRU_0 0x0040057C /* RW-4R */
-#define NV_PGRAPH_PASSTHRU_0_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_PASSTHRU_1 0x00400580 /* RW-4R */
-#define NV_PGRAPH_PASSTHRU_1_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_PASSTHRU_2 0x00400584 /* RW-4R */
-#define NV_PGRAPH_PASSTHRU_2_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_U_RAM(i) (0x00400d00+(i)*4) /* RW-4A */
-#define NV_PGRAPH_U_RAM__SIZE_1 16 /* */
-#define NV_PGRAPH_U_RAM_VALUE 31:6 /* RWXFF */
-#define NV_PGRAPH_V_RAM(i) (0x00400d40+(i)*4) /* RW-4A */
-#define NV_PGRAPH_V_RAM__SIZE_1 16 /* */
-#define NV_PGRAPH_V_RAM_VALUE 31:6 /* RWXFF */
-#define NV_PGRAPH_M_RAM(i) (0x00400d80+(i)*4) /* RW-4A */
-#define NV_PGRAPH_M_RAM__SIZE_1 16 /* */
-#define NV_PGRAPH_M_RAM_VALUE 31:6 /* RWXFF */
-#define NV_PGRAPH_DMA_START_0 0x00401000 /* RW-4R */
-#define NV_PGRAPH_DMA_START_0_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_START_1 0x00401004 /* RW-4R */
-#define NV_PGRAPH_DMA_START_1_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_LENGTH 0x00401008 /* RW-4R */
-#define NV_PGRAPH_DMA_LENGTH_VALUE 21:0 /* RWXUF */
-#define NV_PGRAPH_DMA_MISC 0x0040100C /* RW-4R */
-#define NV_PGRAPH_DMA_MISC_COUNT 15:0 /* RWXUF */
-#define NV_PGRAPH_DMA_MISC_FMT_SRC 18:16 /* RWXVF */
-#define NV_PGRAPH_DMA_MISC_FMT_DST 22:20 /* RWXVF */
-#define NV_PGRAPH_DMA_DATA_0 0x00401020 /* RW-4R */
-#define NV_PGRAPH_DMA_DATA_0_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_DATA_1 0x00401024 /* RW-4R */
-#define NV_PGRAPH_DMA_DATA_1_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_RM 0x00401030 /* RW-4R */
-#define NV_PGRAPH_DMA_RM_ASSIST_A 0:0 /* RWIVF */
-#define NV_PGRAPH_DMA_RM_ASSIST_A_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_DMA_RM_ASSIST_A_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_DMA_RM_ASSIST_A_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_DMA_RM_ASSIST_B 1:1 /* RWIVF */
-#define NV_PGRAPH_DMA_RM_ASSIST_B_NOT_PENDING 0x00000000 /* R-I-V */
-#define NV_PGRAPH_DMA_RM_ASSIST_B_PENDING 0x00000001 /* R---V */
-#define NV_PGRAPH_DMA_RM_ASSIST_B_RESET 0x00000001 /* -W--C */
-#define NV_PGRAPH_DMA_RM_WRITE_REQ 4:4 /* CWIVF */
-#define NV_PGRAPH_DMA_RM_WRITE_REQ_NOT_PENDING 0x00000000 /* CWI-V */
-#define NV_PGRAPH_DMA_RM_WRITE_REQ_PENDING 0x00000001 /* -W--T */
-#define NV_PGRAPH_DMA_A_XLATE_INST 0x00401040 /* RW-4R */
-#define NV_PGRAPH_DMA_A_XLATE_INST_VALUE 15:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_CONTROL 0x00401044 /* RW-4R */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE 12:12 /* RWIVF */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_NOT_PRESENT 0x00000000 /* RWI-V */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_TABLE_PRESENT 0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY 13:13 /* RWXVF */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_NOT_LINEAR 0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_PAGE_ENTRY_LINEAR 0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE 17:16 /* RWXUF */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_NVM 0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_PCI 0x00000002 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_TARGET_NODE_AGP 0x00000003 /* RW--V */
-#define NV_PGRAPH_DMA_A_CONTROL_ADJUST 31:20 /* RWXUF */
-#define NV_PGRAPH_DMA_A_LIMIT 0x00401048 /* RW-4R */
-#define NV_PGRAPH_DMA_A_LIMIT_OFFSET 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_TLB_PTE 0x0040104C /* RW-4R */
-#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS 1:1 /* RWXVF */
-#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_ONLY 0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_A_TLB_PTE_ACCESS_READ_WRITE 0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_A_TLB_PTE_FRAME_ADDRESS 31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_A_TLB_TAG 0x00401050 /* RW-4R */
-#define NV_PGRAPH_DMA_A_TLB_TAG_ADDRESS 31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_A_ADJ_OFFSET 0x00401054 /* RW-4R */
-#define NV_PGRAPH_DMA_A_ADJ_OFFSET_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_OFFSET 0x00401058 /* RW-4R */
-#define NV_PGRAPH_DMA_A_OFFSET_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_SIZE 0x0040105C /* RW-4R */
-#define NV_PGRAPH_DMA_A_SIZE_VALUE 24:0 /* RWXUF */
-#define NV_PGRAPH_DMA_A_Y_SIZE 0x00401060 /* RW-4R */
-#define NV_PGRAPH_DMA_A_Y_SIZE_VALUE 10:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_XLATE_INST 0x00401080 /* RW-4R */
-#define NV_PGRAPH_DMA_B_XLATE_INST_VALUE 15:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_CONTROL 0x00401084 /* RW-4R */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE 12:12 /* RWIVF */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_NOT_PRESENT 0x00000000 /* RWI-V */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_TABLE_PRESENT 0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY 13:13 /* RWXVF */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_NOT_LINEAR 0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_PAGE_ENTRY_LINEAR 0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE 17:16 /* RWXUF */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_NVM 0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_PCI 0x00000002 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_TARGET_NODE_AGP 0x00000003 /* RW--V */
-#define NV_PGRAPH_DMA_B_CONTROL_ADJUST 31:20 /* RWXUF */
-#define NV_PGRAPH_DMA_B_LIMIT 0x00401088 /* RW-4R */
-#define NV_PGRAPH_DMA_B_LIMIT_OFFSET 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_TLB_PTE 0x0040108C /* RW-4R */
-#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS 1:1 /* RWXVF */
-#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_ONLY 0x00000000 /* RW--V */
-#define NV_PGRAPH_DMA_B_TLB_PTE_ACCESS_READ_WRITE 0x00000001 /* RW--V */
-#define NV_PGRAPH_DMA_B_TLB_PTE_FRAME_ADDRESS 31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_B_TLB_TAG 0x00401090 /* RW-4R */
-#define NV_PGRAPH_DMA_B_TLB_TAG_ADDRESS 31:12 /* RWXUF */
-#define NV_PGRAPH_DMA_B_ADJ_OFFSET 0x00401094 /* RW-4R */
-#define NV_PGRAPH_DMA_B_ADJ_OFFSET_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_OFFSET 0x00401098 /* RW-4R */
-#define NV_PGRAPH_DMA_B_OFFSET_VALUE 31:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_SIZE 0x0040109C /* RW-4R */
-#define NV_PGRAPH_DMA_B_SIZE_VALUE 24:0 /* RWXUF */
-#define NV_PGRAPH_DMA_B_Y_SIZE 0x004010A0 /* RW-4R */
-#define NV_PGRAPH_DMA_B_Y_SIZE_VALUE 10:0 /* RWXUF */
-
-/* Framebuffer registers */
-#define NV_PFB 0x00100FFF:0x00100000 /* RW--D */
-#define NV_PFB_BOOT_0 0x00100000 /* RW-4R */
-#define NV_PFB_BOOT_0_RAM_AMOUNT 1:0 /* RW-VF */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_WIDTH_128 2:2 /* RW-VF */
-#define NV_PFB_BOOT_0_RAM_WIDTH_128_OFF 0x00000000 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_WIDTH_128_ON 0x00000001 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE 4:3 /* RW-VF */
-#define NV_PFB_BOOT_0_RAM_TYPE_256K 0x00000000 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE_512K_2BANK 0x00000001 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE_512K_4BANK 0x00000002 /* RW--V */
-#define NV_PFB_BOOT_0_RAM_TYPE_1024K_2BANK 0x00000003 /* RW--V */
-#define NV_PFB_CONFIG_0 0x00100200 /* RW-4R */
-#define NV_PFB_CONFIG_0_TYPE 14:0 /* RWIVF */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_8BPP 0x00000120 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_16BPP 0x00000220 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_FIXED_32BPP 0x00000320 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_8BPP 0x00004120 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_16BPP 0x00004220 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_OLD1024_VAR_32BPP 0x00004320 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_TETRIS 0x00002000 /* RW--V */
-#define NV_PFB_CONFIG_0_TYPE_NOTILING 0x00001114 /* RWI-V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE 17:15 /* RWI-F */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_PASS 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_1 0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_2 0x00000002 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_3 0x00000003 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_4 0x00000004 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_5 0x00000005 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_6 0x00000006 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_MODE_7 0x00000007 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT 19:18 /* RWI-F */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT_0 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT_1 0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_TETRIS_SHIFT_2 0x00000002 /* RW--V */
-#define NV_PFB_CONFIG_0_BANK_SWAP 22:20 /* RWI-F */
-#define NV_PFB_CONFIG_0_BANK_SWAP_OFF 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_BANK_SWAP_1M 0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_BANK_SWAP_2M 0x00000005 /* RW--V */
-#define NV_PFB_CONFIG_0_BANK_SWAP_4M 0x00000007 /* RW--V */
-#define NV_PFB_CONFIG_0_UNUSED 23:23 /* RW-VF */
-#define NV_PFB_CONFIG_0_SCRAMBLE_EN 29:29 /* RWIVF */
-#define NV_PFB_CONFIG_0_SCRAMBLE_EN_INIT 0x00000000 /* RW--V */
-#define NV_PFB_CONFIG_0_SCRAMBLE_ACTIVE 0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR 28:28 /* RWIVF */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_INIT 0x00000000 /* RW--V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_DISABLED 0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK 27:24 /* RWIVF */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_INIT 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_PRAMIN_WR_MASK_CLEAR 0x0000000f /* RWI-V */
-#define NV_PFB_CONFIG_1 0x00100204 /* RW-4R */
-#define NV_PFB_RTL 0x00100300 /* RW-4R */
-#define NV_PFB_RTL_H 0:0 /* RWIUF */
-#define NV_PFB_RTL_H_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PFB_RTL_MC 1:1 /* RWIUF */
-#define NV_PFB_RTL_MC_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PFB_RTL_V 2:2 /* RWIUF */
-#define NV_PFB_RTL_V_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PFB_RTL_G 3:3 /* RWIUF */
-#define NV_PFB_RTL_G_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PFB_RTL_GB 4:4 /* RWIUF */
-#define NV_PFB_RTL_GB_DEFAULT 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_0_RESOLUTION 5:0 /* RWIVF */
-#define NV_PFB_CONFIG_0_RESOLUTION_320_PIXELS 0x0000000a /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_400_PIXELS 0x0000000d /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_480_PIXELS 0x0000000f /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_512_PIXELS 0x00000010 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_640_PIXELS 0x00000014 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_800_PIXELS 0x00000019 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_960_PIXELS 0x0000001e /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1024_PIXELS 0x00000020 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1152_PIXELS 0x00000024 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1280_PIXELS 0x00000028 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_1600_PIXELS 0x00000032 /* RW--V */
-#define NV_PFB_CONFIG_0_RESOLUTION_DEFAULT 0x00000014 /* RWI-V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH 9:8 /* RWIVF */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_8_BITS 0x00000001 /* RW--V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_16_BITS 0x00000002 /* RW--V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_32_BITS 0x00000003 /* RW--V */
-#define NV_PFB_CONFIG_0_PIXEL_DEPTH_DEFAULT 0x00000001 /* RWI-V */
-#define NV_PFB_CONFIG_0_TILING 12:12 /* RWIVF */
-#define NV_PFB_CONFIG_0_TILING_ENABLED 0x00000000 /* RW--V */
-#define NV_PFB_CONFIG_0_TILING_DISABLED 0x00000001 /* RWI-V */
-#define NV_PFB_CONFIG_1_SGRAM100 3:3 /* RWIVF */
-#define NV_PFB_CONFIG_1_SGRAM100_ENABLED 0x00000000 /* RWI-V */
-#define NV_PFB_CONFIG_1_SGRAM100_DISABLED 0x00000001 /* RW--V */
-#define NV_PFB_DEBUG_0_CKE_ALWAYSON 29:29 /* RWIVF */
-#define NV_PFB_DEBUG_0_CKE_ALWAYSON_OFF 0x00000000 /* RW--V */
-#define NV_PFB_DEBUG_0_CKE_ALWAYSON_ON 0x00000001 /* RWI-V */
-
-#define NV_PEXTDEV 0x00101FFF:0x00101000 /* RW--D */
-#define NV_PEXTDEV_BOOT_0 0x00101000 /* R--4R */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED 0:0 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_33MHZ 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_SPEED_66MHZ 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR 1:1 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_NO_BIOS 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_SUB_VENDOR_BIOS 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE 3:2 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_256K 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_2BANK 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_SGRAM_512K_4BANK 0x00000002 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_TYPE_1024K_2BANK 0x00000003 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH 4:4 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_64 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_RAM_WIDTH_128 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE 5:5 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_PCI 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_BUS_TYPE_AGP 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL 6:6 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_13500K 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_CRYSTAL_14318180 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE 8:7 /* R-XVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_SECAM 0x00000000 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_NTSC 0x00000001 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_PAL 0x00000002 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_TVMODE_DISABLED 0x00000003 /* R---V */
-#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE 11:11 /* RWIVF */
-#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_DISABLED 0x00000000 /* RWI-V */
-#define NV_PEXTDEV_BOOT_0_STRAP_OVERWRITE_ENABLED 0x00000001 /* RW--V */
-
-/* Extras */
-#define NV_PRAMIN 0x007FFFFF:0x00700000 /* RW--M */
-/*#define NV_PRAMIN 0x00FFFFFF:0x00C00000*/
-#define NV_PNVM 0x01FFFFFF:0x01000000 /* RW--M */
-/*#define NV_PNVM 0x00BFFFFF:0x00800000*/
-#define NV_CHAN0 0x0080ffff:0x00800000
-
-/* FIFO subchannels */
-#define NV_UROP 0x43
-#define NV_UCHROMA 0x57
-#define NV_UCLIP 0x19
-#define NV_UPATT 0x18
-#define NV_ULIN 0x5C
-#define NV_UTRI 0x5D
-#define NV_URECT 0x5E
-#define NV_UBLIT 0x5F
-#define NV_UGLYPH 0x4B
-
-#endif /*__NV4REF_H__*/
-
diff --git a/drivers/video/riva/nv_driver.c b/drivers/video/riva/nv_driver.c
index be630a0ccfd..a11026812d1 100644
--- a/drivers/video/riva/nv_driver.c
+++ b/drivers/video/riva/nv_driver.c
@@ -231,12 +231,14 @@ unsigned long riva_get_memlen(struct riva_par *par)
case NV_ARCH_30:
if(chipset == NV_CHIP_IGEFORCE2) {
- dev = pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
pci_read_config_dword(dev, 0x7C, &amt);
+ pci_dev_put(dev);
memlen = (((amt >> 6) & 31) + 1) * 1024;
} else if (chipset == NV_CHIP_0x01F0) {
- dev = pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
pci_read_config_dword(dev, 0x84, &amt);
+ pci_dev_put(dev);
memlen = (((amt >> 4) & 127) + 1) * 1024;
} else {
switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) &
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
index e0b8c521cc9..70bfd78eca8 100644
--- a/drivers/video/riva/riva_hw.c
+++ b/drivers/video/riva/riva_hw.c
@@ -1118,8 +1118,9 @@ static void nForceUpdateArbitrationSettings
unsigned int uMClkPostDiv;
struct pci_dev *dev;
- dev = pci_find_slot(0, 3);
+ dev = pci_get_bus_and_slot(0, 3);
pci_read_config_dword(dev, 0x6C, &uMClkPostDiv);
+ pci_dev_put(dev);
uMClkPostDiv = (uMClkPostDiv >> 8) & 0xf;
if(!uMClkPostDiv) uMClkPostDiv = 4;
@@ -1132,8 +1133,9 @@ static void nForceUpdateArbitrationSettings
sim_data.enable_video = 0;
sim_data.enable_mp = 0;
- dev = pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
pci_read_config_dword(dev, 0x7C, &sim_data.memory_type);
+ pci_dev_put(dev);
sim_data.memory_type = (sim_data.memory_type >> 12) & 1;
sim_data.memory_width = 64;
@@ -2112,12 +2114,14 @@ static void nv10GetConfig
* Fill in chip configuration.
*/
if(chipset == NV_CHIP_IGEFORCE2) {
- dev = pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
pci_read_config_dword(dev, 0x7C, &amt);
+ pci_dev_put(dev);
chip->RamAmountKBytes = (((amt >> 6) & 31) + 1) * 1024;
} else if(chipset == NV_CHIP_0x01F0) {
- dev = pci_find_slot(0, 1);
+ dev = pci_get_bus_and_slot(0, 1);
pci_read_config_dword(dev, 0x84, &amt);
+ pci_dev_put(dev);
chip->RamAmountKBytes = (((amt >> 4) & 127) + 1) * 1024;
} else {
switch ((NV_RD32(chip->PFB, 0x0000020C) >> 20) & 0x000000FF)
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 0405e839ff9..76e6ce353c8 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -88,13 +88,16 @@ static int riva_gpio_getsda(void* data)
return val;
}
-static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name)
+static int __devinit riva_setup_i2c_bus(struct riva_i2c_chan *chan,
+ const char *name,
+ unsigned int i2c_class)
{
int rc;
strcpy(chan->adapter.name, name);
chan->adapter.owner = THIS_MODULE;
chan->adapter.id = I2C_HW_B_RIVA;
+ chan->adapter.class = i2c_class;
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pdev->dev;
chan->algo.setsda = riva_gpio_setsda;
@@ -124,42 +127,38 @@ static int riva_setup_i2c_bus(struct riva_i2c_chan *chan, const char *name)
return rc;
}
-void riva_create_i2c_busses(struct riva_par *par)
+void __devinit riva_create_i2c_busses(struct riva_par *par)
{
- par->bus = 3;
-
par->chan[0].par = par;
par->chan[1].par = par;
par->chan[2].par = par;
- par->chan[0].ddc_base = 0x3e;
- par->chan[1].ddc_base = 0x36;
+ par->chan[0].ddc_base = 0x36;
+ par->chan[1].ddc_base = 0x3e;
par->chan[2].ddc_base = 0x50;
- riva_setup_i2c_bus(&par->chan[0], "BUS1");
- riva_setup_i2c_bus(&par->chan[1], "BUS2");
- riva_setup_i2c_bus(&par->chan[2], "BUS3");
+ riva_setup_i2c_bus(&par->chan[0], "BUS1", I2C_CLASS_HWMON);
+ riva_setup_i2c_bus(&par->chan[1], "BUS2", 0);
+ riva_setup_i2c_bus(&par->chan[2], "BUS3", 0);
}
void riva_delete_i2c_busses(struct riva_par *par)
{
- if (par->chan[0].par)
- i2c_del_adapter(&par->chan[0].adapter);
- par->chan[0].par = NULL;
-
- if (par->chan[1].par)
- i2c_del_adapter(&par->chan[1].adapter);
- par->chan[1].par = NULL;
+ int i;
- if (par->chan[2].par)
- i2c_del_adapter(&par->chan[2].adapter);
- par->chan[2].par = NULL;
+ for (i = 0; i < 3; i++) {
+ if (!par->chan[i].par)
+ continue;
+ i2c_del_adapter(&par->chan[i].adapter);
+ par->chan[i].par = NULL;
+ }
}
-int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
+int __devinit riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
{
u8 *edid = NULL;
- edid = fb_ddc_read(&par->chan[conn-1].adapter);
+ if (par->chan[conn].par)
+ edid = fb_ddc_read(&par->chan[conn].adapter);
if (out_edid)
*out_edid = edid;
diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h
index 48ead6d72f2..d9f107b704c 100644
--- a/drivers/video/riva/rivafb.h
+++ b/drivers/video/riva/rivafb.h
@@ -4,7 +4,6 @@
#include <linux/fb.h>
#include <video/vga.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
#include "riva_hw.h"
@@ -61,7 +60,6 @@ struct riva_par {
Bool SecondCRTC;
int FlatPanel;
struct pci_dev *pdev;
- int bus;
int cursor_reset;
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c
index 3091b20124b..d11735895a0 100644
--- a/drivers/video/s3fb.c
+++ b/drivers/video/s3fb.c
@@ -65,7 +65,7 @@ static const struct svga_fb_format s3fb_formats[] = {
static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3,
- 60000, 240000, 14318};
+ 35000, 240000, 14318};
static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512};
@@ -164,7 +164,7 @@ MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, defau
static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
{
const u8 *font = map->data;
- u8* fb = (u8 *) info->screen_base;
+ u8 __iomem *fb = (u8 __iomem *) info->screen_base;
int i, c;
if ((map->width != 8) || (map->height != 16) ||
@@ -177,20 +177,19 @@ static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
fb += 2;
for (i = 0; i < map->height; i++) {
for (c = 0; c < map->length; c++) {
- fb[c * 4] = font[c * map->height + i];
+ fb_writeb(font[c * map->height + i], fb + c * 4);
}
fb += 1024;
}
}
-
-
static struct fb_tile_ops s3fb_tile_ops = {
.fb_settile = svga_settile,
.fb_tilecopy = svga_tilecopy,
.fb_tilefill = svga_tilefill,
.fb_tileblit = svga_tileblit,
.fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
};
static struct fb_tile_ops s3fb_fast_tile_ops = {
@@ -199,6 +198,7 @@ static struct fb_tile_ops s3fb_fast_tile_ops = {
.fb_tilefill = svga_tilefill,
.fb_tileblit = svga_tileblit,
.fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
};
@@ -326,8 +326,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
{
u16 m, n, r;
u8 regval;
+ int rv;
- svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+ rv = svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
/* Set VGA misc register */
regval = vga_r(NULL, VGA_MIS_R);
@@ -449,6 +454,10 @@ static int s3fb_set_par(struct fb_info *info)
info->flags &= ~FBINFO_MISC_TILEBLITTING;
info->tileops = NULL;
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
offset_value = (info->var.xres_virtual * bpp) / 64;
screen_size = info->var.yres_virtual * info->fix.line_length;
} else {
@@ -458,6 +467,10 @@ static int s3fb_set_par(struct fb_info *info)
info->flags |= FBINFO_MISC_TILEBLITTING;
info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops;
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
offset_value = info->var.xres_virtual / 16;
screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
}
@@ -656,7 +669,7 @@ static int s3fb_set_par(struct fb_info *info)
value = ((value * hmul) / 8) - 5;
vga_wcrt(NULL, 0x3C, (value + 1) / 2);
- memset((u8*)info->screen_base, 0x00, screen_size);
+ memset_io(info->screen_base, 0x00, screen_size);
/* Device and screen back on */
svga_wcrt_mask(0x17, 0x80, 0x80);
svga_wseq_mask(0x01, 0x00, 0x20);
@@ -699,7 +712,7 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
break;
case 16:
if (regno >= 16)
- return -EINVAL;
+ return 0;
if (fb->var.green.length == 5)
((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
@@ -712,9 +725,9 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
case 24:
case 32:
if (regno >= 16)
- return -EINVAL;
+ return 0;
- ((u32*)fb->pseudo_palette)[regno] = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) |
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
(green & 0xFF00) | ((blue & 0xFF00) >> 8);
break;
default:
@@ -767,12 +780,6 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
unsigned int offset;
- /* Validate the offsets */
- if ((var->xoffset + var->xres) > var->xres_virtual)
- return -EINVAL;
- if ((var->yoffset + var->yres) > var->yres_virtual)
- return -EINVAL;
-
/* Calculate the offset */
if (var->bits_per_pixel == 0) {
offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2);
@@ -805,6 +812,7 @@ static struct fb_ops s3fb_ops = {
.fb_fillrect = s3fb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = s3fb_imageblit,
+ .fb_get_caps = svga_get_caps,
};
/* ------------------------------------------------------------------------- */
@@ -1061,6 +1069,7 @@ static int s3_pci_resume(struct pci_dev* dev)
{
struct fb_info *info = pci_get_drvdata(dev);
struct s3fb_info *par = info->par;
+ int err;
dev_info(&(dev->dev), "resume\n");
@@ -1075,7 +1084,13 @@ static int s3_pci_resume(struct pci_dev* dev)
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- pci_enable_device(dev);
+ err = pci_enable_device(dev);
+ if (err) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ dev_err(&(dev->dev), "error %d enabling device for resume\n", err);
+ return err;
+ }
pci_set_master(dev);
s3fb_set_par(info);
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 8db066ccca6..35c1ce62b21 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -41,10 +41,6 @@
#define SAVAGE4_I2C_SCL_IN 0x00000008
#define SAVAGE4_I2C_SDA_IN 0x00000010
-#define SET_CR_IX(base, val) writeb((val), base + 0x8000 + VGA_CR_IX)
-#define SET_CR_DATA(base, val) writeb((val), base + 0x8000 + VGA_CR_DATA)
-#define GET_CR_DATA(base) readb(base + 0x8000 + VGA_CR_DATA)
-
static void savage4_gpio_setscl(void *data, int val)
{
struct savagefb_i2c_chan *chan = data;
@@ -92,15 +88,15 @@ static void prosavage_gpio_setscl(void* data, int val)
struct savagefb_i2c_chan *chan = data;
u32 r;
- SET_CR_IX(chan->ioaddr, chan->reg);
- r = GET_CR_DATA(chan->ioaddr);
+ r = VGArCR(chan->reg, chan->par);
r |= PROSAVAGE_I2C_ENAB;
if (val) {
r |= PROSAVAGE_I2C_SCL_OUT;
} else {
r &= ~PROSAVAGE_I2C_SCL_OUT;
}
- SET_CR_DATA(chan->ioaddr, r);
+
+ VGAwCR(chan->reg, r, chan->par);
}
static void prosavage_gpio_setsda(void* data, int val)
@@ -108,31 +104,29 @@ static void prosavage_gpio_setsda(void* data, int val)
struct savagefb_i2c_chan *chan = data;
unsigned int r;
- SET_CR_IX(chan->ioaddr, chan->reg);
- r = GET_CR_DATA(chan->ioaddr);
+ r = VGArCR(chan->reg, chan->par);
r |= PROSAVAGE_I2C_ENAB;
if (val) {
r |= PROSAVAGE_I2C_SDA_OUT;
} else {
r &= ~PROSAVAGE_I2C_SDA_OUT;
}
- SET_CR_DATA(chan->ioaddr, r);
+
+ VGAwCR(chan->reg, r, chan->par);
}
static int prosavage_gpio_getscl(void* data)
{
struct savagefb_i2c_chan *chan = data;
- SET_CR_IX(chan->ioaddr, chan->reg);
- return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SCL_IN));
+ return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SCL_IN) ? 1 : 0;
}
static int prosavage_gpio_getsda(void* data)
{
struct savagefb_i2c_chan *chan = data;
- SET_CR_IX(chan->ioaddr, chan->reg);
- return (0 != (GET_CR_DATA(chan->ioaddr) & PROSAVAGE_I2C_SDA_IN));
+ return (VGArCR(chan->reg, chan->par) & PROSAVAGE_I2C_SDA_IN) ? 1 : 0;
}
static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
index e648a6c0f6d..8bfdfc3c523 100644
--- a/drivers/video/savage/savagefb.h
+++ b/drivers/video/savage/savagefb.h
@@ -15,6 +15,8 @@
#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/mutex.h>
+#include <video/vga.h>
#include "../edid.h"
#ifdef SAVAGEFB_DEBUG
@@ -189,8 +191,12 @@ struct savagefb_par {
struct savagefb_i2c_chan chan;
struct savage_reg state;
struct savage_reg save;
+ struct savage_reg initial;
+ struct vgastate vgastate;
+ struct mutex open_lock;
unsigned char *edid;
u32 pseudo_palette[16];
+ u32 open_count;
int paletteEnabled;
int pm_state;
int display_type;
@@ -203,7 +209,7 @@ struct savagefb_par {
int clock[4];
int MCLK, REFCLK, LCDclk;
struct {
- u8 __iomem *vbase;
+ void __iomem *vbase;
u32 pbase;
u32 len;
#ifdef CONFIG_MTRR
@@ -212,7 +218,7 @@ struct savagefb_par {
} video;
struct {
- volatile u8 __iomem *vbase;
+ void __iomem *vbase;
u32 pbase;
u32 len;
} mmio;
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 0166ec2ccf3..3d7507ad55f 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -1623,8 +1623,46 @@ static void savagefb_restore_state(struct fb_info *info)
savagefb_blank(FB_BLANK_UNBLANK, info);
}
+static int savagefb_open(struct fb_info *info, int user)
+{
+ struct savagefb_par *par = info->par;
+
+ mutex_lock(&par->open_lock);
+
+ if (!par->open_count) {
+ memset(&par->vgastate, 0, sizeof(par->vgastate));
+ par->vgastate.flags = VGA_SAVE_CMAP | VGA_SAVE_FONTS |
+ VGA_SAVE_MODE;
+ par->vgastate.vgabase = par->mmio.vbase + 0x8000;
+ save_vga(&par->vgastate);
+ savage_get_default_par(par, &par->initial);
+ }
+
+ par->open_count++;
+ mutex_unlock(&par->open_lock);
+ return 0;
+}
+
+static int savagefb_release(struct fb_info *info, int user)
+{
+ struct savagefb_par *par = info->par;
+
+ mutex_lock(&par->open_lock);
+
+ if (par->open_count == 1) {
+ savage_set_default_par(par, &par->initial);
+ restore_vga(&par->vgastate);
+ }
+
+ par->open_count--;
+ mutex_unlock(&par->open_lock);
+ return 0;
+}
+
static struct fb_ops savagefb_ops = {
.owner = THIS_MODULE,
+ .fb_open = savagefb_open,
+ .fb_release = savagefb_release,
.fb_check_var = savagefb_check_var,
.fb_set_par = savagefb_set_par,
.fb_setcolreg = savagefb_setcolreg,
@@ -2173,6 +2211,7 @@ static int __devinit savagefb_probe(struct pci_dev* dev,
if (!info)
return -ENOMEM;
par = info->par;
+ mutex_init(&par->open_lock);
err = pci_enable_device(dev);
if (err)
goto failed_enable;
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
index d048bd39961..c1492782cb1 100644
--- a/drivers/video/sis/osdef.h
+++ b/drivers/video/sis/osdef.h
@@ -58,9 +58,6 @@
#define SIS_LINUX_KERNEL /* Linux kernel framebuffer */
#undef SIS_XORG_XF86 /* XFree86/X.org */
-#undef SIS_LINUX_KERNEL_24
-#undef SIS_LINUX_KERNEL_26
-
#ifdef OutPortByte
#undef OutPortByte
#endif
@@ -100,8 +97,6 @@
#define SIS315H
#endif
-#define SIS_LINUX_KERNEL_26
-
#if !defined(SIS300) && !defined(SIS315H)
#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
#warning sisfb will not work!
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index 7d5ee2145e2..d5e2d9c2784 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -27,11 +27,7 @@
#include <linux/version.h>
#include "osdef.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#include <video/sisfb.h>
-#else
-#include <linux/sisfb.h>
-#endif
#include "vgatypes.h"
#include "vstruct.h"
@@ -40,33 +36,17 @@
#define VER_MINOR 8
#define VER_LEVEL 9
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#include <linux/spinlock.h>
-#define SIS_PCI_GET_CLASS(a, b) pci_get_class(a, b)
-#define SIS_PCI_GET_DEVICE(a,b,c) pci_get_device(a,b,c)
-#define SIS_PCI_GET_SLOT(a,b) pci_get_slot(a,b)
-#define SIS_PCI_PUT_DEVICE(a) pci_dev_put(a)
+
#ifdef CONFIG_COMPAT
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,10)
#include <linux/ioctl32.h>
#define SIS_OLD_CONFIG_COMPAT
#else
-#include <linux/smp_lock.h>
#define SIS_NEW_CONFIG_COMPAT
#endif
#endif /* CONFIG_COMPAT */
-#else /* 2.4 */
-#define SIS_PCI_GET_CLASS(a, b) pci_find_class(a, b)
-#define SIS_PCI_GET_DEVICE(a,b,c) pci_find_device(a,b,c)
-#define SIS_PCI_GET_SLOT(a,b) pci_find_slot(a,b)
-#define SIS_PCI_PUT_DEVICE(a)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19)
-#ifdef __x86_64__ /* Shouldn't we check for CONFIG_IA32_EMULATION here? */
-#include <asm/ioctl32.h>
-#define SIS_OLD_CONFIG_COMPAT
-#endif
-#endif
-#endif /* 2.4 */
+
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
#define SIS_IOTYPE1 void __iomem
#define SIS_IOTYPE2 __iomem
@@ -498,26 +478,8 @@ struct sis_video_info {
struct fb_var_screeninfo default_var;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
struct fb_fix_screeninfo sisfb_fix;
u32 pseudo_palette[17];
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- struct display sis_disp;
- struct display_switch sisfb_sw;
- struct {
- u16 red, green, blue, pad;
- } sis_palette[256];
- union {
-#ifdef FBCON_HAS_CFB16
- u16 cfb16[16];
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cfb32[16];
-#endif
- } sis_fbcon_cmap;
-#endif
struct sisfb_monitor {
u16 hmin;
@@ -538,10 +500,6 @@ struct sis_video_info {
int mni; /* Mode number index */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- int currcon;
-#endif
-
unsigned long video_size;
unsigned long video_base;
unsigned long mmio_size;
@@ -578,9 +536,6 @@ struct sis_video_info {
int sisfb_tvplug;
int sisfb_tvstd;
int sisfb_nocrt2rate;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- int sisfb_inverse;
-#endif
u32 heapstart; /* offset */
SIS_IOTYPE1 *sisfb_heap_start; /* address */
@@ -646,9 +601,7 @@ struct sis_video_info {
int modechanged;
unsigned char modeprechange;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
u8 sisfb_lastrates[128];
-#endif
int newrom;
int haveXGIROM;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 01197d74021..a30e1e13d8b 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/string.h>
@@ -1948,7 +1947,7 @@ sisfb_get_northbridge(int basechipid)
default: return NULL;
}
for(i = 0; i < nbridgenum; i++) {
- if((pdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI,
+ if((pdev = pci_get_device(PCI_VENDOR_ID_SI,
nbridgeids[nbridgeidx+i], NULL)))
break;
}
@@ -4613,9 +4612,9 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev,
unsigned short temp;
int ret = 0;
- while((pdev = SIS_PCI_GET_CLASS(PCI_CLASS_BRIDGE_HOST, pdev))) {
+ while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) {
temp = pdev->vendor;
- SIS_PCI_PUT_DEVICE(pdev);
+ pci_dev_put(pdev);
if(temp == pcivendor) {
ret = 1;
break;
@@ -5154,24 +5153,24 @@ sisfb_post_xgi(struct pci_dev *pdev)
if(reg & 0x80) v2 |= 0x80;
v2 |= 0x01;
- if((mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
- SIS_PCI_PUT_DEVICE(mypdev);
+ if((mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0730, NULL))) {
+ pci_dev_put(mypdev);
if(((v2 & 0x06) == 2) || ((v2 & 0x06) == 4))
v2 &= 0xf9;
v2 |= 0x08;
v1 &= 0xfe;
} else {
- mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0735, NULL);
+ mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0735, NULL);
if(!mypdev)
- mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0645, NULL);
+ mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0645, NULL);
if(!mypdev)
- mypdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0650, NULL);
+ mypdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0650, NULL);
if(mypdev) {
pci_read_config_dword(mypdev, 0x94, &regd);
regd &= 0xfffffeff;
pci_write_config_dword(mypdev, 0x94, regd);
v1 &= 0xfe;
- SIS_PCI_PUT_DEVICE(mypdev);
+ pci_dev_put(mypdev);
} else if(sisfb_find_host_bridge(ivideo, pdev, PCI_VENDOR_ID_SI)) {
v1 &= 0xfe;
} else if(sisfb_find_host_bridge(ivideo, pdev, 0x1106) ||
@@ -5194,13 +5193,13 @@ sisfb_post_xgi(struct pci_dev *pdev)
if( (!(v1 & 0x02)) && (v2 & 0x30) && (regd < 0xcf) )
setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
- if((mypdev = SIS_PCI_GET_DEVICE(0x10de, 0x01e0, NULL))) {
+ if((mypdev = pci_get_device(0x10de, 0x01e0, NULL))) {
/* TODO: set CR5f &0xf1 | 0x01 for version 6570
* of nforce 2 ROM
*/
if(0)
setSISIDXREG(SISCR, 0x5f, 0xf1, 0x01);
- SIS_PCI_PUT_DEVICE(mypdev);
+ pci_dev_put(mypdev);
}
}
@@ -5236,9 +5235,9 @@ sisfb_post_xgi(struct pci_dev *pdev)
setSISIDXREG(SISCR, 0x75, 0xe0, bios[0x4ff] & 0x1f);
setSISIDXREG(SISCR, 0x76, 0xe0, bios[0x500] & 0x1f);
v1 = bios[0x501];
- if((mypdev = SIS_PCI_GET_DEVICE(0x8086, 0x2530, NULL))) {
+ if((mypdev = pci_get_device(0x8086, 0x2530, NULL))) {
v1 = 0xf0;
- SIS_PCI_PUT_DEVICE(mypdev);
+ pci_dev_put(mypdev);
}
outSISIDXREG(SISCR, 0x77, v1);
}
@@ -5947,7 +5946,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if(!ivideo->sisvga_enabled) {
if(pci_enable_device(pdev)) {
- if(ivideo->nbridge) SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+ if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
pci_set_drvdata(pdev, NULL);
kfree(sis_fb_info);
return -EIO;
@@ -5974,7 +5973,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
"requiring Chrontel/GPIO setup\n",
mychswtable[i].vendorName,
mychswtable[i].cardName);
- ivideo->lpcdev = SIS_PCI_GET_DEVICE(PCI_VENDOR_ID_SI, 0x0008, NULL);
+ ivideo->lpcdev = pci_get_device(PCI_VENDOR_ID_SI, 0x0008, NULL);
break;
}
i++;
@@ -5984,7 +5983,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_FB_SIS_315
if((ivideo->chip == SIS_760) && (ivideo->nbridge)) {
- ivideo->lpcdev = SIS_PCI_GET_SLOT(ivideo->nbridge->bus, (2 << 3));
+ ivideo->lpcdev = pci_get_slot(ivideo->nbridge->bus, (2 << 3));
}
#endif
@@ -6149,9 +6148,9 @@ error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
error_3: vfree(ivideo->bios_abase);
if(ivideo->lpcdev)
- SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+ pci_dev_put(ivideo->lpcdev);
if(ivideo->nbridge)
- SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+ pci_dev_put(ivideo->nbridge);
pci_set_drvdata(pdev, NULL);
if(!ivideo->sisvga_enabled)
pci_disable_device(pdev);
@@ -6331,70 +6330,6 @@ error_3: vfree(ivideo->bios_abase);
sisfb_set_vparms(ivideo);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
- /* ---------------- For 2.4: Now switch the mode ------------------ */
-
- printk(KERN_INFO "sisfb: Setting mode %dx%dx%d (%dHz)\n",
- ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
- ivideo->refresh_rate);
-
- /* Determine whether or not acceleration is to be
- * used. Need to know before pre/post_set_mode()
- */
- ivideo->accel = 0;
- ivideo->default_var.accel_flags &= ~FB_ACCELF_TEXT;
- if(ivideo->sisfb_accel) {
- ivideo->accel = -1;
- ivideo->default_var.accel_flags |= FB_ACCELF_TEXT;
- }
-
- /* Now switch the mode */
- sisfb_pre_setmode(ivideo);
-
- if(SiSSetMode(&ivideo->SiS_Pr, ivideo->mode_no) == 0) {
- printk(KERN_ERR "sisfb: Fatal error: Setting mode[0x%x] failed\n",
- ivideo->mode_no);
- ret = -EINVAL;
- iounmap(ivideo->mmio_vbase);
- goto error_0;
- }
-
- outSISIDXREG(SISSR, IND_SIS_PASSWORD, SIS_PASSWORD);
-
- sisfb_post_setmode(ivideo);
-
- /* Maximize regardless of sisfb_max at startup */
- ivideo->default_var.yres_virtual = 32767;
-
- /* Force reset of x virtual in crtc_to_var */
- ivideo->default_var.xres_virtual = 0;
-
- /* Copy mode timing to var */
- sisfb_crtc_to_var(ivideo, &ivideo->default_var);
-
- /* Find out about screen pitch */
- sisfb_calc_pitch(ivideo, &ivideo->default_var);
- sisfb_set_pitch(ivideo);
-
- /* Init the accelerator (does nothing currently) */
- sisfb_initaccel(ivideo);
-
- /* Init some fbinfo entries */
- sis_fb_info->node = -1;
- sis_fb_info->flags = FBINFO_FLAG_DEFAULT;
- sis_fb_info->fbops = &sisfb_ops;
- sis_fb_info->disp = &ivideo->sis_disp;
- sis_fb_info->blank = &sisfb_blank;
- sis_fb_info->switch_con = &sisfb_switch;
- sis_fb_info->updatevar = &sisfb_update_var;
- sis_fb_info->changevar = NULL;
- strcpy(sis_fb_info->fontname, sisfb_fontname);
-
- sisfb_set_disp(-1, &ivideo->default_var, sis_fb_info);
-
-#else /* --------- For 2.6: Setup a somewhat sane default var ------------ */
-
printk(KERN_INFO "sisfb: Default mode is %dx%dx%d (%dHz)\n",
ivideo->video_width, ivideo->video_height, ivideo->video_bpp,
ivideo->refresh_rate);
@@ -6454,7 +6389,6 @@ error_3: vfree(ivideo->bios_abase);
sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
fb_alloc_cmap(&sis_fb_info->cmap, 256 , 0);
-#endif /* 2.6 */
printk(KERN_DEBUG "sisfb: Initial vbflags 0x%x\n", (int)ivideo->vbflags);
@@ -6564,10 +6498,10 @@ static void __devexit sisfb_remove(struct pci_dev *pdev)
vfree(ivideo->bios_abase);
if(ivideo->lpcdev)
- SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
+ pci_dev_put(ivideo->lpcdev);
if(ivideo->nbridge)
- SIS_PCI_PUT_DEVICE(ivideo->nbridge);
+ pci_dev_put(ivideo->nbridge);
#ifdef CONFIG_MTRR
/* Release MTRR region */
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index bb96cb65fda..836a612af97 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -14,7 +14,7 @@
* of it.
*
* First the roles of struct fb_info and struct display have changed. Struct
- * display will go away. The way the the new framebuffer console code will
+ * display will go away. The way the new framebuffer console code will
* work is that it will act to translate data about the tty/console in
* struct vc_data to data in a device independent way in struct fb_info. Then
* various functions in struct fb_ops will be called to store the device
@@ -51,6 +51,7 @@
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
+#include <linux/pci.h>
/*
* This is just simple sample code.
@@ -60,6 +61,11 @@
*/
/*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
+
+/*
* If your driver supports multiple boards, you should make the
* below data types arrays, or allocate them dynamically (using kmalloc()).
*/
@@ -78,7 +84,7 @@ struct xxx_par;
* if we don't use modedb. If we do use modedb see xxxfb_init how to use it
* to get a fb_var_screeninfo. Otherwise define a default var as well.
*/
-static struct fb_fix_screeninfo xxxfb_fix __initdata = {
+static struct fb_fix_screeninfo xxxfb_fix __devinitdata = {
.id = "FB's name",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
@@ -142,7 +148,7 @@ int xxxfb_setup(char*);
*
* Returns negative errno on error, or zero on success.
*/
-static int xxxfb_open(const struct fb_info *info, int user)
+static int xxxfb_open(struct fb_info *info, int user)
{
return 0;
}
@@ -161,7 +167,7 @@ static int xxxfb_open(const struct fb_info *info, int user)
*
* Returns negative errno on error, or zero on success.
*/
-static int xxxfb_release(const struct fb_info *info, int user)
+static int xxxfb_release(struct fb_info *info, int user)
{
return 0;
}
@@ -278,7 +284,7 @@ static int xxxfb_set_par(struct fb_info *info)
*/
static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
- const struct fb_info *info)
+ struct fb_info *info)
{
if (regno >= 256) /* no. of hw registers */
return -EINVAL;
@@ -416,7 +422,7 @@ static int xxxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
* Returns negative errno on error, or zero on success.
*/
static int xxxfb_pan_display(struct fb_var_screeninfo *var,
- const struct fb_info *info)
+ struct fb_info *info)
{
/*
* If your hardware does not support panning, _do_ _not_ implement this
@@ -454,7 +460,7 @@ static int xxxfb_pan_display(struct fb_var_screeninfo *var,
* Return !0 for any modes that are unimplemented.
*
*/
-static int xxxfb_blank(int blank_mode, const struct fb_info *info)
+static int xxxfb_blank(int blank_mode, struct fb_info *info)
{
/* ... */
return 0;
@@ -483,7 +489,7 @@ static int xxxfb_blank(int blank_mode, const struct fb_info *info)
* depending on the rastering operation with the value of color which
* is in the current color depth format.
*/
-void xxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
+void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
{
/* Meaning of struct fb_fillrect
*
@@ -623,19 +629,6 @@ void xxxfb_rotate(struct fb_info *info, int angle)
}
/**
- * xxxfb_poll - NOT a required function. The purpose of this
- * function is to provide a way for some process
- * to wait until a specific hardware event occurs
- * for the framebuffer device.
- *
- * @info: frame buffer structure that represents a single frame buffer
- * @wait: poll table where we store process that await a event.
- */
-void xxxfb_poll(struct fb_info *info, poll_table *wait)
-{
-}
-
-/**
* xxxfb_sync - NOT a required function. Normally the accel engine
* for a graphics card take a specific amount of time.
* Often we have to wait for the accelerator to finish
@@ -647,21 +640,49 @@ void xxxfb_poll(struct fb_info *info, poll_table *wait)
* If the driver has implemented its own hardware-based drawing function,
* implementing this function is highly recommended.
*/
-void xxxfb_sync(struct fb_info *info)
+int xxxfb_sync(struct fb_info *info)
{
+ return 0;
}
/*
+ * Frame buffer operations
+ */
+
+static struct fb_ops xxxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = xxxfb_open,
+ .fb_read = xxxfb_read,
+ .fb_write = xxxfb_write,
+ .fb_release = xxxfb_release,
+ .fb_check_var = xxxfb_check_var,
+ .fb_set_par = xxxfb_set_par,
+ .fb_setcolreg = xxxfb_setcolreg,
+ .fb_blank = xxxfb_blank,
+ .fb_pan_display = xxxfb_pan_display,
+ .fb_fillrect = xxxfb_fillrect, /* Needed !!! */
+ .fb_copyarea = xxxfb_copyarea, /* Needed !!! */
+ .fb_imageblit = xxxfb_imageblit, /* Needed !!! */
+ .fb_cursor = xxxfb_cursor, /* Optional !!! */
+ .fb_rotate = xxxfb_rotate,
+ .fb_sync = xxxfb_sync,
+ .fb_ioctl = xxxfb_ioctl,
+ .fb_mmap = xxxfb_mmap,
+};
+
+/* ------------------------------------------------------------------------- */
+
+ /*
* Initialization
*/
/* static int __init xxfb_probe (struct device *device) -- for platform devs */
-static int __init xxxfb_probe(struct pci_dev *dev,
- const_struct pci_device_id *ent)
+static int __devinit xxxfb_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
struct fb_info *info;
struct xxx_par *par;
- struct device = &dev->dev; /* for pci drivers */
+ struct device* device = &dev->dev; /* for pci drivers */
int cmap_len, retval;
/*
@@ -684,7 +705,7 @@ static int __init xxxfb_probe(struct pci_dev *dev,
info->screen_base = framebuffer_virtual_memory;
info->fbops = &xxxfb_ops;
info->fix = xxxfb_fix; /* this will be the only time xxxfb_fix will be
- * used, so mark it as __initdata
+ * used, so mark it as __devinitdata
*/
info->pseudo_palette = pseudo_palette; /* The pseudopalette is an
* 16-member array
@@ -760,7 +781,7 @@ static int __init xxxfb_probe(struct pci_dev *dev,
*
* NOTE: This field is currently unused.
*/
- info->pixmap.scan_align = 32
+ info->pixmap.scan_align = 32;
/***************************** End optional stage ***************************/
/*
@@ -770,13 +791,13 @@ static int __init xxxfb_probe(struct pci_dev *dev,
if (!mode_option)
mode_option = "640x480@60";
- retval = fb_find_mode(info->var, info, mode_option, NULL, 0, NULL, 8);
+ retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
if (!retval || retval == 4)
return -EINVAL;
/* This has to been done !!! */
- fb_alloc_cmap(info->cmap, cmap_len, 0);
+ fb_alloc_cmap(&info->cmap, cmap_len, 0);
/*
* The following is done in the case of having hardware with a static
@@ -811,34 +832,77 @@ static int __init xxxfb_probe(struct pci_dev *dev,
/*
* Cleanup
*/
-/* static void __exit xxxfb_remove(struct device *device) */
-static void __exit xxxfb_remove(struct pci_dev *dev)
+/* static void __devexit xxxfb_remove(struct device *device) */
+static void __devexit xxxfb_remove(struct pci_dev *dev)
{
- struct fb_info *info = pci_get_drv_data(dev);
- /* or dev_get_drv_data(device); */
+ struct fb_info *info = pci_get_drvdata(dev);
+ /* or dev_get_drvdata(device); */
if (info) {
unregister_framebuffer(info);
- fb_dealloc_cmap(&info.cmap);
+ fb_dealloc_cmap(&info->cmap);
/* ... */
framebuffer_release(info);
}
+}
+
+#ifdef CONFIG_PCI
+#ifdef CONFIG_PM
+/**
+ * xxxfb_suspend - Optional but recommended function. Suspend the device.
+ * @dev: PCI device
+ * @msg: the suspend event code.
+ *
+ * See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_suspend(struct pci_dev *dev, pm_message_t msg)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct xxxfb_par *par = info->par;
+
+ /* suspend here */
+ return 0;
+}
+
+/**
+ * xxxfb_resume - Optional but recommended function. Resume the device.
+ * @dev: PCI device
+ *
+ * See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_resume(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct xxxfb_par *par = info->par;
+ /* resume here */
return 0;
}
+#else
+#define xxxfb_suspend NULL
+#define xxxfb_resume NULL
+#endif /* CONFIG_PM */
+
+static struct pci_device_id xxxfb_id_table[] = {
+ { PCI_VENDOR_ID_XXX, PCI_DEVICE_ID_XXX,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+ PCI_CLASS_MASK, 0 },
+ { 0, }
+};
-#if CONFIG_PCI
/* For PCI drivers */
static struct pci_driver xxxfb_driver = {
.name = "xxxfb",
- .id_table = xxxfb_devices,
+ .id_table = xxxfb_id_table,
.probe = xxxfb_probe,
.remove = __devexit_p(xxxfb_remove),
- .suspend = xxxfb_suspend, /* optional */
- .resume = xxxfb_resume, /* optional */
+ .suspend = xxxfb_suspend, /* optional but recommended */
+ .resume = xxxfb_resume, /* optional but recommended */
};
-static int __init xxxfb_init(void)
+MODULE_DEVICE_TABLE(pci, xxxfb_id_table);
+
+int __init xxxfb_init(void)
{
/*
* For kernel boot options (in 'video=xxxfb:<options>' format)
@@ -858,16 +922,53 @@ static void __exit xxxfb_exit(void)
{
pci_unregister_driver(&xxxfb_driver);
}
-#else
+#else /* non PCI, platform drivers */
#include <linux/platform_device.h>
/* for platform devices */
+
+#ifdef CONFIG_PM
+/**
+ * xxxfb_suspend - Optional but recommended function. Suspend the device.
+ * @dev: platform device
+ * @msg: the suspend event code.
+ *
+ * See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_suspend(struct platform_device *dev, pm_message_t msg)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct xxxfb_par *par = info->par;
+
+ /* suspend here */
+ return 0;
+}
+
+/**
+ * xxxfb_resume - Optional but recommended function. Resume the device.
+ * @dev: platform device
+ *
+ * See Documentation/power/devices.txt for more information
+ */
+static int xxxfb_resume(struct platform_dev *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct xxxfb_par *par = info->par;
+
+ /* resume here */
+ return 0;
+}
+#else
+#define xxxfb_suspend NULL
+#define xxxfb_resume NULL
+#endif /* CONFIG_PM */
+
static struct device_driver xxxfb_driver = {
.name = "xxxfb",
.bus = &platform_bus_type,
.probe = xxxfb_probe,
.remove = xxxfb_remove,
- .suspend = xxxfb_suspend, /* optional */
- .resume = xxxfb_resume, /* optional */
+ .suspend = xxxfb_suspend, /* optional but recommended */
+ .resume = xxxfb_resume, /* optional but recommended */
};
static struct platform_device xxxfb_device = {
@@ -903,8 +1004,9 @@ static void __exit xxxfb_exit(void)
platform_device_unregister(&xxxfb_device);
driver_unregister(&xxxfb_driver);
}
-#endif
+#endif /* CONFIG_PCI */
+#ifdef MODULE
/*
* Setup
*/
@@ -917,34 +1019,7 @@ int __init xxxfb_setup(char *options)
{
/* Parse user speficied options (`video=xxxfb:') */
}
-
-/* ------------------------------------------------------------------------- */
-
- /*
- * Frame buffer operations
- */
-
-static struct fb_ops xxxfb_ops = {
- .owner = THIS_MODULE,
- .fb_open = xxxfb_open,
- .fb_read = xxxfb_read,
- .fb_write = xxxfb_write,
- .fb_release = xxxfb_release,
- .fb_check_var = xxxfb_check_var,
- .fb_set_par = xxxfb_set_par,
- .fb_setcolreg = xxxfb_setcolreg,
- .fb_blank = xxxfb_blank,
- .fb_pan_display = xxxfb_pan_display,
- .fb_fillrect = xxxfb_fillrect, /* Needed !!! */
- .fb_copyarea = xxxfb_copyarea, /* Needed !!! */
- .fb_imageblit = xxxfb_imageblit, /* Needed !!! */
- .fb_cursor = xxxfb_cursor, /* Optional !!! */
- .fb_rotate = xxxfb_rotate,
- .fb_poll = xxxfb_poll,
- .fb_sync = xxxfb_sync,
- .fb_ioctl = xxxfb_ioctl,
- .fb_mmap = xxxfb_mmap,
-};
+#endif /* MODULE */
/* ------------------------------------------------------------------------- */
@@ -954,6 +1029,6 @@ static struct fb_ops xxxfb_ops = {
*/
module_init(xxxfb_init);
-module_exit(xxxfb_cleanup);
+module_exit(xxxfb_remove);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 0a44c44672c..c86df126f93 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -989,7 +989,7 @@ static int sm501fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
((info->cmap.green[fg_col] & 0xFC) << 3) |
((info->cmap.blue[fg_col] & 0xF8) >> 3);
- dev_dbg(fbi->dev, "fgcol %08x, bgcol %08x\n", fg, bg);
+ dev_dbg(fbi->dev, "fgcol %08lx, bgcol %08lx\n", fg, bg);
writel(bg, base + SM501_OFF_HWC_COLOR_1_2);
writel(fg, base + SM501_OFF_HWC_COLOR_3);
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 69f3b264a22..c97709ecbad 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -64,7 +64,6 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/pci.h>
#include <asm/grfioctl.h> /* for HP-UX compatibility */
#include <asm/uaccess.h>
diff --git a/drivers/video/sunxvr2500.c b/drivers/video/sunxvr2500.c
new file mode 100644
index 00000000000..4316c7fe8e2
--- /dev/null
+++ b/drivers/video/sunxvr2500.c
@@ -0,0 +1,277 @@
+/* s3d.c: Sun 3DLABS XVR-2500 et al. driver for sparc64 systems
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+
+struct s3d_info {
+ struct fb_info *info;
+ struct pci_dev *pdev;
+
+ char __iomem *fb_base;
+ unsigned long fb_base_phys;
+
+ struct device_node *of_node;
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int depth;
+ unsigned int fb_size;
+
+ u32 pseudo_palette[256];
+};
+
+static int __devinit s3d_get_props(struct s3d_info *sp)
+{
+ sp->width = of_getintprop_default(sp->of_node, "width", 0);
+ sp->height = of_getintprop_default(sp->of_node, "height", 0);
+ sp->depth = of_getintprop_default(sp->of_node, "depth", 8);
+
+ if (!sp->width || !sp->height) {
+ printk(KERN_ERR "s3d: Critical properties missing for %s\n",
+ pci_name(sp->pdev));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int s3d_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ u32 value;
+
+ if (regno >= 256)
+ return 1;
+
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ value = (blue << 24) | (green << 16) | (red << 8);
+ ((u32 *)info->pseudo_palette)[regno] = value;
+
+ return 0;
+}
+
+static struct fb_ops s3d_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = s3d_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __devinit s3d_set_fbinfo(struct s3d_info *sp)
+{
+ struct fb_info *info = sp->info;
+ struct fb_var_screeninfo *var = &info->var;
+
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &s3d_ops;
+ info->screen_base = sp->fb_base;
+ info->screen_size = sp->fb_size;
+
+ info->pseudo_palette = sp->pseudo_palette;
+
+ /* Fill fix common fields */
+ strlcpy(info->fix.id, "s3d", sizeof(info->fix.id));
+ info->fix.smem_start = sp->fb_base_phys;
+ info->fix.smem_len = sp->fb_size;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ if (sp->depth == 32 || sp->depth == 24)
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ else
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+ var->xres = sp->width;
+ var->yres = sp->height;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+ var->bits_per_pixel = sp->depth;
+
+ var->red.offset = 8;
+ var->red.length = 8;
+ var->green.offset = 16;
+ var->green.length = 8;
+ var->blue.offset = 24;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+ printk(KERN_ERR "s3d: Cannot allocate color map.\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int __devinit s3d_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct fb_info *info;
+ struct s3d_info *sp;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err < 0) {
+ printk(KERN_ERR "s3d: Cannot enable PCI device %s\n",
+ pci_name(pdev));
+ goto err_out;
+ }
+
+ info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev);
+ if (!info) {
+ printk(KERN_ERR "s3d: Cannot allocate fb_info\n");
+ err = -ENOMEM;
+ goto err_disable;
+ }
+
+ sp = info->par;
+ sp->info = info;
+ sp->pdev = pdev;
+ sp->of_node = pci_device_to_OF_node(pdev);
+ if (!sp->of_node) {
+ printk(KERN_ERR "s3d: Cannot find OF node of %s\n",
+ pci_name(pdev));
+ err = -ENODEV;
+ goto err_release_fb;
+ }
+
+ sp->fb_base_phys = pci_resource_start (pdev, 1);
+
+ err = pci_request_region(pdev, 1, "s3d framebuffer");
+ if (err < 0) {
+ printk("s3d: Cannot request region 1 for %s\n",
+ pci_name(pdev));
+ goto err_release_fb;
+ }
+
+ err = s3d_get_props(sp);
+ if (err)
+ goto err_release_pci;
+
+ /* XXX 'linebytes' is often wrong, it is equal to the width
+ * XXX with depth of 32 on my XVR-2500 which is clearly not
+ * XXX right. So we don't try to use it.
+ */
+ switch (sp->depth) {
+ case 8:
+ info->fix.line_length = sp->width;
+ break;
+ case 16:
+ info->fix.line_length = sp->width * 2;
+ break;
+ case 24:
+ info->fix.line_length = sp->width * 3;
+ break;
+ case 32:
+ info->fix.line_length = sp->width * 4;
+ break;
+ }
+ sp->fb_size = info->fix.line_length * sp->height;
+
+ sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);
+ if (!sp->fb_base)
+ goto err_release_pci;
+
+ err = s3d_set_fbinfo(sp);
+ if (err)
+ goto err_unmap_fb;
+
+ pci_set_drvdata(pdev, info);
+
+ printk("s3d: Found device at %s\n", pci_name(pdev));
+
+ err = register_framebuffer(info);
+ if (err < 0) {
+ printk(KERN_ERR "s3d: Could not register framebuffer %s\n",
+ pci_name(pdev));
+ goto err_unmap_fb;
+ }
+
+ return 0;
+
+err_unmap_fb:
+ iounmap(sp->fb_base);
+
+err_release_pci:
+ pci_release_region(pdev, 1);
+
+err_release_fb:
+ framebuffer_release(info);
+
+err_disable:
+ pci_disable_device(pdev);
+
+err_out:
+ return err;
+}
+
+static void __devexit s3d_pci_unregister(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct s3d_info *sp = info->par;
+
+ unregister_framebuffer(info);
+
+ iounmap(sp->fb_base);
+
+ pci_release_region(pdev, 1);
+
+ framebuffer_release(info);
+
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id s3d_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002c), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002d), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002e), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x002f), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0030), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0031), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0032), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0033), },
+ { 0, }
+};
+
+static struct pci_driver s3d_driver = {
+ .name = "s3d",
+ .id_table = s3d_pci_table,
+ .probe = s3d_pci_register,
+ .remove = __devexit_p(s3d_pci_unregister),
+};
+
+static int __init s3d_init(void)
+{
+ if (fb_get_options("s3d", NULL))
+ return -ENODEV;
+
+ return pci_register_driver(&s3d_driver);
+}
+
+static void __exit s3d_exit(void)
+{
+ pci_unregister_driver(&s3d_driver);
+}
+
+module_init(s3d_init);
+module_exit(s3d_exit);
+
+MODULE_DESCRIPTION("framebuffer driver for Sun XVR-2500 graphics");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sunxvr500.c b/drivers/video/sunxvr500.c
new file mode 100644
index 00000000000..08880a62bfa
--- /dev/null
+++ b/drivers/video/sunxvr500.c
@@ -0,0 +1,443 @@
+/* sunxvr500.c: Sun 3DLABS XVR-500 Expert3D driver for sparc64 systems
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
+
+/* XXX This device has a 'dev-comm' property which aparently is
+ * XXX a pointer into the openfirmware's address space which is
+ * XXX a shared area the kernel driver can use to keep OBP
+ * XXX informed about the current resolution setting. The idea
+ * XXX is that the kernel can change resolutions, and as long
+ * XXX as the values in the 'dev-comm' area are accurate then
+ * XXX OBP can still render text properly to the console.
+ * XXX
+ * XXX I'm still working out the layout of this and whether there
+ * XXX are any signatures we need to look for etc.
+ */
+struct e3d_info {
+ struct fb_info *info;
+ struct pci_dev *pdev;
+
+ spinlock_t lock;
+
+ char __iomem *fb_base;
+ unsigned long fb_base_phys;
+
+ unsigned long fb8_buf_diff;
+ unsigned long regs_base_phys;
+
+ void __iomem *ramdac;
+
+ struct device_node *of_node;
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int depth;
+ unsigned int fb_size;
+
+ u32 fb_base_reg;
+ u32 fb8_0_off;
+ u32 fb8_1_off;
+
+ u32 pseudo_palette[256];
+};
+
+static int __devinit e3d_get_props(struct e3d_info *ep)
+{
+ ep->width = of_getintprop_default(ep->of_node, "width", 0);
+ ep->height = of_getintprop_default(ep->of_node, "height", 0);
+ ep->depth = of_getintprop_default(ep->of_node, "depth", 8);
+
+ if (!ep->width || !ep->height) {
+ printk(KERN_ERR "e3d: Critical properties missing for %s\n",
+ pci_name(ep->pdev));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* My XVR-500 comes up, at 1280x768 and a FB base register value of
+ * 0x04000000, the following video layout register values:
+ *
+ * RAMDAC_VID_WH 0x03ff04ff
+ * RAMDAC_VID_CFG 0x1a0b0088
+ * RAMDAC_VID_32FB_0 0x04000000
+ * RAMDAC_VID_32FB_1 0x04800000
+ * RAMDAC_VID_8FB_0 0x05000000
+ * RAMDAC_VID_8FB_1 0x05200000
+ * RAMDAC_VID_XXXFB 0x05400000
+ * RAMDAC_VID_YYYFB 0x05c00000
+ * RAMDAC_VID_ZZZFB 0x05e00000
+ */
+/* Video layout registers */
+#define RAMDAC_VID_WH 0x00000070UL /* (height-1)<<16 | (width-1) */
+#define RAMDAC_VID_CFG 0x00000074UL /* 0x1a000088|(linesz_log2<<16) */
+#define RAMDAC_VID_32FB_0 0x00000078UL /* PCI base 32bpp FB buffer 0 */
+#define RAMDAC_VID_32FB_1 0x0000007cUL /* PCI base 32bpp FB buffer 1 */
+#define RAMDAC_VID_8FB_0 0x00000080UL /* PCI base 8bpp FB buffer 0 */
+#define RAMDAC_VID_8FB_1 0x00000084UL /* PCI base 8bpp FB buffer 1 */
+#define RAMDAC_VID_XXXFB 0x00000088UL /* PCI base of XXX FB */
+#define RAMDAC_VID_YYYFB 0x0000008cUL /* PCI base of YYY FB */
+#define RAMDAC_VID_ZZZFB 0x00000090UL /* PCI base of ZZZ FB */
+
+/* CLUT registers */
+#define RAMDAC_INDEX 0x000000bcUL
+#define RAMDAC_DATA 0x000000c0UL
+
+static void e3d_clut_write(struct e3d_info *ep, int index, u32 val)
+{
+ void __iomem *ramdac = ep->ramdac;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ writel(index, ramdac + RAMDAC_INDEX);
+ writel(val, ramdac + RAMDAC_DATA);
+
+ spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static int e3d_setcolreg(unsigned regno,
+ unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ struct e3d_info *ep = info->par;
+ u32 red_8, green_8, blue_8;
+ u32 red_10, green_10, blue_10;
+ u32 value;
+
+ if (regno >= 256)
+ return 1;
+
+ red_8 = red >> 8;
+ green_8 = green >> 8;
+ blue_8 = blue >> 8;
+
+ value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8);
+ ((u32 *)info->pseudo_palette)[regno] = value;
+
+
+ red_10 = red >> 6;
+ green_10 = green >> 6;
+ blue_10 = blue >> 6;
+
+ value = (blue_10 << 20) | (green_10 << 10) | (red_10 << 0);
+ e3d_clut_write(ep, regno, value);
+
+ return 0;
+}
+
+/* XXX This is a bit of a hack. I can't figure out exactly how the
+ * XXX two 8bpp areas of the framebuffer work. I imagine there is
+ * XXX a WID attribute somewhere else in the framebuffer which tells
+ * XXX the ramdac which of the two 8bpp framebuffer regions to take
+ * XXX the pixel from. So, for now, render into both regions to make
+ * XXX sure the pixel shows up.
+ */
+static void e3d_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct e3d_info *ep = info->par;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ cfb_imageblit(info, image);
+ info->screen_base += ep->fb8_buf_diff;
+ cfb_imageblit(info, image);
+ info->screen_base -= ep->fb8_buf_diff;
+ spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void e3d_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ struct e3d_info *ep = info->par;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ cfb_fillrect(info, rect);
+ info->screen_base += ep->fb8_buf_diff;
+ cfb_fillrect(info, rect);
+ info->screen_base -= ep->fb8_buf_diff;
+ spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static void e3d_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ struct e3d_info *ep = info->par;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ cfb_copyarea(info, area);
+ info->screen_base += ep->fb8_buf_diff;
+ cfb_copyarea(info, area);
+ info->screen_base -= ep->fb8_buf_diff;
+ spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+static struct fb_ops e3d_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = e3d_setcolreg,
+ .fb_fillrect = e3d_fillrect,
+ .fb_copyarea = e3d_copyarea,
+ .fb_imageblit = e3d_imageblit,
+};
+
+static int __devinit e3d_set_fbinfo(struct e3d_info *ep)
+{
+ struct fb_info *info = ep->info;
+ struct fb_var_screeninfo *var = &info->var;
+
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &e3d_ops;
+ info->screen_base = ep->fb_base;
+ info->screen_size = ep->fb_size;
+
+ info->pseudo_palette = ep->pseudo_palette;
+
+ /* Fill fix common fields */
+ strlcpy(info->fix.id, "e3d", sizeof(info->fix.id));
+ info->fix.smem_start = ep->fb_base_phys;
+ info->fix.smem_len = ep->fb_size;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ if (ep->depth == 32 || ep->depth == 24)
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ else
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+
+ var->xres = ep->width;
+ var->yres = ep->height;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+ var->bits_per_pixel = ep->depth;
+
+ var->red.offset = 8;
+ var->red.length = 8;
+ var->green.offset = 16;
+ var->green.length = 8;
+ var->blue.offset = 24;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0)) {
+ printk(KERN_ERR "e3d: Cannot allocate color map.\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int __devinit e3d_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct fb_info *info;
+ struct e3d_info *ep;
+ unsigned int line_length;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err < 0) {
+ printk(KERN_ERR "e3d: Cannot enable PCI device %s\n",
+ pci_name(pdev));
+ goto err_out;
+ }
+
+ info = framebuffer_alloc(sizeof(struct e3d_info), &pdev->dev);
+ if (!info) {
+ printk(KERN_ERR "e3d: Cannot allocate fb_info\n");
+ err = -ENOMEM;
+ goto err_disable;
+ }
+
+ ep = info->par;
+ ep->info = info;
+ ep->pdev = pdev;
+ spin_lock_init(&ep->lock);
+ ep->of_node = pci_device_to_OF_node(pdev);
+ if (!ep->of_node) {
+ printk(KERN_ERR "e3d: Cannot find OF node of %s\n",
+ pci_name(pdev));
+ err = -ENODEV;
+ goto err_release_fb;
+ }
+
+ /* Read the PCI base register of the frame buffer, which we
+ * need in order to interpret the RAMDAC_VID_*FB* values in
+ * the ramdac correctly.
+ */
+ pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
+ &ep->fb_base_reg);
+ ep->fb_base_reg &= PCI_BASE_ADDRESS_MEM_MASK;
+
+ ep->regs_base_phys = pci_resource_start (pdev, 1);
+ err = pci_request_region(pdev, 1, "e3d regs");
+ if (err < 0) {
+ printk("e3d: Cannot request region 1 for %s\n",
+ pci_name(pdev));
+ goto err_release_fb;
+ }
+ ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000);
+ if (!ep->ramdac)
+ goto err_release_pci1;
+
+ ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0);
+ ep->fb8_0_off -= ep->fb_base_reg;
+
+ ep->fb8_1_off = readl(ep->ramdac + RAMDAC_VID_8FB_1);
+ ep->fb8_1_off -= ep->fb_base_reg;
+
+ ep->fb8_buf_diff = ep->fb8_1_off - ep->fb8_0_off;
+
+ ep->fb_base_phys = pci_resource_start (pdev, 0);
+ ep->fb_base_phys += ep->fb8_0_off;
+
+ err = pci_request_region(pdev, 0, "e3d framebuffer");
+ if (err < 0) {
+ printk("e3d: Cannot request region 0 for %s\n",
+ pci_name(pdev));
+ goto err_unmap_ramdac;
+ }
+
+ err = e3d_get_props(ep);
+ if (err)
+ goto err_release_pci0;
+
+ line_length = (readl(ep->ramdac + RAMDAC_VID_CFG) >> 16) & 0xff;
+ line_length = 1 << line_length;
+
+ switch (ep->depth) {
+ case 8:
+ info->fix.line_length = line_length;
+ break;
+ case 16:
+ info->fix.line_length = line_length * 2;
+ break;
+ case 24:
+ info->fix.line_length = line_length * 3;
+ break;
+ case 32:
+ info->fix.line_length = line_length * 4;
+ break;
+ }
+ ep->fb_size = info->fix.line_length * ep->height;
+
+ ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size);
+ if (!ep->fb_base)
+ goto err_release_pci0;
+
+ err = e3d_set_fbinfo(ep);
+ if (err)
+ goto err_unmap_fb;
+
+ pci_set_drvdata(pdev, info);
+
+ printk("e3d: Found device at %s\n", pci_name(pdev));
+
+ err = register_framebuffer(info);
+ if (err < 0) {
+ printk(KERN_ERR "e3d: Could not register framebuffer %s\n",
+ pci_name(pdev));
+ goto err_unmap_fb;
+ }
+
+ return 0;
+
+err_unmap_fb:
+ iounmap(ep->fb_base);
+
+err_release_pci0:
+ pci_release_region(pdev, 0);
+
+err_unmap_ramdac:
+ iounmap(ep->ramdac);
+
+err_release_pci1:
+ pci_release_region(pdev, 1);
+
+err_release_fb:
+ framebuffer_release(info);
+
+err_disable:
+ pci_disable_device(pdev);
+
+err_out:
+ return err;
+}
+
+static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
+{
+ struct fb_info *info = pci_get_drvdata(pdev);
+ struct e3d_info *ep = info->par;
+
+ unregister_framebuffer(info);
+
+ iounmap(ep->ramdac);
+ iounmap(ep->fb_base);
+
+ pci_release_region(pdev, 0);
+ pci_release_region(pdev, 1);
+
+ framebuffer_release(info);
+
+ pci_disable_device(pdev);
+}
+
+static struct pci_device_id e3d_pci_table[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), },
+ { PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2), },
+ { .vendor = PCI_VENDOR_ID_3DLABS,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_VENDOR_ID_3DLABS,
+ .subdevice = 0x0108,
+ },
+ { .vendor = PCI_VENDOR_ID_3DLABS,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_VENDOR_ID_3DLABS,
+ .subdevice = 0x0140,
+ },
+ { .vendor = PCI_VENDOR_ID_3DLABS,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_VENDOR_ID_3DLABS,
+ .subdevice = 0x1024,
+ },
+ { 0, }
+};
+
+static struct pci_driver e3d_driver = {
+ .name = "e3d",
+ .id_table = e3d_pci_table,
+ .probe = e3d_pci_register,
+ .remove = __devexit_p(e3d_pci_unregister),
+};
+
+static int __init e3d_init(void)
+{
+ if (fb_get_options("e3d", NULL))
+ return -ENODEV;
+
+ return pci_register_driver(&e3d_driver);
+}
+
+static void __exit e3d_exit(void)
+{
+ pci_unregister_driver(&e3d_driver);
+}
+
+module_init(e3d_init);
+module_exit(e3d_exit);
+
+MODULE_DESCRIPTION("framebuffer driver for Sun XVR-500 graphics");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/svgalib.c b/drivers/video/svgalib.c
index 68b30d9eac5..25df928d37d 100644
--- a/drivers/video/svgalib.c
+++ b/drivers/video/svgalib.c
@@ -194,7 +194,7 @@ void svga_dump_var(struct fb_var_screeninfo *var, int node)
void svga_settile(struct fb_info *info, struct fb_tilemap *map)
{
const u8 *font = map->data;
- u8* fb = (u8 *) info->screen_base;
+ u8 __iomem *fb = (u8 __iomem *)info->screen_base;
int i, c;
if ((map->width != 8) || (map->height != 16) ||
@@ -207,7 +207,8 @@ void svga_settile(struct fb_info *info, struct fb_tilemap *map)
fb += 2;
for (c = 0; c < map->length; c++) {
for (i = 0; i < map->height; i++) {
- fb[i * 4] = font[i];
+ fb_writeb(font[i], fb + i * 4);
+// fb[i * 4] = font[i];
}
fb += 128;
font += map->height;
@@ -221,8 +222,8 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
/* colstride is halved in this function because u16 are used */
int colstride = 1 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
int rowstride = colstride * (info->var.xres_virtual / 8);
- u16 *fb = (u16 *) info->screen_base;
- u16 *src, *dst;
+ u16 __iomem *fb = (u16 __iomem *) info->screen_base;
+ u16 __iomem *src, *dst;
if ((area->sy > area->dy) ||
((area->sy == area->dy) && (area->sx > area->dx))) {
@@ -239,10 +240,11 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area)
}
for (dy = 0; dy < area->height; dy++) {
- u16* src2 = src;
- u16* dst2 = dst;
+ u16 __iomem *src2 = src;
+ u16 __iomem *dst2 = dst;
for (dx = 0; dx < area->width; dx++) {
- *dst2 = *src2;
+ fb_writew(fb_readw(src2), dst2);
+// *dst2 = *src2;
src2 += colstride;
dst2 += colstride;
}
@@ -258,14 +260,14 @@ void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect)
int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
int rowstride = colstride * (info->var.xres_virtual / 8);
int attr = (0x0F & rect->bg) << 4 | (0x0F & rect->fg);
- u8 *fb = (u8 *) info->screen_base;
+ u8 __iomem *fb = (u8 __iomem *)info->screen_base;
fb += rect->sx * colstride + rect->sy * rowstride;
for (dy = 0; dy < rect->height; dy++) {
- u8* fb2 = fb;
+ u8 __iomem *fb2 = fb;
for (dx = 0; dx < rect->width; dx++) {
- fb2[0] = rect->index;
- fb2[1] = attr;
+ fb_writeb(rect->index, fb2);
+ fb_writeb(attr, fb2 + 1);
fb2 += colstride;
}
fb += rowstride;
@@ -279,15 +281,15 @@ void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit)
int colstride = 2 << (info->fix.type_aux & FB_AUX_TEXT_SVGA_MASK);
int rowstride = colstride * (info->var.xres_virtual / 8);
int attr = (0x0F & blit->bg) << 4 | (0x0F & blit->fg);
- u8* fb = (u8 *) info->screen_base;
+ u8 __iomem *fb = (u8 __iomem *)info->screen_base;
fb += blit->sx * colstride + blit->sy * rowstride;
i=0;
for (dy=0; dy < blit->height; dy ++) {
- u8* fb2 = fb;
+ u8 __iomem *fb2 = fb;
for (dx = 0; dx < blit->width; dx ++) {
- fb2[0] = blit->indices[i];
- fb2[1] = attr;
+ fb_writeb(blit->indices[i], fb2);
+ fb_writeb(attr, fb2 + 1);
fb2 += colstride;
i ++;
if (i == blit->length) return;
@@ -340,6 +342,28 @@ void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
vga_wcrt(NULL, 0x0A, cs); /* set cursor start and enable it */
}
+int svga_get_tilemax(struct fb_info *info)
+{
+ return 256;
+}
+
+/* Get capabilities of accelerator based on the mode */
+
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+ struct fb_var_screeninfo *var)
+{
+ if (var->bits_per_pixel == 0) {
+ /* can only support 256 8x16 bitmap */
+ caps->x = 1 << (8 - 1);
+ caps->y = 1 << (16 - 1);
+ caps->len = 256;
+ } else {
+ caps->x = (var->bits_per_pixel == 4) ? 1 << (8 - 1) : ~(u32)0;
+ caps->y = ~(u32)0;
+ caps->len = ~(u32)0;
+ }
+}
+EXPORT_SYMBOL(svga_get_caps);
/* ------------------------------------------------------------------------- */
@@ -621,6 +645,7 @@ EXPORT_SYMBOL(svga_tilecopy);
EXPORT_SYMBOL(svga_tilefill);
EXPORT_SYMBOL(svga_tileblit);
EXPORT_SYMBOL(svga_tilecursor);
+EXPORT_SYMBOL(svga_get_tilemax);
EXPORT_SYMBOL(svga_compute_pll);
EXPORT_SYMBOL(svga_check_timings);
diff --git a/drivers/video/syscopyarea.c b/drivers/video/syscopyarea.c
new file mode 100644
index 00000000000..37af10ab8f5
--- /dev/null
+++ b/drivers/video/syscopyarea.c
@@ -0,0 +1,378 @@
+/*
+ * Generic Bit Block Transfer for frame buffers located in system RAM with
+ * packed pixels of any depth.
+ *
+ * Based almost entirely from cfbcopyarea.c (which is based almost entirely
+ * on Geert Uytterhoeven's copyarea routine)
+ *
+ * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <linux/slab.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "fb_draw.h"
+
+ /*
+ * Generic bitwise copy algorithm
+ */
+
+static void
+bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+ int src_idx, int bits, unsigned n)
+{
+ unsigned long first, last;
+ int const shift = dst_idx-src_idx;
+ int left, right;
+
+ first = FB_SHIFT_HIGH(~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+ if (!shift) {
+ /* Same alignment for source and dest */
+ if (dst_idx+n <= bits) {
+ /* Single word */
+ if (last)
+ first &= last;
+ *dst = comp(*src, *dst, first);
+ } else {
+ /* Multiple destination words */
+ /* Leading bits */
+ if (first != ~0UL) {
+ *dst = comp(*src, *dst, first);
+ dst++;
+ src++;
+ n -= bits - dst_idx;
+ }
+
+ /* Main chunk */
+ n /= bits;
+ while (n >= 8) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ *dst++ = *src++;
+ n -= 8;
+ }
+ while (n--)
+ *dst++ = *src++;
+
+ /* Trailing bits */
+ if (last)
+ *dst = comp(*src, *dst, last);
+ }
+ } else {
+ unsigned long d0, d1;
+ int m;
+
+ /* Different alignment for source and dest */
+ right = shift & (bits - 1);
+ left = -shift & (bits - 1);
+
+ if (dst_idx+n <= bits) {
+ /* Single destination word */
+ if (last)
+ first &= last;
+ if (shift > 0) {
+ /* Single source word */
+ *dst = comp(*src >> right, *dst, first);
+ } else if (src_idx+n <= bits) {
+ /* Single source word */
+ *dst = comp(*src << left, *dst, first);
+ } else {
+ /* 2 source words */
+ d0 = *src++;
+ d1 = *src;
+ *dst = comp(d0 << left | d1 >> right, *dst,
+ first);
+ }
+ } else {
+ /* Multiple destination words */
+ /** We must always remember the last value read,
+ because in case SRC and DST overlap bitwise (e.g.
+ when moving just one pixel in 1bpp), we always
+ collect one full long for DST and that might
+ overlap with the current long from SRC. We store
+ this value in 'd0'. */
+ d0 = *src++;
+ /* Leading bits */
+ if (shift > 0) {
+ /* Single source word */
+ *dst = comp(d0 >> right, *dst, first);
+ dst++;
+ n -= bits - dst_idx;
+ } else {
+ /* 2 source words */
+ d1 = *src++;
+ *dst = comp(d0 << left | *dst >> right, *dst, first);
+ d0 = d1;
+ dst++;
+ n -= bits - dst_idx;
+ }
+
+ /* Main chunk */
+ m = n % bits;
+ n /= bits;
+ while (n >= 4) {
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = *src++;
+ *dst++ = d0 << left | d1 >> right;
+ d0 = d1;
+ }
+
+ /* Trailing bits */
+ if (last) {
+ if (m <= right) {
+ /* Single source word */
+ *dst = comp(d0 << left, *dst, last);
+ } else {
+ /* 2 source words */
+ d1 = *src;
+ *dst = comp(d0 << left | d1 >> right,
+ *dst, last);
+ }
+ }
+ }
+ }
+}
+
+ /*
+ * Generic bitwise copy algorithm, operating backward
+ */
+
+static void
+bitcpy_rev(unsigned long *dst, int dst_idx, const unsigned long *src,
+ int src_idx, int bits, unsigned n)
+{
+ unsigned long first, last;
+ int shift;
+
+ dst += (n-1)/bits;
+ src += (n-1)/bits;
+ if ((n-1) % bits) {
+ dst_idx += (n-1) % bits;
+ dst += dst_idx >> (ffs(bits) - 1);
+ dst_idx &= bits - 1;
+ src_idx += (n-1) % bits;
+ src += src_idx >> (ffs(bits) - 1);
+ src_idx &= bits - 1;
+ }
+
+ shift = dst_idx-src_idx;
+
+ first = FB_SHIFT_LOW(~0UL, bits - 1 - dst_idx);
+ last = ~(FB_SHIFT_LOW(~0UL, bits - 1 - ((dst_idx-n) % bits)));
+
+ if (!shift) {
+ /* Same alignment for source and dest */
+ if ((unsigned long)dst_idx+1 >= n) {
+ /* Single word */
+ if (last)
+ first &= last;
+ *dst = comp(*src, *dst, first);
+ } else {
+ /* Multiple destination words */
+
+ /* Leading bits */
+ if (first != ~0UL) {
+ *dst = comp(*src, *dst, first);
+ dst--;
+ src--;
+ n -= dst_idx+1;
+ }
+
+ /* Main chunk */
+ n /= bits;
+ while (n >= 8) {
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ *dst-- = *src--;
+ n -= 8;
+ }
+ while (n--)
+ *dst-- = *src--;
+ /* Trailing bits */
+ if (last)
+ *dst = comp(*src, *dst, last);
+ }
+ } else {
+ /* Different alignment for source and dest */
+
+ int const left = -shift & (bits-1);
+ int const right = shift & (bits-1);
+
+ if ((unsigned long)dst_idx+1 >= n) {
+ /* Single destination word */
+ if (last)
+ first &= last;
+ if (shift < 0) {
+ /* Single source word */
+ *dst = comp(*src << left, *dst, first);
+ } else if (1+(unsigned long)src_idx >= n) {
+ /* Single source word */
+ *dst = comp(*src >> right, *dst, first);
+ } else {
+ /* 2 source words */
+ *dst = comp(*src >> right | *(src-1) << left,
+ *dst, first);
+ }
+ } else {
+ /* Multiple destination words */
+ /** We must always remember the last value read,
+ because in case SRC and DST overlap bitwise (e.g.
+ when moving just one pixel in 1bpp), we always
+ collect one full long for DST and that might
+ overlap with the current long from SRC. We store
+ this value in 'd0'. */
+ unsigned long d0, d1;
+ int m;
+
+ d0 = *src--;
+ /* Leading bits */
+ if (shift < 0) {
+ /* Single source word */
+ *dst = comp(d0 << left, *dst, first);
+ } else {
+ /* 2 source words */
+ d1 = *src--;
+ *dst = comp(d0 >> right | d1 << left, *dst,
+ first);
+ d0 = d1;
+ }
+ dst--;
+ n -= dst_idx+1;
+
+ /* Main chunk */
+ m = n % bits;
+ n /= bits;
+ while (n >= 4) {
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ n -= 4;
+ }
+ while (n--) {
+ d1 = *src--;
+ *dst-- = d0 >> right | d1 << left;
+ d0 = d1;
+ }
+
+ /* Trailing bits */
+ if (last) {
+ if (m <= left) {
+ /* Single source word */
+ *dst = comp(d0 >> right, *dst, last);
+ } else {
+ /* 2 source words */
+ d1 = *src;
+ *dst = comp(d0 >> right | d1 << left,
+ *dst, last);
+ }
+ }
+ }
+ }
+}
+
+void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
+{
+ u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
+ u32 height = area->height, width = area->width;
+ unsigned long const bits_per_line = p->fix.line_length*8u;
+ unsigned long *dst = NULL, *src = NULL;
+ int bits = BITS_PER_LONG, bytes = bits >> 3;
+ int dst_idx = 0, src_idx = 0, rev_copy = 0;
+
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
+ /* if the beginning of the target area might overlap with the end of
+ the source area, be have to copy the area reverse. */
+ if ((dy == sy && dx > sx) || (dy > sy)) {
+ dy += height;
+ sy += height;
+ rev_copy = 1;
+ }
+
+ /* split the base of the framebuffer into a long-aligned address and
+ the index of the first bit */
+ dst = src = (unsigned long *)((unsigned long)p->screen_base &
+ ~(bytes-1));
+ dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
+ /* add offset of source and target area */
+ dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
+ src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel;
+
+ if (p->fbops->fb_sync)
+ p->fbops->fb_sync(p);
+
+ if (rev_copy) {
+ while (height--) {
+ dst_idx -= bits_per_line;
+ src_idx -= bits_per_line;
+ dst += dst_idx >> (ffs(bits) - 1);
+ dst_idx &= (bytes - 1);
+ src += src_idx >> (ffs(bits) - 1);
+ src_idx &= (bytes - 1);
+ bitcpy_rev(dst, dst_idx, src, src_idx, bits,
+ width*p->var.bits_per_pixel);
+ }
+ } else {
+ while (height--) {
+ dst += dst_idx >> (ffs(bits) - 1);
+ dst_idx &= (bytes - 1);
+ src += src_idx >> (ffs(bits) - 1);
+ src_idx &= (bytes - 1);
+ bitcpy(dst, dst_idx, src, src_idx, bits,
+ width*p->var.bits_per_pixel);
+ dst_idx += bits_per_line;
+ src_idx += bits_per_line;
+ }
+ }
+}
+
+EXPORT_SYMBOL(sys_copyarea);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic copyarea (sys-to-sys)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/sysfillrect.c b/drivers/video/sysfillrect.c
new file mode 100644
index 00000000000..a261e9e6a67
--- /dev/null
+++ b/drivers/video/sysfillrect.c
@@ -0,0 +1,334 @@
+/*
+ * Generic fillrect for frame buffers in system RAM with packed pixels of
+ * any depth.
+ *
+ * Based almost entirely from cfbfillrect.c (which is based almost entirely
+ * on Geert Uytterhoeven's fillrect routine)
+ *
+ * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+#include "fb_draw.h"
+
+ /*
+ * Aligned pattern fill using 32/64-bit memory accesses
+ */
+
+static void
+bitfill_aligned(unsigned long *dst, int dst_idx, unsigned long pat,
+ unsigned n, int bits)
+{
+ unsigned long first, last;
+
+ if (!n)
+ return;
+
+ first = FB_SHIFT_HIGH(~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+ if (dst_idx+n <= bits) {
+ /* Single word */
+ if (last)
+ first &= last;
+ *dst = comp(pat, *dst, first);
+ } else {
+ /* Multiple destination words */
+
+ /* Leading bits */
+ if (first!= ~0UL) {
+ *dst = comp(pat, *dst, first);
+ dst++;
+ n -= bits - dst_idx;
+ }
+
+ /* Main chunk */
+ n /= bits;
+ while (n >= 8) {
+ *dst++ = pat;
+ *dst++ = pat;
+ *dst++ = pat;
+ *dst++ = pat;
+ *dst++ = pat;
+ *dst++ = pat;
+ *dst++ = pat;
+ *dst++ = pat;
+ n -= 8;
+ }
+ while (n--)
+ *dst++ = pat;
+ /* Trailing bits */
+ if (last)
+ *dst = comp(pat, *dst, last);
+ }
+}
+
+
+ /*
+ * Unaligned generic pattern fill using 32/64-bit memory accesses
+ * The pattern must have been expanded to a full 32/64-bit value
+ * Left/right are the appropriate shifts to convert to the pattern to be
+ * used for the next 32/64-bit word
+ */
+
+static void
+bitfill_unaligned(unsigned long *dst, int dst_idx, unsigned long pat,
+ int left, int right, unsigned n, int bits)
+{
+ unsigned long first, last;
+
+ if (!n)
+ return;
+
+ first = FB_SHIFT_HIGH(~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+ if (dst_idx+n <= bits) {
+ /* Single word */
+ if (last)
+ first &= last;
+ *dst = comp(pat, *dst, first);
+ } else {
+ /* Multiple destination words */
+ /* Leading bits */
+ if (first) {
+ *dst = comp(pat, *dst, first);
+ dst++;
+ pat = pat << left | pat >> right;
+ n -= bits - dst_idx;
+ }
+
+ /* Main chunk */
+ n /= bits;
+ while (n >= 4) {
+ *dst++ = pat;
+ pat = pat << left | pat >> right;
+ *dst++ = pat;
+ pat = pat << left | pat >> right;
+ *dst++ = pat;
+ pat = pat << left | pat >> right;
+ *dst++ = pat;
+ pat = pat << left | pat >> right;
+ n -= 4;
+ }
+ while (n--) {
+ *dst++ = pat;
+ pat = pat << left | pat >> right;
+ }
+
+ /* Trailing bits */
+ if (last)
+ *dst = comp(pat, *dst, first);
+ }
+}
+
+ /*
+ * Aligned pattern invert using 32/64-bit memory accesses
+ */
+static void
+bitfill_aligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
+ unsigned n, int bits)
+{
+ unsigned long val = pat;
+ unsigned long first, last;
+
+ if (!n)
+ return;
+
+ first = FB_SHIFT_HIGH(~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+ if (dst_idx+n <= bits) {
+ /* Single word */
+ if (last)
+ first &= last;
+ *dst = comp(*dst ^ val, *dst, first);
+ } else {
+ /* Multiple destination words */
+ /* Leading bits */
+ if (first!=0UL) {
+ *dst = comp(*dst ^ val, *dst, first);
+ dst++;
+ n -= bits - dst_idx;
+ }
+
+ /* Main chunk */
+ n /= bits;
+ while (n >= 8) {
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ *dst++ ^= val;
+ n -= 8;
+ }
+ while (n--)
+ *dst++ ^= val;
+ /* Trailing bits */
+ if (last)
+ *dst = comp(*dst ^ val, *dst, last);
+ }
+}
+
+
+ /*
+ * Unaligned generic pattern invert using 32/64-bit memory accesses
+ * The pattern must have been expanded to a full 32/64-bit value
+ * Left/right are the appropriate shifts to convert to the pattern to be
+ * used for the next 32/64-bit word
+ */
+
+static void
+bitfill_unaligned_rev(unsigned long *dst, int dst_idx, unsigned long pat,
+ int left, int right, unsigned n, int bits)
+{
+ unsigned long first, last;
+
+ if (!n)
+ return;
+
+ first = FB_SHIFT_HIGH(~0UL, dst_idx);
+ last = ~(FB_SHIFT_HIGH(~0UL, (dst_idx+n) % bits));
+
+ if (dst_idx+n <= bits) {
+ /* Single word */
+ if (last)
+ first &= last;
+ *dst = comp(*dst ^ pat, *dst, first);
+ } else {
+ /* Multiple destination words */
+
+ /* Leading bits */
+ if (first != 0UL) {
+ *dst = comp(*dst ^ pat, *dst, first);
+ dst++;
+ pat = pat << left | pat >> right;
+ n -= bits - dst_idx;
+ }
+
+ /* Main chunk */
+ n /= bits;
+ while (n >= 4) {
+ *dst++ ^= pat;
+ pat = pat << left | pat >> right;
+ *dst++ ^= pat;
+ pat = pat << left | pat >> right;
+ *dst++ ^= pat;
+ pat = pat << left | pat >> right;
+ *dst++ ^= pat;
+ pat = pat << left | pat >> right;
+ n -= 4;
+ }
+ while (n--) {
+ *dst ^= pat;
+ pat = pat << left | pat >> right;
+ }
+
+ /* Trailing bits */
+ if (last)
+ *dst = comp(*dst ^ pat, *dst, last);
+ }
+}
+
+void sys_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
+{
+ unsigned long pat, fg;
+ unsigned long width = rect->width, height = rect->height;
+ int bits = BITS_PER_LONG, bytes = bits >> 3;
+ u32 bpp = p->var.bits_per_pixel;
+ unsigned long *dst;
+ int dst_idx, left;
+
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+ p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+ fg = ((u32 *) (p->pseudo_palette))[rect->color];
+ else
+ fg = rect->color;
+
+ pat = pixel_to_pat( bpp, fg);
+
+ dst = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
+ dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8;
+ dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp;
+ /* FIXME For now we support 1-32 bpp only */
+ left = bits % bpp;
+ if (p->fbops->fb_sync)
+ p->fbops->fb_sync(p);
+ if (!left) {
+ void (*fill_op32)(unsigned long *dst, int dst_idx,
+ unsigned long pat, unsigned n, int bits) =
+ NULL;
+
+ switch (rect->rop) {
+ case ROP_XOR:
+ fill_op32 = bitfill_aligned_rev;
+ break;
+ case ROP_COPY:
+ fill_op32 = bitfill_aligned;
+ break;
+ default:
+ printk( KERN_ERR "cfb_fillrect(): unknown rop, "
+ "defaulting to ROP_COPY\n");
+ fill_op32 = bitfill_aligned;
+ break;
+ }
+ while (height--) {
+ dst += dst_idx >> (ffs(bits) - 1);
+ dst_idx &= (bits - 1);
+ fill_op32(dst, dst_idx, pat, width*bpp, bits);
+ dst_idx += p->fix.line_length*8;
+ }
+ } else {
+ int right;
+ int r;
+ int rot = (left-dst_idx) % bpp;
+ void (*fill_op)(unsigned long *dst, int dst_idx,
+ unsigned long pat, int left, int right,
+ unsigned n, int bits) = NULL;
+
+ /* rotate pattern to correct start position */
+ pat = pat << rot | pat >> (bpp-rot);
+
+ right = bpp-left;
+ switch (rect->rop) {
+ case ROP_XOR:
+ fill_op = bitfill_unaligned_rev;
+ break;
+ case ROP_COPY:
+ fill_op = bitfill_unaligned;
+ break;
+ default:
+ printk(KERN_ERR "cfb_fillrect(): unknown rop, "
+ "defaulting to ROP_COPY\n");
+ fill_op = bitfill_unaligned;
+ break;
+ }
+ while (height--) {
+ dst += dst_idx >> (ffs(bits) - 1);
+ dst_idx &= (bits - 1);
+ fill_op(dst, dst_idx, pat, left, right,
+ width*bpp, bits);
+ r = (p->fix.line_length*8) % bpp;
+ pat = pat << (bpp-r) | pat >> r;
+ dst_idx += p->fix.line_length*8;
+ }
+ }
+}
+
+EXPORT_SYMBOL(sys_fillrect);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("Generic fill rectangle (sys-to-sys)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/sysimgblt.c b/drivers/video/sysimgblt.c
new file mode 100644
index 00000000000..bd7e7e9d155
--- /dev/null
+++ b/drivers/video/sysimgblt.c
@@ -0,0 +1,291 @@
+/*
+ * Generic 1-bit or 8-bit source to 1-32 bit destination expansion
+ * for frame buffer located in system RAM with packed pixels of any depth.
+ *
+ * Based almost entirely on cfbimgblt.c
+ *
+ * Copyright (C) April 2007 Antonino Daplas <adaplas@pol.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fb.h>
+#include <asm/types.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__FUNCTION__,## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+static const u32 cfb_tab8[] = {
+#if defined(__BIG_ENDIAN)
+ 0x00000000,0x000000ff,0x0000ff00,0x0000ffff,
+ 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff,
+ 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff,
+ 0xffff0000,0xffff00ff,0xffffff00,0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+ 0x00000000,0xff000000,0x00ff0000,0xffff0000,
+ 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00,
+ 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff,
+ 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static const u32 cfb_tab16[] = {
+#if defined(__BIG_ENDIAN)
+ 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff
+#elif defined(__LITTLE_ENDIAN)
+ 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff
+#else
+#error FIXME: No endianness??
+#endif
+};
+
+static const u32 cfb_tab32[] = {
+ 0x00000000, 0xffffffff
+};
+
+static void color_imageblit(const struct fb_image *image, struct fb_info *p,
+ void *dst1, u32 start_index, u32 pitch_index)
+{
+ /* Draw the penguin */
+ u32 *dst, *dst2;
+ u32 color = 0, val, shift;
+ int i, n, bpp = p->var.bits_per_pixel;
+ u32 null_bits = 32 - bpp;
+ u32 *palette = (u32 *) p->pseudo_palette;
+ const u8 *src = image->data;
+
+ dst2 = dst1;
+ for (i = image->height; i--; ) {
+ n = image->width;
+ dst = dst1;
+ shift = 0;
+ val = 0;
+
+ if (start_index) {
+ u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,
+ start_index));
+ val = *dst & start_mask;
+ shift = start_index;
+ }
+ while (n--) {
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+ p->fix.visual == FB_VISUAL_DIRECTCOLOR )
+ color = palette[*src];
+ else
+ color = *src;
+ color <<= FB_LEFT_POS(bpp);
+ val |= FB_SHIFT_HIGH(color, shift);
+ if (shift >= null_bits) {
+ *dst++ = val;
+
+ val = (shift == null_bits) ? 0 :
+ FB_SHIFT_LOW(color, 32 - shift);
+ }
+ shift += bpp;
+ shift &= (32 - 1);
+ src++;
+ }
+ if (shift) {
+ u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+
+ *dst &= end_mask;
+ *dst |= val;
+ }
+ dst1 += p->fix.line_length;
+ if (pitch_index) {
+ dst2 += p->fix.line_length;
+ dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
+
+ start_index += pitch_index;
+ start_index &= 32 - 1;
+ }
+ }
+}
+
+static void slow_imageblit(const struct fb_image *image, struct fb_info *p,
+ void *dst1, u32 fgcolor, u32 bgcolor,
+ u32 start_index, u32 pitch_index)
+{
+ u32 shift, color = 0, bpp = p->var.bits_per_pixel;
+ u32 *dst, *dst2;
+ u32 val, pitch = p->fix.line_length;
+ u32 null_bits = 32 - bpp;
+ u32 spitch = (image->width+7)/8;
+ const u8 *src = image->data, *s;
+ u32 i, j, l;
+
+ dst2 = dst1;
+ fgcolor <<= FB_LEFT_POS(bpp);
+ bgcolor <<= FB_LEFT_POS(bpp);
+
+ for (i = image->height; i--; ) {
+ shift = val = 0;
+ l = 8;
+ j = image->width;
+ dst = dst1;
+ s = src;
+
+ /* write leading bits */
+ if (start_index) {
+ u32 start_mask = ~(FB_SHIFT_HIGH(~(u32)0,start_index));
+ val = *dst & start_mask;
+ shift = start_index;
+ }
+
+ while (j--) {
+ l--;
+ color = (*s & (1 << l)) ? fgcolor : bgcolor;
+ val |= FB_SHIFT_HIGH(color, shift);
+
+ /* Did the bitshift spill bits to the next long? */
+ if (shift >= null_bits) {
+ *dst++ = val;
+ val = (shift == null_bits) ? 0 :
+ FB_SHIFT_LOW(color,32 - shift);
+ }
+ shift += bpp;
+ shift &= (32 - 1);
+ if (!l) { l = 8; s++; };
+ }
+
+ /* write trailing bits */
+ if (shift) {
+ u32 end_mask = FB_SHIFT_HIGH(~(u32)0, shift);
+
+ *dst &= end_mask;
+ *dst |= val;
+ }
+
+ dst1 += pitch;
+ src += spitch;
+ if (pitch_index) {
+ dst2 += pitch;
+ dst1 = (u8 *)((long)dst2 & ~(sizeof(u32) - 1));
+ start_index += pitch_index;
+ start_index &= 32 - 1;
+ }
+
+ }
+}
+
+/*
+ * fast_imageblit - optimized monochrome color expansion
+ *
+ * Only if: bits_per_pixel == 8, 16, or 32
+ * image->width is divisible by pixel/dword (ppw);
+ * fix->line_legth is divisible by 4;
+ * beginning and end of a scanline is dword aligned
+ */
+static void fast_imageblit(const struct fb_image *image, struct fb_info *p,
+ void *dst1, u32 fgcolor, u32 bgcolor)
+{
+ u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel;
+ u32 ppw = 32/bpp, spitch = (image->width + 7)/8;
+ u32 bit_mask, end_mask, eorx, shift;
+ const char *s = image->data, *src;
+ u32 *dst;
+ const u32 *tab = NULL;
+ int i, j, k;
+
+ switch (bpp) {
+ case 8:
+ tab = cfb_tab8;
+ break;
+ case 16:
+ tab = cfb_tab16;
+ break;
+ case 32:
+ default:
+ tab = cfb_tab32;
+ break;
+ }
+
+ for (i = ppw-1; i--; ) {
+ fgx <<= bpp;
+ bgx <<= bpp;
+ fgx |= fgcolor;
+ bgx |= bgcolor;
+ }
+
+ bit_mask = (1 << ppw) - 1;
+ eorx = fgx ^ bgx;
+ k = image->width/ppw;
+
+ for (i = image->height; i--; ) {
+ dst = dst1;
+ shift = 8;
+ src = s;
+
+ for (j = k; j--; ) {
+ shift -= ppw;
+ end_mask = tab[(*src >> shift) & bit_mask];
+ *dst++ = (end_mask & eorx) ^ bgx;
+ if (!shift) {
+ shift = 8;
+ src++;
+ }
+ }
+ dst1 += p->fix.line_length;
+ s += spitch;
+ }
+}
+
+void sys_imageblit(struct fb_info *p, const struct fb_image *image)
+{
+ u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
+ u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel;
+ u32 width = image->width;
+ u32 dx = image->dx, dy = image->dy;
+ void *dst1;
+
+ if (p->state != FBINFO_STATE_RUNNING)
+ return;
+
+ bitstart = (dy * p->fix.line_length * 8) + (dx * bpp);
+ start_index = bitstart & (32 - 1);
+ pitch_index = (p->fix.line_length & (bpl - 1)) * 8;
+
+ bitstart /= 8;
+ bitstart &= ~(bpl - 1);
+ dst1 = (void __force *)p->screen_base + bitstart;
+
+ if (p->fbops->fb_sync)
+ p->fbops->fb_sync(p);
+
+ if (image->depth == 1) {
+ if (p->fix.visual == FB_VISUAL_TRUECOLOR ||
+ p->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color];
+ bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color];
+ } else {
+ fgcolor = image->fg_color;
+ bgcolor = image->bg_color;
+ }
+
+ if (32 % bpp == 0 && !start_index && !pitch_index &&
+ ((width & (32/bpp-1)) == 0) &&
+ bpp >= 8 && bpp <= 32)
+ fast_imageblit(image, p, dst1, fgcolor, bgcolor);
+ else
+ slow_imageblit(image, p, dst1, fgcolor, bgcolor,
+ start_index, pitch_index);
+ } else
+ color_imageblit(image, p, dst1, start_index, pitch_index);
+}
+
+EXPORT_SYMBOL(sys_imageblit);
+
+MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>");
+MODULE_DESCRIPTION("1-bit/8-bit to 1-32 bit color expansion (sys-to-sys)");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 7478d0e3e21..f0fde6ea7c3 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -5,27 +5,45 @@
* Copyright (C) 1997 Geert Uytterhoeven
* Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
* Copyright (C) 2002 Richard Henderson
+ * Copyright (C) 2006 Maciej W. Rozycki
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+#include <linux/bitrev.h>
#include <linux/delay.h>
-#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/pci.h>
#include <linux/selection.h>
-#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/tc.h>
+
#include <asm/io.h>
+
#include <video/tgafb.h>
+#ifdef CONFIG_PCI
+#define TGA_BUS_PCI(dev) (dev->bus == &pci_bus_type)
+#else
+#define TGA_BUS_PCI(dev) 0
+#endif
+
+#ifdef CONFIG_TC
+#define TGA_BUS_TC(dev) (dev->bus == &tc_bus_type)
+#else
+#define TGA_BUS_TC(dev) 0
+#endif
+
/*
* Local functions.
*/
@@ -41,14 +59,19 @@ static void tgafb_init_fix(struct fb_info *);
static void tgafb_imageblit(struct fb_info *, const struct fb_image *);
static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
+static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
-static int __devinit tgafb_pci_register(struct pci_dev *,
- const struct pci_device_id *);
-static void __devexit tgafb_pci_unregister(struct pci_dev *);
+static int __devinit tgafb_register(struct device *dev);
+static void __devexit tgafb_unregister(struct device *dev);
-static const char *mode_option = "640x480@60";
+static const char *mode_option;
+static const char *mode_option_pci = "640x480@60";
+static const char *mode_option_tc = "1280x1024@72";
+static struct pci_driver tgafb_pci_driver;
+static struct tc_driver tgafb_tc_driver;
+
/*
* Frame buffer operations
*/
@@ -59,15 +82,20 @@ static struct fb_ops tgafb_ops = {
.fb_set_par = tgafb_set_par,
.fb_setcolreg = tgafb_setcolreg,
.fb_blank = tgafb_blank,
+ .fb_pan_display = tgafb_pan_display,
.fb_fillrect = tgafb_fillrect,
.fb_copyarea = tgafb_copyarea,
.fb_imageblit = tgafb_imageblit,
};
+#ifdef CONFIG_PCI
/*
* PCI registration operations
*/
+static int __devinit tgafb_pci_register(struct pci_dev *,
+ const struct pci_device_id *);
+static void __devexit tgafb_pci_unregister(struct pci_dev *);
static struct pci_device_id const tgafb_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA) },
@@ -75,13 +103,68 @@ static struct pci_device_id const tgafb_pci_table[] = {
};
MODULE_DEVICE_TABLE(pci, tgafb_pci_table);
-static struct pci_driver tgafb_driver = {
+static struct pci_driver tgafb_pci_driver = {
.name = "tgafb",
.id_table = tgafb_pci_table,
.probe = tgafb_pci_register,
.remove = __devexit_p(tgafb_pci_unregister),
};
+static int __devinit
+tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ return tgafb_register(&pdev->dev);
+}
+
+static void __devexit
+tgafb_pci_unregister(struct pci_dev *pdev)
+{
+ tgafb_unregister(&pdev->dev);
+}
+#endif /* CONFIG_PCI */
+
+#ifdef CONFIG_TC
+/*
+ * TC registration operations
+ */
+static int __devinit tgafb_tc_register(struct device *);
+static int __devexit tgafb_tc_unregister(struct device *);
+
+static struct tc_device_id const tgafb_tc_table[] = {
+ { "DEC ", "PMAGD-AA" },
+ { "DEC ", "PMAGD " },
+ { }
+};
+MODULE_DEVICE_TABLE(tc, tgafb_tc_table);
+
+static struct tc_driver tgafb_tc_driver = {
+ .id_table = tgafb_tc_table,
+ .driver = {
+ .name = "tgafb",
+ .bus = &tc_bus_type,
+ .probe = tgafb_tc_register,
+ .remove = __devexit_p(tgafb_tc_unregister),
+ },
+};
+
+static int __devinit
+tgafb_tc_register(struct device *dev)
+{
+ int status = tgafb_register(dev);
+ if (!status)
+ get_device(dev);
+ return status;
+}
+
+static int __devexit
+tgafb_tc_unregister(struct device *dev)
+{
+ put_device(dev);
+ tgafb_unregister(dev);
+ return 0;
+}
+#endif /* CONFIG_TC */
+
/**
* tgafb_check_var - Optional function. Validates a var passed in.
@@ -132,10 +215,10 @@ static int
tgafb_set_par(struct fb_info *info)
{
static unsigned int const deep_presets[4] = {
- 0x00014000,
- 0x0001440d,
+ 0x00004000,
+ 0x0000440d,
0xffffffff,
- 0x0001441d
+ 0x0000441d
};
static unsigned int const rasterop_presets[4] = {
0x00000003,
@@ -157,6 +240,8 @@ tgafb_set_par(struct fb_info *info)
};
struct tga_par *par = (struct tga_par *) info->par;
+ int tga_bus_pci = TGA_BUS_PCI(par->dev);
+ int tga_bus_tc = TGA_BUS_TC(par->dev);
u32 htimings, vtimings, pll_freq;
u8 tga_type;
int i;
@@ -221,7 +306,7 @@ tgafb_set_par(struct fb_info *info)
TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
/* Initalise RAMDAC. */
- if (tga_type == TGA_TYPE_8PLANE) {
+ if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
/* Init BT485 RAMDAC registers. */
BT485_WRITE(par, 0xa2 | (par->sync_on_green ? 0x8 : 0x0),
@@ -236,21 +321,7 @@ tgafb_set_par(struct fb_info *info)
BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
-#ifdef CONFIG_HW_CONSOLE
- for (i = 0; i < 16; i++) {
- int j = color_table[i];
-
- TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
- TGA_RAMDAC_REG);
- TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
- TGA_RAMDAC_REG);
- }
- for (i = 0; i < 240 * 3; i += 4) {
-#else
for (i = 0; i < 256 * 3; i += 4) {
-#endif
TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8),
TGA_RAMDAC_REG);
TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
@@ -261,6 +332,27 @@ tgafb_set_par(struct fb_info *info)
TGA_RAMDAC_REG);
}
+ } else if (tga_type == TGA_TYPE_8PLANE && tga_bus_tc) {
+
+ /* Init BT459 RAMDAC registers. */
+ BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_0, 0x40);
+ BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_1, 0x00);
+ BT459_WRITE(par, BT459_REG_ACC, BT459_CMD_REG_2,
+ (par->sync_on_green ? 0xc0 : 0x40));
+
+ BT459_WRITE(par, BT459_REG_ACC, BT459_CUR_CMD_REG, 0x00);
+
+ /* Fill the palette. */
+ BT459_LOAD_ADDR(par, 0x0000);
+ TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+
+ for (i = 0; i < 256 * 3; i += 4) {
+ TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
+ }
+
} else { /* 24-plane or 24plusZ */
/* Init BT463 RAMDAC registers. */
@@ -431,6 +523,8 @@ tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
struct tga_par *par = (struct tga_par *) info->par;
+ int tga_bus_pci = TGA_BUS_PCI(par->dev);
+ int tga_bus_tc = TGA_BUS_TC(par->dev);
if (regno > 255)
return 1;
@@ -438,12 +532,18 @@ tgafb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
green >>= 8;
blue >>= 8;
- if (par->tga_type == TGA_TYPE_8PLANE) {
+ if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
BT485_WRITE(par, regno, BT485_ADDR_PAL_WRITE);
TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
TGA_WRITE_REG(par, red|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
TGA_WRITE_REG(par, green|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
TGA_WRITE_REG(par, blue|(BT485_DATA_PAL<<8),TGA_RAMDAC_REG);
+ } else if (par->tga_type == TGA_TYPE_8PLANE && tga_bus_tc) {
+ BT459_LOAD_ADDR(par, regno);
+ TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, red, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, green, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, blue, TGA_RAMDAC_REG);
} else {
if (regno < 16) {
u32 value = (regno << 16) | (regno << 8) | regno;
@@ -523,16 +623,8 @@ tgafb_blank(int blank, struct fb_info *info)
* Acceleration.
*/
-/**
- * tgafb_imageblit - REQUIRED function. Can use generic routines if
- * non acclerated hardware and packed pixel based.
- * Copies a image from system memory to the screen.
- *
- * @info: frame buffer structure that represents a single frame buffer
- * @image: structure defining the image.
- */
static void
-tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct tga_par *par = (struct tga_par *) info->par;
u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
@@ -542,6 +634,17 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
void __iomem *regs_base;
void __iomem *fb_base;
+ is8bpp = info->var.bits_per_pixel == 8;
+
+ /* For copies that aren't pixel expansion, there's little we
+ can do better than the generic code. */
+ /* ??? There is a DMA write mode; I wonder if that could be
+ made to pull the data from the image buffer... */
+ if (image->depth > 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+
dx = image->dx;
dy = image->dy;
width = image->width;
@@ -559,18 +662,8 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
if (dy + height > vyres)
height = vyres - dy;
- /* For copies that aren't pixel expansion, there's little we
- can do better than the generic code. */
- /* ??? There is a DMA write mode; I wonder if that could be
- made to pull the data from the image buffer... */
- if (image->depth > 1) {
- cfb_imageblit(info, image);
- return;
- }
-
regs_base = par->tga_regs_base;
fb_base = par->tga_fb_base;
- is8bpp = info->var.bits_per_pixel == 8;
/* Expand the color values to fill 32-bits. */
/* ??? Would be nice to notice colour changes elsewhere, so
@@ -748,6 +841,85 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
regs_base + TGA_MODE_REG);
}
+static void
+tgafb_clut_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct tga_par *par = (struct tga_par *) info->par;
+ u32 color, dx, dy, width, height, vxres, vyres;
+ u32 *palette = ((u32 *)info->pseudo_palette);
+ unsigned long pos, line_length, i, j;
+ const unsigned char *data;
+ void *regs_base, *fb_base;
+
+ dx = image->dx;
+ dy = image->dy;
+ width = image->width;
+ height = image->height;
+ vxres = info->var.xres_virtual;
+ vyres = info->var.yres_virtual;
+ line_length = info->fix.line_length;
+
+ /* Crop the image to the screen. */
+ if (dx > vxres || dy > vyres)
+ return;
+ if (dx + width > vxres)
+ width = vxres - dx;
+ if (dy + height > vyres)
+ height = vyres - dy;
+
+ regs_base = par->tga_regs_base;
+ fb_base = par->tga_fb_base;
+
+ pos = dy * line_length + (dx * 4);
+ data = image->data;
+
+ /* Now copy the image, color_expanding via the palette. */
+ for (i = 0; i < height; i++) {
+ for (j = 0; j < width; j++) {
+ color = palette[*data++];
+ __raw_writel(color, fb_base + pos + j*4);
+ }
+ pos += line_length;
+ }
+}
+
+/**
+ * tgafb_imageblit - REQUIRED function. Can use generic routines if
+ * non acclerated hardware and packed pixel based.
+ * Copies a image from system memory to the screen.
+ *
+ * @info: frame buffer structure that represents a single frame buffer
+ * @image: structure defining the image.
+ */
+static void
+tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ unsigned int is8bpp = info->var.bits_per_pixel == 8;
+
+ /* If a mono image, regardless of FB depth, go do it. */
+ if (image->depth == 1) {
+ tgafb_mono_imageblit(info, image);
+ return;
+ }
+
+ /* For copies that aren't pixel expansion, there's little we
+ can do better than the generic code. */
+ /* ??? There is a DMA write mode; I wonder if that could be
+ made to pull the data from the image buffer... */
+ if (image->depth == info->var.bits_per_pixel) {
+ cfb_imageblit(info, image);
+ return;
+ }
+
+ /* If 24-plane FB and the image is 8-plane with CLUT, we can do it. */
+ if (!is8bpp && image->depth == 8) {
+ tgafb_clut_imageblit(info, image);
+ return;
+ }
+
+ /* Silently return... */
+}
+
/**
* tgafb_fillrect - REQUIRED function. Can use generic routines if
* non acclerated hardware and packed pixel based.
@@ -1309,18 +1481,29 @@ static void
tgafb_init_fix(struct fb_info *info)
{
struct tga_par *par = (struct tga_par *)info->par;
+ int tga_bus_pci = TGA_BUS_PCI(par->dev);
+ int tga_bus_tc = TGA_BUS_TC(par->dev);
u8 tga_type = par->tga_type;
- const char *tga_type_name;
+ const char *tga_type_name = NULL;
switch (tga_type) {
case TGA_TYPE_8PLANE:
- tga_type_name = "Digital ZLXp-E1";
+ if (tga_bus_pci)
+ tga_type_name = "Digital ZLXp-E1";
+ if (tga_bus_tc)
+ tga_type_name = "Digital ZLX-E1";
break;
case TGA_TYPE_24PLANE:
- tga_type_name = "Digital ZLXp-E2";
+ if (tga_bus_pci)
+ tga_type_name = "Digital ZLXp-E2";
+ if (tga_bus_tc)
+ tga_type_name = "Digital ZLX-E2";
break;
case TGA_TYPE_24PLUSZ:
- tga_type_name = "Digital ZLXp-E3";
+ if (tga_bus_pci)
+ tga_type_name = "Digital ZLXp-E3";
+ if (tga_bus_tc)
+ tga_type_name = "Digital ZLX-E3";
break;
default:
tga_type_name = "Unknown";
@@ -1346,11 +1529,37 @@ tgafb_init_fix(struct fb_info *info)
info->fix.ywrapstep = 0;
info->fix.accel = FB_ACCEL_DEC_TGA;
+
+ /*
+ * These are needed by fb_set_logo_truepalette(), so we
+ * set them here for 24-plane cards.
+ */
+ if (tga_type != TGA_TYPE_8PLANE) {
+ info->var.red.length = 8;
+ info->var.green.length = 8;
+ info->var.blue.length = 8;
+ info->var.red.offset = 16;
+ info->var.green.offset = 8;
+ info->var.blue.offset = 0;
+ }
}
-static __devinit int
-tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ /* We just use this to catch switches out of graphics mode. */
+ tgafb_set_par(info); /* A bit of overkill for BASE_ADDR reset. */
+ return 0;
+}
+
+static int __devinit
+tgafb_register(struct device *dev)
{
+ static const struct fb_videomode modedb_tc = {
+ /* 1280x1024 @ 72 Hz, 76.8 kHz hsync */
+ "1280x1024@72", 0, 1280, 1024, 7645, 224, 28, 33, 3, 160, 3,
+ FB_SYNC_ON_GREEN, FB_VMODE_NONINTERLACED
+ };
+
static unsigned int const fb_offset_presets[4] = {
TGA_8PLANE_FB_OFFSET,
TGA_24PLANE_FB_OFFSET,
@@ -1358,40 +1567,51 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
TGA_24PLUSZ_FB_OFFSET
};
+ const struct fb_videomode *modedb_tga = NULL;
+ resource_size_t bar0_start = 0, bar0_len = 0;
+ const char *mode_option_tga = NULL;
+ int tga_bus_pci = TGA_BUS_PCI(dev);
+ int tga_bus_tc = TGA_BUS_TC(dev);
+ unsigned int modedbsize_tga = 0;
void __iomem *mem_base;
- unsigned long bar0_start, bar0_len;
struct fb_info *info;
struct tga_par *par;
u8 tga_type;
- int ret;
+ int ret = 0;
/* Enable device in PCI config. */
- if (pci_enable_device(pdev)) {
+ if (tga_bus_pci && pci_enable_device(to_pci_dev(dev))) {
printk(KERN_ERR "tgafb: Cannot enable PCI device\n");
return -ENODEV;
}
/* Allocate the fb and par structures. */
- info = framebuffer_alloc(sizeof(struct tga_par), &pdev->dev);
+ info = framebuffer_alloc(sizeof(struct tga_par), dev);
if (!info) {
printk(KERN_ERR "tgafb: Cannot allocate memory\n");
return -ENOMEM;
}
par = info->par;
- pci_set_drvdata(pdev, info);
+ dev_set_drvdata(dev, info);
/* Request the mem regions. */
- bar0_start = pci_resource_start(pdev, 0);
- bar0_len = pci_resource_len(pdev, 0);
ret = -ENODEV;
+ if (tga_bus_pci) {
+ bar0_start = pci_resource_start(to_pci_dev(dev), 0);
+ bar0_len = pci_resource_len(to_pci_dev(dev), 0);
+ }
+ if (tga_bus_tc) {
+ bar0_start = to_tc_dev(dev)->resource.start;
+ bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1;
+ }
if (!request_mem_region (bar0_start, bar0_len, "tgafb")) {
printk(KERN_ERR "tgafb: cannot reserve FB region\n");
goto err0;
}
/* Map the framebuffer. */
- mem_base = ioremap(bar0_start, bar0_len);
+ mem_base = ioremap_nocache(bar0_start, bar0_len);
if (!mem_base) {
printk(KERN_ERR "tgafb: Cannot map MMIO\n");
goto err1;
@@ -1399,12 +1619,16 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Grab info about the card. */
tga_type = (readl(mem_base) >> 12) & 0x0f;
- par->pdev = pdev;
+ par->dev = dev;
par->tga_mem_base = mem_base;
par->tga_fb_base = mem_base + fb_offset_presets[tga_type];
par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
par->tga_type = tga_type;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &par->tga_chip_rev);
+ if (tga_bus_pci)
+ pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID,
+ &par->tga_chip_rev);
+ if (tga_bus_tc)
+ par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff;
/* Setup framebuffer. */
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA |
@@ -1414,8 +1638,17 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
info->pseudo_palette = (void *)(par + 1);
/* This should give a reasonable default video mode. */
-
- ret = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL,
+ if (tga_bus_pci) {
+ mode_option_tga = mode_option_pci;
+ }
+ if (tga_bus_tc) {
+ mode_option_tga = mode_option_tc;
+ modedb_tga = &modedb_tc;
+ modedbsize_tga = 1;
+ }
+ ret = fb_find_mode(&info->var, info,
+ mode_option ? mode_option : mode_option_tga,
+ modedb_tga, modedbsize_tga, NULL,
tga_type == TGA_TYPE_8PLANE ? 8 : 32);
if (ret == 0 || ret == 4) {
printk(KERN_ERR "tgafb: Could not find valid video mode\n");
@@ -1438,13 +1671,19 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err1;
}
- printk(KERN_INFO "tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
- par->tga_chip_rev);
- printk(KERN_INFO "tgafb: at PCI bus %d, device %d, function %d\n",
- pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
- printk(KERN_INFO "fb%d: %s frame buffer device at 0x%lx\n",
- info->node, info->fix.id, bar0_start);
+ if (tga_bus_pci) {
+ pr_info("tgafb: DC21030 [TGA] detected, rev=0x%02x\n",
+ par->tga_chip_rev);
+ pr_info("tgafb: at PCI bus %d, device %d, function %d\n",
+ to_pci_dev(dev)->bus->number,
+ PCI_SLOT(to_pci_dev(dev)->devfn),
+ PCI_FUNC(to_pci_dev(dev)->devfn));
+ }
+ if (tga_bus_tc)
+ pr_info("tgafb: SFB+ detected, rev=0x%02x\n",
+ par->tga_chip_rev);
+ pr_info("fb%d: %s frame buffer device at 0x%lx\n",
+ info->node, info->fix.id, (long)bar0_start);
return 0;
@@ -1458,25 +1697,39 @@ tgafb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
}
static void __devexit
-tgafb_pci_unregister(struct pci_dev *pdev)
+tgafb_unregister(struct device *dev)
{
- struct fb_info *info = pci_get_drvdata(pdev);
- struct tga_par *par = info->par;
+ resource_size_t bar0_start = 0, bar0_len = 0;
+ int tga_bus_pci = TGA_BUS_PCI(dev);
+ int tga_bus_tc = TGA_BUS_TC(dev);
+ struct fb_info *info = NULL;
+ struct tga_par *par;
+ info = dev_get_drvdata(dev);
if (!info)
return;
+
+ par = info->par;
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
iounmap(par->tga_mem_base);
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
+ if (tga_bus_pci) {
+ bar0_start = pci_resource_start(to_pci_dev(dev), 0);
+ bar0_len = pci_resource_len(to_pci_dev(dev), 0);
+ }
+ if (tga_bus_tc) {
+ bar0_start = to_tc_dev(dev)->resource.start;
+ bar0_len = to_tc_dev(dev)->resource.end - bar0_start + 1;
+ }
+ release_mem_region(bar0_start, bar0_len);
framebuffer_release(info);
}
static void __devexit
tgafb_exit(void)
{
- pci_unregister_driver(&tgafb_driver);
+ tc_unregister_driver(&tgafb_tc_driver);
+ pci_unregister_driver(&tgafb_pci_driver);
}
#ifndef MODULE
@@ -1505,6 +1758,7 @@ tgafb_setup(char *arg)
static int __devinit
tgafb_init(void)
{
+ int status;
#ifndef MODULE
char *option = NULL;
@@ -1512,7 +1766,10 @@ tgafb_init(void)
return -ENODEV;
tgafb_setup(option);
#endif
- return pci_register_driver(&tgafb_driver);
+ status = pci_register_driver(&tgafb_pci_driver);
+ if (!status)
+ status = tc_register_driver(&tgafb_tc_driver);
+ return status;
}
/*
@@ -1522,5 +1779,5 @@ tgafb_init(void)
module_init(tgafb_init);
module_exit(tgafb_exit);
-MODULE_DESCRIPTION("framebuffer driver for TGA chipset");
+MODULE_DESCRIPTION("Framebuffer driver for TGA/SFB+ chipset");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 06fc19a6119..ad66f070acb 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -51,7 +51,6 @@
#include <linux/fb.h>
#include <linux/selection.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <linux/nvram.h>
#include <linux/adb.h>
#include <linux/cuda.h>
diff --git a/drivers/video/vermilion/Makefile b/drivers/video/vermilion/Makefile
new file mode 100644
index 00000000000..cc21a656153
--- /dev/null
+++ b/drivers/video/vermilion/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_FB_LE80578) += vmlfb.o
+obj-$(CONFIG_FB_CARILLO_RANCH) += crvml.o
+
+vmlfb-objs := vermilion.o
+crvml-objs := cr_pll.o
diff --git a/drivers/video/vermilion/cr_pll.c b/drivers/video/vermilion/cr_pll.c
new file mode 100644
index 00000000000..ebc6e6e0dd0
--- /dev/null
+++ b/drivers/video/vermilion/cr_pll.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Carillo Ranch video subsystem driver.
+ * The Carillo Ranch video subsystem driver 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 Carillo Ranch video subsystem driver 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 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include "vermilion.h"
+
+/* The PLL Clock register sits on Host bridge */
+#define CRVML_DEVICE_MCH 0x5001
+#define CRVML_REG_MCHBAR 0x44
+#define CRVML_REG_MCHEN 0x54
+#define CRVML_MCHEN_BIT (1 << 28)
+#define CRVML_MCHMAP_SIZE 4096
+#define CRVML_REG_CLOCK 0xc3c
+#define CRVML_CLOCK_SHIFT 8
+#define CRVML_CLOCK_MASK 0x00000f00
+
+static struct pci_dev *mch_dev;
+static u32 mch_bar;
+static void __iomem *mch_regs_base;
+static u32 saved_clock;
+
+static const unsigned crvml_clocks[] = {
+ 6750,
+ 13500,
+ 27000,
+ 29700,
+ 37125,
+ 54000,
+ 59400,
+ 74250,
+ 120000
+ /*
+ * There are more clocks, but they are disabled on the CR board.
+ */
+};
+
+static const u32 crvml_clock_bits[] = {
+ 0x0a,
+ 0x09,
+ 0x08,
+ 0x07,
+ 0x06,
+ 0x05,
+ 0x04,
+ 0x03,
+ 0x0b
+};
+
+static const unsigned crvml_num_clocks = ARRAY_SIZE(crvml_clocks);
+
+static int crvml_sys_restore(struct vml_sys *sys)
+{
+ void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
+
+ iowrite32(saved_clock, clock_reg);
+ ioread32(clock_reg);
+
+ return 0;
+}
+
+static int crvml_sys_save(struct vml_sys *sys)
+{
+ void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
+
+ saved_clock = ioread32(clock_reg);
+
+ return 0;
+}
+
+static int crvml_nearest_index(const struct vml_sys *sys, int clock)
+{
+ int i;
+ int cur_index = 0;
+ int cur_diff;
+ int diff;
+
+ cur_diff = clock - crvml_clocks[0];
+ cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
+ for (i = 1; i < crvml_num_clocks; ++i) {
+ diff = clock - crvml_clocks[i];
+ diff = (diff < 0) ? -diff : diff;
+ if (diff < cur_diff) {
+ cur_index = i;
+ cur_diff = diff;
+ }
+ }
+ return cur_index;
+}
+
+static int crvml_nearest_clock(const struct vml_sys *sys, int clock)
+{
+ return crvml_clocks[crvml_nearest_index(sys, clock)];
+}
+
+static int crvml_set_clock(struct vml_sys *sys, int clock)
+{
+ void __iomem *clock_reg = mch_regs_base + CRVML_REG_CLOCK;
+ int index;
+ u32 clock_val;
+
+ index = crvml_nearest_index(sys, clock);
+
+ if (crvml_clocks[index] != clock)
+ return -EINVAL;
+
+ clock_val = ioread32(clock_reg) & ~CRVML_CLOCK_MASK;
+ clock_val = crvml_clock_bits[index] << CRVML_CLOCK_SHIFT;
+ iowrite32(clock_val, clock_reg);
+ ioread32(clock_reg);
+
+ return 0;
+}
+
+static struct vml_sys cr_pll_ops = {
+ .name = "Carillo Ranch",
+ .save = crvml_sys_save,
+ .restore = crvml_sys_restore,
+ .set_clock = crvml_set_clock,
+ .nearest_clock = crvml_nearest_clock,
+};
+
+static int __init cr_pll_init(void)
+{
+ int err;
+ u32 dev_en;
+
+ mch_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ CRVML_DEVICE_MCH, NULL);
+ if (!mch_dev) {
+ printk(KERN_ERR
+ "Could not find Carillo Ranch MCH device.\n");
+ return -ENODEV;
+ }
+
+ pci_read_config_dword(mch_dev, CRVML_REG_MCHEN, &dev_en);
+ if (!(dev_en & CRVML_MCHEN_BIT)) {
+ printk(KERN_ERR
+ "Carillo Ranch MCH device was not enabled.\n");
+ pci_dev_put(mch_dev);
+ return -ENODEV;
+ }
+
+ pci_read_config_dword(mch_dev, CRVML_REG_MCHBAR,
+ &mch_bar);
+ mch_regs_base =
+ ioremap_nocache(mch_bar, CRVML_MCHMAP_SIZE);
+ if (!mch_regs_base) {
+ printk(KERN_ERR
+ "Carillo Ranch MCH device was not enabled.\n");
+ pci_dev_put(mch_dev);
+ return -ENODEV;
+ }
+
+ err = vmlfb_register_subsys(&cr_pll_ops);
+ if (err) {
+ printk(KERN_ERR
+ "Carillo Ranch failed to initialize vml_sys.\n");
+ pci_dev_put(mch_dev);
+ return err;
+ }
+
+ return 0;
+}
+
+static void __exit cr_pll_exit(void)
+{
+ vmlfb_unregister_subsys(&cr_pll_ops);
+
+ iounmap(mch_regs_base);
+ pci_dev_put(mch_dev);
+}
+
+module_init(cr_pll_init);
+module_exit(cr_pll_exit);
+
+MODULE_AUTHOR("Tungsten Graphics Inc.");
+MODULE_DESCRIPTION("Carillo Ranch PLL Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c
new file mode 100644
index 00000000000..de531c90771
--- /dev/null
+++ b/drivers/video/vermilion/vermilion.c
@@ -0,0 +1,1195 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Vermilion Range fb driver.
+ * The Vermilion Range fb driver 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 Vermilion Range fb driver 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 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ * Michel Dänzer <michel-at-tungstengraphics-dot-com>
+ * Alan Hourihane <alanh-at-tungstengraphics-dot-com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <linux/mmzone.h>
+#include <asm/uaccess.h>
+
+/* #define VERMILION_DEBUG */
+
+#include "vermilion.h"
+
+#define MODULE_NAME "vmlfb"
+
+#define VML_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
+
+static struct mutex vml_mutex;
+static struct list_head global_no_mode;
+static struct list_head global_has_mode;
+static struct fb_ops vmlfb_ops;
+static struct vml_sys *subsys = NULL;
+static char *vml_default_mode = "1024x768@60";
+static struct fb_videomode defaultmode = {
+ NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6,
+ 0, FB_VMODE_NONINTERLACED
+};
+
+static u32 vml_mem_requested = (10 * 1024 * 1024);
+static u32 vml_mem_contig = (4 * 1024 * 1024);
+static u32 vml_mem_min = (4 * 1024 * 1024);
+
+static u32 vml_clocks[] = {
+ 6750,
+ 13500,
+ 27000,
+ 29700,
+ 37125,
+ 54000,
+ 59400,
+ 74250,
+ 120000,
+ 148500
+};
+
+static u32 vml_num_clocks = ARRAY_SIZE(vml_clocks);
+
+/*
+ * Allocate a contiguous vram area and make its linear kernel map
+ * uncached.
+ */
+
+static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
+ unsigned min_order)
+{
+ gfp_t flags;
+ unsigned long i;
+ pgprot_t wc_pageprot;
+
+ wc_pageprot = PAGE_KERNEL_NOCACHE;
+ max_order++;
+ do {
+ /*
+ * Really try hard to get the needed memory.
+ * We need memory below the first 32MB, so we
+ * add the __GFP_DMA flag that guarantees that we are
+ * below the first 16MB.
+ */
+
+ flags = __GFP_DMA | __GFP_HIGH;
+ va->logical =
+ __get_free_pages(flags, --max_order);
+ } while (va->logical == 0 && max_order > min_order);
+
+ if (!va->logical)
+ return -ENOMEM;
+
+ va->phys = virt_to_phys((void *)va->logical);
+ va->size = PAGE_SIZE << max_order;
+ va->order = max_order;
+
+ /*
+ * It seems like __get_free_pages only ups the usage count
+ * of the first page. This doesn't work with nopage mapping, so
+ * up the usage count once more.
+ */
+
+ memset((void *)va->logical, 0x00, va->size);
+ for (i = va->logical; i < va->logical + va->size; i += PAGE_SIZE) {
+ get_page(virt_to_page(i));
+ }
+
+ /*
+ * Change caching policy of the linear kernel map to avoid
+ * mapping type conflicts with user-space mappings.
+ * The first global_flush_tlb() is really only there to do a global
+ * wbinvd().
+ */
+
+ global_flush_tlb();
+ change_page_attr(virt_to_page(va->logical), va->size >> PAGE_SHIFT,
+ wc_pageprot);
+ global_flush_tlb();
+
+ printk(KERN_DEBUG MODULE_NAME
+ ": Allocated %ld bytes vram area at 0x%08lx\n",
+ va->size, va->phys);
+
+ return 0;
+}
+
+/*
+ * Free a contiguous vram area and reset its linear kernel map
+ * mapping type.
+ */
+
+static void vmlfb_free_vram_area(struct vram_area *va)
+{
+ unsigned long j;
+
+ if (va->logical) {
+
+ /*
+ * Reset the linear kernel map caching policy.
+ */
+
+ change_page_attr(virt_to_page(va->logical),
+ va->size >> PAGE_SHIFT, PAGE_KERNEL);
+ global_flush_tlb();
+
+ /*
+ * Decrease the usage count on the pages we've used
+ * to compensate for upping when allocating.
+ */
+
+ for (j = va->logical; j < va->logical + va->size;
+ j += PAGE_SIZE) {
+ (void)put_page_testzero(virt_to_page(j));
+ }
+
+ printk(KERN_DEBUG MODULE_NAME
+ ": Freeing %ld bytes vram area at 0x%08lx\n",
+ va->size, va->phys);
+ free_pages(va->logical, va->order);
+
+ va->logical = 0;
+ }
+}
+
+/*
+ * Free allocated vram.
+ */
+
+static void vmlfb_free_vram(struct vml_info *vinfo)
+{
+ int i;
+
+ for (i = 0; i < vinfo->num_areas; ++i) {
+ vmlfb_free_vram_area(&vinfo->vram[i]);
+ }
+ vinfo->num_areas = 0;
+}
+
+/*
+ * Allocate vram. Currently we try to allocate contiguous areas from the
+ * __GFP_DMA zone and puzzle them together. A better approach would be to
+ * allocate one contiguous area for scanout and use one-page allocations for
+ * offscreen areas. This requires user-space and GPU virtual mappings.
+ */
+
+static int vmlfb_alloc_vram(struct vml_info *vinfo,
+ size_t requested,
+ size_t min_total, size_t min_contig)
+{
+ int i, j;
+ int order;
+ int contiguous;
+ int err;
+ struct vram_area *va;
+ struct vram_area *va2;
+
+ vinfo->num_areas = 0;
+ for (i = 0; i < VML_VRAM_AREAS; ++i) {
+ va = &vinfo->vram[i];
+ order = 0;
+
+ while (requested > (PAGE_SIZE << order) && order < MAX_ORDER)
+ order++;
+
+ err = vmlfb_alloc_vram_area(va, order, 0);
+
+ if (err)
+ break;
+
+ if (i == 0) {
+ vinfo->vram_start = va->phys;
+ vinfo->vram_logical = (void __iomem *) va->logical;
+ vinfo->vram_contig_size = va->size;
+ vinfo->num_areas = 1;
+ } else {
+ contiguous = 0;
+
+ for (j = 0; j < i; ++j) {
+ va2 = &vinfo->vram[j];
+ if (va->phys + va->size == va2->phys ||
+ va2->phys + va2->size == va->phys) {
+ contiguous = 1;
+ break;
+ }
+ }
+
+ if (contiguous) {
+ vinfo->num_areas++;
+ if (va->phys < vinfo->vram_start) {
+ vinfo->vram_start = va->phys;
+ vinfo->vram_logical =
+ (void __iomem *)va->logical;
+ }
+ vinfo->vram_contig_size += va->size;
+ } else {
+ vmlfb_free_vram_area(va);
+ break;
+ }
+ }
+
+ if (requested < va->size)
+ break;
+ else
+ requested -= va->size;
+ }
+
+ if (vinfo->vram_contig_size > min_total &&
+ vinfo->vram_contig_size > min_contig) {
+
+ printk(KERN_DEBUG MODULE_NAME
+ ": Contiguous vram: %ld bytes at physical 0x%08lx.\n",
+ (unsigned long)vinfo->vram_contig_size,
+ (unsigned long)vinfo->vram_start);
+
+ return 0;
+ }
+
+ printk(KERN_ERR MODULE_NAME
+ ": Could not allocate requested minimal amount of vram.\n");
+
+ vmlfb_free_vram(vinfo);
+
+ return -ENOMEM;
+}
+
+/*
+ * Find the GPU to use with our display controller.
+ */
+
+static int vmlfb_get_gpu(struct vml_par *par)
+{
+ mutex_lock(&vml_mutex);
+
+ par->gpu = pci_get_device(PCI_VENDOR_ID_INTEL, VML_DEVICE_GPU, NULL);
+
+ if (!par->gpu) {
+ mutex_unlock(&vml_mutex);
+ return -ENODEV;
+ }
+
+ mutex_unlock(&vml_mutex);
+
+ if (pci_enable_device(par->gpu) < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+/*
+ * Find a contiguous vram area that contains a given offset from vram start.
+ */
+static int vmlfb_vram_offset(struct vml_info *vinfo, unsigned long offset)
+{
+ unsigned long aoffset;
+ unsigned i;
+
+ for (i = 0; i < vinfo->num_areas; ++i) {
+ aoffset = offset - (vinfo->vram[i].phys - vinfo->vram_start);
+
+ if (aoffset < vinfo->vram[i].size) {
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Remap the MMIO register spaces of the VDC and the GPU.
+ */
+
+static int vmlfb_enable_mmio(struct vml_par *par)
+{
+ int err;
+
+ par->vdc_mem_base = pci_resource_start(par->vdc, 0);
+ par->vdc_mem_size = pci_resource_len(par->vdc, 0);
+ if (!request_mem_region(par->vdc_mem_base, par->vdc_mem_size, "vmlfb")) {
+ printk(KERN_ERR MODULE_NAME
+ ": Could not claim display controller MMIO.\n");
+ return -EBUSY;
+ }
+ par->vdc_mem = ioremap_nocache(par->vdc_mem_base, par->vdc_mem_size);
+ if (par->vdc_mem == NULL) {
+ printk(KERN_ERR MODULE_NAME
+ ": Could not map display controller MMIO.\n");
+ err = -ENOMEM;
+ goto out_err_0;
+ }
+
+ par->gpu_mem_base = pci_resource_start(par->gpu, 0);
+ par->gpu_mem_size = pci_resource_len(par->gpu, 0);
+ if (!request_mem_region(par->gpu_mem_base, par->gpu_mem_size, "vmlfb")) {
+ printk(KERN_ERR MODULE_NAME ": Could not claim GPU MMIO.\n");
+ err = -EBUSY;
+ goto out_err_1;
+ }
+ par->gpu_mem = ioremap_nocache(par->gpu_mem_base, par->gpu_mem_size);
+ if (par->gpu_mem == NULL) {
+ printk(KERN_ERR MODULE_NAME ": Could not map GPU MMIO.\n");
+ err = -ENOMEM;
+ goto out_err_2;
+ }
+
+ return 0;
+
+out_err_2:
+ release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
+out_err_1:
+ iounmap(par->vdc_mem);
+out_err_0:
+ release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
+ return err;
+}
+
+/*
+ * Unmap the VDC and GPU register spaces.
+ */
+
+static void vmlfb_disable_mmio(struct vml_par *par)
+{
+ iounmap(par->gpu_mem);
+ release_mem_region(par->gpu_mem_base, par->gpu_mem_size);
+ iounmap(par->vdc_mem);
+ release_mem_region(par->vdc_mem_base, par->vdc_mem_size);
+}
+
+/*
+ * Release and uninit the VDC and GPU.
+ */
+
+static void vmlfb_release_devices(struct vml_par *par)
+{
+ if (atomic_dec_and_test(&par->refcount)) {
+ pci_set_drvdata(par->vdc, NULL);
+ pci_disable_device(par->gpu);
+ pci_disable_device(par->vdc);
+ }
+}
+
+/*
+ * Free up allocated resources for a device.
+ */
+
+static void __devexit vml_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info;
+ struct vml_info *vinfo;
+ struct vml_par *par;
+
+ info = pci_get_drvdata(dev);
+ if (info) {
+ vinfo = container_of(info, struct vml_info, info);
+ par = vinfo->par;
+ mutex_lock(&vml_mutex);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ vmlfb_free_vram(vinfo);
+ vmlfb_disable_mmio(par);
+ vmlfb_release_devices(par);
+ kfree(vinfo);
+ kfree(par);
+ mutex_unlock(&vml_mutex);
+ }
+}
+
+static void vmlfb_set_pref_pixel_format(struct fb_var_screeninfo *var)
+{
+ switch (var->bits_per_pixel) {
+ case 16:
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ break;
+ case 32:
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 0;
+ break;
+ default:
+ break;
+ }
+
+ var->blue.msb_right = var->green.msb_right =
+ var->red.msb_right = var->transp.msb_right = 0;
+}
+
+/*
+ * Device initialization.
+ * We initialize one vml_par struct per device and one vml_info
+ * struct per pipe. Currently we have only one pipe.
+ */
+
+static int __devinit vml_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct vml_info *vinfo;
+ struct fb_info *info;
+ struct vml_par *par;
+ int err = 0;
+
+ par = kzalloc(sizeof(*par), GFP_KERNEL);
+ if (par == NULL)
+ return -ENOMEM;
+
+ vinfo = kzalloc(sizeof(*vinfo), GFP_KERNEL);
+ if (vinfo == NULL) {
+ err = -ENOMEM;
+ goto out_err_0;
+ }
+
+ vinfo->par = par;
+ par->vdc = dev;
+ atomic_set(&par->refcount, 1);
+
+ switch (id->device) {
+ case VML_DEVICE_VDC:
+ if ((err = vmlfb_get_gpu(par)))
+ goto out_err_1;
+ pci_set_drvdata(dev, &vinfo->info);
+ break;
+ default:
+ err = -ENODEV;
+ goto out_err_1;
+ break;
+ }
+
+ info = &vinfo->info;
+ info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK;
+
+ err = vmlfb_enable_mmio(par);
+ if (err)
+ goto out_err_2;
+
+ err = vmlfb_alloc_vram(vinfo, vml_mem_requested,
+ vml_mem_contig, vml_mem_min);
+ if (err)
+ goto out_err_3;
+
+ strcpy(info->fix.id, "Vermilion Range");
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+ info->fix.smem_start = vinfo->vram_start;
+ info->fix.smem_len = vinfo->vram_contig_size;
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.ypanstep = 1;
+ info->fix.xpanstep = 1;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->screen_base = vinfo->vram_logical;
+ info->pseudo_palette = vinfo->pseudo_palette;
+ info->par = par;
+ info->fbops = &vmlfb_ops;
+ info->device = &dev->dev;
+
+ INIT_LIST_HEAD(&vinfo->head);
+ vinfo->pipe_disabled = 1;
+ vinfo->cur_blank_mode = FB_BLANK_UNBLANK;
+
+ info->var.grayscale = 0;
+ info->var.bits_per_pixel = 16;
+ vmlfb_set_pref_pixel_format(&info->var);
+
+ if (!fb_find_mode
+ (&info->var, info, vml_default_mode, NULL, 0, &defaultmode, 16)) {
+ printk(KERN_ERR MODULE_NAME ": Could not find initial mode\n");
+ }
+
+ if (fb_alloc_cmap(&info->cmap, 256, 1) < 0) {
+ err = -ENOMEM;
+ goto out_err_4;
+ }
+
+ err = register_framebuffer(info);
+ if (err) {
+ printk(KERN_ERR MODULE_NAME ": Register framebuffer error.\n");
+ goto out_err_5;
+ }
+
+ printk("Initialized vmlfb\n");
+
+ return 0;
+
+out_err_5:
+ fb_dealloc_cmap(&info->cmap);
+out_err_4:
+ vmlfb_free_vram(vinfo);
+out_err_3:
+ vmlfb_disable_mmio(par);
+out_err_2:
+ vmlfb_release_devices(par);
+out_err_1:
+ kfree(vinfo);
+out_err_0:
+ kfree(par);
+ return err;
+}
+
+static int vmlfb_open(struct fb_info *info, int user)
+{
+ /*
+ * Save registers here?
+ */
+ return 0;
+}
+
+static int vmlfb_release(struct fb_info *info, int user)
+{
+ /*
+ * Restore registers here.
+ */
+
+ return 0;
+}
+
+static int vml_nearest_clock(int clock)
+{
+
+ int i;
+ int cur_index;
+ int cur_diff;
+ int diff;
+
+ cur_index = 0;
+ cur_diff = clock - vml_clocks[0];
+ cur_diff = (cur_diff < 0) ? -cur_diff : cur_diff;
+ for (i = 1; i < vml_num_clocks; ++i) {
+ diff = clock - vml_clocks[i];
+ diff = (diff < 0) ? -diff : diff;
+ if (diff < cur_diff) {
+ cur_index = i;
+ cur_diff = diff;
+ }
+ }
+ return vml_clocks[cur_index];
+}
+
+static int vmlfb_check_var_locked(struct fb_var_screeninfo *var,
+ struct vml_info *vinfo)
+{
+ u32 pitch;
+ u64 mem;
+ int nearest_clock;
+ int clock;
+ int clock_diff;
+ struct fb_var_screeninfo v;
+
+ v = *var;
+ clock = PICOS2KHZ(var->pixclock);
+
+ if (subsys && subsys->nearest_clock) {
+ nearest_clock = subsys->nearest_clock(subsys, clock);
+ } else {
+ nearest_clock = vml_nearest_clock(clock);
+ }
+
+ /*
+ * Accept a 20% diff.
+ */
+
+ clock_diff = nearest_clock - clock;
+ clock_diff = (clock_diff < 0) ? -clock_diff : clock_diff;
+ if (clock_diff > clock / 5) {
+#if 0
+ printk(KERN_DEBUG MODULE_NAME ": Diff failure. %d %d\n",clock_diff,clock);
+#endif
+ return -EINVAL;
+ }
+
+ v.pixclock = KHZ2PICOS(nearest_clock);
+
+ if (var->xres > VML_MAX_XRES || var->yres > VML_MAX_YRES) {
+ printk(KERN_DEBUG MODULE_NAME ": Resolution failure.\n");
+ return -EINVAL;
+ }
+ if (var->xres_virtual > VML_MAX_XRES_VIRTUAL) {
+ printk(KERN_DEBUG MODULE_NAME
+ ": Virtual resolution failure.\n");
+ return -EINVAL;
+ }
+ switch (v.bits_per_pixel) {
+ case 0 ... 16:
+ v.bits_per_pixel = 16;
+ break;
+ case 17 ... 32:
+ v.bits_per_pixel = 32;
+ break;
+ default:
+ printk(KERN_DEBUG MODULE_NAME ": Invalid bpp: %d.\n",
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F);
+ mem = pitch * var->yres_virtual;
+ if (mem > vinfo->vram_contig_size) {
+ return -ENOMEM;
+ }
+
+ switch (v.bits_per_pixel) {
+ case 16:
+ if (var->blue.offset != 0 ||
+ var->blue.length != 5 ||
+ var->green.offset != 5 ||
+ var->green.length != 5 ||
+ var->red.offset != 10 ||
+ var->red.length != 5 ||
+ var->transp.offset != 15 || var->transp.length != 1) {
+ vmlfb_set_pref_pixel_format(&v);
+ }
+ break;
+ case 32:
+ if (var->blue.offset != 0 ||
+ var->blue.length != 8 ||
+ var->green.offset != 8 ||
+ var->green.length != 8 ||
+ var->red.offset != 16 ||
+ var->red.length != 8 ||
+ (var->transp.length != 0 && var->transp.length != 8) ||
+ (var->transp.length == 8 && var->transp.offset != 24)) {
+ vmlfb_set_pref_pixel_format(&v);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *var = v;
+
+ return 0;
+}
+
+static int vmlfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct vml_info *vinfo = container_of(info, struct vml_info, info);
+ int ret;
+
+ mutex_lock(&vml_mutex);
+ ret = vmlfb_check_var_locked(var, vinfo);
+ mutex_unlock(&vml_mutex);
+
+ return ret;
+}
+
+static void vml_wait_vblank(struct vml_info *vinfo)
+{
+ /* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */
+ mdelay(20);
+}
+
+static void vmlfb_disable_pipe(struct vml_info *vinfo)
+{
+ struct vml_par *par = vinfo->par;
+
+ /* Disable the MDVO pad */
+ VML_WRITE32(par, VML_RCOMPSTAT, 0);
+ while (!(VML_READ32(par, VML_RCOMPSTAT) & VML_MDVO_VDC_I_RCOMP)) ;
+
+ /* Disable display planes */
+ VML_WRITE32(par, VML_DSPCCNTR,
+ VML_READ32(par, VML_DSPCCNTR) & ~VML_GFX_ENABLE);
+ (void)VML_READ32(par, VML_DSPCCNTR);
+ /* Wait for vblank for the disable to take effect */
+ vml_wait_vblank(vinfo);
+
+ /* Next, disable display pipes */
+ VML_WRITE32(par, VML_PIPEACONF, 0);
+ (void)VML_READ32(par, VML_PIPEACONF);
+
+ vinfo->pipe_disabled = 1;
+}
+
+#ifdef VERMILION_DEBUG
+static void vml_dump_regs(struct vml_info *vinfo)
+{
+ struct vml_par *par = vinfo->par;
+
+ printk(KERN_DEBUG MODULE_NAME ": Modesetting register dump:\n");
+ printk(KERN_DEBUG MODULE_NAME ": \tHTOTAL_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_HTOTAL_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tHBLANK_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_HBLANK_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tHSYNC_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_HSYNC_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tVTOTAL_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_VTOTAL_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tVBLANK_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_VBLANK_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tVSYNC_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_VSYNC_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tDSPCSTRIDE : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_DSPCSTRIDE));
+ printk(KERN_DEBUG MODULE_NAME ": \tDSPCSIZE : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_DSPCSIZE));
+ printk(KERN_DEBUG MODULE_NAME ": \tDSPCPOS : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_DSPCPOS));
+ printk(KERN_DEBUG MODULE_NAME ": \tDSPARB : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_DSPARB));
+ printk(KERN_DEBUG MODULE_NAME ": \tDSPCADDR : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_DSPCADDR));
+ printk(KERN_DEBUG MODULE_NAME ": \tBCLRPAT_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_BCLRPAT_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tCANVSCLR_A : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_CANVSCLR_A));
+ printk(KERN_DEBUG MODULE_NAME ": \tPIPEASRC : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_PIPEASRC));
+ printk(KERN_DEBUG MODULE_NAME ": \tPIPEACONF : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_PIPEACONF));
+ printk(KERN_DEBUG MODULE_NAME ": \tDSPCCNTR : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_DSPCCNTR));
+ printk(KERN_DEBUG MODULE_NAME ": \tRCOMPSTAT : 0x%08x\n",
+ (unsigned)VML_READ32(par, VML_RCOMPSTAT));
+ printk(KERN_DEBUG MODULE_NAME ": End of modesetting register dump.\n");
+}
+#endif
+
+static int vmlfb_set_par_locked(struct vml_info *vinfo)
+{
+ struct vml_par *par = vinfo->par;
+ struct fb_info *info = &vinfo->info;
+ struct fb_var_screeninfo *var = &info->var;
+ u32 htotal, hactive, hblank_start, hblank_end, hsync_start, hsync_end;
+ u32 vtotal, vactive, vblank_start, vblank_end, vsync_start, vsync_end;
+ u32 dspcntr;
+ int clock;
+
+ vinfo->bytes_per_pixel = var->bits_per_pixel >> 3;
+ vinfo->stride =
+ __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F);
+ info->fix.line_length = vinfo->stride;
+
+ if (!subsys)
+ return 0;
+
+ htotal =
+ var->xres + var->right_margin + var->hsync_len + var->left_margin;
+ hactive = var->xres;
+ hblank_start = var->xres;
+ hblank_end = htotal;
+ hsync_start = hactive + var->right_margin;
+ hsync_end = hsync_start + var->hsync_len;
+
+ vtotal =
+ var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+ vactive = var->yres;
+ vblank_start = var->yres;
+ vblank_end = vtotal;
+ vsync_start = vactive + var->lower_margin;
+ vsync_end = vsync_start + var->vsync_len;
+
+ dspcntr = VML_GFX_ENABLE | VML_GFX_GAMMABYPASS;
+ clock = PICOS2KHZ(var->pixclock);
+
+ if (subsys->nearest_clock) {
+ clock = subsys->nearest_clock(subsys, clock);
+ } else {
+ clock = vml_nearest_clock(clock);
+ }
+ printk(KERN_DEBUG MODULE_NAME
+ ": Set mode Hfreq : %d kHz, Vfreq : %d Hz.\n", clock / htotal,
+ ((clock / htotal) * 1000) / vtotal);
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ dspcntr |= VML_GFX_ARGB1555;
+ break;
+ case 32:
+ if (var->transp.length == 8)
+ dspcntr |= VML_GFX_ARGB8888 | VML_GFX_ALPHAMULT;
+ else
+ dspcntr |= VML_GFX_RGB0888;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ vmlfb_disable_pipe(vinfo);
+ mb();
+
+ if (subsys->set_clock)
+ subsys->set_clock(subsys, clock);
+ else
+ return -EINVAL;
+
+ VML_WRITE32(par, VML_HTOTAL_A, ((htotal - 1) << 16) | (hactive - 1));
+ VML_WRITE32(par, VML_HBLANK_A,
+ ((hblank_end - 1) << 16) | (hblank_start - 1));
+ VML_WRITE32(par, VML_HSYNC_A,
+ ((hsync_end - 1) << 16) | (hsync_start - 1));
+ VML_WRITE32(par, VML_VTOTAL_A, ((vtotal - 1) << 16) | (vactive - 1));
+ VML_WRITE32(par, VML_VBLANK_A,
+ ((vblank_end - 1) << 16) | (vblank_start - 1));
+ VML_WRITE32(par, VML_VSYNC_A,
+ ((vsync_end - 1) << 16) | (vsync_start - 1));
+ VML_WRITE32(par, VML_DSPCSTRIDE, vinfo->stride);
+ VML_WRITE32(par, VML_DSPCSIZE,
+ ((var->yres - 1) << 16) | (var->xres - 1));
+ VML_WRITE32(par, VML_DSPCPOS, 0x00000000);
+ VML_WRITE32(par, VML_DSPARB, VML_FIFO_DEFAULT);
+ VML_WRITE32(par, VML_BCLRPAT_A, 0x00000000);
+ VML_WRITE32(par, VML_CANVSCLR_A, 0x00000000);
+ VML_WRITE32(par, VML_PIPEASRC,
+ ((var->xres - 1) << 16) | (var->yres - 1));
+
+ wmb();
+ VML_WRITE32(par, VML_PIPEACONF, VML_PIPE_ENABLE);
+ wmb();
+ VML_WRITE32(par, VML_DSPCCNTR, dspcntr);
+ wmb();
+ VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
+ var->yoffset * vinfo->stride +
+ var->xoffset * vinfo->bytes_per_pixel);
+
+ VML_WRITE32(par, VML_RCOMPSTAT, VML_MDVO_PAD_ENABLE);
+
+ while (!(VML_READ32(par, VML_RCOMPSTAT) &
+ (VML_MDVO_VDC_I_RCOMP | VML_MDVO_PAD_ENABLE))) ;
+
+ vinfo->pipe_disabled = 0;
+#ifdef VERMILION_DEBUG
+ vml_dump_regs(vinfo);
+#endif
+
+ return 0;
+}
+
+static int vmlfb_set_par(struct fb_info *info)
+{
+ struct vml_info *vinfo = container_of(info, struct vml_info, info);
+ int ret;
+
+ mutex_lock(&vml_mutex);
+ list_del(&vinfo->head);
+ list_add(&vinfo->head, (subsys) ? &global_has_mode : &global_no_mode);
+ ret = vmlfb_set_par_locked(vinfo);
+
+ mutex_unlock(&vml_mutex);
+ return ret;
+}
+
+static int vmlfb_blank_locked(struct vml_info *vinfo)
+{
+ struct vml_par *par = vinfo->par;
+ u32 cur = VML_READ32(par, VML_PIPEACONF);
+
+ switch (vinfo->cur_blank_mode) {
+ case FB_BLANK_UNBLANK:
+ if (vinfo->pipe_disabled) {
+ vmlfb_set_par_locked(vinfo);
+ }
+ VML_WRITE32(par, VML_PIPEACONF, cur & ~VML_PIPE_FORCE_BORDER);
+ (void)VML_READ32(par, VML_PIPEACONF);
+ break;
+ case FB_BLANK_NORMAL:
+ if (vinfo->pipe_disabled) {
+ vmlfb_set_par_locked(vinfo);
+ }
+ VML_WRITE32(par, VML_PIPEACONF, cur | VML_PIPE_FORCE_BORDER);
+ (void)VML_READ32(par, VML_PIPEACONF);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ if (!vinfo->pipe_disabled) {
+ vmlfb_disable_pipe(vinfo);
+ }
+ break;
+ case FB_BLANK_POWERDOWN:
+ if (!vinfo->pipe_disabled) {
+ vmlfb_disable_pipe(vinfo);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vmlfb_blank(int blank_mode, struct fb_info *info)
+{
+ struct vml_info *vinfo = container_of(info, struct vml_info, info);
+ int ret;
+
+ mutex_lock(&vml_mutex);
+ vinfo->cur_blank_mode = blank_mode;
+ ret = vmlfb_blank_locked(vinfo);
+ mutex_unlock(&vml_mutex);
+ return ret;
+}
+
+static int vmlfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct vml_info *vinfo = container_of(info, struct vml_info, info);
+ struct vml_par *par = vinfo->par;
+
+ mutex_lock(&vml_mutex);
+ VML_WRITE32(par, VML_DSPCADDR, (u32) vinfo->vram_start +
+ var->yoffset * vinfo->stride +
+ var->xoffset * vinfo->bytes_per_pixel);
+ (void)VML_READ32(par, VML_DSPCADDR);
+ mutex_unlock(&vml_mutex);
+
+ return 0;
+}
+
+static int vmlfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ u32 v;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ if (info->var.grayscale) {
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ if (info->fix.visual != FB_VISUAL_TRUECOLOR)
+ return -EINVAL;
+
+ red = VML_TOHW(red, info->var.red.length);
+ blue = VML_TOHW(blue, info->var.blue.length);
+ green = VML_TOHW(green, info->var.green.length);
+ transp = VML_TOHW(transp, info->var.transp.length);
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ ((u32 *) info->pseudo_palette)[regno] = v;
+ break;
+ case 24:
+ case 32:
+ ((u32 *) info->pseudo_palette)[regno] = v;
+ break;
+ }
+ return 0;
+}
+
+static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct vml_info *vinfo = container_of(info, struct vml_info, info);
+ unsigned long size = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ int ret;
+
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ if (offset + size > vinfo->vram_contig_size)
+ return -EINVAL;
+ ret = vmlfb_vram_offset(vinfo, offset);
+ if (ret)
+ return -EINVAL;
+ offset += vinfo->vram_start;
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+ vma->vm_flags |= VM_RESERVED | VM_IO;
+ if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
+ size, vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+}
+
+static int vmlfb_sync(struct fb_info *info)
+{
+ return 0;
+}
+
+static int vmlfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ return -EINVAL; /* just to force soft_cursor() call */
+}
+
+static struct fb_ops vmlfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = vmlfb_open,
+ .fb_release = vmlfb_release,
+ .fb_check_var = vmlfb_check_var,
+ .fb_set_par = vmlfb_set_par,
+ .fb_blank = vmlfb_blank,
+ .fb_pan_display = vmlfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_cursor = vmlfb_cursor,
+ .fb_sync = vmlfb_sync,
+ .fb_mmap = vmlfb_mmap,
+ .fb_setcolreg = vmlfb_setcolreg
+};
+
+static struct pci_device_id vml_ids[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, VML_DEVICE_VDC)},
+ {0}
+};
+
+static struct pci_driver vmlfb_pci_driver = {
+ .name = "vmlfb",
+ .id_table = vml_ids,
+ .probe = vml_pci_probe,
+ .remove = __devexit_p(vml_pci_remove)
+};
+
+static void __exit vmlfb_cleanup(void)
+{
+ pci_unregister_driver(&vmlfb_pci_driver);
+}
+
+static int __init vmlfb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options(MODULE_NAME, &option))
+ return -ENODEV;
+#endif
+
+ printk(KERN_DEBUG MODULE_NAME ": initializing\n");
+ mutex_init(&vml_mutex);
+ INIT_LIST_HEAD(&global_no_mode);
+ INIT_LIST_HEAD(&global_has_mode);
+
+ return pci_register_driver(&vmlfb_pci_driver);
+}
+
+int vmlfb_register_subsys(struct vml_sys *sys)
+{
+ struct vml_info *entry;
+ struct list_head *list;
+ u32 save_activate;
+
+ mutex_lock(&vml_mutex);
+ if (subsys != NULL) {
+ subsys->restore(subsys);
+ }
+ subsys = sys;
+ subsys->save(subsys);
+
+ /*
+ * We need to restart list traversal for each item, since we
+ * release the list mutex in the loop.
+ */
+
+ list = global_no_mode.next;
+ while (list != &global_no_mode) {
+ list_del_init(list);
+ entry = list_entry(list, struct vml_info, head);
+
+ /*
+ * First, try the current mode which might not be
+ * completely validated with respect to the pixel clock.
+ */
+
+ if (!vmlfb_check_var_locked(&entry->info.var, entry)) {
+ vmlfb_set_par_locked(entry);
+ list_add_tail(list, &global_has_mode);
+ } else {
+
+ /*
+ * Didn't work. Try to find another mode,
+ * that matches this subsys.
+ */
+
+ mutex_unlock(&vml_mutex);
+ save_activate = entry->info.var.activate;
+ entry->info.var.bits_per_pixel = 16;
+ vmlfb_set_pref_pixel_format(&entry->info.var);
+ if (fb_find_mode(&entry->info.var,
+ &entry->info,
+ vml_default_mode, NULL, 0, NULL, 16)) {
+ entry->info.var.activate |=
+ FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+ fb_set_var(&entry->info, &entry->info.var);
+ } else {
+ printk(KERN_ERR MODULE_NAME
+ ": Sorry. no mode found for this subsys.\n");
+ }
+ entry->info.var.activate = save_activate;
+ mutex_lock(&vml_mutex);
+ }
+ vmlfb_blank_locked(entry);
+ list = global_no_mode.next;
+ }
+ mutex_unlock(&vml_mutex);
+
+ printk(KERN_DEBUG MODULE_NAME ": Registered %s subsystem.\n",
+ subsys->name ? subsys->name : "unknown");
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(vmlfb_register_subsys);
+
+void vmlfb_unregister_subsys(struct vml_sys *sys)
+{
+ struct vml_info *entry, *next;
+
+ mutex_lock(&vml_mutex);
+ if (subsys != sys) {
+ mutex_unlock(&vml_mutex);
+ return;
+ }
+ subsys->restore(subsys);
+ subsys = NULL;
+ list_for_each_entry_safe(entry, next, &global_has_mode, head) {
+ printk(KERN_DEBUG MODULE_NAME ": subsys disable pipe\n");
+ vmlfb_disable_pipe(entry);
+ list_del(&entry->head);
+ list_add_tail(&entry->head, &global_no_mode);
+ }
+ mutex_unlock(&vml_mutex);
+}
+
+EXPORT_SYMBOL_GPL(vmlfb_unregister_subsys);
+
+module_init(vmlfb_init);
+module_exit(vmlfb_cleanup);
+
+MODULE_AUTHOR("Tungsten Graphics");
+MODULE_DESCRIPTION("Initialization of the Vermilion display devices");
+MODULE_VERSION("1.0.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/vermilion/vermilion.h b/drivers/video/vermilion/vermilion.h
new file mode 100644
index 00000000000..1fc6695a49d
--- /dev/null
+++ b/drivers/video/vermilion/vermilion.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) Intel Corp. 2007.
+ * All Rights Reserved.
+ *
+ * Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+ * develop this driver.
+ *
+ * This file is part of the Vermilion Range fb driver.
+ * The Vermilion Range fb driver 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 Vermilion Range fb driver 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 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef _VERMILION_H_
+#define _VERMILION_H_
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/pci.h>
+#include <asm/atomic.h>
+#include <linux/mutex.h>
+
+#define VML_DEVICE_GPU 0x5002
+#define VML_DEVICE_VDC 0x5009
+
+#define VML_VRAM_AREAS 3
+#define VML_MAX_XRES 1024
+#define VML_MAX_YRES 768
+#define VML_MAX_XRES_VIRTUAL 1040
+
+/*
+ * Display controller registers:
+ */
+
+/* Display controller 10-bit color representation */
+
+#define VML_R_MASK 0x3FF00000
+#define VML_R_SHIFT 20
+#define VML_G_MASK 0x000FFC00
+#define VML_G_SHIFT 10
+#define VML_B_MASK 0x000003FF
+#define VML_B_SHIFT 0
+
+/* Graphics plane control */
+#define VML_DSPCCNTR 0x00072180
+#define VML_GFX_ENABLE 0x80000000
+#define VML_GFX_GAMMABYPASS 0x40000000
+#define VML_GFX_ARGB1555 0x0C000000
+#define VML_GFX_RGB0888 0x18000000
+#define VML_GFX_ARGB8888 0x1C000000
+#define VML_GFX_ALPHACONST 0x02000000
+#define VML_GFX_ALPHAMULT 0x01000000
+#define VML_GFX_CONST_ALPHA 0x000000FF
+
+/* Graphics plane start address. Pixel aligned. */
+#define VML_DSPCADDR 0x00072184
+
+/* Graphics plane stride register. */
+#define VML_DSPCSTRIDE 0x00072188
+
+/* Graphics plane position register. */
+#define VML_DSPCPOS 0x0007218C
+#define VML_POS_YMASK 0x0FFF0000
+#define VML_POS_YSHIFT 16
+#define VML_POS_XMASK 0x00000FFF
+#define VML_POS_XSHIFT 0
+
+/* Graphics plane height and width */
+#define VML_DSPCSIZE 0x00072190
+#define VML_SIZE_HMASK 0x0FFF0000
+#define VML_SIZE_HSHIFT 16
+#define VML_SISE_WMASK 0x00000FFF
+#define VML_SIZE_WSHIFT 0
+
+/* Graphics plane gamma correction lookup table registers (129 * 32 bits) */
+#define VML_DSPCGAMLUT 0x00072200
+
+/* Pixel video output configuration register */
+#define VML_PVOCONFIG 0x00061140
+#define VML_CONFIG_BASE 0x80000000
+#define VML_CONFIG_PIXEL_SWAP 0x04000000
+#define VML_CONFIG_DE_INV 0x01000000
+#define VML_CONFIG_HREF_INV 0x00400000
+#define VML_CONFIG_VREF_INV 0x00100000
+#define VML_CONFIG_CLK_INV 0x00040000
+#define VML_CONFIG_CLK_DIV2 0x00010000
+#define VML_CONFIG_ESTRB_INV 0x00008000
+
+/* Pipe A Horizontal total register */
+#define VML_HTOTAL_A 0x00060000
+#define VML_HTOTAL_MASK 0x1FFF0000
+#define VML_HTOTAL_SHIFT 16
+#define VML_HTOTAL_VAL 8192
+#define VML_HACTIVE_MASK 0x000007FF
+#define VML_HACTIVE_SHIFT 0
+#define VML_HACTIVE_VAL 4096
+
+/* Pipe A Horizontal Blank register */
+#define VML_HBLANK_A 0x00060004
+#define VML_HBLANK_END_MASK 0x1FFF0000
+#define VML_HBLANK_END_SHIFT 16
+#define VML_HBLANK_END_VAL 8192
+#define VML_HBLANK_START_MASK 0x00001FFF
+#define VML_HBLANK_START_SHIFT 0
+#define VML_HBLANK_START_VAL 8192
+
+/* Pipe A Horizontal Sync register */
+#define VML_HSYNC_A 0x00060008
+#define VML_HSYNC_END_MASK 0x1FFF0000
+#define VML_HSYNC_END_SHIFT 16
+#define VML_HSYNC_END_VAL 8192
+#define VML_HSYNC_START_MASK 0x00001FFF
+#define VML_HSYNC_START_SHIFT 0
+#define VML_HSYNC_START_VAL 8192
+
+/* Pipe A Vertical total register */
+#define VML_VTOTAL_A 0x0006000C
+#define VML_VTOTAL_MASK 0x1FFF0000
+#define VML_VTOTAL_SHIFT 16
+#define VML_VTOTAL_VAL 8192
+#define VML_VACTIVE_MASK 0x000007FF
+#define VML_VACTIVE_SHIFT 0
+#define VML_VACTIVE_VAL 4096
+
+/* Pipe A Vertical Blank register */
+#define VML_VBLANK_A 0x00060010
+#define VML_VBLANK_END_MASK 0x1FFF0000
+#define VML_VBLANK_END_SHIFT 16
+#define VML_VBLANK_END_VAL 8192
+#define VML_VBLANK_START_MASK 0x00001FFF
+#define VML_VBLANK_START_SHIFT 0
+#define VML_VBLANK_START_VAL 8192
+
+/* Pipe A Vertical Sync register */
+#define VML_VSYNC_A 0x00060014
+#define VML_VSYNC_END_MASK 0x1FFF0000
+#define VML_VSYNC_END_SHIFT 16
+#define VML_VSYNC_END_VAL 8192
+#define VML_VSYNC_START_MASK 0x00001FFF
+#define VML_VSYNC_START_SHIFT 0
+#define VML_VSYNC_START_VAL 8192
+
+/* Pipe A Source Image size (minus one - equal to active size)
+ * Programmable while pipe is enabled.
+ */
+#define VML_PIPEASRC 0x0006001C
+#define VML_PIPEASRC_HMASK 0x0FFF0000
+#define VML_PIPEASRC_HSHIFT 16
+#define VML_PIPEASRC_VMASK 0x00000FFF
+#define VML_PIPEASRC_VSHIFT 0
+
+/* Pipe A Border Color Pattern register (10 bit color) */
+#define VML_BCLRPAT_A 0x00060020
+
+/* Pipe A Canvas Color register (10 bit color) */
+#define VML_CANVSCLR_A 0x00060024
+
+/* Pipe A Configuration register */
+#define VML_PIPEACONF 0x00070008
+#define VML_PIPE_BASE 0x00000000
+#define VML_PIPE_ENABLE 0x80000000
+#define VML_PIPE_FORCE_BORDER 0x02000000
+#define VML_PIPE_PLANES_OFF 0x00080000
+#define VML_PIPE_ARGB_OUTPUT_MODE 0x00040000
+
+/* Pipe A FIFO setting */
+#define VML_DSPARB 0x00070030
+#define VML_FIFO_DEFAULT 0x00001D9C
+
+/* MDVO rcomp status & pads control register */
+#define VML_RCOMPSTAT 0x00070048
+#define VML_MDVO_VDC_I_RCOMP 0x80000000
+#define VML_MDVO_POWERSAVE_OFF 0x00000008
+#define VML_MDVO_PAD_ENABLE 0x00000004
+#define VML_MDVO_PULLDOWN_ENABLE 0x00000001
+
+struct vml_par {
+ struct pci_dev *vdc;
+ u64 vdc_mem_base;
+ u64 vdc_mem_size;
+ char __iomem *vdc_mem;
+
+ struct pci_dev *gpu;
+ u64 gpu_mem_base;
+ u64 gpu_mem_size;
+ char __iomem *gpu_mem;
+
+ atomic_t refcount;
+};
+
+struct vram_area {
+ unsigned long logical;
+ unsigned long phys;
+ unsigned long size;
+ unsigned order;
+};
+
+struct vml_info {
+ struct fb_info info;
+ struct vml_par *par;
+ struct list_head head;
+ struct vram_area vram[VML_VRAM_AREAS];
+ u64 vram_start;
+ u64 vram_contig_size;
+ u32 num_areas;
+ void __iomem *vram_logical;
+ u32 pseudo_palette[16];
+ u32 stride;
+ u32 bytes_per_pixel;
+ atomic_t vmas;
+ int cur_blank_mode;
+ int pipe_disabled;
+};
+
+/*
+ * Subsystem
+ */
+
+struct vml_sys {
+ char *name;
+
+ /*
+ * Save / Restore;
+ */
+
+ int (*save) (struct vml_sys * sys);
+ int (*restore) (struct vml_sys * sys);
+
+ /*
+ * PLL programming;
+ */
+
+ int (*set_clock) (struct vml_sys * sys, int clock);
+ int (*nearest_clock) (const struct vml_sys * sys, int clock);
+};
+
+extern int vmlfb_register_subsys(struct vml_sys *sys);
+extern void vmlfb_unregister_subsys(struct vml_sys *sys);
+
+#define VML_READ32(_par, _offset) \
+ (ioread32((_par)->vdc_mem + (_offset)))
+#define VML_WRITE32(_par, _offset, _value) \
+ iowrite32(_value, (_par)->vdc_mem + (_offset))
+
+#endif
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index a9b99b01bd8..64ee78c3c12 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -84,13 +84,15 @@ static int vfb_mmap(struct fb_info *info,
struct vm_area_struct *vma);
static struct fb_ops vfb_ops = {
+ .fb_read = fb_sys_read,
+ .fb_write = fb_sys_write,
.fb_check_var = vfb_check_var,
.fb_set_par = vfb_set_par,
.fb_setcolreg = vfb_setcolreg,
.fb_pan_display = vfb_pan_display,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
.fb_mmap = vfb_mmap,
};
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index ec4c7dc54a6..2a14d28c416 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -1378,6 +1378,8 @@ static int __init vga16fb_probe(struct platform_device *dev)
info->fbops = &vga16fb_ops;
info->var = vga16fb_defined;
info->fix = vga16fb_fix;
+ /* supports rectangles with widths of multiples of 8 */
+ info->pixmap.blit_x = 1 << 7 | 1 << 15 | 1 << 23 | 1 << 31;
info->flags = FBINFO_FLAG_DEFAULT |
FBINFO_HWACCEL_YPAN;
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index d94efafc77b..b91c466225b 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -50,23 +50,28 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
struct regstate *saved = (struct regstate *) state->vidstate;
int i;
u8 misc, attr10, gr4, gr5, gr6, seq1, seq2, seq4;
+ unsigned short iobase;
/* if in graphics mode, no need to save */
+ misc = vga_r(state->vgabase, VGA_MIS_R);
+ iobase = (misc & 1) ? 0x3d0 : 0x3b0;
+
+ vga_r(state->vgabase, iobase + 0xa);
+ vga_w(state->vgabase, VGA_ATT_W, 0x00);
attr10 = vga_rattr(state->vgabase, 0x10);
+ vga_r(state->vgabase, iobase + 0xa);
+ vga_w(state->vgabase, VGA_ATT_W, 0x20);
+
if (attr10 & 1)
return;
-
+
/* save regs */
- misc = vga_r(state->vgabase, VGA_MIS_R);
gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
gr5 = vga_rgfx(state->vgabase, VGA_GFX_MODE);
gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
- /* force graphics mode */
- vga_w(state->vgabase, VGA_MIS_W, misc | 1);
-
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -115,15 +120,12 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
}
/* restore regs */
- vga_wattr(state->vgabase, 0x10, attr10);
-
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
vga_wgfx(state->vgabase, VGA_GFX_MODE, gr5);
vga_wgfx(state->vgabase, VGA_GFX_MISC, gr6);
- vga_w(state->vgabase, VGA_MIS_W, misc);
/* unblank screen */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -137,11 +139,10 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
{
struct regstate *saved = (struct regstate *) state->vidstate;
int i;
- u8 misc, gr1, gr3, gr4, gr5, gr6, gr8;
+ u8 gr1, gr3, gr4, gr5, gr6, gr8;
u8 seq1, seq2, seq4;
/* save regs */
- misc = vga_r(state->vgabase, VGA_MIS_R);
gr1 = vga_rgfx(state->vgabase, VGA_GFX_SR_ENABLE);
gr3 = vga_rgfx(state->vgabase, VGA_GFX_DATA_ROTATE);
gr4 = vga_rgfx(state->vgabase, VGA_GFX_PLANE_READ);
@@ -151,9 +152,6 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
- /* force graphics mode */
- vga_w(state->vgabase, VGA_MIS_W, misc | 1);
-
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -213,8 +211,6 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x3);
/* restore regs */
- vga_w(state->vgabase, VGA_MIS_W, misc);
-
vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, gr1);
vga_wgfx(state->vgabase, VGA_GFX_DATA_ROTATE, gr3);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, gr4);
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
new file mode 100644
index 00000000000..5e9755e464a
--- /dev/null
+++ b/drivers/video/vt8623fb.c
@@ -0,0 +1,927 @@
+/*
+ * linux/drivers/video/vt8623fb.c - fbdev driver for
+ * integrated graphic core in VIA VT8623 [CLE266] chipset
+ *
+ * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Code is based on s3fb, some parts are from David Boucher's viafb
+ * (http://davesdomain.org.uk/viafb/)
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/svga.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/console.h> /* Why should fb driver call console functions? because acquire_console_sem() */
+#include <video/vga.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+struct vt8623fb_info {
+ char __iomem *mmio_base;
+ int mtrr_reg;
+ struct vgastate state;
+ struct mutex open_lock;
+ unsigned int ref_count;
+ u32 pseudo_palette[16];
+};
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static const struct svga_fb_format vt8623fb_formats[] = {
+ { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP8, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 4, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 1,
+ FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 16, 16},
+ { 8, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 8},
+/* {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4}, */
+ {16, {11, 5, 0}, {5, 6, 0}, {0, 5, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 4, 4},
+ {32, {16, 8, 0}, {8, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0,
+ FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_TRUECOLOR, 2, 2},
+ SVGA_FORMAT_END
+};
+
+static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
+ 60000, 300000, 14318};
+
+/* CRT timing register sets */
+
+struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
+struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
+struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
+struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
+struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
+struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
+
+struct svga_timing_regs vt8623_timing_regs = {
+ vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
+ vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
+ vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
+ vt8623_v_blank_end_regs, vt8623_v_sync_start_regs, vt8623_v_sync_end_regs,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Module parameters */
+
+static char *mode = "640x480-8@60";
+
+#ifdef CONFIG_MTRR
+static int mtrr = 1;
+#endif
+
+MODULE_AUTHOR("(c) 2006 Ondrej Zajicek <santiago@crfreenet.org>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("fbdev driver for integrated graphics core in VIA VT8623 [CLE266]");
+
+module_param(mode, charp, 0644);
+MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc)");
+
+#ifdef CONFIG_MTRR
+module_param(mtrr, int, 0444);
+MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static struct fb_tile_ops vt8623fb_tile_ops = {
+ .fb_settile = svga_settile,
+ .fb_tilecopy = svga_tilecopy,
+ .fb_tilefill = svga_tilefill,
+ .fb_tileblit = svga_tileblit,
+ .fb_tilecursor = svga_tilecursor,
+ .fb_get_tilemax = svga_get_tilemax,
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* image data is MSB-first, fb structure is MSB-first too */
+static inline u32 expand_color(u32 c)
+{
+ return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
+}
+
+/* vt8623fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = expand_color(image->fg_color);
+ u32 bg = expand_color(image->bg_color);
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = *(src++) * 0x01010101;
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+/* vt8623fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ u32 fg = expand_color(rect->color);
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ int x, y;
+
+ dst1 = info->screen_base + (rect->dy * info->fix.line_length)
+ + ((rect->dx / 8) * 4);
+
+ for (y = 0; y < rect->height; y++) {
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < rect->width; x += 8) {
+ fb_writel(fg, dst++);
+ }
+ dst1 += info->fix.line_length;
+ }
+}
+
+
+/* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
+static inline u32 expand_pixel(u32 c)
+{
+ return (((c & 1) << 24) | ((c & 2) << 27) | ((c & 4) << 14) | ((c & 8) << 17) |
+ ((c & 16) << 4) | ((c & 32) << 7) | ((c & 64) >> 6) | ((c & 128) >> 3)) * 0xF;
+}
+
+/* vt8623fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
+static void vt8623fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ u32 fg = image->fg_color * 0x11111111;
+ u32 bg = image->bg_color * 0x11111111;
+ const u8 *src1, *src;
+ u8 __iomem *dst1;
+ u32 __iomem *dst;
+ u32 val;
+ int x, y;
+
+ src1 = image->data;
+ dst1 = info->screen_base + (image->dy * info->fix.line_length)
+ + ((image->dx / 8) * 4);
+
+ for (y = 0; y < image->height; y++) {
+ src = src1;
+ dst = (u32 __iomem *) dst1;
+ for (x = 0; x < image->width; x += 8) {
+ val = expand_pixel(*(src++));
+ val = (val & fg) | (~val & bg);
+ fb_writel(val, dst++);
+ }
+ src1 += image->width / 8;
+ dst1 += info->fix.line_length;
+ }
+}
+
+static void vt8623fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
+ && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
+ if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
+ vt8623fb_iplan_imageblit(info, image);
+ else
+ vt8623fb_cfb4_imageblit(info, image);
+ } else
+ cfb_imageblit(info, image);
+}
+
+static void vt8623fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ if ((info->var.bits_per_pixel == 4)
+ && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
+ && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
+ vt8623fb_iplan_fillrect(info, rect);
+ else
+ cfb_fillrect(info, rect);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+static void vt8623_set_pixclock(struct fb_info *info, u32 pixclock)
+{
+ u16 m, n, r;
+ u8 regval;
+ int rv;
+
+ rv = svga_compute_pll(&vt8623_pll, 1000000000 / pixclock, &m, &n, &r, info->node);
+ if (rv < 0) {
+ printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node);
+ return;
+ }
+
+ /* Set VGA misc register */
+ regval = vga_r(NULL, VGA_MIS_R);
+ vga_w(NULL, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
+
+ /* Set clock registers */
+ vga_wseq(NULL, 0x46, (n | (r << 6)));
+ vga_wseq(NULL, 0x47, m);
+
+ udelay(1000);
+
+ /* PLL reset */
+ svga_wseq_mask(0x40, 0x02, 0x02);
+ svga_wseq_mask(0x40, 0x00, 0x02);
+}
+
+
+static int vt8623fb_open(struct fb_info *info, int user)
+{
+ struct vt8623fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ memset(&(par->state), 0, sizeof(struct vgastate));
+ par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
+ par->state.num_crtc = 0xA2;
+ par->state.num_seq = 0x50;
+ save_vga(&(par->state));
+ }
+
+ par->ref_count++;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+static int vt8623fb_release(struct fb_info *info, int user)
+{
+ struct vt8623fb_info *par = info->par;
+
+ mutex_lock(&(par->open_lock));
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ return -EINVAL;
+ }
+
+ if (par->ref_count == 1)
+ restore_vga(&(par->state));
+
+ par->ref_count--;
+ mutex_unlock(&(par->open_lock));
+
+ return 0;
+}
+
+static int vt8623fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int rv, mem, step;
+
+ /* Find appropriate format */
+ rv = svga_match_format (vt8623fb_formats, var, NULL);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node);
+ return rv;
+ }
+
+ /* Do not allow to have real resoulution larger than virtual */
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ /* Round up xres_virtual to have proper alignment of lines */
+ step = vt8623fb_formats[rv].xresstep - 1;
+ var->xres_virtual = (var->xres_virtual+step) & ~step;
+
+ /* Check whether have enough memory */
+ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
+ if (mem > info->screen_size)
+ {
+ printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
+ return -EINVAL;
+ }
+
+ /* Text mode is limited to 256 kB of memory */
+ if ((var->bits_per_pixel == 0) && (mem > (256*1024)))
+ {
+ printk(KERN_ERR "fb%d: text framebuffer size too large (%d kB requested, 256 kB possible)\n", info->node, mem >> 10);
+ return -EINVAL;
+ }
+
+ rv = svga_check_timings (&vt8623_timing_regs, var, info->node);
+ if (rv < 0)
+ {
+ printk(KERN_ERR "fb%d: invalid timings requested\n", info->node);
+ return rv;
+ }
+
+ /* Interlaced mode not supported */
+ if (var->vmode & FB_VMODE_INTERLACED)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+static int vt8623fb_set_par(struct fb_info *info)
+{
+ u32 mode, offset_value, fetch_value, screen_size;
+ u32 bpp = info->var.bits_per_pixel;
+
+ if (bpp != 0) {
+ info->fix.ypanstep = 1;
+ info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
+
+ info->flags &= ~FBINFO_MISC_TILEBLITTING;
+ info->tileops = NULL;
+
+ /* in 4bpp supports 8p wide tiles only, any tiles otherwise */
+ info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
+ info->pixmap.blit_y = ~(u32)0;
+
+ offset_value = (info->var.xres_virtual * bpp) / 64;
+ fetch_value = ((info->var.xres * bpp) / 128) + 4;
+
+ if (bpp == 4)
+ fetch_value = (info->var.xres / 8) + 8; /* + 0 is OK */
+
+ screen_size = info->var.yres_virtual * info->fix.line_length;
+ } else {
+ info->fix.ypanstep = 16;
+ info->fix.line_length = 0;
+
+ info->flags |= FBINFO_MISC_TILEBLITTING;
+ info->tileops = &vt8623fb_tile_ops;
+
+ /* supports 8x16 tiles only */
+ info->pixmap.blit_x = 1 << (8 - 1);
+ info->pixmap.blit_y = 1 << (16 - 1);
+
+ offset_value = info->var.xres_virtual / 16;
+ fetch_value = (info->var.xres / 8) + 8;
+ screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
+ }
+
+ info->var.xoffset = 0;
+ info->var.yoffset = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+
+ /* Unlock registers */
+ svga_wseq_mask(0x10, 0x01, 0x01);
+ svga_wcrt_mask(0x11, 0x00, 0x80);
+ svga_wcrt_mask(0x47, 0x00, 0x01);
+
+ /* Device, screen and sync off */
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ svga_wcrt_mask(0x36, 0x30, 0x30);
+ svga_wcrt_mask(0x17, 0x00, 0x80);
+
+ /* Set default values */
+ svga_set_default_gfx_regs();
+ svga_set_default_atc_regs();
+ svga_set_default_seq_regs();
+ svga_set_default_crt_regs();
+ svga_wcrt_multi(vt8623_line_compare_regs, 0xFFFFFFFF);
+ svga_wcrt_multi(vt8623_start_address_regs, 0);
+
+ svga_wcrt_multi(vt8623_offset_regs, offset_value);
+ svga_wseq_multi(vt8623_fetch_count_regs, fetch_value);
+
+ if (info->var.vmode & FB_VMODE_DOUBLE)
+ svga_wcrt_mask(0x09, 0x80, 0x80);
+ else
+ svga_wcrt_mask(0x09, 0x00, 0x80);
+
+ svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
+ svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
+ svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold
+ vga_wseq(NULL, 0x17, 0x1F); // FIFO depth
+ vga_wseq(NULL, 0x18, 0x4E);
+ svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
+
+ vga_wcrt(NULL, 0x32, 0x00);
+ vga_wcrt(NULL, 0x34, 0x00);
+ vga_wcrt(NULL, 0x6A, 0x80);
+ vga_wcrt(NULL, 0x6A, 0xC0);
+
+ vga_wgfx(NULL, 0x20, 0x00);
+ vga_wgfx(NULL, 0x21, 0x00);
+ vga_wgfx(NULL, 0x22, 0x00);
+
+ /* Set SR15 according to number of bits per pixel */
+ mode = svga_match_format(vt8623fb_formats, &(info->var), &(info->fix));
+ switch (mode) {
+ case 0:
+ pr_debug("fb%d: text mode\n", info->node);
+ svga_set_textmode_vga_regs();
+ svga_wseq_mask(0x15, 0x00, 0xFE);
+ svga_wcrt_mask(0x11, 0x60, 0x70);
+ break;
+ case 1:
+ pr_debug("fb%d: 4 bit pseudocolor\n", info->node);
+ vga_wgfx(NULL, VGA_GFX_MODE, 0x40);
+ svga_wseq_mask(0x15, 0x20, 0xFE);
+ svga_wcrt_mask(0x11, 0x00, 0x70);
+ break;
+ case 2:
+ pr_debug("fb%d: 4 bit pseudocolor, planar\n", info->node);
+ svga_wseq_mask(0x15, 0x00, 0xFE);
+ svga_wcrt_mask(0x11, 0x00, 0x70);
+ break;
+ case 3:
+ pr_debug("fb%d: 8 bit pseudocolor\n", info->node);
+ svga_wseq_mask(0x15, 0x22, 0xFE);
+ break;
+ case 4:
+ pr_debug("fb%d: 5/6/5 truecolor\n", info->node);
+ svga_wseq_mask(0x15, 0xB6, 0xFE);
+ break;
+ case 5:
+ pr_debug("fb%d: 8/8/8 truecolor\n", info->node);
+ svga_wseq_mask(0x15, 0xAE, 0xFE);
+ break;
+ default:
+ printk(KERN_ERR "vt8623fb: unsupported mode - bug\n");
+ return (-EINVAL);
+ }
+
+ vt8623_set_pixclock(info, info->var.pixclock);
+ svga_set_timings(&vt8623_timing_regs, &(info->var), 1, 1,
+ (info->var.vmode & FB_VMODE_DOUBLE) ? 2 : 1, 1,
+ 1, info->node);
+
+ memset_io(info->screen_base, 0x00, screen_size);
+
+ /* Device and screen back on */
+ svga_wcrt_mask(0x17, 0x80, 0x80);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+
+ return 0;
+}
+
+
+static int vt8623fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *fb)
+{
+ switch (fb->var.bits_per_pixel) {
+ case 0:
+ case 4:
+ if (regno >= 16)
+ return -EINVAL;
+
+ outb(0x0F, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 8:
+ if (regno >= 256)
+ return -EINVAL;
+
+ outb(0xFF, VGA_PEL_MSK);
+ outb(regno, VGA_PEL_IW);
+ outb(red >> 10, VGA_PEL_D);
+ outb(green >> 10, VGA_PEL_D);
+ outb(blue >> 10, VGA_PEL_D);
+ break;
+ case 16:
+ if (regno >= 16)
+ return 0;
+
+ if (fb->var.green.length == 5)
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
+ ((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
+ else if (fb->var.green.length == 6)
+ ((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ else
+ return -EINVAL;
+ break;
+ case 24:
+ case 32:
+ if (regno >= 16)
+ return 0;
+
+ /* ((transp & 0xFF00) << 16) */
+ ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
+ (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int vt8623fb_blank(int blank_mode, struct fb_info *info)
+{
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ pr_debug("fb%d: unblank\n", info->node);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x00, 0x20);
+ break;
+ case FB_BLANK_NORMAL:
+ pr_debug("fb%d: blank\n", info->node);
+ svga_wcrt_mask(0x36, 0x00, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ pr_debug("fb%d: DPMS standby (hsync off)\n", info->node);
+ svga_wcrt_mask(0x36, 0x10, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ pr_debug("fb%d: DPMS suspend (vsync off)\n", info->node);
+ svga_wcrt_mask(0x36, 0x20, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ case FB_BLANK_POWERDOWN:
+ pr_debug("fb%d: DPMS off (no sync)\n", info->node);
+ svga_wcrt_mask(0x36, 0x30, 0x30);
+ svga_wseq_mask(0x01, 0x20, 0x20);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int vt8623fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ unsigned int offset;
+
+ /* Calculate the offset */
+ if (var->bits_per_pixel == 0) {
+ offset = (var->yoffset / 16) * var->xres_virtual + var->xoffset;
+ offset = offset >> 3;
+ } else {
+ offset = (var->yoffset * info->fix.line_length) +
+ (var->xoffset * var->bits_per_pixel / 8);
+ offset = offset >> ((var->bits_per_pixel == 4) ? 2 : 1);
+ }
+
+ /* Set the offset */
+ svga_wcrt_multi(vt8623_start_address_regs, offset);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/* Frame buffer operations */
+
+static struct fb_ops vt8623fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = vt8623fb_open,
+ .fb_release = vt8623fb_release,
+ .fb_check_var = vt8623fb_check_var,
+ .fb_set_par = vt8623fb_set_par,
+ .fb_setcolreg = vt8623fb_setcolreg,
+ .fb_blank = vt8623fb_blank,
+ .fb_pan_display = vt8623fb_pan_display,
+ .fb_fillrect = vt8623fb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = vt8623fb_imageblit,
+ .fb_get_caps = svga_get_caps,
+};
+
+
+/* PCI probe */
+
+static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct fb_info *info;
+ struct vt8623fb_info *par;
+ unsigned int memsize1, memsize2;
+ int rc;
+
+ /* Ignore secondary VGA device because there is no VGA arbitration */
+ if (! svga_primary_device(dev)) {
+ dev_info(&(dev->dev), "ignoring secondary device\n");
+ return -ENODEV;
+ }
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(struct vt8623fb_info), NULL);
+ if (! info) {
+ dev_err(&(dev->dev), "cannot allocate memory\n");
+ return -ENOMEM;
+ }
+
+ par = info->par;
+ mutex_init(&par->open_lock);
+
+ info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
+ info->fbops = &vt8623fb_ops;
+
+ /* Prepare PCI device */
+
+ rc = pci_enable_device(dev);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot enable PCI device\n");
+ goto err_enable_device;
+ }
+
+ rc = pci_request_regions(dev, "vt8623fb");
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot reserve framebuffer region\n");
+ goto err_request_regions;
+ }
+
+ info->fix.smem_start = pci_resource_start(dev, 0);
+ info->fix.smem_len = pci_resource_len(dev, 0);
+ info->fix.mmio_start = pci_resource_start(dev, 1);
+ info->fix.mmio_len = pci_resource_len(dev, 1);
+
+ /* Map physical IO memory address into kernel space */
+ info->screen_base = pci_iomap(dev, 0, 0);
+ if (! info->screen_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for framebuffer failed\n");
+ goto err_iomap_1;
+ }
+
+ par->mmio_base = pci_iomap(dev, 1, 0);
+ if (! par->mmio_base) {
+ rc = -ENOMEM;
+ dev_err(&(dev->dev), "iomap for MMIO failed\n");
+ goto err_iomap_2;
+ }
+
+ /* Find how many physical memory there is on card */
+ memsize1 = (vga_rseq(NULL, 0x34) + 1) >> 1;
+ memsize2 = vga_rseq(NULL, 0x39) << 2;
+
+ if ((16 <= memsize1) && (memsize1 <= 64) && (memsize1 == memsize2))
+ info->screen_size = memsize1 << 20;
+ else {
+ dev_err(&(dev->dev), "memory size detection failed (%x %x), suppose 16 MB\n", memsize1, memsize2);
+ info->screen_size = 16 << 20;
+ }
+
+ info->fix.smem_len = info->screen_size;
+ strcpy(info->fix.id, "VIA VT8623");
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->pseudo_palette = (void*)par->pseudo_palette;
+
+ /* Prepare startup mode */
+
+ rc = fb_find_mode(&(info->var), info, mode, NULL, 0, NULL, 8);
+ if (! ((rc == 1) || (rc == 2))) {
+ rc = -EINVAL;
+ dev_err(&(dev->dev), "mode %s not found\n", mode);
+ goto err_find_mode;
+ }
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot allocate colormap\n");
+ goto err_alloc_cmap;
+ }
+
+ rc = register_framebuffer(info);
+ if (rc < 0) {
+ dev_err(&(dev->dev), "cannot register framebugger\n");
+ goto err_reg_fb;
+ }
+
+ printk(KERN_INFO "fb%d: %s on %s, %d MB RAM\n", info->node, info->fix.id,
+ pci_name(dev), info->fix.smem_len >> 20);
+
+ /* Record a reference to the driver data */
+ pci_set_drvdata(dev, info);
+
+#ifdef CONFIG_MTRR
+ if (mtrr) {
+ par->mtrr_reg = -1;
+ par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
+ }
+#endif
+
+ return 0;
+
+ /* Error handling */
+err_reg_fb:
+ fb_dealloc_cmap(&info->cmap);
+err_alloc_cmap:
+err_find_mode:
+ pci_iounmap(dev, par->mmio_base);
+err_iomap_2:
+ pci_iounmap(dev, info->screen_base);
+err_iomap_1:
+ pci_release_regions(dev);
+err_request_regions:
+/* pci_disable_device(dev); */
+err_enable_device:
+ framebuffer_release(info);
+ return rc;
+}
+
+/* PCI remove */
+
+static void __devexit vt8623_pci_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ if (info) {
+#ifdef CONFIG_MTRR
+ if (par->mtrr_reg >= 0) {
+ mtrr_del(par->mtrr_reg, 0, 0);
+ par->mtrr_reg = -1;
+ }
+#endif
+
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ pci_iounmap(dev, info->screen_base);
+ pci_iounmap(dev, par->mmio_base);
+ pci_release_regions(dev);
+/* pci_disable_device(dev); */
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* PCI suspend */
+
+static int vt8623_pci_suspend(struct pci_dev* dev, pm_message_t state)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "suspend\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ fb_set_suspend(info, 1);
+
+ pci_save_state(dev);
+ pci_disable_device(dev);
+ pci_set_power_state(dev, pci_choose_state(dev, state));
+
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+
+ return 0;
+}
+
+
+/* PCI resume */
+
+static int vt8623_pci_resume(struct pci_dev* dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+ struct vt8623fb_info *par = info->par;
+
+ dev_info(&(dev->dev), "resume\n");
+
+ acquire_console_sem();
+ mutex_lock(&(par->open_lock));
+
+ if (par->ref_count == 0) {
+ mutex_unlock(&(par->open_lock));
+ release_console_sem();
+ return 0;
+ }
+
+ pci_set_power_state(dev, PCI_D0);
+ pci_restore_state(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
+ pci_set_master(dev);
+
+ vt8623fb_set_par(info);
+ fb_set_suspend(info, 0);
+
+ mutex_unlock(&(par->open_lock));
+fail:
+ release_console_sem();
+
+ return 0;
+}
+#else
+#define vt8623_pci_suspend NULL
+#define vt8623_pci_resume NULL
+#endif /* CONFIG_PM */
+
+/* List of boards that we are trying to support */
+
+static struct pci_device_id vt8623_devices[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_VIA, 0x3122)},
+ {0, 0, 0, 0, 0, 0, 0}
+};
+
+MODULE_DEVICE_TABLE(pci, vt8623_devices);
+
+static struct pci_driver vt8623fb_pci_driver = {
+ .name = "vt8623fb",
+ .id_table = vt8623_devices,
+ .probe = vt8623_pci_probe,
+ .remove = __devexit_p(vt8623_pci_remove),
+ .suspend = vt8623_pci_suspend,
+ .resume = vt8623_pci_resume,
+};
+
+/* Cleanup */
+
+static void __exit vt8623fb_cleanup(void)
+{
+ pr_debug("vt8623fb: cleaning up\n");
+ pci_unregister_driver(&vt8623fb_pci_driver);
+}
+
+/* Driver Initialisation */
+
+int __init vt8623fb_init(void)
+{
+
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("vt8623fb", &option))
+ return -ENODEV;
+
+ if (option && *option)
+ mode = option;
+#endif
+
+ pr_debug("vt8623fb: initializing\n");
+ return pci_register_driver(&vt8623fb_pci_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Modularization */
+
+module_init(vt8623fb_init);
+module_exit(vt8623fb_cleanup);
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
new file mode 100644
index 00000000000..1d29a89a86b
--- /dev/null
+++ b/drivers/video/xilinxfb.c
@@ -0,0 +1,381 @@
+/*
+ * xilinxfb.c
+ *
+ * Xilinx TFT LCD frame buffer driver
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2007 (c) MontaVista Software, Inc. 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.
+ */
+
+/*
+ * This driver was based on au1100fb.c by MontaVista rewritten for 2.6
+ * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn
+ * was based on skeletonfb.c, Skeleton for a frame buffer device by
+ * Geert Uytterhoeven.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <syslib/virtex_devices.h>
+
+#define DRIVER_NAME "xilinxfb"
+#define DRIVER_DESCRIPTION "Xilinx TFT LCD frame buffer driver"
+
+/*
+ * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for
+ * the VGA port on the Xilinx ML40x board. This is a hardware display controller
+ * for a 640x480 resolution TFT or VGA screen.
+ *
+ * The interface to the framebuffer is nice and simple. There are two
+ * control registers. The first tells the LCD interface where in memory
+ * the frame buffer is (only the 11 most significant bits are used, so
+ * don't start thinking about scrolling). The second allows the LCD to
+ * be turned on or off as well as rotated 180 degrees.
+ */
+#define NUM_REGS 2
+#define REG_FB_ADDR 0
+#define REG_CTRL 1
+#define REG_CTRL_ENABLE 0x0001
+#define REG_CTRL_ROTATE 0x0002
+
+/*
+ * The hardware only handles a single mode: 640x480 24 bit true
+ * color. Each pixel gets a word (32 bits) of memory. Within each word,
+ * the 8 most significant bits are ignored, the next 8 bits are the red
+ * level, the next 8 bits are the green level and the 8 least
+ * significant bits are the blue level. Each row of the LCD uses 1024
+ * words, but only the first 640 pixels are displayed with the other 384
+ * words being ignored. There are 480 rows.
+ */
+#define BYTES_PER_PIXEL 4
+#define BITS_PER_PIXEL (BYTES_PER_PIXEL * 8)
+#define XRES 640
+#define YRES 480
+#define XRES_VIRTUAL 1024
+#define YRES_VIRTUAL YRES
+#define LINE_LENGTH (XRES_VIRTUAL * BYTES_PER_PIXEL)
+#define FB_SIZE (YRES_VIRTUAL * LINE_LENGTH)
+
+#define RED_SHIFT 16
+#define GREEN_SHIFT 8
+#define BLUE_SHIFT 0
+
+#define PALETTE_ENTRIES_NO 16 /* passed to fb_alloc_cmap() */
+
+/*
+ * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
+ */
+static struct fb_fix_screeninfo xilinx_fb_fix __initdata = {
+ .id = "Xilinx",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .smem_len = FB_SIZE,
+ .line_length = LINE_LENGTH,
+ .accel = FB_ACCEL_NONE
+};
+
+static struct fb_var_screeninfo xilinx_fb_var __initdata = {
+ .xres = XRES,
+ .yres = YRES,
+ .xres_virtual = XRES_VIRTUAL,
+ .yres_virtual = YRES_VIRTUAL,
+
+ .bits_per_pixel = BITS_PER_PIXEL,
+
+ .red = { RED_SHIFT, 8, 0 },
+ .green = { GREEN_SHIFT, 8, 0 },
+ .blue = { BLUE_SHIFT, 8, 0 },
+ .transp = { 0, 0, 0 },
+
+ .activate = FB_ACTIVATE_NOW
+};
+
+struct xilinxfb_drvdata {
+
+ struct fb_info info; /* FB driver info record */
+
+ u32 regs_phys; /* phys. address of the control registers */
+ u32 __iomem *regs; /* virt. address of the control registers */
+
+ unsigned char __iomem *fb_virt; /* virt. address of the frame buffer */
+ dma_addr_t fb_phys; /* phys. address of the frame buffer */
+
+ u32 reg_ctrl_default;
+
+ u32 pseudo_palette[PALETTE_ENTRIES_NO];
+ /* Fake palette of 16 colors */
+};
+
+#define to_xilinxfb_drvdata(_info) \
+ container_of(_info, struct xilinxfb_drvdata, info)
+
+/*
+ * The LCD controller has DCR interface to its registers, but all
+ * the boards and configurations the driver has been tested with
+ * use opb2dcr bridge. So the registers are seen as memory mapped.
+ * This macro is to make it simple to add the direct DCR access
+ * when it's needed.
+ */
+#define xilinx_fb_out_be32(driverdata, offset, val) \
+ out_be32(driverdata->regs + offset, val)
+
+static int
+xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *fbi)
+{
+ u32 *palette = fbi->pseudo_palette;
+
+ if (regno >= PALETTE_ENTRIES_NO)
+ return -EINVAL;
+
+ if (fbi->var.grayscale) {
+ /* Convert color to grayscale.
+ * grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue =
+ (red * 77 + green * 151 + blue * 28 + 127) >> 8;
+ }
+
+ /* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */
+
+ /* We only handle 8 bits of each color. */
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) |
+ (blue << BLUE_SHIFT);
+
+ return 0;
+}
+
+static int
+xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+ struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi);
+
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ /* turn on panel */
+ xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
+ break;
+
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_POWERDOWN:
+ /* turn off panel */
+ xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+ default:
+ break;
+
+ }
+ return 0; /* success */
+}
+
+static struct fb_ops xilinxfb_ops =
+{
+ .owner = THIS_MODULE,
+ .fb_setcolreg = xilinx_fb_setcolreg,
+ .fb_blank = xilinx_fb_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+/* === The device driver === */
+
+static int
+xilinxfb_drv_probe(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct xilinxfb_platform_data *pdata;
+ struct xilinxfb_drvdata *drvdata;
+ struct resource *regs_res;
+ int retval;
+
+ if (!dev)
+ return -EINVAL;
+
+ pdev = to_platform_device(dev);
+ pdata = pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ printk(KERN_ERR "Couldn't find platform data.\n");
+ return -EFAULT;
+ }
+
+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata) {
+ printk(KERN_ERR "Couldn't allocate device private record\n");
+ return -ENOMEM;
+ }
+ dev_set_drvdata(dev, drvdata);
+
+ /* Map the control registers in */
+ regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) {
+ printk(KERN_ERR "Couldn't get registers resource\n");
+ retval = -EFAULT;
+ goto failed1;
+ }
+
+ if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
+ printk(KERN_ERR
+ "Couldn't lock memory region at 0x%08X\n",
+ regs_res->start);
+ retval = -EBUSY;
+ goto failed1;
+ }
+ drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
+ drvdata->regs_phys = regs_res->start;
+
+ /* Allocate the framebuffer memory */
+ drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE),
+ &drvdata->fb_phys, GFP_KERNEL);
+ if (!drvdata->fb_virt) {
+ printk(KERN_ERR "Could not allocate frame buffer memory\n");
+ retval = -ENOMEM;
+ goto failed2;
+ }
+
+ /* Clear (turn to black) the framebuffer */
+ memset_io((void *) drvdata->fb_virt, 0, FB_SIZE);
+
+ /* Tell the hardware where the frame buffer is */
+ xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
+
+ /* Turn on the display */
+ if (pdata->rotate_screen) {
+ drvdata->reg_ctrl_default = REG_CTRL_ENABLE | REG_CTRL_ROTATE;
+ } else {
+ drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
+ }
+ xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
+
+ /* Fill struct fb_info */
+ drvdata->info.device = dev;
+ drvdata->info.screen_base = drvdata->fb_virt;
+ drvdata->info.fbops = &xilinxfb_ops;
+ drvdata->info.fix = xilinx_fb_fix;
+ drvdata->info.fix.smem_start = drvdata->fb_phys;
+ drvdata->info.pseudo_palette = drvdata->pseudo_palette;
+
+ if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) {
+ printk(KERN_ERR "Fail to allocate colormap (%d entries)\n",
+ PALETTE_ENTRIES_NO);
+ retval = -EFAULT;
+ goto failed3;
+ }
+
+ drvdata->info.flags = FBINFO_DEFAULT;
+ xilinx_fb_var.height = pdata->screen_height_mm;
+ xilinx_fb_var.width = pdata->screen_width_mm;
+ drvdata->info.var = xilinx_fb_var;
+
+ /* Register new frame buffer */
+ if (register_framebuffer(&drvdata->info) < 0) {
+ printk(KERN_ERR "Could not register frame buffer\n");
+ retval = -EINVAL;
+ goto failed4;
+ }
+
+ return 0; /* success */
+
+failed4:
+ fb_dealloc_cmap(&drvdata->info.cmap);
+
+failed3:
+ dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
+ drvdata->fb_phys);
+
+ /* Turn off the display */
+ xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+ iounmap(drvdata->regs);
+
+failed2:
+ release_mem_region(regs_res->start, 8);
+
+failed1:
+ kfree(drvdata);
+ dev_set_drvdata(dev, NULL);
+
+ return retval;
+}
+
+static int
+xilinxfb_drv_remove(struct device *dev)
+{
+ struct xilinxfb_drvdata *drvdata;
+
+ if (!dev)
+ return -ENODEV;
+
+ drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev);
+
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+ xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
+#endif
+
+ unregister_framebuffer(&drvdata->info);
+
+ fb_dealloc_cmap(&drvdata->info.cmap);
+
+ dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
+ drvdata->fb_phys);
+
+ /* Turn off the display */
+ xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+ iounmap(drvdata->regs);
+
+ release_mem_region(drvdata->regs_phys, 8);
+
+ kfree(drvdata);
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+
+static struct device_driver xilinxfb_driver = {
+ .name = DRIVER_NAME,
+ .bus = &platform_bus_type,
+
+ .probe = xilinxfb_drv_probe,
+ .remove = xilinxfb_drv_remove
+};
+
+static int __init
+xilinxfb_init(void)
+{
+ /*
+ * No kernel boot options used,
+ * so we just need to register the driver
+ */
+ return driver_register(&xilinxfb_driver);
+}
+
+static void __exit
+xilinxfb_cleanup(void)
+{
+ driver_unregister(&xilinxfb_driver);
+}
+
+module_init(xilinxfb_init);
+module_exit(xilinxfb_cleanup);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 2fb425536ea..8f779338f74 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -35,5 +35,13 @@ config W1_MASTER_DS2482
This driver can also be built as a module. If so, the module
will be called ds2482.
+config W1_MASTER_DS1WM
+ tristate "Maxim DS1WM 1-wire busmaster"
+ depends on W1 && ARM
+ help
+ Say Y here to enable the DS1WM 1-wire driver, such as that
+ in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
+ hx4700.
+
endmenu
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile
index 4cee256a813..11551b32818 100644
--- a/drivers/w1/masters/Makefile
+++ b/drivers/w1/masters/Makefile
@@ -5,4 +5,4 @@
obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
-
+obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
new file mode 100644
index 00000000000..763bc73e507
--- /dev/null
+++ b/drivers/w1/masters/ds1wm.c
@@ -0,0 +1,468 @@
+/*
+ * 1-wire busmaster driver for DS1WM and ASICs with embedded DS1WMs
+ * such as HP iPAQs (including h5xxx, h2200, and devices with ASIC3
+ * like hx4700).
+ *
+ * Copyright (c) 2004-2005, Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>
+ * Copyright (c) 2004-2007, Matt Reimer <mreimer@vpop.net>
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/ds1wm.h>
+
+#include <asm/io.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+
+
+#define DS1WM_CMD 0x00 /* R/W 4 bits command */
+#define DS1WM_DATA 0x01 /* R/W 8 bits, transmit/receive buffer */
+#define DS1WM_INT 0x02 /* R/W interrupt status */
+#define DS1WM_INT_EN 0x03 /* R/W interrupt enable */
+#define DS1WM_CLKDIV 0x04 /* R/W 5 bits of divisor and pre-scale */
+
+#define DS1WM_CMD_1W_RESET (1 << 0) /* force reset on 1-wire bus */
+#define DS1WM_CMD_SRA (1 << 1) /* enable Search ROM accelerator mode */
+#define DS1WM_CMD_DQ_OUTPUT (1 << 2) /* write only - forces bus low */
+#define DS1WM_CMD_DQ_INPUT (1 << 3) /* read only - reflects state of bus */
+#define DS1WM_CMD_RST (1 << 5) /* software reset */
+#define DS1WM_CMD_OD (1 << 7) /* overdrive */
+
+#define DS1WM_INT_PD (1 << 0) /* presence detect */
+#define DS1WM_INT_PDR (1 << 1) /* presence detect result */
+#define DS1WM_INT_TBE (1 << 2) /* tx buffer empty */
+#define DS1WM_INT_TSRE (1 << 3) /* tx shift register empty */
+#define DS1WM_INT_RBF (1 << 4) /* rx buffer full */
+#define DS1WM_INT_RSRF (1 << 5) /* rx shift register full */
+
+#define DS1WM_INTEN_EPD (1 << 0) /* enable presence detect int */
+#define DS1WM_INTEN_IAS (1 << 1) /* INTR active state */
+#define DS1WM_INTEN_ETBE (1 << 2) /* enable tx buffer empty int */
+#define DS1WM_INTEN_ETMT (1 << 3) /* enable tx shift register empty int */
+#define DS1WM_INTEN_ERBF (1 << 4) /* enable rx buffer full int */
+#define DS1WM_INTEN_ERSRF (1 << 5) /* enable rx shift register full int */
+#define DS1WM_INTEN_DQO (1 << 6) /* enable direct bus driving ops */
+
+
+#define DS1WM_TIMEOUT (HZ * 5)
+
+static struct {
+ unsigned long freq;
+ unsigned long divisor;
+} freq[] = {
+ { 4000000, 0x8 },
+ { 5000000, 0x2 },
+ { 6000000, 0x5 },
+ { 7000000, 0x3 },
+ { 8000000, 0xc },
+ { 10000000, 0x6 },
+ { 12000000, 0x9 },
+ { 14000000, 0x7 },
+ { 16000000, 0x10 },
+ { 20000000, 0xa },
+ { 24000000, 0xd },
+ { 28000000, 0xb },
+ { 32000000, 0x14 },
+ { 40000000, 0xe },
+ { 48000000, 0x11 },
+ { 56000000, 0xf },
+ { 64000000, 0x18 },
+ { 80000000, 0x12 },
+ { 96000000, 0x15 },
+ { 112000000, 0x13 },
+ { 128000000, 0x1c },
+};
+
+struct ds1wm_data {
+ void *map;
+ int bus_shift; /* # of shifts to calc register offsets */
+ struct platform_device *pdev;
+ struct ds1wm_platform_data *pdata;
+ int irq;
+ int active_high;
+ struct clk *clk;
+ int slave_present;
+ void *reset_complete;
+ void *read_complete;
+ void *write_complete;
+ u8 read_byte; /* last byte received */
+};
+
+static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg,
+ u8 val)
+{
+ __raw_writeb(val, ds1wm_data->map + (reg << ds1wm_data->bus_shift));
+}
+
+static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg)
+{
+ return __raw_readb(ds1wm_data->map + (reg << ds1wm_data->bus_shift));
+}
+
+
+static irqreturn_t ds1wm_isr(int isr, void *data)
+{
+ struct ds1wm_data *ds1wm_data = data;
+ u8 intr = ds1wm_read_register(ds1wm_data, DS1WM_INT);
+
+ ds1wm_data->slave_present = (intr & DS1WM_INT_PDR) ? 0 : 1;
+
+ if ((intr & DS1WM_INT_PD) && ds1wm_data->reset_complete)
+ complete(ds1wm_data->reset_complete);
+
+ if ((intr & DS1WM_INT_TSRE) && ds1wm_data->write_complete)
+ complete(ds1wm_data->write_complete);
+
+ if (intr & DS1WM_INT_RBF) {
+ ds1wm_data->read_byte = ds1wm_read_register(ds1wm_data,
+ DS1WM_DATA);
+ if (ds1wm_data->read_complete)
+ complete(ds1wm_data->read_complete);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
+{
+ unsigned long timeleft;
+ DECLARE_COMPLETION_ONSTACK(reset_done);
+
+ ds1wm_data->reset_complete = &reset_done;
+
+ ds1wm_write_register(ds1wm_data, DS1WM_INT_EN, DS1WM_INTEN_EPD |
+ (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
+
+ ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_1W_RESET);
+
+ timeleft = wait_for_completion_timeout(&reset_done, DS1WM_TIMEOUT);
+ ds1wm_data->reset_complete = NULL;
+ if (!timeleft) {
+ dev_dbg(&ds1wm_data->pdev->dev, "reset failed\n");
+ return 1;
+ }
+
+ /* Wait for the end of the reset. According to the specs, the time
+ * from when the interrupt is asserted to the end of the reset is:
+ * tRSTH - tPDH - tPDL - tPDI
+ * 625 us - 60 us - 240 us - 100 ns = 324.9 us
+ *
+ * We'll wait a bit longer just to be sure.
+ */
+ udelay(500);
+
+ ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+ DS1WM_INTEN_ERBF | DS1WM_INTEN_ETMT | DS1WM_INTEN_EPD |
+ (ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0));
+
+ if (!ds1wm_data->slave_present) {
+ dev_dbg(&ds1wm_data->pdev->dev, "reset: no devices found\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ds1wm_write(struct ds1wm_data *ds1wm_data, u8 data)
+{
+ DECLARE_COMPLETION_ONSTACK(write_done);
+ ds1wm_data->write_complete = &write_done;
+
+ ds1wm_write_register(ds1wm_data, DS1WM_DATA, data);
+
+ wait_for_completion_timeout(&write_done, DS1WM_TIMEOUT);
+ ds1wm_data->write_complete = NULL;
+
+ return 0;
+}
+
+static int ds1wm_read(struct ds1wm_data *ds1wm_data, unsigned char write_data)
+{
+ DECLARE_COMPLETION_ONSTACK(read_done);
+ ds1wm_data->read_complete = &read_done;
+
+ ds1wm_write(ds1wm_data, write_data);
+ wait_for_completion_timeout(&read_done, DS1WM_TIMEOUT);
+ ds1wm_data->read_complete = NULL;
+
+ return ds1wm_data->read_byte;
+}
+
+static int ds1wm_find_divisor(int gclk)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(freq); i++)
+ if (gclk <= freq[i].freq)
+ return freq[i].divisor;
+
+ return 0;
+}
+
+static void ds1wm_up(struct ds1wm_data *ds1wm_data)
+{
+ int gclk, divisor;
+
+ if (ds1wm_data->pdata->enable)
+ ds1wm_data->pdata->enable(ds1wm_data->pdev);
+
+ gclk = clk_get_rate(ds1wm_data->clk);
+ clk_enable(ds1wm_data->clk);
+ divisor = ds1wm_find_divisor(gclk);
+ if (divisor == 0) {
+ dev_err(&ds1wm_data->pdev->dev,
+ "no suitable divisor for %dHz clock\n", gclk);
+ return;
+ }
+ ds1wm_write_register(ds1wm_data, DS1WM_CLKDIV, divisor);
+
+ /* Let the w1 clock stabilize. */
+ msleep(1);
+
+ ds1wm_reset(ds1wm_data);
+}
+
+static void ds1wm_down(struct ds1wm_data *ds1wm_data)
+{
+ ds1wm_reset(ds1wm_data);
+
+ /* Disable interrupts. */
+ ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
+ ds1wm_data->active_high ? DS1WM_INTEN_IAS : 0);
+
+ if (ds1wm_data->pdata->disable)
+ ds1wm_data->pdata->disable(ds1wm_data->pdev);
+
+ clk_disable(ds1wm_data->clk);
+}
+
+/* --------------------------------------------------------------------- */
+/* w1 methods */
+
+static u8 ds1wm_read_byte(void *data)
+{
+ struct ds1wm_data *ds1wm_data = data;
+
+ return ds1wm_read(ds1wm_data, 0xff);
+}
+
+static void ds1wm_write_byte(void *data, u8 byte)
+{
+ struct ds1wm_data *ds1wm_data = data;
+
+ ds1wm_write(ds1wm_data, byte);
+}
+
+static u8 ds1wm_reset_bus(void *data)
+{
+ struct ds1wm_data *ds1wm_data = data;
+
+ ds1wm_reset(ds1wm_data);
+
+ return 0;
+}
+
+static void ds1wm_search(void *data, u8 search_type,
+ w1_slave_found_callback slave_found)
+{
+ struct ds1wm_data *ds1wm_data = data;
+ int i;
+ unsigned long long rom_id;
+
+ /* XXX We need to iterate for multiple devices per the DS1WM docs.
+ * See http://www.maxim-ic.com/appnotes.cfm/appnote_number/120. */
+ if (ds1wm_reset(ds1wm_data))
+ return;
+
+ ds1wm_write(ds1wm_data, search_type);
+ ds1wm_write_register(ds1wm_data, DS1WM_CMD, DS1WM_CMD_SRA);
+
+ for (rom_id = 0, i = 0; i < 16; i++) {
+
+ unsigned char resp, r, d;
+
+ resp = ds1wm_read(ds1wm_data, 0x00);
+
+ r = ((resp & 0x02) >> 1) |
+ ((resp & 0x08) >> 2) |
+ ((resp & 0x20) >> 3) |
+ ((resp & 0x80) >> 4);
+
+ d = ((resp & 0x01) >> 0) |
+ ((resp & 0x04) >> 1) |
+ ((resp & 0x10) >> 2) |
+ ((resp & 0x40) >> 3);
+
+ rom_id |= (unsigned long long) r << (i * 4);
+
+ }
+ dev_dbg(&ds1wm_data->pdev->dev, "found 0x%08llX", rom_id);
+
+ ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
+ ds1wm_reset(ds1wm_data);
+
+ slave_found(ds1wm_data, rom_id);
+}
+
+/* --------------------------------------------------------------------- */
+
+static struct w1_bus_master ds1wm_master = {
+ .read_byte = ds1wm_read_byte,
+ .write_byte = ds1wm_write_byte,
+ .reset_bus = ds1wm_reset_bus,
+ .search = ds1wm_search,
+};
+
+static int ds1wm_probe(struct platform_device *pdev)
+{
+ struct ds1wm_data *ds1wm_data;
+ struct ds1wm_platform_data *plat;
+ struct resource *res;
+ int ret;
+
+ if (!pdev)
+ return -ENODEV;
+
+ ds1wm_data = kzalloc(sizeof (*ds1wm_data), GFP_KERNEL);
+ if (!ds1wm_data)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ds1wm_data);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENXIO;
+ goto err0;
+ }
+ ds1wm_data->map = ioremap(res->start, res->end - res->start + 1);
+ if (!ds1wm_data->map) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+ plat = pdev->dev.platform_data;
+ ds1wm_data->bus_shift = plat->bus_shift;
+ ds1wm_data->pdev = pdev;
+ ds1wm_data->pdata = plat;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ ret = -ENXIO;
+ goto err1;
+ }
+ ds1wm_data->irq = res->start;
+ ds1wm_data->active_high = (res->flags & IORESOURCE_IRQ_HIGHEDGE) ?
+ 1 : 0;
+
+ set_irq_type(ds1wm_data->irq, ds1wm_data->active_high ?
+ IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING);
+
+ ret = request_irq(ds1wm_data->irq, ds1wm_isr, IRQF_DISABLED,
+ "ds1wm", ds1wm_data);
+ if (ret)
+ goto err1;
+
+ ds1wm_data->clk = clk_get(&pdev->dev, "ds1wm");
+ if (!ds1wm_data->clk) {
+ ret = -ENOENT;
+ goto err2;
+ }
+
+ ds1wm_up(ds1wm_data);
+
+ ds1wm_master.data = (void *)ds1wm_data;
+
+ ret = w1_add_master_device(&ds1wm_master);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ ds1wm_down(ds1wm_data);
+ clk_put(ds1wm_data->clk);
+err2:
+ free_irq(ds1wm_data->irq, ds1wm_data);
+err1:
+ iounmap(ds1wm_data->map);
+err0:
+ kfree(ds1wm_data);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int ds1wm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+ ds1wm_down(ds1wm_data);
+
+ return 0;
+}
+
+static int ds1wm_resume(struct platform_device *pdev)
+{
+ struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+ ds1wm_up(ds1wm_data);
+
+ return 0;
+}
+#else
+#define ds1wm_suspend NULL
+#define ds1wm_resume NULL
+#endif
+
+static int ds1wm_remove(struct platform_device *pdev)
+{
+ struct ds1wm_data *ds1wm_data = platform_get_drvdata(pdev);
+
+ w1_remove_master_device(&ds1wm_master);
+ ds1wm_down(ds1wm_data);
+ clk_put(ds1wm_data->clk);
+ free_irq(ds1wm_data->irq, ds1wm_data);
+ iounmap(ds1wm_data->map);
+ kfree(ds1wm_data);
+
+ return 0;
+}
+
+static struct platform_driver ds1wm_driver = {
+ .driver = {
+ .name = "ds1wm",
+ },
+ .probe = ds1wm_probe,
+ .remove = ds1wm_remove,
+ .suspend = ds1wm_suspend,
+ .resume = ds1wm_resume
+};
+
+static int __init ds1wm_init(void)
+{
+ printk("DS1WM w1 busmaster driver - (c) 2004 Szabolcs Gyurko\n");
+ return platform_driver_register(&ds1wm_driver);
+}
+
+static void __exit ds1wm_exit(void)
+{
+ platform_driver_unregister(&ds1wm_driver);
+}
+
+module_init(ds1wm_init);
+module_exit(ds1wm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Szabolcs Gyurko <szabolcs.gyurko@tlt.hu>, "
+ "Matt Reimer <mreimer@vpop.net>");
+MODULE_DESCRIPTION("DS1WM w1 busmaster driver");
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 63c07243993..7d6876dbcc9 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -459,7 +459,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
(unsigned long long) sl->reg_num.id);
dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,
- &sl->dev.bus_id[0]);
+ &sl->dev.bus_id[0], sl);
err = device_register(&sl->dev);
if (err < 0) {
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 357a2e0f637..258defdb2ef 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -100,7 +100,8 @@ int w1_add_master_device(struct w1_bus_master *master)
/* validate minimum functionality */
if (!(master->touch_bit && master->reset_bus) &&
- !(master->write_bit && master->read_bit)) {
+ !(master->write_bit && master->read_bit) &&
+ !(master->write_byte && master->read_byte && master->reset_bus)) {
printk(KERN_ERR "w1_add_master_device: invalid function set\n");
return(-EINVAL);
}
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index b3ce8859a58..2ce4cebc31d 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -90,8 +90,9 @@ get_zorro_dev_info(char *buf, char **start, off_t pos, int count)
for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) {
struct zorro_dev *z = &zorro_autocon[slot];
len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot,
- z->id, zorro_resource_start(z),
- zorro_resource_len(z), z->rom.er_Type);
+ z->id, (unsigned long)zorro_resource_start(z),
+ (unsigned long)zorro_resource_len(z),
+ z->rom.er_Type);
at += len;
if (at >= pos) {
if (!*start) {
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 87c29d7b6c1..c3ba0ec334c 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -42,7 +42,8 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *
struct zorro_dev *z = to_zorro_dev(dev);
return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
- zorro_resource_start(z), zorro_resource_end(z),
+ (unsigned long)zorro_resource_start(z),
+ (unsigned long)zorro_resource_end(z),
zorro_resource_flags(z));
}
diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c
index 0f2b40605b0..4cc42b64820 100644
--- a/drivers/zorro/zorro.c
+++ b/drivers/zorro/zorro.c
@@ -164,7 +164,8 @@ static int __init zorro_init(void)
if (request_resource(zorro_find_parent_resource(z), &z->resource))
printk(KERN_ERR "Zorro: Address space collision on device %s "
"[%lx:%lx]\n",
- z->name, zorro_resource_start(z), zorro_resource_end(z));
+ z->name, (unsigned long)zorro_resource_start(z),
+ (unsigned long)zorro_resource_end(z));
sprintf(z->dev.bus_id, "%02x", i);
z->dev.parent = &zorro_bus.dev;
z->dev.bus = &zorro_bus_type;
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index bed48fa9652..3128aa948a4 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -29,7 +29,6 @@
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/pagemap.h>
#include <linux/idr.h>
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index ddffd8aa902..775e26e82cb 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -30,7 +30,6 @@
#include <linux/pagemap.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/namei.h>
#include <linux/idr.h>
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 3129688143e..1dd86ee90bc 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -29,7 +29,6 @@
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/inet.h>
#include <linux/idr.h>
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index c7b67725384..6e7678e4852 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -30,7 +30,6 @@
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/list.h>
#include <asm/uaccess.h>
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index b01b0a45793..7624821729a 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -30,7 +30,6 @@
#include <linux/pagemap.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/namei.h>
#include <linux/idr.h>
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 0ec42f66545..8eb9263a67b 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -31,7 +31,6 @@
#include <linux/file.h>
#include <linux/stat.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
diff --git a/fs/Kconfig b/fs/Kconfig
index e33c0892457..0fa0c1193e8 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -314,7 +314,7 @@ config REISERFS_CHECK
config REISERFS_PROC_INFO
bool "Stats in /proc/fs/reiserfs"
- depends on REISERFS_FS
+ depends on REISERFS_FS && PROC_FS
help
Create under /proc/fs/reiserfs a hierarchy of files, displaying
various ReiserFS statistics and internal data at the expense of
@@ -724,10 +724,6 @@ config FAT_FS
file system and use GNU tar's M option. GNU tar is a program
available for Unix and DOS ("man tar" or "info tar").
- It is now also becoming possible to read and write compressed FAT
- file systems; read <file:Documentation/filesystems/fat_cvf.txt> for
- details.
-
The FAT support will enlarge your kernel by about 37 KB. If unsure,
say Y.
@@ -1734,6 +1730,18 @@ config SUNRPC
config SUNRPC_GSS
tristate
+config SUNRPC_BIND34
+ bool "Support for rpcbind versions 3 & 4 (EXPERIMENTAL)"
+ depends on SUNRPC && EXPERIMENTAL
+ help
+ Provides kernel support for querying rpcbind servers via versions 3
+ and 4 of the rpcbind protocol. The kernel automatically falls back
+ to version 2 if a remote rpcbind service does not support versions
+ 3 or 4.
+
+ If unsure, say N to get traditional behavior (version 2 rpcbind
+ requests only).
+
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index f3d3d81eb7e..74c64409ddb 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -26,7 +26,7 @@ config BINFMT_ELF
config BINFMT_ELF_FDPIC
bool "Kernel support for FDPIC ELF binaries"
default y
- depends on FRV
+ depends on (FRV || BLACKFIN)
help
ELF FDPIC binaries are based on ELF, but allow the individual load
segments of a binary to be located in memory independently of each
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 2e5f2c8371e..30c29650849 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -232,8 +232,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct adfs_inode_info *ei = (struct adfs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 4aa8079e71b..c8796906f58 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -628,11 +628,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned
return err;
}
if (to < PAGE_CACHE_SIZE) {
- char *kaddr = kmap_atomic(page, KM_USER0);
-
- memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0);
if (size > offset + to) {
if (size < offset + PAGE_CACHE_SIZE)
tmp = size & ~PAGE_CACHE_MASK;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index c3986a1911b..beff7d21e6e 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -87,8 +87,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct affs_inode_info *ei = (struct affs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
init_MUTEX(&ei->i_link_lock);
init_MUTEX(&ei->i_ext_lock);
inode_init_once(&ei->vfs_inode);
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 01545eb1d87..73ce561f3ea 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -18,10 +18,11 @@ kafs-objs := \
security.o \
server.o \
super.o \
- use-rtnetlink.o \
+ netdevices.o \
vlclient.o \
vlocation.o \
vnode.o \
- volume.o
+ volume.o \
+ write.o
obj-$(CONFIG_AFS_FS) := kafs.o
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index 89e0d1650a7..2198006d2d0 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -18,6 +18,8 @@
enum AFS_FS_Operations {
FSFETCHDATA = 130, /* AFS Fetch file data */
FSFETCHSTATUS = 132, /* AFS Fetch file status */
+ FSSTOREDATA = 133, /* AFS Store file data */
+ FSSTORESTATUS = 135, /* AFS Store file status */
FSREMOVEFILE = 136, /* AFS Remove a file */
FSCREATEFILE = 137, /* AFS Create a file */
FSRENAME = 138, /* AFS Rename or move a file or directory */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 639399f0ab6..f64e40fefc0 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -44,7 +44,7 @@ void afs_init_callback_state(struct afs_server *server)
while (!RB_EMPTY_ROOT(&server->cb_promises)) {
vnode = rb_entry(server->cb_promises.rb_node,
struct afs_vnode, cb_promise);
- _debug("UNPROMISE { vid=%x vn=%u uq=%u}",
+ _debug("UNPROMISE { vid=%x:%u uq=%u}",
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
rb_erase(&vnode->cb_promise, &server->cb_promises);
vnode->cb_promised = false;
@@ -84,11 +84,8 @@ void afs_broken_callback_work(struct work_struct *work)
/* if the vnode's data version number changed then its contents
* are different */
- if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
- _debug("zap data {%x:%u}",
- vnode->fid.vid, vnode->fid.vnode);
- invalidate_remote_inode(&vnode->vfs_inode);
- }
+ if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
+ afs_zap_data(vnode);
}
out:
@@ -468,7 +465,7 @@ int __init afs_callback_update_init(void)
/*
* shut down the callback update process
*/
-void __exit afs_callback_update_kill(void)
+void afs_callback_update_kill(void)
{
destroy_workqueue(afs_callback_update_worker);
}
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 6685f4cbccb..d5b2ad6575b 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -443,6 +443,7 @@ static void SRXAFSCB_GetCapabilities(struct work_struct *work)
reply.ia.netmask[loop] = ifs[loop].netmask.s_addr;
reply.ia.mtu[loop] = htonl(ifs[loop].mtu);
}
+ kfree(ifs);
}
reply.cap.capcount = htonl(1);
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index dac5b990c0c..2fb31276196 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -55,7 +55,8 @@ const struct inode_operations afs_dir_inode_operations = {
.rmdir = afs_rmdir,
.rename = afs_rename,
.permission = afs_permission,
- .getattr = afs_inode_getattr,
+ .getattr = afs_getattr,
+ .setattr = afs_setattr,
};
static struct dentry_operations afs_fs_dentry_operations = {
@@ -194,10 +195,7 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
page = read_mapping_page(dir->i_mapping, index, &file);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
- if (!PageUptodate(page))
- goto fail;
if (!PageChecked(page))
afs_dir_check_page(dir, page);
if (PageError(page))
@@ -494,7 +492,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
vnode = AFS_FS_I(dir);
- _enter("{%x:%d},%p{%s},",
+ _enter("{%x:%u},%p{%s},",
vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name);
ASSERTCMP(dentry->d_inode, ==, NULL);
@@ -734,7 +732,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
dvnode = AFS_FS_I(dir);
- _enter("{%x:%d},{%s},%o",
+ _enter("{%x:%u},{%s},%o",
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
ret = -ENAMETOOLONG;
@@ -799,7 +797,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
dvnode = AFS_FS_I(dir);
- _enter("{%x:%d},{%s}",
+ _enter("{%x:%u},{%s}",
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
ret = -ENAMETOOLONG;
@@ -845,7 +843,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
dvnode = AFS_FS_I(dir);
- _enter("{%x:%d},{%s}",
+ _enter("{%x:%u},{%s}",
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
ret = -ENAMETOOLONG;
@@ -919,7 +917,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode,
dvnode = AFS_FS_I(dir);
- _enter("{%x:%d},{%s},%o,",
+ _enter("{%x:%u},{%s},%o,",
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
ret = -ENAMETOOLONG;
@@ -986,7 +984,7 @@ static int afs_link(struct dentry *from, struct inode *dir,
vnode = AFS_FS_I(from->d_inode);
dvnode = AFS_FS_I(dir);
- _enter("{%x:%d},{%x:%d},{%s}",
+ _enter("{%x:%u},{%x:%u},{%s}",
vnode->fid.vid, vnode->fid.vnode,
dvnode->fid.vid, dvnode->fid.vnode,
dentry->d_name.name);
@@ -1035,7 +1033,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
dvnode = AFS_FS_I(dir);
- _enter("{%x:%d},{%s},%s",
+ _enter("{%x:%u},{%s},%s",
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
content);
@@ -1107,7 +1105,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
orig_dvnode = AFS_FS_I(old_dir);
new_dvnode = AFS_FS_I(new_dir);
- _enter("{%x:%d},{%x:%d},{%x:%d},{%s}",
+ _enter("{%x:%u},{%x:%u},{%x:%u},{%s}",
orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
vnode->fid.vid, vnode->fid.vnode,
new_dvnode->fid.vid, new_dvnode->fid.vnode,
diff --git a/fs/afs/file.c b/fs/afs/file.c
index ae256498f4f..3e25795e5a4 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -15,32 +15,43 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/writeback.h>
#include "internal.h"
-static int afs_file_readpage(struct file *file, struct page *page);
-static void afs_file_invalidatepage(struct page *page, unsigned long offset);
-static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_readpage(struct file *file, struct page *page);
+static void afs_invalidatepage(struct page *page, unsigned long offset);
+static int afs_releasepage(struct page *page, gfp_t gfp_flags);
+static int afs_launder_page(struct page *page);
const struct file_operations afs_file_operations = {
.open = afs_open,
.release = afs_release,
.llseek = generic_file_llseek,
.read = do_sync_read,
+ .write = do_sync_write,
.aio_read = generic_file_aio_read,
+ .aio_write = afs_file_write,
.mmap = generic_file_readonly_mmap,
.sendfile = generic_file_sendfile,
+ .fsync = afs_fsync,
};
const struct inode_operations afs_file_inode_operations = {
- .getattr = afs_inode_getattr,
+ .getattr = afs_getattr,
+ .setattr = afs_setattr,
.permission = afs_permission,
};
const struct address_space_operations afs_fs_aops = {
- .readpage = afs_file_readpage,
- .set_page_dirty = __set_page_dirty_nobuffers,
- .releasepage = afs_file_releasepage,
- .invalidatepage = afs_file_invalidatepage,
+ .readpage = afs_readpage,
+ .set_page_dirty = afs_set_page_dirty,
+ .launder_page = afs_launder_page,
+ .releasepage = afs_releasepage,
+ .invalidatepage = afs_invalidatepage,
+ .prepare_write = afs_prepare_write,
+ .commit_write = afs_commit_write,
+ .writepage = afs_writepage,
+ .writepages = afs_writepages,
};
/*
@@ -52,7 +63,7 @@ int afs_open(struct inode *inode, struct file *file)
struct key *key;
int ret;
- _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+ _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
key = afs_request_key(vnode->volume->cell);
if (IS_ERR(key)) {
@@ -78,7 +89,7 @@ int afs_release(struct inode *inode, struct file *file)
{
struct afs_vnode *vnode = AFS_FS_I(inode);
- _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+ _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
key_put(file->private_data);
_leave(" = 0");
@@ -89,10 +100,10 @@ int afs_release(struct inode *inode, struct file *file)
* deal with notification that a page was read from the cache
*/
#ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_read_complete(void *cookie_data,
- struct page *page,
- void *data,
- int error)
+static void afs_readpage_read_complete(void *cookie_data,
+ struct page *page,
+ void *data,
+ int error)
{
_enter("%p,%p,%p,%d", cookie_data, page, data, error);
@@ -109,10 +120,10 @@ static void afs_file_readpage_read_complete(void *cookie_data,
* deal with notification that a page was written to the cache
*/
#ifdef AFS_CACHING_SUPPORT
-static void afs_file_readpage_write_complete(void *cookie_data,
- struct page *page,
- void *data,
- int error)
+static void afs_readpage_write_complete(void *cookie_data,
+ struct page *page,
+ void *data,
+ int error)
{
_enter("%p,%p,%p,%d", cookie_data, page, data, error);
@@ -121,9 +132,9 @@ static void afs_file_readpage_write_complete(void *cookie_data,
#endif
/*
- * AFS read page from file (or symlink)
+ * AFS read page from file, directory or symlink
*/
-static int afs_file_readpage(struct file *file, struct page *page)
+static int afs_readpage(struct file *file, struct page *page)
{
struct afs_vnode *vnode;
struct inode *inode;
@@ -219,39 +230,17 @@ error:
}
/*
- * get a page cookie for the specified page
- */
-#ifdef AFS_CACHING_SUPPORT
-int afs_cache_get_page_cookie(struct page *page,
- struct cachefs_page **_page_cookie)
-{
- int ret;
-
- _enter("");
- ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO);
-
- _leave(" = %d", ret);
- return ret;
-}
-#endif
-
-/*
* invalidate part or all of a page
*/
-static void afs_file_invalidatepage(struct page *page, unsigned long offset)
+static void afs_invalidatepage(struct page *page, unsigned long offset)
{
int ret = 1;
- _enter("{%lu},%lu", page->index, offset);
+ kenter("{%lu},%lu", page->index, offset);
BUG_ON(!PageLocked(page));
if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
- struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
- cachefs_uncache_page(vnode->cache,page);
-#endif
-
/* We release buffers only if the entire page is being
* invalidated.
* The get_block cached value has been unconditionally
@@ -272,25 +261,33 @@ static void afs_file_invalidatepage(struct page *page, unsigned long offset)
}
/*
+ * write back a dirty page
+ */
+static int afs_launder_page(struct page *page)
+{
+ _enter("{%lu}", page->index);
+
+ return 0;
+}
+
+/*
* release a page and cleanup its private data
*/
-static int afs_file_releasepage(struct page *page, gfp_t gfp_flags)
+static int afs_releasepage(struct page *page, gfp_t gfp_flags)
{
- struct cachefs_page *pageio;
+ struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
+ struct afs_writeback *wb;
- _enter("{%lu},%x", page->index, gfp_flags);
+ _enter("{{%x:%u}[%lu],%lx},%x",
+ vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
+ gfp_flags);
if (PagePrivate(page)) {
-#ifdef AFS_CACHING_SUPPORT
- struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
- cachefs_uncache_page(vnode->cache, page);
-#endif
-
- pageio = (struct cachefs_page *) page_private(page);
+ wb = (struct afs_writeback *) page_private(page);
+ ASSERT(wb != NULL);
set_page_private(page, 0);
ClearPagePrivate(page);
-
- kfree(pageio);
+ afs_put_writeback(wb);
}
_leave(" = 0");
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 2393d2a08d7..025b1903d9e 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -33,8 +33,10 @@ static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid)
*/
static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
struct afs_file_status *status,
- struct afs_vnode *vnode)
+ struct afs_vnode *vnode,
+ afs_dataversion_t *store_version)
{
+ afs_dataversion_t expected_version;
const __be32 *bp = *_bp;
umode_t mode;
u64 data_version, size;
@@ -101,7 +103,11 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime;
}
- if (status->data_version != data_version) {
+ expected_version = status->data_version;
+ if (store_version)
+ expected_version = *store_version;
+
+ if (expected_version != data_version) {
status->data_version = data_version;
if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) {
_debug("vnode modified %llx on {%x:%u}",
@@ -110,6 +116,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
set_bit(AFS_VNODE_MODIFIED, &vnode->flags);
set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags);
}
+ } else if (store_version) {
+ status->data_version = data_version;
}
}
@@ -156,6 +164,44 @@ static void xdr_decode_AFSVolSync(const __be32 **_bp,
}
/*
+ * encode the requested attributes into an AFSStoreStatus block
+ */
+static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)
+{
+ __be32 *bp = *_bp;
+ u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0;
+
+ mask = 0;
+ if (attr->ia_valid & ATTR_MTIME) {
+ mask |= AFS_SET_MTIME;
+ mtime = attr->ia_mtime.tv_sec;
+ }
+
+ if (attr->ia_valid & ATTR_UID) {
+ mask |= AFS_SET_OWNER;
+ owner = attr->ia_uid;
+ }
+
+ if (attr->ia_valid & ATTR_GID) {
+ mask |= AFS_SET_GROUP;
+ group = attr->ia_gid;
+ }
+
+ if (attr->ia_valid & ATTR_MODE) {
+ mask |= AFS_SET_MODE;
+ mode = attr->ia_mode & S_IALLUGO;
+ }
+
+ *bp++ = htonl(mask);
+ *bp++ = htonl(mtime);
+ *bp++ = htonl(owner);
+ *bp++ = htonl(group);
+ *bp++ = htonl(mode);
+ *bp++ = 0; /* segment size */
+ *_bp = bp;
+}
+
+/*
* deliver reply data to an FS.FetchStatus
*/
static int afs_deliver_fs_fetch_status(struct afs_call *call,
@@ -175,7 +221,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call,
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
xdr_decode_AFSCallBack(&bp, vnode);
if (call->reply2)
xdr_decode_AFSVolSync(&bp, call->reply2);
@@ -206,7 +252,7 @@ int afs_fs_fetch_file_status(struct afs_server *server,
struct afs_call *call;
__be32 *bp;
- _enter(",%x,{%x:%d},,",
+ _enter(",%x,{%x:%u},,",
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4);
@@ -265,24 +311,20 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
call->offset = 0;
call->unmarshall++;
- if (call->count < PAGE_SIZE) {
- buffer = kmap_atomic(call->reply3, KM_USER0);
- memset(buffer + PAGE_SIZE - call->count, 0,
- call->count);
- kunmap_atomic(buffer, KM_USER0);
- }
-
/* extract the returned data */
case 2:
_debug("extract data");
- page = call->reply3;
- buffer = kmap_atomic(page, KM_USER0);
- ret = afs_extract_data(call, skb, last, buffer, call->count);
- kunmap_atomic(buffer, KM_USER0);
- switch (ret) {
- case 0: break;
- case -EAGAIN: return 0;
- default: return ret;
+ if (call->count > 0) {
+ page = call->reply3;
+ buffer = kmap_atomic(page, KM_USER0);
+ ret = afs_extract_data(call, skb, last, buffer,
+ call->count);
+ kunmap_atomic(buffer, KM_USER0);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
}
call->offset = 0;
@@ -299,7 +341,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
}
bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
xdr_decode_AFSCallBack(&bp, vnode);
if (call->reply2)
xdr_decode_AFSVolSync(&bp, call->reply2);
@@ -317,6 +359,14 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
if (!last)
return 0;
+ if (call->count < PAGE_SIZE) {
+ _debug("clear");
+ page = call->reply3;
+ buffer = kmap_atomic(page, KM_USER0);
+ memset(buffer + call->count, 0, PAGE_SIZE - call->count);
+ kunmap_atomic(buffer, KM_USER0);
+ }
+
_leave(" = 0 [done]");
return 0;
}
@@ -475,8 +525,8 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call,
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
xdr_decode_AFSFid(&bp, call->reply2);
- xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
- xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+ xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
xdr_decode_AFSCallBack_raw(&bp, call->reply4);
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
@@ -573,7 +623,7 @@ static int afs_deliver_fs_remove(struct afs_call *call,
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave(" = 0 [done]");
@@ -656,8 +706,8 @@ static int afs_deliver_fs_link(struct afs_call *call,
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
- xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode);
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
+ xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL);
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave(" = 0 [done]");
@@ -745,8 +795,8 @@ static int afs_deliver_fs_symlink(struct afs_call *call,
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
xdr_decode_AFSFid(&bp, call->reply2);
- xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL);
- xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode);
+ xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL);
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL);
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave(" = 0 [done]");
@@ -851,9 +901,10 @@ static int afs_deliver_fs_rename(struct afs_call *call,
/* unmarshall the reply once we've received all of it */
bp = call->buffer;
- xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode);
+ xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL);
if (new_dvnode != orig_dvnode)
- xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode);
+ xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode,
+ NULL);
/* xdr_decode_AFSVolSync(&bp, call->replyX); */
_leave(" = 0 [done]");
@@ -935,3 +986,262 @@ int afs_fs_rename(struct afs_server *server,
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
}
+
+/*
+ * deliver reply data to an FS.StoreData
+ */
+static int afs_deliver_fs_store_data(struct afs_call *call,
+ struct sk_buff *skb, bool last)
+{
+ struct afs_vnode *vnode = call->reply;
+ const __be32 *bp;
+
+ _enter(",,%u", last);
+
+ afs_transfer_reply(call, skb);
+ if (!last) {
+ _leave(" = 0 [more]");
+ return 0;
+ }
+
+ if (call->reply_size != call->reply_max) {
+ _leave(" = -EBADMSG [%u != %u]",
+ call->reply_size, call->reply_max);
+ return -EBADMSG;
+ }
+
+ /* unmarshall the reply once we've received all of it */
+ bp = call->buffer;
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode,
+ &call->store_version);
+ /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+ afs_pages_written_back(vnode, call);
+
+ _leave(" = 0 [done]");
+ return 0;
+}
+
+/*
+ * FS.StoreData operation type
+ */
+static const struct afs_call_type afs_RXFSStoreData = {
+ .name = "FS.StoreData",
+ .deliver = afs_deliver_fs_store_data,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * store a set of pages
+ */
+int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb,
+ pgoff_t first, pgoff_t last,
+ unsigned offset, unsigned to,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_vnode *vnode = wb->vnode;
+ struct afs_call *call;
+ loff_t size, pos, i_size;
+ __be32 *bp;
+
+ _enter(",%x,{%x:%u},,",
+ key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+
+ size = to - offset;
+ if (first != last)
+ size += (loff_t)(last - first) << PAGE_SHIFT;
+ pos = (loff_t)first << PAGE_SHIFT;
+ pos += offset;
+
+ i_size = i_size_read(&vnode->vfs_inode);
+ if (pos + size > i_size)
+ i_size = size + pos;
+
+ _debug("size %llx, at %llx, i_size %llx",
+ (unsigned long long) size, (unsigned long long) pos,
+ (unsigned long long) i_size);
+
+ BUG_ON(i_size > 0xffffffff); // TODO: use 64-bit store
+
+ call = afs_alloc_flat_call(&afs_RXFSStoreData,
+ (4 + 6 + 3) * 4,
+ (21 + 6) * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->wb = wb;
+ call->key = wb->key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+ call->mapping = vnode->vfs_inode.i_mapping;
+ call->first = first;
+ call->last = last;
+ call->first_offset = offset;
+ call->last_to = to;
+ call->send_pages = true;
+ call->store_version = vnode->status.data_version + 1;
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSTOREDATA);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ *bp++ = 0; /* mask */
+ *bp++ = 0; /* mtime */
+ *bp++ = 0; /* owner */
+ *bp++ = 0; /* group */
+ *bp++ = 0; /* unix mode */
+ *bp++ = 0; /* segment size */
+
+ *bp++ = htonl(pos);
+ *bp++ = htonl(size);
+ *bp++ = htonl(i_size);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * deliver reply data to an FS.StoreStatus
+ */
+static int afs_deliver_fs_store_status(struct afs_call *call,
+ struct sk_buff *skb, bool last)
+{
+ afs_dataversion_t *store_version;
+ struct afs_vnode *vnode = call->reply;
+ const __be32 *bp;
+
+ _enter(",,%u", last);
+
+ afs_transfer_reply(call, skb);
+ if (!last) {
+ _leave(" = 0 [more]");
+ return 0;
+ }
+
+ if (call->reply_size != call->reply_max) {
+ _leave(" = -EBADMSG [%u != %u]",
+ call->reply_size, call->reply_max);
+ return -EBADMSG;
+ }
+
+ /* unmarshall the reply once we've received all of it */
+ store_version = NULL;
+ if (call->operation_ID == FSSTOREDATA)
+ store_version = &call->store_version;
+
+ bp = call->buffer;
+ xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version);
+ /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+ _leave(" = 0 [done]");
+ return 0;
+}
+
+/*
+ * FS.StoreStatus operation type
+ */
+static const struct afs_call_type afs_RXFSStoreStatus = {
+ .name = "FS.StoreStatus",
+ .deliver = afs_deliver_fs_store_status,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+static const struct afs_call_type afs_RXFSStoreData_as_Status = {
+ .name = "FS.StoreData",
+ .deliver = afs_deliver_fs_store_status,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
+ * so as to alter the file size also
+ */
+static int afs_fs_setattr_size(struct afs_server *server, struct key *key,
+ struct afs_vnode *vnode, struct iattr *attr,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter(",%x,{%x:%u},,",
+ key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+ ASSERT(attr->ia_valid & ATTR_SIZE);
+ ASSERTCMP(attr->ia_size, <=, 0xffffffff); // TODO: use 64-bit store
+
+ call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
+ (4 + 6 + 3) * 4,
+ (21 + 6) * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+ call->store_version = vnode->status.data_version + 1;
+ call->operation_ID = FSSTOREDATA;
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSTOREDATA);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ xdr_encode_AFS_StoreStatus(&bp, attr);
+
+ *bp++ = 0; /* position of start of write */
+ *bp++ = 0; /* size of write */
+ *bp++ = htonl(attr->ia_size); /* new file length */
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * set the attributes on a file, using FS.StoreData if there's a change in file
+ * size, and FS.StoreStatus otherwise
+ */
+int afs_fs_setattr(struct afs_server *server, struct key *key,
+ struct afs_vnode *vnode, struct iattr *attr,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ if (attr->ia_valid & ATTR_SIZE)
+ return afs_fs_setattr_size(server, key, vnode, attr,
+ wait_mode);
+
+ _enter(",%x,{%x:%u},,",
+ key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+ call = afs_alloc_flat_call(&afs_RXFSStoreStatus,
+ (4 + 6) * 4,
+ (21 + 6) * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+ call->operation_ID = FSSTORESTATUS;
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSTORESTATUS);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ xdr_encode_AFS_StoreStatus(&bp, attr);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index c184a4ee599..515a5d12d8f 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -125,7 +125,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,
struct inode *inode;
int ret;
- _enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique);
+ _enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique);
as = sb->s_fs_info;
data.volume = as->volume;
@@ -204,6 +204,19 @@ bad_inode:
}
/*
+ * mark the data attached to an inode as obsolete due to a write on the server
+ * - might also want to ditch all the outstanding writes and dirty pages
+ */
+void afs_zap_data(struct afs_vnode *vnode)
+{
+ _enter("zap data {%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+ /* nuke all the non-dirty pages that aren't locked, mapped or being
+ * written back */
+ invalidate_remote_inode(&vnode->vfs_inode);
+}
+
+/*
* validate a vnode/inode
* - there are several things we need to check
* - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
@@ -258,10 +271,8 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
/* if the vnode's data version number changed then its contents are
* different */
- if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
- _debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode);
- invalidate_remote_inode(&vnode->vfs_inode);
- }
+ if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
+ afs_zap_data(vnode);
clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
mutex_unlock(&vnode->validate_lock);
@@ -278,7 +289,7 @@ error_unlock:
/*
* read the attributes of an inode
*/
-int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
+int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
struct inode *inode;
@@ -301,7 +312,7 @@ void afs_clear_inode(struct inode *inode)
vnode = AFS_FS_I(inode);
- _enter("{%x:%d.%d} v=%u x=%u t=%u }",
+ _enter("{%x:%u.%d} v=%u x=%u t=%u }",
vnode->fid.vid,
vnode->fid.vnode,
vnode->fid.unique,
@@ -323,6 +334,7 @@ void afs_clear_inode(struct inode *inode)
vnode->server = NULL;
}
+ ASSERT(list_empty(&vnode->writebacks));
ASSERT(!vnode->cb_promised);
#ifdef AFS_CACHING_SUPPORT
@@ -339,3 +351,47 @@ void afs_clear_inode(struct inode *inode)
_leave("");
}
+
+/*
+ * set the attributes of an inode
+ */
+int afs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+ struct key *key;
+ int ret;
+
+ _enter("{%x:%u},{n=%s},%x",
+ vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+ attr->ia_valid);
+
+ if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
+ ATTR_MTIME))) {
+ _leave(" = 0 [unsupported]");
+ return 0;
+ }
+
+ /* flush any dirty data outstanding on a regular file */
+ if (S_ISREG(vnode->vfs_inode.i_mode)) {
+ filemap_write_and_wait(vnode->vfs_inode.i_mapping);
+ afs_writeback_all(vnode);
+ }
+
+ if (attr->ia_valid & ATTR_FILE) {
+ key = attr->ia_file->private_data;
+ } else {
+ key = afs_request_key(vnode->volume->cell);
+ if (IS_ERR(key)) {
+ ret = PTR_ERR(key);
+ goto error;
+ }
+ }
+
+ ret = afs_vnode_setattr(vnode, key, attr);
+ if (!(attr->ia_valid & ATTR_FILE))
+ key_put(key);
+
+error:
+ _leave(" = %d", ret);
+ return ret;
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 6dd3197d1d8..a30d4fa768e 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -21,6 +21,7 @@
#define AFS_CELL_MAX_ADDRS 15
+struct pagevec;
struct afs_call;
typedef enum {
@@ -75,12 +76,15 @@ struct afs_call {
struct key *key; /* security for this call */
struct afs_server *server; /* server affected by incoming CM call */
void *request; /* request data (first part) */
- void *request2; /* request data (second part) */
+ struct address_space *mapping; /* page set */
+ struct afs_writeback *wb; /* writeback being performed */
void *buffer; /* reply receive buffer */
void *reply; /* reply buffer (first part) */
void *reply2; /* reply buffer (second part) */
void *reply3; /* reply buffer (third part) */
void *reply4; /* reply buffer (fourth part) */
+ pgoff_t first; /* first page in mapping to deal with */
+ pgoff_t last; /* last page in mapping to deal with */
enum { /* call state */
AFS_CALL_REQUESTING, /* request is being sent for outgoing call */
AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */
@@ -97,14 +101,18 @@ struct afs_call {
unsigned request_size; /* size of request data */
unsigned reply_max; /* maximum size of reply */
unsigned reply_size; /* current size of reply */
+ unsigned first_offset; /* offset into mapping[first] */
+ unsigned last_to; /* amount of mapping[last] */
unsigned short offset; /* offset into received data store */
unsigned char unmarshall; /* unmarshalling phase */
bool incoming; /* T if incoming call */
+ bool send_pages; /* T if data from mapping should be sent */
u16 service_id; /* RxRPC service ID to call */
__be16 port; /* target UDP port */
__be32 operation_ID; /* operation ID for an incoming call */
u32 count; /* count for use in unmarshalling */
__be32 tmp; /* place to extract temporary data */
+ afs_dataversion_t store_version; /* updated version expected from store */
};
struct afs_call_type {
@@ -124,6 +132,32 @@ struct afs_call_type {
};
/*
+ * record of an outstanding writeback on a vnode
+ */
+struct afs_writeback {
+ struct list_head link; /* link in vnode->writebacks */
+ struct work_struct writer; /* work item to perform the writeback */
+ struct afs_vnode *vnode; /* vnode to which this write applies */
+ struct key *key; /* owner of this write */
+ wait_queue_head_t waitq; /* completion and ready wait queue */
+ pgoff_t first; /* first page in batch */
+ pgoff_t point; /* last page in current store op */
+ pgoff_t last; /* last page in batch (inclusive) */
+ unsigned offset_first; /* offset into first page of start of write */
+ unsigned to_last; /* offset into last page of end of write */
+ int num_conflicts; /* count of conflicting writes in list */
+ int usage;
+ bool conflicts; /* T if has dependent conflicts */
+ enum {
+ AFS_WBACK_SYNCING, /* synchronisation being performed */
+ AFS_WBACK_PENDING, /* write pending */
+ AFS_WBACK_CONFLICTING, /* conflicting writes posted */
+ AFS_WBACK_WRITING, /* writing back */
+ AFS_WBACK_COMPLETE /* the writeback record has been unlinked */
+ } state __attribute__((packed));
+};
+
+/*
* AFS superblock private data
* - there's one superblock per volume
*/
@@ -305,6 +339,7 @@ struct afs_vnode {
wait_queue_head_t update_waitq; /* status fetch waitqueue */
int update_cnt; /* number of outstanding ops that will update the
* status */
+ spinlock_t writeback_lock; /* lock for writebacks */
spinlock_t lock; /* waitqueue/flags lock */
unsigned long flags;
#define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */
@@ -316,6 +351,8 @@ struct afs_vnode {
long acl_order; /* ACL check count (callback break count) */
+ struct list_head writebacks; /* alterations in pagecache that need writing */
+
/* outstanding callback notification on this file */
struct rb_node server_rb; /* link in server->fs_vnodes */
struct rb_node cb_promise; /* link in server->cb_promises */
@@ -349,7 +386,6 @@ struct afs_permits {
* record of one of a system's set of network interfaces
*/
struct afs_interface {
- unsigned index; /* interface index */
struct in_addr address; /* IPv4 address bound to interface */
struct in_addr netmask; /* netmask applied to address */
unsigned mtu; /* MTU of interface */
@@ -367,7 +403,7 @@ struct afs_uuid {
u32 time_low; /* low part of timestamp */
u16 time_mid; /* mid part of timestamp */
u16 time_hi_and_version; /* high part of timestamp and version */
-#define AFS_UUID_TO_UNIX_TIME 0x01b21dd213814000
+#define AFS_UUID_TO_UNIX_TIME 0x01b21dd213814000ULL
#define AFS_UUID_TIMEHI_MASK 0x0fff
#define AFS_UUID_VERSION_TIME 0x1000 /* time-based UUID */
#define AFS_UUID_VERSION_NAME 0x3000 /* name-based UUID */
@@ -392,7 +428,7 @@ extern void afs_give_up_callback(struct afs_vnode *);
extern void afs_dispatch_give_up_callbacks(struct work_struct *);
extern void afs_flush_callback_breaks(struct afs_server *);
extern int __init afs_callback_update_init(void);
-extern void __exit afs_callback_update_kill(void);
+extern void afs_callback_update_kill(void);
/*
* cell.c
@@ -434,10 +470,6 @@ extern const struct file_operations afs_file_operations;
extern int afs_open(struct inode *, struct file *);
extern int afs_release(struct inode *, struct file *);
-#ifdef AFS_CACHING_SUPPORT
-extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **);
-#endif
-
/*
* fsclient.c
*/
@@ -468,6 +500,12 @@ extern int afs_fs_rename(struct afs_server *, struct key *,
struct afs_vnode *, const char *,
struct afs_vnode *, const char *,
const struct afs_wait_mode *);
+extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *,
+ pgoff_t, pgoff_t, unsigned, unsigned,
+ const struct afs_wait_mode *);
+extern int afs_fs_setattr(struct afs_server *, struct key *,
+ struct afs_vnode *, struct iattr *,
+ const struct afs_wait_mode *);
/*
* inode.c
@@ -475,10 +513,10 @@ extern int afs_fs_rename(struct afs_server *, struct key *,
extern struct inode *afs_iget(struct super_block *, struct key *,
struct afs_fid *, struct afs_file_status *,
struct afs_callback *);
+extern void afs_zap_data(struct afs_vnode *);
extern int afs_validate(struct afs_vnode *, struct key *);
-extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
- struct kstat *);
-extern void afs_zap_permits(struct rcu_head *);
+extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
+extern int afs_setattr(struct dentry *, struct iattr *);
extern void afs_clear_inode(struct inode *);
/*
@@ -534,6 +572,7 @@ extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *,
*/
extern void afs_clear_permits(struct afs_vnode *);
extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
+extern void afs_zap_permits(struct rcu_head *);
extern struct key *afs_request_key(struct afs_cell *);
extern int afs_permission(struct inode *, int, struct nameidata *);
@@ -564,7 +603,7 @@ extern void afs_fs_exit(void);
* use-rtnetlink.c
*/
extern int afs_get_ipv4_interfaces(struct afs_interface *, size_t, bool);
-extern int afs_get_MAC_address(u8 [6]);
+extern int afs_get_MAC_address(u8 *, size_t);
/*
* vlclient.c
@@ -591,7 +630,7 @@ extern struct afs_vlocation *afs_vlocation_lookup(struct afs_cell *,
struct key *,
const char *, size_t);
extern void afs_put_vlocation(struct afs_vlocation *);
-extern void __exit afs_vlocation_purge(void);
+extern void afs_vlocation_purge(void);
/*
* vnode.c
@@ -630,6 +669,9 @@ extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *,
struct afs_file_status *, struct afs_server **);
extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *,
struct key *, const char *, const char *);
+extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
+ unsigned, unsigned);
+extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
/*
* volume.c
@@ -646,6 +688,23 @@ extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *);
extern int afs_volume_release_fileserver(struct afs_vnode *,
struct afs_server *, int);
+/*
+ * write.c
+ */
+extern int afs_set_page_dirty(struct page *);
+extern void afs_put_writeback(struct afs_writeback *);
+extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_writepage(struct page *, struct writeback_control *);
+extern int afs_writepages(struct address_space *, struct writeback_control *);
+extern int afs_write_inode(struct inode *, int);
+extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
+extern ssize_t afs_file_write(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
+extern int afs_writeback_all(struct afs_vnode *);
+extern int afs_fsync(struct file *, struct dentry *, int);
+
+
/*****************************************************************************/
/*
* debug tracing
@@ -727,6 +786,21 @@ do { \
} \
} while(0)
+#define ASSERTRANGE(L, OP1, N, OP2, H) \
+do { \
+ if (unlikely(!((L) OP1 (N)) || !((N) OP2 (H)))) { \
+ printk(KERN_ERR "\n"); \
+ printk(KERN_ERR "AFS: Assertion failed\n"); \
+ printk(KERN_ERR "%lu "#OP1" %lu "#OP2" %lu is false\n", \
+ (unsigned long)(L), (unsigned long)(N), \
+ (unsigned long)(H)); \
+ printk(KERN_ERR "0x%lx "#OP1" 0x%lx "#OP2" 0x%lx is false\n", \
+ (unsigned long)(L), (unsigned long)(N), \
+ (unsigned long)(H)); \
+ BUG(); \
+ } \
+} while(0)
+
#define ASSERTIF(C, X) \
do { \
if (unlikely((C) && !(X))) { \
@@ -759,6 +833,10 @@ do { \
do { \
} while(0)
+#define ASSERTRANGE(L, OP1, N, OP2, H) \
+do { \
+} while(0)
+
#define ASSERTIF(C, X) \
do { \
} while(0)
diff --git a/fs/afs/main.c b/fs/afs/main.c
index 40c2704e755..f1f71ff7d5c 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -54,7 +54,7 @@ static int __init afs_get_client_UUID(void)
/* read the MAC address of one of the external interfaces and construct
* a UUID from it */
- ret = afs_get_MAC_address(afs_uuid.node);
+ ret = afs_get_MAC_address(afs_uuid.node, sizeof(afs_uuid.node));
if (ret < 0)
return ret;
@@ -149,6 +149,7 @@ error_cache:
afs_vlocation_purge();
afs_cell_purge();
afs_proc_cleanup();
+ rcu_barrier();
printk(KERN_ERR "kAFS: failed to register: %d\n", ret);
return ret;
}
@@ -176,6 +177,7 @@ static void __exit afs_exit(void)
cachefs_unregister_netfs(&afs_cache_netfs);
#endif
afs_proc_cleanup();
+ rcu_barrier();
}
module_exit(afs_exit);
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index cdb9792d816..d1a889c4074 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -22,6 +22,7 @@ int afs_abort_to_error(u32 abort_code)
{
switch (abort_code) {
case 13: return -EACCES;
+ case 27: return -EFBIG;
case 30: return -EROFS;
case VSALVAGE: return -EIO;
case VNOVNODE: return -ENOENT;
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index b905ae37f91..a3684dcc76e 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -36,7 +36,7 @@ const struct inode_operations afs_mntpt_inode_operations = {
.lookup = afs_mntpt_lookup,
.follow_link = afs_mntpt_follow_link,
.readlink = page_readlink,
- .getattr = afs_inode_getattr,
+ .getattr = afs_getattr,
};
static LIST_HEAD(afs_vfsmounts);
@@ -58,7 +58,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
char *buf;
int ret;
- _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique);
+ _enter("{%x:%u,%u}",
+ vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
/* read the contents of the symlink into the pagecache */
page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
@@ -68,13 +69,11 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
}
ret = -EIO;
- wait_on_page_locked(page);
- buf = kmap(page);
- if (!PageUptodate(page))
- goto out_free;
if (PageError(page))
goto out_free;
+ buf = kmap(page);
+
/* examine the symlink's contents */
size = vnode->status.size;
_debug("symlink to %*.*s", (int) size, (int) size, buf);
@@ -91,8 +90,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
ret = 0;
-out_free:
kunmap(page);
+out_free:
page_cache_release(page);
out:
_leave(" = %d", ret);
@@ -171,8 +170,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
}
ret = -EIO;
- wait_on_page_locked(page);
- if (!PageUptodate(page) || PageError(page))
+ if (PageError(page))
goto error;
buf = kmap(page);
diff --git a/fs/afs/netdevices.c b/fs/afs/netdevices.c
new file mode 100644
index 00000000000..fc27d4b52e5
--- /dev/null
+++ b/fs/afs/netdevices.c
@@ -0,0 +1,68 @@
+/* AFS network device helpers
+ *
+ * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ */
+
+#include <linux/string.h>
+#include <linux/rtnetlink.h>
+#include <linux/inetdevice.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include "internal.h"
+
+/*
+ * get a MAC address from a random ethernet interface that has a real one
+ * - the buffer will normally be 6 bytes in size
+ */
+int afs_get_MAC_address(u8 *mac, size_t maclen)
+{
+ struct net_device *dev;
+ int ret = -ENODEV;
+
+ if (maclen != ETH_ALEN)
+ BUG();
+
+ rtnl_lock();
+ dev = __dev_getfirstbyhwtype(ARPHRD_ETHER);
+ if (dev) {
+ memcpy(mac, dev->dev_addr, maclen);
+ ret = 0;
+ }
+ rtnl_unlock();
+ return ret;
+}
+
+/*
+ * get a list of this system's interface IPv4 addresses, netmasks and MTUs
+ * - maxbufs must be at least 1
+ * - returns the number of interface records in the buffer
+ */
+int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
+ bool wantloopback)
+{
+ struct net_device *dev;
+ struct in_device *idev;
+ int n = 0;
+
+ ASSERT(maxbufs > 0);
+
+ rtnl_lock();
+ for_each_netdev(dev) {
+ if (dev->type == ARPHRD_LOOPBACK && !wantloopback)
+ continue;
+ idev = __in_dev_get_rtnl(dev);
+ if (!idev)
+ continue;
+ for_primary_ifa(idev) {
+ bufs[n].address.s_addr = ifa->ifa_address;
+ bufs[n].netmask.s_addr = ifa->ifa_mask;
+ bufs[n].mtu = dev->mtu;
+ n++;
+ if (n >= maxbufs)
+ goto out;
+ } endfor_ifa(idev);
+ }
+out:
+ rtnl_unlock();
+ return n;
+}
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index e7b047328a3..04189c47d6a 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -237,6 +237,70 @@ void afs_flat_call_destructor(struct afs_call *call)
}
/*
+ * attach the data from a bunch of pages on an inode to a call
+ */
+int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov)
+{
+ struct page *pages[8];
+ unsigned count, n, loop, offset, to;
+ pgoff_t first = call->first, last = call->last;
+ int ret;
+
+ _enter("");
+
+ offset = call->first_offset;
+ call->first_offset = 0;
+
+ do {
+ _debug("attach %lx-%lx", first, last);
+
+ count = last - first + 1;
+ if (count > ARRAY_SIZE(pages))
+ count = ARRAY_SIZE(pages);
+ n = find_get_pages_contig(call->mapping, first, count, pages);
+ ASSERTCMP(n, ==, count);
+
+ loop = 0;
+ do {
+ msg->msg_flags = 0;
+ to = PAGE_SIZE;
+ if (first + loop >= last)
+ to = call->last_to;
+ else
+ msg->msg_flags = MSG_MORE;
+ iov->iov_base = kmap(pages[loop]) + offset;
+ iov->iov_len = to - offset;
+ offset = 0;
+
+ _debug("- range %u-%u%s",
+ offset, to, msg->msg_flags ? " [more]" : "");
+ msg->msg_iov = (struct iovec *) iov;
+ msg->msg_iovlen = 1;
+
+ /* have to change the state *before* sending the last
+ * packet as RxRPC might give us the reply before it
+ * returns from sending the request */
+ if (first + loop >= last)
+ call->state = AFS_CALL_AWAIT_REPLY;
+ ret = rxrpc_kernel_send_data(call->rxcall, msg,
+ to - offset);
+ kunmap(pages[loop]);
+ if (ret < 0)
+ break;
+ } while (++loop < count);
+ first += count;
+
+ for (loop = 0; loop < count; loop++)
+ put_page(pages[loop]);
+ if (ret < 0)
+ break;
+ } while (first < last);
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
* initiate a call
*/
int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
@@ -253,8 +317,9 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
ASSERT(call->type != NULL);
ASSERT(call->type->name != NULL);
- _debug("MAKE %p{%s} [%d]",
- call, call->type->name, atomic_read(&afs_outstanding_calls));
+ _debug("____MAKE %p{%s,%x} [%d]____",
+ call, call->type->name, key_serial(call->key),
+ atomic_read(&afs_outstanding_calls));
call->wait_mode = wait_mode;
INIT_WORK(&call->async_work, afs_process_async_call);
@@ -289,16 +354,23 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
- msg.msg_flags = 0;
+ msg.msg_flags = (call->send_pages ? MSG_MORE : 0);
/* have to change the state *before* sending the last packet as RxRPC
* might give us the reply before it returns from sending the
* request */
- call->state = AFS_CALL_AWAIT_REPLY;
+ if (!call->send_pages)
+ call->state = AFS_CALL_AWAIT_REPLY;
ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size);
if (ret < 0)
goto error_do_abort;
+ if (call->send_pages) {
+ ret = afs_send_pages(call, &msg, iov);
+ if (ret < 0)
+ goto error_do_abort;
+ }
+
/* at this point, an async call may no longer exist as it may have
* already completed */
return wait_mode->wait(call);
@@ -772,7 +844,7 @@ int afs_extract_data(struct afs_call *call, struct sk_buff *skb,
if (call->offset < count) {
if (last) {
- _leave(" = -EBADMSG [%d < %lu]", call->offset, count);
+ _leave(" = -EBADMSG [%d < %zu]", call->offset, count);
return -EBADMSG;
}
_leave(" = -EAGAIN");
diff --git a/fs/afs/security.c b/fs/afs/security.c
index f9f424d8045..e0ea88b63eb 100644
--- a/fs/afs/security.c
+++ b/fs/afs/security.c
@@ -109,7 +109,7 @@ void afs_clear_permits(struct afs_vnode *vnode)
{
struct afs_permits *permits;
- _enter("{%x}", vnode->fid.vnode);
+ _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
mutex_lock(&vnode->permits_lock);
permits = vnode->permits;
@@ -132,7 +132,8 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order)
struct afs_vnode *auth_vnode;
int count, loop;
- _enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order);
+ _enter("{%x:%u},%x,%lx",
+ vnode->fid.vid, vnode->fid.vnode, key_serial(key), acl_order);
auth_vnode = afs_get_auth_inode(vnode, key);
if (IS_ERR(auth_vnode)) {
@@ -220,7 +221,8 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
bool valid;
int loop, ret;
- _enter("");
+ _enter("{%x:%u},%x",
+ vnode->fid.vid, vnode->fid.vnode, key_serial(key));
auth_vnode = afs_get_auth_inode(vnode, key);
if (IS_ERR(auth_vnode)) {
@@ -268,9 +270,9 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key,
_leave(" = %d", ret);
return ret;
}
+ *_access = vnode->status.caller_access;
}
- *_access = vnode->status.caller_access;
iput(&auth_vnode->vfs_inode);
_leave(" = 0 [access %x]", *_access);
return 0;
@@ -288,7 +290,7 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd)
struct key *key;
int ret;
- _enter("{{%x:%x},%lx},%x,",
+ _enter("{{%x:%u},%lx},%x,",
vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask);
key = afs_request_key(vnode->volume->cell);
diff --git a/fs/afs/server.c b/fs/afs/server.c
index 96bb23b476a..231ae415027 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -252,6 +252,9 @@ static void afs_destroy_server(struct afs_server *server)
{
_enter("%p", server);
+ ASSERTIF(server->cb_break_head != server->cb_break_tail,
+ delayed_work_pending(&server->cb_break_work));
+
ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL);
ASSERTCMP(server->cb_promises.rb_node, ==, NULL);
ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail);
diff --git a/fs/afs/super.c b/fs/afs/super.c
index cebd03c91f5..d24be334b60 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -20,6 +20,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/parser.h>
#include "internal.h"
#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
@@ -42,13 +43,14 @@ struct file_system_type afs_fs_type = {
.name = "afs",
.get_sb = afs_get_sb,
.kill_sb = kill_anon_super,
- .fs_flags = FS_BINARY_MOUNTDATA,
+ .fs_flags = 0,
};
static const struct super_operations afs_super_ops = {
.statfs = simple_statfs,
.alloc_inode = afs_alloc_inode,
.drop_inode = generic_delete_inode,
+ .write_inode = afs_write_inode,
.destroy_inode = afs_destroy_inode,
.clear_inode = afs_clear_inode,
.umount_begin = afs_umount_begin,
@@ -58,6 +60,20 @@ static const struct super_operations afs_super_ops = {
static struct kmem_cache *afs_inode_cachep;
static atomic_t afs_count_active_inodes;
+enum {
+ afs_no_opt,
+ afs_opt_cell,
+ afs_opt_rwpath,
+ afs_opt_vol,
+};
+
+static match_table_t afs_options_list = {
+ { afs_opt_cell, "cell=%s" },
+ { afs_opt_rwpath, "rwpath" },
+ { afs_opt_vol, "vol=%s" },
+ { afs_no_opt, NULL },
+};
+
/*
* initialise the filesystem
*/
@@ -115,31 +131,6 @@ void __exit afs_fs_exit(void)
}
/*
- * check that an argument has a value
- */
-static int want_arg(char **_value, const char *option)
-{
- if (!_value || !*_value || !**_value) {
- printk(KERN_NOTICE "kAFS: %s: argument missing\n", option);
- return 0;
- }
- return 1;
-}
-
-/*
- * check that there's no subsequent value
- */
-static int want_no_value(char *const *_value, const char *option)
-{
- if (*_value && **_value) {
- printk(KERN_NOTICE "kAFS: %s: Invalid argument: %s\n",
- option, *_value);
- return 0;
- }
- return 1;
-}
-
-/*
* parse the mount options
* - this function has been shamelessly adapted from the ext3 fs which
* shamelessly adapted it from the msdos fs
@@ -148,48 +139,46 @@ static int afs_parse_options(struct afs_mount_params *params,
char *options, const char **devname)
{
struct afs_cell *cell;
- char *key, *value;
- int ret;
+ substring_t args[MAX_OPT_ARGS];
+ char *p;
+ int token;
_enter("%s", options);
options[PAGE_SIZE - 1] = 0;
- ret = 0;
- while ((key = strsep(&options, ","))) {
- value = strchr(key, '=');
- if (value)
- *value++ = 0;
-
- _debug("kAFS: KEY: %s, VAL:%s", key, value ?: "-");
+ while ((p = strsep(&options, ","))) {
+ if (!*p)
+ continue;
- if (strcmp(key, "rwpath") == 0) {
- if (!want_no_value(&value, "rwpath"))
- return -EINVAL;
- params->rwpath = 1;
- } else if (strcmp(key, "vol") == 0) {
- if (!want_arg(&value, "vol"))
- return -EINVAL;
- *devname = value;
- } else if (strcmp(key, "cell") == 0) {
- if (!want_arg(&value, "cell"))
- return -EINVAL;
- cell = afs_cell_lookup(value, strlen(value));
+ token = match_token(p, afs_options_list, args);
+ switch (token) {
+ case afs_opt_cell:
+ cell = afs_cell_lookup(args[0].from,
+ args[0].to - args[0].from);
if (IS_ERR(cell))
return PTR_ERR(cell);
afs_put_cell(params->cell);
params->cell = cell;
- } else {
- printk("kAFS: Unknown mount option: '%s'\n", key);
- ret = -EINVAL;
- goto error;
+ break;
+
+ case afs_opt_rwpath:
+ params->rwpath = 1;
+ break;
+
+ case afs_opt_vol:
+ *devname = args[0].from;
+ break;
+
+ default:
+ printk(KERN_ERR "kAFS:"
+ " Unknown or invalid mount option: '%s'\n", p);
+ return -EINVAL;
}
}
- ret = 0;
-error:
- _leave(" = %d", ret);
- return ret;
+ _leave(" = 0");
+ return 0;
}
/*
@@ -361,7 +350,6 @@ error:
/*
* get an AFS superblock
- * - TODO: don't use get_sb_nodev(), but rather call sget() directly
*/
static int afs_get_sb(struct file_system_type *fs_type,
int flags,
@@ -386,7 +374,6 @@ static int afs_get_sb(struct file_system_type *fs_type,
goto error;
}
-
ret = afs_parse_device_name(&params, dev_name);
if (ret < 0)
goto error;
@@ -467,14 +454,15 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
{
struct afs_vnode *vnode = _vnode;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
memset(vnode, 0, sizeof(*vnode));
inode_init_once(&vnode->vfs_inode);
init_waitqueue_head(&vnode->update_waitq);
mutex_init(&vnode->permits_lock);
mutex_init(&vnode->validate_lock);
+ spin_lock_init(&vnode->writeback_lock);
spin_lock_init(&vnode->lock);
+ INIT_LIST_HEAD(&vnode->writebacks);
INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
}
}
diff --git a/fs/afs/use-rtnetlink.c b/fs/afs/use-rtnetlink.c
deleted file mode 100644
index 82f0daa2897..00000000000
--- a/fs/afs/use-rtnetlink.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* RTNETLINK client
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@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.
- */
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <linux/if_addr.h>
-#include <linux/if_arp.h>
-#include <linux/inetdevice.h>
-#include <net/netlink.h>
-#include "internal.h"
-
-struct afs_rtm_desc {
- struct socket *nlsock;
- struct afs_interface *bufs;
- u8 *mac;
- size_t nbufs;
- size_t maxbufs;
- void *data;
- ssize_t datalen;
- size_t datamax;
- int msg_seq;
- unsigned mac_index;
- bool wantloopback;
- int (*parse)(struct afs_rtm_desc *, struct nlmsghdr *);
-};
-
-/*
- * parse an RTM_GETADDR response
- */
-static int afs_rtm_getaddr_parse(struct afs_rtm_desc *desc,
- struct nlmsghdr *nlhdr)
-{
- struct afs_interface *this;
- struct ifaddrmsg *ifa;
- struct rtattr *rtattr;
- const char *name;
- size_t len;
-
- ifa = (struct ifaddrmsg *) NLMSG_DATA(nlhdr);
-
- _enter("{ix=%d,af=%d}", ifa->ifa_index, ifa->ifa_family);
-
- if (ifa->ifa_family != AF_INET) {
- _leave(" = 0 [family %d]", ifa->ifa_family);
- return 0;
- }
- if (desc->nbufs >= desc->maxbufs) {
- _leave(" = 0 [max %zu/%zu]", desc->nbufs, desc->maxbufs);
- return 0;
- }
-
- this = &desc->bufs[desc->nbufs];
-
- this->index = ifa->ifa_index;
- this->netmask.s_addr = inet_make_mask(ifa->ifa_prefixlen);
- this->mtu = 0;
-
- rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifaddrmsg));
- len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifaddrmsg));
-
- name = "unknown";
- for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
- switch (rtattr->rta_type) {
- case IFA_ADDRESS:
- memcpy(&this->address, RTA_DATA(rtattr), 4);
- break;
- case IFA_LABEL:
- name = RTA_DATA(rtattr);
- break;
- }
- }
-
- _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT,
- name, NIPQUAD(this->address), NIPQUAD(this->netmask));
-
- desc->nbufs++;
- _leave(" = 0");
- return 0;
-}
-
-/*
- * parse an RTM_GETLINK response for MTUs
- */
-static int afs_rtm_getlink_if_parse(struct afs_rtm_desc *desc,
- struct nlmsghdr *nlhdr)
-{
- struct afs_interface *this;
- struct ifinfomsg *ifi;
- struct rtattr *rtattr;
- const char *name;
- size_t len, loop;
-
- ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
-
- _enter("{ix=%d}", ifi->ifi_index);
-
- for (loop = 0; loop < desc->nbufs; loop++) {
- this = &desc->bufs[loop];
- if (this->index == ifi->ifi_index)
- goto found;
- }
-
- _leave(" = 0 [no match]");
- return 0;
-
-found:
- if (ifi->ifi_type == ARPHRD_LOOPBACK && !desc->wantloopback) {
- _leave(" = 0 [loopback]");
- return 0;
- }
-
- rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg));
- len = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg));
-
- name = "unknown";
- for (; RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {
- switch (rtattr->rta_type) {
- case IFLA_MTU:
- memcpy(&this->mtu, RTA_DATA(rtattr), 4);
- break;
- case IFLA_IFNAME:
- name = RTA_DATA(rtattr);
- break;
- }
- }
-
- _debug("%s: "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u",
- name, NIPQUAD(this->address), NIPQUAD(this->netmask),
- this->mtu);
-
- _leave(" = 0");
- return 0;
-}
-
-/*
- * parse an RTM_GETLINK response for the MAC address belonging to the lowest
- * non-internal interface
- */
-static int afs_rtm_getlink_mac_parse(struct afs_rtm_desc *desc,
- struct nlmsghdr *nlhdr)
-{
- struct ifinfomsg *ifi;
- struct rtattr *rtattr;
- const char *name;
- size_t remain, len;
- bool set;
-
- ifi = (struct ifinfomsg *) NLMSG_DATA(nlhdr);
-
- _enter("{ix=%d}", ifi->ifi_index);
-
- if (ifi->ifi_index >= desc->mac_index) {
- _leave(" = 0 [high]");
- return 0;
- }
- if (ifi->ifi_type == ARPHRD_LOOPBACK) {
- _leave(" = 0 [loopback]");
- return 0;
- }
-
- rtattr = NLMSG_DATA(nlhdr) + NLMSG_ALIGN(sizeof(struct ifinfomsg));
- remain = NLMSG_PAYLOAD(nlhdr, sizeof(struct ifinfomsg));
-
- name = "unknown";
- set = false;
- for (; RTA_OK(rtattr, remain); rtattr = RTA_NEXT(rtattr, remain)) {
- switch (rtattr->rta_type) {
- case IFLA_ADDRESS:
- len = RTA_PAYLOAD(rtattr);
- memcpy(desc->mac, RTA_DATA(rtattr),
- min_t(size_t, len, 6));
- desc->mac_index = ifi->ifi_index;
- set = true;
- break;
- case IFLA_IFNAME:
- name = RTA_DATA(rtattr);
- break;
- }
- }
-
- if (set)
- _debug("%s: %02x:%02x:%02x:%02x:%02x:%02x",
- name,
- desc->mac[0], desc->mac[1], desc->mac[2],
- desc->mac[3], desc->mac[4], desc->mac[5]);
-
- _leave(" = 0");
- return 0;
-}
-
-/*
- * read the rtnetlink response and pass to parsing routine
- */
-static int afs_read_rtm(struct afs_rtm_desc *desc)
-{
- struct nlmsghdr *nlhdr, tmphdr;
- struct msghdr msg;
- struct kvec iov[1];
- void *data;
- bool last = false;
- int len, ret, remain;
-
- _enter("");
-
- do {
- /* first of all peek to see how big the packet is */
- memset(&msg, 0, sizeof(msg));
- iov[0].iov_base = &tmphdr;
- iov[0].iov_len = sizeof(tmphdr);
- len = kernel_recvmsg(desc->nlsock, &msg, iov, 1,
- sizeof(tmphdr), MSG_PEEK | MSG_TRUNC);
- if (len < 0) {
- _leave(" = %d [peek]", len);
- return len;
- }
- if (len == 0)
- continue;
- if (len < sizeof(tmphdr) || len < NLMSG_PAYLOAD(&tmphdr, 0)) {
- _leave(" = -EMSGSIZE");
- return -EMSGSIZE;
- }
-
- if (desc->datamax < len) {
- kfree(desc->data);
- desc->data = NULL;
- data = kmalloc(len, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
- desc->data = data;
- }
- desc->datamax = len;
-
- /* read all the data from this packet */
- iov[0].iov_base = desc->data;
- iov[0].iov_len = desc->datamax;
- desc->datalen = kernel_recvmsg(desc->nlsock, &msg, iov, 1,
- desc->datamax, 0);
- if (desc->datalen < 0) {
- _leave(" = %ld [recv]", desc->datalen);
- return desc->datalen;
- }
-
- nlhdr = desc->data;
-
- /* check if the header is valid */
- if (!NLMSG_OK(nlhdr, desc->datalen) ||
- nlhdr->nlmsg_type == NLMSG_ERROR) {
- _leave(" = -EIO");
- return -EIO;
- }
-
- /* see if this is the last message */
- if (nlhdr->nlmsg_type == NLMSG_DONE ||
- !(nlhdr->nlmsg_flags & NLM_F_MULTI))
- last = true;
-
- /* parse the bits we got this time */
- nlmsg_for_each_msg(nlhdr, desc->data, desc->datalen, remain) {
- ret = desc->parse(desc, nlhdr);
- if (ret < 0) {
- _leave(" = %d [parse]", ret);
- return ret;
- }
- }
-
- } while (!last);
-
- _leave(" = 0");
- return 0;
-}
-
-/*
- * list the interface bound addresses to get the address and netmask
- */
-static int afs_rtm_getaddr(struct afs_rtm_desc *desc)
-{
- struct msghdr msg;
- struct kvec iov[1];
- int ret;
-
- struct {
- struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO)));
- struct ifaddrmsg addr_msg __attribute__((aligned(NLMSG_ALIGNTO)));
- } request;
-
- _enter("");
-
- memset(&request, 0, sizeof(request));
-
- request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- request.nl_msg.nlmsg_type = RTM_GETADDR;
- request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
- request.nl_msg.nlmsg_seq = desc->msg_seq++;
- request.nl_msg.nlmsg_pid = 0;
-
- memset(&msg, 0, sizeof(msg));
- iov[0].iov_base = &request;
- iov[0].iov_len = sizeof(request);
-
- ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len);
- _leave(" = %d", ret);
- return ret;
-}
-
-/*
- * list the interface link statuses to get the MTUs
- */
-static int afs_rtm_getlink(struct afs_rtm_desc *desc)
-{
- struct msghdr msg;
- struct kvec iov[1];
- int ret;
-
- struct {
- struct nlmsghdr nl_msg __attribute__((aligned(NLMSG_ALIGNTO)));
- struct ifinfomsg link_msg __attribute__((aligned(NLMSG_ALIGNTO)));
- } request;
-
- _enter("");
-
- memset(&request, 0, sizeof(request));
-
- request.nl_msg.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- request.nl_msg.nlmsg_type = RTM_GETLINK;
- request.nl_msg.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
- request.nl_msg.nlmsg_seq = desc->msg_seq++;
- request.nl_msg.nlmsg_pid = 0;
-
- memset(&msg, 0, sizeof(msg));
- iov[0].iov_base = &request;
- iov[0].iov_len = sizeof(request);
-
- ret = kernel_sendmsg(desc->nlsock, &msg, iov, 1, iov[0].iov_len);
- _leave(" = %d", ret);
- return ret;
-}
-
-/*
- * cull any interface records for which there isn't an MTU value
- */
-static void afs_cull_interfaces(struct afs_rtm_desc *desc)
-{
- struct afs_interface *bufs = desc->bufs;
- size_t nbufs = desc->nbufs;
- int loop, point = 0;
-
- _enter("{%zu}", nbufs);
-
- for (loop = 0; loop < nbufs; loop++) {
- if (desc->bufs[loop].mtu != 0) {
- if (loop != point) {
- ASSERTCMP(loop, >, point);
- bufs[point] = bufs[loop];
- }
- point++;
- }
- }
-
- desc->nbufs = point;
- _leave(" [%zu/%zu]", desc->nbufs, nbufs);
-}
-
-/*
- * get a list of this system's interface IPv4 addresses, netmasks and MTUs
- * - returns the number of interface records in the buffer
- */
-int afs_get_ipv4_interfaces(struct afs_interface *bufs, size_t maxbufs,
- bool wantloopback)
-{
- struct afs_rtm_desc desc;
- int ret, loop;
-
- _enter("");
-
- memset(&desc, 0, sizeof(desc));
- desc.bufs = bufs;
- desc.maxbufs = maxbufs;
- desc.wantloopback = wantloopback;
-
- ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
- &desc.nlsock);
- if (ret < 0) {
- _leave(" = %d [sock]", ret);
- return ret;
- }
-
- /* issue RTM_GETADDR */
- desc.parse = afs_rtm_getaddr_parse;
- ret = afs_rtm_getaddr(&desc);
- if (ret < 0)
- goto error;
- ret = afs_read_rtm(&desc);
- if (ret < 0)
- goto error;
-
- /* issue RTM_GETLINK */
- desc.parse = afs_rtm_getlink_if_parse;
- ret = afs_rtm_getlink(&desc);
- if (ret < 0)
- goto error;
- ret = afs_read_rtm(&desc);
- if (ret < 0)
- goto error;
-
- afs_cull_interfaces(&desc);
- ret = desc.nbufs;
-
- for (loop = 0; loop < ret; loop++)
- _debug("[%d] "NIPQUAD_FMT"/"NIPQUAD_FMT" mtu %u",
- bufs[loop].index,
- NIPQUAD(bufs[loop].address),
- NIPQUAD(bufs[loop].netmask),
- bufs[loop].mtu);
-
-error:
- kfree(desc.data);
- sock_release(desc.nlsock);
- _leave(" = %d", ret);
- return ret;
-}
-
-/*
- * get a MAC address from a random ethernet interface that has a real one
- * - the buffer should be 6 bytes in size
- */
-int afs_get_MAC_address(u8 mac[6])
-{
- struct afs_rtm_desc desc;
- int ret;
-
- _enter("");
-
- memset(&desc, 0, sizeof(desc));
- desc.mac = mac;
- desc.mac_index = UINT_MAX;
-
- ret = sock_create_kern(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE,
- &desc.nlsock);
- if (ret < 0) {
- _leave(" = %d [sock]", ret);
- return ret;
- }
-
- /* issue RTM_GETLINK */
- desc.parse = afs_rtm_getlink_mac_parse;
- ret = afs_rtm_getlink(&desc);
- if (ret < 0)
- goto error;
- ret = afs_read_rtm(&desc);
- if (ret < 0)
- goto error;
-
- if (desc.mac_index < UINT_MAX) {
- /* got a MAC address */
- _debug("[%d] %02x:%02x:%02x:%02x:%02x:%02x",
- desc.mac_index,
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- } else {
- ret = -ENONET;
- }
-
-error:
- sock_release(desc.nlsock);
- _leave(" = %d", ret);
- return ret;
-}
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index 74cce174882..3370cdb7256 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -416,8 +416,8 @@ fill_in_record:
goto error_abandon;
spin_lock(&vl->lock);
vl->state = AFS_VL_VALID;
- wake_up(&vl->waitq);
spin_unlock(&vl->lock);
+ wake_up(&vl->waitq);
/* schedule for regular updates */
afs_vlocation_queue_for_updates(vl);
@@ -442,7 +442,7 @@ found_in_memory:
_debug("invalid [state %d]", state);
- if ((state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME)) {
+ if (state == AFS_VL_NEW || state == AFS_VL_NO_VOLUME) {
vl->state = AFS_VL_CREATING;
spin_unlock(&vl->lock);
goto fill_in_record;
@@ -453,11 +453,10 @@ found_in_memory:
_debug("wait");
spin_unlock(&vl->lock);
- ret = wait_event_interruptible(
- vl->waitq,
- vl->state == AFS_VL_NEW ||
- vl->state == AFS_VL_VALID ||
- vl->state == AFS_VL_NO_VOLUME);
+ ret = wait_event_interruptible(vl->waitq,
+ vl->state == AFS_VL_NEW ||
+ vl->state == AFS_VL_VALID ||
+ vl->state == AFS_VL_NO_VOLUME);
if (ret < 0)
goto error;
spin_lock(&vl->lock);
@@ -471,8 +470,8 @@ success:
error_abandon:
spin_lock(&vl->lock);
vl->state = AFS_VL_NEW;
- wake_up(&vl->waitq);
spin_unlock(&vl->lock);
+ wake_up(&vl->waitq);
error:
ASSERT(vl != NULL);
afs_put_vlocation(vl);
@@ -603,7 +602,7 @@ int __init afs_vlocation_update_init(void)
/*
* discard all the volume location records for rmmod
*/
-void __exit afs_vlocation_purge(void)
+void afs_vlocation_purge(void)
{
afs_vlocation_timeout = 0;
@@ -675,7 +674,6 @@ static void afs_vlocation_updater(struct work_struct *work)
case 0:
afs_vlocation_apply_update(vl, &vldb);
vl->state = AFS_VL_VALID;
- wake_up(&vl->waitq);
break;
case -ENOMEDIUM:
vl->state = AFS_VL_VOLUME_DELETED;
@@ -685,6 +683,7 @@ static void afs_vlocation_updater(struct work_struct *work)
break;
}
spin_unlock(&vl->lock);
+ wake_up(&vl->waitq);
/* and then reschedule */
_debug("reschedule");
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index a1904ab8426..ec814660209 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -261,7 +261,7 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode,
DECLARE_WAITQUEUE(myself, current);
- _enter("%s,{%u,%u,%u}",
+ _enter("%s,{%x:%u.%u}",
vnode->volume->vlocation->vldb.name,
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
@@ -389,7 +389,7 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
struct afs_server *server;
int ret;
- _enter("%s{%u,%u,%u},%x,,,",
+ _enter("%s{%x:%u.%u},%x,,,",
vnode->volume->vlocation->vldb.name,
vnode->fid.vid,
vnode->fid.vnode,
@@ -446,7 +446,7 @@ int afs_vnode_create(struct afs_vnode *vnode, struct key *key,
struct afs_server *server;
int ret;
- _enter("%s{%u,%u,%u},%x,%s,,",
+ _enter("%s{%x:%u.%u},%x,%s,,",
vnode->volume->vlocation->vldb.name,
vnode->fid.vid,
vnode->fid.vnode,
@@ -502,7 +502,7 @@ int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name,
struct afs_server *server;
int ret;
- _enter("%s{%u,%u,%u},%x,%s",
+ _enter("%s{%x:%u.%u},%x,%s",
vnode->volume->vlocation->vldb.name,
vnode->fid.vid,
vnode->fid.vnode,
@@ -557,7 +557,7 @@ extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
struct afs_server *server;
int ret;
- _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s",
+ _enter("%s{%x:%u.%u},%s{%x:%u.%u},%x,%s",
dvnode->volume->vlocation->vldb.name,
dvnode->fid.vid,
dvnode->fid.vnode,
@@ -628,7 +628,7 @@ int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key,
struct afs_server *server;
int ret;
- _enter("%s{%u,%u,%u},%x,%s,%s,,,",
+ _enter("%s{%x:%u.%u},%x,%s,%s,,,",
vnode->volume->vlocation->vldb.name,
vnode->fid.vid,
vnode->fid.vnode,
@@ -687,7 +687,7 @@ int afs_vnode_rename(struct afs_vnode *orig_dvnode,
struct afs_server *server;
int ret;
- _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s",
+ _enter("%s{%x:%u.%u},%s{%u,%u,%u},%x,%s,%s",
orig_dvnode->volume->vlocation->vldb.name,
orig_dvnode->fid.vid,
orig_dvnode->fid.vnode,
@@ -753,3 +753,110 @@ no_server:
_leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt);
return PTR_ERR(server);
}
+
+/*
+ * write to a file
+ */
+int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last,
+ unsigned offset, unsigned to)
+{
+ struct afs_server *server;
+ struct afs_vnode *vnode = wb->vnode;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x,%lx,%lx,%x,%x",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(wb->key),
+ first, last, offset, to);
+
+ /* this op will fetch the status */
+ spin_lock(&vnode->lock);
+ vnode->update_cnt++;
+ spin_unlock(&vnode->lock);
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_store_data(server, wb, first, last, offset, to,
+ &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0) {
+ afs_vnode_finalise_status_update(vnode, server);
+ afs_put_server(server);
+ } else {
+ afs_vnode_status_update_failed(vnode, ret);
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ spin_lock(&vnode->lock);
+ vnode->update_cnt--;
+ ASSERTCMP(vnode->update_cnt, >=, 0);
+ spin_unlock(&vnode->lock);
+ return PTR_ERR(server);
+}
+
+/*
+ * set the attributes on a file
+ */
+int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key,
+ struct iattr *attr)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key));
+
+ /* this op will fetch the status */
+ spin_lock(&vnode->lock);
+ vnode->update_cnt++;
+ spin_unlock(&vnode->lock);
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0) {
+ afs_vnode_finalise_status_update(vnode, server);
+ afs_put_server(server);
+ } else {
+ afs_vnode_status_update_failed(vnode, ret);
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ spin_lock(&vnode->lock);
+ vnode->update_cnt--;
+ ASSERTCMP(vnode->update_cnt, >=, 0);
+ spin_unlock(&vnode->lock);
+ return PTR_ERR(server);
+}
diff --git a/fs/afs/write.c b/fs/afs/write.c
new file mode 100644
index 00000000000..83ff2926281
--- /dev/null
+++ b/fs/afs/write.c
@@ -0,0 +1,835 @@
+/* handling of writes to regular files and writing back to the server
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@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.
+ */
+
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/pagevec.h>
+#include "internal.h"
+
+static int afs_write_back_from_locked_page(struct afs_writeback *wb,
+ struct page *page);
+
+/*
+ * mark a page as having been made dirty and thus needing writeback
+ */
+int afs_set_page_dirty(struct page *page)
+{
+ _enter("");
+ return __set_page_dirty_nobuffers(page);
+}
+
+/*
+ * unlink a writeback record because its usage has reached zero
+ * - must be called with the wb->vnode->writeback_lock held
+ */
+static void afs_unlink_writeback(struct afs_writeback *wb)
+{
+ struct afs_writeback *front;
+ struct afs_vnode *vnode = wb->vnode;
+
+ list_del_init(&wb->link);
+ if (!list_empty(&vnode->writebacks)) {
+ /* if an fsync rises to the front of the queue then wake it
+ * up */
+ front = list_entry(vnode->writebacks.next,
+ struct afs_writeback, link);
+ if (front->state == AFS_WBACK_SYNCING) {
+ _debug("wake up sync");
+ front->state = AFS_WBACK_COMPLETE;
+ wake_up(&front->waitq);
+ }
+ }
+}
+
+/*
+ * free a writeback record
+ */
+static void afs_free_writeback(struct afs_writeback *wb)
+{
+ _enter("");
+ key_put(wb->key);
+ kfree(wb);
+}
+
+/*
+ * dispose of a reference to a writeback record
+ */
+void afs_put_writeback(struct afs_writeback *wb)
+{
+ struct afs_vnode *vnode = wb->vnode;
+
+ _enter("{%d}", wb->usage);
+
+ spin_lock(&vnode->writeback_lock);
+ if (--wb->usage == 0)
+ afs_unlink_writeback(wb);
+ else
+ wb = NULL;
+ spin_unlock(&vnode->writeback_lock);
+ if (wb)
+ afs_free_writeback(wb);
+}
+
+/*
+ * partly or wholly fill a page that's under preparation for writing
+ */
+static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
+ unsigned start, unsigned len, struct page *page)
+{
+ int ret;
+
+ _enter(",,%u,%u", start, len);
+
+ ASSERTCMP(start + len, <=, PAGE_SIZE);
+
+ ret = afs_vnode_fetch_data(vnode, key, start, len, page);
+ if (ret < 0) {
+ if (ret == -ENOENT) {
+ _debug("got NOENT from server"
+ " - marking file deleted and stale");
+ set_bit(AFS_VNODE_DELETED, &vnode->flags);
+ ret = -ESTALE;
+ }
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * prepare a page for being written to
+ */
+static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
+ struct key *key, unsigned offset, unsigned to)
+{
+ unsigned eof, tail, start, stop, len;
+ loff_t i_size, pos;
+ void *p;
+ int ret;
+
+ _enter("");
+
+ if (offset == 0 && to == PAGE_SIZE)
+ return 0;
+
+ p = kmap(page);
+
+ i_size = i_size_read(&vnode->vfs_inode);
+ pos = (loff_t) page->index << PAGE_SHIFT;
+ if (pos >= i_size) {
+ /* partial write, page beyond EOF */
+ _debug("beyond");
+ if (offset > 0)
+ memset(p, 0, offset);
+ if (to < PAGE_SIZE)
+ memset(p + to, 0, PAGE_SIZE - to);
+ kunmap(page);
+ return 0;
+ }
+
+ if (i_size - pos >= PAGE_SIZE) {
+ /* partial write, page entirely before EOF */
+ _debug("before");
+ tail = eof = PAGE_SIZE;
+ } else {
+ /* partial write, page overlaps EOF */
+ eof = i_size - pos;
+ _debug("overlap %u", eof);
+ tail = max(eof, to);
+ if (tail < PAGE_SIZE)
+ memset(p + tail, 0, PAGE_SIZE - tail);
+ if (offset > eof)
+ memset(p + eof, 0, PAGE_SIZE - eof);
+ }
+
+ kunmap(p);
+
+ ret = 0;
+ if (offset > 0 || eof > to) {
+ /* need to fill one or two bits that aren't going to be written
+ * (cover both fillers in one read if there are two) */
+ start = (offset > 0) ? 0 : to;
+ stop = (eof > to) ? eof : offset;
+ len = stop - start;
+ _debug("wr=%u-%u av=0-%u rd=%u@%u",
+ offset, to, eof, start, len);
+ ret = afs_fill_page(vnode, key, start, len, page);
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * prepare to perform part of a write to a page
+ * - the caller holds the page locked, preventing it from being written out or
+ * modified by anyone else
+ */
+int afs_prepare_write(struct file *file, struct page *page,
+ unsigned offset, unsigned to)
+{
+ struct afs_writeback *candidate, *wb;
+ struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+ struct key *key = file->private_data;
+ pgoff_t index;
+ int ret;
+
+ _enter("{%x:%u},{%lx},%u,%u",
+ vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+
+ candidate = kzalloc(sizeof(*candidate), GFP_KERNEL);
+ if (!candidate)
+ return -ENOMEM;
+ candidate->vnode = vnode;
+ candidate->first = candidate->last = page->index;
+ candidate->offset_first = offset;
+ candidate->to_last = to;
+ candidate->usage = 1;
+ candidate->state = AFS_WBACK_PENDING;
+ init_waitqueue_head(&candidate->waitq);
+
+ if (!PageUptodate(page)) {
+ _debug("not up to date");
+ ret = afs_prepare_page(vnode, page, key, offset, to);
+ if (ret < 0) {
+ kfree(candidate);
+ _leave(" = %d [prep]", ret);
+ return ret;
+ }
+ SetPageUptodate(page);
+ }
+
+try_again:
+ index = page->index;
+ spin_lock(&vnode->writeback_lock);
+
+ /* see if this page is already pending a writeback under a suitable key
+ * - if so we can just join onto that one */
+ wb = (struct afs_writeback *) page_private(page);
+ if (wb) {
+ if (wb->key == key && wb->state == AFS_WBACK_PENDING)
+ goto subsume_in_current_wb;
+ goto flush_conflicting_wb;
+ }
+
+ if (index > 0) {
+ /* see if we can find an already pending writeback that we can
+ * append this page to */
+ list_for_each_entry(wb, &vnode->writebacks, link) {
+ if (wb->last == index - 1 && wb->key == key &&
+ wb->state == AFS_WBACK_PENDING)
+ goto append_to_previous_wb;
+ }
+ }
+
+ list_add_tail(&candidate->link, &vnode->writebacks);
+ candidate->key = key_get(key);
+ spin_unlock(&vnode->writeback_lock);
+ SetPagePrivate(page);
+ set_page_private(page, (unsigned long) candidate);
+ _leave(" = 0 [new]");
+ return 0;
+
+subsume_in_current_wb:
+ _debug("subsume");
+ ASSERTRANGE(wb->first, <=, index, <=, wb->last);
+ if (index == wb->first && offset < wb->offset_first)
+ wb->offset_first = offset;
+ if (index == wb->last && to > wb->to_last)
+ wb->to_last = to;
+ spin_unlock(&vnode->writeback_lock);
+ kfree(candidate);
+ _leave(" = 0 [sub]");
+ return 0;
+
+append_to_previous_wb:
+ _debug("append into %lx-%lx", wb->first, wb->last);
+ wb->usage++;
+ wb->last++;
+ wb->to_last = to;
+ spin_unlock(&vnode->writeback_lock);
+ SetPagePrivate(page);
+ set_page_private(page, (unsigned long) wb);
+ kfree(candidate);
+ _leave(" = 0 [app]");
+ return 0;
+
+ /* the page is currently bound to another context, so if it's dirty we
+ * need to flush it before we can use the new context */
+flush_conflicting_wb:
+ _debug("flush conflict");
+ if (wb->state == AFS_WBACK_PENDING)
+ wb->state = AFS_WBACK_CONFLICTING;
+ spin_unlock(&vnode->writeback_lock);
+ if (PageDirty(page)) {
+ ret = afs_write_back_from_locked_page(wb, page);
+ if (ret < 0) {
+ afs_put_writeback(candidate);
+ _leave(" = %d", ret);
+ return ret;
+ }
+ }
+
+ /* the page holds a ref on the writeback record */
+ afs_put_writeback(wb);
+ set_page_private(page, 0);
+ ClearPagePrivate(page);
+ goto try_again;
+}
+
+/*
+ * finalise part of a write to a page
+ */
+int afs_commit_write(struct file *file, struct page *page,
+ unsigned offset, unsigned to)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+ loff_t i_size, maybe_i_size;
+
+ _enter("{%x:%u},{%lx},%u,%u",
+ vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+
+ maybe_i_size = (loff_t) page->index << PAGE_SHIFT;
+ maybe_i_size += to;
+
+ i_size = i_size_read(&vnode->vfs_inode);
+ if (maybe_i_size > i_size) {
+ spin_lock(&vnode->writeback_lock);
+ i_size = i_size_read(&vnode->vfs_inode);
+ if (maybe_i_size > i_size)
+ i_size_write(&vnode->vfs_inode, maybe_i_size);
+ spin_unlock(&vnode->writeback_lock);
+ }
+
+ set_page_dirty(page);
+
+ if (PageDirty(page))
+ _debug("dirtied");
+
+ return 0;
+}
+
+/*
+ * kill all the pages in the given range
+ */
+static void afs_kill_pages(struct afs_vnode *vnode, bool error,
+ pgoff_t first, pgoff_t last)
+{
+ struct pagevec pv;
+ unsigned count, loop;
+
+ _enter("{%x:%u},%lx-%lx",
+ vnode->fid.vid, vnode->fid.vnode, first, last);
+
+ pagevec_init(&pv, 0);
+
+ do {
+ _debug("kill %lx-%lx", first, last);
+
+ count = last - first + 1;
+ if (count > PAGEVEC_SIZE)
+ count = PAGEVEC_SIZE;
+ pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping,
+ first, count, pv.pages);
+ ASSERTCMP(pv.nr, ==, count);
+
+ for (loop = 0; loop < count; loop++) {
+ ClearPageUptodate(pv.pages[loop]);
+ if (error)
+ SetPageError(pv.pages[loop]);
+ end_page_writeback(pv.pages[loop]);
+ }
+
+ __pagevec_release(&pv);
+ } while (first < last);
+
+ _leave("");
+}
+
+/*
+ * synchronously write back the locked page and any subsequent non-locked dirty
+ * pages also covered by the same writeback record
+ */
+static int afs_write_back_from_locked_page(struct afs_writeback *wb,
+ struct page *primary_page)
+{
+ struct page *pages[8], *page;
+ unsigned long count;
+ unsigned n, offset, to;
+ pgoff_t start, first, last;
+ int loop, ret;
+
+ _enter(",%lx", primary_page->index);
+
+ count = 1;
+ if (!clear_page_dirty_for_io(primary_page))
+ BUG();
+ if (test_set_page_writeback(primary_page))
+ BUG();
+
+ /* find all consecutive lockable dirty pages, stopping when we find a
+ * page that is not immediately lockable, is not dirty or is missing,
+ * or we reach the end of the range */
+ start = primary_page->index;
+ if (start >= wb->last)
+ goto no_more;
+ start++;
+ do {
+ _debug("more %lx [%lx]", start, count);
+ n = wb->last - start + 1;
+ if (n > ARRAY_SIZE(pages))
+ n = ARRAY_SIZE(pages);
+ n = find_get_pages_contig(wb->vnode->vfs_inode.i_mapping,
+ start, n, pages);
+ _debug("fgpc %u", n);
+ if (n == 0)
+ goto no_more;
+ if (pages[0]->index != start) {
+ for (n--; n >= 0; n--)
+ put_page(pages[n]);
+ goto no_more;
+ }
+
+ for (loop = 0; loop < n; loop++) {
+ page = pages[loop];
+ if (page->index > wb->last)
+ break;
+ if (TestSetPageLocked(page))
+ break;
+ if (!PageDirty(page) ||
+ page_private(page) != (unsigned long) wb) {
+ unlock_page(page);
+ break;
+ }
+ if (!clear_page_dirty_for_io(page))
+ BUG();
+ if (test_set_page_writeback(page))
+ BUG();
+ unlock_page(page);
+ put_page(page);
+ }
+ count += loop;
+ if (loop < n) {
+ for (; loop < n; loop++)
+ put_page(pages[loop]);
+ goto no_more;
+ }
+
+ start += loop;
+ } while (start <= wb->last && count < 65536);
+
+no_more:
+ /* we now have a contiguous set of dirty pages, each with writeback set
+ * and the dirty mark cleared; the first page is locked and must remain
+ * so, all the rest are unlocked */
+ first = primary_page->index;
+ last = first + count - 1;
+
+ offset = (first == wb->first) ? wb->offset_first : 0;
+ to = (last == wb->last) ? wb->to_last : PAGE_SIZE;
+
+ _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to);
+
+ ret = afs_vnode_store_data(wb, first, last, offset, to);
+ if (ret < 0) {
+ switch (ret) {
+ case -EDQUOT:
+ case -ENOSPC:
+ set_bit(AS_ENOSPC,
+ &wb->vnode->vfs_inode.i_mapping->flags);
+ break;
+ case -EROFS:
+ case -EIO:
+ case -EREMOTEIO:
+ case -EFBIG:
+ case -ENOENT:
+ case -ENOMEDIUM:
+ case -ENXIO:
+ afs_kill_pages(wb->vnode, true, first, last);
+ set_bit(AS_EIO, &wb->vnode->vfs_inode.i_mapping->flags);
+ break;
+ case -EACCES:
+ case -EPERM:
+ case -ENOKEY:
+ case -EKEYEXPIRED:
+ case -EKEYREJECTED:
+ case -EKEYREVOKED:
+ afs_kill_pages(wb->vnode, false, first, last);
+ break;
+ default:
+ break;
+ }
+ } else {
+ ret = count;
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * write a page back to the server
+ * - the caller locked the page for us
+ */
+int afs_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct backing_dev_info *bdi = page->mapping->backing_dev_info;
+ struct afs_writeback *wb;
+ int ret;
+
+ _enter("{%lx},", page->index);
+
+ if (wbc->sync_mode != WB_SYNC_NONE)
+ wait_on_page_writeback(page);
+
+ if (PageWriteback(page) || !PageDirty(page)) {
+ unlock_page(page);
+ return 0;
+ }
+
+ wb = (struct afs_writeback *) page_private(page);
+ ASSERT(wb != NULL);
+
+ ret = afs_write_back_from_locked_page(wb, page);
+ unlock_page(page);
+ if (ret < 0) {
+ _leave(" = %d", ret);
+ return 0;
+ }
+
+ wbc->nr_to_write -= ret;
+ if (wbc->nonblocking && bdi_write_congested(bdi))
+ wbc->encountered_congestion = 1;
+
+ _leave(" = 0");
+ return 0;
+}
+
+/*
+ * write a region of pages back to the server
+ */
+int afs_writepages_region(struct address_space *mapping,
+ struct writeback_control *wbc,
+ pgoff_t index, pgoff_t end, pgoff_t *_next)
+{
+ struct backing_dev_info *bdi = mapping->backing_dev_info;
+ struct afs_writeback *wb;
+ struct page *page;
+ int ret, n;
+
+ _enter(",,%lx,%lx,", index, end);
+
+ do {
+ n = find_get_pages_tag(mapping, &index, PAGECACHE_TAG_DIRTY,
+ 1, &page);
+ if (!n)
+ break;
+
+ _debug("wback %lx", page->index);
+
+ if (page->index > end) {
+ *_next = index;
+ page_cache_release(page);
+ _leave(" = 0 [%lx]", *_next);
+ return 0;
+ }
+
+ /* at this point we hold neither mapping->tree_lock nor lock on
+ * the page itself: the page may be truncated or invalidated
+ * (changing page->mapping to NULL), or even swizzled back from
+ * swapper_space to tmpfs file mapping
+ */
+ lock_page(page);
+
+ if (page->mapping != mapping) {
+ unlock_page(page);
+ page_cache_release(page);
+ continue;
+ }
+
+ if (wbc->sync_mode != WB_SYNC_NONE)
+ wait_on_page_writeback(page);
+
+ if (PageWriteback(page) || !PageDirty(page)) {
+ unlock_page(page);
+ continue;
+ }
+
+ wb = (struct afs_writeback *) page_private(page);
+ ASSERT(wb != NULL);
+
+ spin_lock(&wb->vnode->writeback_lock);
+ wb->state = AFS_WBACK_WRITING;
+ spin_unlock(&wb->vnode->writeback_lock);
+
+ ret = afs_write_back_from_locked_page(wb, page);
+ unlock_page(page);
+ page_cache_release(page);
+ if (ret < 0) {
+ _leave(" = %d", ret);
+ return ret;
+ }
+
+ wbc->nr_to_write -= ret;
+
+ if (wbc->nonblocking && bdi_write_congested(bdi)) {
+ wbc->encountered_congestion = 1;
+ break;
+ }
+
+ cond_resched();
+ } while (index < end && wbc->nr_to_write > 0);
+
+ *_next = index;
+ _leave(" = 0 [%lx]", *_next);
+ return 0;
+}
+
+/*
+ * write some of the pending data back to the server
+ */
+int afs_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ struct backing_dev_info *bdi = mapping->backing_dev_info;
+ pgoff_t start, end, next;
+ int ret;
+
+ _enter("");
+
+ if (wbc->nonblocking && bdi_write_congested(bdi)) {
+ wbc->encountered_congestion = 1;
+ _leave(" = 0 [congest]");
+ return 0;
+ }
+
+ if (wbc->range_cyclic) {
+ start = mapping->writeback_index;
+ end = -1;
+ ret = afs_writepages_region(mapping, wbc, start, end, &next);
+ if (start > 0 && wbc->nr_to_write > 0 && ret == 0 &&
+ !(wbc->nonblocking && wbc->encountered_congestion))
+ ret = afs_writepages_region(mapping, wbc, 0, start,
+ &next);
+ mapping->writeback_index = next;
+ } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) {
+ end = (pgoff_t)(LLONG_MAX >> PAGE_CACHE_SHIFT);
+ ret = afs_writepages_region(mapping, wbc, 0, end, &next);
+ if (wbc->nr_to_write > 0)
+ mapping->writeback_index = next;
+ } else {
+ start = wbc->range_start >> PAGE_CACHE_SHIFT;
+ end = wbc->range_end >> PAGE_CACHE_SHIFT;
+ ret = afs_writepages_region(mapping, wbc, start, end, &next);
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * write an inode back
+ */
+int afs_write_inode(struct inode *inode, int sync)
+{
+ struct afs_vnode *vnode = AFS_FS_I(inode);
+ int ret;
+
+ _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
+
+ ret = 0;
+ if (sync) {
+ ret = filemap_fdatawait(inode->i_mapping);
+ if (ret < 0)
+ __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * completion of write to server
+ */
+void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)
+{
+ struct afs_writeback *wb = call->wb;
+ struct pagevec pv;
+ unsigned count, loop;
+ pgoff_t first = call->first, last = call->last;
+ bool free_wb;
+
+ _enter("{%x:%u},{%lx-%lx}",
+ vnode->fid.vid, vnode->fid.vnode, first, last);
+
+ ASSERT(wb != NULL);
+
+ pagevec_init(&pv, 0);
+
+ do {
+ _debug("attach %lx-%lx", first, last);
+
+ count = last - first + 1;
+ if (count > PAGEVEC_SIZE)
+ count = PAGEVEC_SIZE;
+ pv.nr = find_get_pages_contig(call->mapping, first, count,
+ pv.pages);
+ ASSERTCMP(pv.nr, ==, count);
+
+ spin_lock(&vnode->writeback_lock);
+ for (loop = 0; loop < count; loop++) {
+ struct page *page = pv.pages[loop];
+ end_page_writeback(page);
+ if (page_private(page) == (unsigned long) wb) {
+ set_page_private(page, 0);
+ ClearPagePrivate(page);
+ wb->usage--;
+ }
+ }
+ free_wb = false;
+ if (wb->usage == 0) {
+ afs_unlink_writeback(wb);
+ free_wb = true;
+ }
+ spin_unlock(&vnode->writeback_lock);
+ first += count;
+ if (free_wb) {
+ afs_free_writeback(wb);
+ wb = NULL;
+ }
+
+ __pagevec_release(&pv);
+ } while (first < last);
+
+ _leave("");
+}
+
+/*
+ * write to an AFS file
+ */
+ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct dentry *dentry = iocb->ki_filp->f_path.dentry;
+ struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+ ssize_t result;
+ size_t count = iov_length(iov, nr_segs);
+ int ret;
+
+ _enter("{%x.%u},{%zu},%lu,",
+ vnode->fid.vid, vnode->fid.vnode, count, nr_segs);
+
+ if (IS_SWAPFILE(&vnode->vfs_inode)) {
+ printk(KERN_INFO
+ "AFS: Attempt to write to active swap file!\n");
+ return -EBUSY;
+ }
+
+ if (!count)
+ return 0;
+
+ result = generic_file_aio_write(iocb, iov, nr_segs, pos);
+ if (IS_ERR_VALUE(result)) {
+ _leave(" = %zd", result);
+ return result;
+ }
+
+ /* return error values for O_SYNC and IS_SYNC() */
+ if (IS_SYNC(&vnode->vfs_inode) || iocb->ki_filp->f_flags & O_SYNC) {
+ ret = afs_fsync(iocb->ki_filp, dentry, 1);
+ if (ret < 0)
+ result = ret;
+ }
+
+ _leave(" = %zd", result);
+ return result;
+}
+
+/*
+ * flush the vnode to the fileserver
+ */
+int afs_writeback_all(struct afs_vnode *vnode)
+{
+ struct address_space *mapping = vnode->vfs_inode.i_mapping;
+ struct writeback_control wbc = {
+ .bdi = mapping->backing_dev_info,
+ .sync_mode = WB_SYNC_ALL,
+ .nr_to_write = LONG_MAX,
+ .for_writepages = 1,
+ .range_cyclic = 1,
+ };
+ int ret;
+
+ _enter("");
+
+ ret = mapping->a_ops->writepages(mapping, &wbc);
+ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+ _leave(" = %d", ret);
+ return ret;
+}
+
+/*
+ * flush any dirty pages for this process, and check for write errors.
+ * - the return status from this call provides a reliable indication of
+ * whether any write errors occurred for this process.
+ */
+int afs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct afs_writeback *wb, *xwb;
+ struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+ int ret;
+
+ _enter("{%x:%u},{n=%s},%d",
+ vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+ datasync);
+
+ /* use a writeback record as a marker in the queue - when this reaches
+ * the front of the queue, all the outstanding writes are either
+ * completed or rejected */
+ wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+ if (!wb)
+ return -ENOMEM;
+ wb->vnode = vnode;
+ wb->first = 0;
+ wb->last = -1;
+ wb->offset_first = 0;
+ wb->to_last = PAGE_SIZE;
+ wb->usage = 1;
+ wb->state = AFS_WBACK_SYNCING;
+ init_waitqueue_head(&wb->waitq);
+
+ spin_lock(&vnode->writeback_lock);
+ list_for_each_entry(xwb, &vnode->writebacks, link) {
+ if (xwb->state == AFS_WBACK_PENDING)
+ xwb->state = AFS_WBACK_CONFLICTING;
+ }
+ list_add_tail(&wb->link, &vnode->writebacks);
+ spin_unlock(&vnode->writeback_lock);
+
+ /* push all the outstanding writebacks to the server */
+ ret = afs_writeback_all(vnode);
+ if (ret < 0) {
+ afs_put_writeback(wb);
+ _leave(" = %d [wb]", ret);
+ return ret;
+ }
+
+ /* wait for the preceding writes to actually complete */
+ ret = wait_event_interruptible(wb->waitq,
+ wb->state == AFS_WBACK_COMPLETE ||
+ vnode->writebacks.next == &wb->link);
+ afs_put_writeback(wb);
+ _leave(" = %d", ret);
+ return ret;
+}
diff --git a/fs/aio.c b/fs/aio.c
index e4598d6d49d..ac1c1587aa0 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -68,10 +68,8 @@ static void aio_queue_work(struct kioctx *);
*/
static int __init aio_setup(void)
{
- kiocb_cachep = kmem_cache_create("kiocb", sizeof(struct kiocb),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
- kioctx_cachep = kmem_cache_create("kioctx", sizeof(struct kioctx),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+ kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC);
aio_wq = create_workqueue("aio");
@@ -348,10 +346,9 @@ void fastcall exit_aio(struct mm_struct *mm)
wait_for_all_aios(ctx);
/*
- * this is an overkill, but ensures we don't leave
- * the ctx on the aio_wq
+ * Ensure we don't leave the ctx on the aio_wq
*/
- flush_workqueue(aio_wq);
+ cancel_work_sync(&ctx->wq.work);
if (1 != atomic_read(&ctx->users))
printk(KERN_DEBUG
@@ -374,7 +371,7 @@ void fastcall __put_ioctx(struct kioctx *ctx)
BUG_ON(ctx->reqs_active);
cancel_delayed_work(&ctx->wq);
- flush_workqueue(aio_wq);
+ cancel_work_sync(&ctx->wq.work);
aio_free_ring(ctx);
mmdrop(ctx->mm);
ctx->mm = NULL;
diff --git a/fs/attr.c b/fs/attr.c
index 97de9467087..a0a0c7b07ba 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -9,7 +9,6 @@
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/capability.h>
#include <linux/fsnotify.h>
#include <linux/fcntl.h>
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 26063dc84a2..5769a2f9ad6 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -18,7 +18,6 @@
#include <linux/pagemap.h>
#include <linux/parser.h>
#include <linux/bitops.h>
-#include <linux/smp_lock.h>
#include <linux/magic.h>
#include "autofs_i.h"
#include <linux/module.h>
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index d0e9b3a3905..15170f4e13a 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -17,7 +17,6 @@
#include <linux/stat.h>
#include <linux/param.h>
#include <linux/time.h>
-#include <linux/smp_lock.h>
#include "autofs_i.h"
static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *);
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index efeab2fab40..329ee473eed 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/time.h>
-#include <linux/smp_lock.h>
#include <linux/namei.h>
#include <linux/poll.h>
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index cc6cc8ed2e3..fe96108a788 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -293,8 +293,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct befs_inode_info *bi = (struct befs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&bi->vfs_inode);
}
}
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 93d6219243a..edc08d89aab 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -248,8 +248,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct bfs_inode_info *bi = foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&bi->vfs_inode);
}
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 9cc4f0a8aaa..fa8ea33ab0b 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -31,7 +31,6 @@
#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/compiler.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
@@ -39,6 +38,7 @@
#include <linux/syscalls.h>
#include <linux/random.h>
#include <linux/elf.h>
+#include <linux/utsname.h>
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/page.h>
@@ -871,6 +871,8 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
elf_prot, elf_flags);
if (BAD_ADDR(error)) {
send_sig(SIGKILL, current, 0);
+ retval = IS_ERR((void *)error) ?
+ PTR_ERR((void*)error) : -EINVAL;
goto out_free_dentry;
}
@@ -900,6 +902,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
TASK_SIZE - elf_ppnt->p_memsz < k) {
/* set_brk can never work. Avoid overflows. */
send_sig(SIGKILL, current, 0);
+ retval = -EINVAL;
goto out_free_dentry;
}
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index f3ddca4a387..9d62fbad3d4 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -30,7 +30,6 @@
#include <linux/personality.h>
#include <linux/ptrace.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/elf.h>
#include <linux/elf-fdpic.h>
#include <linux/elfcore.h>
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index 1f2d1ad6331..576dd7de227 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -12,7 +12,6 @@
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
#include <linux/init.h>
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index e6f57990b12..72d0b412c37 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -675,19 +675,8 @@ static ssize_t
bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
char *s = enabled ? "enabled" : "disabled";
- int len = strlen(s);
- loff_t pos = *ppos;
- if (pos < 0)
- return -EINVAL;
- if (pos >= len)
- return 0;
- if (len < pos + nbytes)
- nbytes = len - pos;
- if (copy_to_user(buf, s + pos, nbytes))
- return -EFAULT;
- *ppos = pos + nbytes;
- return nbytes;
+ return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
}
static ssize_t bm_status_write(struct file * file, const char __user * buffer,
@@ -727,8 +716,8 @@ static const struct super_operations s_ops = {
static int bm_fill_super(struct super_block * sb, void * data, int silent)
{
static struct tree_descr bm_files[] = {
- [1] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
- [2] = {"register", &bm_register_operations, S_IWUSR},
+ [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
+ [3] = {"register", &bm_register_operations, S_IWUSR},
/* last one */ {""}
};
int err = simple_fill_super(sb, 0x42494e4d, bm_files);
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 1edbcca25a7..304c88544d8 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -12,7 +12,6 @@
#include <linux/binfmts.h>
#include <linux/init.h>
#include <linux/file.h>
-#include <linux/smp_lock.h>
#include <linux/err.h>
#include <linux/fs.h>
diff --git a/fs/bio.c b/fs/bio.c
index 7618bcb1836..093345f0012 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -28,7 +28,7 @@
#include <linux/blktrace_api.h>
#include <scsi/sg.h> /* for struct sg_iovec */
-#define BIO_POOL_SIZE 256
+#define BIO_POOL_SIZE 2
static struct kmem_cache *bio_slab __read_mostly;
@@ -38,7 +38,7 @@ static struct kmem_cache *bio_slab __read_mostly;
* a small number of entries is fine, not going to be performance critical.
* basically we just need to survive
*/
-#define BIO_SPLIT_ENTRIES 8
+#define BIO_SPLIT_ENTRIES 2
mempool_t *bio_split_pool __read_mostly;
struct biovec_slab {
@@ -1120,7 +1120,7 @@ struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors)
* create memory pools for biovec's in a bio_set.
* use the global biovec slabs created for general use.
*/
-static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
+static int biovec_create_pools(struct bio_set *bs, int pool_entries)
{
int i;
@@ -1128,9 +1128,6 @@ static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
struct biovec_slab *bp = bvec_slabs + i;
mempool_t **bvp = bs->bvec_pools + i;
- if (pool_entries > 1 && i >= scale)
- pool_entries >>= 1;
-
*bvp = mempool_create_slab_pool(pool_entries, bp->slab);
if (!*bvp)
return -ENOMEM;
@@ -1161,7 +1158,7 @@ void bioset_free(struct bio_set *bs)
kfree(bs);
}
-struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
+struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size)
{
struct bio_set *bs = kzalloc(sizeof(*bs), GFP_KERNEL);
@@ -1172,7 +1169,7 @@ struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size, int scale)
if (!bs->bio_pool)
goto bad;
- if (!biovec_create_pools(bs, bvec_pool_size, scale))
+ if (!biovec_create_pools(bs, bvec_pool_size))
return bs;
bad:
@@ -1196,38 +1193,11 @@ static void __init biovec_init_slabs(void)
static int __init init_bio(void)
{
- int megabytes, bvec_pool_entries;
- int scale = BIOVEC_NR_POOLS;
-
- bio_slab = kmem_cache_create("bio", sizeof(struct bio), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
biovec_init_slabs();
- megabytes = nr_free_pages() >> (20 - PAGE_SHIFT);
-
- /*
- * find out where to start scaling
- */
- if (megabytes <= 16)
- scale = 0;
- else if (megabytes <= 32)
- scale = 1;
- else if (megabytes <= 64)
- scale = 2;
- else if (megabytes <= 96)
- scale = 3;
- else if (megabytes <= 128)
- scale = 4;
-
- /*
- * Limit number of entries reserved -- mempools are only used when
- * the system is completely unable to allocate memory, so we only
- * need enough to make progress.
- */
- bvec_pool_entries = 1 + scale;
-
- fs_bio_set = bioset_create(BIO_POOL_SIZE, bvec_pool_entries, scale);
+ fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
if (!fs_bio_set)
panic("bio: can't allocate bios\n");
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 575076c018f..74289924087 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -22,6 +22,7 @@
#include <linux/mount.h>
#include <linux/uio.h>
#include <linux/namei.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -55,17 +56,19 @@ static sector_t max_block(struct block_device *bdev)
return retval;
}
-/* Kill _all_ buffers, dirty or not.. */
+/* Kill _all_ buffers and pagecache , dirty or not.. */
static void kill_bdev(struct block_device *bdev)
{
- invalidate_bdev(bdev, 1);
+ if (bdev->bd_inode->i_mapping->nrpages == 0)
+ return;
+ invalidate_bh_lrus();
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
}
int set_blocksize(struct block_device *bdev, int size)
{
/* Size must be a power of two, and between 512 and PAGE_SIZE */
- if (size > PAGE_SIZE || size < 512 || (size & (size-1)))
+ if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size))
return -EINVAL;
/* Size cannot be smaller than the size supported by the device */
@@ -455,9 +458,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
struct bdev_inode *ei = (struct bdev_inode *) foo;
struct block_device *bdev = &ei->bdev;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
- {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
memset(bdev, 0, sizeof(*bdev));
mutex_init(&bdev->bd_mutex);
sema_init(&bdev->bd_mount_sem, 1);
@@ -1478,7 +1479,7 @@ int __invalidate_device(struct block_device *bdev)
res = invalidate_inodes(sb);
drop_super(sb);
}
- invalidate_bdev(bdev, 0);
+ invalidate_bdev(bdev);
return res;
}
EXPORT_SYMBOL(__invalidate_device);
diff --git a/fs/buffer.c b/fs/buffer.c
index 1d0852fa728..aecd057cd0e 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -24,7 +24,6 @@
#include <linux/mm.h>
#include <linux/percpu.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/capability.h>
#include <linux/blkdev.h>
#include <linux/file.h>
@@ -44,7 +43,6 @@
#include <linux/bit_spinlock.h>
static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
-static void invalidate_bh_lrus(void);
#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers)
@@ -333,7 +331,7 @@ out:
we think the disk contains more recent information than the buffercache.
The update == 1 pass marks the buffers we need to update, the update == 2
pass does the actual I/O. */
-void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
+void invalidate_bdev(struct block_device *bdev)
{
struct address_space *mapping = bdev->bd_inode->i_mapping;
@@ -341,11 +339,6 @@ void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers)
return;
invalidate_bh_lrus();
- /*
- * FIXME: what about destroy_dirty_buffers?
- * We really want to use invalidate_inode_pages2() for
- * that, but not until that's cleaned up.
- */
invalidate_mapping_pages(mapping, 0, -1);
}
@@ -1408,7 +1401,7 @@ static void invalidate_bh_lru(void *arg)
put_cpu_var(bh_lrus);
}
-static void invalidate_bh_lrus(void)
+void invalidate_bh_lrus(void)
{
on_each_cpu(invalidate_bh_lru, NULL, 1, 1);
}
@@ -1700,17 +1693,8 @@ done:
* clean. Someone wrote them back by hand with
* ll_rw_block/submit_bh. A rare case.
*/
- int uptodate = 1;
- do {
- if (!buffer_uptodate(bh)) {
- uptodate = 0;
- break;
- }
- bh = bh->b_this_page;
- } while (bh != head);
- if (uptodate)
- SetPageUptodate(page);
end_page_writeback(page);
+
/*
* The page and buffer_heads can be released at any time from
* here on.
@@ -1742,6 +1726,7 @@ recover:
} while ((bh = bh->b_this_page) != head);
SetPageError(page);
BUG_ON(PageWriteback(page));
+ mapping_set_error(page->mapping, err);
set_page_writeback(page);
do {
struct buffer_head *next = bh->b_this_page;
@@ -1861,13 +1846,8 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
if (block_start >= to)
break;
if (buffer_new(bh)) {
- void *kaddr;
-
clear_buffer_new(bh);
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr+block_start, 0, bh->b_size);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, block_start, bh->b_size, KM_USER0);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
}
@@ -1955,10 +1935,8 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
SetPageError(page);
}
if (!buffer_mapped(bh)) {
- void *kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + i * blocksize, 0, blocksize);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, i * blocksize, blocksize,
+ KM_USER0);
if (!err)
set_buffer_uptodate(bh);
continue;
@@ -2101,7 +2079,6 @@ int cont_prepare_write(struct page *page, unsigned offset,
long status;
unsigned zerofrom;
unsigned blocksize = 1 << inode->i_blkbits;
- void *kaddr;
while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) {
status = -ENOMEM;
@@ -2123,10 +2100,8 @@ int cont_prepare_write(struct page *page, unsigned offset,
PAGE_CACHE_SIZE, get_block);
if (status)
goto out_unmap;
- kaddr = kmap_atomic(new_page, KM_USER0);
- memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom);
- flush_dcache_page(new_page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, zerofrom, PAGE_CACHE_SIZE - zerofrom,
+ KM_USER0);
generic_commit_write(NULL, new_page, zerofrom, PAGE_CACHE_SIZE);
unlock_page(new_page);
page_cache_release(new_page);
@@ -2153,10 +2128,7 @@ int cont_prepare_write(struct page *page, unsigned offset,
if (status)
goto out1;
if (zerofrom < offset) {
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr+zerofrom, 0, offset-zerofrom);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, zerofrom, offset - zerofrom, KM_USER0);
__block_commit_write(inode, page, zerofrom, offset);
}
return 0;
@@ -2355,10 +2327,7 @@ failed:
* Error recovery is pretty slack. Clear the page and mark it dirty
* so we'll later zero out any blocks which _were_ allocated.
*/
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr, 0, PAGE_CACHE_SIZE);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0);
SetPageUptodate(page);
set_page_dirty(page);
return ret;
@@ -2397,7 +2366,6 @@ int nobh_writepage(struct page *page, get_block_t *get_block,
loff_t i_size = i_size_read(inode);
const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
unsigned offset;
- void *kaddr;
int ret;
/* Is the page fully inside i_size? */
@@ -2428,10 +2396,7 @@ int nobh_writepage(struct page *page, get_block_t *get_block,
* the page size, the remaining memory is zeroed when mapped, and
* writes to that region are not written out to the file."
*/
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
out:
ret = mpage_writepage(page, get_block, wbc);
if (ret == -EAGAIN)
@@ -2452,7 +2417,6 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
unsigned to;
struct page *page;
const struct address_space_operations *a_ops = mapping->a_ops;
- char *kaddr;
int ret = 0;
if ((offset & (blocksize - 1)) == 0)
@@ -2466,10 +2430,8 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from)
to = (offset + blocksize) & ~(blocksize - 1);
ret = a_ops->prepare_write(NULL, page, offset, to);
if (ret == 0) {
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
+ KM_USER0);
/*
* It would be more correct to call aops->commit_write()
* here, but this is more efficient.
@@ -2495,7 +2457,6 @@ int block_truncate_page(struct address_space *mapping,
struct inode *inode = mapping->host;
struct page *page;
struct buffer_head *bh;
- void *kaddr;
int err;
blocksize = 1 << inode->i_blkbits;
@@ -2549,11 +2510,7 @@ int block_truncate_page(struct address_space *mapping,
goto unlock;
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
-
+ zero_user_page(page, offset, length, KM_USER0);
mark_buffer_dirty(bh);
err = 0;
@@ -2574,7 +2531,6 @@ int block_write_full_page(struct page *page, get_block_t *get_block,
loff_t i_size = i_size_read(inode);
const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
unsigned offset;
- void *kaddr;
/* Is the page fully inside i_size? */
if (page->index < end_index)
@@ -2600,10 +2556,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block,
* the page size, the remaining memory is zeroed when mapped, and
* writes to that region are not written out to the file."
*/
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
return __block_write_full_page(inode, page, get_block, wbc);
}
@@ -2968,8 +2921,7 @@ EXPORT_SYMBOL(free_buffer_head);
static void
init_buffer_head(void *data, struct kmem_cache *cachep, unsigned long flags)
{
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
struct buffer_head * bh = (struct buffer_head *)data;
memset(bh, 0, sizeof(*bh));
@@ -2994,7 +2946,7 @@ static void buffer_exit_cpu(int cpu)
static int buffer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
- if (action == CPU_DEAD)
+ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
buffer_exit_cpu((unsigned long)hcpu);
return NOTIFY_OK;
}
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 5d1f4873d70..a9b6bc5157b 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,4 +1,16 @@
-Verison 1.48
+Version 1.49
+------------
+IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6
+address after the "ip=" mount option, at least until mount.cifs is fixed to
+handle DNS host to ipv6 name translation). Accept override of uid or gid
+on mount even when Unix Extensions are negotiated (it used to be ignored
+when Unix Extensions were ignored). This allows users to override the
+default uid and gid for files when they are certain that the uids or
+gids on the server do not match those of the client. Make "sec=none"
+mount override username (so that null user connection is attempted)
+to match what documentation said.
+
+Version 1.48
------------
Fix mtime bouncing around from local idea of last write times to remote time.
Fix hang (in i_size_read) when simultaneous size update of same remote file
@@ -9,7 +21,13 @@ from read-only back to read-write, reflect this change in default file mode
(we had been leaving a file's mode read-only until the inode were reloaded).
Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute
when archive dos attribute not set and we are changing mode back to writeable
-on server which does not support the Unix Extensions).
+on server which does not support the Unix Extensions). Remove read only dos
+attribute on chmod when adding any write permission (ie on any of
+user/group/other (not all of user/group/other ie 0222) when
+mounted to windows. Add support for POSIX MkDir (slight performance
+enhancement and eliminates the network race between the mkdir and set
+path info of the mode).
+
Version 1.47
------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 080c5eba112..4d01697722c 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -257,13 +257,19 @@ A partial list of the supported mount options follows:
mount.
domain Set the SMB/CIFS workgroup name prepended to the
username during CIFS session establishment
- uid If CIFS Unix extensions are not supported by the server
- this overrides the default uid for inodes. For mounts to
- servers which do support the CIFS Unix extensions, such
- as a properly configured Samba server, the server provides
- the uid, gid and mode. For servers which do not support
- the Unix extensions, the default uid (and gid) returned on
- lookup of existing files is the uid (gid) of the person
+ uid Set the default uid for inodes. For mounts to servers
+ which do support the CIFS Unix extensions, such as a
+ properly configured Samba server, the server provides
+ the uid, gid and mode so this parameter should not be
+ specified unless the server and clients uid and gid
+ numbering differ. If the server and client are in the
+ same domain (e.g. running winbind or nss_ldap) and
+ the server supports the Unix Extensions then the uid
+ and gid can be retrieved from the server (and uid
+ and gid would not have to be specifed on the mount.
+ For servers which do not support the CIFS Unix
+ extensions, the default uid (and gid) returned on lookup
+ of existing files will be the uid (gid) of the person
who executed the mount (root, except when mount.cifs
is configured setuid for user mounts) unless the "uid="
(gid) mount option is specified. For the uid (gid) of newly
@@ -281,8 +287,7 @@ A partial list of the supported mount options follows:
the client. Note that the mount.cifs helper must be
at version 1.10 or higher to support specifying the uid
(or gid) in non-numberic form.
- gid If CIFS Unix extensions are not supported by the server
- this overrides the default gid for inodes.
+ gid Set the default gid for inodes (similar to above).
file_mode If CIFS Unix extensions are not supported by the server
this overrides the default mode for file inodes.
dir_mode If CIFS Unix extensions are not supported by the server
@@ -467,7 +472,7 @@ including:
-V print mount.cifs version
-? display simple usage information
-With recent 2.6 kernel versions of modutils, the version of the cifs kernel
+With most 2.6 kernel versions of modutils, the version of the cifs kernel
module can be displayed via modinfo.
Misc /proc/fs/cifs Flags and Debug Info
@@ -516,8 +521,22 @@ SecurityFlags Flags which control security negotiation and
must use plaintext passwords 0x20020
(reserved for future packet encryption) 0x00040
-cifsFYI If set to one, additional debug information is
- logged to the system error log. (default 0)
+cifsFYI If set to non-zero value, additional debug information
+ will be logged to the system error log. This field
+ contains three flags controlling different classes of
+ debugging entries. The maximum value it can be set
+ to is 7 which enables all debugging points (default 0).
+ Some debugging statements are not compiled into the
+ cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the
+ kernel configuration. cifsFYI may be set to one or
+ nore of the following flags (7 sets them all):
+
+ log cifs informational messages 0x01
+ log return codes from cifs entry points 0x02
+ log slow responses (ie which take longer than 1 second)
+ CONFIG_CIFS_STATS2 must be enabled in .config 0x04
+
+
traceSMB If set to one, debug information is logged to the
system error log with the start of smb requests
and responses (default 0)
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index d7b9c27c942..78b620e332b 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -1,4 +1,4 @@
-Version 1.39 November 30, 2005
+Version 1.49 April 26, 2007
A Partial List of Missing Features
==================================
@@ -18,7 +18,7 @@ better)
d) Kerberos/SPNEGO session setup support - (started)
-e) NTLMv2 authentication (mostly implemented - double check
+e) More testing of NTLMv2 authentication (mostly implemented - double check
that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in
fs/cifs/connect.c)
@@ -27,55 +27,44 @@ used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
and raw NTLMSSP already. This is important when enabling
extended security and mounting to Windows 2003 Servers
-f) Directory entry caching relies on a 1 second timer, rather than
+g) Directory entry caching relies on a 1 second timer, rather than
using FindNotify or equivalent. - (started)
-g) A few byte range testcases fail due to POSIX vs. Windows/CIFS
-style byte range lock differences. Save byte range locks so
-reconnect can replay them.
-
-h) Support unlock all (unlock 0,MAX_OFFSET)
-by unlocking all known byte range locks that we locked on the file.
-
-i) quota support (needs minor kernel change since quota calls
+h) quota support (needs minor kernel change since quota calls
to make it to network filesystems or deviceless filesystems)
-j) investigate sync behavior (including syncpage) and check
+i) investigate sync behavior (including syncpage) and check
for proper behavior of intr/nointr
-k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
+j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
extra copy in/out of the socket buffers in some cases.
-l) finish support for IPv6. This is mostly complete but
-needs a simple conversion of ipv6 to sin6_addr from the
-address in string representation.
-
-m) Better optimize open (and pathbased setfilesize) to reduce the
+k) Better optimize open (and pathbased setfilesize) to reduce the
oplock breaks coming from windows srv. Piggyback identical file
opens on top of each other by incrementing reference count rather
than resending (helps reduce server resource utilization and avoid
spurious oplock breaks).
-o) Improve performance of readpages by sending more than one read
+l) Improve performance of readpages by sending more than one read
at a time when 8 pages or more are requested. In conjuntion
add support for async_cifs_readpages.
-p) Add support for storing symlink info to Windows servers
+m) Add support for storing symlink info to Windows servers
in the Extended Attribute format their SFU clients would recognize.
-q) Finish fcntl D_NOTIFY support so kde and gnome file list windows
+n) Finish fcntl D_NOTIFY support so kde and gnome file list windows
will autorefresh (partially complete by Asser). Needs minor kernel
vfs change to support removing D_NOTIFY on a file.
-r) Add GUI tool to configure /proc/fs/cifs settings and for display of
+o) Add GUI tool to configure /proc/fs/cifs settings and for display of
the CIFS statistics (started)
-s) implement support for security and trusted categories of xattrs
+p) implement support for security and trusted categories of xattrs
(requires minor protocol extension) to enable better support for SELINUX
-t) Implement O_DIRECT flag on open (already supported on mount)
+q) Implement O_DIRECT flag on open (already supported on mount)
-u) Create UID mapping facility so server UIDs can be mapped on a per
+r) Create UID mapping facility so server UIDs can be mapped on a per
mount or a per server basis to client UIDs or nobody if no mapping
exists. This is helpful when Unix extensions are negotiated to
allow better permission checking when UIDs differ on the server
@@ -83,19 +72,26 @@ and client. Add new protocol request to the CIFS protocol
standard for asking the server for the corresponding name of a
particular uid.
-v) Add support for CIFS Unix and also the newer POSIX extensions to the
+s) Add support for CIFS Unix and also the newer POSIX extensions to the
server side for Samba 4.
-w) Finish up the dos time conversion routines needed to return old server
-time to the client (default time, of now or time 0 is used now for these
-very old servers)
-
-x) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
+t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers)
need to add ability to set time to server (utimes command)
-y) Finish testing of Windows 9x/Windows ME server support (started).
+u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
+
+v) mount check for unmatched uids
+
+w) Add mount option for Linux extension disable per mount, and partial
+disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
-KNOWN BUGS (updated February 26, 2007)
+x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of
+processes can proceed better in parallel (on the server)
+
+y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount
+restriction of wsize max being 127K)
+
+KNOWN BUGS (updated April 24, 2007)
====================================
See http://bugzilla.samba.org - search on product "CifsVFS" for
current bug list.
@@ -127,10 +123,3 @@ negotiated size) and send larger write sizes to modern servers.
4) More exhaustively test against less common servers. More testing
against Windows 9x, Windows ME servers.
-DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
-
-mount check for unmatched uids - and uid override
-
-Add mount option for Linux extension disable per mount, and partial disable per mount (uid off, symlink/fifo/mknod on but what about posix acls?)
-
-Free threads at umount --force that are stuck on the sesSem
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index fd1e52ebcee..4cc2012e932 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -22,12 +22,14 @@
#define CIFS_MOUNT_SET_UID 2 /* set current->euid in create etc. */
#define CIFS_MOUNT_SERVER_INUM 4 /* inode numbers from uniqueid from server */
#define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */
-#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
-#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
-#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */
-#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
-#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
-#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
+#define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */
+#define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */
+#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible*/
+#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */
+#define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */
+#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */
+#define CIFS_MOUNT_OVERR_UID 0x400 /* override uid returned from server */
+#define CIFS_MOUNT_OVERR_GID 0x800 /* override gid returned from server */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index d2a8b2941fc..793c4b95c16 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -74,8 +74,8 @@ cifs_strtoUCS(__le16 * to, const char *from, int len,
charlen = codepage->char2uni(from, len, &wchar_to[i]);
if (charlen < 1) {
cERROR(1,
- ("cifs_strtoUCS: char2uni returned %d",
- charlen));
+ ("strtoUCS: char2uni of %d returned %d",
+ (int)*from, charlen));
/* A question mark */
to[i] = cpu_to_le16(0x003f);
charlen = 1;
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index faba4d69fe9..8568e100953 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -100,7 +100,7 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
cifs_sb = CIFS_SB(sb);
- if(cifs_sb == NULL)
+ if (cifs_sb == NULL)
return -ENOMEM;
rc = cifs_mount(sb, cifs_sb, data, devname);
@@ -115,10 +115,10 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
#ifdef CONFIG_CIFS_EXPERIMENTAL
- if(experimEnabled != 0)
+ if (experimEnabled != 0)
sb->s_export_op = &cifs_export_ops;
#endif /* EXPERIMENTAL */
-/* if(cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
+/* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
#ifdef CONFIG_CIFS_QUOTA
sb->s_qcop = &cifs_quotactl_ops;
@@ -147,8 +147,8 @@ out_no_root:
iput(inode);
out_mount_failed:
- if(cifs_sb) {
- if(cifs_sb->local_nls)
+ if (cifs_sb) {
+ if (cifs_sb->local_nls)
unload_nls(cifs_sb->local_nls);
kfree(cifs_sb);
}
@@ -163,7 +163,7 @@ cifs_put_super(struct super_block *sb)
cFYI(1, ("In cifs_put_super"));
cifs_sb = CIFS_SB(sb);
- if(cifs_sb == NULL) {
+ if (cifs_sb == NULL) {
cFYI(1,("Empty cifs superblock info passed to unmount"));
return;
}
@@ -208,14 +208,14 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
/* Only need to call the old QFSInfo if failed
on newer one */
- if(rc)
- if(pTcon->ses->capabilities & CAP_NT_SMBS)
+ if (rc)
+ if (pTcon->ses->capabilities & CAP_NT_SMBS)
rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
/* Some old Windows servers also do not support level 103, retry with
older level one if old server failed the previous call or we
bypassed it because we detected that this was an older LANMAN sess */
- if(rc)
+ if (rc)
rc = SMBOldQFSInfo(xid, pTcon, buf);
/*
int f_type;
@@ -301,11 +301,19 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
if (cifs_sb->tcon->ses->userName)
seq_printf(s, ",username=%s",
cifs_sb->tcon->ses->userName);
- if(cifs_sb->tcon->ses->domainName)
+ if (cifs_sb->tcon->ses->domainName)
seq_printf(s, ",domain=%s",
cifs_sb->tcon->ses->domainName);
}
}
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
+ seq_printf(s, ",posixpaths");
+ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
+ !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+ seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
+ if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
+ !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+ seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
seq_printf(s, ",rsize=%d",cifs_sb->rsize);
seq_printf(s, ",wsize=%d",cifs_sb->wsize);
}
@@ -321,14 +329,14 @@ int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
- if(cifs_sb)
+ if (cifs_sb)
pTcon = cifs_sb->tcon;
else
return -EIO;
xid = GetXid();
- if(pTcon) {
+ if (pTcon) {
cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
} else {
return -EIO;
@@ -346,13 +354,13 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
- if(cifs_sb)
+ if (cifs_sb)
pTcon = cifs_sb->tcon;
else
return -EIO;
xid = GetXid();
- if(pTcon) {
+ if (pTcon) {
cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
} else {
rc = -EIO;
@@ -369,13 +377,13 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
- if(cifs_sb)
+ if (cifs_sb)
pTcon = cifs_sb->tcon;
else
return -EIO;
xid = GetXid();
- if(pTcon) {
+ if (pTcon) {
cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
} else {
rc = -EIO;
@@ -392,13 +400,13 @@ int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
- if(cifs_sb) {
+ if (cifs_sb) {
pTcon = cifs_sb->tcon;
} else {
return -EIO;
}
xid = GetXid();
- if(pTcon) {
+ if (pTcon) {
cFYI(1,("pqstats %p",qstats));
} else {
rc = -EIO;
@@ -424,11 +432,11 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
if (!(flags & MNT_FORCE))
return;
cifs_sb = CIFS_SB(vfsmnt->mnt_sb);
- if(cifs_sb == NULL)
+ if (cifs_sb == NULL)
return;
tcon = cifs_sb->tcon;
- if(tcon == NULL)
+ if (tcon == NULL)
return;
down(&tcon->tconSem);
if (atomic_read(&tcon->useCount) == 1)
@@ -437,7 +445,7 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
- if(tcon->ses && tcon->ses->server)
+ if (tcon->ses && tcon->ses->server)
{
cFYI(1,("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q);
@@ -529,8 +537,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
/* some applications poll for the file length in this strange
way so we must seek to end on non-oplocked files by
setting the revalidate time to zero */
- if(file->f_path.dentry->d_inode)
- CIFS_I(file->f_path.dentry->d_inode)->time = 0;
+ CIFS_I(file->f_path.dentry->d_inode)->time = 0;
retval = cifs_revalidate(file->f_path.dentry);
if (retval < 0)
@@ -694,8 +701,7 @@ cifs_init_once(void *inode, struct kmem_cache * cachep, unsigned long flags)
{
struct cifsInodeInfo *cifsi = inode;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&cifsi->vfs_inode);
INIT_LIST_HEAD(&cifsi->lockList);
}
@@ -724,7 +730,7 @@ cifs_destroy_inodecache(void)
static int
cifs_init_request_bufs(void)
{
- if(CIFSMaxBufSize < 8192) {
+ if (CIFSMaxBufSize < 8192) {
/* Buffer size can not be smaller than 2 * PATH_MAX since maximum
Unicode path name has to fit in any SMB/CIFS path based frames */
CIFSMaxBufSize = 8192;
@@ -741,7 +747,7 @@ cifs_init_request_bufs(void)
if (cifs_req_cachep == NULL)
return -ENOMEM;
- if(cifs_min_rcv < 1)
+ if (cifs_min_rcv < 1)
cifs_min_rcv = 1;
else if (cifs_min_rcv > 64) {
cifs_min_rcv = 64;
@@ -751,7 +757,7 @@ cifs_init_request_bufs(void)
cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
cifs_req_cachep);
- if(cifs_req_poolp == NULL) {
+ if (cifs_req_poolp == NULL) {
kmem_cache_destroy(cifs_req_cachep);
return -ENOMEM;
}
@@ -772,7 +778,7 @@ cifs_init_request_bufs(void)
return -ENOMEM;
}
- if(cifs_min_small < 2)
+ if (cifs_min_small < 2)
cifs_min_small = 2;
else if (cifs_min_small > 256) {
cifs_min_small = 256;
@@ -782,7 +788,7 @@ cifs_init_request_bufs(void)
cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
cifs_sm_req_cachep);
- if(cifs_sm_req_poolp == NULL) {
+ if (cifs_sm_req_poolp == NULL) {
mempool_destroy(cifs_req_poolp);
kmem_cache_destroy(cifs_req_cachep);
kmem_cache_destroy(cifs_sm_req_cachep);
@@ -812,7 +818,7 @@ cifs_init_mids(void)
/* 3 is a reasonable minimum number of simultaneous operations */
cifs_mid_poolp = mempool_create_slab_pool(3, cifs_mid_cachep);
- if(cifs_mid_poolp == NULL) {
+ if (cifs_mid_poolp == NULL) {
kmem_cache_destroy(cifs_mid_cachep);
return -ENOMEM;
}
@@ -850,14 +856,14 @@ static int cifs_oplock_thread(void * dummyarg)
continue;
spin_lock(&GlobalMid_Lock);
- if(list_empty(&GlobalOplock_Q)) {
+ if (list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(39*HZ);
} else {
oplock_item = list_entry(GlobalOplock_Q.next,
struct oplock_q_entry, qhead);
- if(oplock_item) {
+ if (oplock_item) {
cFYI(1,("found oplock item to write out"));
pTcon = oplock_item->tcon;
inode = oplock_item->pinode;
@@ -871,7 +877,7 @@ static int cifs_oplock_thread(void * dummyarg)
/* mutex_lock(&inode->i_mutex);*/
if (S_ISREG(inode->i_mode)) {
rc = filemap_fdatawrite(inode->i_mapping);
- if(CIFS_I(inode)->clientCanCacheRead == 0) {
+ if (CIFS_I(inode)->clientCanCacheRead == 0) {
filemap_fdatawait(inode->i_mapping);
invalidate_remote_inode(inode);
}
@@ -888,7 +894,7 @@ static int cifs_oplock_thread(void * dummyarg)
not bother sending an oplock release if session
to server still is disconnected since oplock
already released by the server in that case */
- if(pTcon->tidStatus != CifsNeedReconnect) {
+ if (pTcon->tidStatus != CifsNeedReconnect) {
rc = CIFSSMBLock(0, pTcon, netfid,
0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
@@ -922,7 +928,7 @@ static int cifs_dnotify_thread(void * dummyarg)
list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList);
- if(ses && ses->server &&
+ if (ses && ses->server &&
atomic_read(&ses->server->inFlight))
wake_up_all(&ses->server->response_q);
}
@@ -971,10 +977,10 @@ init_cifs(void)
rwlock_init(&GlobalSMBSeslock);
spin_lock_init(&GlobalMid_Lock);
- if(cifs_max_pending < 2) {
+ if (cifs_max_pending < 2) {
cifs_max_pending = 2;
cFYI(1,("cifs_max_pending set to min of 2"));
- } else if(cifs_max_pending > 256) {
+ } else if (cifs_max_pending > 256) {
cifs_max_pending = 256;
cFYI(1,("cifs_max_pending set to max of 256"));
}
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 2c2c384894d..c235d32ad4a 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -100,5 +100,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern int cifs_ioctl (struct inode * inode, struct file * filep,
unsigned int command, unsigned long arg);
-#define CIFS_VERSION "1.48"
+#define CIFS_VERSION "1.49"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index e4de8eba478..23655de2f4a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -311,7 +311,7 @@ struct cifsFileInfo {
/* lock scope id (0 if none) */
struct file * pfile; /* needed for writepage */
struct inode * pInode; /* needed for oplock break */
- struct semaphore lock_sem;
+ struct mutex lock_mutex;
struct list_head llist; /* list of byte range locks we have. */
unsigned closePend:1; /* file is marked to close */
unsigned invalidHandle:1; /* file closed via session abend */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 4d8948e8762..d619ca7d141 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -1388,7 +1388,7 @@ struct smb_t2_rsp {
#define SMB_SET_POSIX_LOCK 0x208
#define SMB_POSIX_OPEN 0x209
#define SMB_POSIX_UNLINK 0x20a
-#define SMB_SET_FILE_UNIX_INFO2
+#define SMB_SET_FILE_UNIX_INFO2 0x20b
#define SMB_SET_FILE_BASIC_INFO2 0x3ec
#define SMB_SET_FILE_RENAME_INFORMATION 0x3f2 /* BB check if qpathinfo too */
#define SMB_FILE_ALL_INFO2 0x3fa
@@ -2109,22 +2109,40 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
/* end of POSIX ACL definitions */
+/* POSIX Open Flags */
+#define SMB_O_RDONLY 0x1
+#define SMB_O_WRONLY 0x2
+#define SMB_O_RDWR 0x4
+#define SMB_O_CREAT 0x10
+#define SMB_O_EXCL 0x20
+#define SMB_O_TRUNC 0x40
+#define SMB_O_APPEND 0x80
+#define SMB_O_SYNC 0x100
+#define SMB_O_DIRECTORY 0x200
+#define SMB_O_NOFOLLOW 0x400
+#define SMB_O_DIRECT 0x800
+
typedef struct {
- __u32 OpenFlags; /* same as NT CreateX */
- __u32 PosixOpenFlags;
- __u32 Mode;
- __u16 Level; /* reply level requested (see QPathInfo levels) */
- __u16 Pad; /* reserved - MBZ */
+ __le32 OpenFlags; /* same as NT CreateX */
+ __le32 PosixOpenFlags;
+ __le64 Permissions;
+ __le16 Level; /* reply level requested (see QPathInfo levels) */
} __attribute__((packed)) OPEN_PSX_REQ; /* level 0x209 SetPathInfo data */
typedef struct {
- /* reply varies based on requested level */
+ __le16 OplockFlags;
+ __u16 Fid;
+ __le32 CreateAction;
+ __le16 ReturnedLevel;
+ __le16 Pad;
+ /* struct following varies based on requested level */
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
struct file_internal_info {
__u64 UniqueId; /* inode number */
} __attribute__((packed)); /* level 0x3ee */
+
struct file_mode_info {
__le32 Mode;
} __attribute__((packed)); /* level 0x3f8 */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 32eb1acab63..5d163e2b614 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsproto.h
*
- * Copyright (c) International Business Machines Corp., 2002,2006
+ * Copyright (c) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -244,6 +244,11 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
+extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
+ u32 posix_flags, __u64 mode, __u16 * netfid,
+ FILE_UNIX_BASIC_INFO *pRetData,
+ __u32 *pOplock, const char *name,
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 48fc0c2ab0e..14de58fa143 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifssmb.c
*
- * Copyright (C) International Business Machines Corp., 2002,2006
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Contains the routines for constructing the SMB PDUs themselves
@@ -24,8 +24,8 @@
/* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
/* These are mostly routines that operate on a pathname, or on a tree id */
/* (mounted volume), but there are eight handle based routines which must be */
- /* treated slightly different for reconnection purposes since we never want */
- /* to reuse a stale file handle and the caller knows the file handle */
+ /* treated slightly differently for reconnection purposes since we never */
+ /* want to reuse a stale file handle and only the caller knows the file info */
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -913,6 +913,130 @@ MkDirRetry:
return rc;
}
+int
+CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
+ __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
+ __u32 *pOplock, const char *name,
+ const struct nls_table *nls_codepage, int remap)
+{
+ TRANSACTION2_SPI_REQ *pSMB = NULL;
+ TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ int name_len;
+ int rc = 0;
+ int bytes_returned = 0;
+ char *data_offset;
+ __u16 params, param_offset, offset, byte_count, count;
+ OPEN_PSX_REQ * pdata;
+ OPEN_PSX_RSP * psx_rsp;
+
+ cFYI(1, ("In POSIX Create"));
+PsxCreat:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifsConvertToUCS((__le16 *) pSMB->FileName, name,
+ PATH_MAX, nls_codepage, remap);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB improve the check for buffer overruns BB */
+ name_len = strnlen(name, PATH_MAX);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, name, name_len);
+ }
+
+ params = 6 + name_len;
+ count = sizeof(OPEN_PSX_REQ);
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ param_offset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ offset = param_offset + params;
+ data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+ pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
+ pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
+ pdata->Permissions = cpu_to_le64(mode);
+ pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
+ pdata->OpenFlags = cpu_to_le32(*pOplock);
+ pSMB->ParameterOffset = cpu_to_le16(param_offset);
+ pSMB->DataOffset = cpu_to_le16(offset);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ byte_count = 3 /* pad */ + params + count;
+
+ pSMB->DataCount = cpu_to_le16(count);
+ pSMB->ParameterCount = cpu_to_le16(params);
+ pSMB->TotalDataCount = pSMB->DataCount;
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->ByteCount = cpu_to_le16(byte_count);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Posix create returned %d", rc));
+ goto psx_create_err;
+ }
+
+ cFYI(1,("copying inode info"));
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+
+ if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
+ rc = -EIO; /* bad smb */
+ goto psx_create_err;
+ }
+
+ /* copy return information to pRetData */
+ psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
+ + le16_to_cpu(pSMBr->t2.DataOffset));
+
+ *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
+ if(netfid)
+ *netfid = psx_rsp->Fid; /* cifs fid stays in le */
+ /* Let caller know file was created so we can set the mode. */
+ /* Do we care about the CreateAction in any other cases? */
+ if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
+ *pOplock |= CIFS_CREATE_ACTION;
+ /* check to make sure response data is there */
+ if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
+ pRetData->Type = -1; /* unknown */
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1,("unknown type"));
+#endif
+ } else {
+ if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
+ + sizeof(FILE_UNIX_BASIC_INFO)) {
+ cERROR(1,("Open response data too small"));
+ pRetData->Type = -1;
+ goto psx_create_err;
+ }
+ memcpy((char *) pRetData,
+ (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
+ sizeof (FILE_UNIX_BASIC_INFO));
+ }
+
+
+psx_create_err:
+ cifs_buf_release(pSMB);
+
+ cifs_stats_inc(&tcon->num_mkdirs);
+
+ if (rc == -EAGAIN)
+ goto PsxCreat;
+
+ return rc;
+}
+
static __u16 convert_disposition(int disposition)
{
__u16 ofun = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 20ba7dcc995..216fb625843 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -30,6 +30,7 @@
#include <linux/mempool.h>
#include <linux/delay.h>
#include <linux/completion.h>
+#include <linux/kthread.h>
#include <linux/pagevec.h>
#include <linux/freezer.h>
#include <asm/uaccess.h>
@@ -74,6 +75,8 @@ struct smb_vol {
unsigned retry:1;
unsigned intr:1;
unsigned setuids:1;
+ unsigned override_uid:1;
+ unsigned override_gid:1;
unsigned noperm:1;
unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
unsigned cifs_acl:1;
@@ -120,7 +123,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
struct mid_q_entry * mid_entry;
spin_lock(&GlobalMid_Lock);
- if(server->tcpStatus == CifsExiting) {
+ if( kthread_should_stop() ) {
/* the demux thread will exit normally
next time through the loop */
spin_unlock(&GlobalMid_Lock);
@@ -182,7 +185,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock);
up(&server->tcpSem);
- while ((server->tcpStatus != CifsExiting) && (server->tcpStatus != CifsGood))
+ while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood))
{
try_to_freeze();
if(server->protocolType == IPV6) {
@@ -199,7 +202,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
} else {
atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock);
- if(server->tcpStatus != CifsExiting)
+ if( !kthread_should_stop() )
server->tcpStatus = CifsGood;
server->sequence_number = 0;
spin_unlock(&GlobalMid_Lock);
@@ -345,7 +348,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
int isMultiRsp;
int reconnect;
- daemonize("cifsd");
allow_signal(SIGKILL);
current->flags |= PF_MEMALLOC;
server->tsk = current; /* save process info to wake at shutdown */
@@ -361,7 +363,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
GFP_KERNEL);
}
- while (server->tcpStatus != CifsExiting) {
+ while (!kthread_should_stop()) {
if (try_to_freeze())
continue;
if (bigbuf == NULL) {
@@ -400,7 +402,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
kernel_recvmsg(csocket, &smb_msg,
&iov, 1, 4, 0 /* BB see socket.h flags */);
- if (server->tcpStatus == CifsExiting) {
+ if ( kthread_should_stop() ) {
break;
} else if (server->tcpStatus == CifsNeedReconnect) {
cFYI(1, ("Reconnect after server stopped responding"));
@@ -524,7 +526,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
total_read += length) {
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
pdu_length - total_read, 0);
- if((server->tcpStatus == CifsExiting) ||
+ if( kthread_should_stop() ||
(length == -EINTR)) {
/* then will exit */
reconnect = 2;
@@ -757,7 +759,6 @@ multi_t2_fnd:
GFP_KERNEL);
}
- complete_and_exit(&cifsd_complete, 0);
return 0;
}
@@ -973,7 +974,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
}
if ((temp_len = strnlen(value, 300)) < 300) {
vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
- if(vol->UNC == NULL)
+ if (vol->UNC == NULL)
return 1;
strcpy(vol->UNC,value);
if (strncmp(vol->UNC, "//", 2) == 0) {
@@ -1010,12 +1011,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
return 1; /* needs_arg; */
}
if ((temp_len = strnlen(value, 1024)) < 1024) {
- if(value[0] != '/')
+ if (value[0] != '/')
temp_len++; /* missing leading slash */
vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
- if(vol->prepath == NULL)
+ if (vol->prepath == NULL)
return 1;
- if(value[0] != '/') {
+ if (value[0] != '/') {
vol->prepath[0] = '/';
strcpy(vol->prepath+1,value);
} else
@@ -1031,7 +1032,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
return 1; /* needs_arg; */
}
if (strnlen(value, 65) < 65) {
- if(strnicmp(value,"default",7))
+ if (strnicmp(value,"default",7))
vol->iocharset = value;
/* if iocharset not set load_nls_default used by caller */
cFYI(1, ("iocharset set to %s",value));
@@ -1043,11 +1044,13 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if (value && *value) {
vol->linux_uid =
simple_strtoul(value, &value, 0);
+ vol->override_uid = 1;
}
} else if (strnicmp(data, "gid", 3) == 0) {
if (value && *value) {
vol->linux_gid =
simple_strtoul(value, &value, 0);
+ vol->override_gid = 1;
}
} else if (strnicmp(data, "file_mode", 4) == 0) {
if (value && *value) {
@@ -1102,7 +1105,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
}
/* The string has 16th byte zero still from
set at top of the function */
- if((i==15) && (value[i] != 0))
+ if ((i==15) && (value[i] != 0))
printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
}
} else if (strnicmp(data, "servern", 7) == 0) {
@@ -1126,7 +1129,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
}
/* The string has 16th byte zero still from
set at top of the function */
- if((i==15) && (value[i] != 0))
+ if ((i==15) && (value[i] != 0))
printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
}
} else if (strnicmp(data, "credentials", 4) == 0) {
@@ -1233,13 +1236,13 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
}
if (vol->UNC == NULL) {
- if(devname == NULL) {
+ if (devname == NULL) {
printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
return 1;
}
if ((temp_len = strnlen(devname, 300)) < 300) {
vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
- if(vol->UNC == NULL)
+ if (vol->UNC == NULL)
return 1;
strcpy(vol->UNC,devname);
if (strncmp(vol->UNC, "//", 2) == 0) {
@@ -1663,7 +1666,13 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
CIFS_SB(sb)->mnt_cifs_flags |=
CIFS_MOUNT_POSIX_PATHS;
}
-
+
+ /* We might be setting the path sep back to a different
+ form if we are reconnecting and the server switched its
+ posix path capability for this share */
+ if(sb && (CIFS_SB(sb)->prepathlen > 0))
+ CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
+
cFYI(1,("Negotiate caps 0x%x",(int)cap));
#ifdef CONFIG_CIFS_DEBUG2
if(cap & CIFS_UNIX_FCNTL_CAP)
@@ -1712,12 +1721,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL;
}
- if (volume_info.username) {
+ if (volume_info.nullauth) {
+ cFYI(1,("null user"));
+ volume_info.username = NULL;
+ } else if (volume_info.username) {
/* BB fixme parse for domain name here */
cFYI(1, ("Username: %s ", volume_info.username));
-
- } else if (volume_info.nullauth) {
- cFYI(1,("null user"));
} else {
cifserror("No username specified");
/* In userspace mount helper we can get user name from alternate
@@ -1791,11 +1800,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
NULL /* no ipv6 addr */,
volume_info.username, &srvTcp);
- else if(address_type == AF_INET6)
+ else if(address_type == AF_INET6) {
+ cFYI(1,("looking for ipv6 address"));
existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
&sin_server6.sin6_addr,
volume_info.username, &srvTcp);
- else {
+ } else {
kfree(volume_info.UNC);
kfree(volume_info.password);
kfree(volume_info.prepath);
@@ -1807,17 +1817,23 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (srvTcp) {
cFYI(1, ("Existing tcp session with server found"));
} else { /* create socket */
- if(volume_info.port)
+ if (volume_info.port)
sin_server.sin_port = htons(volume_info.port);
else
sin_server.sin_port = 0;
- rc = ipv4_connect(&sin_server,&csocket,
+ if (address_type == AF_INET6) {
+ cFYI(1,("attempting ipv6 connect"));
+ /* BB should we allow ipv6 on port 139? */
+ /* other OS never observed in Wild doing 139 with v6 */
+ rc = ipv6_connect(&sin_server6,&csocket);
+ } else
+ rc = ipv4_connect(&sin_server,&csocket,
volume_info.source_rfc1001_name,
volume_info.target_rfc1001_name);
if (rc < 0) {
cERROR(1,
- ("Error connecting to IPv4 socket. Aborting operation"));
- if(csocket != NULL)
+ ("Error connecting to IPv4 socket. Aborting operation"));
+ if (csocket != NULL)
sock_release(csocket);
kfree(volume_info.UNC);
kfree(volume_info.password);
@@ -1850,10 +1866,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
so no need to spinlock this init of tcpStatus */
srvTcp->tcpStatus = CifsNew;
init_MUTEX(&srvTcp->tcpSem);
- rc = (int)kernel_thread((void *)(void *)cifs_demultiplex_thread, srvTcp,
- CLONE_FS | CLONE_FILES | CLONE_VM);
- if(rc < 0) {
- rc = -ENOMEM;
+ srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
+ if ( IS_ERR(srvTcp->tsk) ) {
+ rc = PTR_ERR(srvTcp->tsk);
+ cERROR(1,("error %d create cifsd thread", rc));
+ srvTcp->tsk = NULL;
sock_release(csocket);
kfree(volume_info.UNC);
kfree(volume_info.password);
@@ -1896,7 +1913,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
int len = strlen(volume_info.domainname);
pSesInfo->domainName =
kmalloc(len + 1, GFP_KERNEL);
- if(pSesInfo->domainName)
+ if (pSesInfo->domainName)
strcpy(pSesInfo->domainName,
volume_info.domainname);
}
@@ -1906,7 +1923,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB FIXME need to pass vol->secFlgs BB */
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
up(&pSesInfo->sesSem);
- if(!rc)
+ if (!rc)
atomic_inc(&srvTcp->socketUseCount);
} else
kfree(volume_info.password);
@@ -1914,7 +1931,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* search for existing tcon to this server share */
if (!rc) {
- if(volume_info.rsize > CIFSMaxBufSize) {
+ if (volume_info.rsize > CIFSMaxBufSize) {
cERROR(1,("rsize %d too large, using MaxBufSize",
volume_info.rsize));
cifs_sb->rsize = CIFSMaxBufSize;
@@ -1923,11 +1940,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
else /* default */
cifs_sb->rsize = CIFSMaxBufSize;
- if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
+ if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
cERROR(1,("wsize %d too large using 4096 instead",
volume_info.wsize));
cifs_sb->wsize = 4096;
- } else if(volume_info.wsize)
+ } else if (volume_info.wsize)
cifs_sb->wsize = volume_info.wsize;
else
cifs_sb->wsize =
@@ -1940,14 +1957,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
conjunction with 52K kvec constraint on arch with 4K
page size */
- if(cifs_sb->rsize < 2048) {
+ if (cifs_sb->rsize < 2048) {
cifs_sb->rsize = 2048;
/* Windows ME may prefer this */
cFYI(1,("readsize set to minimum 2048"));
}
/* calculate prepath */
cifs_sb->prepath = volume_info.prepath;
- if(cifs_sb->prepath) {
+ if (cifs_sb->prepath) {
cifs_sb->prepathlen = strlen(cifs_sb->prepath);
cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
volume_info.prepath = NULL;
@@ -1960,24 +1977,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cFYI(1,("file mode: 0x%x dir mode: 0x%x",
cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
- if(volume_info.noperm)
+ if (volume_info.noperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
- if(volume_info.setuids)
+ if (volume_info.setuids)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
- if(volume_info.server_ino)
+ if (volume_info.server_ino)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
- if(volume_info.remap)
+ if (volume_info.remap)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
- if(volume_info.no_xattr)
+ if (volume_info.no_xattr)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
- if(volume_info.sfu_emul)
+ if (volume_info.sfu_emul)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
- if(volume_info.nobrl)
+ if (volume_info.nobrl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
- if(volume_info.cifs_acl)
+ if (volume_info.cifs_acl)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
-
- if(volume_info.direct_io) {
+ if (volume_info.override_uid)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
+ if (volume_info.override_gid)
+ cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
+ if (volume_info.direct_io) {
cFYI(1,("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
}
@@ -2030,7 +2050,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
}
}
- if(pSesInfo) {
+ if (pSesInfo) {
if (pSesInfo->capabilities & CAP_LARGE_FILES) {
sb->s_maxbytes = (u64) 1 << 63;
} else
@@ -2044,13 +2064,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (rc) {
/* if session setup failed, use count is zero but
we still need to free cifsd thread */
- if(atomic_read(&srvTcp->socketUseCount) == 0) {
+ if (atomic_read(&srvTcp->socketUseCount) == 0) {
spin_lock(&GlobalMid_Lock);
srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
- if(srvTcp->tsk) {
+ if (srvTcp->tsk) {
send_sig(SIGKILL,srvTcp->tsk,1);
- wait_for_completion(&cifsd_complete);
+ kthread_stop(srvTcp->tsk);
}
}
/* If find_unc succeeded then rc == 0 so we can not end */
@@ -2063,10 +2083,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
int temp_rc;
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
/* if the socketUseCount is now zero */
- if((temp_rc == -ESHUTDOWN) &&
- (pSesInfo->server->tsk)) {
+ if ((temp_rc == -ESHUTDOWN) &&
+ (pSesInfo->server) && (pSesInfo->server->tsk)) {
send_sig(SIGKILL,pSesInfo->server->tsk,1);
- wait_for_completion(&cifsd_complete);
+ kthread_stop(pSesInfo->server->tsk);
}
} else
cFYI(1, ("No session or bad tcon"));
@@ -2127,7 +2147,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 count;
cFYI(1, ("In sesssetup"));
- if(ses == NULL)
+ if (ses == NULL)
return -EINVAL;
user = ses->userName;
domain = ses->domainName;
@@ -2182,7 +2202,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
*bcc_ptr = 0;
bcc_ptr++;
}
- if(user == NULL)
+ if (user == NULL)
bytes_returned = 0; /* skip null user */
else
bytes_returned =
@@ -2216,7 +2236,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2;
} else {
- if(user != NULL) {
+ if (user != NULL) {
strncpy(bcc_ptr, user, 200);
bcc_ptr += strnlen(user, 200);
}
@@ -3316,7 +3336,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
cFYI(1,("Waking up socket by sending it signal"));
if(cifsd_task) {
send_sig(SIGKILL,cifsd_task,1);
- wait_for_completion(&cifsd_complete);
+ kthread_stop(cifsd_task);
}
rc = 0;
} /* else - we have an smb session
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 3fad638d26d..e5210519ac4 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -274,7 +274,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
pCifsFile->invalidHandle = FALSE;
pCifsFile->closePend = FALSE;
init_MUTEX(&pCifsFile->fh_sem);
- init_MUTEX(&pCifsFile->lock_sem);
+ mutex_init(&pCifsFile->lock_mutex);
INIT_LIST_HEAD(&pCifsFile->llist);
atomic_set(&pCifsFile->wrtPending,0);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 2d3275bedb5..94d5b49049d 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -27,7 +27,6 @@
#include <linux/fcntl.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
-#include <linux/smp_lock.h>
#include <linux/writeback.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/delay.h>
@@ -48,7 +47,7 @@ static inline struct cifsFileInfo *cifs_init_private(
private_data->netfid = netfid;
private_data->pid = current->tgid;
init_MUTEX(&private_data->fh_sem);
- init_MUTEX(&private_data->lock_sem);
+ mutex_init(&private_data->lock_mutex);
INIT_LIST_HEAD(&private_data->llist);
private_data->pfile = file; /* needed for writepage */
private_data->pInode = inode;
@@ -338,8 +337,7 @@ static int cifs_relock_file(struct cifsFileInfo *cifsFile)
return rc;
}
-static int cifs_reopen_file(struct inode *inode, struct file *file,
- int can_flush)
+static int cifs_reopen_file(struct file *file, int can_flush)
{
int rc = -EACCES;
int xid, oplock;
@@ -347,13 +345,12 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
struct cifsTconInfo *pTcon;
struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode;
+ struct inode * inode;
char *full_path = NULL;
int desiredAccess;
int disposition = FILE_OPEN;
__u16 netfid;
- if (inode == NULL)
- return -EBADF;
if (file->private_data) {
pCifsFile = (struct cifsFileInfo *)file->private_data;
} else
@@ -368,25 +365,37 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
}
if (file->f_path.dentry == NULL) {
- up(&pCifsFile->fh_sem);
- cFYI(1, ("failed file reopen, no valid name if dentry freed"));
- FreeXid(xid);
- return -EBADF;
+ cERROR(1, ("no valid name if dentry freed"));
+ dump_stack();
+ rc = -EBADF;
+ goto reopen_error_exit;
}
+
+ inode = file->f_path.dentry->d_inode;
+ if(inode == NULL) {
+ cERROR(1, ("inode not valid"));
+ dump_stack();
+ rc = -EBADF;
+ goto reopen_error_exit;
+ }
+
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
+
/* can not grab rename sem here because various ops, including
those that already have the rename sem can end up causing writepage
to get called and if the server was down that means we end up here,
and we can never tell if the caller already has the rename_sem */
full_path = build_path_from_dentry(file->f_path.dentry);
if (full_path == NULL) {
+ rc = -ENOMEM;
+reopen_error_exit:
up(&pCifsFile->fh_sem);
FreeXid(xid);
- return -ENOMEM;
+ return rc;
}
- cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
+ cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
inode, file->f_flags,full_path));
desiredAccess = cifs_convert_flags(file->f_flags);
@@ -401,13 +410,6 @@ static int cifs_reopen_file(struct inode *inode, struct file *file,
and server version of file size can be stale. If we knew for sure
that inode was not dirty locally we could do this */
-/* buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
- if (buf == 0) {
- up(&pCifsFile->fh_sem);
- kfree(full_path);
- FreeXid(xid);
- return -ENOMEM;
- } */
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
@@ -508,12 +510,12 @@ int cifs_close(struct inode *inode, struct file *file)
/* Delete any outstanding lock records.
We'll lose them when the file is closed anyway. */
- down(&pSMBFile->lock_sem);
+ mutex_lock(&pSMBFile->lock_mutex);
list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {
list_del(&li->llist);
kfree(li);
}
- up(&pSMBFile->lock_sem);
+ mutex_unlock(&pSMBFile->lock_mutex);
write_lock(&GlobalSMBSeslock);
list_del(&pSMBFile->flist);
@@ -598,9 +600,9 @@ static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
li->offset = offset;
li->length = len;
li->type = lockType;
- down(&fid->lock_sem);
+ mutex_lock(&fid->lock_mutex);
list_add(&li->llist, &fid->llist);
- up(&fid->lock_sem);
+ mutex_unlock(&fid->lock_mutex);
return 0;
}
@@ -757,7 +759,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
struct cifsLockInfo *li, *tmp;
rc = 0;
- down(&fid->lock_sem);
+ mutex_lock(&fid->lock_mutex);
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset &&
length >= li->length) {
@@ -771,7 +773,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
kfree(li);
}
}
- up(&fid->lock_sem);
+ mutex_unlock(&fid->lock_mutex);
}
}
@@ -792,12 +794,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
int xid, long_op;
struct cifsFileInfo *open_file;
- if (file->f_path.dentry == NULL)
- return -EBADF;
-
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- if (cifs_sb == NULL)
- return -EBADF;
pTcon = cifs_sb->tcon;
@@ -807,14 +804,9 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
if (file->private_data == NULL)
return -EBADF;
- else
- open_file = (struct cifsFileInfo *) file->private_data;
+ open_file = (struct cifsFileInfo *) file->private_data;
xid = GetXid();
- if (file->f_path.dentry->d_inode == NULL) {
- FreeXid(xid);
- return -EBADF;
- }
if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */
@@ -841,17 +833,11 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
return -EBADF;
}
if (open_file->invalidHandle) {
- if ((file->f_path.dentry == NULL) ||
- (file->f_path.dentry->d_inode == NULL)) {
- FreeXid(xid);
- return total_written;
- }
/* we could deadlock if we called
filemap_fdatawait from here so tell
reopen_file not to flush data to server
now */
- rc = cifs_reopen_file(file->f_path.dentry->d_inode,
- file, FALSE);
+ rc = cifs_reopen_file(file, FALSE);
if (rc != 0)
break;
}
@@ -908,12 +894,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
int xid, long_op;
struct cifsFileInfo *open_file;
- if (file->f_path.dentry == NULL)
- return -EBADF;
-
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- if (cifs_sb == NULL)
- return -EBADF;
pTcon = cifs_sb->tcon;
@@ -922,14 +903,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
if (file->private_data == NULL)
return -EBADF;
- else
- open_file = (struct cifsFileInfo *)file->private_data;
+ open_file = (struct cifsFileInfo *)file->private_data;
xid = GetXid();
- if (file->f_path.dentry->d_inode == NULL) {
- FreeXid(xid);
- return -EBADF;
- }
if (*poffset > file->f_path.dentry->d_inode->i_size)
long_op = 2; /* writes past end of file can take a long time */
@@ -957,17 +933,11 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
return -EBADF;
}
if (open_file->invalidHandle) {
- if ((file->f_path.dentry == NULL) ||
- (file->f_path.dentry->d_inode == NULL)) {
- FreeXid(xid);
- return total_written;
- }
/* we could deadlock if we called
filemap_fdatawait from here so tell
reopen_file not to flush data to
server now */
- rc = cifs_reopen_file(file->f_path.dentry->d_inode,
- file, FALSE);
+ rc = cifs_reopen_file(file, FALSE);
if (rc != 0)
break;
}
@@ -1056,8 +1026,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
read_unlock(&GlobalSMBSeslock);
if((open_file->invalidHandle) &&
(!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
- rc = cifs_reopen_file(&cifs_inode->vfs_inode,
- open_file->pfile, FALSE);
+ rc = cifs_reopen_file(open_file->pfile, FALSE);
/* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */
if(rc) {
@@ -1404,32 +1373,6 @@ static int cifs_commit_write(struct file *file, struct page *page,
spin_lock(&inode->i_lock);
if (position > inode->i_size) {
i_size_write(inode, position);
- /* if (file->private_data == NULL) {
- rc = -EBADF;
- } else {
- open_file = (struct cifsFileInfo *)file->private_data;
- cifs_sb = CIFS_SB(inode->i_sb);
- rc = -EAGAIN;
- while (rc == -EAGAIN) {
- if ((open_file->invalidHandle) &&
- (!open_file->closePend)) {
- rc = cifs_reopen_file(
- file->f_path.dentry->d_inode, file);
- if (rc != 0)
- break;
- }
- if (!open_file->closePend) {
- rc = CIFSSMBSetFileSize(xid,
- cifs_sb->tcon, position,
- open_file->netfid,
- open_file->pid, FALSE);
- } else {
- rc = -EBADF;
- break;
- }
- }
- cFYI(1, (" SetEOF (commit write) rc = %d", rc));
- } */
}
spin_unlock(&inode->i_lock);
if (!PageUptodate(page)) {
@@ -1573,8 +1516,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
int buf_type = CIFS_NO_BUFFER;
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_path.dentry->d_inode,
- file, TRUE);
+ rc = cifs_reopen_file(file, TRUE);
if (rc != 0)
break;
}
@@ -1660,8 +1602,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_path.dentry->d_inode,
- file, TRUE);
+ rc = cifs_reopen_file(file, TRUE);
if (rc != 0)
break;
}
@@ -1817,8 +1758,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
while (rc == -EAGAIN) {
if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
- rc = cifs_reopen_file(file->f_path.dentry->d_inode,
- file, TRUE);
+ rc = cifs_reopen_file(file, TRUE);
if (rc != 0)
break;
}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f414526e476..3e87dad3367 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/inode.c
*
- * Copyright (C) International Business Machines Corp., 2002,2005
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -90,7 +90,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
(*pinode)->i_ino =
(unsigned long)findData.UniqueId;
} /* note ino incremented to unique num in new_inode */
- if(sb->s_flags & MS_NOATIME)
+ if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode);
@@ -139,8 +139,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode->i_mode |= S_IFREG;
cFYI(1,("unknown type %d",type));
}
- inode->i_uid = le64_to_cpu(findData.Uid);
- inode->i_gid = le64_to_cpu(findData.Gid);
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ inode->i_uid = cifs_sb->mnt_uid;
+ else
+ inode->i_uid = le64_to_cpu(findData.Uid);
+
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ inode->i_gid = cifs_sb->mnt_gid;
+ else
+ inode->i_gid = le64_to_cpu(findData.Gid);
+
inode->i_nlink = le64_to_cpu(findData.Nlinks);
spin_lock(&inode->i_lock);
@@ -178,13 +187,13 @@ int cifs_get_inode_info_unix(struct inode **pinode,
&cifs_file_direct_nobrl_ops;
else
inode->i_fop = &cifs_file_direct_ops;
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops;
else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
/* check if server can support readpages */
- if(pTcon->ses->server->maxBuf <
+ if (pTcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
@@ -220,7 +229,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
pbuf = buf;
- if(size == 0) {
+ if (size == 0) {
inode->i_mode |= S_IFIFO;
return 0;
} else if (size < 8) {
@@ -239,11 +248,11 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
netfid,
24 /* length */, 0 /* offset */,
&bytes_read, &pbuf, &buf_type);
- if((rc == 0) && (bytes_read >= 8)) {
- if(memcmp("IntxBLK", pbuf, 8) == 0) {
+ if ((rc == 0) && (bytes_read >= 8)) {
+ if (memcmp("IntxBLK", pbuf, 8) == 0) {
cFYI(1,("Block device"));
inode->i_mode |= S_IFBLK;
- if(bytes_read == 24) {
+ if (bytes_read == 24) {
/* we have enough to decode dev num */
__u64 mjr; /* major */
__u64 mnr; /* minor */
@@ -251,10 +260,10 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
inode->i_rdev = MKDEV(mjr, mnr);
}
- } else if(memcmp("IntxCHR", pbuf, 8) == 0) {
+ } else if (memcmp("IntxCHR", pbuf, 8) == 0) {
cFYI(1,("Char device"));
inode->i_mode |= S_IFCHR;
- if(bytes_read == 24) {
+ if (bytes_read == 24) {
/* we have enough to decode dev num */
__u64 mjr; /* major */
__u64 mnr; /* minor */
@@ -262,7 +271,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
inode->i_rdev = MKDEV(mjr, mnr);
}
- } else if(memcmp("IntxLNK", pbuf, 7) == 0) {
+ } else if (memcmp("IntxLNK", pbuf, 7) == 0) {
cFYI(1,("Symlink"));
inode->i_mode |= S_IFLNK;
} else {
@@ -293,7 +302,7 @@ static int get_sfu_uid_mode(struct inode * inode,
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
ea_value, 4 /* size of buf */, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- if(rc < 0)
+ if (rc < 0)
return (int)rc;
else if (rc > 3) {
mode = le32_to_cpu(*((__le32 *)ea_value));
@@ -348,7 +357,7 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB optimize code so we do not make the above call
when server claims no NT SMB support and the above call
failed at least once - set flag in tcon or mount */
- if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
+ if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, pTcon, search_path,
pfindData, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
@@ -425,7 +434,7 @@ int cifs_get_inode_info(struct inode **pinode,
} else /* do we need cast or hash to ino? */
(*pinode)->i_ino = inode_num;
} /* else ino incremented to unique num in new_inode*/
- if(sb->s_flags & MS_NOATIME)
+ if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
insert_inode_hash(*pinode);
}
@@ -442,7 +451,7 @@ int cifs_get_inode_info(struct inode **pinode,
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
/* Linux can not store file creation time so ignore it */
- if(pfindData->LastAccessTime)
+ if (pfindData->LastAccessTime)
inode->i_atime = cifs_NTtimeToUnix
(le64_to_cpu(pfindData->LastAccessTime));
else /* do not need to use current_fs_time - time not stored */
@@ -452,7 +461,7 @@ int cifs_get_inode_info(struct inode **pinode,
inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
cFYI(0, ("Attributes came in as 0x%x", attr));
- if(adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
+ if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
}
@@ -521,8 +530,10 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB fill in uid and gid here? with help from winbind?
or retrieve from NTFS stream extended attribute */
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in uid, gid, mode from server ACL */
+ /* BB FIXME this should also take into account the
+ * default uid specified on mount if present */
get_sfu_uid_mode(inode, search_path, cifs_sb, xid);
} else if (atomic_read(&cifsInfo->inUse) == 0) {
inode->i_uid = cifs_sb->mnt_uid;
@@ -541,12 +552,12 @@ int cifs_get_inode_info(struct inode **pinode,
&cifs_file_direct_nobrl_ops;
else
inode->i_fop = &cifs_file_direct_ops;
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops;
else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
- if(pTcon->ses->server->maxBuf <
+ if (pTcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
@@ -597,7 +608,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
xid = GetXid();
- if(inode)
+ if (inode)
cifs_sb = CIFS_SB(inode->i_sb);
else
cifs_sb = CIFS_SB(direntry->d_sb);
@@ -723,7 +734,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
when needed */
direntry->d_inode->i_ctime = current_fs_time(inode->i_sb);
}
- if(inode) {
+ if (inode) {
inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
cifsInode = CIFS_I(inode);
cifsInode->time = 0; /* force revalidate of dir as well */
@@ -734,6 +745,136 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
return rc;
}
+static void posix_fill_in_inode(struct inode *tmp_inode,
+ FILE_UNIX_BASIC_INFO *pData, int *pobject_type, int isNewInode)
+{
+ loff_t local_size;
+ struct timespec local_mtime;
+
+ struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
+ struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb);
+
+ __u32 type = le32_to_cpu(pData->Type);
+ __u64 num_of_bytes = le64_to_cpu(pData->NumOfBytes);
+ __u64 end_of_file = le64_to_cpu(pData->EndOfFile);
+ cifsInfo->time = jiffies;
+ atomic_inc(&cifsInfo->inUse);
+
+ /* save mtime and size */
+ local_mtime = tmp_inode->i_mtime;
+ local_size = tmp_inode->i_size;
+
+ tmp_inode->i_atime =
+ cifs_NTtimeToUnix(le64_to_cpu(pData->LastAccessTime));
+ tmp_inode->i_mtime =
+ cifs_NTtimeToUnix(le64_to_cpu(pData->LastModificationTime));
+ tmp_inode->i_ctime =
+ cifs_NTtimeToUnix(le64_to_cpu(pData->LastStatusChange));
+
+ tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
+ /* since we set the inode type below we need to mask off type
+ to avoid strange results if bits above were corrupt */
+ tmp_inode->i_mode &= ~S_IFMT;
+ if (type == UNIX_FILE) {
+ *pobject_type = DT_REG;
+ tmp_inode->i_mode |= S_IFREG;
+ } else if (type == UNIX_SYMLINK) {
+ *pobject_type = DT_LNK;
+ tmp_inode->i_mode |= S_IFLNK;
+ } else if (type == UNIX_DIR) {
+ *pobject_type = DT_DIR;
+ tmp_inode->i_mode |= S_IFDIR;
+ } else if (type == UNIX_CHARDEV) {
+ *pobject_type = DT_CHR;
+ tmp_inode->i_mode |= S_IFCHR;
+ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
+ le64_to_cpu(pData->DevMinor) & MINORMASK);
+ } else if (type == UNIX_BLOCKDEV) {
+ *pobject_type = DT_BLK;
+ tmp_inode->i_mode |= S_IFBLK;
+ tmp_inode->i_rdev = MKDEV(le64_to_cpu(pData->DevMajor),
+ le64_to_cpu(pData->DevMinor) & MINORMASK);
+ } else if (type == UNIX_FIFO) {
+ *pobject_type = DT_FIFO;
+ tmp_inode->i_mode |= S_IFIFO;
+ } else if (type == UNIX_SOCKET) {
+ *pobject_type = DT_SOCK;
+ tmp_inode->i_mode |= S_IFSOCK;
+ } else {
+ /* safest to just call it a file */
+ *pobject_type = DT_REG;
+ tmp_inode->i_mode |= S_IFREG;
+ cFYI(1,("unknown inode type %d",type));
+ }
+
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1,("object type: %d", type));
+#endif
+ tmp_inode->i_uid = le64_to_cpu(pData->Uid);
+ tmp_inode->i_gid = le64_to_cpu(pData->Gid);
+ tmp_inode->i_nlink = le64_to_cpu(pData->Nlinks);
+
+ spin_lock(&tmp_inode->i_lock);
+ if (is_size_safe_to_change(cifsInfo, end_of_file)) {
+ /* can not safely change the file size here if the
+ client is writing to it due to potential races */
+ i_size_write(tmp_inode, end_of_file);
+
+ /* 512 bytes (2**9) is the fake blocksize that must be used */
+ /* for this calculation, not the real blocksize */
+ tmp_inode->i_blocks = (512 - 1 + num_of_bytes) >> 9;
+ }
+ spin_unlock(&tmp_inode->i_lock);
+
+ if (S_ISREG(tmp_inode->i_mode)) {
+ cFYI(1, ("File inode"));
+ tmp_inode->i_op = &cifs_file_inode_ops;
+
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
+ else
+ tmp_inode->i_fop = &cifs_file_direct_ops;
+
+ } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ tmp_inode->i_fop = &cifs_file_nobrl_ops;
+ else
+ tmp_inode->i_fop = &cifs_file_ops;
+
+ if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+ (cifs_sb->tcon->ses->server->maxBuf <
+ PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
+ tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
+ else
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
+
+ if(isNewInode)
+ return; /* No sense invalidating pages for new inode since we
+ have not started caching readahead file data yet */
+
+ if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
+ (local_size == tmp_inode->i_size)) {
+ cFYI(1, ("inode exists but unchanged"));
+ } else {
+ /* file may have changed on server */
+ cFYI(1, ("invalidate inode, readdir detected change"));
+ invalidate_remote_inode(tmp_inode);
+ }
+ } else if (S_ISDIR(tmp_inode->i_mode)) {
+ cFYI(1, ("Directory inode"));
+ tmp_inode->i_op = &cifs_dir_inode_ops;
+ tmp_inode->i_fop = &cifs_dir_ops;
+ } else if (S_ISLNK(tmp_inode->i_mode)) {
+ cFYI(1, ("Symbolic Link inode"));
+ tmp_inode->i_op = &cifs_symlink_inode_ops;
+/* tmp_inode->i_fop = *//* do not need to set to anything */
+ } else {
+ cFYI(1, ("Special inode"));
+ init_special_inode(tmp_inode, tmp_inode->i_mode,
+ tmp_inode->i_rdev);
+ }
+}
+
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
{
int rc = 0;
@@ -755,6 +896,71 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
FreeXid(xid);
return -ENOMEM;
}
+
+ if((pTcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+ u32 oplock = 0;
+ FILE_UNIX_BASIC_INFO * pInfo =
+ kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+ if(pInfo == NULL) {
+ rc = -ENOMEM;
+ goto mkdir_out;
+ }
+
+ rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
+ mode, NULL /* netfid */, pInfo, &oplock,
+ full_path, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
+ CIFS_MOUNT_MAP_SPECIAL_CHR);
+ if (rc) {
+ cFYI(1, ("posix mkdir returned 0x%x", rc));
+ d_drop(direntry);
+ } else {
+ int obj_type;
+ if (pInfo->Type == -1) /* no return info - go query */
+ goto mkdir_get_info;
+/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
+ inc_nlink(inode);
+ if (pTcon->nocase)
+ direntry->d_op = &cifs_ci_dentry_ops;
+ else
+ direntry->d_op = &cifs_dentry_ops;
+
+ newinode = new_inode(inode->i_sb);
+ if (newinode == NULL)
+ goto mkdir_get_info;
+ /* Is an i_ino of zero legal? */
+ /* Are there sanity checks we can use to ensure that
+ the server is really filling in that field? */
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ newinode->i_ino =
+ (unsigned long)pInfo->UniqueId;
+ } /* note ino incremented to unique num in new_inode */
+ if(inode->i_sb->s_flags & MS_NOATIME)
+ newinode->i_flags |= S_NOATIME | S_NOCMTIME;
+ newinode->i_nlink = 2;
+
+ insert_inode_hash(newinode);
+ d_instantiate(direntry, newinode);
+
+ /* we already checked in POSIXCreate whether
+ frame was long enough */
+ posix_fill_in_inode(direntry->d_inode,
+ pInfo, &obj_type, 1 /* NewInode */);
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1,("instantiated dentry %p %s to inode %p",
+ direntry, direntry->d_name.name, newinode));
+
+ if(newinode->i_nlink != 2)
+ cFYI(1,("unexpected number of links %d",
+ newinode->i_nlink));
+#endif
+ }
+ kfree(pInfo);
+ goto mkdir_out;
+ }
+
/* BB add setting the equivalent of mode via CreateX w/ACLs */
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -762,6 +968,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cFYI(1, ("cifs_mkdir returned 0x%x", rc));
d_drop(direntry);
} else {
+mkdir_get_info:
inc_nlink(inode);
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&newinode, full_path,
@@ -775,8 +982,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
else
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
- if (direntry->d_inode)
- direntry->d_inode->i_nlink = 2;
+ /* setting nlink not necessary except in cases where we
+ * failed to get it from the server or was set bogus */
+ if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
+ direntry->d_inode->i_nlink = 2;
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -812,6 +1021,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
}
}
}
+mkdir_out:
kfree(full_path);
FreeXid(xid);
return rc;
@@ -1339,17 +1549,17 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
cpu_to_le32(cifsInode->cifsAttrs |
ATTR_READONLY);
}
- } else if ((mode & S_IWUGO) == S_IWUGO) {
- if (cifsInode->cifsAttrs & ATTR_READONLY) {
- set_dosattr = TRUE;
- time_buf.Attributes =
- cpu_to_le32(cifsInode->cifsAttrs &
- (~ATTR_READONLY));
- /* Windows ignores set to zero */
- if(time_buf.Attributes == 0)
- time_buf.Attributes |=
- cpu_to_le32(ATTR_NORMAL);
- }
+ } else if (cifsInode->cifsAttrs & ATTR_READONLY) {
+ /* If file is readonly on server, we would
+ not be able to write to it - so if any write
+ bit is enabled for user or group or other we
+ need to at least try to remove r/o dos attr */
+ set_dosattr = TRUE;
+ time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
+ (~ATTR_READONLY));
+ /* Windows ignores set to zero */
+ if(time_buf.Attributes == 0)
+ time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
}
/* BB to be implemented -
via Windows security descriptors or streams */
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 992e80edc72..53e304d5954 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -30,6 +30,9 @@
#include <linux/fs.h>
#include <asm/div64.h>
#include <asm/byteorder.h>
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+#include <linux/inet.h>
+#endif
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
@@ -129,11 +132,27 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
/* Convert string containing dotted ip address to binary form */
/* returns 0 if invalid address */
-/* BB add address family, change rc to status flag and return union or for ipv6 */
-/* will need parent to call something like inet_pton to convert ipv6 address BB */
int
cifs_inet_pton(int address_family, char *cp,void *dst)
{
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+ int ret = 0;
+
+ /* calculate length by finding first slash or NULL */
+ /* BB Should we convert '/' slash to '\' here since it seems already done
+ before this */
+ if( address_family == AF_INET ){
+ ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
+ } else if( address_family == AF_INET6 ){
+ ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
+ }
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1,("address conversion returned %d for %s", ret, cp));
+#endif
+ if (ret > 0)
+ ret = 1;
+ return ret;
+#else
int value;
int digit;
int i;
@@ -192,6 +211,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst)
*((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
return 1; /* success */
+#endif /* EXPERIMENTAL */
}
/*****************************************************************************
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 2a374d5215a..c08bda9fcac 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -23,7 +23,6 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/stat.h>
-#include <linux/smp_lock.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
@@ -37,19 +36,19 @@ static void dump_cifs_file_struct(struct file *file, char *label)
{
struct cifsFileInfo * cf;
- if(file) {
+ if (file) {
cf = file->private_data;
- if(cf == NULL) {
+ if (cf == NULL) {
cFYI(1,("empty cifs private file data"));
return;
}
- if(cf->invalidHandle) {
+ if (cf->invalidHandle) {
cFYI(1,("invalid handle"));
}
- if(cf->srch_inf.endOfSearch) {
+ if (cf->srch_inf.endOfSearch) {
cFYI(1,("end of search"));
}
- if(cf->srch_inf.emptyDir) {
+ if (cf->srch_inf.emptyDir) {
cFYI(1,("empty dir"));
}
@@ -77,17 +76,17 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
- if(*ptmp_inode == NULL) {
+ if (*ptmp_inode == NULL) {
*ptmp_inode = new_inode(file->f_path.dentry->d_sb);
- if(*ptmp_inode == NULL)
+ if (*ptmp_inode == NULL)
return rc;
rc = 1;
}
- if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
+ if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
} else {
tmp_dentry = d_alloc(file->f_path.dentry, qstring);
- if(tmp_dentry == NULL) {
+ if (tmp_dentry == NULL) {
cERROR(1,("Failed allocating dentry"));
*ptmp_inode = NULL;
return rc;
@@ -98,9 +97,9 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
tmp_dentry->d_op = &cifs_ci_dentry_ops;
else
tmp_dentry->d_op = &cifs_dentry_ops;
- if(*ptmp_inode == NULL)
+ if (*ptmp_inode == NULL)
return rc;
- if(file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
+ if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
(*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
rc = 2;
}
@@ -112,7 +111,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
{
- if((tcon) && (tcon->ses) && (tcon->ses->server)) {
+ if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
@@ -137,7 +136,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
local_mtime = tmp_inode->i_mtime;
local_size = tmp_inode->i_size;
- if(new_buf_type) {
+ if (new_buf_type) {
FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf;
attr = le32_to_cpu(pfindData->ExtFileAttributes);
@@ -193,7 +192,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
if (attr & ATTR_DIRECTORY) {
*pobject_type = DT_DIR;
/* override default perms since we do not lock dirs */
- if(atomic_read(&cifsInfo->inUse) == 0) {
+ if (atomic_read(&cifsInfo->inUse) == 0) {
tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
}
tmp_inode->i_mode |= S_IFDIR;
@@ -250,25 +249,25 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_direct_ops;
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_ops;
- if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+ if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
- if(isNewInode)
+ if (isNewInode)
return; /* No sense invalidating pages for new inode
since have not started caching readahead file
data yet */
@@ -357,8 +356,14 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
cFYI(1,("unknown inode type %d",type));
}
- tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
- tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
+ tmp_inode->i_uid = cifs_sb->mnt_uid;
+ else
+ tmp_inode->i_uid = le64_to_cpu(pfindData->Uid);
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
+ tmp_inode->i_gid = cifs_sb->mnt_gid;
+ else
+ tmp_inode->i_gid = le64_to_cpu(pfindData->Gid);
tmp_inode->i_nlink = le64_to_cpu(pfindData->Nlinks);
spin_lock(&tmp_inode->i_lock);
@@ -377,25 +382,24 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_direct_ops;
-
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_ops;
- if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+ if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
(cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
- if(isNewInode)
+ if (isNewInode)
return; /* No sense invalidating pages for new inode since we
have not started caching readahead file data yet */
@@ -430,34 +434,28 @@ static int initiate_cifs_search(const int xid, struct file *file)
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- if(file->private_data == NULL) {
+ if (file->private_data == NULL) {
file->private_data =
- kmalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
+ kzalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
}
- if(file->private_data == NULL) {
+ if (file->private_data == NULL)
return -ENOMEM;
- } else {
- memset(file->private_data,0,sizeof(struct cifsFileInfo));
- }
cifsFile = file->private_data;
cifsFile->invalidHandle = TRUE;
cifsFile->srch_inf.endOfSearch = FALSE;
- if(file->f_path.dentry == NULL)
- return -ENOENT;
-
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
- if(cifs_sb == NULL)
+ if (cifs_sb == NULL)
return -EINVAL;
pTcon = cifs_sb->tcon;
- if(pTcon == NULL)
+ if (pTcon == NULL)
return -EINVAL;
full_path = build_path_from_dentry(file->f_path.dentry);
- if(full_path == NULL) {
+ if (full_path == NULL) {
return -ENOMEM;
}
@@ -480,9 +478,9 @@ ffirst_retry:
&cifsFile->netfid, &cifsFile->srch_inf,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
- if(rc == 0)
+ if (rc == 0)
cifsFile->invalidHandle = FALSE;
- if((rc == -EOPNOTSUPP) &&
+ if ((rc == -EOPNOTSUPP) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
goto ffirst_retry;
@@ -498,7 +496,7 @@ static int cifs_unicode_bytelen(char *str)
__le16 * ustr = (__le16 *)str;
for(len=0;len <= PATH_MAX;len++) {
- if(ustr[len] == 0)
+ if (ustr[len] == 0)
return len << 1;
}
cFYI(1,("Unicode string longer than PATH_MAX found"));
@@ -510,7 +508,7 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
char * new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
- if(level == SMB_FIND_FILE_INFO_STANDARD) {
+ if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pfData;
pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo;
@@ -520,12 +518,12 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
/* validate that new_entry is not past end of SMB */
- if(new_entry >= end_of_smb) {
+ if (new_entry >= end_of_smb) {
cERROR(1,
("search entry %p began after end of SMB %p old entry %p",
new_entry, end_of_smb, old_entry));
return NULL;
- } else if(((level == SMB_FIND_FILE_INFO_STANDARD) &&
+ } else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
((level != SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
@@ -546,39 +544,39 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
char * filename = NULL;
int len = 0;
- if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
+ if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
- if(cfile->srch_inf.unicode) {
+ if (cfile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename);
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, 5);
}
- } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
+ } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
FILE_DIRECTORY_INFO * pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level ==
+ } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
FILE_FULL_DIRECTORY_INFO * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level ==
+ } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_ID_FULL_DIR_INFO) {
SEARCH_ID_FULL_DIR_INFO * pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level ==
+ } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
FILE_BOTH_DIRECTORY_INFO * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
+ } else if (cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0];
@@ -587,25 +585,25 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
}
- if(filename) {
- if(cfile->srch_inf.unicode) {
+ if (filename) {
+ if (cfile->srch_inf.unicode) {
__le16 *ufilename = (__le16 *)filename;
- if(len == 2) {
+ if (len == 2) {
/* check for . */
- if(ufilename[0] == UNICODE_DOT)
+ if (ufilename[0] == UNICODE_DOT)
rc = 1;
- } else if(len == 4) {
+ } else if (len == 4) {
/* check for .. */
- if((ufilename[0] == UNICODE_DOT)
+ if ((ufilename[0] == UNICODE_DOT)
&&(ufilename[1] == UNICODE_DOT))
rc = 2;
}
} else /* ASCII */ {
- if(len == 1) {
- if(filename[0] == '.')
+ if (len == 1) {
+ if (filename[0] == '.')
rc = 1;
- } else if(len == 2) {
- if((filename[0] == '.') && (filename[1] == '.'))
+ } else if (len == 2) {
+ if((filename[0] == '.') && (filename[1] == '.'))
rc = 2;
}
}
@@ -618,20 +616,10 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
whether we can use the cached search results from the previous search */
static int is_dir_changed(struct file * file)
{
- struct inode * inode;
- struct cifsInodeInfo *cifsInfo;
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
- if(file->f_path.dentry == NULL)
- return 0;
-
- inode = file->f_path.dentry->d_inode;
-
- if(inode == NULL)
- return 0;
-
- cifsInfo = CIFS_I(inode);
-
- if(cifsInfo->time == 0)
+ if (cifsInfo->time == 0)
return 1; /* directory was changed, perhaps due to unlink */
else
return 0;
@@ -654,7 +642,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
struct cifsFileInfo * cifsFile = file->private_data;
/* check if index in the buffer */
- if((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
+ if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
(num_to_ret == NULL))
return -ENOENT;
@@ -672,7 +660,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
#ifdef CONFIG_CIFS_DEBUG2
dump_cifs_file_struct(file, "In fce ");
#endif
- if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
+ if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) {
/* close and restart search */
@@ -681,9 +669,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
CIFSFindClose(xid, pTcon, cifsFile->netfid);
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL;
- if(cifsFile->srch_inf.ntwrk_buf_start) {
+ if (cifsFile->srch_inf.ntwrk_buf_start) {
cFYI(1,("freeing SMB ff cache buf on search rewind"));
- if(cifsFile->srch_inf.smallBuf)
+ if (cifsFile->srch_inf.smallBuf)
cifs_small_buf_release(cifsFile->srch_inf.
ntwrk_buf_start);
else
@@ -691,7 +679,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
ntwrk_buf_start);
}
rc = initiate_cifs_search(xid,file);
- if(rc) {
+ if (rc) {
cFYI(1,("error %d reinitiating a search on rewind",rc));
return rc;
}
@@ -702,10 +690,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
cFYI(1,("calling findnext2"));
rc = CIFSFindNext(xid,pTcon,cifsFile->netfid,
&cifsFile->srch_inf);
- if(rc)
+ if (rc)
return -ENOENT;
}
- if(index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+ if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
/* we found the buffer that contains the entry */
/* scan and find it */
int i;
@@ -851,9 +839,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
return -ENOENT;
- if(file->f_path.dentry == NULL)
- return -ENOENT;
-
rc = cifs_entry_is_dot(pfindEntry,pCifsF);
/* skip . and .. since we added them first */
if(rc != 0)
@@ -997,11 +982,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
xid = GetXid();
- if(file->f_path.dentry == NULL) {
- FreeXid(xid);
- return -EIO;
- }
-
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
if(pTcon == NULL)
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 614175a3b02..0aaff3651d1 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -62,8 +62,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct coda_inode_info *ei = (struct coda_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/compat.c b/fs/compat.c
index 040a8be38a4..9cf75df9b2b 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -15,6 +15,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/kernel.h>
#include <linux/linkage.h>
#include <linux/compat.h>
#include <linux/errno.h>
@@ -24,10 +25,8 @@
#include <linux/namei.h>
#include <linux/file.h>
#include <linux/vfs.h>
-#include <linux/ioctl32.h>
#include <linux/ioctl.h>
#include <linux/init.h>
-#include <linux/sockios.h> /* for SIOCDEVPRIVATE */
#include <linux/smb.h>
#include <linux/smb_mount.h>
#include <linux/ncp_mount.h>
@@ -45,13 +44,12 @@
#include <linux/personality.h>
#include <linux/rwsem.h>
#include <linux/tsacct_kern.h>
+#include <linux/security.h>
#include <linux/highmem.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/eventpoll.h>
-#include <net/sock.h> /* siocdevprivate_ioctl */
-
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/ioctls.h>
@@ -79,30 +77,57 @@ int compat_printk(const char *fmt, ...)
*/
asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t)
{
- struct timeval tv[2];
+ struct timespec tv[2];
if (t) {
if (get_user(tv[0].tv_sec, &t->actime) ||
get_user(tv[1].tv_sec, &t->modtime))
return -EFAULT;
- tv[0].tv_usec = 0;
- tv[1].tv_usec = 0;
+ tv[0].tv_nsec = 0;
+ tv[1].tv_nsec = 0;
+ }
+ return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0);
+}
+
+asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename, struct compat_timespec __user *t, int flags)
+{
+ struct timespec tv[2];
+
+ if (t) {
+ if (get_compat_timespec(&tv[0], &t[0]) ||
+ get_compat_timespec(&tv[1], &t[1]))
+ return -EFAULT;
+
+ if ((tv[0].tv_nsec == UTIME_OMIT || tv[0].tv_nsec == UTIME_NOW)
+ && tv[0].tv_sec != 0)
+ return -EINVAL;
+ if ((tv[1].tv_nsec == UTIME_OMIT || tv[1].tv_nsec == UTIME_NOW)
+ && tv[1].tv_sec != 0)
+ return -EINVAL;
+
+ if (tv[0].tv_nsec == UTIME_OMIT && tv[1].tv_nsec == UTIME_OMIT)
+ return 0;
}
- return do_utimes(AT_FDCWD, filename, t ? tv : NULL);
+ return do_utimes(dfd, filename, t ? tv : NULL, flags);
}
asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, struct compat_timeval __user *t)
{
- struct timeval tv[2];
+ struct timespec tv[2];
if (t) {
if (get_user(tv[0].tv_sec, &t[0].tv_sec) ||
- get_user(tv[0].tv_usec, &t[0].tv_usec) ||
+ get_user(tv[0].tv_nsec, &t[0].tv_usec) ||
get_user(tv[1].tv_sec, &t[1].tv_sec) ||
- get_user(tv[1].tv_usec, &t[1].tv_usec))
+ get_user(tv[1].tv_nsec, &t[1].tv_usec))
return -EFAULT;
+ if (tv[0].tv_nsec >= 1000000 || tv[0].tv_nsec < 0 ||
+ tv[1].tv_nsec >= 1000000 || tv[1].tv_nsec < 0)
+ return -EINVAL;
+ tv[0].tv_nsec *= 1000;
+ tv[1].tv_nsec *= 1000;
}
- return do_utimes(dfd, filename, t ? tv : NULL);
+ return do_utimes(dfd, filename, t ? tv : NULL, 0);
}
asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
@@ -312,162 +337,6 @@ out:
return error;
}
-/* ioctl32 stuff, used by sparc64, parisc, s390x, ppc64, x86_64, MIPS */
-
-#define IOCTL_HASHSIZE 256
-static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
-
-static inline unsigned long ioctl32_hash(unsigned long cmd)
-{
- return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
-}
-
-static void ioctl32_insert_translation(struct ioctl_trans *trans)
-{
- unsigned long hash;
- struct ioctl_trans *t;
-
- hash = ioctl32_hash (trans->cmd);
- if (!ioctl32_hash_table[hash])
- ioctl32_hash_table[hash] = trans;
- else {
- t = ioctl32_hash_table[hash];
- while (t->next)
- t = t->next;
- trans->next = NULL;
- t->next = trans;
- }
-}
-
-static int __init init_sys32_ioctl(void)
-{
- int i;
-
- for (i = 0; i < ioctl_table_size; i++) {
- if (ioctl_start[i].next != 0) {
- printk("ioctl translation %d bad\n",i);
- return -1;
- }
-
- ioctl32_insert_translation(&ioctl_start[i]);
- }
- return 0;
-}
-
-__initcall(init_sys32_ioctl);
-
-static void compat_ioctl_error(struct file *filp, unsigned int fd,
- unsigned int cmd, unsigned long arg)
-{
- char buf[10];
- char *fn = "?";
- char *path;
-
- /* find the name of the device. */
- path = (char *)__get_free_page(GFP_KERNEL);
- if (path) {
- fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
- if (IS_ERR(fn))
- fn = "?";
- }
-
- sprintf(buf,"'%c'", (cmd>>24) & 0x3f);
- if (!isprint(buf[1]))
- sprintf(buf, "%02x", buf[1]);
- compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
- "cmd(%08x){%s} arg(%08x) on %s\n",
- current->comm, current->pid,
- (int)fd, (unsigned int)cmd, buf,
- (unsigned int)arg, fn);
-
- if (path)
- free_page((unsigned long)path);
-}
-
-asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
- unsigned long arg)
-{
- struct file *filp;
- int error = -EBADF;
- struct ioctl_trans *t;
- int fput_needed;
-
- filp = fget_light(fd, &fput_needed);
- if (!filp)
- goto out;
-
- /* RED-PEN how should LSM module know it's handling 32bit? */
- error = security_file_ioctl(filp, cmd, arg);
- if (error)
- goto out_fput;
-
- /*
- * To allow the compat_ioctl handlers to be self contained
- * we need to check the common ioctls here first.
- * Just handle them with the standard handlers below.
- */
- switch (cmd) {
- case FIOCLEX:
- case FIONCLEX:
- case FIONBIO:
- case FIOASYNC:
- case FIOQSIZE:
- break;
-
- case FIBMAP:
- case FIGETBSZ:
- case FIONREAD:
- if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
- break;
- /*FALL THROUGH*/
-
- default:
- if (filp->f_op && filp->f_op->compat_ioctl) {
- error = filp->f_op->compat_ioctl(filp, cmd, arg);
- if (error != -ENOIOCTLCMD)
- goto out_fput;
- }
-
- if (!filp->f_op ||
- (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl))
- goto do_ioctl;
- break;
- }
-
- for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
- if (t->cmd == cmd)
- goto found_handler;
- }
-
- if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
- cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
- error = siocdevprivate_ioctl(fd, cmd, arg);
- } else {
- static int count;
-
- if (++count <= 50)
- compat_ioctl_error(filp, fd, cmd, arg);
- error = -EINVAL;
- }
-
- goto out_fput;
-
- found_handler:
- if (t->handler) {
- lock_kernel();
- error = t->handler(fd, cmd, arg, filp);
- unlock_kernel();
- goto out_fput;
- }
-
- do_ioctl:
- error = vfs_ioctl(filp, fd, cmd, arg);
- out_fput:
- fput_light(filp, fput_needed);
- out:
- return error;
-}
-
static int get_compat_flock(struct flock *kfl, struct compat_flock __user *ufl)
{
if (!access_ok(VERIFY_READ, ufl, sizeof(*ufl)) ||
@@ -901,8 +770,6 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name,
}
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define COMPAT_ROUND_UP(x) (((x)+sizeof(compat_long_t)-1) & \
- ~(sizeof(compat_long_t)-1))
struct compat_old_linux_dirent {
compat_ulong_t d_ino;
@@ -990,7 +857,7 @@ static int compat_filldir(void *__buf, const char *name, int namlen,
struct compat_linux_dirent __user * dirent;
struct compat_getdents_callback *buf = __buf;
compat_ulong_t d_ino;
- int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
+ int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(compat_long_t));
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
@@ -1065,7 +932,6 @@ out:
}
#ifndef __ARCH_OMIT_COMPAT_SYS_GETDENTS64
-#define COMPAT_ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
struct compat_getdents_callback64 {
struct linux_dirent64 __user *current_dir;
@@ -1080,7 +946,7 @@ static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t
struct linux_dirent64 __user *dirent;
struct compat_getdents_callback64 *buf = __buf;
int jj = NAME_OFFSET(dirent);
- int reclen = COMPAT_ROUND_UP64(jj + namlen + 1);
+ int reclen = ALIGN(jj + namlen + 1, sizeof(u64));
u64 off;
buf->error = -EINVAL; /* only used if we fail.. */
@@ -1593,8 +1459,6 @@ out_ret:
#define __COMPAT_NFDBITS (8 * sizeof(compat_ulong_t))
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
/*
* Ooo, nasty. We need here to frob 32-bit unsigned longs to
* 64-bit unsigned longs.
@@ -1603,7 +1467,7 @@ static
int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
unsigned long *fdset)
{
- nr = ROUND_UP(nr, __COMPAT_NFDBITS);
+ nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
if (ufdset) {
unsigned long odd;
@@ -1637,7 +1501,7 @@ int compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
unsigned long *fdset)
{
unsigned long odd;
- nr = ROUND_UP(nr, __COMPAT_NFDBITS);
+ nr = DIV_ROUND_UP(nr, __COMPAT_NFDBITS);
if (!ufdset)
return 0;
@@ -1759,7 +1623,7 @@ asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
timeout = -1; /* infinite */
else {
- timeout = ROUND_UP(tv.tv_usec, 1000000/HZ);
+ timeout = DIV_ROUND_UP(tv.tv_usec, 1000000/HZ);
timeout += tv.tv_sec * HZ;
}
}
@@ -1827,7 +1691,7 @@ asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
do {
if (tsp) {
if ((unsigned long)ts.tv_sec < MAX_SELECT_SECONDS) {
- timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
+ timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
timeout += ts.tv_sec * (unsigned long)HZ;
ts.tv_sec = 0;
ts.tv_nsec = 0;
@@ -1923,7 +1787,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
/* We assume that ts.tv_sec is always lower than
the number of seconds that can be expressed in
an s64. Otherwise the compiler bitches at us */
- timeout = ROUND_UP(ts.tv_nsec, 1000000000/HZ);
+ timeout = DIV_ROUND_UP(ts.tv_nsec, 1000000000/HZ);
timeout += ts.tv_sec * HZ;
}
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index c68b055fa26..d92bc3eb7af 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -17,7 +17,6 @@
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ioctl.h>
#include <linux/if.h>
#include <linux/if_bridge.h>
@@ -58,7 +57,6 @@
#include <linux/serial.h>
#include <linux/if_tun.h>
#include <linux/ctype.h>
-#include <linux/ioctl32.h>
#include <linux/syscalls.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
@@ -66,7 +64,6 @@
#include <linux/atalk.h>
#include <linux/blktrace_api.h>
-#include <net/sock.h> /* siocdevprivate_ioctl */
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
#include <net/bluetooth/rfcomm.h>
@@ -475,7 +472,7 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
};
}
-int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct ifreq __user *u_ifreq64;
struct ifreq32 __user *u_ifreq32 = compat_ptr(arg);
@@ -687,8 +684,10 @@ static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg)
if (!err) {
err = copy_to_user (ugeo, &geo, 4);
err |= __put_user (geo.start, &ugeo->start);
+ if (err)
+ err = -EFAULT;
}
- return err ? -EFAULT : 0;
+ return err;
}
static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -2385,6 +2384,16 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
return sys_ioctl(fd, cmd, (unsigned long)tn);
}
+
+typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
+ unsigned long, struct file *);
+
+struct ioctl_trans {
+ unsigned long cmd;
+ ioctl_trans_handler_t handler;
+ struct ioctl_trans *next;
+};
+
#define HANDLE_IOCTL(cmd,handler) \
{ (cmd), (ioctl_trans_handler_t)(handler) },
@@ -2396,9 +2405,844 @@ lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
#define ULONG_IOCTL(cmd) \
{ (cmd), (ioctl_trans_handler_t)sys_ioctl },
-
-struct ioctl_trans ioctl_start[] = {
-#include <linux/compat_ioctl.h>
+/* ioctl should not be warned about even if it's not implemented.
+ Valid reasons to use this:
+ - It is implemented with ->compat_ioctl on some device, but programs
+ call it on others too.
+ - The ioctl is not implemented in the native kernel, but programs
+ call it commonly anyways.
+ Most other reasons are not valid. */
+#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
+
+static struct ioctl_trans ioctl_start[] = {
+/* compatible ioctls first */
+COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
+COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
+
+/* Big T */
+COMPATIBLE_IOCTL(TCGETA)
+COMPATIBLE_IOCTL(TCSETA)
+COMPATIBLE_IOCTL(TCSETAW)
+COMPATIBLE_IOCTL(TCSETAF)
+COMPATIBLE_IOCTL(TCSBRK)
+ULONG_IOCTL(TCSBRKP)
+COMPATIBLE_IOCTL(TCXONC)
+COMPATIBLE_IOCTL(TCFLSH)
+COMPATIBLE_IOCTL(TCGETS)
+COMPATIBLE_IOCTL(TCSETS)
+COMPATIBLE_IOCTL(TCSETSW)
+COMPATIBLE_IOCTL(TCSETSF)
+COMPATIBLE_IOCTL(TIOCLINUX)
+COMPATIBLE_IOCTL(TIOCSBRK)
+COMPATIBLE_IOCTL(TIOCCBRK)
+ULONG_IOCTL(TIOCMIWAIT)
+COMPATIBLE_IOCTL(TIOCGICOUNT)
+/* Little t */
+COMPATIBLE_IOCTL(TIOCGETD)
+COMPATIBLE_IOCTL(TIOCSETD)
+COMPATIBLE_IOCTL(TIOCEXCL)
+COMPATIBLE_IOCTL(TIOCNXCL)
+COMPATIBLE_IOCTL(TIOCCONS)
+COMPATIBLE_IOCTL(TIOCGSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSSOFTCAR)
+COMPATIBLE_IOCTL(TIOCSWINSZ)
+COMPATIBLE_IOCTL(TIOCGWINSZ)
+COMPATIBLE_IOCTL(TIOCMGET)
+COMPATIBLE_IOCTL(TIOCMBIC)
+COMPATIBLE_IOCTL(TIOCMBIS)
+COMPATIBLE_IOCTL(TIOCMSET)
+COMPATIBLE_IOCTL(TIOCPKT)
+COMPATIBLE_IOCTL(TIOCNOTTY)
+COMPATIBLE_IOCTL(TIOCSTI)
+COMPATIBLE_IOCTL(TIOCOUTQ)
+COMPATIBLE_IOCTL(TIOCSPGRP)
+COMPATIBLE_IOCTL(TIOCGPGRP)
+ULONG_IOCTL(TIOCSCTTY)
+COMPATIBLE_IOCTL(TIOCGPTN)
+COMPATIBLE_IOCTL(TIOCSPTLCK)
+COMPATIBLE_IOCTL(TIOCSERGETLSR)
+/* Little f */
+COMPATIBLE_IOCTL(FIOCLEX)
+COMPATIBLE_IOCTL(FIONCLEX)
+COMPATIBLE_IOCTL(FIOASYNC)
+COMPATIBLE_IOCTL(FIONBIO)
+COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */
+/* 0x00 */
+COMPATIBLE_IOCTL(FIBMAP)
+COMPATIBLE_IOCTL(FIGETBSZ)
+/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
+ * Some need translations, these do not.
+ */
+COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
+COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
+COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+ULONG_IOCTL(HDIO_SET_MULTCOUNT)
+ULONG_IOCTL(HDIO_SET_UNMASKINTR)
+ULONG_IOCTL(HDIO_SET_KEEPSETTINGS)
+ULONG_IOCTL(HDIO_SET_32BIT)
+ULONG_IOCTL(HDIO_SET_NOWERR)
+ULONG_IOCTL(HDIO_SET_DMA)
+ULONG_IOCTL(HDIO_SET_PIO_MODE)
+ULONG_IOCTL(HDIO_SET_NICE)
+ULONG_IOCTL(HDIO_SET_WCACHE)
+ULONG_IOCTL(HDIO_SET_ACOUSTIC)
+ULONG_IOCTL(HDIO_SET_BUSSTATE)
+ULONG_IOCTL(HDIO_SET_ADDRESS)
+COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
+/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
+COMPATIBLE_IOCTL(0x330)
+/* 0x02 -- Floppy ioctls */
+COMPATIBLE_IOCTL(FDMSGON)
+COMPATIBLE_IOCTL(FDMSGOFF)
+COMPATIBLE_IOCTL(FDSETEMSGTRESH)
+COMPATIBLE_IOCTL(FDFLUSH)
+COMPATIBLE_IOCTL(FDWERRORCLR)
+COMPATIBLE_IOCTL(FDSETMAXERRS)
+COMPATIBLE_IOCTL(FDGETMAXERRS)
+COMPATIBLE_IOCTL(FDGETDRVTYP)
+COMPATIBLE_IOCTL(FDEJECT)
+COMPATIBLE_IOCTL(FDCLRPRM)
+COMPATIBLE_IOCTL(FDFMTBEG)
+COMPATIBLE_IOCTL(FDFMTEND)
+COMPATIBLE_IOCTL(FDRESET)
+COMPATIBLE_IOCTL(FDTWADDLE)
+COMPATIBLE_IOCTL(FDFMTTRK)
+COMPATIBLE_IOCTL(FDRAWCMD)
+/* 0x12 */
+#ifdef CONFIG_BLOCK
+COMPATIBLE_IOCTL(BLKRASET)
+COMPATIBLE_IOCTL(BLKROSET)
+COMPATIBLE_IOCTL(BLKROGET)
+COMPATIBLE_IOCTL(BLKRRPART)
+COMPATIBLE_IOCTL(BLKFLSBUF)
+COMPATIBLE_IOCTL(BLKSECTSET)
+COMPATIBLE_IOCTL(BLKSSZGET)
+COMPATIBLE_IOCTL(BLKTRACESTART)
+COMPATIBLE_IOCTL(BLKTRACESTOP)
+COMPATIBLE_IOCTL(BLKTRACESETUP)
+COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
+ULONG_IOCTL(BLKRASET)
+ULONG_IOCTL(BLKFRASET)
+#endif
+/* RAID */
+COMPATIBLE_IOCTL(RAID_VERSION)
+COMPATIBLE_IOCTL(GET_ARRAY_INFO)
+COMPATIBLE_IOCTL(GET_DISK_INFO)
+COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
+COMPATIBLE_IOCTL(RAID_AUTORUN)
+COMPATIBLE_IOCTL(CLEAR_ARRAY)
+COMPATIBLE_IOCTL(ADD_NEW_DISK)
+ULONG_IOCTL(HOT_REMOVE_DISK)
+COMPATIBLE_IOCTL(SET_ARRAY_INFO)
+COMPATIBLE_IOCTL(SET_DISK_INFO)
+COMPATIBLE_IOCTL(WRITE_RAID_INFO)
+COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
+COMPATIBLE_IOCTL(PROTECT_ARRAY)
+ULONG_IOCTL(HOT_ADD_DISK)
+ULONG_IOCTL(SET_DISK_FAULTY)
+COMPATIBLE_IOCTL(RUN_ARRAY)
+COMPATIBLE_IOCTL(STOP_ARRAY)
+COMPATIBLE_IOCTL(STOP_ARRAY_RO)
+COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
+COMPATIBLE_IOCTL(GET_BITMAP_FILE)
+ULONG_IOCTL(SET_BITMAP_FILE)
+/* DM */
+COMPATIBLE_IOCTL(DM_VERSION_32)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL_32)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES_32)
+COMPATIBLE_IOCTL(DM_DEV_CREATE_32)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE_32)
+COMPATIBLE_IOCTL(DM_DEV_RENAME_32)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND_32)
+COMPATIBLE_IOCTL(DM_DEV_STATUS_32)
+COMPATIBLE_IOCTL(DM_DEV_WAIT_32)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD_32)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR_32)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS_32)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
+COMPATIBLE_IOCTL(DM_TARGET_MSG_32)
+COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32)
+COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
+COMPATIBLE_IOCTL(DM_LIST_DEVICES)
+COMPATIBLE_IOCTL(DM_DEV_CREATE)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE)
+COMPATIBLE_IOCTL(DM_DEV_RENAME)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
+COMPATIBLE_IOCTL(DM_DEV_STATUS)
+COMPATIBLE_IOCTL(DM_DEV_WAIT)
+COMPATIBLE_IOCTL(DM_TABLE_LOAD)
+COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
+COMPATIBLE_IOCTL(DM_TABLE_DEPS)
+COMPATIBLE_IOCTL(DM_TABLE_STATUS)
+COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
+COMPATIBLE_IOCTL(DM_TARGET_MSG)
+COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY)
+/* Big K */
+COMPATIBLE_IOCTL(PIO_FONT)
+COMPATIBLE_IOCTL(GIO_FONT)
+ULONG_IOCTL(KDSIGACCEPT)
+COMPATIBLE_IOCTL(KDGETKEYCODE)
+COMPATIBLE_IOCTL(KDSETKEYCODE)
+ULONG_IOCTL(KIOCSOUND)
+ULONG_IOCTL(KDMKTONE)
+COMPATIBLE_IOCTL(KDGKBTYPE)
+ULONG_IOCTL(KDSETMODE)
+COMPATIBLE_IOCTL(KDGETMODE)
+ULONG_IOCTL(KDSKBMODE)
+COMPATIBLE_IOCTL(KDGKBMODE)
+ULONG_IOCTL(KDSKBMETA)
+COMPATIBLE_IOCTL(KDGKBMETA)
+COMPATIBLE_IOCTL(KDGKBENT)
+COMPATIBLE_IOCTL(KDSKBENT)
+COMPATIBLE_IOCTL(KDGKBSENT)
+COMPATIBLE_IOCTL(KDSKBSENT)
+COMPATIBLE_IOCTL(KDGKBDIACR)
+COMPATIBLE_IOCTL(KDSKBDIACR)
+COMPATIBLE_IOCTL(KDKBDREP)
+COMPATIBLE_IOCTL(KDGKBLED)
+ULONG_IOCTL(KDSKBLED)
+COMPATIBLE_IOCTL(KDGETLED)
+ULONG_IOCTL(KDSETLED)
+COMPATIBLE_IOCTL(GIO_SCRNMAP)
+COMPATIBLE_IOCTL(PIO_SCRNMAP)
+COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
+COMPATIBLE_IOCTL(PIO_FONTRESET)
+COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
+/* Big S */
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
+COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
+COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
+COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
+COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
+/* Big T */
+COMPATIBLE_IOCTL(TUNSETNOCSUM)
+COMPATIBLE_IOCTL(TUNSETDEBUG)
+COMPATIBLE_IOCTL(TUNSETPERSIST)
+COMPATIBLE_IOCTL(TUNSETOWNER)
+/* Big V */
+COMPATIBLE_IOCTL(VT_SETMODE)
+COMPATIBLE_IOCTL(VT_GETMODE)
+COMPATIBLE_IOCTL(VT_GETSTATE)
+COMPATIBLE_IOCTL(VT_OPENQRY)
+ULONG_IOCTL(VT_ACTIVATE)
+ULONG_IOCTL(VT_WAITACTIVE)
+ULONG_IOCTL(VT_RELDISP)
+ULONG_IOCTL(VT_DISALLOCATE)
+COMPATIBLE_IOCTL(VT_RESIZE)
+COMPATIBLE_IOCTL(VT_RESIZEX)
+COMPATIBLE_IOCTL(VT_LOCKSWITCH)
+COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
+COMPATIBLE_IOCTL(VT_GETHIFONTMASK)
+/* Little p (/dev/rtc, /dev/envctrl, etc.) */
+COMPATIBLE_IOCTL(RTC_AIE_ON)
+COMPATIBLE_IOCTL(RTC_AIE_OFF)
+COMPATIBLE_IOCTL(RTC_UIE_ON)
+COMPATIBLE_IOCTL(RTC_UIE_OFF)
+COMPATIBLE_IOCTL(RTC_PIE_ON)
+COMPATIBLE_IOCTL(RTC_PIE_OFF)
+COMPATIBLE_IOCTL(RTC_WIE_ON)
+COMPATIBLE_IOCTL(RTC_WIE_OFF)
+COMPATIBLE_IOCTL(RTC_ALM_SET)
+COMPATIBLE_IOCTL(RTC_ALM_READ)
+COMPATIBLE_IOCTL(RTC_RD_TIME)
+COMPATIBLE_IOCTL(RTC_SET_TIME)
+COMPATIBLE_IOCTL(RTC_WKALM_SET)
+COMPATIBLE_IOCTL(RTC_WKALM_RD)
+/*
+ * These two are only for the sbus rtc driver, but
+ * hwclock tries them on every rtc device first when
+ * running on sparc. On other architectures the entries
+ * are useless but harmless.
+ */
+COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
+COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
+/* Little m */
+COMPATIBLE_IOCTL(MTIOCTOP)
+/* Socket level stuff */
+COMPATIBLE_IOCTL(FIOQSIZE)
+COMPATIBLE_IOCTL(FIOSETOWN)
+COMPATIBLE_IOCTL(SIOCSPGRP)
+COMPATIBLE_IOCTL(FIOGETOWN)
+COMPATIBLE_IOCTL(SIOCGPGRP)
+COMPATIBLE_IOCTL(SIOCATMARK)
+COMPATIBLE_IOCTL(SIOCSIFLINK)
+COMPATIBLE_IOCTL(SIOCSIFENCAP)
+COMPATIBLE_IOCTL(SIOCGIFENCAP)
+COMPATIBLE_IOCTL(SIOCSIFNAME)
+COMPATIBLE_IOCTL(SIOCSARP)
+COMPATIBLE_IOCTL(SIOCGARP)
+COMPATIBLE_IOCTL(SIOCDARP)
+COMPATIBLE_IOCTL(SIOCSRARP)
+COMPATIBLE_IOCTL(SIOCGRARP)
+COMPATIBLE_IOCTL(SIOCDRARP)
+COMPATIBLE_IOCTL(SIOCADDDLCI)
+COMPATIBLE_IOCTL(SIOCDELDLCI)
+COMPATIBLE_IOCTL(SIOCGMIIPHY)
+COMPATIBLE_IOCTL(SIOCGMIIREG)
+COMPATIBLE_IOCTL(SIOCSMIIREG)
+COMPATIBLE_IOCTL(SIOCGIFVLAN)
+COMPATIBLE_IOCTL(SIOCSIFVLAN)
+COMPATIBLE_IOCTL(SIOCBRADDBR)
+COMPATIBLE_IOCTL(SIOCBRDELBR)
+/* SG stuff */
+COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
+COMPATIBLE_IOCTL(SG_EMULATED_HOST)
+ULONG_IOCTL(SG_SET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
+COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
+COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
+COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
+COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
+COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_PACK_ID)
+COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
+COMPATIBLE_IOCTL(SG_SET_DEBUG)
+COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
+COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
+COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
+COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
+COMPATIBLE_IOCTL(SG_SCSI_RESET)
+COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
+COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
+COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
+/* PPP stuff */
+COMPATIBLE_IOCTL(PPPIOCGFLAGS)
+COMPATIBLE_IOCTL(PPPIOCSFLAGS)
+COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGUNIT)
+COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCGMRU)
+COMPATIBLE_IOCTL(PPPIOCSMRU)
+COMPATIBLE_IOCTL(PPPIOCSMAXCID)
+COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
+COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
+/* PPPIOCSCOMPRESS is translated */
+COMPATIBLE_IOCTL(PPPIOCGNPMODE)
+COMPATIBLE_IOCTL(PPPIOCSNPMODE)
+COMPATIBLE_IOCTL(PPPIOCGDEBUG)
+COMPATIBLE_IOCTL(PPPIOCSDEBUG)
+/* PPPIOCSPASS is translated */
+/* PPPIOCSACTIVE is translated */
+/* PPPIOCGIDLE is translated */
+COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
+COMPATIBLE_IOCTL(PPPIOCATTACH)
+COMPATIBLE_IOCTL(PPPIOCDETACH)
+COMPATIBLE_IOCTL(PPPIOCSMRRU)
+COMPATIBLE_IOCTL(PPPIOCCONNECT)
+COMPATIBLE_IOCTL(PPPIOCDISCONN)
+COMPATIBLE_IOCTL(PPPIOCATTCHAN)
+COMPATIBLE_IOCTL(PPPIOCGCHAN)
+/* PPPOX */
+COMPATIBLE_IOCTL(PPPOEIOCSFWD)
+COMPATIBLE_IOCTL(PPPOEIOCDFWD)
+/* LP */
+COMPATIBLE_IOCTL(LPGETSTATUS)
+/* ppdev */
+COMPATIBLE_IOCTL(PPSETMODE)
+COMPATIBLE_IOCTL(PPRSTATUS)
+COMPATIBLE_IOCTL(PPRCONTROL)
+COMPATIBLE_IOCTL(PPWCONTROL)
+COMPATIBLE_IOCTL(PPFCONTROL)
+COMPATIBLE_IOCTL(PPRDATA)
+COMPATIBLE_IOCTL(PPWDATA)
+COMPATIBLE_IOCTL(PPCLAIM)
+COMPATIBLE_IOCTL(PPRELEASE)
+COMPATIBLE_IOCTL(PPYIELD)
+COMPATIBLE_IOCTL(PPEXCL)
+COMPATIBLE_IOCTL(PPDATADIR)
+COMPATIBLE_IOCTL(PPNEGOT)
+COMPATIBLE_IOCTL(PPWCTLONIRQ)
+COMPATIBLE_IOCTL(PPCLRIRQ)
+COMPATIBLE_IOCTL(PPSETPHASE)
+COMPATIBLE_IOCTL(PPGETMODES)
+COMPATIBLE_IOCTL(PPGETMODE)
+COMPATIBLE_IOCTL(PPGETPHASE)
+COMPATIBLE_IOCTL(PPGETFLAGS)
+COMPATIBLE_IOCTL(PPSETFLAGS)
+/* CDROM stuff */
+COMPATIBLE_IOCTL(CDROMPAUSE)
+COMPATIBLE_IOCTL(CDROMRESUME)
+COMPATIBLE_IOCTL(CDROMPLAYMSF)
+COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
+COMPATIBLE_IOCTL(CDROMREADTOCHDR)
+COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
+COMPATIBLE_IOCTL(CDROMSTOP)
+COMPATIBLE_IOCTL(CDROMSTART)
+COMPATIBLE_IOCTL(CDROMEJECT)
+COMPATIBLE_IOCTL(CDROMVOLCTRL)
+COMPATIBLE_IOCTL(CDROMSUBCHNL)
+ULONG_IOCTL(CDROMEJECT_SW)
+COMPATIBLE_IOCTL(CDROMMULTISESSION)
+COMPATIBLE_IOCTL(CDROM_GET_MCN)
+COMPATIBLE_IOCTL(CDROMRESET)
+COMPATIBLE_IOCTL(CDROMVOLREAD)
+COMPATIBLE_IOCTL(CDROMSEEK)
+COMPATIBLE_IOCTL(CDROMPLAYBLK)
+COMPATIBLE_IOCTL(CDROMCLOSETRAY)
+ULONG_IOCTL(CDROM_SET_OPTIONS)
+ULONG_IOCTL(CDROM_CLEAR_OPTIONS)
+ULONG_IOCTL(CDROM_SELECT_SPEED)
+ULONG_IOCTL(CDROM_SELECT_DISC)
+ULONG_IOCTL(CDROM_MEDIA_CHANGED)
+ULONG_IOCTL(CDROM_DRIVE_STATUS)
+COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
+COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
+ULONG_IOCTL(CDROM_LOCKDOOR)
+ULONG_IOCTL(CDROM_DEBUG)
+COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
+/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
+ * not take a struct cdrom_read, instead they take a struct cdrom_msf
+ * which is compatible.
+ */
+COMPATIBLE_IOCTL(CDROMREADMODE2)
+COMPATIBLE_IOCTL(CDROMREADMODE1)
+COMPATIBLE_IOCTL(CDROMREADRAW)
+COMPATIBLE_IOCTL(CDROMREADCOOKED)
+COMPATIBLE_IOCTL(CDROMREADALL)
+/* DVD ioctls */
+COMPATIBLE_IOCTL(DVD_READ_STRUCT)
+COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
+COMPATIBLE_IOCTL(DVD_AUTH)
+/* pktcdvd */
+COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
+/* Big A */
+/* sparc only */
+/* Big Q for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
+COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
+COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
+COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
+COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
+/* Big T for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_START)
+COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
+COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
+COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
+COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
+/* Little m for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
+COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
+/* Big P for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
+COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
+COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
+/* SNDCTL_DSP_MAPINBUF, XXX needs translation */
+/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
+COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
+COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
+COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
+COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
+/* Big C for sound/OSS */
+COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
+COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
+COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
+COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
+COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
+COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
+/* Big M for sound/OSS */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
+/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */
+/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
+COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
+COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
+/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */
+/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */
+COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
+COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
+COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
+COMPATIBLE_IOCTL(SOUND_MIXER_AGC)
+COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
+COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
+COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
+COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
+COMPATIBLE_IOCTL(OSS_GETVERSION)
+/* AUTOFS */
+ULONG_IOCTL(AUTOFS_IOC_READY)
+ULONG_IOCTL(AUTOFS_IOC_FAIL)
+COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
+COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
+COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
+COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
+/* Raw devices */
+COMPATIBLE_IOCTL(RAW_SETBIND)
+COMPATIBLE_IOCTL(RAW_GETBIND)
+/* SMB ioctls which do not need any translations */
+COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
+/* Little a */
+COMPATIBLE_IOCTL(ATMSIGD_CTRL)
+COMPATIBLE_IOCTL(ATMARPD_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_CTRL)
+COMPATIBLE_IOCTL(ATMLEC_MCAST)
+COMPATIBLE_IOCTL(ATMLEC_DATA)
+COMPATIBLE_IOCTL(ATM_SETSC)
+COMPATIBLE_IOCTL(SIOCSIFATMTCP)
+COMPATIBLE_IOCTL(SIOCMKCLIP)
+COMPATIBLE_IOCTL(ATMARP_MKIP)
+COMPATIBLE_IOCTL(ATMARP_SETENTRY)
+COMPATIBLE_IOCTL(ATMARP_ENCAP)
+COMPATIBLE_IOCTL(ATMTCP_CREATE)
+COMPATIBLE_IOCTL(ATMTCP_REMOVE)
+COMPATIBLE_IOCTL(ATMMPC_CTRL)
+COMPATIBLE_IOCTL(ATMMPC_DATA)
+/* Watchdog */
+COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
+COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
+COMPATIBLE_IOCTL(WDIOC_GETTEMP)
+COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
+COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
+COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT)
+COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT)
+/* Big R */
+COMPATIBLE_IOCTL(RNDGETENTCNT)
+COMPATIBLE_IOCTL(RNDADDTOENTCNT)
+COMPATIBLE_IOCTL(RNDGETPOOL)
+COMPATIBLE_IOCTL(RNDADDENTROPY)
+COMPATIBLE_IOCTL(RNDZAPENTCNT)
+COMPATIBLE_IOCTL(RNDCLEARPOOL)
+/* Bluetooth */
+COMPATIBLE_IOCTL(HCIDEVUP)
+COMPATIBLE_IOCTL(HCIDEVDOWN)
+COMPATIBLE_IOCTL(HCIDEVRESET)
+COMPATIBLE_IOCTL(HCIDEVRESTAT)
+COMPATIBLE_IOCTL(HCIGETDEVLIST)
+COMPATIBLE_IOCTL(HCIGETDEVINFO)
+COMPATIBLE_IOCTL(HCIGETCONNLIST)
+COMPATIBLE_IOCTL(HCIGETCONNINFO)
+COMPATIBLE_IOCTL(HCISETRAW)
+COMPATIBLE_IOCTL(HCISETSCAN)
+COMPATIBLE_IOCTL(HCISETAUTH)
+COMPATIBLE_IOCTL(HCISETENCRYPT)
+COMPATIBLE_IOCTL(HCISETPTYPE)
+COMPATIBLE_IOCTL(HCISETLINKPOL)
+COMPATIBLE_IOCTL(HCISETLINKMODE)
+COMPATIBLE_IOCTL(HCISETACLMTU)
+COMPATIBLE_IOCTL(HCISETSCOMTU)
+COMPATIBLE_IOCTL(HCIINQUIRY)
+COMPATIBLE_IOCTL(HCIUARTSETPROTO)
+COMPATIBLE_IOCTL(HCIUARTGETPROTO)
+COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
+COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
+COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
+COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
+COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
+COMPATIBLE_IOCTL(BNEPCONNADD)
+COMPATIBLE_IOCTL(BNEPCONNDEL)
+COMPATIBLE_IOCTL(BNEPGETCONNLIST)
+COMPATIBLE_IOCTL(BNEPGETCONNINFO)
+COMPATIBLE_IOCTL(CMTPCONNADD)
+COMPATIBLE_IOCTL(CMTPCONNDEL)
+COMPATIBLE_IOCTL(CMTPGETCONNLIST)
+COMPATIBLE_IOCTL(CMTPGETCONNINFO)
+COMPATIBLE_IOCTL(HIDPCONNADD)
+COMPATIBLE_IOCTL(HIDPCONNDEL)
+COMPATIBLE_IOCTL(HIDPGETCONNLIST)
+COMPATIBLE_IOCTL(HIDPGETCONNINFO)
+/* CAPI */
+COMPATIBLE_IOCTL(CAPI_REGISTER)
+COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER)
+COMPATIBLE_IOCTL(CAPI_GET_VERSION)
+COMPATIBLE_IOCTL(CAPI_GET_SERIAL)
+COMPATIBLE_IOCTL(CAPI_GET_PROFILE)
+COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD)
+COMPATIBLE_IOCTL(CAPI_GET_ERRCODE)
+COMPATIBLE_IOCTL(CAPI_INSTALLED)
+COMPATIBLE_IOCTL(CAPI_GET_FLAGS)
+COMPATIBLE_IOCTL(CAPI_SET_FLAGS)
+COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
+COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
+COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
+/* Siemens Gigaset */
+COMPATIBLE_IOCTL(GIGASET_REDIR)
+COMPATIBLE_IOCTL(GIGASET_CONFIG)
+COMPATIBLE_IOCTL(GIGASET_BRKCHARS)
+COMPATIBLE_IOCTL(GIGASET_VERSION)
+/* Misc. */
+COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */
+COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */
+COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
+COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
+COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
+/* USB */
+COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
+COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
+COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
+COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
+COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
+COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
+COMPATIBLE_IOCTL(USBDEVFS_RESET)
+COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
+COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
+COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
+/* MTD */
+COMPATIBLE_IOCTL(MEMGETINFO)
+COMPATIBLE_IOCTL(MEMERASE)
+COMPATIBLE_IOCTL(MEMLOCK)
+COMPATIBLE_IOCTL(MEMUNLOCK)
+COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
+COMPATIBLE_IOCTL(MEMGETREGIONINFO)
+COMPATIBLE_IOCTL(MEMGETBADBLOCK)
+COMPATIBLE_IOCTL(MEMSETBADBLOCK)
+/* NBD */
+ULONG_IOCTL(NBD_SET_SOCK)
+ULONG_IOCTL(NBD_SET_BLKSIZE)
+ULONG_IOCTL(NBD_SET_SIZE)
+COMPATIBLE_IOCTL(NBD_DO_IT)
+COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
+COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
+COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
+ULONG_IOCTL(NBD_SET_SIZE_BLOCKS)
+COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* i2c */
+COMPATIBLE_IOCTL(I2C_SLAVE)
+COMPATIBLE_IOCTL(I2C_SLAVE_FORCE)
+COMPATIBLE_IOCTL(I2C_TENBIT)
+COMPATIBLE_IOCTL(I2C_PEC)
+COMPATIBLE_IOCTL(I2C_RETRIES)
+COMPATIBLE_IOCTL(I2C_TIMEOUT)
+/* wireless */
+COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
+COMPATIBLE_IOCTL(SIOCGIWNAME)
+COMPATIBLE_IOCTL(SIOCSIWNWID)
+COMPATIBLE_IOCTL(SIOCGIWNWID)
+COMPATIBLE_IOCTL(SIOCSIWFREQ)
+COMPATIBLE_IOCTL(SIOCGIWFREQ)
+COMPATIBLE_IOCTL(SIOCSIWMODE)
+COMPATIBLE_IOCTL(SIOCGIWMODE)
+COMPATIBLE_IOCTL(SIOCSIWSENS)
+COMPATIBLE_IOCTL(SIOCGIWSENS)
+COMPATIBLE_IOCTL(SIOCSIWRANGE)
+COMPATIBLE_IOCTL(SIOCSIWPRIV)
+COMPATIBLE_IOCTL(SIOCGIWPRIV)
+COMPATIBLE_IOCTL(SIOCSIWSTATS)
+COMPATIBLE_IOCTL(SIOCGIWSTATS)
+COMPATIBLE_IOCTL(SIOCSIWAP)
+COMPATIBLE_IOCTL(SIOCGIWAP)
+COMPATIBLE_IOCTL(SIOCSIWSCAN)
+COMPATIBLE_IOCTL(SIOCSIWRATE)
+COMPATIBLE_IOCTL(SIOCGIWRATE)
+COMPATIBLE_IOCTL(SIOCSIWRTS)
+COMPATIBLE_IOCTL(SIOCGIWRTS)
+COMPATIBLE_IOCTL(SIOCSIWFRAG)
+COMPATIBLE_IOCTL(SIOCGIWFRAG)
+COMPATIBLE_IOCTL(SIOCSIWTXPOW)
+COMPATIBLE_IOCTL(SIOCGIWTXPOW)
+COMPATIBLE_IOCTL(SIOCSIWRETRY)
+COMPATIBLE_IOCTL(SIOCGIWRETRY)
+COMPATIBLE_IOCTL(SIOCSIWPOWER)
+COMPATIBLE_IOCTL(SIOCGIWPOWER)
+/* hiddev */
+COMPATIBLE_IOCTL(HIDIOCGVERSION)
+COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
+COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
+COMPATIBLE_IOCTL(HIDIOCGSTRING)
+COMPATIBLE_IOCTL(HIDIOCINITREPORT)
+COMPATIBLE_IOCTL(HIDIOCGREPORT)
+COMPATIBLE_IOCTL(HIDIOCSREPORT)
+COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
+COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
+COMPATIBLE_IOCTL(HIDIOCGUSAGE)
+COMPATIBLE_IOCTL(HIDIOCSUSAGE)
+COMPATIBLE_IOCTL(HIDIOCGUCODE)
+COMPATIBLE_IOCTL(HIDIOCGFLAG)
+COMPATIBLE_IOCTL(HIDIOCSFLAG)
+COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
+COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
+/* dvb */
+COMPATIBLE_IOCTL(AUDIO_STOP)
+COMPATIBLE_IOCTL(AUDIO_PLAY)
+COMPATIBLE_IOCTL(AUDIO_PAUSE)
+COMPATIBLE_IOCTL(AUDIO_CONTINUE)
+COMPATIBLE_IOCTL(AUDIO_SELECT_SOURCE)
+COMPATIBLE_IOCTL(AUDIO_SET_MUTE)
+COMPATIBLE_IOCTL(AUDIO_SET_AV_SYNC)
+COMPATIBLE_IOCTL(AUDIO_SET_BYPASS_MODE)
+COMPATIBLE_IOCTL(AUDIO_CHANNEL_SELECT)
+COMPATIBLE_IOCTL(AUDIO_GET_STATUS)
+COMPATIBLE_IOCTL(AUDIO_GET_CAPABILITIES)
+COMPATIBLE_IOCTL(AUDIO_CLEAR_BUFFER)
+COMPATIBLE_IOCTL(AUDIO_SET_ID)
+COMPATIBLE_IOCTL(AUDIO_SET_MIXER)
+COMPATIBLE_IOCTL(AUDIO_SET_STREAMTYPE)
+COMPATIBLE_IOCTL(AUDIO_SET_EXT_ID)
+COMPATIBLE_IOCTL(AUDIO_SET_ATTRIBUTES)
+COMPATIBLE_IOCTL(AUDIO_SET_KARAOKE)
+COMPATIBLE_IOCTL(DMX_START)
+COMPATIBLE_IOCTL(DMX_STOP)
+COMPATIBLE_IOCTL(DMX_SET_FILTER)
+COMPATIBLE_IOCTL(DMX_SET_PES_FILTER)
+COMPATIBLE_IOCTL(DMX_SET_BUFFER_SIZE)
+COMPATIBLE_IOCTL(DMX_GET_PES_PIDS)
+COMPATIBLE_IOCTL(DMX_GET_CAPS)
+COMPATIBLE_IOCTL(DMX_SET_SOURCE)
+COMPATIBLE_IOCTL(DMX_GET_STC)
+COMPATIBLE_IOCTL(FE_GET_INFO)
+COMPATIBLE_IOCTL(FE_DISEQC_RESET_OVERLOAD)
+COMPATIBLE_IOCTL(FE_DISEQC_SEND_MASTER_CMD)
+COMPATIBLE_IOCTL(FE_DISEQC_RECV_SLAVE_REPLY)
+COMPATIBLE_IOCTL(FE_DISEQC_SEND_BURST)
+COMPATIBLE_IOCTL(FE_SET_TONE)
+COMPATIBLE_IOCTL(FE_SET_VOLTAGE)
+COMPATIBLE_IOCTL(FE_ENABLE_HIGH_LNB_VOLTAGE)
+COMPATIBLE_IOCTL(FE_READ_STATUS)
+COMPATIBLE_IOCTL(FE_READ_BER)
+COMPATIBLE_IOCTL(FE_READ_SIGNAL_STRENGTH)
+COMPATIBLE_IOCTL(FE_READ_SNR)
+COMPATIBLE_IOCTL(FE_READ_UNCORRECTED_BLOCKS)
+COMPATIBLE_IOCTL(FE_SET_FRONTEND)
+COMPATIBLE_IOCTL(FE_GET_FRONTEND)
+COMPATIBLE_IOCTL(FE_GET_EVENT)
+COMPATIBLE_IOCTL(FE_DISHNETWORK_SEND_LEGACY_CMD)
+COMPATIBLE_IOCTL(VIDEO_STOP)
+COMPATIBLE_IOCTL(VIDEO_PLAY)
+COMPATIBLE_IOCTL(VIDEO_FREEZE)
+COMPATIBLE_IOCTL(VIDEO_CONTINUE)
+COMPATIBLE_IOCTL(VIDEO_SELECT_SOURCE)
+COMPATIBLE_IOCTL(VIDEO_SET_BLANK)
+COMPATIBLE_IOCTL(VIDEO_GET_STATUS)
+COMPATIBLE_IOCTL(VIDEO_SET_DISPLAY_FORMAT)
+COMPATIBLE_IOCTL(VIDEO_FAST_FORWARD)
+COMPATIBLE_IOCTL(VIDEO_SLOWMOTION)
+COMPATIBLE_IOCTL(VIDEO_GET_CAPABILITIES)
+COMPATIBLE_IOCTL(VIDEO_CLEAR_BUFFER)
+COMPATIBLE_IOCTL(VIDEO_SET_ID)
+COMPATIBLE_IOCTL(VIDEO_SET_STREAMTYPE)
+COMPATIBLE_IOCTL(VIDEO_SET_FORMAT)
+COMPATIBLE_IOCTL(VIDEO_SET_SYSTEM)
+COMPATIBLE_IOCTL(VIDEO_SET_HIGHLIGHT)
+COMPATIBLE_IOCTL(VIDEO_SET_SPU)
+COMPATIBLE_IOCTL(VIDEO_GET_NAVI)
+COMPATIBLE_IOCTL(VIDEO_SET_ATTRIBUTES)
+COMPATIBLE_IOCTL(VIDEO_GET_SIZE)
+COMPATIBLE_IOCTL(VIDEO_GET_FRAME_RATE)
+
+/* now things that need handlers */
HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
#ifdef CONFIG_NET
@@ -2594,6 +3438,8 @@ HANDLE_IOCTL(SIOCGIWENCODEEXT, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIWPMKSA, do_wireless_ioctl)
HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
+/* Not implemented in the native kernel */
+IGNORE_IOCTL(SIOCGIFCOUNT)
HANDLE_IOCTL(RTC_IRQP_READ32, rtc_ioctl)
HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl)
HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl)
@@ -2617,6 +3463,167 @@ COMPATIBLE_IOCTL(LPRESET)
/*LPGETSTATS not implemented, but no kernels seem to compile it in anyways*/
COMPATIBLE_IOCTL(LPGETFLAGS)
HANDLE_IOCTL(LPSETTIMEOUT, lp_timeout_trans)
+
+/* fat 'r' ioctls. These are handled by fat with ->compat_ioctl,
+ but we don't want warnings on other file systems. So declare
+ them as compatible here. */
+#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
+#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
+
+IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
+IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
};
-int ioctl_table_size = ARRAY_SIZE(ioctl_start);
+#define IOCTL_HASHSIZE 256
+static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
+
+static inline unsigned long ioctl32_hash(unsigned long cmd)
+{
+ return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
+}
+
+static void compat_ioctl_error(struct file *filp, unsigned int fd,
+ unsigned int cmd, unsigned long arg)
+{
+ char buf[10];
+ char *fn = "?";
+ char *path;
+
+ /* find the name of the device. */
+ path = (char *)__get_free_page(GFP_KERNEL);
+ if (path) {
+ fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE);
+ if (IS_ERR(fn))
+ fn = "?";
+ }
+
+ sprintf(buf,"'%c'", (cmd>>_IOC_TYPESHIFT) & _IOC_TYPEMASK);
+ if (!isprint(buf[1]))
+ sprintf(buf, "%02x", buf[1]);
+ compat_printk("ioctl32(%s:%d): Unknown cmd fd(%d) "
+ "cmd(%08x){t:%s;sz:%u} arg(%08x) on %s\n",
+ current->comm, current->pid,
+ (int)fd, (unsigned int)cmd, buf,
+ (cmd >> _IOC_SIZESHIFT) & _IOC_SIZEMASK,
+ (unsigned int)arg, fn);
+
+ if (path)
+ free_page((unsigned long)path);
+}
+
+asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
+ struct file *filp;
+ int error = -EBADF;
+ struct ioctl_trans *t;
+ int fput_needed;
+
+ filp = fget_light(fd, &fput_needed);
+ if (!filp)
+ goto out;
+
+ /* RED-PEN how should LSM module know it's handling 32bit? */
+ error = security_file_ioctl(filp, cmd, arg);
+ if (error)
+ goto out_fput;
+
+ /*
+ * To allow the compat_ioctl handlers to be self contained
+ * we need to check the common ioctls here first.
+ * Just handle them with the standard handlers below.
+ */
+ switch (cmd) {
+ case FIOCLEX:
+ case FIONCLEX:
+ case FIONBIO:
+ case FIOASYNC:
+ case FIOQSIZE:
+ break;
+
+ case FIBMAP:
+ case FIGETBSZ:
+ case FIONREAD:
+ if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))
+ break;
+ /*FALL THROUGH*/
+
+ default:
+ if (filp->f_op && filp->f_op->compat_ioctl) {
+ error = filp->f_op->compat_ioctl(filp, cmd, arg);
+ if (error != -ENOIOCTLCMD)
+ goto out_fput;
+ }
+
+ if (!filp->f_op ||
+ (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl))
+ goto do_ioctl;
+ break;
+ }
+
+ for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) {
+ if (t->cmd == cmd)
+ goto found_handler;
+ }
+
+ if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
+ cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
+ error = siocdevprivate_ioctl(fd, cmd, arg);
+ } else {
+ static int count;
+
+ if (++count <= 50)
+ compat_ioctl_error(filp, fd, cmd, arg);
+ error = -EINVAL;
+ }
+
+ goto out_fput;
+
+ found_handler:
+ if (t->handler) {
+ lock_kernel();
+ error = t->handler(fd, cmd, arg, filp);
+ unlock_kernel();
+ goto out_fput;
+ }
+
+ do_ioctl:
+ error = vfs_ioctl(filp, fd, cmd, arg);
+ out_fput:
+ fput_light(filp, fput_needed);
+ out:
+ return error;
+}
+
+static void ioctl32_insert_translation(struct ioctl_trans *trans)
+{
+ unsigned long hash;
+ struct ioctl_trans *t;
+
+ hash = ioctl32_hash (trans->cmd);
+ if (!ioctl32_hash_table[hash])
+ ioctl32_hash_table[hash] = trans;
+ else {
+ t = ioctl32_hash_table[hash];
+ while (t->next)
+ t = t->next;
+ trans->next = NULL;
+ t->next = trans;
+ }
+}
+
+static int __init init_sys32_ioctl(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ioctl_start); i++) {
+ if (ioctl_start[i].next != 0) {
+ printk("ioctl translation %d bad\n",i);
+ return -1;
+ }
+
+ ioctl32_insert_translation(&ioctl_start[i]);
+ }
+ return 0;
+}
+__initcall(init_sys32_ioctl);
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index d98be5e0132..3527c7c6def 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -77,36 +77,6 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
return ret;
}
-
-/**
- * flush_read_buffer - push buffer to userspace.
- * @buffer: data buffer for file.
- * @userbuf: user-passed buffer.
- * @count: number of bytes requested.
- * @ppos: file position.
- *
- * Copy the buffer we filled in fill_read_buffer() to userspace.
- * This is done at the reader's leisure, copying and advancing
- * the amount they specify each time.
- * This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct configfs_buffer * buffer, char __user * buf,
- size_t count, loff_t * ppos)
-{
- int error;
-
- if (*ppos > buffer->count)
- return 0;
-
- if (count > (buffer->count - *ppos))
- count = buffer->count - *ppos;
-
- error = copy_to_user(buf,buffer->page + *ppos,count);
- if (!error)
- *ppos += count;
- return error ? -EFAULT : count;
-}
-
/**
* configfs_read_file - read an attribute.
* @file: file pointer.
@@ -139,7 +109,8 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
__FUNCTION__, count, *ppos, buffer->page);
- retval = flush_read_buffer(buffer,buf,count,ppos);
+ retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+ buffer->count);
out:
up(&buffer->sem);
return retval;
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 6f573004cd7..b00d962de83 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -140,7 +140,7 @@ static int __init configfs_init(void)
if (!configfs_dir_cachep)
goto out;
- kset_set_kset_s(&config_subsys, kernel_subsys);
+ kobj_set_kset_s(&config_subsys, kernel_subsys);
err = subsystem_register(&config_subsys);
if (err) {
kmem_cache_destroy(configfs_dir_cachep);
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index facd0c89be8..3d194a2be3f 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -180,7 +180,8 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
struct page *page = NULL;
if (blocknr + i < devsize) {
- page = read_mapping_page(mapping, blocknr + i, NULL);
+ page = read_mapping_page_async(mapping, blocknr + i,
+ NULL);
/* synchronous error? */
if (IS_ERR(page))
page = NULL;
diff --git a/fs/dcache.c b/fs/dcache.c
index d68631f18df..0e73aa0a0e8 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -21,7 +21,6 @@
#include <linux/fsnotify.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/hash.h>
#include <linux/cache.h>
#include <linux/module.h>
@@ -121,6 +120,28 @@ static void dentry_iput(struct dentry * dentry)
}
}
+/**
+ * d_kill - kill dentry and return parent
+ * @dentry: dentry to kill
+ *
+ * Called with dcache_lock and d_lock, releases both. The dentry must
+ * already be unhashed and removed from the LRU.
+ *
+ * If this is the root of the dentry tree, return NULL.
+ */
+static struct dentry *d_kill(struct dentry *dentry)
+{
+ struct dentry *parent;
+
+ list_del(&dentry->d_u.d_child);
+ dentry_stat.nr_dentry--; /* For d_free, below */
+ /*drops the locks, at that point nobody can reach this dentry */
+ dentry_iput(dentry);
+ parent = dentry->d_parent;
+ d_free(dentry);
+ return dentry == parent ? NULL : parent;
+}
+
/*
* This is dput
*
@@ -189,28 +210,17 @@ repeat:
unhash_it:
__d_drop(dentry);
-
-kill_it: {
- struct dentry *parent;
-
- /* If dentry was on d_lru list
- * delete it from there
- */
- if (!list_empty(&dentry->d_lru)) {
- list_del(&dentry->d_lru);
- dentry_stat.nr_unused--;
- }
- list_del(&dentry->d_u.d_child);
- dentry_stat.nr_dentry--; /* For d_free, below */
- /*drops the locks, at that point nobody can reach this dentry */
- dentry_iput(dentry);
- parent = dentry->d_parent;
- d_free(dentry);
- if (dentry == parent)
- return;
- dentry = parent;
- goto repeat;
+kill_it:
+ /* If dentry was on d_lru list
+ * delete it from there
+ */
+ if (!list_empty(&dentry->d_lru)) {
+ list_del(&dentry->d_lru);
+ dentry_stat.nr_unused--;
}
+ dentry = d_kill(dentry);
+ if (dentry)
+ goto repeat;
}
/**
@@ -371,22 +381,40 @@ restart:
* Throw away a dentry - free the inode, dput the parent. This requires that
* the LRU list has already been removed.
*
+ * If prune_parents is true, try to prune ancestors as well.
+ *
* Called with dcache_lock, drops it and then regains.
* Called with dentry->d_lock held, drops it.
*/
-static void prune_one_dentry(struct dentry * dentry)
+static void prune_one_dentry(struct dentry * dentry, int prune_parents)
{
- struct dentry * parent;
-
__d_drop(dentry);
- list_del(&dentry->d_u.d_child);
- dentry_stat.nr_dentry--; /* For d_free, below */
- dentry_iput(dentry);
- parent = dentry->d_parent;
- d_free(dentry);
- if (parent != dentry)
- dput(parent);
+ dentry = d_kill(dentry);
+ if (!prune_parents) {
+ dput(dentry);
+ spin_lock(&dcache_lock);
+ return;
+ }
+
+ /*
+ * Prune ancestors. Locking is simpler than in dput(),
+ * because dcache_lock needs to be taken anyway.
+ */
spin_lock(&dcache_lock);
+ while (dentry) {
+ if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))
+ return;
+
+ if (dentry->d_op && dentry->d_op->d_delete)
+ dentry->d_op->d_delete(dentry);
+ if (!list_empty(&dentry->d_lru)) {
+ list_del(&dentry->d_lru);
+ dentry_stat.nr_unused--;
+ }
+ __d_drop(dentry);
+ dentry = d_kill(dentry);
+ spin_lock(&dcache_lock);
+ }
}
/**
@@ -394,6 +422,7 @@ static void prune_one_dentry(struct dentry * dentry)
* @count: number of entries to try and free
* @sb: if given, ignore dentries for other superblocks
* which are being unmounted.
+ * @prune_parents: if true, try to prune ancestors as well in one go
*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
@@ -404,7 +433,7 @@ static void prune_one_dentry(struct dentry * dentry)
* all the dentries are in use.
*/
-static void prune_dcache(int count, struct super_block *sb)
+static void prune_dcache(int count, struct super_block *sb, int prune_parents)
{
spin_lock(&dcache_lock);
for (; count ; count--) {
@@ -464,7 +493,7 @@ static void prune_dcache(int count, struct super_block *sb)
* without taking the s_umount lock (I already hold it).
*/
if (sb && dentry->d_sb == sb) {
- prune_one_dentry(dentry);
+ prune_one_dentry(dentry, prune_parents);
continue;
}
/*
@@ -479,7 +508,7 @@ static void prune_dcache(int count, struct super_block *sb)
s_umount = &dentry->d_sb->s_umount;
if (down_read_trylock(s_umount)) {
if (dentry->d_sb->s_root != NULL) {
- prune_one_dentry(dentry);
+ prune_one_dentry(dentry, prune_parents);
up_read(s_umount);
continue;
}
@@ -550,7 +579,7 @@ repeat:
spin_unlock(&dentry->d_lock);
continue;
}
- prune_one_dentry(dentry);
+ prune_one_dentry(dentry, 1);
cond_resched_lock(&dcache_lock);
goto repeat;
}
@@ -829,7 +858,7 @@ void shrink_dcache_parent(struct dentry * parent)
int found;
while ((found = select_parent(parent)) != 0)
- prune_dcache(found, parent->d_sb);
+ prune_dcache(found, parent->d_sb, 1);
}
/*
@@ -849,7 +878,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
if (nr) {
if (!(gfp_mask & __GFP_FS))
return -1;
- prune_dcache(nr, NULL);
+ prune_dcache(nr, NULL, 1);
}
return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
@@ -1823,6 +1852,16 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
struct vfsmount *rootmnt;
struct dentry *root;
+ /*
+ * We have various synthetic filesystems that never get mounted. On
+ * these filesystems dentries are never used for lookup purposes, and
+ * thus don't need to be hashed. They also don't need a name until a
+ * user wants to identify the object in /proc/pid/fd/. The little hack
+ * below allows us to generate a name for these objects on demand:
+ */
+ if (dentry->d_op && dentry->d_op->d_dname)
+ return dentry->d_op->d_dname(dentry, buf, buflen);
+
read_lock(&current->fs->lock);
rootmnt = mntget(current->fs->rootmnt);
root = dget(current->fs->root);
@@ -1836,6 +1875,27 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
}
/*
+ * Helper function for dentry_operations.d_dname() members
+ */
+char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen,
+ const char *fmt, ...)
+{
+ va_list args;
+ char temp[64];
+ int sz;
+
+ va_start(args, fmt);
+ sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1;
+ va_end(args);
+
+ if (sz > sizeof(temp) || sz > buflen)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ buffer += buflen - sz;
+ return memcpy(buffer, temp, sz);
+}
+
+/*
* NOTE! The user-level library version returns a
* character pointer. The kernel system call just
* returns the length of the buffer filled (which
@@ -2052,12 +2112,8 @@ static void __init dcache_init(unsigned long mempages)
* but it is probably not worth it because of the cache nature
* of the dcache.
*/
- dentry_cache = kmem_cache_create("dentry_cache",
- sizeof(struct dentry),
- 0,
- (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
- SLAB_MEM_SPREAD),
- NULL, NULL);
+ dentry_cache = KMEM_CACHE(dentry,
+ SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory);
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 7b324cfebcb..ec8896b264d 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -374,7 +374,7 @@ static int __init debugfs_init(void)
{
int retval;
- kset_set_kset_s(&debug_subsys, kernel_subsys);
+ kobj_set_kset_s(&debug_subsys, kernel_subsys);
retval = subsystem_register(&debug_subsys);
if (retval)
return retval;
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 643e57b622b..06ef9a255c7 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -19,6 +19,7 @@
#include <linux/tty.h>
#include <linux/devpts_fs.h>
#include <linux/parser.h>
+#include <linux/fsnotify.h>
#define DEVPTS_SUPER_MAGIC 0x1cd1
@@ -178,8 +179,10 @@ int devpts_pty_new(struct tty_struct *tty)
inode->i_private = tty;
dentry = get_node(number);
- if (!IS_ERR(dentry) && !dentry->d_inode)
+ if (!IS_ERR(dentry) && !dentry->d_inode) {
d_instantiate(dentry, inode);
+ fsnotify_create(devpts_root->d_inode, dentry);
+ }
mutex_unlock(&devpts_root->d_inode->i_mutex);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index d9d0833444f..8593f3dfd29 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -439,7 +439,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio)
* Wait on and process all in-flight BIOs. This must only be called once
* all bios have been issued so that the refcount can only decrease.
* This just waits for all bios to make it through dio_bio_complete. IO
- * errors are propogated through dio->io_error and should be propogated via
+ * errors are propagated through dio->io_error and should be propagated via
* dio_complete().
*/
static void dio_await_completion(struct dio *dio)
@@ -867,7 +867,6 @@ static int do_direct_IO(struct dio *dio)
do_holes:
/* Handle holes */
if (!buffer_mapped(map_bh)) {
- char *kaddr;
loff_t i_size_aligned;
/* AKPM: eargh, -ENOTBLK is a hack */
@@ -888,11 +887,8 @@ do_holes:
page_cache_release(page);
goto out;
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + (block_in_page << blkbits),
- 0, 1 << blkbits);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, block_in_page << blkbits,
+ 1 << blkbits, KM_USER0);
dio->block_in_file++;
block_in_page++;
goto next_block;
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
index 6fa7b0d5c04..69a94690e49 100644
--- a/fs/dlm/Kconfig
+++ b/fs/dlm/Kconfig
@@ -3,36 +3,19 @@ menu "Distributed Lock Manager"
config DLM
tristate "Distributed Lock Manager (DLM)"
- depends on SYSFS && (IPV6 || IPV6=n)
+ depends on IPV6 || IPV6=n
select CONFIGFS_FS
- select IP_SCTP if DLM_SCTP
+ select IP_SCTP
help
- A general purpose distributed lock manager for kernel or userspace
- applications.
-
-choice
- prompt "Select DLM communications protocol"
- depends on DLM
- default DLM_TCP
- help
- The DLM Can use TCP or SCTP for it's network communications.
- SCTP supports multi-homed operations whereas TCP doesn't.
- However, SCTP seems to have stability problems at the moment.
-
-config DLM_TCP
- bool "TCP/IP"
-
-config DLM_SCTP
- bool "SCTP"
-
-endchoice
+ A general purpose distributed lock manager for kernel or userspace
+ applications.
config DLM_DEBUG
bool "DLM debugging"
depends on DLM
help
- Under the debugfs mount point, the name of each lockspace will
- appear as a file in the "dlm" directory. The output is the
- list of resource and locks the local node knows about.
+ Under the debugfs mount point, the name of each lockspace will
+ appear as a file in the "dlm" directory. The output is the
+ list of resource and locks the local node knows about.
endmenu
diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile
index 65388944eba..604cf7dc5f3 100644
--- a/fs/dlm/Makefile
+++ b/fs/dlm/Makefile
@@ -8,14 +8,12 @@ dlm-y := ast.o \
member.o \
memory.o \
midcomms.o \
+ lowcomms.o \
rcom.o \
recover.o \
recoverd.o \
requestqueue.o \
user.o \
- util.o
+ util.o
dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o
-dlm-$(CONFIG_DLM_TCP) += lowcomms-tcp.o
-
-dlm-$(CONFIG_DLM_SCTP) += lowcomms-sctp.o \ No newline at end of file
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index f91d39cb1e0..6308122890c 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -14,6 +14,7 @@
#include "dlm_internal.h"
#include "lock.h"
#include "user.h"
+#include "ast.h"
#define WAKE_ASTS 0
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 8665c88e5af..822abdcd143 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -89,6 +89,7 @@ struct cluster {
unsigned int cl_toss_secs;
unsigned int cl_scan_secs;
unsigned int cl_log_debug;
+ unsigned int cl_protocol;
};
enum {
@@ -101,6 +102,7 @@ enum {
CLUSTER_ATTR_TOSS_SECS,
CLUSTER_ATTR_SCAN_SECS,
CLUSTER_ATTR_LOG_DEBUG,
+ CLUSTER_ATTR_PROTOCOL,
};
struct cluster_attribute {
@@ -159,6 +161,7 @@ CLUSTER_ATTR(recover_timer, 1);
CLUSTER_ATTR(toss_secs, 1);
CLUSTER_ATTR(scan_secs, 1);
CLUSTER_ATTR(log_debug, 0);
+CLUSTER_ATTR(protocol, 0);
static struct configfs_attribute *cluster_attrs[] = {
[CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
@@ -170,6 +173,7 @@ static struct configfs_attribute *cluster_attrs[] = {
[CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
[CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
[CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
+ [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
NULL,
};
@@ -904,6 +908,7 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
#define DEFAULT_TOSS_SECS 10
#define DEFAULT_SCAN_SECS 5
#define DEFAULT_LOG_DEBUG 0
+#define DEFAULT_PROTOCOL 0
struct dlm_config_info dlm_config = {
.ci_tcp_port = DEFAULT_TCP_PORT,
@@ -914,6 +919,7 @@ struct dlm_config_info dlm_config = {
.ci_recover_timer = DEFAULT_RECOVER_TIMER,
.ci_toss_secs = DEFAULT_TOSS_SECS,
.ci_scan_secs = DEFAULT_SCAN_SECS,
- .ci_log_debug = DEFAULT_LOG_DEBUG
+ .ci_log_debug = DEFAULT_LOG_DEBUG,
+ .ci_protocol = DEFAULT_PROTOCOL
};
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
index 1e978611a96..967cc3d72e5 100644
--- a/fs/dlm/config.h
+++ b/fs/dlm/config.h
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -26,6 +26,7 @@ struct dlm_config_info {
int ci_toss_secs;
int ci_scan_secs;
int ci_log_debug;
+ int ci_protocol;
};
extern struct dlm_config_info dlm_config;
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 61d93201e1b..30994d68f6a 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -210,6 +210,9 @@ struct dlm_args {
#define DLM_IFL_MSTCPY 0x00010000
#define DLM_IFL_RESEND 0x00020000
#define DLM_IFL_DEAD 0x00040000
+#define DLM_IFL_OVERLAP_UNLOCK 0x00080000
+#define DLM_IFL_OVERLAP_CANCEL 0x00100000
+#define DLM_IFL_ENDOFLIFE 0x00200000
#define DLM_IFL_USER 0x00000001
#define DLM_IFL_ORPHAN 0x00000002
@@ -230,8 +233,8 @@ struct dlm_lkb {
int8_t lkb_grmode; /* granted lock mode */
int8_t lkb_bastmode; /* requested mode */
int8_t lkb_highbast; /* highest mode bast sent for */
-
int8_t lkb_wait_type; /* type of reply waiting for */
+ int8_t lkb_wait_count;
int8_t lkb_ast_type; /* type of ast queued for */
struct list_head lkb_idtbl_list; /* lockspace lkbtbl */
@@ -339,6 +342,7 @@ struct dlm_header {
#define DLM_MSG_LOOKUP 11
#define DLM_MSG_REMOVE 12
#define DLM_MSG_LOOKUP_REPLY 13
+#define DLM_MSG_PURGE 14
struct dlm_message {
struct dlm_header m_header;
@@ -440,6 +444,9 @@ struct dlm_ls {
struct mutex ls_waiters_mutex;
struct list_head ls_waiters; /* lkbs needing a reply */
+ struct mutex ls_orphans_mutex;
+ struct list_head ls_orphans;
+
struct list_head ls_nodes; /* current nodes in ls */
struct list_head ls_nodes_gone; /* dead node list, recovery */
int ls_num_nodes; /* number of nodes in ls */
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index e725005fafd..d8d6e729f96 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -1,7 +1,7 @@
/******************************************************************************
*******************************************************************************
**
-** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2005-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -85,6 +85,7 @@ static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
struct dlm_message *ms);
static int receive_extralen(struct dlm_message *ms);
+static void do_purge(struct dlm_ls *ls, int nodeid, int pid);
/*
* Lock compatibilty matrix - thanks Steve
@@ -223,6 +224,16 @@ static inline int is_demoted(struct dlm_lkb *lkb)
return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
}
+static inline int is_altmode(struct dlm_lkb *lkb)
+{
+ return (lkb->lkb_sbflags & DLM_SBF_ALTMODE);
+}
+
+static inline int is_granted(struct dlm_lkb *lkb)
+{
+ return (lkb->lkb_status == DLM_LKSTS_GRANTED);
+}
+
static inline int is_remote(struct dlm_rsb *r)
{
DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
@@ -254,6 +265,22 @@ static inline int down_conversion(struct dlm_lkb *lkb)
return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
}
+static inline int is_overlap_unlock(struct dlm_lkb *lkb)
+{
+ return lkb->lkb_flags & DLM_IFL_OVERLAP_UNLOCK;
+}
+
+static inline int is_overlap_cancel(struct dlm_lkb *lkb)
+{
+ return lkb->lkb_flags & DLM_IFL_OVERLAP_CANCEL;
+}
+
+static inline int is_overlap(struct dlm_lkb *lkb)
+{
+ return (lkb->lkb_flags & (DLM_IFL_OVERLAP_UNLOCK |
+ DLM_IFL_OVERLAP_CANCEL));
+}
+
static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
{
if (is_master_copy(lkb))
@@ -267,6 +294,12 @@ static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
dlm_add_ast(lkb, AST_COMP);
}
+static inline void queue_cast_overlap(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ queue_cast(r, lkb,
+ is_overlap_unlock(lkb) ? -DLM_EUNLOCK : -DLM_ECANCEL);
+}
+
static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
{
if (is_master_copy(lkb))
@@ -547,6 +580,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
lkb->lkb_grmode = DLM_LOCK_IV;
kref_init(&lkb->lkb_ref);
INIT_LIST_HEAD(&lkb->lkb_ownqueue);
+ INIT_LIST_HEAD(&lkb->lkb_rsb_lookup);
get_random_bytes(&bucket, sizeof(bucket));
bucket &= (ls->ls_lkbtbl_size - 1);
@@ -556,7 +590,7 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
/* counter can roll over so we must verify lkid is not in use */
while (lkid == 0) {
- lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16);
+ lkid = (bucket << 16) | ls->ls_lkbtbl[bucket].counter++;
list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list,
lkb_idtbl_list) {
@@ -577,8 +611,8 @@ static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
{
- uint16_t bucket = lkid & 0xFFFF;
struct dlm_lkb *lkb;
+ uint16_t bucket = (lkid >> 16);
list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {
if (lkb->lkb_id == lkid)
@@ -590,7 +624,7 @@ static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
{
struct dlm_lkb *lkb;
- uint16_t bucket = lkid & 0xFFFF;
+ uint16_t bucket = (lkid >> 16);
if (bucket >= ls->ls_lkbtbl_size)
return -EBADSLT;
@@ -620,7 +654,7 @@ static void kill_lkb(struct kref *kref)
static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
{
- uint16_t bucket = lkb->lkb_id & 0xFFFF;
+ uint16_t bucket = (lkb->lkb_id >> 16);
write_lock(&ls->ls_lkbtbl[bucket].lock);
if (kref_put(&lkb->lkb_ref, kill_lkb)) {
@@ -735,23 +769,75 @@ static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)
unhold_lkb(lkb);
}
+static int msg_reply_type(int mstype)
+{
+ switch (mstype) {
+ case DLM_MSG_REQUEST:
+ return DLM_MSG_REQUEST_REPLY;
+ case DLM_MSG_CONVERT:
+ return DLM_MSG_CONVERT_REPLY;
+ case DLM_MSG_UNLOCK:
+ return DLM_MSG_UNLOCK_REPLY;
+ case DLM_MSG_CANCEL:
+ return DLM_MSG_CANCEL_REPLY;
+ case DLM_MSG_LOOKUP:
+ return DLM_MSG_LOOKUP_REPLY;
+ }
+ return -1;
+}
+
/* add/remove lkb from global waiters list of lkb's waiting for
a reply from a remote node */
-static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
+static int add_to_waiters(struct dlm_lkb *lkb, int mstype)
{
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+ int error = 0;
mutex_lock(&ls->ls_waiters_mutex);
- if (lkb->lkb_wait_type) {
- log_print("add_to_waiters error %d", lkb->lkb_wait_type);
+
+ if (is_overlap_unlock(lkb) ||
+ (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL))) {
+ error = -EINVAL;
+ goto out;
+ }
+
+ if (lkb->lkb_wait_type || is_overlap_cancel(lkb)) {
+ switch (mstype) {
+ case DLM_MSG_UNLOCK:
+ lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
+ break;
+ case DLM_MSG_CANCEL:
+ lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
+ break;
+ default:
+ error = -EBUSY;
+ goto out;
+ }
+ lkb->lkb_wait_count++;
+ hold_lkb(lkb);
+
+ log_debug(ls, "add overlap %x cur %d new %d count %d flags %x",
+ lkb->lkb_id, lkb->lkb_wait_type, mstype,
+ lkb->lkb_wait_count, lkb->lkb_flags);
goto out;
}
+
+ DLM_ASSERT(!lkb->lkb_wait_count,
+ dlm_print_lkb(lkb);
+ printk("wait_count %d\n", lkb->lkb_wait_count););
+
+ lkb->lkb_wait_count++;
lkb->lkb_wait_type = mstype;
- kref_get(&lkb->lkb_ref);
+ hold_lkb(lkb);
list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
out:
+ if (error)
+ log_error(ls, "add_to_waiters %x error %d flags %x %d %d %s",
+ lkb->lkb_id, error, lkb->lkb_flags, mstype,
+ lkb->lkb_wait_type, lkb->lkb_resource->res_name);
mutex_unlock(&ls->ls_waiters_mutex);
+ return error;
}
/* We clear the RESEND flag because we might be taking an lkb off the waiters
@@ -759,34 +845,85 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
request reply on the requestqueue) between dlm_recover_waiters_pre() which
set RESEND and dlm_recover_waiters_post() */
-static int _remove_from_waiters(struct dlm_lkb *lkb)
+static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype)
{
- int error = 0;
+ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+ int overlap_done = 0;
- if (!lkb->lkb_wait_type) {
- log_print("remove_from_waiters error");
- error = -EINVAL;
- goto out;
+ if (is_overlap_unlock(lkb) && (mstype == DLM_MSG_UNLOCK_REPLY)) {
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+ overlap_done = 1;
+ goto out_del;
+ }
+
+ if (is_overlap_cancel(lkb) && (mstype == DLM_MSG_CANCEL_REPLY)) {
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+ overlap_done = 1;
+ goto out_del;
+ }
+
+ /* N.B. type of reply may not always correspond to type of original
+ msg due to lookup->request optimization, verify others? */
+
+ if (lkb->lkb_wait_type) {
+ lkb->lkb_wait_type = 0;
+ goto out_del;
+ }
+
+ log_error(ls, "remove_from_waiters lkid %x flags %x types %d %d",
+ lkb->lkb_id, lkb->lkb_flags, mstype, lkb->lkb_wait_type);
+ return -1;
+
+ out_del:
+ /* the force-unlock/cancel has completed and we haven't recvd a reply
+ to the op that was in progress prior to the unlock/cancel; we
+ give up on any reply to the earlier op. FIXME: not sure when/how
+ this would happen */
+
+ if (overlap_done && lkb->lkb_wait_type) {
+ log_error(ls, "remove_from_waiters %x reply %d give up on %d",
+ lkb->lkb_id, mstype, lkb->lkb_wait_type);
+ lkb->lkb_wait_count--;
+ lkb->lkb_wait_type = 0;
}
- lkb->lkb_wait_type = 0;
+
+ DLM_ASSERT(lkb->lkb_wait_count, dlm_print_lkb(lkb););
+
lkb->lkb_flags &= ~DLM_IFL_RESEND;
- list_del(&lkb->lkb_wait_reply);
+ lkb->lkb_wait_count--;
+ if (!lkb->lkb_wait_count)
+ list_del_init(&lkb->lkb_wait_reply);
unhold_lkb(lkb);
- out:
- return error;
+ return 0;
}
-static int remove_from_waiters(struct dlm_lkb *lkb)
+static int remove_from_waiters(struct dlm_lkb *lkb, int mstype)
{
struct dlm_ls *ls = lkb->lkb_resource->res_ls;
int error;
mutex_lock(&ls->ls_waiters_mutex);
- error = _remove_from_waiters(lkb);
+ error = _remove_from_waiters(lkb, mstype);
mutex_unlock(&ls->ls_waiters_mutex);
return error;
}
+/* Handles situations where we might be processing a "fake" or "stub" reply in
+ which we can't try to take waiters_mutex again. */
+
+static int remove_from_waiters_ms(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+ int error;
+
+ if (ms != &ls->ls_stub_ms)
+ mutex_lock(&ls->ls_waiters_mutex);
+ error = _remove_from_waiters(lkb, ms->m_type);
+ if (ms != &ls->ls_stub_ms)
+ mutex_unlock(&ls->ls_waiters_mutex);
+ return error;
+}
+
static void dir_remove(struct dlm_rsb *r)
{
int to_nodeid;
@@ -988,8 +1125,14 @@ static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
_remove_lock(r, lkb);
}
-static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+/* returns: 0 did nothing
+ 1 moved lock to granted
+ -1 removed lock */
+
+static int revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
+ int rv = 0;
+
lkb->lkb_rqmode = DLM_LOCK_IV;
switch (lkb->lkb_status) {
@@ -997,6 +1140,7 @@ static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
break;
case DLM_LKSTS_CONVERT:
move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+ rv = 1;
break;
case DLM_LKSTS_WAITING:
del_lkb(r, lkb);
@@ -1004,15 +1148,17 @@ static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
/* this unhold undoes the original ref from create_lkb()
so this leads to the lkb being freed */
unhold_lkb(lkb);
+ rv = -1;
break;
default:
log_print("invalid status for revert %d", lkb->lkb_status);
}
+ return rv;
}
-static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+static int revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
- revert_lock(r, lkb);
+ return revert_lock(r, lkb);
}
static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
@@ -1055,6 +1201,50 @@ static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
queue_cast(r, lkb, 0);
}
+/* The special CONVDEADLK, ALTPR and ALTCW flags allow the master to
+ change the granted/requested modes. We're munging things accordingly in
+ the process copy.
+ CONVDEADLK: our grmode may have been forced down to NL to resolve a
+ conversion deadlock
+ ALTPR/ALTCW: our rqmode may have been changed to PR or CW to become
+ compatible with other granted locks */
+
+static void munge_demoted(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ if (ms->m_type != DLM_MSG_CONVERT_REPLY) {
+ log_print("munge_demoted %x invalid reply type %d",
+ lkb->lkb_id, ms->m_type);
+ return;
+ }
+
+ if (lkb->lkb_rqmode == DLM_LOCK_IV || lkb->lkb_grmode == DLM_LOCK_IV) {
+ log_print("munge_demoted %x invalid modes gr %d rq %d",
+ lkb->lkb_id, lkb->lkb_grmode, lkb->lkb_rqmode);
+ return;
+ }
+
+ lkb->lkb_grmode = DLM_LOCK_NL;
+}
+
+static void munge_altmode(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ if (ms->m_type != DLM_MSG_REQUEST_REPLY &&
+ ms->m_type != DLM_MSG_GRANT) {
+ log_print("munge_altmode %x invalid reply type %d",
+ lkb->lkb_id, ms->m_type);
+ return;
+ }
+
+ if (lkb->lkb_exflags & DLM_LKF_ALTPR)
+ lkb->lkb_rqmode = DLM_LOCK_PR;
+ else if (lkb->lkb_exflags & DLM_LKF_ALTCW)
+ lkb->lkb_rqmode = DLM_LOCK_CW;
+ else {
+ log_print("munge_altmode invalid exflags %x", lkb->lkb_exflags);
+ dlm_print_lkb(lkb);
+ }
+}
+
static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
{
struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
@@ -1499,7 +1689,7 @@ static void process_lookup_list(struct dlm_rsb *r)
struct dlm_lkb *lkb, *safe;
list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
- list_del(&lkb->lkb_rsb_lookup);
+ list_del_init(&lkb->lkb_rsb_lookup);
_request_lock(r, lkb);
schedule();
}
@@ -1530,7 +1720,7 @@ static void confirm_master(struct dlm_rsb *r, int error)
if (!list_empty(&r->res_lookup)) {
lkb = list_entry(r->res_lookup.next, struct dlm_lkb,
lkb_rsb_lookup);
- list_del(&lkb->lkb_rsb_lookup);
+ list_del_init(&lkb->lkb_rsb_lookup);
r->res_first_lkid = lkb->lkb_id;
_request_lock(r, lkb);
} else
@@ -1614,6 +1804,9 @@ static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
DLM_LKF_FORCEUNLOCK))
return -EINVAL;
+ if (flags & DLM_LKF_CANCEL && flags & DLM_LKF_FORCEUNLOCK)
+ return -EINVAL;
+
args->flags = flags;
args->astparam = (long) astarg;
return 0;
@@ -1638,6 +1831,9 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
if (lkb->lkb_wait_type)
goto out;
+
+ if (is_overlap(lkb))
+ goto out;
}
lkb->lkb_exflags = args->flags;
@@ -1654,35 +1850,126 @@ static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
return rv;
}
+/* when dlm_unlock() sees -EBUSY with CANCEL/FORCEUNLOCK it returns 0
+ for success */
+
+/* note: it's valid for lkb_nodeid/res_nodeid to be -1 when we get here
+ because there may be a lookup in progress and it's valid to do
+ cancel/unlockf on it */
+
static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
{
+ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
int rv = -EINVAL;
- if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+ if (lkb->lkb_flags & DLM_IFL_MSTCPY) {
+ log_error(ls, "unlock on MSTCPY %x", lkb->lkb_id);
+ dlm_print_lkb(lkb);
goto out;
+ }
- if (args->flags & DLM_LKF_FORCEUNLOCK)
- goto out_ok;
+ /* an lkb may still exist even though the lock is EOL'ed due to a
+ cancel, unlock or failed noqueue request; an app can't use these
+ locks; return same error as if the lkid had not been found at all */
- if (args->flags & DLM_LKF_CANCEL &&
- lkb->lkb_status == DLM_LKSTS_GRANTED)
+ if (lkb->lkb_flags & DLM_IFL_ENDOFLIFE) {
+ log_debug(ls, "unlock on ENDOFLIFE %x", lkb->lkb_id);
+ rv = -ENOENT;
goto out;
+ }
- if (!(args->flags & DLM_LKF_CANCEL) &&
- lkb->lkb_status != DLM_LKSTS_GRANTED)
- goto out;
+ /* an lkb may be waiting for an rsb lookup to complete where the
+ lookup was initiated by another lock */
+
+ if (args->flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)) {
+ if (!list_empty(&lkb->lkb_rsb_lookup)) {
+ log_debug(ls, "unlock on rsb_lookup %x", lkb->lkb_id);
+ list_del_init(&lkb->lkb_rsb_lookup);
+ queue_cast(lkb->lkb_resource, lkb,
+ args->flags & DLM_LKF_CANCEL ?
+ -DLM_ECANCEL : -DLM_EUNLOCK);
+ unhold_lkb(lkb); /* undoes create_lkb() */
+ rv = -EBUSY;
+ goto out;
+ }
+ }
+
+ /* cancel not allowed with another cancel/unlock in progress */
+
+ if (args->flags & DLM_LKF_CANCEL) {
+ if (lkb->lkb_exflags & DLM_LKF_CANCEL)
+ goto out;
+
+ if (is_overlap(lkb))
+ goto out;
+
+ if (lkb->lkb_flags & DLM_IFL_RESEND) {
+ lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
+ rv = -EBUSY;
+ goto out;
+ }
+
+ switch (lkb->lkb_wait_type) {
+ case DLM_MSG_LOOKUP:
+ case DLM_MSG_REQUEST:
+ lkb->lkb_flags |= DLM_IFL_OVERLAP_CANCEL;
+ rv = -EBUSY;
+ goto out;
+ case DLM_MSG_UNLOCK:
+ case DLM_MSG_CANCEL:
+ goto out;
+ }
+ /* add_to_waiters() will set OVERLAP_CANCEL */
+ goto out_ok;
+ }
+
+ /* do we need to allow a force-unlock if there's a normal unlock
+ already in progress? in what conditions could the normal unlock
+ fail such that we'd want to send a force-unlock to be sure? */
+
+ if (args->flags & DLM_LKF_FORCEUNLOCK) {
+ if (lkb->lkb_exflags & DLM_LKF_FORCEUNLOCK)
+ goto out;
+
+ if (is_overlap_unlock(lkb))
+ goto out;
+ if (lkb->lkb_flags & DLM_IFL_RESEND) {
+ lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
+ rv = -EBUSY;
+ goto out;
+ }
+
+ switch (lkb->lkb_wait_type) {
+ case DLM_MSG_LOOKUP:
+ case DLM_MSG_REQUEST:
+ lkb->lkb_flags |= DLM_IFL_OVERLAP_UNLOCK;
+ rv = -EBUSY;
+ goto out;
+ case DLM_MSG_UNLOCK:
+ goto out;
+ }
+ /* add_to_waiters() will set OVERLAP_UNLOCK */
+ goto out_ok;
+ }
+
+ /* normal unlock not allowed if there's any op in progress */
rv = -EBUSY;
- if (lkb->lkb_wait_type)
+ if (lkb->lkb_wait_type || lkb->lkb_wait_count)
goto out;
out_ok:
- lkb->lkb_exflags = args->flags;
+ /* an overlapping op shouldn't blow away exflags from other op */
+ lkb->lkb_exflags |= args->flags;
lkb->lkb_sbflags = 0;
lkb->lkb_astparam = args->astparam;
-
rv = 0;
out:
+ if (rv)
+ log_debug(ls, "validate_unlock_args %d %x %x %x %x %d %s", rv,
+ lkb->lkb_id, lkb->lkb_flags, lkb->lkb_exflags,
+ args->flags, lkb->lkb_wait_type,
+ lkb->lkb_resource->res_name);
return rv;
}
@@ -1732,9 +2019,24 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
goto out;
}
- if (can_be_queued(lkb)) {
- if (is_demoted(lkb))
+ /* is_demoted() means the can_be_granted() above set the grmode
+ to NL, and left us on the granted queue. This auto-demotion
+ (due to CONVDEADLK) might mean other locks, and/or this lock, are
+ now grantable. We have to try to grant other converting locks
+ before we try again to grant this one. */
+
+ if (is_demoted(lkb)) {
+ grant_pending_convert(r, DLM_LOCK_IV);
+ if (_can_be_granted(r, lkb, 1)) {
+ grant_lock(r, lkb);
+ queue_cast(r, lkb, 0);
grant_pending_locks(r);
+ goto out;
+ }
+ /* else fall through and move to convert queue */
+ }
+
+ if (can_be_queued(lkb)) {
error = -EINPROGRESS;
del_lkb(r, lkb);
add_lkb(r, lkb, DLM_LKSTS_CONVERT);
@@ -1759,17 +2061,19 @@ static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
return -DLM_EUNLOCK;
}
-/* FIXME: if revert_lock() finds that the lkb is granted, we should
- skip the queue_cast(ECANCEL). It indicates that the request/convert
- completed (and queued a normal ast) just before the cancel; we don't
- want to clobber the sb_result for the normal ast with ECANCEL. */
+/* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
- revert_lock(r, lkb);
- queue_cast(r, lkb, -DLM_ECANCEL);
- grant_pending_locks(r);
- return -DLM_ECANCEL;
+ int error;
+
+ error = revert_lock(r, lkb);
+ if (error) {
+ queue_cast(r, lkb, -DLM_ECANCEL);
+ grant_pending_locks(r);
+ return -DLM_ECANCEL;
+ }
+ return 0;
}
/*
@@ -2035,6 +2339,8 @@ int dlm_unlock(dlm_lockspace_t *lockspace,
if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
error = 0;
+ if (error == -EBUSY && (flags & (DLM_LKF_CANCEL | DLM_LKF_FORCEUNLOCK)))
+ error = 0;
out_put:
dlm_put_lkb(lkb);
out:
@@ -2065,31 +2371,14 @@ int dlm_unlock(dlm_lockspace_t *lockspace,
* receive_lookup_reply send_lookup_reply
*/
-static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
- int to_nodeid, int mstype,
- struct dlm_message **ms_ret,
- struct dlm_mhandle **mh_ret)
+static int _create_message(struct dlm_ls *ls, int mb_len,
+ int to_nodeid, int mstype,
+ struct dlm_message **ms_ret,
+ struct dlm_mhandle **mh_ret)
{
struct dlm_message *ms;
struct dlm_mhandle *mh;
char *mb;
- int mb_len = sizeof(struct dlm_message);
-
- switch (mstype) {
- case DLM_MSG_REQUEST:
- case DLM_MSG_LOOKUP:
- case DLM_MSG_REMOVE:
- mb_len += r->res_length;
- break;
- case DLM_MSG_CONVERT:
- case DLM_MSG_UNLOCK:
- case DLM_MSG_REQUEST_REPLY:
- case DLM_MSG_CONVERT_REPLY:
- case DLM_MSG_GRANT:
- if (lkb && lkb->lkb_lvbptr)
- mb_len += r->res_ls->ls_lvblen;
- break;
- }
/* get_buffer gives us a message handle (mh) that we need to
pass into lowcomms_commit and a message buffer (mb) that we
@@ -2104,7 +2393,7 @@ static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
ms = (struct dlm_message *) mb;
ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
- ms->m_header.h_lockspace = r->res_ls->ls_global_id;
+ ms->m_header.h_lockspace = ls->ls_global_id;
ms->m_header.h_nodeid = dlm_our_nodeid();
ms->m_header.h_length = mb_len;
ms->m_header.h_cmd = DLM_MSG;
@@ -2116,6 +2405,33 @@ static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
return 0;
}
+static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ int to_nodeid, int mstype,
+ struct dlm_message **ms_ret,
+ struct dlm_mhandle **mh_ret)
+{
+ int mb_len = sizeof(struct dlm_message);
+
+ switch (mstype) {
+ case DLM_MSG_REQUEST:
+ case DLM_MSG_LOOKUP:
+ case DLM_MSG_REMOVE:
+ mb_len += r->res_length;
+ break;
+ case DLM_MSG_CONVERT:
+ case DLM_MSG_UNLOCK:
+ case DLM_MSG_REQUEST_REPLY:
+ case DLM_MSG_CONVERT_REPLY:
+ case DLM_MSG_GRANT:
+ if (lkb && lkb->lkb_lvbptr)
+ mb_len += r->res_ls->ls_lvblen;
+ break;
+ }
+
+ return _create_message(r->res_ls, mb_len, to_nodeid, mstype,
+ ms_ret, mh_ret);
+}
+
/* further lowcomms enhancements or alternate implementations may make
the return value from this function useful at some point */
@@ -2176,7 +2492,9 @@ static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
struct dlm_mhandle *mh;
int to_nodeid, error;
- add_to_waiters(lkb, mstype);
+ error = add_to_waiters(lkb, mstype);
+ if (error)
+ return error;
to_nodeid = r->res_nodeid;
@@ -2192,7 +2510,7 @@ static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
return 0;
fail:
- remove_from_waiters(lkb);
+ remove_from_waiters(lkb, msg_reply_type(mstype));
return error;
}
@@ -2209,7 +2527,8 @@ static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
/* down conversions go without a reply from the master */
if (!error && down_conversion(lkb)) {
- remove_from_waiters(lkb);
+ remove_from_waiters(lkb, DLM_MSG_CONVERT_REPLY);
+ r->res_ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
r->res_ls->ls_stub_ms.m_result = 0;
r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;
__receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
@@ -2280,7 +2599,9 @@ static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
struct dlm_mhandle *mh;
int to_nodeid, error;
- add_to_waiters(lkb, DLM_MSG_LOOKUP);
+ error = add_to_waiters(lkb, DLM_MSG_LOOKUP);
+ if (error)
+ return error;
to_nodeid = dlm_dir_nodeid(r);
@@ -2296,7 +2617,7 @@ static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
return 0;
fail:
- remove_from_waiters(lkb);
+ remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);
return error;
}
@@ -2656,6 +2977,8 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
lock_rsb(r);
receive_flags_reply(lkb, ms);
+ if (is_altmode(lkb))
+ munge_altmode(lkb, ms);
grant_lock_pc(r, lkb, ms);
queue_cast(r, lkb, 0);
@@ -2736,11 +3059,16 @@ static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)
dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
}
+static void receive_purge(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ do_purge(ls, ms->m_nodeid, ms->m_pid);
+}
+
static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
- int error, mstype;
+ int error, mstype, result;
error = find_lkb(ls, ms->m_remid, &lkb);
if (error) {
@@ -2749,20 +3077,15 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
}
DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
- mstype = lkb->lkb_wait_type;
- error = remove_from_waiters(lkb);
- if (error) {
- log_error(ls, "receive_request_reply not on waiters");
- goto out;
- }
-
- /* this is the value returned from do_request() on the master */
- error = ms->m_result;
-
r = lkb->lkb_resource;
hold_rsb(r);
lock_rsb(r);
+ mstype = lkb->lkb_wait_type;
+ error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
+ if (error)
+ goto out;
+
/* Optimization: the dir node was also the master, so it took our
lookup as a request and sent request reply instead of lookup reply */
if (mstype == DLM_MSG_LOOKUP) {
@@ -2770,14 +3093,15 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
lkb->lkb_nodeid = r->res_nodeid;
}
- switch (error) {
+ /* this is the value returned from do_request() on the master */
+ result = ms->m_result;
+
+ switch (result) {
case -EAGAIN:
- /* request would block (be queued) on remote master;
- the unhold undoes the original ref from create_lkb()
- so it leads to the lkb being freed */
+ /* request would block (be queued) on remote master */
queue_cast(r, lkb, -EAGAIN);
confirm_master(r, -EAGAIN);
- unhold_lkb(lkb);
+ unhold_lkb(lkb); /* undoes create_lkb() */
break;
case -EINPROGRESS:
@@ -2785,41 +3109,64 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
/* request was queued or granted on remote master */
receive_flags_reply(lkb, ms);
lkb->lkb_remid = ms->m_lkid;
- if (error)
+ if (is_altmode(lkb))
+ munge_altmode(lkb, ms);
+ if (result)
add_lkb(r, lkb, DLM_LKSTS_WAITING);
else {
grant_lock_pc(r, lkb, ms);
queue_cast(r, lkb, 0);
}
- confirm_master(r, error);
+ confirm_master(r, result);
break;
case -EBADR:
case -ENOTBLK:
/* find_rsb failed to find rsb or rsb wasn't master */
+ log_debug(ls, "receive_request_reply %x %x master diff %d %d",
+ lkb->lkb_id, lkb->lkb_flags, r->res_nodeid, result);
r->res_nodeid = -1;
lkb->lkb_nodeid = -1;
- _request_lock(r, lkb);
+
+ if (is_overlap(lkb)) {
+ /* we'll ignore error in cancel/unlock reply */
+ queue_cast_overlap(r, lkb);
+ unhold_lkb(lkb); /* undoes create_lkb() */
+ } else
+ _request_lock(r, lkb);
break;
default:
- log_error(ls, "receive_request_reply error %d", error);
+ log_error(ls, "receive_request_reply %x error %d",
+ lkb->lkb_id, result);
}
+ if (is_overlap_unlock(lkb) && (result == 0 || result == -EINPROGRESS)) {
+ log_debug(ls, "receive_request_reply %x result %d unlock",
+ lkb->lkb_id, result);
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+ send_unlock(r, lkb);
+ } else if (is_overlap_cancel(lkb) && (result == -EINPROGRESS)) {
+ log_debug(ls, "receive_request_reply %x cancel", lkb->lkb_id);
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+ send_cancel(r, lkb);
+ } else {
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+ }
+ out:
unlock_rsb(r);
put_rsb(r);
- out:
dlm_put_lkb(lkb);
}
static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
struct dlm_message *ms)
{
- int error = ms->m_result;
-
/* this is the value returned from do_convert() on the master */
-
- switch (error) {
+ switch (ms->m_result) {
case -EAGAIN:
/* convert would block (be queued) on remote master */
queue_cast(r, lkb, -EAGAIN);
@@ -2827,6 +3174,9 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
case -EINPROGRESS:
/* convert was queued on remote master */
+ receive_flags_reply(lkb, ms);
+ if (is_demoted(lkb))
+ munge_demoted(lkb, ms);
del_lkb(r, lkb);
add_lkb(r, lkb, DLM_LKSTS_CONVERT);
break;
@@ -2834,24 +3184,33 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
case 0:
/* convert was granted on remote master */
receive_flags_reply(lkb, ms);
+ if (is_demoted(lkb))
+ munge_demoted(lkb, ms);
grant_lock_pc(r, lkb, ms);
queue_cast(r, lkb, 0);
break;
default:
- log_error(r->res_ls, "receive_convert_reply error %d", error);
+ log_error(r->res_ls, "receive_convert_reply %x error %d",
+ lkb->lkb_id, ms->m_result);
}
}
static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
{
struct dlm_rsb *r = lkb->lkb_resource;
+ int error;
hold_rsb(r);
lock_rsb(r);
- __receive_convert_reply(r, lkb, ms);
+ /* stub reply can happen with waiters_mutex held */
+ error = remove_from_waiters_ms(lkb, ms);
+ if (error)
+ goto out;
+ __receive_convert_reply(r, lkb, ms);
+ out:
unlock_rsb(r);
put_rsb(r);
}
@@ -2868,37 +3227,38 @@ static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
}
DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
- error = remove_from_waiters(lkb);
- if (error) {
- log_error(ls, "receive_convert_reply not on waiters");
- goto out;
- }
-
_receive_convert_reply(lkb, ms);
- out:
dlm_put_lkb(lkb);
}
static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
{
struct dlm_rsb *r = lkb->lkb_resource;
- int error = ms->m_result;
+ int error;
hold_rsb(r);
lock_rsb(r);
+ /* stub reply can happen with waiters_mutex held */
+ error = remove_from_waiters_ms(lkb, ms);
+ if (error)
+ goto out;
+
/* this is the value returned from do_unlock() on the master */
- switch (error) {
+ switch (ms->m_result) {
case -DLM_EUNLOCK:
receive_flags_reply(lkb, ms);
remove_lock_pc(r, lkb);
queue_cast(r, lkb, -DLM_EUNLOCK);
break;
+ case -ENOENT:
+ break;
default:
- log_error(r->res_ls, "receive_unlock_reply error %d", error);
+ log_error(r->res_ls, "receive_unlock_reply %x error %d",
+ lkb->lkb_id, ms->m_result);
}
-
+ out:
unlock_rsb(r);
put_rsb(r);
}
@@ -2915,37 +3275,39 @@ static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
}
DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
- error = remove_from_waiters(lkb);
- if (error) {
- log_error(ls, "receive_unlock_reply not on waiters");
- goto out;
- }
-
_receive_unlock_reply(lkb, ms);
- out:
dlm_put_lkb(lkb);
}
static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
{
struct dlm_rsb *r = lkb->lkb_resource;
- int error = ms->m_result;
+ int error;
hold_rsb(r);
lock_rsb(r);
+ /* stub reply can happen with waiters_mutex held */
+ error = remove_from_waiters_ms(lkb, ms);
+ if (error)
+ goto out;
+
/* this is the value returned from do_cancel() on the master */
- switch (error) {
+ switch (ms->m_result) {
case -DLM_ECANCEL:
receive_flags_reply(lkb, ms);
revert_lock_pc(r, lkb);
- queue_cast(r, lkb, -DLM_ECANCEL);
+ if (ms->m_result)
+ queue_cast(r, lkb, -DLM_ECANCEL);
+ break;
+ case 0:
break;
default:
- log_error(r->res_ls, "receive_cancel_reply error %d", error);
+ log_error(r->res_ls, "receive_cancel_reply %x error %d",
+ lkb->lkb_id, ms->m_result);
}
-
+ out:
unlock_rsb(r);
put_rsb(r);
}
@@ -2962,14 +3324,7 @@ static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
}
DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
- error = remove_from_waiters(lkb);
- if (error) {
- log_error(ls, "receive_cancel_reply not on waiters");
- goto out;
- }
-
_receive_cancel_reply(lkb, ms);
- out:
dlm_put_lkb(lkb);
}
@@ -2985,20 +3340,17 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
return;
}
- error = remove_from_waiters(lkb);
- if (error) {
- log_error(ls, "receive_lookup_reply not on waiters");
- goto out;
- }
-
- /* this is the value returned by dlm_dir_lookup on dir node
+ /* ms->m_result is the value returned by dlm_dir_lookup on dir node
FIXME: will a non-zero error ever be returned? */
- error = ms->m_result;
r = lkb->lkb_resource;
hold_rsb(r);
lock_rsb(r);
+ error = remove_from_waiters(lkb, DLM_MSG_LOOKUP_REPLY);
+ if (error)
+ goto out;
+
ret_nodeid = ms->m_nodeid;
if (ret_nodeid == dlm_our_nodeid()) {
r->res_nodeid = 0;
@@ -3009,14 +3361,22 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
r->res_nodeid = ret_nodeid;
}
+ if (is_overlap(lkb)) {
+ log_debug(ls, "receive_lookup_reply %x unlock %x",
+ lkb->lkb_id, lkb->lkb_flags);
+ queue_cast_overlap(r, lkb);
+ unhold_lkb(lkb); /* undoes create_lkb() */
+ goto out_list;
+ }
+
_request_lock(r, lkb);
+ out_list:
if (!ret_nodeid)
process_lookup_list(r);
-
+ out:
unlock_rsb(r);
put_rsb(r);
- out:
dlm_put_lkb(lkb);
}
@@ -3133,6 +3493,12 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
receive_lookup_reply(ls, ms);
break;
+ /* other messages */
+
+ case DLM_MSG_PURGE:
+ receive_purge(ls, ms);
+ break;
+
default:
log_error(ls, "unknown message type %d", ms->m_type);
}
@@ -3153,9 +3519,9 @@ static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
{
if (middle_conversion(lkb)) {
hold_lkb(lkb);
+ ls->ls_stub_ms.m_type = DLM_MSG_CONVERT_REPLY;
ls->ls_stub_ms.m_result = -EINPROGRESS;
ls->ls_stub_ms.m_flags = lkb->lkb_flags;
- _remove_from_waiters(lkb);
_receive_convert_reply(lkb, &ls->ls_stub_ms);
/* Same special case as in receive_rcom_lock_args() */
@@ -3227,18 +3593,18 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
case DLM_MSG_UNLOCK:
hold_lkb(lkb);
+ ls->ls_stub_ms.m_type = DLM_MSG_UNLOCK_REPLY;
ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
ls->ls_stub_ms.m_flags = lkb->lkb_flags;
- _remove_from_waiters(lkb);
_receive_unlock_reply(lkb, &ls->ls_stub_ms);
dlm_put_lkb(lkb);
break;
case DLM_MSG_CANCEL:
hold_lkb(lkb);
+ ls->ls_stub_ms.m_type = DLM_MSG_CANCEL_REPLY;
ls->ls_stub_ms.m_result = -DLM_ECANCEL;
ls->ls_stub_ms.m_flags = lkb->lkb_flags;
- _remove_from_waiters(lkb);
_receive_cancel_reply(lkb, &ls->ls_stub_ms);
dlm_put_lkb(lkb);
break;
@@ -3252,37 +3618,47 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
mutex_unlock(&ls->ls_waiters_mutex);
}
-static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+static struct dlm_lkb *find_resend_waiter(struct dlm_ls *ls)
{
struct dlm_lkb *lkb;
- int rv = 0;
+ int found = 0;
mutex_lock(&ls->ls_waiters_mutex);
list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
if (lkb->lkb_flags & DLM_IFL_RESEND) {
- rv = lkb->lkb_wait_type;
- _remove_from_waiters(lkb);
- lkb->lkb_flags &= ~DLM_IFL_RESEND;
+ hold_lkb(lkb);
+ found = 1;
break;
}
}
mutex_unlock(&ls->ls_waiters_mutex);
- if (!rv)
+ if (!found)
lkb = NULL;
- *lkb_ret = lkb;
- return rv;
+ return lkb;
}
/* Deal with lookups and lkb's marked RESEND from _pre. We may now be the
master or dir-node for r. Processing the lkb may result in it being placed
back on waiters. */
+/* We do this after normal locking has been enabled and any saved messages
+ (in requestqueue) have been processed. We should be confident that at
+ this point we won't get or process a reply to any of these waiting
+ operations. But, new ops may be coming in on the rsbs/locks here from
+ userspace or remotely. */
+
+/* there may have been an overlap unlock/cancel prior to recovery or after
+ recovery. if before, the lkb may still have a pos wait_count; if after, the
+ overlap flag would just have been set and nothing new sent. we can be
+ confident here than any replies to either the initial op or overlap ops
+ prior to recovery have been received. */
+
int dlm_recover_waiters_post(struct dlm_ls *ls)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
- int error = 0, mstype;
+ int error = 0, mstype, err, oc, ou;
while (1) {
if (dlm_locking_stopped(ls)) {
@@ -3291,48 +3667,78 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
break;
}
- mstype = remove_resend_waiter(ls, &lkb);
- if (!mstype)
+ lkb = find_resend_waiter(ls);
+ if (!lkb)
break;
r = lkb->lkb_resource;
+ hold_rsb(r);
+ lock_rsb(r);
+
+ mstype = lkb->lkb_wait_type;
+ oc = is_overlap_cancel(lkb);
+ ou = is_overlap_unlock(lkb);
+ err = 0;
log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
- switch (mstype) {
-
- case DLM_MSG_LOOKUP:
- hold_rsb(r);
- lock_rsb(r);
- _request_lock(r, lkb);
- if (is_master(r))
- confirm_master(r, 0);
- unlock_rsb(r);
- put_rsb(r);
- break;
-
- case DLM_MSG_REQUEST:
- hold_rsb(r);
- lock_rsb(r);
- _request_lock(r, lkb);
- if (is_master(r))
- confirm_master(r, 0);
- unlock_rsb(r);
- put_rsb(r);
- break;
-
- case DLM_MSG_CONVERT:
- hold_rsb(r);
- lock_rsb(r);
- _convert_lock(r, lkb);
- unlock_rsb(r);
- put_rsb(r);
- break;
-
- default:
- log_error(ls, "recover_waiters_post type %d", mstype);
+ /* At this point we assume that we won't get a reply to any
+ previous op or overlap op on this lock. First, do a big
+ remove_from_waiters() for all previous ops. */
+
+ lkb->lkb_flags &= ~DLM_IFL_RESEND;
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_UNLOCK;
+ lkb->lkb_flags &= ~DLM_IFL_OVERLAP_CANCEL;
+ lkb->lkb_wait_type = 0;
+ lkb->lkb_wait_count = 0;
+ mutex_lock(&ls->ls_waiters_mutex);
+ list_del_init(&lkb->lkb_wait_reply);
+ mutex_unlock(&ls->ls_waiters_mutex);
+ unhold_lkb(lkb); /* for waiters list */
+
+ if (oc || ou) {
+ /* do an unlock or cancel instead of resending */
+ switch (mstype) {
+ case DLM_MSG_LOOKUP:
+ case DLM_MSG_REQUEST:
+ queue_cast(r, lkb, ou ? -DLM_EUNLOCK :
+ -DLM_ECANCEL);
+ unhold_lkb(lkb); /* undoes create_lkb() */
+ break;
+ case DLM_MSG_CONVERT:
+ if (oc) {
+ queue_cast(r, lkb, -DLM_ECANCEL);
+ } else {
+ lkb->lkb_exflags |= DLM_LKF_FORCEUNLOCK;
+ _unlock_lock(r, lkb);
+ }
+ break;
+ default:
+ err = 1;
+ }
+ } else {
+ switch (mstype) {
+ case DLM_MSG_LOOKUP:
+ case DLM_MSG_REQUEST:
+ _request_lock(r, lkb);
+ if (is_master(r))
+ confirm_master(r, 0);
+ break;
+ case DLM_MSG_CONVERT:
+ _convert_lock(r, lkb);
+ break;
+ default:
+ err = 1;
+ }
}
+
+ if (err)
+ log_error(ls, "recover_waiters_post %x %d %x %d %d",
+ lkb->lkb_id, mstype, lkb->lkb_flags, oc, ou);
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
}
return error;
@@ -3684,7 +4090,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
/* add this new lkb to the per-process list of locks */
spin_lock(&ua->proc->locks_spin);
- kref_get(&lkb->lkb_ref);
+ hold_lkb(lkb);
list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
spin_unlock(&ua->proc->locks_spin);
out:
@@ -3774,6 +4180,9 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
if (error == -DLM_EUNLOCK)
error = 0;
+ /* from validate_unlock_args() */
+ if (error == -EBUSY && (flags & DLM_LKF_FORCEUNLOCK))
+ error = 0;
if (error)
goto out_put;
@@ -3786,6 +4195,7 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
dlm_put_lkb(lkb);
out:
unlock_recovery(ls);
+ kfree(ua_tmp);
return error;
}
@@ -3815,33 +4225,37 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
if (error == -DLM_ECANCEL)
error = 0;
- if (error)
- goto out_put;
-
- /* this lkb was removed from the WAITING queue */
- if (lkb->lkb_grmode == DLM_LOCK_IV) {
- spin_lock(&ua->proc->locks_spin);
- list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
- spin_unlock(&ua->proc->locks_spin);
- }
+ /* from validate_unlock_args() */
+ if (error == -EBUSY)
+ error = 0;
out_put:
dlm_put_lkb(lkb);
out:
unlock_recovery(ls);
+ kfree(ua_tmp);
return error;
}
+/* lkb's that are removed from the waiters list by revert are just left on the
+ orphans list with the granted orphan locks, to be freed by purge */
+
static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
{
struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
+ struct dlm_args args;
+ int error;
- if (ua->lksb.sb_lvbptr)
- kfree(ua->lksb.sb_lvbptr);
- kfree(ua);
- lkb->lkb_astparam = (long)NULL;
+ hold_lkb(lkb);
+ mutex_lock(&ls->ls_orphans_mutex);
+ list_add_tail(&lkb->lkb_ownqueue, &ls->ls_orphans);
+ mutex_unlock(&ls->ls_orphans_mutex);
- /* TODO: propogate to master if needed */
- return 0;
+ set_unlock_args(0, ua, &args);
+
+ error = cancel_lock(ls, lkb, &args);
+ if (error == -DLM_ECANCEL)
+ error = 0;
+ return error;
}
/* The force flag allows the unlock to go ahead even if the lkb isn't granted.
@@ -3853,10 +4267,6 @@ static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
struct dlm_args args;
int error;
- /* FIXME: we need to handle the case where the lkb is in limbo
- while the rsb is being looked up, currently we assert in
- _unlock_lock/is_remote because rsb nodeid is -1. */
-
set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args);
error = unlock_lock(ls, lkb, &args);
@@ -3865,6 +4275,31 @@ static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
return error;
}
+/* We have to release clear_proc_locks mutex before calling unlock_proc_lock()
+ (which does lock_rsb) due to deadlock with receiving a message that does
+ lock_rsb followed by dlm_user_add_ast() */
+
+static struct dlm_lkb *del_proc_lock(struct dlm_ls *ls,
+ struct dlm_user_proc *proc)
+{
+ struct dlm_lkb *lkb = NULL;
+
+ mutex_lock(&ls->ls_clear_proc_locks);
+ if (list_empty(&proc->locks))
+ goto out;
+
+ lkb = list_entry(proc->locks.next, struct dlm_lkb, lkb_ownqueue);
+ list_del_init(&lkb->lkb_ownqueue);
+
+ if (lkb->lkb_exflags & DLM_LKF_PERSISTENT)
+ lkb->lkb_flags |= DLM_IFL_ORPHAN;
+ else
+ lkb->lkb_flags |= DLM_IFL_DEAD;
+ out:
+ mutex_unlock(&ls->ls_clear_proc_locks);
+ return lkb;
+}
+
/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which
1) references lkb->ua which we free here and 2) adds lkbs to proc->asts,
which we clear here. */
@@ -3880,18 +4315,15 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
struct dlm_lkb *lkb, *safe;
lock_recovery(ls);
- mutex_lock(&ls->ls_clear_proc_locks);
- list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) {
- list_del_init(&lkb->lkb_ownqueue);
-
- if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
- lkb->lkb_flags |= DLM_IFL_ORPHAN;
+ while (1) {
+ lkb = del_proc_lock(ls, proc);
+ if (!lkb)
+ break;
+ if (lkb->lkb_exflags & DLM_LKF_PERSISTENT)
orphan_proc_lock(ls, lkb);
- } else {
- lkb->lkb_flags |= DLM_IFL_DEAD;
+ else
unlock_proc_lock(ls, lkb);
- }
/* this removes the reference for the proc->locks list
added by dlm_user_request, it may result in the lkb
@@ -3900,6 +4332,8 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
dlm_put_lkb(lkb);
}
+ mutex_lock(&ls->ls_clear_proc_locks);
+
/* in-progress unlocks */
list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
list_del_init(&lkb->lkb_ownqueue);
@@ -3916,3 +4350,92 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
unlock_recovery(ls);
}
+static void purge_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
+{
+ struct dlm_lkb *lkb, *safe;
+
+ while (1) {
+ lkb = NULL;
+ spin_lock(&proc->locks_spin);
+ if (!list_empty(&proc->locks)) {
+ lkb = list_entry(proc->locks.next, struct dlm_lkb,
+ lkb_ownqueue);
+ list_del_init(&lkb->lkb_ownqueue);
+ }
+ spin_unlock(&proc->locks_spin);
+
+ if (!lkb)
+ break;
+
+ lkb->lkb_flags |= DLM_IFL_DEAD;
+ unlock_proc_lock(ls, lkb);
+ dlm_put_lkb(lkb); /* ref from proc->locks list */
+ }
+
+ spin_lock(&proc->locks_spin);
+ list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
+ list_del_init(&lkb->lkb_ownqueue);
+ lkb->lkb_flags |= DLM_IFL_DEAD;
+ dlm_put_lkb(lkb);
+ }
+ spin_unlock(&proc->locks_spin);
+
+ spin_lock(&proc->asts_spin);
+ list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
+ list_del(&lkb->lkb_astqueue);
+ dlm_put_lkb(lkb);
+ }
+ spin_unlock(&proc->asts_spin);
+}
+
+/* pid of 0 means purge all orphans */
+
+static void do_purge(struct dlm_ls *ls, int nodeid, int pid)
+{
+ struct dlm_lkb *lkb, *safe;
+
+ mutex_lock(&ls->ls_orphans_mutex);
+ list_for_each_entry_safe(lkb, safe, &ls->ls_orphans, lkb_ownqueue) {
+ if (pid && lkb->lkb_ownpid != pid)
+ continue;
+ unlock_proc_lock(ls, lkb);
+ list_del_init(&lkb->lkb_ownqueue);
+ dlm_put_lkb(lkb);
+ }
+ mutex_unlock(&ls->ls_orphans_mutex);
+}
+
+static int send_purge(struct dlm_ls *ls, int nodeid, int pid)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int error;
+
+ error = _create_message(ls, sizeof(struct dlm_message), nodeid,
+ DLM_MSG_PURGE, &ms, &mh);
+ if (error)
+ return error;
+ ms->m_nodeid = nodeid;
+ ms->m_pid = pid;
+
+ return send_message(mh, ms);
+}
+
+int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
+ int nodeid, int pid)
+{
+ int error = 0;
+
+ if (nodeid != dlm_our_nodeid()) {
+ error = send_purge(ls, nodeid, pid);
+ } else {
+ lock_recovery(ls);
+ if (pid == current->pid)
+ purge_proc_locks(ls, proc);
+ else
+ do_purge(ls, nodeid, pid);
+ unlock_recovery(ls);
+ }
+ return error;
+}
+
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 0843a3073ec..64fc4ec4066 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -41,6 +41,8 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
uint32_t flags, uint32_t lkid, char *lvb_in);
int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
uint32_t flags, uint32_t lkid);
+int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
+ int nodeid, int pid);
void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);
static inline int is_master(struct dlm_rsb *r)
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index f40817b53c6..a677b2a5eed 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -2,7 +2,7 @@
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+** Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
@@ -167,7 +167,6 @@ static struct kobj_type dlm_ktype = {
};
static struct kset dlm_kset = {
- .subsys = &kernel_subsys,
.kobj = {.name = "dlm",},
.ktype = &dlm_ktype,
};
@@ -218,6 +217,7 @@ int dlm_lockspace_init(void)
INIT_LIST_HEAD(&lslist);
spin_lock_init(&lslist_lock);
+ kobj_set_kset_s(&dlm_kset, kernel_subsys);
error = kset_register(&dlm_kset);
if (error)
printk("dlm_lockspace_init: cannot register kset %d\n", error);
@@ -459,6 +459,8 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
INIT_LIST_HEAD(&ls->ls_waiters);
mutex_init(&ls->ls_waiters_mutex);
+ INIT_LIST_HEAD(&ls->ls_orphans);
+ mutex_init(&ls->ls_orphans_mutex);
INIT_LIST_HEAD(&ls->ls_nodes);
INIT_LIST_HEAD(&ls->ls_nodes_gone);
diff --git a/fs/dlm/lowcomms-sctp.c b/fs/dlm/lowcomms-sctp.c
deleted file mode 100644
index dc83a9d979b..00000000000
--- a/fs/dlm/lowcomms-sctp.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-/******************************************************************************
-*******************************************************************************
-**
-** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
-** Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
-**
-** This copyrighted material is made available to anyone wishing to use,
-** modify, copy, or redistribute it subject to the terms and conditions
-** of the GNU General Public License v.2.
-**
-*******************************************************************************
-******************************************************************************/
-
-/*
- * lowcomms.c
- *
- * This is the "low-level" comms layer.
- *
- * It is responsible for sending/receiving messages
- * from other nodes in the cluster.
- *
- * Cluster nodes are referred to by their nodeids. nodeids are
- * simply 32 bit numbers to the locking module - if they need to
- * be expanded for the cluster infrastructure then that is it's
- * responsibility. It is this layer's
- * responsibility to resolve these into IP address or
- * whatever it needs for inter-node communication.
- *
- * The comms level is two kernel threads that deal mainly with
- * the receiving of messages from other nodes and passing them
- * up to the mid-level comms layer (which understands the
- * message format) for execution by the locking core, and
- * a send thread which does all the setting up of connections
- * to remote nodes and the sending of data. Threads are not allowed
- * to send their own data because it may cause them to wait in times
- * of high load. Also, this way, the sending thread can collect together
- * messages bound for one node and send them in one block.
- *
- * I don't see any problem with the recv thread executing the locking
- * code on behalf of remote processes as the locking code is
- * short, efficient and never (well, hardly ever) waits.
- *
- */
-
-#include <asm/ioctls.h>
-#include <net/sock.h>
-#include <net/tcp.h>
-#include <net/sctp/user.h>
-#include <linux/pagemap.h>
-#include <linux/socket.h>
-#include <linux/idr.h>
-
-#include "dlm_internal.h"
-#include "lowcomms.h"
-#include "config.h"
-#include "midcomms.h"
-
-static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
-static int dlm_local_count;
-static int dlm_local_nodeid;
-
-/* One of these per connected node */
-
-#define NI_INIT_PENDING 1
-#define NI_WRITE_PENDING 2
-
-struct nodeinfo {
- spinlock_t lock;
- sctp_assoc_t assoc_id;
- unsigned long flags;
- struct list_head write_list; /* nodes with pending writes */
- struct list_head writequeue; /* outgoing writequeue_entries */
- spinlock_t writequeue_lock;
- int nodeid;
- struct work_struct swork; /* Send workqueue */
- struct work_struct lwork; /* Locking workqueue */
-};
-
-static DEFINE_IDR(nodeinfo_idr);
-static DECLARE_RWSEM(nodeinfo_lock);
-static int max_nodeid;
-
-struct cbuf {
- unsigned int base;
- unsigned int len;
- unsigned int mask;
-};
-
-/* Just the one of these, now. But this struct keeps
- the connection-specific variables together */
-
-#define CF_READ_PENDING 1
-
-struct connection {
- struct socket *sock;
- unsigned long flags;
- struct page *rx_page;
- atomic_t waiting_requests;
- struct cbuf cb;
- int eagain_flag;
- struct work_struct work; /* Send workqueue */
-};
-
-/* An entry waiting to be sent */
-
-struct writequeue_entry {
- struct list_head list;
- struct page *page;
- int offset;
- int len;
- int end;
- int users;
- struct nodeinfo *ni;
-};
-
-static void cbuf_add(struct cbuf *cb, int n)
-{
- cb->len += n;
-}
-
-static int cbuf_data(struct cbuf *cb)
-{
- return ((cb->base + cb->len) & cb->mask);
-}
-
-static void cbuf_init(struct cbuf *cb, int size)
-{
- cb->base = cb->len = 0;
- cb->mask = size-1;
-}
-
-static void cbuf_eat(struct cbuf *cb, int n)
-{
- cb->len -= n;
- cb->base += n;
- cb->base &= cb->mask;
-}
-
-/* List of nodes which have writes pending */
-static LIST_HEAD(write_nodes);
-static DEFINE_SPINLOCK(write_nodes_lock);
-
-
-/* Maximum number of incoming messages to process before
- * doing a schedule()
- */
-#define MAX_RX_MSG_COUNT 25
-
-/* Work queues */
-static struct workqueue_struct *recv_workqueue;
-static struct workqueue_struct *send_workqueue;
-static struct workqueue_struct *lock_workqueue;
-
-/* The SCTP connection */
-static struct connection sctp_con;
-
-static void process_send_sockets(struct work_struct *work);
-static void process_recv_sockets(struct work_struct *work);
-static void process_lock_request(struct work_struct *work);
-
-static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
-{
- struct sockaddr_storage addr;
- int error;
-
- if (!dlm_local_count)
- return -1;
-
- error = dlm_nodeid_to_addr(nodeid, &addr);
- if (error)
- return error;
-
- if (dlm_local_addr[0]->ss_family == AF_INET) {
- struct sockaddr_in *in4 = (struct sockaddr_in *) &addr;
- struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
- ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
- } else {
- struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr;
- struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
- memcpy(&ret6->sin6_addr, &in6->sin6_addr,
- sizeof(in6->sin6_addr));
- }
-
- return 0;
-}
-
-/* If alloc is 0 here we will not attempt to allocate a new
- nodeinfo struct */
-static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc)
-{
- struct nodeinfo *ni;
- int r;
- int n;
-
- down_read(&nodeinfo_lock);
- ni = idr_find(&nodeinfo_idr, nodeid);
- up_read(&nodeinfo_lock);
-
- if (ni || !alloc)
- return ni;
-
- down_write(&nodeinfo_lock);
-
- ni = idr_find(&nodeinfo_idr, nodeid);
- if (ni)
- goto out_up;
-
- r = idr_pre_get(&nodeinfo_idr, alloc);
- if (!r)
- goto out_up;
-
- ni = kmalloc(sizeof(struct nodeinfo), alloc);
- if (!ni)
- goto out_up;
-
- r = idr_get_new_above(&nodeinfo_idr, ni, nodeid, &n);
- if (r) {
- kfree(ni);
- ni = NULL;
- goto out_up;
- }
- if (n != nodeid) {
- idr_remove(&nodeinfo_idr, n);
- kfree(ni);
- ni = NULL;
- goto out_up;
- }
- memset(ni, 0, sizeof(struct nodeinfo));
- spin_lock_init(&ni->lock);
- INIT_LIST_HEAD(&ni->writequeue);
- spin_lock_init(&ni->writequeue_lock);
- INIT_WORK(&ni->lwork, process_lock_request);
- INIT_WORK(&ni->swork, process_send_sockets);
- ni->nodeid = nodeid;
-
- if (nodeid > max_nodeid)
- max_nodeid = nodeid;
-out_up:
- up_write(&nodeinfo_lock);
-
- return ni;
-}
-
-/* Don't call this too often... */
-static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
-{
- int i;
- struct nodeinfo *ni;
-
- for (i=1; i<=max_nodeid; i++) {
- ni = nodeid2nodeinfo(i, 0);
- if (ni && ni->assoc_id == assoc)
- return ni;
- }
- return NULL;
-}
-
-/* Data or notification available on socket */
-static void lowcomms_data_ready(struct sock *sk, int count_unused)
-{
- if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
- queue_work(recv_workqueue, &sctp_con.work);
-}
-
-
-/* Add the port number to an IP6 or 4 sockaddr and return the address length.
- Also padd out the struct with zeros to make comparisons meaningful */
-
-static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
- int *addr_len)
-{
- struct sockaddr_in *local4_addr;
- struct sockaddr_in6 *local6_addr;
-
- if (!dlm_local_count)
- return;
-
- if (!port) {
- if (dlm_local_addr[0]->ss_family == AF_INET) {
- local4_addr = (struct sockaddr_in *)dlm_local_addr[0];
- port = be16_to_cpu(local4_addr->sin_port);
- } else {
- local6_addr = (struct sockaddr_in6 *)dlm_local_addr[0];
- port = be16_to_cpu(local6_addr->sin6_port);
- }
- }
-
- saddr->ss_family = dlm_local_addr[0]->ss_family;
- if (dlm_local_addr[0]->ss_family == AF_INET) {
- struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
- in4_addr->sin_port = cpu_to_be16(port);
- memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
- memset(in4_addr+1, 0, sizeof(struct sockaddr_storage) -
- sizeof(struct sockaddr_in));
- *addr_len = sizeof(struct sockaddr_in);
- } else {
- struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
- in6_addr->sin6_port = cpu_to_be16(port);
- memset(in6_addr+1, 0, sizeof(struct sockaddr_storage) -
- sizeof(struct sockaddr_in6));
- *addr_len = sizeof(struct sockaddr_in6);
- }
-}
-
-/* Close the connection and tidy up */
-static void close_connection(void)
-{
- if (sctp_con.sock) {
- sock_release(sctp_con.sock);
- sctp_con.sock = NULL;
- }
-
- if (sctp_con.rx_page) {
- __free_page(sctp_con.rx_page);
- sctp_con.rx_page = NULL;
- }
-}
-
-/* We only send shutdown messages to nodes that are not part of the cluster */
-static void send_shutdown(sctp_assoc_t associd)
-{
- static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
- struct msghdr outmessage;
- struct cmsghdr *cmsg;
- struct sctp_sndrcvinfo *sinfo;
- int ret;
-
- outmessage.msg_name = NULL;
- outmessage.msg_namelen = 0;
- outmessage.msg_control = outcmsg;
- outmessage.msg_controllen = sizeof(outcmsg);
- outmessage.msg_flags = MSG_EOR;
-
- cmsg = CMSG_FIRSTHDR(&outmessage);
- cmsg->cmsg_level = IPPROTO_SCTP;
- cmsg->cmsg_type = SCTP_SNDRCV;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
- outmessage.msg_controllen = cmsg->cmsg_len;
- sinfo = CMSG_DATA(cmsg);
- memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
-
- sinfo->sinfo_flags |= MSG_EOF;
- sinfo->sinfo_assoc_id = associd;
-
- ret = kernel_sendmsg(sctp_con.sock, &outmessage, NULL, 0, 0);
-
- if (ret != 0)
- log_print("send EOF to node failed: %d", ret);
-}
-
-
-/* INIT failed but we don't know which node...
- restart INIT on all pending nodes */
-static void init_failed(void)
-{
- int i;
- struct nodeinfo *ni;
-
- for (i=1; i<=max_nodeid; i++) {
- ni = nodeid2nodeinfo(i, 0);
- if (!ni)
- continue;
-
- if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
- ni->assoc_id = 0;
- if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
- spin_lock_bh(&write_nodes_lock);
- list_add_tail(&ni->write_list, &write_nodes);
- spin_unlock_bh(&write_nodes_lock);
- queue_work(send_workqueue, &ni->swork);
- }
- }
- }
-}
-
-/* Something happened to an association */
-static void process_sctp_notification(struct msghdr *msg, char *buf)
-{
- union sctp_notification *sn = (union sctp_notification *)buf;
-
- if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
- switch (sn->sn_assoc_change.sac_state) {
-
- case SCTP_COMM_UP:
- case SCTP_RESTART:
- {
- /* Check that the new node is in the lockspace */
- struct sctp_prim prim;
- mm_segment_t fs;
- int nodeid;
- int prim_len, ret;
- int addr_len;
- struct nodeinfo *ni;
-
- /* This seems to happen when we received a connection
- * too early... or something... anyway, it happens but
- * we always seem to get a real message too, see
- * receive_from_sock */
-
- if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {
- log_print("COMM_UP for invalid assoc ID %d",
- (int)sn->sn_assoc_change.sac_assoc_id);
- init_failed();
- return;
- }
- memset(&prim, 0, sizeof(struct sctp_prim));
- prim_len = sizeof(struct sctp_prim);
- prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;
-
- fs = get_fs();
- set_fs(get_ds());
- ret = sctp_con.sock->ops->getsockopt(sctp_con.sock,
- IPPROTO_SCTP,
- SCTP_PRIMARY_ADDR,
- (char*)&prim,
- &prim_len);
- set_fs(fs);
- if (ret < 0) {
- struct nodeinfo *ni;
-
- log_print("getsockopt/sctp_primary_addr on "
- "new assoc %d failed : %d",
- (int)sn->sn_assoc_change.sac_assoc_id,
- ret);
-
- /* Retry INIT later */
- ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
- if (ni)
- clear_bit(NI_INIT_PENDING, &ni->flags);
- return;
- }
- make_sockaddr(&prim.ssp_addr, 0, &addr_len);
- if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
- log_print("reject connect from unknown addr");
- send_shutdown(prim.ssp_assoc_id);
- return;
- }
-
- ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
- if (!ni)
- return;
-
- /* Save the assoc ID */
- ni->assoc_id = sn->sn_assoc_change.sac_assoc_id;
-
- log_print("got new/restarted association %d nodeid %d",
- (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
-
- /* Send any pending writes */
- clear_bit(NI_INIT_PENDING, &ni->flags);
- if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
- spin_lock_bh(&write_nodes_lock);
- list_add_tail(&ni->write_list, &write_nodes);
- spin_unlock_bh(&write_nodes_lock);
- queue_work(send_workqueue, &ni->swork);
- }
- }
- break;
-
- case SCTP_COMM_LOST:
- case SCTP_SHUTDOWN_COMP:
- {
- struct nodeinfo *ni;
-
- ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
- if (ni) {
- spin_lock(&ni->lock);
- ni->assoc_id = 0;
- spin_unlock(&ni->lock);
- }
- }
- break;
-
- /* We don't know which INIT failed, so clear the PENDING flags
- * on them all. if assoc_id is zero then it will then try
- * again */
-
- case SCTP_CANT_STR_ASSOC:
- {
- log_print("Can't start SCTP association - retrying");
- init_failed();
- }
- break;
-
- default:
- log_print("unexpected SCTP assoc change id=%d state=%d",
- (int)sn->sn_assoc_change.sac_assoc_id,
- sn->sn_assoc_change.sac_state);
- }
- }
-}
-
-/* Data received from remote end */
-static int receive_from_sock(void)
-{
- int ret = 0;
- struct msghdr msg;
- struct kvec iov[2];
- unsigned len;
- int r;
- struct sctp_sndrcvinfo *sinfo;
- struct cmsghdr *cmsg;
- struct nodeinfo *ni;
-
- /* These two are marginally too big for stack allocation, but this
- * function is (currently) only called by dlm_recvd so static should be
- * OK.
- */
- static struct sockaddr_storage msgname;
- static char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
-
- if (sctp_con.sock == NULL)
- goto out;
-
- if (sctp_con.rx_page == NULL) {
- /*
- * This doesn't need to be atomic, but I think it should
- * improve performance if it is.
- */
- sctp_con.rx_page = alloc_page(GFP_ATOMIC);
- if (sctp_con.rx_page == NULL)
- goto out_resched;
- cbuf_init(&sctp_con.cb, PAGE_CACHE_SIZE);
- }
-
- memset(&incmsg, 0, sizeof(incmsg));
- memset(&msgname, 0, sizeof(msgname));
-
- msg.msg_name = &msgname;
- msg.msg_namelen = sizeof(msgname);
- msg.msg_flags = 0;
- msg.msg_control = incmsg;
- msg.msg_controllen = sizeof(incmsg);
- msg.msg_iovlen = 1;
-
- /* I don't see why this circular buffer stuff is necessary for SCTP
- * which is a packet-based protocol, but the whole thing breaks under
- * load without it! The overhead is minimal (and is in the TCP lowcomms
- * anyway, of course) so I'll leave it in until I can figure out what's
- * really happening.
- */
-
- /*
- * iov[0] is the bit of the circular buffer between the current end
- * point (cb.base + cb.len) and the end of the buffer.
- */
- iov[0].iov_len = sctp_con.cb.base - cbuf_data(&sctp_con.cb);
- iov[0].iov_base = page_address(sctp_con.rx_page) +
- cbuf_data(&sctp_con.cb);
- iov[1].iov_len = 0;
-
- /*
- * iov[1] is the bit of the circular buffer between the start of the
- * buffer and the start of the currently used section (cb.base)
- */
- if (cbuf_data(&sctp_con.cb) >= sctp_con.cb.base) {
- iov[0].iov_len = PAGE_CACHE_SIZE - cbuf_data(&sctp_con.cb);
- iov[1].iov_len = sctp_con.cb.base;
- iov[1].iov_base = page_address(sctp_con.rx_page);
- msg.msg_iovlen = 2;
- }
- len = iov[0].iov_len + iov[1].iov_len;
-
- r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, msg.msg_iovlen, len,
- MSG_NOSIGNAL | MSG_DONTWAIT);
- if (ret <= 0)
- goto out_close;
-
- msg.msg_control = incmsg;
- msg.msg_controllen = sizeof(incmsg);
- cmsg = CMSG_FIRSTHDR(&msg);
- sinfo = CMSG_DATA(cmsg);
-
- if (msg.msg_flags & MSG_NOTIFICATION) {
- process_sctp_notification(&msg, page_address(sctp_con.rx_page));
- return 0;
- }
-
- /* Is this a new association ? */
- ni = nodeid2nodeinfo(le32_to_cpu(sinfo->sinfo_ppid), GFP_KERNEL);
- if (ni) {
- ni->assoc_id = sinfo->sinfo_assoc_id;
- if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
-
- if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
- spin_lock_bh(&write_nodes_lock);
- list_add_tail(&ni->write_list, &write_nodes);
- spin_unlock_bh(&write_nodes_lock);
- queue_work(send_workqueue, &ni->swork);
- }
- }
- }
-
- /* INIT sends a message with length of 1 - ignore it */
- if (r == 1)
- return 0;
-
- cbuf_add(&sctp_con.cb, ret);
- // PJC: TODO: Add to node's workqueue....can we ??
- ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
- page_address(sctp_con.rx_page),
- sctp_con.cb.base, sctp_con.cb.len,
- PAGE_CACHE_SIZE);
- if (ret < 0)
- goto out_close;
- cbuf_eat(&sctp_con.cb, ret);
-
-out:
- ret = 0;
- goto out_ret;
-
-out_resched:
- lowcomms_data_ready(sctp_con.sock->sk, 0);
- ret = 0;
- cond_resched();
- goto out_ret;
-
-out_close:
- if (ret != -EAGAIN)
- log_print("error reading from sctp socket: %d", ret);
-out_ret:
- return ret;
-}
-
-/* Bind to an IP address. SCTP allows multiple address so it can do multi-homing */
-static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
-{
- mm_segment_t fs;
- int result = 0;
-
- fs = get_fs();
- set_fs(get_ds());
- if (num == 1)
- result = sctp_con.sock->ops->bind(sctp_con.sock,
- (struct sockaddr *) addr,
- addr_len);
- else
- result = sctp_con.sock->ops->setsockopt(sctp_con.sock, SOL_SCTP,
- SCTP_SOCKOPT_BINDX_ADD,
- (char *)addr, addr_len);
- set_fs(fs);
-
- if (result < 0)
- log_print("Can't bind to port %d addr number %d",
- dlm_config.ci_tcp_port, num);
-
- return result;
-}
-
-static void init_local(void)
-{
- struct sockaddr_storage sas, *addr;
- int i;
-
- dlm_local_nodeid = dlm_our_nodeid();
-
- for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
- if (dlm_our_addr(&sas, i))
- break;
-
- addr = kmalloc(sizeof(*addr), GFP_KERNEL);
- if (!addr)
- break;
- memcpy(addr, &sas, sizeof(*addr));
- dlm_local_addr[dlm_local_count++] = addr;
- }
-}
-
-/* Initialise SCTP socket and bind to all interfaces */
-static int init_sock(void)
-{
- mm_segment_t fs;
- struct socket *sock = NULL;
- struct sockaddr_storage localaddr;
- struct sctp_event_subscribe subscribe;
- int result = -EINVAL, num = 1, i, addr_len;
-
- if (!dlm_local_count) {
- init_local();
- if (!dlm_local_count) {
- log_print("no local IP address has been set");
- goto out;
- }
- }
-
- result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET,
- IPPROTO_SCTP, &sock);
- if (result < 0) {
- log_print("Can't create comms socket, check SCTP is loaded");
- goto out;
- }
-
- /* Listen for events */
- memset(&subscribe, 0, sizeof(subscribe));
- subscribe.sctp_data_io_event = 1;
- subscribe.sctp_association_event = 1;
- subscribe.sctp_send_failure_event = 1;
- subscribe.sctp_shutdown_event = 1;
- subscribe.sctp_partial_delivery_event = 1;
-
- fs = get_fs();
- set_fs(get_ds());
- result = sock->ops->setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
- (char *)&subscribe, sizeof(subscribe));
- set_fs(fs);
-
- if (result < 0) {
- log_print("Failed to set SCTP_EVENTS on socket: result=%d",
- result);
- goto create_delsock;
- }
-
- /* Init con struct */
- sock->sk->sk_user_data = &sctp_con;
- sctp_con.sock = sock;
- sctp_con.sock->sk->sk_data_ready = lowcomms_data_ready;
-
- /* Bind to all interfaces. */
- for (i = 0; i < dlm_local_count; i++) {
- memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
- make_sockaddr(&localaddr, dlm_config.ci_tcp_port, &addr_len);
-
- result = add_bind_addr(&localaddr, addr_len, num);
- if (result)
- goto create_delsock;
- ++num;
- }
-
- result = sock->ops->listen(sock, 5);
- if (result < 0) {
- log_print("Can't set socket listening");
- goto create_delsock;
- }
-
- return 0;
-
-create_delsock:
- sock_release(sock);
- sctp_con.sock = NULL;
-out:
- return result;
-}
-
-
-static struct writequeue_entry *new_writequeue_entry(gfp_t allocation)
-{
- struct writequeue_entry *entry;
-
- entry = kmalloc(sizeof(struct writequeue_entry), allocation);
- if (!entry)
- return NULL;
-
- entry->page = alloc_page(allocation);
- if (!entry->page) {
- kfree(entry);
- return NULL;
- }
-
- entry->offset = 0;
- entry->len = 0;
- entry->end = 0;
- entry->users = 0;
-
- return entry;
-}
-
-void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
-{
- struct writequeue_entry *e;
- int offset = 0;
- int users = 0;
- struct nodeinfo *ni;
-
- ni = nodeid2nodeinfo(nodeid, allocation);
- if (!ni)
- return NULL;
-
- spin_lock(&ni->writequeue_lock);
- e = list_entry(ni->writequeue.prev, struct writequeue_entry, list);
- if ((&e->list == &ni->writequeue) ||
- (PAGE_CACHE_SIZE - e->end < len)) {
- e = NULL;
- } else {
- offset = e->end;
- e->end += len;
- users = e->users++;
- }
- spin_unlock(&ni->writequeue_lock);
-
- if (e) {
- got_one:
- if (users == 0)
- kmap(e->page);
- *ppc = page_address(e->page) + offset;
- return e;
- }
-
- e = new_writequeue_entry(allocation);
- if (e) {
- spin_lock(&ni->writequeue_lock);
- offset = e->end;
- e->end += len;
- e->ni = ni;
- users = e->users++;
- list_add_tail(&e->list, &ni->writequeue);
- spin_unlock(&ni->writequeue_lock);
- goto got_one;
- }
- return NULL;
-}
-
-void dlm_lowcomms_commit_buffer(void *arg)
-{
- struct writequeue_entry *e = (struct writequeue_entry *) arg;
- int users;
- struct nodeinfo *ni = e->ni;
-
- spin_lock(&ni->writequeue_lock);
- users = --e->users;
- if (users)
- goto out;
- e->len = e->end - e->offset;
- kunmap(e->page);
- spin_unlock(&ni->writequeue_lock);
-
- if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
- spin_lock_bh(&write_nodes_lock);
- list_add_tail(&ni->write_list, &write_nodes);
- spin_unlock_bh(&write_nodes_lock);
-
- queue_work(send_workqueue, &ni->swork);
- }
- return;
-
-out:
- spin_unlock(&ni->writequeue_lock);
- return;
-}
-
-static void free_entry(struct writequeue_entry *e)
-{
- __free_page(e->page);
- kfree(e);
-}
-
-/* Initiate an SCTP association. In theory we could just use sendmsg() on
- the first IP address and it should work, but this allows us to set up the
- association before sending any valuable data that we can't afford to lose.
- It also keeps the send path clean as it can now always use the association ID */
-static void initiate_association(int nodeid)
-{
- struct sockaddr_storage rem_addr;
- static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
- struct msghdr outmessage;
- struct cmsghdr *cmsg;
- struct sctp_sndrcvinfo *sinfo;
- int ret;
- int addrlen;
- char buf[1];
- struct kvec iov[1];
- struct nodeinfo *ni;
-
- log_print("Initiating association with node %d", nodeid);
-
- ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
- if (!ni)
- return;
-
- if (nodeid_to_addr(nodeid, (struct sockaddr *)&rem_addr)) {
- log_print("no address for nodeid %d", nodeid);
- return;
- }
-
- make_sockaddr(&rem_addr, dlm_config.ci_tcp_port, &addrlen);
-
- outmessage.msg_name = &rem_addr;
- outmessage.msg_namelen = addrlen;
- outmessage.msg_control = outcmsg;
- outmessage.msg_controllen = sizeof(outcmsg);
- outmessage.msg_flags = MSG_EOR;
-
- iov[0].iov_base = buf;
- iov[0].iov_len = 1;
-
- /* Real INIT messages seem to cause trouble. Just send a 1 byte message
- we can afford to lose */
- cmsg = CMSG_FIRSTHDR(&outmessage);
- cmsg->cmsg_level = IPPROTO_SCTP;
- cmsg->cmsg_type = SCTP_SNDRCV;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
- sinfo = CMSG_DATA(cmsg);
- memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
- sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
-
- outmessage.msg_controllen = cmsg->cmsg_len;
- ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1);
- if (ret < 0) {
- log_print("send INIT to node failed: %d", ret);
- /* Try again later */
- clear_bit(NI_INIT_PENDING, &ni->flags);
- }
-}
-
-/* Send a message */
-static void send_to_sock(struct nodeinfo *ni)
-{
- int ret = 0;
- struct writequeue_entry *e;
- int len, offset;
- struct msghdr outmsg;
- static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
- struct cmsghdr *cmsg;
- struct sctp_sndrcvinfo *sinfo;
- struct kvec iov;
-
- /* See if we need to init an association before we start
- sending precious messages */
- spin_lock(&ni->lock);
- if (!ni->assoc_id && !test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
- spin_unlock(&ni->lock);
- initiate_association(ni->nodeid);
- return;
- }
- spin_unlock(&ni->lock);
-
- outmsg.msg_name = NULL; /* We use assoc_id */
- outmsg.msg_namelen = 0;
- outmsg.msg_control = outcmsg;
- outmsg.msg_controllen = sizeof(outcmsg);
- outmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | MSG_EOR;
-
- cmsg = CMSG_FIRSTHDR(&outmsg);
- cmsg->cmsg_level = IPPROTO_SCTP;
- cmsg->cmsg_type = SCTP_SNDRCV;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
- sinfo = CMSG_DATA(cmsg);
- memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
- sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
- sinfo->sinfo_assoc_id = ni->assoc_id;
- outmsg.msg_controllen = cmsg->cmsg_len;
-
- spin_lock(&ni->writequeue_lock);
- for (;;) {
- if (list_empty(&ni->writequeue))
- break;
- e = list_entry(ni->writequeue.next, struct writequeue_entry,
- list);
- len = e->len;
- offset = e->offset;
- BUG_ON(len == 0 && e->users == 0);
- spin_unlock(&ni->writequeue_lock);
- kmap(e->page);
-
- ret = 0;
- if (len) {
- iov.iov_base = page_address(e->page)+offset;
- iov.iov_len = len;
-
- ret = kernel_sendmsg(sctp_con.sock, &outmsg, &iov, 1,
- len);
- if (ret == -EAGAIN) {
- sctp_con.eagain_flag = 1;
- goto out;
- } else if (ret < 0)
- goto send_error;
- } else {
- /* Don't starve people filling buffers */
- cond_resched();
- }
-
- spin_lock(&ni->writequeue_lock);
- e->offset += ret;
- e->len -= ret;
-
- if (e->len == 0 && e->users == 0) {
- list_del(&e->list);
- kunmap(e->page);
- free_entry(e);
- continue;
- }
- }
- spin_unlock(&ni->writequeue_lock);
-out:
- return;
-
-send_error:
- log_print("Error sending to node %d %d", ni->nodeid, ret);
- spin_lock(&ni->lock);
- if (!test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
- ni->assoc_id = 0;
- spin_unlock(&ni->lock);
- initiate_association(ni->nodeid);
- } else
- spin_unlock(&ni->lock);
-
- return;
-}
-
-/* Try to send any messages that are pending */
-static void process_output_queue(void)
-{
- struct list_head *list;
- struct list_head *temp;
-
- spin_lock_bh(&write_nodes_lock);
- list_for_each_safe(list, temp, &write_nodes) {
- struct nodeinfo *ni =
- list_entry(list, struct nodeinfo, write_list);
- clear_bit(NI_WRITE_PENDING, &ni->flags);
- list_del(&ni->write_list);
-
- spin_unlock_bh(&write_nodes_lock);
-
- send_to_sock(ni);
- spin_lock_bh(&write_nodes_lock);
- }
- spin_unlock_bh(&write_nodes_lock);
-}
-
-/* Called after we've had -EAGAIN and been woken up */
-static void refill_write_queue(void)
-{
- int i;
-
- for (i=1; i<=max_nodeid; i++) {
- struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
-
- if (ni) {
- if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
- spin_lock_bh(&write_nodes_lock);
- list_add_tail(&ni->write_list, &write_nodes);
- spin_unlock_bh(&write_nodes_lock);
- }
- }
- }
-}
-
-static void clean_one_writequeue(struct nodeinfo *ni)
-{
- struct list_head *list;
- struct list_head *temp;
-
- spin_lock(&ni->writequeue_lock);
- list_for_each_safe(list, temp, &ni->writequeue) {
- struct writequeue_entry *e =
- list_entry(list, struct writequeue_entry, list);
- list_del(&e->list);
- free_entry(e);
- }
- spin_unlock(&ni->writequeue_lock);
-}
-
-static void clean_writequeues(void)
-{
- int i;
-
- for (i=1; i<=max_nodeid; i++) {
- struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
- if (ni)
- clean_one_writequeue(ni);
- }
-}
-
-
-static void dealloc_nodeinfo(void)
-{
- int i;
-
- for (i=1; i<=max_nodeid; i++) {
- struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
- if (ni) {
- idr_remove(&nodeinfo_idr, i);
- kfree(ni);
- }
- }
-}
-
-int dlm_lowcomms_close(int nodeid)
-{
- struct nodeinfo *ni;
-
- ni = nodeid2nodeinfo(nodeid, 0);
- if (!ni)
- return -1;
-
- spin_lock(&ni->lock);
- if (ni->assoc_id) {
- ni->assoc_id = 0;
- /* Don't send shutdown here, sctp will just queue it
- till the node comes back up! */
- }
- spin_unlock(&ni->lock);
-
- clean_one_writequeue(ni);
- clear_bit(NI_INIT_PENDING, &ni->flags);
- return 0;
-}
-
-// PJC: The work queue function for receiving.
-static void process_recv_sockets(struct work_struct *work)
-{
- if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
- int ret;
- int count = 0;
-
- do {
- ret = receive_from_sock();
-
- /* Don't starve out everyone else */
- if (++count >= MAX_RX_MSG_COUNT) {
- cond_resched();
- count = 0;
- }
- } while (!kthread_should_stop() && ret >=0);
- }
- cond_resched();
-}
-
-// PJC: the work queue function for sending
-static void process_send_sockets(struct work_struct *work)
-{
- if (sctp_con.eagain_flag) {
- sctp_con.eagain_flag = 0;
- refill_write_queue();
- }
- process_output_queue();
-}
-
-// PJC: Process lock requests from a particular node.
-// TODO: can we optimise this out on UP ??
-static void process_lock_request(struct work_struct *work)
-{
-}
-
-static void daemons_stop(void)
-{
- destroy_workqueue(recv_workqueue);
- destroy_workqueue(send_workqueue);
- destroy_workqueue(lock_workqueue);
-}
-
-static int daemons_start(void)
-{
- int error;
- recv_workqueue = create_workqueue("dlm_recv");
- error = IS_ERR(recv_workqueue);
- if (error) {
- log_print("can't start dlm_recv %d", error);
- return error;
- }
-
- send_workqueue = create_singlethread_workqueue("dlm_send");
- error = IS_ERR(send_workqueue);
- if (error) {
- log_print("can't start dlm_send %d", error);
- destroy_workqueue(recv_workqueue);
- return error;
- }
-
- lock_workqueue = create_workqueue("dlm_rlock");
- error = IS_ERR(lock_workqueue);
- if (error) {
- log_print("can't start dlm_rlock %d", error);
- destroy_workqueue(send_workqueue);
- destroy_workqueue(recv_workqueue);
- return error;
- }
-
- return 0;
-}
-
-/*
- * This is quite likely to sleep...
- */
-int dlm_lowcomms_start(void)
-{
- int error;
-
- INIT_WORK(&sctp_con.work, process_recv_sockets);
-
- error = init_sock();
- if (error)
- goto fail_sock;
- error = daemons_start();
- if (error)
- goto fail_sock;
- return 0;
-
-fail_sock:
- close_connection();
- return error;
-}
-
-void dlm_lowcomms_stop(void)
-{
- int i;
-
- sctp_con.flags = 0x7;
- daemons_stop();
- clean_writequeues();
- close_connection();
- dealloc_nodeinfo();
- max_nodeid = 0;
-
- dlm_local_count = 0;
- dlm_local_nodeid = 0;
-
- for (i = 0; i < dlm_local_count; i++)
- kfree(dlm_local_addr[i]);
-}
diff --git a/fs/dlm/lowcomms-tcp.c b/fs/dlm/lowcomms.c
index 07e0a122c32..27970a58d29 100644
--- a/fs/dlm/lowcomms-tcp.c
+++ b/fs/dlm/lowcomms.c
@@ -36,30 +36,36 @@
* of high load. Also, this way, the sending thread can collect together
* messages bound for one node and send them in one block.
*
- * I don't see any problem with the recv thread executing the locking
- * code on behalf of remote processes as the locking code is
- * short, efficient and never waits.
+ * lowcomms will choose to use wither TCP or SCTP as its transport layer
+ * depending on the configuration variable 'protocol'. This should be set
+ * to 0 (default) for TCP or 1 for SCTP. It shouldbe configured using a
+ * cluster-wide mechanism as it must be the same on all nodes of the cluster
+ * for the DLM to function.
*
*/
-
#include <asm/ioctls.h>
#include <net/sock.h>
#include <net/tcp.h>
#include <linux/pagemap.h>
+#include <linux/idr.h>
+#include <linux/file.h>
+#include <linux/sctp.h>
+#include <net/sctp/user.h>
#include "dlm_internal.h"
#include "lowcomms.h"
#include "midcomms.h"
#include "config.h"
+#define NEEDED_RMEM (4*1024*1024)
+
struct cbuf {
unsigned int base;
unsigned int len;
unsigned int mask;
};
-#define NODE_INCREMENT 32
static void cbuf_add(struct cbuf *cb, int n)
{
cb->len += n;
@@ -88,28 +94,25 @@ static bool cbuf_empty(struct cbuf *cb)
return cb->len == 0;
}
-/* Maximum number of incoming messages to process before
- doing a cond_resched()
-*/
-#define MAX_RX_MSG_COUNT 25
-
struct connection {
struct socket *sock; /* NULL if not connected */
uint32_t nodeid; /* So we know who we are in the list */
struct mutex sock_mutex;
- unsigned long flags; /* bit 1,2 = We are on the read/write lists */
+ unsigned long flags;
#define CF_READ_PENDING 1
#define CF_WRITE_PENDING 2
#define CF_CONNECT_PENDING 3
-#define CF_IS_OTHERCON 4
+#define CF_INIT_PENDING 4
+#define CF_IS_OTHERCON 5
struct list_head writequeue; /* List of outgoing writequeue_entries */
- struct list_head listenlist; /* List of allocated listening sockets */
spinlock_t writequeue_lock;
int (*rx_action) (struct connection *); /* What to do when active */
+ void (*connect_action) (struct connection *); /* What to do to connect */
struct page *rx_page;
struct cbuf cb;
int retries;
#define MAX_CONNECT_RETRIES 3
+ int sctp_assoc;
struct connection *othercon;
struct work_struct rwork; /* Receive workqueue */
struct work_struct swork; /* Send workqueue */
@@ -127,68 +130,136 @@ struct writequeue_entry {
struct connection *con;
};
-static struct sockaddr_storage dlm_local_addr;
+static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
+static int dlm_local_count;
/* Work queues */
static struct workqueue_struct *recv_workqueue;
static struct workqueue_struct *send_workqueue;
-/* An array of pointers to connections, indexed by NODEID */
-static struct connection **connections;
+static DEFINE_IDR(connections_idr);
static DECLARE_MUTEX(connections_lock);
+static int max_nodeid;
static struct kmem_cache *con_cache;
-static int conn_array_size;
static void process_recv_sockets(struct work_struct *work);
static void process_send_sockets(struct work_struct *work);
-static struct connection *nodeid2con(int nodeid, gfp_t allocation)
+/*
+ * If 'allocation' is zero then we don't attempt to create a new
+ * connection structure for this node.
+ */
+static struct connection *__nodeid2con(int nodeid, gfp_t alloc)
{
struct connection *con = NULL;
+ int r;
+ int n;
- down(&connections_lock);
- if (nodeid >= conn_array_size) {
- int new_size = nodeid + NODE_INCREMENT;
- struct connection **new_conns;
+ con = idr_find(&connections_idr, nodeid);
+ if (con || !alloc)
+ return con;
- new_conns = kzalloc(sizeof(struct connection *) *
- new_size, allocation);
- if (!new_conns)
- goto finish;
+ r = idr_pre_get(&connections_idr, alloc);
+ if (!r)
+ return NULL;
+
+ con = kmem_cache_zalloc(con_cache, alloc);
+ if (!con)
+ return NULL;
- memcpy(new_conns, connections, sizeof(struct connection *) * conn_array_size);
- conn_array_size = new_size;
- kfree(connections);
- connections = new_conns;
+ r = idr_get_new_above(&connections_idr, con, nodeid, &n);
+ if (r) {
+ kmem_cache_free(con_cache, con);
+ return NULL;
+ }
+ if (n != nodeid) {
+ idr_remove(&connections_idr, n);
+ kmem_cache_free(con_cache, con);
+ return NULL;
}
- con = connections[nodeid];
- if (con == NULL && allocation) {
- con = kmem_cache_zalloc(con_cache, allocation);
- if (!con)
- goto finish;
+ con->nodeid = nodeid;
+ mutex_init(&con->sock_mutex);
+ INIT_LIST_HEAD(&con->writequeue);
+ spin_lock_init(&con->writequeue_lock);
+ INIT_WORK(&con->swork, process_send_sockets);
+ INIT_WORK(&con->rwork, process_recv_sockets);
- con->nodeid = nodeid;
- mutex_init(&con->sock_mutex);
- INIT_LIST_HEAD(&con->writequeue);
- spin_lock_init(&con->writequeue_lock);
- INIT_WORK(&con->swork, process_send_sockets);
- INIT_WORK(&con->rwork, process_recv_sockets);
+ /* Setup action pointers for child sockets */
+ if (con->nodeid) {
+ struct connection *zerocon = idr_find(&connections_idr, 0);
- connections[nodeid] = con;
+ con->connect_action = zerocon->connect_action;
+ if (!con->rx_action)
+ con->rx_action = zerocon->rx_action;
}
-finish:
+ if (nodeid > max_nodeid)
+ max_nodeid = nodeid;
+
+ return con;
+}
+
+static struct connection *nodeid2con(int nodeid, gfp_t allocation)
+{
+ struct connection *con;
+
+ down(&connections_lock);
+ con = __nodeid2con(nodeid, allocation);
up(&connections_lock);
+
return con;
}
+/* This is a bit drastic, but only called when things go wrong */
+static struct connection *assoc2con(int assoc_id)
+{
+ int i;
+ struct connection *con;
+
+ down(&connections_lock);
+ for (i=0; i<=max_nodeid; i++) {
+ con = __nodeid2con(i, 0);
+ if (con && con->sctp_assoc == assoc_id) {
+ up(&connections_lock);
+ return con;
+ }
+ }
+ up(&connections_lock);
+ return NULL;
+}
+
+static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
+{
+ struct sockaddr_storage addr;
+ int error;
+
+ if (!dlm_local_count)
+ return -1;
+
+ error = dlm_nodeid_to_addr(nodeid, &addr);
+ if (error)
+ return error;
+
+ if (dlm_local_addr[0]->ss_family == AF_INET) {
+ struct sockaddr_in *in4 = (struct sockaddr_in *) &addr;
+ struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
+ ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
+ } else {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr;
+ struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
+ memcpy(&ret6->sin6_addr, &in6->sin6_addr,
+ sizeof(in6->sin6_addr));
+ }
+
+ return 0;
+}
+
/* Data available on socket or listen socket received a connect */
static void lowcomms_data_ready(struct sock *sk, int count_unused)
{
struct connection *con = sock2con(sk);
-
if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
queue_work(recv_workqueue, &con->rwork);
}
@@ -222,20 +293,21 @@ static int add_sock(struct socket *sock, struct connection *con)
con->sock->sk->sk_data_ready = lowcomms_data_ready;
con->sock->sk->sk_write_space = lowcomms_write_space;
con->sock->sk->sk_state_change = lowcomms_state_change;
-
+ con->sock->sk->sk_user_data = con;
return 0;
}
-/* Add the port number to an IP6 or 4 sockaddr and return the address
+/* Add the port number to an IPv6 or 4 sockaddr and return the address
length */
static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
int *addr_len)
{
- saddr->ss_family = dlm_local_addr.ss_family;
+ saddr->ss_family = dlm_local_addr[0]->ss_family;
if (saddr->ss_family == AF_INET) {
struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
in4_addr->sin_port = cpu_to_be16(port);
*addr_len = sizeof(struct sockaddr_in);
+ memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
} else {
struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
in6_addr->sin6_port = cpu_to_be16(port);
@@ -264,6 +336,193 @@ static void close_connection(struct connection *con, bool and_other)
mutex_unlock(&con->sock_mutex);
}
+/* We only send shutdown messages to nodes that are not part of the cluster */
+static void sctp_send_shutdown(sctp_assoc_t associd)
+{
+ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct msghdr outmessage;
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ int ret;
+ struct connection *con;
+
+ con = nodeid2con(0,0);
+ BUG_ON(con == NULL);
+
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = MSG_EOR;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ sinfo->sinfo_flags |= MSG_EOF;
+ sinfo->sinfo_assoc_id = associd;
+
+ ret = kernel_sendmsg(con->sock, &outmessage, NULL, 0, 0);
+
+ if (ret != 0)
+ log_print("send EOF to node failed: %d", ret);
+}
+
+/* INIT failed but we don't know which node...
+ restart INIT on all pending nodes */
+static void sctp_init_failed(void)
+{
+ int i;
+ struct connection *con;
+
+ down(&connections_lock);
+ for (i=1; i<=max_nodeid; i++) {
+ con = __nodeid2con(i, 0);
+ if (!con)
+ continue;
+ con->sctp_assoc = 0;
+ if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
+ if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
+ queue_work(send_workqueue, &con->swork);
+ }
+ }
+ }
+ up(&connections_lock);
+}
+
+/* Something happened to an association */
+static void process_sctp_notification(struct connection *con,
+ struct msghdr *msg, char *buf)
+{
+ union sctp_notification *sn = (union sctp_notification *)buf;
+
+ if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
+ switch (sn->sn_assoc_change.sac_state) {
+
+ case SCTP_COMM_UP:
+ case SCTP_RESTART:
+ {
+ /* Check that the new node is in the lockspace */
+ struct sctp_prim prim;
+ int nodeid;
+ int prim_len, ret;
+ int addr_len;
+ struct connection *new_con;
+ struct file *file;
+ sctp_peeloff_arg_t parg;
+ int parglen = sizeof(parg);
+
+ /*
+ * We get this before any data for an association.
+ * We verify that the node is in the cluster and
+ * then peel off a socket for it.
+ */
+ if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {
+ log_print("COMM_UP for invalid assoc ID %d",
+ (int)sn->sn_assoc_change.sac_assoc_id);
+ sctp_init_failed();
+ return;
+ }
+ memset(&prim, 0, sizeof(struct sctp_prim));
+ prim_len = sizeof(struct sctp_prim);
+ prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;
+
+ ret = kernel_getsockopt(con->sock,
+ IPPROTO_SCTP,
+ SCTP_PRIMARY_ADDR,
+ (char*)&prim,
+ &prim_len);
+ if (ret < 0) {
+ log_print("getsockopt/sctp_primary_addr on "
+ "new assoc %d failed : %d",
+ (int)sn->sn_assoc_change.sac_assoc_id,
+ ret);
+
+ /* Retry INIT later */
+ new_con = assoc2con(sn->sn_assoc_change.sac_assoc_id);
+ if (new_con)
+ clear_bit(CF_CONNECT_PENDING, &con->flags);
+ return;
+ }
+ make_sockaddr(&prim.ssp_addr, 0, &addr_len);
+ if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+ int i;
+ unsigned char *b=(unsigned char *)&prim.ssp_addr;
+ log_print("reject connect from unknown addr");
+ for (i=0; i<sizeof(struct sockaddr_storage);i++)
+ printk("%02x ", b[i]);
+ printk("\n");
+ sctp_send_shutdown(prim.ssp_assoc_id);
+ return;
+ }
+
+ new_con = nodeid2con(nodeid, GFP_KERNEL);
+ if (!new_con)
+ return;
+
+ /* Peel off a new sock */
+ parg.associd = sn->sn_assoc_change.sac_assoc_id;
+ ret = kernel_getsockopt(con->sock, IPPROTO_SCTP,
+ SCTP_SOCKOPT_PEELOFF,
+ (void *)&parg, &parglen);
+ if (ret) {
+ log_print("Can't peel off a socket for "
+ "connection %d to node %d: err=%d\n",
+ parg.associd, nodeid, ret);
+ }
+ file = fget(parg.sd);
+ new_con->sock = SOCKET_I(file->f_dentry->d_inode);
+ add_sock(new_con->sock, new_con);
+ fput(file);
+ put_unused_fd(parg.sd);
+
+ log_print("got new/restarted association %d nodeid %d",
+ (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
+
+ /* Send any pending writes */
+ clear_bit(CF_CONNECT_PENDING, &new_con->flags);
+ clear_bit(CF_INIT_PENDING, &con->flags);
+ if (!test_and_set_bit(CF_WRITE_PENDING, &new_con->flags)) {
+ queue_work(send_workqueue, &new_con->swork);
+ }
+ if (!test_and_set_bit(CF_READ_PENDING, &new_con->flags))
+ queue_work(recv_workqueue, &new_con->rwork);
+ }
+ break;
+
+ case SCTP_COMM_LOST:
+ case SCTP_SHUTDOWN_COMP:
+ {
+ con = assoc2con(sn->sn_assoc_change.sac_assoc_id);
+ if (con) {
+ con->sctp_assoc = 0;
+ }
+ }
+ break;
+
+ /* We don't know which INIT failed, so clear the PENDING flags
+ * on them all. if assoc_id is zero then it will then try
+ * again */
+
+ case SCTP_CANT_STR_ASSOC:
+ {
+ log_print("Can't start SCTP association - retrying");
+ sctp_init_failed();
+ }
+ break;
+
+ default:
+ log_print("unexpected SCTP assoc change id=%d state=%d",
+ (int)sn->sn_assoc_change.sac_assoc_id,
+ sn->sn_assoc_change.sac_state);
+ }
+ }
+}
+
/* Data received from remote end */
static int receive_from_sock(struct connection *con)
{
@@ -274,6 +533,7 @@ static int receive_from_sock(struct connection *con)
int r;
int call_again_soon = 0;
int nvec;
+ char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
mutex_lock(&con->sock_mutex);
@@ -293,12 +553,18 @@ static int receive_from_sock(struct connection *con)
cbuf_init(&con->cb, PAGE_CACHE_SIZE);
}
+ /* Only SCTP needs these really */
+ memset(&incmsg, 0, sizeof(incmsg));
+ msg.msg_control = incmsg;
+ msg.msg_controllen = sizeof(incmsg);
+
/*
* iov[0] is the bit of the circular buffer between the current end
* point (cb.base + cb.len) and the end of the buffer.
*/
iov[0].iov_len = con->cb.base - cbuf_data(&con->cb);
iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb);
+ iov[1].iov_len = 0;
nvec = 1;
/*
@@ -315,11 +581,20 @@ static int receive_from_sock(struct connection *con)
r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len,
MSG_DONTWAIT | MSG_NOSIGNAL);
-
if (ret <= 0)
goto out_close;
- if (ret == -EAGAIN)
- goto out_resched;
+
+ /* Process SCTP notifications */
+ if (msg.msg_flags & MSG_NOTIFICATION) {
+ msg.msg_control = incmsg;
+ msg.msg_controllen = sizeof(incmsg);
+
+ process_sctp_notification(con, &msg,
+ page_address(con->rx_page) + con->cb.base);
+ mutex_unlock(&con->sock_mutex);
+ return 0;
+ }
+ BUG_ON(con->nodeid == 0);
if (ret == len)
call_again_soon = 1;
@@ -329,10 +604,10 @@ static int receive_from_sock(struct connection *con)
con->cb.base, con->cb.len,
PAGE_CACHE_SIZE);
if (ret == -EBADMSG) {
- printk(KERN_INFO "dlm: lowcomms: addr=%p, base=%u, len=%u, "
- "iov_len=%u, iov_base[0]=%p, read=%d\n",
- page_address(con->rx_page), con->cb.base, con->cb.len,
- len, iov[0].iov_base, r);
+ log_print("lowcomms: addr=%p, base=%u, len=%u, "
+ "iov_len=%u, iov_base[0]=%p, read=%d",
+ page_address(con->rx_page), con->cb.base, con->cb.len,
+ len, iov[0].iov_base, r);
}
if (ret < 0)
goto out_close;
@@ -368,7 +643,7 @@ out_close:
}
/* Listening socket is busy, accept a connection */
-static int accept_from_sock(struct connection *con)
+static int tcp_accept_from_sock(struct connection *con)
{
int result;
struct sockaddr_storage peeraddr;
@@ -379,7 +654,7 @@ static int accept_from_sock(struct connection *con)
struct connection *addcon;
memset(&peeraddr, 0, sizeof(peeraddr));
- result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
+ result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
IPPROTO_TCP, &newsock);
if (result < 0)
return -ENOMEM;
@@ -408,7 +683,7 @@ static int accept_from_sock(struct connection *con)
/* Get the new node's NODEID */
make_sockaddr(&peeraddr, 0, &len);
if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
- printk("dlm: connect from non cluster node\n");
+ log_print("connect from non cluster node");
sock_release(newsock);
mutex_unlock(&con->sock_mutex);
return -1;
@@ -419,7 +694,6 @@ static int accept_from_sock(struct connection *con)
/* Check to see if we already have a connection to this node. This
* could happen if the two nodes initiate a connection at roughly
* the same time and the connections cross on the wire.
- * TEMPORARY FIX:
* In this case we store the incoming one in "othercon"
*/
newcon = nodeid2con(nodeid, GFP_KERNEL);
@@ -434,7 +708,7 @@ static int accept_from_sock(struct connection *con)
if (!othercon) {
othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
if (!othercon) {
- printk("dlm: failed to allocate incoming socket\n");
+ log_print("failed to allocate incoming socket");
mutex_unlock(&newcon->sock_mutex);
result = -ENOMEM;
goto accept_err;
@@ -477,12 +751,107 @@ accept_err:
sock_release(newsock);
if (result != -EAGAIN)
- printk("dlm: error accepting connection from node: %d\n", result);
+ log_print("error accepting connection from node: %d", result);
return result;
}
+static void free_entry(struct writequeue_entry *e)
+{
+ __free_page(e->page);
+ kfree(e);
+}
+
+/* Initiate an SCTP association.
+ This is a special case of send_to_sock() in that we don't yet have a
+ peeled-off socket for this association, so we use the listening socket
+ and add the primary IP address of the remote node.
+ */
+static void sctp_init_assoc(struct connection *con)
+{
+ struct sockaddr_storage rem_addr;
+ char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct msghdr outmessage;
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct connection *base_con;
+ struct writequeue_entry *e;
+ int len, offset;
+ int ret;
+ int addrlen;
+ struct kvec iov[1];
+
+ if (test_and_set_bit(CF_INIT_PENDING, &con->flags))
+ return;
+
+ if (con->retries++ > MAX_CONNECT_RETRIES)
+ return;
+
+ log_print("Initiating association with node %d", con->nodeid);
+
+ if (nodeid_to_addr(con->nodeid, (struct sockaddr *)&rem_addr)) {
+ log_print("no address for nodeid %d", con->nodeid);
+ return;
+ }
+ base_con = nodeid2con(0, 0);
+ BUG_ON(base_con == NULL);
+
+ make_sockaddr(&rem_addr, dlm_config.ci_tcp_port, &addrlen);
+
+ outmessage.msg_name = &rem_addr;
+ outmessage.msg_namelen = addrlen;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = MSG_EOR;
+
+ spin_lock(&con->writequeue_lock);
+ e = list_entry(con->writequeue.next, struct writequeue_entry,
+ list);
+
+ BUG_ON((struct list_head *) e == &con->writequeue);
+
+ len = e->len;
+ offset = e->offset;
+ spin_unlock(&con->writequeue_lock);
+ kmap(e->page);
+
+ /* Send the first block off the write queue */
+ iov[0].iov_base = page_address(e->page)+offset;
+ iov[0].iov_len = len;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ sinfo = CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_ppid = cpu_to_le32(dlm_our_nodeid());
+ outmessage.msg_controllen = cmsg->cmsg_len;
+
+ ret = kernel_sendmsg(base_con->sock, &outmessage, iov, 1, len);
+ if (ret < 0) {
+ log_print("Send first packet to node %d failed: %d",
+ con->nodeid, ret);
+
+ /* Try again later */
+ clear_bit(CF_CONNECT_PENDING, &con->flags);
+ clear_bit(CF_INIT_PENDING, &con->flags);
+ }
+ else {
+ spin_lock(&con->writequeue_lock);
+ e->offset += ret;
+ e->len -= ret;
+
+ if (e->len == 0 && e->users == 0) {
+ list_del(&e->list);
+ kunmap(e->page);
+ free_entry(e);
+ }
+ spin_unlock(&con->writequeue_lock);
+ }
+}
+
/* Connect a new socket to its peer */
-static void connect_to_sock(struct connection *con)
+static void tcp_connect_to_sock(struct connection *con)
{
int result = -EHOSTUNREACH;
struct sockaddr_storage saddr;
@@ -505,7 +874,7 @@ static void connect_to_sock(struct connection *con)
}
/* Create a socket to communicate with */
- result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
+ result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
IPPROTO_TCP, &sock);
if (result < 0)
goto out_err;
@@ -516,11 +885,11 @@ static void connect_to_sock(struct connection *con)
sock->sk->sk_user_data = con;
con->rx_action = receive_from_sock;
+ con->connect_action = tcp_connect_to_sock;
+ add_sock(sock, con);
make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
- add_sock(sock, con);
-
log_print("connecting to %d", con->nodeid);
result =
sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
@@ -550,64 +919,57 @@ out:
return;
}
-static struct socket *create_listen_sock(struct connection *con,
- struct sockaddr_storage *saddr)
+static struct socket *tcp_create_listen_sock(struct connection *con,
+ struct sockaddr_storage *saddr)
{
struct socket *sock = NULL;
- mm_segment_t fs;
int result = 0;
int one = 1;
int addr_len;
- if (dlm_local_addr.ss_family == AF_INET)
+ if (dlm_local_addr[0]->ss_family == AF_INET)
addr_len = sizeof(struct sockaddr_in);
else
addr_len = sizeof(struct sockaddr_in6);
/* Create a socket to communicate with */
- result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM, IPPROTO_TCP, &sock);
+ result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
+ IPPROTO_TCP, &sock);
if (result < 0) {
- printk("dlm: Can't create listening comms socket\n");
+ log_print("Can't create listening comms socket");
goto create_out;
}
- fs = get_fs();
- set_fs(get_ds());
- result = sock_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
- (char *)&one, sizeof(one));
- set_fs(fs);
+ result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&one, sizeof(one));
+
if (result < 0) {
- printk("dlm: Failed to set SO_REUSEADDR on socket: result=%d\n",
- result);
+ log_print("Failed to set SO_REUSEADDR on socket: %d", result);
}
sock->sk->sk_user_data = con;
- con->rx_action = accept_from_sock;
+ con->rx_action = tcp_accept_from_sock;
+ con->connect_action = tcp_connect_to_sock;
con->sock = sock;
/* Bind to our port */
make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
if (result < 0) {
- printk("dlm: Can't bind to port %d\n", dlm_config.ci_tcp_port);
+ log_print("Can't bind to port %d", dlm_config.ci_tcp_port);
sock_release(sock);
sock = NULL;
con->sock = NULL;
goto create_out;
}
-
- fs = get_fs();
- set_fs(get_ds());
-
- result = sock_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
+ result = kernel_setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
(char *)&one, sizeof(one));
- set_fs(fs);
if (result < 0) {
- printk("dlm: Set keepalive failed: %d\n", result);
+ log_print("Set keepalive failed: %d", result);
}
result = sock->ops->listen(sock, 5);
if (result < 0) {
- printk("dlm: Can't listen on port %d\n", dlm_config.ci_tcp_port);
+ log_print("Can't listen on port %d", dlm_config.ci_tcp_port);
sock_release(sock);
sock = NULL;
goto create_out;
@@ -617,18 +979,146 @@ create_out:
return sock;
}
+/* Get local addresses */
+static void init_local(void)
+{
+ struct sockaddr_storage sas, *addr;
+ int i;
+
+ dlm_local_count = 0;
+ for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
+ if (dlm_our_addr(&sas, i))
+ break;
+
+ addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+ if (!addr)
+ break;
+ memcpy(addr, &sas, sizeof(*addr));
+ dlm_local_addr[dlm_local_count++] = addr;
+ }
+}
+
+/* Bind to an IP address. SCTP allows multiple address so it can do
+ multi-homing */
+static int add_sctp_bind_addr(struct connection *sctp_con,
+ struct sockaddr_storage *addr,
+ int addr_len, int num)
+{
+ int result = 0;
+
+ if (num == 1)
+ result = kernel_bind(sctp_con->sock,
+ (struct sockaddr *) addr,
+ addr_len);
+ else
+ result = kernel_setsockopt(sctp_con->sock, SOL_SCTP,
+ SCTP_SOCKOPT_BINDX_ADD,
+ (char *)addr, addr_len);
+
+ if (result < 0)
+ log_print("Can't bind to port %d addr number %d",
+ dlm_config.ci_tcp_port, num);
+
+ return result;
+}
-/* Listen on all interfaces */
-static int listen_for_all(void)
+/* Initialise SCTP socket and bind to all interfaces */
+static int sctp_listen_for_all(void)
+{
+ struct socket *sock = NULL;
+ struct sockaddr_storage localaddr;
+ struct sctp_event_subscribe subscribe;
+ int result = -EINVAL, num = 1, i, addr_len;
+ struct connection *con = nodeid2con(0, GFP_KERNEL);
+ int bufsize = NEEDED_RMEM;
+
+ if (!con)
+ return -ENOMEM;
+
+ log_print("Using SCTP for communications");
+
+ result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET,
+ IPPROTO_SCTP, &sock);
+ if (result < 0) {
+ log_print("Can't create comms socket, check SCTP is loaded");
+ goto out;
+ }
+
+ /* Listen for events */
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ subscribe.sctp_send_failure_event = 1;
+ subscribe.sctp_shutdown_event = 1;
+ subscribe.sctp_partial_delivery_event = 1;
+
+ result = kernel_setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ (char *)&bufsize, sizeof(bufsize));
+ if (result)
+ log_print("Error increasing buffer space on socket %d", result);
+
+ result = kernel_setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
+ (char *)&subscribe, sizeof(subscribe));
+ if (result < 0) {
+ log_print("Failed to set SCTP_EVENTS on socket: result=%d",
+ result);
+ goto create_delsock;
+ }
+
+ /* Init con struct */
+ sock->sk->sk_user_data = con;
+ con->sock = sock;
+ con->sock->sk->sk_data_ready = lowcomms_data_ready;
+ con->rx_action = receive_from_sock;
+ con->connect_action = sctp_init_assoc;
+
+ /* Bind to all interfaces. */
+ for (i = 0; i < dlm_local_count; i++) {
+ memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
+ make_sockaddr(&localaddr, dlm_config.ci_tcp_port, &addr_len);
+
+ result = add_sctp_bind_addr(con, &localaddr, addr_len, num);
+ if (result)
+ goto create_delsock;
+ ++num;
+ }
+
+ result = sock->ops->listen(sock, 5);
+ if (result < 0) {
+ log_print("Can't set socket listening");
+ goto create_delsock;
+ }
+
+ return 0;
+
+create_delsock:
+ sock_release(sock);
+ con->sock = NULL;
+out:
+ return result;
+}
+
+static int tcp_listen_for_all(void)
{
struct socket *sock = NULL;
struct connection *con = nodeid2con(0, GFP_KERNEL);
int result = -EINVAL;
+ if (!con)
+ return -ENOMEM;
+
/* We don't support multi-homed hosts */
+ if (dlm_local_addr[1] != NULL) {
+ log_print("TCP protocol can't handle multi-homed hosts, "
+ "try SCTP");
+ return -EINVAL;
+ }
+
+ log_print("Using TCP for communications");
+
set_bit(CF_IS_OTHERCON, &con->flags);
- sock = create_listen_sock(con, &dlm_local_addr);
+ sock = tcp_create_listen_sock(con, dlm_local_addr[0]);
if (sock) {
add_sock(sock, con);
result = 0;
@@ -666,8 +1156,7 @@ static struct writequeue_entry *new_writequeue_entry(struct connection *con,
return entry;
}
-void *dlm_lowcomms_get_buffer(int nodeid, int len,
- gfp_t allocation, char **ppc)
+void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
{
struct connection *con;
struct writequeue_entry *e;
@@ -735,12 +1224,6 @@ out:
return;
}
-static void free_entry(struct writequeue_entry *e)
-{
- __free_page(e->page);
- kfree(e);
-}
-
/* Send a message */
static void send_to_sock(struct connection *con)
{
@@ -777,8 +1260,7 @@ static void send_to_sock(struct connection *con)
goto out;
if (ret <= 0)
goto send_error;
- }
- else {
+ } else {
/* Don't starve people filling buffers */
cond_resched();
}
@@ -807,7 +1289,8 @@ send_error:
out_connect:
mutex_unlock(&con->sock_mutex);
- connect_to_sock(con);
+ if (!test_bit(CF_INIT_PENDING, &con->flags))
+ lowcomms_connect_sock(con);
return;
}
@@ -832,9 +1315,6 @@ int dlm_lowcomms_close(int nodeid)
{
struct connection *con;
- if (!connections)
- goto out;
-
log_print("closing connection to node %d", nodeid);
con = nodeid2con(nodeid, 0);
if (con) {
@@ -842,12 +1322,9 @@ int dlm_lowcomms_close(int nodeid)
close_connection(con, true);
}
return 0;
-
-out:
- return -1;
}
-/* Look for activity on active sockets */
+/* Receive workqueue function */
static void process_recv_sockets(struct work_struct *work)
{
struct connection *con = container_of(work, struct connection, rwork);
@@ -859,15 +1336,14 @@ static void process_recv_sockets(struct work_struct *work)
} while (!err);
}
-
+/* Send workqueue function */
static void process_send_sockets(struct work_struct *work)
{
struct connection *con = container_of(work, struct connection, swork);
if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
- connect_to_sock(con);
+ con->connect_action(con);
}
-
clear_bit(CF_WRITE_PENDING, &con->flags);
send_to_sock(con);
}
@@ -878,8 +1354,8 @@ static void clean_writequeues(void)
{
int nodeid;
- for (nodeid = 1; nodeid < conn_array_size; nodeid++) {
- struct connection *con = nodeid2con(nodeid, 0);
+ for (nodeid = 1; nodeid <= max_nodeid; nodeid++) {
+ struct connection *con = __nodeid2con(nodeid, 0);
if (con)
clean_one_writequeue(con);
@@ -916,64 +1392,67 @@ static int work_start(void)
void dlm_lowcomms_stop(void)
{
int i;
+ struct connection *con;
/* Set all the flags to prevent any
socket activity.
*/
- for (i = 0; i < conn_array_size; i++) {
- if (connections[i])
- connections[i]->flags |= 0xFF;
+ down(&connections_lock);
+ for (i = 0; i <= max_nodeid; i++) {
+ con = __nodeid2con(i, 0);
+ if (con)
+ con->flags |= 0xFF;
}
+ up(&connections_lock);
work_stop();
+
+ down(&connections_lock);
clean_writequeues();
- for (i = 0; i < conn_array_size; i++) {
- if (connections[i]) {
- close_connection(connections[i], true);
- if (connections[i]->othercon)
- kmem_cache_free(con_cache, connections[i]->othercon);
- kmem_cache_free(con_cache, connections[i]);
+ for (i = 0; i <= max_nodeid; i++) {
+ con = __nodeid2con(i, 0);
+ if (con) {
+ close_connection(con, true);
+ if (con->othercon)
+ kmem_cache_free(con_cache, con->othercon);
+ kmem_cache_free(con_cache, con);
}
}
-
- kfree(connections);
- connections = NULL;
-
+ max_nodeid = 0;
+ up(&connections_lock);
kmem_cache_destroy(con_cache);
+ idr_init(&connections_idr);
}
-/* This is quite likely to sleep... */
int dlm_lowcomms_start(void)
{
- int error = 0;
-
- error = -ENOMEM;
- connections = kzalloc(sizeof(struct connection *) *
- NODE_INCREMENT, GFP_KERNEL);
- if (!connections)
- goto out;
-
- conn_array_size = NODE_INCREMENT;
+ int error = -EINVAL;
+ struct connection *con;
- if (dlm_our_addr(&dlm_local_addr, 0)) {
+ init_local();
+ if (!dlm_local_count) {
+ error = -ENOTCONN;
log_print("no local IP address has been set");
- goto fail_free_conn;
- }
- if (!dlm_our_addr(&dlm_local_addr, 1)) {
- log_print("This dlm comms module does not support multi-homed clustering");
- goto fail_free_conn;
+ goto out;
}
+ error = -ENOMEM;
con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
__alignof__(struct connection), 0,
NULL, NULL);
if (!con_cache)
- goto fail_free_conn;
+ goto out;
+ /* Set some sysctl minima */
+ if (sysctl_rmem_max < NEEDED_RMEM)
+ sysctl_rmem_max = NEEDED_RMEM;
/* Start listening */
- error = listen_for_all();
+ if (dlm_config.ci_protocol == 0)
+ error = tcp_listen_for_all();
+ else
+ error = sctp_listen_for_all();
if (error)
goto fail_unlisten;
@@ -984,24 +1463,13 @@ int dlm_lowcomms_start(void)
return 0;
fail_unlisten:
- close_connection(connections[0], false);
- kmem_cache_free(con_cache, connections[0]);
+ con = nodeid2con(0,0);
+ if (con) {
+ close_connection(con, false);
+ kmem_cache_free(con_cache, con);
+ }
kmem_cache_destroy(con_cache);
-fail_free_conn:
- kfree(connections);
-
out:
return error;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 3870150b83a..b0201ec325a 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2006-2007 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
@@ -56,6 +56,7 @@ struct dlm_write_request32 {
union {
struct dlm_lock_params32 lock;
struct dlm_lspace_params lspace;
+ struct dlm_purge_params purge;
} i;
};
@@ -92,6 +93,9 @@ static void compat_input(struct dlm_write_request *kb,
kb->i.lspace.flags = kb32->i.lspace.flags;
kb->i.lspace.minor = kb32->i.lspace.minor;
strcpy(kb->i.lspace.name, kb32->i.lspace.name);
+ } else if (kb->cmd == DLM_USER_PURGE) {
+ kb->i.purge.nodeid = kb32->i.purge.nodeid;
+ kb->i.purge.pid = kb32->i.purge.pid;
} else {
kb->i.lock.mode = kb32->i.lock.mode;
kb->i.lock.namelen = kb32->i.lock.namelen;
@@ -111,8 +115,6 @@ static void compat_input(struct dlm_write_request *kb,
static void compat_output(struct dlm_lock_result *res,
struct dlm_lock_result32 *res32)
{
- res32->length = res->length - (sizeof(struct dlm_lock_result) -
- sizeof(struct dlm_lock_result32));
res32->user_astaddr = (__u32)(long)res->user_astaddr;
res32->user_astparam = (__u32)(long)res->user_astparam;
res32->user_lksb = (__u32)(long)res->user_lksb;
@@ -128,35 +130,30 @@ static void compat_output(struct dlm_lock_result *res,
}
#endif
+/* we could possibly check if the cancel of an orphan has resulted in the lkb
+ being removed and then remove that lkb from the orphans list and free it */
void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
{
struct dlm_ls *ls;
struct dlm_user_args *ua;
struct dlm_user_proc *proc;
- int remove_ownqueue = 0;
+ int eol = 0, ast_type;
- /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
- lkb before dealing with it. We need to check this
- flag before taking ls_clear_proc_locks mutex because if
- it's set, dlm_clear_proc_locks() holds the mutex. */
-
- if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
- /* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */
+ if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
return;
- }
ls = lkb->lkb_resource->res_ls;
mutex_lock(&ls->ls_clear_proc_locks);
/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
- lkb->ua so we can't try to use it. */
+ lkb->ua so we can't try to use it. This second check is necessary
+ for cases where a completion ast is received for an operation that
+ began before clear_proc_locks did its cancel/unlock. */
- if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
- /* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
+ if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD))
goto out;
- }
DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
ua = (struct dlm_user_args *)lkb->lkb_astparam;
@@ -166,28 +163,42 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
goto out;
spin_lock(&proc->asts_spin);
- if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+
+ ast_type = lkb->lkb_ast_type;
+ lkb->lkb_ast_type |= type;
+
+ if (!ast_type) {
kref_get(&lkb->lkb_ref);
list_add_tail(&lkb->lkb_astqueue, &proc->asts);
- lkb->lkb_ast_type |= type;
wake_up_interruptible(&proc->wait);
}
-
- /* noqueue requests that fail may need to be removed from the
- proc's locks list, there should be a better way of detecting
- this situation than checking all these things... */
-
- if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
- ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
- remove_ownqueue = 1;
-
- /* unlocks or cancels of waiting requests need to be removed from the
- proc's unlocking list, again there must be a better way... */
-
- if (ua->lksb.sb_status == -DLM_EUNLOCK ||
+ if (type == AST_COMP && (ast_type & AST_COMP))
+ log_debug(ls, "ast overlap %x status %x %x",
+ lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);
+
+ /* Figure out if this lock is at the end of its life and no longer
+ available for the application to use. The lkb still exists until
+ the final ast is read. A lock becomes EOL in three situations:
+ 1. a noqueue request fails with EAGAIN
+ 2. an unlock completes with EUNLOCK
+ 3. a cancel of a waiting request completes with ECANCEL
+ An EOL lock needs to be removed from the process's list of locks.
+ And we can't allow any new operation on an EOL lock. This is
+ not related to the lifetime of the lkb struct which is managed
+ entirely by refcount. */
+
+ if (type == AST_COMP &&
+ lkb->lkb_grmode == DLM_LOCK_IV &&
+ ua->lksb.sb_status == -EAGAIN)
+ eol = 1;
+ else if (ua->lksb.sb_status == -DLM_EUNLOCK ||
(ua->lksb.sb_status == -DLM_ECANCEL &&
lkb->lkb_grmode == DLM_LOCK_IV))
- remove_ownqueue = 1;
+ eol = 1;
+ if (eol) {
+ lkb->lkb_ast_type &= ~AST_BAST;
+ lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;
+ }
/* We want to copy the lvb to userspace when the completion
ast is read if the status is 0, the lock has an lvb and
@@ -204,11 +215,13 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
spin_unlock(&proc->asts_spin);
- if (remove_ownqueue) {
+ if (eol) {
spin_lock(&ua->proc->locks_spin);
- list_del_init(&lkb->lkb_ownqueue);
+ if (!list_empty(&lkb->lkb_ownqueue)) {
+ list_del_init(&lkb->lkb_ownqueue);
+ dlm_put_lkb(lkb);
+ }
spin_unlock(&ua->proc->locks_spin);
- dlm_put_lkb(lkb);
}
out:
mutex_unlock(&ls->ls_clear_proc_locks);
@@ -286,47 +299,71 @@ static int device_user_unlock(struct dlm_user_proc *proc,
return error;
}
-static int device_create_lockspace(struct dlm_lspace_params *params)
+static int create_misc_device(struct dlm_ls *ls, char *name)
{
- dlm_lockspace_t *lockspace;
- struct dlm_ls *ls;
int error, len;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- error = dlm_new_lockspace(params->name, strlen(params->name),
- &lockspace, 0, DLM_USER_LVB_LEN);
- if (error)
- return error;
-
- ls = dlm_find_lockspace_local(lockspace);
- if (!ls)
- return -ENOENT;
-
error = -ENOMEM;
- len = strlen(params->name) + strlen(name_prefix) + 2;
+ len = strlen(name) + strlen(name_prefix) + 2;
ls->ls_device.name = kzalloc(len, GFP_KERNEL);
if (!ls->ls_device.name)
goto fail;
+
snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
- params->name);
+ name);
ls->ls_device.fops = &device_fops;
ls->ls_device.minor = MISC_DYNAMIC_MINOR;
error = misc_register(&ls->ls_device);
if (error) {
kfree(ls->ls_device.name);
- goto fail;
}
+fail:
+ return error;
+}
+
+static int device_user_purge(struct dlm_user_proc *proc,
+ struct dlm_purge_params *params)
+{
+ struct dlm_ls *ls;
+ int error;
+
+ ls = dlm_find_lockspace_local(proc->lockspace);
+ if (!ls)
+ return -ENOENT;
+
+ error = dlm_user_purge(ls, proc, params->nodeid, params->pid);
- error = ls->ls_device.minor;
dlm_put_lockspace(ls);
return error;
+}
+
+static int device_create_lockspace(struct dlm_lspace_params *params)
+{
+ dlm_lockspace_t *lockspace;
+ struct dlm_ls *ls;
+ int error;
- fail:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ error = dlm_new_lockspace(params->name, strlen(params->name),
+ &lockspace, 0, DLM_USER_LVB_LEN);
+ if (error)
+ return error;
+
+ ls = dlm_find_lockspace_local(lockspace);
+ if (!ls)
+ return -ENOENT;
+
+ error = create_misc_device(ls, params->name);
dlm_put_lockspace(ls);
- dlm_release_lockspace(lockspace, 0);
+
+ if (error)
+ dlm_release_lockspace(lockspace, 0);
+ else
+ error = ls->ls_device.minor;
+
return error;
}
@@ -343,6 +380,10 @@ static int device_remove_lockspace(struct dlm_lspace_params *params)
if (!ls)
return -ENOENT;
+ /* Deregister the misc device first, so we don't have
+ * a device that's not attached to a lockspace. If
+ * dlm_release_lockspace fails then we can recreate it
+ */
error = misc_deregister(&ls->ls_device);
if (error) {
dlm_put_lockspace(ls);
@@ -361,6 +402,8 @@ static int device_remove_lockspace(struct dlm_lspace_params *params)
dlm_put_lockspace(ls);
error = dlm_release_lockspace(lockspace, force);
+ if (error)
+ create_misc_device(ls, ls->ls_name);
out:
return error;
}
@@ -497,6 +540,14 @@ static ssize_t device_write(struct file *file, const char __user *buf,
error = device_remove_lockspace(&kbuf->i.lspace);
break;
+ case DLM_USER_PURGE:
+ if (!proc) {
+ log_print("no locking on control device");
+ goto out_sig;
+ }
+ error = device_user_purge(proc, &kbuf->i.purge);
+ break;
+
default:
log_print("Unknown command passed to DLM device : %d\n",
kbuf->cmd);
diff --git a/fs/dquot.c b/fs/dquot.c
index b16f991662c..3a995841de9 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -69,7 +69,6 @@
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
@@ -475,7 +474,7 @@ int vfs_quota_sync(struct super_block *sb, int type)
spin_lock(&dq_list_lock);
dirty = &dqopt->info[cnt].dqi_dirty_list;
while (!list_empty(dirty)) {
- dquot = list_entry(dirty->next, struct dquot, dq_dirty);
+ dquot = list_first_entry(dirty, struct dquot, dq_dirty);
/* Dirty and inactive can be only bad dquot... */
if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
clear_dquot_dirty(dquot);
@@ -721,7 +720,8 @@ static inline int dqput_blocks(struct dquot *dquot)
/* Remove references to dquots from inode - add dquot to list for freeing if needed */
/* We can't race with anybody because we hold dqptr_sem for writing... */
-int remove_inode_dquot_ref(struct inode *inode, int type, struct list_head *tofree_head)
+static int remove_inode_dquot_ref(struct inode *inode, int type,
+ struct list_head *tofree_head)
{
struct dquot *dquot = inode->i_dquot[type];
@@ -1432,7 +1432,7 @@ int vfs_quota_off(struct super_block *sb, int type)
mutex_unlock(&dqopt->dqonoff_mutex);
}
if (sb->s_bdev)
- invalidate_bdev(sb->s_bdev, 0);
+ invalidate_bdev(sb->s_bdev);
return 0;
}
@@ -1468,7 +1468,7 @@ static int vfs_quota_on_inode(struct inode *inode, int type, int format_id)
* we see all the changes from userspace... */
write_inode_now(inode, 1);
/* And now flush the block cache so that kernel sees the changes */
- invalidate_bdev(sb->s_bdev, 0);
+ invalidate_bdev(sb->s_bdev);
mutex_lock(&inode->i_mutex);
mutex_lock(&dqopt->dqonoff_mutex);
if (sb_has_quota_enabled(sb, type)) {
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 7a7d25d541e..9881b5c5de5 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -28,7 +28,6 @@
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/security.h>
-#include <linux/smp_lock.h>
#include <linux/compat.h>
#include <linux/fs_stack.h>
#include "ecryptfs_kernel.h"
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index fc4a3a22464..8cbf3f69ebe 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -583,8 +583,7 @@ inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
{
struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
@@ -793,7 +792,7 @@ static int do_sysfs_registration(void)
"Unable to register ecryptfs sysfs subsystem\n");
goto out;
}
- rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+ rc = sysfs_create_file(&ecryptfs_subsys.kobj,
&sysfs_attr_version.attr);
if (rc) {
printk(KERN_ERR
@@ -801,12 +800,12 @@ static int do_sysfs_registration(void)
subsystem_unregister(&ecryptfs_subsys);
goto out;
}
- rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+ rc = sysfs_create_file(&ecryptfs_subsys.kobj,
&sysfs_attr_version_str.attr);
if (rc) {
printk(KERN_ERR
"Unable to create ecryptfs version_str attribute\n");
- sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ sysfs_remove_file(&ecryptfs_subsys.kobj,
&sysfs_attr_version.attr);
subsystem_unregister(&ecryptfs_subsys);
goto out;
@@ -841,7 +840,7 @@ static int __init ecryptfs_init(void)
ecryptfs_free_kmem_caches();
goto out;
}
- kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
+ kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
sysfs_attr_version.attr.owner = THIS_MODULE;
sysfs_attr_version_str.attr.owner = THIS_MODULE;
rc = do_sysfs_registration();
@@ -862,9 +861,9 @@ out:
static void __exit ecryptfs_exit(void)
{
- sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ sysfs_remove_file(&ecryptfs_subsys.kobj,
&sysfs_attr_version.attr);
- sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ sysfs_remove_file(&ecryptfs_subsys.kobj,
&sysfs_attr_version_str.attr);
subsystem_unregister(&ecryptfs_subsys);
ecryptfs_release_messaging(ecryptfs_transport);
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index b731b09499c..0770c4b66f5 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -46,7 +46,6 @@ struct kmem_cache *ecryptfs_lower_page_cache;
*/
static struct page *ecryptfs_get1page(struct file *file, int index)
{
- struct page *page;
struct dentry *dentry;
struct inode *inode;
struct address_space *mapping;
@@ -54,14 +53,7 @@ static struct page *ecryptfs_get1page(struct file *file, int index)
dentry = file->f_path.dentry;
inode = dentry->d_inode;
mapping = inode->i_mapping;
- page = read_cache_page(mapping, index,
- (filler_t *)mapping->a_ops->readpage,
- (void *)file);
- if (IS_ERR(page))
- goto out;
- wait_on_page_locked(page);
-out:
- return page;
+ return read_mapping_page(mapping, index, (void *)file);
}
static
@@ -233,7 +225,6 @@ int ecryptfs_do_readpage(struct file *file, struct page *page,
ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
goto out;
}
- wait_on_page_locked(lower_page);
page_data = kmap_atomic(page, KM_USER0);
lower_page_data = kmap_atomic(lower_page, KM_USER1);
memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
diff --git a/fs/efs/super.c b/fs/efs/super.c
index c2235e46edc..ba7a8b9da0c 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -72,8 +72,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct efs_inode_info *ei = (struct efs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 3ae644e7e86..b5c7ca58493 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -22,7 +22,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/hash.h>
@@ -185,7 +184,7 @@ struct eppoll_entry {
/*
* Each file descriptor added to the eventpoll interface will
- * have an entry of this type linked to the hash.
+ * have an entry of this type linked to the "rbr" RB tree.
*/
struct epitem {
/* RB-Tree node used to link this structure to the eventpoll rb-tree */
@@ -217,15 +216,6 @@ struct epitem {
/* List header used to link this item to the "struct file" items list */
struct list_head fllink;
-
- /* List header used to link the item to the transfer list */
- struct list_head txlink;
-
- /*
- * This is used during the collection/transfer of events to userspace
- * to pin items empty events set.
- */
- unsigned int revents;
};
/* Wrapper struct used by poll queueing */
@@ -258,11 +248,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi);
static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key);
static int ep_eventpoll_close(struct inode *inode, struct file *file);
static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
-static int ep_collect_ready_items(struct eventpoll *ep,
- struct list_head *txlist, int maxevents);
static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
- struct epoll_event __user *events);
-static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist);
+ struct epoll_event __user *events, int maxevents);
static int ep_events_transfer(struct eventpoll *ep,
struct epoll_event __user *events,
int maxevents);
@@ -355,17 +342,6 @@ static inline int ep_rb_linked(struct rb_node *n)
return rb_parent(n) != n;
}
-/*
- * Remove the item from the list and perform its initialization.
- * This is useful for us because we can test if the item is linked
- * using "ep_is_linked(p)".
- */
-static inline void ep_list_del(struct list_head *p)
-{
- list_del(p);
- INIT_LIST_HEAD(p);
-}
-
/* Tells us if the item is currently linked */
static inline int ep_is_linked(struct list_head *p)
{
@@ -385,7 +361,7 @@ static inline struct epitem * ep_item_from_epqueue(poll_table *p)
}
/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */
-static inline int ep_op_hash_event(int op)
+static inline int ep_op_has_event(int op)
{
return op != EPOLL_CTL_DEL;
}
@@ -477,10 +453,10 @@ void eventpoll_release_file(struct file *file)
mutex_lock(&epmutex);
while (!list_empty(lsthead)) {
- epi = list_entry(lsthead->next, struct epitem, fllink);
+ epi = list_first_entry(lsthead, struct epitem, fllink);
ep = epi->ep;
- ep_list_del(&epi->fllink);
+ list_del_init(&epi->fllink);
down_write(&ep->sem);
ep_remove(ep, epi);
up_write(&ep->sem);
@@ -557,7 +533,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
current, epfd, op, fd, event));
error = -EFAULT;
- if (ep_op_hash_event(op) &&
+ if (ep_op_has_event(op) &&
copy_from_user(&epds, event, sizeof(struct epoll_event)))
goto eexit_1;
@@ -594,7 +570,7 @@ sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
down_write(&ep->sem);
- /* Try to lookup the file inside our hash table */
+ /* Try to lookup the file inside our RB tree */
epi = ep_find(ep, tfile, fd);
error = -EINVAL;
@@ -876,7 +852,7 @@ static void ep_free(struct eventpoll *ep)
}
/*
- * Walks through the whole hash by freeing each "struct epitem". At this
+ * Walks through the whole tree by freeing each "struct epitem". At this
* point we are sure no poll callbacks will be lingering around, and also by
* write-holding "sem" we can be sure that no file cleanup code will hit
* us during this operation. So we can avoid the lock on "ep->lock".
@@ -891,7 +867,7 @@ static void ep_free(struct eventpoll *ep)
/*
- * Search the file inside the eventpoll hash. It add usage count to
+ * Search the file inside the eventpoll tree. It add usage count to
* the returned item, so the caller must call ep_release_epitem()
* after finished using the "struct epitem".
*/
@@ -1011,7 +987,6 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
ep_rb_initnode(&epi->rbn);
INIT_LIST_HEAD(&epi->rdllink);
INIT_LIST_HEAD(&epi->fllink);
- INIT_LIST_HEAD(&epi->txlink);
INIT_LIST_HEAD(&epi->pwqlist);
epi->ep = ep;
ep_set_ffd(&epi->ffd, tfile, fd);
@@ -1080,7 +1055,7 @@ eexit_2:
*/
write_lock_irqsave(&ep->lock, flags);
if (ep_is_linked(&epi->rdllink))
- ep_list_del(&epi->rdllink);
+ list_del_init(&epi->rdllink);
write_unlock_irqrestore(&ep->lock, flags);
kmem_cache_free(epi_cache, epi);
@@ -1119,7 +1094,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
epi->event.data = event->data;
/*
- * If the item is not linked to the hash it means that it's on its
+ * If the item is not linked to the RB tree it means that it's on its
* way toward the removal. Do nothing in this case.
*/
if (ep_rb_linked(&epi->rbn)) {
@@ -1168,9 +1143,9 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
if (nwait) {
while (!list_empty(lsthead)) {
- pwq = list_entry(lsthead->next, struct eppoll_entry, llink);
+ pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
- ep_list_del(&pwq->llink);
+ list_del_init(&pwq->llink);
remove_wait_queue(pwq->whead, &pwq->wait);
kmem_cache_free(pwq_cache, pwq);
}
@@ -1213,7 +1188,7 @@ static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
* we want to remove it from this list to avoid stale events.
*/
if (ep_is_linked(&epi->rdllink))
- ep_list_del(&epi->rdllink);
+ list_del_init(&epi->rdllink);
error = 0;
eexit_1:
@@ -1226,7 +1201,7 @@ eexit_1:
/*
- * Removes a "struct epitem" from the eventpoll hash and deallocates
+ * Removes a "struct epitem" from the eventpoll RB tree and deallocates
* all the associated resources.
*/
static int ep_remove(struct eventpoll *ep, struct epitem *epi)
@@ -1248,13 +1223,13 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
/* Remove the current item from the list of epoll hooks */
spin_lock(&file->f_ep_lock);
if (ep_is_linked(&epi->fllink))
- ep_list_del(&epi->fllink);
+ list_del_init(&epi->fllink);
spin_unlock(&file->f_ep_lock);
/* We need to acquire the write IRQ lock before calling ep_unlink() */
write_lock_irqsave(&ep->lock, flags);
- /* Really unlink the item from the hash */
+ /* Really unlink the item from the RB tree */
error = ep_unlink(ep, epi);
write_unlock_irqrestore(&ep->lock, flags);
@@ -1362,71 +1337,30 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
/*
- * Since we have to release the lock during the __copy_to_user() operation and
- * during the f_op->poll() call, we try to collect the maximum number of items
- * by reducing the irqlock/irqunlock switching rate.
- */
-static int ep_collect_ready_items(struct eventpoll *ep, struct list_head *txlist, int maxevents)
-{
- int nepi;
- unsigned long flags;
- struct list_head *lsthead = &ep->rdllist, *lnk;
- struct epitem *epi;
-
- write_lock_irqsave(&ep->lock, flags);
-
- for (nepi = 0, lnk = lsthead->next; lnk != lsthead && nepi < maxevents;) {
- epi = list_entry(lnk, struct epitem, rdllink);
-
- lnk = lnk->next;
-
- /* If this file is already in the ready list we exit soon */
- if (!ep_is_linked(&epi->txlink)) {
- /*
- * This is initialized in this way so that the default
- * behaviour of the reinjecting code will be to push back
- * the item inside the ready list.
- */
- epi->revents = epi->event.events;
-
- /* Link the ready item into the transfer list */
- list_add(&epi->txlink, txlist);
- nepi++;
-
- /*
- * Unlink the item from the ready list.
- */
- ep_list_del(&epi->rdllink);
- }
- }
-
- write_unlock_irqrestore(&ep->lock, flags);
-
- return nepi;
-}
-
-
-/*
* This function is called without holding the "ep->lock" since the call to
* __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ
* because of the way poll() is traditionally implemented in Linux.
*/
static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
- struct epoll_event __user *events)
+ struct epoll_event __user *events, int maxevents)
{
- int eventcnt = 0;
+ int eventcnt, error = -EFAULT, pwake = 0;
unsigned int revents;
- struct list_head *lnk;
+ unsigned long flags;
struct epitem *epi;
+ struct list_head injlist;
+
+ INIT_LIST_HEAD(&injlist);
/*
* We can loop without lock because this is a task private list.
- * The test done during the collection loop will guarantee us that
- * another task will not try to collect this file. Also, items
- * cannot vanish during the loop because we are holding "sem".
+ * We just splice'd out the ep->rdllist in ep_collect_ready_items().
+ * Items cannot vanish during the loop because we are holding "sem" in
+ * read.
*/
- list_for_each(lnk, txlist) {
- epi = list_entry(lnk, struct epitem, txlink);
+ for (eventcnt = 0; !list_empty(txlist) && eventcnt < maxevents;) {
+ epi = list_first_entry(txlist, struct epitem, rdllink);
+ prefetch(epi->rdllink.next);
/*
* Get the ready file event set. We can safely use the file
@@ -1434,64 +1368,65 @@ static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
* guarantee that both the file and the item will not vanish.
*/
revents = epi->ffd.file->f_op->poll(epi->ffd.file, NULL);
+ revents &= epi->event.events;
/*
- * Set the return event set for the current file descriptor.
- * Note that only the task task was successfully able to link
- * the item to its "txlist" will write this field.
+ * Is the event mask intersect the caller-requested one,
+ * deliver the event to userspace. Again, we are holding
+ * "sem" in read, so no operations coming from userspace
+ * can change the item.
*/
- epi->revents = revents & epi->event.events;
-
- if (epi->revents) {
- if (__put_user(epi->revents,
+ if (revents) {
+ if (__put_user(revents,
&events[eventcnt].events) ||
__put_user(epi->event.data,
&events[eventcnt].data))
- return -EFAULT;
+ goto errxit;
if (epi->event.events & EPOLLONESHOT)
epi->event.events &= EP_PRIVATE_BITS;
eventcnt++;
}
- }
- return eventcnt;
-}
-
-
-/*
- * Walk through the transfer list we collected with ep_collect_ready_items()
- * and, if 1) the item is still "alive" 2) its event set is not empty 3) it's
- * not already linked, links it to the ready list. Same as above, we are holding
- * "sem" so items cannot vanish underneath our nose.
- */
-static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
-{
- int ricnt = 0, pwake = 0;
- unsigned long flags;
- struct epitem *epi;
-
- write_lock_irqsave(&ep->lock, flags);
-
- while (!list_empty(txlist)) {
- epi = list_entry(txlist->next, struct epitem, txlink);
-
- /* Unlink the current item from the transfer list */
- ep_list_del(&epi->txlink);
/*
- * If the item is no more linked to the interest set, we don't
- * have to push it inside the ready list because the following
- * ep_release_epitem() is going to drop it. Also, if the current
- * item is set to have an Edge Triggered behaviour, we don't have
- * to push it back either.
+ * This is tricky. We are holding the "sem" in read, and this
+ * means that the operations that can change the "linked" status
+ * of the epoll item (epi->rbn and epi->rdllink), cannot touch
+ * them. Also, since we are "linked" from a epi->rdllink POV
+ * (the item is linked to our transmission list we just
+ * spliced), the ep_poll_callback() cannot touch us either,
+ * because of the check present in there. Another parallel
+ * epoll_wait() will not get the same result set, since we
+ * spliced the ready list before. Note that list_del() still
+ * shows the item as linked to the test in ep_poll_callback().
*/
- if (ep_rb_linked(&epi->rbn) && !(epi->event.events & EPOLLET) &&
- (epi->revents & epi->event.events) && !ep_is_linked(&epi->rdllink)) {
- list_add_tail(&epi->rdllink, &ep->rdllist);
- ricnt++;
+ list_del(&epi->rdllink);
+ if (!(epi->event.events & EPOLLET) &&
+ (revents & epi->event.events))
+ list_add_tail(&epi->rdllink, &injlist);
+ else {
+ /*
+ * Be sure the item is totally detached before re-init
+ * the list_head. After INIT_LIST_HEAD() is committed,
+ * the ep_poll_callback() can requeue the item again,
+ * but we don't care since we are already past it.
+ */
+ smp_mb();
+ INIT_LIST_HEAD(&epi->rdllink);
}
}
+ error = 0;
- if (ricnt) {
+ errxit:
+
+ /*
+ * If the re-injection list or the txlist are not empty, re-splice
+ * them to the ready list and do proper wakeups.
+ */
+ if (!list_empty(&injlist) || !list_empty(txlist)) {
+ write_lock_irqsave(&ep->lock, flags);
+
+ list_splice(txlist, &ep->rdllist);
+ list_splice(&injlist, &ep->rdllist);
/*
* Wake up ( if active ) both the eventpoll wait list and the ->poll()
* wait list.
@@ -1501,13 +1436,15 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
TASK_INTERRUPTIBLE);
if (waitqueue_active(&ep->poll_wait))
pwake++;
- }
- write_unlock_irqrestore(&ep->lock, flags);
+ write_unlock_irqrestore(&ep->lock, flags);
+ }
/* We have to call this outside the lock */
if (pwake)
ep_poll_safewake(&psw, &ep->poll_wait);
+
+ return eventcnt == 0 ? error: eventcnt;
}
@@ -1517,7 +1454,8 @@ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist)
static int ep_events_transfer(struct eventpoll *ep,
struct epoll_event __user *events, int maxevents)
{
- int eventcnt = 0;
+ int eventcnt;
+ unsigned long flags;
struct list_head txlist;
INIT_LIST_HEAD(&txlist);
@@ -1528,14 +1466,17 @@ static int ep_events_transfer(struct eventpoll *ep,
*/
down_read(&ep->sem);
- /* Collect/extract ready items */
- if (ep_collect_ready_items(ep, &txlist, maxevents) > 0) {
- /* Build result set in userspace */
- eventcnt = ep_send_events(ep, &txlist, events);
+ /*
+ * Steal the ready list, and re-init the original one to the
+ * empty list.
+ */
+ write_lock_irqsave(&ep->lock, flags);
+ list_splice(&ep->rdllist, &txlist);
+ INIT_LIST_HEAD(&ep->rdllist);
+ write_unlock_irqrestore(&ep->lock, flags);
- /* Reinject ready items into the ready list */
- ep_reinject_items(ep, &txlist);
- }
+ /* Build result set in userspace */
+ eventcnt = ep_send_events(ep, &txlist, events, maxevents);
up_read(&ep->sem);
@@ -1612,14 +1553,12 @@ retry:
return res;
}
-
static int eventpollfs_delete_dentry(struct dentry *dentry)
{
return 1;
}
-
static struct inode *ep_eventpoll_inode(void)
{
int error = -ENOMEM;
@@ -1647,7 +1586,6 @@ eexit_1:
return ERR_PTR(error);
}
-
static int
eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt)
diff --git a/fs/exec.c b/fs/exec.c
index 3155e915307..1ba85c7fc6a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -100,6 +100,7 @@ int unregister_binfmt(struct linux_binfmt * fmt)
while (*tmp) {
if (fmt == *tmp) {
*tmp = fmt->next;
+ fmt->next = NULL;
write_unlock(&binfmt_lock);
return 0;
}
@@ -982,33 +983,51 @@ void compute_creds(struct linux_binprm *bprm)
task_unlock(current);
security_bprm_post_apply_creds(bprm);
}
-
EXPORT_SYMBOL(compute_creds);
+/*
+ * Arguments are '\0' separated strings found at the location bprm->p
+ * points to; chop off the first by relocating brpm->p to right after
+ * the first '\0' encountered.
+ */
void remove_arg_zero(struct linux_binprm *bprm)
{
if (bprm->argc) {
- unsigned long offset;
- char * kaddr;
- struct page *page;
+ char ch;
- offset = bprm->p % PAGE_SIZE;
- goto inside;
+ do {
+ unsigned long offset;
+ unsigned long index;
+ char *kaddr;
+ struct page *page;
- while (bprm->p++, *(kaddr+offset++)) {
- if (offset != PAGE_SIZE)
- continue;
- offset = 0;
- kunmap_atomic(kaddr, KM_USER0);
-inside:
- page = bprm->page[bprm->p/PAGE_SIZE];
+ offset = bprm->p & ~PAGE_MASK;
+ index = bprm->p >> PAGE_SHIFT;
+
+ page = bprm->page[index];
kaddr = kmap_atomic(page, KM_USER0);
- }
- kunmap_atomic(kaddr, KM_USER0);
+
+ /* run through page until we reach end or find NUL */
+ do {
+ ch = *(kaddr + offset);
+
+ /* discard that character... */
+ bprm->p++;
+ offset++;
+ } while (offset < PAGE_SIZE && ch != '\0');
+
+ kunmap_atomic(kaddr, KM_USER0);
+
+ /* free the old page */
+ if (offset == PAGE_SIZE) {
+ __free_page(page);
+ bprm->page[index] = NULL;
+ }
+ } while (ch != '\0');
+
bprm->argc--;
}
}
-
EXPORT_SYMBOL(remove_arg_zero);
/*
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 93e77c3d249..e98f6cd7200 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -2,7 +2,6 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/namei.h>
struct export_operations export_op_default;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index e89bfc8cf95..2bf49d7ef84 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -23,7 +23,6 @@
#include "ext2.h"
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
typedef struct ext2_dir_entry_2 ext2_dirent;
@@ -161,10 +160,7 @@ static struct page * ext2_get_page(struct inode *dir, unsigned long n)
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
- if (!PageUptodate(page))
- goto fail;
if (!PageChecked(page))
ext2_check_page(page);
if (PageError(page))
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index e2a0ea50af1..9fd0ec5ba0d 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -133,6 +133,7 @@ extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern void ext2_truncate (struct inode *);
extern int ext2_setattr (struct dentry *, struct iattr *);
extern void ext2_set_inode_flags(struct inode *inode);
+extern void ext2_get_inode_flags(struct ext2_inode_info *);
/* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c
index 7806b9e8155..fc66c93fcb5 100644
--- a/fs/ext2/fsync.c
+++ b/fs/ext2/fsync.c
@@ -23,7 +23,6 @@
*/
#include "ext2.h"
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h> /* for sync_mapping_buffers() */
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index dd4e14c221e..0079b2cd531 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1055,6 +1055,25 @@ void ext2_set_inode_flags(struct inode *inode)
inode->i_flags |= S_DIRSYNC;
}
+/* Propagate flags from i_flags to EXT2_I(inode)->i_flags */
+void ext2_get_inode_flags(struct ext2_inode_info *ei)
+{
+ unsigned int flags = ei->vfs_inode.i_flags;
+
+ ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL|
+ EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL);
+ if (flags & S_SYNC)
+ ei->i_flags |= EXT2_SYNC_FL;
+ if (flags & S_APPEND)
+ ei->i_flags |= EXT2_APPEND_FL;
+ if (flags & S_IMMUTABLE)
+ ei->i_flags |= EXT2_IMMUTABLE_FL;
+ if (flags & S_NOATIME)
+ ei->i_flags |= EXT2_NOATIME_FL;
+ if (flags & S_DIRSYNC)
+ ei->i_flags |= EXT2_DIRSYNC_FL;
+}
+
void ext2_read_inode (struct inode * inode)
{
struct ext2_inode_info *ei = EXT2_I(inode);
@@ -1079,9 +1098,9 @@ void ext2_read_inode (struct inode * inode)
}
inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
inode->i_size = le32_to_cpu(raw_inode->i_size);
- inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->i_mtime);
+ inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
+ inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
+ inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0;
ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
/* We now have enough fields to check if the inode was active or not.
@@ -1188,6 +1207,7 @@ static int ext2_update_inode(struct inode * inode, int do_sync)
if (ei->i_state & EXT2_STATE_NEW)
memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size);
+ ext2_get_inode_flags(ei);
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
if (!(test_opt(sb, NO_UID32))) {
raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 4b099d31071..e85c4821823 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -27,6 +27,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
switch (cmd) {
case EXT2_IOC_GETFLAGS:
+ ext2_get_inode_flags(ei);
flags = ei->i_flags & EXT2_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT2_IOC_SETFLAGS: {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index a046a419d8a..685a1c28717 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -160,8 +160,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct ext2_inode_info *ei = (struct ext2_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
rwlock_init(&ei->i_meta_lock);
#ifdef CONFIG_EXT2_FS_XATTR
init_rwsem(&ei->xattr_sem);
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index a2661279847..eaa23d2d521 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext2_fs.h>
#include <linux/security.h>
#include "xattr.h"
diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c
index f28a6a499c9..83ee149f353 100644
--- a/fs/ext2/xattr_trusted.c
+++ b/fs/ext2/xattr_trusted.c
@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/capability.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext2_fs.h>
#include "xattr.h"
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 665adee99b3..852869840f2 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -25,7 +25,6 @@
#include <linux/jbd.h>
#include <linux/ext3_fs.h>
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/rbtree.h>
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index a5b150f7e8a..a6cb6171c3a 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -27,7 +27,6 @@
#include <linux/time.h>
#include <linux/ext3_jbd.h>
#include <linux/jbd.h>
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
@@ -1768,7 +1767,6 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
struct inode *inode = mapping->host;
struct buffer_head *bh;
int err = 0;
- void *kaddr;
blocksize = inode->i_sb->s_blocksize;
length = blocksize - (offset & (blocksize - 1));
@@ -1780,10 +1778,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
*/
if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
ext3_should_writeback_data(inode) && PageUptodate(page)) {
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, length, KM_USER0);
set_page_dirty(page);
goto unlock;
}
@@ -1836,11 +1831,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page,
goto unlock;
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
-
+ zero_user_page(page, offset, length, KM_USER0);
BUFFER_TRACE(bh, "zeroed end of block");
err = 0;
@@ -2581,6 +2572,25 @@ void ext3_set_inode_flags(struct inode *inode)
inode->i_flags |= S_DIRSYNC;
}
+/* Propagate flags from i_flags to EXT3_I(inode)->i_flags */
+void ext3_get_inode_flags(struct ext3_inode_info *ei)
+{
+ unsigned int flags = ei->vfs_inode.i_flags;
+
+ ei->i_flags &= ~(EXT3_SYNC_FL|EXT3_APPEND_FL|
+ EXT3_IMMUTABLE_FL|EXT3_NOATIME_FL|EXT3_DIRSYNC_FL);
+ if (flags & S_SYNC)
+ ei->i_flags |= EXT3_SYNC_FL;
+ if (flags & S_APPEND)
+ ei->i_flags |= EXT3_APPEND_FL;
+ if (flags & S_IMMUTABLE)
+ ei->i_flags |= EXT3_IMMUTABLE_FL;
+ if (flags & S_NOATIME)
+ ei->i_flags |= EXT3_NOATIME_FL;
+ if (flags & S_DIRSYNC)
+ ei->i_flags |= EXT3_DIRSYNC_FL;
+}
+
void ext3_read_inode(struct inode * inode)
{
struct ext3_iloc iloc;
@@ -2608,9 +2618,9 @@ void ext3_read_inode(struct inode * inode)
}
inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
inode->i_size = le32_to_cpu(raw_inode->i_size);
- inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->i_mtime);
+ inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
+ inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
+ inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
ei->i_state = 0;
@@ -2736,6 +2746,7 @@ static int ext3_do_update_inode(handle_t *handle,
if (ei->i_state & EXT3_STATE_NEW)
memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size);
+ ext3_get_inode_flags(ei);
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
if(!(test_opt(inode->i_sb, NO_UID32))) {
raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 9b8090d94e6..965006dba6b 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -28,6 +28,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
switch (cmd) {
case EXT3_IOC_GETFLAGS:
+ ext3_get_inode_flags(ei);
flags = ei->i_flags & EXT3_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT3_IOC_SETFLAGS: {
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 49159f13cc1..9bb046df827 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -36,7 +36,6 @@
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
#include <linux/bio.h>
-#include <linux/smp_lock.h>
#include "namei.h"
#include "xattr.h"
@@ -969,6 +968,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
(block<<EXT3_BLOCK_SIZE_BITS(sb))
+((char *)de - bh->b_data))) {
brelse (bh);
+ *err = ERR_BAD_DX_DIR;
goto errout;
}
*res_dir = de;
@@ -1134,9 +1134,9 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
char *data1 = (*bh)->b_data, *data2;
unsigned split;
struct ext3_dir_entry_2 *de = NULL, *de2;
- int err;
+ int err = 0;
- bh2 = ext3_append (handle, dir, &newblock, error);
+ bh2 = ext3_append (handle, dir, &newblock, &err);
if (!(bh2)) {
brelse(*bh);
*bh = NULL;
@@ -1145,14 +1145,9 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
BUFFER_TRACE(*bh, "get_write_access");
err = ext3_journal_get_write_access(handle, *bh);
- if (err) {
- journal_error:
- brelse(*bh);
- brelse(bh2);
- *bh = NULL;
- ext3_std_error(dir->i_sb, err);
- goto errout;
- }
+ if (err)
+ goto journal_error;
+
BUFFER_TRACE(frame->bh, "get_write_access");
err = ext3_journal_get_write_access(handle, frame->bh);
if (err)
@@ -1195,8 +1190,16 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
goto journal_error;
brelse (bh2);
dxtrace(dx_show_index ("frame", frame->entries));
-errout:
return de;
+
+journal_error:
+ brelse(*bh);
+ brelse(bh2);
+ *bh = NULL;
+ ext3_std_error(dir->i_sb, err);
+errout:
+ *error = err;
+ return NULL;
}
#endif
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index ecf89904c11..2c97e09c6c6 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -11,7 +11,6 @@
#define EXT3FS_DEBUG
-#include <linux/smp_lock.h>
#include <linux/ext3_jbd.h>
#include <linux/errno.h>
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 4a4fcd6868c..54d3c904125 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -420,7 +420,7 @@ static void ext3_put_super (struct super_block * sb)
dump_orphan_list(sb, sbi);
J_ASSERT(list_empty(&sbi->s_orphan));
- invalidate_bdev(sb->s_bdev, 0);
+ invalidate_bdev(sb->s_bdev);
if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
/*
* Invalidate the journal device's buffers. We don't want them
@@ -428,7 +428,7 @@ static void ext3_put_super (struct super_block * sb)
* hotswapped, and it breaks the `ro-after' testing code.
*/
sync_blockdev(sbi->journal_bdev);
- invalidate_bdev(sbi->journal_bdev, 0);
+ invalidate_bdev(sbi->journal_bdev);
ext3_blkdev_remove(sbi);
}
sb->s_fs_info = NULL;
@@ -466,8 +466,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct ext3_inode_info *ei = (struct ext3_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
INIT_LIST_HEAD(&ei->i_orphan);
#ifdef CONFIG_EXT3_FS_XATTR
init_rwsem(&ei->xattr_sem);
diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
index b9c40c15647..821efaf2b94 100644
--- a/fs/ext3/xattr_security.c
+++ b/fs/ext3/xattr_security.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include <linux/security.h>
diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c
index 86d91f1186d..0327497a55c 100644
--- a/fs/ext3/xattr_trusted.c
+++ b/fs/ext3/xattr_trusted.c
@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/capability.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include "xattr.h"
diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c
index a85a0a17c4f..1abd8f92c44 100644
--- a/fs/ext3/xattr_user.c
+++ b/fs/ext3/xattr_user.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext3_jbd.h>
#include <linux/ext3_fs.h>
#include "xattr.h"
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index da80368b66f..e8ad06e2831 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -25,7 +25,6 @@
#include <linux/jbd2.h>
#include <linux/ext4_fs.h>
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/rbtree.h>
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 7916b50f9a1..a0f0c04e79b 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -34,7 +34,6 @@
#include <linux/time.h>
#include <linux/ext4_jbd2.h>
#include <linux/jbd.h>
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 810b6d6474b..b34182b6ee4 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -27,7 +27,6 @@
#include <linux/time.h>
#include <linux/ext4_jbd2.h>
#include <linux/jbd2.h>
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
@@ -2611,9 +2610,9 @@ void ext4_read_inode(struct inode * inode)
}
inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
inode->i_size = le32_to_cpu(raw_inode->i_size);
- inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->i_mtime);
+ inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
+ inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
+ inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
ei->i_state = 0;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index e7e1d79a7d7..4ec57be5baf 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -36,7 +36,6 @@
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
#include <linux/bio.h>
-#include <linux/smp_lock.h>
#include "namei.h"
#include "xattr.h"
@@ -967,6 +966,7 @@ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
(block<<EXT4_BLOCK_SIZE_BITS(sb))
+((char *)de - bh->b_data))) {
brelse (bh);
+ *err = ERR_BAD_DX_DIR;
goto errout;
}
*res_dir = de;
@@ -1132,9 +1132,9 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
char *data1 = (*bh)->b_data, *data2;
unsigned split;
struct ext4_dir_entry_2 *de = NULL, *de2;
- int err;
+ int err = 0;
- bh2 = ext4_append (handle, dir, &newblock, error);
+ bh2 = ext4_append (handle, dir, &newblock, &err);
if (!(bh2)) {
brelse(*bh);
*bh = NULL;
@@ -1143,14 +1143,9 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
BUFFER_TRACE(*bh, "get_write_access");
err = ext4_journal_get_write_access(handle, *bh);
- if (err) {
- journal_error:
- brelse(*bh);
- brelse(bh2);
- *bh = NULL;
- ext4_std_error(dir->i_sb, err);
- goto errout;
- }
+ if (err)
+ goto journal_error;
+
BUFFER_TRACE(frame->bh, "get_write_access");
err = ext4_journal_get_write_access(handle, frame->bh);
if (err)
@@ -1193,8 +1188,16 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
goto journal_error;
brelse (bh2);
dxtrace(dx_show_index ("frame", frame->entries));
-errout:
return de;
+
+journal_error:
+ brelse(*bh);
+ brelse(bh2);
+ *bh = NULL;
+ ext4_std_error(dir->i_sb, err);
+errout:
+ *error = err;
+ return NULL;
}
#endif
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index ea99f6c97f5..aa11d7dbe97 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -11,7 +11,6 @@
#define EXT4FS_DEBUG
-#include <linux/smp_lock.h>
#include <linux/ext4_jbd2.h>
#include <linux/errno.h>
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 61c4718e4a5..71912693235 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -470,7 +470,7 @@ static void ext4_put_super (struct super_block * sb)
dump_orphan_list(sb, sbi);
J_ASSERT(list_empty(&sbi->s_orphan));
- invalidate_bdev(sb->s_bdev, 0);
+ invalidate_bdev(sb->s_bdev);
if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
/*
* Invalidate the journal device's buffers. We don't want them
@@ -478,7 +478,7 @@ static void ext4_put_super (struct super_block * sb)
* hotswapped, and it breaks the `ro-after' testing code.
*/
sync_blockdev(sbi->journal_bdev);
- invalidate_bdev(sbi->journal_bdev, 0);
+ invalidate_bdev(sbi->journal_bdev);
ext4_blkdev_remove(sbi);
}
sb->s_fs_info = NULL;
@@ -517,8 +517,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct ext4_inode_info *ei = (struct ext4_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
INIT_LIST_HEAD(&ei->i_orphan);
#ifdef CONFIG_EXT4DEV_FS_XATTR
init_rwsem(&ei->xattr_sem);
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index b6a6861951f..f17eaf2321b 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -6,7 +6,6 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext4_jbd2.h>
#include <linux/ext4_fs.h>
#include <linux/security.h>
diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
index b76f2dbc82d..e0f05acdafe 100644
--- a/fs/ext4/xattr_trusted.c
+++ b/fs/ext4/xattr_trusted.c
@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/capability.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext4_jbd2.h>
#include <linux/ext4_fs.h>
#include "xattr.h"
diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c
index c53cded0761..7ed3d8ebf09 100644
--- a/fs/ext4/xattr_user.c
+++ b/fs/ext4/xattr_user.c
@@ -8,7 +8,6 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/ext4_jbd2.h>
#include <linux/ext4_fs.h>
#include "xattr.h"
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 05c2941c74f..1959143c1d2 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -40,8 +40,7 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct fat_cache *cache = (struct fat_cache *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
INIT_LIST_HEAD(&cache->cache_list);
}
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index c16af246d24..ccf161dffb6 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -422,7 +422,7 @@ EODir:
EXPORT_SYMBOL_GPL(fat_search_long);
struct fat_ioctl_filldir_callback {
- struct dirent __user *dirent;
+ void __user *dirent;
int result;
/* for dir ioctl */
const char *longname;
@@ -647,62 +647,85 @@ static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
return __fat_readdir(inode, filp, dirent, filldir, 0, 0);
}
-static int fat_ioctl_filldir(void *__buf, const char *name, int name_len,
- loff_t offset, u64 ino, unsigned int d_type)
+#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
+static int func(void *__buf, const char *name, int name_len, \
+ loff_t offset, u64 ino, unsigned int d_type) \
+{ \
+ struct fat_ioctl_filldir_callback *buf = __buf; \
+ struct dirent_type __user *d1 = buf->dirent; \
+ struct dirent_type __user *d2 = d1 + 1; \
+ \
+ if (buf->result) \
+ return -EINVAL; \
+ buf->result++; \
+ \
+ if (name != NULL) { \
+ /* dirent has only short name */ \
+ if (name_len >= sizeof(d1->d_name)) \
+ name_len = sizeof(d1->d_name) - 1; \
+ \
+ if (put_user(0, d2->d_name) || \
+ put_user(0, &d2->d_reclen) || \
+ copy_to_user(d1->d_name, name, name_len) || \
+ put_user(0, d1->d_name + name_len) || \
+ put_user(name_len, &d1->d_reclen)) \
+ goto efault; \
+ } else { \
+ /* dirent has short and long name */ \
+ const char *longname = buf->longname; \
+ int long_len = buf->long_len; \
+ const char *shortname = buf->shortname; \
+ int short_len = buf->short_len; \
+ \
+ if (long_len >= sizeof(d1->d_name)) \
+ long_len = sizeof(d1->d_name) - 1; \
+ if (short_len >= sizeof(d1->d_name)) \
+ short_len = sizeof(d1->d_name) - 1; \
+ \
+ if (copy_to_user(d2->d_name, longname, long_len) || \
+ put_user(0, d2->d_name + long_len) || \
+ put_user(long_len, &d2->d_reclen) || \
+ put_user(ino, &d2->d_ino) || \
+ put_user(offset, &d2->d_off) || \
+ copy_to_user(d1->d_name, shortname, short_len) || \
+ put_user(0, d1->d_name + short_len) || \
+ put_user(short_len, &d1->d_reclen)) \
+ goto efault; \
+ } \
+ return 0; \
+efault: \
+ buf->result = -EFAULT; \
+ return -EFAULT; \
+}
+
+FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, dirent)
+
+static int fat_ioctl_readdir(struct inode *inode, struct file *filp,
+ void __user *dirent, filldir_t filldir,
+ int short_only, int both)
{
- struct fat_ioctl_filldir_callback *buf = __buf;
- struct dirent __user *d1 = buf->dirent;
- struct dirent __user *d2 = d1 + 1;
-
- if (buf->result)
- return -EINVAL;
- buf->result++;
-
- if (name != NULL) {
- /* dirent has only short name */
- if (name_len >= sizeof(d1->d_name))
- name_len = sizeof(d1->d_name) - 1;
-
- if (put_user(0, d2->d_name) ||
- put_user(0, &d2->d_reclen) ||
- copy_to_user(d1->d_name, name, name_len) ||
- put_user(0, d1->d_name + name_len) ||
- put_user(name_len, &d1->d_reclen))
- goto efault;
- } else {
- /* dirent has short and long name */
- const char *longname = buf->longname;
- int long_len = buf->long_len;
- const char *shortname = buf->shortname;
- int short_len = buf->short_len;
-
- if (long_len >= sizeof(d1->d_name))
- long_len = sizeof(d1->d_name) - 1;
- if (short_len >= sizeof(d1->d_name))
- short_len = sizeof(d1->d_name) - 1;
-
- if (copy_to_user(d2->d_name, longname, long_len) ||
- put_user(0, d2->d_name + long_len) ||
- put_user(long_len, &d2->d_reclen) ||
- put_user(ino, &d2->d_ino) ||
- put_user(offset, &d2->d_off) ||
- copy_to_user(d1->d_name, shortname, short_len) ||
- put_user(0, d1->d_name + short_len) ||
- put_user(short_len, &d1->d_reclen))
- goto efault;
+ struct fat_ioctl_filldir_callback buf;
+ int ret;
+
+ buf.dirent = dirent;
+ buf.result = 0;
+ mutex_lock(&inode->i_mutex);
+ ret = -ENOENT;
+ if (!IS_DEADDIR(inode)) {
+ ret = __fat_readdir(inode, filp, &buf, filldir,
+ short_only, both);
}
- return 0;
-efault:
- buf->result = -EFAULT;
- return -EFAULT;
+ mutex_unlock(&inode->i_mutex);
+ if (ret >= 0)
+ ret = buf.result;
+ return ret;
}
-static int fat_dir_ioctl(struct inode * inode, struct file * filp,
- unsigned int cmd, unsigned long arg)
+static int fat_dir_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
- struct fat_ioctl_filldir_callback buf;
- struct dirent __user *d1;
- int ret, short_only, both;
+ struct dirent __user *d1 = (struct dirent __user *)arg;
+ int short_only, both;
switch (cmd) {
case VFAT_IOCTL_READDIR_SHORT:
@@ -717,7 +740,6 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
return fat_generic_ioctl(inode, filp, cmd, arg);
}
- d1 = (struct dirent __user *)arg;
if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2])))
return -EFAULT;
/*
@@ -728,69 +750,48 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
if (put_user(0, &d1->d_reclen))
return -EFAULT;
- buf.dirent = d1;
- buf.result = 0;
- mutex_lock(&inode->i_mutex);
- ret = -ENOENT;
- if (!IS_DEADDIR(inode)) {
- ret = __fat_readdir(inode, filp, &buf, fat_ioctl_filldir,
- short_only, both);
- }
- mutex_unlock(&inode->i_mutex);
- if (ret >= 0)
- ret = buf.result;
- return ret;
+ return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir,
+ short_only, both);
}
#ifdef CONFIG_COMPAT
#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
-static long fat_compat_put_dirent32(struct dirent *d,
- struct compat_dirent __user *d32)
-{
- if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
- return -EFAULT;
-
- __put_user(d->d_ino, &d32->d_ino);
- __put_user(d->d_off, &d32->d_off);
- __put_user(d->d_reclen, &d32->d_reclen);
- if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
- return -EFAULT;
+FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent)
- return 0;
-}
-
-static long fat_compat_dir_ioctl(struct file *file, unsigned cmd,
+static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd,
unsigned long arg)
{
- struct compat_dirent __user *p = compat_ptr(arg);
- int ret;
- mm_segment_t oldfs = get_fs();
- struct dirent d[2];
+ struct inode *inode = filp->f_path.dentry->d_inode;
+ struct compat_dirent __user *d1 = compat_ptr(arg);
+ int short_only, both;
switch (cmd) {
- case VFAT_IOCTL_READDIR_BOTH32:
- cmd = VFAT_IOCTL_READDIR_BOTH;
- break;
case VFAT_IOCTL_READDIR_SHORT32:
- cmd = VFAT_IOCTL_READDIR_SHORT;
+ short_only = 1;
+ both = 0;
+ break;
+ case VFAT_IOCTL_READDIR_BOTH32:
+ short_only = 0;
+ both = 1;
break;
default:
return -ENOIOCTLCMD;
}
- set_fs(KERNEL_DS);
- lock_kernel();
- ret = fat_dir_ioctl(file->f_path.dentry->d_inode, file,
- cmd, (unsigned long) &d);
- unlock_kernel();
- set_fs(oldfs);
- if (ret >= 0) {
- ret |= fat_compat_put_dirent32(&d[0], p);
- ret |= fat_compat_put_dirent32(&d[1], p + 1);
- }
- return ret;
+ if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2])))
+ return -EFAULT;
+ /*
+ * Yes, we don't need this put_user() absolutely. However old
+ * code didn't return the right value. So, app use this value,
+ * in order to check whether it is EOF.
+ */
+ if (put_user(0, &d1->d_reclen))
+ return -EFAULT;
+
+ return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir,
+ short_only, both);
}
#endif /* CONFIG_COMPAT */
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 9bfe607c892..2c55e8dce79 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -25,6 +25,7 @@
#include <linux/parser.h>
#include <linux/uio.h>
#include <linux/writeback.h>
+#include <linux/log2.h>
#include <asm/unaligned.h>
#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
@@ -499,8 +500,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
spin_lock_init(&ei->cache_lru_lock);
ei->nr_caches = 0;
ei->cache_valid_id = FAT_CACHE_VALID + 1;
@@ -825,6 +825,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
}
if (opts->name_check != 'n')
seq_printf(m, ",check=%c", opts->name_check);
+ if (opts->usefree)
+ seq_puts(m, ",usefree");
if (opts->quiet)
seq_puts(m, ",quiet");
if (opts->showexec)
@@ -850,7 +852,7 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
enum {
Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
- Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase,
+ Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase,
Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
Opt_dots, Opt_nodots,
Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
@@ -872,6 +874,7 @@ static match_table_t fat_tokens = {
{Opt_dmask, "dmask=%o"},
{Opt_fmask, "fmask=%o"},
{Opt_codepage, "codepage=%u"},
+ {Opt_usefree, "usefree"},
{Opt_nocase, "nocase"},
{Opt_quiet, "quiet"},
{Opt_showexec, "showexec"},
@@ -951,7 +954,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0;
opts->utf8 = opts->unicode_xlate = 0;
opts->numtail = 1;
- opts->nocase = 0;
+ opts->usefree = opts->nocase = 0;
*debug = 0;
if (!options)
@@ -979,6 +982,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
case Opt_check_n:
opts->name_check = 'n';
break;
+ case Opt_usefree:
+ opts->usefree = 1;
+ break;
case Opt_nocase:
if (!is_vfat)
opts->nocase = 1;
@@ -1218,8 +1224,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
}
logical_sector_size =
le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
- if (!logical_sector_size
- || (logical_sector_size & (logical_sector_size - 1))
+ if (!is_power_of_2(logical_sector_size)
|| (logical_sector_size < 512)
|| (PAGE_CACHE_SIZE < logical_sector_size)) {
if (!silent)
@@ -1229,8 +1234,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
goto out_invalid;
}
sbi->sec_per_clus = b->sec_per_clus;
- if (!sbi->sec_per_clus
- || (sbi->sec_per_clus & (sbi->sec_per_clus - 1))) {
+ if (!is_power_of_2(sbi->sec_per_clus)) {
if (!silent)
printk(KERN_ERR "FAT: bogus sectors per cluster %u\n",
sbi->sec_per_clus);
@@ -1306,7 +1310,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
le32_to_cpu(fsinfo->signature2),
sbi->fsinfo_sector);
} else {
- sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
+ if (sbi->options.usefree)
+ sbi->free_clusters =
+ le32_to_cpu(fsinfo->free_clusters);
sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
}
diff --git a/fs/fifo.c b/fs/fifo.c
index 49035b174b4..6e7df725678 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -11,7 +11,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/pipe_fs_i.h>
diff --git a/fs/file_table.c b/fs/file_table.c
index 4c17a18d8c1..d17fd691b83 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -10,7 +10,6 @@
#include <linux/file.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/eventpoll.h>
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 7a4f61aa05f..f37f8726283 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -41,11 +41,12 @@ void put_filesystem(struct file_system_type *fs)
module_put(fs->owner);
}
-static struct file_system_type **find_filesystem(const char *name)
+static struct file_system_type **find_filesystem(const char *name, unsigned len)
{
struct file_system_type **p;
for (p=&file_systems; *p; p=&(*p)->next)
- if (strcmp((*p)->name,name) == 0)
+ if (strlen((*p)->name) == len &&
+ strncmp((*p)->name, name, len) == 0)
break;
return p;
}
@@ -68,11 +69,12 @@ int register_filesystem(struct file_system_type * fs)
int res = 0;
struct file_system_type ** p;
+ BUG_ON(strchr(fs->name, '.'));
if (fs->next)
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);
write_lock(&file_systems_lock);
- p = find_filesystem(fs->name);
+ p = find_filesystem(fs->name, strlen(fs->name));
if (*p)
res = -EBUSY;
else
@@ -215,19 +217,26 @@ int get_filesystem_list(char * buf)
struct file_system_type *get_fs_type(const char *name)
{
struct file_system_type *fs;
+ const char *dot = strchr(name, '.');
+ unsigned len = dot ? dot - name : strlen(name);
read_lock(&file_systems_lock);
- fs = *(find_filesystem(name));
+ fs = *(find_filesystem(name, len));
if (fs && !try_module_get(fs->owner))
fs = NULL;
read_unlock(&file_systems_lock);
- if (!fs && (request_module("%s", name) == 0)) {
+ if (!fs && (request_module("%.*s", len, name) == 0)) {
read_lock(&file_systems_lock);
- fs = *(find_filesystem(name));
+ fs = *(find_filesystem(name, len));
if (fs && !try_module_get(fs->owner))
fs = NULL;
read_unlock(&file_systems_lock);
}
+
+ if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) {
+ put_filesystem(fs);
+ fs = NULL;
+ }
return fs;
}
diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c
index 2d71128bd8d..f86fd3cacd5 100644
--- a/fs/freevxfs/vxfs_bmap.c
+++ b/fs/freevxfs/vxfs_bmap.c
@@ -137,7 +137,7 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
bp = sb_bread(ip->i_sb,
indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
- if (!buffer_mapped(bp))
+ if (!bp || !buffer_mapped(bp))
return 0;
typ = ((struct vxfs_typed *)bp->b_data) +
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 098a915fd9a..d1f7c5b5b3c 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -99,7 +99,7 @@ vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
bp = sb_bread(sbp, block);
- if (buffer_mapped(bp)) {
+ if (bp && buffer_mapped(bp)) {
struct vxfs_inode_info *vip;
struct vxfs_dinode *dip;
diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c
index decac62efe5..ed8f0b0dd88 100644
--- a/fs/freevxfs/vxfs_subr.c
+++ b/fs/freevxfs/vxfs_subr.c
@@ -74,10 +74,7 @@ vxfs_get_page(struct address_space *mapping, u_long n)
pp = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(pp)) {
- wait_on_page_locked(pp);
kmap(pp);
- if (!PageUptodate(pp))
- goto fail;
/** if (!PageChecked(pp)) **/
/** vxfs_check_page(pp); **/
if (PageError(pp))
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 2fd06927e85..acfad65a6e8 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -738,8 +738,7 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
if (cmd == F_GETLK) {
if (fc->no_lock) {
- if (!posix_test_lock(file, fl, fl))
- fl->fl_type = F_UNLCK;
+ posix_test_lock(file, fl);
err = 0;
} else
err = fuse_getlk(file, fl);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 608db81219a..1397018ff47 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -636,6 +636,7 @@ static int fuse_get_sb(struct file_system_type *fs_type,
static struct file_system_type fuse_fs_type = {
.owner = THIS_MODULE,
.name = "fuse",
+ .fs_flags = FS_HAS_SUBTYPE,
.get_sb = fuse_get_sb,
.kill_sb = kill_anon_super,
};
@@ -652,6 +653,7 @@ static int fuse_get_sb_blk(struct file_system_type *fs_type,
static struct file_system_type fuseblk_fs_type = {
.owner = THIS_MODULE,
.name = "fuseblk",
+ .fs_flags = FS_HAS_SUBTYPE,
.get_sb = fuse_get_sb_blk,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
@@ -685,8 +687,7 @@ static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep,
{
struct inode * inode = foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(inode);
}
@@ -731,12 +732,12 @@ static int fuse_sysfs_init(void)
{
int err;
- kset_set_kset_s(&fuse_subsys, fs_subsys);
+ kobj_set_kset_s(&fuse_subsys, fs_subsys);
err = subsystem_register(&fuse_subsys);
if (err)
goto out_err;
- kset_set_kset_s(&connections_subsys, fuse_subsys);
+ kobj_set_kset_s(&connections_subsys, fuse_subsys);
err = subsystem_register(&connections_subsys);
if (err)
goto out_fuse_unregister;
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 82a1ac7895a..a96fa07b3f3 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1262,9 +1262,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
u64 leaf_no)
{
struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
struct buffer_head *bh;
struct gfs2_leaf *lf;
- unsigned entries = 0;
+ unsigned entries = 0, entries2 = 0;
unsigned leaves = 0;
const struct gfs2_dirent **darr, *dent;
struct dirent_gather g;
@@ -1290,7 +1291,13 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
return 0;
error = -ENOMEM;
- larr = vmalloc((leaves + entries) * sizeof(void *));
+ /*
+ * The extra 99 entries are not normally used, but are a buffer
+ * zone in case the number of entries in the leaf is corrupt.
+ * 99 is the maximum number of entries that can fit in a single
+ * leaf block.
+ */
+ larr = vmalloc((leaves + entries + 99) * sizeof(void *));
if (!larr)
goto out;
darr = (const struct gfs2_dirent **)(larr + leaves);
@@ -1305,10 +1312,20 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
lf = (struct gfs2_leaf *)bh->b_data;
lfn = be64_to_cpu(lf->lf_next);
if (lf->lf_entries) {
+ entries2 += be16_to_cpu(lf->lf_entries);
dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
gfs2_dirent_gather, NULL, &g);
error = PTR_ERR(dent);
- if (IS_ERR(dent)) {
+ if (IS_ERR(dent))
+ goto out_kfree;
+ if (entries2 != g.offset) {
+ fs_warn(sdp, "Number of entries corrupt in dir "
+ "leaf %llu, entries2 (%u) != "
+ "g.offset (%u)\n",
+ (unsigned long long)bh->b_blocknr,
+ entries2, g.offset);
+
+ error = -EIO;
goto out_kfree;
}
error = 0;
@@ -1318,6 +1335,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
}
} while(lfn);
+ BUG_ON(entries2 != entries);
error = do_filldir_main(ip, offset, opaque, filldir, darr,
entries, copied);
out_kfree:
@@ -1401,6 +1419,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
filldir_t filldir)
{
struct gfs2_inode *dip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
struct dirent_gather g;
const struct gfs2_dirent **darr, *dent;
struct buffer_head *dibh;
@@ -1423,8 +1442,8 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
return error;
error = -ENOMEM;
- darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
- GFP_KERNEL);
+ /* 96 is max number of dirents which can be stuffed into an inode */
+ darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL);
if (darr) {
g.pdent = darr;
g.offset = 0;
@@ -1434,6 +1453,15 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
error = PTR_ERR(dent);
goto out;
}
+ if (dip->i_di.di_entries != g.offset) {
+ fs_warn(sdp, "Number of entries corrupt in dir %llu, "
+ "ip->i_di.di_entries (%u) != g.offset (%u)\n",
+ (unsigned long long)dip->i_num.no_addr,
+ dip->i_di.di_entries,
+ g.offset);
+ error = -EIO;
+ goto out;
+ }
error = do_filldir_main(dip, offset, opaque, filldir, darr,
dip->i_di.di_entries, &copied);
out:
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 12accb08fe0..1815429a297 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -23,6 +23,10 @@
#include <linux/module.h>
#include <linux/rwsem.h>
#include <asm/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
#include "gfs2.h"
#include "incore.h"
@@ -40,20 +44,30 @@ struct gfs2_gl_hash_bucket {
struct hlist_head hb_list;
};
+struct glock_iter {
+ int hash; /* hash bucket index */
+ struct gfs2_sbd *sdp; /* incore superblock */
+ struct gfs2_glock *gl; /* current glock struct */
+ struct hlist_head *hb_list; /* current hash bucket ptr */
+ struct seq_file *seq; /* sequence file for debugfs */
+ char string[512]; /* scratch space */
+};
+
typedef void (*glock_examiner) (struct gfs2_glock * gl);
static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
-static int dump_glock(struct gfs2_glock *gl);
-static int dump_inode(struct gfs2_inode *ip);
-static void gfs2_glock_xmote_th(struct gfs2_holder *gh);
+static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
+static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
static void gfs2_glock_drop_th(struct gfs2_glock *gl);
static DECLARE_RWSEM(gfs2_umount_flush_sem);
+static struct dentry *gfs2_root;
#define GFS2_GL_HASH_SHIFT 15
#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1)
static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE];
+static struct dentry *gfs2_root;
/*
* Despite what you might think, the numbers below are not arbitrary :-)
@@ -202,7 +216,6 @@ int gfs2_glock_put(struct gfs2_glock *gl)
gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
gfs2_assert(sdp, list_empty(&gl->gl_holders));
gfs2_assert(sdp, list_empty(&gl->gl_waiters1));
- gfs2_assert(sdp, list_empty(&gl->gl_waiters2));
gfs2_assert(sdp, list_empty(&gl->gl_waiters3));
glock_free(gl);
rv = 1;
@@ -303,7 +316,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
atomic_set(&gl->gl_ref, 1);
gl->gl_state = LM_ST_UNLOCKED;
gl->gl_hash = hash;
- gl->gl_owner = NULL;
+ gl->gl_owner_pid = 0;
gl->gl_ip = 0;
gl->gl_ops = glops;
gl->gl_req_gh = NULL;
@@ -367,7 +380,7 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
INIT_LIST_HEAD(&gh->gh_list);
gh->gh_gl = gl;
gh->gh_ip = (unsigned long)__builtin_return_address(0);
- gh->gh_owner = current;
+ gh->gh_owner_pid = current->pid;
gh->gh_state = state;
gh->gh_flags = flags;
gh->gh_error = 0;
@@ -389,7 +402,7 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
{
gh->gh_state = state;
gh->gh_flags = flags;
- gh->gh_iflags &= 1 << HIF_ALLOCED;
+ gh->gh_iflags = 0;
gh->gh_ip = (unsigned long)__builtin_return_address(0);
}
@@ -406,54 +419,8 @@ void gfs2_holder_uninit(struct gfs2_holder *gh)
gh->gh_ip = 0;
}
-/**
- * gfs2_holder_get - get a struct gfs2_holder structure
- * @gl: the glock
- * @state: the state we're requesting
- * @flags: the modifier flags
- * @gfp_flags:
- *
- * Figure out how big an impact this function has. Either:
- * 1) Replace it with a cache of structures hanging off the struct gfs2_sbd
- * 2) Leave it like it is
- *
- * Returns: the holder structure, NULL on ENOMEM
- */
-
-static struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl,
- unsigned int state,
- int flags, gfp_t gfp_flags)
-{
- struct gfs2_holder *gh;
-
- gh = kmalloc(sizeof(struct gfs2_holder), gfp_flags);
- if (!gh)
- return NULL;
-
- gfs2_holder_init(gl, state, flags, gh);
- set_bit(HIF_ALLOCED, &gh->gh_iflags);
- gh->gh_ip = (unsigned long)__builtin_return_address(0);
- return gh;
-}
-
-/**
- * gfs2_holder_put - get rid of a struct gfs2_holder structure
- * @gh: the holder structure
- *
- */
-
-static void gfs2_holder_put(struct gfs2_holder *gh)
+static void gfs2_holder_wake(struct gfs2_holder *gh)
{
- gfs2_holder_uninit(gh);
- kfree(gh);
-}
-
-static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
-{
- if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
- gfs2_holder_put(gh);
- return;
- }
clear_bit(HIF_WAIT, &gh->gh_iflags);
smp_mb();
wake_up_bit(&gh->gh_iflags, HIF_WAIT);
@@ -519,7 +486,7 @@ static int rq_promote(struct gfs2_holder *gh)
gfs2_reclaim_glock(sdp);
}
- gfs2_glock_xmote_th(gh);
+ gfs2_glock_xmote_th(gh->gh_gl, gh);
spin_lock(&gl->gl_spin);
}
return 1;
@@ -542,7 +509,7 @@ static int rq_promote(struct gfs2_holder *gh)
gh->gh_error = 0;
set_bit(HIF_HOLDER, &gh->gh_iflags);
- gfs2_holder_dispose_or_wake(gh);
+ gfs2_holder_wake(gh);
return 0;
}
@@ -554,32 +521,24 @@ static int rq_promote(struct gfs2_holder *gh)
* Returns: 1 if the queue is blocked
*/
-static int rq_demote(struct gfs2_holder *gh)
+static int rq_demote(struct gfs2_glock *gl)
{
- struct gfs2_glock *gl = gh->gh_gl;
-
if (!list_empty(&gl->gl_holders))
return 1;
- if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) {
- list_del_init(&gh->gh_list);
- gh->gh_error = 0;
- spin_unlock(&gl->gl_spin);
- gfs2_holder_dispose_or_wake(gh);
- spin_lock(&gl->gl_spin);
- } else {
- gl->gl_req_gh = gh;
- set_bit(GLF_LOCK, &gl->gl_flags);
- spin_unlock(&gl->gl_spin);
-
- if (gh->gh_state == LM_ST_UNLOCKED ||
- gl->gl_state != LM_ST_EXCLUSIVE)
- gfs2_glock_drop_th(gl);
- else
- gfs2_glock_xmote_th(gh);
-
- spin_lock(&gl->gl_spin);
+ if (gl->gl_state == gl->gl_demote_state ||
+ gl->gl_state == LM_ST_UNLOCKED) {
+ clear_bit(GLF_DEMOTE, &gl->gl_flags);
+ return 0;
}
+ set_bit(GLF_LOCK, &gl->gl_flags);
+ spin_unlock(&gl->gl_spin);
+ if (gl->gl_demote_state == LM_ST_UNLOCKED ||
+ gl->gl_state != LM_ST_EXCLUSIVE)
+ gfs2_glock_drop_th(gl);
+ else
+ gfs2_glock_xmote_th(gl, NULL);
+ spin_lock(&gl->gl_spin);
return 0;
}
@@ -607,16 +566,8 @@ static void run_queue(struct gfs2_glock *gl)
else
gfs2_assert_warn(gl->gl_sbd, 0);
- } else if (!list_empty(&gl->gl_waiters2) &&
- !test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) {
- gh = list_entry(gl->gl_waiters2.next,
- struct gfs2_holder, gh_list);
-
- if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
- blocked = rq_demote(gh);
- else
- gfs2_assert_warn(gl->gl_sbd, 0);
-
+ } else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+ blocked = rq_demote(gl);
} else if (!list_empty(&gl->gl_waiters3)) {
gh = list_entry(gl->gl_waiters3.next,
struct gfs2_holder, gh_list);
@@ -654,7 +605,7 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
list_add_tail(&gh.gh_list, &gl->gl_waiters1);
} else {
- gl->gl_owner = current;
+ gl->gl_owner_pid = current->pid;
gl->gl_ip = (unsigned long)__builtin_return_address(0);
clear_bit(HIF_WAIT, &gh.gh_iflags);
smp_mb();
@@ -681,7 +632,7 @@ static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
acquired = 0;
} else {
- gl->gl_owner = current;
+ gl->gl_owner_pid = current->pid;
gl->gl_ip = (unsigned long)__builtin_return_address(0);
}
spin_unlock(&gl->gl_spin);
@@ -699,7 +650,7 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
{
spin_lock(&gl->gl_spin);
clear_bit(GLF_LOCK, &gl->gl_flags);
- gl->gl_owner = NULL;
+ gl->gl_owner_pid = 0;
gl->gl_ip = 0;
run_queue(gl);
BUG_ON(!spin_is_locked(&gl->gl_spin));
@@ -707,50 +658,24 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
}
/**
- * handle_callback - add a demote request to a lock's queue
+ * handle_callback - process a demote request
* @gl: the glock
* @state: the state the caller wants us to change to
*
- * Note: This may fail sliently if we are out of memory.
+ * There are only two requests that we are going to see in actual
+ * practise: LM_ST_SHARED and LM_ST_UNLOCKED
*/
static void handle_callback(struct gfs2_glock *gl, unsigned int state)
{
- struct gfs2_holder *gh, *new_gh = NULL;
-
-restart:
spin_lock(&gl->gl_spin);
-
- list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
- if (test_bit(HIF_DEMOTE, &gh->gh_iflags) &&
- gl->gl_req_gh != gh) {
- if (gh->gh_state != state)
- gh->gh_state = LM_ST_UNLOCKED;
- goto out;
- }
- }
-
- if (new_gh) {
- list_add_tail(&new_gh->gh_list, &gl->gl_waiters2);
- new_gh = NULL;
- } else {
- spin_unlock(&gl->gl_spin);
-
- new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_NOFS);
- if (!new_gh)
- return;
- set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
- set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
- set_bit(HIF_WAIT, &new_gh->gh_iflags);
-
- goto restart;
+ if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
+ gl->gl_demote_state = state;
+ gl->gl_demote_time = jiffies;
+ } else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
+ gl->gl_demote_state = state;
}
-
-out:
spin_unlock(&gl->gl_spin);
-
- if (new_gh)
- gfs2_holder_put(new_gh);
}
/**
@@ -810,56 +735,37 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
/* Deal with each possible exit condition */
- if (!gh)
+ if (!gh) {
gl->gl_stamp = jiffies;
- else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+ if (ret & LM_OUT_CANCELED)
+ op_done = 0;
+ else
+ clear_bit(GLF_DEMOTE, &gl->gl_flags);
+ } else {
spin_lock(&gl->gl_spin);
list_del_init(&gh->gh_list);
gh->gh_error = -EIO;
- spin_unlock(&gl->gl_spin);
- } else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) {
- spin_lock(&gl->gl_spin);
- list_del_init(&gh->gh_list);
- if (gl->gl_state == gh->gh_state ||
- gl->gl_state == LM_ST_UNLOCKED) {
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ goto out;
+ gh->gh_error = GLR_CANCELED;
+ if (ret & LM_OUT_CANCELED)
+ goto out;
+ if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+ list_add_tail(&gh->gh_list, &gl->gl_holders);
gh->gh_error = 0;
- } else {
- if (gfs2_assert_warn(sdp, gh->gh_flags &
- (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1)
- fs_warn(sdp, "ret = 0x%.8X\n", ret);
- gh->gh_error = GLR_TRYFAILED;
+ set_bit(HIF_HOLDER, &gh->gh_iflags);
+ set_bit(HIF_FIRST, &gh->gh_iflags);
+ op_done = 0;
+ goto out;
}
- spin_unlock(&gl->gl_spin);
-
- if (ret & LM_OUT_CANCELED)
- handle_callback(gl, LM_ST_UNLOCKED);
-
- } else if (ret & LM_OUT_CANCELED) {
- spin_lock(&gl->gl_spin);
- list_del_init(&gh->gh_list);
- gh->gh_error = GLR_CANCELED;
- spin_unlock(&gl->gl_spin);
-
- } else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
- spin_lock(&gl->gl_spin);
- list_move_tail(&gh->gh_list, &gl->gl_holders);
- gh->gh_error = 0;
- set_bit(HIF_HOLDER, &gh->gh_iflags);
- spin_unlock(&gl->gl_spin);
-
- set_bit(HIF_FIRST, &gh->gh_iflags);
-
- op_done = 0;
-
- } else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
- spin_lock(&gl->gl_spin);
- list_del_init(&gh->gh_list);
gh->gh_error = GLR_TRYFAILED;
- spin_unlock(&gl->gl_spin);
-
- } else {
+ if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))
+ goto out;
+ gh->gh_error = -EINVAL;
if (gfs2_assert_withdraw(sdp, 0) == -1)
fs_err(sdp, "ret = 0x%.8X\n", ret);
+out:
+ spin_unlock(&gl->gl_spin);
}
if (glops->go_xmote_bh)
@@ -877,7 +783,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl);
if (gh)
- gfs2_holder_dispose_or_wake(gh);
+ gfs2_holder_wake(gh);
}
/**
@@ -888,12 +794,11 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
*
*/
-void gfs2_glock_xmote_th(struct gfs2_holder *gh)
+void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
{
- struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_sbd *sdp = gl->gl_sbd;
- int flags = gh->gh_flags;
- unsigned state = gh->gh_state;
+ int flags = gh ? gh->gh_flags : 0;
+ unsigned state = gh ? gh->gh_state : gl->gl_demote_state;
const struct gfs2_glock_operations *glops = gl->gl_ops;
int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
LM_FLAG_NOEXP | LM_FLAG_ANY |
@@ -943,6 +848,7 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_assert_warn(sdp, !ret);
state_change(gl, LM_ST_UNLOCKED);
+ clear_bit(GLF_DEMOTE, &gl->gl_flags);
if (glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
@@ -964,7 +870,7 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
gfs2_glock_put(gl);
if (gh)
- gfs2_holder_dispose_or_wake(gh);
+ gfs2_holder_wake(gh);
}
/**
@@ -1097,18 +1003,32 @@ static int glock_wait_internal(struct gfs2_holder *gh)
}
static inline struct gfs2_holder *
-find_holder_by_owner(struct list_head *head, struct task_struct *owner)
+find_holder_by_owner(struct list_head *head, pid_t pid)
{
struct gfs2_holder *gh;
list_for_each_entry(gh, head, gh_list) {
- if (gh->gh_owner == owner)
+ if (gh->gh_owner_pid == pid)
return gh;
}
return NULL;
}
+static void print_dbg(struct glock_iter *gi, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (gi) {
+ vsprintf(gi->string, fmt, args);
+ seq_printf(gi->seq, gi->string);
+ }
+ else
+ vprintk(fmt, args);
+ va_end(args);
+}
+
/**
* add_to_queue - Add a holder to the wait queue (but look for recursion)
* @gh: the holder structure to add
@@ -1120,24 +1040,24 @@ static void add_to_queue(struct gfs2_holder *gh)
struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_holder *existing;
- BUG_ON(!gh->gh_owner);
+ BUG_ON(!gh->gh_owner_pid);
if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
BUG();
- existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
+ existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
if (existing) {
print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
- printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid);
+ printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
printk(KERN_INFO "lock type : %d lock state : %d\n",
existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
- printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid);
+ printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
printk(KERN_INFO "lock type : %d lock state : %d\n",
gl->gl_name.ln_type, gl->gl_state);
BUG();
}
- existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner);
+ existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
if (existing) {
print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
@@ -1267,9 +1187,8 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
if (glops->go_unlock)
glops->go_unlock(gh);
- gl->gl_stamp = jiffies;
-
spin_lock(&gl->gl_spin);
+ gl->gl_stamp = jiffies;
}
clear_bit(GLF_LOCK, &gl->gl_flags);
@@ -1841,6 +1760,15 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
* Diagnostic routines to help debug distributed deadlock
*/
+static void gfs2_print_symbol(struct glock_iter *gi, const char *fmt,
+ unsigned long address)
+{
+ char buffer[KSYM_SYMBOL_LEN];
+
+ sprint_symbol(buffer, address);
+ print_dbg(gi, fmt, buffer);
+}
+
/**
* dump_holder - print information about a glock holder
* @str: a string naming the type of holder
@@ -1849,31 +1777,37 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
* Returns: 0 on success, -ENOBUFS when we run out of space
*/
-static int dump_holder(char *str, struct gfs2_holder *gh)
+static int dump_holder(struct glock_iter *gi, char *str,
+ struct gfs2_holder *gh)
{
unsigned int x;
- int error = -ENOBUFS;
-
- printk(KERN_INFO " %s\n", str);
- printk(KERN_INFO " owner = %ld\n",
- (gh->gh_owner) ? (long)gh->gh_owner->pid : -1);
- printk(KERN_INFO " gh_state = %u\n", gh->gh_state);
- printk(KERN_INFO " gh_flags =");
+ struct task_struct *gh_owner;
+
+ print_dbg(gi, " %s\n", str);
+ if (gh->gh_owner_pid) {
+ print_dbg(gi, " owner = %ld ", (long)gh->gh_owner_pid);
+ gh_owner = find_task_by_pid(gh->gh_owner_pid);
+ if (gh_owner)
+ print_dbg(gi, "(%s)\n", gh_owner->comm);
+ else
+ print_dbg(gi, "(ended)\n");
+ } else
+ print_dbg(gi, " owner = -1\n");
+ print_dbg(gi, " gh_state = %u\n", gh->gh_state);
+ print_dbg(gi, " gh_flags =");
for (x = 0; x < 32; x++)
if (gh->gh_flags & (1 << x))
- printk(" %u", x);
- printk(" \n");
- printk(KERN_INFO " error = %d\n", gh->gh_error);
- printk(KERN_INFO " gh_iflags =");
+ print_dbg(gi, " %u", x);
+ print_dbg(gi, " \n");
+ print_dbg(gi, " error = %d\n", gh->gh_error);
+ print_dbg(gi, " gh_iflags =");
for (x = 0; x < 32; x++)
if (test_bit(x, &gh->gh_iflags))
- printk(" %u", x);
- printk(" \n");
- print_symbol(KERN_INFO " initialized at: %s\n", gh->gh_ip);
-
- error = 0;
+ print_dbg(gi, " %u", x);
+ print_dbg(gi, " \n");
+ gfs2_print_symbol(gi, " initialized at: %s\n", gh->gh_ip);
- return error;
+ return 0;
}
/**
@@ -1883,25 +1817,20 @@ static int dump_holder(char *str, struct gfs2_holder *gh)
* Returns: 0 on success, -ENOBUFS when we run out of space
*/
-static int dump_inode(struct gfs2_inode *ip)
+static int dump_inode(struct glock_iter *gi, struct gfs2_inode *ip)
{
unsigned int x;
- int error = -ENOBUFS;
- printk(KERN_INFO " Inode:\n");
- printk(KERN_INFO " num = %llu %llu\n",
- (unsigned long long)ip->i_num.no_formal_ino,
- (unsigned long long)ip->i_num.no_addr);
- printk(KERN_INFO " type = %u\n", IF2DT(ip->i_inode.i_mode));
- printk(KERN_INFO " i_flags =");
+ print_dbg(gi, " Inode:\n");
+ print_dbg(gi, " num = %llu/%llu\n",
+ ip->i_num.no_formal_ino, ip->i_num.no_addr);
+ print_dbg(gi, " type = %u\n", IF2DT(ip->i_inode.i_mode));
+ print_dbg(gi, " i_flags =");
for (x = 0; x < 32; x++)
if (test_bit(x, &ip->i_flags))
- printk(" %u", x);
- printk(" \n");
-
- error = 0;
-
- return error;
+ print_dbg(gi, " %u", x);
+ print_dbg(gi, " \n");
+ return 0;
}
/**
@@ -1912,74 +1841,86 @@ static int dump_inode(struct gfs2_inode *ip)
* Returns: 0 on success, -ENOBUFS when we run out of space
*/
-static int dump_glock(struct gfs2_glock *gl)
+static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
{
struct gfs2_holder *gh;
unsigned int x;
int error = -ENOBUFS;
+ struct task_struct *gl_owner;
spin_lock(&gl->gl_spin);
- printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
- (unsigned long long)gl->gl_name.ln_number);
- printk(KERN_INFO " gl_flags =");
+ print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+ (unsigned long long)gl->gl_name.ln_number);
+ print_dbg(gi, " gl_flags =");
for (x = 0; x < 32; x++) {
if (test_bit(x, &gl->gl_flags))
- printk(" %u", x);
+ print_dbg(gi, " %u", x);
}
- printk(" \n");
- printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref));
- printk(KERN_INFO " gl_state = %u\n", gl->gl_state);
- printk(KERN_INFO " gl_owner = %s\n", gl->gl_owner->comm);
- print_symbol(KERN_INFO " gl_ip = %s\n", gl->gl_ip);
- printk(KERN_INFO " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
- printk(KERN_INFO " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
- printk(KERN_INFO " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
- printk(KERN_INFO " object = %s\n", (gl->gl_object) ? "yes" : "no");
- printk(KERN_INFO " le = %s\n",
+ if (!test_bit(GLF_LOCK, &gl->gl_flags))
+ print_dbg(gi, " (unlocked)");
+ print_dbg(gi, " \n");
+ print_dbg(gi, " gl_ref = %d\n", atomic_read(&gl->gl_ref));
+ print_dbg(gi, " gl_state = %u\n", gl->gl_state);
+ if (gl->gl_owner_pid) {
+ gl_owner = find_task_by_pid(gl->gl_owner_pid);
+ if (gl_owner)
+ print_dbg(gi, " gl_owner = pid %d (%s)\n",
+ gl->gl_owner_pid, gl_owner->comm);
+ else
+ print_dbg(gi, " gl_owner = %d (ended)\n",
+ gl->gl_owner_pid);
+ } else
+ print_dbg(gi, " gl_owner = -1\n");
+ print_dbg(gi, " gl_ip = %lu\n", gl->gl_ip);
+ print_dbg(gi, " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
+ print_dbg(gi, " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
+ print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
+ print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no");
+ print_dbg(gi, " le = %s\n",
(list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
- printk(KERN_INFO " reclaim = %s\n",
- (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
+ print_dbg(gi, " reclaim = %s\n",
+ (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
if (gl->gl_aspace)
- printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
- gl->gl_aspace->i_mapping->nrpages);
+ print_dbg(gi, " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
+ gl->gl_aspace->i_mapping->nrpages);
else
- printk(KERN_INFO " aspace = no\n");
- printk(KERN_INFO " ail = %d\n", atomic_read(&gl->gl_ail_count));
+ print_dbg(gi, " aspace = no\n");
+ print_dbg(gi, " ail = %d\n", atomic_read(&gl->gl_ail_count));
if (gl->gl_req_gh) {
- error = dump_holder("Request", gl->gl_req_gh);
+ error = dump_holder(gi, "Request", gl->gl_req_gh);
if (error)
goto out;
}
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
- error = dump_holder("Holder", gh);
+ error = dump_holder(gi, "Holder", gh);
if (error)
goto out;
}
list_for_each_entry(gh, &gl->gl_waiters1, gh_list) {
- error = dump_holder("Waiter1", gh);
- if (error)
- goto out;
- }
- list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
- error = dump_holder("Waiter2", gh);
+ error = dump_holder(gi, "Waiter1", gh);
if (error)
goto out;
}
list_for_each_entry(gh, &gl->gl_waiters3, gh_list) {
- error = dump_holder("Waiter3", gh);
+ error = dump_holder(gi, "Waiter3", gh);
if (error)
goto out;
}
+ if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
+ print_dbg(gi, " Demotion req to state %u (%llu uS ago)\n",
+ gl->gl_demote_state,
+ (u64)(jiffies - gl->gl_demote_time)*(1000000/HZ));
+ }
if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) {
if (!test_bit(GLF_LOCK, &gl->gl_flags) &&
- list_empty(&gl->gl_holders)) {
- error = dump_inode(gl->gl_object);
+ list_empty(&gl->gl_holders)) {
+ error = dump_inode(gi, gl->gl_object);
if (error)
goto out;
} else {
error = -ENOBUFS;
- printk(KERN_INFO " Inode: busy\n");
+ print_dbg(gi, " Inode: busy\n");
}
}
@@ -2014,7 +1955,7 @@ static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
if (gl->gl_sbd != sdp)
continue;
- error = dump_glock(gl);
+ error = dump_glock(NULL, gl);
if (error)
break;
}
@@ -2043,3 +1984,189 @@ int __init gfs2_glock_init(void)
return 0;
}
+static int gfs2_glock_iter_next(struct glock_iter *gi)
+{
+ read_lock(gl_lock_addr(gi->hash));
+ while (1) {
+ if (!gi->hb_list) { /* If we don't have a hash bucket yet */
+ gi->hb_list = &gl_hash_table[gi->hash].hb_list;
+ if (hlist_empty(gi->hb_list)) {
+ read_unlock(gl_lock_addr(gi->hash));
+ gi->hash++;
+ read_lock(gl_lock_addr(gi->hash));
+ gi->hb_list = NULL;
+ if (gi->hash >= GFS2_GL_HASH_SIZE) {
+ read_unlock(gl_lock_addr(gi->hash));
+ return 1;
+ }
+ else
+ continue;
+ }
+ if (!hlist_empty(gi->hb_list)) {
+ gi->gl = list_entry(gi->hb_list->first,
+ struct gfs2_glock,
+ gl_list);
+ }
+ } else {
+ if (gi->gl->gl_list.next == NULL) {
+ read_unlock(gl_lock_addr(gi->hash));
+ gi->hash++;
+ read_lock(gl_lock_addr(gi->hash));
+ gi->hb_list = NULL;
+ continue;
+ }
+ gi->gl = list_entry(gi->gl->gl_list.next,
+ struct gfs2_glock, gl_list);
+ }
+ if (gi->gl)
+ break;
+ }
+ read_unlock(gl_lock_addr(gi->hash));
+ return 0;
+}
+
+static void gfs2_glock_iter_free(struct glock_iter *gi)
+{
+ kfree(gi);
+}
+
+static struct glock_iter *gfs2_glock_iter_init(struct gfs2_sbd *sdp)
+{
+ struct glock_iter *gi;
+
+ gi = kmalloc(sizeof (*gi), GFP_KERNEL);
+ if (!gi)
+ return NULL;
+
+ gi->sdp = sdp;
+ gi->hash = 0;
+ gi->gl = NULL;
+ gi->hb_list = NULL;
+ gi->seq = NULL;
+ memset(gi->string, 0, sizeof(gi->string));
+
+ if (gfs2_glock_iter_next(gi)) {
+ gfs2_glock_iter_free(gi);
+ return NULL;
+ }
+
+ return gi;
+}
+
+static void *gfs2_glock_seq_start(struct seq_file *file, loff_t *pos)
+{
+ struct glock_iter *gi;
+ loff_t n = *pos;
+
+ gi = gfs2_glock_iter_init(file->private);
+ if (!gi)
+ return NULL;
+
+ while (n--) {
+ if (gfs2_glock_iter_next(gi)) {
+ gfs2_glock_iter_free(gi);
+ return NULL;
+ }
+ }
+
+ return gi;
+}
+
+static void *gfs2_glock_seq_next(struct seq_file *file, void *iter_ptr,
+ loff_t *pos)
+{
+ struct glock_iter *gi = iter_ptr;
+
+ (*pos)++;
+
+ if (gfs2_glock_iter_next(gi)) {
+ gfs2_glock_iter_free(gi);
+ return NULL;
+ }
+
+ return gi;
+}
+
+static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
+{
+ /* nothing for now */
+}
+
+static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
+{
+ struct glock_iter *gi = iter_ptr;
+
+ gi->seq = file;
+ dump_glock(gi, gi->gl);
+
+ return 0;
+}
+
+static struct seq_operations gfs2_glock_seq_ops = {
+ .start = gfs2_glock_seq_start,
+ .next = gfs2_glock_seq_next,
+ .stop = gfs2_glock_seq_stop,
+ .show = gfs2_glock_seq_show,
+};
+
+static int gfs2_debugfs_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int ret;
+
+ ret = seq_open(file, &gfs2_glock_seq_ops);
+ if (ret)
+ return ret;
+
+ seq = file->private_data;
+ seq->private = inode->i_private;
+
+ return 0;
+}
+
+static const struct file_operations gfs2_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = gfs2_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
+{
+ sdp->debugfs_dir = debugfs_create_dir(sdp->sd_table_name, gfs2_root);
+ if (!sdp->debugfs_dir)
+ return -ENOMEM;
+ sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
+ S_IFREG | S_IRUGO,
+ sdp->debugfs_dir, sdp,
+ &gfs2_debug_fops);
+ if (!sdp->debugfs_dentry_glocks)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
+{
+ if (sdp && sdp->debugfs_dir) {
+ if (sdp->debugfs_dentry_glocks) {
+ debugfs_remove(sdp->debugfs_dentry_glocks);
+ sdp->debugfs_dentry_glocks = NULL;
+ }
+ debugfs_remove(sdp->debugfs_dir);
+ sdp->debugfs_dir = NULL;
+ }
+}
+
+int gfs2_register_debugfs(void)
+{
+ gfs2_root = debugfs_create_dir("gfs2", NULL);
+ return gfs2_root ? 0 : -ENOMEM;
+}
+
+void gfs2_unregister_debugfs(void)
+{
+ debugfs_remove(gfs2_root);
+ gfs2_root = NULL;
+}
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index f50e40ceca4..11477ca3a3c 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -38,7 +38,7 @@ static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
/* Look in glock's list of holders for one with current task as owner */
spin_lock(&gl->gl_spin);
list_for_each_entry(gh, &gl->gl_holders, gh_list) {
- if (gh->gh_owner == current) {
+ if (gh->gh_owner_pid == current->pid) {
locked = 1;
break;
}
@@ -67,7 +67,7 @@ static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
{
int ret;
spin_lock(&gl->gl_spin);
- ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
+ ret = test_bit(GLF_DEMOTE, &gl->gl_flags) || !list_empty(&gl->gl_waiters3);
spin_unlock(&gl->gl_spin);
return ret;
}
@@ -135,5 +135,9 @@ void gfs2_scand_internal(struct gfs2_sbd *sdp);
void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
int __init gfs2_glock_init(void);
+int gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
+void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
+int gfs2_register_debugfs(void);
+void gfs2_unregister_debugfs(void);
#endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 39c8ae23bd9..7b82657a991 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -163,10 +163,7 @@ static void inode_go_sync(struct gfs2_glock *gl)
if (ip) {
struct address_space *mapping = ip->i_inode.i_mapping;
int error = filemap_fdatawait(mapping);
- if (error == -ENOSPC)
- set_bit(AS_ENOSPC, &mapping->flags);
- else if (error)
- set_bit(AS_EIO, &mapping->flags);
+ mapping_set_error(mapping, error);
}
clear_bit(GLF_DIRTY, &gl->gl_flags);
gfs2_ail_empty_gl(gl);
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 49f0dbf40d8..d995441373a 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -115,11 +115,8 @@ enum {
/* Actions */
HIF_MUTEX = 0,
HIF_PROMOTE = 1,
- HIF_DEMOTE = 2,
/* States */
- HIF_ALLOCED = 4,
- HIF_DEALLOC = 5,
HIF_HOLDER = 6,
HIF_FIRST = 7,
HIF_ABORTED = 9,
@@ -130,7 +127,7 @@ struct gfs2_holder {
struct list_head gh_list;
struct gfs2_glock *gh_gl;
- struct task_struct *gh_owner;
+ pid_t gh_owner_pid;
unsigned int gh_state;
unsigned gh_flags;
@@ -142,8 +139,8 @@ struct gfs2_holder {
enum {
GLF_LOCK = 1,
GLF_STICKY = 2,
+ GLF_DEMOTE = 3,
GLF_DIRTY = 5,
- GLF_SKIP_WAITERS2 = 6,
};
struct gfs2_glock {
@@ -156,11 +153,12 @@ struct gfs2_glock {
unsigned int gl_state;
unsigned int gl_hash;
- struct task_struct *gl_owner;
+ unsigned int gl_demote_state; /* state requested by remote node */
+ unsigned long gl_demote_time; /* time of first demote request */
+ pid_t gl_owner_pid;
unsigned long gl_ip;
struct list_head gl_holders;
struct list_head gl_waiters1; /* HIF_MUTEX */
- struct list_head gl_waiters2; /* HIF_DEMOTE */
struct list_head gl_waiters3; /* HIF_PROMOTE */
const struct gfs2_glock_operations *gl_ops;
@@ -611,6 +609,8 @@ struct gfs2_sbd {
unsigned long sd_last_warning;
struct vfsmount *sd_gfs2mnt;
+ struct dentry *debugfs_dir; /* debugfs directory */
+ struct dentry *debugfs_dentry_glocks; /* for debugfs */
};
#endif /* __INCORE_DOT_H__ */
diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
index b167addf9fd..c305255bfe8 100644
--- a/fs/gfs2/locking/dlm/lock.c
+++ b/fs/gfs2/locking/dlm/lock.c
@@ -151,7 +151,7 @@ static inline unsigned int make_flags(struct gdlm_lock *lp,
/* make_strname - convert GFS lock numbers to a string */
-static inline void make_strname(struct lm_lockname *lockname,
+static inline void make_strname(const struct lm_lockname *lockname,
struct gdlm_strname *str)
{
sprintf(str->name, "%8x%16llx", lockname->ln_type,
@@ -169,6 +169,7 @@ static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
return -ENOMEM;
lp->lockname = *name;
+ make_strname(name, &lp->strname);
lp->ls = ls;
lp->cur = DLM_LOCK_IV;
lp->lvb = NULL;
@@ -227,7 +228,6 @@ void gdlm_put_lock(void *lock)
unsigned int gdlm_do_lock(struct gdlm_lock *lp)
{
struct gdlm_ls *ls = lp->ls;
- struct gdlm_strname str;
int error, bast = 1;
/*
@@ -249,8 +249,6 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
if (test_bit(LFL_NOBAST, &lp->flags))
bast = 0;
- make_strname(&lp->lockname, &str);
-
set_bit(LFL_ACTIVE, &lp->flags);
log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
@@ -258,8 +256,8 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
lp->cur, lp->req, lp->lkf);
error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
- str.name, str.namelen, 0, gdlm_ast, lp,
- bast ? gdlm_bast : NULL);
+ lp->strname.name, lp->strname.namelen, 0, gdlm_ast,
+ lp, bast ? gdlm_bast : NULL);
if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
lp->lksb.sb_status = -EAGAIN;
@@ -268,7 +266,7 @@ unsigned int gdlm_do_lock(struct gdlm_lock *lp)
}
if (error) {
- log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
+ log_error("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
"flags=%lx", ls->fsname, lp->lockname.ln_type,
(unsigned long long)lp->lockname.ln_number, error,
lp->cur, lp->req, lp->lkf, lp->flags);
@@ -296,7 +294,7 @@ static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
if (error) {
- log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
+ log_error("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
"flags=%lx", ls->fsname, lp->lockname.ln_type,
(unsigned long long)lp->lockname.ln_number, error,
lp->cur, lp->req, lp->lkf, lp->flags);
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index a87c7bf3c56..d074c6e6f9b 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -36,7 +36,7 @@
#define GDLM_STRNAME_BYTES 24
#define GDLM_LVB_SIZE 32
-#define GDLM_DROP_COUNT 200000
+#define GDLM_DROP_COUNT 0
#define GDLM_DROP_PERIOD 60
#define GDLM_NAME_LEN 128
@@ -106,6 +106,7 @@ enum {
struct gdlm_lock {
struct gdlm_ls *ls;
struct lm_lockname lockname;
+ struct gdlm_strname strname;
char *lvb;
struct dlm_lksb lksb;
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index 1dd4215b83d..f82495e18c2 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -25,6 +25,15 @@ struct plock_op {
struct gdlm_plock_info info;
};
+struct plock_xop {
+ struct plock_op xop;
+ void *callback;
+ void *fl;
+ void *file;
+ struct file_lock flc;
+};
+
+
static inline void set_version(struct gdlm_plock_info *info)
{
info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
@@ -64,12 +73,14 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
{
struct gdlm_ls *ls = lockspace;
struct plock_op *op;
+ struct plock_xop *xop;
int rv;
- op = kzalloc(sizeof(*op), GFP_KERNEL);
- if (!op)
+ xop = kzalloc(sizeof(*xop), GFP_KERNEL);
+ if (!xop)
return -ENOMEM;
+ op = &xop->xop;
op->info.optype = GDLM_PLOCK_OP_LOCK;
op->info.pid = fl->fl_pid;
op->info.ex = (fl->fl_type == F_WRLCK);
@@ -79,9 +90,21 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
op->info.start = fl->fl_start;
op->info.end = fl->fl_end;
op->info.owner = (__u64)(long) fl->fl_owner;
+ if (fl->fl_lmops && fl->fl_lmops->fl_grant) {
+ xop->callback = fl->fl_lmops->fl_grant;
+ locks_init_lock(&xop->flc);
+ locks_copy_lock(&xop->flc, fl);
+ xop->fl = fl;
+ xop->file = file;
+ } else
+ xop->callback = NULL;
send_op(op);
- wait_event(recv_wq, (op->done != 0));
+
+ if (xop->callback == NULL)
+ wait_event(recv_wq, (op->done != 0));
+ else
+ return -EINPROGRESS;
spin_lock(&ops_lock);
if (!list_empty(&op->list)) {
@@ -99,7 +122,63 @@ int gdlm_plock(void *lockspace, struct lm_lockname *name,
(unsigned long long)name->ln_number);
}
- kfree(op);
+ kfree(xop);
+ return rv;
+}
+
+/* Returns failure iff a succesful lock operation should be canceled */
+static int gdlm_plock_callback(struct plock_op *op)
+{
+ struct file *file;
+ struct file_lock *fl;
+ struct file_lock *flc;
+ int (*notify)(void *, void *, int) = NULL;
+ struct plock_xop *xop = (struct plock_xop *)op;
+ int rv = 0;
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&op->list)) {
+ printk(KERN_INFO "plock op on list\n");
+ list_del(&op->list);
+ }
+ spin_unlock(&ops_lock);
+
+ /* check if the following 2 are still valid or make a copy */
+ file = xop->file;
+ flc = &xop->flc;
+ fl = xop->fl;
+ notify = xop->callback;
+
+ if (op->info.rv) {
+ notify(flc, NULL, op->info.rv);
+ goto out;
+ }
+
+ /* got fs lock; bookkeep locally as well: */
+ flc->fl_flags &= ~FL_SLEEP;
+ if (posix_lock_file(file, flc, NULL)) {
+ /*
+ * This can only happen in the case of kmalloc() failure.
+ * The filesystem's own lock is the authoritative lock,
+ * so a failure to get the lock locally is not a disaster.
+ * As long as GFS cannot reliably cancel locks (especially
+ * in a low-memory situation), we're better off ignoring
+ * this failure than trying to recover.
+ */
+ log_error("gdlm_plock: vfs lock error file %p fl %p",
+ file, fl);
+ }
+
+ rv = notify(flc, NULL, 0);
+ if (rv) {
+ /* XXX: We need to cancel the fs lock here: */
+ printk("gfs2 lock granted after lock request failed;"
+ " dangling lock!\n");
+ goto out;
+ }
+
+out:
+ kfree(xop);
return rv;
}
@@ -138,6 +217,9 @@ int gdlm_punlock(void *lockspace, struct lm_lockname *name,
rv = op->info.rv;
+ if (rv == -ENOENT)
+ rv = 0;
+
kfree(op);
return rv;
}
@@ -161,6 +243,7 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
op->info.start = fl->fl_start;
op->info.end = fl->fl_end;
+
send_op(op);
wait_event(recv_wq, (op->done != 0));
@@ -173,9 +256,10 @@ int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
rv = op->info.rv;
- if (rv == 0)
- fl->fl_type = F_UNLCK;
- else if (rv > 0) {
+ fl->fl_type = F_UNLCK;
+ if (rv == -ENOENT)
+ rv = 0;
+ else if (rv == 0 && op->info.pid != fl->fl_pid) {
fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
fl->fl_pid = op->info.pid;
fl->fl_start = op->info.start;
@@ -243,9 +327,14 @@ static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
}
spin_unlock(&ops_lock);
- if (found)
- wake_up(&recv_wq);
- else
+ if (found) {
+ struct plock_xop *xop;
+ xop = (struct plock_xop *)op;
+ if (xop->callback)
+ count = gdlm_plock_callback(op);
+ else
+ wake_up(&recv_wq);
+ } else
printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
(unsigned long long)info.number);
return count;
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index 4746b884662..d9fe3ca40e1 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -190,7 +190,6 @@ static struct kobj_type gdlm_ktype = {
};
static struct kset gdlm_kset = {
- .subsys = &kernel_subsys,
.kobj = {.name = "lock_dlm",},
.ktype = &gdlm_ktype,
};
@@ -225,6 +224,7 @@ int gdlm_sysfs_init(void)
{
int error;
+ kobj_set_kset_s(&gdlm_kset, kernel_subsys);
error = kset_register(&gdlm_kset);
if (error)
printk("lock_dlm: cannot register kset %d\n", error);
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
index acfbc941f31..0d149c8c493 100644
--- a/fs/gfs2/locking/nolock/main.c
+++ b/fs/gfs2/locking/nolock/main.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/fs.h>
-#include <linux/smp_lock.h>
#include <linux/lm_interface.h>
struct nolock_lockspace {
@@ -164,13 +163,7 @@ static void nolock_unhold_lvb(void *lock, char *lvb)
static int nolock_plock_get(void *lockspace, struct lm_lockname *name,
struct file *file, struct file_lock *fl)
{
- struct file_lock tmp;
- int ret;
-
- ret = posix_test_lock(file, fl, &tmp);
- fl->fl_type = F_UNLCK;
- if (ret)
- memcpy(fl, &tmp, sizeof(struct file_lock));
+ posix_test_lock(file, fl);
return 0;
}
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 16bb4b4561a..f82d84d05d2 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -33,16 +33,17 @@ static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
tr->tr_touched = 1;
- if (!list_empty(&le->le_list))
- return;
-
gl = container_of(le, struct gfs2_glock, gl_le);
if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
return;
- gfs2_glock_hold(gl);
- set_bit(GLF_DIRTY, &gl->gl_flags);
gfs2_log_lock(sdp);
+ if (!list_empty(&le->le_list)){
+ gfs2_log_unlock(sdp);
+ return;
+ }
+ gfs2_glock_hold(gl);
+ set_bit(GLF_DIRTY, &gl->gl_flags);
sdp->sd_log_num_gl++;
list_add(&le->le_list, &sdp->sd_log_le_gl);
gfs2_log_unlock(sdp);
@@ -415,13 +416,14 @@ static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
tr->tr_touched = 1;
- if (!list_empty(&le->le_list))
- return;
-
rgd = container_of(le, struct gfs2_rgrpd, rd_le);
- gfs2_rgrp_bh_hold(rgd);
gfs2_log_lock(sdp);
+ if (!list_empty(&le->le_list)){
+ gfs2_log_unlock(sdp);
+ return;
+ }
+ gfs2_rgrp_bh_hold(rgd);
sdp->sd_log_num_rg++;
list_add(&le->le_list, &sdp->sd_log_le_rg);
gfs2_log_unlock(sdp);
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 6e8a59809ab..e460487c055 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -27,8 +27,7 @@
static void gfs2_init_inode_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct gfs2_inode *ip = foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&ip->i_inode);
spin_lock_init(&ip->i_spin);
init_rwsem(&ip->i_rw_mutex);
@@ -39,13 +38,11 @@ static void gfs2_init_inode_once(void *foo, struct kmem_cache *cachep, unsigned
static void gfs2_init_glock_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct gfs2_glock *gl = foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
INIT_HLIST_NODE(&gl->gl_list);
spin_lock_init(&gl->gl_spin);
INIT_LIST_HEAD(&gl->gl_holders);
INIT_LIST_HEAD(&gl->gl_waiters1);
- INIT_LIST_HEAD(&gl->gl_waiters2);
INIT_LIST_HEAD(&gl->gl_waiters3);
gl->gl_lvb = NULL;
atomic_set(&gl->gl_lvb_count, 0);
@@ -103,6 +100,8 @@ static int __init init_gfs2_fs(void)
if (error)
goto fail_unregister;
+ gfs2_register_debugfs();
+
printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
return 0;
@@ -130,6 +129,7 @@ fail:
static void __exit exit_gfs2_fs(void)
{
+ gfs2_unregister_debugfs();
unregister_filesystem(&gfs2_fs_type);
unregister_filesystem(&gfs2meta_fs_type);
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index 32caecd2030..4864659555d 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -13,6 +13,7 @@
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>
+#include <linux/parser.h>
#include "gfs2.h"
#include "incore.h"
@@ -20,6 +21,52 @@
#include "sys.h"
#include "util.h"
+enum {
+ Opt_lockproto,
+ Opt_locktable,
+ Opt_hostdata,
+ Opt_spectator,
+ Opt_ignore_local_fs,
+ Opt_localflocks,
+ Opt_localcaching,
+ Opt_debug,
+ Opt_nodebug,
+ Opt_upgrade,
+ Opt_num_glockd,
+ Opt_acl,
+ Opt_noacl,
+ Opt_quota_off,
+ Opt_quota_account,
+ Opt_quota_on,
+ Opt_suiddir,
+ Opt_nosuiddir,
+ Opt_data_writeback,
+ Opt_data_ordered,
+};
+
+static match_table_t tokens = {
+ {Opt_lockproto, "lockproto=%s"},
+ {Opt_locktable, "locktable=%s"},
+ {Opt_hostdata, "hostdata=%s"},
+ {Opt_spectator, "spectator"},
+ {Opt_ignore_local_fs, "ignore_local_fs"},
+ {Opt_localflocks, "localflocks"},
+ {Opt_localcaching, "localcaching"},
+ {Opt_debug, "debug"},
+ {Opt_nodebug, "nodebug"},
+ {Opt_upgrade, "upgrade"},
+ {Opt_num_glockd, "num_glockd=%d"},
+ {Opt_acl, "acl"},
+ {Opt_noacl, "noacl"},
+ {Opt_quota_off, "quota=off"},
+ {Opt_quota_account, "quota=account"},
+ {Opt_quota_on, "quota=on"},
+ {Opt_suiddir, "suiddir"},
+ {Opt_nosuiddir, "nosuiddir"},
+ {Opt_data_writeback, "data=writeback"},
+ {Opt_data_ordered, "data=ordered"}
+};
+
/**
* gfs2_mount_args - Parse mount options
* @sdp:
@@ -54,146 +101,150 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
process them */
for (options = data; (o = strsep(&options, ",")); ) {
+ int token, option;
+ substring_t tmp[MAX_OPT_ARGS];
+
if (!*o)
continue;
- v = strchr(o, '=');
- if (v)
- *v++ = 0;
+ token = match_token(o, tokens, tmp);
+ switch (token) {
+ case Opt_lockproto:
+ v = match_strdup(&tmp[0]);
+ if (!v) {
+ fs_info(sdp, "no memory for lockproto\n");
+ error = -ENOMEM;
+ goto out_error;
+ }
- if (!strcmp(o, "lockproto")) {
- if (!v)
- goto need_value;
- if (remount && strcmp(v, args->ar_lockproto))
+ if (remount && strcmp(v, args->ar_lockproto)) {
+ kfree(v);
goto cant_remount;
+ }
+
strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
- }
+ kfree(v);
+ break;
+ case Opt_locktable:
+ v = match_strdup(&tmp[0]);
+ if (!v) {
+ fs_info(sdp, "no memory for locktable\n");
+ error = -ENOMEM;
+ goto out_error;
+ }
- else if (!strcmp(o, "locktable")) {
- if (!v)
- goto need_value;
- if (remount && strcmp(v, args->ar_locktable))
+ if (remount && strcmp(v, args->ar_locktable)) {
+ kfree(v);
goto cant_remount;
+ }
+
strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
- args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
- }
+ args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
+ kfree(v);
+ break;
+ case Opt_hostdata:
+ v = match_strdup(&tmp[0]);
+ if (!v) {
+ fs_info(sdp, "no memory for hostdata\n");
+ error = -ENOMEM;
+ goto out_error;
+ }
- else if (!strcmp(o, "hostdata")) {
- if (!v)
- goto need_value;
- if (remount && strcmp(v, args->ar_hostdata))
+ if (remount && strcmp(v, args->ar_hostdata)) {
+ kfree(v);
goto cant_remount;
+ }
+
strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
- }
-
- else if (!strcmp(o, "spectator")) {
+ kfree(v);
+ break;
+ case Opt_spectator:
if (remount && !args->ar_spectator)
goto cant_remount;
args->ar_spectator = 1;
sdp->sd_vfs->s_flags |= MS_RDONLY;
- }
-
- else if (!strcmp(o, "ignore_local_fs")) {
+ break;
+ case Opt_ignore_local_fs:
if (remount && !args->ar_ignore_local_fs)
goto cant_remount;
args->ar_ignore_local_fs = 1;
- }
-
- else if (!strcmp(o, "localflocks")) {
+ break;
+ case Opt_localflocks:
if (remount && !args->ar_localflocks)
goto cant_remount;
args->ar_localflocks = 1;
- }
-
- else if (!strcmp(o, "localcaching")) {
+ break;
+ case Opt_localcaching:
if (remount && !args->ar_localcaching)
goto cant_remount;
args->ar_localcaching = 1;
- }
-
- else if (!strcmp(o, "debug"))
+ break;
+ case Opt_debug:
args->ar_debug = 1;
-
- else if (!strcmp(o, "nodebug"))
+ break;
+ case Opt_nodebug:
args->ar_debug = 0;
-
- else if (!strcmp(o, "upgrade")) {
+ break;
+ case Opt_upgrade:
if (remount && !args->ar_upgrade)
goto cant_remount;
args->ar_upgrade = 1;
- }
+ break;
+ case Opt_num_glockd:
+ if ((error = match_int(&tmp[0], &option))) {
+ fs_info(sdp, "problem getting num_glockd\n");
+ goto out_error;
+ }
- else if (!strcmp(o, "num_glockd")) {
- unsigned int x;
- if (!v)
- goto need_value;
- sscanf(v, "%u", &x);
- if (remount && x != args->ar_num_glockd)
+ if (remount && option != args->ar_num_glockd)
goto cant_remount;
- if (!x || x > GFS2_GLOCKD_MAX) {
+ if (!option || option > GFS2_GLOCKD_MAX) {
fs_info(sdp, "0 < num_glockd <= %u (not %u)\n",
- GFS2_GLOCKD_MAX, x);
+ GFS2_GLOCKD_MAX, option);
error = -EINVAL;
- break;
+ goto out_error;
}
- args->ar_num_glockd = x;
- }
-
- else if (!strcmp(o, "acl")) {
+ args->ar_num_glockd = option;
+ break;
+ case Opt_acl:
args->ar_posix_acl = 1;
sdp->sd_vfs->s_flags |= MS_POSIXACL;
- }
-
- else if (!strcmp(o, "noacl")) {
+ break;
+ case Opt_noacl:
args->ar_posix_acl = 0;
sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
- }
-
- else if (!strcmp(o, "quota")) {
- if (!v)
- goto need_value;
- if (!strcmp(v, "off"))
- args->ar_quota = GFS2_QUOTA_OFF;
- else if (!strcmp(v, "account"))
- args->ar_quota = GFS2_QUOTA_ACCOUNT;
- else if (!strcmp(v, "on"))
- args->ar_quota = GFS2_QUOTA_ON;
- else {
- fs_info(sdp, "invalid value for quota\n");
- error = -EINVAL;
- break;
- }
- }
-
- else if (!strcmp(o, "suiddir"))
+ break;
+ case Opt_quota_off:
+ args->ar_quota = GFS2_QUOTA_OFF;
+ break;
+ case Opt_quota_account:
+ args->ar_quota = GFS2_QUOTA_ACCOUNT;
+ break;
+ case Opt_quota_on:
+ args->ar_quota = GFS2_QUOTA_ON;
+ break;
+ case Opt_suiddir:
args->ar_suiddir = 1;
-
- else if (!strcmp(o, "nosuiddir"))
+ break;
+ case Opt_nosuiddir:
args->ar_suiddir = 0;
-
- else if (!strcmp(o, "data")) {
- if (!v)
- goto need_value;
- if (!strcmp(v, "writeback"))
- args->ar_data = GFS2_DATA_WRITEBACK;
- else if (!strcmp(v, "ordered"))
- args->ar_data = GFS2_DATA_ORDERED;
- else {
- fs_info(sdp, "invalid value for data\n");
- error = -EINVAL;
- break;
- }
- }
-
- else {
+ break;
+ case Opt_data_writeback:
+ args->ar_data = GFS2_DATA_WRITEBACK;
+ break;
+ case Opt_data_ordered:
+ args->ar_data = GFS2_DATA_ORDERED;
+ break;
+ default:
fs_info(sdp, "unknown option: %s\n", o);
error = -EINVAL;
- break;
+ goto out_error;
}
}
+out_error:
if (error)
fs_info(sdp, "invalid mount option(s)\n");
@@ -202,10 +253,6 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
return error;
-need_value:
- fs_info(sdp, "need value for option %s\n", o);
- return -EINVAL;
-
cant_remount:
fs_info(sdp, "can't remount with option %s\n", o);
return -EINVAL;
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index b3b7e847535..30c15622174 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -197,7 +197,19 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
void *kaddr;
int error;
- BUG_ON(page->index);
+ /*
+ * Due to the order of unstuffing files and ->nopage(), we can be
+ * asked for a zero page in the case of a stuffed file being extended,
+ * so we need to supply one here. It doesn't happen often.
+ */
+ if (unlikely(page->index)) {
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr, 0, PAGE_CACHE_SIZE);
+ kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ return 0;
+ }
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
@@ -208,9 +220,8 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
ip->i_di.di_size);
memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
kunmap_atomic(kaddr, KM_USER0);
-
+ flush_dcache_page(page);
brelse(dibh);
-
SetPageUptodate(page);
return 0;
@@ -507,7 +518,9 @@ static int gfs2_commit_write(struct file *file, struct page *page,
gfs2_quota_unlock(ip);
gfs2_alloc_put(ip);
}
+ unlock_page(page);
gfs2_glock_dq_m(1, &ip->i_gh);
+ lock_page(page);
gfs2_holder_uninit(&ip->i_gh);
return 0;
@@ -520,7 +533,9 @@ fail_endtrans:
gfs2_quota_unlock(ip);
gfs2_alloc_put(ip);
}
+ unlock_page(page);
gfs2_glock_dq_m(1, &ip->i_gh);
+ lock_page(page);
gfs2_holder_uninit(&ip->i_gh);
fail_nounlock:
ClearPageUptodate(page);
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
index c6bac6b6942..a6fdc52f554 100644
--- a/fs/gfs2/ops_dentry.c
+++ b/fs/gfs2/ops_dentry.c
@@ -11,7 +11,6 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
-#include <linux/smp_lock.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/lm_interface.h>
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index b50180e2277..064df880458 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -15,7 +15,6 @@
#include <linux/uio.h>
#include <linux/blkdev.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/gfs2_ondisk.h>
#include <linux/ext2_fs.h>
@@ -513,18 +512,18 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
if (sdp->sd_args.ar_localflocks) {
if (IS_GETLK(cmd)) {
- struct file_lock tmp;
- int ret;
- ret = posix_test_lock(file, fl, &tmp);
- fl->fl_type = F_UNLCK;
- if (ret)
- memcpy(fl, &tmp, sizeof(struct file_lock));
+ posix_test_lock(file, fl);
return 0;
} else {
return posix_lock_file_wait(file, fl);
}
}
+ if (cmd == F_CANCELLK) {
+ /* Hack: */
+ cmd = F_SETLK;
+ fl->fl_type = F_UNLCK;
+ }
if (IS_GETLK(cmd))
return gfs2_lm_plock_get(sdp, &name, file, fl);
else if (fl->fl_type == F_UNLCK)
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index ee54cb66708..2c5f8e7def0 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -690,6 +690,8 @@ static int fill_super(struct super_block *sb, void *data, int silent)
if (error)
goto fail;
+ gfs2_create_debugfs_file(sdp);
+
error = gfs2_sys_fs_add(sdp);
if (error)
goto fail;
@@ -754,6 +756,7 @@ fail_lm:
fail_sys:
gfs2_sys_fs_del(sdp);
fail:
+ gfs2_delete_debugfs_file(sdp);
kfree(sdp);
sb->s_fs_info = NULL;
return error;
@@ -896,6 +899,7 @@ error:
static void gfs2_kill_sb(struct super_block *sb)
{
+ gfs2_delete_debugfs_file(sb->s_fs_info);
kill_block_super(sb);
}
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index b89999d3a76..485ce3d4992 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -284,6 +284,31 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
}
/**
+ * gfs2_drop_inode - Drop an inode (test for remote unlink)
+ * @inode: The inode to drop
+ *
+ * If we've received a callback on an iopen lock then its because a
+ * remote node tried to deallocate the inode but failed due to this node
+ * still having the inode open. Here we mark the link count zero
+ * since we know that it must have reached zero if the GLF_DEMOTE flag
+ * is set on the iopen glock. If we didn't do a disk read since the
+ * remote node removed the final link then we might otherwise miss
+ * this event. This check ensures that this node will deallocate the
+ * inode's blocks, or alternatively pass the baton on to another
+ * node for later deallocation.
+ */
+static void gfs2_drop_inode(struct inode *inode)
+{
+ if (inode->i_private && inode->i_nlink) {
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_glock *gl = ip->i_iopen_gh.gh_gl;
+ if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags))
+ clear_nlink(inode);
+ }
+ generic_drop_inode(inode);
+}
+
+/**
* gfs2_clear_inode - Deallocate an inode when VFS is done with it
* @inode: The VFS inode
*
@@ -441,7 +466,7 @@ out_unlock:
out_uninit:
gfs2_holder_uninit(&ip->i_iopen_gh);
gfs2_glock_dq_uninit(&gh);
- if (error)
+ if (error && error != GLR_TRYFAILED)
fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
out:
truncate_inode_pages(&inode->i_data, 0);
@@ -481,6 +506,7 @@ const struct super_operations gfs2_super_ops = {
.statfs = gfs2_statfs,
.remount_fs = gfs2_remount_fs,
.clear_inode = gfs2_clear_inode,
+ .drop_inode = gfs2_drop_inode,
.show_options = gfs2_show_options,
};
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 8d9c08b5c4b..1727f5012ef 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -27,6 +27,7 @@
#include "trans.h"
#include "ops_file.h"
#include "util.h"
+#include "log.h"
#define BFITNOENT ((u32)~0)
@@ -697,8 +698,6 @@ struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
* @al: the struct gfs2_alloc structure describing the reservation
*
* If there's room for the requested blocks to be allocated from the RG:
- * Sets the $al_reserved_data field in @al.
- * Sets the $al_reserved_meta field in @al.
* Sets the $al_rgd field in @al.
*
* Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
@@ -709,6 +708,9 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
struct gfs2_sbd *sdp = rgd->rd_sbd;
int ret = 0;
+ if (rgd->rd_rg.rg_flags & GFS2_RGF_NOALLOC)
+ return 0;
+
spin_lock(&sdp->sd_rindex_spin);
if (rgd->rd_free_clone >= al->al_requested) {
al->al_rgd = rgd;
@@ -941,9 +943,13 @@ static int get_local_rgrp(struct gfs2_inode *ip)
rgd = gfs2_rgrpd_get_first(sdp);
if (rgd == begin) {
- if (++loops >= 2 || !skipped)
+ if (++loops >= 3)
return -ENOSPC;
+ if (!skipped)
+ loops++;
flags = 0;
+ if (loops == 2)
+ gfs2_log_flush(sdp, NULL);
}
}
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index d01f9f0fda2..c26c21b53c1 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -222,7 +222,6 @@ static struct kobj_type gfs2_ktype = {
};
static struct kset gfs2_kset = {
- .subsys = &fs_subsys,
.kobj = {.name = "gfs2"},
.ktype = &gfs2_ktype,
};
@@ -554,6 +553,7 @@ int gfs2_sys_init(void)
{
gfs2_sys_margs = NULL;
spin_lock_init(&gfs2_sys_margs_lock);
+ kobj_set_kset_s(&gfs2_kset, fs_subsys);
return kset_register(&gfs2_kset);
}
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 5fd0ed71f92..8a3a650abc8 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -9,6 +9,7 @@
*/
#include <linux/pagemap.h>
+#include <linux/log2.h>
#include "btree.h"
@@ -76,7 +77,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
tree->depth = be16_to_cpu(head->depth);
size = tree->node_size;
- if (!size || size & (size - 1))
+ if (!is_power_of_2(size))
goto fail_page;
if (!tree->node_count)
goto fail_page;
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 623f509f1d4..4f1888f16cf 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -434,7 +434,7 @@ static void hfs_init_once(void *p, struct kmem_cache *cachep, unsigned long flag
{
struct hfs_inode_info *i = p;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&i->vfs_inode);
}
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index a9b9e872e29..90ebab753d3 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -10,6 +10,7 @@
#include <linux/slab.h>
#include <linux/pagemap.h>
+#include <linux/log2.h>
#include "hfsplus_fs.h"
#include "hfsplus_raw.h"
@@ -69,7 +70,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
}
size = tree->node_size;
- if (!size || size & (size - 1))
+ if (!is_power_of_2(size))
goto fail_page;
if (!tree->node_count)
goto fail_page;
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index 1a97f929344..37afbec8a76 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -470,7 +470,7 @@ static void hfsplus_init_once(void *p, struct kmem_cache *cachep, unsigned long
{
struct hfsplus_inode_info *i = p;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&i->vfs_inode);
}
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
index 70543b17e4c..06e5930515f 100644
--- a/fs/hostfs/hostfs.h
+++ b/fs/hostfs/hostfs.h
@@ -55,7 +55,7 @@ extern int stat_file(const char *path, unsigned long long *inode_out,
int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
unsigned long long *size_out, struct timespec *atime_out,
struct timespec *mtime_out, struct timespec *ctime_out,
- int *blksize_out, unsigned long long *blocks_out);
+ int *blksize_out, unsigned long long *blocks_out, int fd);
extern int access_file(char *path, int r, int w, int x);
extern int open_file(char *path, int r, int w, int append);
extern int file_type(const char *path, int *maj, int *min);
@@ -71,7 +71,7 @@ extern int lseek_file(int fd, long long offset, int whence);
extern int fsync_file(int fd, int datasync);
extern int file_create(char *name, int ur, int uw, int ux, int gr,
int gw, int gx, int or, int ow, int ox);
-extern int set_attr(const char *file, struct hostfs_iattr *attrs);
+extern int set_attr(const char *file, struct hostfs_iattr *attrs, int fd);
extern int make_symlink(const char *from, const char *to);
extern int unlink_file(const char *file);
extern int do_mkdir(const char *file, int mode);
@@ -87,14 +87,3 @@ extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
long *spare_out);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index fd301a91012..8286491dbf3 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*
* Ported the filesystem routines to 2.5.
@@ -31,14 +31,14 @@ struct hostfs_inode_info {
static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
{
- return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
+ return list_entry(inode, struct hostfs_inode_info, vfs_inode);
}
#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode)
int hostfs_d_delete(struct dentry *dentry)
{
- return(1);
+ return 1;
}
struct dentry_operations hostfs_dentry_ops = {
@@ -79,7 +79,7 @@ static int __init hostfs_args(char *options, int *add)
}
options = ptr;
}
- return(0);
+ return 0;
}
__uml_setup("hostfs=", hostfs_args,
@@ -110,7 +110,8 @@ static char *dentry_name(struct dentry *dentry, int extra)
root = HOSTFS_I(parent->d_inode)->host_filename;
len += strlen(root);
name = kmalloc(len + extra + 1, GFP_KERNEL);
- if(name == NULL) return(NULL);
+ if(name == NULL)
+ return NULL;
name[len] = '\0';
parent = dentry;
@@ -122,7 +123,7 @@ static char *dentry_name(struct dentry *dentry, int extra)
parent = parent->d_parent;
}
strncpy(name, root, strlen(root));
- return(name);
+ return name;
}
static char *inode_name(struct inode *ino, int extra)
@@ -130,7 +131,7 @@ static char *inode_name(struct inode *ino, int extra)
struct dentry *dentry;
dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
- return(dentry_name(dentry, extra));
+ return dentry_name(dentry, extra);
}
static int read_name(struct inode *ino, char *name)
@@ -147,16 +148,16 @@ static int read_name(struct inode *ino, char *name)
err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid,
&ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime,
- &ino->i_ctime, &i_blksize, &i_blocks);
+ &ino->i_ctime, &i_blksize, &i_blocks, -1);
if(err)
- return(err);
+ return err;
ino->i_ino = i_ino;
ino->i_mode = i_mode;
ino->i_nlink = i_nlink;
ino->i_size = i_size;
ino->i_blocks = i_blocks;
- return(0);
+ return 0;
}
static char *follow_link(char *link)
@@ -181,11 +182,11 @@ static char *follow_link(char *link)
goto out_free;
if(*name == '/')
- return(name);
+ return name;
end = strrchr(link, '/');
if(end == NULL)
- return(name);
+ return name;
*(end + 1) = '\0';
len = strlen(link) + strlen(name) + 1;
@@ -199,12 +200,12 @@ static char *follow_link(char *link)
sprintf(resolved, "%s%s", link, name);
kfree(name);
kfree(link);
- return(resolved);
+ return resolved;
out_free:
kfree(name);
out:
- return(ERR_PTR(n));
+ return ERR_PTR(n);
}
static int read_inode(struct inode *ino)
@@ -234,7 +235,7 @@ static int read_inode(struct inode *ino)
err = read_name(ino, name);
kfree(name);
out:
- return(err);
+ return err;
}
int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
@@ -254,14 +255,15 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf)
&sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
&f_ffree, &sf->f_fsid, sizeof(sf->f_fsid),
&sf->f_namelen, sf->f_spare);
- if(err) return(err);
+ if(err)
+ return err;
sf->f_blocks = f_blocks;
sf->f_bfree = f_bfree;
sf->f_bavail = f_bavail;
sf->f_files = f_files;
sf->f_ffree = f_ffree;
sf->f_type = HOSTFS_SUPER_MAGIC;
- return(0);
+ return 0;
}
static struct inode *hostfs_alloc_inode(struct super_block *sb)
@@ -270,13 +272,13 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb)
hi = kmalloc(sizeof(*hi), GFP_KERNEL);
if(hi == NULL)
- return(NULL);
+ return NULL;
*hi = ((struct hostfs_inode_info) { .host_filename = NULL,
.fd = -1,
.mode = 0 });
inode_init_once(&hi->vfs_inode);
- return(&hi->vfs_inode);
+ return &hi->vfs_inode;
}
static void hostfs_delete_inode(struct inode *inode)
@@ -325,10 +327,12 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
int error, len;
name = dentry_name(file->f_path.dentry, 0);
- if(name == NULL) return(-ENOMEM);
+ if(name == NULL)
+ return -ENOMEM;
dir = open_dir(name, &error);
kfree(name);
- if(dir == NULL) return(-error);
+ if(dir == NULL)
+ return -error;
next = file->f_pos;
while((name = read_dir(dir, &next, &ino, &len)) != NULL){
error = (*filldir)(ent, name, len, file->f_pos,
@@ -337,7 +341,7 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
file->f_pos = next;
}
close_dir(dir);
- return(0);
+ return 0;
}
int hostfs_file_open(struct inode *ino, struct file *file)
@@ -347,7 +351,7 @@ int hostfs_file_open(struct inode *ino, struct file *file)
mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
if((mode & HOSTFS_I(ino)->mode) == mode)
- return(0);
+ return 0;
/* The file may already have been opened, but with the wrong access,
* so this resets things and reopens the file with the new access.
@@ -367,14 +371,15 @@ int hostfs_file_open(struct inode *ino, struct file *file)
name = dentry_name(file->f_path.dentry, 0);
if(name == NULL)
- return(-ENOMEM);
+ return -ENOMEM;
fd = open_file(name, r, w, append);
kfree(name);
- if(fd < 0) return(fd);
+ if(fd < 0)
+ return fd;
FILE_HOSTFS_I(file)->fd = fd;
- return(0);
+ return 0;
}
int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
@@ -458,7 +463,7 @@ int hostfs_readpage(struct file *file, struct page *page)
out:
kunmap(page);
unlock_page(page);
- return(err);
+ return err;
}
int hostfs_prepare_write(struct file *file, struct page *page,
@@ -485,7 +490,7 @@ int hostfs_prepare_write(struct file *file, struct page *page,
err = 0;
out:
kunmap(page);
- return(err);
+ return err;
}
int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
@@ -511,7 +516,7 @@ int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
inode->i_size = start;
kunmap(page);
- return(err);
+ return err;
}
static const struct address_space_operations hostfs_aops = {
@@ -569,7 +574,7 @@ static int init_inode(struct inode *inode, struct dentry *dentry)
break;
}
out:
- return(err);
+ return err;
}
int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
@@ -607,16 +612,16 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode,
HOSTFS_I(inode)->fd = fd;
HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
d_instantiate(dentry, inode);
- return(0);
+ return 0;
out_put:
iput(inode);
out:
- return(error);
+ return error;
}
struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
- struct nameidata *nd)
+ struct nameidata *nd)
{
struct inode *inode;
char *name;
@@ -647,44 +652,45 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
d_add(dentry, inode);
dentry->d_op = &hostfs_dentry_ops;
- return(NULL);
+ return NULL;
out_put:
iput(inode);
out:
- return(ERR_PTR(err));
+ return ERR_PTR(err);
}
static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
{
- char *file;
+ char *file;
int len;
file = inode_name(ino, dentry->d_name.len + 1);
- if(file == NULL) return(NULL);
- strcat(file, "/");
+ if(file == NULL)
+ return NULL;
+ strcat(file, "/");
len = strlen(file);
- strncat(file, dentry->d_name.name, dentry->d_name.len);
+ strncat(file, dentry->d_name.name, dentry->d_name.len);
file[len + dentry->d_name.len] = '\0';
- return(file);
+ return file;
}
int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
{
- char *from_name, *to_name;
- int err;
+ char *from_name, *to_name;
+ int err;
- if((from_name = inode_dentry_name(ino, from)) == NULL)
- return(-ENOMEM);
- to_name = dentry_name(to, 0);
+ if((from_name = inode_dentry_name(ino, from)) == NULL)
+ return -ENOMEM;
+ to_name = dentry_name(to, 0);
if(to_name == NULL){
kfree(from_name);
- return(-ENOMEM);
+ return -ENOMEM;
}
- err = link_file(to_name, from_name);
- kfree(from_name);
- kfree(to_name);
- return(err);
+ err = link_file(to_name, from_name);
+ kfree(from_name);
+ kfree(to_name);
+ return err;
}
int hostfs_unlink(struct inode *ino, struct dentry *dentry)
@@ -692,13 +698,14 @@ int hostfs_unlink(struct inode *ino, struct dentry *dentry)
char *file;
int err;
- if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ if((file = inode_dentry_name(ino, dentry)) == NULL)
+ return -ENOMEM;
if(append)
- return(-EPERM);
+ return -EPERM;
err = unlink_file(file);
kfree(file);
- return(err);
+ return err;
}
int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
@@ -706,10 +713,11 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
char *file;
int err;
- if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ if((file = inode_dentry_name(ino, dentry)) == NULL)
+ return -ENOMEM;
err = make_symlink(file, to);
kfree(file);
- return(err);
+ return err;
}
int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
@@ -717,10 +725,11 @@ int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
char *file;
int err;
- if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ if((file = inode_dentry_name(ino, dentry)) == NULL)
+ return -ENOMEM;
err = do_mkdir(file, mode);
kfree(file);
- return(err);
+ return err;
}
int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
@@ -728,10 +737,11 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
char *file;
int err;
- if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
+ if((file = inode_dentry_name(ino, dentry)) == NULL)
+ return -ENOMEM;
err = do_rmdir(file);
kfree(file);
- return(err);
+ return err;
}
int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
@@ -764,14 +774,14 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
goto out_put;
d_instantiate(dentry, inode);
- return(0);
+ return 0;
out_free:
kfree(name);
out_put:
iput(inode);
out:
- return(err);
+ return err;
}
int hostfs_rename(struct inode *from_ino, struct dentry *from,
@@ -781,15 +791,15 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
int err;
if((from_name = inode_dentry_name(from_ino, from)) == NULL)
- return(-ENOMEM);
+ return -ENOMEM;
if((to_name = inode_dentry_name(to_ino, to)) == NULL){
kfree(from_name);
- return(-ENOMEM);
+ return -ENOMEM;
}
err = rename_file(from_name, to_name);
kfree(from_name);
kfree(to_name);
- return(err);
+ return err;
}
int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
@@ -801,7 +811,8 @@ int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
if (desired & MAY_WRITE) w = 1;
if (desired & MAY_EXEC) x = 1;
name = inode_name(ino, 0);
- if (name == NULL) return(-ENOMEM);
+ if (name == NULL)
+ return -ENOMEM;
if (S_ISCHR(ino->i_mode) || S_ISBLK(ino->i_mode) ||
S_ISFIFO(ino->i_mode) || S_ISSOCK(ino->i_mode))
@@ -820,6 +831,8 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
char *name;
int err;
+ int fd = HOSTFS_I(dentry->d_inode)->fd;
+
err = inode_change_ok(dentry->d_inode, attr);
if (err)
return err;
@@ -863,20 +876,21 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
}
name = dentry_name(dentry, 0);
- if(name == NULL) return(-ENOMEM);
- err = set_attr(name, &attrs);
+ if(name == NULL)
+ return -ENOMEM;
+ err = set_attr(name, &attrs, fd);
kfree(name);
if(err)
- return(err);
+ return err;
- return(inode_setattr(dentry->d_inode, attr));
+ return inode_setattr(dentry->d_inode, attr);
}
int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
generic_fillattr(dentry->d_inode, stat);
- return(0);
+ return 0;
}
static const struct inode_operations hostfs_iops = {
@@ -915,7 +929,8 @@ int hostfs_link_readpage(struct file *file, struct page *page)
buffer = kmap(page);
name = inode_name(page->mapping->host, 0);
- if(name == NULL) return(-ENOMEM);
+ if(name == NULL)
+ return -ENOMEM;
err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
kfree(name);
if(err == PAGE_CACHE_SIZE)
@@ -928,7 +943,7 @@ int hostfs_link_readpage(struct file *file, struct page *page)
}
kunmap(page);
unlock_page(page);
- return(err);
+ return err;
}
static const struct address_space_operations hostfs_link_aops = {
@@ -978,20 +993,20 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
err = read_inode(root_inode);
if(err){
- /* No iput in this case because the dput does that for us */
- dput(sb->s_root);
- sb->s_root = NULL;
+ /* No iput in this case because the dput does that for us */
+ dput(sb->s_root);
+ sb->s_root = NULL;
goto out;
- }
+ }
- return(0);
+ return 0;
- out_put:
- iput(root_inode);
- out_free:
+out_put:
+ iput(root_inode);
+out_free:
kfree(host_root_path);
- out:
- return(err);
+out:
+ return err;
}
static int hostfs_read_sb(struct file_system_type *type,
@@ -1011,7 +1026,7 @@ static struct file_system_type hostfs_type = {
static int __init init_hostfs(void)
{
- return(register_filesystem(&hostfs_type));
+ return register_filesystem(&hostfs_type);
}
static void __exit exit_hostfs(void)
@@ -1022,14 +1037,3 @@ static void __exit exit_hostfs(void)
module_init(init_hostfs)
module_exit(exit_hostfs)
MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
index 1ed5ea389f1..5625e2481dd 100644
--- a/fs/hostfs/hostfs_user.c
+++ b/fs/hostfs/hostfs_user.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -21,12 +21,16 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
int *nlink_out, int *uid_out, int *gid_out,
unsigned long long *size_out, struct timespec *atime_out,
struct timespec *mtime_out, struct timespec *ctime_out,
- int *blksize_out, unsigned long long *blocks_out)
+ int *blksize_out, unsigned long long *blocks_out, int fd)
{
struct stat64 buf;
- if(lstat64(path, &buf) < 0)
- return(-errno);
+ if(fd >= 0) {
+ if (fstat64(fd, &buf) < 0)
+ return -errno;
+ } else if(lstat64(path, &buf) < 0) {
+ return -errno;
+ }
if(inode_out != NULL) *inode_out = buf.st_ino;
if(mode_out != NULL) *mode_out = buf.st_mode;
@@ -48,7 +52,7 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
}
if(blksize_out != NULL) *blksize_out = buf.st_blksize;
if(blocks_out != NULL) *blocks_out = buf.st_blocks;
- return(0);
+ return 0;
}
int file_type(const char *path, int *maj, int *min)
@@ -56,7 +60,7 @@ int file_type(const char *path, int *maj, int *min)
struct stat64 buf;
if(lstat64(path, &buf) < 0)
- return(-errno);
+ return -errno;
/*We cannot pass rdev as is because glibc and the kernel disagree
*about its definition.*/
if(maj != NULL)
@@ -64,13 +68,13 @@ int file_type(const char *path, int *maj, int *min)
if(min != NULL)
*min = minor(buf.st_rdev);
- if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
- else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
- else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
- else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
- else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
- else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
- else return(OS_TYPE_FILE);
+ if(S_ISDIR(buf.st_mode)) return OS_TYPE_DIR;
+ else if(S_ISLNK(buf.st_mode)) return OS_TYPE_SYMLINK;
+ else if(S_ISCHR(buf.st_mode)) return OS_TYPE_CHARDEV;
+ else if(S_ISBLK(buf.st_mode)) return OS_TYPE_BLOCKDEV;
+ else if(S_ISFIFO(buf.st_mode))return OS_TYPE_FIFO;
+ else if(S_ISSOCK(buf.st_mode))return OS_TYPE_SOCK;
+ else return OS_TYPE_FILE;
}
int access_file(char *path, int r, int w, int x)
@@ -80,8 +84,9 @@ int access_file(char *path, int r, int w, int x)
if(r) mode = R_OK;
if(w) mode |= W_OK;
if(x) mode |= X_OK;
- if(access(path, mode) != 0) return(-errno);
- else return(0);
+ if(access(path, mode) != 0)
+ return -errno;
+ else return 0;
}
int open_file(char *path, int r, int w, int append)
@@ -99,8 +104,9 @@ int open_file(char *path, int r, int w, int append)
if(append)
mode |= O_APPEND;
fd = open64(path, mode);
- if(fd < 0) return(-errno);
- else return(fd);
+ if(fd < 0)
+ return -errno;
+ else return fd;
}
void *open_dir(char *path, int *err_out)
@@ -109,8 +115,9 @@ void *open_dir(char *path, int *err_out)
dir = opendir(path);
*err_out = errno;
- if(dir == NULL) return(NULL);
- return(dir);
+ if(dir == NULL)
+ return NULL;
+ return dir;
}
char *read_dir(void *stream, unsigned long long *pos,
@@ -121,11 +128,12 @@ char *read_dir(void *stream, unsigned long long *pos,
seekdir(dir, *pos);
ent = readdir(dir);
- if(ent == NULL) return(NULL);
+ if(ent == NULL)
+ return NULL;
*len_out = strlen(ent->d_name);
*ino_out = ent->d_ino;
*pos = telldir(dir);
- return(ent->d_name);
+ return ent->d_name;
}
int read_file(int fd, unsigned long long *offset, char *buf, int len)
@@ -133,9 +141,10 @@ int read_file(int fd, unsigned long long *offset, char *buf, int len)
int n;
n = pread64(fd, buf, len, *offset);
- if(n < 0) return(-errno);
+ if(n < 0)
+ return -errno;
*offset += n;
- return(n);
+ return n;
}
int write_file(int fd, unsigned long long *offset, const char *buf, int len)
@@ -143,9 +152,10 @@ int write_file(int fd, unsigned long long *offset, const char *buf, int len)
int n;
n = pwrite64(fd, buf, len, *offset);
- if(n < 0) return(-errno);
+ if(n < 0)
+ return -errno;
*offset += n;
- return(n);
+ return n;
}
int lseek_file(int fd, long long offset, int whence)
@@ -154,8 +164,8 @@ int lseek_file(int fd, long long offset, int whence)
ret = lseek64(fd, offset, whence);
if(ret < 0)
- return(-errno);
- return(0);
+ return -errno;
+ return 0;
}
int fsync_file(int fd, int datasync)
@@ -198,65 +208,90 @@ int file_create(char *name, int ur, int uw, int ux, int gr,
mode |= ox ? S_IXOTH : 0;
fd = open64(name, O_CREAT | O_RDWR, mode);
if(fd < 0)
- return(-errno);
- return(fd);
+ return -errno;
+ return fd;
}
-int set_attr(const char *file, struct hostfs_iattr *attrs)
+int set_attr(const char *file, struct hostfs_iattr *attrs, int fd)
{
- struct utimbuf buf;
+ struct timeval times[2];
+ struct timespec atime_ts, mtime_ts;
int err, ma;
- if(attrs->ia_valid & HOSTFS_ATTR_MODE){
- if(chmod(file, attrs->ia_mode) != 0) return(-errno);
- }
- if(attrs->ia_valid & HOSTFS_ATTR_UID){
- if(chown(file, attrs->ia_uid, -1)) return(-errno);
+ if (attrs->ia_valid & HOSTFS_ATTR_MODE) {
+ if (fd >= 0) {
+ if (fchmod(fd, attrs->ia_mode) != 0)
+ return (-errno);
+ } else if (chmod(file, attrs->ia_mode) != 0) {
+ return -errno;
+ }
}
- if(attrs->ia_valid & HOSTFS_ATTR_GID){
- if(chown(file, -1, attrs->ia_gid)) return(-errno);
+ if (attrs->ia_valid & HOSTFS_ATTR_UID) {
+ if (fd >= 0) {
+ if (fchown(fd, attrs->ia_uid, -1))
+ return -errno;
+ } else if(chown(file, attrs->ia_uid, -1)) {
+ return -errno;
+ }
}
- if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
- if(truncate(file, attrs->ia_size)) return(-errno);
+ if (attrs->ia_valid & HOSTFS_ATTR_GID) {
+ if (fd >= 0) {
+ if (fchown(fd, -1, attrs->ia_gid))
+ return -errno;
+ } else if (chown(file, -1, attrs->ia_gid)) {
+ return -errno;
+ }
}
- ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
- if((attrs->ia_valid & ma) == ma){
- buf.actime = attrs->ia_atime.tv_sec;
- buf.modtime = attrs->ia_mtime.tv_sec;
- if(utime(file, &buf) != 0) return(-errno);
+ if (attrs->ia_valid & HOSTFS_ATTR_SIZE) {
+ if (fd >= 0) {
+ if (ftruncate(fd, attrs->ia_size))
+ return -errno;
+ } else if (truncate(file, attrs->ia_size)) {
+ return -errno;
+ }
}
- else {
- struct timespec ts;
-
- if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
- err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, &ts, NULL, NULL, NULL);
- if(err != 0)
- return(err);
- buf.actime = attrs->ia_atime.tv_sec;
- buf.modtime = ts.tv_sec;
- if(utime(file, &buf) != 0)
- return(-errno);
+
+ /* Update accessed and/or modified time, in two parts: first set
+ * times according to the changes to perform, and then call futimes()
+ * or utimes() to apply them. */
+ ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET);
+ if (attrs->ia_valid & ma) {
+ err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
+ &atime_ts, &mtime_ts, NULL, NULL, NULL, fd);
+ if (err != 0)
+ return err;
+
+ times[0].tv_sec = atime_ts.tv_sec;
+ times[0].tv_usec = atime_ts.tv_nsec * 1000;
+ times[1].tv_sec = mtime_ts.tv_sec;
+ times[1].tv_usec = mtime_ts.tv_nsec * 1000;
+
+ if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) {
+ times[0].tv_sec = attrs->ia_atime.tv_sec;
+ times[0].tv_usec = attrs->ia_atime.tv_nsec * 1000;
+ }
+ if (attrs->ia_valid & HOSTFS_ATTR_MTIME_SET) {
+ times[1].tv_sec = attrs->ia_mtime.tv_sec;
+ times[1].tv_usec = attrs->ia_mtime.tv_nsec * 1000;
}
- if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
- err = stat_file(file, NULL, NULL, NULL, NULL, NULL,
- NULL, &ts, NULL, NULL, NULL, NULL);
- if(err != 0)
- return(err);
- buf.actime = ts.tv_sec;
- buf.modtime = attrs->ia_mtime.tv_sec;
- if(utime(file, &buf) != 0)
- return(-errno);
+
+ if (fd >= 0) {
+ if (futimes(fd, times) != 0)
+ return -errno;
+ } else if (utimes(file, times) != 0) {
+ return -errno;
}
}
+
if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL,
&attrs->ia_atime, &attrs->ia_mtime, NULL,
- NULL, NULL);
- if(err != 0) return(err);
+ NULL, NULL, fd);
+ if(err != 0)
+ return err;
}
- return(0);
+ return 0;
}
int make_symlink(const char *from, const char *to)
@@ -264,8 +299,9 @@ int make_symlink(const char *from, const char *to)
int err;
err = symlink(to, from);
- if(err) return(-errno);
- return(0);
+ if(err)
+ return -errno;
+ return 0;
}
int unlink_file(const char *file)
@@ -273,8 +309,9 @@ int unlink_file(const char *file)
int err;
err = unlink(file);
- if(err) return(-errno);
- return(0);
+ if(err)
+ return -errno;
+ return 0;
}
int do_mkdir(const char *file, int mode)
@@ -282,8 +319,9 @@ int do_mkdir(const char *file, int mode)
int err;
err = mkdir(file, mode);
- if(err) return(-errno);
- return(0);
+ if(err)
+ return -errno;
+ return 0;
}
int do_rmdir(const char *file)
@@ -291,8 +329,9 @@ int do_rmdir(const char *file)
int err;
err = rmdir(file);
- if(err) return(-errno);
- return(0);
+ if(err)
+ return -errno;
+ return 0;
}
int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
@@ -300,8 +339,9 @@ int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor)
int err;
err = mknod(file, mode, makedev(major, minor));
- if(err) return(-errno);
- return(0);
+ if(err)
+ return -errno;
+ return 0;
}
int link_file(const char *to, const char *from)
@@ -309,8 +349,9 @@ int link_file(const char *to, const char *from)
int err;
err = link(to, from);
- if(err) return(-errno);
- return(0);
+ if(err)
+ return -errno;
+ return 0;
}
int do_readlink(char *file, char *buf, int size)
@@ -319,10 +360,10 @@ int do_readlink(char *file, char *buf, int size)
n = readlink(file, buf, size);
if(n < 0)
- return(-errno);
+ return -errno;
if(n < size)
buf[n] = '\0';
- return(n);
+ return n;
}
int rename_file(char *from, char *to)
@@ -330,8 +371,9 @@ int rename_file(char *from, char *to)
int err;
err = rename(from, to);
- if(err < 0) return(-errno);
- return(0);
+ if(err < 0)
+ return -errno;
+ return 0;
}
int do_statfs(char *root, long *bsize_out, long long *blocks_out,
@@ -344,7 +386,9 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out,
int err;
err = statfs64(root, &buf);
- if(err < 0) return(-errno);
+ if(err < 0)
+ return -errno;
+
*bsize_out = buf.f_bsize;
*blocks_out = buf.f_blocks;
*bfree_out = buf.f_bfree;
@@ -360,16 +404,5 @@ int do_statfs(char *root, long *bsize_out, long long *blocks_out,
spare_out[2] = buf.f_spare[2];
spare_out[3] = buf.f_spare[3];
spare_out[4] = buf.f_spare[4];
- return(0);
+ return 0;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index e0174e33852..1b95f39fbc3 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -176,8 +176,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
mutex_init(&ei->i_mutex);
mutex_init(&ei->i_parent_mutex);
inode_init_once(&ei->vfs_inode);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 8c718a3d413..98959b87cdf 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -22,6 +22,7 @@
#include <linux/backing-dev.h>
#include <linux/hugetlb.h>
#include <linux/pagevec.h>
+#include <linux/mman.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
#include <linux/dnotify.h>
@@ -98,10 +99,7 @@ out:
* Called under down_write(mmap_sem).
*/
-#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
-unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
- unsigned long len, unsigned long pgoff, unsigned long flags);
-#else
+#ifndef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
static unsigned long
hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -115,6 +113,12 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
if (len > TASK_SIZE)
return -ENOMEM;
+ if (flags & MAP_FIXED) {
+ if (prepare_hugepage_range(addr, len, pgoff))
+ return -EINVAL;
+ return addr;
+ }
+
if (addr) {
addr = ALIGN(addr, HPAGE_SIZE);
vma = find_vma(mm, addr);
@@ -453,7 +457,7 @@ static int hugetlbfs_symlink(struct inode *dir,
*/
static int hugetlbfs_set_page_dirty(struct page *page)
{
- struct page *head = (struct page *)page_private(page);
+ struct page *head = compound_head(page);
SetPageDirty(head);
return 0;
@@ -552,8 +556,7 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
@@ -744,6 +747,9 @@ struct file *hugetlb_zero_setup(size_t size)
char buf[16];
static atomic_t counter;
+ if (!hugetlbfs_vfsmount)
+ return ERR_PTR(-ENOENT);
+
if (!can_do_hugetlb_shm())
return ERR_PTR(-EPERM);
diff --git a/fs/inode.c b/fs/inode.c
index 5abb097ab1b..df2ef15d03d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -213,8 +213,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct inode * inode = (struct inode *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(inode);
}
@@ -251,7 +250,7 @@ void clear_inode(struct inode *inode)
BUG_ON(inode->i_state & I_CLEAR);
wait_on_inode(inode);
DQUOT_DROP(inode);
- if (inode->i_sb && inode->i_sb->s_op->clear_inode)
+ if (inode->i_sb->s_op->clear_inode)
inode->i_sb->s_op->clear_inode(inode);
if (S_ISBLK(inode->i_mode) && inode->i_bdev)
bd_forget(inode);
@@ -276,7 +275,7 @@ static void dispose_list(struct list_head *head)
while (!list_empty(head)) {
struct inode *inode;
- inode = list_entry(head->next, struct inode, i_list);
+ inode = list_first_entry(head, struct inode, i_list);
list_del(&inode->i_list);
if (inode->i_data.nrpages)
@@ -525,7 +524,12 @@ repeat:
*/
struct inode *new_inode(struct super_block *sb)
{
- static unsigned long last_ino;
+ /*
+ * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
+ * error if st_ino won't fit in target struct field. Use 32bit counter
+ * here to attempt to avoid that.
+ */
+ static unsigned int last_ino;
struct inode * inode;
spin_lock_prefetch(&inode_lock);
@@ -684,27 +688,28 @@ static unsigned long hash(struct super_block *sb, unsigned long hashval)
*/
ino_t iunique(struct super_block *sb, ino_t max_reserved)
{
- static ino_t counter;
+ /*
+ * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW
+ * error if st_ino won't fit in target struct field. Use 32bit counter
+ * here to attempt to avoid that.
+ */
+ static unsigned int counter;
struct inode *inode;
- struct hlist_head * head;
+ struct hlist_head *head;
ino_t res;
+
spin_lock(&inode_lock);
-retry:
- if (counter > max_reserved) {
- head = inode_hashtable + hash(sb,counter);
+ do {
+ if (counter <= max_reserved)
+ counter = max_reserved + 1;
res = counter++;
+ head = inode_hashtable + hash(sb, res);
inode = find_inode_fast(sb, head, res);
- if (!inode) {
- spin_unlock(&inode_lock);
- return res;
- }
- } else {
- counter = max_reserved + 1;
- }
- goto retry;
-
-}
+ } while (inode != NULL);
+ spin_unlock(&inode_lock);
+ return res;
+}
EXPORT_SYMBOL(iunique);
struct inode *igrab(struct inode *inode)
@@ -1041,7 +1046,7 @@ static void generic_forget_inode(struct inode *inode)
if (!(inode->i_state & (I_DIRTY|I_LOCK)))
list_move(&inode->i_list, &inode_unused);
inodes_stat.nr_unused++;
- if (!sb || (sb->s_flags & MS_ACTIVE)) {
+ if (sb->s_flags & MS_ACTIVE) {
spin_unlock(&inode_lock);
return;
}
diff --git a/fs/inotify.c b/fs/inotify.c
index f5099d86fd9..7457501b956 100644
--- a/fs/inotify.c
+++ b/fs/inotify.c
@@ -509,7 +509,7 @@ void inotify_destroy(struct inotify_handle *ih)
mutex_unlock(&ih->mutex);
break;
}
- watch = list_entry(watches->next, struct inotify_watch, h_list);
+ watch = list_first_entry(watches, struct inotify_watch, h_list);
get_inotify_watch(watch);
mutex_unlock(&ih->mutex);
diff --git a/fs/internal.h b/fs/internal.h
index ea00126c9a5..392e8ccd6fc 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -9,8 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/ioctl32.h>
-
struct super_block;
/*
@@ -42,14 +40,6 @@ static inline int sb_is_blkdev_sb(struct super_block *sb)
extern void __init chrdev_init(void);
/*
- * compat_ioctl.c
- */
-#ifdef CONFIG_COMPAT
-extern struct ioctl_trans ioctl_start[];
-extern int ioctl_table_size;
-#endif
-
-/*
* namespace.c
*/
extern int copy_mount_options(const void __user *, unsigned long *);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index ff61772ceed..479c1038ed4 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -67,8 +67,6 @@ static int file_ioctl(struct file *filp, unsigned int cmd,
return put_user(res, p);
}
case FIGETBSZ:
- if (inode->i_sb == NULL)
- return -EBADF;
return put_user(inode->i_sb->s_blocksize, p);
case FIONREAD:
return put_user(i_size_read(inode) - filp->f_pos, p);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 64a96cdfe3a..e99f7ff4ecb 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -77,8 +77,7 @@ static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags
{
struct iso_inode_info *ei = foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 0208cc7ac5d..47552d4a632 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/checkpoint.c
+ * linux/fs/jbd/checkpoint.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index be4648bc7a2..1facfaff97c 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
/*
* Default IO end handler for temporary BJ_IO buffer_heads.
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 10fff944393..46fe7439fb9 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -28,7 +28,6 @@
#include <linux/jbd.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/freezer.h>
@@ -211,10 +210,16 @@ end_loop:
return 0;
}
-static void journal_start_thread(journal_t *journal)
+static int journal_start_thread(journal_t *journal)
{
- kthread_run(kjournald, journal, "kjournald");
+ struct task_struct *t;
+
+ t = kthread_run(kjournald, journal, "kjournald");
+ if (IS_ERR(t))
+ return PTR_ERR(t);
+
wait_event(journal->j_wait_done_commit, journal->j_task != 0);
+ return 0;
}
static void journal_kill_thread(journal_t *journal)
@@ -840,8 +845,7 @@ static int journal_reset(journal_t *journal)
/* Add the dynamic fields and write it to disk. */
journal_update_superblock(journal, 1);
- journal_start_thread(journal);
- return 0;
+ return journal_start_thread(journal);
}
/**
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index 11563fe2a52..2a5f4b833e3 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/recovery.c
+ * linux/fs/jbd/recovery.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index d204ab394f3..824e3b7d4ec 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/revoke.c
+ * linux/fs/jbd/revoke.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 2000
*
@@ -66,7 +66,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#endif
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index cceaf57e377..772b6531a2a 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/transaction.c
+ * linux/fs/jbd/transaction.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1998
*
@@ -23,7 +23,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/timer.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/highmem.h>
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
index 68039fa9a56..3fccde7ba00 100644
--- a/fs/jbd2/checkpoint.c
+++ b/fs/jbd2/checkpoint.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/checkpoint.c
+ * linux/fs/jbd2/checkpoint.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 6bd8005e3d3..2856e1100a5 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -20,7 +20,6 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
/*
* Default IO end handler for temporary BJ_IO buffer_heads.
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 44fc32bfd7f..78d63b818f0 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -28,7 +28,6 @@
#include <linux/jbd2.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/freezer.h>
@@ -211,10 +210,16 @@ end_loop:
return 0;
}
-static void jbd2_journal_start_thread(journal_t *journal)
+static int jbd2_journal_start_thread(journal_t *journal)
{
- kthread_run(kjournald2, journal, "kjournald2");
+ struct task_struct *t;
+
+ t = kthread_run(kjournald2, journal, "kjournald2");
+ if (IS_ERR(t))
+ return PTR_ERR(t);
+
wait_event(journal->j_wait_done_commit, journal->j_task != 0);
+ return 0;
}
static void journal_kill_thread(journal_t *journal)
@@ -840,8 +845,7 @@ static int journal_reset(journal_t *journal)
/* Add the dynamic fields and write it to disk. */
jbd2_journal_update_superblock(journal, 1);
- jbd2_journal_start_thread(journal);
- return 0;
+ return jbd2_journal_start_thread(journal);
}
/**
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 9f10acafaf7..395c92a04ac 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/recovery.c
+ * linux/fs/jbd2/recovery.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index f506646ad0f..9246e763da7 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/revoke.c
+ * linux/fs/jbd2/revoke.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 2000
*
@@ -66,7 +66,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/list.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#endif
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 3a8700153cb..7946ff43fc4 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/transaction.c
+ * linux/fs/jbd2/transaction.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1998
*
@@ -23,7 +23,6 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/timer.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/highmem.h>
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index e51164a8a8d..45368f8bbe7 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -47,8 +47,7 @@ static void jffs2_i_init_once(void * foo, struct kmem_cache * cachep, unsigned l
{
struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
init_MUTEX(&ei->sem);
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index e285022f006..3467dde27e5 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -55,7 +55,6 @@ void jfs_read_inode(struct inode *inode)
inode->i_op = &jfs_file_inode_operations;
init_special_inode(inode, inode->i_mode, inode->i_rdev);
}
- jfs_set_inode_flags(inode);
}
/*
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
index ed814b1ff4d..fe063af6fd2 100644
--- a/fs/jfs/ioctl.c
+++ b/fs/jfs/ioctl.c
@@ -59,6 +59,7 @@ int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
switch (cmd) {
case JFS_IOC_GETFLAGS:
+ jfs_get_inode_flags(jfs_inode);
flags = jfs_inode->mode2 & JFS_FL_USER_VISIBLE;
flags = jfs_map_ext2(flags, 0);
return put_user(flags, (int __user *) arg);
@@ -78,6 +79,7 @@ int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
if (!S_ISDIR(inode->i_mode))
flags &= ~JFS_DIRSYNC_FL;
+ jfs_get_inode_flags(jfs_inode);
oldflags = jfs_inode->mode2;
/*
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index 82b0544bd76..f3b1ebb2228 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -1507,7 +1507,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
if (l2nb < budmin) {
/* search the lower level dmap control pages to get
- * the starting block number of the the dmap that
+ * the starting block number of the dmap that
* contains or starts off the free space.
*/
if ((rc =
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index aa5124b643b..c6530227cda 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -386,7 +386,7 @@ int diRead(struct inode *ip)
return -EIO;
}
- /* locate the the disk inode requested */
+ /* locate the disk inode requested */
dp = (struct dinode *) mp->data;
dp += rel_inode;
@@ -1407,7 +1407,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
inum = pip->i_ino + 1;
ino = inum & (INOSPERIAG - 1);
- /* back off the the hint if it is outside of the iag */
+ /* back off the hint if it is outside of the iag */
if (ino == 0)
inum = pip->i_ino;
@@ -3078,6 +3078,7 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
jfs_ip->fileset = le32_to_cpu(dip->di_fileset);
jfs_ip->mode2 = le32_to_cpu(dip->di_mode);
+ jfs_set_inode_flags(ip);
ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff;
if (sbi->umask != -1) {
@@ -3174,6 +3175,7 @@ static void copy_to_dinode(struct dinode * dip, struct inode *ip)
dip->di_gid = cpu_to_le32(ip->i_gid);
else
dip->di_gid = cpu_to_le32(jfs_ip->saved_gid);
+ jfs_get_inode_flags(jfs_ip);
/*
* mode2 is only needed for storing the higher order bits.
* Trust i_mode for the lower order ones
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 4c67ed97682..ed6574bee51 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -45,6 +45,24 @@ void jfs_set_inode_flags(struct inode *inode)
inode->i_flags |= S_SYNC;
}
+void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip)
+{
+ unsigned int flags = jfs_ip->vfs_inode.i_flags;
+
+ jfs_ip->mode2 &= ~(JFS_IMMUTABLE_FL | JFS_APPEND_FL | JFS_NOATIME_FL |
+ JFS_DIRSYNC_FL | JFS_SYNC_FL);
+ if (flags & S_IMMUTABLE)
+ jfs_ip->mode2 |= JFS_IMMUTABLE_FL;
+ if (flags & S_APPEND)
+ jfs_ip->mode2 |= JFS_APPEND_FL;
+ if (flags & S_NOATIME)
+ jfs_ip->mode2 |= JFS_NOATIME_FL;
+ if (flags & S_DIRSYNC)
+ jfs_ip->mode2 |= JFS_DIRSYNC_FL;
+ if (flags & S_SYNC)
+ jfs_ip->mode2 |= JFS_SYNC_FL;
+}
+
/*
* NAME: ialloc()
*
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index 6802837f757..2374b595f2e 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -31,6 +31,7 @@ extern void jfs_truncate(struct inode *);
extern void jfs_truncate_nolock(struct inode *, loff_t);
extern void jfs_free_zero_link(struct inode *);
extern struct dentry *jfs_get_parent(struct dentry *dentry);
+extern void jfs_get_inode_flags(struct jfs_inode_info *);
extern void jfs_set_inode_flags(struct inode *);
extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
index df48ece4b7a..ecf04882265 100644
--- a/fs/jfs/jfs_lock.h
+++ b/fs/jfs/jfs_lock.h
@@ -45,7 +45,7 @@ do { \
io_schedule(); \
lock_cmd; \
} \
- current->state = TASK_RUNNING; \
+ __set_current_state(TASK_RUNNING); \
remove_wait_queue(&wq, &__wait); \
} while (0)
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 5065baa530b..44a2f33cb98 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -62,7 +62,6 @@
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/kthread.h>
#include <linux/buffer_head.h> /* for sync_blockdev() */
@@ -1590,7 +1589,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
set_current_state(TASK_UNINTERRUPTIBLE);
LOGGC_UNLOCK(log);
schedule();
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
LOGGC_LOCK(log);
remove_wait_queue(&target->gcwait, &__wait);
}
@@ -1961,7 +1960,7 @@ static void lbmfree(struct lbuf * bp)
/*
* NAME: lbmRedrive
*
- * FUNCTION: add a log buffer to the the log redrive list
+ * FUNCTION: add a log buffer to the log redrive list
*
* PARAMETER:
* bp - log buffer
@@ -2354,14 +2353,15 @@ int jfsIOWait(void *arg)
lbmStartIO(bp);
spin_lock_irq(&log_redrive_lock);
}
- spin_unlock_irq(&log_redrive_lock);
if (freezing(current)) {
+ spin_unlock_irq(&log_redrive_lock);
refrigerator();
} else {
set_current_state(TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&log_redrive_lock);
schedule();
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
}
} while (!kthread_should_stop());
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 58deae00750..6b3acb0b578 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -184,8 +184,7 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct metapage *mp = (struct metapage *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
mp->lid = 0;
mp->lsn = 0;
mp->flag = 0;
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 03893acbfda..25430d0b0d5 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -44,7 +44,6 @@
#include <linux/fs.h>
#include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/freezer.h>
#include <linux/module.h>
@@ -136,7 +135,7 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
set_current_state(TASK_UNINTERRUPTIBLE);
TXN_UNLOCK();
io_schedule();
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(event, &wait);
}
@@ -2798,7 +2797,7 @@ int jfs_lazycommit(void *arg)
set_current_state(TASK_INTERRUPTIBLE);
LAZY_UNLOCK(flags);
schedule();
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&jfs_commit_thread_wait, &wq);
}
} while (!kthread_should_stop());
@@ -2990,7 +2989,7 @@ int jfs_sync(void *arg)
set_current_state(TASK_INTERRUPTIBLE);
TXN_UNLOCK();
schedule();
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
}
} while (!kthread_should_stop());
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 52d73d54a93..ea9dc3e65dc 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -752,8 +752,7 @@ static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags
{
struct jfs_inode_info *jfs_ip = (struct jfs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
memset(jfs_ip, 0, sizeof(struct jfs_inode_info));
INIT_LIST_HEAD(&jfs_ip->anon_inode_list);
init_rwsem(&jfs_ip->rdwrlock);
diff --git a/fs/libfs.c b/fs/libfs.c
index d93842d3c0a..5294de1f40c 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -159,7 +159,10 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir)
continue;
spin_unlock(&dcache_lock);
- if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0)
+ if (filldir(dirent, next->d_name.name,
+ next->d_name.len, filp->f_pos,
+ next->d_inode->i_ino,
+ dt_type(next->d_inode)) < 0)
return 0;
spin_lock(&dcache_lock);
/* next is still alive */
@@ -220,6 +223,12 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name,
root = new_inode(s);
if (!root)
goto Enomem;
+ /*
+ * since this is the first inode, make it number 1. New inodes created
+ * after this must take care not to collide with it (by passing
+ * max_reserved of 1 to iunique).
+ */
+ root->i_ino = 1;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_uid = root->i_gid = 0;
root->i_atime = root->i_mtime = root->i_ctime = CURRENT_TIME;
@@ -360,6 +369,11 @@ int simple_commit_write(struct file *file, struct page *page,
return 0;
}
+/*
+ * the inodes created here are not hashed. If you use iunique to generate
+ * unique inode values later for this filesystem, then you must take care
+ * to pass it an appropriate max_reserved value to avoid collisions.
+ */
int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files)
{
struct inode *inode;
@@ -376,6 +390,11 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
inode = new_inode(s);
if (!inode)
return -ENOMEM;
+ /*
+ * because the root inode is 1, the files array must not contain an
+ * entry at index 1
+ */
+ inode->i_ino = 1;
inode->i_mode = S_IFDIR | 0755;
inode->i_uid = inode->i_gid = 0;
inode->i_blocks = 0;
@@ -391,6 +410,13 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
for (i = 0; !files->name || files->name[0]; i++, files++) {
if (!files->name)
continue;
+
+ /* warn if it tries to conflict with the root inode */
+ if (unlikely(i == 1))
+ printk(KERN_WARNING "%s: %s passed in a files array"
+ "with an index of 1!\n", __func__,
+ s->s_type->name);
+
dentry = d_alloc_name(root, files->name);
if (!dentry)
goto out;
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index a5c019e1a44..a10343bed16 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -12,7 +12,6 @@
#include <linux/fs.h>
#include <linux/nfs_fs.h>
#include <linux/utsname.h>
-#include <linux/smp_lock.h>
#include <linux/freezer.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index eb243edf893..2102e2d0134 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -225,16 +225,13 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
#define SM_monres_sz 2
#define SM_unmonres_sz 1
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
-
static struct rpc_procinfo nsm_procedures[] = {
[SM_MON] = {
.p_proc = SM_MON,
.p_encode = (kxdrproc_t) xdr_encode_mon,
.p_decode = (kxdrproc_t) xdr_decode_stat_res,
- .p_bufsiz = MAX(SM_mon_sz, SM_monres_sz) << 2,
+ .p_arglen = SM_mon_sz,
+ .p_replen = SM_monres_sz,
.p_statidx = SM_MON,
.p_name = "MONITOR",
},
@@ -242,7 +239,8 @@ static struct rpc_procinfo nsm_procedures[] = {
.p_proc = SM_UNMON,
.p_encode = (kxdrproc_t) xdr_encode_unmon,
.p_decode = (kxdrproc_t) xdr_decode_stat,
- .p_bufsiz = MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
+ .p_arglen = SM_mon_id_sz,
+ .p_replen = SM_unmonres_sz,
.p_statidx = SM_UNMON,
.p_name = "UNMONITOR",
},
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 47a66aa5d55..bf27b6c6cb6 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -99,7 +99,9 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now check for conflicting locks */
- resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+ resp->status = nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie);
+ if (resp->status == nlm_drop_reply)
+ return rpc_drop_reply;
dprintk("lockd: TEST4 status %d\n", ntohl(resp->status));
nlm_release_host(host);
@@ -143,6 +145,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Now try to lock the file */
resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
argp->block, &argp->cookie);
+ if (resp->status == nlm_drop_reply)
+ return rpc_drop_reply;
dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cf51f849e76..b3efa4536cc 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -173,7 +173,7 @@ found:
*/
static inline struct nlm_block *
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
- struct nlm_lock *lock, struct nlm_cookie *cookie)
+ struct nlm_lock *lock, struct nlm_cookie *cookie)
{
struct nlm_block *block;
struct nlm_host *host;
@@ -210,6 +210,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
block->b_daemon = rqstp->rq_server;
block->b_host = host;
block->b_file = file;
+ block->b_fl = NULL;
file->f_count++;
/* Add to file's list of blocks */
@@ -261,6 +262,7 @@ static void nlmsvc_free_block(struct kref *kref)
nlmsvc_freegrantargs(block->b_call);
nlm_release_call(block->b_call);
nlm_release_file(block->b_file);
+ kfree(block->b_fl);
kfree(block);
}
@@ -331,6 +333,31 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call)
}
/*
+ * Deferred lock request handling for non-blocking lock
+ */
+static u32
+nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
+{
+ u32 status = nlm_lck_denied_nolocks;
+
+ block->b_flags |= B_QUEUED;
+
+ nlmsvc_insert_block(block, NLM_TIMEOUT);
+
+ block->b_cache_req = &rqstp->rq_chandle;
+ if (rqstp->rq_chandle.defer) {
+ block->b_deferred_req =
+ rqstp->rq_chandle.defer(block->b_cache_req);
+ if (block->b_deferred_req != NULL)
+ status = nlm_drop_reply;
+ }
+ dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n",
+ block, block->b_flags, status);
+
+ return status;
+}
+
+/*
* Attempt to establish a lock, and if it can't be granted, block it
* if required.
*/
@@ -338,7 +365,7 @@ __be32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{
- struct nlm_block *block, *newblock = NULL;
+ struct nlm_block *block = NULL;
int error;
__be32 ret;
@@ -351,29 +378,58 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
wait);
- lock->fl.fl_flags &= ~FL_SLEEP;
-again:
/* Lock file against concurrent access */
mutex_lock(&file->f_mutex);
- /* Get existing block (in case client is busy-waiting) */
+ /* Get existing block (in case client is busy-waiting)
+ * or create new block
+ */
block = nlmsvc_lookup_block(file, lock);
if (block == NULL) {
- if (newblock != NULL)
- lock = &newblock->b_call->a_args.lock;
- } else
+ block = nlmsvc_create_block(rqstp, file, lock, cookie);
+ ret = nlm_lck_denied_nolocks;
+ if (block == NULL)
+ goto out;
lock = &block->b_call->a_args.lock;
+ } else
+ lock->fl.fl_flags &= ~FL_SLEEP;
- error = posix_lock_file(file->f_file, &lock->fl);
- lock->fl.fl_flags &= ~FL_SLEEP;
+ if (block->b_flags & B_QUEUED) {
+ dprintk("lockd: nlmsvc_lock deferred block %p flags %d\n",
+ block, block->b_flags);
+ if (block->b_granted) {
+ nlmsvc_unlink_block(block);
+ ret = nlm_granted;
+ goto out;
+ }
+ if (block->b_flags & B_TIMED_OUT) {
+ nlmsvc_unlink_block(block);
+ ret = nlm_lck_denied;
+ goto out;
+ }
+ ret = nlm_drop_reply;
+ goto out;
+ }
- dprintk("lockd: posix_lock_file returned %d\n", error);
+ if (!wait)
+ lock->fl.fl_flags &= ~FL_SLEEP;
+ error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
+ lock->fl.fl_flags &= ~FL_SLEEP;
+ dprintk("lockd: vfs_lock_file returned %d\n", error);
switch(error) {
case 0:
ret = nlm_granted;
goto out;
case -EAGAIN:
+ ret = nlm_lck_denied;
break;
+ case -EINPROGRESS:
+ if (wait)
+ break;
+ /* Filesystem lock operation is in progress
+ Add it to the queue waiting for callback */
+ ret = nlmsvc_defer_lock_rqst(rqstp, block);
+ goto out;
case -EDEADLK:
ret = nlm_deadlock;
goto out;
@@ -387,26 +443,11 @@ again:
goto out;
ret = nlm_lck_blocked;
- if (block != NULL)
- goto out;
-
- /* If we don't have a block, create and initialize it. Then
- * retry because we may have slept in kmalloc. */
- /* We have to release f_mutex as nlmsvc_create_block may try to
- * to claim it while doing host garbage collection */
- if (newblock == NULL) {
- mutex_unlock(&file->f_mutex);
- dprintk("lockd: blocking on this lock (allocating).\n");
- if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
- return nlm_lck_denied_nolocks;
- goto again;
- }
/* Append to list of blocked */
- nlmsvc_insert_block(newblock, NLM_NEVER);
+ nlmsvc_insert_block(block, NLM_NEVER);
out:
mutex_unlock(&file->f_mutex);
- nlmsvc_release_block(newblock);
nlmsvc_release_block(block);
dprintk("lockd: nlmsvc_lock returned %u\n", ret);
return ret;
@@ -416,9 +457,14 @@ out:
* Test for presence of a conflicting lock.
*/
__be32
-nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
- struct nlm_lock *conflock)
+nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
+ struct nlm_lock *lock, struct nlm_lock *conflock,
+ struct nlm_cookie *cookie)
{
+ struct nlm_block *block = NULL;
+ int error;
+ __be32 ret;
+
dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n",
file->f_file->f_path.dentry->d_inode->i_sb->s_id,
file->f_file->f_path.dentry->d_inode->i_ino,
@@ -426,19 +472,70 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
- if (posix_test_lock(file->f_file, &lock->fl, &conflock->fl)) {
- dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
- conflock->fl.fl_type,
- (long long)conflock->fl.fl_start,
- (long long)conflock->fl.fl_end);
- conflock->caller = "somehost"; /* FIXME */
- conflock->len = strlen(conflock->caller);
- conflock->oh.len = 0; /* don't return OH info */
- conflock->svid = conflock->fl.fl_pid;
- return nlm_lck_denied;
+ /* Get existing block (in case client is busy-waiting) */
+ block = nlmsvc_lookup_block(file, lock);
+
+ if (block == NULL) {
+ struct file_lock *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+
+ if (conf == NULL)
+ return nlm_granted;
+ block = nlmsvc_create_block(rqstp, file, lock, cookie);
+ if (block == NULL) {
+ kfree(conf);
+ return nlm_granted;
+ }
+ block->b_fl = conf;
+ }
+ if (block->b_flags & B_QUEUED) {
+ dprintk("lockd: nlmsvc_testlock deferred block %p flags %d fl %p\n",
+ block, block->b_flags, block->b_fl);
+ if (block->b_flags & B_TIMED_OUT) {
+ nlmsvc_unlink_block(block);
+ return nlm_lck_denied;
+ }
+ if (block->b_flags & B_GOT_CALLBACK) {
+ if (block->b_fl != NULL
+ && block->b_fl->fl_type != F_UNLCK) {
+ lock->fl = *block->b_fl;
+ goto conf_lock;
+ }
+ else {
+ nlmsvc_unlink_block(block);
+ return nlm_granted;
+ }
+ }
+ return nlm_drop_reply;
}
- return nlm_granted;
+ error = vfs_test_lock(file->f_file, &lock->fl);
+ if (error == -EINPROGRESS)
+ return nlmsvc_defer_lock_rqst(rqstp, block);
+ if (error) {
+ ret = nlm_lck_denied_nolocks;
+ goto out;
+ }
+ if (lock->fl.fl_type == F_UNLCK) {
+ ret = nlm_granted;
+ goto out;
+ }
+
+conf_lock:
+ dprintk("lockd: conflicting lock(ty=%d, %Ld-%Ld)\n",
+ lock->fl.fl_type, (long long)lock->fl.fl_start,
+ (long long)lock->fl.fl_end);
+ conflock->caller = "somehost"; /* FIXME */
+ conflock->len = strlen(conflock->caller);
+ conflock->oh.len = 0; /* don't return OH info */
+ conflock->svid = lock->fl.fl_pid;
+ conflock->fl.fl_type = lock->fl.fl_type;
+ conflock->fl.fl_start = lock->fl.fl_start;
+ conflock->fl.fl_end = lock->fl.fl_end;
+ ret = nlm_lck_denied;
+out:
+ if (block)
+ nlmsvc_release_block(block);
+ return ret;
}
/*
@@ -464,7 +561,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
nlmsvc_cancel_blocked(file, lock);
lock->fl.fl_type = F_UNLCK;
- error = posix_lock_file(file->f_file, &lock->fl);
+ error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
}
@@ -493,6 +590,8 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
block = nlmsvc_lookup_block(file, lock);
mutex_unlock(&file->f_mutex);
if (block != NULL) {
+ vfs_cancel_lock(block->b_file->f_file,
+ &block->b_call->a_args.lock.fl);
status = nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
}
@@ -500,6 +599,63 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
}
/*
+ * This is a callback from the filesystem for VFS file lock requests.
+ * It will be used if fl_grant is defined and the filesystem can not
+ * respond to the request immediately.
+ * For GETLK request it will copy the reply to the nlm_block.
+ * For SETLK or SETLKW request it will get the local posix lock.
+ * In all cases it will move the block to the head of nlm_blocked q where
+ * nlmsvc_retry_blocked() can send back a reply for SETLKW or revisit the
+ * deferred rpc for GETLK and SETLK.
+ */
+static void
+nlmsvc_update_deferred_block(struct nlm_block *block, struct file_lock *conf,
+ int result)
+{
+ block->b_flags |= B_GOT_CALLBACK;
+ if (result == 0)
+ block->b_granted = 1;
+ else
+ block->b_flags |= B_TIMED_OUT;
+ if (conf) {
+ if (block->b_fl)
+ locks_copy_lock(block->b_fl, conf);
+ }
+}
+
+static int nlmsvc_grant_deferred(struct file_lock *fl, struct file_lock *conf,
+ int result)
+{
+ struct nlm_block *block;
+ int rc = -ENOENT;
+
+ lock_kernel();
+ list_for_each_entry(block, &nlm_blocked, b_list) {
+ if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
+ dprintk("lockd: nlmsvc_notify_blocked block %p flags %d\n",
+ block, block->b_flags);
+ if (block->b_flags & B_QUEUED) {
+ if (block->b_flags & B_TIMED_OUT) {
+ rc = -ENOLCK;
+ break;
+ }
+ nlmsvc_update_deferred_block(block, conf, result);
+ } else if (result == 0)
+ block->b_granted = 1;
+
+ nlmsvc_insert_block(block, 0);
+ svc_wake_up(block->b_daemon);
+ rc = 0;
+ break;
+ }
+ }
+ unlock_kernel();
+ if (rc == -ENOENT)
+ printk(KERN_WARNING "lockd: grant for unknown block\n");
+ return rc;
+}
+
+/*
* Unblock a blocked lock request. This is a callback invoked from the
* VFS layer when a lock on which we blocked is removed.
*
@@ -531,6 +687,7 @@ static int nlmsvc_same_owner(struct file_lock *fl1, struct file_lock *fl2)
struct lock_manager_operations nlmsvc_lock_operations = {
.fl_compare_owner = nlmsvc_same_owner,
.fl_notify = nlmsvc_notify_blocked,
+ .fl_grant = nlmsvc_grant_deferred,
};
/*
@@ -553,6 +710,8 @@ nlmsvc_grant_blocked(struct nlm_block *block)
dprintk("lockd: grant blocked lock %p\n", block);
+ kref_get(&block->b_count);
+
/* Unlink block request from list */
nlmsvc_unlink_block(block);
@@ -566,20 +725,23 @@ nlmsvc_grant_blocked(struct nlm_block *block)
/* Try the lock operation again */
lock->fl.fl_flags |= FL_SLEEP;
- error = posix_lock_file(file->f_file, &lock->fl);
+ error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
lock->fl.fl_flags &= ~FL_SLEEP;
switch (error) {
case 0:
break;
case -EAGAIN:
- dprintk("lockd: lock still blocked\n");
+ case -EINPROGRESS:
+ dprintk("lockd: lock still blocked error %d\n", error);
nlmsvc_insert_block(block, NLM_NEVER);
+ nlmsvc_release_block(block);
return;
default:
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
-error, __FUNCTION__);
nlmsvc_insert_block(block, 10 * HZ);
+ nlmsvc_release_block(block);
return;
}
@@ -592,7 +754,6 @@ callback:
nlmsvc_insert_block(block, 30 * HZ);
/* Call the client */
- kref_get(&block->b_count);
nlm_async_call(block->b_call, NLMPROC_GRANTED_MSG, &nlmsvc_grant_ops);
}
@@ -665,6 +826,23 @@ nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
nlmsvc_release_block(block);
}
+/* Helper function to handle retry of a deferred block.
+ * If it is a blocking lock, call grant_blocked.
+ * For a non-blocking lock or test lock, revisit the request.
+ */
+static void
+retry_deferred_block(struct nlm_block *block)
+{
+ if (!(block->b_flags & B_GOT_CALLBACK))
+ block->b_flags |= B_TIMED_OUT;
+ nlmsvc_insert_block(block, NLM_TIMEOUT);
+ dprintk("revisit block %p flags %d\n", block, block->b_flags);
+ if (block->b_deferred_req) {
+ block->b_deferred_req->revisit(block->b_deferred_req, 0);
+ block->b_deferred_req = NULL;
+ }
+}
+
/*
* Retry all blocked locks that have been notified. This is where lockd
* picks up locks that can be granted, or grant notifications that must
@@ -688,9 +866,12 @@ nlmsvc_retry_blocked(void)
dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
block, block->b_when);
- kref_get(&block->b_count);
- nlmsvc_grant_blocked(block);
- nlmsvc_release_block(block);
+ if (block->b_flags & B_QUEUED) {
+ dprintk("nlmsvc_retry_blocked delete block (%p, granted=%d, flags=%d)\n",
+ block, block->b_granted, block->b_flags);
+ retry_deferred_block(block);
+ } else
+ nlmsvc_grant_blocked(block);
}
return timeout;
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 31cb4842573..9cd5c8b3759 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -33,6 +33,7 @@ cast_to_nlm(__be32 status, u32 vers)
case nlm_lck_denied_nolocks:
case nlm_lck_blocked:
case nlm_lck_denied_grace_period:
+ case nlm_drop_reply:
break;
case nlm4_deadlock:
status = nlm_lck_denied;
@@ -127,7 +128,9 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now check for conflicting locks */
- resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
+ resp->status = cast_status(nlmsvc_testlock(rqstp, file, &argp->lock, &resp->lock, &resp->cookie));
+ if (resp->status == nlm_drop_reply)
+ return rpc_drop_reply;
dprintk("lockd: TEST status %d vers %d\n",
ntohl(resp->status), rqstp->rq_vers);
@@ -172,6 +175,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Now try to lock the file */
resp->status = cast_status(nlmsvc_lock(rqstp, file, &argp->lock,
argp->block, &argp->cookie));
+ if (resp->status == nlm_drop_reply)
+ return rpc_drop_reply;
dprintk("lockd: LOCK status %d\n", ntohl(resp->status));
nlm_release_host(host);
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index c0df00c74ce..84ebba33b98 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -182,7 +182,7 @@ again:
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
- if (posix_lock_file(file->f_file, &lock) < 0) {
+ if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) {
printk("lockd: unlock failure in %s:%d\n",
__FILE__, __LINE__);
return 1;
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 34dae5d7073..9702956d206 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -510,17 +510,20 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
return 0;
}
+#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
+# error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
+#endif
+
/*
* Buffer requirements for NLM
*/
#define NLM_void_sz 0
#define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(utsname()->nodename))
-#define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ)
-/* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */
+#define NLM_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE)
+#define NLM_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE)
#define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE)
-#define NLM_lock_sz 3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
-#define NLM_holder_sz 4+NLM_netobj_sz
+#define NLM_lock_sz 3+NLM_caller_sz+NLM_owner_sz+NLM_fhandle_sz
+#define NLM_holder_sz 4+NLM_owner_sz
#define NLM_testargs_sz NLM_cookie_sz+1+NLM_lock_sz
#define NLM_lockargs_sz NLM_cookie_sz+4+NLM_lock_sz
@@ -531,10 +534,6 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
#define NLM_res_sz NLM_cookie_sz+1
#define NLM_norep_sz 0
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
-
/*
* For NLM, a void procedure really returns nothing
*/
@@ -545,7 +544,8 @@ nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
.p_proc = NLMPROC_##proc, \
.p_encode = (kxdrproc_t) nlmclt_encode_##argtype, \
.p_decode = (kxdrproc_t) nlmclt_decode_##restype, \
- .p_bufsiz = MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2, \
+ .p_arglen = NLM_##argtype##_sz, \
+ .p_replen = NLM_##restype##_sz, \
.p_statidx = NLMPROC_##proc, \
.p_name = #proc, \
}
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index a7824055121..ce1efdbe1b3 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -516,17 +516,24 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
return 0;
}
+#if (NLMCLNT_OHSIZE > XDR_MAX_NETOBJ)
+# error "NLM host name cannot be larger than XDR_MAX_NETOBJ!"
+#endif
+
+#if (NLMCLNT_OHSIZE > NLM_MAXSTRLEN)
+# error "NLM host name cannot be larger than NLM's maximum string length!"
+#endif
+
/*
* Buffer requirements for NLM
*/
#define NLM4_void_sz 0
#define NLM4_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#define NLM4_caller_sz 1+XDR_QUADLEN(NLM_MAXSTRLEN)
-#define NLM4_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ)
-/* #define NLM4_owner_sz 1+XDR_QUADLEN(NLM4_MAXOWNER) */
+#define NLM4_caller_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE)
+#define NLM4_owner_sz 1+XDR_QUADLEN(NLMCLNT_OHSIZE)
#define NLM4_fhandle_sz 1+XDR_QUADLEN(NFS3_FHSIZE)
-#define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
-#define NLM4_holder_sz 6+NLM4_netobj_sz
+#define NLM4_lock_sz 5+NLM4_caller_sz+NLM4_owner_sz+NLM4_fhandle_sz
+#define NLM4_holder_sz 6+NLM4_owner_sz
#define NLM4_testargs_sz NLM4_cookie_sz+1+NLM4_lock_sz
#define NLM4_lockargs_sz NLM4_cookie_sz+4+NLM4_lock_sz
@@ -537,10 +544,6 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
#define NLM4_res_sz NLM4_cookie_sz+1
#define NLM4_norep_sz 0
-#ifndef MAX
-# define MAX(a,b) (((a) > (b))? (a) : (b))
-#endif
-
/*
* For NLM, a void procedure really returns nothing
*/
@@ -551,7 +554,8 @@ nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
.p_proc = NLMPROC_##proc, \
.p_encode = (kxdrproc_t) nlm4clt_encode_##argtype, \
.p_decode = (kxdrproc_t) nlm4clt_decode_##restype, \
- .p_bufsiz = MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2, \
+ .p_arglen = NLM4_##argtype##_sz, \
+ .p_replen = NLM4_##restype##_sz, \
.p_statidx = NLMPROC_##proc, \
.p_name = #proc, \
}
diff --git a/fs/locks.c b/fs/locks.c
index 52a81005dab..671a034dc99 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -203,8 +203,7 @@ static void init_once(void *foo, struct kmem_cache *cache, unsigned long flags)
{
struct file_lock *lock = (struct file_lock *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) !=
- SLAB_CTOR_CONSTRUCTOR)
+ if (!(flags & SLAB_CTOR_CONSTRUCTOR))
return;
locks_init_lock(lock);
@@ -666,11 +665,11 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
}
int
-posix_test_lock(struct file *filp, struct file_lock *fl,
- struct file_lock *conflock)
+posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
+ fl->fl_type = F_UNLCK;
lock_kernel();
for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl))
@@ -679,7 +678,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl,
break;
}
if (cfl) {
- __locks_copy_lock(conflock, cfl);
+ __locks_copy_lock(fl, cfl);
unlock_kernel();
return 1;
}
@@ -801,7 +800,7 @@ out:
return error;
}
-static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
+static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
{
struct file_lock *fl;
struct file_lock *new_fl = NULL;
@@ -1007,6 +1006,7 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
* posix_lock_file - Apply a POSIX-style lock to a file
* @filp: The file to apply the lock to
* @fl: The lock to be applied
+ * @conflock: Place to return a copy of the conflicting lock, if found.
*
* Add a POSIX style lock to a file.
* We merge adjacent & overlapping locks whenever possible.
@@ -1016,26 +1016,12 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
* whether or not a lock was successfully freed by testing the return
* value for -ENOENT.
*/
-int posix_lock_file(struct file *filp, struct file_lock *fl)
-{
- return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, NULL);
-}
-EXPORT_SYMBOL(posix_lock_file);
-
-/**
- * posix_lock_file_conf - Apply a POSIX-style lock to a file
- * @filp: The file to apply the lock to
- * @fl: The lock to be applied
- * @conflock: Place to return a copy of the conflicting lock, if found.
- *
- * Except for the conflock parameter, acts just like posix_lock_file.
- */
-int posix_lock_file_conf(struct file *filp, struct file_lock *fl,
+int posix_lock_file(struct file *filp, struct file_lock *fl,
struct file_lock *conflock)
{
- return __posix_lock_file_conf(filp->f_path.dentry->d_inode, fl, conflock);
+ return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock);
}
-EXPORT_SYMBOL(posix_lock_file_conf);
+EXPORT_SYMBOL(posix_lock_file);
/**
* posix_lock_file_wait - Apply a POSIX-style lock to a file
@@ -1051,7 +1037,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
int error;
might_sleep ();
for (;;) {
- error = posix_lock_file(filp, fl);
+ error = posix_lock_file(filp, fl, NULL);
if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1123,7 +1109,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
fl.fl_end = offset + count - 1;
for (;;) {
- error = __posix_lock_file_conf(inode, &fl, NULL);
+ error = __posix_lock_file(inode, &fl, NULL);
if (error != -EAGAIN)
break;
if (!(fl.fl_flags & FL_SLEEP))
@@ -1611,12 +1597,62 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
return error;
}
+/**
+ * vfs_test_lock - test file byte range lock
+ * @filp: The file to test lock for
+ * @fl: The lock to test
+ * @conf: Place to return a copy of the conflicting lock, if found
+ *
+ * Returns -ERRNO on failure. Indicates presence of conflicting lock by
+ * setting conf->fl_type to something other than F_UNLCK.
+ */
+int vfs_test_lock(struct file *filp, struct file_lock *fl)
+{
+ if (filp->f_op && filp->f_op->lock)
+ return filp->f_op->lock(filp, F_GETLK, fl);
+ posix_test_lock(filp, fl);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vfs_test_lock);
+
+static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
+{
+ flock->l_pid = fl->fl_pid;
+#if BITS_PER_LONG == 32
+ /*
+ * Make sure we can represent the posix lock via
+ * legacy 32bit flock.
+ */
+ if (fl->fl_start > OFFT_OFFSET_MAX)
+ return -EOVERFLOW;
+ if (fl->fl_end != OFFSET_MAX && fl->fl_end > OFFT_OFFSET_MAX)
+ return -EOVERFLOW;
+#endif
+ flock->l_start = fl->fl_start;
+ flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
+ fl->fl_end - fl->fl_start + 1;
+ flock->l_whence = 0;
+ return 0;
+}
+
+#if BITS_PER_LONG == 32
+static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
+{
+ flock->l_pid = fl->fl_pid;
+ flock->l_start = fl->fl_start;
+ flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
+ fl->fl_end - fl->fl_start + 1;
+ flock->l_whence = 0;
+ flock->l_type = fl->fl_type;
+}
+#endif
+
/* Report the first existing lock that would conflict with l.
* This implements the F_GETLK command of fcntl().
*/
int fcntl_getlk(struct file *filp, struct flock __user *l)
{
- struct file_lock *fl, cfl, file_lock;
+ struct file_lock file_lock;
struct flock flock;
int error;
@@ -1631,38 +1667,15 @@ int fcntl_getlk(struct file *filp, struct flock __user *l)
if (error)
goto out;
- if (filp->f_op && filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, &file_lock);
- if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
- file_lock.fl_ops->fl_release_private(&file_lock);
- if (error < 0)
- goto out;
- else
- fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
- } else {
- fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
- }
+ error = vfs_test_lock(filp, &file_lock);
+ if (error)
+ goto out;
- flock.l_type = F_UNLCK;
- if (fl != NULL) {
- flock.l_pid = fl->fl_pid;
-#if BITS_PER_LONG == 32
- /*
- * Make sure we can represent the posix lock via
- * legacy 32bit flock.
- */
- error = -EOVERFLOW;
- if (fl->fl_start > OFFT_OFFSET_MAX)
- goto out;
- if ((fl->fl_end != OFFSET_MAX)
- && (fl->fl_end > OFFT_OFFSET_MAX))
+ flock.l_type = file_lock.fl_type;
+ if (file_lock.fl_type != F_UNLCK) {
+ error = posix_lock_to_flock(&flock, &file_lock);
+ if (error)
goto out;
-#endif
- flock.l_start = fl->fl_start;
- flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
- fl->fl_end - fl->fl_start + 1;
- flock.l_whence = 0;
- flock.l_type = fl->fl_type;
}
error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock)))
@@ -1671,6 +1684,48 @@ out:
return error;
}
+/**
+ * vfs_lock_file - file byte range lock
+ * @filp: The file to apply the lock to
+ * @cmd: type of locking operation (F_SETLK, F_GETLK, etc.)
+ * @fl: The lock to be applied
+ * @conf: Place to return a copy of the conflicting lock, if found.
+ *
+ * A caller that doesn't care about the conflicting lock may pass NULL
+ * as the final argument.
+ *
+ * If the filesystem defines a private ->lock() method, then @conf will
+ * be left unchanged; so a caller that cares should initialize it to
+ * some acceptable default.
+ *
+ * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX
+ * locks, the ->lock() interface may return asynchronously, before the lock has
+ * been granted or denied by the underlying filesystem, if (and only if)
+ * fl_grant is set. Callers expecting ->lock() to return asynchronously
+ * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if)
+ * the request is for a blocking lock. When ->lock() does return asynchronously,
+ * it must return -EINPROGRESS, and call ->fl_grant() when the lock
+ * request completes.
+ * If the request is for non-blocking lock the file system should return
+ * -EINPROGRESS then try to get the lock and call the callback routine with
+ * the result. If the request timed out the callback routine will return a
+ * nonzero return code and the file system should release the lock. The file
+ * system is also responsible to keep a corresponding posix lock when it
+ * grants a lock so the VFS can find out which locks are locally held and do
+ * the correct lock cleanup when required.
+ * The underlying filesystem must not drop the kernel lock or call
+ * ->fl_grant() before returning to the caller with a -EINPROGRESS
+ * return code.
+ */
+int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
+{
+ if (filp->f_op && filp->f_op->lock)
+ return filp->f_op->lock(filp, cmd, fl);
+ else
+ return posix_lock_file(filp, fl, conf);
+}
+EXPORT_SYMBOL_GPL(vfs_lock_file);
+
/* Apply the lock described by l to an open file descriptor.
* This implements both the F_SETLK and F_SETLKW commands of fcntl().
*/
@@ -1733,21 +1788,17 @@ again:
if (error)
goto out;
- if (filp->f_op && filp->f_op->lock != NULL)
- error = filp->f_op->lock(filp, cmd, file_lock);
- else {
- for (;;) {
- error = posix_lock_file(filp, file_lock);
- if ((error != -EAGAIN) || (cmd == F_SETLK))
- break;
- error = wait_event_interruptible(file_lock->fl_wait,
- !file_lock->fl_next);
- if (!error)
- continue;
-
- locks_delete_block(file_lock);
+ for (;;) {
+ error = vfs_lock_file(filp, cmd, file_lock, NULL);
+ if (error != -EAGAIN || cmd == F_SETLK)
break;
- }
+ error = wait_event_interruptible(file_lock->fl_wait,
+ !file_lock->fl_next);
+ if (!error)
+ continue;
+
+ locks_delete_block(file_lock);
+ break;
}
/*
@@ -1770,7 +1821,7 @@ out:
*/
int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
{
- struct file_lock *fl, cfl, file_lock;
+ struct file_lock file_lock;
struct flock64 flock;
int error;
@@ -1785,27 +1836,14 @@ int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
if (error)
goto out;
- if (filp->f_op && filp->f_op->lock) {
- error = filp->f_op->lock(filp, F_GETLK, &file_lock);
- if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private)
- file_lock.fl_ops->fl_release_private(&file_lock);
- if (error < 0)
- goto out;
- else
- fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
- } else {
- fl = (posix_test_lock(filp, &file_lock, &cfl) ? &cfl : NULL);
- }
-
- flock.l_type = F_UNLCK;
- if (fl != NULL) {
- flock.l_pid = fl->fl_pid;
- flock.l_start = fl->fl_start;
- flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
- fl->fl_end - fl->fl_start + 1;
- flock.l_whence = 0;
- flock.l_type = fl->fl_type;
- }
+ error = vfs_test_lock(filp, &file_lock);
+ if (error)
+ goto out;
+
+ flock.l_type = file_lock.fl_type;
+ if (file_lock.fl_type != F_UNLCK)
+ posix_lock_to_flock64(&flock, &file_lock);
+
error = -EFAULT;
if (!copy_to_user(l, &flock, sizeof(flock)))
error = 0;
@@ -1876,21 +1914,17 @@ again:
if (error)
goto out;
- if (filp->f_op && filp->f_op->lock != NULL)
- error = filp->f_op->lock(filp, cmd, file_lock);
- else {
- for (;;) {
- error = posix_lock_file(filp, file_lock);
- if ((error != -EAGAIN) || (cmd == F_SETLK64))
- break;
- error = wait_event_interruptible(file_lock->fl_wait,
- !file_lock->fl_next);
- if (!error)
- continue;
-
- locks_delete_block(file_lock);
+ for (;;) {
+ error = vfs_lock_file(filp, cmd, file_lock, NULL);
+ if (error != -EAGAIN || cmd == F_SETLK64)
break;
- }
+ error = wait_event_interruptible(file_lock->fl_wait,
+ !file_lock->fl_next);
+ if (!error)
+ continue;
+
+ locks_delete_block(file_lock);
+ break;
}
/*
@@ -1935,10 +1969,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
lock.fl_ops = NULL;
lock.fl_lmops = NULL;
- if (filp->f_op && filp->f_op->lock != NULL)
- filp->f_op->lock(filp, F_SETLK, &lock);
- else
- posix_lock_file(filp, &lock);
+ vfs_lock_file(filp, F_SETLK, &lock, NULL);
if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock);
@@ -2015,6 +2046,22 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter)
EXPORT_SYMBOL(posix_unblock_lock);
+/**
+ * vfs_cancel_lock - file byte range unblock lock
+ * @filp: The file to apply the unblock to
+ * @fl: The lock to be unblocked
+ *
+ * Used by lock managers to cancel blocked requests
+ */
+int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
+{
+ if (filp->f_op && filp->f_op->lock)
+ return filp->f_op->lock(filp, F_CANCELLK, fl);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(vfs_cancel_lock);
+
static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
{
struct inode *inode = NULL;
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index cb4cb571fdd..e207cbe7095 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -65,7 +65,6 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n)
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
if (!PageUptodate(page))
goto fail;
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 92e383af370..2f4d43a2a31 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -73,8 +73,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct minix_inode_info *ei = (struct minix_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/mpage.c b/fs/mpage.c
index 692a3e578fc..0fb914fc2ee 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -284,11 +284,9 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages,
}
if (first_hole != blocks_per_page) {
- char *kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + (first_hole << blkbits), 0,
- PAGE_CACHE_SIZE - (first_hole << blkbits));
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, first_hole << blkbits,
+ PAGE_CACHE_SIZE - (first_hole << blkbits),
+ KM_USER0);
if (first_hole == 0) {
SetPageUptodate(page);
unlock_page(page);
@@ -576,14 +574,11 @@ page_is_mapped:
* written out to the file."
*/
unsigned offset = i_size & (PAGE_CACHE_SIZE - 1);
- char *kaddr;
if (page->index > end_index || !offset)
goto confused;
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, PAGE_CACHE_SIZE - offset,
+ KM_USER0);
}
/*
@@ -663,12 +658,7 @@ confused:
/*
* The caller has a ref on the inode, so *mapping is stable
*/
- if (*ret) {
- if (*ret == -ENOSPC)
- set_bit(AS_ENOSPC, &mapping->flags);
- else
- set_bit(AS_EIO, &mapping->flags);
- }
+ mapping_set_error(mapping, *ret);
out:
return bio;
}
@@ -776,14 +766,7 @@ retry:
if (writepage) {
ret = (*writepage)(page, wbc);
- if (ret) {
- if (ret == -ENOSPC)
- set_bit(AS_ENOSPC,
- &mapping->flags);
- else
- set_bit(AS_EIO,
- &mapping->flags);
- }
+ mapping_set_error(mapping, ret);
} else {
bio = __mpage_writepage(bio, page, get_block,
&last_block_in_bio, &ret, wbc,
diff --git a/fs/namei.c b/fs/namei.c
index 880052cadbc..b3780e3fc88 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -22,7 +22,6 @@
#include <linux/quotaops.h>
#include <linux/pagemap.h>
#include <linux/fsnotify.h>
-#include <linux/smp_lock.h>
#include <linux/personality.h>
#include <linux/security.h>
#include <linux/syscalls.h>
@@ -1153,14 +1152,12 @@ static int fastcall do_path_lookup(int dfd, const char *name,
fput_light(file, fput_needed);
}
- current->total_link_count = 0;
- retval = link_path_walk(name, nd);
+
+ retval = path_walk(name, nd);
out:
- if (likely(retval == 0)) {
- if (unlikely(!audit_dummy_context() && nd && nd->dentry &&
+ if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
nd->dentry->d_inode))
audit_inode(name, nd->dentry->d_inode);
- }
out_fail:
return retval;
@@ -1350,17 +1347,6 @@ struct dentry *lookup_one_len_kern(const char *name, struct dentry *base, int le
return __lookup_hash_kern(&this, base, NULL);
}
-/*
- * namei()
- *
- * is used by most simple commands to get the inode of a specified name.
- * Open, link etc use their own routines, but this is enough for things
- * like 'chmod' etc.
- *
- * namei exists in two versions: namei/lnamei. The only difference is
- * that namei follows links, while lnamei does not.
- * SMP-safe
- */
int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
struct nameidata *nd)
{
@@ -2671,19 +2657,9 @@ static char *page_getlink(struct dentry * dentry, struct page **ppage)
struct address_space *mapping = dentry->d_inode->i_mapping;
page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
- goto sync_fail;
- wait_on_page_locked(page);
- if (!PageUptodate(page))
- goto async_fail;
+ return (char*)page;
*ppage = page;
return kmap(page);
-
-async_fail:
- page_cache_release(page);
- return ERR_PTR(-EIO);
-
-sync_fail:
- return (char*)page;
}
int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
diff --git a/fs/namespace.c b/fs/namespace.c
index fd999cab7b5..b696e3a0d18 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -377,6 +377,10 @@ static int show_vfsmnt(struct seq_file *m, void *v)
seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
seq_putc(m, ' ');
mangle(m, mnt->mnt_sb->s_type->name);
+ if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) {
+ seq_putc(m, '.');
+ mangle(m, mnt->mnt_sb->s_subtype);
+ }
seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
if (mnt->mnt_sb->s_flags & fs_infop->flag)
@@ -495,7 +499,7 @@ void release_mounts(struct list_head *head)
{
struct vfsmount *mnt;
while (!list_empty(head)) {
- mnt = list_entry(head->next, struct vfsmount, mnt_hash);
+ mnt = list_first_entry(head, struct vfsmount, mnt_hash);
list_del_init(&mnt->mnt_hash);
if (mnt->mnt_parent != mnt) {
struct dentry *dentry;
@@ -882,6 +886,9 @@ static int do_change_type(struct nameidata *nd, int flag)
int recurse = flag & MS_REC;
int type = flag & ~MS_REC;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
if (nd->dentry != nd->mnt->mnt_root)
return -EINVAL;
@@ -1173,7 +1180,7 @@ static void expire_mount_list(struct list_head *graveyard, struct list_head *mou
while (!list_empty(graveyard)) {
LIST_HEAD(umounts);
- mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire);
+ mnt = list_first_entry(graveyard, struct vfsmount, mnt_expire);
list_del_init(&mnt->mnt_expire);
/* don't do anything if the namespace is dead - all the
@@ -1441,10 +1448,9 @@ dput_out:
* Allocate a new namespace structure and populate it with contents
* copied from the namespace of the passed in task structure.
*/
-struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk,
+static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
struct fs_struct *fs)
{
- struct mnt_namespace *mnt_ns = tsk->nsproxy->mnt_ns;
struct mnt_namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
struct vfsmount *p, *q;
@@ -1509,36 +1515,21 @@ struct mnt_namespace *dup_mnt_ns(struct task_struct *tsk,
return new_ns;
}
-int copy_mnt_ns(int flags, struct task_struct *tsk)
+struct mnt_namespace *copy_mnt_ns(int flags, struct mnt_namespace *ns,
+ struct fs_struct *new_fs)
{
- struct mnt_namespace *ns = tsk->nsproxy->mnt_ns;
struct mnt_namespace *new_ns;
- int err = 0;
-
- if (!ns)
- return 0;
+ BUG_ON(!ns);
get_mnt_ns(ns);
if (!(flags & CLONE_NEWNS))
- return 0;
+ return ns;
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto out;
- }
-
- new_ns = dup_mnt_ns(tsk, tsk->fs);
- if (!new_ns) {
- err = -ENOMEM;
- goto out;
- }
+ new_ns = dup_mnt_ns(ns, new_fs);
- tsk->nsproxy->mnt_ns = new_ns;
-
-out:
put_mnt_ns(ns);
- return err;
+ return new_ns;
}
asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 6b1f6d27099..addfd3147ea 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -17,7 +17,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
#include <linux/ncp_fs.h>
#include "ncplib_kernel.h"
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 7285c94956c..c29f00ad495 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -60,8 +60,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
mutex_init(&ei->open_mutex);
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 2190e6c2792..50c6821bad2 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -27,7 +27,6 @@
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/nfs_idmap.h>
@@ -618,7 +617,8 @@ static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_dat
if (clp->cl_nfsversion == 3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
- server->caps |= NFS_CAP_READDIRPLUS;
+ if (!(data->flags & NFS_MOUNT_NORDIRPLUS))
+ server->caps |= NFS_CAP_READDIRPLUS;
} else {
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
server->namelen = NFS2_MAXNAMLEN;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index cd3469720cb..625d8e5fb39 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -154,6 +154,8 @@ typedef struct {
decode_dirent_t decode;
int plus;
int error;
+ unsigned long timestamp;
+ int timestamp_valid;
} nfs_readdir_descriptor_t;
/* Now we cache directories properly, by stuffing the dirent
@@ -195,6 +197,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
}
goto error;
}
+ desc->timestamp = timestamp;
+ desc->timestamp_valid = 1;
SetPageUptodate(page);
spin_lock(&inode->i_lock);
NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATIME;
@@ -225,6 +229,10 @@ int dir_decode(nfs_readdir_descriptor_t *desc)
if (IS_ERR(p))
return PTR_ERR(p);
desc->ptr = p;
+ if (desc->timestamp_valid)
+ desc->entry->fattr->time_start = desc->timestamp;
+ else
+ desc->entry->fattr->valid &= ~NFS_ATTR_FATTR;
return 0;
}
@@ -316,14 +324,16 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
__FUNCTION__, desc->page_index,
(long long) *desc->dir_cookie);
+ /* If we find the page in the page_cache, we cannot be sure
+ * how fresh the data is, so we will ignore readdir_plus attributes.
+ */
+ desc->timestamp_valid = 0;
page = read_cache_page(inode->i_mapping, desc->page_index,
(filler_t *)nfs_readdir_filler, desc);
if (IS_ERR(page)) {
status = PTR_ERR(page);
goto out;
}
- if (!PageUptodate(page))
- goto read_error;
/* NOTE: Someone else may have changed the READDIRPLUS flag */
desc->page = page;
@@ -337,9 +347,6 @@ int find_dirent_page(nfs_readdir_descriptor_t *desc)
out:
dfprintk(DIRCACHE, "NFS: %s: returns %d\n", __FUNCTION__, status);
return status;
- read_error:
- page_cache_release(page);
- return -EIO;
}
/*
@@ -468,6 +475,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
struct rpc_cred *cred = nfs_file_cred(file);
struct page *page = NULL;
int status;
+ unsigned long timestamp;
dfprintk(DIRCACHE, "NFS: uncached_readdir() searching for cookie %Lu\n",
(unsigned long long)*desc->dir_cookie);
@@ -477,6 +485,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
status = -ENOMEM;
goto out;
}
+ timestamp = jiffies;
desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie,
page,
NFS_SERVER(inode)->dtsize,
@@ -487,6 +496,8 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent,
desc->page = page;
desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */
if (desc->error >= 0) {
+ desc->timestamp = timestamp;
+ desc->timestamp_valid = 1;
if ((status = dir_decode(desc)) == 0)
desc->entry->prev_cookie = *desc->dir_cookie;
} else
@@ -849,6 +860,10 @@ static int nfs_dentry_delete(struct dentry *dentry)
static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
{
nfs_inode_return_delegation(inode);
+ if (S_ISDIR(inode->i_mode))
+ /* drop any readdir cache as it could easily be old */
+ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
lock_kernel();
drop_nlink(inode);
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 2877744cb60..345aa5c0f38 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -41,7 +41,6 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/kref.h>
@@ -54,6 +53,7 @@
#include <asm/uaccess.h>
#include <asm/atomic.h>
+#include "internal.h"
#include "iostat.h"
#define NFSDBG_FACILITY NFSDBG_VFS
@@ -271,7 +271,7 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
bytes = min(rsize,count);
result = -ENOMEM;
- data = nfs_readdata_alloc(pgbase + bytes);
+ data = nfs_readdata_alloc(nfs_page_array_len(pgbase, bytes));
if (unlikely(!data))
break;
@@ -602,7 +602,7 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
bytes = min(wsize,count);
result = -ENOMEM;
- data = nfs_writedata_alloc(pgbase + bytes);
+ data = nfs_writedata_alloc(nfs_page_array_len(pgbase, bytes));
if (unlikely(!data))
break;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 8e66b5a2d49..5eaee6dd040 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -391,17 +391,12 @@ out_swapfile:
static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
{
- struct file_lock cfl;
struct inode *inode = filp->f_mapping->host;
int status = 0;
lock_kernel();
/* Try local locking first */
- if (posix_test_lock(filp, fl, &cfl)) {
- fl->fl_start = cfl.fl_start;
- fl->fl_end = cfl.fl_end;
- fl->fl_type = cfl.fl_type;
- fl->fl_pid = cfl.fl_pid;
+ if (posix_test_lock(filp, fl)) {
goto out;
}
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 6ef268f7c30..234778576f0 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -25,7 +25,6 @@
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
#include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/nfs_idmap.h>
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 44aa9b72657..1e9a915d1fe 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1167,8 +1167,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct nfs_inode *nfsi = (struct nfs_inode *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&nfsi->vfs_inode);
spin_lock_init(&nfsi->req_lock);
INIT_LIST_HEAD(&nfsi->dirty);
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 6610f2b0207..ad2b40db1e6 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -231,3 +231,15 @@ unsigned int nfs_page_length(struct page *page)
}
return 0;
}
+
+/*
+ * Determine the number of pages in an array of length 'len' and
+ * with a base offset of 'base'
+ */
+static inline
+unsigned int nfs_page_array_len(unsigned int base, size_t len)
+{
+ return ((unsigned long)len + (unsigned long)base +
+ PAGE_SIZE - 1) >> PAGE_SHIFT;
+}
+
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index f75fe72b416..ca5a266a314 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -133,13 +133,15 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
#define MNT_dirpath_sz (1 + 256)
#define MNT_fhstatus_sz (1 + 8)
+#define MNT_fhstatus3_sz (1 + 16)
static struct rpc_procinfo mnt_procedures[] = {
[MNTPROC_MNT] = {
.p_proc = MNTPROC_MNT,
.p_encode = (kxdrproc_t) xdr_encode_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus,
- .p_bufsiz = MNT_dirpath_sz << 2,
+ .p_arglen = MNT_dirpath_sz,
+ .p_replen = MNT_fhstatus_sz,
.p_statidx = MNTPROC_MNT,
.p_name = "MOUNT",
},
@@ -150,7 +152,8 @@ static struct rpc_procinfo mnt3_procedures[] = {
.p_proc = MOUNTPROC3_MNT,
.p_encode = (kxdrproc_t) xdr_encode_dirpath,
.p_decode = (kxdrproc_t) xdr_decode_fhstatus3,
- .p_bufsiz = MNT_dirpath_sz << 2,
+ .p_arglen = MNT_dirpath_sz,
+ .p_replen = MNT_fhstatus3_sz,
.p_statidx = MOUNTPROC3_MNT,
.p_name = "MOUNT",
},
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 3be4e72a022..abd9f8b4894 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -687,16 +687,13 @@ nfs_stat_to_errno(int stat)
return nfs_errtbl[i].errno;
}
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
-
#define PROC(proc, argtype, restype, timer) \
[NFSPROC_##proc] = { \
.p_proc = NFSPROC_##proc, \
.p_encode = (kxdrproc_t) nfs_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs_xdr_##restype, \
- .p_bufsiz = MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2, \
+ .p_arglen = NFS_##argtype##_sz, \
+ .p_replen = NFS_##restype##_sz, \
.p_timer = timer, \
.p_statidx = NFSPROC_##proc, \
.p_name = #proc, \
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 7d0371e2bad..45268d6def2 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -16,7 +16,6 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
#include <linux/nfs_mount.h>
#include "iostat.h"
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 0ace092d126..b51df8eb9f0 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -1102,16 +1102,13 @@ nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
}
#endif /* CONFIG_NFS_V3_ACL */
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
-
#define PROC(proc, argtype, restype, timer) \
[NFS3PROC_##proc] = { \
.p_proc = NFS3PROC_##proc, \
.p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
- .p_bufsiz = MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
+ .p_arglen = NFS3_##argtype##_sz, \
+ .p_replen = NFS3_##restype##_sz, \
.p_timer = timer, \
.p_statidx = NFS3PROC_##proc, \
.p_name = #proc, \
@@ -1153,7 +1150,8 @@ static struct rpc_procinfo nfs3_acl_procedures[] = {
.p_proc = ACLPROC3_GETACL,
.p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
.p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
- .p_bufsiz = MAX(ACL3_getaclargs_sz, ACL3_getaclres_sz) << 2,
+ .p_arglen = ACL3_getaclargs_sz,
+ .p_replen = ACL3_getaclres_sz,
.p_timer = 1,
.p_name = "GETACL",
},
@@ -1161,7 +1159,8 @@ static struct rpc_procinfo nfs3_acl_procedures[] = {
.p_proc = ACLPROC3_SETACL,
.p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
.p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
- .p_bufsiz = MAX(ACL3_setaclargs_sz, ACL3_setaclres_sz) << 2,
+ .p_arglen = ACL3_setaclargs_sz,
+ .p_replen = ACL3_setaclres_sz,
.p_timer = 0,
.p_name = "SETACL",
},
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f52cf5c33c6..d6a30e96578 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2647,8 +2647,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
nfs_inode_return_delegation(inode);
buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
- if (ret == 0)
- nfs4_write_cached_acl(inode, buf, buflen);
+ nfs_zap_caches(inode);
return ret;
}
@@ -3018,6 +3017,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
case -NFS4ERR_DENIED:
status = 0;
}
+ request->fl_ops->fl_release_private(request);
out:
up_read(&clp->cl_sem);
return status;
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index f5f4430fb2a..0505ca12403 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -43,7 +43,6 @@
* child task framework of the RPC layer?
*/
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/sunrpc/sched.h>
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index f02d522fd78..b8c28f2380a 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -4546,16 +4546,13 @@ nfs4_stat_to_errno(int stat)
return stat;
}
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
-
#define PROC(proc, argtype, restype) \
[NFSPROC4_CLNT_##proc] = { \
.p_proc = NFSPROC4_COMPOUND, \
.p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs4_xdr_##restype, \
- .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \
+ .p_arglen = NFS4_##argtype##_sz, \
+ .p_replen = NFS4_##restype##_sz, \
.p_statidx = NFSPROC4_CLNT_##proc, \
.p_name = #proc, \
}
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 75f819dc025..49d1008ce1d 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto)
printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
program, version, NIPQUAD(servaddr));
set_sockaddr(&sin, servaddr, 0);
- return rpc_getport_external(&sin, program, version, proto);
+ return rpcb_getport_external(&sin, program, version, proto);
}
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index ca4b1d4ff42..388950118f5 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -17,7 +17,8 @@
#include <linux/nfs_page.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
-#include <linux/writeback.h>
+
+#include "internal.h"
#define NFS_PARANOIA 1
@@ -50,9 +51,7 @@ nfs_page_free(struct nfs_page *p)
* @count: number of bytes to read/write
*
* The page must be locked by the caller. This makes sure we never
- * create two different requests for the same page, and avoids
- * a possible deadlock when we reach the hard limit on the number
- * of dirty pages.
+ * create two different requests for the same page.
* User should ensure it is safe to sleep in this function.
*/
struct nfs_page *
@@ -63,16 +62,12 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
struct nfs_server *server = NFS_SERVER(inode);
struct nfs_page *req;
- /* Deal with hard limits. */
for (;;) {
/* try to allocate the request struct */
req = nfs_page_alloc();
if (req != NULL)
break;
- /* Try to free up at least one request in order to stay
- * below the hard limit
- */
if (signalled() && (server->flags & NFS_MOUNT_INTR))
return ERR_PTR(-ERESTARTSYS);
yield();
@@ -223,124 +218,151 @@ out:
}
/**
- * nfs_coalesce_requests - Split coalesced requests out from a list.
- * @head: source list
- * @dst: destination list
- * @nmax: maximum number of requests to coalesce
- *
- * Moves a maximum of 'nmax' elements from one list to another.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that the RPC credentials are the same.
+ * nfs_pageio_init - initialise a page io descriptor
+ * @desc: pointer to descriptor
+ * @inode: pointer to inode
+ * @doio: pointer to io function
+ * @bsize: io block size
+ * @io_flags: extra parameters for the io function
*/
-int
-nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
- unsigned int nmax)
+void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
+ struct inode *inode,
+ int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+ size_t bsize,
+ int io_flags)
{
- struct nfs_page *req = NULL;
- unsigned int npages = 0;
-
- while (!list_empty(head)) {
- struct nfs_page *prev = req;
-
- req = nfs_list_entry(head->next);
- if (prev) {
- if (req->wb_context->cred != prev->wb_context->cred)
- break;
- if (req->wb_context->lockowner != prev->wb_context->lockowner)
- break;
- if (req->wb_context->state != prev->wb_context->state)
- break;
- if (req->wb_index != (prev->wb_index + 1))
- break;
-
- if (req->wb_pgbase != 0)
- break;
- }
- nfs_list_remove_request(req);
- nfs_list_add_request(req, dst);
- npages++;
- if (req->wb_pgbase + req->wb_bytes != PAGE_CACHE_SIZE)
- break;
- if (npages >= nmax)
- break;
- }
- return npages;
+ INIT_LIST_HEAD(&desc->pg_list);
+ desc->pg_bytes_written = 0;
+ desc->pg_count = 0;
+ desc->pg_bsize = bsize;
+ desc->pg_base = 0;
+ desc->pg_inode = inode;
+ desc->pg_doio = doio;
+ desc->pg_ioflags = io_flags;
+ desc->pg_error = 0;
}
-#define NFS_SCAN_MAXENTRIES 16
/**
- * nfs_scan_dirty - Scan the radix tree for dirty requests
- * @mapping: pointer to address space
- * @wbc: writeback_control structure
- * @dst: Destination list
+ * nfs_can_coalesce_requests - test two requests for compatibility
+ * @prev: pointer to nfs_page
+ * @req: pointer to nfs_page
*
- * Moves elements from one of the inode request lists.
- * If the number of requests is set to 0, the entire address_space
- * starting at index idx_start, is scanned.
- * The requests are *not* checked to ensure that they form a contiguous set.
- * You must be holding the inode's req_lock when calling this function
+ * The nfs_page structures 'prev' and 'req' are compared to ensure that the
+ * page data area they describe is contiguous, and that their RPC
+ * credentials, NFSv4 open state, and lockowners are the same.
+ *
+ * Return 'true' if this is the case, else return 'false'.
*/
-long nfs_scan_dirty(struct address_space *mapping,
- struct writeback_control *wbc,
- struct list_head *dst)
+static int nfs_can_coalesce_requests(struct nfs_page *prev,
+ struct nfs_page *req)
{
- struct nfs_inode *nfsi = NFS_I(mapping->host);
- struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
- struct nfs_page *req;
- pgoff_t idx_start, idx_end;
- long res = 0;
- int found, i;
-
- if (nfsi->ndirty == 0)
+ if (req->wb_context->cred != prev->wb_context->cred)
return 0;
- if (wbc->range_cyclic) {
- idx_start = 0;
- idx_end = ULONG_MAX;
- } else if (wbc->range_end == 0) {
- idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
- idx_end = ULONG_MAX;
- } else {
- idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
- idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
- }
+ if (req->wb_context->lockowner != prev->wb_context->lockowner)
+ return 0;
+ if (req->wb_context->state != prev->wb_context->state)
+ return 0;
+ if (req->wb_index != (prev->wb_index + 1))
+ return 0;
+ if (req->wb_pgbase != 0)
+ return 0;
+ if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE)
+ return 0;
+ return 1;
+}
- for (;;) {
- unsigned int toscan = NFS_SCAN_MAXENTRIES;
+/**
+ * nfs_pageio_do_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
+ struct nfs_page *req)
+{
+ size_t newlen = req->wb_bytes;
- found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
- (void **)&pgvec[0], idx_start, toscan,
- NFS_PAGE_TAG_DIRTY);
+ if (desc->pg_count != 0) {
+ struct nfs_page *prev;
- /* Did we make progress? */
- if (found <= 0)
- break;
+ /*
+ * FIXME: ideally we should be able to coalesce all requests
+ * that are not block boundary aligned, but currently this
+ * is problematic for the case of bsize < PAGE_CACHE_SIZE,
+ * since nfs_flush_multi and nfs_pagein_multi assume you
+ * can have only one struct nfs_page.
+ */
+ if (desc->pg_bsize < PAGE_SIZE)
+ return 0;
+ newlen += desc->pg_count;
+ if (newlen > desc->pg_bsize)
+ return 0;
+ prev = nfs_list_entry(desc->pg_list.prev);
+ if (!nfs_can_coalesce_requests(prev, req))
+ return 0;
+ } else
+ desc->pg_base = req->wb_pgbase;
+ nfs_list_remove_request(req);
+ nfs_list_add_request(req, &desc->pg_list);
+ desc->pg_count = newlen;
+ return 1;
+}
- for (i = 0; i < found; i++) {
- req = pgvec[i];
- if (!wbc->range_cyclic && req->wb_index > idx_end)
- goto out;
+/*
+ * Helper for nfs_pageio_add_request and nfs_pageio_complete
+ */
+static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
+{
+ if (!list_empty(&desc->pg_list)) {
+ int error = desc->pg_doio(desc->pg_inode,
+ &desc->pg_list,
+ nfs_page_array_len(desc->pg_base,
+ desc->pg_count),
+ desc->pg_count,
+ desc->pg_ioflags);
+ if (error < 0)
+ desc->pg_error = error;
+ else
+ desc->pg_bytes_written += desc->pg_count;
+ }
+ if (list_empty(&desc->pg_list)) {
+ desc->pg_count = 0;
+ desc->pg_base = 0;
+ }
+}
- /* Try to lock request and mark it for writeback */
- if (!nfs_set_page_writeback_locked(req))
- goto next;
- radix_tree_tag_clear(&nfsi->nfs_page_tree,
- req->wb_index, NFS_PAGE_TAG_DIRTY);
- nfsi->ndirty--;
- nfs_list_remove_request(req);
- nfs_list_add_request(req, dst);
- res++;
- if (res == LONG_MAX)
- goto out;
-next:
- idx_start = req->wb_index + 1;
- }
+/**
+ * nfs_pageio_add_request - Attempt to coalesce a request into a page list.
+ * @desc: destination io descriptor
+ * @req: request
+ *
+ * Returns true if the request 'req' was successfully coalesced into the
+ * existing list of pages 'desc'.
+ */
+int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+ struct nfs_page *req)
+{
+ while (!nfs_pageio_do_add_request(desc, req)) {
+ nfs_pageio_doio(desc);
+ if (desc->pg_error < 0)
+ return 0;
}
-out:
- WARN_ON ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty));
- return res;
+ return 1;
}
/**
+ * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
+ * @desc: pointer to io descriptor
+ */
+void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
+{
+ nfs_pageio_doio(desc);
+}
+
+#define NFS_SCAN_MAXENTRIES 16
+/**
* nfs_scan_list - Scan a list for matching requests
* @nfsi: NFS inode
* @head: One of the NFS inode request lists
@@ -355,12 +377,12 @@ out:
* You must be holding the inode's req_lock when calling this function
*/
int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
- struct list_head *dst, unsigned long idx_start,
+ struct list_head *dst, pgoff_t idx_start,
unsigned int npages)
{
struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
struct nfs_page *req;
- unsigned long idx_end;
+ pgoff_t idx_end;
int found, i;
int res;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 1dcf56de948..7be0ee2782c 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -43,7 +43,6 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
-#include <linux/smp_lock.h>
#include "internal.h"
#define NFSDBG_FACILITY NFSDBG_PROC
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 6ab4d5a9edf..9a55807b2a7 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -27,7 +27,8 @@
#define NFSDBG_FACILITY NFSDBG_PAGECACHE
-static int nfs_pagein_one(struct list_head *, struct inode *);
+static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int);
+static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int);
static const struct rpc_call_ops nfs_read_partial_ops;
static const struct rpc_call_ops nfs_read_full_ops;
@@ -36,9 +37,8 @@ static mempool_t *nfs_rdata_mempool;
#define MIN_POOL_READ (32)
-struct nfs_read_data *nfs_readdata_alloc(size_t len)
+struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount)
{
- unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS);
if (p) {
@@ -133,7 +133,10 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
nfs_list_add_request(new, &one_request);
- nfs_pagein_one(&one_request, inode);
+ if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
+ nfs_pagein_multi(inode, &one_request, 1, len, 0);
+ else
+ nfs_pagein_one(inode, &one_request, 1, len, 0);
return 0;
}
@@ -230,7 +233,7 @@ static void nfs_execute_read(struct nfs_read_data *data)
* won't see the new data until our attribute cache is updated. This is more
* or less conventional NFS client behavior.
*/
-static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
+static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
{
struct nfs_page *req = nfs_list_entry(head->next);
struct page *page = req->wb_page;
@@ -242,11 +245,11 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
nfs_list_remove_request(req);
- nbytes = req->wb_bytes;
+ nbytes = count;
do {
size_t len = min(nbytes,rsize);
- data = nfs_readdata_alloc(len);
+ data = nfs_readdata_alloc(1);
if (!data)
goto out_bad;
INIT_LIST_HEAD(&data->pages);
@@ -258,23 +261,19 @@ static int nfs_pagein_multi(struct list_head *head, struct inode *inode)
ClearPageError(page);
offset = 0;
- nbytes = req->wb_bytes;
+ nbytes = count;
do {
data = list_entry(list.next, struct nfs_read_data, pages);
list_del_init(&data->pages);
data->pagevec[0] = page;
- if (nbytes > rsize) {
- nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
- rsize, offset);
- offset += rsize;
- nbytes -= rsize;
- } else {
- nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
- nbytes, offset);
- nbytes = 0;
- }
+ if (nbytes < rsize)
+ rsize = nbytes;
+ nfs_read_rpcsetup(req, data, &nfs_read_partial_ops,
+ rsize, offset);
+ offset += rsize;
+ nbytes -= rsize;
nfs_execute_read(data);
} while (nbytes != 0);
@@ -291,30 +290,24 @@ out_bad:
return -ENOMEM;
}
-static int nfs_pagein_one(struct list_head *head, struct inode *inode)
+static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags)
{
struct nfs_page *req;
struct page **pages;
struct nfs_read_data *data;
- unsigned int count;
- if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE)
- return nfs_pagein_multi(head, inode);
-
- data = nfs_readdata_alloc(NFS_SERVER(inode)->rsize);
+ data = nfs_readdata_alloc(npages);
if (!data)
goto out_bad;
INIT_LIST_HEAD(&data->pages);
pages = data->pagevec;
- count = 0;
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
ClearPageError(req->wb_page);
*pages++ = req->wb_page;
- count += req->wb_bytes;
}
req = nfs_list_entry(data->pages.next);
@@ -327,28 +320,6 @@ out_bad:
return -ENOMEM;
}
-static int
-nfs_pagein_list(struct list_head *head, int rpages)
-{
- LIST_HEAD(one_request);
- struct nfs_page *req;
- int error = 0;
- unsigned int pages = 0;
-
- while (!list_empty(head)) {
- pages += nfs_coalesce_requests(head, &one_request, rpages);
- req = nfs_list_entry(one_request.next);
- error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
- if (error < 0)
- break;
- }
- if (error >= 0)
- return pages;
-
- nfs_async_read_error(head);
- return error;
-}
-
/*
* This is the callback from RPC telling us whether a reply was
* received or some error occurred (timeout or socket shutdown).
@@ -538,7 +509,7 @@ out_error:
}
struct nfs_readdesc {
- struct list_head *head;
+ struct nfs_pageio_descriptor *pgio;
struct nfs_open_context *ctx;
};
@@ -562,19 +533,21 @@ readpage_async_filler(void *data, struct page *page)
}
if (len < PAGE_CACHE_SIZE)
memclear_highpage_flush(page, len, PAGE_CACHE_SIZE - len);
- nfs_list_add_request(new, desc->head);
+ nfs_pageio_add_request(desc->pgio, new);
return 0;
}
int nfs_readpages(struct file *filp, struct address_space *mapping,
struct list_head *pages, unsigned nr_pages)
{
- LIST_HEAD(head);
+ struct nfs_pageio_descriptor pgio;
struct nfs_readdesc desc = {
- .head = &head,
+ .pgio = &pgio,
};
struct inode *inode = mapping->host;
struct nfs_server *server = NFS_SERVER(inode);
+ size_t rsize = server->rsize;
+ unsigned long npages;
int ret = -ESTALE;
dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
@@ -593,13 +566,16 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
} else
desc.ctx = get_nfs_open_context((struct nfs_open_context *)
filp->private_data);
+ if (rsize < PAGE_CACHE_SIZE)
+ nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0);
+ else
+ nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0);
+
ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
- if (!list_empty(&head)) {
- int err = nfs_pagein_list(&head, server->rpages);
- if (!ret)
- nfs_add_stats(inode, NFSIOS_READPAGES, err);
- ret = err;
- }
+
+ nfs_pageio_complete(&pgio);
+ npages = (pgio.pg_bytes_written + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ nfs_add_stats(inode, NFSIOS_READPAGES, npages);
put_nfs_open_context(desc.ctx);
out:
return ret;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index f1eae44b9a1..ca20d3cc260 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -204,9 +204,9 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
lock_kernel();
error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
- buf->f_type = NFS_SUPER_MAGIC;
if (error < 0)
goto out_err;
+ buf->f_type = NFS_SUPER_MAGIC;
/*
* Current versions of glibc do not correctly handle the
@@ -233,15 +233,14 @@ static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_ffree = res.afiles;
buf->f_namelen = server->namelen;
- out:
+
unlock_kernel();
return 0;
out_err:
dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
- buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
- goto out;
-
+ unlock_kernel();
+ return error;
}
/*
@@ -291,6 +290,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", "" },
{ NFS_MOUNT_NOACL, ",noacl", "" },
+ { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
{ 0, NULL, NULL }
};
const struct proc_nfs_info *nfs_infop;
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index f4a0548b9ce..83e865a16ad 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -22,7 +22,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/namei.h>
/* Symlink caching in the page cache is even more simplistic
@@ -61,15 +60,9 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
err = page;
goto read_failed;
}
- if (!PageUptodate(page)) {
- err = ERR_PTR(-EIO);
- goto getlink_read_error;
- }
nd_set_link(nd, kmap(page));
return page;
-getlink_read_error:
- page_cache_release(page);
read_failed:
nd_set_link(nd, err);
return NULL;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 79755894174..de92b9509d9 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -21,7 +21,6 @@
#include <linux/backing-dev.h>
#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
#include "delegation.h"
#include "internal.h"
@@ -38,7 +37,8 @@
static struct nfs_page * nfs_update_request(struct nfs_open_context*,
struct page *,
unsigned int, unsigned int);
-static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how);
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
+ struct inode *inode, int ioflags);
static const struct rpc_call_ops nfs_write_partial_ops;
static const struct rpc_call_ops nfs_write_full_ops;
static const struct rpc_call_ops nfs_commit_ops;
@@ -71,9 +71,8 @@ void nfs_commit_free(struct nfs_write_data *wdata)
call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free);
}
-struct nfs_write_data *nfs_writedata_alloc(size_t len)
+struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
{
- unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
if (p) {
@@ -139,7 +138,7 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c
{
struct inode *inode = page->mapping->host;
loff_t end, i_size = i_size_read(inode);
- unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
+ pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
if (i_size > 0 && page->index < end_index)
return;
@@ -201,7 +200,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
static int wb_priority(struct writeback_control *wbc)
{
if (wbc->for_reclaim)
- return FLUSH_HIGHPRI;
+ return FLUSH_HIGHPRI | FLUSH_STABLE;
if (wbc->for_kupdate)
return FLUSH_LOWPRI;
return 0;
@@ -225,7 +224,7 @@ static int nfs_set_page_writeback(struct page *page)
struct inode *inode = page->mapping->host;
struct nfs_server *nfss = NFS_SERVER(inode);
- if (atomic_inc_return(&nfss->writeback) >
+ if (atomic_long_inc_return(&nfss->writeback) >
NFS_CONGESTION_ON_THRESH)
set_bdi_congested(&nfss->backing_dev_info, WRITE);
}
@@ -238,7 +237,7 @@ static void nfs_end_page_writeback(struct page *page)
struct nfs_server *nfss = NFS_SERVER(inode);
end_page_writeback(page);
- if (atomic_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) {
+ if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) {
clear_bdi_congested(&nfss->backing_dev_info, WRITE);
congestion_end(WRITE);
}
@@ -251,7 +250,8 @@ static void nfs_end_page_writeback(struct page *page)
* was not tagged.
* May also return an error if the user signalled nfs_wait_on_request().
*/
-static int nfs_page_mark_flush(struct page *page)
+static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
+ struct page *page)
{
struct nfs_page *req;
struct nfs_inode *nfsi = NFS_I(page->mapping->host);
@@ -273,6 +273,8 @@ static int nfs_page_mark_flush(struct page *page)
* request as dirty (in which case we don't care).
*/
spin_unlock(req_lock);
+ /* Prevent deadlock! */
+ nfs_pageio_complete(pgio);
ret = nfs_wait_on_request(req);
nfs_release_request(req);
if (ret != 0)
@@ -283,21 +285,18 @@ static int nfs_page_mark_flush(struct page *page)
/* This request is marked for commit */
spin_unlock(req_lock);
nfs_unlock_request(req);
+ nfs_pageio_complete(pgio);
return 1;
}
- if (nfs_set_page_writeback(page) == 0) {
- nfs_list_remove_request(req);
- /* add the request to the inode's dirty list. */
- radix_tree_tag_set(&nfsi->nfs_page_tree,
- req->wb_index, NFS_PAGE_TAG_DIRTY);
- nfs_list_add_request(req, &nfsi->dirty);
- nfsi->ndirty++;
- spin_unlock(req_lock);
- __mark_inode_dirty(page->mapping->host, I_DIRTY_PAGES);
- } else
+ if (nfs_set_page_writeback(page) != 0) {
spin_unlock(req_lock);
+ BUG();
+ }
+ radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
+ NFS_PAGE_TAG_WRITEBACK);
ret = test_bit(PG_NEED_FLUSH, &req->wb_flags);
- nfs_unlock_request(req);
+ spin_unlock(req_lock);
+ nfs_pageio_add_request(pgio, req);
return ret;
}
@@ -306,6 +305,7 @@ static int nfs_page_mark_flush(struct page *page)
*/
static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc)
{
+ struct nfs_pageio_descriptor mypgio, *pgio;
struct nfs_open_context *ctx;
struct inode *inode = page->mapping->host;
unsigned offset;
@@ -314,7 +314,14 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
- err = nfs_page_mark_flush(page);
+ if (wbc->for_writepages)
+ pgio = wbc->fs_private;
+ else {
+ nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc));
+ pgio = &mypgio;
+ }
+
+ err = nfs_page_async_flush(pgio, page);
if (err <= 0)
goto out;
err = 0;
@@ -331,12 +338,12 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
put_nfs_open_context(ctx);
if (err != 0)
goto out;
- err = nfs_page_mark_flush(page);
+ err = nfs_page_async_flush(pgio, page);
if (err > 0)
err = 0;
out:
if (!wbc->for_writepages)
- nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc));
+ nfs_pageio_complete(pgio);
return err;
}
@@ -352,20 +359,20 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
struct inode *inode = mapping->host;
+ struct nfs_pageio_descriptor pgio;
int err;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES);
+ nfs_pageio_init_write(&pgio, inode, wb_priority(wbc));
+ wbc->fs_private = &pgio;
err = generic_writepages(mapping, wbc);
+ nfs_pageio_complete(&pgio);
if (err)
return err;
- err = nfs_flush_mapping(mapping, wbc, wb_priority(wbc));
- if (err < 0)
- goto out;
- nfs_add_stats(inode, NFSIOS_WRITEPAGES, err);
- err = 0;
-out:
- return err;
+ if (pgio.pg_error)
+ return pgio.pg_error;
+ return 0;
}
/*
@@ -503,11 +510,11 @@ int nfs_reschedule_unstable_write(struct nfs_page *req)
*
* Interruptible by signals only if mounted with intr flag.
*/
-static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_start, unsigned int npages)
+static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_page *req;
- unsigned long idx_end, next;
+ pgoff_t idx_end, next;
unsigned int res = 0;
int error;
@@ -536,18 +543,6 @@ static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_st
return res;
}
-static void nfs_cancel_dirty_list(struct list_head *head)
-{
- struct nfs_page *req;
- while(!list_empty(head)) {
- req = nfs_list_entry(head->next);
- nfs_list_remove_request(req);
- nfs_end_page_writeback(req->wb_page);
- nfs_inode_remove_request(req);
- nfs_clear_page_writeback(req);
- }
-}
-
static void nfs_cancel_commit_list(struct list_head *head)
{
struct nfs_page *req;
@@ -574,7 +569,7 @@ static void nfs_cancel_commit_list(struct list_head *head)
* The requests are *not* checked to ensure that they form a contiguous set.
*/
static int
-nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
{
struct nfs_inode *nfsi = NFS_I(inode);
int res = 0;
@@ -588,40 +583,12 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st
return res;
}
#else
-static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
+static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages)
{
return 0;
}
#endif
-static int nfs_wait_on_write_congestion(struct address_space *mapping)
-{
- struct inode *inode = mapping->host;
- struct backing_dev_info *bdi = mapping->backing_dev_info;
- int ret = 0;
-
- might_sleep();
-
- if (!bdi_write_congested(bdi))
- return 0;
-
- nfs_inc_stats(inode, NFSIOS_CONGESTIONWAIT);
-
- do {
- struct rpc_clnt *clnt = NFS_CLIENT(inode);
- sigset_t oldset;
-
- rpc_clnt_sigmask(clnt, &oldset);
- ret = congestion_wait_interruptible(WRITE, HZ/10);
- rpc_clnt_sigunmask(clnt, &oldset);
- if (ret == -ERESTARTSYS)
- break;
- ret = 0;
- } while (bdi_write_congested(bdi));
-
- return ret;
-}
-
/*
* Try to update any existing write request, or create one if there is none.
* In order to match, the request's credentials must match those of
@@ -636,12 +603,10 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
struct inode *inode = mapping->host;
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_page *req, *new = NULL;
- unsigned long rqend, end;
+ pgoff_t rqend, end;
end = offset + bytes;
- if (nfs_wait_on_write_congestion(mapping))
- return ERR_PTR(-ERESTARTSYS);
for (;;) {
/* Loop over all inode entries and see if we find
* A request for the page we wish to update
@@ -865,7 +830,7 @@ static void nfs_execute_write(struct nfs_write_data *data)
* Generate multiple small requests to write out a single
* contiguous dirty area on one page.
*/
-static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
+static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
{
struct nfs_page *req = nfs_list_entry(head->next);
struct page *page = req->wb_page;
@@ -877,11 +842,11 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
nfs_list_remove_request(req);
- nbytes = req->wb_bytes;
+ nbytes = count;
do {
size_t len = min(nbytes, wsize);
- data = nfs_writedata_alloc(len);
+ data = nfs_writedata_alloc(1);
if (!data)
goto out_bad;
list_add(&data->pages, &list);
@@ -892,23 +857,19 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how)
ClearPageError(page);
offset = 0;
- nbytes = req->wb_bytes;
+ nbytes = count;
do {
data = list_entry(list.next, struct nfs_write_data, pages);
list_del_init(&data->pages);
data->pagevec[0] = page;
- if (nbytes > wsize) {
- nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
- wsize, offset, how);
- offset += wsize;
- nbytes -= wsize;
- } else {
- nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
- nbytes, offset, how);
- nbytes = 0;
- }
+ if (nbytes < wsize)
+ wsize = nbytes;
+ nfs_write_rpcsetup(req, data, &nfs_write_partial_ops,
+ wsize, offset, how);
+ offset += wsize;
+ nbytes -= wsize;
nfs_execute_write(data);
} while (nbytes != 0);
@@ -934,26 +895,23 @@ out_bad:
* This is the case if nfs_updatepage detects a conflicting request
* that has been written but not committed.
*/
-static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
+static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how)
{
struct nfs_page *req;
struct page **pages;
struct nfs_write_data *data;
- unsigned int count;
- data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize);
+ data = nfs_writedata_alloc(npages);
if (!data)
goto out_bad;
pages = data->pagevec;
- count = 0;
while (!list_empty(head)) {
req = nfs_list_entry(head->next);
nfs_list_remove_request(req);
nfs_list_add_request(req, &data->pages);
ClearPageError(req->wb_page);
*pages++ = req->wb_page;
- count += req->wb_bytes;
}
req = nfs_list_entry(data->pages.next);
@@ -973,40 +931,15 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how)
return -ENOMEM;
}
-static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how)
+static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
+ struct inode *inode, int ioflags)
{
- LIST_HEAD(one_request);
- int (*flush_one)(struct inode *, struct list_head *, int);
- struct nfs_page *req;
- int wpages = NFS_SERVER(inode)->wpages;
int wsize = NFS_SERVER(inode)->wsize;
- int error;
- flush_one = nfs_flush_one;
if (wsize < PAGE_CACHE_SIZE)
- flush_one = nfs_flush_multi;
- /* For single writes, FLUSH_STABLE is more efficient */
- if (npages <= wpages && npages == NFS_I(inode)->npages
- && nfs_list_entry(head->next)->wb_bytes <= wsize)
- how |= FLUSH_STABLE;
-
- do {
- nfs_coalesce_requests(head, &one_request, wpages);
- req = nfs_list_entry(one_request.next);
- error = flush_one(inode, &one_request, how);
- if (error < 0)
- goto out_err;
- } while (!list_empty(head));
- return 0;
-out_err:
- while (!list_empty(head)) {
- req = nfs_list_entry(head->next);
- nfs_list_remove_request(req);
- nfs_redirty_request(req);
- nfs_end_page_writeback(req->wb_page);
- nfs_clear_page_writeback(req);
- }
- return error;
+ nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags);
+ else
+ nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags);
}
/*
@@ -1330,31 +1263,7 @@ static const struct rpc_call_ops nfs_commit_ops = {
.rpc_call_done = nfs_commit_done,
.rpc_release = nfs_commit_release,
};
-#else
-static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how)
-{
- return 0;
-}
-#endif
-
-static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how)
-{
- struct nfs_inode *nfsi = NFS_I(mapping->host);
- LIST_HEAD(head);
- long res;
-
- spin_lock(&nfsi->req_lock);
- res = nfs_scan_dirty(mapping, wbc, &head);
- spin_unlock(&nfsi->req_lock);
- if (res) {
- int error = nfs_flush_list(mapping->host, &head, res, how);
- if (error < 0)
- return error;
- }
- return res;
-}
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
int nfs_commit_inode(struct inode *inode, int how)
{
struct nfs_inode *nfsi = NFS_I(inode);
@@ -1371,13 +1280,18 @@ int nfs_commit_inode(struct inode *inode, int how)
}
return res;
}
+#else
+static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how)
+{
+ return 0;
+}
#endif
long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how)
{
struct inode *inode = mapping->host;
struct nfs_inode *nfsi = NFS_I(inode);
- unsigned long idx_start, idx_end;
+ pgoff_t idx_start, idx_end;
unsigned int npages = 0;
LIST_HEAD(head);
int nocommit = how & FLUSH_NOCOMMIT;
@@ -1390,41 +1304,24 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr
idx_start = wbc->range_start >> PAGE_CACHE_SHIFT;
idx_end = wbc->range_end >> PAGE_CACHE_SHIFT;
if (idx_end > idx_start) {
- unsigned long l_npages = 1 + idx_end - idx_start;
+ pgoff_t l_npages = 1 + idx_end - idx_start;
npages = l_npages;
if (sizeof(npages) != sizeof(l_npages) &&
- (unsigned long)npages != l_npages)
+ (pgoff_t)npages != l_npages)
npages = 0;
}
}
how &= ~FLUSH_NOCOMMIT;
spin_lock(&nfsi->req_lock);
do {
- wbc->pages_skipped = 0;
ret = nfs_wait_on_requests_locked(inode, idx_start, npages);
if (ret != 0)
continue;
- pages = nfs_scan_dirty(mapping, wbc, &head);
- if (pages != 0) {
- spin_unlock(&nfsi->req_lock);
- if (how & FLUSH_INVALIDATE) {
- nfs_cancel_dirty_list(&head);
- ret = pages;
- } else
- ret = nfs_flush_list(inode, &head, pages, how);
- spin_lock(&nfsi->req_lock);
- continue;
- }
- if (wbc->pages_skipped != 0)
- continue;
if (nocommit)
break;
pages = nfs_scan_commit(inode, &head, idx_start, npages);
- if (pages == 0) {
- if (wbc->pages_skipped != 0)
- continue;
+ if (pages == 0)
break;
- }
if (how & FLUSH_INVALIDATE) {
spin_unlock(&nfsi->req_lock);
nfs_cancel_commit_list(&head);
@@ -1456,7 +1353,7 @@ int nfs_wb_all(struct inode *inode)
};
int ret;
- ret = generic_writepages(mapping, &wbc);
+ ret = nfs_writepages(mapping, &wbc);
if (ret < 0)
goto out;
ret = nfs_sync_mapping_wait(mapping, &wbc, 0);
@@ -1479,11 +1376,9 @@ int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, lo
};
int ret;
- if (!(how & FLUSH_NOWRITEPAGE)) {
- ret = generic_writepages(mapping, &wbc);
- if (ret < 0)
- goto out;
- }
+ ret = nfs_writepages(mapping, &wbc);
+ if (ret < 0)
+ goto out;
ret = nfs_sync_mapping_wait(mapping, &wbc, how);
if (ret >= 0)
return 0;
@@ -1506,7 +1401,7 @@ int nfs_wb_page_priority(struct inode *inode, struct page *page, int how)
int ret;
BUG_ON(!PageLocked(page));
- if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) {
+ if (clear_page_dirty_for_io(page)) {
ret = nfs_writepage_locked(page, &wbc);
if (ret < 0)
goto out;
@@ -1531,10 +1426,18 @@ int nfs_wb_page(struct inode *inode, struct page* page)
int nfs_set_page_dirty(struct page *page)
{
- spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
+ struct address_space *mapping = page->mapping;
+ struct inode *inode;
+ spinlock_t *req_lock;
struct nfs_page *req;
int ret;
+ if (!mapping)
+ goto out_raced;
+ inode = mapping->host;
+ if (!inode)
+ goto out_raced;
+ req_lock = &NFS_I(inode)->req_lock;
spin_lock(req_lock);
req = nfs_page_find_request_locked(page);
if (req != NULL) {
@@ -1547,6 +1450,8 @@ int nfs_set_page_dirty(struct page *page)
ret = __set_page_dirty_nobuffers(page);
spin_unlock(req_lock);
return ret;
+out_raced:
+ return !TestSetPageDirty(page);
}
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index ce341dc76d5..9b118ee2019 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -11,4 +11,3 @@ nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
nfs4acl.o nfs4callback.o nfs4recover.o
-nfsd-objs := $(nfsd-y)
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 6f24768272a..79bd03b8bbf 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -469,6 +469,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
nd.dentry = NULL;
exp.ex_path = NULL;
+ /* fs locations */
+ exp.ex_fslocs.locations = NULL;
+ exp.ex_fslocs.locations_count = 0;
+ exp.ex_fslocs.migrated = 0;
+
+ exp.ex_uuid = NULL;
+
if (mesg[mlen-1] != '\n')
return -EINVAL;
mesg[mlen-1] = 0;
@@ -509,13 +516,6 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
if (exp.h.expiry_time == 0)
goto out;
- /* fs locations */
- exp.ex_fslocs.locations = NULL;
- exp.ex_fslocs.locations_count = 0;
- exp.ex_fslocs.migrated = 0;
-
- exp.ex_uuid = NULL;
-
/* flags */
err = get_int(&mesg, &an_int);
if (err == -ENOENT)
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 7f5bad0393b..eac82830bfd 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -177,7 +177,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
if (max_blocksize < resp->count)
resp->count = max_blocksize;
- svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
+ svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
fh_copy(&resp->fh, &argp->fh);
nfserr = nfsd_read(rqstp, &resp->fh, NULL,
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 7e4bb0af24d..10f6e7dcf63 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -239,7 +239,7 @@ static __be32 *
encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct dentry *dentry = fhp->fh_dentry;
- if (dentry && dentry->d_inode != NULL) {
+ if (dentry && dentry->d_inode) {
int err;
struct kstat stat;
@@ -300,9 +300,9 @@ int
nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_sattrargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_sattr3(p, &args->attrs)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = decode_sattr3(p, &args->attrs);
if ((args->check_guard = ntohl(*p++)) != 0) {
struct timespec time;
@@ -343,9 +343,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
int v,pn;
u32 max_blocksize = svc_max_payload(rqstp);
- if (!(p = decode_fh(p, &args->fh))
- || !(p = xdr_decode_hyper(p, &args->offset)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = xdr_decode_hyper(p, &args->offset);
len = args->count = ntohl(*p++);
@@ -369,28 +369,44 @@ int
nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_writeargs *args)
{
- unsigned int len, v, hdr;
+ unsigned int len, v, hdr, dlen;
u32 max_blocksize = svc_max_payload(rqstp);
- if (!(p = decode_fh(p, &args->fh))
- || !(p = xdr_decode_hyper(p, &args->offset)))
+ if (!(p = decode_fh(p, &args->fh)))
return 0;
+ p = xdr_decode_hyper(p, &args->offset);
args->count = ntohl(*p++);
args->stable = ntohl(*p++);
len = args->len = ntohl(*p++);
+ /*
+ * The count must equal the amount of data passed.
+ */
+ if (args->count != args->len)
+ return 0;
+ /*
+ * Check to make sure that we got the right number of
+ * bytes.
+ */
hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
- if (rqstp->rq_arg.len < hdr ||
- rqstp->rq_arg.len - hdr < len)
+ dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+ - hdr;
+ /*
+ * Round the length of the data which was specified up to
+ * the next multiple of XDR units and then compare that
+ * against the length which was actually received.
+ */
+ if (dlen != XDR_QUADLEN(len)*4)
return 0;
+ if (args->count > max_blocksize) {
+ args->count = max_blocksize;
+ len = args->len = max_blocksize;
+ }
rqstp->rq_vec[0].iov_base = (void*)p;
rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
-
- if (len > max_blocksize)
- len = max_blocksize;
- v= 0;
+ v = 0;
while (len > rqstp->rq_vec[v].iov_len) {
len -= rqstp->rq_vec[v].iov_len;
v++;
@@ -398,9 +414,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
rqstp->rq_vec[v].iov_len = PAGE_SIZE;
}
rqstp->rq_vec[v].iov_len = len;
- args->vlen = v+1;
-
- return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
+ args->vlen = v + 1;
+ return 1;
}
int
@@ -414,8 +429,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
switch (args->createmode = ntohl(*p++)) {
case NFS3_CREATE_UNCHECKED:
case NFS3_CREATE_GUARDED:
- if (!(p = decode_sattr3(p, &args->attrs)))
- return 0;
+ p = decode_sattr3(p, &args->attrs);
break;
case NFS3_CREATE_EXCLUSIVE:
args->verf = p;
@@ -431,10 +445,10 @@ int
nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_createargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len))
- || !(p = decode_sattr3(p, &args->attrs)))
+ if (!(p = decode_fh(p, &args->fh)) ||
+ !(p = decode_filename(p, &args->name, &args->len)))
return 0;
+ p = decode_sattr3(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
@@ -448,11 +462,12 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
char *old, *new;
struct kvec *vec;
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_sattr3(p, &args->attrs))
+ if (!(p = decode_fh(p, &args->ffh)) ||
+ !(p = decode_filename(p, &args->fname, &args->flen))
)
return 0;
+ p = decode_sattr3(p, &args->attrs);
+
/* now decode the pathname, which might be larger than the first page.
* As we have to check for nul's anyway, we copy it into a new page
* This page appears in the rq_res.pages list, but as pages_len is always
@@ -502,10 +517,8 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
args->ftype = ntohl(*p++);
if (args->ftype == NF3BLK || args->ftype == NF3CHR
- || args->ftype == NF3SOCK || args->ftype == NF3FIFO) {
- if (!(p = decode_sattr3(p, &args->attrs)))
- return 0;
- }
+ || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
+ p = decode_sattr3(p, &args->attrs);
if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
args->major = ntohl(*p++);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 673a53c014a..cc3b7badd48 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -137,7 +137,6 @@ struct ace_container {
static short ace2type(struct nfs4_ace *);
static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
unsigned int);
-void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
struct nfs4_acl *
nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
@@ -785,21 +784,6 @@ nfs4_acl_new(int n)
return acl;
}
-void
-nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
- int whotype, uid_t who)
-{
- struct nfs4_ace *ace = acl->aces + acl->naces;
-
- ace->type = type;
- ace->flag = flag;
- ace->access_mask = access_mask;
- ace->whotype = whotype;
- ace->who = who;
-
- acl->naces++;
-}
-
static struct {
char *string;
int stringlen;
@@ -851,6 +835,5 @@ nfs4_acl_write_who(int who, char *p)
}
EXPORT_SYMBOL(nfs4_acl_new);
-EXPORT_SYMBOL(nfs4_acl_add_ace);
EXPORT_SYMBOL(nfs4_acl_get_whotype);
EXPORT_SYMBOL(nfs4_acl_write_who);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index fb14d68eaca..32ffea033c7 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -315,16 +315,13 @@ out:
/*
* RPC procedure tables
*/
-#ifndef MAX
-# define MAX(a, b) (((a) > (b))? (a) : (b))
-#endif
-
#define PROC(proc, call, argtype, restype) \
[NFSPROC4_CLNT_##proc] = { \
.p_proc = NFSPROC4_CB_##call, \
.p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \
.p_decode = (kxdrproc_t) nfs4_xdr_##restype, \
- .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \
+ .p_arglen = NFS4_##argtype##_sz, \
+ .p_replen = NFS4_##restype##_sz, \
.p_statidx = NFSPROC4_CB_##call, \
.p_name = #proc, \
}
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index e4a83d727af..45aa21ce678 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -46,7 +46,6 @@
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_page.h>
-#include <linux/smp_lock.h>
#include <linux/sunrpc/cache.h>
#include <linux/nfsd_idmap.h>
#include <linux/list.h>
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index af360705e55..3cc8ce422ab 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -50,6 +50,7 @@
#include <linux/nfsd/xdr4.h>
#include <linux/namei.h>
#include <linux/mutex.h>
+#include <linux/lockd/bind.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -1325,8 +1326,6 @@ do_recall(void *__dp)
{
struct nfs4_delegation *dp = __dp;
- daemonize("nfsv4-recall");
-
nfsd4_cb_recall(dp);
return 0;
}
@@ -2657,6 +2656,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct file_lock conflock;
__be32 status = 0;
unsigned int strhashval;
+ unsigned int cmd;
int err;
dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
@@ -2739,10 +2739,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
case NFS4_READ_LT:
case NFS4_READW_LT:
file_lock.fl_type = F_RDLCK;
+ cmd = F_SETLK;
break;
case NFS4_WRITE_LT:
case NFS4_WRITEW_LT:
file_lock.fl_type = F_WRLCK;
+ cmd = F_SETLK;
break;
default:
status = nfserr_inval;
@@ -2769,9 +2771,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* XXX?: Just to divert the locks_release_private at the start of
* locks_copy_lock: */
- conflock.fl_ops = NULL;
- conflock.fl_lmops = NULL;
- err = posix_lock_file_conf(filp, &file_lock, &conflock);
+ locks_init_lock(&conflock);
+ err = vfs_lock_file(filp, cmd, &file_lock, &conflock);
switch (-err) {
case 0: /* success! */
update_stateid(&lock_stp->st_stateid);
@@ -2788,7 +2789,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfserr_deadlock;
break;
default:
- dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err);
+ dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
status = nfserr_resource;
break;
}
@@ -2813,7 +2814,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct inode *inode;
struct file file;
struct file_lock file_lock;
- struct file_lock conflock;
+ int error;
__be32 status;
if (nfs4_in_grace())
@@ -2869,18 +2870,23 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfs4_transform_lock_offset(&file_lock);
- /* posix_test_lock uses the struct file _only_ to resolve the inode.
+ /* vfs_test_lock uses the struct file _only_ to resolve the inode.
* since LOCKT doesn't require an OPEN, and therefore a struct
- * file may not exist, pass posix_test_lock a struct file with
+ * file may not exist, pass vfs_test_lock a struct file with
* only the dentry:inode set.
*/
memset(&file, 0, sizeof (struct file));
file.f_path.dentry = cstate->current_fh.fh_dentry;
status = nfs_ok;
- if (posix_test_lock(&file, &file_lock, &conflock)) {
+ error = vfs_test_lock(&file, &file_lock);
+ if (error) {
+ status = nfserrno(error);
+ goto out;
+ }
+ if (file_lock.fl_type != F_UNLCK) {
status = nfserr_denied;
- nfs4_set_lock_denied(&conflock, &lockt->lt_denied);
+ nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
}
out:
nfs4_unlock_state();
@@ -2933,9 +2939,9 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/*
* Try to unlock the file in the VFS.
*/
- err = posix_lock_file(filp, &file_lock);
+ err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
if (err) {
- dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
+ dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
goto out_nfserr;
}
/*
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5d090f11f2b..15809dfd88a 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -44,7 +44,6 @@
#include <linux/param.h>
#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/vfs.h>
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 8d995bcef80..6ca2d24fc21 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -10,7 +10,6 @@
*/
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/unistd.h>
#include <linux/string.h>
@@ -324,7 +323,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
*
*/
- u8 version = 1;
+ u8 version;
u8 fsid_type = 0;
struct inode * inode = dentry->d_inode;
struct dentry *parent = dentry->d_parent;
@@ -342,15 +341,59 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
* the reference filehandle (if it is in the same export)
* or the export options.
*/
+ retry:
+ version = 1;
if (ref_fh && ref_fh->fh_export == exp) {
version = ref_fh->fh_handle.fh_version;
- if (version == 0xca)
+ fsid_type = ref_fh->fh_handle.fh_fsid_type;
+
+ if (ref_fh == fhp)
+ fh_put(ref_fh);
+ ref_fh = NULL;
+
+ switch (version) {
+ case 0xca:
fsid_type = FSID_DEV;
- else
- fsid_type = ref_fh->fh_handle.fh_fsid_type;
- /* We know this version/type works for this export
- * so there is no need for further checks.
+ break;
+ case 1:
+ break;
+ default:
+ goto retry;
+ }
+
+ /* Need to check that this type works for this
+ * export point. As the fsid -> filesystem mapping
+ * was guided by user-space, there is no guarantee
+ * that the filesystem actually supports that fsid
+ * type. If it doesn't we loop around again without
+ * ref_fh set.
*/
+ switch(fsid_type) {
+ case FSID_DEV:
+ if (!old_valid_dev(ex_dev))
+ goto retry;
+ /* FALL THROUGH */
+ case FSID_MAJOR_MINOR:
+ case FSID_ENCODE_DEV:
+ if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags
+ & FS_REQUIRES_DEV))
+ goto retry;
+ break;
+ case FSID_NUM:
+ if (! (exp->ex_flags & NFSEXP_FSID))
+ goto retry;
+ break;
+ case FSID_UUID8:
+ case FSID_UUID16:
+ if (!root_export)
+ goto retry;
+ /* fall through */
+ case FSID_UUID4_INUM:
+ case FSID_UUID16_INUM:
+ if (exp->ex_uuid == NULL)
+ goto retry;
+ break;
+ }
} else if (exp->ex_uuid) {
if (fhp->fh_maxsize >= 64) {
if (root_export)
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 5cc2eec981b..b2c7147aa92 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -155,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
argp->count);
argp->count = NFSSVC_MAXBLKSIZE_V2;
}
- svc_reserve(rqstp, (19<<2) + argp->count + 4);
+ svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
resp->count = argp->count;
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 0c24b9e24fe..cb3e7fadb77 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -231,9 +231,10 @@ int
nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_sattrargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_sattr(p, &args->attrs)))
+ p = decode_fh(p, &args->fh);
+ if (!p)
return 0;
+ p = decode_sattr(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
@@ -284,8 +285,9 @@ int
nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_writeargs *args)
{
- unsigned int len;
+ unsigned int len, hdr, dlen;
int v;
+
if (!(p = decode_fh(p, &args->fh)))
return 0;
@@ -293,11 +295,30 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
args->offset = ntohl(*p++); /* offset */
p++; /* totalcount */
len = args->len = ntohl(*p++);
- rqstp->rq_vec[0].iov_base = (void*)p;
- rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
- (((void*)p) - rqstp->rq_arg.head[0].iov_base);
+ /*
+ * The protocol specifies a maximum of 8192 bytes.
+ */
if (len > NFSSVC_MAXBLKSIZE_V2)
- len = NFSSVC_MAXBLKSIZE_V2;
+ return 0;
+
+ /*
+ * Check to make sure that we got the right number of
+ * bytes.
+ */
+ hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
+ dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+ - hdr;
+
+ /*
+ * Round the length of the data which was specified up to
+ * the next multiple of XDR units and then compare that
+ * against the length which was actually received.
+ */
+ if (dlen != XDR_QUADLEN(len)*4)
+ return 0;
+
+ rqstp->rq_vec[0].iov_base = (void*)p;
+ rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
v = 0;
while (len > rqstp->rq_vec[v].iov_len) {
len -= rqstp->rq_vec[v].iov_len;
@@ -306,18 +327,18 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
rqstp->rq_vec[v].iov_len = PAGE_SIZE;
}
rqstp->rq_vec[v].iov_len = len;
- args->vlen = v+1;
- return rqstp->rq_vec[0].iov_len > 0;
+ args->vlen = v + 1;
+ return 1;
}
int
nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_createargs *args)
{
- if (!(p = decode_fh(p, &args->fh))
- || !(p = decode_filename(p, &args->name, &args->len))
- || !(p = decode_sattr(p, &args->attrs)))
+ if ( !(p = decode_fh(p, &args->fh))
+ || !(p = decode_filename(p, &args->name, &args->len)))
return 0;
+ p = decode_sattr(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
@@ -361,11 +382,11 @@ int
nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_symlinkargs *args)
{
- if (!(p = decode_fh(p, &args->ffh))
- || !(p = decode_filename(p, &args->fname, &args->flen))
- || !(p = decode_pathname(p, &args->tname, &args->tlen))
- || !(p = decode_sattr(p, &args->attrs)))
+ if ( !(p = decode_fh(p, &args->ffh))
+ || !(p = decode_filename(p, &args->fname, &args->flen))
+ || !(p = decode_pathname(p, &args->tname, &args->tlen)))
return 0;
+ p = decode_sattr(p, &args->attrs);
return xdr_argsize_check(rqstp, p);
}
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
index 9393f4b1e29..caecc58f529 100644
--- a/fs/ntfs/aops.h
+++ b/fs/ntfs/aops.h
@@ -89,9 +89,8 @@ static inline struct page *ntfs_map_page(struct address_space *mapping,
struct page *page = read_mapping_page(mapping, index, NULL);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
- if (PageUptodate(page) && !PageError(page))
+ if (!PageError(page))
return page;
ntfs_unmap_page(page);
return ERR_PTR(-EIO);
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 7659cc19299..1c08fefe487 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -2532,14 +2532,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
page = read_mapping_page(mapping, idx, NULL);
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read first partial "
- "page (sync error, index 0x%lx).", idx);
- return PTR_ERR(page);
- }
- wait_on_page_locked(page);
- if (unlikely(!PageUptodate(page))) {
- ntfs_error(vol->sb, "Failed to read first partial page "
- "(async error, index 0x%lx).", idx);
- page_cache_release(page);
+ "page (error, index 0x%lx).", idx);
return PTR_ERR(page);
}
/*
@@ -2602,14 +2595,7 @@ int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val)
page = read_mapping_page(mapping, idx, NULL);
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read last partial page "
- "(sync error, index 0x%lx).", idx);
- return PTR_ERR(page);
- }
- wait_on_page_locked(page);
- if (unlikely(!PageUptodate(page))) {
- ntfs_error(vol->sb, "Failed to read last partial page "
- "(async error, index 0x%lx).", idx);
- page_cache_release(page);
+ "(error, index 0x%lx).", idx);
return PTR_ERR(page);
}
kaddr = kmap_atomic(page, KM_USER0);
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index 74f99a6a369..34314b33dbd 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -20,7 +20,6 @@
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include "dir.h"
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index d69c4595ccd..621de369e6f 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -236,8 +236,7 @@ do_non_resident_extend:
err = PTR_ERR(page);
goto init_err_out;
}
- wait_on_page_locked(page);
- if (unlikely(!PageUptodate(page) || PageError(page))) {
+ if (unlikely(PageError(page))) {
page_cache_release(page);
err = -EIO;
goto init_err_out;
@@ -2130,28 +2129,13 @@ static ssize_t ntfs_file_aio_write_nolock(struct kiocb *iocb,
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
loff_t pos;
- unsigned long seg;
size_t count; /* after file limit checks */
ssize_t written, err;
count = 0;
- for (seg = 0; seg < nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- count += iv->iov_len;
- if (unlikely((ssize_t)(count|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
- continue;
- if (!seg)
- return -EFAULT;
- nr_segs = seg;
- count -= iv->iov_len; /* This segment is no good */
- break;
- }
+ err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
+ if (err)
+ return err;
pos = *ppos;
vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
/* We can write back this queue in page reclaim. */
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index f8bf8da67ee..074791ce4ab 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -27,7 +27,6 @@
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include "aops.h"
#include "attrib.h"
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 1594c90b716..21d834e5ed7 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2471,7 +2471,6 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
s64 nr_free = vol->nr_clusters;
u32 *kaddr;
struct address_space *mapping = vol->lcnbmp_ino->i_mapping;
- filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
struct page *page;
pgoff_t index, max_index;
@@ -2494,24 +2493,14 @@ static s64 get_nr_free_clusters(ntfs_volume *vol)
* Read the page from page cache, getting it from backing store
* if necessary, and increment the use count.
*/
- page = read_cache_page(mapping, index, (filler_t*)readpage,
- NULL);
+ page = read_mapping_page(mapping, index, NULL);
/* Ignore pages which errored synchronously. */
if (IS_ERR(page)) {
- ntfs_debug("Sync read_cache_page() error. Skipping "
+ ntfs_debug("read_mapping_page() error. Skipping "
"page (index 0x%lx).", index);
nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
- wait_on_page_locked(page);
- /* Ignore pages which errored asynchronously. */
- if (!PageUptodate(page)) {
- ntfs_debug("Async read_cache_page() error. Skipping "
- "page (index 0x%lx).", index);
- page_cache_release(page);
- nr_free -= PAGE_CACHE_SIZE * 8;
- continue;
- }
kaddr = (u32*)kmap_atomic(page, KM_USER0);
/*
* For each 4 bytes, subtract the number of set bits. If this
@@ -2562,7 +2551,6 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
{
u32 *kaddr;
struct address_space *mapping = vol->mftbmp_ino->i_mapping;
- filler_t *readpage = (filler_t*)mapping->a_ops->readpage;
struct page *page;
pgoff_t index;
@@ -2576,21 +2564,11 @@ static unsigned long __get_nr_free_mft_records(ntfs_volume *vol,
* Read the page from page cache, getting it from backing store
* if necessary, and increment the use count.
*/
- page = read_cache_page(mapping, index, (filler_t*)readpage,
- NULL);
+ page = read_mapping_page(mapping, index, NULL);
/* Ignore pages which errored synchronously. */
if (IS_ERR(page)) {
- ntfs_debug("Sync read_cache_page() error. Skipping "
- "page (index 0x%lx).", index);
- nr_free -= PAGE_CACHE_SIZE * 8;
- continue;
- }
- wait_on_page_locked(page);
- /* Ignore pages which errored asynchronously. */
- if (!PageUptodate(page)) {
- ntfs_debug("Async read_cache_page() error. Skipping "
+ ntfs_debug("read_mapping_page() error. Skipping "
"page (index 0x%lx).", index);
- page_cache_release(page);
nr_free -= PAGE_CACHE_SIZE * 8;
continue;
}
@@ -3107,8 +3085,7 @@ static void ntfs_big_inode_init_once(void *foo, struct kmem_cache *cachep,
{
ntfs_inode *ni = (ntfs_inode *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(VFS_I(ni));
}
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index a0c8667caa7..19712a7d145 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -2869,7 +2869,7 @@ int ocfs2_complete_truncate_log_recovery(struct ocfs2_super *osb,
tl = &tl_copy->id2.i_dealloc;
num_recs = le16_to_cpu(tl->tl_used);
mlog(0, "cleanup %u records from %llu\n", num_recs,
- (unsigned long long)tl_copy->i_blkno);
+ (unsigned long long)le64_to_cpu(tl_copy->i_blkno));
mutex_lock(&tl_inode->i_mutex);
for(i = 0; i < num_recs; i++) {
@@ -3801,8 +3801,8 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
fe = (struct ocfs2_dinode *) fe_bh->b_data;
mlog(0, "fe->i_clusters = %u, new_i_clusters = %u, fe->i_size ="
- "%llu\n", fe->i_clusters, new_i_clusters,
- (unsigned long long)fe->i_size);
+ "%llu\n", le32_to_cpu(fe->i_clusters), new_i_clusters,
+ (unsigned long long)le64_to_cpu(fe->i_size));
*tc = kzalloc(sizeof(struct ocfs2_truncate_context), GFP_KERNEL);
if (!(*tc)) {
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 56963e6c46c..8e7cafb5fc6 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -78,7 +78,8 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
if (!OCFS2_IS_VALID_DINODE(fe)) {
mlog(ML_ERROR, "Invalid dinode #%llu: signature = %.*s\n",
- (unsigned long long)fe->i_blkno, 7, fe->i_signature);
+ (unsigned long long)le64_to_cpu(fe->i_blkno), 7,
+ fe->i_signature);
goto bail;
}
@@ -939,9 +940,9 @@ out:
* Returns a negative error code or the number of bytes copied into
* the page.
*/
-int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
- u64 *p_blkno, struct page *page,
- struct ocfs2_write_ctxt *wc, int new)
+static int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
+ u64 *p_blkno, struct page *page,
+ struct ocfs2_write_ctxt *wc, int new)
{
int ret, copied = 0;
unsigned int from = 0, to = 0;
@@ -1086,7 +1087,7 @@ static ssize_t ocfs2_write(struct file *file, u32 phys, handle_t *handle,
for(i = 0; i < numpages; i++) {
index = start + i;
- cpages[i] = grab_cache_page(mapping, index);
+ cpages[i] = find_or_create_page(mapping, index, GFP_NOFS);
if (!cpages[i]) {
ret = -ENOMEM;
mlog_errno(ret);
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index eba282da500..979113479c6 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -438,7 +438,7 @@ static inline void o2hb_prepare_block(struct o2hb_region *reg,
hb_block));
mlog(ML_HB_BIO, "our node generation = 0x%llx, cksum = 0x%x\n",
- (long long)cpu_to_le64(generation),
+ (long long)generation,
le32_to_cpu(hb_block->hb_cksum));
}
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 636593bf4d1..2e975c0a35e 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -147,7 +147,7 @@ static struct kset mlog_kset = {
.kobj = {.name = "logmask", .ktype = &mlog_ktype},
};
-int mlog_sys_init(struct subsystem *o2cb_subsys)
+int mlog_sys_init(struct kset *o2cb_subsys)
{
int i = 0;
@@ -157,7 +157,7 @@ int mlog_sys_init(struct subsystem *o2cb_subsys)
}
mlog_attr_ptrs[i] = NULL;
- mlog_kset.subsys = o2cb_subsys;
+ kobj_set_kset_s(&mlog_kset, o2cb_subsys);
return kset_register(&mlog_kset);
}
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h
index a42628ba9dd..75cd877f6d4 100644
--- a/fs/ocfs2/cluster/masklog.h
+++ b/fs/ocfs2/cluster/masklog.h
@@ -278,7 +278,7 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits;
#include <linux/kobject.h>
#include <linux/sysfs.h>
-int mlog_sys_init(struct subsystem *o2cb_subsys);
+int mlog_sys_init(struct kset *o2cb_subsys);
void mlog_sys_shutdown(void);
#endif /* O2CLUSTER_MASKLOG_H */
diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c
index 1d9f6acafa2..64f6f378fd0 100644
--- a/fs/ocfs2/cluster/sys.c
+++ b/fs/ocfs2/cluster/sys.c
@@ -42,7 +42,6 @@ struct o2cb_attribute {
#define O2CB_ATTR(_name, _mode, _show, _store) \
struct o2cb_attribute o2cb_attr_##_name = __ATTR(_name, _mode, _show, _store)
-#define to_o2cb_subsys(k) container_of(to_kset(k), struct subsystem, kset)
#define to_o2cb_attr(_attr) container_of(_attr, struct o2cb_attribute, attr)
static ssize_t o2cb_interface_revision_show(char *buf)
@@ -79,7 +78,7 @@ static ssize_t
o2cb_show(struct kobject * kobj, struct attribute * attr, char * buffer)
{
struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
- struct subsystem *sbs = to_o2cb_subsys(kobj);
+ struct kset *sbs = to_kset(kobj);
BUG_ON(sbs != &o2cb_subsys);
@@ -93,7 +92,7 @@ o2cb_store(struct kobject * kobj, struct attribute * attr,
const char * buffer, size_t count)
{
struct o2cb_attribute *o2cb_attr = to_o2cb_attr(attr);
- struct subsystem *sbs = to_o2cb_subsys(kobj);
+ struct kset *sbs = to_kset(kobj);
BUG_ON(sbs != &o2cb_subsys);
@@ -112,7 +111,7 @@ int o2cb_sys_init(void)
{
int ret;
- o2cb_subsys.kset.kobj.ktype = &o2cb_subsys_type;
+ o2cb_subsys.kobj.ktype = &o2cb_subsys_type;
ret = subsystem_register(&o2cb_subsys);
if (ret)
return ret;
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 69caf3e12fe..0b229a9c795 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1496,7 +1496,7 @@ static void o2net_start_connect(struct work_struct *work)
sock->sk->sk_allocation = GFP_ATOMIC;
myaddr.sin_family = AF_INET;
- myaddr.sin_addr.s_addr = (__force u32)mynode->nd_ipv4_address;
+ myaddr.sin_addr.s_addr = mynode->nd_ipv4_address;
myaddr.sin_port = (__force u16)htons(0); /* any port */
ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr,
@@ -1521,8 +1521,8 @@ static void o2net_start_connect(struct work_struct *work)
spin_unlock(&nn->nn_lock);
remoteaddr.sin_family = AF_INET;
- remoteaddr.sin_addr.s_addr = (__force u32)node->nd_ipv4_address;
- remoteaddr.sin_port = (__force u16)node->nd_ipv4_port;
+ remoteaddr.sin_addr.s_addr = node->nd_ipv4_address;
+ remoteaddr.sin_port = node->nd_ipv4_port;
ret = sc->sc_sock->ops->connect(sc->sc_sock,
(struct sockaddr *)&remoteaddr,
@@ -1810,8 +1810,8 @@ static int o2net_open_listening_sock(__be32 addr, __be16 port)
int ret;
struct sockaddr_in sin = {
.sin_family = PF_INET,
- .sin_addr = { .s_addr = (__force u32)addr },
- .sin_port = (__force u16)port,
+ .sin_addr = { .s_addr = addr },
+ .sin_port = port,
};
ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 67e6866a2a4..c441ef1f2ba 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -403,7 +403,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
struct buffer_head **new_de_bh)
{
int status = 0;
- int credits, num_free_extents;
+ int credits, num_free_extents, drop_alloc_sem = 0;
loff_t dir_i_size;
struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
struct ocfs2_alloc_context *data_ac = NULL;
@@ -452,6 +452,9 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
}
+ down_write(&OCFS2_I(dir)->ip_alloc_sem);
+ drop_alloc_sem = 1;
+
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
@@ -497,6 +500,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
*new_de_bh = new_bh;
get_bh(*new_de_bh);
bail:
+ if (drop_alloc_sem)
+ up_write(&OCFS2_I(dir)->ip_alloc_sem);
if (handle)
ocfs2_commit_trans(osb, handle);
diff --git a/fs/ocfs2/dlm/dlmast.c b/fs/ocfs2/dlm/dlmast.c
index 241cad342a4..2fd8bded38f 100644
--- a/fs/ocfs2/dlm/dlmast.c
+++ b/fs/ocfs2/dlm/dlmast.c
@@ -312,8 +312,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
past->type != DLM_BAST) {
mlog(ML_ERROR, "Unknown ast type! %d, cookie=%u:%llu"
"name=%.*s\n", past->type,
- dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
- dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
+ dlm_get_lock_cookie_node(cookie),
+ dlm_get_lock_cookie_seq(cookie),
locklen, name);
ret = DLM_IVLOCKID;
goto leave;
@@ -324,8 +324,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
mlog(0, "got %sast for unknown lockres! "
"cookie=%u:%llu, name=%.*s, namelen=%u\n",
past->type == DLM_AST ? "" : "b",
- dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
- dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
+ dlm_get_lock_cookie_node(cookie),
+ dlm_get_lock_cookie_seq(cookie),
locklen, name, locklen);
ret = DLM_IVLOCKID;
goto leave;
@@ -370,8 +370,8 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
mlog(0, "got %sast for unknown lock! cookie=%u:%llu, "
"name=%.*s, namelen=%u\n", past->type == DLM_AST ? "" : "b",
- dlm_get_lock_cookie_node(be64_to_cpu(cookie)),
- dlm_get_lock_cookie_seq(be64_to_cpu(cookie)),
+ dlm_get_lock_cookie_node(cookie),
+ dlm_get_lock_cookie_seq(cookie),
locklen, name, locklen);
ret = DLM_NORMAL;
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index de952eba29a..5671cf9d638 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -42,7 +42,6 @@
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/backing-dev.h>
#include <asm/uaccess.h>
@@ -263,8 +262,7 @@ static void dlmfs_init_once(void *foo,
struct dlmfs_inode_private *ip =
(struct dlmfs_inode_private *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
ip->ip_dlm = NULL;
ip->ip_parent = NULL;
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index c1807a42c49..671c4ed58ee 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1769,7 +1769,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
/* lock is always created locally first, and
* destroyed locally last. it must be on the list */
if (!lock) {
- u64 c = ml->cookie;
+ __be64 c = ml->cookie;
mlog(ML_ERROR, "could not find local lock "
"with cookie %u:%llu!\n",
dlm_get_lock_cookie_node(be64_to_cpu(c)),
@@ -1878,7 +1878,7 @@ skip_lvb:
spin_lock(&res->spinlock);
list_for_each_entry(lock, queue, list) {
if (lock->ml.cookie == ml->cookie) {
- u64 c = lock->ml.cookie;
+ __be64 c = lock->ml.cookie;
mlog(ML_ERROR, "%s:%.*s: %u:%llu: lock already "
"exists on this lockres!\n", dlm->name,
res->lockname.len, res->lockname.name,
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c
index 2b264c6ba03..cebd089f895 100644
--- a/fs/ocfs2/dlm/dlmthread.c
+++ b/fs/ocfs2/dlm/dlmthread.c
@@ -76,7 +76,7 @@ repeat:
goto repeat;
}
remove_wait_queue(&res->wq, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
}
int __dlm_lockres_has_locks(struct dlm_lock_resource *res)
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 27e43b0c0ea..d1bd305ef0d 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -27,7 +27,6 @@
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/crc32.h>
#include <linux/kthread.h>
#include <linux/pagemap.h>
@@ -104,6 +103,35 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
static void ocfs2_dentry_post_unlock(struct ocfs2_super *osb,
struct ocfs2_lock_res *lockres);
+
+#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
+
+/* This aids in debugging situations where a bad LVB might be involved. */
+static void ocfs2_dump_meta_lvb_info(u64 level,
+ const char *function,
+ unsigned int line,
+ struct ocfs2_lock_res *lockres)
+{
+ struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
+
+ mlog(level, "LVB information for %s (called from %s:%u):\n",
+ lockres->l_name, function, line);
+ mlog(level, "version: %u, clusters: %u, generation: 0x%x\n",
+ lvb->lvb_version, be32_to_cpu(lvb->lvb_iclusters),
+ be32_to_cpu(lvb->lvb_igeneration));
+ mlog(level, "size: %llu, uid %u, gid %u, mode 0x%x\n",
+ (unsigned long long)be64_to_cpu(lvb->lvb_isize),
+ be32_to_cpu(lvb->lvb_iuid), be32_to_cpu(lvb->lvb_igid),
+ be16_to_cpu(lvb->lvb_imode));
+ mlog(level, "nlink %u, atime_packed 0x%llx, ctime_packed 0x%llx, "
+ "mtime_packed 0x%llx iattr 0x%x\n", be16_to_cpu(lvb->lvb_inlink),
+ (long long)be64_to_cpu(lvb->lvb_iatime_packed),
+ (long long)be64_to_cpu(lvb->lvb_ictime_packed),
+ (long long)be64_to_cpu(lvb->lvb_imtime_packed),
+ be32_to_cpu(lvb->lvb_iattr));
+}
+
+
/*
* OCFS2 Lock Resource Operations
*
@@ -3078,28 +3106,3 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
mlog_exit_void();
}
-
-/* This aids in debugging situations where a bad LVB might be involved. */
-void ocfs2_dump_meta_lvb_info(u64 level,
- const char *function,
- unsigned int line,
- struct ocfs2_lock_res *lockres)
-{
- struct ocfs2_meta_lvb *lvb = (struct ocfs2_meta_lvb *) lockres->l_lksb.lvb;
-
- mlog(level, "LVB information for %s (called from %s:%u):\n",
- lockres->l_name, function, line);
- mlog(level, "version: %u, clusters: %u, generation: 0x%x\n",
- lvb->lvb_version, be32_to_cpu(lvb->lvb_iclusters),
- be32_to_cpu(lvb->lvb_igeneration));
- mlog(level, "size: %llu, uid %u, gid %u, mode 0x%x\n",
- (unsigned long long)be64_to_cpu(lvb->lvb_isize),
- be32_to_cpu(lvb->lvb_iuid), be32_to_cpu(lvb->lvb_igid),
- be16_to_cpu(lvb->lvb_imode));
- mlog(level, "nlink %u, atime_packed 0x%llx, ctime_packed 0x%llx, "
- "mtime_packed 0x%llx iattr 0x%x\n", be16_to_cpu(lvb->lvb_inlink),
- (long long)be64_to_cpu(lvb->lvb_iatime_packed),
- (long long)be64_to_cpu(lvb->lvb_ictime_packed),
- (long long)be64_to_cpu(lvb->lvb_imtime_packed),
- be32_to_cpu(lvb->lvb_iattr));
-}
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
index 59cb566e798..492bad32a8c 100644
--- a/fs/ocfs2/dlmglue.h
+++ b/fs/ocfs2/dlmglue.h
@@ -119,11 +119,4 @@ void ocfs2_process_blocked_lock(struct ocfs2_super *osb,
struct ocfs2_dlm_debug *ocfs2_new_dlm_debug(void);
void ocfs2_put_dlm_debug(struct ocfs2_dlm_debug *dlm_debug);
-/* aids in debugging and tracking lvbs */
-void ocfs2_dump_meta_lvb_info(u64 level,
- const char *function,
- unsigned int line,
- struct ocfs2_lock_res *lockres);
-#define mlog_meta_lvb(__level, __lockres) ocfs2_dump_meta_lvb_info(__level, __PRETTY_FUNCTION__, __LINE__, __lockres)
-
#endif /* DLMGLUE_H */
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index 56e1fefc120..bc48177bd18 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -140,7 +140,7 @@ bail:
return parent;
}
-static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len,
+static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
int connectable)
{
struct inode *inode = dentry->d_inode;
@@ -148,6 +148,7 @@ static int ocfs2_encode_fh(struct dentry *dentry, __be32 *fh, int *max_len,
int type = 1;
u64 blkno;
u32 generation;
+ __le32 *fh = (__force __le32 *) fh_in;
mlog_entry("(0x%p, '%.*s', 0x%p, %d, %d)\n", dentry,
dentry->d_name.len, dentry->d_name.name,
@@ -199,7 +200,7 @@ bail:
return type;
}
-static struct dentry *ocfs2_decode_fh(struct super_block *sb, __be32 *fh,
+static struct dentry *ocfs2_decode_fh(struct super_block *sb, u32 *fh_in,
int fh_len, int fileid_type,
int (*acceptable)(void *context,
struct dentry *de),
@@ -207,6 +208,7 @@ static struct dentry *ocfs2_decode_fh(struct super_block *sb, __be32 *fh,
{
struct ocfs2_inode_handle handle, parent;
struct dentry *ret = NULL;
+ __le32 *fh = (__force __le32 *) fh_in;
mlog_entry("(0x%p, 0x%p, %d, %d, 0x%p, 0x%p)\n",
sb, fh, fh_len, fileid_type, acceptable, context);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 520a2a6d767..9395b4fa547 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -207,10 +207,10 @@ out:
return ret;
}
-int ocfs2_set_inode_size(handle_t *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- u64 new_i_size)
+static int ocfs2_set_inode_size(handle_t *handle,
+ struct inode *inode,
+ struct buffer_head *fe_bh,
+ u64 new_i_size)
{
int status;
@@ -713,7 +713,8 @@ restarted_transaction:
}
mlog(0, "fe: i_clusters = %u, i_size=%llu\n",
- fe->i_clusters, (unsigned long long)fe->i_size);
+ le32_to_cpu(fe->i_clusters),
+ (unsigned long long)le64_to_cpu(fe->i_size));
mlog(0, "inode: ip_clusters=%u, i_size=%lld\n",
OCFS2_I(inode)->ip_clusters, i_size_read(inode));
@@ -1853,6 +1854,9 @@ const struct file_operations ocfs2_fops = {
.aio_read = ocfs2_file_aio_read,
.aio_write = ocfs2_file_aio_write,
.ioctl = ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ocfs2_compat_ioctl,
+#endif
.splice_read = ocfs2_file_splice_read,
.splice_write = ocfs2_file_splice_write,
};
@@ -1862,4 +1866,7 @@ const struct file_operations ocfs2_dops = {
.readdir = ocfs2_readdir,
.fsync = ocfs2_sync_file,
.ioctl = ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ocfs2_compat_ioctl,
+#endif
};
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 2c4460fced5..a4dd1fa1822 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -56,11 +56,6 @@ int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
int ocfs2_permission(struct inode *inode, int mask,
struct nameidata *nd);
-int ocfs2_set_inode_size(handle_t *handle,
- struct inode *inode,
- struct buffer_head *fe_bh,
- u64 new_i_size);
-
int ocfs2_should_update_atime(struct inode *inode,
struct vfsmount *vfsmnt);
int ocfs2_update_inode_atime(struct inode *inode,
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 21a605079c6..c53a6763bbb 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -28,7 +28,6 @@
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <asm/byteorder.h>
@@ -89,6 +88,25 @@ void ocfs2_set_inode_flags(struct inode *inode)
inode->i_flags |= S_DIRSYNC;
}
+/* Propagate flags from i_flags to OCFS2_I(inode)->ip_attr */
+void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi)
+{
+ unsigned int flags = oi->vfs_inode.i_flags;
+
+ oi->ip_attr &= ~(OCFS2_SYNC_FL|OCFS2_APPEND_FL|
+ OCFS2_IMMUTABLE_FL|OCFS2_NOATIME_FL|OCFS2_DIRSYNC_FL);
+ if (flags & S_SYNC)
+ oi->ip_attr |= OCFS2_SYNC_FL;
+ if (flags & S_APPEND)
+ oi->ip_attr |= OCFS2_APPEND_FL;
+ if (flags & S_IMMUTABLE)
+ oi->ip_attr |= OCFS2_IMMUTABLE_FL;
+ if (flags & S_NOATIME)
+ oi->ip_attr |= OCFS2_NOATIME_FL;
+ if (flags & S_DIRSYNC)
+ oi->ip_attr |= OCFS2_DIRSYNC_FL;
+}
+
struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, int flags)
{
struct inode *inode = NULL;
@@ -196,7 +214,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
int status = -EINVAL;
mlog_entry("(0x%p, size:%llu)\n", inode,
- (unsigned long long)fe->i_size);
+ (unsigned long long)le64_to_cpu(fe->i_size));
sb = inode->i_sb;
osb = OCFS2_SB(sb);
@@ -248,7 +266,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
mlog(ML_ERROR,
"ip_blkno %llu != i_blkno %llu!\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
- (unsigned long long)fe->i_blkno);
+ (unsigned long long)le64_to_cpu(fe->i_blkno));
inode->i_nlink = le16_to_cpu(fe->i_links_count);
@@ -301,7 +319,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
* the generation argument to
* ocfs2_inode_lock_res_init() will have to change.
*/
- BUG_ON(fe->i_flags & cpu_to_le32(OCFS2_SYSTEM_FL));
+ BUG_ON(le32_to_cpu(fe->i_flags) & OCFS2_SYSTEM_FL);
ocfs2_inode_lock_res_init(&OCFS2_I(inode)->ip_meta_lockres,
OCFS2_LOCK_TYPE_META, 0, inode);
@@ -437,7 +455,8 @@ static int ocfs2_read_locked_inode(struct inode *inode,
fe = (struct ocfs2_dinode *) bh->b_data;
if (!OCFS2_IS_VALID_DINODE(fe)) {
mlog(ML_ERROR, "Invalid dinode #%llu: signature = %.*s\n",
- (unsigned long long)fe->i_blkno, 7, fe->i_signature);
+ (unsigned long long)le64_to_cpu(fe->i_blkno), 7,
+ fe->i_signature);
goto bail;
}
@@ -812,8 +831,8 @@ static int ocfs2_query_inode_wipe(struct inode *inode,
"Inode %llu (on-disk %llu) not orphaned! "
"Disk flags 0x%x, inode flags 0x%x\n",
(unsigned long long)oi->ip_blkno,
- (unsigned long long)di->i_blkno, di->i_flags,
- oi->ip_flags);
+ (unsigned long long)le64_to_cpu(di->i_blkno),
+ le32_to_cpu(di->i_flags), oi->ip_flags);
goto bail;
}
@@ -1106,8 +1125,10 @@ struct buffer_head *ocfs2_bread(struct inode *inode,
return NULL;
}
+ down_read(&OCFS2_I(inode)->ip_alloc_sem);
tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
NULL);
+ up_read(&OCFS2_I(inode)->ip_alloc_sem);
if (tmperr < 0) {
mlog_errno(tmperr);
goto fail;
@@ -1197,6 +1218,7 @@ int ocfs2_mark_inode_dirty(handle_t *handle,
spin_lock(&OCFS2_I(inode)->ip_lock);
fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
+ ocfs2_get_inode_flags(OCFS2_I(inode));
fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
spin_unlock(&OCFS2_I(inode)->ip_lock);
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index 03ae075869e..a41d0817121 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -141,6 +141,7 @@ int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb);
int ocfs2_aio_write(struct file *file, struct kiocb *req, struct iocb *iocb);
void ocfs2_set_inode_flags(struct inode *inode);
+void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi);
static inline blkcnt_t ocfs2_inode_sector_count(struct inode *inode)
{
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 4768be5f308..f3ad21ad9ae 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -31,6 +31,7 @@ static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
mlog_errno(status);
return status;
}
+ ocfs2_get_inode_flags(OCFS2_I(inode));
*flags = OCFS2_I(inode)->ip_attr;
ocfs2_meta_unlock(inode, 0);
@@ -134,3 +135,26 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
}
}
+#ifdef CONFIG_COMPAT
+long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ int ret;
+
+ switch (cmd) {
+ case OCFS2_IOC32_GETFLAGS:
+ cmd = OCFS2_IOC_GETFLAGS;
+ break;
+ case OCFS2_IOC32_SETFLAGS:
+ cmd = OCFS2_IOC_SETFLAGS;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ lock_kernel();
+ ret = ocfs2_ioctl(inode, file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+#endif
diff --git a/fs/ocfs2/ioctl.h b/fs/ocfs2/ioctl.h
index 4a7c82931db..4d6c4f430d0 100644
--- a/fs/ocfs2/ioctl.h
+++ b/fs/ocfs2/ioctl.h
@@ -12,5 +12,6 @@
int ocfs2_ioctl(struct inode * inode, struct file * filp,
unsigned int cmd, unsigned long arg);
+long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg);
#endif /* OCFS2_IOCTL_H */
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 5a8a90d1c78..dc118808172 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -435,7 +435,8 @@ static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb,
* handle the errors in a specific manner, so no need
* to call ocfs2_error() here. */
mlog(ML_ERROR, "Journal dinode %llu has invalid "
- "signature: %.*s", (unsigned long long)fe->i_blkno, 7,
+ "signature: %.*s",
+ (unsigned long long)le64_to_cpu(fe->i_blkno), 7,
fe->i_signature);
status = -EIO;
goto out;
@@ -742,7 +743,7 @@ void ocfs2_complete_recovery(struct work_struct *work)
la_dinode = item->lri_la_dinode;
if (la_dinode) {
mlog(0, "Clean up local alloc %llu\n",
- (unsigned long long)la_dinode->i_blkno);
+ (unsigned long long)le64_to_cpu(la_dinode->i_blkno));
ret = ocfs2_complete_local_alloc_recovery(osb,
la_dinode);
@@ -755,7 +756,7 @@ void ocfs2_complete_recovery(struct work_struct *work)
tl_dinode = item->lri_tl_dinode;
if (tl_dinode) {
mlog(0, "Clean up truncate log %llu\n",
- (unsigned long long)tl_dinode->i_blkno);
+ (unsigned long long)le64_to_cpu(tl_dinode->i_blkno));
ret = ocfs2_complete_truncate_log_recovery(osb,
tl_dinode);
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 2bcf353fd7c..36289e6295c 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -578,8 +578,9 @@ static int ocfs2_mknod_locked(struct ocfs2_super *osb,
if (ocfs2_populate_inode(inode, fe, 1) < 0) {
mlog(ML_ERROR, "populate inode failed! bh->b_blocknr=%llu, "
"i_blkno=%llu, i_ino=%lu\n",
- (unsigned long long) (*new_fe_bh)->b_blocknr,
- (unsigned long long)fe->i_blkno, inode->i_ino);
+ (unsigned long long)(*new_fe_bh)->b_blocknr,
+ (unsigned long long)le64_to_cpu(fe->i_blkno),
+ inode->i_ino);
BUG();
}
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 82cc92dcf8a..a860633e833 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -363,9 +363,9 @@ static inline int ocfs2_mount_local(struct ocfs2_super *osb)
typeof(__di) ____di = (__di); \
ocfs2_error((__sb), \
"Dinode # %llu has bad signature %.*s", \
- (unsigned long long)(____di)->i_blkno, 7, \
+ (unsigned long long)le64_to_cpu((____di)->i_blkno), 7, \
(____di)->i_signature); \
-} while (0);
+} while (0)
#define OCFS2_IS_VALID_EXTENT_BLOCK(ptr) \
(!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE))
@@ -374,9 +374,9 @@ static inline int ocfs2_mount_local(struct ocfs2_super *osb)
typeof(__eb) ____eb = (__eb); \
ocfs2_error((__sb), \
"Extent Block # %llu has bad signature %.*s", \
- (unsigned long long)(____eb)->h_blkno, 7, \
+ (unsigned long long)le64_to_cpu((____eb)->h_blkno), 7, \
(____eb)->h_signature); \
-} while (0);
+} while (0)
#define OCFS2_IS_VALID_GROUP_DESC(ptr) \
(!strcmp((ptr)->bg_signature, OCFS2_GROUP_DESC_SIGNATURE))
@@ -385,9 +385,9 @@ static inline int ocfs2_mount_local(struct ocfs2_super *osb)
typeof(__gd) ____gd = (__gd); \
ocfs2_error((__sb), \
"Group Descriptor # %llu has bad signature %.*s", \
- (unsigned long long)(____gd)->bg_blkno, 7, \
+ (unsigned long long)le64_to_cpu((____gd)->bg_blkno), 7, \
(____gd)->bg_signature); \
-} while (0);
+} while (0)
static inline unsigned long ino_from_blkno(struct super_block *sb,
u64 blkno)
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 71306479c68..f0d9eb08547 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -166,6 +166,8 @@
*/
#define OCFS2_IOC_GETFLAGS _IOR('f', 1, long)
#define OCFS2_IOC_SETFLAGS _IOW('f', 2, long)
+#define OCFS2_IOC32_GETFLAGS _IOR('f', 1, int)
+#define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int)
/*
* Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index d921a28329d..d8b79067dc1 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -26,7 +26,6 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/highmem.h>
-#include <linux/smp_lock.h>
#define MLOG_MASK_PREFIX ML_SUPER
#include <cluster/masklog.h>
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index 0da655ae5d6..e3437626d18 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -849,9 +849,9 @@ static int ocfs2_relink_block_group(handle_t *handle,
}
mlog(0, "Suballoc %llu, chain %u, move group %llu to top, prev = %llu\n",
- (unsigned long long)fe->i_blkno, chain,
- (unsigned long long)bg->bg_blkno,
- (unsigned long long)prev_bg->bg_blkno);
+ (unsigned long long)le64_to_cpu(fe->i_blkno), chain,
+ (unsigned long long)le64_to_cpu(bg->bg_blkno),
+ (unsigned long long)le64_to_cpu(prev_bg->bg_blkno));
fe_ptr = le64_to_cpu(fe->id2.i_chain.cl_recs[chain].c_blkno);
bg_ptr = le64_to_cpu(bg->bg_next_group);
@@ -1162,7 +1162,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
}
mlog(0, "alloc succeeds: we give %u bits from block group %llu\n",
- tmp_bits, (unsigned long long)bg->bg_blkno);
+ tmp_bits, (unsigned long long)le64_to_cpu(bg->bg_blkno));
*num_bits = tmp_bits;
@@ -1227,7 +1227,7 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
}
mlog(0, "Allocated %u bits from suballocator %llu\n", *num_bits,
- (unsigned long long)fe->i_blkno);
+ (unsigned long long)le64_to_cpu(fe->i_blkno));
*bg_blkno = le64_to_cpu(bg->bg_blkno);
*bits_left = le16_to_cpu(bg->bg_free_bits_count);
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 5c9e8243691..7c5e3f5d663 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -937,8 +937,7 @@ static void ocfs2_inode_init_once(void *data,
{
struct ocfs2_inode_info *oi = data;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
oi->ip_flags = 0;
oi->ip_open_count = 0;
spin_lock_init(&oi->ip_lock);
@@ -1538,7 +1537,7 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
} else if (bh->b_blocknr != le64_to_cpu(di->i_blkno)) {
mlog(ML_ERROR, "bad block number on superblock: "
"found %llu, should be %llu\n",
- (unsigned long long)di->i_blkno,
+ (unsigned long long)le64_to_cpu(di->i_blkno),
(unsigned long long)bh->b_blocknr);
} else if (le32_to_cpu(di->id2.i_super.s_clustersize_bits) < 12 ||
le32_to_cpu(di->id2.i_super.s_clustersize_bits) > 20) {
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 40dc1a51f4a..7134007ba22 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -67,16 +67,9 @@ static char *ocfs2_page_getlink(struct dentry * dentry,
page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
goto sync_fail;
- wait_on_page_locked(page);
- if (!PageUptodate(page))
- goto async_fail;
*ppage = page;
return kmap(page);
-async_fail:
- page_cache_release(page);
- return ERR_PTR(-EIO);
-
sync_fail:
return (char*)page;
}
diff --git a/fs/ocfs2/vote.c b/fs/ocfs2/vote.c
index 4f82a2f0efe..66a13ee63d4 100644
--- a/fs/ocfs2/vote.c
+++ b/fs/ocfs2/vote.c
@@ -26,7 +26,6 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/highmem.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <cluster/heartbeat.h>
diff --git a/fs/open.c b/fs/open.c
index c989fb4cf7b..0d515d16197 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -7,7 +7,6 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/file.h>
-#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <linux/fsnotify.h>
#include <linux/module.h>
@@ -211,6 +210,9 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
newattrs.ia_valid |= ATTR_FILE;
}
+ /* Remove suid/sgid on truncate too */
+ newattrs.ia_valid |= should_remove_suid(dentry);
+
mutex_lock(&dentry->d_inode->i_mutex);
err = notify_change(dentry, &newattrs);
mutex_unlock(&dentry->d_inode->i_mutex);
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index bde1c164417..731a90e9f0c 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -419,8 +419,7 @@ static void op_inode_init_once(void *data, struct kmem_cache * cachep, unsigned
{
struct op_inode_info *oi = (struct op_inode_info *) data;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&oi->vfs_inode);
}
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index 6e8bb66fe61..01207042048 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -236,3 +236,12 @@ config EFI_PARTITION
help
Say Y here if you would like to use hard disks under Linux which
were partitioned using EFI GPT.
+
+config SYSV68_PARTITION
+ bool "SYSV68 partition table support" if PARTITION_ADVANCED
+ default y if M68K
+ help
+ Say Y here if you would like to be able to read the hard disk
+ partition table format used by Motorola Delta machines (using
+ sysv68).
+ Otherwise, say N.
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 67e665fdb7f..03af8eac51d 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
obj-$(CONFIG_IBM_PARTITION) += ibm.o
obj-$(CONFIG_EFI_PARTITION) += efi.o
obj-$(CONFIG_KARMA_PARTITION) += karma.o
+obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index 1bc9f372c7d..e3491328596 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -271,7 +271,7 @@ adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev)
extern void xd_set_geometry(struct block_device *,
unsigned char, unsigned char, unsigned int);
xd_set_geometry(bdev, dr->secspertrack, heads, 1);
- invalidate_bdev(bdev, 1);
+ invalidate_bh_lrus();
truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
}
#endif
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 8a7d0035ad7..9a3a058f355 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -34,6 +34,7 @@
#include "ultrix.h"
#include "efi.h"
#include "karma.h"
+#include "sysv68.h"
#ifdef CONFIG_BLK_DEV_MD
extern void md_autodetect_dev(dev_t dev);
@@ -105,6 +106,9 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) =
#ifdef CONFIG_KARMA_PARTITION
karma_partition,
#endif
+#ifdef CONFIG_SYSV68_PARTITION
+ sysv68_partition,
+#endif
NULL
};
@@ -312,7 +316,7 @@ static struct attribute * default_attrs[] = {
NULL,
};
-extern struct subsystem block_subsys;
+extern struct kset block_subsys;
static void part_release(struct kobject *kobj)
{
@@ -388,7 +392,7 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
kobject_add(&p->kobj);
if (!disk->part_uevent_suppress)
kobject_uevent(&p->kobj, KOBJ_ADD);
- sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem");
+ sysfs_create_link(&p->kobj, &block_subsys.kobj, "subsystem");
if (flags & ADDPART_FLAG_WHOLEDISK) {
static struct attribute addpartattr = {
.name = "whole_disk",
@@ -444,7 +448,7 @@ static int disk_sysfs_symlinks(struct gendisk *disk)
goto err_out_dev_link;
}
- err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj,
+ err = sysfs_create_link(&disk->kobj, &block_subsys.kobj,
"subsystem");
if (err)
goto err_out_disk_name_lnk;
@@ -569,9 +573,6 @@ unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p)
page = read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT-9)),
NULL);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
- if (!PageUptodate(page))
- goto fail;
if (PageError(page))
goto fail;
p->v = page;
diff --git a/fs/partitions/sysv68.c b/fs/partitions/sysv68.c
new file mode 100644
index 00000000000..4eba27b7864
--- /dev/null
+++ b/fs/partitions/sysv68.c
@@ -0,0 +1,92 @@
+/*
+ * fs/partitions/sysv68.c
+ *
+ * Copyright (C) 2007 Philippe De Muyter <phdm@macqel.be>
+ */
+
+#include "check.h"
+#include "sysv68.h"
+
+/*
+ * Volume ID structure: on first 256-bytes sector of disk
+ */
+
+struct volumeid {
+ u8 vid_unused[248];
+ u8 vid_mac[8]; /* ASCII string "MOTOROLA" */
+};
+
+/*
+ * config block: second 256-bytes sector on disk
+ */
+
+struct dkconfig {
+ u8 ios_unused0[128];
+ __be32 ios_slcblk; /* Slice table block number */
+ __be16 ios_slccnt; /* Number of entries in slice table */
+ u8 ios_unused1[122];
+};
+
+/*
+ * combined volumeid and dkconfig block
+ */
+
+struct dkblk0 {
+ struct volumeid dk_vid;
+ struct dkconfig dk_ios;
+};
+
+/*
+ * Slice Table Structure
+ */
+
+struct slice {
+ __be32 nblocks; /* slice size (in blocks) */
+ __be32 blkoff; /* block offset of slice */
+};
+
+
+int sysv68_partition(struct parsed_partitions *state, struct block_device *bdev)
+{
+ int i, slices;
+ int slot = 1;
+ Sector sect;
+ unsigned char *data;
+ struct dkblk0 *b;
+ struct slice *slice;
+
+ data = read_dev_sector(bdev, 0, &sect);
+ if (!data)
+ return -1;
+
+ b = (struct dkblk0 *)data;
+ if (memcmp(b->dk_vid.vid_mac, "MOTOROLA", sizeof(b->dk_vid.vid_mac))) {
+ put_dev_sector(sect);
+ return 0;
+ }
+ slices = be16_to_cpu(b->dk_ios.ios_slccnt);
+ i = be32_to_cpu(b->dk_ios.ios_slcblk);
+ put_dev_sector(sect);
+
+ data = read_dev_sector(bdev, i, &sect);
+ if (!data)
+ return -1;
+
+ slices -= 1; /* last slice is the whole disk */
+ printk("sysV68: %s(s%u)", state->name, slices);
+ slice = (struct slice *)data;
+ for (i = 0; i < slices; i++, slice++) {
+ if (slot == state->limit)
+ break;
+ if (be32_to_cpu(slice->nblocks)) {
+ put_partition(state, slot,
+ be32_to_cpu(slice->blkoff),
+ be32_to_cpu(slice->nblocks));
+ printk("(s%u)", i);
+ }
+ slot++;
+ }
+ printk("\n");
+ put_dev_sector(sect);
+ return 1;
+}
diff --git a/fs/partitions/sysv68.h b/fs/partitions/sysv68.h
new file mode 100644
index 00000000000..fa733f68431
--- /dev/null
+++ b/fs/partitions/sysv68.h
@@ -0,0 +1 @@
+extern int sysv68_partition(struct parsed_partitions *state, struct block_device *bdev);
diff --git a/fs/pipe.c b/fs/pipe.c
index ebafde7d6ab..3a89592bdf5 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -841,8 +841,18 @@ static int pipefs_delete_dentry(struct dentry *dentry)
return 0;
}
+/*
+ * pipefs_dname() is called from d_path().
+ */
+static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+ return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]",
+ dentry->d_inode->i_ino);
+}
+
static struct dentry_operations pipefs_dentry_operations = {
.d_delete = pipefs_delete_dentry,
+ .d_dname = pipefs_dname,
};
static struct inode * get_pipe_inode(void)
@@ -888,8 +898,7 @@ struct file *create_write_pipe(void)
struct inode *inode;
struct file *f;
struct dentry *dentry;
- char name[32];
- struct qstr this;
+ struct qstr name = { .name = "" };
f = get_empty_filp();
if (!f)
@@ -899,11 +908,8 @@ struct file *create_write_pipe(void)
if (!inode)
goto err_file;
- this.len = sprintf(name, "[%lu]", inode->i_ino);
- this.name = name;
- this.hash = 0;
err = -ENOMEM;
- dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
+ dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name);
if (!dentry)
goto err_inode;
diff --git a/fs/pnode.c b/fs/pnode.c
index 56aacead836..89940f243fc 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -59,7 +59,7 @@ static int do_make_slave(struct vfsmount *mnt)
} else {
struct list_head *p = &mnt->mnt_slave_list;
while (!list_empty(p)) {
- slave_mnt = list_entry(p->next,
+ slave_mnt = list_first_entry(p,
struct vfsmount, mnt_slave);
list_del_init(&slave_mnt->mnt_slave);
slave_mnt->mnt_master = NULL;
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 07c9cdbcdca..74f30e0c038 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -410,9 +410,9 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
/* convert nsec -> ticks */
start_time = nsec_to_clock_t(start_time);
- res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
+ res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu %llu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n",
task->pid,
tcomm,
state,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 989af5e55d1..a5fa1fdafc4 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -61,9 +61,9 @@
#include <linux/namei.h>
#include <linux/mnt_namespace.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/rcupdate.h>
#include <linux/kallsyms.h>
+#include <linux/module.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
@@ -90,8 +90,8 @@
#define PROC_NUMBUF 13
struct pid_entry {
- int len;
char *name;
+ int len;
mode_t mode;
const struct inode_operations *iop;
const struct file_operations *fop;
@@ -99,8 +99,8 @@ struct pid_entry {
};
#define NOD(NAME, MODE, IOP, FOP, OP) { \
- .len = sizeof(NAME) - 1, \
.name = (NAME), \
+ .len = sizeof(NAME) - 1, \
.mode = MODE, \
.iop = IOP, \
.fop = FOP, \
@@ -123,6 +123,9 @@ struct pid_entry {
NULL, &proc_info_file_operations, \
{ .proc_read = &proc_##OTYPE } )
+int maps_protect;
+EXPORT_SYMBOL(maps_protect);
+
static struct fs_struct *get_fs_struct(struct task_struct *task)
{
struct fs_struct *fs;
@@ -275,17 +278,15 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer)
*/
static int proc_pid_wchan(struct task_struct *task, char *buffer)
{
- char *modname;
- const char *sym_name;
- unsigned long wchan, size, offset;
- char namebuf[KSYM_NAME_LEN+1];
+ unsigned long wchan;
+ char symname[KSYM_NAME_LEN+1];
wchan = get_wchan(task);
- sym_name = kallsyms_lookup(wchan, &size, &offset, &modname, namebuf);
- if (sym_name)
- return sprintf(buffer, "%s", sym_name);
- return sprintf(buffer, "%lu", wchan);
+ if (lookup_symbol_name(wchan, symname) < 0)
+ return sprintf(buffer, "%lu", wchan);
+ else
+ return sprintf(buffer, "%s", symname);
}
#endif /* CONFIG_KALLSYMS */
@@ -310,7 +311,9 @@ static int proc_oom_score(struct task_struct *task, char *buffer)
struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime);
+ read_lock(&tasklist_lock);
points = badness(task, uptime.tv_sec);
+ read_unlock(&tasklist_lock);
return sprintf(buffer, "%lu\n", points);
}
@@ -344,11 +347,8 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr)
return -EPERM;
error = inode_change_ok(inode, attr);
- if (!error) {
- error = security_inode_setattr(dentry, attr);
- if (!error)
- error = inode_setattr(inode, attr);
- }
+ if (!error)
+ error = inode_setattr(inode, attr);
return error;
}
@@ -660,7 +660,6 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
char buffer[PROC_NUMBUF];
size_t len;
int oom_adjust;
- loff_t __ppos = *ppos;
if (!task)
return -ESRCH;
@@ -668,14 +667,8 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
put_task_struct(task);
len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
- if (__ppos >= len)
- return 0;
- if (count > len-__ppos)
- count = len-__ppos;
- if (copy_to_user(buf, buffer + __ppos, count))
- return -EFAULT;
- *ppos = __ppos + count;
- return count;
+
+ return simple_read_from_buffer(buf, count, ppos, buffer, len);
}
static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
@@ -715,6 +708,42 @@ static const struct file_operations proc_oom_adjust_operations = {
.write = oom_adjust_write,
};
+#ifdef CONFIG_MMU
+static ssize_t clear_refs_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task;
+ char buffer[PROC_NUMBUF], *end;
+ struct mm_struct *mm;
+
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ return -EFAULT;
+ if (!simple_strtol(buffer, &end, 0))
+ return -EINVAL;
+ if (*end == '\n')
+ end++;
+ task = get_proc_task(file->f_path.dentry->d_inode);
+ if (!task)
+ return -ESRCH;
+ mm = get_task_mm(task);
+ if (mm) {
+ clear_refs_smap(mm);
+ mmput(mm);
+ }
+ put_task_struct(task);
+ if (end - buffer == 0)
+ return -EIO;
+ return end - buffer;
+}
+
+static struct file_operations proc_clear_refs_operations = {
+ .write = clear_refs_write,
+};
+#endif
+
#ifdef CONFIG_AUDITSYSCALL
#define TMPBUFLEN 21
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
@@ -789,7 +818,6 @@ static ssize_t seccomp_read(struct file *file, char __user *buf,
{
struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
char __buf[20];
- loff_t __ppos = *ppos;
size_t len;
if (!tsk)
@@ -797,14 +825,8 @@ static ssize_t seccomp_read(struct file *file, char __user *buf,
/* no need to print the trailing zero, so use only len */
len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
put_task_struct(tsk);
- if (__ppos >= len)
- return 0;
- if (count > len - __ppos)
- count = len - __ppos;
- if (copy_to_user(buf, __buf + __ppos, count))
- return -EFAULT;
- *ppos = __ppos + count;
- return count;
+
+ return simple_read_from_buffer(buf, count, ppos, __buf, len);
}
static ssize_t seccomp_write(struct file *file, const char __user *buf,
@@ -863,7 +885,6 @@ static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
char buffer[PROC_NUMBUF];
size_t len;
int make_it_fail;
- loff_t __ppos = *ppos;
if (!task)
return -ESRCH;
@@ -871,14 +892,8 @@ static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
put_task_struct(task);
len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
- if (__ppos >= len)
- return 0;
- if (count > len-__ppos)
- count = len-__ppos;
- if (copy_to_user(buf, buffer + __ppos, count))
- return -EFAULT;
- *ppos = __ppos + count;
- return count;
+
+ return simple_read_from_buffer(buf, count, ppos, buffer, len);
}
static ssize_t proc_fault_inject_write(struct file * file,
@@ -941,7 +956,7 @@ static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt,
if (!tmp)
return -ENOMEM;
-
+
inode = dentry->d_inode;
path = d_path(dentry, mnt, tmp, PAGE_SIZE);
len = PTR_ERR(path);
@@ -1121,7 +1136,8 @@ static struct dentry_operations pid_dentry_operations =
/* Lookups */
-typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *,
+ struct task_struct *, const void *);
/*
* Fill a directory entry.
@@ -1137,7 +1153,7 @@ typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct tas
*/
static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
char *name, int len,
- instantiate_t instantiate, struct task_struct *task, void *ptr)
+ instantiate_t instantiate, struct task_struct *task, const void *ptr)
{
struct dentry *child, *dir = filp->f_path.dentry;
struct inode *inode;
@@ -1199,7 +1215,10 @@ out:
return ~0U;
}
-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+#define PROC_FDINFO_MAX 64
+
+static int proc_fd_info(struct inode *inode, struct dentry **dentry,
+ struct vfsmount **mnt, char *info)
{
struct task_struct *task = get_proc_task(inode);
struct files_struct *files = NULL;
@@ -1218,8 +1237,16 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (file) {
- *mnt = mntget(file->f_path.mnt);
- *dentry = dget(file->f_path.dentry);
+ if (mnt)
+ *mnt = mntget(file->f_path.mnt);
+ if (dentry)
+ *dentry = dget(file->f_path.dentry);
+ if (info)
+ snprintf(info, PROC_FDINFO_MAX,
+ "pos:\t%lli\n"
+ "flags:\t0%o\n",
+ (long long) file->f_pos,
+ file->f_flags);
spin_unlock(&files->file_lock);
put_files_struct(files);
return 0;
@@ -1230,6 +1257,12 @@ static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsm
return -ENOENT;
}
+static int proc_fd_link(struct inode *inode, struct dentry **dentry,
+ struct vfsmount **mnt)
+{
+ return proc_fd_info(inode, dentry, mnt, NULL);
+}
+
static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
@@ -1272,9 +1305,9 @@ static struct dentry_operations tid_fd_dentry_operations =
};
static struct dentry *proc_fd_instantiate(struct inode *dir,
- struct dentry *dentry, struct task_struct *task, void *ptr)
+ struct dentry *dentry, struct task_struct *task, const void *ptr)
{
- unsigned fd = *(unsigned *)ptr;
+ unsigned fd = *(const unsigned *)ptr;
struct file *file;
struct files_struct *files;
struct inode *inode;
@@ -1325,7 +1358,9 @@ out_iput:
goto out;
}
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_lookupfd_common(struct inode *dir,
+ struct dentry *dentry,
+ instantiate_t instantiate)
{
struct task_struct *task = get_proc_task(dir);
unsigned fd = name_to_int(dentry);
@@ -1336,23 +1371,15 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
if (fd == ~0U)
goto out;
- result = proc_fd_instantiate(dir, dentry, task, &fd);
+ result = instantiate(dir, dentry, task, &fd);
out:
put_task_struct(task);
out_no_task:
return result;
}
-static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
- struct task_struct *task, int fd)
-{
- char name[PROC_NUMBUF];
- int len = snprintf(name, sizeof(name), "%d", fd);
- return proc_fill_cache(filp, dirent, filldir, name, len,
- proc_fd_instantiate, task, &fd);
-}
-
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+static int proc_readfd_common(struct file * filp, void * dirent,
+ filldir_t filldir, instantiate_t instantiate)
{
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
@@ -1388,12 +1415,17 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
for (fd = filp->f_pos-2;
fd < fdt->max_fds;
fd++, filp->f_pos++) {
+ char name[PROC_NUMBUF];
+ int len;
if (!fcheck_files(files, fd))
continue;
rcu_read_unlock();
- if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
+ len = snprintf(name, sizeof(name), "%d", fd);
+ if (proc_fill_cache(filp, dirent, filldir,
+ name, len, instantiate,
+ p, &fd) < 0) {
rcu_read_lock();
break;
}
@@ -1408,23 +1440,119 @@ out_no_task:
return retval;
}
+static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ return proc_lookupfd_common(dir, dentry, proc_fd_instantiate);
+}
+
+static int proc_readfd(struct file *filp, void *dirent, filldir_t filldir)
+{
+ return proc_readfd_common(filp, dirent, filldir, proc_fd_instantiate);
+}
+
+static ssize_t proc_fdinfo_read(struct file *file, char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ char tmp[PROC_FDINFO_MAX];
+ int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, NULL, tmp);
+ if (!err)
+ err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp));
+ return err;
+}
+
+static const struct file_operations proc_fdinfo_file_operations = {
+ .open = nonseekable_open,
+ .read = proc_fdinfo_read,
+};
+
static const struct file_operations proc_fd_operations = {
.read = generic_read_dir,
.readdir = proc_readfd,
};
/*
+ * /proc/pid/fd needs a special permission handler so that a process can still
+ * access /proc/self/fd after it has executed a setuid().
+ */
+static int proc_fd_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ int rv;
+
+ rv = generic_permission(inode, mask, NULL);
+ if (rv == 0)
+ return 0;
+ if (task_pid(current) == proc_pid(inode))
+ rv = 0;
+ return rv;
+}
+
+/*
* proc directories can do almost nothing..
*/
static const struct inode_operations proc_fd_inode_operations = {
.lookup = proc_lookupfd,
+ .permission = proc_fd_permission,
+ .setattr = proc_setattr,
+};
+
+static struct dentry *proc_fdinfo_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, const void *ptr)
+{
+ unsigned fd = *(unsigned *)ptr;
+ struct inode *inode;
+ struct proc_inode *ei;
+ struct dentry *error = ERR_PTR(-ENOENT);
+
+ inode = proc_pid_make_inode(dir->i_sb, task);
+ if (!inode)
+ goto out;
+ ei = PROC_I(inode);
+ ei->fd = fd;
+ inode->i_mode = S_IFREG | S_IRUSR;
+ inode->i_fop = &proc_fdinfo_file_operations;
+ dentry->d_op = &tid_fd_dentry_operations;
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (tid_fd_revalidate(dentry, NULL))
+ error = NULL;
+
+ out:
+ return error;
+}
+
+static struct dentry *proc_lookupfdinfo(struct inode *dir,
+ struct dentry *dentry,
+ struct nameidata *nd)
+{
+ return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate);
+}
+
+static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir)
+{
+ return proc_readfd_common(filp, dirent, filldir,
+ proc_fdinfo_instantiate);
+}
+
+static const struct file_operations proc_fdinfo_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_readfdinfo,
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+static const struct inode_operations proc_fdinfo_inode_operations = {
+ .lookup = proc_lookupfdinfo,
.setattr = proc_setattr,
};
+
static struct dentry *proc_pident_instantiate(struct inode *dir,
- struct dentry *dentry, struct task_struct *task, void *ptr)
+ struct dentry *dentry, struct task_struct *task, const void *ptr)
{
- struct pid_entry *p = ptr;
+ const struct pid_entry *p = ptr;
struct inode *inode;
struct proc_inode *ei;
struct dentry *error = ERR_PTR(-EINVAL);
@@ -1453,13 +1581,13 @@ out:
static struct dentry *proc_pident_lookup(struct inode *dir,
struct dentry *dentry,
- struct pid_entry *ents,
+ const struct pid_entry *ents,
unsigned int nents)
{
struct inode *inode;
struct dentry *error;
struct task_struct *task = get_proc_task(dir);
- struct pid_entry *p, *last;
+ const struct pid_entry *p, *last;
error = ERR_PTR(-ENOENT);
inode = NULL;
@@ -1488,8 +1616,8 @@ out_no_task:
return error;
}
-static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
- struct task_struct *task, struct pid_entry *p)
+static int proc_pident_fill_cache(struct file *filp, void *dirent,
+ filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
{
return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
proc_pident_instantiate, task, p);
@@ -1497,14 +1625,14 @@ static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t fil
static int proc_pident_readdir(struct file *filp,
void *dirent, filldir_t filldir,
- struct pid_entry *ents, unsigned int nents)
+ const struct pid_entry *ents, unsigned int nents)
{
int i;
int pid;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *task = get_proc_task(inode);
- struct pid_entry *p, *last;
+ const struct pid_entry *p, *last;
ino_t ino;
int ret;
@@ -1619,7 +1747,7 @@ static const struct file_operations proc_pid_attr_operations = {
.write = proc_pid_attr_write,
};
-static struct pid_entry attr_dir_stuff[] = {
+static const struct pid_entry attr_dir_stuff[] = {
REG("current", S_IRUGO|S_IWUGO, pid_attr),
REG("prev", S_IRUGO, pid_attr),
REG("exec", S_IRUGO|S_IWUGO, pid_attr),
@@ -1685,7 +1813,7 @@ static const struct inode_operations proc_self_inode_operations = {
* that properly belong to the /proc filesystem, as they describe
* describe something that is process related.
*/
-static struct pid_entry proc_base_stuff[] = {
+static const struct pid_entry proc_base_stuff[] = {
NOD("self", S_IFLNK|S_IRWXUGO,
&proc_self_inode_operations, NULL, {}),
};
@@ -1714,9 +1842,9 @@ static struct dentry_operations proc_base_dentry_operations =
};
static struct dentry *proc_base_instantiate(struct inode *dir,
- struct dentry *dentry, struct task_struct *task, void *ptr)
+ struct dentry *dentry, struct task_struct *task, const void *ptr)
{
- struct pid_entry *p = ptr;
+ const struct pid_entry *p = ptr;
struct inode *inode;
struct proc_inode *ei;
struct dentry *error = ERR_PTR(-EINVAL);
@@ -1764,7 +1892,7 @@ static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
{
struct dentry *error;
struct task_struct *task = get_proc_task(dir);
- struct pid_entry *p, *last;
+ const struct pid_entry *p, *last;
error = ERR_PTR(-ENOENT);
@@ -1790,8 +1918,8 @@ out_no_task:
return error;
}
-static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
- struct task_struct *task, struct pid_entry *p)
+static int proc_base_fill_cache(struct file *filp, void *dirent,
+ filldir_t filldir, struct task_struct *task, const struct pid_entry *p)
{
return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
proc_base_instantiate, task, p);
@@ -1828,9 +1956,10 @@ static int proc_pid_io_accounting(struct task_struct *task, char *buffer)
static const struct file_operations proc_task_operations;
static const struct inode_operations proc_task_inode_operations;
-static struct pid_entry tgid_base_stuff[] = {
+static const struct pid_entry tgid_base_stuff[] = {
DIR("task", S_IRUGO|S_IXUGO, task),
DIR("fd", S_IRUSR|S_IXUSR, fd),
+ DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo),
INF("environ", S_IRUSR, pid_environ),
INF("auxv", S_IRUSR, pid_auxv),
INF("status", S_IRUGO, pid_status),
@@ -1851,6 +1980,7 @@ static struct pid_entry tgid_base_stuff[] = {
REG("mounts", S_IRUGO, mounts),
REG("mountstats", S_IRUSR, mountstats),
#ifdef CONFIG_MMU
+ REG("clear_refs", S_IWUSR, clear_refs),
REG("smaps", S_IRUGO, smaps),
#endif
#ifdef CONFIG_SECURITY
@@ -1970,7 +2100,7 @@ out:
static struct dentry *proc_pid_instantiate(struct inode *dir,
struct dentry * dentry,
- struct task_struct *task, void *ptr)
+ struct task_struct *task, const void *ptr)
{
struct dentry *error = ERR_PTR(-ENOENT);
struct inode *inode;
@@ -1983,7 +2113,7 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
inode->i_op = &proc_tgid_base_inode_operations;
inode->i_fop = &proc_tgid_base_operations;
inode->i_flags|=S_IMMUTABLE;
- inode->i_nlink = 4;
+ inode->i_nlink = 5;
#ifdef CONFIG_SECURITY
inode->i_nlink += 1;
#endif
@@ -2085,7 +2215,7 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
goto out_no_task;
for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
- struct pid_entry *p = &proc_base_stuff[nr];
+ const struct pid_entry *p = &proc_base_stuff[nr];
if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
goto out;
}
@@ -2111,8 +2241,9 @@ out_no_task:
/*
* Tasks
*/
-static struct pid_entry tid_base_stuff[] = {
+static const struct pid_entry tid_base_stuff[] = {
DIR("fd", S_IRUSR|S_IXUSR, fd),
+ DIR("fdinfo", S_IRUSR|S_IXUSR, fdinfo),
INF("environ", S_IRUSR, pid_environ),
INF("auxv", S_IRUSR, pid_auxv),
INF("status", S_IRUGO, pid_status),
@@ -2132,6 +2263,7 @@ static struct pid_entry tid_base_stuff[] = {
LNK("exe", exe),
REG("mounts", S_IRUGO, mounts),
#ifdef CONFIG_MMU
+ REG("clear_refs", S_IWUSR, clear_refs),
REG("smaps", S_IRUGO, smaps),
#endif
#ifdef CONFIG_SECURITY
@@ -2180,7 +2312,7 @@ static const struct inode_operations proc_tid_base_inode_operations = {
};
static struct dentry *proc_task_instantiate(struct inode *dir,
- struct dentry *dentry, struct task_struct *task, void *ptr)
+ struct dentry *dentry, struct task_struct *task, const void *ptr)
{
struct dentry *error = ERR_PTR(-ENOENT);
struct inode *inode;
@@ -2192,7 +2324,7 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
inode->i_op = &proc_tid_base_inode_operations;
inode->i_fop = &proc_tid_base_operations;
inode->i_flags|=S_IMMUTABLE;
- inode->i_nlink = 3;
+ inode->i_nlink = 4;
#ifdef CONFIG_SECURITY
inode->i_nlink += 1;
#endif
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 775fb21294d..8a40e15f5ec 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -398,6 +398,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
unsigned int ino = de->low_ino;
+ de_get(de);
spin_unlock(&proc_subdir_lock);
error = -EINVAL;
inode = proc_get_inode(dir->i_sb, ino, de);
@@ -414,6 +415,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
d_add(dentry, inode);
return NULL;
}
+ de_put(de);
return ERR_PTR(error);
}
@@ -476,14 +478,21 @@ int proc_readdir(struct file * filp,
}
do {
+ struct proc_dir_entry *next;
+
/* filldir passes info to user space */
+ de_get(de);
spin_unlock(&proc_subdir_lock);
if (filldir(dirent, de->name, de->namelen, filp->f_pos,
- de->low_ino, de->mode >> 12) < 0)
+ de->low_ino, de->mode >> 12) < 0) {
+ de_put(de);
goto out;
+ }
spin_lock(&proc_subdir_lock);
filp->f_pos++;
- de = de->next;
+ next = de->next;
+ de_put(de);
+ de = next;
} while (de);
spin_unlock(&proc_subdir_lock);
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index c372eb151a3..b8171907c83 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -21,7 +21,7 @@
#include "internal.h"
-static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
+struct proc_dir_entry *de_get(struct proc_dir_entry *de)
{
if (de)
atomic_inc(&de->count);
@@ -31,7 +31,7 @@ static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
/*
* Decrements the use count and checks for deferred deletion.
*/
-static void de_put(struct proc_dir_entry *de)
+void de_put(struct proc_dir_entry *de)
{
if (de) {
lock_kernel();
@@ -109,8 +109,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct proc_inode *ei = (struct proc_inode *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
@@ -147,13 +146,6 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
{
struct inode * inode;
- /*
- * Increment the use count so the dir entry can't disappear.
- */
- de_get(de);
-
- WARN_ON(de && de->deleted);
-
if (de != NULL && !try_module_get(de->owner))
goto out_mod;
@@ -185,7 +177,6 @@ out_ino:
if (de != NULL)
module_put(de->owner);
out_mod:
- de_put(de);
return NULL;
}
@@ -200,6 +191,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent)
s->s_op = &proc_sops;
s->s_time_gran = 1;
+ de_get(&proc_root);
root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
if (!root_inode)
goto out_no_root;
@@ -213,6 +205,7 @@ int proc_fill_super(struct super_block *s, void *data, int silent)
out_no_root:
printk("proc_read_super: get root inode failed\n");
iput(root_inode);
+ de_put(&proc_root);
return -ENOMEM;
}
MODULE_LICENSE("GPL");
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index f771889183c..b215c3524fa 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -37,6 +37,8 @@ do { \
extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
#endif
+extern int maps_protect;
+
extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **);
extern int proc_tid_stat(struct task_struct *, char *);
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index abdf068bc27..eca471bc851 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -38,7 +38,7 @@ static int property_read_proc(char *page, char **start, off_t off,
n = count;
else
*eof = 1;
- memcpy(page, pp->value + off, n);
+ memcpy(page, (char *)pp->value + off, n);
*start = page;
return n;
}
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index e2c4c0a5c90..5fd49e47f83 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -35,7 +35,6 @@
#include <linux/signal.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/seq_file.h>
#include <linux/times.h>
#include <linux/profile.h>
@@ -398,8 +397,6 @@ static const struct file_operations proc_modules_operations = {
#endif
#ifdef CONFIG_SLAB
-extern struct seq_operations slabinfo_op;
-extern ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
static int slabinfo_open(struct inode *inode, struct file *file)
{
return seq_open(file, &slabinfo_op);
@@ -431,18 +428,11 @@ static int slabstats_open(struct inode *inode, struct file *file)
return ret;
}
-static int slabstats_release(struct inode *inode, struct file *file)
-{
- struct seq_file *m = file->private_data;
- kfree(m->private);
- return seq_release(inode, file);
-}
-
static const struct file_operations proc_slabstats_operations = {
.open = slabstats_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = slabstats_release,
+ .release = seq_release_private,
};
#endif
#endif
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 20e8cbb3436..680c429bfa2 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -429,11 +429,8 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
return -EPERM;
error = inode_change_ok(inode, attr);
- if (!error) {
- error = security_inode_setattr(dentry, attr);
- if (!error)
- error = inode_setattr(inode, attr);
- }
+ if (!error)
+ error = inode_setattr(inode, attr);
return error;
}
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index c1bbfbeb035..b3a473b0a19 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -108,6 +108,8 @@ static void *t_start(struct seq_file *m, loff_t *pos)
{
struct list_head *p;
loff_t l = *pos;
+
+ mutex_lock(&tty_mutex);
list_for_each(p, &tty_drivers)
if (!l--)
return list_entry(p, struct tty_driver, tty_drivers);
@@ -124,6 +126,7 @@ static void *t_next(struct seq_file *m, void *v, loff_t *pos)
static void t_stop(struct seq_file *m, void *v)
{
+ mutex_unlock(&tty_mutex);
}
static struct seq_operations tty_drivers_op = {
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7445980c802..c24d81a5a04 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -3,6 +3,7 @@
#include <linux/mount.h>
#include <linux/seq_file.h>
#include <linux/highmem.h>
+#include <linux/ptrace.h>
#include <linux/pagemap.h>
#include <linux/mempolicy.h>
@@ -120,6 +121,14 @@ struct mem_size_stats
unsigned long shared_dirty;
unsigned long private_clean;
unsigned long private_dirty;
+ unsigned long referenced;
+};
+
+struct pmd_walker {
+ struct vm_area_struct *vma;
+ void *private;
+ void (*action)(struct vm_area_struct *, pmd_t *, unsigned long,
+ unsigned long, void *);
};
static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
@@ -134,6 +143,9 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
dev_t dev = 0;
int len;
+ if (maps_protect && !ptrace_may_attach(task))
+ return -EACCES;
+
if (file) {
struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
dev = inode->i_sb->s_dev;
@@ -181,18 +193,20 @@ static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats
if (mss)
seq_printf(m,
- "Size: %8lu kB\n"
- "Rss: %8lu kB\n"
- "Shared_Clean: %8lu kB\n"
- "Shared_Dirty: %8lu kB\n"
- "Private_Clean: %8lu kB\n"
- "Private_Dirty: %8lu kB\n",
+ "Size: %8lu kB\n"
+ "Rss: %8lu kB\n"
+ "Shared_Clean: %8lu kB\n"
+ "Shared_Dirty: %8lu kB\n"
+ "Private_Clean: %8lu kB\n"
+ "Private_Dirty: %8lu kB\n"
+ "Referenced: %8lu kB\n",
(vma->vm_end - vma->vm_start) >> 10,
mss->resident >> 10,
mss->shared_clean >> 10,
mss->shared_dirty >> 10,
mss->private_clean >> 10,
- mss->private_dirty >> 10);
+ mss->private_dirty >> 10,
+ mss->referenced >> 10);
if (m->count < m->size) /* vma is copied successfully */
m->version = (vma != get_gate_vma(task))? vma->vm_start: 0;
@@ -205,15 +219,16 @@ static int show_map(struct seq_file *m, void *v)
}
static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
- unsigned long addr, unsigned long end,
- struct mem_size_stats *mss)
+ unsigned long addr, unsigned long end,
+ void *private)
{
+ struct mem_size_stats *mss = private;
pte_t *pte, ptent;
spinlock_t *ptl;
struct page *page;
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
- do {
+ for (; addr != end; pte++, addr += PAGE_SIZE) {
ptent = *pte;
if (!pte_present(ptent))
continue;
@@ -224,6 +239,9 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
if (!page)
continue;
+ /* Accumulate the size in pages that have been accessed. */
+ if (pte_young(ptent) || PageReferenced(page))
+ mss->referenced += PAGE_SIZE;
if (page_mapcount(page) >= 2) {
if (pte_dirty(ptent))
mss->shared_dirty += PAGE_SIZE;
@@ -235,57 +253,99 @@ static void smaps_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
else
mss->private_clean += PAGE_SIZE;
}
- } while (pte++, addr += PAGE_SIZE, addr != end);
+ }
pte_unmap_unlock(pte - 1, ptl);
cond_resched();
}
-static inline void smaps_pmd_range(struct vm_area_struct *vma, pud_t *pud,
- unsigned long addr, unsigned long end,
- struct mem_size_stats *mss)
+static void clear_refs_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ void *private)
+{
+ pte_t *pte, ptent;
+ spinlock_t *ptl;
+ struct page *page;
+
+ pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+ for (; addr != end; pte++, addr += PAGE_SIZE) {
+ ptent = *pte;
+ if (!pte_present(ptent))
+ continue;
+
+ page = vm_normal_page(vma, addr, ptent);
+ if (!page)
+ continue;
+
+ /* Clear accessed and referenced bits. */
+ ptep_test_and_clear_young(vma, addr, pte);
+ ClearPageReferenced(page);
+ }
+ pte_unmap_unlock(pte - 1, ptl);
+ cond_resched();
+}
+
+static inline void walk_pmd_range(struct pmd_walker *walker, pud_t *pud,
+ unsigned long addr, unsigned long end)
{
pmd_t *pmd;
unsigned long next;
- pmd = pmd_offset(pud, addr);
- do {
+ for (pmd = pmd_offset(pud, addr); addr != end;
+ pmd++, addr = next) {
next = pmd_addr_end(addr, end);
if (pmd_none_or_clear_bad(pmd))
continue;
- smaps_pte_range(vma, pmd, addr, next, mss);
- } while (pmd++, addr = next, addr != end);
+ walker->action(walker->vma, pmd, addr, next, walker->private);
+ }
}
-static inline void smaps_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
- unsigned long addr, unsigned long end,
- struct mem_size_stats *mss)
+static inline void walk_pud_range(struct pmd_walker *walker, pgd_t *pgd,
+ unsigned long addr, unsigned long end)
{
pud_t *pud;
unsigned long next;
- pud = pud_offset(pgd, addr);
- do {
+ for (pud = pud_offset(pgd, addr); addr != end;
+ pud++, addr = next) {
next = pud_addr_end(addr, end);
if (pud_none_or_clear_bad(pud))
continue;
- smaps_pmd_range(vma, pud, addr, next, mss);
- } while (pud++, addr = next, addr != end);
+ walk_pmd_range(walker, pud, addr, next);
+ }
}
-static inline void smaps_pgd_range(struct vm_area_struct *vma,
- unsigned long addr, unsigned long end,
- struct mem_size_stats *mss)
+/*
+ * walk_page_range - walk the page tables of a VMA with a callback
+ * @vma - VMA to walk
+ * @action - callback invoked for every bottom-level (PTE) page table
+ * @private - private data passed to the callback function
+ *
+ * Recursively walk the page table for the memory area in a VMA, calling
+ * a callback for every bottom-level (PTE) page table.
+ */
+static inline void walk_page_range(struct vm_area_struct *vma,
+ void (*action)(struct vm_area_struct *,
+ pmd_t *, unsigned long,
+ unsigned long, void *),
+ void *private)
{
+ unsigned long addr = vma->vm_start;
+ unsigned long end = vma->vm_end;
+ struct pmd_walker walker = {
+ .vma = vma,
+ .private = private,
+ .action = action,
+ };
pgd_t *pgd;
unsigned long next;
- pgd = pgd_offset(vma->vm_mm, addr);
- do {
+ for (pgd = pgd_offset(vma->vm_mm, addr); addr != end;
+ pgd++, addr = next) {
next = pgd_addr_end(addr, end);
if (pgd_none_or_clear_bad(pgd))
continue;
- smaps_pud_range(vma, pgd, addr, next, mss);
- } while (pgd++, addr = next, addr != end);
+ walk_pud_range(&walker, pgd, addr, next);
+ }
}
static int show_smap(struct seq_file *m, void *v)
@@ -295,10 +355,22 @@ static int show_smap(struct seq_file *m, void *v)
memset(&mss, 0, sizeof mss);
if (vma->vm_mm && !is_vm_hugetlb_page(vma))
- smaps_pgd_range(vma, vma->vm_start, vma->vm_end, &mss);
+ walk_page_range(vma, smaps_pte_range, &mss);
return show_map_internal(m, v, &mss);
}
+void clear_refs_smap(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ if (vma->vm_mm && !is_vm_hugetlb_page(vma))
+ walk_page_range(vma, clear_refs_pte_range, NULL);
+ flush_tlb_mm(mm);
+ up_read(&mm->mmap_sem);
+}
+
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct proc_maps_private *priv = m->private;
@@ -444,11 +516,22 @@ const struct file_operations proc_maps_operations = {
#ifdef CONFIG_NUMA
extern int show_numa_map(struct seq_file *m, void *v);
+static int show_numa_map_checked(struct seq_file *m, void *v)
+{
+ struct proc_maps_private *priv = m->private;
+ struct task_struct *task = priv->task;
+
+ if (maps_protect && !ptrace_may_attach(task))
+ return -EACCES;
+
+ return show_numa_map(m, v);
+}
+
static struct seq_operations proc_pid_numa_maps_op = {
.start = m_start,
.next = m_next,
.stop = m_stop,
- .show = show_numa_map
+ .show = show_numa_map_checked
};
static int numa_maps_open(struct inode *inode, struct file *file)
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 7cddf6b8635..d8b8c7183c2 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -2,6 +2,7 @@
#include <linux/mm.h>
#include <linux/file.h>
#include <linux/mount.h>
+#include <linux/ptrace.h>
#include <linux/seq_file.h>
#include "internal.h"
@@ -143,6 +144,12 @@ out:
static int show_map(struct seq_file *m, void *_vml)
{
struct vm_list_struct *vml = _vml;
+ struct proc_maps_private *priv = m->private;
+ struct task_struct *task = priv->task;
+
+ if (maps_protect && !ptrace_may_attach(task))
+ return -EACCES;
+
return nommu_vma_show(m, vml->vma);
}
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index d96050728c4..523e1098ae8 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -514,7 +514,7 @@ static int __init parse_crash_elf64_headers(void)
/* Do some basic Verification. */
if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
(ehdr.e_type != ET_CORE) ||
- !elf_check_arch(&ehdr) ||
+ !vmcore_elf_check_arch(&ehdr) ||
ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
ehdr.e_version != EV_CURRENT ||
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 83bc8e7824c..75fc8498f2e 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -536,8 +536,7 @@ static void init_once(void *foo, struct kmem_cache * cachep,
{
struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/quota.c b/fs/quota.c
index b9dae76a0b6..e9d88fd0eca 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -11,7 +11,6 @@
#include <asm/current.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/buffer_head.h>
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index d3fd7c6732d..3b481d557ed 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -16,7 +16,6 @@
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/backing-dev.h>
#include <linux/ramfs.h>
#include <linux/quotaops.h>
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index ff1f7639707..4ace5d72eae 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -30,7 +30,6 @@
#include <linux/time.h>
#include <linux/init.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/backing-dev.h>
#include <linux/ramfs.h>
diff --git a/fs/read_write.c b/fs/read_write.c
index 1f8dc373ede..4d03008f015 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -37,10 +37,10 @@ loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
mutex_lock(&inode->i_mutex);
switch (origin) {
- case 2:
+ case SEEK_END:
offset += inode->i_size;
break;
- case 1:
+ case SEEK_CUR:
offset += file->f_pos;
}
retval = -EINVAL;
@@ -63,10 +63,10 @@ loff_t remote_llseek(struct file *file, loff_t offset, int origin)
lock_kernel();
switch (origin) {
- case 2:
+ case SEEK_END:
offset += i_size_read(file->f_path.dentry->d_inode);
break;
- case 1:
+ case SEEK_CUR:
offset += file->f_pos;
}
retval = -EINVAL;
@@ -94,10 +94,10 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin)
lock_kernel();
switch (origin) {
- case 2:
+ case SEEK_END:
offset += i_size_read(file->f_path.dentry->d_inode);
break;
- case 1:
+ case SEEK_CUR:
offset += file->f_pos;
}
retval = -EINVAL;
@@ -139,7 +139,7 @@ asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
goto bad;
retval = -EINVAL;
- if (origin <= 2) {
+ if (origin <= SEEK_MAX) {
loff_t res = vfs_llseek(file, offset, origin);
retval = res;
if (res != (loff_t)retval)
@@ -166,7 +166,7 @@ asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high,
goto bad;
retval = -EINVAL;
- if (origin > 2)
+ if (origin > SEEK_MAX)
goto out_putf;
offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low,
diff --git a/fs/readdir.c b/fs/readdir.c
index f39f5b31325..efe52e67657 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -4,13 +4,13 @@
* Copyright (C) 1995 Linus Torvalds
*/
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/stat.h>
#include <linux/file.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/dirent.h>
#include <linux/security.h>
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(vfs_readdir);
* case (the low-level handlers don't need to care about this).
*/
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
#ifdef __ARCH_WANT_OLD_READDIR
@@ -147,7 +146,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
struct linux_dirent __user * dirent;
struct getdents_callback * buf = (struct getdents_callback *) __buf;
unsigned long d_ino;
- int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
+ int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 2, sizeof(long));
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
@@ -220,8 +219,6 @@ out:
return error;
}
-#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
-
struct getdents_callback64 {
struct linux_dirent64 __user * current_dir;
struct linux_dirent64 __user * previous;
@@ -234,7 +231,7 @@ static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
{
struct linux_dirent64 __user *dirent;
struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
- int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1);
+ int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 1, sizeof(u64));
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 96a2f8889da..9c23fee3bae 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -7,7 +7,6 @@
#include <linux/fs.h>
#include <linux/reiserfs_fs.h>
#include <linux/stat.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index abfada2f52d..9e451a68580 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -6,7 +6,6 @@
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h>
-#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
@@ -1060,20 +1059,12 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode
maping blocks, since there is none, so we just zero out remaining
parts of first and last pages in write area (if needed) */
if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) {
- if (from != 0) { /* First page needs to be partially zeroed */
- char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
- memset(kaddr, 0, from);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(prepared_pages[0]);
- }
- if (to != PAGE_CACHE_SIZE) { /* Last page needs to be partially zeroed */
- char *kaddr =
- kmap_atomic(prepared_pages[num_pages - 1],
- KM_USER0);
- memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(prepared_pages[num_pages - 1]);
- }
+ if (from != 0) /* First page needs to be partially zeroed */
+ zero_user_page(prepared_pages[0], 0, from, KM_USER0);
+
+ if (to != PAGE_CACHE_SIZE) /* Last page needs to be partially zeroed */
+ zero_user_page(prepared_pages[num_pages-1], to,
+ PAGE_CACHE_SIZE - to, KM_USER0);
/* Since all blocks are new - use already calculated value */
return blocks;
@@ -1200,13 +1191,9 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode
ll_rw_block(READ, 1, &bh);
*wait_bh++ = bh;
} else { /* Not mapped, zero it */
- char *kaddr =
- kmap_atomic(prepared_pages[0],
- KM_USER0);
- memset(kaddr + block_start, 0,
- from - block_start);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(prepared_pages[0]);
+ zero_user_page(prepared_pages[0],
+ block_start,
+ from - block_start, KM_USER0);
set_buffer_uptodate(bh);
}
}
@@ -1238,13 +1225,8 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode
ll_rw_block(READ, 1, &bh);
*wait_bh++ = bh;
} else { /* Not mapped, zero it */
- char *kaddr =
- kmap_atomic(prepared_pages
- [num_pages - 1],
- KM_USER0);
- memset(kaddr + to, 0, block_end - to);
- kunmap_atomic(kaddr, KM_USER0);
- flush_dcache_page(prepared_pages[num_pages - 1]);
+ zero_user_page(prepared_pages[num_pages-1],
+ to, block_end - to, KM_USER0);
set_buffer_uptodate(bh);
}
}
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 9fcbfe31697..1272d11399f 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -2148,13 +2148,8 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
length = offset & (blocksize - 1);
/* if we are not on a block boundary */
if (length) {
- char *kaddr;
-
length = blocksize - length;
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, length, KM_USER0);
if (buffer_mapped(bh) && bh->b_blocknr != 0) {
mark_buffer_dirty(bh);
}
@@ -2370,7 +2365,6 @@ static int reiserfs_write_full_page(struct page *page,
** last byte in the file
*/
if (page->index >= end_index) {
- char *kaddr;
unsigned last_offset;
last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
@@ -2379,10 +2373,7 @@ static int reiserfs_write_full_page(struct page *page,
unlock_page(page);
return 0;
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE - last_offset);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, last_offset, PAGE_CACHE_SIZE - last_offset, KM_USER0);
}
bh = head;
block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 7280a23ef34..f25086aeef5 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -1110,7 +1110,7 @@ static int flush_commit_list(struct super_block *s,
if (!barrier) {
/* If there was a write error in the journal - we can't commit
* this transaction - it will be invalid and, if successful,
- * will just end up propogating the write error out to
+ * will just end up propagating the write error out to
* the file system. */
if (likely(!retval && !reiserfs_is_journal_aborted (journal))) {
if (buffer_dirty(jl->j_commit_bh))
@@ -1125,7 +1125,7 @@ static int flush_commit_list(struct super_block *s,
/* If there was a write error in the journal - we can't commit this
* transaction - it will be invalid and, if successful, will just end
- * up propogating the write error out to the filesystem. */
+ * up propagating the write error out to the filesystem. */
if (unlikely(!buffer_uptodate(jl->j_commit_bh))) {
#ifdef CONFIG_REISERFS_CHECK
reiserfs_warning(s, "journal-615: buffer write failed");
@@ -2918,7 +2918,7 @@ static void queue_log_writer(struct super_block *s)
set_current_state(TASK_UNINTERRUPTIBLE);
if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
schedule();
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&journal->j_join_wait, &wait);
}
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index a2161840bc7..b378eea332c 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -16,7 +16,6 @@
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h>
-#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index ecc9943202f..9aa7a06e093 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -16,11 +16,10 @@
#include <asm/uaccess.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_fs_sb.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
-#if defined( REISERFS_PROC_INFO )
+#ifdef CONFIG_REISERFS_PROC_INFO
/*
* LOCKING:
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 315684793d1..976cc7887a0 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -131,6 +131,10 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
/* don't use read_bitmap_block since it will cache
* the uninitialized bitmap */
bh = sb_bread(s, i * s->s_blocksize * 8);
+ if (!bh) {
+ vfree(bitmap);
+ return -EIO;
+ }
memset(bh->b_data, 0, sb_blocksize(sb));
reiserfs_test_and_set_le_bit(0, bh->b_data);
reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index afb21ea4530..b6f12593c39 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -53,7 +53,6 @@
#include <linux/string.h>
#include <linux/pagemap.h>
#include <linux/reiserfs_fs.h>
-#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/quotaops.h>
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index f13a7f164dc..c7762140c42 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -18,7 +18,6 @@
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
@@ -433,12 +432,13 @@ int remove_save_link(struct inode *inode, int truncate)
static void reiserfs_kill_sb(struct super_block *s)
{
if (REISERFS_SB(s)) {
+#ifdef CONFIG_REISERFS_FS_XATTR
if (REISERFS_SB(s)->xattr_root) {
d_invalidate(REISERFS_SB(s)->xattr_root);
dput(REISERFS_SB(s)->xattr_root);
REISERFS_SB(s)->xattr_root = NULL;
}
-
+#endif
if (REISERFS_SB(s)->priv_root) {
d_invalidate(REISERFS_SB(s)->priv_root);
dput(REISERFS_SB(s)->priv_root);
@@ -511,8 +511,7 @@ static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags
{
struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
INIT_LIST_HEAD(&ei->i_prealloc_list);
inode_init_once(&ei->vfs_inode);
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
@@ -1563,9 +1562,10 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
/* Preallocate by 16 blocks (17-1) at once */
REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
+#ifdef CONFIG_REISERFS_FS_XATTR
/* Initialize the rwsem for xattr dir */
init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
-
+#endif
/* setup default block allocator options */
reiserfs_init_alloc_options(s);
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index c8178b7b921..bf6e5821453 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -68,7 +68,7 @@ static struct dentry *get_xa_root(struct super_block *sb, int flags)
if (!privroot)
return ERR_PTR(-ENODATA);
- mutex_lock(&privroot->d_inode->i_mutex);
+ mutex_lock_nested(&privroot->d_inode->i_mutex, I_MUTEX_XATTR);
if (REISERFS_SB(sb)->xattr_root) {
xaroot = dget(REISERFS_SB(sb)->xattr_root);
goto out;
@@ -410,11 +410,7 @@ static struct page *reiserfs_get_page(struct inode *dir, unsigned long n)
mapping_set_gfp_mask(mapping, GFP_NOFS);
page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
- if (!PageUptodate(page))
- goto fail;
-
if (PageError(page))
goto fail;
}
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index fd601014813..80428519027 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -570,8 +570,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct romfs_inode_info *ei = (struct romfs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/select.c b/fs/select.c
index fe0893afd93..a974082b082 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -14,10 +14,10 @@
* of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian).
*/
+#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/personality.h> /* for STICKY_TIMEOUTS */
#include <linux/file.h>
@@ -26,7 +26,6 @@
#include <asm/uaccess.h>
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)
struct poll_table_page {
@@ -65,7 +64,7 @@ EXPORT_SYMBOL(poll_initwait);
static void free_poll_entry(struct poll_table_entry *entry)
{
- remove_wait_queue(entry->wait_address,&entry->wait);
+ remove_wait_queue(entry->wait_address, &entry->wait);
fput(entry->filp);
}
@@ -129,7 +128,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
entry->filp = filp;
entry->wait_address = wait_address;
init_waitqueue_entry(&entry->wait, current);
- add_wait_queue(wait_address,&entry->wait);
+ add_wait_queue(wait_address, &entry->wait);
}
#define FDS_IN(fds, n) (fds->in + n)
@@ -399,7 +398,7 @@ asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp,
if ((u64)tv.tv_sec >= (u64)MAX_INT64_SECONDS)
timeout = -1; /* infinite */
else {
- timeout = ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
+ timeout = DIV_ROUND_UP(tv.tv_usec, USEC_PER_SEC/HZ);
timeout += tv.tv_sec * HZ;
}
}
@@ -454,7 +453,7 @@ asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp,
if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
timeout = -1; /* infinite */
else {
- timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
+ timeout = DIV_ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
timeout += ts.tv_sec * HZ;
}
}
@@ -776,7 +775,7 @@ asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
if ((u64)ts.tv_sec >= (u64)MAX_INT64_SECONDS)
timeout = -1; /* infinite */
else {
- timeout = ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
+ timeout = DIV_ROUND_UP(ts.tv_nsec, NSEC_PER_SEC/HZ);
timeout += ts.tv_sec * HZ;
}
}
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 5faba4f1c9a..424a3ddf86d 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -69,9 +69,8 @@ static void smb_destroy_inode(struct inode *inode)
static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
{
struct smb_inode_info *ei = (struct smb_inode_info *) foo;
- unsigned long flagmask = SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR;
- if ((flags & flagmask) == SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
index 723f7c66766..c288fbe7953 100644
--- a/fs/smbfs/request.c
+++ b/fs/smbfs/request.c
@@ -6,6 +6,7 @@
* Please add a note about your changes to smbfs in the ChangeLog file.
*/
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/slab.h>
@@ -22,8 +23,6 @@
/* #define SMB_SLAB_DEBUG (SLAB_RED_ZONE | SLAB_POISON) */
#define SMB_SLAB_DEBUG 0
-#define ROUND_UP(x) (((x)+3) & ~3)
-
/* cache for request structures */
static struct kmem_cache *req_cachep;
@@ -200,8 +199,8 @@ static int smb_setup_trans2request(struct smb_request *req)
const int smb_parameters = 15;
const int header = SMB_HEADER_LEN + 2 * smb_parameters + 2;
- const int oparam = ROUND_UP(header + 3);
- const int odata = ROUND_UP(oparam + req->rq_lparm);
+ const int oparam = ALIGN(header + 3, sizeof(u32));
+ const int odata = ALIGN(oparam + req->rq_lparm, sizeof(u32));
const int bcc = (req->rq_data ? odata + req->rq_ldata :
oparam + req->rq_lparm) - header;
diff --git a/fs/smbfs/smbiod.c b/fs/smbfs/smbiod.c
index 89eaf31f1d4..67176af8515 100644
--- a/fs/smbfs/smbiod.c
+++ b/fs/smbfs/smbiod.c
@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/file.h>
#include <linux/dcache.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/net.h>
#include <linux/kthread.h>
@@ -299,8 +298,6 @@ out:
*/
static int smbiod(void *unused)
{
- allow_signal(SIGKILL);
-
VERBOSE("SMB Kernel thread starting (%d) ...\n", current->pid);
for (;;) {
diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c
index 92ea6b2367d..e48bd8235a8 100644
--- a/fs/smbfs/sock.c
+++ b/fs/smbfs/sock.c
@@ -17,7 +17,6 @@
#include <linux/net.h>
#include <linux/mm.h>
#include <linux/netdevice.h>
-#include <linux/smp_lock.h>
#include <linux/workqueue.h>
#include <net/scm.h>
#include <net/tcp_states.h>
diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c
index fea20ceb8a5..00b2909bd46 100644
--- a/fs/smbfs/symlink.c
+++ b/fs/smbfs/symlink.c
@@ -13,7 +13,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include <linux/net.h>
#include <linux/namei.h>
diff --git a/fs/splice.c b/fs/splice.c
index 5428b0ff3b6..12f28281d2b 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -289,12 +289,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
nr_pages = PIPE_BUFFERS;
/*
- * Initiate read-ahead on this page range. however, don't call into
- * read-ahead if this is a non-zero offset (we are likely doing small
- * chunk splice and the page is already there) for a single page.
+ * Don't try to 2nd guess the read-ahead logic, call into
+ * page_cache_readahead() like the page cache reads would do.
*/
- if (!loff || nr_pages > 1)
- page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
+ page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
/*
* Now fill in the holes:
@@ -378,10 +376,11 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
* If in nonblock mode then dont block on waiting
* for an in-flight io page
*/
- if (flags & SPLICE_F_NONBLOCK)
- break;
-
- lock_page(page);
+ if (flags & SPLICE_F_NONBLOCK) {
+ if (TestSetPageLocked(page))
+ break;
+ } else
+ lock_page(page);
/*
* page was truncated, stop here. if this isn't the
diff --git a/fs/stat.c b/fs/stat.c
index 38a8cb2a28d..68510068a64 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -8,7 +8,6 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/file.h>
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/fs.h>
#include <linux/namei.h>
diff --git a/fs/super.c b/fs/super.c
index 8341e4e1d73..5260d620c55 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -107,6 +107,7 @@ out:
static inline void destroy_super(struct super_block *s)
{
security_sb_free(s);
+ kfree(s->s_subtype);
kfree(s);
}
@@ -907,6 +908,29 @@ out:
EXPORT_SYMBOL_GPL(vfs_kern_mount);
+static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
+{
+ int err;
+ const char *subtype = strchr(fstype, '.');
+ if (subtype) {
+ subtype++;
+ err = -EINVAL;
+ if (!subtype[0])
+ goto err;
+ } else
+ subtype = "";
+
+ mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
+ err = -ENOMEM;
+ if (!mnt->mnt_sb->s_subtype)
+ goto err;
+ return mnt;
+
+ err:
+ mntput(mnt);
+ return ERR_PTR(err);
+}
+
struct vfsmount *
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
{
@@ -915,6 +939,9 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
if (!type)
return ERR_PTR(-ENODEV);
mnt = vfs_kern_mount(type, flags, name, data);
+ if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
+ !mnt->mnt_sb->s_subtype)
+ mnt = fs_set_subtype(mnt, fstype);
put_filesystem(type);
return mnt;
}
diff --git a/fs/sync.c b/fs/sync.c
index 5cb9e7e4338..2f97576355b 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -229,7 +229,7 @@ asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
!S_ISLNK(i_mode))
goto out_put;
- ret = do_sync_file_range(file, offset, endbyte, flags);
+ ret = do_sync_mapping_range(file->f_mapping, offset, endbyte, flags);
out_put:
fput_light(file, fput_needed);
out:
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 8ea2a51ce88..d3b9f5f07db 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -59,7 +59,7 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
if (copy_to_user(userbuf, buffer, count))
return -EFAULT;
- pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
+ pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
*off = offs + count;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index db0413a411d..b502c7197ec 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -13,8 +13,7 @@
#include "sysfs.h"
-#define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
-#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
+#define to_sattr(a) container_of(a,struct subsys_attribute, attr)
/*
* Subsystem file operations.
@@ -24,12 +23,12 @@
static ssize_t
subsys_attr_show(struct kobject * kobj, struct attribute * attr, char * page)
{
- struct subsystem * s = to_subsys(kobj);
+ struct kset *kset = to_kset(kobj);
struct subsys_attribute * sattr = to_sattr(attr);
ssize_t ret = -EIO;
if (sattr->show)
- ret = sattr->show(s,page);
+ ret = sattr->show(kset, page);
return ret;
}
@@ -37,12 +36,12 @@ static ssize_t
subsys_attr_store(struct kobject * kobj, struct attribute * attr,
const char * page, size_t count)
{
- struct subsystem * s = to_subsys(kobj);
+ struct kset *kset = to_kset(kobj);
struct subsys_attribute * sattr = to_sattr(attr);
ssize_t ret = -EIO;
if (sattr->store)
- ret = sattr->store(s,page,count);
+ ret = sattr->store(kset, page, count);
return ret;
}
@@ -112,36 +111,6 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
return ret;
}
-
-/**
- * flush_read_buffer - push buffer to userspace.
- * @buffer: data buffer for file.
- * @buf: user-passed buffer.
- * @count: number of bytes requested.
- * @ppos: file position.
- *
- * Copy the buffer we filled in fill_read_buffer() to userspace.
- * This is done at the reader's leisure, copying and advancing
- * the amount they specify each time.
- * This may be called continuously until the buffer is empty.
- */
-static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf,
- size_t count, loff_t * ppos)
-{
- int error;
-
- if (*ppos > buffer->count)
- return 0;
-
- if (count > (buffer->count - *ppos))
- count = buffer->count - *ppos;
-
- error = copy_to_user(buf,buffer->page + *ppos,count);
- if (!error)
- *ppos += count;
- return error ? -EFAULT : count;
-}
-
/**
* sysfs_read_file - read an attribute.
* @file: file pointer.
@@ -178,7 +147,8 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
__FUNCTION__, count, *ppos, buffer->page);
- retval = flush_read_buffer(buffer,buf,count,ppos);
+ retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
+ buffer->count);
out:
up(&buffer->sem);
return retval;
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index ebf7007fa16..e566b387fcf 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -54,17 +54,9 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
- if (!IS_ERR(page)) {
- wait_on_page_locked(page);
+ if (!IS_ERR(page))
kmap(page);
- if (!PageUptodate(page))
- goto fail;
- }
return page;
-
-fail:
- dir_put_page(page);
- return ERR_PTR(-EIO);
}
static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 9311cac186f..3152d741560 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -322,8 +322,7 @@ static void init_once(void *p, struct kmem_cache *cachep, unsigned long flags)
{
struct sysv_inode_info *si = (struct sysv_inode_info *)p;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&si->vfs_inode);
}
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index 4e48abbd2b5..6bd850b7641 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -13,7 +13,6 @@
*/
#include <linux/pagemap.h>
-#include <linux/smp_lock.h>
#include "sysv.h"
static int add_nondir(struct dentry *dentry, struct inode *inode)
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index ea521f846d9..4cec9101568 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -427,9 +427,9 @@ static void udf_table_free_blocks(struct super_block * sb,
{
struct udf_sb_info *sbi = UDF_SB(sb);
uint32_t start, end;
- uint32_t nextoffset, oextoffset, elen;
- kernel_lb_addr nbloc, obloc, eloc;
- struct buffer_head *obh, *nbh;
+ uint32_t elen;
+ kernel_lb_addr eloc;
+ struct extent_position oepos, epos;
int8_t etype;
int i;
@@ -457,14 +457,13 @@ static void udf_table_free_blocks(struct super_block * sb,
start = bloc.logicalBlockNum + offset;
end = bloc.logicalBlockNum + offset + count - 1;
- oextoffset = nextoffset = sizeof(struct unallocSpaceEntry);
+ epos.offset = oepos.offset = sizeof(struct unallocSpaceEntry);
elen = 0;
- obloc = nbloc = UDF_I_LOCATION(table);
-
- obh = nbh = NULL;
+ epos.block = oepos.block = UDF_I_LOCATION(table);
+ epos.bh = oepos.bh = NULL;
while (count && (etype =
- udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+ udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
{
if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
start))
@@ -482,7 +481,7 @@ static void udf_table_free_blocks(struct super_block * sb,
start += count;
count = 0;
}
- udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+ udf_write_aext(table, &oepos, eloc, elen, 1);
}
else if (eloc.logicalBlockNum == (end + 1))
{
@@ -502,20 +501,20 @@ static void udf_table_free_blocks(struct super_block * sb,
end -= count;
count = 0;
}
- udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1);
+ udf_write_aext(table, &oepos, eloc, elen, 1);
}
- if (nbh != obh)
+ if (epos.bh != oepos.bh)
{
i = -1;
- obloc = nbloc;
- udf_release_data(obh);
- atomic_inc(&nbh->b_count);
- obh = nbh;
- oextoffset = 0;
+ oepos.block = epos.block;
+ brelse(oepos.bh);
+ get_bh(epos.bh);
+ oepos.bh = epos.bh;
+ oepos.offset = 0;
}
else
- oextoffset = nextoffset;
+ oepos.offset = epos.offset;
}
if (count)
@@ -547,55 +546,53 @@ static void udf_table_free_blocks(struct super_block * sb,
adsize = sizeof(long_ad);
else
{
- udf_release_data(obh);
- udf_release_data(nbh);
+ brelse(oepos.bh);
+ brelse(epos.bh);
goto error_return;
}
- if (nextoffset + (2 * adsize) > sb->s_blocksize)
+ if (epos.offset + (2 * adsize) > sb->s_blocksize)
{
char *sptr, *dptr;
int loffset;
- udf_release_data(obh);
- obh = nbh;
- obloc = nbloc;
- oextoffset = nextoffset;
+ brelse(oepos.bh);
+ oepos = epos;
/* Steal a block from the extent being free'd */
- nbloc.logicalBlockNum = eloc.logicalBlockNum;
+ epos.block.logicalBlockNum = eloc.logicalBlockNum;
eloc.logicalBlockNum ++;
elen -= sb->s_blocksize;
- if (!(nbh = udf_tread(sb,
- udf_get_lb_pblock(sb, nbloc, 0))))
+ if (!(epos.bh = udf_tread(sb,
+ udf_get_lb_pblock(sb, epos.block, 0))))
{
- udf_release_data(obh);
+ brelse(oepos.bh);
goto error_return;
}
- aed = (struct allocExtDesc *)(nbh->b_data);
- aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
- if (nextoffset + adsize > sb->s_blocksize)
+ aed = (struct allocExtDesc *)(epos.bh->b_data);
+ aed->previousAllocExtLocation = cpu_to_le32(oepos.block.logicalBlockNum);
+ if (epos.offset + adsize > sb->s_blocksize)
{
- loffset = nextoffset;
+ loffset = epos.offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
- sptr = UDF_I_DATA(inode) + nextoffset -
+ sptr = UDF_I_DATA(inode) + epos.offset -
udf_file_entry_alloc_offset(inode) +
UDF_I_LENEATTR(inode) - adsize;
- dptr = nbh->b_data + sizeof(struct allocExtDesc);
+ dptr = epos.bh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
- nextoffset = sizeof(struct allocExtDesc) + adsize;
+ epos.offset = sizeof(struct allocExtDesc) + adsize;
}
else
{
- loffset = nextoffset + adsize;
+ loffset = epos.offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
- sptr = (obh)->b_data + nextoffset;
- nextoffset = sizeof(struct allocExtDesc);
+ sptr = oepos.bh->b_data + epos.offset;
+ epos.offset = sizeof(struct allocExtDesc);
- if (obh)
+ if (oepos.bh)
{
- aed = (struct allocExtDesc *)(obh)->b_data;
+ aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
}
@@ -606,11 +603,11 @@ static void udf_table_free_blocks(struct super_block * sb,
}
}
if (UDF_SB_UDFREV(sb) >= 0x0200)
- udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
- nbloc.logicalBlockNum, sizeof(tag));
+ udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3, 1,
+ epos.block.logicalBlockNum, sizeof(tag));
else
- udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
- nbloc.logicalBlockNum, sizeof(tag));
+ udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 2, 1,
+ epos.block.logicalBlockNum, sizeof(tag));
switch (UDF_I_ALLOCTYPE(table))
{
case ICBTAG_FLAG_AD_SHORT:
@@ -619,7 +616,7 @@ static void udf_table_free_blocks(struct super_block * sb,
sad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
sb->s_blocksize);
- sad->extPosition = cpu_to_le32(nbloc.logicalBlockNum);
+ sad->extPosition = cpu_to_le32(epos.block.logicalBlockNum);
break;
}
case ICBTAG_FLAG_AD_LONG:
@@ -628,14 +625,14 @@ static void udf_table_free_blocks(struct super_block * sb,
lad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
sb->s_blocksize);
- lad->extLocation = cpu_to_lelb(nbloc);
+ lad->extLocation = cpu_to_lelb(epos.block);
break;
}
}
- if (obh)
+ if (oepos.bh)
{
- udf_update_tag(obh->b_data, loffset);
- mark_buffer_dirty(obh);
+ udf_update_tag(oepos.bh->b_data, loffset);
+ mark_buffer_dirty(oepos.bh);
}
else
mark_inode_dirty(table);
@@ -643,26 +640,26 @@ static void udf_table_free_blocks(struct super_block * sb,
if (elen) /* It's possible that stealing the block emptied the extent */
{
- udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1);
+ udf_write_aext(table, &epos, eloc, elen, 1);
- if (!nbh)
+ if (!epos.bh)
{
UDF_I_LENALLOC(table) += adsize;
mark_inode_dirty(table);
}
else
{
- aed = (struct allocExtDesc *)nbh->b_data;
+ aed = (struct allocExtDesc *)epos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- udf_update_tag(nbh->b_data, nextoffset);
- mark_buffer_dirty(nbh);
+ udf_update_tag(epos.bh->b_data, epos.offset);
+ mark_buffer_dirty(epos.bh);
}
}
}
- udf_release_data(nbh);
- udf_release_data(obh);
+ brelse(epos.bh);
+ brelse(oepos.bh);
error_return:
sb->s_dirt = 1;
@@ -677,9 +674,9 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
{
struct udf_sb_info *sbi = UDF_SB(sb);
int alloc_count = 0;
- uint32_t extoffset, elen, adsize;
- kernel_lb_addr bloc, eloc;
- struct buffer_head *bh;
+ uint32_t elen, adsize;
+ kernel_lb_addr eloc;
+ struct extent_position epos;
int8_t etype = -1;
if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition))
@@ -693,14 +690,13 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
return 0;
mutex_lock(&sbi->s_alloc_mutex);
- extoffset = sizeof(struct unallocSpaceEntry);
- bloc = UDF_I_LOCATION(table);
-
- bh = NULL;
+ epos.offset = sizeof(struct unallocSpaceEntry);
+ epos.block = UDF_I_LOCATION(table);
+ epos.bh = NULL;
eloc.logicalBlockNum = 0xFFFFFFFF;
while (first_block != eloc.logicalBlockNum && (etype =
- udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+ udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
{
udf_debug("eloc=%d, elen=%d, first_block=%d\n",
eloc.logicalBlockNum, elen, first_block);
@@ -709,7 +705,7 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
if (first_block == eloc.logicalBlockNum)
{
- extoffset -= adsize;
+ epos.offset -= adsize;
alloc_count = (elen >> sb->s_blocksize_bits);
if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
@@ -719,15 +715,15 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
alloc_count = block_count;
eloc.logicalBlockNum += alloc_count;
elen -= (alloc_count << sb->s_blocksize_bits);
- udf_write_aext(table, bloc, &extoffset, eloc, (etype << 30) | elen, bh, 1);
+ udf_write_aext(table, &epos, eloc, (etype << 30) | elen, 1);
}
else
- udf_delete_aext(table, bloc, extoffset, eloc, (etype << 30) | elen, bh);
+ udf_delete_aext(table, epos, eloc, (etype << 30) | elen);
}
else
alloc_count = 0;
- udf_release_data(bh);
+ brelse(epos.bh);
if (alloc_count && UDF_SB_LVIDBH(sb))
{
@@ -747,9 +743,9 @@ static int udf_table_new_block(struct super_block * sb,
struct udf_sb_info *sbi = UDF_SB(sb);
uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
uint32_t newblock = 0, adsize;
- uint32_t extoffset, goal_extoffset, elen, goal_elen = 0;
- kernel_lb_addr bloc, goal_bloc, eloc, goal_eloc;
- struct buffer_head *bh, *goal_bh;
+ uint32_t elen, goal_elen = 0;
+ kernel_lb_addr eloc, goal_eloc;
+ struct extent_position epos, goal_epos;
int8_t etype;
*err = -ENOSPC;
@@ -770,14 +766,12 @@ static int udf_table_new_block(struct super_block * sb,
We store the buffer_head, bloc, and extoffset of the current closest
match and use that when we are done.
*/
-
- extoffset = sizeof(struct unallocSpaceEntry);
- bloc = UDF_I_LOCATION(table);
-
- goal_bh = bh = NULL;
+ epos.offset = sizeof(struct unallocSpaceEntry);
+ epos.block = UDF_I_LOCATION(table);
+ epos.bh = goal_epos.bh = NULL;
while (spread && (etype =
- udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+ udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
{
if (goal >= eloc.logicalBlockNum)
{
@@ -793,24 +787,24 @@ static int udf_table_new_block(struct super_block * sb,
if (nspread < spread)
{
spread = nspread;
- if (goal_bh != bh)
+ if (goal_epos.bh != epos.bh)
{
- udf_release_data(goal_bh);
- goal_bh = bh;
- atomic_inc(&goal_bh->b_count);
+ brelse(goal_epos.bh);
+ goal_epos.bh = epos.bh;
+ get_bh(goal_epos.bh);
}
- goal_bloc = bloc;
- goal_extoffset = extoffset - adsize;
+ goal_epos.block = epos.block;
+ goal_epos.offset = epos.offset - adsize;
goal_eloc = eloc;
goal_elen = (etype << 30) | elen;
}
}
- udf_release_data(bh);
+ brelse(epos.bh);
if (spread == 0xFFFFFFFF)
{
- udf_release_data(goal_bh);
+ brelse(goal_epos.bh);
mutex_unlock(&sbi->s_alloc_mutex);
return 0;
}
@@ -826,17 +820,17 @@ static int udf_table_new_block(struct super_block * sb,
if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
{
- udf_release_data(goal_bh);
+ brelse(goal_epos.bh);
mutex_unlock(&sbi->s_alloc_mutex);
*err = -EDQUOT;
return 0;
}
if (goal_elen)
- udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1);
+ udf_write_aext(table, &goal_epos, goal_eloc, goal_elen, 1);
else
- udf_delete_aext(table, goal_bloc, goal_extoffset, goal_eloc, goal_elen, goal_bh);
- udf_release_data(goal_bh);
+ udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
+ brelse(goal_epos.bh);
if (UDF_SB_LVIDBH(sb))
{
@@ -921,11 +915,14 @@ inline int udf_new_block(struct super_block * sb,
struct inode * inode,
uint16_t partition, uint32_t goal, int *err)
{
+ int ret;
+
if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
{
- return udf_bitmap_new_block(sb, inode,
+ ret = udf_bitmap_new_block(sb, inode,
UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
partition, goal, err);
+ return ret;
}
else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
{
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index 2391c9150c4..e45f86b5e7b 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -111,11 +111,13 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
uint16_t liu;
uint8_t lfi;
loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
- struct buffer_head * bh = NULL, * tmp, * bha[16];
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
+ struct buffer_head *tmp, *bha[16];
+ kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
int i, num;
unsigned int dt_type;
+ struct extent_position epos = { NULL, 0, {0, 0}};
if (nf_pos >= size)
return 0;
@@ -127,23 +129,22 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
fibh.sbh = fibh.ebh = NULL;
else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
{
- offset >>= dir->i_sb->s_blocksize_bits;
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
+ epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
+ epos.offset -= sizeof(long_ad);
}
else
offset = 0;
if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
{
- udf_release_data(bh);
+ brelse(epos.bh);
return -EIO;
}
@@ -171,7 +172,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
}
else
{
- udf_release_data(bh);
+ brelse(epos.bh);
return -ENOENT;
}
@@ -179,14 +180,14 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
{
filp->f_pos = nf_pos + 1;
- fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
if (!fi)
{
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
@@ -244,9 +245,9 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
{
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
}
@@ -255,9 +256,9 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
filp->f_pos = nf_pos + 1;
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index fe751a2a0e4..198caa33027 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -36,14 +36,14 @@ udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
if (!ad)
{
- udf_release_data(*bh);
+ brelse(*bh);
*error = 1;
return NULL;
}
if (*offset == dir->i_sb->s_blocksize)
{
- udf_release_data(*bh);
+ brelse(*bh);
block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
if (!block)
return NULL;
@@ -57,7 +57,7 @@ udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
remainder = dir->i_sb->s_blocksize - loffset;
memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
- udf_release_data(*bh);
+ brelse(*bh);
block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
if (!block)
return NULL;
@@ -75,9 +75,9 @@ struct fileIdentDesc *
udf_fileident_read(struct inode *dir, loff_t *nf_pos,
struct udf_fileident_bh *fibh,
struct fileIdentDesc *cfi,
- kernel_lb_addr *bloc, uint32_t *extoffset,
+ struct extent_position *epos,
kernel_lb_addr *eloc, uint32_t *elen,
- uint32_t *offset, struct buffer_head **bh)
+ sector_t *offset)
{
struct fileIdentDesc *fi;
int i, num, block;
@@ -105,13 +105,11 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
if (fibh->eoffset == dir->i_sb->s_blocksize)
{
- int lextoffset = *extoffset;
+ int lextoffset = epos->offset;
- if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
+ if (udf_next_aext(dir, epos, eloc, elen, 1) !=
(EXT_RECORDED_ALLOCATED >> 30))
- {
return NULL;
- }
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
@@ -120,9 +118,9 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
*offset = 0;
else
- *extoffset = lextoffset;
+ epos->offset = lextoffset;
- udf_release_data(fibh->sbh);
+ brelse(fibh->sbh);
if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
return NULL;
fibh->soffset = fibh->eoffset = 0;
@@ -151,7 +149,7 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
}
else if (fibh->sbh != fibh->ebh)
{
- udf_release_data(fibh->sbh);
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
@@ -169,13 +167,11 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
}
else if (fibh->eoffset > dir->i_sb->s_blocksize)
{
- int lextoffset = *extoffset;
+ int lextoffset = epos->offset;
- if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
+ if (udf_next_aext(dir, epos, eloc, elen, 1) !=
(EXT_RECORDED_ALLOCATED >> 30))
- {
return NULL;
- }
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
@@ -184,7 +180,7 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
*offset = 0;
else
- *extoffset = lextoffset;
+ epos->offset = lextoffset;
fibh->soffset -= dir->i_sb->s_blocksize;
fibh->eoffset -= dir->i_sb->s_blocksize;
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index 5887d78cde4..6ded93e7c44 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -21,7 +21,6 @@
#include "udfdecl.h"
#include <linux/fs.h>
-#include <linux/smp_lock.h>
static int udf_fsync_inode(struct inode *, int);
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index ae21a0e59e9..c8461551e10 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -49,10 +49,10 @@ MODULE_LICENSE("GPL");
static mode_t udf_convert_permissions(struct fileEntry *);
static int udf_update_inode(struct inode *, int);
static void udf_fill_inode(struct inode *, struct buffer_head *);
-static struct buffer_head *inode_getblk(struct inode *, long, int *,
+static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
long *, int *);
-static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int,
- kernel_lb_addr, uint32_t, struct buffer_head *);
+static int8_t udf_insert_aext(struct inode *, struct extent_position,
+ kernel_lb_addr, uint32_t);
static void udf_split_extents(struct inode *, int *, int, int,
kernel_long_ad [EXTENT_MERGE_SIZE], int *);
static void udf_prealloc_extents(struct inode *, int, int,
@@ -61,7 +61,7 @@ static void udf_merge_extents(struct inode *,
kernel_long_ad [EXTENT_MERGE_SIZE], int *);
static void udf_update_extents(struct inode *,
kernel_long_ad [EXTENT_MERGE_SIZE], int, int,
- kernel_lb_addr, uint32_t, struct buffer_head **);
+ struct extent_position *);
static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
/*
@@ -194,10 +194,11 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
{
int newblock;
- struct buffer_head *sbh = NULL, *dbh = NULL;
- kernel_lb_addr bloc, eloc;
- uint32_t elen, extoffset;
+ struct buffer_head *dbh = NULL;
+ kernel_lb_addr eloc;
+ uint32_t elen;
uint8_t alloctype;
+ struct extent_position epos;
struct udf_fileident_bh sfibh, dfibh;
loff_t f_pos = udf_ext0_offset(inode) >> 2;
@@ -237,16 +238,16 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
mark_buffer_dirty_inode(dbh, inode);
sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2;
- sbh = sfibh.sbh = sfibh.ebh = NULL;
+ sfibh.sbh = sfibh.ebh = NULL;
dfibh.soffset = dfibh.eoffset = 0;
dfibh.sbh = dfibh.ebh = dbh;
while ( (f_pos < size) )
{
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
- sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL);
+ sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
if (!sfi)
{
- udf_release_data(dbh);
+ brelse(dbh);
return NULL;
}
UDF_I_ALLOCTYPE(inode) = alloctype;
@@ -258,7 +259,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse)))
{
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
- udf_release_data(dbh);
+ brelse(dbh);
return NULL;
}
}
@@ -266,16 +267,17 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode));
UDF_I_LENALLOC(inode) = 0;
- bloc = UDF_I_LOCATION(inode);
eloc.logicalBlockNum = *block;
eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
elen = inode->i_size;
UDF_I_LENEXTENTS(inode) = elen;
- extoffset = udf_file_entry_alloc_offset(inode);
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0);
+ epos.bh = NULL;
+ epos.block = UDF_I_LOCATION(inode);
+ epos.offset = udf_file_entry_alloc_offset(inode);
+ udf_add_aext(inode, &epos, eloc, elen, 0);
/* UniqueID stuff */
- udf_release_data(sbh);
+ brelse(epos.bh);
mark_inode_dirty(inode);
return dbh;
}
@@ -354,53 +356,153 @@ udf_getblk(struct inode *inode, long block, int create, int *err)
return NULL;
}
-static struct buffer_head * inode_getblk(struct inode * inode, long block,
+/* Extend the file by 'blocks' blocks, return the number of extents added */
+int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
+ kernel_long_ad *last_ext, sector_t blocks)
+{
+ sector_t add;
+ int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+ struct super_block *sb = inode->i_sb;
+ kernel_lb_addr prealloc_loc = {0, 0};
+ int prealloc_len = 0;
+
+ /* The previous extent is fake and we should not extend by anything
+ * - there's nothing to do... */
+ if (!blocks && fake)
+ return 0;
+ /* Round the last extent up to a multiple of block size */
+ if (last_ext->extLength & (sb->s_blocksize - 1)) {
+ last_ext->extLength =
+ (last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
+ (((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
+ sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+ UDF_I_LENEXTENTS(inode) =
+ (UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
+ ~(sb->s_blocksize - 1);
+ }
+ /* Last extent are just preallocated blocks? */
+ if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) {
+ /* Save the extent so that we can reattach it to the end */
+ prealloc_loc = last_ext->extLocation;
+ prealloc_len = last_ext->extLength;
+ /* Mark the extent as a hole */
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ (last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
+ last_ext->extLocation.logicalBlockNum = 0;
+ last_ext->extLocation.partitionReferenceNum = 0;
+ }
+ /* Can we merge with the previous extent? */
+ if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) {
+ add = ((1<<30) - sb->s_blocksize - (last_ext->extLength &
+ UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
+ if (add > blocks)
+ add = blocks;
+ blocks -= add;
+ last_ext->extLength += add << sb->s_blocksize_bits;
+ }
+
+ if (fake) {
+ udf_add_aext(inode, last_pos, last_ext->extLocation,
+ last_ext->extLength, 1);
+ count++;
+ }
+ else
+ udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1);
+ /* Managed to do everything necessary? */
+ if (!blocks)
+ goto out;
+
+ /* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
+ last_ext->extLocation.logicalBlockNum = 0;
+ last_ext->extLocation.partitionReferenceNum = 0;
+ add = (1 << (30-sb->s_blocksize_bits)) - 1;
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
+ /* Create enough extents to cover the whole hole */
+ while (blocks > add) {
+ blocks -= add;
+ if (udf_add_aext(inode, last_pos, last_ext->extLocation,
+ last_ext->extLength, 1) == -1)
+ return -1;
+ count++;
+ }
+ if (blocks) {
+ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ (blocks << sb->s_blocksize_bits);
+ if (udf_add_aext(inode, last_pos, last_ext->extLocation,
+ last_ext->extLength, 1) == -1)
+ return -1;
+ count++;
+ }
+out:
+ /* Do we have some preallocated blocks saved? */
+ if (prealloc_len) {
+ if (udf_add_aext(inode, last_pos, prealloc_loc, prealloc_len, 1) == -1)
+ return -1;
+ last_ext->extLocation = prealloc_loc;
+ last_ext->extLength = prealloc_len;
+ count++;
+ }
+ /* last_pos should point to the last written extent... */
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
+ last_pos->offset -= sizeof(short_ad);
+ else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
+ last_pos->offset -= sizeof(long_ad);
+ else
+ return -1;
+ return count;
+}
+
+static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
int *err, long *phys, int *new)
{
- struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL;
+ static sector_t last_block;
+ struct buffer_head *result = NULL;
kernel_long_ad laarr[EXTENT_MERGE_SIZE];
- uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0;
+ struct extent_position prev_epos, cur_epos, next_epos;
int count = 0, startnum = 0, endnum = 0;
uint32_t elen = 0;
- kernel_lb_addr eloc, pbloc, cbloc, nbloc;
+ kernel_lb_addr eloc;
int c = 1;
- uint64_t lbcount = 0, b_off = 0;
- uint32_t newblocknum, newblock, offset = 0;
+ loff_t lbcount = 0, b_off = 0;
+ uint32_t newblocknum, newblock;
+ sector_t offset = 0;
int8_t etype;
int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum;
- char lastblock = 0;
+ int lastblock = 0;
- pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode);
- b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits;
- pbloc = cbloc = nbloc = UDF_I_LOCATION(inode);
+ prev_epos.offset = udf_file_entry_alloc_offset(inode);
+ prev_epos.block = UDF_I_LOCATION(inode);
+ prev_epos.bh = NULL;
+ cur_epos = next_epos = prev_epos;
+ b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;
/* find the extent which contains the block we are looking for.
alternate between laarr[0] and laarr[1] for locations of the
current extent, and the previous extent */
do
{
- if (pbh != cbh)
+ if (prev_epos.bh != cur_epos.bh)
{
- udf_release_data(pbh);
- atomic_inc(&cbh->b_count);
- pbh = cbh;
+ brelse(prev_epos.bh);
+ get_bh(cur_epos.bh);
+ prev_epos.bh = cur_epos.bh;
}
- if (cbh != nbh)
+ if (cur_epos.bh != next_epos.bh)
{
- udf_release_data(cbh);
- atomic_inc(&nbh->b_count);
- cbh = nbh;
+ brelse(cur_epos.bh);
+ get_bh(next_epos.bh);
+ cur_epos.bh = next_epos.bh;
}
lbcount += elen;
- pbloc = cbloc;
- cbloc = nbloc;
+ prev_epos.block = cur_epos.block;
+ cur_epos.block = next_epos.block;
- pextoffset = cextoffset;
- cextoffset = nextoffset;
+ prev_epos.offset = cur_epos.offset;
+ cur_epos.offset = next_epos.offset;
- if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1)
+ if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 1)) == -1)
break;
c = !c;
@@ -418,6 +520,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
b_off -= lbcount;
offset = b_off >> inode->i_sb->s_blocksize_bits;
+ /* Move into indirect extent if we are at a pointer to it */
+ udf_next_aext(inode, &prev_epos, &eloc, &elen, 0);
/* if the extent is allocated and recorded, return the block
if the extent is not a multiple of the blocksize, round up */
@@ -429,54 +533,77 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
elen = EXT_RECORDED_ALLOCATED |
((elen + inode->i_sb->s_blocksize - 1) &
~(inode->i_sb->s_blocksize - 1));
- etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1);
+ etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);
}
- udf_release_data(pbh);
- udf_release_data(cbh);
- udf_release_data(nbh);
+ brelse(prev_epos.bh);
+ brelse(cur_epos.bh);
+ brelse(next_epos.bh);
newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset);
*phys = newblock;
return NULL;
}
+ last_block = block;
+ /* Are we beyond EOF? */
if (etype == -1)
{
- endnum = startnum = ((count > 1) ? 1 : count);
- if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1))
- {
- laarr[c].extLength =
- (laarr[c].extLength & UDF_EXTENT_FLAG_MASK) |
- (((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- UDF_I_LENEXTENTS(inode) =
- (UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1);
+ int ret;
+
+ if (count) {
+ if (c)
+ laarr[0] = laarr[1];
+ startnum = 1;
+ }
+ else {
+ /* Create a fake extent when there's not one */
+ memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr));
+ laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
+ /* Will udf_extend_file() create real extent from a fake one? */
+ startnum = (offset > 0);
+ }
+ /* Create extents for the hole between EOF and offset */
+ ret = udf_extend_file(inode, &prev_epos, laarr, offset);
+ if (ret == -1) {
+ brelse(prev_epos.bh);
+ brelse(cur_epos.bh);
+ brelse(next_epos.bh);
+ /* We don't really know the error here so we just make
+ * something up */
+ *err = -ENOSPC;
+ return NULL;
}
- c = !c;
- laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
- ((offset + 1) << inode->i_sb->s_blocksize_bits);
- memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
- count ++;
- endnum ++;
+ c = 0;
+ offset = 0;
+ count += ret;
+ /* We are not covered by a preallocated extent? */
+ if ((laarr[0].extLength & UDF_EXTENT_FLAG_MASK) != EXT_NOT_RECORDED_ALLOCATED) {
+ /* Is there any real extent? - otherwise we overwrite
+ * the fake one... */
+ if (count)
+ c = !c;
+ laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
+ inode->i_sb->s_blocksize;
+ memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
+ count ++;
+ endnum ++;
+ }
+ endnum = c+1;
lastblock = 1;
}
- else
+ else {
endnum = startnum = ((count > 2) ? 2 : count);
- /* if the current extent is in position 0, swap it with the previous */
- if (!c && count != 1)
- {
- laarr[2] = laarr[0];
- laarr[0] = laarr[1];
- laarr[1] = laarr[2];
- c = 1;
- }
+ /* if the current extent is in position 0, swap it with the previous */
+ if (!c && count != 1)
+ {
+ laarr[2] = laarr[0];
+ laarr[0] = laarr[1];
+ laarr[1] = laarr[2];
+ c = 1;
+ }
- /* if the current block is located in a extent, read the next extent */
- if (etype != -1)
- {
- if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1)
+ /* if the current block is located in an extent, read the next extent */
+ if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1)
{
laarr[c+1].extLength = (etype << 30) | elen;
laarr[c+1].extLocation = eloc;
@@ -484,11 +611,10 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
startnum ++;
endnum ++;
}
- else
+ else {
lastblock = 1;
+ }
}
- udf_release_data(cbh);
- udf_release_data(nbh);
/* if the current extent is not recorded but allocated, get the
block in the extent corresponding to the requested block */
@@ -508,7 +634,7 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
if (!(newblocknum = udf_new_block(inode->i_sb, inode,
UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
{
- udf_release_data(pbh);
+ brelse(prev_epos.bh);
*err = -ENOSPC;
return NULL;
}
@@ -529,11 +655,11 @@ static struct buffer_head * inode_getblk(struct inode * inode, long block,
udf_merge_extents(inode, laarr, &endnum);
/* write back the new extents, inserting new extents if the new number
- of extents is greater than the old number, and deleting extents if
- the new number of extents is less than the old number */
- udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh);
+ of extents is greater than the old number, and deleting extents if
+ the new number of extents is less than the old number */
+ udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
- udf_release_data(pbh);
+ brelse(prev_epos.bh);
if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
@@ -795,7 +921,7 @@ static void udf_merge_extents(struct inode *inode,
static void udf_update_extents(struct inode *inode,
kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
- kernel_lb_addr pbloc, uint32_t pextoffset, struct buffer_head **pbh)
+ struct extent_position *epos)
{
int start = 0, i;
kernel_lb_addr tmploc;
@@ -804,28 +930,26 @@ static void udf_update_extents(struct inode *inode,
if (startnum > endnum)
{
for (i=0; i<(startnum-endnum); i++)
- {
- udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
- laarr[i].extLength, *pbh);
- }
+ udf_delete_aext(inode, *epos, laarr[i].extLocation,
+ laarr[i].extLength);
}
else if (startnum < endnum)
{
for (i=0; i<(endnum-startnum); i++)
{
- udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation,
- laarr[i].extLength, *pbh);
- udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation,
- &laarr[i].extLength, pbh, 1);
+ udf_insert_aext(inode, *epos, laarr[i].extLocation,
+ laarr[i].extLength);
+ udf_next_aext(inode, epos, &laarr[i].extLocation,
+ &laarr[i].extLength, 1);
start ++;
}
}
for (i=start; i<endnum; i++)
{
- udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0);
- udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation,
- laarr[i].extLength, *pbh, 1);
+ udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
+ udf_write_aext(inode, epos, laarr[i].extLocation,
+ laarr[i].extLength, 1);
}
}
@@ -931,7 +1055,7 @@ __udf_read_inode(struct inode *inode)
{
printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
inode->i_ino, ident);
- udf_release_data(bh);
+ brelse(bh);
make_bad_inode(inode);
return;
}
@@ -960,35 +1084,36 @@ __udf_read_inode(struct inode *inode)
ident == TAG_IDENT_EFE)
{
memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr));
- udf_release_data(bh);
- udf_release_data(ibh);
- udf_release_data(nbh);
+ brelse(bh);
+ brelse(ibh);
+ brelse(nbh);
__udf_read_inode(inode);
return;
}
else
{
- udf_release_data(nbh);
- udf_release_data(ibh);
+ brelse(nbh);
+ brelse(ibh);
}
}
else
- udf_release_data(ibh);
+ brelse(ibh);
}
}
else
- udf_release_data(ibh);
+ brelse(ibh);
}
else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
{
printk(KERN_ERR "udf: unsupported strategy type: %d\n",
le16_to_cpu(fe->icbTag.strategyType));
- udf_release_data(bh);
+ brelse(bh);
make_bad_inode(inode);
return;
}
udf_fill_inode(inode, bh);
- udf_release_data(bh);
+
+ brelse(bh);
}
static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
@@ -1331,7 +1456,7 @@ udf_update_inode(struct inode *inode, int do_sync)
use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];
mark_buffer_dirty(bh);
- udf_release_data(bh);
+ brelse(bh);
return err;
}
@@ -1520,7 +1645,7 @@ udf_update_inode(struct inode *inode, int do_sync)
err = -EIO;
}
}
- udf_release_data(bh);
+ brelse(bh);
return err;
}
@@ -1556,8 +1681,8 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
return NULL;
}
-int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
- kernel_lb_addr eloc, uint32_t elen, struct buffer_head **bh, int inc)
+int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
+ kernel_lb_addr eloc, uint32_t elen, int inc)
{
int adsize;
short_ad *sad = NULL;
@@ -1566,10 +1691,10 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
int8_t etype;
uint8_t *ptr;
- if (!*bh)
- ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+ if (!epos->bh)
+ ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
else
- ptr = (*bh)->b_data + *extoffset;
+ ptr = epos->bh->b_data + epos->offset;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(short_ad);
@@ -1578,20 +1703,20 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
else
return -1;
- if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize)
+ if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize)
{
char *sptr, *dptr;
struct buffer_head *nbh;
int err, loffset;
- kernel_lb_addr obloc = *bloc;
+ kernel_lb_addr obloc = epos->block;
- if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL,
+ if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
{
return -1;
}
if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
- *bloc, 0))))
+ epos->block, 0))))
{
return -1;
}
@@ -1604,25 +1729,25 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
aed = (struct allocExtDesc *)(nbh->b_data);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
- if (*extoffset + adsize > inode->i_sb->s_blocksize)
+ if (epos->offset + adsize > inode->i_sb->s_blocksize)
{
- loffset = *extoffset;
+ loffset = epos->offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
sptr = ptr - adsize;
dptr = nbh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
- *extoffset = sizeof(struct allocExtDesc) + adsize;
+ epos->offset = sizeof(struct allocExtDesc) + adsize;
}
else
{
- loffset = *extoffset + adsize;
+ loffset = epos->offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
sptr = ptr;
- *extoffset = sizeof(struct allocExtDesc);
+ epos->offset = sizeof(struct allocExtDesc);
- if (*bh)
+ if (epos->bh)
{
- aed = (struct allocExtDesc *)(*bh)->b_data;
+ aed = (struct allocExtDesc *)epos->bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
}
@@ -1634,10 +1759,10 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
}
if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
- bloc->logicalBlockNum, sizeof(tag));
+ epos->block.logicalBlockNum, sizeof(tag));
else
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
- bloc->logicalBlockNum, sizeof(tag));
+ epos->block.logicalBlockNum, sizeof(tag));
switch (UDF_I_ALLOCTYPE(inode))
{
case ICBTAG_FLAG_AD_SHORT:
@@ -1646,7 +1771,7 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
sad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
inode->i_sb->s_blocksize);
- sad->extPosition = cpu_to_le32(bloc->logicalBlockNum);
+ sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
break;
}
case ICBTAG_FLAG_AD_LONG:
@@ -1655,60 +1780,57 @@ int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
lad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
inode->i_sb->s_blocksize);
- lad->extLocation = cpu_to_lelb(*bloc);
+ lad->extLocation = cpu_to_lelb(epos->block);
memset(lad->impUse, 0x00, sizeof(lad->impUse));
break;
}
}
- if (*bh)
+ if (epos->bh)
{
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((*bh)->b_data, loffset);
+ udf_update_tag(epos->bh->b_data, loffset);
else
- udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(*bh, inode);
- udf_release_data(*bh);
+ udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos->bh, inode);
+ brelse(epos->bh);
}
else
mark_inode_dirty(inode);
- *bh = nbh;
+ epos->bh = nbh;
}
- etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc);
+ etype = udf_write_aext(inode, epos, eloc, elen, inc);
- if (!*bh)
+ if (!epos->bh)
{
UDF_I_LENALLOC(inode) += adsize;
mark_inode_dirty(inode);
}
else
{
- aed = (struct allocExtDesc *)(*bh)->b_data;
+ aed = (struct allocExtDesc *)epos->bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize));
+ udf_update_tag(epos->bh->b_data, epos->offset + (inc ? 0 : adsize));
else
- udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(*bh, inode);
+ udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos->bh, inode);
}
return etype;
}
-int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset,
- kernel_lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc)
+int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
+ kernel_lb_addr eloc, uint32_t elen, int inc)
{
int adsize;
uint8_t *ptr;
- if (!bh)
- ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+ if (!epos->bh)
+ ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
else
- {
- ptr = bh->b_data + *extoffset;
- atomic_inc(&bh->b_count);
- }
+ ptr = epos->bh->b_data + epos->offset;
switch (UDF_I_ALLOCTYPE(inode))
{
@@ -1733,40 +1855,39 @@ int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset,
return -1;
}
- if (bh)
+ if (epos->bh)
{
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
{
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data;
- udf_update_tag((bh)->b_data,
+ struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data;
+ udf_update_tag(epos->bh->b_data,
le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
}
- mark_buffer_dirty_inode(bh, inode);
- udf_release_data(bh);
+ mark_buffer_dirty_inode(epos->bh, inode);
}
else
mark_inode_dirty(inode);
if (inc)
- *extoffset += adsize;
+ epos->offset += adsize;
return (elen >> 30);
}
-int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc)
+int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
+ kernel_lb_addr *eloc, uint32_t *elen, int inc)
{
int8_t etype;
- while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) ==
+ while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
(EXT_NEXT_EXTENT_ALLOCDECS >> 30))
{
- *bloc = *eloc;
- *extoffset = sizeof(struct allocExtDesc);
- udf_release_data(*bh);
- if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0))))
+ epos->block = *eloc;
+ epos->offset = sizeof(struct allocExtDesc);
+ brelse(epos->bh);
+ if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0))))
{
udf_debug("reading block %d failed!\n",
- udf_get_lb_pblock(inode->i_sb, *bloc, 0));
+ udf_get_lb_pblock(inode->i_sb, epos->block, 0));
return -1;
}
}
@@ -1774,26 +1895,26 @@ int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
return etype;
}
-int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc)
+int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
+ kernel_lb_addr *eloc, uint32_t *elen, int inc)
{
int alen;
int8_t etype;
uint8_t *ptr;
- if (!*bh)
+ if (!epos->bh)
{
- if (!(*extoffset))
- *extoffset = udf_file_entry_alloc_offset(inode);
- ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
+ if (!epos->offset)
+ epos->offset = udf_file_entry_alloc_offset(inode);
+ ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
}
else
{
- if (!(*extoffset))
- *extoffset = sizeof(struct allocExtDesc);
- ptr = (*bh)->b_data + *extoffset;
- alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs);
+ if (!epos->offset)
+ epos->offset = sizeof(struct allocExtDesc);
+ ptr = epos->bh->b_data + epos->offset;
+ alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
}
switch (UDF_I_ALLOCTYPE(inode))
@@ -1802,7 +1923,7 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse
{
short_ad *sad;
- if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc)))
+ if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
return -1;
etype = le32_to_cpu(sad->extLength) >> 30;
@@ -1815,7 +1936,7 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse
{
long_ad *lad;
- if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc)))
+ if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
return -1;
etype = le32_to_cpu(lad->extLength) >> 30;
@@ -1834,41 +1955,40 @@ int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffse
}
static int8_t
-udf_insert_aext(struct inode *inode, kernel_lb_addr bloc, int extoffset,
- kernel_lb_addr neloc, uint32_t nelen, struct buffer_head *bh)
+udf_insert_aext(struct inode *inode, struct extent_position epos,
+ kernel_lb_addr neloc, uint32_t nelen)
{
kernel_lb_addr oeloc;
uint32_t oelen;
int8_t etype;
- if (bh)
- atomic_inc(&bh->b_count);
+ if (epos.bh)
+ get_bh(epos.bh);
- while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1)
+ while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1)
{
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
+ udf_write_aext(inode, &epos, neloc, nelen, 1);
neloc = oeloc;
nelen = (etype << 30) | oelen;
}
- udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1);
- udf_release_data(bh);
+ udf_add_aext(inode, &epos, neloc, nelen, 1);
+ brelse(epos.bh);
return (nelen >> 30);
}
-int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset,
- kernel_lb_addr eloc, uint32_t elen, struct buffer_head *nbh)
+int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
+ kernel_lb_addr eloc, uint32_t elen)
{
- struct buffer_head *obh;
- kernel_lb_addr obloc;
- int oextoffset, adsize;
+ struct extent_position oepos;
+ int adsize;
int8_t etype;
struct allocExtDesc *aed;
- if (nbh)
+ if (epos.bh)
{
- atomic_inc(&nbh->b_count);
- atomic_inc(&nbh->b_count);
+ get_bh(epos.bh);
+ get_bh(epos.bh);
}
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -1878,80 +1998,77 @@ int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset
else
adsize = 0;
- obh = nbh;
- obloc = nbloc;
- oextoffset = nextoffset;
-
- if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1)
+ oepos = epos;
+ if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1)
return -1;
- while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1)
+ while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
{
- udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1);
- if (obh != nbh)
+ udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1);
+ if (oepos.bh != epos.bh)
{
- obloc = nbloc;
- udf_release_data(obh);
- atomic_inc(&nbh->b_count);
- obh = nbh;
- oextoffset = nextoffset - adsize;
+ oepos.block = epos.block;
+ brelse(oepos.bh);
+ get_bh(epos.bh);
+ oepos.bh = epos.bh;
+ oepos.offset = epos.offset - adsize;
}
}
memset(&eloc, 0x00, sizeof(kernel_lb_addr));
elen = 0;
- if (nbh != obh)
+ if (epos.bh != oepos.bh)
{
- udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1);
- udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
- udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
- if (!obh)
+ udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1);
+ udf_write_aext(inode, &oepos, eloc, elen, 1);
+ udf_write_aext(inode, &oepos, eloc, elen, 1);
+ if (!oepos.bh)
{
UDF_I_LENALLOC(inode) -= (adsize * 2);
mark_inode_dirty(inode);
}
else
{
- aed = (struct allocExtDesc *)(obh)->b_data;
+ aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((obh)->b_data, oextoffset - (2*adsize));
+ udf_update_tag(oepos.bh->b_data, oepos.offset - (2*adsize));
else
- udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(obh, inode);
+ udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(oepos.bh, inode);
}
}
else
{
- udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1);
- if (!obh)
+ udf_write_aext(inode, &oepos, eloc, elen, 1);
+ if (!oepos.bh)
{
UDF_I_LENALLOC(inode) -= adsize;
mark_inode_dirty(inode);
}
else
{
- aed = (struct allocExtDesc *)(obh)->b_data;
+ aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag((obh)->b_data, oextoffset - adsize);
+ udf_update_tag(oepos.bh->b_data, epos.offset - adsize);
else
- udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(obh, inode);
+ udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(oepos.bh, inode);
}
}
- udf_release_data(nbh);
- udf_release_data(obh);
+ brelse(epos.bh);
+ brelse(oepos.bh);
return (elen >> 30);
}
-int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t *extoffset,
- kernel_lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh)
+int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos,
+ kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset)
{
- uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits;
+ loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits;
int8_t etype;
if (block < 0)
@@ -1960,42 +2077,44 @@ int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t
return -1;
}
- *extoffset = 0;
+ pos->offset = 0;
+ pos->block = UDF_I_LOCATION(inode);
+ pos->bh = NULL;
*elen = 0;
- *bloc = UDF_I_LOCATION(inode);
do
{
- if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1)
+ if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1)
{
- *offset = bcount - lbcount;
+ *offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;
UDF_I_LENEXTENTS(inode) = lbcount;
return -1;
}
lbcount += *elen;
} while (lbcount <= bcount);
- *offset = bcount + *elen - lbcount;
+ *offset = (bcount + *elen - lbcount) >> inode->i_sb->s_blocksize_bits;
return etype;
}
-long udf_block_map(struct inode *inode, long block)
+long udf_block_map(struct inode *inode, sector_t block)
{
- kernel_lb_addr eloc, bloc;
- uint32_t offset, extoffset, elen;
- struct buffer_head *bh = NULL;
+ kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = { NULL, 0, { 0, 0}};
int ret;
lock_kernel();
- if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
- ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits);
+ if (inode_bmap(inode, block, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
+ ret = udf_get_lb_pblock(inode->i_sb, eloc, offset);
else
ret = 0;
unlock_kernel();
- udf_release_data(bh);
+ brelse(epos.bh);
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV))
return udf_fixed_to_variable(ret);
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index cc8ca3254db..a2b2a98ce78 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -274,12 +274,6 @@ udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, ui
loc.logicalBlockNum + offset, ident);
}
-void udf_release_data(struct buffer_head *bh)
-{
- if (bh)
- brelse(bh);
-}
-
void udf_update_tag(char *data, int length)
{
tag *tptr = (tag *)data;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index fe361cd19a9..91df4928651 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -155,9 +155,10 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
uint8_t lfi;
uint16_t liu;
loff_t size;
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- struct buffer_head *bh = NULL;
+ kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = { NULL, 0, { 0, 0}};
size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
f_pos = (udf_ext0_offset(dir) >> 2);
@@ -166,42 +167,41 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
fibh->sbh = fibh->ebh = NULL;
else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
{
- offset >>= dir->i_sb->s_blocksize_bits;
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
+ epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
+ epos.offset -= sizeof(long_ad);
}
else
offset = 0;
if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
{
- udf_release_data(bh);
+ brelse(epos.bh);
return NULL;
}
}
else
{
- udf_release_data(bh);
+ brelse(epos.bh);
return NULL;
}
while ( (f_pos < size) )
{
- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
if (!fi)
{
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+ brelse(epos.bh);
return NULL;
}
@@ -247,15 +247,15 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
{
if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
{
- udf_release_data(bh);
+ brelse(epos.bh);
return fi;
}
}
}
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+ brelse(epos.bh);
return NULL;
}
@@ -321,8 +321,8 @@ udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
if (udf_find_entry(dir, dentry, &fibh, &cfi))
{
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
if ( !inode )
@@ -353,9 +353,10 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
uint8_t lfi;
uint16_t liu;
int block;
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- struct buffer_head *bh = NULL;
+ kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = { NULL, 0, { 0, 0 }};
sb = dir->i_sb;
@@ -384,23 +385,22 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
fibh->sbh = fibh->ebh = NULL;
else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
{
- offset >>= dir->i_sb->s_blocksize_bits;
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
+ epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
+ epos.offset -= sizeof(long_ad);
}
else
offset = 0;
if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
{
- udf_release_data(bh);
+ brelse(epos.bh);
*err = -EIO;
return NULL;
}
@@ -418,14 +418,14 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
while ( (f_pos < size) )
{
- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
if (!fi)
{
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+ brelse(epos.bh);
*err = -EIO;
return NULL;
}
@@ -455,7 +455,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
{
if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
{
- udf_release_data(bh);
+ brelse(epos.bh);
cfi->descTag.tagSerialNum = cpu_to_le16(1);
cfi->fileVersionNum = cpu_to_le16(1);
cfi->fileCharacteristics = 0;
@@ -478,9 +478,9 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
{
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
- udf_release_data(bh);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
+ brelse(epos.bh);
*err = -EEXIST;
return NULL;
}
@@ -492,25 +492,25 @@ add:
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
sb->s_blocksize - fibh->eoffset < nfidlen)
{
- udf_release_data(bh);
- bh = NULL;
+ brelse(epos.bh);
+ epos.bh = NULL;
fibh->soffset -= udf_ext0_offset(dir);
fibh->eoffset -= udf_ext0_offset(dir);
f_pos -= (udf_ext0_offset(dir) >> 2);
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err)))
return NULL;
- bloc = UDF_I_LOCATION(dir);
+ epos.block = UDF_I_LOCATION(dir);
eloc.logicalBlockNum = block;
eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
elen = dir->i_sb->s_blocksize;
- extoffset = udf_file_entry_alloc_offset(dir);
+ epos.offset = udf_file_entry_alloc_offset(dir);
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset += sizeof(short_ad);
+ epos.offset += sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset += sizeof(long_ad);
+ epos.offset += sizeof(long_ad);
}
if (sb->s_blocksize - fibh->eoffset >= nfidlen)
@@ -519,7 +519,7 @@ add:
fibh->eoffset += nfidlen;
if (fibh->sbh != fibh->ebh)
{
- udf_release_data(fibh->sbh);
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
@@ -541,7 +541,7 @@ add:
fibh->eoffset += nfidlen - sb->s_blocksize;
if (fibh->sbh != fibh->ebh)
{
- udf_release_data(fibh->sbh);
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
@@ -550,14 +550,14 @@ add:
if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
{
- udf_release_data(bh);
- udf_release_data(fibh->sbh);
+ brelse(epos.bh);
+ brelse(fibh->sbh);
return NULL;
}
if (!(fibh->soffset))
{
- if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) ==
+ if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
(EXT_RECORDED_ALLOCATED >> 30))
{
block = eloc.logicalBlockNum + ((elen - 1) >>
@@ -566,7 +566,7 @@ add:
else
block ++;
- udf_release_data(fibh->sbh);
+ brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
}
@@ -587,7 +587,7 @@ add:
cfi->lengthOfImpUse = cpu_to_le16(0);
if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
{
- udf_release_data(bh);
+ brelse(epos.bh);
dir->i_size += nfidlen;
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
UDF_I_LENALLOC(dir) += nfidlen;
@@ -596,10 +596,10 @@ add:
}
else
{
- udf_release_data(bh);
+ brelse(epos.bh);
if (fibh->sbh != fibh->ebh)
- udf_release_data(fibh->ebh);
- udf_release_data(fibh->sbh);
+ brelse(fibh->ebh);
+ brelse(fibh->sbh);
*err = -EIO;
return NULL;
}
@@ -656,8 +656,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
mark_inode_dirty(dir);
}
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
unlock_kernel();
d_instantiate(dentry, inode);
return 0;
@@ -701,8 +701,8 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
mark_inode_dirty(inode);
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
d_instantiate(dentry, inode);
err = 0;
out:
@@ -743,7 +743,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL);
cfi.fileCharacteristics = FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
- udf_release_data(fibh.sbh);
+ brelse(fibh.sbh);
inode->i_mode = S_IFDIR | mode;
if (dir->i_mode & S_ISGID)
inode->i_mode |= S_ISGID;
@@ -766,8 +766,8 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
mark_inode_dirty(dir);
d_instantiate(dentry, inode);
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
err = 0;
out:
unlock_kernel();
@@ -781,9 +781,10 @@ static int empty_dir(struct inode *dir)
loff_t f_pos;
loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
int block;
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset, elen, offset;
- struct buffer_head *bh = NULL;
+ kernel_lb_addr eloc;
+ uint32_t elen;
+ sector_t offset;
+ struct extent_position epos = { NULL, 0, { 0, 0}};
f_pos = (udf_ext0_offset(dir) >> 2);
@@ -792,59 +793,58 @@ static int empty_dir(struct inode *dir)
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
fibh.sbh = fibh.ebh = NULL;
else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30))
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
{
- offset >>= dir->i_sb->s_blocksize_bits;
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
{
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
- extoffset -= sizeof(short_ad);
+ epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
- extoffset -= sizeof(long_ad);
+ epos.offset -= sizeof(long_ad);
}
else
offset = 0;
if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
{
- udf_release_data(bh);
+ brelse(epos.bh);
return 0;
}
}
else
{
- udf_release_data(bh);
+ brelse(epos.bh);
return 0;
}
while ( (f_pos < size) )
{
- fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
+ fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
if (!fi)
{
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0)
{
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 0;
}
}
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
- udf_release_data(bh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+ brelse(epos.bh);
return 1;
}
@@ -878,14 +878,14 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
inode->i_nlink);
clear_nlink(inode);
inode->i_size = 0;
- inode_dec_link_count(inode);
+ inode_dec_link_count(dir);
inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
mark_inode_dirty(dir);
end_rmdir:
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
out:
unlock_kernel();
return retval;
@@ -928,8 +928,8 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
end_unlink:
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
out:
unlock_kernel();
return retval;
@@ -941,7 +941,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
struct pathComponent *pc;
char *compstart;
struct udf_fileident_bh fibh;
- struct buffer_head *bh = NULL;
+ struct extent_position epos = { NULL, 0, {0, 0}};
int eoffset, elen = 0;
struct fileIdentDesc *fi;
struct fileIdentDesc cfi;
@@ -961,33 +961,33 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
{
- struct buffer_head *bh = NULL;
- kernel_lb_addr bloc, eloc;
- uint32_t elen, extoffset;
+ kernel_lb_addr eloc;
+ uint32_t elen;
block = udf_new_block(inode->i_sb, inode,
UDF_I_LOCATION(inode).partitionReferenceNum,
UDF_I_LOCATION(inode).logicalBlockNum, &err);
if (!block)
goto out_no_entry;
- bloc = UDF_I_LOCATION(inode);
+ epos.block = UDF_I_LOCATION(inode);
+ epos.offset = udf_file_entry_alloc_offset(inode);
+ epos.bh = NULL;
eloc.logicalBlockNum = block;
eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
elen = inode->i_sb->s_blocksize;
UDF_I_LENEXTENTS(inode) = elen;
- extoffset = udf_file_entry_alloc_offset(inode);
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0);
- udf_release_data(bh);
+ udf_add_aext(inode, &epos, eloc, elen, 0);
+ brelse(epos.bh);
block = udf_get_pblock(inode->i_sb, block,
UDF_I_LOCATION(inode).partitionReferenceNum, 0);
- bh = udf_tread(inode->i_sb, block);
- lock_buffer(bh);
- memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
- set_buffer_uptodate(bh);
- unlock_buffer(bh);
- mark_buffer_dirty_inode(bh, inode);
- ea = bh->b_data + udf_ext0_offset(inode);
+ epos.bh = udf_tread(inode->i_sb, block);
+ lock_buffer(epos.bh);
+ memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
+ set_buffer_uptodate(epos.bh);
+ unlock_buffer(epos.bh);
+ mark_buffer_dirty_inode(epos.bh, inode);
+ ea = epos.bh->b_data + udf_ext0_offset(inode);
}
else
ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
@@ -1060,7 +1060,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
}
}
- udf_release_data(bh);
+ brelse(epos.bh);
inode->i_size = elen;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
UDF_I_LENALLOC(inode) = inode->i_size;
@@ -1089,8 +1089,8 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
mark_inode_dirty(dir);
}
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
d_instantiate(dentry, inode);
err = 0;
@@ -1145,8 +1145,8 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
mark_inode_dirty(dir);
}
if (fibh.sbh != fibh.ebh)
- udf_release_data(fibh.ebh);
- udf_release_data(fibh.sbh);
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
inc_nlink(inode);
inode->i_ctime = current_fs_time(inode->i_sb);
mark_inode_dirty(inode);
@@ -1174,8 +1174,8 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
{
if (ofibh.sbh != ofibh.ebh)
- udf_release_data(ofibh.ebh);
- udf_release_data(ofibh.sbh);
+ brelse(ofibh.ebh);
+ brelse(ofibh.sbh);
}
tloc = lelb_to_cpu(ocfi.icb.extLocation);
if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
@@ -1188,8 +1188,8 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
if (!new_inode)
{
if (nfibh.sbh != nfibh.ebh)
- udf_release_data(nfibh.ebh);
- udf_release_data(nfibh.sbh);
+ brelse(nfibh.ebh);
+ brelse(nfibh.sbh);
nfi = NULL;
}
}
@@ -1290,19 +1290,19 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
if (ofi)
{
if (ofibh.sbh != ofibh.ebh)
- udf_release_data(ofibh.ebh);
- udf_release_data(ofibh.sbh);
+ brelse(ofibh.ebh);
+ brelse(ofibh.sbh);
}
retval = 0;
end_rename:
- udf_release_data(dir_bh);
+ brelse(dir_bh);
if (nfi)
{
if (nfibh.sbh != nfibh.ebh)
- udf_release_data(nfibh.ebh);
- udf_release_data(nfibh.sbh);
+ brelse(nfibh.ebh);
+ brelse(nfibh.sbh);
}
unlock_kernel();
return retval;
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index dabf2b841db..467a26171cd 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -81,7 +81,7 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t
loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
- udf_release_data(bh);
+ brelse(bh);
if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
{
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 8672b88f7ff..9b8644a06e5 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -134,9 +134,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct udf_inode_info *ei = (struct udf_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
- {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
ei->i_ext.i_data = NULL;
inode_init_once(&ei->vfs_inode);
}
@@ -565,7 +563,7 @@ udf_vrs(struct super_block *sb, int silent)
if (vsd->stdIdent[0] == 0)
{
- udf_release_data(bh);
+ brelse(bh);
break;
}
else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN))
@@ -598,7 +596,7 @@ udf_vrs(struct super_block *sb, int silent)
}
else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN))
{
- udf_release_data(bh);
+ brelse(bh);
break;
}
else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN))
@@ -609,7 +607,7 @@ udf_vrs(struct super_block *sb, int silent)
{
nsr03 = sector;
}
- udf_release_data(bh);
+ brelse(bh);
}
if (nsr03)
@@ -675,7 +673,7 @@ udf_find_anchor(struct super_block *sb)
{
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
+ brelse(bh);
}
if (ident == TAG_IDENT_AVDP)
@@ -710,7 +708,7 @@ udf_find_anchor(struct super_block *sb)
{
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
+ brelse(bh);
}
if (ident == TAG_IDENT_AVDP &&
@@ -729,7 +727,7 @@ udf_find_anchor(struct super_block *sb)
{
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
+ brelse(bh);
}
if (ident == TAG_IDENT_AVDP &&
@@ -751,7 +749,7 @@ udf_find_anchor(struct super_block *sb)
{
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
- udf_release_data(bh);
+ brelse(bh);
if (ident == TAG_IDENT_AVDP && location == 256)
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
@@ -768,7 +766,7 @@ udf_find_anchor(struct super_block *sb)
}
else
{
- udf_release_data(bh);
+ brelse(bh);
if ((ident != TAG_IDENT_AVDP) && (i ||
(ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE)))
{
@@ -797,7 +795,7 @@ udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr
return 1;
else if (ident != TAG_IDENT_FSD)
{
- udf_release_data(bh);
+ brelse(bh);
return 1;
}
@@ -836,7 +834,7 @@ udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr
newfileset.logicalBlockNum += 1 +
((le32_to_cpu(sp->numOfBytes) + sizeof(struct spaceBitmapDesc) - 1)
>> sb->s_blocksize_bits);
- udf_release_data(bh);
+ brelse(bh);
break;
}
case TAG_IDENT_FSD:
@@ -847,7 +845,7 @@ udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr
default:
{
newfileset.logicalBlockNum ++;
- udf_release_data(bh);
+ brelse(bh);
bh = NULL;
break;
}
@@ -867,7 +865,7 @@ udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr
UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
udf_load_fileset(sb, bh, root);
- udf_release_data(bh);
+ brelse(bh);
return 0;
}
return 1;
@@ -1085,7 +1083,7 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
if (ident != 0 ||
strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
{
- udf_release_data(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
+ brelse(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
}
}
@@ -1139,12 +1137,12 @@ udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
if (UDF_SB_LVIDBH(sb) != bh)
- udf_release_data(bh);
+ brelse(bh);
loc.extLength -= sb->s_blocksize;
loc.extLocation ++;
}
if (UDF_SB_LVIDBH(sb) != bh)
- udf_release_data(bh);
+ brelse(bh);
}
/*
@@ -1247,7 +1245,7 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
done = 1;
break;
}
- udf_release_data(bh);
+ brelse(bh);
}
for (i=0; i<VDS_POS_LENGTH; i++)
{
@@ -1269,10 +1267,10 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
gd = (struct generic_desc *)bh2->b_data;
if (ident == TAG_IDENT_PD)
udf_load_partdesc(sb, bh2);
- udf_release_data(bh2);
+ brelse(bh2);
}
}
- udf_release_data(bh);
+ brelse(bh);
}
}
@@ -1335,7 +1333,7 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
reserve_e = reserve_e >> sb->s_blocksize_bits;
reserve_e += reserve_s;
- udf_release_data(bh);
+ brelse(bh);
/* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */
@@ -1405,12 +1403,14 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
pos = udf_block_map(UDF_SB_VAT(sb), 0);
bh = sb_bread(sb, pos);
+ if (!bh)
+ return 1;
UDF_SB_TYPEVIRT(sb,i).s_start_offset =
le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
udf_ext0_offset(UDF_SB_VAT(sb));
UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2;
- udf_release_data(bh);
+ brelse(bh);
}
UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
@@ -1663,7 +1663,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
iput(inode);
goto error_out;
}
- sb->s_maxbytes = 1<<30;
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
return 0;
error_out:
@@ -1682,7 +1682,7 @@ error_out:
if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
{
for (i=0; i<4; i++)
- udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
+ brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
}
}
#ifdef CONFIG_UDF_NLS
@@ -1691,7 +1691,7 @@ error_out:
#endif
if (!(sb->s_flags & MS_RDONLY))
udf_close_lvid(sb);
- udf_release_data(UDF_SB_LVIDBH(sb));
+ brelse(UDF_SB_LVIDBH(sb));
UDF_SB_FREE(sb);
kfree(sbi);
sb->s_fs_info = NULL;
@@ -1760,7 +1760,7 @@ udf_put_super(struct super_block *sb)
if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
{
for (i=0; i<4; i++)
- udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
+ brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
}
}
#ifdef CONFIG_UDF_NLS
@@ -1769,7 +1769,7 @@ udf_put_super(struct super_block *sb)
#endif
if (!(sb->s_flags & MS_RDONLY))
udf_close_lvid(sb);
- udf_release_data(UDF_SB_LVIDBH(sb));
+ brelse(UDF_SB_LVIDBH(sb));
UDF_SB_FREE(sb);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
@@ -1839,7 +1839,7 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
}
else if (ident != TAG_IDENT_SBD)
{
- udf_release_data(bh);
+ brelse(bh);
printk(KERN_ERR "udf: udf_count_free failed\n");
goto out;
}
@@ -1861,7 +1861,7 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
}
if ( bytes )
{
- udf_release_data(bh);
+ brelse(bh);
newblock = udf_get_lb_pblock(sb, loc, ++block);
bh = udf_tread(sb, newblock);
if (!bh)
@@ -1873,7 +1873,7 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
ptr = (uint8_t *)bh->b_data;
}
}
- udf_release_data(bh);
+ brelse(bh);
out:
unlock_kernel();
@@ -1885,21 +1885,20 @@ static unsigned int
udf_count_free_table(struct super_block *sb, struct inode * table)
{
unsigned int accum = 0;
- uint32_t extoffset, elen;
- kernel_lb_addr bloc, eloc;
+ uint32_t elen;
+ kernel_lb_addr eloc;
int8_t etype;
- struct buffer_head *bh = NULL;
+ struct extent_position epos;
lock_kernel();
- bloc = UDF_I_LOCATION(table);
- extoffset = sizeof(struct unallocSpaceEntry);
+ epos.block = UDF_I_LOCATION(table);
+ epos.offset = sizeof(struct unallocSpaceEntry);
+ epos.bh = NULL;
- while ((etype = udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
- {
+ while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
accum += (elen >> table->i_sb->s_blocksize_bits);
- }
- udf_release_data(bh);
+ brelse(epos.bh);
unlock_kernel();
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index ba068a78656..12613b680cc 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -95,7 +95,7 @@ static int udf_symlink_filler(struct file *file, struct page *page)
}
udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
- udf_release_data(bh);
+ brelse(bh);
unlock_kernel();
SetPageUptodate(page);
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 0abd66ce36e..77975ae291a 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -28,8 +28,8 @@
#include "udf_i.h"
#include "udf_sb.h"
-static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset,
- kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen)
+static void extent_trunc(struct inode * inode, struct extent_position *epos,
+ kernel_lb_addr eloc, int8_t etype, uint32_t elen, uint32_t nelen)
{
kernel_lb_addr neloc = { 0, 0 };
int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
@@ -49,7 +49,7 @@ static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffse
if (elen != nelen)
{
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
+ udf_write_aext(inode, epos, neloc, nelen, 0);
if (last_block - first_block > 0)
{
if (etype == (EXT_RECORDED_ALLOCATED >> 30))
@@ -63,18 +63,16 @@ static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffse
void udf_discard_prealloc(struct inode * inode)
{
- kernel_lb_addr bloc, eloc;
- uint32_t extoffset = 0, elen, nelen;
+ struct extent_position epos = { NULL, 0, {0, 0}};
+ kernel_lb_addr eloc;
+ uint32_t elen, nelen;
uint64_t lbcount = 0;
int8_t etype = -1, netype;
- struct buffer_head *bh = NULL;
int adsize;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
inode->i_size == UDF_I_LENEXTENTS(inode))
- {
return;
- }
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
adsize = sizeof(short_ad);
@@ -83,52 +81,58 @@ void udf_discard_prealloc(struct inode * inode)
else
adsize = 0;
- bloc = UDF_I_LOCATION(inode);
+ epos.block = UDF_I_LOCATION(inode);
- while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1)
+ /* Find the last extent in the file */
+ while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
{
etype = netype;
lbcount += elen;
- if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize)
+ if (lbcount > inode->i_size && lbcount - elen < inode->i_size)
{
+ WARN_ON(lbcount - inode->i_size >= inode->i_sb->s_blocksize);
nelen = elen - (lbcount - inode->i_size);
- extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen);
+ epos.offset -= adsize;
+ extent_trunc(inode, &epos, eloc, etype, elen, nelen);
+ epos.offset += adsize;
lbcount = inode->i_size;
}
}
- if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- extoffset -= adsize;
+ if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ epos.offset -= adsize;
lbcount -= elen;
- extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
- if (!bh)
+ extent_trunc(inode, &epos, eloc, etype, elen, 0);
+ if (!epos.bh)
{
- UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode);
+ UDF_I_LENALLOC(inode) = epos.offset - udf_file_entry_alloc_offset(inode);
mark_inode_dirty(inode);
}
else
{
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
- aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc));
+ struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
+ aed->lengthAllocDescs = cpu_to_le32(epos.offset - sizeof(struct allocExtDesc));
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(bh->b_data, extoffset);
+ udf_update_tag(epos.bh->b_data, epos.offset);
else
- udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(bh, inode);
+ udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos.bh, inode);
}
}
UDF_I_LENEXTENTS(inode) = lbcount;
- udf_release_data(bh);
+ WARN_ON(lbcount != inode->i_size);
+ brelse(epos.bh);
}
void udf_truncate_extents(struct inode * inode)
{
- kernel_lb_addr bloc, eloc, neloc = { 0, 0 };
- uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc;
+ struct extent_position epos;
+ kernel_lb_addr eloc, neloc = { 0, 0 };
+ uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
int8_t etype;
- int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits;
- struct buffer_head *bh = NULL;
+ struct super_block *sb = inode->i_sb;
+ sector_t first_block = inode->i_size >> sb->s_blocksize_bits, offset;
+ loff_t byte_offset;
int adsize;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -136,158 +140,130 @@ void udf_truncate_extents(struct inode * inode)
else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG)
adsize = sizeof(long_ad);
else
- adsize = 0;
+ BUG();
- etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh);
- offset += (inode->i_size & (inode->i_sb->s_blocksize - 1));
+ etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
+ byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize-1));
if (etype != -1)
{
- extoffset -= adsize;
- extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset);
- extoffset += adsize;
-
- if (offset)
- lenalloc = extoffset;
+ epos.offset -= adsize;
+ extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
+ epos.offset += adsize;
+ if (byte_offset)
+ lenalloc = epos.offset;
else
- lenalloc = extoffset - adsize;
+ lenalloc = epos.offset - adsize;
- if (!bh)
+ if (!epos.bh)
lenalloc -= udf_file_entry_alloc_offset(inode);
else
lenalloc -= sizeof(struct allocExtDesc);
- while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1)
+ while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1)
{
if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
{
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0);
- extoffset = 0;
- if (lelen)
+ udf_write_aext(inode, &epos, neloc, nelen, 0);
+ if (indirect_ext_len)
{
- if (!bh)
+ /* We managed to free all extents in the
+ * indirect extent - free it too */
+ if (!epos.bh)
BUG();
- else
- memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
- udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
+ udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
}
else
{
- if (!bh)
+ if (!epos.bh)
{
UDF_I_LENALLOC(inode) = lenalloc;
mark_inode_dirty(inode);
}
else
{
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
+ struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(bh->b_data, lenalloc +
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
+ udf_update_tag(epos.bh->b_data, lenalloc +
sizeof(struct allocExtDesc));
else
- udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(bh, inode);
+ udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos.bh, inode);
}
}
-
- udf_release_data(bh);
- extoffset = sizeof(struct allocExtDesc);
- bloc = eloc;
- bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0));
+ brelse(epos.bh);
+ epos.offset = sizeof(struct allocExtDesc);
+ epos.block = eloc;
+ epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
if (elen)
- lelen = (elen + inode->i_sb->s_blocksize - 1) >>
- inode->i_sb->s_blocksize_bits;
+ indirect_ext_len = (elen +
+ sb->s_blocksize - 1) >>
+ sb->s_blocksize_bits;
else
- lelen = 1;
+ indirect_ext_len = 1;
}
else
{
- extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0);
- extoffset += adsize;
+ extent_trunc(inode, &epos, eloc, etype, elen, 0);
+ epos.offset += adsize;
}
}
- if (lelen)
+ if (indirect_ext_len)
{
- if (!bh)
+ if (!epos.bh)
BUG();
- else
- memset(bh->b_data, 0x00, sizeof(struct allocExtDesc));
- udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen);
+ udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
}
else
{
- if (!bh)
+ if (!epos.bh)
{
UDF_I_LENALLOC(inode) = lenalloc;
mark_inode_dirty(inode);
}
else
{
- struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data);
+ struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(bh->b_data, lenalloc +
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
+ udf_update_tag(epos.bh->b_data, lenalloc +
sizeof(struct allocExtDesc));
else
- udf_update_tag(bh->b_data, sizeof(struct allocExtDesc));
- mark_buffer_dirty_inode(bh, inode);
+ udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+ mark_buffer_dirty_inode(epos.bh, inode);
}
}
}
else if (inode->i_size)
{
- if (offset)
+ if (byte_offset)
{
+ kernel_long_ad extent;
+
/*
* OK, there is not extent covering inode->i_size and
* no extent above inode->i_size => truncate is
- * extending the file by 'offset'.
+ * extending the file by 'offset' blocks.
*/
- if ((!bh && extoffset == udf_file_entry_alloc_offset(inode)) ||
- (bh && extoffset == sizeof(struct allocExtDesc))) {
- /* File has no extents at all! */
- memset(&eloc, 0x00, sizeof(kernel_lb_addr));
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
+ if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
+ (epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
+ /* File has no extents at all or has empty last
+ * indirect extent! Create a fake extent... */
+ extent.extLocation.logicalBlockNum = 0;
+ extent.extLocation.partitionReferenceNum = 0;
+ extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
}
else {
- extoffset -= adsize;
- etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1);
- if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- {
- extoffset -= adsize;
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset);
- udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0);
- }
- else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- kernel_lb_addr neloc = { 0, 0 };
- extoffset -= adsize;
- nelen = EXT_NOT_RECORDED_NOT_ALLOCATED |
- ((elen + offset + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1);
- udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1);
- }
- else
- {
- if (elen & (inode->i_sb->s_blocksize - 1))
- {
- extoffset -= adsize;
- elen = EXT_RECORDED_ALLOCATED |
- ((elen + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
- udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1);
- }
- memset(&eloc, 0x00, sizeof(kernel_lb_addr));
- elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset;
- udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1);
- }
+ epos.offset -= adsize;
+ etype = udf_next_aext(inode, &epos,
+ &extent.extLocation, &extent.extLength, 0);
+ extent.extLength |= etype << 30;
}
+ udf_extend_file(inode, &epos, &extent, offset+((inode->i_size & (sb->s_blocksize-1)) != 0));
}
}
UDF_I_LENEXTENTS(inode) = inode->i_size;
- udf_release_data(bh);
+ brelse(epos.bh);
}
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 110f8d62616..3b2e6c8cb15 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -93,7 +93,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
for (i=0; i<nr_groups; i++)\
{\
if (UDF_SB_BITMAP(X,Y,Z,i))\
- udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\
+ brelse(UDF_SB_BITMAP(X,Y,Z,i));\
}\
if (size <= PAGE_SIZE)\
kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index ee1dece1f6f..67ded289497 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -77,6 +77,13 @@ struct ustr
uint8_t u_len;
};
+struct extent_position {
+ struct buffer_head *bh;
+ uint32_t offset;
+ kernel_lb_addr block;
+};
+
+
/* super.c */
extern void udf_error(struct super_block *, const char *, const char *, ...);
extern void udf_warning(struct super_block *, const char *, const char *, ...);
@@ -98,13 +105,14 @@ extern void udf_read_inode(struct inode *);
extern void udf_delete_inode(struct inode *);
extern void udf_clear_inode(struct inode *);
extern int udf_write_inode(struct inode *, int);
-extern long udf_block_map(struct inode *, long);
-extern int8_t inode_bmap(struct inode *, int, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
-extern int8_t udf_add_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr, uint32_t, struct buffer_head **, int);
-extern int8_t udf_write_aext(struct inode *, kernel_lb_addr, int *, kernel_lb_addr, uint32_t, struct buffer_head *, int);
-extern int8_t udf_delete_aext(struct inode *, kernel_lb_addr, int, kernel_lb_addr, uint32_t, struct buffer_head *);
-extern int8_t udf_next_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
-extern int8_t udf_current_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int);
+extern long udf_block_map(struct inode *, sector_t);
+extern int udf_extend_file(struct inode *, struct extent_position *, kernel_long_ad *, sector_t);
+extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
+extern int8_t udf_add_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
+extern int8_t udf_write_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
+extern int8_t udf_delete_aext(struct inode *, struct extent_position, kernel_lb_addr, uint32_t);
+extern int8_t udf_next_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
+extern int8_t udf_current_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
/* misc.c */
extern struct buffer_head *udf_tgetblk(struct super_block *, int);
@@ -113,7 +121,6 @@ extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint
extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *);
-extern void udf_release_data(struct buffer_head *);
extern void udf_update_tag(char *, int);
extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
@@ -151,7 +158,7 @@ extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_
extern int udf_fsync_file(struct file *, struct dentry *, int);
/* directory.c */
-extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **);
+extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset);
extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int);
extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int);
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index 4890ddf1518..154452172f4 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -19,7 +19,6 @@
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
-#include <linux/smp_lock.h>
#include "swab.h"
#include "util.h"
@@ -180,13 +179,9 @@ fail:
static struct page *ufs_get_page(struct inode *dir, unsigned long n)
{
struct address_space *mapping = dir->i_mapping;
- struct page *page = read_cache_page(mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
+ struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
- wait_on_page_locked(page);
kmap(page);
- if (!PageUptodate(page))
- goto fail;
if (!PageChecked(page))
ufs_check_page(page);
if (PageError(page))
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index b5a6461ec66..be7c48c5f20 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -1237,8 +1237,7 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
{
struct ufs_inode_info *ei = (struct ufs_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 17437574f79..84357f1ff0e 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -251,13 +251,11 @@ struct page *ufs_get_locked_page(struct address_space *mapping,
page = find_lock_page(mapping, index);
if (!page) {
- page = read_cache_page(mapping, index,
- (filler_t*)mapping->a_ops->readpage,
- NULL);
+ page = read_mapping_page(mapping, index, NULL);
if (IS_ERR(page)) {
printk(KERN_ERR "ufs_change_blocknr: "
- "read_cache_page error: ino %lu, index: %lu\n",
+ "read_mapping_page error: ino %lu, index: %lu\n",
mapping->host->i_ino, index);
goto out;
}
diff --git a/fs/utimes.c b/fs/utimes.c
index 99cf2cb11fe..480f7c8c29d 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -1,8 +1,10 @@
#include <linux/compiler.h>
+#include <linux/file.h>
#include <linux/fs.h>
#include <linux/linkage.h>
#include <linux/namei.h>
#include <linux/sched.h>
+#include <linux/stat.h>
#include <linux/utime.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -20,54 +22,18 @@
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
-asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
+asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
{
- int error;
- struct nameidata nd;
- struct inode * inode;
- struct iattr newattrs;
+ struct timespec tv[2];
- error = user_path_walk(filename, &nd);
- if (error)
- goto out;
- inode = nd.dentry->d_inode;
-
- error = -EROFS;
- if (IS_RDONLY(inode))
- goto dput_and_out;
-
- /* Don't worry, the checks are done in inode_change_ok() */
- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
if (times) {
- error = -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
- newattrs.ia_atime.tv_nsec = 0;
- if (!error)
- error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
- newattrs.ia_mtime.tv_nsec = 0;
- if (error)
- goto dput_and_out;
-
- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
- } else {
- error = -EACCES;
- if (IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- if (current->fsuid != inode->i_uid &&
- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
- goto dput_and_out;
+ if (get_user(tv[0].tv_sec, &times->actime) ||
+ get_user(tv[1].tv_sec, &times->modtime))
+ return -EFAULT;
+ tv[0].tv_nsec = 0;
+ tv[1].tv_nsec = 0;
}
- mutex_lock(&inode->i_mutex);
- error = notify_change(nd.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-dput_and_out:
- path_release(&nd);
-out:
- return error;
+ return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0);
}
#endif
@@ -76,18 +42,38 @@ out:
* must be owner or have write permission.
* Else, update from *times, must be owner or super user.
*/
-long do_utimes(int dfd, char __user *filename, struct timeval *times)
+long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
{
int error;
struct nameidata nd;
- struct inode * inode;
+ struct dentry *dentry;
+ struct inode *inode;
struct iattr newattrs;
+ struct file *f = NULL;
- error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
-
- if (error)
+ error = -EINVAL;
+ if (flags & ~AT_SYMLINK_NOFOLLOW)
goto out;
- inode = nd.dentry->d_inode;
+
+ if (filename == NULL && dfd != AT_FDCWD) {
+ error = -EINVAL;
+ if (flags & AT_SYMLINK_NOFOLLOW)
+ goto out;
+
+ error = -EBADF;
+ f = fget(dfd);
+ if (!f)
+ goto out;
+ dentry = f->f_path.dentry;
+ } else {
+ error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
+ if (error)
+ goto out;
+
+ dentry = nd.dentry;
+ }
+
+ inode = dentry->d_inode;
error = -EROFS;
if (IS_RDONLY(inode))
@@ -100,11 +86,21 @@ long do_utimes(int dfd, char __user *filename, struct timeval *times)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
goto dput_and_out;
- newattrs.ia_atime.tv_sec = times[0].tv_sec;
- newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
- newattrs.ia_mtime.tv_sec = times[1].tv_sec;
- newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+ if (times[0].tv_nsec == UTIME_OMIT)
+ newattrs.ia_valid &= ~ATTR_ATIME;
+ else if (times[0].tv_nsec != UTIME_NOW) {
+ newattrs.ia_atime.tv_sec = times[0].tv_sec;
+ newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
+ newattrs.ia_valid |= ATTR_ATIME_SET;
+ }
+
+ if (times[1].tv_nsec == UTIME_OMIT)
+ newattrs.ia_valid &= ~ATTR_MTIME;
+ else if (times[1].tv_nsec != UTIME_NOW) {
+ newattrs.ia_mtime.tv_sec = times[1].tv_sec;
+ newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
+ newattrs.ia_valid |= ATTR_MTIME_SET;
+ }
} else {
error = -EACCES;
if (IS_IMMUTABLE(inode))
@@ -115,21 +111,67 @@ long do_utimes(int dfd, char __user *filename, struct timeval *times)
goto dput_and_out;
}
mutex_lock(&inode->i_mutex);
- error = notify_change(nd.dentry, &newattrs);
+ error = notify_change(dentry, &newattrs);
mutex_unlock(&inode->i_mutex);
dput_and_out:
- path_release(&nd);
+ if (f)
+ fput(f);
+ else
+ path_release(&nd);
out:
return error;
}
+asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __user *utimes, int flags)
+{
+ struct timespec tstimes[2];
+
+ if (utimes) {
+ if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
+ return -EFAULT;
+ if ((tstimes[0].tv_nsec == UTIME_OMIT ||
+ tstimes[0].tv_nsec == UTIME_NOW) &&
+ tstimes[0].tv_sec != 0)
+ return -EINVAL;
+ if ((tstimes[1].tv_nsec == UTIME_OMIT ||
+ tstimes[1].tv_nsec == UTIME_NOW) &&
+ tstimes[1].tv_sec != 0)
+ return -EINVAL;
+
+ /* Nothing to do, we must not even check the path. */
+ if (tstimes[0].tv_nsec == UTIME_OMIT &&
+ tstimes[1].tv_nsec == UTIME_OMIT)
+ return 0;
+ }
+
+ return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags);
+}
+
asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
{
struct timeval times[2];
+ struct timespec tstimes[2];
+
+ if (utimes) {
+ if (copy_from_user(&times, utimes, sizeof(times)))
+ return -EFAULT;
+
+ /* This test is needed to catch all invalid values. If we
+ would test only in do_utimes we would miss those invalid
+ values truncated by the multiplication with 1000. Note
+ that we also catch UTIME_{NOW,OMIT} here which are only
+ valid for utimensat. */
+ if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 ||
+ times[1].tv_usec >= 1000000 || times[1].tv_usec < 0)
+ return -EINVAL;
+
+ tstimes[0].tv_sec = times[0].tv_sec;
+ tstimes[0].tv_nsec = 1000 * times[0].tv_usec;
+ tstimes[1].tv_sec = times[1].tv_sec;
+ tstimes[1].tv_nsec = 1000 * times[1].tv_usec;
+ }
- if (utimes && copy_from_user(&times, utimes, sizeof(times)))
- return -EFAULT;
- return do_utimes(dfd, filename, utimes ? times : NULL);
+ return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0);
}
asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
diff --git a/fs/xattr.c b/fs/xattr.c
index 38646132ab0..9f4568b55b0 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -9,7 +9,6 @@
*/
#include <linux/fs.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/xattr.h>
#include <linux/namei.h>
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h
index af168a1a98c..c110bb00266 100644
--- a/fs/xfs/linux-2.6/mrlock.h
+++ b/fs/xfs/linux-2.6/mrlock.h
@@ -43,6 +43,18 @@ static inline void mrupdate(mrlock_t *mrp)
mrp->mr_writer = 1;
}
+static inline void mraccess_nested(mrlock_t *mrp, int subclass)
+{
+ down_read_nested(&mrp->mr_lock, subclass);
+}
+
+static inline void mrupdate_nested(mrlock_t *mrp, int subclass)
+{
+ down_write_nested(&mrp->mr_lock, subclass);
+ mrp->mr_writer = 1;
+}
+
+
static inline int mrtryaccess(mrlock_t *mrp)
{
return down_read_trylock(&mrp->mr_lock);
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 143ffc851c9..4475588e973 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -141,9 +141,46 @@ xfs_destroy_ioend(
}
/*
+ * Update on-disk file size now that data has been written to disk.
+ * The current in-memory file size is i_size. If a write is beyond
+ * eof io_new_size will be the intended file size until i_size is
+ * updated. If this write does not extend all the way to the valid
+ * file size then restrict this update to the end of the write.
+ */
+STATIC void
+xfs_setfilesize(
+ xfs_ioend_t *ioend)
+{
+ xfs_inode_t *ip;
+ xfs_fsize_t isize;
+ xfs_fsize_t bsize;
+
+ ip = xfs_vtoi(ioend->io_vnode);
+
+ ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
+ ASSERT(ioend->io_type != IOMAP_READ);
+
+ if (unlikely(ioend->io_error))
+ return;
+
+ bsize = ioend->io_offset + ioend->io_size;
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+ isize = MAX(ip->i_size, ip->i_iocore.io_new_size);
+ isize = MIN(isize, bsize);
+
+ if (ip->i_d.di_size < isize) {
+ ip->i_d.di_size = isize;
+ ip->i_update_core = 1;
+ ip->i_update_size = 1;
+ }
+
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+}
+
+/*
* Buffered IO write completion for delayed allocate extents.
- * TODO: Update ondisk isize now that we know the file data
- * has been flushed (i.e. the notorious "NULL file" problem).
*/
STATIC void
xfs_end_bio_delalloc(
@@ -152,6 +189,7 @@ xfs_end_bio_delalloc(
xfs_ioend_t *ioend =
container_of(work, xfs_ioend_t, io_work);
+ xfs_setfilesize(ioend);
xfs_destroy_ioend(ioend);
}
@@ -165,6 +203,7 @@ xfs_end_bio_written(
xfs_ioend_t *ioend =
container_of(work, xfs_ioend_t, io_work);
+ xfs_setfilesize(ioend);
xfs_destroy_ioend(ioend);
}
@@ -184,8 +223,23 @@ xfs_end_bio_unwritten(
xfs_off_t offset = ioend->io_offset;
size_t size = ioend->io_size;
- if (likely(!ioend->io_error))
+ if (likely(!ioend->io_error)) {
bhv_vop_bmap(vp, offset, size, BMAPI_UNWRITTEN, NULL, NULL);
+ xfs_setfilesize(ioend);
+ }
+ xfs_destroy_ioend(ioend);
+}
+
+/*
+ * IO read completion for regular, written extents.
+ */
+STATIC void
+xfs_end_bio_read(
+ struct work_struct *work)
+{
+ xfs_ioend_t *ioend =
+ container_of(work, xfs_ioend_t, io_work);
+
xfs_destroy_ioend(ioend);
}
@@ -224,6 +278,8 @@ xfs_alloc_ioend(
INIT_WORK(&ioend->io_work, xfs_end_bio_unwritten);
else if (type == IOMAP_DELAY)
INIT_WORK(&ioend->io_work, xfs_end_bio_delalloc);
+ else if (type == IOMAP_READ)
+ INIT_WORK(&ioend->io_work, xfs_end_bio_read);
else
INIT_WORK(&ioend->io_work, xfs_end_bio_written);
@@ -913,7 +969,7 @@ xfs_page_state_convert(
bh = head = page_buffers(page);
offset = page_offset(page);
flags = -1;
- type = 0;
+ type = IOMAP_READ;
/* TODO: cleanup count and page_dirty */
@@ -999,7 +1055,7 @@ xfs_page_state_convert(
* That means it must already have extents allocated
* underneath it. Map the extent by reading it.
*/
- if (!iomap_valid || type != 0) {
+ if (!iomap_valid || type != IOMAP_READ) {
flags = BMAPI_READ;
size = xfs_probe_cluster(inode, page, bh,
head, 1);
@@ -1010,7 +1066,7 @@ xfs_page_state_convert(
iomap_valid = xfs_iomap_valid(&iomap, offset);
}
- type = 0;
+ type = IOMAP_READ;
if (!test_and_set_bit(BH_Lock, &bh->b_state)) {
ASSERT(buffer_mapped(bh));
if (iomap_valid)
@@ -1356,12 +1412,21 @@ xfs_end_io_direct(
* completion handler in the future, in which case all this can
* go away.
*/
- if (private && size > 0) {
- ioend->io_offset = offset;
- ioend->io_size = size;
+ ioend->io_offset = offset;
+ ioend->io_size = size;
+ if (ioend->io_type == IOMAP_READ) {
+ xfs_finish_ioend(ioend);
+ } else if (private && size > 0) {
xfs_finish_ioend(ioend);
} else {
- xfs_destroy_ioend(ioend);
+ /*
+ * A direct I/O write ioend starts it's life in unwritten
+ * state in case they map an unwritten extent. This write
+ * didn't map an unwritten extent so switch it's completion
+ * handler.
+ */
+ INIT_WORK(&ioend->io_work, xfs_end_bio_written);
+ xfs_finish_ioend(ioend);
}
/*
@@ -1392,15 +1457,15 @@ xfs_vm_direct_IO(
if (error)
return -error;
- iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN);
-
if (rw == WRITE) {
+ iocb->private = xfs_alloc_ioend(inode, IOMAP_UNWRITTEN);
ret = blockdev_direct_IO_own_locking(rw, iocb, inode,
iomap.iomap_target->bt_bdev,
iov, offset, nr_segs,
xfs_get_blocks_direct,
xfs_end_io_direct);
} else {
+ iocb->private = xfs_alloc_ioend(inode, IOMAP_READ);
ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
iomap.iomap_target->bt_bdev,
iov, offset, nr_segs,
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 69e9e80735d..fe4f66a5af1 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1426,7 +1426,7 @@ xfs_free_bufhash(
/*
* buftarg list for delwrite queue processing
*/
-LIST_HEAD(xfs_buftarg_list);
+static LIST_HEAD(xfs_buftarg_list);
static DEFINE_SPINLOCK(xfs_buftarg_lock);
STATIC void
@@ -1867,3 +1867,11 @@ xfs_buf_terminate(void)
ktrace_free(xfs_buf_trace_buf);
#endif
}
+
+#ifdef CONFIG_KDB_MODULES
+struct list_head *
+xfs_get_buftarg_list(void)
+{
+ return &xfs_buftarg_list;
+}
+#endif
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 9e8ef8fef39..b6241f6201a 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -411,6 +411,9 @@ extern void xfs_free_buftarg(xfs_buftarg_t *, int);
extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
+#ifdef CONFIG_KDB_MODULES
+extern struct list_head *xfs_get_buftarg_list(void);
+#endif
#define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev)
#define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev)
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/linux-2.6/xfs_fs_subr.c
index dc0562828e7..2eb87cd082a 100644
--- a/fs/xfs/linux-2.6/xfs_fs_subr.c
+++ b/fs/xfs/linux-2.6/xfs_fs_subr.c
@@ -35,7 +35,7 @@ fs_tosspages(
truncate_inode_pages(ip->i_mapping, first);
}
-void
+int
fs_flushinval_pages(
bhv_desc_t *bdp,
xfs_off_t first,
@@ -44,13 +44,16 @@ fs_flushinval_pages(
{
bhv_vnode_t *vp = BHV_TO_VNODE(bdp);
struct inode *ip = vn_to_inode(vp);
+ int ret = 0;
if (VN_CACHED(vp)) {
if (VN_TRUNC(vp))
VUNTRUNCATE(vp);
- filemap_write_and_wait(ip->i_mapping);
- truncate_inode_pages(ip->i_mapping, first);
+ ret = filemap_write_and_wait(ip->i_mapping);
+ if (!ret)
+ truncate_inode_pages(ip->i_mapping, first);
}
+ return ret;
}
int
@@ -63,14 +66,18 @@ fs_flush_pages(
{
bhv_vnode_t *vp = BHV_TO_VNODE(bdp);
struct inode *ip = vn_to_inode(vp);
+ int ret = 0;
+ int ret2;
if (VN_DIRTY(vp)) {
if (VN_TRUNC(vp))
VUNTRUNCATE(vp);
- filemap_fdatawrite(ip->i_mapping);
+ ret = filemap_fdatawrite(ip->i_mapping);
if (flags & XFS_B_ASYNC)
- return 0;
- filemap_fdatawait(ip->i_mapping);
+ return ret;
+ ret2 = filemap_fdatawait(ip->i_mapping);
+ if (!ret)
+ ret = ret2;
}
- return 0;
+ return ret;
}
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.h b/fs/xfs/linux-2.6/xfs_fs_subr.h
index aee9ccdd18f..c1b53118a30 100644
--- a/fs/xfs/linux-2.6/xfs_fs_subr.h
+++ b/fs/xfs/linux-2.6/xfs_fs_subr.h
@@ -23,7 +23,7 @@ extern int fs_noerr(void);
extern int fs_nosys(void);
extern void fs_noval(void);
extern void fs_tosspages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
-extern void fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+extern int fs_flushinval_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
extern int fs_flush_pages(bhv_desc_t *, xfs_off_t, xfs_off_t, uint64_t, int);
#endif /* __XFS_FS_SUBR_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index ff8d64eba9f..86fb671a8bc 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -191,7 +191,7 @@ xfs_read(
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
size_t size = 0;
- ssize_t ret;
+ ssize_t ret = 0;
xfs_fsize_t n;
xfs_inode_t *ip;
xfs_mount_t *mp;
@@ -224,7 +224,7 @@ xfs_read(
mp->m_rtdev_targp : mp->m_ddev_targp;
if ((*offset & target->bt_smask) ||
(size & target->bt_smask)) {
- if (*offset == ip->i_d.di_size) {
+ if (*offset == ip->i_size) {
return (0);
}
return -XFS_ERROR(EINVAL);
@@ -263,9 +263,13 @@ xfs_read(
if (unlikely(ioflags & IO_ISDIRECT)) {
if (VN_CACHED(vp))
- bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
+ ret = bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
-1, FI_REMAPF_LOCKED);
mutex_unlock(&inode->i_mutex);
+ if (ret) {
+ xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+ return ret;
+ }
}
xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
@@ -383,9 +387,10 @@ xfs_splice_write(
{
xfs_inode_t *ip = XFS_BHVTOI(bdp);
xfs_mount_t *mp = ip->i_mount;
+ xfs_iocore_t *io = &ip->i_iocore;
ssize_t ret;
struct inode *inode = outfilp->f_mapping->host;
- xfs_fsize_t isize;
+ xfs_fsize_t isize, new_size;
XFS_STATS_INC(xs_write_calls);
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -406,6 +411,14 @@ xfs_splice_write(
return -error;
}
}
+
+ new_size = *ppos + count;
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ if (new_size > ip->i_size)
+ io->io_new_size = new_size;
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore,
pipe, count, *ppos, ioflags);
ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags);
@@ -416,14 +429,18 @@ xfs_splice_write(
if (unlikely(ret < 0 && ret != -EFAULT && *ppos > isize))
*ppos = isize;
- if (*ppos > ip->i_d.di_size) {
+ if (*ppos > ip->i_size) {
xfs_ilock(ip, XFS_ILOCK_EXCL);
- if (*ppos > ip->i_d.di_size) {
- ip->i_d.di_size = *ppos;
- i_size_write(inode, *ppos);
- ip->i_update_core = 1;
- ip->i_update_size = 1;
- }
+ if (*ppos > ip->i_size)
+ ip->i_size = *ppos;
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ }
+
+ if (io->io_new_size) {
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ io->io_new_size = 0;
+ if (ip->i_d.di_size > ip->i_size)
+ ip->i_d.di_size = ip->i_size;
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
@@ -639,37 +656,21 @@ xfs_write(
xfs_fsize_t isize, new_size;
xfs_iocore_t *io;
bhv_vnode_t *vp;
- unsigned long seg;
int iolock;
int eventsent = 0;
bhv_vrwlock_t locktype;
size_t ocount = 0, count;
loff_t pos;
- int need_i_mutex = 1, need_flush = 0;
+ int need_i_mutex;
XFS_STATS_INC(xs_write_calls);
vp = BHV_TO_VNODE(bdp);
xip = XFS_BHVTOI(bdp);
- for (seg = 0; seg < segs; seg++) {
- const struct iovec *iv = &iovp[seg];
-
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- ocount += iv->iov_len;
- if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- segs = seg;
- ocount -= iv->iov_len; /* This segment is no good */
- break;
- }
+ error = generic_segment_checks(iovp, &segs, &ocount, VERIFY_READ);
+ if (error)
+ return error;
count = ocount;
pos = *offset;
@@ -685,39 +686,20 @@ xfs_write(
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
- if (ioflags & IO_ISDIRECT) {
- xfs_buftarg_t *target =
- (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
- mp->m_rtdev_targp : mp->m_ddev_targp;
-
- if ((pos & target->bt_smask) || (count & target->bt_smask))
- return XFS_ERROR(-EINVAL);
-
- if (!VN_CACHED(vp) && pos < i_size_read(inode))
- need_i_mutex = 0;
-
- if (VN_CACHED(vp))
- need_flush = 1;
- }
-
relock:
- if (need_i_mutex) {
+ if (ioflags & IO_ISDIRECT) {
+ iolock = XFS_IOLOCK_SHARED;
+ locktype = VRWLOCK_WRITE_DIRECT;
+ need_i_mutex = 0;
+ } else {
iolock = XFS_IOLOCK_EXCL;
locktype = VRWLOCK_WRITE;
-
+ need_i_mutex = 1;
mutex_lock(&inode->i_mutex);
- } else {
- iolock = XFS_IOLOCK_SHARED;
- locktype = VRWLOCK_WRITE_DIRECT;
}
xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
- isize = i_size_read(inode);
-
- if (file->f_flags & O_APPEND)
- *offset = isize;
-
start:
error = -generic_write_checks(file, &pos, &count,
S_ISBLK(inode->i_mode));
@@ -726,13 +708,8 @@ start:
goto out_unlock_mutex;
}
- new_size = pos + count;
- if (new_size > isize)
- io->io_new_size = new_size;
-
if ((DM_EVENT_ENABLED(vp->v_vfsp, xip, DM_EVENT_WRITE) &&
!(ioflags & IO_INVIS) && !eventsent)) {
- loff_t savedsize = pos;
int dmflags = FILP_DELAY_FLAG(file);
if (need_i_mutex)
@@ -743,8 +720,7 @@ start:
pos, count,
dmflags, &locktype);
if (error) {
- xfs_iunlock(xip, iolock);
- goto out_unlock_mutex;
+ goto out_unlock_internal;
}
xfs_ilock(xip, XFS_ILOCK_EXCL);
eventsent = 1;
@@ -756,12 +732,35 @@ start:
* event prevents another call to XFS_SEND_DATA, which is
* what allows the size to change in the first place.
*/
- if ((file->f_flags & O_APPEND) && savedsize != isize) {
- pos = isize = xip->i_d.di_size;
+ if ((file->f_flags & O_APPEND) && pos != xip->i_size)
+ goto start;
+ }
+
+ if (ioflags & IO_ISDIRECT) {
+ xfs_buftarg_t *target =
+ (xip->i_d.di_flags & XFS_DIFLAG_REALTIME) ?
+ mp->m_rtdev_targp : mp->m_ddev_targp;
+
+ if ((pos & target->bt_smask) || (count & target->bt_smask)) {
+ xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
+ return XFS_ERROR(-EINVAL);
+ }
+
+ if (!need_i_mutex && (VN_CACHED(vp) || pos > xip->i_size)) {
+ xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
+ iolock = XFS_IOLOCK_EXCL;
+ locktype = VRWLOCK_WRITE;
+ need_i_mutex = 1;
+ mutex_lock(&inode->i_mutex);
+ xfs_ilock(xip, XFS_ILOCK_EXCL|iolock);
goto start;
}
}
+ new_size = pos + count;
+ if (new_size > xip->i_size)
+ io->io_new_size = new_size;
+
if (likely(!(ioflags & IO_INVIS))) {
file_update_time(file);
xfs_ichgtime_fast(xip, inode,
@@ -777,11 +776,11 @@ start:
* to zero it out up to the new size.
*/
- if (pos > isize) {
- error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize);
+ if (pos > xip->i_size) {
+ error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, xip->i_size);
if (error) {
- xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock);
- goto out_unlock_mutex;
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
+ goto out_unlock_internal;
}
}
xfs_iunlock(xip, XFS_ILOCK_EXCL);
@@ -801,8 +800,7 @@ start:
if (likely(!error))
error = -remove_suid(file->f_path.dentry);
if (unlikely(error)) {
- xfs_iunlock(xip, iolock);
- goto out_unlock_mutex;
+ goto out_unlock_internal;
}
}
@@ -811,11 +809,14 @@ retry:
current->backing_dev_info = mapping->backing_dev_info;
if ((ioflags & IO_ISDIRECT)) {
- if (need_flush) {
+ if (VN_CACHED(vp)) {
+ WARN_ON(need_i_mutex == 0);
xfs_inval_cached_trace(io, pos, -1,
ctooff(offtoct(pos)), -1);
- bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)),
+ error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(pos)),
-1, FI_REMAPF_LOCKED);
+ if (error)
+ goto out_unlock_internal;
}
if (need_i_mutex) {
@@ -843,7 +844,6 @@ retry:
pos += ret;
count -= ret;
- need_i_mutex = 1;
ioflags &= ~IO_ISDIRECT;
xfs_iunlock(xip, iolock);
goto relock;
@@ -870,12 +870,12 @@ retry:
error = XFS_SEND_NAMESP(xip->i_mount, DM_EVENT_NOSPACE, vp,
DM_RIGHT_NULL, vp, DM_RIGHT_NULL, NULL, NULL,
0, 0, 0); /* Delay flag intentionally unused */
- if (error)
- goto out_nounlocks;
if (need_i_mutex)
mutex_lock(&inode->i_mutex);
xfs_rwlock(bdp, locktype);
- pos = xip->i_d.di_size;
+ if (error)
+ goto out_unlock_internal;
+ pos = xip->i_size;
ret = 0;
goto retry;
}
@@ -884,14 +884,10 @@ retry:
if (unlikely(ret < 0 && ret != -EFAULT && *offset > isize))
*offset = isize;
- if (*offset > xip->i_d.di_size) {
+ if (*offset > xip->i_size) {
xfs_ilock(xip, XFS_ILOCK_EXCL);
- if (*offset > xip->i_d.di_size) {
- xip->i_d.di_size = *offset;
- i_size_write(inode, *offset);
- xip->i_update_core = 1;
- xip->i_update_size = 1;
- }
+ if (*offset > xip->i_size)
+ xip->i_size = *offset;
xfs_iunlock(xip, XFS_ILOCK_EXCL);
}
@@ -913,16 +909,31 @@ retry:
error = sync_page_range(inode, mapping, pos, ret);
if (!error)
- error = ret;
- return error;
+ error = -ret;
+ if (need_i_mutex)
+ mutex_lock(&inode->i_mutex);
+ xfs_rwlock(bdp, locktype);
}
out_unlock_internal:
+ if (io->io_new_size) {
+ xfs_ilock(xip, XFS_ILOCK_EXCL);
+ io->io_new_size = 0;
+ /*
+ * If this was a direct or synchronous I/O that failed (such
+ * as ENOSPC) then part of the I/O may have been written to
+ * disk before the error occured. In this case the on-disk
+ * file size may have been adjusted beyond the in-memory file
+ * size and now needs to be truncated back.
+ */
+ if (xip->i_d.di_size > xip->i_size)
+ xip->i_d.di_size = xip->i_size;
+ xfs_iunlock(xip, XFS_ILOCK_EXCL);
+ }
xfs_rwunlock(bdp, locktype);
out_unlock_mutex:
if (need_i_mutex)
mutex_unlock(&inode->i_mutex);
- out_nounlocks:
return -error;
}
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 2f2c40db562..14e2cbe5a8d 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -360,8 +360,7 @@ xfs_fs_inode_init_once(
kmem_zone_t *zonep,
unsigned long flags)
{
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(vn_to_inode((bhv_vnode_t *)vnode));
}
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index b76118cf489..d1b2d01843d 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -194,7 +194,7 @@ typedef int (*vop_attr_list_t)(bhv_desc_t *, char *, int, int,
typedef void (*vop_link_removed_t)(bhv_desc_t *, bhv_vnode_t *, int);
typedef void (*vop_vnode_change_t)(bhv_desc_t *, bhv_vchange_t, __psint_t);
typedef void (*vop_ptossvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
-typedef void (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
+typedef int (*vop_pflushinvalvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t, int);
typedef int (*vop_pflushvp_t)(bhv_desc_t *, xfs_off_t, xfs_off_t,
uint64_t, int);
typedef int (*vop_iflush_t)(bhv_desc_t *, int);
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index 4adaf13aac6..cfdd35ee9f7 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -753,8 +753,7 @@ xfs_qm_idtodq(
goto error0;
}
if (tp) {
- if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
- NULL)))
+ if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES)))
goto error1;
}
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 1de2acdc7f7..3e4a8ad8a34 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -388,6 +388,17 @@ xfs_qm_mount_quotas(
return XFS_ERROR(error);
}
}
+ /*
+ * If one type of quotas is off, then it will lose its
+ * quotachecked status, since we won't be doing accounting for
+ * that type anymore.
+ */
+ if (!XFS_IS_UQUOTA_ON(mp)) {
+ mp->m_qflags &= ~XFS_UQUOTA_CHKD;
+ }
+ if (!(XFS_IS_GQUOTA_ON(mp) || XFS_IS_PQUOTA_ON(mp))) {
+ mp->m_qflags &= ~XFS_OQUOTA_CHKD;
+ }
write_changes:
/*
@@ -1453,8 +1464,7 @@ xfs_qm_qino_alloc(
XFS_SB_UNLOCK(mp, s);
xfs_mod_sb(tp, sbfields);
- if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
- NULL))) {
+ if ((error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES))) {
xfs_fs_cmn_err(CE_ALERT, mp, "XFS qino_alloc failed!");
return error;
}
@@ -2405,7 +2415,7 @@ xfs_qm_write_sb_changes(
}
xfs_mod_sb(tp, flags);
- (void) xfs_trans_commit(tp, 0, NULL);
+ (void) xfs_trans_commit(tp, 0);
return 0;
}
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 716f562aa8b..2df67fd913e 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -456,9 +456,7 @@ xfs_qm_scall_quotaon(
||
((flags & XFS_PQUOTA_ACCT) == 0 &&
(mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
- (flags & XFS_OQUOTA_ENFD))
- ||
- ((flags & XFS_GQUOTA_ACCT) == 0 &&
+ (flags & XFS_GQUOTA_ACCT) == 0 &&
(mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
(flags & XFS_OQUOTA_ENFD))) {
qdprintk("Can't enforce without acct, flags=%x sbflags=%x\n",
@@ -735,7 +733,7 @@ xfs_qm_scall_setqlim(
xfs_trans_log_dquot(tp, dqp);
xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT");
- xfs_trans_commit(tp, 0, NULL);
+ xfs_trans_commit(tp, 0);
xfs_qm_dqprint(dqp);
xfs_qm_dqrele(dqp);
mutex_unlock(&(XFS_QI_QOFFLOCK(mp)));
@@ -809,7 +807,7 @@ xfs_qm_log_quotaoff_end(
* We don't care about quotoff's performance.
*/
xfs_trans_set_sync(tp);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
return (error);
}
@@ -852,7 +850,7 @@ xfs_qm_log_quotaoff(
* We don't care about quotoff's performance.
*/
xfs_trans_set_sync(tp);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
error0:
if (error) {
@@ -911,14 +909,19 @@ xfs_qm_export_dquot(
* gets turned off. No need to confuse the user level code,
* so return zeroes in that case.
*/
- if (! XFS_IS_QUOTA_ENFORCED(mp)) {
+ if ((!XFS_IS_UQUOTA_ENFORCED(mp) && src->d_flags == XFS_DQ_USER) ||
+ (!XFS_IS_OQUOTA_ENFORCED(mp) &&
+ (src->d_flags & (XFS_DQ_PROJ | XFS_DQ_GROUP)))) {
dst->d_btimer = 0;
dst->d_itimer = 0;
dst->d_rtbtimer = 0;
}
#ifdef DEBUG
- if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) {
+ if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == XFS_USER_QUOTA) ||
+ (XFS_IS_OQUOTA_ENFORCED(mp) &&
+ (dst->d_flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)))) &&
+ dst->d_id != 0) {
if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
(dst->d_blk_softlimit > 0)) {
ASSERT(dst->d_btimer != 0);
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index d7491e7b1f3..7de6874bf1b 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -656,7 +656,9 @@ xfs_trans_dqresv(
if ((flags & XFS_QMOPT_FORCE_RES) == 0 &&
dqp->q_core.d_id &&
- XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) {
+ ((XFS_IS_UQUOTA_ENFORCED(dqp->q_mount) && XFS_QM_ISUDQ(dqp)) ||
+ (XFS_IS_OQUOTA_ENFORCED(dqp->q_mount) &&
+ (XFS_QM_ISPDQ(dqp) || XFS_QM_ISGDQ(dqp))))) {
#ifdef QUOTADEBUG
cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld"
" > hardlimit=%Ld?", nblks, *resbcountp, hardlimit);
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 08bbd3cb87a..f45a49ffd3a 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -81,20 +81,3 @@ assfail(char *expr, char *file, int line)
printk("Assertion failed: %s, file: %s, line: %d\n", expr, file, line);
BUG();
}
-
-#if ((defined(DEBUG) || defined(INDUCE_IO_ERRROR)) && !defined(NO_WANT_RANDOM))
-unsigned long random(void)
-{
- static unsigned long RandomValue = 1;
- /* cycles pseudo-randomly through all values between 1 and 2^31 - 2 */
- register long rv = RandomValue;
- register long lo;
- register long hi;
-
- hi = rv / 127773;
- lo = rv % 127773;
- rv = 16807 * lo - 2836 * hi;
- if (rv <= 0) rv += 2147483647;
- return RandomValue = rv;
-}
-#endif /* DEBUG || INDUCE_IO_ERRROR || !NO_WANT_RANDOM */
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h
index 2a70cc605ae..a27a7c8c052 100644
--- a/fs/xfs/support/debug.h
+++ b/fs/xfs/support/debug.h
@@ -50,7 +50,7 @@ extern void assfail(char *expr, char *f, int l);
#else /* DEBUG */
# define ASSERT(expr) ASSERT_ALWAYS(expr)
-extern unsigned long random(void);
+# include <linux/random.h>
#ifndef STATIC
# define STATIC noinline
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index e80dda3437d..8e9a40aa0cd 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -764,7 +764,7 @@ xfs_alloc_ag_vextent_near(
*/
int dofirst; /* set to do first algorithm */
- dofirst = random() & 1;
+ dofirst = random32() & 1;
#endif
/*
* Get a cursor for the by-size btree.
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 9d358ffce4e..7ce44a7b88a 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -328,8 +328,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
xfs_trans_set_sync(args.trans);
}
err2 = xfs_trans_commit(args.trans,
- XFS_TRANS_RELEASE_LOG_RES,
- NULL);
+ XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
/*
@@ -397,8 +396,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
* Commit the last in the sequence of transactions.
*/
xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
- error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
- NULL);
+ error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
/*
@@ -544,8 +542,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
* Commit the last in the sequence of transactions.
*/
xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
- error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES,
- NULL);
+ error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
/*
@@ -859,8 +856,7 @@ xfs_attr_inactive(xfs_inode_t *dp)
* Commit the last in the sequence of transactions.
*/
xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
- error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES,
- NULL);
+ error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(dp, XFS_ILOCK_EXCL);
return(error);
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 8eab73e8340..81f45dae1c5 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -3053,7 +3053,7 @@ xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp)
* is in progress. The caller takes the responsibility to cancel
* the duplicate transaction that gets returned.
*/
- if ((error = xfs_trans_commit(trans, 0, NULL)))
+ if ((error = xfs_trans_commit(trans, 0)))
return (error);
trans = *transp;
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 87795188ced..b1ea26e40aa 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -130,7 +130,6 @@ STATIC int /* error */
xfs_bmap_add_extent_hole_delay(
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* extent number to update/insert */
- xfs_btree_cur_t *cur, /* if null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp,/* inode logging flags */
xfs_extdelta_t *delta, /* Change made to incore extents */
@@ -399,7 +398,6 @@ xfs_bmap_count_leaves(
STATIC int
xfs_bmap_disk_count_leaves(
- xfs_ifork_t *ifp,
xfs_extnum_t idx,
xfs_bmbt_block_t *block,
int numrecs,
@@ -580,7 +578,7 @@ xfs_bmap_add_extent(
if (cur)
ASSERT((cur->bc_private.b.flags &
XFS_BTCUR_BPRV_WASDEL) == 0);
- if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, cur, new,
+ if ((error = xfs_bmap_add_extent_hole_delay(ip, idx, new,
&logflags, delta, rsvd)))
goto done;
}
@@ -1841,7 +1839,6 @@ STATIC int /* error */
xfs_bmap_add_extent_hole_delay(
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* extent number to update/insert */
- xfs_btree_cur_t *cur, /* if null, not a btree */
xfs_bmbt_irec_t *new, /* new data to add to file extents */
int *logflagsp, /* inode logging flags */
xfs_extdelta_t *delta, /* Change made to incore extents */
@@ -4071,7 +4068,7 @@ xfs_bmap_add_attrfork(
}
if ((error = xfs_bmap_finish(&tp, &flist, &committed)))
goto error2;
- error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES);
ASSERT(ip->i_df.if_ext_max ==
XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t));
return error;
@@ -4227,7 +4224,7 @@ xfs_bmap_finish(
logres = ntp->t_log_res;
logcount = ntp->t_log_count;
ntp = xfs_trans_dup(*tp);
- error = xfs_trans_commit(*tp, 0, NULL);
+ error = xfs_trans_commit(*tp, 0);
*tp = ntp;
*committed = 1;
/*
@@ -4447,8 +4444,11 @@ xfs_bmap_one_block(
xfs_bmbt_irec_t s; /* internal version of extent */
#ifndef DEBUG
- if (whichfork == XFS_DATA_FORK)
- return ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize;
+ if (whichfork == XFS_DATA_FORK) {
+ return ((ip->i_d.di_mode & S_IFMT) == S_IFREG) ?
+ (ip->i_size == ip->i_mount->m_sb.sb_blocksize) :
+ (ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
+ }
#endif /* !DEBUG */
if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1)
return 0;
@@ -4460,7 +4460,7 @@ xfs_bmap_one_block(
xfs_bmbt_get_all(ep, &s);
rval = s.br_startoff == 0 && s.br_blockcount == 1;
if (rval && whichfork == XFS_DATA_FORK)
- ASSERT(ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize);
+ ASSERT(ip->i_size == ip->i_mount->m_sb.sb_blocksize);
return rval;
}
@@ -5820,7 +5820,7 @@ xfs_getbmap(
fixlen = XFS_MAXIOFFSET(mp);
} else {
prealloced = 0;
- fixlen = ip->i_d.di_size;
+ fixlen = ip->i_size;
}
} else {
prealloced = 0;
@@ -5844,7 +5844,8 @@ xfs_getbmap(
xfs_ilock(ip, XFS_IOLOCK_SHARED);
- if (whichfork == XFS_DATA_FORK && ip->i_delayed_blks) {
+ if (whichfork == XFS_DATA_FORK &&
+ (ip->i_delayed_blks || ip->i_size > ip->i_d.di_size)) {
/* xfs_fsize_t last_byte = xfs_file_last_byte(ip); */
error = bhv_vop_flush_pages(vp, (xfs_off_t)0, -1, 0, FI_REMAPF);
}
@@ -6425,8 +6426,8 @@ xfs_bmap_count_tree(
for (;;) {
nextbno = be64_to_cpu(block->bb_rightsib);
numrecs = be16_to_cpu(block->bb_numrecs);
- if (unlikely(xfs_bmap_disk_count_leaves(ifp,
- 0, block, numrecs, count) < 0)) {
+ if (unlikely(xfs_bmap_disk_count_leaves(0,
+ block, numrecs, count) < 0)) {
xfs_trans_brelse(tp, bp);
XFS_ERROR_REPORT("xfs_bmap_count_tree(2)",
XFS_ERRLEVEL_LOW, mp);
@@ -6472,7 +6473,6 @@ xfs_bmap_count_leaves(
*/
int
xfs_bmap_disk_count_leaves(
- xfs_ifork_t *ifp,
xfs_extnum_t idx,
xfs_bmbt_block_t *block,
int numrecs,
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index b847e6a7a3f..de35d18cc00 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -199,7 +199,9 @@ xfs_swap_extents(
if (VN_CACHED(tvp) != 0) {
xfs_inval_cached_trace(&tip->i_iocore, 0, -1, 0, -1);
- bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED);
+ error = bhv_vop_flushinval_pages(tvp, 0, -1, FI_REMAPF_LOCKED);
+ if (error)
+ goto error0;
}
/* Verify O_DIRECT for ftmp */
@@ -382,7 +384,7 @@ xfs_swap_extents(
xfs_trans_set_sync(tp);
}
- error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_SWAPEXT);
locked = 0;
error0:
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 9d7438bba30..3accc1dcd6c 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -282,8 +282,7 @@ xfs_dir2_block_addname(
* This needs to happen before the next call to use_free.
*/
if (needscan) {
- xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
- &needlog, NULL);
+ xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
needscan = 0;
}
}
@@ -333,7 +332,7 @@ xfs_dir2_block_addname(
*/
if (needscan) {
xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
- &needlog, NULL);
+ &needlog);
needscan = 0;
}
/*
@@ -418,8 +417,7 @@ xfs_dir2_block_addname(
* Clean up the bestfree array and log the header, tail, and entry.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
- NULL);
+ xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, bp);
xfs_dir2_block_log_tail(tp, bp);
@@ -798,8 +796,7 @@ xfs_dir2_block_removename(
* Fix up bestfree, log the header if necessary.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
- NULL);
+ xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, bp);
xfs_dir2_data_check(dp, bp);
@@ -996,8 +993,7 @@ xfs_dir2_leaf_to_block(
* Scan the bestfree if we need it and log the data block header.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
- NULL);
+ xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dbp);
/*
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index f7c79921707..c211c37ef67 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -324,8 +324,7 @@ void
xfs_dir2_data_freescan(
xfs_mount_t *mp, /* filesystem mount point */
xfs_dir2_data_t *d, /* data block pointer */
- int *loghead, /* out: log data header */
- char *aendp) /* in: caller's endp */
+ int *loghead) /* out: log data header */
{
xfs_dir2_block_tail_t *btp; /* block tail */
xfs_dir2_data_entry_t *dep; /* active data entry */
@@ -346,9 +345,7 @@ xfs_dir2_data_freescan(
* Set up pointers.
*/
p = (char *)d->u;
- if (aendp)
- endp = aendp;
- else if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
+ if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
} else
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h
index a6ae2d21c40..c94c9099cfb 100644
--- a/fs/xfs/xfs_dir2_data.h
+++ b/fs/xfs/xfs_dir2_data.h
@@ -166,7 +166,7 @@ extern xfs_dir2_data_free_t *xfs_dir2_data_freefind(xfs_dir2_data_t *d,
extern xfs_dir2_data_free_t *xfs_dir2_data_freeinsert(xfs_dir2_data_t *d,
xfs_dir2_data_unused_t *dup, int *loghead);
extern void xfs_dir2_data_freescan(struct xfs_mount *mp, xfs_dir2_data_t *d,
- int *loghead, char *aendp);
+ int *loghead);
extern int xfs_dir2_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
struct xfs_dabuf **bpp);
extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_dabuf *bp,
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index b1cf1fbf423..db14ea71459 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -133,8 +133,7 @@ xfs_dir2_block_to_leaf(
*/
block->hdr.magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC);
if (needscan)
- xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
- NULL);
+ xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);
/*
* Set up leaf tail and bests table.
*/
@@ -414,7 +413,7 @@ xfs_dir2_leaf_addname(
* Need to scan fix up the bestfree table.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+ xfs_dir2_data_freescan(mp, data, &needlog);
/*
* Need to log the data block's header.
*/
@@ -1496,7 +1495,7 @@ xfs_dir2_leaf_removename(
* log the data block header if necessary.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+ xfs_dir2_data_freescan(mp, data, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dbp);
/*
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 9ca71719b68..d083c381993 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -904,7 +904,7 @@ xfs_dir2_leafn_remove(
* Log the data block header if needed.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+ xfs_dir2_data_freescan(mp, data, &needlog);
if (needlog)
xfs_dir2_data_log_header(tp, dbp);
xfs_dir2_data_check(dp, dbp);
@@ -1705,7 +1705,7 @@ xfs_dir2_node_addname_int(
* Rescan the block for bestfree if needed.
*/
if (needscan)
- xfs_dir2_data_freescan(mp, data, &needlog, NULL);
+ xfs_dir2_data_freescan(mp, data, &needlog);
/*
* Log the data block header if needed.
*/
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index b1af54464f0..8c433163133 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -80,7 +80,7 @@ xfs_error_test(int error_tag, int *fsidp, char *expression,
int i;
int64_t fsid;
- if (random() % randfactor)
+ if (random32() % randfactor)
return 0;
memcpy(&fsid, fsidp, sizeof(xfs_fsid_t));
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 32c37c1c47a..b599e6be9ec 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -346,7 +346,7 @@ xfs_growfs_data_private(
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree);
if (dpct)
xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
if (error) {
return error;
}
@@ -605,7 +605,7 @@ xfs_fs_log_dummy(
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
- xfs_trans_commit(tp, 0, NULL);
+ xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index c1c89dac19c..114433a22ba 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -879,17 +879,17 @@ xfs_ilock(xfs_inode_t *ip,
(XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
(XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
- ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+ ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
if (lock_flags & XFS_IOLOCK_EXCL) {
- mrupdate(&ip->i_iolock);
+ mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
} else if (lock_flags & XFS_IOLOCK_SHARED) {
- mraccess(&ip->i_iolock);
+ mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
}
if (lock_flags & XFS_ILOCK_EXCL) {
- mrupdate(&ip->i_lock);
+ mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
} else if (lock_flags & XFS_ILOCK_SHARED) {
- mraccess(&ip->i_lock);
+ mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
}
xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address);
}
@@ -923,7 +923,7 @@ xfs_ilock_nowait(xfs_inode_t *ip,
(XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
(XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
- ASSERT((lock_flags & ~XFS_LOCK_MASK) == 0);
+ ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
iolocked = 0;
if (lock_flags & XFS_IOLOCK_EXCL) {
@@ -983,7 +983,8 @@ xfs_iunlock(xfs_inode_t *ip,
(XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
(XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
- ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY)) == 0);
+ ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_IUNLOCK_NONOTIFY |
+ XFS_LOCK_DEP_MASK)) == 0);
ASSERT(lock_flags != 0);
if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) {
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3da9829c19d..3ca5d43b834 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -442,6 +442,7 @@ xfs_iformat(
return XFS_ERROR(EFSCORRUPTED);
}
ip->i_d.di_size = 0;
+ ip->i_size = 0;
ip->i_df.if_u2.if_rdev = INT_GET(dip->di_u.di_dev, ARCH_CONVERT);
break;
@@ -980,6 +981,7 @@ xfs_iread(
}
ip->i_delayed_blks = 0;
+ ip->i_size = ip->i_d.di_size;
/*
* Mark the buffer containing the inode as something to keep
@@ -1170,6 +1172,7 @@ xfs_ialloc(
}
ip->i_d.di_size = 0;
+ ip->i_size = 0;
ip->i_d.di_nextents = 0;
ASSERT(ip->i_d.di_nblocks == 0);
xfs_ichgtime(ip, XFS_ICHGTIME_CHG|XFS_ICHGTIME_ACC|XFS_ICHGTIME_MOD);
@@ -1340,7 +1343,7 @@ xfs_file_last_byte(
} else {
last_block = 0;
}
- size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_d.di_size);
+ size_last_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)ip->i_size);
last_block = XFS_FILEOFF_MAX(last_block, size_last_block);
last_byte = XFS_FSB_TO_B(mp, last_block);
@@ -1421,7 +1424,7 @@ xfs_itrunc_trace(
* must be called again with all the same restrictions as the initial
* call.
*/
-void
+int
xfs_itruncate_start(
xfs_inode_t *ip,
uint flags,
@@ -1431,9 +1434,10 @@ xfs_itruncate_start(
xfs_off_t toss_start;
xfs_mount_t *mp;
bhv_vnode_t *vp;
+ int error = 0;
ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
- ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size));
+ ASSERT((new_size == 0) || (new_size <= ip->i_size));
ASSERT((flags == XFS_ITRUNC_DEFINITE) ||
(flags == XFS_ITRUNC_MAYBE));
@@ -1468,7 +1472,7 @@ xfs_itruncate_start(
* file size, so there is no way that the data extended
* out there.
*/
- return;
+ return 0;
}
last_byte = xfs_file_last_byte(ip);
xfs_itrunc_trace(XFS_ITRUNC_START, ip, flags, new_size, toss_start,
@@ -1477,7 +1481,7 @@ xfs_itruncate_start(
if (flags & XFS_ITRUNC_DEFINITE) {
bhv_vop_toss_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
} else {
- bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
+ error = bhv_vop_flushinval_pages(vp, toss_start, -1, FI_REMAPF_LOCKED);
}
}
@@ -1486,6 +1490,7 @@ xfs_itruncate_start(
ASSERT(VN_CACHED(vp) == 0);
}
#endif
+ return error;
}
/*
@@ -1556,7 +1561,7 @@ xfs_itruncate_finish(
ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
- ASSERT((new_size == 0) || (new_size <= ip->i_d.di_size));
+ ASSERT((new_size == 0) || (new_size <= ip->i_size));
ASSERT(*tp != NULL);
ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
ASSERT(ip->i_transp == *tp);
@@ -1630,8 +1635,20 @@ xfs_itruncate_finish(
*/
if (fork == XFS_DATA_FORK) {
if (ip->i_d.di_nextents > 0) {
- ip->i_d.di_size = new_size;
- xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
+ /*
+ * If we are not changing the file size then do
+ * not update the on-disk file size - we may be
+ * called from xfs_inactive_free_eofblocks(). If we
+ * update the on-disk file size and then the system
+ * crashes before the contents of the file are
+ * flushed to disk then the files may be full of
+ * holes (ie NULL files bug).
+ */
+ if (ip->i_size != new_size) {
+ ip->i_d.di_size = new_size;
+ ip->i_size = new_size;
+ xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
+ }
}
} else if (sync) {
ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC));
@@ -1746,7 +1763,7 @@ xfs_itruncate_finish(
xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
}
ntp = xfs_trans_dup(ntp);
- (void) xfs_trans_commit(*tp, 0, NULL);
+ (void) xfs_trans_commit(*tp, 0);
*tp = ntp;
error = xfs_trans_reserve(ntp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
@@ -1767,7 +1784,19 @@ xfs_itruncate_finish(
*/
if (fork == XFS_DATA_FORK) {
xfs_isize_check(mp, ip, new_size);
- ip->i_d.di_size = new_size;
+ /*
+ * If we are not changing the file size then do
+ * not update the on-disk file size - we may be
+ * called from xfs_inactive_free_eofblocks(). If we
+ * update the on-disk file size and then the system
+ * crashes before the contents of the file are
+ * flushed to disk then the files may be full of
+ * holes (ie NULL files bug).
+ */
+ if (ip->i_size != new_size) {
+ ip->i_d.di_size = new_size;
+ ip->i_size = new_size;
+ }
}
xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE);
ASSERT((new_size != 0) ||
@@ -1800,7 +1829,7 @@ xfs_igrow_start(
ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);
ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);
- ASSERT(new_size > ip->i_d.di_size);
+ ASSERT(new_size > ip->i_size);
/*
* Zero any pages that may have been created by
@@ -1808,7 +1837,7 @@ xfs_igrow_start(
* and any blocks between the old and new file sizes.
*/
error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size,
- ip->i_d.di_size);
+ ip->i_size);
return error;
}
@@ -1832,13 +1861,14 @@ xfs_igrow_finish(
ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);
ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);
ASSERT(ip->i_transp == tp);
- ASSERT(new_size > ip->i_d.di_size);
+ ASSERT(new_size > ip->i_size);
/*
* Update the file size. Update the inode change timestamp
* if change_flag set.
*/
ip->i_d.di_size = new_size;
+ ip->i_size = new_size;
if (change_flag)
xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
@@ -2321,7 +2351,7 @@ xfs_ifree(
ASSERT(ip->i_d.di_nlink == 0);
ASSERT(ip->i_d.di_nextents == 0);
ASSERT(ip->i_d.di_anextents == 0);
- ASSERT((ip->i_d.di_size == 0) ||
+ ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) ||
((ip->i_d.di_mode & S_IFMT) != S_IFREG));
ASSERT(ip->i_d.di_nblocks == 0);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index bc823720d88..f75afecef8e 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -287,6 +287,7 @@ typedef struct xfs_inode {
struct xfs_inode *i_cnext; /* cluster hash link forward */
struct xfs_inode *i_cprev; /* cluster hash link backward */
+ xfs_fsize_t i_size; /* in-memory size */
/* Trace buffers per inode. */
#ifdef XFS_BMAP_TRACE
struct ktrace *i_xtrace; /* inode extent list trace */
@@ -305,6 +306,8 @@ typedef struct xfs_inode {
#endif
} xfs_inode_t;
+#define XFS_ISIZE(ip) (((ip)->i_d.di_mode & S_IFMT) == S_IFREG) ? \
+ (ip)->i_size : (ip)->i_d.di_size;
/*
* i_flags helper functions
@@ -379,26 +382,58 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags)
/*
* Flags for inode locking.
+ * Bit ranges: 1<<1 - 1<<16-1 -- iolock/ilock modes (bitfield)
+ * 1<<16 - 1<<32-1 -- lockdep annotation (integers)
*/
-#define XFS_IOLOCK_EXCL 0x001
-#define XFS_IOLOCK_SHARED 0x002
-#define XFS_ILOCK_EXCL 0x004
-#define XFS_ILOCK_SHARED 0x008
-#define XFS_IUNLOCK_NONOTIFY 0x010
-/* XFS_IOLOCK_NESTED 0x020 */
-#define XFS_EXTENT_TOKEN_RD 0x040
-#define XFS_SIZE_TOKEN_RD 0x080
+#define XFS_IOLOCK_EXCL (1<<0)
+#define XFS_IOLOCK_SHARED (1<<1)
+#define XFS_ILOCK_EXCL (1<<2)
+#define XFS_ILOCK_SHARED (1<<3)
+#define XFS_IUNLOCK_NONOTIFY (1<<4)
+/* #define XFS_IOLOCK_NESTED (1<<5) */
+#define XFS_EXTENT_TOKEN_RD (1<<6)
+#define XFS_SIZE_TOKEN_RD (1<<7)
#define XFS_EXTSIZE_RD (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD)
-#define XFS_WILLLEND 0x100 /* Always acquire tokens for lending */
+#define XFS_WILLLEND (1<<8) /* Always acquire tokens for lending */
#define XFS_EXTENT_TOKEN_WR (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND)
#define XFS_SIZE_TOKEN_WR (XFS_SIZE_TOKEN_RD | XFS_WILLLEND)
#define XFS_EXTSIZE_WR (XFS_EXTSIZE_RD | XFS_WILLLEND)
-/* XFS_SIZE_TOKEN_WANT 0x200 */
+/* TODO:XFS_SIZE_TOKEN_WANT (1<<9) */
-#define XFS_LOCK_MASK \
- (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL | \
- XFS_ILOCK_SHARED | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD | \
- XFS_WILLLEND)
+#define XFS_LOCK_MASK (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \
+ | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED \
+ | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD \
+ | XFS_WILLLEND)
+
+/*
+ * Flags for lockdep annotations.
+ *
+ * XFS_I[O]LOCK_PARENT - for operations that require locking two inodes
+ * (ie directory operations that require locking a directory inode and
+ * an entry inode). The first inode gets locked with this flag so it
+ * gets a lockdep subclass of 1 and the second lock will have a lockdep
+ * subclass of 0.
+ *
+ * XFS_I[O]LOCK_INUMORDER - for locking several inodes at the some time
+ * with xfs_lock_inodes(). This flag is used as the starting subclass
+ * and each subsequent lock acquired will increment the subclass by one.
+ * So the first lock acquired will have a lockdep subclass of 2, the
+ * second lock will have a lockdep subclass of 3, and so on.
+ */
+#define XFS_IOLOCK_SHIFT 16
+#define XFS_IOLOCK_PARENT (1 << XFS_IOLOCK_SHIFT)
+#define XFS_IOLOCK_INUMORDER (2 << XFS_IOLOCK_SHIFT)
+
+#define XFS_ILOCK_SHIFT 24
+#define XFS_ILOCK_PARENT (1 << XFS_ILOCK_SHIFT)
+#define XFS_ILOCK_INUMORDER (2 << XFS_ILOCK_SHIFT)
+
+#define XFS_IOLOCK_DEP_MASK 0x00ff0000
+#define XFS_ILOCK_DEP_MASK 0xff000000
+#define XFS_LOCK_DEP_MASK (XFS_IOLOCK_DEP_MASK | XFS_ILOCK_DEP_MASK)
+
+#define XFS_IOLOCK_DEP(flags) (((flags) & XFS_IOLOCK_DEP_MASK) >> XFS_IOLOCK_SHIFT)
+#define XFS_ILOCK_DEP(flags) (((flags) & XFS_ILOCK_DEP_MASK) >> XFS_ILOCK_SHIFT)
/*
* Flags for xfs_iflush()
@@ -481,7 +516,7 @@ uint xfs_ip2xflags(struct xfs_inode *);
uint xfs_dic2xflags(struct xfs_dinode_core *);
int xfs_ifree(struct xfs_trans *, xfs_inode_t *,
struct xfs_bmap_free *);
-void xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
+int xfs_itruncate_start(xfs_inode_t *, uint, xfs_fsize_t);
int xfs_itruncate_finish(struct xfs_trans **, xfs_inode_t *,
xfs_fsize_t, int, int);
int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
diff --git a/fs/xfs/xfs_iocore.c b/fs/xfs/xfs_iocore.c
index 06d710c9ce4..81548ec72ba 100644
--- a/fs/xfs/xfs_iocore.c
+++ b/fs/xfs/xfs_iocore.c
@@ -52,7 +52,7 @@ STATIC xfs_fsize_t
xfs_size_fn(
xfs_inode_t *ip)
{
- return (ip->i_d.di_size);
+ return XFS_ISIZE(ip);
}
STATIC int
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index cc6a7b5a991..3f2b9f2a7b9 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -458,7 +458,7 @@ xfs_iomap_write_direct(
extsz = ip->i_d.di_extsize;
}
- isize = ip->i_d.di_size;
+ isize = ip->i_size;
if (io->io_new_size > isize)
isize = io->io_new_size;
@@ -524,7 +524,7 @@ xfs_iomap_write_direct(
xfs_trans_ihold(tp, ip);
bmapi_flag = XFS_BMAPI_WRITE;
- if ((flags & BMAPI_DIRECT) && (offset < ip->i_d.di_size || extsz))
+ if ((flags & BMAPI_DIRECT) && (offset < ip->i_size || extsz))
bmapi_flag |= XFS_BMAPI_PREALLOC;
/*
@@ -543,7 +543,7 @@ xfs_iomap_write_direct(
error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error)
goto error0;
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto error_out;
@@ -676,7 +676,7 @@ xfs_iomap_write_delay(
offset_fsb = XFS_B_TO_FSBT(mp, offset);
retry:
- isize = ip->i_d.di_size;
+ isize = ip->i_size;
if (io->io_new_size > isize)
isize = io->io_new_size;
@@ -817,7 +817,7 @@ xfs_iomap_write_allocate(
* we dropped the ilock in the interim.
*/
- end_fsb = XFS_B_TO_FSB(mp, ip->i_d.di_size);
+ end_fsb = XFS_B_TO_FSB(mp, ip->i_size);
xfs_bmap_last_offset(NULL, ip, &last_block,
XFS_DATA_FORK);
last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
@@ -840,8 +840,7 @@ xfs_iomap_write_allocate(
if (error)
goto trans_cancel;
- error = xfs_trans_commit(tp,
- XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto error0;
@@ -948,7 +947,7 @@ xfs_iomap_write_unwritten(
if (error)
goto error_on_bmapi_transaction;
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return XFS_ERROR(error);
diff --git a/fs/xfs/xfs_iomap.h b/fs/xfs/xfs_iomap.h
index 3ce204a524b..df441ee936b 100644
--- a/fs/xfs/xfs_iomap.h
+++ b/fs/xfs/xfs_iomap.h
@@ -22,6 +22,7 @@
typedef enum { /* iomap_flags values */
+ IOMAP_READ = 0, /* mapping for a read */
IOMAP_EOF = 0x01, /* mapping contains EOF */
IOMAP_HOLE = 0x02, /* mapping covers a hole */
IOMAP_DELAY = 0x04, /* mapping covers delalloc region */
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 7775ddc0b3c..e725ddd3de5 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -809,7 +809,7 @@ xfs_inumbers(
xfs_buf_relse(agbp);
agbp = NULL;
/*
- * Move up the the last inode in the current
+ * Move up the last inode in the current
* chunk. The lookup_ge will always get
* us the first inode in the next chunk.
*/
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index ca74d3f5910..080fabf61c9 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -1509,7 +1509,6 @@ xlog_recover_insert_item_frontq(
STATIC int
xlog_recover_reorder_trans(
- xlog_t *log,
xlog_recover_t *trans)
{
xlog_recover_item_t *first_item, *itemq, *itemq_next;
@@ -1867,7 +1866,6 @@ xlog_recover_do_inode_buffer(
/*ARGSUSED*/
STATIC void
xlog_recover_do_reg_buffer(
- xfs_mount_t *mp,
xlog_recover_item_t *item,
xfs_buf_t *bp,
xfs_buf_log_format_t *buf_f)
@@ -2083,7 +2081,7 @@ xlog_recover_do_dquot_buffer(
if (log->l_quotaoffs_flag & type)
return;
- xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
+ xlog_recover_do_reg_buffer(item, bp, buf_f);
}
/*
@@ -2184,7 +2182,7 @@ xlog_recover_do_buffer_trans(
(XFS_BLI_UDQUOT_BUF|XFS_BLI_PDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
} else {
- xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
+ xlog_recover_do_reg_buffer(item, bp, buf_f);
}
if (error)
return XFS_ERROR(error);
@@ -2765,7 +2763,7 @@ xlog_recover_do_trans(
int error = 0;
xlog_recover_item_t *item, *first_item;
- if ((error = xlog_recover_reorder_trans(log, trans)))
+ if ((error = xlog_recover_reorder_trans(trans)))
return error;
first_item = item = trans->r_itemq;
do {
@@ -3016,7 +3014,7 @@ xlog_recover_process_efi(
}
efip->efi_flags |= XFS_EFI_RECOVERED;
- xfs_trans_commit(tp, 0, NULL);
+ xfs_trans_commit(tp, 0);
}
/*
@@ -3143,7 +3141,7 @@ xlog_recover_clear_agi_bucket(
xfs_trans_log_buf(tp, agibp, offset,
(offset + sizeof(xfs_agino_t) - 1));
- (void) xfs_trans_commit(tp, 0, NULL);
+ (void) xfs_trans_commit(tp, 0);
}
/*
@@ -3886,8 +3884,7 @@ xlog_recover(
* under the vfs layer, so we can get away with it unless
* the device itself is read-only, in which case we fail.
*/
- if ((error = xfs_dev_is_read_only(log->l_mp,
- "recovery required"))) {
+ if ((error = xfs_dev_is_read_only(log->l_mp, "recovery"))) {
return error;
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 3bed0cf0d8a..a96bde6df96 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -1653,7 +1653,7 @@ xfs_mount_log_sbunit(
return;
}
xfs_mod_sb(tp, fields);
- xfs_trans_commit(tp, 0, NULL);
+ xfs_trans_commit(tp, 0);
}
@@ -1734,11 +1734,13 @@ xfs_icsb_cpu_notify(
per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu);
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
/* Easy Case - initialize the area and locks, and
* then rebalance when online does everything else for us. */
memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
xfs_icsb_lock(mp);
xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
@@ -1746,6 +1748,7 @@ xfs_icsb_cpu_notify(
xfs_icsb_unlock(mp);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
/* Disable all the counters, then fold the dead cpu's
* count into the total on the global superblock and
* re-enable the counters. */
diff --git a/fs/xfs/xfs_qmops.c b/fs/xfs/xfs_qmops.c
index 320d63ff9ca..0d594ed7efe 100644
--- a/fs/xfs/xfs_qmops.c
+++ b/fs/xfs/xfs_qmops.c
@@ -78,7 +78,7 @@ xfs_mount_reset_sbqflags(xfs_mount_t *mp)
return error;
}
xfs_mod_sb(tp, XFS_SB_QFLAGS);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
return error;
}
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index 9dcb32aa4e2..6f14df976f7 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -154,10 +154,11 @@ typedef struct xfs_qoff_logformat {
#define XFS_ALL_QUOTA_CHKD (XFS_UQUOTA_CHKD | XFS_OQUOTA_CHKD)
#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_QUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ENFD)
#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT)
#define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT)
#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT)
+#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD)
+#define XFS_IS_OQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_OQUOTA_ENFD)
/*
* Incore only flags for quotaoff - these bits get cleared when quota(s)
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index 4c6573d784c..7679d7a7022 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -584,7 +584,7 @@ xfs_rename(
* trans_commit will unlock src_ip, target_ip & decrement
* the vnode references.
*/
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (target_ip != NULL) {
xfs_refcache_purge_ip(target_ip);
IRELE(target_ip);
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 6fff19dc3cf..b3a5f07bd07 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -150,7 +150,7 @@ xfs_growfs_rt_alloc(
error = xfs_bmap_finish(&tp, &flist, &committed);
if (error)
goto error_exit;
- xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
/*
* Now we need to clear the allocated blocks.
* Do this one block per transaction, to keep it simple.
@@ -187,7 +187,7 @@ xfs_growfs_rt_alloc(
/*
* Commit the transaction.
*/
- xfs_trans_commit(tp, 0, NULL);
+ xfs_trans_commit(tp, 0);
}
/*
* Go on to the next extent, if any.
@@ -2042,7 +2042,7 @@ xfs_growfs_rt(
/*
* Commit the transaction.
*/
- xfs_trans_commit(tp, 0, NULL);
+ xfs_trans_commit(tp, 0);
}
if (error)
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
index 1ea7c0ca6ae..905d1c008be 100644
--- a/fs/xfs/xfs_rw.c
+++ b/fs/xfs/xfs_rw.c
@@ -83,7 +83,7 @@ xfs_write_clear_setuid(
}
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
return 0;
}
@@ -164,7 +164,7 @@ xfs_write_sync_logforce(
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
}
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 301ff9445b6..cc2d60951e2 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -753,7 +753,6 @@ int
_xfs_trans_commit(
xfs_trans_t *tp,
uint flags,
- xfs_lsn_t *commit_lsn_p,
int *log_flushed)
{
xfs_log_iovec_t *log_vector;
@@ -812,8 +811,6 @@ shut_us_down:
xfs_trans_free_busy(tp);
xfs_trans_free(tp);
XFS_STATS_INC(xs_trans_empty);
- if (commit_lsn_p)
- *commit_lsn_p = commit_lsn;
return (shutdown);
}
ASSERT(tp->t_ticket != NULL);
@@ -864,9 +861,6 @@ shut_us_down:
kmem_free(log_vector, nvec * sizeof(xfs_log_iovec_t));
}
- if (commit_lsn_p)
- *commit_lsn_p = commit_lsn;
-
/*
* If we got a log write error. Unpin the logitems that we
* had pinned, clean up, free trans structure, and return error.
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index f1d7ab23672..7dfcc450366 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -988,10 +988,8 @@ void xfs_trans_log_efd_extent(xfs_trans_t *,
xfs_extlen_t);
int _xfs_trans_commit(xfs_trans_t *,
uint flags,
- xfs_lsn_t *,
int *);
-#define xfs_trans_commit(tp, flags, lsn) \
- _xfs_trans_commit(tp, flags, lsn, NULL)
+#define xfs_trans_commit(tp, flags) _xfs_trans_commit(tp, flags, NULL)
void xfs_trans_cancel(xfs_trans_t *, int);
void xfs_trans_ail_init(struct xfs_mount *);
xfs_lsn_t xfs_trans_push_ail(struct xfs_mount *, xfs_lsn_t);
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 9014d7e4448..20ffec308e1 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -222,7 +222,7 @@ xfs_dir_ialloc(
}
ntp = xfs_trans_dup(tp);
- code = xfs_trans_commit(tp, 0, NULL);
+ code = xfs_trans_commit(tp, 0);
tp = ntp;
if (committed != NULL) {
*committed = 1;
@@ -420,7 +420,11 @@ xfs_truncate_file(
* in a transaction.
*/
xfs_ilock(ip, XFS_IOLOCK_EXCL);
- xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0);
+ error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, (xfs_fsize_t)0);
+ if (error) {
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ return error;
+ }
tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
@@ -460,8 +464,7 @@ xfs_truncate_file(
XFS_TRANS_ABORT);
} else {
xfs_ichgtime(ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES,
- NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 29f72f61378..65c561201cb 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -696,7 +696,7 @@ xfs_unmount_flush(
bhv_vnode_t *rvp = XFS_ITOV(rip);
int error;
- xfs_ilock(rip, XFS_ILOCK_EXCL);
+ xfs_ilock(rip, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
xfs_iflock(rip);
/*
@@ -1147,7 +1147,7 @@ xfs_sync_inodes(
if (XFS_FORCED_SHUTDOWN(mp)) {
bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
} else {
- bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
+ error = bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
}
xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -1539,7 +1539,7 @@ xfs_syncsub(
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_log_force(mp, (xfs_lsn_t)0, log_flags);
}
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 52c41714ec5..de17aed578f 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -133,7 +133,7 @@ xfs_getattr(
if (!(flags & ATTR_LAZY))
xfs_ilock(ip, XFS_ILOCK_SHARED);
- vap->va_size = ip->i_d.di_size;
+ vap->va_size = XFS_ISIZE(ip);
if (vap->va_mask == XFS_AT_SIZE)
goto all_done;
@@ -496,7 +496,7 @@ xfs_setattr(
if (mask & XFS_AT_SIZE) {
/* Short circuit the truncate case for zero length files */
if ((vap->va_size == 0) &&
- (ip->i_d.di_size == 0) && (ip->i_d.di_nextents == 0)) {
+ (ip->i_size == 0) && (ip->i_d.di_nextents == 0)) {
xfs_iunlock(ip, XFS_ILOCK_EXCL);
lock_flags &= ~XFS_ILOCK_EXCL;
if (mask & XFS_AT_CTIME)
@@ -614,7 +614,7 @@ xfs_setattr(
*/
if (mask & XFS_AT_SIZE) {
code = 0;
- if ((vap->va_size > ip->i_d.di_size) &&
+ if ((vap->va_size > ip->i_size) &&
(flags & ATTR_NOSIZETOK) == 0) {
code = xfs_igrow_start(ip, vap->va_size, credp);
}
@@ -654,10 +654,10 @@ xfs_setattr(
* Truncate file. Must have write permission and not be a directory.
*/
if (mask & XFS_AT_SIZE) {
- if (vap->va_size > ip->i_d.di_size) {
+ if (vap->va_size > ip->i_size) {
xfs_igrow_finish(tp, ip, vap->va_size,
!(flags & ATTR_DMI));
- } else if ((vap->va_size <= ip->i_d.di_size) ||
+ } else if ((vap->va_size <= ip->i_size) ||
((vap->va_size == 0) && ip->i_d.di_nextents)) {
/*
* signal a sync transaction unless
@@ -873,7 +873,7 @@ xfs_setattr(
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(tp);
- code = xfs_trans_commit(tp, commit_flags, NULL);
+ code = xfs_trans_commit(tp, commit_flags);
}
/*
@@ -1176,7 +1176,7 @@ xfs_fsync(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
if (flag & FSYNC_WAIT)
xfs_trans_set_sync(tp);
- error = _xfs_trans_commit(tp, 0, NULL, &log_flushed);
+ error = _xfs_trans_commit(tp, 0, &log_flushed);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
@@ -1221,7 +1221,7 @@ xfs_inactive_free_eofblocks(
* Figure out if there are any blocks beyond the end
* of the file. If not, then there is nothing to do.
*/
- end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_d.di_size));
+ end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)ip->i_size));
last_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_MAXIOFFSET(mp));
map_len = last_fsb - end_fsb;
if (map_len <= 0)
@@ -1257,8 +1257,12 @@ xfs_inactive_free_eofblocks(
* do that within a transaction.
*/
xfs_ilock(ip, XFS_IOLOCK_EXCL);
- xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
- ip->i_d.di_size);
+ error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
+ ip->i_size);
+ if (error) {
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ return error;
+ }
error = xfs_trans_reserve(tp, 0,
XFS_ITRUNCATE_LOG_RES(mp),
@@ -1278,7 +1282,7 @@ xfs_inactive_free_eofblocks(
xfs_trans_ihold(tp, ip);
error = xfs_itruncate_finish(&tp, ip,
- ip->i_d.di_size,
+ ip->i_size,
XFS_DATA_FORK,
0);
/*
@@ -1291,8 +1295,7 @@ xfs_inactive_free_eofblocks(
XFS_TRANS_ABORT));
} else {
error = xfs_trans_commit(tp,
- XFS_TRANS_RELEASE_LOG_RES,
- NULL);
+ XFS_TRANS_RELEASE_LOG_RES);
}
xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
}
@@ -1406,7 +1409,7 @@ xfs_inactive_symlink_rmt(
* we need to unlock the inode since the new transaction doesn't
* have the inode attached.
*/
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
tp = ntp;
if (error) {
ASSERT(XFS_FORCED_SHUTDOWN(mp));
@@ -1503,7 +1506,7 @@ xfs_inactive_attrs(
tp = *tpp;
mp = ip->i_mount;
ASSERT(ip->i_d.di_forkoff != 0);
- xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
error = xfs_attr_inactive(ip);
@@ -1565,7 +1568,7 @@ xfs_release(
if (ip->i_d.di_nlink != 0) {
if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
- ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
+ ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||
ip->i_delayed_blks > 0)) &&
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
(!(ip->i_d.di_flags &
@@ -1626,8 +1629,8 @@ xfs_inactive(
* only one with a reference to the inode.
*/
truncate = ((ip->i_d.di_nlink == 0) &&
- ((ip->i_d.di_size != 0) || (ip->i_d.di_nextents > 0) ||
- (ip->i_delayed_blks > 0)) &&
+ ((ip->i_d.di_size != 0) || (ip->i_size != 0) ||
+ (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) &&
((ip->i_d.di_mode & S_IFMT) == S_IFREG));
mp = ip->i_mount;
@@ -1645,7 +1648,7 @@ xfs_inactive(
if (ip->i_d.di_nlink != 0) {
if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) &&
- ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0 ||
+ ((ip->i_size > 0) || (VN_CACHED(vp) > 0 ||
ip->i_delayed_blks > 0)) &&
(ip->i_df.if_flags & XFS_IFEXTENTS) &&
(!(ip->i_d.di_flags &
@@ -1675,7 +1678,11 @@ xfs_inactive(
*/
xfs_ilock(ip, XFS_IOLOCK_EXCL);
- xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
+ error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
+ if (error) {
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ return VN_INACTIVE_CACHE;
+ }
error = xfs_trans_reserve(tp, 0,
XFS_ITRUNCATE_LOG_RES(mp),
@@ -1790,7 +1797,7 @@ xfs_inactive(
* nothing we can do except to try to keep going.
*/
(void) xfs_bmap_finish(&tp, &free_list, &committed);
- (void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ (void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
}
/*
* Release the dquots held by inode, if any.
@@ -1940,7 +1947,7 @@ xfs_create(
goto error_return;
}
- xfs_ilock(dp, XFS_ILOCK_EXCL);
+ xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
XFS_BMAP_INIT(&free_list, &first_block);
@@ -2026,7 +2033,7 @@ xfs_create(
goto abort_rele;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error) {
IRELE(ip);
tp = NULL;
@@ -2121,7 +2128,6 @@ int xfs_rm_attempts;
STATIC int
xfs_lock_dir_and_entry(
xfs_inode_t *dp,
- bhv_vname_t *dentry,
xfs_inode_t *ip) /* inode of entry 'name' */
{
int attempts;
@@ -2135,7 +2141,7 @@ xfs_lock_dir_and_entry(
attempts = 0;
again:
- xfs_ilock(dp, XFS_ILOCK_EXCL);
+ xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
e_inum = ip->i_ino;
@@ -2204,6 +2210,21 @@ int xfs_lock_delays;
#endif
/*
+ * Bump the subclass so xfs_lock_inodes() acquires each lock with
+ * a different value
+ */
+static inline int
+xfs_lock_inumorder(int lock_mode, int subclass)
+{
+ if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+ lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+ if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
+ lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT;
+
+ return lock_mode;
+}
+
+/*
* The following routine will lock n inodes in exclusive mode.
* We assume the caller calls us with the inodes in i_ino order.
*
@@ -2270,7 +2291,7 @@ again:
* that is in the AIL.
*/
ASSERT(i != 0);
- if (!xfs_ilock_nowait(ips[i], lock_mode)) {
+ if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
attempts++;
/*
@@ -2305,7 +2326,7 @@ again:
goto again;
}
} else {
- xfs_ilock(ips[i], lock_mode);
+ xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
}
}
@@ -2440,7 +2461,7 @@ xfs_remove(
return error;
}
- error = xfs_lock_dir_and_entry(dp, dentry, ip);
+ error = xfs_lock_dir_and_entry(dp, ip);
if (error) {
REMOVE_DEBUG_TRACE(__LINE__);
xfs_trans_cancel(tp, cancel_flags);
@@ -2511,7 +2532,7 @@ xfs_remove(
goto error_rele;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error) {
IRELE(ip);
goto std_return;
@@ -2719,7 +2740,7 @@ xfs_link(
goto abort_return;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
goto std_return;
@@ -2839,7 +2860,7 @@ xfs_mkdir(
goto error_return;
}
- xfs_ilock(dp, XFS_ILOCK_EXCL);
+ xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
/*
* Check for directory link count overflow.
@@ -2936,7 +2957,7 @@ xfs_mkdir(
goto error2;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
XFS_QM_DQRELE(mp, udqp);
XFS_QM_DQRELE(mp, gdqp);
if (error) {
@@ -3096,7 +3117,7 @@ xfs_rmdir(
* that the directory entry for the child directory inode has
* not changed while we were obtaining a log reservation.
*/
- error = xfs_lock_dir_and_entry(dp, dentry, cdp);
+ error = xfs_lock_dir_and_entry(dp, cdp);
if (error) {
xfs_trans_cancel(tp, cancel_flags);
IRELE(cdp);
@@ -3190,7 +3211,7 @@ xfs_rmdir(
goto std_return;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error) {
IRELE(cdp);
goto std_return;
@@ -3393,7 +3414,7 @@ xfs_symlink(
goto error_return;
}
- xfs_ilock(dp, XFS_ILOCK_EXCL);
+ xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
/*
* Check whether the directory allows new symlinks or not.
@@ -3535,7 +3556,7 @@ xfs_symlink(
if (error) {
goto error2;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
XFS_QM_DQRELE(mp, udqp);
XFS_QM_DQRELE(mp, gdqp);
@@ -3790,7 +3811,7 @@ xfs_set_dmattrs (
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
IHOLD(ip);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
return error;
}
@@ -4049,14 +4070,14 @@ xfs_alloc_file_space(
allocatesize_fsb = XFS_B_TO_FSB(mp, count);
/* Generate a DMAPI event if needed. */
- if (alloc_type != 0 && offset < ip->i_d.di_size &&
+ if (alloc_type != 0 && offset < ip->i_size &&
(attr_flags&ATTR_DMI) == 0 &&
DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
xfs_off_t end_dmi_offset;
end_dmi_offset = offset+len;
- if (end_dmi_offset > ip->i_d.di_size)
- end_dmi_offset = ip->i_d.di_size;
+ if (end_dmi_offset > ip->i_size)
+ end_dmi_offset = ip->i_size;
error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, XFS_ITOV(ip),
offset, end_dmi_offset - offset,
0, NULL);
@@ -4148,7 +4169,7 @@ retry:
goto error0;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error) {
break;
@@ -4283,7 +4304,6 @@ xfs_free_file_space(
int error;
xfs_fsblock_t firstfsb;
xfs_bmap_free_t free_list;
- xfs_off_t ilen;
xfs_bmbt_irec_t imap;
xfs_off_t ioffset;
xfs_extlen_t mod=0;
@@ -4312,11 +4332,11 @@ xfs_free_file_space(
end_dmi_offset = offset + len;
endoffset_fsb = XFS_B_TO_FSBT(mp, end_dmi_offset);
- if (offset < ip->i_d.di_size &&
+ if (offset < ip->i_size &&
(attr_flags & ATTR_DMI) == 0 &&
DM_EVENT_ENABLED(XFS_MTOVFS(mp), ip, DM_EVENT_WRITE)) {
- if (end_dmi_offset > ip->i_d.di_size)
- end_dmi_offset = ip->i_d.di_size;
+ if (end_dmi_offset > ip->i_size)
+ end_dmi_offset = ip->i_size;
error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, vp,
offset, end_dmi_offset - offset,
AT_DELAY_FLAG(attr_flags), NULL);
@@ -4332,16 +4352,15 @@ xfs_free_file_space(
}
rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP);
- ilen = len + (offset & (rounding - 1));
ioffset = offset & ~(rounding - 1);
- if (ilen & (rounding - 1))
- ilen = (ilen + rounding) & ~(rounding - 1);
if (VN_CACHED(vp) != 0) {
xfs_inval_cached_trace(&ip->i_iocore, ioffset, -1,
ctooff(offtoct(ioffset)), -1);
- bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)),
+ error = bhv_vop_flushinval_pages(vp, ctooff(offtoct(ioffset)),
-1, FI_REMAPF_LOCKED);
+ if (error)
+ goto out_unlock_iolock;
}
/*
@@ -4455,7 +4474,7 @@ xfs_free_file_space(
goto error0;
}
- error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+ error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
}
@@ -4533,7 +4552,7 @@ xfs_change_file_space(
bf->l_start += offset;
break;
case 2: /*SEEK_END*/
- bf->l_start += ip->i_d.di_size;
+ bf->l_start += ip->i_size;
break;
default:
return XFS_ERROR(EINVAL);
@@ -4550,7 +4569,7 @@ xfs_change_file_space(
bf->l_whence = 0;
startoffset = bf->l_start;
- fsize = ip->i_d.di_size;
+ fsize = ip->i_size;
/*
* XFS_IOC_RESVSP and XFS_IOC_UNRESVSP will reserve or unreserve
@@ -4649,7 +4668,7 @@ xfs_change_file_space(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
xfs_trans_set_sync(tp);
- error = xfs_trans_commit(tp, 0, NULL);
+ error = xfs_trans_commit(tp, 0);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 0d9f984a60a..9cfd5b1a48e 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -303,6 +303,9 @@ struct acpi_device {
#define to_acpi_device(d) container_of(d, struct acpi_device, dev)
#define to_acpi_driver(d) container_of(d, struct acpi_driver, drv)
+/* acpi_device.dev.bus == &acpi_bus_type */
+extern struct bus_type acpi_bus_type;
+
/*
* Events
* ------
@@ -316,7 +319,7 @@ struct acpi_bus_event {
u32 data;
};
-extern struct subsystem acpi_subsys;
+extern struct kset acpi_subsys;
/*
* External Functions
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 09469e7db6a..955adfb8d64 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -276,6 +276,7 @@ enum acpi_prefered_pm_profiles {
#define BAF_LEGACY_DEVICES 0x0001
#define BAF_8042_KEYBOARD_CONTROLLER 0x0002
+#define BAF_MSI_NOT_SUPPORTED 0x0008
#define FADT2_REVISION_ID 3
#define FADT2_MINUS_REVISION_ID 2
diff --git a/include/asm-alpha/atomic.h b/include/asm-alpha/atomic.h
index fc77f741308..f5cb7b878af 100644
--- a/include/asm-alpha/atomic.h
+++ b/include/asm-alpha/atomic.h
@@ -2,6 +2,7 @@
#define _ALPHA_ATOMIC_H
#include <asm/barrier.h>
+#include <asm/system.h>
/*
* Atomic operations that C can't guarantee us. Useful for
@@ -175,19 +176,64 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
return result;
}
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+/**
+ * atomic_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long c, old;
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic64_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
diff --git a/include/asm-alpha/kdebug.h b/include/asm-alpha/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-alpha/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-alpha/local.h b/include/asm-alpha/local.h
index 90a510fa358..6ad3ea69642 100644
--- a/include/asm-alpha/local.h
+++ b/include/asm-alpha/local.h
@@ -4,37 +4,115 @@
#include <linux/percpu.h>
#include <asm/atomic.h>
-typedef atomic64_t local_t;
+typedef struct
+{
+ atomic_long_t a;
+} local_t;
-#define LOCAL_INIT(i) ATOMIC64_INIT(i)
-#define local_read(v) atomic64_read(v)
-#define local_set(v,i) atomic64_set(v,i)
+#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
+#define local_read(l) atomic_long_read(&(l)->a)
+#define local_set(l,i) atomic_long_set(&(l)->a, (i))
+#define local_inc(l) atomic_long_inc(&(l)->a)
+#define local_dec(l) atomic_long_dec(&(l)->a)
+#define local_add(i,l) atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l) atomic_long_sub((i),(&(l)->a))
-#define local_inc(v) atomic64_inc(v)
-#define local_dec(v) atomic64_dec(v)
-#define local_add(i, v) atomic64_add(i, v)
-#define local_sub(i, v) atomic64_sub(i, v)
+static __inline__ long local_add_return(long i, local_t * l)
+{
+ long temp, result;
+ __asm__ __volatile__(
+ "1: ldq_l %0,%1\n"
+ " addq %0,%3,%2\n"
+ " addq %0,%3,%0\n"
+ " stq_c %0,%1\n"
+ " beq %0,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
+ :"Ir" (i), "m" (l->a.counter) : "memory");
+ return result;
+}
-#define __local_inc(v) ((v)->counter++)
-#define __local_dec(v) ((v)->counter++)
-#define __local_add(i,v) ((v)->counter+=(i))
-#define __local_sub(i,v) ((v)->counter-=(i))
+static __inline__ long local_sub_return(long i, local_t * l)
+{
+ long temp, result;
+ __asm__ __volatile__(
+ "1: ldq_l %0,%1\n"
+ " subq %0,%3,%2\n"
+ " subq %0,%3,%0\n"
+ " stq_c %0,%1\n"
+ " beq %0,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ :"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
+ :"Ir" (i), "m" (l->a.counter) : "memory");
+ return result;
+}
+
+#define local_cmpxchg(l, o, n) \
+ (cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u) \
+({ \
+ long c, old; \
+ c = local_read(l); \
+ for (;;) { \
+ if (unlikely(c == (u))) \
+ break; \
+ old = local_cmpxchg((l), c, c + (a)); \
+ if (likely(old == c)) \
+ break; \
+ c = old; \
+ } \
+ c != (u); \
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
+
+#define local_dec_return(l) local_sub_return(1,(l))
+
+#define local_inc_return(l) local_add_return(1,(l))
+
+#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
+
+#define local_inc_and_test(l) (local_add_return(1, (l)) == 0)
+
+#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
+
+/* Verify if faster than atomic ops */
+#define __local_inc(l) ((l)->a.counter++)
+#define __local_dec(l) ((l)->a.counter++)
+#define __local_add(i,l) ((l)->a.counter+=(i))
+#define __local_sub(i,l) ((l)->a.counter-=(i))
/* Use these for per-cpu local_t variables: on some archs they are
* much more efficient than these naive implementations. Note they take
* a variable, not an address.
*/
-#define cpu_local_read(v) local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
+#define cpu_local_read(l) local_read(&__get_cpu_var(l))
+#define cpu_local_set(l, i) local_set(&__get_cpu_var(l), (i))
+
+#define cpu_local_inc(l) local_inc(&__get_cpu_var(l))
+#define cpu_local_dec(l) local_dec(&__get_cpu_var(l))
+#define cpu_local_add(i, l) local_add((i), &__get_cpu_var(l))
+#define cpu_local_sub(i, l) local_sub((i), &__get_cpu_var(l))
+
+#define __cpu_local_inc(l) __local_inc(&__get_cpu_var(l))
+#define __cpu_local_dec(l) __local_dec(&__get_cpu_var(l))
+#define __cpu_local_add(i, l) __local_add((i), &__get_cpu_var(l))
+#define __cpu_local_sub(i, l) __local_sub((i), &__get_cpu_var(l))
#endif /* _ALPHA_LOCAL_H */
diff --git a/include/asm-alpha/mmu_context.h b/include/asm-alpha/mmu_context.h
index fe249e9d336..0bd7bd2ccb9 100644
--- a/include/asm-alpha/mmu_context.h
+++ b/include/asm-alpha/mmu_context.h
@@ -10,6 +10,7 @@
#include <asm/system.h>
#include <asm/machvec.h>
#include <asm/compiler.h>
+#include <asm-generic/mm_hooks.h>
/*
* Force a context reload. This is needed when we change the page
diff --git a/include/asm-alpha/percpu.h b/include/asm-alpha/percpu.h
index 651ebb141b2..48348fe34c1 100644
--- a/include/asm-alpha/percpu.h
+++ b/include/asm-alpha/percpu.h
@@ -1,20 +1,6 @@
#ifndef __ALPHA_PERCPU_H
#define __ALPHA_PERCPU_H
-/*
- * Increase the per cpu area for Alpha so that
- * modules using percpu area can load.
- */
-#ifdef CONFIG_MODULES
-# define PERCPU_MODULE_RESERVE 8192
-#else
-# define PERCPU_MODULE_RESERVE 0
-#endif
-
-#define PERCPU_ENOUGH_ROOM \
- (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
- PERCPU_MODULE_RESERVE)
-
#include <asm-generic/percpu.h>
#endif /* __ALPHA_PERCPU_H */
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 49ac9bee7ce..616d20662ff 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -345,10 +345,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
#define io_remap_pfn_range(vma, start, pfn, size, prot) \
remap_pfn_range(vma, start, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#define pte_ERROR(e) \
printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
#define pmd_ERROR(e) \
diff --git a/include/asm-alpha/scatterlist.h b/include/asm-alpha/scatterlist.h
index 6afb8bd3aaf..917365405e8 100644
--- a/include/asm-alpha/scatterlist.h
+++ b/include/asm-alpha/scatterlist.h
@@ -2,6 +2,7 @@
#define _ALPHA_SCATTERLIST_H
#include <asm/page.h>
+#include <asm/types.h>
struct scatterlist {
struct page *page;
diff --git a/include/asm-alpha/smp.h b/include/asm-alpha/smp.h
index a1a1eca6be4..286e1d844f6 100644
--- a/include/asm-alpha/smp.h
+++ b/include/asm-alpha/smp.h
@@ -51,6 +51,7 @@ int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, in
#else /* CONFIG_SMP */
+#define hard_smp_processor_id() 0
#define smp_call_function_on_cpu(func,info,retry,wait,cpu) ({ 0; })
#endif /* CONFIG_SMP */
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index 03e9c0e5ed7..cf1021a97b2 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -443,8 +443,110 @@ extern void __xchg_called_with_bad_pointer(void);
(__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
})
-#define tas(ptr) (xchg((ptr),1))
+static inline unsigned long
+__xchg_u8_local(volatile char *m, unsigned long val)
+{
+ unsigned long ret, tmp, addr64;
+
+ __asm__ __volatile__(
+ " andnot %4,7,%3\n"
+ " insbl %1,%4,%1\n"
+ "1: ldq_l %2,0(%3)\n"
+ " extbl %2,%4,%0\n"
+ " mskbl %2,%4,%2\n"
+ " or %1,%2,%2\n"
+ " stq_c %2,0(%3)\n"
+ " beq %2,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+ : "r" ((long)m), "1" (val) : "memory");
+ return ret;
+}
+
+static inline unsigned long
+__xchg_u16_local(volatile short *m, unsigned long val)
+{
+ unsigned long ret, tmp, addr64;
+
+ __asm__ __volatile__(
+ " andnot %4,7,%3\n"
+ " inswl %1,%4,%1\n"
+ "1: ldq_l %2,0(%3)\n"
+ " extwl %2,%4,%0\n"
+ " mskwl %2,%4,%2\n"
+ " or %1,%2,%2\n"
+ " stq_c %2,0(%3)\n"
+ " beq %2,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
+ : "r" ((long)m), "1" (val) : "memory");
+
+ return ret;
+}
+
+static inline unsigned long
+__xchg_u32_local(volatile int *m, unsigned long val)
+{
+ unsigned long dummy;
+
+ __asm__ __volatile__(
+ "1: ldl_l %0,%4\n"
+ " bis $31,%3,%1\n"
+ " stl_c %1,%2\n"
+ " beq %1,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ : "=&r" (val), "=&r" (dummy), "=m" (*m)
+ : "rI" (val), "m" (*m) : "memory");
+
+ return val;
+}
+
+static inline unsigned long
+__xchg_u64_local(volatile long *m, unsigned long val)
+{
+ unsigned long dummy;
+
+ __asm__ __volatile__(
+ "1: ldq_l %0,%4\n"
+ " bis $31,%3,%1\n"
+ " stq_c %1,%2\n"
+ " beq %1,2f\n"
+ ".subsection 2\n"
+ "2: br 1b\n"
+ ".previous"
+ : "=&r" (val), "=&r" (dummy), "=m" (*m)
+ : "rI" (val), "m" (*m) : "memory");
+
+ return val;
+}
+
+#define __xchg_local(ptr, x, size) \
+({ \
+ unsigned long __xchg__res; \
+ volatile void *__xchg__ptr = (ptr); \
+ switch (size) { \
+ case 1: __xchg__res = __xchg_u8_local(__xchg__ptr, x); break; \
+ case 2: __xchg__res = __xchg_u16_local(__xchg__ptr, x); break; \
+ case 4: __xchg__res = __xchg_u32_local(__xchg__ptr, x); break; \
+ case 8: __xchg__res = __xchg_u64_local(__xchg__ptr, x); break; \
+ default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
+ } \
+ __xchg__res; \
+})
+
+#define xchg_local(ptr,x) \
+ ({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_, \
+ sizeof(*(ptr))); \
+ })
/*
* Atomic compare and exchange. Compare OLD with MEM, if identical,
@@ -596,6 +698,128 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
(unsigned long)_n_, sizeof(*(ptr))); \
})
+static inline unsigned long
+__cmpxchg_u8_local(volatile char *m, long old, long new)
+{
+ unsigned long prev, tmp, cmp, addr64;
+
+ __asm__ __volatile__(
+ " andnot %5,7,%4\n"
+ " insbl %1,%5,%1\n"
+ "1: ldq_l %2,0(%4)\n"
+ " extbl %2,%5,%0\n"
+ " cmpeq %0,%6,%3\n"
+ " beq %3,2f\n"
+ " mskbl %2,%5,%2\n"
+ " or %1,%2,%2\n"
+ " stq_c %2,0(%4)\n"
+ " beq %2,3f\n"
+ "2:\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+ : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+ return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u16_local(volatile short *m, long old, long new)
+{
+ unsigned long prev, tmp, cmp, addr64;
+
+ __asm__ __volatile__(
+ " andnot %5,7,%4\n"
+ " inswl %1,%5,%1\n"
+ "1: ldq_l %2,0(%4)\n"
+ " extwl %2,%5,%0\n"
+ " cmpeq %0,%6,%3\n"
+ " beq %3,2f\n"
+ " mskwl %2,%5,%2\n"
+ " or %1,%2,%2\n"
+ " stq_c %2,0(%4)\n"
+ " beq %2,3f\n"
+ "2:\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
+ : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+
+ return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u32_local(volatile int *m, int old, int new)
+{
+ unsigned long prev, cmp;
+
+ __asm__ __volatile__(
+ "1: ldl_l %0,%5\n"
+ " cmpeq %0,%3,%1\n"
+ " beq %1,2f\n"
+ " mov %4,%1\n"
+ " stl_c %1,%2\n"
+ " beq %1,3f\n"
+ "2:\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+ : "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+ return prev;
+}
+
+static inline unsigned long
+__cmpxchg_u64_local(volatile long *m, unsigned long old, unsigned long new)
+{
+ unsigned long prev, cmp;
+
+ __asm__ __volatile__(
+ "1: ldq_l %0,%5\n"
+ " cmpeq %0,%3,%1\n"
+ " beq %1,2f\n"
+ " mov %4,%1\n"
+ " stq_c %1,%2\n"
+ " beq %1,3f\n"
+ "2:\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+ : "r"((long) old), "r"(new), "m"(*m) : "memory");
+
+ return prev;
+}
+
+static __always_inline unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+ int size)
+{
+ switch (size) {
+ case 1:
+ return __cmpxchg_u8_local(ptr, old, new);
+ case 2:
+ return __cmpxchg_u16_local(ptr, old, new);
+ case 4:
+ return __cmpxchg_u32_local(ptr, old, new);
+ case 8:
+ return __cmpxchg_u64_local(ptr, old, new);
+ }
+ __cmpxchg_called_with_bad_pointer();
+ return old;
+}
+
+#define cmpxchg_local(ptr,o,n) \
+ ({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof(*(ptr))); \
+ })
+
#endif /* __ASSEMBLY__ */
#define arch_align_stack(x) (x)
diff --git a/include/asm-alpha/thread_info.h b/include/asm-alpha/thread_info.h
index 69ffd93f8e2..f4defc2bd3f 100644
--- a/include/asm-alpha/thread_info.h
+++ b/include/asm-alpha/thread_info.h
@@ -92,5 +92,27 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
| _TIF_SYSCALL_TRACE)
+#define ALPHA_UAC_SHIFT 6
+#define ALPHA_UAC_MASK (1 << TIF_UAC_NOPRINT | 1 << TIF_UAC_NOFIX | \
+ 1 << TIF_UAC_SIGBUS)
+
+#define SET_UNALIGN_CTL(task,value) ({ \
+ task_thread_info(task)->flags = ((task_thread_info(task)->flags & \
+ ~ALPHA_UAC_MASK) \
+ | (((value) << ALPHA_UAC_SHIFT) & (1<<TIF_UAC_NOPRINT))\
+ | (((value) << (ALPHA_UAC_SHIFT + 1)) & (1<<TIF_UAC_SIGBUS)) \
+ | (((value) << (ALPHA_UAC_SHIFT - 1)) & (1<<TIF_UAC_NOFIX)));\
+ 0; })
+
+#define GET_UNALIGN_CTL(task,value) ({ \
+ put_user((task_thread_info(task)->flags & (1 << TIF_UAC_NOPRINT))\
+ >> ALPHA_UAC_SHIFT \
+ | (task_thread_info(task)->flags & (1 << TIF_UAC_SIGBUS))\
+ >> (ALPHA_UAC_SHIFT + 1) \
+ | (task_thread_info(task)->flags & (1 << TIF_UAC_NOFIX))\
+ >> (ALPHA_UAC_SHIFT - 1), \
+ (int __user *)(value)); \
+ })
+
#endif /* __KERNEL__ */
#endif /* _ALPHA_THREAD_INFO_H */
diff --git a/include/asm-arm/arch-at91/at91_adc.h b/include/asm-arm/arch-at91/at91_adc.h
new file mode 100644
index 00000000000..1ed66eaaf83
--- /dev/null
+++ b/include/asm-arm/arch-at91/at91_adc.h
@@ -0,0 +1,61 @@
+/*
+ * include/asm-arm/arch-at91/at91_adc.h
+ *
+ * Copyright (C) SAN People
+ *
+ * Analog-to-Digital Converter (ADC) registers.
+ * Based on AT91SAM9260 datasheet revision D.
+ *
+ * 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.
+ */
+
+#ifndef AT91_ADC_H
+#define AT91_ADC_H
+
+#define AT91_ADC_CR 0x00 /* Control Register */
+#define AT91_ADC_SWRST (1 << 0) /* Software Reset */
+#define AT91_ADC_START (1 << 1) /* Start Conversion */
+
+#define AT91_ADC_MR 0x04 /* Mode Register */
+#define AT91_ADC_TRGEN (1 << 0) /* Trigger Enable */
+#define AT91_ADC_TRGSEL (7 << 1) /* Trigger Selection */
+#define AT91_ADC_TRGSEL_TC0 (0 << 1)
+#define AT91_ADC_TRGSEL_TC1 (1 << 1)
+#define AT91_ADC_TRGSEL_TC2 (2 << 1)
+#define AT91_ADC_TRGSEL_EXTERNAL (6 << 1)
+#define AT91_ADC_LOWRES (1 << 4) /* Low Resolution */
+#define AT91_ADC_SLEEP (1 << 5) /* Sleep Mode */
+#define AT91_ADC_PRESCAL (0x3f << 8) /* Prescalar Rate Selection */
+#define AT91_ADC_PRESCAL_(x) ((x) << 8)
+#define AT91_ADC_STARTUP (0x1f << 16) /* Startup Up Time */
+#define AT91_ADC_STARTUP_(x) ((x) << 16)
+#define AT91_ADC_SHTIM (0xf << 24) /* Sample & Hold Time */
+#define AT91_ADC_SHTIM_(x) ((x) << 24)
+
+#define AT91_ADC_CHER 0x10 /* Channel Enable Register */
+#define AT91_ADC_CHDR 0x14 /* Channel Disable Register */
+#define AT91_ADC_CHSR 0x18 /* Channel Status Register */
+#define AT91_ADC_CH(n) (1 << (n)) /* Channel Number */
+
+#define AT91_ADC_SR 0x1C /* Status Register */
+#define AT91_ADC_EOC(n) (1 << (n)) /* End of Conversion on Channel N */
+#define AT91_ADC_OVRE(n) (1 << ((n) + 8))/* Overrun Error on Channel N */
+#define AT91_ADC_DRDY (1 << 16) /* Data Ready */
+#define AT91_ADC_GOVRE (1 << 17) /* General Overrun Error */
+#define AT91_ADC_ENDRX (1 << 18) /* End of RX Buffer */
+#define AT91_ADC_RXFUFF (1 << 19) /* RX Buffer Full */
+
+#define AT91_ADC_LCDR 0x20 /* Last Converted Data Register */
+#define AT91_ADC_LDATA (0x3ff)
+
+#define AT91_ADC_IER 0x24 /* Interrupt Enable Register */
+#define AT91_ADC_IDR 0x28 /* Interrupt Disable Register */
+#define AT91_ADC_IMR 0x2C /* Interrupt Mask Register */
+
+#define AT91_ADC_CHR(n) (0x30 + ((n) * 4) /* Channel Data Register N */
+#define AT91_ADC_DATA (0x3ff)
+
+#endif
diff --git a/include/asm-arm/arch-at91/at91rm9200.h b/include/asm-arm/arch-at91/at91rm9200.h
index a12ac8ab2ad..802891a9cd8 100644
--- a/include/asm-arm/arch-at91/at91rm9200.h
+++ b/include/asm-arm/arch-at91/at91rm9200.h
@@ -107,185 +107,4 @@
#define AT91RM9200_UHP_BASE 0x00300000 /* USB Host controller */
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-#define AT91_PA0_MISO (1 << 0) /* A: SPI Master-In Slave-Out */
-#define AT91_PA0_PCK3 (1 << 0) /* B: PMC Programmable Clock Output 3 */
-#define AT91_PA1_MOSI (1 << 1) /* A: SPI Master-Out Slave-In */
-#define AT91_PA1_PCK0 (1 << 1) /* B: PMC Programmable Clock Output 0 */
-#define AT91_PA2_SPCK (1 << 2) /* A: SPI Serial Clock */
-#define AT91_PA2_IRQ4 (1 << 2) /* B: External Interrupt 4 */
-#define AT91_PA3_NPCS0 (1 << 3) /* A: SPI Peripheral Chip Select 0 */
-#define AT91_PA3_IRQ5 (1 << 3) /* B: External Interrupt 5 */
-#define AT91_PA4_NPCS1 (1 << 4) /* A: SPI Peripheral Chip Select 1 */
-#define AT91_PA4_PCK1 (1 << 4) /* B: PMC Programmable Clock Output 1 */
-#define AT91_PA5_NPCS2 (1 << 5) /* A: SPI Peripheral Chip Select 2 */
-#define AT91_PA5_TXD3 (1 << 5) /* B: USART Transmit Data 3 */
-#define AT91_PA6_NPCS3 (1 << 6) /* A: SPI Peripheral Chip Select 3 */
-#define AT91_PA6_RXD3 (1 << 6) /* B: USART Receive Data 3 */
-#define AT91_PA7_ETXCK_EREFCK (1 << 7) /* A: Ethernet Reference Clock / Transmit Clock */
-#define AT91_PA7_PCK2 (1 << 7) /* B: PMC Programmable Clock Output 2 */
-#define AT91_PA8_ETXEN (1 << 8) /* A: Ethernet Transmit Enable */
-#define AT91_PA8_MCCDB (1 << 8) /* B: MMC Multimedia Card B Command */
-#define AT91_PA9_ETX0 (1 << 9) /* A: Ethernet Transmit Data 0 */
-#define AT91_PA9_MCDB0 (1 << 9) /* B: MMC Multimedia Card B Data 0 */
-#define AT91_PA10_ETX1 (1 << 10) /* A: Ethernet Transmit Data 1 */
-#define AT91_PA10_MCDB1 (1 << 10) /* B: MMC Multimedia Card B Data 1 */
-#define AT91_PA11_ECRS_ECRSDV (1 << 11) /* A: Ethernet Carrier Sense / Data Valid */
-#define AT91_PA11_MCDB2 (1 << 11) /* B: MMC Multimedia Card B Data 2 */
-#define AT91_PA12_ERX0 (1 << 12) /* A: Ethernet Receive Data 0 */
-#define AT91_PA12_MCDB3 (1 << 12) /* B: MMC Multimedia Card B Data 3 */
-#define AT91_PA13_ERX1 (1 << 13) /* A: Ethernet Receive Data 1 */
-#define AT91_PA13_TCLK0 (1 << 13) /* B: TC External Clock Input 0 */
-#define AT91_PA14_ERXER (1 << 14) /* A: Ethernet Receive Error */
-#define AT91_PA14_TCLK1 (1 << 14) /* B: TC External Clock Input 1 */
-#define AT91_PA15_EMDC (1 << 15) /* A: Ethernet Management Data Clock */
-#define AT91_PA15_TCLK2 (1 << 15) /* B: TC External Clock Input 2 */
-#define AT91_PA16_EMDIO (1 << 16) /* A: Ethernet Management Data I/O */
-#define AT91_PA16_IRQ6 (1 << 16) /* B: External Interrupt 6 */
-#define AT91_PA17_TXD0 (1 << 17) /* A: USART Transmit Data 0 */
-#define AT91_PA17_TIOA0 (1 << 17) /* B: TC I/O Line A 0 */
-#define AT91_PA18_RXD0 (1 << 18) /* A: USART Receive Data 0 */
-#define AT91_PA18_TIOB0 (1 << 18) /* B: TC I/O Line B 0 */
-#define AT91_PA19_SCK0 (1 << 19) /* A: USART Serial Clock 0 */
-#define AT91_PA19_TIOA1 (1 << 19) /* B: TC I/O Line A 1 */
-#define AT91_PA20_CTS0 (1 << 20) /* A: USART Clear To Send 0 */
-#define AT91_PA20_TIOB1 (1 << 20) /* B: TC I/O Line B 1 */
-#define AT91_PA21_RTS0 (1 << 21) /* A: USART Ready To Send 0 */
-#define AT91_PA21_TIOA2 (1 << 21) /* B: TC I/O Line A 2 */
-#define AT91_PA22_RXD2 (1 << 22) /* A: USART Receive Data 2 */
-#define AT91_PA22_TIOB2 (1 << 22) /* B: TC I/O Line B 2 */
-#define AT91_PA23_TXD2 (1 << 23) /* A: USART Transmit Data 2 */
-#define AT91_PA23_IRQ3 (1 << 23) /* B: External Interrupt 3 */
-#define AT91_PA24_SCK2 (1 << 24) /* A: USART Serial Clock 2 */
-#define AT91_PA24_PCK1 (1 << 24) /* B: PMC Programmable Clock Output 1 */
-#define AT91_PA25_TWD (1 << 25) /* A: TWI Two-wire Serial Data */
-#define AT91_PA25_IRQ2 (1 << 25) /* B: External Interrupt 2 */
-#define AT91_PA26_TWCK (1 << 26) /* A: TWI Two-wire Serial Clock */
-#define AT91_PA26_IRQ1 (1 << 26) /* B: External Interrupt 1 */
-#define AT91_PA27_MCCK (1 << 27) /* A: MMC Multimedia Card Clock */
-#define AT91_PA27_TCLK3 (1 << 27) /* B: TC External Clock Input 3 */
-#define AT91_PA28_MCCDA (1 << 28) /* A: MMC Multimedia Card A Command */
-#define AT91_PA28_TCLK4 (1 << 28) /* B: TC External Clock Input 4 */
-#define AT91_PA29_MCDA0 (1 << 29) /* A: MMC Multimedia Card A Data 0 */
-#define AT91_PA29_TCLK5 (1 << 29) /* B: TC External Clock Input 5 */
-#define AT91_PA30_DRXD (1 << 30) /* A: DBGU Receive Data */
-#define AT91_PA30_CTS2 (1 << 30) /* B: USART Clear To Send 2 */
-#define AT91_PA31_DTXD (1 << 31) /* A: DBGU Transmit Data */
-#define AT91_PA31_RTS2 (1 << 31) /* B: USART Ready To Send 2 */
-
-#define AT91_PB0_TF0 (1 << 0) /* A: SSC Transmit Frame Sync 0 */
-#define AT91_PB0_RTS3 (1 << 0) /* B: USART Ready To Send 3 */
-#define AT91_PB1_TK0 (1 << 1) /* A: SSC Transmit Clock 0 */
-#define AT91_PB1_CTS3 (1 << 1) /* B: USART Clear To Send 3 */
-#define AT91_PB2_TD0 (1 << 2) /* A: SSC Transmit Data 0 */
-#define AT91_PB2_SCK3 (1 << 2) /* B: USART Serial Clock 3 */
-#define AT91_PB3_RD0 (1 << 3) /* A: SSC Receive Data 0 */
-#define AT91_PB3_MCDA1 (1 << 3) /* B: MMC Multimedia Card A Data 1 */
-#define AT91_PB4_RK0 (1 << 4) /* A: SSC Receive Clock 0 */
-#define AT91_PB4_MCDA2 (1 << 4) /* B: MMC Multimedia Card A Data 2 */
-#define AT91_PB5_RF0 (1 << 5) /* A: SSC Receive Frame Sync 0 */
-#define AT91_PB5_MCDA3 (1 << 5) /* B: MMC Multimedia Card A Data 3 */
-#define AT91_PB6_TF1 (1 << 6) /* A: SSC Transmit Frame Sync 1 */
-#define AT91_PB6_TIOA3 (1 << 6) /* B: TC I/O Line A 3 */
-#define AT91_PB7_TK1 (1 << 7) /* A: SSC Transmit Clock 1 */
-#define AT91_PB7_TIOB3 (1 << 7) /* B: TC I/O Line B 3 */
-#define AT91_PB8_TD1 (1 << 8) /* A: SSC Transmit Data 1 */
-#define AT91_PB8_TIOA4 (1 << 8) /* B: TC I/O Line A 4 */
-#define AT91_PB9_RD1 (1 << 9) /* A: SSC Receive Data 1 */
-#define AT91_PB9_TIOB4 (1 << 9) /* B: TC I/O Line B 4 */
-#define AT91_PB10_RK1 (1 << 10) /* A: SSC Receive Clock 1 */
-#define AT91_PB10_TIOA5 (1 << 10) /* B: TC I/O Line A 5 */
-#define AT91_PB11_RF1 (1 << 11) /* A: SSC Receive Frame Sync 1 */
-#define AT91_PB11_TIOB5 (1 << 11) /* B: TC I/O Line B 5 */
-#define AT91_PB12_TF2 (1 << 12) /* A: SSC Transmit Frame Sync 2 */
-#define AT91_PB12_ETX2 (1 << 12) /* B: Ethernet Transmit Data 2 */
-#define AT91_PB13_TK2 (1 << 13) /* A: SSC Transmit Clock 3 */
-#define AT91_PB13_ETX3 (1 << 13) /* B: Ethernet Transmit Data 3 */
-#define AT91_PB14_TD2 (1 << 14) /* A: SSC Transmit Data 2 */
-#define AT91_PB14_ETXER (1 << 14) /* B: Ethernet Transmit Coding Error */
-#define AT91_PB15_RD2 (1 << 15) /* A: SSC Receive Data 2 */
-#define AT91_PB15_ERX2 (1 << 15) /* B: Ethernet Receive Data 2 */
-#define AT91_PB16_RK2 (1 << 16) /* A: SSC Receive Clock 2 */
-#define AT91_PB16_ERX3 (1 << 16) /* B: Ethernet Receive Data 3 */
-#define AT91_PB17_RF2 (1 << 17) /* A: SSC Receive Frame Sync 2 */
-#define AT91_PB17_ERXDV (1 << 17) /* B: Ethernet Receive Data Valid */
-#define AT91_PB18_RI1 (1 << 18) /* A: USART Ring Indicator 1 */
-#define AT91_PB18_ECOL (1 << 18) /* B: Ethernet Collision Detected */
-#define AT91_PB19_DTR1 (1 << 19) /* A: USART Data Terminal Ready 1 */
-#define AT91_PB19_ERXCK (1 << 19) /* B: Ethernet Receive Clock */
-#define AT91_PB20_TXD1 (1 << 20) /* A: USART Transmit Data 1 */
-#define AT91_PB21_RXD1 (1 << 21) /* A: USART Receive Data 1 */
-#define AT91_PB22_SCK1 (1 << 22) /* A: USART Serial Clock 1 */
-#define AT91_PB23_DCD1 (1 << 23) /* A: USART Data Carrier Detect 1 */
-#define AT91_PB24_CTS1 (1 << 24) /* A: USART Clear To Send 1 */
-#define AT91_PB25_DSR1 (1 << 25) /* A: USART Data Set Ready 1 */
-#define AT91_PB25_EF100 (1 << 25) /* B: Ethernet Force 100 Mbit */
-#define AT91_PB26_RTS1 (1 << 26) /* A: USART Ready To Send 1 */
-#define AT91_PB27_PCK0 (1 << 27) /* B: PMC Programmable Clock Output 0 */
-#define AT91_PB28_FIQ (1 << 28) /* A: Fast Interrupt */
-#define AT91_PB29_IRQ0 (1 << 29) /* A: External Interrupt 0 */
-
-#define AT91_PC0_BFCK (1 << 0) /* A: Burst Flash Clock */
-#define AT91_PC1_BFRDY_SMOE (1 << 1) /* A: Burst Flash Ready / SmartMedia Output Enable */
-#define AT91_PC2_BFAVD (1 << 2) /* A: Burst Flash Address Valid */
-#define AT91_PC3_BFBAA_SMWE (1 << 3) /* A: Burst Flash Address Advance / SmartMedia Write Enable */
-#define AT91_PC4_BFOE (1 << 4) /* A: Burst Flash Output Enable */
-#define AT91_PC5_BFWE (1 << 5) /* A: Burst Flash Write Enable */
-#define AT91_PC6_NWAIT (1 << 6) /* A: SMC Wait Signal */
-#define AT91_PC7_A23 (1 << 7) /* A: Address Bus 23 */
-#define AT91_PC8_A24 (1 << 8) /* A: Address Bus 24 */
-#define AT91_PC9_A25_CFRNW (1 << 9) /* A: Address Bus 25 / Compact Flash Read Not Write */
-#define AT91_PC10_NCS4_CFCS (1 << 10) /* A: SMC Chip Select 4 / Compact Flash Chip Select */
-#define AT91_PC11_NCS5_CFCE1 (1 << 11) /* A: SMC Chip Select 5 / Compact Flash Chip Enable 1 */
-#define AT91_PC12_NCS6_CFCE2 (1 << 12) /* A: SMC Chip Select 6 / Compact Flash Chip Enable 2 */
-#define AT91_PC13_NCS7 (1 << 13) /* A: Chip Select 7 */
-
-#define AT91_PD0_ETX0 (1 << 0) /* A: Ethernet Transmit Data 0 */
-#define AT91_PD1_ETX1 (1 << 1) /* A: Ethernet Transmit Data 1 */
-#define AT91_PD2_ETX2 (1 << 2) /* A: Ethernet Transmit Data 2 */
-#define AT91_PD3_ETX3 (1 << 3) /* A: Ethernet Transmit Data 3 */
-#define AT91_PD4_ETXEN (1 << 4) /* A: Ethernet Transmit Enable */
-#define AT91_PD5_ETXER (1 << 5) /* A: Ethernet Transmit Coding Error */
-#define AT91_PD6_DTXD (1 << 6) /* A: DBGU Transmit Data */
-#define AT91_PD7_PCK0 (1 << 7) /* A: PMC Programmable Clock Output 0 */
-#define AT91_PD7_TSYNC (1 << 7) /* B: ETM Trace Synchronization Signal */
-#define AT91_PD8_PCK1 (1 << 8) /* A: PMC Programmable Clock Output 1 */
-#define AT91_PD8_TCLK (1 << 8) /* B: ETM Trace Clock */
-#define AT91_PD9_PCK2 (1 << 9) /* A: PMC Programmable Clock Output 2 */
-#define AT91_PD9_TPS0 (1 << 9) /* B: ETM Trace ARM Pipeline Status 0 */
-#define AT91_PD10_PCK3 (1 << 10) /* A: PMC Programmable Clock Output 3 */
-#define AT91_PD10_TPS1 (1 << 10) /* B: ETM Trace ARM Pipeline Status 1 */
-#define AT91_PD11_TPS2 (1 << 11) /* B: ETM Trace ARM Pipeline Status 2 */
-#define AT91_PD12_TPK0 (1 << 12) /* B: ETM Trace Packet Port 0 */
-#define AT91_PD13_TPK1 (1 << 13) /* B: ETM Trace Packet Port 1 */
-#define AT91_PD14_TPK2 (1 << 14) /* B: ETM Trace Packet Port 2 */
-#define AT91_PD15_TD0 (1 << 15) /* A: SSC Transmit Data 0 */
-#define AT91_PD15_TPK3 (1 << 15) /* B: ETM Trace Packet Port 3 */
-#define AT91_PD16_TD1 (1 << 16) /* A: SSC Transmit Data 1 */
-#define AT91_PD16_TPK4 (1 << 16) /* B: ETM Trace Packet Port 4 */
-#define AT91_PD17_TD2 (1 << 17) /* A: SSC Transmit Data 2 */
-#define AT91_PD17_TPK5 (1 << 17) /* B: ETM Trace Packet Port 5 */
-#define AT91_PD18_NPCS1 (1 << 18) /* A: SPI Peripheral Chip Select 1 */
-#define AT91_PD18_TPK6 (1 << 18) /* B: ETM Trace Packet Port 6 */
-#define AT91_PD19_NPCS2 (1 << 19) /* A: SPI Peripheral Chip Select 2 */
-#define AT91_PD19_TPK7 (1 << 19) /* B: ETM Trace Packet Port 7 */
-#define AT91_PD20_NPCS3 (1 << 20) /* A: SPI Peripheral Chip Select 3 */
-#define AT91_PD20_TPK8 (1 << 20) /* B: ETM Trace Packet Port 8 */
-#define AT91_PD21_RTS0 (1 << 21) /* A: USART Ready To Send 0 */
-#define AT91_PD21_TPK9 (1 << 21) /* B: ETM Trace Packet Port 9 */
-#define AT91_PD22_RTS1 (1 << 22) /* A: USART Ready To Send 1 */
-#define AT91_PD22_TPK10 (1 << 22) /* B: ETM Trace Packet Port 10 */
-#define AT91_PD23_RTS2 (1 << 23) /* A: USART Ready To Send 2 */
-#define AT91_PD23_TPK11 (1 << 23) /* B: ETM Trace Packet Port 11 */
-#define AT91_PD24_RTS3 (1 << 24) /* A: USART Ready To Send 3 */
-#define AT91_PD24_TPK12 (1 << 24) /* B: ETM Trace Packet Port 12 */
-#define AT91_PD25_DTR1 (1 << 25) /* A: USART Data Terminal Ready 1 */
-#define AT91_PD25_TPK13 (1 << 25) /* B: ETM Trace Packet Port 13 */
-#define AT91_PD26_TPK14 (1 << 26) /* B: ETM Trace Packet Port 14 */
-#define AT91_PD27_TPK15 (1 << 27) /* B: ETM Trace Packet Port 15 */
-#endif
-
#endif
diff --git a/include/asm-arm/arch-at91/at91sam9260.h b/include/asm-arm/arch-at91/at91sam9260.h
index 2cadebc36af..0427f8698c0 100644
--- a/include/asm-arm/arch-at91/at91sam9260.h
+++ b/include/asm-arm/arch-at91/at91sam9260.h
@@ -117,13 +117,4 @@
#define AT91SAM9XE_SRAM_BASE 0x00300000 /* Internal SRAM base address */
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-
-// TODO: Add
-
-#endif
-
#endif
diff --git a/include/asm-arm/arch-at91/at91sam9261.h b/include/asm-arm/arch-at91/at91sam9261.h
index 01b58ffe2e2..9eb45957033 100644
--- a/include/asm-arm/arch-at91/at91sam9261.h
+++ b/include/asm-arm/arch-at91/at91sam9261.h
@@ -98,195 +98,4 @@
#define AT91SAM9261_LCDC_BASE 0x00600000 /* LDC controller */
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-#define AT91_PA0_SPI0_MISO (1 << 0) /* A: SPI0 Master In Slave */
-#define AT91_PA0_MCDA0 (1 << 0) /* B: Multimedia Card A Data 0 */
-#define AT91_PA1_SPI0_MOSI (1 << 1) /* A: SPI0 Master Out Slave */
-#define AT91_PA1_MCCDA (1 << 1) /* B: Multimedia Card A Command */
-#define AT91_PA2_SPI0_SPCK (1 << 2) /* A: SPI0 Serial Clock */
-#define AT91_PA2_MCCK (1 << 2) /* B: Multimedia Card Clock */
-#define AT91_PA3_SPI0_NPCS0 (1 << 3) /* A: SPI0 Peripheral Chip Select 0 */
-#define AT91_PA4_SPI0_NPCS1 (1 << 4) /* A: SPI0 Peripheral Chip Select 1 */
-#define AT91_PA4_MCDA1 (1 << 4) /* B: Multimedia Card A Data 1 */
-#define AT91_PA5_SPI0_NPCS2 (1 << 5) /* A: SPI0 Peripheral Chip Select 2 */
-#define AT91_PA5_MCDA2 (1 << 5) /* B: Multimedia Card A Data 2 */
-#define AT91_PA6_SPI0_NPCS3 (1 << 6) /* A: SPI0 Peripheral Chip Select 3 */
-#define AT91_PA6_MCDA3 (1 << 6) /* B: Multimedia Card A Data 3 */
-#define AT91_PA7_TWD (1 << 7) /* A: TWI Two-wire Serial Data */
-#define AT91_PA7_PCK0 (1 << 7) /* B: PMC Programmable clock Output 0 */
-#define AT91_PA8_TWCK (1 << 8) /* A: TWI Two-wire Serial Clock */
-#define AT91_PA8_PCK1 (1 << 8) /* B: PMC Programmable clock Output 1 */
-#define AT91_PA9_DRXD (1 << 9) /* A: DBGU Debug Receive Data */
-#define AT91_PA9_PCK2 (1 << 9) /* B: PMC Programmable clock Output 2 */
-#define AT91_PA10_DTXD (1 << 10) /* A: DBGU Debug Transmit Data */
-#define AT91_PA10_PCK3 (1 << 10) /* B: PMC Programmable clock Output 3 */
-#define AT91_PA11_TSYNC (1 << 11) /* A: Trace Synchronization Signal */
-#define AT91_PA11_SCK1 (1 << 11) /* B: USART1 Serial Clock */
-#define AT91_PA12_TCLK (1 << 12) /* A: Trace Clock */
-#define AT91_PA12_RTS1 (1 << 12) /* B: USART1 Ready To Send */
-#define AT91_PA13_TPS0 (1 << 13) /* A: Trace ARM Pipeline Status 0 */
-#define AT91_PA13_CTS1 (1 << 13) /* B: USART1 Clear To Send */
-#define AT91_PA14_TPS1 (1 << 14) /* A: Trace ARM Pipeline Status 1 */
-#define AT91_PA14_SCK2 (1 << 14) /* B: USART2 Serial Clock */
-#define AT91_PA15_TPS2 (1 << 15) /* A: Trace ARM Pipeline Status 2 */
-#define AT91_PA15_RTS2 (1 << 15) /* B: USART2 Ready To Send */
-#define AT91_PA16_TPK0 (1 << 16) /* A: Trace Packet Port 0 */
-#define AT91_PA16_CTS2 (1 << 16) /* B: USART2 Clear To Send */
-#define AT91_PA17_TPK1 (1 << 17) /* A: Trace Packet Port 1 */
-#define AT91_PA17_TF1 (1 << 17) /* B: SSC1 Transmit Frame Sync */
-#define AT91_PA18_TPK2 (1 << 18) /* A: Trace Packet Port 2 */
-#define AT91_PA18_TK1 (1 << 18) /* B: SSC1 Transmit Clock */
-#define AT91_PA19_TPK3 (1 << 19) /* A: Trace Packet Port 3 */
-#define AT91_PA19_TD1 (1 << 19) /* B: SSC1 Transmit Data */
-#define AT91_PA20_TPK4 (1 << 20) /* A: Trace Packet Port 4 */
-#define AT91_PA20_RD1 (1 << 20) /* B: SSC1 Receive Data */
-#define AT91_PA21_TPK5 (1 << 21) /* A: Trace Packet Port 5 */
-#define AT91_PA21_RK1 (1 << 21) /* B: SSC1 Receive Clock */
-#define AT91_PA22_TPK6 (1 << 22) /* A: Trace Packet Port 6 */
-#define AT91_PA22_RF1 (1 << 22) /* B: SSC1 Receive Frame Sync */
-#define AT91_PA23_TPK7 (1 << 23) /* A: Trace Packet Port 7 */
-#define AT91_PA23_RTS0 (1 << 23) /* B: USART0 Ready To Send */
-#define AT91_PA24_TPK8 (1 << 24) /* A: Trace Packet Port 8 */
-#define AT91_PA24_SPI1_NPCS1 (1 << 24) /* B: SPI1 Peripheral Chip Select 1 */
-#define AT91_PA25_TPK9 (1 << 25) /* A: Trace Packet Port 9 */
-#define AT91_PA25_SPI1_NPCS2 (1 << 25) /* B: SPI1 Peripheral Chip Select 2 */
-#define AT91_PA26_TPK10 (1 << 26) /* A: Trace Packet Port 10 */
-#define AT91_PA26_SPI1_NPCS3 (1 << 26) /* B: SPI1 Peripheral Chip Select 3 */
-#define AT91_PA27_TPK11 (1 << 27) /* A: Trace Packet Port 11 */
-#define AT91_PA27_SPI0_NPCS1 (1 << 27) /* B: SPI0 Peripheral Chip Select 1 */
-#define AT91_PA28_TPK12 (1 << 28) /* A: Trace Packet Port 12 */
-#define AT91_PA28_SPI0_NPCS2 (1 << 28) /* B: SPI0 Peripheral Chip Select 2 */
-#define AT91_PA29_TPK13 (1 << 29) /* A: Trace Packet Port 13 */
-#define AT91_PA29_SPI0_NPCS3 (1 << 29) /* B: SPI0 Peripheral Chip Select 3 */
-#define AT91_PA30_TPK14 (1 << 30) /* A: Trace Packet Port 14 */
-#define AT91_PA30_A23 (1 << 30) /* B: Address Bus bit 23 */
-#define AT91_PA31_TPK15 (1 << 31) /* A: Trace Packet Port 15 */
-#define AT91_PA31_A24 (1 << 31) /* B: Address Bus bit 24 */
-
-#define AT91_PB0_LCDVSYNC (1 << 0) /* A: LCD Vertical Synchronization */
-#define AT91_PB1_LCDHSYNC (1 << 1) /* A: LCD Horizontal Synchronization */
-#define AT91_PB2_LCDDOTCK (1 << 2) /* A: LCD Dot Clock */
-#define AT91_PB2_PCK0 (1 << 2) /* B: PMC Programmable clock Output 0 */
-#define AT91_PB3_LCDDEN (1 << 3) /* A: LCD Data Enable */
-#define AT91_PB4_LCDCC (1 << 4) /* A: LCD Contrast Control */
-#define AT91_PB4_LCDD2 (1 << 4) /* B: LCD Data Bus Bit 2 */
-#define AT91_PB5_LCDD0 (1 << 5) /* A: LCD Data Bus Bit 0 */
-#define AT91_PB5_LCDD3 (1 << 5) /* B: LCD Data Bus Bit 3 */
-#define AT91_PB6_LCDD1 (1 << 6) /* A: LCD Data Bus Bit 1 */
-#define AT91_PB6_LCDD4 (1 << 6) /* B: LCD Data Bus Bit 4 */
-#define AT91_PB7_LCDD2 (1 << 7) /* A: LCD Data Bus Bit 2 */
-#define AT91_PB7_LCDD5 (1 << 7) /* B: LCD Data Bus Bit 5 */
-#define AT91_PB8_LCDD3 (1 << 8) /* A: LCD Data Bus Bit 3 */
-#define AT91_PB8_LCDD6 (1 << 8) /* B: LCD Data Bus Bit 6 */
-#define AT91_PB9_LCDD4 (1 << 9) /* A: LCD Data Bus Bit 4 */
-#define AT91_PB9_LCDD7 (1 << 9) /* B: LCD Data Bus Bit 7 */
-#define AT91_PB10_LCDD5 (1 << 10) /* A: LCD Data Bus Bit 5 */
-#define AT91_PB10_LCDD10 (1 << 10) /* B: LCD Data Bus Bit 10 */
-#define AT91_PB11_LCDD6 (1 << 11) /* A: LCD Data Bus Bit 6 */
-#define AT91_PB11_LCDD11 (1 << 11) /* B: LCD Data Bus Bit 11 */
-#define AT91_PB12_LCDD7 (1 << 12) /* A: LCD Data Bus Bit 7 */
-#define AT91_PB12_LCDD12 (1 << 12) /* B: LCD Data Bus Bit 12 */
-#define AT91_PB13_LCDD8 (1 << 13) /* A: LCD Data Bus Bit 8 */
-#define AT91_PB13_LCDD13 (1 << 13) /* B: LCD Data Bus Bit 13 */
-#define AT91_PB14_LCDD9 (1 << 14) /* A: LCD Data Bus Bit 9 */
-#define AT91_PB14_LCDD14 (1 << 14) /* B: LCD Data Bus Bit 14 */
-#define AT91_PB15_LCDD10 (1 << 15) /* A: LCD Data Bus Bit 10 */
-#define AT91_PB15_LCDD15 (1 << 15) /* B: LCD Data Bus Bit 15 */
-#define AT91_PB16_LCDD11 (1 << 16) /* A: LCD Data Bus Bit 11 */
-#define AT91_PB16_LCDD19 (1 << 16) /* B: LCD Data Bus Bit 19 */
-#define AT91_PB17_LCDD12 (1 << 17) /* A: LCD Data Bus Bit 12 */
-#define AT91_PB17_LCDD20 (1 << 17) /* B: LCD Data Bus Bit 20 */
-#define AT91_PB18_LCDD13 (1 << 18) /* A: LCD Data Bus Bit 13 */
-#define AT91_PB18_LCDD21 (1 << 18) /* B: LCD Data Bus Bit 21 */
-#define AT91_PB19_LCDD14 (1 << 19) /* A: LCD Data Bus Bit 14 */
-#define AT91_PB19_LCDD22 (1 << 19) /* B: LCD Data Bus Bit 22 */
-#define AT91_PB20_LCDD15 (1 << 20) /* A: LCD Data Bus Bit 15 */
-#define AT91_PB20_LCDD23 (1 << 20) /* B: LCD Data Bus Bit 23 */
-#define AT91_PB21_TF0 (1 << 21) /* A: SSC0 Transmit Frame Sync */
-#define AT91_PB21_LCDD16 (1 << 21) /* B: LCD Data Bus Bit 16 */
-#define AT91_PB22_TK0 (1 << 22) /* A: SSC0 Transmit Clock */
-#define AT91_PB22_LCDD17 (1 << 22) /* B: LCD Data Bus Bit 17 */
-#define AT91_PB23_TD0 (1 << 23) /* A: SSC0 Transmit Data */
-#define AT91_PB23_LCDD18 (1 << 23) /* B: LCD Data Bus Bit 18 */
-#define AT91_PB24_RD0 (1 << 24) /* A: SSC0 Receive Data */
-#define AT91_PB24_LCDD19 (1 << 24) /* B: LCD Data Bus Bit 19 */
-#define AT91_PB25_RK0 (1 << 25) /* A: SSC0 Receive Clock */
-#define AT91_PB25_LCDD20 (1 << 25) /* B: LCD Data Bus Bit 20 */
-#define AT91_PB26_RF0 (1 << 26) /* A: SSC0 Receive Frame Sync */
-#define AT91_PB26_LCDD21 (1 << 26) /* B: LCD Data Bus Bit 21 */
-#define AT91_PB27_SPI1_NPCS1 (1 << 27) /* A: SPI1 Peripheral Chip Select 1 */
-#define AT91_PB27_LCDD22 (1 << 27) /* B: LCD Data Bus Bit 22 */
-#define AT91_PB28_SPI1_NPCS0 (1 << 28) /* A: SPI1 Peripheral Chip Select 0 */
-#define AT91_PB28_LCDD23 (1 << 28) /* B: LCD Data Bus Bit 23 */
-#define AT91_PB29_SPI1_SPCK (1 << 29) /* A: SPI1 Serial Clock */
-#define AT91_PB29_IRQ2 (1 << 29) /* B: Interrupt input 2 */
-#define AT91_PB30_SPI1_MISO (1 << 30) /* A: SPI1 Master In Slave */
-#define AT91_PB30_IRQ1 (1 << 30) /* B: Interrupt input 1 */
-#define AT91_PB31_SPI1_MOSI (1 << 31) /* A: SPI1 Master Out Slave */
-#define AT91_PB31_PCK2 (1 << 31) /* B: PMC Programmable clock Output 2 */
-
-#define AT91_PC0_SMOE (1 << 0) /* A: SmartMedia Output Enable */
-#define AT91_PC0_NCS6 (1 << 0) /* B: Chip Select 6 */
-#define AT91_PC1_SMWE (1 << 1) /* A: SmartMedia Write Enable */
-#define AT91_PC1_NCS7 (1 << 1) /* B: Chip Select 7 */
-#define AT91_PC2_NWAIT (1 << 2) /* A: NWAIT */
-#define AT91_PC2_IRQ0 (1 << 2) /* B: Interrupt input 0 */
-#define AT91_PC3_A25_CFRNW (1 << 3) /* A: Address Bus[25] / Compact Flash Read Not Write */
-#define AT91_PC4_NCS4_CFCS0 (1 << 4) /* A: Chip Select 4 / CompactFlash Chip Select 0 */
-#define AT91_PC5_NCS5_CFCS1 (1 << 5) /* A: Chip Select 5 / CompactFlash Chip Select 1 */
-#define AT91_PC6_CFCE1 (1 << 6) /* A: CompactFlash Chip Enable 1 */
-#define AT91_PC7_CFCE2 (1 << 7) /* A: CompactFlash Chip Enable 2 */
-#define AT91_PC8_TXD0 (1 << 8) /* A: USART0 Transmit Data */
-#define AT91_PC8_PCK2 (1 << 8) /* B: PMC Programmable clock Output 2 */
-#define AT91_PC9_RXD0 (1 << 9) /* A: USART0 Receive Data */
-#define AT91_PC9_PCK3 (1 << 9) /* B: PMC Programmable clock Output 3 */
-#define AT91_PC10_RTS0 (1 << 10) /* A: USART0 Ready To Send */
-#define AT91_PC10_SCK0 (1 << 10) /* B: USART0 Serial Clock */
-#define AT91_PC11_CTS0 (1 << 11) /* A: USART0 Clear To Send */
-#define AT91_PC11_FIQ (1 << 11) /* B: AIC Fast Interrupt Input */
-#define AT91_PC12_TXD1 (1 << 12) /* A: USART1 Transmit Data */
-#define AT91_PC12_NCS6 (1 << 12) /* B: Chip Select 6 */
-#define AT91_PC13_RXD1 (1 << 13) /* A: USART1 Receive Data */
-#define AT91_PC13_NCS7 (1 << 13) /* B: Chip Select 7 */
-#define AT91_PC14_TXD2 (1 << 14) /* A: USART2 Transmit Data */
-#define AT91_PC14_SPI1_NPCS2 (1 << 14) /* B: SPI1 Peripheral Chip Select 2 */
-#define AT91_PC15_RXD2 (1 << 15) /* A: USART2 Receive Data */
-#define AT91_PC15_SPI1_NPCS3 (1 << 15) /* B: SPI1 Peripheral Chip Select 3 */
-#define AT91_PC16_D16 (1 << 16) /* A: Data Bus [16] */
-#define AT91_PC16_TCLK0 (1 << 16) /* B: Timer Counter 0 external clock input */
-#define AT91_PC17_D17 (1 << 17) /* A: Data Bus [17] */
-#define AT91_PC17_TCLK1 (1 << 17) /* B: Timer Counter 1 external clock input */
-#define AT91_PC18_D18 (1 << 18) /* A: Data Bus [18] */
-#define AT91_PC18_TCLK2 (1 << 18) /* B: Timer Counter 2 external clock input */
-#define AT91_PC19_D19 (1 << 19) /* A: Data Bus [19] */
-#define AT91_PC19_TIOA0 (1 << 19) /* B: Timer Counter 0 Multipurpose Timer I/O Pin A */
-#define AT91_PC20_D20 (1 << 20) /* A: Data Bus [20] */
-#define AT91_PC20_TIOB0 (1 << 20) /* B: Timer Counter 0 Multipurpose Timer I/O Pin B */
-#define AT91_PC21_D21 (1 << 21) /* A: Data Bus [21] */
-#define AT91_PC21_TIOA1 (1 << 21) /* B: Timer Counter 1 Multipurpose Timer I/O Pin A */
-#define AT91_PC22_D22 (1 << 22) /* A: Data Bus [22] */
-#define AT91_PC22_TIOB1 (1 << 22) /* B: Timer Counter 1 Multipurpose Timer I/O Pin B */
-#define AT91_PC23_D23 (1 << 23) /* A: Data Bus [23] */
-#define AT91_PC23_TIOA2 (1 << 23) /* B: Timer Counter 2 Multipurpose Timer I/O Pin A */
-#define AT91_PC24_D24 (1 << 24) /* A: Data Bus [24] */
-#define AT91_PC24_TIOB2 (1 << 24) /* B: Timer Counter 2 Multipurpose Timer I/O Pin B */
-#define AT91_PC25_D25 (1 << 25) /* A: Data Bus [25] */
-#define AT91_PC25_TF2 (1 << 25) /* B: SSC2 Transmit Frame Sync */
-#define AT91_PC26_D26 (1 << 26) /* A: Data Bus [26] */
-#define AT91_PC26_TK2 (1 << 26) /* B: SSC2 Transmit Clock */
-#define AT91_PC27_D27 (1 << 27) /* A: Data Bus [27] */
-#define AT91_PC27_TD2 (1 << 27) /* B: SSC2 Transmit Data */
-#define AT91_PC28_D28 (1 << 28) /* A: Data Bus [28] */
-#define AT91_PC28_RD2 (1 << 28) /* B: SSC2 Receive Data */
-#define AT91_PC29_D29 (1 << 29) /* A: Data Bus [29] */
-#define AT91_PC29_RK2 (1 << 29) /* B: SSC2 Receive Clock */
-#define AT91_PC30_D30 (1 << 30) /* A: Data Bus [30] */
-#define AT91_PC30_RF2 (1 << 30) /* B: SSC2 Receive Frame Sync */
-#define AT91_PC31_D31 (1 << 31) /* A: Data Bus [31] */
-#define AT91_PC31_PCK1 (1 << 31) /* B: PMC Programmable clock Output 1 */
-#endif
-
#endif
diff --git a/include/asm-arm/arch-at91/at91sam9263.h b/include/asm-arm/arch-at91/at91sam9263.h
index f4af68ae0ea..115c47ac7eb 100644
--- a/include/asm-arm/arch-at91/at91sam9263.h
+++ b/include/asm-arm/arch-at91/at91sam9263.h
@@ -119,13 +119,5 @@
#define AT91SAM9263_DMAC_BASE 0x00800000 /* DMA Controller */
#define AT91SAM9263_UHP_BASE 0x00a00000 /* USB Host controller */
-#if 0
-/*
- * PIO pin definitions (peripheral A/B multiplexing).
- */
-
-// TODO: Add
-
-#endif
#endif
diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
index 7b9903c2c44..0ce6ee98ed0 100644
--- a/include/asm-arm/arch-at91/board.h
+++ b/include/asm-arm/arch-at91/board.h
@@ -62,7 +62,7 @@ struct at91_mmc_data {
};
extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
- /* Ethernet */
+ /* Ethernet (EMAC & MACB) */
struct at91_eth_data {
u8 phy_irq_pin; /* PHY IRQ */
u8 is_rmii; /* using RMII interface? */
@@ -114,6 +114,16 @@ struct atmel_uart_data {
};
extern void __init at91_add_device_serial(void);
+ /* LCD Controller */
+struct atmel_lcdfb_info;
+extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
+
+ /* AC97 */
+struct atmel_ac97_data {
+ u8 reset_pin; /* reset */
+};
+extern void __init at91_add_device_ac97(struct atmel_ac97_data *data);
+
/* LEDs */
extern u8 at91_leds_cpu;
extern u8 at91_leds_timer;
diff --git a/include/asm-arm/arch-at91/cpu.h b/include/asm-arm/arch-at91/cpu.h
index d464ca58cdb..7ef4eebe9f8 100644
--- a/include/asm-arm/arch-at91/cpu.h
+++ b/include/asm-arm/arch-at91/cpu.h
@@ -68,4 +68,10 @@ static inline unsigned long at91_arch_identify(void)
#define cpu_is_at91sam9263() (0)
#endif
+/*
+ * Since this is ARM, we will never run on any AVR32 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at32ap7000() (0)
+
#endif
diff --git a/include/asm-arm/arch-ebsa110/io.h b/include/asm-arm/arch-ebsa110/io.h
index 722c5e08628..44a4001de80 100644
--- a/include/asm-arm/arch-ebsa110/io.h
+++ b/include/asm-arm/arch-ebsa110/io.h
@@ -81,4 +81,12 @@ extern void outsb(unsigned int port, const void *buf, int sz);
extern void outsw(unsigned int port, const void *buf, int sz);
extern void outsl(unsigned int port, const void *buf, int sz);
+/* can't support writesb atm */
+extern void writesw(void __iomem *addr, const void *data, int wordlen);
+extern void writesl(void __iomem *addr, const void *data, int longlen);
+
+/* can't support readsb atm */
+extern void readsw(const void __iomem *addr, void *data, int wordlen);
+extern void readsl(const void __iomem *addr, void *data, int longlen);
+
#endif
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
index e56a4e247d6..30de404c61f 100644
--- a/include/asm-arm/arch-imx/imx-regs.h
+++ b/include/asm-arm/arch-imx/imx-regs.h
@@ -297,7 +297,7 @@
#define SAR(x) __REG2( IMX_DMAC_BASE + 0x80, (x) << 6) /* Source Address Registers */
#define DAR(x) __REG2( IMX_DMAC_BASE + 0x84, (x) << 6) /* Destination Address Registers */
#define CNTR(x) __REG2( IMX_DMAC_BASE + 0x88, (x) << 6) /* Count Registers */
-#define CCR(x) __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6) /* Control Registers */
+#define CCR(x) __REG2( IMX_DMAC_BASE + 0x8c, (x) << 6) /* Control Registers */
#define RSSR(x) __REG2( IMX_DMAC_BASE + 0x90, (x) << 6) /* Request source select Registers */
#define BLR(x) __REG2( IMX_DMAC_BASE + 0x94, (x) << 6) /* Burst length Registers */
#define RTOR(x) __REG2( IMX_DMAC_BASE + 0x98, (x) << 6) /* Request timeout Registers */
@@ -477,122 +477,4 @@
#define LCDISR_EOF (1<<1)
#define LCDISR_BOF (1<<0)
-/*
- * UART Module. Takes the UART base address as argument
- */
-#define URXD0(x) __REG( 0x0 + (x)) /* Receiver Register */
-#define URTX0(x) __REG( 0x40 + (x)) /* Transmitter Register */
-#define UCR1(x) __REG( 0x80 + (x)) /* Control Register 1 */
-#define UCR2(x) __REG( 0x84 + (x)) /* Control Register 2 */
-#define UCR3(x) __REG( 0x88 + (x)) /* Control Register 3 */
-#define UCR4(x) __REG( 0x8c + (x)) /* Control Register 4 */
-#define UFCR(x) __REG( 0x90 + (x)) /* FIFO Control Register */
-#define USR1(x) __REG( 0x94 + (x)) /* Status Register 1 */
-#define USR2(x) __REG( 0x98 + (x)) /* Status Register 2 */
-#define UESC(x) __REG( 0x9c + (x)) /* Escape Character Register */
-#define UTIM(x) __REG( 0xa0 + (x)) /* Escape Timer Register */
-#define UBIR(x) __REG( 0xa4 + (x)) /* BRM Incremental Register */
-#define UBMR(x) __REG( 0xa8 + (x)) /* BRM Modulator Register */
-#define UBRC(x) __REG( 0xac + (x)) /* Baud Rate Count Register */
-#define BIPR1(x) __REG( 0xb0 + (x)) /* Incremental Preset Register 1 */
-#define BIPR2(x) __REG( 0xb4 + (x)) /* Incremental Preset Register 2 */
-#define BIPR3(x) __REG( 0xb8 + (x)) /* Incremental Preset Register 3 */
-#define BIPR4(x) __REG( 0xbc + (x)) /* Incremental Preset Register 4 */
-#define BMPR1(x) __REG( 0xc0 + (x)) /* BRM Modulator Register 1 */
-#define BMPR2(x) __REG( 0xc4 + (x)) /* BRM Modulator Register 2 */
-#define BMPR3(x) __REG( 0xc8 + (x)) /* BRM Modulator Register 3 */
-#define BMPR4(x) __REG( 0xcc + (x)) /* BRM Modulator Register 4 */
-#define UTS(x) __REG( 0xd0 + (x)) /* UART Test Register */
-
-/* UART Control Register Bit Fields.*/
-#define URXD_CHARRDY (1<<15)
-#define URXD_ERR (1<<14)
-#define URXD_OVRRUN (1<<13)
-#define URXD_FRMERR (1<<12)
-#define URXD_BRK (1<<11)
-#define URXD_PRERR (1<<10)
-#define UCR1_ADEN (1<<15) /* Auto dectect interrupt */
-#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
-#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
-#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
-#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
-#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
-#define UCR1_IREN (1<<7) /* Infrared interface enable */
-#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
-#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
-#define UCR1_SNDBRK (1<<4) /* Send break */
-#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
-#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
-#define UCR1_DOZE (1<<1) /* Doze */
-#define UCR1_UARTEN (1<<0) /* UART enabled */
-#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
-#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
-#define UCR2_CTSC (1<<13) /* CTS pin control */
-#define UCR2_CTS (1<<12) /* Clear to send */
-#define UCR2_ESCEN (1<<11) /* Escape enable */
-#define UCR2_PREN (1<<8) /* Parity enable */
-#define UCR2_PROE (1<<7) /* Parity odd/even */
-#define UCR2_STPB (1<<6) /* Stop */
-#define UCR2_WS (1<<5) /* Word size */
-#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
-#define UCR2_TXEN (1<<2) /* Transmitter enabled */
-#define UCR2_RXEN (1<<1) /* Receiver enabled */
-#define UCR2_SRST (1<<0) /* SW reset */
-#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
-#define UCR3_PARERREN (1<<12) /* Parity enable */
-#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
-#define UCR3_DSR (1<<10) /* Data set ready */
-#define UCR3_DCD (1<<9) /* Data carrier detect */
-#define UCR3_RI (1<<8) /* Ring indicator */
-#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
-#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
-#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
-#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
-#define UCR3_REF25 (1<<3) /* Ref freq 25 MHz */
-#define UCR3_REF30 (1<<2) /* Ref Freq 30 MHz */
-#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
-#define UCR3_BPEN (1<<0) /* Preset registers enable */
-#define UCR4_CTSTL_32 (32<<10) /* CTS trigger level (32 chars) */
-#define UCR4_INVR (1<<9) /* Inverted infrared reception */
-#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
-#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
-#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
-#define UCR4_IRSC (1<<5) /* IR special case */
-#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
-#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
-#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
-#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
-#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
-#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
-#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
-#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
-#define USR1_RTSS (1<<14) /* RTS pin status */
-#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
-#define USR1_RTSD (1<<12) /* RTS delta */
-#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
-#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
-#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
-#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
-#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
-#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
-#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
-#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
-#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
-#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
-#define USR2_IDLE (1<<12) /* Idle condition */
-#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
-#define USR2_WAKE (1<<7) /* Wake */
-#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
-#define USR2_TXDC (1<<3) /* Transmitter complete */
-#define USR2_BRCD (1<<2) /* Break condition */
-#define USR2_ORE (1<<1) /* Overrun error */
-#define USR2_RDR (1<<0) /* Recv data ready */
-#define UTS_FRCPERR (1<<13) /* Force parity error */
-#define UTS_LOOP (1<<12) /* Loop tx and rx */
-#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
-#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
-#define UTS_TXFULL (1<<4) /* TxFIFO full */
-#define UTS_RXFULL (1<<3) /* RxFIFO full */
-#define UTS_SOFTRST (1<<0) /* Software reset */
-
#endif // _IMX_REGS_H
diff --git a/include/asm-arm/arch-imx/mmc.h b/include/asm-arm/arch-imx/mmc.h
index 1937151665c..84c726934ac 100644
--- a/include/asm-arm/arch-imx/mmc.h
+++ b/include/asm-arm/arch-imx/mmc.h
@@ -1,7 +1,7 @@
#ifndef ASMARM_ARCH_MMC_H
#define ASMARM_ARCH_MMC_H
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
struct imxmmc_platform_data {
int (*card_present)(void);
diff --git a/include/asm-arm/arch-integrator/platform.h b/include/asm-arm/arch-integrator/platform.h
index 96ad3d2a66d..83c4c1ceb41 100644
--- a/include/asm-arm/arch-integrator/platform.h
+++ b/include/asm-arm/arch-integrator/platform.h
@@ -17,7 +17,7 @@
* from .s file by awk -f s2h.awk
*/
/**************************************************************************
- * * Copyright © ARM Limited 1998. All rights reserved.
+ * * Copyright © ARM Limited 1998. All rights reserved.
* ***********************************************************************/
/* ************************************************************************
*
diff --git a/include/asm-arm/arch-iop13xx/io.h b/include/asm-arm/arch-iop13xx/io.h
index 5a7bdb52660..7dfff4ad82b 100644
--- a/include/asm-arm/arch-iop13xx/io.h
+++ b/include/asm-arm/arch-iop13xx/io.h
@@ -26,7 +26,6 @@
#define __mem_isa(a) (a)
extern void __iomem * __iop13xx_io(unsigned long io_addr);
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
extern void __iomem *__iop13xx_ioremap(unsigned long cookie, size_t size,
unsigned long flags);
extern void __iop13xx_iounmap(void __iomem *addr);
diff --git a/include/asm-arm/arch-iop13xx/iop13xx.h b/include/asm-arm/arch-iop13xx/iop13xx.h
index d26b755a987..85707e9c332 100644
--- a/include/asm-arm/arch-iop13xx/iop13xx.h
+++ b/include/asm-arm/arch-iop13xx/iop13xx.h
@@ -8,6 +8,7 @@ extern u32 iop13xx_atue_pmmr_offset;
void iop13xx_init_irq(void);
void iop13xx_map_io(void);
void iop13xx_platform_init(void);
+void iop13xx_add_tpmi_devices(void);
void iop13xx_init_irq(void);
/* CPUID CP6 R0 Page 0 */
@@ -27,19 +28,24 @@ static inline int iop13xx_cpu_id(void)
#define IOP13XX_PCI_OFFSET IOP13XX_MAX_RAM_SIZE
/* PCI MAP
- * 0x0000.0000 - 0x8000.0000 1:1 mapping with Physical RAM
- * 0x8000.0000 - 0x8800.0000 PCIX/PCIE memory window (128MB)
-*/
+ * bus range cpu phys cpu virt note
+ * 0x0000.0000 + 2GB (n/a) (n/a) inbound, 1:1 mapping with Physical RAM
+ * 0x8000.0000 + 928M 0x1.8000.0000 (ioremap) PCIX outbound memory window
+ * 0x8000.0000 + 928M 0x2.8000.0000 (ioremap) PCIE outbound memory window
+ *
+ * IO MAP
+ * 0x1000 + 64K 0x0.fffb.1000 0xfec6.1000 PCIX outbound i/o window
+ * 0x1000 + 64K 0x0.fffd.1000 0xfed7.1000 PCIE outbound i/o window
+ */
#define IOP13XX_PCIX_IO_WINDOW_SIZE 0x10000UL
#define IOP13XX_PCIX_LOWER_IO_PA 0xfffb0000UL
#define IOP13XX_PCIX_LOWER_IO_VA 0xfec60000UL
-#define IOP13XX_PCIX_LOWER_IO_BA 0x0fff0000UL
+#define IOP13XX_PCIX_LOWER_IO_BA 0x0UL /* OIOTVR */
+#define IOP13XX_PCIX_IO_BUS_OFFSET 0x1000UL
#define IOP13XX_PCIX_UPPER_IO_PA (IOP13XX_PCIX_LOWER_IO_PA +\
IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
#define IOP13XX_PCIX_UPPER_IO_VA (IOP13XX_PCIX_LOWER_IO_VA +\
IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_IO_OFFSET (IOP13XX_PCIX_LOWER_IO_VA -\
- IOP13XX_PCIX_LOWER_IO_BA)
#define IOP13XX_PCIX_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
(IOP13XX_PCIX_LOWER_IO_PA\
- IOP13XX_PCIX_LOWER_IO_VA))
@@ -65,15 +71,14 @@ static inline int iop13xx_cpu_id(void)
#define IOP13XX_PCIE_IO_WINDOW_SIZE 0x10000UL
#define IOP13XX_PCIE_LOWER_IO_PA 0xfffd0000UL
#define IOP13XX_PCIE_LOWER_IO_VA 0xfed70000UL
-#define IOP13XX_PCIE_LOWER_IO_BA 0x0fff0000UL
+#define IOP13XX_PCIE_LOWER_IO_BA 0x0UL /* OIOTVR */
+#define IOP13XX_PCIE_IO_BUS_OFFSET 0x1000UL
#define IOP13XX_PCIE_UPPER_IO_PA (IOP13XX_PCIE_LOWER_IO_PA +\
IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
#define IOP13XX_PCIE_UPPER_IO_VA (IOP13XX_PCIE_LOWER_IO_VA +\
IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
#define IOP13XX_PCIE_UPPER_IO_BA (IOP13XX_PCIE_LOWER_IO_BA +\
IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_IO_OFFSET (IOP13XX_PCIE_LOWER_IO_VA -\
- IOP13XX_PCIE_LOWER_IO_BA)
#define IOP13XX_PCIE_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
(IOP13XX_PCIE_LOWER_IO_PA\
- IOP13XX_PCIE_LOWER_IO_VA))
@@ -451,4 +456,5 @@ static inline int iop13xx_cpu_id(void)
#define IOP13XX_PBI_BAR1 IOP13XX_PBI_OFFSET(0x10)
#define IOP13XX_PBI_LR1 IOP13XX_PBI_OFFSET(0x14)
+#define IOP13XX_PROCESSOR_FREQ IOP13XX_REG_ADDR32(0x2180)
#endif /* _IOP13XX_HW_H_ */
diff --git a/include/asm-arm/arch-iop13xx/time.h b/include/asm-arm/arch-iop13xx/time.h
index 77a837a02de..49213d9d7ca 100644
--- a/include/asm-arm/arch-iop13xx/time.h
+++ b/include/asm-arm/arch-iop13xx/time.h
@@ -7,9 +7,65 @@
#define IOP_TMR_PRIVILEGED 0x08
#define IOP_TMR_RATIO_1_1 0x00
+#define IOP13XX_XSI_FREQ_RATIO_MASK (3 << 19)
+#define IOP13XX_XSI_FREQ_RATIO_2 (0 << 19)
+#define IOP13XX_XSI_FREQ_RATIO_3 (1 << 19)
+#define IOP13XX_XSI_FREQ_RATIO_4 (2 << 19)
+#define IOP13XX_CORE_FREQ_MASK (7 << 16)
+#define IOP13XX_CORE_FREQ_600 (0 << 16)
+#define IOP13XX_CORE_FREQ_667 (1 << 16)
+#define IOP13XX_CORE_FREQ_800 (2 << 16)
+#define IOP13XX_CORE_FREQ_933 (3 << 16)
+#define IOP13XX_CORE_FREQ_1000 (4 << 16)
+#define IOP13XX_CORE_FREQ_1200 (5 << 16)
+
void iop_init_time(unsigned long tickrate);
unsigned long iop_gettimeoffset(void);
+static inline unsigned long iop13xx_core_freq(void)
+{
+ unsigned long freq = __raw_readl(IOP13XX_PROCESSOR_FREQ);
+ freq &= IOP13XX_CORE_FREQ_MASK;
+ switch (freq) {
+ case IOP13XX_CORE_FREQ_600:
+ return 600000000;
+ case IOP13XX_CORE_FREQ_667:
+ return 667000000;
+ case IOP13XX_CORE_FREQ_800:
+ return 800000000;
+ case IOP13XX_CORE_FREQ_933:
+ return 933000000;
+ case IOP13XX_CORE_FREQ_1000:
+ return 1000000000;
+ case IOP13XX_CORE_FREQ_1200:
+ return 1200000000;
+ default:
+ printk("%s: warning unknown frequency, defaulting to 800Mhz\n",
+ __FUNCTION__);
+ }
+
+ return 800000000;
+}
+
+static inline unsigned long iop13xx_xsi_bus_ratio(void)
+{
+ unsigned long ratio = __raw_readl(IOP13XX_PROCESSOR_FREQ);
+ ratio &= IOP13XX_XSI_FREQ_RATIO_MASK;
+ switch (ratio) {
+ case IOP13XX_XSI_FREQ_RATIO_2:
+ return 2;
+ case IOP13XX_XSI_FREQ_RATIO_3:
+ return 3;
+ case IOP13XX_XSI_FREQ_RATIO_4:
+ return 4;
+ default:
+ printk("%s: warning unknown ratio, defaulting to 2\n",
+ __FUNCTION__);
+ }
+
+ return 2;
+}
+
static inline void write_tmr0(u32 val)
{
asm volatile("mcr p6, 0, %0, c0, c9, 0" : : "r" (val));
diff --git a/include/asm-arm/arch-iop32x/glantank.h b/include/asm-arm/arch-iop32x/glantank.h
index 3b065618dd0..bf0665acc1c 100644
--- a/include/asm-arm/arch-iop32x/glantank.h
+++ b/include/asm-arm/arch-iop32x/glantank.h
@@ -1,5 +1,5 @@
/*
- * include/asm/arch-iop32x/glantank.h
+ * include/asm-arm/arch-iop32x/glantank.h
*
* IO-Data GLAN Tank board registers
*/
diff --git a/include/asm-arm/arch-iop32x/io.h b/include/asm-arm/arch-iop32x/io.h
index 5f570a598a3..994f16af505 100644
--- a/include/asm-arm/arch-iop32x/io.h
+++ b/include/asm-arm/arch-iop32x/io.h
@@ -13,7 +13,6 @@
#include <asm/hardware.h>
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size,
unsigned long flags);
extern void __iop3xx_iounmap(void __iomem *addr);
diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h
index 2e9469047eb..0d8af57221a 100644
--- a/include/asm-arm/arch-iop32x/iop32x.h
+++ b/include/asm-arm/arch-iop32x/iop32x.h
@@ -24,5 +24,14 @@
#include <asm/hardware/iop3xx.h>
+/* ATU Parameters
+ * set up a 1:1 bus to physical ram relationship
+ * w/ physical ram on top of pci in the memory map
+ */
+#define IOP32X_MAX_RAM_SIZE 0x40000000UL
+#define IOP3XX_MAX_RAM_SIZE IOP32X_MAX_RAM_SIZE
+#define IOP3XX_PCI_LOWER_MEM_BA 0x80000000
+#define IOP32X_PCI_MEM_WINDOW_SIZE 0x04000000
+#define IOP3XX_PCI_MEM_WINDOW_SIZE IOP32X_PCI_MEM_WINDOW_SIZE
#endif
diff --git a/include/asm-arm/arch-iop32x/memory.h b/include/asm-arm/arch-iop32x/memory.h
index 764cd3f0d41..c51072af214 100644
--- a/include/asm-arm/arch-iop32x/memory.h
+++ b/include/asm-arm/arch-iop32x/memory.h
@@ -19,8 +19,8 @@
* bus_to_virt: Used to convert an address for DMA operations
* to an address that the kernel can use.
*/
-#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0))
-#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2)))
+#define __virt_to_bus(x) (__virt_to_phys(x))
+#define __bus_to_virt(x) (__phys_to_virt(x))
#endif
diff --git a/include/asm-arm/arch-iop32x/n2100.h b/include/asm-arm/arch-iop32x/n2100.h
index fed31a64842..77a8af47662 100644
--- a/include/asm-arm/arch-iop32x/n2100.h
+++ b/include/asm-arm/arch-iop32x/n2100.h
@@ -1,5 +1,5 @@
/*
- * include/asm/arch-iop32x/n2100.h
+ * include/asm-arm/arch-iop32x/n2100.h
*
* Thecus N2100 board registers
*/
diff --git a/include/asm-arm/arch-iop33x/io.h b/include/asm-arm/arch-iop33x/io.h
index 1bb5071e1fa..993f7589b29 100644
--- a/include/asm-arm/arch-iop33x/io.h
+++ b/include/asm-arm/arch-iop33x/io.h
@@ -13,7 +13,6 @@
#include <asm/hardware.h>
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
extern void __iomem *__iop3xx_ioremap(unsigned long cookie, size_t size,
unsigned long flags);
extern void __iop3xx_iounmap(void __iomem *addr);
diff --git a/include/asm-arm/arch-iop33x/iop33x.h b/include/asm-arm/arch-iop33x/iop33x.h
index 7ac6e93db5f..766985b9a72 100644
--- a/include/asm-arm/arch-iop33x/iop33x.h
+++ b/include/asm-arm/arch-iop33x/iop33x.h
@@ -29,5 +29,15 @@
#define IOP33X_UART1_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740)
#define IOP33X_UART1_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740)
+/* ATU Parameters
+ * set up a 1:1 bus to physical ram relationship
+ * w/ pci on top of physical ram in memory map
+ */
+#define IOP33X_MAX_RAM_SIZE 0x80000000UL
+#define IOP3XX_MAX_RAM_SIZE IOP33X_MAX_RAM_SIZE
+#define IOP3XX_PCI_LOWER_MEM_BA (PHYS_OFFSET + IOP33X_MAX_RAM_SIZE)
+#define IOP33X_PCI_MEM_WINDOW_SIZE 0x08000000
+#define IOP3XX_PCI_MEM_WINDOW_SIZE IOP33X_PCI_MEM_WINDOW_SIZE
+
#endif
diff --git a/include/asm-arm/arch-iop33x/memory.h b/include/asm-arm/arch-iop33x/memory.h
index 0d39139b241..c8749127d6a 100644
--- a/include/asm-arm/arch-iop33x/memory.h
+++ b/include/asm-arm/arch-iop33x/memory.h
@@ -19,8 +19,8 @@
* bus_to_virt: Used to convert an address for DMA operations
* to an address that the kernel can use.
*/
-#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0))
-#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2)))
+#define __virt_to_bus(x) (__virt_to_phys(x))
+#define __bus_to_virt(x) (__phys_to_virt(x))
#endif
diff --git a/include/asm-arm/arch-ixp23xx/io.h b/include/asm-arm/arch-ixp23xx/io.h
index 18415a81ac7..66f5bafc315 100644
--- a/include/asm-arm/arch-ixp23xx/io.h
+++ b/include/asm-arm/arch-ixp23xx/io.h
@@ -23,7 +23,7 @@
#include <linux/kernel.h> /* For BUG */
static inline void __iomem *
-ixp23xx_ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+ixp23xx_ioremap(unsigned long addr, unsigned long size, unsigned int mtype)
{
if (addr >= IXP23XX_PCI_MEM_START &&
addr <= IXP23XX_PCI_MEM_START + IXP23XX_PCI_MEM_SIZE) {
@@ -34,7 +34,7 @@ ixp23xx_ioremap(unsigned long addr, unsigned long size, unsigned long flags)
((addr - IXP23XX_PCI_MEM_START) + IXP23XX_PCI_MEM_VIRT);
}
- return __ioremap(addr, size, flags);
+ return __arm_ioremap(addr, size, mtype);
}
static inline void
diff --git a/include/asm-arm/arch-ixp4xx/cpu.h b/include/asm-arm/arch-ixp4xx/cpu.h
new file mode 100644
index 00000000000..d2523b326c6
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/cpu.h
@@ -0,0 +1,31 @@
+/*
+ * include/asm-arm/arch-ixp4xx/cpu.h
+ *
+ * IXP4XX cpu type detection
+ *
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __ASM_ARCH_CPU_H__
+#define __ASM_ARCH_CPU_H__
+
+extern unsigned int processor_id;
+/* Processor id value in CP15 Register 0 */
+#define IXP425_PROCESSOR_ID_VALUE 0x690541c0
+#define IXP435_PROCESSOR_ID_VALUE 0x69054040
+#define IXP465_PROCESSOR_ID_VALUE 0x69054200
+#define IXP4XX_PROCESSOR_ID_MASK 0xfffffff0
+
+#define cpu_is_ixp42x() ((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+ IXP425_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp43x() ((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+ IXP435_PROCESSOR_ID_VALUE)
+#define cpu_is_ixp46x() ((processor_id & IXP4XX_PROCESSOR_ID_MASK) == \
+ IXP465_PROCESSOR_ID_VALUE)
+
+#endif /* _ASM_ARCH_CPU_H */
diff --git a/include/asm-arm/arch-ixp4xx/dma.h b/include/asm-arm/arch-ixp4xx/dma.h
index 789f7f53c35..2c7f5327d80 100644
--- a/include/asm-arm/arch-ixp4xx/dma.h
+++ b/include/asm-arm/arch-ixp4xx/dma.h
@@ -12,7 +12,6 @@
#define __ASM_ARCH_DMA_H
#include <linux/device.h>
-#include <linux/pci.h>
#include <asm/page.h>
#include <asm/sizes.h>
#include <asm/hardware.h>
diff --git a/include/asm-arm/arch-ixp4xx/dsmg600.h b/include/asm-arm/arch-ixp4xx/dsmg600.h
new file mode 100644
index 00000000000..a19605ad240
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/dsmg600.h
@@ -0,0 +1,57 @@
+/*
+ * DSM-G600 platform specific definitions
+ *
+ * Copyright (C) 2006 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on ixdp425.h:
+ * Copyright 2004 (C) MontaVista, Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H__
+#error "Do not include this directly, instead #include <asm/hardware.h>"
+#endif
+
+#define DSMG600_SDA_PIN 5
+#define DSMG600_SCL_PIN 4
+
+/*
+ * DSMG600 PCI IRQs
+ */
+#define DSMG600_PCI_MAX_DEV 4
+#define DSMG600_PCI_IRQ_LINES 3
+
+
+/* PCI controller GPIO to IRQ pin mappings */
+#define DSMG600_PCI_INTA_PIN 11
+#define DSMG600_PCI_INTB_PIN 10
+#define DSMG600_PCI_INTC_PIN 9
+#define DSMG600_PCI_INTD_PIN 8
+#define DSMG600_PCI_INTE_PIN 7
+#define DSMG600_PCI_INTF_PIN 6
+
+/* DSM-G600 Timer Setting */
+#define DSMG600_FREQ 66000000
+
+/* Buttons */
+
+#define DSMG600_PB_GPIO 15 /* power button */
+#define DSMG600_PB_BM (1L << DSMG600_PB_GPIO)
+
+#define DSMG600_RB_GPIO 3 /* reset button */
+
+#define DSMG600_RB_IRQ IRQ_IXP4XX_GPIO3
+
+#define DSMG600_PO_GPIO 2 /* power off */
+
+/* LEDs */
+
+#define DSMG600_LED_PWR_GPIO 0
+#define DSMG600_LED_PWR_BM (1L << DSMG600_LED_PWR_GPIO)
+
+#define DSMG600_LED_WLAN_GPIO 14
+#define DSMG600_LED_WLAN_BM (1L << DSMG600_LED_WLAN_GPIO)
diff --git a/include/asm-arm/arch-ixp4xx/entry-macro.S b/include/asm-arm/arch-ixp4xx/entry-macro.S
index dadb568b7ef..f144a005ed9 100644
--- a/include/asm-arm/arch-ixp4xx/entry-macro.S
+++ b/include/asm-arm/arch-ixp4xx/entry-macro.S
@@ -31,9 +31,9 @@
1001:
/*
- * IXP465 has an upper IRQ status register
+ * IXP465/IXP435 has an upper IRQ status register
*/
-#if defined(CONFIG_CPU_IXP46X)
+#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
ldr \irqstat, =(IXP4XX_INTC_BASE_VIRT+IXP4XX_ICIP2_OFFSET)
ldr \irqstat, [\irqstat] @ get upper interrupts
mov \irqnr, #63
diff --git a/include/asm-arm/arch-ixp4xx/gpio.h b/include/asm-arm/arch-ixp4xx/gpio.h
new file mode 100644
index 00000000000..3a4c5b8ae9e
--- /dev/null
+++ b/include/asm-arm/arch-ixp4xx/gpio.h
@@ -0,0 +1,73 @@
+/*
+ * linux/include/asm-arm/arch-ixp4xx/gpio.h
+ *
+ * IXP4XX GPIO wrappers for arch-neutral GPIO calls
+ *
+ * Written by Milan Svoboda <msvoboda@ra.rockwell.com>
+ * Based on PXA implementation by Philipp Zabel <philipp.zabel@gmail.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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __ASM_ARCH_IXP4XX_GPIO_H
+#define __ASM_ARCH_IXP4XX_GPIO_H
+
+#include <asm/hardware.h>
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ return;
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ gpio_line_config(gpio, IXP4XX_GPIO_IN);
+ return 0;
+}
+
+static inline int gpio_direction_output(unsigned gpio, int level)
+{
+ gpio_line_set(gpio, level);
+ gpio_line_config(gpio, IXP4XX_GPIO_OUT);
+ return 0;
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ int value;
+
+ gpio_line_get(gpio, &value);
+
+ return value;
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ gpio_line_set(gpio, value);
+}
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+extern int gpio_to_irq(int gpio);
+extern int irq_to_gpio(int gpio);
+
+#endif
+
diff --git a/include/asm-arm/arch-ixp4xx/hardware.h b/include/asm-arm/arch-ixp4xx/hardware.h
index 88fd0877dcc..297ceda08b6 100644
--- a/include/asm-arm/arch-ixp4xx/hardware.h
+++ b/include/asm-arm/arch-ixp4xx/hardware.h
@@ -17,8 +17,8 @@
#ifndef __ASM_ARCH_HARDWARE_H__
#define __ASM_ARCH_HARDWARE_H__
-#define PCIBIOS_MIN_IO 0x00001000
-#define PCIBIOS_MIN_MEM 0x48000000
+#define PCIBIOS_MIN_IO 0x00001000
+#define PCIBIOS_MIN_MEM (cpu_is_ixp43x() ? 0x40000000 : 0x48000000)
/*
* We override the standard dma-mask routines for bouncing.
@@ -27,11 +27,8 @@
#define pcibios_assign_all_busses() 1
-#if defined(CONFIG_CPU_IXP46X) && !defined(__ASSEMBLY__)
-extern unsigned int processor_id;
-#define cpu_is_ixp465() ((processor_id & 0xffffffc0) == 0x69054200)
-#else
-#define cpu_is_ixp465() (0)
+#ifndef __ASSEMBLER__
+#include <asm/arch/cpu.h>
#endif
/* Register locations and bits */
@@ -47,5 +44,6 @@ extern unsigned int processor_id;
#include "prpmc1100.h"
#include "nslu2.h"
#include "nas100d.h"
+#include "dsmg600.h"
#endif /* _ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index a41ba229c56..c72f9d79417 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -59,10 +59,10 @@ extern int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data);
* fallback to the default.
*/
static inline void __iomem *
-__ixp4xx_ioremap(unsigned long addr, size_t size, unsigned long flags)
+__ixp4xx_ioremap(unsigned long addr, size_t size, unsigned int mtype)
{
- if((addr < 0x48000000) || (addr > 0x4fffffff))
- return __ioremap(addr, size, flags);
+ if((addr < PCIBIOS_MIN_MEM) || (addr > 0x4fffffff))
+ return __arm_ioremap(addr, size, mtype);
return (void *)addr;
}
diff --git a/include/asm-arm/arch-ixp4xx/irqs.h b/include/asm-arm/arch-ixp4xx/irqs.h
index e44a563d00f..11801605047 100644
--- a/include/asm-arm/arch-ixp4xx/irqs.h
+++ b/include/asm-arm/arch-ixp4xx/irqs.h
@@ -62,10 +62,10 @@
/*
* Only first 32 sources are valid if running on IXP42x systems
*/
-#ifndef CONFIG_CPU_IXP46X
-#define NR_IRQS 32
-#else
+#if defined(CONFIG_CPU_IXP46X) || defined(CONFIG_CPU_IXP43X)
#define NR_IRQS 64
+#else
+#define NR_IRQS 32
#endif
#define XSCALE_PMU_IRQ (IRQ_IXP4XX_XSCALE_PMU)
@@ -118,4 +118,14 @@
#define IRQ_NAS100D_PCI_INTD IRQ_IXP4XX_GPIO8
#define IRQ_NAS100D_PCI_INTE IRQ_IXP4XX_GPIO7
+/*
+ * D-Link DSM-G600 RevA board IRQs
+ */
+#define IRQ_DSMG600_PCI_INTA IRQ_IXP4XX_GPIO11
+#define IRQ_DSMG600_PCI_INTB IRQ_IXP4XX_GPIO10
+#define IRQ_DSMG600_PCI_INTC IRQ_IXP4XX_GPIO9
+#define IRQ_DSMG600_PCI_INTD IRQ_IXP4XX_GPIO8
+#define IRQ_DSMG600_PCI_INTE IRQ_IXP4XX_GPIO7
+#define IRQ_DSMG600_PCI_INTF IRQ_IXP4XX_GPIO6
+
#endif
diff --git a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
index ed35e5c94f4..5d949d763a9 100644
--- a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
+++ b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
@@ -607,19 +607,4 @@
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
-#ifndef __ASSEMBLY__
-static inline int cpu_is_ixp46x(void)
-{
-#ifdef CONFIG_CPU_IXP46X
- unsigned int processor_id;
-
- asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
-
- if ((processor_id & 0xffffff00) == 0x69054200)
- return 1;
-#endif
- return 0;
-}
-#endif
-
#endif
diff --git a/include/asm-arm/arch-netx/netx-regs.h b/include/asm-arm/arch-netx/netx-regs.h
index 8ab45bea83c..fc9aa21f360 100644
--- a/include/asm-arm/arch-netx/netx-regs.h
+++ b/include/asm-arm/arch-netx/netx-regs.h
@@ -121,8 +121,8 @@
#define NETX_SYSTEM_IOC_MR NETX_SYSTEM_REG(0x08)
/* FIXME: Docs are not consistent */
-#define NETX_SYSTEM_RES_CR NETX_SYSTEM_REG(0x08)
-/* #define NETX_SYSTEM_RES_CR NETX_SYSTEM_REG(0x0c) */
+/* #define NETX_SYSTEM_RES_CR NETX_SYSTEM_REG(0x08) */
+#define NETX_SYSTEM_RES_CR NETX_SYSTEM_REG(0x0c)
#define NETX_SYSTEM_PHY_CONTROL NETX_SYSTEM_REG(0x10)
#define NETX_SYSTEM_REV NETX_SYSTEM_REG(0x34)
diff --git a/include/asm-arm/arch-ns9xxx/board.h b/include/asm-arm/arch-ns9xxx/board.h
index 91dc8fb1027..716f34fdb71 100644
--- a/include/asm-arm/arch-ns9xxx/board.h
+++ b/include/asm-arm/arch-ns9xxx/board.h
@@ -15,4 +15,6 @@
#define board_is_a9m9750dev() (machine_is_cc9p9360dev())
+#define board_is_jscc9p9360() (machine_is_cc9p9360js())
+
#endif /* ifndef __ASM_ARCH_BOARD_H */
diff --git a/include/asm-arm/arch-ns9xxx/clock.h b/include/asm-arm/arch-ns9xxx/clock.h
index a7c5ab3d901..bf30cbdcc2b 100644
--- a/include/asm-arm/arch-ns9xxx/clock.h
+++ b/include/asm-arm/arch-ns9xxx/clock.h
@@ -11,13 +11,43 @@
#ifndef __ASM_ARCH_CLOCK_H
#define __ASM_ARCH_CLOCK_H
+#include <asm/arch-ns9xxx/regs-sys.h>
+
+#define CRYSTAL 29491200 /* Hz */
+
+/* The HRM calls this value f_vco */
static inline u32 ns9xxx_systemclock(void) __attribute__((const));
static inline u32 ns9xxx_systemclock(void)
{
+ u32 pll = SYS_PLL;
+
/*
- * This should be a multiple of HZ * TIMERCLOCKSELECT (in time.c)
+ * The system clock should be a multiple of HZ * TIMERCLOCKSELECT (in
+ * time.c).
+ *
+ * The following values are given:
+ * - TIMERCLOCKSELECT == 2^i for an i in {0 .. 6}
+ * - CRYSTAL == 29491200 == 2^17 * 3^2 * 5^2
+ * - ND in {0 .. 31}
+ * - FS in {0 .. 3}
+ *
+ * Assuming the worst, we consider:
+ * - TIMERCLOCKSELECT == 64
+ * - ND == 0
+ * - FS == 3
+ *
+ * So HZ should be a divisor of:
+ * (CRYSTAL * (ND + 1) >> FS) / TIMERCLOCKSELECT
+ * == (2^17 * 3^2 * 5^2 * 1 >> 3) / 64
+ * == 2^8 * 3^2 * 5^2
+ * == 57600
+ *
+ * Currently HZ is defined to be 100 for this platform.
+ *
+ * Fine.
*/
- return 353894400;
+ return CRYSTAL * (REGGET(pll, SYS_PLL, ND) + 1)
+ >> REGGET(pll, SYS_PLL, FS);
}
static inline u32 ns9xxx_cpuclock(void) __attribute__((const));
diff --git a/include/asm-arm/arch-ns9xxx/hardware.h b/include/asm-arm/arch-ns9xxx/hardware.h
index 6819da7c48d..25600554c4f 100644
--- a/include/asm-arm/arch-ns9xxx/hardware.h
+++ b/include/asm-arm/arch-ns9xxx/hardware.h
@@ -51,8 +51,9 @@
~(__REGVAL(reg ## _ ## field, value)))) \
| (__REGVAL(reg ## _ ## field, value))))
-# define REGGET(reg, field) \
- ((reg & (reg ## _ ## field)) / (field & (-field)))
+# define REGGET(var, reg, field) \
+ ((var & (reg ## _ ## field)) / \
+ ((reg ## _ ## field) & (-(reg ## _ ## field))))
#else
diff --git a/include/asm-arm/arch-ns9xxx/processor.h b/include/asm-arm/arch-ns9xxx/processor.h
index 716c106ac0b..223e51b8e10 100644
--- a/include/asm-arm/arch-ns9xxx/processor.h
+++ b/include/asm-arm/arch-ns9xxx/processor.h
@@ -13,6 +13,7 @@
#include <asm/mach-types.h>
-#define processor_is_ns9360() (machine_is_cc9p9360dev())
+#define processor_is_ns9360() (machine_is_cc9p9360dev() \
+ || machine_is_cc9p9360js())
#endif /* ifndef __ASM_ARCH_PROCESSOR_H */
diff --git a/include/asm-arm/arch-ns9xxx/regs-sys.h b/include/asm-arm/arch-ns9xxx/regs-sys.h
index 8162a50bb27..a42546aeb92 100644
--- a/include/asm-arm/arch-ns9xxx/regs-sys.h
+++ b/include/asm-arm/arch-ns9xxx/regs-sys.h
@@ -48,6 +48,12 @@
/* PLL Configuration register */
#define SYS_PLL __REG(0xa0900188)
+/* PLL FS status */
+#define SYS_PLL_FS __REGBITS(24, 23)
+
+/* PLL ND status */
+#define SYS_PLL_ND __REGBITS(20, 16)
+
/* PLL Configuration register: PLL SW change */
#define SYS_PLL_SWC __REGBIT(15)
#define SYS_PLL_SWC_NO __REGVAL(SYS_PLL_SWC, 0)
diff --git a/include/asm-arm/arch-omap/aic23.h b/include/asm-arm/arch-omap/aic23.h
index 6513065941d..aec2d656362 100644
--- a/include/asm-arm/arch-omap/aic23.h
+++ b/include/asm-arm/arch-omap/aic23.h
@@ -110,7 +110,7 @@
#define TLV320AIC23ID1 (0x1a) // cs low
#define TLV320AIC23ID2 (0x1b) // cs high
-void tlv320aic23_power_up(void);
-void tlv320aic23_power_down(void);
+void aic23_power_up(void);
+void aic23_power_down(void);
#endif /* __ASM_ARCH_AIC23_H */
diff --git a/include/asm-arm/arch-omap/board-apollon.h b/include/asm-arm/arch-omap/board-apollon.h
index de0c5b792c5..dcb587b311f 100644
--- a/include/asm-arm/arch-omap/board-apollon.h
+++ b/include/asm-arm/arch-omap/board-apollon.h
@@ -30,16 +30,7 @@
#define __ASM_ARCH_OMAP_APOLLON_H
/* Placeholder for APOLLON specific defines */
-/* GPMC CS0 */
-#define APOLLON_CS0_BASE 0x00000000
-/* GPMC CS1 */
-#define APOLLON_CS1_BASE 0x08000000
-#define APOLLON_ETHR_START (APOLLON_CS1_BASE + 0x300)
#define APOLLON_ETHR_GPIO_IRQ 74
-/* GPMC CS2 - reserved for OneNAND */
-#define APOLLON_CS2_BASE 0x10000000
-/* GPMC CS3 - reserved for NOR or NAND */
-#define APOLLON_CS3_BASE 0x18000000
#endif /* __ASM_ARCH_OMAP_APOLLON_H */
diff --git a/include/asm-arm/arch-omap/board-h4.h b/include/asm-arm/arch-omap/board-h4.h
index 7ef664bc9e3..7e0efef4bb6 100644
--- a/include/asm-arm/arch-omap/board-h4.h
+++ b/include/asm-arm/arch-omap/board-h4.h
@@ -30,9 +30,6 @@
#define __ASM_ARCH_OMAP_H4_H
/* Placeholder for H4 specific defines */
-/* GPMC CS1 */
-#define OMAP24XX_ETHR_START 0x08000300
#define OMAP24XX_ETHR_GPIO_IRQ 92
-#define H4_CS0_BASE 0x04000000
#endif /* __ASM_ARCH_OMAP_H4_H */
diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h
index edf1dc6ad91..031672c5637 100644
--- a/include/asm-arm/arch-omap/board.h
+++ b/include/asm-arm/arch-omap/board.h
@@ -4,7 +4,7 @@
* Information structures for board-specific data
*
* Copyright (C) 2004 Nokia Corporation
- * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Written by Juha Yrjölä <juha.yrjola@nokia.com>
*/
#ifndef _OMAP_BOARD_H
@@ -12,6 +12,8 @@
#include <linux/types.h>
+#include <asm/arch/gpio-switch.h>
+
/* Different peripheral ids */
#define OMAP_TAG_CLOCK 0x4f01
#define OMAP_TAG_MMC 0x4f02
@@ -99,26 +101,31 @@ struct omap_usb_config {
struct omap_lcd_config {
char panel_name[16];
char ctrl_name[16];
+ s16 nreset_gpio;
+ u8 data_lines;
+};
+
+struct device;
+struct fb_info;
+struct omap_backlight_config {
+ int default_intensity;
+ int (*set_power)(struct device *dev, int state);
+ int (*check_fb)(struct fb_info *fb);
};
struct omap_fbmem_config {
- u32 fb_sram_start;
- u32 fb_sram_size;
- u32 fb_sdram_start;
- u32 fb_sdram_size;
-};
-
-/* Cover:
- * high -> closed
- * low -> open
- * Connection:
- * high -> connected
- * low -> disconnected
- */
-#define OMAP_GPIO_SWITCH_TYPE_COVER 0x0000
-#define OMAP_GPIO_SWITCH_TYPE_CONNECTION 0x0001
-#define OMAP_GPIO_SWITCH_FLAG_INVERTED 0x0001
-#define OMAP_GPIO_SWITCH_FLAG_OUTPUT 0x0002
+ u32 start;
+ u32 size;
+};
+
+struct omap_pwm_led_platform_data {
+ const char *name;
+ int intensity_timer;
+ int blink_timer;
+ void (*set_power)(struct omap_pwm_led_platform_data *self, int on_off);
+};
+
+/* See include/asm-arm/arch-omap/gpio-switch.h for definitions */
struct omap_gpio_switch_config {
char name[12];
u16 gpio;
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index d591d0585bb..f7774192a41 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -2,7 +2,7 @@
* linux/include/asm-arm/arch-omap/dma.h
*
* Copyright (C) 2003 Nokia Corporation
- * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Juha Yrjölä <juha.yrjola@nokia.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
diff --git a/include/asm-arm/arch-omap/dsp.h b/include/asm-arm/arch-omap/dsp.h
deleted file mode 100644
index 06dad83dd41..00000000000
--- a/include/asm-arm/arch-omap/dsp.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * linux/include/asm-arm/arch-omap/dsp.h
- *
- * Header for OMAP DSP driver
- *
- * Copyright (C) 2002-2005 Nokia Corporation
- *
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.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.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * 2005/06/01: DSP Gateway version 3.3
- */
-
-#ifndef ASM_ARCH_DSP_H
-#define ASM_ARCH_DSP_H
-
-
-/*
- * for /dev/dspctl/ctl
- */
-#define OMAP_DSP_IOCTL_RESET 1
-#define OMAP_DSP_IOCTL_RUN 2
-#define OMAP_DSP_IOCTL_SETRSTVECT 3
-#define OMAP_DSP_IOCTL_CPU_IDLE 4
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_ON 5
-#define OMAP_DSP_IOCTL_MPUI_WORDSWAP_OFF 6
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_ON 7
-#define OMAP_DSP_IOCTL_MPUI_BYTESWAP_OFF 8
-#define OMAP_DSP_IOCTL_GBL_IDLE 9
-#define OMAP_DSP_IOCTL_DSPCFG 10
-#define OMAP_DSP_IOCTL_DSPUNCFG 11
-#define OMAP_DSP_IOCTL_TASKCNT 12
-#define OMAP_DSP_IOCTL_POLL 13
-#define OMAP_DSP_IOCTL_REGMEMR 40
-#define OMAP_DSP_IOCTL_REGMEMW 41
-#define OMAP_DSP_IOCTL_REGIOR 42
-#define OMAP_DSP_IOCTL_REGIOW 43
-#define OMAP_DSP_IOCTL_GETVAR 44
-#define OMAP_DSP_IOCTL_SETVAR 45
-#define OMAP_DSP_IOCTL_RUNLEVEL 50
-#define OMAP_DSP_IOCTL_SUSPEND 51
-#define OMAP_DSP_IOCTL_RESUME 52
-#define OMAP_DSP_IOCTL_FBEN 53
-#define OMAP_DSP_IOCTL_FBDIS 54
-#define OMAP_DSP_IOCTL_MBSEND 99
-
-/*
- * for taskdev
- * (ioctls below should be >= 0x10000)
- */
-#define OMAP_DSP_TASK_IOCTL_BFLSH 0x10000
-#define OMAP_DSP_TASK_IOCTL_SETBSZ 0x10001
-#define OMAP_DSP_TASK_IOCTL_LOCK 0x10002
-#define OMAP_DSP_TASK_IOCTL_UNLOCK 0x10003
-#define OMAP_DSP_TASK_IOCTL_GETNAME 0x10004
-
-/*
- * for /dev/dspctl/mem
- */
-#define OMAP_DSP_MEM_IOCTL_EXMAP 1
-#define OMAP_DSP_MEM_IOCTL_EXUNMAP 2
-#define OMAP_DSP_MEM_IOCTL_EXMAP_FLUSH 3
-#define OMAP_DSP_MEM_IOCTL_FBEXPORT 5
-#define OMAP_DSP_MEM_IOCTL_MMUITACK 7
-#define OMAP_DSP_MEM_IOCTL_MMUINIT 9
-#define OMAP_DSP_MEM_IOCTL_KMEM_RESERVE 11
-#define OMAP_DSP_MEM_IOCTL_KMEM_RELEASE 12
-
-struct omap_dsp_mapinfo {
- unsigned long dspadr;
- unsigned long size;
-};
-
-/*
- * for /dev/dspctl/twch
- */
-#define OMAP_DSP_TWCH_IOCTL_MKDEV 1
-#define OMAP_DSP_TWCH_IOCTL_RMDEV 2
-#define OMAP_DSP_TWCH_IOCTL_TADD 11
-#define OMAP_DSP_TWCH_IOCTL_TDEL 12
-#define OMAP_DSP_TWCH_IOCTL_TKILL 13
-
-#define OMAP_DSP_DEVSTATE_NOTASK 0x00000001
-#define OMAP_DSP_DEVSTATE_ATTACHED 0x00000002
-#define OMAP_DSP_DEVSTATE_GARBAGE 0x00000004
-#define OMAP_DSP_DEVSTATE_INVALID 0x00000008
-#define OMAP_DSP_DEVSTATE_ADDREQ 0x00000100
-#define OMAP_DSP_DEVSTATE_DELREQ 0x00000200
-#define OMAP_DSP_DEVSTATE_ADDFAIL 0x00001000
-#define OMAP_DSP_DEVSTATE_ADDING 0x00010000
-#define OMAP_DSP_DEVSTATE_DELING 0x00020000
-#define OMAP_DSP_DEVSTATE_KILLING 0x00040000
-#define OMAP_DSP_DEVSTATE_STATE_MASK 0x7fffffff
-#define OMAP_DSP_DEVSTATE_STALE 0x80000000
-
-struct omap_dsp_taddinfo {
- unsigned char minor;
- unsigned long taskadr;
-};
-#define OMAP_DSP_TADD_ABORTADR 0xffffffff
-
-
-/*
- * error cause definition (for error detection device)
- */
-#define OMAP_DSP_ERRDT_WDT 0x00000001
-#define OMAP_DSP_ERRDT_MMU 0x00000002
-
-
-/*
- * mailbox protocol definitions
- */
-
-struct omap_dsp_mailbox_cmd {
- unsigned short cmd;
- unsigned short data;
-};
-
-struct omap_dsp_reginfo {
- unsigned short adr;
- unsigned short val;
-};
-
-struct omap_dsp_varinfo {
- unsigned char varid;
- unsigned short val[0];
-};
-
-#define OMAP_DSP_MBPROT_REVISION 0x0019
-
-#define OMAP_DSP_MBCMD_WDSND 0x10
-#define OMAP_DSP_MBCMD_WDREQ 0x11
-#define OMAP_DSP_MBCMD_BKSND 0x20
-#define OMAP_DSP_MBCMD_BKREQ 0x21
-#define OMAP_DSP_MBCMD_BKYLD 0x23
-#define OMAP_DSP_MBCMD_BKSNDP 0x24
-#define OMAP_DSP_MBCMD_BKREQP 0x25
-#define OMAP_DSP_MBCMD_TCTL 0x30
-#define OMAP_DSP_MBCMD_TCTLDATA 0x31
-#define OMAP_DSP_MBCMD_POLL 0x32
-#define OMAP_DSP_MBCMD_WDT 0x50 /* v3.3: obsolete */
-#define OMAP_DSP_MBCMD_RUNLEVEL 0x51
-#define OMAP_DSP_MBCMD_PM 0x52
-#define OMAP_DSP_MBCMD_SUSPEND 0x53
-#define OMAP_DSP_MBCMD_KFUNC 0x54
-#define OMAP_DSP_MBCMD_TCFG 0x60
-#define OMAP_DSP_MBCMD_TADD 0x62
-#define OMAP_DSP_MBCMD_TDEL 0x63
-#define OMAP_DSP_MBCMD_TSTOP 0x65
-#define OMAP_DSP_MBCMD_DSPCFG 0x70
-#define OMAP_DSP_MBCMD_REGRW 0x72
-#define OMAP_DSP_MBCMD_GETVAR 0x74
-#define OMAP_DSP_MBCMD_SETVAR 0x75
-#define OMAP_DSP_MBCMD_ERR 0x78
-#define OMAP_DSP_MBCMD_DBG 0x79
-
-#define OMAP_DSP_MBCMD_TCTL_TINIT 0x0000
-#define OMAP_DSP_MBCMD_TCTL_TEN 0x0001
-#define OMAP_DSP_MBCMD_TCTL_TDIS 0x0002
-#define OMAP_DSP_MBCMD_TCTL_TCLR 0x0003
-#define OMAP_DSP_MBCMD_TCTL_TCLR_FORCE 0x0004
-
-#define OMAP_DSP_MBCMD_RUNLEVEL_USER 0x01
-#define OMAP_DSP_MBCMD_RUNLEVEL_SUPER 0x0e
-#define OMAP_DSP_MBCMD_RUNLEVEL_RECOVERY 0x10
-
-#define OMAP_DSP_MBCMD_PM_DISABLE 0x00
-#define OMAP_DSP_MBCMD_PM_ENABLE 0x01
-
-#define OMAP_DSP_MBCMD_KFUNC_FBCTL 0x00
-#define OMAP_DSP_MBCMD_KFUNC_AUDIO_PWR 0x01
-
-#define OMAP_DSP_MBCMD_FBCTL_UPD 0x0000
-#define OMAP_DSP_MBCMD_FBCTL_ENABLE 0x0002
-#define OMAP_DSP_MBCMD_FBCTL_DISABLE 0x0003
-
-#define OMAP_DSP_MBCMD_AUDIO_PWR_UP 0x0000
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN1 0x0001
-#define OMAP_DSP_MBCMD_AUDIO_PWR_DOWN2 0x0002
-
-#define OMAP_DSP_MBCMD_TDEL_SAFE 0x0000
-#define OMAP_DSP_MBCMD_TDEL_KILL 0x0001
-
-#define OMAP_DSP_MBCMD_DSPCFG_REQ 0x00
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRH 0x28
-#define OMAP_DSP_MBCMD_DSPCFG_SYSADRL 0x29
-#define OMAP_DSP_MBCMD_DSPCFG_PROTREV 0x70
-#define OMAP_DSP_MBCMD_DSPCFG_ABORT 0x78
-#define OMAP_DSP_MBCMD_DSPCFG_LAST 0x80
-
-#define OMAP_DSP_MBCMD_REGRW_MEMR 0x00
-#define OMAP_DSP_MBCMD_REGRW_MEMW 0x01
-#define OMAP_DSP_MBCMD_REGRW_IOR 0x02
-#define OMAP_DSP_MBCMD_REGRW_IOW 0x03
-#define OMAP_DSP_MBCMD_REGRW_DATA 0x04
-
-#define OMAP_DSP_MBCMD_VARID_ICRMASK 0x00
-#define OMAP_DSP_MBCMD_VARID_LOADINFO 0x01
-
-#define OMAP_DSP_TTYP_ARCV 0x0001
-#define OMAP_DSP_TTYP_ASND 0x0002
-#define OMAP_DSP_TTYP_BKMD 0x0004
-#define OMAP_DSP_TTYP_BKDM 0x0008
-#define OMAP_DSP_TTYP_PVMD 0x0010
-#define OMAP_DSP_TTYP_PVDM 0x0020
-
-#define OMAP_DSP_EID_BADTID 0x10
-#define OMAP_DSP_EID_BADTCN 0x11
-#define OMAP_DSP_EID_BADBID 0x20
-#define OMAP_DSP_EID_BADCNT 0x21
-#define OMAP_DSP_EID_NOTLOCKED 0x22
-#define OMAP_DSP_EID_STVBUF 0x23
-#define OMAP_DSP_EID_BADADR 0x24
-#define OMAP_DSP_EID_BADTCTL 0x30
-#define OMAP_DSP_EID_BADPARAM 0x50
-#define OMAP_DSP_EID_FATAL 0x58
-#define OMAP_DSP_EID_NOMEM 0xc0
-#define OMAP_DSP_EID_NORES 0xc1
-#define OMAP_DSP_EID_IPBFULL 0xc2
-#define OMAP_DSP_EID_WDT 0xd0
-#define OMAP_DSP_EID_TASKNOTRDY 0xe0
-#define OMAP_DSP_EID_TASKBSY 0xe1
-#define OMAP_DSP_EID_TASKERR 0xef
-#define OMAP_DSP_EID_BADCFGTYP 0xf0
-#define OMAP_DSP_EID_DEBUG 0xf8
-#define OMAP_DSP_EID_BADSEQ 0xfe
-#define OMAP_DSP_EID_BADCMD 0xff
-
-#define OMAP_DSP_TNM_LEN 16
-
-#define OMAP_DSP_TID_FREE 0xff
-#define OMAP_DSP_TID_ANON 0xfe
-
-#define OMAP_DSP_BID_NULL 0xffff
-#define OMAP_DSP_BID_PVT 0xfffe
-
-#endif /* ASM_ARCH_DSP_H */
diff --git a/include/asm-arm/arch-omap/dsp_common.h b/include/asm-arm/arch-omap/dsp_common.h
index 16a459dfa71..c61f868f24e 100644
--- a/include/asm-arm/arch-omap/dsp_common.h
+++ b/include/asm-arm/arch-omap/dsp_common.h
@@ -1,38 +1,34 @@
/*
- * linux/include/asm-arm/arch-omap/dsp_common.h
+ * This file is part of OMAP DSP driver (DSP Gateway version 3.3.1)
*
- * Header for OMAP DSP subsystem control
+ * Copyright (C) 2004-2006 Nokia Corporation. All rights reserved.
*
- * Copyright (C) 2004,2005 Nokia Corporation
+ * Contact: Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
*
- * Written by Toshihiro Kobayashi <toshihiro.kobayashi@nokia.com>
+ * 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.
*
- * 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.
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
*
- * 2005/06/03: DSP Gateway version 3.3
*/
#ifndef ASM_ARCH_DSP_COMMON_H
#define ASM_ARCH_DSP_COMMON_H
+#ifdef CONFIG_ARCH_OMAP1
extern void omap_dsp_request_mpui(void);
extern void omap_dsp_release_mpui(void);
extern int omap_dsp_request_mem(void);
extern int omap_dsp_release_mem(void);
-
-extern void (*omap_dsp_audio_pwr_up_request)(int stage);
-extern void (*omap_dsp_audio_pwr_down_request)(int stage);
+#endif
#endif /* ASM_ARCH_DSP_COMMON_H */
diff --git a/include/asm-arm/arch-omap/gpio-switch.h b/include/asm-arm/arch-omap/gpio-switch.h
new file mode 100644
index 00000000000..10da0e07c0c
--- /dev/null
+++ b/include/asm-arm/arch-omap/gpio-switch.h
@@ -0,0 +1,54 @@
+/*
+ * GPIO switch definitions
+ *
+ * Copyright (C) 2006 Nokia Corporation
+ *
+ * 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.
+ */
+
+#ifndef __ASM_ARCH_OMAP_GPIO_SWITCH_H
+#define __ASM_ARCH_OMAP_GPIO_SWITCH_H
+
+#include <linux/types.h>
+
+/* Cover:
+ * high -> closed
+ * low -> open
+ * Connection:
+ * high -> connected
+ * low -> disconnected
+ * Activity:
+ * high -> active
+ * low -> inactive
+ *
+ */
+#define OMAP_GPIO_SWITCH_TYPE_COVER 0x0000
+#define OMAP_GPIO_SWITCH_TYPE_CONNECTION 0x0001
+#define OMAP_GPIO_SWITCH_TYPE_ACTIVITY 0x0002
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED 0x0001
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT 0x0002
+
+struct omap_gpio_switch {
+ const char *name;
+ s16 gpio;
+ unsigned flags:4;
+ unsigned type:4;
+
+ /* Time in ms to debounce when transitioning from
+ * inactive state to active state. */
+ u16 debounce_rising;
+ /* Same for transition from active to inactive state. */
+ u16 debounce_falling;
+
+ /* notify board-specific code about state changes */
+ void (* notify)(void *data, int state);
+ void *notify_data;
+};
+
+/* Call at init time only */
+extern void omap_register_gpio_switches(const struct omap_gpio_switch *tbl,
+ int count);
+
+#endif
diff --git a/include/asm-arm/arch-omap/gpio.h b/include/asm-arm/arch-omap/gpio.h
index 590917efc94..97b397dd7e8 100644
--- a/include/asm-arm/arch-omap/gpio.h
+++ b/include/asm-arm/arch-omap/gpio.h
@@ -5,7 +5,7 @@
*
* Copyright (C) 2003-2005 Nokia Corporation
*
- * Written by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Written by Juha Yrjölä <juha.yrjola@nokia.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
diff --git a/include/asm-arm/arch-omap/gpmc.h b/include/asm-arm/arch-omap/gpmc.h
index 7c03ef6c14c..995cc83482e 100644
--- a/include/asm-arm/arch-omap/gpmc.h
+++ b/include/asm-arm/arch-omap/gpmc.h
@@ -87,5 +87,7 @@ extern int gpmc_cs_calc_divider(int cs, unsigned int sync_clk);
extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
extern void gpmc_cs_free(int cs);
+extern int gpmc_cs_set_reserved(int cs, int reserved);
+extern int gpmc_cs_reserved(int cs);
#endif
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 481048d6521..e225f4f39b3 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -267,6 +267,15 @@
#define OMAP_LPG2_PMR (OMAP_LPG2_BASE + 0x04)
/*
+ * ----------------------------------------------------------------------------
+ * Pulse-Width Light
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_PWL_BASE 0xfffb5800
+#define OMAP_PWL_ENABLE (OMAP_PWL_BASE + 0x00)
+#define OMAP_PWL_CLK_ENABLE (OMAP_PWL_BASE + 0x04)
+
+/*
* ---------------------------------------------------------------------------
* Processor specific defines
* ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/hwa742.h b/include/asm-arm/arch-omap/hwa742.h
new file mode 100644
index 00000000000..577f492f2d3
--- /dev/null
+++ b/include/asm-arm/arch-omap/hwa742.h
@@ -0,0 +1,12 @@
+#ifndef _HWA742_H
+#define _HWA742_H
+
+struct hwa742_platform_data {
+ void (*power_up)(struct device *dev);
+ void (*power_down)(struct device *dev);
+ unsigned long (*get_clock_rate)(struct device *dev);
+
+ unsigned te_connected:1;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/io.h b/include/asm-arm/arch-omap/io.h
index 78f68e6a4f0..4aca7e3d756 100644
--- a/include/asm-arm/arch-omap/io.h
+++ b/include/asm-arm/arch-omap/io.h
@@ -77,6 +77,17 @@
#define io_p2v(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */
#define io_v2p(va) ((va) - IO_OFFSET) /* Works for L3 and L4 */
+/* DSP */
+#define DSP_MEM_24XX_PHYS OMAP24XX_DSP_MEM_BASE /* 0x58000000 */
+#define DSP_MEM_24XX_VIRT 0xe0000000
+#define DSP_MEM_24XX_SIZE 0x28000
+#define DSP_IPI_24XX_PHYS OMAP24XX_DSP_IPI_BASE /* 0x59000000 */
+#define DSP_IPI_24XX_VIRT 0xe1000000
+#define DSP_IPI_24XX_SIZE SZ_4K
+#define DSP_MMU_24XX_PHYS OMAP24XX_DSP_MMU_BASE /* 0x5a000000 */
+#define DSP_MMU_24XX_VIRT 0xe2000000
+#define DSP_MMU_24XX_SIZE SZ_4K
+
#endif
#ifndef __ASSEMBLER__
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index c5bb05a69b8..3ede58b51db 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -37,8 +37,6 @@
#define INT_DSP_MMU_ABORT 7
#define INT_HOST 8
#define INT_ABORT 9
-#define INT_DSP_MAILBOX1 10
-#define INT_DSP_MAILBOX2 11
#define INT_BRIDGE_PRIV 13
#define INT_GPIO_BANK1 14
#define INT_UART3 15
@@ -63,6 +61,8 @@
#define INT_1510_RES2 2
#define INT_1510_SPI_TX 4
#define INT_1510_SPI_RX 5
+#define INT_1510_DSP_MAILBOX1 10
+#define INT_1510_DSP_MAILBOX2 11
#define INT_1510_RES12 12
#define INT_1510_LB_MMU 17
#define INT_1510_RES18 18
@@ -75,6 +75,8 @@
#define INT_1610_IH2_FIQ 2
#define INT_1610_McBSP2_TX 4
#define INT_1610_McBSP2_RX 5
+#define INT_1610_DSP_MAILBOX1 10
+#define INT_1610_DSP_MAILBOX2 11
#define INT_1610_LCD_LINE 12
#define INT_1610_GPTIMER1 17
#define INT_1610_GPTIMER2 18
@@ -131,11 +133,11 @@
#define INT_RTC_TIMER (25 + IH2_BASE)
#define INT_RTC_ALARM (26 + IH2_BASE)
#define INT_MEM_STICK (27 + IH2_BASE)
-#define INT_DSP_MMU (28 + IH2_BASE)
/*
* OMAP-1510 specific IRQ numbers for interrupt handler 2
*/
+#define INT_1510_DSP_MMU (28 + IH2_BASE)
#define INT_1510_COM_SPI_RO (31 + IH2_BASE)
/*
@@ -146,6 +148,7 @@
#define INT_1610_USB_OTG (8 + IH2_BASE)
#define INT_1610_SoSSI (9 + IH2_BASE)
#define INT_1610_SoSSI_MATCH (19 + IH2_BASE)
+#define INT_1610_DSP_MMU (28 + IH2_BASE)
#define INT_1610_McBSP2RX_OF (31 + IH2_BASE)
#define INT_1610_STI (32 + IH2_BASE)
#define INT_1610_STI_WAKEUP (33 + IH2_BASE)
@@ -239,10 +242,15 @@
#define INT_24XX_SDMA_IRQ3 15
#define INT_24XX_CAM_IRQ 24
#define INT_24XX_DSS_IRQ 25
+#define INT_24XX_MAIL_U0_MPU 26
+#define INT_24XX_DSP_UMA 27
+#define INT_24XX_DSP_MMU 28
#define INT_24XX_GPIO_BANK1 29
#define INT_24XX_GPIO_BANK2 30
#define INT_24XX_GPIO_BANK3 31
#define INT_24XX_GPIO_BANK4 32
+#define INT_24XX_GPIO_BANK5 33
+#define INT_24XX_MAIL_U3_MPU 34
#define INT_24XX_GPTIMER1 37
#define INT_24XX_GPTIMER2 38
#define INT_24XX_GPTIMER3 39
@@ -262,6 +270,12 @@
#define INT_24XX_UART1_IRQ 72
#define INT_24XX_UART2_IRQ 73
#define INT_24XX_UART3_IRQ 74
+#define INT_24XX_USB_IRQ_GEN 75
+#define INT_24XX_USB_IRQ_NISO 76
+#define INT_24XX_USB_IRQ_ISO 77
+#define INT_24XX_USB_IRQ_HGEN 78
+#define INT_24XX_USB_IRQ_HSOF 79
+#define INT_24XX_USB_IRQ_OTG 80
#define INT_24XX_MMC_IRQ 83
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
diff --git a/include/asm-arm/arch-omap/lcd_lph8923.h b/include/asm-arm/arch-omap/lcd_lph8923.h
deleted file mode 100644
index 004e67e22ca..00000000000
--- a/include/asm-arm/arch-omap/lcd_lph8923.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LCD_LPH8923_H
-#define __LCD_LPH8923_H
-
-enum lcd_lph8923_test_num {
- LCD_LPH8923_TEST_RGB_LINES,
-};
-
-enum lcd_lph8923_test_result {
- LCD_LPH8923_TEST_SUCCESS,
- LCD_LPH8923_TEST_INVALID,
- LCD_LPH8923_TEST_FAILED,
-};
-
-#endif
diff --git a/include/asm-arm/arch-omap/lcd_mipid.h b/include/asm-arm/arch-omap/lcd_mipid.h
new file mode 100644
index 00000000000..f8fbc4801e5
--- /dev/null
+++ b/include/asm-arm/arch-omap/lcd_mipid.h
@@ -0,0 +1,24 @@
+#ifndef __LCD_MIPID_H
+#define __LCD_MIPID_H
+
+enum mipid_test_num {
+ MIPID_TEST_RGB_LINES,
+};
+
+enum mipid_test_result {
+ MIPID_TEST_SUCCESS,
+ MIPID_TEST_INVALID,
+ MIPID_TEST_FAILED,
+};
+
+#ifdef __KERNEL__
+
+struct mipid_platform_data {
+ int nreset_gpio;
+ int data_lines;
+ void (*shutdown)(struct mipid_platform_data *pdata);
+};
+
+#endif
+
+#endif
diff --git a/include/asm-arm/arch-omap/led.h b/include/asm-arm/arch-omap/led.h
new file mode 100644
index 00000000000..f3acae28e2d
--- /dev/null
+++ b/include/asm-arm/arch-omap/led.h
@@ -0,0 +1,24 @@
+/*
+ * linux/include/asm-arm/arch-omap/led.h
+ *
+ * Copyright (C) 2006 Samsung Electronics
+ * Kyungmin Park <kyungmin.park@samsung.com>
+ *
+ * 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.
+ */
+#ifndef ASMARM_ARCH_LED_H
+#define ASMARM_ARCH_LED_H
+
+struct omap_led_config {
+ struct led_classdev cdev;
+ s16 gpio;
+};
+
+struct omap_led_platform_data {
+ s16 nr_leds;
+ struct omap_led_config *leds;
+};
+
+#endif
diff --git a/include/asm-arm/arch-omap/mailbox.h b/include/asm-arm/arch-omap/mailbox.h
new file mode 100644
index 00000000000..4bf0909461f
--- /dev/null
+++ b/include/asm-arm/arch-omap/mailbox.h
@@ -0,0 +1,73 @@
+/* mailbox.h */
+
+#ifndef MAILBOX_H
+#define MAILBOX_H
+
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/blkdev.h>
+
+typedef u32 mbox_msg_t;
+typedef void (mbox_receiver_t)(mbox_msg_t msg);
+struct omap_mbox;
+
+typedef int __bitwise omap_mbox_irq_t;
+#define IRQ_TX ((__force omap_mbox_irq_t) 1)
+#define IRQ_RX ((__force omap_mbox_irq_t) 2)
+
+typedef int __bitwise omap_mbox_type_t;
+#define OMAP_MBOX_TYPE1 ((__force omap_mbox_type_t) 1)
+#define OMAP_MBOX_TYPE2 ((__force omap_mbox_type_t) 2)
+
+struct omap_mbox_ops {
+ omap_mbox_type_t type;
+ int (*startup)(struct omap_mbox *mbox);
+ void (*shutdown)(struct omap_mbox *mbox);
+ /* fifo */
+ mbox_msg_t (*fifo_read)(struct omap_mbox *mbox);
+ void (*fifo_write)(struct omap_mbox *mbox, mbox_msg_t msg);
+ int (*fifo_empty)(struct omap_mbox *mbox);
+ int (*fifo_full)(struct omap_mbox *mbox);
+ /* irq */
+ void (*enable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+ void (*disable_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+ void (*ack_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+ int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+};
+
+struct omap_mbox_queue {
+ spinlock_t lock;
+ request_queue_t *queue;
+ struct work_struct work;
+ int (*callback)(void *);
+ struct omap_mbox *mbox;
+};
+
+struct omap_mbox {
+ char *name;
+ unsigned int irq;
+
+ struct omap_mbox_queue *txq, *rxq;
+
+ struct omap_mbox_ops *ops;
+
+ mbox_msg_t seq_snd, seq_rcv;
+
+ struct device dev;
+
+ struct omap_mbox *next;
+ void *priv;
+
+ void (*err_notify)(void);
+};
+
+int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg, void *);
+void omap_mbox_init_seq(struct omap_mbox *);
+
+struct omap_mbox *omap_mbox_get(const char *);
+void omap_mbox_put(struct omap_mbox *);
+
+int omap_mbox_register(struct omap_mbox *);
+int omap_mbox_unregister(struct omap_mbox *);
+
+#endif /* MAILBOX_H */
diff --git a/include/asm-arm/arch-omap/mcspi.h b/include/asm-arm/arch-omap/mcspi.h
index 9e7f40a88e1..1254e4945b6 100644
--- a/include/asm-arm/arch-omap/mcspi.h
+++ b/include/asm-arm/arch-omap/mcspi.h
@@ -2,7 +2,6 @@
#define _OMAP2_MCSPI_H
struct omap2_mcspi_platform_config {
- unsigned long base;
unsigned short num_cs;
};
diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h
index 48fabc49316..14cba97c18a 100644
--- a/include/asm-arm/arch-omap/memory.h
+++ b/include/asm-arm/arch-omap/memory.h
@@ -86,5 +86,18 @@
#endif /* CONFIG_ARCH_OMAP15XX */
+/* Override the ARM default */
+#ifdef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+
+#if (CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE == 0)
+#undef CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE
+#define CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE 2
+#endif
+
+#define CONSISTENT_DMA_SIZE \
+ (((CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE + 1) & ~1) * 1024 * 1024)
+
+#endif
+
#endif
diff --git a/include/asm-arm/arch-omap/menelaus.h b/include/asm-arm/arch-omap/menelaus.h
index 88cd4c87f0d..82d276a6bd9 100644
--- a/include/asm-arm/arch-omap/menelaus.h
+++ b/include/asm-arm/arch-omap/menelaus.h
@@ -7,10 +7,19 @@
#ifndef __ASM_ARCH_MENELAUS_H
#define __ASM_ARCH_MENELAUS_H
-extern void menelaus_mmc_register(void (*callback)(unsigned long data, u8 card_mask),
- unsigned long data);
-extern void menelaus_mmc_remove(void);
-extern void menelaus_mmc_opendrain(int enable);
+extern int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
+ void *data);
+extern void menelaus_unregister_mmc_callback(void);
+extern int menelaus_set_mmc_opendrain(int slot, int enable);
+extern int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_on);
+
+extern int menelaus_set_vmem(unsigned int mV);
+extern int menelaus_set_vio(unsigned int mV);
+extern int menelaus_set_vmmc(unsigned int mV);
+extern int menelaus_set_vaux(unsigned int mV);
+extern int menelaus_set_vdcdc(int dcdc, unsigned int mV);
+extern int menelaus_set_slot_sel(int enable);
+extern int menelaus_get_slot_pin_states(void);
#if defined(CONFIG_ARCH_OMAP24XX) && defined(CONFIG_MENELAUS)
#define omap_has_menelaus() 1
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
index f0c7f0fb4dc..f7f5cdfdccc 100644
--- a/include/asm-arm/arch-omap/omap16xx.h
+++ b/include/asm-arm/arch-omap/omap16xx.h
@@ -159,15 +159,6 @@
#define UART3_MVR (OMAP_UART3_BASE + 0x50)
/*
- * ----------------------------------------------------------------------------
- * Pulse-Width Light
- * ----------------------------------------------------------------------------
- */
-#define OMAP16XX_PWL_BASE (0xfffb5800)
-#define OMAP16XX_PWL_ENABLE (OMAP16XX_PWL_BASE + 0x00)
-#define OMAP16XX_PWL_CLK_ENABLE (OMAP16XX_PWL_BASE + 0x04)
-
-/*
* ---------------------------------------------------------------------------
* Watchdog timer
* ---------------------------------------------------------------------------
@@ -199,5 +190,8 @@
#define WSPR_DISABLE_0 (0x0000aaaa)
#define WSPR_DISABLE_1 (0x00005555)
+/* Mailbox */
+#define OMAP16XX_MAILBOX_BASE (0xfffcf000)
+
#endif /* __ASM_ARCH_OMAP16XX_H */
diff --git a/include/asm-arm/arch-omap/omap24xx.h b/include/asm-arm/arch-omap/omap24xx.h
index 6e59805fa65..708b2fac77f 100644
--- a/include/asm-arm/arch-omap/omap24xx.h
+++ b/include/asm-arm/arch-omap/omap24xx.h
@@ -20,5 +20,14 @@
#define OMAP24XX_PRCM_BASE (L4_24XX_BASE + 0x8000)
#define OMAP24XX_SDRC_BASE (L3_24XX_BASE + 0x9000)
+/* DSP SS */
+#define OMAP24XX_DSP_BASE 0x58000000
+#define OMAP24XX_DSP_MEM_BASE (OMAP24XX_DSP_BASE + 0x0)
+#define OMAP24XX_DSP_IPI_BASE (OMAP24XX_DSP_BASE + 0x1000000)
+#define OMAP24XX_DSP_MMU_BASE (OMAP24XX_DSP_BASE + 0x2000000)
+
+/* Mailbox */
+#define OMAP24XX_MAILBOX_BASE (L4_24XX_BASE + 0x94000)
+
#endif /* __ASM_ARCH_OMAP24XX_H */
diff --git a/include/asm-arm/arch-omap/omapfb.h b/include/asm-arm/arch-omap/omapfb.h
index fccdb3db025..46d7a4f6085 100644
--- a/include/asm-arm/arch-omap/omapfb.h
+++ b/include/asm-arm/arch-omap/omapfb.h
@@ -24,6 +24,9 @@
#ifndef __OMAPFB_H
#define __OMAPFB_H
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
/* IOCTL commands. */
#define OMAP_IOW(num, dtype) _IOW('O', num, dtype)
@@ -35,26 +38,46 @@
#define OMAPFB_SYNC_GFX OMAP_IO(37)
#define OMAPFB_VSYNC OMAP_IO(38)
#define OMAPFB_SET_UPDATE_MODE OMAP_IOW(40, int)
-#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(41, struct omapfb_update_window_old)
-#define OMAPFB_GET_CAPS OMAP_IOR(42, unsigned long)
+#define OMAPFB_GET_CAPS OMAP_IOR(42, struct omapfb_caps)
#define OMAPFB_GET_UPDATE_MODE OMAP_IOW(43, int)
#define OMAPFB_LCD_TEST OMAP_IOW(45, int)
#define OMAPFB_CTRL_TEST OMAP_IOW(46, int)
-#define OMAPFB_UPDATE_WINDOW OMAP_IOW(47, struct omapfb_update_window)
-#define OMAPFB_SETUP_PLANE OMAP_IOW(48, struct omapfb_setup_plane)
-#define OMAPFB_ENABLE_PLANE OMAP_IOW(49, struct omapfb_enable_plane)
+#define OMAPFB_UPDATE_WINDOW_OLD OMAP_IOW(47, struct omapfb_update_window_old)
#define OMAPFB_SET_COLOR_KEY OMAP_IOW(50, struct omapfb_color_key)
+#define OMAPFB_GET_COLOR_KEY OMAP_IOW(51, struct omapfb_color_key)
+#define OMAPFB_SETUP_PLANE OMAP_IOW(52, struct omapfb_plane_info)
+#define OMAPFB_QUERY_PLANE OMAP_IOW(53, struct omapfb_plane_info)
+#define OMAPFB_UPDATE_WINDOW OMAP_IOW(54, struct omapfb_update_window)
+#define OMAPFB_SETUP_MEM OMAP_IOW(55, struct omapfb_mem_info)
+#define OMAPFB_QUERY_MEM OMAP_IOW(56, struct omapfb_mem_info)
#define OMAPFB_CAPS_GENERIC_MASK 0x00000fff
#define OMAPFB_CAPS_LCDC_MASK 0x00fff000
#define OMAPFB_CAPS_PANEL_MASK 0xff000000
#define OMAPFB_CAPS_MANUAL_UPDATE 0x00001000
+#define OMAPFB_CAPS_TEARSYNC 0x00002000
+#define OMAPFB_CAPS_PLANE_RELOCATE_MEM 0x00004000
+#define OMAPFB_CAPS_PLANE_SCALE 0x00008000
+#define OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE 0x00010000
+#define OMAPFB_CAPS_WINDOW_SCALE 0x00020000
+#define OMAPFB_CAPS_WINDOW_OVERLAY 0x00040000
#define OMAPFB_CAPS_SET_BACKLIGHT 0x01000000
/* Values from DSP must map to lower 16-bits */
-#define OMAPFB_FORMAT_MASK 0x00ff
-#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
+#define OMAPFB_FORMAT_MASK 0x00ff
+#define OMAPFB_FORMAT_FLAG_DOUBLE 0x0100
+#define OMAPFB_FORMAT_FLAG_TEARSYNC 0x0200
+#define OMAPFB_FORMAT_FLAG_FORCE_VSYNC 0x0400
+#define OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY 0x0800
+#define OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY 0x1000
+
+#define OMAPFB_EVENT_READY 1
+#define OMAPFB_EVENT_DISABLED 2
+
+#define OMAPFB_MEMTYPE_SDRAM 0
+#define OMAPFB_MEMTYPE_SRAM 1
+#define OMAPFB_MEMTYPE_MAX 1
enum omapfb_color_format {
OMAPFB_COLOR_RGB565 = 0,
@@ -64,17 +87,23 @@ enum omapfb_color_format {
OMAPFB_COLOR_CLUT_4BPP,
OMAPFB_COLOR_CLUT_2BPP,
OMAPFB_COLOR_CLUT_1BPP,
+ OMAPFB_COLOR_RGB444,
+ OMAPFB_COLOR_YUY422,
};
struct omapfb_update_window {
__u32 x, y;
__u32 width, height;
__u32 format;
+ __u32 out_x, out_y;
+ __u32 out_width, out_height;
+ __u32 reserved[8];
};
struct omapfb_update_window_old {
__u32 x, y;
__u32 width, height;
+ __u32 format;
};
enum omapfb_plane {
@@ -88,18 +117,28 @@ enum omapfb_channel_out {
OMAPFB_CHANNEL_OUT_DIGIT,
};
-struct omapfb_setup_plane {
- __u8 plane;
+struct omapfb_plane_info {
+ __u32 pos_x;
+ __u32 pos_y;
+ __u8 enabled;
__u8 channel_out;
- __u32 offset;
- __u32 pos_x, pos_y;
- __u32 width, height;
- __u32 color_mode;
+ __u8 mirror;
+ __u8 reserved1;
+ __u32 out_width;
+ __u32 out_height;
+ __u32 reserved2[12];
};
-struct omapfb_enable_plane {
- __u8 plane;
- __u8 enable;
+struct omapfb_mem_info {
+ __u32 size;
+ __u8 type;
+ __u8 reserved[3];
+};
+
+struct omapfb_caps {
+ __u32 ctrl;
+ __u32 plane_color;
+ __u32 wnd_color;
};
enum omapfb_color_key_type {
@@ -141,6 +180,9 @@ enum omapfb_update_mode {
#define OMAP_LCDC_PANEL_TFT 0x0100
+#define OMAPFB_PLANE_XRES_MIN 8
+#define OMAPFB_PLANE_YRES_MIN 8
+
#ifdef CONFIG_ARCH_OMAP1
#define OMAPFB_PLANE_NUM 1
#else
@@ -169,19 +211,19 @@ struct lcd_panel {
int pcd; /* pixel clock divider.
Obsolete use pixel_clock instead */
- int (*init) (struct omapfb_device *fbdev);
- void (*cleanup) (void);
- int (*enable) (void);
- void (*disable) (void);
- unsigned long (*get_caps) (void);
- int (*set_bklight_level)(unsigned int level);
- unsigned int (*get_bklight_level)(void);
- unsigned int (*get_bklight_max) (void);
- int (*run_test) (int test_num);
+ int (*init) (struct lcd_panel *panel,
+ struct omapfb_device *fbdev);
+ void (*cleanup) (struct lcd_panel *panel);
+ int (*enable) (struct lcd_panel *panel);
+ void (*disable) (struct lcd_panel *panel);
+ unsigned long (*get_caps) (struct lcd_panel *panel);
+ int (*set_bklight_level)(struct lcd_panel *panel,
+ unsigned int level);
+ unsigned int (*get_bklight_level)(struct lcd_panel *panel);
+ unsigned int (*get_bklight_max) (struct lcd_panel *panel);
+ int (*run_test) (struct lcd_panel *panel, int test_num);
};
-struct omapfb_device;
-
struct extif_timings {
int cs_on_time;
int cs_off_time;
@@ -202,9 +244,10 @@ struct extif_timings {
};
struct lcd_ctrl_extif {
- int (*init) (void);
+ int (*init) (struct omapfb_device *fbdev);
void (*cleanup) (void);
void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div);
+ unsigned long (*get_max_tx_rate)(void);
int (*convert_timings) (struct extif_timings *timings);
void (*set_timings) (const struct extif_timings *timings);
void (*set_bits_per_cycle)(int bpc);
@@ -213,31 +256,48 @@ struct lcd_ctrl_extif {
void (*write_data) (const void *buf, unsigned int len);
void (*transfer_area) (int width, int height,
void (callback)(void * data), void *data);
+ int (*setup_tearsync) (unsigned pin_cnt,
+ unsigned hs_pulse_time, unsigned vs_pulse_time,
+ int hs_pol_inv, int vs_pol_inv, int div);
+ int (*enable_tearsync) (int enable, unsigned line);
+
unsigned long max_transmit_size;
};
struct omapfb_notifier_block {
struct notifier_block nb;
void *data;
+ int plane_idx;
};
-typedef int (*omapfb_notifier_callback_t)(struct omapfb_notifier_block *,
- unsigned long event,
- struct omapfb_device *fbdev);
+typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
+ unsigned long event,
+ void *fbi);
+
+struct omapfb_mem_region {
+ dma_addr_t paddr;
+ void *vaddr;
+ unsigned long size;
+ u8 type; /* OMAPFB_PLANE_MEM_* */
+ unsigned alloc:1; /* allocated by the driver */
+ unsigned map:1; /* kernel mapped by the driver */
+};
+
+struct omapfb_mem_desc {
+ int region_cnt;
+ struct omapfb_mem_region region[OMAPFB_PLANE_NUM];
+};
struct lcd_ctrl {
const char *name;
void *data;
int (*init) (struct omapfb_device *fbdev,
- int ext_mode, int req_vram_size);
+ int ext_mode,
+ struct omapfb_mem_desc *req_md);
void (*cleanup) (void);
void (*bind_client) (struct omapfb_notifier_block *nb);
- void (*get_vram_layout)(unsigned long *size,
- void **virt_base,
- dma_addr_t *phys_base);
- int (*mmap) (struct vm_area_struct *vma);
- unsigned long (*get_caps) (void);
+ void (*get_caps) (int plane, struct omapfb_caps *caps);
int (*set_update_mode)(enum omapfb_update_mode mode);
enum omapfb_update_mode (*get_update_mode)(void);
int (*setup_plane) (int plane, int channel_out,
@@ -245,8 +305,16 @@ struct lcd_ctrl {
int screen_width,
int pos_x, int pos_y, int width,
int height, int color_mode);
+ int (*setup_mem) (int plane, size_t size,
+ int mem_type, unsigned long *paddr);
+ int (*mmap) (struct fb_info *info,
+ struct vm_area_struct *vma);
+ int (*set_scale) (int plane,
+ int orig_width, int orig_height,
+ int out_width, int out_height);
int (*enable_plane) (int plane, int enable);
- int (*update_window) (struct omapfb_update_window *win,
+ int (*update_window) (struct fb_info *fbi,
+ struct omapfb_update_window *win,
void (*callback)(void *),
void *callback_data);
void (*sync) (void);
@@ -257,7 +325,7 @@ struct lcd_ctrl {
u16 blue, u16 transp,
int update_hw_mem);
int (*set_color_key) (struct omapfb_color_key *ck);
-
+ int (*get_color_key) (struct omapfb_color_key *ck);
};
enum omapfb_state {
@@ -266,19 +334,20 @@ enum omapfb_state {
OMAPFB_ACTIVE = 100
};
+struct omapfb_plane_struct {
+ int idx;
+ struct omapfb_plane_info info;
+ enum omapfb_color_format color_mode;
+ struct omapfb_device *fbdev;
+};
+
struct omapfb_device {
int state;
int ext_lcdc; /* Using external
LCD controller */
struct mutex rqueue_mutex;
- void *vram_virt_base;
- dma_addr_t vram_phys_base;
- unsigned long vram_size;
-
- int color_mode;
int palette_size;
- int mirror;
u32 pseudo_palette[17];
struct lcd_panel *panel; /* LCD panel */
@@ -286,19 +355,19 @@ struct omapfb_device {
struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */
struct lcd_ctrl_extif *ext_if; /* LCD ctrl external
interface */
- struct fb_info *fb_info;
-
struct device *dev;
+ struct fb_var_screeninfo new_var; /* for mode changes */
+
+ struct omapfb_mem_desc mem_desc;
+ struct fb_info *fb_info[OMAPFB_PLANE_NUM];
};
struct omapfb_platform_data {
- struct omap_lcd_config lcd;
- struct omap_fbmem_config fbmem;
+ struct omap_lcd_config lcd;
+ struct omapfb_mem_desc mem_desc;
+ void *ctrl_platform_data;
};
-#define OMAPFB_EVENT_READY 1
-#define OMAPFB_EVENT_DISABLED 2
-
#ifdef CONFIG_ARCH_OMAP1
extern struct lcd_ctrl omap1_lcd_ctrl;
#else
@@ -310,15 +379,16 @@ extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
extern void omapfb_notify_clients(struct omapfb_device *fbdev,
unsigned long event);
extern int omapfb_register_client(struct omapfb_notifier_block *nb,
- omapfb_notifier_callback_t callback,
- void *callback_data);
+ omapfb_notifier_callback_t callback,
+ void *callback_data);
extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
-extern int omapfb_update_window_async(struct omapfb_update_window *win,
- void (*callback)(void *),
- void *callback_data);
+extern int omapfb_update_window_async(struct fb_info *fbi,
+ struct omapfb_update_window *win,
+ void (*callback)(void *),
+ void *callback_data);
-/* in arch/arm/plat-omap/devices.c */
-extern void omapfb_reserve_mem(void);
+/* in arch/arm/plat-omap/fb.c */
+extern void omapfb_set_ctrl_platform_data(void *pdata);
#endif /* __KERNEL__ */
diff --git a/include/asm-arm/arch-omap/sram.h b/include/asm-arm/arch-omap/sram.h
index 6fc0dd57b7c..bb9bb3fd532 100644
--- a/include/asm-arm/arch-omap/sram.h
+++ b/include/asm-arm/arch-omap/sram.h
@@ -20,9 +20,6 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
u32 mem_type);
extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
-extern unsigned long omap_fb_sram_start;
-extern unsigned long omap_fb_sram_size;
-
/* Do not use these */
extern void sram_reprogram_clock(u32 ckctl, u32 dpllctl);
extern unsigned long sram_reprogram_clock_sz;
diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h
index 054fb9a8e0c..99ae9eabaf7 100644
--- a/include/asm-arm/arch-omap/usb.h
+++ b/include/asm-arm/arch-omap/usb.h
@@ -7,9 +7,27 @@
/*-------------------------------------------------------------------------*/
-#define OTG_BASE 0xfffb0400
-#define UDC_BASE 0xfffb4000
-#define OMAP_OHCI_BASE 0xfffba000
+#define OMAP1_OTG_BASE 0xfffb0400
+#define OMAP1_UDC_BASE 0xfffb4000
+#define OMAP1_OHCI_BASE 0xfffba000
+
+#define OMAP2_OHCI_BASE 0x4805e000
+#define OMAP2_UDC_BASE 0x4805e200
+#define OMAP2_OTG_BASE 0x4805e300
+
+#ifdef CONFIG_ARCH_OMAP1
+
+#define OTG_BASE OMAP1_OTG_BASE
+#define UDC_BASE OMAP1_UDC_BASE
+#define OMAP_OHCI_BASE OMAP1_OHCI_BASE
+
+#else
+
+#define OTG_BASE OMAP2_OTG_BASE
+#define UDC_BASE OMAP2_UDC_BASE
+#define OMAP_OHCI_BASE OMAP2_OHCI_BASE
+
+#endif
/*-------------------------------------------------------------------------*/
@@ -28,6 +46,7 @@
# define HST_IDLE_EN (1 << 14)
# define DEV_IDLE_EN (1 << 13)
# define OTG_RESET_DONE (1 << 2)
+# define OTG_SOFT_RESET (1 << 1)
#define OTG_SYSCON_2_REG OTG_REG32(0x08)
# define OTG_EN (1 << 31)
# define USBX_SYNCHRO (1 << 30)
@@ -103,6 +122,7 @@
/*-------------------------------------------------------------------------*/
+/* OMAP1 */
#define USB_TRANSCEIVER_CTRL_REG __REG32(0xfffe1000 + 0x0064)
# define CONF_USB2_UNI_R (1 << 8)
# define CONF_USB1_UNI_R (1 << 7)
@@ -111,7 +131,17 @@
# define CONF_USB_PWRDN_DM_R (1 << 2)
# define CONF_USB_PWRDN_DP_R (1 << 1)
-
-
+/* OMAP2 */
+#define CONTROL_DEVCONF_REG __REG32(L4_24XX_BASE + 0x0274)
+# define USB_UNIDIR 0x0
+# define USB_UNIDIR_TLL 0x1
+# define USB_BIDIR 0x2
+# define USB_BIDIR_TLL 0x3
+# define USBT0WRMODEI(x) ((x) << 22)
+# define USBT1WRMODEI(x) ((x) << 20)
+# define USBT2WRMODEI(x) ((x) << 18)
+# define USBT2TLL5PI (1 << 17)
+# define USB0PUENACTLOI (1 << 16)
+# define USBSTANDBYCTRL (1 << 15)
#endif /* __ASM_ARCH_OMAP_USB_H */
diff --git a/include/asm-arm/arch-pxa/i2c.h b/include/asm-arm/arch-pxa/i2c.h
index 46ec2243974..e404b233d8a 100644
--- a/include/asm-arm/arch-pxa/i2c.h
+++ b/include/asm-arm/arch-pxa/i2c.h
@@ -64,6 +64,7 @@ struct i2c_slave_client;
struct i2c_pxa_platform_data {
unsigned int slave_addr;
struct i2c_slave_client *slave;
+ unsigned int class;
};
extern void pxa_set_i2c_info(struct i2c_pxa_platform_data *info);
diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
index a38a28c4bbd..ef4f570381d 100644
--- a/include/asm-arm/arch-pxa/mmc.h
+++ b/include/asm-arm/arch-pxa/mmc.h
@@ -1,7 +1,7 @@
#ifndef ASMARM_ARCH_MMC_H
#define ASMARM_ARCH_MMC_H
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
#include <linux/interrupt.h>
struct device;
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 139c9d95481..dbcc9298b0c 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1801,35 +1801,35 @@
#define CCCR_M_MASK 0x0060 /* Memory Frequency to Run Mode Frequency Multiplier */
#define CCCR_L_MASK 0x001f /* Crystal Frequency to Memory Frequency Multiplier */
-#define CKEN24_CAMERA (1 << 24) /* Camera Interface Clock Enable */
-#define CKEN23_SSP1 (1 << 23) /* SSP1 Unit Clock Enable */
-#define CKEN22_MEMC (1 << 22) /* Memory Controller Clock Enable */
-#define CKEN21_MEMSTK (1 << 21) /* Memory Stick Host Controller */
-#define CKEN20_IM (1 << 20) /* Internal Memory Clock Enable */
-#define CKEN19_KEYPAD (1 << 19) /* Keypad Interface Clock Enable */
-#define CKEN18_USIM (1 << 18) /* USIM Unit Clock Enable */
-#define CKEN17_MSL (1 << 17) /* MSL Unit Clock Enable */
-#define CKEN16_LCD (1 << 16) /* LCD Unit Clock Enable */
-#define CKEN15_PWRI2C (1 << 15) /* PWR I2C Unit Clock Enable */
-#define CKEN14_I2C (1 << 14) /* I2C Unit Clock Enable */
-#define CKEN13_FICP (1 << 13) /* FICP Unit Clock Enable */
-#define CKEN12_MMC (1 << 12) /* MMC Unit Clock Enable */
-#define CKEN11_USB (1 << 11) /* USB Unit Clock Enable */
-#define CKEN10_ASSP (1 << 10) /* ASSP (SSP3) Clock Enable */
-#define CKEN10_USBHOST (1 << 10) /* USB Host Unit Clock Enable */
-#define CKEN9_OSTIMER (1 << 9) /* OS Timer Unit Clock Enable */
-#define CKEN9_NSSP (1 << 9) /* NSSP (SSP2) Clock Enable */
-#define CKEN8_I2S (1 << 8) /* I2S Unit Clock Enable */
-#define CKEN7_BTUART (1 << 7) /* BTUART Unit Clock Enable */
-#define CKEN6_FFUART (1 << 6) /* FFUART Unit Clock Enable */
-#define CKEN5_STUART (1 << 5) /* STUART Unit Clock Enable */
-#define CKEN4_HWUART (1 << 4) /* HWUART Unit Clock Enable */
-#define CKEN4_SSP3 (1 << 4) /* SSP3 Unit Clock Enable */
-#define CKEN3_SSP (1 << 3) /* SSP Unit Clock Enable */
-#define CKEN3_SSP2 (1 << 3) /* SSP2 Unit Clock Enable */
-#define CKEN2_AC97 (1 << 2) /* AC97 Unit Clock Enable */
-#define CKEN1_PWM1 (1 << 1) /* PWM1 Clock Enable */
-#define CKEN0_PWM0 (1 << 0) /* PWM0 Clock Enable */
+#define CKEN_CAMERA (24) /* Camera Interface Clock Enable */
+#define CKEN_SSP1 (23) /* SSP1 Unit Clock Enable */
+#define CKEN_MEMC (22) /* Memory Controller Clock Enable */
+#define CKEN_MEMSTK (21) /* Memory Stick Host Controller */
+#define CKEN_IM (20) /* Internal Memory Clock Enable */
+#define CKEN_KEYPAD (19) /* Keypad Interface Clock Enable */
+#define CKEN_USIM (18) /* USIM Unit Clock Enable */
+#define CKEN_MSL (17) /* MSL Unit Clock Enable */
+#define CKEN_LCD (16) /* LCD Unit Clock Enable */
+#define CKEN_PWRI2C (15) /* PWR I2C Unit Clock Enable */
+#define CKEN_I2C (14) /* I2C Unit Clock Enable */
+#define CKEN_FICP (13) /* FICP Unit Clock Enable */
+#define CKEN_MMC (12) /* MMC Unit Clock Enable */
+#define CKEN_USB (11) /* USB Unit Clock Enable */
+#define CKEN_ASSP (10) /* ASSP (SSP3) Clock Enable */
+#define CKEN_USBHOST (10) /* USB Host Unit Clock Enable */
+#define CKEN_OSTIMER (9) /* OS Timer Unit Clock Enable */
+#define CKEN_NSSP (9) /* NSSP (SSP2) Clock Enable */
+#define CKEN_I2S (8) /* I2S Unit Clock Enable */
+#define CKEN_BTUART (7) /* BTUART Unit Clock Enable */
+#define CKEN_FFUART (6) /* FFUART Unit Clock Enable */
+#define CKEN_STUART (5) /* STUART Unit Clock Enable */
+#define CKEN_HWUART (4) /* HWUART Unit Clock Enable */
+#define CKEN_SSP3 (4) /* SSP3 Unit Clock Enable */
+#define CKEN_SSP (3) /* SSP Unit Clock Enable */
+#define CKEN_SSP2 (3) /* SSP2 Unit Clock Enable */
+#define CKEN_AC97 (2) /* AC97 Unit Clock Enable */
+#define CKEN_PWM1 (1) /* PWM1 Clock Enable */
+#define CKEN_PWM0 (0) /* PWM0 Clock Enable */
#define OSCC_OON (1 << 1) /* 32.768kHz OON (write-once only bit) */
#define OSCC_OOK (1 << 0) /* 32.768kHz OOK (read-only bit) */
diff --git a/include/asm-arm/arch-pxa/pxa27x_keyboard.h b/include/asm-arm/arch-pxa/pxa27x_keyboard.h
new file mode 100644
index 00000000000..3aaff923b2c
--- /dev/null
+++ b/include/asm-arm/arch-pxa/pxa27x_keyboard.h
@@ -0,0 +1,13 @@
+#define PXAKBD_MAXROW 8
+#define PXAKBD_MAXCOL 8
+
+struct pxa27x_keyboard_platform_data {
+ int nr_rows, nr_cols;
+ int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
+ int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
+
+#ifdef CONFIG_PM
+ u32 reg_kpc;
+ u32 reg_kprec;
+#endif
+};
diff --git a/include/asm-arm/arch-s3c2410/regs-ac97.h b/include/asm-arm/arch-s3c2410/regs-ac97.h
index bdd6a4f93d7..b004dee6bca 100644
--- a/include/asm-arm/arch-s3c2410/regs-ac97.h
+++ b/include/asm-arm/arch-s3c2410/regs-ac97.h
@@ -13,11 +13,55 @@
#ifndef __ASM_ARCH_REGS_AC97_H
#define __ASM_ARCH_REGS_AC97_H __FILE__
-#define S3C_AC97_GLBCTRL (0x00)
-#define S3C_AC97_GLBSTAT (0x04)
-#define S3C_AC97_CODEC_CMD (0x08)
-#define S3C_AC97_PCM_ADDR (0x10)
-#define S3C_AC97_PCM_DATA (0x18)
-#define S3C_AC97_MIC_DATA (0x1C)
+#define S3C_AC97_GLBCTRL (0x00)
+
+#define S3C_AC97_GLBCTRL_CODECREADYIE (1<<22)
+#define S3C_AC97_GLBCTRL_PCMOUTURIE (1<<21)
+#define S3C_AC97_GLBCTRL_PCMINORIE (1<<20)
+#define S3C_AC97_GLBCTRL_MICINORIE (1<<19)
+#define S3C_AC97_GLBCTRL_PCMOUTTIE (1<<18)
+#define S3C_AC97_GLBCTRL_PCMINTIE (1<<17)
+#define S3C_AC97_GLBCTRL_MICINTIE (1<<16)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF (0<<12)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO (1<<12)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA (2<<12)
+#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK (3<<12)
+#define S3C_AC97_GLBCTRL_PCMINTM_OFF (0<<10)
+#define S3C_AC97_GLBCTRL_PCMINTM_PIO (1<<10)
+#define S3C_AC97_GLBCTRL_PCMINTM_DMA (2<<10)
+#define S3C_AC97_GLBCTRL_PCMINTM_MASK (3<<10)
+#define S3C_AC97_GLBCTRL_MICINTM_OFF (0<<8)
+#define S3C_AC97_GLBCTRL_MICINTM_PIO (1<<8)
+#define S3C_AC97_GLBCTRL_MICINTM_DMA (2<<8)
+#define S3C_AC97_GLBCTRL_MICINTM_MASK (3<<8)
+#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE (1<<3)
+#define S3C_AC97_GLBCTRL_ACLINKON (1<<2)
+#define S3C_AC97_GLBCTRL_WARMRESET (1<<1)
+#define S3C_AC97_GLBCTRL_COLDRESET (1<<0)
+
+#define S3C_AC97_GLBSTAT (0x04)
+
+#define S3C_AC97_GLBSTAT_CODECREADY (1<<22)
+#define S3C_AC97_GLBSTAT_PCMOUTUR (1<<21)
+#define S3C_AC97_GLBSTAT_PCMINORI (1<<20)
+#define S3C_AC97_GLBSTAT_MICINORI (1<<19)
+#define S3C_AC97_GLBSTAT_PCMOUTTI (1<<18)
+#define S3C_AC97_GLBSTAT_PCMINTI (1<<17)
+#define S3C_AC97_GLBSTAT_MICINTI (1<<16)
+#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE (0<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_INIT (1<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_READY (2<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE (3<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_LP (4<<0)
+#define S3C_AC97_GLBSTAT_MAINSTATE_WARM (5<<0)
+
+#define S3C_AC97_CODEC_CMD (0x08)
+
+#define S3C_AC97_CODEC_CMD_READ (1<<23)
+
+#define S3C_AC97_STAT (0x0c)
+#define S3C_AC97_PCM_ADDR (0x10)
+#define S3C_AC97_PCM_DATA (0x18)
+#define S3C_AC97_MIC_DATA (0x1C)
#endif /* __ASM_ARCH_REGS_AC97_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-power.h b/include/asm-arm/arch-s3c2410/regs-power.h
index 6c319ea2afa..94ff96505b6 100644
--- a/include/asm-arm/arch-s3c2410/regs-power.h
+++ b/include/asm-arm/arch-s3c2410/regs-power.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-power.h
+/* linux/include/asm-arm/arch-s3c2410/regs-power.h
*
* Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
* http://armlinux.simtec.co.uk/
diff --git a/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
index ff0536d2de4..cd9e26568f8 100644
--- a/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-s3c2410/regs-clock.h
+/* linux/include/asm-arm/arch-s3c2410/regs-s3c2443-clock.h
*
* Copyright (c) 2007 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
index 3c8354619b6..e1e9805d2d9 100644
--- a/include/asm-arm/arch-s3c2410/regs-udc.h
+++ b/include/asm-arm/arch-s3c2410/regs-udc.h
@@ -75,7 +75,7 @@
#define S3C2410_UDC_OUT_FIFO_CNT1_REG S3C2410_USBDREG(0x0198)
#define S3C2410_UDC_OUT_FIFO_CNT2_REG S3C2410_USBDREG(0x019c)
-
+#define S3C2410_UDC_FUNCADDR_UPDATE (1<<7)
#define S3C2410_UDC_PWR_ISOUP (1<<7) // R/W
#define S3C2410_UDC_PWR_RESET (1<<3) // R
@@ -135,10 +135,6 @@
#define S3C2410_UDC_OCSR2_ISO (1<<6) // R/W
#define S3C2410_UDC_OCSR2_DMAIEN (1<<5) // R/W
-#define S3C2410_UDC_SETIX(base,x) \
- writel(S3C2410_UDC_INDEX_ ## x, base+S3C2410_UDC_INDEX_REG);
-
-
#define S3C2410_UDC_EP0_CSR_OPKRDY (1<<0)
#define S3C2410_UDC_EP0_CSR_IPKRDY (1<<1)
#define S3C2410_UDC_EP0_CSR_SENTSTL (1<<2)
diff --git a/include/asm-arm/arch-s3c2410/regs-watchdog.h b/include/asm-arm/arch-s3c2410/regs-watchdog.h
index f4fff448c7b..a9c5d491bdb 100644
--- a/include/asm-arm/arch-s3c2410/regs-watchdog.h
+++ b/include/asm-arm/arch-s3c2410/regs-watchdog.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-watchdog.h
+/* linux/include/asm-arm/arch-s3c2410/regs-watchdog.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/udc.h b/include/asm-arm/arch-s3c2410/udc.h
index e59ec339d61..b8aa6cb69b5 100644
--- a/include/asm-arm/arch-s3c2410/udc.h
+++ b/include/asm-arm/arch-s3c2410/udc.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/udc.h
+/* linux/include/asm-arm/arch-s3c2410/udc.h
*
* Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org>
*
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
index f266c279512..3b59f94b5a3 100644
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -12,6 +12,7 @@
#define __ASM_ARM_ATOMIC_H
#include <linux/compiler.h>
+#include <asm/system.h>
typedef struct { volatile int counter; } atomic_t;
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index afad32c76e6..d1294a46c70 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -102,6 +102,14 @@
//# endif
#endif
+#if defined(CONFIG_CPU_V7)
+//# ifdef _CACHE
+# define MULTI_CACHE 1
+//# else
+//# define _CACHE v7
+//# endif
+#endif
+
#if !defined(_CACHE) && !defined(MULTI_CACHE)
#error Unknown cache maintainence model
#endif
@@ -418,11 +426,19 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
*/
#define flush_icache_page(vma,page) do { } while (0)
-#define __cacheid_present(val) (val != read_cpuid(CPUID_ID))
-#define __cacheid_vivt(val) ((val & (15 << 25)) != (14 << 25))
-#define __cacheid_vipt(val) ((val & (15 << 25)) == (14 << 25))
-#define __cacheid_vipt_nonaliasing(val) ((val & (15 << 25 | 1 << 23)) == (14 << 25))
-#define __cacheid_vipt_aliasing(val) ((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
+#define __cacheid_present(val) (val != read_cpuid(CPUID_ID))
+#define __cacheid_type_v7(val) ((val & (7 << 29)) == (4 << 29))
+
+#define __cacheid_vivt_prev7(val) ((val & (15 << 25)) != (14 << 25))
+#define __cacheid_vipt_prev7(val) ((val & (15 << 25)) == (14 << 25))
+#define __cacheid_vipt_nonaliasing_prev7(val) ((val & (15 << 25 | 1 << 23)) == (14 << 25))
+#define __cacheid_vipt_aliasing_prev7(val) ((val & (15 << 25 | 1 << 23)) == (14 << 25 | 1 << 23))
+
+#define __cacheid_vivt(val) (__cacheid_type_v7(val) ? 0 : __cacheid_vivt_prev7(val))
+#define __cacheid_vipt(val) (__cacheid_type_v7(val) ? 1 : __cacheid_vipt_prev7(val))
+#define __cacheid_vipt_nonaliasing(val) (__cacheid_type_v7(val) ? 1 : __cacheid_vipt_nonaliasing_prev7(val))
+#define __cacheid_vipt_aliasing(val) (__cacheid_type_v7(val) ? 0 : __cacheid_vipt_aliasing_prev7(val))
+#define __cacheid_vivt_asid_tagged_instr(val) (__cacheid_type_v7(val) ? ((val & (3 << 14)) == (1 << 14)) : 0)
#if defined(CONFIG_CPU_CACHE_VIVT) && !defined(CONFIG_CPU_CACHE_VIPT)
@@ -430,6 +446,7 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
#define cache_is_vipt() 0
#define cache_is_vipt_nonaliasing() 0
#define cache_is_vipt_aliasing() 0
+#define icache_is_vivt_asid_tagged() 0
#elif defined(CONFIG_CPU_CACHE_VIPT)
@@ -447,6 +464,12 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
__cacheid_vipt_aliasing(__val); \
})
+#define icache_is_vivt_asid_tagged() \
+ ({ \
+ unsigned int __val = read_cpuid(CPUID_CACHETYPE); \
+ __cacheid_vivt_asid_tagged_instr(__val); \
+ })
+
#else
#define cache_is_vivt() \
@@ -475,6 +498,13 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
__cacheid_vipt_aliasing(__val); \
})
+#define icache_is_vivt_asid_tagged() \
+ ({ \
+ unsigned int __val = read_cpuid(CPUID_CACHETYPE); \
+ __cacheid_present(__val) && \
+ __cacheid_vivt_asid_tagged_instr(__val); \
+ })
+
#endif
#endif
diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
index abfb75b654c..c8b5d0db0cf 100644
--- a/include/asm-arm/dma-mapping.h
+++ b/include/asm-arm/dma-mapping.h
@@ -445,7 +445,7 @@ extern void dmabounce_unregister_dev(struct device *);
*
* The dmabounce routines call this function whenever a dma-mapping
* is requested to determine whether a given buffer needs to be bounced
- * or not. The function must return 0 if the the buffer is OK for
+ * or not. The function must return 0 if the buffer is OK for
* DMA access and 1 if the buffer needs to be bounced.
*
*/
diff --git a/include/asm-arm/ecard.h b/include/asm-arm/ecard.h
index a0ae2b954d2..3a6d3eb2762 100644
--- a/include/asm-arm/ecard.h
+++ b/include/asm-arm/ecard.h
@@ -160,6 +160,7 @@ struct expansion_card {
unsigned char irqmask; /* IRQ mask */
unsigned char fiqmask; /* FIQ mask */
unsigned char claimed; /* Card claimed? */
+ unsigned char easi; /* EASI card */
void *irq_data; /* Data for use for IRQ by card */
void *fiq_data; /* Data for use for FIQ by card */
@@ -169,7 +170,6 @@ struct expansion_card {
CONST unsigned int dma; /* DMA number (for request_dma) */
CONST unsigned int irq; /* IRQ number (for request_irq) */
CONST unsigned int fiq; /* FIQ number (for request_irq) */
- CONST card_type_t type; /* Type of card */
CONST struct in_ecid cid; /* Card Identification */
/* Private internal data */
@@ -224,56 +224,6 @@ ecard_address(struct expansion_card *ec, card_type_t type, card_speed_t speed)
extern int ecard_request_resources(struct expansion_card *ec);
extern void ecard_release_resources(struct expansion_card *ec);
-#ifdef ECARD_C
-/* Definitions internal to ecard.c - for it's use only!!
- *
- * External expansion card header as read from the card
- */
-struct ex_ecid {
- unsigned char r_irq:1;
- unsigned char r_zero:1;
- unsigned char r_fiq:1;
- unsigned char r_id:4;
- unsigned char r_a:1;
-
- unsigned char r_cd:1;
- unsigned char r_is:1;
- unsigned char r_w:2;
- unsigned char r_r1:4;
-
- unsigned char r_r2:8;
-
- unsigned char r_prod[2];
-
- unsigned char r_manu[2];
-
- unsigned char r_country;
-
- unsigned char r_fiqmask;
- unsigned char r_fiqoff[3];
-
- unsigned char r_irqmask;
- unsigned char r_irqoff[3];
-};
-
-/*
- * Chunk directory entry as read from the card
- */
-struct ex_chunk_dir {
- unsigned char r_id;
- unsigned char r_len[3];
- unsigned long r_start;
- union {
- char string[256];
- char data[1];
- } d;
-#define c_id(x) ((x)->r_id)
-#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16))
-#define c_start(x) ((x)->r_start)
-};
-
-#endif
-
extern struct bus_type ecard_bus_type;
#define ECARD_DEV(_d) container_of((_d), struct expansion_card, dev)
diff --git a/include/asm-arm/glue.h b/include/asm-arm/glue.h
index 0cc5d3b10ce..22274ce8137 100644
--- a/include/asm-arm/glue.h
+++ b/include/asm-arm/glue.h
@@ -38,6 +38,7 @@
* v5tej_early - ARMv5 with Thumb and Java early abort handler
* xscale - ARMv5 with Thumb with Xscale extensions
* v6_early - ARMv6 generic early abort handler
+ * v7_early - ARMv7 generic early abort handler
*/
#undef CPU_ABORT_HANDLER
#undef MULTI_ABORT
@@ -106,6 +107,14 @@
# endif
#endif
+#ifdef CONFIG_CPU_ABRT_EV7
+# ifdef CPU_ABORT_HANDLER
+# define MULTI_ABORT 1
+# else
+# define CPU_ABORT_HANDLER v7_early_abort
+# endif
+#endif
+
#ifndef CPU_ABORT_HANDLER
#error Unknown data abort handler type
#endif
diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
index 15141a9caca..63feceb7ede 100644
--- a/include/asm-arm/hardware/iop3xx.h
+++ b/include/asm-arm/hardware/iop3xx.h
@@ -28,6 +28,7 @@
extern void gpio_line_config(int line, int direction);
extern int gpio_line_get(int line);
extern void gpio_line_set(int line, int value);
+extern int init_atu;
#endif
@@ -41,7 +42,7 @@ extern void gpio_line_set(int line, int value);
IOP3XX_PERIPHERAL_SIZE - 1)
#define IOP3XX_PERIPHERAL_UPPER_VA (IOP3XX_PERIPHERAL_VIRT_BASE +\
IOP3XX_PERIPHERAL_SIZE - 1)
-#define IOP3XX_PMMR_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
+#define IOP3XX_PMMR_PHYS_TO_VIRT(addr) (u32) ((u32) (addr) -\
(IOP3XX_PERIPHERAL_PHYS_BASE\
- IOP3XX_PERIPHERAL_VIRT_BASE))
#define IOP3XX_REG_ADDR(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + (reg))
@@ -103,6 +104,21 @@ extern void gpio_line_set(int line, int value);
#define IOP3XX_PCIXCMD (volatile u16 *)IOP3XX_REG_ADDR(0x01e2)
#define IOP3XX_PCIXSR (volatile u32 *)IOP3XX_REG_ADDR(0x01e4)
#define IOP3XX_PCIIRSR (volatile u32 *)IOP3XX_REG_ADDR(0x01ec)
+#define IOP3XX_PCSR_OUT_Q_BUSY (1 << 15)
+#define IOP3XX_PCSR_IN_Q_BUSY (1 << 14)
+#define IOP3XX_ATUCR_OUT_EN (1 << 1)
+
+#define IOP3XX_INIT_ATU_DEFAULT 0
+#define IOP3XX_INIT_ATU_DISABLE -1
+#define IOP3XX_INIT_ATU_ENABLE 1
+
+#ifdef CONFIG_IOP3XX_ATU
+#define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\
+ IOP3XX_INIT_ATU_ENABLE : init_atu)
+#else
+#define iop3xx_get_init_atu(x) (init_atu == IOP3XX_INIT_ATU_DEFAULT ?\
+ IOP3XX_INIT_ATU_DISABLE : init_atu)
+#endif
/* Messaging Unit */
#define IOP3XX_IMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0310)
@@ -253,14 +269,12 @@ extern void gpio_line_set(int line, int value);
/*
* IOP3XX I/O and Mem space regions for PCI autoconfiguration
*/
-#define IOP3XX_PCI_MEM_WINDOW_SIZE 0x04000000
-#define IOP3XX_PCI_LOWER_MEM_PA 0x80000000
-#define IOP3XX_PCI_LOWER_MEM_BA (*IOP3XX_OMWTVR0)
+#define IOP3XX_PCI_LOWER_MEM_PA 0x80000000
#define IOP3XX_PCI_IO_WINDOW_SIZE 0x00010000
#define IOP3XX_PCI_LOWER_IO_PA 0x90000000
#define IOP3XX_PCI_LOWER_IO_VA 0xfe000000
-#define IOP3XX_PCI_LOWER_IO_BA (*IOP3XX_OIOWTVR)
+#define IOP3XX_PCI_LOWER_IO_BA 0x90000000
#define IOP3XX_PCI_UPPER_IO_PA (IOP3XX_PCI_LOWER_IO_PA +\
IOP3XX_PCI_IO_WINDOW_SIZE - 1)
#define IOP3XX_PCI_UPPER_IO_VA (IOP3XX_PCI_LOWER_IO_VA +\
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 5f60b422090..8261ff9e795 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -56,13 +56,22 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
/*
* Architecture ioremap implementation.
- *
- * __ioremap takes CPU physical address.
- *
- * __ioremap_pfn takes a Page Frame Number and an offset into that page
*/
-extern void __iomem * __ioremap_pfn(unsigned long, unsigned long, size_t, unsigned long);
-extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
+#define MT_DEVICE 0
+#define MT_DEVICE_NONSHARED 1
+#define MT_DEVICE_CACHED 2
+#define MT_DEVICE_IXP2000 3
+/*
+ * types 4 onwards can be found in asm/mach/map.h and are undefined
+ * for ioremap
+ */
+
+/*
+ * __arm_ioremap takes CPU physical address.
+ * __arm_ioremap_pfn takes a Page Frame Number and an offset into that page
+ */
+extern void __iomem * __arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
+extern void __iomem * __arm_ioremap(unsigned long, size_t, unsigned int);
extern void __iounmap(volatile void __iomem *addr);
/*
@@ -203,14 +212,14 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
*
*/
#ifndef __arch_ioremap
-#define ioremap(cookie,size) __ioremap(cookie,size,0)
-#define ioremap_nocache(cookie,size) __ioremap(cookie,size,0)
-#define ioremap_cached(cookie,size) __ioremap(cookie,size,L_PTE_CACHEABLE)
+#define ioremap(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
+#define ioremap_nocache(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE)
+#define ioremap_cached(cookie,size) __arm_ioremap(cookie, size, MT_DEVICE_CACHED)
#define iounmap(cookie) __iounmap(cookie)
#else
-#define ioremap(cookie,size) __arch_ioremap((cookie),(size),0)
-#define ioremap_nocache(cookie,size) __arch_ioremap((cookie),(size),0)
-#define ioremap_cached(cookie,size) __arch_ioremap((cookie),(size),L_PTE_CACHEABLE)
+#define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
+#define ioremap_nocache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE)
+#define ioremap_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED)
#define iounmap(cookie) __arch_iounmap(cookie)
#endif
diff --git a/include/asm-arm/kdebug.h b/include/asm-arm/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-arm/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-arm/kexec.h b/include/asm-arm/kexec.h
index 8c1c6162a80..b5b030ef633 100644
--- a/include/asm-arm/kexec.h
+++ b/include/asm-arm/kexec.h
@@ -16,8 +16,6 @@
#ifndef __ASSEMBLY__
-#define MAX_NOTE_BYTES 1024
-
struct kimage;
/* Provide a dummy definition to avoid build failures. */
static inline void crash_setup_regs(struct pt_regs *newregs,
diff --git a/include/asm-arm/mach/map.h b/include/asm-arm/mach/map.h
index cef5364ed5f..7ef3c839018 100644
--- a/include/asm-arm/mach/map.h
+++ b/include/asm-arm/mach/map.h
@@ -9,6 +9,8 @@
*
* Page table mapping constructs and function prototypes
*/
+#include <asm/io.h>
+
struct map_desc {
unsigned long virtual;
unsigned long pfn;
@@ -16,15 +18,16 @@ struct map_desc {
unsigned int type;
};
-#define MT_DEVICE 0
-#define MT_CACHECLEAN 1
-#define MT_MINICLEAN 2
-#define MT_LOW_VECTORS 3
-#define MT_HIGH_VECTORS 4
-#define MT_MEMORY 5
-#define MT_ROM 6
-#define MT_IXP2000_DEVICE 7
-#define MT_NONSHARED_DEVICE 8
+/* types 0-3 are defined in asm/io.h */
+#define MT_CACHECLEAN 4
+#define MT_MINICLEAN 5
+#define MT_LOW_VECTORS 6
+#define MT_HIGH_VECTORS 7
+#define MT_MEMORY 8
+#define MT_ROM 9
+
+#define MT_NONSHARED_DEVICE MT_DEVICE_NONSHARED
+#define MT_IXP2000_DEVICE MT_DEVICE_IXP2000
#ifdef CONFIG_MMU
extern void iotable_init(struct map_desc *, int);
diff --git a/include/asm-arm/mach/mmc.h b/include/asm-arm/mach/mmc.h
index 1b3555d4b41..eb91145c00c 100644
--- a/include/asm-arm/mach/mmc.h
+++ b/include/asm-arm/mach/mmc.h
@@ -4,7 +4,7 @@
#ifndef ASMARM_MACH_MMC_H
#define ASMARM_MACH_MMC_H
-#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
struct mmc_platform_data {
unsigned int ocr_mask; /* available voltages */
diff --git a/include/asm-arm/mmu_context.h b/include/asm-arm/mmu_context.h
index d1a65b1edca..4981ad41919 100644
--- a/include/asm-arm/mmu_context.h
+++ b/include/asm-arm/mmu_context.h
@@ -16,6 +16,7 @@
#include <linux/compiler.h>
#include <asm/cacheflush.h>
#include <asm/proc-fns.h>
+#include <asm-generic/mm_hooks.h>
void __check_kvm_seq(struct mm_struct *mm);
@@ -35,8 +36,9 @@ void __check_kvm_seq(struct mm_struct *mm);
* The context ID is used by debuggers and trace logic, and
* should be unique within all running processes.
*/
-#define ASID_BITS 8
-#define ASID_MASK ((~0) << ASID_BITS)
+#define ASID_BITS 8
+#define ASID_MASK ((~0) << ASID_BITS)
+#define ASID_FIRST_VERSION (1 << ASID_BITS)
extern unsigned int cpu_last_asid;
@@ -95,8 +97,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
#ifdef CONFIG_MMU
unsigned int cpu = smp_processor_id();
- if (prev != next) {
- cpu_set(cpu, next->cpu_vm_mask);
+ if (!cpu_test_and_set(cpu, next->cpu_vm_mask) || prev != next) {
check_context(next);
cpu_switch_mm(next->pgd, next);
if (cache_is_vivt())
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
index 7b1c9acdf79..0c8be19fd66 100644
--- a/include/asm-arm/pgtable-nommu.h
+++ b/include/asm-arm/pgtable-nommu.h
@@ -83,10 +83,6 @@ extern int is_in_rom(unsigned long);
#define io_remap_page_range remap_page_range
#define io_remap_pfn_range remap_pfn_range
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/*
* All 32bit addresses are effectively valid for vmalloc...
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 7b2bafce21a..21dec9f258d 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -395,10 +395,6 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma, from, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#define pgtable_cache_init() do { } while (0)
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-arm/plat-s3c24xx/clock.h b/include/asm-arm/plat-s3c24xx/clock.h
index f6135dbb9fa..235b753cd87 100644
--- a/include/asm-arm/plat-s3c24xx/clock.h
+++ b/include/asm-arm/plat-s3c24xx/clock.h
@@ -56,6 +56,7 @@ extern struct mutex clocks_mutex;
extern int s3c2410_clkcon_enable(struct clk *clk, int enable);
extern int s3c24xx_register_clock(struct clk *clk);
+extern int s3c24xx_register_clocks(struct clk **clk, int nr_clks);
extern int s3c24xx_setup_clocks(unsigned long xtal,
unsigned long fclk,
diff --git a/include/asm-arm/plat-s3c24xx/cpu.h b/include/asm-arm/plat-s3c24xx/cpu.h
index 15dd1881090..23e420e8bd5 100644
--- a/include/asm-arm/plat-s3c24xx/cpu.h
+++ b/include/asm-arm/plat-s3c24xx/cpu.h
@@ -40,22 +40,6 @@ extern void s3c24xx_init_uartdevs(char *name,
struct s3c24xx_uart_resources *res,
struct s3c2410_uartcfg *cfg, int no);
-/* the board structure is used at first initialsation time
- * to get info such as the devices to register for this
- * board. This is done because platfrom_add_devices() cannot
- * be called from the map_io entry.
-*/
-
-struct s3c24xx_board {
- struct platform_device **devices;
- unsigned int devices_count;
-
- struct clk **clocks;
- unsigned int clocks_count;
-};
-
-extern void s3c24xx_set_board(struct s3c24xx_board *board);
-
/* timer for 2410/2440 */
struct sys_timer;
diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h
index ea7e54c319b..5599d4e5e70 100644
--- a/include/asm-arm/proc-fns.h
+++ b/include/asm-arm/proc-fns.h
@@ -193,6 +193,14 @@
# define CPU_NAME cpu_v6
# endif
# endif
+# ifdef CONFIG_CPU_V7
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_v7
+# endif
+# endif
#endif
#ifndef __ASSEMBLY__
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
index 5a8ef787dbf..2d0dad8c10a 100644
--- a/include/asm-arm/ptrace.h
+++ b/include/asm-arm/ptrace.h
@@ -10,23 +10,19 @@
#ifndef __ASM_ARM_PTRACE_H
#define __ASM_ARM_PTRACE_H
-
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
#define PTRACE_SETFPREGS 15
-
+/* PTRACE_ATTACH is 16 */
+/* PTRACE_DETACH is 17 */
#define PTRACE_GETWMMXREGS 18
#define PTRACE_SETWMMXREGS 19
-
+/* 20 is unused */
#define PTRACE_OLDSETOPTIONS 21
-
#define PTRACE_GET_THREAD_AREA 22
-
#define PTRACE_SET_SYSCALL 23
-
/* PTRACE_SYSCALL is 24 */
-
#define PTRACE_GETCRUNCHREGS 25
#define PTRACE_SETCRUNCHREGS 26
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 69134c7518c..6f8e6a69dc5 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -14,6 +14,7 @@
#define CPU_ARCH_ARMv5TE 6
#define CPU_ARCH_ARMv5TEJ 7
#define CPU_ARCH_ARMv6 8
+#define CPU_ARCH_ARMv7 9
/*
* CR1 bits (CP#15 CR1)
@@ -76,6 +77,8 @@
#include <linux/linkage.h>
#include <linux/irqflags.h>
+#define __exception __attribute__((section(".exception.text")))
+
struct thread_info;
struct task_struct;
@@ -91,7 +94,7 @@ void die(const char *msg, struct pt_regs *regs, int err)
__attribute__((noreturn));
struct siginfo;
-void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
+void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
unsigned long err, unsigned long trap);
void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
@@ -101,8 +104,6 @@ void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
#define xchg(ptr,x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
-
extern asmlinkage void __backtrace(void);
extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
@@ -155,7 +156,11 @@ extern unsigned int user_debug;
#define vectors_high() (0)
#endif
-#if defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ >= 6
+#if __LINUX_ARM_ARCH__ >= 7
+#define isb() __asm__ __volatile__ ("isb" : : : "memory")
+#define dsb() __asm__ __volatile__ ("dsb" : : : "memory")
+#define dmb() __asm__ __volatile__ ("dmb" : : : "memory")
+#elif defined(CONFIG_CPU_XSC3) || __LINUX_ARM_ARCH__ == 6
#define isb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c5, 4" \
: : "r" (0) : "memory")
#define dsb() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 4" \
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
index 5014794f9eb..eae85b09db2 100644
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -57,6 +57,7 @@ struct thread_info {
__u32 cpu; /* cpu */
__u32 cpu_domain; /* cpu domain */
struct cpu_context_save cpu_context; /* cpu context */
+ __u32 syscall; /* syscall number */
__u8 used_cp[16]; /* thread used copro */
unsigned long tp_value;
struct crunch_state crunchstate;
diff --git a/include/asm-arm26/atomic.h b/include/asm-arm26/atomic.h
index 97e944fe1cf..d6dd42374cf 100644
--- a/include/asm-arm26/atomic.h
+++ b/include/asm-arm26/atomic.h
@@ -20,7 +20,6 @@
#ifndef __ASM_ARM_ATOMIC_H
#define __ASM_ARM_ATOMIC_H
-
#ifdef CONFIG_SMP
#error SMP is NOT supported
#endif
diff --git a/include/asm-arm26/io.h b/include/asm-arm26/io.h
index 2aa033bd067..a5a7a4d5e09 100644
--- a/include/asm-arm26/io.h
+++ b/include/asm-arm26/io.h
@@ -321,7 +321,7 @@ DECLARE_IO(int,l,"")
#define mmiowb()
-/* the following macro is depreciated */
+/* the following macro is deprecated */
#define ioaddr(port) __ioaddr((port))
/*
diff --git a/include/asm-arm26/kdebug.h b/include/asm-arm26/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-arm26/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-arm26/memory.h b/include/asm-arm26/memory.h
index a65f10b80df..7c1e5be3906 100644
--- a/include/asm-arm26/memory.h
+++ b/include/asm-arm26/memory.h
@@ -60,7 +60,7 @@ static inline void *phys_to_virt(unsigned long x)
/*
* Virtual <-> DMA view memory address translations
* Again, these are *only* valid on the kernel direct mapped RAM
- * memory. Use of these is *depreciated*.
+ * memory. Use of these is *deprecated*.
*/
#define virt_to_bus(x) ((unsigned long)(x))
#define bus_to_virt(x) ((void *)((unsigned long)(x)))
@@ -93,7 +93,7 @@ static inline void *phys_to_virt(unsigned long x)
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
/*
- * We should really eliminate virt_to_bus() here - it's depreciated.
+ * We should really eliminate virt_to_bus() here - it's deprecated.
*/
#define page_to_bus(page) (page_address(page))
diff --git a/include/asm-arm26/mmu_context.h b/include/asm-arm26/mmu_context.h
index 1a929bfe5c3..16c821f81b8 100644
--- a/include/asm-arm26/mmu_context.h
+++ b/include/asm-arm26/mmu_context.h
@@ -13,6 +13,8 @@
#ifndef __ASM_ARM_MMU_CONTEXT_H
#define __ASM_ARM_MMU_CONTEXT_H
+#include <asm-generic/mm_hooks.h>
+
#define init_new_context(tsk,mm) 0
#define destroy_context(mm) do { } while(0)
diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
index 63a8881fae1..2b20e9f0885 100644
--- a/include/asm-arm26/pgtable.h
+++ b/include/asm-arm26/pgtable.h
@@ -297,10 +297,6 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
#define io_remap_pfn_range(vma,from,pfn,size,prot) \
remap_pfn_range(vma, from, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#endif /* !__ASSEMBLY__ */
#endif /* _ASMARM_PGTABLE_H */
diff --git a/include/asm-arm26/setup.h b/include/asm-arm26/setup.h
index 1a867b4e8d5..10fd07c7666 100644
--- a/include/asm-arm26/setup.h
+++ b/include/asm-arm26/setup.h
@@ -70,7 +70,7 @@ struct tag_ramdisk {
/* describes where the compressed ramdisk image lives */
/*
* this one accidentally used virtual addresses - as such,
- * its depreciated.
+ * it's deprecated.
*/
#define ATAG_INITRD 0x54410005
diff --git a/include/asm-arm26/system.h b/include/asm-arm26/system.h
index 00ae32aa1db..4703593b3bb 100644
--- a/include/asm-arm26/system.h
+++ b/include/asm-arm26/system.h
@@ -52,8 +52,6 @@ void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
#define xchg(ptr,x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
-
extern asmlinkage void __backtrace(void);
#define set_cr(x) \
diff --git a/include/asm-avr32/arch-at32ap/cpu.h b/include/asm-avr32/arch-at32ap/cpu.h
new file mode 100644
index 00000000000..2bdc5bd6f79
--- /dev/null
+++ b/include/asm-avr32/arch-at32ap/cpu.h
@@ -0,0 +1,33 @@
+/*
+ * AVR32 and (fake) AT91 CPU identification
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef __ASM_ARCH_CPU_H
+#define __ASM_ARCH_CPU_H
+
+/*
+ * Only AT32AP7000 is defined for now. We can identify the specific
+ * chip at runtime, but I'm not sure if it's really worth it.
+ */
+#ifdef CONFIG_CPU_AT32AP7000
+# define cpu_is_at32ap7000() (1)
+#else
+# define cpu_is_at32ap7000() (0)
+#endif
+
+/*
+ * Since this is AVR32, we will never run on any AT91 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at91rm9200() (0)
+#define cpu_is_at91sam9xe() (0)
+#define cpu_is_at91sam9260() (0)
+#define cpu_is_at91sam9261() (0)
+#define cpu_is_at91sam9263() (0)
+
+#endif /* __ASM_ARCH_CPU_H */
diff --git a/include/asm-avr32/kdebug.h b/include/asm-avr32/kdebug.h
index f583b643ffb..de419278fc3 100644
--- a/include/asm-avr32/kdebug.h
+++ b/include/asm-avr32/kdebug.h
@@ -3,19 +3,6 @@
#include <linux/notifier.h>
-struct pt_regs;
-
-struct die_args {
- struct pt_regs *regs;
- int trapnr;
-};
-
-int register_die_notifier(struct notifier_block *nb);
-int unregister_die_notifier(struct notifier_block *nb);
-int register_page_fault_notifier(struct notifier_block *nb);
-int unregister_page_fault_notifier(struct notifier_block *nb);
-extern struct atomic_notifier_head avr32_die_chain;
-
/* Grossly misnamed. */
enum die_val {
DIE_FAULT,
@@ -24,15 +11,7 @@ enum die_val {
DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val, struct pt_regs *regs,
- int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .trapnr = trap,
- };
-
- return atomic_notifier_call_chain(&avr32_die_chain, val, &args);
-}
+int register_page_fault_notifier(struct notifier_block *nb);
+int unregister_page_fault_notifier(struct notifier_block *nb);
#endif /* __ASM_AVR32_KDEBUG_H */
diff --git a/include/asm-avr32/mmu_context.h b/include/asm-avr32/mmu_context.h
index 31add1ae808..c37c391faef 100644
--- a/include/asm-avr32/mmu_context.h
+++ b/include/asm-avr32/mmu_context.h
@@ -15,6 +15,7 @@
#include <asm/tlbflush.h>
#include <asm/pgalloc.h>
#include <asm/sysreg.h>
+#include <asm-generic/mm_hooks.h>
/*
* The MMU "context" consists of two things:
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index 6b8ca9db2bd..f6cc2b0f75c 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -394,10 +394,6 @@ typedef pte_t *pte_addr_t;
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/* No page table caches to initialize (?) */
#define pgtable_cache_init() do { } while(0)
diff --git a/include/asm-avr32/scatterlist.h b/include/asm-avr32/scatterlist.h
index bfe7d753423..c6d5ce3b3a2 100644
--- a/include/asm-avr32/scatterlist.h
+++ b/include/asm-avr32/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef __ASM_AVR32_SCATTERLIST_H
#define __ASM_AVR32_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-avr32/setup.h b/include/asm-avr32/setup.h
index 1ff1a217015..b0828d43e11 100644
--- a/include/asm-avr32/setup.h
+++ b/include/asm-avr32/setup.h
@@ -110,7 +110,7 @@ struct tagtable {
int (*parse)(struct tag *);
};
-#define __tag __attribute_used__ __attribute__((__section__(".taglist")))
+#define __tag __attribute_used__ __attribute__((__section__(".taglist.init")))
#define __tagtable(tag, fn) \
static struct tagtable __tagtable_##fn __tag = { tag, fn }
diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h
index 8f512047181..2418cce624c 100644
--- a/include/asm-avr32/unistd.h
+++ b/include/asm-avr32/unistd.h
@@ -295,8 +295,10 @@
#define __NR_shmdt 276
#define __NR_shmctl 277
+#define __NR_utimensat 278
+
#ifdef __KERNEL__
-#define NR_syscalls 278
+#define NR_syscalls 279
#define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-blackfin/Kbuild b/include/asm-blackfin/Kbuild
new file mode 100644
index 00000000000..c68e1680da0
--- /dev/null
+++ b/include/asm-blackfin/Kbuild
@@ -0,0 +1 @@
+include include/asm-generic/Kbuild.asm
diff --git a/include/asm-blackfin/a.out.h b/include/asm-blackfin/a.out.h
new file mode 100644
index 00000000000..d37a6849bf7
--- /dev/null
+++ b/include/asm-blackfin/a.out.h
@@ -0,0 +1,25 @@
+#ifndef __BFIN_A_OUT_H__
+#define __BFIN_A_OUT_H__
+
+struct exec {
+ unsigned long a_info; /* Use macros N_MAGIC, etc for access */
+ unsigned a_text; /* length of text, in bytes */
+ unsigned a_data; /* length of data, in bytes */
+ unsigned a_bss; /* length of uninitialized data area for file, in bytes */
+ unsigned a_syms; /* length of symbol table data in file, in bytes */
+ unsigned a_entry; /* start address */
+ unsigned a_trsize; /* length of relocation info for text, in bytes */
+ unsigned a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#define N_TRSIZE(a) ((a).a_trsize)
+#define N_DRSIZE(a) ((a).a_drsize)
+#define N_SYMSIZE(a) ((a).a_syms)
+
+#ifdef __KERNEL__
+
+#define STACK_TOP TASK_SIZE
+
+#endif
+
+#endif /* __BFIN_A_OUT_H__ */
diff --git a/include/asm-blackfin/atomic.h b/include/asm-blackfin/atomic.h
new file mode 100644
index 00000000000..7cf50871860
--- /dev/null
+++ b/include/asm-blackfin/atomic.h
@@ -0,0 +1,144 @@
+#ifndef __ARCH_BLACKFIN_ATOMIC__
+#define __ARCH_BLACKFIN_ATOMIC__
+
+#include <asm/system.h> /* local_irq_XXX() */
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ *
+ * Generally we do not concern about SMP BFIN systems, so we don't have
+ * to deal with that.
+ *
+ * Tony Kou (tonyko@lineo.ca) Lineo Inc. 2001
+ */
+
+typedef struct {
+ int counter;
+} atomic_t;
+#define ATOMIC_INIT(i) { (i) }
+
+#define atomic_read(v) ((v)->counter)
+#define atomic_set(v, i) (((v)->counter) = i)
+
+static __inline__ void atomic_add(int i, atomic_t * v)
+{
+ long flags;
+
+ local_irq_save(flags);
+ v->counter += i;
+ local_irq_restore(flags);
+}
+
+static __inline__ void atomic_sub(int i, atomic_t * v)
+{
+ long flags;
+
+ local_irq_save(flags);
+ v->counter -= i;
+ local_irq_restore(flags);
+
+}
+
+static inline int atomic_add_return(int i, atomic_t * v)
+{
+ int __temp = 0;
+ long flags;
+
+ local_irq_save(flags);
+ v->counter += i;
+ __temp = v->counter;
+ local_irq_restore(flags);
+
+
+ return __temp;
+}
+
+#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
+static inline int atomic_sub_return(int i, atomic_t * v)
+{
+ int __temp = 0;
+ long flags;
+
+ local_irq_save(flags);
+ v->counter -= i;
+ __temp = v->counter;
+ local_irq_restore(flags);
+
+ return __temp;
+}
+
+static __inline__ void atomic_inc(volatile atomic_t * v)
+{
+ long flags;
+
+ local_irq_save(flags);
+ v->counter++;
+ local_irq_restore(flags);
+}
+
+#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_add_unless(v, a, u) \
+({ \
+ int c, old; \
+ c = atomic_read(v); \
+ while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+static __inline__ void atomic_dec(volatile atomic_t * v)
+{
+ long flags;
+
+ local_irq_save(flags);
+ v->counter--;
+ local_irq_restore(flags);
+}
+
+static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v)
+{
+ long flags;
+
+ local_irq_save(flags);
+ v->counter &= ~mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v)
+{
+ long flags;
+
+ local_irq_save(flags);
+ v->counter |= mask;
+ local_irq_restore(flags);
+}
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+/*
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
+
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+
+#include <asm-generic/atomic.h>
+
+#endif /* __ARCH_BLACKFIN_ATOMIC __ */
diff --git a/include/asm-blackfin/auxvec.h b/include/asm-blackfin/auxvec.h
new file mode 100644
index 00000000000..215506cd87b
--- /dev/null
+++ b/include/asm-blackfin/auxvec.h
@@ -0,0 +1,4 @@
+#ifndef __ASMBFIN_AUXVEC_H
+#define __ASMBFIN_AUXVEC_H
+
+#endif
diff --git a/include/asm-blackfin/bf5xx_timers.h b/include/asm-blackfin/bf5xx_timers.h
new file mode 100644
index 00000000000..86c770321b6
--- /dev/null
+++ b/include/asm-blackfin/bf5xx_timers.h
@@ -0,0 +1,209 @@
+/*
+ * include/asm/bf5xx_timers.h
+ *
+ * This file contains the major Data structures and constants
+ * used for General Purpose Timer Implementation in BF5xx
+ *
+ * Copyright (C) 2005 John DeHority
+ * Copyright (C) 2006 Hella Aglaia GmbH (awe@aglaia-gmbh.de)
+ *
+ */
+
+#ifndef _BLACKFIN_TIMERS_H_
+#define _BLACKFIN_TIMERS_H_
+
+#undef MAX_BLACKFIN_GPTIMERS
+/*
+ * BF537: 8 timers:
+ */
+#if defined(CONFIG_BF537)
+# define MAX_BLACKFIN_GPTIMERS 8
+# define TIMER0_GROUP_REG TIMER_ENABLE
+#endif
+/*
+ * BF561: 12 timers:
+ */
+#if defined(CONFIG_BF561)
+# define MAX_BLACKFIN_GPTIMERS 12
+# define TIMER0_GROUP_REG TMRS8_ENABLE
+# define TIMER8_GROUP_REG TMRS4_ENABLE
+#endif
+/*
+ * All others: 3 timers:
+ */
+#if !defined(MAX_BLACKFIN_GPTIMERS)
+# define MAX_BLACKFIN_GPTIMERS 3
+# define TIMER0_GROUP_REG TIMER_ENABLE
+#endif
+
+#define BLACKFIN_GPTIMER_IDMASK ((1UL << MAX_BLACKFIN_GPTIMERS) - 1)
+#define BFIN_TIMER_OCTET(x) ((x) >> 3)
+
+/* used in masks for timer_enable() and timer_disable() */
+#define TIMER0bit 0x0001 /* 0001b */
+#define TIMER1bit 0x0002 /* 0010b */
+#define TIMER2bit 0x0004 /* 0100b */
+
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER3bit 0x0008
+# define TIMER4bit 0x0010
+# define TIMER5bit 0x0020
+# define TIMER6bit 0x0040
+# define TIMER7bit 0x0080
+#endif
+
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER8bit 0x0100
+# define TIMER9bit 0x0200
+# define TIMER10bit 0x0400
+# define TIMER11bit 0x0800
+#endif
+
+#define TIMER0_id 0
+#define TIMER1_id 1
+#define TIMER2_id 2
+
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER3_id 3
+# define TIMER4_id 4
+# define TIMER5_id 5
+# define TIMER6_id 6
+# define TIMER7_id 7
+#endif
+
+#if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER8_id 8
+# define TIMER9_id 9
+# define TIMER10_id 10
+# define TIMER11_id 11
+#endif
+
+/* associated timers for ppi framesync: */
+
+#if defined(CONFIG_BF561)
+# define FS0_1_TIMER_ID TIMER8_id
+# define FS0_2_TIMER_ID TIMER9_id
+# define FS1_1_TIMER_ID TIMER10_id
+# define FS1_2_TIMER_ID TIMER11_id
+# define FS0_1_TIMER_BIT TIMER8bit
+# define FS0_2_TIMER_BIT TIMER9bit
+# define FS1_1_TIMER_BIT TIMER10bit
+# define FS1_2_TIMER_BIT TIMER11bit
+# undef FS1_TIMER_ID
+# undef FS2_TIMER_ID
+# undef FS1_TIMER_BIT
+# undef FS2_TIMER_BIT
+#else
+# define FS1_TIMER_ID TIMER0_id
+# define FS2_TIMER_ID TIMER1_id
+# define FS1_TIMER_BIT TIMER0bit
+# define FS2_TIMER_BIT TIMER1bit
+#endif
+
+/*
+** Timer Configuration Register Bits
+*/
+#define TIMER_ERR 0xC000
+#define TIMER_ERR_OVFL 0x4000
+#define TIMER_ERR_PROG_PER 0x8000
+#define TIMER_ERR_PROG_PW 0xC000
+#define TIMER_EMU_RUN 0x0200
+#define TIMER_TOGGLE_HI 0x0100
+#define TIMER_CLK_SEL 0x0080
+#define TIMER_OUT_DIS 0x0040
+#define TIMER_TIN_SEL 0x0020
+#define TIMER_IRQ_ENA 0x0010
+#define TIMER_PERIOD_CNT 0x0008
+#define TIMER_PULSE_HI 0x0004
+#define TIMER_MODE 0x0003
+#define TIMER_MODE_PWM 0x0001
+#define TIMER_MODE_WDTH 0x0002
+#define TIMER_MODE_EXT_CLK 0x0003
+
+/*
+** Timer Status Register Bits
+*/
+#define TIMER_STATUS_TIMIL0 0x0001
+#define TIMER_STATUS_TIMIL1 0x0002
+#define TIMER_STATUS_TIMIL2 0x0004
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER_STATUS_TIMIL3 0x00000008
+# define TIMER_STATUS_TIMIL4 0x00010000
+# define TIMER_STATUS_TIMIL5 0x00020000
+# define TIMER_STATUS_TIMIL6 0x00040000
+# define TIMER_STATUS_TIMIL7 0x00080000
+# if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER_STATUS_TIMIL8 0x0001
+# define TIMER_STATUS_TIMIL9 0x0002
+# define TIMER_STATUS_TIMIL10 0x0004
+# define TIMER_STATUS_TIMIL11 0x0008
+# endif
+# define TIMER_STATUS_INTR 0x000F000F
+#else
+# define TIMER_STATUS_INTR 0x0007 /* any timer interrupt */
+#endif
+
+#define TIMER_STATUS_TOVF0 0x0010 /* timer 0 overflow error */
+#define TIMER_STATUS_TOVF1 0x0020
+#define TIMER_STATUS_TOVF2 0x0040
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER_STATUS_TOVF3 0x00000080
+# define TIMER_STATUS_TOVF4 0x00100000
+# define TIMER_STATUS_TOVF5 0x00200000
+# define TIMER_STATUS_TOVF6 0x00400000
+# define TIMER_STATUS_TOVF7 0x00800000
+# if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER_STATUS_TOVF8 0x0010
+# define TIMER_STATUS_TOVF9 0x0020
+# define TIMER_STATUS_TOVF10 0x0040
+# define TIMER_STATUS_TOVF11 0x0080
+# endif
+# define TIMER_STATUS_OFLOW 0x00F000F0
+#else
+# define TIMER_STATUS_OFLOW 0x0070 /* any timer overflow */
+#endif
+
+/*
+** Timer Slave Enable Status : write 1 to clear
+*/
+#define TIMER_STATUS_TRUN0 0x1000
+#define TIMER_STATUS_TRUN1 0x2000
+#define TIMER_STATUS_TRUN2 0x4000
+#if (MAX_BLACKFIN_GPTIMERS > 3)
+# define TIMER_STATUS_TRUN3 0x00008000
+# define TIMER_STATUS_TRUN4 0x10000000
+# define TIMER_STATUS_TRUN5 0x20000000
+# define TIMER_STATUS_TRUN6 0x40000000
+# define TIMER_STATUS_TRUN7 0x80000000
+# define TIMER_STATUS_TRUN 0xF000F000
+# if (MAX_BLACKFIN_GPTIMERS > 8)
+# define TIMER_STATUS_TRUN8 0x1000
+# define TIMER_STATUS_TRUN9 0x2000
+# define TIMER_STATUS_TRUN10 0x4000
+# define TIMER_STATUS_TRUN11 0x8000
+# endif
+#else
+# define TIMER_STATUS_TRUN 0x7000
+#endif
+
+/*******************************************************************************
+* GP_TIMER API's
+*******************************************************************************/
+
+void set_gptimer_pwidth (int timer_id, int width);
+int get_gptimer_pwidth (int timer_id);
+void set_gptimer_period (int timer_id, int period);
+int get_gptimer_period (int timer_id);
+int get_gptimer_count (int timer_id);
+short get_gptimer_intr (int timer_id);
+void set_gptimer_config (int timer_id, short config);
+short get_gptimer_config (int timer_id);
+void set_gptimer_pulse_hi (int timer_id);
+void clear_gptimer_pulse_hi(int timer_id);
+void enable_gptimers (short mask);
+void disable_gptimers (short mask);
+short get_enabled_timers (void);
+int get_gptimer_status (int octet);
+void set_gptimer_status (int octet, int value);
+
+#endif
diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
new file mode 100644
index 00000000000..e37f81609fc
--- /dev/null
+++ b/include/asm-blackfin/bfin-global.h
@@ -0,0 +1,120 @@
+/*
+ * File: include/asm-blackfin/bfin-global.h
+ * Based on:
+ * Author: *
+ * Created:
+ * Description: Global extern defines for blackfin
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _BFIN_GLOBAL_H_
+#define _BFIN_GLOBAL_H_
+
+#ifndef __ASSEMBLY__
+
+#include <asm-generic/sections.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+#if defined(CONFIG_DMA_UNCACHED_2M)
+# define DMA_UNCACHED_REGION (2 * 1024 * 1024)
+#elif defined(CONFIG_DMA_UNCACHED_1M)
+# define DMA_UNCACHED_REGION (1024 * 1024)
+#else
+# define DMA_UNCACHED_REGION (0)
+#endif
+
+extern unsigned long get_cclk(void);
+extern unsigned long get_sclk(void);
+
+extern void dump_thread(struct pt_regs *regs, struct user *dump);
+extern void dump_bfin_regs(struct pt_regs *fp, void *retaddr);
+extern void dump_bfin_trace_buffer(void);
+
+extern int init_arch_irq(void);
+extern void bfin_reset(void);
+extern void _cplb_hdr(void);
+/* Blackfin cache functions */
+extern void bfin_icache_init(void);
+extern void bfin_dcache_init(void);
+extern int read_iloc(void);
+extern int bfin_console_init(void);
+extern asmlinkage void lower_to_irq14(void);
+extern void init_dma(void);
+extern void program_IAR(void);
+extern void evt14_softirq(void);
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type);
+
+extern void *l1_data_A_sram_alloc(size_t);
+extern void *l1_data_B_sram_alloc(size_t);
+extern void *l1_inst_sram_alloc(size_t);
+extern void *l1_data_sram_alloc(size_t);
+extern void *l1_data_sram_zalloc(size_t);
+extern int l1_data_A_sram_free(const void*);
+extern int l1_data_B_sram_free(const void*);
+extern int l1_inst_sram_free(const void*);
+extern int l1_data_sram_free(const void*);
+extern int sram_free(const void*);
+
+#define L1_INST_SRAM 0x00000001
+#define L1_DATA_A_SRAM 0x00000002
+#define L1_DATA_B_SRAM 0x00000004
+#define L1_DATA_SRAM 0x00000006
+extern void *sram_alloc_with_lsl(size_t, unsigned long);
+extern int sram_free_with_lsl(const void*);
+
+extern void led_on(int);
+extern void led_off(int);
+extern void led_toggle(int);
+extern void led_disp_num(int);
+extern void led_toggle_num(int);
+extern void init_leds(void);
+
+extern char *bfin_board_name __attribute__ ((weak));
+extern unsigned long wall_jiffies;
+extern unsigned long ipdt_table[];
+extern unsigned long dpdt_table[];
+extern unsigned long icplb_table[];
+extern unsigned long dcplb_table[];
+
+extern unsigned long ipdt_swapcount_table[];
+extern unsigned long dpdt_swapcount_table[];
+
+extern unsigned long table_start, table_end;
+
+extern struct file_operations dpmc_fops;
+extern char _start;
+extern unsigned long _ramstart, _ramend, _rambase;
+extern unsigned long memory_start, memory_end, physical_mem_end;
+extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
+ _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _ebss_b_l1[];
+
+#ifdef CONFIG_MTD_UCLINUX
+extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
+#endif
+
+#endif
+
+#endif /* _BLACKFIN_H_ */
diff --git a/include/asm-blackfin/bfin5xx_spi.h b/include/asm-blackfin/bfin5xx_spi.h
new file mode 100644
index 00000000000..95c1c952e7c
--- /dev/null
+++ b/include/asm-blackfin/bfin5xx_spi.h
@@ -0,0 +1,170 @@
+/************************************************************
+*
+* Copyright (C) 2004, Analog Devices. All Rights Reserved
+*
+* FILE bfin5xx_spi.h
+* PROGRAMMER(S): Luke Yang (Analog Devices Inc.)
+*
+*
+* DATE OF CREATION: March. 10th 2006
+*
+* SYNOPSIS:
+*
+* DESCRIPTION: header file for SPI controller driver for Blackfin5xx.
+**************************************************************
+
+* MODIFICATION HISTORY:
+* March 10, 2006 bfin5xx_spi.h Created. (Luke Yang)
+
+************************************************************/
+
+#ifndef _SPI_CHANNEL_H_
+#define _SPI_CHANNEL_H_
+
+#define SPI0_REGBASE 0xffc00500
+
+#define SPI_READ 0
+#define SPI_WRITE 1
+
+#define SPI_CTRL_OFF 0x0
+#define SPI_FLAG_OFF 0x4
+#define SPI_STAT_OFF 0x8
+#define SPI_TXBUFF_OFF 0xc
+#define SPI_RXBUFF_OFF 0x10
+#define SPI_BAUD_OFF 0x14
+#define SPI_SHAW_OFF 0x18
+
+#define CMD_SPI_OUT_ENABLE 1
+#define CMD_SPI_SET_BAUDRATE 2
+#define CMD_SPI_SET_POLAR 3
+#define CMD_SPI_SET_PHASE 4
+#define CMD_SPI_SET_MASTER 5
+#define CMD_SPI_SET_SENDOPT 6
+#define CMD_SPI_SET_RECVOPT 7
+#define CMD_SPI_SET_ORDER 8
+#define CMD_SPI_SET_LENGTH16 9
+#define CMD_SPI_GET_STAT 11
+#define CMD_SPI_GET_CFG 12
+#define CMD_SPI_SET_CSAVAIL 13
+#define CMD_SPI_SET_CSHIGH 14 /* CS unavail */
+#define CMD_SPI_SET_CSLOW 15 /* CS avail */
+#define CMD_SPI_MISO_ENABLE 16
+#define CMD_SPI_SET_CSENABLE 17
+#define CMD_SPI_SET_CSDISABLE 18
+
+#define CMD_SPI_SET_TRIGGER_MODE 19
+#define CMD_SPI_SET_TRIGGER_SENSE 20
+#define CMD_SPI_SET_TRIGGER_EDGE 21
+#define CMD_SPI_SET_TRIGGER_LEVEL 22
+
+#define CMD_SPI_SET_TIME_SPS 23
+#define CMD_SPI_SET_TIME_SAMPLES 24
+#define CMD_SPI_GET_SYSTEMCLOCK 25
+
+#define CMD_SPI_SET_WRITECONTINUOUS 26
+#define CMD_SPI_SET_SKFS 27
+
+#define CMD_SPI_GET_ALLCONFIG 32 /* For debug */
+
+#define SPI_DEFAULT_BARD 0x0100
+
+#define SPI0_IRQ_NUM IRQ_SPI
+#define SPI_ERR_TRIG -1
+
+#define BIT_CTL_ENABLE 0x4000
+#define BIT_CTL_OPENDRAIN 0x2000
+#define BIT_CTL_MASTER 0x1000
+#define BIT_CTL_POLAR 0x0800
+#define BIT_CTL_PHASE 0x0400
+#define BIT_CTL_BITORDER 0x0200
+#define BIT_CTL_WORDSIZE 0x0100
+#define BIT_CTL_MISOENABLE 0x0020
+#define BIT_CTL_RXMOD 0x0000
+#define BIT_CTL_TXMOD 0x0001
+#define BIT_CTL_TIMOD_DMA_TX 0x0003
+#define BIT_CTL_TIMOD_DMA_RX 0x0002
+#define BIT_CTL_SENDOPT 0x0004
+#define BIT_CTL_TIMOD 0x0003
+
+#define BIT_STAT_SPIF 0x0001
+#define BIT_STAT_MODF 0x0002
+#define BIT_STAT_TXE 0x0004
+#define BIT_STAT_TXS 0x0008
+#define BIT_STAT_RBSY 0x0010
+#define BIT_STAT_RXS 0x0020
+#define BIT_STAT_TXCOL 0x0040
+#define BIT_STAT_CLR 0xFFFF
+
+#define BIT_STU_SENDOVER 0x0001
+#define BIT_STU_RECVFULL 0x0020
+
+#define CFG_SPI_ENABLE 1
+#define CFG_SPI_DISABLE 0
+
+#define CFG_SPI_OUTENABLE 1
+#define CFG_SPI_OUTDISABLE 0
+
+#define CFG_SPI_ACTLOW 1
+#define CFG_SPI_ACTHIGH 0
+
+#define CFG_SPI_PHASESTART 1
+#define CFG_SPI_PHASEMID 0
+
+#define CFG_SPI_MASTER 1
+#define CFG_SPI_SLAVE 0
+
+#define CFG_SPI_SENELAST 0
+#define CFG_SPI_SENDZERO 1
+
+#define CFG_SPI_RCVFLUSH 1
+#define CFG_SPI_RCVDISCARD 0
+
+#define CFG_SPI_LSBFIRST 1
+#define CFG_SPI_MSBFIRST 0
+
+#define CFG_SPI_WORDSIZE16 1
+#define CFG_SPI_WORDSIZE8 0
+
+#define CFG_SPI_MISOENABLE 1
+#define CFG_SPI_MISODISABLE 0
+
+#define CFG_SPI_READ 0x00
+#define CFG_SPI_WRITE 0x01
+#define CFG_SPI_DMAREAD 0x02
+#define CFG_SPI_DMAWRITE 0x03
+
+#define CFG_SPI_CSCLEARALL 0
+#define CFG_SPI_CHIPSEL1 1
+#define CFG_SPI_CHIPSEL2 2
+#define CFG_SPI_CHIPSEL3 3
+#define CFG_SPI_CHIPSEL4 4
+#define CFG_SPI_CHIPSEL5 5
+#define CFG_SPI_CHIPSEL6 6
+#define CFG_SPI_CHIPSEL7 7
+
+#define CFG_SPI_CS1VALUE 1
+#define CFG_SPI_CS2VALUE 2
+#define CFG_SPI_CS3VALUE 3
+#define CFG_SPI_CS4VALUE 4
+#define CFG_SPI_CS5VALUE 5
+#define CFG_SPI_CS6VALUE 6
+#define CFG_SPI_CS7VALUE 7
+
+/* device.platform_data for SSP controller devices */
+struct bfin5xx_spi_master {
+ u16 num_chipselect;
+ u8 enable_dma;
+};
+
+/* spi_board_info.controller_data for SPI slave devices,
+ * copied to spi_device.platform_data ... mostly for dma tuning
+ */
+struct bfin5xx_spi_chip {
+ u16 ctl_reg;
+ u8 enable_dma;
+ u8 bits_per_word;
+ u8 cs_change_per_word;
+ u8 cs_chg_udelay;
+};
+
+#endif /* _SPI_CHANNEL_H_ */
diff --git a/include/asm-blackfin/bfin_simple_timer.h b/include/asm-blackfin/bfin_simple_timer.h
new file mode 100644
index 00000000000..fccbb595464
--- /dev/null
+++ b/include/asm-blackfin/bfin_simple_timer.h
@@ -0,0 +1,13 @@
+#ifndef _bfin_simple_timer_h_
+#define _bfin_simple_timer_h_
+
+#include <linux/ioctl.h>
+
+#define BFIN_SIMPLE_TIMER_IOCTL_MAGIC 't'
+
+#define BFIN_SIMPLE_TIMER_SET_PERIOD _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 2)
+#define BFIN_SIMPLE_TIMER_START _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 6)
+#define BFIN_SIMPLE_TIMER_STOP _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 8)
+#define BFIN_SIMPLE_TIMER_READ _IO (BFIN_SIMPLE_TIMER_IOCTL_MAGIC, 10)
+
+#endif
diff --git a/include/asm-blackfin/bfin_sport.h b/include/asm-blackfin/bfin_sport.h
new file mode 100644
index 00000000000..c76ed8def30
--- /dev/null
+++ b/include/asm-blackfin/bfin_sport.h
@@ -0,0 +1,175 @@
+/*
+ * File: include/asm-blackfin/bfin_sport.h
+ * Based on:
+ * Author: Roy Huang (roy.huang@analog.com)
+ *
+ * Created: Thu Aug. 24 2006
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __BFIN_SPORT_H__
+#define __BFIN_SPORT_H__
+
+#define SPORT_MAJOR 237
+#define SPORT_NR_DEVS 2
+
+/* Sport mode: it can be set to TDM, i2s or others */
+#define NORM_MODE 0x0
+#define TDM_MODE 0x1
+#define I2S_MODE 0x2
+
+/* Data format, normal, a-law or u-law */
+#define NORM_FORMAT 0x0
+#define ALAW_FORMAT 0x2
+#define ULAW_FORMAT 0x3
+struct sport_register;
+
+/* Function driver which use sport must initialize the structure */
+struct sport_config {
+ /*TDM (multichannels), I2S or other mode */
+ unsigned int mode:3;
+
+ /* if TDM mode is selected, channels must be set */
+ int channels; /* Must be in 8 units */
+ unsigned int frame_delay:4; /* Delay between frame sync pulse and first bit */
+
+ /* I2S mode */
+ unsigned int right_first:1; /* Right stereo channel first */
+
+ /* In mormal mode, the following item need to be set */
+ unsigned int lsb_first:1; /* order of transmit or receive data */
+ unsigned int fsync:1; /* Frame sync required */
+ unsigned int data_indep:1; /* data independent frame sync generated */
+ unsigned int act_low:1; /* Active low TFS */
+ unsigned int late_fsync:1; /* Late frame sync */
+ unsigned int tckfe:1;
+ unsigned int sec_en:1; /* Secondary side enabled */
+
+ /* Choose clock source */
+ unsigned int int_clk:1; /* Internal or external clock */
+
+ /* If external clock is used, the following fields are ignored */
+ int serial_clk;
+ int fsync_clk;
+
+ unsigned int data_format:2; /*Normal, u-law or a-law */
+
+ int word_len; /* How length of the word in bits, 3-32 bits */
+ int dma_enabled;
+};
+
+struct sport_register {
+ unsigned short tcr1;
+ unsigned short reserved0;
+ unsigned short tcr2;
+ unsigned short reserved1;
+ unsigned short tclkdiv;
+ unsigned short reserved2;
+ unsigned short tfsdiv;
+ unsigned short reserved3;
+ unsigned long tx;
+ unsigned long reserved_l0;
+ unsigned long rx;
+ unsigned long reserved_l1;
+ unsigned short rcr1;
+ unsigned short reserved4;
+ unsigned short rcr2;
+ unsigned short reserved5;
+ unsigned short rclkdiv;
+ unsigned short reserved6;
+ unsigned short rfsdiv;
+ unsigned short reserved7;
+ unsigned short stat;
+ unsigned short reserved8;
+ unsigned short chnl;
+ unsigned short reserved9;
+ unsigned short mcmc1;
+ unsigned short reserved10;
+ unsigned short mcmc2;
+ unsigned short reserved11;
+ unsigned long mtcs0;
+ unsigned long mtcs1;
+ unsigned long mtcs2;
+ unsigned long mtcs3;
+ unsigned long mrcs0;
+ unsigned long mrcs1;
+ unsigned long mrcs2;
+ unsigned long mrcs3;
+};
+
+#define SPORT_IOC_MAGIC 'P'
+#define SPORT_IOC_CONFIG _IOWR('P', 0x01, struct sport_config)
+
+/* Test purpose */
+#define ENABLE_AD73311 _IOWR('P', 0x02, int)
+
+struct sport_dev {
+ struct cdev cdev; /* Char device structure */
+
+ int sport_num;
+
+ int dma_rx_chan;
+ int dma_tx_chan;
+
+ int rx_irq;
+ unsigned char *rx_buf; /* Buffer store the received data */
+ int rx_len; /* How many bytes will be received */
+ int rx_received; /* How many bytes has been received */
+
+ int tx_irq;
+ const unsigned char *tx_buf;
+ int tx_len;
+ int tx_sent;
+
+ int sport_err_irq;
+
+ struct mutex mutex; /* mutual exclusion semaphore */
+ struct task_struct *task;
+
+ wait_queue_head_t waitq;
+ int wait_con;
+ struct sport_register *regs;
+ struct sport_config config;
+};
+
+#define SPORT_TCR1 0
+#define SPORT_TCR2 1
+#define SPORT_TCLKDIV 2
+#define SPORT_TFSDIV 3
+#define SPORT_RCR1 8
+#define SPORT_RCR2 9
+#define SPORT_RCLKDIV 10
+#define SPORT_RFSDIV 11
+#define SPORT_CHANNEL 13
+#define SPORT_MCMC1 14
+#define SPORT_MCMC2 15
+#define SPORT_MTCS0 16
+#define SPORT_MTCS1 17
+#define SPORT_MTCS2 18
+#define SPORT_MTCS3 19
+#define SPORT_MRCS0 20
+#define SPORT_MRCS1 21
+#define SPORT_MRCS2 22
+#define SPORT_MRCS3 23
+
+#endif /*__BFIN_SPORT_H__*/
diff --git a/include/asm-blackfin/bitops.h b/include/asm-blackfin/bitops.h
new file mode 100644
index 00000000000..27c2d0e48e1
--- /dev/null
+++ b/include/asm-blackfin/bitops.h
@@ -0,0 +1,213 @@
+#ifndef _BLACKFIN_BITOPS_H
+#define _BLACKFIN_BITOPS_H
+
+/*
+ * Copyright 1992, Linus Torvalds.
+ */
+
+#include <linux/compiler.h>
+#include <asm/byteorder.h> /* swab32 */
+#include <asm/system.h> /* save_flags */
+
+#ifdef __KERNEL__
+
+#include <asm-generic/bitops/ffs.h>
+#include <asm-generic/bitops/__ffs.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ffz.h>
+
+static __inline__ void set_bit(int nr, volatile unsigned long *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+ unsigned long flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ local_irq_save(flags);
+ *a |= mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void __set_bit(int nr, volatile unsigned long *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a |= mask;
+}
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+#define smp_mb__before_clear_bit() barrier()
+#define smp_mb__after_clear_bit() barrier()
+
+static __inline__ void clear_bit(int nr, volatile unsigned long *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+ unsigned long flags;
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ local_irq_save(flags);
+ *a &= ~mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ *a &= ~mask;
+}
+
+static __inline__ void change_bit(int nr, volatile unsigned long *addr)
+{
+ int mask, flags;
+ unsigned long *ADDR = (unsigned long *)addr;
+
+ ADDR += nr >> 5;
+ mask = 1 << (nr & 31);
+ local_irq_save(flags);
+ *ADDR ^= mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void __change_bit(int nr, volatile unsigned long *addr)
+{
+ int mask;
+ unsigned long *ADDR = (unsigned long *)addr;
+
+ ADDR += nr >> 5;
+ mask = 1 << (nr & 31);
+ *ADDR ^= mask;
+}
+
+static __inline__ int test_and_set_bit(int nr, void *addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = (volatile unsigned int *)addr;
+ unsigned long flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ local_irq_save(flags);
+ retval = (mask & *a) != 0;
+ *a |= mask;
+ local_irq_restore(flags);
+
+ return retval;
+}
+
+static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = (volatile unsigned int *)addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a |= mask;
+ return retval;
+}
+
+static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = (volatile unsigned int *)addr;
+ unsigned long flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ local_irq_save(flags);
+ retval = (mask & *a) != 0;
+ *a &= ~mask;
+ local_irq_restore(flags);
+
+ return retval;
+}
+
+static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = (volatile unsigned int *)addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a &= ~mask;
+ return retval;
+}
+
+static __inline__ int test_and_change_bit(int nr, volatile unsigned long *addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = (volatile unsigned int *)addr;
+ unsigned long flags;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ local_irq_save(flags);
+ retval = (mask & *a) != 0;
+ *a ^= mask;
+ local_irq_restore(flags);
+ return retval;
+}
+
+static __inline__ int __test_and_change_bit(int nr,
+ volatile unsigned long *addr)
+{
+ int mask, retval;
+ volatile unsigned int *a = (volatile unsigned int *)addr;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ retval = (mask & *a) != 0;
+ *a ^= mask;
+ return retval;
+}
+
+/*
+ * This routine doesn't need to be atomic.
+ */
+static __inline__ int __constant_test_bit(int nr, const void *addr)
+{
+ return ((1UL << (nr & 31)) &
+ (((const volatile unsigned int *)addr)[nr >> 5])) != 0;
+}
+
+static __inline__ int __test_bit(int nr, const void *addr)
+{
+ int *a = (int *)addr;
+ int mask;
+
+ a += nr >> 5;
+ mask = 1 << (nr & 0x1f);
+ return ((mask & *a) != 0);
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ __constant_test_bit((nr),(addr)) : \
+ __test_bit((nr),(addr)))
+
+#include <asm-generic/bitops/find.h>
+#include <asm-generic/bitops/hweight.h>
+
+#include <asm-generic/bitops/ext2-atomic.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+
+#include <asm-generic/bitops/minix.h>
+
+#endif /* __KERNEL__ */
+
+#include <asm-generic/bitops/fls.h>
+#include <asm-generic/bitops/fls64.h>
+
+#endif /* _BLACKFIN_BITOPS_H */
diff --git a/include/asm-blackfin/blackfin.h b/include/asm-blackfin/blackfin.h
new file mode 100644
index 00000000000..14e58de7397
--- /dev/null
+++ b/include/asm-blackfin/blackfin.h
@@ -0,0 +1,81 @@
+/*
+ * Common header file for blackfin family of processors.
+ *
+ */
+
+#ifndef _BLACKFIN_H_
+#define _BLACKFIN_H_
+
+#include <asm/macros.h>
+#include <asm/mach/blackfin.h>
+#include <asm/bfin-global.h>
+
+#ifndef __ASSEMBLY__
+
+/* SSYNC implementation for C file */
+#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+ int _tmp;
+ __asm__ __volatile__ ("cli %0;\n\t"
+ "nop;nop;\n\t"
+ "ssync;\n\t"
+ "sti %0;\n\t"
+ :"=d"(_tmp):);
+}
+#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+ int _tmp;
+ __asm__ __volatile__ ("cli %0;\n\t"
+ "ssync;\n\t"
+ "sti %0;\n\t"
+ :"=d"(_tmp):);
+}
+#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+ __builtin_bfin_ssync();
+}
+#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void SSYNC (void)
+{
+ __asm__ __volatile__ ("ssync;\n\t");
+}
+#endif
+
+/* CSYNC implementation for C file */
+#if defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+ int _tmp;
+ __asm__ __volatile__ ("cli %0;\n\t"
+ "nop;nop;\n\t"
+ "csync;\n\t"
+ "sti %0;\n\t"
+ :"=d"(_tmp):);
+}
+#elif defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+ int _tmp;
+ __asm__ __volatile__ ("cli %0;\n\t"
+ "csync;\n\t"
+ "sti %0;\n\t"
+ :"=d"(_tmp):);
+}
+#elif !defined(ANOMALY_05000312) && defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+ __builtin_bfin_csync();
+}
+#elif !defined(ANOMALY_05000312) && !defined(ANOMALY_05000244)
+static inline void CSYNC (void)
+{
+ __asm__ __volatile__ ("csync;\n\t");
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _BLACKFIN_H_ */
diff --git a/include/asm-blackfin/bug.h b/include/asm-blackfin/bug.h
new file mode 100644
index 00000000000..41e53b29f16
--- /dev/null
+++ b/include/asm-blackfin/bug.h
@@ -0,0 +1,4 @@
+#ifndef _BLACKFIN_BUG_H
+#define _BLACKFIN_BUG_H
+#include <asm-generic/bug.h>
+#endif
diff --git a/include/asm-blackfin/bugs.h b/include/asm-blackfin/bugs.h
new file mode 100644
index 00000000000..9093c9c1fb8
--- /dev/null
+++ b/include/asm-blackfin/bugs.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-blackfin/bugs.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ */
+
+/*
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Needs:
+ * void check_bugs(void);
+ */
+
+static void check_bugs(void)
+{
+}
diff --git a/include/asm-blackfin/byteorder.h b/include/asm-blackfin/byteorder.h
new file mode 100644
index 00000000000..6a673d42da1
--- /dev/null
+++ b/include/asm-blackfin/byteorder.h
@@ -0,0 +1,48 @@
+#ifndef _BLACKFIN_BYTEORDER_H
+#define _BLACKFIN_BYTEORDER_H
+
+#include <asm/types.h>
+#include <linux/compiler.h>
+
+#ifdef __GNUC__
+
+static __inline__ __attribute_const__ __u32 ___arch__swahb32(__u32 xx)
+{
+ __u32 tmp;
+ __asm__("%1 = %0 >> 8 (V);\n\t"
+ "%0 = %0 << 8 (V);\n\t"
+ "%0 = %0 | %1;\n\t"
+ : "+d"(xx), "=&d"(tmp));
+ return xx;
+}
+
+static __inline__ __attribute_const__ __u32 ___arch__swahw32(__u32 xx)
+{
+ __u32 rv;
+ __asm__("%0 = PACK(%1.L, %1.H);\n\t": "=d"(rv): "d"(xx));
+ return rv;
+}
+
+#define __arch__swahb32(x) ___arch__swahb32(x)
+#define __arch__swahw32(x) ___arch__swahw32(x)
+#define __arch__swab32(x) ___arch__swahb32(___arch__swahw32(x))
+
+static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 xx)
+{
+ __u32 xw = xx;
+ __asm__("%0 <<= 8;\n %0.L = %0.L + %0.H (NS);\n": "+d"(xw));
+ return (__u16)xw;
+}
+
+#define __arch__swab16(x) ___arch__swab16(x)
+
+#endif
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+# define __BYTEORDER_HAS_U64__
+# define __SWAB_64_THRU_32__
+#endif
+
+#include <linux/byteorder/little_endian.h>
+
+#endif /* _BLACKFIN_BYTEORDER_H */
diff --git a/include/asm-blackfin/cache.h b/include/asm-blackfin/cache.h
new file mode 100644
index 00000000000..023d72133b5
--- /dev/null
+++ b/include/asm-blackfin/cache.h
@@ -0,0 +1,29 @@
+/*
+ * include/asm-blackfin/cache.h
+ */
+#ifndef __ARCH_BLACKFIN_CACHE_H
+#define __ARCH_BLACKFIN_CACHE_H
+
+/*
+ * Bytes per L1 cache line
+ * Blackfin loads 32 bytes for cache
+ */
+#define L1_CACHE_SHIFT 5
+#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
+
+/*
+ * Put cacheline_aliged data to L1 data memory
+ */
+#ifdef CONFIG_CACHELINE_ALIGNED_L1
+#define __cacheline_aligned \
+ __attribute__((__aligned__(L1_CACHE_BYTES), \
+ __section__(".data_l1.cacheline_aligned")))
+#endif
+
+/*
+ * largest L1 which this arch supports
+ */
+#define L1_CACHE_SHIFT_MAX 5
+
+#endif
diff --git a/include/asm-blackfin/cacheflush.h b/include/asm-blackfin/cacheflush.h
new file mode 100644
index 00000000000..e5e000de3c3
--- /dev/null
+++ b/include/asm-blackfin/cacheflush.h
@@ -0,0 +1,90 @@
+/*
+ * File: include/asm-blackfin/cacheflush.h
+ * Based on: include/asm-m68knommu/cacheflush.h
+ * Author: LG Soft India
+ * Copyright (C) 2004 Analog Devices Inc.
+ * Created: Tue Sep 21 2004
+ * Description: Blackfin low-level cache routines adapted from the i386
+ * and PPC versions by Greg Ungerer (gerg@snapgear.com)
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BLACKFIN_CACHEFLUSH_H
+#define _BLACKFIN_CACHEFLUSH_H
+
+#include <asm/cplb.h>
+
+extern void blackfin_icache_dcache_flush_range(unsigned int, unsigned int);
+extern void blackfin_icache_flush_range(unsigned int, unsigned int);
+extern void blackfin_dcache_flush_range(unsigned int, unsigned int);
+extern void blackfin_dcache_invalidate_range(unsigned int, unsigned int);
+extern void blackfin_dflush_page(void *);
+
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_range(vma, start, end) do { } while (0)
+#define flush_cache_page(vma, vmaddr) do { } while (0)
+#define flush_cache_vmap(start, end) do { } while (0)
+#define flush_cache_vunmap(start, end) do { } while (0)
+
+static inline void flush_icache_range(unsigned start, unsigned end)
+{
+#if defined(CONFIG_BLKFIN_DCACHE) && defined(CONFIG_BLKFIN_CACHE)
+
+# if defined(CONFIG_BLKFIN_WT)
+ blackfin_icache_flush_range((start), (end));
+# else
+ blackfin_icache_dcache_flush_range((start), (end));
+# endif
+
+#else
+
+# if defined(CONFIG_BLKFIN_CACHE)
+ blackfin_icache_flush_range((start), (end));
+# endif
+# if defined(CONFIG_BLKFIN_DCACHE)
+ blackfin_dcache_flush_range((start), (end));
+# endif
+
+#endif
+}
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+do { memcpy(dst, src, len); \
+ flush_icache_range ((unsigned) (dst), (unsigned) (dst) + (len)); \
+} while (0)
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len)
+
+#if defined(CONFIG_BLKFIN_DCACHE)
+# define invalidate_dcache_range(start,end) blackfin_dcache_invalidate_range((start), (end))
+#else
+# define invalidate_dcache_range(start,end) do { } while (0)
+#endif
+#if defined(CONFIG_BLKFIN_DCACHE) && defined(CONFIG_BLKFIN_WB)
+# define flush_dcache_range(start,end) blackfin_dcache_flush_range((start), (end))
+# define flush_dcache_page(page) blackfin_dflush_page(page_address(page))
+#else
+# define flush_dcache_range(start,end) do { } while (0)
+# define flush_dcache_page(page) do { } while (0)
+#endif
+
+#endif /* _BLACKFIN_CACHEFLUSH_H */
diff --git a/include/asm-blackfin/checksum.h b/include/asm-blackfin/checksum.h
new file mode 100644
index 00000000000..2638f2586d2
--- /dev/null
+++ b/include/asm-blackfin/checksum.h
@@ -0,0 +1,101 @@
+#ifndef _BFIN_CHECKSUM_H
+#define _BFIN_CHECKSUM_H
+
+/*
+ * MODIFIED FOR BFIN April 30, 2001 akbar.hussain@lineo.com
+ *
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+unsigned int csum_partial(const unsigned char *buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
+ int len, int sum);
+
+/*
+ * the same as csum_partial_copy, but copies from user space.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+extern unsigned int csum_partial_copy_from_user(const unsigned char *src,
+ unsigned char *dst, int len,
+ int sum, int *csum_err);
+
+#define csum_partial_copy_nocheck(src, dst, len, sum) \
+ csum_partial_copy((src), (dst), (len), (sum))
+
+unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl);
+
+/*
+ * Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+ return ((~(sum << 16)) >> 16);
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+
+static inline unsigned int
+csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
+ unsigned short proto, unsigned int sum)
+{
+
+ __asm__ ("%0 = %0 + %1;\n\t"
+ "CC = AC0;\n\t"
+ "if !CC jump 4;\n\t"
+ "%0 = %0 + %4;\n\t"
+ "%0 = %0 + %2;\n\t"
+ "CC = AC0;\n\t"
+ "if !CC jump 4;\n\t"
+ "%0 = %0 + %4;\n\t"
+ "%0 = %0 + %3;\n\t"
+ "CC = AC0;\n\t"
+ "if !CC jump 4;\n\t"
+ "%0 = %0 + %4;\n\t"
+ "NOP;\n\t"
+ : "=d" (sum)
+ : "d" (daddr), "d" (saddr), "d" ((ntohs(len)<<16)+proto*256), "d" (1), "0"(sum));
+
+ return (sum);
+}
+
+static inline unsigned short int
+csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len,
+ unsigned short proto, unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+extern unsigned short ip_compute_csum(const unsigned char *buff, int len);
+
+#endif /* _BFIN_CHECKSUM_H */
diff --git a/include/asm-blackfin/cplb.h b/include/asm-blackfin/cplb.h
new file mode 100644
index 00000000000..e0dd56bfa4c
--- /dev/null
+++ b/include/asm-blackfin/cplb.h
@@ -0,0 +1,51 @@
+/************************************************************************
+ *
+ * cplb.h
+ *
+ * (c) Copyright 2002-2003 Analog Devices, Inc. All rights reserved.
+ *
+ ************************************************************************/
+
+/* Defines necessary for cplb initialisation routines. */
+
+#ifndef _CPLB_H
+#define _CPLB_H
+
+# include <asm/blackfin.h>
+
+#define CPLB_ENABLE_ICACHE_P 0
+#define CPLB_ENABLE_DCACHE_P 1
+#define CPLB_ENABLE_DCACHE2_P 2
+#define CPLB_ENABLE_CPLBS_P 3 /* Deprecated! */
+#define CPLB_ENABLE_ICPLBS_P 4
+#define CPLB_ENABLE_DCPLBS_P 5
+
+#define CPLB_ENABLE_ICACHE (1<<CPLB_ENABLE_ICACHE_P)
+#define CPLB_ENABLE_DCACHE (1<<CPLB_ENABLE_DCACHE_P)
+#define CPLB_ENABLE_DCACHE2 (1<<CPLB_ENABLE_DCACHE2_P)
+#define CPLB_ENABLE_CPLBS (1<<CPLB_ENABLE_CPLBS_P)
+#define CPLB_ENABLE_ICPLBS (1<<CPLB_ENABLE_ICPLBS_P)
+#define CPLB_ENABLE_DCPLBS (1<<CPLB_ENABLE_DCPLBS_P)
+#define CPLB_ENABLE_ANY_CPLBS CPLB_ENABLE_CPLBS | \
+ CPLB_ENABLE_ICPLBS | \
+ CPLB_ENABLE_DCPLBS
+
+#define CPLB_RELOADED 0x0000
+#define CPLB_NO_UNLOCKED 0x0001
+#define CPLB_NO_ADDR_MATCH 0x0002
+#define CPLB_PROT_VIOL 0x0003
+#define CPLB_UNKNOWN_ERR 0x0004
+
+#define CPLB_DEF_CACHE CPLB_L1_CHBL | CPLB_WT
+#define CPLB_CACHE_ENABLED CPLB_L1_CHBL | CPLB_DIRTY
+
+#define CPLB_ALL_ACCESS CPLB_SUPV_WR | CPLB_USER_RD | CPLB_USER_WR
+
+#define CPLB_I_PAGE_MGMT CPLB_LOCK | CPLB_VALID
+#define CPLB_D_PAGE_MGMT CPLB_LOCK | CPLB_ALL_ACCESS | CPLB_VALID
+#define CPLB_DNOCACHE CPLB_ALL_ACCESS | CPLB_VALID
+#define CPLB_DDOCACHE CPLB_DNOCACHE | CPLB_DEF_CACHE
+#define CPLB_INOCACHE CPLB_USER_RD | CPLB_VALID
+#define CPLB_IDOCACHE CPLB_INOCACHE | CPLB_L1_CHBL
+
+#endif /* _CPLB_H */
diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h
new file mode 100644
index 00000000000..3bad2d1e6a8
--- /dev/null
+++ b/include/asm-blackfin/cplbinit.h
@@ -0,0 +1,203 @@
+/*
+ * File: include/asm-blackfin/cplbinit.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <asm/blackfin.h>
+#include <asm/cplb.h>
+
+#define INITIAL_T 0x1
+#define SWITCH_T 0x2
+#define I_CPLB 0x4
+#define D_CPLB 0x8
+
+#define IN_KERNEL 1
+
+enum
+{ZERO_P, L1I_MEM, L1D_MEM, SDRAM_KERN , SDRAM_RAM_MTD, SDRAM_DMAZ, RES_MEM, ASYNC_MEM, L2_MEM};
+
+struct cplb_desc {
+ u32 start; /* start address */
+ u32 end; /* end address */
+ u32 psize; /* prefered size if any otherwise 1MB or 4MB*/
+ u16 attr;/* attributes */
+ u16 i_conf;/* I-CPLB DATA */
+ u16 d_conf;/* D-CPLB DATA */
+ u16 valid;/* valid */
+ const s8 name[30];/* name */
+};
+
+struct cplb_tab {
+ u_long *tab;
+ u16 pos;
+ u16 size;
+};
+
+u_long icplb_table[MAX_CPLBS+1];
+u_long dcplb_table[MAX_CPLBS+1];
+
+/* Till here we are discussing about the static memory management model.
+ * However, the operating envoronments commonly define more CPLB
+ * descriptors to cover the entire addressable memory than will fit into
+ * the available on-chip 16 CPLB MMRs. When this happens, the below table
+ * will be used which will hold all the potentially required CPLB descriptors
+ *
+ * This is how Page descriptor Table is implemented in uClinux/Blackfin.
+ */
+
+#ifdef CONFIG_CPLB_SWITCH_TAB_L1
+u_long ipdt_table[MAX_SWITCH_I_CPLBS+1]__attribute__((l1_data));
+u_long dpdt_table[MAX_SWITCH_D_CPLBS+1]__attribute__((l1_data));
+
+#ifdef CONFIG_CPLB_INFO
+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS]__attribute__((l1_data));
+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS]__attribute__((l1_data));
+#endif /* CONFIG_CPLB_INFO */
+
+#else
+
+u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
+u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];
+
+#ifdef CONFIG_CPLB_INFO
+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS];
+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS];
+#endif /* CONFIG_CPLB_INFO */
+
+#endif /*CONFIG_CPLB_SWITCH_TAB_L1*/
+
+struct s_cplb {
+ struct cplb_tab init_i;
+ struct cplb_tab init_d;
+ struct cplb_tab switch_i;
+ struct cplb_tab switch_d;
+};
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+static struct cplb_desc cplb_data[] = {
+ {
+ .start = 0,
+ .end = SIZE_4K,
+ .psize = SIZE_4K,
+ .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+ .i_conf = SDRAM_OOPS,
+ .d_conf = SDRAM_OOPS,
+#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
+ .valid = 1,
+#else
+ .valid = 0,
+#endif
+ .name = "ZERO Pointer Saveguard",
+ },
+ {
+ .start = L1_CODE_START,
+ .end = L1_CODE_START + L1_CODE_LENGTH,
+ .psize = SIZE_4M,
+ .attr = INITIAL_T | SWITCH_T | I_CPLB,
+ .i_conf = L1_IMEMORY,
+ .d_conf = 0,
+ .valid = 1,
+ .name = "L1 I-Memory",
+ },
+ {
+ .start = L1_DATA_A_START,
+ .end = L1_DATA_B_START + L1_DATA_B_LENGTH,
+ .psize = SIZE_4M,
+ .attr = INITIAL_T | SWITCH_T | D_CPLB,
+ .i_conf = 0,
+ .d_conf = L1_DMEMORY,
+#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
+ .valid = 1,
+#else
+ .valid = 0,
+#endif
+ .name = "L1 D-Memory",
+ },
+ {
+ .start = 0,
+ .end = 0, /* dynamic */
+ .psize = 0,
+ .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+ .i_conf = SDRAM_IGENERIC,
+ .d_conf = SDRAM_DGENERIC,
+ .valid = 1,
+ .name = "SDRAM Kernel",
+ },
+ {
+ .start = 0, /* dynamic */
+ .end = 0, /* dynamic */
+ .psize = 0,
+ .attr = INITIAL_T | SWITCH_T | D_CPLB,
+ .i_conf = SDRAM_IGENERIC,
+ .d_conf = SDRAM_DNON_CHBL,
+ .valid = 1,
+ .name = "SDRAM RAM MTD",
+ },
+ {
+ .start = 0, /* dynamic */
+ .end = 0, /* dynamic */
+ .psize = SIZE_1M,
+ .attr = INITIAL_T | SWITCH_T | D_CPLB,
+ .d_conf = SDRAM_DNON_CHBL,
+ .valid = 1,//(DMA_UNCACHED_REGION > 0),
+ .name = "SDRAM Uncached DMA ZONE",
+ },
+ {
+ .start = 0, /* dynamic */
+ .end = 0, /* dynamic */
+ .psize = 0,
+ .attr = SWITCH_T | D_CPLB,
+ .i_conf = 0, /* dynamic */
+ .d_conf = 0, /* dynamic */
+ .valid = 1,
+ .name = "SDRAM Reserved Memory",
+ },
+ {
+ .start = ASYNC_BANK0_BASE,
+ .end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
+ .psize = 0,
+ .attr = SWITCH_T | D_CPLB,
+ .d_conf = SDRAM_EBIU,
+ .valid = 1,
+ .name = "ASYNC Memory",
+ },
+ {
+#if defined(CONFIG_BF561)
+ .start = L2_SRAM,
+ .end = L2_SRAM_END,
+ .psize = SIZE_1M,
+ .attr = SWITCH_T | D_CPLB,
+ .i_conf = L2_MEMORY,
+ .d_conf = L2_MEMORY,
+ .valid = 1,
+#else
+ .valid = 0,
+#endif
+ .name = "L2 Memory",
+ }
+};
+#endif
diff --git a/include/asm-blackfin/cpumask.h b/include/asm-blackfin/cpumask.h
new file mode 100644
index 00000000000..b20a8e9012c
--- /dev/null
+++ b/include/asm-blackfin/cpumask.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_BLACKFIN_CPUMASK_H
+#define _ASM_BLACKFIN_CPUMASK_H
+
+#include <asm-generic/cpumask.h>
+
+#endif /* _ASM_BLACKFIN_CPUMASK_H */
diff --git a/include/asm-blackfin/cputime.h b/include/asm-blackfin/cputime.h
new file mode 100644
index 00000000000..2b19705f988
--- /dev/null
+++ b/include/asm-blackfin/cputime.h
@@ -0,0 +1,6 @@
+#ifndef __BLACKFIN_CPUTIME_H
+#define __BLACKFIN_CPUTIME_H
+
+#include <asm-generic/cputime.h>
+
+#endif /* __BLACKFIN_CPUTIME_H */
diff --git a/include/asm-blackfin/current.h b/include/asm-blackfin/current.h
new file mode 100644
index 00000000000..31918d29122
--- /dev/null
+++ b/include/asm-blackfin/current.h
@@ -0,0 +1,23 @@
+#ifndef _BLACKFIN_CURRENT_H
+#define _BLACKFIN_CURRENT_H
+/*
+ * current.h
+ * (C) Copyright 2000, Lineo, David McCullough <davidm@lineo.com>
+ *
+ * rather than dedicate a register (as the m68k source does), we
+ * just keep a global, we should probably just change it all to be
+ * current and lose _current_task.
+ */
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void) __attribute__ ((__const__));
+static inline struct task_struct *get_current(void)
+{
+ return (current_thread_info()->task);
+}
+
+#define current (get_current())
+
+#endif /* _BLACKFIN_CURRENT_H */
diff --git a/include/asm-blackfin/delay.h b/include/asm-blackfin/delay.h
new file mode 100644
index 00000000000..52e7a10d7ff
--- /dev/null
+++ b/include/asm-blackfin/delay.h
@@ -0,0 +1,44 @@
+#ifndef _BLACKFIN_DELAY_H
+#define _BLACKFIN_DELAY_H
+
+static inline void __delay(unsigned long loops)
+{
+
+/* FIXME: Currently the assembler doesn't recognize Loop Register Clobbers,
+ uncomment this as soon those are implemented */
+/*
+ __asm__ __volatile__ ( "\t LSETUP (1f,1f) LC0= %0\n\t"
+ "1:\t NOP;\n\t"
+ : :"a" (loops)
+ : "LT0","LB0","LC0");
+
+*/
+
+ __asm__ __volatile__("[--SP] = LC0;\n\t"
+ "[--SP] = LT0;\n\t"
+ "[--SP] = LB0;\n\t"
+ "LSETUP (1f,1f) LC0 = %0;\n\t"
+ "1:\t NOP;\n\t"
+ "LB0 = [SP++];\n\t"
+ "LT0 = [SP++];\n\t"
+ "LC0 = [SP++];\n"
+ :
+ :"a" (loops));
+}
+
+#include <linux/param.h> /* needed for HZ */
+
+/*
+ * Use only for very small delays ( < 1 msec). Should probably use a
+ * lookup table, really, as the multiplications take much too long with
+ * short delays. This is a "reasonable" implementation, though (and the
+ * first constant multiplications gets optimized away if the delay is
+ * a constant)
+ */
+static inline void udelay(unsigned long usecs)
+{
+ extern unsigned long loops_per_jiffy;
+ __delay(usecs * loops_per_jiffy / (1000000 / HZ));
+}
+
+#endif /* defined(_BLACKFIN_DELAY_H) */
diff --git a/include/asm-blackfin/device.h b/include/asm-blackfin/device.h
new file mode 100644
index 00000000000..d8f9872b0e2
--- /dev/null
+++ b/include/asm-blackfin/device.h
@@ -0,0 +1,7 @@
+/*
+ * Arch specific extensions to struct device
+ *
+ * This file is released under the GPLv2
+ */
+#include <asm-generic/device.h>
+
diff --git a/include/asm-blackfin/div64.h b/include/asm-blackfin/div64.h
new file mode 100644
index 00000000000..6cd978cefb2
--- /dev/null
+++ b/include/asm-blackfin/div64.h
@@ -0,0 +1 @@
+#include <asm-generic/div64.h>
diff --git a/include/asm-blackfin/dma-mapping.h b/include/asm-blackfin/dma-mapping.h
new file mode 100644
index 00000000000..7a77d7fe3a3
--- /dev/null
+++ b/include/asm-blackfin/dma-mapping.h
@@ -0,0 +1,66 @@
+#ifndef _BLACKFIN_DMA_MAPPING_H
+#define _BLACKFIN_DMA_MAPPING_H
+
+#include <asm/scatterlist.h>
+
+void dma_alloc_init(unsigned long start, unsigned long end);
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp);
+void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle);
+
+/*
+ * Now for the API extensions over the pci_ one
+ */
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+/*
+ * Map a single buffer of the indicated size for DMA in streaming mode.
+ * The 32-bit bus address to use is returned.
+ *
+ * Once the device is given the dma address, the device owns this memory
+ * until either pci_unmap_single or pci_dma_sync_single is performed.
+ */
+extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction);
+
+/*
+ * Unmap a single streaming mode DMA translation. The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call. All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction);
+
+/*
+ * Map a set of buffers described by scatterlist in streaming
+ * mode for DMA. This is the scather-gather version of the
+ * above pci_map_single interface. Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length. They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ * DMA address/length pairs than there are SG table elements.
+ * (for example via virtual mapping capabilities)
+ * The routine returns the number of addr/length pairs actually
+ * used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction);
+
+/*
+ * Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries, enum dma_data_direction direction);
+
+#endif /* _BLACKFIN_DMA_MAPPING_H */
diff --git a/include/asm-blackfin/dma.h b/include/asm-blackfin/dma.h
new file mode 100644
index 00000000000..be0d913e551
--- /dev/null
+++ b/include/asm-blackfin/dma.h
@@ -0,0 +1,188 @@
+/*
+ * File: include/asm-blackfin/simple_bf533_dma.h
+ * Based on: none - original work
+ * Author: LG Soft India
+ * Copyright (C) 2004-2005 Analog Devices Inc.
+ * Created: Tue Sep 21 2004
+ * Description: This file contains the major Data structures and constants
+ * used for DMA Implementation in BF533
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BLACKFIN_DMA_H_
+#define _BLACKFIN_DMA_H_
+
+#include <asm/io.h>
+#include <linux/slab.h>
+#include <asm/irq.h>
+#include <asm/signal.h>
+#include <asm/semaphore.h>
+
+#include <linux/kernel.h>
+#include <asm/mach/dma.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/blackfin.h>
+
+#define MAX_DMA_ADDRESS PAGE_OFFSET
+
+/*****************************************************************************
+* Generic DMA Declarations
+*
+****************************************************************************/
+enum dma_chan_status {
+ DMA_CHANNEL_FREE,
+ DMA_CHANNEL_REQUESTED,
+ DMA_CHANNEL_ENABLED,
+};
+
+/*-------------------------
+ * config reg bits value
+ *-------------------------*/
+#define DATA_SIZE_8 0
+#define DATA_SIZE_16 1
+#define DATA_SIZE_32 2
+
+#define DMA_FLOW_STOP 0
+#define DMA_FLOW_AUTO 1
+#define DMA_FLOW_ARRAY 4
+#define DMA_FLOW_SMALL 6
+#define DMA_FLOW_LARGE 7
+
+#define DIMENSION_LINEAR 0
+#define DIMENSION_2D 1
+
+#define DIR_READ 0
+#define DIR_WRITE 1
+
+#define INTR_DISABLE 0
+#define INTR_ON_BUF 2
+#define INTR_ON_ROW 3
+
+struct dmasg {
+ unsigned long next_desc_addr;
+ unsigned long start_addr;
+ unsigned short cfg;
+ unsigned short x_count;
+ short x_modify;
+ unsigned short y_count;
+ short y_modify;
+} __attribute__((packed));
+
+struct dma_register {
+ unsigned long next_desc_ptr; /* DMA Next Descriptor Pointer register */
+ unsigned long start_addr; /* DMA Start address register */
+
+ unsigned short cfg; /* DMA Configuration register */
+ unsigned short dummy1; /* DMA Configuration register */
+
+ unsigned long reserved;
+
+ unsigned short x_count; /* DMA x_count register */
+ unsigned short dummy2;
+
+ short x_modify; /* DMA x_modify register */
+ unsigned short dummy3;
+
+ unsigned short y_count; /* DMA y_count register */
+ unsigned short dummy4;
+
+ short y_modify; /* DMA y_modify register */
+ unsigned short dummy5;
+
+ unsigned long curr_desc_ptr; /* DMA Current Descriptor Pointer
+ register */
+ unsigned short curr_addr_ptr_lo; /* DMA Current Address Pointer
+ register */
+ unsigned short curr_addr_ptr_hi; /* DMA Current Address Pointer
+ register */
+ unsigned short irq_status; /* DMA irq status register */
+ unsigned short dummy6;
+
+ unsigned short peripheral_map; /* DMA peripheral map register */
+ unsigned short dummy7;
+
+ unsigned short curr_x_count; /* DMA Current x-count register */
+ unsigned short dummy8;
+
+ unsigned long reserved2;
+
+ unsigned short curr_y_count; /* DMA Current y-count register */
+ unsigned short dummy9;
+
+ unsigned long reserved3;
+
+};
+
+typedef irqreturn_t(*dma_interrupt_t) (int irq, void *dev_id);
+
+struct dma_channel {
+ struct mutex dmalock;
+ char *device_id;
+ enum dma_chan_status chan_status;
+ struct dma_register *regs;
+ struct dmasg *sg; /* large mode descriptor */
+ unsigned int ctrl_num; /* controller number */
+ dma_interrupt_t irq_callback;
+ void *data;
+ unsigned int dma_enable_flag;
+ unsigned int loopback_flag;
+};
+
+/*******************************************************************************
+* DMA API's
+*******************************************************************************/
+/* functions to set register mode */
+void set_dma_start_addr(unsigned int channel, unsigned long addr);
+void set_dma_next_desc_addr(unsigned int channel, unsigned long addr);
+void set_dma_x_count(unsigned int channel, unsigned short x_count);
+void set_dma_x_modify(unsigned int channel, short x_modify);
+void set_dma_y_count(unsigned int channel, unsigned short y_count);
+void set_dma_y_modify(unsigned int channel, short y_modify);
+void set_dma_config(unsigned int channel, unsigned short config);
+unsigned short set_bfin_dma_config(char direction, char flow_mode,
+ char intr_mode, char dma_mode, char width);
+
+/* get curr status for polling */
+unsigned short get_dma_curr_irqstat(unsigned int channel);
+unsigned short get_dma_curr_xcount(unsigned int channel);
+unsigned short get_dma_curr_ycount(unsigned int channel);
+
+/* set large DMA mode descriptor */
+void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg);
+
+/* check if current channel is in use */
+int dma_channel_active(unsigned int channel);
+
+/* common functions must be called in any mode */
+void free_dma(unsigned int channel);
+int dma_channel_active(unsigned int channel); /* check if a channel is in use */
+void disable_dma(unsigned int channel);
+void enable_dma(unsigned int channel);
+int request_dma(unsigned int channel, char *device_id);
+int set_dma_callback(unsigned int channel, dma_interrupt_t callback,
+ void *data);
+void dma_disable_irq(unsigned int channel);
+void dma_enable_irq(unsigned int channel);
+void clear_dma_irqstat(unsigned int channel);
+void *dma_memcpy(void *dest, const void *src, size_t count);
+void *safe_dma_memcpy(void *dest, const void *src, size_t count);
+
+#endif
diff --git a/include/asm-blackfin/dpmc.h b/include/asm-blackfin/dpmc.h
new file mode 100644
index 00000000000..f162edb2303
--- /dev/null
+++ b/include/asm-blackfin/dpmc.h
@@ -0,0 +1,70 @@
+/*
+ * include/asm-blackfin/dpmc.h - Miscellaneous IOCTL commands for Dynamic Power
+ * Management Controller Driver.
+ * Copyright (C) 2004 Analog Device Inc.
+ *
+ */
+#ifndef _BLACKFIN_DPMC_H_
+#define _BLACKFIN_DPMC_H_
+
+#define SLEEP_MODE 1
+#define DEEP_SLEEP_MODE 2
+#define ACTIVE_PLL_DISABLED 3
+#define FULLON_MODE 4
+#define ACTIVE_PLL_ENABLED 5
+#define HIBERNATE_MODE 6
+
+#define IOCTL_FULL_ON_MODE _IO('s', 0xA0)
+#define IOCTL_ACTIVE_MODE _IO('s', 0xA1)
+#define IOCTL_SLEEP_MODE _IO('s', 0xA2)
+#define IOCTL_DEEP_SLEEP_MODE _IO('s', 0xA3)
+#define IOCTL_HIBERNATE_MODE _IO('s', 0xA4)
+#define IOCTL_CHANGE_FREQUENCY _IOW('s', 0xA5, unsigned long)
+#define IOCTL_CHANGE_VOLTAGE _IOW('s', 0xA6, unsigned long)
+#define IOCTL_SET_CCLK _IOW('s', 0xA7, unsigned long)
+#define IOCTL_SET_SCLK _IOW('s', 0xA8, unsigned long)
+#define IOCTL_GET_PLLSTATUS _IOW('s', 0xA9, unsigned long)
+#define IOCTL_GET_CORECLOCK _IOW('s', 0xAA, unsigned long)
+#define IOCTL_GET_SYSTEMCLOCK _IOW('s', 0xAB, unsigned long)
+#define IOCTL_GET_VCO _IOW('s', 0xAC, unsigned long)
+#define IOCTL_DISABLE_WDOG_TIMER _IO('s', 0xAD)
+#define IOCTL_UNMASK_WDOG_WAKEUP_EVENT _IO('s',0xAE)
+#define IOCTL_PROGRAM_WDOG_TIMER _IOW('s',0xAF,unsigned long)
+#define IOCTL_CLEAR_WDOG_WAKEUP_EVENT _IO('s',0xB0)
+#define IOCTL_SLEEP_DEEPER_MODE _IO('s',0xB1)
+
+#define DPMC_MINOR 254
+
+#define ON 0
+#define OFF 1
+
+#ifdef __KERNEL__
+
+unsigned long calc_volt(void);
+int calc_vlev(int vlt);
+unsigned long change_voltage(unsigned long volt);
+int calc_msel(int vco_hz);
+unsigned long change_frequency(unsigned long vco_mhz);
+int set_pll_div(unsigned short sel, unsigned char flag);
+int get_vco(void);
+unsigned long change_system_clock(unsigned long clock);
+unsigned long change_core_clock(unsigned long clock);
+unsigned long get_pll_status(void);
+void change_baud(int baud);
+void fullon_mode(void);
+void active_mode(void);
+void sleep_mode(u32 sic_iwr);
+void deep_sleep(u32 sic_iwr);
+void hibernate_mode(u32 sic_iwr);
+void sleep_deeper(u32 sic_iwr);
+void program_wdog_timer(unsigned long);
+void unmask_wdog_wakeup_evt(void);
+void clear_wdog_wakeup_evt(void);
+void disable_wdog_timer(void);
+
+extern unsigned long get_cclk(void);
+extern unsigned long get_sclk(void);
+
+#endif /* __KERNEL__ */
+
+#endif /*_BLACKFIN_DPMC_H_*/
diff --git a/include/asm-blackfin/elf.h b/include/asm-blackfin/elf.h
new file mode 100644
index 00000000000..5264b5536a7
--- /dev/null
+++ b/include/asm-blackfin/elf.h
@@ -0,0 +1,127 @@
+/* Changes made by LG Soft Oct 2004*/
+
+#ifndef __ASMBFIN_ELF_H
+#define __ASMBFIN_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_BFIN_PIC 0x00000001 /* -fpic */
+#define EF_BFIN_FDPIC 0x00000002 /* -mfdpic */
+#define EF_BFIN_CODE_IN_L1 0x00000010 /* --code-in-l1 */
+#define EF_BFIN_DATA_IN_L1 0x00000020 /* --data-in-l1 */
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef struct user_bfinfp_struct elf_fpregset_t;
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_BLACKFIN)
+
+#define elf_check_fdpic(x) ((x)->e_flags & EF_BFIN_FDPIC /* && !((x)->e_flags & EF_FRV_NON_PIC_RELOCS) */)
+#define elf_check_const_displacement(x) ((x)->e_flags & EF_BFIN_PIC)
+
+/* EM_BLACKFIN defined in linux/elf.h */
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_BLACKFIN
+
+#define ELF_PLAT_INIT(_r) _r->p1 = 0
+
+#define ELF_FDPIC_PLAT_INIT(_regs, _exec_map_addr, _interp_map_addr, _dynamic_addr) \
+do { \
+ _regs->r7 = 0; \
+ _regs->p0 = _exec_map_addr; \
+ _regs->p1 = _interp_map_addr; \
+ _regs->p2 = _dynamic_addr; \
+} while(0)
+
+#define USE_ELF_CORE_DUMP
+#define ELF_FDPIC_CORE_EFLAGS EF_BFIN_FDPIC
+#define ELF_EXEC_PAGESIZE 4096
+
+#define R_unused0 0 /* relocation type 0 is not defined */
+#define R_pcrel5m2 1 /*LSETUP part a */
+#define R_unused1 2 /* relocation type 2 is not defined */
+#define R_pcrel10 3 /* type 3, if cc jump <target> */
+#define R_pcrel12_jump 4 /* type 4, jump <target> */
+#define R_rimm16 5 /* type 0x5, rN = <target> */
+#define R_luimm16 6 /* # 0x6, preg.l=<target> Load imm 16 to lower half */
+#define R_huimm16 7 /* # 0x7, preg.h=<target> Load imm 16 to upper half */
+#define R_pcrel12_jump_s 8 /* # 0x8 jump.s <target> */
+#define R_pcrel24_jump_x 9 /* # 0x9 jump.x <target> */
+#define R_pcrel24 10 /* # 0xa call <target> , not expandable */
+#define R_unusedb 11 /* # 0xb not generated */
+#define R_unusedc 12 /* # 0xc not used */
+#define R_pcrel24_jump_l 13 /*0xd jump.l <target> */
+#define R_pcrel24_call_x 14 /* 0xE, call.x <target> if <target> is above 24 bit limit call through P1 */
+#define R_var_eq_symb 15 /* 0xf, linker should treat it same as 0x12 */
+#define R_byte_data 16 /* 0x10, .byte var = symbol */
+#define R_byte2_data 17 /* 0x11, .byte2 var = symbol */
+#define R_byte4_data 18 /* 0x12, .byte4 var = symbol and .var var=symbol */
+#define R_pcrel11 19 /* 0x13, lsetup part b */
+#define R_unused14 20 /* 0x14, undefined */
+#define R_unused15 21 /* not generated by VDSP 3.5 */
+
+/* arithmetic relocations */
+#define R_push 0xE0
+#define R_const 0xE1
+#define R_add 0xE2
+#define R_sub 0xE3
+#define R_mult 0xE4
+#define R_div 0xE5
+#define R_mod 0xE6
+#define R_lshift 0xE7
+#define R_rshift 0xE8
+#define R_and 0xE9
+#define R_or 0xEA
+#define R_xor 0xEB
+#define R_land 0xEC
+#define R_lor 0xED
+#define R_len 0xEE
+#define R_neg 0xEF
+#define R_comp 0xF0
+#define R_page 0xF1
+#define R_hwpage 0xF2
+#define R_addr 0xF3
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE 0xD0000000UL
+
+#define ELF_CORE_COPY_REGS(pr_reg, regs) \
+ memcpy((char *) &pr_reg, (char *)regs, \
+ sizeof(struct pt_regs));
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this cpu supports. */
+
+#define ELF_HWCAP (0)
+
+/* This yields a string that ld.so will use to load implementation
+ specific libraries for optimization. This is more specific in
+ intent than poking at uname or /proc/cpuinfo. */
+
+#define ELF_PLATFORM (NULL)
+
+#ifdef __KERNEL__
+#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#endif
+
+#endif
diff --git a/include/asm-blackfin/emergency-restart.h b/include/asm-blackfin/emergency-restart.h
new file mode 100644
index 00000000000..27f6c785d10
--- /dev/null
+++ b/include/asm-blackfin/emergency-restart.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_EMERGENCY_RESTART_H
+#define _ASM_EMERGENCY_RESTART_H
+
+#include <asm-generic/emergency-restart.h>
+
+#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/include/asm-blackfin/entry.h b/include/asm-blackfin/entry.h
new file mode 100644
index 00000000000..562c6d3a323
--- /dev/null
+++ b/include/asm-blackfin/entry.h
@@ -0,0 +1,56 @@
+#ifndef __BFIN_ENTRY_H
+#define __BFIN_ENTRY_H
+
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#ifdef __ASSEMBLY__
+
+#define LFLUSH_I_AND_D 0x00000808
+#define LSIGTRAP 5
+
+/* process bits for task_struct.flags */
+#define PF_TRACESYS_OFF 3
+#define PF_TRACESYS_BIT 5
+#define PF_PTRACED_OFF 3
+#define PF_PTRACED_BIT 4
+#define PF_DTRACE_OFF 1
+#define PF_DTRACE_BIT 5
+
+/* This one is used for exceptions, emulation, and NMI. It doesn't push
+ RETI and doesn't do cli. */
+#define SAVE_ALL_SYS save_context_no_interrupts
+/* This is used for all normal interrupts. It saves a minimum of registers
+ to the stack, loads the IRQ number, and jumps to common code. */
+#define INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ R0 = (N); \
+ jump __common_int_entry;
+
+/* For timer interrupts, we need to save IPEND, since the user_mode
+ macro accesses it to determine where to account time. */
+#define TIMER_INTERRUPT_ENTRY(N) \
+ [--sp] = SYSCFG; \
+ \
+ [--sp] = P0; /*orig_p0*/ \
+ [--sp] = R0; /*orig_r0*/ \
+ [--sp] = (R7:0,P5:0); \
+ p0.l = lo(IPEND); \
+ p0.h = hi(IPEND); \
+ r1 = [p0]; \
+ R0 = (N); \
+ jump __common_int_entry;
+
+/* This one pushes RETI without using CLI. Interrupts are enabled. */
+#define SAVE_CONTEXT_SYSCALL save_context_syscall
+#define SAVE_CONTEXT save_context_with_interrupts
+
+#define RESTORE_ALL_SYS restore_context_no_interrupts
+#define RESTORE_CONTEXT restore_context_with_interrupts
+
+#endif /* __ASSEMBLY__ */
+#endif /* __BFIN_ENTRY_H */
diff --git a/include/asm-blackfin/errno.h b/include/asm-blackfin/errno.h
new file mode 100644
index 00000000000..164e4f39bb5
--- /dev/null
+++ b/include/asm-blackfin/errno.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_ERRNO_H
+#define _BFIN_ERRNO_H
+
+#include<asm-generic/errno.h>
+
+#endif /* _BFIN_ERRNO_H */
diff --git a/include/asm-blackfin/fcntl.h b/include/asm-blackfin/fcntl.h
new file mode 100644
index 00000000000..9c403712785
--- /dev/null
+++ b/include/asm-blackfin/fcntl.h
@@ -0,0 +1,13 @@
+#ifndef _BFIN_FCNTL_H
+#define _BFIN_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+ located on an ext2 file system */
+#define O_DIRECTORY 040000 /* must be a directory */
+#define O_NOFOLLOW 0100000 /* don't follow links */
+#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */
+#define O_LARGEFILE 0400000
+
+#include <asm-generic/fcntl.h>
+
+#endif
diff --git a/include/asm-blackfin/flat.h b/include/asm-blackfin/flat.h
new file mode 100644
index 00000000000..e70074e05f4
--- /dev/null
+++ b/include/asm-blackfin/flat.h
@@ -0,0 +1,58 @@
+/*
+ * include/asm-blackfin/flat.h -- uClinux flat-format executables
+ *
+ * Copyright (C) 2003,
+ *
+ */
+
+#ifndef __BLACKFIN_FLAT_H__
+#define __BLACKFIN_FLAT_H__
+
+#include <asm/unaligned.h>
+
+#define flat_stack_align(sp) /* nothing needed */
+#define flat_argvp_envp_on_stack() 0
+#define flat_old_ram_flag(flags) (flags)
+
+extern unsigned long bfin_get_addr_from_rp (unsigned long *ptr,
+ unsigned long relval,
+ unsigned long flags,
+ unsigned long *persistent);
+
+extern void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
+ unsigned long relval);
+
+/* The amount by which a relocation can exceed the program image limits
+ without being regarded as an error. */
+
+#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
+
+#define flat_get_addr_from_rp(rp, relval, flags, persistent) \
+ bfin_get_addr_from_rp(rp, relval, flags, persistent)
+#define flat_put_addr_at_rp(rp, val, relval) \
+ bfin_put_addr_at_rp(rp, val, relval)
+
+/* Convert a relocation entry into an address. */
+static inline unsigned long
+flat_get_relocate_addr (unsigned long relval)
+{
+ return relval & 0x03ffffff; /* Mask out top 6 bits */
+}
+
+static inline int flat_set_persistent(unsigned long relval,
+ unsigned long *persistent)
+{
+ int type = (relval >> 26) & 7;
+ if (type == 3) {
+ *persistent = relval << 16;
+ return 1;
+ }
+ return 0;
+}
+
+static inline int flat_addr_absolute(unsigned long relval)
+{
+ return (relval & (1 << 29)) != 0;
+}
+
+#endif /* __BLACKFIN_FLAT_H__ */
diff --git a/include/asm-blackfin/futex.h b/include/asm-blackfin/futex.h
new file mode 100644
index 00000000000..6a332a9f099
--- /dev/null
+++ b/include/asm-blackfin/futex.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_FUTEX_H
+#define _ASM_FUTEX_H
+
+#include <asm-generic/futex.h>
+
+#endif
diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h
new file mode 100644
index 00000000000..d16fe3cd613
--- /dev/null
+++ b/include/asm-blackfin/gpio.h
@@ -0,0 +1,367 @@
+/*
+ * File: arch/blackfin/kernel/bfin_gpio.h
+ * Based on:
+ * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+* Number BF537/6/4 BF561 BF533/2/1
+*
+* GPIO_0 PF0 PF0 PF0
+* GPIO_1 PF1 PF1 PF1
+* GPIO_2 PF2 PF2 PF2
+* GPIO_3 PF3 PF3 PF3
+* GPIO_4 PF4 PF4 PF4
+* GPIO_5 PF5 PF5 PF5
+* GPIO_6 PF6 PF6 PF6
+* GPIO_7 PF7 PF7 PF7
+* GPIO_8 PF8 PF8 PF8
+* GPIO_9 PF9 PF9 PF9
+* GPIO_10 PF10 PF10 PF10
+* GPIO_11 PF11 PF11 PF11
+* GPIO_12 PF12 PF12 PF12
+* GPIO_13 PF13 PF13 PF13
+* GPIO_14 PF14 PF14 PF14
+* GPIO_15 PF15 PF15 PF15
+* GPIO_16 PG0 PF16
+* GPIO_17 PG1 PF17
+* GPIO_18 PG2 PF18
+* GPIO_19 PG3 PF19
+* GPIO_20 PG4 PF20
+* GPIO_21 PG5 PF21
+* GPIO_22 PG6 PF22
+* GPIO_23 PG7 PF23
+* GPIO_24 PG8 PF24
+* GPIO_25 PG9 PF25
+* GPIO_26 PG10 PF26
+* GPIO_27 PG11 PF27
+* GPIO_28 PG12 PF28
+* GPIO_29 PG13 PF29
+* GPIO_30 PG14 PF30
+* GPIO_31 PG15 PF31
+* GPIO_32 PH0 PF32
+* GPIO_33 PH1 PF33
+* GPIO_34 PH2 PF34
+* GPIO_35 PH3 PF35
+* GPIO_36 PH4 PF36
+* GPIO_37 PH5 PF37
+* GPIO_38 PH6 PF38
+* GPIO_39 PH7 PF39
+* GPIO_40 PH8 PF40
+* GPIO_41 PH9 PF41
+* GPIO_42 PH10 PF42
+* GPIO_43 PH11 PF43
+* GPIO_44 PH12 PF44
+* GPIO_45 PH13 PF45
+* GPIO_46 PH14 PF46
+* GPIO_47 PH15 PF47
+*/
+
+#ifndef __ARCH_BLACKFIN_GPIO_H__
+#define __ARCH_BLACKFIN_GPIO_H__
+
+#define gpio_bank(x) ((x) >> 4)
+#define gpio_bit(x) (1<<((x) & 0xF))
+#define gpio_sub_n(x) ((x) & 0xF)
+
+#define GPIO_BANKSIZE 16
+
+#define GPIO_0 0
+#define GPIO_1 1
+#define GPIO_2 2
+#define GPIO_3 3
+#define GPIO_4 4
+#define GPIO_5 5
+#define GPIO_6 6
+#define GPIO_7 7
+#define GPIO_8 8
+#define GPIO_9 9
+#define GPIO_10 10
+#define GPIO_11 11
+#define GPIO_12 12
+#define GPIO_13 13
+#define GPIO_14 14
+#define GPIO_15 15
+#define GPIO_16 16
+#define GPIO_17 17
+#define GPIO_18 18
+#define GPIO_19 19
+#define GPIO_20 20
+#define GPIO_21 21
+#define GPIO_22 22
+#define GPIO_23 23
+#define GPIO_24 24
+#define GPIO_25 25
+#define GPIO_26 26
+#define GPIO_27 27
+#define GPIO_28 28
+#define GPIO_29 29
+#define GPIO_30 30
+#define GPIO_31 31
+#define GPIO_32 32
+#define GPIO_33 33
+#define GPIO_34 34
+#define GPIO_35 35
+#define GPIO_36 36
+#define GPIO_37 37
+#define GPIO_38 38
+#define GPIO_39 39
+#define GPIO_40 40
+#define GPIO_41 41
+#define GPIO_42 42
+#define GPIO_43 43
+#define GPIO_44 44
+#define GPIO_45 45
+#define GPIO_46 46
+#define GPIO_47 47
+
+
+#define PERIPHERAL_USAGE 1
+#define GPIO_USAGE 0
+
+#ifdef BF533_FAMILY
+#define MAX_BLACKFIN_GPIOS 16
+#endif
+
+#ifdef BF537_FAMILY
+#define MAX_BLACKFIN_GPIOS 48
+#define PORT_F 0
+#define PORT_G 1
+#define PORT_H 2
+#define PORT_J 3
+
+#define GPIO_PF0 0
+#define GPIO_PF1 1
+#define GPIO_PF2 2
+#define GPIO_PF3 3
+#define GPIO_PF4 4
+#define GPIO_PF5 5
+#define GPIO_PF6 6
+#define GPIO_PF7 7
+#define GPIO_PF8 8
+#define GPIO_PF9 9
+#define GPIO_PF10 10
+#define GPIO_PF11 11
+#define GPIO_PF12 12
+#define GPIO_PF13 13
+#define GPIO_PF14 14
+#define GPIO_PF15 15
+#define GPIO_PG0 16
+#define GPIO_PG1 17
+#define GPIO_PG2 18
+#define GPIO_PG3 19
+#define GPIO_PG4 20
+#define GPIO_PG5 21
+#define GPIO_PG6 22
+#define GPIO_PG7 23
+#define GPIO_PG8 24
+#define GPIO_PG9 25
+#define GPIO_PG10 26
+#define GPIO_PG11 27
+#define GPIO_PG12 28
+#define GPIO_PG13 29
+#define GPIO_PG14 30
+#define GPIO_PG15 31
+#define GPIO_PH0 32
+#define GPIO_PH1 33
+#define GPIO_PH2 34
+#define GPIO_PH3 35
+#define GPIO_PH4 36
+#define GPIO_PH5 37
+#define GPIO_PH6 38
+#define GPIO_PH7 39
+#define GPIO_PH8 40
+#define GPIO_PH9 41
+#define GPIO_PH10 42
+#define GPIO_PH11 43
+#define GPIO_PH12 44
+#define GPIO_PH13 45
+#define GPIO_PH14 46
+#define GPIO_PH15 47
+
+#endif
+
+#ifdef BF561_FAMILY
+#define MAX_BLACKFIN_GPIOS 48
+#define PORT_FIO0 0
+#define PORT_FIO1 1
+#define PORT_FIO2 2
+#endif
+
+#ifndef __ASSEMBLY__
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin General Purpose Ports Access Functions
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: These functions abstract direct register access
+* to Blackfin processor General Purpose
+* Ports Regsiters
+*
+* CAUTION: These functions do not belong to the GPIO Driver API
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+void set_gpio_dir(unsigned short, unsigned short);
+void set_gpio_inen(unsigned short, unsigned short);
+void set_gpio_polar(unsigned short, unsigned short);
+void set_gpio_edge(unsigned short, unsigned short);
+void set_gpio_both(unsigned short, unsigned short);
+void set_gpio_data(unsigned short, unsigned short);
+void set_gpio_maska(unsigned short, unsigned short);
+void set_gpio_maskb(unsigned short, unsigned short);
+void set_gpio_toggle(unsigned short);
+void set_gpiop_dir(unsigned short, unsigned short);
+void set_gpiop_inen(unsigned short, unsigned short);
+void set_gpiop_polar(unsigned short, unsigned short);
+void set_gpiop_edge(unsigned short, unsigned short);
+void set_gpiop_both(unsigned short, unsigned short);
+void set_gpiop_data(unsigned short, unsigned short);
+void set_gpiop_maska(unsigned short, unsigned short);
+void set_gpiop_maskb(unsigned short, unsigned short);
+unsigned short get_gpio_dir(unsigned short);
+unsigned short get_gpio_inen(unsigned short);
+unsigned short get_gpio_polar(unsigned short);
+unsigned short get_gpio_edge(unsigned short);
+unsigned short get_gpio_both(unsigned short);
+unsigned short get_gpio_maska(unsigned short);
+unsigned short get_gpio_maskb(unsigned short);
+unsigned short get_gpio_data(unsigned short);
+unsigned short get_gpiop_dir(unsigned short);
+unsigned short get_gpiop_inen(unsigned short);
+unsigned short get_gpiop_polar(unsigned short);
+unsigned short get_gpiop_edge(unsigned short);
+unsigned short get_gpiop_both(unsigned short);
+unsigned short get_gpiop_maska(unsigned short);
+unsigned short get_gpiop_maskb(unsigned short);
+unsigned short get_gpiop_data(unsigned short);
+
+struct gpio_port_t {
+ unsigned short data;
+ unsigned short dummy1;
+ unsigned short data_clear;
+ unsigned short dummy2;
+ unsigned short data_set;
+ unsigned short dummy3;
+ unsigned short toggle;
+ unsigned short dummy4;
+ unsigned short maska;
+ unsigned short dummy5;
+ unsigned short maska_clear;
+ unsigned short dummy6;
+ unsigned short maska_set;
+ unsigned short dummy7;
+ unsigned short maska_toggle;
+ unsigned short dummy8;
+ unsigned short maskb;
+ unsigned short dummy9;
+ unsigned short maskb_clear;
+ unsigned short dummy10;
+ unsigned short maskb_set;
+ unsigned short dummy11;
+ unsigned short maskb_toggle;
+ unsigned short dummy12;
+ unsigned short dir;
+ unsigned short dummy13;
+ unsigned short polar;
+ unsigned short dummy14;
+ unsigned short edge;
+ unsigned short dummy15;
+ unsigned short both;
+ unsigned short dummy16;
+ unsigned short inen;
+};
+
+#ifdef CONFIG_PM
+#define PM_WAKE_RISING 0x1
+#define PM_WAKE_FALLING 0x2
+#define PM_WAKE_HIGH 0x4
+#define PM_WAKE_LOW 0x8
+#define PM_WAKE_BOTH_EDGES (PM_WAKE_RISING | PM_WAKE_FALLING)
+
+int gpio_pm_wakeup_request(unsigned short gpio, unsigned char type);
+void gpio_pm_wakeup_free(unsigned short gpio);
+unsigned int gpio_pm_setup(void);
+void gpio_pm_restore(void);
+
+struct gpio_port_s {
+ unsigned short data;
+ unsigned short data_clear;
+ unsigned short data_set;
+ unsigned short toggle;
+ unsigned short maska;
+ unsigned short maska_clear;
+ unsigned short maska_set;
+ unsigned short maska_toggle;
+ unsigned short maskb;
+ unsigned short maskb_clear;
+ unsigned short maskb_set;
+ unsigned short maskb_toggle;
+ unsigned short dir;
+ unsigned short polar;
+ unsigned short edge;
+ unsigned short both;
+ unsigned short inen;
+
+ unsigned short fer;
+};
+#endif /*CONFIG_PM*/
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: Blackfin GPIO Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+int gpio_request(unsigned short, const char *);
+void gpio_free(unsigned short);
+
+void gpio_set_value(unsigned short gpio, unsigned short arg);
+unsigned short gpio_get_value(unsigned short gpio);
+
+#define gpio_get_value(gpio) get_gpio_data(gpio)
+#define gpio_set_value(gpio, value) set_gpio_data(gpio, value)
+
+void gpio_direction_input(unsigned short gpio);
+void gpio_direction_output(unsigned short gpio);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_BLACKFIN_GPIO_H__ */
diff --git a/include/asm-blackfin/hardirq.h b/include/asm-blackfin/hardirq.h
new file mode 100644
index 00000000000..0cab0d35bad
--- /dev/null
+++ b/include/asm-blackfin/hardirq.h
@@ -0,0 +1,41 @@
+#ifndef __BFIN_HARDIRQ_H
+#define __BFIN_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+#include <asm/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __syscall_count;
+ struct task_struct *__ksoftirqd_task;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+/*
+ * We put the hardirq and softirq counter into the preemption
+ * counter. The bitmask has the following meaning:
+ *
+ * - bits 0-7 are the preemption count (max preemption depth: 256)
+ * - bits 8-15 are the softirq count (max # of softirqs: 256)
+ * - bits 16-23 are the hardirq count (max # of hardirqs: 256)
+ *
+ * - ( bit 26 is the PREEMPT_ACTIVE flag. )
+ *
+ * PREEMPT_MASK: 0x000000ff
+ * HARDIRQ_MASK: 0x0000ff00
+ * SOFTIRQ_MASK: 0x00ff0000
+ */
+
+#define HARDIRQ_BITS 8
+
+#ifdef NR_IRQS
+# if (1 << HARDIRQ_BITS) < NR_IRQS
+# error HARDIRQ_BITS is too low!
+# endif
+#endif
+
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED 1
+
+#endif
diff --git a/include/asm-blackfin/hw_irq.h b/include/asm-blackfin/hw_irq.h
new file mode 100644
index 00000000000..5b51eaec012
--- /dev/null
+++ b/include/asm-blackfin/hw_irq.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_BFIN_HW_IRQ_H
+#define __ASM_BFIN_HW_IRQ_H
+
+/* Dummy include. */
+
+#endif
diff --git a/include/asm-blackfin/ide.h b/include/asm-blackfin/ide.h
new file mode 100644
index 00000000000..41b2db46a16
--- /dev/null
+++ b/include/asm-blackfin/ide.h
@@ -0,0 +1,32 @@
+/****************************************************************************/
+
+/*
+ * linux/include/asm-blackfin/ide.h
+ *
+ * Copyright (C) 1994-1996 Linus Torvalds & authors
+ * Copyright (C) 2001 Lineo Inc., davidm@snapgear.com
+ * Copyright (C) 2002 Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 2002 Yoshinori Sato (ysato@users.sourceforge.jp)
+ * Copyright (C) 2005 Hennerich Michael (hennerich@blackfin.uclinux.org)
+ */
+
+/****************************************************************************/
+#ifndef _BLACKFIN_IDE_H
+#define _BLACKFIN_IDE_H
+/****************************************************************************/
+#ifdef __KERNEL__
+/****************************************************************************/
+
+#define MAX_HWIFS 1
+
+/* Legacy ... BLK_DEV_IDECS */
+#define IDE_ARCH_OBSOLETE_INIT
+#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */
+
+
+#include <asm-generic/ide_iops.h>
+
+/****************************************************************************/
+#endif /* __KERNEL__ */
+#endif /* _BLACKFIN_IDE_H */
+/****************************************************************************/
diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h
new file mode 100644
index 00000000000..7e6995e80d9
--- /dev/null
+++ b/include/asm-blackfin/io.h
@@ -0,0 +1,207 @@
+#ifndef _BFIN_IO_H
+#define _BFIN_IO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#endif
+#include <linux/compiler.h>
+
+/*
+ * These are for ISA/PCI shared memory _only_ and should never be used
+ * on any other type of memory, including Zorro memory. They are meant to
+ * access the bus in the bus byte order which is little-endian!.
+ *
+ * readX/writeX() are used to access memory mapped devices. On some
+ * architectures the memory mapped IO stuff needs to be accessed
+ * differently. On the bfin architecture, we just read/write the
+ * memory location directly.
+ */
+#ifndef __ASSEMBLY__
+
+static inline unsigned char readb(void __iomem *addr)
+{
+ unsigned int val;
+ int tmp;
+
+ __asm__ __volatile__ ("cli %1;\n\t"
+ "NOP; NOP; SSYNC;\n\t"
+ "%0 = b [%2] (z);\n\t"
+ "sti %1;\n\t"
+ : "=d"(val), "=d"(tmp): "a"(addr)
+ );
+
+ return (unsigned char) val;
+}
+
+static inline unsigned short readw(void __iomem *addr)
+{
+ unsigned int val;
+ int tmp;
+
+ __asm__ __volatile__ ("cli %1;\n\t"
+ "NOP; NOP; SSYNC;\n\t"
+ "%0 = w [%2] (z);\n\t"
+ "sti %1;\n\t"
+ : "=d"(val), "=d"(tmp): "a"(addr)
+ );
+
+ return (unsigned short) val;
+}
+
+static inline unsigned int readl(void __iomem *addr)
+{
+ unsigned int val;
+ int tmp;
+
+ __asm__ __volatile__ ("cli %1;\n\t"
+ "NOP; NOP; SSYNC;\n\t"
+ "%0 = [%2];\n\t"
+ "sti %1;\n\t"
+ : "=d"(val), "=d"(tmp): "a"(addr)
+ );
+ return val;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
+
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+#define memset_io(a,b,c) memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
+
+#define inb(addr) readb(addr)
+#define inw(addr) readw(addr)
+#define inl(addr) readl(addr)
+#define outb(x,addr) ((void) writeb(x,addr))
+#define outw(x,addr) ((void) writew(x,addr))
+#define outl(x,addr) ((void) writel(x,addr))
+
+#define inb_p(addr) inb(addr)
+#define inw_p(addr) inw(addr)
+#define inl_p(addr) inl(addr)
+#define outb_p(x,addr) outb(x,addr)
+#define outw_p(x,addr) outw(x,addr)
+#define outl_p(x,addr) outl(x,addr)
+
+#define ioread8_rep(a,d,c) insb(a,d,c)
+#define ioread16_rep(a,d,c) insw(a,d,c)
+#define ioread32_rep(a,d,c) insl(a,d,c)
+#define iowrite8_rep(a,s,c) outsb(a,s,c)
+#define iowrite16_rep(a,s,c) outsw(a,s,c)
+#define iowrite32_rep(a,s,c) outsl(a,s,c)
+
+#define ioread8(X) readb(X)
+#define ioread16(X) readw(X)
+#define ioread32(X) readl(X)
+#define iowrite8(val,X) writeb(val,X)
+#define iowrite16(val,X) writew(val,X)
+#define iowrite32(val,X) writel(val,X)
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/* Values for nocacheflag and cmode */
+#define IOMAP_NOCACHE_SER 1
+
+#ifndef __ASSEMBLY__
+
+extern void outsb(void __iomem *port, const void *addr, unsigned long count);
+extern void outsw(void __iomem *port, const void *addr, unsigned long count);
+extern void outsl(void __iomem *port, const void *addr, unsigned long count);
+
+extern void insb(const void __iomem *port, void *addr, unsigned long count);
+extern void insw(const void __iomem *port, void *addr, unsigned long count);
+extern void insl(const void __iomem *port, void *addr, unsigned long count);
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+static inline void __iomem *__ioremap(unsigned long physaddr, unsigned long size,
+ int cacheflag)
+{
+ return (void __iomem *)physaddr;
+}
+
+/*
+ * Unmap a ioremap()ed region again
+ */
+static inline void iounmap(void *addr)
+{
+}
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+static inline void __iounmap(void *addr, unsigned long size)
+{
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+static inline void kernel_set_cachemode(void *addr, unsigned long size,
+ int cmode)
+{
+}
+
+static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size)
+{
+ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+static inline void __iomem *ioremap_nocache(unsigned long physaddr,
+ unsigned long size)
+{
+ return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
+}
+
+extern void blkfin_inv_cache_all(void);
+
+#endif
+
+#define ioport_map(port, nr) ((void __iomem*)(port))
+#define ioport_unmap(addr)
+
+#define dma_cache_inv(_start,_size) do { blkfin_inv_cache_all();} while (0)
+#define dma_cache_wback(_start,_size) do { } while (0)
+#define dma_cache_wback_inv(_start,_size) do { blkfin_inv_cache_all();} while (0)
+
+/* Pages to physical address... */
+#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
+#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT)
+
+#define mm_ptov(vaddr) ((void *) (vaddr))
+#define mm_vtop(vaddr) ((unsigned long) (vaddr))
+#define phys_to_virt(vaddr) ((void *) (vaddr))
+#define virt_to_phys(vaddr) ((unsigned long) (vaddr))
+
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p) __va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p) p
+
+#endif /* __KERNEL__ */
+
+#endif /* _BFIN_IO_H */
diff --git a/include/asm-blackfin/ioctl.h b/include/asm-blackfin/ioctl.h
new file mode 100644
index 00000000000..b279fe06dfe
--- /dev/null
+++ b/include/asm-blackfin/ioctl.h
@@ -0,0 +1 @@
+#include <asm-generic/ioctl.h>
diff --git a/include/asm-blackfin/ioctls.h b/include/asm-blackfin/ioctls.h
new file mode 100644
index 00000000000..8356204151d
--- /dev/null
+++ b/include/asm-blackfin/ioctls.h
@@ -0,0 +1,82 @@
+#ifndef __ARCH_BFIN_IOCTLS_H__
+#define __ARCH_BFIN_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS 0x5401
+#define TCSETS 0x5402
+#define TCSETSW 0x5403
+#define TCSETSF 0x5404
+#define TCGETA 0x5405
+#define TCSETA 0x5406
+#define TCSETAW 0x5407
+#define TCSETAF 0x5408
+#define TCSBRK 0x5409
+#define TCXONC 0x540A
+#define TCFLSH 0x540B
+#define TIOCEXCL 0x540C
+#define TIOCNXCL 0x540D
+#define TIOCSCTTY 0x540E
+#define TIOCGPGRP 0x540F
+#define TIOCSPGRP 0x5410
+#define TIOCOUTQ 0x5411
+#define TIOCSTI 0x5412
+#define TIOCGWINSZ 0x5413
+#define TIOCSWINSZ 0x5414
+#define TIOCMGET 0x5415
+#define TIOCMBIS 0x5416
+#define TIOCMBIC 0x5417
+#define TIOCMSET 0x5418
+#define TIOCGSOFTCAR 0x5419
+#define TIOCSSOFTCAR 0x541A
+#define FIONREAD 0x541B
+#define TIOCINQ FIONREAD
+#define TIOCLINUX 0x541C
+#define TIOCCONS 0x541D
+#define TIOCGSERIAL 0x541E
+#define TIOCSSERIAL 0x541F
+#define TIOCPKT 0x5420
+#define FIONBIO 0x5421
+#define TIOCNOTTY 0x5422
+#define TIOCSETD 0x5423
+#define TIOCGETD 0x5424
+#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */
+#define TIOCSBRK 0x5427 /* BSD compatibility */
+#define TIOCCBRK 0x5428 /* BSD compatibility */
+#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
+
+#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
+#define FIOCLEX 0x5451
+#define FIOASYNC 0x5452
+#define TIOCSERCONFIG 0x5453
+#define TIOCSERGWILD 0x5454
+#define TIOCSERSWILD 0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+
+#define FIOQSIZE 0x545E
+
+/* Used for packet mode */
+#define TIOCPKT_DATA 0
+#define TIOCPKT_FLUSHREAD 1
+#define TIOCPKT_FLUSHWRITE 2
+#define TIOCPKT_STOP 4
+#define TIOCPKT_START 8
+#define TIOCPKT_NOSTOP 16
+#define TIOCPKT_DOSTOP 32
+
+#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+
+#endif /* __ARCH_BFIN_IOCTLS_H__ */
diff --git a/include/asm-blackfin/ipc.h b/include/asm-blackfin/ipc.h
new file mode 100644
index 00000000000..a46e3d9c2a3
--- /dev/null
+++ b/include/asm-blackfin/ipc.h
@@ -0,0 +1 @@
+#include <asm-generic/ipc.h>
diff --git a/include/asm-blackfin/ipcbuf.h b/include/asm-blackfin/ipcbuf.h
new file mode 100644
index 00000000000..8f0899cdf4d
--- /dev/null
+++ b/include/asm-blackfin/ipcbuf.h
@@ -0,0 +1,30 @@
+/* Changes origined from m68k version. Lineo Inc. May 2001 */
+
+#ifndef __BFIN_IPCBUF_H__
+#define __BFIN_IPCBUF_H__
+
+/*
+ * The user_ipc_perm structure for m68k architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct ipc64_perm {
+ __kernel_key_t key;
+ __kernel_uid32_t uid;
+ __kernel_gid32_t gid;
+ __kernel_uid32_t cuid;
+ __kernel_gid32_t cgid;
+ __kernel_mode_t mode;
+ unsigned short __pad1;
+ unsigned short seq;
+ unsigned short __pad2;
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* __BFIN_IPCBUF_H__ */
diff --git a/include/asm-blackfin/irq.h b/include/asm-blackfin/irq.h
new file mode 100644
index 00000000000..65480dab244
--- /dev/null
+++ b/include/asm-blackfin/irq.h
@@ -0,0 +1,70 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Changed by HuTao Apr18, 2003
+ *
+ * Copyright was missing when I got the code so took from MIPS arch ...MaTed---
+ * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
+ * Copyright (C) 1995, 96, 97, 98, 99, 2000, 2001 by Ralf Baechle
+ *
+ * Adapted for BlackFin (ADI) by Ted Ma <mated@sympatico.ca>
+ * Copyright (c) 2002 Arcturus Networks Inc. (www.arcturusnetworks.com)
+ * Copyright (c) 2002 Lineo, Inc. <mattw@lineo.com>
+ */
+
+#ifndef _BFIN_IRQ_H_
+#define _BFIN_IRQ_H_
+
+#include <asm/mach/irq.h>
+#include <asm/ptrace.h>
+
+/*******************************************************************************
+ ***** INTRODUCTION ***********
+ * On the Blackfin, the interrupt structure allows remmapping of the hardware
+ * levels.
+ * - I'm going to assume that the H/W level is going to stay at the default
+ * settings. If someone wants to go through and abstart this out, feel free
+ * to mod the interrupt numbering scheme.
+ * - I'm abstracting the interrupts so that uClinux does not know anything
+ * about the H/W levels. If you want to change the H/W AND keep the abstracted
+ * levels that uClinux sees, you should be able to do most of it here.
+ * - I've left the "abstract" numbering sparce in case someone wants to pull the
+ * interrupts apart (just the TX/RX for the various devices)
+ *******************************************************************************/
+
+/* SYS_IRQS and NR_IRQS are defined in <asm/mach-bf5xx/irq.h>*/
+
+/*
+ * Machine specific interrupt sources.
+ *
+ * Adding an interrupt service routine for a source with this bit
+ * set indicates a special machine specific interrupt source.
+ * The machine specific files define these sources.
+ *
+ * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
+ * introduce unnecessary overhead.
+ *
+ * All interrupt handling is actually machine specific so it is better
+ * to use function pointers, as used by the Sparc port, and select the
+ * interrupt handling functions when initializing the kernel. This way
+ * we save some unnecessary overhead at run-time.
+ * 01/11/97 - Jes
+ */
+
+extern void ack_bad_irq(unsigned int irq);
+
+static __inline__ int irq_canonicalize(int irq)
+{
+ return irq;
+}
+
+/* count of spurious interrupts */
+/* extern volatile unsigned int num_spurious; */
+
+#ifndef NO_IRQ
+#define NO_IRQ ((unsigned int)(-1))
+#endif
+
+#endif /* _BFIN_IRQ_H_ */
diff --git a/include/asm-blackfin/irq_handler.h b/include/asm-blackfin/irq_handler.h
new file mode 100644
index 00000000000..d830f0a49a1
--- /dev/null
+++ b/include/asm-blackfin/irq_handler.h
@@ -0,0 +1,22 @@
+#ifndef _IRQ_HANDLER_H
+#define _IRQ_HANDLER_H
+
+/* BASE LEVEL interrupt handler routines */
+asmlinkage void evt_emulation(void);
+asmlinkage void evt_exception(void);
+asmlinkage void trap(void);
+asmlinkage void evt_ivhw(void);
+asmlinkage void evt_timer(void);
+asmlinkage void evt_evt2(void);
+asmlinkage void evt_evt7(void);
+asmlinkage void evt_evt8(void);
+asmlinkage void evt_evt9(void);
+asmlinkage void evt_evt10(void);
+asmlinkage void evt_evt11(void);
+asmlinkage void evt_evt12(void);
+asmlinkage void evt_evt13(void);
+asmlinkage void evt_soft_int1(void);
+asmlinkage void evt_system_call(void);
+asmlinkage void init_exception_buff(void);
+
+#endif
diff --git a/include/asm-blackfin/irq_regs.h b/include/asm-blackfin/irq_regs.h
new file mode 100644
index 00000000000..3dd9c0b7027
--- /dev/null
+++ b/include/asm-blackfin/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-blackfin/kdebug.h b/include/asm-blackfin/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-blackfin/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-blackfin/kmap_types.h b/include/asm-blackfin/kmap_types.h
new file mode 100644
index 00000000000..e215f710497
--- /dev/null
+++ b/include/asm-blackfin/kmap_types.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_KMAP_TYPES_H
+#define _ASM_KMAP_TYPES_H
+
+enum km_type {
+ KM_BOUNCE_READ,
+ KM_SKB_SUNRPC_DATA,
+ KM_SKB_DATA_SOFTIRQ,
+ KM_USER0,
+ KM_USER1,
+ KM_BIO_SRC_IRQ,
+ KM_BIO_DST_IRQ,
+ KM_PTE0,
+ KM_PTE1,
+ KM_IRQ0,
+ KM_IRQ1,
+ KM_SOFTIRQ0,
+ KM_SOFTIRQ1,
+ KM_TYPE_NR
+};
+
+#endif
diff --git a/include/asm-blackfin/l1layout.h b/include/asm-blackfin/l1layout.h
new file mode 100644
index 00000000000..c13ded77782
--- /dev/null
+++ b/include/asm-blackfin/l1layout.h
@@ -0,0 +1,31 @@
+/*
+ * l1layout.h
+ * Defines a layout of L1 scratchpad memory that userspace can rely on.
+ */
+
+#ifndef _L1LAYOUT_H_
+#define _L1LAYOUT_H_
+
+#include <asm/blackfin.h>
+
+#ifndef __ASSEMBLY__
+
+/* Data that is "mapped" into the process VM at the start of the L1 scratch
+ memory, so that each process can access it at a fixed address. Used for
+ stack checking. */
+struct l1_scratch_task_info
+{
+ /* Points to the start of the stack. */
+ void *stack_start;
+ /* Not updated by the kernel; a user process can modify this to
+ keep track of the lowest address of the stack pointer during its
+ runtime. */
+ void *lowest_sp;
+};
+
+/* A pointer to the structure in memory. */
+#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)L1_SCRATCH_START)
+
+#endif
+
+#endif
diff --git a/include/asm-blackfin/linkage.h b/include/asm-blackfin/linkage.h
new file mode 100644
index 00000000000..5a822bb790f
--- /dev/null
+++ b/include/asm-blackfin/linkage.h
@@ -0,0 +1,7 @@
+#ifndef __ASM_LINKAGE_H
+#define __ASM_LINKAGE_H
+
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+
+#endif
diff --git a/include/asm-blackfin/local.h b/include/asm-blackfin/local.h
new file mode 100644
index 00000000000..75afffbc642
--- /dev/null
+++ b/include/asm-blackfin/local.h
@@ -0,0 +1,6 @@
+#ifndef __BLACKFIN_LOCAL_H
+#define __BLACKFIN_LOCAL_H
+
+#include <asm-generic/local.h>
+
+#endif /* __BLACKFIN_LOCAL_H */
diff --git a/include/asm-blackfin/mach-bf533/anomaly.h b/include/asm-blackfin/mach-bf533/anomaly.h
new file mode 100644
index 00000000000..a84d3909345
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/anomaly.h
@@ -0,0 +1,175 @@
+/*
+ * File: include/asm-blackfin/mach-bf533/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file shoule be up to date with:
+ * - Revision U, May 17, 2006; ADSP-BF533 Blackfin Processor Anomaly List
+ * - Revision Y, May 17, 2006; ADSP-BF532 Blackfin Processor Anomaly List
+ * - Revision T, May 17, 2006; ADSP-BF531 Blackfin Processor Anomaly List
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+
+/* We do not support 0.1 or 0.2 silicon - sorry */
+#if (defined(CONFIG_BF_REV_0_1) || defined(CONFIG_BF_REV_0_2))
+#error Kernel will not work on BF533 Version 0.1 or 0.2
+#endif
+
+/* Issues that are common to 0.5, 0.4, and 0.3 silicon */
+#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_4) || defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+ slot1 and store of a P register in slot 2 is not
+ supported */
+#define ANOMALY_05000105 /* Watchpoint Status Register (WPSTAT) bits are set on
+ every corresponding match */
+#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive
+ Channel DMA stops */
+#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR
+ registers. */
+#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out
+ upper bits*/
+#define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */
+#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame
+ syncs */
+#define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not
+ functional */
+#define ANOMALY_05000219 /* NMI event at boot time results in unpredictable
+ state */
+#define ANOMALY_05000229 /* SPI Slave Boot Mode modifies registers */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+ VDDint <=0.9V */
+#define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */
+#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after
+ an edge is detected may clear interrupt */
+#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause
+ DMA system instability */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+ not restored */
+#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic
+ control */
+#define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when
+ killed in a particular stage*/
+#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC
+ registers are interrupted */
+#define ANOMALY_05000311 /* Erroneous flag pin operations under specific sequences*/
+
+#endif
+
+/* These issues only occur on 0.3 or 0.4 BF533 */
+#if (defined(CONFIG_BF_REV_0_4) || defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not
+ updated at the same time. */
+#define ANOMALY_05000158 /* Boot fails when data cache enabled: Data from a Data
+ Cache Fill can be corrupted after or during
+ Instruction DMA if certain core stalls exist */
+#define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General
+ Purpose TX or RX modes */
+#define ANOMALY_05000198 /* Failing SYSTEM MMR accesses when stalled by
+ preceding memory read */
+#define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during
+ inactive channels in certain conditions */
+#define ANOMALY_05000202 /* Possible infinite stall with specific dual dag
+ situation */
+#define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */
+#define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */
+#define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect
+ data*/
+#define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate
+ Differences in certain Conditions */
+#define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */
+#define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to
+ hardware reset */
+#define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or
+ IDLE around a Change of Control causes
+ unpredictable results */
+#define ANOMALY_05000245 /* Spurious Hardware Error from an access in the
+ shadow of a conditional branch */
+#define ANOMALY_05000246 /* Data CPLB's should prevent spurious hardware
+ errors */
+#define ANOMALY_05000253 /* Maximum external clock speed for Timers */
+#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event
+ interrupt not functional */
+#define ANOMALY_05000257 /* An interrupt or exception during short Hardware
+ loops may cause the instruction fetch unit to
+ malfunction */
+#define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of
+ the ICPLB Data registers differ */
+#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */
+#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */
+#define ANOMALY_05000262 /* Stores to data cache may be lost */
+#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */
+#define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE
+ instruction will cause an infinite stall in the
+ second to last instruction in a hardware loop */
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+ SPORT external receive and transmit clocks. */
+#define ANOMALY_05000269 /* High I/O activity causes the output voltage of the
+ internal voltage regulator (VDDint) to increase. */
+#define ANOMALY_05000270 /* High I/O activity causes the output voltage of the
+ internal voltage regulator (VDDint) to decrease */
+#endif
+
+/* These issues are only on 0.4 silicon */
+#if (defined(CONFIG_BF_REV_0_4))
+#define ANOMALY_05000234 /* Incorrect Revision Number in DSPID Register */
+#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel
+ (TDM) */
+#endif
+
+/* These issues are only on 0.3 silicon */
+#if defined(CONFIG_BF_REV_0_3)
+#define ANOMALY_05000183 /* Timer Pin limitations for PPI TX Modes with
+ External Frame Syncs */
+#define ANOMALY_05000189 /* False Protection Exceptions caused by Speculative
+ Instruction or Data Fetches, or by Fetches at the
+ boundary of reserved memory space */
+#define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs
+ when polarity setting is changed */
+#define ANOMALY_05000194 /* Sport Restarting in specific modes may cause data
+ corruption */
+#define ANOMALY_05000199 /* DMA current address shows wrong value during carry
+ fix */
+#define ANOMALY_05000201 /* Receive frame sync not ignored during active
+ frames in sport MCM */
+#define ANOMALY_05000203 /* Specific sequence that can cause DMA error or DMA
+ stopping */
+#if defined(CONFIG_BF533)
+#define ANOMALY_05000204 /* Incorrect data read with write-through cache and
+ allocate cache lines on reads only mode */
+#endif /* CONFIG_BF533 */
+#define ANOMALY_05000207 /* Recovery from "brown-out" condition */
+#define ANOMALY_05000209 /* Speed-Path in computational unit affects certain
+ instructions */
+#define ANOMALY_05000233 /* PPI_FS3 is not driven in 2 or 3 internal Frame
+ Sync Transmit Mode */
+#define ANOMALY_05000271 /* Spontaneous reset of Internal Voltage Regulator */
+#endif
+
+#endif /* _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf533/bf533.h b/include/asm-blackfin/mach-bf533/bf533.h
new file mode 100644
index 00000000000..185fc128485
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/bf533.h
@@ -0,0 +1,306 @@
+/*
+ * File: include/asm-blackfin/mach-bf533/bf533.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MACH_BF533_H__
+#define __MACH_BF533_H__
+
+#define SUPPORTED_REVID 2
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+
+/*some misc defines*/
+#define IMASK_IVG15 0x8000
+#define IMASK_IVG14 0x4000
+#define IMASK_IVG13 0x2000
+#define IMASK_IVG12 0x1000
+
+#define IMASK_IVG11 0x0800
+#define IMASK_IVG10 0x0400
+#define IMASK_IVG9 0x0200
+#define IMASK_IVG8 0x0100
+
+#define IMASK_IVG7 0x0080
+#define IMASK_IVGTMR 0x0040
+#define IMASK_IVGHW 0x0020
+
+/***************************/
+
+
+#define BLKFIN_DSUBBANKS 4
+#define BLKFIN_DWAYS 2
+#define BLKFIN_DLINES 64
+#define BLKFIN_ISUBBANKS 4
+#define BLKFIN_IWAYS 4
+#define BLKFIN_ILINES 32
+
+#define WAY0_L 0x1
+#define WAY1_L 0x2
+#define WAY01_L 0x3
+#define WAY2_L 0x4
+#define WAY02_L 0x5
+#define WAY12_L 0x6
+#define WAY012_L 0x7
+
+#define WAY3_L 0x8
+#define WAY03_L 0x9
+#define WAY13_L 0xA
+#define WAY013_L 0xB
+
+#define WAY32_L 0xC
+#define WAY320_L 0xD
+#define WAY321_L 0xE
+#define WAYALL_L 0xF
+
+#define DMC_ENABLE (2<<2) /*yes, 2, not 1 */
+
+/* IAR0 BIT FIELDS*/
+#define RTC_ERROR_BIT 0x0FFFFFFF
+#define UART_ERROR_BIT 0xF0FFFFFF
+#define SPORT1_ERROR_BIT 0xFF0FFFFF
+#define SPI_ERROR_BIT 0xFFF0FFFF
+#define SPORT0_ERROR_BIT 0xFFFF0FFF
+#define PPI_ERROR_BIT 0xFFFFF0FF
+#define DMA_ERROR_BIT 0xFFFFFF0F
+#define PLLWAKE_ERROR_BIT 0xFFFFFFFF
+
+/* IAR1 BIT FIELDS*/
+#define DMA7_UARTTX_BIT 0x0FFFFFFF
+#define DMA6_UARTRX_BIT 0xF0FFFFFF
+#define DMA5_SPI_BIT 0xFF0FFFFF
+#define DMA4_SPORT1TX_BIT 0xFFF0FFFF
+#define DMA3_SPORT1RX_BIT 0xFFFF0FFF
+#define DMA2_SPORT0TX_BIT 0xFFFFF0FF
+#define DMA1_SPORT0RX_BIT 0xFFFFFF0F
+#define DMA0_PPI_BIT 0xFFFFFFFF
+
+/* IAR2 BIT FIELDS*/
+#define WDTIMER_BIT 0x0FFFFFFF
+#define MEMDMA1_BIT 0xF0FFFFFF
+#define MEMDMA0_BIT 0xFF0FFFFF
+#define PFB_BIT 0xFFF0FFFF
+#define PFA_BIT 0xFFFF0FFF
+#define TIMER2_BIT 0xFFFFF0FF
+#define TIMER1_BIT 0xFFFFFF0F
+#define TIMER0_BIT 0xFFFFFFFF
+
+/********************************* EBIU Settings ************************************/
+#define AMBCTL0VAL ((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL ((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#ifdef CONFIG_C_AMBEN_ALL
+#define V_AMBEN AMBEN_ALL
+#endif
+#ifdef CONFIG_C_AMBEN
+#define V_AMBEN 0x0
+#endif
+#ifdef CONFIG_C_AMBEN_B0
+#define V_AMBEN AMBEN_B0
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1
+#define V_AMBEN AMBEN_B0_B1
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1_B2
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL (V_AMBEN | V_AMCKEN | V_CDPRIO)
+
+#define MAX_VC 650000000
+#define MIN_VC 50000000
+
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+/********************************PLL Settings **************************************/
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT > 64)
+#error "VCO Multiplier is more than 64. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ > CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1)
+#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK
+#endif
+
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF533
+#define CPU "BF533"
+#define CPUID 0x027a5000
+#endif
+#ifdef CONFIG_BF532
+#define CPU "BF532"
+#define CPUID 0x0275A000
+#endif
+#ifdef CONFIG_BF531
+#define CPU "BF531"
+#define CPUID 0x027a5000
+#endif
+#ifndef CPU
+#define CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM mem size must be multible of 4MB"
+#endif
+
+#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND 0x200
+#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else /*Write Through */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_DIRTY \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#endif
+
+#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+
+#define SIZE_1K 0x00000400 /* 1K */
+#define SIZE_4K 0x00001000 /* 4K */
+#define SIZE_1M 0x00100000 /* 1M */
+#define SIZE_4M 0x00400000 /* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 1 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2)
+
+#endif /* __MACH_BF533_H__ */
diff --git a/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
new file mode 100644
index 00000000000..23bf76aa345
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
@@ -0,0 +1,108 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS 1
+
+#define OFFSET_THR 0x00 /* Transmit Holding register */
+#define OFFSET_RBR 0x00 /* Receive Buffer register */
+#define OFFSET_DLL 0x00 /* Divisor Latch (Low-Byte) */
+#define OFFSET_IER 0x04 /* Interrupt Enable Register */
+#define OFFSET_DLH 0x04 /* Divisor Latch (High-Byte) */
+#define OFFSET_IIR 0x08 /* Interrupt Identification Register */
+#define OFFSET_LCR 0x0C /* Line Control Register */
+#define OFFSET_MCR 0x10 /* Modem Control Register */
+#define OFFSET_LSR 0x14 /* Line Status Register */
+#define OFFSET_MSR 0x18 /* Modem Status Register */
+#define OFFSET_SCR 0x1C /* SCR Scratch Register */
+#define OFFSET_GCTL 0x24 /* Global Control Register */
+
+#define UART_GET_CHAR(uart) bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart) bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart) bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_PUT_IER(uart,v) bfin_write16(((uart)->port.membase + OFFSET_IER),v)
+#define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+# define CONFIG_SERIAL_BFIN_CTSRTS
+# ifndef CONFIG_UART0_CTS_PIN
+# define CONFIG_UART0_CTS_PIN -1
+# endif
+# ifndef CONFIG_UART0_RTS_PIN
+# define CONFIG_UART0_RTS_PIN -1
+# endif
+#endif
+
+struct bfin_serial_port {
+ struct uart_port port;
+ unsigned int old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ int tx_done;
+ int tx_count;
+ struct circ_buf rx_dma_buf;
+ struct timer_list rx_dma_timer;
+ int rx_dma_nrows;
+ unsigned int tx_dma_channel;
+ unsigned int rx_dma_channel;
+ struct work_struct tx_dma_workqueue;
+#else
+ struct work_struct cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int cts_pin;
+ int rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+ unsigned long uart_base_addr;
+ int uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ unsigned int uart_tx_dma_channel;
+ unsigned int uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int uart_cts_pin;
+ int uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+ 0xFFC00400,
+ IRQ_UART_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART_TX,
+ CH_UART_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+ CONFIG_UART0_CTS_PIN,
+ CONFIG_UART0_RTS_PIN,
+#endif
+};
+
+
+int nr_ports = NR_PORTS;
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ if (uart->cts_pin >= 0) {
+ gpio_request(uart->cts_pin, NULL);
+ gpio_direction_input(uart->cts_pin);
+ }
+ if (uart->rts_pin >= 0) {
+ gpio_request(uart->rts_pin, NULL);
+ gpio_direction_input(uart->rts_pin);
+ }
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf533/blackfin.h b/include/asm-blackfin/mach-bf533/blackfin.h
new file mode 100644
index 00000000000..e4384491e97
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/blackfin.h
@@ -0,0 +1,45 @@
+/*
+ * File: include/asm-blackfin/mach-bf533/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF533_FAMILY
+
+#include "bf533.h"
+#include "mem_map.h"
+#include "defBF532.h"
+#include "anomaly.h"
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#include "cdefBF532.h"
+#endif
+
+#endif /* _MACH_BLACKFIN_H_ */
diff --git a/include/asm-blackfin/mach-bf533/cdefBF532.h b/include/asm-blackfin/mach-bf533/cdefBF532.h
new file mode 100644
index 00000000000..1d7c494ceb6
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/cdefBF532.h
@@ -0,0 +1,706 @@
+/*
+ * File: include/asm-blackfin/mach-bf533/cdefBF532.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF532_H
+#define _CDEF_BF532_H
+/*
+#if !defined(__ADSPLPBLACKFIN__)
+#warning cdefBF532.h should only be included for 532 compatible chips.
+#endif
+*/
+/*include all Core registers and bit definitions*/
+#include "defBF532.h"
+
+/*include core specific register pointer definitions*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+#include <asm/system.h>
+
+/* Clock and System Control (0xFFC0 0400-0xFFC0 07FF) */
+#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
+#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL,val)
+#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
+#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
+#define bfin_read_PLL_LOCKCNT() bfin_read16(PLL_LOCKCNT)
+#define bfin_write_PLL_LOCKCNT(val) bfin_write16(PLL_LOCKCNT,val)
+#define bfin_read_CHIPID() bfin_read32(CHIPID)
+#define bfin_read_SWRST() bfin_read16(SWRST)
+#define bfin_write_SWRST(val) bfin_write16(SWRST,val)
+#define bfin_read_SYSCR() bfin_read16(SYSCR)
+#define bfin_write_SYSCR(val) bfin_write16(SYSCR,val)
+#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
+#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV,val)
+#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+ unsigned long flags, iwr;
+
+ bfin_write16(VR_CTL, val);
+ __builtin_bfin_ssync();
+ /* Enable the PLL Wakeup bit in SIC IWR */
+ iwr = bfin_read32(SIC_IWR);
+ /* Only allow PPL Wakeup) */
+ bfin_write32(SIC_IWR, IWR_ENABLE(0));
+ local_irq_save(flags);
+ asm("IDLE;");
+ local_irq_restore(flags);
+ bfin_write32(SIC_IWR, iwr);
+}
+
+/* System Interrupt Controller (0xFFC0 0C00-0xFFC0 0FFF) */
+#define bfin_read_SIC_IAR0() bfin_read32(SIC_IAR0)
+#define bfin_write_SIC_IAR0(val) bfin_write32(SIC_IAR0,val)
+#define bfin_read_SIC_IAR1() bfin_read32(SIC_IAR1)
+#define bfin_write_SIC_IAR1(val) bfin_write32(SIC_IAR1,val)
+#define bfin_read_SIC_IAR2() bfin_read32(SIC_IAR2)
+#define bfin_write_SIC_IAR2(val) bfin_write32(SIC_IAR2,val)
+#define bfin_read_SIC_IAR3() bfin_read32(SIC_IAR3)
+#define bfin_write_SIC_IAR3(val) bfin_write32(SIC_IAR3,val)
+#define bfin_read_SIC_IMASK() bfin_read32(SIC_IMASK)
+#define bfin_write_SIC_IMASK(val) bfin_write32(SIC_IMASK,val)
+#define bfin_read_SIC_ISR() bfin_read32(SIC_ISR)
+#define bfin_write_SIC_ISR(val) bfin_write32(SIC_ISR,val)
+#define bfin_read_SIC_IWR() bfin_read32(SIC_IWR)
+#define bfin_write_SIC_IWR(val) bfin_write32(SIC_IWR,val)
+
+/* Watchdog Timer (0xFFC0 1000-0xFFC0 13FF) */
+#define bfin_read_WDOG_CTL() bfin_read16(WDOG_CTL)
+#define bfin_write_WDOG_CTL(val) bfin_write16(WDOG_CTL,val)
+#define bfin_read_WDOG_CNT() bfin_read32(WDOG_CNT)
+#define bfin_write_WDOG_CNT(val) bfin_write32(WDOG_CNT,val)
+#define bfin_read_WDOG_STAT() bfin_read32(WDOG_STAT)
+#define bfin_write_WDOG_STAT(val) bfin_write32(WDOG_STAT,val)
+
+/* Real Time Clock (0xFFC0 1400-0xFFC0 17FF) */
+#define bfin_read_RTC_STAT() bfin_read32(RTC_STAT)
+#define bfin_write_RTC_STAT(val) bfin_write32(RTC_STAT,val)
+#define bfin_read_RTC_ICTL() bfin_read16(RTC_ICTL)
+#define bfin_write_RTC_ICTL(val) bfin_write16(RTC_ICTL,val)
+#define bfin_read_RTC_ISTAT() bfin_read16(RTC_ISTAT)
+#define bfin_write_RTC_ISTAT(val) bfin_write16(RTC_ISTAT,val)
+#define bfin_read_RTC_SWCNT() bfin_read16(RTC_SWCNT)
+#define bfin_write_RTC_SWCNT(val) bfin_write16(RTC_SWCNT,val)
+#define bfin_read_RTC_ALARM() bfin_read32(RTC_ALARM)
+#define bfin_write_RTC_ALARM(val) bfin_write32(RTC_ALARM,val)
+#define bfin_read_RTC_FAST() bfin_read16(RTC_FAST)
+#define bfin_write_RTC_FAST(val) bfin_write16(RTC_FAST,val)
+#define bfin_read_RTC_PREN() bfin_read16(RTC_PREN)
+#define bfin_write_RTC_PREN(val) bfin_write16(RTC_PREN,val)
+
+/* General Purpose IO (0xFFC0 2400-0xFFC0 27FF) */
+#define bfin_read_FIO_DIR() bfin_read16(FIO_DIR)
+#define bfin_write_FIO_DIR(val) bfin_write16(FIO_DIR,val)
+#define bfin_read_FIO_FLAG_C() bfin_read16(FIO_FLAG_C)
+#define bfin_write_FIO_FLAG_C(val) bfin_write16(FIO_FLAG_C,val)
+#define bfin_read_FIO_FLAG_S() bfin_read16(FIO_FLAG_S)
+#define bfin_write_FIO_FLAG_S(val) bfin_write16(FIO_FLAG_S,val)
+#define bfin_read_FIO_MASKA_C() bfin_read16(FIO_MASKA_C)
+#define bfin_write_FIO_MASKA_C(val) bfin_write16(FIO_MASKA_C,val)
+#define bfin_read_FIO_MASKA_S() bfin_read16(FIO_MASKA_S)
+#define bfin_write_FIO_MASKA_S(val) bfin_write16(FIO_MASKA_S,val)
+#define bfin_read_FIO_MASKB_C() bfin_read16(FIO_MASKB_C)
+#define bfin_write_FIO_MASKB_C(val) bfin_write16(FIO_MASKB_C,val)
+#define bfin_read_FIO_MASKB_S() bfin_read16(FIO_MASKB_S)
+#define bfin_write_FIO_MASKB_S(val) bfin_write16(FIO_MASKB_S,val)
+#define bfin_read_FIO_POLAR() bfin_read16(FIO_POLAR)
+#define bfin_write_FIO_POLAR(val) bfin_write16(FIO_POLAR,val)
+#define bfin_read_FIO_EDGE() bfin_read16(FIO_EDGE)
+#define bfin_write_FIO_EDGE(val) bfin_write16(FIO_EDGE,val)
+#define bfin_read_FIO_BOTH() bfin_read16(FIO_BOTH)
+#define bfin_write_FIO_BOTH(val) bfin_write16(FIO_BOTH,val)
+#define bfin_read_FIO_INEN() bfin_read16(FIO_INEN)
+#define bfin_write_FIO_INEN(val) bfin_write16(FIO_INEN,val)
+#define bfin_read_FIO_FLAG_D() bfin_read16(FIO_FLAG_D)
+#define bfin_write_FIO_FLAG_D(val) bfin_write16(FIO_FLAG_D,val)
+#define bfin_read_FIO_FLAG_T() bfin_read16(FIO_FLAG_T)
+#define bfin_write_FIO_FLAG_T(val) bfin_write16(FIO_FLAG_T,val)
+#define bfin_read_FIO_MASKA_D() bfin_read16(FIO_MASKA_D)
+#define bfin_write_FIO_MASKA_D(val) bfin_write16(FIO_MASKA_D,val)
+#define bfin_read_FIO_MASKA_T() bfin_read16(FIO_MASKA_T)
+#define bfin_write_FIO_MASKA_T(val) bfin_write16(FIO_MASKA_T,val)
+#define bfin_read_FIO_MASKB_D() bfin_read16(FIO_MASKB_D)
+#define bfin_write_FIO_MASKB_D(val) bfin_write16(FIO_MASKB_D,val)
+#define bfin_read_FIO_MASKB_T() bfin_read16(FIO_MASKB_T)
+#define bfin_write_FIO_MASKB_T(val) bfin_write16(FIO_MASKB_T,val)
+
+/* DMA Traffic controls */
+#define bfin_read_DMA_TCPER() bfin_read16(DMA_TCPER)
+#define bfin_write_DMA_TCPER(val) bfin_write16(DMA_TCPER,val)
+#define bfin_read_DMA_TCCNT() bfin_read16(DMA_TCCNT)
+#define bfin_write_DMA_TCCNT(val) bfin_write16(DMA_TCCNT,val)
+#define bfin_read_DMA_TC_PER() bfin_read16(DMA_TC_PER)
+#define bfin_write_DMA_TC_PER(val) bfin_write16(DMA_TC_PER,val)
+#define bfin_read_DMA_TC_CNT() bfin_read16(DMA_TC_CNT)
+#define bfin_write_DMA_TC_CNT(val) bfin_write16(DMA_TC_CNT,val)
+
+/* DMA Controller */
+#define bfin_read_DMA0_CONFIG() bfin_read16(DMA0_CONFIG)
+#define bfin_write_DMA0_CONFIG(val) bfin_write16(DMA0_CONFIG,val)
+#define bfin_read_DMA0_NEXT_DESC_PTR() bfin_read32(DMA0_NEXT_DESC_PTR)
+#define bfin_write_DMA0_NEXT_DESC_PTR(val) bfin_write32(DMA0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA0_START_ADDR() bfin_read32(DMA0_START_ADDR)
+#define bfin_write_DMA0_START_ADDR(val) bfin_write32(DMA0_START_ADDR,val)
+#define bfin_read_DMA0_X_COUNT() bfin_read16(DMA0_X_COUNT)
+#define bfin_write_DMA0_X_COUNT(val) bfin_write16(DMA0_X_COUNT,val)
+#define bfin_read_DMA0_Y_COUNT() bfin_read16(DMA0_Y_COUNT)
+#define bfin_write_DMA0_Y_COUNT(val) bfin_write16(DMA0_Y_COUNT,val)
+#define bfin_read_DMA0_X_MODIFY() bfin_read16(DMA0_X_MODIFY)
+#define bfin_write_DMA0_X_MODIFY(val) bfin_write16(DMA0_X_MODIFY,val)
+#define bfin_read_DMA0_Y_MODIFY() bfin_read16(DMA0_Y_MODIFY)
+#define bfin_write_DMA0_Y_MODIFY(val) bfin_write16(DMA0_Y_MODIFY,val)
+#define bfin_read_DMA0_CURR_DESC_PTR() bfin_read32(DMA0_CURR_DESC_PTR)
+#define bfin_write_DMA0_CURR_DESC_PTR(val) bfin_write32(DMA0_CURR_DESC_PTR,val)
+#define bfin_read_DMA0_CURR_ADDR() bfin_read32(DMA0_CURR_ADDR)
+#define bfin_write_DMA0_CURR_ADDR(val) bfin_write32(DMA0_CURR_ADDR,val)
+#define bfin_read_DMA0_CURR_X_COUNT() bfin_read16(DMA0_CURR_X_COUNT)
+#define bfin_write_DMA0_CURR_X_COUNT(val) bfin_write16(DMA0_CURR_X_COUNT,val)
+#define bfin_read_DMA0_CURR_Y_COUNT() bfin_read16(DMA0_CURR_Y_COUNT)
+#define bfin_write_DMA0_CURR_Y_COUNT(val) bfin_write16(DMA0_CURR_Y_COUNT,val)
+#define bfin_read_DMA0_IRQ_STATUS() bfin_read16(DMA0_IRQ_STATUS)
+#define bfin_write_DMA0_IRQ_STATUS(val) bfin_write16(DMA0_IRQ_STATUS,val)
+#define bfin_read_DMA0_PERIPHERAL_MAP() bfin_read16(DMA0_PERIPHERAL_MAP)
+#define bfin_write_DMA0_PERIPHERAL_MAP(val) bfin_write16(DMA0_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA1_CONFIG() bfin_read16(DMA1_CONFIG)
+#define bfin_write_DMA1_CONFIG(val) bfin_write16(DMA1_CONFIG,val)
+#define bfin_read_DMA1_NEXT_DESC_PTR() bfin_read32(DMA1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_NEXT_DESC_PTR(val) bfin_write32(DMA1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_START_ADDR() bfin_read32(DMA1_START_ADDR)
+#define bfin_write_DMA1_START_ADDR(val) bfin_write32(DMA1_START_ADDR,val)
+#define bfin_read_DMA1_X_COUNT() bfin_read16(DMA1_X_COUNT)
+#define bfin_write_DMA1_X_COUNT(val) bfin_write16(DMA1_X_COUNT,val)
+#define bfin_read_DMA1_Y_COUNT() bfin_read16(DMA1_Y_COUNT)
+#define bfin_write_DMA1_Y_COUNT(val) bfin_write16(DMA1_Y_COUNT,val)
+#define bfin_read_DMA1_X_MODIFY() bfin_read16(DMA1_X_MODIFY)
+#define bfin_write_DMA1_X_MODIFY(val) bfin_write16(DMA1_X_MODIFY,val)
+#define bfin_read_DMA1_Y_MODIFY() bfin_read16(DMA1_Y_MODIFY)
+#define bfin_write_DMA1_Y_MODIFY(val) bfin_write16(DMA1_Y_MODIFY,val)
+#define bfin_read_DMA1_CURR_DESC_PTR() bfin_read32(DMA1_CURR_DESC_PTR)
+#define bfin_write_DMA1_CURR_DESC_PTR(val) bfin_write32(DMA1_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_CURR_ADDR() bfin_read32(DMA1_CURR_ADDR)
+#define bfin_write_DMA1_CURR_ADDR(val) bfin_write32(DMA1_CURR_ADDR,val)
+#define bfin_read_DMA1_CURR_X_COUNT() bfin_read16(DMA1_CURR_X_COUNT)
+#define bfin_write_DMA1_CURR_X_COUNT(val) bfin_write16(DMA1_CURR_X_COUNT,val)
+#define bfin_read_DMA1_CURR_Y_COUNT() bfin_read16(DMA1_CURR_Y_COUNT)
+#define bfin_write_DMA1_CURR_Y_COUNT(val) bfin_write16(DMA1_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_IRQ_STATUS() bfin_read16(DMA1_IRQ_STATUS)
+#define bfin_write_DMA1_IRQ_STATUS(val) bfin_write16(DMA1_IRQ_STATUS,val)
+#define bfin_read_DMA1_PERIPHERAL_MAP() bfin_read16(DMA1_PERIPHERAL_MAP)
+#define bfin_write_DMA1_PERIPHERAL_MAP(val) bfin_write16(DMA1_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA2_CONFIG() bfin_read16(DMA2_CONFIG)
+#define bfin_write_DMA2_CONFIG(val) bfin_write16(DMA2_CONFIG,val)
+#define bfin_read_DMA2_NEXT_DESC_PTR() bfin_read32(DMA2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_NEXT_DESC_PTR(val) bfin_write32(DMA2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_START_ADDR() bfin_read32(DMA2_START_ADDR)
+#define bfin_write_DMA2_START_ADDR(val) bfin_write32(DMA2_START_ADDR,val)
+#define bfin_read_DMA2_X_COUNT() bfin_read16(DMA2_X_COUNT)
+#define bfin_write_DMA2_X_COUNT(val) bfin_write16(DMA2_X_COUNT,val)
+#define bfin_read_DMA2_Y_COUNT() bfin_read16(DMA2_Y_COUNT)
+#define bfin_write_DMA2_Y_COUNT(val) bfin_write16(DMA2_Y_COUNT,val)
+#define bfin_read_DMA2_X_MODIFY() bfin_read16(DMA2_X_MODIFY)
+#define bfin_write_DMA2_X_MODIFY(val) bfin_write16(DMA2_X_MODIFY,val)
+#define bfin_read_DMA2_Y_MODIFY() bfin_read16(DMA2_Y_MODIFY)
+#define bfin_write_DMA2_Y_MODIFY(val) bfin_write16(DMA2_Y_MODIFY,val)
+#define bfin_read_DMA2_CURR_DESC_PTR() bfin_read32(DMA2_CURR_DESC_PTR)
+#define bfin_write_DMA2_CURR_DESC_PTR(val) bfin_write32(DMA2_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_CURR_ADDR() bfin_read32(DMA2_CURR_ADDR)
+#define bfin_write_DMA2_CURR_ADDR(val) bfin_write32(DMA2_CURR_ADDR,val)
+#define bfin_read_DMA2_CURR_X_COUNT() bfin_read16(DMA2_CURR_X_COUNT)
+#define bfin_write_DMA2_CURR_X_COUNT(val) bfin_write16(DMA2_CURR_X_COUNT,val)
+#define bfin_read_DMA2_CURR_Y_COUNT() bfin_read16(DMA2_CURR_Y_COUNT)
+#define bfin_write_DMA2_CURR_Y_COUNT(val) bfin_write16(DMA2_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_IRQ_STATUS() bfin_read16(DMA2_IRQ_STATUS)
+#define bfin_write_DMA2_IRQ_STATUS(val) bfin_write16(DMA2_IRQ_STATUS,val)
+#define bfin_read_DMA2_PERIPHERAL_MAP() bfin_read16(DMA2_PERIPHERAL_MAP)
+#define bfin_write_DMA2_PERIPHERAL_MAP(val) bfin_write16(DMA2_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA3_CONFIG() bfin_read16(DMA3_CONFIG)
+#define bfin_write_DMA3_CONFIG(val) bfin_write16(DMA3_CONFIG,val)
+#define bfin_read_DMA3_NEXT_DESC_PTR() bfin_read32(DMA3_NEXT_DESC_PTR)
+#define bfin_write_DMA3_NEXT_DESC_PTR(val) bfin_write32(DMA3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA3_START_ADDR() bfin_read32(DMA3_START_ADDR)
+#define bfin_write_DMA3_START_ADDR(val) bfin_write32(DMA3_START_ADDR,val)
+#define bfin_read_DMA3_X_COUNT() bfin_read16(DMA3_X_COUNT)
+#define bfin_write_DMA3_X_COUNT(val) bfin_write16(DMA3_X_COUNT,val)
+#define bfin_read_DMA3_Y_COUNT() bfin_read16(DMA3_Y_COUNT)
+#define bfin_write_DMA3_Y_COUNT(val) bfin_write16(DMA3_Y_COUNT,val)
+#define bfin_read_DMA3_X_MODIFY() bfin_read16(DMA3_X_MODIFY)
+#define bfin_write_DMA3_X_MODIFY(val) bfin_write16(DMA3_X_MODIFY,val)
+#define bfin_read_DMA3_Y_MODIFY() bfin_read16(DMA3_Y_MODIFY)
+#define bfin_write_DMA3_Y_MODIFY(val) bfin_write16(DMA3_Y_MODIFY,val)
+#define bfin_read_DMA3_CURR_DESC_PTR() bfin_read32(DMA3_CURR_DESC_PTR)
+#define bfin_write_DMA3_CURR_DESC_PTR(val) bfin_write32(DMA3_CURR_DESC_PTR,val)
+#define bfin_read_DMA3_CURR_ADDR() bfin_read32(DMA3_CURR_ADDR)
+#define bfin_write_DMA3_CURR_ADDR(val) bfin_write32(DMA3_CURR_ADDR,val)
+#define bfin_read_DMA3_CURR_X_COUNT() bfin_read16(DMA3_CURR_X_COUNT)
+#define bfin_write_DMA3_CURR_X_COUNT(val) bfin_write16(DMA3_CURR_X_COUNT,val)
+#define bfin_read_DMA3_CURR_Y_COUNT() bfin_read16(DMA3_CURR_Y_COUNT)
+#define bfin_write_DMA3_CURR_Y_COUNT(val) bfin_write16(DMA3_CURR_Y_COUNT,val)
+#define bfin_read_DMA3_IRQ_STATUS() bfin_read16(DMA3_IRQ_STATUS)
+#define bfin_write_DMA3_IRQ_STATUS(val) bfin_write16(DMA3_IRQ_STATUS,val)
+#define bfin_read_DMA3_PERIPHERAL_MAP() bfin_read16(DMA3_PERIPHERAL_MAP)
+#define bfin_write_DMA3_PERIPHERAL_MAP(val) bfin_write16(DMA3_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA4_CONFIG() bfin_read16(DMA4_CONFIG)
+#define bfin_write_DMA4_CONFIG(val) bfin_write16(DMA4_CONFIG,val)
+#define bfin_read_DMA4_NEXT_DESC_PTR() bfin_read32(DMA4_NEXT_DESC_PTR)
+#define bfin_write_DMA4_NEXT_DESC_PTR(val) bfin_write32(DMA4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA4_START_ADDR() bfin_read32(DMA4_START_ADDR)
+#define bfin_write_DMA4_START_ADDR(val) bfin_write32(DMA4_START_ADDR,val)
+#define bfin_read_DMA4_X_COUNT() bfin_read16(DMA4_X_COUNT)
+#define bfin_write_DMA4_X_COUNT(val) bfin_write16(DMA4_X_COUNT,val)
+#define bfin_read_DMA4_Y_COUNT() bfin_read16(DMA4_Y_COUNT)
+#define bfin_write_DMA4_Y_COUNT(val) bfin_write16(DMA4_Y_COUNT,val)
+#define bfin_read_DMA4_X_MODIFY() bfin_read16(DMA4_X_MODIFY)
+#define bfin_write_DMA4_X_MODIFY(val) bfin_write16(DMA4_X_MODIFY,val)
+#define bfin_read_DMA4_Y_MODIFY() bfin_read16(DMA4_Y_MODIFY)
+#define bfin_write_DMA4_Y_MODIFY(val) bfin_write16(DMA4_Y_MODIFY,val)
+#define bfin_read_DMA4_CURR_DESC_PTR() bfin_read32(DMA4_CURR_DESC_PTR)
+#define bfin_write_DMA4_CURR_DESC_PTR(val) bfin_write32(DMA4_CURR_DESC_PTR,val)
+#define bfin_read_DMA4_CURR_ADDR() bfin_read32(DMA4_CURR_ADDR)
+#define bfin_write_DMA4_CURR_ADDR(val) bfin_write32(DMA4_CURR_ADDR,val)
+#define bfin_read_DMA4_CURR_X_COUNT() bfin_read16(DMA4_CURR_X_COUNT)
+#define bfin_write_DMA4_CURR_X_COUNT(val) bfin_write16(DMA4_CURR_X_COUNT,val)
+#define bfin_read_DMA4_CURR_Y_COUNT() bfin_read16(DMA4_CURR_Y_COUNT)
+#define bfin_write_DMA4_CURR_Y_COUNT(val) bfin_write16(DMA4_CURR_Y_COUNT,val)
+#define bfin_read_DMA4_IRQ_STATUS() bfin_read16(DMA4_IRQ_STATUS)
+#define bfin_write_DMA4_IRQ_STATUS(val) bfin_write16(DMA4_IRQ_STATUS,val)
+#define bfin_read_DMA4_PERIPHERAL_MAP() bfin_read16(DMA4_PERIPHERAL_MAP)
+#define bfin_write_DMA4_PERIPHERAL_MAP(val) bfin_write16(DMA4_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA5_CONFIG() bfin_read16(DMA5_CONFIG)
+#define bfin_write_DMA5_CONFIG(val) bfin_write16(DMA5_CONFIG,val)
+#define bfin_read_DMA5_NEXT_DESC_PTR() bfin_read32(DMA5_NEXT_DESC_PTR)
+#define bfin_write_DMA5_NEXT_DESC_PTR(val) bfin_write32(DMA5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA5_START_ADDR() bfin_read32(DMA5_START_ADDR)
+#define bfin_write_DMA5_START_ADDR(val) bfin_write32(DMA5_START_ADDR,val)
+#define bfin_read_DMA5_X_COUNT() bfin_read16(DMA5_X_COUNT)
+#define bfin_write_DMA5_X_COUNT(val) bfin_write16(DMA5_X_COUNT,val)
+#define bfin_read_DMA5_Y_COUNT() bfin_read16(DMA5_Y_COUNT)
+#define bfin_write_DMA5_Y_COUNT(val) bfin_write16(DMA5_Y_COUNT,val)
+#define bfin_read_DMA5_X_MODIFY() bfin_read16(DMA5_X_MODIFY)
+#define bfin_write_DMA5_X_MODIFY(val) bfin_write16(DMA5_X_MODIFY,val)
+#define bfin_read_DMA5_Y_MODIFY() bfin_read16(DMA5_Y_MODIFY)
+#define bfin_write_DMA5_Y_MODIFY(val) bfin_write16(DMA5_Y_MODIFY,val)
+#define bfin_read_DMA5_CURR_DESC_PTR() bfin_read32(DMA5_CURR_DESC_PTR)
+#define bfin_write_DMA5_CURR_DESC_PTR(val) bfin_write32(DMA5_CURR_DESC_PTR,val)
+#define bfin_read_DMA5_CURR_ADDR() bfin_read32(DMA5_CURR_ADDR)
+#define bfin_write_DMA5_CURR_ADDR(val) bfin_write32(DMA5_CURR_ADDR,val)
+#define bfin_read_DMA5_CURR_X_COUNT() bfin_read16(DMA5_CURR_X_COUNT)
+#define bfin_write_DMA5_CURR_X_COUNT(val) bfin_write16(DMA5_CURR_X_COUNT,val)
+#define bfin_read_DMA5_CURR_Y_COUNT() bfin_read16(DMA5_CURR_Y_COUNT)
+#define bfin_write_DMA5_CURR_Y_COUNT(val) bfin_write16(DMA5_CURR_Y_COUNT,val)
+#define bfin_read_DMA5_IRQ_STATUS() bfin_read16(DMA5_IRQ_STATUS)
+#define bfin_write_DMA5_IRQ_STATUS(val) bfin_write16(DMA5_IRQ_STATUS,val)
+#define bfin_read_DMA5_PERIPHERAL_MAP() bfin_read16(DMA5_PERIPHERAL_MAP)
+#define bfin_write_DMA5_PERIPHERAL_MAP(val) bfin_write16(DMA5_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA6_CONFIG() bfin_read16(DMA6_CONFIG)
+#define bfin_write_DMA6_CONFIG(val) bfin_write16(DMA6_CONFIG,val)
+#define bfin_read_DMA6_NEXT_DESC_PTR() bfin_read32(DMA6_NEXT_DESC_PTR)
+#define bfin_write_DMA6_NEXT_DESC_PTR(val) bfin_write32(DMA6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA6_START_ADDR() bfin_read32(DMA6_START_ADDR)
+#define bfin_write_DMA6_START_ADDR(val) bfin_write32(DMA6_START_ADDR,val)
+#define bfin_read_DMA6_X_COUNT() bfin_read16(DMA6_X_COUNT)
+#define bfin_write_DMA6_X_COUNT(val) bfin_write16(DMA6_X_COUNT,val)
+#define bfin_read_DMA6_Y_COUNT() bfin_read16(DMA6_Y_COUNT)
+#define bfin_write_DMA6_Y_COUNT(val) bfin_write16(DMA6_Y_COUNT,val)
+#define bfin_read_DMA6_X_MODIFY() bfin_read16(DMA6_X_MODIFY)
+#define bfin_write_DMA6_X_MODIFY(val) bfin_write16(DMA6_X_MODIFY,val)
+#define bfin_read_DMA6_Y_MODIFY() bfin_read16(DMA6_Y_MODIFY)
+#define bfin_write_DMA6_Y_MODIFY(val) bfin_write16(DMA6_Y_MODIFY,val)
+#define bfin_read_DMA6_CURR_DESC_PTR() bfin_read32(DMA6_CURR_DESC_PTR)
+#define bfin_write_DMA6_CURR_DESC_PTR(val) bfin_write32(DMA6_CURR_DESC_PTR,val)
+#define bfin_read_DMA6_CURR_ADDR() bfin_read32(DMA6_CURR_ADDR)
+#define bfin_write_DMA6_CURR_ADDR(val) bfin_write32(DMA6_CURR_ADDR,val)
+#define bfin_read_DMA6_CURR_X_COUNT() bfin_read16(DMA6_CURR_X_COUNT)
+#define bfin_write_DMA6_CURR_X_COUNT(val) bfin_write16(DMA6_CURR_X_COUNT,val)
+#define bfin_read_DMA6_CURR_Y_COUNT() bfin_read16(DMA6_CURR_Y_COUNT)
+#define bfin_write_DMA6_CURR_Y_COUNT(val) bfin_write16(DMA6_CURR_Y_COUNT,val)
+#define bfin_read_DMA6_IRQ_STATUS() bfin_read16(DMA6_IRQ_STATUS)
+#define bfin_write_DMA6_IRQ_STATUS(val) bfin_write16(DMA6_IRQ_STATUS,val)
+#define bfin_read_DMA6_PERIPHERAL_MAP() bfin_read16(DMA6_PERIPHERAL_MAP)
+#define bfin_write_DMA6_PERIPHERAL_MAP(val) bfin_write16(DMA6_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA7_CONFIG() bfin_read16(DMA7_CONFIG)
+#define bfin_write_DMA7_CONFIG(val) bfin_write16(DMA7_CONFIG,val)
+#define bfin_read_DMA7_NEXT_DESC_PTR() bfin_read32(DMA7_NEXT_DESC_PTR)
+#define bfin_write_DMA7_NEXT_DESC_PTR(val) bfin_write32(DMA7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA7_START_ADDR() bfin_read32(DMA7_START_ADDR)
+#define bfin_write_DMA7_START_ADDR(val) bfin_write32(DMA7_START_ADDR,val)
+#define bfin_read_DMA7_X_COUNT() bfin_read16(DMA7_X_COUNT)
+#define bfin_write_DMA7_X_COUNT(val) bfin_write16(DMA7_X_COUNT,val)
+#define bfin_read_DMA7_Y_COUNT() bfin_read16(DMA7_Y_COUNT)
+#define bfin_write_DMA7_Y_COUNT(val) bfin_write16(DMA7_Y_COUNT,val)
+#define bfin_read_DMA7_X_MODIFY() bfin_read16(DMA7_X_MODIFY)
+#define bfin_write_DMA7_X_MODIFY(val) bfin_write16(DMA7_X_MODIFY,val)
+#define bfin_read_DMA7_Y_MODIFY() bfin_read16(DMA7_Y_MODIFY)
+#define bfin_write_DMA7_Y_MODIFY(val) bfin_write16(DMA7_Y_MODIFY,val)
+#define bfin_read_DMA7_CURR_DESC_PTR() bfin_read32(DMA7_CURR_DESC_PTR)
+#define bfin_write_DMA7_CURR_DESC_PTR(val) bfin_write32(DMA7_CURR_DESC_PTR,val)
+#define bfin_read_DMA7_CURR_ADDR() bfin_read32(DMA7_CURR_ADDR)
+#define bfin_write_DMA7_CURR_ADDR(val) bfin_write32(DMA7_CURR_ADDR,val)
+#define bfin_read_DMA7_CURR_X_COUNT() bfin_read16(DMA7_CURR_X_COUNT)
+#define bfin_write_DMA7_CURR_X_COUNT(val) bfin_write16(DMA7_CURR_X_COUNT,val)
+#define bfin_read_DMA7_CURR_Y_COUNT() bfin_read16(DMA7_CURR_Y_COUNT)
+#define bfin_write_DMA7_CURR_Y_COUNT(val) bfin_write16(DMA7_CURR_Y_COUNT,val)
+#define bfin_read_DMA7_IRQ_STATUS() bfin_read16(DMA7_IRQ_STATUS)
+#define bfin_write_DMA7_IRQ_STATUS(val) bfin_write16(DMA7_IRQ_STATUS,val)
+#define bfin_read_DMA7_PERIPHERAL_MAP() bfin_read16(DMA7_PERIPHERAL_MAP)
+#define bfin_write_DMA7_PERIPHERAL_MAP(val) bfin_write16(DMA7_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D1_CONFIG() bfin_read16(MDMA_D1_CONFIG)
+#define bfin_write_MDMA_D1_CONFIG(val) bfin_write16(MDMA_D1_CONFIG,val)
+#define bfin_read_MDMA_D1_NEXT_DESC_PTR() bfin_read32(MDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D1_START_ADDR() bfin_read32(MDMA_D1_START_ADDR)
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write32(MDMA_D1_START_ADDR,val)
+#define bfin_read_MDMA_D1_X_COUNT() bfin_read16(MDMA_D1_X_COUNT)
+#define bfin_write_MDMA_D1_X_COUNT(val) bfin_write16(MDMA_D1_X_COUNT,val)
+#define bfin_read_MDMA_D1_Y_COUNT() bfin_read16(MDMA_D1_Y_COUNT)
+#define bfin_write_MDMA_D1_Y_COUNT(val) bfin_write16(MDMA_D1_Y_COUNT,val)
+#define bfin_read_MDMA_D1_X_MODIFY() bfin_read16(MDMA_D1_X_MODIFY)
+#define bfin_write_MDMA_D1_X_MODIFY(val) bfin_write16(MDMA_D1_X_MODIFY,val)
+#define bfin_read_MDMA_D1_Y_MODIFY() bfin_read16(MDMA_D1_Y_MODIFY)
+#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write16(MDMA_D1_Y_MODIFY,val)
+#define bfin_read_MDMA_D1_CURR_DESC_PTR() bfin_read32(MDMA_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA_D1_CURR_DESC_PTR(val) bfin_write32(MDMA_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D1_CURR_ADDR() bfin_read32(MDMA_D1_CURR_ADDR)
+#define bfin_write_MDMA_D1_CURR_ADDR(val) bfin_write32(MDMA_D1_CURR_ADDR,val)
+#define bfin_read_MDMA_D1_CURR_X_COUNT() bfin_read16(MDMA_D1_CURR_X_COUNT)
+#define bfin_write_MDMA_D1_CURR_X_COUNT(val) bfin_write16(MDMA_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D1_CURR_Y_COUNT() bfin_read16(MDMA_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA_D1_CURR_Y_COUNT(val) bfin_write16(MDMA_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D1_IRQ_STATUS() bfin_read16(MDMA_D1_IRQ_STATUS)
+#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write16(MDMA_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA_D1_PERIPHERAL_MAP() bfin_read16(MDMA_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA_D1_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S1_CONFIG() bfin_read16(MDMA_S1_CONFIG)
+#define bfin_write_MDMA_S1_CONFIG(val) bfin_write16(MDMA_S1_CONFIG,val)
+#define bfin_read_MDMA_S1_NEXT_DESC_PTR() bfin_read32(MDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S1_START_ADDR() bfin_read32(MDMA_S1_START_ADDR)
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write32(MDMA_S1_START_ADDR,val)
+#define bfin_read_MDMA_S1_X_COUNT() bfin_read16(MDMA_S1_X_COUNT)
+#define bfin_write_MDMA_S1_X_COUNT(val) bfin_write16(MDMA_S1_X_COUNT,val)
+#define bfin_read_MDMA_S1_Y_COUNT() bfin_read16(MDMA_S1_Y_COUNT)
+#define bfin_write_MDMA_S1_Y_COUNT(val) bfin_write16(MDMA_S1_Y_COUNT,val)
+#define bfin_read_MDMA_S1_X_MODIFY() bfin_read16(MDMA_S1_X_MODIFY)
+#define bfin_write_MDMA_S1_X_MODIFY(val) bfin_write16(MDMA_S1_X_MODIFY,val)
+#define bfin_read_MDMA_S1_Y_MODIFY() bfin_read16(MDMA_S1_Y_MODIFY)
+#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write16(MDMA_S1_Y_MODIFY,val)
+#define bfin_read_MDMA_S1_CURR_DESC_PTR() bfin_read32(MDMA_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA_S1_CURR_DESC_PTR(val) bfin_write32(MDMA_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S1_CURR_ADDR() bfin_read32(MDMA_S1_CURR_ADDR)
+#define bfin_write_MDMA_S1_CURR_ADDR(val) bfin_write32(MDMA_S1_CURR_ADDR,val)
+#define bfin_read_MDMA_S1_CURR_X_COUNT() bfin_read16(MDMA_S1_CURR_X_COUNT)
+#define bfin_write_MDMA_S1_CURR_X_COUNT(val) bfin_write16(MDMA_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S1_CURR_Y_COUNT() bfin_read16(MDMA_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA_S1_CURR_Y_COUNT(val) bfin_write16(MDMA_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S1_IRQ_STATUS() bfin_read16(MDMA_S1_IRQ_STATUS)
+#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write16(MDMA_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA_S1_PERIPHERAL_MAP() bfin_read16(MDMA_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA_S1_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D0_CONFIG() bfin_read16(MDMA_D0_CONFIG)
+#define bfin_write_MDMA_D0_CONFIG(val) bfin_write16(MDMA_D0_CONFIG,val)
+#define bfin_read_MDMA_D0_NEXT_DESC_PTR() bfin_read32(MDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D0_START_ADDR() bfin_read32(MDMA_D0_START_ADDR)
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write32(MDMA_D0_START_ADDR,val)
+#define bfin_read_MDMA_D0_X_COUNT() bfin_read16(MDMA_D0_X_COUNT)
+#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write16(MDMA_D0_X_COUNT,val)
+#define bfin_read_MDMA_D0_Y_COUNT() bfin_read16(MDMA_D0_Y_COUNT)
+#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write16(MDMA_D0_Y_COUNT,val)
+#define bfin_read_MDMA_D0_X_MODIFY() bfin_read16(MDMA_D0_X_MODIFY)
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write16(MDMA_D0_X_MODIFY,val)
+#define bfin_read_MDMA_D0_Y_MODIFY() bfin_read16(MDMA_D0_Y_MODIFY)
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write16(MDMA_D0_Y_MODIFY,val)
+#define bfin_read_MDMA_D0_CURR_DESC_PTR() bfin_read32(MDMA_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA_D0_CURR_DESC_PTR(val) bfin_write32(MDMA_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D0_CURR_ADDR() bfin_read32(MDMA_D0_CURR_ADDR)
+#define bfin_write_MDMA_D0_CURR_ADDR(val) bfin_write32(MDMA_D0_CURR_ADDR,val)
+#define bfin_read_MDMA_D0_CURR_X_COUNT() bfin_read16(MDMA_D0_CURR_X_COUNT)
+#define bfin_write_MDMA_D0_CURR_X_COUNT(val) bfin_write16(MDMA_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D0_CURR_Y_COUNT() bfin_read16(MDMA_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA_D0_CURR_Y_COUNT(val) bfin_write16(MDMA_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D0_IRQ_STATUS() bfin_read16(MDMA_D0_IRQ_STATUS)
+#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write16(MDMA_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA_D0_PERIPHERAL_MAP() bfin_read16(MDMA_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA_D0_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S0_CONFIG() bfin_read16(MDMA_S0_CONFIG)
+#define bfin_write_MDMA_S0_CONFIG(val) bfin_write16(MDMA_S0_CONFIG,val)
+#define bfin_read_MDMA_S0_NEXT_DESC_PTR() bfin_read32(MDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S0_START_ADDR() bfin_read32(MDMA_S0_START_ADDR)
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write32(MDMA_S0_START_ADDR,val)
+#define bfin_read_MDMA_S0_X_COUNT() bfin_read16(MDMA_S0_X_COUNT)
+#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write16(MDMA_S0_X_COUNT,val)
+#define bfin_read_MDMA_S0_Y_COUNT() bfin_read16(MDMA_S0_Y_COUNT)
+#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write16(MDMA_S0_Y_COUNT,val)
+#define bfin_read_MDMA_S0_X_MODIFY() bfin_read16(MDMA_S0_X_MODIFY)
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write16(MDMA_S0_X_MODIFY,val)
+#define bfin_read_MDMA_S0_Y_MODIFY() bfin_read16(MDMA_S0_Y_MODIFY)
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write16(MDMA_S0_Y_MODIFY,val)
+#define bfin_read_MDMA_S0_CURR_DESC_PTR() bfin_read32(MDMA_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA_S0_CURR_DESC_PTR(val) bfin_write32(MDMA_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S0_CURR_ADDR() bfin_read32(MDMA_S0_CURR_ADDR)
+#define bfin_write_MDMA_S0_CURR_ADDR(val) bfin_write32(MDMA_S0_CURR_ADDR,val)
+#define bfin_read_MDMA_S0_CURR_X_COUNT() bfin_read16(MDMA_S0_CURR_X_COUNT)
+#define bfin_write_MDMA_S0_CURR_X_COUNT(val) bfin_write16(MDMA_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S0_CURR_Y_COUNT() bfin_read16(MDMA_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA_S0_CURR_Y_COUNT(val) bfin_write16(MDMA_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S0_IRQ_STATUS() bfin_read16(MDMA_S0_IRQ_STATUS)
+#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write16(MDMA_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA_S0_PERIPHERAL_MAP() bfin_read16(MDMA_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA_S0_PERIPHERAL_MAP,val)
+
+/* Aysnchronous Memory Controller - External Bus Interface Unit (0xFFC0 3C00-0xFFC0 3FFF) */
+#define bfin_read_EBIU_AMGCTL() bfin_read16(EBIU_AMGCTL)
+#define bfin_write_EBIU_AMGCTL(val) bfin_write16(EBIU_AMGCTL,val)
+#define bfin_read_EBIU_AMBCTL0() bfin_read32(EBIU_AMBCTL0)
+#define bfin_write_EBIU_AMBCTL0(val) bfin_write32(EBIU_AMBCTL0,val)
+#define bfin_read_EBIU_AMBCTL1() bfin_read32(EBIU_AMBCTL1)
+#define bfin_write_EBIU_AMBCTL1(val) bfin_write32(EBIU_AMBCTL1,val)
+
+/* SDRAM Controller External Bus Interface Unit (0xFFC0 4C00-0xFFC0 4FFF) */
+#define bfin_read_EBIU_SDGCTL() bfin_read32(EBIU_SDGCTL)
+#define bfin_write_EBIU_SDGCTL(val) bfin_write32(EBIU_SDGCTL,val)
+#define bfin_read_EBIU_SDRRC() bfin_read16(EBIU_SDRRC)
+#define bfin_write_EBIU_SDRRC(val) bfin_write16(EBIU_SDRRC,val)
+#define bfin_read_EBIU_SDSTAT() bfin_read16(EBIU_SDSTAT)
+#define bfin_write_EBIU_SDSTAT(val) bfin_write16(EBIU_SDSTAT,val)
+#define bfin_read_EBIU_SDBCTL() bfin_read16(EBIU_SDBCTL)
+#define bfin_write_EBIU_SDBCTL(val) bfin_write16(EBIU_SDBCTL,val)
+
+/* UART Controller */
+#define bfin_read_UART_THR() bfin_read16(UART_THR)
+#define bfin_write_UART_THR(val) bfin_write16(UART_THR,val)
+#define bfin_read_UART_RBR() bfin_read16(UART_RBR)
+#define bfin_write_UART_RBR(val) bfin_write16(UART_RBR,val)
+#define bfin_read_UART_DLL() bfin_read16(UART_DLL)
+#define bfin_write_UART_DLL(val) bfin_write16(UART_DLL,val)
+#define bfin_read_UART_IER() bfin_read16(UART_IER)
+#define bfin_write_UART_IER(val) bfin_write16(UART_IER,val)
+#define bfin_read_UART_DLH() bfin_read16(UART_DLH)
+#define bfin_write_UART_DLH(val) bfin_write16(UART_DLH,val)
+#define bfin_read_UART_IIR() bfin_read16(UART_IIR)
+#define bfin_write_UART_IIR(val) bfin_write16(UART_IIR,val)
+#define bfin_read_UART_LCR() bfin_read16(UART_LCR)
+#define bfin_write_UART_LCR(val) bfin_write16(UART_LCR,val)
+#define bfin_read_UART_MCR() bfin_read16(UART_MCR)
+#define bfin_write_UART_MCR(val) bfin_write16(UART_MCR,val)
+#define bfin_read_UART_LSR() bfin_read16(UART_LSR)
+#define bfin_write_UART_LSR(val) bfin_write16(UART_LSR,val)
+/*
+#define UART_MSR
+*/
+#define bfin_read_UART_SCR() bfin_read16(UART_SCR)
+#define bfin_write_UART_SCR(val) bfin_write16(UART_SCR,val)
+#define bfin_read_UART_GCTL() bfin_read16(UART_GCTL)
+#define bfin_write_UART_GCTL(val) bfin_write16(UART_GCTL,val)
+
+/* SPI Controller */
+#define bfin_read_SPI_CTL() bfin_read16(SPI_CTL)
+#define bfin_write_SPI_CTL(val) bfin_write16(SPI_CTL,val)
+#define bfin_read_SPI_FLG() bfin_read16(SPI_FLG)
+#define bfin_write_SPI_FLG(val) bfin_write16(SPI_FLG,val)
+#define bfin_read_SPI_STAT() bfin_read16(SPI_STAT)
+#define bfin_write_SPI_STAT(val) bfin_write16(SPI_STAT,val)
+#define bfin_read_SPI_TDBR() bfin_read16(SPI_TDBR)
+#define bfin_write_SPI_TDBR(val) bfin_write16(SPI_TDBR,val)
+#define bfin_read_SPI_RDBR() bfin_read16(SPI_RDBR)
+#define bfin_write_SPI_RDBR(val) bfin_write16(SPI_RDBR,val)
+#define bfin_read_SPI_BAUD() bfin_read16(SPI_BAUD)
+#define bfin_write_SPI_BAUD(val) bfin_write16(SPI_BAUD,val)
+#define bfin_read_SPI_SHADOW() bfin_read16(SPI_SHADOW)
+#define bfin_write_SPI_SHADOW(val) bfin_write16(SPI_SHADOW,val)
+
+/* TIMER 0, 1, 2 Registers */
+#define bfin_read_TIMER0_CONFIG() bfin_read16(TIMER0_CONFIG)
+#define bfin_write_TIMER0_CONFIG(val) bfin_write16(TIMER0_CONFIG,val)
+#define bfin_read_TIMER0_COUNTER() bfin_read32(TIMER0_COUNTER)
+#define bfin_write_TIMER0_COUNTER(val) bfin_write32(TIMER0_COUNTER,val)
+#define bfin_read_TIMER0_PERIOD() bfin_read32(TIMER0_PERIOD)
+#define bfin_write_TIMER0_PERIOD(val) bfin_write32(TIMER0_PERIOD,val)
+#define bfin_read_TIMER0_WIDTH() bfin_read32(TIMER0_WIDTH)
+#define bfin_write_TIMER0_WIDTH(val) bfin_write32(TIMER0_WIDTH,val)
+
+#define bfin_read_TIMER1_CONFIG() bfin_read16(TIMER1_CONFIG)
+#define bfin_write_TIMER1_CONFIG(val) bfin_write16(TIMER1_CONFIG,val)
+#define bfin_read_TIMER1_COUNTER() bfin_read32(TIMER1_COUNTER)
+#define bfin_write_TIMER1_COUNTER(val) bfin_write32(TIMER1_COUNTER,val)
+#define bfin_read_TIMER1_PERIOD() bfin_read32(TIMER1_PERIOD)
+#define bfin_write_TIMER1_PERIOD(val) bfin_write32(TIMER1_PERIOD,val)
+#define bfin_read_TIMER1_WIDTH() bfin_read32(TIMER1_WIDTH)
+#define bfin_write_TIMER1_WIDTH(val) bfin_write32(TIMER1_WIDTH,val)
+
+#define bfin_read_TIMER2_CONFIG() bfin_read16(TIMER2_CONFIG)
+#define bfin_write_TIMER2_CONFIG(val) bfin_write16(TIMER2_CONFIG,val)
+#define bfin_read_TIMER2_COUNTER() bfin_read32(TIMER2_COUNTER)
+#define bfin_write_TIMER2_COUNTER(val) bfin_write32(TIMER2_COUNTER,val)
+#define bfin_read_TIMER2_PERIOD() bfin_read32(TIMER2_PERIOD)
+#define bfin_write_TIMER2_PERIOD(val) bfin_write32(TIMER2_PERIOD,val)
+#define bfin_read_TIMER2_WIDTH() bfin_read32(TIMER2_WIDTH)
+#define bfin_write_TIMER2_WIDTH(val) bfin_write32(TIMER2_WIDTH,val)
+
+#define bfin_read_TIMER_ENABLE() bfin_read16(TIMER_ENABLE)
+#define bfin_write_TIMER_ENABLE(val) bfin_write16(TIMER_ENABLE,val)
+#define bfin_read_TIMER_DISABLE() bfin_read16(TIMER_DISABLE)
+#define bfin_write_TIMER_DISABLE(val) bfin_write16(TIMER_DISABLE,val)
+#define bfin_read_TIMER_STATUS() bfin_read16(TIMER_STATUS)
+#define bfin_write_TIMER_STATUS(val) bfin_write16(TIMER_STATUS,val)
+
+/* SPORT0 Controller */
+#define bfin_read_SPORT0_TCR1() bfin_read16(SPORT0_TCR1)
+#define bfin_write_SPORT0_TCR1(val) bfin_write16(SPORT0_TCR1,val)
+#define bfin_read_SPORT0_TCR2() bfin_read16(SPORT0_TCR2)
+#define bfin_write_SPORT0_TCR2(val) bfin_write16(SPORT0_TCR2,val)
+#define bfin_read_SPORT0_TCLKDIV() bfin_read16(SPORT0_TCLKDIV)
+#define bfin_write_SPORT0_TCLKDIV(val) bfin_write16(SPORT0_TCLKDIV,val)
+#define bfin_read_SPORT0_TFSDIV() bfin_read16(SPORT0_TFSDIV)
+#define bfin_write_SPORT0_TFSDIV(val) bfin_write16(SPORT0_TFSDIV,val)
+#define bfin_read_SPORT0_TX() bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX(val) bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX() bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX(val) bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX32() bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val) bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX32() bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val) bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX16() bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val) bfin_write16(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX16() bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val) bfin_write16(SPORT0_RX,val)
+#define bfin_read_SPORT0_RCR1() bfin_read16(SPORT0_RCR1)
+#define bfin_write_SPORT0_RCR1(val) bfin_write16(SPORT0_RCR1,val)
+#define bfin_read_SPORT0_RCR2() bfin_read16(SPORT0_RCR2)
+#define bfin_write_SPORT0_RCR2(val) bfin_write16(SPORT0_RCR2,val)
+#define bfin_read_SPORT0_RCLKDIV() bfin_read16(SPORT0_RCLKDIV)
+#define bfin_write_SPORT0_RCLKDIV(val) bfin_write16(SPORT0_RCLKDIV,val)
+#define bfin_read_SPORT0_RFSDIV() bfin_read16(SPORT0_RFSDIV)
+#define bfin_write_SPORT0_RFSDIV(val) bfin_write16(SPORT0_RFSDIV,val)
+#define bfin_read_SPORT0_STAT() bfin_read16(SPORT0_STAT)
+#define bfin_write_SPORT0_STAT(val) bfin_write16(SPORT0_STAT,val)
+#define bfin_read_SPORT0_CHNL() bfin_read16(SPORT0_CHNL)
+#define bfin_write_SPORT0_CHNL(val) bfin_write16(SPORT0_CHNL,val)
+#define bfin_read_SPORT0_MCMC1() bfin_read16(SPORT0_MCMC1)
+#define bfin_write_SPORT0_MCMC1(val) bfin_write16(SPORT0_MCMC1,val)
+#define bfin_read_SPORT0_MCMC2() bfin_read16(SPORT0_MCMC2)
+#define bfin_write_SPORT0_MCMC2(val) bfin_write16(SPORT0_MCMC2,val)
+#define bfin_read_SPORT0_MTCS0() bfin_read32(SPORT0_MTCS0)
+#define bfin_write_SPORT0_MTCS0(val) bfin_write32(SPORT0_MTCS0,val)
+#define bfin_read_SPORT0_MTCS1() bfin_read32(SPORT0_MTCS1)
+#define bfin_write_SPORT0_MTCS1(val) bfin_write32(SPORT0_MTCS1,val)
+#define bfin_read_SPORT0_MTCS2() bfin_read32(SPORT0_MTCS2)
+#define bfin_write_SPORT0_MTCS2(val) bfin_write32(SPORT0_MTCS2,val)
+#define bfin_read_SPORT0_MTCS3() bfin_read32(SPORT0_MTCS3)
+#define bfin_write_SPORT0_MTCS3(val) bfin_write32(SPORT0_MTCS3,val)
+#define bfin_read_SPORT0_MRCS0() bfin_read32(SPORT0_MRCS0)
+#define bfin_write_SPORT0_MRCS0(val) bfin_write32(SPORT0_MRCS0,val)
+#define bfin_read_SPORT0_MRCS1() bfin_read32(SPORT0_MRCS1)
+#define bfin_write_SPORT0_MRCS1(val) bfin_write32(SPORT0_MRCS1,val)
+#define bfin_read_SPORT0_MRCS2() bfin_read32(SPORT0_MRCS2)
+#define bfin_write_SPORT0_MRCS2(val) bfin_write32(SPORT0_MRCS2,val)
+#define bfin_read_SPORT0_MRCS3() bfin_read32(SPORT0_MRCS3)
+#define bfin_write_SPORT0_MRCS3(val) bfin_write32(SPORT0_MRCS3,val)
+
+/* SPORT1 Controller */
+#define bfin_read_SPORT1_TCR1() bfin_read16(SPORT1_TCR1)
+#define bfin_write_SPORT1_TCR1(val) bfin_write16(SPORT1_TCR1,val)
+#define bfin_read_SPORT1_TCR2() bfin_read16(SPORT1_TCR2)
+#define bfin_write_SPORT1_TCR2(val) bfin_write16(SPORT1_TCR2,val)
+#define bfin_read_SPORT1_TCLKDIV() bfin_read16(SPORT1_TCLKDIV)
+#define bfin_write_SPORT1_TCLKDIV(val) bfin_write16(SPORT1_TCLKDIV,val)
+#define bfin_read_SPORT1_TFSDIV() bfin_read16(SPORT1_TFSDIV)
+#define bfin_write_SPORT1_TFSDIV(val) bfin_write16(SPORT1_TFSDIV,val)
+#define bfin_read_SPORT1_TX() bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX(val) bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX() bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX(val) bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX32() bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val) bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX32() bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val) bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX16() bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val) bfin_write16(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX16() bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val) bfin_write16(SPORT1_RX,val)
+#define bfin_read_SPORT1_RCR1() bfin_read16(SPORT1_RCR1)
+#define bfin_write_SPORT1_RCR1(val) bfin_write16(SPORT1_RCR1,val)
+#define bfin_read_SPORT1_RCR2() bfin_read16(SPORT1_RCR2)
+#define bfin_write_SPORT1_RCR2(val) bfin_write16(SPORT1_RCR2,val)
+#define bfin_read_SPORT1_RCLKDIV() bfin_read16(SPORT1_RCLKDIV)
+#define bfin_write_SPORT1_RCLKDIV(val) bfin_write16(SPORT1_RCLKDIV,val)
+#define bfin_read_SPORT1_RFSDIV() bfin_read16(SPORT1_RFSDIV)
+#define bfin_write_SPORT1_RFSDIV(val) bfin_write16(SPORT1_RFSDIV,val)
+#define bfin_read_SPORT1_STAT() bfin_read16(SPORT1_STAT)
+#define bfin_write_SPORT1_STAT(val) bfin_write16(SPORT1_STAT,val)
+#define bfin_read_SPORT1_CHNL() bfin_read16(SPORT1_CHNL)
+#define bfin_write_SPORT1_CHNL(val) bfin_write16(SPORT1_CHNL,val)
+#define bfin_read_SPORT1_MCMC1() bfin_read16(SPORT1_MCMC1)
+#define bfin_write_SPORT1_MCMC1(val) bfin_write16(SPORT1_MCMC1,val)
+#define bfin_read_SPORT1_MCMC2() bfin_read16(SPORT1_MCMC2)
+#define bfin_write_SPORT1_MCMC2(val) bfin_write16(SPORT1_MCMC2,val)
+#define bfin_read_SPORT1_MTCS0() bfin_read32(SPORT1_MTCS0)
+#define bfin_write_SPORT1_MTCS0(val) bfin_write32(SPORT1_MTCS0,val)
+#define bfin_read_SPORT1_MTCS1() bfin_read32(SPORT1_MTCS1)
+#define bfin_write_SPORT1_MTCS1(val) bfin_write32(SPORT1_MTCS1,val)
+#define bfin_read_SPORT1_MTCS2() bfin_read32(SPORT1_MTCS2)
+#define bfin_write_SPORT1_MTCS2(val) bfin_write32(SPORT1_MTCS2,val)
+#define bfin_read_SPORT1_MTCS3() bfin_read32(SPORT1_MTCS3)
+#define bfin_write_SPORT1_MTCS3(val) bfin_write32(SPORT1_MTCS3,val)
+#define bfin_read_SPORT1_MRCS0() bfin_read32(SPORT1_MRCS0)
+#define bfin_write_SPORT1_MRCS0(val) bfin_write32(SPORT1_MRCS0,val)
+#define bfin_read_SPORT1_MRCS1() bfin_read32(SPORT1_MRCS1)
+#define bfin_write_SPORT1_MRCS1(val) bfin_write32(SPORT1_MRCS1,val)
+#define bfin_read_SPORT1_MRCS2() bfin_read32(SPORT1_MRCS2)
+#define bfin_write_SPORT1_MRCS2(val) bfin_write32(SPORT1_MRCS2,val)
+#define bfin_read_SPORT1_MRCS3() bfin_read32(SPORT1_MRCS3)
+#define bfin_write_SPORT1_MRCS3(val) bfin_write32(SPORT1_MRCS3,val)
+
+/* Parallel Peripheral Interface (PPI) */
+#define bfin_read_PPI_CONTROL() bfin_read16(PPI_CONTROL)
+#define bfin_write_PPI_CONTROL(val) bfin_write16(PPI_CONTROL,val)
+#define bfin_read_PPI_STATUS() bfin_read16(PPI_STATUS)
+#define bfin_write_PPI_STATUS(val) bfin_write16(PPI_STATUS,val)
+#define bfin_clear_PPI_STATUS() bfin_read_PPI_STATUS()
+#define bfin_read_PPI_DELAY() bfin_read16(PPI_DELAY)
+#define bfin_write_PPI_DELAY(val) bfin_write16(PPI_DELAY,val)
+#define bfin_read_PPI_COUNT() bfin_read16(PPI_COUNT)
+#define bfin_write_PPI_COUNT(val) bfin_write16(PPI_COUNT,val)
+#define bfin_read_PPI_FRAME() bfin_read16(PPI_FRAME)
+#define bfin_write_PPI_FRAME(val) bfin_write16(PPI_FRAME,val)
+
+#endif /* _CDEF_BF532_H */
diff --git a/include/asm-blackfin/mach-bf533/defBF532.h b/include/asm-blackfin/mach-bf533/defBF532.h
new file mode 100644
index 00000000000..b240a082aa0
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/defBF532.h
@@ -0,0 +1,1175 @@
+/************************************************************************
+ *
+ * This file is subject to the terms and conditions of the GNU Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Non-GPL License also available as part of VisualDSP++
+ * http://www.analog.com/processors/resources/crosscore/visualDspDevSoftware.html
+ *
+ * (c) Copyright 2001-2005 Analog Devices, Inc. All rights reserved
+ *
+ * This file under source code control, please send bugs or changes to:
+ * dsptools.support@analog.com
+ *
+ ************************************************************************/
+/*
+ * File: include/asm-blackfin/mach-bf533/defBF532.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/* SYSTEM & MM REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF532 */
+
+#ifndef _DEF_BF532_H
+#define _DEF_BF532_H
+/*
+#if !defined(__ADSPLPBLACKFIN__)
+#warning defBF532.h should only be included for 532 compatible chips
+#endif
+*/
+/* include all Core registers and bit definitions */
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/*********************************************************************************** */
+/* System MMR Register Map */
+/*********************************************************************************** */
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+
+#define PLL_CTL 0xFFC00000 /* PLL Control register (16-bit) */
+#define PLL_DIV 0xFFC00004 /* PLL Divide Register (16-bit) */
+#define VR_CTL 0xFFC00008 /* Voltage Regulator Control Register (16-bit) */
+#define PLL_STAT 0xFFC0000C /* PLL Status register (16-bit) */
+#define PLL_LOCKCNT 0xFFC00010 /* PLL Lock Count register (16-bit) */
+#define CHIPID 0xFFC00014 /* Chip ID Register */
+#define SWRST 0xFFC00100 /* Software Reset Register (16-bit) */
+#define SYSCR 0xFFC00104 /* System Configuration registe */
+
+/* System Interrupt Controller (0xFFC00100 - 0xFFC001FF) */
+#define SIC_RVECT 0xFFC00108 /* Interrupt Reset Vector Address Register */
+#define SIC_IMASK 0xFFC0010C /* Interrupt Mask Register */
+#define SIC_IAR0 0xFFC00110 /* Interrupt Assignment Register 0 */
+#define SIC_IAR1 0xFFC00114 /* Interrupt Assignment Register 1 */
+#define SIC_IAR2 0xFFC00118 /* Interrupt Assignment Register 2 */
+#define SIC_ISR 0xFFC00120 /* Interrupt Status Register */
+#define SIC_IWR 0xFFC00124 /* Interrupt Wakeup Register */
+
+/* Watchdog Timer (0xFFC00200 - 0xFFC002FF) */
+#define WDOG_CTL 0xFFC00200 /* Watchdog Control Register */
+#define WDOG_CNT 0xFFC00204 /* Watchdog Count Register */
+#define WDOG_STAT 0xFFC00208 /* Watchdog Status Register */
+
+/* Real Time Clock (0xFFC00300 - 0xFFC003FF) */
+#define RTC_STAT 0xFFC00300 /* RTC Status Register */
+#define RTC_ICTL 0xFFC00304 /* RTC Interrupt Control Register */
+#define RTC_ISTAT 0xFFC00308 /* RTC Interrupt Status Register */
+#define RTC_SWCNT 0xFFC0030C /* RTC Stopwatch Count Register */
+#define RTC_ALARM 0xFFC00310 /* RTC Alarm Time Register */
+#define RTC_FAST 0xFFC00314 /* RTC Prescaler Enable Register */
+#define RTC_PREN 0xFFC00314 /* RTC Prescaler Enable Register (alternate macro) */
+
+/* UART Controller (0xFFC00400 - 0xFFC004FF) */
+#define UART_THR 0xFFC00400 /* Transmit Holding register */
+#define UART_RBR 0xFFC00400 /* Receive Buffer register */
+#define UART_DLL 0xFFC00400 /* Divisor Latch (Low-Byte) */
+#define UART_IER 0xFFC00404 /* Interrupt Enable Register */
+#define UART_DLH 0xFFC00404 /* Divisor Latch (High-Byte) */
+#define UART_IIR 0xFFC00408 /* Interrupt Identification Register */
+#define UART_LCR 0xFFC0040C /* Line Control Register */
+#define UART_MCR 0xFFC00410 /* Modem Control Register */
+#define UART_LSR 0xFFC00414 /* Line Status Register */
+#if 0
+#define UART_MSR 0xFFC00418 /* Modem Status Register (UNUSED in ADSP-BF532) */
+#endif
+#define UART_SCR 0xFFC0041C /* SCR Scratch Register */
+#define UART_GCTL 0xFFC00424 /* Global Control Register */
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define SPI_CTL 0xFFC00500 /* SPI Control Register */
+#define SPI_FLG 0xFFC00504 /* SPI Flag register */
+#define SPI_STAT 0xFFC00508 /* SPI Status register */
+#define SPI_TDBR 0xFFC0050C /* SPI Transmit Data Buffer Register */
+#define SPI_RDBR 0xFFC00510 /* SPI Receive Data Buffer Register */
+#define SPI_BAUD 0xFFC00514 /* SPI Baud rate Register */
+#define SPI_SHADOW 0xFFC00518 /* SPI_RDBR Shadow Register */
+
+/* TIMER 0, 1, 2 Registers (0xFFC00600 - 0xFFC006FF) */
+
+#define TIMER0_CONFIG 0xFFC00600 /* Timer 0 Configuration Register */
+#define TIMER0_COUNTER 0xFFC00604 /* Timer 0 Counter Register */
+#define TIMER0_PERIOD 0xFFC00608 /* Timer 0 Period Register */
+#define TIMER0_WIDTH 0xFFC0060C /* Timer 0 Width Register */
+
+#define TIMER1_CONFIG 0xFFC00610 /* Timer 1 Configuration Register */
+#define TIMER1_COUNTER 0xFFC00614 /* Timer 1 Counter Register */
+#define TIMER1_PERIOD 0xFFC00618 /* Timer 1 Period Register */
+#define TIMER1_WIDTH 0xFFC0061C /* Timer 1 Width Register */
+
+#define TIMER2_CONFIG 0xFFC00620 /* Timer 2 Configuration Register */
+#define TIMER2_COUNTER 0xFFC00624 /* Timer 2 Counter Register */
+#define TIMER2_PERIOD 0xFFC00628 /* Timer 2 Period Register */
+#define TIMER2_WIDTH 0xFFC0062C /* Timer 2 Width Register */
+
+#define TIMER_ENABLE 0xFFC00640 /* Timer Enable Register */
+#define TIMER_DISABLE 0xFFC00644 /* Timer Disable Register */
+#define TIMER_STATUS 0xFFC00648 /* Timer Status Register */
+
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) */
+
+#define FIO_FLAG_D 0xFFC00700 /* Flag Mask to directly specify state of pins */
+#define FIO_FLAG_C 0xFFC00704 /* Peripheral Interrupt Flag Register (clear) */
+#define FIO_FLAG_S 0xFFC00708 /* Peripheral Interrupt Flag Register (set) */
+#define FIO_FLAG_T 0xFFC0070C /* Flag Mask to directly toggle state of pins */
+#define FIO_MASKA_D 0xFFC00710 /* Flag Mask Interrupt A Register (set directly) */
+#define FIO_MASKA_C 0xFFC00714 /* Flag Mask Interrupt A Register (clear) */
+#define FIO_MASKA_S 0xFFC00718 /* Flag Mask Interrupt A Register (set) */
+#define FIO_MASKA_T 0xFFC0071C /* Flag Mask Interrupt A Register (toggle) */
+#define FIO_MASKB_D 0xFFC00720 /* Flag Mask Interrupt B Register (set directly) */
+#define FIO_MASKB_C 0xFFC00724 /* Flag Mask Interrupt B Register (clear) */
+#define FIO_MASKB_S 0xFFC00728 /* Flag Mask Interrupt B Register (set) */
+#define FIO_MASKB_T 0xFFC0072C /* Flag Mask Interrupt B Register (toggle) */
+#define FIO_DIR 0xFFC00730 /* Peripheral Flag Direction Register */
+#define FIO_POLAR 0xFFC00734 /* Flag Source Polarity Register */
+#define FIO_EDGE 0xFFC00738 /* Flag Source Sensitivity Register */
+#define FIO_BOTH 0xFFC0073C /* Flag Set on BOTH Edges Register */
+#define FIO_INEN 0xFFC00740 /* Flag Input Enable Register */
+
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define SPORT0_TCR1 0xFFC00800 /* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_TCR2 0xFFC00804 /* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_TCLKDIV 0xFFC00808 /* SPORT0 Transmit Clock Divider */
+#define SPORT0_TFSDIV 0xFFC0080C /* SPORT0 Transmit Frame Sync Divider */
+#define SPORT0_TX 0xFFC00810 /* SPORT0 TX Data Register */
+#define SPORT0_RX 0xFFC00818 /* SPORT0 RX Data Register */
+#define SPORT0_RCR1 0xFFC00820 /* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_RCR2 0xFFC00824 /* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_RCLKDIV 0xFFC00828 /* SPORT0 Receive Clock Divider */
+#define SPORT0_RFSDIV 0xFFC0082C /* SPORT0 Receive Frame Sync Divider */
+#define SPORT0_STAT 0xFFC00830 /* SPORT0 Status Register */
+#define SPORT0_CHNL 0xFFC00834 /* SPORT0 Current Channel Register */
+#define SPORT0_MCMC1 0xFFC00838 /* SPORT0 Multi-Channel Configuration Register 1 */
+#define SPORT0_MCMC2 0xFFC0083C /* SPORT0 Multi-Channel Configuration Register 2 */
+#define SPORT0_MTCS0 0xFFC00840 /* SPORT0 Multi-Channel Transmit Select Register 0 */
+#define SPORT0_MTCS1 0xFFC00844 /* SPORT0 Multi-Channel Transmit Select Register 1 */
+#define SPORT0_MTCS2 0xFFC00848 /* SPORT0 Multi-Channel Transmit Select Register 2 */
+#define SPORT0_MTCS3 0xFFC0084C /* SPORT0 Multi-Channel Transmit Select Register 3 */
+#define SPORT0_MRCS0 0xFFC00850 /* SPORT0 Multi-Channel Receive Select Register 0 */
+#define SPORT0_MRCS1 0xFFC00854 /* SPORT0 Multi-Channel Receive Select Register 1 */
+#define SPORT0_MRCS2 0xFFC00858 /* SPORT0 Multi-Channel Receive Select Register 2 */
+#define SPORT0_MRCS3 0xFFC0085C /* SPORT0 Multi-Channel Receive Select Register 3 */
+
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define SPORT1_TCR1 0xFFC00900 /* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_TCR2 0xFFC00904 /* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_TCLKDIV 0xFFC00908 /* SPORT1 Transmit Clock Divider */
+#define SPORT1_TFSDIV 0xFFC0090C /* SPORT1 Transmit Frame Sync Divider */
+#define SPORT1_TX 0xFFC00910 /* SPORT1 TX Data Register */
+#define SPORT1_RX 0xFFC00918 /* SPORT1 RX Data Register */
+#define SPORT1_RCR1 0xFFC00920 /* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_RCR2 0xFFC00924 /* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_RCLKDIV 0xFFC00928 /* SPORT1 Receive Clock Divider */
+#define SPORT1_RFSDIV 0xFFC0092C /* SPORT1 Receive Frame Sync Divider */
+#define SPORT1_STAT 0xFFC00930 /* SPORT1 Status Register */
+#define SPORT1_CHNL 0xFFC00934 /* SPORT1 Current Channel Register */
+#define SPORT1_MCMC1 0xFFC00938 /* SPORT1 Multi-Channel Configuration Register 1 */
+#define SPORT1_MCMC2 0xFFC0093C /* SPORT1 Multi-Channel Configuration Register 2 */
+#define SPORT1_MTCS0 0xFFC00940 /* SPORT1 Multi-Channel Transmit Select Register 0 */
+#define SPORT1_MTCS1 0xFFC00944 /* SPORT1 Multi-Channel Transmit Select Register 1 */
+#define SPORT1_MTCS2 0xFFC00948 /* SPORT1 Multi-Channel Transmit Select Register 2 */
+#define SPORT1_MTCS3 0xFFC0094C /* SPORT1 Multi-Channel Transmit Select Register 3 */
+#define SPORT1_MRCS0 0xFFC00950 /* SPORT1 Multi-Channel Receive Select Register 0 */
+#define SPORT1_MRCS1 0xFFC00954 /* SPORT1 Multi-Channel Receive Select Register 1 */
+#define SPORT1_MRCS2 0xFFC00958 /* SPORT1 Multi-Channel Receive Select Register 2 */
+#define SPORT1_MRCS3 0xFFC0095C /* SPORT1 Multi-Channel Receive Select Register 3 */
+
+/* Asynchronous Memory Controller - External Bus Interface Unit */
+#define EBIU_AMGCTL 0xFFC00A00 /* Asynchronous Memory Global Control Register */
+#define EBIU_AMBCTL0 0xFFC00A04 /* Asynchronous Memory Bank Control Register 0 */
+#define EBIU_AMBCTL1 0xFFC00A08 /* Asynchronous Memory Bank Control Register 1 */
+
+/* SDRAM Controller External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+
+#define EBIU_SDGCTL 0xFFC00A10 /* SDRAM Global Control Register */
+#define EBIU_SDBCTL 0xFFC00A14 /* SDRAM Bank Control Register */
+#define EBIU_SDRRC 0xFFC00A18 /* SDRAM Refresh Rate Control Register */
+#define EBIU_SDSTAT 0xFFC00A1C /* SDRAM Status Register */
+
+/* DMA Traffic controls */
+#define DMA_TCPER 0xFFC00B0C /* Traffic Control Periods Register */
+#define DMA_TCCNT 0xFFC00B10 /* Traffic Control Current Counts Register */
+#define DMA_TC_PER 0xFFC00B0C /* Traffic Control Periods Register */
+#define DMA_TC_CNT 0xFFC00B10 /* Traffic Control Current Counts Register */
+
+/* DMA Controller (0xFFC00C00 - 0xFFC00FFF) */
+#define DMA0_CONFIG 0xFFC00C08 /* DMA Channel 0 Configuration Register */
+#define DMA0_NEXT_DESC_PTR 0xFFC00C00 /* DMA Channel 0 Next Descriptor Pointer Register */
+#define DMA0_START_ADDR 0xFFC00C04 /* DMA Channel 0 Start Address Register */
+#define DMA0_X_COUNT 0xFFC00C10 /* DMA Channel 0 X Count Register */
+#define DMA0_Y_COUNT 0xFFC00C18 /* DMA Channel 0 Y Count Register */
+#define DMA0_X_MODIFY 0xFFC00C14 /* DMA Channel 0 X Modify Register */
+#define DMA0_Y_MODIFY 0xFFC00C1C /* DMA Channel 0 Y Modify Register */
+#define DMA0_CURR_DESC_PTR 0xFFC00C20 /* DMA Channel 0 Current Descriptor Pointer Register */
+#define DMA0_CURR_ADDR 0xFFC00C24 /* DMA Channel 0 Current Address Register */
+#define DMA0_CURR_X_COUNT 0xFFC00C30 /* DMA Channel 0 Current X Count Register */
+#define DMA0_CURR_Y_COUNT 0xFFC00C38 /* DMA Channel 0 Current Y Count Register */
+#define DMA0_IRQ_STATUS 0xFFC00C28 /* DMA Channel 0 Interrupt/Status Register */
+#define DMA0_PERIPHERAL_MAP 0xFFC00C2C /* DMA Channel 0 Peripheral Map Register */
+
+#define DMA1_CONFIG 0xFFC00C48 /* DMA Channel 1 Configuration Register */
+#define DMA1_NEXT_DESC_PTR 0xFFC00C40 /* DMA Channel 1 Next Descriptor Pointer Register */
+#define DMA1_START_ADDR 0xFFC00C44 /* DMA Channel 1 Start Address Register */
+#define DMA1_X_COUNT 0xFFC00C50 /* DMA Channel 1 X Count Register */
+#define DMA1_Y_COUNT 0xFFC00C58 /* DMA Channel 1 Y Count Register */
+#define DMA1_X_MODIFY 0xFFC00C54 /* DMA Channel 1 X Modify Register */
+#define DMA1_Y_MODIFY 0xFFC00C5C /* DMA Channel 1 Y Modify Register */
+#define DMA1_CURR_DESC_PTR 0xFFC00C60 /* DMA Channel 1 Current Descriptor Pointer Register */
+#define DMA1_CURR_ADDR 0xFFC00C64 /* DMA Channel 1 Current Address Register */
+#define DMA1_CURR_X_COUNT 0xFFC00C70 /* DMA Channel 1 Current X Count Register */
+#define DMA1_CURR_Y_COUNT 0xFFC00C78 /* DMA Channel 1 Current Y Count Register */
+#define DMA1_IRQ_STATUS 0xFFC00C68 /* DMA Channel 1 Interrupt/Status Register */
+#define DMA1_PERIPHERAL_MAP 0xFFC00C6C /* DMA Channel 1 Peripheral Map Register */
+
+#define DMA2_CONFIG 0xFFC00C88 /* DMA Channel 2 Configuration Register */
+#define DMA2_NEXT_DESC_PTR 0xFFC00C80 /* DMA Channel 2 Next Descriptor Pointer Register */
+#define DMA2_START_ADDR 0xFFC00C84 /* DMA Channel 2 Start Address Register */
+#define DMA2_X_COUNT 0xFFC00C90 /* DMA Channel 2 X Count Register */
+#define DMA2_Y_COUNT 0xFFC00C98 /* DMA Channel 2 Y Count Register */
+#define DMA2_X_MODIFY 0xFFC00C94 /* DMA Channel 2 X Modify Register */
+#define DMA2_Y_MODIFY 0xFFC00C9C /* DMA Channel 2 Y Modify Register */
+#define DMA2_CURR_DESC_PTR 0xFFC00CA0 /* DMA Channel 2 Current Descriptor Pointer Register */
+#define DMA2_CURR_ADDR 0xFFC00CA4 /* DMA Channel 2 Current Address Register */
+#define DMA2_CURR_X_COUNT 0xFFC00CB0 /* DMA Channel 2 Current X Count Register */
+#define DMA2_CURR_Y_COUNT 0xFFC00CB8 /* DMA Channel 2 Current Y Count Register */
+#define DMA2_IRQ_STATUS 0xFFC00CA8 /* DMA Channel 2 Interrupt/Status Register */
+#define DMA2_PERIPHERAL_MAP 0xFFC00CAC /* DMA Channel 2 Peripheral Map Register */
+
+#define DMA3_CONFIG 0xFFC00CC8 /* DMA Channel 3 Configuration Register */
+#define DMA3_NEXT_DESC_PTR 0xFFC00CC0 /* DMA Channel 3 Next Descriptor Pointer Register */
+#define DMA3_START_ADDR 0xFFC00CC4 /* DMA Channel 3 Start Address Register */
+#define DMA3_X_COUNT 0xFFC00CD0 /* DMA Channel 3 X Count Register */
+#define DMA3_Y_COUNT 0xFFC00CD8 /* DMA Channel 3 Y Count Register */
+#define DMA3_X_MODIFY 0xFFC00CD4 /* DMA Channel 3 X Modify Register */
+#define DMA3_Y_MODIFY 0xFFC00CDC /* DMA Channel 3 Y Modify Register */
+#define DMA3_CURR_DESC_PTR 0xFFC00CE0 /* DMA Channel 3 Current Descriptor Pointer Register */
+#define DMA3_CURR_ADDR 0xFFC00CE4 /* DMA Channel 3 Current Address Register */
+#define DMA3_CURR_X_COUNT 0xFFC00CF0 /* DMA Channel 3 Current X Count Register */
+#define DMA3_CURR_Y_COUNT 0xFFC00CF8 /* DMA Channel 3 Current Y Count Register */
+#define DMA3_IRQ_STATUS 0xFFC00CE8 /* DMA Channel 3 Interrupt/Status Register */
+#define DMA3_PERIPHERAL_MAP 0xFFC00CEC /* DMA Channel 3 Peripheral Map Register */
+
+#define DMA4_CONFIG 0xFFC00D08 /* DMA Channel 4 Configuration Register */
+#define DMA4_NEXT_DESC_PTR 0xFFC00D00 /* DMA Channel 4 Next Descriptor Pointer Register */
+#define DMA4_START_ADDR 0xFFC00D04 /* DMA Channel 4 Start Address Register */
+#define DMA4_X_COUNT 0xFFC00D10 /* DMA Channel 4 X Count Register */
+#define DMA4_Y_COUNT 0xFFC00D18 /* DMA Channel 4 Y Count Register */
+#define DMA4_X_MODIFY 0xFFC00D14 /* DMA Channel 4 X Modify Register */
+#define DMA4_Y_MODIFY 0xFFC00D1C /* DMA Channel 4 Y Modify Register */
+#define DMA4_CURR_DESC_PTR 0xFFC00D20 /* DMA Channel 4 Current Descriptor Pointer Register */
+#define DMA4_CURR_ADDR 0xFFC00D24 /* DMA Channel 4 Current Address Register */
+#define DMA4_CURR_X_COUNT 0xFFC00D30 /* DMA Channel 4 Current X Count Register */
+#define DMA4_CURR_Y_COUNT 0xFFC00D38 /* DMA Channel 4 Current Y Count Register */
+#define DMA4_IRQ_STATUS 0xFFC00D28 /* DMA Channel 4 Interrupt/Status Register */
+#define DMA4_PERIPHERAL_MAP 0xFFC00D2C /* DMA Channel 4 Peripheral Map Register */
+
+#define DMA5_CONFIG 0xFFC00D48 /* DMA Channel 5 Configuration Register */
+#define DMA5_NEXT_DESC_PTR 0xFFC00D40 /* DMA Channel 5 Next Descriptor Pointer Register */
+#define DMA5_START_ADDR 0xFFC00D44 /* DMA Channel 5 Start Address Register */
+#define DMA5_X_COUNT 0xFFC00D50 /* DMA Channel 5 X Count Register */
+#define DMA5_Y_COUNT 0xFFC00D58 /* DMA Channel 5 Y Count Register */
+#define DMA5_X_MODIFY 0xFFC00D54 /* DMA Channel 5 X Modify Register */
+#define DMA5_Y_MODIFY 0xFFC00D5C /* DMA Channel 5 Y Modify Register */
+#define DMA5_CURR_DESC_PTR 0xFFC00D60 /* DMA Channel 5 Current Descriptor Pointer Register */
+#define DMA5_CURR_ADDR 0xFFC00D64 /* DMA Channel 5 Current Address Register */
+#define DMA5_CURR_X_COUNT 0xFFC00D70 /* DMA Channel 5 Current X Count Register */
+#define DMA5_CURR_Y_COUNT 0xFFC00D78 /* DMA Channel 5 Current Y Count Register */
+#define DMA5_IRQ_STATUS 0xFFC00D68 /* DMA Channel 5 Interrupt/Status Register */
+#define DMA5_PERIPHERAL_MAP 0xFFC00D6C /* DMA Channel 5 Peripheral Map Register */
+
+#define DMA6_CONFIG 0xFFC00D88 /* DMA Channel 6 Configuration Register */
+#define DMA6_NEXT_DESC_PTR 0xFFC00D80 /* DMA Channel 6 Next Descriptor Pointer Register */
+#define DMA6_START_ADDR 0xFFC00D84 /* DMA Channel 6 Start Address Register */
+#define DMA6_X_COUNT 0xFFC00D90 /* DMA Channel 6 X Count Register */
+#define DMA6_Y_COUNT 0xFFC00D98 /* DMA Channel 6 Y Count Register */
+#define DMA6_X_MODIFY 0xFFC00D94 /* DMA Channel 6 X Modify Register */
+#define DMA6_Y_MODIFY 0xFFC00D9C /* DMA Channel 6 Y Modify Register */
+#define DMA6_CURR_DESC_PTR 0xFFC00DA0 /* DMA Channel 6 Current Descriptor Pointer Register */
+#define DMA6_CURR_ADDR 0xFFC00DA4 /* DMA Channel 6 Current Address Register */
+#define DMA6_CURR_X_COUNT 0xFFC00DB0 /* DMA Channel 6 Current X Count Register */
+#define DMA6_CURR_Y_COUNT 0xFFC00DB8 /* DMA Channel 6 Current Y Count Register */
+#define DMA6_IRQ_STATUS 0xFFC00DA8 /* DMA Channel 6 Interrupt/Status Register */
+#define DMA6_PERIPHERAL_MAP 0xFFC00DAC /* DMA Channel 6 Peripheral Map Register */
+
+#define DMA7_CONFIG 0xFFC00DC8 /* DMA Channel 7 Configuration Register */
+#define DMA7_NEXT_DESC_PTR 0xFFC00DC0 /* DMA Channel 7 Next Descriptor Pointer Register */
+#define DMA7_START_ADDR 0xFFC00DC4 /* DMA Channel 7 Start Address Register */
+#define DMA7_X_COUNT 0xFFC00DD0 /* DMA Channel 7 X Count Register */
+#define DMA7_Y_COUNT 0xFFC00DD8 /* DMA Channel 7 Y Count Register */
+#define DMA7_X_MODIFY 0xFFC00DD4 /* DMA Channel 7 X Modify Register */
+#define DMA7_Y_MODIFY 0xFFC00DDC /* DMA Channel 7 Y Modify Register */
+#define DMA7_CURR_DESC_PTR 0xFFC00DE0 /* DMA Channel 7 Current Descriptor Pointer Register */
+#define DMA7_CURR_ADDR 0xFFC00DE4 /* DMA Channel 7 Current Address Register */
+#define DMA7_CURR_X_COUNT 0xFFC00DF0 /* DMA Channel 7 Current X Count Register */
+#define DMA7_CURR_Y_COUNT 0xFFC00DF8 /* DMA Channel 7 Current Y Count Register */
+#define DMA7_IRQ_STATUS 0xFFC00DE8 /* DMA Channel 7 Interrupt/Status Register */
+#define DMA7_PERIPHERAL_MAP 0xFFC00DEC /* DMA Channel 7 Peripheral Map Register */
+
+#define MDMA_D1_CONFIG 0xFFC00E88 /* MemDMA Stream 1 Destination Configuration Register */
+#define MDMA_D1_NEXT_DESC_PTR 0xFFC00E80 /* MemDMA Stream 1 Destination Next Descriptor Pointer Register */
+#define MDMA_D1_START_ADDR 0xFFC00E84 /* MemDMA Stream 1 Destination Start Address Register */
+#define MDMA_D1_X_COUNT 0xFFC00E90 /* MemDMA Stream 1 Destination X Count Register */
+#define MDMA_D1_Y_COUNT 0xFFC00E98 /* MemDMA Stream 1 Destination Y Count Register */
+#define MDMA_D1_X_MODIFY 0xFFC00E94 /* MemDMA Stream 1 Destination X Modify Register */
+#define MDMA_D1_Y_MODIFY 0xFFC00E9C /* MemDMA Stream 1 Destination Y Modify Register */
+#define MDMA_D1_CURR_DESC_PTR 0xFFC00EA0 /* MemDMA Stream 1 Destination Current Descriptor Pointer Register */
+#define MDMA_D1_CURR_ADDR 0xFFC00EA4 /* MemDMA Stream 1 Destination Current Address Register */
+#define MDMA_D1_CURR_X_COUNT 0xFFC00EB0 /* MemDMA Stream 1 Destination Current X Count Register */
+#define MDMA_D1_CURR_Y_COUNT 0xFFC00EB8 /* MemDMA Stream 1 Destination Current Y Count Register */
+#define MDMA_D1_IRQ_STATUS 0xFFC00EA8 /* MemDMA Stream 1 Destination Interrupt/Status Register */
+#define MDMA_D1_PERIPHERAL_MAP 0xFFC00EAC /* MemDMA Stream 1 Destination Peripheral Map Register */
+
+#define MDMA_S1_CONFIG 0xFFC00EC8 /* MemDMA Stream 1 Source Configuration Register */
+#define MDMA_S1_NEXT_DESC_PTR 0xFFC00EC0 /* MemDMA Stream 1 Source Next Descriptor Pointer Register */
+#define MDMA_S1_START_ADDR 0xFFC00EC4 /* MemDMA Stream 1 Source Start Address Register */
+#define MDMA_S1_X_COUNT 0xFFC00ED0 /* MemDMA Stream 1 Source X Count Register */
+#define MDMA_S1_Y_COUNT 0xFFC00ED8 /* MemDMA Stream 1 Source Y Count Register */
+#define MDMA_S1_X_MODIFY 0xFFC00ED4 /* MemDMA Stream 1 Source X Modify Register */
+#define MDMA_S1_Y_MODIFY 0xFFC00EDC /* MemDMA Stream 1 Source Y Modify Register */
+#define MDMA_S1_CURR_DESC_PTR 0xFFC00EE0 /* MemDMA Stream 1 Source Current Descriptor Pointer Register */
+#define MDMA_S1_CURR_ADDR 0xFFC00EE4 /* MemDMA Stream 1 Source Current Address Register */
+#define MDMA_S1_CURR_X_COUNT 0xFFC00EF0 /* MemDMA Stream 1 Source Current X Count Register */
+#define MDMA_S1_CURR_Y_COUNT 0xFFC00EF8 /* MemDMA Stream 1 Source Current Y Count Register */
+#define MDMA_S1_IRQ_STATUS 0xFFC00EE8 /* MemDMA Stream 1 Source Interrupt/Status Register */
+#define MDMA_S1_PERIPHERAL_MAP 0xFFC00EEC /* MemDMA Stream 1 Source Peripheral Map Register */
+
+#define MDMA_D0_CONFIG 0xFFC00E08 /* MemDMA Stream 0 Destination Configuration Register */
+#define MDMA_D0_NEXT_DESC_PTR 0xFFC00E00 /* MemDMA Stream 0 Destination Next Descriptor Pointer Register */
+#define MDMA_D0_START_ADDR 0xFFC00E04 /* MemDMA Stream 0 Destination Start Address Register */
+#define MDMA_D0_X_COUNT 0xFFC00E10 /* MemDMA Stream 0 Destination X Count Register */
+#define MDMA_D0_Y_COUNT 0xFFC00E18 /* MemDMA Stream 0 Destination Y Count Register */
+#define MDMA_D0_X_MODIFY 0xFFC00E14 /* MemDMA Stream 0 Destination X Modify Register */
+#define MDMA_D0_Y_MODIFY 0xFFC00E1C /* MemDMA Stream 0 Destination Y Modify Register */
+#define MDMA_D0_CURR_DESC_PTR 0xFFC00E20 /* MemDMA Stream 0 Destination Current Descriptor Pointer Register */
+#define MDMA_D0_CURR_ADDR 0xFFC00E24 /* MemDMA Stream 0 Destination Current Address Register */
+#define MDMA_D0_CURR_X_COUNT 0xFFC00E30 /* MemDMA Stream 0 Destination Current X Count Register */
+#define MDMA_D0_CURR_Y_COUNT 0xFFC00E38 /* MemDMA Stream 0 Destination Current Y Count Register */
+#define MDMA_D0_IRQ_STATUS 0xFFC00E28 /* MemDMA Stream 0 Destination Interrupt/Status Register */
+#define MDMA_D0_PERIPHERAL_MAP 0xFFC00E2C /* MemDMA Stream 0 Destination Peripheral Map Register */
+
+#define MDMA_S0_CONFIG 0xFFC00E48 /* MemDMA Stream 0 Source Configuration Register */
+#define MDMA_S0_NEXT_DESC_PTR 0xFFC00E40 /* MemDMA Stream 0 Source Next Descriptor Pointer Register */
+#define MDMA_S0_START_ADDR 0xFFC00E44 /* MemDMA Stream 0 Source Start Address Register */
+#define MDMA_S0_X_COUNT 0xFFC00E50 /* MemDMA Stream 0 Source X Count Register */
+#define MDMA_S0_Y_COUNT 0xFFC00E58 /* MemDMA Stream 0 Source Y Count Register */
+#define MDMA_S0_X_MODIFY 0xFFC00E54 /* MemDMA Stream 0 Source X Modify Register */
+#define MDMA_S0_Y_MODIFY 0xFFC00E5C /* MemDMA Stream 0 Source Y Modify Register */
+#define MDMA_S0_CURR_DESC_PTR 0xFFC00E60 /* MemDMA Stream 0 Source Current Descriptor Pointer Register */
+#define MDMA_S0_CURR_ADDR 0xFFC00E64 /* MemDMA Stream 0 Source Current Address Register */
+#define MDMA_S0_CURR_X_COUNT 0xFFC00E70 /* MemDMA Stream 0 Source Current X Count Register */
+#define MDMA_S0_CURR_Y_COUNT 0xFFC00E78 /* MemDMA Stream 0 Source Current Y Count Register */
+#define MDMA_S0_IRQ_STATUS 0xFFC00E68 /* MemDMA Stream 0 Source Interrupt/Status Register */
+#define MDMA_S0_PERIPHERAL_MAP 0xFFC00E6C /* MemDMA Stream 0 Source Peripheral Map Register */
+
+/* Parallel Peripheral Interface (PPI) (0xFFC01000 - 0xFFC010FF) */
+
+#define PPI_CONTROL 0xFFC01000 /* PPI Control Register */
+#define PPI_STATUS 0xFFC01004 /* PPI Status Register */
+#define PPI_COUNT 0xFFC01008 /* PPI Transfer Count Register */
+#define PPI_DELAY 0xFFC0100C /* PPI Delay Count Register */
+#define PPI_FRAME 0xFFC01010 /* PPI Frame Length Register */
+
+/*********************************************************************************** */
+/* System MMR Register Bits */
+/******************************************************************************* */
+
+/* ********************* PLL AND RESET MASKS ************************ */
+
+/* PLL_CTL Masks */
+#define PLL_CLKIN 0x00000000 /* Pass CLKIN to PLL */
+#define PLL_CLKIN_DIV2 0x00000001 /* Pass CLKIN/2 to PLL */
+#define PLL_OFF 0x00000002 /* Shut off PLL clocks */
+#define STOPCK_OFF 0x00000008 /* Core clock off */
+#define PDWN 0x00000020 /* Put the PLL in a Deep Sleep state */
+#define BYPASS 0x00000100 /* Bypass the PLL */
+
+/* PLL_DIV Masks */
+
+#define SCLK_DIV(x) (x) /* SCLK = VCO / x */
+
+#define CCLK_DIV1 0x00000000 /* CCLK = VCO / 1 */
+#define CCLK_DIV2 0x00000010 /* CCLK = VCO / 2 */
+#define CCLK_DIV4 0x00000020 /* CCLK = VCO / 4 */
+#define CCLK_DIV8 0x00000030 /* CCLK = VCO / 8 */
+
+/* PLL_STAT Masks */
+#define ACTIVE_PLLENABLED 0x0001 /* Processor In Active Mode With PLL Enabled */
+#define FULL_ON 0x0002 /* Processor In Full On Mode */
+#define ACTIVE_PLLDISABLED 0x0004 /* Processor In Active Mode With PLL Disabled */
+#define PLL_LOCKED 0x0020 /* PLL_LOCKCNT Has Been Reached */
+
+/* CHIPID Masks */
+#define CHIPID_VERSION 0xF0000000
+#define CHIPID_FAMILY 0x0FFFF000
+#define CHIPID_MANUFACTURE 0x00000FFE
+
+/* SWRST Mask */
+#define SYSTEM_RESET 0x00000007 /* Initiates a system software reset */
+
+/* ************* SYSTEM INTERRUPT CONTROLLER MASKS ***************** */
+
+ /* SIC_IAR0 Masks */
+
+#define P0_IVG(x) ((x)-7) /* Peripheral #0 assigned IVG #x */
+#define P1_IVG(x) ((x)-7) << 0x4 /* Peripheral #1 assigned IVG #x */
+#define P2_IVG(x) ((x)-7) << 0x8 /* Peripheral #2 assigned IVG #x */
+#define P3_IVG(x) ((x)-7) << 0xC /* Peripheral #3 assigned IVG #x */
+#define P4_IVG(x) ((x)-7) << 0x10 /* Peripheral #4 assigned IVG #x */
+#define P5_IVG(x) ((x)-7) << 0x14 /* Peripheral #5 assigned IVG #x */
+#define P6_IVG(x) ((x)-7) << 0x18 /* Peripheral #6 assigned IVG #x */
+#define P7_IVG(x) ((x)-7) << 0x1C /* Peripheral #7 assigned IVG #x */
+
+/* SIC_IAR1 Masks */
+
+#define P8_IVG(x) ((x)-7) /* Peripheral #8 assigned IVG #x */
+#define P9_IVG(x) ((x)-7) << 0x4 /* Peripheral #9 assigned IVG #x */
+#define P10_IVG(x) ((x)-7) << 0x8 /* Peripheral #10 assigned IVG #x */
+#define P11_IVG(x) ((x)-7) << 0xC /* Peripheral #11 assigned IVG #x */
+#define P12_IVG(x) ((x)-7) << 0x10 /* Peripheral #12 assigned IVG #x */
+#define P13_IVG(x) ((x)-7) << 0x14 /* Peripheral #13 assigned IVG #x */
+#define P14_IVG(x) ((x)-7) << 0x18 /* Peripheral #14 assigned IVG #x */
+#define P15_IVG(x) ((x)-7) << 0x1C /* Peripheral #15 assigned IVG #x */
+
+/* SIC_IAR2 Masks */
+#define P16_IVG(x) ((x)-7) /* Peripheral #16 assigned IVG #x */
+#define P17_IVG(x) ((x)-7) << 0x4 /* Peripheral #17 assigned IVG #x */
+#define P18_IVG(x) ((x)-7) << 0x8 /* Peripheral #18 assigned IVG #x */
+#define P19_IVG(x) ((x)-7) << 0xC /* Peripheral #19 assigned IVG #x */
+#define P20_IVG(x) ((x)-7) << 0x10 /* Peripheral #20 assigned IVG #x */
+#define P21_IVG(x) ((x)-7) << 0x14 /* Peripheral #21 assigned IVG #x */
+#define P22_IVG(x) ((x)-7) << 0x18 /* Peripheral #22 assigned IVG #x */
+#define P23_IVG(x) ((x)-7) << 0x1C /* Peripheral #23 assigned IVG #x */
+
+/* SIC_IMASK Masks */
+#define SIC_UNMASK_ALL 0x00000000 /* Unmask all peripheral interrupts */
+#define SIC_MASK_ALL 0xFFFFFFFF /* Mask all peripheral interrupts */
+#define SIC_MASK(x) (1 << (x)) /* Mask Peripheral #x interrupt */
+#define SIC_UNMASK(x) (0xFFFFFFFF ^ (1 << (x))) /* Unmask Peripheral #x interrupt */
+
+/* SIC_IWR Masks */
+#define IWR_DISABLE_ALL 0x00000000 /* Wakeup Disable all peripherals */
+#define IWR_ENABLE_ALL 0xFFFFFFFF /* Wakeup Enable all peripherals */
+#define IWR_ENABLE(x) (1 << (x)) /* Wakeup Enable Peripheral #x */
+#define IWR_DISABLE(x) (0xFFFFFFFF ^ (1 << (x))) /* Wakeup Disable Peripheral #x */
+
+/* ********* WATCHDOG TIMER MASKS ********************8 */
+
+/* Watchdog Timer WDOG_CTL Register */
+#define ICTL(x) ((x<<1) & 0x0006)
+#define ENABLE_RESET 0x00000000 /* Set Watchdog Timer to generate reset */
+#define ENABLE_NMI 0x00000002 /* Set Watchdog Timer to generate non-maskable interrupt */
+#define ENABLE_GPI 0x00000004 /* Set Watchdog Timer to generate general-purpose interrupt */
+#define DISABLE_EVT 0x00000006 /* Disable Watchdog Timer interrupts */
+
+#define TMR_EN 0x0000
+#define TMR_DIS 0x0AD0
+#define TRO 0x8000
+
+#define ICTL_P0 0x01
+#define ICTL_P1 0x02
+#define TRO_P 0x0F
+
+/* ***************************** UART CONTROLLER MASKS ********************** */
+
+/* UART_LCR Register */
+
+#define DLAB 0x80
+#define SB 0x40
+#define STP 0x20
+#define EPS 0x10
+#define PEN 0x08
+#define STB 0x04
+#define WLS(x) ((x-5) & 0x03)
+
+#define DLAB_P 0x07
+#define SB_P 0x06
+#define STP_P 0x05
+#define EPS_P 0x04
+#define PEN_P 0x03
+#define STB_P 0x02
+#define WLS_P1 0x01
+#define WLS_P0 0x00
+
+/* UART_MCR Register */
+#define LOOP_ENA 0x10
+#define LOOP_ENA_P 0x04
+
+/* UART_LSR Register */
+#define TEMT 0x40
+#define THRE 0x20
+#define BI 0x10
+#define FE 0x08
+#define PE 0x04
+#define OE 0x02
+#define DR 0x01
+
+#define TEMP_P 0x06
+#define THRE_P 0x05
+#define BI_P 0x04
+#define FE_P 0x03
+#define PE_P 0x02
+#define OE_P 0x01
+#define DR_P 0x00
+
+/* UART_IER Register */
+#define ELSI 0x04
+#define ETBEI 0x02
+#define ERBFI 0x01
+
+#define ELSI_P 0x02
+#define ETBEI_P 0x01
+#define ERBFI_P 0x00
+
+/* UART_IIR Register */
+#define STATUS(x) ((x << 1) & 0x06)
+#define NINT 0x01
+#define STATUS_P1 0x02
+#define STATUS_P0 0x01
+#define NINT_P 0x00
+#define IIR_TX_READY 0x02 /* UART_THR empty */
+#define IIR_RX_READY 0x04 /* Receive data ready */
+#define IIR_LINE_CHANGE 0x06 /* Receive line status */
+#define IIR_STATUS 0x06
+
+/* UART_GCTL Register */
+#define FFE 0x20
+#define FPE 0x10
+#define RPOLC 0x08
+#define TPOLC 0x04
+#define IREN 0x02
+#define UCEN 0x01
+
+#define FFE_P 0x05
+#define FPE_P 0x04
+#define RPOLC_P 0x03
+#define TPOLC_P 0x02
+#define IREN_P 0x01
+#define UCEN_P 0x00
+
+/* ********** SERIAL PORT MASKS ********************** */
+
+/* SPORTx_TCR1 Masks */
+#define TSPEN 0x0001 /* TX enable */
+#define ITCLK 0x0002 /* Internal TX Clock Select */
+#define TDTYPE 0x000C /* TX Data Formatting Select */
+#define TLSBIT 0x0010 /* TX Bit Order */
+#define ITFS 0x0200 /* Internal TX Frame Sync Select */
+#define TFSR 0x0400 /* TX Frame Sync Required Select */
+#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */
+#define LTFS 0x1000 /* Low TX Frame Sync Select */
+#define LATFS 0x2000 /* Late TX Frame Sync Select */
+#define TCKFE 0x4000 /* TX Clock Falling Edge Select */
+
+/* SPORTx_TCR2 Masks */
+#define SLEN 0x001F /*TX Word Length */
+#define TXSE 0x0100 /*TX Secondary Enable */
+#define TSFSE 0x0200 /*TX Stereo Frame Sync Enable */
+#define TRFST 0x0400 /*TX Right-First Data Order */
+
+/* SPORTx_RCR1 Masks */
+#define RSPEN 0x0001 /* RX enable */
+#define IRCLK 0x0002 /* Internal RX Clock Select */
+#define RDTYPE 0x000C /* RX Data Formatting Select */
+#define RULAW 0x0008 /* u-Law enable */
+#define RALAW 0x000C /* A-Law enable */
+#define RLSBIT 0x0010 /* RX Bit Order */
+#define IRFS 0x0200 /* Internal RX Frame Sync Select */
+#define RFSR 0x0400 /* RX Frame Sync Required Select */
+#define LRFS 0x1000 /* Low RX Frame Sync Select */
+#define LARFS 0x2000 /* Late RX Frame Sync Select */
+#define RCKFE 0x4000 /* RX Clock Falling Edge Select */
+
+/* SPORTx_RCR2 Masks */
+#define SLEN 0x001F /*RX Word Length */
+#define RXSE 0x0100 /*RX Secondary Enable */
+#define RSFSE 0x0200 /*RX Stereo Frame Sync Enable */
+#define RRFST 0x0400 /*Right-First Data Order */
+
+/*SPORTx_STAT Masks */
+#define RXNE 0x0001 /*RX FIFO Not Empty Status */
+#define RUVF 0x0002 /*RX Underflow Status */
+#define ROVF 0x0004 /*RX Overflow Status */
+#define TXF 0x0008 /*TX FIFO Full Status */
+#define TUVF 0x0010 /*TX Underflow Status */
+#define TOVF 0x0020 /*TX Overflow Status */
+#define TXHRE 0x0040 /*TX Hold Register Empty */
+
+/*SPORTx_MCMC1 Masks */
+#define SP_WSIZE 0x0000F000 /*Multichannel Window Size Field */
+#define SP_WOFF 0x000003FF /*Multichannel Window Offset Field */
+
+/*SPORTx_MCMC2 Masks */
+#define MCCRM 0x00000003 /*Multichannel Clock Recovery Mode */
+#define MCDTXPE 0x00000004 /*Multichannel DMA Transmit Packing */
+#define MCDRXPE 0x00000008 /*Multichannel DMA Receive Packing */
+#define MCMEN 0x00000010 /*Multichannel Frame Mode Enable */
+#define FSDR 0x00000080 /*Multichannel Frame Sync to Data Relationship */
+#define MFD 0x0000F000 /*Multichannel Frame Delay */
+
+/* ********* PARALLEL PERIPHERAL INTERFACE (PPI) MASKS **************** */
+
+/* PPI_CONTROL Masks */
+#define PORT_EN 0x00000001 /* PPI Port Enable */
+#define PORT_DIR 0x00000002 /* PPI Port Direction */
+#define XFR_TYPE 0x0000000C /* PPI Transfer Type */
+#define PORT_CFG 0x00000030 /* PPI Port Configuration */
+#define FLD_SEL 0x00000040 /* PPI Active Field Select */
+#define PACK_EN 0x00000080 /* PPI Packing Mode */
+#define DMA32 0x00000100 /* PPI 32-bit DMA Enable */
+#define SKIP_EN 0x00000200 /* PPI Skip Element Enable */
+#define SKIP_EO 0x00000400 /* PPI Skip Even/Odd Elements */
+#define DLENGTH 0x00003800 /* PPI Data Length */
+#define DLEN_8 0x0000 /* Data Length = 8 Bits */
+#define DLEN_10 0x0800 /* Data Length = 10 Bits */
+#define DLEN_11 0x1000 /* Data Length = 11 Bits */
+#define DLEN_12 0x1800 /* Data Length = 12 Bits */
+#define DLEN_13 0x2000 /* Data Length = 13 Bits */
+#define DLEN_14 0x2800 /* Data Length = 14 Bits */
+#define DLEN_15 0x3000 /* Data Length = 15 Bits */
+#define DLEN_16 0x3800 /* Data Length = 16 Bits */
+#define DLEN(x) (((x-9) & 0x07) << 11) /* PPI Data Length (only works for x=10-->x=16) */
+#define POL 0x0000C000 /* PPI Signal Polarities */
+
+/* PPI_STATUS Masks */
+#define FLD 0x00000400 /* Field Indicator */
+#define FT_ERR 0x00000800 /* Frame Track Error */
+#define OVR 0x00001000 /* FIFO Overflow Error */
+#define UNDR 0x00002000 /* FIFO Underrun Error */
+#define ERR_DET 0x00004000 /* Error Detected Indicator */
+#define ERR_NCOR 0x00008000 /* Error Not Corrected Indicator */
+
+/* ********** DMA CONTROLLER MASKS *********************8 */
+
+/*DMAx_CONFIG, MDMA_yy_CONFIG Masks */
+#define DMAEN 0x00000001 /* Channel Enable */
+#define WNR 0x00000002 /* Channel Direction (W/R*) */
+#define WDSIZE_8 0x00000000 /* Word Size 8 bits */
+#define WDSIZE_16 0x00000004 /* Word Size 16 bits */
+#define WDSIZE_32 0x00000008 /* Word Size 32 bits */
+#define DMA2D 0x00000010 /* 2D/1D* Mode */
+#define RESTART 0x00000020 /* Restart */
+#define DI_SEL 0x00000040 /* Data Interrupt Select */
+#define DI_EN 0x00000080 /* Data Interrupt Enable */
+#define NDSIZE_0 0x0000 /* Next Descriptor Size = 0 (Stop/Autobuffer) */
+#define NDSIZE_1 0x0100 /* Next Descriptor Size = 1 */
+#define NDSIZE_2 0x0200 /* Next Descriptor Size = 2 */
+#define NDSIZE_3 0x0300 /* Next Descriptor Size = 3 */
+#define NDSIZE_4 0x0400 /* Next Descriptor Size = 4 */
+#define NDSIZE_5 0x0500 /* Next Descriptor Size = 5 */
+#define NDSIZE_6 0x0600 /* Next Descriptor Size = 6 */
+#define NDSIZE_7 0x0700 /* Next Descriptor Size = 7 */
+#define NDSIZE_8 0x0800 /* Next Descriptor Size = 8 */
+#define NDSIZE_9 0x0900 /* Next Descriptor Size = 9 */
+#define NDSIZE 0x00000900 /* Next Descriptor Size */
+#define DMAFLOW 0x00007000 /* Flow Control */
+#define DMAFLOW_STOP 0x0000 /* Stop Mode */
+#define DMAFLOW_AUTO 0x1000 /* Autobuffer Mode */
+#define DMAFLOW_ARRAY 0x4000 /* Descriptor Array Mode */
+#define DMAFLOW_SMALL 0x6000 /* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE 0x7000 /* Large Model Descriptor List Mode */
+
+#define DMAEN_P 0 /* Channel Enable */
+#define WNR_P 1 /* Channel Direction (W/R*) */
+#define DMA2D_P 4 /* 2D/1D* Mode */
+#define RESTART_P 5 /* Restart */
+#define DI_SEL_P 6 /* Data Interrupt Select */
+#define DI_EN_P 7 /* Data Interrupt Enable */
+
+/*DMAx_IRQ_STATUS, MDMA_yy_IRQ_STATUS Masks */
+
+#define DMA_DONE 0x00000001 /* DMA Done Indicator */
+#define DMA_ERR 0x00000002 /* DMA Error Indicator */
+#define DFETCH 0x00000004 /* Descriptor Fetch Indicator */
+#define DMA_RUN 0x00000008 /* DMA Running Indicator */
+
+#define DMA_DONE_P 0 /* DMA Done Indicator */
+#define DMA_ERR_P 1 /* DMA Error Indicator */
+#define DFETCH_P 2 /* Descriptor Fetch Indicator */
+#define DMA_RUN_P 3 /* DMA Running Indicator */
+
+/*DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP Masks */
+
+#define CTYPE 0x00000040 /* DMA Channel Type Indicator */
+#define CTYPE_P 6 /* DMA Channel Type Indicator BIT POSITION */
+#define PCAP8 0x00000080 /* DMA 8-bit Operation Indicator */
+#define PCAP16 0x00000100 /* DMA 16-bit Operation Indicator */
+#define PCAP32 0x00000200 /* DMA 32-bit Operation Indicator */
+#define PCAPWR 0x00000400 /* DMA Write Operation Indicator */
+#define PCAPRD 0x00000800 /* DMA Read Operation Indicator */
+#define PMAP 0x00007000 /* DMA Peripheral Map Field */
+
+/* ************* GENERAL PURPOSE TIMER MASKS ******************** */
+
+/* PWM Timer bit definitions */
+
+/* TIMER_ENABLE Register */
+#define TIMEN0 0x0001
+#define TIMEN1 0x0002
+#define TIMEN2 0x0004
+
+#define TIMEN0_P 0x00
+#define TIMEN1_P 0x01
+#define TIMEN2_P 0x02
+
+/* TIMER_DISABLE Register */
+#define TIMDIS0 0x0001
+#define TIMDIS1 0x0002
+#define TIMDIS2 0x0004
+
+#define TIMDIS0_P 0x00
+#define TIMDIS1_P 0x01
+#define TIMDIS2_P 0x02
+
+/* TIMER_STATUS Register */
+#define TIMIL0 0x0001
+#define TIMIL1 0x0002
+#define TIMIL2 0x0004
+#define TOVL_ERR0 0x0010
+#define TOVL_ERR1 0x0020
+#define TOVL_ERR2 0x0040
+#define TRUN0 0x1000
+#define TRUN1 0x2000
+#define TRUN2 0x4000
+
+#define TIMIL0_P 0x00
+#define TIMIL1_P 0x01
+#define TIMIL2_P 0x02
+#define TOVL_ERR0_P 0x04
+#define TOVL_ERR1_P 0x05
+#define TOVL_ERR2_P 0x06
+#define TRUN0_P 0x0C
+#define TRUN1_P 0x0D
+#define TRUN2_P 0x0E
+
+/* TIMERx_CONFIG Registers */
+#define PWM_OUT 0x0001
+#define WDTH_CAP 0x0002
+#define EXT_CLK 0x0003
+#define PULSE_HI 0x0004
+#define PERIOD_CNT 0x0008
+#define IRQ_ENA 0x0010
+#define TIN_SEL 0x0020
+#define OUT_DIS 0x0040
+#define CLK_SEL 0x0080
+#define TOGGLE_HI 0x0100
+#define EMU_RUN 0x0200
+#define ERR_TYP(x) ((x & 0x03) << 14)
+
+#define TMODE_P0 0x00
+#define TMODE_P1 0x01
+#define PULSE_HI_P 0x02
+#define PERIOD_CNT_P 0x03
+#define IRQ_ENA_P 0x04
+#define TIN_SEL_P 0x05
+#define OUT_DIS_P 0x06
+#define CLK_SEL_P 0x07
+#define TOGGLE_HI_P 0x08
+#define EMU_RUN_P 0x09
+#define ERR_TYP_P0 0x0E
+#define ERR_TYP_P1 0x0F
+
+/*/ ****************** PROGRAMMABLE FLAG MASKS ********************* */
+
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) Masks */
+#define PF0 0x0001
+#define PF1 0x0002
+#define PF2 0x0004
+#define PF3 0x0008
+#define PF4 0x0010
+#define PF5 0x0020
+#define PF6 0x0040
+#define PF7 0x0080
+#define PF8 0x0100
+#define PF9 0x0200
+#define PF10 0x0400
+#define PF11 0x0800
+#define PF12 0x1000
+#define PF13 0x2000
+#define PF14 0x4000
+#define PF15 0x8000
+
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) BIT POSITIONS */
+#define PF0_P 0
+#define PF1_P 1
+#define PF2_P 2
+#define PF3_P 3
+#define PF4_P 4
+#define PF5_P 5
+#define PF6_P 6
+#define PF7_P 7
+#define PF8_P 8
+#define PF9_P 9
+#define PF10_P 10
+#define PF11_P 11
+#define PF12_P 12
+#define PF13_P 13
+#define PF14_P 14
+#define PF15_P 15
+
+/* *********** SERIAL PERIPHERAL INTERFACE (SPI) MASKS **************** */
+
+/* SPI_CTL Masks */
+#define TIMOD 0x00000003 /* Transfer initiation mode and interrupt generation */
+#define SZ 0x00000004 /* Send Zero (=0) or last (=1) word when TDBR empty. */
+#define GM 0x00000008 /* When RDBR full, get more (=1) data or discard (=0) incoming Data */
+#define PSSE 0x00000010 /* Enable (=1) Slave-Select input for Master. */
+#define EMISO 0x00000020 /* Enable (=1) MISO pin as an output. */
+#define SPI_LEN 0x00000100 /* Word length (0 => 8 bits, 1 => 16 bits) */
+#define LSBF 0x00000200 /* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */
+#define CPHA 0x00000400 /* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */
+#define CPOL 0x00000800 /* Clock polarity (0 => active-high, 1 => active-low) */
+#define MSTR 0x00001000 /* Configures SPI as master (=1) or slave (=0) */
+#define WOM 0x00002000 /* Open drain (=1) data output enable (for MOSI and MISO) */
+#define SPE 0x00004000 /* SPI module enable (=1), disable (=0) */
+
+/* SPI_FLG Masks */
+#define FLS1 0x00000002 /* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2 0x00000004 /* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3 0x00000008 /* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4 0x00000010 /* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5 0x00000020 /* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6 0x00000040 /* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7 0x00000080 /* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1 0x00000200 /* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLG2 0x00000400 /* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3 0x00000800 /* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLG4 0x00001000 /* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLG5 0x00002000 /* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLG6 0x00004000 /* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLG7 0x00008000 /* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_FLG Bit Positions */
+#define FLS1_P 0x00000001 /* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2_P 0x00000002 /* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3_P 0x00000003 /* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4_P 0x00000004 /* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5_P 0x00000005 /* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6_P 0x00000006 /* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7_P 0x00000007 /* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1_P 0x00000009 /* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLG2_P 0x0000000A /* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3_P 0x0000000B /* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLG4_P 0x0000000C /* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLG5_P 0x0000000D /* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLG6_P 0x0000000E /* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLG7_P 0x0000000F /* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_STAT Masks */
+#define SPIF 0x00000001 /* Set (=1) when SPI single-word transfer complete */
+#define MODF 0x00000002 /* Set (=1) in a master device when some other device tries to become master */
+#define TXE 0x00000004 /* Set (=1) when transmission occurs with no new data in SPI_TDBR */
+#define TXS 0x00000008 /* SPI_TDBR Data Buffer Status (0=Empty, 1=Full) */
+#define RBSY 0x00000010 /* Set (=1) when data is received with RDBR full */
+#define RXS 0x00000020 /* SPI_RDBR Data Buffer Status (0=Empty, 1=Full) */
+#define TXCOL 0x00000040 /* When set (=1), corrupt data may have been transmitted */
+
+/* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS ************* */
+
+/* AMGCTL Masks */
+#define AMCKEN 0x00000001 /* Enable CLKOUT */
+#define AMBEN_B0 0x00000002 /* Enable Asynchronous Memory Bank 0 only */
+#define AMBEN_B0_B1 0x00000004 /* Enable Asynchronous Memory Banks 0 & 1 only */
+#define AMBEN_B0_B1_B2 0x00000006 /* Enable Asynchronous Memory Banks 0, 1, and 2 */
+#define AMBEN_ALL 0x00000008 /* Enable Asynchronous Memory Banks (all) 0, 1, 2, and 3 */
+
+/* AMGCTL Bit Positions */
+#define AMCKEN_P 0x00000000 /* Enable CLKOUT */
+#define AMBEN_P0 0x00000001 /* Asynchronous Memory Enable, 000 - banks 0-3 disabled, 001 - Bank 0 enabled */
+#define AMBEN_P1 0x00000002 /* Asynchronous Memory Enable, 010 - banks 0&1 enabled, 011 - banks 0-3 enabled */
+#define AMBEN_P2 0x00000003 /* Asynchronous Memory Enable, 1xx - All banks (bank 0, 1, 2, and 3) enabled */
+
+/* AMBCTL0 Masks */
+#define B0RDYEN 0x00000001 /* Bank 0 RDY Enable, 0=disable, 1=enable */
+#define B0RDYPOL 0x00000002 /* Bank 0 RDY Active high, 0=active low, 1=active high */
+#define B0TT_1 0x00000004 /* Bank 0 Transition Time from Read to Write = 1 cycle */
+#define B0TT_2 0x00000008 /* Bank 0 Transition Time from Read to Write = 2 cycles */
+#define B0TT_3 0x0000000C /* Bank 0 Transition Time from Read to Write = 3 cycles */
+#define B0TT_4 0x00000000 /* Bank 0 Transition Time from Read to Write = 4 cycles */
+#define B0ST_1 0x00000010 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=1 cycle */
+#define B0ST_2 0x00000020 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=2 cycles */
+#define B0ST_3 0x00000030 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=3 cycles */
+#define B0ST_4 0x00000000 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=4 cycles */
+#define B0HT_1 0x00000040 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 1 cycle */
+#define B0HT_2 0x00000080 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 2 cycles */
+#define B0HT_3 0x000000C0 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 3 cycles */
+#define B0HT_0 0x00000000 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 0 cycles */
+#define B0RAT_1 0x00000100 /* Bank 0 Read Access Time = 1 cycle */
+#define B0RAT_2 0x00000200 /* Bank 0 Read Access Time = 2 cycles */
+#define B0RAT_3 0x00000300 /* Bank 0 Read Access Time = 3 cycles */
+#define B0RAT_4 0x00000400 /* Bank 0 Read Access Time = 4 cycles */
+#define B0RAT_5 0x00000500 /* Bank 0 Read Access Time = 5 cycles */
+#define B0RAT_6 0x00000600 /* Bank 0 Read Access Time = 6 cycles */
+#define B0RAT_7 0x00000700 /* Bank 0 Read Access Time = 7 cycles */
+#define B0RAT_8 0x00000800 /* Bank 0 Read Access Time = 8 cycles */
+#define B0RAT_9 0x00000900 /* Bank 0 Read Access Time = 9 cycles */
+#define B0RAT_10 0x00000A00 /* Bank 0 Read Access Time = 10 cycles */
+#define B0RAT_11 0x00000B00 /* Bank 0 Read Access Time = 11 cycles */
+#define B0RAT_12 0x00000C00 /* Bank 0 Read Access Time = 12 cycles */
+#define B0RAT_13 0x00000D00 /* Bank 0 Read Access Time = 13 cycles */
+#define B0RAT_14 0x00000E00 /* Bank 0 Read Access Time = 14 cycles */
+#define B0RAT_15 0x00000F00 /* Bank 0 Read Access Time = 15 cycles */
+#define B0WAT_1 0x00001000 /* Bank 0 Write Access Time = 1 cycle */
+#define B0WAT_2 0x00002000 /* Bank 0 Write Access Time = 2 cycles */
+#define B0WAT_3 0x00003000 /* Bank 0 Write Access Time = 3 cycles */
+#define B0WAT_4 0x00004000 /* Bank 0 Write Access Time = 4 cycles */
+#define B0WAT_5 0x00005000 /* Bank 0 Write Access Time = 5 cycles */
+#define B0WAT_6 0x00006000 /* Bank 0 Write Access Time = 6 cycles */
+#define B0WAT_7 0x00007000 /* Bank 0 Write Access Time = 7 cycles */
+#define B0WAT_8 0x00008000 /* Bank 0 Write Access Time = 8 cycles */
+#define B0WAT_9 0x00009000 /* Bank 0 Write Access Time = 9 cycles */
+#define B0WAT_10 0x0000A000 /* Bank 0 Write Access Time = 10 cycles */
+#define B0WAT_11 0x0000B000 /* Bank 0 Write Access Time = 11 cycles */
+#define B0WAT_12 0x0000C000 /* Bank 0 Write Access Time = 12 cycles */
+#define B0WAT_13 0x0000D000 /* Bank 0 Write Access Time = 13 cycles */
+#define B0WAT_14 0x0000E000 /* Bank 0 Write Access Time = 14 cycles */
+#define B0WAT_15 0x0000F000 /* Bank 0 Write Access Time = 15 cycles */
+#define B1RDYEN 0x00010000 /* Bank 1 RDY enable, 0=disable, 1=enable */
+#define B1RDYPOL 0x00020000 /* Bank 1 RDY Active high, 0=active low, 1=active high */
+#define B1TT_1 0x00040000 /* Bank 1 Transition Time from Read to Write = 1 cycle */
+#define B1TT_2 0x00080000 /* Bank 1 Transition Time from Read to Write = 2 cycles */
+#define B1TT_3 0x000C0000 /* Bank 1 Transition Time from Read to Write = 3 cycles */
+#define B1TT_4 0x00000000 /* Bank 1 Transition Time from Read to Write = 4 cycles */
+#define B1ST_1 0x00100000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B1ST_2 0x00200000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B1ST_3 0x00300000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B1ST_4 0x00000000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B1HT_1 0x00400000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B1HT_2 0x00800000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B1HT_3 0x00C00000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B1HT_0 0x00000000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B1RAT_1 0x01000000 /* Bank 1 Read Access Time = 1 cycle */
+#define B1RAT_2 0x02000000 /* Bank 1 Read Access Time = 2 cycles */
+#define B1RAT_3 0x03000000 /* Bank 1 Read Access Time = 3 cycles */
+#define B1RAT_4 0x04000000 /* Bank 1 Read Access Time = 4 cycles */
+#define B1RAT_5 0x05000000 /* Bank 1 Read Access Time = 5 cycles */
+#define B1RAT_6 0x06000000 /* Bank 1 Read Access Time = 6 cycles */
+#define B1RAT_7 0x07000000 /* Bank 1 Read Access Time = 7 cycles */
+#define B1RAT_8 0x08000000 /* Bank 1 Read Access Time = 8 cycles */
+#define B1RAT_9 0x09000000 /* Bank 1 Read Access Time = 9 cycles */
+#define B1RAT_10 0x0A000000 /* Bank 1 Read Access Time = 10 cycles */
+#define B1RAT_11 0x0B000000 /* Bank 1 Read Access Time = 11 cycles */
+#define B1RAT_12 0x0C000000 /* Bank 1 Read Access Time = 12 cycles */
+#define B1RAT_13 0x0D000000 /* Bank 1 Read Access Time = 13 cycles */
+#define B1RAT_14 0x0E000000 /* Bank 1 Read Access Time = 14 cycles */
+#define B1RAT_15 0x0F000000 /* Bank 1 Read Access Time = 15 cycles */
+#define B1WAT_1 0x10000000 /* Bank 1 Write Access Time = 1 cycle */
+#define B1WAT_2 0x20000000 /* Bank 1 Write Access Time = 2 cycles */
+#define B1WAT_3 0x30000000 /* Bank 1 Write Access Time = 3 cycles */
+#define B1WAT_4 0x40000000 /* Bank 1 Write Access Time = 4 cycles */
+#define B1WAT_5 0x50000000 /* Bank 1 Write Access Time = 5 cycles */
+#define B1WAT_6 0x60000000 /* Bank 1 Write Access Time = 6 cycles */
+#define B1WAT_7 0x70000000 /* Bank 1 Write Access Time = 7 cycles */
+#define B1WAT_8 0x80000000 /* Bank 1 Write Access Time = 8 cycles */
+#define B1WAT_9 0x90000000 /* Bank 1 Write Access Time = 9 cycles */
+#define B1WAT_10 0xA0000000 /* Bank 1 Write Access Time = 10 cycles */
+#define B1WAT_11 0xB0000000 /* Bank 1 Write Access Time = 11 cycles */
+#define B1WAT_12 0xC0000000 /* Bank 1 Write Access Time = 12 cycles */
+#define B1WAT_13 0xD0000000 /* Bank 1 Write Access Time = 13 cycles */
+#define B1WAT_14 0xE0000000 /* Bank 1 Write Access Time = 14 cycles */
+#define B1WAT_15 0xF0000000 /* Bank 1 Write Access Time = 15 cycles */
+
+/* AMBCTL1 Masks */
+#define B2RDYEN 0x00000001 /* Bank 2 RDY Enable, 0=disable, 1=enable */
+#define B2RDYPOL 0x00000002 /* Bank 2 RDY Active high, 0=active low, 1=active high */
+#define B2TT_1 0x00000004 /* Bank 2 Transition Time from Read to Write = 1 cycle */
+#define B2TT_2 0x00000008 /* Bank 2 Transition Time from Read to Write = 2 cycles */
+#define B2TT_3 0x0000000C /* Bank 2 Transition Time from Read to Write = 3 cycles */
+#define B2TT_4 0x00000000 /* Bank 2 Transition Time from Read to Write = 4 cycles */
+#define B2ST_1 0x00000010 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B2ST_2 0x00000020 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B2ST_3 0x00000030 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B2ST_4 0x00000000 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B2HT_1 0x00000040 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B2HT_2 0x00000080 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B2HT_3 0x000000C0 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B2HT_0 0x00000000 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B2RAT_1 0x00000100 /* Bank 2 Read Access Time = 1 cycle */
+#define B2RAT_2 0x00000200 /* Bank 2 Read Access Time = 2 cycles */
+#define B2RAT_3 0x00000300 /* Bank 2 Read Access Time = 3 cycles */
+#define B2RAT_4 0x00000400 /* Bank 2 Read Access Time = 4 cycles */
+#define B2RAT_5 0x00000500 /* Bank 2 Read Access Time = 5 cycles */
+#define B2RAT_6 0x00000600 /* Bank 2 Read Access Time = 6 cycles */
+#define B2RAT_7 0x00000700 /* Bank 2 Read Access Time = 7 cycles */
+#define B2RAT_8 0x00000800 /* Bank 2 Read Access Time = 8 cycles */
+#define B2RAT_9 0x00000900 /* Bank 2 Read Access Time = 9 cycles */
+#define B2RAT_10 0x00000A00 /* Bank 2 Read Access Time = 10 cycles */
+#define B2RAT_11 0x00000B00 /* Bank 2 Read Access Time = 11 cycles */
+#define B2RAT_12 0x00000C00 /* Bank 2 Read Access Time = 12 cycles */
+#define B2RAT_13 0x00000D00 /* Bank 2 Read Access Time = 13 cycles */
+#define B2RAT_14 0x00000E00 /* Bank 2 Read Access Time = 14 cycles */
+#define B2RAT_15 0x00000F00 /* Bank 2 Read Access Time = 15 cycles */
+#define B2WAT_1 0x00001000 /* Bank 2 Write Access Time = 1 cycle */
+#define B2WAT_2 0x00002000 /* Bank 2 Write Access Time = 2 cycles */
+#define B2WAT_3 0x00003000 /* Bank 2 Write Access Time = 3 cycles */
+#define B2WAT_4 0x00004000 /* Bank 2 Write Access Time = 4 cycles */
+#define B2WAT_5 0x00005000 /* Bank 2 Write Access Time = 5 cycles */
+#define B2WAT_6 0x00006000 /* Bank 2 Write Access Time = 6 cycles */
+#define B2WAT_7 0x00007000 /* Bank 2 Write Access Time = 7 cycles */
+#define B2WAT_8 0x00008000 /* Bank 2 Write Access Time = 8 cycles */
+#define B2WAT_9 0x00009000 /* Bank 2 Write Access Time = 9 cycles */
+#define B2WAT_10 0x0000A000 /* Bank 2 Write Access Time = 10 cycles */
+#define B2WAT_11 0x0000B000 /* Bank 2 Write Access Time = 11 cycles */
+#define B2WAT_12 0x0000C000 /* Bank 2 Write Access Time = 12 cycles */
+#define B2WAT_13 0x0000D000 /* Bank 2 Write Access Time = 13 cycles */
+#define B2WAT_14 0x0000E000 /* Bank 2 Write Access Time = 14 cycles */
+#define B2WAT_15 0x0000F000 /* Bank 2 Write Access Time = 15 cycles */
+#define B3RDYEN 0x00010000 /* Bank 3 RDY enable, 0=disable, 1=enable */
+#define B3RDYPOL 0x00020000 /* Bank 3 RDY Active high, 0=active low, 1=active high */
+#define B3TT_1 0x00040000 /* Bank 3 Transition Time from Read to Write = 1 cycle */
+#define B3TT_2 0x00080000 /* Bank 3 Transition Time from Read to Write = 2 cycles */
+#define B3TT_3 0x000C0000 /* Bank 3 Transition Time from Read to Write = 3 cycles */
+#define B3TT_4 0x00000000 /* Bank 3 Transition Time from Read to Write = 4 cycles */
+#define B3ST_1 0x00100000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B3ST_2 0x00200000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B3ST_3 0x00300000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B3ST_4 0x00000000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B3HT_1 0x00400000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B3HT_2 0x00800000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B3HT_3 0x00C00000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B3HT_0 0x00000000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B3RAT_1 0x01000000 /* Bank 3 Read Access Time = 1 cycle */
+#define B3RAT_2 0x02000000 /* Bank 3 Read Access Time = 2 cycles */
+#define B3RAT_3 0x03000000 /* Bank 3 Read Access Time = 3 cycles */
+#define B3RAT_4 0x04000000 /* Bank 3 Read Access Time = 4 cycles */
+#define B3RAT_5 0x05000000 /* Bank 3 Read Access Time = 5 cycles */
+#define B3RAT_6 0x06000000 /* Bank 3 Read Access Time = 6 cycles */
+#define B3RAT_7 0x07000000 /* Bank 3 Read Access Time = 7 cycles */
+#define B3RAT_8 0x08000000 /* Bank 3 Read Access Time = 8 cycles */
+#define B3RAT_9 0x09000000 /* Bank 3 Read Access Time = 9 cycles */
+#define B3RAT_10 0x0A000000 /* Bank 3 Read Access Time = 10 cycles */
+#define B3RAT_11 0x0B000000 /* Bank 3 Read Access Time = 11 cycles */
+#define B3RAT_12 0x0C000000 /* Bank 3 Read Access Time = 12 cycles */
+#define B3RAT_13 0x0D000000 /* Bank 3 Read Access Time = 13 cycles */
+#define B3RAT_14 0x0E000000 /* Bank 3 Read Access Time = 14 cycles */
+#define B3RAT_15 0x0F000000 /* Bank 3 Read Access Time = 15 cycles */
+#define B3WAT_1 0x10000000 /* Bank 3 Write Access Time = 1 cycle */
+#define B3WAT_2 0x20000000 /* Bank 3 Write Access Time = 2 cycles */
+#define B3WAT_3 0x30000000 /* Bank 3 Write Access Time = 3 cycles */
+#define B3WAT_4 0x40000000 /* Bank 3 Write Access Time = 4 cycles */
+#define B3WAT_5 0x50000000 /* Bank 3 Write Access Time = 5 cycles */
+#define B3WAT_6 0x60000000 /* Bank 3 Write Access Time = 6 cycles */
+#define B3WAT_7 0x70000000 /* Bank 3 Write Access Time = 7 cycles */
+#define B3WAT_8 0x80000000 /* Bank 3 Write Access Time = 8 cycles */
+#define B3WAT_9 0x90000000 /* Bank 3 Write Access Time = 9 cycles */
+#define B3WAT_10 0xA0000000 /* Bank 3 Write Access Time = 10 cycles */
+#define B3WAT_11 0xB0000000 /* Bank 3 Write Access Time = 11 cycles */
+#define B3WAT_12 0xC0000000 /* Bank 3 Write Access Time = 12 cycles */
+#define B3WAT_13 0xD0000000 /* Bank 3 Write Access Time = 13 cycles */
+#define B3WAT_14 0xE0000000 /* Bank 3 Write Access Time = 14 cycles */
+#define B3WAT_15 0xF0000000 /* Bank 3 Write Access Time = 15 cycles */
+
+/* ********************** SDRAM CONTROLLER MASKS *************************** */
+
+/* SDGCTL Masks */
+#define SCTLE 0x00000001 /* Enable SCLK[0], /SRAS, /SCAS, /SWE, SDQM[3:0] */
+#define CL_2 0x00000008 /* SDRAM CAS latency = 2 cycles */
+#define CL_3 0x0000000C /* SDRAM CAS latency = 3 cycles */
+#define PFE 0x00000010 /* Enable SDRAM prefetch */
+#define PFP 0x00000020 /* Prefetch has priority over AMC requests */
+#define TRAS_1 0x00000040 /* SDRAM tRAS = 1 cycle */
+#define TRAS_2 0x00000080 /* SDRAM tRAS = 2 cycles */
+#define TRAS_3 0x000000C0 /* SDRAM tRAS = 3 cycles */
+#define TRAS_4 0x00000100 /* SDRAM tRAS = 4 cycles */
+#define TRAS_5 0x00000140 /* SDRAM tRAS = 5 cycles */
+#define TRAS_6 0x00000180 /* SDRAM tRAS = 6 cycles */
+#define TRAS_7 0x000001C0 /* SDRAM tRAS = 7 cycles */
+#define TRAS_8 0x00000200 /* SDRAM tRAS = 8 cycles */
+#define TRAS_9 0x00000240 /* SDRAM tRAS = 9 cycles */
+#define TRAS_10 0x00000280 /* SDRAM tRAS = 10 cycles */
+#define TRAS_11 0x000002C0 /* SDRAM tRAS = 11 cycles */
+#define TRAS_12 0x00000300 /* SDRAM tRAS = 12 cycles */
+#define TRAS_13 0x00000340 /* SDRAM tRAS = 13 cycles */
+#define TRAS_14 0x00000380 /* SDRAM tRAS = 14 cycles */
+#define TRAS_15 0x000003C0 /* SDRAM tRAS = 15 cycles */
+#define TRP_1 0x00000800 /* SDRAM tRP = 1 cycle */
+#define TRP_2 0x00001000 /* SDRAM tRP = 2 cycles */
+#define TRP_3 0x00001800 /* SDRAM tRP = 3 cycles */
+#define TRP_4 0x00002000 /* SDRAM tRP = 4 cycles */
+#define TRP_5 0x00002800 /* SDRAM tRP = 5 cycles */
+#define TRP_6 0x00003000 /* SDRAM tRP = 6 cycles */
+#define TRP_7 0x00003800 /* SDRAM tRP = 7 cycles */
+#define TRCD_1 0x00008000 /* SDRAM tRCD = 1 cycle */
+#define TRCD_2 0x00010000 /* SDRAM tRCD = 2 cycles */
+#define TRCD_3 0x00018000 /* SDRAM tRCD = 3 cycles */
+#define TRCD_4 0x00020000 /* SDRAM tRCD = 4 cycles */
+#define TRCD_5 0x00028000 /* SDRAM tRCD = 5 cycles */
+#define TRCD_6 0x00030000 /* SDRAM tRCD = 6 cycles */
+#define TRCD_7 0x00038000 /* SDRAM tRCD = 7 cycles */
+#define TWR_1 0x00080000 /* SDRAM tWR = 1 cycle */
+#define TWR_2 0x00100000 /* SDRAM tWR = 2 cycles */
+#define TWR_3 0x00180000 /* SDRAM tWR = 3 cycles */
+#define PUPSD 0x00200000 /*Power-up start delay */
+#define PSM 0x00400000 /* SDRAM power-up sequence = Precharge, mode register set, 8 CBR refresh cycles */
+#define PSS 0x00800000 /* enable SDRAM power-up sequence on next SDRAM access */
+#define SRFS 0x01000000 /* Start SDRAM self-refresh mode */
+#define EBUFE 0x02000000 /* Enable external buffering timing */
+#define FBBRW 0x04000000 /* Fast back-to-back read write enable */
+#define EMREN 0x10000000 /* Extended mode register enable */
+#define TCSR 0x20000000 /* Temp compensated self refresh value 85 deg C */
+#define CDDBG 0x40000000 /* Tristate SDRAM controls during bus grant */
+
+/* EBIU_SDBCTL Masks */
+#define EBE 0x00000001 /* Enable SDRAM external bank */
+#define EBSZ_16 0x00000000 /* SDRAM external bank size = 16MB */
+#define EBSZ_32 0x00000002 /* SDRAM external bank size = 32MB */
+#define EBSZ_64 0x00000004 /* SDRAM external bank size = 64MB */
+#define EBSZ_128 0x00000006 /* SDRAM external bank size = 128MB */
+#define EBCAW_8 0x00000000 /* SDRAM external bank column address width = 8 bits */
+#define EBCAW_9 0x00000010 /* SDRAM external bank column address width = 9 bits */
+#define EBCAW_10 0x00000020 /* SDRAM external bank column address width = 9 bits */
+#define EBCAW_11 0x00000030 /* SDRAM external bank column address width = 9 bits */
+
+/* EBIU_SDSTAT Masks */
+#define SDCI 0x00000001 /* SDRAM controller is idle */
+#define SDSRA 0x00000002 /* SDRAM SDRAM self refresh is active */
+#define SDPUA 0x00000004 /* SDRAM power up active */
+#define SDRS 0x00000008 /* SDRAM is in reset state */
+#define SDEASE 0x00000010 /* SDRAM EAB sticky error status - W1C */
+#define BGSTAT 0x00000020 /* Bus granted */
+
+/*VR_CTL Masks*/
+#define WAKE 0x100
+#define VLEV_6 0x60
+#define VLEV_7 0x70
+#define VLEV_8 0x80
+#define VLEV_9 0x90
+#define VLEV_10 0xA0
+#define VLEV_11 0xB0
+#define VLEV_12 0xC0
+#define VLEV_13 0xD0
+#define VLEV_14 0xE0
+#define VLEV_15 0xF0
+#define FREQ_3 0x03
+
+#endif /* _DEF_BF532_H */
diff --git a/include/asm-blackfin/mach-bf533/dma.h b/include/asm-blackfin/mach-bf533/dma.h
new file mode 100644
index 00000000000..bd9d5e94307
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/dma.h
@@ -0,0 +1,54 @@
+/*****************************************************************************
+*
+* BF-533/2/1 Specific Declarations
+*
+****************************************************************************/
+/*
+ * File: include/asm-blackfin/mach-bf533/dma.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 12
+
+#define CH_PPI 0
+#define CH_SPORT0_RX 1
+#define CH_SPORT0_TX 2
+#define CH_SPORT1_RX 3
+#define CH_SPORT1_TX 4
+#define CH_SPI 5
+#define CH_UART_RX 6
+#define CH_UART_TX 7
+#define CH_MEM_STREAM0_DEST 8 /* TX */
+#define CH_MEM_STREAM0_SRC 9 /* RX */
+#define CH_MEM_STREAM1_DEST 10 /* TX */
+#define CH_MEM_STREAM1_SRC 11 /* RX */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf533/irq.h b/include/asm-blackfin/mach-bf533/irq.h
new file mode 100644
index 00000000000..9879e68e315
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/irq.h
@@ -0,0 +1,177 @@
+/*
+ * File: include/asm-blackfin/mach-bf533/defBF532.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BF533_IRQ_H_
+#define _BF533_IRQ_H_
+
+/*
+ * Interrupt source definitions
+ Event Source Core Event Name
+Core Emulation **
+ Events (highest priority) EMU 0
+ Reset RST 1
+ NMI NMI 2
+ Exception EVX 3
+ Reserved -- 4
+ Hardware Error IVHW 5
+ Core Timer IVTMR 6 *
+ PLL Wakeup Interrupt IVG7 7
+ DMA Error (generic) IVG7 8
+ PPI Error Interrupt IVG7 9
+ SPORT0 Error Interrupt IVG7 10
+ SPORT1 Error Interrupt IVG7 11
+ SPI Error Interrupt IVG7 12
+ UART Error Interrupt IVG7 13
+ RTC Interrupt IVG8 14
+ DMA0 Interrupt (PPI) IVG8 15
+ DMA1 (SPORT0 RX) IVG9 16
+ DMA2 (SPORT0 TX) IVG9 17
+ DMA3 (SPORT1 RX) IVG9 18
+ DMA4 (SPORT1 TX) IVG9 19
+ DMA5 (PPI) IVG10 20
+ DMA6 (UART RX) IVG10 21
+ DMA7 (UART TX) IVG10 22
+ Timer0 IVG11 23
+ Timer1 IVG11 24
+ Timer2 IVG11 25
+ PF Interrupt A IVG12 26
+ PF Interrupt B IVG12 27
+ DMA8/9 Interrupt IVG13 28
+ DMA10/11 Interrupt IVG13 29
+ Watchdog Timer IVG13 30
+ Software Interrupt 1 IVG14 31
+ Software Interrupt 2 --
+ (lowest priority) IVG15 32 *
+ */
+#define SYS_IRQS 32
+#define NR_PERI_INTS 24
+
+/* The ABSTRACT IRQ definitions */
+/** the first seven of the following are fixed, the rest you change if you need to **/
+#define IRQ_EMU 0 /*Emulation */
+#define IRQ_RST 1 /*reset */
+#define IRQ_NMI 2 /*Non Maskable */
+#define IRQ_EVX 3 /*Exception */
+#define IRQ_UNUSED 4 /*- unused interrupt*/
+#define IRQ_HWERR 5 /*Hardware Error */
+#define IRQ_CORETMR 6 /*Core timer */
+
+#define IRQ_PLL_WAKEUP 7 /*PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR 8 /*DMA Error (general) */
+#define IRQ_PPI_ERROR 9 /*PPI Error Interrupt */
+#define IRQ_SPORT0_ERROR 10 /*SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR 11 /*SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR 12 /*SPI Error Interrupt */
+#define IRQ_UART_ERROR 13 /*UART Error Interrupt */
+#define IRQ_RTC 14 /*RTC Interrupt */
+#define IRQ_PPI 15 /*DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX 16 /*DMA1 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX 17 /*DMA2 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX 18 /*DMA3 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX 19 /*DMA4 Interrupt (SPORT1 TX) */
+#define IRQ_SPI 20 /*DMA5 Interrupt (SPI) */
+#define IRQ_UART_RX 21 /*DMA6 Interrupt (UART RX) */
+#define IRQ_UART_TX 22 /*DMA7 Interrupt (UART TX) */
+#define IRQ_TMR0 23 /*Timer 0 */
+#define IRQ_TMR1 24 /*Timer 1 */
+#define IRQ_TMR2 25 /*Timer 2 */
+#define IRQ_PROG_INTA 26 /*Programmable Flags A (8) */
+#define IRQ_PROG_INTB 27 /*Programmable Flags B (8) */
+#define IRQ_MEM_DMA0 28 /*DMA8/9 Interrupt (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1 29 /*DMA10/11 Interrupt (Memory DMA Stream 1) */
+#define IRQ_WATCH 30 /*Watch Dog Timer */
+
+#define IRQ_SW_INT1 31 /*Software Int 1 */
+#define IRQ_SW_INT2 32 /*Software Int 2 (reserved for SYSCALL) */
+
+#define IRQ_PF0 33
+#define IRQ_PF1 34
+#define IRQ_PF2 35
+#define IRQ_PF3 36
+#define IRQ_PF4 37
+#define IRQ_PF5 38
+#define IRQ_PF6 39
+#define IRQ_PF7 40
+#define IRQ_PF8 41
+#define IRQ_PF9 42
+#define IRQ_PF10 43
+#define IRQ_PF11 44
+#define IRQ_PF12 45
+#define IRQ_PF13 46
+#define IRQ_PF14 47
+#define IRQ_PF15 48
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS (IRQ_PF15+1)
+#else
+#define NR_IRQS SYS_IRQS
+#endif
+
+#define IVG7 7
+#define IVG8 8
+#define IVG9 9
+#define IVG10 10
+#define IVG11 11
+#define IVG12 12
+#define IVG13 13
+#define IVG14 14
+#define IVG15 15
+
+/* IAR0 BIT FIELDS*/
+#define RTC_ERROR_POS 28
+#define UART_ERROR_POS 24
+#define SPORT1_ERROR_POS 20
+#define SPI_ERROR_POS 16
+#define SPORT0_ERROR_POS 12
+#define PPI_ERROR_POS 8
+#define DMA_ERROR_POS 4
+#define PLLWAKE_ERROR_POS 0
+
+/* IAR1 BIT FIELDS*/
+#define DMA7_UARTTX_POS 28
+#define DMA6_UARTRX_POS 24
+#define DMA5_SPI_POS 20
+#define DMA4_SPORT1TX_POS 16
+#define DMA3_SPORT1RX_POS 12
+#define DMA2_SPORT0TX_POS 8
+#define DMA1_SPORT0RX_POS 4
+#define DMA0_PPI_POS 0
+
+/* IAR2 BIT FIELDS*/
+#define WDTIMER_POS 28
+#define MEMDMA1_POS 24
+#define MEMDMA0_POS 20
+#define PFB_POS 16
+#define PFA_POS 12
+#define TIMER2_POS 8
+#define TIMER1_POS 4
+#define TIMER0_POS 0
+
+#endif /* _BF533_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf533/mem_init.h b/include/asm-blackfin/mach-bf533/mem_init.h
new file mode 100644
index 00000000000..1620dae5254
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/mem_init.h
@@ -0,0 +1,316 @@
+/*
+ * File: include/asm-blackfin/mach-bf533/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_GENERIC_BOARD)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_7
+#define SDRAM_tRAS_num 7
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_6
+#define SDRAM_tRAS_num 6
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 8955223) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_5
+#define SDRAM_tRAS_num 5
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_4
+#define SDRAM_tRAS_num 4
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_3
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_4
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_3
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_2
+#define SDRAM_tRAS_num 2
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_1
+#define SDRAM_tRAS_num 1
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+ /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE EBSZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE EBSZ_64
+#endif
+#if (CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE EBSZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE EBSZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH EBCAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH EBCAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH EBCAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH EBCAW_8
+#endif
+
+#define mem_SDBCTL (SDRAM_WIDTH | SDRAM_SIZE | EBE)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF 1
+#else
+#define CLKIN_HALF 0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS 1
+#else
+#define PLL_BYPASS 0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT ((CONFIG_FLASH_SPEED_BHT * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST ((CONFIG_FLASH_SPEED_BST * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT ((CONFIG_FLASH_SPEED_BTT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0 \
+ (flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+ flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf533/mem_map.h b/include/asm-blackfin/mach-bf533/mem_map.h
new file mode 100644
index 00000000000..e84baa3e939
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/mem_map.h
@@ -0,0 +1,168 @@
+
+/*
+ * File: include/asm-blackfin/mach-bf533/mem_map.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MEM_MAP_533_H_
+#define _MEM_MAP_533_H_
+
+#define COREMMR_BASE 0xFFE00000 /* Core MMRs */
+#define SYSMMR_BASE 0xFFC00000 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE 0x20300000 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE 0x00100000 /* 1M */
+#define ASYNC_BANK2_BASE 0x20200000 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE 0x00100000 /* 1M */
+#define ASYNC_BANK1_BASE 0x20100000 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE 0x00100000 /* 1M */
+#define ASYNC_BANK0_BASE 0x20000000 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE 0x00100000 /* 1M */
+
+/* Boot ROM Memory */
+
+#define BOOT_ROM_START 0xEF000000
+
+/* Level 1 Memory */
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define BLKFIN_ICACHESIZE (16*1024)
+#else
+#define BLKFIN_ICACHESIZE (0*1024)
+#endif
+
+/* Memory Map for ADSP-BF533 processors */
+
+#ifdef CONFIG_BF533
+#define L1_CODE_START 0xFFA00000
+#define L1_DATA_A_START 0xFF800000
+#define L1_DATA_B_START 0xFF900000
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define L1_CODE_LENGTH (0x14000 - 0x4000)
+#else
+#define L1_CODE_LENGTH 0x14000
+#endif
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x8000
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+#endif
+
+/* Memory Map for ADSP-BF532 processors */
+
+#ifdef CONFIG_BF532
+#define L1_CODE_START 0xFFA08000
+#define L1_DATA_A_START 0xFF804000
+#define L1_DATA_B_START 0xFF904000
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define L1_CODE_LENGTH (0xC000 - 0x4000)
+#else
+#define L1_CODE_LENGTH 0xC000
+#endif
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x4000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x4000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x4000
+#define L1_DATA_B_LENGTH 0x4000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+#endif
+
+/* Memory Map for ADSP-BF531 processors */
+
+#ifdef CONFIG_BF531
+#define L1_CODE_START 0xFFA08000
+#define L1_DATA_A_START 0xFF804000
+#define L1_DATA_B_START 0xFF904000
+#define L1_CODE_LENGTH 0x4000
+#define L1_DATA_B_LENGTH 0x0000
+
+
+#ifdef CONFIG_BLKFIN_DCACHE
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x4000 - 0x4000)
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x4000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif
+
+#endif
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF533) || defined(CONFIG_BF532) || defined(CONFIG_BF531)
+#define L1_SCRATCH_START 0xFFB00000
+#define L1_SCRATCH_LENGTH 0x1000
+#endif
+
+#endif /* _MEM_MAP_533_H_ */
diff --git a/include/asm-blackfin/mach-bf537/anomaly.h b/include/asm-blackfin/mach-bf537/anomaly.h
new file mode 100644
index 00000000000..7f040f5ba01
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/anomaly.h
@@ -0,0 +1,120 @@
+
+/*
+ * File: include/asm-blackfin/mach-bf537/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file shoule be up to date with:
+ * - Revision J, June 1, 2006; ADSP-BF537 Blackfin Processor Anomaly List
+ * - Revision I, June 1, 2006; ADSP-BF536 Blackfin Processor Anomaly List
+ * - Revision J, June 1, 2006; ADSP-BF534 Blackfin Processor Anomaly List
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+
+/* We do not support 0.1 silicon - sorry */
+#if (defined(CONFIG_BF_REV_0_1))
+#error Kernel will not work on BF537/6/4 Version 0.1
+#endif
+
+#if (defined(CONFIG_BF_REV_0_3) || defined(CONFIG_BF_REV_0_2))
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+ slot1 and store of a P register in slot 2 is not
+ supported */
+#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive
+ Channel DMA stops */
+#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR
+ registers. */
+#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out
+ upper bits*/
+#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame
+ syncs */
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+#define ANOMALY_05000247 /* CLKIN Buffer Output Enable Reset Behavior Is
+ Changed */
+#endif
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+ SPORT external receive and transmit clocks. */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+ VDDint <=0.9V */
+#define ANOMALY_05000273 /* Writes to Synchronous SDRAM memory may be lost */
+#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after
+ an edge is detected may clear interrupt */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+ not restored */
+#define ANOMALY_05000282 /* Memory DMA corruption with 32-bit data and traffic
+ control */
+#define ANOMALY_05000283 /* A system MMR write is stalled indefinitely when
+ killed in a particular stage*/
+#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC
+ registers are interrupted */
+#endif
+
+#if defined(CONFIG_BF_REV_0_2)
+#define ANOMALY_05000244 /* With instruction cache enabled, a CSYNC or SSYNC or
+ IDLE around a Change of Control causes
+ unpredictable results */
+#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel
+ (TDM) */
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+#define ANOMALY_05000252 /* EMAC Tx DMA error after an early frame abort */
+#endif
+#define ANOMALY_05000253 /* Maximum external clock speed for Timers */
+#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event
+ interrupt not functional */
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+#define ANOMALY_05000256 /* EMAC MDIO input latched on wrong MDC edge */
+#endif
+#define ANOMALY_05000257 /* An interrupt or exception during short Hardware
+ loops may cause the instruction fetch unit to
+ malfunction */
+#define ANOMALY_05000258 /* Instruction Cache is corrupted when bit 9 and 12 of
+ the ICPLB Data registers differ */
+#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */
+#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */
+#define ANOMALY_05000262 /* Stores to data cache may be lost */
+#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB exception */
+#define ANOMALY_05000264 /* A Sync instruction (CSYNC, SSYNC) or an IDLE
+ instruction will cause an infinite stall in the
+ second to last instruction in a hardware loop */
+#define ANOMALY_05000268 /* Memory DMA error when peripheral DMA is running
+ and non-zero DEB_TRAFFIC_PERIOD value */
+#define ANOMALY_05000270 /* High I/O activity causes the output voltage of the
+ internal voltage regulator (VDDint) to decrease */
+#define ANOMALY_05000277 /* Writes to a flag data register one SCLK cycle after
+ an edge is detected may clear interrupt */
+#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause
+ DMA system instability */
+#define ANOMALY_05000280 /* SPI Master boot mode does not work well with
+ Atmel Dataflash devices */
+
+#endif /* CONFIG_BF_REV_0_2 */
+
+#endif /* _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf537/bf537.h b/include/asm-blackfin/mach-bf537/bf537.h
new file mode 100644
index 00000000000..b8924cd7730
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/bf537.h
@@ -0,0 +1,287 @@
+/*
+ * File: include/asm-blackfin/mach-bf537/bf537.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF537
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MACH_BF537_H__
+#define __MACH_BF537_H__
+
+#define SUPPORTED_REVID 2
+
+/* Masks for generic ERROR IRQ demultiplexing used in int-priority-sc.c */
+
+#define SPI_ERR_MASK (TXCOL | RBSY | MODF | TXE) /* SPI_STAT */
+#define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF) /* SPORTx_STAT */
+#define PPI_ERR_MASK (0xFFFF & ~FLD) /* PPI_STATUS */
+#define EMAC_ERR_MASK (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */
+#define UART_ERR_MASK_STAT1 (0x4) /* UARTx_IIR */
+#define UART_ERR_MASK_STAT0 (0x2) /* UARTx_IIR */
+#define CAN_ERR_MASK (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF) /* CAN_GIF */
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+
+/*some misc defines*/
+#define IMASK_IVG15 0x8000
+#define IMASK_IVG14 0x4000
+#define IMASK_IVG13 0x2000
+#define IMASK_IVG12 0x1000
+
+#define IMASK_IVG11 0x0800
+#define IMASK_IVG10 0x0400
+#define IMASK_IVG9 0x0200
+#define IMASK_IVG8 0x0100
+
+#define IMASK_IVG7 0x0080
+#define IMASK_IVGTMR 0x0040
+#define IMASK_IVGHW 0x0020
+
+/***************************/
+
+
+#define BLKFIN_DSUBBANKS 4
+#define BLKFIN_DWAYS 2
+#define BLKFIN_DLINES 64
+#define BLKFIN_ISUBBANKS 4
+#define BLKFIN_IWAYS 4
+#define BLKFIN_ILINES 32
+
+#define WAY0_L 0x1
+#define WAY1_L 0x2
+#define WAY01_L 0x3
+#define WAY2_L 0x4
+#define WAY02_L 0x5
+#define WAY12_L 0x6
+#define WAY012_L 0x7
+
+#define WAY3_L 0x8
+#define WAY03_L 0x9
+#define WAY13_L 0xA
+#define WAY013_L 0xB
+
+#define WAY32_L 0xC
+#define WAY320_L 0xD
+#define WAY321_L 0xE
+#define WAYALL_L 0xF
+
+#define DMC_ENABLE (2<<2) /*yes, 2, not 1 */
+
+/********************************* EBIU Settings ************************************/
+#define AMBCTL0VAL ((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL ((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#ifdef CONFIG_C_AMBEN_ALL
+#define V_AMBEN AMBEN_ALL
+#endif
+#ifdef CONFIG_C_AMBEN
+#define V_AMBEN 0x0
+#endif
+#ifdef CONFIG_C_AMBEN_B0
+#define V_AMBEN AMBEN_B0
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1
+#define V_AMBEN AMBEN_B0_B1
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1_B2
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL (V_AMBEN | V_AMCKEN | V_CDPRIO)
+
+#define MAX_VC 650000000
+#define MIN_VC 50000000
+
+/********************************PLL Settings **************************************/
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT > 64)
+#error "VCO Multiplier is more than 64. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1)
+#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK
+#endif
+
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF537
+#define CPU "BF537"
+#define CPUID 0x027c8000
+#endif
+#ifdef CONFIG_BF536
+#define CPU "BF536"
+#define CPUID 0x027c8000
+#endif
+#ifdef CONFIG_BF534
+#define CPU "BF534"
+#define CPUID 0x027c6000
+#endif
+#ifndef CPU
+#define CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM mem size must be multible of 4MB"
+#endif
+
+#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND 0x200
+#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else /*Write Through */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#endif
+
+
+#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY )
+#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY )
+
+#define SIZE_1K 0x00000400 /* 1K */
+#define SIZE_4K 0x00001000 /* 4K */
+#define SIZE_1M 0x00100000 /* 1M */
+#define SIZE_4M 0x00400000 /* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 1 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2)
+
+#endif /* __MACH_BF537_H__ */
diff --git a/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
new file mode 100644
index 00000000000..8f5d9c4d8d5
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
@@ -0,0 +1,147 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS 2
+
+#define OFFSET_THR 0x00 /* Transmit Holding register */
+#define OFFSET_RBR 0x00 /* Receive Buffer register */
+#define OFFSET_DLL 0x00 /* Divisor Latch (Low-Byte) */
+#define OFFSET_IER 0x04 /* Interrupt Enable Register */
+#define OFFSET_DLH 0x04 /* Divisor Latch (High-Byte) */
+#define OFFSET_IIR 0x08 /* Interrupt Identification Register */
+#define OFFSET_LCR 0x0C /* Line Control Register */
+#define OFFSET_MCR 0x10 /* Modem Control Register */
+#define OFFSET_LSR 0x14 /* Line Status Register */
+#define OFFSET_MSR 0x18 /* Modem Status Register */
+#define OFFSET_SCR 0x1C /* SCR Scratch Register */
+#define OFFSET_GCTL 0x24 /* Global Control Register */
+
+#define UART_GET_CHAR(uart) bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart) bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart) bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_PUT_IER(uart,v) bfin_write16(((uart)->port.membase + OFFSET_IER),v)
+#define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
+# define CONFIG_SERIAL_BFIN_CTSRTS
+
+# ifndef CONFIG_UART0_CTS_PIN
+# define CONFIG_UART0_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART0_RTS_PIN
+# define CONFIG_UART0_RTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_CTS_PIN
+# define CONFIG_UART1_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_RTS_PIN
+# define CONFIG_UART1_RTS_PIN -1
+# endif
+#endif
+/*
+ * The pin configuration is different from schematic
+ */
+struct bfin_serial_port {
+ struct uart_port port;
+ unsigned int old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ int tx_done;
+ int tx_count;
+ struct circ_buf rx_dma_buf;
+ struct timer_list rx_dma_timer;
+ int rx_dma_nrows;
+ unsigned int tx_dma_channel;
+ unsigned int rx_dma_channel;
+ struct work_struct tx_dma_workqueue;
+#else
+ struct work_struct cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int cts_pin;
+ int rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+ unsigned long uart_base_addr;
+ int uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ unsigned int uart_tx_dma_channel;
+ unsigned int uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int uart_cts_pin;
+ int uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ {
+ 0xFFC00400,
+ IRQ_UART0_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART0_TX,
+ CH_UART0_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+ CONFIG_UART0_CTS_PIN,
+ CONFIG_UART0_RTS_PIN,
+#endif
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+ {
+ 0xFFC02000,
+ IRQ_UART1_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART1_TX,
+ CH_UART1_RX,
+#endif
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+ CONFIG_UART1_CTS_PIN,
+ CONFIG_UART1_RTS_PIN,
+#endif
+ },
+#endif
+};
+
+int nr_ports = ARRAY_SIZE(bfin_serial_resource);
+
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+ unsigned short val;
+ val = bfin_read16(BFIN_PORT_MUX);
+ val &= ~(PFDE | PFTE);
+ bfin_write16(BFIN_PORT_MUX, val);
+
+ val = bfin_read16(PORTF_FER);
+ val |= 0xF;
+ bfin_write16(PORTF_FER, val);
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ if (uart->cts_pin >= 0) {
+ gpio_request(uart->cts_pin, NULL);
+ gpio_direction_input(uart->cts_pin);
+ }
+
+ if (uart->rts_pin >= 0) {
+ gpio_request(uart->rts_pin, NULL);
+ gpio_direction_output(uart->rts_pin);
+ }
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf537/blackfin.h b/include/asm-blackfin/mach-bf537/blackfin.h
new file mode 100644
index 00000000000..bbd97051ec9
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/blackfin.h
@@ -0,0 +1,430 @@
+/*
+ * File: include/asm-blackfin/mach-bf537/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF537_FAMILY
+
+#include "bf537.h"
+#include "mem_map.h"
+#include "defBF534.h"
+#include "anomaly.h"
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+#include "defBF537.h"
+#endif
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#include "cdefBF534.h"
+
+/* UART 0*/
+#define bfin_read_UART_THR() bfin_read_UART0_THR()
+#define bfin_write_UART_THR(val) bfin_write_UART0_THR(val)
+#define bfin_read_UART_RBR() bfin_read_UART0_RBR()
+#define bfin_write_UART_RBR(val) bfin_write_UART0_RBR(val)
+#define bfin_read_UART_DLL() bfin_read_UART0_DLL()
+#define bfin_write_UART_DLL(val) bfin_write_UART0_DLL(val)
+#define bfin_read_UART_IER() bfin_read_UART0_IER()
+#define bfin_write_UART_IER(val) bfin_write_UART0_IER(val)
+#define bfin_read_UART_DLH() bfin_read_UART0_DLH()
+#define bfin_write_UART_DLH(val) bfin_write_UART0_DLH(val)
+#define bfin_read_UART_IIR() bfin_read_UART0_IIR()
+#define bfin_write_UART_IIR(val) bfin_write_UART0_IIR(val)
+#define bfin_read_UART_LCR() bfin_read_UART0_LCR()
+#define bfin_write_UART_LCR(val) bfin_write_UART0_LCR(val)
+#define bfin_read_UART_MCR() bfin_read_UART0_MCR()
+#define bfin_write_UART_MCR(val) bfin_write_UART0_MCR(val)
+#define bfin_read_UART_LSR() bfin_read_UART0_LSR()
+#define bfin_write_UART_LSR(val) bfin_write_UART0_LSR(val)
+#define bfin_read_UART_SCR() bfin_read_UART0_SCR()
+#define bfin_write_UART_SCR(val) bfin_write_UART0_SCR(val)
+#define bfin_read_UART_GCTL() bfin_read_UART0_GCTL()
+#define bfin_write_UART_GCTL(val) bfin_write_UART0_GCTL(val)
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+#include "cdefBF537.h"
+#endif
+#endif
+
+/* MAP used DEFINES from BF533 to BF537 - so we don't need to change them in the driver, kernel, etc. */
+
+/* UART_IIR Register */
+#define STATUS(x) ((x << 1) & 0x06)
+#define STATUS_P1 0x02
+#define STATUS_P0 0x01
+
+/* UART 0*/
+
+/* DMA Channnel */
+#define bfin_read_CH_UART_RX() bfin_read_CH_UART0_RX()
+#define bfin_write_CH_UART_RX(val) bfin_write_CH_UART0_RX(val)
+#define CH_UART_RX CH_UART0_RX
+#define bfin_read_CH_UART_TX() bfin_read_CH_UART0_TX()
+#define bfin_write_CH_UART_TX(val) bfin_write_CH_UART0_TX(val)
+#define CH_UART_TX CH_UART0_TX
+
+/* System Interrupt Controller */
+#define bfin_read_IRQ_UART_RX() bfin_read_IRQ_UART0_RX()
+#define bfin_write_IRQ_UART_RX(val) bfin_write_IRQ_UART0_RX(val)
+#define IRQ_UART_RX IRQ_UART0_RX
+#define bfin_read_IRQ_UART_TX() bfin_read_IRQ_UART0_TX()
+#define bfin_write_IRQ_UART_TX(val) bfin_write_IRQ_UART0_TX(val)
+#define IRQ_UART_TX IRQ_UART0_TX
+#define bfin_read_IRQ_UART_ERROR() bfin_read_IRQ_UART0_ERROR()
+#define bfin_write_IRQ_UART_ERROR(val) bfin_write_IRQ_UART0_ERROR(val)
+#define IRQ_UART_ERROR IRQ_UART0_ERROR
+
+/* MMR Registers*/
+#define bfin_read_UART_THR() bfin_read_UART0_THR()
+#define bfin_write_UART_THR(val) bfin_write_UART0_THR(val)
+#define UART_THR UART0_THR
+#define bfin_read_UART_RBR() bfin_read_UART0_RBR()
+#define bfin_write_UART_RBR(val) bfin_write_UART0_RBR(val)
+#define UART_RBR UART0_RBR
+#define bfin_read_UART_DLL() bfin_read_UART0_DLL()
+#define bfin_write_UART_DLL(val) bfin_write_UART0_DLL(val)
+#define UART_DLL UART0_DLL
+#define bfin_read_UART_IER() bfin_read_UART0_IER()
+#define bfin_write_UART_IER(val) bfin_write_UART0_IER(val)
+#define UART_IER UART0_IER
+#define bfin_read_UART_DLH() bfin_read_UART0_DLH()
+#define bfin_write_UART_DLH(val) bfin_write_UART0_DLH(val)
+#define UART_DLH UART0_DLH
+#define bfin_read_UART_IIR() bfin_read_UART0_IIR()
+#define bfin_write_UART_IIR(val) bfin_write_UART0_IIR(val)
+#define UART_IIR UART0_IIR
+#define bfin_read_UART_LCR() bfin_read_UART0_LCR()
+#define bfin_write_UART_LCR(val) bfin_write_UART0_LCR(val)
+#define UART_LCR UART0_LCR
+#define bfin_read_UART_MCR() bfin_read_UART0_MCR()
+#define bfin_write_UART_MCR(val) bfin_write_UART0_MCR(val)
+#define UART_MCR UART0_MCR
+#define bfin_read_UART_LSR() bfin_read_UART0_LSR()
+#define bfin_write_UART_LSR(val) bfin_write_UART0_LSR(val)
+#define UART_LSR UART0_LSR
+#define bfin_read_UART_SCR() bfin_read_UART0_SCR()
+#define bfin_write_UART_SCR(val) bfin_write_UART0_SCR(val)
+#define UART_SCR UART0_SCR
+#define bfin_read_UART_GCTL() bfin_read_UART0_GCTL()
+#define bfin_write_UART_GCTL(val) bfin_write_UART0_GCTL(val)
+#define UART_GCTL UART0_GCTL
+
+/* DPMC*/
+#define bfin_read_STOPCK_OFF() bfin_read_STOPCK()
+#define bfin_write_STOPCK_OFF(val) bfin_write_STOPCK(val)
+#define STOPCK_OFF STOPCK
+
+/* FIO USE PORT F*/
+#ifdef CONFIG_BF537_PORT_F
+#define bfin_read_PORT_FER() bfin_read_PORTF_FER()
+#define bfin_write_PORT_FER(val) bfin_write_PORTF_FER(val)
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTFIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTFIO(val)
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTFIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTFIO_CLEAR(val)
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTFIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTFIO_SET(val)
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTFIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTFIO_TOGGLE(val)
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTFIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTFIO_MASKA(val)
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTFIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTFIO_MASKA_CLEAR(val)
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTFIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTFIO_MASKA_SET(val)
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTFIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTFIO_MASKA_TOGGLE(val)
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTFIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTFIO_MASKB(val)
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTFIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTFIO_MASKB_CLEAR(val)
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTFIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTFIO_MASKB_SET(val)
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTFIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTFIO_MASKB_TOGGLE(val)
+#define bfin_read_FIO_DIR() bfin_read_PORTFIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTFIO_DIR(val)
+#define bfin_read_FIO_POLAR() bfin_read_PORTFIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTFIO_POLAR(val)
+#define bfin_read_FIO_EDGE() bfin_read_PORTFIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTFIO_EDGE(val)
+#define bfin_read_FIO_BOTH() bfin_read_PORTFIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTFIO_BOTH(val)
+#define bfin_read_FIO_INEN() bfin_read_PORTFIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTFIO_INEN(val)
+
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTFIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTFIO(val)
+#define FIO_FLAG_D PORTFIO
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTFIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTFIO_CLEAR(val)
+#define FIO_FLAG_C PORTFIO_CLEAR
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTFIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTFIO_SET(val)
+#define FIO_FLAG_S PORTFIO_SET
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTFIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTFIO_TOGGLE(val)
+#define FIO_FLAG_T PORTFIO_TOGGLE
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTFIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTFIO_MASKA(val)
+#define FIO_MASKA_D PORTFIO_MASKA
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTFIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTFIO_MASKA_CLEAR(val)
+#define FIO_MASKA_C PORTFIO_MASKA_CLEAR
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTFIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTFIO_MASKA_SET(val)
+#define FIO_MASKA_S PORTFIO_MASKA_SET
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTFIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTFIO_MASKA_TOGGLE(val)
+#define FIO_MASKA_T PORTFIO_MASKA_TOGGLE
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTFIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTFIO_MASKB(val)
+#define FIO_MASKB_D PORTFIO_MASKB
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTFIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTFIO_MASKB_CLEAR(val)
+#define FIO_MASKB_C PORTFIO_MASKB_CLEAR
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTFIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTFIO_MASKB_SET(val)
+#define FIO_MASKB_S PORTFIO_MASKB_SET
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTFIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTFIO_MASKB_TOGGLE(val)
+#define FIO_MASKB_T PORTFIO_MASKB_TOGGLE
+#define bfin_read_FIO_DIR() bfin_read_PORTFIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTFIO_DIR(val)
+#define FIO_DIR PORTFIO_DIR
+#define bfin_read_FIO_POLAR() bfin_read_PORTFIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTFIO_POLAR(val)
+#define FIO_POLAR PORTFIO_POLAR
+#define bfin_read_FIO_EDGE() bfin_read_PORTFIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTFIO_EDGE(val)
+#define FIO_EDGE PORTFIO_EDGE
+#define bfin_read_FIO_BOTH() bfin_read_PORTFIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTFIO_BOTH(val)
+#define FIO_BOTH PORTFIO_BOTH
+#define bfin_read_FIO_INEN() bfin_read_PORTFIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTFIO_INEN(val)
+#define FIO_INEN PORTFIO_INEN
+#endif
+
+/* FIO USE PORT G*/
+#ifdef CONFIG_BF537_PORT_G
+#define bfin_read_PORT_FER() bfin_read_PORTG_FER()
+#define bfin_write_PORT_FER(val) bfin_write_PORTG_FER(val)
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTGIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTGIO(val)
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTGIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTGIO_CLEAR(val)
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTGIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTGIO_SET(val)
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTGIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTGIO_TOGGLE(val)
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTGIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTGIO_MASKA(val)
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTGIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTGIO_MASKA_CLEAR(val)
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTGIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTGIO_MASKA_SET(val)
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTGIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTGIO_MASKA_TOGGLE(val)
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTGIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTGIO_MASKB(val)
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTGIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTGIO_MASKB_CLEAR(val)
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTGIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTGIO_MASKB_SET(val)
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTGIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTGIO_MASKB_TOGGLE(val)
+#define bfin_read_FIO_DIR() bfin_read_PORTGIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTGIO_DIR(val)
+#define bfin_read_FIO_POLAR() bfin_read_PORTGIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTGIO_POLAR(val)
+#define bfin_read_FIO_EDGE() bfin_read_PORTGIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTGIO_EDGE(val)
+#define bfin_read_FIO_BOTH() bfin_read_PORTGIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTGIO_BOTH(val)
+#define bfin_read_FIO_INEN() bfin_read_PORTGIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTGIO_INEN(val)
+
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTGIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTGIO(val)
+#define FIO_FLAG_D PORTGIO
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTGIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTGIO_CLEAR(val)
+#define FIO_FLAG_C PORTGIO_CLEAR
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTGIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTGIO_SET(val)
+#define FIO_FLAG_S PORTGIO_SET
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTGIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTGIO_TOGGLE(val)
+#define FIO_FLAG_T PORTGIO_TOGGLE
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTGIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTGIO_MASKA(val)
+#define FIO_MASKA_D PORTGIO_MASKA
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTGIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTGIO_MASKA_CLEAR(val)
+#define FIO_MASKA_C PORTGIO_MASKA_CLEAR
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTGIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTGIO_MASKA_SET(val)
+#define FIO_MASKA_S PORTGIO_MASKA_SET
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTGIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTGIO_MASKA_TOGGLE(val)
+#define FIO_MASKA_T PORTGIO_MASKA_TOGGLE
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTGIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTGIO_MASKB(val)
+#define FIO_MASKB_D PORTGIO_MASKB
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTGIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTGIO_MASKB_CLEAR(val)
+#define FIO_MASKB_C PORTGIO_MASKB_CLEAR
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTGIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTGIO_MASKB_SET(val)
+#define FIO_MASKB_S PORTGIO_MASKB_SET
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTGIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTGIO_MASKB_TOGGLE(val)
+#define FIO_MASKB_T PORTGIO_MASKB_TOGGLE
+#define bfin_read_FIO_DIR() bfin_read_PORTGIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTGIO_DIR(val)
+#define FIO_DIR PORTGIO_DIR
+#define bfin_read_FIO_POLAR() bfin_read_PORTGIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTGIO_POLAR(val)
+#define FIO_POLAR PORTGIO_POLAR
+#define bfin_read_FIO_EDGE() bfin_read_PORTGIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTGIO_EDGE(val)
+#define FIO_EDGE PORTGIO_EDGE
+#define bfin_read_FIO_BOTH() bfin_read_PORTGIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTGIO_BOTH(val)
+#define FIO_BOTH PORTGIO_BOTH
+#define bfin_read_FIO_INEN() bfin_read_PORTGIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTGIO_INEN(val)
+#define FIO_INEN PORTGIO_INEN
+
+#endif
+
+/* FIO USE PORT H*/
+#ifdef CONFIG_BF537_PORT_H
+#define bfin_read_PORT_FER() bfin_read_PORTH_FER()
+#define bfin_write_PORT_FER(val) bfin_write_PORTH_FER(val)
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTHIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTHIO(val)
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTHIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTHIO_CLEAR(val)
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTHIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTHIO_SET(val)
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTHIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTHIO_TOGGLE(val)
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTHIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTHIO_MASKA(val)
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTHIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTHIO_MASKA_CLEAR(val)
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTHIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTHIO_MASKA_SET(val)
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTHIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTHIO_MASKA_TOGGLE(val)
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTHIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTHIO_MASKB(val)
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTHIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTHIO_MASKB_CLEAR(val)
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTHIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTHIO_MASKB_SET(val)
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTHIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTHIO_MASKB_TOGGLE(val)
+#define bfin_read_FIO_DIR() bfin_read_PORTHIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTHIO_DIR(val)
+#define bfin_read_FIO_POLAR() bfin_read_PORTHIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTHIO_POLAR(val)
+#define bfin_read_FIO_EDGE() bfin_read_PORTHIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTHIO_EDGE(val)
+#define bfin_read_FIO_BOTH() bfin_read_PORTHIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTHIO_BOTH(val)
+#define bfin_read_FIO_INEN() bfin_read_PORTHIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTHIO_INEN(val)
+
+#define bfin_read_FIO_FLAG_D() bfin_read_PORTHIO()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_PORTHIO(val)
+#define FIO_FLAG_D PORTHIO
+#define bfin_read_FIO_FLAG_C() bfin_read_PORTHIO_CLEAR()
+#define bfin_write_FIO_FLAG_C(val) bfin_write_PORTHIO_CLEAR(val)
+#define FIO_FLAG_C PORTHIO_CLEAR
+#define bfin_read_FIO_FLAG_S() bfin_read_PORTHIO_SET()
+#define bfin_write_FIO_FLAG_S(val) bfin_write_PORTHIO_SET(val)
+#define FIO_FLAG_S PORTHIO_SET
+#define bfin_read_FIO_FLAG_T() bfin_read_PORTHIO_TOGGLE()
+#define bfin_write_FIO_FLAG_T(val) bfin_write_PORTHIO_TOGGLE(val)
+#define FIO_FLAG_T PORTHIO_TOGGLE
+#define bfin_read_FIO_MASKA_D() bfin_read_PORTHIO_MASKA()
+#define bfin_write_FIO_MASKA_D(val) bfin_write_PORTHIO_MASKA(val)
+#define FIO_MASKA_D PORTHIO_MASKA
+#define bfin_read_FIO_MASKA_C() bfin_read_PORTHIO_MASKA_CLEAR()
+#define bfin_write_FIO_MASKA_C(val) bfin_write_PORTHIO_MASKA_CLEAR(val)
+#define FIO_MASKA_C PORTHIO_MASKA_CLEAR
+#define bfin_read_FIO_MASKA_S() bfin_read_PORTHIO_MASKA_SET()
+#define bfin_write_FIO_MASKA_S(val) bfin_write_PORTHIO_MASKA_SET(val)
+#define FIO_MASKA_S PORTHIO_MASKA_SET
+#define bfin_read_FIO_MASKA_T() bfin_read_PORTHIO_MASKA_TOGGLE()
+#define bfin_write_FIO_MASKA_T(val) bfin_write_PORTHIO_MASKA_TOGGLE(val)
+#define FIO_MASKA_T PORTHIO_MASKA_TOGGLE
+#define bfin_read_FIO_MASKB_D() bfin_read_PORTHIO_MASKB()
+#define bfin_write_FIO_MASKB_D(val) bfin_write_PORTHIO_MASKB(val)
+#define FIO_MASKB_D PORTHIO_MASKB
+#define bfin_read_FIO_MASKB_C() bfin_read_PORTHIO_MASKB_CLEAR()
+#define bfin_write_FIO_MASKB_C(val) bfin_write_PORTHIO_MASKB_CLEAR(val)
+#define FIO_MASKB_C PORTHIO_MASKB_CLEAR
+#define bfin_read_FIO_MASKB_S() bfin_read_PORTHIO_MASKB_SET()
+#define bfin_write_FIO_MASKB_S(val) bfin_write_PORTHIO_MASKB_SET(val)
+#define FIO_MASKB_S PORTHIO_MASKB_SET
+#define bfin_read_FIO_MASKB_T() bfin_read_PORTHIO_MASKB_TOGGLE()
+#define bfin_write_FIO_MASKB_T(val) bfin_write_PORTHIO_MASKB_TOGGLE(val)
+#define FIO_MASKB_T PORTHIO_MASKB_TOGGLE
+#define bfin_read_FIO_DIR() bfin_read_PORTHIO_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_PORTHIO_DIR(val)
+#define FIO_DIR PORTHIO_DIR
+#define bfin_read_FIO_POLAR() bfin_read_PORTHIO_POLAR()
+#define bfin_write_FIO_POLAR(val) bfin_write_PORTHIO_POLAR(val)
+#define FIO_POLAR PORTHIO_POLAR
+#define bfin_read_FIO_EDGE() bfin_read_PORTHIO_EDGE()
+#define bfin_write_FIO_EDGE(val) bfin_write_PORTHIO_EDGE(val)
+#define FIO_EDGE PORTHIO_EDGE
+#define bfin_read_FIO_BOTH() bfin_read_PORTHIO_BOTH()
+#define bfin_write_FIO_BOTH(val) bfin_write_PORTHIO_BOTH(val)
+#define FIO_BOTH PORTHIO_BOTH
+#define bfin_read_FIO_INEN() bfin_read_PORTHIO_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_PORTHIO_INEN(val)
+#define FIO_INEN PORTHIO_INEN
+
+#endif
+
+/* PLL_DIV Masks */
+#define CCLK_DIV1 CSEL_DIV1 /* CCLK = VCO / 1 */
+#define CCLK_DIV2 CSEL_DIV2 /* CCLK = VCO / 2 */
+#define CCLK_DIV4 CSEL_DIV4 /* CCLK = VCO / 4 */
+#define CCLK_DIV8 CSEL_DIV8 /* CCLK = VCO / 8 */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf537/cdefBF534.h b/include/asm-blackfin/mach-bf537/cdefBF534.h
new file mode 100644
index 00000000000..7b658c175f8
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/cdefBF534.h
@@ -0,0 +1,1823 @@
+/*
+ * File: include/asm-blackfin/mach-bf537/cdefbf534.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: system mmr register map
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF534_H
+#define _CDEF_BF534_H
+
+/* Include all Core registers and bit definitions */
+#include "defBF534.h"
+
+/* Include core specific register pointer definitions */
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+#include <asm/system.h>
+
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
+#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL,val)
+#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
+#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV,val)
+#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+ unsigned long flags, iwr;
+
+ bfin_write16(VR_CTL, val);
+ __builtin_bfin_ssync();
+ /* Enable the PLL Wakeup bit in SIC IWR */
+ iwr = bfin_read32(SIC_IWR);
+ /* Only allow PPL Wakeup) */
+ bfin_write32(SIC_IWR, IWR_ENABLE(0));
+ local_irq_save(flags);
+ asm("IDLE;");
+ local_irq_restore(flags);
+ bfin_write32(SIC_IWR, iwr);
+}
+#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
+#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
+#define bfin_read_PLL_LOCKCNT() bfin_read16(PLL_LOCKCNT)
+#define bfin_write_PLL_LOCKCNT(val) bfin_write16(PLL_LOCKCNT,val)
+#define bfin_read_CHIPID() bfin_read32(CHIPID)
+
+/* System Interrupt Controller (0xFFC00100 - 0xFFC001FF) */
+#define bfin_read_SWRST() bfin_read16(SWRST)
+#define bfin_write_SWRST(val) bfin_write16(SWRST,val)
+#define bfin_read_SYSCR() bfin_read16(SYSCR)
+#define bfin_write_SYSCR(val) bfin_write16(SYSCR,val)
+#define pSIC_RVECT ((void * volatile *)SIC_RVECT)
+#define bfin_read_SIC_RVECT() bfin_read32(SIC_RVECT)
+#define bfin_write_SIC_RVECT(val) bfin_write32(SIC_RVECT,val)
+#define bfin_read_SIC_IMASK() bfin_read32(SIC_IMASK)
+#define bfin_write_SIC_IMASK(val) bfin_write32(SIC_IMASK,val)
+#define bfin_read_SIC_IAR0() bfin_read32(SIC_IAR0)
+#define bfin_write_SIC_IAR0(val) bfin_write32(SIC_IAR0,val)
+#define bfin_read_SIC_IAR1() bfin_read32(SIC_IAR1)
+#define bfin_write_SIC_IAR1(val) bfin_write32(SIC_IAR1,val)
+#define bfin_read_SIC_IAR2() bfin_read32(SIC_IAR2)
+#define bfin_write_SIC_IAR2(val) bfin_write32(SIC_IAR2,val)
+#define bfin_read_SIC_IAR3() bfin_read32(SIC_IAR3)
+#define bfin_write_SIC_IAR3(val) bfin_write32(SIC_IAR3,val)
+#define bfin_read_SIC_ISR() bfin_read32(SIC_ISR)
+#define bfin_write_SIC_ISR(val) bfin_write32(SIC_ISR,val)
+#define bfin_read_SIC_IWR() bfin_read32(SIC_IWR)
+#define bfin_write_SIC_IWR(val) bfin_write32(SIC_IWR,val)
+
+/* Watchdog Timer (0xFFC00200 - 0xFFC002FF) */
+#define bfin_read_WDOG_CTL() bfin_read16(WDOG_CTL)
+#define bfin_write_WDOG_CTL(val) bfin_write16(WDOG_CTL,val)
+#define bfin_read_WDOG_CNT() bfin_read32(WDOG_CNT)
+#define bfin_write_WDOG_CNT(val) bfin_write32(WDOG_CNT,val)
+#define bfin_read_WDOG_STAT() bfin_read32(WDOG_STAT)
+#define bfin_write_WDOG_STAT(val) bfin_write32(WDOG_STAT,val)
+
+/* Real Time Clock (0xFFC00300 - 0xFFC003FF) */
+#define bfin_read_RTC_STAT() bfin_read32(RTC_STAT)
+#define bfin_write_RTC_STAT(val) bfin_write32(RTC_STAT,val)
+#define bfin_read_RTC_ICTL() bfin_read16(RTC_ICTL)
+#define bfin_write_RTC_ICTL(val) bfin_write16(RTC_ICTL,val)
+#define bfin_read_RTC_ISTAT() bfin_read16(RTC_ISTAT)
+#define bfin_write_RTC_ISTAT(val) bfin_write16(RTC_ISTAT,val)
+#define bfin_read_RTC_SWCNT() bfin_read16(RTC_SWCNT)
+#define bfin_write_RTC_SWCNT(val) bfin_write16(RTC_SWCNT,val)
+#define bfin_read_RTC_ALARM() bfin_read32(RTC_ALARM)
+#define bfin_write_RTC_ALARM(val) bfin_write32(RTC_ALARM,val)
+#define bfin_read_RTC_FAST() bfin_read16(RTC_FAST)
+#define bfin_write_RTC_FAST(val) bfin_write16(RTC_FAST,val)
+#define bfin_read_RTC_PREN() bfin_read16(RTC_PREN)
+#define bfin_write_RTC_PREN(val) bfin_write16(RTC_PREN,val)
+
+/* UART0 Controller (0xFFC00400 - 0xFFC004FF) */
+#define bfin_read_UART0_THR() bfin_read16(UART0_THR)
+#define bfin_write_UART0_THR(val) bfin_write16(UART0_THR,val)
+#define bfin_read_UART0_RBR() bfin_read16(UART0_RBR)
+#define bfin_write_UART0_RBR(val) bfin_write16(UART0_RBR,val)
+#define bfin_read_UART0_DLL() bfin_read16(UART0_DLL)
+#define bfin_write_UART0_DLL(val) bfin_write16(UART0_DLL,val)
+#define bfin_read_UART0_IER() bfin_read16(UART0_IER)
+#define bfin_write_UART0_IER(val) bfin_write16(UART0_IER,val)
+#define bfin_read_UART0_DLH() bfin_read16(UART0_DLH)
+#define bfin_write_UART0_DLH(val) bfin_write16(UART0_DLH,val)
+#define bfin_read_UART0_IIR() bfin_read16(UART0_IIR)
+#define bfin_write_UART0_IIR(val) bfin_write16(UART0_IIR,val)
+#define bfin_read_UART0_LCR() bfin_read16(UART0_LCR)
+#define bfin_write_UART0_LCR(val) bfin_write16(UART0_LCR,val)
+#define bfin_read_UART0_MCR() bfin_read16(UART0_MCR)
+#define bfin_write_UART0_MCR(val) bfin_write16(UART0_MCR,val)
+#define bfin_read_UART0_LSR() bfin_read16(UART0_LSR)
+#define bfin_write_UART0_LSR(val) bfin_write16(UART0_LSR,val)
+#define bfin_read_UART0_MSR() bfin_read16(UART0_MSR)
+#define bfin_write_UART0_MSR(val) bfin_write16(UART0_MSR,val)
+#define bfin_read_UART0_SCR() bfin_read16(UART0_SCR)
+#define bfin_write_UART0_SCR(val) bfin_write16(UART0_SCR,val)
+#define bfin_read_UART0_GCTL() bfin_read16(UART0_GCTL)
+#define bfin_write_UART0_GCTL(val) bfin_write16(UART0_GCTL,val)
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define bfin_read_SPI_CTL() bfin_read16(SPI_CTL)
+#define bfin_write_SPI_CTL(val) bfin_write16(SPI_CTL,val)
+#define bfin_read_SPI_FLG() bfin_read16(SPI_FLG)
+#define bfin_write_SPI_FLG(val) bfin_write16(SPI_FLG,val)
+#define bfin_read_SPI_STAT() bfin_read16(SPI_STAT)
+#define bfin_write_SPI_STAT(val) bfin_write16(SPI_STAT,val)
+#define bfin_read_SPI_TDBR() bfin_read16(SPI_TDBR)
+#define bfin_write_SPI_TDBR(val) bfin_write16(SPI_TDBR,val)
+#define bfin_read_SPI_RDBR() bfin_read16(SPI_RDBR)
+#define bfin_write_SPI_RDBR(val) bfin_write16(SPI_RDBR,val)
+#define bfin_read_SPI_BAUD() bfin_read16(SPI_BAUD)
+#define bfin_write_SPI_BAUD(val) bfin_write16(SPI_BAUD,val)
+#define bfin_read_SPI_SHADOW() bfin_read16(SPI_SHADOW)
+#define bfin_write_SPI_SHADOW(val) bfin_write16(SPI_SHADOW,val)
+
+/* TIMER0-7 Registers (0xFFC00600 - 0xFFC006FF) */
+#define bfin_read_TIMER0_CONFIG() bfin_read16(TIMER0_CONFIG)
+#define bfin_write_TIMER0_CONFIG(val) bfin_write16(TIMER0_CONFIG,val)
+#define bfin_read_TIMER0_COUNTER() bfin_read32(TIMER0_COUNTER)
+#define bfin_write_TIMER0_COUNTER(val) bfin_write32(TIMER0_COUNTER,val)
+#define bfin_read_TIMER0_PERIOD() bfin_read32(TIMER0_PERIOD)
+#define bfin_write_TIMER0_PERIOD(val) bfin_write32(TIMER0_PERIOD,val)
+#define bfin_read_TIMER0_WIDTH() bfin_read32(TIMER0_WIDTH)
+#define bfin_write_TIMER0_WIDTH(val) bfin_write32(TIMER0_WIDTH,val)
+
+#define bfin_read_TIMER1_CONFIG() bfin_read16(TIMER1_CONFIG)
+#define bfin_write_TIMER1_CONFIG(val) bfin_write16(TIMER1_CONFIG,val)
+#define bfin_read_TIMER1_COUNTER() bfin_read32(TIMER1_COUNTER)
+#define bfin_write_TIMER1_COUNTER(val) bfin_write32(TIMER1_COUNTER,val)
+#define bfin_read_TIMER1_PERIOD() bfin_read32(TIMER1_PERIOD)
+#define bfin_write_TIMER1_PERIOD(val) bfin_write32(TIMER1_PERIOD,val)
+#define bfin_read_TIMER1_WIDTH() bfin_read32(TIMER1_WIDTH)
+#define bfin_write_TIMER1_WIDTH(val) bfin_write32(TIMER1_WIDTH,val)
+
+#define bfin_read_TIMER2_CONFIG() bfin_read16(TIMER2_CONFIG)
+#define bfin_write_TIMER2_CONFIG(val) bfin_write16(TIMER2_CONFIG,val)
+#define bfin_read_TIMER2_COUNTER() bfin_read32(TIMER2_COUNTER)
+#define bfin_write_TIMER2_COUNTER(val) bfin_write32(TIMER2_COUNTER,val)
+#define bfin_read_TIMER2_PERIOD() bfin_read32(TIMER2_PERIOD)
+#define bfin_write_TIMER2_PERIOD(val) bfin_write32(TIMER2_PERIOD,val)
+#define bfin_read_TIMER2_WIDTH() bfin_read32(TIMER2_WIDTH)
+#define bfin_write_TIMER2_WIDTH(val) bfin_write32(TIMER2_WIDTH,val)
+
+#define bfin_read_TIMER3_CONFIG() bfin_read16(TIMER3_CONFIG)
+#define bfin_write_TIMER3_CONFIG(val) bfin_write16(TIMER3_CONFIG,val)
+#define bfin_read_TIMER3_COUNTER() bfin_read32(TIMER3_COUNTER)
+#define bfin_write_TIMER3_COUNTER(val) bfin_write32(TIMER3_COUNTER,val)
+#define bfin_read_TIMER3_PERIOD() bfin_read32(TIMER3_PERIOD)
+#define bfin_write_TIMER3_PERIOD(val) bfin_write32(TIMER3_PERIOD,val)
+#define bfin_read_TIMER3_WIDTH() bfin_read32(TIMER3_WIDTH)
+#define bfin_write_TIMER3_WIDTH(val) bfin_write32(TIMER3_WIDTH,val)
+
+#define bfin_read_TIMER4_CONFIG() bfin_read16(TIMER4_CONFIG)
+#define bfin_write_TIMER4_CONFIG(val) bfin_write16(TIMER4_CONFIG,val)
+#define bfin_read_TIMER4_COUNTER() bfin_read32(TIMER4_COUNTER)
+#define bfin_write_TIMER4_COUNTER(val) bfin_write32(TIMER4_COUNTER,val)
+#define bfin_read_TIMER4_PERIOD() bfin_read32(TIMER4_PERIOD)
+#define bfin_write_TIMER4_PERIOD(val) bfin_write32(TIMER4_PERIOD,val)
+#define bfin_read_TIMER4_WIDTH() bfin_read32(TIMER4_WIDTH)
+#define bfin_write_TIMER4_WIDTH(val) bfin_write32(TIMER4_WIDTH,val)
+
+#define bfin_read_TIMER5_CONFIG() bfin_read16(TIMER5_CONFIG)
+#define bfin_write_TIMER5_CONFIG(val) bfin_write16(TIMER5_CONFIG,val)
+#define bfin_read_TIMER5_COUNTER() bfin_read32(TIMER5_COUNTER)
+#define bfin_write_TIMER5_COUNTER(val) bfin_write32(TIMER5_COUNTER,val)
+#define bfin_read_TIMER5_PERIOD() bfin_read32(TIMER5_PERIOD)
+#define bfin_write_TIMER5_PERIOD(val) bfin_write32(TIMER5_PERIOD,val)
+#define bfin_read_TIMER5_WIDTH() bfin_read32(TIMER5_WIDTH)
+#define bfin_write_TIMER5_WIDTH(val) bfin_write32(TIMER5_WIDTH,val)
+
+#define bfin_read_TIMER6_CONFIG() bfin_read16(TIMER6_CONFIG)
+#define bfin_write_TIMER6_CONFIG(val) bfin_write16(TIMER6_CONFIG,val)
+#define bfin_read_TIMER6_COUNTER() bfin_read32(TIMER6_COUNTER)
+#define bfin_write_TIMER6_COUNTER(val) bfin_write32(TIMER6_COUNTER,val)
+#define bfin_read_TIMER6_PERIOD() bfin_read32(TIMER6_PERIOD)
+#define bfin_write_TIMER6_PERIOD(val) bfin_write32(TIMER6_PERIOD,val)
+#define bfin_read_TIMER6_WIDTH() bfin_read32(TIMER6_WIDTH)
+#define bfin_write_TIMER6_WIDTH(val) bfin_write32(TIMER6_WIDTH,val)
+
+#define bfin_read_TIMER7_CONFIG() bfin_read16(TIMER7_CONFIG)
+#define bfin_write_TIMER7_CONFIG(val) bfin_write16(TIMER7_CONFIG,val)
+#define bfin_read_TIMER7_COUNTER() bfin_read32(TIMER7_COUNTER)
+#define bfin_write_TIMER7_COUNTER(val) bfin_write32(TIMER7_COUNTER,val)
+#define bfin_read_TIMER7_PERIOD() bfin_read32(TIMER7_PERIOD)
+#define bfin_write_TIMER7_PERIOD(val) bfin_write32(TIMER7_PERIOD,val)
+#define bfin_read_TIMER7_WIDTH() bfin_read32(TIMER7_WIDTH)
+#define bfin_write_TIMER7_WIDTH(val) bfin_write32(TIMER7_WIDTH,val)
+
+#define bfin_read_TIMER_ENABLE() bfin_read16(TIMER_ENABLE)
+#define bfin_write_TIMER_ENABLE(val) bfin_write16(TIMER_ENABLE,val)
+#define bfin_read_TIMER_DISABLE() bfin_read16(TIMER_DISABLE)
+#define bfin_write_TIMER_DISABLE(val) bfin_write16(TIMER_DISABLE,val)
+#define bfin_read_TIMER_STATUS() bfin_read32(TIMER_STATUS)
+#define bfin_write_TIMER_STATUS(val) bfin_write32(TIMER_STATUS,val)
+
+/* General Purpose I/O Port F (0xFFC00700 - 0xFFC007FF) */
+#define bfin_read_PORTFIO() bfin_read16(PORTFIO)
+#define bfin_write_PORTFIO(val) bfin_write16(PORTFIO,val)
+#define bfin_read_PORTFIO_CLEAR() bfin_read16(PORTFIO_CLEAR)
+#define bfin_write_PORTFIO_CLEAR(val) bfin_write16(PORTFIO_CLEAR,val)
+#define bfin_read_PORTFIO_SET() bfin_read16(PORTFIO_SET)
+#define bfin_write_PORTFIO_SET(val) bfin_write16(PORTFIO_SET,val)
+#define bfin_read_PORTFIO_TOGGLE() bfin_read16(PORTFIO_TOGGLE)
+#define bfin_write_PORTFIO_TOGGLE(val) bfin_write16(PORTFIO_TOGGLE,val)
+#define bfin_read_PORTFIO_MASKA() bfin_read16(PORTFIO_MASKA)
+#define bfin_write_PORTFIO_MASKA(val) bfin_write16(PORTFIO_MASKA,val)
+#define bfin_read_PORTFIO_MASKA_CLEAR() bfin_read16(PORTFIO_MASKA_CLEAR)
+#define bfin_write_PORTFIO_MASKA_CLEAR(val) bfin_write16(PORTFIO_MASKA_CLEAR,val)
+#define bfin_read_PORTFIO_MASKA_SET() bfin_read16(PORTFIO_MASKA_SET)
+#define bfin_write_PORTFIO_MASKA_SET(val) bfin_write16(PORTFIO_MASKA_SET,val)
+#define bfin_read_PORTFIO_MASKA_TOGGLE() bfin_read16(PORTFIO_MASKA_TOGGLE)
+#define bfin_write_PORTFIO_MASKA_TOGGLE(val) bfin_write16(PORTFIO_MASKA_TOGGLE,val)
+#define bfin_read_PORTFIO_MASKB() bfin_read16(PORTFIO_MASKB)
+#define bfin_write_PORTFIO_MASKB(val) bfin_write16(PORTFIO_MASKB,val)
+#define bfin_read_PORTFIO_MASKB_CLEAR() bfin_read16(PORTFIO_MASKB_CLEAR)
+#define bfin_write_PORTFIO_MASKB_CLEAR(val) bfin_write16(PORTFIO_MASKB_CLEAR,val)
+#define bfin_read_PORTFIO_MASKB_SET() bfin_read16(PORTFIO_MASKB_SET)
+#define bfin_write_PORTFIO_MASKB_SET(val) bfin_write16(PORTFIO_MASKB_SET,val)
+#define bfin_read_PORTFIO_MASKB_TOGGLE() bfin_read16(PORTFIO_MASKB_TOGGLE)
+#define bfin_write_PORTFIO_MASKB_TOGGLE(val) bfin_write16(PORTFIO_MASKB_TOGGLE,val)
+#define bfin_read_PORTFIO_DIR() bfin_read16(PORTFIO_DIR)
+#define bfin_write_PORTFIO_DIR(val) bfin_write16(PORTFIO_DIR,val)
+#define bfin_read_PORTFIO_POLAR() bfin_read16(PORTFIO_POLAR)
+#define bfin_write_PORTFIO_POLAR(val) bfin_write16(PORTFIO_POLAR,val)
+#define bfin_read_PORTFIO_EDGE() bfin_read16(PORTFIO_EDGE)
+#define bfin_write_PORTFIO_EDGE(val) bfin_write16(PORTFIO_EDGE,val)
+#define bfin_read_PORTFIO_BOTH() bfin_read16(PORTFIO_BOTH)
+#define bfin_write_PORTFIO_BOTH(val) bfin_write16(PORTFIO_BOTH,val)
+#define bfin_read_PORTFIO_INEN() bfin_read16(PORTFIO_INEN)
+#define bfin_write_PORTFIO_INEN(val) bfin_write16(PORTFIO_INEN,val)
+
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define bfin_read_SPORT0_TCR1() bfin_read16(SPORT0_TCR1)
+#define bfin_write_SPORT0_TCR1(val) bfin_write16(SPORT0_TCR1,val)
+#define bfin_read_SPORT0_TCR2() bfin_read16(SPORT0_TCR2)
+#define bfin_write_SPORT0_TCR2(val) bfin_write16(SPORT0_TCR2,val)
+#define bfin_read_SPORT0_TCLKDIV() bfin_read16(SPORT0_TCLKDIV)
+#define bfin_write_SPORT0_TCLKDIV(val) bfin_write16(SPORT0_TCLKDIV,val)
+#define bfin_read_SPORT0_TFSDIV() bfin_read16(SPORT0_TFSDIV)
+#define bfin_write_SPORT0_TFSDIV(val) bfin_write16(SPORT0_TFSDIV,val)
+#define bfin_read_SPORT0_TX() bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX(val) bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX() bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX(val) bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX32() bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val) bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX32() bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val) bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX16() bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val) bfin_write16(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX16() bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val) bfin_write16(SPORT0_RX,val)
+#define bfin_read_SPORT0_RCR1() bfin_read16(SPORT0_RCR1)
+#define bfin_write_SPORT0_RCR1(val) bfin_write16(SPORT0_RCR1,val)
+#define bfin_read_SPORT0_RCR2() bfin_read16(SPORT0_RCR2)
+#define bfin_write_SPORT0_RCR2(val) bfin_write16(SPORT0_RCR2,val)
+#define bfin_read_SPORT0_RCLKDIV() bfin_read16(SPORT0_RCLKDIV)
+#define bfin_write_SPORT0_RCLKDIV(val) bfin_write16(SPORT0_RCLKDIV,val)
+#define bfin_read_SPORT0_RFSDIV() bfin_read16(SPORT0_RFSDIV)
+#define bfin_write_SPORT0_RFSDIV(val) bfin_write16(SPORT0_RFSDIV,val)
+#define bfin_read_SPORT0_STAT() bfin_read16(SPORT0_STAT)
+#define bfin_write_SPORT0_STAT(val) bfin_write16(SPORT0_STAT,val)
+#define bfin_read_SPORT0_CHNL() bfin_read16(SPORT0_CHNL)
+#define bfin_write_SPORT0_CHNL(val) bfin_write16(SPORT0_CHNL,val)
+#define bfin_read_SPORT0_MCMC1() bfin_read16(SPORT0_MCMC1)
+#define bfin_write_SPORT0_MCMC1(val) bfin_write16(SPORT0_MCMC1,val)
+#define bfin_read_SPORT0_MCMC2() bfin_read16(SPORT0_MCMC2)
+#define bfin_write_SPORT0_MCMC2(val) bfin_write16(SPORT0_MCMC2,val)
+#define bfin_read_SPORT0_MTCS0() bfin_read32(SPORT0_MTCS0)
+#define bfin_write_SPORT0_MTCS0(val) bfin_write32(SPORT0_MTCS0,val)
+#define bfin_read_SPORT0_MTCS1() bfin_read32(SPORT0_MTCS1)
+#define bfin_write_SPORT0_MTCS1(val) bfin_write32(SPORT0_MTCS1,val)
+#define bfin_read_SPORT0_MTCS2() bfin_read32(SPORT0_MTCS2)
+#define bfin_write_SPORT0_MTCS2(val) bfin_write32(SPORT0_MTCS2,val)
+#define bfin_read_SPORT0_MTCS3() bfin_read32(SPORT0_MTCS3)
+#define bfin_write_SPORT0_MTCS3(val) bfin_write32(SPORT0_MTCS3,val)
+#define bfin_read_SPORT0_MRCS0() bfin_read32(SPORT0_MRCS0)
+#define bfin_write_SPORT0_MRCS0(val) bfin_write32(SPORT0_MRCS0,val)
+#define bfin_read_SPORT0_MRCS1() bfin_read32(SPORT0_MRCS1)
+#define bfin_write_SPORT0_MRCS1(val) bfin_write32(SPORT0_MRCS1,val)
+#define bfin_read_SPORT0_MRCS2() bfin_read32(SPORT0_MRCS2)
+#define bfin_write_SPORT0_MRCS2(val) bfin_write32(SPORT0_MRCS2,val)
+#define bfin_read_SPORT0_MRCS3() bfin_read32(SPORT0_MRCS3)
+#define bfin_write_SPORT0_MRCS3(val) bfin_write32(SPORT0_MRCS3,val)
+
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define bfin_read_SPORT1_TCR1() bfin_read16(SPORT1_TCR1)
+#define bfin_write_SPORT1_TCR1(val) bfin_write16(SPORT1_TCR1,val)
+#define bfin_read_SPORT1_TCR2() bfin_read16(SPORT1_TCR2)
+#define bfin_write_SPORT1_TCR2(val) bfin_write16(SPORT1_TCR2,val)
+#define bfin_read_SPORT1_TCLKDIV() bfin_read16(SPORT1_TCLKDIV)
+#define bfin_write_SPORT1_TCLKDIV(val) bfin_write16(SPORT1_TCLKDIV,val)
+#define bfin_read_SPORT1_TFSDIV() bfin_read16(SPORT1_TFSDIV)
+#define bfin_write_SPORT1_TFSDIV(val) bfin_write16(SPORT1_TFSDIV,val)
+#define bfin_read_SPORT1_TX() bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX(val) bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX() bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX(val) bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX32() bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val) bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX32() bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val) bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX16() bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val) bfin_write16(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX16() bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val) bfin_write16(SPORT1_RX,val)
+#define bfin_read_SPORT1_RCR1() bfin_read16(SPORT1_RCR1)
+#define bfin_write_SPORT1_RCR1(val) bfin_write16(SPORT1_RCR1,val)
+#define bfin_read_SPORT1_RCR2() bfin_read16(SPORT1_RCR2)
+#define bfin_write_SPORT1_RCR2(val) bfin_write16(SPORT1_RCR2,val)
+#define bfin_read_SPORT1_RCLKDIV() bfin_read16(SPORT1_RCLKDIV)
+#define bfin_write_SPORT1_RCLKDIV(val) bfin_write16(SPORT1_RCLKDIV,val)
+#define bfin_read_SPORT1_RFSDIV() bfin_read16(SPORT1_RFSDIV)
+#define bfin_write_SPORT1_RFSDIV(val) bfin_write16(SPORT1_RFSDIV,val)
+#define bfin_read_SPORT1_STAT() bfin_read16(SPORT1_STAT)
+#define bfin_write_SPORT1_STAT(val) bfin_write16(SPORT1_STAT,val)
+#define bfin_read_SPORT1_CHNL() bfin_read16(SPORT1_CHNL)
+#define bfin_write_SPORT1_CHNL(val) bfin_write16(SPORT1_CHNL,val)
+#define bfin_read_SPORT1_MCMC1() bfin_read16(SPORT1_MCMC1)
+#define bfin_write_SPORT1_MCMC1(val) bfin_write16(SPORT1_MCMC1,val)
+#define bfin_read_SPORT1_MCMC2() bfin_read16(SPORT1_MCMC2)
+#define bfin_write_SPORT1_MCMC2(val) bfin_write16(SPORT1_MCMC2,val)
+#define bfin_read_SPORT1_MTCS0() bfin_read32(SPORT1_MTCS0)
+#define bfin_write_SPORT1_MTCS0(val) bfin_write32(SPORT1_MTCS0,val)
+#define bfin_read_SPORT1_MTCS1() bfin_read32(SPORT1_MTCS1)
+#define bfin_write_SPORT1_MTCS1(val) bfin_write32(SPORT1_MTCS1,val)
+#define bfin_read_SPORT1_MTCS2() bfin_read32(SPORT1_MTCS2)
+#define bfin_write_SPORT1_MTCS2(val) bfin_write32(SPORT1_MTCS2,val)
+#define bfin_read_SPORT1_MTCS3() bfin_read32(SPORT1_MTCS3)
+#define bfin_write_SPORT1_MTCS3(val) bfin_write32(SPORT1_MTCS3,val)
+#define bfin_read_SPORT1_MRCS0() bfin_read32(SPORT1_MRCS0)
+#define bfin_write_SPORT1_MRCS0(val) bfin_write32(SPORT1_MRCS0,val)
+#define bfin_read_SPORT1_MRCS1() bfin_read32(SPORT1_MRCS1)
+#define bfin_write_SPORT1_MRCS1(val) bfin_write32(SPORT1_MRCS1,val)
+#define bfin_read_SPORT1_MRCS2() bfin_read32(SPORT1_MRCS2)
+#define bfin_write_SPORT1_MRCS2(val) bfin_write32(SPORT1_MRCS2,val)
+#define bfin_read_SPORT1_MRCS3() bfin_read32(SPORT1_MRCS3)
+#define bfin_write_SPORT1_MRCS3(val) bfin_write32(SPORT1_MRCS3,val)
+
+/* External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+#define bfin_read_EBIU_AMGCTL() bfin_read16(EBIU_AMGCTL)
+#define bfin_write_EBIU_AMGCTL(val) bfin_write16(EBIU_AMGCTL,val)
+#define bfin_read_EBIU_AMBCTL0() bfin_read32(EBIU_AMBCTL0)
+#define bfin_write_EBIU_AMBCTL0(val) bfin_write32(EBIU_AMBCTL0,val)
+#define bfin_read_EBIU_AMBCTL1() bfin_read32(EBIU_AMBCTL1)
+#define bfin_write_EBIU_AMBCTL1(val) bfin_write32(EBIU_AMBCTL1,val)
+#define bfin_read_EBIU_SDGCTL() bfin_read32(EBIU_SDGCTL)
+#define bfin_write_EBIU_SDGCTL(val) bfin_write32(EBIU_SDGCTL,val)
+#define bfin_read_EBIU_SDBCTL() bfin_read16(EBIU_SDBCTL)
+#define bfin_write_EBIU_SDBCTL(val) bfin_write16(EBIU_SDBCTL,val)
+#define bfin_read_EBIU_SDRRC() bfin_read16(EBIU_SDRRC)
+#define bfin_write_EBIU_SDRRC(val) bfin_write16(EBIU_SDRRC,val)
+#define bfin_read_EBIU_SDSTAT() bfin_read16(EBIU_SDSTAT)
+#define bfin_write_EBIU_SDSTAT(val) bfin_write16(EBIU_SDSTAT,val)
+
+/* DMA Traffic Control Registers */
+#define pDMA_TCPER ((volatile unsigned short *)DMA_TCPER)
+#define bfin_read_DMA_TCPER() bfin_read16(DMA_TCPER)
+#define bfin_write_DMA_TCPER(val) bfin_write16(DMA_TCPER,val)
+#define pDMA_TCCNT ((volatile unsigned short *)DMA_TCCNT)
+#define bfin_read_DMA_TCCNT() bfin_read16(DMA_TCCNT)
+#define bfin_write_DMA_TCCNT(val) bfin_write16(DMA_TCCNT,val)
+
+/* DMA Controller */
+#define bfin_read_DMA0_CONFIG() bfin_read16(DMA0_CONFIG)
+#define bfin_write_DMA0_CONFIG(val) bfin_write16(DMA0_CONFIG,val)
+#define bfin_read_DMA0_NEXT_DESC_PTR() bfin_read32(DMA0_NEXT_DESC_PTR)
+#define bfin_write_DMA0_NEXT_DESC_PTR(val) bfin_write32(DMA0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA0_START_ADDR() bfin_read32(DMA0_START_ADDR)
+#define bfin_write_DMA0_START_ADDR(val) bfin_write32(DMA0_START_ADDR,val)
+#define bfin_read_DMA0_X_COUNT() bfin_read16(DMA0_X_COUNT)
+#define bfin_write_DMA0_X_COUNT(val) bfin_write16(DMA0_X_COUNT,val)
+#define bfin_read_DMA0_Y_COUNT() bfin_read16(DMA0_Y_COUNT)
+#define bfin_write_DMA0_Y_COUNT(val) bfin_write16(DMA0_Y_COUNT,val)
+#define bfin_read_DMA0_X_MODIFY() bfin_read16(DMA0_X_MODIFY)
+#define bfin_write_DMA0_X_MODIFY(val) bfin_write16(DMA0_X_MODIFY,val)
+#define bfin_read_DMA0_Y_MODIFY() bfin_read16(DMA0_Y_MODIFY)
+#define bfin_write_DMA0_Y_MODIFY(val) bfin_write16(DMA0_Y_MODIFY,val)
+#define bfin_read_DMA0_CURR_DESC_PTR() bfin_read32(DMA0_CURR_DESC_PTR)
+#define bfin_write_DMA0_CURR_DESC_PTR(val) bfin_write32(DMA0_CURR_DESC_PTR,val)
+#define bfin_read_DMA0_CURR_ADDR() bfin_read32(DMA0_CURR_ADDR)
+#define bfin_write_DMA0_CURR_ADDR(val) bfin_write32(DMA0_CURR_ADDR,val)
+#define bfin_read_DMA0_CURR_X_COUNT() bfin_read16(DMA0_CURR_X_COUNT)
+#define bfin_write_DMA0_CURR_X_COUNT(val) bfin_write16(DMA0_CURR_X_COUNT,val)
+#define bfin_read_DMA0_CURR_Y_COUNT() bfin_read16(DMA0_CURR_Y_COUNT)
+#define bfin_write_DMA0_CURR_Y_COUNT(val) bfin_write16(DMA0_CURR_Y_COUNT,val)
+#define bfin_read_DMA0_IRQ_STATUS() bfin_read16(DMA0_IRQ_STATUS)
+#define bfin_write_DMA0_IRQ_STATUS(val) bfin_write16(DMA0_IRQ_STATUS,val)
+#define bfin_read_DMA0_PERIPHERAL_MAP() bfin_read16(DMA0_PERIPHERAL_MAP)
+#define bfin_write_DMA0_PERIPHERAL_MAP(val) bfin_write16(DMA0_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA1_CONFIG() bfin_read16(DMA1_CONFIG)
+#define bfin_write_DMA1_CONFIG(val) bfin_write16(DMA1_CONFIG,val)
+#define bfin_read_DMA1_NEXT_DESC_PTR() bfin_read32(DMA1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_NEXT_DESC_PTR(val) bfin_write32(DMA1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_START_ADDR() bfin_read32(DMA1_START_ADDR)
+#define bfin_write_DMA1_START_ADDR(val) bfin_write32(DMA1_START_ADDR,val)
+#define bfin_read_DMA1_X_COUNT() bfin_read16(DMA1_X_COUNT)
+#define bfin_write_DMA1_X_COUNT(val) bfin_write16(DMA1_X_COUNT,val)
+#define bfin_read_DMA1_Y_COUNT() bfin_read16(DMA1_Y_COUNT)
+#define bfin_write_DMA1_Y_COUNT(val) bfin_write16(DMA1_Y_COUNT,val)
+#define bfin_read_DMA1_X_MODIFY() bfin_read16(DMA1_X_MODIFY)
+#define bfin_write_DMA1_X_MODIFY(val) bfin_write16(DMA1_X_MODIFY,val)
+#define bfin_read_DMA1_Y_MODIFY() bfin_read16(DMA1_Y_MODIFY)
+#define bfin_write_DMA1_Y_MODIFY(val) bfin_write16(DMA1_Y_MODIFY,val)
+#define bfin_read_DMA1_CURR_DESC_PTR() bfin_read32(DMA1_CURR_DESC_PTR)
+#define bfin_write_DMA1_CURR_DESC_PTR(val) bfin_write32(DMA1_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_CURR_ADDR() bfin_read32(DMA1_CURR_ADDR)
+#define bfin_write_DMA1_CURR_ADDR(val) bfin_write32(DMA1_CURR_ADDR,val)
+#define bfin_read_DMA1_CURR_X_COUNT() bfin_read16(DMA1_CURR_X_COUNT)
+#define bfin_write_DMA1_CURR_X_COUNT(val) bfin_write16(DMA1_CURR_X_COUNT,val)
+#define bfin_read_DMA1_CURR_Y_COUNT() bfin_read16(DMA1_CURR_Y_COUNT)
+#define bfin_write_DMA1_CURR_Y_COUNT(val) bfin_write16(DMA1_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_IRQ_STATUS() bfin_read16(DMA1_IRQ_STATUS)
+#define bfin_write_DMA1_IRQ_STATUS(val) bfin_write16(DMA1_IRQ_STATUS,val)
+#define bfin_read_DMA1_PERIPHERAL_MAP() bfin_read16(DMA1_PERIPHERAL_MAP)
+#define bfin_write_DMA1_PERIPHERAL_MAP(val) bfin_write16(DMA1_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA2_CONFIG() bfin_read16(DMA2_CONFIG)
+#define bfin_write_DMA2_CONFIG(val) bfin_write16(DMA2_CONFIG,val)
+#define bfin_read_DMA2_NEXT_DESC_PTR() bfin_read32(DMA2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_NEXT_DESC_PTR(val) bfin_write32(DMA2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_START_ADDR() bfin_read32(DMA2_START_ADDR)
+#define bfin_write_DMA2_START_ADDR(val) bfin_write32(DMA2_START_ADDR,val)
+#define bfin_read_DMA2_X_COUNT() bfin_read16(DMA2_X_COUNT)
+#define bfin_write_DMA2_X_COUNT(val) bfin_write16(DMA2_X_COUNT,val)
+#define bfin_read_DMA2_Y_COUNT() bfin_read16(DMA2_Y_COUNT)
+#define bfin_write_DMA2_Y_COUNT(val) bfin_write16(DMA2_Y_COUNT,val)
+#define bfin_read_DMA2_X_MODIFY() bfin_read16(DMA2_X_MODIFY)
+#define bfin_write_DMA2_X_MODIFY(val) bfin_write16(DMA2_X_MODIFY,val)
+#define bfin_read_DMA2_Y_MODIFY() bfin_read16(DMA2_Y_MODIFY)
+#define bfin_write_DMA2_Y_MODIFY(val) bfin_write16(DMA2_Y_MODIFY,val)
+#define bfin_read_DMA2_CURR_DESC_PTR() bfin_read32(DMA2_CURR_DESC_PTR)
+#define bfin_write_DMA2_CURR_DESC_PTR(val) bfin_write32(DMA2_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_CURR_ADDR() bfin_read32(DMA2_CURR_ADDR)
+#define bfin_write_DMA2_CURR_ADDR(val) bfin_write32(DMA2_CURR_ADDR,val)
+#define bfin_read_DMA2_CURR_X_COUNT() bfin_read16(DMA2_CURR_X_COUNT)
+#define bfin_write_DMA2_CURR_X_COUNT(val) bfin_write16(DMA2_CURR_X_COUNT,val)
+#define bfin_read_DMA2_CURR_Y_COUNT() bfin_read16(DMA2_CURR_Y_COUNT)
+#define bfin_write_DMA2_CURR_Y_COUNT(val) bfin_write16(DMA2_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_IRQ_STATUS() bfin_read16(DMA2_IRQ_STATUS)
+#define bfin_write_DMA2_IRQ_STATUS(val) bfin_write16(DMA2_IRQ_STATUS,val)
+#define bfin_read_DMA2_PERIPHERAL_MAP() bfin_read16(DMA2_PERIPHERAL_MAP)
+#define bfin_write_DMA2_PERIPHERAL_MAP(val) bfin_write16(DMA2_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA3_CONFIG() bfin_read16(DMA3_CONFIG)
+#define bfin_write_DMA3_CONFIG(val) bfin_write16(DMA3_CONFIG,val)
+#define bfin_read_DMA3_NEXT_DESC_PTR() bfin_read32(DMA3_NEXT_DESC_PTR)
+#define bfin_write_DMA3_NEXT_DESC_PTR(val) bfin_write32(DMA3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA3_START_ADDR() bfin_read32(DMA3_START_ADDR)
+#define bfin_write_DMA3_START_ADDR(val) bfin_write32(DMA3_START_ADDR,val)
+#define bfin_read_DMA3_X_COUNT() bfin_read16(DMA3_X_COUNT)
+#define bfin_write_DMA3_X_COUNT(val) bfin_write16(DMA3_X_COUNT,val)
+#define bfin_read_DMA3_Y_COUNT() bfin_read16(DMA3_Y_COUNT)
+#define bfin_write_DMA3_Y_COUNT(val) bfin_write16(DMA3_Y_COUNT,val)
+#define bfin_read_DMA3_X_MODIFY() bfin_read16(DMA3_X_MODIFY)
+#define bfin_write_DMA3_X_MODIFY(val) bfin_write16(DMA3_X_MODIFY,val)
+#define bfin_read_DMA3_Y_MODIFY() bfin_read16(DMA3_Y_MODIFY)
+#define bfin_write_DMA3_Y_MODIFY(val) bfin_write16(DMA3_Y_MODIFY,val)
+#define bfin_read_DMA3_CURR_DESC_PTR() bfin_read32(DMA3_CURR_DESC_PTR)
+#define bfin_write_DMA3_CURR_DESC_PTR(val) bfin_write32(DMA3_CURR_DESC_PTR,val)
+#define bfin_read_DMA3_CURR_ADDR() bfin_read32(DMA3_CURR_ADDR)
+#define bfin_write_DMA3_CURR_ADDR(val) bfin_write32(DMA3_CURR_ADDR,val)
+#define bfin_read_DMA3_CURR_X_COUNT() bfin_read16(DMA3_CURR_X_COUNT)
+#define bfin_write_DMA3_CURR_X_COUNT(val) bfin_write16(DMA3_CURR_X_COUNT,val)
+#define bfin_read_DMA3_CURR_Y_COUNT() bfin_read16(DMA3_CURR_Y_COUNT)
+#define bfin_write_DMA3_CURR_Y_COUNT(val) bfin_write16(DMA3_CURR_Y_COUNT,val)
+#define bfin_read_DMA3_IRQ_STATUS() bfin_read16(DMA3_IRQ_STATUS)
+#define bfin_write_DMA3_IRQ_STATUS(val) bfin_write16(DMA3_IRQ_STATUS,val)
+#define bfin_read_DMA3_PERIPHERAL_MAP() bfin_read16(DMA3_PERIPHERAL_MAP)
+#define bfin_write_DMA3_PERIPHERAL_MAP(val) bfin_write16(DMA3_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA4_CONFIG() bfin_read16(DMA4_CONFIG)
+#define bfin_write_DMA4_CONFIG(val) bfin_write16(DMA4_CONFIG,val)
+#define bfin_read_DMA4_NEXT_DESC_PTR() bfin_read32(DMA4_NEXT_DESC_PTR)
+#define bfin_write_DMA4_NEXT_DESC_PTR(val) bfin_write32(DMA4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA4_START_ADDR() bfin_read32(DMA4_START_ADDR)
+#define bfin_write_DMA4_START_ADDR(val) bfin_write32(DMA4_START_ADDR,val)
+#define bfin_read_DMA4_X_COUNT() bfin_read16(DMA4_X_COUNT)
+#define bfin_write_DMA4_X_COUNT(val) bfin_write16(DMA4_X_COUNT,val)
+#define bfin_read_DMA4_Y_COUNT() bfin_read16(DMA4_Y_COUNT)
+#define bfin_write_DMA4_Y_COUNT(val) bfin_write16(DMA4_Y_COUNT,val)
+#define bfin_read_DMA4_X_MODIFY() bfin_read16(DMA4_X_MODIFY)
+#define bfin_write_DMA4_X_MODIFY(val) bfin_write16(DMA4_X_MODIFY,val)
+#define bfin_read_DMA4_Y_MODIFY() bfin_read16(DMA4_Y_MODIFY)
+#define bfin_write_DMA4_Y_MODIFY(val) bfin_write16(DMA4_Y_MODIFY,val)
+#define bfin_read_DMA4_CURR_DESC_PTR() bfin_read32(DMA4_CURR_DESC_PTR)
+#define bfin_write_DMA4_CURR_DESC_PTR(val) bfin_write32(DMA4_CURR_DESC_PTR,val)
+#define bfin_read_DMA4_CURR_ADDR() bfin_read32(DMA4_CURR_ADDR)
+#define bfin_write_DMA4_CURR_ADDR(val) bfin_write32(DMA4_CURR_ADDR,val)
+#define bfin_read_DMA4_CURR_X_COUNT() bfin_read16(DMA4_CURR_X_COUNT)
+#define bfin_write_DMA4_CURR_X_COUNT(val) bfin_write16(DMA4_CURR_X_COUNT,val)
+#define bfin_read_DMA4_CURR_Y_COUNT() bfin_read16(DMA4_CURR_Y_COUNT)
+#define bfin_write_DMA4_CURR_Y_COUNT(val) bfin_write16(DMA4_CURR_Y_COUNT,val)
+#define bfin_read_DMA4_IRQ_STATUS() bfin_read16(DMA4_IRQ_STATUS)
+#define bfin_write_DMA4_IRQ_STATUS(val) bfin_write16(DMA4_IRQ_STATUS,val)
+#define bfin_read_DMA4_PERIPHERAL_MAP() bfin_read16(DMA4_PERIPHERAL_MAP)
+#define bfin_write_DMA4_PERIPHERAL_MAP(val) bfin_write16(DMA4_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA5_CONFIG() bfin_read16(DMA5_CONFIG)
+#define bfin_write_DMA5_CONFIG(val) bfin_write16(DMA5_CONFIG,val)
+#define bfin_read_DMA5_NEXT_DESC_PTR() bfin_read32(DMA5_NEXT_DESC_PTR)
+#define bfin_write_DMA5_NEXT_DESC_PTR(val) bfin_write32(DMA5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA5_START_ADDR() bfin_read32(DMA5_START_ADDR)
+#define bfin_write_DMA5_START_ADDR(val) bfin_write32(DMA5_START_ADDR,val)
+#define bfin_read_DMA5_X_COUNT() bfin_read16(DMA5_X_COUNT)
+#define bfin_write_DMA5_X_COUNT(val) bfin_write16(DMA5_X_COUNT,val)
+#define bfin_read_DMA5_Y_COUNT() bfin_read16(DMA5_Y_COUNT)
+#define bfin_write_DMA5_Y_COUNT(val) bfin_write16(DMA5_Y_COUNT,val)
+#define bfin_read_DMA5_X_MODIFY() bfin_read16(DMA5_X_MODIFY)
+#define bfin_write_DMA5_X_MODIFY(val) bfin_write16(DMA5_X_MODIFY,val)
+#define bfin_read_DMA5_Y_MODIFY() bfin_read16(DMA5_Y_MODIFY)
+#define bfin_write_DMA5_Y_MODIFY(val) bfin_write16(DMA5_Y_MODIFY,val)
+#define bfin_read_DMA5_CURR_DESC_PTR() bfin_read32(DMA5_CURR_DESC_PTR)
+#define bfin_write_DMA5_CURR_DESC_PTR(val) bfin_write32(DMA5_CURR_DESC_PTR,val)
+#define bfin_read_DMA5_CURR_ADDR() bfin_read32(DMA5_CURR_ADDR)
+#define bfin_write_DMA5_CURR_ADDR(val) bfin_write32(DMA5_CURR_ADDR,val)
+#define bfin_read_DMA5_CURR_X_COUNT() bfin_read16(DMA5_CURR_X_COUNT)
+#define bfin_write_DMA5_CURR_X_COUNT(val) bfin_write16(DMA5_CURR_X_COUNT,val)
+#define bfin_read_DMA5_CURR_Y_COUNT() bfin_read16(DMA5_CURR_Y_COUNT)
+#define bfin_write_DMA5_CURR_Y_COUNT(val) bfin_write16(DMA5_CURR_Y_COUNT,val)
+#define bfin_read_DMA5_IRQ_STATUS() bfin_read16(DMA5_IRQ_STATUS)
+#define bfin_write_DMA5_IRQ_STATUS(val) bfin_write16(DMA5_IRQ_STATUS,val)
+#define bfin_read_DMA5_PERIPHERAL_MAP() bfin_read16(DMA5_PERIPHERAL_MAP)
+#define bfin_write_DMA5_PERIPHERAL_MAP(val) bfin_write16(DMA5_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA6_CONFIG() bfin_read16(DMA6_CONFIG)
+#define bfin_write_DMA6_CONFIG(val) bfin_write16(DMA6_CONFIG,val)
+#define bfin_read_DMA6_NEXT_DESC_PTR() bfin_read32(DMA6_NEXT_DESC_PTR)
+#define bfin_write_DMA6_NEXT_DESC_PTR(val) bfin_write32(DMA6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA6_START_ADDR() bfin_read32(DMA6_START_ADDR)
+#define bfin_write_DMA6_START_ADDR(val) bfin_write32(DMA6_START_ADDR,val)
+#define bfin_read_DMA6_X_COUNT() bfin_read16(DMA6_X_COUNT)
+#define bfin_write_DMA6_X_COUNT(val) bfin_write16(DMA6_X_COUNT,val)
+#define bfin_read_DMA6_Y_COUNT() bfin_read16(DMA6_Y_COUNT)
+#define bfin_write_DMA6_Y_COUNT(val) bfin_write16(DMA6_Y_COUNT,val)
+#define bfin_read_DMA6_X_MODIFY() bfin_read16(DMA6_X_MODIFY)
+#define bfin_write_DMA6_X_MODIFY(val) bfin_write16(DMA6_X_MODIFY,val)
+#define bfin_read_DMA6_Y_MODIFY() bfin_read16(DMA6_Y_MODIFY)
+#define bfin_write_DMA6_Y_MODIFY(val) bfin_write16(DMA6_Y_MODIFY,val)
+#define bfin_read_DMA6_CURR_DESC_PTR() bfin_read32(DMA6_CURR_DESC_PTR)
+#define bfin_write_DMA6_CURR_DESC_PTR(val) bfin_write32(DMA6_CURR_DESC_PTR,val)
+#define bfin_read_DMA6_CURR_ADDR() bfin_read32(DMA6_CURR_ADDR)
+#define bfin_write_DMA6_CURR_ADDR(val) bfin_write32(DMA6_CURR_ADDR,val)
+#define bfin_read_DMA6_CURR_X_COUNT() bfin_read16(DMA6_CURR_X_COUNT)
+#define bfin_write_DMA6_CURR_X_COUNT(val) bfin_write16(DMA6_CURR_X_COUNT,val)
+#define bfin_read_DMA6_CURR_Y_COUNT() bfin_read16(DMA6_CURR_Y_COUNT)
+#define bfin_write_DMA6_CURR_Y_COUNT(val) bfin_write16(DMA6_CURR_Y_COUNT,val)
+#define bfin_read_DMA6_IRQ_STATUS() bfin_read16(DMA6_IRQ_STATUS)
+#define bfin_write_DMA6_IRQ_STATUS(val) bfin_write16(DMA6_IRQ_STATUS,val)
+#define bfin_read_DMA6_PERIPHERAL_MAP() bfin_read16(DMA6_PERIPHERAL_MAP)
+#define bfin_write_DMA6_PERIPHERAL_MAP(val) bfin_write16(DMA6_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA7_CONFIG() bfin_read16(DMA7_CONFIG)
+#define bfin_write_DMA7_CONFIG(val) bfin_write16(DMA7_CONFIG,val)
+#define bfin_read_DMA7_NEXT_DESC_PTR() bfin_read32(DMA7_NEXT_DESC_PTR)
+#define bfin_write_DMA7_NEXT_DESC_PTR(val) bfin_write32(DMA7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA7_START_ADDR() bfin_read32(DMA7_START_ADDR)
+#define bfin_write_DMA7_START_ADDR(val) bfin_write32(DMA7_START_ADDR,val)
+#define bfin_read_DMA7_X_COUNT() bfin_read16(DMA7_X_COUNT)
+#define bfin_write_DMA7_X_COUNT(val) bfin_write16(DMA7_X_COUNT,val)
+#define bfin_read_DMA7_Y_COUNT() bfin_read16(DMA7_Y_COUNT)
+#define bfin_write_DMA7_Y_COUNT(val) bfin_write16(DMA7_Y_COUNT,val)
+#define bfin_read_DMA7_X_MODIFY() bfin_read16(DMA7_X_MODIFY)
+#define bfin_write_DMA7_X_MODIFY(val) bfin_write16(DMA7_X_MODIFY,val)
+#define bfin_read_DMA7_Y_MODIFY() bfin_read16(DMA7_Y_MODIFY)
+#define bfin_write_DMA7_Y_MODIFY(val) bfin_write16(DMA7_Y_MODIFY,val)
+#define bfin_read_DMA7_CURR_DESC_PTR() bfin_read32(DMA7_CURR_DESC_PTR)
+#define bfin_write_DMA7_CURR_DESC_PTR(val) bfin_write32(DMA7_CURR_DESC_PTR,val)
+#define bfin_read_DMA7_CURR_ADDR() bfin_read32(DMA7_CURR_ADDR)
+#define bfin_write_DMA7_CURR_ADDR(val) bfin_write32(DMA7_CURR_ADDR,val)
+#define bfin_read_DMA7_CURR_X_COUNT() bfin_read16(DMA7_CURR_X_COUNT)
+#define bfin_write_DMA7_CURR_X_COUNT(val) bfin_write16(DMA7_CURR_X_COUNT,val)
+#define bfin_read_DMA7_CURR_Y_COUNT() bfin_read16(DMA7_CURR_Y_COUNT)
+#define bfin_write_DMA7_CURR_Y_COUNT(val) bfin_write16(DMA7_CURR_Y_COUNT,val)
+#define bfin_read_DMA7_IRQ_STATUS() bfin_read16(DMA7_IRQ_STATUS)
+#define bfin_write_DMA7_IRQ_STATUS(val) bfin_write16(DMA7_IRQ_STATUS,val)
+#define bfin_read_DMA7_PERIPHERAL_MAP() bfin_read16(DMA7_PERIPHERAL_MAP)
+#define bfin_write_DMA7_PERIPHERAL_MAP(val) bfin_write16(DMA7_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA8_CONFIG() bfin_read16(DMA8_CONFIG)
+#define bfin_write_DMA8_CONFIG(val) bfin_write16(DMA8_CONFIG,val)
+#define bfin_read_DMA8_NEXT_DESC_PTR() bfin_read32(DMA8_NEXT_DESC_PTR)
+#define bfin_write_DMA8_NEXT_DESC_PTR(val) bfin_write32(DMA8_NEXT_DESC_PTR,val)
+#define bfin_read_DMA8_START_ADDR() bfin_read32(DMA8_START_ADDR)
+#define bfin_write_DMA8_START_ADDR(val) bfin_write32(DMA8_START_ADDR,val)
+#define bfin_read_DMA8_X_COUNT() bfin_read16(DMA8_X_COUNT)
+#define bfin_write_DMA8_X_COUNT(val) bfin_write16(DMA8_X_COUNT,val)
+#define bfin_read_DMA8_Y_COUNT() bfin_read16(DMA8_Y_COUNT)
+#define bfin_write_DMA8_Y_COUNT(val) bfin_write16(DMA8_Y_COUNT,val)
+#define bfin_read_DMA8_X_MODIFY() bfin_read16(DMA8_X_MODIFY)
+#define bfin_write_DMA8_X_MODIFY(val) bfin_write16(DMA8_X_MODIFY,val)
+#define bfin_read_DMA8_Y_MODIFY() bfin_read16(DMA8_Y_MODIFY)
+#define bfin_write_DMA8_Y_MODIFY(val) bfin_write16(DMA8_Y_MODIFY,val)
+#define bfin_read_DMA8_CURR_DESC_PTR() bfin_read32(DMA8_CURR_DESC_PTR)
+#define bfin_write_DMA8_CURR_DESC_PTR(val) bfin_write32(DMA8_CURR_DESC_PTR,val)
+#define bfin_read_DMA8_CURR_ADDR() bfin_read32(DMA8_CURR_ADDR)
+#define bfin_write_DMA8_CURR_ADDR(val) bfin_write32(DMA8_CURR_ADDR,val)
+#define bfin_read_DMA8_CURR_X_COUNT() bfin_read16(DMA8_CURR_X_COUNT)
+#define bfin_write_DMA8_CURR_X_COUNT(val) bfin_write16(DMA8_CURR_X_COUNT,val)
+#define bfin_read_DMA8_CURR_Y_COUNT() bfin_read16(DMA8_CURR_Y_COUNT)
+#define bfin_write_DMA8_CURR_Y_COUNT(val) bfin_write16(DMA8_CURR_Y_COUNT,val)
+#define bfin_read_DMA8_IRQ_STATUS() bfin_read16(DMA8_IRQ_STATUS)
+#define bfin_write_DMA8_IRQ_STATUS(val) bfin_write16(DMA8_IRQ_STATUS,val)
+#define bfin_read_DMA8_PERIPHERAL_MAP() bfin_read16(DMA8_PERIPHERAL_MAP)
+#define bfin_write_DMA8_PERIPHERAL_MAP(val) bfin_write16(DMA8_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA9_CONFIG() bfin_read16(DMA9_CONFIG)
+#define bfin_write_DMA9_CONFIG(val) bfin_write16(DMA9_CONFIG,val)
+#define bfin_read_DMA9_NEXT_DESC_PTR() bfin_read32(DMA9_NEXT_DESC_PTR)
+#define bfin_write_DMA9_NEXT_DESC_PTR(val) bfin_write32(DMA9_NEXT_DESC_PTR,val)
+#define bfin_read_DMA9_START_ADDR() bfin_read32(DMA9_START_ADDR)
+#define bfin_write_DMA9_START_ADDR(val) bfin_write32(DMA9_START_ADDR,val)
+#define bfin_read_DMA9_X_COUNT() bfin_read16(DMA9_X_COUNT)
+#define bfin_write_DMA9_X_COUNT(val) bfin_write16(DMA9_X_COUNT,val)
+#define bfin_read_DMA9_Y_COUNT() bfin_read16(DMA9_Y_COUNT)
+#define bfin_write_DMA9_Y_COUNT(val) bfin_write16(DMA9_Y_COUNT,val)
+#define bfin_read_DMA9_X_MODIFY() bfin_read16(DMA9_X_MODIFY)
+#define bfin_write_DMA9_X_MODIFY(val) bfin_write16(DMA9_X_MODIFY,val)
+#define bfin_read_DMA9_Y_MODIFY() bfin_read16(DMA9_Y_MODIFY)
+#define bfin_write_DMA9_Y_MODIFY(val) bfin_write16(DMA9_Y_MODIFY,val)
+#define bfin_read_DMA9_CURR_DESC_PTR() bfin_read32(DMA9_CURR_DESC_PTR)
+#define bfin_write_DMA9_CURR_DESC_PTR(val) bfin_write32(DMA9_CURR_DESC_PTR,val)
+#define bfin_read_DMA9_CURR_ADDR() bfin_read32(DMA9_CURR_ADDR)
+#define bfin_write_DMA9_CURR_ADDR(val) bfin_write32(DMA9_CURR_ADDR,val)
+#define bfin_read_DMA9_CURR_X_COUNT() bfin_read16(DMA9_CURR_X_COUNT)
+#define bfin_write_DMA9_CURR_X_COUNT(val) bfin_write16(DMA9_CURR_X_COUNT,val)
+#define bfin_read_DMA9_CURR_Y_COUNT() bfin_read16(DMA9_CURR_Y_COUNT)
+#define bfin_write_DMA9_CURR_Y_COUNT(val) bfin_write16(DMA9_CURR_Y_COUNT,val)
+#define bfin_read_DMA9_IRQ_STATUS() bfin_read16(DMA9_IRQ_STATUS)
+#define bfin_write_DMA9_IRQ_STATUS(val) bfin_write16(DMA9_IRQ_STATUS,val)
+#define bfin_read_DMA9_PERIPHERAL_MAP() bfin_read16(DMA9_PERIPHERAL_MAP)
+#define bfin_write_DMA9_PERIPHERAL_MAP(val) bfin_write16(DMA9_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA10_CONFIG() bfin_read16(DMA10_CONFIG)
+#define bfin_write_DMA10_CONFIG(val) bfin_write16(DMA10_CONFIG,val)
+#define bfin_read_DMA10_NEXT_DESC_PTR() bfin_read32(DMA10_NEXT_DESC_PTR)
+#define bfin_write_DMA10_NEXT_DESC_PTR(val) bfin_write32(DMA10_NEXT_DESC_PTR,val)
+#define bfin_read_DMA10_START_ADDR() bfin_read32(DMA10_START_ADDR)
+#define bfin_write_DMA10_START_ADDR(val) bfin_write32(DMA10_START_ADDR,val)
+#define bfin_read_DMA10_X_COUNT() bfin_read16(DMA10_X_COUNT)
+#define bfin_write_DMA10_X_COUNT(val) bfin_write16(DMA10_X_COUNT,val)
+#define bfin_read_DMA10_Y_COUNT() bfin_read16(DMA10_Y_COUNT)
+#define bfin_write_DMA10_Y_COUNT(val) bfin_write16(DMA10_Y_COUNT,val)
+#define bfin_read_DMA10_X_MODIFY() bfin_read16(DMA10_X_MODIFY)
+#define bfin_write_DMA10_X_MODIFY(val) bfin_write16(DMA10_X_MODIFY,val)
+#define bfin_read_DMA10_Y_MODIFY() bfin_read16(DMA10_Y_MODIFY)
+#define bfin_write_DMA10_Y_MODIFY(val) bfin_write16(DMA10_Y_MODIFY,val)
+#define bfin_read_DMA10_CURR_DESC_PTR() bfin_read32(DMA10_CURR_DESC_PTR)
+#define bfin_write_DMA10_CURR_DESC_PTR(val) bfin_write32(DMA10_CURR_DESC_PTR,val)
+#define bfin_read_DMA10_CURR_ADDR() bfin_read32(DMA10_CURR_ADDR)
+#define bfin_write_DMA10_CURR_ADDR(val) bfin_write32(DMA10_CURR_ADDR,val)
+#define bfin_read_DMA10_CURR_X_COUNT() bfin_read16(DMA10_CURR_X_COUNT)
+#define bfin_write_DMA10_CURR_X_COUNT(val) bfin_write16(DMA10_CURR_X_COUNT,val)
+#define bfin_read_DMA10_CURR_Y_COUNT() bfin_read16(DMA10_CURR_Y_COUNT)
+#define bfin_write_DMA10_CURR_Y_COUNT(val) bfin_write16(DMA10_CURR_Y_COUNT,val)
+#define bfin_read_DMA10_IRQ_STATUS() bfin_read16(DMA10_IRQ_STATUS)
+#define bfin_write_DMA10_IRQ_STATUS(val) bfin_write16(DMA10_IRQ_STATUS,val)
+#define bfin_read_DMA10_PERIPHERAL_MAP() bfin_read16(DMA10_PERIPHERAL_MAP)
+#define bfin_write_DMA10_PERIPHERAL_MAP(val) bfin_write16(DMA10_PERIPHERAL_MAP,val)
+
+#define bfin_read_DMA11_CONFIG() bfin_read16(DMA11_CONFIG)
+#define bfin_write_DMA11_CONFIG(val) bfin_write16(DMA11_CONFIG,val)
+#define bfin_read_DMA11_NEXT_DESC_PTR() bfin_read32(DMA11_NEXT_DESC_PTR)
+#define bfin_write_DMA11_NEXT_DESC_PTR(val) bfin_write32(DMA11_NEXT_DESC_PTR,val)
+#define bfin_read_DMA11_START_ADDR() bfin_read32(DMA11_START_ADDR)
+#define bfin_write_DMA11_START_ADDR(val) bfin_write32(DMA11_START_ADDR,val)
+#define bfin_read_DMA11_X_COUNT() bfin_read16(DMA11_X_COUNT)
+#define bfin_write_DMA11_X_COUNT(val) bfin_write16(DMA11_X_COUNT,val)
+#define bfin_read_DMA11_Y_COUNT() bfin_read16(DMA11_Y_COUNT)
+#define bfin_write_DMA11_Y_COUNT(val) bfin_write16(DMA11_Y_COUNT,val)
+#define bfin_read_DMA11_X_MODIFY() bfin_read16(DMA11_X_MODIFY)
+#define bfin_write_DMA11_X_MODIFY(val) bfin_write16(DMA11_X_MODIFY,val)
+#define bfin_read_DMA11_Y_MODIFY() bfin_read16(DMA11_Y_MODIFY)
+#define bfin_write_DMA11_Y_MODIFY(val) bfin_write16(DMA11_Y_MODIFY,val)
+#define bfin_read_DMA11_CURR_DESC_PTR() bfin_read32(DMA11_CURR_DESC_PTR)
+#define bfin_write_DMA11_CURR_DESC_PTR(val) bfin_write32(DMA11_CURR_DESC_PTR,val)
+#define bfin_read_DMA11_CURR_ADDR() bfin_read32(DMA11_CURR_ADDR)
+#define bfin_write_DMA11_CURR_ADDR(val) bfin_write32(DMA11_CURR_ADDR,val)
+#define bfin_read_DMA11_CURR_X_COUNT() bfin_read16(DMA11_CURR_X_COUNT)
+#define bfin_write_DMA11_CURR_X_COUNT(val) bfin_write16(DMA11_CURR_X_COUNT,val)
+#define bfin_read_DMA11_CURR_Y_COUNT() bfin_read16(DMA11_CURR_Y_COUNT)
+#define bfin_write_DMA11_CURR_Y_COUNT(val) bfin_write16(DMA11_CURR_Y_COUNT,val)
+#define bfin_read_DMA11_IRQ_STATUS() bfin_read16(DMA11_IRQ_STATUS)
+#define bfin_write_DMA11_IRQ_STATUS(val) bfin_write16(DMA11_IRQ_STATUS,val)
+#define bfin_read_DMA11_PERIPHERAL_MAP() bfin_read16(DMA11_PERIPHERAL_MAP)
+#define bfin_write_DMA11_PERIPHERAL_MAP(val) bfin_write16(DMA11_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D0_CONFIG() bfin_read16(MDMA_D0_CONFIG)
+#define bfin_write_MDMA_D0_CONFIG(val) bfin_write16(MDMA_D0_CONFIG,val)
+#define bfin_read_MDMA_D0_NEXT_DESC_PTR() bfin_read32(MDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D0_START_ADDR() bfin_read32(MDMA_D0_START_ADDR)
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write32(MDMA_D0_START_ADDR,val)
+#define bfin_read_MDMA_D0_X_COUNT() bfin_read16(MDMA_D0_X_COUNT)
+#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write16(MDMA_D0_X_COUNT,val)
+#define bfin_read_MDMA_D0_Y_COUNT() bfin_read16(MDMA_D0_Y_COUNT)
+#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write16(MDMA_D0_Y_COUNT,val)
+#define bfin_read_MDMA_D0_X_MODIFY() bfin_read16(MDMA_D0_X_MODIFY)
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write16(MDMA_D0_X_MODIFY,val)
+#define bfin_read_MDMA_D0_Y_MODIFY() bfin_read16(MDMA_D0_Y_MODIFY)
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write16(MDMA_D0_Y_MODIFY,val)
+#define bfin_read_MDMA_D0_CURR_DESC_PTR() bfin_read32(MDMA_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA_D0_CURR_DESC_PTR(val) bfin_write32(MDMA_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D0_CURR_ADDR() bfin_read32(MDMA_D0_CURR_ADDR)
+#define bfin_write_MDMA_D0_CURR_ADDR(val) bfin_write32(MDMA_D0_CURR_ADDR,val)
+#define bfin_read_MDMA_D0_CURR_X_COUNT() bfin_read16(MDMA_D0_CURR_X_COUNT)
+#define bfin_write_MDMA_D0_CURR_X_COUNT(val) bfin_write16(MDMA_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D0_CURR_Y_COUNT() bfin_read16(MDMA_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA_D0_CURR_Y_COUNT(val) bfin_write16(MDMA_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D0_IRQ_STATUS() bfin_read16(MDMA_D0_IRQ_STATUS)
+#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write16(MDMA_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA_D0_PERIPHERAL_MAP() bfin_read16(MDMA_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA_D0_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S0_CONFIG() bfin_read16(MDMA_S0_CONFIG)
+#define bfin_write_MDMA_S0_CONFIG(val) bfin_write16(MDMA_S0_CONFIG,val)
+#define bfin_read_MDMA_S0_NEXT_DESC_PTR() bfin_read32(MDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S0_START_ADDR() bfin_read32(MDMA_S0_START_ADDR)
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write32(MDMA_S0_START_ADDR,val)
+#define bfin_read_MDMA_S0_X_COUNT() bfin_read16(MDMA_S0_X_COUNT)
+#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write16(MDMA_S0_X_COUNT,val)
+#define bfin_read_MDMA_S0_Y_COUNT() bfin_read16(MDMA_S0_Y_COUNT)
+#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write16(MDMA_S0_Y_COUNT,val)
+#define bfin_read_MDMA_S0_X_MODIFY() bfin_read16(MDMA_S0_X_MODIFY)
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write16(MDMA_S0_X_MODIFY,val)
+#define bfin_read_MDMA_S0_Y_MODIFY() bfin_read16(MDMA_S0_Y_MODIFY)
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write16(MDMA_S0_Y_MODIFY,val)
+#define bfin_read_MDMA_S0_CURR_DESC_PTR() bfin_read32(MDMA_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA_S0_CURR_DESC_PTR(val) bfin_write32(MDMA_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S0_CURR_ADDR() bfin_read32(MDMA_S0_CURR_ADDR)
+#define bfin_write_MDMA_S0_CURR_ADDR(val) bfin_write32(MDMA_S0_CURR_ADDR,val)
+#define bfin_read_MDMA_S0_CURR_X_COUNT() bfin_read16(MDMA_S0_CURR_X_COUNT)
+#define bfin_write_MDMA_S0_CURR_X_COUNT(val) bfin_write16(MDMA_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S0_CURR_Y_COUNT() bfin_read16(MDMA_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA_S0_CURR_Y_COUNT(val) bfin_write16(MDMA_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S0_IRQ_STATUS() bfin_read16(MDMA_S0_IRQ_STATUS)
+#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write16(MDMA_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA_S0_PERIPHERAL_MAP() bfin_read16(MDMA_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA_S0_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_D1_CONFIG() bfin_read16(MDMA_D1_CONFIG)
+#define bfin_write_MDMA_D1_CONFIG(val) bfin_write16(MDMA_D1_CONFIG,val)
+#define bfin_read_MDMA_D1_NEXT_DESC_PTR() bfin_read32(MDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_D1_START_ADDR() bfin_read32(MDMA_D1_START_ADDR)
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write32(MDMA_D1_START_ADDR,val)
+#define bfin_read_MDMA_D1_X_COUNT() bfin_read16(MDMA_D1_X_COUNT)
+#define bfin_write_MDMA_D1_X_COUNT(val) bfin_write16(MDMA_D1_X_COUNT,val)
+#define bfin_read_MDMA_D1_Y_COUNT() bfin_read16(MDMA_D1_Y_COUNT)
+#define bfin_write_MDMA_D1_Y_COUNT(val) bfin_write16(MDMA_D1_Y_COUNT,val)
+#define bfin_read_MDMA_D1_X_MODIFY() bfin_read16(MDMA_D1_X_MODIFY)
+#define bfin_write_MDMA_D1_X_MODIFY(val) bfin_write16(MDMA_D1_X_MODIFY,val)
+#define bfin_read_MDMA_D1_Y_MODIFY() bfin_read16(MDMA_D1_Y_MODIFY)
+#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write16(MDMA_D1_Y_MODIFY,val)
+#define bfin_read_MDMA_D1_CURR_DESC_PTR() bfin_read32(MDMA_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA_D1_CURR_DESC_PTR(val) bfin_write32(MDMA_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_D1_CURR_ADDR() bfin_read32(MDMA_D1_CURR_ADDR)
+#define bfin_write_MDMA_D1_CURR_ADDR(val) bfin_write32(MDMA_D1_CURR_ADDR,val)
+#define bfin_read_MDMA_D1_CURR_X_COUNT() bfin_read16(MDMA_D1_CURR_X_COUNT)
+#define bfin_write_MDMA_D1_CURR_X_COUNT(val) bfin_write16(MDMA_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_D1_CURR_Y_COUNT() bfin_read16(MDMA_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA_D1_CURR_Y_COUNT(val) bfin_write16(MDMA_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_D1_IRQ_STATUS() bfin_read16(MDMA_D1_IRQ_STATUS)
+#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write16(MDMA_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA_D1_PERIPHERAL_MAP() bfin_read16(MDMA_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA_D1_PERIPHERAL_MAP,val)
+
+#define bfin_read_MDMA_S1_CONFIG() bfin_read16(MDMA_S1_CONFIG)
+#define bfin_write_MDMA_S1_CONFIG(val) bfin_write16(MDMA_S1_CONFIG,val)
+#define bfin_read_MDMA_S1_NEXT_DESC_PTR() bfin_read32(MDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA_S1_START_ADDR() bfin_read32(MDMA_S1_START_ADDR)
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write32(MDMA_S1_START_ADDR,val)
+#define bfin_read_MDMA_S1_X_COUNT() bfin_read16(MDMA_S1_X_COUNT)
+#define bfin_write_MDMA_S1_X_COUNT(val) bfin_write16(MDMA_S1_X_COUNT,val)
+#define bfin_read_MDMA_S1_Y_COUNT() bfin_read16(MDMA_S1_Y_COUNT)
+#define bfin_write_MDMA_S1_Y_COUNT(val) bfin_write16(MDMA_S1_Y_COUNT,val)
+#define bfin_read_MDMA_S1_X_MODIFY() bfin_read16(MDMA_S1_X_MODIFY)
+#define bfin_write_MDMA_S1_X_MODIFY(val) bfin_write16(MDMA_S1_X_MODIFY,val)
+#define bfin_read_MDMA_S1_Y_MODIFY() bfin_read16(MDMA_S1_Y_MODIFY)
+#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write16(MDMA_S1_Y_MODIFY,val)
+#define bfin_read_MDMA_S1_CURR_DESC_PTR() bfin_read32(MDMA_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA_S1_CURR_DESC_PTR(val) bfin_write32(MDMA_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA_S1_CURR_ADDR() bfin_read32(MDMA_S1_CURR_ADDR)
+#define bfin_write_MDMA_S1_CURR_ADDR(val) bfin_write32(MDMA_S1_CURR_ADDR,val)
+#define bfin_read_MDMA_S1_CURR_X_COUNT() bfin_read16(MDMA_S1_CURR_X_COUNT)
+#define bfin_write_MDMA_S1_CURR_X_COUNT(val) bfin_write16(MDMA_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA_S1_CURR_Y_COUNT() bfin_read16(MDMA_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA_S1_CURR_Y_COUNT(val) bfin_write16(MDMA_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA_S1_IRQ_STATUS() bfin_read16(MDMA_S1_IRQ_STATUS)
+#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write16(MDMA_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA_S1_PERIPHERAL_MAP() bfin_read16(MDMA_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA_S1_PERIPHERAL_MAP,val)
+
+/* Parallel Peripheral Interface (0xFFC01000 - 0xFFC010FF) */
+#define bfin_read_PPI_CONTROL() bfin_read16(PPI_CONTROL)
+#define bfin_write_PPI_CONTROL(val) bfin_write16(PPI_CONTROL,val)
+#define bfin_read_PPI_STATUS() bfin_read16(PPI_STATUS)
+#define bfin_write_PPI_STATUS(val) bfin_write16(PPI_STATUS,val)
+#define bfin_clear_PPI_STATUS() bfin_write_PPI_STATUS(0xFFFF)
+#define bfin_read_PPI_DELAY() bfin_read16(PPI_DELAY)
+#define bfin_write_PPI_DELAY(val) bfin_write16(PPI_DELAY,val)
+#define bfin_read_PPI_COUNT() bfin_read16(PPI_COUNT)
+#define bfin_write_PPI_COUNT(val) bfin_write16(PPI_COUNT,val)
+#define bfin_read_PPI_FRAME() bfin_read16(PPI_FRAME)
+#define bfin_write_PPI_FRAME(val) bfin_write16(PPI_FRAME,val)
+
+/* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */
+#define bfin_read_TWI_CLKDIV() bfin_read16(TWI_CLKDIV)
+#define bfin_write_TWI_CLKDIV(val) bfin_write16(TWI_CLKDIV,val)
+#define bfin_read_TWI_CONTROL() bfin_read16(TWI_CONTROL)
+#define bfin_write_TWI_CONTROL(val) bfin_write16(TWI_CONTROL,val)
+#define bfin_read_TWI_SLAVE_CTL() bfin_read16(TWI_SLAVE_CTL)
+#define bfin_write_TWI_SLAVE_CTL(val) bfin_write16(TWI_SLAVE_CTL,val)
+#define bfin_read_TWI_SLAVE_STAT() bfin_read16(TWI_SLAVE_STAT)
+#define bfin_write_TWI_SLAVE_STAT(val) bfin_write16(TWI_SLAVE_STAT,val)
+#define bfin_read_TWI_SLAVE_ADDR() bfin_read16(TWI_SLAVE_ADDR)
+#define bfin_write_TWI_SLAVE_ADDR(val) bfin_write16(TWI_SLAVE_ADDR,val)
+#define bfin_read_TWI_MASTER_CTL() bfin_read16(TWI_MASTER_CTL)
+#define bfin_write_TWI_MASTER_CTL(val) bfin_write16(TWI_MASTER_CTL,val)
+#define bfin_read_TWI_MASTER_STAT() bfin_read16(TWI_MASTER_STAT)
+#define bfin_write_TWI_MASTER_STAT(val) bfin_write16(TWI_MASTER_STAT,val)
+#define bfin_read_TWI_MASTER_ADDR() bfin_read16(TWI_MASTER_ADDR)
+#define bfin_write_TWI_MASTER_ADDR(val) bfin_write16(TWI_MASTER_ADDR,val)
+#define bfin_read_TWI_INT_STAT() bfin_read16(TWI_INT_STAT)
+#define bfin_write_TWI_INT_STAT(val) bfin_write16(TWI_INT_STAT,val)
+#define bfin_read_TWI_INT_MASK() bfin_read16(TWI_INT_MASK)
+#define bfin_write_TWI_INT_MASK(val) bfin_write16(TWI_INT_MASK,val)
+#define bfin_read_TWI_FIFO_CTL() bfin_read16(TWI_FIFO_CTL)
+#define bfin_write_TWI_FIFO_CTL(val) bfin_write16(TWI_FIFO_CTL,val)
+#define bfin_read_TWI_FIFO_STAT() bfin_read16(TWI_FIFO_STAT)
+#define bfin_write_TWI_FIFO_STAT(val) bfin_write16(TWI_FIFO_STAT,val)
+#define bfin_read_TWI_XMT_DATA8() bfin_read16(TWI_XMT_DATA8)
+#define bfin_write_TWI_XMT_DATA8(val) bfin_write16(TWI_XMT_DATA8,val)
+#define bfin_read_TWI_XMT_DATA16() bfin_read16(TWI_XMT_DATA16)
+#define bfin_write_TWI_XMT_DATA16(val) bfin_write16(TWI_XMT_DATA16,val)
+#define bfin_read_TWI_RCV_DATA8() bfin_read16(TWI_RCV_DATA8)
+#define bfin_write_TWI_RCV_DATA8(val) bfin_write16(TWI_RCV_DATA8,val)
+#define bfin_read_TWI_RCV_DATA16() bfin_read16(TWI_RCV_DATA16)
+#define bfin_write_TWI_RCV_DATA16(val) bfin_write16(TWI_RCV_DATA16,val)
+
+/* General Purpose I/O Port G (0xFFC01500 - 0xFFC015FF) */
+#define bfin_read_PORTGIO() bfin_read16(PORTGIO)
+#define bfin_write_PORTGIO(val) bfin_write16(PORTGIO,val)
+#define bfin_read_PORTGIO_CLEAR() bfin_read16(PORTGIO_CLEAR)
+#define bfin_write_PORTGIO_CLEAR(val) bfin_write16(PORTGIO_CLEAR,val)
+#define bfin_read_PORTGIO_SET() bfin_read16(PORTGIO_SET)
+#define bfin_write_PORTGIO_SET(val) bfin_write16(PORTGIO_SET,val)
+#define bfin_read_PORTGIO_TOGGLE() bfin_read16(PORTGIO_TOGGLE)
+#define bfin_write_PORTGIO_TOGGLE(val) bfin_write16(PORTGIO_TOGGLE,val)
+#define bfin_read_PORTGIO_MASKA() bfin_read16(PORTGIO_MASKA)
+#define bfin_write_PORTGIO_MASKA(val) bfin_write16(PORTGIO_MASKA,val)
+#define bfin_read_PORTGIO_MASKA_CLEAR() bfin_read16(PORTGIO_MASKA_CLEAR)
+#define bfin_write_PORTGIO_MASKA_CLEAR(val) bfin_write16(PORTGIO_MASKA_CLEAR,val)
+#define bfin_read_PORTGIO_MASKA_SET() bfin_read16(PORTGIO_MASKA_SET)
+#define bfin_write_PORTGIO_MASKA_SET(val) bfin_write16(PORTGIO_MASKA_SET,val)
+#define bfin_read_PORTGIO_MASKA_TOGGLE() bfin_read16(PORTGIO_MASKA_TOGGLE)
+#define bfin_write_PORTGIO_MASKA_TOGGLE(val) bfin_write16(PORTGIO_MASKA_TOGGLE,val)
+#define bfin_read_PORTGIO_MASKB() bfin_read16(PORTGIO_MASKB)
+#define bfin_write_PORTGIO_MASKB(val) bfin_write16(PORTGIO_MASKB,val)
+#define bfin_read_PORTGIO_MASKB_CLEAR() bfin_read16(PORTGIO_MASKB_CLEAR)
+#define bfin_write_PORTGIO_MASKB_CLEAR(val) bfin_write16(PORTGIO_MASKB_CLEAR,val)
+#define bfin_read_PORTGIO_MASKB_SET() bfin_read16(PORTGIO_MASKB_SET)
+#define bfin_write_PORTGIO_MASKB_SET(val) bfin_write16(PORTGIO_MASKB_SET,val)
+#define bfin_read_PORTGIO_MASKB_TOGGLE() bfin_read16(PORTGIO_MASKB_TOGGLE)
+#define bfin_write_PORTGIO_MASKB_TOGGLE(val) bfin_write16(PORTGIO_MASKB_TOGGLE,val)
+#define bfin_read_PORTGIO_DIR() bfin_read16(PORTGIO_DIR)
+#define bfin_write_PORTGIO_DIR(val) bfin_write16(PORTGIO_DIR,val)
+#define bfin_read_PORTGIO_POLAR() bfin_read16(PORTGIO_POLAR)
+#define bfin_write_PORTGIO_POLAR(val) bfin_write16(PORTGIO_POLAR,val)
+#define bfin_read_PORTGIO_EDGE() bfin_read16(PORTGIO_EDGE)
+#define bfin_write_PORTGIO_EDGE(val) bfin_write16(PORTGIO_EDGE,val)
+#define bfin_read_PORTGIO_BOTH() bfin_read16(PORTGIO_BOTH)
+#define bfin_write_PORTGIO_BOTH(val) bfin_write16(PORTGIO_BOTH,val)
+#define bfin_read_PORTGIO_INEN() bfin_read16(PORTGIO_INEN)
+#define bfin_write_PORTGIO_INEN(val) bfin_write16(PORTGIO_INEN,val)
+
+/* General Purpose I/O Port H (0xFFC01700 - 0xFFC017FF) */
+#define bfin_read_PORTHIO() bfin_read16(PORTHIO)
+#define bfin_write_PORTHIO(val) bfin_write16(PORTHIO,val)
+#define bfin_read_PORTHIO_CLEAR() bfin_read16(PORTHIO_CLEAR)
+#define bfin_write_PORTHIO_CLEAR(val) bfin_write16(PORTHIO_CLEAR,val)
+#define bfin_read_PORTHIO_SET() bfin_read16(PORTHIO_SET)
+#define bfin_write_PORTHIO_SET(val) bfin_write16(PORTHIO_SET,val)
+#define bfin_read_PORTHIO_TOGGLE() bfin_read16(PORTHIO_TOGGLE)
+#define bfin_write_PORTHIO_TOGGLE(val) bfin_write16(PORTHIO_TOGGLE,val)
+#define bfin_read_PORTHIO_MASKA() bfin_read16(PORTHIO_MASKA)
+#define bfin_write_PORTHIO_MASKA(val) bfin_write16(PORTHIO_MASKA,val)
+#define bfin_read_PORTHIO_MASKA_CLEAR() bfin_read16(PORTHIO_MASKA_CLEAR)
+#define bfin_write_PORTHIO_MASKA_CLEAR(val) bfin_write16(PORTHIO_MASKA_CLEAR,val)
+#define bfin_read_PORTHIO_MASKA_SET() bfin_read16(PORTHIO_MASKA_SET)
+#define bfin_write_PORTHIO_MASKA_SET(val) bfin_write16(PORTHIO_MASKA_SET,val)
+#define bfin_read_PORTHIO_MASKA_TOGGLE() bfin_read16(PORTHIO_MASKA_TOGGLE)
+#define bfin_write_PORTHIO_MASKA_TOGGLE(val) bfin_write16(PORTHIO_MASKA_TOGGLE,val)
+#define bfin_read_PORTHIO_MASKB() bfin_read16(PORTHIO_MASKB)
+#define bfin_write_PORTHIO_MASKB(val) bfin_write16(PORTHIO_MASKB,val)
+#define bfin_read_PORTHIO_MASKB_CLEAR() bfin_read16(PORTHIO_MASKB_CLEAR)
+#define bfin_write_PORTHIO_MASKB_CLEAR(val) bfin_write16(PORTHIO_MASKB_CLEAR,val)
+#define bfin_read_PORTHIO_MASKB_SET() bfin_read16(PORTHIO_MASKB_SET)
+#define bfin_write_PORTHIO_MASKB_SET(val) bfin_write16(PORTHIO_MASKB_SET,val)
+#define bfin_read_PORTHIO_MASKB_TOGGLE() bfin_read16(PORTHIO_MASKB_TOGGLE)
+#define bfin_write_PORTHIO_MASKB_TOGGLE(val) bfin_write16(PORTHIO_MASKB_TOGGLE,val)
+#define bfin_read_PORTHIO_DIR() bfin_read16(PORTHIO_DIR)
+#define bfin_write_PORTHIO_DIR(val) bfin_write16(PORTHIO_DIR,val)
+#define bfin_read_PORTHIO_POLAR() bfin_read16(PORTHIO_POLAR)
+#define bfin_write_PORTHIO_POLAR(val) bfin_write16(PORTHIO_POLAR,val)
+#define bfin_read_PORTHIO_EDGE() bfin_read16(PORTHIO_EDGE)
+#define bfin_write_PORTHIO_EDGE(val) bfin_write16(PORTHIO_EDGE,val)
+#define bfin_read_PORTHIO_BOTH() bfin_read16(PORTHIO_BOTH)
+#define bfin_write_PORTHIO_BOTH(val) bfin_write16(PORTHIO_BOTH,val)
+#define bfin_read_PORTHIO_INEN() bfin_read16(PORTHIO_INEN)
+#define bfin_write_PORTHIO_INEN(val) bfin_write16(PORTHIO_INEN,val)
+
+/* UART1 Controller (0xFFC02000 - 0xFFC020FF) */
+#define bfin_read_UART1_THR() bfin_read16(UART1_THR)
+#define bfin_write_UART1_THR(val) bfin_write16(UART1_THR,val)
+#define bfin_read_UART1_RBR() bfin_read16(UART1_RBR)
+#define bfin_write_UART1_RBR(val) bfin_write16(UART1_RBR,val)
+#define bfin_read_UART1_DLL() bfin_read16(UART1_DLL)
+#define bfin_write_UART1_DLL(val) bfin_write16(UART1_DLL,val)
+#define bfin_read_UART1_IER() bfin_read16(UART1_IER)
+#define bfin_write_UART1_IER(val) bfin_write16(UART1_IER,val)
+#define bfin_read_UART1_DLH() bfin_read16(UART1_DLH)
+#define bfin_write_UART1_DLH(val) bfin_write16(UART1_DLH,val)
+#define bfin_read_UART1_IIR() bfin_read16(UART1_IIR)
+#define bfin_write_UART1_IIR(val) bfin_write16(UART1_IIR,val)
+#define bfin_read_UART1_LCR() bfin_read16(UART1_LCR)
+#define bfin_write_UART1_LCR(val) bfin_write16(UART1_LCR,val)
+#define bfin_read_UART1_MCR() bfin_read16(UART1_MCR)
+#define bfin_write_UART1_MCR(val) bfin_write16(UART1_MCR,val)
+#define bfin_read_UART1_LSR() bfin_read16(UART1_LSR)
+#define bfin_write_UART1_LSR(val) bfin_write16(UART1_LSR,val)
+#define bfin_read_UART1_MSR() bfin_read16(UART1_MSR)
+#define bfin_write_UART1_MSR(val) bfin_write16(UART1_MSR,val)
+#define bfin_read_UART1_SCR() bfin_read16(UART1_SCR)
+#define bfin_write_UART1_SCR(val) bfin_write16(UART1_SCR,val)
+#define bfin_read_UART1_GCTL() bfin_read16(UART1_GCTL)
+#define bfin_write_UART1_GCTL(val) bfin_write16(UART1_GCTL,val)
+
+/* CAN Controller (0xFFC02A00 - 0xFFC02FFF) */
+/* For Mailboxes 0-15 */
+#define bfin_read_CAN_MC1() bfin_read16(CAN_MC1)
+#define bfin_write_CAN_MC1(val) bfin_write16(CAN_MC1,val)
+#define bfin_read_CAN_MD1() bfin_read16(CAN_MD1)
+#define bfin_write_CAN_MD1(val) bfin_write16(CAN_MD1,val)
+#define bfin_read_CAN_TRS1() bfin_read16(CAN_TRS1)
+#define bfin_write_CAN_TRS1(val) bfin_write16(CAN_TRS1,val)
+#define bfin_read_CAN_TRR1() bfin_read16(CAN_TRR1)
+#define bfin_write_CAN_TRR1(val) bfin_write16(CAN_TRR1,val)
+#define bfin_read_CAN_TA1() bfin_read16(CAN_TA1)
+#define bfin_write_CAN_TA1(val) bfin_write16(CAN_TA1,val)
+#define bfin_read_CAN_AA1() bfin_read16(CAN_AA1)
+#define bfin_write_CAN_AA1(val) bfin_write16(CAN_AA1,val)
+#define bfin_read_CAN_RMP1() bfin_read16(CAN_RMP1)
+#define bfin_write_CAN_RMP1(val) bfin_write16(CAN_RMP1,val)
+#define bfin_read_CAN_RML1() bfin_read16(CAN_RML1)
+#define bfin_write_CAN_RML1(val) bfin_write16(CAN_RML1,val)
+#define bfin_read_CAN_MBTIF1() bfin_read16(CAN_MBTIF1)
+#define bfin_write_CAN_MBTIF1(val) bfin_write16(CAN_MBTIF1,val)
+#define bfin_read_CAN_MBRIF1() bfin_read16(CAN_MBRIF1)
+#define bfin_write_CAN_MBRIF1(val) bfin_write16(CAN_MBRIF1,val)
+#define bfin_read_CAN_MBIM1() bfin_read16(CAN_MBIM1)
+#define bfin_write_CAN_MBIM1(val) bfin_write16(CAN_MBIM1,val)
+#define bfin_read_CAN_RFH1() bfin_read16(CAN_RFH1)
+#define bfin_write_CAN_RFH1(val) bfin_write16(CAN_RFH1,val)
+#define bfin_read_CAN_OPSS1() bfin_read16(CAN_OPSS1)
+#define bfin_write_CAN_OPSS1(val) bfin_write16(CAN_OPSS1,val)
+
+/* For Mailboxes 16-31 */
+#define bfin_read_CAN_MC2() bfin_read16(CAN_MC2)
+#define bfin_write_CAN_MC2(val) bfin_write16(CAN_MC2,val)
+#define bfin_read_CAN_MD2() bfin_read16(CAN_MD2)
+#define bfin_write_CAN_MD2(val) bfin_write16(CAN_MD2,val)
+#define bfin_read_CAN_TRS2() bfin_read16(CAN_TRS2)
+#define bfin_write_CAN_TRS2(val) bfin_write16(CAN_TRS2,val)
+#define bfin_read_CAN_TRR2() bfin_read16(CAN_TRR2)
+#define bfin_write_CAN_TRR2(val) bfin_write16(CAN_TRR2,val)
+#define bfin_read_CAN_TA2() bfin_read16(CAN_TA2)
+#define bfin_write_CAN_TA2(val) bfin_write16(CAN_TA2,val)
+#define bfin_read_CAN_AA2() bfin_read16(CAN_AA2)
+#define bfin_write_CAN_AA2(val) bfin_write16(CAN_AA2,val)
+#define bfin_read_CAN_RMP2() bfin_read16(CAN_RMP2)
+#define bfin_write_CAN_RMP2(val) bfin_write16(CAN_RMP2,val)
+#define bfin_read_CAN_RML2() bfin_read16(CAN_RML2)
+#define bfin_write_CAN_RML2(val) bfin_write16(CAN_RML2,val)
+#define bfin_read_CAN_MBTIF2() bfin_read16(CAN_MBTIF2)
+#define bfin_write_CAN_MBTIF2(val) bfin_write16(CAN_MBTIF2,val)
+#define bfin_read_CAN_MBRIF2() bfin_read16(CAN_MBRIF2)
+#define bfin_write_CAN_MBRIF2(val) bfin_write16(CAN_MBRIF2,val)
+#define bfin_read_CAN_MBIM2() bfin_read16(CAN_MBIM2)
+#define bfin_write_CAN_MBIM2(val) bfin_write16(CAN_MBIM2,val)
+#define bfin_read_CAN_RFH2() bfin_read16(CAN_RFH2)
+#define bfin_write_CAN_RFH2(val) bfin_write16(CAN_RFH2,val)
+#define bfin_read_CAN_OPSS2() bfin_read16(CAN_OPSS2)
+#define bfin_write_CAN_OPSS2(val) bfin_write16(CAN_OPSS2,val)
+
+#define bfin_read_CAN_CLOCK() bfin_read16(CAN_CLOCK)
+#define bfin_write_CAN_CLOCK(val) bfin_write16(CAN_CLOCK,val)
+#define bfin_read_CAN_TIMING() bfin_read16(CAN_TIMING)
+#define bfin_write_CAN_TIMING(val) bfin_write16(CAN_TIMING,val)
+#define bfin_read_CAN_DEBUG() bfin_read16(CAN_DEBUG)
+#define bfin_write_CAN_DEBUG(val) bfin_write16(CAN_DEBUG,val)
+#define bfin_read_CAN_STATUS() bfin_read16(CAN_STATUS)
+#define bfin_write_CAN_STATUS(val) bfin_write16(CAN_STATUS,val)
+#define bfin_read_CAN_CEC() bfin_read16(CAN_CEC)
+#define bfin_write_CAN_CEC(val) bfin_write16(CAN_CEC,val)
+#define bfin_read_CAN_GIS() bfin_read16(CAN_GIS)
+#define bfin_write_CAN_GIS(val) bfin_write16(CAN_GIS,val)
+#define bfin_read_CAN_GIM() bfin_read16(CAN_GIM)
+#define bfin_write_CAN_GIM(val) bfin_write16(CAN_GIM,val)
+#define bfin_read_CAN_GIF() bfin_read16(CAN_GIF)
+#define bfin_write_CAN_GIF(val) bfin_write16(CAN_GIF,val)
+#define bfin_read_CAN_CONTROL() bfin_read16(CAN_CONTROL)
+#define bfin_write_CAN_CONTROL(val) bfin_write16(CAN_CONTROL,val)
+#define bfin_read_CAN_INTR() bfin_read16(CAN_INTR)
+#define bfin_write_CAN_INTR(val) bfin_write16(CAN_INTR,val)
+#define bfin_read_CAN_SFCMVER() bfin_read16(CAN_SFCMVER)
+#define bfin_write_CAN_SFCMVER(val) bfin_write16(CAN_SFCMVER,val)
+#define bfin_read_CAN_MBTD() bfin_read16(CAN_MBTD)
+#define bfin_write_CAN_MBTD(val) bfin_write16(CAN_MBTD,val)
+#define bfin_read_CAN_EWR() bfin_read16(CAN_EWR)
+#define bfin_write_CAN_EWR(val) bfin_write16(CAN_EWR,val)
+#define bfin_read_CAN_ESR() bfin_read16(CAN_ESR)
+#define bfin_write_CAN_ESR(val) bfin_write16(CAN_ESR,val)
+#define bfin_read_CAN_UCREG() bfin_read16(CAN_UCREG)
+#define bfin_write_CAN_UCREG(val) bfin_write16(CAN_UCREG,val)
+#define bfin_read_CAN_UCCNT() bfin_read16(CAN_UCCNT)
+#define bfin_write_CAN_UCCNT(val) bfin_write16(CAN_UCCNT,val)
+#define bfin_read_CAN_UCRC() bfin_read16(CAN_UCRC)
+#define bfin_write_CAN_UCRC(val) bfin_write16(CAN_UCRC,val)
+#define bfin_read_CAN_UCCNF() bfin_read16(CAN_UCCNF)
+#define bfin_write_CAN_UCCNF(val) bfin_write16(CAN_UCCNF,val)
+#define bfin_read_CAN_SFCMVER2() bfin_read16(CAN_SFCMVER2)
+#define bfin_write_CAN_SFCMVER2(val) bfin_write16(CAN_SFCMVER2,val)
+
+/* Mailbox Acceptance Masks */
+#define bfin_read_CAN_AM00L() bfin_read16(CAN_AM00L)
+#define bfin_write_CAN_AM00L(val) bfin_write16(CAN_AM00L,val)
+#define bfin_read_CAN_AM00H() bfin_read16(CAN_AM00H)
+#define bfin_write_CAN_AM00H(val) bfin_write16(CAN_AM00H,val)
+#define bfin_read_CAN_AM01L() bfin_read16(CAN_AM01L)
+#define bfin_write_CAN_AM01L(val) bfin_write16(CAN_AM01L,val)
+#define bfin_read_CAN_AM01H() bfin_read16(CAN_AM01H)
+#define bfin_write_CAN_AM01H(val) bfin_write16(CAN_AM01H,val)
+#define bfin_read_CAN_AM02L() bfin_read16(CAN_AM02L)
+#define bfin_write_CAN_AM02L(val) bfin_write16(CAN_AM02L,val)
+#define bfin_read_CAN_AM02H() bfin_read16(CAN_AM02H)
+#define bfin_write_CAN_AM02H(val) bfin_write16(CAN_AM02H,val)
+#define bfin_read_CAN_AM03L() bfin_read16(CAN_AM03L)
+#define bfin_write_CAN_AM03L(val) bfin_write16(CAN_AM03L,val)
+#define bfin_read_CAN_AM03H() bfin_read16(CAN_AM03H)
+#define bfin_write_CAN_AM03H(val) bfin_write16(CAN_AM03H,val)
+#define bfin_read_CAN_AM04L() bfin_read16(CAN_AM04L)
+#define bfin_write_CAN_AM04L(val) bfin_write16(CAN_AM04L,val)
+#define bfin_read_CAN_AM04H() bfin_read16(CAN_AM04H)
+#define bfin_write_CAN_AM04H(val) bfin_write16(CAN_AM04H,val)
+#define bfin_read_CAN_AM05L() bfin_read16(CAN_AM05L)
+#define bfin_write_CAN_AM05L(val) bfin_write16(CAN_AM05L,val)
+#define bfin_read_CAN_AM05H() bfin_read16(CAN_AM05H)
+#define bfin_write_CAN_AM05H(val) bfin_write16(CAN_AM05H,val)
+#define bfin_read_CAN_AM06L() bfin_read16(CAN_AM06L)
+#define bfin_write_CAN_AM06L(val) bfin_write16(CAN_AM06L,val)
+#define bfin_read_CAN_AM06H() bfin_read16(CAN_AM06H)
+#define bfin_write_CAN_AM06H(val) bfin_write16(CAN_AM06H,val)
+#define bfin_read_CAN_AM07L() bfin_read16(CAN_AM07L)
+#define bfin_write_CAN_AM07L(val) bfin_write16(CAN_AM07L,val)
+#define bfin_read_CAN_AM07H() bfin_read16(CAN_AM07H)
+#define bfin_write_CAN_AM07H(val) bfin_write16(CAN_AM07H,val)
+#define bfin_read_CAN_AM08L() bfin_read16(CAN_AM08L)
+#define bfin_write_CAN_AM08L(val) bfin_write16(CAN_AM08L,val)
+#define bfin_read_CAN_AM08H() bfin_read16(CAN_AM08H)
+#define bfin_write_CAN_AM08H(val) bfin_write16(CAN_AM08H,val)
+#define bfin_read_CAN_AM09L() bfin_read16(CAN_AM09L)
+#define bfin_write_CAN_AM09L(val) bfin_write16(CAN_AM09L,val)
+#define bfin_read_CAN_AM09H() bfin_read16(CAN_AM09H)
+#define bfin_write_CAN_AM09H(val) bfin_write16(CAN_AM09H,val)
+#define bfin_read_CAN_AM10L() bfin_read16(CAN_AM10L)
+#define bfin_write_CAN_AM10L(val) bfin_write16(CAN_AM10L,val)
+#define bfin_read_CAN_AM10H() bfin_read16(CAN_AM10H)
+#define bfin_write_CAN_AM10H(val) bfin_write16(CAN_AM10H,val)
+#define bfin_read_CAN_AM11L() bfin_read16(CAN_AM11L)
+#define bfin_write_CAN_AM11L(val) bfin_write16(CAN_AM11L,val)
+#define bfin_read_CAN_AM11H() bfin_read16(CAN_AM11H)
+#define bfin_write_CAN_AM11H(val) bfin_write16(CAN_AM11H,val)
+#define bfin_read_CAN_AM12L() bfin_read16(CAN_AM12L)
+#define bfin_write_CAN_AM12L(val) bfin_write16(CAN_AM12L,val)
+#define bfin_read_CAN_AM12H() bfin_read16(CAN_AM12H)
+#define bfin_write_CAN_AM12H(val) bfin_write16(CAN_AM12H,val)
+#define bfin_read_CAN_AM13L() bfin_read16(CAN_AM13L)
+#define bfin_write_CAN_AM13L(val) bfin_write16(CAN_AM13L,val)
+#define bfin_read_CAN_AM13H() bfin_read16(CAN_AM13H)
+#define bfin_write_CAN_AM13H(val) bfin_write16(CAN_AM13H,val)
+#define bfin_read_CAN_AM14L() bfin_read16(CAN_AM14L)
+#define bfin_write_CAN_AM14L(val) bfin_write16(CAN_AM14L,val)
+#define bfin_read_CAN_AM14H() bfin_read16(CAN_AM14H)
+#define bfin_write_CAN_AM14H(val) bfin_write16(CAN_AM14H,val)
+#define bfin_read_CAN_AM15L() bfin_read16(CAN_AM15L)
+#define bfin_write_CAN_AM15L(val) bfin_write16(CAN_AM15L,val)
+#define bfin_read_CAN_AM15H() bfin_read16(CAN_AM15H)
+#define bfin_write_CAN_AM15H(val) bfin_write16(CAN_AM15H,val)
+
+#define bfin_read_CAN_AM16L() bfin_read16(CAN_AM16L)
+#define bfin_write_CAN_AM16L(val) bfin_write16(CAN_AM16L,val)
+#define bfin_read_CAN_AM16H() bfin_read16(CAN_AM16H)
+#define bfin_write_CAN_AM16H(val) bfin_write16(CAN_AM16H,val)
+#define bfin_read_CAN_AM17L() bfin_read16(CAN_AM17L)
+#define bfin_write_CAN_AM17L(val) bfin_write16(CAN_AM17L,val)
+#define bfin_read_CAN_AM17H() bfin_read16(CAN_AM17H)
+#define bfin_write_CAN_AM17H(val) bfin_write16(CAN_AM17H,val)
+#define bfin_read_CAN_AM18L() bfin_read16(CAN_AM18L)
+#define bfin_write_CAN_AM18L(val) bfin_write16(CAN_AM18L,val)
+#define bfin_read_CAN_AM18H() bfin_read16(CAN_AM18H)
+#define bfin_write_CAN_AM18H(val) bfin_write16(CAN_AM18H,val)
+#define bfin_read_CAN_AM19L() bfin_read16(CAN_AM19L)
+#define bfin_write_CAN_AM19L(val) bfin_write16(CAN_AM19L,val)
+#define bfin_read_CAN_AM19H() bfin_read16(CAN_AM19H)
+#define bfin_write_CAN_AM19H(val) bfin_write16(CAN_AM19H,val)
+#define bfin_read_CAN_AM20L() bfin_read16(CAN_AM20L)
+#define bfin_write_CAN_AM20L(val) bfin_write16(CAN_AM20L,val)
+#define bfin_read_CAN_AM20H() bfin_read16(CAN_AM20H)
+#define bfin_write_CAN_AM20H(val) bfin_write16(CAN_AM20H,val)
+#define bfin_read_CAN_AM21L() bfin_read16(CAN_AM21L)
+#define bfin_write_CAN_AM21L(val) bfin_write16(CAN_AM21L,val)
+#define bfin_read_CAN_AM21H() bfin_read16(CAN_AM21H)
+#define bfin_write_CAN_AM21H(val) bfin_write16(CAN_AM21H,val)
+#define bfin_read_CAN_AM22L() bfin_read16(CAN_AM22L)
+#define bfin_write_CAN_AM22L(val) bfin_write16(CAN_AM22L,val)
+#define bfin_read_CAN_AM22H() bfin_read16(CAN_AM22H)
+#define bfin_write_CAN_AM22H(val) bfin_write16(CAN_AM22H,val)
+#define bfin_read_CAN_AM23L() bfin_read16(CAN_AM23L)
+#define bfin_write_CAN_AM23L(val) bfin_write16(CAN_AM23L,val)
+#define bfin_read_CAN_AM23H() bfin_read16(CAN_AM23H)
+#define bfin_write_CAN_AM23H(val) bfin_write16(CAN_AM23H,val)
+#define bfin_read_CAN_AM24L() bfin_read16(CAN_AM24L)
+#define bfin_write_CAN_AM24L(val) bfin_write16(CAN_AM24L,val)
+#define bfin_read_CAN_AM24H() bfin_read16(CAN_AM24H)
+#define bfin_write_CAN_AM24H(val) bfin_write16(CAN_AM24H,val)
+#define bfin_read_CAN_AM25L() bfin_read16(CAN_AM25L)
+#define bfin_write_CAN_AM25L(val) bfin_write16(CAN_AM25L,val)
+#define bfin_read_CAN_AM25H() bfin_read16(CAN_AM25H)
+#define bfin_write_CAN_AM25H(val) bfin_write16(CAN_AM25H,val)
+#define bfin_read_CAN_AM26L() bfin_read16(CAN_AM26L)
+#define bfin_write_CAN_AM26L(val) bfin_write16(CAN_AM26L,val)
+#define bfin_read_CAN_AM26H() bfin_read16(CAN_AM26H)
+#define bfin_write_CAN_AM26H(val) bfin_write16(CAN_AM26H,val)
+#define bfin_read_CAN_AM27L() bfin_read16(CAN_AM27L)
+#define bfin_write_CAN_AM27L(val) bfin_write16(CAN_AM27L,val)
+#define bfin_read_CAN_AM27H() bfin_read16(CAN_AM27H)
+#define bfin_write_CAN_AM27H(val) bfin_write16(CAN_AM27H,val)
+#define bfin_read_CAN_AM28L() bfin_read16(CAN_AM28L)
+#define bfin_write_CAN_AM28L(val) bfin_write16(CAN_AM28L,val)
+#define bfin_read_CAN_AM28H() bfin_read16(CAN_AM28H)
+#define bfin_write_CAN_AM28H(val) bfin_write16(CAN_AM28H,val)
+#define bfin_read_CAN_AM29L() bfin_read16(CAN_AM29L)
+#define bfin_write_CAN_AM29L(val) bfin_write16(CAN_AM29L,val)
+#define bfin_read_CAN_AM29H() bfin_read16(CAN_AM29H)
+#define bfin_write_CAN_AM29H(val) bfin_write16(CAN_AM29H,val)
+#define bfin_read_CAN_AM30L() bfin_read16(CAN_AM30L)
+#define bfin_write_CAN_AM30L(val) bfin_write16(CAN_AM30L,val)
+#define bfin_read_CAN_AM30H() bfin_read16(CAN_AM30H)
+#define bfin_write_CAN_AM30H(val) bfin_write16(CAN_AM30H,val)
+#define bfin_read_CAN_AM31L() bfin_read16(CAN_AM31L)
+#define bfin_write_CAN_AM31L(val) bfin_write16(CAN_AM31L,val)
+#define bfin_read_CAN_AM31H() bfin_read16(CAN_AM31H)
+#define bfin_write_CAN_AM31H(val) bfin_write16(CAN_AM31H,val)
+
+/* CAN Acceptance Mask Area Macros */
+#define bfin_read_CAN_AM_L(x)() bfin_read16(CAN_AM_L(x))
+#define bfin_write_CAN_AM_L(x)(val) bfin_write16(CAN_AM_L(x),val)
+#define bfin_read_CAN_AM_H(x)() bfin_read16(CAN_AM_H(x))
+#define bfin_write_CAN_AM_H(x)(val) bfin_write16(CAN_AM_H(x),val)
+
+/* Mailbox Registers */
+#define bfin_read_CAN_MB00_ID1() bfin_read16(CAN_MB00_ID1)
+#define bfin_write_CAN_MB00_ID1(val) bfin_write16(CAN_MB00_ID1,val)
+#define bfin_read_CAN_MB00_ID0() bfin_read16(CAN_MB00_ID0)
+#define bfin_write_CAN_MB00_ID0(val) bfin_write16(CAN_MB00_ID0,val)
+#define bfin_read_CAN_MB00_TIMESTAMP() bfin_read16(CAN_MB00_TIMESTAMP)
+#define bfin_write_CAN_MB00_TIMESTAMP(val) bfin_write16(CAN_MB00_TIMESTAMP,val)
+#define bfin_read_CAN_MB00_LENGTH() bfin_read16(CAN_MB00_LENGTH)
+#define bfin_write_CAN_MB00_LENGTH(val) bfin_write16(CAN_MB00_LENGTH,val)
+#define bfin_read_CAN_MB00_DATA3() bfin_read16(CAN_MB00_DATA3)
+#define bfin_write_CAN_MB00_DATA3(val) bfin_write16(CAN_MB00_DATA3,val)
+#define bfin_read_CAN_MB00_DATA2() bfin_read16(CAN_MB00_DATA2)
+#define bfin_write_CAN_MB00_DATA2(val) bfin_write16(CAN_MB00_DATA2,val)
+#define bfin_read_CAN_MB00_DATA1() bfin_read16(CAN_MB00_DATA1)
+#define bfin_write_CAN_MB00_DATA1(val) bfin_write16(CAN_MB00_DATA1,val)
+#define bfin_read_CAN_MB00_DATA0() bfin_read16(CAN_MB00_DATA0)
+#define bfin_write_CAN_MB00_DATA0(val) bfin_write16(CAN_MB00_DATA0,val)
+
+#define bfin_read_CAN_MB01_ID1() bfin_read16(CAN_MB01_ID1)
+#define bfin_write_CAN_MB01_ID1(val) bfin_write16(CAN_MB01_ID1,val)
+#define bfin_read_CAN_MB01_ID0() bfin_read16(CAN_MB01_ID0)
+#define bfin_write_CAN_MB01_ID0(val) bfin_write16(CAN_MB01_ID0,val)
+#define bfin_read_CAN_MB01_TIMESTAMP() bfin_read16(CAN_MB01_TIMESTAMP)
+#define bfin_write_CAN_MB01_TIMESTAMP(val) bfin_write16(CAN_MB01_TIMESTAMP,val)
+#define bfin_read_CAN_MB01_LENGTH() bfin_read16(CAN_MB01_LENGTH)
+#define bfin_write_CAN_MB01_LENGTH(val) bfin_write16(CAN_MB01_LENGTH,val)
+#define bfin_read_CAN_MB01_DATA3() bfin_read16(CAN_MB01_DATA3)
+#define bfin_write_CAN_MB01_DATA3(val) bfin_write16(CAN_MB01_DATA3,val)
+#define bfin_read_CAN_MB01_DATA2() bfin_read16(CAN_MB01_DATA2)
+#define bfin_write_CAN_MB01_DATA2(val) bfin_write16(CAN_MB01_DATA2,val)
+#define bfin_read_CAN_MB01_DATA1() bfin_read16(CAN_MB01_DATA1)
+#define bfin_write_CAN_MB01_DATA1(val) bfin_write16(CAN_MB01_DATA1,val)
+#define bfin_read_CAN_MB01_DATA0() bfin_read16(CAN_MB01_DATA0)
+#define bfin_write_CAN_MB01_DATA0(val) bfin_write16(CAN_MB01_DATA0,val)
+
+#define bfin_read_CAN_MB02_ID1() bfin_read16(CAN_MB02_ID1)
+#define bfin_write_CAN_MB02_ID1(val) bfin_write16(CAN_MB02_ID1,val)
+#define bfin_read_CAN_MB02_ID0() bfin_read16(CAN_MB02_ID0)
+#define bfin_write_CAN_MB02_ID0(val) bfin_write16(CAN_MB02_ID0,val)
+#define bfin_read_CAN_MB02_TIMESTAMP() bfin_read16(CAN_MB02_TIMESTAMP)
+#define bfin_write_CAN_MB02_TIMESTAMP(val) bfin_write16(CAN_MB02_TIMESTAMP,val)
+#define bfin_read_CAN_MB02_LENGTH() bfin_read16(CAN_MB02_LENGTH)
+#define bfin_write_CAN_MB02_LENGTH(val) bfin_write16(CAN_MB02_LENGTH,val)
+#define bfin_read_CAN_MB02_DATA3() bfin_read16(CAN_MB02_DATA3)
+#define bfin_write_CAN_MB02_DATA3(val) bfin_write16(CAN_MB02_DATA3,val)
+#define bfin_read_CAN_MB02_DATA2() bfin_read16(CAN_MB02_DATA2)
+#define bfin_write_CAN_MB02_DATA2(val) bfin_write16(CAN_MB02_DATA2,val)
+#define bfin_read_CAN_MB02_DATA1() bfin_read16(CAN_MB02_DATA1)
+#define bfin_write_CAN_MB02_DATA1(val) bfin_write16(CAN_MB02_DATA1,val)
+#define bfin_read_CAN_MB02_DATA0() bfin_read16(CAN_MB02_DATA0)
+#define bfin_write_CAN_MB02_DATA0(val) bfin_write16(CAN_MB02_DATA0,val)
+
+#define bfin_read_CAN_MB03_ID1() bfin_read16(CAN_MB03_ID1)
+#define bfin_write_CAN_MB03_ID1(val) bfin_write16(CAN_MB03_ID1,val)
+#define bfin_read_CAN_MB03_ID0() bfin_read16(CAN_MB03_ID0)
+#define bfin_write_CAN_MB03_ID0(val) bfin_write16(CAN_MB03_ID0,val)
+#define bfin_read_CAN_MB03_TIMESTAMP() bfin_read16(CAN_MB03_TIMESTAMP)
+#define bfin_write_CAN_MB03_TIMESTAMP(val) bfin_write16(CAN_MB03_TIMESTAMP,val)
+#define bfin_read_CAN_MB03_LENGTH() bfin_read16(CAN_MB03_LENGTH)
+#define bfin_write_CAN_MB03_LENGTH(val) bfin_write16(CAN_MB03_LENGTH,val)
+#define bfin_read_CAN_MB03_DATA3() bfin_read16(CAN_MB03_DATA3)
+#define bfin_write_CAN_MB03_DATA3(val) bfin_write16(CAN_MB03_DATA3,val)
+#define bfin_read_CAN_MB03_DATA2() bfin_read16(CAN_MB03_DATA2)
+#define bfin_write_CAN_MB03_DATA2(val) bfin_write16(CAN_MB03_DATA2,val)
+#define bfin_read_CAN_MB03_DATA1() bfin_read16(CAN_MB03_DATA1)
+#define bfin_write_CAN_MB03_DATA1(val) bfin_write16(CAN_MB03_DATA1,val)
+#define bfin_read_CAN_MB03_DATA0() bfin_read16(CAN_MB03_DATA0)
+#define bfin_write_CAN_MB03_DATA0(val) bfin_write16(CAN_MB03_DATA0,val)
+
+#define bfin_read_CAN_MB04_ID1() bfin_read16(CAN_MB04_ID1)
+#define bfin_write_CAN_MB04_ID1(val) bfin_write16(CAN_MB04_ID1,val)
+#define bfin_read_CAN_MB04_ID0() bfin_read16(CAN_MB04_ID0)
+#define bfin_write_CAN_MB04_ID0(val) bfin_write16(CAN_MB04_ID0,val)
+#define bfin_read_CAN_MB04_TIMESTAMP() bfin_read16(CAN_MB04_TIMESTAMP)
+#define bfin_write_CAN_MB04_TIMESTAMP(val) bfin_write16(CAN_MB04_TIMESTAMP,val)
+#define bfin_read_CAN_MB04_LENGTH() bfin_read16(CAN_MB04_LENGTH)
+#define bfin_write_CAN_MB04_LENGTH(val) bfin_write16(CAN_MB04_LENGTH,val)
+#define bfin_read_CAN_MB04_DATA3() bfin_read16(CAN_MB04_DATA3)
+#define bfin_write_CAN_MB04_DATA3(val) bfin_write16(CAN_MB04_DATA3,val)
+#define bfin_read_CAN_MB04_DATA2() bfin_read16(CAN_MB04_DATA2)
+#define bfin_write_CAN_MB04_DATA2(val) bfin_write16(CAN_MB04_DATA2,val)
+#define bfin_read_CAN_MB04_DATA1() bfin_read16(CAN_MB04_DATA1)
+#define bfin_write_CAN_MB04_DATA1(val) bfin_write16(CAN_MB04_DATA1,val)
+#define bfin_read_CAN_MB04_DATA0() bfin_read16(CAN_MB04_DATA0)
+#define bfin_write_CAN_MB04_DATA0(val) bfin_write16(CAN_MB04_DATA0,val)
+
+#define bfin_read_CAN_MB05_ID1() bfin_read16(CAN_MB05_ID1)
+#define bfin_write_CAN_MB05_ID1(val) bfin_write16(CAN_MB05_ID1,val)
+#define bfin_read_CAN_MB05_ID0() bfin_read16(CAN_MB05_ID0)
+#define bfin_write_CAN_MB05_ID0(val) bfin_write16(CAN_MB05_ID0,val)
+#define bfin_read_CAN_MB05_TIMESTAMP() bfin_read16(CAN_MB05_TIMESTAMP)
+#define bfin_write_CAN_MB05_TIMESTAMP(val) bfin_write16(CAN_MB05_TIMESTAMP,val)
+#define bfin_read_CAN_MB05_LENGTH() bfin_read16(CAN_MB05_LENGTH)
+#define bfin_write_CAN_MB05_LENGTH(val) bfin_write16(CAN_MB05_LENGTH,val)
+#define bfin_read_CAN_MB05_DATA3() bfin_read16(CAN_MB05_DATA3)
+#define bfin_write_CAN_MB05_DATA3(val) bfin_write16(CAN_MB05_DATA3,val)
+#define bfin_read_CAN_MB05_DATA2() bfin_read16(CAN_MB05_DATA2)
+#define bfin_write_CAN_MB05_DATA2(val) bfin_write16(CAN_MB05_DATA2,val)
+#define bfin_read_CAN_MB05_DATA1() bfin_read16(CAN_MB05_DATA1)
+#define bfin_write_CAN_MB05_DATA1(val) bfin_write16(CAN_MB05_DATA1,val)
+#define bfin_read_CAN_MB05_DATA0() bfin_read16(CAN_MB05_DATA0)
+#define bfin_write_CAN_MB05_DATA0(val) bfin_write16(CAN_MB05_DATA0,val)
+
+#define bfin_read_CAN_MB06_ID1() bfin_read16(CAN_MB06_ID1)
+#define bfin_write_CAN_MB06_ID1(val) bfin_write16(CAN_MB06_ID1,val)
+#define bfin_read_CAN_MB06_ID0() bfin_read16(CAN_MB06_ID0)
+#define bfin_write_CAN_MB06_ID0(val) bfin_write16(CAN_MB06_ID0,val)
+#define bfin_read_CAN_MB06_TIMESTAMP() bfin_read16(CAN_MB06_TIMESTAMP)
+#define bfin_write_CAN_MB06_TIMESTAMP(val) bfin_write16(CAN_MB06_TIMESTAMP,val)
+#define bfin_read_CAN_MB06_LENGTH() bfin_read16(CAN_MB06_LENGTH)
+#define bfin_write_CAN_MB06_LENGTH(val) bfin_write16(CAN_MB06_LENGTH,val)
+#define bfin_read_CAN_MB06_DATA3() bfin_read16(CAN_MB06_DATA3)
+#define bfin_write_CAN_MB06_DATA3(val) bfin_write16(CAN_MB06_DATA3,val)
+#define bfin_read_CAN_MB06_DATA2() bfin_read16(CAN_MB06_DATA2)
+#define bfin_write_CAN_MB06_DATA2(val) bfin_write16(CAN_MB06_DATA2,val)
+#define bfin_read_CAN_MB06_DATA1() bfin_read16(CAN_MB06_DATA1)
+#define bfin_write_CAN_MB06_DATA1(val) bfin_write16(CAN_MB06_DATA1,val)
+#define bfin_read_CAN_MB06_DATA0() bfin_read16(CAN_MB06_DATA0)
+#define bfin_write_CAN_MB06_DATA0(val) bfin_write16(CAN_MB06_DATA0,val)
+
+#define bfin_read_CAN_MB07_ID1() bfin_read16(CAN_MB07_ID1)
+#define bfin_write_CAN_MB07_ID1(val) bfin_write16(CAN_MB07_ID1,val)
+#define bfin_read_CAN_MB07_ID0() bfin_read16(CAN_MB07_ID0)
+#define bfin_write_CAN_MB07_ID0(val) bfin_write16(CAN_MB07_ID0,val)
+#define bfin_read_CAN_MB07_TIMESTAMP() bfin_read16(CAN_MB07_TIMESTAMP)
+#define bfin_write_CAN_MB07_TIMESTAMP(val) bfin_write16(CAN_MB07_TIMESTAMP,val)
+#define bfin_read_CAN_MB07_LENGTH() bfin_read16(CAN_MB07_LENGTH)
+#define bfin_write_CAN_MB07_LENGTH(val) bfin_write16(CAN_MB07_LENGTH,val)
+#define bfin_read_CAN_MB07_DATA3() bfin_read16(CAN_MB07_DATA3)
+#define bfin_write_CAN_MB07_DATA3(val) bfin_write16(CAN_MB07_DATA3,val)
+#define bfin_read_CAN_MB07_DATA2() bfin_read16(CAN_MB07_DATA2)
+#define bfin_write_CAN_MB07_DATA2(val) bfin_write16(CAN_MB07_DATA2,val)
+#define bfin_read_CAN_MB07_DATA1() bfin_read16(CAN_MB07_DATA1)
+#define bfin_write_CAN_MB07_DATA1(val) bfin_write16(CAN_MB07_DATA1,val)
+#define bfin_read_CAN_MB07_DATA0() bfin_read16(CAN_MB07_DATA0)
+#define bfin_write_CAN_MB07_DATA0(val) bfin_write16(CAN_MB07_DATA0,val)
+
+#define bfin_read_CAN_MB08_ID1() bfin_read16(CAN_MB08_ID1)
+#define bfin_write_CAN_MB08_ID1(val) bfin_write16(CAN_MB08_ID1,val)
+#define bfin_read_CAN_MB08_ID0() bfin_read16(CAN_MB08_ID0)
+#define bfin_write_CAN_MB08_ID0(val) bfin_write16(CAN_MB08_ID0,val)
+#define bfin_read_CAN_MB08_TIMESTAMP() bfin_read16(CAN_MB08_TIMESTAMP)
+#define bfin_write_CAN_MB08_TIMESTAMP(val) bfin_write16(CAN_MB08_TIMESTAMP,val)
+#define bfin_read_CAN_MB08_LENGTH() bfin_read16(CAN_MB08_LENGTH)
+#define bfin_write_CAN_MB08_LENGTH(val) bfin_write16(CAN_MB08_LENGTH,val)
+#define bfin_read_CAN_MB08_DATA3() bfin_read16(CAN_MB08_DATA3)
+#define bfin_write_CAN_MB08_DATA3(val) bfin_write16(CAN_MB08_DATA3,val)
+#define bfin_read_CAN_MB08_DATA2() bfin_read16(CAN_MB08_DATA2)
+#define bfin_write_CAN_MB08_DATA2(val) bfin_write16(CAN_MB08_DATA2,val)
+#define bfin_read_CAN_MB08_DATA1() bfin_read16(CAN_MB08_DATA1)
+#define bfin_write_CAN_MB08_DATA1(val) bfin_write16(CAN_MB08_DATA1,val)
+#define bfin_read_CAN_MB08_DATA0() bfin_read16(CAN_MB08_DATA0)
+#define bfin_write_CAN_MB08_DATA0(val) bfin_write16(CAN_MB08_DATA0,val)
+
+#define bfin_read_CAN_MB09_ID1() bfin_read16(CAN_MB09_ID1)
+#define bfin_write_CAN_MB09_ID1(val) bfin_write16(CAN_MB09_ID1,val)
+#define bfin_read_CAN_MB09_ID0() bfin_read16(CAN_MB09_ID0)
+#define bfin_write_CAN_MB09_ID0(val) bfin_write16(CAN_MB09_ID0,val)
+#define bfin_read_CAN_MB09_TIMESTAMP() bfin_read16(CAN_MB09_TIMESTAMP)
+#define bfin_write_CAN_MB09_TIMESTAMP(val) bfin_write16(CAN_MB09_TIMESTAMP,val)
+#define bfin_read_CAN_MB09_LENGTH() bfin_read16(CAN_MB09_LENGTH)
+#define bfin_write_CAN_MB09_LENGTH(val) bfin_write16(CAN_MB09_LENGTH,val)
+#define bfin_read_CAN_MB09_DATA3() bfin_read16(CAN_MB09_DATA3)
+#define bfin_write_CAN_MB09_DATA3(val) bfin_write16(CAN_MB09_DATA3,val)
+#define bfin_read_CAN_MB09_DATA2() bfin_read16(CAN_MB09_DATA2)
+#define bfin_write_CAN_MB09_DATA2(val) bfin_write16(CAN_MB09_DATA2,val)
+#define bfin_read_CAN_MB09_DATA1() bfin_read16(CAN_MB09_DATA1)
+#define bfin_write_CAN_MB09_DATA1(val) bfin_write16(CAN_MB09_DATA1,val)
+#define bfin_read_CAN_MB09_DATA0() bfin_read16(CAN_MB09_DATA0)
+#define bfin_write_CAN_MB09_DATA0(val) bfin_write16(CAN_MB09_DATA0,val)
+
+#define bfin_read_CAN_MB10_ID1() bfin_read16(CAN_MB10_ID1)
+#define bfin_write_CAN_MB10_ID1(val) bfin_write16(CAN_MB10_ID1,val)
+#define bfin_read_CAN_MB10_ID0() bfin_read16(CAN_MB10_ID0)
+#define bfin_write_CAN_MB10_ID0(val) bfin_write16(CAN_MB10_ID0,val)
+#define bfin_read_CAN_MB10_TIMESTAMP() bfin_read16(CAN_MB10_TIMESTAMP)
+#define bfin_write_CAN_MB10_TIMESTAMP(val) bfin_write16(CAN_MB10_TIMESTAMP,val)
+#define bfin_read_CAN_MB10_LENGTH() bfin_read16(CAN_MB10_LENGTH)
+#define bfin_write_CAN_MB10_LENGTH(val) bfin_write16(CAN_MB10_LENGTH,val)
+#define bfin_read_CAN_MB10_DATA3() bfin_read16(CAN_MB10_DATA3)
+#define bfin_write_CAN_MB10_DATA3(val) bfin_write16(CAN_MB10_DATA3,val)
+#define bfin_read_CAN_MB10_DATA2() bfin_read16(CAN_MB10_DATA2)
+#define bfin_write_CAN_MB10_DATA2(val) bfin_write16(CAN_MB10_DATA2,val)
+#define bfin_read_CAN_MB10_DATA1() bfin_read16(CAN_MB10_DATA1)
+#define bfin_write_CAN_MB10_DATA1(val) bfin_write16(CAN_MB10_DATA1,val)
+#define bfin_read_CAN_MB10_DATA0() bfin_read16(CAN_MB10_DATA0)
+#define bfin_write_CAN_MB10_DATA0(val) bfin_write16(CAN_MB10_DATA0,val)
+
+#define bfin_read_CAN_MB11_ID1() bfin_read16(CAN_MB11_ID1)
+#define bfin_write_CAN_MB11_ID1(val) bfin_write16(CAN_MB11_ID1,val)
+#define bfin_read_CAN_MB11_ID0() bfin_read16(CAN_MB11_ID0)
+#define bfin_write_CAN_MB11_ID0(val) bfin_write16(CAN_MB11_ID0,val)
+#define bfin_read_CAN_MB11_TIMESTAMP() bfin_read16(CAN_MB11_TIMESTAMP)
+#define bfin_write_CAN_MB11_TIMESTAMP(val) bfin_write16(CAN_MB11_TIMESTAMP,val)
+#define bfin_read_CAN_MB11_LENGTH() bfin_read16(CAN_MB11_LENGTH)
+#define bfin_write_CAN_MB11_LENGTH(val) bfin_write16(CAN_MB11_LENGTH,val)
+#define bfin_read_CAN_MB11_DATA3() bfin_read16(CAN_MB11_DATA3)
+#define bfin_write_CAN_MB11_DATA3(val) bfin_write16(CAN_MB11_DATA3,val)
+#define bfin_read_CAN_MB11_DATA2() bfin_read16(CAN_MB11_DATA2)
+#define bfin_write_CAN_MB11_DATA2(val) bfin_write16(CAN_MB11_DATA2,val)
+#define bfin_read_CAN_MB11_DATA1() bfin_read16(CAN_MB11_DATA1)
+#define bfin_write_CAN_MB11_DATA1(val) bfin_write16(CAN_MB11_DATA1,val)
+#define bfin_read_CAN_MB11_DATA0() bfin_read16(CAN_MB11_DATA0)
+#define bfin_write_CAN_MB11_DATA0(val) bfin_write16(CAN_MB11_DATA0,val)
+
+#define bfin_read_CAN_MB12_ID1() bfin_read16(CAN_MB12_ID1)
+#define bfin_write_CAN_MB12_ID1(val) bfin_write16(CAN_MB12_ID1,val)
+#define bfin_read_CAN_MB12_ID0() bfin_read16(CAN_MB12_ID0)
+#define bfin_write_CAN_MB12_ID0(val) bfin_write16(CAN_MB12_ID0,val)
+#define bfin_read_CAN_MB12_TIMESTAMP() bfin_read16(CAN_MB12_TIMESTAMP)
+#define bfin_write_CAN_MB12_TIMESTAMP(val) bfin_write16(CAN_MB12_TIMESTAMP,val)
+#define bfin_read_CAN_MB12_LENGTH() bfin_read16(CAN_MB12_LENGTH)
+#define bfin_write_CAN_MB12_LENGTH(val) bfin_write16(CAN_MB12_LENGTH,val)
+#define bfin_read_CAN_MB12_DATA3() bfin_read16(CAN_MB12_DATA3)
+#define bfin_write_CAN_MB12_DATA3(val) bfin_write16(CAN_MB12_DATA3,val)
+#define bfin_read_CAN_MB12_DATA2() bfin_read16(CAN_MB12_DATA2)
+#define bfin_write_CAN_MB12_DATA2(val) bfin_write16(CAN_MB12_DATA2,val)
+#define bfin_read_CAN_MB12_DATA1() bfin_read16(CAN_MB12_DATA1)
+#define bfin_write_CAN_MB12_DATA1(val) bfin_write16(CAN_MB12_DATA1,val)
+#define bfin_read_CAN_MB12_DATA0() bfin_read16(CAN_MB12_DATA0)
+#define bfin_write_CAN_MB12_DATA0(val) bfin_write16(CAN_MB12_DATA0,val)
+
+#define bfin_read_CAN_MB13_ID1() bfin_read16(CAN_MB13_ID1)
+#define bfin_write_CAN_MB13_ID1(val) bfin_write16(CAN_MB13_ID1,val)
+#define bfin_read_CAN_MB13_ID0() bfin_read16(CAN_MB13_ID0)
+#define bfin_write_CAN_MB13_ID0(val) bfin_write16(CAN_MB13_ID0,val)
+#define bfin_read_CAN_MB13_TIMESTAMP() bfin_read16(CAN_MB13_TIMESTAMP)
+#define bfin_write_CAN_MB13_TIMESTAMP(val) bfin_write16(CAN_MB13_TIMESTAMP,val)
+#define bfin_read_CAN_MB13_LENGTH() bfin_read16(CAN_MB13_LENGTH)
+#define bfin_write_CAN_MB13_LENGTH(val) bfin_write16(CAN_MB13_LENGTH,val)
+#define bfin_read_CAN_MB13_DATA3() bfin_read16(CAN_MB13_DATA3)
+#define bfin_write_CAN_MB13_DATA3(val) bfin_write16(CAN_MB13_DATA3,val)
+#define bfin_read_CAN_MB13_DATA2() bfin_read16(CAN_MB13_DATA2)
+#define bfin_write_CAN_MB13_DATA2(val) bfin_write16(CAN_MB13_DATA2,val)
+#define bfin_read_CAN_MB13_DATA1() bfin_read16(CAN_MB13_DATA1)
+#define bfin_write_CAN_MB13_DATA1(val) bfin_write16(CAN_MB13_DATA1,val)
+#define bfin_read_CAN_MB13_DATA0() bfin_read16(CAN_MB13_DATA0)
+#define bfin_write_CAN_MB13_DATA0(val) bfin_write16(CAN_MB13_DATA0,val)
+
+#define bfin_read_CAN_MB14_ID1() bfin_read16(CAN_MB14_ID1)
+#define bfin_write_CAN_MB14_ID1(val) bfin_write16(CAN_MB14_ID1,val)
+#define bfin_read_CAN_MB14_ID0() bfin_read16(CAN_MB14_ID0)
+#define bfin_write_CAN_MB14_ID0(val) bfin_write16(CAN_MB14_ID0,val)
+#define bfin_read_CAN_MB14_TIMESTAMP() bfin_read16(CAN_MB14_TIMESTAMP)
+#define bfin_write_CAN_MB14_TIMESTAMP(val) bfin_write16(CAN_MB14_TIMESTAMP,val)
+#define bfin_read_CAN_MB14_LENGTH() bfin_read16(CAN_MB14_LENGTH)
+#define bfin_write_CAN_MB14_LENGTH(val) bfin_write16(CAN_MB14_LENGTH,val)
+#define bfin_read_CAN_MB14_DATA3() bfin_read16(CAN_MB14_DATA3)
+#define bfin_write_CAN_MB14_DATA3(val) bfin_write16(CAN_MB14_DATA3,val)
+#define bfin_read_CAN_MB14_DATA2() bfin_read16(CAN_MB14_DATA2)
+#define bfin_write_CAN_MB14_DATA2(val) bfin_write16(CAN_MB14_DATA2,val)
+#define bfin_read_CAN_MB14_DATA1() bfin_read16(CAN_MB14_DATA1)
+#define bfin_write_CAN_MB14_DATA1(val) bfin_write16(CAN_MB14_DATA1,val)
+#define bfin_read_CAN_MB14_DATA0() bfin_read16(CAN_MB14_DATA0)
+#define bfin_write_CAN_MB14_DATA0(val) bfin_write16(CAN_MB14_DATA0,val)
+
+#define bfin_read_CAN_MB15_ID1() bfin_read16(CAN_MB15_ID1)
+#define bfin_write_CAN_MB15_ID1(val) bfin_write16(CAN_MB15_ID1,val)
+#define bfin_read_CAN_MB15_ID0() bfin_read16(CAN_MB15_ID0)
+#define bfin_write_CAN_MB15_ID0(val) bfin_write16(CAN_MB15_ID0,val)
+#define bfin_read_CAN_MB15_TIMESTAMP() bfin_read16(CAN_MB15_TIMESTAMP)
+#define bfin_write_CAN_MB15_TIMESTAMP(val) bfin_write16(CAN_MB15_TIMESTAMP,val)
+#define bfin_read_CAN_MB15_LENGTH() bfin_read16(CAN_MB15_LENGTH)
+#define bfin_write_CAN_MB15_LENGTH(val) bfin_write16(CAN_MB15_LENGTH,val)
+#define bfin_read_CAN_MB15_DATA3() bfin_read16(CAN_MB15_DATA3)
+#define bfin_write_CAN_MB15_DATA3(val) bfin_write16(CAN_MB15_DATA3,val)
+#define bfin_read_CAN_MB15_DATA2() bfin_read16(CAN_MB15_DATA2)
+#define bfin_write_CAN_MB15_DATA2(val) bfin_write16(CAN_MB15_DATA2,val)
+#define bfin_read_CAN_MB15_DATA1() bfin_read16(CAN_MB15_DATA1)
+#define bfin_write_CAN_MB15_DATA1(val) bfin_write16(CAN_MB15_DATA1,val)
+#define bfin_read_CAN_MB15_DATA0() bfin_read16(CAN_MB15_DATA0)
+#define bfin_write_CAN_MB15_DATA0(val) bfin_write16(CAN_MB15_DATA0,val)
+
+#define bfin_read_CAN_MB16_ID1() bfin_read16(CAN_MB16_ID1)
+#define bfin_write_CAN_MB16_ID1(val) bfin_write16(CAN_MB16_ID1,val)
+#define bfin_read_CAN_MB16_ID0() bfin_read16(CAN_MB16_ID0)
+#define bfin_write_CAN_MB16_ID0(val) bfin_write16(CAN_MB16_ID0,val)
+#define bfin_read_CAN_MB16_TIMESTAMP() bfin_read16(CAN_MB16_TIMESTAMP)
+#define bfin_write_CAN_MB16_TIMESTAMP(val) bfin_write16(CAN_MB16_TIMESTAMP,val)
+#define bfin_read_CAN_MB16_LENGTH() bfin_read16(CAN_MB16_LENGTH)
+#define bfin_write_CAN_MB16_LENGTH(val) bfin_write16(CAN_MB16_LENGTH,val)
+#define bfin_read_CAN_MB16_DATA3() bfin_read16(CAN_MB16_DATA3)
+#define bfin_write_CAN_MB16_DATA3(val) bfin_write16(CAN_MB16_DATA3,val)
+#define bfin_read_CAN_MB16_DATA2() bfin_read16(CAN_MB16_DATA2)
+#define bfin_write_CAN_MB16_DATA2(val) bfin_write16(CAN_MB16_DATA2,val)
+#define bfin_read_CAN_MB16_DATA1() bfin_read16(CAN_MB16_DATA1)
+#define bfin_write_CAN_MB16_DATA1(val) bfin_write16(CAN_MB16_DATA1,val)
+#define bfin_read_CAN_MB16_DATA0() bfin_read16(CAN_MB16_DATA0)
+#define bfin_write_CAN_MB16_DATA0(val) bfin_write16(CAN_MB16_DATA0,val)
+
+#define bfin_read_CAN_MB17_ID1() bfin_read16(CAN_MB17_ID1)
+#define bfin_write_CAN_MB17_ID1(val) bfin_write16(CAN_MB17_ID1,val)
+#define bfin_read_CAN_MB17_ID0() bfin_read16(CAN_MB17_ID0)
+#define bfin_write_CAN_MB17_ID0(val) bfin_write16(CAN_MB17_ID0,val)
+#define bfin_read_CAN_MB17_TIMESTAMP() bfin_read16(CAN_MB17_TIMESTAMP)
+#define bfin_write_CAN_MB17_TIMESTAMP(val) bfin_write16(CAN_MB17_TIMESTAMP,val)
+#define bfin_read_CAN_MB17_LENGTH() bfin_read16(CAN_MB17_LENGTH)
+#define bfin_write_CAN_MB17_LENGTH(val) bfin_write16(CAN_MB17_LENGTH,val)
+#define bfin_read_CAN_MB17_DATA3() bfin_read16(CAN_MB17_DATA3)
+#define bfin_write_CAN_MB17_DATA3(val) bfin_write16(CAN_MB17_DATA3,val)
+#define bfin_read_CAN_MB17_DATA2() bfin_read16(CAN_MB17_DATA2)
+#define bfin_write_CAN_MB17_DATA2(val) bfin_write16(CAN_MB17_DATA2,val)
+#define bfin_read_CAN_MB17_DATA1() bfin_read16(CAN_MB17_DATA1)
+#define bfin_write_CAN_MB17_DATA1(val) bfin_write16(CAN_MB17_DATA1,val)
+#define bfin_read_CAN_MB17_DATA0() bfin_read16(CAN_MB17_DATA0)
+#define bfin_write_CAN_MB17_DATA0(val) bfin_write16(CAN_MB17_DATA0,val)
+
+#define bfin_read_CAN_MB18_ID1() bfin_read16(CAN_MB18_ID1)
+#define bfin_write_CAN_MB18_ID1(val) bfin_write16(CAN_MB18_ID1,val)
+#define bfin_read_CAN_MB18_ID0() bfin_read16(CAN_MB18_ID0)
+#define bfin_write_CAN_MB18_ID0(val) bfin_write16(CAN_MB18_ID0,val)
+#define bfin_read_CAN_MB18_TIMESTAMP() bfin_read16(CAN_MB18_TIMESTAMP)
+#define bfin_write_CAN_MB18_TIMESTAMP(val) bfin_write16(CAN_MB18_TIMESTAMP,val)
+#define bfin_read_CAN_MB18_LENGTH() bfin_read16(CAN_MB18_LENGTH)
+#define bfin_write_CAN_MB18_LENGTH(val) bfin_write16(CAN_MB18_LENGTH,val)
+#define bfin_read_CAN_MB18_DATA3() bfin_read16(CAN_MB18_DATA3)
+#define bfin_write_CAN_MB18_DATA3(val) bfin_write16(CAN_MB18_DATA3,val)
+#define bfin_read_CAN_MB18_DATA2() bfin_read16(CAN_MB18_DATA2)
+#define bfin_write_CAN_MB18_DATA2(val) bfin_write16(CAN_MB18_DATA2,val)
+#define bfin_read_CAN_MB18_DATA1() bfin_read16(CAN_MB18_DATA1)
+#define bfin_write_CAN_MB18_DATA1(val) bfin_write16(CAN_MB18_DATA1,val)
+#define bfin_read_CAN_MB18_DATA0() bfin_read16(CAN_MB18_DATA0)
+#define bfin_write_CAN_MB18_DATA0(val) bfin_write16(CAN_MB18_DATA0,val)
+
+#define bfin_read_CAN_MB19_ID1() bfin_read16(CAN_MB19_ID1)
+#define bfin_write_CAN_MB19_ID1(val) bfin_write16(CAN_MB19_ID1,val)
+#define bfin_read_CAN_MB19_ID0() bfin_read16(CAN_MB19_ID0)
+#define bfin_write_CAN_MB19_ID0(val) bfin_write16(CAN_MB19_ID0,val)
+#define bfin_read_CAN_MB19_TIMESTAMP() bfin_read16(CAN_MB19_TIMESTAMP)
+#define bfin_write_CAN_MB19_TIMESTAMP(val) bfin_write16(CAN_MB19_TIMESTAMP,val)
+#define bfin_read_CAN_MB19_LENGTH() bfin_read16(CAN_MB19_LENGTH)
+#define bfin_write_CAN_MB19_LENGTH(val) bfin_write16(CAN_MB19_LENGTH,val)
+#define bfin_read_CAN_MB19_DATA3() bfin_read16(CAN_MB19_DATA3)
+#define bfin_write_CAN_MB19_DATA3(val) bfin_write16(CAN_MB19_DATA3,val)
+#define bfin_read_CAN_MB19_DATA2() bfin_read16(CAN_MB19_DATA2)
+#define bfin_write_CAN_MB19_DATA2(val) bfin_write16(CAN_MB19_DATA2,val)
+#define bfin_read_CAN_MB19_DATA1() bfin_read16(CAN_MB19_DATA1)
+#define bfin_write_CAN_MB19_DATA1(val) bfin_write16(CAN_MB19_DATA1,val)
+#define bfin_read_CAN_MB19_DATA0() bfin_read16(CAN_MB19_DATA0)
+#define bfin_write_CAN_MB19_DATA0(val) bfin_write16(CAN_MB19_DATA0,val)
+
+#define bfin_read_CAN_MB20_ID1() bfin_read16(CAN_MB20_ID1)
+#define bfin_write_CAN_MB20_ID1(val) bfin_write16(CAN_MB20_ID1,val)
+#define bfin_read_CAN_MB20_ID0() bfin_read16(CAN_MB20_ID0)
+#define bfin_write_CAN_MB20_ID0(val) bfin_write16(CAN_MB20_ID0,val)
+#define bfin_read_CAN_MB20_TIMESTAMP() bfin_read16(CAN_MB20_TIMESTAMP)
+#define bfin_write_CAN_MB20_TIMESTAMP(val) bfin_write16(CAN_MB20_TIMESTAMP,val)
+#define bfin_read_CAN_MB20_LENGTH() bfin_read16(CAN_MB20_LENGTH)
+#define bfin_write_CAN_MB20_LENGTH(val) bfin_write16(CAN_MB20_LENGTH,val)
+#define bfin_read_CAN_MB20_DATA3() bfin_read16(CAN_MB20_DATA3)
+#define bfin_write_CAN_MB20_DATA3(val) bfin_write16(CAN_MB20_DATA3,val)
+#define bfin_read_CAN_MB20_DATA2() bfin_read16(CAN_MB20_DATA2)
+#define bfin_write_CAN_MB20_DATA2(val) bfin_write16(CAN_MB20_DATA2,val)
+#define bfin_read_CAN_MB20_DATA1() bfin_read16(CAN_MB20_DATA1)
+#define bfin_write_CAN_MB20_DATA1(val) bfin_write16(CAN_MB20_DATA1,val)
+#define bfin_read_CAN_MB20_DATA0() bfin_read16(CAN_MB20_DATA0)
+#define bfin_write_CAN_MB20_DATA0(val) bfin_write16(CAN_MB20_DATA0,val)
+
+#define bfin_read_CAN_MB21_ID1() bfin_read16(CAN_MB21_ID1)
+#define bfin_write_CAN_MB21_ID1(val) bfin_write16(CAN_MB21_ID1,val)
+#define bfin_read_CAN_MB21_ID0() bfin_read16(CAN_MB21_ID0)
+#define bfin_write_CAN_MB21_ID0(val) bfin_write16(CAN_MB21_ID0,val)
+#define bfin_read_CAN_MB21_TIMESTAMP() bfin_read16(CAN_MB21_TIMESTAMP)
+#define bfin_write_CAN_MB21_TIMESTAMP(val) bfin_write16(CAN_MB21_TIMESTAMP,val)
+#define bfin_read_CAN_MB21_LENGTH() bfin_read16(CAN_MB21_LENGTH)
+#define bfin_write_CAN_MB21_LENGTH(val) bfin_write16(CAN_MB21_LENGTH,val)
+#define bfin_read_CAN_MB21_DATA3() bfin_read16(CAN_MB21_DATA3)
+#define bfin_write_CAN_MB21_DATA3(val) bfin_write16(CAN_MB21_DATA3,val)
+#define bfin_read_CAN_MB21_DATA2() bfin_read16(CAN_MB21_DATA2)
+#define bfin_write_CAN_MB21_DATA2(val) bfin_write16(CAN_MB21_DATA2,val)
+#define bfin_read_CAN_MB21_DATA1() bfin_read16(CAN_MB21_DATA1)
+#define bfin_write_CAN_MB21_DATA1(val) bfin_write16(CAN_MB21_DATA1,val)
+#define bfin_read_CAN_MB21_DATA0() bfin_read16(CAN_MB21_DATA0)
+#define bfin_write_CAN_MB21_DATA0(val) bfin_write16(CAN_MB21_DATA0,val)
+
+#define bfin_read_CAN_MB22_ID1() bfin_read16(CAN_MB22_ID1)
+#define bfin_write_CAN_MB22_ID1(val) bfin_write16(CAN_MB22_ID1,val)
+#define bfin_read_CAN_MB22_ID0() bfin_read16(CAN_MB22_ID0)
+#define bfin_write_CAN_MB22_ID0(val) bfin_write16(CAN_MB22_ID0,val)
+#define bfin_read_CAN_MB22_TIMESTAMP() bfin_read16(CAN_MB22_TIMESTAMP)
+#define bfin_write_CAN_MB22_TIMESTAMP(val) bfin_write16(CAN_MB22_TIMESTAMP,val)
+#define bfin_read_CAN_MB22_LENGTH() bfin_read16(CAN_MB22_LENGTH)
+#define bfin_write_CAN_MB22_LENGTH(val) bfin_write16(CAN_MB22_LENGTH,val)
+#define bfin_read_CAN_MB22_DATA3() bfin_read16(CAN_MB22_DATA3)
+#define bfin_write_CAN_MB22_DATA3(val) bfin_write16(CAN_MB22_DATA3,val)
+#define bfin_read_CAN_MB22_DATA2() bfin_read16(CAN_MB22_DATA2)
+#define bfin_write_CAN_MB22_DATA2(val) bfin_write16(CAN_MB22_DATA2,val)
+#define bfin_read_CAN_MB22_DATA1() bfin_read16(CAN_MB22_DATA1)
+#define bfin_write_CAN_MB22_DATA1(val) bfin_write16(CAN_MB22_DATA1,val)
+#define bfin_read_CAN_MB22_DATA0() bfin_read16(CAN_MB22_DATA0)
+#define bfin_write_CAN_MB22_DATA0(val) bfin_write16(CAN_MB22_DATA0,val)
+
+#define bfin_read_CAN_MB23_ID1() bfin_read16(CAN_MB23_ID1)
+#define bfin_write_CAN_MB23_ID1(val) bfin_write16(CAN_MB23_ID1,val)
+#define bfin_read_CAN_MB23_ID0() bfin_read16(CAN_MB23_ID0)
+#define bfin_write_CAN_MB23_ID0(val) bfin_write16(CAN_MB23_ID0,val)
+#define bfin_read_CAN_MB23_TIMESTAMP() bfin_read16(CAN_MB23_TIMESTAMP)
+#define bfin_write_CAN_MB23_TIMESTAMP(val) bfin_write16(CAN_MB23_TIMESTAMP,val)
+#define bfin_read_CAN_MB23_LENGTH() bfin_read16(CAN_MB23_LENGTH)
+#define bfin_write_CAN_MB23_LENGTH(val) bfin_write16(CAN_MB23_LENGTH,val)
+#define bfin_read_CAN_MB23_DATA3() bfin_read16(CAN_MB23_DATA3)
+#define bfin_write_CAN_MB23_DATA3(val) bfin_write16(CAN_MB23_DATA3,val)
+#define bfin_read_CAN_MB23_DATA2() bfin_read16(CAN_MB23_DATA2)
+#define bfin_write_CAN_MB23_DATA2(val) bfin_write16(CAN_MB23_DATA2,val)
+#define bfin_read_CAN_MB23_DATA1() bfin_read16(CAN_MB23_DATA1)
+#define bfin_write_CAN_MB23_DATA1(val) bfin_write16(CAN_MB23_DATA1,val)
+#define bfin_read_CAN_MB23_DATA0() bfin_read16(CAN_MB23_DATA0)
+#define bfin_write_CAN_MB23_DATA0(val) bfin_write16(CAN_MB23_DATA0,val)
+
+#define bfin_read_CAN_MB24_ID1() bfin_read16(CAN_MB24_ID1)
+#define bfin_write_CAN_MB24_ID1(val) bfin_write16(CAN_MB24_ID1,val)
+#define bfin_read_CAN_MB24_ID0() bfin_read16(CAN_MB24_ID0)
+#define bfin_write_CAN_MB24_ID0(val) bfin_write16(CAN_MB24_ID0,val)
+#define bfin_read_CAN_MB24_TIMESTAMP() bfin_read16(CAN_MB24_TIMESTAMP)
+#define bfin_write_CAN_MB24_TIMESTAMP(val) bfin_write16(CAN_MB24_TIMESTAMP,val)
+#define bfin_read_CAN_MB24_LENGTH() bfin_read16(CAN_MB24_LENGTH)
+#define bfin_write_CAN_MB24_LENGTH(val) bfin_write16(CAN_MB24_LENGTH,val)
+#define bfin_read_CAN_MB24_DATA3() bfin_read16(CAN_MB24_DATA3)
+#define bfin_write_CAN_MB24_DATA3(val) bfin_write16(CAN_MB24_DATA3,val)
+#define bfin_read_CAN_MB24_DATA2() bfin_read16(CAN_MB24_DATA2)
+#define bfin_write_CAN_MB24_DATA2(val) bfin_write16(CAN_MB24_DATA2,val)
+#define bfin_read_CAN_MB24_DATA1() bfin_read16(CAN_MB24_DATA1)
+#define bfin_write_CAN_MB24_DATA1(val) bfin_write16(CAN_MB24_DATA1,val)
+#define bfin_read_CAN_MB24_DATA0() bfin_read16(CAN_MB24_DATA0)
+#define bfin_write_CAN_MB24_DATA0(val) bfin_write16(CAN_MB24_DATA0,val)
+
+#define bfin_read_CAN_MB25_ID1() bfin_read16(CAN_MB25_ID1)
+#define bfin_write_CAN_MB25_ID1(val) bfin_write16(CAN_MB25_ID1,val)
+#define bfin_read_CAN_MB25_ID0() bfin_read16(CAN_MB25_ID0)
+#define bfin_write_CAN_MB25_ID0(val) bfin_write16(CAN_MB25_ID0,val)
+#define bfin_read_CAN_MB25_TIMESTAMP() bfin_read16(CAN_MB25_TIMESTAMP)
+#define bfin_write_CAN_MB25_TIMESTAMP(val) bfin_write16(CAN_MB25_TIMESTAMP,val)
+#define bfin_read_CAN_MB25_LENGTH() bfin_read16(CAN_MB25_LENGTH)
+#define bfin_write_CAN_MB25_LENGTH(val) bfin_write16(CAN_MB25_LENGTH,val)
+#define bfin_read_CAN_MB25_DATA3() bfin_read16(CAN_MB25_DATA3)
+#define bfin_write_CAN_MB25_DATA3(val) bfin_write16(CAN_MB25_DATA3,val)
+#define bfin_read_CAN_MB25_DATA2() bfin_read16(CAN_MB25_DATA2)
+#define bfin_write_CAN_MB25_DATA2(val) bfin_write16(CAN_MB25_DATA2,val)
+#define bfin_read_CAN_MB25_DATA1() bfin_read16(CAN_MB25_DATA1)
+#define bfin_write_CAN_MB25_DATA1(val) bfin_write16(CAN_MB25_DATA1,val)
+#define bfin_read_CAN_MB25_DATA0() bfin_read16(CAN_MB25_DATA0)
+#define bfin_write_CAN_MB25_DATA0(val) bfin_write16(CAN_MB25_DATA0,val)
+
+#define bfin_read_CAN_MB26_ID1() bfin_read16(CAN_MB26_ID1)
+#define bfin_write_CAN_MB26_ID1(val) bfin_write16(CAN_MB26_ID1,val)
+#define bfin_read_CAN_MB26_ID0() bfin_read16(CAN_MB26_ID0)
+#define bfin_write_CAN_MB26_ID0(val) bfin_write16(CAN_MB26_ID0,val)
+#define bfin_read_CAN_MB26_TIMESTAMP() bfin_read16(CAN_MB26_TIMESTAMP)
+#define bfin_write_CAN_MB26_TIMESTAMP(val) bfin_write16(CAN_MB26_TIMESTAMP,val)
+#define bfin_read_CAN_MB26_LENGTH() bfin_read16(CAN_MB26_LENGTH)
+#define bfin_write_CAN_MB26_LENGTH(val) bfin_write16(CAN_MB26_LENGTH,val)
+#define bfin_read_CAN_MB26_DATA3() bfin_read16(CAN_MB26_DATA3)
+#define bfin_write_CAN_MB26_DATA3(val) bfin_write16(CAN_MB26_DATA3,val)
+#define bfin_read_CAN_MB26_DATA2() bfin_read16(CAN_MB26_DATA2)
+#define bfin_write_CAN_MB26_DATA2(val) bfin_write16(CAN_MB26_DATA2,val)
+#define bfin_read_CAN_MB26_DATA1() bfin_read16(CAN_MB26_DATA1)
+#define bfin_write_CAN_MB26_DATA1(val) bfin_write16(CAN_MB26_DATA1,val)
+#define bfin_read_CAN_MB26_DATA0() bfin_read16(CAN_MB26_DATA0)
+#define bfin_write_CAN_MB26_DATA0(val) bfin_write16(CAN_MB26_DATA0,val)
+
+#define bfin_read_CAN_MB27_ID1() bfin_read16(CAN_MB27_ID1)
+#define bfin_write_CAN_MB27_ID1(val) bfin_write16(CAN_MB27_ID1,val)
+#define bfin_read_CAN_MB27_ID0() bfin_read16(CAN_MB27_ID0)
+#define bfin_write_CAN_MB27_ID0(val) bfin_write16(CAN_MB27_ID0,val)
+#define bfin_read_CAN_MB27_TIMESTAMP() bfin_read16(CAN_MB27_TIMESTAMP)
+#define bfin_write_CAN_MB27_TIMESTAMP(val) bfin_write16(CAN_MB27_TIMESTAMP,val)
+#define bfin_read_CAN_MB27_LENGTH() bfin_read16(CAN_MB27_LENGTH)
+#define bfin_write_CAN_MB27_LENGTH(val) bfin_write16(CAN_MB27_LENGTH,val)
+#define bfin_read_CAN_MB27_DATA3() bfin_read16(CAN_MB27_DATA3)
+#define bfin_write_CAN_MB27_DATA3(val) bfin_write16(CAN_MB27_DATA3,val)
+#define bfin_read_CAN_MB27_DATA2() bfin_read16(CAN_MB27_DATA2)
+#define bfin_write_CAN_MB27_DATA2(val) bfin_write16(CAN_MB27_DATA2,val)
+#define bfin_read_CAN_MB27_DATA1() bfin_read16(CAN_MB27_DATA1)
+#define bfin_write_CAN_MB27_DATA1(val) bfin_write16(CAN_MB27_DATA1,val)
+#define bfin_read_CAN_MB27_DATA0() bfin_read16(CAN_MB27_DATA0)
+#define bfin_write_CAN_MB27_DATA0(val) bfin_write16(CAN_MB27_DATA0,val)
+
+#define bfin_read_CAN_MB28_ID1() bfin_read16(CAN_MB28_ID1)
+#define bfin_write_CAN_MB28_ID1(val) bfin_write16(CAN_MB28_ID1,val)
+#define bfin_read_CAN_MB28_ID0() bfin_read16(CAN_MB28_ID0)
+#define bfin_write_CAN_MB28_ID0(val) bfin_write16(CAN_MB28_ID0,val)
+#define bfin_read_CAN_MB28_TIMESTAMP() bfin_read16(CAN_MB28_TIMESTAMP)
+#define bfin_write_CAN_MB28_TIMESTAMP(val) bfin_write16(CAN_MB28_TIMESTAMP,val)
+#define bfin_read_CAN_MB28_LENGTH() bfin_read16(CAN_MB28_LENGTH)
+#define bfin_write_CAN_MB28_LENGTH(val) bfin_write16(CAN_MB28_LENGTH,val)
+#define bfin_read_CAN_MB28_DATA3() bfin_read16(CAN_MB28_DATA3)
+#define bfin_write_CAN_MB28_DATA3(val) bfin_write16(CAN_MB28_DATA3,val)
+#define bfin_read_CAN_MB28_DATA2() bfin_read16(CAN_MB28_DATA2)
+#define bfin_write_CAN_MB28_DATA2(val) bfin_write16(CAN_MB28_DATA2,val)
+#define bfin_read_CAN_MB28_DATA1() bfin_read16(CAN_MB28_DATA1)
+#define bfin_write_CAN_MB28_DATA1(val) bfin_write16(CAN_MB28_DATA1,val)
+#define bfin_read_CAN_MB28_DATA0() bfin_read16(CAN_MB28_DATA0)
+#define bfin_write_CAN_MB28_DATA0(val) bfin_write16(CAN_MB28_DATA0,val)
+
+#define bfin_read_CAN_MB29_ID1() bfin_read16(CAN_MB29_ID1)
+#define bfin_write_CAN_MB29_ID1(val) bfin_write16(CAN_MB29_ID1,val)
+#define bfin_read_CAN_MB29_ID0() bfin_read16(CAN_MB29_ID0)
+#define bfin_write_CAN_MB29_ID0(val) bfin_write16(CAN_MB29_ID0,val)
+#define bfin_read_CAN_MB29_TIMESTAMP() bfin_read16(CAN_MB29_TIMESTAMP)
+#define bfin_write_CAN_MB29_TIMESTAMP(val) bfin_write16(CAN_MB29_TIMESTAMP,val)
+#define bfin_read_CAN_MB29_LENGTH() bfin_read16(CAN_MB29_LENGTH)
+#define bfin_write_CAN_MB29_LENGTH(val) bfin_write16(CAN_MB29_LENGTH,val)
+#define bfin_read_CAN_MB29_DATA3() bfin_read16(CAN_MB29_DATA3)
+#define bfin_write_CAN_MB29_DATA3(val) bfin_write16(CAN_MB29_DATA3,val)
+#define bfin_read_CAN_MB29_DATA2() bfin_read16(CAN_MB29_DATA2)
+#define bfin_write_CAN_MB29_DATA2(val) bfin_write16(CAN_MB29_DATA2,val)
+#define bfin_read_CAN_MB29_DATA1() bfin_read16(CAN_MB29_DATA1)
+#define bfin_write_CAN_MB29_DATA1(val) bfin_write16(CAN_MB29_DATA1,val)
+#define bfin_read_CAN_MB29_DATA0() bfin_read16(CAN_MB29_DATA0)
+#define bfin_write_CAN_MB29_DATA0(val) bfin_write16(CAN_MB29_DATA0,val)
+
+#define bfin_read_CAN_MB30_ID1() bfin_read16(CAN_MB30_ID1)
+#define bfin_write_CAN_MB30_ID1(val) bfin_write16(CAN_MB30_ID1,val)
+#define bfin_read_CAN_MB30_ID0() bfin_read16(CAN_MB30_ID0)
+#define bfin_write_CAN_MB30_ID0(val) bfin_write16(CAN_MB30_ID0,val)
+#define bfin_read_CAN_MB30_TIMESTAMP() bfin_read16(CAN_MB30_TIMESTAMP)
+#define bfin_write_CAN_MB30_TIMESTAMP(val) bfin_write16(CAN_MB30_TIMESTAMP,val)
+#define bfin_read_CAN_MB30_LENGTH() bfin_read16(CAN_MB30_LENGTH)
+#define bfin_write_CAN_MB30_LENGTH(val) bfin_write16(CAN_MB30_LENGTH,val)
+#define bfin_read_CAN_MB30_DATA3() bfin_read16(CAN_MB30_DATA3)
+#define bfin_write_CAN_MB30_DATA3(val) bfin_write16(CAN_MB30_DATA3,val)
+#define bfin_read_CAN_MB30_DATA2() bfin_read16(CAN_MB30_DATA2)
+#define bfin_write_CAN_MB30_DATA2(val) bfin_write16(CAN_MB30_DATA2,val)
+#define bfin_read_CAN_MB30_DATA1() bfin_read16(CAN_MB30_DATA1)
+#define bfin_write_CAN_MB30_DATA1(val) bfin_write16(CAN_MB30_DATA1,val)
+#define bfin_read_CAN_MB30_DATA0() bfin_read16(CAN_MB30_DATA0)
+#define bfin_write_CAN_MB30_DATA0(val) bfin_write16(CAN_MB30_DATA0,val)
+
+#define bfin_read_CAN_MB31_ID1() bfin_read16(CAN_MB31_ID1)
+#define bfin_write_CAN_MB31_ID1(val) bfin_write16(CAN_MB31_ID1,val)
+#define bfin_read_CAN_MB31_ID0() bfin_read16(CAN_MB31_ID0)
+#define bfin_write_CAN_MB31_ID0(val) bfin_write16(CAN_MB31_ID0,val)
+#define bfin_read_CAN_MB31_TIMESTAMP() bfin_read16(CAN_MB31_TIMESTAMP)
+#define bfin_write_CAN_MB31_TIMESTAMP(val) bfin_write16(CAN_MB31_TIMESTAMP,val)
+#define bfin_read_CAN_MB31_LENGTH() bfin_read16(CAN_MB31_LENGTH)
+#define bfin_write_CAN_MB31_LENGTH(val) bfin_write16(CAN_MB31_LENGTH,val)
+#define bfin_read_CAN_MB31_DATA3() bfin_read16(CAN_MB31_DATA3)
+#define bfin_write_CAN_MB31_DATA3(val) bfin_write16(CAN_MB31_DATA3,val)
+#define bfin_read_CAN_MB31_DATA2() bfin_read16(CAN_MB31_DATA2)
+#define bfin_write_CAN_MB31_DATA2(val) bfin_write16(CAN_MB31_DATA2,val)
+#define bfin_read_CAN_MB31_DATA1() bfin_read16(CAN_MB31_DATA1)
+#define bfin_write_CAN_MB31_DATA1(val) bfin_write16(CAN_MB31_DATA1,val)
+#define bfin_read_CAN_MB31_DATA0() bfin_read16(CAN_MB31_DATA0)
+#define bfin_write_CAN_MB31_DATA0(val) bfin_write16(CAN_MB31_DATA0,val)
+
+/* CAN Mailbox Area Macros */
+#define bfin_read_CAN_MB_ID1(x)() bfin_read16(CAN_MB_ID1(x))
+#define bfin_write_CAN_MB_ID1(x)(val) bfin_write16(CAN_MB_ID1(x),val)
+#define bfin_read_CAN_MB_ID0(x)() bfin_read16(CAN_MB_ID0(x))
+#define bfin_write_CAN_MB_ID0(x)(val) bfin_write16(CAN_MB_ID0(x),val)
+#define bfin_read_CAN_MB_TIMESTAMP(x)() bfin_read16(CAN_MB_TIMESTAMP(x))
+#define bfin_write_CAN_MB_TIMESTAMP(x)(val) bfin_write16(CAN_MB_TIMESTAMP(x),val)
+#define bfin_read_CAN_MB_LENGTH(x)() bfin_read16(CAN_MB_LENGTH(x))
+#define bfin_write_CAN_MB_LENGTH(x)(val) bfin_write16(CAN_MB_LENGTH(x),val)
+#define bfin_read_CAN_MB_DATA3(x)() bfin_read16(CAN_MB_DATA3(x))
+#define bfin_write_CAN_MB_DATA3(x)(val) bfin_write16(CAN_MB_DATA3(x),val)
+#define bfin_read_CAN_MB_DATA2(x)() bfin_read16(CAN_MB_DATA2(x))
+#define bfin_write_CAN_MB_DATA2(x)(val) bfin_write16(CAN_MB_DATA2(x),val)
+#define bfin_read_CAN_MB_DATA1(x)() bfin_read16(CAN_MB_DATA1(x))
+#define bfin_write_CAN_MB_DATA1(x)(val) bfin_write16(CAN_MB_DATA1(x),val)
+#define bfin_read_CAN_MB_DATA0(x)() bfin_read16(CAN_MB_DATA0(x))
+#define bfin_write_CAN_MB_DATA0(x)(val) bfin_write16(CAN_MB_DATA0(x),val)
+
+/* Pin Control Registers (0xFFC03200 - 0xFFC032FF) */
+#define bfin_read_PORTF_FER() bfin_read16(PORTF_FER)
+#define bfin_write_PORTF_FER(val) bfin_write16(PORTF_FER,val)
+#define bfin_read_PORTG_FER() bfin_read16(PORTG_FER)
+#define bfin_write_PORTG_FER(val) bfin_write16(PORTG_FER,val)
+#define bfin_read_PORTH_FER() bfin_read16(PORTH_FER)
+#define bfin_write_PORTH_FER(val) bfin_write16(PORTH_FER,val)
+#define bfin_read_PORT_MUX() bfin_read16(BFIN_PORT_MUX)
+#define bfin_write_PORT_MUX(val) bfin_write16(BFIN_PORT_MUX,val)
+
+/* Handshake MDMA Registers (0xFFC03300 - 0xFFC033FF) */
+#define bfin_read_HMDMA0_CONTROL() bfin_read16(HMDMA0_CONTROL)
+#define bfin_write_HMDMA0_CONTROL(val) bfin_write16(HMDMA0_CONTROL,val)
+#define bfin_read_HMDMA0_ECINIT() bfin_read16(HMDMA0_ECINIT)
+#define bfin_write_HMDMA0_ECINIT(val) bfin_write16(HMDMA0_ECINIT,val)
+#define bfin_read_HMDMA0_BCINIT() bfin_read16(HMDMA0_BCINIT)
+#define bfin_write_HMDMA0_BCINIT(val) bfin_write16(HMDMA0_BCINIT,val)
+#define bfin_read_HMDMA0_ECURGENT() bfin_read16(HMDMA0_ECURGENT)
+#define bfin_write_HMDMA0_ECURGENT(val) bfin_write16(HMDMA0_ECURGENT,val)
+#define bfin_read_HMDMA0_ECOVERFLOW() bfin_read16(HMDMA0_ECOVERFLOW)
+#define bfin_write_HMDMA0_ECOVERFLOW(val) bfin_write16(HMDMA0_ECOVERFLOW,val)
+#define bfin_read_HMDMA0_ECOUNT() bfin_read16(HMDMA0_ECOUNT)
+#define bfin_write_HMDMA0_ECOUNT(val) bfin_write16(HMDMA0_ECOUNT,val)
+#define bfin_read_HMDMA0_BCOUNT() bfin_read16(HMDMA0_BCOUNT)
+#define bfin_write_HMDMA0_BCOUNT(val) bfin_write16(HMDMA0_BCOUNT,val)
+
+#define bfin_read_HMDMA1_CONTROL() bfin_read16(HMDMA1_CONTROL)
+#define bfin_write_HMDMA1_CONTROL(val) bfin_write16(HMDMA1_CONTROL,val)
+#define bfin_read_HMDMA1_ECINIT() bfin_read16(HMDMA1_ECINIT)
+#define bfin_write_HMDMA1_ECINIT(val) bfin_write16(HMDMA1_ECINIT,val)
+#define bfin_read_HMDMA1_BCINIT() bfin_read16(HMDMA1_BCINIT)
+#define bfin_write_HMDMA1_BCINIT(val) bfin_write16(HMDMA1_BCINIT,val)
+#define bfin_read_HMDMA1_ECURGENT() bfin_read16(HMDMA1_ECURGENT)
+#define bfin_write_HMDMA1_ECURGENT(val) bfin_write16(HMDMA1_ECURGENT,val)
+#define bfin_read_HMDMA1_ECOVERFLOW() bfin_read16(HMDMA1_ECOVERFLOW)
+#define bfin_write_HMDMA1_ECOVERFLOW(val) bfin_write16(HMDMA1_ECOVERFLOW,val)
+#define bfin_read_HMDMA1_ECOUNT() bfin_read16(HMDMA1_ECOUNT)
+#define bfin_write_HMDMA1_ECOUNT(val) bfin_write16(HMDMA1_ECOUNT,val)
+#define bfin_read_HMDMA1_BCOUNT() bfin_read16(HMDMA1_BCOUNT)
+#define bfin_write_HMDMA1_BCOUNT(val) bfin_write16(HMDMA1_BCOUNT,val)
+
+#endif /* _CDEF_BF534_H */
diff --git a/include/asm-blackfin/mach-bf537/cdefBF537.h b/include/asm-blackfin/mach-bf537/cdefBF537.h
new file mode 100644
index 00000000000..932a1b6b5d1
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/cdefBF537.h
@@ -0,0 +1,209 @@
+/*
+ * File: include/asm-blackfin/mach-bf537/cdefBF537.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ * System MMR Register Map
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF537_H
+#define _CDEF_BF537_H
+
+/* Include MMRs Common to BF534 */
+#include "cdefBF534.h"
+
+/* Include all Core registers and bit definitions */
+#include "defBF537.h"
+
+/* Include Macro "Defines" For EMAC (Unique to BF536/BF537 */
+/* 10/100 Ethernet Controller (0xFFC03000 - 0xFFC031FF) */
+#define pEMAC_OPMODE ((volatile unsigned long *)EMAC_OPMODE)
+#define bfin_read_EMAC_OPMODE() bfin_read32(EMAC_OPMODE)
+#define bfin_write_EMAC_OPMODE(val) bfin_write32(EMAC_OPMODE,val)
+#define bfin_read_EMAC_ADDRLO() bfin_read32(EMAC_ADDRLO)
+#define bfin_write_EMAC_ADDRLO(val) bfin_write32(EMAC_ADDRLO,val)
+#define bfin_read_EMAC_ADDRHI() bfin_read32(EMAC_ADDRHI)
+#define bfin_write_EMAC_ADDRHI(val) bfin_write32(EMAC_ADDRHI,val)
+#define bfin_read_EMAC_HASHLO() bfin_read32(EMAC_HASHLO)
+#define bfin_write_EMAC_HASHLO(val) bfin_write32(EMAC_HASHLO,val)
+#define bfin_read_EMAC_HASHHI() bfin_read32(EMAC_HASHHI)
+#define bfin_write_EMAC_HASHHI(val) bfin_write32(EMAC_HASHHI,val)
+#define bfin_read_EMAC_STAADD() bfin_read32(EMAC_STAADD)
+#define bfin_write_EMAC_STAADD(val) bfin_write32(EMAC_STAADD,val)
+#define bfin_read_EMAC_STADAT() bfin_read32(EMAC_STADAT)
+#define bfin_write_EMAC_STADAT(val) bfin_write32(EMAC_STADAT,val)
+#define bfin_read_EMAC_FLC() bfin_read32(EMAC_FLC)
+#define bfin_write_EMAC_FLC(val) bfin_write32(EMAC_FLC,val)
+#define bfin_read_EMAC_VLAN1() bfin_read32(EMAC_VLAN1)
+#define bfin_write_EMAC_VLAN1(val) bfin_write32(EMAC_VLAN1,val)
+#define bfin_read_EMAC_VLAN2() bfin_read32(EMAC_VLAN2)
+#define bfin_write_EMAC_VLAN2(val) bfin_write32(EMAC_VLAN2,val)
+#define bfin_read_EMAC_WKUP_CTL() bfin_read32(EMAC_WKUP_CTL)
+#define bfin_write_EMAC_WKUP_CTL(val) bfin_write32(EMAC_WKUP_CTL,val)
+#define bfin_read_EMAC_WKUP_FFMSK0() bfin_read32(EMAC_WKUP_FFMSK0)
+#define bfin_write_EMAC_WKUP_FFMSK0(val) bfin_write32(EMAC_WKUP_FFMSK0,val)
+#define bfin_read_EMAC_WKUP_FFMSK1() bfin_read32(EMAC_WKUP_FFMSK1)
+#define bfin_write_EMAC_WKUP_FFMSK1(val) bfin_write32(EMAC_WKUP_FFMSK1,val)
+#define bfin_read_EMAC_WKUP_FFMSK2() bfin_read32(EMAC_WKUP_FFMSK2)
+#define bfin_write_EMAC_WKUP_FFMSK2(val) bfin_write32(EMAC_WKUP_FFMSK2,val)
+#define bfin_read_EMAC_WKUP_FFMSK3() bfin_read32(EMAC_WKUP_FFMSK3)
+#define bfin_write_EMAC_WKUP_FFMSK3(val) bfin_write32(EMAC_WKUP_FFMSK3,val)
+#define bfin_read_EMAC_WKUP_FFCMD() bfin_read32(EMAC_WKUP_FFCMD)
+#define bfin_write_EMAC_WKUP_FFCMD(val) bfin_write32(EMAC_WKUP_FFCMD,val)
+#define bfin_read_EMAC_WKUP_FFOFF() bfin_read32(EMAC_WKUP_FFOFF)
+#define bfin_write_EMAC_WKUP_FFOFF(val) bfin_write32(EMAC_WKUP_FFOFF,val)
+#define bfin_read_EMAC_WKUP_FFCRC0() bfin_read32(EMAC_WKUP_FFCRC0)
+#define bfin_write_EMAC_WKUP_FFCRC0(val) bfin_write32(EMAC_WKUP_FFCRC0,val)
+#define bfin_read_EMAC_WKUP_FFCRC1() bfin_read32(EMAC_WKUP_FFCRC1)
+#define bfin_write_EMAC_WKUP_FFCRC1(val) bfin_write32(EMAC_WKUP_FFCRC1,val)
+
+#define pEMAC_SYSCTL ((volatile unsigned long *)EMAC_SYSCTL)
+#define bfin_read_EMAC_SYSCTL() bfin_read32(EMAC_SYSCTL)
+#define bfin_write_EMAC_SYSCTL(val) bfin_write32(EMAC_SYSCTL,val)
+#define bfin_read_EMAC_SYSTAT() bfin_read32(EMAC_SYSTAT)
+#define bfin_write_EMAC_SYSTAT(val) bfin_write32(EMAC_SYSTAT,val)
+#define bfin_read_EMAC_RX_STAT() bfin_read32(EMAC_RX_STAT)
+#define bfin_write_EMAC_RX_STAT(val) bfin_write32(EMAC_RX_STAT,val)
+#define bfin_read_EMAC_RX_STKY() bfin_read32(EMAC_RX_STKY)
+#define bfin_write_EMAC_RX_STKY(val) bfin_write32(EMAC_RX_STKY,val)
+#define bfin_read_EMAC_RX_IRQE() bfin_read32(EMAC_RX_IRQE)
+#define bfin_write_EMAC_RX_IRQE(val) bfin_write32(EMAC_RX_IRQE,val)
+#define bfin_read_EMAC_TX_STAT() bfin_read32(EMAC_TX_STAT)
+#define bfin_write_EMAC_TX_STAT(val) bfin_write32(EMAC_TX_STAT,val)
+#define bfin_read_EMAC_TX_STKY() bfin_read32(EMAC_TX_STKY)
+#define bfin_write_EMAC_TX_STKY(val) bfin_write32(EMAC_TX_STKY,val)
+#define bfin_read_EMAC_TX_IRQE() bfin_read32(EMAC_TX_IRQE)
+#define bfin_write_EMAC_TX_IRQE(val) bfin_write32(EMAC_TX_IRQE,val)
+
+#define bfin_read_EMAC_MMC_CTL() bfin_read32(EMAC_MMC_CTL)
+#define bfin_write_EMAC_MMC_CTL(val) bfin_write32(EMAC_MMC_CTL,val)
+#define bfin_read_EMAC_MMC_RIRQS() bfin_read32(EMAC_MMC_RIRQS)
+#define bfin_write_EMAC_MMC_RIRQS(val) bfin_write32(EMAC_MMC_RIRQS,val)
+#define bfin_read_EMAC_MMC_RIRQE() bfin_read32(EMAC_MMC_RIRQE)
+#define bfin_write_EMAC_MMC_RIRQE(val) bfin_write32(EMAC_MMC_RIRQE,val)
+#define bfin_read_EMAC_MMC_TIRQS() bfin_read32(EMAC_MMC_TIRQS)
+#define bfin_write_EMAC_MMC_TIRQS(val) bfin_write32(EMAC_MMC_TIRQS,val)
+#define bfin_read_EMAC_MMC_TIRQE() bfin_read32(EMAC_MMC_TIRQE)
+#define bfin_write_EMAC_MMC_TIRQE(val) bfin_write32(EMAC_MMC_TIRQE,val)
+
+#define bfin_read_EMAC_RXC_OK() bfin_read32(EMAC_RXC_OK)
+#define bfin_write_EMAC_RXC_OK(val) bfin_write32(EMAC_RXC_OK,val)
+#define bfin_read_EMAC_RXC_FCS() bfin_read32(EMAC_RXC_FCS)
+#define bfin_write_EMAC_RXC_FCS(val) bfin_write32(EMAC_RXC_FCS,val)
+#define bfin_read_EMAC_RXC_ALIGN() bfin_read32(EMAC_RXC_ALIGN)
+#define bfin_write_EMAC_RXC_ALIGN(val) bfin_write32(EMAC_RXC_ALIGN,val)
+#define bfin_read_EMAC_RXC_OCTET() bfin_read32(EMAC_RXC_OCTET)
+#define bfin_write_EMAC_RXC_OCTET(val) bfin_write32(EMAC_RXC_OCTET,val)
+#define bfin_read_EMAC_RXC_DMAOVF() bfin_read32(EMAC_RXC_DMAOVF)
+#define bfin_write_EMAC_RXC_DMAOVF(val) bfin_write32(EMAC_RXC_DMAOVF,val)
+#define bfin_read_EMAC_RXC_UNICST() bfin_read32(EMAC_RXC_UNICST)
+#define bfin_write_EMAC_RXC_UNICST(val) bfin_write32(EMAC_RXC_UNICST,val)
+#define bfin_read_EMAC_RXC_MULTI() bfin_read32(EMAC_RXC_MULTI)
+#define bfin_write_EMAC_RXC_MULTI(val) bfin_write32(EMAC_RXC_MULTI,val)
+#define bfin_read_EMAC_RXC_BROAD() bfin_read32(EMAC_RXC_BROAD)
+#define bfin_write_EMAC_RXC_BROAD(val) bfin_write32(EMAC_RXC_BROAD,val)
+#define bfin_read_EMAC_RXC_LNERRI() bfin_read32(EMAC_RXC_LNERRI)
+#define bfin_write_EMAC_RXC_LNERRI(val) bfin_write32(EMAC_RXC_LNERRI,val)
+#define bfin_read_EMAC_RXC_LNERRO() bfin_read32(EMAC_RXC_LNERRO)
+#define bfin_write_EMAC_RXC_LNERRO(val) bfin_write32(EMAC_RXC_LNERRO,val)
+#define bfin_read_EMAC_RXC_LONG() bfin_read32(EMAC_RXC_LONG)
+#define bfin_write_EMAC_RXC_LONG(val) bfin_write32(EMAC_RXC_LONG,val)
+#define bfin_read_EMAC_RXC_MACCTL() bfin_read32(EMAC_RXC_MACCTL)
+#define bfin_write_EMAC_RXC_MACCTL(val) bfin_write32(EMAC_RXC_MACCTL,val)
+#define bfin_read_EMAC_RXC_OPCODE() bfin_read32(EMAC_RXC_OPCODE)
+#define bfin_write_EMAC_RXC_OPCODE(val) bfin_write32(EMAC_RXC_OPCODE,val)
+#define bfin_read_EMAC_RXC_PAUSE() bfin_read32(EMAC_RXC_PAUSE)
+#define bfin_write_EMAC_RXC_PAUSE(val) bfin_write32(EMAC_RXC_PAUSE,val)
+#define bfin_read_EMAC_RXC_ALLFRM() bfin_read32(EMAC_RXC_ALLFRM)
+#define bfin_write_EMAC_RXC_ALLFRM(val) bfin_write32(EMAC_RXC_ALLFRM,val)
+#define bfin_read_EMAC_RXC_ALLOCT() bfin_read32(EMAC_RXC_ALLOCT)
+#define bfin_write_EMAC_RXC_ALLOCT(val) bfin_write32(EMAC_RXC_ALLOCT,val)
+#define bfin_read_EMAC_RXC_TYPED() bfin_read32(EMAC_RXC_TYPED)
+#define bfin_write_EMAC_RXC_TYPED(val) bfin_write32(EMAC_RXC_TYPED,val)
+#define bfin_read_EMAC_RXC_SHORT() bfin_read32(EMAC_RXC_SHORT)
+#define bfin_write_EMAC_RXC_SHORT(val) bfin_write32(EMAC_RXC_SHORT,val)
+#define bfin_read_EMAC_RXC_EQ64() bfin_read32(EMAC_RXC_EQ64)
+#define bfin_write_EMAC_RXC_EQ64(val) bfin_write32(EMAC_RXC_EQ64,val)
+#define pEMAC_RXC_LT128 ((volatile unsigned long *)EMAC_RXC_LT128)
+#define bfin_read_EMAC_RXC_LT128() bfin_read32(EMAC_RXC_LT128)
+#define bfin_write_EMAC_RXC_LT128(val) bfin_write32(EMAC_RXC_LT128,val)
+#define bfin_read_EMAC_RXC_LT256() bfin_read32(EMAC_RXC_LT256)
+#define bfin_write_EMAC_RXC_LT256(val) bfin_write32(EMAC_RXC_LT256,val)
+#define bfin_read_EMAC_RXC_LT512() bfin_read32(EMAC_RXC_LT512)
+#define bfin_write_EMAC_RXC_LT512(val) bfin_write32(EMAC_RXC_LT512,val)
+#define bfin_read_EMAC_RXC_LT1024() bfin_read32(EMAC_RXC_LT1024)
+#define bfin_write_EMAC_RXC_LT1024(val) bfin_write32(EMAC_RXC_LT1024,val)
+#define bfin_read_EMAC_RXC_GE1024() bfin_read32(EMAC_RXC_GE1024)
+#define bfin_write_EMAC_RXC_GE1024(val) bfin_write32(EMAC_RXC_GE1024,val)
+
+#define bfin_read_EMAC_TXC_OK() bfin_read32(EMAC_TXC_OK)
+#define bfin_write_EMAC_TXC_OK(val) bfin_write32(EMAC_TXC_OK,val)
+#define bfin_read_EMAC_TXC_1COL() bfin_read32(EMAC_TXC_1COL)
+#define bfin_write_EMAC_TXC_1COL(val) bfin_write32(EMAC_TXC_1COL,val)
+#define bfin_read_EMAC_TXC_GT1COL() bfin_read32(EMAC_TXC_GT1COL)
+#define bfin_write_EMAC_TXC_GT1COL(val) bfin_write32(EMAC_TXC_GT1COL,val)
+#define bfin_read_EMAC_TXC_OCTET() bfin_read32(EMAC_TXC_OCTET)
+#define bfin_write_EMAC_TXC_OCTET(val) bfin_write32(EMAC_TXC_OCTET,val)
+#define bfin_read_EMAC_TXC_DEFER() bfin_read32(EMAC_TXC_DEFER)
+#define bfin_write_EMAC_TXC_DEFER(val) bfin_write32(EMAC_TXC_DEFER,val)
+#define bfin_read_EMAC_TXC_LATECL() bfin_read32(EMAC_TXC_LATECL)
+#define bfin_write_EMAC_TXC_LATECL(val) bfin_write32(EMAC_TXC_LATECL,val)
+#define bfin_read_EMAC_TXC_XS_COL() bfin_read32(EMAC_TXC_XS_COL)
+#define bfin_write_EMAC_TXC_XS_COL(val) bfin_write32(EMAC_TXC_XS_COL,val)
+#define bfin_read_EMAC_TXC_DMAUND() bfin_read32(EMAC_TXC_DMAUND)
+#define bfin_write_EMAC_TXC_DMAUND(val) bfin_write32(EMAC_TXC_DMAUND,val)
+#define bfin_read_EMAC_TXC_CRSERR() bfin_read32(EMAC_TXC_CRSERR)
+#define bfin_write_EMAC_TXC_CRSERR(val) bfin_write32(EMAC_TXC_CRSERR,val)
+#define bfin_read_EMAC_TXC_UNICST() bfin_read32(EMAC_TXC_UNICST)
+#define bfin_write_EMAC_TXC_UNICST(val) bfin_write32(EMAC_TXC_UNICST,val)
+#define bfin_read_EMAC_TXC_MULTI() bfin_read32(EMAC_TXC_MULTI)
+#define bfin_write_EMAC_TXC_MULTI(val) bfin_write32(EMAC_TXC_MULTI,val)
+#define bfin_read_EMAC_TXC_BROAD() bfin_read32(EMAC_TXC_BROAD)
+#define bfin_write_EMAC_TXC_BROAD(val) bfin_write32(EMAC_TXC_BROAD,val)
+#define bfin_read_EMAC_TXC_XS_DFR() bfin_read32(EMAC_TXC_XS_DFR)
+#define bfin_write_EMAC_TXC_XS_DFR(val) bfin_write32(EMAC_TXC_XS_DFR,val)
+#define bfin_read_EMAC_TXC_MACCTL() bfin_read32(EMAC_TXC_MACCTL)
+#define bfin_write_EMAC_TXC_MACCTL(val) bfin_write32(EMAC_TXC_MACCTL,val)
+#define bfin_read_EMAC_TXC_ALLFRM() bfin_read32(EMAC_TXC_ALLFRM)
+#define bfin_write_EMAC_TXC_ALLFRM(val) bfin_write32(EMAC_TXC_ALLFRM,val)
+#define bfin_read_EMAC_TXC_ALLOCT() bfin_read32(EMAC_TXC_ALLOCT)
+#define bfin_write_EMAC_TXC_ALLOCT(val) bfin_write32(EMAC_TXC_ALLOCT,val)
+#define bfin_read_EMAC_TXC_EQ64() bfin_read32(EMAC_TXC_EQ64)
+#define bfin_write_EMAC_TXC_EQ64(val) bfin_write32(EMAC_TXC_EQ64,val)
+#define bfin_read_EMAC_TXC_LT128() bfin_read32(EMAC_TXC_LT128)
+#define bfin_write_EMAC_TXC_LT128(val) bfin_write32(EMAC_TXC_LT128,val)
+#define bfin_read_EMAC_TXC_LT256() bfin_read32(EMAC_TXC_LT256)
+#define bfin_write_EMAC_TXC_LT256(val) bfin_write32(EMAC_TXC_LT256,val)
+#define bfin_read_EMAC_TXC_LT512() bfin_read32(EMAC_TXC_LT512)
+#define bfin_write_EMAC_TXC_LT512(val) bfin_write32(EMAC_TXC_LT512,val)
+#define bfin_read_EMAC_TXC_LT1024() bfin_read32(EMAC_TXC_LT1024)
+#define bfin_write_EMAC_TXC_LT1024(val) bfin_write32(EMAC_TXC_LT1024,val)
+#define bfin_read_EMAC_TXC_GE1024() bfin_read32(EMAC_TXC_GE1024)
+#define bfin_write_EMAC_TXC_GE1024(val) bfin_write32(EMAC_TXC_GE1024,val)
+#define bfin_read_EMAC_TXC_ABORT() bfin_read32(EMAC_TXC_ABORT)
+#define bfin_write_EMAC_TXC_ABORT(val) bfin_write32(EMAC_TXC_ABORT,val)
+
+#endif /* _CDEF_BF537_H */
diff --git a/include/asm-blackfin/mach-bf537/defBF534.h b/include/asm-blackfin/mach-bf537/defBF534.h
new file mode 100644
index 00000000000..e605e970900
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/defBF534.h
@@ -0,0 +1,2501 @@
+/*
+ * File: include/asm-blackfin/mach-bf537/cdefBF537.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DEF_BF534_H
+#define _DEF_BF534_H
+
+/* Include all Core registers and bit definitions */
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/************************************************************************************
+** System MMR Register Map
+*************************************************************************************/
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+#define PLL_CTL 0xFFC00000 /* PLL Control Register */
+#define PLL_DIV 0xFFC00004 /* PLL Divide Register */
+#define VR_CTL 0xFFC00008 /* Voltage Regulator Control Register */
+#define PLL_STAT 0xFFC0000C /* PLL Status Register */
+#define PLL_LOCKCNT 0xFFC00010 /* PLL Lock Count Register */
+#define CHIPID 0xFFC00014 /* Chip ID Register */
+
+/* System Interrupt Controller (0xFFC00100 - 0xFFC001FF) */
+#define SWRST 0xFFC00100 /* Software Reset Register */
+#define SYSCR 0xFFC00104 /* System Configuration Register */
+#define SIC_RVECT 0xFFC00108 /* Interrupt Reset Vector Address Register */
+#define SIC_IMASK 0xFFC0010C /* Interrupt Mask Register */
+#define SIC_IAR0 0xFFC00110 /* Interrupt Assignment Register 0 */
+#define SIC_IAR1 0xFFC00114 /* Interrupt Assignment Register 1 */
+#define SIC_IAR2 0xFFC00118 /* Interrupt Assignment Register 2 */
+#define SIC_IAR3 0xFFC0011C /* Interrupt Assignment Register 3 */
+#define SIC_ISR 0xFFC00120 /* Interrupt Status Register */
+#define SIC_IWR 0xFFC00124 /* Interrupt Wakeup Register */
+
+/* Watchdog Timer (0xFFC00200 - 0xFFC002FF) */
+#define WDOG_CTL 0xFFC00200 /* Watchdog Control Register */
+#define WDOG_CNT 0xFFC00204 /* Watchdog Count Register */
+#define WDOG_STAT 0xFFC00208 /* Watchdog Status Register */
+
+/* Real Time Clock (0xFFC00300 - 0xFFC003FF) */
+#define RTC_STAT 0xFFC00300 /* RTC Status Register */
+#define RTC_ICTL 0xFFC00304 /* RTC Interrupt Control Register */
+#define RTC_ISTAT 0xFFC00308 /* RTC Interrupt Status Register */
+#define RTC_SWCNT 0xFFC0030C /* RTC Stopwatch Count Register */
+#define RTC_ALARM 0xFFC00310 /* RTC Alarm Time Register */
+#define RTC_FAST 0xFFC00314 /* RTC Prescaler Enable Register */
+#define RTC_PREN 0xFFC00314 /* RTC Prescaler Enable Alternate Macro */
+
+/* UART0 Controller (0xFFC00400 - 0xFFC004FF) */
+#define UART0_THR 0xFFC00400 /* Transmit Holding register */
+#define UART0_RBR 0xFFC00400 /* Receive Buffer register */
+#define UART0_DLL 0xFFC00400 /* Divisor Latch (Low-Byte) */
+#define UART0_IER 0xFFC00404 /* Interrupt Enable Register */
+#define UART0_DLH 0xFFC00404 /* Divisor Latch (High-Byte) */
+#define UART0_IIR 0xFFC00408 /* Interrupt Identification Register */
+#define UART0_LCR 0xFFC0040C /* Line Control Register */
+#define UART0_MCR 0xFFC00410 /* Modem Control Register */
+#define UART0_LSR 0xFFC00414 /* Line Status Register */
+#define UART0_MSR 0xFFC00418 /* Modem Status Register */
+#define UART0_SCR 0xFFC0041C /* SCR Scratch Register */
+#define UART0_GCTL 0xFFC00424 /* Global Control Register */
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define SPI_CTL 0xFFC00500 /* SPI Control Register */
+#define SPI_FLG 0xFFC00504 /* SPI Flag register */
+#define SPI_STAT 0xFFC00508 /* SPI Status register */
+#define SPI_TDBR 0xFFC0050C /* SPI Transmit Data Buffer Register */
+#define SPI_RDBR 0xFFC00510 /* SPI Receive Data Buffer Register */
+#define SPI_BAUD 0xFFC00514 /* SPI Baud rate Register */
+#define SPI_SHADOW 0xFFC00518 /* SPI_RDBR Shadow Register */
+
+/* TIMER0-7 Registers (0xFFC00600 - 0xFFC006FF) */
+#define TIMER0_CONFIG 0xFFC00600 /* Timer 0 Configuration Register */
+#define TIMER0_COUNTER 0xFFC00604 /* Timer 0 Counter Register */
+#define TIMER0_PERIOD 0xFFC00608 /* Timer 0 Period Register */
+#define TIMER0_WIDTH 0xFFC0060C /* Timer 0 Width Register */
+
+#define TIMER1_CONFIG 0xFFC00610 /* Timer 1 Configuration Register */
+#define TIMER1_COUNTER 0xFFC00614 /* Timer 1 Counter Register */
+#define TIMER1_PERIOD 0xFFC00618 /* Timer 1 Period Register */
+#define TIMER1_WIDTH 0xFFC0061C /* Timer 1 Width Register */
+
+#define TIMER2_CONFIG 0xFFC00620 /* Timer 2 Configuration Register */
+#define TIMER2_COUNTER 0xFFC00624 /* Timer 2 Counter Register */
+#define TIMER2_PERIOD 0xFFC00628 /* Timer 2 Period Register */
+#define TIMER2_WIDTH 0xFFC0062C /* Timer 2 Width Register */
+
+#define TIMER3_CONFIG 0xFFC00630 /* Timer 3 Configuration Register */
+#define TIMER3_COUNTER 0xFFC00634 /* Timer 3 Counter Register */
+#define TIMER3_PERIOD 0xFFC00638 /* Timer 3 Period Register */
+#define TIMER3_WIDTH 0xFFC0063C /* Timer 3 Width Register */
+
+#define TIMER4_CONFIG 0xFFC00640 /* Timer 4 Configuration Register */
+#define TIMER4_COUNTER 0xFFC00644 /* Timer 4 Counter Register */
+#define TIMER4_PERIOD 0xFFC00648 /* Timer 4 Period Register */
+#define TIMER4_WIDTH 0xFFC0064C /* Timer 4 Width Register */
+
+#define TIMER5_CONFIG 0xFFC00650 /* Timer 5 Configuration Register */
+#define TIMER5_COUNTER 0xFFC00654 /* Timer 5 Counter Register */
+#define TIMER5_PERIOD 0xFFC00658 /* Timer 5 Period Register */
+#define TIMER5_WIDTH 0xFFC0065C /* Timer 5 Width Register */
+
+#define TIMER6_CONFIG 0xFFC00660 /* Timer 6 Configuration Register */
+#define TIMER6_COUNTER 0xFFC00664 /* Timer 6 Counter Register */
+#define TIMER6_PERIOD 0xFFC00668 /* Timer 6 Period Register */
+#define TIMER6_WIDTH 0xFFC0066C /* Timer 6 Width Register */
+
+#define TIMER7_CONFIG 0xFFC00670 /* Timer 7 Configuration Register */
+#define TIMER7_COUNTER 0xFFC00674 /* Timer 7 Counter Register */
+#define TIMER7_PERIOD 0xFFC00678 /* Timer 7 Period Register */
+#define TIMER7_WIDTH 0xFFC0067C /* Timer 7 Width Register */
+
+#define TIMER_ENABLE 0xFFC00680 /* Timer Enable Register */
+#define TIMER_DISABLE 0xFFC00684 /* Timer Disable Register */
+#define TIMER_STATUS 0xFFC00688 /* Timer Status Register */
+
+/* General Purpose I/O Port F (0xFFC00700 - 0xFFC007FF) */
+#define PORTFIO 0xFFC00700 /* Port F I/O Pin State Specify Register */
+#define PORTFIO_CLEAR 0xFFC00704 /* Port F I/O Peripheral Interrupt Clear Register */
+#define PORTFIO_SET 0xFFC00708 /* Port F I/O Peripheral Interrupt Set Register */
+#define PORTFIO_TOGGLE 0xFFC0070C /* Port F I/O Pin State Toggle Register */
+#define PORTFIO_MASKA 0xFFC00710 /* Port F I/O Mask State Specify Interrupt A Register */
+#define PORTFIO_MASKA_CLEAR 0xFFC00714 /* Port F I/O Mask Disable Interrupt A Register */
+#define PORTFIO_MASKA_SET 0xFFC00718 /* Port F I/O Mask Enable Interrupt A Register */
+#define PORTFIO_MASKA_TOGGLE 0xFFC0071C /* Port F I/O Mask Toggle Enable Interrupt A Register */
+#define PORTFIO_MASKB 0xFFC00720 /* Port F I/O Mask State Specify Interrupt B Register */
+#define PORTFIO_MASKB_CLEAR 0xFFC00724 /* Port F I/O Mask Disable Interrupt B Register */
+#define PORTFIO_MASKB_SET 0xFFC00728 /* Port F I/O Mask Enable Interrupt B Register */
+#define PORTFIO_MASKB_TOGGLE 0xFFC0072C /* Port F I/O Mask Toggle Enable Interrupt B Register */
+#define PORTFIO_DIR 0xFFC00730 /* Port F I/O Direction Register */
+#define PORTFIO_POLAR 0xFFC00734 /* Port F I/O Source Polarity Register */
+#define PORTFIO_EDGE 0xFFC00738 /* Port F I/O Source Sensitivity Register */
+#define PORTFIO_BOTH 0xFFC0073C /* Port F I/O Set on BOTH Edges Register */
+#define PORTFIO_INEN 0xFFC00740 /* Port F I/O Input Enable Register */
+
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define SPORT0_TCR1 0xFFC00800 /* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_TCR2 0xFFC00804 /* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_TCLKDIV 0xFFC00808 /* SPORT0 Transmit Clock Divider */
+#define SPORT0_TFSDIV 0xFFC0080C /* SPORT0 Transmit Frame Sync Divider */
+#define SPORT0_TX 0xFFC00810 /* SPORT0 TX Data Register */
+#define SPORT0_RX 0xFFC00818 /* SPORT0 RX Data Register */
+#define SPORT0_RCR1 0xFFC00820 /* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_RCR2 0xFFC00824 /* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_RCLKDIV 0xFFC00828 /* SPORT0 Receive Clock Divider */
+#define SPORT0_RFSDIV 0xFFC0082C /* SPORT0 Receive Frame Sync Divider */
+#define SPORT0_STAT 0xFFC00830 /* SPORT0 Status Register */
+#define SPORT0_CHNL 0xFFC00834 /* SPORT0 Current Channel Register */
+#define SPORT0_MCMC1 0xFFC00838 /* SPORT0 Multi-Channel Configuration Register 1 */
+#define SPORT0_MCMC2 0xFFC0083C /* SPORT0 Multi-Channel Configuration Register 2 */
+#define SPORT0_MTCS0 0xFFC00840 /* SPORT0 Multi-Channel Transmit Select Register 0 */
+#define SPORT0_MTCS1 0xFFC00844 /* SPORT0 Multi-Channel Transmit Select Register 1 */
+#define SPORT0_MTCS2 0xFFC00848 /* SPORT0 Multi-Channel Transmit Select Register 2 */
+#define SPORT0_MTCS3 0xFFC0084C /* SPORT0 Multi-Channel Transmit Select Register 3 */
+#define SPORT0_MRCS0 0xFFC00850 /* SPORT0 Multi-Channel Receive Select Register 0 */
+#define SPORT0_MRCS1 0xFFC00854 /* SPORT0 Multi-Channel Receive Select Register 1 */
+#define SPORT0_MRCS2 0xFFC00858 /* SPORT0 Multi-Channel Receive Select Register 2 */
+#define SPORT0_MRCS3 0xFFC0085C /* SPORT0 Multi-Channel Receive Select Register 3 */
+
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define SPORT1_TCR1 0xFFC00900 /* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_TCR2 0xFFC00904 /* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_TCLKDIV 0xFFC00908 /* SPORT1 Transmit Clock Divider */
+#define SPORT1_TFSDIV 0xFFC0090C /* SPORT1 Transmit Frame Sync Divider */
+#define SPORT1_TX 0xFFC00910 /* SPORT1 TX Data Register */
+#define SPORT1_RX 0xFFC00918 /* SPORT1 RX Data Register */
+#define SPORT1_RCR1 0xFFC00920 /* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_RCR2 0xFFC00924 /* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_RCLKDIV 0xFFC00928 /* SPORT1 Receive Clock Divider */
+#define SPORT1_RFSDIV 0xFFC0092C /* SPORT1 Receive Frame Sync Divider */
+#define SPORT1_STAT 0xFFC00930 /* SPORT1 Status Register */
+#define SPORT1_CHNL 0xFFC00934 /* SPORT1 Current Channel Register */
+#define SPORT1_MCMC1 0xFFC00938 /* SPORT1 Multi-Channel Configuration Register 1 */
+#define SPORT1_MCMC2 0xFFC0093C /* SPORT1 Multi-Channel Configuration Register 2 */
+#define SPORT1_MTCS0 0xFFC00940 /* SPORT1 Multi-Channel Transmit Select Register 0 */
+#define SPORT1_MTCS1 0xFFC00944 /* SPORT1 Multi-Channel Transmit Select Register 1 */
+#define SPORT1_MTCS2 0xFFC00948 /* SPORT1 Multi-Channel Transmit Select Register 2 */
+#define SPORT1_MTCS3 0xFFC0094C /* SPORT1 Multi-Channel Transmit Select Register 3 */
+#define SPORT1_MRCS0 0xFFC00950 /* SPORT1 Multi-Channel Receive Select Register 0 */
+#define SPORT1_MRCS1 0xFFC00954 /* SPORT1 Multi-Channel Receive Select Register 1 */
+#define SPORT1_MRCS2 0xFFC00958 /* SPORT1 Multi-Channel Receive Select Register 2 */
+#define SPORT1_MRCS3 0xFFC0095C /* SPORT1 Multi-Channel Receive Select Register 3 */
+
+/* External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+#define EBIU_AMGCTL 0xFFC00A00 /* Asynchronous Memory Global Control Register */
+#define EBIU_AMBCTL0 0xFFC00A04 /* Asynchronous Memory Bank Control Register 0 */
+#define EBIU_AMBCTL1 0xFFC00A08 /* Asynchronous Memory Bank Control Register 1 */
+#define EBIU_SDGCTL 0xFFC00A10 /* SDRAM Global Control Register */
+#define EBIU_SDBCTL 0xFFC00A14 /* SDRAM Bank Control Register */
+#define EBIU_SDRRC 0xFFC00A18 /* SDRAM Refresh Rate Control Register */
+#define EBIU_SDSTAT 0xFFC00A1C /* SDRAM Status Register */
+
+/* DMA Traffic Control Registers */
+#define DMA_TCPER 0xFFC00B0C /* Traffic Control Periods Register */
+#define DMA_TCCNT 0xFFC00B10 /* Traffic Control Current Counts Register */
+
+/* DMA Controller (0xFFC00C00 - 0xFFC00FFF) */
+#define DMA0_NEXT_DESC_PTR 0xFFC00C00 /* DMA Channel 0 Next Descriptor Pointer Register */
+#define DMA0_START_ADDR 0xFFC00C04 /* DMA Channel 0 Start Address Register */
+#define DMA0_CONFIG 0xFFC00C08 /* DMA Channel 0 Configuration Register */
+#define DMA0_X_COUNT 0xFFC00C10 /* DMA Channel 0 X Count Register */
+#define DMA0_X_MODIFY 0xFFC00C14 /* DMA Channel 0 X Modify Register */
+#define DMA0_Y_COUNT 0xFFC00C18 /* DMA Channel 0 Y Count Register */
+#define DMA0_Y_MODIFY 0xFFC00C1C /* DMA Channel 0 Y Modify Register */
+#define DMA0_CURR_DESC_PTR 0xFFC00C20 /* DMA Channel 0 Current Descriptor Pointer Register */
+#define DMA0_CURR_ADDR 0xFFC00C24 /* DMA Channel 0 Current Address Register */
+#define DMA0_IRQ_STATUS 0xFFC00C28 /* DMA Channel 0 Interrupt/Status Register */
+#define DMA0_PERIPHERAL_MAP 0xFFC00C2C /* DMA Channel 0 Peripheral Map Register */
+#define DMA0_CURR_X_COUNT 0xFFC00C30 /* DMA Channel 0 Current X Count Register */
+#define DMA0_CURR_Y_COUNT 0xFFC00C38 /* DMA Channel 0 Current Y Count Register */
+
+#define DMA1_NEXT_DESC_PTR 0xFFC00C40 /* DMA Channel 1 Next Descriptor Pointer Register */
+#define DMA1_START_ADDR 0xFFC00C44 /* DMA Channel 1 Start Address Register */
+#define DMA1_CONFIG 0xFFC00C48 /* DMA Channel 1 Configuration Register */
+#define DMA1_X_COUNT 0xFFC00C50 /* DMA Channel 1 X Count Register */
+#define DMA1_X_MODIFY 0xFFC00C54 /* DMA Channel 1 X Modify Register */
+#define DMA1_Y_COUNT 0xFFC00C58 /* DMA Channel 1 Y Count Register */
+#define DMA1_Y_MODIFY 0xFFC00C5C /* DMA Channel 1 Y Modify Register */
+#define DMA1_CURR_DESC_PTR 0xFFC00C60 /* DMA Channel 1 Current Descriptor Pointer Register */
+#define DMA1_CURR_ADDR 0xFFC00C64 /* DMA Channel 1 Current Address Register */
+#define DMA1_IRQ_STATUS 0xFFC00C68 /* DMA Channel 1 Interrupt/Status Register */
+#define DMA1_PERIPHERAL_MAP 0xFFC00C6C /* DMA Channel 1 Peripheral Map Register */
+#define DMA1_CURR_X_COUNT 0xFFC00C70 /* DMA Channel 1 Current X Count Register */
+#define DMA1_CURR_Y_COUNT 0xFFC00C78 /* DMA Channel 1 Current Y Count Register */
+
+#define DMA2_NEXT_DESC_PTR 0xFFC00C80 /* DMA Channel 2 Next Descriptor Pointer Register */
+#define DMA2_START_ADDR 0xFFC00C84 /* DMA Channel 2 Start Address Register */
+#define DMA2_CONFIG 0xFFC00C88 /* DMA Channel 2 Configuration Register */
+#define DMA2_X_COUNT 0xFFC00C90 /* DMA Channel 2 X Count Register */
+#define DMA2_X_MODIFY 0xFFC00C94 /* DMA Channel 2 X Modify Register */
+#define DMA2_Y_COUNT 0xFFC00C98 /* DMA Channel 2 Y Count Register */
+#define DMA2_Y_MODIFY 0xFFC00C9C /* DMA Channel 2 Y Modify Register */
+#define DMA2_CURR_DESC_PTR 0xFFC00CA0 /* DMA Channel 2 Current Descriptor Pointer Register */
+#define DMA2_CURR_ADDR 0xFFC00CA4 /* DMA Channel 2 Current Address Register */
+#define DMA2_IRQ_STATUS 0xFFC00CA8 /* DMA Channel 2 Interrupt/Status Register */
+#define DMA2_PERIPHERAL_MAP 0xFFC00CAC /* DMA Channel 2 Peripheral Map Register */
+#define DMA2_CURR_X_COUNT 0xFFC00CB0 /* DMA Channel 2 Current X Count Register */
+#define DMA2_CURR_Y_COUNT 0xFFC00CB8 /* DMA Channel 2 Current Y Count Register */
+
+#define DMA3_NEXT_DESC_PTR 0xFFC00CC0 /* DMA Channel 3 Next Descriptor Pointer Register */
+#define DMA3_START_ADDR 0xFFC00CC4 /* DMA Channel 3 Start Address Register */
+#define DMA3_CONFIG 0xFFC00CC8 /* DMA Channel 3 Configuration Register */
+#define DMA3_X_COUNT 0xFFC00CD0 /* DMA Channel 3 X Count Register */
+#define DMA3_X_MODIFY 0xFFC00CD4 /* DMA Channel 3 X Modify Register */
+#define DMA3_Y_COUNT 0xFFC00CD8 /* DMA Channel 3 Y Count Register */
+#define DMA3_Y_MODIFY 0xFFC00CDC /* DMA Channel 3 Y Modify Register */
+#define DMA3_CURR_DESC_PTR 0xFFC00CE0 /* DMA Channel 3 Current Descriptor Pointer Register */
+#define DMA3_CURR_ADDR 0xFFC00CE4 /* DMA Channel 3 Current Address Register */
+#define DMA3_IRQ_STATUS 0xFFC00CE8 /* DMA Channel 3 Interrupt/Status Register */
+#define DMA3_PERIPHERAL_MAP 0xFFC00CEC /* DMA Channel 3 Peripheral Map Register */
+#define DMA3_CURR_X_COUNT 0xFFC00CF0 /* DMA Channel 3 Current X Count Register */
+#define DMA3_CURR_Y_COUNT 0xFFC00CF8 /* DMA Channel 3 Current Y Count Register */
+
+#define DMA4_NEXT_DESC_PTR 0xFFC00D00 /* DMA Channel 4 Next Descriptor Pointer Register */
+#define DMA4_START_ADDR 0xFFC00D04 /* DMA Channel 4 Start Address Register */
+#define DMA4_CONFIG 0xFFC00D08 /* DMA Channel 4 Configuration Register */
+#define DMA4_X_COUNT 0xFFC00D10 /* DMA Channel 4 X Count Register */
+#define DMA4_X_MODIFY 0xFFC00D14 /* DMA Channel 4 X Modify Register */
+#define DMA4_Y_COUNT 0xFFC00D18 /* DMA Channel 4 Y Count Register */
+#define DMA4_Y_MODIFY 0xFFC00D1C /* DMA Channel 4 Y Modify Register */
+#define DMA4_CURR_DESC_PTR 0xFFC00D20 /* DMA Channel 4 Current Descriptor Pointer Register */
+#define DMA4_CURR_ADDR 0xFFC00D24 /* DMA Channel 4 Current Address Register */
+#define DMA4_IRQ_STATUS 0xFFC00D28 /* DMA Channel 4 Interrupt/Status Register */
+#define DMA4_PERIPHERAL_MAP 0xFFC00D2C /* DMA Channel 4 Peripheral Map Register */
+#define DMA4_CURR_X_COUNT 0xFFC00D30 /* DMA Channel 4 Current X Count Register */
+#define DMA4_CURR_Y_COUNT 0xFFC00D38 /* DMA Channel 4 Current Y Count Register */
+
+#define DMA5_NEXT_DESC_PTR 0xFFC00D40 /* DMA Channel 5 Next Descriptor Pointer Register */
+#define DMA5_START_ADDR 0xFFC00D44 /* DMA Channel 5 Start Address Register */
+#define DMA5_CONFIG 0xFFC00D48 /* DMA Channel 5 Configuration Register */
+#define DMA5_X_COUNT 0xFFC00D50 /* DMA Channel 5 X Count Register */
+#define DMA5_X_MODIFY 0xFFC00D54 /* DMA Channel 5 X Modify Register */
+#define DMA5_Y_COUNT 0xFFC00D58 /* DMA Channel 5 Y Count Register */
+#define DMA5_Y_MODIFY 0xFFC00D5C /* DMA Channel 5 Y Modify Register */
+#define DMA5_CURR_DESC_PTR 0xFFC00D60 /* DMA Channel 5 Current Descriptor Pointer Register */
+#define DMA5_CURR_ADDR 0xFFC00D64 /* DMA Channel 5 Current Address Register */
+#define DMA5_IRQ_STATUS 0xFFC00D68 /* DMA Channel 5 Interrupt/Status Register */
+#define DMA5_PERIPHERAL_MAP 0xFFC00D6C /* DMA Channel 5 Peripheral Map Register */
+#define DMA5_CURR_X_COUNT 0xFFC00D70 /* DMA Channel 5 Current X Count Register */
+#define DMA5_CURR_Y_COUNT 0xFFC00D78 /* DMA Channel 5 Current Y Count Register */
+
+#define DMA6_NEXT_DESC_PTR 0xFFC00D80 /* DMA Channel 6 Next Descriptor Pointer Register */
+#define DMA6_START_ADDR 0xFFC00D84 /* DMA Channel 6 Start Address Register */
+#define DMA6_CONFIG 0xFFC00D88 /* DMA Channel 6 Configuration Register */
+#define DMA6_X_COUNT 0xFFC00D90 /* DMA Channel 6 X Count Register */
+#define DMA6_X_MODIFY 0xFFC00D94 /* DMA Channel 6 X Modify Register */
+#define DMA6_Y_COUNT 0xFFC00D98 /* DMA Channel 6 Y Count Register */
+#define DMA6_Y_MODIFY 0xFFC00D9C /* DMA Channel 6 Y Modify Register */
+#define DMA6_CURR_DESC_PTR 0xFFC00DA0 /* DMA Channel 6 Current Descriptor Pointer Register */
+#define DMA6_CURR_ADDR 0xFFC00DA4 /* DMA Channel 6 Current Address Register */
+#define DMA6_IRQ_STATUS 0xFFC00DA8 /* DMA Channel 6 Interrupt/Status Register */
+#define DMA6_PERIPHERAL_MAP 0xFFC00DAC /* DMA Channel 6 Peripheral Map Register */
+#define DMA6_CURR_X_COUNT 0xFFC00DB0 /* DMA Channel 6 Current X Count Register */
+#define DMA6_CURR_Y_COUNT 0xFFC00DB8 /* DMA Channel 6 Current Y Count Register */
+
+#define DMA7_NEXT_DESC_PTR 0xFFC00DC0 /* DMA Channel 7 Next Descriptor Pointer Register */
+#define DMA7_START_ADDR 0xFFC00DC4 /* DMA Channel 7 Start Address Register */
+#define DMA7_CONFIG 0xFFC00DC8 /* DMA Channel 7 Configuration Register */
+#define DMA7_X_COUNT 0xFFC00DD0 /* DMA Channel 7 X Count Register */
+#define DMA7_X_MODIFY 0xFFC00DD4 /* DMA Channel 7 X Modify Register */
+#define DMA7_Y_COUNT 0xFFC00DD8 /* DMA Channel 7 Y Count Register */
+#define DMA7_Y_MODIFY 0xFFC00DDC /* DMA Channel 7 Y Modify Register */
+#define DMA7_CURR_DESC_PTR 0xFFC00DE0 /* DMA Channel 7 Current Descriptor Pointer Register */
+#define DMA7_CURR_ADDR 0xFFC00DE4 /* DMA Channel 7 Current Address Register */
+#define DMA7_IRQ_STATUS 0xFFC00DE8 /* DMA Channel 7 Interrupt/Status Register */
+#define DMA7_PERIPHERAL_MAP 0xFFC00DEC /* DMA Channel 7 Peripheral Map Register */
+#define DMA7_CURR_X_COUNT 0xFFC00DF0 /* DMA Channel 7 Current X Count Register */
+#define DMA7_CURR_Y_COUNT 0xFFC00DF8 /* DMA Channel 7 Current Y Count Register */
+
+#define DMA8_NEXT_DESC_PTR 0xFFC00E00 /* DMA Channel 8 Next Descriptor Pointer Register */
+#define DMA8_START_ADDR 0xFFC00E04 /* DMA Channel 8 Start Address Register */
+#define DMA8_CONFIG 0xFFC00E08 /* DMA Channel 8 Configuration Register */
+#define DMA8_X_COUNT 0xFFC00E10 /* DMA Channel 8 X Count Register */
+#define DMA8_X_MODIFY 0xFFC00E14 /* DMA Channel 8 X Modify Register */
+#define DMA8_Y_COUNT 0xFFC00E18 /* DMA Channel 8 Y Count Register */
+#define DMA8_Y_MODIFY 0xFFC00E1C /* DMA Channel 8 Y Modify Register */
+#define DMA8_CURR_DESC_PTR 0xFFC00E20 /* DMA Channel 8 Current Descriptor Pointer Register */
+#define DMA8_CURR_ADDR 0xFFC00E24 /* DMA Channel 8 Current Address Register */
+#define DMA8_IRQ_STATUS 0xFFC00E28 /* DMA Channel 8 Interrupt/Status Register */
+#define DMA8_PERIPHERAL_MAP 0xFFC00E2C /* DMA Channel 8 Peripheral Map Register */
+#define DMA8_CURR_X_COUNT 0xFFC00E30 /* DMA Channel 8 Current X Count Register */
+#define DMA8_CURR_Y_COUNT 0xFFC00E38 /* DMA Channel 8 Current Y Count Register */
+
+#define DMA9_NEXT_DESC_PTR 0xFFC00E40 /* DMA Channel 9 Next Descriptor Pointer Register */
+#define DMA9_START_ADDR 0xFFC00E44 /* DMA Channel 9 Start Address Register */
+#define DMA9_CONFIG 0xFFC00E48 /* DMA Channel 9 Configuration Register */
+#define DMA9_X_COUNT 0xFFC00E50 /* DMA Channel 9 X Count Register */
+#define DMA9_X_MODIFY 0xFFC00E54 /* DMA Channel 9 X Modify Register */
+#define DMA9_Y_COUNT 0xFFC00E58 /* DMA Channel 9 Y Count Register */
+#define DMA9_Y_MODIFY 0xFFC00E5C /* DMA Channel 9 Y Modify Register */
+#define DMA9_CURR_DESC_PTR 0xFFC00E60 /* DMA Channel 9 Current Descriptor Pointer Register */
+#define DMA9_CURR_ADDR 0xFFC00E64 /* DMA Channel 9 Current Address Register */
+#define DMA9_IRQ_STATUS 0xFFC00E68 /* DMA Channel 9 Interrupt/Status Register */
+#define DMA9_PERIPHERAL_MAP 0xFFC00E6C /* DMA Channel 9 Peripheral Map Register */
+#define DMA9_CURR_X_COUNT 0xFFC00E70 /* DMA Channel 9 Current X Count Register */
+#define DMA9_CURR_Y_COUNT 0xFFC00E78 /* DMA Channel 9 Current Y Count Register */
+
+#define DMA10_NEXT_DESC_PTR 0xFFC00E80 /* DMA Channel 10 Next Descriptor Pointer Register */
+#define DMA10_START_ADDR 0xFFC00E84 /* DMA Channel 10 Start Address Register */
+#define DMA10_CONFIG 0xFFC00E88 /* DMA Channel 10 Configuration Register */
+#define DMA10_X_COUNT 0xFFC00E90 /* DMA Channel 10 X Count Register */
+#define DMA10_X_MODIFY 0xFFC00E94 /* DMA Channel 10 X Modify Register */
+#define DMA10_Y_COUNT 0xFFC00E98 /* DMA Channel 10 Y Count Register */
+#define DMA10_Y_MODIFY 0xFFC00E9C /* DMA Channel 10 Y Modify Register */
+#define DMA10_CURR_DESC_PTR 0xFFC00EA0 /* DMA Channel 10 Current Descriptor Pointer Register */
+#define DMA10_CURR_ADDR 0xFFC00EA4 /* DMA Channel 10 Current Address Register */
+#define DMA10_IRQ_STATUS 0xFFC00EA8 /* DMA Channel 10 Interrupt/Status Register */
+#define DMA10_PERIPHERAL_MAP 0xFFC00EAC /* DMA Channel 10 Peripheral Map Register */
+#define DMA10_CURR_X_COUNT 0xFFC00EB0 /* DMA Channel 10 Current X Count Register */
+#define DMA10_CURR_Y_COUNT 0xFFC00EB8 /* DMA Channel 10 Current Y Count Register */
+
+#define DMA11_NEXT_DESC_PTR 0xFFC00EC0 /* DMA Channel 11 Next Descriptor Pointer Register */
+#define DMA11_START_ADDR 0xFFC00EC4 /* DMA Channel 11 Start Address Register */
+#define DMA11_CONFIG 0xFFC00EC8 /* DMA Channel 11 Configuration Register */
+#define DMA11_X_COUNT 0xFFC00ED0 /* DMA Channel 11 X Count Register */
+#define DMA11_X_MODIFY 0xFFC00ED4 /* DMA Channel 11 X Modify Register */
+#define DMA11_Y_COUNT 0xFFC00ED8 /* DMA Channel 11 Y Count Register */
+#define DMA11_Y_MODIFY 0xFFC00EDC /* DMA Channel 11 Y Modify Register */
+#define DMA11_CURR_DESC_PTR 0xFFC00EE0 /* DMA Channel 11 Current Descriptor Pointer Register */
+#define DMA11_CURR_ADDR 0xFFC00EE4 /* DMA Channel 11 Current Address Register */
+#define DMA11_IRQ_STATUS 0xFFC00EE8 /* DMA Channel 11 Interrupt/Status Register */
+#define DMA11_PERIPHERAL_MAP 0xFFC00EEC /* DMA Channel 11 Peripheral Map Register */
+#define DMA11_CURR_X_COUNT 0xFFC00EF0 /* DMA Channel 11 Current X Count Register */
+#define DMA11_CURR_Y_COUNT 0xFFC00EF8 /* DMA Channel 11 Current Y Count Register */
+
+#define MDMA_D0_NEXT_DESC_PTR 0xFFC00F00 /* MemDMA Stream 0 Destination Next Descriptor Pointer Register */
+#define MDMA_D0_START_ADDR 0xFFC00F04 /* MemDMA Stream 0 Destination Start Address Register */
+#define MDMA_D0_CONFIG 0xFFC00F08 /* MemDMA Stream 0 Destination Configuration Register */
+#define MDMA_D0_X_COUNT 0xFFC00F10 /* MemDMA Stream 0 Destination X Count Register */
+#define MDMA_D0_X_MODIFY 0xFFC00F14 /* MemDMA Stream 0 Destination X Modify Register */
+#define MDMA_D0_Y_COUNT 0xFFC00F18 /* MemDMA Stream 0 Destination Y Count Register */
+#define MDMA_D0_Y_MODIFY 0xFFC00F1C /* MemDMA Stream 0 Destination Y Modify Register */
+#define MDMA_D0_CURR_DESC_PTR 0xFFC00F20 /* MemDMA Stream 0 Destination Current Descriptor Pointer Register */
+#define MDMA_D0_CURR_ADDR 0xFFC00F24 /* MemDMA Stream 0 Destination Current Address Register */
+#define MDMA_D0_IRQ_STATUS 0xFFC00F28 /* MemDMA Stream 0 Destination Interrupt/Status Register */
+#define MDMA_D0_PERIPHERAL_MAP 0xFFC00F2C /* MemDMA Stream 0 Destination Peripheral Map Register */
+#define MDMA_D0_CURR_X_COUNT 0xFFC00F30 /* MemDMA Stream 0 Destination Current X Count Register */
+#define MDMA_D0_CURR_Y_COUNT 0xFFC00F38 /* MemDMA Stream 0 Destination Current Y Count Register */
+
+#define MDMA_S0_NEXT_DESC_PTR 0xFFC00F40 /* MemDMA Stream 0 Source Next Descriptor Pointer Register */
+#define MDMA_S0_START_ADDR 0xFFC00F44 /* MemDMA Stream 0 Source Start Address Register */
+#define MDMA_S0_CONFIG 0xFFC00F48 /* MemDMA Stream 0 Source Configuration Register */
+#define MDMA_S0_X_COUNT 0xFFC00F50 /* MemDMA Stream 0 Source X Count Register */
+#define MDMA_S0_X_MODIFY 0xFFC00F54 /* MemDMA Stream 0 Source X Modify Register */
+#define MDMA_S0_Y_COUNT 0xFFC00F58 /* MemDMA Stream 0 Source Y Count Register */
+#define MDMA_S0_Y_MODIFY 0xFFC00F5C /* MemDMA Stream 0 Source Y Modify Register */
+#define MDMA_S0_CURR_DESC_PTR 0xFFC00F60 /* MemDMA Stream 0 Source Current Descriptor Pointer Register */
+#define MDMA_S0_CURR_ADDR 0xFFC00F64 /* MemDMA Stream 0 Source Current Address Register */
+#define MDMA_S0_IRQ_STATUS 0xFFC00F68 /* MemDMA Stream 0 Source Interrupt/Status Register */
+#define MDMA_S0_PERIPHERAL_MAP 0xFFC00F6C /* MemDMA Stream 0 Source Peripheral Map Register */
+#define MDMA_S0_CURR_X_COUNT 0xFFC00F70 /* MemDMA Stream 0 Source Current X Count Register */
+#define MDMA_S0_CURR_Y_COUNT 0xFFC00F78 /* MemDMA Stream 0 Source Current Y Count Register */
+
+#define MDMA_D1_NEXT_DESC_PTR 0xFFC00F80 /* MemDMA Stream 1 Destination Next Descriptor Pointer Register */
+#define MDMA_D1_START_ADDR 0xFFC00F84 /* MemDMA Stream 1 Destination Start Address Register */
+#define MDMA_D1_CONFIG 0xFFC00F88 /* MemDMA Stream 1 Destination Configuration Register */
+#define MDMA_D1_X_COUNT 0xFFC00F90 /* MemDMA Stream 1 Destination X Count Register */
+#define MDMA_D1_X_MODIFY 0xFFC00F94 /* MemDMA Stream 1 Destination X Modify Register */
+#define MDMA_D1_Y_COUNT 0xFFC00F98 /* MemDMA Stream 1 Destination Y Count Register */
+#define MDMA_D1_Y_MODIFY 0xFFC00F9C /* MemDMA Stream 1 Destination Y Modify Register */
+#define MDMA_D1_CURR_DESC_PTR 0xFFC00FA0 /* MemDMA Stream 1 Destination Current Descriptor Pointer Register */
+#define MDMA_D1_CURR_ADDR 0xFFC00FA4 /* MemDMA Stream 1 Destination Current Address Register */
+#define MDMA_D1_IRQ_STATUS 0xFFC00FA8 /* MemDMA Stream 1 Destination Interrupt/Status Register */
+#define MDMA_D1_PERIPHERAL_MAP 0xFFC00FAC /* MemDMA Stream 1 Destination Peripheral Map Register */
+#define MDMA_D1_CURR_X_COUNT 0xFFC00FB0 /* MemDMA Stream 1 Destination Current X Count Register */
+#define MDMA_D1_CURR_Y_COUNT 0xFFC00FB8 /* MemDMA Stream 1 Destination Current Y Count Register */
+
+#define MDMA_S1_NEXT_DESC_PTR 0xFFC00FC0 /* MemDMA Stream 1 Source Next Descriptor Pointer Register */
+#define MDMA_S1_START_ADDR 0xFFC00FC4 /* MemDMA Stream 1 Source Start Address Register */
+#define MDMA_S1_CONFIG 0xFFC00FC8 /* MemDMA Stream 1 Source Configuration Register */
+#define MDMA_S1_X_COUNT 0xFFC00FD0 /* MemDMA Stream 1 Source X Count Register */
+#define MDMA_S1_X_MODIFY 0xFFC00FD4 /* MemDMA Stream 1 Source X Modify Register */
+#define MDMA_S1_Y_COUNT 0xFFC00FD8 /* MemDMA Stream 1 Source Y Count Register */
+#define MDMA_S1_Y_MODIFY 0xFFC00FDC /* MemDMA Stream 1 Source Y Modify Register */
+#define MDMA_S1_CURR_DESC_PTR 0xFFC00FE0 /* MemDMA Stream 1 Source Current Descriptor Pointer Register */
+#define MDMA_S1_CURR_ADDR 0xFFC00FE4 /* MemDMA Stream 1 Source Current Address Register */
+#define MDMA_S1_IRQ_STATUS 0xFFC00FE8 /* MemDMA Stream 1 Source Interrupt/Status Register */
+#define MDMA_S1_PERIPHERAL_MAP 0xFFC00FEC /* MemDMA Stream 1 Source Peripheral Map Register */
+#define MDMA_S1_CURR_X_COUNT 0xFFC00FF0 /* MemDMA Stream 1 Source Current X Count Register */
+#define MDMA_S1_CURR_Y_COUNT 0xFFC00FF8 /* MemDMA Stream 1 Source Current Y Count Register */
+
+/* Parallel Peripheral Interface (0xFFC01000 - 0xFFC010FF) */
+#define PPI_CONTROL 0xFFC01000 /* PPI Control Register */
+#define PPI_STATUS 0xFFC01004 /* PPI Status Register */
+#define PPI_COUNT 0xFFC01008 /* PPI Transfer Count Register */
+#define PPI_DELAY 0xFFC0100C /* PPI Delay Count Register */
+#define PPI_FRAME 0xFFC01010 /* PPI Frame Length Register */
+
+/* Two-Wire Interface (0xFFC01400 - 0xFFC014FF) */
+#define TWI_CLKDIV 0xFFC01400 /* Serial Clock Divider Register */
+#define TWI_CONTROL 0xFFC01404 /* TWI Control Register */
+#define TWI_SLAVE_CTL 0xFFC01408 /* Slave Mode Control Register */
+#define TWI_SLAVE_STAT 0xFFC0140C /* Slave Mode Status Register */
+#define TWI_SLAVE_ADDR 0xFFC01410 /* Slave Mode Address Register */
+#define TWI_MASTER_CTL 0xFFC01414 /* Master Mode Control Register */
+#define TWI_MASTER_STAT 0xFFC01418 /* Master Mode Status Register */
+#define TWI_MASTER_ADDR 0xFFC0141C /* Master Mode Address Register */
+#define TWI_INT_STAT 0xFFC01420 /* TWI Interrupt Status Register */
+#define TWI_INT_MASK 0xFFC01424 /* TWI Master Interrupt Mask Register */
+#define TWI_FIFO_CTL 0xFFC01428 /* FIFO Control Register */
+#define TWI_FIFO_STAT 0xFFC0142C /* FIFO Status Register */
+#define TWI_XMT_DATA8 0xFFC01480 /* FIFO Transmit Data Single Byte Register */
+#define TWI_XMT_DATA16 0xFFC01484 /* FIFO Transmit Data Double Byte Register */
+#define TWI_RCV_DATA8 0xFFC01488 /* FIFO Receive Data Single Byte Register */
+#define TWI_RCV_DATA16 0xFFC0148C /* FIFO Receive Data Double Byte Register */
+
+/* General Purpose I/O Port G (0xFFC01500 - 0xFFC015FF) */
+#define PORTGIO 0xFFC01500 /* Port G I/O Pin State Specify Register */
+#define PORTGIO_CLEAR 0xFFC01504 /* Port G I/O Peripheral Interrupt Clear Register */
+#define PORTGIO_SET 0xFFC01508 /* Port G I/O Peripheral Interrupt Set Register */
+#define PORTGIO_TOGGLE 0xFFC0150C /* Port G I/O Pin State Toggle Register */
+#define PORTGIO_MASKA 0xFFC01510 /* Port G I/O Mask State Specify Interrupt A Register */
+#define PORTGIO_MASKA_CLEAR 0xFFC01514 /* Port G I/O Mask Disable Interrupt A Register */
+#define PORTGIO_MASKA_SET 0xFFC01518 /* Port G I/O Mask Enable Interrupt A Register */
+#define PORTGIO_MASKA_TOGGLE 0xFFC0151C /* Port G I/O Mask Toggle Enable Interrupt A Register */
+#define PORTGIO_MASKB 0xFFC01520 /* Port G I/O Mask State Specify Interrupt B Register */
+#define PORTGIO_MASKB_CLEAR 0xFFC01524 /* Port G I/O Mask Disable Interrupt B Register */
+#define PORTGIO_MASKB_SET 0xFFC01528 /* Port G I/O Mask Enable Interrupt B Register */
+#define PORTGIO_MASKB_TOGGLE 0xFFC0152C /* Port G I/O Mask Toggle Enable Interrupt B Register */
+#define PORTGIO_DIR 0xFFC01530 /* Port G I/O Direction Register */
+#define PORTGIO_POLAR 0xFFC01534 /* Port G I/O Source Polarity Register */
+#define PORTGIO_EDGE 0xFFC01538 /* Port G I/O Source Sensitivity Register */
+#define PORTGIO_BOTH 0xFFC0153C /* Port G I/O Set on BOTH Edges Register */
+#define PORTGIO_INEN 0xFFC01540 /* Port G I/O Input Enable Register */
+
+/* General Purpose I/O Port H (0xFFC01700 - 0xFFC017FF) */
+#define PORTHIO 0xFFC01700 /* Port H I/O Pin State Specify Register */
+#define PORTHIO_CLEAR 0xFFC01704 /* Port H I/O Peripheral Interrupt Clear Register */
+#define PORTHIO_SET 0xFFC01708 /* Port H I/O Peripheral Interrupt Set Register */
+#define PORTHIO_TOGGLE 0xFFC0170C /* Port H I/O Pin State Toggle Register */
+#define PORTHIO_MASKA 0xFFC01710 /* Port H I/O Mask State Specify Interrupt A Register */
+#define PORTHIO_MASKA_CLEAR 0xFFC01714 /* Port H I/O Mask Disable Interrupt A Register */
+#define PORTHIO_MASKA_SET 0xFFC01718 /* Port H I/O Mask Enable Interrupt A Register */
+#define PORTHIO_MASKA_TOGGLE 0xFFC0171C /* Port H I/O Mask Toggle Enable Interrupt A Register */
+#define PORTHIO_MASKB 0xFFC01720 /* Port H I/O Mask State Specify Interrupt B Register */
+#define PORTHIO_MASKB_CLEAR 0xFFC01724 /* Port H I/O Mask Disable Interrupt B Register */
+#define PORTHIO_MASKB_SET 0xFFC01728 /* Port H I/O Mask Enable Interrupt B Register */
+#define PORTHIO_MASKB_TOGGLE 0xFFC0172C /* Port H I/O Mask Toggle Enable Interrupt B Register */
+#define PORTHIO_DIR 0xFFC01730 /* Port H I/O Direction Register */
+#define PORTHIO_POLAR 0xFFC01734 /* Port H I/O Source Polarity Register */
+#define PORTHIO_EDGE 0xFFC01738 /* Port H I/O Source Sensitivity Register */
+#define PORTHIO_BOTH 0xFFC0173C /* Port H I/O Set on BOTH Edges Register */
+#define PORTHIO_INEN 0xFFC01740 /* Port H I/O Input Enable Register */
+
+/* UART1 Controller (0xFFC02000 - 0xFFC020FF) */
+#define UART1_THR 0xFFC02000 /* Transmit Holding register */
+#define UART1_RBR 0xFFC02000 /* Receive Buffer register */
+#define UART1_DLL 0xFFC02000 /* Divisor Latch (Low-Byte) */
+#define UART1_IER 0xFFC02004 /* Interrupt Enable Register */
+#define UART1_DLH 0xFFC02004 /* Divisor Latch (High-Byte) */
+#define UART1_IIR 0xFFC02008 /* Interrupt Identification Register */
+#define UART1_LCR 0xFFC0200C /* Line Control Register */
+#define UART1_MCR 0xFFC02010 /* Modem Control Register */
+#define UART1_LSR 0xFFC02014 /* Line Status Register */
+#define UART1_MSR 0xFFC02018 /* Modem Status Register */
+#define UART1_SCR 0xFFC0201C /* SCR Scratch Register */
+#define UART1_GCTL 0xFFC02024 /* Global Control Register */
+
+/* CAN Controller (0xFFC02A00 - 0xFFC02FFF) */
+/* For Mailboxes 0-15 */
+#define CAN_MC1 0xFFC02A00 /* Mailbox config reg 1 */
+#define CAN_MD1 0xFFC02A04 /* Mailbox direction reg 1 */
+#define CAN_TRS1 0xFFC02A08 /* Transmit Request Set reg 1 */
+#define CAN_TRR1 0xFFC02A0C /* Transmit Request Reset reg 1 */
+#define CAN_TA1 0xFFC02A10 /* Transmit Acknowledge reg 1 */
+#define CAN_AA1 0xFFC02A14 /* Transmit Abort Acknowledge reg 1 */
+#define CAN_RMP1 0xFFC02A18 /* Receive Message Pending reg 1 */
+#define CAN_RML1 0xFFC02A1C /* Receive Message Lost reg 1 */
+#define CAN_MBTIF1 0xFFC02A20 /* Mailbox Transmit Interrupt Flag reg 1 */
+#define CAN_MBRIF1 0xFFC02A24 /* Mailbox Receive Interrupt Flag reg 1 */
+#define CAN_MBIM1 0xFFC02A28 /* Mailbox Interrupt Mask reg 1 */
+#define CAN_RFH1 0xFFC02A2C /* Remote Frame Handling reg 1 */
+#define CAN_OPSS1 0xFFC02A30 /* Overwrite Protection Single Shot Xmit reg 1 */
+
+/* For Mailboxes 16-31 */
+#define CAN_MC2 0xFFC02A40 /* Mailbox config reg 2 */
+#define CAN_MD2 0xFFC02A44 /* Mailbox direction reg 2 */
+#define CAN_TRS2 0xFFC02A48 /* Transmit Request Set reg 2 */
+#define CAN_TRR2 0xFFC02A4C /* Transmit Request Reset reg 2 */
+#define CAN_TA2 0xFFC02A50 /* Transmit Acknowledge reg 2 */
+#define CAN_AA2 0xFFC02A54 /* Transmit Abort Acknowledge reg 2 */
+#define CAN_RMP2 0xFFC02A58 /* Receive Message Pending reg 2 */
+#define CAN_RML2 0xFFC02A5C /* Receive Message Lost reg 2 */
+#define CAN_MBTIF2 0xFFC02A60 /* Mailbox Transmit Interrupt Flag reg 2 */
+#define CAN_MBRIF2 0xFFC02A64 /* Mailbox Receive Interrupt Flag reg 2 */
+#define CAN_MBIM2 0xFFC02A68 /* Mailbox Interrupt Mask reg 2 */
+#define CAN_RFH2 0xFFC02A6C /* Remote Frame Handling reg 2 */
+#define CAN_OPSS2 0xFFC02A70 /* Overwrite Protection Single Shot Xmit reg 2 */
+
+/* CAN Configuration, Control, and Status Registers */
+#define CAN_CLOCK 0xFFC02A80 /* Bit Timing Configuration register 0 */
+#define CAN_TIMING 0xFFC02A84 /* Bit Timing Configuration register 1 */
+#define CAN_DEBUG 0xFFC02A88 /* Debug Register */
+#define CAN_STATUS 0xFFC02A8C /* Global Status Register */
+#define CAN_CEC 0xFFC02A90 /* Error Counter Register */
+#define CAN_GIS 0xFFC02A94 /* Global Interrupt Status Register */
+#define CAN_GIM 0xFFC02A98 /* Global Interrupt Mask Register */
+#define CAN_GIF 0xFFC02A9C /* Global Interrupt Flag Register */
+#define CAN_CONTROL 0xFFC02AA0 /* Master Control Register */
+#define CAN_INTR 0xFFC02AA4 /* Interrupt Pending Register */
+#define CAN_SFCMVER 0xFFC02AA8 /* Version Code Register */
+#define CAN_MBTD 0xFFC02AAC /* Mailbox Temporary Disable Feature */
+#define CAN_EWR 0xFFC02AB0 /* Programmable Warning Level */
+#define CAN_ESR 0xFFC02AB4 /* Error Status Register */
+#define CAN_UCREG 0xFFC02AC0 /* Universal Counter Register/Capture Register */
+#define CAN_UCCNT 0xFFC02AC4 /* Universal Counter */
+#define CAN_UCRC 0xFFC02AC8 /* Universal Counter Force Reload Register */
+#define CAN_UCCNF 0xFFC02ACC /* Universal Counter Configuration Register */
+
+/* Mailbox Acceptance Masks */
+#define CAN_AM00L 0xFFC02B00 /* Mailbox 0 Low Acceptance Mask */
+#define CAN_AM00H 0xFFC02B04 /* Mailbox 0 High Acceptance Mask */
+#define CAN_AM01L 0xFFC02B08 /* Mailbox 1 Low Acceptance Mask */
+#define CAN_AM01H 0xFFC02B0C /* Mailbox 1 High Acceptance Mask */
+#define CAN_AM02L 0xFFC02B10 /* Mailbox 2 Low Acceptance Mask */
+#define CAN_AM02H 0xFFC02B14 /* Mailbox 2 High Acceptance Mask */
+#define CAN_AM03L 0xFFC02B18 /* Mailbox 3 Low Acceptance Mask */
+#define CAN_AM03H 0xFFC02B1C /* Mailbox 3 High Acceptance Mask */
+#define CAN_AM04L 0xFFC02B20 /* Mailbox 4 Low Acceptance Mask */
+#define CAN_AM04H 0xFFC02B24 /* Mailbox 4 High Acceptance Mask */
+#define CAN_AM05L 0xFFC02B28 /* Mailbox 5 Low Acceptance Mask */
+#define CAN_AM05H 0xFFC02B2C /* Mailbox 5 High Acceptance Mask */
+#define CAN_AM06L 0xFFC02B30 /* Mailbox 6 Low Acceptance Mask */
+#define CAN_AM06H 0xFFC02B34 /* Mailbox 6 High Acceptance Mask */
+#define CAN_AM07L 0xFFC02B38 /* Mailbox 7 Low Acceptance Mask */
+#define CAN_AM07H 0xFFC02B3C /* Mailbox 7 High Acceptance Mask */
+#define CAN_AM08L 0xFFC02B40 /* Mailbox 8 Low Acceptance Mask */
+#define CAN_AM08H 0xFFC02B44 /* Mailbox 8 High Acceptance Mask */
+#define CAN_AM09L 0xFFC02B48 /* Mailbox 9 Low Acceptance Mask */
+#define CAN_AM09H 0xFFC02B4C /* Mailbox 9 High Acceptance Mask */
+#define CAN_AM10L 0xFFC02B50 /* Mailbox 10 Low Acceptance Mask */
+#define CAN_AM10H 0xFFC02B54 /* Mailbox 10 High Acceptance Mask */
+#define CAN_AM11L 0xFFC02B58 /* Mailbox 11 Low Acceptance Mask */
+#define CAN_AM11H 0xFFC02B5C /* Mailbox 11 High Acceptance Mask */
+#define CAN_AM12L 0xFFC02B60 /* Mailbox 12 Low Acceptance Mask */
+#define CAN_AM12H 0xFFC02B64 /* Mailbox 12 High Acceptance Mask */
+#define CAN_AM13L 0xFFC02B68 /* Mailbox 13 Low Acceptance Mask */
+#define CAN_AM13H 0xFFC02B6C /* Mailbox 13 High Acceptance Mask */
+#define CAN_AM14L 0xFFC02B70 /* Mailbox 14 Low Acceptance Mask */
+#define CAN_AM14H 0xFFC02B74 /* Mailbox 14 High Acceptance Mask */
+#define CAN_AM15L 0xFFC02B78 /* Mailbox 15 Low Acceptance Mask */
+#define CAN_AM15H 0xFFC02B7C /* Mailbox 15 High Acceptance Mask */
+
+#define CAN_AM16L 0xFFC02B80 /* Mailbox 16 Low Acceptance Mask */
+#define CAN_AM16H 0xFFC02B84 /* Mailbox 16 High Acceptance Mask */
+#define CAN_AM17L 0xFFC02B88 /* Mailbox 17 Low Acceptance Mask */
+#define CAN_AM17H 0xFFC02B8C /* Mailbox 17 High Acceptance Mask */
+#define CAN_AM18L 0xFFC02B90 /* Mailbox 18 Low Acceptance Mask */
+#define CAN_AM18H 0xFFC02B94 /* Mailbox 18 High Acceptance Mask */
+#define CAN_AM19L 0xFFC02B98 /* Mailbox 19 Low Acceptance Mask */
+#define CAN_AM19H 0xFFC02B9C /* Mailbox 19 High Acceptance Mask */
+#define CAN_AM20L 0xFFC02BA0 /* Mailbox 20 Low Acceptance Mask */
+#define CAN_AM20H 0xFFC02BA4 /* Mailbox 20 High Acceptance Mask */
+#define CAN_AM21L 0xFFC02BA8 /* Mailbox 21 Low Acceptance Mask */
+#define CAN_AM21H 0xFFC02BAC /* Mailbox 21 High Acceptance Mask */
+#define CAN_AM22L 0xFFC02BB0 /* Mailbox 22 Low Acceptance Mask */
+#define CAN_AM22H 0xFFC02BB4 /* Mailbox 22 High Acceptance Mask */
+#define CAN_AM23L 0xFFC02BB8 /* Mailbox 23 Low Acceptance Mask */
+#define CAN_AM23H 0xFFC02BBC /* Mailbox 23 High Acceptance Mask */
+#define CAN_AM24L 0xFFC02BC0 /* Mailbox 24 Low Acceptance Mask */
+#define CAN_AM24H 0xFFC02BC4 /* Mailbox 24 High Acceptance Mask */
+#define CAN_AM25L 0xFFC02BC8 /* Mailbox 25 Low Acceptance Mask */
+#define CAN_AM25H 0xFFC02BCC /* Mailbox 25 High Acceptance Mask */
+#define CAN_AM26L 0xFFC02BD0 /* Mailbox 26 Low Acceptance Mask */
+#define CAN_AM26H 0xFFC02BD4 /* Mailbox 26 High Acceptance Mask */
+#define CAN_AM27L 0xFFC02BD8 /* Mailbox 27 Low Acceptance Mask */
+#define CAN_AM27H 0xFFC02BDC /* Mailbox 27 High Acceptance Mask */
+#define CAN_AM28L 0xFFC02BE0 /* Mailbox 28 Low Acceptance Mask */
+#define CAN_AM28H 0xFFC02BE4 /* Mailbox 28 High Acceptance Mask */
+#define CAN_AM29L 0xFFC02BE8 /* Mailbox 29 Low Acceptance Mask */
+#define CAN_AM29H 0xFFC02BEC /* Mailbox 29 High Acceptance Mask */
+#define CAN_AM30L 0xFFC02BF0 /* Mailbox 30 Low Acceptance Mask */
+#define CAN_AM30H 0xFFC02BF4 /* Mailbox 30 High Acceptance Mask */
+#define CAN_AM31L 0xFFC02BF8 /* Mailbox 31 Low Acceptance Mask */
+#define CAN_AM31H 0xFFC02BFC /* Mailbox 31 High Acceptance Mask */
+
+/* CAN Acceptance Mask Macros */
+#define CAN_AM_L(x) (CAN_AM00L+((x)*0x8))
+#define CAN_AM_H(x) (CAN_AM00H+((x)*0x8))
+
+/* Mailbox Registers */
+#define CAN_MB00_DATA0 0xFFC02C00 /* Mailbox 0 Data Word 0 [15:0] Register */
+#define CAN_MB00_DATA1 0xFFC02C04 /* Mailbox 0 Data Word 1 [31:16] Register */
+#define CAN_MB00_DATA2 0xFFC02C08 /* Mailbox 0 Data Word 2 [47:32] Register */
+#define CAN_MB00_DATA3 0xFFC02C0C /* Mailbox 0 Data Word 3 [63:48] Register */
+#define CAN_MB00_LENGTH 0xFFC02C10 /* Mailbox 0 Data Length Code Register */
+#define CAN_MB00_TIMESTAMP 0xFFC02C14 /* Mailbox 0 Time Stamp Value Register */
+#define CAN_MB00_ID0 0xFFC02C18 /* Mailbox 0 Identifier Low Register */
+#define CAN_MB00_ID1 0xFFC02C1C /* Mailbox 0 Identifier High Register */
+
+#define CAN_MB01_DATA0 0xFFC02C20 /* Mailbox 1 Data Word 0 [15:0] Register */
+#define CAN_MB01_DATA1 0xFFC02C24 /* Mailbox 1 Data Word 1 [31:16] Register */
+#define CAN_MB01_DATA2 0xFFC02C28 /* Mailbox 1 Data Word 2 [47:32] Register */
+#define CAN_MB01_DATA3 0xFFC02C2C /* Mailbox 1 Data Word 3 [63:48] Register */
+#define CAN_MB01_LENGTH 0xFFC02C30 /* Mailbox 1 Data Length Code Register */
+#define CAN_MB01_TIMESTAMP 0xFFC02C34 /* Mailbox 1 Time Stamp Value Register */
+#define CAN_MB01_ID0 0xFFC02C38 /* Mailbox 1 Identifier Low Register */
+#define CAN_MB01_ID1 0xFFC02C3C /* Mailbox 1 Identifier High Register */
+
+#define CAN_MB02_DATA0 0xFFC02C40 /* Mailbox 2 Data Word 0 [15:0] Register */
+#define CAN_MB02_DATA1 0xFFC02C44 /* Mailbox 2 Data Word 1 [31:16] Register */
+#define CAN_MB02_DATA2 0xFFC02C48 /* Mailbox 2 Data Word 2 [47:32] Register */
+#define CAN_MB02_DATA3 0xFFC02C4C /* Mailbox 2 Data Word 3 [63:48] Register */
+#define CAN_MB02_LENGTH 0xFFC02C50 /* Mailbox 2 Data Length Code Register */
+#define CAN_MB02_TIMESTAMP 0xFFC02C54 /* Mailbox 2 Time Stamp Value Register */
+#define CAN_MB02_ID0 0xFFC02C58 /* Mailbox 2 Identifier Low Register */
+#define CAN_MB02_ID1 0xFFC02C5C /* Mailbox 2 Identifier High Register */
+
+#define CAN_MB03_DATA0 0xFFC02C60 /* Mailbox 3 Data Word 0 [15:0] Register */
+#define CAN_MB03_DATA1 0xFFC02C64 /* Mailbox 3 Data Word 1 [31:16] Register */
+#define CAN_MB03_DATA2 0xFFC02C68 /* Mailbox 3 Data Word 2 [47:32] Register */
+#define CAN_MB03_DATA3 0xFFC02C6C /* Mailbox 3 Data Word 3 [63:48] Register */
+#define CAN_MB03_LENGTH 0xFFC02C70 /* Mailbox 3 Data Length Code Register */
+#define CAN_MB03_TIMESTAMP 0xFFC02C74 /* Mailbox 3 Time Stamp Value Register */
+#define CAN_MB03_ID0 0xFFC02C78 /* Mailbox 3 Identifier Low Register */
+#define CAN_MB03_ID1 0xFFC02C7C /* Mailbox 3 Identifier High Register */
+
+#define CAN_MB04_DATA0 0xFFC02C80 /* Mailbox 4 Data Word 0 [15:0] Register */
+#define CAN_MB04_DATA1 0xFFC02C84 /* Mailbox 4 Data Word 1 [31:16] Register */
+#define CAN_MB04_DATA2 0xFFC02C88 /* Mailbox 4 Data Word 2 [47:32] Register */
+#define CAN_MB04_DATA3 0xFFC02C8C /* Mailbox 4 Data Word 3 [63:48] Register */
+#define CAN_MB04_LENGTH 0xFFC02C90 /* Mailbox 4 Data Length Code Register */
+#define CAN_MB04_TIMESTAMP 0xFFC02C94 /* Mailbox 4 Time Stamp Value Register */
+#define CAN_MB04_ID0 0xFFC02C98 /* Mailbox 4 Identifier Low Register */
+#define CAN_MB04_ID1 0xFFC02C9C /* Mailbox 4 Identifier High Register */
+
+#define CAN_MB05_DATA0 0xFFC02CA0 /* Mailbox 5 Data Word 0 [15:0] Register */
+#define CAN_MB05_DATA1 0xFFC02CA4 /* Mailbox 5 Data Word 1 [31:16] Register */
+#define CAN_MB05_DATA2 0xFFC02CA8 /* Mailbox 5 Data Word 2 [47:32] Register */
+#define CAN_MB05_DATA3 0xFFC02CAC /* Mailbox 5 Data Word 3 [63:48] Register */
+#define CAN_MB05_LENGTH 0xFFC02CB0 /* Mailbox 5 Data Length Code Register */
+#define CAN_MB05_TIMESTAMP 0xFFC02CB4 /* Mailbox 5 Time Stamp Value Register */
+#define CAN_MB05_ID0 0xFFC02CB8 /* Mailbox 5 Identifier Low Register */
+#define CAN_MB05_ID1 0xFFC02CBC /* Mailbox 5 Identifier High Register */
+
+#define CAN_MB06_DATA0 0xFFC02CC0 /* Mailbox 6 Data Word 0 [15:0] Register */
+#define CAN_MB06_DATA1 0xFFC02CC4 /* Mailbox 6 Data Word 1 [31:16] Register */
+#define CAN_MB06_DATA2 0xFFC02CC8 /* Mailbox 6 Data Word 2 [47:32] Register */
+#define CAN_MB06_DATA3 0xFFC02CCC /* Mailbox 6 Data Word 3 [63:48] Register */
+#define CAN_MB06_LENGTH 0xFFC02CD0 /* Mailbox 6 Data Length Code Register */
+#define CAN_MB06_TIMESTAMP 0xFFC02CD4 /* Mailbox 6 Time Stamp Value Register */
+#define CAN_MB06_ID0 0xFFC02CD8 /* Mailbox 6 Identifier Low Register */
+#define CAN_MB06_ID1 0xFFC02CDC /* Mailbox 6 Identifier High Register */
+
+#define CAN_MB07_DATA0 0xFFC02CE0 /* Mailbox 7 Data Word 0 [15:0] Register */
+#define CAN_MB07_DATA1 0xFFC02CE4 /* Mailbox 7 Data Word 1 [31:16] Register */
+#define CAN_MB07_DATA2 0xFFC02CE8 /* Mailbox 7 Data Word 2 [47:32] Register */
+#define CAN_MB07_DATA3 0xFFC02CEC /* Mailbox 7 Data Word 3 [63:48] Register */
+#define CAN_MB07_LENGTH 0xFFC02CF0 /* Mailbox 7 Data Length Code Register */
+#define CAN_MB07_TIMESTAMP 0xFFC02CF4 /* Mailbox 7 Time Stamp Value Register */
+#define CAN_MB07_ID0 0xFFC02CF8 /* Mailbox 7 Identifier Low Register */
+#define CAN_MB07_ID1 0xFFC02CFC /* Mailbox 7 Identifier High Register */
+
+#define CAN_MB08_DATA0 0xFFC02D00 /* Mailbox 8 Data Word 0 [15:0] Register */
+#define CAN_MB08_DATA1 0xFFC02D04 /* Mailbox 8 Data Word 1 [31:16] Register */
+#define CAN_MB08_DATA2 0xFFC02D08 /* Mailbox 8 Data Word 2 [47:32] Register */
+#define CAN_MB08_DATA3 0xFFC02D0C /* Mailbox 8 Data Word 3 [63:48] Register */
+#define CAN_MB08_LENGTH 0xFFC02D10 /* Mailbox 8 Data Length Code Register */
+#define CAN_MB08_TIMESTAMP 0xFFC02D14 /* Mailbox 8 Time Stamp Value Register */
+#define CAN_MB08_ID0 0xFFC02D18 /* Mailbox 8 Identifier Low Register */
+#define CAN_MB08_ID1 0xFFC02D1C /* Mailbox 8 Identifier High Register */
+
+#define CAN_MB09_DATA0 0xFFC02D20 /* Mailbox 9 Data Word 0 [15:0] Register */
+#define CAN_MB09_DATA1 0xFFC02D24 /* Mailbox 9 Data Word 1 [31:16] Register */
+#define CAN_MB09_DATA2 0xFFC02D28 /* Mailbox 9 Data Word 2 [47:32] Register */
+#define CAN_MB09_DATA3 0xFFC02D2C /* Mailbox 9 Data Word 3 [63:48] Register */
+#define CAN_MB09_LENGTH 0xFFC02D30 /* Mailbox 9 Data Length Code Register */
+#define CAN_MB09_TIMESTAMP 0xFFC02D34 /* Mailbox 9 Time Stamp Value Register */
+#define CAN_MB09_ID0 0xFFC02D38 /* Mailbox 9 Identifier Low Register */
+#define CAN_MB09_ID1 0xFFC02D3C /* Mailbox 9 Identifier High Register */
+
+#define CAN_MB10_DATA0 0xFFC02D40 /* Mailbox 10 Data Word 0 [15:0] Register */
+#define CAN_MB10_DATA1 0xFFC02D44 /* Mailbox 10 Data Word 1 [31:16] Register */
+#define CAN_MB10_DATA2 0xFFC02D48 /* Mailbox 10 Data Word 2 [47:32] Register */
+#define CAN_MB10_DATA3 0xFFC02D4C /* Mailbox 10 Data Word 3 [63:48] Register */
+#define CAN_MB10_LENGTH 0xFFC02D50 /* Mailbox 10 Data Length Code Register */
+#define CAN_MB10_TIMESTAMP 0xFFC02D54 /* Mailbox 10 Time Stamp Value Register */
+#define CAN_MB10_ID0 0xFFC02D58 /* Mailbox 10 Identifier Low Register */
+#define CAN_MB10_ID1 0xFFC02D5C /* Mailbox 10 Identifier High Register */
+
+#define CAN_MB11_DATA0 0xFFC02D60 /* Mailbox 11 Data Word 0 [15:0] Register */
+#define CAN_MB11_DATA1 0xFFC02D64 /* Mailbox 11 Data Word 1 [31:16] Register */
+#define CAN_MB11_DATA2 0xFFC02D68 /* Mailbox 11 Data Word 2 [47:32] Register */
+#define CAN_MB11_DATA3 0xFFC02D6C /* Mailbox 11 Data Word 3 [63:48] Register */
+#define CAN_MB11_LENGTH 0xFFC02D70 /* Mailbox 11 Data Length Code Register */
+#define CAN_MB11_TIMESTAMP 0xFFC02D74 /* Mailbox 11 Time Stamp Value Register */
+#define CAN_MB11_ID0 0xFFC02D78 /* Mailbox 11 Identifier Low Register */
+#define CAN_MB11_ID1 0xFFC02D7C /* Mailbox 11 Identifier High Register */
+
+#define CAN_MB12_DATA0 0xFFC02D80 /* Mailbox 12 Data Word 0 [15:0] Register */
+#define CAN_MB12_DATA1 0xFFC02D84 /* Mailbox 12 Data Word 1 [31:16] Register */
+#define CAN_MB12_DATA2 0xFFC02D88 /* Mailbox 12 Data Word 2 [47:32] Register */
+#define CAN_MB12_DATA3 0xFFC02D8C /* Mailbox 12 Data Word 3 [63:48] Register */
+#define CAN_MB12_LENGTH 0xFFC02D90 /* Mailbox 12 Data Length Code Register */
+#define CAN_MB12_TIMESTAMP 0xFFC02D94 /* Mailbox 12 Time Stamp Value Register */
+#define CAN_MB12_ID0 0xFFC02D98 /* Mailbox 12 Identifier Low Register */
+#define CAN_MB12_ID1 0xFFC02D9C /* Mailbox 12 Identifier High Register */
+
+#define CAN_MB13_DATA0 0xFFC02DA0 /* Mailbox 13 Data Word 0 [15:0] Register */
+#define CAN_MB13_DATA1 0xFFC02DA4 /* Mailbox 13 Data Word 1 [31:16] Register */
+#define CAN_MB13_DATA2 0xFFC02DA8 /* Mailbox 13 Data Word 2 [47:32] Register */
+#define CAN_MB13_DATA3 0xFFC02DAC /* Mailbox 13 Data Word 3 [63:48] Register */
+#define CAN_MB13_LENGTH 0xFFC02DB0 /* Mailbox 13 Data Length Code Register */
+#define CAN_MB13_TIMESTAMP 0xFFC02DB4 /* Mailbox 13 Time Stamp Value Register */
+#define CAN_MB13_ID0 0xFFC02DB8 /* Mailbox 13 Identifier Low Register */
+#define CAN_MB13_ID1 0xFFC02DBC /* Mailbox 13 Identifier High Register */
+
+#define CAN_MB14_DATA0 0xFFC02DC0 /* Mailbox 14 Data Word 0 [15:0] Register */
+#define CAN_MB14_DATA1 0xFFC02DC4 /* Mailbox 14 Data Word 1 [31:16] Register */
+#define CAN_MB14_DATA2 0xFFC02DC8 /* Mailbox 14 Data Word 2 [47:32] Register */
+#define CAN_MB14_DATA3 0xFFC02DCC /* Mailbox 14 Data Word 3 [63:48] Register */
+#define CAN_MB14_LENGTH 0xFFC02DD0 /* Mailbox 14 Data Length Code Register */
+#define CAN_MB14_TIMESTAMP 0xFFC02DD4 /* Mailbox 14 Time Stamp Value Register */
+#define CAN_MB14_ID0 0xFFC02DD8 /* Mailbox 14 Identifier Low Register */
+#define CAN_MB14_ID1 0xFFC02DDC /* Mailbox 14 Identifier High Register */
+
+#define CAN_MB15_DATA0 0xFFC02DE0 /* Mailbox 15 Data Word 0 [15:0] Register */
+#define CAN_MB15_DATA1 0xFFC02DE4 /* Mailbox 15 Data Word 1 [31:16] Register */
+#define CAN_MB15_DATA2 0xFFC02DE8 /* Mailbox 15 Data Word 2 [47:32] Register */
+#define CAN_MB15_DATA3 0xFFC02DEC /* Mailbox 15 Data Word 3 [63:48] Register */
+#define CAN_MB15_LENGTH 0xFFC02DF0 /* Mailbox 15 Data Length Code Register */
+#define CAN_MB15_TIMESTAMP 0xFFC02DF4 /* Mailbox 15 Time Stamp Value Register */
+#define CAN_MB15_ID0 0xFFC02DF8 /* Mailbox 15 Identifier Low Register */
+#define CAN_MB15_ID1 0xFFC02DFC /* Mailbox 15 Identifier High Register */
+
+#define CAN_MB16_DATA0 0xFFC02E00 /* Mailbox 16 Data Word 0 [15:0] Register */
+#define CAN_MB16_DATA1 0xFFC02E04 /* Mailbox 16 Data Word 1 [31:16] Register */
+#define CAN_MB16_DATA2 0xFFC02E08 /* Mailbox 16 Data Word 2 [47:32] Register */
+#define CAN_MB16_DATA3 0xFFC02E0C /* Mailbox 16 Data Word 3 [63:48] Register */
+#define CAN_MB16_LENGTH 0xFFC02E10 /* Mailbox 16 Data Length Code Register */
+#define CAN_MB16_TIMESTAMP 0xFFC02E14 /* Mailbox 16 Time Stamp Value Register */
+#define CAN_MB16_ID0 0xFFC02E18 /* Mailbox 16 Identifier Low Register */
+#define CAN_MB16_ID1 0xFFC02E1C /* Mailbox 16 Identifier High Register */
+
+#define CAN_MB17_DATA0 0xFFC02E20 /* Mailbox 17 Data Word 0 [15:0] Register */
+#define CAN_MB17_DATA1 0xFFC02E24 /* Mailbox 17 Data Word 1 [31:16] Register */
+#define CAN_MB17_DATA2 0xFFC02E28 /* Mailbox 17 Data Word 2 [47:32] Register */
+#define CAN_MB17_DATA3 0xFFC02E2C /* Mailbox 17 Data Word 3 [63:48] Register */
+#define CAN_MB17_LENGTH 0xFFC02E30 /* Mailbox 17 Data Length Code Register */
+#define CAN_MB17_TIMESTAMP 0xFFC02E34 /* Mailbox 17 Time Stamp Value Register */
+#define CAN_MB17_ID0 0xFFC02E38 /* Mailbox 17 Identifier Low Register */
+#define CAN_MB17_ID1 0xFFC02E3C /* Mailbox 17 Identifier High Register */
+
+#define CAN_MB18_DATA0 0xFFC02E40 /* Mailbox 18 Data Word 0 [15:0] Register */
+#define CAN_MB18_DATA1 0xFFC02E44 /* Mailbox 18 Data Word 1 [31:16] Register */
+#define CAN_MB18_DATA2 0xFFC02E48 /* Mailbox 18 Data Word 2 [47:32] Register */
+#define CAN_MB18_DATA3 0xFFC02E4C /* Mailbox 18 Data Word 3 [63:48] Register */
+#define CAN_MB18_LENGTH 0xFFC02E50 /* Mailbox 18 Data Length Code Register */
+#define CAN_MB18_TIMESTAMP 0xFFC02E54 /* Mailbox 18 Time Stamp Value Register */
+#define CAN_MB18_ID0 0xFFC02E58 /* Mailbox 18 Identifier Low Register */
+#define CAN_MB18_ID1 0xFFC02E5C /* Mailbox 18 Identifier High Register */
+
+#define CAN_MB19_DATA0 0xFFC02E60 /* Mailbox 19 Data Word 0 [15:0] Register */
+#define CAN_MB19_DATA1 0xFFC02E64 /* Mailbox 19 Data Word 1 [31:16] Register */
+#define CAN_MB19_DATA2 0xFFC02E68 /* Mailbox 19 Data Word 2 [47:32] Register */
+#define CAN_MB19_DATA3 0xFFC02E6C /* Mailbox 19 Data Word 3 [63:48] Register */
+#define CAN_MB19_LENGTH 0xFFC02E70 /* Mailbox 19 Data Length Code Register */
+#define CAN_MB19_TIMESTAMP 0xFFC02E74 /* Mailbox 19 Time Stamp Value Register */
+#define CAN_MB19_ID0 0xFFC02E78 /* Mailbox 19 Identifier Low Register */
+#define CAN_MB19_ID1 0xFFC02E7C /* Mailbox 19 Identifier High Register */
+
+#define CAN_MB20_DATA0 0xFFC02E80 /* Mailbox 20 Data Word 0 [15:0] Register */
+#define CAN_MB20_DATA1 0xFFC02E84 /* Mailbox 20 Data Word 1 [31:16] Register */
+#define CAN_MB20_DATA2 0xFFC02E88 /* Mailbox 20 Data Word 2 [47:32] Register */
+#define CAN_MB20_DATA3 0xFFC02E8C /* Mailbox 20 Data Word 3 [63:48] Register */
+#define CAN_MB20_LENGTH 0xFFC02E90 /* Mailbox 20 Data Length Code Register */
+#define CAN_MB20_TIMESTAMP 0xFFC02E94 /* Mailbox 20 Time Stamp Value Register */
+#define CAN_MB20_ID0 0xFFC02E98 /* Mailbox 20 Identifier Low Register */
+#define CAN_MB20_ID1 0xFFC02E9C /* Mailbox 20 Identifier High Register */
+
+#define CAN_MB21_DATA0 0xFFC02EA0 /* Mailbox 21 Data Word 0 [15:0] Register */
+#define CAN_MB21_DATA1 0xFFC02EA4 /* Mailbox 21 Data Word 1 [31:16] Register */
+#define CAN_MB21_DATA2 0xFFC02EA8 /* Mailbox 21 Data Word 2 [47:32] Register */
+#define CAN_MB21_DATA3 0xFFC02EAC /* Mailbox 21 Data Word 3 [63:48] Register */
+#define CAN_MB21_LENGTH 0xFFC02EB0 /* Mailbox 21 Data Length Code Register */
+#define CAN_MB21_TIMESTAMP 0xFFC02EB4 /* Mailbox 21 Time Stamp Value Register */
+#define CAN_MB21_ID0 0xFFC02EB8 /* Mailbox 21 Identifier Low Register */
+#define CAN_MB21_ID1 0xFFC02EBC /* Mailbox 21 Identifier High Register */
+
+#define CAN_MB22_DATA0 0xFFC02EC0 /* Mailbox 22 Data Word 0 [15:0] Register */
+#define CAN_MB22_DATA1 0xFFC02EC4 /* Mailbox 22 Data Word 1 [31:16] Register */
+#define CAN_MB22_DATA2 0xFFC02EC8 /* Mailbox 22 Data Word 2 [47:32] Register */
+#define CAN_MB22_DATA3 0xFFC02ECC /* Mailbox 22 Data Word 3 [63:48] Register */
+#define CAN_MB22_LENGTH 0xFFC02ED0 /* Mailbox 22 Data Length Code Register */
+#define CAN_MB22_TIMESTAMP 0xFFC02ED4 /* Mailbox 22 Time Stamp Value Register */
+#define CAN_MB22_ID0 0xFFC02ED8 /* Mailbox 22 Identifier Low Register */
+#define CAN_MB22_ID1 0xFFC02EDC /* Mailbox 22 Identifier High Register */
+
+#define CAN_MB23_DATA0 0xFFC02EE0 /* Mailbox 23 Data Word 0 [15:0] Register */
+#define CAN_MB23_DATA1 0xFFC02EE4 /* Mailbox 23 Data Word 1 [31:16] Register */
+#define CAN_MB23_DATA2 0xFFC02EE8 /* Mailbox 23 Data Word 2 [47:32] Register */
+#define CAN_MB23_DATA3 0xFFC02EEC /* Mailbox 23 Data Word 3 [63:48] Register */
+#define CAN_MB23_LENGTH 0xFFC02EF0 /* Mailbox 23 Data Length Code Register */
+#define CAN_MB23_TIMESTAMP 0xFFC02EF4 /* Mailbox 23 Time Stamp Value Register */
+#define CAN_MB23_ID0 0xFFC02EF8 /* Mailbox 23 Identifier Low Register */
+#define CAN_MB23_ID1 0xFFC02EFC /* Mailbox 23 Identifier High Register */
+
+#define CAN_MB24_DATA0 0xFFC02F00 /* Mailbox 24 Data Word 0 [15:0] Register */
+#define CAN_MB24_DATA1 0xFFC02F04 /* Mailbox 24 Data Word 1 [31:16] Register */
+#define CAN_MB24_DATA2 0xFFC02F08 /* Mailbox 24 Data Word 2 [47:32] Register */
+#define CAN_MB24_DATA3 0xFFC02F0C /* Mailbox 24 Data Word 3 [63:48] Register */
+#define CAN_MB24_LENGTH 0xFFC02F10 /* Mailbox 24 Data Length Code Register */
+#define CAN_MB24_TIMESTAMP 0xFFC02F14 /* Mailbox 24 Time Stamp Value Register */
+#define CAN_MB24_ID0 0xFFC02F18 /* Mailbox 24 Identifier Low Register */
+#define CAN_MB24_ID1 0xFFC02F1C /* Mailbox 24 Identifier High Register */
+
+#define CAN_MB25_DATA0 0xFFC02F20 /* Mailbox 25 Data Word 0 [15:0] Register */
+#define CAN_MB25_DATA1 0xFFC02F24 /* Mailbox 25 Data Word 1 [31:16] Register */
+#define CAN_MB25_DATA2 0xFFC02F28 /* Mailbox 25 Data Word 2 [47:32] Register */
+#define CAN_MB25_DATA3 0xFFC02F2C /* Mailbox 25 Data Word 3 [63:48] Register */
+#define CAN_MB25_LENGTH 0xFFC02F30 /* Mailbox 25 Data Length Code Register */
+#define CAN_MB25_TIMESTAMP 0xFFC02F34 /* Mailbox 25 Time Stamp Value Register */
+#define CAN_MB25_ID0 0xFFC02F38 /* Mailbox 25 Identifier Low Register */
+#define CAN_MB25_ID1 0xFFC02F3C /* Mailbox 25 Identifier High Register */
+
+#define CAN_MB26_DATA0 0xFFC02F40 /* Mailbox 26 Data Word 0 [15:0] Register */
+#define CAN_MB26_DATA1 0xFFC02F44 /* Mailbox 26 Data Word 1 [31:16] Register */
+#define CAN_MB26_DATA2 0xFFC02F48 /* Mailbox 26 Data Word 2 [47:32] Register */
+#define CAN_MB26_DATA3 0xFFC02F4C /* Mailbox 26 Data Word 3 [63:48] Register */
+#define CAN_MB26_LENGTH 0xFFC02F50 /* Mailbox 26 Data Length Code Register */
+#define CAN_MB26_TIMESTAMP 0xFFC02F54 /* Mailbox 26 Time Stamp Value Register */
+#define CAN_MB26_ID0 0xFFC02F58 /* Mailbox 26 Identifier Low Register */
+#define CAN_MB26_ID1 0xFFC02F5C /* Mailbox 26 Identifier High Register */
+
+#define CAN_MB27_DATA0 0xFFC02F60 /* Mailbox 27 Data Word 0 [15:0] Register */
+#define CAN_MB27_DATA1 0xFFC02F64 /* Mailbox 27 Data Word 1 [31:16] Register */
+#define CAN_MB27_DATA2 0xFFC02F68 /* Mailbox 27 Data Word 2 [47:32] Register */
+#define CAN_MB27_DATA3 0xFFC02F6C /* Mailbox 27 Data Word 3 [63:48] Register */
+#define CAN_MB27_LENGTH 0xFFC02F70 /* Mailbox 27 Data Length Code Register */
+#define CAN_MB27_TIMESTAMP 0xFFC02F74 /* Mailbox 27 Time Stamp Value Register */
+#define CAN_MB27_ID0 0xFFC02F78 /* Mailbox 27 Identifier Low Register */
+#define CAN_MB27_ID1 0xFFC02F7C /* Mailbox 27 Identifier High Register */
+
+#define CAN_MB28_DATA0 0xFFC02F80 /* Mailbox 28 Data Word 0 [15:0] Register */
+#define CAN_MB28_DATA1 0xFFC02F84 /* Mailbox 28 Data Word 1 [31:16] Register */
+#define CAN_MB28_DATA2 0xFFC02F88 /* Mailbox 28 Data Word 2 [47:32] Register */
+#define CAN_MB28_DATA3 0xFFC02F8C /* Mailbox 28 Data Word 3 [63:48] Register */
+#define CAN_MB28_LENGTH 0xFFC02F90 /* Mailbox 28 Data Length Code Register */
+#define CAN_MB28_TIMESTAMP 0xFFC02F94 /* Mailbox 28 Time Stamp Value Register */
+#define CAN_MB28_ID0 0xFFC02F98 /* Mailbox 28 Identifier Low Register */
+#define CAN_MB28_ID1 0xFFC02F9C /* Mailbox 28 Identifier High Register */
+
+#define CAN_MB29_DATA0 0xFFC02FA0 /* Mailbox 29 Data Word 0 [15:0] Register */
+#define CAN_MB29_DATA1 0xFFC02FA4 /* Mailbox 29 Data Word 1 [31:16] Register */
+#define CAN_MB29_DATA2 0xFFC02FA8 /* Mailbox 29 Data Word 2 [47:32] Register */
+#define CAN_MB29_DATA3 0xFFC02FAC /* Mailbox 29 Data Word 3 [63:48] Register */
+#define CAN_MB29_LENGTH 0xFFC02FB0 /* Mailbox 29 Data Length Code Register */
+#define CAN_MB29_TIMESTAMP 0xFFC02FB4 /* Mailbox 29 Time Stamp Value Register */
+#define CAN_MB29_ID0 0xFFC02FB8 /* Mailbox 29 Identifier Low Register */
+#define CAN_MB29_ID1 0xFFC02FBC /* Mailbox 29 Identifier High Register */
+
+#define CAN_MB30_DATA0 0xFFC02FC0 /* Mailbox 30 Data Word 0 [15:0] Register */
+#define CAN_MB30_DATA1 0xFFC02FC4 /* Mailbox 30 Data Word 1 [31:16] Register */
+#define CAN_MB30_DATA2 0xFFC02FC8 /* Mailbox 30 Data Word 2 [47:32] Register */
+#define CAN_MB30_DATA3 0xFFC02FCC /* Mailbox 30 Data Word 3 [63:48] Register */
+#define CAN_MB30_LENGTH 0xFFC02FD0 /* Mailbox 30 Data Length Code Register */
+#define CAN_MB30_TIMESTAMP 0xFFC02FD4 /* Mailbox 30 Time Stamp Value Register */
+#define CAN_MB30_ID0 0xFFC02FD8 /* Mailbox 30 Identifier Low Register */
+#define CAN_MB30_ID1 0xFFC02FDC /* Mailbox 30 Identifier High Register */
+
+#define CAN_MB31_DATA0 0xFFC02FE0 /* Mailbox 31 Data Word 0 [15:0] Register */
+#define CAN_MB31_DATA1 0xFFC02FE4 /* Mailbox 31 Data Word 1 [31:16] Register */
+#define CAN_MB31_DATA2 0xFFC02FE8 /* Mailbox 31 Data Word 2 [47:32] Register */
+#define CAN_MB31_DATA3 0xFFC02FEC /* Mailbox 31 Data Word 3 [63:48] Register */
+#define CAN_MB31_LENGTH 0xFFC02FF0 /* Mailbox 31 Data Length Code Register */
+#define CAN_MB31_TIMESTAMP 0xFFC02FF4 /* Mailbox 31 Time Stamp Value Register */
+#define CAN_MB31_ID0 0xFFC02FF8 /* Mailbox 31 Identifier Low Register */
+#define CAN_MB31_ID1 0xFFC02FFC /* Mailbox 31 Identifier High Register */
+
+/* CAN Mailbox Area Macros */
+#define CAN_MB_ID1(x) (CAN_MB00_ID1+((x)*0x20))
+#define CAN_MB_ID0(x) (CAN_MB00_ID0+((x)*0x20))
+#define CAN_MB_TIMESTAMP(x) (CAN_MB00_TIMESTAMP+((x)*0x20))
+#define CAN_MB_LENGTH(x) (CAN_MB00_LENGTH+((x)*0x20))
+#define CAN_MB_DATA3(x) (CAN_MB00_DATA3+((x)*0x20))
+#define CAN_MB_DATA2(x) (CAN_MB00_DATA2+((x)*0x20))
+#define CAN_MB_DATA1(x) (CAN_MB00_DATA1+((x)*0x20))
+#define CAN_MB_DATA0(x) (CAN_MB00_DATA0+((x)*0x20))
+
+/* Pin Control Registers (0xFFC03200 - 0xFFC032FF) */
+#define PORTF_FER 0xFFC03200 /* Port F Function Enable Register (Alternate/Flag*) */
+#define PORTG_FER 0xFFC03204 /* Port G Function Enable Register (Alternate/Flag*) */
+#define PORTH_FER 0xFFC03208 /* Port H Function Enable Register (Alternate/Flag*) */
+#define BFIN_PORT_MUX 0xFFC0320C /* Port Multiplexer Control Register */
+
+/* Handshake MDMA Registers (0xFFC03300 - 0xFFC033FF) */
+#define HMDMA0_CONTROL 0xFFC03300 /* Handshake MDMA0 Control Register */
+#define HMDMA0_ECINIT 0xFFC03304 /* HMDMA0 Initial Edge Count Register */
+#define HMDMA0_BCINIT 0xFFC03308 /* HMDMA0 Initial Block Count Register */
+#define HMDMA0_ECURGENT 0xFFC0330C /* HMDMA0 Urgent Edge Count Threshhold Register */
+#define HMDMA0_ECOVERFLOW 0xFFC03310 /* HMDMA0 Edge Count Overflow Interrupt Register */
+#define HMDMA0_ECOUNT 0xFFC03314 /* HMDMA0 Current Edge Count Register */
+#define HMDMA0_BCOUNT 0xFFC03318 /* HMDMA0 Current Block Count Register */
+
+#define HMDMA1_CONTROL 0xFFC03340 /* Handshake MDMA1 Control Register */
+#define HMDMA1_ECINIT 0xFFC03344 /* HMDMA1 Initial Edge Count Register */
+#define HMDMA1_BCINIT 0xFFC03348 /* HMDMA1 Initial Block Count Register */
+#define HMDMA1_ECURGENT 0xFFC0334C /* HMDMA1 Urgent Edge Count Threshhold Register */
+#define HMDMA1_ECOVERFLOW 0xFFC03350 /* HMDMA1 Edge Count Overflow Interrupt Register */
+#define HMDMA1_ECOUNT 0xFFC03354 /* HMDMA1 Current Edge Count Register */
+#define HMDMA1_BCOUNT 0xFFC03358 /* HMDMA1 Current Block Count Register */
+
+/***********************************************************************************
+** System MMR Register Bits And Macros
+**
+** Disclaimer: All macros are intended to make C and Assembly code more readable.
+** Use these macros carefully, as any that do left shifts for field
+** depositing will result in the lower order bits being destroyed. Any
+** macro that shifts left to properly position the bit-field should be
+** used as part of an OR to initialize a register and NOT as a dynamic
+** modifier UNLESS the lower order bits are saved and ORed back in when
+** the macro is used.
+*************************************************************************************/
+/*
+** ********************* PLL AND RESET MASKS ****************************************/
+/* PLL_CTL Masks */
+#define DF 0x0001 /* 0: PLL = CLKIN, 1: PLL = CLKIN/2 */
+#define PLL_OFF 0x0002 /* PLL Not Powered */
+#define STOPCK 0x0008 /* Core Clock Off */
+#define PDWN 0x0020 /* Enter Deep Sleep Mode */
+#define IN_DELAY 0x0040 /* Add 200ps Delay To EBIU Input Latches */
+#define OUT_DELAY 0x0080 /* Add 200ps Delay To EBIU Output Signals */
+#define BYPASS 0x0100 /* Bypass the PLL */
+#define MSEL 0x7E00 /* Multiplier Select For CCLK/VCO Factors */
+/* PLL_CTL Macros (Only Use With Logic OR While Setting Lower Order Bits) */
+#define SET_MSEL(x) (((x)&0x3F) << 0x9) /* Set MSEL = 0-63 --> VCO = CLKIN*MSEL */
+
+/* PLL_DIV Masks */
+#define SSEL 0x000F /* System Select */
+#define CSEL 0x0030 /* Core Select */
+#define CSEL_DIV1 0x0000 /* CCLK = VCO / 1 */
+#define CSEL_DIV2 0x0010 /* CCLK = VCO / 2 */
+#define CSEL_DIV4 0x0020 /* CCLK = VCO / 4 */
+#define CSEL_DIV8 0x0030 /* CCLK = VCO / 8 */
+/* PLL_DIV Macros */
+#define SET_SSEL(x) ((x)&0xF) /* Set SSEL = 0-15 --> SCLK = VCO/SSEL */
+
+/* VR_CTL Masks */
+#define FREQ 0x0003 /* Switching Oscillator Frequency For Regulator */
+#define HIBERNATE 0x0000 /* Powerdown/Bypass On-Board Regulation */
+#define FREQ_333 0x0001 /* Switching Frequency Is 333 kHz */
+#define FREQ_667 0x0002 /* Switching Frequency Is 667 kHz */
+#define FREQ_1000 0x0003 /* Switching Frequency Is 1 MHz */
+
+#define GAIN 0x000C /* Voltage Level Gain */
+#define GAIN_5 0x0000 /* GAIN = 5 */
+#define GAIN_10 0x0004 /* GAIN = 10 */
+#define GAIN_20 0x0008 /* GAIN = 20 */
+#define GAIN_50 0x000C /* GAIN = 50 */
+
+#define VLEV 0x00F0 /* Internal Voltage Level */
+#define VLEV_085 0x0060 /* VLEV = 0.85 V (-5% - +10% Accuracy) */
+#define VLEV_090 0x0070 /* VLEV = 0.90 V (-5% - +10% Accuracy) */
+#define VLEV_095 0x0080 /* VLEV = 0.95 V (-5% - +10% Accuracy) */
+#define VLEV_100 0x0090 /* VLEV = 1.00 V (-5% - +10% Accuracy) */
+#define VLEV_105 0x00A0 /* VLEV = 1.05 V (-5% - +10% Accuracy) */
+#define VLEV_110 0x00B0 /* VLEV = 1.10 V (-5% - +10% Accuracy) */
+#define VLEV_115 0x00C0 /* VLEV = 1.15 V (-5% - +10% Accuracy) */
+#define VLEV_120 0x00D0 /* VLEV = 1.20 V (-5% - +10% Accuracy) */
+#define VLEV_125 0x00E0 /* VLEV = 1.25 V (-5% - +10% Accuracy) */
+#define VLEV_130 0x00F0 /* VLEV = 1.30 V (-5% - +10% Accuracy) */
+
+#define WAKE 0x0100 /* Enable RTC/Reset Wakeup From Hibernate */
+#define PHYWE 0x0200 /* Enable PHY Wakeup From Hibernate */
+#define CANWE 0x0400 /* Enable CAN Wakeup From Hibernate */
+#define PHYCLKOE 0x4000 /* PHY Clock Output Enable */
+#define CKELOW 0x8000 /* Enable Drive CKE Low During Reset */
+
+/* PLL_STAT Masks */
+#define ACTIVE_PLLENABLED 0x0001 /* Processor In Active Mode With PLL Enabled */
+#define FULL_ON 0x0002 /* Processor In Full On Mode */
+#define ACTIVE_PLLDISABLED 0x0004 /* Processor In Active Mode With PLL Disabled */
+#define PLL_LOCKED 0x0020 /* PLL_LOCKCNT Has Been Reached */
+
+/* CHIPID Masks */
+#define CHIPID_VERSION 0xF0000000
+#define CHIPID_FAMILY 0x0FFFF000
+#define CHIPID_MANUFACTURE 0x00000FFE
+
+/* SWRST Masks */
+#define SYSTEM_RESET 0x0007 /* Initiates A System Software Reset */
+#define DOUBLE_FAULT 0x0008 /* Core Double Fault Causes Reset */
+#define RESET_DOUBLE 0x2000 /* SW Reset Generated By Core Double-Fault */
+#define RESET_WDOG 0x4000 /* SW Reset Generated By Watchdog Timer */
+#define RESET_SOFTWARE 0x8000 /* SW Reset Occurred Since Last Read Of SWRST */
+
+/* SYSCR Masks */
+#define BMODE 0x0006 /* Boot Mode - Latched During HW Reset From Mode Pins */
+#define NOBOOT 0x0010 /* Execute From L1 or ASYNC Bank 0 When BMODE = 0 */
+
+/* ************* SYSTEM INTERRUPT CONTROLLER MASKS *************************************/
+
+/* SIC_IAR0 Macros */
+#define P0_IVG(x) (((x)&0xF)-7) /* Peripheral #0 assigned IVG #x */
+#define P1_IVG(x) (((x)&0xF)-7) << 0x4 /* Peripheral #1 assigned IVG #x */
+#define P2_IVG(x) (((x)&0xF)-7) << 0x8 /* Peripheral #2 assigned IVG #x */
+#define P3_IVG(x) (((x)&0xF)-7) << 0xC /* Peripheral #3 assigned IVG #x */
+#define P4_IVG(x) (((x)&0xF)-7) << 0x10 /* Peripheral #4 assigned IVG #x */
+#define P5_IVG(x) (((x)&0xF)-7) << 0x14 /* Peripheral #5 assigned IVG #x */
+#define P6_IVG(x) (((x)&0xF)-7) << 0x18 /* Peripheral #6 assigned IVG #x */
+#define P7_IVG(x) (((x)&0xF)-7) << 0x1C /* Peripheral #7 assigned IVG #x */
+
+/* SIC_IAR1 Macros */
+#define P8_IVG(x) (((x)&0xF)-7) /* Peripheral #8 assigned IVG #x */
+#define P9_IVG(x) (((x)&0xF)-7) << 0x4 /* Peripheral #9 assigned IVG #x */
+#define P10_IVG(x) (((x)&0xF)-7) << 0x8 /* Peripheral #10 assigned IVG #x */
+#define P11_IVG(x) (((x)&0xF)-7) << 0xC /* Peripheral #11 assigned IVG #x */
+#define P12_IVG(x) (((x)&0xF)-7) << 0x10 /* Peripheral #12 assigned IVG #x */
+#define P13_IVG(x) (((x)&0xF)-7) << 0x14 /* Peripheral #13 assigned IVG #x */
+#define P14_IVG(x) (((x)&0xF)-7) << 0x18 /* Peripheral #14 assigned IVG #x */
+#define P15_IVG(x) (((x)&0xF)-7) << 0x1C /* Peripheral #15 assigned IVG #x */
+
+/* SIC_IAR2 Macros */
+#define P16_IVG(x) (((x)&0xF)-7) /* Peripheral #16 assigned IVG #x */
+#define P17_IVG(x) (((x)&0xF)-7) << 0x4 /* Peripheral #17 assigned IVG #x */
+#define P18_IVG(x) (((x)&0xF)-7) << 0x8 /* Peripheral #18 assigned IVG #x */
+#define P19_IVG(x) (((x)&0xF)-7) << 0xC /* Peripheral #19 assigned IVG #x */
+#define P20_IVG(x) (((x)&0xF)-7) << 0x10 /* Peripheral #20 assigned IVG #x */
+#define P21_IVG(x) (((x)&0xF)-7) << 0x14 /* Peripheral #21 assigned IVG #x */
+#define P22_IVG(x) (((x)&0xF)-7) << 0x18 /* Peripheral #22 assigned IVG #x */
+#define P23_IVG(x) (((x)&0xF)-7) << 0x1C /* Peripheral #23 assigned IVG #x */
+
+/* SIC_IAR3 Macros */
+#define P24_IVG(x) (((x)&0xF)-7) /* Peripheral #24 assigned IVG #x */
+#define P25_IVG(x) (((x)&0xF)-7) << 0x4 /* Peripheral #25 assigned IVG #x */
+#define P26_IVG(x) (((x)&0xF)-7) << 0x8 /* Peripheral #26 assigned IVG #x */
+#define P27_IVG(x) (((x)&0xF)-7) << 0xC /* Peripheral #27 assigned IVG #x */
+#define P28_IVG(x) (((x)&0xF)-7) << 0x10 /* Peripheral #28 assigned IVG #x */
+#define P29_IVG(x) (((x)&0xF)-7) << 0x14 /* Peripheral #29 assigned IVG #x */
+#define P30_IVG(x) (((x)&0xF)-7) << 0x18 /* Peripheral #30 assigned IVG #x */
+#define P31_IVG(x) (((x)&0xF)-7) << 0x1C /* Peripheral #31 assigned IVG #x */
+
+/* SIC_IMASK Masks */
+#define SIC_UNMASK_ALL 0x00000000 /* Unmask all peripheral interrupts */
+#define SIC_MASK_ALL 0xFFFFFFFF /* Mask all peripheral interrupts */
+#define SIC_MASK(x) (1 << ((x)&0x1F)) /* Mask Peripheral #x interrupt */
+#define SIC_UNMASK(x) (0xFFFFFFFF ^ (1 << ((x)&0x1F))) /* Unmask Peripheral #x interrupt */
+
+/* SIC_IWR Masks */
+#define IWR_DISABLE_ALL 0x00000000 /* Wakeup Disable all peripherals */
+#define IWR_ENABLE_ALL 0xFFFFFFFF /* Wakeup Enable all peripherals */
+#define IWR_ENABLE(x) (1 << ((x)&0x1F)) /* Wakeup Enable Peripheral #x */
+#define IWR_DISABLE(x) (0xFFFFFFFF ^ (1 << ((x)&0x1F))) /* Wakeup Disable Peripheral #x */
+
+/* *************** WATCHDOG TIMER MASKS *******************************************/
+/* WDOG_CTL Masks */
+#define WDOG_RESET 0x0000 /* Generate Reset Event */
+#define WDOG_NMI 0x0002 /* Generate Non-Maskable Interrupt (NMI) Event */
+#define WDOG_GPI 0x0004 /* Generate General Purpose (GP) Interrupt */
+#define WDOG_NONE 0x0006 /* Disable Watchdog Timer Interrupts */
+#define TMR_EN 0x0FF0 /* Watchdog Counter Enable */
+#define TMR_DIS 0x0AD0 /* Watchdog Counter Disable */
+#define TRO 0x8000 /* Watchdog Expired */
+
+/* ************** UART CONTROLLER MASKS *************************/
+/* UARTx_LCR Masks */
+#define WLS(x) ((((x)&0x3)-5) & 0x03) /* Word Length Select */
+#define STB 0x04 /* Stop Bits */
+#define PEN 0x08 /* Parity Enable */
+#define EPS 0x10 /* Even Parity Select */
+#define STP 0x20 /* Stick Parity */
+#define SB 0x40 /* Set Break */
+#define DLAB 0x80 /* Divisor Latch Access */
+
+/* UARTx_MCR Mask */
+#define LOOP 0x10 /* Loopback Mode Enable */
+
+/* UARTx_LSR Masks */
+#define DR 0x01 /* Data Ready */
+#define OE 0x02 /* Overrun Error */
+#define PE 0x04 /* Parity Error */
+#define FE 0x08 /* Framing Error */
+#define BI 0x10 /* Break Interrupt */
+#define THRE 0x20 /* THR Empty */
+#define TEMT 0x40 /* TSR and UART_THR Empty */
+
+/* UARTx_IER Masks */
+#define ERBFI 0x01 /* Enable Receive Buffer Full Interrupt */
+#define ETBEI 0x02 /* Enable Transmit Buffer Empty Interrupt */
+#define ELSI 0x04 /* Enable RX Status Interrupt */
+
+/* UARTx_IIR Masks */
+#define NINT 0x01 /* Pending Interrupt */
+#define IIR_TX_READY 0x02 /* UART_THR empty */
+#define IIR_RX_READY 0x04 /* Receive data ready */
+#define IIR_LINE_CHANGE 0x06 /* Receive line status */
+#define IIR_STATUS 0x06
+
+/* UARTx_GCTL Masks */
+#define UCEN 0x01 /* Enable UARTx Clocks */
+#define IREN 0x02 /* Enable IrDA Mode */
+#define TPOLC 0x04 /* IrDA TX Polarity Change */
+#define RPOLC 0x08 /* IrDA RX Polarity Change */
+#define FPE 0x10 /* Force Parity Error On Transmit */
+#define FFE 0x20 /* Force Framing Error On Transmit */
+
+/* *********** SERIAL PERIPHERAL INTERFACE (SPI) MASKS ****************************/
+/* SPI_CTL Masks */
+#define TIMOD 0x0003 /* Transfer Initiate Mode */
+#define RDBR_CORE 0x0000 /* RDBR Read Initiates, IRQ When RDBR Full */
+#define TDBR_CORE 0x0001 /* TDBR Write Initiates, IRQ When TDBR Empty */
+#define RDBR_DMA 0x0002 /* DMA Read, DMA Until FIFO Empty */
+#define TDBR_DMA 0x0003 /* DMA Write, DMA Until FIFO Full */
+#define SZ 0x0004 /* Send Zero (When TDBR Empty, Send Zero/Last*) */
+#define GM 0x0008 /* Get More (When RDBR Full, Overwrite/Discard*) */
+#define PSSE 0x0010 /* Slave-Select Input Enable */
+#define EMISO 0x0020 /* Enable MISO As Output */
+#define SPI_SIZE 0x0100 /* Size of Words (16/8* Bits) */
+#define LSBF 0x0200 /* LSB First */
+#define CPHA 0x0400 /* Clock Phase */
+#define CPOL 0x0800 /* Clock Polarity */
+#define MSTR 0x1000 /* Master/Slave* */
+#define WOM 0x2000 /* Write Open Drain Master */
+#define SPE 0x4000 /* SPI Enable */
+
+/* SPI_FLG Masks */
+#define FLS1 0x0002 /* Enables SPI_FLOUT1 as SPI Slave-Select Output */
+#define FLS2 0x0004 /* Enables SPI_FLOUT2 as SPI Slave-Select Output */
+#define FLS3 0x0008 /* Enables SPI_FLOUT3 as SPI Slave-Select Output */
+#define FLS4 0x0010 /* Enables SPI_FLOUT4 as SPI Slave-Select Output */
+#define FLS5 0x0020 /* Enables SPI_FLOUT5 as SPI Slave-Select Output */
+#define FLS6 0x0040 /* Enables SPI_FLOUT6 as SPI Slave-Select Output */
+#define FLS7 0x0080 /* Enables SPI_FLOUT7 as SPI Slave-Select Output */
+#define FLG1 0xFDFF /* Activates SPI_FLOUT1 */
+#define FLG2 0xFBFF /* Activates SPI_FLOUT2 */
+#define FLG3 0xF7FF /* Activates SPI_FLOUT3 */
+#define FLG4 0xEFFF /* Activates SPI_FLOUT4 */
+#define FLG5 0xDFFF /* Activates SPI_FLOUT5 */
+#define FLG6 0xBFFF /* Activates SPI_FLOUT6 */
+#define FLG7 0x7FFF /* Activates SPI_FLOUT7 */
+
+/* SPI_STAT Masks */
+#define SPIF 0x0001 /* SPI Finished (Single-Word Transfer Complete) */
+#define MODF 0x0002 /* Mode Fault Error (Another Device Tried To Become Master) */
+#define TXE 0x0004 /* Transmission Error (Data Sent With No New Data In TDBR) */
+#define TXS 0x0008 /* SPI_TDBR Data Buffer Status (Full/Empty*) */
+#define RBSY 0x0010 /* Receive Error (Data Received With RDBR Full) */
+#define RXS 0x0020 /* SPI_RDBR Data Buffer Status (Full/Empty*) */
+#define TXCOL 0x0040 /* Transmit Collision Error (Corrupt Data May Have Been Sent) */
+
+/* **************** GENERAL PURPOSE TIMER MASKS **********************/
+/* TIMER_ENABLE Masks */
+#define TIMEN0 0x0001 /* Enable Timer 0 */
+#define TIMEN1 0x0002 /* Enable Timer 1 */
+#define TIMEN2 0x0004 /* Enable Timer 2 */
+#define TIMEN3 0x0008 /* Enable Timer 3 */
+#define TIMEN4 0x0010 /* Enable Timer 4 */
+#define TIMEN5 0x0020 /* Enable Timer 5 */
+#define TIMEN6 0x0040 /* Enable Timer 6 */
+#define TIMEN7 0x0080 /* Enable Timer 7 */
+
+/* TIMER_DISABLE Masks */
+#define TIMDIS0 TIMEN0 /* Disable Timer 0 */
+#define TIMDIS1 TIMEN1 /* Disable Timer 1 */
+#define TIMDIS2 TIMEN2 /* Disable Timer 2 */
+#define TIMDIS3 TIMEN3 /* Disable Timer 3 */
+#define TIMDIS4 TIMEN4 /* Disable Timer 4 */
+#define TIMDIS5 TIMEN5 /* Disable Timer 5 */
+#define TIMDIS6 TIMEN6 /* Disable Timer 6 */
+#define TIMDIS7 TIMEN7 /* Disable Timer 7 */
+
+/* TIMER_STATUS Masks */
+#define TIMIL0 0x00000001 /* Timer 0 Interrupt */
+#define TIMIL1 0x00000002 /* Timer 1 Interrupt */
+#define TIMIL2 0x00000004 /* Timer 2 Interrupt */
+#define TIMIL3 0x00000008 /* Timer 3 Interrupt */
+#define TOVL_ERR0 0x00000010 /* Timer 0 Counter Overflow */
+#define TOVL_ERR1 0x00000020 /* Timer 1 Counter Overflow */
+#define TOVL_ERR2 0x00000040 /* Timer 2 Counter Overflow */
+#define TOVL_ERR3 0x00000080 /* Timer 3 Counter Overflow */
+#define TRUN0 0x00001000 /* Timer 0 Slave Enable Status */
+#define TRUN1 0x00002000 /* Timer 1 Slave Enable Status */
+#define TRUN2 0x00004000 /* Timer 2 Slave Enable Status */
+#define TRUN3 0x00008000 /* Timer 3 Slave Enable Status */
+#define TIMIL4 0x00010000 /* Timer 4 Interrupt */
+#define TIMIL5 0x00020000 /* Timer 5 Interrupt */
+#define TIMIL6 0x00040000 /* Timer 6 Interrupt */
+#define TIMIL7 0x00080000 /* Timer 7 Interrupt */
+#define TOVL_ERR4 0x00100000 /* Timer 4 Counter Overflow */
+#define TOVL_ERR5 0x00200000 /* Timer 5 Counter Overflow */
+#define TOVL_ERR6 0x00400000 /* Timer 6 Counter Overflow */
+#define TOVL_ERR7 0x00800000 /* Timer 7 Counter Overflow */
+#define TRUN4 0x10000000 /* Timer 4 Slave Enable Status */
+#define TRUN5 0x20000000 /* Timer 5 Slave Enable Status */
+#define TRUN6 0x40000000 /* Timer 6 Slave Enable Status */
+#define TRUN7 0x80000000 /* Timer 7 Slave Enable Status */
+
+/* TIMERx_CONFIG Masks */
+#define PWM_OUT 0x0001 /* Pulse-Width Modulation Output Mode */
+#define WDTH_CAP 0x0002 /* Width Capture Input Mode */
+#define EXT_CLK 0x0003 /* External Clock Mode */
+#define PULSE_HI 0x0004 /* Action Pulse (Positive/Negative*) */
+#define PERIOD_CNT 0x0008 /* Period Count */
+#define IRQ_ENA 0x0010 /* Interrupt Request Enable */
+#define TIN_SEL 0x0020 /* Timer Input Select */
+#define OUT_DIS 0x0040 /* Output Pad Disable */
+#define CLK_SEL 0x0080 /* Timer Clock Select */
+#define TOGGLE_HI 0x0100 /* PWM_OUT PULSE_HI Toggle Mode */
+#define EMU_RUN 0x0200 /* Emulation Behavior Select */
+#define ERR_TYP 0xC000 /* Error Type */
+
+/* ****************** GPIO PORTS F, G, H MASKS ***********************/
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) Masks */
+/* Port F Masks */
+#define PF0 0x0001
+#define PF1 0x0002
+#define PF2 0x0004
+#define PF3 0x0008
+#define PF4 0x0010
+#define PF5 0x0020
+#define PF6 0x0040
+#define PF7 0x0080
+#define PF8 0x0100
+#define PF9 0x0200
+#define PF10 0x0400
+#define PF11 0x0800
+#define PF12 0x1000
+#define PF13 0x2000
+#define PF14 0x4000
+#define PF15 0x8000
+
+/* Port G Masks */
+#define PG0 0x0001
+#define PG1 0x0002
+#define PG2 0x0004
+#define PG3 0x0008
+#define PG4 0x0010
+#define PG5 0x0020
+#define PG6 0x0040
+#define PG7 0x0080
+#define PG8 0x0100
+#define PG9 0x0200
+#define PG10 0x0400
+#define PG11 0x0800
+#define PG12 0x1000
+#define PG13 0x2000
+#define PG14 0x4000
+#define PG15 0x8000
+
+/* Port H Masks */
+#define PH0 0x0001
+#define PH1 0x0002
+#define PH2 0x0004
+#define PH3 0x0008
+#define PH4 0x0010
+#define PH5 0x0020
+#define PH6 0x0040
+#define PH7 0x0080
+#define PH8 0x0100
+#define PH9 0x0200
+#define PH10 0x0400
+#define PH11 0x0800
+#define PH12 0x1000
+#define PH13 0x2000
+#define PH14 0x4000
+#define PH15 0x8000
+
+/* ******************* SERIAL PORT MASKS **************************************/
+/* SPORTx_TCR1 Masks */
+#define TSPEN 0x0001 /* Transmit Enable */
+#define ITCLK 0x0002 /* Internal Transmit Clock Select */
+#define DTYPE_NORM 0x0004 /* Data Format Normal */
+#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */
+#define DTYPE_ALAW 0x000C /* Compand Using A-Law */
+#define TLSBIT 0x0010 /* Transmit Bit Order */
+#define ITFS 0x0200 /* Internal Transmit Frame Sync Select */
+#define TFSR 0x0400 /* Transmit Frame Sync Required Select */
+#define DITFS 0x0800 /* Data-Independent Transmit Frame Sync Select */
+#define LTFS 0x1000 /* Low Transmit Frame Sync Select */
+#define LATFS 0x2000 /* Late Transmit Frame Sync Select */
+#define TCKFE 0x4000 /* Clock Falling Edge Select */
+
+/* SPORTx_TCR2 Masks and Macro */
+#define SLEN(x) ((x)&0x1F) /* SPORT TX Word Length (2 - 31) */
+#define TXSE 0x0100 /* TX Secondary Enable */
+#define TSFSE 0x0200 /* Transmit Stereo Frame Sync Enable */
+#define TRFST 0x0400 /* Left/Right Order (1 = Right Channel 1st) */
+
+/* SPORTx_RCR1 Masks */
+#define RSPEN 0x0001 /* Receive Enable */
+#define IRCLK 0x0002 /* Internal Receive Clock Select */
+#define DTYPE_NORM 0x0004 /* Data Format Normal */
+#define DTYPE_ULAW 0x0008 /* Compand Using u-Law */
+#define DTYPE_ALAW 0x000C /* Compand Using A-Law */
+#define RLSBIT 0x0010 /* Receive Bit Order */
+#define IRFS 0x0200 /* Internal Receive Frame Sync Select */
+#define RFSR 0x0400 /* Receive Frame Sync Required Select */
+#define LRFS 0x1000 /* Low Receive Frame Sync Select */
+#define LARFS 0x2000 /* Late Receive Frame Sync Select */
+#define RCKFE 0x4000 /* Clock Falling Edge Select */
+
+/* SPORTx_RCR2 Masks */
+#define SLEN(x) ((x)&0x1F) /* SPORT RX Word Length (2 - 31) */
+#define RXSE 0x0100 /* RX Secondary Enable */
+#define RSFSE 0x0200 /* RX Stereo Frame Sync Enable */
+#define RRFST 0x0400 /* Right-First Data Order */
+
+/* SPORTx_STAT Masks */
+#define RXNE 0x0001 /* Receive FIFO Not Empty Status */
+#define RUVF 0x0002 /* Sticky Receive Underflow Status */
+#define ROVF 0x0004 /* Sticky Receive Overflow Status */
+#define TXF 0x0008 /* Transmit FIFO Full Status */
+#define TUVF 0x0010 /* Sticky Transmit Underflow Status */
+#define TOVF 0x0020 /* Sticky Transmit Overflow Status */
+#define TXHRE 0x0040 /* Transmit Hold Register Empty */
+
+/* SPORTx_MCMC1 Macros */
+#define SP_WOFF(x) ((x) & 0x3FF) /* Multichannel Window Offset Field */
+
+/* Only use WSIZE Macro With Logic OR While Setting Lower Order Bits */
+#define SP_WSIZE(x) (((((x)>>0x3)-1)&0xF) << 0xC) /* Multichannel Window Size = (x/8)-1 */
+
+/* SPORTx_MCMC2 Masks */
+#define REC_BYPASS 0x0000 /* Bypass Mode (No Clock Recovery) */
+#define REC_2FROM4 0x0002 /* Recover 2 MHz Clock from 4 MHz Clock */
+#define REC_8FROM16 0x0003 /* Recover 8 MHz Clock from 16 MHz Clock */
+#define MCDTXPE 0x0004 /* Multichannel DMA Transmit Packing */
+#define MCDRXPE 0x0008 /* Multichannel DMA Receive Packing */
+#define MCMEN 0x0010 /* Multichannel Frame Mode Enable */
+#define FSDR 0x0080 /* Multichannel Frame Sync to Data Relationship */
+#define MFD_0 0x0000 /* Multichannel Frame Delay = 0 */
+#define MFD_1 0x1000 /* Multichannel Frame Delay = 1 */
+#define MFD_2 0x2000 /* Multichannel Frame Delay = 2 */
+#define MFD_3 0x3000 /* Multichannel Frame Delay = 3 */
+#define MFD_4 0x4000 /* Multichannel Frame Delay = 4 */
+#define MFD_5 0x5000 /* Multichannel Frame Delay = 5 */
+#define MFD_6 0x6000 /* Multichannel Frame Delay = 6 */
+#define MFD_7 0x7000 /* Multichannel Frame Delay = 7 */
+#define MFD_8 0x8000 /* Multichannel Frame Delay = 8 */
+#define MFD_9 0x9000 /* Multichannel Frame Delay = 9 */
+#define MFD_10 0xA000 /* Multichannel Frame Delay = 10 */
+#define MFD_11 0xB000 /* Multichannel Frame Delay = 11 */
+#define MFD_12 0xC000 /* Multichannel Frame Delay = 12 */
+#define MFD_13 0xD000 /* Multichannel Frame Delay = 13 */
+#define MFD_14 0xE000 /* Multichannel Frame Delay = 14 */
+#define MFD_15 0xF000 /* Multichannel Frame Delay = 15 */
+
+/* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS *************************/
+/* EBIU_AMGCTL Masks */
+#define AMCKEN 0x0001 /* Enable CLKOUT */
+#define AMBEN_NONE 0x0000 /* All Banks Disabled */
+#define AMBEN_B0 0x0002 /* Enable Async Memory Bank 0 only */
+#define AMBEN_B0_B1 0x0004 /* Enable Async Memory Banks 0 & 1 only */
+#define AMBEN_B0_B1_B2 0x0006 /* Enable Async Memory Banks 0, 1, and 2 */
+#define AMBEN_ALL 0x0008 /* Enable Async Memory Banks (all) 0, 1, 2, and 3 */
+
+/* EBIU_AMBCTL0 Masks */
+#define B0RDYEN 0x00000001 /* Bank 0 (B0) RDY Enable */
+#define B0RDYPOL 0x00000002 /* B0 RDY Active High */
+#define B0TT_1 0x00000004 /* B0 Transition Time (Read to Write) = 1 cycle */
+#define B0TT_2 0x00000008 /* B0 Transition Time (Read to Write) = 2 cycles */
+#define B0TT_3 0x0000000C /* B0 Transition Time (Read to Write) = 3 cycles */
+#define B0TT_4 0x00000000 /* B0 Transition Time (Read to Write) = 4 cycles */
+#define B0ST_1 0x00000010 /* B0 Setup Time (AOE to Read/Write) = 1 cycle */
+#define B0ST_2 0x00000020 /* B0 Setup Time (AOE to Read/Write) = 2 cycles */
+#define B0ST_3 0x00000030 /* B0 Setup Time (AOE to Read/Write) = 3 cycles */
+#define B0ST_4 0x00000000 /* B0 Setup Time (AOE to Read/Write) = 4 cycles */
+#define B0HT_1 0x00000040 /* B0 Hold Time (~Read/Write to ~AOE) = 1 cycle */
+#define B0HT_2 0x00000080 /* B0 Hold Time (~Read/Write to ~AOE) = 2 cycles */
+#define B0HT_3 0x000000C0 /* B0 Hold Time (~Read/Write to ~AOE) = 3 cycles */
+#define B0HT_0 0x00000000 /* B0 Hold Time (~Read/Write to ~AOE) = 0 cycles */
+#define B0RAT_1 0x00000100 /* B0 Read Access Time = 1 cycle */
+#define B0RAT_2 0x00000200 /* B0 Read Access Time = 2 cycles */
+#define B0RAT_3 0x00000300 /* B0 Read Access Time = 3 cycles */
+#define B0RAT_4 0x00000400 /* B0 Read Access Time = 4 cycles */
+#define B0RAT_5 0x00000500 /* B0 Read Access Time = 5 cycles */
+#define B0RAT_6 0x00000600 /* B0 Read Access Time = 6 cycles */
+#define B0RAT_7 0x00000700 /* B0 Read Access Time = 7 cycles */
+#define B0RAT_8 0x00000800 /* B0 Read Access Time = 8 cycles */
+#define B0RAT_9 0x00000900 /* B0 Read Access Time = 9 cycles */
+#define B0RAT_10 0x00000A00 /* B0 Read Access Time = 10 cycles */
+#define B0RAT_11 0x00000B00 /* B0 Read Access Time = 11 cycles */
+#define B0RAT_12 0x00000C00 /* B0 Read Access Time = 12 cycles */
+#define B0RAT_13 0x00000D00 /* B0 Read Access Time = 13 cycles */
+#define B0RAT_14 0x00000E00 /* B0 Read Access Time = 14 cycles */
+#define B0RAT_15 0x00000F00 /* B0 Read Access Time = 15 cycles */
+#define B0WAT_1 0x00001000 /* B0 Write Access Time = 1 cycle */
+#define B0WAT_2 0x00002000 /* B0 Write Access Time = 2 cycles */
+#define B0WAT_3 0x00003000 /* B0 Write Access Time = 3 cycles */
+#define B0WAT_4 0x00004000 /* B0 Write Access Time = 4 cycles */
+#define B0WAT_5 0x00005000 /* B0 Write Access Time = 5 cycles */
+#define B0WAT_6 0x00006000 /* B0 Write Access Time = 6 cycles */
+#define B0WAT_7 0x00007000 /* B0 Write Access Time = 7 cycles */
+#define B0WAT_8 0x00008000 /* B0 Write Access Time = 8 cycles */
+#define B0WAT_9 0x00009000 /* B0 Write Access Time = 9 cycles */
+#define B0WAT_10 0x0000A000 /* B0 Write Access Time = 10 cycles */
+#define B0WAT_11 0x0000B000 /* B0 Write Access Time = 11 cycles */
+#define B0WAT_12 0x0000C000 /* B0 Write Access Time = 12 cycles */
+#define B0WAT_13 0x0000D000 /* B0 Write Access Time = 13 cycles */
+#define B0WAT_14 0x0000E000 /* B0 Write Access Time = 14 cycles */
+#define B0WAT_15 0x0000F000 /* B0 Write Access Time = 15 cycles */
+
+#define B1RDYEN 0x00010000 /* Bank 1 (B1) RDY Enable */
+#define B1RDYPOL 0x00020000 /* B1 RDY Active High */
+#define B1TT_1 0x00040000 /* B1 Transition Time (Read to Write) = 1 cycle */
+#define B1TT_2 0x00080000 /* B1 Transition Time (Read to Write) = 2 cycles */
+#define B1TT_3 0x000C0000 /* B1 Transition Time (Read to Write) = 3 cycles */
+#define B1TT_4 0x00000000 /* B1 Transition Time (Read to Write) = 4 cycles */
+#define B1ST_1 0x00100000 /* B1 Setup Time (AOE to Read/Write) = 1 cycle */
+#define B1ST_2 0x00200000 /* B1 Setup Time (AOE to Read/Write) = 2 cycles */
+#define B1ST_3 0x00300000 /* B1 Setup Time (AOE to Read/Write) = 3 cycles */
+#define B1ST_4 0x00000000 /* B1 Setup Time (AOE to Read/Write) = 4 cycles */
+#define B1HT_1 0x00400000 /* B1 Hold Time (~Read/Write to ~AOE) = 1 cycle */
+#define B1HT_2 0x00800000 /* B1 Hold Time (~Read/Write to ~AOE) = 2 cycles */
+#define B1HT_3 0x00C00000 /* B1 Hold Time (~Read/Write to ~AOE) = 3 cycles */
+#define B1HT_0 0x00000000 /* B1 Hold Time (~Read/Write to ~AOE) = 0 cycles */
+#define B1RAT_1 0x01000000 /* B1 Read Access Time = 1 cycle */
+#define B1RAT_2 0x02000000 /* B1 Read Access Time = 2 cycles */
+#define B1RAT_3 0x03000000 /* B1 Read Access Time = 3 cycles */
+#define B1RAT_4 0x04000000 /* B1 Read Access Time = 4 cycles */
+#define B1RAT_5 0x05000000 /* B1 Read Access Time = 5 cycles */
+#define B1RAT_6 0x06000000 /* B1 Read Access Time = 6 cycles */
+#define B1RAT_7 0x07000000 /* B1 Read Access Time = 7 cycles */
+#define B1RAT_8 0x08000000 /* B1 Read Access Time = 8 cycles */
+#define B1RAT_9 0x09000000 /* B1 Read Access Time = 9 cycles */
+#define B1RAT_10 0x0A000000 /* B1 Read Access Time = 10 cycles */
+#define B1RAT_11 0x0B000000 /* B1 Read Access Time = 11 cycles */
+#define B1RAT_12 0x0C000000 /* B1 Read Access Time = 12 cycles */
+#define B1RAT_13 0x0D000000 /* B1 Read Access Time = 13 cycles */
+#define B1RAT_14 0x0E000000 /* B1 Read Access Time = 14 cycles */
+#define B1RAT_15 0x0F000000 /* B1 Read Access Time = 15 cycles */
+#define B1WAT_1 0x10000000 /* B1 Write Access Time = 1 cycle */
+#define B1WAT_2 0x20000000 /* B1 Write Access Time = 2 cycles */
+#define B1WAT_3 0x30000000 /* B1 Write Access Time = 3 cycles */
+#define B1WAT_4 0x40000000 /* B1 Write Access Time = 4 cycles */
+#define B1WAT_5 0x50000000 /* B1 Write Access Time = 5 cycles */
+#define B1WAT_6 0x60000000 /* B1 Write Access Time = 6 cycles */
+#define B1WAT_7 0x70000000 /* B1 Write Access Time = 7 cycles */
+#define B1WAT_8 0x80000000 /* B1 Write Access Time = 8 cycles */
+#define B1WAT_9 0x90000000 /* B1 Write Access Time = 9 cycles */
+#define B1WAT_10 0xA0000000 /* B1 Write Access Time = 10 cycles */
+#define B1WAT_11 0xB0000000 /* B1 Write Access Time = 11 cycles */
+#define B1WAT_12 0xC0000000 /* B1 Write Access Time = 12 cycles */
+#define B1WAT_13 0xD0000000 /* B1 Write Access Time = 13 cycles */
+#define B1WAT_14 0xE0000000 /* B1 Write Access Time = 14 cycles */
+#define B1WAT_15 0xF0000000 /* B1 Write Access Time = 15 cycles */
+
+/* EBIU_AMBCTL1 Masks */
+#define B2RDYEN 0x00000001 /* Bank 2 (B2) RDY Enable */
+#define B2RDYPOL 0x00000002 /* B2 RDY Active High */
+#define B2TT_1 0x00000004 /* B2 Transition Time (Read to Write) = 1 cycle */
+#define B2TT_2 0x00000008 /* B2 Transition Time (Read to Write) = 2 cycles */
+#define B2TT_3 0x0000000C /* B2 Transition Time (Read to Write) = 3 cycles */
+#define B2TT_4 0x00000000 /* B2 Transition Time (Read to Write) = 4 cycles */
+#define B2ST_1 0x00000010 /* B2 Setup Time (AOE to Read/Write) = 1 cycle */
+#define B2ST_2 0x00000020 /* B2 Setup Time (AOE to Read/Write) = 2 cycles */
+#define B2ST_3 0x00000030 /* B2 Setup Time (AOE to Read/Write) = 3 cycles */
+#define B2ST_4 0x00000000 /* B2 Setup Time (AOE to Read/Write) = 4 cycles */
+#define B2HT_1 0x00000040 /* B2 Hold Time (~Read/Write to ~AOE) = 1 cycle */
+#define B2HT_2 0x00000080 /* B2 Hold Time (~Read/Write to ~AOE) = 2 cycles */
+#define B2HT_3 0x000000C0 /* B2 Hold Time (~Read/Write to ~AOE) = 3 cycles */
+#define B2HT_0 0x00000000 /* B2 Hold Time (~Read/Write to ~AOE) = 0 cycles */
+#define B2RAT_1 0x00000100 /* B2 Read Access Time = 1 cycle */
+#define B2RAT_2 0x00000200 /* B2 Read Access Time = 2 cycles */
+#define B2RAT_3 0x00000300 /* B2 Read Access Time = 3 cycles */
+#define B2RAT_4 0x00000400 /* B2 Read Access Time = 4 cycles */
+#define B2RAT_5 0x00000500 /* B2 Read Access Time = 5 cycles */
+#define B2RAT_6 0x00000600 /* B2 Read Access Time = 6 cycles */
+#define B2RAT_7 0x00000700 /* B2 Read Access Time = 7 cycles */
+#define B2RAT_8 0x00000800 /* B2 Read Access Time = 8 cycles */
+#define B2RAT_9 0x00000900 /* B2 Read Access Time = 9 cycles */
+#define B2RAT_10 0x00000A00 /* B2 Read Access Time = 10 cycles */
+#define B2RAT_11 0x00000B00 /* B2 Read Access Time = 11 cycles */
+#define B2RAT_12 0x00000C00 /* B2 Read Access Time = 12 cycles */
+#define B2RAT_13 0x00000D00 /* B2 Read Access Time = 13 cycles */
+#define B2RAT_14 0x00000E00 /* B2 Read Access Time = 14 cycles */
+#define B2RAT_15 0x00000F00 /* B2 Read Access Time = 15 cycles */
+#define B2WAT_1 0x00001000 /* B2 Write Access Time = 1 cycle */
+#define B2WAT_2 0x00002000 /* B2 Write Access Time = 2 cycles */
+#define B2WAT_3 0x00003000 /* B2 Write Access Time = 3 cycles */
+#define B2WAT_4 0x00004000 /* B2 Write Access Time = 4 cycles */
+#define B2WAT_5 0x00005000 /* B2 Write Access Time = 5 cycles */
+#define B2WAT_6 0x00006000 /* B2 Write Access Time = 6 cycles */
+#define B2WAT_7 0x00007000 /* B2 Write Access Time = 7 cycles */
+#define B2WAT_8 0x00008000 /* B2 Write Access Time = 8 cycles */
+#define B2WAT_9 0x00009000 /* B2 Write Access Time = 9 cycles */
+#define B2WAT_10 0x0000A000 /* B2 Write Access Time = 10 cycles */
+#define B2WAT_11 0x0000B000 /* B2 Write Access Time = 11 cycles */
+#define B2WAT_12 0x0000C000 /* B2 Write Access Time = 12 cycles */
+#define B2WAT_13 0x0000D000 /* B2 Write Access Time = 13 cycles */
+#define B2WAT_14 0x0000E000 /* B2 Write Access Time = 14 cycles */
+#define B2WAT_15 0x0000F000 /* B2 Write Access Time = 15 cycles */
+
+#define B3RDYEN 0x00010000 /* Bank 3 (B3) RDY Enable */
+#define B3RDYPOL 0x00020000 /* B3 RDY Active High */
+#define B3TT_1 0x00040000 /* B3 Transition Time (Read to Write) = 1 cycle */
+#define B3TT_2 0x00080000 /* B3 Transition Time (Read to Write) = 2 cycles */
+#define B3TT_3 0x000C0000 /* B3 Transition Time (Read to Write) = 3 cycles */
+#define B3TT_4 0x00000000 /* B3 Transition Time (Read to Write) = 4 cycles */
+#define B3ST_1 0x00100000 /* B3 Setup Time (AOE to Read/Write) = 1 cycle */
+#define B3ST_2 0x00200000 /* B3 Setup Time (AOE to Read/Write) = 2 cycles */
+#define B3ST_3 0x00300000 /* B3 Setup Time (AOE to Read/Write) = 3 cycles */
+#define B3ST_4 0x00000000 /* B3 Setup Time (AOE to Read/Write) = 4 cycles */
+#define B3HT_1 0x00400000 /* B3 Hold Time (~Read/Write to ~AOE) = 1 cycle */
+#define B3HT_2 0x00800000 /* B3 Hold Time (~Read/Write to ~AOE) = 2 cycles */
+#define B3HT_3 0x00C00000 /* B3 Hold Time (~Read/Write to ~AOE) = 3 cycles */
+#define B3HT_0 0x00000000 /* B3 Hold Time (~Read/Write to ~AOE) = 0 cycles */
+#define B3RAT_1 0x01000000 /* B3 Read Access Time = 1 cycle */
+#define B3RAT_2 0x02000000 /* B3 Read Access Time = 2 cycles */
+#define B3RAT_3 0x03000000 /* B3 Read Access Time = 3 cycles */
+#define B3RAT_4 0x04000000 /* B3 Read Access Time = 4 cycles */
+#define B3RAT_5 0x05000000 /* B3 Read Access Time = 5 cycles */
+#define B3RAT_6 0x06000000 /* B3 Read Access Time = 6 cycles */
+#define B3RAT_7 0x07000000 /* B3 Read Access Time = 7 cycles */
+#define B3RAT_8 0x08000000 /* B3 Read Access Time = 8 cycles */
+#define B3RAT_9 0x09000000 /* B3 Read Access Time = 9 cycles */
+#define B3RAT_10 0x0A000000 /* B3 Read Access Time = 10 cycles */
+#define B3RAT_11 0x0B000000 /* B3 Read Access Time = 11 cycles */
+#define B3RAT_12 0x0C000000 /* B3 Read Access Time = 12 cycles */
+#define B3RAT_13 0x0D000000 /* B3 Read Access Time = 13 cycles */
+#define B3RAT_14 0x0E000000 /* B3 Read Access Time = 14 cycles */
+#define B3RAT_15 0x0F000000 /* B3 Read Access Time = 15 cycles */
+#define B3WAT_1 0x10000000 /* B3 Write Access Time = 1 cycle */
+#define B3WAT_2 0x20000000 /* B3 Write Access Time = 2 cycles */
+#define B3WAT_3 0x30000000 /* B3 Write Access Time = 3 cycles */
+#define B3WAT_4 0x40000000 /* B3 Write Access Time = 4 cycles */
+#define B3WAT_5 0x50000000 /* B3 Write Access Time = 5 cycles */
+#define B3WAT_6 0x60000000 /* B3 Write Access Time = 6 cycles */
+#define B3WAT_7 0x70000000 /* B3 Write Access Time = 7 cycles */
+#define B3WAT_8 0x80000000 /* B3 Write Access Time = 8 cycles */
+#define B3WAT_9 0x90000000 /* B3 Write Access Time = 9 cycles */
+#define B3WAT_10 0xA0000000 /* B3 Write Access Time = 10 cycles */
+#define B3WAT_11 0xB0000000 /* B3 Write Access Time = 11 cycles */
+#define B3WAT_12 0xC0000000 /* B3 Write Access Time = 12 cycles */
+#define B3WAT_13 0xD0000000 /* B3 Write Access Time = 13 cycles */
+#define B3WAT_14 0xE0000000 /* B3 Write Access Time = 14 cycles */
+#define B3WAT_15 0xF0000000 /* B3 Write Access Time = 15 cycles */
+
+/* ********************** SDRAM CONTROLLER MASKS **********************************************/
+/* EBIU_SDGCTL Masks */
+#define SCTLE 0x00000001 /* Enable SDRAM Signals */
+#define CL_2 0x00000008 /* SDRAM CAS Latency = 2 cycles */
+#define CL_3 0x0000000C /* SDRAM CAS Latency = 3 cycles */
+#define PASR_ALL 0x00000000 /* All 4 SDRAM Banks Refreshed In Self-Refresh */
+#define PASR_B0_B1 0x00000010 /* SDRAM Banks 0 and 1 Are Refreshed In Self-Refresh */
+#define PASR_B0 0x00000020 /* Only SDRAM Bank 0 Is Refreshed In Self-Refresh */
+#define TRAS_1 0x00000040 /* SDRAM tRAS = 1 cycle */
+#define TRAS_2 0x00000080 /* SDRAM tRAS = 2 cycles */
+#define TRAS_3 0x000000C0 /* SDRAM tRAS = 3 cycles */
+#define TRAS_4 0x00000100 /* SDRAM tRAS = 4 cycles */
+#define TRAS_5 0x00000140 /* SDRAM tRAS = 5 cycles */
+#define TRAS_6 0x00000180 /* SDRAM tRAS = 6 cycles */
+#define TRAS_7 0x000001C0 /* SDRAM tRAS = 7 cycles */
+#define TRAS_8 0x00000200 /* SDRAM tRAS = 8 cycles */
+#define TRAS_9 0x00000240 /* SDRAM tRAS = 9 cycles */
+#define TRAS_10 0x00000280 /* SDRAM tRAS = 10 cycles */
+#define TRAS_11 0x000002C0 /* SDRAM tRAS = 11 cycles */
+#define TRAS_12 0x00000300 /* SDRAM tRAS = 12 cycles */
+#define TRAS_13 0x00000340 /* SDRAM tRAS = 13 cycles */
+#define TRAS_14 0x00000380 /* SDRAM tRAS = 14 cycles */
+#define TRAS_15 0x000003C0 /* SDRAM tRAS = 15 cycles */
+#define TRP_1 0x00000800 /* SDRAM tRP = 1 cycle */
+#define TRP_2 0x00001000 /* SDRAM tRP = 2 cycles */
+#define TRP_3 0x00001800 /* SDRAM tRP = 3 cycles */
+#define TRP_4 0x00002000 /* SDRAM tRP = 4 cycles */
+#define TRP_5 0x00002800 /* SDRAM tRP = 5 cycles */
+#define TRP_6 0x00003000 /* SDRAM tRP = 6 cycles */
+#define TRP_7 0x00003800 /* SDRAM tRP = 7 cycles */
+#define TRCD_1 0x00008000 /* SDRAM tRCD = 1 cycle */
+#define TRCD_2 0x00010000 /* SDRAM tRCD = 2 cycles */
+#define TRCD_3 0x00018000 /* SDRAM tRCD = 3 cycles */
+#define TRCD_4 0x00020000 /* SDRAM tRCD = 4 cycles */
+#define TRCD_5 0x00028000 /* SDRAM tRCD = 5 cycles */
+#define TRCD_6 0x00030000 /* SDRAM tRCD = 6 cycles */
+#define TRCD_7 0x00038000 /* SDRAM tRCD = 7 cycles */
+#define TWR_1 0x00080000 /* SDRAM tWR = 1 cycle */
+#define TWR_2 0x00100000 /* SDRAM tWR = 2 cycles */
+#define TWR_3 0x00180000 /* SDRAM tWR = 3 cycles */
+#define PUPSD 0x00200000 /* Power-Up Start Delay (15 SCLK Cycles Delay) */
+#define PSM 0x00400000 /* Power-Up Sequence (Mode Register Before/After* Refresh) */
+#define PSS 0x00800000 /* Enable Power-Up Sequence on Next SDRAM Access */
+#define SRFS 0x01000000 /* Enable SDRAM Self-Refresh Mode */
+#define EBUFE 0x02000000 /* Enable External Buffering Timing */
+#define FBBRW 0x04000000 /* Enable Fast Back-To-Back Read To Write */
+#define EMREN 0x10000000 /* Extended Mode Register Enable */
+#define TCSR 0x20000000 /* Temp-Compensated Self-Refresh Value (85/45* Deg C) */
+#define CDDBG 0x40000000 /* Tristate SDRAM Controls During Bus Grant */
+
+/* EBIU_SDBCTL Masks */
+#define EBE 0x0001 /* Enable SDRAM External Bank */
+#define EBSZ_16 0x0000 /* SDRAM External Bank Size = 16MB */
+#define EBSZ_32 0x0002 /* SDRAM External Bank Size = 32MB */
+#define EBSZ_64 0x0004 /* SDRAM External Bank Size = 64MB */
+#define EBSZ_128 0x0006 /* SDRAM External Bank Size = 128MB */
+#define EBCAW_8 0x0000 /* SDRAM External Bank Column Address Width = 8 Bits */
+#define EBCAW_9 0x0010 /* SDRAM External Bank Column Address Width = 9 Bits */
+#define EBCAW_10 0x0020 /* SDRAM External Bank Column Address Width = 10 Bits */
+#define EBCAW_11 0x0030 /* SDRAM External Bank Column Address Width = 11 Bits */
+
+/* EBIU_SDSTAT Masks */
+#define SDCI 0x0001 /* SDRAM Controller Idle */
+#define SDSRA 0x0002 /* SDRAM Self-Refresh Active */
+#define SDPUA 0x0004 /* SDRAM Power-Up Active */
+#define SDRS 0x0008 /* SDRAM Will Power-Up On Next Access */
+#define SDEASE 0x0010 /* SDRAM EAB Sticky Error Status */
+#define BGSTAT 0x0020 /* Bus Grant Status */
+
+/* ************************** DMA CONTROLLER MASKS ********************************/
+/* DMAx_CONFIG, MDMA_yy_CONFIG Masks */
+#define DMAEN 0x0001 /* DMA Channel Enable */
+#define WNR 0x0002 /* Channel Direction (W/R*) */
+#define WDSIZE_8 0x0000 /* Transfer Word Size = 8 */
+#define WDSIZE_16 0x0004 /* Transfer Word Size = 16 */
+#define WDSIZE_32 0x0008 /* Transfer Word Size = 32 */
+#define DMA2D 0x0010 /* DMA Mode (2D/1D*) */
+#define RESTART 0x0020 /* DMA Buffer Clear */
+#define DI_SEL 0x0040 /* Data Interrupt Timing Select */
+#define DI_EN 0x0080 /* Data Interrupt Enable */
+#define NDSIZE_0 0x0000 /* Next Descriptor Size = 0 (Stop/Autobuffer) */
+#define NDSIZE_1 0x0100 /* Next Descriptor Size = 1 */
+#define NDSIZE_2 0x0200 /* Next Descriptor Size = 2 */
+#define NDSIZE_3 0x0300 /* Next Descriptor Size = 3 */
+#define NDSIZE_4 0x0400 /* Next Descriptor Size = 4 */
+#define NDSIZE_5 0x0500 /* Next Descriptor Size = 5 */
+#define NDSIZE_6 0x0600 /* Next Descriptor Size = 6 */
+#define NDSIZE_7 0x0700 /* Next Descriptor Size = 7 */
+#define NDSIZE_8 0x0800 /* Next Descriptor Size = 8 */
+#define NDSIZE_9 0x0900 /* Next Descriptor Size = 9 */
+#define NDSIZE 0x0900 /* Next Descriptor Size */
+
+#define DMAFLOW 0x7000 /* Flow Control */
+#define DMAFLOW_STOP 0x0000 /* Stop Mode */
+#define DMAFLOW_AUTO 0x1000 /* Autobuffer Mode */
+#define DMAFLOW_ARRAY 0x4000 /* Descriptor Array Mode */
+#define DMAFLOW_SMALL 0x6000 /* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE 0x7000 /* Large Model Descriptor List Mode */
+
+/* DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP Masks */
+#define CTYPE 0x0040 /* DMA Channel Type Indicator (Memory/Peripheral*) */
+#define PMAP 0xF000 /* Peripheral Mapped To This Channel */
+#define PMAP_PPI 0x0000 /* PPI Port DMA */
+#define PMAP_EMACRX 0x1000 /* Ethernet Receive DMA */
+#define PMAP_EMACTX 0x2000 /* Ethernet Transmit DMA */
+#define PMAP_SPORT0RX 0x3000 /* SPORT0 Receive DMA */
+#define PMAP_SPORT0TX 0x4000 /* SPORT0 Transmit DMA */
+#define PMAP_SPORT1RX 0x5000 /* SPORT1 Receive DMA */
+#define PMAP_SPORT1TX 0x6000 /* SPORT1 Transmit DMA */
+#define PMAP_SPI 0x7000 /* SPI Port DMA */
+#define PMAP_UART0RX 0x8000 /* UART0 Port Receive DMA */
+#define PMAP_UART0TX 0x9000 /* UART0 Port Transmit DMA */
+#define PMAP_UART1RX 0xA000 /* UART1 Port Receive DMA */
+#define PMAP_UART1TX 0xB000 /* UART1 Port Transmit DMA */
+
+/* DMAx_IRQ_STATUS, MDMA_yy_IRQ_STATUS Masks */
+#define DMA_DONE 0x0001 /* DMA Completion Interrupt Status */
+#define DMA_ERR 0x0002 /* DMA Error Interrupt Status */
+#define DFETCH 0x0004 /* DMA Descriptor Fetch Indicator */
+#define DMA_RUN 0x0008 /* DMA Channel Running Indicator */
+
+/* ************ PARALLEL PERIPHERAL INTERFACE (PPI) MASKS *************/
+/* PPI_CONTROL Masks */
+#define PORT_EN 0x0001 /* PPI Port Enable */
+#define PORT_DIR 0x0002 /* PPI Port Direction */
+#define XFR_TYPE 0x000C /* PPI Transfer Type */
+#define PORT_CFG 0x0030 /* PPI Port Configuration */
+#define FLD_SEL 0x0040 /* PPI Active Field Select */
+#define PACK_EN 0x0080 /* PPI Packing Mode */
+#define DMA32 0x0100 /* PPI 32-bit DMA Enable */
+#define SKIP_EN 0x0200 /* PPI Skip Element Enable */
+#define SKIP_EO 0x0400 /* PPI Skip Even/Odd Elements */
+#define DLENGTH 0x3800 /* PPI Data Length */
+#define DLEN_8 0x0000 /* Data Length = 8 Bits */
+#define DLEN_10 0x0800 /* Data Length = 10 Bits */
+#define DLEN_11 0x1000 /* Data Length = 11 Bits */
+#define DLEN_12 0x1800 /* Data Length = 12 Bits */
+#define DLEN_13 0x2000 /* Data Length = 13 Bits */
+#define DLEN_14 0x2800 /* Data Length = 14 Bits */
+#define DLEN_15 0x3000 /* Data Length = 15 Bits */
+#define DLEN_16 0x3800 /* Data Length = 16 Bits */
+#define POLC 0x4000 /* PPI Clock Polarity */
+#define POLS 0x8000 /* PPI Frame Sync Polarity */
+
+/* PPI_STATUS Masks */
+#define FLD 0x0400 /* Field Indicator */
+#define FT_ERR 0x0800 /* Frame Track Error */
+#define OVR 0x1000 /* FIFO Overflow Error */
+#define UNDR 0x2000 /* FIFO Underrun Error */
+#define ERR_DET 0x4000 /* Error Detected Indicator */
+#define ERR_NCOR 0x8000 /* Error Not Corrected Indicator */
+
+/* ******************** TWO-WIRE INTERFACE (TWI) MASKS ***********************/
+/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y); ) */
+#define CLKLOW(x) ((x) & 0xFF) /* Periods Clock Is Held Low */
+#define CLKHI(y) (((y)&0xFF)<<0x8) /* Periods Before New Clock Low */
+
+/* TWI_PRESCALE Masks */
+#define PRESCALE 0x007F /* SCLKs Per Internal Time Reference (10MHz) */
+#define TWI_ENA 0x0080 /* TWI Enable */
+#define SCCB 0x0200 /* SCCB Compatibility Enable */
+
+/* TWI_SLAVE_CTRL Masks */
+#define SEN 0x0001 /* Slave Enable */
+#define SADD_LEN 0x0002 /* Slave Address Length */
+#define STDVAL 0x0004 /* Slave Transmit Data Valid */
+#define NAK 0x0008 /* NAK/ACK* Generated At Conclusion Of Transfer */
+#define GEN 0x0010 /* General Call Adrress Matching Enabled */
+
+/* TWI_SLAVE_STAT Masks */
+#define SDIR 0x0001 /* Slave Transfer Direction (Transmit/Receive*) */
+#define GCALL 0x0002 /* General Call Indicator */
+
+/* TWI_MASTER_CTRL Masks */
+#define MEN 0x0001 /* Master Mode Enable */
+#define MADD_LEN 0x0002 /* Master Address Length */
+#define MDIR 0x0004 /* Master Transmit Direction (RX/TX*) */
+#define FAST 0x0008 /* Use Fast Mode Timing Specs */
+#define STOP 0x0010 /* Issue Stop Condition */
+#define RSTART 0x0020 /* Repeat Start or Stop* At End Of Transfer */
+#define DCNT 0x3FC0 /* Data Bytes To Transfer */
+#define SDAOVR 0x4000 /* Serial Data Override */
+#define SCLOVR 0x8000 /* Serial Clock Override */
+
+/* TWI_MASTER_STAT Masks */
+#define MPROG 0x0001 /* Master Transfer In Progress */
+#define LOSTARB 0x0002 /* Lost Arbitration Indicator (Xfer Aborted) */
+#define ANAK 0x0004 /* Address Not Acknowledged */
+#define DNAK 0x0008 /* Data Not Acknowledged */
+#define BUFRDERR 0x0010 /* Buffer Read Error */
+#define BUFWRERR 0x0020 /* Buffer Write Error */
+#define SDASEN 0x0040 /* Serial Data Sense */
+#define SCLSEN 0x0080 /* Serial Clock Sense */
+#define BUSBUSY 0x0100 /* Bus Busy Indicator */
+
+/* TWI_INT_SRC and TWI_INT_ENABLE Masks */
+#define SINIT 0x0001 /* Slave Transfer Initiated */
+#define SCOMP 0x0002 /* Slave Transfer Complete */
+#define SERR 0x0004 /* Slave Transfer Error */
+#define SOVF 0x0008 /* Slave Overflow */
+#define MCOMP 0x0010 /* Master Transfer Complete */
+#define MERR 0x0020 /* Master Transfer Error */
+#define XMTSERV 0x0040 /* Transmit FIFO Service */
+#define RCVSERV 0x0080 /* Receive FIFO Service */
+
+/* TWI_FIFO_CTRL Masks */
+#define XMTFLUSH 0x0001 /* Transmit Buffer Flush */
+#define RCVFLUSH 0x0002 /* Receive Buffer Flush */
+#define XMTINTLEN 0x0004 /* Transmit Buffer Interrupt Length */
+#define RCVINTLEN 0x0008 /* Receive Buffer Interrupt Length */
+
+/* TWI_FIFO_STAT Masks */
+#define XMTSTAT 0x0003 /* Transmit FIFO Status */
+#define XMT_EMPTY 0x0000 /* Transmit FIFO Empty */
+#define XMT_HALF 0x0001 /* Transmit FIFO Has 1 Byte To Write */
+#define XMT_FULL 0x0003 /* Transmit FIFO Full (2 Bytes To Write) */
+
+#define RCVSTAT 0x000C /* Receive FIFO Status */
+#define RCV_EMPTY 0x0000 /* Receive FIFO Empty */
+#define RCV_HALF 0x0004 /* Receive FIFO Has 1 Byte To Read */
+#define RCV_FULL 0x000C /* Receive FIFO Full (2 Bytes To Read) */
+
+/* ************ CONTROLLER AREA NETWORK (CAN) MASKS ***************/
+/* CAN_CONTROL Masks */
+#define SRS 0x0001 /* Software Reset */
+#define DNM 0x0002 /* Device Net Mode */
+#define ABO 0x0004 /* Auto-Bus On Enable */
+#define TXPRIO 0x0008 /* TX Priority (Priority/Mailbox*) */
+#define WBA 0x0010 /* Wake-Up On CAN Bus Activity Enable */
+#define SMR 0x0020 /* Sleep Mode Request */
+#define CSR 0x0040 /* CAN Suspend Mode Request */
+#define CCR 0x0080 /* CAN Configuration Mode Request */
+
+/* CAN_STATUS Masks */
+#define WT 0x0001 /* TX Warning Flag */
+#define WR 0x0002 /* RX Warning Flag */
+#define EP 0x0004 /* Error Passive Mode */
+#define EBO 0x0008 /* Error Bus Off Mode */
+#define SMA 0x0020 /* Sleep Mode Acknowledge */
+#define CSA 0x0040 /* Suspend Mode Acknowledge */
+#define CCA 0x0080 /* Configuration Mode Acknowledge */
+#define MBPTR 0x1F00 /* Mailbox Pointer */
+#define TRM 0x4000 /* Transmit Mode */
+#define REC 0x8000 /* Receive Mode */
+
+/* CAN_CLOCK Masks */
+#define BRP 0x03FF /* Bit-Rate Pre-Scaler */
+
+/* CAN_TIMING Masks */
+#define TSEG1 0x000F /* Time Segment 1 */
+#define TSEG2 0x0070 /* Time Segment 2 */
+#define SAM 0x0080 /* Sampling */
+#define SJW 0x0300 /* Synchronization Jump Width */
+
+/* CAN_DEBUG Masks */
+#define DEC 0x0001 /* Disable CAN Error Counters */
+#define DRI 0x0002 /* Disable CAN RX Input */
+#define DTO 0x0004 /* Disable CAN TX Output */
+#define DIL 0x0008 /* Disable CAN Internal Loop */
+#define MAA 0x0010 /* Mode Auto-Acknowledge Enable */
+#define MRB 0x0020 /* Mode Read Back Enable */
+#define CDE 0x8000 /* CAN Debug Enable */
+
+/* CAN_CEC Masks */
+#define RXECNT 0x00FF /* Receive Error Counter */
+#define TXECNT 0xFF00 /* Transmit Error Counter */
+
+/* CAN_INTR Masks */
+#define MBRIF 0x0001 /* Mailbox Receive Interrupt */
+#define MBTIF 0x0002 /* Mailbox Transmit Interrupt */
+#define GIRQ 0x0004 /* Global Interrupt */
+#define SMACK 0x0008 /* Sleep Mode Acknowledge */
+#define CANTX 0x0040 /* CAN TX Bus Value */
+#define CANRX 0x0080 /* CAN RX Bus Value */
+
+/* CAN_MBxx_ID1 and CAN_MBxx_ID0 Masks */
+#define DFC 0xFFFF /* Data Filtering Code (If Enabled) (ID0) */
+#define EXTID_LO 0xFFFF /* Lower 16 Bits of Extended Identifier (ID0) */
+#define EXTID_HI 0x0003 /* Upper 2 Bits of Extended Identifier (ID1) */
+#define BASEID 0x1FFC /* Base Identifier */
+#define IDE 0x2000 /* Identifier Extension */
+#define RTR 0x4000 /* Remote Frame Transmission Request */
+#define AME 0x8000 /* Acceptance Mask Enable */
+
+/* CAN_MBxx_TIMESTAMP Masks */
+#define TSV 0xFFFF /* Timestamp */
+
+/* CAN_MBxx_LENGTH Masks */
+#define DLC 0x000F /* Data Length Code */
+
+/* CAN_AMxxH and CAN_AMxxL Masks */
+#define DFM 0xFFFF /* Data Field Mask (If Enabled) (CAN_AMxxL) */
+#define EXTID_LO 0xFFFF /* Lower 16 Bits of Extended Identifier (CAN_AMxxL) */
+#define EXTID_HI 0x0003 /* Upper 2 Bits of Extended Identifier (CAN_AMxxH) */
+#define BASEID 0x1FFC /* Base Identifier */
+#define AMIDE 0x2000 /* Acceptance Mask ID Extension Enable */
+#define FMD 0x4000 /* Full Mask Data Field Enable */
+#define FDF 0x8000 /* Filter On Data Field Enable */
+
+/* CAN_MC1 Masks */
+#define MC0 0x0001 /* Enable Mailbox 0 */
+#define MC1 0x0002 /* Enable Mailbox 1 */
+#define MC2 0x0004 /* Enable Mailbox 2 */
+#define MC3 0x0008 /* Enable Mailbox 3 */
+#define MC4 0x0010 /* Enable Mailbox 4 */
+#define MC5 0x0020 /* Enable Mailbox 5 */
+#define MC6 0x0040 /* Enable Mailbox 6 */
+#define MC7 0x0080 /* Enable Mailbox 7 */
+#define MC8 0x0100 /* Enable Mailbox 8 */
+#define MC9 0x0200 /* Enable Mailbox 9 */
+#define MC10 0x0400 /* Enable Mailbox 10 */
+#define MC11 0x0800 /* Enable Mailbox 11 */
+#define MC12 0x1000 /* Enable Mailbox 12 */
+#define MC13 0x2000 /* Enable Mailbox 13 */
+#define MC14 0x4000 /* Enable Mailbox 14 */
+#define MC15 0x8000 /* Enable Mailbox 15 */
+
+/* CAN_MC2 Masks */
+#define MC16 0x0001 /* Enable Mailbox 16 */
+#define MC17 0x0002 /* Enable Mailbox 17 */
+#define MC18 0x0004 /* Enable Mailbox 18 */
+#define MC19 0x0008 /* Enable Mailbox 19 */
+#define MC20 0x0010 /* Enable Mailbox 20 */
+#define MC21 0x0020 /* Enable Mailbox 21 */
+#define MC22 0x0040 /* Enable Mailbox 22 */
+#define MC23 0x0080 /* Enable Mailbox 23 */
+#define MC24 0x0100 /* Enable Mailbox 24 */
+#define MC25 0x0200 /* Enable Mailbox 25 */
+#define MC26 0x0400 /* Enable Mailbox 26 */
+#define MC27 0x0800 /* Enable Mailbox 27 */
+#define MC28 0x1000 /* Enable Mailbox 28 */
+#define MC29 0x2000 /* Enable Mailbox 29 */
+#define MC30 0x4000 /* Enable Mailbox 30 */
+#define MC31 0x8000 /* Enable Mailbox 31 */
+
+/* CAN_MD1 Masks */
+#define MD0 0x0001 /* Enable Mailbox 0 For Receive */
+#define MD1 0x0002 /* Enable Mailbox 1 For Receive */
+#define MD2 0x0004 /* Enable Mailbox 2 For Receive */
+#define MD3 0x0008 /* Enable Mailbox 3 For Receive */
+#define MD4 0x0010 /* Enable Mailbox 4 For Receive */
+#define MD5 0x0020 /* Enable Mailbox 5 For Receive */
+#define MD6 0x0040 /* Enable Mailbox 6 For Receive */
+#define MD7 0x0080 /* Enable Mailbox 7 For Receive */
+#define MD8 0x0100 /* Enable Mailbox 8 For Receive */
+#define MD9 0x0200 /* Enable Mailbox 9 For Receive */
+#define MD10 0x0400 /* Enable Mailbox 10 For Receive */
+#define MD11 0x0800 /* Enable Mailbox 11 For Receive */
+#define MD12 0x1000 /* Enable Mailbox 12 For Receive */
+#define MD13 0x2000 /* Enable Mailbox 13 For Receive */
+#define MD14 0x4000 /* Enable Mailbox 14 For Receive */
+#define MD15 0x8000 /* Enable Mailbox 15 For Receive */
+
+/* CAN_MD2 Masks */
+#define MD16 0x0001 /* Enable Mailbox 16 For Receive */
+#define MD17 0x0002 /* Enable Mailbox 17 For Receive */
+#define MD18 0x0004 /* Enable Mailbox 18 For Receive */
+#define MD19 0x0008 /* Enable Mailbox 19 For Receive */
+#define MD20 0x0010 /* Enable Mailbox 20 For Receive */
+#define MD21 0x0020 /* Enable Mailbox 21 For Receive */
+#define MD22 0x0040 /* Enable Mailbox 22 For Receive */
+#define MD23 0x0080 /* Enable Mailbox 23 For Receive */
+#define MD24 0x0100 /* Enable Mailbox 24 For Receive */
+#define MD25 0x0200 /* Enable Mailbox 25 For Receive */
+#define MD26 0x0400 /* Enable Mailbox 26 For Receive */
+#define MD27 0x0800 /* Enable Mailbox 27 For Receive */
+#define MD28 0x1000 /* Enable Mailbox 28 For Receive */
+#define MD29 0x2000 /* Enable Mailbox 29 For Receive */
+#define MD30 0x4000 /* Enable Mailbox 30 For Receive */
+#define MD31 0x8000 /* Enable Mailbox 31 For Receive */
+
+/* CAN_RMP1 Masks */
+#define RMP0 0x0001 /* RX Message Pending In Mailbox 0 */
+#define RMP1 0x0002 /* RX Message Pending In Mailbox 1 */
+#define RMP2 0x0004 /* RX Message Pending In Mailbox 2 */
+#define RMP3 0x0008 /* RX Message Pending In Mailbox 3 */
+#define RMP4 0x0010 /* RX Message Pending In Mailbox 4 */
+#define RMP5 0x0020 /* RX Message Pending In Mailbox 5 */
+#define RMP6 0x0040 /* RX Message Pending In Mailbox 6 */
+#define RMP7 0x0080 /* RX Message Pending In Mailbox 7 */
+#define RMP8 0x0100 /* RX Message Pending In Mailbox 8 */
+#define RMP9 0x0200 /* RX Message Pending In Mailbox 9 */
+#define RMP10 0x0400 /* RX Message Pending In Mailbox 10 */
+#define RMP11 0x0800 /* RX Message Pending In Mailbox 11 */
+#define RMP12 0x1000 /* RX Message Pending In Mailbox 12 */
+#define RMP13 0x2000 /* RX Message Pending In Mailbox 13 */
+#define RMP14 0x4000 /* RX Message Pending In Mailbox 14 */
+#define RMP15 0x8000 /* RX Message Pending In Mailbox 15 */
+
+/* CAN_RMP2 Masks */
+#define RMP16 0x0001 /* RX Message Pending In Mailbox 16 */
+#define RMP17 0x0002 /* RX Message Pending In Mailbox 17 */
+#define RMP18 0x0004 /* RX Message Pending In Mailbox 18 */
+#define RMP19 0x0008 /* RX Message Pending In Mailbox 19 */
+#define RMP20 0x0010 /* RX Message Pending In Mailbox 20 */
+#define RMP21 0x0020 /* RX Message Pending In Mailbox 21 */
+#define RMP22 0x0040 /* RX Message Pending In Mailbox 22 */
+#define RMP23 0x0080 /* RX Message Pending In Mailbox 23 */
+#define RMP24 0x0100 /* RX Message Pending In Mailbox 24 */
+#define RMP25 0x0200 /* RX Message Pending In Mailbox 25 */
+#define RMP26 0x0400 /* RX Message Pending In Mailbox 26 */
+#define RMP27 0x0800 /* RX Message Pending In Mailbox 27 */
+#define RMP28 0x1000 /* RX Message Pending In Mailbox 28 */
+#define RMP29 0x2000 /* RX Message Pending In Mailbox 29 */
+#define RMP30 0x4000 /* RX Message Pending In Mailbox 30 */
+#define RMP31 0x8000 /* RX Message Pending In Mailbox 31 */
+
+/* CAN_RML1 Masks */
+#define RML0 0x0001 /* RX Message Lost In Mailbox 0 */
+#define RML1 0x0002 /* RX Message Lost In Mailbox 1 */
+#define RML2 0x0004 /* RX Message Lost In Mailbox 2 */
+#define RML3 0x0008 /* RX Message Lost In Mailbox 3 */
+#define RML4 0x0010 /* RX Message Lost In Mailbox 4 */
+#define RML5 0x0020 /* RX Message Lost In Mailbox 5 */
+#define RML6 0x0040 /* RX Message Lost In Mailbox 6 */
+#define RML7 0x0080 /* RX Message Lost In Mailbox 7 */
+#define RML8 0x0100 /* RX Message Lost In Mailbox 8 */
+#define RML9 0x0200 /* RX Message Lost In Mailbox 9 */
+#define RML10 0x0400 /* RX Message Lost In Mailbox 10 */
+#define RML11 0x0800 /* RX Message Lost In Mailbox 11 */
+#define RML12 0x1000 /* RX Message Lost In Mailbox 12 */
+#define RML13 0x2000 /* RX Message Lost In Mailbox 13 */
+#define RML14 0x4000 /* RX Message Lost In Mailbox 14 */
+#define RML15 0x8000 /* RX Message Lost In Mailbox 15 */
+
+/* CAN_RML2 Masks */
+#define RML16 0x0001 /* RX Message Lost In Mailbox 16 */
+#define RML17 0x0002 /* RX Message Lost In Mailbox 17 */
+#define RML18 0x0004 /* RX Message Lost In Mailbox 18 */
+#define RML19 0x0008 /* RX Message Lost In Mailbox 19 */
+#define RML20 0x0010 /* RX Message Lost In Mailbox 20 */
+#define RML21 0x0020 /* RX Message Lost In Mailbox 21 */
+#define RML22 0x0040 /* RX Message Lost In Mailbox 22 */
+#define RML23 0x0080 /* RX Message Lost In Mailbox 23 */
+#define RML24 0x0100 /* RX Message Lost In Mailbox 24 */
+#define RML25 0x0200 /* RX Message Lost In Mailbox 25 */
+#define RML26 0x0400 /* RX Message Lost In Mailbox 26 */
+#define RML27 0x0800 /* RX Message Lost In Mailbox 27 */
+#define RML28 0x1000 /* RX Message Lost In Mailbox 28 */
+#define RML29 0x2000 /* RX Message Lost In Mailbox 29 */
+#define RML30 0x4000 /* RX Message Lost In Mailbox 30 */
+#define RML31 0x8000 /* RX Message Lost In Mailbox 31 */
+
+/* CAN_OPSS1 Masks */
+#define OPSS0 0x0001 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 0 */
+#define OPSS1 0x0002 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 1 */
+#define OPSS2 0x0004 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 2 */
+#define OPSS3 0x0008 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 3 */
+#define OPSS4 0x0010 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 4 */
+#define OPSS5 0x0020 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 5 */
+#define OPSS6 0x0040 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 6 */
+#define OPSS7 0x0080 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 7 */
+#define OPSS8 0x0100 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 8 */
+#define OPSS9 0x0200 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 9 */
+#define OPSS10 0x0400 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 10 */
+#define OPSS11 0x0800 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 11 */
+#define OPSS12 0x1000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 12 */
+#define OPSS13 0x2000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 13 */
+#define OPSS14 0x4000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 14 */
+#define OPSS15 0x8000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 15 */
+
+/* CAN_OPSS2 Masks */
+#define OPSS16 0x0001 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 16 */
+#define OPSS17 0x0002 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 17 */
+#define OPSS18 0x0004 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 18 */
+#define OPSS19 0x0008 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 19 */
+#define OPSS20 0x0010 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 20 */
+#define OPSS21 0x0020 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 21 */
+#define OPSS22 0x0040 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 22 */
+#define OPSS23 0x0080 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 23 */
+#define OPSS24 0x0100 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 24 */
+#define OPSS25 0x0200 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 25 */
+#define OPSS26 0x0400 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 26 */
+#define OPSS27 0x0800 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 27 */
+#define OPSS28 0x1000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 28 */
+#define OPSS29 0x2000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 29 */
+#define OPSS30 0x4000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 30 */
+#define OPSS31 0x8000 /* Enable RX Overwrite Protection or TX Single-Shot For Mailbox 31 */
+
+/* CAN_TRR1 Masks */
+#define TRR0 0x0001 /* Deny But Don't Lock Access To Mailbox 0 */
+#define TRR1 0x0002 /* Deny But Don't Lock Access To Mailbox 1 */
+#define TRR2 0x0004 /* Deny But Don't Lock Access To Mailbox 2 */
+#define TRR3 0x0008 /* Deny But Don't Lock Access To Mailbox 3 */
+#define TRR4 0x0010 /* Deny But Don't Lock Access To Mailbox 4 */
+#define TRR5 0x0020 /* Deny But Don't Lock Access To Mailbox 5 */
+#define TRR6 0x0040 /* Deny But Don't Lock Access To Mailbox 6 */
+#define TRR7 0x0080 /* Deny But Don't Lock Access To Mailbox 7 */
+#define TRR8 0x0100 /* Deny But Don't Lock Access To Mailbox 8 */
+#define TRR9 0x0200 /* Deny But Don't Lock Access To Mailbox 9 */
+#define TRR10 0x0400 /* Deny But Don't Lock Access To Mailbox 10 */
+#define TRR11 0x0800 /* Deny But Don't Lock Access To Mailbox 11 */
+#define TRR12 0x1000 /* Deny But Don't Lock Access To Mailbox 12 */
+#define TRR13 0x2000 /* Deny But Don't Lock Access To Mailbox 13 */
+#define TRR14 0x4000 /* Deny But Don't Lock Access To Mailbox 14 */
+#define TRR15 0x8000 /* Deny But Don't Lock Access To Mailbox 15 */
+
+/* CAN_TRR2 Masks */
+#define TRR16 0x0001 /* Deny But Don't Lock Access To Mailbox 16 */
+#define TRR17 0x0002 /* Deny But Don't Lock Access To Mailbox 17 */
+#define TRR18 0x0004 /* Deny But Don't Lock Access To Mailbox 18 */
+#define TRR19 0x0008 /* Deny But Don't Lock Access To Mailbox 19 */
+#define TRR20 0x0010 /* Deny But Don't Lock Access To Mailbox 20 */
+#define TRR21 0x0020 /* Deny But Don't Lock Access To Mailbox 21 */
+#define TRR22 0x0040 /* Deny But Don't Lock Access To Mailbox 22 */
+#define TRR23 0x0080 /* Deny But Don't Lock Access To Mailbox 23 */
+#define TRR24 0x0100 /* Deny But Don't Lock Access To Mailbox 24 */
+#define TRR25 0x0200 /* Deny But Don't Lock Access To Mailbox 25 */
+#define TRR26 0x0400 /* Deny But Don't Lock Access To Mailbox 26 */
+#define TRR27 0x0800 /* Deny But Don't Lock Access To Mailbox 27 */
+#define TRR28 0x1000 /* Deny But Don't Lock Access To Mailbox 28 */
+#define TRR29 0x2000 /* Deny But Don't Lock Access To Mailbox 29 */
+#define TRR30 0x4000 /* Deny But Don't Lock Access To Mailbox 30 */
+#define TRR31 0x8000 /* Deny But Don't Lock Access To Mailbox 31 */
+
+/* CAN_TRS1 Masks */
+#define TRS0 0x0001 /* Remote Frame Request For Mailbox 0 */
+#define TRS1 0x0002 /* Remote Frame Request For Mailbox 1 */
+#define TRS2 0x0004 /* Remote Frame Request For Mailbox 2 */
+#define TRS3 0x0008 /* Remote Frame Request For Mailbox 3 */
+#define TRS4 0x0010 /* Remote Frame Request For Mailbox 4 */
+#define TRS5 0x0020 /* Remote Frame Request For Mailbox 5 */
+#define TRS6 0x0040 /* Remote Frame Request For Mailbox 6 */
+#define TRS7 0x0080 /* Remote Frame Request For Mailbox 7 */
+#define TRS8 0x0100 /* Remote Frame Request For Mailbox 8 */
+#define TRS9 0x0200 /* Remote Frame Request For Mailbox 9 */
+#define TRS10 0x0400 /* Remote Frame Request For Mailbox 10 */
+#define TRS11 0x0800 /* Remote Frame Request For Mailbox 11 */
+#define TRS12 0x1000 /* Remote Frame Request For Mailbox 12 */
+#define TRS13 0x2000 /* Remote Frame Request For Mailbox 13 */
+#define TRS14 0x4000 /* Remote Frame Request For Mailbox 14 */
+#define TRS15 0x8000 /* Remote Frame Request For Mailbox 15 */
+
+/* CAN_TRS2 Masks */
+#define TRS16 0x0001 /* Remote Frame Request For Mailbox 16 */
+#define TRS17 0x0002 /* Remote Frame Request For Mailbox 17 */
+#define TRS18 0x0004 /* Remote Frame Request For Mailbox 18 */
+#define TRS19 0x0008 /* Remote Frame Request For Mailbox 19 */
+#define TRS20 0x0010 /* Remote Frame Request For Mailbox 20 */
+#define TRS21 0x0020 /* Remote Frame Request For Mailbox 21 */
+#define TRS22 0x0040 /* Remote Frame Request For Mailbox 22 */
+#define TRS23 0x0080 /* Remote Frame Request For Mailbox 23 */
+#define TRS24 0x0100 /* Remote Frame Request For Mailbox 24 */
+#define TRS25 0x0200 /* Remote Frame Request For Mailbox 25 */
+#define TRS26 0x0400 /* Remote Frame Request For Mailbox 26 */
+#define TRS27 0x0800 /* Remote Frame Request For Mailbox 27 */
+#define TRS28 0x1000 /* Remote Frame Request For Mailbox 28 */
+#define TRS29 0x2000 /* Remote Frame Request For Mailbox 29 */
+#define TRS30 0x4000 /* Remote Frame Request For Mailbox 30 */
+#define TRS31 0x8000 /* Remote Frame Request For Mailbox 31 */
+
+/* CAN_AA1 Masks */
+#define AA0 0x0001 /* Aborted Message In Mailbox 0 */
+#define AA1 0x0002 /* Aborted Message In Mailbox 1 */
+#define AA2 0x0004 /* Aborted Message In Mailbox 2 */
+#define AA3 0x0008 /* Aborted Message In Mailbox 3 */
+#define AA4 0x0010 /* Aborted Message In Mailbox 4 */
+#define AA5 0x0020 /* Aborted Message In Mailbox 5 */
+#define AA6 0x0040 /* Aborted Message In Mailbox 6 */
+#define AA7 0x0080 /* Aborted Message In Mailbox 7 */
+#define AA8 0x0100 /* Aborted Message In Mailbox 8 */
+#define AA9 0x0200 /* Aborted Message In Mailbox 9 */
+#define AA10 0x0400 /* Aborted Message In Mailbox 10 */
+#define AA11 0x0800 /* Aborted Message In Mailbox 11 */
+#define AA12 0x1000 /* Aborted Message In Mailbox 12 */
+#define AA13 0x2000 /* Aborted Message In Mailbox 13 */
+#define AA14 0x4000 /* Aborted Message In Mailbox 14 */
+#define AA15 0x8000 /* Aborted Message In Mailbox 15 */
+
+/* CAN_AA2 Masks */
+#define AA16 0x0001 /* Aborted Message In Mailbox 16 */
+#define AA17 0x0002 /* Aborted Message In Mailbox 17 */
+#define AA18 0x0004 /* Aborted Message In Mailbox 18 */
+#define AA19 0x0008 /* Aborted Message In Mailbox 19 */
+#define AA20 0x0010 /* Aborted Message In Mailbox 20 */
+#define AA21 0x0020 /* Aborted Message In Mailbox 21 */
+#define AA22 0x0040 /* Aborted Message In Mailbox 22 */
+#define AA23 0x0080 /* Aborted Message In Mailbox 23 */
+#define AA24 0x0100 /* Aborted Message In Mailbox 24 */
+#define AA25 0x0200 /* Aborted Message In Mailbox 25 */
+#define AA26 0x0400 /* Aborted Message In Mailbox 26 */
+#define AA27 0x0800 /* Aborted Message In Mailbox 27 */
+#define AA28 0x1000 /* Aborted Message In Mailbox 28 */
+#define AA29 0x2000 /* Aborted Message In Mailbox 29 */
+#define AA30 0x4000 /* Aborted Message In Mailbox 30 */
+#define AA31 0x8000 /* Aborted Message In Mailbox 31 */
+
+/* CAN_TA1 Masks */
+#define TA0 0x0001 /* Transmit Successful From Mailbox 0 */
+#define TA1 0x0002 /* Transmit Successful From Mailbox 1 */
+#define TA2 0x0004 /* Transmit Successful From Mailbox 2 */
+#define TA3 0x0008 /* Transmit Successful From Mailbox 3 */
+#define TA4 0x0010 /* Transmit Successful From Mailbox 4 */
+#define TA5 0x0020 /* Transmit Successful From Mailbox 5 */
+#define TA6 0x0040 /* Transmit Successful From Mailbox 6 */
+#define TA7 0x0080 /* Transmit Successful From Mailbox 7 */
+#define TA8 0x0100 /* Transmit Successful From Mailbox 8 */
+#define TA9 0x0200 /* Transmit Successful From Mailbox 9 */
+#define TA10 0x0400 /* Transmit Successful From Mailbox 10 */
+#define TA11 0x0800 /* Transmit Successful From Mailbox 11 */
+#define TA12 0x1000 /* Transmit Successful From Mailbox 12 */
+#define TA13 0x2000 /* Transmit Successful From Mailbox 13 */
+#define TA14 0x4000 /* Transmit Successful From Mailbox 14 */
+#define TA15 0x8000 /* Transmit Successful From Mailbox 15 */
+
+/* CAN_TA2 Masks */
+#define TA16 0x0001 /* Transmit Successful From Mailbox 16 */
+#define TA17 0x0002 /* Transmit Successful From Mailbox 17 */
+#define TA18 0x0004 /* Transmit Successful From Mailbox 18 */
+#define TA19 0x0008 /* Transmit Successful From Mailbox 19 */
+#define TA20 0x0010 /* Transmit Successful From Mailbox 20 */
+#define TA21 0x0020 /* Transmit Successful From Mailbox 21 */
+#define TA22 0x0040 /* Transmit Successful From Mailbox 22 */
+#define TA23 0x0080 /* Transmit Successful From Mailbox 23 */
+#define TA24 0x0100 /* Transmit Successful From Mailbox 24 */
+#define TA25 0x0200 /* Transmit Successful From Mailbox 25 */
+#define TA26 0x0400 /* Transmit Successful From Mailbox 26 */
+#define TA27 0x0800 /* Transmit Successful From Mailbox 27 */
+#define TA28 0x1000 /* Transmit Successful From Mailbox 28 */
+#define TA29 0x2000 /* Transmit Successful From Mailbox 29 */
+#define TA30 0x4000 /* Transmit Successful From Mailbox 30 */
+#define TA31 0x8000 /* Transmit Successful From Mailbox 31 */
+
+/* CAN_MBTD Masks */
+#define TDPTR 0x001F /* Mailbox To Temporarily Disable */
+#define TDA 0x0040 /* Temporary Disable Acknowledge */
+#define TDR 0x0080 /* Temporary Disable Request */
+
+/* CAN_RFH1 Masks */
+#define RFH0 0x0001 /* Enable Automatic Remote Frame Handling For Mailbox 0 */
+#define RFH1 0x0002 /* Enable Automatic Remote Frame Handling For Mailbox 1 */
+#define RFH2 0x0004 /* Enable Automatic Remote Frame Handling For Mailbox 2 */
+#define RFH3 0x0008 /* Enable Automatic Remote Frame Handling For Mailbox 3 */
+#define RFH4 0x0010 /* Enable Automatic Remote Frame Handling For Mailbox 4 */
+#define RFH5 0x0020 /* Enable Automatic Remote Frame Handling For Mailbox 5 */
+#define RFH6 0x0040 /* Enable Automatic Remote Frame Handling For Mailbox 6 */
+#define RFH7 0x0080 /* Enable Automatic Remote Frame Handling For Mailbox 7 */
+#define RFH8 0x0100 /* Enable Automatic Remote Frame Handling For Mailbox 8 */
+#define RFH9 0x0200 /* Enable Automatic Remote Frame Handling For Mailbox 9 */
+#define RFH10 0x0400 /* Enable Automatic Remote Frame Handling For Mailbox 10 */
+#define RFH11 0x0800 /* Enable Automatic Remote Frame Handling For Mailbox 11 */
+#define RFH12 0x1000 /* Enable Automatic Remote Frame Handling For Mailbox 12 */
+#define RFH13 0x2000 /* Enable Automatic Remote Frame Handling For Mailbox 13 */
+#define RFH14 0x4000 /* Enable Automatic Remote Frame Handling For Mailbox 14 */
+#define RFH15 0x8000 /* Enable Automatic Remote Frame Handling For Mailbox 15 */
+
+/* CAN_RFH2 Masks */
+#define RFH16 0x0001 /* Enable Automatic Remote Frame Handling For Mailbox 16 */
+#define RFH17 0x0002 /* Enable Automatic Remote Frame Handling For Mailbox 17 */
+#define RFH18 0x0004 /* Enable Automatic Remote Frame Handling For Mailbox 18 */
+#define RFH19 0x0008 /* Enable Automatic Remote Frame Handling For Mailbox 19 */
+#define RFH20 0x0010 /* Enable Automatic Remote Frame Handling For Mailbox 20 */
+#define RFH21 0x0020 /* Enable Automatic Remote Frame Handling For Mailbox 21 */
+#define RFH22 0x0040 /* Enable Automatic Remote Frame Handling For Mailbox 22 */
+#define RFH23 0x0080 /* Enable Automatic Remote Frame Handling For Mailbox 23 */
+#define RFH24 0x0100 /* Enable Automatic Remote Frame Handling For Mailbox 24 */
+#define RFH25 0x0200 /* Enable Automatic Remote Frame Handling For Mailbox 25 */
+#define RFH26 0x0400 /* Enable Automatic Remote Frame Handling For Mailbox 26 */
+#define RFH27 0x0800 /* Enable Automatic Remote Frame Handling For Mailbox 27 */
+#define RFH28 0x1000 /* Enable Automatic Remote Frame Handling For Mailbox 28 */
+#define RFH29 0x2000 /* Enable Automatic Remote Frame Handling For Mailbox 29 */
+#define RFH30 0x4000 /* Enable Automatic Remote Frame Handling For Mailbox 30 */
+#define RFH31 0x8000 /* Enable Automatic Remote Frame Handling For Mailbox 31 */
+
+/* CAN_MBTIF1 Masks */
+#define MBTIF0 0x0001 /* TX Interrupt Active In Mailbox 0 */
+#define MBTIF1 0x0002 /* TX Interrupt Active In Mailbox 1 */
+#define MBTIF2 0x0004 /* TX Interrupt Active In Mailbox 2 */
+#define MBTIF3 0x0008 /* TX Interrupt Active In Mailbox 3 */
+#define MBTIF4 0x0010 /* TX Interrupt Active In Mailbox 4 */
+#define MBTIF5 0x0020 /* TX Interrupt Active In Mailbox 5 */
+#define MBTIF6 0x0040 /* TX Interrupt Active In Mailbox 6 */
+#define MBTIF7 0x0080 /* TX Interrupt Active In Mailbox 7 */
+#define MBTIF8 0x0100 /* TX Interrupt Active In Mailbox 8 */
+#define MBTIF9 0x0200 /* TX Interrupt Active In Mailbox 9 */
+#define MBTIF10 0x0400 /* TX Interrupt Active In Mailbox 10 */
+#define MBTIF11 0x0800 /* TX Interrupt Active In Mailbox 11 */
+#define MBTIF12 0x1000 /* TX Interrupt Active In Mailbox 12 */
+#define MBTIF13 0x2000 /* TX Interrupt Active In Mailbox 13 */
+#define MBTIF14 0x4000 /* TX Interrupt Active In Mailbox 14 */
+#define MBTIF15 0x8000 /* TX Interrupt Active In Mailbox 15 */
+
+/* CAN_MBTIF2 Masks */
+#define MBTIF16 0x0001 /* TX Interrupt Active In Mailbox 16 */
+#define MBTIF17 0x0002 /* TX Interrupt Active In Mailbox 17 */
+#define MBTIF18 0x0004 /* TX Interrupt Active In Mailbox 18 */
+#define MBTIF19 0x0008 /* TX Interrupt Active In Mailbox 19 */
+#define MBTIF20 0x0010 /* TX Interrupt Active In Mailbox 20 */
+#define MBTIF21 0x0020 /* TX Interrupt Active In Mailbox 21 */
+#define MBTIF22 0x0040 /* TX Interrupt Active In Mailbox 22 */
+#define MBTIF23 0x0080 /* TX Interrupt Active In Mailbox 23 */
+#define MBTIF24 0x0100 /* TX Interrupt Active In Mailbox 24 */
+#define MBTIF25 0x0200 /* TX Interrupt Active In Mailbox 25 */
+#define MBTIF26 0x0400 /* TX Interrupt Active In Mailbox 26 */
+#define MBTIF27 0x0800 /* TX Interrupt Active In Mailbox 27 */
+#define MBTIF28 0x1000 /* TX Interrupt Active In Mailbox 28 */
+#define MBTIF29 0x2000 /* TX Interrupt Active In Mailbox 29 */
+#define MBTIF30 0x4000 /* TX Interrupt Active In Mailbox 30 */
+#define MBTIF31 0x8000 /* TX Interrupt Active In Mailbox 31 */
+
+/* CAN_MBRIF1 Masks */
+#define MBRIF0 0x0001 /* RX Interrupt Active In Mailbox 0 */
+#define MBRIF1 0x0002 /* RX Interrupt Active In Mailbox 1 */
+#define MBRIF2 0x0004 /* RX Interrupt Active In Mailbox 2 */
+#define MBRIF3 0x0008 /* RX Interrupt Active In Mailbox 3 */
+#define MBRIF4 0x0010 /* RX Interrupt Active In Mailbox 4 */
+#define MBRIF5 0x0020 /* RX Interrupt Active In Mailbox 5 */
+#define MBRIF6 0x0040 /* RX Interrupt Active In Mailbox 6 */
+#define MBRIF7 0x0080 /* RX Interrupt Active In Mailbox 7 */
+#define MBRIF8 0x0100 /* RX Interrupt Active In Mailbox 8 */
+#define MBRIF9 0x0200 /* RX Interrupt Active In Mailbox 9 */
+#define MBRIF10 0x0400 /* RX Interrupt Active In Mailbox 10 */
+#define MBRIF11 0x0800 /* RX Interrupt Active In Mailbox 11 */
+#define MBRIF12 0x1000 /* RX Interrupt Active In Mailbox 12 */
+#define MBRIF13 0x2000 /* RX Interrupt Active In Mailbox 13 */
+#define MBRIF14 0x4000 /* RX Interrupt Active In Mailbox 14 */
+#define MBRIF15 0x8000 /* RX Interrupt Active In Mailbox 15 */
+
+/* CAN_MBRIF2 Masks */
+#define MBRIF16 0x0001 /* RX Interrupt Active In Mailbox 16 */
+#define MBRIF17 0x0002 /* RX Interrupt Active In Mailbox 17 */
+#define MBRIF18 0x0004 /* RX Interrupt Active In Mailbox 18 */
+#define MBRIF19 0x0008 /* RX Interrupt Active In Mailbox 19 */
+#define MBRIF20 0x0010 /* RX Interrupt Active In Mailbox 20 */
+#define MBRIF21 0x0020 /* RX Interrupt Active In Mailbox 21 */
+#define MBRIF22 0x0040 /* RX Interrupt Active In Mailbox 22 */
+#define MBRIF23 0x0080 /* RX Interrupt Active In Mailbox 23 */
+#define MBRIF24 0x0100 /* RX Interrupt Active In Mailbox 24 */
+#define MBRIF25 0x0200 /* RX Interrupt Active In Mailbox 25 */
+#define MBRIF26 0x0400 /* RX Interrupt Active In Mailbox 26 */
+#define MBRIF27 0x0800 /* RX Interrupt Active In Mailbox 27 */
+#define MBRIF28 0x1000 /* RX Interrupt Active In Mailbox 28 */
+#define MBRIF29 0x2000 /* RX Interrupt Active In Mailbox 29 */
+#define MBRIF30 0x4000 /* RX Interrupt Active In Mailbox 30 */
+#define MBRIF31 0x8000 /* RX Interrupt Active In Mailbox 31 */
+
+/* CAN_MBIM1 Masks */
+#define MBIM0 0x0001 /* Enable Interrupt For Mailbox 0 */
+#define MBIM1 0x0002 /* Enable Interrupt For Mailbox 1 */
+#define MBIM2 0x0004 /* Enable Interrupt For Mailbox 2 */
+#define MBIM3 0x0008 /* Enable Interrupt For Mailbox 3 */
+#define MBIM4 0x0010 /* Enable Interrupt For Mailbox 4 */
+#define MBIM5 0x0020 /* Enable Interrupt For Mailbox 5 */
+#define MBIM6 0x0040 /* Enable Interrupt For Mailbox 6 */
+#define MBIM7 0x0080 /* Enable Interrupt For Mailbox 7 */
+#define MBIM8 0x0100 /* Enable Interrupt For Mailbox 8 */
+#define MBIM9 0x0200 /* Enable Interrupt For Mailbox 9 */
+#define MBIM10 0x0400 /* Enable Interrupt For Mailbox 10 */
+#define MBIM11 0x0800 /* Enable Interrupt For Mailbox 11 */
+#define MBIM12 0x1000 /* Enable Interrupt For Mailbox 12 */
+#define MBIM13 0x2000 /* Enable Interrupt For Mailbox 13 */
+#define MBIM14 0x4000 /* Enable Interrupt For Mailbox 14 */
+#define MBIM15 0x8000 /* Enable Interrupt For Mailbox 15 */
+
+/* CAN_MBIM2 Masks */
+#define MBIM16 0x0001 /* Enable Interrupt For Mailbox 16 */
+#define MBIM17 0x0002 /* Enable Interrupt For Mailbox 17 */
+#define MBIM18 0x0004 /* Enable Interrupt For Mailbox 18 */
+#define MBIM19 0x0008 /* Enable Interrupt For Mailbox 19 */
+#define MBIM20 0x0010 /* Enable Interrupt For Mailbox 20 */
+#define MBIM21 0x0020 /* Enable Interrupt For Mailbox 21 */
+#define MBIM22 0x0040 /* Enable Interrupt For Mailbox 22 */
+#define MBIM23 0x0080 /* Enable Interrupt For Mailbox 23 */
+#define MBIM24 0x0100 /* Enable Interrupt For Mailbox 24 */
+#define MBIM25 0x0200 /* Enable Interrupt For Mailbox 25 */
+#define MBIM26 0x0400 /* Enable Interrupt For Mailbox 26 */
+#define MBIM27 0x0800 /* Enable Interrupt For Mailbox 27 */
+#define MBIM28 0x1000 /* Enable Interrupt For Mailbox 28 */
+#define MBIM29 0x2000 /* Enable Interrupt For Mailbox 29 */
+#define MBIM30 0x4000 /* Enable Interrupt For Mailbox 30 */
+#define MBIM31 0x8000 /* Enable Interrupt For Mailbox 31 */
+
+/* CAN_GIM Masks */
+#define EWTIM 0x0001 /* Enable TX Error Count Interrupt */
+#define EWRIM 0x0002 /* Enable RX Error Count Interrupt */
+#define EPIM 0x0004 /* Enable Error-Passive Mode Interrupt */
+#define BOIM 0x0008 /* Enable Bus Off Interrupt */
+#define WUIM 0x0010 /* Enable Wake-Up Interrupt */
+#define UIAIM 0x0020 /* Enable Access To Unimplemented Address Interrupt */
+#define AAIM 0x0040 /* Enable Abort Acknowledge Interrupt */
+#define RMLIM 0x0080 /* Enable RX Message Lost Interrupt */
+#define UCEIM 0x0100 /* Enable Universal Counter Overflow Interrupt */
+#define EXTIM 0x0200 /* Enable External Trigger Output Interrupt */
+#define ADIM 0x0400 /* Enable Access Denied Interrupt */
+
+/* CAN_GIS Masks */
+#define EWTIS 0x0001 /* TX Error Count IRQ Status */
+#define EWRIS 0x0002 /* RX Error Count IRQ Status */
+#define EPIS 0x0004 /* Error-Passive Mode IRQ Status */
+#define BOIS 0x0008 /* Bus Off IRQ Status */
+#define WUIS 0x0010 /* Wake-Up IRQ Status */
+#define UIAIS 0x0020 /* Access To Unimplemented Address IRQ Status */
+#define AAIS 0x0040 /* Abort Acknowledge IRQ Status */
+#define RMLIS 0x0080 /* RX Message Lost IRQ Status */
+#define UCEIS 0x0100 /* Universal Counter Overflow IRQ Status */
+#define EXTIS 0x0200 /* External Trigger Output IRQ Status */
+#define ADIS 0x0400 /* Access Denied IRQ Status */
+
+/* CAN_GIF Masks */
+#define EWTIF 0x0001 /* TX Error Count IRQ Flag */
+#define EWRIF 0x0002 /* RX Error Count IRQ Flag */
+#define EPIF 0x0004 /* Error-Passive Mode IRQ Flag */
+#define BOIF 0x0008 /* Bus Off IRQ Flag */
+#define WUIF 0x0010 /* Wake-Up IRQ Flag */
+#define UIAIF 0x0020 /* Access To Unimplemented Address IRQ Flag */
+#define AAIF 0x0040 /* Abort Acknowledge IRQ Flag */
+#define RMLIF 0x0080 /* RX Message Lost IRQ Flag */
+#define UCEIF 0x0100 /* Universal Counter Overflow IRQ Flag */
+#define EXTIF 0x0200 /* External Trigger Output IRQ Flag */
+#define ADIF 0x0400 /* Access Denied IRQ Flag */
+
+/* CAN_UCCNF Masks */
+#define UCCNF 0x000F /* Universal Counter Mode */
+#define UC_STAMP 0x0001 /* Timestamp Mode */
+#define UC_WDOG 0x0002 /* Watchdog Mode */
+#define UC_AUTOTX 0x0003 /* Auto-Transmit Mode */
+#define UC_ERROR 0x0006 /* CAN Error Frame Count */
+#define UC_OVER 0x0007 /* CAN Overload Frame Count */
+#define UC_LOST 0x0008 /* Arbitration Lost During TX Count */
+#define UC_AA 0x0009 /* TX Abort Count */
+#define UC_TA 0x000A /* TX Successful Count */
+#define UC_REJECT 0x000B /* RX Message Rejected Count */
+#define UC_RML 0x000C /* RX Message Lost Count */
+#define UC_RX 0x000D /* Total Successful RX Messages Count */
+#define UC_RMP 0x000E /* Successful RX W/Matching ID Count */
+#define UC_ALL 0x000F /* Correct Message On CAN Bus Line Count */
+#define UCRC 0x0020 /* Universal Counter Reload/Clear */
+#define UCCT 0x0040 /* Universal Counter CAN Trigger */
+#define UCE 0x0080 /* Universal Counter Enable */
+
+/* CAN_ESR Masks */
+#define ACKE 0x0004 /* Acknowledge Error */
+#define SER 0x0008 /* Stuff Error */
+#define CRCE 0x0010 /* CRC Error */
+#define SA0 0x0020 /* Stuck At Dominant Error */
+#define BEF 0x0040 /* Bit Error Flag */
+#define FER 0x0080 /* Form Error Flag */
+
+/* CAN_EWR Masks */
+#define EWLREC 0x00FF /* RX Error Count Limit (For EWRIS) */
+#define EWLTEC 0xFF00 /* TX Error Count Limit (For EWTIS) */
+
+/* ******************* PIN CONTROL REGISTER MASKS ************************/
+/* PORT_MUX Masks */
+#define PJSE 0x0001 /* Port J SPI/SPORT Enable */
+#define PJSE_SPORT 0x0000 /* Enable TFS0/DT0PRI */
+#define PJSE_SPI 0x0001 /* Enable SPI_SSEL3:2 */
+
+#define PJCE(x) (((x)&0x3)<<1) /* Port J CAN/SPI/SPORT Enable */
+#define PJCE_SPORT 0x0000 /* Enable DR0SEC/DT0SEC */
+#define PJCE_CAN 0x0002 /* Enable CAN RX/TX */
+#define PJCE_SPI 0x0004 /* Enable SPI_SSEL7 */
+
+#define PFDE 0x0008 /* Port F DMA Request Enable */
+#define PGDE_UART 0x0000 /* Enable UART0 RX/TX */
+#define PGDE_DMA 0x0008 /* Enable DMAR1:0 */
+
+#define PFTE 0x0010 /* Port F Timer Enable */
+#define PFTE_UART 0x0000 /* Enable UART1 RX/TX */
+#define PFTE_TIMER 0x0010 /* Enable TMR7:6 */
+
+#define PFS6E 0x0020 /* Port F SPI SSEL 6 Enable */
+#define PFS6E_TIMER 0x0000 /* Enable TMR5 */
+#define PFS6E_SPI 0x0020 /* Enable SPI_SSEL6 */
+
+#define PFS5E 0x0040 /* Port F SPI SSEL 5 Enable */
+#define PFS5E_TIMER 0x0000 /* Enable TMR4 */
+#define PFS5E_SPI 0x0040 /* Enable SPI_SSEL5 */
+
+#define PFS4E 0x0080 /* Port F SPI SSEL 4 Enable */
+#define PFS4E_TIMER 0x0000 /* Enable TMR3 */
+#define PFS4E_SPI 0x0080 /* Enable SPI_SSEL4 */
+
+#define PFFE 0x0100 /* Port F PPI Frame Sync Enable */
+#define PFFE_TIMER 0x0000 /* Enable TMR2 */
+#define PFFE_PPI 0x0100 /* Enable PPI FS3 */
+
+#define PGSE 0x0200 /* Port G SPORT1 Secondary Enable */
+#define PGSE_PPI 0x0000 /* Enable PPI D9:8 */
+#define PGSE_SPORT 0x0200 /* Enable DR1SEC/DT1SEC */
+
+#define PGRE 0x0400 /* Port G SPORT1 Receive Enable */
+#define PGRE_PPI 0x0000 /* Enable PPI D12:10 */
+#define PGRE_SPORT 0x0400 /* Enable DR1PRI/RFS1/RSCLK1 */
+
+#define PGTE 0x0800 /* Port G SPORT1 Transmit Enable */
+#define PGTE_PPI 0x0000 /* Enable PPI D15:13 */
+#define PGTE_SPORT 0x0800 /* Enable DT1PRI/TFS1/TSCLK1 */
+
+/* ****************** HANDSHAKE DMA (HDMA) MASKS *********************/
+/* HDMAx_CTL Masks */
+#define HMDMAEN 0x0001 /* Enable Handshake DMA 0/1 */
+#define REP 0x0002 /* HDMA Request Polarity */
+#define UTE 0x0004 /* Urgency Threshold Enable */
+#define OIE 0x0010 /* Overflow Interrupt Enable */
+#define BDIE 0x0020 /* Block Done Interrupt Enable */
+#define MBDI 0x0040 /* Mask Block Done IRQ If Pending ECNT */
+#define DRQ 0x0300 /* HDMA Request Type */
+#define DRQ_NONE 0x0000 /* No Request */
+#define DRQ_SINGLE 0x0100 /* Channels Request Single */
+#define DRQ_MULTI 0x0200 /* Channels Request Multi (Default) */
+#define DRQ_URGENT 0x0300 /* Channels Request Multi Urgent */
+#define RBC 0x1000 /* Reload BCNT With IBCNT */
+#define PS 0x2000 /* HDMA Pin Status */
+#define OI 0x4000 /* Overflow Interrupt Generated */
+#define BDI 0x8000 /* Block Done Interrupt Generated */
+
+#endif /* _DEF_BF534_H */
diff --git a/include/asm-blackfin/mach-bf537/defBF537.h b/include/asm-blackfin/mach-bf537/defBF537.h
new file mode 100644
index 00000000000..26f9c02eb73
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/defBF537.h
@@ -0,0 +1,404 @@
+/*
+ * file: include/asm-blackfin/mach-bf537/defbf537.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ * system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _DEF_BF537_H
+#define _DEF_BF537_H
+
+/*include all Core registers and bit definitions*/
+#include "defBF537.h"
+
+/*include core specific register pointer definitions*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+/************************************************************************************
+** Define EMAC Section Unique to BF536/BF537
+*************************************************************************************/
+
+/* 10/100 Ethernet Controller (0xFFC03000 - 0xFFC031FF) */
+#define EMAC_OPMODE 0xFFC03000 /* Operating Mode Register */
+#define EMAC_ADDRLO 0xFFC03004 /* Address Low (32 LSBs) Register */
+#define EMAC_ADDRHI 0xFFC03008 /* Address High (16 MSBs) Register */
+#define EMAC_HASHLO 0xFFC0300C /* Multicast Hash Table Low (Bins 31-0) Register */
+#define EMAC_HASHHI 0xFFC03010 /* Multicast Hash Table High (Bins 63-32) Register */
+#define EMAC_STAADD 0xFFC03014 /* Station Management Address Register */
+#define EMAC_STADAT 0xFFC03018 /* Station Management Data Register */
+#define EMAC_FLC 0xFFC0301C /* Flow Control Register */
+#define EMAC_VLAN1 0xFFC03020 /* VLAN1 Tag Register */
+#define EMAC_VLAN2 0xFFC03024 /* VLAN2 Tag Register */
+#define EMAC_WKUP_CTL 0xFFC0302C /* Wake-Up Control/Status Register */
+#define EMAC_WKUP_FFMSK0 0xFFC03030 /* Wake-Up Frame Filter 0 Byte Mask Register */
+#define EMAC_WKUP_FFMSK1 0xFFC03034 /* Wake-Up Frame Filter 1 Byte Mask Register */
+#define EMAC_WKUP_FFMSK2 0xFFC03038 /* Wake-Up Frame Filter 2 Byte Mask Register */
+#define EMAC_WKUP_FFMSK3 0xFFC0303C /* Wake-Up Frame Filter 3 Byte Mask Register */
+#define EMAC_WKUP_FFCMD 0xFFC03040 /* Wake-Up Frame Filter Commands Register */
+#define EMAC_WKUP_FFOFF 0xFFC03044 /* Wake-Up Frame Filter Offsets Register */
+#define EMAC_WKUP_FFCRC0 0xFFC03048 /* Wake-Up Frame Filter 0,1 CRC-16 Register */
+#define EMAC_WKUP_FFCRC1 0xFFC0304C /* Wake-Up Frame Filter 2,3 CRC-16 Register */
+
+#define EMAC_SYSCTL 0xFFC03060 /* EMAC System Control Register */
+#define EMAC_SYSTAT 0xFFC03064 /* EMAC System Status Register */
+#define EMAC_RX_STAT 0xFFC03068 /* RX Current Frame Status Register */
+#define EMAC_RX_STKY 0xFFC0306C /* RX Sticky Frame Status Register */
+#define EMAC_RX_IRQE 0xFFC03070 /* RX Frame Status Interrupt Enables Register */
+#define EMAC_TX_STAT 0xFFC03074 /* TX Current Frame Status Register */
+#define EMAC_TX_STKY 0xFFC03078 /* TX Sticky Frame Status Register */
+#define EMAC_TX_IRQE 0xFFC0307C /* TX Frame Status Interrupt Enables Register */
+
+#define EMAC_MMC_CTL 0xFFC03080 /* MMC Counter Control Register */
+#define EMAC_MMC_RIRQS 0xFFC03084 /* MMC RX Interrupt Status Register */
+#define EMAC_MMC_RIRQE 0xFFC03088 /* MMC RX Interrupt Enables Register */
+#define EMAC_MMC_TIRQS 0xFFC0308C /* MMC TX Interrupt Status Register */
+#define EMAC_MMC_TIRQE 0xFFC03090 /* MMC TX Interrupt Enables Register */
+
+#define EMAC_RXC_OK 0xFFC03100 /* RX Frame Successful Count */
+#define EMAC_RXC_FCS 0xFFC03104 /* RX Frame FCS Failure Count */
+#define EMAC_RXC_ALIGN 0xFFC03108 /* RX Alignment Error Count */
+#define EMAC_RXC_OCTET 0xFFC0310C /* RX Octets Successfully Received Count */
+#define EMAC_RXC_DMAOVF 0xFFC03110 /* Internal MAC Sublayer Error RX Frame Count */
+#define EMAC_RXC_UNICST 0xFFC03114 /* Unicast RX Frame Count */
+#define EMAC_RXC_MULTI 0xFFC03118 /* Multicast RX Frame Count */
+#define EMAC_RXC_BROAD 0xFFC0311C /* Broadcast RX Frame Count */
+#define EMAC_RXC_LNERRI 0xFFC03120 /* RX Frame In Range Error Count */
+#define EMAC_RXC_LNERRO 0xFFC03124 /* RX Frame Out Of Range Error Count */
+#define EMAC_RXC_LONG 0xFFC03128 /* RX Frame Too Long Count */
+#define EMAC_RXC_MACCTL 0xFFC0312C /* MAC Control RX Frame Count */
+#define EMAC_RXC_OPCODE 0xFFC03130 /* Unsupported Op-Code RX Frame Count */
+#define EMAC_RXC_PAUSE 0xFFC03134 /* MAC Control Pause RX Frame Count */
+#define EMAC_RXC_ALLFRM 0xFFC03138 /* Overall RX Frame Count */
+#define EMAC_RXC_ALLOCT 0xFFC0313C /* Overall RX Octet Count */
+#define EMAC_RXC_TYPED 0xFFC03140 /* Type/Length Consistent RX Frame Count */
+#define EMAC_RXC_SHORT 0xFFC03144 /* RX Frame Fragment Count - Byte Count x < 64 */
+#define EMAC_RXC_EQ64 0xFFC03148 /* Good RX Frame Count - Byte Count x = 64 */
+#define EMAC_RXC_LT128 0xFFC0314C /* Good RX Frame Count - Byte Count 64 <= x < 128 */
+#define EMAC_RXC_LT256 0xFFC03150 /* Good RX Frame Count - Byte Count 128 <= x < 256 */
+#define EMAC_RXC_LT512 0xFFC03154 /* Good RX Frame Count - Byte Count 256 <= x < 512 */
+#define EMAC_RXC_LT1024 0xFFC03158 /* Good RX Frame Count - Byte Count 512 <= x < 1024 */
+#define EMAC_RXC_GE1024 0xFFC0315C /* Good RX Frame Count - Byte Count x >= 1024 */
+
+#define EMAC_TXC_OK 0xFFC03180 /* TX Frame Successful Count */
+#define EMAC_TXC_1COL 0xFFC03184 /* TX Frames Successful After Single Collision Count */
+#define EMAC_TXC_GT1COL 0xFFC03188 /* TX Frames Successful After Multiple Collisions Count */
+#define EMAC_TXC_OCTET 0xFFC0318C /* TX Octets Successfully Received Count */
+#define EMAC_TXC_DEFER 0xFFC03190 /* TX Frame Delayed Due To Busy Count */
+#define EMAC_TXC_LATECL 0xFFC03194 /* Late TX Collisions Count */
+#define EMAC_TXC_XS_COL 0xFFC03198 /* TX Frame Failed Due To Excessive Collisions Count */
+#define EMAC_TXC_DMAUND 0xFFC0319C /* Internal MAC Sublayer Error TX Frame Count */
+#define EMAC_TXC_CRSERR 0xFFC031A0 /* Carrier Sense Deasserted During TX Frame Count */
+#define EMAC_TXC_UNICST 0xFFC031A4 /* Unicast TX Frame Count */
+#define EMAC_TXC_MULTI 0xFFC031A8 /* Multicast TX Frame Count */
+#define EMAC_TXC_BROAD 0xFFC031AC /* Broadcast TX Frame Count */
+#define EMAC_TXC_XS_DFR 0xFFC031B0 /* TX Frames With Excessive Deferral Count */
+#define EMAC_TXC_MACCTL 0xFFC031B4 /* MAC Control TX Frame Count */
+#define EMAC_TXC_ALLFRM 0xFFC031B8 /* Overall TX Frame Count */
+#define EMAC_TXC_ALLOCT 0xFFC031BC /* Overall TX Octet Count */
+#define EMAC_TXC_EQ64 0xFFC031C0 /* Good TX Frame Count - Byte Count x = 64 */
+#define EMAC_TXC_LT128 0xFFC031C4 /* Good TX Frame Count - Byte Count 64 <= x < 128 */
+#define EMAC_TXC_LT256 0xFFC031C8 /* Good TX Frame Count - Byte Count 128 <= x < 256 */
+#define EMAC_TXC_LT512 0xFFC031CC /* Good TX Frame Count - Byte Count 256 <= x < 512 */
+#define EMAC_TXC_LT1024 0xFFC031D0 /* Good TX Frame Count - Byte Count 512 <= x < 1024 */
+#define EMAC_TXC_GE1024 0xFFC031D4 /* Good TX Frame Count - Byte Count x >= 1024 */
+#define EMAC_TXC_ABORT 0xFFC031D8 /* Total TX Frames Aborted Count */
+
+/* Listing for IEEE-Supported Count Registers */
+#define FramesReceivedOK EMAC_RXC_OK /* RX Frame Successful Count */
+#define FrameCheckSequenceErrors EMAC_RXC_FCS /* RX Frame FCS Failure Count */
+#define AlignmentErrors EMAC_RXC_ALIGN /* RX Alignment Error Count */
+#define OctetsReceivedOK EMAC_RXC_OCTET /* RX Octets Successfully Received Count */
+#define FramesLostDueToIntMACRcvError EMAC_RXC_DMAOVF /* Internal MAC Sublayer Error RX Frame Count */
+#define UnicastFramesReceivedOK EMAC_RXC_UNICST /* Unicast RX Frame Count */
+#define MulticastFramesReceivedOK EMAC_RXC_MULTI /* Multicast RX Frame Count */
+#define BroadcastFramesReceivedOK EMAC_RXC_BROAD /* Broadcast RX Frame Count */
+#define InRangeLengthErrors EMAC_RXC_LNERRI /* RX Frame In Range Error Count */
+#define OutOfRangeLengthField EMAC_RXC_LNERRO /* RX Frame Out Of Range Error Count */
+#define FrameTooLongErrors EMAC_RXC_LONG /* RX Frame Too Long Count */
+#define MACControlFramesReceived EMAC_RXC_MACCTL /* MAC Control RX Frame Count */
+#define UnsupportedOpcodesReceived EMAC_RXC_OPCODE /* Unsupported Op-Code RX Frame Count */
+#define PAUSEMACCtrlFramesReceived EMAC_RXC_PAUSE /* MAC Control Pause RX Frame Count */
+#define FramesReceivedAll EMAC_RXC_ALLFRM /* Overall RX Frame Count */
+#define OctetsReceivedAll EMAC_RXC_ALLOCT /* Overall RX Octet Count */
+#define TypedFramesReceived EMAC_RXC_TYPED /* Type/Length Consistent RX Frame Count */
+#define FramesLenLt64Received EMAC_RXC_SHORT /* RX Frame Fragment Count - Byte Count x < 64 */
+#define FramesLenEq64Received EMAC_RXC_EQ64 /* Good RX Frame Count - Byte Count x = 64 */
+#define FramesLen65_127Received EMAC_RXC_LT128 /* Good RX Frame Count - Byte Count 64 <= x < 128 */
+#define FramesLen128_255Received EMAC_RXC_LT256 /* Good RX Frame Count - Byte Count 128 <= x < 256 */
+#define FramesLen256_511Received EMAC_RXC_LT512 /* Good RX Frame Count - Byte Count 256 <= x < 512 */
+#define FramesLen512_1023Received EMAC_RXC_LT1024 /* Good RX Frame Count - Byte Count 512 <= x < 1024 */
+#define FramesLen1024_MaxReceived EMAC_RXC_GE1024 /* Good RX Frame Count - Byte Count x >= 1024 */
+
+#define FramesTransmittedOK EMAC_TXC_OK /* TX Frame Successful Count */
+#define SingleCollisionFrames EMAC_TXC_1COL /* TX Frames Successful After Single Collision Count */
+#define MultipleCollisionFrames EMAC_TXC_GT1COL /* TX Frames Successful After Multiple Collisions Count */
+#define OctetsTransmittedOK EMAC_TXC_OCTET /* TX Octets Successfully Received Count */
+#define FramesWithDeferredXmissions EMAC_TXC_DEFER /* TX Frame Delayed Due To Busy Count */
+#define LateCollisions EMAC_TXC_LATECL /* Late TX Collisions Count */
+#define FramesAbortedDueToXSColls EMAC_TXC_XS_COL /* TX Frame Failed Due To Excessive Collisions Count */
+#define FramesLostDueToIntMacXmitError EMAC_TXC_DMAUND /* Internal MAC Sublayer Error TX Frame Count */
+#define CarrierSenseErrors EMAC_TXC_CRSERR /* Carrier Sense Deasserted During TX Frame Count */
+#define UnicastFramesXmittedOK EMAC_TXC_UNICST /* Unicast TX Frame Count */
+#define MulticastFramesXmittedOK EMAC_TXC_MULTI /* Multicast TX Frame Count */
+#define BroadcastFramesXmittedOK EMAC_TXC_BROAD /* Broadcast TX Frame Count */
+#define FramesWithExcessiveDeferral EMAC_TXC_XS_DFR /* TX Frames With Excessive Deferral Count */
+#define MACControlFramesTransmitted EMAC_TXC_MACCTL /* MAC Control TX Frame Count */
+#define FramesTransmittedAll EMAC_TXC_ALLFRM /* Overall TX Frame Count */
+#define OctetsTransmittedAll EMAC_TXC_ALLOCT /* Overall TX Octet Count */
+#define FramesLenEq64Transmitted EMAC_TXC_EQ64 /* Good TX Frame Count - Byte Count x = 64 */
+#define FramesLen65_127Transmitted EMAC_TXC_LT128 /* Good TX Frame Count - Byte Count 64 <= x < 128 */
+#define FramesLen128_255Transmitted EMAC_TXC_LT256 /* Good TX Frame Count - Byte Count 128 <= x < 256 */
+#define FramesLen256_511Transmitted EMAC_TXC_LT512 /* Good TX Frame Count - Byte Count 256 <= x < 512 */
+#define FramesLen512_1023Transmitted EMAC_TXC_LT1024 /* Good TX Frame Count - Byte Count 512 <= x < 1024 */
+#define FramesLen1024_MaxTransmitted EMAC_TXC_GE1024 /* Good TX Frame Count - Byte Count x >= 1024 */
+#define TxAbortedFrames EMAC_TXC_ABORT /* Total TX Frames Aborted Count */
+
+/***********************************************************************************
+** System MMR Register Bits And Macros
+**
+** Disclaimer: All macros are intended to make C and Assembly code more readable.
+** Use these macros carefully, as any that do left shifts for field
+** depositing will result in the lower order bits being destroyed. Any
+** macro that shifts left to properly position the bit-field should be
+** used as part of an OR to initialize a register and NOT as a dynamic
+** modifier UNLESS the lower order bits are saved and ORed back in when
+** the macro is used.
+*************************************************************************************/
+/************************ ETHERNET 10/100 CONTROLLER MASKS ************************/
+/* EMAC_OPMODE Masks */
+#define RE 0x00000001 /* Receiver Enable */
+#define ASTP 0x00000002 /* Enable Automatic Pad Stripping On RX Frames */
+#define HU 0x00000010 /* Hash Filter Unicast Address */
+#define HM 0x00000020 /* Hash Filter Multicast Address */
+#define PAM 0x00000040 /* Pass-All-Multicast Mode Enable */
+#define PR 0x00000080 /* Promiscuous Mode Enable */
+#define IFE 0x00000100 /* Inverse Filtering Enable */
+#define DBF 0x00000200 /* Disable Broadcast Frame Reception */
+#define PBF 0x00000400 /* Pass Bad Frames Enable */
+#define PSF 0x00000800 /* Pass Short Frames Enable */
+#define RAF 0x00001000 /* Receive-All Mode */
+#define TE 0x00010000 /* Transmitter Enable */
+#define DTXPAD 0x00020000 /* Disable Automatic TX Padding */
+#define DTXCRC 0x00040000 /* Disable Automatic TX CRC Generation */
+#define DC 0x00080000 /* Deferral Check */
+#define BOLMT 0x00300000 /* Back-Off Limit */
+#define BOLMT_10 0x00000000 /* 10-bit range */
+#define BOLMT_8 0x00100000 /* 8-bit range */
+#define BOLMT_4 0x00200000 /* 4-bit range */
+#define BOLMT_1 0x00300000 /* 1-bit range */
+#define DRTY 0x00400000 /* Disable TX Retry On Collision */
+#define LCTRE 0x00800000 /* Enable TX Retry On Late Collision */
+#define RMII 0x01000000 /* RMII/MII* Mode */
+#define RMII_10 0x02000000 /* Speed Select for RMII Port (10MBit/100MBit*) */
+#define FDMODE 0x04000000 /* Duplex Mode Enable (Full/Half*) */
+#define LB 0x08000000 /* Internal Loopback Enable */
+#define DRO 0x10000000 /* Disable Receive Own Frames (Half-Duplex Mode) */
+
+/* EMAC_STAADD Masks */
+#define STABUSY 0x00000001 /* Initiate Station Mgt Reg Access / STA Busy Stat */
+#define STAOP 0x00000002 /* Station Management Operation Code (Write/Read*) */
+#define STADISPRE 0x00000004 /* Disable Preamble Generation */
+#define STAIE 0x00000008 /* Station Mgt. Transfer Done Interrupt Enable */
+#define REGAD 0x000007C0 /* STA Register Address */
+#define PHYAD 0x0000F800 /* PHY Device Address */
+
+#define SET_REGAD(x) (((x)&0x1F)<< 6 ) /* Set STA Register Address */
+#define SET_PHYAD(x) (((x)&0x1F)<< 11 ) /* Set PHY Device Address */
+
+/* EMAC_STADAT Mask */
+#define STADATA 0x0000FFFF /* Station Management Data */
+
+/* EMAC_FLC Masks */
+#define FLCBUSY 0x00000001 /* Send Flow Ctrl Frame / Flow Ctrl Busy Status */
+#define FLCE 0x00000002 /* Flow Control Enable */
+#define PCF 0x00000004 /* Pass Control Frames */
+#define BKPRSEN 0x00000008 /* Enable Backpressure */
+#define FLCPAUSE 0xFFFF0000 /* Pause Time */
+
+#define SET_FLCPAUSE(x) (((x)&0xFFFF)<< 16) /* Set Pause Time */
+
+/* EMAC_WKUP_CTL Masks */
+#define CAPWKFRM 0x00000001 /* Capture Wake-Up Frames */
+#define MPKE 0x00000002 /* Magic Packet Enable */
+#define RWKE 0x00000004 /* Remote Wake-Up Frame Enable */
+#define GUWKE 0x00000008 /* Global Unicast Wake Enable */
+#define MPKS 0x00000020 /* Magic Packet Received Status */
+#define RWKS 0x00000F00 /* Wake-Up Frame Received Status, Filters 3:0 */
+
+/* EMAC_WKUP_FFCMD Masks */
+#define WF0_E 0x00000001 /* Enable Wake-Up Filter 0 */
+#define WF0_T 0x00000008 /* Wake-Up Filter 0 Addr Type (Multicast/Unicast*) */
+#define WF1_E 0x00000100 /* Enable Wake-Up Filter 1 */
+#define WF1_T 0x00000800 /* Wake-Up Filter 1 Addr Type (Multicast/Unicast*) */
+#define WF2_E 0x00010000 /* Enable Wake-Up Filter 2 */
+#define WF2_T 0x00080000 /* Wake-Up Filter 2 Addr Type (Multicast/Unicast*) */
+#define WF3_E 0x01000000 /* Enable Wake-Up Filter 3 */
+#define WF3_T 0x08000000 /* Wake-Up Filter 3 Addr Type (Multicast/Unicast*) */
+
+/* EMAC_WKUP_FFOFF Masks */
+#define WF0_OFF 0x000000FF /* Wake-Up Filter 0 Pattern Offset */
+#define WF1_OFF 0x0000FF00 /* Wake-Up Filter 1 Pattern Offset */
+#define WF2_OFF 0x00FF0000 /* Wake-Up Filter 2 Pattern Offset */
+#define WF3_OFF 0xFF000000 /* Wake-Up Filter 3 Pattern Offset */
+
+#define SET_WF0_OFF(x) (((x)&0xFF)<< 0 ) /* Set Wake-Up Filter 0 Byte Offset */
+#define SET_WF1_OFF(x) (((x)&0xFF)<< 8 ) /* Set Wake-Up Filter 1 Byte Offset */
+#define SET_WF2_OFF(x) (((x)&0xFF)<< 16 ) /* Set Wake-Up Filter 2 Byte Offset */
+#define SET_WF3_OFF(x) (((x)&0xFF)<< 24 ) /* Set Wake-Up Filter 3 Byte Offset */
+/* Set ALL Offsets */
+#define SET_WF_OFFS(x0,x1,x2,x3) (SET_WF0_OFF((x0))|SET_WF1_OFF((x1))|SET_WF2_OFF((x2))|SET_WF3_OFF((x3)))
+
+/* EMAC_WKUP_FFCRC0 Masks */
+#define WF0_CRC 0x0000FFFF /* Wake-Up Filter 0 Pattern CRC */
+#define WF1_CRC 0xFFFF0000 /* Wake-Up Filter 1 Pattern CRC */
+
+#define SET_WF0_CRC(x) (((x)&0xFFFF)<< 0 ) /* Set Wake-Up Filter 0 Target CRC */
+#define SET_WF1_CRC(x) (((x)&0xFFFF)<< 16 ) /* Set Wake-Up Filter 1 Target CRC */
+
+/* EMAC_WKUP_FFCRC1 Masks */
+#define WF2_CRC 0x0000FFFF /* Wake-Up Filter 2 Pattern CRC */
+#define WF3_CRC 0xFFFF0000 /* Wake-Up Filter 3 Pattern CRC */
+
+#define SET_WF2_CRC(x) (((x)&0xFFFF)<< 0 ) /* Set Wake-Up Filter 2 Target CRC */
+#define SET_WF3_CRC(x) (((x)&0xFFFF)<< 16 ) /* Set Wake-Up Filter 3 Target CRC */
+
+/* EMAC_SYSCTL Masks */
+#define PHYIE 0x00000001 /* PHY_INT Interrupt Enable */
+#define RXDWA 0x00000002 /* Receive Frame DMA Word Alignment (Odd/Even*) */
+#define RXCKS 0x00000004 /* Enable RX Frame TCP/UDP Checksum Computation */
+#define MDCDIV 0x00003F00 /* SCLK:MDC Clock Divisor [MDC=SCLK/(2*(N+1))] */
+
+#define SET_MDCDIV(x) (((x)&0x3F)<< 8) /* Set MDC Clock Divisor */
+
+/* EMAC_SYSTAT Masks */
+#define PHYINT 0x00000001 /* PHY_INT Interrupt Status */
+#define MMCINT 0x00000002 /* MMC Counter Interrupt Status */
+#define RXFSINT 0x00000004 /* RX Frame-Status Interrupt Status */
+#define TXFSINT 0x00000008 /* TX Frame-Status Interrupt Status */
+#define WAKEDET 0x00000010 /* Wake-Up Detected Status */
+#define RXDMAERR 0x00000020 /* RX DMA Direction Error Status */
+#define TXDMAERR 0x00000040 /* TX DMA Direction Error Status */
+#define STMDONE 0x00000080 /* Station Mgt. Transfer Done Interrupt Status */
+
+/* EMAC_RX_STAT, EMAC_RX_STKY, and EMAC_RX_IRQE Masks */
+#define RX_FRLEN 0x000007FF /* Frame Length In Bytes */
+#define RX_COMP 0x00001000 /* RX Frame Complete */
+#define RX_OK 0x00002000 /* RX Frame Received With No Errors */
+#define RX_LONG 0x00004000 /* RX Frame Too Long Error */
+#define RX_ALIGN 0x00008000 /* RX Frame Alignment Error */
+#define RX_CRC 0x00010000 /* RX Frame CRC Error */
+#define RX_LEN 0x00020000 /* RX Frame Length Error */
+#define RX_FRAG 0x00040000 /* RX Frame Fragment Error */
+#define RX_ADDR 0x00080000 /* RX Frame Address Filter Failed Error */
+#define RX_DMAO 0x00100000 /* RX Frame DMA Overrun Error */
+#define RX_PHY 0x00200000 /* RX Frame PHY Error */
+#define RX_LATE 0x00400000 /* RX Frame Late Collision Error */
+#define RX_RANGE 0x00800000 /* RX Frame Length Field Out of Range Error */
+#define RX_MULTI 0x01000000 /* RX Multicast Frame Indicator */
+#define RX_BROAD 0x02000000 /* RX Broadcast Frame Indicator */
+#define RX_CTL 0x04000000 /* RX Control Frame Indicator */
+#define RX_UCTL 0x08000000 /* Unsupported RX Control Frame Indicator */
+#define RX_TYPE 0x10000000 /* RX Typed Frame Indicator */
+#define RX_VLAN1 0x20000000 /* RX VLAN1 Frame Indicator */
+#define RX_VLAN2 0x40000000 /* RX VLAN2 Frame Indicator */
+#define RX_ACCEPT 0x80000000 /* RX Frame Accepted Indicator */
+
+/* EMAC_TX_STAT, EMAC_TX_STKY, and EMAC_TX_IRQE Masks */
+#define TX_COMP 0x00000001 /* TX Frame Complete */
+#define TX_OK 0x00000002 /* TX Frame Sent With No Errors */
+#define TX_ECOLL 0x00000004 /* TX Frame Excessive Collision Error */
+#define TX_LATE 0x00000008 /* TX Frame Late Collision Error */
+#define TX_DMAU 0x00000010 /* TX Frame DMA Underrun Error (STAT) */
+#define TX_MACE 0x00000010 /* Internal MAC Error Detected (STKY and IRQE) */
+#define TX_EDEFER 0x00000020 /* TX Frame Excessive Deferral Error */
+#define TX_BROAD 0x00000040 /* TX Broadcast Frame Indicator */
+#define TX_MULTI 0x00000080 /* TX Multicast Frame Indicator */
+#define TX_CCNT 0x00000F00 /* TX Frame Collision Count */
+#define TX_DEFER 0x00001000 /* TX Frame Deferred Indicator */
+#define TX_CRS 0x00002000 /* TX Frame Carrier Sense Not Asserted Error */
+#define TX_LOSS 0x00004000 /* TX Frame Carrier Lost During TX Error */
+#define TX_RETRY 0x00008000 /* TX Frame Successful After Retry */
+#define TX_FRLEN 0x07FF0000 /* TX Frame Length (Bytes) */
+
+/* EMAC_MMC_CTL Masks */
+#define RSTC 0x00000001 /* Reset All Counters */
+#define CROLL 0x00000002 /* Counter Roll-Over Enable */
+#define CCOR 0x00000004 /* Counter Clear-On-Read Mode Enable */
+#define MMCE 0x00000008 /* Enable MMC Counter Operation */
+
+/* EMAC_MMC_RIRQS and EMAC_MMC_RIRQE Masks */
+#define RX_OK_CNT 0x00000001 /* RX Frames Received With No Errors */
+#define RX_FCS_CNT 0x00000002 /* RX Frames W/Frame Check Sequence Errors */
+#define RX_ALIGN_CNT 0x00000004 /* RX Frames With Alignment Errors */
+#define RX_OCTET_CNT 0x00000008 /* RX Octets Received OK */
+#define RX_LOST_CNT 0x00000010 /* RX Frames Lost Due To Internal MAC RX Error */
+#define RX_UNI_CNT 0x00000020 /* Unicast RX Frames Received OK */
+#define RX_MULTI_CNT 0x00000040 /* Multicast RX Frames Received OK */
+#define RX_BROAD_CNT 0x00000080 /* Broadcast RX Frames Received OK */
+#define RX_IRL_CNT 0x00000100 /* RX Frames With In-Range Length Errors */
+#define RX_ORL_CNT 0x00000200 /* RX Frames With Out-Of-Range Length Errors */
+#define RX_LONG_CNT 0x00000400 /* RX Frames With Frame Too Long Errors */
+#define RX_MACCTL_CNT 0x00000800 /* MAC Control RX Frames Received */
+#define RX_OPCODE_CTL 0x00001000 /* Unsupported Op-Code RX Frames Received */
+#define RX_PAUSE_CNT 0x00002000 /* PAUSEMAC Control RX Frames Received */
+#define RX_ALLF_CNT 0x00004000 /* All RX Frames Received */
+#define RX_ALLO_CNT 0x00008000 /* All RX Octets Received */
+#define RX_TYPED_CNT 0x00010000 /* Typed RX Frames Received */
+#define RX_SHORT_CNT 0x00020000 /* RX Frame Fragments (< 64 Bytes) Received */
+#define RX_EQ64_CNT 0x00040000 /* 64-Byte RX Frames Received */
+#define RX_LT128_CNT 0x00080000 /* 65-127-Byte RX Frames Received */
+#define RX_LT256_CNT 0x00100000 /* 128-255-Byte RX Frames Received */
+#define RX_LT512_CNT 0x00200000 /* 256-511-Byte RX Frames Received */
+#define RX_LT1024_CNT 0x00400000 /* 512-1023-Byte RX Frames Received */
+#define RX_GE1024_CNT 0x00800000 /* 1024-Max-Byte RX Frames Received */
+
+/* EMAC_MMC_TIRQS and EMAC_MMC_TIRQE Masks */
+#define TX_OK_CNT 0x00000001 /* TX Frames Sent OK */
+#define TX_SCOLL_CNT 0x00000002 /* TX Frames With Single Collisions */
+#define TX_MCOLL_CNT 0x00000004 /* TX Frames With Multiple Collisions */
+#define TX_OCTET_CNT 0x00000008 /* TX Octets Sent OK */
+#define TX_DEFER_CNT 0x00000010 /* TX Frames With Deferred Transmission */
+#define TX_LATE_CNT 0x00000020 /* TX Frames With Late Collisions */
+#define TX_ABORTC_CNT 0x00000040 /* TX Frames Aborted Due To Excess Collisions */
+#define TX_LOST_CNT 0x00000080 /* TX Frames Lost Due To Internal MAC TX Error */
+#define TX_CRS_CNT 0x00000100 /* TX Frames With Carrier Sense Errors */
+#define TX_UNI_CNT 0x00000200 /* Unicast TX Frames Sent */
+#define TX_MULTI_CNT 0x00000400 /* Multicast TX Frames Sent */
+#define TX_BROAD_CNT 0x00000800 /* Broadcast TX Frames Sent */
+#define TX_EXDEF_CTL 0x00001000 /* TX Frames With Excessive Deferral */
+#define TX_MACCTL_CNT 0x00002000 /* MAC Control TX Frames Sent */
+#define TX_ALLF_CNT 0x00004000 /* All TX Frames Sent */
+#define TX_ALLO_CNT 0x00008000 /* All TX Octets Sent */
+#define TX_EQ64_CNT 0x00010000 /* 64-Byte TX Frames Sent */
+#define TX_LT128_CNT 0x00020000 /* 65-127-Byte TX Frames Sent */
+#define TX_LT256_CNT 0x00040000 /* 128-255-Byte TX Frames Sent */
+#define TX_LT512_CNT 0x00080000 /* 256-511-Byte TX Frames Sent */
+#define TX_LT1024_CNT 0x00100000 /* 512-1023-Byte TX Frames Sent */
+#define TX_GE1024_CNT 0x00200000 /* 1024-Max-Byte TX Frames Sent */
+#define TX_ABORT_CNT 0x00400000 /* TX Frames Aborted */
+
+#endif /* _DEF_BF537_H */
diff --git a/include/asm-blackfin/mach-bf537/dma.h b/include/asm-blackfin/mach-bf537/dma.h
new file mode 100644
index 00000000000..7a964040870
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/dma.h
@@ -0,0 +1,55 @@
+/*
+ * file: include/asm-blackfin/mach-bf537/dma.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ * system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 16
+
+#define CH_PPI 0
+#define CH_EMAC_RX 1
+#define CH_EMAC_TX 2
+#define CH_SPORT0_RX 3
+#define CH_SPORT0_TX 4
+#define CH_SPORT1_RX 5
+#define CH_SPORT1_TX 6
+#define CH_SPI 7
+#define CH_UART0_RX 8
+#define CH_UART0_TX 9
+#define CH_UART1_RX 10
+#define CH_UART1_TX 11
+
+#define CH_MEM_STREAM0_DEST 12 /* TX */
+#define CH_MEM_STREAM0_SRC 13 /* RX */
+#define CH_MEM_STREAM1_DEST 14 /* TX */
+#define CH_MEM_STREAM1_SRC 15 /* RX */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf537/irq.h b/include/asm-blackfin/mach-bf537/irq.h
new file mode 100644
index 00000000000..8af2a832ef6
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/irq.h
@@ -0,0 +1,219 @@
+/*
+ * file: include/asm-blackfin/mach-bf537/irq.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ * system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _BF537_IRQ_H_
+#define _BF537_IRQ_H_
+
+/*
+ * Interrupt source definitions
+ Event Source Core Event Name
+Core Emulation **
+ Events (highest priority) EMU 0
+ Reset RST 1
+ NMI NMI 2
+ Exception EVX 3
+ Reserved -- 4
+ Hardware Error IVHW 5
+ Core Timer IVTMR 6 *
+
+.....
+
+ Software Interrupt 1 IVG14 31
+ Software Interrupt 2 --
+ (lowest priority) IVG15 32 *
+ */
+
+#define SYS_IRQS 41
+#define NR_PERI_INTS 32
+
+/* The ABSTRACT IRQ definitions */
+/** the first seven of the following are fixed, the rest you change if you need to **/
+#define IRQ_EMU 0 /*Emulation */
+#define IRQ_RST 1 /*reset */
+#define IRQ_NMI 2 /*Non Maskable */
+#define IRQ_EVX 3 /*Exception */
+#define IRQ_UNUSED 4 /*- unused interrupt*/
+#define IRQ_HWERR 5 /*Hardware Error */
+#define IRQ_CORETMR 6 /*Core timer */
+
+#define IRQ_PLL_WAKEUP 7 /*PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR 8 /*DMA Error (general) */
+#define IRQ_GENERIC_ERROR 9 /*GENERIC Error Interrupt */
+#define IRQ_RTC 10 /*RTC Interrupt */
+#define IRQ_PPI 11 /*DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX 12 /*DMA3 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX 13 /*DMA4 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX 14 /*DMA5 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX 15 /*DMA6 Interrupt (SPORT1 TX) */
+#define IRQ_TWI 16 /*TWI Interrupt */
+#define IRQ_SPI 17 /*DMA7 Interrupt (SPI) */
+#define IRQ_UART0_RX 18 /*DMA8 Interrupt (UART0 RX) */
+#define IRQ_UART0_TX 19 /*DMA9 Interrupt (UART0 TX) */
+#define IRQ_UART1_RX 20 /*DMA10 Interrupt (UART1 RX) */
+#define IRQ_UART1_TX 21 /*DMA11 Interrupt (UART1 TX) */
+#define IRQ_CAN_RX 22 /*CAN Receive Interrupt */
+#define IRQ_CAN_TX 23 /*CAN Transmit Interrupt */
+#define IRQ_MAC_RX 24 /*DMA1 (Ethernet RX) Interrupt */
+#define IRQ_MAC_TX 25 /*DMA2 (Ethernet TX) Interrupt */
+#define IRQ_TMR0 26 /*Timer 0 */
+#define IRQ_TMR1 27 /*Timer 1 */
+#define IRQ_TMR2 28 /*Timer 2 */
+#define IRQ_TMR3 29 /*Timer 3 */
+#define IRQ_TMR4 30 /*Timer 4 */
+#define IRQ_TMR5 31 /*Timer 5 */
+#define IRQ_TMR6 32 /*Timer 6 */
+#define IRQ_TMR7 33 /*Timer 7 */
+#define IRQ_PROG_INTA 34 /* PF Ports F&G (PF15:0) Interrupt A */
+#define IRQ_PORTG_INTB 35 /* PF Port G (PF15:0) Interrupt B */
+#define IRQ_MEM_DMA0 36 /*(Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1 37 /*(Memory DMA Stream 1) */
+#define IRQ_PROG_INTB 38 /* PF Ports F (PF15:0) Interrupt B */
+#define IRQ_WATCH 38 /*Watch Dog Timer */
+#define IRQ_SW_INT1 40 /*Software Int 1 */
+#define IRQ_SW_INT2 41 /*Software Int 2 (reserved for SYSCALL) */
+
+#define IRQ_PPI_ERROR 42 /*PPI Error Interrupt */
+#define IRQ_CAN_ERROR 43 /*CAN Error Interrupt */
+#define IRQ_MAC_ERROR 44 /*PPI Error Interrupt */
+#define IRQ_SPORT0_ERROR 45 /*SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR 46 /*SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR 47 /*SPI Error Interrupt */
+#define IRQ_UART0_ERROR 48 /*UART Error Interrupt */
+#define IRQ_UART1_ERROR 49 /*UART Error Interrupt */
+
+#define IRQ_PF0 50
+#define IRQ_PF1 51
+#define IRQ_PF2 52
+#define IRQ_PF3 53
+#define IRQ_PF4 54
+#define IRQ_PF5 55
+#define IRQ_PF6 56
+#define IRQ_PF7 57
+#define IRQ_PF8 58
+#define IRQ_PF9 59
+#define IRQ_PF10 60
+#define IRQ_PF11 61
+#define IRQ_PF12 62
+#define IRQ_PF13 63
+#define IRQ_PF14 64
+#define IRQ_PF15 65
+
+#define IRQ_PG0 66
+#define IRQ_PG1 67
+#define IRQ_PG2 68
+#define IRQ_PG3 69
+#define IRQ_PG4 70
+#define IRQ_PG5 71
+#define IRQ_PG6 72
+#define IRQ_PG7 73
+#define IRQ_PG8 74
+#define IRQ_PG9 75
+#define IRQ_PG10 76
+#define IRQ_PG11 77
+#define IRQ_PG12 78
+#define IRQ_PG13 79
+#define IRQ_PG14 80
+#define IRQ_PG15 81
+
+#define IRQ_PH0 82
+#define IRQ_PH1 83
+#define IRQ_PH2 84
+#define IRQ_PH3 85
+#define IRQ_PH4 86
+#define IRQ_PH5 87
+#define IRQ_PH6 88
+#define IRQ_PH7 89
+#define IRQ_PH8 90
+#define IRQ_PH9 91
+#define IRQ_PH10 92
+#define IRQ_PH11 93
+#define IRQ_PH12 94
+#define IRQ_PH13 95
+#define IRQ_PH14 96
+#define IRQ_PH15 97
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS (IRQ_PH15+1)
+#else
+#define NR_IRQS (IRQ_UART1_ERROR+1)
+#endif
+
+#define IVG7 7
+#define IVG8 8
+#define IVG9 9
+#define IVG10 10
+#define IVG11 11
+#define IVG12 12
+#define IVG13 13
+#define IVG14 14
+#define IVG15 15
+
+/* IAR0 BIT FIELDS*/
+#define IRQ_PLL_WAKEUP_POS 0
+#define IRQ_DMA_ERROR_POS 4
+#define IRQ_ERROR_POS 8
+#define IRQ_RTC_POS 12
+#define IRQ_PPI_POS 16
+#define IRQ_SPORT0_RX_POS 20
+#define IRQ_SPORT0_TX_POS 24
+#define IRQ_SPORT1_RX_POS 28
+
+/* IAR1 BIT FIELDS*/
+#define IRQ_SPORT1_TX_POS 0
+#define IRQ_TWI_POS 4
+#define IRQ_SPI_POS 8
+#define IRQ_UART0_RX_POS 12
+#define IRQ_UART0_TX_POS 16
+#define IRQ_UART1_RX_POS 20
+#define IRQ_UART1_TX_POS 24
+#define IRQ_CAN_RX_POS 28
+
+/* IAR2 BIT FIELDS*/
+#define IRQ_CAN_TX_POS 0
+#define IRQ_MAC_RX_POS 4
+#define IRQ_MAC_TX_POS 8
+#define IRQ_TMR0_POS 12
+#define IRQ_TMR1_POS 16
+#define IRQ_TMR2_POS 20
+#define IRQ_TMR3_POS 24
+#define IRQ_TMR4_POS 28
+
+/* IAR3 BIT FIELDS*/
+#define IRQ_TMR5_POS 0
+#define IRQ_TMR6_POS 4
+#define IRQ_TMR7_POS 8
+#define IRQ_PROG_INTA_POS 12
+#define IRQ_PORTG_INTB_POS 16
+#define IRQ_MEM_DMA0_POS 20
+#define IRQ_MEM_DMA1_POS 24
+#define IRQ_WATCH_POS 28
+
+#endif /* _BF537_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf537/mem_init.h b/include/asm-blackfin/mach-bf537/mem_init.h
new file mode 100644
index 00000000000..9ad979d416c
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/mem_init.h
@@ -0,0 +1,330 @@
+/*
+ * File: include/asm-blackfin/mach-bf537/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_MT48LC16M8A2TG_75 || CONFIG_MEM_GENERIC_BOARD || CONFIG_MEM_MT48LC32M8A2_75)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_7
+#define SDRAM_tRAS_num 7
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_6
+#define SDRAM_tRAS_num 6
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 89552239) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_5
+#define SDRAM_tRAS_num 5
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_4
+#define SDRAM_tRAS_num 4
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_3
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_4
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_3
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_2
+#define SDRAM_tRAS_num 2
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_1
+#define SDRAM_tRAS_num 1
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC16M8A2TG_75)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 4096 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC32M8A2_75)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+ /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE EBSZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE EBSZ_64
+#endif
+#if (CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE EBSZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE EBSZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH EBCAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH EBCAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH EBCAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH EBCAW_8
+#endif
+
+#define mem_SDBCTL (SDRAM_WIDTH | SDRAM_SIZE | EBE)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF 1
+#else
+#define CLKIN_HALF 0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS 1
+#else
+#define PLL_BYPASS 0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT ((CONFIG_FLASH_SPEED_BHT * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST ((CONFIG_FLASH_SPEED_BST * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT ((CONFIG_FLASH_SPEED_BTT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0 \
+ (flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+ flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf537/mem_map.h b/include/asm-blackfin/mach-bf537/mem_map.h
new file mode 100644
index 00000000000..2a808c1202b
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/mem_map.h
@@ -0,0 +1,175 @@
+/*
+ * file: include/asm-blackfin/mach-bf537/mem_map.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ * Memory MAP Common header file for blackfin BF537/6/4 of processors.
+ * rev:
+ *
+ * modified:
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MEM_MAP_537_H_
+#define _MEM_MAP_537_H_
+
+#define COREMMR_BASE 0xFFE00000 /* Core MMRs */
+#define SYSMMR_BASE 0xFFC00000 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE 0x20300000 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE 0x00100000 /* 1M */
+#define ASYNC_BANK2_BASE 0x20200000 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE 0x00100000 /* 1M */
+#define ASYNC_BANK1_BASE 0x20100000 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE 0x00100000 /* 1M */
+#define ASYNC_BANK0_BASE 0x20000000 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE 0x00100000 /* 1M */
+
+/* Boot ROM Memory */
+
+#define BOOT_ROM_START 0xEF000000
+
+/* Level 1 Memory */
+
+/* Memory Map for ADSP-BF537 processors */
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define BLKFIN_ICACHESIZE (16*1024)
+#else
+#define BLKFIN_ICACHESIZE (0*1024)
+#endif
+
+
+#ifdef CONFIG_BF537
+#define L1_CODE_START 0xFFA00000
+#define L1_DATA_A_START 0xFF800000
+#define L1_DATA_B_START 0xFF900000
+
+#define L1_CODE_LENGTH 0xC000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x8000
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+#endif /*CONFIG_BF537*/
+
+/* Memory Map for ADSP-BF536 processors */
+
+#ifdef CONFIG_BF536
+#define L1_CODE_START 0xFFA00000
+#define L1_DATA_A_START 0xFF804000
+#define L1_DATA_B_START 0xFF904000
+
+#define L1_CODE_LENGTH 0xC000
+
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x4000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x4000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x4000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x4000
+#define L1_DATA_B_LENGTH 0x4000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+#endif
+
+/* Memory Map for ADSP-BF534 processors */
+
+#ifdef CONFIG_BF534
+#define L1_CODE_START 0xFFA00000
+#define L1_DATA_A_START 0xFF800000
+#define L1_DATA_B_START 0xFF900000
+
+#define L1_CODE_LENGTH 0xC000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x8000
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+#endif
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536) || defined(CONFIG_BF534)
+#define L1_SCRATCH_START 0xFFB00000
+#define L1_SCRATCH_LENGTH 0x1000
+#endif
+
+#endif /* _MEM_MAP_537_H_ */
diff --git a/include/asm-blackfin/mach-bf561/anomaly.h b/include/asm-blackfin/mach-bf561/anomaly.h
new file mode 100644
index 00000000000..f5b32d66517
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/anomaly.h
@@ -0,0 +1,184 @@
+
+/*
+ * File: include/asm-blackfin/mach-bf561/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* This file shoule be up to date with:
+ * - Revision L, 10Aug2006; ADSP-BF561 Silicon Anomaly List
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+
+/* We do not support 0.1 or 0.4 silicon - sorry */
+#if (defined(CONFIG_BF_REV_0_1) || defined(CONFIG_BF_REV_0_2) || defined(CONFIG_BF_REV_0_4))
+#error Kernel will not work on BF561 Version 0.1, 0.2, or 0.4
+#endif
+
+/* Issues that are common to 0.5 and 0.3 silicon */
+#if (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+ slot1 and store of a P register in slot 2 is not
+ supported */
+#define ANOMALY_05000099 /* UART Line Status Register (UART_LSR) bits are not
+ updated at the same time. */
+#define ANOMALY_05000120 /* Testset instructions restricted to 32-bit aligned
+ memory locations */
+#define ANOMALY_05000122 /* Rx.H cannot be used to access 16-bit System MMR
+ registers */
+#define ANOMALY_05000127 /* Signbits instruction not functional under certain
+ conditions */
+#define ANOMALY_05000149 /* IMDMA S1/D1 channel may stall */
+#define ANOMALY_05000166 /* PPI Data Lengths Between 8 and 16 do not zero out
+ upper bits */
+#define ANOMALY_05000167 /* Turning Serial Ports on With External Frame Syncs */
+#define ANOMALY_05000180 /* PPI_DELAY not functional in PPI modes with 0 frame
+ syncs */
+#define ANOMALY_05000182 /* IMDMA does not operate to full speed for 600MHz
+ and higher devices */
+#define ANOMALY_05000187 /* IMDMA Corrupted Data after a Halt */
+#define ANOMALY_05000190 /* PPI not functional at core voltage < 1Volt */
+#define ANOMALY_05000208 /* VSTAT status bit in PLL_STAT register is not
+ functional */
+#define ANOMALY_05000245 /* Spurious Hardware Error from an access in the
+ shadow of a conditional branch */
+#define ANOMALY_05000257 /* Interrupt/Exception during short hardware loop
+ may cause bad instruction fetches */
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+ external SPORT TX and RX clocks */
+#define ANOMALY_05000267 /* IMDMA may corrupt data under certain conditions */
+#define ANOMALY_05000269 /* High I/O activity causes output voltage of internal
+ voltage regulator (VDDint) to increase */
+#define ANOMALY_05000270 /* High I/O activity causes output voltage of internal
+ voltage regulator (VDDint) to decrease */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+ VDDint <=0.9V */
+#define ANOMALY_05000274 /* Data cache write back to external synchronous memory
+ may be lost */
+#define ANOMALY_05000275 /* PPI Timing and sampling informaton updates */
+#define ANOMALY_05000312 /* Errors when SSYNC, CSYNC, or loads to LT, LB and LC
+ registers are interrupted */
+
+#endif /* (defined(CONFIG_BF_REV_0_5) || defined(CONFIG_BF_REV_0_3)) */
+
+#if (defined(CONFIG_BF_REV_0_5))
+#define ANOMALY_05000254 /* Incorrect Timer Pulse Width in Single-Shot PWM_OUT
+ mode with external clock */
+#define ANOMALY_05000266 /* IMDMA destination IRQ status must be read prior to
+ using IMDMA */
+#endif
+
+#if (defined(CONFIG_BF_REV_0_3))
+#define ANOMALY_05000156 /* Timers in PWM-Out Mode with PPI GP Receive (Input)
+ Mode with 0 Frame Syncs */
+#define ANOMALY_05000168 /* SDRAM auto-refresh and subsequent Power Ups */
+#define ANOMALY_05000169 /* DATA CPLB page miss can result in lost write-through
+ cache data writes */
+#define ANOMALY_05000171 /* Boot-ROM code modifies SICA_IWRx wakeup registers */
+#define ANOMALY_05000174 /* Cache Fill Buffer Data lost */
+#define ANOMALY_05000175 /* Overlapping Sequencer and Memory Stalls */
+#define ANOMALY_05000176 /* Multiplication of (-1) by (-1) followed by an
+ accumulator saturation */
+#define ANOMALY_05000179 /* PPI_COUNT cannot be programmed to 0 in General
+ Purpose TX or RX modes */
+#define ANOMALY_05000181 /* Disabling the PPI resets the PPI configuration
+ registers */
+#define ANOMALY_05000184 /* Timer Pin limitations for PPI TX Modes with
+ External Frame Syncs */
+#define ANOMALY_05000185 /* PPI TX Mode with 2 External Frame Syncs */
+#define ANOMALY_05000186 /* PPI packing with Data Length greater than 8 bits
+ (not a meaningful mode) */
+#define ANOMALY_05000188 /* IMDMA Restrictions on Descriptor and Buffer
+ Placement in Memory */
+#define ANOMALY_05000189 /* False Protection Exception */
+#define ANOMALY_05000193 /* False Flag Pin Interrupts on Edge Sensitive Inputs
+ when polarity setting is changed */
+#define ANOMALY_05000194 /* Restarting SPORT in specific modes may cause data
+ corruption */
+#define ANOMALY_05000198 /* Failing MMR accesses when stalled by preceding
+ memory read */
+#define ANOMALY_05000199 /* DMA current address shows wrong value during carry
+ fix */
+#define ANOMALY_05000200 /* SPORT TFS and DT are incorrectly driven during
+ inactive channels in certain conditions */
+#define ANOMALY_05000202 /* Possible infinite stall with specific dual-DAG
+ situation */
+#define ANOMALY_05000204 /* Incorrect data read with write-through cache and
+ allocate cache lines on reads only mode */
+#define ANOMALY_05000205 /* Specific sequence that can cause DMA error or DMA
+ stopping */
+#define ANOMALY_05000207 /* Recovery from "brown-out" condition */
+#define ANOMALY_05000209 /* Speed-Path in computational unit affects certain
+ instructions */
+#define ANOMALY_05000215 /* UART TX Interrupt masked erroneously */
+#define ANOMALY_05000219 /* NMI event at boot time results in unpredictable
+ state */
+#define ANOMALY_05000220 /* Data Corruption with Cached External Memory and
+ Non-Cached On-Chip L2 Memory */
+#define ANOMALY_05000225 /* Incorrect pulse-width of UART start-bit */
+#define ANOMALY_05000227 /* Scratchpad memory bank reads may return incorrect
+ data */
+#define ANOMALY_05000230 /* UART Receiver is less robust against Baudrate
+ Differences in certain Conditions */
+#define ANOMALY_05000231 /* UART STB bit incorrectly affects receiver setting */
+#define ANOMALY_05000232 /* SPORT data transmit lines are incorrectly driven in
+ multichannel mode */
+#define ANOMALY_05000242 /* DF bit in PLL_CTL register does not respond to
+ hardware reset */
+#define ANOMALY_05000244 /* If i-cache is on, CSYNC/SSYNC/IDLE around Change of
+ Control causes failures */
+#define ANOMALY_05000248 /* TESTSET operation forces stall on the other core */
+#define ANOMALY_05000250 /* Incorrect Bit-Shift of Data Word in Multichannel
+ (TDM) mode in certain conditions */
+#define ANOMALY_05000251 /* Exception not generated for MMR accesses in
+ reserved region */
+#define ANOMALY_05000253 /* Maximum external clock speed for Timers */
+#define ANOMALY_05000258 /* Instruction Cache is corrupted when bits 9 and 12
+ of the ICPLB Data registers differ */
+#define ANOMALY_05000260 /* ICPLB_STATUS MMR register may be corrupted */
+#define ANOMALY_05000261 /* DCPLB_FAULT_ADDR MMR register may be corrupted */
+#define ANOMALY_05000262 /* Stores to data cache may be lost */
+#define ANOMALY_05000263 /* Hardware loop corrupted when taking an ICPLB
+ exception */
+#define ANOMALY_05000264 /* CSYNC/SSYNC/IDLE causes infinite stall in second
+ to last instruction in hardware loop */
+#define ANOMALY_05000276 /* Timing requirements change for External Frame
+ Sync PPI Modes with non-zero PPI_DELAY */
+#define ANOMALY_05000278 /* Disabling Peripherals with DMA running may cause
+ DMA system instability */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+ not restored */
+#define ANOMALY_05000283 /* An MMR write is stalled indefinitely when killed
+ in a particular stage */
+#define ANOMALY_05000287 /* A read will receive incorrect data under certain
+ conditions */
+#define ANOMALY_05000288 /* SPORTs may receive bad data if FIFOs fill up */
+#endif
+
+#endif /* _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf561/bf561.h b/include/asm-blackfin/mach-bf561/bf561.h
new file mode 100644
index 00000000000..96a5d3a47e4
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/bf561.h
@@ -0,0 +1,408 @@
+/*
+ * File: include/asm-blackfin/mach-bf561/bf561.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MACH_BF561_H__
+#define __MACH_BF561_H__
+
+#define SUPPORTED_REVID 0x3
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+#define L1_ISRAM 0xFFA00000
+#define L1_ISRAM_END 0xFFA04000
+#define DATA_BANKA_SRAM 0xFF800000
+#define DATA_BANKA_SRAM_END 0xFF804000
+#define DATA_BANKB_SRAM 0xFF900000
+#define DATA_BANKB_SRAM_END 0xFF904000
+#define L1_DSRAMA 0xFF800000
+#define L1_DSRAMA_END 0xFF804000
+#define L1_DSRAMB 0xFF900000
+#define L1_DSRAMB_END 0xFF904000
+#define L2_SRAM 0xFEB00000
+#define L2_SRAM_END 0xFEB20000
+#define AMB_FLASH 0x20000000
+#define AMB_FLASH_END 0x21000000
+#define AMB_FLASH_LENGTH 0x01000000
+#define L1_ISRAM_LENGTH 0x4000
+#define L1_DSRAMA_LENGTH 0x4000
+#define L1_DSRAMB_LENGTH 0x4000
+#define L2_SRAM_LENGTH 0x20000
+
+/*some misc defines*/
+#define IMASK_IVG15 0x8000
+#define IMASK_IVG14 0x4000
+#define IMASK_IVG13 0x2000
+#define IMASK_IVG12 0x1000
+
+#define IMASK_IVG11 0x0800
+#define IMASK_IVG10 0x0400
+#define IMASK_IVG9 0x0200
+#define IMASK_IVG8 0x0100
+
+#define IMASK_IVG7 0x0080
+#define IMASK_IVGTMR 0x0040
+#define IMASK_IVGHW 0x0020
+
+/***************************
+ * Blackfin Cache setup
+ */
+
+
+#define BLKFIN_ISUBBANKS 4
+#define BLKFIN_IWAYS 4
+#define BLKFIN_ILINES 32
+
+#define BLKFIN_DSUBBANKS 4
+#define BLKFIN_DWAYS 2
+#define BLKFIN_DLINES 64
+
+#define WAY0_L 0x1
+#define WAY1_L 0x2
+#define WAY01_L 0x3
+#define WAY2_L 0x4
+#define WAY02_L 0x5
+#define WAY12_L 0x6
+#define WAY012_L 0x7
+
+#define WAY3_L 0x8
+#define WAY03_L 0x9
+#define WAY13_L 0xA
+#define WAY013_L 0xB
+
+#define WAY32_L 0xC
+#define WAY320_L 0xD
+#define WAY321_L 0xE
+#define WAYALL_L 0xF
+
+#define DMC_ENABLE (2<<2) /*yes, 2, not 1 */
+
+/* IAR0 BIT FIELDS */
+#define PLL_WAKEUP_BIT 0xFFFFFFFF
+#define DMA1_ERROR_BIT 0xFFFFFF0F
+#define DMA2_ERROR_BIT 0xFFFFF0FF
+#define IMDMA_ERROR_BIT 0xFFFF0FFF
+#define PPI1_ERROR_BIT 0xFFF0FFFF
+#define PPI2_ERROR_BIT 0xFF0FFFFF
+#define SPORT0_ERROR_BIT 0xF0FFFFFF
+#define SPORT1_ERROR_BIT 0x0FFFFFFF
+/* IAR1 BIT FIELDS */
+#define SPI_ERROR_BIT 0xFFFFFFFF
+#define UART_ERROR_BIT 0xFFFFFF0F
+#define RESERVED_ERROR_BIT 0xFFFFF0FF
+#define DMA1_0_BIT 0xFFFF0FFF
+#define DMA1_1_BIT 0xFFF0FFFF
+#define DMA1_2_BIT 0xFF0FFFFF
+#define DMA1_3_BIT 0xF0FFFFFF
+#define DMA1_4_BIT 0x0FFFFFFF
+/* IAR2 BIT FIELDS */
+#define DMA1_5_BIT 0xFFFFFFFF
+#define DMA1_6_BIT 0xFFFFFF0F
+#define DMA1_7_BIT 0xFFFFF0FF
+#define DMA1_8_BIT 0xFFFF0FFF
+#define DMA1_9_BIT 0xFFF0FFFF
+#define DMA1_10_BIT 0xFF0FFFFF
+#define DMA1_11_BIT 0xF0FFFFFF
+#define DMA2_0_BIT 0x0FFFFFFF
+/* IAR3 BIT FIELDS */
+#define DMA2_1_BIT 0xFFFFFFFF
+#define DMA2_2_BIT 0xFFFFFF0F
+#define DMA2_3_BIT 0xFFFFF0FF
+#define DMA2_4_BIT 0xFFFF0FFF
+#define DMA2_5_BIT 0xFFF0FFFF
+#define DMA2_6_BIT 0xFF0FFFFF
+#define DMA2_7_BIT 0xF0FFFFFF
+#define DMA2_8_BIT 0x0FFFFFFF
+/* IAR4 BIT FIELDS */
+#define DMA2_9_BIT 0xFFFFFFFF
+#define DMA2_10_BIT 0xFFFFFF0F
+#define DMA2_11_BIT 0xFFFFF0FF
+#define TIMER0_BIT 0xFFFF0FFF
+#define TIMER1_BIT 0xFFF0FFFF
+#define TIMER2_BIT 0xFF0FFFFF
+#define TIMER3_BIT 0xF0FFFFFF
+#define TIMER4_BIT 0x0FFFFFFF
+/* IAR5 BIT FIELDS */
+#define TIMER5_BIT 0xFFFFFFFF
+#define TIMER6_BIT 0xFFFFFF0F
+#define TIMER7_BIT 0xFFFFF0FF
+#define TIMER8_BIT 0xFFFF0FFF
+#define TIMER9_BIT 0xFFF0FFFF
+#define TIMER10_BIT 0xFF0FFFFF
+#define TIMER11_BIT 0xF0FFFFFF
+#define PROG0_INTA_BIT 0x0FFFFFFF
+/* IAR6 BIT FIELDS */
+#define PROG0_INTB_BIT 0xFFFFFFFF
+#define PROG1_INTA_BIT 0xFFFFFF0F
+#define PROG1_INTB_BIT 0xFFFFF0FF
+#define PROG2_INTA_BIT 0xFFFF0FFF
+#define PROG2_INTB_BIT 0xFFF0FFFF
+#define DMA1_WRRD0_BIT 0xFF0FFFFF
+#define DMA1_WRRD1_BIT 0xF0FFFFFF
+#define DMA2_WRRD0_BIT 0x0FFFFFFF
+/* IAR7 BIT FIELDS */
+#define DMA2_WRRD1_BIT 0xFFFFFFFF
+#define IMDMA_WRRD0_BIT 0xFFFFFF0F
+#define IMDMA_WRRD1_BIT 0xFFFFF0FF
+#define WATCH_BIT 0xFFFF0FFF
+#define RESERVED_1_BIT 0xFFF0FFFF
+#define RESERVED_2_BIT 0xFF0FFFFF
+#define SUPPLE_0_BIT 0xF0FFFFFF
+#define SUPPLE_1_BIT 0x0FFFFFFF
+
+/* Miscellaneous Values */
+
+/****************************** EBIU Settings ********************************/
+#define AMBCTL0VAL ((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL ((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#if defined(CONFIG_C_AMBEN_ALL)
+#define V_AMBEN AMBEN_ALL
+#elif defined(CONFIG_C_AMBEN)
+#define V_AMBEN 0x0
+#elif defined(CONFIG_C_AMBEN_B0)
+#define V_AMBEN AMBEN_B0
+#elif defined(CONFIG_C_AMBEN_B0_B1)
+#define V_AMBEN AMBEN_B0_B1
+#elif defined(CONFIG_C_AMBEN_B0_B1_B2)
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+
+#ifdef CONFIG_C_B0PEN
+#define V_B0PEN 0x10
+#else
+#define V_B0PEN 0x00
+#endif
+
+#ifdef CONFIG_C_B1PEN
+#define V_B1PEN 0x20
+#else
+#define V_B1PEN 0x00
+#endif
+
+#ifdef CONFIG_C_B2PEN
+#define V_B2PEN 0x40
+#else
+#define V_B2PEN 0x00
+#endif
+
+#ifdef CONFIG_C_B3PEN
+#define V_B3PEN 0x80
+#else
+#define V_B3PEN 0x00
+#endif
+
+#ifdef CONFIG_C_CDPRIO
+#define V_CDPRIO 0x100
+#else
+#define V_CDPRIO 0x0
+#endif
+
+#define AMGCTLVAL (V_AMBEN | V_AMCKEN | V_CDPRIO | V_B0PEN | V_B1PEN | V_B2PEN | V_B3PEN | 0x0002)
+
+#define MAX_VC 600000000
+#define MIN_VC 50000000
+
+/******************************* PLL Settings ********************************/
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#if defined(ANOMALY_05000273) && (CONFIG_CCLK_DIV == 1)
+#error ANOMALY 05000273, please make sure CCLK is at least 2x SCLK
+#endif
+
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF561
+#define CPU "BF561"
+#define CPUID 0x027bb000
+#endif
+#ifndef CPU
+#define CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM memory size must be a multiple of 4MB!"
+#endif
+#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND 0x200
+#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else /*Write Through */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW | CPLB_DIRTY \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#endif
+
+
+#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY)
+
+#define L2_MEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY)
+
+#define SIZE_1K 0x00000400 /* 1K */
+#define SIZE_4K 0x00001000 /* 4K */
+#define SIZE_1M 0x00100000 /* 1M */
+#define SIZE_4M 0x00400000 /* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for L2 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 64 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1 + 64) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for L2 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1 + 1) * 2)
+
+#if 0 /* comment by mhfan */
+/* Event Vector Table Address */
+#define EVT_EMULATION_ADDR 0xffe02000
+#define EVT_RESET_ADDR 0xffe02004
+#define EVT_NMI_ADDR 0xffe02008
+#define EVT_EXCEPTION_ADDR 0xffe0200c
+#define EVT_GLOBAL_INT_ENB_ADDR 0xffe02010
+#define EVT_HARDWARE_ERROR_ADDR 0xffe02014
+#define EVT_TIMER_ADDR 0xffe02018
+#define EVT_IVG7_ADDR 0xffe0201c
+#define EVT_IVG8_ADDR 0xffe02020
+#define EVT_IVG9_ADDR 0xffe02024
+#define EVT_IVG10_ADDR 0xffe02028
+#define EVT_IVG11_ADDR 0xffe0202c
+#define EVT_IVG12_ADDR 0xffe02030
+#define EVT_IVG13_ADDR 0xffe02034
+#define EVT_IVG14_ADDR 0xffe02038
+#define EVT_IVG15_ADDR 0xffe0203c
+#define EVT_OVERRIDE_ADDR 0xffe02100
+#endif /* comment by mhfan */
+
+#endif /* __MACH_BF561_H__ */
diff --git a/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
new file mode 100644
index 00000000000..23bf76aa345
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
@@ -0,0 +1,108 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS 1
+
+#define OFFSET_THR 0x00 /* Transmit Holding register */
+#define OFFSET_RBR 0x00 /* Receive Buffer register */
+#define OFFSET_DLL 0x00 /* Divisor Latch (Low-Byte) */
+#define OFFSET_IER 0x04 /* Interrupt Enable Register */
+#define OFFSET_DLH 0x04 /* Divisor Latch (High-Byte) */
+#define OFFSET_IIR 0x08 /* Interrupt Identification Register */
+#define OFFSET_LCR 0x0C /* Line Control Register */
+#define OFFSET_MCR 0x10 /* Modem Control Register */
+#define OFFSET_LSR 0x14 /* Line Status Register */
+#define OFFSET_MSR 0x18 /* Modem Status Register */
+#define OFFSET_SCR 0x1C /* SCR Scratch Register */
+#define OFFSET_GCTL 0x24 /* Global Control Register */
+
+#define UART_GET_CHAR(uart) bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart) bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_IER(uart) bfin_read16(((uart)->port.membase + OFFSET_IER))
+#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IIR(uart) bfin_read16(((uart)->port.membase + OFFSET_IIR))
+#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_PUT_IER(uart,v) bfin_write16(((uart)->port.membase + OFFSET_IER),v)
+#define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+# define CONFIG_SERIAL_BFIN_CTSRTS
+# ifndef CONFIG_UART0_CTS_PIN
+# define CONFIG_UART0_CTS_PIN -1
+# endif
+# ifndef CONFIG_UART0_RTS_PIN
+# define CONFIG_UART0_RTS_PIN -1
+# endif
+#endif
+
+struct bfin_serial_port {
+ struct uart_port port;
+ unsigned int old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ int tx_done;
+ int tx_count;
+ struct circ_buf rx_dma_buf;
+ struct timer_list rx_dma_timer;
+ int rx_dma_nrows;
+ unsigned int tx_dma_channel;
+ unsigned int rx_dma_channel;
+ struct work_struct tx_dma_workqueue;
+#else
+ struct work_struct cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int cts_pin;
+ int rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+ unsigned long uart_base_addr;
+ int uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ unsigned int uart_tx_dma_channel;
+ unsigned int uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int uart_cts_pin;
+ int uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+ 0xFFC00400,
+ IRQ_UART_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART_TX,
+ CH_UART_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+ CONFIG_UART0_CTS_PIN,
+ CONFIG_UART0_RTS_PIN,
+#endif
+};
+
+
+int nr_ports = NR_PORTS;
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ if (uart->cts_pin >= 0) {
+ gpio_request(uart->cts_pin, NULL);
+ gpio_direction_input(uart->cts_pin);
+ }
+ if (uart->rts_pin >= 0) {
+ gpio_request(uart->rts_pin, NULL);
+ gpio_direction_input(uart->rts_pin);
+ }
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf561/blackfin.h b/include/asm-blackfin/mach-bf561/blackfin.h
new file mode 100644
index 00000000000..2537c845e8b
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/blackfin.h
@@ -0,0 +1,52 @@
+/*
+ * File: include/asm-blackfin/mach-bf561/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF561_FAMILY
+
+#include "bf561.h"
+#include "mem_map.h"
+#include "defBF561.h"
+#include "anomaly.h"
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#include "cdefBF561.h"
+#endif
+
+#define bfin_read_FIO_FLAG_D() bfin_read_FIO0_FLAG_D()
+#define bfin_write_FIO_FLAG_D(val) bfin_write_FIO0_FLAG_D(val)
+#define bfin_read_FIO_DIR() bfin_read_FIO0_DIR()
+#define bfin_write_FIO_DIR(val) bfin_write_FIO0_DIR(val)
+#define bfin_read_FIO_INEN() bfin_read_FIO0_INEN()
+#define bfin_write_FIO_INEN(val) bfin_write_FIO0_INEN(val)
+
+#endif /* _MACH_BLACKFIN_H_ */
diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h
new file mode 100644
index 00000000000..5dc0ed83544
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/cdefBF561.h
@@ -0,0 +1,1543 @@
+/*
+ * File: include/asm-blackfin/mach-bf561/cdefBF561.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: C POINTERS TO SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_BF561_H
+#define _CDEF_BF561_H
+
+/*
+#if !defined(__ADSPBF561__)
+#warning cdefBF561.h should only be included for BF561 chip.
+#endif
+*/
+/* include all Core registers and bit definitions */
+#include "defBF561.h"
+
+/*include core specific register pointer definitions*/
+#include <asm/mach-common/cdef_LPBlackfin.h>
+
+#include <asm/system.h>
+
+/*********************************************************************************** */
+/* System MMR Register Map */
+/*********************************************************************************** */
+
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+#define bfin_read_PLL_CTL() bfin_read16(PLL_CTL)
+#define bfin_write_PLL_CTL(val) bfin_write16(PLL_CTL,val)
+#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
+#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV,val)
+#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+ unsigned long flags, iwr;
+
+ bfin_write16(VR_CTL, val);
+ __builtin_bfin_ssync();
+ /* Enable the PLL Wakeup bit in SIC IWR */
+ iwr = bfin_read32(SICA_IWR0);
+ /* Only allow PPL Wakeup) */
+ bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+ local_irq_save(flags);
+ asm("IDLE;");
+ local_irq_restore(flags);
+ bfin_write32(SICA_IWR0, iwr);
+}
+#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
+#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
+#define bfin_read_PLL_LOCKCNT() bfin_read16(PLL_LOCKCNT)
+#define bfin_write_PLL_LOCKCNT(val) bfin_write16(PLL_LOCKCNT,val)
+#define bfin_read_CHIPID() bfin_read32(CHIPID)
+
+/* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
+#define bfin_read_SICA_SWRST() bfin_read16(SICA_SWRST)
+#define bfin_write_SICA_SWRST(val) bfin_write16(SICA_SWRST,val)
+#define bfin_read_SICA_SYSCR() bfin_read16(SICA_SYSCR)
+#define bfin_write_SICA_SYSCR(val) bfin_write16(SICA_SYSCR,val)
+#define bfin_read_SICA_RVECT() bfin_read16(SICA_RVECT)
+#define bfin_write_SICA_RVECT(val) bfin_write16(SICA_RVECT,val)
+#define bfin_read_SICA_IMASK() bfin_read32(SICA_IMASK)
+#define bfin_write_SICA_IMASK(val) bfin_write32(SICA_IMASK,val)
+#define bfin_read_SICA_IMASK0() bfin_read32(SICA_IMASK0)
+#define bfin_write_SICA_IMASK0(val) bfin_write32(SICA_IMASK0,val)
+#define bfin_read_SICA_IMASK1() bfin_read32(SICA_IMASK1)
+#define bfin_write_SICA_IMASK1(val) bfin_write32(SICA_IMASK1,val)
+#define bfin_read_SICA_IAR0() bfin_read32(SICA_IAR0)
+#define bfin_write_SICA_IAR0(val) bfin_write32(SICA_IAR0,val)
+#define bfin_read_SICA_IAR1() bfin_read32(SICA_IAR1)
+#define bfin_write_SICA_IAR1(val) bfin_write32(SICA_IAR1,val)
+#define bfin_read_SICA_IAR2() bfin_read32(SICA_IAR2)
+#define bfin_write_SICA_IAR2(val) bfin_write32(SICA_IAR2,val)
+#define bfin_read_SICA_IAR3() bfin_read32(SICA_IAR3)
+#define bfin_write_SICA_IAR3(val) bfin_write32(SICA_IAR3,val)
+#define bfin_read_SICA_IAR4() bfin_read32(SICA_IAR4)
+#define bfin_write_SICA_IAR4(val) bfin_write32(SICA_IAR4,val)
+#define bfin_read_SICA_IAR5() bfin_read32(SICA_IAR5)
+#define bfin_write_SICA_IAR5(val) bfin_write32(SICA_IAR5,val)
+#define bfin_read_SICA_IAR6() bfin_read32(SICA_IAR6)
+#define bfin_write_SICA_IAR6(val) bfin_write32(SICA_IAR6,val)
+#define bfin_read_SICA_IAR7() bfin_read32(SICA_IAR7)
+#define bfin_write_SICA_IAR7(val) bfin_write32(SICA_IAR7,val)
+#define bfin_read_SICA_ISR0() bfin_read32(SICA_ISR0)
+#define bfin_write_SICA_ISR0(val) bfin_write32(SICA_ISR0,val)
+#define bfin_read_SICA_ISR1() bfin_read32(SICA_ISR1)
+#define bfin_write_SICA_ISR1(val) bfin_write32(SICA_ISR1,val)
+#define bfin_read_SICA_IWR0() bfin_read32(SICA_IWR0)
+#define bfin_write_SICA_IWR0(val) bfin_write32(SICA_IWR0,val)
+#define bfin_read_SICA_IWR1() bfin_read32(SICA_IWR1)
+#define bfin_write_SICA_IWR1(val) bfin_write32(SICA_IWR1,val)
+
+/* System Reset and Interrupt Controller registers for Core B (0xFFC0 1100-0xFFC0 11FF) */
+#define bfin_read_SICB_SWRST() bfin_read16(SICB_SWRST)
+#define bfin_write_SICB_SWRST(val) bfin_write16(SICB_SWRST,val)
+#define bfin_read_SICB_SYSCR() bfin_read16(SICB_SYSCR)
+#define bfin_write_SICB_SYSCR(val) bfin_write16(SICB_SYSCR,val)
+#define bfin_read_SICB_RVECT() bfin_read16(SICB_RVECT)
+#define bfin_write_SICB_RVECT(val) bfin_write16(SICB_RVECT,val)
+#define bfin_read_SICB_IMASK0() bfin_read32(SICB_IMASK0)
+#define bfin_write_SICB_IMASK0(val) bfin_write32(SICB_IMASK0,val)
+#define bfin_read_SICB_IMASK1() bfin_read32(SICB_IMASK1)
+#define bfin_write_SICB_IMASK1(val) bfin_write32(SICB_IMASK1,val)
+#define bfin_read_SICB_IAR0() bfin_read32(SICB_IAR0)
+#define bfin_write_SICB_IAR0(val) bfin_write32(SICB_IAR0,val)
+#define bfin_read_SICB_IAR1() bfin_read32(SICB_IAR1)
+#define bfin_write_SICB_IAR1(val) bfin_write32(SICB_IAR1,val)
+#define bfin_read_SICB_IAR2() bfin_read32(SICB_IAR2)
+#define bfin_write_SICB_IAR2(val) bfin_write32(SICB_IAR2,val)
+#define bfin_read_SICB_IAR3() bfin_read32(SICB_IAR3)
+#define bfin_write_SICB_IAR3(val) bfin_write32(SICB_IAR3,val)
+#define bfin_read_SICB_IAR4() bfin_read32(SICB_IAR4)
+#define bfin_write_SICB_IAR4(val) bfin_write32(SICB_IAR4,val)
+#define bfin_read_SICB_IAR5() bfin_read32(SICB_IAR5)
+#define bfin_write_SICB_IAR5(val) bfin_write32(SICB_IAR5,val)
+#define bfin_read_SICB_IAR6() bfin_read32(SICB_IAR6)
+#define bfin_write_SICB_IAR6(val) bfin_write32(SICB_IAR6,val)
+#define bfin_read_SICB_IAR7() bfin_read32(SICB_IAR7)
+#define bfin_write_SICB_IAR7(val) bfin_write32(SICB_IAR7,val)
+#define bfin_read_SICB_ISR0() bfin_read32(SICB_ISR0)
+#define bfin_write_SICB_ISR0(val) bfin_write32(SICB_ISR0,val)
+#define bfin_read_SICB_ISR1() bfin_read32(SICB_ISR1)
+#define bfin_write_SICB_ISR1(val) bfin_write32(SICB_ISR1,val)
+#define bfin_read_SICB_IWR0() bfin_read32(SICB_IWR0)
+#define bfin_write_SICB_IWR0(val) bfin_write32(SICB_IWR0,val)
+#define bfin_read_SICB_IWR1() bfin_read32(SICB_IWR1)
+#define bfin_write_SICB_IWR1(val) bfin_write32(SICB_IWR1,val)
+/* Watchdog Timer registers for Core A (0xFFC0 0200-0xFFC0 02FF) */
+#define bfin_read_WDOGA_CTL() bfin_read16(WDOGA_CTL)
+#define bfin_write_WDOGA_CTL(val) bfin_write16(WDOGA_CTL,val)
+#define bfin_read_WDOGA_CNT() bfin_read32(WDOGA_CNT)
+#define bfin_write_WDOGA_CNT(val) bfin_write32(WDOGA_CNT,val)
+#define bfin_read_WDOGA_STAT() bfin_read32(WDOGA_STAT)
+#define bfin_write_WDOGA_STAT(val) bfin_write32(WDOGA_STAT,val)
+
+/* Watchdog Timer registers for Core B (0xFFC0 1200-0xFFC0 12FF) */
+#define bfin_read_WDOGB_CTL() bfin_read16(WDOGB_CTL)
+#define bfin_write_WDOGB_CTL(val) bfin_write16(WDOGB_CTL,val)
+#define bfin_read_WDOGB_CNT() bfin_read32(WDOGB_CNT)
+#define bfin_write_WDOGB_CNT(val) bfin_write32(WDOGB_CNT,val)
+#define bfin_read_WDOGB_STAT() bfin_read32(WDOGB_STAT)
+#define bfin_write_WDOGB_STAT(val) bfin_write32(WDOGB_STAT,val)
+
+/* UART Controller (0xFFC00400 - 0xFFC004FF) */
+#define bfin_read_UART_THR() bfin_read16(UART_THR)
+#define bfin_write_UART_THR(val) bfin_write16(UART_THR,val)
+#define bfin_read_UART_RBR() bfin_read16(UART_RBR)
+#define bfin_write_UART_RBR(val) bfin_write16(UART_RBR,val)
+#define bfin_read_UART_DLL() bfin_read16(UART_DLL)
+#define bfin_write_UART_DLL(val) bfin_write16(UART_DLL,val)
+#define bfin_read_UART_IER() bfin_read16(UART_IER)
+#define bfin_write_UART_IER(val) bfin_write16(UART_IER,val)
+#define bfin_read_UART_DLH() bfin_read16(UART_DLH)
+#define bfin_write_UART_DLH(val) bfin_write16(UART_DLH,val)
+#define bfin_read_UART_IIR() bfin_read16(UART_IIR)
+#define bfin_write_UART_IIR(val) bfin_write16(UART_IIR,val)
+#define bfin_read_UART_LCR() bfin_read16(UART_LCR)
+#define bfin_write_UART_LCR(val) bfin_write16(UART_LCR,val)
+#define bfin_read_UART_MCR() bfin_read16(UART_MCR)
+#define bfin_write_UART_MCR(val) bfin_write16(UART_MCR,val)
+#define bfin_read_UART_LSR() bfin_read16(UART_LSR)
+#define bfin_write_UART_LSR(val) bfin_write16(UART_LSR,val)
+#define bfin_read_UART_MSR() bfin_read16(UART_MSR)
+#define bfin_write_UART_MSR(val) bfin_write16(UART_MSR,val)
+#define bfin_read_UART_SCR() bfin_read16(UART_SCR)
+#define bfin_write_UART_SCR(val) bfin_write16(UART_SCR,val)
+#define bfin_read_UART_GCTL() bfin_read16(UART_GCTL)
+#define bfin_write_UART_GCTL(val) bfin_write16(UART_GCTL,val)
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define bfin_read_SPI_CTL() bfin_read16(SPI_CTL)
+#define bfin_write_SPI_CTL(val) bfin_write16(SPI_CTL,val)
+#define bfin_read_SPI_FLG() bfin_read16(SPI_FLG)
+#define bfin_write_SPI_FLG(val) bfin_write16(SPI_FLG,val)
+#define bfin_read_SPI_STAT() bfin_read16(SPI_STAT)
+#define bfin_write_SPI_STAT(val) bfin_write16(SPI_STAT,val)
+#define bfin_read_SPI_TDBR() bfin_read16(SPI_TDBR)
+#define bfin_write_SPI_TDBR(val) bfin_write16(SPI_TDBR,val)
+#define bfin_read_SPI_RDBR() bfin_read16(SPI_RDBR)
+#define bfin_write_SPI_RDBR(val) bfin_write16(SPI_RDBR,val)
+#define bfin_read_SPI_BAUD() bfin_read16(SPI_BAUD)
+#define bfin_write_SPI_BAUD(val) bfin_write16(SPI_BAUD,val)
+#define bfin_read_SPI_SHADOW() bfin_read16(SPI_SHADOW)
+#define bfin_write_SPI_SHADOW(val) bfin_write16(SPI_SHADOW,val)
+
+/* Timer 0-7 registers (0xFFC0 0600-0xFFC0 06FF) */
+#define bfin_read_TIMER0_CONFIG() bfin_read16(TIMER0_CONFIG)
+#define bfin_write_TIMER0_CONFIG(val) bfin_write16(TIMER0_CONFIG,val)
+#define bfin_read_TIMER0_COUNTER() bfin_read32(TIMER0_COUNTER)
+#define bfin_write_TIMER0_COUNTER(val) bfin_write32(TIMER0_COUNTER,val)
+#define bfin_read_TIMER0_PERIOD() bfin_read32(TIMER0_PERIOD)
+#define bfin_write_TIMER0_PERIOD(val) bfin_write32(TIMER0_PERIOD,val)
+#define bfin_read_TIMER0_WIDTH() bfin_read32(TIMER0_WIDTH)
+#define bfin_write_TIMER0_WIDTH(val) bfin_write32(TIMER0_WIDTH,val)
+#define bfin_read_TIMER1_CONFIG() bfin_read16(TIMER1_CONFIG)
+#define bfin_write_TIMER1_CONFIG(val) bfin_write16(TIMER1_CONFIG,val)
+#define bfin_read_TIMER1_COUNTER() bfin_read32(TIMER1_COUNTER)
+#define bfin_write_TIMER1_COUNTER(val) bfin_write32(TIMER1_COUNTER,val)
+#define bfin_read_TIMER1_PERIOD() bfin_read32(TIMER1_PERIOD)
+#define bfin_write_TIMER1_PERIOD(val) bfin_write32(TIMER1_PERIOD,val)
+#define bfin_read_TIMER1_WIDTH() bfin_read32(TIMER1_WIDTH)
+#define bfin_write_TIMER1_WIDTH(val) bfin_write32(TIMER1_WIDTH,val)
+#define bfin_read_TIMER2_CONFIG() bfin_read16(TIMER2_CONFIG)
+#define bfin_write_TIMER2_CONFIG(val) bfin_write16(TIMER2_CONFIG,val)
+#define bfin_read_TIMER2_COUNTER() bfin_read32(TIMER2_COUNTER)
+#define bfin_write_TIMER2_COUNTER(val) bfin_write32(TIMER2_COUNTER,val)
+#define bfin_read_TIMER2_PERIOD() bfin_read32(TIMER2_PERIOD)
+#define bfin_write_TIMER2_PERIOD(val) bfin_write32(TIMER2_PERIOD,val)
+#define bfin_read_TIMER2_WIDTH() bfin_read32(TIMER2_WIDTH)
+#define bfin_write_TIMER2_WIDTH(val) bfin_write32(TIMER2_WIDTH,val)
+#define bfin_read_TIMER3_CONFIG() bfin_read16(TIMER3_CONFIG)
+#define bfin_write_TIMER3_CONFIG(val) bfin_write16(TIMER3_CONFIG,val)
+#define bfin_read_TIMER3_COUNTER() bfin_read32(TIMER3_COUNTER)
+#define bfin_write_TIMER3_COUNTER(val) bfin_write32(TIMER3_COUNTER,val)
+#define bfin_read_TIMER3_PERIOD() bfin_read32(TIMER3_PERIOD)
+#define bfin_write_TIMER3_PERIOD(val) bfin_write32(TIMER3_PERIOD,val)
+#define bfin_read_TIMER3_WIDTH() bfin_read32(TIMER3_WIDTH)
+#define bfin_write_TIMER3_WIDTH(val) bfin_write32(TIMER3_WIDTH,val)
+#define bfin_read_TIMER4_CONFIG() bfin_read16(TIMER4_CONFIG)
+#define bfin_write_TIMER4_CONFIG(val) bfin_write16(TIMER4_CONFIG,val)
+#define bfin_read_TIMER4_COUNTER() bfin_read32(TIMER4_COUNTER)
+#define bfin_write_TIMER4_COUNTER(val) bfin_write32(TIMER4_COUNTER,val)
+#define bfin_read_TIMER4_PERIOD() bfin_read32(TIMER4_PERIOD)
+#define bfin_write_TIMER4_PERIOD(val) bfin_write32(TIMER4_PERIOD,val)
+#define bfin_read_TIMER4_WIDTH() bfin_read32(TIMER4_WIDTH)
+#define bfin_write_TIMER4_WIDTH(val) bfin_write32(TIMER4_WIDTH,val)
+#define bfin_read_TIMER5_CONFIG() bfin_read16(TIMER5_CONFIG)
+#define bfin_write_TIMER5_CONFIG(val) bfin_write16(TIMER5_CONFIG,val)
+#define bfin_read_TIMER5_COUNTER() bfin_read32(TIMER5_COUNTER)
+#define bfin_write_TIMER5_COUNTER(val) bfin_write32(TIMER5_COUNTER,val)
+#define bfin_read_TIMER5_PERIOD() bfin_read32(TIMER5_PERIOD)
+#define bfin_write_TIMER5_PERIOD(val) bfin_write32(TIMER5_PERIOD,val)
+#define bfin_read_TIMER5_WIDTH() bfin_read32(TIMER5_WIDTH)
+#define bfin_write_TIMER5_WIDTH(val) bfin_write32(TIMER5_WIDTH,val)
+#define bfin_read_TIMER6_CONFIG() bfin_read16(TIMER6_CONFIG)
+#define bfin_write_TIMER6_CONFIG(val) bfin_write16(TIMER6_CONFIG,val)
+#define bfin_read_TIMER6_COUNTER() bfin_read32(TIMER6_COUNTER)
+#define bfin_write_TIMER6_COUNTER(val) bfin_write32(TIMER6_COUNTER,val)
+#define bfin_read_TIMER6_PERIOD() bfin_read32(TIMER6_PERIOD)
+#define bfin_write_TIMER6_PERIOD(val) bfin_write32(TIMER6_PERIOD,val)
+#define bfin_read_TIMER6_WIDTH() bfin_read32(TIMER6_WIDTH)
+#define bfin_write_TIMER6_WIDTH(val) bfin_write32(TIMER6_WIDTH,val)
+#define bfin_read_TIMER7_CONFIG() bfin_read16(TIMER7_CONFIG)
+#define bfin_write_TIMER7_CONFIG(val) bfin_write16(TIMER7_CONFIG,val)
+#define bfin_read_TIMER7_COUNTER() bfin_read32(TIMER7_COUNTER)
+#define bfin_write_TIMER7_COUNTER(val) bfin_write32(TIMER7_COUNTER,val)
+#define bfin_read_TIMER7_PERIOD() bfin_read32(TIMER7_PERIOD)
+#define bfin_write_TIMER7_PERIOD(val) bfin_write32(TIMER7_PERIOD,val)
+#define bfin_read_TIMER7_WIDTH() bfin_read32(TIMER7_WIDTH)
+#define bfin_write_TIMER7_WIDTH(val) bfin_write32(TIMER7_WIDTH,val)
+
+/* Timer registers 8-11 (0xFFC0 1600-0xFFC0 16FF) */
+#define bfin_read_TMRS8_ENABLE() bfin_read16(TMRS8_ENABLE)
+#define bfin_write_TMRS8_ENABLE(val) bfin_write16(TMRS8_ENABLE,val)
+#define bfin_read_TMRS8_DISABLE() bfin_read16(TMRS8_DISABLE)
+#define bfin_write_TMRS8_DISABLE(val) bfin_write16(TMRS8_DISABLE,val)
+#define bfin_read_TMRS8_STATUS() bfin_read32(TMRS8_STATUS)
+#define bfin_write_TMRS8_STATUS(val) bfin_write32(TMRS8_STATUS,val)
+#define bfin_read_TIMER8_CONFIG() bfin_read16(TIMER8_CONFIG)
+#define bfin_write_TIMER8_CONFIG(val) bfin_write16(TIMER8_CONFIG,val)
+#define bfin_read_TIMER8_COUNTER() bfin_read32(TIMER8_COUNTER)
+#define bfin_write_TIMER8_COUNTER(val) bfin_write32(TIMER8_COUNTER,val)
+#define bfin_read_TIMER8_PERIOD() bfin_read32(TIMER8_PERIOD)
+#define bfin_write_TIMER8_PERIOD(val) bfin_write32(TIMER8_PERIOD,val)
+#define bfin_read_TIMER8_WIDTH() bfin_read32(TIMER8_WIDTH)
+#define bfin_write_TIMER8_WIDTH(val) bfin_write32(TIMER8_WIDTH,val)
+#define bfin_read_TIMER9_CONFIG() bfin_read16(TIMER9_CONFIG)
+#define bfin_write_TIMER9_CONFIG(val) bfin_write16(TIMER9_CONFIG,val)
+#define bfin_read_TIMER9_COUNTER() bfin_read32(TIMER9_COUNTER)
+#define bfin_write_TIMER9_COUNTER(val) bfin_write32(TIMER9_COUNTER,val)
+#define bfin_read_TIMER9_PERIOD() bfin_read32(TIMER9_PERIOD)
+#define bfin_write_TIMER9_PERIOD(val) bfin_write32(TIMER9_PERIOD,val)
+#define bfin_read_TIMER9_WIDTH() bfin_read32(TIMER9_WIDTH)
+#define bfin_write_TIMER9_WIDTH(val) bfin_write32(TIMER9_WIDTH,val)
+#define bfin_read_TIMER10_CONFIG() bfin_read16(TIMER10_CONFIG)
+#define bfin_write_TIMER10_CONFIG(val) bfin_write16(TIMER10_CONFIG,val)
+#define bfin_read_TIMER10_COUNTER() bfin_read32(TIMER10_COUNTER)
+#define bfin_write_TIMER10_COUNTER(val) bfin_write32(TIMER10_COUNTER,val)
+#define bfin_read_TIMER10_PERIOD() bfin_read32(TIMER10_PERIOD)
+#define bfin_write_TIMER10_PERIOD(val) bfin_write32(TIMER10_PERIOD,val)
+#define bfin_read_TIMER10_WIDTH() bfin_read32(TIMER10_WIDTH)
+#define bfin_write_TIMER10_WIDTH(val) bfin_write32(TIMER10_WIDTH,val)
+#define bfin_read_TIMER11_CONFIG() bfin_read16(TIMER11_CONFIG)
+#define bfin_write_TIMER11_CONFIG(val) bfin_write16(TIMER11_CONFIG,val)
+#define bfin_read_TIMER11_COUNTER() bfin_read32(TIMER11_COUNTER)
+#define bfin_write_TIMER11_COUNTER(val) bfin_write32(TIMER11_COUNTER,val)
+#define bfin_read_TIMER11_PERIOD() bfin_read32(TIMER11_PERIOD)
+#define bfin_write_TIMER11_PERIOD(val) bfin_write32(TIMER11_PERIOD,val)
+#define bfin_read_TIMER11_WIDTH() bfin_read32(TIMER11_WIDTH)
+#define bfin_write_TIMER11_WIDTH(val) bfin_write32(TIMER11_WIDTH,val)
+#define bfin_read_TMRS4_ENABLE() bfin_read16(TMRS4_ENABLE)
+#define bfin_write_TMRS4_ENABLE(val) bfin_write16(TMRS4_ENABLE,val)
+#define bfin_read_TMRS4_DISABLE() bfin_read16(TMRS4_DISABLE)
+#define bfin_write_TMRS4_DISABLE(val) bfin_write16(TMRS4_DISABLE,val)
+#define bfin_read_TMRS4_STATUS() bfin_read32(TMRS4_STATUS)
+#define bfin_write_TMRS4_STATUS(val) bfin_write32(TMRS4_STATUS,val)
+
+/* Programmable Flag 0 registers (0xFFC0 0700-0xFFC0 07FF) */
+#define bfin_read_FIO0_FLAG_D() bfin_read16(FIO0_FLAG_D)
+#define bfin_write_FIO0_FLAG_D(val) bfin_write16(FIO0_FLAG_D,val)
+#define bfin_read_FIO0_FLAG_C() bfin_read16(FIO0_FLAG_C)
+#define bfin_write_FIO0_FLAG_C(val) bfin_write16(FIO0_FLAG_C,val)
+#define bfin_read_FIO0_FLAG_S() bfin_read16(FIO0_FLAG_S)
+#define bfin_write_FIO0_FLAG_S(val) bfin_write16(FIO0_FLAG_S,val)
+#define bfin_read_FIO0_FLAG_T() bfin_read16(FIO0_FLAG_T)
+#define bfin_write_FIO0_FLAG_T(val) bfin_write16(FIO0_FLAG_T,val)
+#define bfin_read_FIO0_MASKA_D() bfin_read16(FIO0_MASKA_D)
+#define bfin_write_FIO0_MASKA_D(val) bfin_write16(FIO0_MASKA_D,val)
+#define bfin_read_FIO0_MASKA_C() bfin_read16(FIO0_MASKA_C)
+#define bfin_write_FIO0_MASKA_C(val) bfin_write16(FIO0_MASKA_C,val)
+#define bfin_read_FIO0_MASKA_S() bfin_read16(FIO0_MASKA_S)
+#define bfin_write_FIO0_MASKA_S(val) bfin_write16(FIO0_MASKA_S,val)
+#define bfin_read_FIO0_MASKA_T() bfin_read16(FIO0_MASKA_T)
+#define bfin_write_FIO0_MASKA_T(val) bfin_write16(FIO0_MASKA_T,val)
+#define bfin_read_FIO0_MASKB_D() bfin_read16(FIO0_MASKB_D)
+#define bfin_write_FIO0_MASKB_D(val) bfin_write16(FIO0_MASKB_D,val)
+#define bfin_read_FIO0_MASKB_C() bfin_read16(FIO0_MASKB_C)
+#define bfin_write_FIO0_MASKB_C(val) bfin_write16(FIO0_MASKB_C,val)
+#define bfin_read_FIO0_MASKB_S() bfin_read16(FIO0_MASKB_S)
+#define bfin_write_FIO0_MASKB_S(val) bfin_write16(FIO0_MASKB_S,val)
+#define bfin_read_FIO0_MASKB_T() bfin_read16(FIO0_MASKB_T)
+#define bfin_write_FIO0_MASKB_T(val) bfin_write16(FIO0_MASKB_T,val)
+#define bfin_read_FIO0_DIR() bfin_read16(FIO0_DIR)
+#define bfin_write_FIO0_DIR(val) bfin_write16(FIO0_DIR,val)
+#define bfin_read_FIO0_POLAR() bfin_read16(FIO0_POLAR)
+#define bfin_write_FIO0_POLAR(val) bfin_write16(FIO0_POLAR,val)
+#define bfin_read_FIO0_EDGE() bfin_read16(FIO0_EDGE)
+#define bfin_write_FIO0_EDGE(val) bfin_write16(FIO0_EDGE,val)
+#define bfin_read_FIO0_BOTH() bfin_read16(FIO0_BOTH)
+#define bfin_write_FIO0_BOTH(val) bfin_write16(FIO0_BOTH,val)
+#define bfin_read_FIO0_INEN() bfin_read16(FIO0_INEN)
+#define bfin_write_FIO0_INEN(val) bfin_write16(FIO0_INEN,val)
+/* Programmable Flag 1 registers (0xFFC0 1500-0xFFC0 15FF) */
+#define bfin_read_FIO1_FLAG_D() bfin_read16(FIO1_FLAG_D)
+#define bfin_write_FIO1_FLAG_D(val) bfin_write16(FIO1_FLAG_D,val)
+#define bfin_read_FIO1_FLAG_C() bfin_read16(FIO1_FLAG_C)
+#define bfin_write_FIO1_FLAG_C(val) bfin_write16(FIO1_FLAG_C,val)
+#define bfin_read_FIO1_FLAG_S() bfin_read16(FIO1_FLAG_S)
+#define bfin_write_FIO1_FLAG_S(val) bfin_write16(FIO1_FLAG_S,val)
+#define bfin_read_FIO1_FLAG_T() bfin_read16(FIO1_FLAG_T)
+#define bfin_write_FIO1_FLAG_T(val) bfin_write16(FIO1_FLAG_T,val)
+#define bfin_read_FIO1_MASKA_D() bfin_read16(FIO1_MASKA_D)
+#define bfin_write_FIO1_MASKA_D(val) bfin_write16(FIO1_MASKA_D,val)
+#define bfin_read_FIO1_MASKA_C() bfin_read16(FIO1_MASKA_C)
+#define bfin_write_FIO1_MASKA_C(val) bfin_write16(FIO1_MASKA_C,val)
+#define bfin_read_FIO1_MASKA_S() bfin_read16(FIO1_MASKA_S)
+#define bfin_write_FIO1_MASKA_S(val) bfin_write16(FIO1_MASKA_S,val)
+#define bfin_read_FIO1_MASKA_T() bfin_read16(FIO1_MASKA_T)
+#define bfin_write_FIO1_MASKA_T(val) bfin_write16(FIO1_MASKA_T,val)
+#define bfin_read_FIO1_MASKB_D() bfin_read16(FIO1_MASKB_D)
+#define bfin_write_FIO1_MASKB_D(val) bfin_write16(FIO1_MASKB_D,val)
+#define bfin_read_FIO1_MASKB_C() bfin_read16(FIO1_MASKB_C)
+#define bfin_write_FIO1_MASKB_C(val) bfin_write16(FIO1_MASKB_C,val)
+#define bfin_read_FIO1_MASKB_S() bfin_read16(FIO1_MASKB_S)
+#define bfin_write_FIO1_MASKB_S(val) bfin_write16(FIO1_MASKB_S,val)
+#define bfin_read_FIO1_MASKB_T() bfin_read16(FIO1_MASKB_T)
+#define bfin_write_FIO1_MASKB_T(val) bfin_write16(FIO1_MASKB_T,val)
+#define bfin_read_FIO1_DIR() bfin_read16(FIO1_DIR)
+#define bfin_write_FIO1_DIR(val) bfin_write16(FIO1_DIR,val)
+#define bfin_read_FIO1_POLAR() bfin_read16(FIO1_POLAR)
+#define bfin_write_FIO1_POLAR(val) bfin_write16(FIO1_POLAR,val)
+#define bfin_read_FIO1_EDGE() bfin_read16(FIO1_EDGE)
+#define bfin_write_FIO1_EDGE(val) bfin_write16(FIO1_EDGE,val)
+#define bfin_read_FIO1_BOTH() bfin_read16(FIO1_BOTH)
+#define bfin_write_FIO1_BOTH(val) bfin_write16(FIO1_BOTH,val)
+#define bfin_read_FIO1_INEN() bfin_read16(FIO1_INEN)
+#define bfin_write_FIO1_INEN(val) bfin_write16(FIO1_INEN,val)
+/* Programmable Flag registers (0xFFC0 1700-0xFFC0 17FF) */
+#define bfin_read_FIO2_FLAG_D() bfin_read16(FIO2_FLAG_D)
+#define bfin_write_FIO2_FLAG_D(val) bfin_write16(FIO2_FLAG_D,val)
+#define bfin_read_FIO2_FLAG_C() bfin_read16(FIO2_FLAG_C)
+#define bfin_write_FIO2_FLAG_C(val) bfin_write16(FIO2_FLAG_C,val)
+#define bfin_read_FIO2_FLAG_S() bfin_read16(FIO2_FLAG_S)
+#define bfin_write_FIO2_FLAG_S(val) bfin_write16(FIO2_FLAG_S,val)
+#define bfin_read_FIO2_FLAG_T() bfin_read16(FIO2_FLAG_T)
+#define bfin_write_FIO2_FLAG_T(val) bfin_write16(FIO2_FLAG_T,val)
+#define bfin_read_FIO2_MASKA_D() bfin_read16(FIO2_MASKA_D)
+#define bfin_write_FIO2_MASKA_D(val) bfin_write16(FIO2_MASKA_D,val)
+#define bfin_read_FIO2_MASKA_C() bfin_read16(FIO2_MASKA_C)
+#define bfin_write_FIO2_MASKA_C(val) bfin_write16(FIO2_MASKA_C,val)
+#define bfin_read_FIO2_MASKA_S() bfin_read16(FIO2_MASKA_S)
+#define bfin_write_FIO2_MASKA_S(val) bfin_write16(FIO2_MASKA_S,val)
+#define bfin_read_FIO2_MASKA_T() bfin_read16(FIO2_MASKA_T)
+#define bfin_write_FIO2_MASKA_T(val) bfin_write16(FIO2_MASKA_T,val)
+#define bfin_read_FIO2_MASKB_D() bfin_read16(FIO2_MASKB_D)
+#define bfin_write_FIO2_MASKB_D(val) bfin_write16(FIO2_MASKB_D,val)
+#define bfin_read_FIO2_MASKB_C() bfin_read16(FIO2_MASKB_C)
+#define bfin_write_FIO2_MASKB_C(val) bfin_write16(FIO2_MASKB_C,val)
+#define bfin_read_FIO2_MASKB_S() bfin_read16(FIO2_MASKB_S)
+#define bfin_write_FIO2_MASKB_S(val) bfin_write16(FIO2_MASKB_S,val)
+#define bfin_read_FIO2_MASKB_T() bfin_read16(FIO2_MASKB_T)
+#define bfin_write_FIO2_MASKB_T(val) bfin_write16(FIO2_MASKB_T,val)
+#define bfin_read_FIO2_DIR() bfin_read16(FIO2_DIR)
+#define bfin_write_FIO2_DIR(val) bfin_write16(FIO2_DIR,val)
+#define bfin_read_FIO2_POLAR() bfin_read16(FIO2_POLAR)
+#define bfin_write_FIO2_POLAR(val) bfin_write16(FIO2_POLAR,val)
+#define bfin_read_FIO2_EDGE() bfin_read16(FIO2_EDGE)
+#define bfin_write_FIO2_EDGE(val) bfin_write16(FIO2_EDGE,val)
+#define bfin_read_FIO2_BOTH() bfin_read16(FIO2_BOTH)
+#define bfin_write_FIO2_BOTH(val) bfin_write16(FIO2_BOTH,val)
+#define bfin_read_FIO2_INEN() bfin_read16(FIO2_INEN)
+#define bfin_write_FIO2_INEN(val) bfin_write16(FIO2_INEN,val)
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define bfin_read_SPORT0_TCR1() bfin_read16(SPORT0_TCR1)
+#define bfin_write_SPORT0_TCR1(val) bfin_write16(SPORT0_TCR1,val)
+#define bfin_read_SPORT0_TCR2() bfin_read16(SPORT0_TCR2)
+#define bfin_write_SPORT0_TCR2(val) bfin_write16(SPORT0_TCR2,val)
+#define bfin_read_SPORT0_TCLKDIV() bfin_read16(SPORT0_TCLKDIV)
+#define bfin_write_SPORT0_TCLKDIV(val) bfin_write16(SPORT0_TCLKDIV,val)
+#define bfin_read_SPORT0_TFSDIV() bfin_read16(SPORT0_TFSDIV)
+#define bfin_write_SPORT0_TFSDIV(val) bfin_write16(SPORT0_TFSDIV,val)
+#define bfin_read_SPORT0_TX() bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX(val) bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX() bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX(val) bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX32() bfin_read32(SPORT0_TX)
+#define bfin_write_SPORT0_TX32(val) bfin_write32(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX32() bfin_read32(SPORT0_RX)
+#define bfin_write_SPORT0_RX32(val) bfin_write32(SPORT0_RX,val)
+#define bfin_read_SPORT0_TX16() bfin_read16(SPORT0_TX)
+#define bfin_write_SPORT0_TX16(val) bfin_write16(SPORT0_TX,val)
+#define bfin_read_SPORT0_RX16() bfin_read16(SPORT0_RX)
+#define bfin_write_SPORT0_RX16(val) bfin_write16(SPORT0_RX,val)
+#define bfin_read_SPORT0_RCR1() bfin_read16(SPORT0_RCR1)
+#define bfin_write_SPORT0_RCR1(val) bfin_write16(SPORT0_RCR1,val)
+#define bfin_read_SPORT0_RCR2() bfin_read16(SPORT0_RCR2)
+#define bfin_write_SPORT0_RCR2(val) bfin_write16(SPORT0_RCR2,val)
+#define bfin_read_SPORT0_RCLKDIV() bfin_read16(SPORT0_RCLKDIV)
+#define bfin_write_SPORT0_RCLKDIV(val) bfin_write16(SPORT0_RCLKDIV,val)
+#define bfin_read_SPORT0_RFSDIV() bfin_read16(SPORT0_RFSDIV)
+#define bfin_write_SPORT0_RFSDIV(val) bfin_write16(SPORT0_RFSDIV,val)
+#define bfin_read_SPORT0_STAT() bfin_read16(SPORT0_STAT)
+#define bfin_write_SPORT0_STAT(val) bfin_write16(SPORT0_STAT,val)
+#define bfin_read_SPORT0_CHNL() bfin_read16(SPORT0_CHNL)
+#define bfin_write_SPORT0_CHNL(val) bfin_write16(SPORT0_CHNL,val)
+#define bfin_read_SPORT0_MCMC1() bfin_read16(SPORT0_MCMC1)
+#define bfin_write_SPORT0_MCMC1(val) bfin_write16(SPORT0_MCMC1,val)
+#define bfin_read_SPORT0_MCMC2() bfin_read16(SPORT0_MCMC2)
+#define bfin_write_SPORT0_MCMC2(val) bfin_write16(SPORT0_MCMC2,val)
+#define bfin_read_SPORT0_MTCS0() bfin_read32(SPORT0_MTCS0)
+#define bfin_write_SPORT0_MTCS0(val) bfin_write32(SPORT0_MTCS0,val)
+#define bfin_read_SPORT0_MTCS1() bfin_read32(SPORT0_MTCS1)
+#define bfin_write_SPORT0_MTCS1(val) bfin_write32(SPORT0_MTCS1,val)
+#define bfin_read_SPORT0_MTCS2() bfin_read32(SPORT0_MTCS2)
+#define bfin_write_SPORT0_MTCS2(val) bfin_write32(SPORT0_MTCS2,val)
+#define bfin_read_SPORT0_MTCS3() bfin_read32(SPORT0_MTCS3)
+#define bfin_write_SPORT0_MTCS3(val) bfin_write32(SPORT0_MTCS3,val)
+#define bfin_read_SPORT0_MRCS0() bfin_read32(SPORT0_MRCS0)
+#define bfin_write_SPORT0_MRCS0(val) bfin_write32(SPORT0_MRCS0,val)
+#define bfin_read_SPORT0_MRCS1() bfin_read32(SPORT0_MRCS1)
+#define bfin_write_SPORT0_MRCS1(val) bfin_write32(SPORT0_MRCS1,val)
+#define bfin_read_SPORT0_MRCS2() bfin_read32(SPORT0_MRCS2)
+#define bfin_write_SPORT0_MRCS2(val) bfin_write32(SPORT0_MRCS2,val)
+#define bfin_read_SPORT0_MRCS3() bfin_read32(SPORT0_MRCS3)
+#define bfin_write_SPORT0_MRCS3(val) bfin_write32(SPORT0_MRCS3,val)
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define bfin_read_SPORT1_TCR1() bfin_read16(SPORT1_TCR1)
+#define bfin_write_SPORT1_TCR1(val) bfin_write16(SPORT1_TCR1,val)
+#define bfin_read_SPORT1_TCR2() bfin_read16(SPORT1_TCR2)
+#define bfin_write_SPORT1_TCR2(val) bfin_write16(SPORT1_TCR2,val)
+#define bfin_read_SPORT1_TCLKDIV() bfin_read16(SPORT1_TCLKDIV)
+#define bfin_write_SPORT1_TCLKDIV(val) bfin_write16(SPORT1_TCLKDIV,val)
+#define bfin_read_SPORT1_TFSDIV() bfin_read16(SPORT1_TFSDIV)
+#define bfin_write_SPORT1_TFSDIV(val) bfin_write16(SPORT1_TFSDIV,val)
+#define bfin_read_SPORT1_TX() bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX(val) bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX() bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX(val) bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX32() bfin_read32(SPORT1_TX)
+#define bfin_write_SPORT1_TX32(val) bfin_write32(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX32() bfin_read32(SPORT1_RX)
+#define bfin_write_SPORT1_RX32(val) bfin_write32(SPORT1_RX,val)
+#define bfin_read_SPORT1_TX16() bfin_read16(SPORT1_TX)
+#define bfin_write_SPORT1_TX16(val) bfin_write16(SPORT1_TX,val)
+#define bfin_read_SPORT1_RX16() bfin_read16(SPORT1_RX)
+#define bfin_write_SPORT1_RX16(val) bfin_write16(SPORT1_RX,val)
+#define bfin_read_SPORT1_RCR1() bfin_read16(SPORT1_RCR1)
+#define bfin_write_SPORT1_RCR1(val) bfin_write16(SPORT1_RCR1,val)
+#define bfin_read_SPORT1_RCR2() bfin_read16(SPORT1_RCR2)
+#define bfin_write_SPORT1_RCR2(val) bfin_write16(SPORT1_RCR2,val)
+#define bfin_read_SPORT1_RCLKDIV() bfin_read16(SPORT1_RCLKDIV)
+#define bfin_write_SPORT1_RCLKDIV(val) bfin_write16(SPORT1_RCLKDIV,val)
+#define bfin_read_SPORT1_RFSDIV() bfin_read16(SPORT1_RFSDIV)
+#define bfin_write_SPORT1_RFSDIV(val) bfin_write16(SPORT1_RFSDIV,val)
+#define bfin_read_SPORT1_STAT() bfin_read16(SPORT1_STAT)
+#define bfin_write_SPORT1_STAT(val) bfin_write16(SPORT1_STAT,val)
+#define bfin_read_SPORT1_CHNL() bfin_read16(SPORT1_CHNL)
+#define bfin_write_SPORT1_CHNL(val) bfin_write16(SPORT1_CHNL,val)
+#define bfin_read_SPORT1_MCMC1() bfin_read16(SPORT1_MCMC1)
+#define bfin_write_SPORT1_MCMC1(val) bfin_write16(SPORT1_MCMC1,val)
+#define bfin_read_SPORT1_MCMC2() bfin_read16(SPORT1_MCMC2)
+#define bfin_write_SPORT1_MCMC2(val) bfin_write16(SPORT1_MCMC2,val)
+#define bfin_read_SPORT1_MTCS0() bfin_read32(SPORT1_MTCS0)
+#define bfin_write_SPORT1_MTCS0(val) bfin_write32(SPORT1_MTCS0,val)
+#define bfin_read_SPORT1_MTCS1() bfin_read32(SPORT1_MTCS1)
+#define bfin_write_SPORT1_MTCS1(val) bfin_write32(SPORT1_MTCS1,val)
+#define bfin_read_SPORT1_MTCS2() bfin_read32(SPORT1_MTCS2)
+#define bfin_write_SPORT1_MTCS2(val) bfin_write32(SPORT1_MTCS2,val)
+#define bfin_read_SPORT1_MTCS3() bfin_read32(SPORT1_MTCS3)
+#define bfin_write_SPORT1_MTCS3(val) bfin_write32(SPORT1_MTCS3,val)
+#define bfin_read_SPORT1_MRCS0() bfin_read32(SPORT1_MRCS0)
+#define bfin_write_SPORT1_MRCS0(val) bfin_write32(SPORT1_MRCS0,val)
+#define bfin_read_SPORT1_MRCS1() bfin_read32(SPORT1_MRCS1)
+#define bfin_write_SPORT1_MRCS1(val) bfin_write32(SPORT1_MRCS1,val)
+#define bfin_read_SPORT1_MRCS2() bfin_read32(SPORT1_MRCS2)
+#define bfin_write_SPORT1_MRCS2(val) bfin_write32(SPORT1_MRCS2,val)
+#define bfin_read_SPORT1_MRCS3() bfin_read32(SPORT1_MRCS3)
+#define bfin_write_SPORT1_MRCS3(val) bfin_write32(SPORT1_MRCS3,val)
+/* Asynchronous Memory Controller - External Bus Interface Unit */
+#define bfin_read_EBIU_AMGCTL() bfin_read16(EBIU_AMGCTL)
+#define bfin_write_EBIU_AMGCTL(val) bfin_write16(EBIU_AMGCTL,val)
+#define bfin_read_EBIU_AMBCTL0() bfin_read32(EBIU_AMBCTL0)
+#define bfin_write_EBIU_AMBCTL0(val) bfin_write32(EBIU_AMBCTL0,val)
+#define bfin_read_EBIU_AMBCTL1() bfin_read32(EBIU_AMBCTL1)
+#define bfin_write_EBIU_AMBCTL1(val) bfin_write32(EBIU_AMBCTL1,val)
+/* SDRAM Controller External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+#define bfin_read_EBIU_SDGCTL() bfin_read32(EBIU_SDGCTL)
+#define bfin_write_EBIU_SDGCTL(val) bfin_write32(EBIU_SDGCTL,val)
+#define bfin_read_EBIU_SDBCTL() bfin_read32(EBIU_SDBCTL)
+#define bfin_write_EBIU_SDBCTL(val) bfin_write32(EBIU_SDBCTL,val)
+#define bfin_read_EBIU_SDRRC() bfin_read16(EBIU_SDRRC)
+#define bfin_write_EBIU_SDRRC(val) bfin_write16(EBIU_SDRRC,val)
+#define bfin_read_EBIU_SDSTAT() bfin_read16(EBIU_SDSTAT)
+#define bfin_write_EBIU_SDSTAT(val) bfin_write16(EBIU_SDSTAT,val)
+/* Parallel Peripheral Interface (PPI) 0 registers (0xFFC0 1000-0xFFC0 10FF) */
+#define bfin_read_PPI0_CONTROL() bfin_read16(PPI0_CONTROL)
+#define bfin_write_PPI0_CONTROL(val) bfin_write16(PPI0_CONTROL,val)
+#define bfin_read_PPI0_STATUS() bfin_read16(PPI0_STATUS)
+#define bfin_write_PPI0_STATUS(val) bfin_write16(PPI0_STATUS,val)
+#define bfin_read_PPI0_COUNT() bfin_read16(PPI0_COUNT)
+#define bfin_write_PPI0_COUNT(val) bfin_write16(PPI0_COUNT,val)
+#define bfin_read_PPI0_DELAY() bfin_read16(PPI0_DELAY)
+#define bfin_write_PPI0_DELAY(val) bfin_write16(PPI0_DELAY,val)
+#define bfin_read_PPI0_FRAME() bfin_read16(PPI0_FRAME)
+#define bfin_write_PPI0_FRAME(val) bfin_write16(PPI0_FRAME,val)
+/* Parallel Peripheral Interface (PPI) 1 registers (0xFFC0 1300-0xFFC0 13FF) */
+#define bfin_read_PPI1_CONTROL() bfin_read16(PPI1_CONTROL)
+#define bfin_write_PPI1_CONTROL(val) bfin_write16(PPI1_CONTROL,val)
+#define bfin_read_PPI1_STATUS() bfin_read16(PPI1_STATUS)
+#define bfin_write_PPI1_STATUS(val) bfin_write16(PPI1_STATUS,val)
+#define bfin_read_PPI1_COUNT() bfin_read16(PPI1_COUNT)
+#define bfin_write_PPI1_COUNT(val) bfin_write16(PPI1_COUNT,val)
+#define bfin_read_PPI1_DELAY() bfin_read16(PPI1_DELAY)
+#define bfin_write_PPI1_DELAY(val) bfin_write16(PPI1_DELAY,val)
+#define bfin_read_PPI1_FRAME() bfin_read16(PPI1_FRAME)
+#define bfin_write_PPI1_FRAME(val) bfin_write16(PPI1_FRAME,val)
+/*DMA traffic control registers */
+#define bfin_read_DMA1_TC_PER() bfin_read16(DMA1_TC_PER)
+#define bfin_write_DMA1_TC_PER(val) bfin_write16(DMA1_TC_PER,val)
+#define bfin_read_DMA1_TC_CNT() bfin_read16(DMA1_TC_CNT)
+#define bfin_write_DMA1_TC_CNT(val) bfin_write16(DMA1_TC_CNT,val)
+#define bfin_read_DMA2_TC_PER() bfin_read16(DMA2_TC_PER)
+#define bfin_write_DMA2_TC_PER(val) bfin_write16(DMA2_TC_PER,val)
+#define bfin_read_DMA2_TC_CNT() bfin_read16(DMA2_TC_CNT)
+#define bfin_write_DMA2_TC_CNT(val) bfin_write16(DMA2_TC_CNT,val)
+/* DMA1 Controller registers (0xFFC0 1C00-0xFFC0 1FFF) */
+#define bfin_read_DMA1_0_CONFIG() bfin_read16(DMA1_0_CONFIG)
+#define bfin_write_DMA1_0_CONFIG(val) bfin_write16(DMA1_0_CONFIG,val)
+#define bfin_read_DMA1_0_NEXT_DESC_PTR() bfin_read32(DMA1_0_NEXT_DESC_PTR)
+#define bfin_write_DMA1_0_NEXT_DESC_PTR(val) bfin_write32(DMA1_0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_0_START_ADDR() bfin_read32(DMA1_0_START_ADDR)
+#define bfin_write_DMA1_0_START_ADDR(val) bfin_write32(DMA1_0_START_ADDR,val)
+#define bfin_read_DMA1_0_X_COUNT() bfin_read16(DMA1_0_X_COUNT)
+#define bfin_write_DMA1_0_X_COUNT(val) bfin_write16(DMA1_0_X_COUNT,val)
+#define bfin_read_DMA1_0_Y_COUNT() bfin_read16(DMA1_0_Y_COUNT)
+#define bfin_write_DMA1_0_Y_COUNT(val) bfin_write16(DMA1_0_Y_COUNT,val)
+#define bfin_read_DMA1_0_X_MODIFY() bfin_read16(DMA1_0_X_MODIFY)
+#define bfin_write_DMA1_0_X_MODIFY(val) bfin_write16(DMA1_0_X_MODIFY,val)
+#define bfin_read_DMA1_0_Y_MODIFY() bfin_read16(DMA1_0_Y_MODIFY)
+#define bfin_write_DMA1_0_Y_MODIFY(val) bfin_write16(DMA1_0_Y_MODIFY,val)
+#define bfin_read_DMA1_0_CURR_DESC_PTR() bfin_read32(DMA1_0_CURR_DESC_PTR)
+#define bfin_write_DMA1_0_CURR_DESC_PTR(val) bfin_write32(DMA1_0_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_0_CURR_ADDR() bfin_read32(DMA1_0_CURR_ADDR)
+#define bfin_write_DMA1_0_CURR_ADDR(val) bfin_write32(DMA1_0_CURR_ADDR,val)
+#define bfin_read_DMA1_0_CURR_X_COUNT() bfin_read16(DMA1_0_CURR_X_COUNT)
+#define bfin_write_DMA1_0_CURR_X_COUNT(val) bfin_write16(DMA1_0_CURR_X_COUNT,val)
+#define bfin_read_DMA1_0_CURR_Y_COUNT() bfin_read16(DMA1_0_CURR_Y_COUNT)
+#define bfin_write_DMA1_0_CURR_Y_COUNT(val) bfin_write16(DMA1_0_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_0_IRQ_STATUS() bfin_read16(DMA1_0_IRQ_STATUS)
+#define bfin_write_DMA1_0_IRQ_STATUS(val) bfin_write16(DMA1_0_IRQ_STATUS,val)
+#define bfin_read_DMA1_0_PERIPHERAL_MAP() bfin_read16(DMA1_0_PERIPHERAL_MAP)
+#define bfin_write_DMA1_0_PERIPHERAL_MAP(val) bfin_write16(DMA1_0_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_1_CONFIG() bfin_read16(DMA1_1_CONFIG)
+#define bfin_write_DMA1_1_CONFIG(val) bfin_write16(DMA1_1_CONFIG,val)
+#define bfin_read_DMA1_1_NEXT_DESC_PTR() bfin_read32(DMA1_1_NEXT_DESC_PTR)
+#define bfin_write_DMA1_1_NEXT_DESC_PTR(val) bfin_write32(DMA1_1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_1_START_ADDR() bfin_read32(DMA1_1_START_ADDR)
+#define bfin_write_DMA1_1_START_ADDR(val) bfin_write32(DMA1_1_START_ADDR,val)
+#define bfin_read_DMA1_1_X_COUNT() bfin_read16(DMA1_1_X_COUNT)
+#define bfin_write_DMA1_1_X_COUNT(val) bfin_write16(DMA1_1_X_COUNT,val)
+#define bfin_read_DMA1_1_Y_COUNT() bfin_read16(DMA1_1_Y_COUNT)
+#define bfin_write_DMA1_1_Y_COUNT(val) bfin_write16(DMA1_1_Y_COUNT,val)
+#define bfin_read_DMA1_1_X_MODIFY() bfin_read16(DMA1_1_X_MODIFY)
+#define bfin_write_DMA1_1_X_MODIFY(val) bfin_write16(DMA1_1_X_MODIFY,val)
+#define bfin_read_DMA1_1_Y_MODIFY() bfin_read16(DMA1_1_Y_MODIFY)
+#define bfin_write_DMA1_1_Y_MODIFY(val) bfin_write16(DMA1_1_Y_MODIFY,val)
+#define bfin_read_DMA1_1_CURR_DESC_PTR() bfin_read32(DMA1_1_CURR_DESC_PTR)
+#define bfin_write_DMA1_1_CURR_DESC_PTR(val) bfin_write32(DMA1_1_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_1_CURR_ADDR() bfin_read32(DMA1_1_CURR_ADDR)
+#define bfin_write_DMA1_1_CURR_ADDR(val) bfin_write32(DMA1_1_CURR_ADDR,val)
+#define bfin_read_DMA1_1_CURR_X_COUNT() bfin_read16(DMA1_1_CURR_X_COUNT)
+#define bfin_write_DMA1_1_CURR_X_COUNT(val) bfin_write16(DMA1_1_CURR_X_COUNT,val)
+#define bfin_read_DMA1_1_CURR_Y_COUNT() bfin_read16(DMA1_1_CURR_Y_COUNT)
+#define bfin_write_DMA1_1_CURR_Y_COUNT(val) bfin_write16(DMA1_1_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_1_IRQ_STATUS() bfin_read16(DMA1_1_IRQ_STATUS)
+#define bfin_write_DMA1_1_IRQ_STATUS(val) bfin_write16(DMA1_1_IRQ_STATUS,val)
+#define bfin_read_DMA1_1_PERIPHERAL_MAP() bfin_read16(DMA1_1_PERIPHERAL_MAP)
+#define bfin_write_DMA1_1_PERIPHERAL_MAP(val) bfin_write16(DMA1_1_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_2_CONFIG() bfin_read16(DMA1_2_CONFIG)
+#define bfin_write_DMA1_2_CONFIG(val) bfin_write16(DMA1_2_CONFIG,val)
+#define bfin_read_DMA1_2_NEXT_DESC_PTR() bfin_read32(DMA1_2_NEXT_DESC_PTR)
+#define bfin_write_DMA1_2_NEXT_DESC_PTR(val) bfin_write32(DMA1_2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_2_START_ADDR() bfin_read32(DMA1_2_START_ADDR)
+#define bfin_write_DMA1_2_START_ADDR(val) bfin_write32(DMA1_2_START_ADDR,val)
+#define bfin_read_DMA1_2_X_COUNT() bfin_read16(DMA1_2_X_COUNT)
+#define bfin_write_DMA1_2_X_COUNT(val) bfin_write16(DMA1_2_X_COUNT,val)
+#define bfin_read_DMA1_2_Y_COUNT() bfin_read16(DMA1_2_Y_COUNT)
+#define bfin_write_DMA1_2_Y_COUNT(val) bfin_write16(DMA1_2_Y_COUNT,val)
+#define bfin_read_DMA1_2_X_MODIFY() bfin_read16(DMA1_2_X_MODIFY)
+#define bfin_write_DMA1_2_X_MODIFY(val) bfin_write16(DMA1_2_X_MODIFY,val)
+#define bfin_read_DMA1_2_Y_MODIFY() bfin_read16(DMA1_2_Y_MODIFY)
+#define bfin_write_DMA1_2_Y_MODIFY(val) bfin_write16(DMA1_2_Y_MODIFY,val)
+#define bfin_read_DMA1_2_CURR_DESC_PTR() bfin_read32(DMA1_2_CURR_DESC_PTR)
+#define bfin_write_DMA1_2_CURR_DESC_PTR(val) bfin_write32(DMA1_2_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_2_CURR_ADDR() bfin_read32(DMA1_2_CURR_ADDR)
+#define bfin_write_DMA1_2_CURR_ADDR(val) bfin_write32(DMA1_2_CURR_ADDR,val)
+#define bfin_read_DMA1_2_CURR_X_COUNT() bfin_read16(DMA1_2_CURR_X_COUNT)
+#define bfin_write_DMA1_2_CURR_X_COUNT(val) bfin_write16(DMA1_2_CURR_X_COUNT,val)
+#define bfin_read_DMA1_2_CURR_Y_COUNT() bfin_read16(DMA1_2_CURR_Y_COUNT)
+#define bfin_write_DMA1_2_CURR_Y_COUNT(val) bfin_write16(DMA1_2_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_2_IRQ_STATUS() bfin_read16(DMA1_2_IRQ_STATUS)
+#define bfin_write_DMA1_2_IRQ_STATUS(val) bfin_write16(DMA1_2_IRQ_STATUS,val)
+#define bfin_read_DMA1_2_PERIPHERAL_MAP() bfin_read16(DMA1_2_PERIPHERAL_MAP)
+#define bfin_write_DMA1_2_PERIPHERAL_MAP(val) bfin_write16(DMA1_2_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_3_CONFIG() bfin_read16(DMA1_3_CONFIG)
+#define bfin_write_DMA1_3_CONFIG(val) bfin_write16(DMA1_3_CONFIG,val)
+#define bfin_read_DMA1_3_NEXT_DESC_PTR() bfin_read32(DMA1_3_NEXT_DESC_PTR)
+#define bfin_write_DMA1_3_NEXT_DESC_PTR(val) bfin_write32(DMA1_3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_3_START_ADDR() bfin_read32(DMA1_3_START_ADDR)
+#define bfin_write_DMA1_3_START_ADDR(val) bfin_write32(DMA1_3_START_ADDR,val)
+#define bfin_read_DMA1_3_X_COUNT() bfin_read16(DMA1_3_X_COUNT)
+#define bfin_write_DMA1_3_X_COUNT(val) bfin_write16(DMA1_3_X_COUNT,val)
+#define bfin_read_DMA1_3_Y_COUNT() bfin_read16(DMA1_3_Y_COUNT)
+#define bfin_write_DMA1_3_Y_COUNT(val) bfin_write16(DMA1_3_Y_COUNT,val)
+#define bfin_read_DMA1_3_X_MODIFY() bfin_read16(DMA1_3_X_MODIFY)
+#define bfin_write_DMA1_3_X_MODIFY(val) bfin_write16(DMA1_3_X_MODIFY,val)
+#define bfin_read_DMA1_3_Y_MODIFY() bfin_read16(DMA1_3_Y_MODIFY)
+#define bfin_write_DMA1_3_Y_MODIFY(val) bfin_write16(DMA1_3_Y_MODIFY,val)
+#define bfin_read_DMA1_3_CURR_DESC_PTR() bfin_read32(DMA1_3_CURR_DESC_PTR)
+#define bfin_write_DMA1_3_CURR_DESC_PTR(val) bfin_write32(DMA1_3_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_3_CURR_ADDR() bfin_read32(DMA1_3_CURR_ADDR)
+#define bfin_write_DMA1_3_CURR_ADDR(val) bfin_write32(DMA1_3_CURR_ADDR,val)
+#define bfin_read_DMA1_3_CURR_X_COUNT() bfin_read16(DMA1_3_CURR_X_COUNT)
+#define bfin_write_DMA1_3_CURR_X_COUNT(val) bfin_write16(DMA1_3_CURR_X_COUNT,val)
+#define bfin_read_DMA1_3_CURR_Y_COUNT() bfin_read16(DMA1_3_CURR_Y_COUNT)
+#define bfin_write_DMA1_3_CURR_Y_COUNT(val) bfin_write16(DMA1_3_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_3_IRQ_STATUS() bfin_read16(DMA1_3_IRQ_STATUS)
+#define bfin_write_DMA1_3_IRQ_STATUS(val) bfin_write16(DMA1_3_IRQ_STATUS,val)
+#define bfin_read_DMA1_3_PERIPHERAL_MAP() bfin_read16(DMA1_3_PERIPHERAL_MAP)
+#define bfin_write_DMA1_3_PERIPHERAL_MAP(val) bfin_write16(DMA1_3_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_4_CONFIG() bfin_read16(DMA1_4_CONFIG)
+#define bfin_write_DMA1_4_CONFIG(val) bfin_write16(DMA1_4_CONFIG,val)
+#define bfin_read_DMA1_4_NEXT_DESC_PTR() bfin_read32(DMA1_4_NEXT_DESC_PTR)
+#define bfin_write_DMA1_4_NEXT_DESC_PTR(val) bfin_write32(DMA1_4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_4_START_ADDR() bfin_read32(DMA1_4_START_ADDR)
+#define bfin_write_DMA1_4_START_ADDR(val) bfin_write32(DMA1_4_START_ADDR,val)
+#define bfin_read_DMA1_4_X_COUNT() bfin_read16(DMA1_4_X_COUNT)
+#define bfin_write_DMA1_4_X_COUNT(val) bfin_write16(DMA1_4_X_COUNT,val)
+#define bfin_read_DMA1_4_Y_COUNT() bfin_read16(DMA1_4_Y_COUNT)
+#define bfin_write_DMA1_4_Y_COUNT(val) bfin_write16(DMA1_4_Y_COUNT,val)
+#define bfin_read_DMA1_4_X_MODIFY() bfin_read16(DMA1_4_X_MODIFY)
+#define bfin_write_DMA1_4_X_MODIFY(val) bfin_write16(DMA1_4_X_MODIFY,val)
+#define bfin_read_DMA1_4_Y_MODIFY() bfin_read16(DMA1_4_Y_MODIFY)
+#define bfin_write_DMA1_4_Y_MODIFY(val) bfin_write16(DMA1_4_Y_MODIFY,val)
+#define bfin_read_DMA1_4_CURR_DESC_PTR() bfin_read32(DMA1_4_CURR_DESC_PTR)
+#define bfin_write_DMA1_4_CURR_DESC_PTR(val) bfin_write32(DMA1_4_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_4_CURR_ADDR() bfin_read32(DMA1_4_CURR_ADDR)
+#define bfin_write_DMA1_4_CURR_ADDR(val) bfin_write32(DMA1_4_CURR_ADDR,val)
+#define bfin_read_DMA1_4_CURR_X_COUNT() bfin_read16(DMA1_4_CURR_X_COUNT)
+#define bfin_write_DMA1_4_CURR_X_COUNT(val) bfin_write16(DMA1_4_CURR_X_COUNT,val)
+#define bfin_read_DMA1_4_CURR_Y_COUNT() bfin_read16(DMA1_4_CURR_Y_COUNT)
+#define bfin_write_DMA1_4_CURR_Y_COUNT(val) bfin_write16(DMA1_4_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_4_IRQ_STATUS() bfin_read16(DMA1_4_IRQ_STATUS)
+#define bfin_write_DMA1_4_IRQ_STATUS(val) bfin_write16(DMA1_4_IRQ_STATUS,val)
+#define bfin_read_DMA1_4_PERIPHERAL_MAP() bfin_read16(DMA1_4_PERIPHERAL_MAP)
+#define bfin_write_DMA1_4_PERIPHERAL_MAP(val) bfin_write16(DMA1_4_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_5_CONFIG() bfin_read16(DMA1_5_CONFIG)
+#define bfin_write_DMA1_5_CONFIG(val) bfin_write16(DMA1_5_CONFIG,val)
+#define bfin_read_DMA1_5_NEXT_DESC_PTR() bfin_read32(DMA1_5_NEXT_DESC_PTR)
+#define bfin_write_DMA1_5_NEXT_DESC_PTR(val) bfin_write32(DMA1_5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_5_START_ADDR() bfin_read32(DMA1_5_START_ADDR)
+#define bfin_write_DMA1_5_START_ADDR(val) bfin_write32(DMA1_5_START_ADDR,val)
+#define bfin_read_DMA1_5_X_COUNT() bfin_read16(DMA1_5_X_COUNT)
+#define bfin_write_DMA1_5_X_COUNT(val) bfin_write16(DMA1_5_X_COUNT,val)
+#define bfin_read_DMA1_5_Y_COUNT() bfin_read16(DMA1_5_Y_COUNT)
+#define bfin_write_DMA1_5_Y_COUNT(val) bfin_write16(DMA1_5_Y_COUNT,val)
+#define bfin_read_DMA1_5_X_MODIFY() bfin_read16(DMA1_5_X_MODIFY)
+#define bfin_write_DMA1_5_X_MODIFY(val) bfin_write16(DMA1_5_X_MODIFY,val)
+#define bfin_read_DMA1_5_Y_MODIFY() bfin_read16(DMA1_5_Y_MODIFY)
+#define bfin_write_DMA1_5_Y_MODIFY(val) bfin_write16(DMA1_5_Y_MODIFY,val)
+#define bfin_read_DMA1_5_CURR_DESC_PTR() bfin_read32(DMA1_5_CURR_DESC_PTR)
+#define bfin_write_DMA1_5_CURR_DESC_PTR(val) bfin_write32(DMA1_5_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_5_CURR_ADDR() bfin_read32(DMA1_5_CURR_ADDR)
+#define bfin_write_DMA1_5_CURR_ADDR(val) bfin_write32(DMA1_5_CURR_ADDR,val)
+#define bfin_read_DMA1_5_CURR_X_COUNT() bfin_read16(DMA1_5_CURR_X_COUNT)
+#define bfin_write_DMA1_5_CURR_X_COUNT(val) bfin_write16(DMA1_5_CURR_X_COUNT,val)
+#define bfin_read_DMA1_5_CURR_Y_COUNT() bfin_read16(DMA1_5_CURR_Y_COUNT)
+#define bfin_write_DMA1_5_CURR_Y_COUNT(val) bfin_write16(DMA1_5_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_5_IRQ_STATUS() bfin_read16(DMA1_5_IRQ_STATUS)
+#define bfin_write_DMA1_5_IRQ_STATUS(val) bfin_write16(DMA1_5_IRQ_STATUS,val)
+#define bfin_read_DMA1_5_PERIPHERAL_MAP() bfin_read16(DMA1_5_PERIPHERAL_MAP)
+#define bfin_write_DMA1_5_PERIPHERAL_MAP(val) bfin_write16(DMA1_5_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_6_CONFIG() bfin_read16(DMA1_6_CONFIG)
+#define bfin_write_DMA1_6_CONFIG(val) bfin_write16(DMA1_6_CONFIG,val)
+#define bfin_read_DMA1_6_NEXT_DESC_PTR() bfin_read32(DMA1_6_NEXT_DESC_PTR)
+#define bfin_write_DMA1_6_NEXT_DESC_PTR(val) bfin_write32(DMA1_6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_6_START_ADDR() bfin_read32(DMA1_6_START_ADDR)
+#define bfin_write_DMA1_6_START_ADDR(val) bfin_write32(DMA1_6_START_ADDR,val)
+#define bfin_read_DMA1_6_X_COUNT() bfin_read16(DMA1_6_X_COUNT)
+#define bfin_write_DMA1_6_X_COUNT(val) bfin_write16(DMA1_6_X_COUNT,val)
+#define bfin_read_DMA1_6_Y_COUNT() bfin_read16(DMA1_6_Y_COUNT)
+#define bfin_write_DMA1_6_Y_COUNT(val) bfin_write16(DMA1_6_Y_COUNT,val)
+#define bfin_read_DMA1_6_X_MODIFY() bfin_read16(DMA1_6_X_MODIFY)
+#define bfin_write_DMA1_6_X_MODIFY(val) bfin_write16(DMA1_6_X_MODIFY,val)
+#define bfin_read_DMA1_6_Y_MODIFY() bfin_read16(DMA1_6_Y_MODIFY)
+#define bfin_write_DMA1_6_Y_MODIFY(val) bfin_write16(DMA1_6_Y_MODIFY,val)
+#define bfin_read_DMA1_6_CURR_DESC_PTR() bfin_read32(DMA1_6_CURR_DESC_PTR)
+#define bfin_write_DMA1_6_CURR_DESC_PTR(val) bfin_write32(DMA1_6_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_6_CURR_ADDR() bfin_read32(DMA1_6_CURR_ADDR)
+#define bfin_write_DMA1_6_CURR_ADDR(val) bfin_write32(DMA1_6_CURR_ADDR,val)
+#define bfin_read_DMA1_6_CURR_X_COUNT() bfin_read16(DMA1_6_CURR_X_COUNT)
+#define bfin_write_DMA1_6_CURR_X_COUNT(val) bfin_write16(DMA1_6_CURR_X_COUNT,val)
+#define bfin_read_DMA1_6_CURR_Y_COUNT() bfin_read16(DMA1_6_CURR_Y_COUNT)
+#define bfin_write_DMA1_6_CURR_Y_COUNT(val) bfin_write16(DMA1_6_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_6_IRQ_STATUS() bfin_read16(DMA1_6_IRQ_STATUS)
+#define bfin_write_DMA1_6_IRQ_STATUS(val) bfin_write16(DMA1_6_IRQ_STATUS,val)
+#define bfin_read_DMA1_6_PERIPHERAL_MAP() bfin_read16(DMA1_6_PERIPHERAL_MAP)
+#define bfin_write_DMA1_6_PERIPHERAL_MAP(val) bfin_write16(DMA1_6_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_7_CONFIG() bfin_read16(DMA1_7_CONFIG)
+#define bfin_write_DMA1_7_CONFIG(val) bfin_write16(DMA1_7_CONFIG,val)
+#define bfin_read_DMA1_7_NEXT_DESC_PTR() bfin_read32(DMA1_7_NEXT_DESC_PTR)
+#define bfin_write_DMA1_7_NEXT_DESC_PTR(val) bfin_write32(DMA1_7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_7_START_ADDR() bfin_read32(DMA1_7_START_ADDR)
+#define bfin_write_DMA1_7_START_ADDR(val) bfin_write32(DMA1_7_START_ADDR,val)
+#define bfin_read_DMA1_7_X_COUNT() bfin_read16(DMA1_7_X_COUNT)
+#define bfin_write_DMA1_7_X_COUNT(val) bfin_write16(DMA1_7_X_COUNT,val)
+#define bfin_read_DMA1_7_Y_COUNT() bfin_read16(DMA1_7_Y_COUNT)
+#define bfin_write_DMA1_7_Y_COUNT(val) bfin_write16(DMA1_7_Y_COUNT,val)
+#define bfin_read_DMA1_7_X_MODIFY() bfin_read16(DMA1_7_X_MODIFY)
+#define bfin_write_DMA1_7_X_MODIFY(val) bfin_write16(DMA1_7_X_MODIFY,val)
+#define bfin_read_DMA1_7_Y_MODIFY() bfin_read16(DMA1_7_Y_MODIFY)
+#define bfin_write_DMA1_7_Y_MODIFY(val) bfin_write16(DMA1_7_Y_MODIFY,val)
+#define bfin_read_DMA1_7_CURR_DESC_PTR() bfin_read32(DMA1_7_CURR_DESC_PTR)
+#define bfin_write_DMA1_7_CURR_DESC_PTR(val) bfin_write32(DMA1_7_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_7_CURR_ADDR() bfin_read32(DMA1_7_CURR_ADDR)
+#define bfin_write_DMA1_7_CURR_ADDR(val) bfin_write32(DMA1_7_CURR_ADDR,val)
+#define bfin_read_DMA1_7_CURR_X_COUNT() bfin_read16(DMA1_7_CURR_X_COUNT)
+#define bfin_write_DMA1_7_CURR_X_COUNT(val) bfin_write16(DMA1_7_CURR_X_COUNT,val)
+#define bfin_read_DMA1_7_CURR_Y_COUNT() bfin_read16(DMA1_7_CURR_Y_COUNT)
+#define bfin_write_DMA1_7_CURR_Y_COUNT(val) bfin_write16(DMA1_7_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_7_IRQ_STATUS() bfin_read16(DMA1_7_IRQ_STATUS)
+#define bfin_write_DMA1_7_IRQ_STATUS(val) bfin_write16(DMA1_7_IRQ_STATUS,val)
+#define bfin_read_DMA1_7_PERIPHERAL_MAP() bfin_read16(DMA1_7_PERIPHERAL_MAP)
+#define bfin_write_DMA1_7_PERIPHERAL_MAP(val) bfin_write16(DMA1_7_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_8_CONFIG() bfin_read16(DMA1_8_CONFIG)
+#define bfin_write_DMA1_8_CONFIG(val) bfin_write16(DMA1_8_CONFIG,val)
+#define bfin_read_DMA1_8_NEXT_DESC_PTR() bfin_read32(DMA1_8_NEXT_DESC_PTR)
+#define bfin_write_DMA1_8_NEXT_DESC_PTR(val) bfin_write32(DMA1_8_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_8_START_ADDR() bfin_read32(DMA1_8_START_ADDR)
+#define bfin_write_DMA1_8_START_ADDR(val) bfin_write32(DMA1_8_START_ADDR,val)
+#define bfin_read_DMA1_8_X_COUNT() bfin_read16(DMA1_8_X_COUNT)
+#define bfin_write_DMA1_8_X_COUNT(val) bfin_write16(DMA1_8_X_COUNT,val)
+#define bfin_read_DMA1_8_Y_COUNT() bfin_read16(DMA1_8_Y_COUNT)
+#define bfin_write_DMA1_8_Y_COUNT(val) bfin_write16(DMA1_8_Y_COUNT,val)
+#define bfin_read_DMA1_8_X_MODIFY() bfin_read16(DMA1_8_X_MODIFY)
+#define bfin_write_DMA1_8_X_MODIFY(val) bfin_write16(DMA1_8_X_MODIFY,val)
+#define bfin_read_DMA1_8_Y_MODIFY() bfin_read16(DMA1_8_Y_MODIFY)
+#define bfin_write_DMA1_8_Y_MODIFY(val) bfin_write16(DMA1_8_Y_MODIFY,val)
+#define bfin_read_DMA1_8_CURR_DESC_PTR() bfin_read32(DMA1_8_CURR_DESC_PTR)
+#define bfin_write_DMA1_8_CURR_DESC_PTR(val) bfin_write32(DMA1_8_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_8_CURR_ADDR() bfin_read32(DMA1_8_CURR_ADDR)
+#define bfin_write_DMA1_8_CURR_ADDR(val) bfin_write32(DMA1_8_CURR_ADDR,val)
+#define bfin_read_DMA1_8_CURR_X_COUNT() bfin_read16(DMA1_8_CURR_X_COUNT)
+#define bfin_write_DMA1_8_CURR_X_COUNT(val) bfin_write16(DMA1_8_CURR_X_COUNT,val)
+#define bfin_read_DMA1_8_CURR_Y_COUNT() bfin_read16(DMA1_8_CURR_Y_COUNT)
+#define bfin_write_DMA1_8_CURR_Y_COUNT(val) bfin_write16(DMA1_8_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_8_IRQ_STATUS() bfin_read16(DMA1_8_IRQ_STATUS)
+#define bfin_write_DMA1_8_IRQ_STATUS(val) bfin_write16(DMA1_8_IRQ_STATUS,val)
+#define bfin_read_DMA1_8_PERIPHERAL_MAP() bfin_read16(DMA1_8_PERIPHERAL_MAP)
+#define bfin_write_DMA1_8_PERIPHERAL_MAP(val) bfin_write16(DMA1_8_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_9_CONFIG() bfin_read16(DMA1_9_CONFIG)
+#define bfin_write_DMA1_9_CONFIG(val) bfin_write16(DMA1_9_CONFIG,val)
+#define bfin_read_DMA1_9_NEXT_DESC_PTR() bfin_read32(DMA1_9_NEXT_DESC_PTR)
+#define bfin_write_DMA1_9_NEXT_DESC_PTR(val) bfin_write32(DMA1_9_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_9_START_ADDR() bfin_read32(DMA1_9_START_ADDR)
+#define bfin_write_DMA1_9_START_ADDR(val) bfin_write32(DMA1_9_START_ADDR,val)
+#define bfin_read_DMA1_9_X_COUNT() bfin_read16(DMA1_9_X_COUNT)
+#define bfin_write_DMA1_9_X_COUNT(val) bfin_write16(DMA1_9_X_COUNT,val)
+#define bfin_read_DMA1_9_Y_COUNT() bfin_read16(DMA1_9_Y_COUNT)
+#define bfin_write_DMA1_9_Y_COUNT(val) bfin_write16(DMA1_9_Y_COUNT,val)
+#define bfin_read_DMA1_9_X_MODIFY() bfin_read16(DMA1_9_X_MODIFY)
+#define bfin_write_DMA1_9_X_MODIFY(val) bfin_write16(DMA1_9_X_MODIFY,val)
+#define bfin_read_DMA1_9_Y_MODIFY() bfin_read16(DMA1_9_Y_MODIFY)
+#define bfin_write_DMA1_9_Y_MODIFY(val) bfin_write16(DMA1_9_Y_MODIFY,val)
+#define bfin_read_DMA1_9_CURR_DESC_PTR() bfin_read32(DMA1_9_CURR_DESC_PTR)
+#define bfin_write_DMA1_9_CURR_DESC_PTR(val) bfin_write32(DMA1_9_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_9_CURR_ADDR() bfin_read32(DMA1_9_CURR_ADDR)
+#define bfin_write_DMA1_9_CURR_ADDR(val) bfin_write32(DMA1_9_CURR_ADDR,val)
+#define bfin_read_DMA1_9_CURR_X_COUNT() bfin_read16(DMA1_9_CURR_X_COUNT)
+#define bfin_write_DMA1_9_CURR_X_COUNT(val) bfin_write16(DMA1_9_CURR_X_COUNT,val)
+#define bfin_read_DMA1_9_CURR_Y_COUNT() bfin_read16(DMA1_9_CURR_Y_COUNT)
+#define bfin_write_DMA1_9_CURR_Y_COUNT(val) bfin_write16(DMA1_9_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_9_IRQ_STATUS() bfin_read16(DMA1_9_IRQ_STATUS)
+#define bfin_write_DMA1_9_IRQ_STATUS(val) bfin_write16(DMA1_9_IRQ_STATUS,val)
+#define bfin_read_DMA1_9_PERIPHERAL_MAP() bfin_read16(DMA1_9_PERIPHERAL_MAP)
+#define bfin_write_DMA1_9_PERIPHERAL_MAP(val) bfin_write16(DMA1_9_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_10_CONFIG() bfin_read16(DMA1_10_CONFIG)
+#define bfin_write_DMA1_10_CONFIG(val) bfin_write16(DMA1_10_CONFIG,val)
+#define bfin_read_DMA1_10_NEXT_DESC_PTR() bfin_read32(DMA1_10_NEXT_DESC_PTR)
+#define bfin_write_DMA1_10_NEXT_DESC_PTR(val) bfin_write32(DMA1_10_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_10_START_ADDR() bfin_read32(DMA1_10_START_ADDR)
+#define bfin_write_DMA1_10_START_ADDR(val) bfin_write32(DMA1_10_START_ADDR,val)
+#define bfin_read_DMA1_10_X_COUNT() bfin_read16(DMA1_10_X_COUNT)
+#define bfin_write_DMA1_10_X_COUNT(val) bfin_write16(DMA1_10_X_COUNT,val)
+#define bfin_read_DMA1_10_Y_COUNT() bfin_read16(DMA1_10_Y_COUNT)
+#define bfin_write_DMA1_10_Y_COUNT(val) bfin_write16(DMA1_10_Y_COUNT,val)
+#define bfin_read_DMA1_10_X_MODIFY() bfin_read16(DMA1_10_X_MODIFY)
+#define bfin_write_DMA1_10_X_MODIFY(val) bfin_write16(DMA1_10_X_MODIFY,val)
+#define bfin_read_DMA1_10_Y_MODIFY() bfin_read16(DMA1_10_Y_MODIFY)
+#define bfin_write_DMA1_10_Y_MODIFY(val) bfin_write16(DMA1_10_Y_MODIFY,val)
+#define bfin_read_DMA1_10_CURR_DESC_PTR() bfin_read32(DMA1_10_CURR_DESC_PTR)
+#define bfin_write_DMA1_10_CURR_DESC_PTR(val) bfin_write32(DMA1_10_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_10_CURR_ADDR() bfin_read32(DMA1_10_CURR_ADDR)
+#define bfin_write_DMA1_10_CURR_ADDR(val) bfin_write32(DMA1_10_CURR_ADDR,val)
+#define bfin_read_DMA1_10_CURR_X_COUNT() bfin_read16(DMA1_10_CURR_X_COUNT)
+#define bfin_write_DMA1_10_CURR_X_COUNT(val) bfin_write16(DMA1_10_CURR_X_COUNT,val)
+#define bfin_read_DMA1_10_CURR_Y_COUNT() bfin_read16(DMA1_10_CURR_Y_COUNT)
+#define bfin_write_DMA1_10_CURR_Y_COUNT(val) bfin_write16(DMA1_10_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_10_IRQ_STATUS() bfin_read16(DMA1_10_IRQ_STATUS)
+#define bfin_write_DMA1_10_IRQ_STATUS(val) bfin_write16(DMA1_10_IRQ_STATUS,val)
+#define bfin_read_DMA1_10_PERIPHERAL_MAP() bfin_read16(DMA1_10_PERIPHERAL_MAP)
+#define bfin_write_DMA1_10_PERIPHERAL_MAP(val) bfin_write16(DMA1_10_PERIPHERAL_MAP,val)
+#define bfin_read_DMA1_11_CONFIG() bfin_read16(DMA1_11_CONFIG)
+#define bfin_write_DMA1_11_CONFIG(val) bfin_write16(DMA1_11_CONFIG,val)
+#define bfin_read_DMA1_11_NEXT_DESC_PTR() bfin_read32(DMA1_11_NEXT_DESC_PTR)
+#define bfin_write_DMA1_11_NEXT_DESC_PTR(val) bfin_write32(DMA1_11_NEXT_DESC_PTR,val)
+#define bfin_read_DMA1_11_START_ADDR() bfin_read32(DMA1_11_START_ADDR)
+#define bfin_write_DMA1_11_START_ADDR(val) bfin_write32(DMA1_11_START_ADDR,val)
+#define bfin_read_DMA1_11_X_COUNT() bfin_read16(DMA1_11_X_COUNT)
+#define bfin_write_DMA1_11_X_COUNT(val) bfin_write16(DMA1_11_X_COUNT,val)
+#define bfin_read_DMA1_11_Y_COUNT() bfin_read16(DMA1_11_Y_COUNT)
+#define bfin_write_DMA1_11_Y_COUNT(val) bfin_write16(DMA1_11_Y_COUNT,val)
+#define bfin_read_DMA1_11_X_MODIFY() bfin_read16(DMA1_11_X_MODIFY)
+#define bfin_write_DMA1_11_X_MODIFY(val) bfin_write16(DMA1_11_X_MODIFY,val)
+#define bfin_read_DMA1_11_Y_MODIFY() bfin_read16(DMA1_11_Y_MODIFY)
+#define bfin_write_DMA1_11_Y_MODIFY(val) bfin_write16(DMA1_11_Y_MODIFY,val)
+#define bfin_read_DMA1_11_CURR_DESC_PTR() bfin_read32(DMA1_11_CURR_DESC_PTR)
+#define bfin_write_DMA1_11_CURR_DESC_PTR(val) bfin_write32(DMA1_11_CURR_DESC_PTR,val)
+#define bfin_read_DMA1_11_CURR_ADDR() bfin_read32(DMA1_11_CURR_ADDR)
+#define bfin_write_DMA1_11_CURR_ADDR(val) bfin_write32(DMA1_11_CURR_ADDR,val)
+#define bfin_read_DMA1_11_CURR_X_COUNT() bfin_read16(DMA1_11_CURR_X_COUNT)
+#define bfin_write_DMA1_11_CURR_X_COUNT(val) bfin_write16(DMA1_11_CURR_X_COUNT,val)
+#define bfin_read_DMA1_11_CURR_Y_COUNT() bfin_read16(DMA1_11_CURR_Y_COUNT)
+#define bfin_write_DMA1_11_CURR_Y_COUNT(val) bfin_write16(DMA1_11_CURR_Y_COUNT,val)
+#define bfin_read_DMA1_11_IRQ_STATUS() bfin_read16(DMA1_11_IRQ_STATUS)
+#define bfin_write_DMA1_11_IRQ_STATUS(val) bfin_write16(DMA1_11_IRQ_STATUS,val)
+#define bfin_read_DMA1_11_PERIPHERAL_MAP() bfin_read16(DMA1_11_PERIPHERAL_MAP)
+#define bfin_write_DMA1_11_PERIPHERAL_MAP(val) bfin_write16(DMA1_11_PERIPHERAL_MAP,val)
+/* Memory DMA1 Controller registers (0xFFC0 1E80-0xFFC0 1FFF) */
+#define bfin_read_MDMA1_D0_CONFIG() bfin_read16(MDMA1_D0_CONFIG)
+#define bfin_write_MDMA1_D0_CONFIG(val) bfin_write16(MDMA1_D0_CONFIG,val)
+#define bfin_read_MDMA1_D0_NEXT_DESC_PTR() bfin_read32(MDMA1_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA1_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_D0_START_ADDR() bfin_read32(MDMA1_D0_START_ADDR)
+#define bfin_write_MDMA1_D0_START_ADDR(val) bfin_write32(MDMA1_D0_START_ADDR,val)
+#define bfin_read_MDMA1_D0_X_COUNT() bfin_read16(MDMA1_D0_X_COUNT)
+#define bfin_write_MDMA1_D0_X_COUNT(val) bfin_write16(MDMA1_D0_X_COUNT,val)
+#define bfin_read_MDMA1_D0_Y_COUNT() bfin_read16(MDMA1_D0_Y_COUNT)
+#define bfin_write_MDMA1_D0_Y_COUNT(val) bfin_write16(MDMA1_D0_Y_COUNT,val)
+#define bfin_read_MDMA1_D0_X_MODIFY() bfin_read16(MDMA1_D0_X_MODIFY)
+#define bfin_write_MDMA1_D0_X_MODIFY(val) bfin_write16(MDMA1_D0_X_MODIFY,val)
+#define bfin_read_MDMA1_D0_Y_MODIFY() bfin_read16(MDMA1_D0_Y_MODIFY)
+#define bfin_write_MDMA1_D0_Y_MODIFY(val) bfin_write16(MDMA1_D0_Y_MODIFY,val)
+#define bfin_read_MDMA1_D0_CURR_DESC_PTR() bfin_read32(MDMA1_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA1_D0_CURR_DESC_PTR(val) bfin_write32(MDMA1_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_D0_CURR_ADDR() bfin_read32(MDMA1_D0_CURR_ADDR)
+#define bfin_write_MDMA1_D0_CURR_ADDR(val) bfin_write32(MDMA1_D0_CURR_ADDR,val)
+#define bfin_read_MDMA1_D0_CURR_X_COUNT() bfin_read16(MDMA1_D0_CURR_X_COUNT)
+#define bfin_write_MDMA1_D0_CURR_X_COUNT(val) bfin_write16(MDMA1_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_D0_CURR_Y_COUNT() bfin_read16(MDMA1_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA1_D0_CURR_Y_COUNT(val) bfin_write16(MDMA1_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_D0_IRQ_STATUS() bfin_read16(MDMA1_D0_IRQ_STATUS)
+#define bfin_write_MDMA1_D0_IRQ_STATUS(val) bfin_write16(MDMA1_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA1_D0_PERIPHERAL_MAP() bfin_read16(MDMA1_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA1_D0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA1_S0_CONFIG() bfin_read16(MDMA1_S0_CONFIG)
+#define bfin_write_MDMA1_S0_CONFIG(val) bfin_write16(MDMA1_S0_CONFIG,val)
+#define bfin_read_MDMA1_S0_NEXT_DESC_PTR() bfin_read32(MDMA1_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA1_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_S0_START_ADDR() bfin_read32(MDMA1_S0_START_ADDR)
+#define bfin_write_MDMA1_S0_START_ADDR(val) bfin_write32(MDMA1_S0_START_ADDR,val)
+#define bfin_read_MDMA1_S0_X_COUNT() bfin_read16(MDMA1_S0_X_COUNT)
+#define bfin_write_MDMA1_S0_X_COUNT(val) bfin_write16(MDMA1_S0_X_COUNT,val)
+#define bfin_read_MDMA1_S0_Y_COUNT() bfin_read16(MDMA1_S0_Y_COUNT)
+#define bfin_write_MDMA1_S0_Y_COUNT(val) bfin_write16(MDMA1_S0_Y_COUNT,val)
+#define bfin_read_MDMA1_S0_X_MODIFY() bfin_read16(MDMA1_S0_X_MODIFY)
+#define bfin_write_MDMA1_S0_X_MODIFY(val) bfin_write16(MDMA1_S0_X_MODIFY,val)
+#define bfin_read_MDMA1_S0_Y_MODIFY() bfin_read16(MDMA1_S0_Y_MODIFY)
+#define bfin_write_MDMA1_S0_Y_MODIFY(val) bfin_write16(MDMA1_S0_Y_MODIFY,val)
+#define bfin_read_MDMA1_S0_CURR_DESC_PTR() bfin_read32(MDMA1_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA1_S0_CURR_DESC_PTR(val) bfin_write32(MDMA1_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_S0_CURR_ADDR() bfin_read32(MDMA1_S0_CURR_ADDR)
+#define bfin_write_MDMA1_S0_CURR_ADDR(val) bfin_write32(MDMA1_S0_CURR_ADDR,val)
+#define bfin_read_MDMA1_S0_CURR_X_COUNT() bfin_read16(MDMA1_S0_CURR_X_COUNT)
+#define bfin_write_MDMA1_S0_CURR_X_COUNT(val) bfin_write16(MDMA1_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_S0_CURR_Y_COUNT() bfin_read16(MDMA1_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA1_S0_CURR_Y_COUNT(val) bfin_write16(MDMA1_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_S0_IRQ_STATUS() bfin_read16(MDMA1_S0_IRQ_STATUS)
+#define bfin_write_MDMA1_S0_IRQ_STATUS(val) bfin_write16(MDMA1_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA1_S0_PERIPHERAL_MAP() bfin_read16(MDMA1_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA1_S0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA1_D1_CONFIG() bfin_read16(MDMA1_D1_CONFIG)
+#define bfin_write_MDMA1_D1_CONFIG(val) bfin_write16(MDMA1_D1_CONFIG,val)
+#define bfin_read_MDMA1_D1_NEXT_DESC_PTR() bfin_read32(MDMA1_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA1_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_D1_START_ADDR() bfin_read32(MDMA1_D1_START_ADDR)
+#define bfin_write_MDMA1_D1_START_ADDR(val) bfin_write32(MDMA1_D1_START_ADDR,val)
+#define bfin_read_MDMA1_D1_X_COUNT() bfin_read16(MDMA1_D1_X_COUNT)
+#define bfin_write_MDMA1_D1_X_COUNT(val) bfin_write16(MDMA1_D1_X_COUNT,val)
+#define bfin_read_MDMA1_D1_Y_COUNT() bfin_read16(MDMA1_D1_Y_COUNT)
+#define bfin_write_MDMA1_D1_Y_COUNT(val) bfin_write16(MDMA1_D1_Y_COUNT,val)
+#define bfin_read_MDMA1_D1_X_MODIFY() bfin_read16(MDMA1_D1_X_MODIFY)
+#define bfin_write_MDMA1_D1_X_MODIFY(val) bfin_write16(MDMA1_D1_X_MODIFY,val)
+#define bfin_read_MDMA1_D1_Y_MODIFY() bfin_read16(MDMA1_D1_Y_MODIFY)
+#define bfin_write_MDMA1_D1_Y_MODIFY(val) bfin_write16(MDMA1_D1_Y_MODIFY,val)
+#define bfin_read_MDMA1_D1_CURR_DESC_PTR() bfin_read32(MDMA1_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA1_D1_CURR_DESC_PTR(val) bfin_write32(MDMA1_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_D1_CURR_ADDR() bfin_read32(MDMA1_D1_CURR_ADDR)
+#define bfin_write_MDMA1_D1_CURR_ADDR(val) bfin_write32(MDMA1_D1_CURR_ADDR,val)
+#define bfin_read_MDMA1_D1_CURR_X_COUNT() bfin_read16(MDMA1_D1_CURR_X_COUNT)
+#define bfin_write_MDMA1_D1_CURR_X_COUNT(val) bfin_write16(MDMA1_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_D1_CURR_Y_COUNT() bfin_read16(MDMA1_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA1_D1_CURR_Y_COUNT(val) bfin_write16(MDMA1_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_D1_IRQ_STATUS() bfin_read16(MDMA1_D1_IRQ_STATUS)
+#define bfin_write_MDMA1_D1_IRQ_STATUS(val) bfin_write16(MDMA1_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA1_D1_PERIPHERAL_MAP() bfin_read16(MDMA1_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA1_D1_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA1_S1_CONFIG() bfin_read16(MDMA1_S1_CONFIG)
+#define bfin_write_MDMA1_S1_CONFIG(val) bfin_write16(MDMA1_S1_CONFIG,val)
+#define bfin_read_MDMA1_S1_NEXT_DESC_PTR() bfin_read32(MDMA1_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA1_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA1_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA1_S1_START_ADDR() bfin_read32(MDMA1_S1_START_ADDR)
+#define bfin_write_MDMA1_S1_START_ADDR(val) bfin_write32(MDMA1_S1_START_ADDR,val)
+#define bfin_read_MDMA1_S1_X_COUNT() bfin_read16(MDMA1_S1_X_COUNT)
+#define bfin_write_MDMA1_S1_X_COUNT(val) bfin_write16(MDMA1_S1_X_COUNT,val)
+#define bfin_read_MDMA1_S1_Y_COUNT() bfin_read16(MDMA1_S1_Y_COUNT)
+#define bfin_write_MDMA1_S1_Y_COUNT(val) bfin_write16(MDMA1_S1_Y_COUNT,val)
+#define bfin_read_MDMA1_S1_X_MODIFY() bfin_read16(MDMA1_S1_X_MODIFY)
+#define bfin_write_MDMA1_S1_X_MODIFY(val) bfin_write16(MDMA1_S1_X_MODIFY,val)
+#define bfin_read_MDMA1_S1_Y_MODIFY() bfin_read16(MDMA1_S1_Y_MODIFY)
+#define bfin_write_MDMA1_S1_Y_MODIFY(val) bfin_write16(MDMA1_S1_Y_MODIFY,val)
+#define bfin_read_MDMA1_S1_CURR_DESC_PTR() bfin_read32(MDMA1_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA1_S1_CURR_DESC_PTR(val) bfin_write32(MDMA1_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA1_S1_CURR_ADDR() bfin_read32(MDMA1_S1_CURR_ADDR)
+#define bfin_write_MDMA1_S1_CURR_ADDR(val) bfin_write32(MDMA1_S1_CURR_ADDR,val)
+#define bfin_read_MDMA1_S1_CURR_X_COUNT() bfin_read16(MDMA1_S1_CURR_X_COUNT)
+#define bfin_write_MDMA1_S1_CURR_X_COUNT(val) bfin_write16(MDMA1_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA1_S1_CURR_Y_COUNT() bfin_read16(MDMA1_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA1_S1_CURR_Y_COUNT(val) bfin_write16(MDMA1_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA1_S1_IRQ_STATUS() bfin_read16(MDMA1_S1_IRQ_STATUS)
+#define bfin_write_MDMA1_S1_IRQ_STATUS(val) bfin_write16(MDMA1_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA1_S1_PERIPHERAL_MAP() bfin_read16(MDMA1_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA1_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA1_S1_PERIPHERAL_MAP,val)
+/* DMA2 Controller registers (0xFFC0 0C00-0xFFC0 0DFF) */
+#define bfin_read_DMA2_0_CONFIG() bfin_read16(DMA2_0_CONFIG)
+#define bfin_write_DMA2_0_CONFIG(val) bfin_write16(DMA2_0_CONFIG,val)
+#define bfin_read_DMA2_0_NEXT_DESC_PTR() bfin_read32(DMA2_0_NEXT_DESC_PTR)
+#define bfin_write_DMA2_0_NEXT_DESC_PTR(val) bfin_write32(DMA2_0_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_0_START_ADDR() bfin_read32(DMA2_0_START_ADDR)
+#define bfin_write_DMA2_0_START_ADDR(val) bfin_write32(DMA2_0_START_ADDR,val)
+#define bfin_read_DMA2_0_X_COUNT() bfin_read16(DMA2_0_X_COUNT)
+#define bfin_write_DMA2_0_X_COUNT(val) bfin_write16(DMA2_0_X_COUNT,val)
+#define bfin_read_DMA2_0_Y_COUNT() bfin_read16(DMA2_0_Y_COUNT)
+#define bfin_write_DMA2_0_Y_COUNT(val) bfin_write16(DMA2_0_Y_COUNT,val)
+#define bfin_read_DMA2_0_X_MODIFY() bfin_read16(DMA2_0_X_MODIFY)
+#define bfin_write_DMA2_0_X_MODIFY(val) bfin_write16(DMA2_0_X_MODIFY,val)
+#define bfin_read_DMA2_0_Y_MODIFY() bfin_read16(DMA2_0_Y_MODIFY)
+#define bfin_write_DMA2_0_Y_MODIFY(val) bfin_write16(DMA2_0_Y_MODIFY,val)
+#define bfin_read_DMA2_0_CURR_DESC_PTR() bfin_read32(DMA2_0_CURR_DESC_PTR)
+#define bfin_write_DMA2_0_CURR_DESC_PTR(val) bfin_write32(DMA2_0_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_0_CURR_ADDR() bfin_read32(DMA2_0_CURR_ADDR)
+#define bfin_write_DMA2_0_CURR_ADDR(val) bfin_write32(DMA2_0_CURR_ADDR,val)
+#define bfin_read_DMA2_0_CURR_X_COUNT() bfin_read16(DMA2_0_CURR_X_COUNT)
+#define bfin_write_DMA2_0_CURR_X_COUNT(val) bfin_write16(DMA2_0_CURR_X_COUNT,val)
+#define bfin_read_DMA2_0_CURR_Y_COUNT() bfin_read16(DMA2_0_CURR_Y_COUNT)
+#define bfin_write_DMA2_0_CURR_Y_COUNT(val) bfin_write16(DMA2_0_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_0_IRQ_STATUS() bfin_read16(DMA2_0_IRQ_STATUS)
+#define bfin_write_DMA2_0_IRQ_STATUS(val) bfin_write16(DMA2_0_IRQ_STATUS,val)
+#define bfin_read_DMA2_0_PERIPHERAL_MAP() bfin_read16(DMA2_0_PERIPHERAL_MAP)
+#define bfin_write_DMA2_0_PERIPHERAL_MAP(val) bfin_write16(DMA2_0_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_1_CONFIG() bfin_read16(DMA2_1_CONFIG)
+#define bfin_write_DMA2_1_CONFIG(val) bfin_write16(DMA2_1_CONFIG,val)
+#define bfin_read_DMA2_1_NEXT_DESC_PTR() bfin_read32(DMA2_1_NEXT_DESC_PTR)
+#define bfin_write_DMA2_1_NEXT_DESC_PTR(val) bfin_write32(DMA2_1_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_1_START_ADDR() bfin_read32(DMA2_1_START_ADDR)
+#define bfin_write_DMA2_1_START_ADDR(val) bfin_write32(DMA2_1_START_ADDR,val)
+#define bfin_read_DMA2_1_X_COUNT() bfin_read16(DMA2_1_X_COUNT)
+#define bfin_write_DMA2_1_X_COUNT(val) bfin_write16(DMA2_1_X_COUNT,val)
+#define bfin_read_DMA2_1_Y_COUNT() bfin_read16(DMA2_1_Y_COUNT)
+#define bfin_write_DMA2_1_Y_COUNT(val) bfin_write16(DMA2_1_Y_COUNT,val)
+#define bfin_read_DMA2_1_X_MODIFY() bfin_read16(DMA2_1_X_MODIFY)
+#define bfin_write_DMA2_1_X_MODIFY(val) bfin_write16(DMA2_1_X_MODIFY,val)
+#define bfin_read_DMA2_1_Y_MODIFY() bfin_read16(DMA2_1_Y_MODIFY)
+#define bfin_write_DMA2_1_Y_MODIFY(val) bfin_write16(DMA2_1_Y_MODIFY,val)
+#define bfin_read_DMA2_1_CURR_DESC_PTR() bfin_read32(DMA2_1_CURR_DESC_PTR)
+#define bfin_write_DMA2_1_CURR_DESC_PTR(val) bfin_write32(DMA2_1_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_1_CURR_ADDR() bfin_read32(DMA2_1_CURR_ADDR)
+#define bfin_write_DMA2_1_CURR_ADDR(val) bfin_write32(DMA2_1_CURR_ADDR,val)
+#define bfin_read_DMA2_1_CURR_X_COUNT() bfin_read16(DMA2_1_CURR_X_COUNT)
+#define bfin_write_DMA2_1_CURR_X_COUNT(val) bfin_write16(DMA2_1_CURR_X_COUNT,val)
+#define bfin_read_DMA2_1_CURR_Y_COUNT() bfin_read16(DMA2_1_CURR_Y_COUNT)
+#define bfin_write_DMA2_1_CURR_Y_COUNT(val) bfin_write16(DMA2_1_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_1_IRQ_STATUS() bfin_read16(DMA2_1_IRQ_STATUS)
+#define bfin_write_DMA2_1_IRQ_STATUS(val) bfin_write16(DMA2_1_IRQ_STATUS,val)
+#define bfin_read_DMA2_1_PERIPHERAL_MAP() bfin_read16(DMA2_1_PERIPHERAL_MAP)
+#define bfin_write_DMA2_1_PERIPHERAL_MAP(val) bfin_write16(DMA2_1_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_2_CONFIG() bfin_read16(DMA2_2_CONFIG)
+#define bfin_write_DMA2_2_CONFIG(val) bfin_write16(DMA2_2_CONFIG,val)
+#define bfin_read_DMA2_2_NEXT_DESC_PTR() bfin_read32(DMA2_2_NEXT_DESC_PTR)
+#define bfin_write_DMA2_2_NEXT_DESC_PTR(val) bfin_write32(DMA2_2_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_2_START_ADDR() bfin_read32(DMA2_2_START_ADDR)
+#define bfin_write_DMA2_2_START_ADDR(val) bfin_write32(DMA2_2_START_ADDR,val)
+#define bfin_read_DMA2_2_X_COUNT() bfin_read16(DMA2_2_X_COUNT)
+#define bfin_write_DMA2_2_X_COUNT(val) bfin_write16(DMA2_2_X_COUNT,val)
+#define bfin_read_DMA2_2_Y_COUNT() bfin_read16(DMA2_2_Y_COUNT)
+#define bfin_write_DMA2_2_Y_COUNT(val) bfin_write16(DMA2_2_Y_COUNT,val)
+#define bfin_read_DMA2_2_X_MODIFY() bfin_read16(DMA2_2_X_MODIFY)
+#define bfin_write_DMA2_2_X_MODIFY(val) bfin_write16(DMA2_2_X_MODIFY,val)
+#define bfin_read_DMA2_2_Y_MODIFY() bfin_read16(DMA2_2_Y_MODIFY)
+#define bfin_write_DMA2_2_Y_MODIFY(val) bfin_write16(DMA2_2_Y_MODIFY,val)
+#define bfin_read_DMA2_2_CURR_DESC_PTR() bfin_read32(DMA2_2_CURR_DESC_PTR)
+#define bfin_write_DMA2_2_CURR_DESC_PTR(val) bfin_write32(DMA2_2_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_2_CURR_ADDR() bfin_read32(DMA2_2_CURR_ADDR)
+#define bfin_write_DMA2_2_CURR_ADDR(val) bfin_write32(DMA2_2_CURR_ADDR,val)
+#define bfin_read_DMA2_2_CURR_X_COUNT() bfin_read16(DMA2_2_CURR_X_COUNT)
+#define bfin_write_DMA2_2_CURR_X_COUNT(val) bfin_write16(DMA2_2_CURR_X_COUNT,val)
+#define bfin_read_DMA2_2_CURR_Y_COUNT() bfin_read16(DMA2_2_CURR_Y_COUNT)
+#define bfin_write_DMA2_2_CURR_Y_COUNT(val) bfin_write16(DMA2_2_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_2_IRQ_STATUS() bfin_read16(DMA2_2_IRQ_STATUS)
+#define bfin_write_DMA2_2_IRQ_STATUS(val) bfin_write16(DMA2_2_IRQ_STATUS,val)
+#define bfin_read_DMA2_2_PERIPHERAL_MAP() bfin_read16(DMA2_2_PERIPHERAL_MAP)
+#define bfin_write_DMA2_2_PERIPHERAL_MAP(val) bfin_write16(DMA2_2_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_3_CONFIG() bfin_read16(DMA2_3_CONFIG)
+#define bfin_write_DMA2_3_CONFIG(val) bfin_write16(DMA2_3_CONFIG,val)
+#define bfin_read_DMA2_3_NEXT_DESC_PTR() bfin_read32(DMA2_3_NEXT_DESC_PTR)
+#define bfin_write_DMA2_3_NEXT_DESC_PTR(val) bfin_write32(DMA2_3_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_3_START_ADDR() bfin_read32(DMA2_3_START_ADDR)
+#define bfin_write_DMA2_3_START_ADDR(val) bfin_write32(DMA2_3_START_ADDR,val)
+#define bfin_read_DMA2_3_X_COUNT() bfin_read16(DMA2_3_X_COUNT)
+#define bfin_write_DMA2_3_X_COUNT(val) bfin_write16(DMA2_3_X_COUNT,val)
+#define bfin_read_DMA2_3_Y_COUNT() bfin_read16(DMA2_3_Y_COUNT)
+#define bfin_write_DMA2_3_Y_COUNT(val) bfin_write16(DMA2_3_Y_COUNT,val)
+#define bfin_read_DMA2_3_X_MODIFY() bfin_read16(DMA2_3_X_MODIFY)
+#define bfin_write_DMA2_3_X_MODIFY(val) bfin_write16(DMA2_3_X_MODIFY,val)
+#define bfin_read_DMA2_3_Y_MODIFY() bfin_read16(DMA2_3_Y_MODIFY)
+#define bfin_write_DMA2_3_Y_MODIFY(val) bfin_write16(DMA2_3_Y_MODIFY,val)
+#define bfin_read_DMA2_3_CURR_DESC_PTR() bfin_read32(DMA2_3_CURR_DESC_PTR)
+#define bfin_write_DMA2_3_CURR_DESC_PTR(val) bfin_write32(DMA2_3_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_3_CURR_ADDR() bfin_read32(DMA2_3_CURR_ADDR)
+#define bfin_write_DMA2_3_CURR_ADDR(val) bfin_write32(DMA2_3_CURR_ADDR,val)
+#define bfin_read_DMA2_3_CURR_X_COUNT() bfin_read16(DMA2_3_CURR_X_COUNT)
+#define bfin_write_DMA2_3_CURR_X_COUNT(val) bfin_write16(DMA2_3_CURR_X_COUNT,val)
+#define bfin_read_DMA2_3_CURR_Y_COUNT() bfin_read16(DMA2_3_CURR_Y_COUNT)
+#define bfin_write_DMA2_3_CURR_Y_COUNT(val) bfin_write16(DMA2_3_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_3_IRQ_STATUS() bfin_read16(DMA2_3_IRQ_STATUS)
+#define bfin_write_DMA2_3_IRQ_STATUS(val) bfin_write16(DMA2_3_IRQ_STATUS,val)
+#define bfin_read_DMA2_3_PERIPHERAL_MAP() bfin_read16(DMA2_3_PERIPHERAL_MAP)
+#define bfin_write_DMA2_3_PERIPHERAL_MAP(val) bfin_write16(DMA2_3_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_4_CONFIG() bfin_read16(DMA2_4_CONFIG)
+#define bfin_write_DMA2_4_CONFIG(val) bfin_write16(DMA2_4_CONFIG,val)
+#define bfin_read_DMA2_4_NEXT_DESC_PTR() bfin_read32(DMA2_4_NEXT_DESC_PTR)
+#define bfin_write_DMA2_4_NEXT_DESC_PTR(val) bfin_write32(DMA2_4_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_4_START_ADDR() bfin_read32(DMA2_4_START_ADDR)
+#define bfin_write_DMA2_4_START_ADDR(val) bfin_write32(DMA2_4_START_ADDR,val)
+#define bfin_read_DMA2_4_X_COUNT() bfin_read16(DMA2_4_X_COUNT)
+#define bfin_write_DMA2_4_X_COUNT(val) bfin_write16(DMA2_4_X_COUNT,val)
+#define bfin_read_DMA2_4_Y_COUNT() bfin_read16(DMA2_4_Y_COUNT)
+#define bfin_write_DMA2_4_Y_COUNT(val) bfin_write16(DMA2_4_Y_COUNT,val)
+#define bfin_read_DMA2_4_X_MODIFY() bfin_read16(DMA2_4_X_MODIFY)
+#define bfin_write_DMA2_4_X_MODIFY(val) bfin_write16(DMA2_4_X_MODIFY,val)
+#define bfin_read_DMA2_4_Y_MODIFY() bfin_read16(DMA2_4_Y_MODIFY)
+#define bfin_write_DMA2_4_Y_MODIFY(val) bfin_write16(DMA2_4_Y_MODIFY,val)
+#define bfin_read_DMA2_4_CURR_DESC_PTR() bfin_read32(DMA2_4_CURR_DESC_PTR)
+#define bfin_write_DMA2_4_CURR_DESC_PTR(val) bfin_write32(DMA2_4_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_4_CURR_ADDR() bfin_read32(DMA2_4_CURR_ADDR)
+#define bfin_write_DMA2_4_CURR_ADDR(val) bfin_write32(DMA2_4_CURR_ADDR,val)
+#define bfin_read_DMA2_4_CURR_X_COUNT() bfin_read16(DMA2_4_CURR_X_COUNT)
+#define bfin_write_DMA2_4_CURR_X_COUNT(val) bfin_write16(DMA2_4_CURR_X_COUNT,val)
+#define bfin_read_DMA2_4_CURR_Y_COUNT() bfin_read16(DMA2_4_CURR_Y_COUNT)
+#define bfin_write_DMA2_4_CURR_Y_COUNT(val) bfin_write16(DMA2_4_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_4_IRQ_STATUS() bfin_read16(DMA2_4_IRQ_STATUS)
+#define bfin_write_DMA2_4_IRQ_STATUS(val) bfin_write16(DMA2_4_IRQ_STATUS,val)
+#define bfin_read_DMA2_4_PERIPHERAL_MAP() bfin_read16(DMA2_4_PERIPHERAL_MAP)
+#define bfin_write_DMA2_4_PERIPHERAL_MAP(val) bfin_write16(DMA2_4_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_5_CONFIG() bfin_read16(DMA2_5_CONFIG)
+#define bfin_write_DMA2_5_CONFIG(val) bfin_write16(DMA2_5_CONFIG,val)
+#define bfin_read_DMA2_5_NEXT_DESC_PTR() bfin_read32(DMA2_5_NEXT_DESC_PTR)
+#define bfin_write_DMA2_5_NEXT_DESC_PTR(val) bfin_write32(DMA2_5_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_5_START_ADDR() bfin_read32(DMA2_5_START_ADDR)
+#define bfin_write_DMA2_5_START_ADDR(val) bfin_write32(DMA2_5_START_ADDR,val)
+#define bfin_read_DMA2_5_X_COUNT() bfin_read16(DMA2_5_X_COUNT)
+#define bfin_write_DMA2_5_X_COUNT(val) bfin_write16(DMA2_5_X_COUNT,val)
+#define bfin_read_DMA2_5_Y_COUNT() bfin_read16(DMA2_5_Y_COUNT)
+#define bfin_write_DMA2_5_Y_COUNT(val) bfin_write16(DMA2_5_Y_COUNT,val)
+#define bfin_read_DMA2_5_X_MODIFY() bfin_read16(DMA2_5_X_MODIFY)
+#define bfin_write_DMA2_5_X_MODIFY(val) bfin_write16(DMA2_5_X_MODIFY,val)
+#define bfin_read_DMA2_5_Y_MODIFY() bfin_read16(DMA2_5_Y_MODIFY)
+#define bfin_write_DMA2_5_Y_MODIFY(val) bfin_write16(DMA2_5_Y_MODIFY,val)
+#define bfin_read_DMA2_5_CURR_DESC_PTR() bfin_read32(DMA2_5_CURR_DESC_PTR)
+#define bfin_write_DMA2_5_CURR_DESC_PTR(val) bfin_write32(DMA2_5_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_5_CURR_ADDR() bfin_read32(DMA2_5_CURR_ADDR)
+#define bfin_write_DMA2_5_CURR_ADDR(val) bfin_write32(DMA2_5_CURR_ADDR,val)
+#define bfin_read_DMA2_5_CURR_X_COUNT() bfin_read16(DMA2_5_CURR_X_COUNT)
+#define bfin_write_DMA2_5_CURR_X_COUNT(val) bfin_write16(DMA2_5_CURR_X_COUNT,val)
+#define bfin_read_DMA2_5_CURR_Y_COUNT() bfin_read16(DMA2_5_CURR_Y_COUNT)
+#define bfin_write_DMA2_5_CURR_Y_COUNT(val) bfin_write16(DMA2_5_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_5_IRQ_STATUS() bfin_read16(DMA2_5_IRQ_STATUS)
+#define bfin_write_DMA2_5_IRQ_STATUS(val) bfin_write16(DMA2_5_IRQ_STATUS,val)
+#define bfin_read_DMA2_5_PERIPHERAL_MAP() bfin_read16(DMA2_5_PERIPHERAL_MAP)
+#define bfin_write_DMA2_5_PERIPHERAL_MAP(val) bfin_write16(DMA2_5_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_6_CONFIG() bfin_read16(DMA2_6_CONFIG)
+#define bfin_write_DMA2_6_CONFIG(val) bfin_write16(DMA2_6_CONFIG,val)
+#define bfin_read_DMA2_6_NEXT_DESC_PTR() bfin_read32(DMA2_6_NEXT_DESC_PTR)
+#define bfin_write_DMA2_6_NEXT_DESC_PTR(val) bfin_write32(DMA2_6_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_6_START_ADDR() bfin_read32(DMA2_6_START_ADDR)
+#define bfin_write_DMA2_6_START_ADDR(val) bfin_write32(DMA2_6_START_ADDR,val)
+#define bfin_read_DMA2_6_X_COUNT() bfin_read16(DMA2_6_X_COUNT)
+#define bfin_write_DMA2_6_X_COUNT(val) bfin_write16(DMA2_6_X_COUNT,val)
+#define bfin_read_DMA2_6_Y_COUNT() bfin_read16(DMA2_6_Y_COUNT)
+#define bfin_write_DMA2_6_Y_COUNT(val) bfin_write16(DMA2_6_Y_COUNT,val)
+#define bfin_read_DMA2_6_X_MODIFY() bfin_read16(DMA2_6_X_MODIFY)
+#define bfin_write_DMA2_6_X_MODIFY(val) bfin_write16(DMA2_6_X_MODIFY,val)
+#define bfin_read_DMA2_6_Y_MODIFY() bfin_read16(DMA2_6_Y_MODIFY)
+#define bfin_write_DMA2_6_Y_MODIFY(val) bfin_write16(DMA2_6_Y_MODIFY,val)
+#define bfin_read_DMA2_6_CURR_DESC_PTR() bfin_read32(DMA2_6_CURR_DESC_PTR)
+#define bfin_write_DMA2_6_CURR_DESC_PTR(val) bfin_write32(DMA2_6_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_6_CURR_ADDR() bfin_read32(DMA2_6_CURR_ADDR)
+#define bfin_write_DMA2_6_CURR_ADDR(val) bfin_write32(DMA2_6_CURR_ADDR,val)
+#define bfin_read_DMA2_6_CURR_X_COUNT() bfin_read16(DMA2_6_CURR_X_COUNT)
+#define bfin_write_DMA2_6_CURR_X_COUNT(val) bfin_write16(DMA2_6_CURR_X_COUNT,val)
+#define bfin_read_DMA2_6_CURR_Y_COUNT() bfin_read16(DMA2_6_CURR_Y_COUNT)
+#define bfin_write_DMA2_6_CURR_Y_COUNT(val) bfin_write16(DMA2_6_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_6_IRQ_STATUS() bfin_read16(DMA2_6_IRQ_STATUS)
+#define bfin_write_DMA2_6_IRQ_STATUS(val) bfin_write16(DMA2_6_IRQ_STATUS,val)
+#define bfin_read_DMA2_6_PERIPHERAL_MAP() bfin_read16(DMA2_6_PERIPHERAL_MAP)
+#define bfin_write_DMA2_6_PERIPHERAL_MAP(val) bfin_write16(DMA2_6_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_7_CONFIG() bfin_read16(DMA2_7_CONFIG)
+#define bfin_write_DMA2_7_CONFIG(val) bfin_write16(DMA2_7_CONFIG,val)
+#define bfin_read_DMA2_7_NEXT_DESC_PTR() bfin_read32(DMA2_7_NEXT_DESC_PTR)
+#define bfin_write_DMA2_7_NEXT_DESC_PTR(val) bfin_write32(DMA2_7_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_7_START_ADDR() bfin_read32(DMA2_7_START_ADDR)
+#define bfin_write_DMA2_7_START_ADDR(val) bfin_write32(DMA2_7_START_ADDR,val)
+#define bfin_read_DMA2_7_X_COUNT() bfin_read16(DMA2_7_X_COUNT)
+#define bfin_write_DMA2_7_X_COUNT(val) bfin_write16(DMA2_7_X_COUNT,val)
+#define bfin_read_DMA2_7_Y_COUNT() bfin_read16(DMA2_7_Y_COUNT)
+#define bfin_write_DMA2_7_Y_COUNT(val) bfin_write16(DMA2_7_Y_COUNT,val)
+#define bfin_read_DMA2_7_X_MODIFY() bfin_read16(DMA2_7_X_MODIFY)
+#define bfin_write_DMA2_7_X_MODIFY(val) bfin_write16(DMA2_7_X_MODIFY,val)
+#define bfin_read_DMA2_7_Y_MODIFY() bfin_read16(DMA2_7_Y_MODIFY)
+#define bfin_write_DMA2_7_Y_MODIFY(val) bfin_write16(DMA2_7_Y_MODIFY,val)
+#define bfin_read_DMA2_7_CURR_DESC_PTR() bfin_read32(DMA2_7_CURR_DESC_PTR)
+#define bfin_write_DMA2_7_CURR_DESC_PTR(val) bfin_write32(DMA2_7_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_7_CURR_ADDR() bfin_read32(DMA2_7_CURR_ADDR)
+#define bfin_write_DMA2_7_CURR_ADDR(val) bfin_write32(DMA2_7_CURR_ADDR,val)
+#define bfin_read_DMA2_7_CURR_X_COUNT() bfin_read16(DMA2_7_CURR_X_COUNT)
+#define bfin_write_DMA2_7_CURR_X_COUNT(val) bfin_write16(DMA2_7_CURR_X_COUNT,val)
+#define bfin_read_DMA2_7_CURR_Y_COUNT() bfin_read16(DMA2_7_CURR_Y_COUNT)
+#define bfin_write_DMA2_7_CURR_Y_COUNT(val) bfin_write16(DMA2_7_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_7_IRQ_STATUS() bfin_read16(DMA2_7_IRQ_STATUS)
+#define bfin_write_DMA2_7_IRQ_STATUS(val) bfin_write16(DMA2_7_IRQ_STATUS,val)
+#define bfin_read_DMA2_7_PERIPHERAL_MAP() bfin_read16(DMA2_7_PERIPHERAL_MAP)
+#define bfin_write_DMA2_7_PERIPHERAL_MAP(val) bfin_write16(DMA2_7_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_8_CONFIG() bfin_read16(DMA2_8_CONFIG)
+#define bfin_write_DMA2_8_CONFIG(val) bfin_write16(DMA2_8_CONFIG,val)
+#define bfin_read_DMA2_8_NEXT_DESC_PTR() bfin_read32(DMA2_8_NEXT_DESC_PTR)
+#define bfin_write_DMA2_8_NEXT_DESC_PTR(val) bfin_write32(DMA2_8_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_8_START_ADDR() bfin_read32(DMA2_8_START_ADDR)
+#define bfin_write_DMA2_8_START_ADDR(val) bfin_write32(DMA2_8_START_ADDR,val)
+#define bfin_read_DMA2_8_X_COUNT() bfin_read16(DMA2_8_X_COUNT)
+#define bfin_write_DMA2_8_X_COUNT(val) bfin_write16(DMA2_8_X_COUNT,val)
+#define bfin_read_DMA2_8_Y_COUNT() bfin_read16(DMA2_8_Y_COUNT)
+#define bfin_write_DMA2_8_Y_COUNT(val) bfin_write16(DMA2_8_Y_COUNT,val)
+#define bfin_read_DMA2_8_X_MODIFY() bfin_read16(DMA2_8_X_MODIFY)
+#define bfin_write_DMA2_8_X_MODIFY(val) bfin_write16(DMA2_8_X_MODIFY,val)
+#define bfin_read_DMA2_8_Y_MODIFY() bfin_read16(DMA2_8_Y_MODIFY)
+#define bfin_write_DMA2_8_Y_MODIFY(val) bfin_write16(DMA2_8_Y_MODIFY,val)
+#define bfin_read_DMA2_8_CURR_DESC_PTR() bfin_read32(DMA2_8_CURR_DESC_PTR)
+#define bfin_write_DMA2_8_CURR_DESC_PTR(val) bfin_write32(DMA2_8_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_8_CURR_ADDR() bfin_read32(DMA2_8_CURR_ADDR)
+#define bfin_write_DMA2_8_CURR_ADDR(val) bfin_write32(DMA2_8_CURR_ADDR,val)
+#define bfin_read_DMA2_8_CURR_X_COUNT() bfin_read16(DMA2_8_CURR_X_COUNT)
+#define bfin_write_DMA2_8_CURR_X_COUNT(val) bfin_write16(DMA2_8_CURR_X_COUNT,val)
+#define bfin_read_DMA2_8_CURR_Y_COUNT() bfin_read16(DMA2_8_CURR_Y_COUNT)
+#define bfin_write_DMA2_8_CURR_Y_COUNT(val) bfin_write16(DMA2_8_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_8_IRQ_STATUS() bfin_read16(DMA2_8_IRQ_STATUS)
+#define bfin_write_DMA2_8_IRQ_STATUS(val) bfin_write16(DMA2_8_IRQ_STATUS,val)
+#define bfin_read_DMA2_8_PERIPHERAL_MAP() bfin_read16(DMA2_8_PERIPHERAL_MAP)
+#define bfin_write_DMA2_8_PERIPHERAL_MAP(val) bfin_write16(DMA2_8_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_9_CONFIG() bfin_read16(DMA2_9_CONFIG)
+#define bfin_write_DMA2_9_CONFIG(val) bfin_write16(DMA2_9_CONFIG,val)
+#define bfin_read_DMA2_9_NEXT_DESC_PTR() bfin_read32(DMA2_9_NEXT_DESC_PTR)
+#define bfin_write_DMA2_9_NEXT_DESC_PTR(val) bfin_write32(DMA2_9_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_9_START_ADDR() bfin_read32(DMA2_9_START_ADDR)
+#define bfin_write_DMA2_9_START_ADDR(val) bfin_write32(DMA2_9_START_ADDR,val)
+#define bfin_read_DMA2_9_X_COUNT() bfin_read16(DMA2_9_X_COUNT)
+#define bfin_write_DMA2_9_X_COUNT(val) bfin_write16(DMA2_9_X_COUNT,val)
+#define bfin_read_DMA2_9_Y_COUNT() bfin_read16(DMA2_9_Y_COUNT)
+#define bfin_write_DMA2_9_Y_COUNT(val) bfin_write16(DMA2_9_Y_COUNT,val)
+#define bfin_read_DMA2_9_X_MODIFY() bfin_read16(DMA2_9_X_MODIFY)
+#define bfin_write_DMA2_9_X_MODIFY(val) bfin_write16(DMA2_9_X_MODIFY,val)
+#define bfin_read_DMA2_9_Y_MODIFY() bfin_read16(DMA2_9_Y_MODIFY)
+#define bfin_write_DMA2_9_Y_MODIFY(val) bfin_write16(DMA2_9_Y_MODIFY,val)
+#define bfin_read_DMA2_9_CURR_DESC_PTR() bfin_read32(DMA2_9_CURR_DESC_PTR)
+#define bfin_write_DMA2_9_CURR_DESC_PTR(val) bfin_write32(DMA2_9_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_9_CURR_ADDR() bfin_read32(DMA2_9_CURR_ADDR)
+#define bfin_write_DMA2_9_CURR_ADDR(val) bfin_write32(DMA2_9_CURR_ADDR,val)
+#define bfin_read_DMA2_9_CURR_X_COUNT() bfin_read16(DMA2_9_CURR_X_COUNT)
+#define bfin_write_DMA2_9_CURR_X_COUNT(val) bfin_write16(DMA2_9_CURR_X_COUNT,val)
+#define bfin_read_DMA2_9_CURR_Y_COUNT() bfin_read16(DMA2_9_CURR_Y_COUNT)
+#define bfin_write_DMA2_9_CURR_Y_COUNT(val) bfin_write16(DMA2_9_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_9_IRQ_STATUS() bfin_read16(DMA2_9_IRQ_STATUS)
+#define bfin_write_DMA2_9_IRQ_STATUS(val) bfin_write16(DMA2_9_IRQ_STATUS,val)
+#define bfin_read_DMA2_9_PERIPHERAL_MAP() bfin_read16(DMA2_9_PERIPHERAL_MAP)
+#define bfin_write_DMA2_9_PERIPHERAL_MAP(val) bfin_write16(DMA2_9_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_10_CONFIG() bfin_read16(DMA2_10_CONFIG)
+#define bfin_write_DMA2_10_CONFIG(val) bfin_write16(DMA2_10_CONFIG,val)
+#define bfin_read_DMA2_10_NEXT_DESC_PTR() bfin_read32(DMA2_10_NEXT_DESC_PTR)
+#define bfin_write_DMA2_10_NEXT_DESC_PTR(val) bfin_write32(DMA2_10_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_10_START_ADDR() bfin_read32(DMA2_10_START_ADDR)
+#define bfin_write_DMA2_10_START_ADDR(val) bfin_write32(DMA2_10_START_ADDR,val)
+#define bfin_read_DMA2_10_X_COUNT() bfin_read16(DMA2_10_X_COUNT)
+#define bfin_write_DMA2_10_X_COUNT(val) bfin_write16(DMA2_10_X_COUNT,val)
+#define bfin_read_DMA2_10_Y_COUNT() bfin_read16(DMA2_10_Y_COUNT)
+#define bfin_write_DMA2_10_Y_COUNT(val) bfin_write16(DMA2_10_Y_COUNT,val)
+#define bfin_read_DMA2_10_X_MODIFY() bfin_read16(DMA2_10_X_MODIFY)
+#define bfin_write_DMA2_10_X_MODIFY(val) bfin_write16(DMA2_10_X_MODIFY,val)
+#define bfin_read_DMA2_10_Y_MODIFY() bfin_read16(DMA2_10_Y_MODIFY)
+#define bfin_write_DMA2_10_Y_MODIFY(val) bfin_write16(DMA2_10_Y_MODIFY,val)
+#define bfin_read_DMA2_10_CURR_DESC_PTR() bfin_read32(DMA2_10_CURR_DESC_PTR)
+#define bfin_write_DMA2_10_CURR_DESC_PTR(val) bfin_write32(DMA2_10_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_10_CURR_ADDR() bfin_read32(DMA2_10_CURR_ADDR)
+#define bfin_write_DMA2_10_CURR_ADDR(val) bfin_write32(DMA2_10_CURR_ADDR,val)
+#define bfin_read_DMA2_10_CURR_X_COUNT() bfin_read16(DMA2_10_CURR_X_COUNT)
+#define bfin_write_DMA2_10_CURR_X_COUNT(val) bfin_write16(DMA2_10_CURR_X_COUNT,val)
+#define bfin_read_DMA2_10_CURR_Y_COUNT() bfin_read16(DMA2_10_CURR_Y_COUNT)
+#define bfin_write_DMA2_10_CURR_Y_COUNT(val) bfin_write16(DMA2_10_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_10_IRQ_STATUS() bfin_read16(DMA2_10_IRQ_STATUS)
+#define bfin_write_DMA2_10_IRQ_STATUS(val) bfin_write16(DMA2_10_IRQ_STATUS,val)
+#define bfin_read_DMA2_10_PERIPHERAL_MAP() bfin_read16(DMA2_10_PERIPHERAL_MAP)
+#define bfin_write_DMA2_10_PERIPHERAL_MAP(val) bfin_write16(DMA2_10_PERIPHERAL_MAP,val)
+#define bfin_read_DMA2_11_CONFIG() bfin_read16(DMA2_11_CONFIG)
+#define bfin_write_DMA2_11_CONFIG(val) bfin_write16(DMA2_11_CONFIG,val)
+#define bfin_read_DMA2_11_NEXT_DESC_PTR() bfin_read32(DMA2_11_NEXT_DESC_PTR)
+#define bfin_write_DMA2_11_NEXT_DESC_PTR(val) bfin_write32(DMA2_11_NEXT_DESC_PTR,val)
+#define bfin_read_DMA2_11_START_ADDR() bfin_read32(DMA2_11_START_ADDR)
+#define bfin_write_DMA2_11_START_ADDR(val) bfin_write32(DMA2_11_START_ADDR,val)
+#define bfin_read_DMA2_11_X_COUNT() bfin_read16(DMA2_11_X_COUNT)
+#define bfin_write_DMA2_11_X_COUNT(val) bfin_write16(DMA2_11_X_COUNT,val)
+#define bfin_read_DMA2_11_Y_COUNT() bfin_read16(DMA2_11_Y_COUNT)
+#define bfin_write_DMA2_11_Y_COUNT(val) bfin_write16(DMA2_11_Y_COUNT,val)
+#define bfin_read_DMA2_11_X_MODIFY() bfin_read16(DMA2_11_X_MODIFY)
+#define bfin_write_DMA2_11_X_MODIFY(val) bfin_write16(DMA2_11_X_MODIFY,val)
+#define bfin_read_DMA2_11_Y_MODIFY() bfin_read16(DMA2_11_Y_MODIFY)
+#define bfin_write_DMA2_11_Y_MODIFY(val) bfin_write16(DMA2_11_Y_MODIFY,val)
+#define bfin_read_DMA2_11_CURR_DESC_PTR() bfin_read32(DMA2_11_CURR_DESC_PTR)
+#define bfin_write_DMA2_11_CURR_DESC_PTR(val) bfin_write32(DMA2_11_CURR_DESC_PTR,val)
+#define bfin_read_DMA2_11_CURR_ADDR() bfin_read32(DMA2_11_CURR_ADDR)
+#define bfin_write_DMA2_11_CURR_ADDR(val) bfin_write32(DMA2_11_CURR_ADDR,val)
+#define bfin_read_DMA2_11_CURR_X_COUNT() bfin_read16(DMA2_11_CURR_X_COUNT)
+#define bfin_write_DMA2_11_CURR_X_COUNT(val) bfin_write16(DMA2_11_CURR_X_COUNT,val)
+#define bfin_read_DMA2_11_CURR_Y_COUNT() bfin_read16(DMA2_11_CURR_Y_COUNT)
+#define bfin_write_DMA2_11_CURR_Y_COUNT(val) bfin_write16(DMA2_11_CURR_Y_COUNT,val)
+#define bfin_read_DMA2_11_IRQ_STATUS() bfin_read16(DMA2_11_IRQ_STATUS)
+#define bfin_write_DMA2_11_IRQ_STATUS(val) bfin_write16(DMA2_11_IRQ_STATUS,val)
+#define bfin_read_DMA2_11_PERIPHERAL_MAP() bfin_read16(DMA2_11_PERIPHERAL_MAP)
+#define bfin_write_DMA2_11_PERIPHERAL_MAP(val) bfin_write16(DMA2_11_PERIPHERAL_MAP,val)
+/* Memory DMA2 Controller registers (0xFFC0 0E80-0xFFC0 0FFF) */
+#define bfin_read_MDMA2_D0_CONFIG() bfin_read16(MDMA2_D0_CONFIG)
+#define bfin_write_MDMA2_D0_CONFIG(val) bfin_write16(MDMA2_D0_CONFIG,val)
+#define bfin_read_MDMA2_D0_NEXT_DESC_PTR() bfin_read32(MDMA2_D0_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA2_D0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_D0_START_ADDR() bfin_read32(MDMA2_D0_START_ADDR)
+#define bfin_write_MDMA2_D0_START_ADDR(val) bfin_write32(MDMA2_D0_START_ADDR,val)
+#define bfin_read_MDMA2_D0_X_COUNT() bfin_read16(MDMA2_D0_X_COUNT)
+#define bfin_write_MDMA2_D0_X_COUNT(val) bfin_write16(MDMA2_D0_X_COUNT,val)
+#define bfin_read_MDMA2_D0_Y_COUNT() bfin_read16(MDMA2_D0_Y_COUNT)
+#define bfin_write_MDMA2_D0_Y_COUNT(val) bfin_write16(MDMA2_D0_Y_COUNT,val)
+#define bfin_read_MDMA2_D0_X_MODIFY() bfin_read16(MDMA2_D0_X_MODIFY)
+#define bfin_write_MDMA2_D0_X_MODIFY(val) bfin_write16(MDMA2_D0_X_MODIFY,val)
+#define bfin_read_MDMA2_D0_Y_MODIFY() bfin_read16(MDMA2_D0_Y_MODIFY)
+#define bfin_write_MDMA2_D0_Y_MODIFY(val) bfin_write16(MDMA2_D0_Y_MODIFY,val)
+#define bfin_read_MDMA2_D0_CURR_DESC_PTR() bfin_read32(MDMA2_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA2_D0_CURR_DESC_PTR(val) bfin_write32(MDMA2_D0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_D0_CURR_ADDR() bfin_read32(MDMA2_D0_CURR_ADDR)
+#define bfin_write_MDMA2_D0_CURR_ADDR(val) bfin_write32(MDMA2_D0_CURR_ADDR,val)
+#define bfin_read_MDMA2_D0_CURR_X_COUNT() bfin_read16(MDMA2_D0_CURR_X_COUNT)
+#define bfin_write_MDMA2_D0_CURR_X_COUNT(val) bfin_write16(MDMA2_D0_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_D0_CURR_Y_COUNT() bfin_read16(MDMA2_D0_CURR_Y_COUNT)
+#define bfin_write_MDMA2_D0_CURR_Y_COUNT(val) bfin_write16(MDMA2_D0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_D0_IRQ_STATUS() bfin_read16(MDMA2_D0_IRQ_STATUS)
+#define bfin_write_MDMA2_D0_IRQ_STATUS(val) bfin_write16(MDMA2_D0_IRQ_STATUS,val)
+#define bfin_read_MDMA2_D0_PERIPHERAL_MAP() bfin_read16(MDMA2_D0_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_D0_PERIPHERAL_MAP(val) bfin_write16(MDMA2_D0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA2_S0_CONFIG() bfin_read16(MDMA2_S0_CONFIG)
+#define bfin_write_MDMA2_S0_CONFIG(val) bfin_write16(MDMA2_S0_CONFIG,val)
+#define bfin_read_MDMA2_S0_NEXT_DESC_PTR() bfin_read32(MDMA2_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA2_S0_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_S0_START_ADDR() bfin_read32(MDMA2_S0_START_ADDR)
+#define bfin_write_MDMA2_S0_START_ADDR(val) bfin_write32(MDMA2_S0_START_ADDR,val)
+#define bfin_read_MDMA2_S0_X_COUNT() bfin_read16(MDMA2_S0_X_COUNT)
+#define bfin_write_MDMA2_S0_X_COUNT(val) bfin_write16(MDMA2_S0_X_COUNT,val)
+#define bfin_read_MDMA2_S0_Y_COUNT() bfin_read16(MDMA2_S0_Y_COUNT)
+#define bfin_write_MDMA2_S0_Y_COUNT(val) bfin_write16(MDMA2_S0_Y_COUNT,val)
+#define bfin_read_MDMA2_S0_X_MODIFY() bfin_read16(MDMA2_S0_X_MODIFY)
+#define bfin_write_MDMA2_S0_X_MODIFY(val) bfin_write16(MDMA2_S0_X_MODIFY,val)
+#define bfin_read_MDMA2_S0_Y_MODIFY() bfin_read16(MDMA2_S0_Y_MODIFY)
+#define bfin_write_MDMA2_S0_Y_MODIFY(val) bfin_write16(MDMA2_S0_Y_MODIFY,val)
+#define bfin_read_MDMA2_S0_CURR_DESC_PTR() bfin_read32(MDMA2_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA2_S0_CURR_DESC_PTR(val) bfin_write32(MDMA2_S0_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_S0_CURR_ADDR() bfin_read32(MDMA2_S0_CURR_ADDR)
+#define bfin_write_MDMA2_S0_CURR_ADDR(val) bfin_write32(MDMA2_S0_CURR_ADDR,val)
+#define bfin_read_MDMA2_S0_CURR_X_COUNT() bfin_read16(MDMA2_S0_CURR_X_COUNT)
+#define bfin_write_MDMA2_S0_CURR_X_COUNT(val) bfin_write16(MDMA2_S0_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_S0_CURR_Y_COUNT() bfin_read16(MDMA2_S0_CURR_Y_COUNT)
+#define bfin_write_MDMA2_S0_CURR_Y_COUNT(val) bfin_write16(MDMA2_S0_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_S0_IRQ_STATUS() bfin_read16(MDMA2_S0_IRQ_STATUS)
+#define bfin_write_MDMA2_S0_IRQ_STATUS(val) bfin_write16(MDMA2_S0_IRQ_STATUS,val)
+#define bfin_read_MDMA2_S0_PERIPHERAL_MAP() bfin_read16(MDMA2_S0_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_S0_PERIPHERAL_MAP(val) bfin_write16(MDMA2_S0_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA2_D1_CONFIG() bfin_read16(MDMA2_D1_CONFIG)
+#define bfin_write_MDMA2_D1_CONFIG(val) bfin_write16(MDMA2_D1_CONFIG,val)
+#define bfin_read_MDMA2_D1_NEXT_DESC_PTR() bfin_read32(MDMA2_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA2_D1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_D1_START_ADDR() bfin_read32(MDMA2_D1_START_ADDR)
+#define bfin_write_MDMA2_D1_START_ADDR(val) bfin_write32(MDMA2_D1_START_ADDR,val)
+#define bfin_read_MDMA2_D1_X_COUNT() bfin_read16(MDMA2_D1_X_COUNT)
+#define bfin_write_MDMA2_D1_X_COUNT(val) bfin_write16(MDMA2_D1_X_COUNT,val)
+#define bfin_read_MDMA2_D1_Y_COUNT() bfin_read16(MDMA2_D1_Y_COUNT)
+#define bfin_write_MDMA2_D1_Y_COUNT(val) bfin_write16(MDMA2_D1_Y_COUNT,val)
+#define bfin_read_MDMA2_D1_X_MODIFY() bfin_read16(MDMA2_D1_X_MODIFY)
+#define bfin_write_MDMA2_D1_X_MODIFY(val) bfin_write16(MDMA2_D1_X_MODIFY,val)
+#define bfin_read_MDMA2_D1_Y_MODIFY() bfin_read16(MDMA2_D1_Y_MODIFY)
+#define bfin_write_MDMA2_D1_Y_MODIFY(val) bfin_write16(MDMA2_D1_Y_MODIFY,val)
+#define bfin_read_MDMA2_D1_CURR_DESC_PTR() bfin_read32(MDMA2_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA2_D1_CURR_DESC_PTR(val) bfin_write32(MDMA2_D1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_D1_CURR_ADDR() bfin_read32(MDMA2_D1_CURR_ADDR)
+#define bfin_write_MDMA2_D1_CURR_ADDR(val) bfin_write32(MDMA2_D1_CURR_ADDR,val)
+#define bfin_read_MDMA2_D1_CURR_X_COUNT() bfin_read16(MDMA2_D1_CURR_X_COUNT)
+#define bfin_write_MDMA2_D1_CURR_X_COUNT(val) bfin_write16(MDMA2_D1_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_D1_CURR_Y_COUNT() bfin_read16(MDMA2_D1_CURR_Y_COUNT)
+#define bfin_write_MDMA2_D1_CURR_Y_COUNT(val) bfin_write16(MDMA2_D1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_D1_IRQ_STATUS() bfin_read16(MDMA2_D1_IRQ_STATUS)
+#define bfin_write_MDMA2_D1_IRQ_STATUS(val) bfin_write16(MDMA2_D1_IRQ_STATUS,val)
+#define bfin_read_MDMA2_D1_PERIPHERAL_MAP() bfin_read16(MDMA2_D1_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_D1_PERIPHERAL_MAP(val) bfin_write16(MDMA2_D1_PERIPHERAL_MAP,val)
+#define bfin_read_MDMA2_S1_CONFIG() bfin_read16(MDMA2_S1_CONFIG)
+#define bfin_write_MDMA2_S1_CONFIG(val) bfin_write16(MDMA2_S1_CONFIG,val)
+#define bfin_read_MDMA2_S1_NEXT_DESC_PTR() bfin_read32(MDMA2_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA2_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA2_S1_NEXT_DESC_PTR,val)
+#define bfin_read_MDMA2_S1_START_ADDR() bfin_read32(MDMA2_S1_START_ADDR)
+#define bfin_write_MDMA2_S1_START_ADDR(val) bfin_write32(MDMA2_S1_START_ADDR,val)
+#define bfin_read_MDMA2_S1_X_COUNT() bfin_read16(MDMA2_S1_X_COUNT)
+#define bfin_write_MDMA2_S1_X_COUNT(val) bfin_write16(MDMA2_S1_X_COUNT,val)
+#define bfin_read_MDMA2_S1_Y_COUNT() bfin_read16(MDMA2_S1_Y_COUNT)
+#define bfin_write_MDMA2_S1_Y_COUNT(val) bfin_write16(MDMA2_S1_Y_COUNT,val)
+#define bfin_read_MDMA2_S1_X_MODIFY() bfin_read16(MDMA2_S1_X_MODIFY)
+#define bfin_write_MDMA2_S1_X_MODIFY(val) bfin_write16(MDMA2_S1_X_MODIFY,val)
+#define bfin_read_MDMA2_S1_Y_MODIFY() bfin_read16(MDMA2_S1_Y_MODIFY)
+#define bfin_write_MDMA2_S1_Y_MODIFY(val) bfin_write16(MDMA2_S1_Y_MODIFY,val)
+#define bfin_read_MDMA2_S1_CURR_DESC_PTR() bfin_read32(MDMA2_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA2_S1_CURR_DESC_PTR(val) bfin_write32(MDMA2_S1_CURR_DESC_PTR,val)
+#define bfin_read_MDMA2_S1_CURR_ADDR() bfin_read32(MDMA2_S1_CURR_ADDR)
+#define bfin_write_MDMA2_S1_CURR_ADDR(val) bfin_write32(MDMA2_S1_CURR_ADDR,val)
+#define bfin_read_MDMA2_S1_CURR_X_COUNT() bfin_read16(MDMA2_S1_CURR_X_COUNT)
+#define bfin_write_MDMA2_S1_CURR_X_COUNT(val) bfin_write16(MDMA2_S1_CURR_X_COUNT,val)
+#define bfin_read_MDMA2_S1_CURR_Y_COUNT() bfin_read16(MDMA2_S1_CURR_Y_COUNT)
+#define bfin_write_MDMA2_S1_CURR_Y_COUNT(val) bfin_write16(MDMA2_S1_CURR_Y_COUNT,val)
+#define bfin_read_MDMA2_S1_IRQ_STATUS() bfin_read16(MDMA2_S1_IRQ_STATUS)
+#define bfin_write_MDMA2_S1_IRQ_STATUS(val) bfin_write16(MDMA2_S1_IRQ_STATUS,val)
+#define bfin_read_MDMA2_S1_PERIPHERAL_MAP() bfin_read16(MDMA2_S1_PERIPHERAL_MAP)
+#define bfin_write_MDMA2_S1_PERIPHERAL_MAP(val) bfin_write16(MDMA2_S1_PERIPHERAL_MAP,val)
+/* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
+#define bfin_read_IMDMA_D0_CONFIG() bfin_read16(IMDMA_D0_CONFIG)
+#define bfin_write_IMDMA_D0_CONFIG(val) bfin_write16(IMDMA_D0_CONFIG,val)
+#define bfin_read_IMDMA_D0_NEXT_DESC_PTR() bfin_read32(IMDMA_D0_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_D0_NEXT_DESC_PTR(val) bfin_write32(IMDMA_D0_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_D0_START_ADDR() bfin_read32(IMDMA_D0_START_ADDR)
+#define bfin_write_IMDMA_D0_START_ADDR(val) bfin_write32(IMDMA_D0_START_ADDR,val)
+#define bfin_read_IMDMA_D0_X_COUNT() bfin_read16(IMDMA_D0_X_COUNT)
+#define bfin_write_IMDMA_D0_X_COUNT(val) bfin_write16(IMDMA_D0_X_COUNT,val)
+#define bfin_read_IMDMA_D0_Y_COUNT() bfin_read16(IMDMA_D0_Y_COUNT)
+#define bfin_write_IMDMA_D0_Y_COUNT(val) bfin_write16(IMDMA_D0_Y_COUNT,val)
+#define bfin_read_IMDMA_D0_X_MODIFY() bfin_read16(IMDMA_D0_X_MODIFY)
+#define bfin_write_IMDMA_D0_X_MODIFY(val) bfin_write16(IMDMA_D0_X_MODIFY,val)
+#define bfin_read_IMDMA_D0_Y_MODIFY() bfin_read16(IMDMA_D0_Y_MODIFY)
+#define bfin_write_IMDMA_D0_Y_MODIFY(val) bfin_write16(IMDMA_D0_Y_MODIFY,val)
+#define bfin_read_IMDMA_D0_CURR_DESC_PTR() bfin_read32(IMDMA_D0_CURR_DESC_PTR)
+#define bfin_write_IMDMA_D0_CURR_DESC_PTR(val) bfin_write32(IMDMA_D0_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_D0_CURR_ADDR() bfin_read32(IMDMA_D0_CURR_ADDR)
+#define bfin_write_IMDMA_D0_CURR_ADDR(val) bfin_write32(IMDMA_D0_CURR_ADDR,val)
+#define bfin_read_IMDMA_D0_CURR_X_COUNT() bfin_read16(IMDMA_D0_CURR_X_COUNT)
+#define bfin_write_IMDMA_D0_CURR_X_COUNT(val) bfin_write16(IMDMA_D0_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_D0_CURR_Y_COUNT() bfin_read16(IMDMA_D0_CURR_Y_COUNT)
+#define bfin_write_IMDMA_D0_CURR_Y_COUNT(val) bfin_write16(IMDMA_D0_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_D0_IRQ_STATUS() bfin_read16(IMDMA_D0_IRQ_STATUS)
+#define bfin_write_IMDMA_D0_IRQ_STATUS(val) bfin_write16(IMDMA_D0_IRQ_STATUS,val)
+#define bfin_read_IMDMA_S0_CONFIG() bfin_read16(IMDMA_S0_CONFIG)
+#define bfin_write_IMDMA_S0_CONFIG(val) bfin_write16(IMDMA_S0_CONFIG,val)
+#define bfin_read_IMDMA_S0_NEXT_DESC_PTR() bfin_read32(IMDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_S0_NEXT_DESC_PTR(val) bfin_write32(IMDMA_S0_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_S0_START_ADDR() bfin_read32(IMDMA_S0_START_ADDR)
+#define bfin_write_IMDMA_S0_START_ADDR(val) bfin_write32(IMDMA_S0_START_ADDR,val)
+#define bfin_read_IMDMA_S0_X_COUNT() bfin_read16(IMDMA_S0_X_COUNT)
+#define bfin_write_IMDMA_S0_X_COUNT(val) bfin_write16(IMDMA_S0_X_COUNT,val)
+#define bfin_read_IMDMA_S0_Y_COUNT() bfin_read16(IMDMA_S0_Y_COUNT)
+#define bfin_write_IMDMA_S0_Y_COUNT(val) bfin_write16(IMDMA_S0_Y_COUNT,val)
+#define bfin_read_IMDMA_S0_X_MODIFY() bfin_read16(IMDMA_S0_X_MODIFY)
+#define bfin_write_IMDMA_S0_X_MODIFY(val) bfin_write16(IMDMA_S0_X_MODIFY,val)
+#define bfin_read_IMDMA_S0_Y_MODIFY() bfin_read16(IMDMA_S0_Y_MODIFY)
+#define bfin_write_IMDMA_S0_Y_MODIFY(val) bfin_write16(IMDMA_S0_Y_MODIFY,val)
+#define bfin_read_IMDMA_S0_CURR_DESC_PTR() bfin_read32(IMDMA_S0_CURR_DESC_PTR)
+#define bfin_write_IMDMA_S0_CURR_DESC_PTR(val) bfin_write32(IMDMA_S0_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_S0_CURR_ADDR() bfin_read32(IMDMA_S0_CURR_ADDR)
+#define bfin_write_IMDMA_S0_CURR_ADDR(val) bfin_write32(IMDMA_S0_CURR_ADDR,val)
+#define bfin_read_IMDMA_S0_CURR_X_COUNT() bfin_read16(IMDMA_S0_CURR_X_COUNT)
+#define bfin_write_IMDMA_S0_CURR_X_COUNT(val) bfin_write16(IMDMA_S0_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_S0_CURR_Y_COUNT() bfin_read16(IMDMA_S0_CURR_Y_COUNT)
+#define bfin_write_IMDMA_S0_CURR_Y_COUNT(val) bfin_write16(IMDMA_S0_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_S0_IRQ_STATUS() bfin_read16(IMDMA_S0_IRQ_STATUS)
+#define bfin_write_IMDMA_S0_IRQ_STATUS(val) bfin_write16(IMDMA_S0_IRQ_STATUS,val)
+#define bfin_read_IMDMA_D1_CONFIG() bfin_read16(IMDMA_D1_CONFIG)
+#define bfin_write_IMDMA_D1_CONFIG(val) bfin_write16(IMDMA_D1_CONFIG,val)
+#define bfin_read_IMDMA_D1_NEXT_DESC_PTR() bfin_read32(IMDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_D1_NEXT_DESC_PTR(val) bfin_write32(IMDMA_D1_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_D1_START_ADDR() bfin_read32(IMDMA_D1_START_ADDR)
+#define bfin_write_IMDMA_D1_START_ADDR(val) bfin_write32(IMDMA_D1_START_ADDR,val)
+#define bfin_read_IMDMA_D1_X_COUNT() bfin_read16(IMDMA_D1_X_COUNT)
+#define bfin_write_IMDMA_D1_X_COUNT(val) bfin_write16(IMDMA_D1_X_COUNT,val)
+#define bfin_read_IMDMA_D1_Y_COUNT() bfin_read16(IMDMA_D1_Y_COUNT)
+#define bfin_write_IMDMA_D1_Y_COUNT(val) bfin_write16(IMDMA_D1_Y_COUNT,val)
+#define bfin_read_IMDMA_D1_X_MODIFY() bfin_read16(IMDMA_D1_X_MODIFY)
+#define bfin_write_IMDMA_D1_X_MODIFY(val) bfin_write16(IMDMA_D1_X_MODIFY,val)
+#define bfin_read_IMDMA_D1_Y_MODIFY() bfin_read16(IMDMA_D1_Y_MODIFY)
+#define bfin_write_IMDMA_D1_Y_MODIFY(val) bfin_write16(IMDMA_D1_Y_MODIFY,val)
+#define bfin_read_IMDMA_D1_CURR_DESC_PTR() bfin_read32(IMDMA_D1_CURR_DESC_PTR)
+#define bfin_write_IMDMA_D1_CURR_DESC_PTR(val) bfin_write32(IMDMA_D1_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_D1_CURR_ADDR() bfin_read32(IMDMA_D1_CURR_ADDR)
+#define bfin_write_IMDMA_D1_CURR_ADDR(val) bfin_write32(IMDMA_D1_CURR_ADDR,val)
+#define bfin_read_IMDMA_D1_CURR_X_COUNT() bfin_read16(IMDMA_D1_CURR_X_COUNT)
+#define bfin_write_IMDMA_D1_CURR_X_COUNT(val) bfin_write16(IMDMA_D1_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_D1_CURR_Y_COUNT() bfin_read16(IMDMA_D1_CURR_Y_COUNT)
+#define bfin_write_IMDMA_D1_CURR_Y_COUNT(val) bfin_write16(IMDMA_D1_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_D1_IRQ_STATUS() bfin_read16(IMDMA_D1_IRQ_STATUS)
+#define bfin_write_IMDMA_D1_IRQ_STATUS(val) bfin_write16(IMDMA_D1_IRQ_STATUS,val)
+#define bfin_read_IMDMA_S1_CONFIG() bfin_read16(IMDMA_S1_CONFIG)
+#define bfin_write_IMDMA_S1_CONFIG(val) bfin_write16(IMDMA_S1_CONFIG,val)
+#define bfin_read_IMDMA_S1_NEXT_DESC_PTR() bfin_read32(IMDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_IMDMA_S1_NEXT_DESC_PTR(val) bfin_write32(IMDMA_S1_NEXT_DESC_PTR,val)
+#define bfin_read_IMDMA_S1_START_ADDR() bfin_read32(IMDMA_S1_START_ADDR)
+#define bfin_write_IMDMA_S1_START_ADDR(val) bfin_write32(IMDMA_S1_START_ADDR,val)
+#define bfin_read_IMDMA_S1_X_COUNT() bfin_read16(IMDMA_S1_X_COUNT)
+#define bfin_write_IMDMA_S1_X_COUNT(val) bfin_write16(IMDMA_S1_X_COUNT,val)
+#define bfin_read_IMDMA_S1_Y_COUNT() bfin_read16(IMDMA_S1_Y_COUNT)
+#define bfin_write_IMDMA_S1_Y_COUNT(val) bfin_write16(IMDMA_S1_Y_COUNT,val)
+#define bfin_read_IMDMA_S1_X_MODIFY() bfin_read16(IMDMA_S1_X_MODIFY)
+#define bfin_write_IMDMA_S1_X_MODIFY(val) bfin_write16(IMDMA_S1_X_MODIFY,val)
+#define bfin_read_IMDMA_S1_Y_MODIFY() bfin_read16(IMDMA_S1_Y_MODIFY)
+#define bfin_write_IMDMA_S1_Y_MODIFY(val) bfin_write16(IMDMA_S1_Y_MODIFY,val)
+#define bfin_read_IMDMA_S1_CURR_DESC_PTR() bfin_read32(IMDMA_S1_CURR_DESC_PTR)
+#define bfin_write_IMDMA_S1_CURR_DESC_PTR(val) bfin_write32(IMDMA_S1_CURR_DESC_PTR,val)
+#define bfin_read_IMDMA_S1_CURR_ADDR() bfin_read32(IMDMA_S1_CURR_ADDR)
+#define bfin_write_IMDMA_S1_CURR_ADDR(val) bfin_write32(IMDMA_S1_CURR_ADDR,val)
+#define bfin_read_IMDMA_S1_CURR_X_COUNT() bfin_read16(IMDMA_S1_CURR_X_COUNT)
+#define bfin_write_IMDMA_S1_CURR_X_COUNT(val) bfin_write16(IMDMA_S1_CURR_X_COUNT,val)
+#define bfin_read_IMDMA_S1_CURR_Y_COUNT() bfin_read16(IMDMA_S1_CURR_Y_COUNT)
+#define bfin_write_IMDMA_S1_CURR_Y_COUNT(val) bfin_write16(IMDMA_S1_CURR_Y_COUNT,val)
+#define bfin_read_IMDMA_S1_IRQ_STATUS() bfin_read16(IMDMA_S1_IRQ_STATUS)
+#define bfin_write_IMDMA_S1_IRQ_STATUS(val) bfin_write16(IMDMA_S1_IRQ_STATUS,val)
+
+#define bfin_read_MDMA_S0_CONFIG() bfin_read_MDMA1_S0_CONFIG()
+#define bfin_write_MDMA_S0_CONFIG(val) bfin_write_MDMA1_S0_CONFIG(val)
+#define bfin_read_MDMA_S0_IRQ_STATUS() bfin_read_MDMA1_S0_IRQ_STATUS()
+#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write_MDMA1_S0_IRQ_STATUS(val)
+#define bfin_read_MDMA_S0_X_MODIFY() bfin_read_MDMA1_S0_X_MODIFY()
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write_MDMA1_S0_X_MODIFY(val)
+#define bfin_read_MDMA_S0_Y_MODIFY() bfin_read_MDMA1_S0_Y_MODIFY()
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write_MDMA1_S0_Y_MODIFY(val)
+#define bfin_read_MDMA_S0_X_COUNT() bfin_read_MDMA1_S0_X_COUNT()
+#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write_MDMA1_S0_X_COUNT(val)
+#define bfin_read_MDMA_S0_Y_COUNT() bfin_read_MDMA1_S0_Y_COUNT()
+#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write_MDMA1_S0_Y_COUNT(val)
+#define bfin_read_MDMA_S0_START_ADDR() bfin_read_MDMA1_S0_START_ADDR()
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write_MDMA1_S0_START_ADDR(val)
+#define bfin_read_MDMA_D0_CONFIG() bfin_read_MDMA1_D0_CONFIG()
+#define bfin_write_MDMA_D0_CONFIG(val) bfin_write_MDMA1_D0_CONFIG(val)
+#define bfin_read_MDMA_D0_IRQ_STATUS() bfin_read_MDMA1_D0_IRQ_STATUS()
+#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write_MDMA1_D0_IRQ_STATUS(val)
+#define bfin_read_MDMA_D0_X_MODIFY() bfin_read_MDMA1_D0_X_MODIFY()
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write_MDMA1_D0_X_MODIFY(val)
+#define bfin_read_MDMA_D0_Y_MODIFY() bfin_read_MDMA1_D0_Y_MODIFY()
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write_MDMA1_D0_Y_MODIFY(val)
+#define bfin_read_MDMA_D0_X_COUNT() bfin_read_MDMA1_D0_X_COUNT()
+#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write_MDMA1_D0_X_COUNT(val)
+#define bfin_read_MDMA_D0_Y_COUNT() bfin_read_MDMA1_D0_Y_COUNT()
+#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write_MDMA1_D0_Y_COUNT(val)
+#define bfin_read_MDMA_D0_START_ADDR() bfin_read_MDMA1_D0_START_ADDR()
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write_MDMA1_D0_START_ADDR(val)
+
+#endif /* _CDEF_BF561_H */
diff --git a/include/asm-blackfin/mach-bf561/defBF561.h b/include/asm-blackfin/mach-bf561/defBF561.h
new file mode 100644
index 00000000000..a6de4c69ba5
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/defBF561.h
@@ -0,0 +1,1717 @@
+
+/*
+ * File: include/asm-blackfin/mach-bf561/defBF561.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ * SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DEF_BF561_H
+#define _DEF_BF561_H
+/*
+#if !defined(__ADSPBF561__)
+#warning defBF561.h should only be included for BF561 chip.
+#endif
+*/
+/* include all Core registers and bit definitions */
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/*********************************************************************************** */
+/* System MMR Register Map */
+/*********************************************************************************** */
+
+/* Clock and System Control (0xFFC00000 - 0xFFC000FF) */
+
+#define PLL_CTL 0xFFC00000 /* PLL Control register (16-bit) */
+#define PLL_DIV 0xFFC00004 /* PLL Divide Register (16-bit) */
+#define VR_CTL 0xFFC00008 /* Voltage Regulator Control Register (16-bit) */
+#define PLL_STAT 0xFFC0000C /* PLL Status register (16-bit) */
+#define PLL_LOCKCNT 0xFFC00010 /* PLL Lock Count register (16-bit) */
+#define CHIPID 0xFFC00014 /* Chip ID Register */
+
+/* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */
+#define SICA_SWRST 0xFFC00100 /* Software Reset register */
+#define SICA_SYSCR 0xFFC00104 /* System Reset Configuration register */
+#define SICA_RVECT 0xFFC00108 /* SIC Reset Vector Address Register */
+#define SICA_IMASK 0xFFC0010C /* SIC Interrupt Mask register 0 - hack to fix old tests */
+#define SICA_IMASK0 0xFFC0010C /* SIC Interrupt Mask register 0 */
+#define SICA_IMASK1 0xFFC00110 /* SIC Interrupt Mask register 1 */
+#define SICA_IAR0 0xFFC00124 /* SIC Interrupt Assignment Register 0 */
+#define SICA_IAR1 0xFFC00128 /* SIC Interrupt Assignment Register 1 */
+#define SICA_IAR2 0xFFC0012C /* SIC Interrupt Assignment Register 2 */
+#define SICA_IAR3 0xFFC00130 /* SIC Interrupt Assignment Register 3 */
+#define SICA_IAR4 0xFFC00134 /* SIC Interrupt Assignment Register 4 */
+#define SICA_IAR5 0xFFC00138 /* SIC Interrupt Assignment Register 5 */
+#define SICA_IAR6 0xFFC0013C /* SIC Interrupt Assignment Register 6 */
+#define SICA_IAR7 0xFFC00140 /* SIC Interrupt Assignment Register 7 */
+#define SICA_ISR0 0xFFC00114 /* SIC Interrupt Status register 0 */
+#define SICA_ISR1 0xFFC00118 /* SIC Interrupt Status register 1 */
+#define SICA_IWR0 0xFFC0011C /* SIC Interrupt Wakeup-Enable register 0 */
+#define SICA_IWR1 0xFFC00120 /* SIC Interrupt Wakeup-Enable register 1 */
+
+/* System Reset and Interrupt Controller registers for Core B (0xFFC0 1100-0xFFC0 11FF) */
+#define SICB_SWRST 0xFFC01100 /* reserved */
+#define SICB_SYSCR 0xFFC01104 /* reserved */
+#define SICB_RVECT 0xFFC01108 /* SIC Reset Vector Address Register */
+#define SICB_IMASK0 0xFFC0110C /* SIC Interrupt Mask register 0 */
+#define SICB_IMASK1 0xFFC01110 /* SIC Interrupt Mask register 1 */
+#define SICB_IAR0 0xFFC01124 /* SIC Interrupt Assignment Register 0 */
+#define SICB_IAR1 0xFFC01128 /* SIC Interrupt Assignment Register 1 */
+#define SICB_IAR2 0xFFC0112C /* SIC Interrupt Assignment Register 2 */
+#define SICB_IAR3 0xFFC01130 /* SIC Interrupt Assignment Register 3 */
+#define SICB_IAR4 0xFFC01134 /* SIC Interrupt Assignment Register 4 */
+#define SICB_IAR5 0xFFC01138 /* SIC Interrupt Assignment Register 5 */
+#define SICB_IAR6 0xFFC0113C /* SIC Interrupt Assignment Register 6 */
+#define SICB_IAR7 0xFFC01140 /* SIC Interrupt Assignment Register 7 */
+#define SICB_ISR0 0xFFC01114 /* SIC Interrupt Status register 0 */
+#define SICB_ISR1 0xFFC01118 /* SIC Interrupt Status register 1 */
+#define SICB_IWR0 0xFFC0111C /* SIC Interrupt Wakeup-Enable register 0 */
+#define SICB_IWR1 0xFFC01120 /* SIC Interrupt Wakeup-Enable register 1 */
+
+/* Watchdog Timer registers for Core A (0xFFC0 0200-0xFFC0 02FF) */
+#define WDOGA_CTL 0xFFC00200 /* Watchdog Control register */
+#define WDOGA_CNT 0xFFC00204 /* Watchdog Count register */
+#define WDOGA_STAT 0xFFC00208 /* Watchdog Status register */
+
+/* Watchdog Timer registers for Core B (0xFFC0 1200-0xFFC0 12FF) */
+#define WDOGB_CTL 0xFFC01200 /* Watchdog Control register */
+#define WDOGB_CNT 0xFFC01204 /* Watchdog Count register */
+#define WDOGB_STAT 0xFFC01208 /* Watchdog Status register */
+
+/* UART Controller (0xFFC00400 - 0xFFC004FF) */
+#define UART_THR 0xFFC00400 /* Transmit Holding register */
+#define UART_RBR 0xFFC00400 /* Receive Buffer register */
+#define UART_DLL 0xFFC00400 /* Divisor Latch (Low-Byte) */
+#define UART_IER 0xFFC00404 /* Interrupt Enable Register */
+#define UART_DLH 0xFFC00404 /* Divisor Latch (High-Byte) */
+#define UART_IIR 0xFFC00408 /* Interrupt Identification Register */
+#define UART_LCR 0xFFC0040C /* Line Control Register */
+#define UART_MCR 0xFFC00410 /* Modem Control Register */
+#define UART_LSR 0xFFC00414 /* Line Status Register */
+#define UART_MSR 0xFFC00418 /* Modem Status Register */
+#define UART_SCR 0xFFC0041C /* SCR Scratch Register */
+#define UART_GCTL 0xFFC00424 /* Global Control Register */
+
+/* SPI Controller (0xFFC00500 - 0xFFC005FF) */
+#define SPI_CTL 0xFFC00500 /* SPI Control Register */
+#define SPI_FLG 0xFFC00504 /* SPI Flag register */
+#define SPI_STAT 0xFFC00508 /* SPI Status register */
+#define SPI_TDBR 0xFFC0050C /* SPI Transmit Data Buffer Register */
+#define SPI_RDBR 0xFFC00510 /* SPI Receive Data Buffer Register */
+#define SPI_BAUD 0xFFC00514 /* SPI Baud rate Register */
+#define SPI_SHADOW 0xFFC00518 /* SPI_RDBR Shadow Register */
+
+/* Timer 0-7 registers (0xFFC0 0600-0xFFC0 06FF) */
+#define TIMER0_CONFIG 0xFFC00600 /* Timer0 Configuration register */
+#define TIMER0_COUNTER 0xFFC00604 /* Timer0 Counter register */
+#define TIMER0_PERIOD 0xFFC00608 /* Timer0 Period register */
+#define TIMER0_WIDTH 0xFFC0060C /* Timer0 Width register */
+
+#define TIMER1_CONFIG 0xFFC00610 /* Timer1 Configuration register */
+#define TIMER1_COUNTER 0xFFC00614 /* Timer1 Counter register */
+#define TIMER1_PERIOD 0xFFC00618 /* Timer1 Period register */
+#define TIMER1_WIDTH 0xFFC0061C /* Timer1 Width register */
+
+#define TIMER2_CONFIG 0xFFC00620 /* Timer2 Configuration register */
+#define TIMER2_COUNTER 0xFFC00624 /* Timer2 Counter register */
+#define TIMER2_PERIOD 0xFFC00628 /* Timer2 Period register */
+#define TIMER2_WIDTH 0xFFC0062C /* Timer2 Width register */
+
+#define TIMER3_CONFIG 0xFFC00630 /* Timer3 Configuration register */
+#define TIMER3_COUNTER 0xFFC00634 /* Timer3 Counter register */
+#define TIMER3_PERIOD 0xFFC00638 /* Timer3 Period register */
+#define TIMER3_WIDTH 0xFFC0063C /* Timer3 Width register */
+
+#define TIMER4_CONFIG 0xFFC00640 /* Timer4 Configuration register */
+#define TIMER4_COUNTER 0xFFC00644 /* Timer4 Counter register */
+#define TIMER4_PERIOD 0xFFC00648 /* Timer4 Period register */
+#define TIMER4_WIDTH 0xFFC0064C /* Timer4 Width register */
+
+#define TIMER5_CONFIG 0xFFC00650 /* Timer5 Configuration register */
+#define TIMER5_COUNTER 0xFFC00654 /* Timer5 Counter register */
+#define TIMER5_PERIOD 0xFFC00658 /* Timer5 Period register */
+#define TIMER5_WIDTH 0xFFC0065C /* Timer5 Width register */
+
+#define TIMER6_CONFIG 0xFFC00660 /* Timer6 Configuration register */
+#define TIMER6_COUNTER 0xFFC00664 /* Timer6 Counter register */
+#define TIMER6_PERIOD 0xFFC00668 /* Timer6 Period register */
+#define TIMER6_WIDTH 0xFFC0066C /* Timer6 Width register */
+
+#define TIMER7_CONFIG 0xFFC00670 /* Timer7 Configuration register */
+#define TIMER7_COUNTER 0xFFC00674 /* Timer7 Counter register */
+#define TIMER7_PERIOD 0xFFC00678 /* Timer7 Period register */
+#define TIMER7_WIDTH 0xFFC0067C /* Timer7 Width register */
+
+#define TMRS8_ENABLE 0xFFC00680 /* Timer Enable Register */
+#define TMRS8_DISABLE 0xFFC00684 /* Timer Disable register */
+#define TMRS8_STATUS 0xFFC00688 /* Timer Status register */
+
+/* Timer registers 8-11 (0xFFC0 1600-0xFFC0 16FF) */
+#define TIMER8_CONFIG 0xFFC01600 /* Timer8 Configuration register */
+#define TIMER8_COUNTER 0xFFC01604 /* Timer8 Counter register */
+#define TIMER8_PERIOD 0xFFC01608 /* Timer8 Period register */
+#define TIMER8_WIDTH 0xFFC0160C /* Timer8 Width register */
+
+#define TIMER9_CONFIG 0xFFC01610 /* Timer9 Configuration register */
+#define TIMER9_COUNTER 0xFFC01614 /* Timer9 Counter register */
+#define TIMER9_PERIOD 0xFFC01618 /* Timer9 Period register */
+#define TIMER9_WIDTH 0xFFC0161C /* Timer9 Width register */
+
+#define TIMER10_CONFIG 0xFFC01620 /* Timer10 Configuration register */
+#define TIMER10_COUNTER 0xFFC01624 /* Timer10 Counter register */
+#define TIMER10_PERIOD 0xFFC01628 /* Timer10 Period register */
+#define TIMER10_WIDTH 0xFFC0162C /* Timer10 Width register */
+
+#define TIMER11_CONFIG 0xFFC01630 /* Timer11 Configuration register */
+#define TIMER11_COUNTER 0xFFC01634 /* Timer11 Counter register */
+#define TIMER11_PERIOD 0xFFC01638 /* Timer11 Period register */
+#define TIMER11_WIDTH 0xFFC0163C /* Timer11 Width register */
+
+#define TMRS4_ENABLE 0xFFC01640 /* Timer Enable Register */
+#define TMRS4_DISABLE 0xFFC01644 /* Timer Disable register */
+#define TMRS4_STATUS 0xFFC01648 /* Timer Status register */
+
+/* Programmable Flag 0 registers (0xFFC0 0700-0xFFC0 07FF) */
+#define FIO0_FLAG_D 0xFFC00700 /* Flag Data register */
+#define FIO0_FLAG_C 0xFFC00704 /* Flag Clear register */
+#define FIO0_FLAG_S 0xFFC00708 /* Flag Set register */
+#define FIO0_FLAG_T 0xFFC0070C /* Flag Toggle register */
+#define FIO0_MASKA_D 0xFFC00710 /* Flag Mask Interrupt A Data register */
+#define FIO0_MASKA_C 0xFFC00714 /* Flag Mask Interrupt A Clear register */
+#define FIO0_MASKA_S 0xFFC00718 /* Flag Mask Interrupt A Set register */
+#define FIO0_MASKA_T 0xFFC0071C /* Flag Mask Interrupt A Toggle register */
+#define FIO0_MASKB_D 0xFFC00720 /* Flag Mask Interrupt B Data register */
+#define FIO0_MASKB_C 0xFFC00724 /* Flag Mask Interrupt B Clear register */
+#define FIO0_MASKB_S 0xFFC00728 /* Flag Mask Interrupt B Set register */
+#define FIO0_MASKB_T 0xFFC0072C /* Flag Mask Interrupt B Toggle register */
+#define FIO0_DIR 0xFFC00730 /* Flag Direction register */
+#define FIO0_POLAR 0xFFC00734 /* Flag Polarity register */
+#define FIO0_EDGE 0xFFC00738 /* Flag Interrupt Sensitivity register */
+#define FIO0_BOTH 0xFFC0073C /* Flag Set on Both Edges register */
+#define FIO0_INEN 0xFFC00740 /* Flag Input Enable register */
+
+/* Programmable Flag 1 registers (0xFFC0 1500-0xFFC0 15FF) */
+#define FIO1_FLAG_D 0xFFC01500 /* Flag Data register (mask used to directly */
+#define FIO1_FLAG_C 0xFFC01504 /* Flag Clear register */
+#define FIO1_FLAG_S 0xFFC01508 /* Flag Set register */
+#define FIO1_FLAG_T 0xFFC0150C /* Flag Toggle register (mask used to */
+#define FIO1_MASKA_D 0xFFC01510 /* Flag Mask Interrupt A Data register */
+#define FIO1_MASKA_C 0xFFC01514 /* Flag Mask Interrupt A Clear register */
+#define FIO1_MASKA_S 0xFFC01518 /* Flag Mask Interrupt A Set register */
+#define FIO1_MASKA_T 0xFFC0151C /* Flag Mask Interrupt A Toggle register */
+#define FIO1_MASKB_D 0xFFC01520 /* Flag Mask Interrupt B Data register */
+#define FIO1_MASKB_C 0xFFC01524 /* Flag Mask Interrupt B Clear register */
+#define FIO1_MASKB_S 0xFFC01528 /* Flag Mask Interrupt B Set register */
+#define FIO1_MASKB_T 0xFFC0152C /* Flag Mask Interrupt B Toggle register */
+#define FIO1_DIR 0xFFC01530 /* Flag Direction register */
+#define FIO1_POLAR 0xFFC01534 /* Flag Polarity register */
+#define FIO1_EDGE 0xFFC01538 /* Flag Interrupt Sensitivity register */
+#define FIO1_BOTH 0xFFC0153C /* Flag Set on Both Edges register */
+#define FIO1_INEN 0xFFC01540 /* Flag Input Enable register */
+
+/* Programmable Flag registers (0xFFC0 1700-0xFFC0 17FF) */
+#define FIO2_FLAG_D 0xFFC01700 /* Flag Data register (mask used to directly */
+#define FIO2_FLAG_C 0xFFC01704 /* Flag Clear register */
+#define FIO2_FLAG_S 0xFFC01708 /* Flag Set register */
+#define FIO2_FLAG_T 0xFFC0170C /* Flag Toggle register (mask used to */
+#define FIO2_MASKA_D 0xFFC01710 /* Flag Mask Interrupt A Data register */
+#define FIO2_MASKA_C 0xFFC01714 /* Flag Mask Interrupt A Clear register */
+#define FIO2_MASKA_S 0xFFC01718 /* Flag Mask Interrupt A Set register */
+#define FIO2_MASKA_T 0xFFC0171C /* Flag Mask Interrupt A Toggle register */
+#define FIO2_MASKB_D 0xFFC01720 /* Flag Mask Interrupt B Data register */
+#define FIO2_MASKB_C 0xFFC01724 /* Flag Mask Interrupt B Clear register */
+#define FIO2_MASKB_S 0xFFC01728 /* Flag Mask Interrupt B Set register */
+#define FIO2_MASKB_T 0xFFC0172C /* Flag Mask Interrupt B Toggle register */
+#define FIO2_DIR 0xFFC01730 /* Flag Direction register */
+#define FIO2_POLAR 0xFFC01734 /* Flag Polarity register */
+#define FIO2_EDGE 0xFFC01738 /* Flag Interrupt Sensitivity register */
+#define FIO2_BOTH 0xFFC0173C /* Flag Set on Both Edges register */
+#define FIO2_INEN 0xFFC01740 /* Flag Input Enable register */
+
+/* SPORT0 Controller (0xFFC00800 - 0xFFC008FF) */
+#define SPORT0_TCR1 0xFFC00800 /* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_TCR2 0xFFC00804 /* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_TCLKDIV 0xFFC00808 /* SPORT0 Transmit Clock Divider */
+#define SPORT0_TFSDIV 0xFFC0080C /* SPORT0 Transmit Frame Sync Divider */
+#define SPORT0_TX 0xFFC00810 /* SPORT0 TX Data Register */
+#define SPORT0_RX 0xFFC00818 /* SPORT0 RX Data Register */
+#define SPORT0_RCR1 0xFFC00820 /* SPORT0 Transmit Configuration 1 Register */
+#define SPORT0_RCR2 0xFFC00824 /* SPORT0 Transmit Configuration 2 Register */
+#define SPORT0_RCLKDIV 0xFFC00828 /* SPORT0 Receive Clock Divider */
+#define SPORT0_RFSDIV 0xFFC0082C /* SPORT0 Receive Frame Sync Divider */
+#define SPORT0_STAT 0xFFC00830 /* SPORT0 Status Register */
+#define SPORT0_CHNL 0xFFC00834 /* SPORT0 Current Channel Register */
+#define SPORT0_MCMC1 0xFFC00838 /* SPORT0 Multi-Channel Configuration Register 1 */
+#define SPORT0_MCMC2 0xFFC0083C /* SPORT0 Multi-Channel Configuration Register 2 */
+#define SPORT0_MTCS0 0xFFC00840 /* SPORT0 Multi-Channel Transmit Select Register 0 */
+#define SPORT0_MTCS1 0xFFC00844 /* SPORT0 Multi-Channel Transmit Select Register 1 */
+#define SPORT0_MTCS2 0xFFC00848 /* SPORT0 Multi-Channel Transmit Select Register 2 */
+#define SPORT0_MTCS3 0xFFC0084C /* SPORT0 Multi-Channel Transmit Select Register 3 */
+#define SPORT0_MRCS0 0xFFC00850 /* SPORT0 Multi-Channel Receive Select Register 0 */
+#define SPORT0_MRCS1 0xFFC00854 /* SPORT0 Multi-Channel Receive Select Register 1 */
+#define SPORT0_MRCS2 0xFFC00858 /* SPORT0 Multi-Channel Receive Select Register 2 */
+#define SPORT0_MRCS3 0xFFC0085C /* SPORT0 Multi-Channel Receive Select Register 3 */
+
+/* SPORT1 Controller (0xFFC00900 - 0xFFC009FF) */
+#define SPORT1_TCR1 0xFFC00900 /* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_TCR2 0xFFC00904 /* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_TCLKDIV 0xFFC00908 /* SPORT1 Transmit Clock Divider */
+#define SPORT1_TFSDIV 0xFFC0090C /* SPORT1 Transmit Frame Sync Divider */
+#define SPORT1_TX 0xFFC00910 /* SPORT1 TX Data Register */
+#define SPORT1_RX 0xFFC00918 /* SPORT1 RX Data Register */
+#define SPORT1_RCR1 0xFFC00920 /* SPORT1 Transmit Configuration 1 Register */
+#define SPORT1_RCR2 0xFFC00924 /* SPORT1 Transmit Configuration 2 Register */
+#define SPORT1_RCLKDIV 0xFFC00928 /* SPORT1 Receive Clock Divider */
+#define SPORT1_RFSDIV 0xFFC0092C /* SPORT1 Receive Frame Sync Divider */
+#define SPORT1_STAT 0xFFC00930 /* SPORT1 Status Register */
+#define SPORT1_CHNL 0xFFC00934 /* SPORT1 Current Channel Register */
+#define SPORT1_MCMC1 0xFFC00938 /* SPORT1 Multi-Channel Configuration Register 1 */
+#define SPORT1_MCMC2 0xFFC0093C /* SPORT1 Multi-Channel Configuration Register 2 */
+#define SPORT1_MTCS0 0xFFC00940 /* SPORT1 Multi-Channel Transmit Select Register 0 */
+#define SPORT1_MTCS1 0xFFC00944 /* SPORT1 Multi-Channel Transmit Select Register 1 */
+#define SPORT1_MTCS2 0xFFC00948 /* SPORT1 Multi-Channel Transmit Select Register 2 */
+#define SPORT1_MTCS3 0xFFC0094C /* SPORT1 Multi-Channel Transmit Select Register 3 */
+#define SPORT1_MRCS0 0xFFC00950 /* SPORT1 Multi-Channel Receive Select Register 0 */
+#define SPORT1_MRCS1 0xFFC00954 /* SPORT1 Multi-Channel Receive Select Register 1 */
+#define SPORT1_MRCS2 0xFFC00958 /* SPORT1 Multi-Channel Receive Select Register 2 */
+#define SPORT1_MRCS3 0xFFC0095C /* SPORT1 Multi-Channel Receive Select Register 3 */
+
+/* Asynchronous Memory Controller - External Bus Interface Unit */
+#define EBIU_AMGCTL 0xFFC00A00 /* Asynchronous Memory Global Control Register */
+#define EBIU_AMBCTL0 0xFFC00A04 /* Asynchronous Memory Bank Control Register 0 */
+#define EBIU_AMBCTL1 0xFFC00A08 /* Asynchronous Memory Bank Control Register 1 */
+
+/* SDRAM Controller External Bus Interface Unit (0xFFC00A00 - 0xFFC00AFF) */
+#define EBIU_SDGCTL 0xFFC00A10 /* SDRAM Global Control Register */
+#define EBIU_SDBCTL 0xFFC00A14 /* SDRAM Bank Control Register */
+#define EBIU_SDRRC 0xFFC00A18 /* SDRAM Refresh Rate Control Register */
+#define EBIU_SDSTAT 0xFFC00A1C /* SDRAM Status Register */
+
+/* Parallel Peripheral Interface (PPI) 0 registers (0xFFC0 1000-0xFFC0 10FF) */
+#define PPI0_CONTROL 0xFFC01000 /* PPI0 Control register */
+#define PPI0_STATUS 0xFFC01004 /* PPI0 Status register */
+#define PPI0_COUNT 0xFFC01008 /* PPI0 Transfer Count register */
+#define PPI0_DELAY 0xFFC0100C /* PPI0 Delay Count register */
+#define PPI0_FRAME 0xFFC01010 /* PPI0 Frame Length register */
+
+/*Parallel Peripheral Interface (PPI) 1 registers (0xFFC0 1300-0xFFC0 13FF) */
+#define PPI1_CONTROL 0xFFC01300 /* PPI1 Control register */
+#define PPI1_STATUS 0xFFC01304 /* PPI1 Status register */
+#define PPI1_COUNT 0xFFC01308 /* PPI1 Transfer Count register */
+#define PPI1_DELAY 0xFFC0130C /* PPI1 Delay Count register */
+#define PPI1_FRAME 0xFFC01310 /* PPI1 Frame Length register */
+
+/*DMA traffic control registers */
+#define DMA1_TC_PER 0xFFC01B0C /* Traffic control periods */
+#define DMA1_TC_CNT 0xFFC01B10 /* Traffic control current counts */
+#define DMA2_TC_PER 0xFFC00B0C /* Traffic control periods */
+#define DMA2_TC_CNT 0xFFC00B10 /* Traffic control current counts */
+
+/* DMA1 Controller registers (0xFFC0 1C00-0xFFC0 1FFF) */
+#define DMA1_0_CONFIG 0xFFC01C08 /* DMA1 Channel 0 Configuration register */
+#define DMA1_0_NEXT_DESC_PTR 0xFFC01C00 /* DMA1 Channel 0 Next Descripter Ptr Reg */
+#define DMA1_0_START_ADDR 0xFFC01C04 /* DMA1 Channel 0 Start Address */
+#define DMA1_0_X_COUNT 0xFFC01C10 /* DMA1 Channel 0 Inner Loop Count */
+#define DMA1_0_Y_COUNT 0xFFC01C18 /* DMA1 Channel 0 Outer Loop Count */
+#define DMA1_0_X_MODIFY 0xFFC01C14 /* DMA1 Channel 0 Inner Loop Addr Increment */
+#define DMA1_0_Y_MODIFY 0xFFC01C1C /* DMA1 Channel 0 Outer Loop Addr Increment */
+#define DMA1_0_CURR_DESC_PTR 0xFFC01C20 /* DMA1 Channel 0 Current Descriptor Pointer */
+#define DMA1_0_CURR_ADDR 0xFFC01C24 /* DMA1 Channel 0 Current Address Pointer */
+#define DMA1_0_CURR_X_COUNT 0xFFC01C30 /* DMA1 Channel 0 Current Inner Loop Count */
+#define DMA1_0_CURR_Y_COUNT 0xFFC01C38 /* DMA1 Channel 0 Current Outer Loop Count */
+#define DMA1_0_IRQ_STATUS 0xFFC01C28 /* DMA1 Channel 0 Interrupt/Status Register */
+#define DMA1_0_PERIPHERAL_MAP 0xFFC01C2C /* DMA1 Channel 0 Peripheral Map Register */
+
+#define DMA1_1_CONFIG 0xFFC01C48 /* DMA1 Channel 1 Configuration register */
+#define DMA1_1_NEXT_DESC_PTR 0xFFC01C40 /* DMA1 Channel 1 Next Descripter Ptr Reg */
+#define DMA1_1_START_ADDR 0xFFC01C44 /* DMA1 Channel 1 Start Address */
+#define DMA1_1_X_COUNT 0xFFC01C50 /* DMA1 Channel 1 Inner Loop Count */
+#define DMA1_1_Y_COUNT 0xFFC01C58 /* DMA1 Channel 1 Outer Loop Count */
+#define DMA1_1_X_MODIFY 0xFFC01C54 /* DMA1 Channel 1 Inner Loop Addr Increment */
+#define DMA1_1_Y_MODIFY 0xFFC01C5C /* DMA1 Channel 1 Outer Loop Addr Increment */
+#define DMA1_1_CURR_DESC_PTR 0xFFC01C60 /* DMA1 Channel 1 Current Descriptor Pointer */
+#define DMA1_1_CURR_ADDR 0xFFC01C64 /* DMA1 Channel 1 Current Address Pointer */
+#define DMA1_1_CURR_X_COUNT 0xFFC01C70 /* DMA1 Channel 1 Current Inner Loop Count */
+#define DMA1_1_CURR_Y_COUNT 0xFFC01C78 /* DMA1 Channel 1 Current Outer Loop Count */
+#define DMA1_1_IRQ_STATUS 0xFFC01C68 /* DMA1 Channel 1 Interrupt/Status Register */
+#define DMA1_1_PERIPHERAL_MAP 0xFFC01C6C /* DMA1 Channel 1 Peripheral Map Register */
+
+#define DMA1_2_CONFIG 0xFFC01C88 /* DMA1 Channel 2 Configuration register */
+#define DMA1_2_NEXT_DESC_PTR 0xFFC01C80 /* DMA1 Channel 2 Next Descripter Ptr Reg */
+#define DMA1_2_START_ADDR 0xFFC01C84 /* DMA1 Channel 2 Start Address */
+#define DMA1_2_X_COUNT 0xFFC01C90 /* DMA1 Channel 2 Inner Loop Count */
+#define DMA1_2_Y_COUNT 0xFFC01C98 /* DMA1 Channel 2 Outer Loop Count */
+#define DMA1_2_X_MODIFY 0xFFC01C94 /* DMA1 Channel 2 Inner Loop Addr Increment */
+#define DMA1_2_Y_MODIFY 0xFFC01C9C /* DMA1 Channel 2 Outer Loop Addr Increment */
+#define DMA1_2_CURR_DESC_PTR 0xFFC01CA0 /* DMA1 Channel 2 Current Descriptor Pointer */
+#define DMA1_2_CURR_ADDR 0xFFC01CA4 /* DMA1 Channel 2 Current Address Pointer */
+#define DMA1_2_CURR_X_COUNT 0xFFC01CB0 /* DMA1 Channel 2 Current Inner Loop Count */
+#define DMA1_2_CURR_Y_COUNT 0xFFC01CB8 /* DMA1 Channel 2 Current Outer Loop Count */
+#define DMA1_2_IRQ_STATUS 0xFFC01CA8 /* DMA1 Channel 2 Interrupt/Status Register */
+#define DMA1_2_PERIPHERAL_MAP 0xFFC01CAC /* DMA1 Channel 2 Peripheral Map Register */
+
+#define DMA1_3_CONFIG 0xFFC01CC8 /* DMA1 Channel 3 Configuration register */
+#define DMA1_3_NEXT_DESC_PTR 0xFFC01CC0 /* DMA1 Channel 3 Next Descripter Ptr Reg */
+#define DMA1_3_START_ADDR 0xFFC01CC4 /* DMA1 Channel 3 Start Address */
+#define DMA1_3_X_COUNT 0xFFC01CD0 /* DMA1 Channel 3 Inner Loop Count */
+#define DMA1_3_Y_COUNT 0xFFC01CD8 /* DMA1 Channel 3 Outer Loop Count */
+#define DMA1_3_X_MODIFY 0xFFC01CD4 /* DMA1 Channel 3 Inner Loop Addr Increment */
+#define DMA1_3_Y_MODIFY 0xFFC01CDC /* DMA1 Channel 3 Outer Loop Addr Increment */
+#define DMA1_3_CURR_DESC_PTR 0xFFC01CE0 /* DMA1 Channel 3 Current Descriptor Pointer */
+#define DMA1_3_CURR_ADDR 0xFFC01CE4 /* DMA1 Channel 3 Current Address Pointer */
+#define DMA1_3_CURR_X_COUNT 0xFFC01CF0 /* DMA1 Channel 3 Current Inner Loop Count */
+#define DMA1_3_CURR_Y_COUNT 0xFFC01CF8 /* DMA1 Channel 3 Current Outer Loop Count */
+#define DMA1_3_IRQ_STATUS 0xFFC01CE8 /* DMA1 Channel 3 Interrupt/Status Register */
+#define DMA1_3_PERIPHERAL_MAP 0xFFC01CEC /* DMA1 Channel 3 Peripheral Map Register */
+
+#define DMA1_4_CONFIG 0xFFC01D08 /* DMA1 Channel 4 Configuration register */
+#define DMA1_4_NEXT_DESC_PTR 0xFFC01D00 /* DMA1 Channel 4 Next Descripter Ptr Reg */
+#define DMA1_4_START_ADDR 0xFFC01D04 /* DMA1 Channel 4 Start Address */
+#define DMA1_4_X_COUNT 0xFFC01D10 /* DMA1 Channel 4 Inner Loop Count */
+#define DMA1_4_Y_COUNT 0xFFC01D18 /* DMA1 Channel 4 Outer Loop Count */
+#define DMA1_4_X_MODIFY 0xFFC01D14 /* DMA1 Channel 4 Inner Loop Addr Increment */
+#define DMA1_4_Y_MODIFY 0xFFC01D1C /* DMA1 Channel 4 Outer Loop Addr Increment */
+#define DMA1_4_CURR_DESC_PTR 0xFFC01D20 /* DMA1 Channel 4 Current Descriptor Pointer */
+#define DMA1_4_CURR_ADDR 0xFFC01D24 /* DMA1 Channel 4 Current Address Pointer */
+#define DMA1_4_CURR_X_COUNT 0xFFC01D30 /* DMA1 Channel 4 Current Inner Loop Count */
+#define DMA1_4_CURR_Y_COUNT 0xFFC01D38 /* DMA1 Channel 4 Current Outer Loop Count */
+#define DMA1_4_IRQ_STATUS 0xFFC01D28 /* DMA1 Channel 4 Interrupt/Status Register */
+#define DMA1_4_PERIPHERAL_MAP 0xFFC01D2C /* DMA1 Channel 4 Peripheral Map Register */
+
+#define DMA1_5_CONFIG 0xFFC01D48 /* DMA1 Channel 5 Configuration register */
+#define DMA1_5_NEXT_DESC_PTR 0xFFC01D40 /* DMA1 Channel 5 Next Descripter Ptr Reg */
+#define DMA1_5_START_ADDR 0xFFC01D44 /* DMA1 Channel 5 Start Address */
+#define DMA1_5_X_COUNT 0xFFC01D50 /* DMA1 Channel 5 Inner Loop Count */
+#define DMA1_5_Y_COUNT 0xFFC01D58 /* DMA1 Channel 5 Outer Loop Count */
+#define DMA1_5_X_MODIFY 0xFFC01D54 /* DMA1 Channel 5 Inner Loop Addr Increment */
+#define DMA1_5_Y_MODIFY 0xFFC01D5C /* DMA1 Channel 5 Outer Loop Addr Increment */
+#define DMA1_5_CURR_DESC_PTR 0xFFC01D60 /* DMA1 Channel 5 Current Descriptor Pointer */
+#define DMA1_5_CURR_ADDR 0xFFC01D64 /* DMA1 Channel 5 Current Address Pointer */
+#define DMA1_5_CURR_X_COUNT 0xFFC01D70 /* DMA1 Channel 5 Current Inner Loop Count */
+#define DMA1_5_CURR_Y_COUNT 0xFFC01D78 /* DMA1 Channel 5 Current Outer Loop Count */
+#define DMA1_5_IRQ_STATUS 0xFFC01D68 /* DMA1 Channel 5 Interrupt/Status Register */
+#define DMA1_5_PERIPHERAL_MAP 0xFFC01D6C /* DMA1 Channel 5 Peripheral Map Register */
+
+#define DMA1_6_CONFIG 0xFFC01D88 /* DMA1 Channel 6 Configuration register */
+#define DMA1_6_NEXT_DESC_PTR 0xFFC01D80 /* DMA1 Channel 6 Next Descripter Ptr Reg */
+#define DMA1_6_START_ADDR 0xFFC01D84 /* DMA1 Channel 6 Start Address */
+#define DMA1_6_X_COUNT 0xFFC01D90 /* DMA1 Channel 6 Inner Loop Count */
+#define DMA1_6_Y_COUNT 0xFFC01D98 /* DMA1 Channel 6 Outer Loop Count */
+#define DMA1_6_X_MODIFY 0xFFC01D94 /* DMA1 Channel 6 Inner Loop Addr Increment */
+#define DMA1_6_Y_MODIFY 0xFFC01D9C /* DMA1 Channel 6 Outer Loop Addr Increment */
+#define DMA1_6_CURR_DESC_PTR 0xFFC01DA0 /* DMA1 Channel 6 Current Descriptor Pointer */
+#define DMA1_6_CURR_ADDR 0xFFC01DA4 /* DMA1 Channel 6 Current Address Pointer */
+#define DMA1_6_CURR_X_COUNT 0xFFC01DB0 /* DMA1 Channel 6 Current Inner Loop Count */
+#define DMA1_6_CURR_Y_COUNT 0xFFC01DB8 /* DMA1 Channel 6 Current Outer Loop Count */
+#define DMA1_6_IRQ_STATUS 0xFFC01DA8 /* DMA1 Channel 6 Interrupt/Status Register */
+#define DMA1_6_PERIPHERAL_MAP 0xFFC01DAC /* DMA1 Channel 6 Peripheral Map Register */
+
+#define DMA1_7_CONFIG 0xFFC01DC8 /* DMA1 Channel 7 Configuration register */
+#define DMA1_7_NEXT_DESC_PTR 0xFFC01DC0 /* DMA1 Channel 7 Next Descripter Ptr Reg */
+#define DMA1_7_START_ADDR 0xFFC01DC4 /* DMA1 Channel 7 Start Address */
+#define DMA1_7_X_COUNT 0xFFC01DD0 /* DMA1 Channel 7 Inner Loop Count */
+#define DMA1_7_Y_COUNT 0xFFC01DD8 /* DMA1 Channel 7 Outer Loop Count */
+#define DMA1_7_X_MODIFY 0xFFC01DD4 /* DMA1 Channel 7 Inner Loop Addr Increment */
+#define DMA1_7_Y_MODIFY 0xFFC01DDC /* DMA1 Channel 7 Outer Loop Addr Increment */
+#define DMA1_7_CURR_DESC_PTR 0xFFC01DE0 /* DMA1 Channel 7 Current Descriptor Pointer */
+#define DMA1_7_CURR_ADDR 0xFFC01DE4 /* DMA1 Channel 7 Current Address Pointer */
+#define DMA1_7_CURR_X_COUNT 0xFFC01DF0 /* DMA1 Channel 7 Current Inner Loop Count */
+#define DMA1_7_CURR_Y_COUNT 0xFFC01DF8 /* DMA1 Channel 7 Current Outer Loop Count */
+#define DMA1_7_IRQ_STATUS 0xFFC01DE8 /* DMA1 Channel 7 Interrupt/Status Register */
+#define DMA1_7_PERIPHERAL_MAP 0xFFC01DEC /* DMA1 Channel 7 Peripheral Map Register */
+
+#define DMA1_8_CONFIG 0xFFC01E08 /* DMA1 Channel 8 Configuration register */
+#define DMA1_8_NEXT_DESC_PTR 0xFFC01E00 /* DMA1 Channel 8 Next Descripter Ptr Reg */
+#define DMA1_8_START_ADDR 0xFFC01E04 /* DMA1 Channel 8 Start Address */
+#define DMA1_8_X_COUNT 0xFFC01E10 /* DMA1 Channel 8 Inner Loop Count */
+#define DMA1_8_Y_COUNT 0xFFC01E18 /* DMA1 Channel 8 Outer Loop Count */
+#define DMA1_8_X_MODIFY 0xFFC01E14 /* DMA1 Channel 8 Inner Loop Addr Increment */
+#define DMA1_8_Y_MODIFY 0xFFC01E1C /* DMA1 Channel 8 Outer Loop Addr Increment */
+#define DMA1_8_CURR_DESC_PTR 0xFFC01E20 /* DMA1 Channel 8 Current Descriptor Pointer */
+#define DMA1_8_CURR_ADDR 0xFFC01E24 /* DMA1 Channel 8 Current Address Pointer */
+#define DMA1_8_CURR_X_COUNT 0xFFC01E30 /* DMA1 Channel 8 Current Inner Loop Count */
+#define DMA1_8_CURR_Y_COUNT 0xFFC01E38 /* DMA1 Channel 8 Current Outer Loop Count */
+#define DMA1_8_IRQ_STATUS 0xFFC01E28 /* DMA1 Channel 8 Interrupt/Status Register */
+#define DMA1_8_PERIPHERAL_MAP 0xFFC01E2C /* DMA1 Channel 8 Peripheral Map Register */
+
+#define DMA1_9_CONFIG 0xFFC01E48 /* DMA1 Channel 9 Configuration register */
+#define DMA1_9_NEXT_DESC_PTR 0xFFC01E40 /* DMA1 Channel 9 Next Descripter Ptr Reg */
+#define DMA1_9_START_ADDR 0xFFC01E44 /* DMA1 Channel 9 Start Address */
+#define DMA1_9_X_COUNT 0xFFC01E50 /* DMA1 Channel 9 Inner Loop Count */
+#define DMA1_9_Y_COUNT 0xFFC01E58 /* DMA1 Channel 9 Outer Loop Count */
+#define DMA1_9_X_MODIFY 0xFFC01E54 /* DMA1 Channel 9 Inner Loop Addr Increment */
+#define DMA1_9_Y_MODIFY 0xFFC01E5C /* DMA1 Channel 9 Outer Loop Addr Increment */
+#define DMA1_9_CURR_DESC_PTR 0xFFC01E60 /* DMA1 Channel 9 Current Descriptor Pointer */
+#define DMA1_9_CURR_ADDR 0xFFC01E64 /* DMA1 Channel 9 Current Address Pointer */
+#define DMA1_9_CURR_X_COUNT 0xFFC01E70 /* DMA1 Channel 9 Current Inner Loop Count */
+#define DMA1_9_CURR_Y_COUNT 0xFFC01E78 /* DMA1 Channel 9 Current Outer Loop Count */
+#define DMA1_9_IRQ_STATUS 0xFFC01E68 /* DMA1 Channel 9 Interrupt/Status Register */
+#define DMA1_9_PERIPHERAL_MAP 0xFFC01E6C /* DMA1 Channel 9 Peripheral Map Register */
+
+#define DMA1_10_CONFIG 0xFFC01E88 /* DMA1 Channel 10 Configuration register */
+#define DMA1_10_NEXT_DESC_PTR 0xFFC01E80 /* DMA1 Channel 10 Next Descripter Ptr Reg */
+#define DMA1_10_START_ADDR 0xFFC01E84 /* DMA1 Channel 10 Start Address */
+#define DMA1_10_X_COUNT 0xFFC01E90 /* DMA1 Channel 10 Inner Loop Count */
+#define DMA1_10_Y_COUNT 0xFFC01E98 /* DMA1 Channel 10 Outer Loop Count */
+#define DMA1_10_X_MODIFY 0xFFC01E94 /* DMA1 Channel 10 Inner Loop Addr Increment */
+#define DMA1_10_Y_MODIFY 0xFFC01E9C /* DMA1 Channel 10 Outer Loop Addr Increment */
+#define DMA1_10_CURR_DESC_PTR 0xFFC01EA0 /* DMA1 Channel 10 Current Descriptor Pointer */
+#define DMA1_10_CURR_ADDR 0xFFC01EA4 /* DMA1 Channel 10 Current Address Pointer */
+#define DMA1_10_CURR_X_COUNT 0xFFC01EB0 /* DMA1 Channel 10 Current Inner Loop Count */
+#define DMA1_10_CURR_Y_COUNT 0xFFC01EB8 /* DMA1 Channel 10 Current Outer Loop Count */
+#define DMA1_10_IRQ_STATUS 0xFFC01EA8 /* DMA1 Channel 10 Interrupt/Status Register */
+#define DMA1_10_PERIPHERAL_MAP 0xFFC01EAC /* DMA1 Channel 10 Peripheral Map Register */
+
+#define DMA1_11_CONFIG 0xFFC01EC8 /* DMA1 Channel 11 Configuration register */
+#define DMA1_11_NEXT_DESC_PTR 0xFFC01EC0 /* DMA1 Channel 11 Next Descripter Ptr Reg */
+#define DMA1_11_START_ADDR 0xFFC01EC4 /* DMA1 Channel 11 Start Address */
+#define DMA1_11_X_COUNT 0xFFC01ED0 /* DMA1 Channel 11 Inner Loop Count */
+#define DMA1_11_Y_COUNT 0xFFC01ED8 /* DMA1 Channel 11 Outer Loop Count */
+#define DMA1_11_X_MODIFY 0xFFC01ED4 /* DMA1 Channel 11 Inner Loop Addr Increment */
+#define DMA1_11_Y_MODIFY 0xFFC01EDC /* DMA1 Channel 11 Outer Loop Addr Increment */
+#define DMA1_11_CURR_DESC_PTR 0xFFC01EE0 /* DMA1 Channel 11 Current Descriptor Pointer */
+#define DMA1_11_CURR_ADDR 0xFFC01EE4 /* DMA1 Channel 11 Current Address Pointer */
+#define DMA1_11_CURR_X_COUNT 0xFFC01EF0 /* DMA1 Channel 11 Current Inner Loop Count */
+#define DMA1_11_CURR_Y_COUNT 0xFFC01EF8 /* DMA1 Channel 11 Current Outer Loop Count */
+#define DMA1_11_IRQ_STATUS 0xFFC01EE8 /* DMA1 Channel 11 Interrupt/Status Register */
+#define DMA1_11_PERIPHERAL_MAP 0xFFC01EEC /* DMA1 Channel 11 Peripheral Map Register */
+
+/* Memory DMA1 Controller registers (0xFFC0 1E80-0xFFC0 1FFF) */
+#define MDMA1_D0_CONFIG 0xFFC01F08 /*MemDMA1 Stream 0 Destination Configuration */
+#define MDMA1_D0_NEXT_DESC_PTR 0xFFC01F00 /*MemDMA1 Stream 0 Destination Next Descriptor Ptr Reg */
+#define MDMA1_D0_START_ADDR 0xFFC01F04 /*MemDMA1 Stream 0 Destination Start Address */
+#define MDMA1_D0_X_COUNT 0xFFC01F10 /*MemDMA1 Stream 0 Destination Inner-Loop Count */
+#define MDMA1_D0_Y_COUNT 0xFFC01F18 /*MemDMA1 Stream 0 Destination Outer-Loop Count */
+#define MDMA1_D0_X_MODIFY 0xFFC01F14 /*MemDMA1 Stream 0 Dest Inner-Loop Address-Increment */
+#define MDMA1_D0_Y_MODIFY 0xFFC01F1C /*MemDMA1 Stream 0 Dest Outer-Loop Address-Increment */
+#define MDMA1_D0_CURR_DESC_PTR 0xFFC01F20 /*MemDMA1 Stream 0 Dest Current Descriptor Ptr reg */
+#define MDMA1_D0_CURR_ADDR 0xFFC01F24 /*MemDMA1 Stream 0 Destination Current Address */
+#define MDMA1_D0_CURR_X_COUNT 0xFFC01F30 /*MemDMA1 Stream 0 Dest Current Inner-Loop Count */
+#define MDMA1_D0_CURR_Y_COUNT 0xFFC01F38 /*MemDMA1 Stream 0 Dest Current Outer-Loop Count */
+#define MDMA1_D0_IRQ_STATUS 0xFFC01F28 /*MemDMA1 Stream 0 Destination Interrupt/Status */
+#define MDMA1_D0_PERIPHERAL_MAP 0xFFC01F2C /*MemDMA1 Stream 0 Destination Peripheral Map */
+
+#define MDMA1_S0_CONFIG 0xFFC01F48 /*MemDMA1 Stream 0 Source Configuration */
+#define MDMA1_S0_NEXT_DESC_PTR 0xFFC01F40 /*MemDMA1 Stream 0 Source Next Descriptor Ptr Reg */
+#define MDMA1_S0_START_ADDR 0xFFC01F44 /*MemDMA1 Stream 0 Source Start Address */
+#define MDMA1_S0_X_COUNT 0xFFC01F50 /*MemDMA1 Stream 0 Source Inner-Loop Count */
+#define MDMA1_S0_Y_COUNT 0xFFC01F58 /*MemDMA1 Stream 0 Source Outer-Loop Count */
+#define MDMA1_S0_X_MODIFY 0xFFC01F54 /*MemDMA1 Stream 0 Source Inner-Loop Address-Increment */
+#define MDMA1_S0_Y_MODIFY 0xFFC01F5C /*MemDMA1 Stream 0 Source Outer-Loop Address-Increment */
+#define MDMA1_S0_CURR_DESC_PTR 0xFFC01F60 /*MemDMA1 Stream 0 Source Current Descriptor Ptr reg */
+#define MDMA1_S0_CURR_ADDR 0xFFC01F64 /*MemDMA1 Stream 0 Source Current Address */
+#define MDMA1_S0_CURR_X_COUNT 0xFFC01F70 /*MemDMA1 Stream 0 Source Current Inner-Loop Count */
+#define MDMA1_S0_CURR_Y_COUNT 0xFFC01F78 /*MemDMA1 Stream 0 Source Current Outer-Loop Count */
+#define MDMA1_S0_IRQ_STATUS 0xFFC01F68 /*MemDMA1 Stream 0 Source Interrupt/Status */
+#define MDMA1_S0_PERIPHERAL_MAP 0xFFC01F6C /*MemDMA1 Stream 0 Source Peripheral Map */
+
+#define MDMA1_D1_CONFIG 0xFFC01F88 /*MemDMA1 Stream 1 Destination Configuration */
+#define MDMA1_D1_NEXT_DESC_PTR 0xFFC01F80 /*MemDMA1 Stream 1 Destination Next Descriptor Ptr Reg */
+#define MDMA1_D1_START_ADDR 0xFFC01F84 /*MemDMA1 Stream 1 Destination Start Address */
+#define MDMA1_D1_X_COUNT 0xFFC01F90 /*MemDMA1 Stream 1 Destination Inner-Loop Count */
+#define MDMA1_D1_Y_COUNT 0xFFC01F98 /*MemDMA1 Stream 1 Destination Outer-Loop Count */
+#define MDMA1_D1_X_MODIFY 0xFFC01F94 /*MemDMA1 Stream 1 Dest Inner-Loop Address-Increment */
+#define MDMA1_D1_Y_MODIFY 0xFFC01F9C /*MemDMA1 Stream 1 Dest Outer-Loop Address-Increment */
+#define MDMA1_D1_CURR_DESC_PTR 0xFFC01FA0 /*MemDMA1 Stream 1 Dest Current Descriptor Ptr reg */
+#define MDMA1_D1_CURR_ADDR 0xFFC01FA4 /*MemDMA1 Stream 1 Dest Current Address */
+#define MDMA1_D1_CURR_X_COUNT 0xFFC01FB0 /*MemDMA1 Stream 1 Dest Current Inner-Loop Count */
+#define MDMA1_D1_CURR_Y_COUNT 0xFFC01FB8 /*MemDMA1 Stream 1 Dest Current Outer-Loop Count */
+#define MDMA1_D1_IRQ_STATUS 0xFFC01FA8 /*MemDMA1 Stream 1 Dest Interrupt/Status */
+#define MDMA1_D1_PERIPHERAL_MAP 0xFFC01FAC /*MemDMA1 Stream 1 Dest Peripheral Map */
+
+#define MDMA1_S1_CONFIG 0xFFC01FC8 /*MemDMA1 Stream 1 Source Configuration */
+#define MDMA1_S1_NEXT_DESC_PTR 0xFFC01FC0 /*MemDMA1 Stream 1 Source Next Descriptor Ptr Reg */
+#define MDMA1_S1_START_ADDR 0xFFC01FC4 /*MemDMA1 Stream 1 Source Start Address */
+#define MDMA1_S1_X_COUNT 0xFFC01FD0 /*MemDMA1 Stream 1 Source Inner-Loop Count */
+#define MDMA1_S1_Y_COUNT 0xFFC01FD8 /*MemDMA1 Stream 1 Source Outer-Loop Count */
+#define MDMA1_S1_X_MODIFY 0xFFC01FD4 /*MemDMA1 Stream 1 Source Inner-Loop Address-Increment */
+#define MDMA1_S1_Y_MODIFY 0xFFC01FDC /*MemDMA1 Stream 1 Source Outer-Loop Address-Increment */
+#define MDMA1_S1_CURR_DESC_PTR 0xFFC01FE0 /*MemDMA1 Stream 1 Source Current Descriptor Ptr reg */
+#define MDMA1_S1_CURR_ADDR 0xFFC01FE4 /*MemDMA1 Stream 1 Source Current Address */
+#define MDMA1_S1_CURR_X_COUNT 0xFFC01FF0 /*MemDMA1 Stream 1 Source Current Inner-Loop Count */
+#define MDMA1_S1_CURR_Y_COUNT 0xFFC01FF8 /*MemDMA1 Stream 1 Source Current Outer-Loop Count */
+#define MDMA1_S1_IRQ_STATUS 0xFFC01FE8 /*MemDMA1 Stream 1 Source Interrupt/Status */
+#define MDMA1_S1_PERIPHERAL_MAP 0xFFC01FEC /*MemDMA1 Stream 1 Source Peripheral Map */
+
+/* DMA2 Controller registers (0xFFC0 0C00-0xFFC0 0DFF) */
+#define DMA2_0_CONFIG 0xFFC00C08 /* DMA2 Channel 0 Configuration register */
+#define DMA2_0_NEXT_DESC_PTR 0xFFC00C00 /* DMA2 Channel 0 Next Descripter Ptr Reg */
+#define DMA2_0_START_ADDR 0xFFC00C04 /* DMA2 Channel 0 Start Address */
+#define DMA2_0_X_COUNT 0xFFC00C10 /* DMA2 Channel 0 Inner Loop Count */
+#define DMA2_0_Y_COUNT 0xFFC00C18 /* DMA2 Channel 0 Outer Loop Count */
+#define DMA2_0_X_MODIFY 0xFFC00C14 /* DMA2 Channel 0 Inner Loop Addr Increment */
+#define DMA2_0_Y_MODIFY 0xFFC00C1C /* DMA2 Channel 0 Outer Loop Addr Increment */
+#define DMA2_0_CURR_DESC_PTR 0xFFC00C20 /* DMA2 Channel 0 Current Descriptor Pointer */
+#define DMA2_0_CURR_ADDR 0xFFC00C24 /* DMA2 Channel 0 Current Address Pointer */
+#define DMA2_0_CURR_X_COUNT 0xFFC00C30 /* DMA2 Channel 0 Current Inner Loop Count */
+#define DMA2_0_CURR_Y_COUNT 0xFFC00C38 /* DMA2 Channel 0 Current Outer Loop Count */
+#define DMA2_0_IRQ_STATUS 0xFFC00C28 /* DMA2 Channel 0 Interrupt/Status Register */
+#define DMA2_0_PERIPHERAL_MAP 0xFFC00C2C /* DMA2 Channel 0 Peripheral Map Register */
+
+#define DMA2_1_CONFIG 0xFFC00C48 /* DMA2 Channel 1 Configuration register */
+#define DMA2_1_NEXT_DESC_PTR 0xFFC00C40 /* DMA2 Channel 1 Next Descripter Ptr Reg */
+#define DMA2_1_START_ADDR 0xFFC00C44 /* DMA2 Channel 1 Start Address */
+#define DMA2_1_X_COUNT 0xFFC00C50 /* DMA2 Channel 1 Inner Loop Count */
+#define DMA2_1_Y_COUNT 0xFFC00C58 /* DMA2 Channel 1 Outer Loop Count */
+#define DMA2_1_X_MODIFY 0xFFC00C54 /* DMA2 Channel 1 Inner Loop Addr Increment */
+#define DMA2_1_Y_MODIFY 0xFFC00C5C /* DMA2 Channel 1 Outer Loop Addr Increment */
+#define DMA2_1_CURR_DESC_PTR 0xFFC00C60 /* DMA2 Channel 1 Current Descriptor Pointer */
+#define DMA2_1_CURR_ADDR 0xFFC00C64 /* DMA2 Channel 1 Current Address Pointer */
+#define DMA2_1_CURR_X_COUNT 0xFFC00C70 /* DMA2 Channel 1 Current Inner Loop Count */
+#define DMA2_1_CURR_Y_COUNT 0xFFC00C78 /* DMA2 Channel 1 Current Outer Loop Count */
+#define DMA2_1_IRQ_STATUS 0xFFC00C68 /* DMA2 Channel 1 Interrupt/Status Register */
+#define DMA2_1_PERIPHERAL_MAP 0xFFC00C6C /* DMA2 Channel 1 Peripheral Map Register */
+
+#define DMA2_2_CONFIG 0xFFC00C88 /* DMA2 Channel 2 Configuration register */
+#define DMA2_2_NEXT_DESC_PTR 0xFFC00C80 /* DMA2 Channel 2 Next Descripter Ptr Reg */
+#define DMA2_2_START_ADDR 0xFFC00C84 /* DMA2 Channel 2 Start Address */
+#define DMA2_2_X_COUNT 0xFFC00C90 /* DMA2 Channel 2 Inner Loop Count */
+#define DMA2_2_Y_COUNT 0xFFC00C98 /* DMA2 Channel 2 Outer Loop Count */
+#define DMA2_2_X_MODIFY 0xFFC00C94 /* DMA2 Channel 2 Inner Loop Addr Increment */
+#define DMA2_2_Y_MODIFY 0xFFC00C9C /* DMA2 Channel 2 Outer Loop Addr Increment */
+#define DMA2_2_CURR_DESC_PTR 0xFFC00CA0 /* DMA2 Channel 2 Current Descriptor Pointer */
+#define DMA2_2_CURR_ADDR 0xFFC00CA4 /* DMA2 Channel 2 Current Address Pointer */
+#define DMA2_2_CURR_X_COUNT 0xFFC00CB0 /* DMA2 Channel 2 Current Inner Loop Count */
+#define DMA2_2_CURR_Y_COUNT 0xFFC00CB8 /* DMA2 Channel 2 Current Outer Loop Count */
+#define DMA2_2_IRQ_STATUS 0xFFC00CA8 /* DMA2 Channel 2 Interrupt/Status Register */
+#define DMA2_2_PERIPHERAL_MAP 0xFFC00CAC /* DMA2 Channel 2 Peripheral Map Register */
+
+#define DMA2_3_CONFIG 0xFFC00CC8 /* DMA2 Channel 3 Configuration register */
+#define DMA2_3_NEXT_DESC_PTR 0xFFC00CC0 /* DMA2 Channel 3 Next Descripter Ptr Reg */
+#define DMA2_3_START_ADDR 0xFFC00CC4 /* DMA2 Channel 3 Start Address */
+#define DMA2_3_X_COUNT 0xFFC00CD0 /* DMA2 Channel 3 Inner Loop Count */
+#define DMA2_3_Y_COUNT 0xFFC00CD8 /* DMA2 Channel 3 Outer Loop Count */
+#define DMA2_3_X_MODIFY 0xFFC00CD4 /* DMA2 Channel 3 Inner Loop Addr Increment */
+#define DMA2_3_Y_MODIFY 0xFFC00CDC /* DMA2 Channel 3 Outer Loop Addr Increment */
+#define DMA2_3_CURR_DESC_PTR 0xFFC00CE0 /* DMA2 Channel 3 Current Descriptor Pointer */
+#define DMA2_3_CURR_ADDR 0xFFC00CE4 /* DMA2 Channel 3 Current Address Pointer */
+#define DMA2_3_CURR_X_COUNT 0xFFC00CF0 /* DMA2 Channel 3 Current Inner Loop Count */
+#define DMA2_3_CURR_Y_COUNT 0xFFC00CF8 /* DMA2 Channel 3 Current Outer Loop Count */
+#define DMA2_3_IRQ_STATUS 0xFFC00CE8 /* DMA2 Channel 3 Interrupt/Status Register */
+#define DMA2_3_PERIPHERAL_MAP 0xFFC00CEC /* DMA2 Channel 3 Peripheral Map Register */
+
+#define DMA2_4_CONFIG 0xFFC00D08 /* DMA2 Channel 4 Configuration register */
+#define DMA2_4_NEXT_DESC_PTR 0xFFC00D00 /* DMA2 Channel 4 Next Descripter Ptr Reg */
+#define DMA2_4_START_ADDR 0xFFC00D04 /* DMA2 Channel 4 Start Address */
+#define DMA2_4_X_COUNT 0xFFC00D10 /* DMA2 Channel 4 Inner Loop Count */
+#define DMA2_4_Y_COUNT 0xFFC00D18 /* DMA2 Channel 4 Outer Loop Count */
+#define DMA2_4_X_MODIFY 0xFFC00D14 /* DMA2 Channel 4 Inner Loop Addr Increment */
+#define DMA2_4_Y_MODIFY 0xFFC00D1C /* DMA2 Channel 4 Outer Loop Addr Increment */
+#define DMA2_4_CURR_DESC_PTR 0xFFC00D20 /* DMA2 Channel 4 Current Descriptor Pointer */
+#define DMA2_4_CURR_ADDR 0xFFC00D24 /* DMA2 Channel 4 Current Address Pointer */
+#define DMA2_4_CURR_X_COUNT 0xFFC00D30 /* DMA2 Channel 4 Current Inner Loop Count */
+#define DMA2_4_CURR_Y_COUNT 0xFFC00D38 /* DMA2 Channel 4 Current Outer Loop Count */
+#define DMA2_4_IRQ_STATUS 0xFFC00D28 /* DMA2 Channel 4 Interrupt/Status Register */
+#define DMA2_4_PERIPHERAL_MAP 0xFFC00D2C /* DMA2 Channel 4 Peripheral Map Register */
+
+#define DMA2_5_CONFIG 0xFFC00D48 /* DMA2 Channel 5 Configuration register */
+#define DMA2_5_NEXT_DESC_PTR 0xFFC00D40 /* DMA2 Channel 5 Next Descripter Ptr Reg */
+#define DMA2_5_START_ADDR 0xFFC00D44 /* DMA2 Channel 5 Start Address */
+#define DMA2_5_X_COUNT 0xFFC00D50 /* DMA2 Channel 5 Inner Loop Count */
+#define DMA2_5_Y_COUNT 0xFFC00D58 /* DMA2 Channel 5 Outer Loop Count */
+#define DMA2_5_X_MODIFY 0xFFC00D54 /* DMA2 Channel 5 Inner Loop Addr Increment */
+#define DMA2_5_Y_MODIFY 0xFFC00D5C /* DMA2 Channel 5 Outer Loop Addr Increment */
+#define DMA2_5_CURR_DESC_PTR 0xFFC00D60 /* DMA2 Channel 5 Current Descriptor Pointer */
+#define DMA2_5_CURR_ADDR 0xFFC00D64 /* DMA2 Channel 5 Current Address Pointer */
+#define DMA2_5_CURR_X_COUNT 0xFFC00D70 /* DMA2 Channel 5 Current Inner Loop Count */
+#define DMA2_5_CURR_Y_COUNT 0xFFC00D78 /* DMA2 Channel 5 Current Outer Loop Count */
+#define DMA2_5_IRQ_STATUS 0xFFC00D68 /* DMA2 Channel 5 Interrupt/Status Register */
+#define DMA2_5_PERIPHERAL_MAP 0xFFC00D6C /* DMA2 Channel 5 Peripheral Map Register */
+
+#define DMA2_6_CONFIG 0xFFC00D88 /* DMA2 Channel 6 Configuration register */
+#define DMA2_6_NEXT_DESC_PTR 0xFFC00D80 /* DMA2 Channel 6 Next Descripter Ptr Reg */
+#define DMA2_6_START_ADDR 0xFFC00D84 /* DMA2 Channel 6 Start Address */
+#define DMA2_6_X_COUNT 0xFFC00D90 /* DMA2 Channel 6 Inner Loop Count */
+#define DMA2_6_Y_COUNT 0xFFC00D98 /* DMA2 Channel 6 Outer Loop Count */
+#define DMA2_6_X_MODIFY 0xFFC00D94 /* DMA2 Channel 6 Inner Loop Addr Increment */
+#define DMA2_6_Y_MODIFY 0xFFC00D9C /* DMA2 Channel 6 Outer Loop Addr Increment */
+#define DMA2_6_CURR_DESC_PTR 0xFFC00DA0 /* DMA2 Channel 6 Current Descriptor Pointer */
+#define DMA2_6_CURR_ADDR 0xFFC00DA4 /* DMA2 Channel 6 Current Address Pointer */
+#define DMA2_6_CURR_X_COUNT 0xFFC00DB0 /* DMA2 Channel 6 Current Inner Loop Count */
+#define DMA2_6_CURR_Y_COUNT 0xFFC00DB8 /* DMA2 Channel 6 Current Outer Loop Count */
+#define DMA2_6_IRQ_STATUS 0xFFC00DA8 /* DMA2 Channel 6 Interrupt/Status Register */
+#define DMA2_6_PERIPHERAL_MAP 0xFFC00DAC /* DMA2 Channel 6 Peripheral Map Register */
+
+#define DMA2_7_CONFIG 0xFFC00DC8 /* DMA2 Channel 7 Configuration register */
+#define DMA2_7_NEXT_DESC_PTR 0xFFC00DC0 /* DMA2 Channel 7 Next Descripter Ptr Reg */
+#define DMA2_7_START_ADDR 0xFFC00DC4 /* DMA2 Channel 7 Start Address */
+#define DMA2_7_X_COUNT 0xFFC00DD0 /* DMA2 Channel 7 Inner Loop Count */
+#define DMA2_7_Y_COUNT 0xFFC00DD8 /* DMA2 Channel 7 Outer Loop Count */
+#define DMA2_7_X_MODIFY 0xFFC00DD4 /* DMA2 Channel 7 Inner Loop Addr Increment */
+#define DMA2_7_Y_MODIFY 0xFFC00DDC /* DMA2 Channel 7 Outer Loop Addr Increment */
+#define DMA2_7_CURR_DESC_PTR 0xFFC00DE0 /* DMA2 Channel 7 Current Descriptor Pointer */
+#define DMA2_7_CURR_ADDR 0xFFC00DE4 /* DMA2 Channel 7 Current Address Pointer */
+#define DMA2_7_CURR_X_COUNT 0xFFC00DF0 /* DMA2 Channel 7 Current Inner Loop Count */
+#define DMA2_7_CURR_Y_COUNT 0xFFC00DF8 /* DMA2 Channel 7 Current Outer Loop Count */
+#define DMA2_7_IRQ_STATUS 0xFFC00DE8 /* DMA2 Channel 7 Interrupt/Status Register */
+#define DMA2_7_PERIPHERAL_MAP 0xFFC00DEC /* DMA2 Channel 7 Peripheral Map Register */
+
+#define DMA2_8_CONFIG 0xFFC00E08 /* DMA2 Channel 8 Configuration register */
+#define DMA2_8_NEXT_DESC_PTR 0xFFC00E00 /* DMA2 Channel 8 Next Descripter Ptr Reg */
+#define DMA2_8_START_ADDR 0xFFC00E04 /* DMA2 Channel 8 Start Address */
+#define DMA2_8_X_COUNT 0xFFC00E10 /* DMA2 Channel 8 Inner Loop Count */
+#define DMA2_8_Y_COUNT 0xFFC00E18 /* DMA2 Channel 8 Outer Loop Count */
+#define DMA2_8_X_MODIFY 0xFFC00E14 /* DMA2 Channel 8 Inner Loop Addr Increment */
+#define DMA2_8_Y_MODIFY 0xFFC00E1C /* DMA2 Channel 8 Outer Loop Addr Increment */
+#define DMA2_8_CURR_DESC_PTR 0xFFC00E20 /* DMA2 Channel 8 Current Descriptor Pointer */
+#define DMA2_8_CURR_ADDR 0xFFC00E24 /* DMA2 Channel 8 Current Address Pointer */
+#define DMA2_8_CURR_X_COUNT 0xFFC00E30 /* DMA2 Channel 8 Current Inner Loop Count */
+#define DMA2_8_CURR_Y_COUNT 0xFFC00E38 /* DMA2 Channel 8 Current Outer Loop Count */
+#define DMA2_8_IRQ_STATUS 0xFFC00E28 /* DMA2 Channel 8 Interrupt/Status Register */
+#define DMA2_8_PERIPHERAL_MAP 0xFFC00E2C /* DMA2 Channel 8 Peripheral Map Register */
+
+#define DMA2_9_CONFIG 0xFFC00E48 /* DMA2 Channel 9 Configuration register */
+#define DMA2_9_NEXT_DESC_PTR 0xFFC00E40 /* DMA2 Channel 9 Next Descripter Ptr Reg */
+#define DMA2_9_START_ADDR 0xFFC00E44 /* DMA2 Channel 9 Start Address */
+#define DMA2_9_X_COUNT 0xFFC00E50 /* DMA2 Channel 9 Inner Loop Count */
+#define DMA2_9_Y_COUNT 0xFFC00E58 /* DMA2 Channel 9 Outer Loop Count */
+#define DMA2_9_X_MODIFY 0xFFC00E54 /* DMA2 Channel 9 Inner Loop Addr Increment */
+#define DMA2_9_Y_MODIFY 0xFFC00E5C /* DMA2 Channel 9 Outer Loop Addr Increment */
+#define DMA2_9_CURR_DESC_PTR 0xFFC00E60 /* DMA2 Channel 9 Current Descriptor Pointer */
+#define DMA2_9_CURR_ADDR 0xFFC00E64 /* DMA2 Channel 9 Current Address Pointer */
+#define DMA2_9_CURR_X_COUNT 0xFFC00E70 /* DMA2 Channel 9 Current Inner Loop Count */
+#define DMA2_9_CURR_Y_COUNT 0xFFC00E78 /* DMA2 Channel 9 Current Outer Loop Count */
+#define DMA2_9_IRQ_STATUS 0xFFC00E68 /* DMA2 Channel 9 Interrupt/Status Register */
+#define DMA2_9_PERIPHERAL_MAP 0xFFC00E6C /* DMA2 Channel 9 Peripheral Map Register */
+
+#define DMA2_10_CONFIG 0xFFC00E88 /* DMA2 Channel 10 Configuration register */
+#define DMA2_10_NEXT_DESC_PTR 0xFFC00E80 /* DMA2 Channel 10 Next Descripter Ptr Reg */
+#define DMA2_10_START_ADDR 0xFFC00E84 /* DMA2 Channel 10 Start Address */
+#define DMA2_10_X_COUNT 0xFFC00E90 /* DMA2 Channel 10 Inner Loop Count */
+#define DMA2_10_Y_COUNT 0xFFC00E98 /* DMA2 Channel 10 Outer Loop Count */
+#define DMA2_10_X_MODIFY 0xFFC00E94 /* DMA2 Channel 10 Inner Loop Addr Increment */
+#define DMA2_10_Y_MODIFY 0xFFC00E9C /* DMA2 Channel 10 Outer Loop Addr Increment */
+#define DMA2_10_CURR_DESC_PTR 0xFFC00EA0 /* DMA2 Channel 10 Current Descriptor Pointer */
+#define DMA2_10_CURR_ADDR 0xFFC00EA4 /* DMA2 Channel 10 Current Address Pointer */
+#define DMA2_10_CURR_X_COUNT 0xFFC00EB0 /* DMA2 Channel 10 Current Inner Loop Count */
+#define DMA2_10_CURR_Y_COUNT 0xFFC00EB8 /* DMA2 Channel 10 Current Outer Loop Count */
+#define DMA2_10_IRQ_STATUS 0xFFC00EA8 /* DMA2 Channel 10 Interrupt/Status Register */
+#define DMA2_10_PERIPHERAL_MAP 0xFFC00EAC /* DMA2 Channel 10 Peripheral Map Register */
+
+#define DMA2_11_CONFIG 0xFFC00EC8 /* DMA2 Channel 11 Configuration register */
+#define DMA2_11_NEXT_DESC_PTR 0xFFC00EC0 /* DMA2 Channel 11 Next Descripter Ptr Reg */
+#define DMA2_11_START_ADDR 0xFFC00EC4 /* DMA2 Channel 11 Start Address */
+#define DMA2_11_X_COUNT 0xFFC00ED0 /* DMA2 Channel 11 Inner Loop Count */
+#define DMA2_11_Y_COUNT 0xFFC00ED8 /* DMA2 Channel 11 Outer Loop Count */
+#define DMA2_11_X_MODIFY 0xFFC00ED4 /* DMA2 Channel 11 Inner Loop Addr Increment */
+#define DMA2_11_Y_MODIFY 0xFFC00EDC /* DMA2 Channel 11 Outer Loop Addr Increment */
+#define DMA2_11_CURR_DESC_PTR 0xFFC00EE0 /* DMA2 Channel 11 Current Descriptor Pointer */
+#define DMA2_11_CURR_ADDR 0xFFC00EE4 /* DMA2 Channel 11 Current Address Pointer */
+#define DMA2_11_CURR_X_COUNT 0xFFC00EF0 /* DMA2 Channel 11 Current Inner Loop Count */
+#define DMA2_11_CURR_Y_COUNT 0xFFC00EF8 /* DMA2 Channel 11 Current Outer Loop Count */
+#define DMA2_11_IRQ_STATUS 0xFFC00EE8 /* DMA2 Channel 11 Interrupt/Status Register */
+#define DMA2_11_PERIPHERAL_MAP 0xFFC00EEC /* DMA2 Channel 11 Peripheral Map Register */
+
+/* Memory DMA2 Controller registers (0xFFC0 0E80-0xFFC0 0FFF) */
+#define MDMA2_D0_CONFIG 0xFFC00F08 /*MemDMA2 Stream 0 Destination Configuration register */
+#define MDMA2_D0_NEXT_DESC_PTR 0xFFC00F00 /*MemDMA2 Stream 0 Destination Next Descriptor Ptr Reg */
+#define MDMA2_D0_START_ADDR 0xFFC00F04 /*MemDMA2 Stream 0 Destination Start Address */
+#define MDMA2_D0_X_COUNT 0xFFC00F10 /*MemDMA2 Stream 0 Dest Inner-Loop Count register */
+#define MDMA2_D0_Y_COUNT 0xFFC00F18 /*MemDMA2 Stream 0 Dest Outer-Loop Count register */
+#define MDMA2_D0_X_MODIFY 0xFFC00F14 /*MemDMA2 Stream 0 Dest Inner-Loop Address-Increment */
+#define MDMA2_D0_Y_MODIFY 0xFFC00F1C /*MemDMA2 Stream 0 Dest Outer-Loop Address-Increment */
+#define MDMA2_D0_CURR_DESC_PTR 0xFFC00F20 /*MemDMA2 Stream 0 Dest Current Descriptor Ptr reg */
+#define MDMA2_D0_CURR_ADDR 0xFFC00F24 /*MemDMA2 Stream 0 Destination Current Address */
+#define MDMA2_D0_CURR_X_COUNT 0xFFC00F30 /*MemDMA2 Stream 0 Dest Current Inner-Loop Count reg */
+#define MDMA2_D0_CURR_Y_COUNT 0xFFC00F38 /*MemDMA2 Stream 0 Dest Current Outer-Loop Count reg */
+#define MDMA2_D0_IRQ_STATUS 0xFFC00F28 /*MemDMA2 Stream 0 Dest Interrupt/Status Register */
+#define MDMA2_D0_PERIPHERAL_MAP 0xFFC00F2C /*MemDMA2 Stream 0 Destination Peripheral Map register */
+
+#define MDMA2_S0_CONFIG 0xFFC00F48 /*MemDMA2 Stream 0 Source Configuration register */
+#define MDMA2_S0_NEXT_DESC_PTR 0xFFC00F40 /*MemDMA2 Stream 0 Source Next Descriptor Ptr Reg */
+#define MDMA2_S0_START_ADDR 0xFFC00F44 /*MemDMA2 Stream 0 Source Start Address */
+#define MDMA2_S0_X_COUNT 0xFFC00F50 /*MemDMA2 Stream 0 Source Inner-Loop Count register */
+#define MDMA2_S0_Y_COUNT 0xFFC00F58 /*MemDMA2 Stream 0 Source Outer-Loop Count register */
+#define MDMA2_S0_X_MODIFY 0xFFC00F54 /*MemDMA2 Stream 0 Src Inner-Loop Addr-Increment reg */
+#define MDMA2_S0_Y_MODIFY 0xFFC00F5C /*MemDMA2 Stream 0 Src Outer-Loop Addr-Increment reg */
+#define MDMA2_S0_CURR_DESC_PTR 0xFFC00F60 /*MemDMA2 Stream 0 Source Current Descriptor Ptr reg */
+#define MDMA2_S0_CURR_ADDR 0xFFC00F64 /*MemDMA2 Stream 0 Source Current Address */
+#define MDMA2_S0_CURR_X_COUNT 0xFFC00F70 /*MemDMA2 Stream 0 Src Current Inner-Loop Count reg */
+#define MDMA2_S0_CURR_Y_COUNT 0xFFC00F78 /*MemDMA2 Stream 0 Src Current Outer-Loop Count reg */
+#define MDMA2_S0_IRQ_STATUS 0xFFC00F68 /*MemDMA2 Stream 0 Source Interrupt/Status Register */
+#define MDMA2_S0_PERIPHERAL_MAP 0xFFC00F6C /*MemDMA2 Stream 0 Source Peripheral Map register */
+
+#define MDMA2_D1_CONFIG 0xFFC00F88 /*MemDMA2 Stream 1 Destination Configuration register */
+#define MDMA2_D1_NEXT_DESC_PTR 0xFFC00F80 /*MemDMA2 Stream 1 Destination Next Descriptor Ptr Reg */
+#define MDMA2_D1_START_ADDR 0xFFC00F84 /*MemDMA2 Stream 1 Destination Start Address */
+#define MDMA2_D1_X_COUNT 0xFFC00F90 /*MemDMA2 Stream 1 Dest Inner-Loop Count register */
+#define MDMA2_D1_Y_COUNT 0xFFC00F98 /*MemDMA2 Stream 1 Dest Outer-Loop Count register */
+#define MDMA2_D1_X_MODIFY 0xFFC00F94 /*MemDMA2 Stream 1 Dest Inner-Loop Address-Increment */
+#define MDMA2_D1_Y_MODIFY 0xFFC00F9C /*MemDMA2 Stream 1 Dest Outer-Loop Address-Increment */
+#define MDMA2_D1_CURR_DESC_PTR 0xFFC00FA0 /*MemDMA2 Stream 1 Destination Current Descriptor Ptr */
+#define MDMA2_D1_CURR_ADDR 0xFFC00FA4 /*MemDMA2 Stream 1 Destination Current Address reg */
+#define MDMA2_D1_CURR_X_COUNT 0xFFC00FB0 /*MemDMA2 Stream 1 Dest Current Inner-Loop Count reg */
+#define MDMA2_D1_CURR_Y_COUNT 0xFFC00FB8 /*MemDMA2 Stream 1 Dest Current Outer-Loop Count reg */
+#define MDMA2_D1_IRQ_STATUS 0xFFC00FA8 /*MemDMA2 Stream 1 Destination Interrupt/Status Reg */
+#define MDMA2_D1_PERIPHERAL_MAP 0xFFC00FAC /*MemDMA2 Stream 1 Destination Peripheral Map register */
+
+#define MDMA2_S1_CONFIG 0xFFC00FC8 /*MemDMA2 Stream 1 Source Configuration register */
+#define MDMA2_S1_NEXT_DESC_PTR 0xFFC00FC0 /*MemDMA2 Stream 1 Source Next Descriptor Ptr Reg */
+#define MDMA2_S1_START_ADDR 0xFFC00FC4 /*MemDMA2 Stream 1 Source Start Address */
+#define MDMA2_S1_X_COUNT 0xFFC00FD0 /*MemDMA2 Stream 1 Source Inner-Loop Count register */
+#define MDMA2_S1_Y_COUNT 0xFFC00FD8 /*MemDMA2 Stream 1 Source Outer-Loop Count register */
+#define MDMA2_S1_X_MODIFY 0xFFC00FD4 /*MemDMA2 Stream 1 Src Inner-Loop Address-Increment */
+#define MDMA2_S1_Y_MODIFY 0xFFC00FDC /*MemDMA2 Stream 1 Source Outer-Loop Address-Increment */
+#define MDMA2_S1_CURR_DESC_PTR 0xFFC00FE0 /*MemDMA2 Stream 1 Source Current Descriptor Ptr reg */
+#define MDMA2_S1_CURR_ADDR 0xFFC00FE4 /*MemDMA2 Stream 1 Source Current Address */
+#define MDMA2_S1_CURR_X_COUNT 0xFFC00FF0 /*MemDMA2 Stream 1 Source Current Inner-Loop Count */
+#define MDMA2_S1_CURR_Y_COUNT 0xFFC00FF8 /*MemDMA2 Stream 1 Source Current Outer-Loop Count */
+#define MDMA2_S1_IRQ_STATUS 0xFFC00FE8 /*MemDMA2 Stream 1 Source Interrupt/Status Register */
+#define MDMA2_S1_PERIPHERAL_MAP 0xFFC00FEC /*MemDMA2 Stream 1 Source Peripheral Map register */
+
+/* Internal Memory DMA Registers (0xFFC0_1800 - 0xFFC0_19FF) */
+#define IMDMA_D0_CONFIG 0xFFC01808 /*IMDMA Stream 0 Destination Configuration */
+#define IMDMA_D0_NEXT_DESC_PTR 0xFFC01800 /*IMDMA Stream 0 Destination Next Descriptor Ptr Reg */
+#define IMDMA_D0_START_ADDR 0xFFC01804 /*IMDMA Stream 0 Destination Start Address */
+#define IMDMA_D0_X_COUNT 0xFFC01810 /*IMDMA Stream 0 Destination Inner-Loop Count */
+#define IMDMA_D0_Y_COUNT 0xFFC01818 /*IMDMA Stream 0 Destination Outer-Loop Count */
+#define IMDMA_D0_X_MODIFY 0xFFC01814 /*IMDMA Stream 0 Dest Inner-Loop Address-Increment */
+#define IMDMA_D0_Y_MODIFY 0xFFC0181C /*IMDMA Stream 0 Dest Outer-Loop Address-Increment */
+#define IMDMA_D0_CURR_DESC_PTR 0xFFC01820 /*IMDMA Stream 0 Destination Current Descriptor Ptr */
+#define IMDMA_D0_CURR_ADDR 0xFFC01824 /*IMDMA Stream 0 Destination Current Address */
+#define IMDMA_D0_CURR_X_COUNT 0xFFC01830 /*IMDMA Stream 0 Destination Current Inner-Loop Count */
+#define IMDMA_D0_CURR_Y_COUNT 0xFFC01838 /*IMDMA Stream 0 Destination Current Outer-Loop Count */
+#define IMDMA_D0_IRQ_STATUS 0xFFC01828 /*IMDMA Stream 0 Destination Interrupt/Status */
+
+#define IMDMA_S0_CONFIG 0xFFC01848 /*IMDMA Stream 0 Source Configuration */
+#define IMDMA_S0_NEXT_DESC_PTR 0xFFC01840 /*IMDMA Stream 0 Source Next Descriptor Ptr Reg */
+#define IMDMA_S0_START_ADDR 0xFFC01844 /*IMDMA Stream 0 Source Start Address */
+#define IMDMA_S0_X_COUNT 0xFFC01850 /*IMDMA Stream 0 Source Inner-Loop Count */
+#define IMDMA_S0_Y_COUNT 0xFFC01858 /*IMDMA Stream 0 Source Outer-Loop Count */
+#define IMDMA_S0_X_MODIFY 0xFFC01854 /*IMDMA Stream 0 Source Inner-Loop Address-Increment */
+#define IMDMA_S0_Y_MODIFY 0xFFC0185C /*IMDMA Stream 0 Source Outer-Loop Address-Increment */
+#define IMDMA_S0_CURR_DESC_PTR 0xFFC01860 /*IMDMA Stream 0 Source Current Descriptor Ptr reg */
+#define IMDMA_S0_CURR_ADDR 0xFFC01864 /*IMDMA Stream 0 Source Current Address */
+#define IMDMA_S0_CURR_X_COUNT 0xFFC01870 /*IMDMA Stream 0 Source Current Inner-Loop Count */
+#define IMDMA_S0_CURR_Y_COUNT 0xFFC01878 /*IMDMA Stream 0 Source Current Outer-Loop Count */
+#define IMDMA_S0_IRQ_STATUS 0xFFC01868 /*IMDMA Stream 0 Source Interrupt/Status */
+
+#define IMDMA_D1_CONFIG 0xFFC01888 /*IMDMA Stream 1 Destination Configuration */
+#define IMDMA_D1_NEXT_DESC_PTR 0xFFC01880 /*IMDMA Stream 1 Destination Next Descriptor Ptr Reg */
+#define IMDMA_D1_START_ADDR 0xFFC01884 /*IMDMA Stream 1 Destination Start Address */
+#define IMDMA_D1_X_COUNT 0xFFC01890 /*IMDMA Stream 1 Destination Inner-Loop Count */
+#define IMDMA_D1_Y_COUNT 0xFFC01898 /*IMDMA Stream 1 Destination Outer-Loop Count */
+#define IMDMA_D1_X_MODIFY 0xFFC01894 /*IMDMA Stream 1 Dest Inner-Loop Address-Increment */
+#define IMDMA_D1_Y_MODIFY 0xFFC0189C /*IMDMA Stream 1 Dest Outer-Loop Address-Increment */
+#define IMDMA_D1_CURR_DESC_PTR 0xFFC018A0 /*IMDMA Stream 1 Destination Current Descriptor Ptr */
+#define IMDMA_D1_CURR_ADDR 0xFFC018A4 /*IMDMA Stream 1 Destination Current Address */
+#define IMDMA_D1_CURR_X_COUNT 0xFFC018B0 /*IMDMA Stream 1 Destination Current Inner-Loop Count */
+#define IMDMA_D1_CURR_Y_COUNT 0xFFC018B8 /*IMDMA Stream 1 Destination Current Outer-Loop Count */
+#define IMDMA_D1_IRQ_STATUS 0xFFC018A8 /*IMDMA Stream 1 Destination Interrupt/Status */
+
+#define IMDMA_S1_CONFIG 0xFFC018C8 /*IMDMA Stream 1 Source Configuration */
+#define IMDMA_S1_NEXT_DESC_PTR 0xFFC018C0 /*IMDMA Stream 1 Source Next Descriptor Ptr Reg */
+#define IMDMA_S1_START_ADDR 0xFFC018C4 /*IMDMA Stream 1 Source Start Address */
+#define IMDMA_S1_X_COUNT 0xFFC018D0 /*IMDMA Stream 1 Source Inner-Loop Count */
+#define IMDMA_S1_Y_COUNT 0xFFC018D8 /*IMDMA Stream 1 Source Outer-Loop Count */
+#define IMDMA_S1_X_MODIFY 0xFFC018D4 /*IMDMA Stream 1 Source Inner-Loop Address-Increment */
+#define IMDMA_S1_Y_MODIFY 0xFFC018DC /*IMDMA Stream 1 Source Outer-Loop Address-Increment */
+#define IMDMA_S1_CURR_DESC_PTR 0xFFC018E0 /*IMDMA Stream 1 Source Current Descriptor Ptr reg */
+#define IMDMA_S1_CURR_ADDR 0xFFC018E4 /*IMDMA Stream 1 Source Current Address */
+#define IMDMA_S1_CURR_X_COUNT 0xFFC018F0 /*IMDMA Stream 1 Source Current Inner-Loop Count */
+#define IMDMA_S1_CURR_Y_COUNT 0xFFC018F8 /*IMDMA Stream 1 Source Current Outer-Loop Count */
+#define IMDMA_S1_IRQ_STATUS 0xFFC018E8 /*IMDMA Stream 1 Source Interrupt/Status */
+
+/*********************************************************************************** */
+/* System MMR Register Bits */
+/******************************************************************************* */
+
+/* ********************* PLL AND RESET MASKS ************************ */
+
+/* PLL_CTL Masks */
+#define PLL_CLKIN 0x00000000 /* Pass CLKIN to PLL */
+#define PLL_CLKIN_DIV2 0x00000001 /* Pass CLKIN/2 to PLL */
+#define PLL_OFF 0x00000002 /* Shut off PLL clocks */
+#define STOPCK_OFF 0x00000008 /* Core clock off */
+#define PDWN 0x00000020 /* Put the PLL in a Deep Sleep state */
+#define BYPASS 0x00000100 /* Bypass the PLL */
+
+/* CHIPID Masks */
+#define CHIPID_VERSION 0xF0000000
+#define CHIPID_FAMILY 0x0FFFF000
+#define CHIPID_MANUFACTURE 0x00000FFE
+
+/* PLL_DIV Masks */
+#define SCLK_DIV(x) (x) /* SCLK = VCO / x */
+
+#define CCLK_DIV1 0x00000000 /* CCLK = VCO / 1 */
+#define CCLK_DIV2 0x00000010 /* CCLK = VCO / 2 */
+#define CCLK_DIV4 0x00000020 /* CCLK = VCO / 4 */
+#define CCLK_DIV8 0x00000030 /* CCLK = VCO / 8 */
+
+/* PLL_STAT Masks */
+#define ACTIVE_PLLENABLED 0x0001 /* Processor In Active Mode With PLL Enabled */
+#define FULL_ON 0x0002 /* Processor In Full On Mode */
+#define ACTIVE_PLLDISABLED 0x0004 /* Processor In Active Mode With PLL Disabled */
+#define PLL_LOCKED 0x0020 /* PLL_LOCKCNT Has Been Reached */
+
+/* SWRST Mask */
+#define SYSTEM_RESET 0x00000007 /* Initiates a system software reset */
+#define SWRST_DBL_FAULT_B 0x00000800 /* SWRST Core B Double Fault */
+#define SWRST_DBL_FAULT_A 0x00001000 /* SWRST Core A Double Fault */
+#define SWRST_WDT_B 0x00002000 /* SWRST Watchdog B */
+#define SWRST_WDT_A 0x00004000 /* SWRST Watchdog A */
+#define SWRST_OCCURRED 0x00008000 /* SWRST Status */
+
+/* ************* SYSTEM INTERRUPT CONTROLLER MASKS ***************** */
+
+/* SICu_IARv Masks */
+/* u = A or B */
+/* v = 0 to 7 */
+/* w = 0 or 1 */
+
+/* Per_number = 0 to 63 */
+/* IVG_number = 7 to 15 */
+#define Peripheral_IVG(Per_number, IVG_number) \
+ ((IVG_number) - 7) << (((Per_number) % 8) * 4) /* Peripheral #Per_number assigned IVG #IVG_number */
+ /* Usage: r0.l = lo(Peripheral_IVG(62, 10)); */
+ /* r0.h = hi(Peripheral_IVG(62, 10)); */
+
+/* SICx_IMASKw Masks */
+/* masks are 32 bit wide, so two writes reguired for "64 bit" wide registers */
+#define SIC_UNMASK_ALL 0x00000000 /* Unmask all peripheral interrupts */
+#define SIC_MASK_ALL 0xFFFFFFFF /* Mask all peripheral interrupts */
+#define SIC_MASK(x) (1 << (x)) /* Mask Peripheral #x interrupt */
+#define SIC_UNMASK(x) (0xFFFFFFFF ^ (1 << (x))) /* Unmask Peripheral #x interrupt */
+
+/* SIC_IWR Masks */
+#define IWR_DISABLE_ALL 0x00000000 /* Wakeup Disable all peripherals */
+#define IWR_ENABLE_ALL 0xFFFFFFFF /* Wakeup Enable all peripherals */
+/* x = pos 0 to 31, for 32-63 use value-32 */
+#define IWR_ENABLE(x) (1 << (x)) /* Wakeup Enable Peripheral #x */
+#define IWR_DISABLE(x) (0xFFFFFFFF ^ (1 << (x))) /* Wakeup Disable Peripheral #x */
+
+/* ********* WATCHDOG TIMER MASKS ********************8 */
+
+/* Watchdog Timer WDOG_CTL Register */
+#define ICTL(x) ((x<<1) & 0x0006)
+#define ENABLE_RESET 0x00000000 /* Set Watchdog Timer to generate reset */
+#define ENABLE_NMI 0x00000002 /* Set Watchdog Timer to generate non-maskable interrupt */
+#define ENABLE_GPI 0x00000004 /* Set Watchdog Timer to generate general-purpose interrupt */
+#define DISABLE_EVT 0x00000006 /* Disable Watchdog Timer interrupts */
+
+#define TMR_EN 0x0000
+#define TMR_DIS 0x0AD0
+#define TRO 0x8000
+
+#define ICTL_P0 0x01
+#define ICTL_P1 0x02
+#define TRO_P 0x0F
+
+/* ***************************** UART CONTROLLER MASKS ********************** */
+
+/* UART_LCR Register */
+
+#define DLAB 0x80
+#define SB 0x40
+#define STP 0x20
+#define EPS 0x10
+#define PEN 0x08
+#define STB 0x04
+#define WLS(x) ((x-5) & 0x03)
+
+#define DLAB_P 0x07
+#define SB_P 0x06
+#define STP_P 0x05
+#define EPS_P 0x04
+#define PEN_P 0x03
+#define STB_P 0x02
+#define WLS_P1 0x01
+#define WLS_P0 0x00
+
+/* UART_MCR Register */
+#define LOOP_ENA 0x10
+#define LOOP_ENA_P 0x04
+
+/* UART_LSR Register */
+#define TEMT 0x40
+#define THRE 0x20
+#define BI 0x10
+#define FE 0x08
+#define PE 0x04
+#define OE 0x02
+#define DR 0x01
+
+#define TEMP_P 0x06
+#define THRE_P 0x05
+#define BI_P 0x04
+#define FE_P 0x03
+#define PE_P 0x02
+#define OE_P 0x01
+#define DR_P 0x00
+
+/* UART_IER Register */
+#define ELSI 0x04
+#define ETBEI 0x02
+#define ERBFI 0x01
+
+#define ELSI_P 0x02
+#define ETBEI_P 0x01
+#define ERBFI_P 0x00
+
+/* UART_IIR Register */
+#define STATUS(x) ((x << 1) & 0x06)
+#define NINT 0x01
+#define STATUS_P1 0x02
+#define STATUS_P0 0x01
+#define NINT_P 0x00
+#define IIR_TX_READY 0x02 /* UART_THR empty */
+#define IIR_RX_READY 0x04 /* Receive data ready */
+#define IIR_LINE_CHANGE 0x06 /* Receive line status */
+#define IIR_STATUS 0x06
+
+/* UART_GCTL Register */
+#define FFE 0x20
+#define FPE 0x10
+#define RPOLC 0x08
+#define TPOLC 0x04
+#define IREN 0x02
+#define UCEN 0x01
+
+#define FFE_P 0x05
+#define FPE_P 0x04
+#define RPOLC_P 0x03
+#define TPOLC_P 0x02
+#define IREN_P 0x01
+#define UCEN_P 0x00
+
+/* ********** SERIAL PORT MASKS ********************** */
+
+/* SPORTx_TCR1 Masks */
+#define TSPEN 0x0001 /* TX enable */
+#define ITCLK 0x0002 /* Internal TX Clock Select */
+#define TDTYPE 0x000C /* TX Data Formatting Select */
+#define TLSBIT 0x0010 /* TX Bit Order */
+#define ITFS 0x0200 /* Internal TX Frame Sync Select */
+#define TFSR 0x0400 /* TX Frame Sync Required Select */
+#define DITFS 0x0800 /* Data Independent TX Frame Sync Select */
+#define LTFS 0x1000 /* Low TX Frame Sync Select */
+#define LATFS 0x2000 /* Late TX Frame Sync Select */
+#define TCKFE 0x4000 /* TX Clock Falling Edge Select */
+
+/* SPORTx_TCR2 Masks */
+#define SLEN 0x001F /*TX Word Length */
+#define TXSE 0x0100 /*TX Secondary Enable */
+#define TSFSE 0x0200 /*TX Stereo Frame Sync Enable */
+#define TRFST 0x0400 /*TX Right-First Data Order */
+
+/* SPORTx_RCR1 Masks */
+#define RSPEN 0x0001 /* RX enable */
+#define IRCLK 0x0002 /* Internal RX Clock Select */
+#define RDTYPE 0x000C /* RX Data Formatting Select */
+#define RULAW 0x0008 /* u-Law enable */
+#define RALAW 0x000C /* A-Law enable */
+#define RLSBIT 0x0010 /* RX Bit Order */
+#define IRFS 0x0200 /* Internal RX Frame Sync Select */
+#define RFSR 0x0400 /* RX Frame Sync Required Select */
+#define LRFS 0x1000 /* Low RX Frame Sync Select */
+#define LARFS 0x2000 /* Late RX Frame Sync Select */
+#define RCKFE 0x4000 /* RX Clock Falling Edge Select */
+
+/* SPORTx_RCR2 Masks */
+#define SLEN 0x001F /*RX Word Length */
+#define RXSE 0x0100 /*RX Secondary Enable */
+#define RSFSE 0x0200 /*RX Stereo Frame Sync Enable */
+#define RRFST 0x0400 /*Right-First Data Order */
+
+/*SPORTx_STAT Masks */
+#define RXNE 0x0001 /*RX FIFO Not Empty Status */
+#define RUVF 0x0002 /*RX Underflow Status */
+#define ROVF 0x0004 /*RX Overflow Status */
+#define TXF 0x0008 /*TX FIFO Full Status */
+#define TUVF 0x0010 /*TX Underflow Status */
+#define TOVF 0x0020 /*TX Overflow Status */
+#define TXHRE 0x0040 /*TX Hold Register Empty */
+
+/*SPORTx_MCMC1 Masks */
+#define SP_WSIZE 0x0000F000 /*Multichannel Window Size Field */
+#define SP_WOFF 0x000003FF /*Multichannel Window Offset Field */
+
+/*SPORTx_MCMC2 Masks */
+#define MCCRM 0x00000003 /*Multichannel Clock Recovery Mode */
+#define MCDTXPE 0x00000004 /*Multichannel DMA Transmit Packing */
+#define MCDRXPE 0x00000008 /*Multichannel DMA Receive Packing */
+#define MCMEN 0x00000010 /*Multichannel Frame Mode Enable */
+#define FSDR 0x00000080 /*Multichannel Frame Sync to Data Relationship */
+#define MFD 0x0000F000 /*Multichannel Frame Delay */
+
+/* ********* PARALLEL PERIPHERAL INTERFACE (PPI) MASKS **************** */
+
+/* PPI_CONTROL Masks */
+#define PORT_EN 0x00000001 /* PPI Port Enable */
+#define PORT_DIR 0x00000002 /* PPI Port Direction */
+#define XFR_TYPE 0x0000000C /* PPI Transfer Type */
+#define PORT_CFG 0x00000030 /* PPI Port Configuration */
+#define FLD_SEL 0x00000040 /* PPI Active Field Select */
+#define PACK_EN 0x00000080 /* PPI Packing Mode */
+#define DMA32 0x00000100 /* PPI 32-bit DMA Enable */
+#define SKIP_EN 0x00000200 /* PPI Skip Element Enable */
+#define SKIP_EO 0x00000400 /* PPI Skip Even/Odd Elements */
+#define DLENGTH 0x00003800 /* PPI Data Length */
+#define DLEN_8 0x0 /* PPI Data Length mask for DLEN=8 */
+#define DLEN(x) (((x-9) & 0x07) << 11) /* PPI Data Length (only works for x=10-->x=16) */
+#define POL 0x0000C000 /* PPI Signal Polarities */
+
+/* PPI_STATUS Masks */
+#define FLD 0x00000400 /* Field Indicator */
+#define FT_ERR 0x00000800 /* Frame Track Error */
+#define OVR 0x00001000 /* FIFO Overflow Error */
+#define UNDR 0x00002000 /* FIFO Underrun Error */
+#define ERR_DET 0x00004000 /* Error Detected Indicator */
+#define ERR_NCOR 0x00008000 /* Error Not Corrected Indicator */
+
+/* ********** DMA CONTROLLER MASKS *********************8 */
+
+/* DMAx_CONFIG, MDMA_yy_CONFIG, IMDMA_yy_CONFIG Masks */
+#define DMAEN 0x00000001 /* Channel Enable */
+#define WNR 0x00000002 /* Channel Direction (W/R*) */
+#define WDSIZE_8 0x00000000 /* Word Size 8 bits */
+#define WDSIZE_16 0x00000004 /* Word Size 16 bits */
+#define WDSIZE_32 0x00000008 /* Word Size 32 bits */
+#define DMA2D 0x00000010 /* 2D/1D* Mode */
+#define RESTART 0x00000020 /* Restart */
+#define DI_SEL 0x00000040 /* Data Interrupt Select */
+#define DI_EN 0x00000080 /* Data Interrupt Enable */
+#define NDSIZE_0 0x0000 /* Next Descriptor Size = 0 (Stop/Autobuffer) */
+#define NDSIZE_1 0x0100 /* Next Descriptor Size = 1 */
+#define NDSIZE_2 0x0200 /* Next Descriptor Size = 2 */
+#define NDSIZE_3 0x0300 /* Next Descriptor Size = 3 */
+#define NDSIZE_4 0x0400 /* Next Descriptor Size = 4 */
+#define NDSIZE_5 0x0500 /* Next Descriptor Size = 5 */
+#define NDSIZE_6 0x0600 /* Next Descriptor Size = 6 */
+#define NDSIZE_7 0x0700 /* Next Descriptor Size = 7 */
+#define NDSIZE_8 0x0800 /* Next Descriptor Size = 8 */
+#define NDSIZE_9 0x0900 /* Next Descriptor Size = 9 */
+#define NDSIZE 0x00000900 /* Next Descriptor Size */
+#define DMAFLOW 0x00007000 /* Flow Control */
+#define DMAFLOW_STOP 0x0000 /* Stop Mode */
+#define DMAFLOW_AUTO 0x1000 /* Autobuffer Mode */
+#define DMAFLOW_ARRAY 0x4000 /* Descriptor Array Mode */
+#define DMAFLOW_SMALL 0x6000 /* Small Model Descriptor List Mode */
+#define DMAFLOW_LARGE 0x7000 /* Large Model Descriptor List Mode */
+
+#define DMAEN_P 0 /* Channel Enable */
+#define WNR_P 1 /* Channel Direction (W/R*) */
+#define DMA2D_P 4 /* 2D/1D* Mode */
+#define RESTART_P 5 /* Restart */
+#define DI_SEL_P 6 /* Data Interrupt Select */
+#define DI_EN_P 7 /* Data Interrupt Enable */
+
+/* DMAx_IRQ_STATUS, MDMA_yy_IRQ_STATUS, IMDMA_yy_IRQ_STATUS Masks */
+
+#define DMA_DONE 0x00000001 /* DMA Done Indicator */
+#define DMA_ERR 0x00000002 /* DMA Error Indicator */
+#define DFETCH 0x00000004 /* Descriptor Fetch Indicator */
+#define DMA_RUN 0x00000008 /* DMA Running Indicator */
+
+#define DMA_DONE_P 0 /* DMA Done Indicator */
+#define DMA_ERR_P 1 /* DMA Error Indicator */
+#define DFETCH_P 2 /* Descriptor Fetch Indicator */
+#define DMA_RUN_P 3 /* DMA Running Indicator */
+
+/* DMAx_PERIPHERAL_MAP, MDMA_yy_PERIPHERAL_MAP, IMDMA_yy_PERIPHERAL_MAP Masks */
+
+#define CTYPE 0x00000040 /* DMA Channel Type Indicator */
+#define CTYPE_P 6 /* DMA Channel Type Indicator BIT POSITION */
+#define PCAP8 0x00000080 /* DMA 8-bit Operation Indicator */
+#define PCAP16 0x00000100 /* DMA 16-bit Operation Indicator */
+#define PCAP32 0x00000200 /* DMA 32-bit Operation Indicator */
+#define PCAPWR 0x00000400 /* DMA Write Operation Indicator */
+#define PCAPRD 0x00000800 /* DMA Read Operation Indicator */
+#define PMAP 0x00007000 /* DMA Peripheral Map Field */
+
+/* ************* GENERAL PURPOSE TIMER MASKS ******************** */
+
+/* PWM Timer bit definitions */
+
+/* TIMER_ENABLE Register */
+#define TIMEN0 0x0001
+#define TIMEN1 0x0002
+#define TIMEN2 0x0004
+#define TIMEN3 0x0008
+#define TIMEN4 0x0010
+#define TIMEN5 0x0020
+#define TIMEN6 0x0040
+#define TIMEN7 0x0080
+#define TIMEN8 0x0001
+#define TIMEN9 0x0002
+#define TIMEN10 0x0004
+#define TIMEN11 0x0008
+
+#define TIMEN0_P 0x00
+#define TIMEN1_P 0x01
+#define TIMEN2_P 0x02
+#define TIMEN3_P 0x03
+#define TIMEN4_P 0x04
+#define TIMEN5_P 0x05
+#define TIMEN6_P 0x06
+#define TIMEN7_P 0x07
+#define TIMEN8_P 0x00
+#define TIMEN9_P 0x01
+#define TIMEN10_P 0x02
+#define TIMEN11_P 0x03
+
+/* TIMER_DISABLE Register */
+#define TIMDIS0 0x0001
+#define TIMDIS1 0x0002
+#define TIMDIS2 0x0004
+#define TIMDIS3 0x0008
+#define TIMDIS4 0x0010
+#define TIMDIS5 0x0020
+#define TIMDIS6 0x0040
+#define TIMDIS7 0x0080
+#define TIMDIS8 0x0001
+#define TIMDIS9 0x0002
+#define TIMDIS10 0x0004
+#define TIMDIS11 0x0008
+
+#define TIMDIS0_P 0x00
+#define TIMDIS1_P 0x01
+#define TIMDIS2_P 0x02
+#define TIMDIS3_P 0x03
+#define TIMDIS4_P 0x04
+#define TIMDIS5_P 0x05
+#define TIMDIS6_P 0x06
+#define TIMDIS7_P 0x07
+#define TIMDIS8_P 0x00
+#define TIMDIS9_P 0x01
+#define TIMDIS10_P 0x02
+#define TIMDIS11_P 0x03
+
+/* TIMER_STATUS Register */
+#define TIMIL0 0x00000001
+#define TIMIL1 0x00000002
+#define TIMIL2 0x00000004
+#define TIMIL3 0x00000008
+#define TIMIL4 0x00010000
+#define TIMIL5 0x00020000
+#define TIMIL6 0x00040000
+#define TIMIL7 0x00080000
+#define TIMIL8 0x0001
+#define TIMIL9 0x0002
+#define TIMIL10 0x0004
+#define TIMIL11 0x0008
+#define TOVL_ERR0 0x00000010
+#define TOVL_ERR1 0x00000020
+#define TOVL_ERR2 0x00000040
+#define TOVL_ERR3 0x00000080
+#define TOVL_ERR4 0x00100000
+#define TOVL_ERR5 0x00200000
+#define TOVL_ERR6 0x00400000
+#define TOVL_ERR7 0x00800000
+#define TOVL_ERR8 0x0010
+#define TOVL_ERR9 0x0020
+#define TOVL_ERR10 0x0040
+#define TOVL_ERR11 0x0080
+#define TRUN0 0x00001000
+#define TRUN1 0x00002000
+#define TRUN2 0x00004000
+#define TRUN3 0x00008000
+#define TRUN4 0x10000000
+#define TRUN5 0x20000000
+#define TRUN6 0x40000000
+#define TRUN7 0x80000000
+#define TRUN8 0x1000
+#define TRUN9 0x2000
+#define TRUN10 0x4000
+#define TRUN11 0x8000
+
+#define TIMIL0_P 0x00
+#define TIMIL1_P 0x01
+#define TIMIL2_P 0x02
+#define TIMIL3_P 0x03
+#define TIMIL4_P 0x10
+#define TIMIL5_P 0x11
+#define TIMIL6_P 0x12
+#define TIMIL7_P 0x13
+#define TIMIL8_P 0x00
+#define TIMIL9_P 0x01
+#define TIMIL10_P 0x02
+#define TIMIL11_P 0x03
+#define TOVL_ERR0_P 0x04
+#define TOVL_ERR1_P 0x05
+#define TOVL_ERR2_P 0x06
+#define TOVL_ERR3_P 0x07
+#define TOVL_ERR4_P 0x14
+#define TOVL_ERR5_P 0x15
+#define TOVL_ERR6_P 0x16
+#define TOVL_ERR7_P 0x17
+#define TOVL_ERR8_P 0x04
+#define TOVL_ERR9_P 0x05
+#define TOVL_ERR10_P 0x06
+#define TOVL_ERR11_P 0x07
+#define TRUN0_P 0x0C
+#define TRUN1_P 0x0D
+#define TRUN2_P 0x0E
+#define TRUN3_P 0x0F
+#define TRUN4_P 0x1C
+#define TRUN5_P 0x1D
+#define TRUN6_P 0x1E
+#define TRUN7_P 0x1F
+#define TRUN8_P 0x0C
+#define TRUN9_P 0x0D
+#define TRUN10_P 0x0E
+#define TRUN11_P 0x0F
+
+/* TIMERx_CONFIG Registers */
+#define PWM_OUT 0x0001
+#define WDTH_CAP 0x0002
+#define EXT_CLK 0x0003
+#define PULSE_HI 0x0004
+#define PERIOD_CNT 0x0008
+#define IRQ_ENA 0x0010
+#define TIN_SEL 0x0020
+#define OUT_DIS 0x0040
+#define CLK_SEL 0x0080
+#define TOGGLE_HI 0x0100
+#define EMU_RUN 0x0200
+#define ERR_TYP(x) ((x & 0x03) << 14)
+
+#define TMODE_P0 0x00
+#define TMODE_P1 0x01
+#define PULSE_HI_P 0x02
+#define PERIOD_CNT_P 0x03
+#define IRQ_ENA_P 0x04
+#define TIN_SEL_P 0x05
+#define OUT_DIS_P 0x06
+#define CLK_SEL_P 0x07
+#define TOGGLE_HI_P 0x08
+#define EMU_RUN_P 0x09
+#define ERR_TYP_P0 0x0E
+#define ERR_TYP_P1 0x0F
+
+/*/ ****************** PROGRAMMABLE FLAG MASKS ********************* */
+
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) Masks */
+#define PF0 0x0001
+#define PF1 0x0002
+#define PF2 0x0004
+#define PF3 0x0008
+#define PF4 0x0010
+#define PF5 0x0020
+#define PF6 0x0040
+#define PF7 0x0080
+#define PF8 0x0100
+#define PF9 0x0200
+#define PF10 0x0400
+#define PF11 0x0800
+#define PF12 0x1000
+#define PF13 0x2000
+#define PF14 0x4000
+#define PF15 0x8000
+
+/* General Purpose IO (0xFFC00700 - 0xFFC007FF) BIT POSITIONS */
+#define PF0_P 0
+#define PF1_P 1
+#define PF2_P 2
+#define PF3_P 3
+#define PF4_P 4
+#define PF5_P 5
+#define PF6_P 6
+#define PF7_P 7
+#define PF8_P 8
+#define PF9_P 9
+#define PF10_P 10
+#define PF11_P 11
+#define PF12_P 12
+#define PF13_P 13
+#define PF14_P 14
+#define PF15_P 15
+
+/* *********** SERIAL PERIPHERAL INTERFACE (SPI) MASKS **************** */
+
+/* SPI_CTL Masks */
+#define TIMOD 0x00000003 /* Transfer initiation mode and interrupt generation */
+#define SZ 0x00000004 /* Send Zero (=0) or last (=1) word when TDBR empty. */
+#define GM 0x00000008 /* When RDBR full, get more (=1) data or discard (=0) incoming Data */
+#define PSSE 0x00000010 /* Enable (=1) Slave-Select input for Master. */
+#define EMISO 0x00000020 /* Enable (=1) MISO pin as an output. */
+#define SIZE 0x00000100 /* Word length (0 => 8 bits, 1 => 16 bits) */
+#define LSBF 0x00000200 /* Data format (0 => MSB sent/received first 1 => LSB sent/received first) */
+#define CPHA 0x00000400 /* Clock phase (0 => SPICLK starts toggling in middle of xfer, 1 => SPICLK toggles at the beginning of xfer. */
+#define CPOL 0x00000800 /* Clock polarity (0 => active-high, 1 => active-low) */
+#define MSTR 0x00001000 /* Configures SPI as master (=1) or slave (=0) */
+#define WOM 0x00002000 /* Open drain (=1) data output enable (for MOSI and MISO) */
+#define SPE 0x00004000 /* SPI module enable (=1), disable (=0) */
+
+/* SPI_FLG Masks */
+#define FLS1 0x00000002 /* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2 0x00000004 /* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3 0x00000008 /* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4 0x00000010 /* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5 0x00000020 /* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6 0x00000040 /* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7 0x00000080 /* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1 0x00000200 /* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLG2 0x00000400 /* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3 0x00000800 /* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLG4 0x00001000 /* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLG5 0x00002000 /* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLG6 0x00004000 /* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLG7 0x00008000 /* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_FLG Bit Positions */
+#define FLS1_P 0x00000001 /* Enables (=1) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLS2_P 0x00000002 /* Enables (=1) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLS3_P 0x00000003 /* Enables (=1) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLS4_P 0x00000004 /* Enables (=1) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLS5_P 0x00000005 /* Enables (=1) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLS6_P 0x00000006 /* Enables (=1) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLS7_P 0x00000007 /* Enables (=1) SPI_FLOUT7 as flag output for SPI Slave-select */
+#define FLG1_P 0x00000009 /* Activates (=0) SPI_FLOUT1 as flag output for SPI Slave-select */
+#define FLG2_P 0x0000000A /* Activates (=0) SPI_FLOUT2 as flag output for SPI Slave-select */
+#define FLG3_P 0x0000000B /* Activates (=0) SPI_FLOUT3 as flag output for SPI Slave-select */
+#define FLG4_P 0x0000000C /* Activates (=0) SPI_FLOUT4 as flag output for SPI Slave-select */
+#define FLG5_P 0x0000000D /* Activates (=0) SPI_FLOUT5 as flag output for SPI Slave-select */
+#define FLG6_P 0x0000000E /* Activates (=0) SPI_FLOUT6 as flag output for SPI Slave-select */
+#define FLG7_P 0x0000000F /* Activates (=0) SPI_FLOUT7 as flag output for SPI Slave-select */
+
+/* SPI_STAT Masks */
+#define SPIF 0x00000001 /* Set (=1) when SPI single-word transfer complete */
+#define MODF 0x00000002 /* Set (=1) in a master device when some other device tries to become master */
+#define TXE 0x00000004 /* Set (=1) when transmission occurs with no new data in SPI_TDBR */
+#define TXS 0x00000008 /* SPI_TDBR Data Buffer Status (0=Empty, 1=Full) */
+#define RBSY 0x00000010 /* Set (=1) when data is received with RDBR full */
+#define RXS 0x00000020 /* SPI_RDBR Data Buffer Status (0=Empty, 1=Full) */
+#define TXCOL 0x00000040 /* When set (=1), corrupt data may have been transmitted */
+
+/* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS ************* */
+
+/* AMGCTL Masks */
+#define AMCKEN 0x0001 /* Enable CLKOUT */
+#define AMBEN_B0 0x0002 /* Enable Asynchronous Memory Bank 0 only */
+#define AMBEN_B0_B1 0x0004 /* Enable Asynchronous Memory Banks 0 & 1 only */
+#define AMBEN_B0_B1_B2 0x0006 /* Enable Asynchronous Memory Banks 0, 1, and 2 */
+#define AMBEN_ALL 0x0008 /* Enable Asynchronous Memory Banks (all) 0, 1, 2, and 3 */
+#define B0_PEN 0x0010 /* Enable 16-bit packing Bank 0 */
+#define B1_PEN 0x0020 /* Enable 16-bit packing Bank 1 */
+#define B2_PEN 0x0040 /* Enable 16-bit packing Bank 2 */
+#define B3_PEN 0x0080 /* Enable 16-bit packing Bank 3 */
+
+/* AMGCTL Bit Positions */
+#define AMCKEN_P 0x00000000 /* Enable CLKOUT */
+#define AMBEN_P0 0x00000001 /* Asynchronous Memory Enable, 000 - banks 0-3 disabled, 001 - Bank 0 enabled */
+#define AMBEN_P1 0x00000002 /* Asynchronous Memory Enable, 010 - banks 0&1 enabled, 011 - banks 0-3 enabled */
+#define AMBEN_P2 0x00000003 /* Asynchronous Memory Enable, 1xx - All banks (bank 0, 1, 2, and 3) enabled */
+#define B0_PEN_P 0x004 /* Enable 16-bit packing Bank 0 */
+#define B1_PEN_P 0x005 /* Enable 16-bit packing Bank 1 */
+#define B2_PEN_P 0x006 /* Enable 16-bit packing Bank 2 */
+#define B3_PEN_P 0x007 /* Enable 16-bit packing Bank 3 */
+
+/* AMBCTL0 Masks */
+#define B0RDYEN 0x00000001 /* Bank 0 RDY Enable, 0=disable, 1=enable */
+#define B0RDYPOL 0x00000002 /* Bank 0 RDY Active high, 0=active low, 1=active high */
+#define B0TT_1 0x00000004 /* Bank 0 Transition Time from Read to Write = 1 cycle */
+#define B0TT_2 0x00000008 /* Bank 0 Transition Time from Read to Write = 2 cycles */
+#define B0TT_3 0x0000000C /* Bank 0 Transition Time from Read to Write = 3 cycles */
+#define B0TT_4 0x00000000 /* Bank 0 Transition Time from Read to Write = 4 cycles */
+#define B0ST_1 0x00000010 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=1 cycle */
+#define B0ST_2 0x00000020 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=2 cycles */
+#define B0ST_3 0x00000030 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=3 cycles */
+#define B0ST_4 0x00000000 /* Bank 0 Setup Time from AOE asserted to Read/Write asserted=4 cycles */
+#define B0HT_1 0x00000040 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 1 cycle */
+#define B0HT_2 0x00000080 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 2 cycles */
+#define B0HT_3 0x000000C0 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 3 cycles */
+#define B0HT_0 0x00000000 /* Bank 0 Hold Time from Read/Write deasserted to AOE deasserted = 0 cycles */
+#define B0RAT_1 0x00000100 /* Bank 0 Read Access Time = 1 cycle */
+#define B0RAT_2 0x00000200 /* Bank 0 Read Access Time = 2 cycles */
+#define B0RAT_3 0x00000300 /* Bank 0 Read Access Time = 3 cycles */
+#define B0RAT_4 0x00000400 /* Bank 0 Read Access Time = 4 cycles */
+#define B0RAT_5 0x00000500 /* Bank 0 Read Access Time = 5 cycles */
+#define B0RAT_6 0x00000600 /* Bank 0 Read Access Time = 6 cycles */
+#define B0RAT_7 0x00000700 /* Bank 0 Read Access Time = 7 cycles */
+#define B0RAT_8 0x00000800 /* Bank 0 Read Access Time = 8 cycles */
+#define B0RAT_9 0x00000900 /* Bank 0 Read Access Time = 9 cycles */
+#define B0RAT_10 0x00000A00 /* Bank 0 Read Access Time = 10 cycles */
+#define B0RAT_11 0x00000B00 /* Bank 0 Read Access Time = 11 cycles */
+#define B0RAT_12 0x00000C00 /* Bank 0 Read Access Time = 12 cycles */
+#define B0RAT_13 0x00000D00 /* Bank 0 Read Access Time = 13 cycles */
+#define B0RAT_14 0x00000E00 /* Bank 0 Read Access Time = 14 cycles */
+#define B0RAT_15 0x00000F00 /* Bank 0 Read Access Time = 15 cycles */
+#define B0WAT_1 0x00001000 /* Bank 0 Write Access Time = 1 cycle */
+#define B0WAT_2 0x00002000 /* Bank 0 Write Access Time = 2 cycles */
+#define B0WAT_3 0x00003000 /* Bank 0 Write Access Time = 3 cycles */
+#define B0WAT_4 0x00004000 /* Bank 0 Write Access Time = 4 cycles */
+#define B0WAT_5 0x00005000 /* Bank 0 Write Access Time = 5 cycles */
+#define B0WAT_6 0x00006000 /* Bank 0 Write Access Time = 6 cycles */
+#define B0WAT_7 0x00007000 /* Bank 0 Write Access Time = 7 cycles */
+#define B0WAT_8 0x00008000 /* Bank 0 Write Access Time = 8 cycles */
+#define B0WAT_9 0x00009000 /* Bank 0 Write Access Time = 9 cycles */
+#define B0WAT_10 0x0000A000 /* Bank 0 Write Access Time = 10 cycles */
+#define B0WAT_11 0x0000B000 /* Bank 0 Write Access Time = 11 cycles */
+#define B0WAT_12 0x0000C000 /* Bank 0 Write Access Time = 12 cycles */
+#define B0WAT_13 0x0000D000 /* Bank 0 Write Access Time = 13 cycles */
+#define B0WAT_14 0x0000E000 /* Bank 0 Write Access Time = 14 cycles */
+#define B0WAT_15 0x0000F000 /* Bank 0 Write Access Time = 15 cycles */
+#define B1RDYEN 0x00010000 /* Bank 1 RDY enable, 0=disable, 1=enable */
+#define B1RDYPOL 0x00020000 /* Bank 1 RDY Active high, 0=active low, 1=active high */
+#define B1TT_1 0x00040000 /* Bank 1 Transition Time from Read to Write = 1 cycle */
+#define B1TT_2 0x00080000 /* Bank 1 Transition Time from Read to Write = 2 cycles */
+#define B1TT_3 0x000C0000 /* Bank 1 Transition Time from Read to Write = 3 cycles */
+#define B1TT_4 0x00000000 /* Bank 1 Transition Time from Read to Write = 4 cycles */
+#define B1ST_1 0x00100000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B1ST_2 0x00200000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B1ST_3 0x00300000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B1ST_4 0x00000000 /* Bank 1 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B1HT_1 0x00400000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B1HT_2 0x00800000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B1HT_3 0x00C00000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B1HT_0 0x00000000 /* Bank 1 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B1RAT_1 0x01000000 /* Bank 1 Read Access Time = 1 cycle */
+#define B1RAT_2 0x02000000 /* Bank 1 Read Access Time = 2 cycles */
+#define B1RAT_3 0x03000000 /* Bank 1 Read Access Time = 3 cycles */
+#define B1RAT_4 0x04000000 /* Bank 1 Read Access Time = 4 cycles */
+#define B1RAT_5 0x05000000 /* Bank 1 Read Access Time = 5 cycles */
+#define B1RAT_6 0x06000000 /* Bank 1 Read Access Time = 6 cycles */
+#define B1RAT_7 0x07000000 /* Bank 1 Read Access Time = 7 cycles */
+#define B1RAT_8 0x08000000 /* Bank 1 Read Access Time = 8 cycles */
+#define B1RAT_9 0x09000000 /* Bank 1 Read Access Time = 9 cycles */
+#define B1RAT_10 0x0A000000 /* Bank 1 Read Access Time = 10 cycles */
+#define B1RAT_11 0x0B000000 /* Bank 1 Read Access Time = 11 cycles */
+#define B1RAT_12 0x0C000000 /* Bank 1 Read Access Time = 12 cycles */
+#define B1RAT_13 0x0D000000 /* Bank 1 Read Access Time = 13 cycles */
+#define B1RAT_14 0x0E000000 /* Bank 1 Read Access Time = 14 cycles */
+#define B1RAT_15 0x0F000000 /* Bank 1 Read Access Time = 15 cycles */
+#define B1WAT_1 0x10000000 /* Bank 1 Write Access Time = 1 cycle */
+#define B1WAT_2 0x20000000 /* Bank 1 Write Access Time = 2 cycles */
+#define B1WAT_3 0x30000000 /* Bank 1 Write Access Time = 3 cycles */
+#define B1WAT_4 0x40000000 /* Bank 1 Write Access Time = 4 cycles */
+#define B1WAT_5 0x50000000 /* Bank 1 Write Access Time = 5 cycles */
+#define B1WAT_6 0x60000000 /* Bank 1 Write Access Time = 6 cycles */
+#define B1WAT_7 0x70000000 /* Bank 1 Write Access Time = 7 cycles */
+#define B1WAT_8 0x80000000 /* Bank 1 Write Access Time = 8 cycles */
+#define B1WAT_9 0x90000000 /* Bank 1 Write Access Time = 9 cycles */
+#define B1WAT_10 0xA0000000 /* Bank 1 Write Access Time = 10 cycles */
+#define B1WAT_11 0xB0000000 /* Bank 1 Write Access Time = 11 cycles */
+#define B1WAT_12 0xC0000000 /* Bank 1 Write Access Time = 12 cycles */
+#define B1WAT_13 0xD0000000 /* Bank 1 Write Access Time = 13 cycles */
+#define B1WAT_14 0xE0000000 /* Bank 1 Write Access Time = 14 cycles */
+#define B1WAT_15 0xF0000000 /* Bank 1 Write Access Time = 15 cycles */
+
+/* AMBCTL1 Masks */
+#define B2RDYEN 0x00000001 /* Bank 2 RDY Enable, 0=disable, 1=enable */
+#define B2RDYPOL 0x00000002 /* Bank 2 RDY Active high, 0=active low, 1=active high */
+#define B2TT_1 0x00000004 /* Bank 2 Transition Time from Read to Write = 1 cycle */
+#define B2TT_2 0x00000008 /* Bank 2 Transition Time from Read to Write = 2 cycles */
+#define B2TT_3 0x0000000C /* Bank 2 Transition Time from Read to Write = 3 cycles */
+#define B2TT_4 0x00000000 /* Bank 2 Transition Time from Read to Write = 4 cycles */
+#define B2ST_1 0x00000010 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B2ST_2 0x00000020 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B2ST_3 0x00000030 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B2ST_4 0x00000000 /* Bank 2 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B2HT_1 0x00000040 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B2HT_2 0x00000080 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B2HT_3 0x000000C0 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B2HT_0 0x00000000 /* Bank 2 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B2RAT_1 0x00000100 /* Bank 2 Read Access Time = 1 cycle */
+#define B2RAT_2 0x00000200 /* Bank 2 Read Access Time = 2 cycles */
+#define B2RAT_3 0x00000300 /* Bank 2 Read Access Time = 3 cycles */
+#define B2RAT_4 0x00000400 /* Bank 2 Read Access Time = 4 cycles */
+#define B2RAT_5 0x00000500 /* Bank 2 Read Access Time = 5 cycles */
+#define B2RAT_6 0x00000600 /* Bank 2 Read Access Time = 6 cycles */
+#define B2RAT_7 0x00000700 /* Bank 2 Read Access Time = 7 cycles */
+#define B2RAT_8 0x00000800 /* Bank 2 Read Access Time = 8 cycles */
+#define B2RAT_9 0x00000900 /* Bank 2 Read Access Time = 9 cycles */
+#define B2RAT_10 0x00000A00 /* Bank 2 Read Access Time = 10 cycles */
+#define B2RAT_11 0x00000B00 /* Bank 2 Read Access Time = 11 cycles */
+#define B2RAT_12 0x00000C00 /* Bank 2 Read Access Time = 12 cycles */
+#define B2RAT_13 0x00000D00 /* Bank 2 Read Access Time = 13 cycles */
+#define B2RAT_14 0x00000E00 /* Bank 2 Read Access Time = 14 cycles */
+#define B2RAT_15 0x00000F00 /* Bank 2 Read Access Time = 15 cycles */
+#define B2WAT_1 0x00001000 /* Bank 2 Write Access Time = 1 cycle */
+#define B2WAT_2 0x00002000 /* Bank 2 Write Access Time = 2 cycles */
+#define B2WAT_3 0x00003000 /* Bank 2 Write Access Time = 3 cycles */
+#define B2WAT_4 0x00004000 /* Bank 2 Write Access Time = 4 cycles */
+#define B2WAT_5 0x00005000 /* Bank 2 Write Access Time = 5 cycles */
+#define B2WAT_6 0x00006000 /* Bank 2 Write Access Time = 6 cycles */
+#define B2WAT_7 0x00007000 /* Bank 2 Write Access Time = 7 cycles */
+#define B2WAT_8 0x00008000 /* Bank 2 Write Access Time = 8 cycles */
+#define B2WAT_9 0x00009000 /* Bank 2 Write Access Time = 9 cycles */
+#define B2WAT_10 0x0000A000 /* Bank 2 Write Access Time = 10 cycles */
+#define B2WAT_11 0x0000B000 /* Bank 2 Write Access Time = 11 cycles */
+#define B2WAT_12 0x0000C000 /* Bank 2 Write Access Time = 12 cycles */
+#define B2WAT_13 0x0000D000 /* Bank 2 Write Access Time = 13 cycles */
+#define B2WAT_14 0x0000E000 /* Bank 2 Write Access Time = 14 cycles */
+#define B2WAT_15 0x0000F000 /* Bank 2 Write Access Time = 15 cycles */
+#define B3RDYEN 0x00010000 /* Bank 3 RDY enable, 0=disable, 1=enable */
+#define B3RDYPOL 0x00020000 /* Bank 3 RDY Active high, 0=active low, 1=active high */
+#define B3TT_1 0x00040000 /* Bank 3 Transition Time from Read to Write = 1 cycle */
+#define B3TT_2 0x00080000 /* Bank 3 Transition Time from Read to Write = 2 cycles */
+#define B3TT_3 0x000C0000 /* Bank 3 Transition Time from Read to Write = 3 cycles */
+#define B3TT_4 0x00000000 /* Bank 3 Transition Time from Read to Write = 4 cycles */
+#define B3ST_1 0x00100000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 1 cycle */
+#define B3ST_2 0x00200000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 2 cycles */
+#define B3ST_3 0x00300000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 3 cycles */
+#define B3ST_4 0x00000000 /* Bank 3 Setup Time from AOE asserted to Read or Write asserted = 4 cycles */
+#define B3HT_1 0x00400000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 1 cycle */
+#define B3HT_2 0x00800000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 2 cycles */
+#define B3HT_3 0x00C00000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 3 cycles */
+#define B3HT_0 0x00000000 /* Bank 3 Hold Time from Read or Write deasserted to AOE deasserted = 0 cycles */
+#define B3RAT_1 0x01000000 /* Bank 3 Read Access Time = 1 cycle */
+#define B3RAT_2 0x02000000 /* Bank 3 Read Access Time = 2 cycles */
+#define B3RAT_3 0x03000000 /* Bank 3 Read Access Time = 3 cycles */
+#define B3RAT_4 0x04000000 /* Bank 3 Read Access Time = 4 cycles */
+#define B3RAT_5 0x05000000 /* Bank 3 Read Access Time = 5 cycles */
+#define B3RAT_6 0x06000000 /* Bank 3 Read Access Time = 6 cycles */
+#define B3RAT_7 0x07000000 /* Bank 3 Read Access Time = 7 cycles */
+#define B3RAT_8 0x08000000 /* Bank 3 Read Access Time = 8 cycles */
+#define B3RAT_9 0x09000000 /* Bank 3 Read Access Time = 9 cycles */
+#define B3RAT_10 0x0A000000 /* Bank 3 Read Access Time = 10 cycles */
+#define B3RAT_11 0x0B000000 /* Bank 3 Read Access Time = 11 cycles */
+#define B3RAT_12 0x0C000000 /* Bank 3 Read Access Time = 12 cycles */
+#define B3RAT_13 0x0D000000 /* Bank 3 Read Access Time = 13 cycles */
+#define B3RAT_14 0x0E000000 /* Bank 3 Read Access Time = 14 cycles */
+#define B3RAT_15 0x0F000000 /* Bank 3 Read Access Time = 15 cycles */
+#define B3WAT_1 0x10000000 /* Bank 3 Write Access Time = 1 cycle */
+#define B3WAT_2 0x20000000 /* Bank 3 Write Access Time = 2 cycles */
+#define B3WAT_3 0x30000000 /* Bank 3 Write Access Time = 3 cycles */
+#define B3WAT_4 0x40000000 /* Bank 3 Write Access Time = 4 cycles */
+#define B3WAT_5 0x50000000 /* Bank 3 Write Access Time = 5 cycles */
+#define B3WAT_6 0x60000000 /* Bank 3 Write Access Time = 6 cycles */
+#define B3WAT_7 0x70000000 /* Bank 3 Write Access Time = 7 cycles */
+#define B3WAT_8 0x80000000 /* Bank 3 Write Access Time = 8 cycles */
+#define B3WAT_9 0x90000000 /* Bank 3 Write Access Time = 9 cycles */
+#define B3WAT_10 0xA0000000 /* Bank 3 Write Access Time = 10 cycles */
+#define B3WAT_11 0xB0000000 /* Bank 3 Write Access Time = 11 cycles */
+#define B3WAT_12 0xC0000000 /* Bank 3 Write Access Time = 12 cycles */
+#define B3WAT_13 0xD0000000 /* Bank 3 Write Access Time = 13 cycles */
+#define B3WAT_14 0xE0000000 /* Bank 3 Write Access Time = 14 cycles */
+#define B3WAT_15 0xF0000000 /* Bank 3 Write Access Time = 15 cycles */
+
+/* ********************** SDRAM CONTROLLER MASKS *************************** */
+
+/* EBIU_SDGCTL Masks */
+#define SCTLE 0x00000001 /* Enable SCLK[0], /SRAS, /SCAS, /SWE, SDQM[3:0] */
+#define CL_2 0x00000008 /* SDRAM CAS latency = 2 cycles */
+#define CL_3 0x0000000C /* SDRAM CAS latency = 3 cycles */
+#define PFE 0x00000010 /* Enable SDRAM prefetch */
+#define PFP 0x00000020 /* Prefetch has priority over AMC requests */
+#define TRAS_1 0x00000040 /* SDRAM tRAS = 1 cycle */
+#define TRAS_2 0x00000080 /* SDRAM tRAS = 2 cycles */
+#define TRAS_3 0x000000C0 /* SDRAM tRAS = 3 cycles */
+#define TRAS_4 0x00000100 /* SDRAM tRAS = 4 cycles */
+#define TRAS_5 0x00000140 /* SDRAM tRAS = 5 cycles */
+#define TRAS_6 0x00000180 /* SDRAM tRAS = 6 cycles */
+#define TRAS_7 0x000001C0 /* SDRAM tRAS = 7 cycles */
+#define TRAS_8 0x00000200 /* SDRAM tRAS = 8 cycles */
+#define TRAS_9 0x00000240 /* SDRAM tRAS = 9 cycles */
+#define TRAS_10 0x00000280 /* SDRAM tRAS = 10 cycles */
+#define TRAS_11 0x000002C0 /* SDRAM tRAS = 11 cycles */
+#define TRAS_12 0x00000300 /* SDRAM tRAS = 12 cycles */
+#define TRAS_13 0x00000340 /* SDRAM tRAS = 13 cycles */
+#define TRAS_14 0x00000380 /* SDRAM tRAS = 14 cycles */
+#define TRAS_15 0x000003C0 /* SDRAM tRAS = 15 cycles */
+#define TRP_1 0x00000800 /* SDRAM tRP = 1 cycle */
+#define TRP_2 0x00001000 /* SDRAM tRP = 2 cycles */
+#define TRP_3 0x00001800 /* SDRAM tRP = 3 cycles */
+#define TRP_4 0x00002000 /* SDRAM tRP = 4 cycles */
+#define TRP_5 0x00002800 /* SDRAM tRP = 5 cycles */
+#define TRP_6 0x00003000 /* SDRAM tRP = 6 cycles */
+#define TRP_7 0x00003800 /* SDRAM tRP = 7 cycles */
+#define TRCD_1 0x00008000 /* SDRAM tRCD = 1 cycle */
+#define TRCD_2 0x00010000 /* SDRAM tRCD = 2 cycles */
+#define TRCD_3 0x00018000 /* SDRAM tRCD = 3 cycles */
+#define TRCD_4 0x00020000 /* SDRAM tRCD = 4 cycles */
+#define TRCD_5 0x00028000 /* SDRAM tRCD = 5 cycles */
+#define TRCD_6 0x00030000 /* SDRAM tRCD = 6 cycles */
+#define TRCD_7 0x00038000 /* SDRAM tRCD = 7 cycles */
+#define TWR_1 0x00080000 /* SDRAM tWR = 1 cycle */
+#define TWR_2 0x00100000 /* SDRAM tWR = 2 cycles */
+#define TWR_3 0x00180000 /* SDRAM tWR = 3 cycles */
+#define PUPSD 0x00200000 /*Power-up start delay */
+#define PSM 0x00400000 /* SDRAM power-up sequence = Precharge, mode register set, 8 CBR refresh cycles */
+#define PSS 0x00800000 /* enable SDRAM power-up sequence on next SDRAM access */
+#define SRFS 0x01000000 /* Start SDRAM self-refresh mode */
+#define EBUFE 0x02000000 /* Enable external buffering timing */
+#define FBBRW 0x04000000 /* Fast back-to-back read write enable */
+#define EMREN 0x10000000 /* Extended mode register enable */
+#define TCSR 0x20000000 /* Temp compensated self refresh value 85 deg C */
+#define CDDBG 0x40000000 /* Tristate SDRAM controls during bus grant */
+
+/* EBIU_SDBCTL Masks */
+#define EB0_E 0x00000001 /* Enable SDRAM external bank 0 */
+#define EB0_SZ_16 0x00000000 /* SDRAM external bank size = 16MB */
+#define EB0_SZ_32 0x00000002 /* SDRAM external bank size = 32MB */
+#define EB0_SZ_64 0x00000004 /* SDRAM external bank size = 64MB */
+#define EB0_SZ_128 0x00000006 /* SDRAM external bank size = 128MB */
+#define EB0_CAW_8 0x00000000 /* SDRAM external bank column address width = 8 bits */
+#define EB0_CAW_9 0x00000010 /* SDRAM external bank column address width = 9 bits */
+#define EB0_CAW_10 0x00000020 /* SDRAM external bank column address width = 9 bits */
+#define EB0_CAW_11 0x00000030 /* SDRAM external bank column address width = 9 bits */
+
+#define EB1_E 0x00000100 /* Enable SDRAM external bank 1 */
+#define EB1__SZ_16 0x00000000 /* SDRAM external bank size = 16MB */
+#define EB1__SZ_32 0x00000200 /* SDRAM external bank size = 32MB */
+#define EB1__SZ_64 0x00000400 /* SDRAM external bank size = 64MB */
+#define EB1__SZ_128 0x00000600 /* SDRAM external bank size = 128MB */
+#define EB1__CAW_8 0x00000000 /* SDRAM external bank column address width = 8 bits */
+#define EB1__CAW_9 0x00001000 /* SDRAM external bank column address width = 9 bits */
+#define EB1__CAW_10 0x00002000 /* SDRAM external bank column address width = 9 bits */
+#define EB1__CAW_11 0x00003000 /* SDRAM external bank column address width = 9 bits */
+
+#define EB2__E 0x00010000 /* Enable SDRAM external bank 2 */
+#define EB2__SZ_16 0x00000000 /* SDRAM external bank size = 16MB */
+#define EB2__SZ_32 0x00020000 /* SDRAM external bank size = 32MB */
+#define EB2__SZ_64 0x00040000 /* SDRAM external bank size = 64MB */
+#define EB2__SZ_128 0x00060000 /* SDRAM external bank size = 128MB */
+#define EB2__CAW_8 0x00000000 /* SDRAM external bank column address width = 8 bits */
+#define EB2__CAW_9 0x00100000 /* SDRAM external bank column address width = 9 bits */
+#define EB2__CAW_10 0x00200000 /* SDRAM external bank column address width = 9 bits */
+#define EB2__CAW_11 0x00300000 /* SDRAM external bank column address width = 9 bits */
+
+#define EB3__E 0x01000000 /* Enable SDRAM external bank 3 */
+#define EB3__SZ_16 0x00000000 /* SDRAM external bank size = 16MB */
+#define EB3__SZ_32 0x02000000 /* SDRAM external bank size = 32MB */
+#define EB3__SZ_64 0x04000000 /* SDRAM external bank size = 64MB */
+#define EB3__SZ_128 0x06000000 /* SDRAM external bank size = 128MB */
+#define EB3__CAW_8 0x00000000 /* SDRAM external bank column address width = 8 bits */
+#define EB3__CAW_9 0x10000000 /* SDRAM external bank column address width = 9 bits */
+#define EB3__CAW_10 0x20000000 /* SDRAM external bank column address width = 9 bits */
+#define EB3__CAW_11 0x30000000 /* SDRAM external bank column address width = 9 bits */
+
+/* EBIU_SDSTAT Masks */
+#define SDCI 0x00000001 /* SDRAM controller is idle */
+#define SDSRA 0x00000002 /* SDRAM SDRAM self refresh is active */
+#define SDPUA 0x00000004 /* SDRAM power up active */
+#define SDRS 0x00000008 /* SDRAM is in reset state */
+#define SDEASE 0x00000010 /* SDRAM EAB sticky error status - W1C */
+#define BGSTAT 0x00000020 /* Bus granted */
+
+/*VR_CTL Masks*/
+#define WAKE 0x100
+#define VLEV_6 0x60
+#define VLEV_7 0x70
+#define VLEV_8 0x80
+#define VLEV_9 0x90
+#define VLEV_10 0xA0
+#define VLEV_11 0xB0
+#define VLEV_12 0xC0
+#define VLEV_13 0xD0
+#define VLEV_14 0xE0
+#define VLEV_15 0xF0
+#define FREQ_3 0x03
+
+#endif /* _DEF_BF561_H */
diff --git a/include/asm-blackfin/mach-bf561/dma.h b/include/asm-blackfin/mach-bf561/dma.h
new file mode 100644
index 00000000000..21d982003e7
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/dma.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+*
+* BF-533/2/1 Specific Declarations
+*
+****************************************************************************/
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define MAX_BLACKFIN_DMA_CHANNEL 36
+
+#define CH_PPI0 0
+#define CH_PPI (CH_PPI0)
+#define CH_PPI1 1
+#define CH_SPORT0_RX 12
+#define CH_SPORT0_TX 13
+#define CH_SPORT1_RX 14
+#define CH_SPORT1_TX 15
+#define CH_SPI 16
+#define CH_UART_RX 17
+#define CH_UART_TX 18
+#define CH_MEM_STREAM0_DEST 24 /* TX */
+#define CH_MEM_STREAM0_SRC 25 /* RX */
+#define CH_MEM_STREAM1_DEST 26 /* TX */
+#define CH_MEM_STREAM1_SRC 27 /* RX */
+#define CH_MEM_STREAM2_DEST 28
+#define CH_MEM_STREAM2_SRC 29
+#define CH_MEM_STREAM3_SRC 30
+#define CH_MEM_STREAM3_DEST 31
+#define CH_IMEM_STREAM0_DEST 32
+#define CH_IMEM_STREAM0_SRC 33
+#define CH_IMEM_STREAM1_SRC 34
+#define CH_IMEM_STREAM1_DEST 35
+
+#endif
diff --git a/include/asm-blackfin/mach-bf561/irq.h b/include/asm-blackfin/mach-bf561/irq.h
new file mode 100644
index 00000000000..a753ce720d7
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/irq.h
@@ -0,0 +1,450 @@
+
+/*
+ * File: include/asm-blackfin/mach-bf561/irq.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BF561_IRQ_H_
+#define _BF561_IRQ_H_
+
+/***********************************************************************
+ * Interrupt source definitions:
+ Event Source Core Event Name IRQ No
+ (highest priority)
+ Emulation Events EMU 0
+ Reset RST 1
+ NMI NMI 2
+ Exception EVX 3
+ Reserved -- 4
+ Hardware Error IVHW 5
+ Core Timer IVTMR 6 *
+
+ PLL Wakeup Interrupt IVG7 7
+ DMA1 Error (generic) IVG7 8
+ DMA2 Error (generic) IVG7 9
+ IMDMA Error (generic) IVG7 10
+ PPI1 Error Interrupt IVG7 11
+ PPI2 Error Interrupt IVG7 12
+ SPORT0 Error Interrupt IVG7 13
+ SPORT1 Error Interrupt IVG7 14
+ SPI Error Interrupt IVG7 15
+ UART Error Interrupt IVG7 16
+ Reserved Interrupt IVG7 17
+
+ DMA1 0 Interrupt(PPI1) IVG8 18
+ DMA1 1 Interrupt(PPI2) IVG8 19
+ DMA1 2 Interrupt IVG8 20
+ DMA1 3 Interrupt IVG8 21
+ DMA1 4 Interrupt IVG8 22
+ DMA1 5 Interrupt IVG8 23
+ DMA1 6 Interrupt IVG8 24
+ DMA1 7 Interrupt IVG8 25
+ DMA1 8 Interrupt IVG8 26
+ DMA1 9 Interrupt IVG8 27
+ DMA1 10 Interrupt IVG8 28
+ DMA1 11 Interrupt IVG8 29
+
+ DMA2 0 (SPORT0 RX) IVG9 30
+ DMA2 1 (SPORT0 TX) IVG9 31
+ DMA2 2 (SPORT1 RX) IVG9 32
+ DMA2 3 (SPORT2 TX) IVG9 33
+ DMA2 4 (SPI) IVG9 34
+ DMA2 5 (UART RX) IVG9 35
+ DMA2 6 (UART TX) IVG9 36
+ DMA2 7 Interrupt IVG9 37
+ DMA2 8 Interrupt IVG9 38
+ DMA2 9 Interrupt IVG9 39
+ DMA2 10 Interrupt IVG9 40
+ DMA2 11 Interrupt IVG9 41
+
+ TIMER 0 Interrupt IVG10 42
+ TIMER 1 Interrupt IVG10 43
+ TIMER 2 Interrupt IVG10 44
+ TIMER 3 Interrupt IVG10 45
+ TIMER 4 Interrupt IVG10 46
+ TIMER 5 Interrupt IVG10 47
+ TIMER 6 Interrupt IVG10 48
+ TIMER 7 Interrupt IVG10 49
+ TIMER 8 Interrupt IVG10 50
+ TIMER 9 Interrupt IVG10 51
+ TIMER 10 Interrupt IVG10 52
+ TIMER 11 Interrupt IVG10 53
+
+ Programmable Flags0 A (8) IVG11 54
+ Programmable Flags0 B (8) IVG11 55
+ Programmable Flags1 A (8) IVG11 56
+ Programmable Flags1 B (8) IVG11 57
+ Programmable Flags2 A (8) IVG11 58
+ Programmable Flags2 B (8) IVG11 59
+
+ MDMA1 0 write/read INT IVG8 60
+ MDMA1 1 write/read INT IVG8 61
+
+ MDMA2 0 write/read INT IVG9 62
+ MDMA2 1 write/read INT IVG9 63
+
+ IMDMA 0 write/read INT IVG12 64
+ IMDMA 1 write/read INT IVG12 65
+
+ Watch Dog Timer IVG13 66
+
+ Reserved interrupt IVG7 67
+ Reserved interrupt IVG7 68
+ Supplemental interrupt 0 IVG7 69
+ supplemental interrupt 1 IVG7 70
+
+ Software Interrupt 1 IVG14 71
+ Software Interrupt 2 IVG15 72 *
+ (lowest priority)
+ **********************************************************************/
+
+#define SYS_IRQS 72
+#define NR_PERI_INTS 64
+
+/*
+ * The ABSTRACT IRQ definitions
+ * the first seven of the following are fixed,
+ * the rest you change if you need to.
+ */
+/* IVG 0-6*/
+#define IRQ_EMU 0 /* Emulation */
+#define IRQ_RST 1 /* Reset */
+#define IRQ_NMI 2 /* Non Maskable Interrupt */
+#define IRQ_EVX 3 /* Exception */
+#define IRQ_UNUSED 4 /* Reserved interrupt */
+#define IRQ_HWERR 5 /* Hardware Error */
+#define IRQ_CORETMR 6 /* Core timer */
+
+#define IVG_BASE 7
+/* IVG 7 */
+#define IRQ_PLL_WAKEUP (IVG_BASE + 0) /* PLL Wakeup Interrupt */
+#define IRQ_DMA1_ERROR (IVG_BASE + 1) /* DMA1 Error (general) */
+#define IRQ_DMA_ERROR IRQ_DMA1_ERROR /* DMA1 Error (general) */
+#define IRQ_DMA2_ERROR (IVG_BASE + 2) /* DMA2 Error (general) */
+#define IRQ_IMDMA_ERROR (IVG_BASE + 3) /* IMDMA Error Interrupt */
+#define IRQ_PPI1_ERROR (IVG_BASE + 4) /* PPI1 Error Interrupt */
+#define IRQ_PPI_ERROR IRQ_PPI1_ERROR /* PPI1 Error Interrupt */
+#define IRQ_PPI2_ERROR (IVG_BASE + 5) /* PPI2 Error Interrupt */
+#define IRQ_SPORT0_ERROR (IVG_BASE + 6) /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR (IVG_BASE + 7) /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR (IVG_BASE + 8) /* SPI Error Interrupt */
+#define IRQ_UART_ERROR (IVG_BASE + 9) /* UART Error Interrupt */
+#define IRQ_RESERVED_ERROR (IVG_BASE + 10) /* Reversed Interrupt */
+/* IVG 8 */
+#define IRQ_DMA1_0 (IVG_BASE + 11) /* DMA1 0 Interrupt(PPI1) */
+#define IRQ_PPI IRQ_DMA1_0 /* DMA1 0 Interrupt(PPI1) */
+#define IRQ_PPI0 IRQ_DMA1_0 /* DMA1 0 Interrupt(PPI1) */
+#define IRQ_DMA1_1 (IVG_BASE + 12) /* DMA1 1 Interrupt(PPI2) */
+#define IRQ_PPI1 IRQ_DMA1_1 /* DMA1 1 Interrupt(PPI2) */
+#define IRQ_DMA1_2 (IVG_BASE + 13) /* DMA1 2 Interrupt */
+#define IRQ_DMA1_3 (IVG_BASE + 14) /* DMA1 3 Interrupt */
+#define IRQ_DMA1_4 (IVG_BASE + 15) /* DMA1 4 Interrupt */
+#define IRQ_DMA1_5 (IVG_BASE + 16) /* DMA1 5 Interrupt */
+#define IRQ_DMA1_6 (IVG_BASE + 17) /* DMA1 6 Interrupt */
+#define IRQ_DMA1_7 (IVG_BASE + 18) /* DMA1 7 Interrupt */
+#define IRQ_DMA1_8 (IVG_BASE + 19) /* DMA1 8 Interrupt */
+#define IRQ_DMA1_9 (IVG_BASE + 20) /* DMA1 9 Interrupt */
+#define IRQ_DMA1_10 (IVG_BASE + 21) /* DMA1 10 Interrupt */
+#define IRQ_DMA1_11 (IVG_BASE + 22) /* DMA1 11 Interrupt */
+/* IVG 9 */
+#define IRQ_DMA2_0 (IVG_BASE + 23) /* DMA2 0 (SPORT0 RX) */
+#define IRQ_SPORT0_RX IRQ_DMA2_0 /* DMA2 0 (SPORT0 RX) */
+#define IRQ_DMA2_1 (IVG_BASE + 24) /* DMA2 1 (SPORT0 TX) */
+#define IRQ_SPORT0_TX IRQ_DMA2_1 /* DMA2 1 (SPORT0 TX) */
+#define IRQ_DMA2_2 (IVG_BASE + 25) /* DMA2 2 (SPORT1 RX) */
+#define IRQ_SPORT1_RX IRQ_DMA2_2 /* DMA2 2 (SPORT1 RX) */
+#define IRQ_DMA2_3 (IVG_BASE + 26) /* DMA2 3 (SPORT2 TX) */
+#define IRQ_SPORT1_TX IRQ_DMA2_3 /* DMA2 3 (SPORT2 TX) */
+#define IRQ_DMA2_4 (IVG_BASE + 27) /* DMA2 4 (SPI) */
+#define IRQ_SPI IRQ_DMA2_4 /* DMA2 4 (SPI) */
+#define IRQ_DMA2_5 (IVG_BASE + 28) /* DMA2 5 (UART RX) */
+#define IRQ_UART_RX IRQ_DMA2_5 /* DMA2 5 (UART RX) */
+#define IRQ_DMA2_6 (IVG_BASE + 29) /* DMA2 6 (UART TX) */
+#define IRQ_UART_TX IRQ_DMA2_6 /* DMA2 6 (UART TX) */
+#define IRQ_DMA2_7 (IVG_BASE + 30) /* DMA2 7 Interrupt */
+#define IRQ_DMA2_8 (IVG_BASE + 31) /* DMA2 8 Interrupt */
+#define IRQ_DMA2_9 (IVG_BASE + 32) /* DMA2 9 Interrupt */
+#define IRQ_DMA2_10 (IVG_BASE + 33) /* DMA2 10 Interrupt */
+#define IRQ_DMA2_11 (IVG_BASE + 34) /* DMA2 11 Interrupt */
+/* IVG 10 */
+#define IRQ_TIMER0 (IVG_BASE + 35) /* TIMER 0 Interrupt */
+#define IRQ_TIMER1 (IVG_BASE + 36) /* TIMER 1 Interrupt */
+#define IRQ_TIMER2 (IVG_BASE + 37) /* TIMER 2 Interrupt */
+#define IRQ_TIMER3 (IVG_BASE + 38) /* TIMER 3 Interrupt */
+#define IRQ_TIMER4 (IVG_BASE + 39) /* TIMER 4 Interrupt */
+#define IRQ_TIMER5 (IVG_BASE + 40) /* TIMER 5 Interrupt */
+#define IRQ_TIMER6 (IVG_BASE + 41) /* TIMER 6 Interrupt */
+#define IRQ_TIMER7 (IVG_BASE + 42) /* TIMER 7 Interrupt */
+#define IRQ_TIMER8 (IVG_BASE + 43) /* TIMER 8 Interrupt */
+#define IRQ_TIMER9 (IVG_BASE + 44) /* TIMER 9 Interrupt */
+#define IRQ_TIMER10 (IVG_BASE + 45) /* TIMER 10 Interrupt */
+#define IRQ_TIMER11 (IVG_BASE + 46) /* TIMER 11 Interrupt */
+/* IVG 11 */
+#define IRQ_PROG0_INTA (IVG_BASE + 47) /* Programmable Flags0 A (8) */
+#define IRQ_PROG_INTA IRQ_PROG0_INTA /* Programmable Flags0 A (8) */
+#define IRQ_PROG0_INTB (IVG_BASE + 48) /* Programmable Flags0 B (8) */
+#define IRQ_PROG_INTB IRQ_PROG0_INTB /* Programmable Flags0 B (8) */
+#define IRQ_PROG1_INTA (IVG_BASE + 49) /* Programmable Flags1 A (8) */
+#define IRQ_PROG1_INTB (IVG_BASE + 50) /* Programmable Flags1 B (8) */
+#define IRQ_PROG2_INTA (IVG_BASE + 51) /* Programmable Flags2 A (8) */
+#define IRQ_PROG2_INTB (IVG_BASE + 52) /* Programmable Flags2 B (8) */
+/* IVG 8 */
+#define IRQ_DMA1_WRRD0 (IVG_BASE + 53) /* MDMA1 0 write/read INT */
+#define IRQ_DMA_WRRD0 IRQ_DMA1_WRRD0 /* MDMA1 0 write/read INT */
+#define IRQ_MEM_DMA0 IRQ_DMA1_WRRD0
+#define IRQ_DMA1_WRRD1 (IVG_BASE + 54) /* MDMA1 1 write/read INT */
+#define IRQ_DMA_WRRD1 IRQ_DMA1_WRRD1 /* MDMA1 1 write/read INT */
+#define IRQ_MEM_DMA1 IRQ_DMA1_WRRD1
+/* IVG 9 */
+#define IRQ_DMA2_WRRD0 (IVG_BASE + 55) /* MDMA2 0 write/read INT */
+#define IRQ_MEM_DMA2 IRQ_DMA2_WRRD0
+#define IRQ_DMA2_WRRD1 (IVG_BASE + 56) /* MDMA2 1 write/read INT */
+#define IRQ_MEM_DMA3 IRQ_DMA2_WRRD1
+/* IVG 12 */
+#define IRQ_IMDMA_WRRD0 (IVG_BASE + 57) /* IMDMA 0 write/read INT */
+#define IRQ_IMEM_DMA0 IRQ_IMDMA_WRRD0
+#define IRQ_IMDMA_WRRD1 (IVG_BASE + 58) /* IMDMA 1 write/read INT */
+#define IRQ_IMEM_DMA1 IRQ_IMDMA_WRRD1
+/* IVG 13 */
+#define IRQ_WATCH (IVG_BASE + 59) /* Watch Dog Timer */
+/* IVG 7 */
+#define IRQ_RESERVED_1 (IVG_BASE + 60) /* Reserved interrupt */
+#define IRQ_RESERVED_2 (IVG_BASE + 61) /* Reserved interrupt */
+#define IRQ_SUPPLE_0 (IVG_BASE + 62) /* Supplemental interrupt 0 */
+#define IRQ_SUPPLE_1 (IVG_BASE + 63) /* supplemental interrupt 1 */
+#define IRQ_SW_INT1 71 /* Software Interrupt 1 */
+#define IRQ_SW_INT2 72 /* Software Interrupt 2 */
+ /* reserved for SYSCALL */
+#define IRQ_PF0 73
+#define IRQ_PF1 74
+#define IRQ_PF2 75
+#define IRQ_PF3 76
+#define IRQ_PF4 77
+#define IRQ_PF5 78
+#define IRQ_PF6 79
+#define IRQ_PF7 80
+#define IRQ_PF8 81
+#define IRQ_PF9 82
+#define IRQ_PF10 83
+#define IRQ_PF11 84
+#define IRQ_PF12 85
+#define IRQ_PF13 86
+#define IRQ_PF14 87
+#define IRQ_PF15 88
+#define IRQ_PF16 89
+#define IRQ_PF17 90
+#define IRQ_PF18 91
+#define IRQ_PF19 92
+#define IRQ_PF20 93
+#define IRQ_PF21 94
+#define IRQ_PF22 95
+#define IRQ_PF23 96
+#define IRQ_PF24 97
+#define IRQ_PF25 98
+#define IRQ_PF26 99
+#define IRQ_PF27 100
+#define IRQ_PF28 101
+#define IRQ_PF29 102
+#define IRQ_PF30 103
+#define IRQ_PF31 104
+#define IRQ_PF32 105
+#define IRQ_PF33 106
+#define IRQ_PF34 107
+#define IRQ_PF35 108
+#define IRQ_PF36 109
+#define IRQ_PF37 110
+#define IRQ_PF38 111
+#define IRQ_PF39 112
+#define IRQ_PF40 113
+#define IRQ_PF41 114
+#define IRQ_PF42 115
+#define IRQ_PF43 116
+#define IRQ_PF44 117
+#define IRQ_PF45 118
+#define IRQ_PF46 119
+#define IRQ_PF47 120
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS (IRQ_PF47 + 1)
+#else
+#define NR_IRQS SYS_IRQS
+#endif
+
+#define IVG7 7
+#define IVG8 8
+#define IVG9 9
+#define IVG10 10
+#define IVG11 11
+#define IVG12 12
+#define IVG13 13
+#define IVG14 14
+#define IVG15 15
+
+/*
+ * DEFAULT PRIORITIES:
+ */
+
+#define CONFIG_DEF_PLL_WAKEUP 7
+#define CONFIG_DEF_DMA1_ERROR 7
+#define CONFIG_DEF_DMA2_ERROR 7
+#define CONFIG_DEF_IMDMA_ERROR 7
+#define CONFIG_DEF_PPI1_ERROR 7
+#define CONFIG_DEF_PPI2_ERROR 7
+#define CONFIG_DEF_SPORT0_ERROR 7
+#define CONFIG_DEF_SPORT1_ERROR 7
+#define CONFIG_DEF_SPI_ERROR 7
+#define CONFIG_DEF_UART_ERROR 7
+#define CONFIG_DEF_RESERVED_ERROR 7
+#define CONFIG_DEF_DMA1_0 8
+#define CONFIG_DEF_DMA1_1 8
+#define CONFIG_DEF_DMA1_2 8
+#define CONFIG_DEF_DMA1_3 8
+#define CONFIG_DEF_DMA1_4 8
+#define CONFIG_DEF_DMA1_5 8
+#define CONFIG_DEF_DMA1_6 8
+#define CONFIG_DEF_DMA1_7 8
+#define CONFIG_DEF_DMA1_8 8
+#define CONFIG_DEF_DMA1_9 8
+#define CONFIG_DEF_DMA1_10 8
+#define CONFIG_DEF_DMA1_11 8
+#define CONFIG_DEF_DMA2_0 9
+#define CONFIG_DEF_DMA2_1 9
+#define CONFIG_DEF_DMA2_2 9
+#define CONFIG_DEF_DMA2_3 9
+#define CONFIG_DEF_DMA2_4 9
+#define CONFIG_DEF_DMA2_5 9
+#define CONFIG_DEF_DMA2_6 9
+#define CONFIG_DEF_DMA2_7 9
+#define CONFIG_DEF_DMA2_8 9
+#define CONFIG_DEF_DMA2_9 9
+#define CONFIG_DEF_DMA2_10 9
+#define CONFIG_DEF_DMA2_11 9
+#define CONFIG_DEF_TIMER0 10
+#define CONFIG_DEF_TIMER1 10
+#define CONFIG_DEF_TIMER2 10
+#define CONFIG_DEF_TIMER3 10
+#define CONFIG_DEF_TIMER4 10
+#define CONFIG_DEF_TIMER5 10
+#define CONFIG_DEF_TIMER6 10
+#define CONFIG_DEF_TIMER7 10
+#define CONFIG_DEF_TIMER8 10
+#define CONFIG_DEF_TIMER9 10
+#define CONFIG_DEF_TIMER10 10
+#define CONFIG_DEF_TIMER11 10
+#define CONFIG_DEF_PROG0_INTA 11
+#define CONFIG_DEF_PROG0_INTB 11
+#define CONFIG_DEF_PROG1_INTA 11
+#define CONFIG_DEF_PROG1_INTB 11
+#define CONFIG_DEF_PROG2_INTA 11
+#define CONFIG_DEF_PROG2_INTB 11
+#define CONFIG_DEF_DMA1_WRRD0 8
+#define CONFIG_DEF_DMA1_WRRD1 8
+#define CONFIG_DEF_DMA2_WRRD0 9
+#define CONFIG_DEF_DMA2_WRRD1 9
+#define CONFIG_DEF_IMDMA_WRRD0 12
+#define CONFIG_DEF_IMDMA_WRRD1 12
+#define CONFIG_DEF_WATCH 13
+#define CONFIG_DEF_RESERVED_1 7
+#define CONFIG_DEF_RESERVED_2 7
+#define CONFIG_DEF_SUPPLE_0 7
+#define CONFIG_DEF_SUPPLE_1 7
+
+/* IAR0 BIT FIELDS */
+#define IRQ_PLL_WAKEUP_POS 0
+#define IRQ_DMA1_ERROR_POS 4
+#define IRQ_DMA2_ERROR_POS 8
+#define IRQ_IMDMA_ERROR_POS 12
+#define IRQ_PPI0_ERROR_POS 16
+#define IRQ_PPI1_ERROR_POS 20
+#define IRQ_SPORT0_ERROR_POS 24
+#define IRQ_SPORT1_ERROR_POS 28
+/* IAR1 BIT FIELDS */
+#define IRQ_SPI_ERROR_POS 0
+#define IRQ_UART_ERROR_POS 4
+#define IRQ_RESERVED_ERROR_POS 8
+#define IRQ_DMA1_0_POS 12
+#define IRQ_DMA1_1_POS 16
+#define IRQ_DMA1_2_POS 20
+#define IRQ_DMA1_3_POS 24
+#define IRQ_DMA1_4_POS 28
+/* IAR2 BIT FIELDS */
+#define IRQ_DMA1_5_POS 0
+#define IRQ_DMA1_6_POS 4
+#define IRQ_DMA1_7_POS 8
+#define IRQ_DMA1_8_POS 12
+#define IRQ_DMA1_9_POS 16
+#define IRQ_DMA1_10_POS 20
+#define IRQ_DMA1_11_POS 24
+#define IRQ_DMA2_0_POS 28
+/* IAR3 BIT FIELDS */
+#define IRQ_DMA2_1_POS 0
+#define IRQ_DMA2_2_POS 4
+#define IRQ_DMA2_3_POS 8
+#define IRQ_DMA2_4_POS 12
+#define IRQ_DMA2_5_POS 16
+#define IRQ_DMA2_6_POS 20
+#define IRQ_DMA2_7_POS 24
+#define IRQ_DMA2_8_POS 28
+/* IAR4 BIT FIELDS */
+#define IRQ_DMA2_9_POS 0
+#define IRQ_DMA2_10_POS 4
+#define IRQ_DMA2_11_POS 8
+#define IRQ_TIMER0_POS 12
+#define IRQ_TIMER1_POS 16
+#define IRQ_TIMER2_POS 20
+#define IRQ_TIMER3_POS 24
+#define IRQ_TIMER4_POS 28
+/* IAR5 BIT FIELDS */
+#define IRQ_TIMER5_POS 0
+#define IRQ_TIMER6_POS 4
+#define IRQ_TIMER7_POS 8
+#define IRQ_TIMER8_POS 12
+#define IRQ_TIMER9_POS 16
+#define IRQ_TIMER10_POS 20
+#define IRQ_TIMER11_POS 24
+#define IRQ_PROG0_INTA_POS 28
+/* IAR6 BIT FIELDS */
+#define IRQ_PROG0_INTB_POS 0
+#define IRQ_PROG1_INTA_POS 4
+#define IRQ_PROG1_INTB_POS 8
+#define IRQ_PROG2_INTA_POS 12
+#define IRQ_PROG2_INTB_POS 16
+#define IRQ_DMA1_WRRD0_POS 20
+#define IRQ_DMA1_WRRD1_POS 24
+#define IRQ_DMA2_WRRD0_POS 28
+/* IAR7 BIT FIELDS */
+#define IRQ_DMA2_WRRD1_POS 0
+#define IRQ_IMDMA_WRRD0_POS 4
+#define IRQ_IMDMA_WRRD1_POS 8
+#define IRQ_WDTIMER_POS 12
+#define IRQ_RESERVED_1_POS 16
+#define IRQ_RESERVED_2_POS 20
+#define IRQ_SUPPLE_0_POS 24
+#define IRQ_SUPPLE_1_POS 28
+
+#endif /* _BF561_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf561/mem_init.h b/include/asm-blackfin/mach-bf561/mem_init.h
new file mode 100644
index 00000000000..439a5895b34
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/mem_init.h
@@ -0,0 +1,322 @@
+/*
+ * File: include/asm-blackfin/mach-bf561/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75 || CONFIG_MEM_MT48LC64M4A2FB_7E || CONFIG_MEM_GENERIC_BOARD || CONFIG_MEM_MT48LC8M32B2B5_7)
+#if (CONFIG_SCLK_HZ > 119402985)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_7
+#define SDRAM_tRAS_num 7
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 104477612) && (CONFIG_SCLK_HZ <= 119402985)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_6
+#define SDRAM_tRAS_num 6
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 89552239) && (CONFIG_SCLK_HZ <= 104477612)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_5
+#define SDRAM_tRAS_num 5
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 74626866) && (CONFIG_SCLK_HZ <= 89552239)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_4
+#define SDRAM_tRAS_num 4
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 66666667) && (CONFIG_SCLK_HZ <= 74626866)
+#define SDRAM_tRP TRP_2
+#define SDRAM_tRP_num 2
+#define SDRAM_tRAS TRAS_3
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_2
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 59701493) && (CONFIG_SCLK_HZ <= 66666667)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_4
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 44776119) && (CONFIG_SCLK_HZ <= 59701493)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_3
+#define SDRAM_tRAS_num 3
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ > 29850746) && (CONFIG_SCLK_HZ <= 44776119)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_2
+#define SDRAM_tRAS_num 2
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#if (CONFIG_SCLK_HZ <= 29850746)
+#define SDRAM_tRP TRP_1
+#define SDRAM_tRP_num 1
+#define SDRAM_tRAS TRAS_1
+#define SDRAM_tRAS_num 1
+#define SDRAM_tRCD TRCD_1
+#define SDRAM_tWR TWR_2
+#endif
+#endif
+
+#if (CONFIG_MEM_MT48LC16M16A2TG_75)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC64M4A2FB_7E)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_MT48LC8M32B2B5_7)
+ /*SDRAM INFORMATION: */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 4096 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_GENERIC_BOARD)
+ /*SDRAM INFORMATION: Modify this for your board */
+#define SDRAM_Tref 64 /* Refresh period in milliseconds */
+#define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
+#define SDRAM_CL CL_3
+#endif
+
+#if (CONFIG_MEM_SIZE == 128)
+#define SDRAM_SIZE EB0_SZ_128
+#endif
+#if (CONFIG_MEM_SIZE == 64)
+#define SDRAM_SIZE EB0_SZ_64
+#endif
+#if ( CONFIG_MEM_SIZE == 32)
+#define SDRAM_SIZE EB0_SZ_32
+#endif
+#if (CONFIG_MEM_SIZE == 16)
+#define SDRAM_SIZE EB0_SZ_16
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 11)
+#define SDRAM_WIDTH EB0_CAW_11
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 10)
+#define SDRAM_WIDTH EB0_CAW_10
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 9)
+#define SDRAM_WIDTH EB0_CAW_9
+#endif
+#if (CONFIG_MEM_ADD_WIDTH == 8)
+#define SDRAM_WIDTH EB0_CAW_8
+#endif
+
+#define mem_SDBCTL (SDRAM_WIDTH | SDRAM_SIZE | EB0_E)
+
+/* Equation from section 17 (p17-46) of BF533 HRM */
+#define mem_SDRRC (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
+
+/* Enable SCLK Out */
+#define mem_SDGCTL (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF 1
+#else
+#define CLKIN_HALF 0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS 1
+#else
+#define PLL_BYPASS 0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT ((CONFIG_FLASH_SPEED_BHT * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST ((CONFIG_FLASH_SPEED_BST * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT ((CONFIG_FLASH_SPEED_BTT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0 \
+ (flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+ flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf561/mem_map.h b/include/asm-blackfin/mach-bf561/mem_map.h
new file mode 100644
index 00000000000..ebac9a8d838
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/mem_map.h
@@ -0,0 +1,75 @@
+/*
+ * Memory MAP
+ * Common header file for blackfin BF561 of processors.
+ */
+
+#ifndef _MEM_MAP_561_H_
+#define _MEM_MAP_561_H_
+
+#define COREMMR_BASE 0xFFE00000 /* Core MMRs */
+#define SYSMMR_BASE 0xFFC00000 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE 0x2C000000 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE 0x04000000 /* 64M */
+#define ASYNC_BANK2_BASE 0x28000000 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE 0x04000000 /* 64M */
+#define ASYNC_BANK1_BASE 0x24000000 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE 0x04000000 /* 64M */
+#define ASYNC_BANK0_BASE 0x20000000 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE 0x04000000 /* 64M */
+
+/* Level 1 Memory */
+
+#ifdef CONFIG_BLKFIN_CACHE
+#define BLKFIN_ICACHESIZE (16*1024)
+#else
+#define BLKFIN_ICACHESIZE (0*1024)
+#endif
+
+/* Memory Map for ADSP-BF561 processors */
+
+#ifdef CONFIG_BF561
+#define L1_CODE_START 0xFFA00000
+#define L1_DATA_A_START 0xFF800000
+#define L1_DATA_B_START 0xFF900000
+
+#define L1_CODE_LENGTH 0x4000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x8000
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+#endif
+
+/* Level 2 Memory */
+#define L2_START 0xFEB00000
+#define L2_LENGTH 0x20000
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF561)
+#define L1_SCRATCH_START 0xFFB00000
+#define L1_SCRATCH_LENGTH 0x1000
+#endif
+
+#endif /* _MEM_MAP_533_H_ */
diff --git a/include/asm-blackfin/mach-common/cdef_LPBlackfin.h b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
new file mode 100644
index 00000000000..22aa5e63799
--- /dev/null
+++ b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
@@ -0,0 +1,471 @@
+ /*
+ * File: include/asm-blackfin/mach-common/cdef_LPBlackfin.h
+ * Based on:
+ * Author: unknown
+ * COPYRIGHT 2005 Analog Devices
+ * Created: ?
+ * Description:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _CDEF_LPBLACKFIN_H
+#define _CDEF_LPBLACKFIN_H
+
+/*#if !defined(__ADSPLPBLACKFIN__)
+#warning cdef_LPBlackfin.h should only be included for 532 compatible chips.
+#endif
+*/
+#include <asm/mach-common/def_LPBlackfin.h>
+
+/*Cache & SRAM Memory*/
+#define pSRAM_BASE_ADDRESS ((volatile void **)SRAM_BASE_ADDRESS)
+#define bfin_read_SRAM_BASE_ADDRESS() bfin_read32(SRAM_BASE_ADDRESS)
+#define bfin_write_SRAM_BASE_ADDRESS(val) bfin_write32(SRAM_BASE_ADDRESS,val)
+#define pDMEM_CONTROL ((volatile unsigned long *)DMEM_CONTROL)
+#define bfin_read_DMEM_CONTROL() bfin_read32(DMEM_CONTROL)
+#define bfin_write_DMEM_CONTROL(val) bfin_write32(DMEM_CONTROL,val)
+#define pDCPLB_STATUS ((volatile unsigned long *)DCPLB_STATUS)
+#define bfin_read_DCPLB_STATUS() bfin_read32(DCPLB_STATUS)
+#define bfin_write_DCPLB_STATUS(val) bfin_write32(DCPLB_STATUS,val)
+#define pDCPLB_FAULT_ADDR ((volatile void **)DCPLB_FAULT_ADDR)
+#define bfin_read_DCPLB_FAULT_ADDR() bfin_read32(DCPLB_FAULT_ADDR)
+#define bfin_write_DCPLB_FAULT_ADDR(val) bfin_write32(DCPLB_FAULT_ADDR,val)
+/*
+#define MMR_TIMEOUT 0xFFE00010
+*/
+#define pDCPLB_ADDR0 ((volatile void **)DCPLB_ADDR0)
+#define bfin_read_DCPLB_ADDR0() bfin_read32(DCPLB_ADDR0)
+#define bfin_write_DCPLB_ADDR0(val) bfin_write32(DCPLB_ADDR0,val)
+#define pDCPLB_ADDR1 ((volatile void **)DCPLB_ADDR1)
+#define bfin_read_DCPLB_ADDR1() bfin_read32(DCPLB_ADDR1)
+#define bfin_write_DCPLB_ADDR1(val) bfin_write32(DCPLB_ADDR1,val)
+#define pDCPLB_ADDR2 ((volatile void **)DCPLB_ADDR2)
+#define bfin_read_DCPLB_ADDR2() bfin_read32(DCPLB_ADDR2)
+#define bfin_write_DCPLB_ADDR2(val) bfin_write32(DCPLB_ADDR2,val)
+#define pDCPLB_ADDR3 ((volatile void **)DCPLB_ADDR3)
+#define bfin_read_DCPLB_ADDR3() bfin_read32(DCPLB_ADDR3)
+#define bfin_write_DCPLB_ADDR3(val) bfin_write32(DCPLB_ADDR3,val)
+#define pDCPLB_ADDR4 ((volatile void **)DCPLB_ADDR4)
+#define bfin_read_DCPLB_ADDR4() bfin_read32(DCPLB_ADDR4)
+#define bfin_write_DCPLB_ADDR4(val) bfin_write32(DCPLB_ADDR4,val)
+#define pDCPLB_ADDR5 ((volatile void **)DCPLB_ADDR5)
+#define bfin_read_DCPLB_ADDR5() bfin_read32(DCPLB_ADDR5)
+#define bfin_write_DCPLB_ADDR5(val) bfin_write32(DCPLB_ADDR5,val)
+#define pDCPLB_ADDR6 ((volatile void **)DCPLB_ADDR6)
+#define bfin_read_DCPLB_ADDR6() bfin_read32(DCPLB_ADDR6)
+#define bfin_write_DCPLB_ADDR6(val) bfin_write32(DCPLB_ADDR6,val)
+#define pDCPLB_ADDR7 ((volatile void **)DCPLB_ADDR7)
+#define bfin_read_DCPLB_ADDR7() bfin_read32(DCPLB_ADDR7)
+#define bfin_write_DCPLB_ADDR7(val) bfin_write32(DCPLB_ADDR7,val)
+#define pDCPLB_ADDR8 ((volatile void **)DCPLB_ADDR8)
+#define bfin_read_DCPLB_ADDR8() bfin_read32(DCPLB_ADDR8)
+#define bfin_write_DCPLB_ADDR8(val) bfin_write32(DCPLB_ADDR8,val)
+#define pDCPLB_ADDR9 ((volatile void **)DCPLB_ADDR9)
+#define bfin_read_DCPLB_ADDR9() bfin_read32(DCPLB_ADDR9)
+#define bfin_write_DCPLB_ADDR9(val) bfin_write32(DCPLB_ADDR9,val)
+#define pDCPLB_ADDR10 ((volatile void **)DCPLB_ADDR10)
+#define bfin_read_DCPLB_ADDR10() bfin_read32(DCPLB_ADDR10)
+#define bfin_write_DCPLB_ADDR10(val) bfin_write32(DCPLB_ADDR10,val)
+#define pDCPLB_ADDR11 ((volatile void **)DCPLB_ADDR11)
+#define bfin_read_DCPLB_ADDR11() bfin_read32(DCPLB_ADDR11)
+#define bfin_write_DCPLB_ADDR11(val) bfin_write32(DCPLB_ADDR11,val)
+#define pDCPLB_ADDR12 ((volatile void **)DCPLB_ADDR12)
+#define bfin_read_DCPLB_ADDR12() bfin_read32(DCPLB_ADDR12)
+#define bfin_write_DCPLB_ADDR12(val) bfin_write32(DCPLB_ADDR12,val)
+#define pDCPLB_ADDR13 ((volatile void **)DCPLB_ADDR13)
+#define bfin_read_DCPLB_ADDR13() bfin_read32(DCPLB_ADDR13)
+#define bfin_write_DCPLB_ADDR13(val) bfin_write32(DCPLB_ADDR13,val)
+#define pDCPLB_ADDR14 ((volatile void **)DCPLB_ADDR14)
+#define bfin_read_DCPLB_ADDR14() bfin_read32(DCPLB_ADDR14)
+#define bfin_write_DCPLB_ADDR14(val) bfin_write32(DCPLB_ADDR14,val)
+#define pDCPLB_ADDR15 ((volatile void **)DCPLB_ADDR15)
+#define bfin_read_DCPLB_ADDR15() bfin_read32(DCPLB_ADDR15)
+#define bfin_write_DCPLB_ADDR15(val) bfin_write32(DCPLB_ADDR15,val)
+#define pDCPLB_DATA0 ((volatile unsigned long *)DCPLB_DATA0)
+#define bfin_read_DCPLB_DATA0() bfin_read32(DCPLB_DATA0)
+#define bfin_write_DCPLB_DATA0(val) bfin_write32(DCPLB_DATA0,val)
+#define pDCPLB_DATA1 ((volatile unsigned long *)DCPLB_DATA1)
+#define bfin_read_DCPLB_DATA1() bfin_read32(DCPLB_DATA1)
+#define bfin_write_DCPLB_DATA1(val) bfin_write32(DCPLB_DATA1,val)
+#define pDCPLB_DATA2 ((volatile unsigned long *)DCPLB_DATA2)
+#define bfin_read_DCPLB_DATA2() bfin_read32(DCPLB_DATA2)
+#define bfin_write_DCPLB_DATA2(val) bfin_write32(DCPLB_DATA2,val)
+#define pDCPLB_DATA3 ((volatile unsigned long *)DCPLB_DATA3)
+#define bfin_read_DCPLB_DATA3() bfin_read32(DCPLB_DATA3)
+#define bfin_write_DCPLB_DATA3(val) bfin_write32(DCPLB_DATA3,val)
+#define pDCPLB_DATA4 ((volatile unsigned long *)DCPLB_DATA4)
+#define bfin_read_DCPLB_DATA4() bfin_read32(DCPLB_DATA4)
+#define bfin_write_DCPLB_DATA4(val) bfin_write32(DCPLB_DATA4,val)
+#define pDCPLB_DATA5 ((volatile unsigned long *)DCPLB_DATA5)
+#define bfin_read_DCPLB_DATA5() bfin_read32(DCPLB_DATA5)
+#define bfin_write_DCPLB_DATA5(val) bfin_write32(DCPLB_DATA5,val)
+#define pDCPLB_DATA6 ((volatile unsigned long *)DCPLB_DATA6)
+#define bfin_read_DCPLB_DATA6() bfin_read32(DCPLB_DATA6)
+#define bfin_write_DCPLB_DATA6(val) bfin_write32(DCPLB_DATA6,val)
+#define pDCPLB_DATA7 ((volatile unsigned long *)DCPLB_DATA7)
+#define bfin_read_DCPLB_DATA7() bfin_read32(DCPLB_DATA7)
+#define bfin_write_DCPLB_DATA7(val) bfin_write32(DCPLB_DATA7,val)
+#define pDCPLB_DATA8 ((volatile unsigned long *)DCPLB_DATA8)
+#define bfin_read_DCPLB_DATA8() bfin_read32(DCPLB_DATA8)
+#define bfin_write_DCPLB_DATA8(val) bfin_write32(DCPLB_DATA8,val)
+#define pDCPLB_DATA9 ((volatile unsigned long *)DCPLB_DATA9)
+#define bfin_read_DCPLB_DATA9() bfin_read32(DCPLB_DATA9)
+#define bfin_write_DCPLB_DATA9(val) bfin_write32(DCPLB_DATA9,val)
+#define pDCPLB_DATA10 ((volatile unsigned long *)DCPLB_DATA10)
+#define bfin_read_DCPLB_DATA10() bfin_read32(DCPLB_DATA10)
+#define bfin_write_DCPLB_DATA10(val) bfin_write32(DCPLB_DATA10,val)
+#define pDCPLB_DATA11 ((volatile unsigned long *)DCPLB_DATA11)
+#define bfin_read_DCPLB_DATA11() bfin_read32(DCPLB_DATA11)
+#define bfin_write_DCPLB_DATA11(val) bfin_write32(DCPLB_DATA11,val)
+#define pDCPLB_DATA12 ((volatile unsigned long *)DCPLB_DATA12)
+#define bfin_read_DCPLB_DATA12() bfin_read32(DCPLB_DATA12)
+#define bfin_write_DCPLB_DATA12(val) bfin_write32(DCPLB_DATA12,val)
+#define pDCPLB_DATA13 ((volatile unsigned long *)DCPLB_DATA13)
+#define bfin_read_DCPLB_DATA13() bfin_read32(DCPLB_DATA13)
+#define bfin_write_DCPLB_DATA13(val) bfin_write32(DCPLB_DATA13,val)
+#define pDCPLB_DATA14 ((volatile unsigned long *)DCPLB_DATA14)
+#define bfin_read_DCPLB_DATA14() bfin_read32(DCPLB_DATA14)
+#define bfin_write_DCPLB_DATA14(val) bfin_write32(DCPLB_DATA14,val)
+#define pDCPLB_DATA15 ((volatile unsigned long *)DCPLB_DATA15)
+#define bfin_read_DCPLB_DATA15() bfin_read32(DCPLB_DATA15)
+#define bfin_write_DCPLB_DATA15(val) bfin_write32(DCPLB_DATA15,val)
+#define pDTEST_COMMAND ((volatile unsigned long *)DTEST_COMMAND)
+#define bfin_read_DTEST_COMMAND() bfin_read32(DTEST_COMMAND)
+#define bfin_write_DTEST_COMMAND(val) bfin_write32(DTEST_COMMAND,val)
+/*
+#define DTEST_INDEX 0xFFE00304
+*/
+#define pDTEST_DATA0 ((volatile unsigned long *)DTEST_DATA0)
+#define bfin_read_DTEST_DATA0() bfin_read32(DTEST_DATA0)
+#define bfin_write_DTEST_DATA0(val) bfin_write32(DTEST_DATA0,val)
+#define pDTEST_DATA1 ((volatile unsigned long *)DTEST_DATA1)
+#define bfin_read_DTEST_DATA1() bfin_read32(DTEST_DATA1)
+#define bfin_write_DTEST_DATA1(val) bfin_write32(DTEST_DATA1,val)
+/*
+#define DTEST_DATA2 0xFFE00408
+#define DTEST_DATA3 0xFFE0040C
+*/
+#define pIMEM_CONTROL ((volatile unsigned long *)IMEM_CONTROL)
+#define bfin_read_IMEM_CONTROL() bfin_read32(IMEM_CONTROL)
+#define bfin_write_IMEM_CONTROL(val) bfin_write32(IMEM_CONTROL,val)
+#define pICPLB_STATUS ((volatile unsigned long *)ICPLB_STATUS)
+#define bfin_read_ICPLB_STATUS() bfin_read32(ICPLB_STATUS)
+#define bfin_write_ICPLB_STATUS(val) bfin_write32(ICPLB_STATUS,val)
+#define pICPLB_FAULT_ADDR ((volatile void **)ICPLB_FAULT_ADDR)
+#define bfin_read_ICPLB_FAULT_ADDR() bfin_read32(ICPLB_FAULT_ADDR)
+#define bfin_write_ICPLB_FAULT_ADDR(val) bfin_write32(ICPLB_FAULT_ADDR,val)
+#define pICPLB_ADDR0 ((volatile void **)ICPLB_ADDR0)
+#define bfin_read_ICPLB_ADDR0() bfin_read32(ICPLB_ADDR0)
+#define bfin_write_ICPLB_ADDR0(val) bfin_write32(ICPLB_ADDR0,val)
+#define pICPLB_ADDR1 ((volatile void **)ICPLB_ADDR1)
+#define bfin_read_ICPLB_ADDR1() bfin_read32(ICPLB_ADDR1)
+#define bfin_write_ICPLB_ADDR1(val) bfin_write32(ICPLB_ADDR1,val)
+#define pICPLB_ADDR2 ((volatile void **)ICPLB_ADDR2)
+#define bfin_read_ICPLB_ADDR2() bfin_read32(ICPLB_ADDR2)
+#define bfin_write_ICPLB_ADDR2(val) bfin_write32(ICPLB_ADDR2,val)
+#define pICPLB_ADDR3 ((volatile void **)ICPLB_ADDR3)
+#define bfin_read_ICPLB_ADDR3() bfin_read32(ICPLB_ADDR3)
+#define bfin_write_ICPLB_ADDR3(val) bfin_write32(ICPLB_ADDR3,val)
+#define pICPLB_ADDR4 ((volatile void **)ICPLB_ADDR4)
+#define bfin_read_ICPLB_ADDR4() bfin_read32(ICPLB_ADDR4)
+#define bfin_write_ICPLB_ADDR4(val) bfin_write32(ICPLB_ADDR4,val)
+#define pICPLB_ADDR5 ((volatile void **)ICPLB_ADDR5)
+#define bfin_read_ICPLB_ADDR5() bfin_read32(ICPLB_ADDR5)
+#define bfin_write_ICPLB_ADDR5(val) bfin_write32(ICPLB_ADDR5,val)
+#define pICPLB_ADDR6 ((volatile void **)ICPLB_ADDR6)
+#define bfin_read_ICPLB_ADDR6() bfin_read32(ICPLB_ADDR6)
+#define bfin_write_ICPLB_ADDR6(val) bfin_write32(ICPLB_ADDR6,val)
+#define pICPLB_ADDR7 ((volatile void **)ICPLB_ADDR7)
+#define bfin_read_ICPLB_ADDR7() bfin_read32(ICPLB_ADDR7)
+#define bfin_write_ICPLB_ADDR7(val) bfin_write32(ICPLB_ADDR7,val)
+#define pICPLB_ADDR8 ((volatile void **)ICPLB_ADDR8)
+#define bfin_read_ICPLB_ADDR8() bfin_read32(ICPLB_ADDR8)
+#define bfin_write_ICPLB_ADDR8(val) bfin_write32(ICPLB_ADDR8,val)
+#define pICPLB_ADDR9 ((volatile void **)ICPLB_ADDR9)
+#define bfin_read_ICPLB_ADDR9() bfin_read32(ICPLB_ADDR9)
+#define bfin_write_ICPLB_ADDR9(val) bfin_write32(ICPLB_ADDR9,val)
+#define pICPLB_ADDR10 ((volatile void **)ICPLB_ADDR10)
+#define bfin_read_ICPLB_ADDR10() bfin_read32(ICPLB_ADDR10)
+#define bfin_write_ICPLB_ADDR10(val) bfin_write32(ICPLB_ADDR10,val)
+#define pICPLB_ADDR11 ((volatile void **)ICPLB_ADDR11)
+#define bfin_read_ICPLB_ADDR11() bfin_read32(ICPLB_ADDR11)
+#define bfin_write_ICPLB_ADDR11(val) bfin_write32(ICPLB_ADDR11,val)
+#define pICPLB_ADDR12 ((volatile void **)ICPLB_ADDR12)
+#define bfin_read_ICPLB_ADDR12() bfin_read32(ICPLB_ADDR12)
+#define bfin_write_ICPLB_ADDR12(val) bfin_write32(ICPLB_ADDR12,val)
+#define pICPLB_ADDR13 ((volatile void **)ICPLB_ADDR13)
+#define bfin_read_ICPLB_ADDR13() bfin_read32(ICPLB_ADDR13)
+#define bfin_write_ICPLB_ADDR13(val) bfin_write32(ICPLB_ADDR13,val)
+#define pICPLB_ADDR14 ((volatile void **)ICPLB_ADDR14)
+#define bfin_read_ICPLB_ADDR14() bfin_read32(ICPLB_ADDR14)
+#define bfin_write_ICPLB_ADDR14(val) bfin_write32(ICPLB_ADDR14,val)
+#define pICPLB_ADDR15 ((volatile void **)ICPLB_ADDR15)
+#define bfin_read_ICPLB_ADDR15() bfin_read32(ICPLB_ADDR15)
+#define bfin_write_ICPLB_ADDR15(val) bfin_write32(ICPLB_ADDR15,val)
+#define pICPLB_DATA0 ((volatile unsigned long *)ICPLB_DATA0)
+#define bfin_read_ICPLB_DATA0() bfin_read32(ICPLB_DATA0)
+#define bfin_write_ICPLB_DATA0(val) bfin_write32(ICPLB_DATA0,val)
+#define pICPLB_DATA1 ((volatile unsigned long *)ICPLB_DATA1)
+#define bfin_read_ICPLB_DATA1() bfin_read32(ICPLB_DATA1)
+#define bfin_write_ICPLB_DATA1(val) bfin_write32(ICPLB_DATA1,val)
+#define pICPLB_DATA2 ((volatile unsigned long *)ICPLB_DATA2)
+#define bfin_read_ICPLB_DATA2() bfin_read32(ICPLB_DATA2)
+#define bfin_write_ICPLB_DATA2(val) bfin_write32(ICPLB_DATA2,val)
+#define pICPLB_DATA3 ((volatile unsigned long *)ICPLB_DATA3)
+#define bfin_read_ICPLB_DATA3() bfin_read32(ICPLB_DATA3)
+#define bfin_write_ICPLB_DATA3(val) bfin_write32(ICPLB_DATA3,val)
+#define pICPLB_DATA4 ((volatile unsigned long *)ICPLB_DATA4)
+#define bfin_read_ICPLB_DATA4() bfin_read32(ICPLB_DATA4)
+#define bfin_write_ICPLB_DATA4(val) bfin_write32(ICPLB_DATA4,val)
+#define pICPLB_DATA5 ((volatile unsigned long *)ICPLB_DATA5)
+#define bfin_read_ICPLB_DATA5() bfin_read32(ICPLB_DATA5)
+#define bfin_write_ICPLB_DATA5(val) bfin_write32(ICPLB_DATA5,val)
+#define pICPLB_DATA6 ((volatile unsigned long *)ICPLB_DATA6)
+#define bfin_read_ICPLB_DATA6() bfin_read32(ICPLB_DATA6)
+#define bfin_write_ICPLB_DATA6(val) bfin_write32(ICPLB_DATA6,val)
+#define pICPLB_DATA7 ((volatile unsigned long *)ICPLB_DATA7)
+#define bfin_read_ICPLB_DATA7() bfin_read32(ICPLB_DATA7)
+#define bfin_write_ICPLB_DATA7(val) bfin_write32(ICPLB_DATA7,val)
+#define pICPLB_DATA8 ((volatile unsigned long *)ICPLB_DATA8)
+#define bfin_read_ICPLB_DATA8() bfin_read32(ICPLB_DATA8)
+#define bfin_write_ICPLB_DATA8(val) bfin_write32(ICPLB_DATA8,val)
+#define pICPLB_DATA9 ((volatile unsigned long *)ICPLB_DATA9)
+#define bfin_read_ICPLB_DATA9() bfin_read32(ICPLB_DATA9)
+#define bfin_write_ICPLB_DATA9(val) bfin_write32(ICPLB_DATA9,val)
+#define pICPLB_DATA10 ((volatile unsigned long *)ICPLB_DATA10)
+#define bfin_read_ICPLB_DATA10() bfin_read32(ICPLB_DATA10)
+#define bfin_write_ICPLB_DATA10(val) bfin_write32(ICPLB_DATA10,val)
+#define pICPLB_DATA11 ((volatile unsigned long *)ICPLB_DATA11)
+#define bfin_read_ICPLB_DATA11() bfin_read32(ICPLB_DATA11)
+#define bfin_write_ICPLB_DATA11(val) bfin_write32(ICPLB_DATA11,val)
+#define pICPLB_DATA12 ((volatile unsigned long *)ICPLB_DATA12)
+#define bfin_read_ICPLB_DATA12() bfin_read32(ICPLB_DATA12)
+#define bfin_write_ICPLB_DATA12(val) bfin_write32(ICPLB_DATA12,val)
+#define pICPLB_DATA13 ((volatile unsigned long *)ICPLB_DATA13)
+#define bfin_read_ICPLB_DATA13() bfin_read32(ICPLB_DATA13)
+#define bfin_write_ICPLB_DATA13(val) bfin_write32(ICPLB_DATA13,val)
+#define pICPLB_DATA14 ((volatile unsigned long *)ICPLB_DATA14)
+#define bfin_read_ICPLB_DATA14() bfin_read32(ICPLB_DATA14)
+#define bfin_write_ICPLB_DATA14(val) bfin_write32(ICPLB_DATA14,val)
+#define pICPLB_DATA15 ((volatile unsigned long *)ICPLB_DATA15)
+#define bfin_read_ICPLB_DATA15() bfin_read32(ICPLB_DATA15)
+#define bfin_write_ICPLB_DATA15(val) bfin_write32(ICPLB_DATA15,val)
+#define pITEST_COMMAND ((volatile unsigned long *)ITEST_COMMAND)
+#define bfin_read_ITEST_COMMAND() bfin_read32(ITEST_COMMAND)
+#define bfin_write_ITEST_COMMAND(val) bfin_write32(ITEST_COMMAND,val)
+#if 0
+#define ITEST_INDEX 0xFFE01304 /* Instruction Test Index Register */
+#endif
+#define pITEST_DATA0 ((volatile unsigned long *)ITEST_DATA0)
+#define bfin_read_ITEST_DATA0() bfin_read32(ITEST_DATA0)
+#define bfin_write_ITEST_DATA0(val) bfin_write32(ITEST_DATA0,val)
+#define pITEST_DATA1 ((volatile unsigned long *)ITEST_DATA1)
+#define bfin_read_ITEST_DATA1() bfin_read32(ITEST_DATA1)
+#define bfin_write_ITEST_DATA1(val) bfin_write32(ITEST_DATA1,val)
+
+/* Event/Interrupt Registers*/
+
+#define pEVT0 ((volatile void **)EVT0)
+#define bfin_read_EVT0() bfin_read32(EVT0)
+#define bfin_write_EVT0(val) bfin_write32(EVT0,val)
+#define pEVT1 ((volatile void **)EVT1)
+#define bfin_read_EVT1() bfin_read32(EVT1)
+#define bfin_write_EVT1(val) bfin_write32(EVT1,val)
+#define pEVT2 ((volatile void **)EVT2)
+#define bfin_read_EVT2() bfin_read32(EVT2)
+#define bfin_write_EVT2(val) bfin_write32(EVT2,val)
+#define pEVT3 ((volatile void **)EVT3)
+#define bfin_read_EVT3() bfin_read32(EVT3)
+#define bfin_write_EVT3(val) bfin_write32(EVT3,val)
+#define pEVT4 ((volatile void **)EVT4)
+#define bfin_read_EVT4() bfin_read32(EVT4)
+#define bfin_write_EVT4(val) bfin_write32(EVT4,val)
+#define pEVT5 ((volatile void **)EVT5)
+#define bfin_read_EVT5() bfin_read32(EVT5)
+#define bfin_write_EVT5(val) bfin_write32(EVT5,val)
+#define pEVT6 ((volatile void **)EVT6)
+#define bfin_read_EVT6() bfin_read32(EVT6)
+#define bfin_write_EVT6(val) bfin_write32(EVT6,val)
+#define pEVT7 ((volatile void **)EVT7)
+#define bfin_read_EVT7() bfin_read32(EVT7)
+#define bfin_write_EVT7(val) bfin_write32(EVT7,val)
+#define pEVT8 ((volatile void **)EVT8)
+#define bfin_read_EVT8() bfin_read32(EVT8)
+#define bfin_write_EVT8(val) bfin_write32(EVT8,val)
+#define pEVT9 ((volatile void **)EVT9)
+#define bfin_read_EVT9() bfin_read32(EVT9)
+#define bfin_write_EVT9(val) bfin_write32(EVT9,val)
+#define pEVT10 ((volatile void **)EVT10)
+#define bfin_read_EVT10() bfin_read32(EVT10)
+#define bfin_write_EVT10(val) bfin_write32(EVT10,val)
+#define pEVT11 ((volatile void **)EVT11)
+#define bfin_read_EVT11() bfin_read32(EVT11)
+#define bfin_write_EVT11(val) bfin_write32(EVT11,val)
+#define pEVT12 ((volatile void **)EVT12)
+#define bfin_read_EVT12() bfin_read32(EVT12)
+#define bfin_write_EVT12(val) bfin_write32(EVT12,val)
+#define pEVT13 ((volatile void **)EVT13)
+#define bfin_read_EVT13() bfin_read32(EVT13)
+#define bfin_write_EVT13(val) bfin_write32(EVT13,val)
+#define pEVT14 ((volatile void **)EVT14)
+#define bfin_read_EVT14() bfin_read32(EVT14)
+#define bfin_write_EVT14(val) bfin_write32(EVT14,val)
+#define pEVT15 ((volatile void **)EVT15)
+#define bfin_read_EVT15() bfin_read32(EVT15)
+#define bfin_write_EVT15(val) bfin_write32(EVT15,val)
+#define pIMASK ((volatile unsigned long *)IMASK)
+#define bfin_read_IMASK() bfin_read32(IMASK)
+#define bfin_write_IMASK(val) bfin_write32(IMASK,val)
+#define pIPEND ((volatile unsigned long *)IPEND)
+#define bfin_read_IPEND() bfin_read32(IPEND)
+#define bfin_write_IPEND(val) bfin_write32(IPEND,val)
+#define pILAT ((volatile unsigned long *)ILAT)
+#define bfin_read_ILAT() bfin_read32(ILAT)
+#define bfin_write_ILAT(val) bfin_write32(ILAT,val)
+
+/*Core Timer Registers*/
+#define pTCNTL ((volatile unsigned long *)TCNTL)
+#define bfin_read_TCNTL() bfin_read32(TCNTL)
+#define bfin_write_TCNTL(val) bfin_write32(TCNTL,val)
+#define pTPERIOD ((volatile unsigned long *)TPERIOD)
+#define bfin_read_TPERIOD() bfin_read32(TPERIOD)
+#define bfin_write_TPERIOD(val) bfin_write32(TPERIOD,val)
+#define pTSCALE ((volatile unsigned long *)TSCALE)
+#define bfin_read_TSCALE() bfin_read32(TSCALE)
+#define bfin_write_TSCALE(val) bfin_write32(TSCALE,val)
+#define pTCOUNT ((volatile unsigned long *)TCOUNT)
+#define bfin_read_TCOUNT() bfin_read32(TCOUNT)
+#define bfin_write_TCOUNT(val) bfin_write32(TCOUNT,val)
+
+/*Debug/MP/Emulation Registers*/
+#define pDSPID ((volatile unsigned long *)DSPID)
+#define bfin_read_DSPID() bfin_read32(DSPID)
+#define bfin_write_DSPID(val) bfin_write32(DSPID,val)
+#define pDBGCTL ((volatile unsigned long *)DBGCTL)
+#define bfin_read_DBGCTL() bfin_read32(DBGCTL)
+#define bfin_write_DBGCTL(val) bfin_write32(DBGCTL,val)
+#define pDBGSTAT ((volatile unsigned long *)DBGSTAT)
+#define bfin_read_DBGSTAT() bfin_read32(DBGSTAT)
+#define bfin_write_DBGSTAT(val) bfin_write32(DBGSTAT,val)
+#define pEMUDAT ((volatile unsigned long *)EMUDAT)
+#define bfin_read_EMUDAT() bfin_read32(EMUDAT)
+#define bfin_write_EMUDAT(val) bfin_write32(EMUDAT,val)
+
+/*Trace Buffer Registers*/
+#define pTBUFCTL ((volatile unsigned long *)TBUFCTL)
+#define bfin_read_TBUFCTL() bfin_read32(TBUFCTL)
+#define bfin_write_TBUFCTL(val) bfin_write32(TBUFCTL,val)
+#define pTBUFSTAT ((volatile unsigned long *)TBUFSTAT)
+#define bfin_read_TBUFSTAT() bfin_read32(TBUFSTAT)
+#define bfin_write_TBUFSTAT(val) bfin_write32(TBUFSTAT,val)
+#define pTBUF ((volatile void **)TBUF)
+#define bfin_read_TBUF() bfin_read32(TBUF)
+#define bfin_write_TBUF(val) bfin_write32(TBUF,val)
+
+/*Watch Point Control Registers*/
+#define pWPIACTL ((volatile unsigned long *)WPIACTL)
+#define bfin_read_WPIACTL() bfin_read32(WPIACTL)
+#define bfin_write_WPIACTL(val) bfin_write32(WPIACTL,val)
+#define pWPIA0 ((volatile void **)WPIA0)
+#define bfin_read_WPIA0() bfin_read32(WPIA0)
+#define bfin_write_WPIA0(val) bfin_write32(WPIA0,val)
+#define pWPIA1 ((volatile void **)WPIA1)
+#define bfin_read_WPIA1() bfin_read32(WPIA1)
+#define bfin_write_WPIA1(val) bfin_write32(WPIA1,val)
+#define pWPIA2 ((volatile void **)WPIA2)
+#define bfin_read_WPIA2() bfin_read32(WPIA2)
+#define bfin_write_WPIA2(val) bfin_write32(WPIA2,val)
+#define pWPIA3 ((volatile void **)WPIA3)
+#define bfin_read_WPIA3() bfin_read32(WPIA3)
+#define bfin_write_WPIA3(val) bfin_write32(WPIA3,val)
+#define pWPIA4 ((volatile void **)WPIA4)
+#define bfin_read_WPIA4() bfin_read32(WPIA4)
+#define bfin_write_WPIA4(val) bfin_write32(WPIA4,val)
+#define pWPIA5 ((volatile void **)WPIA5)
+#define bfin_read_WPIA5() bfin_read32(WPIA5)
+#define bfin_write_WPIA5(val) bfin_write32(WPIA5,val)
+#define pWPIACNT0 ((volatile unsigned long *)WPIACNT0)
+#define bfin_read_WPIACNT0() bfin_read32(WPIACNT0)
+#define bfin_write_WPIACNT0(val) bfin_write32(WPIACNT0,val)
+#define pWPIACNT1 ((volatile unsigned long *)WPIACNT1)
+#define bfin_read_WPIACNT1() bfin_read32(WPIACNT1)
+#define bfin_write_WPIACNT1(val) bfin_write32(WPIACNT1,val)
+#define pWPIACNT2 ((volatile unsigned long *)WPIACNT2)
+#define bfin_read_WPIACNT2() bfin_read32(WPIACNT2)
+#define bfin_write_WPIACNT2(val) bfin_write32(WPIACNT2,val)
+#define pWPIACNT3 ((volatile unsigned long *)WPIACNT3)
+#define bfin_read_WPIACNT3() bfin_read32(WPIACNT3)
+#define bfin_write_WPIACNT3(val) bfin_write32(WPIACNT3,val)
+#define pWPIACNT4 ((volatile unsigned long *)WPIACNT4)
+#define bfin_read_WPIACNT4() bfin_read32(WPIACNT4)
+#define bfin_write_WPIACNT4(val) bfin_write32(WPIACNT4,val)
+#define pWPIACNT5 ((volatile unsigned long *)WPIACNT5)
+#define bfin_read_WPIACNT5() bfin_read32(WPIACNT5)
+#define bfin_write_WPIACNT5(val) bfin_write32(WPIACNT5,val)
+#define pWPDACTL ((volatile unsigned long *)WPDACTL)
+#define bfin_read_WPDACTL() bfin_read32(WPDACTL)
+#define bfin_write_WPDACTL(val) bfin_write32(WPDACTL,val)
+#define pWPDA0 ((volatile void **)WPDA0)
+#define bfin_read_WPDA0() bfin_read32(WPDA0)
+#define bfin_write_WPDA0(val) bfin_write32(WPDA0,val)
+#define pWPDA1 ((volatile void **)WPDA1)
+#define bfin_read_WPDA1() bfin_read32(WPDA1)
+#define bfin_write_WPDA1(val) bfin_write32(WPDA1,val)
+#define pWPDACNT0 ((volatile unsigned long *)WPDACNT0)
+#define bfin_read_WPDACNT0() bfin_read32(WPDACNT0)
+#define bfin_write_WPDACNT0(val) bfin_write32(WPDACNT0,val)
+#define pWPDACNT1 ((volatile unsigned long *)WPDACNT1)
+#define bfin_read_WPDACNT1() bfin_read32(WPDACNT1)
+#define bfin_write_WPDACNT1(val) bfin_write32(WPDACNT1,val)
+#define pWPSTAT ((volatile unsigned long *)WPSTAT)
+#define bfin_read_WPSTAT() bfin_read32(WPSTAT)
+#define bfin_write_WPSTAT(val) bfin_write32(WPSTAT,val)
+
+/*Performance Monitor Registers*/
+#define pPFCTL ((volatile unsigned long *)PFCTL)
+#define bfin_read_PFCTL() bfin_read32(PFCTL)
+#define bfin_write_PFCTL(val) bfin_write32(PFCTL,val)
+#define pPFCNTR0 ((volatile unsigned long *)PFCNTR0)
+#define bfin_read_PFCNTR0() bfin_read32(PFCNTR0)
+#define bfin_write_PFCNTR0(val) bfin_write32(PFCNTR0,val)
+#define pPFCNTR1 ((volatile unsigned long *)PFCNTR1)
+#define bfin_read_PFCNTR1() bfin_read32(PFCNTR1)
+#define bfin_write_PFCNTR1(val) bfin_write32(PFCNTR1,val)
+
+/*
+#define IPRIO 0xFFE02110
+*/
+
+#if defined(CONFIG_BFIN_ALIVE_LED)
+#define pCONFIG_BFIN_ALIVE_LED_DPORT \
+ (volatile unsigned short *)CONFIG_BFIN_ALIVE_LED_DPORT
+#define pCONFIG_BFIN_ALIVE_LED_PORT \
+ (volatile unsigned short *)CONFIG_BFIN_ALIVE_LED_PORT
+#endif
+
+#if defined(CONFIG_BFIN_IDLE_LED)
+#define pCONFIG_BFIN_IDLE_LED_DPORT \
+ (volatile unsigned short *)CONFIG_BFIN_IDLE_LED_DPORT
+#define pCONFIG_BFIN_IDLE_LED_PORT \
+ (volatile unsigned short *)CONFIG_BFIN_IDLE_LED_PORT
+#endif
+
+#endif /* _CDEF_LPBLACKFIN_H */
diff --git a/include/asm-blackfin/mach-common/context.S b/include/asm-blackfin/mach-common/context.S
new file mode 100644
index 00000000000..fd0ebe1862b
--- /dev/null
+++ b/include/asm-blackfin/mach-common/context.S
@@ -0,0 +1,350 @@
+/*
+ * File: arch/blackfin/kernel/context.S
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Code to save processor context.
+ * We even save the register which are preserved by a function call
+ * - r4, r5, r6, r7, p3, p4, p5
+ */
+.macro save_context_with_interrupts
+ [--sp] = SYSCFG;
+
+ [--sp] = P0; /*orig_p0*/
+ [--sp] = R0; /*orig_r0*/
+
+ [--sp] = ( R7:0, P5:0 );
+ [--sp] = fp;
+ [--sp] = usp;
+
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = a0.x;
+ [--sp] = a0.w;
+ [--sp] = a1.x;
+ [--sp] = a1.w;
+
+ [--sp] = LC0;
+ [--sp] = LC1;
+ [--sp] = LT0;
+ [--sp] = LT1;
+ [--sp] = LB0;
+ [--sp] = LB1;
+
+ [--sp] = ASTAT;
+
+ [--sp] = r0; /* Skip reserved */
+ [--sp] = RETS;
+ r0 = RETI;
+ [--sp] = r0;
+ [--sp] = RETX;
+ [--sp] = RETN;
+ [--sp] = RETE;
+ [--sp] = SEQSTAT;
+ [--sp] = r0; /* Skip IPEND as well. */
+ /* Switch to other method of keeping interrupts disabled. */
+#ifdef CONFIG_DEBUG_HWERR
+ r0 = 0x3f;
+ sti r0;
+#else
+ cli r0;
+#endif
+ [--sp] = RETI; /*orig_pc*/
+ /* Clear all L registers. */
+ r0 = 0 (x);
+ l0 = r0;
+ l1 = r0;
+ l2 = r0;
+ l3 = r0;
+.endm
+
+.macro save_context_syscall
+ [--sp] = SYSCFG;
+
+ [--sp] = P0; /*orig_p0*/
+ [--sp] = R0; /*orig_r0*/
+ [--sp] = ( R7:0, P5:0 );
+ [--sp] = fp;
+ [--sp] = usp;
+
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = a0.x;
+ [--sp] = a0.w;
+ [--sp] = a1.x;
+ [--sp] = a1.w;
+
+ [--sp] = LC0;
+ [--sp] = LC1;
+ [--sp] = LT0;
+ [--sp] = LT1;
+ [--sp] = LB0;
+ [--sp] = LB1;
+
+ [--sp] = ASTAT;
+
+ [--sp] = r0; /* Skip reserved */
+ [--sp] = RETS;
+ r0 = RETI;
+ [--sp] = r0;
+ [--sp] = RETX;
+ [--sp] = RETN;
+ [--sp] = RETE;
+ [--sp] = SEQSTAT;
+ [--sp] = r0; /* Skip IPEND as well. */
+ [--sp] = RETI; /*orig_pc*/
+ /* Clear all L registers. */
+ r0 = 0 (x);
+ l0 = r0;
+ l1 = r0;
+ l2 = r0;
+ l3 = r0;
+.endm
+
+.macro save_context_no_interrupts
+ [--sp] = SYSCFG;
+ [--sp] = P0; /* orig_p0 */
+ [--sp] = R0; /* orig_r0 */
+ [--sp] = ( R7:0, P5:0 );
+ [--sp] = fp;
+ [--sp] = usp;
+
+ [--sp] = i0;
+ [--sp] = i1;
+ [--sp] = i2;
+ [--sp] = i3;
+
+ [--sp] = m0;
+ [--sp] = m1;
+ [--sp] = m2;
+ [--sp] = m3;
+
+ [--sp] = l0;
+ [--sp] = l1;
+ [--sp] = l2;
+ [--sp] = l3;
+
+ [--sp] = b0;
+ [--sp] = b1;
+ [--sp] = b2;
+ [--sp] = b3;
+ [--sp] = a0.x;
+ [--sp] = a0.w;
+ [--sp] = a1.x;
+ [--sp] = a1.w;
+
+ [--sp] = LC0;
+ [--sp] = LC1;
+ [--sp] = LT0;
+ [--sp] = LT1;
+ [--sp] = LB0;
+ [--sp] = LB1;
+
+ [--sp] = ASTAT;
+
+#ifdef CONFIG_KGDB
+ fp = 0(Z);
+ r1 = sp;
+ r1 += 60;
+ r1 += 60;
+ r1 += 60;
+ [--sp] = r1;
+#else
+ [--sp] = r0; /* Skip reserved */
+#endif
+ [--sp] = RETS;
+ r0 = RETI;
+ [--sp] = r0;
+ [--sp] = RETX;
+ [--sp] = RETN;
+ [--sp] = RETE;
+ [--sp] = SEQSTAT;
+#ifdef CONFIG_KGDB
+ r1.l = lo(IPEND);
+ r1.h = hi(IPEND);
+ [--sp] = r1;
+#else
+ [--sp] = r0; /* Skip IPEND as well. */
+#endif
+ [--sp] = r0; /*orig_pc*/
+ /* Clear all L registers. */
+ r0 = 0 (x);
+ l0 = r0;
+ l1 = r0;
+ l2 = r0;
+ l3 = r0;
+.endm
+
+.macro restore_context_no_interrupts
+ sp += 4; /* Skip orig_pc */
+ sp += 4; /* Skip IPEND */
+ SEQSTAT = [sp++];
+ RETE = [sp++];
+ RETN = [sp++];
+ RETX = [sp++];
+ r0 = [sp++];
+ RETI = r0; /* Restore RETI indirectly when in exception */
+ RETS = [sp++];
+
+ sp += 4; /* Skip Reserved */
+
+ ASTAT = [sp++];
+
+ LB1 = [sp++];
+ LB0 = [sp++];
+ LT1 = [sp++];
+ LT0 = [sp++];
+ LC1 = [sp++];
+ LC0 = [sp++];
+
+ a1.w = [sp++];
+ a1.x = [sp++];
+ a0.w = [sp++];
+ a0.x = [sp++];
+ b3 = [sp++];
+ b2 = [sp++];
+ b1 = [sp++];
+ b0 = [sp++];
+
+ l3 = [sp++];
+ l2 = [sp++];
+ l1 = [sp++];
+ l0 = [sp++];
+
+ m3 = [sp++];
+ m2 = [sp++];
+ m1 = [sp++];
+ m0 = [sp++];
+
+ i3 = [sp++];
+ i2 = [sp++];
+ i1 = [sp++];
+ i0 = [sp++];
+
+ sp += 4;
+ fp = [sp++];
+
+ ( R7 : 0, P5 : 0) = [ SP ++ ];
+ sp += 8; /* Skip orig_r0/orig_p0 */
+ SYSCFG = [sp++];
+.endm
+
+.macro restore_context_with_interrupts
+ sp += 4; /* Skip orig_pc */
+ sp += 4; /* Skip IPEND */
+ SEQSTAT = [sp++];
+ RETE = [sp++];
+ RETN = [sp++];
+ RETX = [sp++];
+ RETI = [sp++];
+ RETS = [sp++];
+
+ p0.h = _irq_flags;
+ p0.l = _irq_flags;
+ r0 = [p0];
+ sti r0;
+
+ sp += 4; /* Skip Reserved */
+
+ ASTAT = [sp++];
+
+ LB1 = [sp++];
+ LB0 = [sp++];
+ LT1 = [sp++];
+ LT0 = [sp++];
+ LC1 = [sp++];
+ LC0 = [sp++];
+
+ a1.w = [sp++];
+ a1.x = [sp++];
+ a0.w = [sp++];
+ a0.x = [sp++];
+ b3 = [sp++];
+ b2 = [sp++];
+ b1 = [sp++];
+ b0 = [sp++];
+
+ l3 = [sp++];
+ l2 = [sp++];
+ l1 = [sp++];
+ l0 = [sp++];
+
+ m3 = [sp++];
+ m2 = [sp++];
+ m1 = [sp++];
+ m0 = [sp++];
+
+ i3 = [sp++];
+ i2 = [sp++];
+ i1 = [sp++];
+ i0 = [sp++];
+
+ sp += 4;
+ fp = [sp++];
+
+ ( R7 : 0, P5 : 0) = [ SP ++ ];
+ sp += 8; /* Skip orig_r0/orig_p0 */
+ csync;
+ SYSCFG = [sp++];
+ csync;
+.endm
+
diff --git a/include/asm-blackfin/mach-common/def_LPBlackfin.h b/include/asm-blackfin/mach-common/def_LPBlackfin.h
new file mode 100644
index 00000000000..76103526aec
--- /dev/null
+++ b/include/asm-blackfin/mach-common/def_LPBlackfin.h
@@ -0,0 +1,691 @@
+ /*
+ * File: include/asm-blackfin/mach-common/def_LPBlackfin.h
+ * Based on:
+ * Author: unknown
+ * COPYRIGHT 2005 Analog Devices
+ * Created: ?
+ * Description:
+ *
+ * Modified:
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* LP Blackfin CORE REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF532/33 */
+
+#ifndef _DEF_LPBLACKFIN_H
+#define _DEF_LPBLACKFIN_H
+
+#include <asm/mach/anomaly.h>
+
+/*#if !defined(__ADSPLPBLACKFIN__)
+#warning def_LPBlackfin.h should only be included for 532 compatible chips.
+#endif
+*/
+
+#define MK_BMSK_(x) (1<<x)
+
+#if defined(ANOMALY_05000198)
+
+#define bfin_read16(addr) ({ unsigned __v; \
+ __asm__ __volatile__ ("NOP;\n\t"\
+ "%0 = w[%1] (z);\n\t"\
+ : "=d"(__v) : "a"(addr)); (unsigned short)__v; })
+
+#define bfin_read32(addr) ({ unsigned __v; \
+ __asm__ __volatile__ ("NOP;\n\t"\
+ "%0 = [%1];\n\t"\
+ : "=d"(__v) : "a"(addr)); __v; })
+
+#define bfin_write16(addr,val) ({\
+ __asm__ __volatile__ ("NOP;\n\t"\
+ "w[%0] = %1;\n\t"\
+ : : "a"(addr) , "d"(val) : "memory");})
+
+#define bfin_write32(addr,val) ({\
+ __asm__ __volatile__ ("NOP;\n\t"\
+ "[%0] = %1;\n\t"\
+ : : "a"(addr) , "d"(val) : "memory");})
+
+#else
+
+#define bfin_read16(addr) ({ unsigned __v; \
+ __asm__ __volatile__ (\
+ "%0 = w[%1] (z);\n\t"\
+ : "=d"(__v) : "a"(addr)); (unsigned short)__v; })
+
+#define bfin_read32(addr) ({ unsigned __v; \
+ __asm__ __volatile__ (\
+ "%0 = [%1];\n\t"\
+ : "=d"(__v) : "a"(addr)); __v; })
+
+#define bfin_write16(addr,val) ({\
+ __asm__ __volatile__ (\
+ "w[%0] = %1;\n\t"\
+ : : "a"(addr) , "d"(val) : "memory");})
+
+#define bfin_write32(addr,val) ({\
+ __asm__ __volatile__ (\
+ "[%0] = %1;\n\t"\
+ : : "a"(addr) , "d"(val) : "memory");})
+
+#endif
+
+/**************************************************
+ * System Register Bits
+ **************************************************/
+
+/**************************************************
+ * ASTAT register
+ **************************************************/
+
+/* definitions of ASTAT bit positions*/
+
+/*Result of last ALU0 or shifter operation is zero*/
+#define ASTAT_AZ_P 0x00000000
+/*Result of last ALU0 or shifter operation is negative*/
+#define ASTAT_AN_P 0x00000001
+/*Condition Code, used for holding comparison results*/
+#define ASTAT_CC_P 0x00000005
+/*Quotient Bit*/
+#define ASTAT_AQ_P 0x00000006
+/*Rounding mode, set for biased, clear for unbiased*/
+#define ASTAT_RND_MOD_P 0x00000008
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0_P 0x0000000C
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0_COPY_P 0x00000002
+/*Result of last ALU1 operation generated a carry*/
+#define ASTAT_AC1_P 0x0000000D
+/*Result of last ALU0 or MAC0 operation overflowed, sticky for MAC*/
+#define ASTAT_AV0_P 0x00000010
+/*Sticky version of ASTAT_AV0 */
+#define ASTAT_AV0S_P 0x00000011
+/*Result of last MAC1 operation overflowed, sticky for MAC*/
+#define ASTAT_AV1_P 0x00000012
+/*Sticky version of ASTAT_AV1 */
+#define ASTAT_AV1S_P 0x00000013
+/*Result of last ALU0 or MAC0 operation overflowed*/
+#define ASTAT_V_P 0x00000018
+/*Result of last ALU0 or MAC0 operation overflowed*/
+#define ASTAT_V_COPY_P 0x00000003
+/*Sticky version of ASTAT_V*/
+#define ASTAT_VS_P 0x00000019
+
+/* Masks */
+
+/*Result of last ALU0 or shifter operation is zero*/
+#define ASTAT_AZ MK_BMSK_(ASTAT_AZ_P)
+/*Result of last ALU0 or shifter operation is negative*/
+#define ASTAT_AN MK_BMSK_(ASTAT_AN_P)
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0 MK_BMSK_(ASTAT_AC0_P)
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC0_COPY MK_BMSK_(ASTAT_AC0_COPY_P)
+/*Result of last ALU0 operation generated a carry*/
+#define ASTAT_AC1 MK_BMSK_(ASTAT_AC1_P)
+/*Result of last ALU0 or MAC0 operation overflowed, sticky for MAC*/
+#define ASTAT_AV0 MK_BMSK_(ASTAT_AV0_P)
+/*Result of last MAC1 operation overflowed, sticky for MAC*/
+#define ASTAT_AV1 MK_BMSK_(ASTAT_AV1_P)
+/*Condition Code, used for holding comparison results*/
+#define ASTAT_CC MK_BMSK_(ASTAT_CC_P)
+/*Quotient Bit*/
+#define ASTAT_AQ MK_BMSK_(ASTAT_AQ_P)
+/*Rounding mode, set for biased, clear for unbiased*/
+#define ASTAT_RND_MOD MK_BMSK_(ASTAT_RND_MOD_P)
+/*Overflow Bit*/
+#define ASTAT_V MK_BMSK_(ASTAT_V_P)
+/*Overflow Bit*/
+#define ASTAT_V_COPY MK_BMSK_(ASTAT_V_COPY_P)
+
+/**************************************************
+ * SEQSTAT register
+ **************************************************/
+
+/* Bit Positions */
+#define SEQSTAT_EXCAUSE0_P 0x00000000 /* Last exception cause bit 0 */
+#define SEQSTAT_EXCAUSE1_P 0x00000001 /* Last exception cause bit 1 */
+#define SEQSTAT_EXCAUSE2_P 0x00000002 /* Last exception cause bit 2 */
+#define SEQSTAT_EXCAUSE3_P 0x00000003 /* Last exception cause bit 3 */
+#define SEQSTAT_EXCAUSE4_P 0x00000004 /* Last exception cause bit 4 */
+#define SEQSTAT_EXCAUSE5_P 0x00000005 /* Last exception cause bit 5 */
+#define SEQSTAT_IDLE_REQ_P 0x0000000C /* Pending idle mode request,
+ * set by IDLE instruction.
+ */
+#define SEQSTAT_SFTRESET_P 0x0000000D /* Indicates whether the last
+ * reset was a software reset
+ * (=1)
+ */
+#define SEQSTAT_HWERRCAUSE0_P 0x0000000E /* Last hw error cause bit 0 */
+#define SEQSTAT_HWERRCAUSE1_P 0x0000000F /* Last hw error cause bit 1 */
+#define SEQSTAT_HWERRCAUSE2_P 0x00000010 /* Last hw error cause bit 2 */
+#define SEQSTAT_HWERRCAUSE3_P 0x00000011 /* Last hw error cause bit 3 */
+#define SEQSTAT_HWERRCAUSE4_P 0x00000012 /* Last hw error cause bit 4 */
+/* Masks */
+/* Exception cause */
+#define SEQSTAT_EXCAUSE (MK_BMSK_(SEQSTAT_EXCAUSE0_P) | \
+ MK_BMSK_(SEQSTAT_EXCAUSE1_P) | \
+ MK_BMSK_(SEQSTAT_EXCAUSE2_P) | \
+ MK_BMSK_(SEQSTAT_EXCAUSE3_P) | \
+ MK_BMSK_(SEQSTAT_EXCAUSE4_P) | \
+ MK_BMSK_(SEQSTAT_EXCAUSE5_P) | \
+ 0)
+
+/* Indicates whether the last reset was a software reset (=1) */
+#define SEQSTAT_SFTRESET (MK_BMSK_(SEQSTAT_SFTRESET_P))
+
+/* Last hw error cause */
+#define SEQSTAT_HWERRCAUSE (MK_BMSK_(SEQSTAT_HWERRCAUSE0_P) | \
+ MK_BMSK_(SEQSTAT_HWERRCAUSE1_P) | \
+ MK_BMSK_(SEQSTAT_HWERRCAUSE2_P) | \
+ MK_BMSK_(SEQSTAT_HWERRCAUSE3_P) | \
+ MK_BMSK_(SEQSTAT_HWERRCAUSE4_P) | \
+ 0)
+
+/* Translate bits to something useful */
+
+/* Last hw error cause */
+#define SEQSTAT_HWERRCAUSE_SHIFT (14)
+#define SEQSTAT_HWERRCAUSE_SYSTEM_MMR (0x02 << SEQSTAT_HWERRCAUSE_SHIFT)
+#define SEQSTAT_HWERRCAUSE_EXTERN_ADDR (0x03 << SEQSTAT_HWERRCAUSE_SHIFT)
+#define SEQSTAT_HWERRCAUSE_PERF_FLOW (0x12 << SEQSTAT_HWERRCAUSE_SHIFT)
+#define SEQSTAT_HWERRCAUSE_RAISE_5 (0x18 << SEQSTAT_HWERRCAUSE_SHIFT)
+
+/**************************************************
+ * SYSCFG register
+ **************************************************/
+
+/* Bit Positions */
+#define SYSCFG_SSSTEP_P 0x00000000 /* Supervisor single step, when
+ * set it forces an exception
+ * for each instruction executed
+ */
+#define SYSCFG_CCEN_P 0x00000001 /* Enable cycle counter (=1) */
+#define SYSCFG_SNEN_P 0x00000002 /* Self nesting Interrupt Enable */
+
+/* Masks */
+
+/* Supervisor single step, when set it forces an exception for each
+ *instruction executed
+ */
+#define SYSCFG_SSSTEP MK_BMSK_(SYSCFG_SSSTEP_P )
+/* Enable cycle counter (=1) */
+#define SYSCFG_CCEN MK_BMSK_(SYSCFG_CCEN_P )
+/* Self Nesting Interrupt Enable */
+#define SYSCFG_SNEN MK_BMSK_(SYSCFG_SNEN_P)
+/* Backward-compatibility for typos in prior releases */
+#define SYSCFG_SSSSTEP SYSCFG_SSSTEP
+#define SYSCFG_CCCEN SYSCFG_CCEN
+
+/****************************************************
+ * Core MMR Register Map
+ ****************************************************/
+
+/* Data Cache & SRAM Memory (0xFFE00000 - 0xFFE00404) */
+
+#define SRAM_BASE_ADDRESS 0xFFE00000 /* SRAM Base Address Register */
+#define DMEM_CONTROL 0xFFE00004 /* Data memory control */
+#define DCPLB_STATUS 0xFFE00008 /* Data Cache Programmable Look-Aside
+ * Buffer Status
+ */
+#define DCPLB_FAULT_STATUS 0xFFE00008 /* "" (older define) */
+#define DCPLB_FAULT_ADDR 0xFFE0000C /* Data Cache Programmable Look-Aside
+ * Buffer Fault Address
+ */
+#define DCPLB_ADDR0 0xFFE00100 /* Data Cache Protection Lookaside
+ * Buffer 0
+ */
+#define DCPLB_ADDR1 0xFFE00104 /* Data Cache Protection Lookaside
+ * Buffer 1
+ */
+#define DCPLB_ADDR2 0xFFE00108 /* Data Cache Protection Lookaside
+ * Buffer 2
+ */
+#define DCPLB_ADDR3 0xFFE0010C /* Data Cacheability Protection
+ * Lookaside Buffer 3
+ */
+#define DCPLB_ADDR4 0xFFE00110 /* Data Cacheability Protection
+ * Lookaside Buffer 4
+ */
+#define DCPLB_ADDR5 0xFFE00114 /* Data Cacheability Protection
+ * Lookaside Buffer 5
+ */
+#define DCPLB_ADDR6 0xFFE00118 /* Data Cacheability Protection
+ * Lookaside Buffer 6
+ */
+#define DCPLB_ADDR7 0xFFE0011C /* Data Cacheability Protection
+ * Lookaside Buffer 7
+ */
+#define DCPLB_ADDR8 0xFFE00120 /* Data Cacheability Protection
+ * Lookaside Buffer 8
+ */
+#define DCPLB_ADDR9 0xFFE00124 /* Data Cacheability Protection
+ * Lookaside Buffer 9
+ */
+#define DCPLB_ADDR10 0xFFE00128 /* Data Cacheability Protection
+ * Lookaside Buffer 10
+ */
+#define DCPLB_ADDR11 0xFFE0012C /* Data Cacheability Protection
+ * Lookaside Buffer 11
+ */
+#define DCPLB_ADDR12 0xFFE00130 /* Data Cacheability Protection
+ * Lookaside Buffer 12
+ */
+#define DCPLB_ADDR13 0xFFE00134 /* Data Cacheability Protection
+ * Lookaside Buffer 13
+ */
+#define DCPLB_ADDR14 0xFFE00138 /* Data Cacheability Protection
+ * Lookaside Buffer 14
+ */
+#define DCPLB_ADDR15 0xFFE0013C /* Data Cacheability Protection
+ * Lookaside Buffer 15
+ */
+#define DCPLB_DATA0 0xFFE00200 /* Data Cache 0 Status */
+#define DCPLB_DATA1 0xFFE00204 /* Data Cache 1 Status */
+#define DCPLB_DATA2 0xFFE00208 /* Data Cache 2 Status */
+#define DCPLB_DATA3 0xFFE0020C /* Data Cache 3 Status */
+#define DCPLB_DATA4 0xFFE00210 /* Data Cache 4 Status */
+#define DCPLB_DATA5 0xFFE00214 /* Data Cache 5 Status */
+#define DCPLB_DATA6 0xFFE00218 /* Data Cache 6 Status */
+#define DCPLB_DATA7 0xFFE0021C /* Data Cache 7 Status */
+#define DCPLB_DATA8 0xFFE00220 /* Data Cache 8 Status */
+#define DCPLB_DATA9 0xFFE00224 /* Data Cache 9 Status */
+#define DCPLB_DATA10 0xFFE00228 /* Data Cache 10 Status */
+#define DCPLB_DATA11 0xFFE0022C /* Data Cache 11 Status */
+#define DCPLB_DATA12 0xFFE00230 /* Data Cache 12 Status */
+#define DCPLB_DATA13 0xFFE00234 /* Data Cache 13 Status */
+#define DCPLB_DATA14 0xFFE00238 /* Data Cache 14 Status */
+#define DCPLB_DATA15 0xFFE0023C /* Data Cache 15 Status */
+#define DCPLB_DATA16 0xFFE00240 /* Extra Dummy entry */
+
+#define DTEST_COMMAND 0xFFE00300 /* Data Test Command Register */
+#define DTEST_DATA0 0xFFE00400 /* Data Test Data Register */
+#define DTEST_DATA1 0xFFE00404 /* Data Test Data Register */
+
+/* Instruction Cache & SRAM Memory (0xFFE01004 - 0xFFE01404) */
+
+#define IMEM_CONTROL 0xFFE01004 /* Instruction Memory Control */
+#define ICPLB_STATUS 0xFFE01008 /* Instruction Cache miss status */
+#define CODE_FAULT_STATUS 0xFFE01008 /* "" (older define) */
+#define ICPLB_FAULT_ADDR 0xFFE0100C /* Instruction Cache miss address */
+#define CODE_FAULT_ADDR 0xFFE0100C /* "" (older define) */
+#define ICPLB_ADDR0 0xFFE01100 /* Instruction Cacheability
+ * Protection Lookaside Buffer 0
+ */
+#define ICPLB_ADDR1 0xFFE01104 /* Instruction Cacheability
+ * Protection Lookaside Buffer 1
+ */
+#define ICPLB_ADDR2 0xFFE01108 /* Instruction Cacheability
+ * Protection Lookaside Buffer 2
+ */
+#define ICPLB_ADDR3 0xFFE0110C /* Instruction Cacheability
+ * Protection Lookaside Buffer 3
+ */
+#define ICPLB_ADDR4 0xFFE01110 /* Instruction Cacheability
+ * Protection Lookaside Buffer 4
+ */
+#define ICPLB_ADDR5 0xFFE01114 /* Instruction Cacheability
+ * Protection Lookaside Buffer 5
+ */
+#define ICPLB_ADDR6 0xFFE01118 /* Instruction Cacheability
+ * Protection Lookaside Buffer 6
+ */
+#define ICPLB_ADDR7 0xFFE0111C /* Instruction Cacheability
+ * Protection Lookaside Buffer 7
+ */
+#define ICPLB_ADDR8 0xFFE01120 /* Instruction Cacheability
+ * Protection Lookaside Buffer 8
+ */
+#define ICPLB_ADDR9 0xFFE01124 /* Instruction Cacheability
+ * Protection Lookaside Buffer 9
+ */
+#define ICPLB_ADDR10 0xFFE01128 /* Instruction Cacheability
+ * Protection Lookaside Buffer 10
+ */
+#define ICPLB_ADDR11 0xFFE0112C /* Instruction Cacheability
+ * Protection Lookaside Buffer 11
+ */
+#define ICPLB_ADDR12 0xFFE01130 /* Instruction Cacheability
+ * Protection Lookaside Buffer 12
+ */
+#define ICPLB_ADDR13 0xFFE01134 /* Instruction Cacheability
+ * Protection Lookaside Buffer 13
+ */
+#define ICPLB_ADDR14 0xFFE01138 /* Instruction Cacheability
+ * Protection Lookaside Buffer 14
+ */
+#define ICPLB_ADDR15 0xFFE0113C /* Instruction Cacheability
+ * Protection Lookaside Buffer 15
+ */
+#define ICPLB_DATA0 0xFFE01200 /* Instruction Cache 0 Status */
+#define ICPLB_DATA1 0xFFE01204 /* Instruction Cache 1 Status */
+#define ICPLB_DATA2 0xFFE01208 /* Instruction Cache 2 Status */
+#define ICPLB_DATA3 0xFFE0120C /* Instruction Cache 3 Status */
+#define ICPLB_DATA4 0xFFE01210 /* Instruction Cache 4 Status */
+#define ICPLB_DATA5 0xFFE01214 /* Instruction Cache 5 Status */
+#define ICPLB_DATA6 0xFFE01218 /* Instruction Cache 6 Status */
+#define ICPLB_DATA7 0xFFE0121C /* Instruction Cache 7 Status */
+#define ICPLB_DATA8 0xFFE01220 /* Instruction Cache 8 Status */
+#define ICPLB_DATA9 0xFFE01224 /* Instruction Cache 9 Status */
+#define ICPLB_DATA10 0xFFE01228 /* Instruction Cache 10 Status */
+#define ICPLB_DATA11 0xFFE0122C /* Instruction Cache 11 Status */
+#define ICPLB_DATA12 0xFFE01230 /* Instruction Cache 12 Status */
+#define ICPLB_DATA13 0xFFE01234 /* Instruction Cache 13 Status */
+#define ICPLB_DATA14 0xFFE01238 /* Instruction Cache 14 Status */
+#define ICPLB_DATA15 0xFFE0123C /* Instruction Cache 15 Status */
+#define ITEST_COMMAND 0xFFE01300 /* Instruction Test Command Register */
+#define ITEST_DATA0 0xFFE01400 /* Instruction Test Data Register */
+#define ITEST_DATA1 0xFFE01404 /* Instruction Test Data Register */
+
+/* Event/Interrupt Controller Registers (0xFFE02000 - 0xFFE02110) */
+
+#define EVT0 0xFFE02000 /* Event Vector 0 ESR Address */
+#define EVT1 0xFFE02004 /* Event Vector 1 ESR Address */
+#define EVT2 0xFFE02008 /* Event Vector 2 ESR Address */
+#define EVT3 0xFFE0200C /* Event Vector 3 ESR Address */
+#define EVT4 0xFFE02010 /* Event Vector 4 ESR Address */
+#define EVT5 0xFFE02014 /* Event Vector 5 ESR Address */
+#define EVT6 0xFFE02018 /* Event Vector 6 ESR Address */
+#define EVT7 0xFFE0201C /* Event Vector 7 ESR Address */
+#define EVT8 0xFFE02020 /* Event Vector 8 ESR Address */
+#define EVT9 0xFFE02024 /* Event Vector 9 ESR Address */
+#define EVT10 0xFFE02028 /* Event Vector 10 ESR Address */
+#define EVT11 0xFFE0202C /* Event Vector 11 ESR Address */
+#define EVT12 0xFFE02030 /* Event Vector 12 ESR Address */
+#define EVT13 0xFFE02034 /* Event Vector 13 ESR Address */
+#define EVT14 0xFFE02038 /* Event Vector 14 ESR Address */
+#define EVT15 0xFFE0203C /* Event Vector 15 ESR Address */
+#define IMASK 0xFFE02104 /* Interrupt Mask Register */
+#define IPEND 0xFFE02108 /* Interrupt Pending Register */
+#define ILAT 0xFFE0210C /* Interrupt Latch Register */
+#define IPRIO 0xFFE02110 /* Core Interrupt Priority Register */
+
+/* Core Timer Registers (0xFFE03000 - 0xFFE0300C) */
+
+#define TCNTL 0xFFE03000 /* Core Timer Control Register */
+#define TPERIOD 0xFFE03004 /* Core Timer Period Register */
+#define TSCALE 0xFFE03008 /* Core Timer Scale Register */
+#define TCOUNT 0xFFE0300C /* Core Timer Count Register */
+
+/* Debug/MP/Emulation Registers (0xFFE05000 - 0xFFE05008) */
+#define DSPID 0xFFE05000 /* DSP Processor ID Register for
+ * MP implementations
+ */
+
+#define DBGSTAT 0xFFE05008 /* Debug Status Register */
+
+/* Trace Buffer Registers (0xFFE06000 - 0xFFE06100) */
+
+#define TBUFCTL 0xFFE06000 /* Trace Buffer Control Register */
+#define TBUFSTAT 0xFFE06004 /* Trace Buffer Status Register */
+#define TBUF 0xFFE06100 /* Trace Buffer */
+
+/* Watchpoint Control Registers (0xFFE07000 - 0xFFE07200) */
+
+/* Watchpoint Instruction Address Control Register */
+#define WPIACTL 0xFFE07000
+/* Watchpoint Instruction Address Register 0 */
+#define WPIA0 0xFFE07040
+/* Watchpoint Instruction Address Register 1 */
+#define WPIA1 0xFFE07044
+/* Watchpoint Instruction Address Register 2 */
+#define WPIA2 0xFFE07048
+/* Watchpoint Instruction Address Register 3 */
+#define WPIA3 0xFFE0704C
+/* Watchpoint Instruction Address Register 4 */
+#define WPIA4 0xFFE07050
+/* Watchpoint Instruction Address Register 5 */
+#define WPIA5 0xFFE07054
+/* Watchpoint Instruction Address Count Register 0 */
+#define WPIACNT0 0xFFE07080
+/* Watchpoint Instruction Address Count Register 1 */
+#define WPIACNT1 0xFFE07084
+/* Watchpoint Instruction Address Count Register 2 */
+#define WPIACNT2 0xFFE07088
+/* Watchpoint Instruction Address Count Register 3 */
+#define WPIACNT3 0xFFE0708C
+/* Watchpoint Instruction Address Count Register 4 */
+#define WPIACNT4 0xFFE07090
+/* Watchpoint Instruction Address Count Register 5 */
+#define WPIACNT5 0xFFE07094
+/* Watchpoint Data Address Control Register */
+#define WPDACTL 0xFFE07100
+/* Watchpoint Data Address Register 0 */
+#define WPDA0 0xFFE07140
+/* Watchpoint Data Address Register 1 */
+#define WPDA1 0xFFE07144
+/* Watchpoint Data Address Count Value Register 0 */
+#define WPDACNT0 0xFFE07180
+/* Watchpoint Data Address Count Value Register 1 */
+#define WPDACNT1 0xFFE07184
+/* Watchpoint Status Register */
+#define WPSTAT 0xFFE07200
+
+/* Performance Monitor Registers (0xFFE08000 - 0xFFE08104) */
+
+/* Performance Monitor Control Register */
+#define PFCTL 0xFFE08000
+/* Performance Monitor Counter Register 0 */
+#define PFCNTR0 0xFFE08100
+/* Performance Monitor Counter Register 1 */
+#define PFCNTR1 0xFFE08104
+
+/****************************************************
+ * Core MMR Register Bits
+ ****************************************************/
+
+/**************************************************
+ * EVT registers (ILAT, IMASK, and IPEND).
+ **************************************************/
+
+/* Bit Positions */
+#define EVT_EMU_P 0x00000000 /* Emulator interrupt bit position */
+#define EVT_RST_P 0x00000001 /* Reset interrupt bit position */
+#define EVT_NMI_P 0x00000002 /* Non Maskable interrupt bit position */
+#define EVT_EVX_P 0x00000003 /* Exception bit position */
+#define EVT_IRPTEN_P 0x00000004 /* Global interrupt enable bit position */
+#define EVT_IVHW_P 0x00000005 /* Hardware Error interrupt bit position */
+#define EVT_IVTMR_P 0x00000006 /* Timer interrupt bit position */
+#define EVT_IVG7_P 0x00000007 /* IVG7 interrupt bit position */
+#define EVT_IVG8_P 0x00000008 /* IVG8 interrupt bit position */
+#define EVT_IVG9_P 0x00000009 /* IVG9 interrupt bit position */
+#define EVT_IVG10_P 0x0000000a /* IVG10 interrupt bit position */
+#define EVT_IVG11_P 0x0000000b /* IVG11 interrupt bit position */
+#define EVT_IVG12_P 0x0000000c /* IVG12 interrupt bit position */
+#define EVT_IVG13_P 0x0000000d /* IVG13 interrupt bit position */
+#define EVT_IVG14_P 0x0000000e /* IVG14 interrupt bit position */
+#define EVT_IVG15_P 0x0000000f /* IVG15 interrupt bit position */
+
+/* Masks */
+#define EVT_EMU MK_BMSK_(EVT_EMU_P ) /* Emulator interrupt mask */
+#define EVT_RST MK_BMSK_(EVT_RST_P ) /* Reset interrupt mask */
+#define EVT_NMI MK_BMSK_(EVT_NMI_P ) /* Non Maskable interrupt mask */
+#define EVT_EVX MK_BMSK_(EVT_EVX_P ) /* Exception mask */
+#define EVT_IRPTEN MK_BMSK_(EVT_IRPTEN_P) /* Global interrupt enable mask */
+#define EVT_IVHW MK_BMSK_(EVT_IVHW_P ) /* Hardware Error interrupt mask */
+#define EVT_IVTMR MK_BMSK_(EVT_IVTMR_P ) /* Timer interrupt mask */
+#define EVT_IVG7 MK_BMSK_(EVT_IVG7_P ) /* IVG7 interrupt mask */
+#define EVT_IVG8 MK_BMSK_(EVT_IVG8_P ) /* IVG8 interrupt mask */
+#define EVT_IVG9 MK_BMSK_(EVT_IVG9_P ) /* IVG9 interrupt mask */
+#define EVT_IVG10 MK_BMSK_(EVT_IVG10_P ) /* IVG10 interrupt mask */
+#define EVT_IVG11 MK_BMSK_(EVT_IVG11_P ) /* IVG11 interrupt mask */
+#define EVT_IVG12 MK_BMSK_(EVT_IVG12_P ) /* IVG12 interrupt mask */
+#define EVT_IVG13 MK_BMSK_(EVT_IVG13_P ) /* IVG13 interrupt mask */
+#define EVT_IVG14 MK_BMSK_(EVT_IVG14_P ) /* IVG14 interrupt mask */
+#define EVT_IVG15 MK_BMSK_(EVT_IVG15_P ) /* IVG15 interrupt mask */
+
+/**************************************************
+ * DMEM_CONTROL Register
+ **************************************************/
+/* Bit Positions */
+#define ENDM_P 0x00 /* (doesn't really exist) Enable
+ *Data Memory L1
+ */
+#define DMCTL_ENDM_P ENDM_P /* "" (older define) */
+
+#define ENDCPLB_P 0x01 /* Enable DCPLBS */
+#define DMCTL_ENDCPLB_P ENDCPLB_P /* "" (older define) */
+#define DMC0_P 0x02 /* L1 Data Memory Configure bit 0 */
+#define DMCTL_DMC0_P DMC0_P /* "" (older define) */
+#define DMC1_P 0x03 /* L1 Data Memory Configure bit 1 */
+#define DMCTL_DMC1_P DMC1_P /* "" (older define) */
+#define DCBS_P 0x04 /* L1 Data Cache Bank Select */
+#define PORT_PREF0_P 0x12 /* DAG0 Port Preference */
+#define PORT_PREF1_P 0x13 /* DAG1 Port Preference */
+
+/* Masks */
+#define ENDM 0x00000001 /* (doesn't really exist) Enable
+ * Data Memory L1
+ */
+#define ENDCPLB 0x00000002 /* Enable DCPLB */
+#define ASRAM_BSRAM 0x00000000
+#define ACACHE_BSRAM 0x00000008
+#define ACACHE_BCACHE 0x0000000C
+#define DCBS 0x00000010 /* L1 Data Cache Bank Select */
+#define PORT_PREF0 0x00001000 /* DAG0 Port Preference */
+#define PORT_PREF1 0x00002000 /* DAG1 Port Preference */
+
+/* IMEM_CONTROL Register */
+/* Bit Positions */
+#define ENIM_P 0x00 /* Enable L1 Code Memory */
+#define IMCTL_ENIM_P 0x00 /* "" (older define) */
+#define ENICPLB_P 0x01 /* Enable ICPLB */
+#define IMCTL_ENICPLB_P 0x01 /* "" (older define) */
+#define IMC_P 0x02 /* Enable */
+#define IMCTL_IMC_P 0x02 /* Configure L1 code memory as
+ * cache (0=SRAM)
+ */
+#define ILOC0_P 0x03 /* Lock Way 0 */
+#define ILOC1_P 0x04 /* Lock Way 1 */
+#define ILOC2_P 0x05 /* Lock Way 2 */
+#define ILOC3_P 0x06 /* Lock Way 3 */
+#define LRUPRIORST_P 0x0D /* Least Recently Used Replacement
+ * Priority
+ */
+/* Masks */
+#define ENIM 0x00000001 /* Enable L1 Code Memory */
+#define ENICPLB 0x00000002 /* Enable ICPLB */
+#define IMC 0x00000004 /* Configure L1 code memory as
+ * cache (0=SRAM)
+ */
+#define ILOC0 0x00000008 /* Lock Way 0 */
+#define ILOC1 0x00000010 /* Lock Way 1 */
+#define ILOC2 0x00000020 /* Lock Way 2 */
+#define ILOC3 0x00000040 /* Lock Way 3 */
+#define LRUPRIORST 0x00002000 /* Least Recently Used Replacement
+ * Priority
+ */
+
+/* TCNTL Masks */
+#define TMPWR 0x00000001 /* Timer Low Power Control,
+ * 0=low power mode, 1=active state
+ */
+#define TMREN 0x00000002 /* Timer enable, 0=disable, 1=enable */
+#define TAUTORLD 0x00000004 /* Timer auto reload */
+#define TINT 0x00000008 /* Timer generated interrupt 0=no
+ * interrupt has been generated,
+ * 1=interrupt has been generated
+ * (sticky)
+ */
+
+/* DCPLB_DATA and ICPLB_DATA Registers */
+/* Bit Positions */
+#define CPLB_VALID_P 0x00000000 /* 0=invalid entry, 1=valid entry */
+#define CPLB_LOCK_P 0x00000001 /* 0=entry may be replaced, 1=entry
+ * locked
+ */
+#define CPLB_USER_RD_P 0x00000002 /* 0=no read access, 1=read access
+ * allowed (user mode)
+ */
+/* Masks */
+#define CPLB_VALID 0x00000001 /* 0=invalid entry, 1=valid entry */
+#define CPLB_LOCK 0x00000002 /* 0=entry may be replaced, 1=entry
+ * locked
+ */
+#define CPLB_USER_RD 0x00000004 /* 0=no read access, 1=read access
+ * allowed (user mode)
+ */
+#define PAGE_SIZE_1KB 0x00000000 /* 1 KB page size */
+#define PAGE_SIZE_4KB 0x00010000 /* 4 KB page size */
+#define PAGE_SIZE_1MB 0x00020000 /* 1 MB page size */
+#define PAGE_SIZE_4MB 0x00030000 /* 4 MB page size */
+#define CPLB_L1SRAM 0x00000020 /* 0=SRAM mapped in L1, 0=SRAM not
+ * mapped to L1
+ */
+#define CPLB_PORTPRIO 0x00000200 /* 0=low priority port, 1= high
+ * priority port
+ */
+#define CPLB_L1_CHBL 0x00001000 /* 0=non-cacheable in L1, 1=cacheable
+ * in L1
+ */
+/* ICPLB_DATA only */
+#define CPLB_LRUPRIO 0x00000100 /* 0=can be replaced by any line,
+ * 1=priority for non-replacement
+ */
+/* DCPLB_DATA only */
+#define CPLB_USER_WR 0x00000008 /* 0=no write access, 0=write
+ * access allowed (user mode)
+ */
+#define CPLB_SUPV_WR 0x00000010 /* 0=no write access, 0=write
+ * access allowed (supervisor mode)
+ */
+#define CPLB_DIRTY 0x00000080 /* 1=dirty, 0=clean */
+#define CPLB_L1_AOW 0x00008000 /* 0=do not allocate cache lines on
+ * write-through writes,
+ * 1= allocate cache lines on
+ * write-through writes.
+ */
+#define CPLB_WT 0x00004000 /* 0=write-back, 1=write-through */
+
+/* TBUFCTL Masks */
+#define TBUFPWR 0x0001
+#define TBUFEN 0x0002
+#define TBUFOVF 0x0004
+#define TBUFCMPLP_SINGLE 0x0008
+#define TBUFCMPLP_DOUBLE 0x0010
+#define TBUFCMPLP (TBUFCMPLP_SINGLE | TBUFCMPLP_DOUBLE)
+
+/* TBUFSTAT Masks */
+#define TBUFCNT 0x001F
+
+/* ITEST_COMMAND and DTEST_COMMAND Registers */
+/* Masks */
+#define TEST_READ 0x00000000 /* Read Access */
+#define TEST_WRITE 0x00000002 /* Write Access */
+#define TEST_TAG 0x00000000 /* Access TAG */
+#define TEST_DATA 0x00000004 /* Access DATA */
+#define TEST_DW0 0x00000000 /* Select Double Word 0 */
+#define TEST_DW1 0x00000008 /* Select Double Word 1 */
+#define TEST_DW2 0x00000010 /* Select Double Word 2 */
+#define TEST_DW3 0x00000018 /* Select Double Word 3 */
+#define TEST_MB0 0x00000000 /* Select Mini-Bank 0 */
+#define TEST_MB1 0x00010000 /* Select Mini-Bank 1 */
+#define TEST_MB2 0x00020000 /* Select Mini-Bank 2 */
+#define TEST_MB3 0x00030000 /* Select Mini-Bank 3 */
+#define TEST_SET(x) ((x << 5) & 0x03E0) /* Set Index 0->31 */
+#define TEST_WAY0 0x00000000 /* Access Way0 */
+#define TEST_WAY1 0x04000000 /* Access Way1 */
+/* ITEST_COMMAND only */
+#define TEST_WAY2 0x08000000 /* Access Way2 */
+#define TEST_WAY3 0x0C000000 /* Access Way3 */
+/* DTEST_COMMAND only */
+#define TEST_BNKSELA 0x00000000 /* Access SuperBank A */
+#define TEST_BNKSELB 0x00800000 /* Access SuperBank B */
+
+#endif /* _DEF_LPBLACKFIN_H */
diff --git a/include/asm-blackfin/macros.h b/include/asm-blackfin/macros.h
new file mode 100644
index 00000000000..c0c04a2f2dd
--- /dev/null
+++ b/include/asm-blackfin/macros.h
@@ -0,0 +1,95 @@
+/************************************************************************
+ *
+ * macros.h
+ *
+ * (c) Copyright 2001-2003 Analog Devices, Inc. All rights reserved.
+ *
+ ************************************************************************/
+
+/* Defines various assembly macros. */
+
+#ifndef _MACROS_H
+#define _MACROS_H
+
+#define LO(con32) ((con32) & 0xFFFF)
+#define lo(con32) ((con32) & 0xFFFF)
+#define HI(con32) (((con32) >> 16) & 0xFFFF)
+#define hi(con32) (((con32) >> 16) & 0xFFFF)
+
+/*
+ * Set the corresponding bits in a System Register (SR);
+ * All bits set in "mask" will be set in the system register
+ * specified by "sys_reg" bitset_SR(sys_reg, mask), where
+ * sys_reg is the system register and mask are the bits to be set.
+ */
+#define bitset_SR(sys_reg, mask)\
+ [--SP] = (R7:6);\
+ r7 = sys_reg;\
+ r6.l = (mask) & 0xffff;\
+ r6.h = (mask) >> 16;\
+ r7 = r7 | r6;\
+ sys_reg = r7;\
+ csync;\
+ (R7:6) = [SP++]
+
+/*
+ * Clear the corresponding bits in a System Register (SR);
+ * All bits set in "mask" will be cleared in the SR
+ * specified by "sys_reg" bitclr_SR(sys_reg, mask), where
+ * sys_reg is the SR and mask are the bits to be cleared.
+ */
+#define bitclr_SR(sys_reg, mask)\
+ [--SP] = (R7:6);\
+ r7 = sys_reg;\
+ r7 =~ r7;\
+ r6.l = (mask) & 0xffff;\
+ r6.h = (mask) >> 16;\
+ r7 = r7 | r6;\
+ r7 =~ r7;\
+ sys_reg = r7;\
+ csync;\
+ (R7:6) = [SP++]
+
+/*
+ * Set the corresponding bits in a Memory Mapped Register (MMR);
+ * All bits set in "mask" will be set in the MMR specified by "mmr_reg"
+ * bitset_MMR(mmr_reg, mask), where mmr_reg is the MMR and mask are
+ * the bits to be set.
+ */
+#define bitset_MMR(mmr_reg, mask)\
+ [--SP] = (R7:6);\
+ [--SP] = P5;\
+ p5.l = mmr_reg & 0xffff;\
+ p5.h = mmr_reg >> 16;\
+ r7 = [p5];\
+ r6.l = (mask) & 0xffff;\
+ r6.h = (mask) >> 16;\
+ r7 = r7 | r6;\
+ [p5] = r7;\
+ csync;\
+ p5 = [SP++];\
+ (R7:6) = [SP++]
+
+/*
+ * Clear the corresponding bits in a Memory Mapped Register (MMR);
+ * All bits set in "mask" will be cleared in the MMR specified by "mmr_reg"
+ * bitclr_MMRreg(mmr_reg, mask), where sys_reg is the MMR and mask are
+ * the bits to be cleared.
+ */
+#define bitclr_MMR(mmr_reg, mask)\
+ [--SP] = (R7:6);\
+ [--SP] = P5;\
+ p5.l = mmr_reg & 0xffff;\
+ p5.h = mmr_reg >> 16;\
+ r7 = [p5];\
+ r7 =~ r7;\
+ r6.l = (mask) & 0xffff;\
+ r6.h = (mask) >> 16;\
+ r7 = r7 | r6;\
+ r7 =~ r7;\
+ [p5] = r7;\
+ csync;\
+ p5 = [SP++];\
+ (R7:6) = [SP++]
+
+#endif /* _MACROS_H */
diff --git a/include/asm-blackfin/mem_map.h b/include/asm-blackfin/mem_map.h
new file mode 100644
index 00000000000..42d1f37f6d9
--- /dev/null
+++ b/include/asm-blackfin/mem_map.h
@@ -0,0 +1,12 @@
+/*
+ * mem_map.h
+ * Common header file for blackfin family of processors.
+ *
+ */
+
+#ifndef _MEM_MAP_H_
+#define _MEM_MAP_H_
+
+#include <asm/mach/mem_map.h>
+
+#endif /* _MEM_MAP_H_ */
diff --git a/include/asm-blackfin/mman.h b/include/asm-blackfin/mman.h
new file mode 100644
index 00000000000..4d504f908c0
--- /dev/null
+++ b/include/asm-blackfin/mman.h
@@ -0,0 +1,45 @@
+#ifndef __BFIN_MMAN_H__
+#define __BFIN_MMAN_H__
+
+#define PROT_READ 0x1 /* page can be read */
+#define PROT_WRITE 0x2 /* page can be written */
+#define PROT_EXEC 0x4 /* page can be executed */
+#define PROT_SEM 0x8 /* page may be used for atomic ops */
+#define PROT_NONE 0x0 /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
+
+#define MAP_SHARED 0x01 /* Share changes */
+#define MAP_PRIVATE 0x02 /* Changes are private */
+#define MAP_TYPE 0x0f /* Mask for type of mapping */
+#define MAP_FIXED 0x10 /* Interpret addr exactly */
+#define MAP_ANONYMOUS 0x20 /* don't use a file */
+
+#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
+#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
+#define MAP_LOCKED 0x2000 /* pages are locked */
+#define MAP_NORESERVE 0x4000 /* don't check for reservations */
+#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x10000 /* do not block on IO */
+#define MAP_UNINITIALIZE 0x4000000 /* For anonymous mmap, memory could
+ be uninitialized. */
+
+#define MS_ASYNC 1 /* sync memory asynchronously */
+#define MS_INVALIDATE 2 /* invalidate the caches */
+#define MS_SYNC 4 /* synchronous memory sync */
+
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+
+#define MADV_NORMAL 0x0 /* default page-in behavior */
+#define MADV_RANDOM 0x1 /* page-in minimum required */
+#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */
+#define MADV_WILLNEED 0x3 /* pre-fault pages */
+#define MADV_DONTNEED 0x4 /* discard these pages */
+
+/* compatibility flags */
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FILE 0
+
+#endif /* __BFIN_MMAN_H__ */
diff --git a/include/asm-blackfin/mmu.h b/include/asm-blackfin/mmu.h
new file mode 100644
index 00000000000..11d52f1167d
--- /dev/null
+++ b/include/asm-blackfin/mmu.h
@@ -0,0 +1,30 @@
+#ifndef __MMU_H
+#define __MMU_H
+
+/* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
+
+struct sram_list_struct {
+ struct sram_list_struct *next;
+ void *addr;
+ size_t length;
+};
+
+typedef struct {
+ struct vm_list_struct *vmlist;
+ unsigned long end_brk;
+ unsigned long stack_start;
+
+ /* Points to the location in SDRAM where the L1 stack is normally
+ saved, or NULL if the stack is always in SDRAM. */
+ void *l1_stack_save;
+
+ struct sram_list_struct *sram_list;
+
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+ unsigned long exec_fdpic_loadmap;
+ unsigned long interp_fdpic_loadmap;
+#endif
+
+} mm_context_t;
+
+#endif
diff --git a/include/asm-blackfin/mmu_context.h b/include/asm-blackfin/mmu_context.h
new file mode 100644
index 00000000000..c5c71a6aaf1
--- /dev/null
+++ b/include/asm-blackfin/mmu_context.h
@@ -0,0 +1,129 @@
+/*
+ * File: include/asm-blackfin/mmu_context.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __BLACKFIN_MMU_CONTEXT_H__
+#define __BLACKFIN_MMU_CONTEXT_H__
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+
+extern void *current_l1_stack_save;
+extern int nr_l1stack_tasks;
+extern void *l1_stack_base;
+extern unsigned long l1_stack_len;
+
+extern int l1sram_free(const void*);
+extern void *l1sram_alloc_max(void*);
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/* Called when creating a new context during fork() or execve(). */
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ return 0;
+}
+
+static inline void free_l1stack(void)
+{
+ nr_l1stack_tasks--;
+ if (nr_l1stack_tasks == 0)
+ l1sram_free(l1_stack_base);
+}
+static inline void destroy_context(struct mm_struct *mm)
+{
+ struct sram_list_struct *tmp;
+
+ if (current_l1_stack_save == mm->context.l1_stack_save)
+ current_l1_stack_save = 0;
+ if (mm->context.l1_stack_save)
+ free_l1stack();
+
+ while ((tmp = mm->context.sram_list)) {
+ mm->context.sram_list = tmp->next;
+ sram_free(tmp->addr);
+ kfree(tmp);
+ }
+}
+
+static inline unsigned long
+alloc_l1stack(unsigned long length, unsigned long *stack_base)
+{
+ if (nr_l1stack_tasks == 0) {
+ l1_stack_base = l1sram_alloc_max(&l1_stack_len);
+ if (!l1_stack_base)
+ return 0;
+ }
+
+ if (l1_stack_len < length) {
+ if (nr_l1stack_tasks == 0)
+ l1sram_free(l1_stack_base);
+ return 0;
+ }
+ *stack_base = (unsigned long)l1_stack_base;
+ nr_l1stack_tasks++;
+ return l1_stack_len;
+}
+
+static inline int
+activate_l1stack(struct mm_struct *mm, unsigned long sp_base)
+{
+ if (current_l1_stack_save)
+ memcpy(current_l1_stack_save, l1_stack_base, l1_stack_len);
+ mm->context.l1_stack_save = current_l1_stack_save = (void*)sp_base;
+ memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+ return 1;
+}
+
+#define deactivate_mm(tsk,mm) do { } while (0)
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+ struct mm_struct *next_mm)
+{
+ if (!next_mm->context.l1_stack_save)
+ return;
+ if (next_mm->context.l1_stack_save == current_l1_stack_save)
+ return;
+ if (current_l1_stack_save) {
+ memcpy(current_l1_stack_save, l1_stack_base, l1_stack_len);
+ }
+ current_l1_stack_save = next_mm->context.l1_stack_save;
+ memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+ activate_mm(prev, next);
+}
+
+#endif
diff --git a/include/asm-blackfin/module.h b/include/asm-blackfin/module.h
new file mode 100644
index 00000000000..3c7ce164428
--- /dev/null
+++ b/include/asm-blackfin/module.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_BFIN_MODULE_H
+#define _ASM_BFIN_MODULE_H
+
+#define MODULE_SYMBOL_PREFIX "_"
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+#define FLG_CODE_IN_L1 0x10
+#define FLG_DATA_IN_L1 0x20
+
+struct mod_arch_specific {
+ Elf_Shdr *text_l1;
+ Elf_Shdr *data_a_l1;
+ Elf_Shdr *bss_a_l1;
+ Elf_Shdr *data_b_l1;
+ Elf_Shdr *bss_b_l1;
+};
+#endif /* _ASM_BFIN_MODULE_H */
diff --git a/include/asm-blackfin/msgbuf.h b/include/asm-blackfin/msgbuf.h
new file mode 100644
index 00000000000..6fcbe8cd801
--- /dev/null
+++ b/include/asm-blackfin/msgbuf.h
@@ -0,0 +1,31 @@
+#ifndef _BFIN_MSGBUF_H
+#define _BFIN_MSGBUF_H
+
+/*
+ * The msqid64_ds structure for bfin architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+ __kernel_time_t msg_stime; /* last msgsnd time */
+ unsigned long __unused1;
+ __kernel_time_t msg_rtime; /* last msgrcv time */
+ unsigned long __unused2;
+ __kernel_time_t msg_ctime; /* last change time */
+ unsigned long __unused3;
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#endif /* _BFIN_MSGBUF_H */
diff --git a/include/asm-blackfin/mutex.h b/include/asm-blackfin/mutex.h
new file mode 100644
index 00000000000..458c1f7fbc1
--- /dev/null
+++ b/include/asm-blackfin/mutex.h
@@ -0,0 +1,9 @@
+/*
+ * Pull in the generic implementation for the mutex fastpath.
+ *
+ * TODO: implement optimized primitives instead, or leave the generic
+ * implementation in place, or pick the atomic_xchg() based generic
+ * implementation. (see asm-generic/mutex-xchg.h for details)
+ */
+
+#include <asm-generic/mutex-dec.h>
diff --git a/include/asm-blackfin/namei.h b/include/asm-blackfin/namei.h
new file mode 100644
index 00000000000..8b89a2d65cb
--- /dev/null
+++ b/include/asm-blackfin/namei.h
@@ -0,0 +1,19 @@
+/*
+ * linux/include/asm/namei.h
+ *
+ * Included from linux/fs/namei.c
+ *
+ * Changes made by Lineo Inc. May 2001
+ */
+
+#ifndef __BFIN_NAMEI_H
+#define __BFIN_NAMEI_H
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif
diff --git a/include/asm-blackfin/page.h b/include/asm-blackfin/page.h
new file mode 100644
index 00000000000..ffad947f1b2
--- /dev/null
+++ b/include/asm-blackfin/page.h
@@ -0,0 +1,89 @@
+#ifndef _BLACKFIN_PAGE_H
+#define _BLACKFIN_PAGE_H
+
+/* PAGE_SHIFT determines the page size */
+
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+
+#include <asm/setup.h>
+
+#ifndef __ASSEMBLY__
+
+#define get_user_page(vaddr) __get_free_page(GFP_KERNEL)
+#define free_user_page(page, addr) free_page(addr)
+
+#define clear_page(page) memset((page), 0, PAGE_SIZE)
+#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE)
+
+#define clear_user_page(page, vaddr,pg) clear_page(page)
+#define copy_user_page(to, from, vaddr,pg) copy_page(to, from)
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct {
+ unsigned long pte;
+} pte_t;
+typedef struct {
+ unsigned long pmd[16];
+} pmd_t;
+typedef struct {
+ unsigned long pgd;
+} pgd_t;
+typedef struct {
+ unsigned long pgprot;
+} pgprot_t;
+
+#define pte_val(x) ((x).pte)
+#define pmd_val(x) ((&x)->pmd[0])
+#define pgd_val(x) ((x).pgd)
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+
+#endif /* !__ASSEMBLY__ */
+
+#include <asm/page_offset.h>
+#include <asm/io.h>
+
+#define PAGE_OFFSET (PAGE_OFFSET_RAW)
+
+#ifndef __ASSEMBLY__
+
+#define __pa(vaddr) virt_to_phys((void *)(vaddr))
+#define __va(paddr) phys_to_virt((unsigned long)(paddr))
+
+#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
+
+#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
+#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT)
+#define virt_to_page(addr) (mem_map + (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT))
+#define page_to_virt(page) ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
+#define VALID_PAGE(page) ((page - mem_map) < max_mapnr)
+
+#define pfn_to_page(pfn) virt_to_page(pfn_to_virt(pfn))
+#define page_to_pfn(page) virt_to_pfn(page_to_virt(page))
+#define pfn_valid(pfn) ((pfn) < max_mapnr)
+
+#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \
+ ((void *)(kaddr) < (void *)memory_end))
+
+#include <asm-generic/page.h>
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+
+#endif /* _BLACKFIN_PAGE_H */
diff --git a/include/asm-blackfin/page_offset.h b/include/asm-blackfin/page_offset.h
new file mode 100644
index 00000000000..3b671d5fd70
--- /dev/null
+++ b/include/asm-blackfin/page_offset.h
@@ -0,0 +1,6 @@
+
+/* This handles the memory map.. */
+
+#ifdef CONFIG_BFIN
+#define PAGE_OFFSET_RAW 0x00000000
+#endif
diff --git a/include/asm-blackfin/param.h b/include/asm-blackfin/param.h
new file mode 100644
index 00000000000..41564a6347f
--- /dev/null
+++ b/include/asm-blackfin/param.h
@@ -0,0 +1,22 @@
+#ifndef _BLACKFIN_PARAM_H
+#define _BLACKFIN_PARAM_H
+
+#ifdef __KERNEL__
+#define HZ CONFIG_HZ
+#define USER_HZ 100
+#define CLOCKS_PER_SEC (USER_HZ)
+#endif
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE 4096
+
+#ifndef NOGROUP
+#define NOGROUP (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64 /* max length of hostname */
+
+#endif /* _BLACKFIN_PARAM_H */
diff --git a/include/asm-blackfin/pci.h b/include/asm-blackfin/pci.h
new file mode 100644
index 00000000000..61277358c86
--- /dev/null
+++ b/include/asm-blackfin/pci.h
@@ -0,0 +1,148 @@
+/* Changed from asm-m68k version, Lineo Inc. May 2001 */
+
+#ifndef _ASM_BFIN_PCI_H
+#define _ASM_BFIN_PCI_H
+
+#include <asm/scatterlist.h>
+
+/*
+ *
+ * Written by Wout Klaren.
+ */
+
+/* Added by Chang Junxiao */
+#define PCIBIOS_MIN_IO 0x00001000
+#define PCIBIOS_MIN_MEM 0x10000000
+
+#define PCI_DMA_BUS_IS_PHYS (1)
+struct pci_ops;
+
+/*
+ * Structure with hardware dependent information and functions of the
+ * PCI bus.
+ */
+struct pci_bus_info {
+
+ /*
+ * Resources of the PCI bus.
+ */
+ struct resource mem_space;
+ struct resource io_space;
+
+ /*
+ * System dependent functions.
+ */
+ struct pci_ops *bfin_pci_ops;
+ void (*fixup) (int pci_modify);
+ void (*conf_device) (unsigned char bus, unsigned char device_fn);
+};
+
+#define pcibios_assign_all_busses() 0
+static inline void pcibios_set_master(struct pci_dev *dev)
+{
+
+ /* No special bus mastering setup handling */
+}
+static inline void pcibios_penalize_isa_irq(int irq)
+{
+
+ /* We don't do dynamic PCI IRQ allocation */
+}
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+ size_t size, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
+ /* return virt_to_bus(ptr); */
+ return (dma_addr_t) ptr;
+}
+
+/* Unmap a single streaming mode DMA translation. The dma_addr and size
+ * must match what was provided for in a previous pci_map_single call. All
+ * other usages are undefined.
+ *
+ * After this call, reads by the cpu to the buffer are guarenteed to see
+ * whatever the device wrote there.
+ */
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+ size_t size, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
+ /* Nothing to do */
+}
+
+/* Map a set of buffers described by scatterlist in streaming
+ * mode for DMA. This is the scather-gather version of the
+ * above pci_map_single interface. Here the scatter gather list
+ * elements are each tagged with the appropriate dma address
+ * and length. They are obtained via sg_dma_{address,length}(SG).
+ *
+ * NOTE: An implementation may be able to use a smaller number of
+ * DMA address/length pairs than there are SG table elements.
+ * (for example via virtual mapping capabilities)
+ * The routine returns the number of addr/length pairs actually
+ * used, at most nents.
+ *
+ * Device ownership issues as mentioned above for pci_map_single are
+ * the same here.
+ */
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+ int nents, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+ return nents;
+}
+
+/* Unmap a set of streaming mode DMA translations.
+ * Again, cpu read rules concerning calls here are the same as for
+ * pci_unmap_single() above.
+ */
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+ int nents, int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
+ /* Nothing to do */
+}
+
+/* Make physical memory consistent for a single
+ * streaming mode DMA translation after a transfer.
+ *
+ * If you perform a pci_map_single() but wish to interrogate the
+ * buffer using the cpu, yet do not wish to teardown the PCI dma
+ * mapping, you must call this function before doing so. At the
+ * next point you give the PCI dma address back to the card, the
+ * device again owns the buffer.
+ */
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
+ dma_addr_t dma_handle, size_t size,
+ int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
+ /* Nothing to do */
+}
+
+/* Make physical memory consistent for a set of streaming
+ * mode DMA translations after a transfer.
+ *
+ * The same as pci_dma_sync_single but for a scatter-gather list,
+ * same rules and usage.
+ */
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+ struct scatterlist *sg, int nelems,
+ int direction)
+{
+ if (direction == PCI_DMA_NONE)
+ BUG();
+
+ /* Nothing to do */
+}
+
+#endif /* _ASM_BFIN_PCI_H */
diff --git a/include/asm-blackfin/percpu.h b/include/asm-blackfin/percpu.h
new file mode 100644
index 00000000000..78dd61f6b39
--- /dev/null
+++ b/include/asm-blackfin/percpu.h
@@ -0,0 +1,6 @@
+#ifndef __ARCH_BLACKFIN_PERCPU__
+#define __ARCH_BLACKFIN_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_BLACKFIN_PERCPU__ */
diff --git a/include/asm-blackfin/pgalloc.h b/include/asm-blackfin/pgalloc.h
new file mode 100644
index 00000000000..c686e0542fd
--- /dev/null
+++ b/include/asm-blackfin/pgalloc.h
@@ -0,0 +1,8 @@
+#ifndef _BLACKFIN_PGALLOC_H
+#define _BLACKFIN_PGALLOC_H
+
+#include <asm/setup.h>
+
+#define check_pgt_cache() do { } while (0)
+
+#endif /* _BLACKFIN_PGALLOC_H */
diff --git a/include/asm-blackfin/pgtable.h b/include/asm-blackfin/pgtable.h
new file mode 100644
index 00000000000..5a8f9e431c4
--- /dev/null
+++ b/include/asm-blackfin/pgtable.h
@@ -0,0 +1,96 @@
+#ifndef _BLACKFIN_PGTABLE_H
+#define _BLACKFIN_PGTABLE_H
+
+#include <asm-generic/4level-fixup.h>
+
+#include <asm/page.h>
+#include <asm/cplb.h>
+
+typedef pte_t *pte_addr_t;
+/*
+* Trivial page table functions.
+*/
+#define pgd_present(pgd) (1)
+#define pgd_none(pgd) (0)
+#define pgd_bad(pgd) (0)
+#define pgd_clear(pgdp)
+#define kern_addr_valid(addr) (1)
+
+#define pmd_offset(a, b) ((void *)0)
+#define pmd_none(x) (!pmd_val(x))
+#define pmd_present(x) (pmd_val(x))
+#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
+#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK)
+
+#define kern_addr_valid(addr) (1)
+
+#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */
+#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */
+
+extern void paging_init(void);
+
+#define __swp_type(x) (0)
+#define __swp_offset(x) (0)
+#define __swp_entry(typ,off) ((swp_entry_t) { ((typ) | ((off) << 7)) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
+
+static inline int pte_file(pte_t pte)
+{
+ return 0;
+}
+
+#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
+
+/*
+ * Page assess control based on Blackfin CPLB management
+ */
+#define _PAGE_RD (CPLB_USER_RD)
+#define _PAGE_WR (CPLB_USER_WR)
+#define _PAGE_USER (CPLB_USER_RD | CPLB_USER_WR)
+#define _PAGE_ACCESSED CPLB_ALL_ACCESS
+#define _PAGE_DIRTY (CPLB_DIRTY)
+
+#define PTE_BIT_FUNC(fn, op) \
+ static inline pte_t pte_##fn(pte_t _pte) { _pte.pte op; return _pte; }
+
+PTE_BIT_FUNC(rdprotect, &= ~_PAGE_RD);
+PTE_BIT_FUNC(mkread, |= _PAGE_RD);
+PTE_BIT_FUNC(wrprotect, &= ~_PAGE_WR);
+PTE_BIT_FUNC(mkwrite, |= _PAGE_WR);
+PTE_BIT_FUNC(exprotect, &= ~_PAGE_USER);
+PTE_BIT_FUNC(mkexec, |= _PAGE_USER);
+PTE_BIT_FUNC(mkclean, &= ~_PAGE_DIRTY);
+PTE_BIT_FUNC(mkdirty, |= _PAGE_DIRTY);
+PTE_BIT_FUNC(mkold, &= ~_PAGE_ACCESSED);
+PTE_BIT_FUNC(mkyoung, |= _PAGE_ACCESSED);
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+#define ZERO_PAGE(vaddr) (virt_to_page(0))
+
+extern unsigned int kobjsize(const void *objp);
+
+#define swapper_pg_dir ((pgd_t *) 0)
+/*
+ * No page table caches to initialise.
+ */
+#define pgtable_cache_init() do { } while (0)
+#define io_remap_pfn_range remap_pfn_range
+
+/*
+ * All 32bit addresses are effectively valid for vmalloc...
+ * Sort of meaningless for non-VM targets.
+ */
+#define VMALLOC_START 0
+#define VMALLOC_END 0xffffffff
+
+#include <asm-generic/pgtable.h>
+
+#endif /* _BLACKFIN_PGTABLE_H */
diff --git a/include/asm-blackfin/poll.h b/include/asm-blackfin/poll.h
new file mode 100644
index 00000000000..94cc2636e0e
--- /dev/null
+++ b/include/asm-blackfin/poll.h
@@ -0,0 +1,24 @@
+#ifndef __BFIN_POLL_H
+#define __BFIN_POLL_H
+
+#define POLLIN 1
+#define POLLPRI 2
+#define POLLOUT 4
+#define POLLERR 8
+#define POLLHUP 16
+#define POLLNVAL 32
+#define POLLRDNORM 64
+#define POLLWRNORM POLLOUT
+#define POLLRDBAND 128
+#define POLLWRBAND 256
+#define POLLMSG 0x0400
+#define POLLREMOVE 0x1000
+#define POLLRDHUP 0x2000
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+#endif /* __BFIN_POLL_H */
diff --git a/include/asm-blackfin/posix_types.h b/include/asm-blackfin/posix_types.h
new file mode 100644
index 00000000000..c3fa50fa50b
--- /dev/null
+++ b/include/asm-blackfin/posix_types.h
@@ -0,0 +1,65 @@
+#ifndef __ARCH_BFIN_POSIX_TYPES_H
+#define __ARCH_BFIN_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc. Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned long __kernel_ino_t;
+typedef unsigned short __kernel_mode_t;
+typedef unsigned short __kernel_nlink_t;
+typedef long __kernel_off_t;
+typedef int __kernel_pid_t;
+typedef unsigned int __kernel_ipc_pid_t;
+typedef unsigned int __kernel_uid_t;
+typedef unsigned int __kernel_gid_t;
+typedef unsigned long __kernel_size_t;
+typedef long __kernel_ssize_t;
+typedef int __kernel_ptrdiff_t;
+typedef long __kernel_time_t;
+typedef long __kernel_suseconds_t;
+typedef long __kernel_clock_t;
+typedef int __kernel_timer_t;
+typedef int __kernel_clockid_t;
+typedef int __kernel_daddr_t;
+typedef char *__kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+typedef unsigned int __kernel_uid32_t;
+typedef unsigned int __kernel_gid32_t;
+
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
+typedef unsigned short __kernel_old_dev_t;
+
+#ifdef __GNUC__
+typedef long long __kernel_loff_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+ int val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+ int __val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef __FD_SET
+#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+
+#undef __FD_CLR
+#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+
+#undef __FD_ISSET
+#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+
+#undef __FD_ZERO
+#define __FD_ZERO(fdsetp) (memset (fdsetp, 0, sizeof(*(fd_set *)fdsetp)))
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
+#endif
diff --git a/include/asm-blackfin/processor.h b/include/asm-blackfin/processor.h
new file mode 100644
index 00000000000..0336ff132c1
--- /dev/null
+++ b/include/asm-blackfin/processor.h
@@ -0,0 +1,130 @@
+#ifndef __ASM_BFIN_PROCESSOR_H
+#define __ASM_BFIN_PROCESSOR_H
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+#include <asm/blackfin.h>
+#include <asm/segment.h>
+#include <linux/compiler.h>
+
+static inline unsigned long rdusp(void)
+{
+ unsigned long usp;
+
+ __asm__ __volatile__("%0 = usp;\n\t":"=da"(usp));
+ return usp;
+}
+
+static inline void wrusp(unsigned long usp)
+{
+ __asm__ __volatile__("usp = %0;\n\t"::"da"(usp));
+}
+
+/*
+ * User space process size: 1st byte beyond user address space.
+ */
+extern unsigned long memory_end;
+#define TASK_SIZE (memory_end)
+
+#define TASK_UNMAPPED_BASE 0
+
+struct thread_struct {
+ unsigned long ksp; /* kernel stack pointer */
+ unsigned long usp; /* user stack pointer */
+ unsigned short seqstat; /* saved status register */
+ unsigned long esp0; /* points to SR of stack frame pt_regs */
+ unsigned long pc; /* instruction pointer */
+ void * debuggerinfo;
+};
+
+#define INIT_THREAD { \
+ sizeof(init_stack) + (unsigned long) init_stack, 0, \
+ PS_S, 0, 0 \
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ *
+ * pass the data segment into user programs if it exists,
+ * it can't hurt anything as far as I can tell
+ */
+#define start_thread(_regs, _pc, _usp) \
+do { \
+ set_fs(USER_DS); \
+ (_regs)->pc = (_pc); \
+ if (current->mm) \
+ (_regs)->p5 = current->mm->start_data; \
+ task_thread_info(current)->l1_task_info.stack_start \
+ = (void *)current->mm->context.stack_start; \
+ task_thread_info(current)->l1_task_info.lowest_sp = (void *)(_usp); \
+ memcpy(L1_SCRATCH_TASK_INFO, &task_thread_info(current)->l1_task_info, \
+ sizeof(*L1_SCRATCH_TASK_INFO)); \
+ wrusp(_usp); \
+} while(0)
+
+/* Forward declaration, a strange C thing */
+struct task_struct;
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+#define prepare_to_copy(tsk) do { } while (0)
+
+extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
+
+/*
+ * Free current thread data structures etc..
+ */
+static inline void exit_thread(void)
+{
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+#define thread_saved_pc(tsk) (tsk->thread.pc)
+
+unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk) \
+ ({ \
+ unsigned long eip = 0; \
+ if ((tsk)->thread.esp0 > PAGE_SIZE && \
+ MAP_NR((tsk)->thread.esp0) < max_mapnr) \
+ eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
+ eip; })
+#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
+
+#define cpu_relax() barrier()
+
+/* Get the Silicon Revision of the chip */
+static inline uint32_t bfin_revid(void)
+{
+ /* stored in the upper 4 bits */
+ return bfin_read_CHIPID() >> 28;
+}
+
+static inline uint32_t bfin_compiled_revid(void)
+{
+#if defined(CONFIG_BF_REV_0_0)
+ return 0;
+#elif defined(CONFIG_BF_REV_0_1)
+ return 1;
+#elif defined(CONFIG_BF_REV_0_2)
+ return 2;
+#elif defined(CONFIG_BF_REV_0_3)
+ return 3;
+#elif defined(CONFIG_BF_REV_0_4)
+ return 4;
+#elif defined(CONFIG_BF_REV_0_5)
+ return 5;
+#endif
+}
+
+#endif
diff --git a/include/asm-blackfin/ptrace.h b/include/asm-blackfin/ptrace.h
new file mode 100644
index 00000000000..b8346cd3a6f
--- /dev/null
+++ b/include/asm-blackfin/ptrace.h
@@ -0,0 +1,166 @@
+#ifndef _BFIN_PTRACE_H
+#define _BFIN_PTRACE_H
+
+/*
+ * GCC defines register number like this:
+ * -----------------------------
+ * 0 - 7 are data registers R0-R7
+ * 8 - 15 are address registers P0-P7
+ * 16 - 31 dsp registers I/B/L0 -- I/B/L3 & M0--M3
+ * 32 - 33 A registers A0 & A1
+ * 34 - status register
+ * -----------------------------
+ *
+ * We follows above, except:
+ * 32-33 --- Low 32-bit of A0&1
+ * 34-35 --- High 8-bit of A0&1
+ */
+
+#ifndef __ASSEMBLY__
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call. */
+
+struct pt_regs {
+ long orig_pc;
+ long ipend;
+ long seqstat;
+ long rete;
+ long retn;
+ long retx;
+ long pc; /* PC == RETI */
+ long rets;
+ long reserved; /* Used as scratch during system calls */
+ long astat;
+ long lb1;
+ long lb0;
+ long lt1;
+ long lt0;
+ long lc1;
+ long lc0;
+ long a1w;
+ long a1x;
+ long a0w;
+ long a0x;
+ long b3;
+ long b2;
+ long b1;
+ long b0;
+ long l3;
+ long l2;
+ long l1;
+ long l0;
+ long m3;
+ long m2;
+ long m1;
+ long m0;
+ long i3;
+ long i2;
+ long i1;
+ long i0;
+ long usp;
+ long fp;
+ long p5;
+ long p4;
+ long p3;
+ long p2;
+ long p1;
+ long p0;
+ long r7;
+ long r6;
+ long r5;
+ long r4;
+ long r3;
+ long r2;
+ long r1;
+ long r0;
+ long orig_r0;
+ long orig_p0;
+ long syscfg;
+};
+
+/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13 /* ptrace signal */
+
+#ifdef CONFIG_BINFMT_ELF_FDPIC
+#define PTRACE_GETFDPIC 31
+#define PTRACE_GETFDPIC_EXEC 0
+#define PTRACE_GETFDPIC_INTERP 1
+#endif
+
+#define PS_S (0x0002)
+
+/* user_mode returns true if only one bit is set in IPEND, other than the
+ master interrupt enable. */
+#define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+extern void show_regs(struct pt_regs *);
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Offsets used by 'ptrace' system call interface.
+ */
+
+#define PT_R0 204
+#define PT_R1 200
+#define PT_R2 196
+#define PT_R3 192
+#define PT_R4 188
+#define PT_R5 184
+#define PT_R6 180
+#define PT_R7 176
+#define PT_P0 172
+#define PT_P1 168
+#define PT_P2 164
+#define PT_P3 160
+#define PT_P4 156
+#define PT_P5 152
+#define PT_FP 148
+#define PT_USP 144
+#define PT_I0 140
+#define PT_I1 136
+#define PT_I2 132
+#define PT_I3 128
+#define PT_M0 124
+#define PT_M1 120
+#define PT_M2 116
+#define PT_M3 112
+#define PT_L0 108
+#define PT_L1 104
+#define PT_L2 100
+#define PT_L3 96
+#define PT_B0 92
+#define PT_B1 88
+#define PT_B2 84
+#define PT_B3 80
+#define PT_A0X 76
+#define PT_A0W 72
+#define PT_A1X 68
+#define PT_A1W 64
+#define PT_LC0 60
+#define PT_LC1 56
+#define PT_LT0 52
+#define PT_LT1 48
+#define PT_LB0 44
+#define PT_LB1 40
+#define PT_ASTAT 36
+#define PT_RESERVED 32
+#define PT_RETS 28
+#define PT_PC 24
+#define PT_RETX 20
+#define PT_RETN 16
+#define PT_RETE 12
+#define PT_SEQSTAT 8
+#define PT_IPEND 4
+
+#define PT_SYSCFG 216
+#define PT_TEXT_ADDR 220
+#define PT_TEXT_END_ADDR 224
+#define PT_DATA_ADDR 228
+#define PT_FDPIC_EXEC 232
+#define PT_FDPIC_INTERP 236
+
+#endif /* _BFIN_PTRACE_H */
diff --git a/include/asm-blackfin/resource.h b/include/asm-blackfin/resource.h
new file mode 100644
index 00000000000..091355ab349
--- /dev/null
+++ b/include/asm-blackfin/resource.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_RESOURCE_H
+#define _BFIN_RESOURCE_H
+
+#include <asm-generic/resource.h>
+
+#endif /* _BFIN_RESOURCE_H */
diff --git a/include/asm-blackfin/scatterlist.h b/include/asm-blackfin/scatterlist.h
new file mode 100644
index 00000000000..60e07b92044
--- /dev/null
+++ b/include/asm-blackfin/scatterlist.h
@@ -0,0 +1,26 @@
+#ifndef _BLACKFIN_SCATTERLIST_H
+#define _BLACKFIN_SCATTERLIST_H
+
+#include <linux/mm.h>
+
+struct scatterlist {
+ struct page *page;
+ unsigned int offset;
+ dma_addr_t dma_address;
+ unsigned int length;
+};
+
+/*
+ * These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_address(sg) (page_address((sg)->page) + (sg)->offset)
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->length)
+
+#define ISA_DMA_THRESHOLD (0xffffffff)
+
+#endif /* !(_BLACKFIN_SCATTERLIST_H) */
diff --git a/include/asm-blackfin/sections.h b/include/asm-blackfin/sections.h
new file mode 100644
index 00000000000..1443c3353a8
--- /dev/null
+++ b/include/asm-blackfin/sections.h
@@ -0,0 +1,7 @@
+#ifndef _BLACKFIN_SECTIONS_H
+#define _BLACKFIN_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+#endif
diff --git a/include/asm-blackfin/segment.h b/include/asm-blackfin/segment.h
new file mode 100644
index 00000000000..02cfd09b5a9
--- /dev/null
+++ b/include/asm-blackfin/segment.h
@@ -0,0 +1,7 @@
+#ifndef _BFIN_SEGMENT_H
+#define _BFIN_SEGMENT_H
+
+#define KERNEL_DS (0x5)
+#define USER_DS (0x1)
+
+#endif /* _BFIN_SEGMENT_H */
diff --git a/include/asm-blackfin/semaphore-helper.h b/include/asm-blackfin/semaphore-helper.h
new file mode 100644
index 00000000000..9082b0dc3eb
--- /dev/null
+++ b/include/asm-blackfin/semaphore-helper.h
@@ -0,0 +1,82 @@
+/* Based on M68K version, Lineo Inc. May 2001 */
+
+#ifndef _BFIN_SEMAPHORE_HELPER_H
+#define _BFIN_SEMAPHORE_HELPER_H
+
+/*
+ * SMP- and interrupt-safe semaphores helper functions.
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ */
+
+#include <asm/errno.h>
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore *sem)
+{
+ atomic_inc(&sem->waking);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+ int ret;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ ret = 0;
+ if (atomic_read(&sem->waking) > 0) {
+ atomic_dec(&sem->waking);
+ ret = 1;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ * 1 got the lock
+ * 0 go to sleep
+ * -EINTR interrupted
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+ struct task_struct *tsk)
+{
+ int ret = 0;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (atomic_read(&sem->waking) > 0) {
+ atomic_dec(&sem->waking);
+ ret = 1;
+ } else if (signal_pending(tsk)) {
+ atomic_inc(&sem->count);
+ ret = -EINTR;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ * 1 failed to lock
+ * 0 got the lock
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+ int ret = 1;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (atomic_read(&sem->waking) > 0) {
+ atomic_dec(&sem->waking);
+ ret = 0;
+ } else
+ atomic_inc(&sem->count);
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+#endif /* _BFIN_SEMAPHORE_HELPER_H */
diff --git a/include/asm-blackfin/semaphore.h b/include/asm-blackfin/semaphore.h
new file mode 100644
index 00000000000..94c04d7ab23
--- /dev/null
+++ b/include/asm-blackfin/semaphore.h
@@ -0,0 +1,106 @@
+#ifndef _BFIN_SEMAPHORE_H
+#define _BFIN_SEMAPHORE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/linkage.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/rwsem.h>
+#include <asm/atomic.h>
+
+/*
+ * Interrupt-safe semaphores..
+ *
+ * (C) Copyright 1996 Linus Torvalds
+ *
+ * BFIN version by akbar hussain Lineo Inc April 2001
+ *
+ */
+
+struct semaphore {
+ atomic_t count;
+ int sleepers;
+ wait_queue_head_t wait;
+};
+
+#define __SEMAPHORE_INITIALIZER(name, n) \
+{ \
+ .count = ATOMIC_INIT(n), \
+ .sleepers = 0, \
+ .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+}
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+static inline void sema_init(struct semaphore *sem, int val)
+{
+ *sem = (struct semaphore)__SEMAPHORE_INITIALIZER(*sem, val);
+}
+
+static inline void init_MUTEX(struct semaphore *sem)
+{
+ sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED(struct semaphore *sem)
+{
+ sema_init(sem, 0);
+}
+
+asmlinkage void __down(struct semaphore *sem);
+asmlinkage int __down_interruptible(struct semaphore *sem);
+asmlinkage int __down_trylock(struct semaphore *sem);
+asmlinkage void __up(struct semaphore *sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+/*
+ * This is ugly, but we want the default case to fall through.
+ * "down_failed" is a special asm handler that calls the C
+ * routine that actually waits.
+ */
+static inline void down(struct semaphore *sem)
+{
+ might_sleep();
+ if (atomic_dec_return(&sem->count) < 0)
+ __down(sem);
+}
+
+static inline int down_interruptible(struct semaphore *sem)
+{
+ int ret = 0;
+
+ might_sleep();
+ if (atomic_dec_return(&sem->count) < 0)
+ ret = __down_interruptible(sem);
+ return (ret);
+}
+
+static inline int down_trylock(struct semaphore *sem)
+{
+ int ret = 0;
+
+ if (atomic_dec_return(&sem->count) < 0)
+ ret = __down_trylock(sem);
+ return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ * The default case (no contention) will result in NO
+ * jumps for both down() and up().
+ */
+static inline void up(struct semaphore *sem)
+{
+ if (atomic_inc_return(&sem->count) <= 0)
+ __up(sem);
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* _BFIN_SEMAPHORE_H */
diff --git a/include/asm-blackfin/sembuf.h b/include/asm-blackfin/sembuf.h
new file mode 100644
index 00000000000..18deb5c7fa5
--- /dev/null
+++ b/include/asm-blackfin/sembuf.h
@@ -0,0 +1,25 @@
+#ifndef _BFIN_SEMBUF_H
+#define _BFIN_SEMBUF_H
+
+/*
+ * The semid64_ds structure for bfin architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t sem_otime; /* last semop time */
+ unsigned long __unused1;
+ __kernel_time_t sem_ctime; /* last change time */
+ unsigned long __unused2;
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+#endif /* _BFIN_SEMBUF_H */
diff --git a/include/asm-blackfin/setup.h b/include/asm-blackfin/setup.h
new file mode 100644
index 00000000000..01c8c6cbe6f
--- /dev/null
+++ b/include/asm-blackfin/setup.h
@@ -0,0 +1,17 @@
+/*
+** asm/setup.h -- Definition of the Linux/bfin setup information
+**
+** This file is subject to the terms and conditions of the GNU General Public
+** License. See the file COPYING in the main directory of this archive
+** for more details.
+**
+** Copyright Lineo, Inc 2001 Tony Kou
+**
+*/
+
+#ifndef _BFIN_SETUP_H
+#define _BFIN_SETUP_H
+
+#define COMMAND_LINE_SIZE 512
+
+#endif /* _BFIN_SETUP_H */
diff --git a/include/asm-blackfin/shmbuf.h b/include/asm-blackfin/shmbuf.h
new file mode 100644
index 00000000000..612436303e8
--- /dev/null
+++ b/include/asm-blackfin/shmbuf.h
@@ -0,0 +1,42 @@
+#ifndef _BFIN_SHMBUF_H
+#define _BFIN_SHMBUF_H
+
+/*
+ * The shmid64_ds structure for bfin architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_time_t shm_atime; /* last attach time */
+ unsigned long __unused1;
+ __kernel_time_t shm_dtime; /* last detach time */
+ unsigned long __unused2;
+ __kernel_time_t shm_ctime; /* last change time */
+ unsigned long __unused3;
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+struct shminfo64 {
+ unsigned long shmmax;
+ unsigned long shmmin;
+ unsigned long shmmni;
+ unsigned long shmseg;
+ unsigned long shmall;
+ unsigned long __unused1;
+ unsigned long __unused2;
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+#endif /* _BFIN_SHMBUF_H */
diff --git a/include/asm-blackfin/shmparam.h b/include/asm-blackfin/shmparam.h
new file mode 100644
index 00000000000..3c03906b766
--- /dev/null
+++ b/include/asm-blackfin/shmparam.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_SHMPARAM_H
+#define _BFIN_SHMPARAM_H
+
+#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
+
+#endif /* _BFIN_SHMPARAM_H */
diff --git a/include/asm-blackfin/sigcontext.h b/include/asm-blackfin/sigcontext.h
new file mode 100644
index 00000000000..ce00b03c277
--- /dev/null
+++ b/include/asm-blackfin/sigcontext.h
@@ -0,0 +1,55 @@
+#ifndef _ASM_BLACKFIN_SIGCONTEXT_H
+#define _ASM_BLACKFIN_SIGCONTEXT_H
+
+/* Add new entries at the end of the structure only. */
+struct sigcontext {
+ unsigned long sc_r0;
+ unsigned long sc_r1;
+ unsigned long sc_r2;
+ unsigned long sc_r3;
+ unsigned long sc_r4;
+ unsigned long sc_r5;
+ unsigned long sc_r6;
+ unsigned long sc_r7;
+ unsigned long sc_p0;
+ unsigned long sc_p1;
+ unsigned long sc_p2;
+ unsigned long sc_p3;
+ unsigned long sc_p4;
+ unsigned long sc_p5;
+ unsigned long sc_usp;
+ unsigned long sc_a0w;
+ unsigned long sc_a1w;
+ unsigned long sc_a0x;
+ unsigned long sc_a1x;
+ unsigned long sc_astat;
+ unsigned long sc_rets;
+ unsigned long sc_pc;
+ unsigned long sc_retx;
+ unsigned long sc_fp;
+ unsigned long sc_i0;
+ unsigned long sc_i1;
+ unsigned long sc_i2;
+ unsigned long sc_i3;
+ unsigned long sc_m0;
+ unsigned long sc_m1;
+ unsigned long sc_m2;
+ unsigned long sc_m3;
+ unsigned long sc_l0;
+ unsigned long sc_l1;
+ unsigned long sc_l2;
+ unsigned long sc_l3;
+ unsigned long sc_b0;
+ unsigned long sc_b1;
+ unsigned long sc_b2;
+ unsigned long sc_b3;
+ unsigned long sc_lc0;
+ unsigned long sc_lc1;
+ unsigned long sc_lt0;
+ unsigned long sc_lt1;
+ unsigned long sc_lb0;
+ unsigned long sc_lb1;
+ unsigned long sc_seqstat;
+};
+
+#endif
diff --git a/include/asm-blackfin/siginfo.h b/include/asm-blackfin/siginfo.h
new file mode 100644
index 00000000000..eca4565cea3
--- /dev/null
+++ b/include/asm-blackfin/siginfo.h
@@ -0,0 +1,35 @@
+#ifndef _BFIN_SIGINFO_H
+#define _BFIN_SIGINFO_H
+
+#include <linux/types.h>
+#include <asm-generic/siginfo.h>
+
+#define UID16_SIGINFO_COMPAT_NEEDED
+
+#define si_uid16 _sifields._kill._uid
+
+#define ILL_ILLPARAOP (__SI_FAULT|2) /* illegal opcode combine ********** */
+#define ILL_ILLEXCPT (__SI_FAULT|4) /* unrecoverable exception ********** */
+#define ILL_CPLB_VI (__SI_FAULT|9) /* D/I CPLB protect violation ******** */
+#define ILL_CPLB_MISS (__SI_FAULT|10) /* D/I CPLB miss ******** */
+#define ILL_CPLB_MULHIT (__SI_FAULT|11) /* D/I CPLB multiple hit ******** */
+
+/*
+ * SIGBUS si_codes
+ */
+#define BUS_OPFETCH (__SI_FAULT|4) /* error from instruction fetch ******** */
+
+/*
+ * SIGTRAP si_codes
+ */
+#define TRAP_STEP (__SI_FAULT|1) /* single-step breakpoint************* */
+#define TRAP_TRACEFLOW (__SI_FAULT|2) /* trace buffer overflow ************* */
+#define TRAP_WATCHPT (__SI_FAULT|3) /* watchpoint match ************* */
+#define TRAP_ILLTRAP (__SI_FAULT|4) /* illegal trap ************* */
+
+/*
+ * SIGSEGV si_codes
+ */
+#define SEGV_STACKFLOW (__SI_FAULT|3) /* stack overflow */
+
+#endif
diff --git a/include/asm-blackfin/signal.h b/include/asm-blackfin/signal.h
new file mode 100644
index 00000000000..0250429b736
--- /dev/null
+++ b/include/asm-blackfin/signal.h
@@ -0,0 +1,160 @@
+#ifndef _BLACKFIN_SIGNAL_H
+#define _BLACKFIN_SIGNAL_H
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems. */
+struct siginfo;
+
+#ifdef __KERNEL__
+/* Most things should be clean enough to redefine this at will, if care
+ is taken to make libc match. */
+
+#define _NSIG 64
+#define _NSIG_BPW 32
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+typedef unsigned long old_sigset_t; /* at least 32 bits */
+
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#else
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+#define NSIG 32
+typedef unsigned long sigset_t;
+
+#endif /* __KERNEL__ */
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+/*
+#define SIGLOST 29
+*/
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+/* These should not be considered constants from userland. */
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP 0x00000001
+#define SA_NOCLDWAIT 0x00000002 /* not supported yet */
+#define SA_SIGINFO 0x00000004
+#define SA_ONSTACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192
+
+#include <asm-generic/signal.h>
+
+#ifdef __KERNEL__
+struct old_sigaction {
+ __sighandler_t sa_handler;
+ old_sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer) (void);
+};
+
+struct sigaction {
+ __sighandler_t sa_handler;
+ unsigned long sa_flags;
+ void (*sa_restorer) (void);
+ sigset_t sa_mask; /* mask last for extensibility */
+};
+
+struct k_sigaction {
+ struct sigaction sa;
+};
+#else
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction) (int, struct siginfo *, void *);
+ } _u;
+ sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer) (void);
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+ void *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+
+#include <asm/sigcontext.h>
+#undef __HAVE_ARCH_SIG_BITOPS
+
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _BLACKFIN_SIGNAL_H */
diff --git a/include/asm-blackfin/socket.h b/include/asm-blackfin/socket.h
new file mode 100644
index 00000000000..5213c965218
--- /dev/null
+++ b/include/asm-blackfin/socket.h
@@ -0,0 +1,53 @@
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET 1
+
+#define SO_DEBUG 1
+#define SO_REUSEADDR 2
+#define SO_TYPE 3
+#define SO_ERROR 4
+#define SO_DONTROUTE 5
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_SNDBUFFORCE 32
+#define SO_RCVBUFFORCE 33
+#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_LINGER 13
+#define SO_BSDCOMPAT 14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_PASSCRED 16
+#define SO_PEERCRED 17
+#define SO_RCVLOWAT 18
+#define SO_SNDLOWAT 19
+#define SO_RCVTIMEO 20
+#define SO_SNDTIMEO 21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION 22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
+#define SO_SECURITY_ENCRYPTION_NETWORK 24
+
+#define SO_BINDTODEVICE 25
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER 26
+#define SO_DETACH_FILTER 27
+
+#define SO_PEERNAME 28
+#define SO_TIMESTAMP 29
+#define SCM_TIMESTAMP SO_TIMESTAMP
+
+#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+#define SO_PASSSEC 34
+#define SO_TIMESTAMPNS 35
+#define SCM_TIMESTAMPNS SO_TIMESTAMPNS
+#endif /* _ASM_SOCKET_H */
diff --git a/include/asm-blackfin/sockios.h b/include/asm-blackfin/sockios.h
new file mode 100644
index 00000000000..426b89bfaa8
--- /dev/null
+++ b/include/asm-blackfin/sockios.h
@@ -0,0 +1,13 @@
+#ifndef __ARCH_BFIN_SOCKIOS__
+#define __ARCH_BFIN_SOCKIOS__
+
+/* Socket-level I/O control calls. */
+#define FIOSETOWN 0x8901
+#define SIOCSPGRP 0x8902
+#define FIOGETOWN 0x8903
+#define SIOCGPGRP 0x8904
+#define SIOCATMARK 0x8905
+#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
+#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
+
+#endif /* __ARCH_BFIN_SOCKIOS__ */
diff --git a/include/asm-blackfin/spinlock.h b/include/asm-blackfin/spinlock.h
new file mode 100644
index 00000000000..64e908a5064
--- /dev/null
+++ b/include/asm-blackfin/spinlock.h
@@ -0,0 +1,6 @@
+#ifndef __BFIN_SPINLOCK_H
+#define __BFIN_SPINLOCK_H
+
+#error blackfin architecture does not support SMP spin lock yet
+
+#endif
diff --git a/include/asm-blackfin/stat.h b/include/asm-blackfin/stat.h
new file mode 100644
index 00000000000..d2b6f11ec23
--- /dev/null
+++ b/include/asm-blackfin/stat.h
@@ -0,0 +1,63 @@
+#ifndef _BFIN_STAT_H
+#define _BFIN_STAT_H
+
+struct stat {
+ unsigned short st_dev;
+ unsigned short __pad1;
+ unsigned long st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ unsigned short __pad2;
+ unsigned long st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ unsigned long st_atime;
+ unsigned long __unused1;
+ unsigned long st_mtime;
+ unsigned long __unused2;
+ unsigned long st_ctime;
+ unsigned long __unused3;
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct stat64 {
+ unsigned long long st_dev;
+ unsigned char __pad1[4];
+
+#define STAT64_HAS_BROKEN_ST_INO 1
+ unsigned long __st_ino;
+
+ unsigned int st_mode;
+ unsigned int st_nlink;
+
+ unsigned long st_uid;
+ unsigned long st_gid;
+
+ unsigned long long st_rdev;
+ unsigned char __pad2[4];
+
+ long long st_size;
+ unsigned long st_blksize;
+
+ long long st_blocks; /* Number 512-byte blocks allocated. */
+
+ unsigned long st_atime;
+ unsigned long st_atime_nsec;
+
+ unsigned long st_mtime;
+ unsigned long st_mtime_nsec;
+
+ unsigned long st_ctime;
+ unsigned long st_ctime_nsec;
+
+ unsigned long long st_ino;
+};
+
+#endif /* _BFIN_STAT_H */
diff --git a/include/asm-blackfin/statfs.h b/include/asm-blackfin/statfs.h
new file mode 100644
index 00000000000..350672091ba
--- /dev/null
+++ b/include/asm-blackfin/statfs.h
@@ -0,0 +1,6 @@
+#ifndef _BFIN_STATFS_H
+#define _BFIN_STATFS_H
+
+#include <asm-generic/statfs.h>
+
+#endif /* _BFIN_STATFS_H */
diff --git a/include/asm-blackfin/string.h b/include/asm-blackfin/string.h
new file mode 100644
index 00000000000..6f1eb7d6d3c
--- /dev/null
+++ b/include/asm-blackfin/string.h
@@ -0,0 +1,104 @@
+#ifndef _BLACKFIN_STRING_H_
+#define _BLACKFIN_STRING_H_
+
+#ifdef __KERNEL__ /* only set these up for kernel code */
+
+#define __HAVE_ARCH_STRCPY
+extern inline char *strcpy(char *dest, const char *src)
+{
+ char *xdest = dest;
+ char temp = 0;
+
+ __asm__ __volatile__
+ ("1:\t%2 = B [%1++] (Z);\n\t"
+ "B [%0++] = %2;\n\t"
+ "CC = %2;\n\t"
+ "if cc jump 1b (bp);\n"
+ : "+&a" (dest), "+&a" (src), "=&d" (temp)
+ ::"memory", "CC");
+ return xdest;
+}
+
+#define __HAVE_ARCH_STRNCPY
+extern inline char *strncpy(char *dest, const char *src, size_t n)
+{
+ char *xdest = dest;
+ char temp = 0;
+
+ if (n == 0)
+ return xdest;
+
+ __asm__ __volatile__
+ ("1:\t%3 = B [%1++] (Z);\n\t"
+ "B [%0++] = %3;\n\t"
+ "CC = %3;\n\t"
+ "if ! cc jump 2f;\n\t"
+ "%2 += -1;\n\t"
+ "CC = %2 == 0;\n\t"
+ "if ! cc jump 1b (bp);\n"
+ "2:\n"
+ : "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp)
+ ::"memory", "CC");
+ return xdest;
+}
+
+#define __HAVE_ARCH_STRCMP
+extern inline int strcmp(const char *cs, const char *ct)
+{
+ char __res1, __res2;
+
+ __asm__
+ ("1:\t%2 = B[%0++] (Z);\n\t" /* get *cs */
+ "%3 = B[%1++] (Z);\n\t" /* get *ct */
+ "CC = %2 == %3;\n\t" /* compare a byte */
+ "if ! cc jump 2f;\n\t" /* not equal, break out */
+ "CC = %2;\n\t" /* at end of cs? */
+ "if cc jump 1b (bp);\n\t" /* no, keep going */
+ "jump.s 3f;\n" /* strings are equal */
+ "2:\t%2 = %2 - %3;\n" /* *cs - *ct */
+ "3:\n"
+ : "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2)
+ : : "CC");
+
+ return __res1;
+}
+
+#define __HAVE_ARCH_STRNCMP
+extern inline int strncmp(const char *cs, const char *ct, size_t count)
+{
+ char __res1, __res2;
+
+ if (!count)
+ return 0;
+ __asm__
+ ("1:\t%3 = B[%0++] (Z);\n\t" /* get *cs */
+ "%4 = B[%1++] (Z);\n\t" /* get *ct */
+ "CC = %3 == %4;\n\t" /* compare a byte */
+ "if ! cc jump 3f;\n\t" /* not equal, break out */
+ "CC = %3;\n\t" /* at end of cs? */
+ "if ! cc jump 4f;\n\t" /* yes, all done */
+ "%2 += -1;\n\t" /* no, adjust count */
+ "CC = %2 == 0;\n\t"
+ "if ! cc jump 1b;\n" /* more to do, keep going */
+ "2:\t%3 = 0;\n\t" /* strings are equal */
+ "jump.s 4f;\n"
+ "3:\t%3 = %3 - %4;\n" /* *cs - *ct */
+ "4:"
+ : "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2)
+ : : "CC");
+ return __res1;
+}
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *s, int c, size_t count);
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *d, const void *s, size_t count);
+#define __HAVE_ARCH_MEMCMP
+extern int memcmp(const void *, const void *, __kernel_size_t);
+#define __HAVE_ARCH_MEMCHR
+extern void *memchr(const void *s, int c, size_t n);
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *dest, const void *src, size_t count);
+
+#endif /*__KERNEL__*/
+#endif /* _BLACKFIN_STRING_H_ */
diff --git a/include/asm-blackfin/system.h b/include/asm-blackfin/system.h
new file mode 100644
index 00000000000..5e5f1a0566c
--- /dev/null
+++ b/include/asm-blackfin/system.h
@@ -0,0 +1,249 @@
+/*
+ * File: include/asm/system.h
+ * Based on:
+ * Author: Tony Kou (tonyko@lineo.ca)
+ * Copyright (c) 2002 Arcturus Networks Inc.
+ * (www.arcturusnetworks.com)
+ * Copyright (c) 2003 Metrowerks (www.metrowerks.com)
+ * Copyright (c) 2004 Analog Device Inc.
+ * Created: 25Jan2001 - Tony Kou
+ * Description: system.h include file
+ *
+ * Modified: 22Sep2006 - Robin Getz
+ * - move include blackfin.h down, so I can get access to
+ * irq functions in other include files.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _BLACKFIN_SYSTEM_H
+#define _BLACKFIN_SYSTEM_H
+
+#include <linux/linkage.h>
+#include <linux/compiler.h>
+
+/*
+ * Interrupt configuring macros.
+ */
+
+extern unsigned long irq_flags;
+
+#define local_irq_enable() do { \
+ __asm__ __volatile__ ( \
+ "sti %0;" \
+ ::"d"(irq_flags)); \
+} while (0)
+
+#define local_irq_disable() do { \
+ int _tmp_dummy; \
+ __asm__ __volatile__ ( \
+ "cli %0;" \
+ :"=d" (_tmp_dummy):); \
+} while (0)
+
+#if defined(ANOMALY_05000244) && defined (CONFIG_BLKFIN_CACHE)
+#define idle_with_irq_disabled() do { \
+ __asm__ __volatile__ ( \
+ "nop; nop;\n" \
+ ".align 8;\n" \
+ "sti %0; idle;\n" \
+ ::"d" (irq_flags)); \
+} while (0)
+#else
+#define idle_with_irq_disabled() do { \
+ __asm__ __volatile__ ( \
+ ".align 8;\n" \
+ "sti %0; idle;\n" \
+ ::"d" (irq_flags)); \
+} while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_HWERR
+#define __save_and_cli(x) do { \
+ __asm__ __volatile__ ( \
+ "cli %0;\n\tsti %1;" \
+ :"=&d"(x): "d" (0x3F)); \
+} while (0)
+#else
+#define __save_and_cli(x) do { \
+ __asm__ __volatile__ ( \
+ "cli %0;" \
+ :"=&d"(x):); \
+} while (0)
+#endif
+
+#define local_save_flags(x) asm volatile ("cli %0;" \
+ "sti %0;" \
+ :"=d"(x):);
+
+#ifdef CONFIG_DEBUG_HWERR
+#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0)
+#else
+#define irqs_enabled_from_flags(x) ((x) != 0x1f)
+#endif
+
+#define local_irq_restore(x) do { \
+ if (irqs_enabled_from_flags(x)) \
+ local_irq_enable (); \
+} while (0)
+
+/* For spinlocks etc */
+#define local_irq_save(x) __save_and_cli(x)
+
+#define irqs_disabled() \
+({ \
+ unsigned long flags; \
+ local_save_flags(flags); \
+ !irqs_enabled_from_flags(flags); \
+})
+
+/*
+ * Force strict CPU ordering.
+ */
+#define nop() asm volatile ("nop;\n\t"::)
+#define mb() asm volatile ("" : : :"memory")
+#define rmb() asm volatile ("" : : :"memory")
+#define wmb() asm volatile ("" : : :"memory")
+#define set_rmb(var, value) do { (void) xchg(&var, value); } while (0)
+#define set_mb(var, value) set_rmb(var, value)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#define read_barrier_depends() do { } while(0)
+
+#ifdef CONFIG_SMP
+#define smp_mb() mb()
+#define smp_rmb() rmb()
+#define smp_wmb() wmb()
+#define smp_read_barrier_depends() read_barrier_depends()
+#else
+#define smp_mb() barrier()
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+#define smp_read_barrier_depends() do { } while(0)
+#endif
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+struct __xchg_dummy {
+ unsigned long a[100];
+};
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+ int size)
+{
+ unsigned long tmp = 0;
+ unsigned long flags = 0;
+
+ local_irq_save(flags);
+
+ switch (size) {
+ case 1:
+ __asm__ __volatile__
+ ("%0 = b%2 (z);\n\t"
+ "b%2 = %1;\n\t"
+ : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+ break;
+ case 2:
+ __asm__ __volatile__
+ ("%0 = w%2 (z);\n\t"
+ "w%2 = %1;\n\t"
+ : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+ break;
+ case 4:
+ __asm__ __volatile__
+ ("%0 = %2;\n\t"
+ "%2 = %1;\n\t"
+ : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
+ break;
+ }
+ local_irq_restore(flags);
+ return tmp;
+}
+
+/*
+ * Atomic compare and exchange. Compare OLD with MEM, if identical,
+ * store NEW in MEM. Return the initial value in MEM. Success is
+ * indicated by comparing RETURN with OLD.
+ */
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long tmp = 0;
+ unsigned long flags = 0;
+
+ local_irq_save(flags);
+
+ switch (size) {
+ case 1:
+ __asm__ __volatile__
+ ("%0 = b%3 (z);\n\t"
+ "CC = %1 == %0;\n\t"
+ "IF !CC JUMP 1f;\n\t"
+ "b%3 = %2;\n\t"
+ "1:\n\t"
+ : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
+ break;
+ case 2:
+ __asm__ __volatile__
+ ("%0 = w%3 (z);\n\t"
+ "CC = %1 == %0;\n\t"
+ "IF !CC JUMP 1f;\n\t"
+ "w%3 = %2;\n\t"
+ "1:\n\t"
+ : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
+ break;
+ case 4:
+ __asm__ __volatile__
+ ("%0 = %3;\n\t"
+ "CC = %1 == %0;\n\t"
+ "IF !CC JUMP 1f;\n\t"
+ "%3 = %2;\n\t"
+ "1:\n\t"
+ : "=&d" (tmp) : "d" (old), "d" (new), "m" (*__xg(ptr)) : "memory");
+ break;
+ }
+ local_irq_restore(flags);
+ return tmp;
+}
+
+#define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+
+#define prepare_to_switch() do { } while(0)
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing.
+ */
+
+#include <asm/blackfin.h>
+
+asmlinkage struct task_struct *resume(struct task_struct *prev, struct task_struct *next);
+
+#define switch_to(prev,next,last) \
+do { \
+ memcpy (&task_thread_info(prev)->l1_task_info, L1_SCRATCH_TASK_INFO, \
+ sizeof *L1_SCRATCH_TASK_INFO); \
+ memcpy (L1_SCRATCH_TASK_INFO, &task_thread_info(next)->l1_task_info, \
+ sizeof *L1_SCRATCH_TASK_INFO); \
+ (last) = resume (prev, next); \
+} while (0)
+
+#endif /* _BLACKFIN_SYSTEM_H */
diff --git a/include/asm-blackfin/termbits.h b/include/asm-blackfin/termbits.h
new file mode 100644
index 00000000000..2fd9dabdba7
--- /dev/null
+++ b/include/asm-blackfin/termbits.h
@@ -0,0 +1,184 @@
+#ifndef __ARCH_BFIN_TERMBITS_H__
+#define __ARCH_BFIN_TERMBITS_H__
+
+#include <linux/posix_types.h>
+
+typedef unsigned char cc_t;
+typedef unsigned int speed_t;
+typedef unsigned int tcflag_t;
+
+#define NCCS 19
+struct termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+};
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK 0000020
+#define ISTRIP 0000040
+#define INLCR 0000100
+#define IGNCR 0000200
+#define ICRNL 0000400
+#define IUCLC 0001000
+#define IXON 0002000
+#define IXANY 0004000
+#define IXOFF 0010000
+#define IMAXBEL 0020000
+#define IUTF8 0040000
+
+/* c_oflag bits */
+#define OPOST 0000001
+#define OLCUC 0000002
+#define ONLCR 0000004
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#define NLDLY 0000400
+#define NL0 0000000
+#define NL1 0000400
+#define CRDLY 0003000
+#define CR0 0000000
+#define CR1 0001000
+#define CR2 0002000
+#define CR3 0003000
+#define TABDLY 0014000
+#define TAB0 0000000
+#define TAB1 0004000
+#define TAB2 0010000
+#define TAB3 0014000
+#define XTABS 0014000
+#define BSDLY 0020000
+#define BS0 0000000
+#define BS1 0020000
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+#define FFDLY 0100000
+#define FF0 0000000
+#define FF1 0100000
+
+/* c_cflag bit meaning */
+#define CBAUD 0010017
+#define B0 0000000 /* hang up */
+#define B50 0000001
+#define B75 0000002
+#define B110 0000003
+#define B134 0000004
+#define B150 0000005
+#define B200 0000006
+#define B300 0000007
+#define B600 0000010
+#define B1200 0000011
+#define B1800 0000012
+#define B2400 0000013
+#define B4800 0000014
+#define B9600 0000015
+#define B19200 0000016
+#define B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE 0000060
+#define CS5 0000000
+#define CS6 0000020
+#define CS7 0000040
+#define CS8 0000060
+#define CSTOPB 0000100
+#define CREAD 0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL 0002000
+#define CLOCAL 0004000
+#define CBAUDEX 0010000
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
+#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CMSPAR 010000000000 /* mark or space (stick) parity */
+#define CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* tcflow() and TCXONC use these */
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+#endif /* __ARCH_BFIN_TERMBITS_H__ */
diff --git a/include/asm-blackfin/termios.h b/include/asm-blackfin/termios.h
new file mode 100644
index 00000000000..5c41478a51c
--- /dev/null
+++ b/include/asm-blackfin/termios.h
@@ -0,0 +1,106 @@
+#ifndef __BFIN_TERMIOS_H__
+#define __BFIN_TERMIOS_H__
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+/* modem lines */
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+#define TIOCM_OUT1 0x2000
+#define TIOCM_OUT2 0x4000
+#define TIOCM_LOOP 0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* line disciplines */
+#define N_TTY 0
+#define N_SLIP 1
+#define N_MOUSE 2
+#define N_PPP 3
+#define N_STRIP 4
+#define N_AX25 5
+#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
+#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964 9 /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14 /* synchronous PPP */
+#define N_HCI 15 /* Bluetooth HCI UART */
+
+#ifdef __KERNEL__
+
+/* intr=^C quit=^\ erase=del kill=^U
+ eof=^D vtime=\0 vmin=\1 sxtc=\0
+ start=^Q stop=^S susp=^Z eol=\0
+ reprint=^R discard=^U werase=^W lnext=^V
+ eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+ unsigned short __tmp; \
+ get_user(__tmp,&(termio)->x); \
+ *(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+ put_user((termios)->c_iflag, &(termio)->c_iflag); \
+ put_user((termios)->c_oflag, &(termio)->c_oflag); \
+ put_user((termios)->c_cflag, &(termio)->c_cflag); \
+ put_user((termios)->c_lflag, &(termio)->c_lflag); \
+ put_user((termios)->c_line, &(termio)->c_line); \
+ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif /* __KERNEL__ */
+
+#endif /* __BFIN_TERMIOS_H__ */
diff --git a/include/asm-blackfin/thread_info.h b/include/asm-blackfin/thread_info.h
new file mode 100644
index 00000000000..fa8f08cf283
--- /dev/null
+++ b/include/asm-blackfin/thread_info.h
@@ -0,0 +1,143 @@
+/*
+ * File: include/asm-blackfin/thread_info.h
+ * Based on: include/asm-m68knommu/thread_info.h
+ * Author: LG Soft India
+ * Copyright (C) 2004-2005 Analog Devices Inc.
+ * Created: Tue Sep 21 2004
+ * Description: Blackfin low-level thread information
+ * Modified:
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#include <asm/page.h>
+#include <asm/entry.h>
+#include <asm/l1layout.h>
+#include <linux/compiler.h>
+
+#ifdef __KERNEL__
+
+/* Thread Align Mask to reach to the top of the stack
+ * for any process
+ */
+#define ALIGN_PAGE_MASK 0xffffe000
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long mm_segment_t;
+
+/*
+ * low level task data.
+ * If you change this, change the TI_* offsets below to match.
+ */
+
+struct thread_info {
+ struct task_struct *task; /* main task structure */
+ struct exec_domain *exec_domain; /* execution domain */
+ unsigned long flags; /* low level flags */
+ int cpu; /* cpu we're on */
+ int preempt_count; /* 0 => preemptable, <0 => BUG */
+ mm_segment_t addr_limit; /* address limit */
+ struct restart_block restart_block;
+ struct l1_scratch_task_info l1_task_info;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .task = &tsk, \
+ .exec_domain = &default_exec_domain, \
+ .flags = 0, \
+ .cpu = 0, \
+ .preempt_count = 1, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
+}
+#define init_thread_info (init_thread_union.thread_info)
+#define init_stack (init_thread_union.stack)
+
+/*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#define THREAD_SIZE 8192 /* 2 pages */
+
+/* How to get the thread information struct from C */
+
+static inline struct thread_info *current_thread_info(void)
+ __attribute__ ((__const__));
+
+/* Given a task stack pointer, you can find it's task structure
+ * just by masking it to the 8K boundary.
+ */
+static inline struct thread_info *current_thread_info(void)
+{
+ struct thread_info *ti;
+ __asm__("%0 = sp;": "=&d"(ti):
+ );
+ return (struct thread_info *)((long)ti & ~8191UL);
+}
+
+/* thread information allocation */
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+ __get_free_pages(GFP_KERNEL, 1))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Offsets in thread_info structure, used in assembly code
+ */
+#define TI_TASK 0
+#define TI_EXECDOMAIN 4
+#define TI_FLAGS 8
+#define TI_CPU 12
+#define TI_PREEMPT 16
+
+#define PREEMPT_ACTIVE 0x4000000
+
+/*
+ * thread information flag bit numbers
+ */
+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
+#define TIF_SIGPENDING 2 /* signal pending */
+#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling
+ TIF_NEED_RESCHED */
+#define TIF_MEMDIE 5
+#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
+#define TIF_FREEZE 7 /* is freezing for suspend */
+
+/* as above, but as bit values */
+#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_FREEZE (1<<TIF_FREEZE)
+
+#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-blackfin/timex.h b/include/asm-blackfin/timex.h
new file mode 100644
index 00000000000..828590117f5
--- /dev/null
+++ b/include/asm-blackfin/timex.h
@@ -0,0 +1,18 @@
+/* blackfin architecture timex specifications: Lineo Inc. 2001
+ *
+ * Based on: include/asm-m68knommu/timex.h
+ */
+
+#ifndef _ASMBLACKFIN_TIMEX_H
+#define _ASMBLACKFIN_TIMEX_H
+
+#define CLOCK_TICK_RATE 1000000 /* Underlying HZ */
+
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/include/asm-blackfin/tlb.h b/include/asm-blackfin/tlb.h
new file mode 100644
index 00000000000..89a12ee916d
--- /dev/null
+++ b/include/asm-blackfin/tlb.h
@@ -0,0 +1,16 @@
+#ifndef _BLACKFIN_TLB_H
+#define _BLACKFIN_TLB_H
+
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+
+/*
+ * .. because we flush the whole mm when it
+ * fills up.
+ */
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#endif /* _BLACKFIN_TLB_H */
diff --git a/include/asm-blackfin/tlbflush.h b/include/asm-blackfin/tlbflush.h
new file mode 100644
index 00000000000..10a07ba1e01
--- /dev/null
+++ b/include/asm-blackfin/tlbflush.h
@@ -0,0 +1,62 @@
+#ifndef _BLACKFIN_TLBFLUSH_H
+#define _BLACKFIN_TLBFLUSH_H
+
+/*
+ * Copyright (C) 2000 Lineo, David McCullough <davidm@uclinux.org>
+ * Copyright (C) 2000-2002, Greg Ungerer <gerg@snapgear.com>
+ */
+
+#include <asm/setup.h>
+
+/*
+ * flush all user-space atc entries.
+ */
+static inline void __flush_tlb(void)
+{
+ BUG();
+}
+
+static inline void __flush_tlb_one(unsigned long addr)
+{
+ BUG();
+}
+
+#define flush_tlb() __flush_tlb()
+
+/*
+ * flush all atc entries (both kernel and user-space entries).
+ */
+static inline void flush_tlb_all(void)
+{
+ BUG();
+}
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ BUG();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ BUG();
+}
+
+static inline void flush_tlb_range(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ BUG();
+}
+
+static inline void flush_tlb_kernel_page(unsigned long addr)
+{
+ BUG();
+}
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ BUG();
+}
+
+#endif
diff --git a/include/asm-blackfin/topology.h b/include/asm-blackfin/topology.h
new file mode 100644
index 00000000000..acee2398789
--- /dev/null
+++ b/include/asm-blackfin/topology.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_BLACKFIN_TOPOLOGY_H
+#define _ASM_BLACKFIN_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_BLACKFIN_TOPOLOGY_H */
diff --git a/include/asm-blackfin/traps.h b/include/asm-blackfin/traps.h
new file mode 100644
index 00000000000..fe365b1b7ca
--- /dev/null
+++ b/include/asm-blackfin/traps.h
@@ -0,0 +1,75 @@
+/*
+ * linux/include/asm/traps.h
+ *
+ * Copyright (C) 1993 Hamish Macdonald
+ *
+ * Lineo, Inc Jul 2001 Tony Kou
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _BFIN_TRAPS_H
+#define _BFIN_TRAPS_H
+
+#define VEC_SYS (0)
+#define VEC_EXCPT01 (1)
+#define VEC_EXCPT02 (2)
+#define VEC_EXCPT03 (3)
+#define VEC_EXCPT04 (4)
+#define VEC_EXCPT05 (5)
+#define VEC_EXCPT06 (6)
+#define VEC_EXCPT07 (7)
+#define VEC_EXCPT08 (8)
+#define VEC_EXCPT09 (9)
+#define VEC_EXCPT10 (10)
+#define VEC_EXCPT11 (11)
+#define VEC_EXCPT12 (12)
+#define VEC_EXCPT13 (13)
+#define VEC_EXCPT14 (14)
+#define VEC_EXCPT15 (15)
+#define VEC_STEP (16)
+#define VEC_OVFLOW (17)
+#define VEC_UNDEF_I (33)
+#define VEC_ILGAL_I (34)
+#define VEC_CPLB_VL (35)
+#define VEC_MISALI_D (36)
+#define VEC_UNCOV (37)
+#define VEC_CPLB_M (38)
+#define VEC_CPLB_MHIT (39)
+#define VEC_WATCH (40)
+#define VEC_ISTRU_VL (41) /*ADSP-BF535 only (MH) */
+#define VEC_MISALI_I (42)
+#define VEC_CPLB_I_VL (43)
+#define VEC_CPLB_I_M (44)
+#define VEC_CPLB_I_MHIT (45)
+#define VEC_ILL_RES (46) /* including unvalid supervisor mode insn */
+
+#ifndef __ASSEMBLY__
+
+#define HWC_x2 "System MMR Error\nAn error occurred due to an invalid access to an System MMR location\nPossible reason: a 32-bit register is accessed with a 16-bit instruction,\nor a 16-bit register is accessed with a 32-bit instruction.\n"
+#define HWC_x3 "External Memory Addressing Error\n"
+#define HWC_x12 "Performance Monitor Overflow\n"
+#define HWC_x18 "RAISE 5 instruction\n Software issued a RAISE 5 instruction to invoke the Hardware\n"
+#define HWC_default "Reserved\n"
+
+#define EXC_0x03 "Application stack overflow\n - Please increase the stack size of the application using elf2flt -s option,\n and/or reduce the stack use of the application.\n"
+#define EXC_0x10 "Single step\n - When the processor is in single step mode, every instruction\n generates an exception. Primarily used for debugging.\n"
+#define EXC_0x11 "Exception caused by a trace buffer full condition\n - The processor takes this exception when the trace\n buffer overflows (only when enabled by the Trace Unit Control register).\n"
+#define EXC_0x21 "Undefined instruction\n - May be used to emulate instructions that are not defined for\n a particular processor implementation.\n"
+#define EXC_0x22 "Illegal instruction combination\n - See section for multi-issue rules in the ADSP-BF53x Blackfin\n Processor Instruction Set Reference.\n"
+#define EXC_0x23 "Data access CPLB protection violation\n - Attempted read or write to Supervisor resource,\n or illegal data memory access. \n"
+#define EXC_0x24 "Data access misaligned address violation\n - Attempted misaligned data memory or data cache access.\n"
+#define EXC_0x25 "Unrecoverable event\n - For example, an exception generated while processing a previous exception.\n"
+#define EXC_0x26 "Data access CPLB miss\n - Used by the MMU to signal a CPLB miss on a data access.\n"
+#define EXC_0x27 "Data access multiple CPLB hits\n - More than one CPLB entry matches data fetch address.\n"
+#define EXC_0x28 "Program Sequencer Exception caused by an emulation watchpoint match\n - There is a watchpoint match, and one of the EMUSW\n bits in the Watchpoint Instruction Address Control register (WPIACTL) is set.\n"
+#define EXC_0x2A "Instruction fetch misaligned address violation\n - Attempted misaligned instruction cache fetch. On a misaligned instruction fetch exception,\n the return address provided in RETX is the destination address which is misaligned, rather than the address of the offending instruction.\n"
+#define EXC_0x2B "CPLB protection violation\n - Illegal instruction fetch access (memory protection violation).\n"
+#define EXC_0x2C "Instruction fetch CPLB miss\n - CPLB miss on an instruction fetch.\n"
+#define EXC_0x2D "Instruction fetch multiple CPLB hits\n - More than one CPLB entry matches instruction fetch address.\n"
+#define EXC_0x2E "Illegal use of supervisor resource\n - Attempted to use a Supervisor register or instruction from User mode.\n Supervisor resources are registers and instructions that are reserved\n for Supervisor use: Supervisor only registers, all MMRs, and Supervisor\n only instructions.\n"
+
+#endif /* __ASSEMBLY__ */
+#endif /* _BFIN_TRAPS_H */
diff --git a/include/asm-blackfin/types.h b/include/asm-blackfin/types.h
new file mode 100644
index 00000000000..36f8dc8c52b
--- /dev/null
+++ b/include/asm-blackfin/types.h
@@ -0,0 +1,66 @@
+#ifndef _BFIN_TYPES_H
+#define _BFIN_TYPES_H
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue. However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+/* HK0617 -- Changes to unsigned long temporarily */
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+#endif /* __ASSEMBLY__ */
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+#define BITS_PER_LONG 32
+
+#ifndef __ASSEMBLY__
+
+typedef signed char s8;
+typedef unsigned char u8;
+
+typedef signed short s16;
+typedef unsigned short u16;
+
+typedef signed int s32;
+typedef unsigned int u32;
+
+typedef signed long long s64;
+typedef unsigned long long u64;
+
+/* Dma addresses are 32-bits wide. */
+
+typedef u32 dma_addr_t;
+typedef u64 dma64_addr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __KERNEL__ */
+
+#endif /* _BFIN_TYPES_H */
diff --git a/include/asm-blackfin/uaccess.h b/include/asm-blackfin/uaccess.h
new file mode 100644
index 00000000000..bfcb6794c67
--- /dev/null
+++ b/include/asm-blackfin/uaccess.h
@@ -0,0 +1,271 @@
+/* Changes made by Lineo Inc. May 2001
+ *
+ * Based on: include/asm-m68knommu/uaccess.h
+ */
+
+#ifndef __BLACKFIN_UACCESS_H
+#define __BLACKFIN_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+
+#include <asm/segment.h>
+#ifndef CONFIG_NO_ACCESS_CHECK
+# include <asm/bfin-global.h>
+#endif
+
+#define get_ds() (KERNEL_DS)
+#define get_fs() (current_thread_info()->addr_limit)
+
+static inline void set_fs(mm_segment_t fs)
+{
+ current_thread_info()->addr_limit = fs;
+}
+
+#define segment_eq(a,b) ((a) == (b))
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size))
+
+static inline int is_in_rom(unsigned long addr)
+{
+ /*
+ * What we are really trying to do is determine if addr is
+ * in an allocated kernel memory region. If not then assume
+ * we cannot free it or otherwise de-allocate it. Ideally
+ * we could restrict this to really being in a ROM or flash,
+ * but that would need to be done on a board by board basis,
+ * not globally.
+ */
+ if ((addr < _ramstart) || (addr >= _ramend))
+ return (1);
+
+ /* Default case, not in ROM */
+ return (0);
+}
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ */
+
+#ifdef CONFIG_NO_ACCESS_CHECK
+static inline int _access_ok(unsigned long addr, unsigned long size) { return 1; }
+#else
+#ifdef CONFIG_ACCESS_OK_L1
+extern int _access_ok(unsigned long addr, unsigned long size)__attribute__((l1_text));
+#else
+extern int _access_ok(unsigned long addr, unsigned long size);
+#endif
+#endif
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue. No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path. This means when everything is well,
+ * we don't even have to jump over them. Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry {
+ unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup otherwise. */
+extern unsigned long search_exception_table(unsigned long);
+
+/*
+ * These are the main single-value transfer routines. They automatically
+ * use the right size if we just have the right pointer type.
+ */
+
+#define put_user(x,p) \
+ ({ \
+ int _err = 0; \
+ typeof(*(p)) _x = (x); \
+ typeof(*(p)) *_p = (p); \
+ if (!access_ok(VERIFY_WRITE, _p, sizeof(*(_p)))) {\
+ _err = -EFAULT; \
+ } \
+ else { \
+ switch (sizeof (*(_p))) { \
+ case 1: \
+ __put_user_asm(_x, _p, B); \
+ break; \
+ case 2: \
+ __put_user_asm(_x, _p, W); \
+ break; \
+ case 4: \
+ __put_user_asm(_x, _p, ); \
+ break; \
+ case 8: { \
+ long _xl, _xh; \
+ _xl = ((long *)&_x)[0]; \
+ _xh = ((long *)&_x)[1]; \
+ __put_user_asm(_xl, ((long *)_p)+0, ); \
+ __put_user_asm(_xh, ((long *)_p)+1, ); \
+ } break; \
+ default: \
+ _err = __put_user_bad(); \
+ break; \
+ } \
+ } \
+ _err; \
+ })
+
+#define __put_user(x,p) put_user(x,p)
+static inline int bad_user_access_length(void)
+{
+ panic("bad_user_access_length");
+ return -1;
+}
+
+#define __put_user_bad() (printk(KERN_INFO "put_user_bad %s:%d %s\n",\
+ __FILE__, __LINE__, __FUNCTION__),\
+ bad_user_access_length(), (-EFAULT))
+
+/*
+ * Tell gcc we read from memory instead of writing: this is because
+ * we do not write to any memory gcc knows about, so there are no
+ * aliasing issues.
+ */
+
+#define __ptr(x) ((unsigned long *)(x))
+
+#define __put_user_asm(x,p,bhw) \
+ __asm__ (#bhw"[%1] = %0;\n\t" \
+ : /* no outputs */ \
+ :"d" (x),"a" (__ptr(p)) : "memory")
+
+#define get_user(x,p) \
+ ({ \
+ int _err = 0; \
+ typeof(*(p)) *_p = (p); \
+ if (!access_ok(VERIFY_READ, _p, sizeof(*(_p)))) { \
+ _err = -EFAULT; \
+ } \
+ else { \
+ switch (sizeof(*(_p))) { \
+ case 1: \
+ __get_user_asm(x, _p, B,(Z)); \
+ break; \
+ case 2: \
+ __get_user_asm(x, _p, W,(Z)); \
+ break; \
+ case 4: \
+ __get_user_asm(x, _p, , ); \
+ break; \
+ case 8: { \
+ unsigned long _xl, _xh; \
+ __get_user_asm(_xl, ((unsigned long *)_p)+0, , ); \
+ __get_user_asm(_xh, ((unsigned long *)_p)+1, , ); \
+ ((unsigned long *)&x)[0] = _xl; \
+ ((unsigned long *)&x)[1] = _xh; \
+ } break; \
+ default: \
+ x = 0; \
+ printk(KERN_INFO "get_user_bad: %s:%d %s\n", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ _err = __get_user_bad(); \
+ break; \
+ } \
+ } \
+ _err; \
+ })
+
+#define __get_user(x,p) get_user(x,p)
+
+#define __get_user_bad() (bad_user_access_length(), (-EFAULT))
+
+#define __get_user_asm(x,p,bhw,option) \
+ { \
+ unsigned long _tmp; \
+ __asm__ ("%0 =" #bhw "[%1]"#option";\n\t" \
+ : "=d" (_tmp) \
+ : "a" (__ptr(p))); \
+ (x) = (__typeof__(*(p))) _tmp; \
+ }
+
+#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
+#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
+
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n))\
+ return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n))\
+ return retval; })
+
+static inline long copy_from_user(void *to,
+ const void __user * from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ memcpy(to, from, n);
+ else
+ return n;
+ return 0;
+}
+
+static inline long copy_to_user(void *to,
+ const void __user * from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ memcpy(to, from, n);
+ else
+ return n;
+ return 0;
+}
+
+/*
+ * Copy a null terminated string from userspace.
+ */
+
+static inline long strncpy_from_user(char *dst,
+ const char *src, long count)
+{
+ char *tmp;
+ if (!access_ok(VERIFY_READ, src, 1))
+ return -EFAULT;
+ strncpy(dst, src, count);
+ for (tmp = dst; *tmp && count > 0; tmp++, count--) ;
+ return (tmp - dst);
+}
+
+/*
+ * Return the size of a string (including the ending 0)
+ *
+ * Return 0 on exception, a value greater than N if too long
+ */
+static inline long strnlen_user(const char *src, long n)
+{
+ return (strlen(src) + 1);
+}
+
+#define strlen_user(str) strnlen_user(str, 32767)
+
+/*
+ * Zero Userspace
+ */
+
+static inline unsigned long __clear_user(void *to, unsigned long n)
+{
+ memset(to, 0, n);
+ return 0;
+}
+
+#define clear_user(to, n) __clear_user(to, n)
+
+#endif /* _BLACKFIN_UACCESS_H */
diff --git a/include/asm-blackfin/ucontext.h b/include/asm-blackfin/ucontext.h
new file mode 100644
index 00000000000..4a4e3856beb
--- /dev/null
+++ b/include/asm-blackfin/ucontext.h
@@ -0,0 +1,17 @@
+/** Changes made by Tony Kou Lineo Inc. May 2001
+ *
+ * Based on: include/m68knommu/ucontext.h
+ */
+
+#ifndef _BLACKFIN_UCONTEXT_H
+#define _BLACKFIN_UCONTEXT_H
+
+struct ucontext {
+ unsigned long uc_flags; /* the others are necessary */
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+#endif /* _BLACKFIN_UCONTEXT_H */
diff --git a/include/asm-blackfin/unaligned.h b/include/asm-blackfin/unaligned.h
new file mode 100644
index 00000000000..10081dc241e
--- /dev/null
+++ b/include/asm-blackfin/unaligned.h
@@ -0,0 +1,6 @@
+#ifndef __BFIN_UNALIGNED_H
+#define __BFIN_UNALIGNED_H
+
+#include <asm-generic/unaligned.h>
+
+#endif /* __BFIN_UNALIGNED_H */
diff --git a/include/asm-blackfin/unistd.h b/include/asm-blackfin/unistd.h
new file mode 100644
index 00000000000..4df8790a67d
--- /dev/null
+++ b/include/asm-blackfin/unistd.h
@@ -0,0 +1,382 @@
+#ifndef __ASM_BFIN_UNISTD_H
+#define __ASM_BFIN_UNISTD_H
+/*
+ * This file contains the system call numbers.
+ */
+#define __NR_exit 1
+#define __NR_fork 2
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+ /* 7 __NR_waitpid obsolete */
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_chdir 12
+#define __NR_time 13
+#define __NR_mknod 14
+#define __NR_chmod 15
+#define __NR_chown 16
+ /* 17 __NR_break obsolete */
+ /* 18 __NR_oldstat obsolete */
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+ /* 22 __NR_umount obsolete */
+#define __NR_setuid 23
+#define __NR_getuid 24
+#define __NR_stime 25
+#define __NR_ptrace 26
+#define __NR_alarm 27
+ /* 28 __NR_oldfstat obsolete */
+#define __NR_pause 29
+ /* 30 __NR_utime obsolete */
+ /* 31 __NR_stty obsolete */
+ /* 32 __NR_gtty obsolete */
+#define __NR_access 33
+#define __NR_nice 34
+ /* 35 __NR_ftime obsolete */
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+ /* 44 __NR_prof obsolete */
+#define __NR_brk 45
+#define __NR_setgid 46
+#define __NR_getgid 47
+ /* 48 __NR_signal obsolete */
+#define __NR_geteuid 49
+#define __NR_getegid 50
+#define __NR_acct 51
+#define __NR_umount2 52
+ /* 53 __NR_lock obsolete */
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+ /* 56 __NR_mpx obsolete */
+#define __NR_setpgid 57
+ /* 58 __NR_ulimit obsolete */
+ /* 59 __NR_oldolduname obsolete */
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_getpgrp 65
+#define __NR_setsid 66
+ /* 67 __NR_sigaction obsolete */
+#define __NR_sgetmask 68
+#define __NR_ssetmask 69
+#define __NR_setreuid 70
+#define __NR_setregid 71
+ /* 72 __NR_sigsuspend obsolete */
+ /* 73 __NR_sigpending obsolete */
+#define __NR_sethostname 74
+#define __NR_setrlimit 75
+ /* 76 __NR_old_getrlimit obsolete */
+#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+#define __NR_settimeofday 79
+#define __NR_getgroups 80
+#define __NR_setgroups 81
+ /* 82 __NR_select obsolete */
+#define __NR_symlink 83
+ /* 84 __NR_oldlstat obsolete */
+#define __NR_readlink 85
+ /* 86 __NR_uselib obsolete */
+ /* 87 __NR_swapon obsolete */
+#define __NR_reboot 88
+ /* 89 __NR_readdir obsolete */
+ /* 90 __NR_mmap obsolete */
+#define __NR_munmap 91
+#define __NR_truncate 92
+#define __NR_ftruncate 93
+#define __NR_fchmod 94
+#define __NR_fchown 95
+#define __NR_getpriority 96
+#define __NR_setpriority 97
+ /* 98 __NR_profil obsolete */
+#define __NR_statfs 99
+#define __NR_fstatfs 100
+ /* 101 __NR_ioperm */
+ /* 102 __NR_socketcall obsolete */
+#define __NR_syslog 103
+#define __NR_setitimer 104
+#define __NR_getitimer 105
+#define __NR_stat 106
+#define __NR_lstat 107
+#define __NR_fstat 108
+ /* 109 __NR_olduname obsolete */
+ /* 110 __NR_iopl obsolete */
+#define __NR_vhangup 111
+ /* 112 __NR_idle obsolete */
+ /* 113 __NR_vm86old */
+#define __NR_wait4 114
+ /* 115 __NR_swapoff obsolete */
+#define __NR_sysinfo 116
+ /* 117 __NR_ipc oboslete */
+#define __NR_fsync 118
+ /* 119 __NR_sigreturn obsolete */
+#define __NR_clone 120
+#define __NR_setdomainname 121
+#define __NR_uname 122
+ /* 123 __NR_modify_ldt obsolete */
+#define __NR_adjtimex 124
+#define __NR_mprotect 125
+ /* 126 __NR_sigprocmask obsolete */
+ /* 127 __NR_create_module obsolete */
+#define __NR_init_module 128
+#define __NR_delete_module 129
+ /* 130 __NR_get_kernel_syms obsolete */
+#define __NR_quotactl 131
+#define __NR_getpgid 132
+#define __NR_fchdir 133
+#define __NR_bdflush 134
+ /* 135 was sysfs */
+#define __NR_personality 136
+ /* 137 __NR_afs_syscall */
+#define __NR_setfsuid 138
+#define __NR_setfsgid 139
+#define __NR__llseek 140
+#define __NR_getdents 141
+ /* 142 __NR__newselect obsolete */
+#define __NR_flock 143
+ /* 144 __NR_msync obsolete */
+#define __NR_readv 145
+#define __NR_writev 146
+#define __NR_getsid 147
+#define __NR_fdatasync 148
+#define __NR__sysctl 149
+ /* 150 __NR_mlock */
+ /* 151 __NR_munlock */
+ /* 152 __NR_mlockall */
+ /* 153 __NR_munlockall */
+#define __NR_sched_setparam 154
+#define __NR_sched_getparam 155
+#define __NR_sched_setscheduler 156
+#define __NR_sched_getscheduler 157
+#define __NR_sched_yield 158
+#define __NR_sched_get_priority_max 159
+#define __NR_sched_get_priority_min 160
+#define __NR_sched_rr_get_interval 161
+#define __NR_nanosleep 162
+ /* 163 __NR_mremap */
+#define __NR_setresuid 164
+#define __NR_getresuid 165
+ /* 166 __NR_vm86 */
+ /* 167 __NR_query_module */
+ /* 168 __NR_poll */
+ /* 169 __NR_nfsservctl */
+#define __NR_setresgid 170
+#define __NR_getresgid 171
+#define __NR_prctl 172
+#define __NR_rt_sigreturn 173
+#define __NR_rt_sigaction 174
+#define __NR_rt_sigprocmask 175
+#define __NR_rt_sigpending 176
+#define __NR_rt_sigtimedwait 177
+#define __NR_rt_sigqueueinfo 178
+#define __NR_rt_sigsuspend 179
+#define __NR_pread 180
+#define __NR_pwrite 181
+#define __NR_lchown 182
+#define __NR_getcwd 183
+#define __NR_capget 184
+#define __NR_capset 185
+#define __NR_sigaltstack 186
+#define __NR_sendfile 187
+ /* 188 __NR_getpmsg */
+ /* 189 __NR_putpmsg */
+#define __NR_vfork 190
+#define __NR_getrlimit 191
+#define __NR_mmap2 192
+#define __NR_truncate64 193
+#define __NR_ftruncate64 194
+#define __NR_stat64 195
+#define __NR_lstat64 196
+#define __NR_fstat64 197
+#define __NR_chown32 198
+#define __NR_getuid32 199
+#define __NR_getgid32 200
+#define __NR_geteuid32 201
+#define __NR_getegid32 202
+#define __NR_setreuid32 203
+#define __NR_setregid32 204
+#define __NR_getgroups32 205
+#define __NR_setgroups32 206
+#define __NR_fchown32 207
+#define __NR_setresuid32 208
+#define __NR_getresuid32 209
+#define __NR_setresgid32 210
+#define __NR_getresgid32 211
+#define __NR_lchown32 212
+#define __NR_setuid32 213
+#define __NR_setgid32 214
+#define __NR_setfsuid32 215
+#define __NR_setfsgid32 216
+#define __NR_pivot_root 217
+ /* 218 __NR_mincore */
+ /* 219 __NR_madvise */
+#define __NR_getdents64 220
+#define __NR_fcntl64 221
+ /* 222 reserved for TUX */
+ /* 223 reserved for TUX */
+#define __NR_gettid 224
+ /* 225 __NR_readahead */
+#define __NR_setxattr 226
+#define __NR_lsetxattr 227
+#define __NR_fsetxattr 228
+#define __NR_getxattr 229
+#define __NR_lgetxattr 230
+#define __NR_fgetxattr 231
+#define __NR_listxattr 232
+#define __NR_llistxattr 233
+#define __NR_flistxattr 234
+#define __NR_removexattr 235
+#define __NR_lremovexattr 236
+#define __NR_fremovexattr 237
+#define __NR_tkill 238
+#define __NR_sendfile64 239
+#define __NR_futex 240
+#define __NR_sched_setaffinity 241
+#define __NR_sched_getaffinity 242
+ /* 243 __NR_set_thread_area */
+ /* 244 __NR_get_thread_area */
+#define __NR_io_setup 245
+#define __NR_io_destroy 246
+#define __NR_io_getevents 247
+#define __NR_io_submit 248
+#define __NR_io_cancel 249
+ /* 250 __NR_alloc_hugepages */
+ /* 251 __NR_free_hugepages */
+#define __NR_exit_group 252
+#define __NR_lookup_dcookie 253
+#define __NR_bfin_spinlock 254
+
+#define __NR_epoll_create 255
+#define __NR_epoll_ctl 256
+#define __NR_epoll_wait 257
+ /* 258 __NR_remap_file_pages */
+#define __NR_set_tid_address 259
+#define __NR_timer_create 260
+#define __NR_timer_settime (__NR_timer_create+1)
+#define __NR_timer_gettime (__NR_timer_create+2)
+#define __NR_timer_getoverrun (__NR_timer_create+3)
+#define __NR_timer_delete (__NR_timer_create+4)
+#define __NR_clock_settime (__NR_timer_create+5)
+#define __NR_clock_gettime (__NR_timer_create+6)
+#define __NR_clock_getres (__NR_timer_create+7)
+#define __NR_clock_nanosleep (__NR_timer_create+8)
+#define __NR_statfs64 269
+#define __NR_fstatfs64 270
+#define __NR_tgkill 271
+#define __NR_utimes 272
+#define __NR_fadvise64_64 273
+ /* 274 __NR_vserver */
+ /* 275 __NR_mbind */
+ /* 276 __NR_get_mempolicy */
+ /* 277 __NR_set_mempolicy */
+#define __NR_mq_open 278
+#define __NR_mq_unlink (__NR_mq_open+1)
+#define __NR_mq_timedsend (__NR_mq_open+2)
+#define __NR_mq_timedreceive (__NR_mq_open+3)
+#define __NR_mq_notify (__NR_mq_open+4)
+#define __NR_mq_getsetattr (__NR_mq_open+5)
+ /* 284 __NR_sys_kexec_load */
+#define __NR_waitid 285
+#define __NR_add_key 286
+#define __NR_request_key 287
+#define __NR_keyctl 288
+#define __NR_ioprio_set 289
+#define __NR_ioprio_get 290
+#define __NR_inotify_init 291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch 293
+ /* 294 __NR_migrate_pages */
+#define __NR_openat 295
+#define __NR_mkdirat 296
+#define __NR_mknodat 297
+#define __NR_fchownat 298
+#define __NR_futimesat 299
+#define __NR_fstatat64 300
+#define __NR_unlinkat 301
+#define __NR_renameat 302
+#define __NR_linkat 303
+#define __NR_symlinkat 304
+#define __NR_readlinkat 305
+#define __NR_fchmodat 306
+#define __NR_faccessat 307
+#define __NR_pselect6 308
+#define __NR_ppoll 309
+#define __NR_unshare 310
+
+/* Blackfin private syscalls */
+#define __NR_sram_alloc 311
+#define __NR_sram_free 312
+#define __NR_dma_memcpy 313
+
+/* socket syscalls */
+#define __NR_accept 314
+#define __NR_bind 315
+#define __NR_connect 316
+#define __NR_getpeername 317
+#define __NR_getsockname 318
+#define __NR_getsockopt 319
+#define __NR_listen 320
+#define __NR_recv 321
+#define __NR_recvfrom 322
+#define __NR_recvmsg 323
+#define __NR_send 324
+#define __NR_sendmsg 325
+#define __NR_sendto 326
+#define __NR_setsockopt 327
+#define __NR_shutdown 328
+#define __NR_socket 329
+#define __NR_socketpair 330
+
+/* sysv ipc syscalls */
+#define __NR_semctl 331
+#define __NR_semget 332
+#define __NR_semop 333
+#define __NR_msgctl 334
+#define __NR_msgget 335
+#define __NR_msgrcv 336
+#define __NR_msgsnd 337
+#define __NR_shmat 338
+#define __NR_shmctl 339
+#define __NR_shmdt 340
+#define __NR_shmget 341
+
+#define __NR_syscall 342
+#define NR_syscalls __NR_syscall
+
+#ifdef __KERNEL__
+#define __ARCH_WANT_IPC_PARSE_VERSION
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_SGETMASK
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_FADVISE64
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t_" #x "\n\t.set\t_" #x ",_sys_ni_syscall");
+
+#endif /* __ASM_BFIN_UNISTD_H */
diff --git a/include/asm-blackfin/user.h b/include/asm-blackfin/user.h
new file mode 100644
index 00000000000..abc34629bd5
--- /dev/null
+++ b/include/asm-blackfin/user.h
@@ -0,0 +1,89 @@
+#ifndef _BFIN_USER_H
+#define _BFIN_USER_H
+
+/* Changes by Tony Kou Lineo, Inc. July, 2001
+ *
+ * Based include/asm-m68knommu/user.h
+ *
+ */
+
+/* Core file format: The core file is written in such a way that gdb
+ can understand it and provide useful information to the user (under
+ linux we use the 'trad-core' bfd). There are quite a number of
+ obstacles to being able to view the contents of the floating point
+ registers, and until these are solved you will not be able to view the
+ contents of them. Actually, you can read in the core file and look at
+ the contents of the user struct to find out what the floating point
+ registers contain.
+ The actual file contents are as follows:
+ UPAGE: 1 page consisting of a user struct that tells gdb what is present
+ in the file. Directly after this is a copy of the task_struct, which
+ is currently not used by gdb, but it may come in useful at some point.
+ All of the registers are stored as part of the upage. The upage should
+ always be only one page.
+ DATA: The data area is stored. We use current->end_text to
+ current->brk to pick up all of the user variables, plus any memory
+ that may have been malloced. No attempt is made to determine if a page
+ is demand-zero or if a page is totally unused, we just cover the entire
+ range. All of the addresses are rounded in such a way that an integral
+ number of pages is written.
+ STACK: We need the stack information in order to get a meaningful
+ backtrace. We need to write the data from (esp) to
+ current->start_stack, so we round each of these off in order to be able
+ to write an integer number of pages.
+ The minimum core file size is 3 pages, or 12288 bytes.
+*/
+struct user_bfinfp_struct {
+};
+
+/* This is the old layout of "struct pt_regs" as of Linux 1.x, and
+ is still the layout used by user (the new pt_regs doesn't have
+ all registers). */
+struct user_regs_struct {
+ long r0, r1, r2, r3, r4, r5, r6, r7;
+ long p0, p1, p2, p3, p4, p5, usp, fp;
+ long i0, i1, i2, i3;
+ long l0, l1, l2, l3;
+ long b0, b1, b2, b3;
+ long m0, m1, m2, m3;
+ long a0w, a1w;
+ long a0x, a1x;
+ unsigned long rets;
+ unsigned long astat;
+ unsigned long pc;
+ unsigned long orig_p0;
+};
+
+/* When the kernel dumps core, it starts by dumping the user struct -
+ this will be used by gdb to figure out where the data and stack segments
+ are within the file, and what virtual addresses to use. */
+
+struct user {
+/* We start with the registers, to mimic the way that "memory" is returned
+ from the ptrace(3,...) function. */
+
+ struct user_regs_struct regs; /* Where the registers are actually stored */
+
+/* The rest of this junk is to help gdb figure out what goes where */
+ unsigned long int u_tsize; /* Text segment size (pages). */
+ unsigned long int u_dsize; /* Data segment size (pages). */
+ unsigned long int u_ssize; /* Stack segment size (pages). */
+ unsigned long start_code; /* Starting virtual address of text. */
+ unsigned long start_stack; /* Starting virtual address of stack area.
+ This is actually the bottom of the stack,
+ the top of the stack is always found in the
+ esp register. */
+ long int signal; /* Signal that caused the core dump. */
+ int reserved; /* No longer used */
+ struct user_regs_struct *u_ar0;
+ /* Used by gdb to help find the values for */
+ /* the registers. */
+ unsigned long magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+};
+#define NBPG PAGE_SIZE
+#define UPAGES 1
+#define HOST_TEXT_START_ADDR (u.start_code)
+#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+
+#endif
diff --git a/include/asm-cris/kdebug.h b/include/asm-cris/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-cris/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-cris/mmu_context.h b/include/asm-cris/mmu_context.h
index e6e659dc757..72ba08dcfd1 100644
--- a/include/asm-cris/mmu_context.h
+++ b/include/asm-cris/mmu_context.h
@@ -1,6 +1,8 @@
#ifndef __CRIS_MMU_CONTEXT_H
#define __CRIS_MMU_CONTEXT_H
+#include <asm-generic/mm_hooks.h>
+
extern int init_new_context(struct task_struct *tsk, struct mm_struct *mm);
extern void get_mmu_context(struct mm_struct *mm);
extern void destroy_context(struct mm_struct *mm);
diff --git a/include/asm-frv/atomic.h b/include/asm-frv/atomic.h
index 066386ac238..d425d8d0ad7 100644
--- a/include/asm-frv/atomic.h
+++ b/include/asm-frv/atomic.h
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <asm/spr-regs.h>
+#include <asm/system.h>
#ifdef CONFIG_SMP
#error not SMP safe
@@ -258,85 +259,23 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
#define tas(ptr) (xchg((ptr), 1))
-/*****************************************************************************/
-/*
- * compare and conditionally exchange value with memory
- * - if (*ptr == test) then orig = *ptr; *ptr = test;
- * - if (*ptr != test) then orig = *ptr;
- */
-#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
-
-#define cmpxchg(ptr, test, new) \
-({ \
- __typeof__(ptr) __xg_ptr = (ptr); \
- __typeof__(*(ptr)) __xg_orig, __xg_tmp; \
- __typeof__(*(ptr)) __xg_test = (test); \
- __typeof__(*(ptr)) __xg_new = (new); \
- \
- switch (sizeof(__xg_orig)) { \
- case 4: \
- asm volatile( \
- "0: \n" \
- " orcc gr0,gr0,gr0,icc3 \n" \
- " ckeq icc3,cc7 \n" \
- " ld.p %M0,%1 \n" \
- " orcr cc7,cc7,cc3 \n" \
- " sub%I4cc %1,%4,%2,icc0 \n" \
- " bne icc0,#0,1f \n" \
- " cst.p %3,%M0 ,cc3,#1 \n" \
- " corcc gr29,gr29,gr0 ,cc3,#1 \n" \
- " beq icc3,#0,0b \n" \
- "1: \n" \
- : "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp) \
- : "r"(__xg_new), "NPr"(__xg_test) \
- : "memory", "cc7", "cc3", "icc3", "icc0" \
- ); \
- break; \
- \
- default: \
- __xg_orig = 0; \
- asm volatile("break"); \
- break; \
- } \
- \
- __xg_orig; \
-})
-
-#else
-
-extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
-
-#define cmpxchg(ptr, test, new) \
-({ \
- __typeof__(ptr) __xg_ptr = (ptr); \
- __typeof__(*(ptr)) __xg_orig; \
- __typeof__(*(ptr)) __xg_test = (test); \
- __typeof__(*(ptr)) __xg_new = (new); \
- \
- switch (sizeof(__xg_orig)) { \
- case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break; \
- default: \
- __xg_orig = 0; \
- asm volatile("break"); \
- break; \
- } \
- \
- __xg_orig; \
-})
-
-#endif
-
#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
diff --git a/include/asm-frv/kdebug.h b/include/asm-frv/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-frv/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-frv/mmu_context.h b/include/asm-frv/mmu_context.h
index 72edcaaccd5..c7daa395156 100644
--- a/include/asm-frv/mmu_context.h
+++ b/include/asm-frv/mmu_context.h
@@ -15,6 +15,7 @@
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 8a05aa16861..2687c771512 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -509,10 +509,6 @@ static inline int pte_file(pte_t pte)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-frv/scatterlist.h b/include/asm-frv/scatterlist.h
index fb38fd329a5..8e827fa853f 100644
--- a/include/asm-frv/scatterlist.h
+++ b/include/asm-frv/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef _ASM_SCATTERLIST_H
#define _ASM_SCATTERLIST_H
+#include <asm/types.h>
+
/*
* Drivers must set either ->address or (preferred) ->page and ->offset
* to indicate where data must be transferred to/from.
diff --git a/include/asm-frv/semaphore.h b/include/asm-frv/semaphore.h
index 907c5c3643c..09586528e00 100644
--- a/include/asm-frv/semaphore.h
+++ b/include/asm-frv/semaphore.h
@@ -20,8 +20,6 @@
#include <linux/spinlock.h>
#include <linux/rwsem.h>
-#define SEMAPHORE_DEBUG 0
-
/*
* the semaphore definition
* - if counter is >0 then there are tokens available on the semaphore for down to collect
@@ -32,12 +30,12 @@ struct semaphore {
unsigned counter;
spinlock_t wait_lock;
struct list_head wait_list;
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
unsigned __magic;
#endif
};
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
# define __SEM_DEBUG_INIT(name) , (long)&(name).__magic
#else
# define __SEM_DEBUG_INIT(name)
@@ -76,7 +74,7 @@ static inline void down(struct semaphore *sem)
{
unsigned long flags;
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
CHECK_MAGIC(sem->__magic);
#endif
@@ -95,7 +93,7 @@ static inline int down_interruptible(struct semaphore *sem)
unsigned long flags;
int ret = 0;
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
CHECK_MAGIC(sem->__magic);
#endif
@@ -119,7 +117,7 @@ static inline int down_trylock(struct semaphore *sem)
unsigned long flags;
int success = 0;
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
CHECK_MAGIC(sem->__magic);
#endif
@@ -136,7 +134,7 @@ static inline void up(struct semaphore *sem)
{
unsigned long flags;
-#if SEMAPHORE_DEBUG
+#ifdef CONFIG_DEBUG_SEMAPHORE
CHECK_MAGIC(sem->__magic);
#endif
diff --git a/include/asm-frv/system.h b/include/asm-frv/system.h
index 1166899317d..be303b3eef4 100644
--- a/include/asm-frv/system.h
+++ b/include/asm-frv/system.h
@@ -13,7 +13,6 @@
#define _ASM_SYSTEM_H
#include <linux/linkage.h>
-#include <asm/atomic.h>
struct thread_struct;
@@ -197,4 +196,73 @@ extern void free_initmem(void);
#define arch_align_stack(x) (x)
+/*****************************************************************************/
+/*
+ * compare and conditionally exchange value with memory
+ * - if (*ptr == test) then orig = *ptr; *ptr = test;
+ * - if (*ptr != test) then orig = *ptr;
+ */
+#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
+
+#define cmpxchg(ptr, test, new) \
+({ \
+ __typeof__(ptr) __xg_ptr = (ptr); \
+ __typeof__(*(ptr)) __xg_orig, __xg_tmp; \
+ __typeof__(*(ptr)) __xg_test = (test); \
+ __typeof__(*(ptr)) __xg_new = (new); \
+ \
+ switch (sizeof(__xg_orig)) { \
+ case 4: \
+ asm volatile( \
+ "0: \n" \
+ " orcc gr0,gr0,gr0,icc3 \n" \
+ " ckeq icc3,cc7 \n" \
+ " ld.p %M0,%1 \n" \
+ " orcr cc7,cc7,cc3 \n" \
+ " sub%I4cc %1,%4,%2,icc0 \n" \
+ " bne icc0,#0,1f \n" \
+ " cst.p %3,%M0 ,cc3,#1 \n" \
+ " corcc gr29,gr29,gr0 ,cc3,#1 \n" \
+ " beq icc3,#0,0b \n" \
+ "1: \n" \
+ : "+U"(*__xg_ptr), "=&r"(__xg_orig), "=&r"(__xg_tmp) \
+ : "r"(__xg_new), "NPr"(__xg_test) \
+ : "memory", "cc7", "cc3", "icc3", "icc0" \
+ ); \
+ break; \
+ \
+ default: \
+ __xg_orig = 0; \
+ asm volatile("break"); \
+ break; \
+ } \
+ \
+ __xg_orig; \
+})
+
+#else
+
+extern uint32_t __cmpxchg_32(uint32_t *v, uint32_t test, uint32_t new);
+
+#define cmpxchg(ptr, test, new) \
+({ \
+ __typeof__(ptr) __xg_ptr = (ptr); \
+ __typeof__(*(ptr)) __xg_orig; \
+ __typeof__(*(ptr)) __xg_test = (test); \
+ __typeof__(*(ptr)) __xg_new = (new); \
+ \
+ switch (sizeof(__xg_orig)) { \
+ case 4: __xg_orig = __cmpxchg_32(__xg_ptr, __xg_test, __xg_new); break; \
+ default: \
+ __xg_orig = 0; \
+ asm volatile("break"); \
+ break; \
+ } \
+ \
+ __xg_orig; \
+})
+
+#endif
+
+
#endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-frv/tlb.h b/include/asm-frv/tlb.h
index f94fe5cb9b3..cd458eb6d75 100644
--- a/include/asm-frv/tlb.h
+++ b/include/asm-frv/tlb.h
@@ -3,7 +3,11 @@
#include <asm/tlbflush.h>
+#ifdef CONFIG_MMU
+extern void check_pgt_cache(void);
+#else
#define check_pgt_cache() do {} while(0)
+#endif
/*
* we don't need any special per-pte or per-vma handling...
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index 584c0417ae4..d0ea6789b31 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -186,8 +186,8 @@
#define __NR_rt_sigtimedwait 177
#define __NR_rt_sigqueueinfo 178
#define __NR_rt_sigsuspend 179
-#define __NR_pread 180
-#define __NR_pwrite 181
+#define __NR_pread64 180
+#define __NR_pwrite64 181
#define __NR_chown 182
#define __NR_getcwd 183
#define __NR_capget 184
@@ -316,10 +316,20 @@
#define __NR_faccessat 307
#define __NR_pselect6 308
#define __NR_ppoll 309
+#define __NR_unshare 310
+#define __NR_set_robust_list 311
+#define __NR_get_robust_list 312
+#define __NR_splice 313
+#define __NR_sync_file_range 314
+#define __NR_tee 315
+#define __NR_vmsplice 316
+#define __NR_move_pages 317
+#define __NR_getcpu 318
+#define __NR_epoll_pwait 319
#ifdef __KERNEL__
-#define NR_syscalls 310
+#define NR_syscalls 320
#define __ARCH_WANT_IPC_PARSE_VERSION
/* #define __ARCH_WANT_OLD_READDIR */
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
index b7e4a0467cb..85fd0aa27a8 100644
--- a/include/asm-generic/atomic.h
+++ b/include/asm-generic/atomic.h
@@ -66,6 +66,76 @@ static inline void atomic_long_sub(long i, atomic_long_t *l)
atomic64_sub(i, v);
}
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return atomic64_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return atomic64_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return atomic64_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return atomic64_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return (long)atomic64_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return (long)atomic64_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return (long)atomic64_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return (long)atomic64_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+ atomic64_t *v = (atomic64_t *)l;
+
+ return (long)atomic64_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+ (atomic_cmpxchg((atomic64_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+ (atomic_xchg((atomic64_t *)(l), (new)))
+
#else /* BITS_PER_LONG == 64 */
typedef atomic_t atomic_long_t;
@@ -113,6 +183,76 @@ static inline void atomic_long_sub(long i, atomic_long_t *l)
atomic_sub(i, v);
}
+static inline int atomic_long_sub_and_test(long i, atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return atomic_sub_and_test(i, v);
+}
+
+static inline int atomic_long_dec_and_test(atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return atomic_dec_and_test(v);
+}
+
+static inline int atomic_long_inc_and_test(atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return atomic_inc_and_test(v);
+}
+
+static inline int atomic_long_add_negative(long i, atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return atomic_add_negative(i, v);
+}
+
+static inline long atomic_long_add_return(long i, atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return (long)atomic_add_return(i, v);
+}
+
+static inline long atomic_long_sub_return(long i, atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return (long)atomic_sub_return(i, v);
+}
+
+static inline long atomic_long_inc_return(atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return (long)atomic_inc_return(v);
+}
+
+static inline long atomic_long_dec_return(atomic_long_t *l)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return (long)atomic_dec_return(v);
+}
+
+static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u)
+{
+ atomic_t *v = (atomic_t *)l;
+
+ return (long)atomic_add_unless(v, a, u);
+}
+
+#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l))
+
+#define atomic_long_cmpxchg(l, old, new) \
+ (atomic_cmpxchg((atomic_t *)(l), (old), (new)))
+#define atomic_long_xchg(v, new) \
+ (atomic_xchg((atomic_t *)(l), (new)))
+
#endif /* BITS_PER_LONG == 64 */
#endif /* _ASM_GENERIC_ATOMIC_H */
diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h
index 78339319ba0..cd8a9641bd6 100644
--- a/include/asm-generic/bitops/atomic.h
+++ b/include/asm-generic/bitops/atomic.h
@@ -58,7 +58,7 @@ extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
* if you do not require the atomic guarantees.
*
* Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non x86 architectures, so if you are writing portable code,
* make sure not to rely on its reordering guarantees.
*
* Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-generic/kdebug.h b/include/asm-generic/kdebug.h
new file mode 100644
index 00000000000..2b799c90b2d
--- /dev/null
+++ b/include/asm-generic/kdebug.h
@@ -0,0 +1,8 @@
+#ifndef _ASM_GENERIC_KDEBUG_H
+#define _ASM_GENERIC_KDEBUG_H
+
+enum die_val {
+ DIE_UNUSED,
+};
+
+#endif /* _ASM_GENERIC_KDEBUG_H */
diff --git a/include/asm-generic/local.h b/include/asm-generic/local.h
index ab469297272..33d7d04e411 100644
--- a/include/asm-generic/local.h
+++ b/include/asm-generic/local.h
@@ -33,6 +33,19 @@ typedef struct
#define local_add(i,l) atomic_long_add((i),(&(l)->a))
#define local_sub(i,l) atomic_long_sub((i),(&(l)->a))
+#define local_sub_and_test(i, l) atomic_long_sub_and_test((i), (&(l)->a))
+#define local_dec_and_test(l) atomic_long_dec_and_test(&(l)->a)
+#define local_inc_and_test(l) atomic_long_inc_and_test(&(l)->a)
+#define local_add_negative(i, l) atomic_long_add_negative((i), (&(l)->a))
+#define local_add_return(i, l) atomic_long_add_return((i), (&(l)->a))
+#define local_sub_return(i, l) atomic_long_sub_return((i), (&(l)->a))
+#define local_inc_return(l) atomic_long_inc_return(&(l)->a)
+
+#define local_cmpxchg(l, o, n) atomic_long_cmpxchg((&(l)->a), (o), (n))
+#define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n))
+#define local_add_unless(l, a, u) atomic_long_add_unless((&(l)->a), (a), (u))
+#define local_inc_not_zero(l) atomic_long_inc_not_zero(&(l)->a)
+
/* Non-atomic variants, ie. preemption disabled and won't be touched
* in interrupt, etc. Some archs can optimize this case well. */
#define __local_inc(l) local_set((l), local_read(l) + 1)
@@ -44,19 +57,19 @@ typedef struct
* much more efficient than these naive implementations. Note they take
* a variable (eg. mystruct.foo), not an address.
*/
-#define cpu_local_read(v) local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
-#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
+#define cpu_local_read(l) local_read(&__get_cpu_var(l))
+#define cpu_local_set(l, i) local_set(&__get_cpu_var(l), (i))
+#define cpu_local_inc(l) local_inc(&__get_cpu_var(l))
+#define cpu_local_dec(l) local_dec(&__get_cpu_var(l))
+#define cpu_local_add(i, l) local_add((i), &__get_cpu_var(l))
+#define cpu_local_sub(i, l) local_sub((i), &__get_cpu_var(l))
/* Non-atomic increments, ie. preemption disabled and won't be touched
* in interrupt, etc. Some archs can optimize this case well.
*/
-#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
+#define __cpu_local_inc(l) __local_inc(&__get_cpu_var(l))
+#define __cpu_local_dec(l) __local_dec(&__get_cpu_var(l))
+#define __cpu_local_add(i, l) __local_add((i), &__get_cpu_var(l))
+#define __cpu_local_sub(i, l) __local_sub((i), &__get_cpu_var(l))
#endif /* _ASM_GENERIC_LOCAL_H */
diff --git a/include/asm-generic/mm_hooks.h b/include/asm-generic/mm_hooks.h
new file mode 100644
index 00000000000..67dea812368
--- /dev/null
+++ b/include/asm-generic/mm_hooks.h
@@ -0,0 +1,18 @@
+/*
+ * Define generic no-op hooks for arch_dup_mmap and arch_exit_mmap, to
+ * be included in asm-FOO/mmu_context.h for any arch FOO which doesn't
+ * need to hook these.
+ */
+#ifndef _ASM_GENERIC_MM_HOOKS_H
+#define _ASM_GENERIC_MM_HOOKS_H
+
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+ struct mm_struct *mm)
+{
+}
+
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+}
+
+#endif /* _ASM_GENERIC_MM_HOOKS_H */
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 19637626224..d984a904143 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -1,6 +1,7 @@
#ifndef _ASM_GENERIC_PERCPU_H_
#define _ASM_GENERIC_PERCPU_H_
#include <linux/compiler.h>
+#include <linux/threads.h>
#define __GENERIC_PER_CPU
#ifdef CONFIG_SMP
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 9fcc8d9fbb1..f3806a74c47 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -208,7 +208,7 @@
}
#define NOTES \
- .notes : { *(.note.*) } :note
+ .notes : { *(.note.*) } :note
#define INITCALLS \
*(.initcall0.init) \
diff --git a/include/asm-h8300/irq.h b/include/asm-h8300/irq.h
index 42a3ac424a9..41be646c351 100644
--- a/include/asm-h8300/irq.h
+++ b/include/asm-h8300/irq.h
@@ -61,6 +61,5 @@ static __inline__ int irq_canonicalize(int irq)
extern void enable_irq(unsigned int);
extern void disable_irq(unsigned int);
-#define disable_irq_nosync(x) disable_irq(x)
#endif /* _H8300_IRQ_H_ */
diff --git a/include/asm-h8300/irq_regs.h b/include/asm-h8300/irq_regs.h
new file mode 100644
index 00000000000..3dd9c0b7027
--- /dev/null
+++ b/include/asm-h8300/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-h8300/kdebug.h b/include/asm-h8300/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-h8300/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-h8300/mmu_context.h b/include/asm-h8300/mmu_context.h
index 5c165f7bee0..f44b730da54 100644
--- a/include/asm-h8300/mmu_context.h
+++ b/include/asm-h8300/mmu_context.h
@@ -4,6 +4,7 @@
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/include/asm-h8300/pgtable.h b/include/asm-h8300/pgtable.h
index 8b7c6857998..a09230a08e0 100644
--- a/include/asm-h8300/pgtable.h
+++ b/include/asm-h8300/pgtable.h
@@ -55,10 +55,6 @@ extern int is_in_rom(unsigned long);
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
@@ -73,4 +69,5 @@ extern int is_in_rom(unsigned long);
#define VMALLOC_START 0
#define VMALLOC_END 0xffffffff
+#define arch_enter_lazy_cpu_mode() do {} while (0)
#endif /* _H8300_PGTABLE_H */
diff --git a/include/asm-h8300/scatterlist.h b/include/asm-h8300/scatterlist.h
index 7627f0cd1a2..985fdf54eac 100644
--- a/include/asm-h8300/scatterlist.h
+++ b/include/asm-h8300/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef _H8300_SCATTERLIST_H
#define _H8300_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-h8300/system.h b/include/asm-h8300/system.h
index 5084a9d4292..7807018f850 100644
--- a/include/asm-h8300/system.h
+++ b/include/asm-h8300/system.h
@@ -98,7 +98,6 @@ asmlinkage void resume(void);
#endif
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
diff --git a/include/asm-i386/Kbuild b/include/asm-i386/Kbuild
index 5ae93afc67e..cbf6e8f1087 100644
--- a/include/asm-i386/Kbuild
+++ b/include/asm-i386/Kbuild
@@ -3,8 +3,10 @@ include include/asm-generic/Kbuild.asm
header-y += boot.h
header-y += debugreg.h
header-y += ldt.h
+header-y += msr-index.h
header-y += ptrace-abi.h
header-y += ucontext.h
+unifdef-y += msr.h
unifdef-y += mtrr.h
unifdef-y += vm86.h
diff --git a/include/asm-i386/agp.h b/include/asm-i386/agp.h
index 9075083bab7..6af173dbf12 100644
--- a/include/asm-i386/agp.h
+++ b/include/asm-i386/agp.h
@@ -12,8 +12,10 @@
* data corruption on some CPUs.
*/
-int map_page_into_agp(struct page *page);
-int unmap_page_from_agp(struct page *page);
+/* Caller's responsibility to call global_flush_tlb() for
+ * performance reasons */
+#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE)
+#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL)
#define flush_agp_mappings() global_flush_tlb()
/* Could use CLFLUSH here if the cpu supports it. But then it would
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index b8fa9557c53..0f70b379b02 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -1,8 +1,6 @@
#ifndef _I386_ALTERNATIVE_H
#define _I386_ALTERNATIVE_H
-#ifdef __KERNEL__
-
#include <asm/types.h>
#include <linux/stddef.h>
#include <linux/types.h>
@@ -16,6 +14,7 @@ struct alt_instr {
u8 pad;
};
+extern void alternative_instructions(void);
extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
struct module;
@@ -31,9 +30,7 @@ static inline void alternatives_smp_module_add(struct module *mod, char *name,
void *text, void *text_end) {}
static inline void alternatives_smp_module_del(struct module *mod) {}
static inline void alternatives_smp_switch(int smp) {}
-#endif
-
-#endif
+#endif /* CONFIG_SMP */
/*
* Alternative instructions for different CPU types or capabilities.
@@ -85,6 +82,21 @@ static inline void alternatives_smp_switch(int smp) {}
"663:\n\t" newinstr "\n664:\n" /* replacement */\
".previous" :: "i" (feature), ##input)
+/* Like alternative_input, but with a single output argument */
+#define alternative_io(oldinstr, newinstr, feature, output, input...) \
+ asm volatile ("661:\n\t" oldinstr "\n662:\n" \
+ ".section .altinstructions,\"a\"\n" \
+ " .align 4\n" \
+ " .long 661b\n" /* label */ \
+ " .long 663f\n" /* new instruction */ \
+ " .byte %c[feat]\n" /* feature bit */ \
+ " .byte 662b-661b\n" /* sourcelen */ \
+ " .byte 664f-663f\n" /* replacementlen */ \
+ ".previous\n" \
+ ".section .altinstr_replacement,\"ax\"\n" \
+ "663:\n\t" newinstr "\n664:\n" /* replacement */ \
+ ".previous" : output : [feat] "i" (feature), ##input)
+
/*
* Alternative inline assembly for SMP.
*
@@ -118,15 +130,17 @@ static inline void alternatives_smp_switch(int smp) {}
#define LOCK_PREFIX ""
#endif
-struct paravirt_patch;
+struct paravirt_patch_site;
#ifdef CONFIG_PARAVIRT
-void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end);
+void apply_paravirt(struct paravirt_patch_site *start,
+ struct paravirt_patch_site *end);
#else
static inline void
-apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
+apply_paravirt(struct paravirt_patch_site *start,
+ struct paravirt_patch_site *end)
{}
-#define __start_parainstructions NULL
-#define __stop_parainstructions NULL
+#define __parainstructions NULL
+#define __parainstructions_end NULL
#endif
#endif /* _I386_ALTERNATIVE_H */
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index a19810a08ae..1e8f6f252dd 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -2,6 +2,7 @@
#define __ASM_APIC_H
#include <linux/pm.h>
+#include <linux/delay.h>
#include <asm/fixmap.h>
#include <asm/apicdef.h>
#include <asm/processor.h>
@@ -64,12 +65,8 @@ static __inline fastcall unsigned long native_apic_read(unsigned long reg)
return *((volatile unsigned long *)(APIC_BASE+reg));
}
-static __inline__ void apic_wait_icr_idle(void)
-{
- while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY )
- cpu_relax();
-}
-
+void apic_wait_icr_idle(void);
+unsigned long safe_apic_wait_icr_idle(void);
int get_physical_broadcast(void);
#ifdef CONFIG_X86_GOOD_APIC
diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h
index 4dd27233136..0baa2f89463 100644
--- a/include/asm-i386/atomic.h
+++ b/include/asm-i386/atomic.h
@@ -3,6 +3,7 @@
#include <linux/compiler.h>
#include <asm/processor.h>
+#include <asm/cmpxchg.h>
/*
* Atomic operations that C can't guarantee us. Useful for
@@ -51,7 +52,7 @@ static __inline__ void atomic_add(int i, atomic_t *v)
}
/**
- * atomic_sub - subtract the atomic variable
+ * atomic_sub - subtract integer from atomic variable
* @i: integer value to subtract
* @v: pointer of type atomic_t
*
@@ -170,7 +171,7 @@ static __inline__ int atomic_add_negative(int i, atomic_t *v)
}
/**
- * atomic_add_return - add and return
+ * atomic_add_return - add integer and return
* @v: pointer of type atomic_t
* @i: integer value to add
*
@@ -202,13 +203,20 @@ no_xadd: /* Legacy 386 processor */
#endif
}
+/**
+ * atomic_sub_return - subtract integer and return
+ * @v: pointer of type atomic_t
+ * @i: integer value to subtract
+ *
+ * Atomically subtracts @i from @v and returns @v - @i
+ */
static __inline__ int atomic_sub_return(int i, atomic_t *v)
{
return atomic_add_return(-i,v);
}
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
/**
* atomic_add_unless - add unless the number is already a given value
@@ -219,20 +227,21 @@ static __inline__ int atomic_sub_return(int i, atomic_t *v)
* Atomically adds @a to @v, so long as @v was not already @u.
* Returns non-zero if @v was not @u, and zero otherwise.
*/
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- for (;;) { \
- if (unlikely(c == (u))) \
- break; \
- old = atomic_cmpxchg((v), c, c + (a)); \
- if (likely(old == c)) \
- break; \
- c = old; \
- } \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
#define atomic_inc_return(v) (atomic_add_return(1,v))
diff --git a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
index 273b5062935..a20fe9822f6 100644
--- a/include/asm-i386/bitops.h
+++ b/include/asm-i386/bitops.h
@@ -27,7 +27,7 @@
* if you do not require the atomic guarantees.
*
* Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non x86 architectures, so if you are writing portable code,
* make sure not to rely on its reordering guarantees.
*
* Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-i386/boot.h b/include/asm-i386/boot.h
index e7686d0a841..bd024ab4fe5 100644
--- a/include/asm-i386/boot.h
+++ b/include/asm-i386/boot.h
@@ -12,7 +12,7 @@
#define EXTENDED_VGA 0xfffe /* 80x50 mode */
#define ASK_VGA 0xfffd /* ask for it at bootup */
-/* Physical address where kenrel should be loaded. */
+/* Physical address where kernel should be loaded. */
#define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \
+ (CONFIG_PHYSICAL_ALIGN - 1)) \
& ~(CONFIG_PHYSICAL_ALIGN - 1))
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index c90c7c49930..d28979ff73b 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -1,198 +1,12 @@
/*
- * include/asm-i386/bugs.h
- *
- * Copyright (C) 1994 Linus Torvalds
- *
- * Cyrix stuff, June 1998 by:
- * - Rafael R. Reilova (moved everything from head.S),
- * <rreilova@ececs.uc.edu>
- * - Channing Corn (tests & fixes),
- * - Andrew D. Balsa (code cleanup).
- */
-
-/*
* This is included by init/main.c to check for architecture-dependent bugs.
*
* Needs:
* void check_bugs(void);
*/
+#ifndef _ASM_I386_BUG_H
+#define _ASM_I386_BUG_H
-#include <linux/init.h>
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/paravirt.h>
-
-static int __init no_halt(char *s)
-{
- boot_cpu_data.hlt_works_ok = 0;
- return 1;
-}
-
-__setup("no-hlt", no_halt);
-
-static int __init mca_pentium(char *s)
-{
- mca_pentium_flag = 1;
- return 1;
-}
-
-__setup("mca-pentium", mca_pentium);
-
-static int __init no_387(char *s)
-{
- boot_cpu_data.hard_math = 0;
- write_cr0(0xE | read_cr0());
- return 1;
-}
-
-__setup("no387", no_387);
-
-static double __initdata x = 4195835.0;
-static double __initdata y = 3145727.0;
-
-/*
- * This used to check for exceptions..
- * However, it turns out that to support that,
- * the XMM trap handlers basically had to
- * be buggy. So let's have a correct XMM trap
- * handler, and forget about printing out
- * some status at boot.
- *
- * We should really only care about bugs here
- * anyway. Not features.
- */
-static void __init check_fpu(void)
-{
- if (!boot_cpu_data.hard_math) {
-#ifndef CONFIG_MATH_EMULATION
- printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
- printk(KERN_EMERG "Giving up.\n");
- for (;;) ;
-#endif
- return;
- }
-
-/* trap_init() enabled FXSR and company _before_ testing for FP problems here. */
- /* Test for the divl bug.. */
- __asm__("fninit\n\t"
- "fldl %1\n\t"
- "fdivl %2\n\t"
- "fmull %2\n\t"
- "fldl %1\n\t"
- "fsubp %%st,%%st(1)\n\t"
- "fistpl %0\n\t"
- "fwait\n\t"
- "fninit"
- : "=m" (*&boot_cpu_data.fdiv_bug)
- : "m" (*&x), "m" (*&y));
- if (boot_cpu_data.fdiv_bug)
- printk("Hmm, FPU with FDIV bug.\n");
-}
-
-static void __init check_hlt(void)
-{
- if (paravirt_enabled())
- return;
-
- printk(KERN_INFO "Checking 'hlt' instruction... ");
- if (!boot_cpu_data.hlt_works_ok) {
- printk("disabled\n");
- return;
- }
- halt();
- halt();
- halt();
- halt();
- printk("OK.\n");
-}
-
-/*
- * Most 386 processors have a bug where a POPAD can lock the
- * machine even from user space.
- */
-
-static void __init check_popad(void)
-{
-#ifndef CONFIG_X86_POPAD_OK
- int res, inp = (int) &res;
-
- printk(KERN_INFO "Checking for popad bug... ");
- __asm__ __volatile__(
- "movl $12345678,%%eax; movl $0,%%edi; pusha; popa; movl (%%edx,%%edi),%%ecx "
- : "=&a" (res)
- : "d" (inp)
- : "ecx", "edi" );
- /* If this fails, it means that any user program may lock the CPU hard. Too bad. */
- if (res != 12345678) printk( "Buggy.\n" );
- else printk( "OK.\n" );
-#endif
-}
-
-/*
- * Check whether we are able to run this kernel safely on SMP.
- *
- * - In order to run on a i386, we need to be compiled for i386
- * (for due to lack of "invlpg" and working WP on a i386)
- * - In order to run on anything without a TSC, we need to be
- * compiled for a i486.
- * - In order to support the local APIC on a buggy Pentium machine,
- * we need to be compiled with CONFIG_X86_GOOD_APIC disabled,
- * which happens implicitly if compiled for a Pentium or lower
- * (unless an advanced selection of CPU features is used) as an
- * otherwise config implies a properly working local APIC without
- * the need to do extra reads from the APIC.
-*/
-
-static void __init check_config(void)
-{
-/*
- * We'd better not be a i386 if we're configured to use some
- * i486+ only features! (WP works in supervisor mode and the
- * new "invlpg" and "bswap" instructions)
- */
-#if defined(CONFIG_X86_WP_WORKS_OK) || defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_BSWAP)
- if (boot_cpu_data.x86 == 3)
- panic("Kernel requires i486+ for 'invlpg' and other features");
-#endif
-
-/*
- * If we configured ourselves for a TSC, we'd better have one!
- */
-#ifdef CONFIG_X86_TSC
- if (!cpu_has_tsc && !tsc_disable)
- panic("Kernel compiled for Pentium+, requires TSC feature!");
-#endif
-
-/*
- * If we were told we had a good local APIC, check for buggy Pentia,
- * i.e. all B steppings and the C2 stepping of P54C when using their
- * integrated APIC (see 11AP erratum in "Pentium Processor
- * Specification Update").
- */
-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_GOOD_APIC)
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL
- && cpu_has_apic
- && boot_cpu_data.x86 == 5
- && boot_cpu_data.x86_model == 2
- && (boot_cpu_data.x86_mask < 6 || boot_cpu_data.x86_mask == 11))
- panic("Kernel compiled for PMMX+, assumes a local APIC without the read-before-write bug!");
-#endif
-}
-
-extern void alternative_instructions(void);
+void check_bugs(void);
-static void __init check_bugs(void)
-{
- identify_cpu(&boot_cpu_data);
-#ifndef CONFIG_SMP
- printk("CPU: ");
- print_cpu_info(&boot_cpu_data);
-#endif
- check_config();
- check_fpu();
- check_hlt();
- check_popad();
- init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
- alternative_instructions();
-}
+#endif /* _ASM_I386_BUG_H */
diff --git a/include/asm-i386/cmpxchg.h b/include/asm-i386/cmpxchg.h
new file mode 100644
index 00000000000..7adcef0cd53
--- /dev/null
+++ b/include/asm-i386/cmpxchg.h
@@ -0,0 +1,293 @@
+#ifndef __ASM_CMPXCHG_H
+#define __ASM_CMPXCHG_H
+
+#include <linux/bitops.h> /* for LOCK_PREFIX */
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((struct __xchg_dummy *)(x))
+
+
+#ifdef CONFIG_X86_CMPXCHG64
+
+/*
+ * The semantics of XCHGCMP8B are a bit strange, this is why
+ * there is a loop and the loading of %%eax and %%edx has to
+ * be inside. This inlines well in most cases, the cached
+ * cost is around ~38 cycles. (in the future we might want
+ * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
+ * might have an implicit FPU-save as a cost, so it's not
+ * clear which path to go.)
+ *
+ * cmpxchg8b must be used with the lock prefix here to allow
+ * the instruction to be executed atomically, see page 3-102
+ * of the instruction set reference 24319102.pdf. We need
+ * the reader side to see the coherent 64bit value.
+ */
+static inline void __set_64bit (unsigned long long * ptr,
+ unsigned int low, unsigned int high)
+{
+ __asm__ __volatile__ (
+ "\n1:\t"
+ "movl (%0), %%eax\n\t"
+ "movl 4(%0), %%edx\n\t"
+ "lock cmpxchg8b (%0)\n\t"
+ "jnz 1b"
+ : /* no outputs */
+ : "D"(ptr),
+ "b"(low),
+ "c"(high)
+ : "ax","dx","memory");
+}
+
+static inline void __set_64bit_constant (unsigned long long *ptr,
+ unsigned long long value)
+{
+ __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
+}
+#define ll_low(x) *(((unsigned int*)&(x))+0)
+#define ll_high(x) *(((unsigned int*)&(x))+1)
+
+static inline void __set_64bit_var (unsigned long long *ptr,
+ unsigned long long value)
+{
+ __set_64bit(ptr,ll_low(value), ll_high(value));
+}
+
+#define set_64bit(ptr,value) \
+(__builtin_constant_p(value) ? \
+ __set_64bit_constant(ptr, value) : \
+ __set_64bit_var(ptr, value) )
+
+#define _set_64bit(ptr,value) \
+(__builtin_constant_p(value) ? \
+ __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
+ __set_64bit(ptr, ll_low(value), ll_high(value)) )
+
+#endif
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ * but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("xchgb %b0,%1"
+ :"=q" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 2:
+ __asm__ __volatile__("xchgw %w0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 4:
+ __asm__ __volatile__("xchgl %0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ }
+ return x;
+}
+
+/*
+ * Atomic compare and exchange. Compare OLD with MEM, if identical,
+ * store NEW in MEM. Return the initial value in MEM. Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#ifdef CONFIG_X86_CMPXCHG
+#define __HAVE_ARCH_CMPXCHG 1
+#define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+#define sync_cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg_local(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+#endif
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+/*
+ * Always use locked operations when touching memory shared with a
+ * hypervisor, since the system may be SMP even if the guest kernel
+ * isn't.
+ */
+static inline unsigned long __sync_cmpxchg(volatile void *ptr,
+ unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("lock; cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__("lock; cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__("lock; cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+ unsigned long old, unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__("cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__("cmpxchgl %1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+#ifndef CONFIG_X86_CMPXCHG
+/*
+ * Building a kernel capable running on 80386. It may be necessary to
+ * simulate the cmpxchg on the 80386 CPU. For that purpose we define
+ * a function for each of the sizes we support.
+ */
+
+extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
+extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
+extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
+
+static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ switch (size) {
+ case 1:
+ return cmpxchg_386_u8(ptr, old, new);
+ case 2:
+ return cmpxchg_386_u16(ptr, old, new);
+ case 4:
+ return cmpxchg_386_u32(ptr, old, new);
+ }
+ return old;
+}
+
+#define cmpxchg(ptr,o,n) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ if (likely(boot_cpu_data.x86 > 3)) \
+ __ret = __cmpxchg((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))); \
+ else \
+ __ret = cmpxchg_386((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))); \
+ __ret; \
+})
+#define cmpxchg_local(ptr,o,n) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ if (likely(boot_cpu_data.x86 > 3)) \
+ __ret = __cmpxchg_local((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))); \
+ else \
+ __ret = cmpxchg_386((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))); \
+ __ret; \
+})
+#endif
+
+#ifdef CONFIG_X86_CMPXCHG64
+
+static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
+ unsigned long long new)
+{
+ unsigned long long prev;
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3"
+ : "=A"(prev)
+ : "b"((unsigned long)new),
+ "c"((unsigned long)(new >> 32)),
+ "m"(*__xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+}
+
+static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
+ unsigned long long old, unsigned long long new)
+{
+ unsigned long long prev;
+ __asm__ __volatile__("cmpxchg8b %3"
+ : "=A"(prev)
+ : "b"((unsigned long)new),
+ "c"((unsigned long)(new >> 32)),
+ "m"(*__xg(ptr)),
+ "0"(old)
+ : "memory");
+ return prev;
+}
+
+#define cmpxchg64(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
+ (unsigned long long)(n)))
+#define cmpxchg64_local(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
+ (unsigned long long)(n)))
+#endif
+
+#endif
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index d1b8e4ab6c1..f514e906643 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -7,7 +7,10 @@
#ifndef __ASM_I386_CPUFEATURE_H
#define __ASM_I386_CPUFEATURE_H
+#ifndef __ASSEMBLY__
#include <linux/bitops.h>
+#endif
+#include <asm/required-features.h>
#define NCAPINTS 7 /* N 32-bit words worth of info */
@@ -49,6 +52,7 @@
#define X86_FEATURE_MP (1*32+19) /* MP Capable. */
#define X86_FEATURE_NX (1*32+20) /* Execute Disable */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
+#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */
#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */
@@ -76,6 +80,7 @@
#define X86_FEATURE_PEBS (3*32+12) /* Precise-Event Based Sampling */
#define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */
#define X86_FEATURE_LAPIC_TIMER_BROKEN (3*32+ 14) /* lapic timer broken in C1 */
+#define X86_FEATURE_SYNC_RDTSC (3*32+15) /* RDTSC synchronizes the CPU */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
@@ -103,8 +108,12 @@
#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */
#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
-#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
-#define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability)
+#define cpu_has(c, bit) \
+ ((__builtin_constant_p(bit) && (bit) < 32 && \
+ (1UL << (bit)) & REQUIRED_MASK1) ? \
+ 1 : \
+ test_bit(bit, (c)->x86_capability))
+#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
#define cpu_has_fpu boot_cpu_has(X86_FEATURE_FPU)
#define cpu_has_vme boot_cpu_has(X86_FEATURE_VME)
diff --git a/include/asm-i386/current.h b/include/asm-i386/current.h
index 5252ee0f6d7..d3524853991 100644
--- a/include/asm-i386/current.h
+++ b/include/asm-i386/current.h
@@ -1,14 +1,15 @@
#ifndef _I386_CURRENT_H
#define _I386_CURRENT_H
-#include <asm/pda.h>
#include <linux/compiler.h>
+#include <asm/percpu.h>
struct task_struct;
+DECLARE_PER_CPU(struct task_struct *, current_task);
static __always_inline struct task_struct *get_current(void)
{
- return read_pda(pcurrent);
+ return x86_read_percpu(current_task);
}
#define current get_current()
diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h
index 050831f34f7..c547403f341 100644
--- a/include/asm-i386/desc.h
+++ b/include/asm-i386/desc.h
@@ -12,23 +12,24 @@
#include <asm/mmu.h>
-extern struct desc_struct cpu_gdt_table[GDT_ENTRIES];
-
struct Xgt_desc_struct {
unsigned short size;
unsigned long address __attribute__((packed));
unsigned short pad;
} __attribute__ ((packed));
-extern struct Xgt_desc_struct idt_descr;
-DECLARE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr);
-extern struct Xgt_desc_struct early_gdt_descr;
+struct gdt_page
+{
+ struct desc_struct gdt[GDT_ENTRIES];
+} __attribute__((aligned(PAGE_SIZE)));
+DECLARE_PER_CPU(struct gdt_page, gdt_page);
static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu)
{
- return (struct desc_struct *)per_cpu(cpu_gdt_descr, cpu).address;
+ return per_cpu(gdt_page, cpu).gdt;
}
+extern struct Xgt_desc_struct idt_descr;
extern struct desc_struct idt_table[];
extern void set_intr_gate(unsigned int irq, void * addr);
@@ -58,45 +59,33 @@ static inline void pack_gate(__u32 *a, __u32 *b,
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else
-#define load_TR_desc() __asm__ __volatile__("ltr %w0"::"q" (GDT_ENTRY_TSS*8))
-
-#define load_gdt(dtr) __asm__ __volatile("lgdt %0"::"m" (*dtr))
-#define load_idt(dtr) __asm__ __volatile("lidt %0"::"m" (*dtr))
+#define load_TR_desc() native_load_tr_desc()
+#define load_gdt(dtr) native_load_gdt(dtr)
+#define load_idt(dtr) native_load_idt(dtr)
#define load_tr(tr) __asm__ __volatile("ltr %0"::"m" (tr))
#define load_ldt(ldt) __asm__ __volatile("lldt %0"::"m" (ldt))
-#define store_gdt(dtr) __asm__ ("sgdt %0":"=m" (*dtr))
-#define store_idt(dtr) __asm__ ("sidt %0":"=m" (*dtr))
-#define store_tr(tr) __asm__ ("str %0":"=m" (tr))
+#define store_gdt(dtr) native_store_gdt(dtr)
+#define store_idt(dtr) native_store_idt(dtr)
+#define store_tr(tr) (tr = native_store_tr())
#define store_ldt(ldt) __asm__ ("sldt %0":"=m" (ldt))
-#if TLS_SIZE != 24
-# error update this code.
-#endif
-
-static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
-{
-#define C(i) get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]
- C(0); C(1); C(2);
-#undef C
-}
+#define load_TLS(t, cpu) native_load_tls(t, cpu)
+#define set_ldt native_set_ldt
#define write_ldt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b)
#define write_gdt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b)
#define write_idt_entry(dt, entry, a, b) write_dt_entry(dt, entry, a, b)
+#endif
-static inline void write_dt_entry(void *dt, int entry, __u32 entry_a, __u32 entry_b)
+static inline void write_dt_entry(struct desc_struct *dt,
+ int entry, u32 entry_low, u32 entry_high)
{
- __u32 *lp = (__u32 *)((char *)dt + entry*8);
- *lp = entry_a;
- *(lp+1) = entry_b;
+ dt[entry].a = entry_low;
+ dt[entry].b = entry_high;
}
-#define set_ldt native_set_ldt
-#endif /* CONFIG_PARAVIRT */
-
-static inline fastcall void native_set_ldt(const void *addr,
- unsigned int entries)
+static inline void native_set_ldt(const void *addr, unsigned int entries)
{
if (likely(entries == 0))
__asm__ __volatile__("lldt %w0"::"q" (0));
@@ -112,6 +101,48 @@ static inline fastcall void native_set_ldt(const void *addr,
}
}
+
+static inline void native_load_tr_desc(void)
+{
+ asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8));
+}
+
+static inline void native_load_gdt(const struct Xgt_desc_struct *dtr)
+{
+ asm volatile("lgdt %0"::"m" (*dtr));
+}
+
+static inline void native_load_idt(const struct Xgt_desc_struct *dtr)
+{
+ asm volatile("lidt %0"::"m" (*dtr));
+}
+
+static inline void native_store_gdt(struct Xgt_desc_struct *dtr)
+{
+ asm ("sgdt %0":"=m" (*dtr));
+}
+
+static inline void native_store_idt(struct Xgt_desc_struct *dtr)
+{
+ asm ("sidt %0":"=m" (*dtr));
+}
+
+static inline unsigned long native_store_tr(void)
+{
+ unsigned long tr;
+ asm ("str %0":"=r" (tr));
+ return tr;
+}
+
+static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+ unsigned int i;
+ struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+
+ for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
+ gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i];
+}
+
static inline void _set_gate(int gate, unsigned int type, void *addr, unsigned short seg)
{
__u32 a, b;
diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
index c5b8fc6109d..096a2a8eb1d 100644
--- a/include/asm-i386/e820.h
+++ b/include/asm-i386/e820.h
@@ -38,6 +38,7 @@ extern struct e820map e820;
extern int e820_all_mapped(unsigned long start, unsigned long end,
unsigned type);
+extern int e820_any_mapped(u64 start, u64 end, unsigned type);
extern void find_max_pfn(void);
extern void register_bootmem_low_pages(unsigned long max_low_pfn);
extern void e820_register_memory(void);
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index 952b3ee3c9b..b32df3a332d 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -9,8 +9,6 @@
#include <asm/user.h>
#include <asm/auxvec.h>
-#include <linux/utsname.h>
-
#define R_386_NONE 0
#define R_386_32 1
#define R_386_PC32 2
@@ -133,39 +131,31 @@ extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct
#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
#define VDSO_HIGH_BASE (__fix_to_virt(FIX_VDSO))
-#define VDSO_BASE ((unsigned long)current->mm->context.vdso)
-
-#ifdef CONFIG_COMPAT_VDSO
-# define VDSO_COMPAT_BASE VDSO_HIGH_BASE
-# define VDSO_PRELINK VDSO_HIGH_BASE
-#else
-# define VDSO_COMPAT_BASE VDSO_BASE
-# define VDSO_PRELINK 0
-#endif
+#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso)
+#define VDSO_PRELINK 0
#define VDSO_SYM(x) \
- (VDSO_COMPAT_BASE + (unsigned long)(x) - VDSO_PRELINK)
+ (VDSO_CURRENT_BASE + (unsigned long)(x) - VDSO_PRELINK)
#define VDSO_HIGH_EHDR ((const struct elfhdr *) VDSO_HIGH_BASE)
-#define VDSO_EHDR ((const struct elfhdr *) VDSO_COMPAT_BASE)
+#define VDSO_EHDR ((const struct elfhdr *) VDSO_CURRENT_BASE)
extern void __kernel_vsyscall;
#define VDSO_ENTRY VDSO_SYM(&__kernel_vsyscall)
-#ifndef CONFIG_COMPAT_VDSO
-#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
struct linux_binprm;
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
int executable_stack);
-#endif
extern unsigned int vdso_enabled;
-#define ARCH_DLINFO \
-do if (vdso_enabled) { \
- NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
- NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
+#define ARCH_DLINFO \
+do if (vdso_enabled) { \
+ NEW_AUX_ENT(AT_SYSINFO, VDSO_ENTRY); \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE); \
} while (0)
#endif
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 3e9f610c35d..80ea052ee3a 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -19,13 +19,9 @@
* Leave one empty page between vmalloc'ed areas and
* the start of the fixmap.
*/
-#ifndef CONFIG_COMPAT_VDSO
extern unsigned long __FIXADDR_TOP;
-#else
-#define __FIXADDR_TOP 0xfffff000
-#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO)
-#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1)
-#endif
+#define FIXADDR_USER_START __fix_to_virt(FIX_VDSO)
+#define FIXADDR_USER_END __fix_to_virt(FIX_VDSO - 1)
#ifndef __ASSEMBLY__
#include <linux/kernel.h>
@@ -88,6 +84,9 @@ enum fixed_addresses {
#ifdef CONFIG_PCI_MMCONFIG
FIX_PCIE_MCFG,
#endif
+#ifdef CONFIG_PARAVIRT
+ FIX_PARAVIRT_BOOTMAP,
+#endif
__end_of_permanent_fixed_addresses,
/* temporary boot-time mappings, used before ioremap() is functional */
#define NR_FIX_BTMAPS 16
diff --git a/include/asm-i386/genapic.h b/include/asm-i386/genapic.h
index fd2be593b06..33e3ffe1766 100644
--- a/include/asm-i386/genapic.h
+++ b/include/asm-i386/genapic.h
@@ -36,7 +36,7 @@ struct genapic {
void (*init_apic_ldr)(void);
physid_mask_t (*ioapic_phys_id_map)(physid_mask_t map);
- void (*clustered_apic_check)(void);
+ void (*setup_apic_routing)(void);
int (*multi_timer_check)(int apic, int irq);
int (*apicid_to_node)(int logical_apicid);
int (*cpu_to_logical_apicid)(int cpu);
@@ -99,7 +99,7 @@ struct genapic {
APICFUNC(check_apicid_present) \
APICFUNC(init_apic_ldr) \
APICFUNC(ioapic_phys_id_map) \
- APICFUNC(clustered_apic_check) \
+ APICFUNC(setup_apic_routing) \
APICFUNC(multi_timer_check) \
APICFUNC(apicid_to_node) \
APICFUNC(cpu_to_logical_apicid) \
@@ -122,6 +122,6 @@ struct genapic {
APICFUNC(phys_pkg_id) \
}
-extern struct genapic *genapic, apic_default;
+extern struct genapic *genapic;
#endif
diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
index e9a34ebc25d..13cdcd66fff 100644
--- a/include/asm-i386/highmem.h
+++ b/include/asm-i386/highmem.h
@@ -24,6 +24,7 @@
#include <linux/threads.h>
#include <asm/kmap_types.h>
#include <asm/tlbflush.h>
+#include <asm/paravirt.h>
/* declarations for highmem.c */
extern unsigned long highstart_pfn, highend_pfn;
@@ -67,11 +68,16 @@ extern void FASTCALL(kunmap_high(struct page *page));
void *kmap(struct page *page);
void kunmap(struct page *page);
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *kvaddr, enum km_type type);
void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
struct page *kmap_atomic_to_page(void *ptr);
+#ifndef CONFIG_PARAVIRT
+#define kmap_atomic_pte(page, type) kmap_atomic(page, type)
+#endif
+
#define flush_cache_kmaps() do { } while (0)
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
index fc03cf9de5c..dddeedf504b 100644
--- a/include/asm-i386/hpet.h
+++ b/include/asm-i386/hpet.h
@@ -28,8 +28,6 @@
#include <linux/timex.h>
-#include <asm/fixmap.h>
-
/*
* Documentation on HPET can be found at:
* http://www.intel.com/ial/home/sp/pcmmspec.htm
diff --git a/include/asm-i386/i387.h b/include/asm-i386/i387.h
index 434936c732d..cdd1e248e3b 100644
--- a/include/asm-i386/i387.h
+++ b/include/asm-i386/i387.h
@@ -74,17 +74,18 @@ static inline void __save_init_fpu( struct task_struct *tsk )
task_thread_info(tsk)->status &= ~TS_USEDFPU;
}
-#define __unlazy_fpu( tsk ) do { \
- if (task_thread_info(tsk)->status & TS_USEDFPU) \
- save_init_fpu( tsk ); \
- else \
- tsk->fpu_counter = 0; \
+#define __unlazy_fpu( tsk ) do { \
+ if (task_thread_info(tsk)->status & TS_USEDFPU) { \
+ __save_init_fpu(tsk); \
+ stts(); \
+ } else \
+ tsk->fpu_counter = 0; \
} while (0)
#define __clear_fpu( tsk ) \
do { \
- if (task_thread_info(tsk)->status & TS_USEDFPU) { \
- asm volatile("fnclex ; fwait"); \
+ if (task_thread_info(tsk)->status & TS_USEDFPU) { \
+ asm volatile("fnclex ; fwait"); \
task_thread_info(tsk)->status &= ~TS_USEDFPU; \
stts(); \
} \
@@ -113,7 +114,7 @@ static inline void save_init_fpu( struct task_struct *tsk )
__clear_fpu( tsk ); \
preempt_enable(); \
} while (0)
- \
+
/*
* FPU state interaction...
*/
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index 59fe616933c..e797586a5bf 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -250,19 +250,22 @@ static inline void flush_write_buffers(void)
#endif /* __KERNEL__ */
+static inline void native_io_delay(void)
+{
+ asm volatile("outb %%al,$0x80" : : : "memory");
+}
+
#if defined(CONFIG_PARAVIRT)
#include <asm/paravirt.h>
#else
-#define __SLOW_DOWN_IO "outb %%al,$0x80;"
-
static inline void slow_down_io(void) {
- __asm__ __volatile__(
- __SLOW_DOWN_IO
+ native_io_delay();
#ifdef REALLY_SLOW_IO
- __SLOW_DOWN_IO __SLOW_DOWN_IO __SLOW_DOWN_IO
+ native_io_delay();
+ native_io_delay();
+ native_io_delay();
#endif
- : : );
}
#endif
diff --git a/include/asm-i386/ioctls.h b/include/asm-i386/ioctls.h
index f962fadab0f..ef5878762dc 100644
--- a/include/asm-i386/ioctls.h
+++ b/include/asm-i386/ioctls.h
@@ -47,6 +47,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h
index 11761cdaae1..9e15ce0006e 100644
--- a/include/asm-i386/irq.h
+++ b/include/asm-i386/irq.h
@@ -37,8 +37,6 @@ static __inline__ int irq_canonicalize(int irq)
extern int irqbalance_disable(char *str);
#endif
-extern void quirk_intel_irqbalance(void);
-
#ifdef CONFIG_HOTPLUG_CPU
extern void fixup_irqs(cpumask_t map);
#endif
diff --git a/include/asm-i386/irq_regs.h b/include/asm-i386/irq_regs.h
index a1b3f7f594a..3368b20c0b4 100644
--- a/include/asm-i386/irq_regs.h
+++ b/include/asm-i386/irq_regs.h
@@ -1,25 +1,27 @@
/*
* Per-cpu current frame pointer - the location of the last exception frame on
- * the stack, stored in the PDA.
+ * the stack, stored in the per-cpu area.
*
* Jeremy Fitzhardinge <jeremy@goop.org>
*/
#ifndef _ASM_I386_IRQ_REGS_H
#define _ASM_I386_IRQ_REGS_H
-#include <asm/pda.h>
+#include <asm/percpu.h>
+
+DECLARE_PER_CPU(struct pt_regs *, irq_regs);
static inline struct pt_regs *get_irq_regs(void)
{
- return read_pda(irq_regs);
+ return x86_read_percpu(irq_regs);
}
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
{
struct pt_regs *old_regs;
- old_regs = read_pda(irq_regs);
- write_pda(irq_regs, new_regs);
+ old_regs = get_irq_regs();
+ x86_write_percpu(irq_regs, new_regs);
return old_regs;
}
diff --git a/include/asm-i386/irqflags.h b/include/asm-i386/irqflags.h
index 17b18cf4fe9..eff8585cb74 100644
--- a/include/asm-i386/irqflags.h
+++ b/include/asm-i386/irqflags.h
@@ -9,6 +9,43 @@
*/
#ifndef _ASM_IRQFLAGS_H
#define _ASM_IRQFLAGS_H
+#include <asm/processor-flags.h>
+
+#ifndef __ASSEMBLY__
+static inline unsigned long native_save_fl(void)
+{
+ unsigned long f;
+ asm volatile("pushfl ; popl %0":"=g" (f): /* no input */);
+ return f;
+}
+
+static inline void native_restore_fl(unsigned long f)
+{
+ asm volatile("pushl %0 ; popfl": /* no output */
+ :"g" (f)
+ :"memory", "cc");
+}
+
+static inline void native_irq_disable(void)
+{
+ asm volatile("cli": : :"memory");
+}
+
+static inline void native_irq_enable(void)
+{
+ asm volatile("sti": : :"memory");
+}
+
+static inline void native_safe_halt(void)
+{
+ asm volatile("sti; hlt": : :"memory");
+}
+
+static inline void native_halt(void)
+{
+ asm volatile("hlt": : :"memory");
+}
+#endif /* __ASSEMBLY__ */
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
@@ -17,35 +54,22 @@
static inline unsigned long __raw_local_save_flags(void)
{
- unsigned long flags;
-
- __asm__ __volatile__(
- "pushfl ; popl %0"
- : "=g" (flags)
- : /* no input */
- );
-
- return flags;
+ return native_save_fl();
}
static inline void raw_local_irq_restore(unsigned long flags)
{
- __asm__ __volatile__(
- "pushl %0 ; popfl"
- : /* no output */
- :"g" (flags)
- :"memory", "cc"
- );
+ native_restore_fl(flags);
}
static inline void raw_local_irq_disable(void)
{
- __asm__ __volatile__("cli" : : : "memory");
+ native_irq_disable();
}
static inline void raw_local_irq_enable(void)
{
- __asm__ __volatile__("sti" : : : "memory");
+ native_irq_enable();
}
/*
@@ -54,7 +78,7 @@ static inline void raw_local_irq_enable(void)
*/
static inline void raw_safe_halt(void)
{
- __asm__ __volatile__("sti; hlt" : : : "memory");
+ native_safe_halt();
}
/*
@@ -63,7 +87,7 @@ static inline void raw_safe_halt(void)
*/
static inline void halt(void)
{
- __asm__ __volatile__("hlt": : :"memory");
+ native_halt();
}
/*
@@ -96,7 +120,7 @@ static inline unsigned long __raw_local_irq_save(void)
static inline int raw_irqs_disabled_flags(unsigned long flags)
{
- return !(flags & (1 << 9));
+ return !(flags & X86_EFLAGS_IF);
}
static inline int raw_irqs_disabled(void)
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
index d18cdb9fc9a..05c3117788b 100644
--- a/include/asm-i386/kdebug.h
+++ b/include/asm-i386/kdebug.h
@@ -9,19 +9,8 @@
struct pt_regs;
-struct die_args {
- struct pt_regs *regs;
- const char *str;
- long err;
- int trapnr;
- int signr;
-};
-
-extern int register_die_notifier(struct notifier_block *);
-extern int unregister_die_notifier(struct notifier_block *);
extern int register_page_fault_notifier(struct notifier_block *);
extern int unregister_page_fault_notifier(struct notifier_block *);
-extern struct atomic_notifier_head i386die_chain;
/* Grossly misnamed. */
@@ -38,20 +27,8 @@ enum die_val {
DIE_GPF,
DIE_CALL,
DIE_NMI_IPI,
+ DIE_NMI_POST,
DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
- return atomic_notifier_call_chain(&i386die_chain, val, &args);
-}
-
#endif
diff --git a/include/asm-i386/kexec.h b/include/asm-i386/kexec.h
index 4dfc9f5ed03..4b9dc9e6b70 100644
--- a/include/asm-i386/kexec.h
+++ b/include/asm-i386/kexec.h
@@ -21,7 +21,6 @@
#ifndef __ASSEMBLY__
-#include <asm/fixmap.h>
#include <asm/ptrace.h>
#include <asm/string.h>
@@ -29,10 +28,6 @@
* KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
* I.e. Maximum page that is mapped directly into kernel memory,
* and kmap is not required.
- *
- * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
- * calculation for the amount of memory directly mappable into the
- * kernel memory space.
*/
/* Maximum physical address we can use pages from */
@@ -47,7 +42,8 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_386
-#define MAX_NOTE_BYTES 1024
+/* We can also handle crash dumps from 64 bit kernel. */
+#define vmcore_elf_check_arch_cross(x) ((x)->e_machine == EM_X86_64)
/* CPU does not save ss and esp on stack if execution is already
* running in kernel mode at the time of NMI occurrence. This code
diff --git a/include/asm-i386/local.h b/include/asm-i386/local.h
index 12060e22f7e..e13d3e98823 100644
--- a/include/asm-i386/local.h
+++ b/include/asm-i386/local.h
@@ -2,47 +2,198 @@
#define _ARCH_I386_LOCAL_H
#include <linux/percpu.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
typedef struct
{
- volatile long counter;
+ atomic_long_t a;
} local_t;
-#define LOCAL_INIT(i) { (i) }
+#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
-#define local_read(v) ((v)->counter)
-#define local_set(v,i) (((v)->counter) = (i))
+#define local_read(l) atomic_long_read(&(l)->a)
+#define local_set(l,i) atomic_long_set(&(l)->a, (i))
-static __inline__ void local_inc(local_t *v)
+static __inline__ void local_inc(local_t *l)
{
__asm__ __volatile__(
"incl %0"
- :"+m" (v->counter));
+ :"+m" (l->a.counter));
}
-static __inline__ void local_dec(local_t *v)
+static __inline__ void local_dec(local_t *l)
{
__asm__ __volatile__(
"decl %0"
- :"+m" (v->counter));
+ :"+m" (l->a.counter));
}
-static __inline__ void local_add(long i, local_t *v)
+static __inline__ void local_add(long i, local_t *l)
{
__asm__ __volatile__(
"addl %1,%0"
- :"+m" (v->counter)
+ :"+m" (l->a.counter)
:"ir" (i));
}
-static __inline__ void local_sub(long i, local_t *v)
+static __inline__ void local_sub(long i, local_t *l)
{
__asm__ __volatile__(
"subl %1,%0"
- :"+m" (v->counter)
+ :"+m" (l->a.counter)
:"ir" (i));
}
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_sub_and_test(long i, local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "subl %2,%0; sete %1"
+ :"+m" (l->a.counter), "=qm" (c)
+ :"ir" (i) : "memory");
+ return c;
+}
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+static __inline__ int local_dec_and_test(local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "decl %0; sete %1"
+ :"+m" (l->a.counter), "=qm" (c)
+ : : "memory");
+ return c != 0;
+}
+
+/**
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_inc_and_test(local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "incl %0; sete %1"
+ :"+m" (l->a.counter), "=qm" (c)
+ : : "memory");
+ return c != 0;
+}
+
+/**
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+static __inline__ int local_add_negative(long i, local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "addl %2,%0; sets %1"
+ :"+m" (l->a.counter), "=qm" (c)
+ :"ir" (i) : "memory");
+ return c;
+}
+
+/**
+ * local_add_return - add and return
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns @i + @l
+ */
+static __inline__ long local_add_return(long i, local_t *l)
+{
+ long __i;
+#ifdef CONFIG_M386
+ unsigned long flags;
+ if(unlikely(boot_cpu_data.x86==3))
+ goto no_xadd;
+#endif
+ /* Modern 486+ processor */
+ __i = i;
+ __asm__ __volatile__(
+ "xaddl %0, %1;"
+ :"+r" (i), "+m" (l->a.counter)
+ : : "memory");
+ return i + __i;
+
+#ifdef CONFIG_M386
+no_xadd: /* Legacy 386 processor */
+ local_irq_save(flags);
+ __i = local_read(l);
+ local_set(l, i + __i);
+ local_irq_restore(flags);
+ return i + __i;
+#endif
+}
+
+static __inline__ long local_sub_return(long i, local_t *l)
+{
+ return local_add_return(-i,l);
+}
+
+#define local_inc_return(l) (local_add_return(1,l))
+#define local_dec_return(l) (local_sub_return(1,l))
+
+#define local_cmpxchg(l, o, n) \
+ (cmpxchg_local(&((l)->a.counter), (o), (n)))
+/* Always has a lock prefix */
+#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u) \
+({ \
+ long c, old; \
+ c = local_read(l); \
+ for (;;) { \
+ if (unlikely(c == (u))) \
+ break; \
+ old = local_cmpxchg((l), c, c + (a)); \
+ if (likely(old == c)) \
+ break; \
+ c = old; \
+ } \
+ c != (u); \
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
/* On x86, these are no better than the atomic variants. */
#define __local_inc(l) local_inc(l)
#define __local_dec(l) local_dec(l)
@@ -56,27 +207,27 @@ static __inline__ void local_sub(long i, local_t *v)
/* Need to disable preemption for the cpu local counters otherwise we could
still access a variable of a previous CPU in a non atomic way. */
-#define cpu_local_wrap_v(v) \
+#define cpu_local_wrap_v(l) \
({ local_t res__; \
preempt_disable(); \
- res__ = (v); \
+ res__ = (l); \
preempt_enable(); \
res__; })
-#define cpu_local_wrap(v) \
+#define cpu_local_wrap(l) \
({ preempt_disable(); \
- v; \
+ l; \
preempt_enable(); }) \
-#define cpu_local_read(v) cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
-#define cpu_local_set(v, i) cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
-#define cpu_local_inc(v) cpu_local_wrap(local_inc(&__get_cpu_var(v)))
-#define cpu_local_dec(v) cpu_local_wrap(local_dec(&__get_cpu_var(v)))
-#define cpu_local_add(i, v) cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
-#define cpu_local_sub(i, v) cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
-
-#define __cpu_local_inc(v) cpu_local_inc(v)
-#define __cpu_local_dec(v) cpu_local_dec(v)
-#define __cpu_local_add(i, v) cpu_local_add((i), (v))
-#define __cpu_local_sub(i, v) cpu_local_sub((i), (v))
+#define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l) cpu_local_inc(l)
+#define __cpu_local_dec(l) cpu_local_dec(l)
+#define __cpu_local_add(i, l) cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l) cpu_local_sub((i), (l))
#endif /* _ARCH_I386_LOCAL_H */
diff --git a/include/asm-i386/mach-bigsmp/mach_apic.h b/include/asm-i386/mach-bigsmp/mach_apic.h
index 18b19a77344..ebd319f838a 100644
--- a/include/asm-i386/mach-bigsmp/mach_apic.h
+++ b/include/asm-i386/mach-bigsmp/mach_apic.h
@@ -71,7 +71,7 @@ static inline void init_apic_ldr(void)
apic_write_around(APIC_LDR, val);
}
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
{
printk("Enabling APIC mode: %s. Using %d I/O APICs\n",
"Physflat", nr_ioapics);
diff --git a/include/asm-i386/mach-default/mach_apic.h b/include/asm-i386/mach-default/mach_apic.h
index 3ef6292db78..6db1c3babe9 100644
--- a/include/asm-i386/mach-default/mach_apic.h
+++ b/include/asm-i386/mach-default/mach_apic.h
@@ -54,7 +54,7 @@ static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map)
return phys_map;
}
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
{
printk("Enabling APIC mode: %s. Using %d I/O APICs\n",
"Flat", nr_ioapics);
diff --git a/include/asm-i386/mach-es7000/mach_apic.h b/include/asm-i386/mach-es7000/mach_apic.h
index 26333685a7f..2d978928a39 100644
--- a/include/asm-i386/mach-es7000/mach_apic.h
+++ b/include/asm-i386/mach-es7000/mach_apic.h
@@ -73,15 +73,8 @@ static inline void init_apic_ldr(void)
apic_write_around(APIC_LDR, val);
}
-extern void es7000_sw_apic(void);
-static inline void enable_apic_mode(void)
-{
- es7000_sw_apic();
- return;
-}
-
extern int apic_version [MAX_APICS];
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
{
int apic = bios_cpu_apicid[smp_processor_id()];
printk("Enabling APIC mode: %s. Using %d I/O APICs, target cpus %lx\n",
diff --git a/include/asm-i386/mach-es7000/mach_mpparse.h b/include/asm-i386/mach-es7000/mach_mpparse.h
index 24990e546da..b9fb784e1fd 100644
--- a/include/asm-i386/mach-es7000/mach_mpparse.h
+++ b/include/asm-i386/mach-es7000/mach_mpparse.h
@@ -18,18 +18,6 @@ extern int parse_unisys_oem (char *oemptr);
extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
extern void setup_unisys(void);
-static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
- char *productid)
-{
- if (mpc->mpc_oemptr) {
- struct mp_config_oemtable *oem_table =
- (struct mp_config_oemtable *)mpc->mpc_oemptr;
- if (!strncmp(oem, "UNISYS", 6))
- return parse_unisys_oem((char *)oem_table);
- }
- return 0;
-}
-
#ifdef CONFIG_ACPI
static inline int es7000_check_dsdt(void)
@@ -41,26 +29,6 @@ static inline int es7000_check_dsdt(void)
return 1;
return 0;
}
-
-/* Hook from generic ACPI tables.c */
-static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- unsigned long oem_addr;
- if (!find_unisys_acpi_oem_table(&oem_addr)) {
- if (es7000_check_dsdt())
- return parse_unisys_oem((char *)oem_addr);
- else {
- setup_unisys();
- return 1;
- }
- }
- return 0;
-}
-#else
-static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
-{
- return 0;
-}
#endif
#endif /* __ASM_MACH_MPPARSE_H */
diff --git a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h
index d9dc039da94..a236e702152 100644
--- a/include/asm-i386/mach-generic/mach_apic.h
+++ b/include/asm-i386/mach-generic/mach_apic.h
@@ -13,7 +13,7 @@
#define apic_id_registered (genapic->apic_id_registered)
#define init_apic_ldr (genapic->init_apic_ldr)
#define ioapic_phys_id_map (genapic->ioapic_phys_id_map)
-#define clustered_apic_check (genapic->clustered_apic_check)
+#define setup_apic_routing (genapic->setup_apic_routing)
#define multi_timer_check (genapic->multi_timer_check)
#define apicid_to_node (genapic->apicid_to_node)
#define cpu_to_logical_apicid (genapic->cpu_to_logical_apicid)
diff --git a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-i386/mach-numaq/mach_apic.h
index 9d158095da8..5e5e7dd2692 100644
--- a/include/asm-i386/mach-numaq/mach_apic.h
+++ b/include/asm-i386/mach-numaq/mach_apic.h
@@ -34,7 +34,7 @@ static inline void init_apic_ldr(void)
/* Already done in NUMA-Q firmware */
}
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
{
printk("Enabling APIC mode: %s. Using %d I/O APICs\n",
"NUMA-Q", nr_ioapics);
diff --git a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h
index 43e5bd8f4a1..732f776aab8 100644
--- a/include/asm-i386/mach-summit/mach_apic.h
+++ b/include/asm-i386/mach-summit/mach_apic.h
@@ -80,7 +80,7 @@ static inline int apic_id_registered(void)
return 1;
}
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
{
printk("Enabling APIC mode: Summit. Using %d I/O APICs\n",
nr_ioapics);
diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h
index 94268399170..c2520539d93 100644
--- a/include/asm-i386/mach-summit/mach_mpparse.h
+++ b/include/asm-i386/mach-summit/mach_mpparse.h
@@ -30,7 +30,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
(!strncmp(productid, "VIGIL SMP", 9)
|| !strncmp(productid, "EXA", 3)
|| !strncmp(productid, "RUTHLESS SMP", 12))){
- mark_tsc_unstable();
+ mark_tsc_unstable("Summit based system");
use_cyclone = 1; /*enable cyclone-timer*/
setup_summit();
return 1;
@@ -44,7 +44,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
if (!strncmp(oem_id, "IBM", 3) &&
(!strncmp(oem_table_id, "SERVIGIL", 8)
|| !strncmp(oem_table_id, "EXA", 3))){
- mark_tsc_unstable();
+ mark_tsc_unstable("Summit based system");
use_cyclone = 1; /*enable cyclone-timer*/
setup_summit();
return 1;
diff --git a/include/asm-i386/mach-visws/mach_apic.h b/include/asm-i386/mach-visws/mach_apic.h
index 18afe6b6fc4..efac6f0d139 100644
--- a/include/asm-i386/mach-visws/mach_apic.h
+++ b/include/asm-i386/mach-visws/mach_apic.h
@@ -47,7 +47,7 @@ static inline void summit_check(char *oem, char *productid)
{
}
-static inline void clustered_apic_check(void)
+static inline void setup_apic_routing(void)
{
}
diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
index e6aa30f8de5..8198d1cca1f 100644
--- a/include/asm-i386/mmu_context.h
+++ b/include/asm-i386/mmu_context.h
@@ -5,6 +5,16 @@
#include <asm/atomic.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
+#include <asm/paravirt.h>
+#ifndef CONFIG_PARAVIRT
+#include <asm-generic/mm_hooks.h>
+
+static inline void paravirt_activate_mm(struct mm_struct *prev,
+ struct mm_struct *next)
+{
+}
+#endif /* !CONFIG_PARAVIRT */
+
/*
* Used for LDT copy/destruction.
@@ -65,7 +75,10 @@ static inline void switch_mm(struct mm_struct *prev,
#define deactivate_mm(tsk, mm) \
asm("movl %0,%%gs": :"r" (0));
-#define activate_mm(prev, next) \
- switch_mm((prev),(next),NULL)
+#define activate_mm(prev, next) \
+ do { \
+ paravirt_activate_mm(prev, next); \
+ switch_mm((prev),(next),NULL); \
+ } while(0);
#endif
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
index 3503ad66945..118e9812778 100644
--- a/include/asm-i386/mmzone.h
+++ b/include/asm-i386/mmzone.h
@@ -122,21 +122,21 @@ static inline int pfn_valid(int pfn)
__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0)
#define alloc_bootmem_node(pgdat, x) \
({ \
- struct pglist_data __attribute__ ((unused)) \
+ struct pglist_data __maybe_unused \
*__alloc_bootmem_node__pgdat = (pgdat); \
__alloc_bootmem_node(NODE_DATA(0), (x), SMP_CACHE_BYTES, \
__pa(MAX_DMA_ADDRESS)); \
})
#define alloc_bootmem_pages_node(pgdat, x) \
({ \
- struct pglist_data __attribute__ ((unused)) \
+ struct pglist_data __maybe_unused \
*__alloc_bootmem_node__pgdat = (pgdat); \
__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, \
__pa(MAX_DMA_ADDRESS)) \
})
#define alloc_bootmem_low_pages_node(pgdat, x) \
({ \
- struct pglist_data __attribute__ ((unused)) \
+ struct pglist_data __maybe_unused \
*__alloc_bootmem_node__pgdat = (pgdat); \
__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0); \
})
diff --git a/include/asm-i386/module.h b/include/asm-i386/module.h
index 02f8f541cbe..7e5fda6c397 100644
--- a/include/asm-i386/module.h
+++ b/include/asm-i386/module.h
@@ -54,6 +54,8 @@ struct mod_arch_specific
#define MODULE_PROC_FAMILY "CYRIXIII "
#elif defined CONFIG_MVIAC3_2
#define MODULE_PROC_FAMILY "VIAC3-2 "
+#elif defined CONFIG_MVIAC7
+#define MODULE_PROC_FAMILY "VIAC7 "
#elif defined CONFIG_MGEODEGX1
#define MODULE_PROC_FAMILY "GEODEGX1 "
#elif defined CONFIG_MGEODE_LX
diff --git a/include/asm-i386/msr-index.h b/include/asm-i386/msr-index.h
new file mode 100644
index 00000000000..a02eb299134
--- /dev/null
+++ b/include/asm-i386/msr-index.h
@@ -0,0 +1,278 @@
+#ifndef __ASM_MSR_INDEX_H
+#define __ASM_MSR_INDEX_H
+
+/* CPU model specific register (MSR) numbers */
+
+/* x86-64 specific MSRs */
+#define MSR_EFER 0xc0000080 /* extended feature register */
+#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */
+#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */
+#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */
+#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */
+#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */
+#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */
+#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */
+
+/* EFER bits: */
+#define _EFER_SCE 0 /* SYSCALL/SYSRET */
+#define _EFER_LME 8 /* Long mode enable */
+#define _EFER_LMA 10 /* Long mode active (read-only) */
+#define _EFER_NX 11 /* No execute enable */
+
+#define EFER_SCE (1<<_EFER_SCE)
+#define EFER_LME (1<<_EFER_LME)
+#define EFER_LMA (1<<_EFER_LMA)
+#define EFER_NX (1<<_EFER_NX)
+
+/* Intel MSRs. Some also available on other CPUs */
+#define MSR_IA32_PERFCTR0 0x000000c1
+#define MSR_IA32_PERFCTR1 0x000000c2
+#define MSR_FSB_FREQ 0x000000cd
+
+#define MSR_MTRRcap 0x000000fe
+#define MSR_IA32_BBL_CR_CTL 0x00000119
+
+#define MSR_IA32_SYSENTER_CS 0x00000174
+#define MSR_IA32_SYSENTER_ESP 0x00000175
+#define MSR_IA32_SYSENTER_EIP 0x00000176
+
+#define MSR_IA32_MCG_CAP 0x00000179
+#define MSR_IA32_MCG_STATUS 0x0000017a
+#define MSR_IA32_MCG_CTL 0x0000017b
+
+#define MSR_IA32_PEBS_ENABLE 0x000003f1
+#define MSR_IA32_DS_AREA 0x00000600
+#define MSR_IA32_PERF_CAPABILITIES 0x00000345
+
+#define MSR_MTRRfix64K_00000 0x00000250
+#define MSR_MTRRfix16K_80000 0x00000258
+#define MSR_MTRRfix16K_A0000 0x00000259
+#define MSR_MTRRfix4K_C0000 0x00000268
+#define MSR_MTRRfix4K_C8000 0x00000269
+#define MSR_MTRRfix4K_D0000 0x0000026a
+#define MSR_MTRRfix4K_D8000 0x0000026b
+#define MSR_MTRRfix4K_E0000 0x0000026c
+#define MSR_MTRRfix4K_E8000 0x0000026d
+#define MSR_MTRRfix4K_F0000 0x0000026e
+#define MSR_MTRRfix4K_F8000 0x0000026f
+#define MSR_MTRRdefType 0x000002ff
+
+#define MSR_IA32_DEBUGCTLMSR 0x000001d9
+#define MSR_IA32_LASTBRANCHFROMIP 0x000001db
+#define MSR_IA32_LASTBRANCHTOIP 0x000001dc
+#define MSR_IA32_LASTINTFROMIP 0x000001dd
+#define MSR_IA32_LASTINTTOIP 0x000001de
+
+#define MSR_IA32_MC0_CTL 0x00000400
+#define MSR_IA32_MC0_STATUS 0x00000401
+#define MSR_IA32_MC0_ADDR 0x00000402
+#define MSR_IA32_MC0_MISC 0x00000403
+
+#define MSR_P6_PERFCTR0 0x000000c1
+#define MSR_P6_PERFCTR1 0x000000c2
+#define MSR_P6_EVNTSEL0 0x00000186
+#define MSR_P6_EVNTSEL1 0x00000187
+
+/* K7/K8 MSRs. Not complete. See the architecture manual for a more
+ complete list. */
+#define MSR_K7_EVNTSEL0 0xc0010000
+#define MSR_K7_PERFCTR0 0xc0010004
+#define MSR_K7_EVNTSEL1 0xc0010001
+#define MSR_K7_PERFCTR1 0xc0010005
+#define MSR_K7_EVNTSEL2 0xc0010002
+#define MSR_K7_PERFCTR2 0xc0010006
+#define MSR_K7_EVNTSEL3 0xc0010003
+#define MSR_K7_PERFCTR3 0xc0010007
+#define MSR_K8_TOP_MEM1 0xc001001a
+#define MSR_K7_CLK_CTL 0xc001001b
+#define MSR_K8_TOP_MEM2 0xc001001d
+#define MSR_K8_SYSCFG 0xc0010010
+
+#define K8_MTRRFIXRANGE_DRAM_ENABLE 0x00040000 /* MtrrFixDramEn bit */
+#define K8_MTRRFIXRANGE_DRAM_MODIFY 0x00080000 /* MtrrFixDramModEn bit */
+#define K8_MTRR_RDMEM_WRMEM_MASK 0x18181818 /* Mask: RdMem|WrMem */
+
+#define MSR_K7_HWCR 0xc0010015
+#define MSR_K8_HWCR 0xc0010015
+#define MSR_K7_FID_VID_CTL 0xc0010041
+#define MSR_K7_FID_VID_STATUS 0xc0010042
+#define MSR_K8_ENABLE_C1E 0xc0010055
+
+/* K6 MSRs */
+#define MSR_K6_EFER 0xc0000080
+#define MSR_K6_STAR 0xc0000081
+#define MSR_K6_WHCR 0xc0000082
+#define MSR_K6_UWCCR 0xc0000085
+#define MSR_K6_EPMR 0xc0000086
+#define MSR_K6_PSOR 0xc0000087
+#define MSR_K6_PFIR 0xc0000088
+
+/* Centaur-Hauls/IDT defined MSRs. */
+#define MSR_IDT_FCR1 0x00000107
+#define MSR_IDT_FCR2 0x00000108
+#define MSR_IDT_FCR3 0x00000109
+#define MSR_IDT_FCR4 0x0000010a
+
+#define MSR_IDT_MCR0 0x00000110
+#define MSR_IDT_MCR1 0x00000111
+#define MSR_IDT_MCR2 0x00000112
+#define MSR_IDT_MCR3 0x00000113
+#define MSR_IDT_MCR4 0x00000114
+#define MSR_IDT_MCR5 0x00000115
+#define MSR_IDT_MCR6 0x00000116
+#define MSR_IDT_MCR7 0x00000117
+#define MSR_IDT_MCR_CTRL 0x00000120
+
+/* VIA Cyrix defined MSRs*/
+#define MSR_VIA_FCR 0x00001107
+#define MSR_VIA_LONGHAUL 0x0000110a
+#define MSR_VIA_RNG 0x0000110b
+#define MSR_VIA_BCR2 0x00001147
+
+/* Transmeta defined MSRs */
+#define MSR_TMTA_LONGRUN_CTRL 0x80868010
+#define MSR_TMTA_LONGRUN_FLAGS 0x80868011
+#define MSR_TMTA_LRTI_READOUT 0x80868018
+#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a
+
+/* Intel defined MSRs. */
+#define MSR_IA32_P5_MC_ADDR 0x00000000
+#define MSR_IA32_P5_MC_TYPE 0x00000001
+#define MSR_IA32_TSC 0x00000010
+#define MSR_IA32_PLATFORM_ID 0x00000017
+#define MSR_IA32_EBL_CR_POWERON 0x0000002a
+
+#define MSR_IA32_APICBASE 0x0000001b
+#define MSR_IA32_APICBASE_BSP (1<<8)
+#define MSR_IA32_APICBASE_ENABLE (1<<11)
+#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+
+#define MSR_IA32_UCODE_WRITE 0x00000079
+#define MSR_IA32_UCODE_REV 0x0000008b
+
+#define MSR_IA32_PERF_STATUS 0x00000198
+#define MSR_IA32_PERF_CTL 0x00000199
+
+#define MSR_IA32_MPERF 0x000000e7
+#define MSR_IA32_APERF 0x000000e8
+
+#define MSR_IA32_THERM_CONTROL 0x0000019a
+#define MSR_IA32_THERM_INTERRUPT 0x0000019b
+#define MSR_IA32_THERM_STATUS 0x0000019c
+#define MSR_IA32_MISC_ENABLE 0x000001a0
+
+/* Intel Model 6 */
+#define MSR_P6_EVNTSEL0 0x00000186
+#define MSR_P6_EVNTSEL1 0x00000187
+
+/* P4/Xeon+ specific */
+#define MSR_IA32_MCG_EAX 0x00000180
+#define MSR_IA32_MCG_EBX 0x00000181
+#define MSR_IA32_MCG_ECX 0x00000182
+#define MSR_IA32_MCG_EDX 0x00000183
+#define MSR_IA32_MCG_ESI 0x00000184
+#define MSR_IA32_MCG_EDI 0x00000185
+#define MSR_IA32_MCG_EBP 0x00000186
+#define MSR_IA32_MCG_ESP 0x00000187
+#define MSR_IA32_MCG_EFLAGS 0x00000188
+#define MSR_IA32_MCG_EIP 0x00000189
+#define MSR_IA32_MCG_RESERVED 0x0000018a
+
+/* Pentium IV performance counter MSRs */
+#define MSR_P4_BPU_PERFCTR0 0x00000300
+#define MSR_P4_BPU_PERFCTR1 0x00000301
+#define MSR_P4_BPU_PERFCTR2 0x00000302
+#define MSR_P4_BPU_PERFCTR3 0x00000303
+#define MSR_P4_MS_PERFCTR0 0x00000304
+#define MSR_P4_MS_PERFCTR1 0x00000305
+#define MSR_P4_MS_PERFCTR2 0x00000306
+#define MSR_P4_MS_PERFCTR3 0x00000307
+#define MSR_P4_FLAME_PERFCTR0 0x00000308
+#define MSR_P4_FLAME_PERFCTR1 0x00000309
+#define MSR_P4_FLAME_PERFCTR2 0x0000030a
+#define MSR_P4_FLAME_PERFCTR3 0x0000030b
+#define MSR_P4_IQ_PERFCTR0 0x0000030c
+#define MSR_P4_IQ_PERFCTR1 0x0000030d
+#define MSR_P4_IQ_PERFCTR2 0x0000030e
+#define MSR_P4_IQ_PERFCTR3 0x0000030f
+#define MSR_P4_IQ_PERFCTR4 0x00000310
+#define MSR_P4_IQ_PERFCTR5 0x00000311
+#define MSR_P4_BPU_CCCR0 0x00000360
+#define MSR_P4_BPU_CCCR1 0x00000361
+#define MSR_P4_BPU_CCCR2 0x00000362
+#define MSR_P4_BPU_CCCR3 0x00000363
+#define MSR_P4_MS_CCCR0 0x00000364
+#define MSR_P4_MS_CCCR1 0x00000365
+#define MSR_P4_MS_CCCR2 0x00000366
+#define MSR_P4_MS_CCCR3 0x00000367
+#define MSR_P4_FLAME_CCCR0 0x00000368
+#define MSR_P4_FLAME_CCCR1 0x00000369
+#define MSR_P4_FLAME_CCCR2 0x0000036a
+#define MSR_P4_FLAME_CCCR3 0x0000036b
+#define MSR_P4_IQ_CCCR0 0x0000036c
+#define MSR_P4_IQ_CCCR1 0x0000036d
+#define MSR_P4_IQ_CCCR2 0x0000036e
+#define MSR_P4_IQ_CCCR3 0x0000036f
+#define MSR_P4_IQ_CCCR4 0x00000370
+#define MSR_P4_IQ_CCCR5 0x00000371
+#define MSR_P4_ALF_ESCR0 0x000003ca
+#define MSR_P4_ALF_ESCR1 0x000003cb
+#define MSR_P4_BPU_ESCR0 0x000003b2
+#define MSR_P4_BPU_ESCR1 0x000003b3
+#define MSR_P4_BSU_ESCR0 0x000003a0
+#define MSR_P4_BSU_ESCR1 0x000003a1
+#define MSR_P4_CRU_ESCR0 0x000003b8
+#define MSR_P4_CRU_ESCR1 0x000003b9
+#define MSR_P4_CRU_ESCR2 0x000003cc
+#define MSR_P4_CRU_ESCR3 0x000003cd
+#define MSR_P4_CRU_ESCR4 0x000003e0
+#define MSR_P4_CRU_ESCR5 0x000003e1
+#define MSR_P4_DAC_ESCR0 0x000003a8
+#define MSR_P4_DAC_ESCR1 0x000003a9
+#define MSR_P4_FIRM_ESCR0 0x000003a4
+#define MSR_P4_FIRM_ESCR1 0x000003a5
+#define MSR_P4_FLAME_ESCR0 0x000003a6
+#define MSR_P4_FLAME_ESCR1 0x000003a7
+#define MSR_P4_FSB_ESCR0 0x000003a2
+#define MSR_P4_FSB_ESCR1 0x000003a3
+#define MSR_P4_IQ_ESCR0 0x000003ba
+#define MSR_P4_IQ_ESCR1 0x000003bb
+#define MSR_P4_IS_ESCR0 0x000003b4
+#define MSR_P4_IS_ESCR1 0x000003b5
+#define MSR_P4_ITLB_ESCR0 0x000003b6
+#define MSR_P4_ITLB_ESCR1 0x000003b7
+#define MSR_P4_IX_ESCR0 0x000003c8
+#define MSR_P4_IX_ESCR1 0x000003c9
+#define MSR_P4_MOB_ESCR0 0x000003aa
+#define MSR_P4_MOB_ESCR1 0x000003ab
+#define MSR_P4_MS_ESCR0 0x000003c0
+#define MSR_P4_MS_ESCR1 0x000003c1
+#define MSR_P4_PMH_ESCR0 0x000003ac
+#define MSR_P4_PMH_ESCR1 0x000003ad
+#define MSR_P4_RAT_ESCR0 0x000003bc
+#define MSR_P4_RAT_ESCR1 0x000003bd
+#define MSR_P4_SAAT_ESCR0 0x000003ae
+#define MSR_P4_SAAT_ESCR1 0x000003af
+#define MSR_P4_SSU_ESCR0 0x000003be
+#define MSR_P4_SSU_ESCR1 0x000003bf /* guess: not in manual */
+
+#define MSR_P4_TBPU_ESCR0 0x000003c2
+#define MSR_P4_TBPU_ESCR1 0x000003c3
+#define MSR_P4_TC_ESCR0 0x000003c4
+#define MSR_P4_TC_ESCR1 0x000003c5
+#define MSR_P4_U2L_ESCR0 0x000003b0
+#define MSR_P4_U2L_ESCR1 0x000003b1
+
+/* Intel Core-based CPU performance counters */
+#define MSR_CORE_PERF_FIXED_CTR0 0x00000309
+#define MSR_CORE_PERF_FIXED_CTR1 0x0000030a
+#define MSR_CORE_PERF_FIXED_CTR2 0x0000030b
+#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x0000038d
+#define MSR_CORE_PERF_GLOBAL_STATUS 0x0000038e
+#define MSR_CORE_PERF_GLOBAL_CTRL 0x0000038f
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x00000390
+
+/* Geode defined MSRs */
+#define MSR_GEODE_BUSCONT_CONF0 0x00001900
+
+#endif /* __ASM_MSR_INDEX_H */
diff --git a/include/asm-i386/msr.h b/include/asm-i386/msr.h
index 2ad3f30b1a6..df21ea04936 100644
--- a/include/asm-i386/msr.h
+++ b/include/asm-i386/msr.h
@@ -1,91 +1,143 @@
#ifndef __ASM_MSR_H
#define __ASM_MSR_H
+#include <asm/msr-index.h>
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+
+#include <asm/errno.h>
+
+static inline unsigned long long native_read_msr(unsigned int msr)
+{
+ unsigned long long val;
+
+ asm volatile("rdmsr" : "=A" (val) : "c" (msr));
+ return val;
+}
+
+static inline unsigned long long native_read_msr_safe(unsigned int msr,
+ int *err)
+{
+ unsigned long long val;
+
+ asm volatile("2: rdmsr ; xorl %0,%0\n"
+ "1:\n\t"
+ ".section .fixup,\"ax\"\n\t"
+ "3: movl %3,%0 ; jmp 1b\n\t"
+ ".previous\n\t"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n\t"
+ " .long 2b,3b\n\t"
+ ".previous"
+ : "=r" (*err), "=A" (val)
+ : "c" (msr), "i" (-EFAULT));
+
+ return val;
+}
+
+static inline void native_write_msr(unsigned int msr, unsigned long long val)
+{
+ asm volatile("wrmsr" : : "c" (msr), "A"(val));
+}
+
+static inline int native_write_msr_safe(unsigned int msr,
+ unsigned long long val)
+{
+ int err;
+ asm volatile("2: wrmsr ; xorl %0,%0\n"
+ "1:\n\t"
+ ".section .fixup,\"ax\"\n\t"
+ "3: movl %4,%0 ; jmp 1b\n\t"
+ ".previous\n\t"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n\t"
+ " .long 2b,3b\n\t"
+ ".previous"
+ : "=a" (err)
+ : "c" (msr), "0" ((u32)val), "d" ((u32)(val>>32)),
+ "i" (-EFAULT));
+ return err;
+}
+
+static inline unsigned long long native_read_tsc(void)
+{
+ unsigned long long val;
+ asm volatile("rdtsc" : "=A" (val));
+ return val;
+}
+
+static inline unsigned long long native_read_pmc(void)
+{
+ unsigned long long val;
+ asm volatile("rdpmc" : "=A" (val));
+ return val;
+}
+
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else
-
+#include <linux/errno.h>
/*
* Access to machine-specific registers (available on 586 and better only)
* Note: the rd* operations modify the parameters directly (without using
* pointer indirection), this allows gcc to optimize better
*/
-#define rdmsr(msr,val1,val2) \
- __asm__ __volatile__("rdmsr" \
- : "=a" (val1), "=d" (val2) \
- : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
- __asm__ __volatile__("wrmsr" \
- : /* no outputs */ \
- : "c" (msr), "a" (val1), "d" (val2))
+#define rdmsr(msr,val1,val2) \
+ do { \
+ u64 __val = native_read_msr(msr); \
+ (val1) = (u32)__val; \
+ (val2) = (u32)(__val >> 32); \
+ } while(0)
-#define rdmsrl(msr,val) do { \
- unsigned long l__,h__; \
- rdmsr (msr, l__, h__); \
- val = l__; \
- val |= ((u64)h__<<32); \
-} while(0)
-
-static inline void wrmsrl (unsigned long msr, unsigned long long val)
+static inline void wrmsr(u32 __msr, u32 __low, u32 __high)
{
- unsigned long lo, hi;
- lo = (unsigned long) val;
- hi = val >> 32;
- wrmsr (msr, lo, hi);
+ native_write_msr(__msr, ((u64)__high << 32) | __low);
}
+#define rdmsrl(msr,val) \
+ ((val) = native_read_msr(msr))
+
+#define wrmsrl(msr,val) native_write_msr(msr, val)
+
/* wrmsr with exception handling */
-#define wrmsr_safe(msr,a,b) ({ int ret__; \
- asm volatile("2: wrmsr ; xorl %0,%0\n" \
- "1:\n\t" \
- ".section .fixup,\"ax\"\n\t" \
- "3: movl %4,%0 ; jmp 1b\n\t" \
- ".previous\n\t" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n\t" \
- " .long 2b,3b\n\t" \
- ".previous" \
- : "=a" (ret__) \
- : "c" (msr), "0" (a), "d" (b), "i" (-EFAULT));\
- ret__; })
+static inline int wrmsr_safe(u32 __msr, u32 __low, u32 __high)
+{
+ return native_write_msr_safe(__msr, ((u64)__high << 32) | __low);
+}
/* rdmsr with exception handling */
-#define rdmsr_safe(msr,a,b) ({ int ret__; \
- asm volatile("2: rdmsr ; xorl %0,%0\n" \
- "1:\n\t" \
- ".section .fixup,\"ax\"\n\t" \
- "3: movl %4,%0 ; jmp 1b\n\t" \
- ".previous\n\t" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n\t" \
- " .long 2b,3b\n\t" \
- ".previous" \
- : "=r" (ret__), "=a" (*(a)), "=d" (*(b)) \
- : "c" (msr), "i" (-EFAULT));\
- ret__; })
-
-#define rdtsc(low,high) \
- __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+#define rdmsr_safe(msr,p1,p2) \
+ ({ \
+ int __err; \
+ u64 __val = native_read_msr_safe(msr, &__err); \
+ (*p1) = (u32)__val; \
+ (*p2) = (u32)(__val >> 32); \
+ __err; \
+ })
-#define rdtscl(low) \
- __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
+#define rdtscl(low) \
+ ((low) = (u32)native_read_tsc())
-#define rdtscll(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
+#define rdtscll(val) \
+ ((val) = native_read_tsc())
#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
-#define rdpmc(counter,low,high) \
- __asm__ __volatile__("rdpmc" \
- : "=a" (low), "=d" (high) \
- : "c" (counter))
+#define rdpmc(counter,low,high) \
+ do { \
+ u64 _l = native_read_pmc(); \
+ (low) = (u32)_l; \
+ (high) = (u32)(_l >> 32); \
+ } while(0)
#endif /* !CONFIG_PARAVIRT */
#ifdef CONFIG_SMP
void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
#else /* CONFIG_SMP */
static inline void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
{
@@ -95,235 +147,15 @@ static inline void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
{
wrmsr(msr_no, l, h);
}
+static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+ return rdmsr_safe(msr_no, l, h);
+}
+static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+ return wrmsr_safe(msr_no, l, h);
+}
#endif /* CONFIG_SMP */
-
-/* symbolic names for some interesting MSRs */
-/* Intel defined MSRs. */
-#define MSR_IA32_P5_MC_ADDR 0
-#define MSR_IA32_P5_MC_TYPE 1
-#define MSR_IA32_PLATFORM_ID 0x17
-#define MSR_IA32_EBL_CR_POWERON 0x2a
-
-#define MSR_IA32_APICBASE 0x1b
-#define MSR_IA32_APICBASE_BSP (1<<8)
-#define MSR_IA32_APICBASE_ENABLE (1<<11)
-#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
-
-#define MSR_IA32_UCODE_WRITE 0x79
-#define MSR_IA32_UCODE_REV 0x8b
-
-#define MSR_P6_PERFCTR0 0xc1
-#define MSR_P6_PERFCTR1 0xc2
-#define MSR_FSB_FREQ 0xcd
-
-
-#define MSR_IA32_BBL_CR_CTL 0x119
-
-#define MSR_IA32_SYSENTER_CS 0x174
-#define MSR_IA32_SYSENTER_ESP 0x175
-#define MSR_IA32_SYSENTER_EIP 0x176
-
-#define MSR_IA32_MCG_CAP 0x179
-#define MSR_IA32_MCG_STATUS 0x17a
-#define MSR_IA32_MCG_CTL 0x17b
-
-/* P4/Xeon+ specific */
-#define MSR_IA32_MCG_EAX 0x180
-#define MSR_IA32_MCG_EBX 0x181
-#define MSR_IA32_MCG_ECX 0x182
-#define MSR_IA32_MCG_EDX 0x183
-#define MSR_IA32_MCG_ESI 0x184
-#define MSR_IA32_MCG_EDI 0x185
-#define MSR_IA32_MCG_EBP 0x186
-#define MSR_IA32_MCG_ESP 0x187
-#define MSR_IA32_MCG_EFLAGS 0x188
-#define MSR_IA32_MCG_EIP 0x189
-#define MSR_IA32_MCG_RESERVED 0x18A
-
-#define MSR_P6_EVNTSEL0 0x186
-#define MSR_P6_EVNTSEL1 0x187
-
-#define MSR_IA32_PERF_STATUS 0x198
-#define MSR_IA32_PERF_CTL 0x199
-
-#define MSR_IA32_MPERF 0xE7
-#define MSR_IA32_APERF 0xE8
-
-#define MSR_IA32_THERM_CONTROL 0x19a
-#define MSR_IA32_THERM_INTERRUPT 0x19b
-#define MSR_IA32_THERM_STATUS 0x19c
-#define MSR_IA32_MISC_ENABLE 0x1a0
-
-#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
-
-#define MSR_IA32_MC0_CTL 0x400
-#define MSR_IA32_MC0_STATUS 0x401
-#define MSR_IA32_MC0_ADDR 0x402
-#define MSR_IA32_MC0_MISC 0x403
-
-#define MSR_IA32_PEBS_ENABLE 0x3f1
-#define MSR_IA32_DS_AREA 0x600
-#define MSR_IA32_PERF_CAPABILITIES 0x345
-
-/* Pentium IV performance counter MSRs */
-#define MSR_P4_BPU_PERFCTR0 0x300
-#define MSR_P4_BPU_PERFCTR1 0x301
-#define MSR_P4_BPU_PERFCTR2 0x302
-#define MSR_P4_BPU_PERFCTR3 0x303
-#define MSR_P4_MS_PERFCTR0 0x304
-#define MSR_P4_MS_PERFCTR1 0x305
-#define MSR_P4_MS_PERFCTR2 0x306
-#define MSR_P4_MS_PERFCTR3 0x307
-#define MSR_P4_FLAME_PERFCTR0 0x308
-#define MSR_P4_FLAME_PERFCTR1 0x309
-#define MSR_P4_FLAME_PERFCTR2 0x30a
-#define MSR_P4_FLAME_PERFCTR3 0x30b
-#define MSR_P4_IQ_PERFCTR0 0x30c
-#define MSR_P4_IQ_PERFCTR1 0x30d
-#define MSR_P4_IQ_PERFCTR2 0x30e
-#define MSR_P4_IQ_PERFCTR3 0x30f
-#define MSR_P4_IQ_PERFCTR4 0x310
-#define MSR_P4_IQ_PERFCTR5 0x311
-#define MSR_P4_BPU_CCCR0 0x360
-#define MSR_P4_BPU_CCCR1 0x361
-#define MSR_P4_BPU_CCCR2 0x362
-#define MSR_P4_BPU_CCCR3 0x363
-#define MSR_P4_MS_CCCR0 0x364
-#define MSR_P4_MS_CCCR1 0x365
-#define MSR_P4_MS_CCCR2 0x366
-#define MSR_P4_MS_CCCR3 0x367
-#define MSR_P4_FLAME_CCCR0 0x368
-#define MSR_P4_FLAME_CCCR1 0x369
-#define MSR_P4_FLAME_CCCR2 0x36a
-#define MSR_P4_FLAME_CCCR3 0x36b
-#define MSR_P4_IQ_CCCR0 0x36c
-#define MSR_P4_IQ_CCCR1 0x36d
-#define MSR_P4_IQ_CCCR2 0x36e
-#define MSR_P4_IQ_CCCR3 0x36f
-#define MSR_P4_IQ_CCCR4 0x370
-#define MSR_P4_IQ_CCCR5 0x371
-#define MSR_P4_ALF_ESCR0 0x3ca
-#define MSR_P4_ALF_ESCR1 0x3cb
-#define MSR_P4_BPU_ESCR0 0x3b2
-#define MSR_P4_BPU_ESCR1 0x3b3
-#define MSR_P4_BSU_ESCR0 0x3a0
-#define MSR_P4_BSU_ESCR1 0x3a1
-#define MSR_P4_CRU_ESCR0 0x3b8
-#define MSR_P4_CRU_ESCR1 0x3b9
-#define MSR_P4_CRU_ESCR2 0x3cc
-#define MSR_P4_CRU_ESCR3 0x3cd
-#define MSR_P4_CRU_ESCR4 0x3e0
-#define MSR_P4_CRU_ESCR5 0x3e1
-#define MSR_P4_DAC_ESCR0 0x3a8
-#define MSR_P4_DAC_ESCR1 0x3a9
-#define MSR_P4_FIRM_ESCR0 0x3a4
-#define MSR_P4_FIRM_ESCR1 0x3a5
-#define MSR_P4_FLAME_ESCR0 0x3a6
-#define MSR_P4_FLAME_ESCR1 0x3a7
-#define MSR_P4_FSB_ESCR0 0x3a2
-#define MSR_P4_FSB_ESCR1 0x3a3
-#define MSR_P4_IQ_ESCR0 0x3ba
-#define MSR_P4_IQ_ESCR1 0x3bb
-#define MSR_P4_IS_ESCR0 0x3b4
-#define MSR_P4_IS_ESCR1 0x3b5
-#define MSR_P4_ITLB_ESCR0 0x3b6
-#define MSR_P4_ITLB_ESCR1 0x3b7
-#define MSR_P4_IX_ESCR0 0x3c8
-#define MSR_P4_IX_ESCR1 0x3c9
-#define MSR_P4_MOB_ESCR0 0x3aa
-#define MSR_P4_MOB_ESCR1 0x3ab
-#define MSR_P4_MS_ESCR0 0x3c0
-#define MSR_P4_MS_ESCR1 0x3c1
-#define MSR_P4_PMH_ESCR0 0x3ac
-#define MSR_P4_PMH_ESCR1 0x3ad
-#define MSR_P4_RAT_ESCR0 0x3bc
-#define MSR_P4_RAT_ESCR1 0x3bd
-#define MSR_P4_SAAT_ESCR0 0x3ae
-#define MSR_P4_SAAT_ESCR1 0x3af
-#define MSR_P4_SSU_ESCR0 0x3be
-#define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */
-#define MSR_P4_TBPU_ESCR0 0x3c2
-#define MSR_P4_TBPU_ESCR1 0x3c3
-#define MSR_P4_TC_ESCR0 0x3c4
-#define MSR_P4_TC_ESCR1 0x3c5
-#define MSR_P4_U2L_ESCR0 0x3b0
-#define MSR_P4_U2L_ESCR1 0x3b1
-
-/* AMD Defined MSRs */
-#define MSR_K6_EFER 0xC0000080
-#define MSR_K6_STAR 0xC0000081
-#define MSR_K6_WHCR 0xC0000082
-#define MSR_K6_UWCCR 0xC0000085
-#define MSR_K6_EPMR 0xC0000086
-#define MSR_K6_PSOR 0xC0000087
-#define MSR_K6_PFIR 0xC0000088
-
-#define MSR_K7_EVNTSEL0 0xC0010000
-#define MSR_K7_EVNTSEL1 0xC0010001
-#define MSR_K7_EVNTSEL2 0xC0010002
-#define MSR_K7_EVNTSEL3 0xC0010003
-#define MSR_K7_PERFCTR0 0xC0010004
-#define MSR_K7_PERFCTR1 0xC0010005
-#define MSR_K7_PERFCTR2 0xC0010006
-#define MSR_K7_PERFCTR3 0xC0010007
-#define MSR_K7_HWCR 0xC0010015
-#define MSR_K7_CLK_CTL 0xC001001b
-#define MSR_K7_FID_VID_CTL 0xC0010041
-#define MSR_K7_FID_VID_STATUS 0xC0010042
-
-#define MSR_K8_ENABLE_C1E 0xC0010055
-
-/* extended feature register */
-#define MSR_EFER 0xc0000080
-
-/* EFER bits: */
-
-/* Execute Disable enable */
-#define _EFER_NX 11
-#define EFER_NX (1<<_EFER_NX)
-
-/* Centaur-Hauls/IDT defined MSRs. */
-#define MSR_IDT_FCR1 0x107
-#define MSR_IDT_FCR2 0x108
-#define MSR_IDT_FCR3 0x109
-#define MSR_IDT_FCR4 0x10a
-
-#define MSR_IDT_MCR0 0x110
-#define MSR_IDT_MCR1 0x111
-#define MSR_IDT_MCR2 0x112
-#define MSR_IDT_MCR3 0x113
-#define MSR_IDT_MCR4 0x114
-#define MSR_IDT_MCR5 0x115
-#define MSR_IDT_MCR6 0x116
-#define MSR_IDT_MCR7 0x117
-#define MSR_IDT_MCR_CTRL 0x120
-
-/* VIA Cyrix defined MSRs*/
-#define MSR_VIA_FCR 0x1107
-#define MSR_VIA_LONGHAUL 0x110a
-#define MSR_VIA_RNG 0x110b
-#define MSR_VIA_BCR2 0x1147
-
-/* Transmeta defined MSRs */
-#define MSR_TMTA_LONGRUN_CTRL 0x80868010
-#define MSR_TMTA_LONGRUN_FLAGS 0x80868011
-#define MSR_TMTA_LRTI_READOUT 0x80868018
-#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a
-
-/* Intel Core-based CPU performance counters */
-#define MSR_CORE_PERF_FIXED_CTR0 0x309
-#define MSR_CORE_PERF_FIXED_CTR1 0x30a
-#define MSR_CORE_PERF_FIXED_CTR2 0x30b
-#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x38d
-#define MSR_CORE_PERF_GLOBAL_STATUS 0x38e
-#define MSR_CORE_PERF_GLOBAL_CTRL 0x38f
-#define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x390
-
-/* Geode defined MSRs */
-#define MSR_GEODE_BUSCONT_CONF0 0x1900
-
+#endif
+#endif
#endif /* __ASM_MSR_H */
diff --git a/include/asm-i386/mtrr.h b/include/asm-i386/mtrr.h
index 07f063ae26e..7e9c7ccbdcf 100644
--- a/include/asm-i386/mtrr.h
+++ b/include/asm-i386/mtrr.h
@@ -69,6 +69,8 @@ struct mtrr_gentry
/* The following functions are for use by other drivers */
# ifdef CONFIG_MTRR
+extern void mtrr_save_fixed_ranges(void *);
+extern void mtrr_save_state(void);
extern int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment);
extern int mtrr_add_page (unsigned long base, unsigned long size,
@@ -79,6 +81,8 @@ extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi);
extern void mtrr_ap_init(void);
extern void mtrr_bp_init(void);
# else
+#define mtrr_save_fixed_ranges(arg) do {} while (0)
+#define mtrr_save_state() do {} while (0)
static __inline__ int mtrr_add (unsigned long base, unsigned long size,
unsigned int type, char increment)
{
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index b04333ea6f3..fb1e133efd9 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -50,4 +50,12 @@ void __trigger_all_cpu_backtrace(void);
#endif
+void lapic_watchdog_stop(void);
+int lapic_watchdog_init(unsigned nmi_hz);
+int lapic_wd_event(unsigned nmi_hz);
+unsigned lapic_adjust_nmi_hz(unsigned hz);
+int lapic_watchdog_ok(void);
+void disable_lapic_nmi_watchdog(void);
+void enable_lapic_nmi_watchdog(void);
+
#endif /* ASM_NMI_H */
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 7b19f454761..818ac8bf01e 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -12,7 +12,6 @@
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
-
#ifdef CONFIG_X86_USE_3DNOW
#include <asm/mmx.h>
@@ -42,26 +41,81 @@
* These are used to make use of C type-checking..
*/
extern int nx_enabled;
+
#ifdef CONFIG_X86_PAE
extern unsigned long long __supported_pte_mask;
typedef struct { unsigned long pte_low, pte_high; } pte_t;
typedef struct { unsigned long long pmd; } pmd_t;
typedef struct { unsigned long long pgd; } pgd_t;
typedef struct { unsigned long long pgprot; } pgprot_t;
-#define pmd_val(x) ((x).pmd)
-#define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
-#define __pmd(x) ((pmd_t) { (x) } )
+
+static inline unsigned long long native_pgd_val(pgd_t pgd)
+{
+ return pgd.pgd;
+}
+
+static inline unsigned long long native_pmd_val(pmd_t pmd)
+{
+ return pmd.pmd;
+}
+
+static inline unsigned long long native_pte_val(pte_t pte)
+{
+ return pte.pte_low | ((unsigned long long)pte.pte_high << 32);
+}
+
+static inline pgd_t native_make_pgd(unsigned long long val)
+{
+ return (pgd_t) { val };
+}
+
+static inline pmd_t native_make_pmd(unsigned long long val)
+{
+ return (pmd_t) { val };
+}
+
+static inline pte_t native_make_pte(unsigned long long val)
+{
+ return (pte_t) { .pte_low = val, .pte_high = (val >> 32) } ;
+}
+
+#ifndef CONFIG_PARAVIRT
+#define pmd_val(x) native_pmd_val(x)
+#define __pmd(x) native_make_pmd(x)
+#endif
+
#define HPAGE_SHIFT 21
#include <asm-generic/pgtable-nopud.h>
-#else
+#else /* !CONFIG_X86_PAE */
typedef struct { unsigned long pte_low; } pte_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
#define boot_pte_t pte_t /* or would you rather have a typedef */
-#define pte_val(x) ((x).pte_low)
+
+static inline unsigned long native_pgd_val(pgd_t pgd)
+{
+ return pgd.pgd;
+}
+
+static inline unsigned long native_pte_val(pte_t pte)
+{
+ return pte.pte_low;
+}
+
+static inline pgd_t native_make_pgd(unsigned long val)
+{
+ return (pgd_t) { val };
+}
+
+static inline pte_t native_make_pte(unsigned long val)
+{
+ return (pte_t) { .pte_low = val };
+}
+
#define HPAGE_SHIFT 22
#include <asm-generic/pgtable-nopmd.h>
-#endif
+#endif /* CONFIG_X86_PAE */
+
#define PTE_MASK PAGE_MASK
#ifdef CONFIG_HUGETLB_PAGE
@@ -71,13 +125,16 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#endif
-#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
-
-#define __pte(x) ((pte_t) { (x) } )
-#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
+#ifndef CONFIG_PARAVIRT
+#define pgd_val(x) native_pgd_val(x)
+#define __pgd(x) native_make_pgd(x)
+#define pte_val(x) native_pte_val(x)
+#define __pte(x) native_make_pte(x)
+#endif
+
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
@@ -143,9 +200,7 @@ extern int page_is_ram(unsigned long pagenr);
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
-#ifndef CONFIG_COMPAT_VDSO
#define __HAVE_ARCH_GATE_AREA 1
-#endif
#endif /* __KERNEL__ */
#endif /* _I386_PAGE_H */
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index e63f1e444fc..bc5c12c1358 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -2,20 +2,9 @@
#define __ASM_PARAVIRT_H
/* Various instructions on x86 need to be replaced for
* para-virtualization: those hooks are defined here. */
-#include <linux/linkage.h>
-#include <linux/stringify.h>
-#include <asm/page.h>
#ifdef CONFIG_PARAVIRT
-/* These are the most performance critical ops, so we want to be able to patch
- * callers */
-#define PARAVIRT_IRQ_DISABLE 0
-#define PARAVIRT_IRQ_ENABLE 1
-#define PARAVIRT_RESTORE_FLAGS 2
-#define PARAVIRT_SAVE_FLAGS 3
-#define PARAVIRT_SAVE_FLAGS_IRQ_DISABLE 4
-#define PARAVIRT_INTERRUPT_RETURN 5
-#define PARAVIRT_STI_SYSEXIT 6
+#include <asm/page.h>
/* Bitmask of what can be clobbered: usually at least eax. */
#define CLBR_NONE 0x0
@@ -25,13 +14,29 @@
#define CLBR_ANY 0x7
#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/cpumask.h>
+#include <asm/kmap_types.h>
+
+struct page;
struct thread_struct;
struct Xgt_desc_struct;
struct tss_struct;
struct mm_struct;
+struct desc_struct;
+
+/* Lazy mode for batching updates / context switch */
+enum paravirt_lazy_mode {
+ PARAVIRT_LAZY_NONE = 0,
+ PARAVIRT_LAZY_MMU = 1,
+ PARAVIRT_LAZY_CPU = 2,
+ PARAVIRT_LAZY_FLUSH = 3,
+};
+
struct paravirt_ops
{
unsigned int kernel_rpl;
+ int shared_kernel_pmd;
int paravirt_enabled;
const char *name;
@@ -44,24 +49,33 @@ struct paravirt_ops
*/
unsigned (*patch)(u8 type, u16 clobber, void *firstinsn, unsigned len);
+ /* Basic arch-specific setup */
void (*arch_setup)(void);
char *(*memory_setup)(void);
void (*init_IRQ)(void);
+ void (*time_init)(void);
+ /*
+ * Called before/after init_mm pagetable setup. setup_start
+ * may reset %cr3, and may pre-install parts of the pagetable;
+ * pagetable setup is expected to preserve any existing
+ * mapping.
+ */
+ void (*pagetable_setup_start)(pgd_t *pgd_base);
+ void (*pagetable_setup_done)(pgd_t *pgd_base);
+
+ /* Print a banner to identify the environment */
void (*banner)(void);
+ /* Set and set time of day */
unsigned long (*get_wallclock)(void);
int (*set_wallclock)(unsigned long);
- void (*time_init)(void);
-
- /* All the function pointers here are declared as "fastcall"
- so that we get a specific register-based calling
- convention. This makes it easier to implement inline
- assembler replacements. */
+ /* cpuid emulation, mostly so that caps bits can be disabled */
void (*cpuid)(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
+ /* hooks for various privileged instructions */
unsigned long (*get_debugreg)(int regno);
void (*set_debugreg)(int regno, unsigned long value);
@@ -80,15 +94,23 @@ struct paravirt_ops
unsigned long (*read_cr4)(void);
void (*write_cr4)(unsigned long);
+ /*
+ * Get/set interrupt state. save_fl and restore_fl are only
+ * expected to use X86_EFLAGS_IF; all other bits
+ * returned from save_fl are undefined, and may be ignored by
+ * restore_fl.
+ */
unsigned long (*save_fl)(void);
void (*restore_fl)(unsigned long);
void (*irq_disable)(void);
void (*irq_enable)(void);
void (*safe_halt)(void);
void (*halt)(void);
+
void (*wbinvd)(void);
- /* err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */
+ /* MSR, PMC and TSR operations.
+ err = 0/-EFAULT. wrmsr returns 0/-EFAULT. */
u64 (*read_msr)(unsigned int msr, int *err);
int (*write_msr)(unsigned int msr, u64 val);
@@ -97,6 +119,7 @@ struct paravirt_ops
u64 (*get_scheduled_cycles)(void);
unsigned long (*get_cpu_khz)(void);
+ /* Segment descriptor handling */
void (*load_tr_desc)(void);
void (*load_gdt)(const struct Xgt_desc_struct *);
void (*load_idt)(const struct Xgt_desc_struct *);
@@ -105,59 +128,98 @@ struct paravirt_ops
void (*set_ldt)(const void *desc, unsigned entries);
unsigned long (*store_tr)(void);
void (*load_tls)(struct thread_struct *t, unsigned int cpu);
- void (*write_ldt_entry)(void *dt, int entrynum,
- u32 low, u32 high);
- void (*write_gdt_entry)(void *dt, int entrynum,
- u32 low, u32 high);
- void (*write_idt_entry)(void *dt, int entrynum,
- u32 low, u32 high);
- void (*load_esp0)(struct tss_struct *tss,
- struct thread_struct *thread);
+ void (*write_ldt_entry)(struct desc_struct *,
+ int entrynum, u32 low, u32 high);
+ void (*write_gdt_entry)(struct desc_struct *,
+ int entrynum, u32 low, u32 high);
+ void (*write_idt_entry)(struct desc_struct *,
+ int entrynum, u32 low, u32 high);
+ void (*load_esp0)(struct tss_struct *tss, struct thread_struct *t);
void (*set_iopl_mask)(unsigned mask);
-
void (*io_delay)(void);
+ /*
+ * Hooks for intercepting the creation/use/destruction of an
+ * mm_struct.
+ */
+ void (*activate_mm)(struct mm_struct *prev,
+ struct mm_struct *next);
+ void (*dup_mmap)(struct mm_struct *oldmm,
+ struct mm_struct *mm);
+ void (*exit_mmap)(struct mm_struct *mm);
+
#ifdef CONFIG_X86_LOCAL_APIC
+ /*
+ * Direct APIC operations, principally for VMI. Ideally
+ * these shouldn't be in this interface.
+ */
void (*apic_write)(unsigned long reg, unsigned long v);
void (*apic_write_atomic)(unsigned long reg, unsigned long v);
unsigned long (*apic_read)(unsigned long reg);
void (*setup_boot_clock)(void);
void (*setup_secondary_clock)(void);
+
+ void (*startup_ipi_hook)(int phys_apicid,
+ unsigned long start_eip,
+ unsigned long start_esp);
#endif
+ /* TLB operations */
void (*flush_tlb_user)(void);
void (*flush_tlb_kernel)(void);
- void (*flush_tlb_single)(u32 addr);
-
- void (*map_pt_hook)(int type, pte_t *va, u32 pfn);
+ void (*flush_tlb_single)(unsigned long addr);
+ void (*flush_tlb_others)(const cpumask_t *cpus, struct mm_struct *mm,
+ unsigned long va);
+ /* Hooks for allocating/releasing pagetable pages */
void (*alloc_pt)(u32 pfn);
void (*alloc_pd)(u32 pfn);
void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
void (*release_pt)(u32 pfn);
void (*release_pd)(u32 pfn);
+ /* Pagetable manipulation functions */
void (*set_pte)(pte_t *ptep, pte_t pteval);
- void (*set_pte_at)(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval);
+ void (*set_pte_at)(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval);
void (*set_pmd)(pmd_t *pmdp, pmd_t pmdval);
- void (*pte_update)(struct mm_struct *mm, u32 addr, pte_t *ptep);
- void (*pte_update_defer)(struct mm_struct *mm, u32 addr, pte_t *ptep);
+ void (*pte_update)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+ void (*pte_update_defer)(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep);
+
+#ifdef CONFIG_HIGHPTE
+ void *(*kmap_atomic_pte)(struct page *page, enum km_type type);
+#endif
+
#ifdef CONFIG_X86_PAE
void (*set_pte_atomic)(pte_t *ptep, pte_t pteval);
- void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
+ void (*set_pte_present)(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte);
void (*set_pud)(pud_t *pudp, pud_t pudval);
- void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+ void (*pte_clear)(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
void (*pmd_clear)(pmd_t *pmdp);
+
+ unsigned long long (*pte_val)(pte_t);
+ unsigned long long (*pmd_val)(pmd_t);
+ unsigned long long (*pgd_val)(pgd_t);
+
+ pte_t (*make_pte)(unsigned long long pte);
+ pmd_t (*make_pmd)(unsigned long long pmd);
+ pgd_t (*make_pgd)(unsigned long long pgd);
+#else
+ unsigned long (*pte_val)(pte_t);
+ unsigned long (*pgd_val)(pgd_t);
+
+ pte_t (*make_pte)(unsigned long pte);
+ pgd_t (*make_pgd)(unsigned long pgd);
#endif
- void (*set_lazy_mode)(int mode);
+ /* Set deferred update mode, used for batching operations. */
+ void (*set_lazy_mode)(enum paravirt_lazy_mode mode);
/* These two are jmp to, not actually called. */
void (*irq_enable_sysexit)(void);
void (*iret)(void);
-
- void (*startup_ipi_hook)(int phys_apicid, unsigned long start_eip, unsigned long start_esp);
};
/* Mark a paravirt probe function. */
@@ -167,23 +229,202 @@ struct paravirt_ops
extern struct paravirt_ops paravirt_ops;
-#define paravirt_enabled() (paravirt_ops.paravirt_enabled)
+#define PARAVIRT_PATCH(x) \
+ (offsetof(struct paravirt_ops, x) / sizeof(void *))
+
+#define paravirt_type(type) \
+ [paravirt_typenum] "i" (PARAVIRT_PATCH(type))
+#define paravirt_clobber(clobber) \
+ [paravirt_clobber] "i" (clobber)
+
+/*
+ * Generate some code, and mark it as patchable by the
+ * apply_paravirt() alternate instruction patcher.
+ */
+#define _paravirt_alt(insn_string, type, clobber) \
+ "771:\n\t" insn_string "\n" "772:\n" \
+ ".pushsection .parainstructions,\"a\"\n" \
+ " .long 771b\n" \
+ " .byte " type "\n" \
+ " .byte 772b-771b\n" \
+ " .short " clobber "\n" \
+ ".popsection\n"
+
+/* Generate patchable code, with the default asm parameters. */
+#define paravirt_alt(insn_string) \
+ _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
+
+unsigned paravirt_patch_nop(void);
+unsigned paravirt_patch_ignore(unsigned len);
+unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
+ void *site, u16 site_clobbers,
+ unsigned len);
+unsigned paravirt_patch_jmp(void *target, void *site, unsigned len);
+unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len);
+
+unsigned paravirt_patch_insns(void *site, unsigned len,
+ const char *start, const char *end);
+
+
+/*
+ * This generates an indirect call based on the operation type number.
+ * The type number, computed in PARAVIRT_PATCH, is derived from the
+ * offset into the paravirt_ops structure, and can therefore be freely
+ * converted back into a structure offset.
+ */
+#define PARAVIRT_CALL "call *(paravirt_ops+%c[paravirt_typenum]*4);"
+
+/*
+ * These macros are intended to wrap calls into a paravirt_ops
+ * operation, so that they can be later identified and patched at
+ * runtime.
+ *
+ * Normally, a call to a pv_op function is a simple indirect call:
+ * (paravirt_ops.operations)(args...).
+ *
+ * Unfortunately, this is a relatively slow operation for modern CPUs,
+ * because it cannot necessarily determine what the destination
+ * address is. In this case, the address is a runtime constant, so at
+ * the very least we can patch the call to e a simple direct call, or
+ * ideally, patch an inline implementation into the callsite. (Direct
+ * calls are essentially free, because the call and return addresses
+ * are completely predictable.)
+ *
+ * These macros rely on the standard gcc "regparm(3)" calling
+ * convention, in which the first three arguments are placed in %eax,
+ * %edx, %ecx (in that order), and the remaining arguments are placed
+ * on the stack. All caller-save registers (eax,edx,ecx) are expected
+ * to be modified (either clobbered or used for return values).
+ *
+ * The call instruction itself is marked by placing its start address
+ * and size into the .parainstructions section, so that
+ * apply_paravirt() in arch/i386/kernel/alternative.c can do the
+ * appropriate patching under the control of the backend paravirt_ops
+ * implementation.
+ *
+ * Unfortunately there's no way to get gcc to generate the args setup
+ * for the call, and then allow the call itself to be generated by an
+ * inline asm. Because of this, we must do the complete arg setup and
+ * return value handling from within these macros. This is fairly
+ * cumbersome.
+ *
+ * There are 5 sets of PVOP_* macros for dealing with 0-4 arguments.
+ * It could be extended to more arguments, but there would be little
+ * to be gained from that. For each number of arguments, there are
+ * the two VCALL and CALL variants for void and non-void functions.
+ *
+ * When there is a return value, the invoker of the macro must specify
+ * the return type. The macro then uses sizeof() on that type to
+ * determine whether its a 32 or 64 bit value, and places the return
+ * in the right register(s) (just %eax for 32-bit, and %edx:%eax for
+ * 64-bit).
+ *
+ * 64-bit arguments are passed as a pair of adjacent 32-bit arguments
+ * in low,high order.
+ *
+ * Small structures are passed and returned in registers. The macro
+ * calling convention can't directly deal with this, so the wrapper
+ * functions must do this.
+ *
+ * These PVOP_* macros are only defined within this header. This
+ * means that all uses must be wrapped in inline functions. This also
+ * makes sure the incoming and outgoing types are always correct.
+ */
+#define __PVOP_CALL(rettype, op, pre, post, ...) \
+ ({ \
+ rettype __ret; \
+ unsigned long __eax, __edx, __ecx; \
+ if (sizeof(rettype) > sizeof(unsigned long)) { \
+ asm volatile(pre \
+ paravirt_alt(PARAVIRT_CALL) \
+ post \
+ : "=a" (__eax), "=d" (__edx), \
+ "=c" (__ecx) \
+ : paravirt_type(op), \
+ paravirt_clobber(CLBR_ANY), \
+ ##__VA_ARGS__ \
+ : "memory", "cc"); \
+ __ret = (rettype)((((u64)__edx) << 32) | __eax); \
+ } else { \
+ asm volatile(pre \
+ paravirt_alt(PARAVIRT_CALL) \
+ post \
+ : "=a" (__eax), "=d" (__edx), \
+ "=c" (__ecx) \
+ : paravirt_type(op), \
+ paravirt_clobber(CLBR_ANY), \
+ ##__VA_ARGS__ \
+ : "memory", "cc"); \
+ __ret = (rettype)__eax; \
+ } \
+ __ret; \
+ })
+#define __PVOP_VCALL(op, pre, post, ...) \
+ ({ \
+ unsigned long __eax, __edx, __ecx; \
+ asm volatile(pre \
+ paravirt_alt(PARAVIRT_CALL) \
+ post \
+ : "=a" (__eax), "=d" (__edx), "=c" (__ecx) \
+ : paravirt_type(op), \
+ paravirt_clobber(CLBR_ANY), \
+ ##__VA_ARGS__ \
+ : "memory", "cc"); \
+ })
+
+#define PVOP_CALL0(rettype, op) \
+ __PVOP_CALL(rettype, op, "", "")
+#define PVOP_VCALL0(op) \
+ __PVOP_VCALL(op, "", "")
+
+#define PVOP_CALL1(rettype, op, arg1) \
+ __PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)))
+#define PVOP_VCALL1(op, arg1) \
+ __PVOP_VCALL(op, "", "", "0" ((u32)(arg1)))
+
+#define PVOP_CALL2(rettype, op, arg1, arg2) \
+ __PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)), "1" ((u32)(arg2)))
+#define PVOP_VCALL2(op, arg1, arg2) \
+ __PVOP_VCALL(op, "", "", "0" ((u32)(arg1)), "1" ((u32)(arg2)))
+
+#define PVOP_CALL3(rettype, op, arg1, arg2, arg3) \
+ __PVOP_CALL(rettype, op, "", "", "0" ((u32)(arg1)), \
+ "1"((u32)(arg2)), "2"((u32)(arg3)))
+#define PVOP_VCALL3(op, arg1, arg2, arg3) \
+ __PVOP_VCALL(op, "", "", "0" ((u32)(arg1)), "1"((u32)(arg2)), \
+ "2"((u32)(arg3)))
+
+#define PVOP_CALL4(rettype, op, arg1, arg2, arg3, arg4) \
+ __PVOP_CALL(rettype, op, \
+ "push %[_arg4];", "lea 4(%%esp),%%esp;", \
+ "0" ((u32)(arg1)), "1" ((u32)(arg2)), \
+ "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
+#define PVOP_VCALL4(op, arg1, arg2, arg3, arg4) \
+ __PVOP_VCALL(op, \
+ "push %[_arg4];", "lea 4(%%esp),%%esp;", \
+ "0" ((u32)(arg1)), "1" ((u32)(arg2)), \
+ "2" ((u32)(arg3)), [_arg4] "mr" ((u32)(arg4)))
+
+static inline int paravirt_enabled(void)
+{
+ return paravirt_ops.paravirt_enabled;
+}
static inline void load_esp0(struct tss_struct *tss,
struct thread_struct *thread)
{
- paravirt_ops.load_esp0(tss, thread);
+ PVOP_VCALL2(load_esp0, tss, thread);
}
#define ARCH_SETUP paravirt_ops.arch_setup();
static inline unsigned long get_wallclock(void)
{
- return paravirt_ops.get_wallclock();
+ return PVOP_CALL0(unsigned long, get_wallclock);
}
static inline int set_wallclock(unsigned long nowtime)
{
- return paravirt_ops.set_wallclock(nowtime);
+ return PVOP_CALL1(int, set_wallclock, nowtime);
}
static inline void (*choose_time_init(void))(void)
@@ -195,113 +436,203 @@ static inline void (*choose_time_init(void))(void)
static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
- paravirt_ops.cpuid(eax, ebx, ecx, edx);
+ PVOP_VCALL4(cpuid, eax, ebx, ecx, edx);
}
/*
* These special macros can be used to get or set a debugging register
*/
-#define get_debugreg(var, reg) var = paravirt_ops.get_debugreg(reg)
-#define set_debugreg(val, reg) paravirt_ops.set_debugreg(reg, val)
+static inline unsigned long paravirt_get_debugreg(int reg)
+{
+ return PVOP_CALL1(unsigned long, get_debugreg, reg);
+}
+#define get_debugreg(var, reg) var = paravirt_get_debugreg(reg)
+static inline void set_debugreg(unsigned long val, int reg)
+{
+ PVOP_VCALL2(set_debugreg, reg, val);
+}
-#define clts() paravirt_ops.clts()
+static inline void clts(void)
+{
+ PVOP_VCALL0(clts);
+}
-#define read_cr0() paravirt_ops.read_cr0()
-#define write_cr0(x) paravirt_ops.write_cr0(x)
+static inline unsigned long read_cr0(void)
+{
+ return PVOP_CALL0(unsigned long, read_cr0);
+}
-#define read_cr2() paravirt_ops.read_cr2()
-#define write_cr2(x) paravirt_ops.write_cr2(x)
+static inline void write_cr0(unsigned long x)
+{
+ PVOP_VCALL1(write_cr0, x);
+}
-#define read_cr3() paravirt_ops.read_cr3()
-#define write_cr3(x) paravirt_ops.write_cr3(x)
+static inline unsigned long read_cr2(void)
+{
+ return PVOP_CALL0(unsigned long, read_cr2);
+}
-#define read_cr4() paravirt_ops.read_cr4()
-#define read_cr4_safe(x) paravirt_ops.read_cr4_safe()
-#define write_cr4(x) paravirt_ops.write_cr4(x)
+static inline void write_cr2(unsigned long x)
+{
+ PVOP_VCALL1(write_cr2, x);
+}
+
+static inline unsigned long read_cr3(void)
+{
+ return PVOP_CALL0(unsigned long, read_cr3);
+}
+
+static inline void write_cr3(unsigned long x)
+{
+ PVOP_VCALL1(write_cr3, x);
+}
+
+static inline unsigned long read_cr4(void)
+{
+ return PVOP_CALL0(unsigned long, read_cr4);
+}
+static inline unsigned long read_cr4_safe(void)
+{
+ return PVOP_CALL0(unsigned long, read_cr4_safe);
+}
+
+static inline void write_cr4(unsigned long x)
+{
+ PVOP_VCALL1(write_cr4, x);
+}
static inline void raw_safe_halt(void)
{
- paravirt_ops.safe_halt();
+ PVOP_VCALL0(safe_halt);
}
static inline void halt(void)
{
- paravirt_ops.safe_halt();
+ PVOP_VCALL0(safe_halt);
+}
+
+static inline void wbinvd(void)
+{
+ PVOP_VCALL0(wbinvd);
}
-#define wbinvd() paravirt_ops.wbinvd()
#define get_kernel_rpl() (paravirt_ops.kernel_rpl)
-#define rdmsr(msr,val1,val2) do { \
- int _err; \
- u64 _l = paravirt_ops.read_msr(msr,&_err); \
- val1 = (u32)_l; \
- val2 = _l >> 32; \
+static inline u64 paravirt_read_msr(unsigned msr, int *err)
+{
+ return PVOP_CALL2(u64, read_msr, msr, err);
+}
+static inline int paravirt_write_msr(unsigned msr, unsigned low, unsigned high)
+{
+ return PVOP_CALL3(int, write_msr, msr, low, high);
+}
+
+/* These should all do BUG_ON(_err), but our headers are too tangled. */
+#define rdmsr(msr,val1,val2) do { \
+ int _err; \
+ u64 _l = paravirt_read_msr(msr, &_err); \
+ val1 = (u32)_l; \
+ val2 = _l >> 32; \
} while(0)
-#define wrmsr(msr,val1,val2) do { \
- u64 _l = ((u64)(val2) << 32) | (val1); \
- paravirt_ops.write_msr((msr), _l); \
+#define wrmsr(msr,val1,val2) do { \
+ paravirt_write_msr(msr, val1, val2); \
} while(0)
-#define rdmsrl(msr,val) do { \
- int _err; \
- val = paravirt_ops.read_msr((msr),&_err); \
+#define rdmsrl(msr,val) do { \
+ int _err; \
+ val = paravirt_read_msr(msr, &_err); \
} while(0)
-#define wrmsrl(msr,val) (paravirt_ops.write_msr((msr),(val)))
-#define wrmsr_safe(msr,a,b) ({ \
- u64 _l = ((u64)(b) << 32) | (a); \
- paravirt_ops.write_msr((msr),_l); \
-})
+#define wrmsrl(msr,val) ((void)paravirt_write_msr(msr, val, 0))
+#define wrmsr_safe(msr,a,b) paravirt_write_msr(msr, a, b)
/* rdmsr with exception handling */
-#define rdmsr_safe(msr,a,b) ({ \
- int _err; \
- u64 _l = paravirt_ops.read_msr(msr,&_err); \
- (*a) = (u32)_l; \
- (*b) = _l >> 32; \
+#define rdmsr_safe(msr,a,b) ({ \
+ int _err; \
+ u64 _l = paravirt_read_msr(msr, &_err); \
+ (*a) = (u32)_l; \
+ (*b) = _l >> 32; \
_err; })
-#define rdtsc(low,high) do { \
- u64 _l = paravirt_ops.read_tsc(); \
- low = (u32)_l; \
- high = _l >> 32; \
-} while(0)
-#define rdtscl(low) do { \
- u64 _l = paravirt_ops.read_tsc(); \
- low = (int)_l; \
+static inline u64 paravirt_read_tsc(void)
+{
+ return PVOP_CALL0(u64, read_tsc);
+}
+
+#define rdtscl(low) do { \
+ u64 _l = paravirt_read_tsc(); \
+ low = (int)_l; \
} while(0)
-#define rdtscll(val) (val = paravirt_ops.read_tsc())
+#define rdtscll(val) (val = paravirt_read_tsc())
#define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
#define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
-#define rdpmc(counter,low,high) do { \
- u64 _l = paravirt_ops.read_pmc(); \
- low = (u32)_l; \
- high = _l >> 32; \
+static inline unsigned long long paravirt_read_pmc(int counter)
+{
+ return PVOP_CALL1(u64, read_pmc, counter);
+}
+
+#define rdpmc(counter,low,high) do { \
+ u64 _l = paravirt_read_pmc(counter); \
+ low = (u32)_l; \
+ high = _l >> 32; \
} while(0)
-#define load_TR_desc() (paravirt_ops.load_tr_desc())
-#define load_gdt(dtr) (paravirt_ops.load_gdt(dtr))
-#define load_idt(dtr) (paravirt_ops.load_idt(dtr))
-#define set_ldt(addr, entries) (paravirt_ops.set_ldt((addr), (entries)))
-#define store_gdt(dtr) (paravirt_ops.store_gdt(dtr))
-#define store_idt(dtr) (paravirt_ops.store_idt(dtr))
-#define store_tr(tr) ((tr) = paravirt_ops.store_tr())
-#define load_TLS(t,cpu) (paravirt_ops.load_tls((t),(cpu)))
-#define write_ldt_entry(dt, entry, low, high) \
- (paravirt_ops.write_ldt_entry((dt), (entry), (low), (high)))
-#define write_gdt_entry(dt, entry, low, high) \
- (paravirt_ops.write_gdt_entry((dt), (entry), (low), (high)))
-#define write_idt_entry(dt, entry, low, high) \
- (paravirt_ops.write_idt_entry((dt), (entry), (low), (high)))
-#define set_iopl_mask(mask) (paravirt_ops.set_iopl_mask(mask))
+static inline void load_TR_desc(void)
+{
+ PVOP_VCALL0(load_tr_desc);
+}
+static inline void load_gdt(const struct Xgt_desc_struct *dtr)
+{
+ PVOP_VCALL1(load_gdt, dtr);
+}
+static inline void load_idt(const struct Xgt_desc_struct *dtr)
+{
+ PVOP_VCALL1(load_idt, dtr);
+}
+static inline void set_ldt(const void *addr, unsigned entries)
+{
+ PVOP_VCALL2(set_ldt, addr, entries);
+}
+static inline void store_gdt(struct Xgt_desc_struct *dtr)
+{
+ PVOP_VCALL1(store_gdt, dtr);
+}
+static inline void store_idt(struct Xgt_desc_struct *dtr)
+{
+ PVOP_VCALL1(store_idt, dtr);
+}
+static inline unsigned long paravirt_store_tr(void)
+{
+ return PVOP_CALL0(unsigned long, store_tr);
+}
+#define store_tr(tr) ((tr) = paravirt_store_tr())
+static inline void load_TLS(struct thread_struct *t, unsigned cpu)
+{
+ PVOP_VCALL2(load_tls, t, cpu);
+}
+static inline void write_ldt_entry(void *dt, int entry, u32 low, u32 high)
+{
+ PVOP_VCALL4(write_ldt_entry, dt, entry, low, high);
+}
+static inline void write_gdt_entry(void *dt, int entry, u32 low, u32 high)
+{
+ PVOP_VCALL4(write_gdt_entry, dt, entry, low, high);
+}
+static inline void write_idt_entry(void *dt, int entry, u32 low, u32 high)
+{
+ PVOP_VCALL4(write_idt_entry, dt, entry, low, high);
+}
+static inline void set_iopl_mask(unsigned mask)
+{
+ PVOP_VCALL1(set_iopl_mask, mask);
+}
/* The paravirtualized I/O functions */
static inline void slow_down_io(void) {
@@ -319,215 +650,390 @@ static inline void slow_down_io(void) {
*/
static inline void apic_write(unsigned long reg, unsigned long v)
{
- paravirt_ops.apic_write(reg,v);
+ PVOP_VCALL2(apic_write, reg, v);
}
static inline void apic_write_atomic(unsigned long reg, unsigned long v)
{
- paravirt_ops.apic_write_atomic(reg,v);
+ PVOP_VCALL2(apic_write_atomic, reg, v);
}
static inline unsigned long apic_read(unsigned long reg)
{
- return paravirt_ops.apic_read(reg);
+ return PVOP_CALL1(unsigned long, apic_read, reg);
}
static inline void setup_boot_clock(void)
{
- paravirt_ops.setup_boot_clock();
+ PVOP_VCALL0(setup_boot_clock);
}
static inline void setup_secondary_clock(void)
{
- paravirt_ops.setup_secondary_clock();
+ PVOP_VCALL0(setup_secondary_clock);
}
#endif
+static inline void paravirt_pagetable_setup_start(pgd_t *base)
+{
+ if (paravirt_ops.pagetable_setup_start)
+ (*paravirt_ops.pagetable_setup_start)(base);
+}
+
+static inline void paravirt_pagetable_setup_done(pgd_t *base)
+{
+ if (paravirt_ops.pagetable_setup_done)
+ (*paravirt_ops.pagetable_setup_done)(base);
+}
+
#ifdef CONFIG_SMP
static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip,
unsigned long start_esp)
{
- return paravirt_ops.startup_ipi_hook(phys_apicid, start_eip, start_esp);
+ PVOP_VCALL3(startup_ipi_hook, phys_apicid, start_eip, start_esp);
}
#endif
-#define __flush_tlb() paravirt_ops.flush_tlb_user()
-#define __flush_tlb_global() paravirt_ops.flush_tlb_kernel()
-#define __flush_tlb_single(addr) paravirt_ops.flush_tlb_single(addr)
+static inline void paravirt_activate_mm(struct mm_struct *prev,
+ struct mm_struct *next)
+{
+ PVOP_VCALL2(activate_mm, prev, next);
+}
-#define paravirt_map_pt_hook(type, va, pfn) paravirt_ops.map_pt_hook(type, va, pfn)
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+ struct mm_struct *mm)
+{
+ PVOP_VCALL2(dup_mmap, oldmm, mm);
+}
-#define paravirt_alloc_pt(pfn) paravirt_ops.alloc_pt(pfn)
-#define paravirt_release_pt(pfn) paravirt_ops.release_pt(pfn)
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+ PVOP_VCALL1(exit_mmap, mm);
+}
-#define paravirt_alloc_pd(pfn) paravirt_ops.alloc_pd(pfn)
-#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) \
- paravirt_ops.alloc_pd_clone(pfn, clonepfn, start, count)
-#define paravirt_release_pd(pfn) paravirt_ops.release_pd(pfn)
+static inline void __flush_tlb(void)
+{
+ PVOP_VCALL0(flush_tlb_user);
+}
+static inline void __flush_tlb_global(void)
+{
+ PVOP_VCALL0(flush_tlb_kernel);
+}
+static inline void __flush_tlb_single(unsigned long addr)
+{
+ PVOP_VCALL1(flush_tlb_single, addr);
+}
-static inline void set_pte(pte_t *ptep, pte_t pteval)
+static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+ unsigned long va)
{
- paravirt_ops.set_pte(ptep, pteval);
+ PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
}
-static inline void set_pte_at(struct mm_struct *mm, u32 addr, pte_t *ptep, pte_t pteval)
+static inline void paravirt_alloc_pt(unsigned pfn)
{
- paravirt_ops.set_pte_at(mm, addr, ptep, pteval);
+ PVOP_VCALL1(alloc_pt, pfn);
+}
+static inline void paravirt_release_pt(unsigned pfn)
+{
+ PVOP_VCALL1(release_pt, pfn);
}
-static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
+static inline void paravirt_alloc_pd(unsigned pfn)
{
- paravirt_ops.set_pmd(pmdp, pmdval);
+ PVOP_VCALL1(alloc_pd, pfn);
}
-static inline void pte_update(struct mm_struct *mm, u32 addr, pte_t *ptep)
+static inline void paravirt_alloc_pd_clone(unsigned pfn, unsigned clonepfn,
+ unsigned start, unsigned count)
{
- paravirt_ops.pte_update(mm, addr, ptep);
+ PVOP_VCALL4(alloc_pd_clone, pfn, clonepfn, start, count);
+}
+static inline void paravirt_release_pd(unsigned pfn)
+{
+ PVOP_VCALL1(release_pd, pfn);
}
-static inline void pte_update_defer(struct mm_struct *mm, u32 addr, pte_t *ptep)
+#ifdef CONFIG_HIGHPTE
+static inline void *kmap_atomic_pte(struct page *page, enum km_type type)
{
- paravirt_ops.pte_update_defer(mm, addr, ptep);
+ unsigned long ret;
+ ret = PVOP_CALL2(unsigned long, kmap_atomic_pte, page, type);
+ return (void *)ret;
+}
+#endif
+
+static inline void pte_update(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ PVOP_VCALL3(pte_update, mm, addr, ptep);
+}
+
+static inline void pte_update_defer(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ PVOP_VCALL3(pte_update_defer, mm, addr, ptep);
}
#ifdef CONFIG_X86_PAE
+static inline pte_t __pte(unsigned long long val)
+{
+ unsigned long long ret = PVOP_CALL2(unsigned long long, make_pte,
+ val, val >> 32);
+ return (pte_t) { ret, ret >> 32 };
+}
+
+static inline pmd_t __pmd(unsigned long long val)
+{
+ return (pmd_t) { PVOP_CALL2(unsigned long long, make_pmd, val, val >> 32) };
+}
+
+static inline pgd_t __pgd(unsigned long long val)
+{
+ return (pgd_t) { PVOP_CALL2(unsigned long long, make_pgd, val, val >> 32) };
+}
+
+static inline unsigned long long pte_val(pte_t x)
+{
+ return PVOP_CALL2(unsigned long long, pte_val, x.pte_low, x.pte_high);
+}
+
+static inline unsigned long long pmd_val(pmd_t x)
+{
+ return PVOP_CALL2(unsigned long long, pmd_val, x.pmd, x.pmd >> 32);
+}
+
+static inline unsigned long long pgd_val(pgd_t x)
+{
+ return PVOP_CALL2(unsigned long long, pgd_val, x.pgd, x.pgd >> 32);
+}
+
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+ PVOP_VCALL3(set_pte, ptep, pteval.pte_low, pteval.pte_high);
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ /* 5 arg words */
+ paravirt_ops.set_pte_at(mm, addr, ptep, pteval);
+}
+
static inline void set_pte_atomic(pte_t *ptep, pte_t pteval)
{
- paravirt_ops.set_pte_atomic(ptep, pteval);
+ PVOP_VCALL3(set_pte_atomic, ptep, pteval.pte_low, pteval.pte_high);
}
-static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+static inline void set_pte_present(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
{
+ /* 5 arg words */
paravirt_ops.set_pte_present(mm, addr, ptep, pte);
}
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ PVOP_VCALL3(set_pmd, pmdp, pmdval.pmd, pmdval.pmd >> 32);
+}
+
static inline void set_pud(pud_t *pudp, pud_t pudval)
{
- paravirt_ops.set_pud(pudp, pudval);
+ PVOP_VCALL3(set_pud, pudp, pudval.pgd.pgd, pudval.pgd.pgd >> 32);
}
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
- paravirt_ops.pte_clear(mm, addr, ptep);
+ PVOP_VCALL3(pte_clear, mm, addr, ptep);
}
static inline void pmd_clear(pmd_t *pmdp)
{
- paravirt_ops.pmd_clear(pmdp);
+ PVOP_VCALL1(pmd_clear, pmdp);
}
-#endif
-/* Lazy mode for batching updates / context switch */
-#define PARAVIRT_LAZY_NONE 0
-#define PARAVIRT_LAZY_MMU 1
-#define PARAVIRT_LAZY_CPU 2
-#define PARAVIRT_LAZY_FLUSH 3
+#else /* !CONFIG_X86_PAE */
+
+static inline pte_t __pte(unsigned long val)
+{
+ return (pte_t) { PVOP_CALL1(unsigned long, make_pte, val) };
+}
+
+static inline pgd_t __pgd(unsigned long val)
+{
+ return (pgd_t) { PVOP_CALL1(unsigned long, make_pgd, val) };
+}
+
+static inline unsigned long pte_val(pte_t x)
+{
+ return PVOP_CALL1(unsigned long, pte_val, x.pte_low);
+}
+
+static inline unsigned long pgd_val(pgd_t x)
+{
+ return PVOP_CALL1(unsigned long, pgd_val, x.pgd);
+}
+
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+ PVOP_VCALL2(set_pte, ptep, pteval.pte_low);
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ PVOP_VCALL4(set_pte_at, mm, addr, ptep, pteval.pte_low);
+}
+
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ PVOP_VCALL2(set_pmd, pmdp, pmdval.pud.pgd.pgd);
+}
+#endif /* CONFIG_X86_PAE */
#define __HAVE_ARCH_ENTER_LAZY_CPU_MODE
-#define arch_enter_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_CPU)
-#define arch_leave_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE)
-#define arch_flush_lazy_cpu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_FLUSH)
+static inline void arch_enter_lazy_cpu_mode(void)
+{
+ PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_CPU);
+}
+
+static inline void arch_leave_lazy_cpu_mode(void)
+{
+ PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_NONE);
+}
+
+static inline void arch_flush_lazy_cpu_mode(void)
+{
+ PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_FLUSH);
+}
+
#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
-#define arch_enter_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_MMU)
-#define arch_leave_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_NONE)
-#define arch_flush_lazy_mmu_mode() paravirt_ops.set_lazy_mode(PARAVIRT_LAZY_FLUSH)
+static inline void arch_enter_lazy_mmu_mode(void)
+{
+ PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_MMU);
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
+{
+ PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_NONE);
+}
+
+static inline void arch_flush_lazy_mmu_mode(void)
+{
+ PVOP_VCALL1(set_lazy_mode, PARAVIRT_LAZY_FLUSH);
+}
+
+void _paravirt_nop(void);
+#define paravirt_nop ((void *)_paravirt_nop)
/* These all sit in the .parainstructions section to tell us what to patch. */
-struct paravirt_patch {
+struct paravirt_patch_site {
u8 *instr; /* original instructions */
u8 instrtype; /* type of this instruction */
u8 len; /* length of original instruction */
u16 clobbers; /* what registers you may clobber */
};
-#define paravirt_alt(insn_string, typenum, clobber) \
- "771:\n\t" insn_string "\n" "772:\n" \
- ".pushsection .parainstructions,\"a\"\n" \
- " .long 771b\n" \
- " .byte " __stringify(typenum) "\n" \
- " .byte 772b-771b\n" \
- " .short " __stringify(clobber) "\n" \
- ".popsection"
+extern struct paravirt_patch_site __parainstructions[],
+ __parainstructions_end[];
static inline unsigned long __raw_local_save_flags(void)
{
unsigned long f;
- __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
- "call *%1;"
- "popl %%edx; popl %%ecx",
- PARAVIRT_SAVE_FLAGS, CLBR_NONE)
- : "=a"(f): "m"(paravirt_ops.save_fl)
- : "memory", "cc");
+ asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+ PARAVIRT_CALL
+ "popl %%edx; popl %%ecx")
+ : "=a"(f)
+ : paravirt_type(save_fl),
+ paravirt_clobber(CLBR_EAX)
+ : "memory", "cc");
return f;
}
static inline void raw_local_irq_restore(unsigned long f)
{
- __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
- "call *%1;"
- "popl %%edx; popl %%ecx",
- PARAVIRT_RESTORE_FLAGS, CLBR_EAX)
- : "=a"(f) : "m" (paravirt_ops.restore_fl), "0"(f)
- : "memory", "cc");
+ asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+ PARAVIRT_CALL
+ "popl %%edx; popl %%ecx")
+ : "=a"(f)
+ : "0"(f),
+ paravirt_type(restore_fl),
+ paravirt_clobber(CLBR_EAX)
+ : "memory", "cc");
}
static inline void raw_local_irq_disable(void)
{
- __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
- "call *%0;"
- "popl %%edx; popl %%ecx",
- PARAVIRT_IRQ_DISABLE, CLBR_EAX)
- : : "m" (paravirt_ops.irq_disable)
- : "memory", "eax", "cc");
+ asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+ PARAVIRT_CALL
+ "popl %%edx; popl %%ecx")
+ :
+ : paravirt_type(irq_disable),
+ paravirt_clobber(CLBR_EAX)
+ : "memory", "eax", "cc");
}
static inline void raw_local_irq_enable(void)
{
- __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
- "call *%0;"
- "popl %%edx; popl %%ecx",
- PARAVIRT_IRQ_ENABLE, CLBR_EAX)
- : : "m" (paravirt_ops.irq_enable)
- : "memory", "eax", "cc");
+ asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
+ PARAVIRT_CALL
+ "popl %%edx; popl %%ecx")
+ :
+ : paravirt_type(irq_enable),
+ paravirt_clobber(CLBR_EAX)
+ : "memory", "eax", "cc");
}
static inline unsigned long __raw_local_irq_save(void)
{
unsigned long f;
- __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
- "call *%1; pushl %%eax;"
- "call *%2; popl %%eax;"
- "popl %%edx; popl %%ecx",
- PARAVIRT_SAVE_FLAGS_IRQ_DISABLE,
- CLBR_NONE)
- : "=a"(f)
- : "m" (paravirt_ops.save_fl),
- "m" (paravirt_ops.irq_disable)
- : "memory", "cc");
+ f = __raw_local_save_flags();
+ raw_local_irq_disable();
return f;
}
-#define CLI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;" \
- "call *paravirt_ops+%c[irq_disable];" \
- "popl %%edx; popl %%ecx", \
- PARAVIRT_IRQ_DISABLE, CLBR_EAX)
+#define CLI_STRING \
+ _paravirt_alt("pushl %%ecx; pushl %%edx;" \
+ "call *paravirt_ops+%c[paravirt_cli_type]*4;" \
+ "popl %%edx; popl %%ecx", \
+ "%c[paravirt_cli_type]", "%c[paravirt_clobber]")
+
+#define STI_STRING \
+ _paravirt_alt("pushl %%ecx; pushl %%edx;" \
+ "call *paravirt_ops+%c[paravirt_sti_type]*4;" \
+ "popl %%edx; popl %%ecx", \
+ "%c[paravirt_sti_type]", "%c[paravirt_clobber]")
-#define STI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;" \
- "call *paravirt_ops+%c[irq_enable];" \
- "popl %%edx; popl %%ecx", \
- PARAVIRT_IRQ_ENABLE, CLBR_EAX)
#define CLI_STI_CLOBBERS , "%eax"
-#define CLI_STI_INPUT_ARGS \
+#define CLI_STI_INPUT_ARGS \
, \
- [irq_disable] "i" (offsetof(struct paravirt_ops, irq_disable)), \
- [irq_enable] "i" (offsetof(struct paravirt_ops, irq_enable))
+ [paravirt_cli_type] "i" (PARAVIRT_PATCH(irq_disable)), \
+ [paravirt_sti_type] "i" (PARAVIRT_PATCH(irq_enable)), \
+ paravirt_clobber(CLBR_EAX)
+
+/* Make sure as little as possible of this mess escapes. */
+#undef PARAVIRT_CALL
+#undef __PVOP_CALL
+#undef __PVOP_VCALL
+#undef PVOP_VCALL0
+#undef PVOP_CALL0
+#undef PVOP_VCALL1
+#undef PVOP_CALL1
+#undef PVOP_VCALL2
+#undef PVOP_CALL2
+#undef PVOP_VCALL3
+#undef PVOP_CALL3
+#undef PVOP_VCALL4
+#undef PVOP_CALL4
#else /* __ASSEMBLY__ */
-#define PARA_PATCH(ptype, clobbers, ops) \
+#define PARA_PATCH(off) ((off) / 4)
+
+#define PARA_SITE(ptype, clobbers, ops) \
771:; \
ops; \
772:; \
@@ -538,28 +1044,30 @@ static inline unsigned long __raw_local_irq_save(void)
.short clobbers; \
.popsection
-#define INTERRUPT_RETURN \
- PARA_PATCH(PARAVIRT_INTERRUPT_RETURN, CLBR_ANY, \
- jmp *%cs:paravirt_ops+PARAVIRT_iret)
+#define INTERRUPT_RETURN \
+ PARA_SITE(PARA_PATCH(PARAVIRT_iret), CLBR_NONE, \
+ jmp *%cs:paravirt_ops+PARAVIRT_iret)
-#define DISABLE_INTERRUPTS(clobbers) \
- PARA_PATCH(PARAVIRT_IRQ_DISABLE, clobbers, \
- pushl %ecx; pushl %edx; \
- call *paravirt_ops+PARAVIRT_irq_disable; \
- popl %edx; popl %ecx) \
+#define DISABLE_INTERRUPTS(clobbers) \
+ PARA_SITE(PARA_PATCH(PARAVIRT_irq_disable), clobbers, \
+ pushl %eax; pushl %ecx; pushl %edx; \
+ call *%cs:paravirt_ops+PARAVIRT_irq_disable; \
+ popl %edx; popl %ecx; popl %eax) \
-#define ENABLE_INTERRUPTS(clobbers) \
- PARA_PATCH(PARAVIRT_IRQ_ENABLE, clobbers, \
- pushl %ecx; pushl %edx; \
- call *%cs:paravirt_ops+PARAVIRT_irq_enable; \
- popl %edx; popl %ecx)
+#define ENABLE_INTERRUPTS(clobbers) \
+ PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable), clobbers, \
+ pushl %eax; pushl %ecx; pushl %edx; \
+ call *%cs:paravirt_ops+PARAVIRT_irq_enable; \
+ popl %edx; popl %ecx; popl %eax)
-#define ENABLE_INTERRUPTS_SYSEXIT \
- PARA_PATCH(PARAVIRT_STI_SYSEXIT, CLBR_ANY, \
- jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
+#define ENABLE_INTERRUPTS_SYSEXIT \
+ PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable_sysexit), CLBR_NONE, \
+ jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
#define GET_CR0_INTO_EAX \
- call *paravirt_ops+PARAVIRT_read_cr0
+ push %ecx; push %edx; \
+ call *paravirt_ops+PARAVIRT_read_cr0; \
+ pop %edx; pop %ecx
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_PARAVIRT */
diff --git a/include/asm-i386/pda.h b/include/asm-i386/pda.h
deleted file mode 100644
index b12d59a318b..00000000000
--- a/include/asm-i386/pda.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- Per-processor Data Areas
- Jeremy Fitzhardinge <jeremy@goop.org> 2006
- Based on asm-x86_64/pda.h by Andi Kleen.
- */
-#ifndef _I386_PDA_H
-#define _I386_PDA_H
-
-#include <linux/stddef.h>
-#include <linux/types.h>
-
-struct i386_pda
-{
- struct i386_pda *_pda; /* pointer to self */
-
- int cpu_number;
- struct task_struct *pcurrent; /* current process */
- struct pt_regs *irq_regs;
-};
-
-extern struct i386_pda *_cpu_pda[];
-
-#define cpu_pda(i) (_cpu_pda[i])
-
-#define pda_offset(field) offsetof(struct i386_pda, field)
-
-extern void __bad_pda_field(void);
-
-/* This variable is never instantiated. It is only used as a stand-in
- for the real per-cpu PDA memory, so that gcc can understand what
- memory operations the inline asms() below are performing. This
- eliminates the need to make the asms volatile or have memory
- clobbers, so gcc can readily analyse them. */
-extern struct i386_pda _proxy_pda;
-
-#define pda_to_op(op,field,val) \
- do { \
- typedef typeof(_proxy_pda.field) T__; \
- if (0) { T__ tmp__; tmp__ = (val); } \
- switch (sizeof(_proxy_pda.field)) { \
- case 1: \
- asm(op "b %1,%%fs:%c2" \
- : "+m" (_proxy_pda.field) \
- :"ri" ((T__)val), \
- "i"(pda_offset(field))); \
- break; \
- case 2: \
- asm(op "w %1,%%fs:%c2" \
- : "+m" (_proxy_pda.field) \
- :"ri" ((T__)val), \
- "i"(pda_offset(field))); \
- break; \
- case 4: \
- asm(op "l %1,%%fs:%c2" \
- : "+m" (_proxy_pda.field) \
- :"ri" ((T__)val), \
- "i"(pda_offset(field))); \
- break; \
- default: __bad_pda_field(); \
- } \
- } while (0)
-
-#define pda_from_op(op,field) \
- ({ \
- typeof(_proxy_pda.field) ret__; \
- switch (sizeof(_proxy_pda.field)) { \
- case 1: \
- asm(op "b %%fs:%c1,%0" \
- : "=r" (ret__) \
- : "i" (pda_offset(field)), \
- "m" (_proxy_pda.field)); \
- break; \
- case 2: \
- asm(op "w %%fs:%c1,%0" \
- : "=r" (ret__) \
- : "i" (pda_offset(field)), \
- "m" (_proxy_pda.field)); \
- break; \
- case 4: \
- asm(op "l %%fs:%c1,%0" \
- : "=r" (ret__) \
- : "i" (pda_offset(field)), \
- "m" (_proxy_pda.field)); \
- break; \
- default: __bad_pda_field(); \
- } \
- ret__; })
-
-/* Return a pointer to a pda field */
-#define pda_addr(field) \
- ((typeof(_proxy_pda.field) *)((unsigned char *)read_pda(_pda) + \
- pda_offset(field)))
-
-#define read_pda(field) pda_from_op("mov",field)
-#define write_pda(field,val) pda_to_op("mov",field,val)
-#define add_pda(field,val) pda_to_op("add",field,val)
-#define sub_pda(field,val) pda_to_op("sub",field,val)
-#define or_pda(field,val) pda_to_op("or",field,val)
-
-#endif /* _I386_PDA_H */
diff --git a/include/asm-i386/percpu.h b/include/asm-i386/percpu.h
index 510ae1d3486..f54830b5d5a 100644
--- a/include/asm-i386/percpu.h
+++ b/include/asm-i386/percpu.h
@@ -1,9 +1,32 @@
#ifndef __ARCH_I386_PERCPU__
#define __ARCH_I386_PERCPU__
-#ifndef __ASSEMBLY__
-#include <asm-generic/percpu.h>
-#else
+#ifdef __ASSEMBLY__
+
+/*
+ * PER_CPU finds an address of a per-cpu variable.
+ *
+ * Args:
+ * var - variable name
+ * reg - 32bit register
+ *
+ * The resulting address is stored in the "reg" argument.
+ *
+ * Example:
+ * PER_CPU(cpu_gdt_descr, %ebx)
+ */
+#ifdef CONFIG_SMP
+#define PER_CPU(var, reg) \
+ movl %fs:per_cpu__##this_cpu_off, reg; \
+ lea per_cpu__##var(reg), reg
+#define PER_CPU_VAR(var) %fs:per_cpu__##var
+#else /* ! SMP */
+#define PER_CPU(var, reg) \
+ movl $per_cpu__##var, reg
+#define PER_CPU_VAR(var) per_cpu__##var
+#endif /* SMP */
+
+#else /* ...!ASSEMBLY */
/*
* PER_CPU finds an address of a per-cpu variable.
@@ -18,14 +41,109 @@
* PER_CPU(cpu_gdt_descr, %ebx)
*/
#ifdef CONFIG_SMP
-#define PER_CPU(var, cpu) \
- movl __per_cpu_offset(,cpu,4), cpu; \
- addl $per_cpu__/**/var, cpu;
-#else /* ! SMP */
-#define PER_CPU(var, cpu) \
- movl $per_cpu__/**/var, cpu;
+/* Same as generic implementation except for optimized local access. */
+#define __GENERIC_PER_CPU
+
+/* This is used for other cpus to find our section. */
+extern unsigned long __per_cpu_offset[];
+
+#define per_cpu_offset(x) (__per_cpu_offset[x])
+
+/* Separate out the type, so (int[3], foo) works. */
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU(type, name) \
+ __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+
+/* We can use this directly for local CPU (faster). */
+DECLARE_PER_CPU(unsigned long, this_cpu_off);
+
+/* var is in discarded region: offset to particular copy we want */
+#define per_cpu(var, cpu) (*({ \
+ extern int simple_indentifier_##var(void); \
+ RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
+
+#define __raw_get_cpu_var(var) (*({ \
+ extern int simple_indentifier_##var(void); \
+ RELOC_HIDE(&per_cpu__##var, x86_read_percpu(this_cpu_off)); \
+}))
+
+#define __get_cpu_var(var) __raw_get_cpu_var(var)
+
+/* A macro to avoid #include hell... */
+#define percpu_modcopy(pcpudst, src, size) \
+do { \
+ unsigned int __i; \
+ for_each_possible_cpu(__i) \
+ memcpy((pcpudst)+__per_cpu_offset[__i], \
+ (src), (size)); \
+} while (0)
+
+#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
+#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
+
+/* fs segment starts at (positive) offset == __per_cpu_offset[cpu] */
+#define __percpu_seg "%%fs:"
+#else /* !SMP */
+#include <asm-generic/percpu.h>
+#define __percpu_seg ""
#endif /* SMP */
+/* For arch-specific code, we can use direct single-insn ops (they
+ * don't give an lvalue though). */
+extern void __bad_percpu_size(void);
+
+#define percpu_to_op(op,var,val) \
+ do { \
+ typedef typeof(var) T__; \
+ if (0) { T__ tmp__; tmp__ = (val); } \
+ switch (sizeof(var)) { \
+ case 1: \
+ asm(op "b %1,"__percpu_seg"%0" \
+ : "+m" (var) \
+ :"ri" ((T__)val)); \
+ break; \
+ case 2: \
+ asm(op "w %1,"__percpu_seg"%0" \
+ : "+m" (var) \
+ :"ri" ((T__)val)); \
+ break; \
+ case 4: \
+ asm(op "l %1,"__percpu_seg"%0" \
+ : "+m" (var) \
+ :"ri" ((T__)val)); \
+ break; \
+ default: __bad_percpu_size(); \
+ } \
+ } while (0)
+
+#define percpu_from_op(op,var) \
+ ({ \
+ typeof(var) ret__; \
+ switch (sizeof(var)) { \
+ case 1: \
+ asm(op "b "__percpu_seg"%1,%0" \
+ : "=r" (ret__) \
+ : "m" (var)); \
+ break; \
+ case 2: \
+ asm(op "w "__percpu_seg"%1,%0" \
+ : "=r" (ret__) \
+ : "m" (var)); \
+ break; \
+ case 4: \
+ asm(op "l "__percpu_seg"%1,%0" \
+ : "=r" (ret__) \
+ : "m" (var)); \
+ break; \
+ default: __bad_percpu_size(); \
+ } \
+ ret__; })
+
+#define x86_read_percpu(var) percpu_from_op("mov", per_cpu__##var)
+#define x86_write_percpu(var,val) percpu_to_op("mov", per_cpu__##var, val)
+#define x86_add_percpu(var,val) percpu_to_op("add", per_cpu__##var, val)
+#define x86_sub_percpu(var,val) percpu_to_op("sub", per_cpu__##var, val)
+#define x86_or_percpu(var,val) percpu_to_op("or", per_cpu__##var, val)
#endif /* !__ASSEMBLY__ */
#endif /* __ARCH_I386_PERCPU__ */
diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
index c8dc2d0141a..47430175b75 100644
--- a/include/asm-i386/pgalloc.h
+++ b/include/asm-i386/pgalloc.h
@@ -1,7 +1,6 @@
#ifndef _I386_PGALLOC_H
#define _I386_PGALLOC_H
-#include <asm/fixmap.h>
#include <linux/threads.h>
#include <linux/mm.h> /* for struct page */
diff --git a/include/asm-i386/pgtable-2level-defs.h b/include/asm-i386/pgtable-2level-defs.h
index 02518079f81..0f71c9f13da 100644
--- a/include/asm-i386/pgtable-2level-defs.h
+++ b/include/asm-i386/pgtable-2level-defs.h
@@ -1,6 +1,8 @@
#ifndef _I386_PGTABLE_2LEVEL_DEFS_H
#define _I386_PGTABLE_2LEVEL_DEFS_H
+#define SHARED_KERNEL_PMD 0
+
/*
* traditional i386 two-level paging structure:
*/
diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
index 38c3fcc0676..a50fd1773de 100644
--- a/include/asm-i386/pgtable-2level.h
+++ b/include/asm-i386/pgtable-2level.h
@@ -11,10 +11,23 @@
* within a page table are directly modified. Thus, the following
* hook is made available.
*/
+static inline void native_set_pte(pte_t *ptep , pte_t pte)
+{
+ *ptep = pte;
+}
+static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep , pte_t pte)
+{
+ native_set_pte(ptep, pte);
+}
+static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+ *pmdp = pmd;
+}
#ifndef CONFIG_PARAVIRT
-#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#define set_pte(pteptr, pteval) native_set_pte(pteptr, pteval)
+#define set_pte_at(mm,addr,ptep,pteval) native_set_pte_at(mm, addr, ptep, pteval)
+#define set_pmd(pmdptr, pmdval) native_set_pmd(pmdptr, pmdval)
#endif
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
@@ -23,11 +36,23 @@
#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0)
-#define raw_ptep_get_and_clear(xp) __pte(xchg(&(xp)->pte_low, 0))
+static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *xp)
+{
+ *xp = __pte(0);
+}
+
+#ifdef CONFIG_SMP
+static inline pte_t native_ptep_get_and_clear(pte_t *xp)
+{
+ return __pte(xchg(&xp->pte_low, 0));
+}
+#else
+#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
+#endif
#define pte_page(x) pfn_to_page(pte_pfn(x))
#define pte_none(x) (!(x).pte_low)
-#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
+#define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
@@ -66,6 +91,4 @@ static inline int pte_exec_kernel(pte_t pte)
#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).pte_low })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
-void vmalloc_sync_all(void);
-
#endif /* _I386_PGTABLE_2LEVEL_H */
diff --git a/include/asm-i386/pgtable-3level-defs.h b/include/asm-i386/pgtable-3level-defs.h
index eb3a1ea8867..c0df89f66e8 100644
--- a/include/asm-i386/pgtable-3level-defs.h
+++ b/include/asm-i386/pgtable-3level-defs.h
@@ -1,6 +1,12 @@
#ifndef _I386_PGTABLE_3LEVEL_DEFS_H
#define _I386_PGTABLE_3LEVEL_DEFS_H
+#ifdef CONFIG_PARAVIRT
+#define SHARED_KERNEL_PMD (paravirt_ops.shared_kernel_pmd)
+#else
+#define SHARED_KERNEL_PMD 1
+#endif
+
/*
* PGDIR_SHIFT determines what a top-level page table entry can map
*/
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
index 7a2318f3830..eb0f1d7e96a 100644
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -42,20 +42,23 @@ static inline int pte_exec_kernel(pte_t pte)
return pte_x(pte);
}
-#ifndef CONFIG_PARAVIRT
/* Rules for using set_pte: the pte being assigned *must* be
* either not present or in a state where the hardware will
* not attempt to update the pte. In places where this is
* not possible, use pte_get_and_clear to obtain the old pte
* value and then use set_pte to update it. -ben
*/
-static inline void set_pte(pte_t *ptep, pte_t pte)
+static inline void native_set_pte(pte_t *ptep, pte_t pte)
{
ptep->pte_high = pte.pte_high;
smp_wmb();
ptep->pte_low = pte.pte_low;
}
-#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+static inline void native_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep , pte_t pte)
+{
+ native_set_pte(ptep, pte);
+}
/*
* Since this is only called on user PTEs, and the page fault handler
@@ -63,7 +66,8 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
* we are justified in merely clearing the PTE present bit, followed
* by a set. The ordering here is important.
*/
-static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+static inline void native_set_pte_present(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
{
ptep->pte_low = 0;
smp_wmb();
@@ -72,32 +76,48 @@ static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte
ptep->pte_low = pte.pte_low;
}
-#define set_pte_atomic(pteptr,pteval) \
- set_64bit((unsigned long long *)(pteptr),pte_val(pteval))
-#define set_pmd(pmdptr,pmdval) \
- set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval))
-#define set_pud(pudptr,pudval) \
- (*(pudptr) = (pudval))
+static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+ set_64bit((unsigned long long *)(ptep),native_pte_val(pte));
+}
+static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+ set_64bit((unsigned long long *)(pmdp),native_pmd_val(pmd));
+}
+static inline void native_set_pud(pud_t *pudp, pud_t pud)
+{
+ *pudp = pud;
+}
/*
* For PTEs and PDEs, we must clear the P-bit first when clearing a page table
* entry, so clear the bottom half first and enforce ordering with a compiler
* barrier.
*/
-static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static inline void native_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
ptep->pte_low = 0;
smp_wmb();
ptep->pte_high = 0;
}
-static inline void pmd_clear(pmd_t *pmd)
+static inline void native_pmd_clear(pmd_t *pmd)
{
u32 *tmp = (u32 *)pmd;
*tmp = 0;
smp_wmb();
*(tmp + 1) = 0;
}
+
+#ifndef CONFIG_PARAVIRT
+#define set_pte(ptep, pte) native_set_pte(ptep, pte)
+#define set_pte_at(mm, addr, ptep, pte) native_set_pte_at(mm, addr, ptep, pte)
+#define set_pte_present(mm, addr, ptep, pte) native_set_pte_present(mm, addr, ptep, pte)
+#define set_pte_atomic(ptep, pte) native_set_pte_atomic(ptep, pte)
+#define set_pmd(pmdp, pmd) native_set_pmd(pmdp, pmd)
+#define set_pud(pudp, pud) native_set_pud(pudp, pud)
+#define pte_clear(mm, addr, ptep) native_pte_clear(mm, addr, ptep)
+#define pmd_clear(pmd) native_pmd_clear(pmd)
#endif
/*
@@ -119,7 +139,8 @@ static inline void pud_clear (pud_t * pud) { }
#define pmd_offset(pud, address) ((pmd_t *) pud_page(*(pud)) + \
pmd_index(address))
-static inline pte_t raw_ptep_get_and_clear(pte_t *ptep)
+#ifdef CONFIG_SMP
+static inline pte_t native_ptep_get_and_clear(pte_t *ptep)
{
pte_t res;
@@ -130,6 +151,9 @@ static inline pte_t raw_ptep_get_and_clear(pte_t *ptep)
return res;
}
+#else
+#define native_ptep_get_and_clear(xp) native_local_ptep_get_and_clear(xp)
+#endif
#define __HAVE_ARCH_PTE_SAME
static inline int pte_same(pte_t a, pte_t b)
@@ -146,28 +170,21 @@ static inline int pte_none(pte_t pte)
static inline unsigned long pte_pfn(pte_t pte)
{
- return (pte.pte_low >> PAGE_SHIFT) |
- (pte.pte_high << (32 - PAGE_SHIFT));
+ return pte_val(pte) >> PAGE_SHIFT;
}
extern unsigned long long __supported_pte_mask;
static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
{
- pte_t pte;
-
- pte.pte_high = (page_nr >> (32 - PAGE_SHIFT)) | \
- (pgprot_val(pgprot) >> 32);
- pte.pte_high &= (__supported_pte_mask >> 32);
- pte.pte_low = ((page_nr << PAGE_SHIFT) | pgprot_val(pgprot)) & \
- __supported_pte_mask;
- return pte;
+ return __pte((((unsigned long long)page_nr << PAGE_SHIFT) |
+ pgprot_val(pgprot)) & __supported_pte_mask);
}
static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
{
- return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) | \
- pgprot_val(pgprot)) & __supported_pte_mask);
+ return __pmd((((unsigned long long)page_nr << PAGE_SHIFT) |
+ pgprot_val(pgprot)) & __supported_pte_mask);
}
/*
@@ -187,6 +204,4 @@ static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
#define __pmd_free_tlb(tlb, x) do { } while (0)
-#define vmalloc_sync_all() ((void)0)
-
#endif /* _I386_PGTABLE_3LEVEL_H */
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index c3b58d473a5..edce9d51a67 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -159,6 +159,7 @@ void paging_init(void);
extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
+#define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD)
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
@@ -166,6 +167,7 @@ extern unsigned long long __PAGE_KERNEL, __PAGE_KERNEL_EXEC;
#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
+#define PAGE_KERNEL_RX __pgprot(__PAGE_KERNEL_RX)
#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)
@@ -263,9 +265,18 @@ static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return p
*/
#define pte_update(mm, addr, ptep) do { } while (0)
#define pte_update_defer(mm, addr, ptep) do { } while (0)
-#define paravirt_map_pt_hook(slot, va, pfn) do { } while (0)
#endif
+/* local pte updates need not use xchg for locking */
+static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
+{
+ pte_t res = *ptep;
+
+ /* Pure native function needs no input for mm, addr */
+ native_pte_clear(NULL, 0, ptep);
+ return res;
+}
+
/*
* We only update the dirty/accessed state if we set
* the dirty bit by hand in the kernel, since the hardware
@@ -283,12 +294,25 @@ do { \
} \
} while (0)
-/*
- * We don't actually have these, but we want to advertise them so that
- * we can encompass the flush here.
- */
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define ptep_test_and_clear_dirty(vma, addr, ptep) ({ \
+ int ret = 0; \
+ if (pte_dirty(*ptep)) \
+ ret = test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low); \
+ if (ret) \
+ pte_update_defer(vma->vm_mm, addr, ptep); \
+ ret; \
+})
+
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(vma, addr, ptep) ({ \
+ int ret = 0; \
+ if (pte_young(*ptep)) \
+ ret = test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low); \
+ if (ret) \
+ pte_update_defer(vma->vm_mm, addr, ptep); \
+ ret; \
+})
/*
* Rules for using ptep_establish: the pte MUST be a user pte, and
@@ -305,12 +329,9 @@ do { \
#define ptep_clear_flush_dirty(vma, address, ptep) \
({ \
int __dirty; \
- __dirty = pte_dirty(*(ptep)); \
- if (__dirty) { \
- clear_bit(_PAGE_BIT_DIRTY, &(ptep)->pte_low); \
- pte_update_defer((vma)->vm_mm, (address), (ptep)); \
+ __dirty = ptep_test_and_clear_dirty((vma), (address), (ptep)); \
+ if (__dirty) \
flush_tlb_page(vma, address); \
- } \
__dirty; \
})
@@ -318,19 +339,16 @@ do { \
#define ptep_clear_flush_young(vma, address, ptep) \
({ \
int __young; \
- __young = pte_young(*(ptep)); \
- if (__young) { \
- clear_bit(_PAGE_BIT_ACCESSED, &(ptep)->pte_low); \
- pte_update_defer((vma)->vm_mm, (address), (ptep)); \
+ __young = ptep_test_and_clear_young((vma), (address), (ptep)); \
+ if (__young) \
flush_tlb_page(vma, address); \
- } \
__young; \
})
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
- pte_t pte = raw_ptep_get_and_clear(ptep);
+ pte_t pte = native_ptep_get_and_clear(ptep);
pte_update(mm, addr, ptep);
return pte;
}
@@ -340,8 +358,11 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
{
pte_t pte;
if (full) {
- pte = *ptep;
- pte_clear(mm, addr, ptep);
+ /*
+ * Full address destruction in progress; paravirt does not
+ * care about updates and native needs no locking
+ */
+ pte = native_local_ptep_get_and_clear(ptep);
} else {
pte = ptep_get_and_clear(mm, addr, ptep);
}
@@ -470,24 +491,10 @@ extern pte_t *lookup_address(unsigned long address);
#endif
#if defined(CONFIG_HIGHPTE)
-#define pte_offset_map(dir, address) \
-({ \
- pte_t *__ptep; \
- unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \
- __ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE0);\
- paravirt_map_pt_hook(KM_PTE0,__ptep, pfn); \
- __ptep = __ptep + pte_index(address); \
- __ptep; \
-})
-#define pte_offset_map_nested(dir, address) \
-({ \
- pte_t *__ptep; \
- unsigned pfn = pmd_val(*(dir)) >> PAGE_SHIFT; \
- __ptep = (pte_t *)kmap_atomic(pfn_to_page(pfn),KM_PTE1);\
- paravirt_map_pt_hook(KM_PTE1,__ptep, pfn); \
- __ptep = __ptep + pte_index(address); \
- __ptep; \
-})
+#define pte_offset_map(dir, address) \
+ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE0) + pte_index(address))
+#define pte_offset_map_nested(dir, address) \
+ ((pte_t *)kmap_atomic_pte(pmd_page(*(dir)),KM_PTE1) + pte_index(address))
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
#else
@@ -510,6 +517,22 @@ do { \
* tables contain all the necessary information.
*/
#define update_mmu_cache(vma,address,pte) do { } while (0)
+
+void native_pagetable_setup_start(pgd_t *base);
+void native_pagetable_setup_done(pgd_t *base);
+
+#ifndef CONFIG_PARAVIRT
+static inline void paravirt_pagetable_setup_start(pgd_t *base)
+{
+ native_pagetable_setup_start(base);
+}
+
+static inline void paravirt_pagetable_setup_done(pgd_t *base)
+{
+ native_pagetable_setup_done(base);
+}
+#endif /* !CONFIG_PARAVIRT */
+
#endif /* !__ASSEMBLY__ */
#ifdef CONFIG_FLATMEM
@@ -519,10 +542,6 @@ do { \
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#include <asm-generic/pgtable.h>
#endif /* _I386_PGTABLE_H */
diff --git a/include/asm-i386/processor-flags.h b/include/asm-i386/processor-flags.h
new file mode 100644
index 00000000000..5404e90edd5
--- /dev/null
+++ b/include/asm-i386/processor-flags.h
@@ -0,0 +1,91 @@
+#ifndef __ASM_I386_PROCESSOR_FLAGS_H
+#define __ASM_I386_PROCESSOR_FLAGS_H
+/* Various flags defined: can be included from assembler. */
+
+/*
+ * EFLAGS bits
+ */
+#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
+#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
+#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
+#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
+#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
+#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
+#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
+#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
+#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
+#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
+#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
+#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
+#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
+#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
+#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
+#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
+#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
+
+/*
+ * Basic CPU control in CR0
+ */
+#define X86_CR0_PE 0x00000001 /* Protection Enable */
+#define X86_CR0_MP 0x00000002 /* Monitor Coprocessor */
+#define X86_CR0_EM 0x00000004 /* Emulation */
+#define X86_CR0_TS 0x00000008 /* Task Switched */
+#define X86_CR0_ET 0x00000010 /* Extension Type */
+#define X86_CR0_NE 0x00000020 /* Numeric Error */
+#define X86_CR0_WP 0x00010000 /* Write Protect */
+#define X86_CR0_AM 0x00040000 /* Alignment Mask */
+#define X86_CR0_NW 0x20000000 /* Not Write-through */
+#define X86_CR0_CD 0x40000000 /* Cache Disable */
+#define X86_CR0_PG 0x80000000 /* Paging */
+
+/*
+ * Paging options in CR3
+ */
+#define X86_CR3_PWT 0x00000008 /* Page Write Through */
+#define X86_CR3_PCD 0x00000010 /* Page Cache Disable */
+
+/*
+ * Intel CPU features in CR4
+ */
+#define X86_CR4_VME 0x00000001 /* enable vm86 extensions */
+#define X86_CR4_PVI 0x00000002 /* virtual interrupts flag enable */
+#define X86_CR4_TSD 0x00000004 /* disable time stamp at ipl 3 */
+#define X86_CR4_DE 0x00000008 /* enable debugging extensions */
+#define X86_CR4_PSE 0x00000010 /* enable page size extensions */
+#define X86_CR4_PAE 0x00000020 /* enable physical address extensions */
+#define X86_CR4_MCE 0x00000040 /* Machine check enable */
+#define X86_CR4_PGE 0x00000080 /* enable global pages */
+#define X86_CR4_PCE 0x00000100 /* enable performance counters at ipl 3 */
+#define X86_CR4_OSFXSR 0x00000200 /* enable fast FPU save and restore */
+#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
+#define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */
+
+/*
+ * x86-64 Task Priority Register, CR8
+ */
+#define X86_CR8_TPR 0x00000007 /* task priority register */
+
+/*
+ * AMD and Transmeta use MSRs for configuration; see <asm/msr-index.h>
+ */
+
+/*
+ * NSC/Cyrix CPU configuration register indexes
+ */
+#define CX86_PCR0 0x20
+#define CX86_GCR 0xb8
+#define CX86_CCR0 0xc0
+#define CX86_CCR1 0xc1
+#define CX86_CCR2 0xc2
+#define CX86_CCR3 0xc3
+#define CX86_CCR4 0xe8
+#define CX86_CCR5 0xe9
+#define CX86_CCR6 0xea
+#define CX86_CCR7 0xeb
+#define CX86_PCR1 0xf0
+#define CX86_DIR0 0xfe
+#define CX86_DIR1 0xff
+#define CX86_ARR_BASE 0xc4
+#define CX86_RCR_BASE 0xdc
+
+#endif /* __ASM_I386_PROCESSOR_FLAGS_H */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 11bf899de8a..70f3515c3db 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -21,6 +21,7 @@
#include <asm/percpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
+#include <asm/processor-flags.h>
/* flag for disabling the tsc */
extern int tsc_disable;
@@ -115,7 +116,8 @@ extern char ignore_fpu_irq;
void __init cpu_detect(struct cpuinfo_x86 *c);
-extern void identify_cpu(struct cpuinfo_x86 *);
+extern void identify_boot_cpu(void);
+extern void identify_secondary_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);
extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
extern unsigned short num_cache_leaves;
@@ -126,28 +128,7 @@ extern void detect_ht(struct cpuinfo_x86 *c);
static inline void detect_ht(struct cpuinfo_x86 *c) {}
#endif
-/*
- * EFLAGS bits
- */
-#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
-#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
-#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
-#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
-#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
-#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
-#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
-#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
-#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
-#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
-#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
-#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
-#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
-#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
-
-static inline fastcall void native_cpuid(unsigned int *eax, unsigned int *ebx,
+static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
/* ecx is often an input as well as an output. */
@@ -162,21 +143,6 @@ static inline fastcall void native_cpuid(unsigned int *eax, unsigned int *ebx,
#define load_cr3(pgdir) write_cr3(__pa(pgdir))
/*
- * Intel CPU features in CR4
- */
-#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
-#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
-#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
-#define X86_CR4_DE 0x0008 /* enable debugging extensions */
-#define X86_CR4_PSE 0x0010 /* enable page size extensions */
-#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
-#define X86_CR4_MCE 0x0040 /* Machine check enable */
-#define X86_CR4_PGE 0x0080 /* enable global pages */
-#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
-#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
-#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
-
-/*
* Save the cr4 feature set we're using (ie
* Pentium 4MB enable and PPro Global page
* enable), so that any CPU's that boot up
@@ -203,26 +169,6 @@ static inline void clear_in_cr4 (unsigned long mask)
}
/*
- * NSC/Cyrix CPU configuration register indexes
- */
-
-#define CX86_PCR0 0x20
-#define CX86_GCR 0xb8
-#define CX86_CCR0 0xc0
-#define CX86_CCR1 0xc1
-#define CX86_CCR2 0xc2
-#define CX86_CCR3 0xc3
-#define CX86_CCR4 0xe8
-#define CX86_CCR5 0xe9
-#define CX86_CCR6 0xea
-#define CX86_CCR7 0xeb
-#define CX86_PCR1 0xf0
-#define CX86_DIR0 0xfe
-#define CX86_DIR1 0xff
-#define CX86_ARR_BASE 0xc4
-#define CX86_RCR_BASE 0xdc
-
-/*
* NSC/Cyrix CPU indexed register access macros
*/
@@ -345,7 +291,8 @@ typedef struct {
struct thread_struct;
-struct tss_struct {
+/* This is the TSS defined by the hardware. */
+struct i386_hw_tss {
unsigned short back_link,__blh;
unsigned long esp0;
unsigned short ss0,__ss0h;
@@ -369,6 +316,11 @@ struct tss_struct {
unsigned short gs, __gsh;
unsigned short ldt, __ldth;
unsigned short trace, io_bitmap_base;
+} __attribute__((packed));
+
+struct tss_struct {
+ struct i386_hw_tss x86_tss;
+
/*
* The extra 1 is there because the CPU will access an
* additional byte beyond the end of the IO permission
@@ -421,10 +373,11 @@ struct thread_struct {
};
#define INIT_THREAD { \
+ .esp0 = sizeof(init_stack) + (long)&init_stack, \
.vm86_info = NULL, \
.sysenter_cs = __KERNEL_CS, \
.io_bitmap_ptr = NULL, \
- .fs = __KERNEL_PDA, \
+ .fs = __KERNEL_PERCPU, \
}
/*
@@ -434,10 +387,12 @@ struct thread_struct {
* be within the limit.
*/
#define INIT_TSS { \
- .esp0 = sizeof(init_stack) + (long)&init_stack, \
- .ss0 = __KERNEL_DS, \
- .ss1 = __KERNEL_CS, \
- .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \
+ .x86_tss = { \
+ .esp0 = sizeof(init_stack) + (long)&init_stack, \
+ .ss0 = __KERNEL_DS, \
+ .ss1 = __KERNEL_CS, \
+ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \
+ }, \
.io_bitmap = { [ 0 ... IO_BITMAP_LONGS] = ~0 }, \
}
@@ -544,40 +499,70 @@ static inline void rep_nop(void)
#define cpu_relax() rep_nop()
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define paravirt_enabled() 0
-#define __cpuid native_cpuid
-
-static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
+static inline void native_load_esp0(struct tss_struct *tss, struct thread_struct *thread)
{
- tss->esp0 = thread->esp0;
+ tss->x86_tss.esp0 = thread->esp0;
/* This can only happen when SEP is enabled, no need to test "SEP"arately */
- if (unlikely(tss->ss1 != thread->sysenter_cs)) {
- tss->ss1 = thread->sysenter_cs;
+ if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
+ tss->x86_tss.ss1 = thread->sysenter_cs;
wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
}
}
-/*
- * These special macros can be used to get or set a debugging register
- */
-#define get_debugreg(var, register) \
- __asm__("movl %%db" #register ", %0" \
- :"=r" (var))
-#define set_debugreg(value, register) \
- __asm__("movl %0,%%db" #register \
- : /* no output */ \
- :"r" (value))
-#define set_iopl_mask native_set_iopl_mask
-#endif /* CONFIG_PARAVIRT */
+static inline unsigned long native_get_debugreg(int regno)
+{
+ unsigned long val = 0; /* Damn you, gcc! */
+
+ switch (regno) {
+ case 0:
+ asm("movl %%db0, %0" :"=r" (val)); break;
+ case 1:
+ asm("movl %%db1, %0" :"=r" (val)); break;
+ case 2:
+ asm("movl %%db2, %0" :"=r" (val)); break;
+ case 3:
+ asm("movl %%db3, %0" :"=r" (val)); break;
+ case 6:
+ asm("movl %%db6, %0" :"=r" (val)); break;
+ case 7:
+ asm("movl %%db7, %0" :"=r" (val)); break;
+ default:
+ BUG();
+ }
+ return val;
+}
+
+static inline void native_set_debugreg(int regno, unsigned long value)
+{
+ switch (regno) {
+ case 0:
+ asm("movl %0,%%db0" : /* no output */ :"r" (value));
+ break;
+ case 1:
+ asm("movl %0,%%db1" : /* no output */ :"r" (value));
+ break;
+ case 2:
+ asm("movl %0,%%db2" : /* no output */ :"r" (value));
+ break;
+ case 3:
+ asm("movl %0,%%db3" : /* no output */ :"r" (value));
+ break;
+ case 6:
+ asm("movl %0,%%db6" : /* no output */ :"r" (value));
+ break;
+ case 7:
+ asm("movl %0,%%db7" : /* no output */ :"r" (value));
+ break;
+ default:
+ BUG();
+ }
+}
/*
* Set IOPL bits in EFLAGS from given mask
*/
-static fastcall inline void native_set_iopl_mask(unsigned mask)
+static inline void native_set_iopl_mask(unsigned mask)
{
unsigned int reg;
__asm__ __volatile__ ("pushfl;"
@@ -590,6 +575,28 @@ static fastcall inline void native_set_iopl_mask(unsigned mask)
: "i" (~X86_EFLAGS_IOPL), "r" (mask));
}
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define paravirt_enabled() 0
+#define __cpuid native_cpuid
+
+static inline void load_esp0(struct tss_struct *tss, struct thread_struct *thread)
+{
+ native_load_esp0(tss, thread);
+}
+
+/*
+ * These special macros can be used to get or set a debugging register
+ */
+#define get_debugreg(var, register) \
+ (var) = native_get_debugreg(register)
+#define set_debugreg(value, register) \
+ native_set_debugreg(register, value)
+
+#define set_iopl_mask native_set_iopl_mask
+#endif /* CONFIG_PARAVIRT */
+
/*
* Generic CPUID function
* clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
@@ -742,8 +749,10 @@ extern unsigned long boot_option_idle_override;
extern void enable_sep_cpu(void);
extern int sysenter_setup(void);
-extern int init_gdt(int cpu, struct task_struct *idle);
extern void cpu_set_gdt(int);
-extern void secondary_cpu_init(void);
+extern void switch_to_new_gdt(void);
+extern void cpu_init(void);
+
+extern int force_mwait;
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/reboot.h b/include/asm-i386/reboot.h
new file mode 100644
index 00000000000..e9e3ffc22c0
--- /dev/null
+++ b/include/asm-i386/reboot.h
@@ -0,0 +1,20 @@
+#ifndef _ASM_REBOOT_H
+#define _ASM_REBOOT_H
+
+struct pt_regs;
+
+struct machine_ops
+{
+ void (*restart)(char *cmd);
+ void (*halt)(void);
+ void (*power_off)(void);
+ void (*shutdown)(void);
+ void (*crash_shutdown)(struct pt_regs *);
+ void (*emergency_restart)(void);
+};
+
+extern struct machine_ops machine_ops;
+
+void machine_real_restart(unsigned char *code, int length);
+
+#endif /* _ASM_REBOOT_H */
diff --git a/include/linux/reboot_fixups.h b/include/asm-i386/reboot_fixups.h
index 480ea2d489d..0cb7d87c2b6 100644
--- a/include/linux/reboot_fixups.h
+++ b/include/asm-i386/reboot_fixups.h
@@ -1,10 +1,6 @@
#ifndef _LINUX_REBOOT_FIXUPS_H
#define _LINUX_REBOOT_FIXUPS_H
-#ifdef CONFIG_X86_REBOOTFIXUPS
extern void mach_reboot_fixups(void);
-#else
-#define mach_reboot_fixups() ((void)(0))
-#endif
#endif /* _LINUX_REBOOT_FIXUPS_H */
diff --git a/include/asm-i386/required-features.h b/include/asm-i386/required-features.h
new file mode 100644
index 00000000000..9db866c1e64
--- /dev/null
+++ b/include/asm-i386/required-features.h
@@ -0,0 +1,34 @@
+#ifndef _ASM_REQUIRED_FEATURES_H
+#define _ASM_REQUIRED_FEATURES_H 1
+
+/* Define minimum CPUID feature set for kernel These bits are checked
+ really early to actually display a visible error message before the
+ kernel dies. Only add word 0 bits here
+
+ Some requirements that are not in CPUID yet are also in the
+ CONFIG_X86_MINIMUM_CPU mode which is checked too.
+
+ The real information is in arch/i386/Kconfig.cpu, this just converts
+ the CONFIGs into a bitmask */
+
+#ifdef CONFIG_X86_PAE
+#define NEED_PAE (1<<X86_FEATURE_PAE)
+#else
+#define NEED_PAE 0
+#endif
+
+#ifdef CONFIG_X86_CMOV
+#define NEED_CMOV (1<<X86_FEATURE_CMOV)
+#else
+#define NEED_CMOV 0
+#endif
+
+#ifdef CONFIG_X86_CMPXCHG64
+#define NEED_CMPXCHG64 (1<<X86_FEATURE_CX8)
+#else
+#define NEED_CMPXCHG64 0
+#endif
+
+#define REQUIRED_MASK1 (NEED_PAE|NEED_CMOV|NEED_CMPXCHG64)
+
+#endif
diff --git a/include/asm-i386/scatterlist.h b/include/asm-i386/scatterlist.h
index 55d6c953a76..d7e45a8f1aa 100644
--- a/include/asm-i386/scatterlist.h
+++ b/include/asm-i386/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef _I386_SCATTERLIST_H
#define _I386_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-i386/segment.h b/include/asm-i386/segment.h
index 065f10bfa48..597a47c2515 100644
--- a/include/asm-i386/segment.h
+++ b/include/asm-i386/segment.h
@@ -39,7 +39,7 @@
* 25 - APM BIOS support
*
* 26 - ESPFIX small SS
- * 27 - PDA [ per-cpu private data area ]
+ * 27 - per-cpu [ offset to per-cpu data area ]
* 28 - unused
* 29 - unused
* 30 - unused
@@ -74,8 +74,12 @@
#define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14)
#define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8)
-#define GDT_ENTRY_PDA (GDT_ENTRY_KERNEL_BASE + 15)
-#define __KERNEL_PDA (GDT_ENTRY_PDA * 8)
+#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15)
+#ifdef CONFIG_SMP
+#define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8)
+#else
+#define __KERNEL_PERCPU 0
+#endif
#define GDT_ENTRY_DOUBLEFAULT_TSS 31
diff --git a/include/asm-i386/serial.h b/include/asm-i386/serial.h
index bd67480ca10..57a4306cdf6 100644
--- a/include/asm-i386/serial.h
+++ b/include/asm-i386/serial.h
@@ -11,19 +11,3 @@
* megabits/second; but this requires the faster clock.
*/
#define BASE_BAUD ( 1843200 / 16 )
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#define SERIAL_PORT_DFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 6bf0033a301..0c713278706 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -8,19 +8,15 @@
#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/cpumask.h>
-#include <asm/pda.h>
#endif
-#ifdef CONFIG_X86_LOCAL_APIC
-#ifndef __ASSEMBLY__
-#include <asm/fixmap.h>
+#if defined(CONFIG_X86_LOCAL_APIC) && !defined(__ASSEMBLY__)
#include <asm/bitops.h>
#include <asm/mpspec.h>
+#include <asm/apic.h>
#ifdef CONFIG_X86_IO_APIC
#include <asm/io_apic.h>
#endif
-#include <asm/apic.h>
-#endif
#endif
#define BAD_APICID 0xFFu
@@ -52,6 +48,59 @@ extern void cpu_exit_clear(void);
extern void cpu_uninit(void);
#endif
+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 (*smp_call_function_mask)(cpumask_t mask,
+ void (*func)(void *info), void *info,
+ int wait);
+};
+
+extern struct smp_ops smp_ops;
+
+static inline void smp_prepare_boot_cpu(void)
+{
+ smp_ops.smp_prepare_boot_cpu();
+}
+static inline void smp_prepare_cpus(unsigned int max_cpus)
+{
+ smp_ops.smp_prepare_cpus(max_cpus);
+}
+static inline int __cpu_up(unsigned int cpu)
+{
+ return smp_ops.cpu_up(cpu);
+}
+static inline void smp_cpus_done(unsigned int max_cpus)
+{
+ smp_ops.smp_cpus_done(max_cpus);
+}
+
+static inline void smp_send_stop(void)
+{
+ smp_ops.smp_send_stop();
+}
+static inline void smp_send_reschedule(int cpu)
+{
+ smp_ops.smp_send_reschedule(cpu);
+}
+static inline int smp_call_function_mask(cpumask_t mask,
+ void (*func) (void *info), void *info,
+ int wait)
+{
+ return smp_ops.smp_call_function_mask(mask, func, info, wait);
+}
+
+void native_smp_prepare_boot_cpu(void);
+void native_smp_prepare_cpus(unsigned int max_cpus);
+int native_cpu_up(unsigned int cpunum);
+void native_smp_cpus_done(unsigned int max_cpus);
+
#ifndef CONFIG_PARAVIRT
#define startup_ipi_hook(phys_apicid, start_eip, start_esp) \
do { } while (0)
@@ -62,7 +111,8 @@ do { } while (0)
* from the initial startup. We map APIC_BASE very early in page_setup(),
* so this is correct in the x86 case.
*/
-#define raw_smp_processor_id() (read_pda(cpu_number))
+DECLARE_PER_CPU(int, cpu_number);
+#define raw_smp_processor_id() (x86_read_percpu(cpu_number))
extern cpumask_t cpu_callout_map;
extern cpumask_t cpu_callin_map;
@@ -74,20 +124,6 @@ static inline int num_booting_cpus(void)
return cpus_weight(cpu_callout_map);
}
-#ifdef CONFIG_X86_LOCAL_APIC
-
-#ifdef APIC_DEFINITION
-extern int hard_smp_processor_id(void);
-#else
-#include <mach_apicdef.h>
-static inline int hard_smp_processor_id(void)
-{
- /* we don't want to mark this access volatile - bad code generation */
- return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
-}
-#endif
-#endif
-
extern int safe_smp_processor_id(void);
extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
@@ -102,10 +138,31 @@ extern unsigned int num_processors;
#define NO_PROC_ID 0xFF /* No processor magic marker */
-#endif
+#endif /* CONFIG_SMP */
#ifndef __ASSEMBLY__
+#ifdef CONFIG_X86_LOCAL_APIC
+
+#ifdef APIC_DEFINITION
+extern int hard_smp_processor_id(void);
+#else
+#include <mach_apicdef.h>
+static inline int hard_smp_processor_id(void)
+{
+ /* we don't want to mark this access volatile - bad code generation */
+ return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
+}
+#endif /* APIC_DEFINITION */
+
+#else /* CONFIG_X86_LOCAL_APIC */
+
+#ifndef CONFIG_SMP
+#define hard_smp_processor_id() 0
+#endif
+
+#endif /* CONFIG_X86_LOCAL_APIC */
+
extern u8 apicid_2_node[];
#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-i386/sync_bitops.h b/include/asm-i386/sync_bitops.h
index 7d72351bea7..cbce08a2d13 100644
--- a/include/asm-i386/sync_bitops.h
+++ b/include/asm-i386/sync_bitops.h
@@ -24,7 +24,7 @@
* if you do not require the atomic guarantees.
*
* Note: there are no guarantees that this function will not be reordered
- * on non x86 architectures, so if you are writting portable code,
+ * on non-x86 architectures, so if you are writing portable code,
* make sure not to rely on its reordering guarantees.
*
* Note that @nr may be almost arbitrarily large; this function is not
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index a6d20d9a1a3..94ed3686a5f 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -4,7 +4,7 @@
#include <linux/kernel.h>
#include <asm/segment.h>
#include <asm/cpufeature.h>
-#include <linux/bitops.h> /* for LOCK_PREFIX */
+#include <asm/cmpxchg.h>
#ifdef __KERNEL__
@@ -88,314 +88,113 @@ __asm__ __volatile__ ("movw %%dx,%1\n\t" \
#define savesegment(seg, value) \
asm volatile("mov %%" #seg ",%0":"=rm" (value))
-#ifdef CONFIG_PARAVIRT
-#include <asm/paravirt.h>
-#else
-#define read_cr0() ({ \
- unsigned int __dummy; \
- __asm__ __volatile__( \
- "movl %%cr0,%0\n\t" \
- :"=r" (__dummy)); \
- __dummy; \
-})
-#define write_cr0(x) \
- __asm__ __volatile__("movl %0,%%cr0": :"r" (x))
-
-#define read_cr2() ({ \
- unsigned int __dummy; \
- __asm__ __volatile__( \
- "movl %%cr2,%0\n\t" \
- :"=r" (__dummy)); \
- __dummy; \
-})
-#define write_cr2(x) \
- __asm__ __volatile__("movl %0,%%cr2": :"r" (x))
-
-#define read_cr3() ({ \
- unsigned int __dummy; \
- __asm__ ( \
- "movl %%cr3,%0\n\t" \
- :"=r" (__dummy)); \
- __dummy; \
-})
-#define write_cr3(x) \
- __asm__ __volatile__("movl %0,%%cr3": :"r" (x))
-
-#define read_cr4() ({ \
- unsigned int __dummy; \
- __asm__( \
- "movl %%cr4,%0\n\t" \
- :"=r" (__dummy)); \
- __dummy; \
-})
-#define read_cr4_safe() ({ \
- unsigned int __dummy; \
- /* This could fault if %cr4 does not exist */ \
- __asm__("1: movl %%cr4, %0 \n" \
- "2: \n" \
- ".section __ex_table,\"a\" \n" \
- ".long 1b,2b \n" \
- ".previous \n" \
- : "=r" (__dummy): "0" (0)); \
- __dummy; \
-})
-#define write_cr4(x) \
- __asm__ __volatile__("movl %0,%%cr4": :"r" (x))
-
-#define wbinvd() \
- __asm__ __volatile__ ("wbinvd": : :"memory")
-
-/* Clear the 'TS' bit */
-#define clts() __asm__ __volatile__ ("clts")
-#endif/* CONFIG_PARAVIRT */
-
-/* Set the 'TS' bit */
-#define stts() write_cr0(8 | read_cr0())
-
-#endif /* __KERNEL__ */
-static inline unsigned long get_limit(unsigned long segment)
+static inline void native_clts(void)
{
- unsigned long __limit;
- __asm__("lsll %1,%0"
- :"=r" (__limit):"r" (segment));
- return __limit+1;
+ asm volatile ("clts");
}
-#define nop() __asm__ __volatile__ ("nop")
-
-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
-
-#define tas(ptr) (xchg((ptr),1))
-
-struct __xchg_dummy { unsigned long a[100]; };
-#define __xg(x) ((struct __xchg_dummy *)(x))
-
-
-#ifdef CONFIG_X86_CMPXCHG64
-
-/*
- * The semantics of XCHGCMP8B are a bit strange, this is why
- * there is a loop and the loading of %%eax and %%edx has to
- * be inside. This inlines well in most cases, the cached
- * cost is around ~38 cycles. (in the future we might want
- * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
- * might have an implicit FPU-save as a cost, so it's not
- * clear which path to go.)
- *
- * cmpxchg8b must be used with the lock prefix here to allow
- * the instruction to be executed atomically, see page 3-102
- * of the instruction set reference 24319102.pdf. We need
- * the reader side to see the coherent 64bit value.
- */
-static inline void __set_64bit (unsigned long long * ptr,
- unsigned int low, unsigned int high)
+static inline unsigned long native_read_cr0(void)
{
- __asm__ __volatile__ (
- "\n1:\t"
- "movl (%0), %%eax\n\t"
- "movl 4(%0), %%edx\n\t"
- "lock cmpxchg8b (%0)\n\t"
- "jnz 1b"
- : /* no outputs */
- : "D"(ptr),
- "b"(low),
- "c"(high)
- : "ax","dx","memory");
+ unsigned long val;
+ asm volatile("movl %%cr0,%0\n\t" :"=r" (val));
+ return val;
}
-static inline void __set_64bit_constant (unsigned long long *ptr,
- unsigned long long value)
+static inline void native_write_cr0(unsigned long val)
{
- __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
+ asm volatile("movl %0,%%cr0": :"r" (val));
}
-#define ll_low(x) *(((unsigned int*)&(x))+0)
-#define ll_high(x) *(((unsigned int*)&(x))+1)
-static inline void __set_64bit_var (unsigned long long *ptr,
- unsigned long long value)
+static inline unsigned long native_read_cr2(void)
{
- __set_64bit(ptr,ll_low(value), ll_high(value));
+ unsigned long val;
+ asm volatile("movl %%cr2,%0\n\t" :"=r" (val));
+ return val;
}
-#define set_64bit(ptr,value) \
-(__builtin_constant_p(value) ? \
- __set_64bit_constant(ptr, value) : \
- __set_64bit_var(ptr, value) )
-
-#define _set_64bit(ptr,value) \
-(__builtin_constant_p(value) ? \
- __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
- __set_64bit(ptr, ll_low(value), ll_high(value)) )
+static inline void native_write_cr2(unsigned long val)
+{
+ asm volatile("movl %0,%%cr2": :"r" (val));
+}
-#endif
+static inline unsigned long native_read_cr3(void)
+{
+ unsigned long val;
+ asm volatile("movl %%cr3,%0\n\t" :"=r" (val));
+ return val;
+}
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static inline void native_write_cr3(unsigned long val)
{
- switch (size) {
- case 1:
- __asm__ __volatile__("xchgb %b0,%1"
- :"=q" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 2:
- __asm__ __volatile__("xchgw %w0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 4:
- __asm__ __volatile__("xchgl %0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- }
- return x;
+ asm volatile("movl %0,%%cr3": :"r" (val));
}
-/*
- * Atomic compare and exchange. Compare OLD with MEM, if identical,
- * store NEW in MEM. Return the initial value in MEM. Success is
- * indicated by comparing RETURN with OLD.
- */
+static inline unsigned long native_read_cr4(void)
+{
+ unsigned long val;
+ asm volatile("movl %%cr4,%0\n\t" :"=r" (val));
+ return val;
+}
-#ifdef CONFIG_X86_CMPXCHG
-#define __HAVE_ARCH_CMPXCHG 1
-#define cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
-#define sync_cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__sync_cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
-#endif
+static inline unsigned long native_read_cr4_safe(void)
+{
+ unsigned long val;
+ /* This could fault if %cr4 does not exist */
+ asm("1: movl %%cr4, %0 \n"
+ "2: \n"
+ ".section __ex_table,\"a\" \n"
+ ".long 1b,2b \n"
+ ".previous \n"
+ : "=r" (val): "0" (0));
+ return val;
+}
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
+static inline void native_write_cr4(unsigned long val)
{
- unsigned long prev;
- switch (size) {
- case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
+ asm volatile("movl %0,%%cr4": :"r" (val));
}
-/*
- * Always use locked operations when touching memory shared with a
- * hypervisor, since the system may be SMP even if the guest kernel
- * isn't.
- */
-static inline unsigned long __sync_cmpxchg(volatile void *ptr,
- unsigned long old,
- unsigned long new, int size)
+static inline void native_wbinvd(void)
{
- unsigned long prev;
- switch (size) {
- case 1:
- __asm__ __volatile__("lock; cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- __asm__ __volatile__("lock; cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- __asm__ __volatile__("lock; cmpxchgl %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
+ asm volatile("wbinvd": : :"memory");
}
-#ifndef CONFIG_X86_CMPXCHG
-/*
- * Building a kernel capable running on 80386. It may be necessary to
- * simulate the cmpxchg on the 80386 CPU. For that purpose we define
- * a function for each of the sizes we support.
- */
-extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
-extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
-extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#else
+#define read_cr0() (native_read_cr0())
+#define write_cr0(x) (native_write_cr0(x))
+#define read_cr2() (native_read_cr2())
+#define write_cr2(x) (native_write_cr2(x))
+#define read_cr3() (native_read_cr3())
+#define write_cr3(x) (native_write_cr3(x))
+#define read_cr4() (native_read_cr4())
+#define read_cr4_safe() (native_read_cr4_safe())
+#define write_cr4(x) (native_write_cr4(x))
+#define wbinvd() (native_wbinvd())
+
+/* Clear the 'TS' bit */
+#define clts() (native_clts())
-static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- switch (size) {
- case 1:
- return cmpxchg_386_u8(ptr, old, new);
- case 2:
- return cmpxchg_386_u16(ptr, old, new);
- case 4:
- return cmpxchg_386_u32(ptr, old, new);
- }
- return old;
-}
+#endif/* CONFIG_PARAVIRT */
-#define cmpxchg(ptr,o,n) \
-({ \
- __typeof__(*(ptr)) __ret; \
- if (likely(boot_cpu_data.x86 > 3)) \
- __ret = __cmpxchg((ptr), (unsigned long)(o), \
- (unsigned long)(n), sizeof(*(ptr))); \
- else \
- __ret = cmpxchg_386((ptr), (unsigned long)(o), \
- (unsigned long)(n), sizeof(*(ptr))); \
- __ret; \
-})
-#endif
+/* Set the 'TS' bit */
+#define stts() write_cr0(8 | read_cr0())
-#ifdef CONFIG_X86_CMPXCHG64
+#endif /* __KERNEL__ */
-static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
- unsigned long long new)
+static inline unsigned long get_limit(unsigned long segment)
{
- unsigned long long prev;
- __asm__ __volatile__(LOCK_PREFIX "cmpxchg8b %3"
- : "=A"(prev)
- : "b"((unsigned long)new),
- "c"((unsigned long)(new >> 32)),
- "m"(*__xg(ptr)),
- "0"(old)
- : "memory");
- return prev;
+ unsigned long __limit;
+ __asm__("lsll %1,%0"
+ :"=r" (__limit):"r" (segment));
+ return __limit+1;
}
-#define cmpxchg64(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg64((ptr),(unsigned long long)(o),\
- (unsigned long long)(n)))
+#define nop() __asm__ __volatile__ ("nop")
-#endif
-
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
diff --git a/include/asm-i386/termbits.h b/include/asm-i386/termbits.h
index 2e623769381..a21700352e7 100644
--- a/include/asm-i386/termbits.h
+++ b/include/asm-i386/termbits.h
@@ -17,6 +17,17 @@ struct termios {
cc_t c_cc[NCCS]; /* control characters */
};
+struct termios2 {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
struct ktermios {
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
@@ -129,6 +140,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -148,6 +160,8 @@ struct ktermios {
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-i386/termios.h b/include/asm-i386/termios.h
index 7c99678a8f8..f520b7c16fa 100644
--- a/include/asm-i386/termios.h
+++ b/include/asm-i386/termios.h
@@ -81,8 +81,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 4b187bb377b..4cb0f91ae64 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -95,12 +95,14 @@ static inline struct thread_info *current_thread_info(void)
/* thread information allocation */
#ifdef CONFIG_DEBUG_STACK_USAGE
-#define alloc_thread_info(tsk) kzalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+ __get_free_pages(GFP_KERNEL| __GFP_ZERO, get_order(THREAD_SIZE)))
#else
-#define alloc_thread_info(tsk) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#define alloc_thread_info(tsk) ((struct thread_info *) \
+ __get_free_pages(GFP_KERNEL, get_order(THREAD_SIZE)))
#endif
-#define free_thread_info(info) kfree(info)
+#define free_thread_info(info) free_pages((unsigned long)(info), get_order(THREAD_SIZE))
#else /* !__ASSEMBLY__ */
@@ -170,7 +172,7 @@ static inline struct thread_info *current_thread_info(void)
#define TS_USEDFPU 0x0001 /* FPU was used by this task this quantum (SMP) */
#define TS_POLLING 0x0002 /* True if in idle loop and not sleeping */
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index 12dd67bf760..153770e25fa 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -9,8 +9,6 @@ void setup_pit_timer(void);
unsigned long long native_sched_clock(void);
unsigned long native_calculate_cpu_khz(void);
-/* Modifiers for buggy PIT handling */
-extern int pit_latch_buggy;
extern int timer_ack;
extern int no_timer_check;
extern int no_sync_cmos_clock;
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
index 4dd82840d53..db7f77eacfa 100644
--- a/include/asm-i386/tlbflush.h
+++ b/include/asm-i386/tlbflush.h
@@ -79,11 +79,15 @@
* - flush_tlb_range(vma, start, end) flushes a range of pages
* - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
* - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ * - flush_tlb_others(cpumask, mm, va) flushes a TLBs on other cpus
*
* ..but the i386 has somewhat limited tlb flushing capabilities,
* and page-granular flushes are available only on i486 and up.
*/
+#define TLB_FLUSH_ALL 0xffffffff
+
+
#ifndef CONFIG_SMP
#define flush_tlb() __flush_tlb()
@@ -110,7 +114,12 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
__flush_tlb();
}
-#else
+static inline void native_flush_tlb_others(const cpumask_t *cpumask,
+ struct mm_struct *mm, unsigned long va)
+{
+}
+
+#else /* SMP */
#include <asm/smp.h>
@@ -129,6 +138,9 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st
flush_tlb_mm(vma->vm_mm);
}
+void native_flush_tlb_others(const cpumask_t *cpumask, struct mm_struct *mm,
+ unsigned long va);
+
#define TLBSTATE_OK 1
#define TLBSTATE_LAZY 2
@@ -139,8 +151,11 @@ struct tlb_state
char __cacheline_padding[L1_CACHE_BYTES-8];
};
DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+#endif /* SMP */
-
+#ifndef CONFIG_PARAVIRT
+#define flush_tlb_others(mask, mm, va) \
+ native_flush_tlb_others(&mask, mm, va)
#endif
#define flush_tlb_kernel_range(start, end) flush_tlb_all()
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
index 84016ff481b..3f3c1fa000b 100644
--- a/include/asm-i386/tsc.h
+++ b/include/asm-i386/tsc.h
@@ -35,25 +35,30 @@ static inline cycles_t get_cycles(void)
static __always_inline cycles_t get_cycles_sync(void)
{
unsigned long long ret;
-#ifdef X86_FEATURE_SYNC_RDTSC
unsigned eax;
/*
+ * Use RDTSCP if possible; it is guaranteed to be synchronous
+ * and doesn't cause a VMEXIT on Hypervisors
+ */
+ alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP,
+ "=A" (ret), "0" (0ULL) : "ecx", "memory");
+ if (ret)
+ return ret;
+
+ /*
* Don't do an additional sync on CPUs where we know
* RDTSC is already synchronous:
*/
alternative_io("cpuid", ASM_NOP2, X86_FEATURE_SYNC_RDTSC,
"=a" (eax), "0" (1) : "ebx","ecx","edx","memory");
-#else
- sync_core();
-#endif
rdtscll(ret);
return ret;
}
extern void tsc_init(void);
-extern void mark_tsc_unstable(void);
+extern void mark_tsc_unstable(char *reason);
extern int unsynchronized_tsc(void);
extern void init_tsc_clocksource(void);
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 70829ae3ad5..e2aa5e0d0cc 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -397,7 +397,19 @@ unsigned long __must_check __copy_from_user_ll_nocache(void *to,
unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to,
const void __user *from, unsigned long n);
-/*
+/**
+ * __copy_to_user_inatomic: - Copy a block of data into user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only.
+ *
+ * Copy data from kernel space to user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ * The caller should also make sure he pins the user space address
+ * so that the we don't result in page fault and sleep.
+ *
* Here we special-case 1, 2 and 4-byte copy_*_user invocations. On a fault
* we return the initial request size (1, 2 or 4), as copy_*_user should do.
* If a store crosses a page boundary and gets a fault, the x86 will not write
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 833fa1704ff..bd21e795197 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -325,10 +325,11 @@
#define __NR_move_pages 317
#define __NR_getcpu 318
#define __NR_epoll_pwait 319
+#define __NR_utimensat 320
#ifdef __KERNEL__
-#define NR_syscalls 320
+#define NR_syscalls 321
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-i386/vmi_time.h b/include/asm-i386/vmi_time.h
index c3a1fcf66c9..213930b995c 100644
--- a/include/asm-i386/vmi_time.h
+++ b/include/asm-i386/vmi_time.h
@@ -53,22 +53,8 @@ extern unsigned long long vmi_get_sched_cycles(void);
extern unsigned long vmi_cpu_khz(void);
#ifdef CONFIG_X86_LOCAL_APIC
-extern void __init vmi_timer_setup_boot_alarm(void);
-extern void __devinit vmi_timer_setup_secondary_alarm(void);
-extern void apic_vmi_timer_interrupt(void);
-#endif
-
-#ifdef CONFIG_NO_IDLE_HZ
-extern int vmi_stop_hz_timer(void);
-extern void vmi_account_time_restart_hz_timer(void);
-#else
-static inline int vmi_stop_hz_timer(void)
-{
- return 0;
-}
-static inline void vmi_account_time_restart_hz_timer(void)
-{
-}
+extern void __devinit vmi_time_bsp_init(void);
+extern void __devinit vmi_time_ap_init(void);
#endif
/*
diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h
index 5b27838905b..91a9932937a 100644
--- a/include/asm-i386/voyager.h
+++ b/include/asm-i386/voyager.h
@@ -487,15 +487,11 @@ extern struct voyager_qic_cpi *voyager_quad_cpi_addr[NR_CPUS];
extern struct voyager_SUS *voyager_SUS;
/* variables exported always */
+extern struct task_struct *voyager_thread;
extern int voyager_level;
-extern int kvoyagerd_running;
-extern struct semaphore kvoyagerd_sem;
extern struct voyager_status voyager_status;
-
-
/* functions exported by the voyager and voyager_smp modules */
-
extern int voyager_cat_readb(__u8 module, __u8 asic, int reg);
extern void voyager_cat_init(void);
extern void voyager_detect(struct voyager_bios_info *);
diff --git a/include/asm-ia64/asmmacro.h b/include/asm-ia64/asmmacro.h
index c22b4658fc6..c1642fd6402 100644
--- a/include/asm-ia64/asmmacro.h
+++ b/include/asm-ia64/asmmacro.h
@@ -104,6 +104,16 @@ name:
#endif
/*
+ * If physical stack register size is different from DEF_NUM_STACK_REG,
+ * dynamically patch the kernel for correct size.
+ */
+ .section ".data.patch.phys_stack_reg", "a"
+ .previous
+#define LOAD_PHYS_STACK_REG_SIZE(reg) \
+[1:] adds reg=IA64_NUM_PHYS_STACK_REG*8+8,r0; \
+ .xdata4 ".data.patch.phys_stack_reg", 1b-.
+
+/*
* Up until early 2004, use of .align within a function caused bad unwind info.
* TEXT_ALIGN(n) expands into ".align n" if a fixed GAS is available or into nothing
* otherwise.
diff --git a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
index 569ec7574ba..1fc3b83325d 100644
--- a/include/asm-ia64/atomic.h
+++ b/include/asm-ia64/atomic.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <asm/intrinsics.h>
+#include <asm/system.h>
/*
* On IA-64, counter must always be volatile to ensure that that the
@@ -88,25 +89,47 @@ ia64_atomic64_sub (__s64 i, atomic64_t *v)
return new;
}
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- for (;;) { \
- if (unlikely(c == (u))) \
- break; \
- old = atomic_cmpxchg((v), c, c + (a)); \
- if (likely(old == c)) \
- break; \
- c = old; \
- } \
- c != (u); \
-})
+#define atomic64_cmpxchg(v, old, new) \
+ (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long c, old;
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic64_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
#define atomic_add_return(i,v) \
({ \
int __ia64_aar_i = (i); \
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 6311e168cd3..eb17a869296 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -421,11 +421,7 @@ __writeq (unsigned long val, volatile void __iomem *addr)
extern void __iomem * ioremap(unsigned long offset, unsigned long size);
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
-
-static inline void
-iounmap (volatile void __iomem *addr)
-{
-}
+extern void iounmap (volatile void __iomem *addr);
/* Use normal IO mappings for DMI */
#define dmi_ioremap ioremap
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h
index aed7142f9e4..ba211e011a1 100644
--- a/include/asm-ia64/kdebug.h
+++ b/include/asm-ia64/kdebug.h
@@ -28,21 +28,8 @@
*/
#include <linux/notifier.h>
-struct pt_regs;
-
-struct die_args {
- struct pt_regs *regs;
- const char *str;
- long err;
- int trapnr;
- int signr;
-};
-
-extern int register_die_notifier(struct notifier_block *);
-extern int unregister_die_notifier(struct notifier_block *);
extern int register_page_fault_notifier(struct notifier_block *);
extern int unregister_page_fault_notifier(struct notifier_block *);
-extern struct atomic_notifier_head ia64die_chain;
enum die_val {
DIE_BREAK = 1,
@@ -74,18 +61,4 @@ enum die_val {
DIE_KDUMP_LEAVE,
};
-static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs,
- long err, int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
-
- return atomic_notifier_call_chain(&ia64die_chain, val, &args);
-}
-
#endif
diff --git a/include/asm-ia64/kexec.h b/include/asm-ia64/kexec.h
index 41299ddfee3..541be835fc5 100644
--- a/include/asm-ia64/kexec.h
+++ b/include/asm-ia64/kexec.h
@@ -14,8 +14,6 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_IA_64
-#define MAX_NOTE_BYTES 1024
-
#define kexec_flush_icache_page(page) do { \
unsigned long page_addr = (unsigned long)page_address(page); \
flush_icache_range(page_addr, page_addr + PAGE_SIZE); \
diff --git a/include/asm-ia64/kregs.h b/include/asm-ia64/kregs.h
index 221b5cb564b..7e55a584975 100644
--- a/include/asm-ia64/kregs.h
+++ b/include/asm-ia64/kregs.h
@@ -29,8 +29,7 @@
*/
#define IA64_TR_KERNEL 0 /* itr0, dtr0: maps kernel image (code & data) */
#define IA64_TR_PALCODE 1 /* itr1: maps PALcode as required by EFI */
-#define IA64_TR_PERCPU_DATA 1 /* dtr1: percpu data */
-#define IA64_TR_CURRENT_STACK 2 /* dtr2: maps kernel's memory- & register-stacks */
+#define IA64_TR_CURRENT_STACK 1 /* dtr1: maps kernel's memory- & register-stacks */
/* Processor status register bits: */
#define IA64_PSR_BE_BIT 1
diff --git a/include/asm-ia64/local.h b/include/asm-ia64/local.h
index dc519092ef4..c11c530f74d 100644
--- a/include/asm-ia64/local.h
+++ b/include/asm-ia64/local.h
@@ -1,50 +1 @@
-#ifndef _ASM_IA64_LOCAL_H
-#define _ASM_IA64_LOCAL_H
-
-/*
- * Copyright (C) 2003 Hewlett-Packard Co
- * David Mosberger-Tang <davidm@hpl.hp.com>
- */
-
-#include <linux/percpu.h>
-
-typedef struct {
- atomic64_t val;
-} local_t;
-
-#define LOCAL_INIT(i) ((local_t) { { (i) } })
-#define local_read(l) atomic64_read(&(l)->val)
-#define local_set(l, i) atomic64_set(&(l)->val, i)
-#define local_inc(l) atomic64_inc(&(l)->val)
-#define local_dec(l) atomic64_dec(&(l)->val)
-#define local_add(i, l) atomic64_add((i), &(l)->val)
-#define local_sub(i, l) atomic64_sub((i), &(l)->val)
-
-/* Non-atomic variants, i.e., preemption disabled and won't be touched in interrupt, etc. */
-
-#define __local_inc(l) (++(l)->val.counter)
-#define __local_dec(l) (--(l)->val.counter)
-#define __local_add(i,l) ((l)->val.counter += (i))
-#define __local_sub(i,l) ((l)->val.counter -= (i))
-
-/*
- * Use these for per-cpu local_t variables. Note they take a variable (eg. mystruct.foo),
- * not an address.
- */
-#define cpu_local_read(v) local_read(&__ia64_per_cpu_var(v))
-#define cpu_local_set(v, i) local_set(&__ia64_per_cpu_var(v), (i))
-#define cpu_local_inc(v) local_inc(&__ia64_per_cpu_var(v))
-#define cpu_local_dec(v) local_dec(&__ia64_per_cpu_var(v))
-#define cpu_local_add(i, v) local_add((i), &__ia64_per_cpu_var(v))
-#define cpu_local_sub(i, v) local_sub((i), &__ia64_per_cpu_var(v))
-
-/*
- * Non-atomic increments, i.e., preemption disabled and won't be touched in interrupt,
- * etc.
- */
-#define __cpu_local_inc(v) __local_inc(&__ia64_per_cpu_var(v))
-#define __cpu_local_dec(v) __local_dec(&__ia64_per_cpu_var(v))
-#define __cpu_local_add(i, v) __local_add((i), &__ia64_per_cpu_var(v))
-#define __cpu_local_sub(i, v) __local_sub((i), &__ia64_per_cpu_var(v))
-
-#endif /* _ASM_IA64_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
index b5c65081a3a..cef2400983f 100644
--- a/include/asm-ia64/mmu_context.h
+++ b/include/asm-ia64/mmu_context.h
@@ -29,6 +29,7 @@
#include <linux/spinlock.h>
#include <asm/processor.h>
+#include <asm-generic/mm_hooks.h>
struct ia64_ctx {
spinlock_t lock;
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 67656ce767c..abfcb3a2588 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -89,6 +89,8 @@
#define PAL_GET_PSTATE_TYPE_AVGNORESET 2
#define PAL_GET_PSTATE_TYPE_INSTANT 3
+#define PAL_MC_ERROR_INJECT 276 /* Injects processor error or returns injection capabilities */
+
#ifndef __ASSEMBLY__
#include <linux/types.h>
@@ -1235,6 +1237,37 @@ ia64_pal_mc_error_info (u64 info_index, u64 type_index, u64 *size, u64 *error_in
return iprv.status;
}
+/* Injects the requested processor error or returns info on
+ * supported injection capabilities for current processor implementation
+ */
+static inline s64
+ia64_pal_mc_error_inject_phys (u64 err_type_info, u64 err_struct_info,
+ u64 err_data_buffer, u64 *capabilities, u64 *resources)
+{
+ struct ia64_pal_retval iprv;
+ PAL_CALL_PHYS_STK(iprv, PAL_MC_ERROR_INJECT, err_type_info,
+ err_struct_info, err_data_buffer);
+ if (capabilities)
+ *capabilities= iprv.v0;
+ if (resources)
+ *resources= iprv.v1;
+ return iprv.status;
+}
+
+static inline s64
+ia64_pal_mc_error_inject_virt (u64 err_type_info, u64 err_struct_info,
+ u64 err_data_buffer, u64 *capabilities, u64 *resources)
+{
+ struct ia64_pal_retval iprv;
+ PAL_CALL_STK(iprv, PAL_MC_ERROR_INJECT, err_type_info,
+ err_struct_info, err_data_buffer);
+ if (capabilities)
+ *capabilities= iprv.v0;
+ if (resources)
+ *resources= iprv.v1;
+ return iprv.status;
+}
+
/* Inform PALE_CHECK whether a machine check is expected so that PALE_CHECK willnot
* attempt to correct any expected machine checks.
*/
diff --git a/include/asm-ia64/patch.h b/include/asm-ia64/patch.h
index 4797f3535e6..a71543084fb 100644
--- a/include/asm-ia64/patch.h
+++ b/include/asm-ia64/patch.h
@@ -20,6 +20,7 @@ extern void ia64_patch_imm60 (u64 insn_addr, u64 val); /* patch "brl" w/ip-rel
extern void ia64_patch_mckinley_e9 (unsigned long start, unsigned long end);
extern void ia64_patch_vtop (unsigned long start, unsigned long end);
+extern void ia64_patch_phys_stack_reg(unsigned long val);
extern void ia64_patch_gate (void);
#endif /* _ASM_IA64_PATCH_H */
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 55318274772..670b706411b 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -485,10 +485,6 @@ extern void paging_init (void);
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 4f4ee1c2db2..db81ba406ce 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -19,6 +19,7 @@
#include <asm/ptrace.h>
#include <asm/ustack.h>
+#define IA64_NUM_PHYS_STACK_REG 96
#define IA64_NUM_DBG_REGS 8
#define DEFAULT_MAP_BASE __IA64_UL_CONST(0x2000000000000000)
diff --git a/include/asm-ia64/scatterlist.h b/include/asm-ia64/scatterlist.h
index 9dbea8844d5..a452ea24205 100644
--- a/include/asm-ia64/scatterlist.h
+++ b/include/asm-ia64/scatterlist.h
@@ -6,6 +6,8 @@
* David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
*/
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-ia64/sections.h b/include/asm-ia64/sections.h
index e9eb7f62d32..dc42a359894 100644
--- a/include/asm-ia64/sections.h
+++ b/include/asm-ia64/sections.h
@@ -11,6 +11,7 @@
extern char __per_cpu_start[], __per_cpu_end[], __phys_per_cpu_start[];
extern char __start___vtop_patchlist[], __end___vtop_patchlist[];
extern char __start___mckinley_e9_bundles[], __end___mckinley_e9_bundles[];
+extern char __start___phys_stack_reg_patchlist[], __end___phys_stack_reg_patchlist[];
extern char __start_gate_section[];
extern char __start_gate_mckinley_e9_patchlist[], __end_gate_mckinley_e9_patchlist[];
extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[];
diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
index 60fd4ae014f..c60024989eb 100644
--- a/include/asm-ia64/smp.h
+++ b/include/asm-ia64/smp.h
@@ -38,6 +38,8 @@ ia64_get_lid (void)
return lid.f.id << 8 | lid.f.eid;
}
+#define hard_smp_processor_id() ia64_get_lid()
+
#ifdef CONFIG_SMP
#define XTP_OFFSET 0x1e0008
@@ -110,8 +112,6 @@ max_xtp (void)
writeb(0x0f, ipi_base_addr + XTP_OFFSET); /* Set XTP to max */
}
-#define hard_smp_processor_id() ia64_get_lid()
-
/* Upping and downing of CPUs */
extern int __cpu_disable (void);
extern void __cpu_die (unsigned int cpu);
@@ -128,7 +128,7 @@ extern void unlock_ipi_calllock(void);
extern void identify_siblings (struct cpuinfo_ia64 *);
extern int is_multithreading_enabled(void);
-#else
+#else /* CONFIG_SMP */
#define cpu_logical_id(i) 0
#define cpu_physical_id(i) ia64_get_lid()
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 91698599f91..d2814750658 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -110,6 +110,6 @@ struct thread_info {
#define TS_POLLING 1 /* true if in idle loop and not sleeping */
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
#endif /* _ASM_IA64_THREAD_INFO_H */
diff --git a/include/asm-m32r/atomic.h b/include/asm-m32r/atomic.h
index f5a7d7301c7..3a38ffe4a4f 100644
--- a/include/asm-m32r/atomic.h
+++ b/include/asm-m32r/atomic.h
@@ -253,14 +253,21 @@ static __inline__ int atomic_dec_return(atomic_t *v)
* Atomically adds @a to @v, so long as it was not @u.
* Returns non-zero if @v was not @u, and zero otherwise.
*/
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr)
diff --git a/include/asm-m32r/kdebug.h b/include/asm-m32r/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-m32r/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-m32r/mmu_context.h b/include/asm-m32r/mmu_context.h
index 1f40d4a0acf..91909e5dd9d 100644
--- a/include/asm-m32r/mmu_context.h
+++ b/include/asm-m32r/mmu_context.h
@@ -15,6 +15,7 @@
#include <asm/pgalloc.h>
#include <asm/mmu.h>
#include <asm/tlbflush.h>
+#include <asm-generic/mm_hooks.h>
/*
* Cache of MMU context last used.
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 1c15ba7ce31..8b2a2f17e69 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -381,10 +381,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
diff --git a/include/asm-m32r/scatterlist.h b/include/asm-m32r/scatterlist.h
index c2de96cb69e..352415ff5eb 100644
--- a/include/asm-m32r/scatterlist.h
+++ b/include/asm-m32r/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef _ASM_M32R_SCATTERLIST_H
#define _ASM_M32R_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
char * address; /* Location data is to be transferred to, NULL for
* highmem page */
diff --git a/include/asm-m32r/smp.h b/include/asm-m32r/smp.h
index abd937ac523..078e1a51a04 100644
--- a/include/asm-m32r/smp.h
+++ b/include/asm-m32r/smp.h
@@ -108,6 +108,10 @@ extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
#define IPI_SHIFT (0)
#define NR_IPIS (8)
-#endif /* CONFIG_SMP */
+#else /* CONFIG_SMP */
+
+#define hard_smp_processor_id() 0
+
+#endif /* CONFIG_SMP */
#endif /* _ASM_M32R_SMP_H */
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 99ee09889ff..f62f5c9abba 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -122,8 +122,6 @@ static inline void local_irq_disable(void)
#define xchg(ptr,x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
-
#ifdef CONFIG_SMP
extern void __xchg_called_with_bad_pointer(void);
#endif
@@ -138,7 +136,7 @@ extern void __xchg_called_with_bad_pointer(void);
"add3 "reg0", "addr", #0x2000; \n\t" \
"ld "reg0", @"reg0"; \n\t" \
"unlock "reg0", @"reg1"; \n\t"
- /* FIXME: This workaround code cannot handle kenrel modules
+ /* FIXME: This workaround code cannot handle kernel modules
* correctly under SMP environment.
*/
#else /* CONFIG_CHIP_M32700_TS1 */
diff --git a/include/asm-m68k/adb.h b/include/asm-m68k/adb.h
deleted file mode 100644
index 9176b55185b..00000000000
--- a/include/asm-m68k/adb.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Definitions for talking to ADB and CUDA. The CUDA is a microcontroller
- * which controls the ADB, system power, RTC, and various other things on
- * later Macintoshes
- *
- * Copyright (C) 1996 Paul Mackerras.
- */
-
-/* First byte sent to or received from CUDA */
-#define ADB_PACKET 0
-#define CUDA_PACKET 1
-#define ERROR_PACKET 2
-#define TIMER_PACKET 3
-#define POWER_PACKET 4
-#define MACIIC_PACKET 5
-
-/* ADB commands (2nd byte) */
-#define ADB_BUSRESET 0
-#define ADB_FLUSH(id) (1 + ((id) << 4))
-#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4))
-#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4))
-
-/* ADB default device IDs (upper 4 bits of 2nd byte) */
-#define ADB_DONGLE 1 /* "software execution control" devices */
-#define ADB_KEYBOARD 2
-#define ADB_MOUSE 3
-#define ADB_TABLET 4
-#define ADB_MODEM 5
-#define ADB_MISC 7 /* maybe a monitor */
-
-/* CUDA commands (2nd byte) */
-#define CUDA_WARM_START 0
-#define CUDA_AUTOPOLL 1
-#define CUDA_GET_6805_ADDR 2
-#define CUDA_GET_TIME 3
-#define CUDA_GET_PRAM 7
-#define CUDA_SET_6805_ADDR 8
-#define CUDA_SET_TIME 9
-#define CUDA_POWERDOWN 0xa
-#define CUDA_POWERUP_TIME 0xb
-#define CUDA_SET_PRAM 0xc
-#define CUDA_MS_RESET 0xd
-#define CUDA_SEND_DFAC 0xe
-#define CUDA_RESET_SYSTEM 0x11
-#define CUDA_SET_IPL 0x12
-#define CUDA_SET_AUTO_RATE 0x14
-#define CUDA_GET_AUTO_RATE 0x16
-#define CUDA_SET_DEVICE_LIST 0x19
-#define CUDA_GET_DEVICE_LIST 0x1a
-#define CUDA_GET_SET_IIC 0x22
-
-#ifdef __KERNEL__
-
-struct adb_request {
- unsigned char data[16];
- int nbytes;
- unsigned char reply[16];
- int reply_len;
- unsigned char reply_expected;
- unsigned char sent;
- unsigned char got_reply;
- void (*done)(struct adb_request *);
- void *arg;
- struct adb_request *next;
-};
-
-void via_adb_init(void);
-int adb_request(struct adb_request *req,
- void (*done)(struct adb_request *), int nbytes, ...);
-int adb_send_request(struct adb_request *req);
-void adb_poll(void);
-int adb_register(int default_id,
- void (*handler)(unsigned char *, int, struct pt_regs *));
-
-#endif /* __KERNEL */
diff --git a/include/asm-m68k/atarihw.h b/include/asm-m68k/atarihw.h
index f28acd0fd68..6211363a345 100644
--- a/include/asm-m68k/atarihw.h
+++ b/include/asm-m68k/atarihw.h
@@ -2,7 +2,7 @@
** linux/atarihw.h -- This header defines some macros and pointers for
** the various Atari custom hardware registers.
**
-** Copyright 1994 by Bj”rn Brauel
+** Copyright 1994 by Bj”rn Brauel
**
** 5/1/94 Roman Hodek:
** Added definitions for TT specific chips.
diff --git a/include/asm-m68k/atariints.h b/include/asm-m68k/atariints.h
index 0ed454fc24b..ce6c445805b 100644
--- a/include/asm-m68k/atariints.h
+++ b/include/asm-m68k/atariints.h
@@ -1,7 +1,7 @@
/*
** atariints.h -- Atari Linux interrupt handling structs and prototypes
**
-** Copyright 1994 by Bj”rn Brauel
+** Copyright 1994 by Bj”rn Brauel
**
** 5/2/94 Roman Hodek:
** TT interrupt definitions added.
diff --git a/include/asm-m68k/atarikb.h b/include/asm-m68k/atarikb.h
index 18926058fde..546e7da5804 100644
--- a/include/asm-m68k/atarikb.h
+++ b/include/asm-m68k/atarikb.h
@@ -36,5 +36,11 @@ void ikbd_joystick_disable(void);
extern void (*atari_MIDI_interrupt_hook) (void);
/* Hook for mouse driver */
extern void (*atari_mouse_interrupt_hook) (char *);
+/* Hook for keyboard inputdev driver */
+extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
+/* Hook for mouse inputdev driver */
+extern void (*atari_input_mouse_interrupt_hook) (char *);
+
+int atari_keyb_init(void);
#endif /* _LINUX_ATARIKB_H */
diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h
index d5eed64cb83..4915294fea6 100644
--- a/include/asm-m68k/atomic.h
+++ b/include/asm-m68k/atomic.h
@@ -2,7 +2,7 @@
#define __ARCH_M68K_ATOMIC__
-#include <asm/system.h> /* local_irq_XXX() */
+#include <asm/system.h>
/*
* Atomic operations that C can't guarantee us. Useful for
@@ -170,20 +170,21 @@ static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
__asm__ __volatile__("orl %1,%0" : "+m" (*v) : "id" (mask));
}
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- for (;;) { \
- if (unlikely(c == (u))) \
- break; \
- old = atomic_cmpxchg((v), c, c + (a)); \
- if (likely(old == c)) \
- break; \
- c = old; \
- } \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
/* Atomic operations are already serializing */
diff --git a/include/asm-m68k/kdebug.h b/include/asm-m68k/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-m68k/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-m68k/mmu_context.h b/include/asm-m68k/mmu_context.h
index 231d11bd8e3..894dacbcee1 100644
--- a/include/asm-m68k/mmu_context.h
+++ b/include/asm-m68k/mmu_context.h
@@ -1,6 +1,7 @@
#ifndef __M68K_MMU_CONTEXT_H
#define __M68K_MMU_CONTEXT_H
+#include <asm-generic/mm_hooks.h>
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h
index f3aa0537798..555b87a1f7e 100644
--- a/include/asm-m68k/pgtable.h
+++ b/include/asm-m68k/pgtable.h
@@ -143,10 +143,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/* MMU-specific headers */
#ifdef CONFIG_SUN3
diff --git a/include/asm-m68k/scatterlist.h b/include/asm-m68k/scatterlist.h
index 8e612266da5..24887a2d9c7 100644
--- a/include/asm-m68k/scatterlist.h
+++ b/include/asm-m68k/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef _M68K_SCATTERLIST_H
#define _M68K_SCATTERLIST_H
+#include <linux/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index 243dd13e6bf..198878b53a6 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -88,7 +88,6 @@ static inline int irqs_disabled(void)
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
diff --git a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h
index c4d622a57df..d635a375248 100644
--- a/include/asm-m68k/thread_info.h
+++ b/include/asm-m68k/thread_info.h
@@ -37,17 +37,17 @@ struct thread_info {
#define init_stack (init_thread_union.stack)
#define task_thread_info(tsk) (&(tsk)->thread.info)
-#define task_stack_page(tsk) ((void *)(tsk)->thread_info)
+#define task_stack_page(tsk) ((tsk)->stack)
#define current_thread_info() task_thread_info(current)
#define __HAVE_THREAD_FUNCTIONS
#define setup_thread_stack(p, org) ({ \
- *(struct task_struct **)(p)->thread_info = (p); \
+ *(struct task_struct **)(p)->stack = (p); \
task_thread_info(p)->task = (p); \
})
-#define end_of_stack(p) ((unsigned long *)(p)->thread_info + 1)
+#define end_of_stack(p) ((unsigned long *)(p)->stack + 1)
/* entry.S relies on these definitions!
* bits 0-7 are tested at every exception exit
diff --git a/include/asm-m68knommu/atomic.h b/include/asm-m68knommu/atomic.h
index 6c4e4b63e45..d5632a305da 100644
--- a/include/asm-m68knommu/atomic.h
+++ b/include/asm-m68knommu/atomic.h
@@ -1,7 +1,7 @@
#ifndef __ARCH_M68KNOMMU_ATOMIC__
#define __ARCH_M68KNOMMU_ATOMIC__
-#include <asm/system.h> /* local_irq_XXX() */
+#include <asm/system.h>
/*
* Atomic operations that C can't guarantee us. Useful for
@@ -131,14 +131,21 @@ static inline int atomic_sub_return(int i, atomic_t * v)
#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
#define atomic_dec_return(v) atomic_sub_return(1,(v))
diff --git a/include/asm-m68knommu/kdebug.h b/include/asm-m68knommu/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-m68knommu/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-m68knommu/mmu_context.h b/include/asm-m68knommu/mmu_context.h
index 6c077d3a257..9ccee4278c9 100644
--- a/include/asm-m68knommu/mmu_context.h
+++ b/include/asm-m68knommu/mmu_context.h
@@ -4,6 +4,7 @@
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h
index 549ad231efa..9dfbbc24aa7 100644
--- a/include/asm-m68knommu/pgtable.h
+++ b/include/asm-m68knommu/pgtable.h
@@ -59,10 +59,6 @@ extern int is_in_rom(unsigned long);
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
diff --git a/include/asm-m68knommu/scatterlist.h b/include/asm-m68knommu/scatterlist.h
index 2085d6ff878..4da79d3d3f3 100644
--- a/include/asm-m68knommu/scatterlist.h
+++ b/include/asm-m68knommu/scatterlist.h
@@ -2,6 +2,7 @@
#define _M68KNOMMU_SCATTERLIST_H
#include <linux/mm.h>
+#include <asm/types.h>
struct scatterlist {
struct page *page;
diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h
index 2a814498672..5e5ed18bb78 100644
--- a/include/asm-m68knommu/system.h
+++ b/include/asm-m68knommu/system.h
@@ -120,7 +120,6 @@ asmlinkage void resume(void);
#endif
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 1ac50b6c47a..62daa746a9c 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -18,6 +18,7 @@
#include <asm/barrier.h>
#include <asm/cpu-features.h>
#include <asm/war.h>
+#include <asm/system.h>
typedef struct { volatile int counter; } atomic_t;
@@ -306,8 +307,8 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
return result;
}
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
/**
* atomic_add_unless - add unless the number is a given value
@@ -318,14 +319,20 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
* Atomically adds @a to @v, so long as it was not @u.
* Returns non-zero if @v was not @u, and zero otherwise.
*/
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
#define atomic_dec_return(v) atomic_sub_return(1,(v))
@@ -681,6 +688,36 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
return result;
}
+#define atomic64_cmpxchg(v, o, n) \
+ (((__typeof__((v)->counter)))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long c, old;
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic64_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
#define atomic64_dec_return(v) atomic64_sub_return(1,(v))
#define atomic64_inc_return(v) atomic64_add_return(1,(v))
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index c7c945baf1e..dbf834f4dac 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -254,7 +254,7 @@ extern void free_init_pages(const char *what,
extern char arcs_cmdline[CL_SIZE];
/*
- * Registers a0, a1, a3 and a4 as passed to the kenrel entry by firmware
+ * Registers a0, a1, a3 and a4 as passed to the kernel entry by firmware
*/
extern unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
diff --git a/include/asm-mips/kdebug.h b/include/asm-mips/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-mips/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-mips/kexec.h b/include/asm-mips/kexec.h
index b25267ebcb0..cdbab43b7d3 100644
--- a/include/asm-mips/kexec.h
+++ b/include/asm-mips/kexec.h
@@ -21,8 +21,6 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_MIPS
-#define MAX_NOTE_BYTES 1024
-
static inline void crash_setup_regs(struct pt_regs *newregs,
struct pt_regs *oldregs)
{
diff --git a/include/asm-mips/local.h b/include/asm-mips/local.h
index 9e2d43bae38..ed882c88e0c 100644
--- a/include/asm-mips/local.h
+++ b/include/asm-mips/local.h
@@ -1,60 +1,288 @@
-#ifndef _ASM_LOCAL_H
-#define _ASM_LOCAL_H
+#ifndef _ARCH_MIPS_LOCAL_H
+#define _ARCH_MIPS_LOCAL_H
#include <linux/percpu.h>
+#include <linux/bitops.h>
#include <asm/atomic.h>
+#include <asm/war.h>
-#ifdef CONFIG_32BIT
+typedef struct
+{
+ atomic_long_t a;
+} local_t;
-typedef atomic_t local_t;
+#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
-#define LOCAL_INIT(i) ATOMIC_INIT(i)
-#define local_read(v) atomic_read(v)
-#define local_set(v,i) atomic_set(v,i)
+#define local_read(l) atomic_long_read(&(l)->a)
+#define local_set(l,i) atomic_long_set(&(l)->a, (i))
-#define local_inc(v) atomic_inc(v)
-#define local_dec(v) atomic_dec(v)
-#define local_add(i, v) atomic_add(i, v)
-#define local_sub(i, v) atomic_sub(i, v)
+#define local_add(i,l) atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l) atomic_long_sub((i),(&(l)->a))
+#define local_inc(l) atomic_long_inc(&(l)->a)
+#define local_dec(l) atomic_long_dec(&(l)->a)
-#endif
+/*
+ * Same as above, but return the result value
+ */
+static __inline__ long local_add_return(long i, local_t * l)
+{
+ unsigned long result;
+
+ if (cpu_has_llsc && R10000_LLSC_WAR) {
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ " .set mips3 \n"
+ "1:" __LL "%1, %2 # local_add_return \n"
+ " addu %0, %1, %3 \n"
+ __SC "%0, %2 \n"
+ " beqzl %0, 1b \n"
+ " addu %0, %1, %3 \n"
+ " .set mips0 \n"
+ : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+ : "Ir" (i), "m" (l->a.counter)
+ : "memory");
+ } else if (cpu_has_llsc) {
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ " .set mips3 \n"
+ "1:" __LL "%1, %2 # local_add_return \n"
+ " addu %0, %1, %3 \n"
+ __SC "%0, %2 \n"
+ " beqz %0, 1b \n"
+ " addu %0, %1, %3 \n"
+ " .set mips0 \n"
+ : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+ : "Ir" (i), "m" (l->a.counter)
+ : "memory");
+ } else {
+ unsigned long flags;
-#ifdef CONFIG_64BIT
+ local_irq_save(flags);
+ result = l->a.counter;
+ result += i;
+ l->a.counter = result;
+ local_irq_restore(flags);
+ }
-typedef atomic64_t local_t;
+ return result;
+}
-#define LOCAL_INIT(i) ATOMIC64_INIT(i)
-#define local_read(v) atomic64_read(v)
-#define local_set(v,i) atomic64_set(v,i)
+static __inline__ long local_sub_return(long i, local_t * l)
+{
+ unsigned long result;
-#define local_inc(v) atomic64_inc(v)
-#define local_dec(v) atomic64_dec(v)
-#define local_add(i, v) atomic64_add(i, v)
-#define local_sub(i, v) atomic64_sub(i, v)
+ if (cpu_has_llsc && R10000_LLSC_WAR) {
+ unsigned long temp;
-#endif
+ __asm__ __volatile__(
+ " .set mips3 \n"
+ "1:" __LL "%1, %2 # local_sub_return \n"
+ " subu %0, %1, %3 \n"
+ __SC "%0, %2 \n"
+ " beqzl %0, 1b \n"
+ " subu %0, %1, %3 \n"
+ " .set mips0 \n"
+ : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+ : "Ir" (i), "m" (l->a.counter)
+ : "memory");
+ } else if (cpu_has_llsc) {
+ unsigned long temp;
-#define __local_inc(v) ((v)->counter++)
-#define __local_dec(v) ((v)->counter--)
-#define __local_add(i,v) ((v)->counter+=(i))
-#define __local_sub(i,v) ((v)->counter-=(i))
+ __asm__ __volatile__(
+ " .set mips3 \n"
+ "1:" __LL "%1, %2 # local_sub_return \n"
+ " subu %0, %1, %3 \n"
+ __SC "%0, %2 \n"
+ " beqz %0, 1b \n"
+ " subu %0, %1, %3 \n"
+ " .set mips0 \n"
+ : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+ : "Ir" (i), "m" (l->a.counter)
+ : "memory");
+ } else {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ result = l->a.counter;
+ result -= i;
+ l->a.counter = result;
+ local_irq_restore(flags);
+ }
+
+ return result;
+}
/*
- * Use these for per-cpu local_t variables: on some archs they are
+ * local_sub_if_positive - conditionally subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically test @l and subtract @i if @l is greater or equal than @i.
+ * The function returns the old value of @l minus @i.
+ */
+static __inline__ long local_sub_if_positive(long i, local_t * l)
+{
+ unsigned long result;
+
+ if (cpu_has_llsc && R10000_LLSC_WAR) {
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ " .set mips3 \n"
+ "1:" __LL "%1, %2 # local_sub_if_positive\n"
+ " dsubu %0, %1, %3 \n"
+ " bltz %0, 1f \n"
+ __SC "%0, %2 \n"
+ " .set noreorder \n"
+ " beqzl %0, 1b \n"
+ " dsubu %0, %1, %3 \n"
+ " .set reorder \n"
+ "1: \n"
+ " .set mips0 \n"
+ : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+ : "Ir" (i), "m" (l->a.counter)
+ : "memory");
+ } else if (cpu_has_llsc) {
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ " .set mips3 \n"
+ "1:" __LL "%1, %2 # local_sub_if_positive\n"
+ " dsubu %0, %1, %3 \n"
+ " bltz %0, 1f \n"
+ __SC "%0, %2 \n"
+ " .set noreorder \n"
+ " beqz %0, 1b \n"
+ " dsubu %0, %1, %3 \n"
+ " .set reorder \n"
+ "1: \n"
+ " .set mips0 \n"
+ : "=&r" (result), "=&r" (temp), "=m" (l->a.counter)
+ : "Ir" (i), "m" (l->a.counter)
+ : "memory");
+ } else {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ result = l->a.counter;
+ result -= i;
+ if (result >= 0)
+ l->a.counter = result;
+ local_irq_restore(flags);
+ }
+
+ return result;
+}
+
+#define local_cmpxchg(l, o, n) \
+ ((long)cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter),(n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u) \
+({ \
+ long c, old; \
+ c = local_read(l); \
+ while (c != (u) && (old = local_cmpxchg((l), c, c + (a))) != c) \
+ c = old; \
+ c != (u); \
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_dec_return(l) local_sub_return(1,(l))
+#define local_inc_return(l) local_add_return(1,(l))
+
+/*
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer of type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
+
+/*
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+/*
+ * local_dec_and_test - decrement by 1 and test
+ * @l: pointer of type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
+
+/*
+ * local_dec_if_positive - decrement by 1 if old value positive
+ * @l: pointer of type local_t
+ */
+#define local_dec_if_positive(l) local_sub_if_positive(1, l)
+
+/*
+ * local_add_negative - add and test if negative
+ * @l: pointer of type local_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+#define local_add_negative(i,l) (local_add_return(i, (l)) < 0)
+
+/* Use these for per-cpu local_t variables: on some archs they are
* much more efficient than these naive implementations. Note they take
* a variable, not an address.
*/
-#define cpu_local_read(v) local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
-#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
+#define __local_inc(l) ((l)->a.counter++)
+#define __local_dec(l) ((l)->a.counter++)
+#define __local_add(i,l) ((l)->a.counter+=(i))
+#define __local_sub(i,l) ((l)->a.counter-=(i))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+ still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(l) \
+ ({ local_t res__; \
+ preempt_disable(); \
+ res__ = (l); \
+ preempt_enable(); \
+ res__; })
+#define cpu_local_wrap(l) \
+ ({ preempt_disable(); \
+ l; \
+ preempt_enable(); }) \
+
+#define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
-#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
+#define __cpu_local_inc(l) cpu_local_inc(l)
+#define __cpu_local_dec(l) cpu_local_dec(l)
+#define __cpu_local_add(i, l) cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l) cpu_local_sub((i), (l))
-#endif /* _ASM_LOCAL_H */
+#endif /* _ARCH_MIPS_LOCAL_H */
diff --git a/include/asm-mips/mach-au1x00/au1550_spi.h b/include/asm-mips/mach-au1x00/au1550_spi.h
new file mode 100644
index 00000000000..c2f0466523e
--- /dev/null
+++ b/include/asm-mips/mach-au1x00/au1550_spi.h
@@ -0,0 +1,16 @@
+/*
+ * au1550_spi.h - au1550 psc spi controller driver - platform data struct
+ */
+
+#ifndef _AU1550_SPI_H_
+#define _AU1550_SPI_H_
+
+struct au1550_spi_info {
+ s16 bus_num; /* defines which PSC and IRQ to use */
+ u32 mainclk_hz; /* main input clock frequency of PSC */
+ u16 num_chipselect; /* number of chipselects supported */
+ void (*activate_cs)(struct au1550_spi_info *spi, int cs, int polarity);
+ void (*deactivate_cs)(struct au1550_spi_info *spi, int cs, int polarity);
+};
+
+#endif
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index fe065d6070c..65024ffd787 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -20,6 +20,7 @@
#include <asm/mipsmtregs.h>
#include <asm/smtc.h>
#endif /* SMTC */
+#include <asm-generic/mm_hooks.h>
/*
* For the fast tlb miss handlers, we keep a per cpu array of pointers
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 0d3295f57a9..27d77d98193 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -387,10 +387,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
remap_pfn_range(vma, vaddr, pfn, size, prot)
#endif
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#include <asm-generic/pgtable.h>
/*
diff --git a/include/asm-mips/scatterlist.h b/include/asm-mips/scatterlist.h
index 22634706e9d..7af104c95b2 100644
--- a/include/asm-mips/scatterlist.h
+++ b/include/asm-mips/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef __ASM_SCATTERLIST_H
#define __ASM_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page * page;
unsigned int offset;
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 290887077e4..3713d256d36 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -55,7 +55,7 @@ do { \
if (cpu_has_dsp) \
__save_dsp(prev); \
next->thread.emulated_fp = 0; \
- (last) = resume(prev, next, next->thread_info); \
+ (last) = resume(prev, next, task_thread_info(next)); \
if (cpu_has_dsp) \
__restore_dsp(current); \
} while(0)
@@ -201,7 +201,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
}
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
#define __HAVE_ARCH_CMPXCHG 1
@@ -262,6 +261,58 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
return retval;
}
+static inline unsigned long __cmpxchg_u32_local(volatile int * m,
+ unsigned long old, unsigned long new)
+{
+ __u32 retval;
+
+ if (cpu_has_llsc && R10000_LLSC_WAR) {
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noat \n"
+ " .set mips3 \n"
+ "1: ll %0, %2 # __cmpxchg_u32 \n"
+ " bne %0, %z3, 2f \n"
+ " .set mips0 \n"
+ " move $1, %z4 \n"
+ " .set mips3 \n"
+ " sc $1, %1 \n"
+ " beqzl $1, 1b \n"
+ "2: \n"
+ " .set pop \n"
+ : "=&r" (retval), "=R" (*m)
+ : "R" (*m), "Jr" (old), "Jr" (new)
+ : "memory");
+ } else if (cpu_has_llsc) {
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noat \n"
+ " .set mips3 \n"
+ "1: ll %0, %2 # __cmpxchg_u32 \n"
+ " bne %0, %z3, 2f \n"
+ " .set mips0 \n"
+ " move $1, %z4 \n"
+ " .set mips3 \n"
+ " sc $1, %1 \n"
+ " beqz $1, 1b \n"
+ "2: \n"
+ " .set pop \n"
+ : "=&r" (retval), "=R" (*m)
+ : "R" (*m), "Jr" (old), "Jr" (new)
+ : "memory");
+ } else {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ retval = *m;
+ if (retval == old)
+ *m = new;
+ local_irq_restore(flags); /* implies memory barrier */
+ }
+
+ return retval;
+}
+
#ifdef CONFIG_64BIT
static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
unsigned long new)
@@ -315,10 +366,62 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
return retval;
}
+
+static inline unsigned long __cmpxchg_u64_local(volatile int * m,
+ unsigned long old, unsigned long new)
+{
+ __u64 retval;
+
+ if (cpu_has_llsc && R10000_LLSC_WAR) {
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noat \n"
+ " .set mips3 \n"
+ "1: lld %0, %2 # __cmpxchg_u64 \n"
+ " bne %0, %z3, 2f \n"
+ " move $1, %z4 \n"
+ " scd $1, %1 \n"
+ " beqzl $1, 1b \n"
+ "2: \n"
+ " .set pop \n"
+ : "=&r" (retval), "=R" (*m)
+ : "R" (*m), "Jr" (old), "Jr" (new)
+ : "memory");
+ } else if (cpu_has_llsc) {
+ __asm__ __volatile__(
+ " .set push \n"
+ " .set noat \n"
+ " .set mips3 \n"
+ "1: lld %0, %2 # __cmpxchg_u64 \n"
+ " bne %0, %z3, 2f \n"
+ " move $1, %z4 \n"
+ " scd $1, %1 \n"
+ " beqz $1, 1b \n"
+ "2: \n"
+ " .set pop \n"
+ : "=&r" (retval), "=R" (*m)
+ : "R" (*m), "Jr" (old), "Jr" (new)
+ : "memory");
+ } else {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ retval = *m;
+ if (retval == old)
+ *m = new;
+ local_irq_restore(flags); /* implies memory barrier */
+ }
+
+ return retval;
+}
+
#else
extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels(
volatile int * m, unsigned long old, unsigned long new);
#define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels
+extern unsigned long __cmpxchg_u64_local_unsupported_on_32bit_kernels(
+ volatile int * m, unsigned long old, unsigned long new);
+#define __cmpxchg_u64_local __cmpxchg_u64_local_unsupported_on_32bit_kernels
#endif
/* This function doesn't exist, so you'll get a linker error
@@ -338,7 +441,26 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
return old;
}
-#define cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+static inline unsigned long __cmpxchg_local(volatile void * ptr,
+ unsigned long old, unsigned long new, int size)
+{
+ switch (size) {
+ case 4:
+ return __cmpxchg_u32_local(ptr, old, new);
+ case 8:
+ return __cmpxchg_u64_local(ptr, old, new);
+ }
+ __cmpxchg_called_with_bad_pointer();
+ return old;
+}
+
+#define cmpxchg(ptr,old,new) \
+ ((__typeof__(*(ptr)))__cmpxchg((ptr), \
+ (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
+
+#define cmpxchg_local(ptr,old,new) \
+ ((__typeof__(*(ptr)))__cmpxchg_local((ptr), \
+ (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr))))
extern void set_handler (unsigned long offset, void *addr, unsigned long len);
extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len);
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 7d57d34fcca..e894ee35074 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -163,7 +163,7 @@ static __inline__ int atomic_read(const atomic_t *v)
}
/* exported interface */
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
/**
@@ -175,14 +175,21 @@ static __inline__ int atomic_read(const atomic_t *v)
* Atomically adds @a to @v, so long as it was not @u.
* Returns non-zero if @v was not @u, and zero otherwise.
*/
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
#define atomic_add(i,v) ((void)(__atomic_add_return( ((int)i),(v))))
@@ -270,6 +277,37 @@ atomic64_read(const atomic64_t *v)
#define atomic64_dec_and_test(v) (atomic64_dec_return(v) == 0)
#define atomic64_sub_and_test(i,v) (atomic64_sub_return((i),(v)) == 0)
+/* exported interface */
+#define atomic64_cmpxchg(v, o, n) \
+ ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long c, old;
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic64_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
#endif /* CONFIG_64BIT */
#include <asm-generic/atomic.h>
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index fe857902353..11f4222597a 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -152,7 +152,7 @@ static __inline__ void __user *compat_alloc_user_space(long len)
static inline int __is_compat_task(struct task_struct *t)
{
- return test_ti_thread_flag(t->thread_info, TIF_32BIT);
+ return test_ti_thread_flag(task_thread_info(t), TIF_32BIT);
}
static inline int is_compat_task(void)
diff --git a/include/asm-parisc/kdebug.h b/include/asm-parisc/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-parisc/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-parisc/local.h b/include/asm-parisc/local.h
index d0f55091275..c11c530f74d 100644
--- a/include/asm-parisc/local.h
+++ b/include/asm-parisc/local.h
@@ -1,40 +1 @@
-#ifndef _ARCH_PARISC_LOCAL_H
-#define _ARCH_PARISC_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-typedef atomic_long_t local_t;
-
-#define LOCAL_INIT(i) ATOMIC_LONG_INIT(i)
-#define local_read(v) atomic_long_read(v)
-#define local_set(v,i) atomic_long_set(v,i)
-
-#define local_inc(v) atomic_long_inc(v)
-#define local_dec(v) atomic_long_dec(v)
-#define local_add(i, v) atomic_long_add(i, v)
-#define local_sub(i, v) atomic_long_sub(i, v)
-
-#define __local_inc(v) ((v)->counter++)
-#define __local_dec(v) ((v)->counter--)
-#define __local_add(i,v) ((v)->counter+=(i))
-#define __local_sub(i,v) ((v)->counter-=(i))
-
-/* Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations. Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v) local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ARCH_PARISC_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-parisc/mmu_context.h b/include/asm-parisc/mmu_context.h
index 9c05836239a..bad690298f0 100644
--- a/include/asm-parisc/mmu_context.h
+++ b/include/asm-parisc/mmu_context.h
@@ -5,6 +5,7 @@
#include <asm/atomic.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
+#include <asm-generic/mm_hooks.h>
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index d7e1b10da5c..beb2adb979d 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -528,10 +528,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/* We provide our own get_unmapped_area to provide cache coherency */
#define HAVE_ARCH_UNMAPPED_AREA
diff --git a/include/asm-parisc/scatterlist.h b/include/asm-parisc/scatterlist.h
index 236c1d0fba3..e7211c74844 100644
--- a/include/asm-parisc/scatterlist.h
+++ b/include/asm-parisc/scatterlist.h
@@ -2,6 +2,7 @@
#define _ASM_PARISC_SCATTERLIST_H
#include <asm/page.h>
+#include <asm/types.h>
struct scatterlist {
struct page *page;
diff --git a/include/asm-powerpc/asm-compat.h b/include/asm-powerpc/asm-compat.h
index c89bd58ee28..c19e7367fce 100644
--- a/include/asm-powerpc/asm-compat.h
+++ b/include/asm-powerpc/asm-compat.h
@@ -78,6 +78,15 @@
#define PPC_STLCX stringify_in_c(stdcx.)
#define PPC_CNTLZL stringify_in_c(cntlzd)
+/* Move to CR, single-entry optimized version. Only available
+ * on POWER4 and later.
+ */
+#ifdef CONFIG_POWER4_ONLY
+#define PPC_MTOCRF stringify_in_c(mtocrf)
+#else
+#define PPC_MTOCRF stringify_in_c(mtcrf)
+#endif
+
#else /* 32-bit */
/* operations for longs and pointers */
@@ -89,6 +98,7 @@
#define PPC_LLARX stringify_in_c(lwarx)
#define PPC_STLCX stringify_in_c(stwcx.)
#define PPC_CNTLZL stringify_in_c(cntlzw)
+#define PPC_MTOCRF stringify_in_c(mtcrf)
#endif
diff --git a/include/asm-powerpc/atomic.h b/include/asm-powerpc/atomic.h
index 2ce4b6b7b34..c44810b9d32 100644
--- a/include/asm-powerpc/atomic.h
+++ b/include/asm-powerpc/atomic.h
@@ -11,6 +11,7 @@ typedef struct { volatile int counter; } atomic_t;
#include <linux/compiler.h>
#include <asm/synch.h>
#include <asm/asm-compat.h>
+#include <asm/system.h>
#define ATOMIC_INIT(i) { (i) }
@@ -165,8 +166,7 @@ static __inline__ int atomic_dec_return(atomic_t *v)
return t;
}
-#define atomic_cmpxchg(v, o, n) \
- ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
/**
@@ -414,8 +414,7 @@ static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
return t;
}
-#define atomic64_cmpxchg(v, o, n) \
- ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
/**
diff --git a/include/asm-powerpc/bitops.h b/include/asm-powerpc/bitops.h
index 8f757f6246e..8144a2788db 100644
--- a/include/asm-powerpc/bitops.h
+++ b/include/asm-powerpc/bitops.h
@@ -39,7 +39,6 @@
#ifdef __KERNEL__
#include <linux/compiler.h>
-#include <asm/atomic.h>
#include <asm/asm-compat.h>
#include <asm/synch.h>
diff --git a/include/asm-powerpc/cacheflush.h b/include/asm-powerpc/cacheflush.h
index 08e93e78921..ba667a383b8 100644
--- a/include/asm-powerpc/cacheflush.h
+++ b/include/asm-powerpc/cacheflush.h
@@ -64,6 +64,12 @@ extern void flush_dcache_phys_range(unsigned long start, unsigned long stop);
memcpy(dst, src, len)
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+/* internal debugging function */
+void kernel_map_pages(struct page *page, int numpages, int enable);
+#endif
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_CACHEFLUSH_H */
diff --git a/include/asm-powerpc/cell-pmu.h b/include/asm-powerpc/cell-pmu.h
index 35b95773746..8066eede3a0 100644
--- a/include/asm-powerpc/cell-pmu.h
+++ b/include/asm-powerpc/cell-pmu.h
@@ -97,11 +97,6 @@ extern void cbe_disable_pm_interrupts(u32 cpu);
extern u32 cbe_get_and_clear_pm_interrupts(u32 cpu);
extern void cbe_sync_irq(int node);
-/* Utility functions, macros */
-extern u32 cbe_get_hw_thread_id(int cpu);
-
-#define cbe_cpu_to_node(cpu) ((cpu) >> 1)
-
#define CBE_COUNT_SUPERVISOR_MODE 0
#define CBE_COUNT_HYPERVISOR_MODE 1
#define CBE_COUNT_PROBLEM_MODE 2
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index e870b539317..434524931ef 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -48,6 +48,7 @@ enum powerpc_oprofile_type {
PPC_OPROFILE_G4 = 3,
PPC_OPROFILE_BOOKE = 4,
PPC_OPROFILE_CELL = 5,
+ PPC_OPROFILE_PA6T = 6,
};
enum powerpc_pmc_type {
@@ -223,6 +224,10 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_PPC_LE)
+#define CPU_FTRS_750CL (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+ CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_750FX1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
@@ -235,9 +240,9 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750GX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
- CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU | \
- CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
+#define CPU_FTRS_750GX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+ CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
+ CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
#define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
diff --git a/include/asm-powerpc/current.h b/include/asm-powerpc/current.h
index b8708aedf92..e2c7f06931e 100644
--- a/include/asm-powerpc/current.h
+++ b/include/asm-powerpc/current.h
@@ -12,6 +12,7 @@
struct task_struct;
#ifdef __powerpc64__
+#include <linux/stddef.h>
#include <asm/paca.h>
static inline struct task_struct *get_current(void)
diff --git a/include/asm-powerpc/edac.h b/include/asm-powerpc/edac.h
new file mode 100644
index 00000000000..6ead88bbfbb
--- /dev/null
+++ b/include/asm-powerpc/edac.h
@@ -0,0 +1,40 @@
+/*
+ * PPC EDAC common defs
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. 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.
+ */
+#ifndef ASM_EDAC_H
+#define ASM_EDAC_H
+/*
+ * ECC atomic, DMA, SMP and interrupt safe scrub function.
+ * Implements the per arch atomic_scrub() that EDAC use for software
+ * ECC scrubbing. It reads memory and then writes back the original
+ * value, allowing the hardware to detect and correct memory errors.
+ */
+static __inline__ void atomic_scrub(void *va, u32 size)
+{
+ unsigned int *virt_addr = va;
+ unsigned int temp;
+ unsigned int i;
+
+ for (i = 0; i < size / sizeof(*virt_addr); i++, virt_addr++) {
+ /* Very carefully read and write to memory atomically
+ * so we are interrupt, DMA and SMP safe.
+ */
+ __asm__ __volatile__ ("\n\
+ 1: lwarx %0,0,%1\n\
+ stwcx. %0,0,%1\n\
+ bne- 1b\n\
+ isync"
+ : "=&r"(temp)
+ : "r"(virt_addr)
+ : "cr0", "memory");
+ }
+}
+
+#endif
diff --git a/include/asm-powerpc/eeh_event.h b/include/asm-powerpc/eeh_event.h
index dc6bf0ffb79..cc3cb04539a 100644
--- a/include/asm-powerpc/eeh_event.h
+++ b/include/asm-powerpc/eeh_event.h
@@ -30,8 +30,6 @@ struct eeh_event {
struct list_head list;
struct device_node *dn; /* struct device node */
struct pci_dev *dev; /* affected device */
- enum pci_channel_state state; /* PCI bus state for the affected device */
- int time_unavail; /* milliseconds until device might be available */
};
/**
@@ -46,9 +44,7 @@ struct eeh_event {
* (from a workqueue).
*/
int eeh_send_failure_event (struct device_node *dn,
- struct pci_dev *dev,
- enum pci_channel_state state,
- int time_unavail);
+ struct pci_dev *dev);
/* Main recovery function */
struct pci_dn * handle_eeh_events (struct eeh_event *);
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
index 66112114b8c..87d396e28db 100644
--- a/include/asm-powerpc/ibmebus.h
+++ b/include/asm-powerpc/ibmebus.h
@@ -2,36 +2,37 @@
* IBM PowerPC eBus Infrastructure Support.
*
* Copyright (c) 2005 IBM Corporation
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Heiko J Schick <schickhj@de.ibm.com>
- *
+ *
* All rights reserved.
*
- * This source code is distributed under a dual license of GPL v2.0 and OpenIB
- * BSD.
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
*
* OpenIB BSD License
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
*
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
*
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
* and/or other materials
- * provided with the distribution.
+ * provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
@@ -46,12 +47,11 @@
extern struct bus_type ibmebus_bus_type;
-struct ibmebus_dev {
- const char *name;
+struct ibmebus_dev {
struct of_device ofdev;
};
-struct ibmebus_driver {
+struct ibmebus_driver {
char *name;
struct of_device_id *id_table;
int (*probe) (struct ibmebus_dev *dev, const struct of_device_id *id);
@@ -63,7 +63,7 @@ int ibmebus_register_driver(struct ibmebus_driver *drv);
void ibmebus_unregister_driver(struct ibmebus_driver *drv);
int ibmebus_request_irq(struct ibmebus_dev *dev,
- u32 ist,
+ u32 ist,
irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id);
diff --git a/include/asm-powerpc/immap_86xx.h b/include/asm-powerpc/immap_86xx.h
index d905b662226..59b9e07b8e9 100644
--- a/include/asm-powerpc/immap_86xx.h
+++ b/include/asm-powerpc/immap_86xx.h
@@ -85,81 +85,6 @@ typedef struct ccsr_pci {
char res19[472];
} ccsr_pci_t;
-/* PCI Express Registers */
-typedef struct ccsr_pex {
- uint pex_config_addr; /* 0x.000 - PCI Express Configuration Address Register */
- uint pex_config_data; /* 0x.004 - PCI Express Configuration Data Register */
- char res1[4];
- uint pex_otb_cpl_tor; /* 0x.00c - PCI Express Outbound completion timeout register */
- uint pex_conf_tor; /* 0x.010 - PCI Express configuration timeout register */
- char res2[12];
- uint pex_pme_mes_dr; /* 0x.020 - PCI Express PME and message detect register */
- uint pex_pme_mes_disr; /* 0x.024 - PCI Express PME and message disable register */
- uint pex_pme_mes_ier; /* 0x.028 - PCI Express PME and message interrupt enable register */
- uint pex_pmcr; /* 0x.02c - PCI Express power management command register */
- char res3[3024];
- uint pexotar0; /* 0x.c00 - PCI Express outbound translation address register 0 */
- uint pexotear0; /* 0x.c04 - PCI Express outbound translation extended address register 0*/
- char res4[8];
- uint pexowar0; /* 0x.c10 - PCI Express outbound window attributes register 0*/
- char res5[12];
- uint pexotar1; /* 0x.c20 - PCI Express outbound translation address register 1 */
- uint pexotear1; /* 0x.c24 - PCI Express outbound translation extended address register 1*/
- uint pexowbar1; /* 0x.c28 - PCI Express outbound window base address register 1*/
- char res6[4];
- uint pexowar1; /* 0x.c30 - PCI Express outbound window attributes register 1*/
- char res7[12];
- uint pexotar2; /* 0x.c40 - PCI Express outbound translation address register 2 */
- uint pexotear2; /* 0x.c44 - PCI Express outbound translation extended address register 2*/
- uint pexowbar2; /* 0x.c48 - PCI Express outbound window base address register 2*/
- char res8[4];
- uint pexowar2; /* 0x.c50 - PCI Express outbound window attributes register 2*/
- char res9[12];
- uint pexotar3; /* 0x.c60 - PCI Express outbound translation address register 3 */
- uint pexotear3; /* 0x.c64 - PCI Express outbound translation extended address register 3*/
- uint pexowbar3; /* 0x.c68 - PCI Express outbound window base address register 3*/
- char res10[4];
- uint pexowar3; /* 0x.c70 - PCI Express outbound window attributes register 3*/
- char res11[12];
- uint pexotar4; /* 0x.c80 - PCI Express outbound translation address register 4 */
- uint pexotear4; /* 0x.c84 - PCI Express outbound translation extended address register 4*/
- uint pexowbar4; /* 0x.c88 - PCI Express outbound window base address register 4*/
- char res12[4];
- uint pexowar4; /* 0x.c90 - PCI Express outbound window attributes register 4*/
- char res13[12];
- char res14[256];
- uint pexitar3; /* 0x.da0 - PCI Express inbound translation address register 3 */
- char res15[4];
- uint pexiwbar3; /* 0x.da8 - PCI Express inbound window base address register 3 */
- uint pexiwbear3; /* 0x.dac - PCI Express inbound window base extended address register 3 */
- uint pexiwar3; /* 0x.db0 - PCI Express inbound window attributes register 3 */
- char res16[12];
- uint pexitar2; /* 0x.dc0 - PCI Express inbound translation address register 2 */
- char res17[4];
- uint pexiwbar2; /* 0x.dc8 - PCI Express inbound window base address register 2 */
- uint pexiwbear2; /* 0x.dcc - PCI Express inbound window base extended address register 2 */
- uint pexiwar2; /* 0x.dd0 - PCI Express inbound window attributes register 2 */
- char res18[12];
- uint pexitar1; /* 0x.de0 - PCI Express inbound translation address register 2 */
- char res19[4];
- uint pexiwbar1; /* 0x.de8 - PCI Express inbound window base address register 2 */
- uint pexiwbear1; /* 0x.dec - PCI Express inbound window base extended address register 2 */
- uint pexiwar1; /* 0x.df0 - PCI Express inbound window attributes register 2 */
- char res20[12];
- uint pex_err_dr; /* 0x.e00 - PCI Express error detect register */
- char res21[4];
- uint pex_err_en; /* 0x.e08 - PCI Express error interrupt enable register */
- char res22[4];
- uint pex_err_disr; /* 0x.e10 - PCI Express error disable register */
- char res23[12];
- uint pex_err_cap_stat; /* 0x.e20 - PCI Express error capture status register */
- char res24[4];
- uint pex_err_cap_r0; /* 0x.e28 - PCI Express error capture register 0 */
- uint pex_err_cap_r1; /* 0x.e2c - PCI Express error capture register 0 */
- uint pex_err_cap_r2; /* 0x.e30 - PCI Express error capture register 0 */
- uint pex_err_cap_r3; /* 0x.e34 - PCI Express error capture register 0 */
-} ccsr_pex_t;
-
/* Global Utility Registers */
typedef struct ccsr_guts {
uint porpllsr; /* 0x.0000 - POR PLL Ratio Status Register */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 301c9bb308b..350c9bdb31d 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -11,7 +11,12 @@
/* Check of existence of legacy devices */
extern int check_legacy_ioport(unsigned long base_port);
-#define PNPBIOS_BASE 0xf000 /* only relevant for PReP */
+#define I8042_DATA_REG 0x60
+#define FDC_BASE 0x3f0
+/* only relevant for PReP */
+#define _PIDXR 0x279
+#define _PNPWRP 0xa79
+#define PNPBIOS_BASE 0xf000
#include <linux/compiler.h>
#include <asm/page.h>
diff --git a/include/asm-powerpc/iommu.h b/include/asm-powerpc/iommu.h
index b2e56b30306..870967e4720 100644
--- a/include/asm-powerpc/iommu.h
+++ b/include/asm-powerpc/iommu.h
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <asm/machdep.h>
#include <asm/types.h>
#include <asm/bitops.h>
@@ -109,6 +110,19 @@ static inline void pci_iommu_init(void) { }
#endif
extern void alloc_dart_table(void);
+#if defined(CONFIG_PPC64) && defined(CONFIG_PM)
+static inline void iommu_save(void)
+{
+ if (ppc_md.iommu_save)
+ ppc_md.iommu_save();
+}
+
+static inline void iommu_restore(void)
+{
+ if (ppc_md.iommu_restore)
+ ppc_md.iommu_restore();
+}
+#endif
#endif /* __KERNEL__ */
#endif /* _ASM_IOMMU_H */
diff --git a/include/asm-powerpc/kdebug.h b/include/asm-powerpc/kdebug.h
index 532bfee934f..295f0162c60 100644
--- a/include/asm-powerpc/kdebug.h
+++ b/include/asm-powerpc/kdebug.h
@@ -6,20 +6,19 @@
#include <linux/notifier.h>
-struct pt_regs;
-
-struct die_args {
- struct pt_regs *regs;
- const char *str;
- long err;
- int trapnr;
- int signr;
-};
-
-extern int register_die_notifier(struct notifier_block *);
-extern int unregister_die_notifier(struct notifier_block *);
-extern int register_page_fault_notifier(struct notifier_block *);
-extern int unregister_page_fault_notifier(struct notifier_block *);
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation. Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
extern struct atomic_notifier_head powerpc_die_chain;
/* Grossly misnamed. */
@@ -29,14 +28,7 @@ enum die_val {
DIE_DABR_MATCH,
DIE_BPT,
DIE_SSTEP,
- DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val,char *str,struct pt_regs *regs,long err,int trap, int sig)
-{
- struct die_args args = { .regs=regs, .str=str, .err=err, .trapnr=trap,.signr=sig };
- return atomic_notifier_call_chain(&powerpc_die_chain, val, &args);
-}
-
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_KDEBUG_H */
diff --git a/include/asm-powerpc/kexec.h b/include/asm-powerpc/kexec.h
index 11cbdf81fd2..b6f817b8ba3 100644
--- a/include/asm-powerpc/kexec.h
+++ b/include/asm-powerpc/kexec.h
@@ -108,8 +108,6 @@ static inline void crash_setup_regs(struct pt_regs *newregs,
struct pt_regs *oldregs) { }
#endif /* !__powerpc64 __ */
-#define MAX_NOTE_BYTES 1024
-
extern void kexec_smp_wait(void); /* get and clear naca physid, wait for
master to copy new code to 0 */
extern int crashing_cpu;
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 3a5dd492588..b0e40ff32ee 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -64,6 +64,12 @@ typedef unsigned int kprobe_opcode_t;
addr = *(kprobe_opcode_t **)addr; \
} else if (name[0] != '.') \
addr = *(kprobe_opcode_t **)addr; \
+ } else { \
+ char dot_name[KSYM_NAME_LEN+1]; \
+ dot_name[0] = '.'; \
+ dot_name[1] = '\0'; \
+ strncat(dot_name, name, KSYM_NAME_LEN); \
+ addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \
} \
}
@@ -87,6 +93,11 @@ extern void arch_remove_kprobe(struct kprobe *p);
struct arch_specific_insn {
/* copy of original instruction */
kprobe_opcode_t *insn;
+ /*
+ * Set in kprobes code, initially to 0. If the instruction can be
+ * eumulated, this is set to 1, if not, to -1.
+ */
+ int boostable;
};
struct prev_kprobe {
@@ -105,5 +116,6 @@ struct kprobe_ctlblk {
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_KPROBES_H */
diff --git a/include/asm-powerpc/local.h b/include/asm-powerpc/local.h
index c11c530f74d..612d8327665 100644
--- a/include/asm-powerpc/local.h
+++ b/include/asm-powerpc/local.h
@@ -1 +1,200 @@
-#include <asm-generic/local.h>
+#ifndef _ARCH_POWERPC_LOCAL_H
+#define _ARCH_POWERPC_LOCAL_H
+
+#include <linux/percpu.h>
+#include <asm/atomic.h>
+
+typedef struct
+{
+ atomic_long_t a;
+} local_t;
+
+#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
+
+#define local_read(l) atomic_long_read(&(l)->a)
+#define local_set(l,i) atomic_long_set(&(l)->a, (i))
+
+#define local_add(i,l) atomic_long_add((i),(&(l)->a))
+#define local_sub(i,l) atomic_long_sub((i),(&(l)->a))
+#define local_inc(l) atomic_long_inc(&(l)->a)
+#define local_dec(l) atomic_long_dec(&(l)->a)
+
+static __inline__ long local_add_return(long a, local_t *l)
+{
+ long t;
+
+ __asm__ __volatile__(
+"1:" PPC_LLARX "%0,0,%2 # local_add_return\n\
+ add %0,%1,%0\n"
+ PPC405_ERR77(0,%2)
+ PPC_STLCX "%0,0,%2 \n\
+ bne- 1b"
+ : "=&r" (t)
+ : "r" (a), "r" (&(l->a.counter))
+ : "cc", "memory");
+
+ return t;
+}
+
+#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
+
+static __inline__ long local_sub_return(long a, local_t *l)
+{
+ long t;
+
+ __asm__ __volatile__(
+"1:" PPC_LLARX "%0,0,%2 # local_sub_return\n\
+ subf %0,%1,%0\n"
+ PPC405_ERR77(0,%2)
+ PPC_STLCX "%0,0,%2 \n\
+ bne- 1b"
+ : "=&r" (t)
+ : "r" (a), "r" (&(l->a.counter))
+ : "cc", "memory");
+
+ return t;
+}
+
+static __inline__ long local_inc_return(local_t *l)
+{
+ long t;
+
+ __asm__ __volatile__(
+"1:" PPC_LLARX "%0,0,%1 # local_inc_return\n\
+ addic %0,%0,1\n"
+ PPC405_ERR77(0,%1)
+ PPC_STLCX "%0,0,%1 \n\
+ bne- 1b"
+ : "=&r" (t)
+ : "r" (&(l->a.counter))
+ : "cc", "memory");
+
+ return t;
+}
+
+/*
+ * local_inc_and_test - increment and test
+ * @l: pointer of type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define local_inc_and_test(l) (local_inc_return(l) == 0)
+
+static __inline__ long local_dec_return(local_t *l)
+{
+ long t;
+
+ __asm__ __volatile__(
+"1:" PPC_LLARX "%0,0,%1 # local_dec_return\n\
+ addic %0,%0,-1\n"
+ PPC405_ERR77(0,%1)
+ PPC_STLCX "%0,0,%1\n\
+ bne- 1b"
+ : "=&r" (t)
+ : "r" (&(l->a.counter))
+ : "cc", "memory");
+
+ return t;
+}
+
+#define local_cmpxchg(l, o, n) \
+ (cmpxchg_local(&((l)->a.counter), (o), (n)))
+#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
+
+/**
+ * local_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+static __inline__ int local_add_unless(local_t *l, long a, long u)
+{
+ long t;
+
+ __asm__ __volatile__ (
+"1:" PPC_LLARX "%0,0,%1 # local_add_unless\n\
+ cmpw 0,%0,%3 \n\
+ beq- 2f \n\
+ add %0,%2,%0 \n"
+ PPC405_ERR77(0,%2)
+ PPC_STLCX "%0,0,%1 \n\
+ bne- 1b \n"
+" subf %0,%2,%0 \n\
+2:"
+ : "=&r" (t)
+ : "r" (&(l->a.counter)), "r" (a), "r" (u)
+ : "cc", "memory");
+
+ return t != u;
+}
+
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
+#define local_sub_and_test(a, l) (local_sub_return((a), (l)) == 0)
+#define local_dec_and_test(l) (local_dec_return((l)) == 0)
+
+/*
+ * Atomically test *l and decrement if it is greater than 0.
+ * The function returns the old value of *l minus 1.
+ */
+static __inline__ long local_dec_if_positive(local_t *l)
+{
+ long t;
+
+ __asm__ __volatile__(
+"1:" PPC_LLARX "%0,0,%1 # local_dec_if_positive\n\
+ cmpwi %0,1\n\
+ addi %0,%0,-1\n\
+ blt- 2f\n"
+ PPC405_ERR77(0,%1)
+ PPC_STLCX "%0,0,%1\n\
+ bne- 1b"
+ "\n\
+2:" : "=&b" (t)
+ : "r" (&(l->a.counter))
+ : "cc", "memory");
+
+ return t;
+}
+
+/* Use these for per-cpu local_t variables: on some archs they are
+ * much more efficient than these naive implementations. Note they take
+ * a variable, not an address.
+ */
+
+#define __local_inc(l) ((l)->a.counter++)
+#define __local_dec(l) ((l)->a.counter++)
+#define __local_add(i,l) ((l)->a.counter+=(i))
+#define __local_sub(i,l) ((l)->a.counter-=(i))
+
+/* Need to disable preemption for the cpu local counters otherwise we could
+ still access a variable of a previous CPU in a non atomic way. */
+#define cpu_local_wrap_v(l) \
+ ({ local_t res__; \
+ preempt_disable(); \
+ res__ = (l); \
+ preempt_enable(); \
+ res__; })
+#define cpu_local_wrap(l) \
+ ({ preempt_disable(); \
+ l; \
+ preempt_enable(); }) \
+
+#define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
+
+#define __cpu_local_inc(l) cpu_local_inc(l)
+#define __cpu_local_dec(l) cpu_local_dec(l)
+#define __cpu_local_add(i, l) cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l) cpu_local_sub((i), (l))
+
+#endif /* _ARCH_POWERPC_LOCAL_H */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 1b04e572354..6cf1a831f55 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -91,6 +91,11 @@ struct machdep_calls {
void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
unsigned long flags);
void (*iounmap)(volatile void __iomem *token);
+
+#ifdef CONFIG_PM
+ void (*iommu_save)(void);
+ void (*iommu_restore)(void);
+#endif
#endif /* CONFIG_PPC64 */
int (*probe)(void);
@@ -115,6 +120,14 @@ struct machdep_calls {
/* To setup PHBs when using automatic OF platform driver for PCI */
int (*pci_setup_phb)(struct pci_controller *host);
+#ifdef CONFIG_PCI_MSI
+ int (*msi_check_device)(struct pci_dev* dev,
+ int nvec, int type);
+ int (*setup_msi_irqs)(struct pci_dev *dev,
+ int nvec, int type);
+ void (*teardown_msi_irqs)(struct pci_dev *dev);
+#endif
+
void (*restart)(char *cmd);
void (*power_off)(void);
void (*halt)(void);
@@ -153,9 +166,6 @@ struct machdep_calls {
*/
long (*feature_call)(unsigned int feature, ...);
- /* Check availability of legacy devices like i8042 */
- int (*check_legacy_ioport)(unsigned int baseport);
-
/* Get legacy PCI/IDE interrupt mapping */
int (*pci_get_legacy_ide_irq)(struct pci_dev *dev, int channel);
@@ -243,14 +253,10 @@ struct machdep_calls {
*/
void (*machine_kexec)(struct kimage *image);
#endif /* CONFIG_KEXEC */
-
-#ifdef CONFIG_PCI_MSI
- int (*enable_msi)(struct pci_dev *pdev);
- void (*disable_msi)(struct pci_dev *pdev);
-#endif /* CONFIG_PCI_MSI */
};
extern void power4_idle(void);
+extern void power4_cpu_offline_powersave(void);
extern void ppc6xx_idle(void);
/*
diff --git a/include/asm-powerpc/mmu-44x.h b/include/asm-powerpc/mmu-44x.h
new file mode 100644
index 00000000000..d5ce7a8dfe9
--- /dev/null
+++ b/include/asm-powerpc/mmu-44x.h
@@ -0,0 +1,78 @@
+#ifndef _ASM_POWERPC_MMU_44X_H_
+#define _ASM_POWERPC_MMU_44X_H_
+/*
+ * PPC440 support
+ */
+
+#define PPC44x_MMUCR_TID 0x000000ff
+#define PPC44x_MMUCR_STS 0x00010000
+
+#define PPC44x_TLB_PAGEID 0
+#define PPC44x_TLB_XLAT 1
+#define PPC44x_TLB_ATTRIB 2
+
+/* Page identification fields */
+#define PPC44x_TLB_EPN_MASK 0xfffffc00 /* Effective Page Number */
+#define PPC44x_TLB_VALID 0x00000200 /* Valid flag */
+#define PPC44x_TLB_TS 0x00000100 /* Translation address space */
+#define PPC44x_TLB_1K 0x00000000 /* Page sizes */
+#define PPC44x_TLB_4K 0x00000010
+#define PPC44x_TLB_16K 0x00000020
+#define PPC44x_TLB_64K 0x00000030
+#define PPC44x_TLB_256K 0x00000040
+#define PPC44x_TLB_1M 0x00000050
+#define PPC44x_TLB_16M 0x00000070
+#define PPC44x_TLB_256M 0x00000090
+
+/* Translation fields */
+#define PPC44x_TLB_RPN_MASK 0xfffffc00 /* Real Page Number */
+#define PPC44x_TLB_ERPN_MASK 0x0000000f
+
+/* Storage attribute and access control fields */
+#define PPC44x_TLB_ATTR_MASK 0x0000ff80
+#define PPC44x_TLB_U0 0x00008000 /* User 0 */
+#define PPC44x_TLB_U1 0x00004000 /* User 1 */
+#define PPC44x_TLB_U2 0x00002000 /* User 2 */
+#define PPC44x_TLB_U3 0x00001000 /* User 3 */
+#define PPC44x_TLB_W 0x00000800 /* Caching is write-through */
+#define PPC44x_TLB_I 0x00000400 /* Caching is inhibited */
+#define PPC44x_TLB_M 0x00000200 /* Memory is coherent */
+#define PPC44x_TLB_G 0x00000100 /* Memory is guarded */
+#define PPC44x_TLB_E 0x00000080 /* Memory is guarded */
+
+#define PPC44x_TLB_PERM_MASK 0x0000003f
+#define PPC44x_TLB_UX 0x00000020 /* User execution */
+#define PPC44x_TLB_UW 0x00000010 /* User write */
+#define PPC44x_TLB_UR 0x00000008 /* User read */
+#define PPC44x_TLB_SX 0x00000004 /* Super execution */
+#define PPC44x_TLB_SW 0x00000002 /* Super write */
+#define PPC44x_TLB_SR 0x00000001 /* Super read */
+
+/* Number of TLB entries */
+#define PPC44x_TLB_SIZE 64
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long long phys_addr_t;
+
+extern phys_addr_t fixup_bigphys_addr(phys_addr_t, phys_addr_t);
+
+typedef struct {
+ unsigned long id;
+ unsigned long vdso_base;
+} mm_context_t;
+
+#endif /* !__ASSEMBLY__ */
+
+#ifndef CONFIG_PPC_EARLY_DEBUG_44x
+#define PPC44x_EARLY_TLBS 1
+#else
+#define PPC44x_EARLY_TLBS 2
+#define PPC44x_EARLY_DEBUG_VIRTADDR (ASM_CONST(0xf0000000) \
+ | (ASM_CONST(CONFIG_PPC_EARLY_DEBUG_44x_PHYSLOW) & 0xffff))
+#endif
+
+/* Size of the TLBs used for pinning in lowmem */
+#define PPC_PIN_SIZE (1 << 28) /* 256M */
+
+#endif /* _ASM_POWERPC_MMU_44X_H_ */
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
new file mode 100644
index 00000000000..e2ca55bcfe0
--- /dev/null
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -0,0 +1,403 @@
+#ifndef _ASM_POWERPC_MMU_HASH64_H_
+#define _ASM_POWERPC_MMU_HASH64_H_
+/*
+ * PowerPC64 memory management structures
+ *
+ * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
+ * PPC64 rework.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/asm-compat.h>
+#include <asm/page.h>
+
+/*
+ * Segment table
+ */
+
+#define STE_ESID_V 0x80
+#define STE_ESID_KS 0x20
+#define STE_ESID_KP 0x10
+#define STE_ESID_N 0x08
+
+#define STE_VSID_SHIFT 12
+
+/* Location of cpu0's segment table */
+#define STAB0_PAGE 0x6
+#define STAB0_OFFSET (STAB0_PAGE << 12)
+#define STAB0_PHYS_ADDR (STAB0_OFFSET + PHYSICAL_START)
+
+#ifndef __ASSEMBLY__
+extern char initial_stab[];
+#endif /* ! __ASSEMBLY */
+
+/*
+ * SLB
+ */
+
+#define SLB_NUM_BOLTED 3
+#define SLB_CACHE_ENTRIES 8
+
+/* Bits in the SLB ESID word */
+#define SLB_ESID_V ASM_CONST(0x0000000008000000) /* valid */
+
+/* Bits in the SLB VSID word */
+#define SLB_VSID_SHIFT 12
+#define SLB_VSID_B ASM_CONST(0xc000000000000000)
+#define SLB_VSID_B_256M ASM_CONST(0x0000000000000000)
+#define SLB_VSID_B_1T ASM_CONST(0x4000000000000000)
+#define SLB_VSID_KS ASM_CONST(0x0000000000000800)
+#define SLB_VSID_KP ASM_CONST(0x0000000000000400)
+#define SLB_VSID_N ASM_CONST(0x0000000000000200) /* no-execute */
+#define SLB_VSID_L ASM_CONST(0x0000000000000100)
+#define SLB_VSID_C ASM_CONST(0x0000000000000080) /* class */
+#define SLB_VSID_LP ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LP_00 ASM_CONST(0x0000000000000000)
+#define SLB_VSID_LP_01 ASM_CONST(0x0000000000000010)
+#define SLB_VSID_LP_10 ASM_CONST(0x0000000000000020)
+#define SLB_VSID_LP_11 ASM_CONST(0x0000000000000030)
+#define SLB_VSID_LLP (SLB_VSID_L|SLB_VSID_LP)
+
+#define SLB_VSID_KERNEL (SLB_VSID_KP)
+#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
+
+#define SLBIE_C (0x08000000)
+
+/*
+ * Hash table
+ */
+
+#define HPTES_PER_GROUP 8
+
+#define HPTE_V_AVPN_SHIFT 7
+#define HPTE_V_AVPN ASM_CONST(0xffffffffffffff80)
+#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
+#define HPTE_V_COMPARE(x,y) (!(((x) ^ (y)) & HPTE_V_AVPN))
+#define HPTE_V_BOLTED ASM_CONST(0x0000000000000010)
+#define HPTE_V_LOCK ASM_CONST(0x0000000000000008)
+#define HPTE_V_LARGE ASM_CONST(0x0000000000000004)
+#define HPTE_V_SECONDARY ASM_CONST(0x0000000000000002)
+#define HPTE_V_VALID ASM_CONST(0x0000000000000001)
+
+#define HPTE_R_PP0 ASM_CONST(0x8000000000000000)
+#define HPTE_R_TS ASM_CONST(0x4000000000000000)
+#define HPTE_R_RPN_SHIFT 12
+#define HPTE_R_RPN ASM_CONST(0x3ffffffffffff000)
+#define HPTE_R_FLAGS ASM_CONST(0x00000000000003ff)
+#define HPTE_R_PP ASM_CONST(0x0000000000000003)
+#define HPTE_R_N ASM_CONST(0x0000000000000004)
+#define HPTE_R_C ASM_CONST(0x0000000000000080)
+#define HPTE_R_R ASM_CONST(0x0000000000000100)
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+/* pp0 will always be 0 for linux */
+#define PP_RWXX 0 /* Supervisor read/write, User none */
+#define PP_RWRX 1 /* Supervisor read/write, User read */
+#define PP_RWRW 2 /* Supervisor read/write, User read/write */
+#define PP_RXRX 3 /* Supervisor read, User read */
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+ unsigned long v;
+ unsigned long r;
+} hpte_t;
+
+extern hpte_t *htab_address;
+extern unsigned long htab_size_bytes;
+extern unsigned long htab_hash_mask;
+
+/*
+ * Page size definition
+ *
+ * shift : is the "PAGE_SHIFT" value for that page size
+ * sllp : is a bit mask with the value of SLB L || LP to be or'ed
+ * directly to a slbmte "vsid" value
+ * penc : is the HPTE encoding mask for the "LP" field:
+ *
+ */
+struct mmu_psize_def
+{
+ unsigned int shift; /* number of bits */
+ unsigned int penc; /* HPTE encoding */
+ unsigned int tlbiel; /* tlbiel supported for that page size */
+ unsigned long avpnm; /* bits to mask out in AVPN in the HPTE */
+ unsigned long sllp; /* SLB L||LP (exact mask to use in slbmte) */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The kernel use the constants below to index in the page sizes array.
+ * The use of fixed constants for this purpose is better for performances
+ * of the low level hash refill handlers.
+ *
+ * A non supported page size has a "shift" field set to 0
+ *
+ * Any new page size being implemented can get a new entry in here. Whether
+ * the kernel will use it or not is a different matter though. The actual page
+ * size used by hugetlbfs is not defined here and may be made variable
+ */
+
+#define MMU_PAGE_4K 0 /* 4K */
+#define MMU_PAGE_64K 1 /* 64K */
+#define MMU_PAGE_64K_AP 2 /* 64K Admixed (in a 4K segment) */
+#define MMU_PAGE_1M 3 /* 1M */
+#define MMU_PAGE_16M 4 /* 16M */
+#define MMU_PAGE_16G 5 /* 16G */
+#define MMU_PAGE_COUNT 6
+
+#ifndef __ASSEMBLY__
+
+/*
+ * The current system page sizes
+ */
+extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
+extern int mmu_linear_psize;
+extern int mmu_virtual_psize;
+extern int mmu_vmalloc_psize;
+extern int mmu_io_psize;
+
+/*
+ * If the processor supports 64k normal pages but not 64k cache
+ * inhibited pages, we have to be prepared to switch processes
+ * to use 4k pages when they create cache-inhibited mappings.
+ * If this is the case, mmu_ci_restrictions will be set to 1.
+ */
+extern int mmu_ci_restrictions;
+
+#ifdef CONFIG_HUGETLB_PAGE
+/*
+ * The page size index of the huge pages for use by hugetlbfs
+ */
+extern int mmu_huge_psize;
+
+#endif /* CONFIG_HUGETLB_PAGE */
+
+/*
+ * This function sets the AVPN and L fields of the HPTE appropriately
+ * for the page size
+ */
+static inline unsigned long hpte_encode_v(unsigned long va, int psize)
+{
+ unsigned long v =
+ v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
+ v <<= HPTE_V_AVPN_SHIFT;
+ if (psize != MMU_PAGE_4K)
+ v |= HPTE_V_LARGE;
+ return v;
+}
+
+/*
+ * This function sets the ARPN, and LP fields of the HPTE appropriately
+ * for the page size. We assume the pa is already "clean" that is properly
+ * aligned for the requested page size
+ */
+static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
+{
+ unsigned long r;
+
+ /* A 4K page needs no special encoding */
+ if (psize == MMU_PAGE_4K)
+ return pa & HPTE_R_RPN;
+ else {
+ unsigned int penc = mmu_psize_defs[psize].penc;
+ unsigned int shift = mmu_psize_defs[psize].shift;
+ return (pa & ~((1ul << shift) - 1)) | (penc << 12);
+ }
+ return r;
+}
+
+/*
+ * This hashes a virtual address for a 256Mb segment only for now
+ */
+
+static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
+{
+ return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
+}
+
+extern int __hash_page_4K(unsigned long ea, unsigned long access,
+ unsigned long vsid, pte_t *ptep, unsigned long trap,
+ unsigned int local);
+extern int __hash_page_64K(unsigned long ea, unsigned long access,
+ unsigned long vsid, pte_t *ptep, unsigned long trap,
+ unsigned int local);
+struct mm_struct;
+extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap);
+extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
+ unsigned long ea, unsigned long vsid, int local,
+ unsigned long trap);
+
+extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
+ unsigned long pstart, unsigned long mode,
+ int psize);
+
+extern void htab_initialize(void);
+extern void htab_initialize_secondary(void);
+extern void hpte_init_native(void);
+extern void hpte_init_lpar(void);
+extern void hpte_init_iSeries(void);
+extern void hpte_init_beat(void);
+
+extern void stabs_alloc(void);
+extern void slb_initialize(void);
+extern void slb_flush_and_rebolt(void);
+extern void stab_initialize(unsigned long stab);
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * VSID allocation
+ *
+ * We first generate a 36-bit "proto-VSID". For kernel addresses this
+ * is equal to the ESID, for user addresses it is:
+ * (context << 15) | (esid & 0x7fff)
+ *
+ * The two forms are distinguishable because the top bit is 0 for user
+ * addresses, whereas the top two bits are 1 for kernel addresses.
+ * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
+ * now.
+ *
+ * The proto-VSIDs are then scrambled into real VSIDs with the
+ * multiplicative hash:
+ *
+ * VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
+ * where VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
+ * VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
+ *
+ * This scramble is only well defined for proto-VSIDs below
+ * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
+ * reserved. VSID_MULTIPLIER is prime, so in particular it is
+ * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
+ * Because the modulus is 2^n-1 we can compute it efficiently without
+ * a divide or extra multiply (see below).
+ *
+ * This scheme has several advantages over older methods:
+ *
+ * - We have VSIDs allocated for every kernel address
+ * (i.e. everything above 0xC000000000000000), except the very top
+ * segment, which simplifies several things.
+ *
+ * - We allow for 15 significant bits of ESID and 20 bits of
+ * context for user addresses. i.e. 8T (43 bits) of address space for
+ * up to 1M contexts (although the page table structure and context
+ * allocation will need changes to take advantage of this).
+ *
+ * - The scramble function gives robust scattering in the hash
+ * table (at least based on some initial results). The previous
+ * method was more susceptible to pathological cases giving excessive
+ * hash collisions.
+ */
+/*
+ * WARNING - If you change these you must make sure the asm
+ * implementations in slb_allocate (slb_low.S), do_stab_bolted
+ * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
+ *
+ * You'll also need to change the precomputed VSID values in head.S
+ * which are used by the iSeries firmware.
+ */
+
+#define VSID_MULTIPLIER ASM_CONST(200730139) /* 28-bit prime */
+#define VSID_BITS 36
+#define VSID_MODULUS ((1UL<<VSID_BITS)-1)
+
+#define CONTEXT_BITS 19
+#define USER_ESID_BITS 16
+
+#define USER_VSID_RANGE (1UL << (USER_ESID_BITS + SID_SHIFT))
+
+/*
+ * This macro generates asm code to compute the VSID scramble
+ * function. Used in slb_allocate() and do_stab_bolted. The function
+ * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
+ *
+ * rt = register continaing the proto-VSID and into which the
+ * VSID will be stored
+ * rx = scratch register (clobbered)
+ *
+ * - rt and rx must be different registers
+ * - The answer will end up in the low 36 bits of rt. The higher
+ * bits may contain other garbage, so you may need to mask the
+ * result.
+ */
+#define ASM_VSID_SCRAMBLE(rt, rx) \
+ lis rx,VSID_MULTIPLIER@h; \
+ ori rx,rx,VSID_MULTIPLIER@l; \
+ mulld rt,rt,rx; /* rt = rt * MULTIPLIER */ \
+ \
+ srdi rx,rt,VSID_BITS; \
+ clrldi rt,rt,(64-VSID_BITS); \
+ add rt,rt,rx; /* add high and low bits */ \
+ /* Now, r3 == VSID (mod 2^36-1), and lies between 0 and \
+ * 2^36-1+2^28-1. That in particular means that if r3 >= \
+ * 2^36-1, then r3+1 has the 2^36 bit set. So, if r3+1 has \
+ * the bit clear, r3 already has the answer we want, if it \
+ * doesn't, the answer is the low 36 bits of r3+1. So in all \
+ * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\
+ addi rx,rt,1; \
+ srdi rx,rx,VSID_BITS; /* extract 2^36 bit */ \
+ add rt,rt,rx
+
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned long mm_context_id_t;
+
+typedef struct {
+ mm_context_id_t id;
+ u16 user_psize; /* page size index */
+
+#ifdef CONFIG_PPC_MM_SLICES
+ u64 low_slices_psize; /* SLB page size encodings */
+ u64 high_slices_psize; /* 4 bits per slice for now */
+#else
+ u16 sllp; /* SLB page size encoding */
+#endif
+ unsigned long vdso_base;
+} mm_context_t;
+
+
+static inline unsigned long vsid_scramble(unsigned long protovsid)
+{
+#if 0
+ /* The code below is equivalent to this function for arguments
+ * < 2^VSID_BITS, which is all this should ever be called
+ * with. However gcc is not clever enough to compute the
+ * modulus (2^n-1) without a second multiply. */
+ return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
+#else /* 1 */
+ unsigned long x;
+
+ x = protovsid * VSID_MULTIPLIER;
+ x = (x >> VSID_BITS) + (x & VSID_MODULUS);
+ return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
+#endif /* 1 */
+}
+
+/* This is only valid for addresses >= KERNELBASE */
+static inline unsigned long get_kernel_vsid(unsigned long ea)
+{
+ return vsid_scramble(ea >> SID_SHIFT);
+}
+
+/* This is only valid for user addresses (which are below 2^41) */
+static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
+{
+ return vsid_scramble((context << USER_ESID_BITS)
+ | (ea >> SID_SHIFT));
+}
+
+#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
+#define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea))
+
+/* Physical address used by some IO functions */
+typedef unsigned long phys_addr_t;
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_MMU_HASH64_H_ */
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 200055a4b82..fe510fff890 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -2,407 +2,17 @@
#define _ASM_POWERPC_MMU_H_
#ifdef __KERNEL__
-#ifndef CONFIG_PPC64
-#include <asm-ppc/mmu.h>
+#ifdef CONFIG_PPC64
+/* 64-bit classic hash table MMU */
+# include <asm/mmu-hash64.h>
+#elif defined(CONFIG_44x)
+/* 44x-style software loaded TLB */
+# include <asm/mmu-44x.h>
#else
-
-/*
- * PowerPC memory management structures
- *
- * Dave Engebretsen & Mike Corrigan <{engebret|mikejc}@us.ibm.com>
- * PPC64 rework.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <asm/asm-compat.h>
-#include <asm/page.h>
-
-/*
- * Segment table
- */
-
-#define STE_ESID_V 0x80
-#define STE_ESID_KS 0x20
-#define STE_ESID_KP 0x10
-#define STE_ESID_N 0x08
-
-#define STE_VSID_SHIFT 12
-
-/* Location of cpu0's segment table */
-#define STAB0_PAGE 0x6
-#define STAB0_OFFSET (STAB0_PAGE << 12)
-#define STAB0_PHYS_ADDR (STAB0_OFFSET + PHYSICAL_START)
-
-#ifndef __ASSEMBLY__
-extern char initial_stab[];
-#endif /* ! __ASSEMBLY */
-
-/*
- * SLB
- */
-
-#define SLB_NUM_BOLTED 3
-#define SLB_CACHE_ENTRIES 8
-
-/* Bits in the SLB ESID word */
-#define SLB_ESID_V ASM_CONST(0x0000000008000000) /* valid */
-
-/* Bits in the SLB VSID word */
-#define SLB_VSID_SHIFT 12
-#define SLB_VSID_B ASM_CONST(0xc000000000000000)
-#define SLB_VSID_B_256M ASM_CONST(0x0000000000000000)
-#define SLB_VSID_B_1T ASM_CONST(0x4000000000000000)
-#define SLB_VSID_KS ASM_CONST(0x0000000000000800)
-#define SLB_VSID_KP ASM_CONST(0x0000000000000400)
-#define SLB_VSID_N ASM_CONST(0x0000000000000200) /* no-execute */
-#define SLB_VSID_L ASM_CONST(0x0000000000000100)
-#define SLB_VSID_C ASM_CONST(0x0000000000000080) /* class */
-#define SLB_VSID_LP ASM_CONST(0x0000000000000030)
-#define SLB_VSID_LP_00 ASM_CONST(0x0000000000000000)
-#define SLB_VSID_LP_01 ASM_CONST(0x0000000000000010)
-#define SLB_VSID_LP_10 ASM_CONST(0x0000000000000020)
-#define SLB_VSID_LP_11 ASM_CONST(0x0000000000000030)
-#define SLB_VSID_LLP (SLB_VSID_L|SLB_VSID_LP)
-
-#define SLB_VSID_KERNEL (SLB_VSID_KP)
-#define SLB_VSID_USER (SLB_VSID_KP|SLB_VSID_KS|SLB_VSID_C)
-
-#define SLBIE_C (0x08000000)
-
-/*
- * Hash table
- */
-
-#define HPTES_PER_GROUP 8
-
-#define HPTE_V_AVPN_SHIFT 7
-#define HPTE_V_AVPN ASM_CONST(0xffffffffffffff80)
-#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
-#define HPTE_V_COMPARE(x,y) (!(((x) ^ (y)) & HPTE_V_AVPN))
-#define HPTE_V_BOLTED ASM_CONST(0x0000000000000010)
-#define HPTE_V_LOCK ASM_CONST(0x0000000000000008)
-#define HPTE_V_LARGE ASM_CONST(0x0000000000000004)
-#define HPTE_V_SECONDARY ASM_CONST(0x0000000000000002)
-#define HPTE_V_VALID ASM_CONST(0x0000000000000001)
-
-#define HPTE_R_PP0 ASM_CONST(0x8000000000000000)
-#define HPTE_R_TS ASM_CONST(0x4000000000000000)
-#define HPTE_R_RPN_SHIFT 12
-#define HPTE_R_RPN ASM_CONST(0x3ffffffffffff000)
-#define HPTE_R_FLAGS ASM_CONST(0x00000000000003ff)
-#define HPTE_R_PP ASM_CONST(0x0000000000000003)
-#define HPTE_R_N ASM_CONST(0x0000000000000004)
-#define HPTE_R_C ASM_CONST(0x0000000000000080)
-#define HPTE_R_R ASM_CONST(0x0000000000000100)
-
-/* Values for PP (assumes Ks=0, Kp=1) */
-/* pp0 will always be 0 for linux */
-#define PP_RWXX 0 /* Supervisor read/write, User none */
-#define PP_RWRX 1 /* Supervisor read/write, User read */
-#define PP_RWRW 2 /* Supervisor read/write, User read/write */
-#define PP_RXRX 3 /* Supervisor read, User read */
-
-#ifndef __ASSEMBLY__
-
-typedef struct {
- unsigned long v;
- unsigned long r;
-} hpte_t;
-
-extern hpte_t *htab_address;
-extern unsigned long htab_size_bytes;
-extern unsigned long htab_hash_mask;
-
-/*
- * Page size definition
- *
- * shift : is the "PAGE_SHIFT" value for that page size
- * sllp : is a bit mask with the value of SLB L || LP to be or'ed
- * directly to a slbmte "vsid" value
- * penc : is the HPTE encoding mask for the "LP" field:
- *
- */
-struct mmu_psize_def
-{
- unsigned int shift; /* number of bits */
- unsigned int penc; /* HPTE encoding */
- unsigned int tlbiel; /* tlbiel supported for that page size */
- unsigned long avpnm; /* bits to mask out in AVPN in the HPTE */
- unsigned long sllp; /* SLB L||LP (exact mask to use in slbmte) */
-};
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * The kernel use the constants below to index in the page sizes array.
- * The use of fixed constants for this purpose is better for performances
- * of the low level hash refill handlers.
- *
- * A non supported page size has a "shift" field set to 0
- *
- * Any new page size being implemented can get a new entry in here. Whether
- * the kernel will use it or not is a different matter though. The actual page
- * size used by hugetlbfs is not defined here and may be made variable
- */
-
-#define MMU_PAGE_4K 0 /* 4K */
-#define MMU_PAGE_64K 1 /* 64K */
-#define MMU_PAGE_64K_AP 2 /* 64K Admixed (in a 4K segment) */
-#define MMU_PAGE_1M 3 /* 1M */
-#define MMU_PAGE_16M 4 /* 16M */
-#define MMU_PAGE_16G 5 /* 16G */
-#define MMU_PAGE_COUNT 6
-
-#ifndef __ASSEMBLY__
-
-/*
- * The current system page sizes
- */
-extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
-extern int mmu_linear_psize;
-extern int mmu_virtual_psize;
-extern int mmu_vmalloc_psize;
-extern int mmu_io_psize;
-
-/*
- * If the processor supports 64k normal pages but not 64k cache
- * inhibited pages, we have to be prepared to switch processes
- * to use 4k pages when they create cache-inhibited mappings.
- * If this is the case, mmu_ci_restrictions will be set to 1.
- */
-extern int mmu_ci_restrictions;
-
-#ifdef CONFIG_HUGETLB_PAGE
-/*
- * The page size index of the huge pages for use by hugetlbfs
- */
-extern int mmu_huge_psize;
-
-#endif /* CONFIG_HUGETLB_PAGE */
-
-/*
- * This function sets the AVPN and L fields of the HPTE appropriately
- * for the page size
- */
-static inline unsigned long hpte_encode_v(unsigned long va, int psize)
-{
- unsigned long v =
- v = (va >> 23) & ~(mmu_psize_defs[psize].avpnm);
- v <<= HPTE_V_AVPN_SHIFT;
- if (psize != MMU_PAGE_4K)
- v |= HPTE_V_LARGE;
- return v;
-}
-
-/*
- * This function sets the ARPN, and LP fields of the HPTE appropriately
- * for the page size. We assume the pa is already "clean" that is properly
- * aligned for the requested page size
- */
-static inline unsigned long hpte_encode_r(unsigned long pa, int psize)
-{
- unsigned long r;
-
- /* A 4K page needs no special encoding */
- if (psize == MMU_PAGE_4K)
- return pa & HPTE_R_RPN;
- else {
- unsigned int penc = mmu_psize_defs[psize].penc;
- unsigned int shift = mmu_psize_defs[psize].shift;
- return (pa & ~((1ul << shift) - 1)) | (penc << 12);
- }
- return r;
-}
-
-/*
- * This hashes a virtual address for a 256Mb segment only for now
- */
-
-static inline unsigned long hpt_hash(unsigned long va, unsigned int shift)
-{
- return ((va >> 28) & 0x7fffffffffUL) ^ ((va & 0x0fffffffUL) >> shift);
-}
-
-extern int __hash_page_4K(unsigned long ea, unsigned long access,
- unsigned long vsid, pte_t *ptep, unsigned long trap,
- unsigned int local);
-extern int __hash_page_64K(unsigned long ea, unsigned long access,
- unsigned long vsid, pte_t *ptep, unsigned long trap,
- unsigned int local);
-struct mm_struct;
-extern int hash_huge_page(struct mm_struct *mm, unsigned long access,
- unsigned long ea, unsigned long vsid, int local,
- unsigned long trap);
-
-extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
- unsigned long pstart, unsigned long mode,
- int psize);
-
-extern void htab_initialize(void);
-extern void htab_initialize_secondary(void);
-extern void hpte_init_native(void);
-extern void hpte_init_lpar(void);
-extern void hpte_init_iSeries(void);
-extern void hpte_init_beat(void);
-
-extern void stabs_alloc(void);
-extern void slb_initialize(void);
-extern void slb_flush_and_rebolt(void);
-extern void stab_initialize(unsigned long stab);
-
-#endif /* __ASSEMBLY__ */
-
-/*
- * VSID allocation
- *
- * We first generate a 36-bit "proto-VSID". For kernel addresses this
- * is equal to the ESID, for user addresses it is:
- * (context << 15) | (esid & 0x7fff)
- *
- * The two forms are distinguishable because the top bit is 0 for user
- * addresses, whereas the top two bits are 1 for kernel addresses.
- * Proto-VSIDs with the top two bits equal to 0b10 are reserved for
- * now.
- *
- * The proto-VSIDs are then scrambled into real VSIDs with the
- * multiplicative hash:
- *
- * VSID = (proto-VSID * VSID_MULTIPLIER) % VSID_MODULUS
- * where VSID_MULTIPLIER = 268435399 = 0xFFFFFC7
- * VSID_MODULUS = 2^36-1 = 0xFFFFFFFFF
- *
- * This scramble is only well defined for proto-VSIDs below
- * 0xFFFFFFFFF, so both proto-VSID and actual VSID 0xFFFFFFFFF are
- * reserved. VSID_MULTIPLIER is prime, so in particular it is
- * co-prime to VSID_MODULUS, making this a 1:1 scrambling function.
- * Because the modulus is 2^n-1 we can compute it efficiently without
- * a divide or extra multiply (see below).
- *
- * This scheme has several advantages over older methods:
- *
- * - We have VSIDs allocated for every kernel address
- * (i.e. everything above 0xC000000000000000), except the very top
- * segment, which simplifies several things.
- *
- * - We allow for 15 significant bits of ESID and 20 bits of
- * context for user addresses. i.e. 8T (43 bits) of address space for
- * up to 1M contexts (although the page table structure and context
- * allocation will need changes to take advantage of this).
- *
- * - The scramble function gives robust scattering in the hash
- * table (at least based on some initial results). The previous
- * method was more susceptible to pathological cases giving excessive
- * hash collisions.
- */
-/*
- * WARNING - If you change these you must make sure the asm
- * implementations in slb_allocate (slb_low.S), do_stab_bolted
- * (head.S) and ASM_VSID_SCRAMBLE (below) are changed accordingly.
- *
- * You'll also need to change the precomputed VSID values in head.S
- * which are used by the iSeries firmware.
- */
-
-#define VSID_MULTIPLIER ASM_CONST(200730139) /* 28-bit prime */
-#define VSID_BITS 36
-#define VSID_MODULUS ((1UL<<VSID_BITS)-1)
-
-#define CONTEXT_BITS 19
-#define USER_ESID_BITS 16
-
-#define USER_VSID_RANGE (1UL << (USER_ESID_BITS + SID_SHIFT))
-
-/*
- * This macro generates asm code to compute the VSID scramble
- * function. Used in slb_allocate() and do_stab_bolted. The function
- * computed is: (protovsid*VSID_MULTIPLIER) % VSID_MODULUS
- *
- * rt = register continaing the proto-VSID and into which the
- * VSID will be stored
- * rx = scratch register (clobbered)
- *
- * - rt and rx must be different registers
- * - The answer will end up in the low 36 bits of rt. The higher
- * bits may contain other garbage, so you may need to mask the
- * result.
- */
-#define ASM_VSID_SCRAMBLE(rt, rx) \
- lis rx,VSID_MULTIPLIER@h; \
- ori rx,rx,VSID_MULTIPLIER@l; \
- mulld rt,rt,rx; /* rt = rt * MULTIPLIER */ \
- \
- srdi rx,rt,VSID_BITS; \
- clrldi rt,rt,(64-VSID_BITS); \
- add rt,rt,rx; /* add high and low bits */ \
- /* Now, r3 == VSID (mod 2^36-1), and lies between 0 and \
- * 2^36-1+2^28-1. That in particular means that if r3 >= \
- * 2^36-1, then r3+1 has the 2^36 bit set. So, if r3+1 has \
- * the bit clear, r3 already has the answer we want, if it \
- * doesn't, the answer is the low 36 bits of r3+1. So in all \
- * cases the answer is the low 36 bits of (r3 + ((r3+1) >> 36))*/\
- addi rx,rt,1; \
- srdi rx,rx,VSID_BITS; /* extract 2^36 bit */ \
- add rt,rt,rx
-
-
-#ifndef __ASSEMBLY__
-
-typedef unsigned long mm_context_id_t;
-
-typedef struct {
- mm_context_id_t id;
- u16 user_psize; /* page size index */
- u16 sllp; /* SLB entry page size encoding */
-#ifdef CONFIG_HUGETLB_PAGE
- u16 low_htlb_areas, high_htlb_areas;
+/* Other 32-bit. FIXME: split up the other 32-bit MMU types, and
+ * revise for arch/powerpc */
+# include <asm-ppc/mmu.h>
#endif
- unsigned long vdso_base;
-} mm_context_t;
-
-
-static inline unsigned long vsid_scramble(unsigned long protovsid)
-{
-#if 0
- /* The code below is equivalent to this function for arguments
- * < 2^VSID_BITS, which is all this should ever be called
- * with. However gcc is not clever enough to compute the
- * modulus (2^n-1) without a second multiply. */
- return ((protovsid * VSID_MULTIPLIER) % VSID_MODULUS);
-#else /* 1 */
- unsigned long x;
-
- x = protovsid * VSID_MULTIPLIER;
- x = (x >> VSID_BITS) + (x & VSID_MODULUS);
- return (x + ((x+1) >> VSID_BITS)) & VSID_MODULUS;
-#endif /* 1 */
-}
-
-/* This is only valid for addresses >= KERNELBASE */
-static inline unsigned long get_kernel_vsid(unsigned long ea)
-{
- return vsid_scramble(ea >> SID_SHIFT);
-}
-
-/* This is only valid for user addresses (which are below 2^41) */
-static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
-{
- return vsid_scramble((context << USER_ESID_BITS)
- | (ea >> SID_SHIFT));
-}
-
-#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
-#define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea))
-
-/* Physical address used by some IO functions */
-typedef unsigned long phys_addr_t;
-
-
-#endif /* __ASSEMBLY */
-#endif /* CONFIG_PPC64 */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MMU_H_ */
diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h
index 083ac917bd2..c0d7795e3d2 100644
--- a/include/asm-powerpc/mmu_context.h
+++ b/include/asm-powerpc/mmu_context.h
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <asm/mmu.h>
#include <asm/cputable.h>
+#include <asm-generic/mm_hooks.h>
/*
* Copyright (C) 2001 PPC 64 Team, IBM Corp
diff --git a/include/asm-powerpc/mpc52xx.h b/include/asm-powerpc/mpc52xx.h
index 7afd5bf9452..c4631f6dd4f 100644
--- a/include/asm-powerpc/mpc52xx.h
+++ b/include/asm-powerpc/mpc52xx.h
@@ -253,5 +253,16 @@ extern int __init mpc52xx_add_bridge(struct device_node *node);
#endif /* __ASSEMBLY__ */
+#ifdef CONFIG_PM
+struct mpc52xx_suspend {
+ void (*board_suspend_prepare)(void __iomem *mbar);
+ void (*board_resume_finish)(void __iomem *mbar);
+};
+
+extern struct mpc52xx_suspend mpc52xx_suspend;
+extern int __init mpc52xx_pm_init(void);
+extern int mpc52xx_set_wakeup_gpio(u8 pin, u8 level);
+#endif /* CONFIG_PM */
+
#endif /* __ASM_POWERPC_MPC52xx_H__ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index cb204a71e91..2ffb06abe88 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -3,6 +3,7 @@
#ifdef __KERNEL__
#include <linux/irq.h>
+#include <linux/sysdev.h>
#include <asm/dcr.h>
/*
@@ -199,7 +200,7 @@ enum {
};
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
/* Fixup table entry */
struct mpic_irq_fixup
{
@@ -208,7 +209,7 @@ struct mpic_irq_fixup
u32 data;
unsigned int index;
};
-#endif /* CONFIG_MPIC_BROKEN_U3 */
+#endif /* CONFIG_MPIC_U3_HT_IRQS */
enum mpic_reg_type {
@@ -228,6 +229,14 @@ struct mpic_reg_bank {
#endif /* CONFIG_PPC_DCR */
};
+struct mpic_irq_save {
+ u32 vecprio,
+ dest;
+#ifdef CONFIG_MPIC_U3_HT_IRQS
+ u32 fixup_data;
+#endif
+};
+
/* The instance data of a given MPIC */
struct mpic
{
@@ -239,7 +248,7 @@ struct mpic
/* The "linux" controller struct */
struct irq_chip hc_irq;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
struct irq_chip hc_ht_irq;
#endif
#ifdef CONFIG_SMP
@@ -268,7 +277,7 @@ struct mpic
/* Spurious vector to program into unused sources */
unsigned int spurious_vec;
-#ifdef CONFIG_MPIC_BROKEN_U3
+#ifdef CONFIG_MPIC_U3_HT_IRQS
/* The fixup table */
struct mpic_irq_fixup *fixups;
spinlock_t fixup_lock;
@@ -292,8 +301,19 @@ struct mpic
u32 *hw_set;
#endif
+#ifdef CONFIG_PCI_MSI
+ spinlock_t bitmap_lock;
+ unsigned long *hwirq_bitmap;
+#endif
+
/* link */
struct mpic *next;
+
+ struct sys_device sysdev;
+
+#ifdef CONFIG_PM
+ struct mpic_irq_save *save_data;
+#endif
};
/*
@@ -313,7 +333,7 @@ struct mpic
/* Set this for a big-endian MPIC */
#define MPIC_BIG_ENDIAN 0x00000002
/* Broken U3 MPIC */
-#define MPIC_BROKEN_U3 0x00000004
+#define MPIC_U3_HT_IRQS 0x00000004
/* Broken IPI registers (autodetected) */
#define MPIC_BROKEN_IPI 0x00000008
/* MPIC wants a reset */
@@ -352,7 +372,7 @@ struct mpic
* @senses_num: number of entries in the array
*
* Note about the sense array. If none is passed, all interrupts are
- * setup to be level negative unless MPIC_BROKEN_U3 is set in which
+ * setup to be level negative unless MPIC_U3_HT_IRQS is set in which
* case they are edge positive (and the array is ignored anyway).
* The values in the array start at the first source of the MPIC,
* that is senses[0] correspond to linux irq "irq_offset".
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index a889b2005bf..e9af49eb1aa 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -32,5 +32,10 @@ extern int of_device_register(struct of_device *ofdev);
extern void of_device_unregister(struct of_device *ofdev);
extern void of_release_dev(struct device *dev);
+extern ssize_t of_device_get_modalias(struct of_device *ofdev,
+ char *str, ssize_t len);
+extern int of_device_uevent(struct device *dev,
+ char **envp, int num_envp, char *buffer, int buffer_size);
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 94c0ad2bff9..8d6b47f7b30 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -57,6 +57,8 @@ extern struct op_powerpc_model op_model_rs64;
extern struct op_powerpc_model op_model_power4;
extern struct op_powerpc_model op_model_7450;
extern struct op_powerpc_model op_model_cell;
+extern struct op_powerpc_model op_model_pa6t;
+
/* All the classic PPC parts use these */
static inline unsigned int classic_ctr_read(unsigned int i)
diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h
index 0d3adc09c84..c6a5b173566 100644
--- a/include/asm-powerpc/paca.h
+++ b/include/asm-powerpc/paca.h
@@ -70,6 +70,7 @@ struct paca_struct {
s16 hw_cpu_id; /* Physical processor number */
u8 cpu_start; /* At startup, processor spins until */
/* this becomes non-zero. */
+ struct slb_shadow *slb_shadow_ptr;
/*
* Now, starting in cacheline 2, the exception save areas
@@ -82,8 +83,8 @@ struct paca_struct {
mm_context_t context;
u16 vmalloc_sllp;
- u16 slb_cache[SLB_CACHE_ENTRIES];
u16 slb_cache_ptr;
+ u16 slb_cache[SLB_CACHE_ENTRIES];
/*
* then miscellaneous read-write fields
@@ -93,6 +94,7 @@ struct paca_struct {
u64 stab_rr; /* stab/slb round-robin counter */
u64 saved_r1; /* r1 save for RTAS calls */
u64 saved_msr; /* MSR saved here by enter_rtas */
+ u16 trap_save; /* Used when bad stack is encountered */
u8 soft_enabled; /* irq soft-enable flag */
u8 hard_enabled; /* set if irqs are enabled in MSR */
u8 io_sync; /* writel() needs spin_unlock sync */
@@ -101,8 +103,6 @@ struct paca_struct {
u64 user_time; /* accumulated usermode TB ticks */
u64 system_time; /* accumulated system TB ticks */
u64 startpurr; /* PURR/TB value snapshot */
-
- struct slb_shadow *slb_shadow_ptr;
};
extern struct paca_struct paca[];
diff --git a/include/asm-powerpc/page.h b/include/asm-powerpc/page.h
index b4d38b0b15f..10c51f457d4 100644
--- a/include/asm-powerpc/page.h
+++ b/include/asm-powerpc/page.h
@@ -121,6 +121,7 @@ typedef struct { pte_t pte; } real_pte_t;
#endif
/* PMD level */
+#ifdef CONFIG_PPC64
typedef struct { unsigned long pmd; } pmd_t;
#define pmd_val(x) ((x).pmd)
#define __pmd(x) ((pmd_t) { (x) })
@@ -130,7 +131,8 @@ typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
#define pud_val(x) ((x).pud)
#define __pud(x) ((pud_t) { (x) })
-#endif
+#endif /* !CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC64 */
/* PGD level */
typedef struct { unsigned long pgd; } pgd_t;
@@ -159,15 +161,17 @@ typedef unsigned long real_pte_t;
#endif
+#ifdef CONFIG_PPC64
typedef unsigned long pmd_t;
#define pmd_val(x) (x)
#define __pmd(x) (x)
-#if defined(CONFIG_PPC64) && !defined(CONFIG_PPC_64K_PAGES)
+#ifndef CONFIG_PPC_64K_PAGES
typedef unsigned long pud_t;
#define pud_val(x) (x)
#define __pud(x) (x)
-#endif
+#endif /* !CONFIG_PPC_64K_PAGES */
+#endif /* CONFIG_PPC64 */
typedef unsigned long pgd_t;
#define pgd_val(x) (x)
diff --git a/include/asm-powerpc/page_32.h b/include/asm-powerpc/page_32.h
index 07f6d3cf5e5..374d0db37e1 100644
--- a/include/asm-powerpc/page_32.h
+++ b/include/asm-powerpc/page_32.h
@@ -14,11 +14,9 @@
#ifdef CONFIG_PTE_64BIT
typedef unsigned long long pte_basic_t;
#define PTE_SHIFT (PAGE_SHIFT - 3) /* 512 ptes per page */
-#define PTE_FMT "%16Lx"
#else
typedef unsigned long pte_basic_t;
#define PTE_SHIFT (PAGE_SHIFT - 2) /* 1024 ptes per page */
-#define PTE_FMT "%.8lx"
#endif
struct page;
diff --git a/include/asm-powerpc/page_64.h b/include/asm-powerpc/page_64.h
index eab779c2199..3448a3d4bc6 100644
--- a/include/asm-powerpc/page_64.h
+++ b/include/asm-powerpc/page_64.h
@@ -88,57 +88,55 @@ extern unsigned int HPAGE_SHIFT;
#endif /* __ASSEMBLY__ */
-#ifdef CONFIG_HUGETLB_PAGE
+#ifdef CONFIG_PPC_MM_SLICES
-#define HTLB_AREA_SHIFT 40
-#define HTLB_AREA_SIZE (1UL << HTLB_AREA_SHIFT)
-#define GET_HTLB_AREA(x) ((x) >> HTLB_AREA_SHIFT)
+#define SLICE_LOW_SHIFT 28
+#define SLICE_HIGH_SHIFT 40
-#define LOW_ESID_MASK(addr, len) \
- (((1U << (GET_ESID(min((addr)+(len)-1, 0x100000000UL))+1)) \
- - (1U << GET_ESID(min((addr), 0x100000000UL)))) & 0xffff)
-#define HTLB_AREA_MASK(addr, len) (((1U << (GET_HTLB_AREA(addr+len-1)+1)) \
- - (1U << GET_HTLB_AREA(addr))) & 0xffff)
+#define SLICE_LOW_TOP (0x100000000ul)
+#define SLICE_NUM_LOW (SLICE_LOW_TOP >> SLICE_LOW_SHIFT)
+#define SLICE_NUM_HIGH (PGTABLE_RANGE >> SLICE_HIGH_SHIFT)
-#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
-#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define GET_LOW_SLICE_INDEX(addr) ((addr) >> SLICE_LOW_SHIFT)
+#define GET_HIGH_SLICE_INDEX(addr) ((addr) >> SLICE_HIGH_SHIFT)
-#define touches_hugepage_low_range(mm, addr, len) \
- (((addr) < 0x100000000UL) \
- && (LOW_ESID_MASK((addr), (len)) & (mm)->context.low_htlb_areas))
-#define touches_hugepage_high_range(mm, addr, len) \
- ((((addr) + (len)) > 0x100000000UL) \
- && (HTLB_AREA_MASK((addr), (len)) & (mm)->context.high_htlb_areas))
-
-#define __within_hugepage_low_range(addr, len, segmask) \
- ( (((addr)+(len)) <= 0x100000000UL) \
- && ((LOW_ESID_MASK((addr), (len)) | (segmask)) == (segmask)))
-#define within_hugepage_low_range(addr, len) \
- __within_hugepage_low_range((addr), (len), \
- current->mm->context.low_htlb_areas)
-#define __within_hugepage_high_range(addr, len, zonemask) \
- ( ((addr) >= 0x100000000UL) \
- && ((HTLB_AREA_MASK((addr), (len)) | (zonemask)) == (zonemask)))
-#define within_hugepage_high_range(addr, len) \
- __within_hugepage_high_range((addr), (len), \
- current->mm->context.high_htlb_areas)
-
-#define is_hugepage_only_range(mm, addr, len) \
- (touches_hugepage_high_range((mm), (addr), (len)) || \
- touches_hugepage_low_range((mm), (addr), (len)))
-#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#ifndef __ASSEMBLY__
+
+struct slice_mask {
+ u16 low_slices;
+ u16 high_slices;
+};
+
+struct mm_struct;
-#define in_hugepage_area(context, addr) \
- (cpu_has_feature(CPU_FTR_16M_PAGE) && \
- ( ( (addr) >= 0x100000000UL) \
- ? ((1 << GET_HTLB_AREA(addr)) & (context).high_htlb_areas) \
- : ((1 << GET_ESID(addr)) & (context).low_htlb_areas) ) )
+extern unsigned long slice_get_unmapped_area(unsigned long addr,
+ unsigned long len,
+ unsigned long flags,
+ unsigned int psize,
+ int topdown,
+ int use_cache);
-#else /* !CONFIG_HUGETLB_PAGE */
+extern unsigned int get_slice_psize(struct mm_struct *mm,
+ unsigned long addr);
-#define in_hugepage_area(mm, addr) 0
+extern void slice_init_context(struct mm_struct *mm, unsigned int psize);
+extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
+
+#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
+extern int is_hugepage_only_range(struct mm_struct *m,
+ unsigned long addr,
+ unsigned long len);
+
+#endif /* __ASSEMBLY__ */
+#else
+#define slice_init()
+#endif /* CONFIG_PPC_MM_SLICES */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#define ARCH_HAS_HUGETLB_FREE_PGD_RANGE
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#endif /* !CONFIG_HUGETLB_PAGE */
diff --git a/include/asm-powerpc/parport.h b/include/asm-powerpc/parport.h
index 3fca21ddf54..414c50e2e88 100644
--- a/include/asm-powerpc/parport.h
+++ b/include/asm-powerpc/parport.h
@@ -12,26 +12,21 @@
#include <asm/prom.h>
-extern struct parport *parport_pc_probe_port (unsigned long int base,
- unsigned long int base_hi,
- int irq, int dma,
- struct pci_dev *dev);
-
static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma)
{
struct device_node *np;
- u32 *prop;
+ const u32 *prop;
u32 io1, io2;
int propsize;
int count = 0;
for (np = NULL; (np = of_find_compatible_node(np,
"parallel",
"pnpPNP,400")) != NULL;) {
- prop = (u32 *)get_property(np, "reg", &propsize);
+ prop = of_get_property(np, "reg", &propsize);
if (!prop || propsize > 6*sizeof(u32))
continue;
io1 = prop[1]; io2 = prop[2];
- prop = (u32 *)get_property(np, "interrupts", NULL);
+ prop = of_get_property(np, "interrupts", NULL);
if (!prop)
continue;
if (parport_pc_probe_port(io1, io2, prop[0], autodma, NULL) != NULL)
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index ac656ee6bb1..ce0f13e8eb1 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -70,19 +70,22 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
*/
#define PCI_DISABLE_MWI
-extern struct dma_mapping_ops *pci_dma_ops;
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
+extern struct dma_mapping_ops *get_pci_dma_ops(void);
/* For DAC DMA, we currently don't support it by default, but
* we let 64-bit platforms override this.
*/
static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
{
- if (pci_dma_ops && pci_dma_ops->dac_dma_supported)
- return pci_dma_ops->dac_dma_supported(&hwdev->dev, mask);
+ struct dma_mapping_ops *d = get_pci_dma_ops();
+
+ if (d && d->dac_dma_supported)
+ return d->dac_dma_supported(&hwdev->dev, mask);
return 0;
}
-#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
unsigned long *strategy_parameter)
@@ -99,6 +102,9 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
*strat = PCI_DMA_BURST_MULTIPLE;
*strategy_parameter = cacheline_size;
}
+#else /* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops() NULL
#endif
extern int pci_domain_nr(struct pci_bus *bus);
diff --git a/include/asm-powerpc/pgalloc-32.h b/include/asm-powerpc/pgalloc-32.h
new file mode 100644
index 00000000000..e1307432163
--- /dev/null
+++ b/include/asm-powerpc/pgalloc-32.h
@@ -0,0 +1,41 @@
+#ifndef _ASM_POWERPC_PGALLOC_32_H
+#define _ASM_POWERPC_PGALLOC_32_H
+
+#include <linux/threads.h>
+
+extern void __bad_pte(pmd_t *pmd);
+
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(pgd_t *pgd);
+
+/*
+ * We don't have any real pmd's, and this code never triggers because
+ * the pgd will always be present..
+ */
+/* #define pmd_alloc_one(mm,address) ({ BUG(); ((pmd_t *)2); }) */
+#define pmd_free(x) do { } while (0)
+#define __pmd_free_tlb(tlb,x) do { } while (0)
+/* #define pgd_populate(mm, pmd, pte) BUG() */
+
+#ifndef CONFIG_BOOKE
+#define pmd_populate_kernel(mm, pmd, pte) \
+ (pmd_val(*(pmd)) = __pa(pte) | _PMD_PRESENT)
+#define pmd_populate(mm, pmd, pte) \
+ (pmd_val(*(pmd)) = (page_to_pfn(pte) << PAGE_SHIFT) | _PMD_PRESENT)
+#else
+#define pmd_populate_kernel(mm, pmd, pte) \
+ (pmd_val(*(pmd)) = (unsigned long)pte | _PMD_PRESENT)
+#define pmd_populate(mm, pmd, pte) \
+ (pmd_val(*(pmd)) = (unsigned long)lowmem_page_address(pte) | _PMD_PRESENT)
+#endif
+
+extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr);
+extern struct page *pte_alloc_one(struct mm_struct *mm, unsigned long addr);
+extern void pte_free_kernel(pte_t *pte);
+extern void pte_free(struct page *pte);
+
+#define __pte_free_tlb(tlb, pte) pte_free((pte))
+
+#define check_pgt_cache() do { } while (0)
+
+#endif /* _ASM_POWERPC_PGALLOC_32_H */
diff --git a/include/asm-powerpc/pgalloc-64.h b/include/asm-powerpc/pgalloc-64.h
new file mode 100644
index 00000000000..d9a3a8ca58a
--- /dev/null
+++ b/include/asm-powerpc/pgalloc-64.h
@@ -0,0 +1,147 @@
+#ifndef _ASM_POWERPC_PGALLOC_64_H
+#define _ASM_POWERPC_PGALLOC_64_H
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/cpumask.h>
+#include <linux/percpu.h>
+
+extern struct kmem_cache *pgtable_cache[];
+
+#define PGD_CACHE_NUM 0
+#define PUD_CACHE_NUM 1
+#define PMD_CACHE_NUM 1
+#define HUGEPTE_CACHE_NUM 2
+#define PTE_NONCACHE_NUM 3 /* from GFP rather than kmem_cache */
+
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
+}
+
+static inline void pgd_free(pgd_t *pgd)
+{
+ kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
+}
+
+#ifndef CONFIG_PPC_64K_PAGES
+
+#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD)
+
+static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],
+ GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pud_free(pud_t *pud)
+{
+ kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
+}
+
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+ pud_set(pud, (unsigned long)pmd);
+}
+
+#define pmd_populate(mm, pmd, pte_page) \
+ pmd_populate_kernel(mm, pmd, page_address(pte_page))
+#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte))
+
+
+#else /* CONFIG_PPC_64K_PAGES */
+
+#define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd)
+
+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
+ pte_t *pte)
+{
+ pmd_set(pmd, (unsigned long)pte);
+}
+
+#define pmd_populate(mm, pmd, pte_page) \
+ pmd_populate_kernel(mm, pmd, page_address(pte_page))
+
+#endif /* CONFIG_PPC_64K_PAGES */
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],
+ GFP_KERNEL|__GFP_REPEAT);
+}
+
+static inline void pmd_free(pmd_t *pmd)
+{
+ kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
+}
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+ unsigned long address)
+{
+ return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+}
+
+static inline struct page *pte_alloc_one(struct mm_struct *mm,
+ unsigned long address)
+{
+ return virt_to_page(pte_alloc_one_kernel(mm, address));
+}
+
+static inline void pte_free_kernel(pte_t *pte)
+{
+ free_page((unsigned long)pte);
+}
+
+static inline void pte_free(struct page *ptepage)
+{
+ __free_page(ptepage);
+}
+
+#define PGF_CACHENUM_MASK 0x3
+
+typedef struct pgtable_free {
+ unsigned long val;
+} pgtable_free_t;
+
+static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
+ unsigned long mask)
+{
+ BUG_ON(cachenum > PGF_CACHENUM_MASK);
+
+ return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
+}
+
+static inline void pgtable_free(pgtable_free_t pgf)
+{
+ void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
+ int cachenum = pgf.val & PGF_CACHENUM_MASK;
+
+ if (cachenum == PTE_NONCACHE_NUM)
+ free_page((unsigned long)p);
+ else
+ kmem_cache_free(pgtable_cache[cachenum], p);
+}
+
+extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
+
+#define __pte_free_tlb(tlb, ptepage) \
+ pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
+ PTE_NONCACHE_NUM, PTE_TABLE_SIZE-1))
+#define __pmd_free_tlb(tlb, pmd) \
+ pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
+ PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
+#ifndef CONFIG_PPC_64K_PAGES
+#define __pud_free_tlb(tlb, pud) \
+ pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
+ PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
+#endif /* CONFIG_PPC_64K_PAGES */
+
+#define check_pgt_cache() do { } while (0)
+
+#endif /* _ASM_POWERPC_PGALLOC_64_H */
diff --git a/include/asm-powerpc/pgalloc.h b/include/asm-powerpc/pgalloc.h
index b0830db68f8..b4505ed0f0f 100644
--- a/include/asm-powerpc/pgalloc.h
+++ b/include/asm-powerpc/pgalloc.h
@@ -2,159 +2,11 @@
#define _ASM_POWERPC_PGALLOC_H
#ifdef __KERNEL__
-#ifndef CONFIG_PPC64
-#include <asm-ppc/pgalloc.h>
+#ifdef CONFIG_PPC64
+#include <asm/pgalloc-64.h>
#else
-
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/cpumask.h>
-#include <linux/percpu.h>
-
-extern struct kmem_cache *pgtable_cache[];
-
-#ifdef CONFIG_PPC_64K_PAGES
-#define PTE_CACHE_NUM 0
-#define PMD_CACHE_NUM 1
-#define PGD_CACHE_NUM 2
-#define HUGEPTE_CACHE_NUM 3
-#else
-#define PTE_CACHE_NUM 0
-#define PMD_CACHE_NUM 1
-#define PUD_CACHE_NUM 1
-#define PGD_CACHE_NUM 0
-#define HUGEPTE_CACHE_NUM 2
+#include <asm/pgalloc-32.h>
#endif
-/*
- * 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.
- */
-
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
- return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL);
-}
-
-static inline void pgd_free(pgd_t *pgd)
-{
- kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd);
-}
-
-#ifndef CONFIG_PPC_64K_PAGES
-
-#define pgd_populate(MM, PGD, PUD) pgd_set(PGD, PUD)
-
-static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
- return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM],
- GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline void pud_free(pud_t *pud)
-{
- kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud);
-}
-
-static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
-{
- pud_set(pud, (unsigned long)pmd);
-}
-
-#define pmd_populate(mm, pmd, pte_page) \
- pmd_populate_kernel(mm, pmd, page_address(pte_page))
-#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, (unsigned long)(pte))
-
-
-#else /* CONFIG_PPC_64K_PAGES */
-
-#define pud_populate(mm, pud, pmd) pud_set(pud, (unsigned long)pmd)
-
-static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
- pte_t *pte)
-{
- pmd_set(pmd, (unsigned long)pte);
-}
-
-#define pmd_populate(mm, pmd, pte_page) \
- pmd_populate_kernel(mm, pmd, page_address(pte_page))
-
-#endif /* CONFIG_PPC_64K_PAGES */
-
-static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
- return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM],
- GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline void pmd_free(pmd_t *pmd)
-{
- kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd);
-}
-
-static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
- unsigned long address)
-{
- return kmem_cache_alloc(pgtable_cache[PTE_CACHE_NUM],
- GFP_KERNEL|__GFP_REPEAT);
-}
-
-static inline struct page *pte_alloc_one(struct mm_struct *mm,
- unsigned long address)
-{
- return virt_to_page(pte_alloc_one_kernel(mm, address));
-}
-
-static inline void pte_free_kernel(pte_t *pte)
-{
- kmem_cache_free(pgtable_cache[PTE_CACHE_NUM], pte);
-}
-
-static inline void pte_free(struct page *ptepage)
-{
- pte_free_kernel(page_address(ptepage));
-}
-
-#define PGF_CACHENUM_MASK 0x3
-
-typedef struct pgtable_free {
- unsigned long val;
-} pgtable_free_t;
-
-static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum,
- unsigned long mask)
-{
- BUG_ON(cachenum > PGF_CACHENUM_MASK);
-
- return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum};
-}
-
-static inline void pgtable_free(pgtable_free_t pgf)
-{
- void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK);
- int cachenum = pgf.val & PGF_CACHENUM_MASK;
-
- kmem_cache_free(pgtable_cache[cachenum], p);
-}
-
-extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf);
-
-#define __pte_free_tlb(tlb, ptepage) \
- pgtable_free_tlb(tlb, pgtable_free_cache(page_address(ptepage), \
- PTE_CACHE_NUM, PTE_TABLE_SIZE-1))
-#define __pmd_free_tlb(tlb, pmd) \
- pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \
- PMD_CACHE_NUM, PMD_TABLE_SIZE-1))
-#ifndef CONFIG_PPC_64K_PAGES
-#define __pud_free_tlb(tlb, pud) \
- pgtable_free_tlb(tlb, pgtable_free_cache(pud, \
- PUD_CACHE_NUM, PUD_TABLE_SIZE-1))
-#endif /* CONFIG_PPC_64K_PAGES */
-
-#define check_pgt_cache() do { } while (0)
-
-#endif /* CONFIG_PPC64 */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PGALLOC_H */
diff --git a/include/asm-powerpc/pgtable-4k.h b/include/asm-powerpc/pgtable-4k.h
index 345d9b07b3e..add5481fd7c 100644
--- a/include/asm-powerpc/pgtable-4k.h
+++ b/include/asm-powerpc/pgtable-4k.h
@@ -1,3 +1,5 @@
+#ifndef _ASM_POWERPC_PGTABLE_4K_H
+#define _ASM_POWERPC_PGTABLE_4K_H
/*
* Entries per page directory level. The PTE level must use a 64b record
* for each page table entry. The PMD and PGD level use a 32b record for
@@ -78,7 +80,11 @@
#define pte_iterate_hashed_end() } while(0)
-#define pte_pagesize_index(pte) MMU_PAGE_4K
+#ifdef CONFIG_PPC_HAS_HASH_64K
+#define pte_pagesize_index(mm, addr, pte) get_slice_psize(mm, addr)
+#else
+#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
+#endif
/*
* 4-level page tables related bits
@@ -97,3 +103,7 @@
#define pud_ERROR(e) \
printk("%s:%d: bad pud %08lx.\n", __FILE__, __LINE__, pud_val(e))
+
+#define remap_4k_pfn(vma, addr, pfn, prot) \
+ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, (prot))
+#endif /* _ASM_POWERPC_PGTABLE_4K_H */
diff --git a/include/asm-powerpc/pgtable-64k.h b/include/asm-powerpc/pgtable-64k.h
index 4b7126c53f3..31cbd3d7fce 100644
--- a/include/asm-powerpc/pgtable-64k.h
+++ b/include/asm-powerpc/pgtable-64k.h
@@ -1,6 +1,5 @@
#ifndef _ASM_POWERPC_PGTABLE_64K_H
#define _ASM_POWERPC_PGTABLE_64K_H
-#ifdef __KERNEL__
#include <asm-generic/pgtable-nopud.h>
@@ -35,6 +34,12 @@
#define _PAGE_HPTE_SUB 0x0ffff000 /* combo only: sub pages HPTE bits */
#define _PAGE_HPTE_SUB0 0x08000000 /* combo only: first sub page */
#define _PAGE_COMBO 0x10000000 /* this is a combo 4k page */
+#define _PAGE_4K_PFN 0x20000000 /* PFN is for a single 4k page */
+
+/* Note the full page bits must be in the same location as for normal
+ * 4k pages as the same asssembly will be used to insert 64K pages
+ * wether the kernel has CONFIG_PPC_64K_PAGES or not
+ */
#define _PAGE_F_SECOND 0x00008000 /* full page: hidx bits */
#define _PAGE_F_GIX 0x00007000 /* full page: hidx bits */
@@ -64,8 +69,6 @@
/* Bits to mask out from a PGD/PUD to get to the PMD page */
#define PUD_MASKED_BITS 0x1ff
-#ifndef __ASSEMBLY__
-
/* Manipulate "rpte" values */
#define __real_pte(e,p) ((real_pte_t) { \
(e), pte_val(*((p) + PTRS_PER_PTE)) })
@@ -90,9 +93,11 @@
#define pte_iterate_hashed_end() } while(0); } } while(0)
-#define pte_pagesize_index(pte) \
+#define pte_pagesize_index(mm, addr, pte) \
(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
-#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
+#define remap_4k_pfn(vma, addr, pfn, prot) \
+ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
+ __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+
#endif /* _ASM_POWERPC_PGTABLE_64K_H */
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h
new file mode 100644
index 00000000000..09662a24f22
--- /dev/null
+++ b/include/asm-powerpc/pgtable-ppc32.h
@@ -0,0 +1,813 @@
+#ifndef _ASM_POWERPC_PGTABLE_PPC32_H
+#define _ASM_POWERPC_PGTABLE_PPC32_H
+
+#include <asm-generic/pgtable-nopmd.h>
+
+#ifndef __ASSEMBLY__
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <asm/processor.h> /* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/io.h> /* For sub-arch specific PPC_PIN_SIZE */
+struct mm_struct;
+
+extern unsigned long va_to_phys(unsigned long address);
+extern pte_t *va_to_pte(unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
+#endif /* __ASSEMBLY__ */
+
+/*
+ * The PowerPC MMU uses a hash table containing PTEs, together with
+ * a set of 16 segment registers (on 32-bit implementations), to define
+ * the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings. We maintain a two-level page table tree, much
+ * like that used by the i386, for the sake of the Linux memory
+ * management code. Low-level assembler code in hashtable.S
+ * (procedure hash_page) is responsible for extracting ptes from the
+ * tree and putting them into the hash table when necessary, and
+ * updating the accessed and modified bits in the page table tree.
+ */
+
+/*
+ * The PowerPC MPC8xx uses a TLB with hardware assisted, software tablewalk.
+ * We also use the two level tables, but we can put the real bits in them
+ * needed for the TLB and tablewalk. These definitions require Mx_CTR.PPM = 0,
+ * Mx_CTR.PPCS = 0, and MD_CTR.TWAM = 1. The level 2 descriptor has
+ * additional page protection (when Mx_CTR.PPCS = 1) that allows TLB hit
+ * based upon user/super access. The TLB does not have accessed nor write
+ * protect. We assume that if the TLB get loaded with an entry it is
+ * accessed, and overload the changed bit for write protect. We use
+ * two bits in the software pte that are supposed to be set to zero in
+ * the TLB entry (24 and 25) for these indicators. Although the level 1
+ * descriptor contains the guarded and writethrough/copyback bits, we can
+ * set these at the page level since they get copied from the Mx_TWC
+ * register when the TLB entry is loaded. We will use bit 27 for guard, since
+ * that is where it exists in the MD_TWC, and bit 26 for writethrough.
+ * These will get masked from the level 2 descriptor at TLB load time, and
+ * copied to the MD_TWC before it gets loaded.
+ * Large page sizes added. We currently support two sizes, 4K and 8M.
+ * This also allows a TLB hander optimization because we can directly
+ * load the PMD into MD_TWC. The 8M pages are only used for kernel
+ * mapping of well known areas. The PMD (PGD) entries contain control
+ * flags in addition to the address, so care must be taken that the
+ * software no longer assumes these are only pointers.
+ */
+
+/*
+ * At present, all PowerPC 400-class processors share a similar TLB
+ * architecture. The instruction and data sides share a unified,
+ * 64-entry, fully-associative TLB which is maintained totally under
+ * software control. In addition, the instruction side has a
+ * hardware-managed, 4-entry, fully-associative TLB which serves as a
+ * first level to the shared TLB. These two TLBs are known as the UTLB
+ * and ITLB, respectively (see "mmu.h" for definitions).
+ */
+
+/*
+ * The normal case is that PTEs are 32-bits and we have a 1-page
+ * 1024-entry pgdir pointing to 1-page 1024-entry PTE pages. -- paulus
+ *
+ * For any >32-bit physical address platform, we can use the following
+ * two level page table layout where the pgdir is 8KB and the MS 13 bits
+ * are an index to the second level table. The combined pgdir/pmd first
+ * level has 2048 entries and the second level has 512 64-bit PTE entries.
+ * -Matt
+ */
+/* PGDIR_SHIFT determines what a top-level page table entry can map */
+#define PGDIR_SHIFT (PAGE_SHIFT + PTE_SHIFT)
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/*
+ * entries per page directory level: our page-table tree is two-level, so
+ * we don't really have any PMD directory.
+ */
+#define PTRS_PER_PTE (1 << PTE_SHIFT)
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT))
+
+#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
+#define FIRST_USER_ADDRESS 0
+
+#define USER_PGD_PTRS (PAGE_OFFSET >> PGDIR_SHIFT)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS)
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %llx.\n", __FILE__, __LINE__, \
+ (unsigned long long)pte_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * Just any arbitrary offset to the start of the vmalloc VM area: the
+ * current 64MB value just means that there will be a 64MB "hole" after the
+ * physical memory until the kernel virtual memory starts. That means that
+ * any out-of-bounds memory accesses will hopefully be caught.
+ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
+ * area for the same reason. ;)
+ *
+ * We no longer map larger than phys RAM with the BATs so we don't have
+ * to worry about the VMALLOC_OFFSET causing problems. We do have to worry
+ * about clashes between our early calls to ioremap() that start growing down
+ * from ioremap_base being run into the VM area allocations (growing upwards
+ * from VMALLOC_START). For this reason we have ioremap_bot to check when
+ * we actually run into our mappings setup in the early boot with the VM
+ * system. This really does become a problem for machines with good amounts
+ * of RAM. -- Cort
+ */
+#define VMALLOC_OFFSET (0x1000000) /* 16M */
+#ifdef PPC_PIN_SIZE
+#define VMALLOC_START (((_ALIGN((long)high_memory, PPC_PIN_SIZE) + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#else
+#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
+#endif
+#define VMALLOC_END ioremap_bot
+
+/*
+ * Bits in a linux-style PTE. These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible.
+ */
+
+#if defined(CONFIG_40x)
+
+/* There are several potential gotchas here. The 40x hardware TLBLO
+ field looks like this:
+
+ 0 1 2 3 4 ... 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ RPN..................... 0 0 EX WR ZSEL....... W I M G
+
+ Where possible we make the Linux PTE bits match up with this
+
+ - bits 20 and 21 must be cleared, because we use 4k pages (40x can
+ support down to 1k pages), this is done in the TLBMiss exception
+ handler.
+ - We use only zones 0 (for kernel pages) and 1 (for user pages)
+ of the 16 available. Bit 24-26 of the TLB are cleared in the TLB
+ miss handler. Bit 27 is PAGE_USER, thus selecting the correct
+ zone.
+ - PRESENT *must* be in the bottom two bits because swap cache
+ entries use the top 30 bits. Because 40x doesn't support SMP
+ anyway, M is irrelevant so we borrow it for PAGE_PRESENT. Bit 30
+ is cleared in the TLB miss handler before the TLB entry is loaded.
+ - All other bits of the PTE are loaded into TLBLO without
+ modification, leaving us only the bits 20, 21, 24, 25, 26, 30 for
+ software PTE bits. We actually use use bits 21, 24, 25, and
+ 30 respectively for the software bits: ACCESSED, DIRTY, RW, and
+ PRESENT.
+*/
+
+/* Definitions for 40x embedded chips. */
+#define _PAGE_GUARDED 0x001 /* G: page is guarded from prefetch */
+#define _PAGE_FILE 0x001 /* when !present: nonlinear file mapping */
+#define _PAGE_PRESENT 0x002 /* software: PTE contains a translation */
+#define _PAGE_NO_CACHE 0x004 /* I: caching is inhibited */
+#define _PAGE_WRITETHRU 0x008 /* W: caching is write-through */
+#define _PAGE_USER 0x010 /* matches one of the zone permission bits */
+#define _PAGE_RW 0x040 /* software: Writes permitted */
+#define _PAGE_DIRTY 0x080 /* software: dirty page */
+#define _PAGE_HWWRITE 0x100 /* hardware: Dirty & RW, set in exception */
+#define _PAGE_HWEXEC 0x200 /* hardware: EX permission */
+#define _PAGE_ACCESSED 0x400 /* software: R: page referenced */
+
+#define _PMD_PRESENT 0x400 /* PMD points to page of PTEs */
+#define _PMD_BAD 0x802
+#define _PMD_SIZE 0x0e0 /* size field, != 0 for large-page PMD entry */
+#define _PMD_SIZE_4M 0x0c0
+#define _PMD_SIZE_16M 0x0e0
+#define PMD_PAGE_SIZE(pmdval) (1024 << (((pmdval) & _PMD_SIZE) >> 4))
+
+#elif defined(CONFIG_44x)
+/*
+ * Definitions for PPC440
+ *
+ * Because of the 3 word TLB entries to support 36-bit addressing,
+ * the attribute are difficult to map in such a fashion that they
+ * are easily loaded during exception processing. I decided to
+ * organize the entry so the ERPN is the only portion in the
+ * upper word of the PTE and the attribute bits below are packed
+ * in as sensibly as they can be in the area below a 4KB page size
+ * oriented RPN. This at least makes it easy to load the RPN and
+ * ERPN fields in the TLB. -Matt
+ *
+ * Note that these bits preclude future use of a page size
+ * less than 4KB.
+ *
+ *
+ * PPC 440 core has following TLB attribute fields;
+ *
+ * TLB1:
+ * 0 1 2 3 4 ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ * RPN................................. - - - - - - ERPN.......
+ *
+ * TLB2:
+ * 0 1 2 3 4 ... 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
+ * - - - - - - U0 U1 U2 U3 W I M G E - UX UW UR SX SW SR
+ *
+ * There are some constrains and options, to decide mapping software bits
+ * into TLB entry.
+ *
+ * - PRESENT *must* be in the bottom three bits because swap cache
+ * entries use the top 29 bits for TLB2.
+ *
+ * - FILE *must* be in the bottom three bits because swap cache
+ * entries use the top 29 bits for TLB2.
+ *
+ * - CACHE COHERENT bit (M) has no effect on PPC440 core, because it
+ * doesn't support SMP. So we can use this as software bit, like
+ * DIRTY.
+ *
+ * With the PPC 44x Linux implementation, the 0-11th LSBs of the PTE are used
+ * for memory protection related functions (see PTE structure in
+ * include/asm-ppc/mmu.h). The _PAGE_XXX definitions in this file map to the
+ * above bits. Note that the bit values are CPU specific, not architecture
+ * specific.
+ *
+ * The kernel PTE entry holds an arch-dependent swp_entry structure under
+ * certain situations. In other words, in such situations some portion of
+ * the PTE bits are used as a swp_entry. In the PPC implementation, the
+ * 3-24th LSB are shared with swp_entry, however the 0-2nd three LSB still
+ * hold protection values. That means the three protection bits are
+ * reserved for both PTE and SWAP entry at the most significant three
+ * LSBs.
+ *
+ * There are three protection bits available for SWAP entry:
+ * _PAGE_PRESENT
+ * _PAGE_FILE
+ * _PAGE_HASHPTE (if HW has)
+ *
+ * So those three bits have to be inside of 0-2nd LSB of PTE.
+ *
+ */
+
+#define _PAGE_PRESENT 0x00000001 /* S: PTE valid */
+#define _PAGE_RW 0x00000002 /* S: Write permission */
+#define _PAGE_FILE 0x00000004 /* S: nonlinear file mapping */
+#define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */
+#define _PAGE_HWWRITE 0x00000010 /* H: Dirty & RW */
+#define _PAGE_HWEXEC 0x00000020 /* H: Execute permission */
+#define _PAGE_USER 0x00000040 /* S: User page */
+#define _PAGE_ENDIAN 0x00000080 /* H: E bit */
+#define _PAGE_GUARDED 0x00000100 /* H: G bit */
+#define _PAGE_DIRTY 0x00000200 /* S: Page dirty */
+#define _PAGE_NO_CACHE 0x00000400 /* H: I bit */
+#define _PAGE_WRITETHRU 0x00000800 /* H: W bit */
+
+/* TODO: Add large page lowmem mapping support */
+#define _PMD_PRESENT 0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD (~PAGE_MASK)
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK 0xffffffff00000000ULL
+
+#elif defined(CONFIG_FSL_BOOKE)
+/*
+ MMU Assist Register 3:
+
+ 32 33 34 35 36 ... 50 51 52 53 54 55 56 57 58 59 60 61 62 63
+ RPN...................... 0 0 U0 U1 U2 U3 UX SX UW SW UR SR
+
+ - PRESENT *must* be in the bottom three bits because swap cache
+ entries use the top 29 bits.
+
+ - FILE *must* be in the bottom three bits because swap cache
+ entries use the top 29 bits.
+*/
+
+/* Definitions for FSL Book-E Cores */
+#define _PAGE_PRESENT 0x00001 /* S: PTE contains a translation */
+#define _PAGE_USER 0x00002 /* S: User page (maps to UR) */
+#define _PAGE_FILE 0x00002 /* S: when !present: nonlinear file mapping */
+#define _PAGE_ACCESSED 0x00004 /* S: Page referenced */
+#define _PAGE_HWWRITE 0x00008 /* H: Dirty & RW, set in exception */
+#define _PAGE_RW 0x00010 /* S: Write permission */
+#define _PAGE_HWEXEC 0x00020 /* H: UX permission */
+
+#define _PAGE_ENDIAN 0x00040 /* H: E bit */
+#define _PAGE_GUARDED 0x00080 /* H: G bit */
+#define _PAGE_COHERENT 0x00100 /* H: M bit */
+#define _PAGE_NO_CACHE 0x00200 /* H: I bit */
+#define _PAGE_WRITETHRU 0x00400 /* H: W bit */
+
+#ifdef CONFIG_PTE_64BIT
+#define _PAGE_DIRTY 0x08000 /* S: Page dirty */
+
+/* ERPN in a PTE never gets cleared, ignore it */
+#define _PTE_NONE_MASK 0xffffffffffff0000ULL
+#else
+#define _PAGE_DIRTY 0x00800 /* S: Page dirty */
+#endif
+
+#define _PMD_PRESENT 0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD (~PAGE_MASK)
+
+#elif defined(CONFIG_8xx)
+/* Definitions for 8xx embedded chips. */
+#define _PAGE_PRESENT 0x0001 /* Page is valid */
+#define _PAGE_FILE 0x0002 /* when !present: nonlinear file mapping */
+#define _PAGE_NO_CACHE 0x0002 /* I: cache inhibit */
+#define _PAGE_SHARED 0x0004 /* No ASID (context) compare */
+
+/* These five software bits must be masked out when the entry is loaded
+ * into the TLB.
+ */
+#define _PAGE_EXEC 0x0008 /* software: i-cache coherency required */
+#define _PAGE_GUARDED 0x0010 /* software: guarded access */
+#define _PAGE_DIRTY 0x0020 /* software: page changed */
+#define _PAGE_RW 0x0040 /* software: user write access allowed */
+#define _PAGE_ACCESSED 0x0080 /* software: page referenced */
+
+/* Setting any bits in the nibble with the follow two controls will
+ * require a TLB exception handler change. It is assumed unused bits
+ * are always zero.
+ */
+#define _PAGE_HWWRITE 0x0100 /* h/w write enable: never set in Linux PTE */
+#define _PAGE_USER 0x0800 /* One of the PP bits, the other is USER&~RW */
+
+#define _PMD_PRESENT 0x0001
+#define _PMD_BAD 0x0ff0
+#define _PMD_PAGE_MASK 0x000c
+#define _PMD_PAGE_8M 0x000c
+
+/*
+ * The 8xx TLB miss handler allegedly sets _PAGE_ACCESSED in the PTE
+ * for an address even if _PAGE_PRESENT is not set, as a performance
+ * optimization. This is a bug if you ever want to use swap unless
+ * _PAGE_ACCESSED is 2, which it isn't, or unless you have 8xx-specific
+ * definitions for __swp_entry etc. below, which would be gross.
+ * -- paulus
+ */
+#define _PTE_NONE_MASK _PAGE_ACCESSED
+
+#else /* CONFIG_6xx */
+/* Definitions for 60x, 740/750, etc. */
+#define _PAGE_PRESENT 0x001 /* software: pte contains a translation */
+#define _PAGE_HASHPTE 0x002 /* hash_page has made an HPTE for this pte */
+#define _PAGE_FILE 0x004 /* when !present: nonlinear file mapping */
+#define _PAGE_USER 0x004 /* usermode access allowed */
+#define _PAGE_GUARDED 0x008 /* G: prohibit speculative access */
+#define _PAGE_COHERENT 0x010 /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE 0x020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU 0x040 /* W: cache write-through */
+#define _PAGE_DIRTY 0x080 /* C: page changed */
+#define _PAGE_ACCESSED 0x100 /* R: page referenced */
+#define _PAGE_EXEC 0x200 /* software: i-cache coherency required */
+#define _PAGE_RW 0x400 /* software: user write access allowed */
+
+#define _PTE_NONE_MASK _PAGE_HASHPTE
+
+#define _PMD_PRESENT 0
+#define _PMD_PRESENT_MASK (PAGE_MASK)
+#define _PMD_BAD (~PAGE_MASK)
+#endif
+
+/*
+ * Some bits are only used on some cpu families...
+ */
+#ifndef _PAGE_HASHPTE
+#define _PAGE_HASHPTE 0
+#endif
+#ifndef _PTE_NONE_MASK
+#define _PTE_NONE_MASK 0
+#endif
+#ifndef _PAGE_SHARED
+#define _PAGE_SHARED 0
+#endif
+#ifndef _PAGE_HWWRITE
+#define _PAGE_HWWRITE 0
+#endif
+#ifndef _PAGE_HWEXEC
+#define _PAGE_HWEXEC 0
+#endif
+#ifndef _PAGE_EXEC
+#define _PAGE_EXEC 0
+#endif
+#ifndef _PMD_PRESENT_MASK
+#define _PMD_PRESENT_MASK _PMD_PRESENT
+#endif
+#ifndef _PMD_SIZE
+#define _PMD_SIZE 0
+#define PMD_PAGE_SIZE(pmd) bad_call_to_PMD_PAGE_SIZE()
+#endif
+
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+/*
+ * Note: the _PAGE_COHERENT bit automatically gets set in the hardware
+ * PTE if CONFIG_SMP is defined (hash_page does this); there is no need
+ * to have it in the Linux PTE, and in fact the bit could be reused for
+ * another purpose. -- paulus.
+ */
+
+#ifdef CONFIG_44x
+#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_GUARDED)
+#else
+#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED)
+#endif
+#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE)
+#define _PAGE_KERNEL (_PAGE_BASE | _PAGE_SHARED | _PAGE_WRENABLE)
+
+#ifdef CONFIG_PPC_STD_MMU
+/* On standard PPC MMU, no user access implies kernel read/write access,
+ * so to write-protect kernel memory we must turn on user access */
+#define _PAGE_KERNEL_RO (_PAGE_BASE | _PAGE_SHARED | _PAGE_USER)
+#else
+#define _PAGE_KERNEL_RO (_PAGE_BASE | _PAGE_SHARED)
+#endif
+
+#define _PAGE_IO (_PAGE_KERNEL | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define _PAGE_RAM (_PAGE_KERNEL | _PAGE_HWEXEC)
+
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) || defined(CONFIG_BDI_SWITCH)
+/* We want the debuggers to be able to set breakpoints anywhere, so
+ * don't write protect the kernel text */
+#define _PAGE_RAM_TEXT _PAGE_RAM
+#else
+#define _PAGE_RAM_TEXT (_PAGE_KERNEL_RO | _PAGE_HWEXEC)
+#endif
+
+#define PAGE_NONE __pgprot(_PAGE_BASE)
+#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW)
+#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_RW | _PAGE_EXEC)
+#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+
+#define PAGE_KERNEL __pgprot(_PAGE_RAM)
+#define PAGE_KERNEL_NOCACHE __pgprot(_PAGE_IO)
+
+/*
+ * The PowerPC can only do execute protection on a segment (256MB) basis,
+ * not on a page basis. So we consider execute permission the same as read.
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY_X
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY_X
+#define __P100 PAGE_READONLY
+#define __P101 PAGE_READONLY_X
+#define __P110 PAGE_COPY
+#define __P111 PAGE_COPY_X
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY_X
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED_X
+#define __S100 PAGE_READONLY
+#define __S101 PAGE_READONLY_X
+#define __S110 PAGE_SHARED
+#define __S111 PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+/* Make sure we get a link error if PMD_PAGE_SIZE is ever called on a
+ * kernel without large page PMD support */
+extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
+
+/*
+ * Conversions between PTE values and page frame numbers.
+ */
+
+/* in some case we want to additionaly adjust where the pfn is in the pte to
+ * allow room for more flags */
+#if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_PTE_64BIT)
+#define PFN_SHIFT_OFFSET (PAGE_SHIFT + 8)
+#else
+#define PFN_SHIFT_OFFSET (PAGE_SHIFT)
+#endif
+
+#define pte_pfn(x) (pte_val(x) >> PFN_SHIFT_OFFSET)
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+#define pfn_pte(pfn, prot) __pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) |\
+ pgprot_val(prot))
+#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[1024];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#endif /* __ASSEMBLY__ */
+
+#define pte_none(pte) ((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
+#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
+#define pte_clear(mm,addr,ptep) do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
+
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
+#define pmd_present(pmd) (pmd_val(pmd) & _PMD_PRESENT_MASK)
+#define pmd_clear(pmdp) do { pmd_val(*(pmdp)) = 0; } while (0)
+
+#ifndef __ASSEMBLY__
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; }
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+static inline pte_t pte_rdprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_exprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_EXEC; return pte; }
+static inline pte_t pte_mkclean(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
+static inline pte_t pte_mkold(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+
+static inline pte_t pte_mkread(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) {
+ pte_val(pte) |= _PAGE_RW; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) {
+ pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) {
+ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+ return pte;
+}
+
+/*
+ * When flushing the tlb entry for a page, we also need to flush the hash
+ * table entry. flush_hash_pages is assembler (for speed) in hashtable.S.
+ */
+extern int flush_hash_pages(unsigned context, unsigned long va,
+ unsigned long pmdval, int count);
+
+/* Add an HPTE to the hash table */
+extern void add_hash_page(unsigned context, unsigned long va,
+ unsigned long pmdval);
+
+/*
+ * Atomic PTE updates.
+ *
+ * pte_update clears and sets bit atomically, and returns
+ * the old pte value. In the 64-bit PTE case we lock around the
+ * low PTE word since we expect ALL flag bits to be there
+ */
+#ifndef CONFIG_PTE_64BIT
+static inline unsigned long pte_update(pte_t *p, unsigned long clr,
+ unsigned long set)
+{
+ unsigned long old, tmp;
+
+ __asm__ __volatile__("\
+1: lwarx %0,0,%3\n\
+ andc %1,%0,%4\n\
+ or %1,%1,%5\n"
+ PPC405_ERR77(0,%3)
+" stwcx. %1,0,%3\n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*p)
+ : "r" (p), "r" (clr), "r" (set), "m" (*p)
+ : "cc" );
+ return old;
+}
+#else
+static inline unsigned long long pte_update(pte_t *p, unsigned long clr,
+ unsigned long set)
+{
+ unsigned long long old;
+ unsigned long tmp;
+
+ __asm__ __volatile__("\
+1: lwarx %L0,0,%4\n\
+ lwzx %0,0,%3\n\
+ andc %1,%L0,%5\n\
+ or %1,%1,%6\n"
+ PPC405_ERR77(0,%3)
+" stwcx. %1,0,%4\n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*p)
+ : "r" (p), "r" ((unsigned long)(p) + 4), "r" (clr), "r" (set), "m" (*p)
+ : "cc" );
+ return old;
+}
+#endif
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ * On machines which use an MMU hash table we avoid changing the
+ * _PAGE_HASHPTE bit.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+#if _PAGE_HASHPTE != 0
+ pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
+#else
+ *ptep = pte;
+#endif
+}
+
+/*
+ * 2.6 calles this without flushing the TLB entry, this is wrong
+ * for our hash-based implementation, we fix that up here
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int __ptep_test_and_clear_young(unsigned int context, unsigned long addr, pte_t *ptep)
+{
+ unsigned long old;
+ old = pte_update(ptep, _PAGE_ACCESSED, 0);
+#if _PAGE_HASHPTE != 0
+ if (old & _PAGE_HASHPTE) {
+ unsigned long ptephys = __pa(ptep) & PAGE_MASK;
+ flush_hash_pages(context, addr, ptephys, 1);
+ }
+#endif
+ return (old & _PAGE_ACCESSED) != 0;
+}
+#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
+ __ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ return (pte_update(ptep, (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
+}
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ return __pte(pte_update(ptep, ~_PAGE_HASHPTE, 0));
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_update(ptep, (_PAGE_RW | _PAGE_HWWRITE), 0);
+}
+
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+{
+ unsigned long bits = pte_val(entry) &
+ (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW);
+ pte_update(ptep, 0, bits);
+}
+
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+ do { \
+ __ptep_set_access_flags(__ptep, __entry, __dirty); \
+ flush_tlb_page_nohash(__vma, __address); \
+ } while(0)
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HASHPTE) == 0)
+
+/*
+ * Note that on Book E processors, the pmd contains the kernel virtual
+ * (lowmem) address of the pte page. The physical address is less useful
+ * because everything runs with translation enabled (even the TLB miss
+ * handler). On everything else the pmd contains the physical address
+ * of the pte page. -- paulus
+ */
+#ifndef CONFIG_BOOKE
+#define pmd_page_vaddr(pmd) \
+ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) \
+ (mem_map + (pmd_val(pmd) >> PAGE_SHIFT))
+#else
+#define pmd_page_vaddr(pmd) \
+ ((unsigned long) (pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) \
+ (mem_map + (__pa(pmd_val(pmd)) >> PAGE_SHIFT))
+#endif
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+
+/* Find an entry in the third-level page table.. */
+#define pte_index(address) \
+ (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir, addr) \
+ ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(addr))
+#define pte_offset_map(dir, addr) \
+ ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE0) + pte_index(addr))
+#define pte_offset_map_nested(dir, addr) \
+ ((pte_t *) kmap_atomic(pmd_page(*(dir)), KM_PTE1) + pte_index(addr))
+
+#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+extern void paging_init(void);
+
+/*
+ * Encode and decode a swap entry.
+ * Note that the bits we use in a PTE for representing a swap entry
+ * must not include the _PAGE_PRESENT bit, the _PAGE_FILE bit, or the
+ *_PAGE_HASHPTE bit (if used). -- paulus
+ */
+#define __swp_type(entry) ((entry).val & 0x1f)
+#define __swp_offset(entry) ((entry).val >> 5)
+#define __swp_entry(type, offset) ((swp_entry_t) { (type) | ((offset) << 5) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 3 })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val << 3 })
+
+/* Encode and decode a nonlinear file mapping entry */
+#define PTE_FILE_MAX_BITS 29
+#define pte_to_pgoff(pte) (pte_val(pte) >> 3)
+#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE })
+
+/* CONFIG_APUS */
+/* For virtual address to physical address conversion */
+extern void cache_clear(__u32 addr, int length);
+extern void cache_push(__u32 addr, int length);
+extern int mm_end_of_chunk (unsigned long addr, int len);
+extern unsigned long iopa(unsigned long addr);
+extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
+
+/* Values for nocacheflag and cmode */
+/* These are not used by the APUS kernel_map, but prevents
+ compilation errors. */
+#define KERNELMAP_FULL_CACHING 0
+#define KERNELMAP_NOCACHE_SER 1
+#define KERNELMAP_NOCACHE_NONSER 2
+#define KERNELMAP_NO_COPYBACK 3
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
+ int nocacheflag, unsigned long *memavailp );
+
+/*
+ * Set cache mode of (kernel space) address range.
+ */
+extern void kernel_set_cachemode (unsigned long address, unsigned long size,
+ unsigned int cmode);
+
+/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+#define kern_addr_valid(addr) (1)
+
+#ifdef CONFIG_PHYS_64BIT
+extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long paddr, unsigned long size, pgprot_t prot);
+
+static inline int io_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long vaddr,
+ unsigned long pfn,
+ unsigned long size,
+ pgprot_t prot)
+{
+ phys_addr_t paddr64 = fixup_bigphys_addr(pfn << PAGE_SHIFT, size);
+ return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot);
+}
+#else
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+#endif
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init() do { } while (0)
+
+extern int get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep,
+ pmd_t **pmdp);
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_PGTABLE_PPC32_H */
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h
new file mode 100644
index 00000000000..704c4e669fe
--- /dev/null
+++ b/include/asm-powerpc/pgtable-ppc64.h
@@ -0,0 +1,492 @@
+#ifndef _ASM_POWERPC_PGTABLE_PPC64_H_
+#define _ASM_POWERPC_PGTABLE_PPC64_H_
+/*
+ * This file contains the functions and defines necessary to modify and use
+ * the ppc64 hashed page table.
+ */
+
+#ifndef __ASSEMBLY__
+#include <linux/stddef.h>
+#include <asm/processor.h> /* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+struct mm_struct;
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_PPC_64K_PAGES
+#include <asm/pgtable-64k.h>
+#else
+#include <asm/pgtable-4k.h>
+#endif
+
+#define FIRST_USER_ADDRESS 0
+
+/*
+ * Size of EA range mapped by our pagetables.
+ */
+#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
+ PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
+#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
+
+#if TASK_SIZE_USER64 > PGTABLE_RANGE
+#error TASK_SIZE_USER64 exceeds pagetable range
+#endif
+
+#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
+#error TASK_SIZE_USER64 exceeds user VSID range
+#endif
+
+/*
+ * Define the address range of the vmalloc VM area.
+ */
+#define VMALLOC_START ASM_CONST(0xD000000000000000)
+#define VMALLOC_SIZE ASM_CONST(0x80000000000)
+#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
+
+/*
+ * Define the address range of the imalloc VM area.
+ */
+#define PHBS_IO_BASE VMALLOC_END
+#define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
+#define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE)
+
+/*
+ * Region IDs
+ */
+#define REGION_SHIFT 60UL
+#define REGION_MASK (0xfUL << REGION_SHIFT)
+#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
+
+#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
+#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
+#define USER_REGION_ID (0UL)
+
+/*
+ * Common bits in a linux-style PTE. These match the bits in the
+ * (hardware-defined) PowerPC PTE as closely as possible. Additional
+ * bits may be defined in pgtable-*.h
+ */
+#define _PAGE_PRESENT 0x0001 /* software: pte contains a translation */
+#define _PAGE_USER 0x0002 /* matches one of the PP bits */
+#define _PAGE_FILE 0x0002 /* (!present only) software: pte holds file offset */
+#define _PAGE_EXEC 0x0004 /* No execute on POWER4 and newer (we invert) */
+#define _PAGE_GUARDED 0x0008
+#define _PAGE_COHERENT 0x0010 /* M: enforce memory coherence (SMP systems) */
+#define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */
+#define _PAGE_WRITETHRU 0x0040 /* W: cache write-through */
+#define _PAGE_DIRTY 0x0080 /* C: page changed */
+#define _PAGE_ACCESSED 0x0100 /* R: page referenced */
+#define _PAGE_RW 0x0200 /* software: user write access allowed */
+#define _PAGE_HASHPTE 0x0400 /* software: pte has an associated HPTE */
+#define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */
+
+#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
+
+#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY)
+
+/* __pgprot defined in asm-powerpc/page.h */
+#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+
+#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
+#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
+#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
+#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_WRENABLE)
+#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
+ _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
+
+#define PAGE_AGP __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
+#define HAVE_PAGE_AGP
+
+/* PTEIDX nibble */
+#define _PTEIDX_SECONDARY 0x8
+#define _PTEIDX_GROUP_IX 0x7
+
+
+/*
+ * POWER4 and newer have per page execute protection, older chips can only
+ * do this on a segment (256MB) basis.
+ *
+ * Also, write permissions imply read permissions.
+ * This is the closest we can get..
+ *
+ * Note due to the way vm flags are laid out, the bits are XWR
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY_X
+#define __P101 PAGE_READONLY_X
+#define __P110 PAGE_COPY_X
+#define __P111 PAGE_COPY_X
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY_X
+#define __S101 PAGE_READONLY_X
+#define __S110 PAGE_SHARED_X
+#define __S111 PAGE_SHARED_X
+
+#ifndef __ASSEMBLY__
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+#endif /* __ASSEMBLY__ */
+
+#ifdef CONFIG_HUGETLB_PAGE
+
+#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+
+#endif
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ *
+ * mk_pte takes a (struct page *) as input
+ */
+#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
+
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+ pte_t pte;
+
+
+ pte_val(pte) = (pfn << PTE_RPN_SHIFT) | pgprot_val(pgprot);
+ return pte;
+}
+
+#define pte_modify(_pte, newprot) \
+ (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
+
+#define pte_none(pte) ((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
+#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
+
+/* pte_clear moved to later in this file */
+
+#define pte_pfn(x) ((unsigned long)((pte_val(x)>>PTE_RPN_SHIFT)))
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
+#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
+
+#define pmd_set(pmdp, pmdval) (pmd_val(*(pmdp)) = (pmdval))
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_bad(pmd) (!is_kernel_addr(pmd_val(pmd)) \
+ || (pmd_val(pmd) & PMD_BAD_BITS))
+#define pmd_present(pmd) (pmd_val(pmd) != 0)
+#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
+#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
+#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd))
+
+#define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
+#define pud_none(pud) (!pud_val(pud))
+#define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \
+ || (pud_val(pud) & PUD_BAD_BITS))
+#define pud_present(pud) (pud_val(pud) != 0)
+#define pud_clear(pudp) (pud_val(*(pudp)) = 0)
+#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
+#define pud_page(pud) virt_to_page(pud_page_vaddr(pud))
+
+#define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
+
+/*
+ * Find an entry in a page-table-directory. We combine the address region
+ * (the high order N bits) and the pgd portion of the address.
+ */
+/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
+#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
+
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+
+#define pmd_offset(pudp,addr) \
+ (((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+
+#define pte_offset_kernel(dir,addr) \
+ (((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+
+#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
+#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
+#define pte_unmap(pte) do { } while(0)
+#define pte_unmap_nested(pte) do { } while(0)
+
+/* to find an entry in a kernel page-table-directory */
+/* This now only contains the vmalloc pages */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER;}
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
+static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC;}
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
+static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
+
+static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
+static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
+
+static inline pte_t pte_rdprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_exprotect(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_EXEC; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_RW); return pte; }
+static inline pte_t pte_mkclean(pte_t pte) {
+ pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
+static inline pte_t pte_mkold(pte_t pte) {
+ pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkread(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkexec(pte_t pte) {
+ pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) {
+ pte_val(pte) |= _PAGE_RW; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) {
+ pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) {
+ pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkhuge(pte_t pte) {
+ return pte; }
+
+/* Atomic PTE updates */
+static inline unsigned long pte_update(struct mm_struct *mm,
+ unsigned long addr,
+ pte_t *ptep, unsigned long clr,
+ int huge)
+{
+ unsigned long old, tmp;
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%3 # pte_update\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ andc %1,%0,%4 \n\
+ stdcx. %1,0,%3 \n\
+ bne- 1b"
+ : "=&r" (old), "=&r" (tmp), "=m" (*ptep)
+ : "r" (ptep), "r" (clr), "m" (*ptep), "i" (_PAGE_BUSY)
+ : "cc" );
+
+ if (old & _PAGE_HASHPTE)
+ hpte_need_flush(mm, addr, ptep, old, huge);
+ return old;
+}
+
+static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ unsigned long old;
+
+ if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
+ return 0;
+ old = pte_update(mm, addr, ptep, _PAGE_ACCESSED, 0);
+ return (old & _PAGE_ACCESSED) != 0;
+}
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
+({ \
+ int __r; \
+ __r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
+ __r; \
+})
+
+/*
+ * On RW/DIRTY bit transitions we can avoid flushing the hpte. For the
+ * moment we always flush but we need to fix hpte_update and test if the
+ * optimisation is worth it.
+ */
+static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ unsigned long old;
+
+ if ((pte_val(*ptep) & _PAGE_DIRTY) == 0)
+ return 0;
+ old = pte_update(mm, addr, ptep, _PAGE_DIRTY, 0);
+ return (old & _PAGE_DIRTY) != 0;
+}
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define ptep_test_and_clear_dirty(__vma, __addr, __ptep) \
+({ \
+ int __r; \
+ __r = __ptep_test_and_clear_dirty((__vma)->vm_mm, __addr, __ptep); \
+ __r; \
+})
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ unsigned long old;
+
+ if ((pte_val(*ptep) & _PAGE_RW) == 0)
+ return;
+ old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
+}
+
+/*
+ * We currently remove entries from the hashtable regardless of whether
+ * the entry was young or dirty. The generic routines only flush if the
+ * entry was young or dirty which is not good enough.
+ *
+ * We should be more intelligent about this but for the moment we override
+ * these functions and force a tlb flush unconditionally
+ */
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+#define ptep_clear_flush_young(__vma, __address, __ptep) \
+({ \
+ int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
+ __ptep); \
+ __young; \
+})
+
+#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
+#define ptep_clear_flush_dirty(__vma, __address, __ptep) \
+({ \
+ int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
+ __ptep); \
+ __dirty; \
+})
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ unsigned long old = pte_update(mm, addr, ptep, ~0UL, 0);
+ return __pte(old);
+}
+
+static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t * ptep)
+{
+ pte_update(mm, addr, ptep, ~0UL, 0);
+}
+
+/*
+ * set_pte stores a linux PTE into the linux page table.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ if (pte_present(*ptep))
+ pte_clear(mm, addr, ptep);
+ pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
+ *ptep = pte;
+}
+
+/* Set the dirty and/or accessed bits atomically in a linux PTE, this
+ * function doesn't need to flush the hash entry
+ */
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
+{
+ unsigned long bits = pte_val(entry) &
+ (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
+ unsigned long old, tmp;
+
+ __asm__ __volatile__(
+ "1: ldarx %0,0,%4\n\
+ andi. %1,%0,%6\n\
+ bne- 1b \n\
+ or %0,%3,%0\n\
+ stdcx. %0,0,%4\n\
+ bne- 1b"
+ :"=&r" (old), "=&r" (tmp), "=m" (*ptep)
+ :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
+ :"cc");
+}
+#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+ do { \
+ __ptep_set_access_flags(__ptep, __entry, __dirty); \
+ flush_tlb_page_nohash(__vma, __address); \
+ } while(0)
+
+/*
+ * Macro to mark a page protection value as "uncacheable".
+ */
+#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
+
+struct file;
+extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
+ unsigned long size, pgprot_t vma_prot);
+#define __HAVE_PHYS_MEM_ACCESS_PROT
+
+#define __HAVE_ARCH_PTE_SAME
+#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+extern pgd_t swapper_pg_dir[];
+
+extern void paging_init(void);
+
+/* Encode and de-code a swap entry */
+#define __swp_type(entry) (((entry).val >> 1) & 0x3f)
+#define __swp_offset(entry) ((entry).val >> 8)
+#define __swp_entry(type, offset) ((swp_entry_t){((type)<< 1)|((offset)<<8)})
+#define __pte_to_swp_entry(pte) ((swp_entry_t){pte_val(pte) >> PTE_RPN_SHIFT})
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val << PTE_RPN_SHIFT })
+#define pte_to_pgoff(pte) (pte_val(pte) >> PTE_RPN_SHIFT)
+#define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
+#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT)
+
+/*
+ * kern_addr_valid is intended to indicate whether an address is a valid
+ * kernel address. Most 32-bit archs define it as always true (like this)
+ * but most 64-bit archs actually perform a test. What should we do here?
+ * The only use is in fs/ncpfs/dir.c
+ */
+#define kern_addr_valid(addr) (1)
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+void pgtable_cache_init(void);
+
+/*
+ * find_linux_pte returns the address of a linux pte for a given
+ * effective address and directory. If not found, it returns zero.
+ */static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
+{
+ pgd_t *pg;
+ pud_t *pu;
+ pmd_t *pm;
+ pte_t *pt = NULL;
+
+ pg = pgdir + pgd_index(ea);
+ if (!pgd_none(*pg)) {
+ pu = pud_offset(pg, ea);
+ if (!pud_none(*pu)) {
+ pm = pmd_offset(pu, ea);
+ if (pmd_present(*pm))
+ pt = pte_offset_kernel(pm, ea);
+ }
+ }
+ return pt;
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 10f52743f4f..78bf4ae712a 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -2,530 +2,15 @@
#define _ASM_POWERPC_PGTABLE_H
#ifdef __KERNEL__
-#ifndef CONFIG_PPC64
-#include <asm-ppc/pgtable.h>
+#if defined(CONFIG_PPC64)
+# include <asm/pgtable-ppc64.h>
#else
-
-/*
- * This file contains the functions and defines necessary to modify and use
- * the ppc64 hashed page table.
- */
-
-#ifndef __ASSEMBLY__
-#include <linux/stddef.h>
-#include <asm/processor.h> /* For TASK_SIZE */
-#include <asm/mmu.h>
-#include <asm/page.h>
-#include <asm/tlbflush.h>
-struct mm_struct;
-#endif /* __ASSEMBLY__ */
-
-#ifdef CONFIG_PPC_64K_PAGES
-#include <asm/pgtable-64k.h>
-#else
-#include <asm/pgtable-4k.h>
-#endif
-
-#define FIRST_USER_ADDRESS 0
-
-/*
- * Size of EA range mapped by our pagetables.
- */
-#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
- PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
-#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
-
-#if TASK_SIZE_USER64 > PGTABLE_RANGE
-#error TASK_SIZE_USER64 exceeds pagetable range
-#endif
-
-#if TASK_SIZE_USER64 > (1UL << (USER_ESID_BITS + SID_SHIFT))
-#error TASK_SIZE_USER64 exceeds user VSID range
-#endif
-
-/*
- * Define the address range of the vmalloc VM area.
- */
-#define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE ASM_CONST(0x80000000000)
-#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
-
-/*
- * Define the address range of the imalloc VM area.
- */
-#define PHBS_IO_BASE VMALLOC_END
-#define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
-#define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE)
-
-/*
- * Region IDs
- */
-#define REGION_SHIFT 60UL
-#define REGION_MASK (0xfUL << REGION_SHIFT)
-#define REGION_ID(ea) (((unsigned long)(ea)) >> REGION_SHIFT)
-
-#define VMALLOC_REGION_ID (REGION_ID(VMALLOC_START))
-#define KERNEL_REGION_ID (REGION_ID(PAGE_OFFSET))
-#define USER_REGION_ID (0UL)
-
-/*
- * Common bits in a linux-style PTE. These match the bits in the
- * (hardware-defined) PowerPC PTE as closely as possible. Additional
- * bits may be defined in pgtable-*.h
- */
-#define _PAGE_PRESENT 0x0001 /* software: pte contains a translation */
-#define _PAGE_USER 0x0002 /* matches one of the PP bits */
-#define _PAGE_FILE 0x0002 /* (!present only) software: pte holds file offset */
-#define _PAGE_EXEC 0x0004 /* No execute on POWER4 and newer (we invert) */
-#define _PAGE_GUARDED 0x0008
-#define _PAGE_COHERENT 0x0010 /* M: enforce memory coherence (SMP systems) */
-#define _PAGE_NO_CACHE 0x0020 /* I: cache inhibit */
-#define _PAGE_WRITETHRU 0x0040 /* W: cache write-through */
-#define _PAGE_DIRTY 0x0080 /* C: page changed */
-#define _PAGE_ACCESSED 0x0100 /* R: page referenced */
-#define _PAGE_RW 0x0200 /* software: user write access allowed */
-#define _PAGE_HASHPTE 0x0400 /* software: pte has an associated HPTE */
-#define _PAGE_BUSY 0x0800 /* software: PTE & hash are busy */
-
-#define _PAGE_BASE (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_COHERENT)
-
-#define _PAGE_WRENABLE (_PAGE_RW | _PAGE_DIRTY)
-
-/* __pgprot defined in asm-powerpc/page.h */
-#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-
-#define PAGE_SHARED __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER)
-#define PAGE_SHARED_X __pgprot(_PAGE_BASE | _PAGE_RW | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_COPY __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_COPY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_READONLY __pgprot(_PAGE_BASE | _PAGE_USER)
-#define PAGE_READONLY_X __pgprot(_PAGE_BASE | _PAGE_USER | _PAGE_EXEC)
-#define PAGE_KERNEL __pgprot(_PAGE_BASE | _PAGE_WRENABLE)
-#define PAGE_KERNEL_CI __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
- _PAGE_WRENABLE | _PAGE_NO_CACHE | _PAGE_GUARDED)
-#define PAGE_KERNEL_EXEC __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_EXEC)
-
-#define PAGE_AGP __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
-#define HAVE_PAGE_AGP
-
-/* PTEIDX nibble */
-#define _PTEIDX_SECONDARY 0x8
-#define _PTEIDX_GROUP_IX 0x7
-
-
-/*
- * POWER4 and newer have per page execute protection, older chips can only
- * do this on a segment (256MB) basis.
- *
- * Also, write permissions imply read permissions.
- * This is the closest we can get..
- *
- * Note due to the way vm flags are laid out, the bits are XWR
- */
-#define __P000 PAGE_NONE
-#define __P001 PAGE_READONLY
-#define __P010 PAGE_COPY
-#define __P011 PAGE_COPY
-#define __P100 PAGE_READONLY_X
-#define __P101 PAGE_READONLY_X
-#define __P110 PAGE_COPY_X
-#define __P111 PAGE_COPY_X
-
-#define __S000 PAGE_NONE
-#define __S001 PAGE_READONLY
-#define __S010 PAGE_SHARED
-#define __S011 PAGE_SHARED
-#define __S100 PAGE_READONLY_X
-#define __S101 PAGE_READONLY_X
-#define __S110 PAGE_SHARED_X
-#define __S111 PAGE_SHARED_X
-
-#ifndef __ASSEMBLY__
-
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
-#endif /* __ASSEMBLY__ */
-
-#ifdef CONFIG_HUGETLB_PAGE
-
-#define HAVE_ARCH_UNMAPPED_AREA
-#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
-
+# include <asm/pgtable-ppc32.h>
#endif
#ifndef __ASSEMBLY__
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- *
- * mk_pte takes a (struct page *) as input
- */
-#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
-
-static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
-{
- pte_t pte;
-
-
- pte_val(pte) = (pfn << PTE_RPN_SHIFT) | pgprot_val(pgprot);
- return pte;
-}
-
-#define pte_modify(_pte, newprot) \
- (__pte((pte_val(_pte) & _PAGE_CHG_MASK) | pgprot_val(newprot)))
-
-#define pte_none(pte) ((pte_val(pte) & ~_PAGE_HPTEFLAGS) == 0)
-#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
-
-/* pte_clear moved to later in this file */
-
-#define pte_pfn(x) ((unsigned long)((pte_val(x)>>PTE_RPN_SHIFT)))
-#define pte_page(x) pfn_to_page(pte_pfn(x))
-
-#define PMD_BAD_BITS (PTE_TABLE_SIZE-1)
-#define PUD_BAD_BITS (PMD_TABLE_SIZE-1)
-
-#define pmd_set(pmdp, pmdval) (pmd_val(*(pmdp)) = (pmdval))
-#define pmd_none(pmd) (!pmd_val(pmd))
-#define pmd_bad(pmd) (!is_kernel_addr(pmd_val(pmd)) \
- || (pmd_val(pmd) & PMD_BAD_BITS))
-#define pmd_present(pmd) (pmd_val(pmd) != 0)
-#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0)
-#define pmd_page_vaddr(pmd) (pmd_val(pmd) & ~PMD_MASKED_BITS)
-#define pmd_page(pmd) virt_to_page(pmd_page_vaddr(pmd))
-
-#define pud_set(pudp, pudval) (pud_val(*(pudp)) = (pudval))
-#define pud_none(pud) (!pud_val(pud))
-#define pud_bad(pud) (!is_kernel_addr(pud_val(pud)) \
- || (pud_val(pud) & PUD_BAD_BITS))
-#define pud_present(pud) (pud_val(pud) != 0)
-#define pud_clear(pudp) (pud_val(*(pudp)) = 0)
-#define pud_page_vaddr(pud) (pud_val(pud) & ~PUD_MASKED_BITS)
-#define pud_page(pud) virt_to_page(pud_page_vaddr(pud))
-
-#define pgd_set(pgdp, pudp) ({pgd_val(*(pgdp)) = (unsigned long)(pudp);})
-
-/*
- * Find an entry in a page-table-directory. We combine the address region
- * (the high order N bits) and the pgd portion of the address.
- */
-/* to avoid overflow in free_pgtables we don't use PTRS_PER_PGD here */
-#define pgd_index(address) (((address) >> (PGDIR_SHIFT)) & 0x1ff)
-
-#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
-
-#define pmd_offset(pudp,addr) \
- (((pmd_t *) pud_page_vaddr(*(pudp))) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
-
-#define pte_offset_kernel(dir,addr) \
- (((pte_t *) pmd_page_vaddr(*(dir))) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
-
-#define pte_offset_map(dir,addr) pte_offset_kernel((dir), (addr))
-#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir), (addr))
-#define pte_unmap(pte) do { } while(0)
-#define pte_unmap_nested(pte) do { } while(0)
-
-/* to find an entry in a kernel page-table-directory */
-/* This now only contains the vmalloc pages */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER;}
-static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC;}
-static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY;}
-static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED;}
-static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
-
-static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
-static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
-
-static inline pte_t pte_rdprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_USER; return pte; }
-static inline pte_t pte_exprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_EXEC; return pte; }
-static inline pte_t pte_wrprotect(pte_t pte) {
- pte_val(pte) &= ~(_PAGE_RW); return pte; }
-static inline pte_t pte_mkclean(pte_t pte) {
- pte_val(pte) &= ~(_PAGE_DIRTY); return pte; }
-static inline pte_t pte_mkold(pte_t pte) {
- pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkread(pte_t pte) {
- pte_val(pte) |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) {
- pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
-static inline pte_t pte_mkwrite(pte_t pte) {
- pte_val(pte) |= _PAGE_RW; return pte; }
-static inline pte_t pte_mkdirty(pte_t pte) {
- pte_val(pte) |= _PAGE_DIRTY; return pte; }
-static inline pte_t pte_mkyoung(pte_t pte) {
- pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkhuge(pte_t pte) {
- return pte; }
-
-/* Atomic PTE updates */
-static inline unsigned long pte_update(pte_t *p, unsigned long clr)
-{
- unsigned long old, tmp;
-
- __asm__ __volatile__(
- "1: ldarx %0,0,%3 # pte_update\n\
- andi. %1,%0,%6\n\
- bne- 1b \n\
- andc %1,%0,%4 \n\
- stdcx. %1,0,%3 \n\
- bne- 1b"
- : "=&r" (old), "=&r" (tmp), "=m" (*p)
- : "r" (p), "r" (clr), "m" (*p), "i" (_PAGE_BUSY)
- : "cc" );
- return old;
-}
-
-/* PTE updating functions, this function puts the PTE in the
- * batch, doesn't actually triggers the hash flush immediately,
- * you need to call flush_tlb_pending() to do that.
- * Pass -1 for "normal" size (4K or 64K)
- */
-extern void hpte_update(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, unsigned long pte, int huge);
-
-static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- unsigned long old;
-
- if ((pte_val(*ptep) & (_PAGE_ACCESSED | _PAGE_HASHPTE)) == 0)
- return 0;
- old = pte_update(ptep, _PAGE_ACCESSED);
- if (old & _PAGE_HASHPTE) {
- hpte_update(mm, addr, ptep, old, 0);
- flush_tlb_pending();
- }
- return (old & _PAGE_ACCESSED) != 0;
-}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
-({ \
- int __r; \
- __r = __ptep_test_and_clear_young((__vma)->vm_mm, __addr, __ptep); \
- __r; \
-})
-
-/*
- * On RW/DIRTY bit transitions we can avoid flushing the hpte. For the
- * moment we always flush but we need to fix hpte_update and test if the
- * optimisation is worth it.
- */
-static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- unsigned long old;
-
- if ((pte_val(*ptep) & _PAGE_DIRTY) == 0)
- return 0;
- old = pte_update(ptep, _PAGE_DIRTY);
- if (old & _PAGE_HASHPTE)
- hpte_update(mm, addr, ptep, old, 0);
- return (old & _PAGE_DIRTY) != 0;
-}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define ptep_test_and_clear_dirty(__vma, __addr, __ptep) \
-({ \
- int __r; \
- __r = __ptep_test_and_clear_dirty((__vma)->vm_mm, __addr, __ptep); \
- __r; \
-})
-
-#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep)
-{
- unsigned long old;
-
- if ((pte_val(*ptep) & _PAGE_RW) == 0)
- return;
- old = pte_update(ptep, _PAGE_RW);
- if (old & _PAGE_HASHPTE)
- hpte_update(mm, addr, ptep, old, 0);
-}
-
-/*
- * We currently remove entries from the hashtable regardless of whether
- * the entry was young or dirty. The generic routines only flush if the
- * entry was young or dirty which is not good enough.
- *
- * We should be more intelligent about this but for the moment we override
- * these functions and force a tlb flush unconditionally
- */
-#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
-#define ptep_clear_flush_young(__vma, __address, __ptep) \
-({ \
- int __young = __ptep_test_and_clear_young((__vma)->vm_mm, __address, \
- __ptep); \
- __young; \
-})
-
-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
-#define ptep_clear_flush_dirty(__vma, __address, __ptep) \
-({ \
- int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
- __ptep); \
- flush_tlb_page(__vma, __address); \
- __dirty; \
-})
-
-#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- unsigned long old = pte_update(ptep, ~0UL);
-
- if (old & _PAGE_HASHPTE)
- hpte_update(mm, addr, ptep, old, 0);
- return __pte(old);
-}
-
-static inline void pte_clear(struct mm_struct *mm, unsigned long addr,
- pte_t * ptep)
-{
- unsigned long old = pte_update(ptep, ~0UL);
-
- if (old & _PAGE_HASHPTE)
- hpte_update(mm, addr, ptep, old, 0);
-}
-
-/*
- * set_pte stores a linux PTE into the linux page table.
- */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pte)
-{
- if (pte_present(*ptep)) {
- pte_clear(mm, addr, ptep);
- flush_tlb_pending();
- }
- pte = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS);
- *ptep = pte;
-}
-
-/* Set the dirty and/or accessed bits atomically in a linux PTE, this
- * function doesn't need to flush the hash entry
- */
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry, int dirty)
-{
- unsigned long bits = pte_val(entry) &
- (_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_RW | _PAGE_EXEC);
- unsigned long old, tmp;
-
- __asm__ __volatile__(
- "1: ldarx %0,0,%4\n\
- andi. %1,%0,%6\n\
- bne- 1b \n\
- or %0,%3,%0\n\
- stdcx. %0,0,%4\n\
- bne- 1b"
- :"=&r" (old), "=&r" (tmp), "=m" (*ptep)
- :"r" (bits), "r" (ptep), "m" (*ptep), "i" (_PAGE_BUSY)
- :"cc");
-}
-#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
- do { \
- __ptep_set_access_flags(__ptep, __entry, __dirty); \
- flush_tlb_page_nohash(__vma, __address); \
- } while(0)
-
-/*
- * Macro to mark a page protection value as "uncacheable".
- */
-#define pgprot_noncached(prot) (__pgprot(pgprot_val(prot) | _PAGE_NO_CACHE | _PAGE_GUARDED))
-
-struct file;
-extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
- unsigned long size, pgprot_t vma_prot);
-#define __HAVE_PHYS_MEM_ACCESS_PROT
-
-#define __HAVE_ARCH_PTE_SAME
-#define pte_same(A,B) (((pte_val(A) ^ pte_val(B)) & ~_PAGE_HPTEFLAGS) == 0)
-
-#define pte_ERROR(e) \
- printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
-#define pmd_ERROR(e) \
- printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))
-#define pgd_ERROR(e) \
- printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
-
-extern pgd_t swapper_pg_dir[];
-
-extern void paging_init(void);
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to put a corresponding HPTE into the hash table
- * ahead of time, instead of waiting for the inevitable extra
- * hash-table miss exception.
- */
-struct vm_area_struct;
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
-/* Encode and de-code a swap entry */
-#define __swp_type(entry) (((entry).val >> 1) & 0x3f)
-#define __swp_offset(entry) ((entry).val >> 8)
-#define __swp_entry(type, offset) ((swp_entry_t){((type)<< 1)|((offset)<<8)})
-#define __pte_to_swp_entry(pte) ((swp_entry_t){pte_val(pte) >> PTE_RPN_SHIFT})
-#define __swp_entry_to_pte(x) ((pte_t) { (x).val << PTE_RPN_SHIFT })
-#define pte_to_pgoff(pte) (pte_val(pte) >> PTE_RPN_SHIFT)
-#define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
-#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT)
-
-/*
- * kern_addr_valid is intended to indicate whether an address is a valid
- * kernel address. Most 32-bit archs define it as always true (like this)
- * but most 64-bit archs actually perform a test. What should we do here?
- * The only use is in fs/ncpfs/dir.c
- */
-#define kern_addr_valid(addr) (1)
-
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
- remap_pfn_range(vma, vaddr, pfn, size, prot)
-
-void pgtable_cache_init(void);
-
-/*
- * find_linux_pte returns the address of a linux pte for a given
- * effective address and directory. If not found, it returns zero.
- */static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
-{
- pgd_t *pg;
- pud_t *pu;
- pmd_t *pm;
- pte_t *pt = NULL;
-
- pg = pgdir + pgd_index(ea);
- if (!pgd_none(*pg)) {
- pu = pud_offset(pg, ea);
- if (!pud_none(*pu)) {
- pm = pmd_offset(pu, ea);
- if (pmd_present(*pm))
- pt = pte_offset_kernel(pm, ea);
- }
- }
- return pt;
-}
-
#include <asm-generic/pgtable.h>
-
#endif /* __ASSEMBLY__ */
-#endif /* CONFIG_PPC64 */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PGTABLE_H */
diff --git a/include/asm-powerpc/pmac_feature.h b/include/asm-powerpc/pmac_feature.h
index d3599cc9aa7..d43d91beba9 100644
--- a/include/asm-powerpc/pmac_feature.h
+++ b/include/asm-powerpc/pmac_feature.h
@@ -146,7 +146,7 @@ struct device_node;
static inline long pmac_call_feature(int selector, struct device_node* node,
long param, long value)
{
- if (!ppc_md.feature_call)
+ if (!ppc_md.feature_call || !machine_is(powermac))
return -ENODEV;
return ppc_md.feature_call(selector, node, param, value);
}
diff --git a/include/asm-powerpc/pmc.h b/include/asm-powerpc/pmc.h
index 8588be68e0a..d6a616a1b3e 100644
--- a/include/asm-powerpc/pmc.h
+++ b/include/asm-powerpc/pmc.h
@@ -30,6 +30,7 @@ void release_pmc_hardware(void);
#ifdef CONFIG_PPC64
void power4_enable_pmcs(void);
+void pasemi_enable_pmcs(void);
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index ab6eddb518c..6dcd7a811fe 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -10,6 +10,8 @@
#define _ASM_POWERPC_PPC_PCI_H
#ifdef __KERNEL__
+#ifdef CONFIG_PCI
+
#include <linux/pci.h>
#include <asm/pci-bridge.h>
@@ -22,7 +24,7 @@ extern void pci_setup_phb_io_dynamic(struct pci_controller *hose, int primary);
extern struct list_head hose_list;
extern int global_phb_number;
-extern unsigned long find_and_init_phbs(void);
+extern void find_and_init_phbs(void);
extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */
@@ -62,13 +64,13 @@ struct pci_dev *pci_get_device_by_addr(unsigned long addr);
* eeh_slot_error_detail -- record and EEH error condition to the log
* @severity: 1 if temporary, 2 if permanent failure.
*
- * Obtains the the EEH error details from the RTAS subsystem,
+ * Obtains the EEH error details from the RTAS subsystem,
* and then logs these details with the RTAS error log system.
*/
void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
/**
- * rtas_pci_enableo - enable IO transfers for this slot
+ * rtas_pci_enable - enable IO transfers for this slot
* @pdn: pci device node
* @function: either EEH_THAW_MMIO or EEH_THAW_DMA
*
@@ -89,6 +91,7 @@ int rtas_pci_enable(struct pci_dn *pdn, int function);
* Returns a non-zero value if the reset failed.
*/
int rtas_set_slot_reset (struct pci_dn *);
+int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs);
/**
* eeh_restore_bars - Restore device configuration info.
@@ -126,5 +129,10 @@ struct device_node * find_device_pe(struct device_node *dn);
#endif
+#else /* CONFIG_PCI */
+static inline void find_and_init_phbs(void) { }
+static inline void init_pci_config_tokens(void) { }
+#endif /* !CONFIG_PCI */
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_PPC_PCI_H */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index a26c32ee552..d947b160949 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -133,7 +133,6 @@ struct thread_struct {
mm_segment_t fs; /* for get_fs() validation */
#ifdef CONFIG_PPC32
void *pgdir; /* root of page-table tree */
- signed long last_syscall;
#endif
#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
unsigned long dbcr0; /* debug control register values */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 020ed015a94..6845af93ba9 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/platform_device.h>
+#include <asm/irq.h>
#include <asm/atomic.h>
/* Definitions used by the flattened device tree */
@@ -58,6 +59,8 @@ struct boot_param_header
u32 boot_cpuid_phys; /* Physical CPU id we're booting on */
/* version 3 fields below */
u32 dt_strings_size; /* size of the DT strings block */
+ /* version 17 fields below */
+ u32 dt_struct_size; /* size of the DT structure block */
};
@@ -68,7 +71,7 @@ typedef u32 ihandle;
struct property {
char *name;
int length;
- unsigned char *value;
+ void *value;
struct property *next;
};
@@ -108,14 +111,6 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e
}
-/* OBSOLETE: Old style node lookup */
-extern struct device_node *find_devices(const char *name);
-extern struct device_node *find_type_devices(const char *type);
-extern struct device_node *find_path_device(const char *path);
-extern struct device_node *find_compatible_devices(const char *type,
- const char *compat);
-extern struct device_node *find_all_nodes(void);
-
/* New style node lookup */
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
@@ -159,15 +154,17 @@ extern void of_detach_node(const struct device_node *);
extern void finish_device_tree(void);
extern void unflatten_device_tree(void);
extern void early_init_devtree(void *);
-extern int device_is_compatible(const struct device_node *device,
+extern int of_device_is_compatible(const struct device_node *device,
const char *);
+#define device_is_compatible(d, c) of_device_is_compatible((d), (c))
extern int machine_is_compatible(const char *compat);
-extern const void *get_property(const struct device_node *node,
+extern const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp);
+#define get_property(a, b, c) of_get_property((a), (b), (c))
extern void print_properties(struct device_node *node);
-extern int prom_n_addr_cells(struct device_node* np);
-extern int prom_n_size_cells(struct device_node* np);
+extern int of_n_addr_cells(struct device_node* np);
+extern int of_n_size_cells(struct device_node* np);
extern int prom_n_intr_cells(struct device_node* np);
extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -336,20 +333,17 @@ extern int of_irq_map_one(struct device_node *device, int index,
struct pci_dev;
extern int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq);
-static inline int of_irq_to_resource(struct device_node *dev, int index, struct resource *r)
-{
- int irq = irq_of_parse_and_map(dev, index);
-
- /* Only dereference the resource if both the
- * resource and the irq are valid. */
- if (r && irq != NO_IRQ) {
- r->start = r->end = irq;
- r->flags = IORESOURCE_IRQ;
- }
-
- return irq;
-}
+extern int of_irq_to_resource(struct device_node *dev, int index,
+ struct resource *r);
+/**
+ * of_iomap - Maps the memory mapped IO for a given device_node
+ * @device: the device whose io range will be mapped
+ * @index: index of the io range
+ *
+ * Returns a pointer to the mapped memory
+ */
+extern void __iomem *of_iomap(struct device_node *device, int index);
#endif /* __KERNEL__ */
#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 821581a8b64..13c372df99e 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -167,26 +167,31 @@ enum ps3_cpu_binding {
PS3_BINDING_CPU_1 = 1,
};
-int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
+int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
unsigned int *virq);
-int ps3_free_io_irq(unsigned int virq);
-int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq);
-int ps3_free_event_irq(unsigned int virq);
+int ps3_virq_destroy(unsigned int virq);
+int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
+ unsigned int *virq);
+int ps3_irq_plug_destroy(unsigned int virq);
+int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq);
+int ps3_event_receive_port_destroy(unsigned int virq);
int ps3_send_event_locally(unsigned int virq);
-int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
- const struct ps3_device_id *did, unsigned int interrupt_id,
+
+int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
unsigned int *virq);
-int ps3_disconnect_event_irq(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int virq);
-int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
+int ps3_io_irq_destroy(unsigned int virq);
+int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
unsigned int *virq);
-int ps3_free_vuart_irq(unsigned int virq);
-int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
+int ps3_vuart_irq_destroy(unsigned int virq);
+int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
unsigned int class, unsigned int *virq);
-int ps3_free_spe_irq(unsigned int virq);
-int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
+int ps3_spe_irq_destroy(unsigned int virq);
+
+int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
+ const struct ps3_device_id *did, unsigned int interrupt_id,
unsigned int *virq);
-int ps3_free_irq(unsigned int virq);
+int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
+ unsigned int interrupt_id, unsigned int virq);
/* lv1 result codes */
diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h
index 43e90ea9613..9efc40f1c77 100644
--- a/include/asm-powerpc/ps3av.h
+++ b/include/asm-powerpc/ps3av.h
@@ -18,8 +18,6 @@
#ifndef _ASM_POWERPC_PS3AV_H_
#define _ASM_POWERPC_PS3AV_H_
-#include <linux/mutex.h>
-
/** command for ioctl() **/
#define PS3AV_VERSION 0x205 /* version of ps3av command */
@@ -643,24 +641,6 @@ struct ps3av_pkt_avb_param {
u8 buf[PS3AV_PKT_AVB_PARAM_MAX_BUF_SIZE];
};
-struct ps3av {
- int available;
- struct semaphore sem;
- struct semaphore ping;
- struct semaphore pong;
- struct mutex mutex;
- int open_count;
- struct ps3_vuart_port_device *dev;
-
- int region;
- struct ps3av_pkt_av_get_hw_conf av_hw_conf;
- u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX];
- u32 opt_port[PS3AV_OPT_PORT_MAX];
- u32 head[PS3AV_HEAD_MAX];
- u32 audio_port;
- int ps3av_mode;
- int ps3av_mode_old;
-};
/** command status **/
#define PS3AV_STATUS_SUCCESS 0x0000 /* success */
@@ -718,6 +698,7 @@ static inline void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_
extern int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *,
u32);
+struct ps3_vuart_port_device;
extern int ps3av_vuart_write(struct ps3_vuart_port_device *dev,
const void *buf, unsigned long size);
extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
@@ -725,6 +706,7 @@ extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
extern int ps3av_set_video_mode(u32, int);
extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
+extern int ps3av_get_auto_mode(int);
extern int ps3av_set_mode(u32, int);
extern int ps3av_get_mode(void);
extern int ps3av_get_scanmode(int);
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 0d7f0164ed8..749c7f953b5 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -469,12 +469,68 @@
#define SPRN_SIAR 780
#define SPRN_SDAR 781
-#define PA6T_SPRN_PMC0 787
-#define PA6T_SPRN_PMC1 788
-#define PA6T_SPRN_PMC2 789
-#define PA6T_SPRN_PMC3 790
-#define PA6T_SPRN_PMC4 791
-#define PA6T_SPRN_PMC5 792
+#define SPRN_PA6T_MMCR0 795
+#define PA6T_MMCR0_EN0 0x0000000000000001UL
+#define PA6T_MMCR0_EN1 0x0000000000000002UL
+#define PA6T_MMCR0_EN2 0x0000000000000004UL
+#define PA6T_MMCR0_EN3 0x0000000000000008UL
+#define PA6T_MMCR0_EN4 0x0000000000000010UL
+#define PA6T_MMCR0_EN5 0x0000000000000020UL
+#define PA6T_MMCR0_SUPEN 0x0000000000000040UL
+#define PA6T_MMCR0_PREN 0x0000000000000080UL
+#define PA6T_MMCR0_HYPEN 0x0000000000000100UL
+#define PA6T_MMCR0_FCM0 0x0000000000000200UL
+#define PA6T_MMCR0_FCM1 0x0000000000000400UL
+#define PA6T_MMCR0_INTGEN 0x0000000000000800UL
+#define PA6T_MMCR0_INTEN0 0x0000000000001000UL
+#define PA6T_MMCR0_INTEN1 0x0000000000002000UL
+#define PA6T_MMCR0_INTEN2 0x0000000000004000UL
+#define PA6T_MMCR0_INTEN3 0x0000000000008000UL
+#define PA6T_MMCR0_INTEN4 0x0000000000010000UL
+#define PA6T_MMCR0_INTEN5 0x0000000000020000UL
+#define PA6T_MMCR0_DISCNT 0x0000000000040000UL
+#define PA6T_MMCR0_UOP 0x0000000000080000UL
+#define PA6T_MMCR0_TRG 0x0000000000100000UL
+#define PA6T_MMCR0_TRGEN 0x0000000000200000UL
+#define PA6T_MMCR0_TRGREG 0x0000000001600000UL
+#define PA6T_MMCR0_SIARLOG 0x0000000002000000UL
+#define PA6T_MMCR0_SDARLOG 0x0000000004000000UL
+#define PA6T_MMCR0_PROEN 0x0000000008000000UL
+#define PA6T_MMCR0_PROLOG 0x0000000010000000UL
+#define PA6T_MMCR0_DAMEN2 0x0000000020000000UL
+#define PA6T_MMCR0_DAMEN3 0x0000000040000000UL
+#define PA6T_MMCR0_DAMEN4 0x0000000080000000UL
+#define PA6T_MMCR0_DAMEN5 0x0000000100000000UL
+#define PA6T_MMCR0_DAMSEL2 0x0000000200000000UL
+#define PA6T_MMCR0_DAMSEL3 0x0000000400000000UL
+#define PA6T_MMCR0_DAMSEL4 0x0000000800000000UL
+#define PA6T_MMCR0_DAMSEL5 0x0000001000000000UL
+#define PA6T_MMCR0_HANDDIS 0x0000002000000000UL
+#define PA6T_MMCR0_PCTEN 0x0000004000000000UL
+#define PA6T_MMCR0_SOCEN 0x0000008000000000UL
+#define PA6T_MMCR0_SOCMOD 0x0000010000000000UL
+
+#define SPRN_PA6T_MMCR1 798
+#define PA6T_MMCR1_ES2 0x00000000000000ffUL
+#define PA6T_MMCR1_ES3 0x000000000000ff00UL
+#define PA6T_MMCR1_ES4 0x0000000000ff0000UL
+#define PA6T_MMCR1_ES5 0x00000000ff000000UL
+
+#define SPRN_PA6T_SIAR 780
+#define SPRN_PA6T_UPMC0 771
+#define SPRN_PA6T_UPMC1 772
+#define SPRN_PA6T_UPMC2 773
+#define SPRN_PA6T_UPMC3 774
+#define SPRN_PA6T_UPMC4 775
+#define SPRN_PA6T_UPMC5 776
+#define SPRN_PA6T_UMMCR0 779
+#define SPRN_PA6T_UMMCR1 782
+#define SPRN_PA6T_PMC0 787
+#define SPRN_PA6T_PMC1 788
+#define SPRN_PA6T_PMC2 789
+#define SPRN_PA6T_PMC3 790
+#define SPRN_PA6T_PMC4 791
+#define SPRN_PA6T_PMC5 792
#else /* 32-bit */
#define SPRN_MMCR0 952 /* Monitor Mode Control Register 0 */
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 01717f266dc..d037f50580e 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -83,6 +83,7 @@ extern void __cpu_die(unsigned int cpu);
#else
/* for UP */
+#define hard_smp_processor_id() 0
#define smp_setup_cpu_maps()
#endif /* CONFIG_SMP */
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index 8aad0619eb8..c48ae185c87 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -235,6 +235,12 @@ struct spu_priv2_collapsed {
*/
struct spu_state {
struct spu_lscsa *lscsa;
+#ifdef CONFIG_SPU_FS_64K_LS
+ int use_big_pages;
+ /* One struct page per 64k page */
+#define SPU_LSCSA_NUM_BIG_PAGES (sizeof(struct spu_lscsa) / 0x10000)
+ struct page *lscsa_pages[SPU_LSCSA_NUM_BIG_PAGES];
+#endif
struct spu_problem_collapsed prob;
struct spu_priv1_collapsed priv1;
struct spu_priv2_collapsed priv2;
@@ -242,16 +248,19 @@ struct spu_state {
u64 spu_chnldata_RW[32];
u32 spu_mailbox_data[4];
u32 pu_mailbox_data[1];
+ u64 dar, dsisr;
unsigned long suspend_time;
spinlock_t register_lock;
};
-extern void spu_init_csa(struct spu_state *csa);
+extern int spu_init_csa(struct spu_state *csa);
extern void spu_fini_csa(struct spu_state *csa);
extern int spu_save(struct spu_state *prev, struct spu *spu);
extern int spu_restore(struct spu_state *new, struct spu *spu);
extern int spu_switch(struct spu_state *prev, struct spu_state *new,
struct spu *spu);
+extern int spu_alloc_lscsa(struct spu_state *csa);
+extern void spu_free_lscsa(struct spu_state *csa);
#endif /* !__SPU__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/suspend.h b/include/asm-powerpc/suspend.h
new file mode 100644
index 00000000000..cbf2c9404c3
--- /dev/null
+++ b/include/asm-powerpc/suspend.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_POWERPC_SUSPEND_H
+#define __ASM_POWERPC_SUSPEND_H
+
+static inline int arch_prepare_suspend(void) { return 0; }
+
+void save_processor_state(void);
+void restore_processor_state(void);
+
+#endif /* __ASM_POWERPC_SUSPEND_H */
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index f7b1227d645..09621f611db 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -7,7 +7,6 @@
#include <linux/kernel.h>
#include <asm/hw_irq.h>
-#include <asm/atomic.h>
/*
* Memory barrier.
@@ -131,6 +130,7 @@ extern void enable_kernel_altivec(void);
extern void giveup_altivec(struct task_struct *);
extern void load_up_altivec(struct task_struct *);
extern int emulate_altivec(struct pt_regs *);
+extern void enable_kernel_spe(void);
extern void giveup_spe(struct task_struct *);
extern void load_up_spe(struct task_struct *);
extern int fix_alignment(struct pt_regs *);
@@ -226,6 +226,29 @@ __xchg_u32(volatile void *p, unsigned long val)
return prev;
}
+/*
+ * Atomic exchange
+ *
+ * Changes the memory location '*ptr' to be val and returns
+ * the previous value stored there.
+ */
+static __inline__ unsigned long
+__xchg_u32_local(volatile void *p, unsigned long val)
+{
+ unsigned long prev;
+
+ __asm__ __volatile__(
+"1: lwarx %0,0,%2 \n"
+ PPC405_ERR77(0,%2)
+" stwcx. %3,0,%2 \n\
+ bne- 1b"
+ : "=&r" (prev), "+m" (*(volatile unsigned int *)p)
+ : "r" (p), "r" (val)
+ : "cc", "memory");
+
+ return prev;
+}
+
#ifdef CONFIG_PPC64
static __inline__ unsigned long
__xchg_u64(volatile void *p, unsigned long val)
@@ -245,6 +268,23 @@ __xchg_u64(volatile void *p, unsigned long val)
return prev;
}
+
+static __inline__ unsigned long
+__xchg_u64_local(volatile void *p, unsigned long val)
+{
+ unsigned long prev;
+
+ __asm__ __volatile__(
+"1: ldarx %0,0,%2 \n"
+ PPC405_ERR77(0,%2)
+" stdcx. %3,0,%2 \n\
+ bne- 1b"
+ : "=&r" (prev), "+m" (*(volatile unsigned long *)p)
+ : "r" (p), "r" (val)
+ : "cc", "memory");
+
+ return prev;
+}
#endif
/*
@@ -268,13 +308,32 @@ __xchg(volatile void *ptr, unsigned long x, unsigned int size)
return x;
}
+static __inline__ unsigned long
+__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
+{
+ switch (size) {
+ case 4:
+ return __xchg_u32_local(ptr, x);
+#ifdef CONFIG_PPC64
+ case 8:
+ return __xchg_u64_local(ptr, x);
+#endif
+ }
+ __xchg_called_with_bad_pointer();
+ return x;
+}
#define xchg(ptr,x) \
({ \
__typeof__(*(ptr)) _x_ = (x); \
(__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
})
-#define tas(ptr) (xchg((ptr),1))
+#define xchg_local(ptr,x) \
+ ({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_local((ptr), \
+ (unsigned long)_x_, sizeof(*(ptr))); \
+ })
/*
* Compare and exchange - if *p == old, set it to new,
@@ -305,6 +364,28 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
return prev;
}
+static __inline__ unsigned long
+__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
+ unsigned long new)
+{
+ unsigned int prev;
+
+ __asm__ __volatile__ (
+"1: lwarx %0,0,%2 # __cmpxchg_u32\n\
+ cmpw 0,%0,%3\n\
+ bne- 2f\n"
+ PPC405_ERR77(0,%2)
+" stwcx. %4,0,%2\n\
+ bne- 1b"
+ "\n\
+2:"
+ : "=&r" (prev), "+m" (*p)
+ : "r" (p), "r" (old), "r" (new)
+ : "cc", "memory");
+
+ return prev;
+}
+
#ifdef CONFIG_PPC64
static __inline__ unsigned long
__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
@@ -327,6 +408,27 @@ __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
return prev;
}
+
+static __inline__ unsigned long
+__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
+ unsigned long new)
+{
+ unsigned long prev;
+
+ __asm__ __volatile__ (
+"1: ldarx %0,0,%2 # __cmpxchg_u64\n\
+ cmpd 0,%0,%3\n\
+ bne- 2f\n\
+ stdcx. %4,0,%2\n\
+ bne- 1b"
+ "\n\
+2:"
+ : "=&r" (prev), "+m" (*p)
+ : "r" (p), "r" (old), "r" (new)
+ : "cc", "memory");
+
+ return prev;
+}
#endif
/* This function doesn't exist, so you'll get a linker error
@@ -349,6 +451,22 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
return old;
}
+static __inline__ unsigned long
+__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
+ unsigned int size)
+{
+ switch (size) {
+ case 4:
+ return __cmpxchg_u32_local(ptr, old, new);
+#ifdef CONFIG_PPC64
+ case 8:
+ return __cmpxchg_u64_local(ptr, old, new);
+#endif
+ }
+ __cmpxchg_called_with_bad_pointer();
+ return old;
+}
+
#define cmpxchg(ptr,o,n) \
({ \
__typeof__(*(ptr)) _o_ = (o); \
@@ -357,6 +475,15 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
(unsigned long)_n_, sizeof(*(ptr))); \
})
+
+#define cmpxchg_local(ptr,o,n) \
+ ({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof(*(ptr))); \
+ })
+
#ifdef CONFIG_PPC64
/*
* We handle most unaligned accesses in hardware. On the other hand
diff --git a/include/asm-powerpc/tlb.h b/include/asm-powerpc/tlb.h
index 4e2a834683f..0a17682663d 100644
--- a/include/asm-powerpc/tlb.h
+++ b/include/asm-powerpc/tlb.h
@@ -38,7 +38,6 @@ extern void pte_free_finish(void);
static inline void tlb_flush(struct mmu_gather *tlb)
{
- flush_tlb_pending();
pte_free_finish();
}
diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h
index 93c7d0c7230..86e6266a028 100644
--- a/include/asm-powerpc/tlbflush.h
+++ b/include/asm-powerpc/tlbflush.h
@@ -17,10 +17,73 @@
*/
#ifdef __KERNEL__
-
struct mm_struct;
+struct vm_area_struct;
+
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+/*
+ * TLB flushing for software loaded TLB chips
+ *
+ * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
+ * flush_tlb_kernel_range are best implemented as tlbia vs
+ * specific tlbie's
+ */
+
+extern void _tlbie(unsigned long address);
+
+#if defined(CONFIG_40x) || defined(CONFIG_8xx)
+#define _tlbia() asm volatile ("tlbia; sync" : : : "memory")
+#else /* CONFIG_44x || CONFIG_FSL_BOOKE */
+extern void _tlbia(void);
+#endif
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ _tlbia();
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long vmaddr)
+{
+ _tlbie(vmaddr);
+}
+
+static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
+ unsigned long vmaddr)
+{
+ _tlbie(vmaddr);
+}
+
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ _tlbia();
+}
+
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ _tlbia();
+}
-#ifdef CONFIG_PPC64
+#elif defined(CONFIG_PPC32)
+/*
+ * TLB flushing for "classic" hash-MMMU 32-bit CPUs, 6xx, 7xx, 7xxx
+ */
+extern void _tlbie(unsigned long address);
+extern void _tlbia(void);
+
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
+extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+
+#else
+/*
+ * TLB flushing for 64-bit has-MMU CPUs
+ */
#include <linux/percpu.h>
#include <asm/page.h>
@@ -28,117 +91,90 @@ struct mm_struct;
#define PPC64_TLB_BATCH_NR 192
struct ppc64_tlb_batch {
- unsigned long index;
- struct mm_struct *mm;
- real_pte_t pte[PPC64_TLB_BATCH_NR];
- unsigned long vaddr[PPC64_TLB_BATCH_NR];
- unsigned int psize;
+ int active;
+ unsigned long index;
+ struct mm_struct *mm;
+ real_pte_t pte[PPC64_TLB_BATCH_NR];
+ unsigned long vaddr[PPC64_TLB_BATCH_NR];
+ unsigned int psize;
};
DECLARE_PER_CPU(struct ppc64_tlb_batch, ppc64_tlb_batch);
extern void __flush_tlb_pending(struct ppc64_tlb_batch *batch);
-static inline void flush_tlb_pending(void)
+extern void hpte_need_flush(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, unsigned long pte, int huge);
+
+#define __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+
+static inline void arch_enter_lazy_mmu_mode(void)
+{
+ struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
+
+ batch->active = 1;
+}
+
+static inline void arch_leave_lazy_mmu_mode(void)
{
- struct ppc64_tlb_batch *batch = &get_cpu_var(ppc64_tlb_batch);
+ struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
if (batch->index)
__flush_tlb_pending(batch);
- put_cpu_var(ppc64_tlb_batch);
+ batch->active = 0;
}
+#define arch_flush_lazy_mmu_mode() do {} while (0)
+
+
extern void flush_hash_page(unsigned long va, real_pte_t pte, int psize,
int local);
extern void flush_hash_range(unsigned long number, int local);
-#else /* CONFIG_PPC64 */
-
-#include <linux/mm.h>
-
-extern void _tlbie(unsigned long address);
-extern void _tlbia(void);
-
-/*
- * TODO: (CONFIG_FSL_BOOKE) determine if flush_tlb_range &
- * flush_tlb_kernel_range are best implemented as tlbia vs
- * specific tlbie's
- */
-
-#if (defined(CONFIG_4xx) && !defined(CONFIG_44x)) || defined(CONFIG_8xx)
-#define flush_tlb_pending() asm volatile ("tlbia; sync" : : : "memory")
-#elif defined(CONFIG_4xx) || defined(CONFIG_FSL_BOOKE)
-#define flush_tlb_pending() _tlbia()
-#endif
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to ensure coherency between the i-cache and d-cache
- * for the page which has just been mapped in.
- * On machines which use an MMU hash table, we use this to put a
- * corresponding HPTE into the hash table ahead of time, instead of
- * waiting for the inevitable extra hash-table miss exception.
- */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
-
-#endif /* CONFIG_PPC64 */
-
-#if defined(CONFIG_PPC64) || defined(CONFIG_4xx) || \
- defined(CONFIG_FSL_BOOKE) || defined(CONFIG_8xx)
static inline void flush_tlb_mm(struct mm_struct *mm)
{
- flush_tlb_pending();
}
static inline void flush_tlb_page(struct vm_area_struct *vma,
- unsigned long vmaddr)
+ unsigned long vmaddr)
{
-#ifdef CONFIG_PPC64
- flush_tlb_pending();
-#else
- _tlbie(vmaddr);
-#endif
}
static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
unsigned long vmaddr)
{
-#ifndef CONFIG_PPC64
- _tlbie(vmaddr);
-#endif
}
static inline void flush_tlb_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long end)
{
- flush_tlb_pending();
}
static inline void flush_tlb_kernel_range(unsigned long start,
- unsigned long end)
+ unsigned long end)
{
- flush_tlb_pending();
}
-#else /* 6xx, 7xx, 7xxx cpus */
-
-extern void flush_tlb_mm(struct mm_struct *mm);
-extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
-extern void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long addr);
-extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end);
-extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
-
#endif
/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to ensure coherency between the i-cache and d-cache
+ * for the page which has just been mapped in.
+ * On machines which use an MMU hash table, we use this to put a
+ * corresponding HPTE into the hash table ahead of time, instead of
+ * waiting for the inevitable extra hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
+
+/*
* This is called in munmap when we have freed up some page-table
* pages. We don't need to do anything here, there's nothing special
* about our page-table pages. -- paulus
*/
static inline void flush_tlb_pgtables(struct mm_struct *mm,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long end)
{
}
diff --git a/include/asm-powerpc/tsi108.h b/include/asm-powerpc/tsi108.h
index 4e95d153be8..f8b60793b7a 100644
--- a/include/asm-powerpc/tsi108.h
+++ b/include/asm-powerpc/tsi108.h
@@ -68,8 +68,17 @@
#define TSI108_PB_ERRCS_ES (1 << 1)
#define TSI108_PB_ISR_PBS_RD_ERR (1 << 8)
-#define TSI108_PCI_CFG_BASE_PHYS (0xfb000000)
#define TSI108_PCI_CFG_SIZE (0x01000000)
+
+/*
+ * PHY Configuration Options
+ *
+ * Specify "bcm54xx" in the compatible property of your device tree phy
+ * nodes if your board uses the Broadcom PHYs
+ */
+#define TSI108_PHY_MV88E 0 /* Marvel 88Exxxx PHY */
+#define TSI108_PHY_BCM54XX 1 /* Broardcom BCM54xx PHY */
+
/* Global variables */
extern u32 tsi108_pci_cfg_base;
@@ -93,6 +102,7 @@ typedef struct {
u16 phy; /* phy address */
u16 irq_num; /* irq number */
u8 mac_addr[6]; /* phy mac address */
+ u16 phy_type; /* type of phy on board */
} hw_info;
extern u32 get_vir_csrbase(void);
diff --git a/include/asm-powerpc/tsi108_pci.h b/include/asm-powerpc/tsi108_pci.h
new file mode 100644
index 00000000000..a9f92f73232
--- /dev/null
+++ b/include/asm-powerpc/tsi108_pci.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2007 IBM Corp
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _ASM_PPC_TSI108_PCI_H
+#define _ASM_PPC_TSI108_PCI_H
+
+#include <asm/tsi108.h>
+
+/* Register definitions */
+#define TSI108_PCI_P2O_BAR0 (TSI108_PCI_OFFSET + 0x10)
+#define TSI108_PCI_P2O_BAR0_UPPER (TSI108_PCI_OFFSET + 0x14)
+#define TSI108_PCI_P2O_BAR2 (TSI108_PCI_OFFSET + 0x18)
+#define TSI108_PCI_P2O_BAR2_UPPER (TSI108_PCI_OFFSET + 0x1c)
+#define TSI108_PCI_P2O_PAGE_SIZES (TSI108_PCI_OFFSET + 0x4c)
+#define TSI108_PCI_PFAB_BAR0 (TSI108_PCI_OFFSET + 0x204)
+#define TSI108_PCI_PFAB_BAR0_UPPER (TSI108_PCI_OFFSET + 0x208)
+#define TSI108_PCI_PFAB_IO (TSI108_PCI_OFFSET + 0x20c)
+#define TSI108_PCI_PFAB_IO_UPPER (TSI108_PCI_OFFSET + 0x210)
+#define TSI108_PCI_PFAB_MEM32 (TSI108_PCI_OFFSET + 0x214)
+#define TSI108_PCI_PFAB_PFM3 (TSI108_PCI_OFFSET + 0x220)
+#define TSI108_PCI_PFAB_PFM4 (TSI108_PCI_OFFSET + 0x230)
+
+extern int tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary);
+extern void tsi108_pci_int_init(struct device_node *node);
+extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc);
+extern void tsi108_clear_pci_cfg_error(void);
+
+#endif /* _ASM_PPC_TSI108_PCI_H */
diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h
index adbf16b8cfb..8e798e3758b 100644
--- a/include/asm-powerpc/uaccess.h
+++ b/include/asm-powerpc/uaccess.h
@@ -110,12 +110,18 @@ struct exception_table_entry {
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
#define __put_user(x, ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
#ifndef __powerpc64__
#define __get_user64(x, ptr) \
__get_user64_nocheck((x), (ptr), sizeof(*(ptr)))
#define __put_user64(x, ptr) __put_user(x, ptr)
#endif
+#define __get_user_inatomic(x, ptr) \
+ __get_user_nosleep((x), (ptr), sizeof(*(ptr)))
+#define __put_user_inatomic(x, ptr) \
+ __put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
#define __get_user_unaligned __get_user
#define __put_user_unaligned __put_user
@@ -198,6 +204,16 @@ do { \
__pu_err; \
})
+#define __put_user_nosleep(x, ptr, size) \
+({ \
+ long __pu_err; \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
+ __chk_user_ptr(ptr); \
+ __put_user_size((x), __pu_addr, (size), __pu_err); \
+ __pu_err; \
+})
+
+
extern long __get_user_bad(void);
#define __get_user_asm(x, addr, err, op) \
@@ -297,6 +313,18 @@ do { \
__gu_err; \
})
+#define __get_user_nosleep(x, ptr, size) \
+({ \
+ long __gu_err; \
+ unsigned long __gu_val; \
+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __chk_user_ptr(ptr); \
+ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+
/* more complex routines */
extern unsigned long __copy_tofrom_user(void __user *to,
diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
index 39d1c90fd2c..f529f70b1d8 100644
--- a/include/asm-powerpc/ucc_fast.h
+++ b/include/asm-powerpc/ucc_fast.h
@@ -159,6 +159,9 @@ struct ucc_fast_private {
struct ucc_fast *uf_regs; /* a pointer to memory map of UCC regs. */
u32 *p_ucce; /* a pointer to the event register in memory. */
u32 *p_uccm; /* a pointer to the mask register in memory. */
+#ifdef CONFIG_UGETH_TX_ON_DEMAND
+ u16 *p_utodr; /* pointer to the transmit on demand register */
+#endif
int enabled_tx; /* Whether channel is enabled for Tx (ENT) */
int enabled_rx; /* Whether channel is enabled for Rx (ENR) */
int stopped_tx; /* Whether channel has been stopped for Tx
diff --git a/include/asm-powerpc/udbg.h b/include/asm-powerpc/udbg.h
index d03d8557f70..ce9d82fb7b6 100644
--- a/include/asm-powerpc/udbg.h
+++ b/include/asm-powerpc/udbg.h
@@ -47,6 +47,7 @@ extern void __init udbg_init_rtas_panel(void);
extern void __init udbg_init_rtas_console(void);
extern void __init udbg_init_debug_beat(void);
extern void __init udbg_init_btext(void);
+extern void __init udbg_init_44x_as1(void);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UDBG_H */
diff --git a/include/asm-powerpc/uic.h b/include/asm-powerpc/uic.h
new file mode 100644
index 00000000000..970eb7e2186
--- /dev/null
+++ b/include/asm-powerpc/uic.h
@@ -0,0 +1,23 @@
+/*
+ * include/asm-powerpc/uic.h
+ *
+ * IBM PPC4xx UIC external definitions and structure.
+ *
+ * Maintainer: David Gibson <dwg@au1.ibm.com>
+ * Copyright 2007 IBM Corporation.
+ *
+ * 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.
+ */
+#ifndef _ASM_POWERPC_UIC_H
+#define _ASM_POWERPC_UIC_H
+
+#ifdef __KERNEL__
+
+extern void __init uic_init_tree(void);
+extern unsigned int uic_get_irq(void);
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_UIC_H */
diff --git a/include/asm-ppc/hydra.h b/include/asm-ppc/hydra.h
index 833a8aff2a8..1ad4eed07fb 100644
--- a/include/asm-ppc/hydra.h
+++ b/include/asm-ppc/hydra.h
@@ -8,7 +8,7 @@
* Macintosh Technology in the Common Hardware Reference Platform
* Apple Computer, Inc.
*
- * © Copyright 1995 Apple Computer, Inc. All rights reserved.
+ * © Copyright 1995 Apple Computer, Inc. All rights reserved.
*
* It's available online from http://chrp.apple.com/MacTech.pdf.
* You can obtain paper copies of this book from computer bookstores or by
diff --git a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
index 92fd02d7b17..ed6891af05d 100644
--- a/include/asm-ppc/ibm4xx.h
+++ b/include/asm-ppc/ibm4xx.h
@@ -47,12 +47,8 @@
#include <platforms/4xx/walnut.h>
#endif
-#if defined(CONFIG_XILINX_ML300)
-#include <platforms/4xx/xilinx_ml300.h>
-#endif
-
-#if defined(CONFIG_XILINX_ML403)
-#include <platforms/4xx/xilinx_ml403.h>
+#if defined(CONFIG_XILINX_VIRTEX)
+#include <platforms/4xx/virtex.h>
#endif
#ifndef __ASSEMBLY__
diff --git a/include/asm-ppc/kdebug.h b/include/asm-ppc/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-ppc/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index 2bc8589cc45..a6441a063e5 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -6,6 +6,7 @@
#include <asm/bitops.h>
#include <asm/mmu.h>
#include <asm/cputable.h>
+#include <asm-generic/mm_hooks.h>
/*
* On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index b1fdbf40dba..bed452d4a5f 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -827,10 +827,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma,
remap_pfn_range(vma, vaddr, pfn, size, prot)
#endif
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
/*
* No page table caches to initialise
*/
diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h
index 40f197af650..de99e92d627 100644
--- a/include/asm-ppc/ppc_sys.h
+++ b/include/asm-ppc/ppc_sys.h
@@ -33,8 +33,6 @@
#include <asm/mpc52xx.h>
#elif defined(CONFIG_MPC10X_BRIDGE)
#include <asm/mpc10x.h>
-#elif defined(CONFIG_XILINX_VIRTEX)
-#include <platforms/4xx/virtex.h>
#else
#error "need definition of ppc_sys_devices"
#endif
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index adc5ae78492..901f7fa8b2d 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -34,7 +34,8 @@ extern unsigned long sub_reloc_offset(unsigned long);
*/
#define machine_is_compatible(x) 0
#define of_find_compatible_node(f, t, c) NULL
-#define get_property(p, n, l) NULL
+#define of_get_property(p, n, l) NULL
+#define get_property(a, b, c) of_get_property((a), (b), (c))
#endif /* _PPC_PROM_H */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index 738943584c0..d84a3cf4d03 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -6,7 +6,6 @@
#include <linux/kernel.h>
-#include <asm/atomic.h>
#include <asm/hw_irq.h>
/*
@@ -170,7 +169,6 @@ xchg_u32(volatile void *p, unsigned long val)
extern void __xchg_called_with_bad_pointer(void);
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
index cfc81533b9b..6795ecefd15 100644
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -164,9 +164,9 @@ extern int ccw_device_resume(struct ccw_device *);
extern int ccw_device_halt(struct ccw_device *, unsigned long);
extern int ccw_device_clear(struct ccw_device *, unsigned long);
-extern int read_dev_chars(struct ccw_device *cdev, void **buffer, int length);
-extern int read_conf_data(struct ccw_device *cdev, void **buffer, int *length);
-extern int read_conf_data_lpm(struct ccw_device *cdev, void **buffer,
+extern int __deprecated read_dev_chars(struct ccw_device *cdev, void **buffer, int length);
+extern int __deprecated read_conf_data(struct ccw_device *cdev, void **buffer, int *length);
+extern int __deprecated read_conf_data_lpm(struct ccw_device *cdev, void **buffer,
int *length, __u8 lpm);
extern int ccw_device_set_online(struct ccw_device *cdev);
diff --git a/include/asm-s390/dma-mapping.h b/include/asm-s390/dma-mapping.h
index 09bb7b04f96..3f8c12fde0f 100644
--- a/include/asm-s390/dma-mapping.h
+++ b/include/asm-s390/dma-mapping.h
@@ -9,6 +9,4 @@
#ifndef _ASM_DMA_MAPPING_H
#define _ASM_DMA_MAPPING_H
-#include <asm-generic/dma-mapping-broken.h>
-
#endif /* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h
index c0d629d61d3..91d06325cc7 100644
--- a/include/asm-s390/elf.h
+++ b/include/asm-s390/elf.h
@@ -188,7 +188,8 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
/* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. */
-#define ELF_HWCAP (0)
+extern unsigned long elf_hwcap;
+#define ELF_HWCAP (elf_hwcap)
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
@@ -197,7 +198,9 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs)
For the moment, we have only optimizations for the Intel generations,
but that could change... */
-#define ELF_PLATFORM (NULL)
+#define ELF_PLATFORM_SIZE 8
+extern char elf_platform[];
+#define ELF_PLATFORM (elf_platform)
#ifndef __s390x__
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h
index 1b50f89819a..04418af08f8 100644
--- a/include/asm-s390/kdebug.h
+++ b/include/asm-s390/kdebug.h
@@ -8,23 +8,19 @@
struct pt_regs;
-struct die_args {
- struct pt_regs *regs;
- const char *str;
- long err;
- int trapnr;
- int signr;
-};
-
-/* Note - you should never unregister because that can race with NMIs.
- * If you really want to do it first unregister - then synchronize_sched
- * - then free.
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation. Will hopefully go away soon once all
+ * architectures are updated.
*/
-extern int register_die_notifier(struct notifier_block *);
-extern int unregister_die_notifier(struct notifier_block *);
-extern int register_page_fault_notifier(struct notifier_block *);
-extern int unregister_page_fault_notifier(struct notifier_block *);
-extern struct atomic_notifier_head s390die_chain;
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
enum die_val {
DIE_OOPS = 1,
@@ -39,22 +35,8 @@ enum die_val {
DIE_GPF,
DIE_CALL,
DIE_NMI_IPI,
- DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
- return atomic_notifier_call_chain(&s390die_chain, val, &args);
-}
-
extern void die(const char *, struct pt_regs *, long);
#endif
diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h
index 9c35c8ad1af..7592af708b4 100644
--- a/include/asm-s390/kexec.h
+++ b/include/asm-s390/kexec.h
@@ -34,8 +34,6 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_S390
-#define MAX_NOTE_BYTES 1024
-
/* Provide a dummy definition to avoid build failures. */
static inline void crash_setup_regs(struct pt_regs *newregs,
struct pt_regs *oldregs) { }
diff --git a/include/asm-s390/kprobes.h b/include/asm-s390/kprobes.h
index b847ff0ec3f..830fe4c4eea 100644
--- a/include/asm-s390/kprobes.h
+++ b/include/asm-s390/kprobes.h
@@ -97,18 +97,10 @@ void kretprobe_trampoline(void);
int is_prohibited_opcode(kprobe_opcode_t *instruction);
void get_instruction_type(struct arch_specific_insn *ainsn);
+int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
+int kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data);
+
#define flush_insn_slot(p) do { } while (0)
#endif /* _ASM_S390_KPROBES_H */
-
-#ifdef CONFIG_KPROBES
-
-extern int kprobe_exceptions_notify(struct notifier_block *self,
- unsigned long val, void *data);
-#else /* !CONFIG_KPROBES */
-static inline int kprobe_exceptions_notify(struct notifier_block *self,
- unsigned long val, void *data)
-{
- return 0;
-}
-#endif
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index ffc9788a21a..801a6fd35b5 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -229,17 +229,19 @@ struct _lowcore
__u16 subchannel_nr; /* 0x0ba */
__u32 io_int_parm; /* 0x0bc */
__u32 io_int_word; /* 0x0c0 */
- __u8 pad3[0xD4-0xC4]; /* 0x0c4 */
+ __u8 pad3[0xc8-0xc4]; /* 0x0c4 */
+ __u32 stfl_fac_list; /* 0x0c8 */
+ __u8 pad4[0xd4-0xcc]; /* 0x0cc */
__u32 extended_save_area_addr; /* 0x0d4 */
__u32 cpu_timer_save_area[2]; /* 0x0d8 */
__u32 clock_comp_save_area[2]; /* 0x0e0 */
__u32 mcck_interruption_code[2]; /* 0x0e8 */
- __u8 pad4[0xf4-0xf0]; /* 0x0f0 */
+ __u8 pad5[0xf4-0xf0]; /* 0x0f0 */
__u32 external_damage_code; /* 0x0f4 */
__u32 failing_storage_address; /* 0x0f8 */
- __u8 pad5[0x100-0xfc]; /* 0x0fc */
+ __u8 pad6[0x100-0xfc]; /* 0x0fc */
__u32 st_status_fixed_logout[4];/* 0x100 */
- __u8 pad6[0x120-0x110]; /* 0x110 */
+ __u8 pad7[0x120-0x110]; /* 0x110 */
__u32 access_regs_save_area[16];/* 0x120 */
__u32 floating_pt_save_area[8]; /* 0x160 */
__u32 gpregs_save_area[16]; /* 0x180 */
diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h
index 1d21da220d4..501cb9b0631 100644
--- a/include/asm-s390/mmu_context.h
+++ b/include/asm-s390/mmu_context.h
@@ -10,6 +10,8 @@
#define __S390_MMU_CONTEXT_H
#include <asm/pgalloc.h>
+#include <asm-generic/mm_hooks.h>
+
/*
* get a new mmu context.. S390 don't know about contexts.
*/
diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
index 127f72e7741..74db1dc10a7 100644
--- a/include/asm-s390/qdio.h
+++ b/include/asm-s390/qdio.h
@@ -120,6 +120,7 @@ extern unsigned long qdio_get_status(int irq);
#define QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT 0x08 /* no effect on
adapter interrupts */
#define QDIO_FLAG_DONT_SIGA 0x10
+#define QDIO_FLAG_PCI_OUT 0x20
extern int do_QDIO(struct ccw_device*, unsigned int flags,
unsigned int queue_number,
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 0a28e6d6ef4..76e424f718c 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -110,6 +110,7 @@ static inline void smp_send_stop(void)
__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
}
+#define hard_smp_processor_id() 0
#define smp_cpu_not_running(cpu) 1
#define smp_setup_cpu_possible_map() do { } while (0)
#endif
diff --git a/include/asm-sh/bug.h b/include/asm-sh/bug.h
index 2f89dd06d0c..46f925c815a 100644
--- a/include/asm-sh/bug.h
+++ b/include/asm-sh/bug.h
@@ -1,51 +1,81 @@
#ifndef __ASM_SH_BUG_H
#define __ASM_SH_BUG_H
-#ifdef CONFIG_BUG
-
-struct bug_frame {
- unsigned short opcode;
- unsigned short line;
- const char *file;
- const char *func;
-};
-
-struct pt_regs;
-
-extern void handle_BUG(struct pt_regs *);
-
#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
+#ifdef CONFIG_BUG
+#define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
+
+/**
+ * _EMIT_BUG_ENTRY
+ * %1 - __FILE__
+ * %2 - __LINE__
+ * %3 - trap type
+ * %4 - sizeof(struct bug_entry)
+ *
+ * The trapa opcode itself sits in %0.
+ * The %O notation is used to avoid # generation.
+ *
+ * The offending file and line are encoded in the __bug_table section.
+ */
#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _EMIT_BUG_ENTRY \
+ "\t.pushsection __bug_table,\"a\"\n" \
+ "2:\t.long 1b, %O1\n" \
+ "\t.short %O2, %O3\n" \
+ "\t.org 2b+%O4\n" \
+ "\t.popsection\n"
+#else
+#define _EMIT_BUG_ENTRY \
+ "\t.pushsection __bug_table,\"a\"\n" \
+ "2:\t.long 1b\n" \
+ "\t.short %O3\n" \
+ "\t.org 2b+%O4\n" \
+ "\t.popsection\n"
+#endif
#define BUG() \
do { \
__asm__ __volatile__ ( \
- ".align 2\n\t" \
- ".short %O0\n\t" \
- ".short %O1\n\t" \
- ".long %O2\n\t" \
- ".long %O3\n\t" \
- : \
- : "n" (TRAPA_BUG_OPCODE), \
- "i" (__LINE__), "X" (__FILE__), \
- "X" (__FUNCTION__)); \
+ "1:\t.short %O0\n" \
+ _EMIT_BUG_ENTRY \
+ : \
+ : "n" (TRAPA_BUG_OPCODE), \
+ "i" (__FILE__), \
+ "i" (__LINE__), "i" (0), \
+ "i" (sizeof(struct bug_entry))); \
} while (0)
-#else
-
-#define BUG() \
-do { \
- __asm__ __volatile__ ( \
- ".align 2\n\t" \
- ".short %O0\n\t" \
- : \
- : "n" (TRAPA_BUG_OPCODE)); \
+#define __WARN() \
+do { \
+ __asm__ __volatile__ ( \
+ "1:\t.short %O0\n" \
+ _EMIT_BUG_ENTRY \
+ : \
+ : "n" (TRAPA_BUG_OPCODE), \
+ "i" (__FILE__), \
+ "i" (__LINE__), \
+ "i" (BUGFLAG_WARNING), \
+ "i" (sizeof(struct bug_entry))); \
} while (0)
-#endif /* CONFIG_DEBUG_BUGVERBOSE */
+#define WARN_ON(x) ({ \
+ typeof(x) __ret_warn_on = (x); \
+ if (__builtin_constant_p(__ret_warn_on)) { \
+ if (__ret_warn_on) \
+ __WARN(); \
+ } else { \
+ if (unlikely(__ret_warn_on)) \
+ __WARN(); \
+ } \
+ unlikely(__ret_warn_on); \
+})
-#define HAVE_ARCH_BUG
+struct pt_regs;
+
+/* arch/sh/kernel/traps.c */
+void handle_BUG(struct pt_regs *);
#endif /* CONFIG_BUG */
diff --git a/include/asm-sh/clock.h b/include/asm-sh/clock.h
index 1df92807f8c..386d797d86b 100644
--- a/include/asm-sh/clock.h
+++ b/include/asm-sh/clock.h
@@ -13,7 +13,7 @@ struct clk_ops {
void (*enable)(struct clk *clk);
void (*disable)(struct clk *clk);
void (*recalc)(struct clk *clk);
- int (*set_rate)(struct clk *clk, unsigned long rate);
+ int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
};
struct clk {
@@ -48,6 +48,34 @@ void clk_recalc_rate(struct clk *);
int clk_register(struct clk *);
void clk_unregister(struct clk *);
-int show_clocks(struct seq_file *m);
+/* the exported API, in addition to clk_set_rate */
+/**
+ * clk_set_rate_ex - set the clock rate for a clock source, with additional parameter
+ * @clk: clock source
+ * @rate: desired clock rate in Hz
+ * @algo_id: algorithm id to be passed down to ops->set_rate
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id);
+enum clk_sh_algo_id {
+ NO_CHANGE = 0,
+
+ IUS_N1_N1,
+ IUS_322,
+ IUS_522,
+ IUS_N11,
+
+ SB_N1,
+
+ SB3_N1,
+ SB3_32,
+ SB3_43,
+ SB3_54,
+
+ BP_N1,
+
+ IP_N1,
+};
#endif /* __ASM_SH_CLOCK_H */
diff --git a/include/asm-sh/cpu-features.h b/include/asm-sh/cpu-features.h
index 4bccd7c032f..86308aa3973 100644
--- a/include/asm-sh/cpu-features.h
+++ b/include/asm-sh/cpu-features.h
@@ -20,5 +20,6 @@
#define CPU_HAS_PTEA 0x0020 /* PTEA register */
#define CPU_HAS_LLSC 0x0040 /* movli.l/movco.l */
#define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */
+#define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */
#endif /* __ASM_SH_CPU_FEATURES_H */
diff --git a/include/asm-sh/cpu-sh3/dma.h b/include/asm-sh/cpu-sh3/dma.h
index 954801b4602..3a66dc45802 100644
--- a/include/asm-sh/cpu-sh3/dma.h
+++ b/include/asm-sh/cpu-sh3/dma.h
@@ -26,7 +26,7 @@ enum {
XMIT_SZ_128BIT,
};
-static unsigned int ts_shift[] __attribute__ ((used)) = {
+static unsigned int ts_shift[] __maybe_unused = {
[XMIT_SZ_8BIT] = 0,
[XMIT_SZ_16BIT] = 1,
[XMIT_SZ_32BIT] = 2,
diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h
index bccb7ddb438..4704e86dff5 100644
--- a/include/asm-sh/cpu-sh3/mmu_context.h
+++ b/include/asm-sh/cpu-sh3/mmu_context.h
@@ -32,6 +32,7 @@
defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7300) || \
defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7712) || \
defined(CONFIG_CPU_SUBTYPE_SH7710)
#define INTEVT 0xa4000000 /* INTEVTE2(0xa4000000) */
#else
diff --git a/include/asm-sh/cpu-sh4/dma-sh7780.h b/include/asm-sh/cpu-sh4/dma-sh7780.h
index 6c90d28331b..71b426a6e48 100644
--- a/include/asm-sh/cpu-sh4/dma-sh7780.h
+++ b/include/asm-sh/cpu-sh4/dma-sh7780.h
@@ -28,7 +28,7 @@ enum {
/*
* The DMA count is defined as the number of bytes to transfer.
*/
-static unsigned int __attribute__ ((used)) ts_shift[] = {
+static unsigned int ts_shift[] __maybe_unused = {
[XMIT_SZ_8BIT] = 0,
[XMIT_SZ_16BIT] = 1,
[XMIT_SZ_32BIT] = 2,
diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
index c135e9cebd9..36e26a96476 100644
--- a/include/asm-sh/cpu-sh4/dma.h
+++ b/include/asm-sh/cpu-sh4/dma.h
@@ -53,7 +53,7 @@ enum {
/*
* The DMA count is defined as the number of bytes to transfer.
*/
-static unsigned int ts_shift[] __attribute__ ((used)) = {
+static unsigned int ts_shift[] __maybe_unused = {
[XMIT_SZ_64BIT] = 3,
[XMIT_SZ_8BIT] = 0,
[XMIT_SZ_16BIT] = 1,
diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h
index 602d061ca2d..86564e7a26a 100644
--- a/include/asm-sh/cpu-sh4/freq.h
+++ b/include/asm-sh/cpu-sh4/freq.h
@@ -12,8 +12,16 @@
#if defined(CONFIG_CPU_SUBTYPE_SH73180) || defined(CONFIG_CPU_SUBTYPE_SH7722)
#define FRQCR 0xa4150000
+#define VCLKCR 0xa4150004
+#define SCLKACR 0xa4150008
+#define SCLKBCR 0xa415000c
+#define IrDACLKCR 0xa4150010
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
#define FRQCR 0xffc80000
+#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
+#define FRQCR0 0xffc80000
+#define FRQCR1 0xffc80004
+#define FRQMR1 0xffc80014
#else
#define FRQCR 0xffc00000
#endif
diff --git a/include/asm-sh/dmabrg.h b/include/asm-sh/dmabrg.h
new file mode 100644
index 00000000000..c5edba216cf
--- /dev/null
+++ b/include/asm-sh/dmabrg.h
@@ -0,0 +1,23 @@
+/*
+ * SH7760 DMABRG (USB/Audio) support
+ */
+
+#ifndef _DMABRG_H_
+#define _DMABRG_H_
+
+/* IRQ sources */
+#define DMABRGIRQ_USBDMA 0
+#define DMABRGIRQ_USBDMAERR 1
+#define DMABRGIRQ_A0TXF 2
+#define DMABRGIRQ_A0TXH 3
+#define DMABRGIRQ_A0RXF 4
+#define DMABRGIRQ_A0RXH 5
+#define DMABRGIRQ_A1TXF 6
+#define DMABRGIRQ_A1TXH 7
+#define DMABRGIRQ_A1RXF 8
+#define DMABRGIRQ_A1RXH 9
+
+extern int dmabrg_request_irq(unsigned int, void(*)(void *), void *);
+extern void dmabrg_free_irq(unsigned int);
+
+#endif
diff --git a/include/asm-sh/edosk7705.h b/include/asm-sh/edosk7705.h
index a1089a65bc3..5bdc9d9be3d 100644
--- a/include/asm-sh/edosk7705.h
+++ b/include/asm-sh/edosk7705.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/edosk7705/io.h
+ * include/asm-sh/edosk7705.h
*
* Modified version of io_se.h for the EDOSK7705 specific functions.
*
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
index afe188f0ad5..e81bf21c801 100644
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -2,94 +2,13 @@
#define __ASM_SH_IRQ_H
#include <asm/machvec.h>
-#include <asm/ptrace.h> /* for pt_regs */
-/* NR_IRQS is made from three components:
- * 1. ONCHIP_NR_IRQS - number of IRLS + on-chip peripherial modules
- * 2. PINT_NR_IRQS - number of PINT interrupts
- * 3. OFFCHIP_NR_IRQS - numbe of IRQs from off-chip peripherial modules
+/*
+ * A sane default based on a reasonable vector table size, platforms are
+ * advised to cap this at the hard limit that they're interested in
+ * through the machvec.
*/
-
-/* 1. ONCHIP_NR_IRQS */
-#if defined(CONFIG_CPU_SUBTYPE_SH7604)
-# define ONCHIP_NR_IRQS 24 // Actually 21
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707)
-# define ONCHIP_NR_IRQS 64
-# define PINT_NR_IRQS 16
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
-# define ONCHIP_NR_IRQS 32
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709) || \
- defined(CONFIG_CPU_SUBTYPE_SH7706) || \
- defined(CONFIG_CPU_SUBTYPE_SH7705)
-# define ONCHIP_NR_IRQS 64 // Actually 61
-# define PINT_NR_IRQS 16
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
-# define ONCHIP_NR_IRQS 104
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
-# define ONCHIP_NR_IRQS 48 // Actually 44
-#elif defined(CONFIG_CPU_SUBTYPE_SH7751)
-# define ONCHIP_NR_IRQS 72
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
-# define ONCHIP_NR_IRQS 112 /* XXX */
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
-# define ONCHIP_NR_IRQS 72
-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
-# define ONCHIP_NR_IRQS 144
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH73180) || \
- defined(CONFIG_CPU_SUBTYPE_SH7343) || \
- defined(CONFIG_CPU_SUBTYPE_SH7722)
-# define ONCHIP_NR_IRQS 109
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-# define ONCHIP_NR_IRQS 111
-#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
-# define ONCHIP_NR_IRQS 256
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
-# define ONCHIP_NR_IRQS 128
-#elif defined(CONFIG_SH_UNKNOWN) /* Most be last */
-# define ONCHIP_NR_IRQS 144
-#endif
-
-/* 2. PINT_NR_IRQS */
-#ifdef CONFIG_SH_UNKNOWN
-# define PINT_NR_IRQS 16
-#else
-# ifndef PINT_NR_IRQS
-# define PINT_NR_IRQS 0
-# endif
-#endif
-
-#if PINT_NR_IRQS > 0
-# define PINT_IRQ_BASE ONCHIP_NR_IRQS
-#endif
-
-/* 3. OFFCHIP_NR_IRQS */
-#if defined(CONFIG_HD64461)
-# define OFFCHIP_NR_IRQS 18
-#elif defined(CONFIG_HD64465)
-# define OFFCHIP_NR_IRQS 16
-#elif defined (CONFIG_SH_DREAMCAST)
-# define OFFCHIP_NR_IRQS 96
-#elif defined (CONFIG_SH_TITAN)
-# define OFFCHIP_NR_IRQS 4
-#elif defined(CONFIG_SH_R7780RP)
-# define OFFCHIP_NR_IRQS 16
-#elif defined(CONFIG_SH_7343_SOLUTION_ENGINE)
-# define OFFCHIP_NR_IRQS 12
-#elif defined(CONFIG_SH_7722_SOLUTION_ENGINE)
-# define OFFCHIP_NR_IRQS 14
-#elif defined(CONFIG_SH_UNKNOWN)
-# define OFFCHIP_NR_IRQS 16 /* Must also be last */
-#else
-# define OFFCHIP_NR_IRQS 0
-#endif
-
-#if OFFCHIP_NR_IRQS > 0
-# define OFFCHIP_IRQ_BASE (ONCHIP_NR_IRQS + PINT_NR_IRQS)
-#endif
-
-/* NR_IRQS. 1+2+3 */
-#define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS)
+#define NR_IRQS 256
/*
* Convert back and forth between INTEVT and IRQ values.
diff --git a/include/asm-sh/kdebug.h b/include/asm-sh/kdebug.h
new file mode 100644
index 00000000000..16578b7c9da
--- /dev/null
+++ b/include/asm-sh/kdebug.h
@@ -0,0 +1,15 @@
+#ifndef __ASM_SH_KDEBUG_H
+#define __ASM_SH_KDEBUG_H
+
+#include <linux/notifier.h>
+
+/* Grossly misnamed. */
+enum die_val {
+ DIE_TRAP,
+ DIE_PAGE_FAULT,
+};
+
+int register_page_fault_notifier(struct notifier_block *nb);
+int unregister_page_fault_notifier(struct notifier_block *nb);
+
+#endif /* __ASM_SH_KDEBUG_H */
diff --git a/include/asm-sh/kexec.h b/include/asm-sh/kexec.h
index 9d235af20cd..00f4260ef09 100644
--- a/include/asm-sh/kexec.h
+++ b/include/asm-sh/kexec.h
@@ -1,5 +1,8 @@
-#ifndef _SH_KEXEC_H
-#define _SH_KEXEC_H
+#ifndef __ASM_SH_KEXEC_H
+#define __ASM_SH_KEXEC_H
+
+#include <asm/ptrace.h>
+#include <asm/string.h>
/*
* KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
@@ -23,10 +26,37 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_SH
-#define MAX_NOTE_BYTES 1024
-
-/* Provide a dummy definition to avoid build failures. */
static inline void crash_setup_regs(struct pt_regs *newregs,
- struct pt_regs *oldregs) { }
+ struct pt_regs *oldregs)
+{
+ if (oldregs)
+ memcpy(newregs, oldregs, sizeof(*newregs));
+ else {
+ __asm__ __volatile__ ("mov r0, %0" : "=r" (newregs->regs[0]));
+ __asm__ __volatile__ ("mov r1, %0" : "=r" (newregs->regs[1]));
+ __asm__ __volatile__ ("mov r2, %0" : "=r" (newregs->regs[2]));
+ __asm__ __volatile__ ("mov r3, %0" : "=r" (newregs->regs[3]));
+ __asm__ __volatile__ ("mov r4, %0" : "=r" (newregs->regs[4]));
+ __asm__ __volatile__ ("mov r5, %0" : "=r" (newregs->regs[5]));
+ __asm__ __volatile__ ("mov r6, %0" : "=r" (newregs->regs[6]));
+ __asm__ __volatile__ ("mov r7, %0" : "=r" (newregs->regs[7]));
+ __asm__ __volatile__ ("mov r8, %0" : "=r" (newregs->regs[8]));
+ __asm__ __volatile__ ("mov r9, %0" : "=r" (newregs->regs[9]));
+ __asm__ __volatile__ ("mov r10, %0" : "=r" (newregs->regs[10]));
+ __asm__ __volatile__ ("mov r11, %0" : "=r" (newregs->regs[11]));
+ __asm__ __volatile__ ("mov r12, %0" : "=r" (newregs->regs[12]));
+ __asm__ __volatile__ ("mov r13, %0" : "=r" (newregs->regs[13]));
+ __asm__ __volatile__ ("mov r14, %0" : "=r" (newregs->regs[14]));
+ __asm__ __volatile__ ("mov r15, %0" : "=r" (newregs->regs[15]));
+
+ __asm__ __volatile__ ("sts pr, %0" : "=r" (newregs->pr));
+ __asm__ __volatile__ ("sts macl, %0" : "=r" (newregs->macl));
+ __asm__ __volatile__ ("sts mach, %0" : "=r" (newregs->mach));
+
+ __asm__ __volatile__ ("stc gbr, %0" : "=r" (newregs->gbr));
+ __asm__ __volatile__ ("stc sr, %0" : "=r" (newregs->sr));
-#endif /* _SH_KEXEC_H */
+ newregs->pc = (unsigned long)current_text_addr();
+ }
+}
+#endif /* __ASM_SH_KEXEC_H */
diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h
index 0095c665d27..74bd0953e5c 100644
--- a/include/asm-sh/kgdb.h
+++ b/include/asm-sh/kgdb.h
@@ -17,6 +17,7 @@
#define __KGDB_H
#include <asm/ptrace.h>
+#include <asm/cacheflush.h>
struct console;
@@ -45,35 +46,21 @@ extern int kgdb_portnum;
extern int kgdb_baud;
extern char kgdb_parity;
extern char kgdb_bits;
-extern int kgdb_console_setup(struct console *, char *);
/* Init and interface stuff */
extern int kgdb_init(void);
-extern int (*kgdb_serial_setup)(void);
extern int (*kgdb_getchar)(void);
extern void (*kgdb_putchar)(int);
-struct kgdb_sermap {
- char *name;
- int namelen;
- int (*setup_fn)(struct console *, char *);
- struct kgdb_sermap *next;
-};
-extern void kgdb_register_sermap(struct kgdb_sermap *map);
-extern struct kgdb_sermap *kgdb_porttype;
-
/* Trap functions */
-typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
+typedef void (kgdb_debug_hook_t)(struct pt_regs *regs);
typedef void (kgdb_bus_error_hook_t)(void);
extern kgdb_debug_hook_t *kgdb_debug_hook;
extern kgdb_bus_error_hook_t *kgdb_bus_err_hook;
-extern void breakpoint(void);
-
/* Console */
-struct console;
void kgdb_console_write(struct console *co, const char *s, unsigned count);
-void kgdb_console_init(void);
+extern int kgdb_console_setup(struct console *, char *);
/* Prototypes for jmp fns */
#define _JBLEN 9
@@ -81,11 +68,8 @@ typedef int jmp_buf[_JBLEN];
extern void longjmp(jmp_buf __jmpb, int __retval);
extern int setjmp(jmp_buf __jmpb);
-/* Variadic macro to print our own message to the console */
-#define KGDB_PRINTK(...) printk("KGDB: " __VA_ARGS__)
-
/* Forced breakpoint */
-#define BREAKPOINT() \
+#define breakpoint() \
do { \
if (kgdb_enabled) \
__asm__ __volatile__("trapa #0x3c"); \
@@ -95,7 +79,6 @@ do { \
#if defined(CONFIG_CPU_SH4)
#define kgdb_flush_icache_range(start, end) \
{ \
- extern void __flush_purge_region(void *, int); \
__flush_purge_region((void*)(start), (int)(end) - (int)(start));\
flush_icache_range((start), (end)); \
}
@@ -103,31 +86,6 @@ do { \
#define kgdb_flush_icache_range(start, end) do { } while (0)
#endif
-/* Kernel assert macros */
-#ifdef CONFIG_KGDB_KERNEL_ASSERTS
-
-/* Predefined conditions */
-#define KA_VALID_ERRNO(errno) ((errno) > 0 && (errno) <= EMEDIUMTYPE)
-#define KA_VALID_PTR_ERR(ptr) KA_VALID_ERRNO(-PTR_ERR(ptr))
-#define KA_VALID_KPTR(ptr) (!(ptr) || \
- ((void *)(ptr) >= (void *)PAGE_OFFSET && \
- (void *)(ptr) < ERR_PTR(-EMEDIUMTYPE)))
-#define KA_VALID_PTRORERR(errptr) \
- (KA_VALID_KPTR(errptr) || KA_VALID_PTR_ERR(errptr))
-#define KA_HELD_GKL() (current->lock_depth >= 0)
-
-/* The actual assert */
-#define KGDB_ASSERT(condition, message) do { \
- if (!(condition) && (kgdb_enabled)) { \
- KGDB_PRINTK("Assertion failed at %s:%d: %s\n", \
- __FILE__, __LINE__, message);\
- BREAKPOINT(); \
- } \
-} while (0)
-#else
-#define KGDB_ASSERT(condition, message)
-#endif
-
/* Taken from sh-stub.c of GDB 4.18 */
static const char hexchars[] = "0123456789abcdef";
@@ -142,5 +100,4 @@ static inline char lowhex(const int x)
{
return hexchars[x & 0xf];
}
-
#endif
diff --git a/include/asm-sh/lboxre2.h b/include/asm-sh/lboxre2.h
new file mode 100644
index 00000000000..e6d16050492
--- /dev/null
+++ b/include/asm-sh/lboxre2.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_SH_LBOXRE2_H
+#define __ASM_SH_LBOXRE2_H
+
+/*
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * NTT COMWARE L-BOX RE2 support
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#define IRQ_CF1 9 /* CF1 */
+#define IRQ_CF0 10 /* CF0 */
+#define IRQ_INTD 11 /* INTD */
+#define IRQ_ETH1 12 /* Ether1 */
+#define IRQ_ETH0 13 /* Ether0 */
+#define IRQ_INTA 14 /* INTA */
+
+void init_lboxre2_IRQ(void);
+
+#define __IO_PREFIX lboxre2
+#include <asm/io_generic.h>
+
+#endif /* __ASM_SH_LBOXRE2_H */
diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
index 342024425b7..199662bb35c 100644
--- a/include/asm-sh/mmu_context.h
+++ b/include/asm-sh/mmu_context.h
@@ -12,6 +12,7 @@
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm-generic/mm_hooks.h>
/*
* The MMU "context" consists of two things:
@@ -168,6 +169,8 @@ enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
#define destroy_context(mm) do { } while (0)
#define set_asid(asid) do { } while (0)
#define get_asid() (0)
+#define set_TTB(pgd) do { } while (0)
+#define get_TTB() (0)
#define activate_context(mm,cpu) do { } while (0)
#define switch_mm(prev,next,tsk) do { } while (0)
#define deactivate_mm(tsk,mm) do { } while (0)
@@ -210,8 +213,8 @@ static inline void disable_mmu(void)
* MMU control handlers for processors lacking memory
* management hardware.
*/
-#define enable_mmu() do { BUG(); } while (0)
-#define disable_mmu() do { BUG(); } while (0)
+#define enable_mmu() do { } while (0)
+#define disable_mmu() do { } while (0)
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index ac4b4677f28..7464de4ba07 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -59,6 +59,7 @@ extern void (*clear_page)(void *to);
extern void (*copy_page)(void *to, void *from);
extern unsigned long shm_align_mask;
+extern unsigned long max_low_pfn, min_low_pfn;
#ifdef CONFIG_MMU
extern void clear_page_slow(void *to);
@@ -124,17 +125,16 @@ typedef struct { unsigned long pgd; } pgd_t;
#define PAGE_OFFSET CONFIG_PAGE_OFFSET
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
+#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-#define MAP_NR(addr) (((unsigned long)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
-
-#define phys_to_page(phys) (mem_map + (((phys)-__MEMORY_START) >> PAGE_SHIFT))
-#define page_to_phys(page) (((page - mem_map) << PAGE_SHIFT) + __MEMORY_START)
+#define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT))
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
/* PFN start number, because of __MEMORY_START */
#define PFN_START (__MEMORY_START >> PAGE_SHIFT)
#define ARCH_PFN_OFFSET (PFN_START)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
-#define pfn_valid(pfn) (((pfn) - PFN_START) < max_mapnr)
+#define pfn_valid(pfn) ((pfn) >= min_low_pfn && (pfn) < max_low_pfn)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
diff --git a/include/asm-sh/param.h b/include/asm-sh/param.h
index ce13064fec2..1012296e07a 100644
--- a/include/asm-sh/param.h
+++ b/include/asm-sh/param.h
@@ -5,7 +5,7 @@
# ifdef CONFIG_SH_WDT
# define HZ 1000 /* Needed for high-res WOVF */
# else
-# define HZ 100
+# define HZ CONFIG_HZ
# endif
# define USER_HZ 100 /* User interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ) /* frequency at which times() counts */
diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
index 6ccc948fe21..b1f9a9e0231 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -35,7 +35,7 @@ extern struct pci_channel board_pci_channels[];
/*
* I/O routine helpers
*/
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
#define PCI_IO_AREA 0xFE400000
#define PCI_IO_SIZE 0x00400000
#else
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
index 888e4529e6f..18b613c57cf 100644
--- a/include/asm-sh/pgalloc.h
+++ b/include/asm-sh/pgalloc.h
@@ -1,6 +1,12 @@
#ifndef __ASM_SH_PGALLOC_H
#define __ASM_SH_PGALLOC_H
+#include <linux/quicklist.h>
+#include <asm/page.h>
+
+#define QUICK_PGD 0 /* We preserve special mappings over free */
+#define QUICK_PT 1 /* Other page table pages that are zero on free */
+
static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
pte_t *pte)
{
@@ -13,48 +19,49 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
}
+static inline void pgd_ctor(void *x)
+{
+ pgd_t *pgd = x;
+
+ memcpy(pgd + USER_PTRS_PER_PGD,
+ swapper_pg_dir + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
/*
* Allocate and free page tables.
*/
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
-
- if (pgd) {
- memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
- memcpy(pgd + USER_PTRS_PER_PGD,
- swapper_pg_dir + USER_PTRS_PER_PGD,
- (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
- }
-
- return pgd;
+ return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
}
static inline void pgd_free(pgd_t *pgd)
{
- free_page((unsigned long)pgd);
+ quicklist_free(QUICK_PGD, NULL, pgd);
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
unsigned long address)
{
- return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+ return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
}
static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long address)
{
- return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
+ void *pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL);
+ return pg ? virt_to_page(pg) : NULL;
}
static inline void pte_free_kernel(pte_t *pte)
{
- free_page((unsigned long)pte);
+ quicklist_free(QUICK_PT, NULL, pte);
}
static inline void pte_free(struct page *pte)
{
- __free_page(pte);
+ quicklist_free_page(QUICK_PT, NULL, pte);
}
#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
@@ -66,6 +73,11 @@ static inline void pte_free(struct page *pte)
#define pmd_free(x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
-#define check_pgt_cache() do { } while (0)
+
+static inline void check_pgt_cache(void)
+{
+ quicklist_trim(QUICK_PGD, NULL, 25, 16);
+ quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
#endif /* __ASM_SH_PGALLOC_H */
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index 184d7fcaaf1..5b523c7e7d9 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -568,10 +568,6 @@ typedef pte_t *pte_addr_t;
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
struct mm_struct;
/*
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index 3e46a7afe76..d42f68e724f 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -44,7 +44,7 @@ enum cpu_type {
/* SH-3 types */
CPU_SH7705, CPU_SH7706, CPU_SH7707,
CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
- CPU_SH7709, CPU_SH7709A, CPU_SH7710,
+ CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712,
CPU_SH7729, CPU_SH7300,
/* SH-4 types */
diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h
index c18f648a799..4083b594992 100644
--- a/include/asm-sh/r7780rp.h
+++ b/include/asm-sh/r7780rp.h
@@ -1,17 +1,11 @@
#ifndef __ASM_SH_RENESAS_R7780RP_H
#define __ASM_SH_RENESAS_R7780RP_H
-/*
- * linux/include/asm-sh/r7780rp.h
- *
- * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
- *
- * Renesas Solutions Highlander R7780RP support
- */
-
/* Box specific addresses. */
#if defined(CONFIG_SH_R7780MP)
#define PA_BCR 0xa4000000 /* FPGA */
+#define PA_SDPOW (-1)
+
#define PA_IRLMSK (PA_BCR+0x0000) /* Interrupt Mask control */
#define PA_IRLMON (PA_BCR+0x0002) /* Interrupt Status control */
#define PA_IRLPRI1 (PA_BCR+0x0004) /* Interrupt Priorty 1 */
@@ -70,18 +64,12 @@
#define PA_POFF (PA_BCR+0x0800) /* System Power Off control */
#define PA_PMR (PA_BCR+0x0900) /* */
-#define PA_AX88796L 0xa4100400 /* AX88796L Area */
-#define PA_SC1602BSLB 0xa6000000 /* SC1602BSLB Area */
-#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
-#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
-
#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
#define IRQ_PCISLOT1 65 /* PCI Slot #1 IRQ */
#define IRQ_PCISLOT2 66 /* PCI Slot #2 IRQ */
#define IRQ_PCISLOT3 67 /* PCI Slot #3 IRQ */
#define IRQ_PCISLOT4 68 /* PCI Slot #4 IRQ */
-// #define IRQ_CFINST 0 /* CF Card Insert IRQ */
#define IRQ_TP 2 /* Touch Panel IRQ */
#define IRQ_SCI1 3 /* SCI1 IRQ */
#define IRQ_SCI0 4 /* SCI0 IRQ */
@@ -95,7 +83,10 @@
#define IRQ_ONETH 13 /* On board Ethernet IRQ */
#define IRQ_PSW 14 /* Push Switch IRQ */
-#else /* R7780RP */
+#define IVDR_CK_ON 8 /* iVDR Clock ON */
+
+#elif defined(CONFIG_SH_R7780RP)
+#define PA_POFF (-1)
#define PA_BCR 0xa5000000 /* FPGA */
#define PA_IRLMSK (PA_BCR+0x0000) /* Interrupt Mask control */
@@ -163,7 +154,60 @@
#define IRQ_PSW 13 /* Push Switch IRQ */
#define IRQ_ZIGBEE 14 /* Ziggbee IO IRQ */
-#endif /* CONFIG_SH_R7780MP */
+#define IVDR_CK_ON 8 /* iVDR Clock ON */
+
+#elif defined(CONFIG_SH_R7785RP)
+#define PA_BCR 0xa4000000 /* FPGA */
+#define PA_SDPOW (-1)
+
+#define PA_PCISCR (PA_BCR+0x0000)
+#define PA_IRLPRA (PA_BCR+0x0002)
+#define PA_IRLPRB (PA_BCR+0x0004)
+#define PA_IRLPRC (PA_BCR+0x0006)
+#define PA_IRLPRD (PA_BCR+0x0008)
+#define IRLCNTR1 (PA_BCR+0x0010)
+#define PA_IRLPRE (PA_BCR+0x000a)
+#define PA_IRLPRF (PA_BCR+0x000c)
+#define PA_EXIRLCR (PA_BCR+0x000e)
+#define PA_IRLMCR1 (PA_BCR+0x0010)
+#define PA_IRLMCR2 (PA_BCR+0x0012)
+#define PA_IRLSSR1 (PA_BCR+0x0014)
+#define PA_IRLSSR2 (PA_BCR+0x0016)
+#define PA_CFTCR (PA_BCR+0x0100)
+#define PA_CFPCR (PA_BCR+0x0102)
+#define PA_PCICR (PA_BCR+0x0110)
+#define PA_IVDRCTL (PA_BCR+0x0112)
+#define PA_IVDRSR (PA_BCR+0x0114)
+#define PA_PDRSTCR (PA_BCR+0x0116)
+#define PA_POFF (PA_BCR+0x0120)
+#define PA_LCDCR (PA_BCR+0x0130)
+#define PA_TPCR (PA_BCR+0x0140)
+#define PA_TPCKCR (PA_BCR+0x0142)
+#define PA_TPRSTR (PA_BCR+0x0144)
+#define PA_TPXPDR (PA_BCR+0x0146)
+#define PA_TPYPDR (PA_BCR+0x0148)
+#define PA_GPIOPFR (PA_BCR+0x0150)
+#define PA_GPIODR (PA_BCR+0x0152)
+#define PA_OBLED (PA_BCR+0x0154)
+#define PA_SWSR (PA_BCR+0x0156)
+#define PA_VERREG (PA_BCR+0x0158)
+#define PA_SMCR (PA_BCR+0x0200)
+#define PA_SMSMADR (PA_BCR+0x0202)
+#define PA_SMMR (PA_BCR+0x0204)
+#define PA_SMSADR1 (PA_BCR+0x0206)
+#define PA_SMSADR32 (PA_BCR+0x0244)
+#define PA_SMTRDR1 (PA_BCR+0x0246)
+#define PA_SMTRDR16 (PA_BCR+0x0264)
+#define PA_CU3MDR (PA_BCR+0x0300)
+#define PA_CU5MDR (PA_BCR+0x0302)
+#define PA_MMSR (PA_BCR+0x0400)
+
+#define IVDR_CK_ON 4 /* iVDR Clock ON */
+
+#endif
+
+void make_r7780rp_irq(unsigned int irq);
+void highlander_init_irq(void);
#define __IO_PREFIX r7780rp
#include <asm/io_generic.h>
diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h
index d19e7cd3b02..b9ae53c3836 100644
--- a/include/asm-sh/scatterlist.h
+++ b/include/asm-sh/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef __ASM_SH_SCATTERLIST_H
#define __ASM_SH_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page * page; /* Location for highmem page, if any */
unsigned int offset;/* for highmem, page offset */
diff --git a/include/asm-sh/se.h b/include/asm-sh/se.h
index a1832154a3a..bd2596c014a 100644
--- a/include/asm-sh/se.h
+++ b/include/asm-sh/se.h
@@ -69,9 +69,11 @@
#define BCR_ILCRG (PA_BCR + 12)
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
-#define IRQ_STNIC 12
+#define IRQ_STNIC 12
+#define IRQ_CFCARD 14
#else
#define IRQ_STNIC 10
+#define IRQ_CFCARD 7
#endif
#define __IO_PREFIX se
diff --git a/include/asm-sh/se7722.h b/include/asm-sh/se7722.h
new file mode 100644
index 00000000000..b3b31e4725c
--- /dev/null
+++ b/include/asm-sh/se7722.h
@@ -0,0 +1,118 @@
+#ifndef __ASM_SH_SE7722_H
+#define __ASM_SH_SE7722_H
+
+/*
+ * linux/include/asm-sh/se7722.h
+ *
+ * Copyright (C) 2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7722 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <asm/addrspace.h>
+
+/* Box specific addresses. */
+#define SE_AREA0_WIDTH 4 /* Area0: 32bit */
+#define PA_ROM 0xa0000000 /* EPROM */
+#define PA_ROM_SIZE 0x00200000 /* EPROM size 2M byte */
+#define PA_FROM 0xa1000000 /* Flash-ROM */
+#define PA_FROM_SIZE 0x01000000 /* Flash-ROM size 16M byte */
+#define PA_EXT1 0xa4000000
+#define PA_EXT1_SIZE 0x04000000
+#define PA_SDRAM 0xaC000000 /* DDR-SDRAM(Area3) 64MB */
+#define PA_SDRAM_SIZE 0x04000000
+
+#define PA_EXT4 0xb0000000
+#define PA_EXT4_SIZE 0x04000000
+
+#define PA_PERIPHERAL 0xB0000000
+
+#define PA_PCIC PA_PERIPHERAL /* MR-SHPC-01 PCMCIA */
+#define PA_MRSHPC (PA_PERIPHERAL + 0x003fffe0) /* MR-SHPC-01 PCMCIA controller */
+#define PA_MRSHPC_MW1 (PA_PERIPHERAL + 0x00400000) /* MR-SHPC-01 memory window base */
+#define PA_MRSHPC_MW2 (PA_PERIPHERAL + 0x00500000) /* MR-SHPC-01 attribute window base */
+#define PA_MRSHPC_IO (PA_PERIPHERAL + 0x00600000) /* MR-SHPC-01 I/O window base */
+#define MRSHPC_OPTION (PA_MRSHPC + 6)
+#define MRSHPC_CSR (PA_MRSHPC + 8)
+#define MRSHPC_ISR (PA_MRSHPC + 10)
+#define MRSHPC_ICR (PA_MRSHPC + 12)
+#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+#define MRSHPC_CDCR (PA_MRSHPC + 28)
+#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+
+#define PA_LED (PA_PERIPHERAL + 0x00800000) /* 8bit LED */
+#define PA_FPGA (PA_PERIPHERAL + 0x01800000) /* FPGA base address */
+
+#define PA_LAN (PA_AREA6_IO + 0) /* SMC LAN91C111 */
+/* GPIO */
+#define MSTPCR0 0xA4150030UL
+#define MSTPCR1 0xA4150034UL
+#define MSTPCR2 0xA4150038UL
+
+#define FPGA_IN 0xb1840000UL
+#define FPGA_OUT 0xb1840004UL
+
+#define PORT_PECR 0xA4050108UL
+#define PORT_PJCR 0xA4050110UL
+#define PORT_PSELD 0xA4050154UL
+#define PORT_PSELB 0xA4050150UL
+
+#define PORT_PSELC 0xA4050152UL
+#define PORT_PKCR 0xA4050112UL
+#define PORT_PHCR 0xA405010EUL
+#define PORT_PLCR 0xA4050114UL
+#define PORT_PMCR 0xA4050116UL
+#define PORT_PRCR 0xA405011CUL
+#define PORT_PXCR 0xA4050148UL
+#define PORT_PSELA 0xA405014EUL
+#define PORT_PYCR 0xA405014AUL
+#define PORT_PZCR 0xA405014CUL
+
+/* IRQ */
+#define IRQ0_IRQ 32
+#define IRQ1_IRQ 33
+#define INTC_ICR0 0xA4140000UL
+#define INTC_ICR1 0xA414001CUL
+
+#define INTMSK0 0xa4140044
+#define INTMSKCLR0 0xa4140064
+#define INTC_INTPRI0 0xa4140010
+
+#define IRQ01_MODE 0xb1800000
+#define IRQ01_STS 0xb1800004
+#define IRQ01_MASK 0xb1800008
+#define EXT_BIT (0x3fc0) /* SH IRQ1 */
+#define MRSHPC_BIT0 (0x0004) /* SH IRQ1 */
+#define MRSHPC_BIT1 (0x0008) /* SH IRQ1 */
+#define MRSHPC_BIT2 (0x0010) /* SH IRQ1 */
+#define MRSHPC_BIT3 (0x0020) /* SH IRQ1 */
+#define SMC_BIT (0x0002) /* SH IRQ0 */
+#define USB_BIT (0x0001) /* SH IRQ0 */
+
+#define MRSHPC_IRQ3 11
+#define MRSHPC_IRQ2 12
+#define MRSHPC_IRQ1 13
+#define MRSHPC_IRQ0 14
+#define SMC_IRQ 10
+#define EXT_IRQ 5
+#define USB_IRQ 6
+
+
+/* arch/sh/boards/se/7722/irq.c */
+void init_se7722_IRQ(void);
+int se7722_irq_demux(int);
+
+#define __IO_PREFIX se7722
+#include <asm/io_generic.h>
+
+#endif /* __ASM_SH_SE7722_H */
diff --git a/include/asm-sh/se7751.h b/include/asm-sh/se7751.h
index 88cd379d908..02ca9347f04 100644
--- a/include/asm-sh/se7751.h
+++ b/include/asm-sh/se7751.h
@@ -65,6 +65,8 @@
#define IRQ_79C973 13
+void init_7751se_IRQ(void);
+
#define __IO_PREFIX sh7751se
#include <asm/io_generic.h>
diff --git a/include/asm-sh/se7780.h b/include/asm-sh/se7780.h
new file mode 100644
index 00000000000..40e9b41458c
--- /dev/null
+++ b/include/asm-sh/se7780.h
@@ -0,0 +1,108 @@
+#ifndef __ASM_SH_SE7780_H
+#define __ASM_SH_SE7780_H
+
+/*
+ * linux/include/asm-sh/se7780.h
+ *
+ * Copyright (C) 2006,2007 Nobuhiro Iwamatsu
+ *
+ * Hitachi UL SolutionEngine 7780 Support.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <asm/addrspace.h>
+
+/* Box specific addresses. */
+#define SE_AREA0_WIDTH 4 /* Area0: 32bit */
+#define PA_ROM 0xa0000000 /* EPROM */
+#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte */
+#define PA_FROM 0xa1000000 /* Flash-ROM */
+#define PA_FROM_SIZE 0x01000000 /* Flash-ROM size 16M byte */
+#define PA_EXT1 0xa4000000
+#define PA_EXT1_SIZE 0x04000000
+#define PA_SM501 PA_EXT1 /* Graphic IC (SM501) */
+#define PA_SM501_SIZE PA_EXT1_SIZE /* Graphic IC (SM501) */
+#define PA_SDRAM 0xa8000000 /* DDR-SDRAM(Area2/3) 128MB */
+#define PA_SDRAM_SIZE 0x08000000
+
+#define PA_EXT4 0xb0000000
+#define PA_EXT4_SIZE 0x04000000
+#define PA_EXT_FLASH PA_EXT4 /* Expansion Flash-ROM */
+
+#define PA_PERIPHERAL PA_AREA6_IO /* SW6-6=ON */
+
+#define PA_LAN (PA_PERIPHERAL + 0) /* SMC LAN91C111 */
+#define PA_LED_DISP (PA_PERIPHERAL + 0x02000000) /* 8words LED Display */
+#define DISP_CHAR_RAM (7 << 3)
+#define DISP_SEL0_ADDR (DISP_CHAR_RAM + 0)
+#define DISP_SEL1_ADDR (DISP_CHAR_RAM + 1)
+#define DISP_SEL2_ADDR (DISP_CHAR_RAM + 2)
+#define DISP_SEL3_ADDR (DISP_CHAR_RAM + 3)
+#define DISP_SEL4_ADDR (DISP_CHAR_RAM + 4)
+#define DISP_SEL5_ADDR (DISP_CHAR_RAM + 5)
+#define DISP_SEL6_ADDR (DISP_CHAR_RAM + 6)
+#define DISP_SEL7_ADDR (DISP_CHAR_RAM + 7)
+
+#define DISP_UDC_RAM (5 << 3)
+#define PA_FPGA (PA_PERIPHERAL + 0x03000000) /* FPGA base address */
+
+/* FPGA register address and bit */
+#define FPGA_SFTRST (PA_FPGA + 0) /* Soft reset register */
+#define FPGA_INTMSK1 (PA_FPGA + 2) /* Interrupt Mask register 1 */
+#define FPGA_INTMSK2 (PA_FPGA + 4) /* Interrupt Mask register 2 */
+#define FPGA_INTSEL1 (PA_FPGA + 6) /* Interrupt select register 1 */
+#define FPGA_INTSEL2 (PA_FPGA + 8) /* Interrupt select register 2 */
+#define FPGA_INTSEL3 (PA_FPGA + 10) /* Interrupt select register 3 */
+#define FPGA_PCI_INTSEL1 (PA_FPGA + 12) /* PCI Interrupt select register 1 */
+#define FPGA_PCI_INTSEL2 (PA_FPGA + 14) /* PCI Interrupt select register 2 */
+#define FPGA_INTSET (PA_FPGA + 16) /* IRQ/IRL select register */
+#define FPGA_INTSTS1 (PA_FPGA + 18) /* Interrupt status register 1 */
+#define FPGA_INTSTS2 (PA_FPGA + 20) /* Interrupt status register 2 */
+#define FPGA_REQSEL (PA_FPGA + 22) /* REQ/GNT select register */
+#define FPGA_DBG_LED (PA_FPGA + 32) /* Debug LED(D-LED[8:1] */
+#define PA_LED FPGA_DBG_LED
+#define FPGA_IVDRID (PA_FPGA + 36) /* iVDR ID Register */
+#define FPGA_IVDRPW (PA_FPGA + 38) /* iVDR Power ON Register */
+#define FPGA_MMCID (PA_FPGA + 40) /* MMC ID Register */
+
+/* FPGA INTSEL position */
+/* INTSEL1 */
+#define IRQPOS_SMC91CX (0 * 4)
+#define IRQPOS_SM501 (1 * 4)
+/* INTSEL2 */
+#define IRQPOS_EXTINT1 (0 * 4)
+#define IRQPOS_EXTINT2 (1 * 4)
+#define IRQPOS_EXTINT3 (2 * 4)
+#define IRQPOS_EXTINT4 (3 * 4)
+/* INTSEL3 */
+#define IRQPOS_PCCPW (0 * 4)
+
+/* IDE interrupt */
+#define IRQ_IDE0 67 /* iVDR */
+
+/* SMC interrupt */
+#define SMC_IRQ 8
+
+/* SM501 interrupt */
+#define SM501_IRQ 0
+
+/* interrupt pin */
+#define IRQPIN_EXTINT1 0 /* IRQ0 pin */
+#define IRQPIN_EXTINT2 1 /* IRQ1 pin */
+#define IRQPIN_EXTINT3 2 /* IRQ2 pin */
+#define IRQPIN_SMC91CX 3 /* IRQ3 pin */
+#define IRQPIN_EXTINT4 4 /* IRQ4 pin */
+#define IRQPIN_PCC0 5 /* IRQ5 pin */
+#define IRQPIN_PCC2 6 /* IRQ6 pin */
+#define IRQPIN_SM501 7 /* IRQ7 pin */
+#define IRQPIN_PCCPW 7 /* IRQ7 pin */
+
+/* arch/sh/boards/se/7780/irq.c */
+void init_se7780_IRQ(void);
+
+#define __IO_PREFIX se7780
+#include <asm/io_generic.h>
+
+#endif /* __ASM_SH_SE7780_H */
diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h
index 6b5e4ddc073..2d712e72c9e 100644
--- a/include/asm-sh/snapgear.h
+++ b/include/asm-sh/snapgear.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/snapgear/io.h
+ * include/asm-sh/snapgear.h
*
* Modified version of io_se.h for the snapgear-specific functions.
*
diff --git a/include/asm-sh/stat.h b/include/asm-sh/stat.h
index 6c41a60657f..6d6ad26e3a2 100644
--- a/include/asm-sh/stat.h
+++ b/include/asm-sh/stat.h
@@ -16,15 +16,13 @@ struct __old_kernel_stat {
};
struct stat {
- unsigned short st_dev;
- unsigned short __pad1;
- unsigned long st_ino;
+ unsigned long st_dev;
+ unsigned long st_ino;
unsigned short st_mode;
unsigned short st_nlink;
unsigned short st_uid;
unsigned short st_gid;
- unsigned short st_rdev;
- unsigned short __pad2;
+ unsigned long st_rdev;
unsigned long st_size;
unsigned long st_blksize;
unsigned long st_blocks;
@@ -38,8 +36,6 @@ struct stat {
unsigned long __unused5;
};
-#define STAT_HAVE_NSEC 1
-
/* This matches struct stat64 in glibc2.1, hence the absolutely
* insane amounts of padding around dev_t's.
*/
@@ -47,7 +43,9 @@ struct stat64 {
unsigned long long st_dev;
unsigned char __pad0[4];
- unsigned long st_ino;
+#define STAT64_HAS_BROKEN_ST_INO 1
+ unsigned long __st_ino;
+
unsigned int st_mode;
unsigned int st_nlink;
@@ -71,8 +69,9 @@ struct stat64 {
unsigned long st_ctime;
unsigned long st_ctime_nsec;
- unsigned long __unused1;
- unsigned long __unused2;
+ unsigned long long st_ino;
};
+#define STAT_HAVE_NSEC 1
+
#endif /* __ASM_SH_STAT_H */
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index 4a6a19f4f8a..82f3e229e62 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -9,6 +9,7 @@
#include <linux/irqflags.h>
#include <linux/compiler.h>
#include <asm/types.h>
+#include <asm/ptrace.h>
/*
* switch_to() should switch tasks to task nr n, first
@@ -81,16 +82,6 @@ static inline void sched_cacheflush(void)
}
#endif
-static inline unsigned long tas(volatile int *m)
-{
- unsigned long retval;
-
- __asm__ __volatile__ ("tas.b @%1\n\t"
- "movt %0"
- : "=r" (retval): "r" (m): "t", "memory");
- return retval;
-}
-
/*
* A brief note on ctrl_barrier(), the control register write barrier.
*
@@ -255,6 +246,8 @@ static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
(unsigned long)_n_, sizeof(*(ptr))); \
})
+extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
+
extern void *set_exception_table_vec(unsigned int vec, void *handler);
static inline void *set_exception_table_evt(unsigned int evt, void *handler)
@@ -262,6 +255,15 @@ static inline void *set_exception_table_evt(unsigned int evt, void *handler)
return set_exception_table_vec(evt >> 5, handler);
}
+/*
+ * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks.
+ */
+#ifdef CONFIG_CPU_SH2A
+extern unsigned int instruction_size(unsigned int insn);
+#else
+#define instruction_size(insn) (2)
+#endif
+
/* XXX
* disable hlt during certain critical i/o operations
*/
diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h
index 17b5e76a4c3..701ba84c704 100644
--- a/include/asm-sh/timer.h
+++ b/include/asm-sh/timer.h
@@ -2,12 +2,14 @@
#define __ASM_SH_TIMER_H
#include <linux/sysdev.h>
+#include <linux/clocksource.h>
#include <asm/cpu/timer.h>
struct sys_timer_ops {
int (*init)(void);
int (*start)(void);
int (*stop)(void);
+ cycle_t (*read)(void);
#ifndef CONFIG_GENERIC_TIME
unsigned long (*get_offset)(void);
#endif
@@ -18,29 +20,8 @@ struct sys_timer {
struct sys_device dev;
struct sys_timer_ops *ops;
-
-#ifdef CONFIG_NO_IDLE_HZ
- struct dyn_tick_timer *dyn_tick;
-#endif
};
-#ifdef CONFIG_NO_IDLE_HZ
-#define DYN_TICK_ENABLED (1 << 1)
-
-struct dyn_tick_timer {
- spinlock_t lock;
- unsigned int state; /* Current state */
- int (*enable)(void); /* Enables dynamic tick */
- int (*disable)(void); /* Disables dynamic tick */
- void (*reprogram)(unsigned long); /* Reprograms the timer */
- int (*handler)(int, void *);
-};
-
-void timer_dyn_reprogram(void);
-#else
-#define timer_dyn_reprogram() do { } while (0)
-#endif
-
#define TICK_SIZE (tick_nsec / 1000)
extern struct sys_timer tmu_timer, cmt_timer, mtu2_timer;
@@ -58,5 +39,7 @@ struct sys_timer *get_sys_timer(void);
/* arch/sh/kernel/time.c */
void handle_timer_tick(void);
+extern unsigned long sh_hpt_frequency;
+extern struct clocksource clocksource_sh;
#endif /* __ASM_SH_TIMER_H */
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 49be50a36b7..af71e379a5e 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -85,7 +85,7 @@
#define __NR_sigpending 73
#define __NR_sethostname 74
#define __NR_setrlimit 75
-#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
+#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
#define __NR_getrusage 77
#define __NR_gettimeofday 78
#define __NR_settimeofday 79
@@ -328,8 +328,9 @@
#define __NR_move_pages 317
#define __NR_getcpu 318
#define __NR_epoll_pwait 319
+#define __NR_utimensat 320
-#define NR_syscalls 320
+#define NR_syscalls 321
#ifdef __KERNEL__
diff --git a/include/asm-sh64/kdebug.h b/include/asm-sh64/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-sh64/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-sh64/mmu_context.h b/include/asm-sh64/mmu_context.h
index 8c860dab2d0..507bf72bb8e 100644
--- a/include/asm-sh64/mmu_context.h
+++ b/include/asm-sh64/mmu_context.h
@@ -27,7 +27,7 @@
extern unsigned long mmu_context_cache;
#include <asm/page.h>
-
+#include <asm-generic/mm_hooks.h>
/* Current mm's pgd */
extern pgd_t *mmu_pdtp_cache;
diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
index 6b97c4cb1d6..b875482eb59 100644
--- a/include/asm-sh64/pgtable.h
+++ b/include/asm-sh64/pgtable.h
@@ -485,10 +485,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#endif /* !__ASSEMBLY__ */
/*
diff --git a/include/asm-sh64/scatterlist.h b/include/asm-sh64/scatterlist.h
index 5d8fa32d2e9..1c723f2d7a9 100644
--- a/include/asm-sh64/scatterlist.h
+++ b/include/asm-sh64/scatterlist.h
@@ -11,6 +11,8 @@
#ifndef __ASM_SH64_SCATTERLIST_H
#define __ASM_SH64_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page * page; /* Location for highmem page, if any */
unsigned int offset;/* for highmem, page offset */
diff --git a/include/asm-sh64/system.h b/include/asm-sh64/system.h
index b1598c26fcb..5ff94644e8c 100644
--- a/include/asm-sh64/system.h
+++ b/include/asm-sh64/system.h
@@ -43,8 +43,6 @@ extern struct task_struct *sh64_switch_to(struct task_struct *prev,
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr), 1))
-
extern void __xchg_called_with_bad_pointer(void);
#define mb() __asm__ __volatile__ ("synco": : :"memory")
diff --git a/include/asm-sparc/kdebug.h b/include/asm-sparc/kdebug.h
index fba92485fdb..404d8076732 100644
--- a/include/asm-sparc/kdebug.h
+++ b/include/asm-sparc/kdebug.h
@@ -66,4 +66,8 @@ static inline void sp_enter_debugger(void)
#define KDEBUG_DUNNO2_OFF 0x8
#define KDEBUG_TEACH_OFF 0xc
+enum die_val {
+ DIE_UNUSED,
+};
+
#endif /* !(_SPARC_KDEBUG_H) */
diff --git a/include/asm-sparc/mmu_context.h b/include/asm-sparc/mmu_context.h
index ed1e01d04d2..671a997b9e6 100644
--- a/include/asm-sparc/mmu_context.h
+++ b/include/asm-sparc/mmu_context.h
@@ -5,6 +5,8 @@
#ifndef __ASSEMBLY__
+#include <asm-generic/mm_hooks.h>
+
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
}
diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
index b9da9a600e3..b3f492208fd 100644
--- a/include/asm-sparc/smp.h
+++ b/include/asm-sparc/smp.h
@@ -165,6 +165,7 @@ void smp_setup_cpu_possible_map(void);
#else /* SMP */
+#define hard_smp_processor_id() 0
#define smp_setup_cpu_possible_map() do { } while (0)
#endif /* !(SMP) */
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 100c3eaf3c1..8b6d9c9c8b9 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -241,7 +241,6 @@ static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned lon
}
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
extern void __xchg_called_with_bad_pointer(void);
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index e43ed1d63a9..da9bdc5e552 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -326,8 +326,9 @@
#define __NR_move_pages 307
#define __NR_getcpu 308
#define __NR_epoll_pwait 309
+#define __NR_utimensat 310
-#define NR_SYSCALLS 310
+#define NR_SYSCALLS 311
#ifdef __KERNEL__
#define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-sparc64/Kbuild b/include/asm-sparc64/Kbuild
index a7f44408c93..854fd3a65ac 100644
--- a/include/asm-sparc64/Kbuild
+++ b/include/asm-sparc64/Kbuild
@@ -8,7 +8,6 @@ header-y += apb.h
header-y += asi.h
header-y += bbc.h
header-y += bpp.h
-header-y += const.h
header-y += display7seg.h
header-y += envctrl.h
header-y += ipc.h
diff --git a/include/asm-sparc64/atomic.h b/include/asm-sparc64/atomic.h
index 2f0bec26a69..3fb4e1f7f18 100644
--- a/include/asm-sparc64/atomic.h
+++ b/include/asm-sparc64/atomic.h
@@ -9,6 +9,7 @@
#define __ARCH_SPARC64_ATOMIC__
#include <linux/types.h>
+#include <asm/system.h>
typedef struct { volatile int counter; } atomic_t;
typedef struct { volatile __s64 counter; } atomic64_t;
@@ -70,25 +71,47 @@ extern int atomic64_sub_ret(int, atomic64_t *);
#define atomic_add_negative(i, v) (atomic_add_ret(i, v) < 0)
#define atomic64_add_negative(i, v) (atomic64_add_ret(i, v) < 0)
-#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
+#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- for (;;) { \
- if (unlikely(c == (u))) \
- break; \
- old = atomic_cmpxchg((v), c, c + (a)); \
- if (likely(old == c)) \
- break; \
- c = old; \
- } \
- likely(c != (u)); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+#define atomic64_cmpxchg(v, o, n) \
+ ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long c, old;
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic64_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
/* Atomic operations are already serializing */
#ifdef CONFIG_SMP
#define smp_mb__before_atomic_dec() membar_storeload_loadload();
diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h
index e199594a1e9..0b1813f4104 100644
--- a/include/asm-sparc64/iommu.h
+++ b/include/asm-sparc64/iommu.h
@@ -32,6 +32,7 @@ struct iommu {
unsigned long iommu_control;
unsigned long iommu_tsbbase;
unsigned long iommu_flush;
+ unsigned long iommu_flushinv;
unsigned long iommu_ctxflush;
unsigned long write_complete_reg;
unsigned long dummy_page;
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
index 11251bdd00c..627e3396a5f 100644
--- a/include/asm-sparc64/kdebug.h
+++ b/include/asm-sparc64/kdebug.h
@@ -7,19 +7,19 @@
struct pt_regs;
-struct die_args {
- struct pt_regs *regs;
- const char *str;
- long err;
- int trapnr;
- int signr;
-};
-
-extern int register_die_notifier(struct notifier_block *);
-extern int unregister_die_notifier(struct notifier_block *);
-extern int register_page_fault_notifier(struct notifier_block *);
-extern int unregister_page_fault_notifier(struct notifier_block *);
-extern struct atomic_notifier_head sparc64die_chain;
+/*
+ * These are only here because kprobes.c wants them to implement a
+ * blatant layering violation. Will hopefully go away soon once all
+ * architectures are updated.
+ */
+static inline int register_page_fault_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+static inline int unregister_page_fault_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
extern void bad_trap(struct pt_regs *, long);
@@ -31,21 +31,8 @@ enum die_val {
DIE_DIE,
DIE_TRAP,
DIE_TRAP_TL1,
- DIE_GPF,
DIE_CALL,
DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val,char *str, struct pt_regs *regs,
- long err, int trap, int sig)
-{
- struct die_args args = { .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig };
-
- return atomic_notifier_call_chain(&sparc64die_chain, val, &args);
-}
-
#endif
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
index becc38fa06c..a331b7b0dff 100644
--- a/include/asm-sparc64/kprobes.h
+++ b/include/asm-sparc64/kprobes.h
@@ -43,4 +43,5 @@ struct kprobe_ctlblk {
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
+extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
#endif /* _SPARC64_KPROBES_H */
diff --git a/include/asm-sparc64/local.h b/include/asm-sparc64/local.h
index dfde115ac89..c11c530f74d 100644
--- a/include/asm-sparc64/local.h
+++ b/include/asm-sparc64/local.h
@@ -1,40 +1 @@
-#ifndef _ARCH_SPARC64_LOCAL_H
-#define _ARCH_SPARC64_LOCAL_H
-
-#include <linux/percpu.h>
-#include <asm/atomic.h>
-
-typedef atomic64_t local_t;
-
-#define LOCAL_INIT(i) ATOMIC64_INIT(i)
-#define local_read(v) atomic64_read(v)
-#define local_set(v,i) atomic64_set(v,i)
-
-#define local_inc(v) atomic64_inc(v)
-#define local_dec(v) atomic64_dec(v)
-#define local_add(i, v) atomic64_add(i, v)
-#define local_sub(i, v) atomic64_sub(i, v)
-
-#define __local_inc(v) ((v)->counter++)
-#define __local_dec(v) ((v)->counter--)
-#define __local_add(i,v) ((v)->counter+=(i))
-#define __local_sub(i,v) ((v)->counter-=(i))
-
-/* Use these for per-cpu local_t variables: on some archs they are
- * much more efficient than these naive implementations. Note they take
- * a variable, not an address.
- */
-#define cpu_local_read(v) local_read(&__get_cpu_var(v))
-#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
-
-#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
-#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
-#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
-#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
-
-#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
-#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
-#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
-#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
-
-#endif /* _ARCH_SPARC64_LOCAL_H */
+#include <asm-generic/local.h>
diff --git a/include/asm-sparc64/lsu.h b/include/asm-sparc64/lsu.h
index e5329c7f583..79f109840c3 100644
--- a/include/asm-sparc64/lsu.h
+++ b/include/asm-sparc64/lsu.h
@@ -2,7 +2,7 @@
#ifndef _SPARC64_LSU_H
#define _SPARC64_LSU_H
-#include <asm/const.h>
+#include <linux/const.h>
/* LSU Control Register */
#define LSU_CONTROL_PM _AC(0x000001fe00000000,UL) /* Phys-watchpoint byte mask*/
diff --git a/include/asm-sparc64/mmu.h b/include/asm-sparc64/mmu.h
index 70af4b6ce13..8abc58f0f9d 100644
--- a/include/asm-sparc64/mmu.h
+++ b/include/asm-sparc64/mmu.h
@@ -1,8 +1,8 @@
#ifndef __MMU_H
#define __MMU_H
+#include <linux/const.h>
#include <asm/page.h>
-#include <asm/const.h>
#include <asm/hypervisor.h>
#define CTX_NR_BITS 13
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index 2337eb48771..8d129032013 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -9,6 +9,7 @@
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/spitfire.h>
+#include <asm-generic/mm_hooks.h>
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
index ff736eafa64..7af1077451f 100644
--- a/include/asm-sparc64/page.h
+++ b/include/asm-sparc64/page.h
@@ -5,7 +5,7 @@
#ifdef __KERNEL__
-#include <asm/const.h>
+#include <linux/const.h>
#if defined(CONFIG_SPARC64_PAGE_SIZE_8KB)
#define PAGE_SHIFT 13
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
deleted file mode 100644
index c008cecca14..00000000000
--- a/include/asm-sparc64/pbm.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/* pbm.h: UltraSparc PCI controller software state.
- *
- * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef __SPARC64_PBM_H
-#define __SPARC64_PBM_H
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/msi.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/iommu.h>
-
-/* The abstraction used here is that there are PCI controllers,
- * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules
- * underneath. Each PCI bus module uses an IOMMU (shared by both
- * PBMs of a controller, or per-PBM), and if a streaming buffer
- * is present, each PCI bus module has it's own. (ie. the IOMMU
- * might be shared between PBMs, the STC is never shared)
- * Furthermore, each PCI bus module controls it's own autonomous
- * PCI bus.
- */
-
-extern void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask);
-
-#define PCI_STC_FLUSHFLAG_INIT(STC) \
- (*((STC)->strbuf_flushflag) = 0UL)
-#define PCI_STC_FLUSHFLAG_SET(STC) \
- (*((STC)->strbuf_flushflag) != 0UL)
-
-/* There can be quite a few ranges and interrupt maps on a PCI
- * segment. Thus...
- */
-#define PROM_PCIRNG_MAX 64
-#define PROM_PCIIMAP_MAX 64
-
-struct pci_controller_info;
-
-struct pci_pbm_info {
- /* PCI controller we sit under. */
- struct pci_controller_info *parent;
-
- /* Physical address base of controller registers. */
- unsigned long controller_regs;
-
- /* Physical address base of PBM registers. */
- unsigned long pbm_regs;
-
- /* Physical address of DMA sync register, if any. */
- unsigned long sync_reg;
-
- /* Opaque 32-bit system bus Port ID. */
- u32 portid;
-
- /* Opaque 32-bit handle used for hypervisor calls. */
- u32 devhandle;
-
- /* Chipset version information. */
- int chip_type;
-#define PBM_CHIP_TYPE_SABRE 1
-#define PBM_CHIP_TYPE_PSYCHO 2
-#define PBM_CHIP_TYPE_SCHIZO 3
-#define PBM_CHIP_TYPE_SCHIZO_PLUS 4
-#define PBM_CHIP_TYPE_TOMATILLO 5
- int chip_version;
- int chip_revision;
-
- /* Name used for top-level resources. */
- char *name;
-
- /* OBP specific information. */
- struct device_node *prom_node;
- u64 ino_bitmap;
-
- /* PBM I/O and Memory space resources. */
- struct resource io_space;
- struct resource mem_space;
-
- /* Base of PCI Config space, can be per-PBM or shared. */
- unsigned long config_space;
-
- /* State of 66MHz capabilities on this PBM. */
- int is_66mhz_capable;
- int all_devs_66mhz;
-
-#ifdef CONFIG_PCI_MSI
- /* MSI info. */
- u32 msiq_num;
- u32 msiq_ent_count;
- u32 msiq_first;
- u32 msiq_first_devino;
- u32 msi_num;
- u32 msi_first;
- u32 msi_data_mask;
- u32 msix_data_width;
- u64 msi32_start;
- u64 msi64_start;
- u32 msi32_len;
- u32 msi64_len;
- void *msi_queues;
- unsigned long *msi_bitmap;
-#endif /* !(CONFIG_PCI_MSI) */
-
- /* This PBM's streaming buffer. */
- struct strbuf stc;
-
- /* IOMMU state, potentially shared by both PBM segments. */
- struct iommu *iommu;
-
- /* Now things for the actual PCI bus probes. */
- unsigned int pci_first_busno;
- unsigned int pci_last_busno;
- struct pci_bus *pci_bus;
-};
-
-struct pci_controller_info {
- /* List of all PCI controllers. */
- struct pci_controller_info *next;
-
- /* Each controller gets a unique index, used mostly for
- * error logging purposes.
- */
- int index;
-
- /* The PCI bus modules controlled by us. */
- struct pci_pbm_info pbm_A;
- struct pci_pbm_info pbm_B;
-
- /* Operations which are controller specific. */
- void (*scan_bus)(struct pci_controller_info *);
-
-#ifdef CONFIG_PCI_MSI
- int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
- struct msi_desc *entry);
- void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
-#endif
-
- /* Now things for the actual PCI bus probes. */
- struct pci_ops *pci_ops;
- unsigned int pci_first_busno;
- unsigned int pci_last_busno;
-};
-
-#endif /* !(__SPARC64_PBM_H) */
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
index 0d3df76aa47..ced8cbde046 100644
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -5,16 +5,6 @@
#ifdef CONFIG_SMP
-#ifdef CONFIG_MODULES
-# define PERCPU_MODULE_RESERVE 8192
-#else
-# define PERCPU_MODULE_RESERVE 0
-#endif
-
-#define PERCPU_ENOUGH_ROOM \
- (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
- PERCPU_MODULE_RESERVE)
-
extern void setup_per_cpu_areas(void);
extern unsigned long __per_cpu_base;
diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h
index 5891ff7ba76..5d66b858a96 100644
--- a/include/asm-sparc64/pgalloc.h
+++ b/include/asm-sparc64/pgalloc.h
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/quicklist.h>
#include <asm/spitfire.h>
#include <asm/cpudata.h>
@@ -13,52 +14,50 @@
#include <asm/page.h>
/* Page table allocation/freeing. */
-extern struct kmem_cache *pgtable_cache;
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
- return kmem_cache_alloc(pgtable_cache, GFP_KERNEL);
+ return quicklist_alloc(0, GFP_KERNEL, NULL);
}
static inline void pgd_free(pgd_t *pgd)
{
- kmem_cache_free(pgtable_cache, pgd);
+ quicklist_free(0, NULL, pgd);
}
#define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD)
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- return kmem_cache_alloc(pgtable_cache,
- GFP_KERNEL|__GFP_REPEAT);
+ return quicklist_alloc(0, GFP_KERNEL, NULL);
}
static inline void pmd_free(pmd_t *pmd)
{
- kmem_cache_free(pgtable_cache, pmd);
+ quicklist_free(0, NULL, pmd);
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
unsigned long address)
{
- return kmem_cache_alloc(pgtable_cache,
- GFP_KERNEL|__GFP_REPEAT);
+ return quicklist_alloc(0, GFP_KERNEL, NULL);
}
static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long address)
{
- return virt_to_page(pte_alloc_one_kernel(mm, address));
+ void *pg = quicklist_alloc(0, GFP_KERNEL, NULL);
+ return pg ? virt_to_page(pg) : NULL;
}
static inline void pte_free_kernel(pte_t *pte)
{
- kmem_cache_free(pgtable_cache, pte);
+ quicklist_free(0, NULL, pte);
}
static inline void pte_free(struct page *ptepage)
{
- pte_free_kernel(page_address(ptepage));
+ quicklist_free_page(0, NULL, ptepage);
}
@@ -66,6 +65,9 @@ static inline void pte_free(struct page *ptepage)
#define pmd_populate(MM,PMD,PTE_PAGE) \
pmd_populate_kernel(MM,PMD,page_address(PTE_PAGE))
-#define check_pgt_cache() do { } while (0)
+static inline void check_pgt_cache(void)
+{
+ quicklist_trim(0, NULL, 25, 16);
+}
#endif /* _SPARC64_PGALLOC_H */
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 46705ef47d2..9e80ad43b29 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -15,13 +15,13 @@
#include <asm-generic/pgtable-nopud.h>
#include <linux/compiler.h>
+#include <linux/const.h>
#include <asm/types.h>
#include <asm/spitfire.h>
#include <asm/asi.h>
#include <asm/system.h>
#include <asm/page.h>
#include <asm/processor.h>
-#include <asm/const.h>
/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB).
* The page copy blockops can use 0x2000000 to 0x4000000.
diff --git a/include/asm-sparc64/pstate.h b/include/asm-sparc64/pstate.h
index 49a7924a89a..f3c45484c63 100644
--- a/include/asm-sparc64/pstate.h
+++ b/include/asm-sparc64/pstate.h
@@ -2,7 +2,7 @@
#ifndef _SPARC64_PSTATE_H
#define _SPARC64_PSTATE_H
-#include <asm/const.h>
+#include <linux/const.h>
/* The V9 PSTATE Register (with SpitFire extensions).
*
diff --git a/include/asm-sparc64/scatterlist.h b/include/asm-sparc64/scatterlist.h
index ec4f3c63fe9..048fdb40e81 100644
--- a/include/asm-sparc64/scatterlist.h
+++ b/include/asm-sparc64/scatterlist.h
@@ -3,6 +3,7 @@
#define _SPARC64_SCATTERLIST_H
#include <asm/page.h>
+#include <asm/types.h>
struct scatterlist {
struct page *page;
diff --git a/include/asm-sparc64/sfafsr.h b/include/asm-sparc64/sfafsr.h
index 2f792c20b53..e96137b04a4 100644
--- a/include/asm-sparc64/sfafsr.h
+++ b/include/asm-sparc64/sfafsr.h
@@ -1,7 +1,7 @@
#ifndef _SPARC64_SFAFSR_H
#define _SPARC64_SFAFSR_H
-#include <asm/const.h>
+#include <linux/const.h>
/* Spitfire Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index cca54804b72..869d16fb907 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -48,6 +48,7 @@ extern unsigned char boot_cpu_id;
#else
+#define hard_smp_processor_id() 0
#define smp_setup_cpu_possible_map() do { } while (0)
#define boot_cpu_id (0)
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 32281acb878..8ba380ec6da 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -253,7 +253,6 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long
}
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
-#define tas(ptr) (xchg((ptr),1))
extern void __xchg_called_with_bad_pointer(void);
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index e2dcb87e0c6..fcd627594f4 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -328,8 +328,9 @@
#define __NR_move_pages 307
#define __NR_getcpu 308
#define __NR_epoll_pwait 309
+#define __NR_utimensat 310
-#define NR_SYSCALLS 310
+#define NR_SYSCALLS 311
#ifdef __KERNEL__
/* sysconf options, for SunOS compatibility */
diff --git a/include/asm-um/cmpxchg.h b/include/asm-um/cmpxchg.h
new file mode 100644
index 00000000000..529376a9988
--- /dev/null
+++ b/include/asm-um/cmpxchg.h
@@ -0,0 +1,6 @@
+#ifndef __UM_CMPXCHG_H
+#define __UM_CMPXCHG_H
+
+#include "asm/arch/cmpxchg.h"
+
+#endif
diff --git a/include/asm-um/kdebug.h b/include/asm-um/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-um/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index f709c784bf1..9aa4b44e8cc 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -6,6 +6,8 @@
#ifndef __UM_MMU_CONTEXT_H
#define __UM_MMU_CONTEXT_H
+#include <asm-generic/mm_hooks.h>
+
#include "linux/sched.h"
#include "choose-mode.h"
#include "um_mmu.h"
diff --git a/include/asm-um/page.h b/include/asm-um/page.h
index 4296d3135aa..8e310d81e5b 100644
--- a/include/asm-um/page.h
+++ b/include/asm-um/page.h
@@ -114,9 +114,6 @@ extern unsigned long uml_physmem;
extern struct page *arch_validate(struct page *page, gfp_t mask, int order);
#define HAVE_ARCH_VALIDATE
-extern void arch_free_page(struct page *page, int order);
-#define HAVE_ARCH_FREE_PAGE
-
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
diff --git a/include/asm-um/required-features.h b/include/asm-um/required-features.h
new file mode 100644
index 00000000000..dfb967b2d2f
--- /dev/null
+++ b/include/asm-um/required-features.h
@@ -0,0 +1,9 @@
+#ifndef __UM_REQUIRED_FEATURES_H
+#define __UM_REQUIRED_FEATURES_H
+
+/*
+ * Nothing to see, just need something for the i386 and x86_64 asm
+ * headers to include.
+ */
+
+#endif
diff --git a/include/asm-um/smp.h b/include/asm-um/smp.h
index ca552261ed1..84f8cf29324 100644
--- a/include/asm-um/smp.h
+++ b/include/asm-um/smp.h
@@ -24,6 +24,10 @@ extern inline void smp_cpus_done(unsigned int maxcpus)
extern struct task_struct *idle_threads[NR_CPUS];
+#else
+
+#define hard_smp_processor_id() 0
+
#endif
#endif
diff --git a/include/asm-um/tlbflush.h b/include/asm-um/tlbflush.h
index 522aa30f7ea..e78c28c1f35 100644
--- a/include/asm-um/tlbflush.h
+++ b/include/asm-um/tlbflush.h
@@ -7,6 +7,7 @@
#define __UM_TLBFLUSH_H
#include <linux/mm.h>
+#include "choose-mode.h"
/*
* TLB flushing:
@@ -24,6 +25,18 @@ extern void flush_tlb_all(void);
extern void flush_tlb_mm(struct mm_struct *mm);
extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end);
+extern void flush_tlb_page_skas(struct vm_area_struct *vma,
+ unsigned long address);
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long address)
+{
+ address &= PAGE_MASK;
+
+ CHOOSE_MODE(flush_tlb_range(vma, address, address + PAGE_SIZE),
+ flush_tlb_page_skas(vma, address));
+}
+
extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
extern void flush_tlb_kernel_vm(void);
extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
@@ -35,14 +48,3 @@ static inline void flush_tlb_pgtables(struct mm_struct *mm,
}
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/include/asm-v850/kdebug.h b/include/asm-v850/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-v850/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-v850/mmu_context.h b/include/asm-v850/mmu_context.h
index f521c8050d3..01daacd5474 100644
--- a/include/asm-v850/mmu_context.h
+++ b/include/asm-v850/mmu_context.h
@@ -1,6 +1,8 @@
#ifndef __V850_MMU_CONTEXT_H__
#define __V850_MMU_CONTEXT_H__
+#include <asm-generic/mm_hooks.h>
+
#define destroy_context(mm) ((void)0)
#define init_new_context(tsk,mm) 0
#define switch_mm(prev,next,tsk) ((void)0)
diff --git a/include/asm-v850/scatterlist.h b/include/asm-v850/scatterlist.h
index af1cba69a52..56f402920db 100644
--- a/include/asm-v850/scatterlist.h
+++ b/include/asm-v850/scatterlist.h
@@ -14,6 +14,8 @@
#ifndef __V850_SCATTERLIST_H__
#define __V850_SCATTERLIST_H__
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned offset;
diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h
index da39916f10b..0de2481fd99 100644
--- a/include/asm-v850/system.h
+++ b/include/asm-v850/system.h
@@ -76,7 +76,6 @@ static inline int irqs_disabled (void)
#define xchg(ptr, with) \
((__typeof__ (*(ptr)))__xchg ((unsigned long)(with), (ptr), sizeof (*(ptr))))
-#define tas(ptr) (xchg ((ptr), 1))
static inline unsigned long __xchg (unsigned long with,
__volatile__ void *ptr, int size)
diff --git a/include/asm-x86_64/Kbuild b/include/asm-x86_64/Kbuild
index ebd7117782a..75a2deffca6 100644
--- a/include/asm-x86_64/Kbuild
+++ b/include/asm-x86_64/Kbuild
@@ -8,7 +8,7 @@ header-y += boot.h
header-y += bootsetup.h
header-y += debugreg.h
header-y += ldt.h
-header-y += msr.h
+header-y += msr-index.h
header-y += prctl.h
header-y += ptrace-abi.h
header-y += sigcontext32.h
@@ -16,5 +16,6 @@ header-y += ucontext.h
header-y += vsyscall32.h
unifdef-y += mce.h
+unifdef-y += msr.h
unifdef-y += mtrr.h
unifdef-y += vsyscall.h
diff --git a/include/asm-x86_64/agp.h b/include/asm-x86_64/agp.h
index 06c52ee9c06..de338666f3f 100644
--- a/include/asm-x86_64/agp.h
+++ b/include/asm-x86_64/agp.h
@@ -10,8 +10,10 @@
* with different cachability attributes for the same page.
*/
-int map_page_into_agp(struct page *page);
-int unmap_page_from_agp(struct page *page);
+/* Caller's responsibility to call global_flush_tlb() for
+ * performance reasons */
+#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE)
+#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL)
#define flush_agp_mappings() global_flush_tlb()
/* Could use CLFLUSH here if the cpu supports it. But then it would
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
index a6657b4f3e0..a09fe85c268 100644
--- a/include/asm-x86_64/alternative.h
+++ b/include/asm-x86_64/alternative.h
@@ -16,6 +16,7 @@ struct alt_instr {
u8 pad[5];
};
+extern void alternative_instructions(void);
extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
struct module;
@@ -141,8 +142,8 @@ void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end);
static inline void
apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
{}
-#define __start_parainstructions NULL
-#define __stop_parainstructions NULL
+#define __parainstructions NULL
+#define __parainstructions_end NULL
#endif
#endif /* _X86_64_ALTERNATIVE_H */
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 7cfb39cbd91..45e9fca1feb 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -2,6 +2,7 @@
#define __ASM_APIC_H
#include <linux/pm.h>
+#include <linux/delay.h>
#include <asm/fixmap.h>
#include <asm/apicdef.h>
#include <asm/system.h>
@@ -47,11 +48,8 @@ static __inline unsigned int apic_read(unsigned long reg)
return *((volatile unsigned int *)(APIC_BASE+reg));
}
-static __inline__ void apic_wait_icr_idle(void)
-{
- while (apic_read( APIC_ICR ) & APIC_ICR_BUSY)
- cpu_relax();
-}
+extern void apic_wait_icr_idle(void);
+extern unsigned int safe_apic_wait_icr_idle(void);
static inline void ack_APIC_irq(void)
{
@@ -83,7 +81,7 @@ extern void setup_secondary_APIC_clock (void);
extern int APIC_init_uniprocessor (void);
extern void disable_APIC_timer(void);
extern void enable_APIC_timer(void);
-extern void clustered_apic_check(void);
+extern void setup_apic_routing(void);
extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
unsigned char msg_type, unsigned char mask);
diff --git a/include/asm-x86_64/atomic.h b/include/asm-x86_64/atomic.h
index 706ca4b6000..f2e64634fa4 100644
--- a/include/asm-x86_64/atomic.h
+++ b/include/asm-x86_64/atomic.h
@@ -2,6 +2,7 @@
#define __ARCH_X86_64_ATOMIC__
#include <asm/alternative.h>
+#include <asm/cmpxchg.h>
/* atomic_t should be 32 bit signed type */
@@ -375,8 +376,8 @@ static __inline__ long atomic64_add_return(long i, atomic64_t *v)
long __i = i;
__asm__ __volatile__(
LOCK_PREFIX "xaddq %0, %1;"
- :"=r"(i)
- :"m"(v->counter), "0"(i));
+ :"+r" (i), "+m" (v->counter)
+ : : "memory");
return i + __i;
}
@@ -388,7 +389,10 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t *v)
#define atomic64_inc_return(v) (atomic64_add_return(1,v))
#define atomic64_dec_return(v) (atomic64_sub_return(1,v))
-#define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
+#define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
+#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
+
+#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new))
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
/**
@@ -400,22 +404,49 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t *v)
* Atomically adds @a to @v, so long as it was not @u.
* Returns non-zero if @v was not @u, and zero otherwise.
*/
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- for (;;) { \
- if (unlikely(c == (u))) \
- break; \
- old = atomic_cmpxchg((v), c, c + (a)); \
- if (likely(old == c)) \
- break; \
- c = old; \
- } \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+/**
+ * atomic64_add_unless - add unless the number is a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long c, old;
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic64_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
/* These are x86-specific, used by some header files */
#define atomic_clear_mask(mask, addr) \
__asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \
diff --git a/include/asm-x86_64/bugs.h b/include/asm-x86_64/bugs.h
index d86c5dd689f..b33dc04d8f4 100644
--- a/include/asm-x86_64/bugs.h
+++ b/include/asm-x86_64/bugs.h
@@ -1,28 +1,6 @@
-/*
- * include/asm-x86_64/bugs.h
- *
- * Copyright (C) 1994 Linus Torvalds
- * Copyright (C) 2000 SuSE
- *
- * This is included by init/main.c to check for architecture-dependent bugs.
- *
- * Needs:
- * void check_bugs(void);
- */
+#ifndef _ASM_X86_64_BUGS_H
+#define _ASM_X86_64_BUGS_H
-#include <asm/processor.h>
-#include <asm/i387.h>
-#include <asm/msr.h>
-#include <asm/pda.h>
+void check_bugs(void);
-extern void alternative_instructions(void);
-
-static void __init check_bugs(void)
-{
- identify_cpu(&boot_cpu_data);
-#if !defined(CONFIG_SMP)
- printk("CPU: ");
- print_cpu_info(&boot_cpu_data);
-#endif
- alternative_instructions();
-}
+#endif /* _ASM_X86_64_BUGS_H */
diff --git a/include/asm-x86_64/cmpxchg.h b/include/asm-x86_64/cmpxchg.h
new file mode 100644
index 00000000000..09a6b6b6b74
--- /dev/null
+++ b/include/asm-x86_64/cmpxchg.h
@@ -0,0 +1,134 @@
+#ifndef __ASM_CMPXCHG_H
+#define __ASM_CMPXCHG_H
+
+#include <asm/alternative.h> /* Provides LOCK_PREFIX */
+
+#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
+
+#define __xg(x) ((volatile long *)(x))
+
+static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
+{
+ *ptr = val;
+}
+
+#define _set_64bit set_64bit
+
+/*
+ * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
+ * Note 2: xchg has side effect, so that attribute volatile is necessary,
+ * but generally the primitive is invalid, *ptr is output argument. --ANK
+ */
+static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+{
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("xchgb %b0,%1"
+ :"=q" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 2:
+ __asm__ __volatile__("xchgw %w0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 4:
+ __asm__ __volatile__("xchgl %k0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ case 8:
+ __asm__ __volatile__("xchgq %0,%1"
+ :"=r" (x)
+ :"m" (*__xg(ptr)), "0" (x)
+ :"memory");
+ break;
+ }
+ return x;
+}
+
+/*
+ * Atomic compare and exchange. Compare OLD with MEM, if identical,
+ * store NEW in MEM. Return the initial value in MEM. Success is
+ * indicated by comparing RETURN with OLD.
+ */
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 8:
+ __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+ unsigned long old, unsigned long new, int size)
+{
+ unsigned long prev;
+ switch (size) {
+ case 1:
+ __asm__ __volatile__("cmpxchgb %b1,%2"
+ : "=a"(prev)
+ : "q"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 2:
+ __asm__ __volatile__("cmpxchgw %w1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 4:
+ __asm__ __volatile__("cmpxchgl %k1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ case 8:
+ __asm__ __volatile__("cmpxchgq %1,%2"
+ : "=a"(prev)
+ : "r"(new), "m"(*__xg(ptr)), "0"(old)
+ : "memory");
+ return prev;
+ }
+ return old;
+}
+
+#define cmpxchg(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+#define cmpxchg_local(ptr,o,n)\
+ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ (unsigned long)(n),sizeof(*(ptr))))
+
+#endif
diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h
index 913d6ac0003..ac991b5ca0f 100644
--- a/include/asm-x86_64/desc.h
+++ b/include/asm-x86_64/desc.h
@@ -107,16 +107,6 @@ static inline void set_ldt_desc(unsigned cpu, void *addr, int size)
DESC_LDT, size * 8 - 1);
}
-static inline void set_seg_base(unsigned cpu, int entry, void *base)
-{
- struct desc_struct *d = &cpu_gdt(cpu)[entry];
- u32 addr = (u32)(u64)base;
- BUG_ON((u64)base >> 32);
- d->base0 = addr & 0xffff;
- d->base1 = (addr >> 16) & 0xff;
- d->base2 = (addr >> 24) & 0xff;
-}
-
#define LDT_entry_a(info) \
((((info)->base_addr & 0x0000ffff) << 16) | ((info)->limit & 0x0ffff))
/* Don't allow setting of the lm bit. It is useless anyways because
@@ -145,16 +135,13 @@ static inline void set_seg_base(unsigned cpu, int entry, void *base)
(info)->useable == 0 && \
(info)->lm == 0)
-#if TLS_SIZE != 24
-# error update this code.
-#endif
-
static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
{
+ unsigned int i;
u64 *gdt = (u64 *)(cpu_gdt(cpu) + GDT_ENTRY_TLS_MIN);
- gdt[0] = t->tls_array[0];
- gdt[1] = t->tls_array[1];
- gdt[2] = t->tls_array[2];
+
+ for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++)
+ gdt[i] = t->tls_array[i];
}
/*
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index d2af227f06d..6897e2a436e 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -52,7 +52,7 @@ struct dma_mapping_ops {
};
extern dma_addr_t bad_dma_address;
-extern struct dma_mapping_ops* dma_ops;
+extern const struct dma_mapping_ops* dma_ops;
extern int iommu_merge;
static inline int dma_mapping_error(dma_addr_t dma_addr)
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index 1b620db5b9e..e90e1677531 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -15,7 +15,6 @@
#include <asm/apicdef.h>
#include <asm/page.h>
#include <asm/vsyscall.h>
-#include <asm/vsyscall32.h>
/*
* Here we define all the compile-time 'special' virtual
diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86_64/genapic.h
index b80f4bb5f27..d7e516ccbaa 100644
--- a/include/asm-x86_64/genapic.h
+++ b/include/asm-x86_64/genapic.h
@@ -29,7 +29,9 @@ struct genapic {
unsigned int (*phys_pkg_id)(int index_msb);
};
+extern struct genapic *genapic;
-extern struct genapic *genapic, *genapic_force, apic_flat;
+extern struct genapic apic_flat;
+extern struct genapic apic_physflat;
#endif
diff --git a/include/asm-x86_64/ipi.h b/include/asm-x86_64/ipi.h
index 2a5c162b7d9..a7c75ea408a 100644
--- a/include/asm-x86_64/ipi.h
+++ b/include/asm-x86_64/ipi.h
@@ -18,10 +18,8 @@
* Subject to the GNU Public License, v.2
*/
-#include <asm/fixmap.h>
#include <asm/hw_irq.h>
-#include <asm/apicdef.h>
-#include <asm/genapic.h>
+#include <asm/apic.h>
/*
* the following functions deal with sending IPIs between CPUs.
@@ -76,10 +74,42 @@ static inline void __send_IPI_shortcut(unsigned int shortcut, int vector, unsign
apic_write(APIC_ICR, cfg);
}
+/*
+ * This is used to send an IPI with no shorthand notation (the destination is
+ * specified in bits 56 to 63 of the ICR).
+ */
+static inline void __send_IPI_dest_field(unsigned int mask, int vector, unsigned int dest)
+{
+ unsigned long cfg;
+
+ /*
+ * Wait for idle.
+ */
+ if (unlikely(vector == NMI_VECTOR))
+ safe_apic_wait_icr_idle();
+ else
+ apic_wait_icr_idle();
+
+ /*
+ * prepare target chip field
+ */
+ cfg = __prepare_ICR2(mask);
+ apic_write(APIC_ICR2, cfg);
+
+ /*
+ * program the ICR
+ */
+ cfg = __prepare_ICR(0, vector, dest);
+
+ /*
+ * Send the IPI. The write to APIC_ICR fires this off.
+ */
+ apic_write(APIC_ICR, cfg);
+}
static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
{
- unsigned long cfg, flags;
+ unsigned long flags;
unsigned long query_cpu;
/*
@@ -88,28 +118,9 @@ static inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
* - mbligh
*/
local_irq_save(flags);
-
for_each_cpu_mask(query_cpu, mask) {
- /*
- * Wait for idle.
- */
- apic_wait_icr_idle();
-
- /*
- * prepare target chip field
- */
- cfg = __prepare_ICR2(x86_cpu_to_apicid[query_cpu]);
- apic_write(APIC_ICR2, cfg);
-
- /*
- * program the ICR
- */
- cfg = __prepare_ICR(0, vector, APIC_DEST_PHYSICAL);
-
- /*
- * Send the IPI. The write to APIC_ICR fires this off.
- */
- apic_write(APIC_ICR, cfg);
+ __send_IPI_dest_field(x86_cpu_to_apicid[query_cpu],
+ vector, APIC_DEST_PHYSICAL);
}
local_irq_restore(flags);
}
diff --git a/include/asm-x86_64/irqflags.h b/include/asm-x86_64/irqflags.h
index cce6937e87c..86e70fe2365 100644
--- a/include/asm-x86_64/irqflags.h
+++ b/include/asm-x86_64/irqflags.h
@@ -9,6 +9,7 @@
*/
#ifndef _ASM_IRQFLAGS_H
#define _ASM_IRQFLAGS_H
+#include <asm/processor-flags.h>
#ifndef __ASSEMBLY__
/*
@@ -53,19 +54,19 @@ static inline void raw_local_irq_disable(void)
{
unsigned long flags = __raw_local_save_flags();
- raw_local_irq_restore((flags & ~(1 << 9)) | (1 << 18));
+ raw_local_irq_restore((flags & ~X86_EFLAGS_IF) | X86_EFLAGS_AC);
}
static inline void raw_local_irq_enable(void)
{
unsigned long flags = __raw_local_save_flags();
- raw_local_irq_restore((flags | (1 << 9)) & ~(1 << 18));
+ raw_local_irq_restore((flags | X86_EFLAGS_IF) & (~X86_EFLAGS_AC));
}
static inline int raw_irqs_disabled_flags(unsigned long flags)
{
- return !(flags & (1<<9)) || (flags & (1 << 18));
+ return !(flags & X86_EFLAGS_IF) || (flags & X86_EFLAGS_AC);
}
#else /* CONFIG_X86_VSMP */
@@ -82,7 +83,7 @@ static inline void raw_local_irq_enable(void)
static inline int raw_irqs_disabled_flags(unsigned long flags)
{
- return !(flags & (1 << 9));
+ return !(flags & X86_EFLAGS_IF);
}
#endif
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
index 2b0c088e295..74feae945a2 100644
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -5,19 +5,8 @@
struct pt_regs;
-struct die_args {
- struct pt_regs *regs;
- const char *str;
- long err;
- int trapnr;
- int signr;
-};
-
-extern int register_die_notifier(struct notifier_block *);
-extern int unregister_die_notifier(struct notifier_block *);
extern int register_page_fault_notifier(struct notifier_block *);
extern int unregister_page_fault_notifier(struct notifier_block *);
-extern struct atomic_notifier_head die_chain;
/* Grossly misnamed. */
enum die_val {
@@ -33,22 +22,10 @@ enum die_val {
DIE_GPF,
DIE_CALL,
DIE_NMI_IPI,
+ DIE_NMI_POST,
DIE_PAGE_FAULT,
};
-static inline int notify_die(enum die_val val, const char *str,
- struct pt_regs *regs, long err, int trap, int sig)
-{
- struct die_args args = {
- .regs = regs,
- .str = str,
- .err = err,
- .trapnr = trap,
- .signr = sig
- };
- return atomic_notifier_call_chain(&die_chain, val, &args);
-}
-
extern void printk_address(unsigned long address);
extern void die(const char *,struct pt_regs *,long);
extern void __die(const char *,struct pt_regs *,long);
diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h
index 5fab957e109..738e581b67f 100644
--- a/include/asm-x86_64/kexec.h
+++ b/include/asm-x86_64/kexec.h
@@ -48,8 +48,6 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_X86_64
-#define MAX_NOTE_BYTES 1024
-
/*
* Saving the registers of the cpu on which panic occured in
* crash_kexec to save a valid sp. The registers of other cpus
diff --git a/include/asm-x86_64/local.h b/include/asm-x86_64/local.h
index e769e620022..e87492bb069 100644
--- a/include/asm-x86_64/local.h
+++ b/include/asm-x86_64/local.h
@@ -2,49 +2,183 @@
#define _ARCH_X8664_LOCAL_H
#include <linux/percpu.h>
+#include <asm/atomic.h>
typedef struct
{
- volatile long counter;
+ atomic_long_t a;
} local_t;
-#define LOCAL_INIT(i) { (i) }
+#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
-#define local_read(v) ((v)->counter)
-#define local_set(v,i) (((v)->counter) = (i))
+#define local_read(l) atomic_long_read(&(l)->a)
+#define local_set(l,i) atomic_long_set(&(l)->a, (i))
-static inline void local_inc(local_t *v)
+static inline void local_inc(local_t *l)
{
__asm__ __volatile__(
"incq %0"
- :"=m" (v->counter)
- :"m" (v->counter));
+ :"=m" (l->a.counter)
+ :"m" (l->a.counter));
}
-static inline void local_dec(local_t *v)
+static inline void local_dec(local_t *l)
{
__asm__ __volatile__(
"decq %0"
- :"=m" (v->counter)
- :"m" (v->counter));
+ :"=m" (l->a.counter)
+ :"m" (l->a.counter));
}
-static inline void local_add(long i, local_t *v)
+static inline void local_add(long i, local_t *l)
{
__asm__ __volatile__(
"addq %1,%0"
- :"=m" (v->counter)
- :"ir" (i), "m" (v->counter));
+ :"=m" (l->a.counter)
+ :"ir" (i), "m" (l->a.counter));
}
-static inline void local_sub(long i, local_t *v)
+static inline void local_sub(long i, local_t *l)
{
__asm__ __volatile__(
"subq %1,%0"
- :"=m" (v->counter)
- :"ir" (i), "m" (v->counter));
+ :"=m" (l->a.counter)
+ :"ir" (i), "m" (l->a.counter));
}
+/**
+ * local_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @l: pointer to type local_t
+ *
+ * Atomically subtracts @i from @l and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_sub_and_test(long i, local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "subq %2,%0; sete %1"
+ :"=m" (l->a.counter), "=qm" (c)
+ :"ir" (i), "m" (l->a.counter) : "memory");
+ return c;
+}
+
+/**
+ * local_dec_and_test - decrement and test
+ * @l: pointer to type local_t
+ *
+ * Atomically decrements @l by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+static __inline__ int local_dec_and_test(local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "decq %0; sete %1"
+ :"=m" (l->a.counter), "=qm" (c)
+ :"m" (l->a.counter) : "memory");
+ return c != 0;
+}
+
+/**
+ * local_inc_and_test - increment and test
+ * @l: pointer to type local_t
+ *
+ * Atomically increments @l by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+static __inline__ int local_inc_and_test(local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "incq %0; sete %1"
+ :"=m" (l->a.counter), "=qm" (c)
+ :"m" (l->a.counter) : "memory");
+ return c != 0;
+}
+
+/**
+ * local_add_negative - add and test if negative
+ * @i: integer value to add
+ * @l: pointer to type local_t
+ *
+ * Atomically adds @i to @l and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+static __inline__ int local_add_negative(long i, local_t *l)
+{
+ unsigned char c;
+
+ __asm__ __volatile__(
+ "addq %2,%0; sets %1"
+ :"=m" (l->a.counter), "=qm" (c)
+ :"ir" (i), "m" (l->a.counter) : "memory");
+ return c;
+}
+
+/**
+ * local_add_return - add and return
+ * @i: integer value to add
+ * @l: pointer to type local_t
+ *
+ * Atomically adds @i to @l and returns @i + @l
+ */
+static __inline__ long local_add_return(long i, local_t *l)
+{
+ long __i = i;
+ __asm__ __volatile__(
+ "xaddq %0, %1;"
+ :"+r" (i), "+m" (l->a.counter)
+ : : "memory");
+ return i + __i;
+}
+
+static __inline__ long local_sub_return(long i, local_t *l)
+{
+ return local_add_return(-i,l);
+}
+
+#define local_inc_return(l) (local_add_return(1,l))
+#define local_dec_return(l) (local_sub_return(1,l))
+
+#define local_cmpxchg(l, o, n) \
+ (cmpxchg_local(&((l)->a.counter), (o), (n)))
+/* Always has a lock prefix */
+#define local_xchg(l, n) (xchg(&((l)->a.counter), (n)))
+
+/**
+ * atomic_up_add_unless - add unless the number is a given value
+ * @l: pointer of type local_t
+ * @a: the amount to add to l...
+ * @u: ...unless l is equal to u.
+ *
+ * Atomically adds @a to @l, so long as it was not @u.
+ * Returns non-zero if @l was not @u, and zero otherwise.
+ */
+#define local_add_unless(l, a, u) \
+({ \
+ long c, old; \
+ c = local_read(l); \
+ for (;;) { \
+ if (unlikely(c == (u))) \
+ break; \
+ old = local_cmpxchg((l), c, c + (a)); \
+ if (likely(old == c)) \
+ break; \
+ c = old; \
+ } \
+ c != (u); \
+})
+#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
+
/* On x86-64 these are better than the atomic variants on SMP kernels
because they dont use a lock prefix. */
#define __local_inc(l) local_inc(l)
@@ -62,27 +196,27 @@ static inline void local_sub(long i, local_t *v)
/* Need to disable preemption for the cpu local counters otherwise we could
still access a variable of a previous CPU in a non atomic way. */
-#define cpu_local_wrap_v(v) \
+#define cpu_local_wrap_v(l) \
({ local_t res__; \
preempt_disable(); \
- res__ = (v); \
+ res__ = (l); \
preempt_enable(); \
res__; })
-#define cpu_local_wrap(v) \
+#define cpu_local_wrap(l) \
({ preempt_disable(); \
- v; \
+ l; \
preempt_enable(); }) \
-#define cpu_local_read(v) cpu_local_wrap_v(local_read(&__get_cpu_var(v)))
-#define cpu_local_set(v, i) cpu_local_wrap(local_set(&__get_cpu_var(v), (i)))
-#define cpu_local_inc(v) cpu_local_wrap(local_inc(&__get_cpu_var(v)))
-#define cpu_local_dec(v) cpu_local_wrap(local_dec(&__get_cpu_var(v)))
-#define cpu_local_add(i, v) cpu_local_wrap(local_add((i), &__get_cpu_var(v)))
-#define cpu_local_sub(i, v) cpu_local_wrap(local_sub((i), &__get_cpu_var(v)))
+#define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
+#define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
+#define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l)))
+#define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l)))
+#define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
+#define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
-#define __cpu_local_inc(v) cpu_local_inc(v)
-#define __cpu_local_dec(v) cpu_local_dec(v)
-#define __cpu_local_add(i, v) cpu_local_add((i), (v))
-#define __cpu_local_sub(i, v) cpu_local_sub((i), (v))
+#define __cpu_local_inc(l) cpu_local_inc(l)
+#define __cpu_local_dec(l) cpu_local_dec(l)
+#define __cpu_local_add(i, l) cpu_local_add((i), (l))
+#define __cpu_local_sub(i, l) cpu_local_sub((i), (l))
-#endif /* _ARCH_I386_LOCAL_H */
+#endif /* _ARCH_X8664_LOCAL_H */
diff --git a/include/asm-x86_64/mmu_context.h b/include/asm-x86_64/mmu_context.h
index af03b9f852d..0cce83a7837 100644
--- a/include/asm-x86_64/mmu_context.h
+++ b/include/asm-x86_64/mmu_context.h
@@ -7,6 +7,7 @@
#include <asm/pda.h>
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include <asm-generic/mm_hooks.h>
/*
* possibly do the LDT unload here?
diff --git a/include/asm-x86_64/mmzone.h b/include/asm-x86_64/mmzone.h
index fb558fb1d21..19a89377b12 100644
--- a/include/asm-x86_64/mmzone.h
+++ b/include/asm-x86_64/mmzone.h
@@ -49,7 +49,7 @@ extern int pfn_valid(unsigned long pfn);
#ifdef CONFIG_NUMA_EMU
#define FAKE_NODE_MIN_SIZE (64*1024*1024)
-#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1ul))
+#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1uL))
#endif
#endif
diff --git a/include/asm-x86_64/msr-index.h b/include/asm-x86_64/msr-index.h
new file mode 100644
index 00000000000..d77a63f1ddf
--- /dev/null
+++ b/include/asm-x86_64/msr-index.h
@@ -0,0 +1 @@
+#include <asm-i386/msr-index.h>
diff --git a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h
index 902f9a58617..d5c55b80da5 100644
--- a/include/asm-x86_64/msr.h
+++ b/include/asm-x86_64/msr.h
@@ -1,7 +1,10 @@
#ifndef X86_64_MSR_H
#define X86_64_MSR_H 1
+#include <asm/msr-index.h>
+
#ifndef __ASSEMBLY__
+#include <linux/errno.h>
/*
* Access to machine-specific registers (available on 586 and better only)
* Note: the rd* operations modify the parameters directly (without using
@@ -157,12 +160,11 @@ static inline unsigned int cpuid_edx(unsigned int op)
return edx;
}
-#define MSR_IA32_UCODE_WRITE 0x79
-#define MSR_IA32_UCODE_REV 0x8b
-
#ifdef CONFIG_SMP
void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
+int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
+int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
#else /* CONFIG_SMP */
static inline void rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
{
@@ -172,269 +174,14 @@ static inline void wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
{
wrmsr(msr_no, l, h);
}
-#endif /* CONFIG_SMP */
-
-#endif
-
-/* AMD/K8 specific MSRs */
-#define MSR_EFER 0xc0000080 /* extended feature register */
-#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */
-#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */
-#define MSR_CSTAR 0xc0000083 /* compatibility mode SYSCALL target */
-#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */
-#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */
-#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */
-#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow (or USER_GS from kernel) */
-/* EFER bits: */
-#define _EFER_SCE 0 /* SYSCALL/SYSRET */
-#define _EFER_LME 8 /* Long mode enable */
-#define _EFER_LMA 10 /* Long mode active (read-only) */
-#define _EFER_NX 11 /* No execute enable */
-
-#define EFER_SCE (1<<_EFER_SCE)
-#define EFER_LME (1<<_EFER_LME)
-#define EFER_LMA (1<<_EFER_LMA)
-#define EFER_NX (1<<_EFER_NX)
-
-/* Intel MSRs. Some also available on other CPUs */
-#define MSR_IA32_TSC 0x10
-#define MSR_IA32_PLATFORM_ID 0x17
-
-#define MSR_IA32_PERFCTR0 0xc1
-#define MSR_IA32_PERFCTR1 0xc2
-#define MSR_FSB_FREQ 0xcd
-
-#define MSR_MTRRcap 0x0fe
-#define MSR_IA32_BBL_CR_CTL 0x119
-
-#define MSR_IA32_SYSENTER_CS 0x174
-#define MSR_IA32_SYSENTER_ESP 0x175
-#define MSR_IA32_SYSENTER_EIP 0x176
-
-#define MSR_IA32_MCG_CAP 0x179
-#define MSR_IA32_MCG_STATUS 0x17a
-#define MSR_IA32_MCG_CTL 0x17b
-
-#define MSR_IA32_EVNTSEL0 0x186
-#define MSR_IA32_EVNTSEL1 0x187
-
-#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
-
-#define MSR_IA32_PEBS_ENABLE 0x3f1
-#define MSR_IA32_DS_AREA 0x600
-#define MSR_IA32_PERF_CAPABILITIES 0x345
-
-#define MSR_MTRRfix64K_00000 0x250
-#define MSR_MTRRfix16K_80000 0x258
-#define MSR_MTRRfix16K_A0000 0x259
-#define MSR_MTRRfix4K_C0000 0x268
-#define MSR_MTRRfix4K_C8000 0x269
-#define MSR_MTRRfix4K_D0000 0x26a
-#define MSR_MTRRfix4K_D8000 0x26b
-#define MSR_MTRRfix4K_E0000 0x26c
-#define MSR_MTRRfix4K_E8000 0x26d
-#define MSR_MTRRfix4K_F0000 0x26e
-#define MSR_MTRRfix4K_F8000 0x26f
-#define MSR_MTRRdefType 0x2ff
-
-#define MSR_IA32_MC0_CTL 0x400
-#define MSR_IA32_MC0_STATUS 0x401
-#define MSR_IA32_MC0_ADDR 0x402
-#define MSR_IA32_MC0_MISC 0x403
-
-#define MSR_P6_PERFCTR0 0xc1
-#define MSR_P6_PERFCTR1 0xc2
-#define MSR_P6_EVNTSEL0 0x186
-#define MSR_P6_EVNTSEL1 0x187
-
-/* K7/K8 MSRs. Not complete. See the architecture manual for a more complete list. */
-#define MSR_K7_EVNTSEL0 0xC0010000
-#define MSR_K7_PERFCTR0 0xC0010004
-#define MSR_K7_EVNTSEL1 0xC0010001
-#define MSR_K7_PERFCTR1 0xC0010005
-#define MSR_K7_EVNTSEL2 0xC0010002
-#define MSR_K7_PERFCTR2 0xC0010006
-#define MSR_K7_EVNTSEL3 0xC0010003
-#define MSR_K7_PERFCTR3 0xC0010007
-#define MSR_K8_TOP_MEM1 0xC001001A
-#define MSR_K8_TOP_MEM2 0xC001001D
-#define MSR_K8_SYSCFG 0xC0010010
-#define MSR_K8_HWCR 0xC0010015
-
-/* K6 MSRs */
-#define MSR_K6_EFER 0xC0000080
-#define MSR_K6_STAR 0xC0000081
-#define MSR_K6_WHCR 0xC0000082
-#define MSR_K6_UWCCR 0xC0000085
-#define MSR_K6_PSOR 0xC0000087
-#define MSR_K6_PFIR 0xC0000088
-
-/* Centaur-Hauls/IDT defined MSRs. */
-#define MSR_IDT_FCR1 0x107
-#define MSR_IDT_FCR2 0x108
-#define MSR_IDT_FCR3 0x109
-#define MSR_IDT_FCR4 0x10a
-
-#define MSR_IDT_MCR0 0x110
-#define MSR_IDT_MCR1 0x111
-#define MSR_IDT_MCR2 0x112
-#define MSR_IDT_MCR3 0x113
-#define MSR_IDT_MCR4 0x114
-#define MSR_IDT_MCR5 0x115
-#define MSR_IDT_MCR6 0x116
-#define MSR_IDT_MCR7 0x117
-#define MSR_IDT_MCR_CTRL 0x120
-
-/* VIA Cyrix defined MSRs*/
-#define MSR_VIA_FCR 0x1107
-#define MSR_VIA_LONGHAUL 0x110a
-#define MSR_VIA_RNG 0x110b
-#define MSR_VIA_BCR2 0x1147
-
-/* Intel defined MSRs. */
-#define MSR_IA32_P5_MC_ADDR 0
-#define MSR_IA32_P5_MC_TYPE 1
-#define MSR_IA32_PLATFORM_ID 0x17
-#define MSR_IA32_EBL_CR_POWERON 0x2a
-
-#define MSR_IA32_APICBASE 0x1b
-#define MSR_IA32_APICBASE_BSP (1<<8)
-#define MSR_IA32_APICBASE_ENABLE (1<<11)
-#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
-
-/* P4/Xeon+ specific */
-#define MSR_IA32_MCG_EAX 0x180
-#define MSR_IA32_MCG_EBX 0x181
-#define MSR_IA32_MCG_ECX 0x182
-#define MSR_IA32_MCG_EDX 0x183
-#define MSR_IA32_MCG_ESI 0x184
-#define MSR_IA32_MCG_EDI 0x185
-#define MSR_IA32_MCG_EBP 0x186
-#define MSR_IA32_MCG_ESP 0x187
-#define MSR_IA32_MCG_EFLAGS 0x188
-#define MSR_IA32_MCG_EIP 0x189
-#define MSR_IA32_MCG_RESERVED 0x18A
-
-#define MSR_P6_EVNTSEL0 0x186
-#define MSR_P6_EVNTSEL1 0x187
-
-#define MSR_IA32_PERF_STATUS 0x198
-#define MSR_IA32_PERF_CTL 0x199
-
-#define MSR_IA32_MPERF 0xE7
-#define MSR_IA32_APERF 0xE8
-
-#define MSR_IA32_THERM_CONTROL 0x19a
-#define MSR_IA32_THERM_INTERRUPT 0x19b
-#define MSR_IA32_THERM_STATUS 0x19c
-#define MSR_IA32_MISC_ENABLE 0x1a0
-
-#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
-
-#define MSR_IA32_MC0_CTL 0x400
-#define MSR_IA32_MC0_STATUS 0x401
-#define MSR_IA32_MC0_ADDR 0x402
-#define MSR_IA32_MC0_MISC 0x403
-
-/* Pentium IV performance counter MSRs */
-#define MSR_P4_BPU_PERFCTR0 0x300
-#define MSR_P4_BPU_PERFCTR1 0x301
-#define MSR_P4_BPU_PERFCTR2 0x302
-#define MSR_P4_BPU_PERFCTR3 0x303
-#define MSR_P4_MS_PERFCTR0 0x304
-#define MSR_P4_MS_PERFCTR1 0x305
-#define MSR_P4_MS_PERFCTR2 0x306
-#define MSR_P4_MS_PERFCTR3 0x307
-#define MSR_P4_FLAME_PERFCTR0 0x308
-#define MSR_P4_FLAME_PERFCTR1 0x309
-#define MSR_P4_FLAME_PERFCTR2 0x30a
-#define MSR_P4_FLAME_PERFCTR3 0x30b
-#define MSR_P4_IQ_PERFCTR0 0x30c
-#define MSR_P4_IQ_PERFCTR1 0x30d
-#define MSR_P4_IQ_PERFCTR2 0x30e
-#define MSR_P4_IQ_PERFCTR3 0x30f
-#define MSR_P4_IQ_PERFCTR4 0x310
-#define MSR_P4_IQ_PERFCTR5 0x311
-#define MSR_P4_BPU_CCCR0 0x360
-#define MSR_P4_BPU_CCCR1 0x361
-#define MSR_P4_BPU_CCCR2 0x362
-#define MSR_P4_BPU_CCCR3 0x363
-#define MSR_P4_MS_CCCR0 0x364
-#define MSR_P4_MS_CCCR1 0x365
-#define MSR_P4_MS_CCCR2 0x366
-#define MSR_P4_MS_CCCR3 0x367
-#define MSR_P4_FLAME_CCCR0 0x368
-#define MSR_P4_FLAME_CCCR1 0x369
-#define MSR_P4_FLAME_CCCR2 0x36a
-#define MSR_P4_FLAME_CCCR3 0x36b
-#define MSR_P4_IQ_CCCR0 0x36c
-#define MSR_P4_IQ_CCCR1 0x36d
-#define MSR_P4_IQ_CCCR2 0x36e
-#define MSR_P4_IQ_CCCR3 0x36f
-#define MSR_P4_IQ_CCCR4 0x370
-#define MSR_P4_IQ_CCCR5 0x371
-#define MSR_P4_ALF_ESCR0 0x3ca
-#define MSR_P4_ALF_ESCR1 0x3cb
-#define MSR_P4_BPU_ESCR0 0x3b2
-#define MSR_P4_BPU_ESCR1 0x3b3
-#define MSR_P4_BSU_ESCR0 0x3a0
-#define MSR_P4_BSU_ESCR1 0x3a1
-#define MSR_P4_CRU_ESCR0 0x3b8
-#define MSR_P4_CRU_ESCR1 0x3b9
-#define MSR_P4_CRU_ESCR2 0x3cc
-#define MSR_P4_CRU_ESCR3 0x3cd
-#define MSR_P4_CRU_ESCR4 0x3e0
-#define MSR_P4_CRU_ESCR5 0x3e1
-#define MSR_P4_DAC_ESCR0 0x3a8
-#define MSR_P4_DAC_ESCR1 0x3a9
-#define MSR_P4_FIRM_ESCR0 0x3a4
-#define MSR_P4_FIRM_ESCR1 0x3a5
-#define MSR_P4_FLAME_ESCR0 0x3a6
-#define MSR_P4_FLAME_ESCR1 0x3a7
-#define MSR_P4_FSB_ESCR0 0x3a2
-#define MSR_P4_FSB_ESCR1 0x3a3
-#define MSR_P4_IQ_ESCR0 0x3ba
-#define MSR_P4_IQ_ESCR1 0x3bb
-#define MSR_P4_IS_ESCR0 0x3b4
-#define MSR_P4_IS_ESCR1 0x3b5
-#define MSR_P4_ITLB_ESCR0 0x3b6
-#define MSR_P4_ITLB_ESCR1 0x3b7
-#define MSR_P4_IX_ESCR0 0x3c8
-#define MSR_P4_IX_ESCR1 0x3c9
-#define MSR_P4_MOB_ESCR0 0x3aa
-#define MSR_P4_MOB_ESCR1 0x3ab
-#define MSR_P4_MS_ESCR0 0x3c0
-#define MSR_P4_MS_ESCR1 0x3c1
-#define MSR_P4_PMH_ESCR0 0x3ac
-#define MSR_P4_PMH_ESCR1 0x3ad
-#define MSR_P4_RAT_ESCR0 0x3bc
-#define MSR_P4_RAT_ESCR1 0x3bd
-#define MSR_P4_SAAT_ESCR0 0x3ae
-#define MSR_P4_SAAT_ESCR1 0x3af
-#define MSR_P4_SSU_ESCR0 0x3be
-#define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */
-#define MSR_P4_TBPU_ESCR0 0x3c2
-#define MSR_P4_TBPU_ESCR1 0x3c3
-#define MSR_P4_TC_ESCR0 0x3c4
-#define MSR_P4_TC_ESCR1 0x3c5
-#define MSR_P4_U2L_ESCR0 0x3b0
-#define MSR_P4_U2L_ESCR1 0x3b1
-
-/* Intel Core-based CPU performance counters */
-#define MSR_CORE_PERF_FIXED_CTR0 0x309
-#define MSR_CORE_PERF_FIXED_CTR1 0x30a
-#define MSR_CORE_PERF_FIXED_CTR2 0x30b
-#define MSR_CORE_PERF_FIXED_CTR_CTRL 0x38d
-#define MSR_CORE_PERF_GLOBAL_STATUS 0x38e
-#define MSR_CORE_PERF_GLOBAL_CTRL 0x38f
-#define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x390
-
-#endif
+static inline int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h)
+{
+ return rdmsr_safe(msr_no, l, h);
+}
+static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h)
+{
+ return wrmsr_safe(msr_no, l, h);
+}
+#endif /* CONFIG_SMP */
+#endif /* __ASSEMBLY__ */
+#endif /* X86_64_MSR_H */
diff --git a/include/asm-x86_64/mtrr.h b/include/asm-x86_64/mtrr.h
index d6135b2549b..b557c486bef 100644
--- a/include/asm-x86_64/mtrr.h
+++ b/include/asm-x86_64/mtrr.h
@@ -135,6 +135,18 @@ struct mtrr_gentry32
#endif /* CONFIG_COMPAT */
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+extern void mtrr_save_fixed_ranges(void *);
+extern void mtrr_save_state(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#define mtrr_save_fixed_ranges(arg) do {} while (0)
+#define mtrr_save_state() do {} while (0)
+#endif
+
#endif /* __KERNEL__ */
#endif /* _LINUX_MTRR_H */
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index 72375e7d32a..d0a7f53b149 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -80,4 +80,13 @@ extern int unknown_nmi_panic;
void __trigger_all_cpu_backtrace(void);
#define trigger_all_cpu_backtrace() __trigger_all_cpu_backtrace()
+
+void lapic_watchdog_stop(void);
+int lapic_watchdog_init(unsigned nmi_hz);
+int lapic_wd_event(unsigned nmi_hz);
+unsigned lapic_adjust_nmi_hz(unsigned hz);
+int lapic_watchdog_ok(void);
+void disable_lapic_nmi_watchdog(void);
+void enable_lapic_nmi_watchdog(void);
+
#endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 10f346165ca..dee632fa457 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -1,14 +1,11 @@
#ifndef _X86_64_PAGE_H
#define _X86_64_PAGE_H
+#include <linux/const.h>
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
-#ifdef __ASSEMBLY__
-#define PAGE_SIZE (0x1 << PAGE_SHIFT)
-#else
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#endif
+#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PHYSICAL_PAGE_MASK (~(PAGE_SIZE-1) & __PHYSICAL_MASK)
@@ -33,10 +30,10 @@
#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */
#define LARGE_PAGE_MASK (~(LARGE_PAGE_SIZE-1))
-#define LARGE_PAGE_SIZE (1UL << PMD_SHIFT)
+#define LARGE_PAGE_SIZE (_AC(1,UL) << PMD_SHIFT)
#define HPAGE_SHIFT PMD_SHIFT
-#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
+#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
@@ -64,6 +61,8 @@ typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
+extern unsigned long phys_base;
+
#define pte_val(x) ((x).pte)
#define pmd_val(x) ((x).pmd)
#define pud_val(x) ((x).pud)
@@ -76,47 +75,38 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START)
-#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
-#define __START_KERNEL_map 0xffffffff80000000UL
-#define __PAGE_OFFSET 0xffff810000000000UL
+#endif /* !__ASSEMBLY__ */
-#else
#define __PHYSICAL_START CONFIG_PHYSICAL_START
+#define __KERNEL_ALIGN 0x200000
+
#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
-#define __START_KERNEL_map 0xffffffff80000000
-#define __PAGE_OFFSET 0xffff810000000000
-#endif /* !__ASSEMBLY__ */
+#define __START_KERNEL_map _AC(0xffffffff80000000, UL)
+#define __PAGE_OFFSET _AC(0xffff810000000000, UL)
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
/* See Documentation/x86_64/mm.txt for a description of the memory map. */
#define __PHYSICAL_MASK_SHIFT 46
-#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1)
+#define __PHYSICAL_MASK ((_AC(1,UL) << __PHYSICAL_MASK_SHIFT) - 1)
#define __VIRTUAL_MASK_SHIFT 48
-#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
+#define __VIRTUAL_MASK ((_AC(1,UL) << __VIRTUAL_MASK_SHIFT) - 1)
-#define KERNEL_TEXT_SIZE (40UL*1024*1024)
-#define KERNEL_TEXT_START 0xffffffff80000000UL
+#define KERNEL_TEXT_SIZE (40*1024*1024)
+#define KERNEL_TEXT_START _AC(0xffffffff80000000, UL)
+#define PAGE_OFFSET __PAGE_OFFSET
#ifndef __ASSEMBLY__
#include <asm/bug.h>
+extern unsigned long __phys_addr(unsigned long);
+
#endif /* __ASSEMBLY__ */
-#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
-
-/* Note: __pa(&symbol_visible_to_c) should be always replaced with __pa_symbol.
- Otherwise you risk miscompilation. */
-#define __pa(x) (((unsigned long)(x)>=__START_KERNEL_map)?(unsigned long)(x) - (unsigned long)__START_KERNEL_map:(unsigned long)(x) - PAGE_OFFSET)
-/* __pa_symbol should be used for C visible symbols.
- This seems to be the official gcc blessed way to do such arithmetic. */
-#define __pa_symbol(x) \
- ({unsigned long v; \
- asm("" : "=r" (v) : "0" (x)); \
- __pa(v); })
+#define __pa(x) __phys_addr((unsigned long)(x))
+#define __pa_symbol(x) __phys_addr((unsigned long)(x))
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
#define __boot_va(x) __va(x)
diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
index 5ed0ef34084..c6fbb67eac9 100644
--- a/include/asm-x86_64/percpu.h
+++ b/include/asm-x86_64/percpu.h
@@ -11,16 +11,6 @@
#include <asm/pda.h>
-#ifdef CONFIG_MODULES
-# define PERCPU_MODULE_RESERVE 8192
-#else
-# define PERCPU_MODULE_RESERVE 0
-#endif
-
-#define PERCPU_ENOUGH_ROOM \
- (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
- PERCPU_MODULE_RESERVE)
-
#define __per_cpu_offset(cpu) (cpu_pda(cpu)->data_offset)
#define __my_cpu_offset() read_pda(data_offset)
diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h
index 4e28b6060a5..8bb56468786 100644
--- a/include/asm-x86_64/pgalloc.h
+++ b/include/asm-x86_64/pgalloc.h
@@ -1,7 +1,6 @@
#ifndef _X86_64_PGALLOC_H
#define _X86_64_PGALLOC_H
-#include <asm/fixmap.h>
#include <asm/pda.h>
#include <linux/threads.h>
#include <linux/mm.h>
@@ -45,24 +44,16 @@ static inline void pgd_list_add(pgd_t *pgd)
struct page *page = virt_to_page(pgd);
spin_lock(&pgd_lock);
- page->index = (pgoff_t)pgd_list;
- if (pgd_list)
- pgd_list->private = (unsigned long)&page->index;
- pgd_list = page;
- page->private = (unsigned long)&pgd_list;
+ list_add(&page->lru, &pgd_list);
spin_unlock(&pgd_lock);
}
static inline void pgd_list_del(pgd_t *pgd)
{
- struct page *next, **pprev, *page = virt_to_page(pgd);
+ struct page *page = virt_to_page(pgd);
spin_lock(&pgd_lock);
- next = (struct page *)page->index;
- pprev = (struct page **)page->private;
- *pprev = next;
- if (next)
- next->private = (unsigned long)pprev;
+ list_del(&page->lru);
spin_unlock(&pgd_lock);
}
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 730bd602841..08b9831f2e1 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -1,22 +1,22 @@
#ifndef _X86_64_PGTABLE_H
#define _X86_64_PGTABLE_H
+#include <linux/const.h>
+#ifndef __ASSEMBLY__
+
/*
* This file contains the functions and defines necessary to modify and use
* the x86-64 page table tree.
*/
#include <asm/processor.h>
-#include <asm/fixmap.h>
#include <asm/bitops.h>
#include <linux/threads.h>
#include <asm/pda.h>
extern pud_t level3_kernel_pgt[512];
-extern pud_t level3_physmem_pgt[512];
extern pud_t level3_ident_pgt[512];
extern pmd_t level2_kernel_pgt[512];
extern pgd_t init_level4_pgt[];
-extern pgd_t boot_level4_pgt[];
extern unsigned long __supported_pte_mask;
#define swapper_pg_dir init_level4_pgt
@@ -31,6 +31,8 @@ extern void clear_kernel_mapping(unsigned long addr, unsigned long size);
extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+#endif /* !__ASSEMBLY__ */
+
/*
* PGDIR_SHIFT determines what a top-level page table entry can map
*/
@@ -55,6 +57,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
*/
#define PTRS_PER_PTE 512
+#ifndef __ASSEMBLY__
+
#define pte_ERROR(e) \
printk("%s:%d: bad pte %p(%016lx).\n", __FILE__, __LINE__, &(e), pte_val(e))
#define pmd_ERROR(e) \
@@ -118,22 +122,23 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
#define pte_pgprot(a) (__pgprot((a).pte & ~PHYSICAL_PAGE_MASK))
-#define PMD_SIZE (1UL << PMD_SHIFT)
+#endif /* !__ASSEMBLY__ */
+
+#define PMD_SIZE (_AC(1,UL) << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
-#define PUD_SIZE (1UL << PUD_SHIFT)
+#define PUD_SIZE (_AC(1,UL) << PUD_SHIFT)
#define PUD_MASK (~(PUD_SIZE-1))
-#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1))
#define USER_PTRS_PER_PGD ((TASK_SIZE-1)/PGDIR_SIZE+1)
#define FIRST_USER_ADDRESS 0
-#ifndef __ASSEMBLY__
-#define MAXMEM 0x3fffffffffffUL
-#define VMALLOC_START 0xffffc20000000000UL
-#define VMALLOC_END 0xffffe1ffffffffffUL
-#define MODULES_VADDR 0xffffffff88000000UL
-#define MODULES_END 0xfffffffffff00000UL
+#define MAXMEM _AC(0x3fffffffffff, UL)
+#define VMALLOC_START _AC(0xffffc20000000000, UL)
+#define VMALLOC_END _AC(0xffffe1ffffffffff, UL)
+#define MODULES_VADDR _AC(0xffffffff88000000, UL)
+#define MODULES_END _AC(0xfffffffffff00000, UL)
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
#define _PAGE_BIT_PRESENT 0
@@ -159,7 +164,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
#define _PAGE_GLOBAL 0x100 /* Global TLB entry */
#define _PAGE_PROTNONE 0x080 /* If not present */
-#define _PAGE_NX (1UL<<_PAGE_BIT_NX)
+#define _PAGE_NX (_AC(1,UL)<<_PAGE_BIT_NX)
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
@@ -221,6 +226,8 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
#define __S110 PAGE_SHARED_EXEC
#define __S111 PAGE_SHARED_EXEC
+#ifndef __ASSEMBLY__
+
static inline unsigned long pgd_bad(pgd_t pgd)
{
return pgd_val(pgd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
@@ -403,20 +410,13 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
extern spinlock_t pgd_lock;
-extern struct page *pgd_list;
-void vmalloc_sync_all(void);
-
-#endif /* !__ASSEMBLY__ */
+extern struct list_head pgd_list;
extern int kern_addr_valid(unsigned long addr);
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
-#define MK_IOSPACE_PFN(space, pfn) (pfn)
-#define GET_IOSPACE(pfn) 0
-#define GET_PFN(pfn) (pfn)
-
#define HAVE_ARCH_UNMAPPED_AREA
#define pgtable_cache_init() do { } while (0)
@@ -437,5 +437,6 @@ extern int kern_addr_valid(unsigned long addr);
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
#include <asm-generic/pgtable.h>
+#endif /* !__ASSEMBLY__ */
#endif /* _X86_64_PGTABLE_H */
diff --git a/include/asm-x86_64/processor-flags.h b/include/asm-x86_64/processor-flags.h
new file mode 100644
index 00000000000..ec99a57b2c6
--- /dev/null
+++ b/include/asm-x86_64/processor-flags.h
@@ -0,0 +1 @@
+#include <asm-i386/processor-flags.h>
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 76552d72804..461ffe4c1fc 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -20,6 +20,7 @@
#include <asm/percpu.h>
#include <linux/personality.h>
#include <linux/cpumask.h>
+#include <asm/processor-flags.h>
#define TF_MASK 0x00000100
#define IF_MASK 0x00000200
@@ -103,42 +104,6 @@ extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
extern unsigned short num_cache_leaves;
/*
- * EFLAGS bits
- */
-#define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
-#define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
-#define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
-#define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
-#define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
-#define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
-#define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
-#define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
-#define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
-#define X86_EFLAGS_NT 0x00004000 /* Nested Task */
-#define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
-#define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
-#define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
-#define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
-
-/*
- * Intel CPU features in CR4
- */
-#define X86_CR4_VME 0x0001 /* enable vm86 extensions */
-#define X86_CR4_PVI 0x0002 /* virtual interrupts flag enable */
-#define X86_CR4_TSD 0x0004 /* disable time stamp at ipl 3 */
-#define X86_CR4_DE 0x0008 /* enable debugging extensions */
-#define X86_CR4_PSE 0x0010 /* enable page size extensions */
-#define X86_CR4_PAE 0x0020 /* enable physical address extensions */
-#define X86_CR4_MCE 0x0040 /* Machine check enable */
-#define X86_CR4_PGE 0x0080 /* enable global pages */
-#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
-#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
-#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
-
-/*
* Save the cr4 feature set we're using (ie
* Pentium 4MB enable and PPro Global page
* enable), so that any CPU's that boot up
@@ -201,7 +166,7 @@ struct i387_fxsave_struct {
u32 mxcsr;
u32 mxcsr_mask;
u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
- u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 128 bytes */
+ u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
u32 padding[24];
} __attribute__ ((aligned (16)));
@@ -427,22 +392,6 @@ static inline void prefetchw(void *x)
#define cpu_relax() rep_nop()
/*
- * NSC/Cyrix CPU configuration register indexes
- */
-#define CX86_CCR0 0xc0
-#define CX86_CCR1 0xc1
-#define CX86_CCR2 0xc2
-#define CX86_CCR3 0xc3
-#define CX86_CCR4 0xe8
-#define CX86_CCR5 0xe9
-#define CX86_CCR6 0xea
-#define CX86_CCR7 0xeb
-#define CX86_DIR0 0xfe
-#define CX86_DIR1 0xff
-#define CX86_ARR_BASE 0xc4
-#define CX86_RCR_BASE 0xdc
-
-/*
* NSC/Cyrix CPU indexed register access macros
*/
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index b6e65a699f2..85255db1e82 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -11,18 +11,9 @@ struct pt_regs;
extern void start_kernel(void);
extern void pda_init(int);
-extern void zap_low_mappings(int cpu);
-
extern void early_idt_handler(void);
extern void mcheck_init(struct cpuinfo_x86 *c);
-#ifdef CONFIG_MTRR
-extern void mtrr_ap_init(void);
-extern void mtrr_bp_init(void);
-#else
-#define mtrr_ap_init() do {} while (0)
-#define mtrr_bp_init() do {} while (0)
-#endif
extern void init_memory_mapping(unsigned long start, unsigned long end);
extern void system_call(void);
@@ -82,7 +73,6 @@ extern void syscall32_cpu_init(void);
extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
extern void early_quirks(void);
-extern void quirk_intel_irqbalance(void);
extern void check_efer(void);
extern int unhandled_signal(struct task_struct *tsk, int sig);
@@ -93,6 +83,7 @@ extern unsigned long table_start, table_end;
extern int exception_trace;
extern unsigned cpu_khz;
+extern unsigned tsc_khz;
extern void no_iommu_init(void);
extern int force_iommu, no_iommu;
@@ -121,8 +112,12 @@ extern int gsi_irq_sharing(int gsi);
extern void smp_local_timer_interrupt(void);
+extern int force_mwait;
+
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
+void i8254_timer_resume(void);
+
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
#define round_down(x,y) ((x) & ~((y)-1))
diff --git a/include/asm-x86_64/scatterlist.h b/include/asm-x86_64/scatterlist.h
index 49d89f8129c..eaf7ada27e1 100644
--- a/include/asm-x86_64/scatterlist.h
+++ b/include/asm-x86_64/scatterlist.h
@@ -1,6 +1,8 @@
#ifndef _X8664_SCATTERLIST_H
#define _X8664_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
index 334ddcdd8f9..adf2bf1e187 100644
--- a/include/asm-x86_64/segment.h
+++ b/include/asm-x86_64/segment.h
@@ -6,7 +6,7 @@
#define __KERNEL_CS 0x10
#define __KERNEL_DS 0x18
-#define __KERNEL32_CS 0x38
+#define __KERNEL32_CS 0x08
/*
* we cannot use the same code segment descriptor for user and kernel
diff --git a/include/asm-x86_64/serial.h b/include/asm-x86_64/serial.h
index b0496e0d72a..8ebd765c674 100644
--- a/include/asm-x86_64/serial.h
+++ b/include/asm-x86_64/serial.h
@@ -11,19 +11,3 @@
* megabits/second; but this requires the faster clock.
*/
#define BASE_BAUD ( 1843200 / 16 )
-
-/* Standard COM flags (except for COM4, because of the 8514 problem) */
-#ifdef CONFIG_SERIAL_DETECT_IRQ
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ)
-#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ)
-#else
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
-#endif
-
-#define SERIAL_PORT_DFNS \
- /* UART CLK PORT IRQ FLAGS */ \
- { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
- { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
- { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index de592a408c0..3f303d2365e 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -10,10 +10,9 @@
#include <linux/init.h>
extern int disable_apic;
-#include <asm/fixmap.h>
#include <asm/mpspec.h>
-#include <asm/io_apic.h>
#include <asm/apic.h>
+#include <asm/io_apic.h>
#include <asm/thread_info.h>
#ifdef CONFIG_SMP
@@ -38,7 +37,6 @@ extern void lock_ipi_call_lock(void);
extern void unlock_ipi_call_lock(void);
extern int smp_num_siblings;
extern void smp_send_reschedule(int cpu);
-void smp_stop_cpu(void);
extern cpumask_t cpu_sibling_map[NR_CPUS];
extern cpumask_t cpu_core_map[NR_CPUS];
@@ -59,12 +57,6 @@ static inline int num_booting_cpus(void)
#define raw_smp_processor_id() read_pda(cpunumber)
-static inline int hard_smp_processor_id(void)
-{
- /* we don't want to mark this access volatile - bad code generation */
- return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
-}
-
extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
extern void prefill_possible_map(void);
@@ -73,7 +65,13 @@ extern unsigned __cpuinitdata disabled_cpus;
#define NO_PROC_ID 0xFF /* No processor magic marker */
-#endif
+#endif /* CONFIG_SMP */
+
+static inline int hard_smp_processor_id(void)
+{
+ /* we don't want to mark this access volatile - bad code generation */
+ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID));
+}
/*
* Some lowlevel functions might want to know about
diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
index bc7f81715e5..9c3f8de90d2 100644
--- a/include/asm-x86_64/suspend.h
+++ b/include/asm-x86_64/suspend.h
@@ -17,6 +17,7 @@ struct saved_context {
u16 ds, es, fs, gs, ss;
unsigned long gs_base, gs_kernel_base, fs_base;
unsigned long cr0, cr2, cr3, cr4, cr8;
+ unsigned long efer;
u16 gdt_pad;
u16 gdt_limit;
unsigned long gdt_base;
@@ -44,12 +45,12 @@ extern unsigned long saved_context_eflags;
extern void fix_processor_context(void);
#ifdef CONFIG_ACPI_SLEEP
-extern unsigned long saved_eip;
-extern unsigned long saved_esp;
-extern unsigned long saved_ebp;
-extern unsigned long saved_ebx;
-extern unsigned long saved_esi;
-extern unsigned long saved_edi;
+extern unsigned long saved_rip;
+extern unsigned long saved_rsp;
+extern unsigned long saved_rbp;
+extern unsigned long saved_rbx;
+extern unsigned long saved_rsi;
+extern unsigned long saved_rdi;
/* routines for saving/restoring kernel state */
extern int acpi_save_state_mem(void);
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index bd376bc8c4a..ead9f9a5623 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -3,7 +3,7 @@
#include <linux/kernel.h>
#include <asm/segment.h>
-#include <asm/alternative.h>
+#include <asm/cmpxchg.h>
#ifdef __KERNEL__
@@ -39,7 +39,7 @@
[threadrsp] "i" (offsetof(struct task_struct, thread.rsp)), \
[ti_flags] "i" (offsetof(struct thread_info, flags)),\
[tif_fork] "i" (TIF_FORK), \
- [thread_info] "i" (offsetof(struct task_struct, thread_info)), \
+ [thread_info] "i" (offsetof(struct task_struct, stack)), \
[pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)) \
: "memory", "cc" __EXTRA_CLOBBER)
@@ -89,6 +89,11 @@ static inline unsigned long read_cr3(void)
return cr3;
}
+static inline void write_cr3(unsigned long val)
+{
+ asm volatile("movq %0,%%cr3" :: "r" (val) : "memory");
+}
+
static inline unsigned long read_cr4(void)
{
unsigned long cr4;
@@ -98,7 +103,7 @@ static inline unsigned long read_cr4(void)
static inline void write_cr4(unsigned long val)
{
- asm volatile("movq %0,%%cr4" :: "r" (val));
+ asm volatile("movq %0,%%cr4" :: "r" (val) : "memory");
}
#define stts() write_cr0(8 | read_cr0())
@@ -119,100 +124,6 @@ static inline void sched_cacheflush(void)
#define nop() __asm__ __volatile__ ("nop")
-#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
-
-#define tas(ptr) (xchg((ptr),1))
-
-#define __xg(x) ((volatile long *)(x))
-
-static inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
-{
- *ptr = val;
-}
-
-#define _set_64bit set_64bit
-
-/*
- * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
- * Note 2: xchg has side effect, so that attribute volatile is necessary,
- * but generally the primitive is invalid, *ptr is output argument. --ANK
- */
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
-{
- switch (size) {
- case 1:
- __asm__ __volatile__("xchgb %b0,%1"
- :"=q" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 2:
- __asm__ __volatile__("xchgw %w0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 4:
- __asm__ __volatile__("xchgl %k0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- case 8:
- __asm__ __volatile__("xchgq %0,%1"
- :"=r" (x)
- :"m" (*__xg(ptr)), "0" (x)
- :"memory");
- break;
- }
- return x;
-}
-
-/*
- * Atomic compare and exchange. Compare OLD with MEM, if identical,
- * store NEW in MEM. Return the initial value in MEM. Success is
- * indicated by comparing RETURN with OLD.
- */
-
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- unsigned long prev;
- switch (size) {
- case 1:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
- : "=a"(prev)
- : "q"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 2:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 4:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- case 8:
- __asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
- : "=a"(prev)
- : "r"(new), "m"(*__xg(ptr)), "0"(old)
- : "memory");
- return prev;
- }
- return old;
-}
-
-#define cmpxchg(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
- (unsigned long)(n),sizeof(*(ptr))))
-
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
diff --git a/include/asm-x86_64/termbits.h b/include/asm-x86_64/termbits.h
index 6cfc3bb10c1..7405756dd41 100644
--- a/include/asm-x86_64/termbits.h
+++ b/include/asm-x86_64/termbits.h
@@ -160,7 +160,7 @@ struct ktermios {
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
-#define IBSHIFT 8 /* Shift from CBAUD to CIBAUD */
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
/* c_lflag bits */
#define ISIG 0000001
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 74a6c74397f..10bb5a8ed68 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -162,7 +162,7 @@ static inline struct thread_info *stack_thread_info(void)
#define TS_COMPAT 0x0002 /* 32bit syscall active */
#define TS_POLLING 0x0004 /* true if in idle loop and not sleeping */
-#define tsk_is_polling(t) ((t)->thread_info->status & TS_POLLING)
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
#endif /* __KERNEL__ */
diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h
index 8c6808a3fba..f6527e1b6c1 100644
--- a/include/asm-x86_64/timex.h
+++ b/include/asm-x86_64/timex.h
@@ -27,6 +27,6 @@ extern int read_current_timer(unsigned long *timer_value);
#define NS_SCALE 10 /* 2^10, carefully chosen */
#define US_SCALE 32 /* 2^32, arbitralrily chosen */
-extern void mark_tsc_unstable(void);
+extern void mark_tsc_unstable(char *msg);
extern void set_cyc2ns_scale(unsigned long khz);
#endif
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 983bd296c81..512401b8725 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -3,41 +3,18 @@
#include <linux/mm.h>
#include <asm/processor.h>
-
-static inline unsigned long get_cr3(void)
-{
- unsigned long cr3;
- asm volatile("mov %%cr3,%0" : "=r" (cr3));
- return cr3;
-}
-
-static inline void set_cr3(unsigned long cr3)
-{
- asm volatile("mov %0,%%cr3" :: "r" (cr3) : "memory");
-}
+#include <asm/system.h>
static inline void __flush_tlb(void)
{
- set_cr3(get_cr3());
-}
-
-static inline unsigned long get_cr4(void)
-{
- unsigned long cr4;
- asm volatile("mov %%cr4,%0" : "=r" (cr4));
- return cr4;
-}
-
-static inline void set_cr4(unsigned long cr4)
-{
- asm volatile("mov %0,%%cr4" :: "r" (cr4) : "memory");
+ write_cr3(read_cr3());
}
static inline void __flush_tlb_all(void)
{
- unsigned long cr4 = get_cr4();
- set_cr4(cr4 & ~X86_CR4_PGE); /* clear PGE */
- set_cr4(cr4); /* write old PGE again and flush TLBs */
+ unsigned long cr4 = read_cr4();
+ write_cr4(cr4 & ~X86_CR4_PGE); /* clear PGE */
+ write_cr4(cr4); /* write old PGE again and flush TLBs */
}
#define __flush_tlb_one(addr) \
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index c5f596e71fa..595703949df 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -619,8 +619,8 @@ __SYSCALL(__NR_sync_file_range, sys_sync_file_range)
__SYSCALL(__NR_vmsplice, sys_vmsplice)
#define __NR_move_pages 279
__SYSCALL(__NR_move_pages, sys_move_pages)
-
-#define __NR_syscall_max __NR_move_pages
+#define __NR_utimensat 280
+__SYSCALL(__NR_utimensat, sys_utimensat)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
@@ -655,7 +655,6 @@ __SYSCALL(__NR_move_pages, sys_move_pages)
#include <asm/ptrace.h>
asmlinkage long sys_iopl(unsigned int level, struct pt_regs *regs);
-asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on);
struct sigaction;
asmlinkage long sys_rt_sigaction(int sig,
const struct sigaction __user *act,
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
index 5c267202106..b3b23540f14 100644
--- a/include/asm-xtensa/atomic.h
+++ b/include/asm-xtensa/atomic.h
@@ -234,14 +234,21 @@ static inline int atomic_sub_return(int i, atomic_t * v)
* Atomically adds @a to @v, so long as it was not @u.
* Returns non-zero if @v was not @u, and zero otherwise.
*/
-#define atomic_add_unless(v, a, u) \
-({ \
- int c, old; \
- c = atomic_read(v); \
- while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
- c = old; \
- c != (u); \
-})
+static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int c, old;
+ c = atomic_read(v);
+ for (;;) {
+ if (unlikely(c == (u)))
+ break;
+ old = atomic_cmpxchg((v), c, c + (a));
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != (u);
+}
+
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
diff --git a/include/asm-xtensa/kdebug.h b/include/asm-xtensa/kdebug.h
new file mode 100644
index 00000000000..6ece1b03766
--- /dev/null
+++ b/include/asm-xtensa/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/include/asm-xtensa/mmu_context.h b/include/asm-xtensa/mmu_context.h
index f14851f086c..92f948392eb 100644
--- a/include/asm-xtensa/mmu_context.h
+++ b/include/asm-xtensa/mmu_context.h
@@ -18,6 +18,7 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
+#include <asm-generic/mm_hooks.h>
#define XCHAL_MMU_ASID_BITS 8
diff --git a/include/asm-xtensa/platform-iss/simcall.h b/include/asm-xtensa/platform-iss/simcall.h
index 6acb572759a..b7952c06a2b 100644
--- a/include/asm-xtensa/platform-iss/simcall.h
+++ b/include/asm-xtensa/platform-iss/simcall.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/platform-iss/hardware.h
+ * include/asm-xtensa/platform-iss/simcall.h
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
diff --git a/include/asm-xtensa/scatterlist.h b/include/asm-xtensa/scatterlist.h
index 38a2b9acd65..ca337a29429 100644
--- a/include/asm-xtensa/scatterlist.h
+++ b/include/asm-xtensa/scatterlist.h
@@ -11,6 +11,8 @@
#ifndef _XTENSA_SCATTERLIST_H
#define _XTENSA_SCATTERLIST_H
+#include <asm/types.h>
+
struct scatterlist {
struct page *page;
unsigned int offset;
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
index 4aaed7fe6cf..ddc970847ae 100644
--- a/include/asm-xtensa/system.h
+++ b/include/asm-xtensa/system.h
@@ -183,8 +183,6 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val)
return tmp;
}
-#define tas(ptr) (xchg((ptr),1))
-
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
/*
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 4e05e93ff68..b2b1e6efd81 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -13,8 +13,11 @@
#define _CRYPTO_ALGAPI_H
#include <linux/crypto.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
struct module;
+struct rtattr;
struct seq_file;
struct crypto_type {
@@ -38,7 +41,7 @@ struct crypto_template {
struct hlist_head instances;
struct module *module;
- struct crypto_instance *(*alloc)(void *param, unsigned int len);
+ struct crypto_instance *(*alloc)(struct rtattr **tb);
void (*free)(struct crypto_instance *inst);
char name[CRYPTO_MAX_ALG_NAME];
@@ -48,6 +51,15 @@ struct crypto_spawn {
struct list_head list;
struct crypto_alg *alg;
struct crypto_instance *inst;
+ u32 mask;
+};
+
+struct crypto_queue {
+ struct list_head list;
+ struct list_head *backlog;
+
+ unsigned int qlen;
+ unsigned int max_qlen;
};
struct scatter_walk {
@@ -81,6 +93,7 @@ struct blkcipher_walk {
int flags;
};
+extern const struct crypto_type crypto_ablkcipher_type;
extern const struct crypto_type crypto_blkcipher_type;
extern const struct crypto_type crypto_hash_type;
@@ -91,16 +104,23 @@ void crypto_unregister_template(struct crypto_template *tmpl);
struct crypto_template *crypto_lookup_template(const char *name);
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
- struct crypto_instance *inst);
+ struct crypto_instance *inst, u32 mask);
void crypto_drop_spawn(struct crypto_spawn *spawn);
struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
u32 mask);
-struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
- u32 type, u32 mask);
+struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb);
+int crypto_check_attr_type(struct rtattr **tb, u32 type);
+struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask);
struct crypto_instance *crypto_alloc_instance(const char *name,
struct crypto_alg *alg);
+void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen);
+int crypto_enqueue_request(struct crypto_queue *queue,
+ struct crypto_async_request *request);
+struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue);
+int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm);
+
int blkcipher_walk_done(struct blkcipher_desc *desc,
struct blkcipher_walk *walk, int err);
int blkcipher_walk_virt(struct blkcipher_desc *desc,
@@ -118,11 +138,37 @@ static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm)
return (void *)ALIGN(addr, align);
}
+static inline struct crypto_instance *crypto_tfm_alg_instance(
+ struct crypto_tfm *tfm)
+{
+ return container_of(tfm->__crt_alg, struct crypto_instance, alg);
+}
+
static inline void *crypto_instance_ctx(struct crypto_instance *inst)
{
return inst->__ctx;
}
+static inline struct ablkcipher_alg *crypto_ablkcipher_alg(
+ struct crypto_ablkcipher *tfm)
+{
+ return &crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_ablkcipher;
+}
+
+static inline void *crypto_ablkcipher_ctx(struct crypto_ablkcipher *tfm)
+{
+ return crypto_tfm_ctx(&tfm->base);
+}
+
+static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
+ struct crypto_spawn *spawn)
+{
+ u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
+ u32 mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
+
+ return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
static inline void *crypto_blkcipher_ctx(struct crypto_blkcipher *tfm)
{
return crypto_tfm_ctx(&tfm->base);
@@ -170,5 +216,35 @@ static inline void blkcipher_walk_init(struct blkcipher_walk *walk,
walk->total = nbytes;
}
+static inline struct crypto_async_request *crypto_get_backlog(
+ struct crypto_queue *queue)
+{
+ return queue->backlog == &queue->list ? NULL :
+ container_of(queue->backlog, struct crypto_async_request, list);
+}
+
+static inline int ablkcipher_enqueue_request(struct ablkcipher_alg *alg,
+ struct ablkcipher_request *request)
+{
+ return crypto_enqueue_request(alg->queue, &request->base);
+}
+
+static inline struct ablkcipher_request *ablkcipher_dequeue_request(
+ struct ablkcipher_alg *alg)
+{
+ return ablkcipher_request_cast(crypto_dequeue_request(alg->queue));
+}
+
+static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req)
+{
+ return req->__ctx;
+}
+
+static inline int ablkcipher_tfm_in_queue(struct crypto_ablkcipher *tfm)
+{
+ return crypto_tfm_in_queue(crypto_ablkcipher_alg(tfm)->queue,
+ crypto_ablkcipher_tfm(tfm));
+}
+
#endif /* _CRYPTO_ALGAPI_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 4ff0f57d0ad..94cc04a143f 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -4,6 +4,7 @@ header-y += hdlc/
header-y += isdn/
header-y += nfsd/
header-y += raid/
+header-y += spi/
header-y += sunrpc/
header-y += tc_act/
header-y += netfilter/
@@ -33,7 +34,6 @@ header-y += atmsvc.h
header-y += atm_zatm.h
header-y += auto_fs4.h
header-y += auxvec.h
-header-y += awe_voice.h
header-y += ax25.h
header-y += b1lli.h
header-y += baycom.h
@@ -46,6 +46,7 @@ header-y += coda_psdev.h
header-y += coff.h
header-y += comstats.h
header-y += consolemap.h
+header-y += const.h
header-y += cycx_cfm.h
header-y += dlm_device.h
header-y += dm-ioctl.h
@@ -91,11 +92,11 @@ header-y += ip_mp_alg.h
header-y += ipsec.h
header-y += ipx.h
header-y += irda.h
-header-y += isdn_divertif.h
header-y += iso_fs.h
header-y += ixjuser.h
header-y += jffs2.h
header-y += keyctl.h
+header-y += kvm.h
header-y += limits.h
header-y += lock_dlm_plock.h
header-y += magic.h
@@ -120,6 +121,7 @@ header-y += pci_regs.h
header-y += personality.h
header-y += pfkeyv2.h
header-y += pg.h
+header-y += phantom.h
header-y += pkt_cls.h
header-y += pkt_sched.h
header-y += posix_types.h
@@ -139,6 +141,7 @@ header-y += sockios.h
header-y += som.h
header-y += sound.h
header-y += synclink.h
+header-y += taskstats.h
header-y += telephony.h
header-y += termios.h
header-y += ticable.h
@@ -238,6 +241,7 @@ unifdef-y += ipv6.h
unifdef-y += ipv6_route.h
unifdef-y += isdn.h
unifdef-y += isdnif.h
+unifdef-y += isdn_divertif.h
unifdef-y += isdn_ppp.h
unifdef-y += isicom.h
unifdef-y += jbd.h
diff --git a/include/linux/aio.h b/include/linux/aio.h
index a30ef13c9e6..43dc2ebfaa0 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -226,7 +226,8 @@ int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
__put_ioctx(kioctx); \
} while (0)
-#define in_aio() !is_sync_wait(current->io_wait)
+#define in_aio() (unlikely(!is_sync_wait(current->io_wait)))
+
/* may be used for debugging */
#define warn_if_async() \
do { \
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 6caeb98e29d..edb31bfff68 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -159,11 +159,19 @@ enum {
ATA_CMD_INIT_DEV_PARAMS = 0x91,
ATA_CMD_READ_NATIVE_MAX = 0xF8,
ATA_CMD_READ_NATIVE_MAX_EXT = 0x27,
+ ATA_CMD_SET_MAX = 0xF9,
+ ATA_CMD_SET_MAX_EXT = 0x37,
ATA_CMD_READ_LOG_EXT = 0x2f,
/* READ_LOG_EXT pages */
ATA_LOG_SATA_NCQ = 0x10,
+ /* READ/WRITE LONG (obsolete) */
+ ATA_CMD_READ_LONG = 0x22,
+ ATA_CMD_READ_LONG_ONCE = 0x23,
+ ATA_CMD_WRITE_LONG = 0x32,
+ ATA_CMD_WRITE_LONG_ONCE = 0x33,
+
/* SETFEATURES stuff */
SETFEATURES_XFER = 0x03,
XFER_UDMA_7 = 0x47,
@@ -194,6 +202,8 @@ enum {
SETFEATURES_WC_ON = 0x02, /* Enable write cache */
SETFEATURES_WC_OFF = 0x82, /* Disable write cache */
+ SETFEATURES_SPINUP = 0x07, /* Spin-up drive */
+
/* ATAPI stuff */
ATAPI_PKT_DMA = (1 << 0),
ATAPI_DMADIR = (1 << 2), /* ATAPI data dir:
diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h
deleted file mode 100644
index bf33f17bea9..00000000000
--- a/include/linux/awe_voice.h
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * include/linux/awe_voice.h
- *
- * Voice information definitions for the low level driver for the
- * AWE32/SB32/AWE64 wave table synth.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * 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 AWE_VOICE_H
-#define AWE_VOICE_H
-
-#ifndef SAMPLE_TYPE_AWE32
-#define SAMPLE_TYPE_AWE32 0x20
-#endif
-
-#define _LINUX_PATCHKEY_H_INDIRECT
-#include <linux/patchkey.h>
-#undef _LINUX_PATCHKEY_H_INDIRECT
-
-/*----------------------------------------------------------------
- * patch information record
- *----------------------------------------------------------------*/
-
-/* patch interface header: 16 bytes */
-typedef struct awe_patch_info {
- short key; /* use AWE_PATCH here */
-#define AWE_PATCH _PATCHKEY(0x07)
-
- short device_no; /* synthesizer number */
- unsigned short sf_id; /* file id (should be zero) */
- short optarg; /* optional argument */
- int len; /* data length (without this header) */
-
- short type; /* patch operation type */
-#define AWE_LOAD_INFO 0 /* awe_voice_rec */
-#define AWE_LOAD_DATA 1 /* awe_sample_info */
-#define AWE_OPEN_PATCH 2 /* awe_open_parm */
-#define AWE_CLOSE_PATCH 3 /* none */
-#define AWE_UNLOAD_PATCH 4 /* none */
-#define AWE_REPLACE_DATA 5 /* awe_sample_info (optarg=#channels)*/
-#define AWE_MAP_PRESET 6 /* awe_voice_map */
-/*#define AWE_PROBE_INFO 7*/ /* awe_voice_map (pat only) */
-#define AWE_PROBE_DATA 8 /* optarg=sample */
-#define AWE_REMOVE_INFO 9 /* optarg=(bank<<8)|instr */
-#define AWE_LOAD_CHORUS_FX 0x10 /* awe_chorus_fx_rec (optarg=mode) */
-#define AWE_LOAD_REVERB_FX 0x11 /* awe_reverb_fx_rec (optarg=mode) */
-
- short reserved; /* word alignment data */
-
- /* the actual patch data begins after this */
-#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
- char data[0];
-#endif
-} awe_patch_info;
-
-/*#define AWE_PATCH_INFO_SIZE 16*/
-#define AWE_PATCH_INFO_SIZE sizeof(awe_patch_info)
-
-
-/*----------------------------------------------------------------
- * open patch
- *----------------------------------------------------------------*/
-
-#define AWE_PATCH_NAME_LEN 32
-
-typedef struct _awe_open_parm {
- unsigned short type; /* sample type */
-#define AWE_PAT_TYPE_MISC 0
-#define AWE_PAT_TYPE_GM 1
-#define AWE_PAT_TYPE_GS 2
-#define AWE_PAT_TYPE_MT32 3
-#define AWE_PAT_TYPE_XG 4
-#define AWE_PAT_TYPE_SFX 5
-#define AWE_PAT_TYPE_GUS 6
-#define AWE_PAT_TYPE_MAP 7
-
-#define AWE_PAT_LOCKED 0x100 /* lock the samples */
-#define AWE_PAT_SHARED 0x200 /* sample is shared */
-
- short reserved;
- char name[AWE_PATCH_NAME_LEN];
-} awe_open_parm;
-
-/*#define AWE_OPEN_PARM_SIZE 28*/
-#define AWE_OPEN_PARM_SIZE sizeof(awe_open_parm)
-
-
-/*----------------------------------------------------------------
- * raw voice information record
- *----------------------------------------------------------------*/
-
-/* wave table envelope & effect parameters to control EMU8000 */
-typedef struct _awe_voice_parm {
- unsigned short moddelay; /* modulation delay (0x8000) */
- unsigned short modatkhld; /* modulation attack & hold time (0x7f7f) */
- unsigned short moddcysus; /* modulation decay & sustain (0x7f7f) */
- unsigned short modrelease; /* modulation release time (0x807f) */
- short modkeyhold, modkeydecay; /* envelope change per key (not used) */
- unsigned short voldelay; /* volume delay (0x8000) */
- unsigned short volatkhld; /* volume attack & hold time (0x7f7f) */
- unsigned short voldcysus; /* volume decay & sustain (0x7f7f) */
- unsigned short volrelease; /* volume release time (0x807f) */
- short volkeyhold, volkeydecay; /* envelope change per key (not used) */
- unsigned short lfo1delay; /* LFO1 delay (0x8000) */
- unsigned short lfo2delay; /* LFO2 delay (0x8000) */
- unsigned short pefe; /* modulation pitch & cutoff (0x0000) */
- unsigned short fmmod; /* LFO1 pitch & cutoff (0x0000) */
- unsigned short tremfrq; /* LFO1 volume & freq (0x0000) */
- unsigned short fm2frq2; /* LFO2 pitch & freq (0x0000) */
- unsigned char cutoff; /* initial cutoff (0xff) */
- unsigned char filterQ; /* initial filter Q [0-15] (0x0) */
- unsigned char chorus; /* chorus send (0x00) */
- unsigned char reverb; /* reverb send (0x00) */
- unsigned short reserved[4]; /* not used */
-} awe_voice_parm;
-
-typedef struct _awe_voice_parm_block {
- unsigned short moddelay; /* modulation delay (0x8000) */
- unsigned char modatk, modhld;
- unsigned char moddcy, modsus;
- unsigned char modrel, moddummy;
- short modkeyhold, modkeydecay; /* envelope change per key (not used) */
- unsigned short voldelay; /* volume delay (0x8000) */
- unsigned char volatk, volhld;
- unsigned char voldcy, volsus;
- unsigned char volrel, voldummy;
- short volkeyhold, volkeydecay; /* envelope change per key (not used) */
- unsigned short lfo1delay; /* LFO1 delay (0x8000) */
- unsigned short lfo2delay; /* LFO2 delay (0x8000) */
- unsigned char env1fc, env1pit;
- unsigned char lfo1fc, lfo1pit;
- unsigned char lfo1freq, lfo1vol;
- unsigned char lfo2freq, lfo2pit;
- unsigned char cutoff; /* initial cutoff (0xff) */
- unsigned char filterQ; /* initial filter Q [0-15] (0x0) */
- unsigned char chorus; /* chorus send (0x00) */
- unsigned char reverb; /* reverb send (0x00) */
- unsigned short reserved[4]; /* not used */
-} awe_voice_parm_block;
-
-#define AWE_VOICE_PARM_SIZE 48
-
-
-/* wave table parameters: 92 bytes */
-typedef struct _awe_voice_info {
- unsigned short sf_id; /* file id (should be zero) */
- unsigned short sample; /* sample id */
- int start, end; /* sample offset correction */
- int loopstart, loopend; /* loop offset correction */
- short rate_offset; /* sample rate pitch offset */
- unsigned short mode; /* sample mode */
-#define AWE_MODE_ROMSOUND 0x8000
-#define AWE_MODE_STEREO 1
-#define AWE_MODE_LOOPING 2
-#define AWE_MODE_NORELEASE 4 /* obsolete */
-#define AWE_MODE_INIT_PARM 8
-
- short root; /* midi root key */
- short tune; /* pitch tuning (in cents) */
- signed char low, high; /* key note range */
- signed char vellow, velhigh; /* velocity range */
- signed char fixkey, fixvel; /* fixed key, velocity */
- signed char pan, fixpan; /* panning, fixed panning */
- short exclusiveClass; /* exclusive class (0 = none) */
- unsigned char amplitude; /* sample volume (127 max) */
- unsigned char attenuation; /* attenuation (0.375dB) */
- short scaleTuning; /* pitch scale tuning(%), normally 100 */
- awe_voice_parm parm; /* voice envelope parameters */
- short index; /* internal index (set by driver) */
-} awe_voice_info;
-
-/*#define AWE_VOICE_INFO_SIZE 92*/
-#define AWE_VOICE_INFO_SIZE sizeof(awe_voice_info)
-
-/*----------------------------------------------------------------*/
-
-/* The info entry of awe_voice_rec is changed from 0 to 1
- * for some compilers refusing zero size array.
- * Due to this change, sizeof(awe_voice_rec) becomes different
- * from older versions.
- * Use AWE_VOICE_REC_SIZE instead.
- */
-
-/* instrument info header: 4 bytes */
-typedef struct _awe_voice_rec_hdr {
- unsigned char bank; /* midi bank number */
- unsigned char instr; /* midi preset number */
- char nvoices; /* number of voices */
- char write_mode; /* write mode; normally 0 */
-#define AWE_WR_APPEND 0 /* append anyway */
-#define AWE_WR_EXCLUSIVE 1 /* skip if already exists */
-#define AWE_WR_REPLACE 2 /* replace if already exists */
-} awe_voice_rec_hdr;
-
-/*#define AWE_VOICE_REC_SIZE 4*/
-#define AWE_VOICE_REC_SIZE sizeof(awe_voice_rec_hdr)
-
-/* the standard patch structure for one sample */
-typedef struct _awe_voice_rec_patch {
- awe_patch_info patch;
- awe_voice_rec_hdr hdr;
- awe_voice_info info;
-} awe_voice_rec_patch;
-
-
-/* obsolete data type */
-#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
-#define AWE_INFOARRAY_SIZE 0
-#else
-#define AWE_INFOARRAY_SIZE 1
-#endif
-
-typedef struct _awe_voice_rec {
- unsigned char bank; /* midi bank number */
- unsigned char instr; /* midi preset number */
- short nvoices; /* number of voices */
- /* voice information follows here */
- awe_voice_info info[AWE_INFOARRAY_SIZE];
-} awe_voice_rec;
-
-
-/*----------------------------------------------------------------
- * sample wave information
- *----------------------------------------------------------------*/
-
-/* wave table sample header: 32 bytes */
-typedef struct awe_sample_info {
- unsigned short sf_id; /* file id (should be zero) */
- unsigned short sample; /* sample id */
- int start, end; /* start & end offset */
- int loopstart, loopend; /* loop start & end offset */
- int size; /* size (0 = ROM) */
- short checksum_flag; /* use check sum = 1 */
- unsigned short mode_flags; /* mode flags */
-#define AWE_SAMPLE_8BITS 1 /* wave data is 8bits */
-#define AWE_SAMPLE_UNSIGNED 2 /* wave data is unsigned */
-#define AWE_SAMPLE_NO_BLANK 4 /* no blank loop is attached */
-#define AWE_SAMPLE_SINGLESHOT 8 /* single-shot w/o loop */
-#define AWE_SAMPLE_BIDIR_LOOP 16 /* bidirectional looping */
-#define AWE_SAMPLE_STEREO_LEFT 32 /* stereo left sound */
-#define AWE_SAMPLE_STEREO_RIGHT 64 /* stereo right sound */
-#define AWE_SAMPLE_REVERSE_LOOP 128 /* reverse looping */
- unsigned int checksum; /* check sum */
-#if defined(AWE_COMPAT_030) && AWE_COMPAT_030
- unsigned short data[0]; /* sample data follows here */
-#endif
-} awe_sample_info;
-
-/*#define AWE_SAMPLE_INFO_SIZE 32*/
-#define AWE_SAMPLE_INFO_SIZE sizeof(awe_sample_info)
-
-
-/*----------------------------------------------------------------
- * voice preset mapping
- *----------------------------------------------------------------*/
-
-typedef struct awe_voice_map {
- int map_bank, map_instr, map_key; /* key = -1 means all keys */
- int src_bank, src_instr, src_key;
-} awe_voice_map;
-
-#define AWE_VOICE_MAP_SIZE sizeof(awe_voice_map)
-
-
-/*----------------------------------------------------------------
- * awe hardware controls
- *----------------------------------------------------------------*/
-
-#define _AWE_DEBUG_MODE 0x00
-#define _AWE_REVERB_MODE 0x01
-#define _AWE_CHORUS_MODE 0x02
-#define _AWE_REMOVE_LAST_SAMPLES 0x03
-#define _AWE_INITIALIZE_CHIP 0x04
-#define _AWE_SEND_EFFECT 0x05
-#define _AWE_TERMINATE_CHANNEL 0x06
-#define _AWE_TERMINATE_ALL 0x07
-#define _AWE_INITIAL_VOLUME 0x08
-#define _AWE_INITIAL_ATTEN _AWE_INITIAL_VOLUME
-#define _AWE_RESET_CHANNEL 0x09
-#define _AWE_CHANNEL_MODE 0x0a
-#define _AWE_DRUM_CHANNELS 0x0b
-#define _AWE_MISC_MODE 0x0c
-#define _AWE_RELEASE_ALL 0x0d
-#define _AWE_NOTEOFF_ALL 0x0e
-#define _AWE_CHN_PRESSURE 0x0f
-/*#define _AWE_GET_CURRENT_MODE 0x10*/
-#define _AWE_EQUALIZER 0x11
-/*#define _AWE_GET_MISC_MODE 0x12*/
-/*#define _AWE_GET_FONTINFO 0x13*/
-
-#define _AWE_MODE_FLAG 0x80
-#define _AWE_COOKED_FLAG 0x40 /* not supported */
-#define _AWE_MODE_VALUE_MASK 0x3F
-
-/*----------------------------------------------------------------*/
-
-#define _AWE_SET_CMD(p,dev,voice,cmd,p1,p2) \
-{((char*)(p))[0] = SEQ_PRIVATE;\
- ((char*)(p))[1] = dev;\
- ((char*)(p))[2] = _AWE_MODE_FLAG|(cmd);\
- ((char*)(p))[3] = voice;\
- ((unsigned short*)(p))[2] = p1;\
- ((unsigned short*)(p))[3] = p2;}
-
-/* buffered access */
-#define _AWE_CMD(dev, voice, cmd, p1, p2) \
-{_SEQ_NEEDBUF(8);\
- _AWE_SET_CMD(_seqbuf + _seqbufptr, dev, voice, cmd, p1, p2);\
- _SEQ_ADVBUF(8);}
-
-/* direct access */
-#define _AWE_CMD_NOW(seqfd,dev,voice,cmd,p1,p2) \
-{struct seq_event_rec tmp;\
- _AWE_SET_CMD(&tmp, dev, voice, cmd, p1, p2);\
- ioctl(seqfd, SNDCTL_SEQ_OUTOFBAND, &tmp);}
-
-/*----------------------------------------------------------------*/
-
-/* set debugging mode */
-#define AWE_DEBUG_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_DEBUG_MODE, p1, 0)
-/* set reverb mode; from 0 to 7 */
-#define AWE_REVERB_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_REVERB_MODE, p1, 0)
-/* set chorus mode; from 0 to 7 */
-#define AWE_CHORUS_MODE(dev,p1) _AWE_CMD(dev, 0, _AWE_CHORUS_MODE, p1, 0)
-
-/* reset channel */
-#define AWE_RESET_CHANNEL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 0, 0)
-#define AWE_RESET_CONTROL(dev,ch) _AWE_CMD(dev, ch, _AWE_RESET_CHANNEL, 1, 0)
-
-/* send an effect to all layers */
-#define AWE_SEND_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,type,value)
-#define AWE_ADD_EFFECT(dev,voice,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x80),value)
-#define AWE_UNSET_EFFECT(dev,voice,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((type)|0x40),0)
-/* send an effect to a layer */
-#define AWE_SEND_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)),value)
-#define AWE_ADD_LAYER_EFFECT(dev,voice,layer,type,value) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x80),value)
-#define AWE_UNSET_LAYER_EFFECT(dev,voice,layer,type) _AWE_CMD(dev,voice,_AWE_SEND_EFFECT,((layer+1)<<8|(type)|0x40),0)
-
-/* terminate sound on the channel/voice */
-#define AWE_TERMINATE_CHANNEL(dev,voice) _AWE_CMD(dev,voice,_AWE_TERMINATE_CHANNEL,0,0)
-/* terminate all sounds */
-#define AWE_TERMINATE_ALL(dev) _AWE_CMD(dev, 0, _AWE_TERMINATE_ALL, 0, 0)
-/* release all sounds (w/o sustain effect) */
-#define AWE_RELEASE_ALL(dev) _AWE_CMD(dev, 0, _AWE_RELEASE_ALL, 0, 0)
-/* note off all sounds (w sustain effect) */
-#define AWE_NOTEOFF_ALL(dev) _AWE_CMD(dev, 0, _AWE_NOTEOFF_ALL, 0, 0)
-
-/* set initial attenuation */
-#define AWE_INITIAL_VOLUME(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 0)
-#define AWE_INITIAL_ATTEN AWE_INITIAL_VOLUME
-/* relative attenuation */
-#define AWE_SET_ATTEN(dev,atten) _AWE_CMD(dev, 0, _AWE_INITIAL_VOLUME, atten, 1)
-
-/* set channel playing mode; mode=0/1/2 */
-#define AWE_SET_CHANNEL_MODE(dev,mode) _AWE_CMD(dev, 0, _AWE_CHANNEL_MODE, mode, 0)
-#define AWE_PLAY_INDIRECT 0 /* indirect voice mode (default) */
-#define AWE_PLAY_MULTI 1 /* multi note voice mode */
-#define AWE_PLAY_DIRECT 2 /* direct single voice mode */
-#define AWE_PLAY_MULTI2 3 /* sequencer2 mode; used internally */
-
-/* set drum channel mask; channels is 32bit long value */
-#define AWE_DRUM_CHANNELS(dev,channels) _AWE_CMD(dev, 0, _AWE_DRUM_CHANNELS, ((channels) & 0xffff), ((channels) >> 16))
-
-/* set bass and treble control; values are from 0 to 11 */
-#define AWE_EQUALIZER(dev,bass,treble) _AWE_CMD(dev, 0, _AWE_EQUALIZER, bass, treble)
-
-/* remove last loaded samples */
-#define AWE_REMOVE_LAST_SAMPLES(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_REMOVE_LAST_SAMPLES, 0, 0)
-/* initialize emu8000 chip */
-#define AWE_INITIALIZE_CHIP(seqfd,dev) _AWE_CMD_NOW(seqfd, dev, 0, _AWE_INITIALIZE_CHIP, 0, 0)
-
-/* set miscellaneous modes; meta command */
-#define AWE_MISC_MODE(dev,mode,value) _AWE_CMD(dev, 0, _AWE_MISC_MODE, mode, value)
-/* exclusive sound off; 1=off */
-#define AWE_EXCLUSIVE_SOUND(dev,mode) AWE_MISC_MODE(dev,AWE_MD_EXCLUSIVE_SOUND,mode)
-/* default GUS bank number */
-#define AWE_SET_GUS_BANK(dev,bank) AWE_MISC_MODE(dev,AWE_MD_GUS_BANK,bank)
-/* change panning position in realtime; 0=don't 1=do */
-#define AWE_REALTIME_PAN(dev,mode) AWE_MISC_MODE(dev,AWE_MD_REALTIME_PAN,mode)
-
-/* extended pressure controls; not portable with other sound drivers */
-#define AWE_KEY_PRESSURE(dev,ch,note,vel) SEQ_START_NOTE(dev,ch,(note)+128,vel)
-#define AWE_CHN_PRESSURE(dev,ch,vel) _AWE_CMD(dev,ch,_AWE_CHN_PRESSURE,vel,0)
-
-/*----------------------------------------------------------------*/
-
-/* reverb mode parameters */
-#define AWE_REVERB_ROOM1 0
-#define AWE_REVERB_ROOM2 1
-#define AWE_REVERB_ROOM3 2
-#define AWE_REVERB_HALL1 3
-#define AWE_REVERB_HALL2 4
-#define AWE_REVERB_PLATE 5
-#define AWE_REVERB_DELAY 6
-#define AWE_REVERB_PANNINGDELAY 7
-#define AWE_REVERB_PREDEFINED 8
-/* user can define reverb modes up to 32 */
-#define AWE_REVERB_NUMBERS 32
-
-typedef struct awe_reverb_fx_rec {
- unsigned short parms[28];
-} awe_reverb_fx_rec;
-
-/*----------------------------------------------------------------*/
-
-/* chorus mode parameters */
-#define AWE_CHORUS_1 0
-#define AWE_CHORUS_2 1
-#define AWE_CHORUS_3 2
-#define AWE_CHORUS_4 3
-#define AWE_CHORUS_FEEDBACK 4
-#define AWE_CHORUS_FLANGER 5
-#define AWE_CHORUS_SHORTDELAY 6
-#define AWE_CHORUS_SHORTDELAY2 7
-#define AWE_CHORUS_PREDEFINED 8
-/* user can define chorus modes up to 32 */
-#define AWE_CHORUS_NUMBERS 32
-
-typedef struct awe_chorus_fx_rec {
- unsigned short feedback; /* feedback level (0xE600-0xE6FF) */
- unsigned short delay_offset; /* delay (0-0x0DA3) [1/44100 sec] */
- unsigned short lfo_depth; /* LFO depth (0xBC00-0xBCFF) */
- unsigned int delay; /* right delay (0-0xFFFFFFFF) [1/256/44100 sec] */
- unsigned int lfo_freq; /* LFO freq LFO freq (0-0xFFFFFFFF) */
-} awe_chorus_fx_rec;
-
-/*----------------------------------------------------------------*/
-
-/* misc mode types */
-enum {
-/* 0*/ AWE_MD_EXCLUSIVE_OFF, /* obsolete */
-/* 1*/ AWE_MD_EXCLUSIVE_ON, /* obsolete */
-/* 2*/ AWE_MD_VERSION, /* read only */
-/* 3*/ AWE_MD_EXCLUSIVE_SOUND, /* 0/1: exclusive note on (default=1) */
-/* 4*/ AWE_MD_REALTIME_PAN, /* 0/1: do realtime pan change (default=1) */
-/* 5*/ AWE_MD_GUS_BANK, /* bank number for GUS patches (default=0) */
-/* 6*/ AWE_MD_KEEP_EFFECT, /* 0/1: keep effect values, (default=0) */
-/* 7*/ AWE_MD_ZERO_ATTEN, /* attenuation of max volume (default=32) */
-/* 8*/ AWE_MD_CHN_PRIOR, /* 0/1: set MIDI channel priority mode (default=1) */
-/* 9*/ AWE_MD_MOD_SENSE, /* integer: modwheel sensitivity (def=18) */
-/*10*/ AWE_MD_DEF_PRESET, /* integer: default preset number (def=0) */
-/*11*/ AWE_MD_DEF_BANK, /* integer: default bank number (def=0) */
-/*12*/ AWE_MD_DEF_DRUM, /* integer: default drumset number (def=0) */
-/*13*/ AWE_MD_TOGGLE_DRUM_BANK, /* 0/1: toggle drum flag with bank# (def=0) */
-/*14*/ AWE_MD_NEW_VOLUME_CALC, /* 0/1: volume calculation mode (def=1) */
-/*15*/ AWE_MD_CHORUS_MODE, /* integer: chorus mode (def=2) */
-/*16*/ AWE_MD_REVERB_MODE, /* integer: chorus mode (def=4) */
-/*17*/ AWE_MD_BASS_LEVEL, /* integer: bass level (def=5) */
-/*18*/ AWE_MD_TREBLE_LEVEL, /* integer: treble level (def=9) */
-/*19*/ AWE_MD_DEBUG_MODE, /* integer: debug level (def=0) */
-/*20*/ AWE_MD_PAN_EXCHANGE, /* 0/1: exchange panning direction (def=0) */
- AWE_MD_END,
-};
-
-/*----------------------------------------------------------------*/
-
-/* effect parameters */
-enum {
-
-/* modulation envelope parameters */
-/* 0*/ AWE_FX_ENV1_DELAY, /* WORD: ENVVAL */
-/* 1*/ AWE_FX_ENV1_ATTACK, /* BYTE: up ATKHLD */
-/* 2*/ AWE_FX_ENV1_HOLD, /* BYTE: lw ATKHLD */
-/* 3*/ AWE_FX_ENV1_DECAY, /* BYTE: lw DCYSUS */
-/* 4*/ AWE_FX_ENV1_RELEASE, /* BYTE: lw DCYSUS */
-/* 5*/ AWE_FX_ENV1_SUSTAIN, /* BYTE: up DCYSUS */
-/* 6*/ AWE_FX_ENV1_PITCH, /* BYTE: up PEFE */
-/* 7*/ AWE_FX_ENV1_CUTOFF, /* BYTE: lw PEFE */
-
-/* volume envelope parameters */
-/* 8*/ AWE_FX_ENV2_DELAY, /* WORD: ENVVOL */
-/* 9*/ AWE_FX_ENV2_ATTACK, /* BYTE: up ATKHLDV */
-/*10*/ AWE_FX_ENV2_HOLD, /* BYTE: lw ATKHLDV */
-/*11*/ AWE_FX_ENV2_DECAY, /* BYTE: lw DCYSUSV */
-/*12*/ AWE_FX_ENV2_RELEASE, /* BYTE: lw DCYSUSV */
-/*13*/ AWE_FX_ENV2_SUSTAIN, /* BYTE: up DCYSUSV */
-
-/* LFO1 (tremolo & vibrato) parameters */
-/*14*/ AWE_FX_LFO1_DELAY, /* WORD: LFO1VAL */
-/*15*/ AWE_FX_LFO1_FREQ, /* BYTE: lo TREMFRQ */
-/*16*/ AWE_FX_LFO1_VOLUME, /* BYTE: up TREMFRQ */
-/*17*/ AWE_FX_LFO1_PITCH, /* BYTE: up FMMOD */
-/*18*/ AWE_FX_LFO1_CUTOFF, /* BYTE: lo FMMOD */
-
-/* LFO2 (vibrato) parameters */
-/*19*/ AWE_FX_LFO2_DELAY, /* WORD: LFO2VAL */
-/*20*/ AWE_FX_LFO2_FREQ, /* BYTE: lo FM2FRQ2 */
-/*21*/ AWE_FX_LFO2_PITCH, /* BYTE: up FM2FRQ2 */
-
-/* Other overall effect parameters */
-/*22*/ AWE_FX_INIT_PITCH, /* SHORT: pitch offset */
-/*23*/ AWE_FX_CHORUS, /* BYTE: chorus effects send (0-255) */
-/*24*/ AWE_FX_REVERB, /* BYTE: reverb effects send (0-255) */
-/*25*/ AWE_FX_CUTOFF, /* BYTE: up IFATN */
-/*26*/ AWE_FX_FILTERQ, /* BYTE: up CCCA */
-
-/* Sample / loop offset changes */
-/*27*/ AWE_FX_SAMPLE_START, /* SHORT: offset */
-/*28*/ AWE_FX_LOOP_START, /* SHORT: offset */
-/*29*/ AWE_FX_LOOP_END, /* SHORT: offset */
-/*30*/ AWE_FX_COARSE_SAMPLE_START, /* SHORT: upper word offset */
-/*31*/ AWE_FX_COARSE_LOOP_START, /* SHORT: upper word offset */
-/*32*/ AWE_FX_COARSE_LOOP_END, /* SHORT: upper word offset */
-/*33*/ AWE_FX_ATTEN, /* BYTE: lo IFATN */
-
- AWE_FX_END,
-};
-
-#endif /* AWE_VOICE_H */
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 08daf3272c0..4d85262b4fa 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -276,7 +276,7 @@ extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool,
extern mempool_t *bio_split_pool;
extern void bio_pair_release(struct bio_pair *dbio);
-extern struct bio_set *bioset_create(int, int, int);
+extern struct bio_set *bioset_create(int, int);
extern void bioset_free(struct bio_set *);
extern struct bio *bio_alloc(gfp_t, int);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 83dcd8c0e97..db5b00a792f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -116,6 +116,7 @@ struct io_context {
struct as_io_context *aic;
struct rb_root cic_root;
+ void *ioc_data;
};
void put_io_context(struct io_context *ioc);
@@ -853,7 +854,7 @@ static inline void put_dev_sector(Sector p)
struct work_struct;
int kblockd_schedule_work(struct work_struct *work);
-void kblockd_flush(void);
+void kblockd_flush_work(struct work_struct *work);
#define MODULE_ALIAS_BLOCKDEV(major,minor) \
MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 81c07cd1864..0365ec9fc0c 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -122,9 +122,9 @@ extern void *alloc_large_system_hash(const char *tablename,
#define HASH_EARLY 0x00000001 /* Allocating during early boot? */
/* Only NUMA needs hash distribution.
- * IA64 is known to have sufficient vmalloc space.
+ * IA64 and x86_64 have sufficient vmalloc space.
*/
-#if defined(CONFIG_NUMA) && defined(CONFIG_IA64)
+#if defined(CONFIG_NUMA) && (defined(CONFIG_IA64) || defined(CONFIG_X86_64))
#define HASHDIST_DEFAULT 1
#else
#define HASHDIST_DEFAULT 0
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index dd27b1c7227..5c6e12853a9 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -165,7 +165,7 @@ int sync_mapping_buffers(struct address_space *mapping);
void unmap_underlying_metadata(struct block_device *bdev, sector_t block);
void mark_buffer_async_write(struct buffer_head *bh);
-void invalidate_bdev(struct block_device *, int);
+void invalidate_bdev(struct block_device *);
int sync_blockdev(struct block_device *bdev);
void __wait_on_buffer(struct buffer_head *);
wait_queue_head_t *bh_waitq_head(struct buffer_head *bh);
@@ -182,6 +182,7 @@ void __brelse(struct buffer_head *);
void __bforget(struct buffer_head *);
void __breadahead(struct block_device *, sector_t block, unsigned int size);
struct buffer_head *__bread(struct block_device *, sector_t block, unsigned size);
+void invalidate_bh_lrus(void);
struct buffer_head *alloc_buffer_head(gfp_t gfp_flags);
void free_buffer_head(struct buffer_head * bh);
void FASTCALL(unlock_buffer(struct buffer_head *bh));
@@ -319,7 +320,7 @@ static inline int inode_has_buffers(struct inode *inode) { return 0; }
static inline void invalidate_inode_buffers(struct inode *inode) {}
static inline int remove_inode_buffers(struct inode *inode) { return 1; }
static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; }
-static inline void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers) {}
+static inline void invalidate_bdev(struct block_device *bdev) {}
#endif /* CONFIG_BLOCK */
diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h
index e86e4a93837..3dc715b0250 100644
--- a/include/linux/byteorder/generic.h
+++ b/include/linux/byteorder/generic.h
@@ -124,19 +124,8 @@
#define be32_to_cpus __be32_to_cpus
#define cpu_to_be16s __cpu_to_be16s
#define be16_to_cpus __be16_to_cpus
-#endif
-
-#if defined(__KERNEL__)
/*
- * Handle ntohl and suches. These have various compatibility
- * issues - like we want to give the prototype even though we
- * also have a macro for them in case some strange program
- * wants to take the address of the thing or something..
- *
- * Note that these used to return a "long" in libc5, even though
- * long is often 64-bit these days.. Thus the casts.
- *
* They have to be macros in order to do the constant folding
* correctly - if the argument passed into a inline function
* it is no longer constant according to gcc..
@@ -147,17 +136,6 @@
#undef htonl
#undef htons
-/*
- * Do the prototypes. Somebody might want to take the
- * address or some such sick thing..
- */
-extern __u32 ntohl(__be32);
-extern __be32 htonl(__u32);
-extern __u16 ntohs(__be16);
-extern __be16 htons(__u16);
-
-#if defined(__GNUC__) && defined(__OPTIMIZE__)
-
#define ___htonl(x) __cpu_to_be32(x)
#define ___htons(x) __cpu_to_be16(x)
#define ___ntohl(x) __be32_to_cpu(x)
@@ -168,9 +146,6 @@ extern __be16 htons(__u16);
#define htons(x) ___htons(x)
#define ntohs(x) ___ntohs(x)
-#endif /* OPTIMIZE */
-
#endif /* KERNEL */
-
#endif /* _LINUX_BYTEORDER_GENERIC_H */
diff --git a/include/linux/byteorder/swab.h b/include/linux/byteorder/swab.h
index 25f7f32883e..142134ff164 100644
--- a/include/linux/byteorder/swab.h
+++ b/include/linux/byteorder/swab.h
@@ -10,6 +10,10 @@
* separated swab functions from cpu_to_XX,
* to clean up support for bizarre-endian architectures.
*
+ * Trent Piepho <xyzzy@speakeasy.org> 2007114
+ * make constant-folding work, provide C versions that
+ * gcc can optimize better, explain different versions
+ *
* See asm-i386/byteorder.h and suches for examples of how to provide
* architecture-dependent optimized versions
*
@@ -17,40 +21,66 @@
#include <linux/compiler.h>
+/* Functions/macros defined, there are a lot:
+ *
+ * ___swabXX
+ * Generic C versions of the swab functions.
+ *
+ * ___constant_swabXX
+ * C versions that gcc can fold into a compile-time constant when
+ * the argument is a compile-time constant.
+ *
+ * __arch__swabXX[sp]?
+ * Architecture optimized versions of all the swab functions
+ * (including the s and p versions). These can be defined in
+ * asm-arch/byteorder.h. Any which are not, are defined here.
+ * __arch__swabXXs() is defined in terms of __arch__swabXXp(), which
+ * is defined in terms of __arch__swabXX(), which is in turn defined
+ * in terms of ___swabXX(x).
+ * These must be macros. They may be unsafe for arguments with
+ * side-effects.
+ *
+ * __fswabXX
+ * Inline function versions of the __arch__ macros. These _are_ safe
+ * if the arguments have side-effects. Note there are no s and p
+ * versions of these.
+ *
+ * __swabXX[sb]
+ * There are the ones you should actually use. The __swabXX versions
+ * will be a constant given a constant argument and use the arch
+ * specific code (if any) for non-constant arguments. The s and p
+ * versions always use the arch specific code (constant folding
+ * doesn't apply). They are safe to use with arguments with
+ * side-effects.
+ *
+ * swabXX[sb]
+ * Nicknames for __swabXX[sb] to use in the kernel.
+ */
+
/* casts are necessary for constants, because we never know how for sure
* how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way.
*/
-#define ___swab16(x) \
-({ \
- __u16 __x = (x); \
- ((__u16)( \
- (((__u16)(__x) & (__u16)0x00ffU) << 8) | \
- (((__u16)(__x) & (__u16)0xff00U) >> 8) )); \
-})
-#define ___swab32(x) \
-({ \
- __u32 __x = (x); \
- ((__u32)( \
- (((__u32)(__x) & (__u32)0x000000ffUL) << 24) | \
- (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) | \
- (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) | \
- (((__u32)(__x) & (__u32)0xff000000UL) >> 24) )); \
-})
-
-#define ___swab64(x) \
-({ \
- __u64 __x = (x); \
- ((__u64)( \
- (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
- (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
- (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
- (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \
- (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \
- (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
- (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
- (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56) )); \
-})
+static __inline__ __attribute_const__ __u16 ___swab16(__u16 x)
+{
+ return x<<8 | x>>8;
+}
+static __inline__ __attribute_const__ __u32 ___swab32(__u32 x)
+{
+ return x<<24 | x>>24 |
+ (x & (__u32)0x0000ff00UL)<<8 |
+ (x & (__u32)0x00ff0000UL)>>8;
+}
+static __inline__ __attribute_const__ __u64 ___swab64(__u64 x)
+{
+ return x<<56 | x>>56 |
+ (x & (__u64)0x000000000000ff00ULL)<<40 |
+ (x & (__u64)0x0000000000ff0000ULL)<<24 |
+ (x & (__u64)0x00000000ff000000ULL)<< 8 |
+ (x & (__u64)0x000000ff00000000ULL)>> 8 |
+ (x & (__u64)0x0000ff0000000000ULL)>>24 |
+ (x & (__u64)0x00ff000000000000ULL)>>40;
+}
#define ___constant_swab16(x) \
((__u16)( \
@@ -77,13 +107,13 @@
* provide defaults when no architecture-specific optimization is detected
*/
#ifndef __arch__swab16
-# define __arch__swab16(x) ({ __u16 __tmp = (x) ; ___swab16(__tmp); })
+# define __arch__swab16(x) ___swab16(x)
#endif
#ifndef __arch__swab32
-# define __arch__swab32(x) ({ __u32 __tmp = (x) ; ___swab32(__tmp); })
+# define __arch__swab32(x) ___swab32(x)
#endif
#ifndef __arch__swab64
-# define __arch__swab64(x) ({ __u64 __tmp = (x) ; ___swab64(__tmp); })
+# define __arch__swab64(x) ___swab64(x)
#endif
#ifndef __arch__swab16p
@@ -97,13 +127,13 @@
#endif
#ifndef __arch__swab16s
-# define __arch__swab16s(x) do { *(x) = __arch__swab16p((x)); } while (0)
+# define __arch__swab16s(x) ((void)(*(x) = __arch__swab16p(x)))
#endif
#ifndef __arch__swab32s
-# define __arch__swab32s(x) do { *(x) = __arch__swab32p((x)); } while (0)
+# define __arch__swab32s(x) ((void)(*(x) = __arch__swab32p(x)))
#endif
#ifndef __arch__swab64s
-# define __arch__swab64s(x) do { *(x) = __arch__swab64p((x)); } while (0)
+# define __arch__swab64s(x) ((void)(*(x) = __arch__swab64p(x)))
#endif
@@ -113,15 +143,15 @@
#if defined(__GNUC__) && defined(__OPTIMIZE__)
# define __swab16(x) \
(__builtin_constant_p((__u16)(x)) ? \
- ___swab16((x)) : \
+ ___constant_swab16((x)) : \
__fswab16((x)))
# define __swab32(x) \
(__builtin_constant_p((__u32)(x)) ? \
- ___swab32((x)) : \
+ ___constant_swab32((x)) : \
__fswab32((x)))
# define __swab64(x) \
(__builtin_constant_p((__u64)(x)) ? \
- ___swab64((x)) : \
+ ___constant_swab64((x)) : \
__fswab64((x)))
#else
# define __swab16(x) __fswab16(x)
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 4ea7e7bcfaf..8486e78f733 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -54,17 +54,17 @@ enum clock_event_nofitiers {
/**
* struct clock_event_device - clock event device descriptor
* @name: ptr to clock event name
- * @hints: usage hints
+ * @features: features
* @max_delta_ns: maximum delta value in ns
* @min_delta_ns: minimum delta value in ns
* @mult: nanosecond to cycles multiplier
* @shift: nanoseconds to cycles divisor (power of two)
* @rating: variable to rate clock event devices
- * @irq: irq number (only for non cpu local devices)
- * @cpumask: cpumask to indicate for which cpus this device works
- * @set_next_event: set next event
+ * @irq: IRQ number (only for non CPU local devices)
+ * @cpumask: cpumask to indicate for which CPUs this device works
+ * @set_next_event: set next event function
* @set_mode: set mode function
- * @evthandler: Assigned by the framework to be called by the low
+ * @event_handler: Assigned by the framework to be called by the low
* level handler of the event source
* @broadcast: function to broadcast events
* @list: list head for the management code
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index daa4940cc0f..bf297b03a4e 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -12,6 +12,7 @@
#include <linux/timex.h>
#include <linux/time.h>
#include <linux/list.h>
+#include <linux/cache.h>
#include <linux/timer.h>
#include <asm/div64.h>
#include <asm/io.h>
@@ -48,10 +49,14 @@ struct clocksource;
* @shift: cycle to nanosecond divisor (power of two)
* @flags: flags describing special properties
* @vread: vsyscall based read
+ * @resume: resume function for the clocksource, if necessary
* @cycle_interval: Used internally by timekeeping core, please ignore.
* @xtime_interval: Used internally by timekeeping core, please ignore.
*/
struct clocksource {
+ /*
+ * First part of structure is read mostly
+ */
char *name;
struct list_head list;
int rating;
@@ -61,10 +66,18 @@ struct clocksource {
u32 shift;
unsigned long flags;
cycle_t (*vread)(void);
+ void (*resume)(void);
/* timekeeping specific data, ignore */
- cycle_t cycle_last, cycle_interval;
- u64 xtime_nsec, xtime_interval;
+ cycle_t cycle_interval;
+ u64 xtime_interval;
+ /*
+ * Second part is written at each timer interrupt
+ * Keep it in a different cache line to dirty no
+ * more than one cache line.
+ */
+ cycle_t cycle_last ____cacheline_aligned_in_smp;
+ u64 xtime_nsec;
s64 error;
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
@@ -198,6 +211,7 @@ static inline void clocksource_calculate_interval(struct clocksource *c,
extern int clocksource_register(struct clocksource*);
extern struct clocksource* clocksource_get_next(void);
extern void clocksource_change_rating(struct clocksource *cs, int rating);
+extern void clocksource_resume(void);
#ifdef CONFIG_GENERIC_TIME_VSYSCALL
extern void update_vsyscall(struct timespec *ts, struct clocksource *c);
diff --git a/include/linux/compat.h b/include/linux/compat.h
index ccd863dd77f..70a157a130b 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -253,5 +253,8 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
+asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename,
+ struct compat_timespec __user *t, int flags);
+
#endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
deleted file mode 100644
index c26c3adcfac..00000000000
--- a/include/linux/compat_ioctl.h
+++ /dev/null
@@ -1,830 +0,0 @@
-/* List here explicitly which ioctl's are known to have
- * compatible types passed or none at all... Please include
- * only stuff that is compatible on *all architectures*.
- */
-
-COMPATIBLE_IOCTL(0x4B50) /* KDGHWCLK - not in the kernel, but don't complain */
-COMPATIBLE_IOCTL(0x4B51) /* KDSHWCLK - not in the kernel, but don't complain */
-
-/* Big T */
-COMPATIBLE_IOCTL(TCGETA)
-COMPATIBLE_IOCTL(TCSETA)
-COMPATIBLE_IOCTL(TCSETAW)
-COMPATIBLE_IOCTL(TCSETAF)
-COMPATIBLE_IOCTL(TCSBRK)
-ULONG_IOCTL(TCSBRKP)
-COMPATIBLE_IOCTL(TCXONC)
-COMPATIBLE_IOCTL(TCFLSH)
-COMPATIBLE_IOCTL(TCGETS)
-COMPATIBLE_IOCTL(TCSETS)
-COMPATIBLE_IOCTL(TCSETSW)
-COMPATIBLE_IOCTL(TCSETSF)
-COMPATIBLE_IOCTL(TIOCLINUX)
-COMPATIBLE_IOCTL(TIOCSBRK)
-COMPATIBLE_IOCTL(TIOCCBRK)
-ULONG_IOCTL(TIOCMIWAIT)
-COMPATIBLE_IOCTL(TIOCGICOUNT)
-/* Little t */
-COMPATIBLE_IOCTL(TIOCGETD)
-COMPATIBLE_IOCTL(TIOCSETD)
-COMPATIBLE_IOCTL(TIOCEXCL)
-COMPATIBLE_IOCTL(TIOCNXCL)
-COMPATIBLE_IOCTL(TIOCCONS)
-COMPATIBLE_IOCTL(TIOCGSOFTCAR)
-COMPATIBLE_IOCTL(TIOCSSOFTCAR)
-COMPATIBLE_IOCTL(TIOCSWINSZ)
-COMPATIBLE_IOCTL(TIOCGWINSZ)
-COMPATIBLE_IOCTL(TIOCMGET)
-COMPATIBLE_IOCTL(TIOCMBIC)
-COMPATIBLE_IOCTL(TIOCMBIS)
-COMPATIBLE_IOCTL(TIOCMSET)
-COMPATIBLE_IOCTL(TIOCPKT)
-COMPATIBLE_IOCTL(TIOCNOTTY)
-COMPATIBLE_IOCTL(TIOCSTI)
-COMPATIBLE_IOCTL(TIOCOUTQ)
-COMPATIBLE_IOCTL(TIOCSPGRP)
-COMPATIBLE_IOCTL(TIOCGPGRP)
-ULONG_IOCTL(TIOCSCTTY)
-COMPATIBLE_IOCTL(TIOCGPTN)
-COMPATIBLE_IOCTL(TIOCSPTLCK)
-COMPATIBLE_IOCTL(TIOCSERGETLSR)
-/* Little f */
-COMPATIBLE_IOCTL(FIOCLEX)
-COMPATIBLE_IOCTL(FIONCLEX)
-COMPATIBLE_IOCTL(FIOASYNC)
-COMPATIBLE_IOCTL(FIONBIO)
-COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */
-/* 0x00 */
-COMPATIBLE_IOCTL(FIBMAP)
-COMPATIBLE_IOCTL(FIGETBSZ)
-/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
- * Some need translations, these do not.
- */
-COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
-COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
-COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
-ULONG_IOCTL(HDIO_SET_MULTCOUNT)
-ULONG_IOCTL(HDIO_SET_UNMASKINTR)
-ULONG_IOCTL(HDIO_SET_KEEPSETTINGS)
-ULONG_IOCTL(HDIO_SET_32BIT)
-ULONG_IOCTL(HDIO_SET_NOWERR)
-ULONG_IOCTL(HDIO_SET_DMA)
-ULONG_IOCTL(HDIO_SET_PIO_MODE)
-ULONG_IOCTL(HDIO_SET_NICE)
-ULONG_IOCTL(HDIO_SET_WCACHE)
-ULONG_IOCTL(HDIO_SET_ACOUSTIC)
-ULONG_IOCTL(HDIO_SET_BUSSTATE)
-ULONG_IOCTL(HDIO_SET_ADDRESS)
-COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
-/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
-COMPATIBLE_IOCTL(0x330)
-/* 0x02 -- Floppy ioctls */
-COMPATIBLE_IOCTL(FDMSGON)
-COMPATIBLE_IOCTL(FDMSGOFF)
-COMPATIBLE_IOCTL(FDSETEMSGTRESH)
-COMPATIBLE_IOCTL(FDFLUSH)
-COMPATIBLE_IOCTL(FDWERRORCLR)
-COMPATIBLE_IOCTL(FDSETMAXERRS)
-COMPATIBLE_IOCTL(FDGETMAXERRS)
-COMPATIBLE_IOCTL(FDGETDRVTYP)
-COMPATIBLE_IOCTL(FDEJECT)
-COMPATIBLE_IOCTL(FDCLRPRM)
-COMPATIBLE_IOCTL(FDFMTBEG)
-COMPATIBLE_IOCTL(FDFMTEND)
-COMPATIBLE_IOCTL(FDRESET)
-COMPATIBLE_IOCTL(FDTWADDLE)
-COMPATIBLE_IOCTL(FDFMTTRK)
-COMPATIBLE_IOCTL(FDRAWCMD)
-/* 0x12 */
-#ifdef CONFIG_BLOCK
-COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(BLKROSET)
-COMPATIBLE_IOCTL(BLKROGET)
-COMPATIBLE_IOCTL(BLKRRPART)
-COMPATIBLE_IOCTL(BLKFLSBUF)
-COMPATIBLE_IOCTL(BLKSECTSET)
-COMPATIBLE_IOCTL(BLKSSZGET)
-COMPATIBLE_IOCTL(BLKTRACESTART)
-COMPATIBLE_IOCTL(BLKTRACESTOP)
-COMPATIBLE_IOCTL(BLKTRACESETUP)
-COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
-ULONG_IOCTL(BLKRASET)
-ULONG_IOCTL(BLKFRASET)
-#endif
-/* RAID */
-COMPATIBLE_IOCTL(RAID_VERSION)
-COMPATIBLE_IOCTL(GET_ARRAY_INFO)
-COMPATIBLE_IOCTL(GET_DISK_INFO)
-COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
-COMPATIBLE_IOCTL(RAID_AUTORUN)
-COMPATIBLE_IOCTL(CLEAR_ARRAY)
-COMPATIBLE_IOCTL(ADD_NEW_DISK)
-ULONG_IOCTL(HOT_REMOVE_DISK)
-COMPATIBLE_IOCTL(SET_ARRAY_INFO)
-COMPATIBLE_IOCTL(SET_DISK_INFO)
-COMPATIBLE_IOCTL(WRITE_RAID_INFO)
-COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
-COMPATIBLE_IOCTL(PROTECT_ARRAY)
-ULONG_IOCTL(HOT_ADD_DISK)
-ULONG_IOCTL(SET_DISK_FAULTY)
-COMPATIBLE_IOCTL(RUN_ARRAY)
-COMPATIBLE_IOCTL(STOP_ARRAY)
-COMPATIBLE_IOCTL(STOP_ARRAY_RO)
-COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-COMPATIBLE_IOCTL(GET_BITMAP_FILE)
-ULONG_IOCTL(SET_BITMAP_FILE)
-/* DM */
-COMPATIBLE_IOCTL(DM_VERSION_32)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL_32)
-COMPATIBLE_IOCTL(DM_LIST_DEVICES_32)
-COMPATIBLE_IOCTL(DM_DEV_CREATE_32)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE_32)
-COMPATIBLE_IOCTL(DM_DEV_RENAME_32)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND_32)
-COMPATIBLE_IOCTL(DM_DEV_STATUS_32)
-COMPATIBLE_IOCTL(DM_DEV_WAIT_32)
-COMPATIBLE_IOCTL(DM_TABLE_LOAD_32)
-COMPATIBLE_IOCTL(DM_TABLE_CLEAR_32)
-COMPATIBLE_IOCTL(DM_TABLE_DEPS_32)
-COMPATIBLE_IOCTL(DM_TABLE_STATUS_32)
-COMPATIBLE_IOCTL(DM_LIST_VERSIONS_32)
-COMPATIBLE_IOCTL(DM_TARGET_MSG_32)
-COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY_32)
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_LIST_DEVICES)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_DEV_WAIT)
-COMPATIBLE_IOCTL(DM_TABLE_LOAD)
-COMPATIBLE_IOCTL(DM_TABLE_CLEAR)
-COMPATIBLE_IOCTL(DM_TABLE_DEPS)
-COMPATIBLE_IOCTL(DM_TABLE_STATUS)
-COMPATIBLE_IOCTL(DM_LIST_VERSIONS)
-COMPATIBLE_IOCTL(DM_TARGET_MSG)
-COMPATIBLE_IOCTL(DM_DEV_SET_GEOMETRY)
-/* Big K */
-COMPATIBLE_IOCTL(PIO_FONT)
-COMPATIBLE_IOCTL(GIO_FONT)
-ULONG_IOCTL(KDSIGACCEPT)
-COMPATIBLE_IOCTL(KDGETKEYCODE)
-COMPATIBLE_IOCTL(KDSETKEYCODE)
-ULONG_IOCTL(KIOCSOUND)
-ULONG_IOCTL(KDMKTONE)
-COMPATIBLE_IOCTL(KDGKBTYPE)
-ULONG_IOCTL(KDSETMODE)
-COMPATIBLE_IOCTL(KDGETMODE)
-ULONG_IOCTL(KDSKBMODE)
-COMPATIBLE_IOCTL(KDGKBMODE)
-ULONG_IOCTL(KDSKBMETA)
-COMPATIBLE_IOCTL(KDGKBMETA)
-COMPATIBLE_IOCTL(KDGKBENT)
-COMPATIBLE_IOCTL(KDSKBENT)
-COMPATIBLE_IOCTL(KDGKBSENT)
-COMPATIBLE_IOCTL(KDSKBSENT)
-COMPATIBLE_IOCTL(KDGKBDIACR)
-COMPATIBLE_IOCTL(KDSKBDIACR)
-COMPATIBLE_IOCTL(KDKBDREP)
-COMPATIBLE_IOCTL(KDGKBLED)
-ULONG_IOCTL(KDSKBLED)
-COMPATIBLE_IOCTL(KDGETLED)
-ULONG_IOCTL(KDSETLED)
-COMPATIBLE_IOCTL(GIO_SCRNMAP)
-COMPATIBLE_IOCTL(PIO_SCRNMAP)
-COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
-COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
-COMPATIBLE_IOCTL(PIO_FONTRESET)
-COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
-/* Big S */
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
-COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
-COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
-/* Big T */
-COMPATIBLE_IOCTL(TUNSETNOCSUM)
-COMPATIBLE_IOCTL(TUNSETDEBUG)
-COMPATIBLE_IOCTL(TUNSETPERSIST)
-COMPATIBLE_IOCTL(TUNSETOWNER)
-/* Big V */
-COMPATIBLE_IOCTL(VT_SETMODE)
-COMPATIBLE_IOCTL(VT_GETMODE)
-COMPATIBLE_IOCTL(VT_GETSTATE)
-COMPATIBLE_IOCTL(VT_OPENQRY)
-ULONG_IOCTL(VT_ACTIVATE)
-ULONG_IOCTL(VT_WAITACTIVE)
-ULONG_IOCTL(VT_RELDISP)
-ULONG_IOCTL(VT_DISALLOCATE)
-COMPATIBLE_IOCTL(VT_RESIZE)
-COMPATIBLE_IOCTL(VT_RESIZEX)
-COMPATIBLE_IOCTL(VT_LOCKSWITCH)
-COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-COMPATIBLE_IOCTL(VT_GETHIFONTMASK)
-/* Little p (/dev/rtc, /dev/envctrl, etc.) */
-COMPATIBLE_IOCTL(RTC_AIE_ON)
-COMPATIBLE_IOCTL(RTC_AIE_OFF)
-COMPATIBLE_IOCTL(RTC_UIE_ON)
-COMPATIBLE_IOCTL(RTC_UIE_OFF)
-COMPATIBLE_IOCTL(RTC_PIE_ON)
-COMPATIBLE_IOCTL(RTC_PIE_OFF)
-COMPATIBLE_IOCTL(RTC_WIE_ON)
-COMPATIBLE_IOCTL(RTC_WIE_OFF)
-COMPATIBLE_IOCTL(RTC_ALM_SET)
-COMPATIBLE_IOCTL(RTC_ALM_READ)
-COMPATIBLE_IOCTL(RTC_RD_TIME)
-COMPATIBLE_IOCTL(RTC_SET_TIME)
-COMPATIBLE_IOCTL(RTC_WKALM_SET)
-COMPATIBLE_IOCTL(RTC_WKALM_RD)
-/*
- * These two are only for the sbus rtc driver, but
- * hwclock tries them on every rtc device first when
- * running on sparc. On other architectures the entries
- * are useless but harmless.
- */
-COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
-COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
-/* Little m */
-COMPATIBLE_IOCTL(MTIOCTOP)
-/* Socket level stuff */
-COMPATIBLE_IOCTL(FIOQSIZE)
-COMPATIBLE_IOCTL(FIOSETOWN)
-COMPATIBLE_IOCTL(SIOCSPGRP)
-COMPATIBLE_IOCTL(FIOGETOWN)
-COMPATIBLE_IOCTL(SIOCGPGRP)
-COMPATIBLE_IOCTL(SIOCATMARK)
-COMPATIBLE_IOCTL(SIOCSIFLINK)
-COMPATIBLE_IOCTL(SIOCSIFENCAP)
-COMPATIBLE_IOCTL(SIOCGIFENCAP)
-COMPATIBLE_IOCTL(SIOCSIFNAME)
-COMPATIBLE_IOCTL(SIOCSARP)
-COMPATIBLE_IOCTL(SIOCGARP)
-COMPATIBLE_IOCTL(SIOCDARP)
-COMPATIBLE_IOCTL(SIOCSRARP)
-COMPATIBLE_IOCTL(SIOCGRARP)
-COMPATIBLE_IOCTL(SIOCDRARP)
-COMPATIBLE_IOCTL(SIOCADDDLCI)
-COMPATIBLE_IOCTL(SIOCDELDLCI)
-COMPATIBLE_IOCTL(SIOCGMIIPHY)
-COMPATIBLE_IOCTL(SIOCGMIIREG)
-COMPATIBLE_IOCTL(SIOCSMIIREG)
-COMPATIBLE_IOCTL(SIOCGIFVLAN)
-COMPATIBLE_IOCTL(SIOCSIFVLAN)
-COMPATIBLE_IOCTL(SIOCBRADDBR)
-COMPATIBLE_IOCTL(SIOCBRDELBR)
-/* SG stuff */
-COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_EMULATED_HOST)
-ULONG_IOCTL(SG_SET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
-COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
-COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
-COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
-COMPATIBLE_IOCTL(SG_SET_DEBUG)
-COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
-COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
-COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
-COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
-COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
-/* PPP stuff */
-COMPATIBLE_IOCTL(PPPIOCGFLAGS)
-COMPATIBLE_IOCTL(PPPIOCSFLAGS)
-COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGUNIT)
-COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGMRU)
-COMPATIBLE_IOCTL(PPPIOCSMRU)
-COMPATIBLE_IOCTL(PPPIOCSMAXCID)
-COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
-/* PPPIOCSCOMPRESS is translated */
-COMPATIBLE_IOCTL(PPPIOCGNPMODE)
-COMPATIBLE_IOCTL(PPPIOCSNPMODE)
-COMPATIBLE_IOCTL(PPPIOCGDEBUG)
-COMPATIBLE_IOCTL(PPPIOCSDEBUG)
-/* PPPIOCSPASS is translated */
-/* PPPIOCSACTIVE is translated */
-/* PPPIOCGIDLE is translated */
-COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
-COMPATIBLE_IOCTL(PPPIOCATTACH)
-COMPATIBLE_IOCTL(PPPIOCDETACH)
-COMPATIBLE_IOCTL(PPPIOCSMRRU)
-COMPATIBLE_IOCTL(PPPIOCCONNECT)
-COMPATIBLE_IOCTL(PPPIOCDISCONN)
-COMPATIBLE_IOCTL(PPPIOCATTCHAN)
-COMPATIBLE_IOCTL(PPPIOCGCHAN)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
-/* LP */
-COMPATIBLE_IOCTL(LPGETSTATUS)
-/* ppdev */
-COMPATIBLE_IOCTL(PPSETMODE)
-COMPATIBLE_IOCTL(PPRSTATUS)
-COMPATIBLE_IOCTL(PPRCONTROL)
-COMPATIBLE_IOCTL(PPWCONTROL)
-COMPATIBLE_IOCTL(PPFCONTROL)
-COMPATIBLE_IOCTL(PPRDATA)
-COMPATIBLE_IOCTL(PPWDATA)
-COMPATIBLE_IOCTL(PPCLAIM)
-COMPATIBLE_IOCTL(PPRELEASE)
-COMPATIBLE_IOCTL(PPYIELD)
-COMPATIBLE_IOCTL(PPEXCL)
-COMPATIBLE_IOCTL(PPDATADIR)
-COMPATIBLE_IOCTL(PPNEGOT)
-COMPATIBLE_IOCTL(PPWCTLONIRQ)
-COMPATIBLE_IOCTL(PPCLRIRQ)
-COMPATIBLE_IOCTL(PPSETPHASE)
-COMPATIBLE_IOCTL(PPGETMODES)
-COMPATIBLE_IOCTL(PPGETMODE)
-COMPATIBLE_IOCTL(PPGETPHASE)
-COMPATIBLE_IOCTL(PPGETFLAGS)
-COMPATIBLE_IOCTL(PPSETFLAGS)
-/* CDROM stuff */
-COMPATIBLE_IOCTL(CDROMPAUSE)
-COMPATIBLE_IOCTL(CDROMRESUME)
-COMPATIBLE_IOCTL(CDROMPLAYMSF)
-COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
-COMPATIBLE_IOCTL(CDROMREADTOCHDR)
-COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
-COMPATIBLE_IOCTL(CDROMSTOP)
-COMPATIBLE_IOCTL(CDROMSTART)
-COMPATIBLE_IOCTL(CDROMEJECT)
-COMPATIBLE_IOCTL(CDROMVOLCTRL)
-COMPATIBLE_IOCTL(CDROMSUBCHNL)
-ULONG_IOCTL(CDROMEJECT_SW)
-COMPATIBLE_IOCTL(CDROMMULTISESSION)
-COMPATIBLE_IOCTL(CDROM_GET_MCN)
-COMPATIBLE_IOCTL(CDROMRESET)
-COMPATIBLE_IOCTL(CDROMVOLREAD)
-COMPATIBLE_IOCTL(CDROMSEEK)
-COMPATIBLE_IOCTL(CDROMPLAYBLK)
-COMPATIBLE_IOCTL(CDROMCLOSETRAY)
-ULONG_IOCTL(CDROM_SET_OPTIONS)
-ULONG_IOCTL(CDROM_CLEAR_OPTIONS)
-ULONG_IOCTL(CDROM_SELECT_SPEED)
-ULONG_IOCTL(CDROM_SELECT_DISC)
-ULONG_IOCTL(CDROM_MEDIA_CHANGED)
-ULONG_IOCTL(CDROM_DRIVE_STATUS)
-COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
-COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
-ULONG_IOCTL(CDROM_LOCKDOOR)
-ULONG_IOCTL(CDROM_DEBUG)
-COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
-/* Ignore cdrom.h about these next 5 ioctls, they absolutely do
- * not take a struct cdrom_read, instead they take a struct cdrom_msf
- * which is compatible.
- */
-COMPATIBLE_IOCTL(CDROMREADMODE2)
-COMPATIBLE_IOCTL(CDROMREADMODE1)
-COMPATIBLE_IOCTL(CDROMREADRAW)
-COMPATIBLE_IOCTL(CDROMREADCOOKED)
-COMPATIBLE_IOCTL(CDROMREADALL)
-/* DVD ioctls */
-COMPATIBLE_IOCTL(DVD_READ_STRUCT)
-COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
-COMPATIBLE_IOCTL(DVD_AUTH)
-/* pktcdvd */
-COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
-/* Big A */
-/* sparc only */
-/* Big Q for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
-COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
-COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
-/* Big T for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_START)
-COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
-COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
-/* Little m for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
-/* Big P for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
-COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
-/* SNDCTL_DSP_MAPINBUF, XXX needs translation */
-/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
-COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
-/* Big C for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
-COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
-COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
-COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
-/* Big M for sound/OSS */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
-/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */
-/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
-/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */
-/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
-COMPATIBLE_IOCTL(SOUND_MIXER_AGC)
-COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
-COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
-COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
-COMPATIBLE_IOCTL(OSS_GETVERSION)
-/* AUTOFS */
-ULONG_IOCTL(AUTOFS_IOC_READY)
-ULONG_IOCTL(AUTOFS_IOC_FAIL)
-COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI)
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER)
-COMPATIBLE_IOCTL(AUTOFS_IOC_ASKREGHOST)
-COMPATIBLE_IOCTL(AUTOFS_IOC_TOGGLEREGHOST)
-COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT)
-/* Raw devices */
-COMPATIBLE_IOCTL(RAW_SETBIND)
-COMPATIBLE_IOCTL(RAW_GETBIND)
-/* SMB ioctls which do not need any translations */
-COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
-/* Little a */
-COMPATIBLE_IOCTL(ATMSIGD_CTRL)
-COMPATIBLE_IOCTL(ATMARPD_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_MCAST)
-COMPATIBLE_IOCTL(ATMLEC_DATA)
-COMPATIBLE_IOCTL(ATM_SETSC)
-COMPATIBLE_IOCTL(SIOCSIFATMTCP)
-COMPATIBLE_IOCTL(SIOCMKCLIP)
-COMPATIBLE_IOCTL(ATMARP_MKIP)
-COMPATIBLE_IOCTL(ATMARP_SETENTRY)
-COMPATIBLE_IOCTL(ATMARP_ENCAP)
-COMPATIBLE_IOCTL(ATMTCP_CREATE)
-COMPATIBLE_IOCTL(ATMTCP_REMOVE)
-COMPATIBLE_IOCTL(ATMMPC_CTRL)
-COMPATIBLE_IOCTL(ATMMPC_DATA)
-/* Watchdog */
-COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
-COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
-COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
-COMPATIBLE_IOCTL(WDIOC_GETTEMP)
-COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
-COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
-COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT)
-COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT)
-/* Big R */
-COMPATIBLE_IOCTL(RNDGETENTCNT)
-COMPATIBLE_IOCTL(RNDADDTOENTCNT)
-COMPATIBLE_IOCTL(RNDGETPOOL)
-COMPATIBLE_IOCTL(RNDADDENTROPY)
-COMPATIBLE_IOCTL(RNDZAPENTCNT)
-COMPATIBLE_IOCTL(RNDCLEARPOOL)
-/* Bluetooth */
-COMPATIBLE_IOCTL(HCIDEVUP)
-COMPATIBLE_IOCTL(HCIDEVDOWN)
-COMPATIBLE_IOCTL(HCIDEVRESET)
-COMPATIBLE_IOCTL(HCIDEVRESTAT)
-COMPATIBLE_IOCTL(HCIGETDEVLIST)
-COMPATIBLE_IOCTL(HCIGETDEVINFO)
-COMPATIBLE_IOCTL(HCIGETCONNLIST)
-COMPATIBLE_IOCTL(HCIGETCONNINFO)
-COMPATIBLE_IOCTL(HCISETRAW)
-COMPATIBLE_IOCTL(HCISETSCAN)
-COMPATIBLE_IOCTL(HCISETAUTH)
-COMPATIBLE_IOCTL(HCISETENCRYPT)
-COMPATIBLE_IOCTL(HCISETPTYPE)
-COMPATIBLE_IOCTL(HCISETLINKPOL)
-COMPATIBLE_IOCTL(HCISETLINKMODE)
-COMPATIBLE_IOCTL(HCISETACLMTU)
-COMPATIBLE_IOCTL(HCISETSCOMTU)
-COMPATIBLE_IOCTL(HCIINQUIRY)
-COMPATIBLE_IOCTL(HCIUARTSETPROTO)
-COMPATIBLE_IOCTL(HCIUARTGETPROTO)
-COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
-COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
-COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
-COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
-COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-COMPATIBLE_IOCTL(BNEPCONNADD)
-COMPATIBLE_IOCTL(BNEPCONNDEL)
-COMPATIBLE_IOCTL(BNEPGETCONNLIST)
-COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-COMPATIBLE_IOCTL(CMTPCONNADD)
-COMPATIBLE_IOCTL(CMTPCONNDEL)
-COMPATIBLE_IOCTL(CMTPGETCONNLIST)
-COMPATIBLE_IOCTL(CMTPGETCONNINFO)
-COMPATIBLE_IOCTL(HIDPCONNADD)
-COMPATIBLE_IOCTL(HIDPCONNDEL)
-COMPATIBLE_IOCTL(HIDPGETCONNLIST)
-COMPATIBLE_IOCTL(HIDPGETCONNINFO)
-/* CAPI */
-COMPATIBLE_IOCTL(CAPI_REGISTER)
-COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER)
-COMPATIBLE_IOCTL(CAPI_GET_VERSION)
-COMPATIBLE_IOCTL(CAPI_GET_SERIAL)
-COMPATIBLE_IOCTL(CAPI_GET_PROFILE)
-COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD)
-COMPATIBLE_IOCTL(CAPI_GET_ERRCODE)
-COMPATIBLE_IOCTL(CAPI_INSTALLED)
-COMPATIBLE_IOCTL(CAPI_GET_FLAGS)
-COMPATIBLE_IOCTL(CAPI_SET_FLAGS)
-COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
-COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
-COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
-/* Siemens Gigaset */
-COMPATIBLE_IOCTL(GIGASET_REDIR)
-COMPATIBLE_IOCTL(GIGASET_CONFIG)
-COMPATIBLE_IOCTL(GIGASET_BRKCHARS)
-COMPATIBLE_IOCTL(GIGASET_VERSION)
-/* Misc. */
-COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */
-COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */
-COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
-COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
-/* USB */
-COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
-COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
-COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
-COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
-COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_RESET)
-COMPATIBLE_IOCTL(USBDEVFS_SUBMITURB32)
-COMPATIBLE_IOCTL(USBDEVFS_REAPURB32)
-COMPATIBLE_IOCTL(USBDEVFS_REAPURBNDELAY32)
-COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
-/* MTD */
-COMPATIBLE_IOCTL(MEMGETINFO)
-COMPATIBLE_IOCTL(MEMERASE)
-COMPATIBLE_IOCTL(MEMLOCK)
-COMPATIBLE_IOCTL(MEMUNLOCK)
-COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
-COMPATIBLE_IOCTL(MEMGETREGIONINFO)
-COMPATIBLE_IOCTL(MEMGETBADBLOCK)
-COMPATIBLE_IOCTL(MEMSETBADBLOCK)
-/* NBD */
-ULONG_IOCTL(NBD_SET_SOCK)
-ULONG_IOCTL(NBD_SET_BLKSIZE)
-ULONG_IOCTL(NBD_SET_SIZE)
-COMPATIBLE_IOCTL(NBD_DO_IT)
-COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
-COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
-COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
-ULONG_IOCTL(NBD_SET_SIZE_BLOCKS)
-COMPATIBLE_IOCTL(NBD_DISCONNECT)
-/* i2c */
-COMPATIBLE_IOCTL(I2C_SLAVE)
-COMPATIBLE_IOCTL(I2C_SLAVE_FORCE)
-COMPATIBLE_IOCTL(I2C_TENBIT)
-COMPATIBLE_IOCTL(I2C_PEC)
-COMPATIBLE_IOCTL(I2C_RETRIES)
-COMPATIBLE_IOCTL(I2C_TIMEOUT)
-/* wireless */
-COMPATIBLE_IOCTL(SIOCSIWCOMMIT)
-COMPATIBLE_IOCTL(SIOCGIWNAME)
-COMPATIBLE_IOCTL(SIOCSIWNWID)
-COMPATIBLE_IOCTL(SIOCGIWNWID)
-COMPATIBLE_IOCTL(SIOCSIWFREQ)
-COMPATIBLE_IOCTL(SIOCGIWFREQ)
-COMPATIBLE_IOCTL(SIOCSIWMODE)
-COMPATIBLE_IOCTL(SIOCGIWMODE)
-COMPATIBLE_IOCTL(SIOCSIWSENS)
-COMPATIBLE_IOCTL(SIOCGIWSENS)
-COMPATIBLE_IOCTL(SIOCSIWRANGE)
-COMPATIBLE_IOCTL(SIOCSIWPRIV)
-COMPATIBLE_IOCTL(SIOCGIWPRIV)
-COMPATIBLE_IOCTL(SIOCSIWSTATS)
-COMPATIBLE_IOCTL(SIOCGIWSTATS)
-COMPATIBLE_IOCTL(SIOCSIWAP)
-COMPATIBLE_IOCTL(SIOCGIWAP)
-COMPATIBLE_IOCTL(SIOCSIWSCAN)
-COMPATIBLE_IOCTL(SIOCSIWRATE)
-COMPATIBLE_IOCTL(SIOCGIWRATE)
-COMPATIBLE_IOCTL(SIOCSIWRTS)
-COMPATIBLE_IOCTL(SIOCGIWRTS)
-COMPATIBLE_IOCTL(SIOCSIWFRAG)
-COMPATIBLE_IOCTL(SIOCGIWFRAG)
-COMPATIBLE_IOCTL(SIOCSIWTXPOW)
-COMPATIBLE_IOCTL(SIOCGIWTXPOW)
-COMPATIBLE_IOCTL(SIOCSIWRETRY)
-COMPATIBLE_IOCTL(SIOCGIWRETRY)
-COMPATIBLE_IOCTL(SIOCSIWPOWER)
-COMPATIBLE_IOCTL(SIOCGIWPOWER)
-/* hiddev */
-COMPATIBLE_IOCTL(HIDIOCGVERSION)
-COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
-COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
-COMPATIBLE_IOCTL(HIDIOCGSTRING)
-COMPATIBLE_IOCTL(HIDIOCINITREPORT)
-COMPATIBLE_IOCTL(HIDIOCGREPORT)
-COMPATIBLE_IOCTL(HIDIOCSREPORT)
-COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
-COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
-COMPATIBLE_IOCTL(HIDIOCGUSAGE)
-COMPATIBLE_IOCTL(HIDIOCSUSAGE)
-COMPATIBLE_IOCTL(HIDIOCGUCODE)
-COMPATIBLE_IOCTL(HIDIOCGFLAG)
-COMPATIBLE_IOCTL(HIDIOCSFLAG)
-COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
-COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
-/* dvb */
-COMPATIBLE_IOCTL(AUDIO_STOP)
-COMPATIBLE_IOCTL(AUDIO_PLAY)
-COMPATIBLE_IOCTL(AUDIO_PAUSE)
-COMPATIBLE_IOCTL(AUDIO_CONTINUE)
-COMPATIBLE_IOCTL(AUDIO_SELECT_SOURCE)
-COMPATIBLE_IOCTL(AUDIO_SET_MUTE)
-COMPATIBLE_IOCTL(AUDIO_SET_AV_SYNC)
-COMPATIBLE_IOCTL(AUDIO_SET_BYPASS_MODE)
-COMPATIBLE_IOCTL(AUDIO_CHANNEL_SELECT)
-COMPATIBLE_IOCTL(AUDIO_GET_STATUS)
-COMPATIBLE_IOCTL(AUDIO_GET_CAPABILITIES)
-COMPATIBLE_IOCTL(AUDIO_CLEAR_BUFFER)
-COMPATIBLE_IOCTL(AUDIO_SET_ID)
-COMPATIBLE_IOCTL(AUDIO_SET_MIXER)
-COMPATIBLE_IOCTL(AUDIO_SET_STREAMTYPE)
-COMPATIBLE_IOCTL(AUDIO_SET_EXT_ID)
-COMPATIBLE_IOCTL(AUDIO_SET_ATTRIBUTES)
-COMPATIBLE_IOCTL(AUDIO_SET_KARAOKE)
-COMPATIBLE_IOCTL(DMX_START)
-COMPATIBLE_IOCTL(DMX_STOP)
-COMPATIBLE_IOCTL(DMX_SET_FILTER)
-COMPATIBLE_IOCTL(DMX_SET_PES_FILTER)
-COMPATIBLE_IOCTL(DMX_SET_BUFFER_SIZE)
-COMPATIBLE_IOCTL(DMX_GET_PES_PIDS)
-COMPATIBLE_IOCTL(DMX_GET_CAPS)
-COMPATIBLE_IOCTL(DMX_SET_SOURCE)
-COMPATIBLE_IOCTL(DMX_GET_STC)
-COMPATIBLE_IOCTL(FE_GET_INFO)
-COMPATIBLE_IOCTL(FE_DISEQC_RESET_OVERLOAD)
-COMPATIBLE_IOCTL(FE_DISEQC_SEND_MASTER_CMD)
-COMPATIBLE_IOCTL(FE_DISEQC_RECV_SLAVE_REPLY)
-COMPATIBLE_IOCTL(FE_DISEQC_SEND_BURST)
-COMPATIBLE_IOCTL(FE_SET_TONE)
-COMPATIBLE_IOCTL(FE_SET_VOLTAGE)
-COMPATIBLE_IOCTL(FE_ENABLE_HIGH_LNB_VOLTAGE)
-COMPATIBLE_IOCTL(FE_READ_STATUS)
-COMPATIBLE_IOCTL(FE_READ_BER)
-COMPATIBLE_IOCTL(FE_READ_SIGNAL_STRENGTH)
-COMPATIBLE_IOCTL(FE_READ_SNR)
-COMPATIBLE_IOCTL(FE_READ_UNCORRECTED_BLOCKS)
-COMPATIBLE_IOCTL(FE_SET_FRONTEND)
-COMPATIBLE_IOCTL(FE_GET_FRONTEND)
-COMPATIBLE_IOCTL(FE_GET_EVENT)
-COMPATIBLE_IOCTL(FE_DISHNETWORK_SEND_LEGACY_CMD)
-COMPATIBLE_IOCTL(VIDEO_STOP)
-COMPATIBLE_IOCTL(VIDEO_PLAY)
-COMPATIBLE_IOCTL(VIDEO_FREEZE)
-COMPATIBLE_IOCTL(VIDEO_CONTINUE)
-COMPATIBLE_IOCTL(VIDEO_SELECT_SOURCE)
-COMPATIBLE_IOCTL(VIDEO_SET_BLANK)
-COMPATIBLE_IOCTL(VIDEO_GET_STATUS)
-COMPATIBLE_IOCTL(VIDEO_SET_DISPLAY_FORMAT)
-COMPATIBLE_IOCTL(VIDEO_FAST_FORWARD)
-COMPATIBLE_IOCTL(VIDEO_SLOWMOTION)
-COMPATIBLE_IOCTL(VIDEO_GET_CAPABILITIES)
-COMPATIBLE_IOCTL(VIDEO_CLEAR_BUFFER)
-COMPATIBLE_IOCTL(VIDEO_SET_ID)
-COMPATIBLE_IOCTL(VIDEO_SET_STREAMTYPE)
-COMPATIBLE_IOCTL(VIDEO_SET_FORMAT)
-COMPATIBLE_IOCTL(VIDEO_SET_SYSTEM)
-COMPATIBLE_IOCTL(VIDEO_SET_HIGHLIGHT)
-COMPATIBLE_IOCTL(VIDEO_SET_SPU)
-COMPATIBLE_IOCTL(VIDEO_GET_NAVI)
-COMPATIBLE_IOCTL(VIDEO_SET_ATTRIBUTES)
-COMPATIBLE_IOCTL(VIDEO_GET_SIZE)
-COMPATIBLE_IOCTL(VIDEO_GET_FRAME_RATE)
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index 9008eabb9c3..03ec2311fb2 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -22,6 +22,9 @@
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
+/* &a[0] degrades to a pointer: a different type from an array */
+#define __must_be_array(a) \
+ BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
#define inline inline __attribute__((always_inline))
#define __inline__ __inline__ __attribute__((always_inline))
@@ -37,3 +40,4 @@
#define noinline __attribute__((noinline))
#define __attribute_pure__ __attribute__((pure))
#define __attribute_const__ __attribute__((__const__))
+#define __maybe_unused __attribute__((unused))
diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h
index 1698b845761..a9e2863c2db 100644
--- a/include/linux/compiler-gcc3.h
+++ b/include/linux/compiler-gcc3.h
@@ -4,13 +4,21 @@
#include <linux/compiler-gcc.h>
#if __GNUC_MINOR__ >= 3
-# define __attribute_used__ __attribute__((__used__))
+# define __used __attribute__((__used__))
+# define __attribute_used__ __used /* deprecated */
#else
-# define __attribute_used__ __attribute__((__unused__))
+# define __used __attribute__((__unused__))
+# define __attribute_used__ __used /* deprecated */
#endif
#if __GNUC_MINOR__ >= 4
#define __must_check __attribute__((warn_unused_result))
#endif
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
+
#define __always_inline inline __attribute__((always_inline))
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index 6f5cc6f0e7a..a03e9398a6c 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -12,7 +12,14 @@
# define __inline __inline __attribute__((always_inline))
#endif
-#define __attribute_used__ __attribute__((__used__))
+#define __used __attribute__((__used__))
+#define __attribute_used__ __used /* deprecated */
#define __must_check __attribute__((warn_unused_result))
#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
#define __always_inline inline __attribute__((always_inline))
+
+/*
+ * A trick to suppress uninitialized variable warning without generating any
+ * code
+ */
+#define uninitialized_var(x) x = x
diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h
index 1d1c3ceaff4..b769961e6f2 100644
--- a/include/linux/compiler-intel.h
+++ b/include/linux/compiler-intel.h
@@ -21,4 +21,9 @@
__ptr = (unsigned long) (ptr); \
(typeof(ptr)) (__ptr + (off)); })
+/* Intel ECC compiler doesn't support __builtin_types_compatible_p() */
+#define __must_be_array(a) 0
+
#endif
+
+#define uninitialized_var(x) x
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 3b6949b4174..498c3592076 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -108,15 +108,30 @@ extern void __chk_io_ptr(const void __iomem *);
* Allow us to avoid 'defined but not used' warnings on functions and data,
* as well as force them to be emitted to the assembly file.
*
- * As of gcc 3.3, static functions that are not marked with attribute((used))
- * may be elided from the assembly file. As of gcc 3.3, static data not so
+ * As of gcc 3.4, static functions that are not marked with attribute((used))
+ * may be elided from the assembly file. As of gcc 3.4, static data not so
* marked will not be elided, but this may change in a future gcc version.
*
+ * NOTE: Because distributions shipped with a backported unit-at-a-time
+ * compiler in gcc 3.3, we must define __used to be __attribute__((used))
+ * for gcc >=3.3 instead of 3.4.
+ *
* In prior versions of gcc, such functions and data would be emitted, but
* would be warned about except with attribute((unused)).
+ *
+ * Mark functions that are referenced only in inline assembly as __used so
+ * the code is emitted even though it appears to be unreferenced.
*/
#ifndef __attribute_used__
-# define __attribute_used__ /* unimplemented */
+# define __attribute_used__ /* deprecated */
+#endif
+
+#ifndef __used
+# define __used /* unimplemented */
+#endif
+
+#ifndef __maybe_unused
+# define __maybe_unused /* unimplemented */
#endif
/*
diff --git a/include/linux/console.h b/include/linux/console.h
index de25ee3b791..62ef6e11d0d 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -51,7 +51,7 @@ struct consw {
int (*con_scrolldelta)(struct vc_data *, int);
int (*con_set_origin)(struct vc_data *);
void (*con_save_screen)(struct vc_data *);
- u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8);
+ u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8);
void (*con_invert_region)(struct vc_data *, u16 *, int);
u16 *(*con_screen_pos)(struct vc_data *, int);
unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
@@ -92,9 +92,8 @@ void give_up_console(const struct consw *sw);
#define CON_BOOT (8)
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
-struct console
-{
- char name[8];
+struct console {
+ char name[16];
void (*write)(struct console *, const char *, unsigned);
int (*read)(struct console *, char *, unsigned);
struct tty_driver *(*device)(struct console *, int *);
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index a86162b26c0..a461f76fb00 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -37,6 +37,7 @@ struct vc_data {
unsigned char vc_color; /* Foreground & background */
unsigned char vc_s_color; /* Saved foreground & background */
unsigned char vc_ulcolor; /* Color for underline mode */
+ unsigned char vc_itcolor;
unsigned char vc_halfcolor; /* Color for half intensity mode */
/* cursor */
unsigned int vc_cursor_type;
@@ -71,10 +72,12 @@ struct vc_data {
unsigned int vc_deccolm : 1; /* 80/132 Column Mode */
/* attribute flags */
unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */
+ unsigned int vc_italic:1;
unsigned int vc_underline : 1;
unsigned int vc_blink : 1;
unsigned int vc_reverse : 1;
unsigned int vc_s_intensity : 2; /* saved rendition */
+ unsigned int vc_s_italic:1;
unsigned int vc_s_underline : 1;
unsigned int vc_s_blink : 1;
unsigned int vc_s_reverse : 1;
diff --git a/include/asm-sparc64/const.h b/include/linux/const.h
index 8ad902b2ce0..07b300bfe34 100644
--- a/include/asm-sparc64/const.h
+++ b/include/linux/const.h
@@ -1,19 +1,19 @@
/* const.h: Macros for dealing with constants. */
-#ifndef _SPARC64_CONST_H
-#define _SPARC64_CONST_H
+#ifndef _LINUX_CONST_H
+#define _LINUX_CONST_H
/* Some constant macros are used in both assembler and
* C code. Therefore we cannot annotate them always with
- * 'UL' and other type specificers unilaterally. We
+ * 'UL' and other type specifiers unilaterally. We
* use the following macros to deal with this.
*/
#ifdef __ASSEMBLY__
#define _AC(X,Y) X
#else
-#define _AC(X,Y) (X##Y)
+#define __AC(X,Y) (X##Y)
+#define _AC(X,Y) __AC(X,Y)
#endif
-
-#endif /* !(_SPARC64_CONST_H) */
+#endif /* !(_LINUX_CONST_H) */
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index c22b0dfcbcd..3b2df2523f1 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -41,6 +41,9 @@ extern void cpu_remove_sysdev_attr(struct sysdev_attribute *attr);
extern int cpu_add_sysdev_attr_group(struct attribute_group *attrs);
extern void cpu_remove_sysdev_attr_group(struct attribute_group *attrs);
+extern struct sysdev_attribute attr_sched_mc_power_savings;
+extern struct sysdev_attribute attr_sched_smt_power_savings;
+extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
#ifdef CONFIG_HOTPLUG_CPU
extern void unregister_cpu(struct cpu *cpu);
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 0899e2cdcdd..963051a967d 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -32,7 +32,15 @@
* CPUFREQ NOTIFIER INTERFACE *
*********************************************************************/
+#ifdef CONFIG_CPU_FREQ
int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+#else
+static inline int cpufreq_register_notifier(struct notifier_block *nb,
+ unsigned int list)
+{
+ return 0;
+}
+#endif
int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
#define CPUFREQ_TRANSITION_NOTIFIER (0)
@@ -257,21 +265,25 @@ struct freq_attr {
/*********************************************************************
* CPUFREQ 2.6. INTERFACE *
*********************************************************************/
-int cpufreq_set_policy(struct cpufreq_policy *policy);
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
int cpufreq_update_policy(unsigned int cpu);
-/* query the current CPU frequency (in kHz). If zero, cpufreq couldn't detect it */
-unsigned int cpufreq_get(unsigned int cpu);
-/* query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it */
+/*
+ * query the last known CPU freq (in kHz). If zero, cpufreq couldn't detect it
+ */
#ifdef CONFIG_CPU_FREQ
unsigned int cpufreq_quick_get(unsigned int cpu);
+unsigned int cpufreq_get(unsigned int cpu);
#else
static inline unsigned int cpufreq_quick_get(unsigned int cpu)
{
return 0;
}
+static inline unsigned int cpufreq_get(unsigned int cpu)
+{
+ return 0;
+}
#endif
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 32503657f14..22c7ac5cd80 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -14,5 +14,13 @@ extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
extern const struct file_operations proc_vmcore_operations;
extern struct proc_dir_entry *proc_vmcore;
+/* Architecture code defines this if there are other possible ELF
+ * machine types, e.g. on bi-arch capable hardware. */
+#ifndef vmcore_elf_check_arch_cross
+#define vmcore_elf_check_arch_cross(x) 0
+#endif
+
+#define vmcore_elf_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x))
+
#endif /* CONFIG_CRASH_DUMP */
#endif /* LINUX_CRASHDUMP_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 779aa78ee64..0de7e2ace82 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -56,6 +56,7 @@
#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100
#define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200
+#define CRYPTO_TFM_REQ_MAY_BACKLOG 0x00000400
#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000
#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000
#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000
@@ -88,11 +89,38 @@
#endif
struct scatterlist;
+struct crypto_ablkcipher;
+struct crypto_async_request;
struct crypto_blkcipher;
struct crypto_hash;
+struct crypto_queue;
struct crypto_tfm;
struct crypto_type;
+typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err);
+
+struct crypto_async_request {
+ struct list_head list;
+ crypto_completion_t complete;
+ void *data;
+ struct crypto_tfm *tfm;
+
+ u32 flags;
+};
+
+struct ablkcipher_request {
+ struct crypto_async_request base;
+
+ unsigned int nbytes;
+
+ void *info;
+
+ struct scatterlist *src;
+ struct scatterlist *dst;
+
+ void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
struct blkcipher_desc {
struct crypto_blkcipher *tfm;
void *info;
@@ -116,6 +144,19 @@ struct hash_desc {
* Algorithms: modular crypto algorithm implementations, managed
* via crypto_register_alg() and crypto_unregister_alg().
*/
+struct ablkcipher_alg {
+ int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int (*encrypt)(struct ablkcipher_request *req);
+ int (*decrypt)(struct ablkcipher_request *req);
+
+ struct crypto_queue *queue;
+
+ unsigned int min_keysize;
+ unsigned int max_keysize;
+ unsigned int ivsize;
+};
+
struct blkcipher_alg {
int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen);
@@ -170,6 +211,7 @@ struct compress_alg {
unsigned int slen, u8 *dst, unsigned int *dlen);
};
+#define cra_ablkcipher cra_u.ablkcipher
#define cra_blkcipher cra_u.blkcipher
#define cra_cipher cra_u.cipher
#define cra_digest cra_u.digest
@@ -194,6 +236,7 @@ struct crypto_alg {
const struct crypto_type *cra_type;
union {
+ struct ablkcipher_alg ablkcipher;
struct blkcipher_alg blkcipher;
struct cipher_alg cipher;
struct digest_alg digest;
@@ -232,6 +275,15 @@ static inline int crypto_has_alg(const char *name, u32 type, u32 mask)
* crypto_free_*(), as well as the various helpers below.
*/
+struct ablkcipher_tfm {
+ int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+ unsigned int keylen);
+ int (*encrypt)(struct ablkcipher_request *req);
+ int (*decrypt)(struct ablkcipher_request *req);
+ unsigned int ivsize;
+ unsigned int reqsize;
+};
+
struct blkcipher_tfm {
void *iv;
int (*setkey)(struct crypto_tfm *tfm, const u8 *key,
@@ -290,6 +342,7 @@ struct compress_tfm {
u8 *dst, unsigned int *dlen);
};
+#define crt_ablkcipher crt_u.ablkcipher
#define crt_blkcipher crt_u.blkcipher
#define crt_cipher crt_u.cipher
#define crt_hash crt_u.hash
@@ -300,6 +353,7 @@ struct crypto_tfm {
u32 crt_flags;
union {
+ struct ablkcipher_tfm ablkcipher;
struct blkcipher_tfm blkcipher;
struct cipher_tfm cipher;
struct hash_tfm hash;
@@ -311,6 +365,10 @@ struct crypto_tfm {
void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
};
+struct crypto_ablkcipher {
+ struct crypto_tfm base;
+};
+
struct crypto_blkcipher {
struct crypto_tfm base;
};
@@ -330,12 +388,21 @@ struct crypto_hash {
enum {
CRYPTOA_UNSPEC,
CRYPTOA_ALG,
+ CRYPTOA_TYPE,
+ __CRYPTOA_MAX,
};
+#define CRYPTOA_MAX (__CRYPTOA_MAX - 1)
+
struct crypto_attr_alg {
char name[CRYPTO_MAX_ALG_NAME];
};
+struct crypto_attr_type {
+ u32 type;
+ u32 mask;
+};
+
/*
* Transform user interface.
*/
@@ -411,6 +478,167 @@ static inline unsigned int crypto_tfm_ctx_alignment(void)
/*
* API wrappers.
*/
+static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast(
+ struct crypto_tfm *tfm)
+{
+ return (struct crypto_ablkcipher *)tfm;
+}
+
+static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher(
+ const char *alg_name, u32 type, u32 mask)
+{
+ type &= ~CRYPTO_ALG_TYPE_MASK;
+ type |= CRYPTO_ALG_TYPE_BLKCIPHER;
+ mask |= CRYPTO_ALG_TYPE_MASK;
+
+ return __crypto_ablkcipher_cast(
+ crypto_alloc_base(alg_name, type, mask));
+}
+
+static inline struct crypto_tfm *crypto_ablkcipher_tfm(
+ struct crypto_ablkcipher *tfm)
+{
+ return &tfm->base;
+}
+
+static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm)
+{
+ crypto_free_tfm(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline int crypto_has_ablkcipher(const char *alg_name, u32 type,
+ u32 mask)
+{
+ type &= ~CRYPTO_ALG_TYPE_MASK;
+ type |= CRYPTO_ALG_TYPE_BLKCIPHER;
+ mask |= CRYPTO_ALG_TYPE_MASK;
+
+ return crypto_has_alg(alg_name, type, mask);
+}
+
+static inline struct ablkcipher_tfm *crypto_ablkcipher_crt(
+ struct crypto_ablkcipher *tfm)
+{
+ return &crypto_ablkcipher_tfm(tfm)->crt_ablkcipher;
+}
+
+static inline unsigned int crypto_ablkcipher_ivsize(
+ struct crypto_ablkcipher *tfm)
+{
+ return crypto_ablkcipher_crt(tfm)->ivsize;
+}
+
+static inline unsigned int crypto_ablkcipher_blocksize(
+ struct crypto_ablkcipher *tfm)
+{
+ return crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline unsigned int crypto_ablkcipher_alignmask(
+ struct crypto_ablkcipher *tfm)
+{
+ return crypto_tfm_alg_alignmask(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline u32 crypto_ablkcipher_get_flags(struct crypto_ablkcipher *tfm)
+{
+ return crypto_tfm_get_flags(crypto_ablkcipher_tfm(tfm));
+}
+
+static inline void crypto_ablkcipher_set_flags(struct crypto_ablkcipher *tfm,
+ u32 flags)
+{
+ crypto_tfm_set_flags(crypto_ablkcipher_tfm(tfm), flags);
+}
+
+static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm,
+ u32 flags)
+{
+ crypto_tfm_clear_flags(crypto_ablkcipher_tfm(tfm), flags);
+}
+
+static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen);
+}
+
+static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm(
+ struct ablkcipher_request *req)
+{
+ return __crypto_ablkcipher_cast(req->base.tfm);
+}
+
+static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+ struct ablkcipher_tfm *crt =
+ crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
+ return crt->encrypt(req);
+}
+
+static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+ struct ablkcipher_tfm *crt =
+ crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req));
+ return crt->decrypt(req);
+}
+
+static inline int crypto_ablkcipher_reqsize(struct crypto_ablkcipher *tfm)
+{
+ return crypto_ablkcipher_crt(tfm)->reqsize;
+}
+
+static inline void ablkcipher_request_set_tfm(
+ struct ablkcipher_request *req, struct crypto_ablkcipher *tfm)
+{
+ req->base.tfm = crypto_ablkcipher_tfm(tfm);
+}
+
+static inline struct ablkcipher_request *ablkcipher_request_cast(
+ struct crypto_async_request *req)
+{
+ return container_of(req, struct ablkcipher_request, base);
+}
+
+static inline struct ablkcipher_request *ablkcipher_request_alloc(
+ struct crypto_ablkcipher *tfm, gfp_t gfp)
+{
+ struct ablkcipher_request *req;
+
+ req = kmalloc(sizeof(struct ablkcipher_request) +
+ crypto_ablkcipher_reqsize(tfm), gfp);
+
+ if (likely(req))
+ ablkcipher_request_set_tfm(req, tfm);
+
+ return req;
+}
+
+static inline void ablkcipher_request_free(struct ablkcipher_request *req)
+{
+ kfree(req);
+}
+
+static inline void ablkcipher_request_set_callback(
+ struct ablkcipher_request *req,
+ u32 flags, crypto_completion_t complete, void *data)
+{
+ req->base.complete = complete;
+ req->base.data = data;
+ req->base.flags = flags;
+}
+
+static inline void ablkcipher_request_set_crypt(
+ struct ablkcipher_request *req,
+ struct scatterlist *src, struct scatterlist *dst,
+ unsigned int nbytes, void *iv)
+{
+ req->src = src;
+ req->dst = dst;
+ req->nbytes = nbytes;
+ req->info = iv;
+}
+
static inline struct crypto_blkcipher *__crypto_blkcipher_cast(
struct crypto_tfm *tfm)
{
@@ -427,9 +655,9 @@ static inline struct crypto_blkcipher *crypto_blkcipher_cast(
static inline struct crypto_blkcipher *crypto_alloc_blkcipher(
const char *alg_name, u32 type, u32 mask)
{
- type &= ~CRYPTO_ALG_TYPE_MASK;
+ type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
type |= CRYPTO_ALG_TYPE_BLKCIPHER;
- mask |= CRYPTO_ALG_TYPE_MASK;
+ mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask));
}
@@ -447,9 +675,9 @@ static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm)
static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask)
{
- type &= ~CRYPTO_ALG_TYPE_MASK;
+ type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
type |= CRYPTO_ALG_TYPE_BLKCIPHER;
- mask |= CRYPTO_ALG_TYPE_MASK;
+ mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC;
return crypto_has_alg(alg_name, type, mask);
}
diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h
index 46d8254c1a7..72aa00cc4b2 100644
--- a/include/linux/cyclades.h
+++ b/include/linux/cyclades.h
@@ -67,6 +67,8 @@
#ifndef _LINUX_CYCLADES_H
#define _LINUX_CYCLADES_H
+#include <linux/types.h>
+
struct cyclades_monitor {
unsigned long int_count;
unsigned long char_count;
@@ -108,7 +110,6 @@ struct cyclades_idle_stats {
#define CYZSETPOLLCYCLE 0x43590e
#define CYZGETPOLLCYCLE 0x43590f
#define CYGETCD1400VER 0x435910
-#define CYGETCARDINFO 0x435911
#define CYSETWAIT 0x435912
#define CYGETWAIT 0x435913
@@ -149,14 +150,12 @@ struct CYZ_BOOT_CTRL {
* architectures and compilers.
*/
-#if defined(__alpha__)
-typedef unsigned long ucdouble; /* 64 bits, unsigned */
-typedef unsigned int uclong; /* 32 bits, unsigned */
-#else
-typedef unsigned long uclong; /* 32 bits, unsigned */
-#endif
-typedef unsigned short ucshort; /* 16 bits, unsigned */
-typedef unsigned char ucchar; /* 8 bits, unsigned */
+#include <asm/types.h>
+
+typedef __u64 ucdouble; /* 64 bits, unsigned */
+typedef __u32 uclong; /* 32 bits, unsigned */
+typedef __u16 ucshort; /* 16 bits, unsigned */
+typedef __u8 ucchar; /* 8 bits, unsigned */
/*
* Memory Window Sizes
@@ -174,24 +173,24 @@ typedef unsigned char ucchar; /* 8 bits, unsigned */
*/
struct CUSTOM_REG {
- uclong fpga_id; /* FPGA Identification Register */
- uclong fpga_version; /* FPGA Version Number Register */
- uclong cpu_start; /* CPU start Register (write) */
- uclong cpu_stop; /* CPU stop Register (write) */
- uclong misc_reg; /* Miscelaneous Register */
- uclong idt_mode; /* IDT mode Register */
- uclong uart_irq_status; /* UART IRQ status Register */
- uclong clear_timer0_irq; /* Clear timer interrupt Register */
- uclong clear_timer1_irq; /* Clear timer interrupt Register */
- uclong clear_timer2_irq; /* Clear timer interrupt Register */
- uclong test_register; /* Test Register */
- uclong test_count; /* Test Count Register */
- uclong timer_select; /* Timer select register */
- uclong pr_uart_irq_status; /* Prioritized UART IRQ stat Reg */
- uclong ram_wait_state; /* RAM wait-state Register */
- uclong uart_wait_state; /* UART wait-state Register */
- uclong timer_wait_state; /* timer wait-state Register */
- uclong ack_wait_state; /* ACK wait State Register */
+ __u32 fpga_id; /* FPGA Identification Register */
+ __u32 fpga_version; /* FPGA Version Number Register */
+ __u32 cpu_start; /* CPU start Register (write) */
+ __u32 cpu_stop; /* CPU stop Register (write) */
+ __u32 misc_reg; /* Miscelaneous Register */
+ __u32 idt_mode; /* IDT mode Register */
+ __u32 uart_irq_status; /* UART IRQ status Register */
+ __u32 clear_timer0_irq; /* Clear timer interrupt Register */
+ __u32 clear_timer1_irq; /* Clear timer interrupt Register */
+ __u32 clear_timer2_irq; /* Clear timer interrupt Register */
+ __u32 test_register; /* Test Register */
+ __u32 test_count; /* Test Count Register */
+ __u32 timer_select; /* Timer select register */
+ __u32 pr_uart_irq_status; /* Prioritized UART IRQ stat Reg */
+ __u32 ram_wait_state; /* RAM wait-state Register */
+ __u32 uart_wait_state; /* UART wait-state Register */
+ __u32 timer_wait_state; /* timer wait-state Register */
+ __u32 ack_wait_state; /* ACK wait State Register */
};
/*
@@ -201,34 +200,34 @@ struct CUSTOM_REG {
*/
struct RUNTIME_9060 {
- uclong loc_addr_range; /* 00h - Local Address Range */
- uclong loc_addr_base; /* 04h - Local Address Base */
- uclong loc_arbitr; /* 08h - Local Arbitration */
- uclong endian_descr; /* 0Ch - Big/Little Endian Descriptor */
- uclong loc_rom_range; /* 10h - Local ROM Range */
- uclong loc_rom_base; /* 14h - Local ROM Base */
- uclong loc_bus_descr; /* 18h - Local Bus descriptor */
- uclong loc_range_mst; /* 1Ch - Local Range for Master to PCI */
- uclong loc_base_mst; /* 20h - Local Base for Master PCI */
- uclong loc_range_io; /* 24h - Local Range for Master IO */
- uclong pci_base_mst; /* 28h - PCI Base for Master PCI */
- uclong pci_conf_io; /* 2Ch - PCI configuration for Master IO */
- uclong filler1; /* 30h */
- uclong filler2; /* 34h */
- uclong filler3; /* 38h */
- uclong filler4; /* 3Ch */
- uclong mail_box_0; /* 40h - Mail Box 0 */
- uclong mail_box_1; /* 44h - Mail Box 1 */
- uclong mail_box_2; /* 48h - Mail Box 2 */
- uclong mail_box_3; /* 4Ch - Mail Box 3 */
- uclong filler5; /* 50h */
- uclong filler6; /* 54h */
- uclong filler7; /* 58h */
- uclong filler8; /* 5Ch */
- uclong pci_doorbell; /* 60h - PCI to Local Doorbell */
- uclong loc_doorbell; /* 64h - Local to PCI Doorbell */
- uclong intr_ctrl_stat; /* 68h - Interrupt Control/Status */
- uclong init_ctrl; /* 6Ch - EEPROM control, Init Control, etc */
+ __u32 loc_addr_range; /* 00h - Local Address Range */
+ __u32 loc_addr_base; /* 04h - Local Address Base */
+ __u32 loc_arbitr; /* 08h - Local Arbitration */
+ __u32 endian_descr; /* 0Ch - Big/Little Endian Descriptor */
+ __u32 loc_rom_range; /* 10h - Local ROM Range */
+ __u32 loc_rom_base; /* 14h - Local ROM Base */
+ __u32 loc_bus_descr; /* 18h - Local Bus descriptor */
+ __u32 loc_range_mst; /* 1Ch - Local Range for Master to PCI */
+ __u32 loc_base_mst; /* 20h - Local Base for Master PCI */
+ __u32 loc_range_io; /* 24h - Local Range for Master IO */
+ __u32 pci_base_mst; /* 28h - PCI Base for Master PCI */
+ __u32 pci_conf_io; /* 2Ch - PCI configuration for Master IO */
+ __u32 filler1; /* 30h */
+ __u32 filler2; /* 34h */
+ __u32 filler3; /* 38h */
+ __u32 filler4; /* 3Ch */
+ __u32 mail_box_0; /* 40h - Mail Box 0 */
+ __u32 mail_box_1; /* 44h - Mail Box 1 */
+ __u32 mail_box_2; /* 48h - Mail Box 2 */
+ __u32 mail_box_3; /* 4Ch - Mail Box 3 */
+ __u32 filler5; /* 50h */
+ __u32 filler6; /* 54h */
+ __u32 filler7; /* 58h */
+ __u32 filler8; /* 5Ch */
+ __u32 pci_doorbell; /* 60h - PCI to Local Doorbell */
+ __u32 loc_doorbell; /* 64h - Local to PCI Doorbell */
+ __u32 intr_ctrl_stat; /* 68h - Interrupt Control/Status */
+ __u32 init_ctrl; /* 6Ch - EEPROM control, Init Control, etc */
};
/* Values for the Local Base Address re-map register */
@@ -270,8 +269,8 @@ struct RUNTIME_9060 {
#define ZF_TINACT ZF_TINACT_DEF
struct FIRM_ID {
- uclong signature; /* ZFIRM/U signature */
- uclong zfwctrl_addr; /* pointer to ZFW_CTRL structure */
+ __u32 signature; /* ZFIRM/U signature */
+ __u32 zfwctrl_addr; /* pointer to ZFW_CTRL structure */
};
/* Op. System id */
@@ -408,24 +407,24 @@ struct FIRM_ID {
*/
struct CH_CTRL {
- uclong op_mode; /* operation mode */
- uclong intr_enable; /* interrupt masking */
- uclong sw_flow; /* SW flow control */
- uclong flow_status; /* output flow status */
- uclong comm_baud; /* baud rate - numerically specified */
- uclong comm_parity; /* parity */
- uclong comm_data_l; /* data length/stop */
- uclong comm_flags; /* other flags */
- uclong hw_flow; /* HW flow control */
- uclong rs_control; /* RS-232 outputs */
- uclong rs_status; /* RS-232 inputs */
- uclong flow_xon; /* xon char */
- uclong flow_xoff; /* xoff char */
- uclong hw_overflow; /* hw overflow counter */
- uclong sw_overflow; /* sw overflow counter */
- uclong comm_error; /* frame/parity error counter */
- uclong ichar;
- uclong filler[7];
+ __u32 op_mode; /* operation mode */
+ __u32 intr_enable; /* interrupt masking */
+ __u32 sw_flow; /* SW flow control */
+ __u32 flow_status; /* output flow status */
+ __u32 comm_baud; /* baud rate - numerically specified */
+ __u32 comm_parity; /* parity */
+ __u32 comm_data_l; /* data length/stop */
+ __u32 comm_flags; /* other flags */
+ __u32 hw_flow; /* HW flow control */
+ __u32 rs_control; /* RS-232 outputs */
+ __u32 rs_status; /* RS-232 inputs */
+ __u32 flow_xon; /* xon char */
+ __u32 flow_xoff; /* xoff char */
+ __u32 hw_overflow; /* hw overflow counter */
+ __u32 sw_overflow; /* sw overflow counter */
+ __u32 comm_error; /* frame/parity error counter */
+ __u32 ichar;
+ __u32 filler[7];
};
@@ -435,18 +434,18 @@ struct CH_CTRL {
*/
struct BUF_CTRL {
- uclong flag_dma; /* buffers are in Host memory */
- uclong tx_bufaddr; /* address of the tx buffer */
- uclong tx_bufsize; /* tx buffer size */
- uclong tx_threshold; /* tx low water mark */
- uclong tx_get; /* tail index tx buf */
- uclong tx_put; /* head index tx buf */
- uclong rx_bufaddr; /* address of the rx buffer */
- uclong rx_bufsize; /* rx buffer size */
- uclong rx_threshold; /* rx high water mark */
- uclong rx_get; /* tail index rx buf */
- uclong rx_put; /* head index rx buf */
- uclong filler[5]; /* filler to align structures */
+ __u32 flag_dma; /* buffers are in Host memory */
+ __u32 tx_bufaddr; /* address of the tx buffer */
+ __u32 tx_bufsize; /* tx buffer size */
+ __u32 tx_threshold; /* tx low water mark */
+ __u32 tx_get; /* tail index tx buf */
+ __u32 tx_put; /* head index tx buf */
+ __u32 rx_bufaddr; /* address of the rx buffer */
+ __u32 rx_bufsize; /* rx buffer size */
+ __u32 rx_threshold; /* rx high water mark */
+ __u32 rx_get; /* tail index rx buf */
+ __u32 rx_put; /* head index rx buf */
+ __u32 filler[5]; /* filler to align structures */
};
/*
@@ -457,27 +456,27 @@ struct BUF_CTRL {
struct BOARD_CTRL {
/* static info provided by the on-board CPU */
- uclong n_channel; /* number of channels */
- uclong fw_version; /* firmware version */
+ __u32 n_channel; /* number of channels */
+ __u32 fw_version; /* firmware version */
/* static info provided by the driver */
- uclong op_system; /* op_system id */
- uclong dr_version; /* driver version */
+ __u32 op_system; /* op_system id */
+ __u32 dr_version; /* driver version */
/* board control area */
- uclong inactivity; /* inactivity control */
+ __u32 inactivity; /* inactivity control */
/* host to FW commands */
- uclong hcmd_channel; /* channel number */
- uclong hcmd_param; /* pointer to parameters */
+ __u32 hcmd_channel; /* channel number */
+ __u32 hcmd_param; /* pointer to parameters */
/* FW to Host commands */
- uclong fwcmd_channel; /* channel number */
- uclong fwcmd_param; /* pointer to parameters */
- uclong zf_int_queue_addr; /* offset for INT_QUEUE structure */
+ __u32 fwcmd_channel; /* channel number */
+ __u32 fwcmd_param; /* pointer to parameters */
+ __u32 zf_int_queue_addr; /* offset for INT_QUEUE structure */
/* filler so the structures are aligned */
- uclong filler[6];
+ __u32 filler[6];
};
/* Host Interrupt Queue */
@@ -506,11 +505,10 @@ struct ZFW_CTRL {
/****************** ****************** *******************/
#endif
+#ifdef __KERNEL__
+
/* Per card data structure */
-struct resource;
struct cyclades_card {
- unsigned long base_phys;
- unsigned long ctl_phys;
void __iomem *base_addr;
void __iomem *ctl_addr;
int irq;
@@ -519,33 +517,18 @@ struct cyclades_card {
int nports; /* Number of ports in the card */
int bus_index; /* address shift - 0 for ISA, 1 for PCI */
int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */
- struct pci_dev *pdev;
-#ifdef __KERNEL__
spinlock_t card_lock;
-#else
- unsigned long filler;
-#endif
+ struct cyclades_port *ports;
};
-struct cyclades_chip {
- int filler;
-};
-
-
-#ifdef __KERNEL__
-
/***************************************
* Memory access functions/macros *
* (required to support Alpha systems) *
***************************************/
-#define cy_writeb(port,val) {writeb((val),(port)); mb();}
-#define cy_writew(port,val) {writew((val),(port)); mb();}
-#define cy_writel(port,val) {writel((val),(port)); mb();}
-
-#define cy_readb(port) readb(port)
-#define cy_readw(port) readw(port)
-#define cy_readl(port) readl(port)
+#define cy_writeb(port,val) do { writeb((val), (port)); mb(); } while (0)
+#define cy_writew(port,val) do { writew((val), (port)); mb(); } while (0)
+#define cy_writel(port,val) do { writel((val), (port)); mb(); } while (0)
/*
* Statistics counters
@@ -567,7 +550,7 @@ struct cyclades_icount {
struct cyclades_port {
int magic;
- int card;
+ struct cyclades_card *card;
int line;
int flags; /* defined in tty.h */
int type; /* UART type */
@@ -587,7 +570,6 @@ struct cyclades_port {
int close_delay;
unsigned short closing_wait;
unsigned long event;
- unsigned long last_active;
int count; /* # of fd on device */
int breakon;
int breakoff;
@@ -598,7 +580,6 @@ struct cyclades_port {
int xmit_cnt;
int default_threshold;
int default_timeout;
- unsigned long jiffies[3];
unsigned long rflush_count;
struct cyclades_monitor mon;
struct cyclades_idle_stats idle_stats;
@@ -606,7 +587,7 @@ struct cyclades_port {
struct work_struct tqueue;
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
- wait_queue_head_t shutdown_wait;
+ struct completion shutdown_wait;
wait_queue_head_t delta_msr_wait;
int throttle;
};
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 63f64a9a5bf..aab53df4faf 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -133,6 +133,7 @@ struct dentry_operations {
int (*d_delete)(struct dentry *);
void (*d_release)(struct dentry *);
void (*d_iput)(struct dentry *, struct inode *);
+ char *(*d_dname)(struct dentry *, char *, int);
};
/* the dentry parameter passed to d_hash and d_compare is the parent
@@ -293,6 +294,11 @@ extern struct dentry * d_hash_and_lookup(struct dentry *, struct qstr *);
/* validate "insecure" dentry pointer */
extern int d_validate(struct dentry *, struct dentry *);
+/*
+ * helper function for dentry_operations.d_dname() members
+ */
+extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
+
extern char * d_path(struct dentry *, struct vfsmount *, char *, int);
/* Allocation counts.. */
diff --git a/include/linux/device.h b/include/linux/device.h
index a0cd2ced31a..2e1a2988b7e 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -53,7 +53,7 @@ struct bus_type {
const char * name;
struct module * owner;
- struct subsystem subsys;
+ struct kset subsys;
struct kset drivers;
struct kset devices;
struct klist klist_devices;
@@ -80,7 +80,6 @@ struct bus_type {
int (*resume)(struct device * dev);
unsigned int drivers_autoprobe:1;
- unsigned int multithread_probe:1;
};
extern int __must_check bus_register(struct bus_type * bus);
@@ -179,7 +178,7 @@ struct class {
const char * name;
struct module * owner;
- struct subsystem subsys;
+ struct kset subsys;
struct list_head children;
struct list_head devices;
struct list_head interfaces;
@@ -413,12 +412,13 @@ struct device {
struct klist_node knode_parent; /* node in sibling list */
struct klist_node knode_driver;
struct klist_node knode_bus;
- struct device * parent;
+ struct device *parent;
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct device_type *type;
unsigned is_registered:1;
+ unsigned uevent_suppress:1;
struct device_attribute uevent_attr;
struct device_attribute *devt_attr;
@@ -459,7 +459,6 @@ struct device {
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
struct attribute_group **groups; /* optional groups */
- int uevent_suppress;
void (*release)(struct device * dev);
};
@@ -559,8 +558,8 @@ extern void device_shutdown(void);
/* drivers/base/firmware.c */
-extern int __must_check firmware_register(struct subsystem *);
-extern void firmware_unregister(struct subsystem *);
+extern int __must_check firmware_register(struct kset *);
+extern void firmware_unregister(struct kset *);
/* debugging and troubleshooting/diagnostic helpers. */
extern const char *dev_driver_string(struct device *dev);
diff --git a/include/linux/display.h b/include/linux/display.h
new file mode 100644
index 00000000000..3bf70d63972
--- /dev/null
+++ b/include/linux/display.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2006 James Simmons <jsimmons@infradead.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef _LINUX_DISPLAY_H
+#define _LINUX_DISPLAY_H
+
+#include <linux/device.h>
+
+struct display_device;
+
+/* This structure defines all the properties of a Display. */
+struct display_driver {
+ int (*set_contrast)(struct display_device *, unsigned int);
+ int (*get_contrast)(struct display_device *);
+ void (*suspend)(struct display_device *, pm_message_t state);
+ void (*resume)(struct display_device *);
+ int (*probe)(struct display_device *, void *);
+ int (*remove)(struct display_device *);
+ int max_contrast;
+};
+
+struct display_device {
+ struct module *owner; /* Owner module */
+ struct display_driver *driver;
+ struct device *parent; /* This is the parent */
+ struct device *dev; /* This is this display device */
+ struct mutex lock;
+ void *priv_data;
+ char type[16];
+ char *name;
+ int idx;
+};
+
+extern struct display_device *display_device_register(struct display_driver *driver,
+ struct device *dev, void *devdata);
+extern void display_device_unregister(struct display_device *dev);
+
+extern int probe_edid(struct display_device *dev, void *devdata);
+
+#define to_display_device(obj) container_of(obj, struct display_device, class_dev)
+
+#endif
diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h
index 2a2dd189b9f..c2735cab2eb 100644
--- a/include/linux/dlm_device.h
+++ b/include/linux/dlm_device.h
@@ -19,7 +19,7 @@
/* Version of the device interface */
#define DLM_DEVICE_VERSION_MAJOR 5
-#define DLM_DEVICE_VERSION_MINOR 0
+#define DLM_DEVICE_VERSION_MINOR 1
#define DLM_DEVICE_VERSION_PATCH 0
/* struct passed to the lock write */
@@ -44,6 +44,11 @@ struct dlm_lspace_params {
char name[0];
};
+struct dlm_purge_params {
+ __u32 nodeid;
+ __u32 pid;
+};
+
struct dlm_write_request {
__u32 version[3];
__u8 cmd;
@@ -53,6 +58,7 @@ struct dlm_write_request {
union {
struct dlm_lock_params lock;
struct dlm_lspace_params lspace;
+ struct dlm_purge_params purge;
} i;
};
@@ -76,6 +82,7 @@ struct dlm_lock_result {
#define DLM_USER_QUERY 3
#define DLM_USER_CREATE_LOCKSPACE 4
#define DLM_USER_REMOVE_LOCKSPACE 5
+#define DLM_USER_PURGE 6
/* Arbitrary length restriction */
#define MAX_LS_NAME_LEN 64
diff --git a/include/linux/ds1wm.h b/include/linux/ds1wm.h
new file mode 100644
index 00000000000..31f6e3c427f
--- /dev/null
+++ b/include/linux/ds1wm.h
@@ -0,0 +1,11 @@
+/* platform data for the DS1WM driver */
+
+struct ds1wm_platform_data {
+ int bus_shift; /* number of shifts needed to calculate the
+ * offset between DS1WM registers;
+ * e.g. on h5xxx and h2200 this is 2
+ * (registers aligned to 4-byte boundaries),
+ * while on hx4700 this is 1 */
+ void (*enable)(struct platform_device *pdev);
+ void (*disable)(struct platform_device *pdev);
+};
diff --git a/include/linux/efi.h b/include/linux/efi.h
index f8ebd7c1ddb..0b9579a4cd4 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -213,7 +213,6 @@ typedef struct {
} efi_config_table_t;
#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
-#define EFI_SYSTEM_TABLE_REVISION ((1 << 16) | 00)
typedef struct {
efi_table_hdr_t hdr;
diff --git a/include/linux/elf-em.h b/include/linux/elf-em.h
index 666e0a5f00f..0311bad838b 100644
--- a/include/linux/elf-em.h
+++ b/include/linux/elf-em.h
@@ -30,6 +30,7 @@
#define EM_V850 87 /* NEC v850 */
#define EM_M32R 88 /* Renesas M32R */
#define EM_H8_300 46 /* Renesas H8/300,300H,H8S */
+#define EM_BLACKFIN 106 /* ADI Blackfin Processor */
#define EM_FRV 0x5441 /* Fujitsu FR-V */
#define EM_AVR32 0x18ad /* Atmel AVR32 */
diff --git a/include/linux/elf.h b/include/linux/elf.h
index 60713e6ea29..8b17ffe222c 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -83,6 +83,23 @@ typedef __s64 Elf64_Sxword;
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
+#define DT_ENCODING 32
+#define OLD_DT_LOOS 0x60000000
+#define DT_LOOS 0x6000000d
+#define DT_HIOS 0x6ffff000
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_VALRNGHI 0x6ffffdff
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_ADDRRNGHI 0x6ffffeff
+#define DT_VERSYM 0x6ffffff0
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+#define DT_FLAGS_1 0x6ffffffb
+#define DT_VERDEF 0x6ffffffc
+#define DT_VERDEFNUM 0x6ffffffd
+#define DT_VERNEED 0x6ffffffe
+#define DT_VERNEEDNUM 0x6fffffff
+#define OLD_DT_HIOS 0x6fffffff
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h
index 67396db141e..9a1e0674e56 100644
--- a/include/linux/elfnote.h
+++ b/include/linux/elfnote.h
@@ -39,12 +39,12 @@
* ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
*/
#define ELFNOTE(name, type, desctype, descdata) \
-.pushsection .note.name ; \
+.pushsection .note.name, "",@note ; \
.align 4 ; \
.long 2f - 1f /* namesz */ ; \
.long 4f - 3f /* descsz */ ; \
.long type ; \
-1:.asciz "name" ; \
+1:.asciz #name ; \
2:.align 4 ; \
3:desctype descdata ; \
4:.align 4 ; \
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 745c988359c..071c67abed8 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -71,6 +71,18 @@ static inline int is_multicast_ether_addr(const u8 *addr)
}
/**
+ * is_local_ether_addr - Determine if the Ethernet address is locally-assigned
+ * one (IEEE 802).
+ * @addr: Pointer to a six-byte array containing the Ethernet address
+ *
+ * Return true if the address is a local address.
+ */
+static inline int is_local_ether_addr(const u8 *addr)
+{
+ return (0x02 & addr[0]);
+}
+
+/**
* is_broadcast_ether_addr - Determine if the Ethernet address is broadcast
* @addr: Pointer to a six-byte array containing the Ethernet address
*
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index c6310aef5ab..f2d248f8cc9 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -434,6 +434,7 @@ struct ethtool_ops {
#define SUPPORTED_10000baseT_Full (1 << 12)
#define SUPPORTED_Pause (1 << 13)
#define SUPPORTED_Asym_Pause (1 << 14)
+#define SUPPORTED_2500baseX_Full (1 << 15)
/* Indicates what features are advertised by the interface. */
#define ADVERTISED_10baseT_Half (1 << 0)
@@ -451,6 +452,7 @@ struct ethtool_ops {
#define ADVERTISED_10000baseT_Full (1 << 12)
#define ADVERTISED_Pause (1 << 13)
#define ADVERTISED_Asym_Pause (1 << 14)
+#define ADVERTISED_2500baseX_Full (1 << 15)
/* The following are all involved in forcing a particular link
* mode for the device for setting things. When getting the
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 4eb18ac510a..ece49a804fe 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -824,6 +824,7 @@ extern int ext3_change_inode_journal_flag(struct inode *, int);
extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
extern void ext3_truncate (struct inode *);
extern void ext3_set_inode_flags(struct inode *);
+extern void ext3_get_inode_flags(struct ext3_inode_info *);
extern void ext3_set_aops(struct inode *inode);
/* ioctl.c */
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
index 4395e520674..7894dd0f3b7 100644
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -54,7 +54,7 @@ struct ext3_block_alloc_info {
/*
* Was i_next_alloc_goal in ext3_inode_info
* is the *physical* companion to i_next_alloc_block.
- * it the the physical block number of the block which was most-recentl
+ * it the physical block number of the block which was most-recentl
* allocated to this file. This give us the goal (target) for the next
* allocation when we detect linearly ascending requests.
*/
diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h
index bb42379cb7f..d5b177e5b39 100644
--- a/include/linux/ext4_fs_i.h
+++ b/include/linux/ext4_fs_i.h
@@ -52,7 +52,7 @@ struct ext4_block_alloc_info {
/*
* Was i_next_alloc_goal in ext4_inode_info
* is the *physical* companion to i_next_alloc_block.
- * it the the physical block number of the block which was most-recentl
+ * it the physical block number of the block which was most-recentl
* allocated to this file. This give us the goal (target) for the next
* allocation when we detect linearly ascending requests.
*/
diff --git a/include/linux/fb.h b/include/linux/fb.h
index be913ec8716..c654d0e9ce3 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -4,6 +4,8 @@
#include <asm/types.h>
#include <linux/i2c.h>
+struct dentry;
+
/* Definitions of frame buffers */
#define FB_MAJOR 29
@@ -525,12 +527,20 @@ struct fb_cursor_user {
#define FB_EVENT_MODE_CHANGE_ALL 0x0B
/* A software display blank change occured */
#define FB_EVENT_CONBLANK 0x0C
+/* Get drawing requirements */
+#define FB_EVENT_GET_REQ 0x0D
struct fb_event {
struct fb_info *info;
void *data;
};
+struct fb_blit_caps {
+ u32 x;
+ u32 y;
+ u32 len;
+ u32 flags;
+};
extern int fb_register_client(struct notifier_block *nb);
extern int fb_unregister_client(struct notifier_block *nb);
@@ -556,11 +566,25 @@ struct fb_pixmap {
u32 scan_align; /* alignment per scanline */
u32 access_align; /* alignment per read/write (bits) */
u32 flags; /* see FB_PIXMAP_* */
+ u32 blit_x; /* supported bit block dimensions (1-32)*/
+ u32 blit_y; /* Format: blit_x = 1 << (width - 1) */
+ /* blit_y = 1 << (height - 1) */
+ /* if 0, will be set to 0xffffffff (all)*/
/* access methods */
void (*writeio)(struct fb_info *info, void __iomem *dst, void *src, unsigned int size);
void (*readio) (struct fb_info *info, void *dst, void __iomem *src, unsigned int size);
};
+#ifdef CONFIG_FB_DEFERRED_IO
+struct fb_deferred_io {
+ /* delay between mkwrite and deferred handler */
+ unsigned long delay;
+ struct mutex lock; /* mutex that protects the page list */
+ struct list_head pagelist; /* list of touched pages */
+ /* callback */
+ void (*deferred_io)(struct fb_info *info, struct list_head *pagelist);
+};
+#endif
/*
* Frame buffer operations
@@ -579,8 +603,10 @@ struct fb_ops {
/* For framebuffers with strange non linear layouts or that do not
* work with normal memory mapped access
*/
- ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);
- ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
+ ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos);
+ ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos);
/* checks var and eventually tweaks it to something supported,
* DO NOT MODIFY PAR */
@@ -634,10 +660,13 @@ struct fb_ops {
/* restore saved state */
void (*fb_restore_state)(struct fb_info *info);
+
+ /* get capability given var */
+ void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
+ struct fb_var_screeninfo *var);
};
#ifdef CONFIG_FB_TILEBLITTING
-
#define FB_TILE_CURSOR_NONE 0
#define FB_TILE_CURSOR_UNDERLINE 1
#define FB_TILE_CURSOR_LOWER_THIRD 2
@@ -709,6 +738,8 @@ struct fb_tile_ops {
/* cursor */
void (*fb_tilecursor)(struct fb_info *info,
struct fb_tilecursor *cursor);
+ /* get maximum length of the tile map */
+ int (*fb_get_tilemax)(struct fb_info *info);
};
#endif /* CONFIG_FB_TILEBLITTING */
@@ -778,6 +809,10 @@ struct fb_info {
struct mutex bl_curve_mutex;
u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
+#ifdef CONFIG_FB_DEFERRED_IO
+ struct delayed_work deferred_work;
+ struct fb_deferred_io *fbdefio;
+#endif
struct fb_ops *fbops;
struct device *device; /* This is the parent */
@@ -833,7 +868,7 @@ struct fb_info {
#define fb_writeq sbus_writeq
#define fb_memset sbus_memset_io
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || (defined(__sh__) && !defined(__SH5__)) || defined(__powerpc__) || defined(__avr32__)
#define fb_readb __raw_readb
#define fb_readw __raw_readw
@@ -879,6 +914,16 @@ extern int fb_blank(struct fb_info *info, int blank);
extern void cfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
extern void cfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
extern void cfb_imageblit(struct fb_info *info, const struct fb_image *image);
+/*
+ * Drawing operations where framebuffer is in system RAM
+ */
+extern void sys_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+extern void sys_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+extern void sys_imageblit(struct fb_info *info, const struct fb_image *image);
+extern ssize_t fb_sys_read(struct fb_info *info, char __user *buf,
+ size_t count, loff_t *ppos);
+extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos);
/* drivers/video/fbmem.c */
extern int register_framebuffer(struct fb_info *fb_info);
@@ -913,6 +958,12 @@ static inline void __fb_pad_aligned_buffer(u8 *dst, u32 d_pitch,
}
}
+/* drivers/video/fb_defio.c */
+extern void fb_deferred_io_init(struct fb_info *info);
+extern void fb_deferred_io_cleanup(struct fb_info *info);
+extern int fb_deferred_io_fsync(struct file *file, struct dentry *dentry,
+ int datasync);
+
/* drivers/video/fbsysfs.c */
extern struct fb_info *framebuffer_alloc(size_t size, struct device *dev);
extern void framebuffer_release(struct fb_info *info);
diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h
index 996f5611cd5..40b93265d4b 100644
--- a/include/linux/fcntl.h
+++ b/include/linux/fcntl.h
@@ -3,6 +3,10 @@
#include <asm/fcntl.h>
+/* Cancel a blocking posix lock; internal use only until we expose an
+ * asynchronous lock api to userspace: */
+#define F_CANCELLK (F_LINUX_SPECIFIC_BASE+5)
+
#define F_SETLEASE (F_LINUX_SPECIFIC_BASE+0)
#define F_GETLEASE (F_LINUX_SPECIFIC_BASE+1)
diff --git a/include/linux/font.h b/include/linux/font.h
index 53b129f07f6..40a24ab41b3 100644
--- a/include/linux/font.h
+++ b/include/linux/font.h
@@ -49,7 +49,8 @@ extern const struct font_desc *find_font(const char *name);
/* Get the default font for a specific screen size */
-extern const struct font_desc *get_default_font(int xres, int yres);
+extern const struct font_desc *get_default_font(int xres, int yres,
+ u32 font_w, u32 font_h);
/* Max. length for the name of a predefined font */
#define MAX_FONT_NAME 32
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 095a9c9a64f..7cf0c54a46a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -30,6 +30,7 @@
#define SEEK_SET 0 /* seek relative to beginning of file */
#define SEEK_CUR 1 /* seek relative to current file position */
#define SEEK_END 2 /* seek relative to end of file */
+#define SEEK_MAX SEEK_END
/* And dynamically-tunable limits and defaults: */
struct files_stat_struct {
@@ -91,6 +92,7 @@ extern int dir_notify_enable;
/* public flags for file_system_type */
#define FS_REQUIRES_DEV 1
#define FS_BINARY_MOUNTDATA 2
+#define FS_HAS_SUBTYPE 4
#define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */
#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move()
* during rename() internally.
@@ -696,12 +698,13 @@ struct file_ra_state {
unsigned long size;
unsigned long flags; /* ra flags RA_FLAG_xxx*/
unsigned long cache_hit; /* cache hit count*/
- unsigned long prev_page; /* Cache last read() position */
+ unsigned long prev_index; /* Cache last read() position */
unsigned long ahead_start; /* Ahead window */
unsigned long ahead_size;
unsigned long ra_pages; /* Maximum readahead window */
unsigned long mmap_hit; /* Cache hit stat for mmap accesses */
unsigned long mmap_miss; /* Cache miss stat for mmap accesses */
+ unsigned int prev_offset; /* Offset where last read() ended in a page */
};
#define RA_FLAG_MISS 0x01 /* a cache miss occured against this file */
#define RA_FLAG_INCACHE 0x02 /* file is already in cache */
@@ -785,6 +788,7 @@ struct file_lock_operations {
struct lock_manager_operations {
int (*fl_compare_owner)(struct file_lock *, struct file_lock *);
void (*fl_notify)(struct file_lock *); /* unblock callback */
+ int (*fl_grant)(struct file_lock *, struct file_lock *, int);
void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
void (*fl_release_private)(struct file_lock *);
void (*fl_break)(struct file_lock *);
@@ -845,22 +849,19 @@ extern int fcntl_getlease(struct file *filp);
/* fs/sync.c */
extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
loff_t endbyte, unsigned int flags);
-static inline int do_sync_file_range(struct file *file, loff_t offset,
- loff_t endbyte, unsigned int flags)
-{
- return do_sync_mapping_range(file->f_mapping, offset, endbyte, flags);
-}
/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *);
-extern int posix_test_lock(struct file *, struct file_lock *, struct file_lock *);
-extern int posix_lock_file_conf(struct file *, struct file_lock *, struct file_lock *);
-extern int posix_lock_file(struct file *, struct file_lock *);
+extern int posix_test_lock(struct file *, struct file_lock *);
+extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file *, struct file_lock *);
+extern int vfs_test_lock(struct file *, struct file_lock *);
+extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
+extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time);
@@ -956,6 +957,12 @@ struct super_block {
/* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran;
+
+ /*
+ * Filesystem subtype. If non-empty the filesystem type field
+ * in /proc/mounts will be "type.subtype"
+ */
+ char *s_subtype;
};
extern struct timespec current_fs_time(struct super_block *sb);
@@ -1416,7 +1423,7 @@ extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
extern int vfs_statfs(struct dentry *, struct kstatfs *);
/* /sys/fs */
-extern struct subsystem fs_subsys;
+extern struct kset fs_subsys;
#define FLOCK_VERIFY_READ 1
#define FLOCK_VERIFY_WRITE 2
@@ -1731,6 +1738,8 @@ extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor
extern void do_generic_mapping_read(struct address_space *mapping,
struct file_ra_state *, struct file *,
loff_t *, read_descriptor_t *, read_actor_t);
+extern int generic_segment_checks(const struct iovec *iov,
+ unsigned long *nr_segs, size_t *count, int access_flags);
/* fs/splice.c */
extern ssize_t generic_file_splice_read(struct file *, loff_t *,
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index abb64c437f6..73710d61777 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -120,44 +120,5 @@ struct fsl_spi_platform_data {
u32 sysclk;
};
-/* Ethernet interface (phy management and speed)
-*/
-enum enet_interface {
- ENET_10_MII, /* 10 Base T, MII interface */
- ENET_10_RMII, /* 10 Base T, RMII interface */
- ENET_10_RGMII, /* 10 Base T, RGMII interface */
- ENET_100_MII, /* 100 Base T, MII interface */
- ENET_100_RMII, /* 100 Base T, RMII interface */
- ENET_100_RGMII, /* 100 Base T, RGMII interface */
- ENET_1000_GMII, /* 1000 Base T, GMII interface */
- ENET_1000_RGMII, /* 1000 Base T, RGMII interface */
- ENET_1000_TBI, /* 1000 Base T, TBI interface */
- ENET_1000_RTBI /* 1000 Base T, RTBI interface */
-};
-
-struct ucc_geth_platform_data {
- /* device specific information */
- u32 device_flags;
- u32 phy_reg_addr;
-
- /* board specific information */
- u32 board_flags;
- u8 rx_clock;
- u8 tx_clock;
- u32 phy_id;
- enum enet_interface phy_interface;
- u32 phy_interrupt;
- u8 mac_addr[6];
-};
-
-/* Flags related to UCC Gigabit Ethernet device features */
-#define FSL_UGETH_DEV_HAS_GIGABIT 0x00000001
-#define FSL_UGETH_DEV_HAS_COALESCE 0x00000002
-#define FSL_UGETH_DEV_HAS_RMON 0x00000004
-
-/* Flags in ucc_geth_platform_data */
-#define FSL_UGETH_BRD_HAS_PHY_INTR 0x00000001
- /* if not set use a timer */
-
#endif /* _FSL_DEVICE_H_ */
#endif /* __KERNEL__ */
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 3f153b4e156..899fc7f20ed 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -3,6 +3,8 @@
#include <linux/sched.h>
+union ktime;
+
/* Second argument to futex syscall */
@@ -15,6 +17,19 @@
#define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8
+#define FUTEX_CMP_REQUEUE_PI 9
+
+#define FUTEX_PRIVATE_FLAG 128
+#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG
+
+#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG)
+#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
/*
* Support for robust futexes: the kernel cleans up held futexes at
@@ -83,9 +98,14 @@ struct robust_list_head {
#define FUTEX_OWNER_DIED 0x40000000
/*
+ * Some processes have been requeued on this PI-futex
+ */
+#define FUTEX_WAITER_REQUEUED 0x20000000
+
+/*
* The rest of the robust-futex field is for the TID:
*/
-#define FUTEX_TID_MASK 0x3fffffff
+#define FUTEX_TID_MASK 0x0fffffff
/*
* This limit protects against a deliberately circular list.
@@ -94,12 +114,53 @@ struct robust_list_head {
#define ROBUST_LIST_LIMIT 2048
#ifdef __KERNEL__
-long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
u32 __user *uaddr2, u32 val2, u32 val3);
extern int
handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
+/*
+ * Futexes are matched on equal values of this key.
+ * The key type depends on whether it's a shared or private mapping.
+ * Don't rearrange members without looking at hash_futex().
+ *
+ * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
+ * We use the two low order bits of offset to tell what is the kind of key :
+ * 00 : Private process futex (PTHREAD_PROCESS_PRIVATE)
+ * (no reference on an inode or mm)
+ * 01 : Shared futex (PTHREAD_PROCESS_SHARED)
+ * mapped on a file (reference on the underlying inode)
+ * 10 : Shared futex (PTHREAD_PROCESS_SHARED)
+ * (but private mapping on an mm, and reference taken on it)
+*/
+
+#define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */
+#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */
+
+union futex_key {
+ u32 __user *uaddr;
+ struct {
+ unsigned long pgoff;
+ struct inode *inode;
+ int offset;
+ } shared;
+ struct {
+ unsigned long address;
+ struct mm_struct *mm;
+ int offset;
+ } private;
+ struct {
+ unsigned long word;
+ void *ptr;
+ int offset;
+ } both;
+};
+int get_futex_key(u32 __user *uaddr, struct rw_semaphore *shared,
+ union futex_key *key);
+void get_futex_key_refs(union futex_key *key);
+void drop_futex_key_refs(union futex_key *key);
+
#ifdef CONFIG_FUTEX
extern void exit_robust_list(struct task_struct *curr);
extern void exit_pi_state_list(struct task_struct *curr);
diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h
index 80764f40be7..886f5faa08c 100644
--- a/include/linux/generic_acl.h
+++ b/include/linux/generic_acl.h
@@ -1,5 +1,5 @@
/*
- * fs/generic_acl.c
+ * include/linux/generic_acl.h
*
* (C) 2005 Andreas Gruenbacher <agruen@suse.de>
*
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 2c65da7cabb..f589559cf07 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -413,6 +413,7 @@ char *disk_name (struct gendisk *hd, int part, char *buf);
extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev);
extern void add_partition(struct gendisk *, int, sector_t, sector_t, int);
extern void delete_partition(struct gendisk *, int);
+extern void printk_all_partitions(void);
extern struct gendisk *alloc_disk_node(int minors, int node_id);
extern struct gendisk *alloc_disk(int minors);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 2a7d15bcde4..0d2ef0b082a 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -40,7 +40,6 @@ struct vm_area_struct;
#define __GFP_REPEAT ((__force gfp_t)0x400u) /* Retry the allocation. Might fail */
#define __GFP_NOFAIL ((__force gfp_t)0x800u) /* Retry for ever. Cannot fail */
#define __GFP_NORETRY ((__force gfp_t)0x1000u)/* Do not retry. Might fail */
-#define __GFP_NO_GROW ((__force gfp_t)0x2000u)/* Slab internal usage */
#define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */
#define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */
#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
@@ -53,7 +52,7 @@ struct vm_area_struct;
/* if you forget to add the bitmask here kernel will crash, period */
#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
- __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
+ __GFP_NOFAIL|__GFP_NORETRY|__GFP_COMP| \
__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)
/* This equals 0, but use constants in case they ever change */
@@ -177,10 +176,6 @@ extern void FASTCALL(free_cold_page(struct page *page));
#define free_page(addr) free_pages((addr),0)
void page_alloc_init(void);
-#ifdef CONFIG_NUMA
-void drain_node_pages(int node);
-#else
-static inline void drain_node_pages(int node) { };
-#endif
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
#endif /* __LINUX_GFP_H */
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 2b217c7b931..265d17830a0 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -3,10 +3,11 @@
struct gpio_keys_button {
/* Configuration parameters */
- int keycode;
+ int code; /* input event code (KEY_*, SW_*) */
int gpio;
int active_low;
char *desc;
+ int type; /* input event type (EV_KEY, EV_SW) */
};
struct gpio_keys_platform_data {
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index 0fe562af9c8..db390c511ad 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -43,8 +43,7 @@ struct hdlc_proto {
void (*stop)(struct net_device *dev); /* if open & !DCD */
void (*detach)(struct net_device *dev);
int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
- unsigned short (*type_trans)(struct sk_buff *skb,
- struct net_device *dev);
+ __be16 (*type_trans)(struct sk_buff *skb, struct net_device *dev);
struct module *module;
struct hdlc_proto *next; /* next protocol in the list */
};
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 8c97d4d3fdb..37076b116ed 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -247,6 +247,11 @@ struct hid_item {
* HID device quirks.
*/
+/*
+ * Increase this if you need to configure more HID quirks at module load time
+ */
+#define MAX_USBHID_BOOT_QUIRKS 4
+
#define HID_QUIRK_INVERT 0x00000001
#define HID_QUIRK_NOTOUCH 0x00000002
#define HID_QUIRK_IGNORE 0x00000004
@@ -267,8 +272,9 @@ struct hid_item {
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00020000
#define HID_QUIRK_IGNORE_MOUSE 0x00040000
#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00080000
-#define HID_QUIRK_LOGITECH_S510_DESCRIPTOR 0x00100000
+#define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000
+#define HID_QUIRK_RESET_LEDS 0x00400000
/*
* This is the global environment of the parser. This information is
@@ -494,6 +500,12 @@ void hid_output_report(struct hid_report *report, __u8 *data);
void hid_free_device(struct hid_device *device);
struct hid_device *hid_parse_report(__u8 *start, unsigned size);
+/* HID quirks API */
+u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
+int usbhid_modify_dquirk(const u16 idVendor, const u16 idProduct, const u32 quirks);
+int usbhid_quirks_init(char **quirks_param);
+void usbhid_quirks_exit(void);
+
#ifdef CONFIG_HID_FF
int hid_ff_init(struct hid_device *hid);
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 645d440807c..98e2cce996a 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -27,6 +27,8 @@ static inline void flush_kernel_dcache_page(struct page *page)
unsigned int nr_free_highpages(void);
extern unsigned long totalhigh_pages;
+void kmap_flush_unused(void);
+
#else /* CONFIG_HIGHMEM */
static inline unsigned int nr_free_highpages(void) { return 0; }
@@ -42,11 +44,20 @@ static inline void *kmap(struct page *page)
#define kunmap(page) do { (void) (page); } while (0)
-#define kmap_atomic(page, idx) \
- ({ pagefault_disable(); page_address(page); })
+#include <asm/kmap_types.h>
+
+static inline void *kmap_atomic(struct page *page, enum km_type idx)
+{
+ pagefault_disable();
+ return page_address(page);
+}
+#define kmap_atomic_prot(page, idx, prot) kmap_atomic(page, idx)
+
#define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0)
#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
+
+#define kmap_flush_unused() do {} while(0)
#endif
#endif /* CONFIG_HIGHMEM */
@@ -83,17 +94,26 @@ static inline void clear_highpage(struct page *page)
/*
* Same but also flushes aliased cache contents to RAM.
+ *
+ * This must be a macro because KM_USER0 and friends aren't defined if
+ * !CONFIG_HIGHMEM
*/
-static inline void memclear_highpage_flush(struct page *page, unsigned int offset, unsigned int size)
+#define zero_user_page(page, offset, size, km_type) \
+ do { \
+ void *kaddr; \
+ \
+ BUG_ON((offset) + (size) > PAGE_SIZE); \
+ \
+ kaddr = kmap_atomic(page, km_type); \
+ memset((char *)kaddr + (offset), 0, (size)); \
+ flush_dcache_page(page); \
+ kunmap_atomic(kaddr, (km_type)); \
+ } while (0)
+
+static inline void __deprecated memclear_highpage_flush(struct page *page,
+ unsigned int offset, unsigned int size)
{
- void *kaddr;
-
- BUG_ON(offset + size > PAGE_SIZE);
-
- kaddr = kmap_atomic(page, KM_USER0);
- memset((char *)kaddr + offset, 0, size);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, size, KM_USER0);
}
#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE
diff --git a/include/linux/hp_sdc.h b/include/linux/hp_sdc.h
index debd7151531..9db3d454887 100644
--- a/include/linux/hp_sdc.h
+++ b/include/linux/hp_sdc.h
@@ -71,6 +71,7 @@ typedef struct {
struct semaphore *semaphore; /* Semaphore to sleep on. */
} act;
} hp_sdc_transaction;
+int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
int hp_sdc_enqueue_transaction(hp_sdc_transaction *this);
int hp_sdc_dequeue_transaction(hp_sdc_transaction *this);
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 3f3e7a648da..b4570b62ab8 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -189,4 +189,10 @@ static inline void set_file_hugepages(struct file *file)
#endif /* !CONFIG_HUGETLBFS */
+#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff,
+ unsigned long flags);
+#endif /* HAVE_ARCH_HUGETLB_UNMAPPED_AREA */
+
#endif /* _LINUX_HUGETLB_H */
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index 937da70cb4c..111334f5b92 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -18,7 +18,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
#ifndef _LINUX_I2C_ALGO_BIT_H
@@ -38,11 +38,14 @@ struct i2c_algo_bit_data {
int (*getscl) (void *data);
/* local settings */
- int udelay; /* half-clock-cycle time in microsecs */
- /* i.e. clock is (500 / udelay) KHz */
+ int udelay; /* half clock cycle time in us,
+ minimum 2 us for fast-mode I2C,
+ minimum 5 us for standard-mode I2C and SMBus,
+ maximum 50 us for SMBus */
int timeout; /* in jiffies */
};
int i2c_bit_add_bus(struct i2c_adapter *);
+int i2c_bit_add_numbered_bus(struct i2c_adapter *);
#endif /* _LINUX_I2C_ALGO_BIT_H */
diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
index 994eb86f882..77afbb60fd1 100644
--- a/include/linux/i2c-algo-pcf.h
+++ b/include/linux/i2c-algo-pcf.h
@@ -19,7 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
+/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
Frodo Looijaard <frodol@dds.nl> */
#ifndef _LINUX_I2C_ALGO_PCF_H
diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h
new file mode 100644
index 00000000000..c1bcb1f1d73
--- /dev/null
+++ b/include/linux/i2c-gpio.h
@@ -0,0 +1,38 @@
+/*
+ * i2c-gpio interface to platform code
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * 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.
+ */
+#ifndef _LINUX_I2C_GPIO_H
+#define _LINUX_I2C_GPIO_H
+
+/**
+ * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio
+ * @sda_pin: GPIO pin ID to use for SDA
+ * @scl_pin: GPIO pin ID to use for SCL
+ * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz
+ * @timeout: clock stretching timeout in jiffies. If the slave keeps
+ * SCL low for longer than this, the transfer will time out.
+ * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin
+ * isn't actively driven high when setting the output value high.
+ * gpio_get_value() must return the actual pin state even if the
+ * pin is configured as an output.
+ * @scl_is_open_drain: SCL is set up as open drain. Same requirements
+ * as for sda_is_open_drain apply.
+ * @scl_is_output_only: SCL output drivers cannot be turned off.
+ */
+struct i2c_gpio_platform_data {
+ unsigned int sda_pin;
+ unsigned int scl_pin;
+ int udelay;
+ int timeout;
+ unsigned int sda_is_open_drain:1;
+ unsigned int scl_is_open_drain:1;
+ unsigned int scl_is_output_only:1;
+};
+
+#endif /* _LINUX_I2C_GPIO_H */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 9c21dc793d7..0e8da684ce6 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -258,8 +258,9 @@
/* --- MCP107 adapter */
#define I2C_HW_MPC107 0x0d0000
-/* --- Marvell mv64xxx i2c adapter */
+/* --- Embedded adapters */
#define I2C_HW_MV64XXX 0x190000
+#define I2C_HW_BLACKFIN 0x190001 /* ADI Blackfin I2C TWI driver */
/* --- Miscellaneous adapters */
#define I2C_HW_SAA7146 0x060000 /* SAA7146 video decoder bus */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 9428092017e..cae7d618030 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -35,11 +35,6 @@
#include <linux/sched.h> /* for completion */
#include <linux/mutex.h>
-/* --- For i2c-isa ---------------------------------------------------- */
-
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct device_driver i2c_adapter_driver;
-extern struct class i2c_adapter_class;
extern struct bus_type i2c_bus_type;
/* --- General options ------------------------------------------------ */
@@ -87,6 +82,9 @@ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
u8 command, u16 value);
+/* Returns the number of read bytes */
+extern s32 i2c_smbus_read_block_data(struct i2c_client *client,
+ u8 command, u8 *values);
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
u8 command, u8 length,
const u8 *values);
@@ -114,7 +112,7 @@ struct i2c_driver {
* can be used by the driver to test if the bus meets its conditions
* & seek for the presence of the chip(s) it supports. If found, it
* registers the client(s) that are on the bus to the i2c admin. via
- * i2c_attach_client.
+ * i2c_attach_client. (LEGACY I2C DRIVERS ONLY)
*/
int (*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(struct i2c_adapter *);
@@ -122,10 +120,17 @@ struct i2c_driver {
/* tells the driver that a client is about to be deleted & gives it
* the chance to remove its private data. Also, if the client struct
* has been dynamically allocated by the driver in the function above,
- * it must be freed here.
+ * it must be freed here. (LEGACY I2C DRIVERS ONLY)
*/
int (*detach_client)(struct i2c_client *);
+ /* Standard driver model interfaces, for "new style" i2c drivers.
+ * With the driver model, device enumeration is NEVER done by drivers;
+ * it's done by infrastructure. (NEW STYLE DRIVERS ONLY)
+ */
+ int (*probe)(struct i2c_client *);
+ int (*remove)(struct i2c_client *);
+
/* driver model interfaces that don't relate to enumeration */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
@@ -141,25 +146,34 @@ struct i2c_driver {
};
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
-#define I2C_NAME_SIZE 50
+#define I2C_NAME_SIZE 20
-/*
- * i2c_client identifies a single device (i.e. chip) that is connected to an
- * i2c bus. The behaviour is defined by the routines of the driver. This
- * function is mainly used for lookup & other admin. functions.
+/**
+ * struct i2c_client - represent an I2C slave device
+ * @addr: Address used on the I2C bus connected to the parent adapter.
+ * @name: Indicates the type of the device, usually a chip name that's
+ * generic enough to hide second-sourcing and compatible revisions.
+ * @dev: Driver model device node for the slave.
+ * @driver_name: Identifies new-style driver used with this device; also
+ * used as the module name for hotplug/coldplug modprobe support.
+ *
+ * An i2c_client identifies a single device (i.e. chip) connected to an
+ * i2c bus. The behaviour is defined by the routines of the driver.
*/
struct i2c_client {
- unsigned int flags; /* div., see below */
+ unsigned short flags; /* div., see below */
unsigned short addr; /* chip address - NOTE: 7bit */
/* addresses are stored in the */
/* _LOWER_ 7 bits */
+ char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter; /* the adapter we sit on */
struct i2c_driver *driver; /* and our access routines */
int usage_count; /* How many accesses currently */
/* to the client */
struct device dev; /* the device structure */
+ int irq; /* irq issued by device (or -1) */
+ char driver_name[KOBJ_NAME_LEN];
struct list_head list;
- char name[I2C_NAME_SIZE];
struct completion released;
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
@@ -179,6 +193,76 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
dev_set_drvdata (&dev->dev, data);
}
+/**
+ * struct i2c_board_info - template for device creation
+ * @driver_name: identifies the driver to be bound to the device
+ * @type: optional chip type information, to initialize i2c_client.name
+ * @flags: to initialize i2c_client.flags
+ * @addr: stored in i2c_client.addr
+ * @platform_data: stored in i2c_client.dev.platform_data
+ * @irq: stored in i2c_client.irq
+
+ * I2C doesn't actually support hardware probing, although controllers and
+ * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
+ * a device at a given address. Drivers commonly need more information than
+ * that, such as chip type, configuration, associated IRQ, and so on.
+ *
+ * i2c_board_info is used to build tables of information listing I2C devices
+ * that are present. This information is used to grow the driver model tree
+ * for "new style" I2C drivers. For mainboards this is done statically using
+ * i2c_register_board_info(), where @bus_num represents an adapter that isn't
+ * yet available. For add-on boards, i2c_new_device() does this dynamically
+ * with the adapter already known.
+ */
+struct i2c_board_info {
+ char driver_name[KOBJ_NAME_LEN];
+ char type[I2C_NAME_SIZE];
+ unsigned short flags;
+ unsigned short addr;
+ void *platform_data;
+ int irq;
+};
+
+/**
+ * I2C_BOARD_INFO - macro used to list an i2c device and its driver
+ * @driver: identifies the driver to use with the device
+ * @dev_addr: the device's address on the bus.
+ *
+ * This macro initializes essential fields of a struct i2c_board_info,
+ * declaring what has been provided on a particular board. Optional
+ * fields (such as the chip type, its associated irq, or device-specific
+ * platform_data) are provided using conventional syntax.
+ */
+#define I2C_BOARD_INFO(driver,dev_addr) \
+ .driver_name = (driver), .addr = (dev_addr)
+
+
+/* Add-on boards should register/unregister their devices; e.g. a board
+ * with integrated I2C, a config eeprom, sensors, and a codec that's
+ * used in conjunction with the primary hardware.
+ */
+extern struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
+
+/* If you don't know the exact address of an I2C device, use this variant
+ * instead, which can probe for device presence in a list of possible
+ * addresses.
+ */
+extern struct i2c_client *
+i2c_new_probed_device(struct i2c_adapter *adap,
+ struct i2c_board_info *info,
+ unsigned short const *addr_list);
+
+extern void i2c_unregister_device(struct i2c_client *);
+
+/* Mainboard arch_initcall() code should register all its I2C devices.
+ * This is done at arch_initcall time, before declaring any i2c adapters.
+ * Modules for add-on boards must use other calls.
+ */
+extern int
+i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);
+
+
/*
* The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can
@@ -228,17 +312,14 @@ struct i2c_adapter {
int timeout;
int retries;
struct device dev; /* the adapter device */
- struct class_device class_dev; /* the class device */
int nr;
struct list_head clients;
struct list_head list;
- char name[I2C_NAME_SIZE];
+ char name[48];
struct completion dev_released;
- struct completion class_dev_released;
};
-#define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
-#define class_dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, class_dev)
+#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
static inline void *i2c_get_adapdata (struct i2c_adapter *dev)
{
@@ -290,9 +371,10 @@ struct i2c_client_address_data {
*/
extern int i2c_add_adapter(struct i2c_adapter *);
extern int i2c_del_adapter(struct i2c_adapter *);
+extern int i2c_add_numbered_adapter(struct i2c_adapter *);
extern int i2c_register_driver(struct module *, struct i2c_driver *);
-extern int i2c_del_driver(struct i2c_driver *);
+extern void i2c_del_driver(struct i2c_driver *);
static inline int i2c_add_driver(struct i2c_driver *driver)
{
@@ -365,6 +447,7 @@ struct i2c_msg {
#define I2C_M_REV_DIR_ADDR 0x2000
#define I2C_M_IGNORE_NAK 0x1000
#define I2C_M_NO_RD_ACK 0x0800
+#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
diff --git a/include/linux/ide.h b/include/linux/ide.h
index d3bbc7188b6..418dfb5adad 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -613,7 +613,6 @@ typedef struct ide_drive_s {
u8 quirk_list; /* considered quirky, set for a specific host */
u8 init_speed; /* transfer rate set at boot */
- u8 pio_speed; /* unused by core, used by some drivers for fallback from DMA */
u8 current_speed; /* current transfer rate set */
u8 desired_speed; /* desired transfer rate set */
u8 dn; /* now wide spread use */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
new file mode 100644
index 00000000000..ecd61e8438a
--- /dev/null
+++ b/include/linux/ieee80211.h
@@ -0,0 +1,342 @@
+/*
+ * IEEE 802.11 defines
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * 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.
+ */
+
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/types.h>
+
+#define FCS_LEN 4
+
+#define IEEE80211_FCTL_VERS 0x0003
+#define IEEE80211_FCTL_FTYPE 0x000c
+#define IEEE80211_FCTL_STYPE 0x00f0
+#define IEEE80211_FCTL_TODS 0x0100
+#define IEEE80211_FCTL_FROMDS 0x0200
+#define IEEE80211_FCTL_MOREFRAGS 0x0400
+#define IEEE80211_FCTL_RETRY 0x0800
+#define IEEE80211_FCTL_PM 0x1000
+#define IEEE80211_FCTL_MOREDATA 0x2000
+#define IEEE80211_FCTL_PROTECTED 0x4000
+#define IEEE80211_FCTL_ORDER 0x8000
+
+#define IEEE80211_SCTL_FRAG 0x000F
+#define IEEE80211_SCTL_SEQ 0xFFF0
+
+#define IEEE80211_FTYPE_MGMT 0x0000
+#define IEEE80211_FTYPE_CTL 0x0004
+#define IEEE80211_FTYPE_DATA 0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ 0x0000
+#define IEEE80211_STYPE_ASSOC_RESP 0x0010
+#define IEEE80211_STYPE_REASSOC_REQ 0x0020
+#define IEEE80211_STYPE_REASSOC_RESP 0x0030
+#define IEEE80211_STYPE_PROBE_REQ 0x0040
+#define IEEE80211_STYPE_PROBE_RESP 0x0050
+#define IEEE80211_STYPE_BEACON 0x0080
+#define IEEE80211_STYPE_ATIM 0x0090
+#define IEEE80211_STYPE_DISASSOC 0x00A0
+#define IEEE80211_STYPE_AUTH 0x00B0
+#define IEEE80211_STYPE_DEAUTH 0x00C0
+#define IEEE80211_STYPE_ACTION 0x00D0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL 0x00A0
+#define IEEE80211_STYPE_RTS 0x00B0
+#define IEEE80211_STYPE_CTS 0x00C0
+#define IEEE80211_STYPE_ACK 0x00D0
+#define IEEE80211_STYPE_CFEND 0x00E0
+#define IEEE80211_STYPE_CFENDACK 0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA 0x0000
+#define IEEE80211_STYPE_DATA_CFACK 0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL 0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
+#define IEEE80211_STYPE_NULLFUNC 0x0040
+#define IEEE80211_STYPE_CFACK 0x0050
+#define IEEE80211_STYPE_CFPOLL 0x0060
+#define IEEE80211_STYPE_CFACKPOLL 0x0070
+#define IEEE80211_STYPE_QOS_DATA 0x0080
+#define IEEE80211_STYPE_QOS_DATA_CFACK 0x0090
+#define IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0
+#define IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0
+#define IEEE80211_STYPE_QOS_NULLFUNC 0x00C0
+#define IEEE80211_STYPE_QOS_CFACK 0x00D0
+#define IEEE80211_STYPE_QOS_CFPOLL 0x00E0
+#define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0
+
+
+/* miscellaneous IEEE 802.11 constants */
+#define IEEE80211_MAX_FRAG_THRESHOLD 2346
+#define IEEE80211_MAX_RTS_THRESHOLD 2347
+#define IEEE80211_MAX_AID 2007
+#define IEEE80211_MAX_TIM_LEN 251
+#define IEEE80211_MAX_DATA_LEN 2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+ 6.2.1.1.2.
+
+ The figure in section 7.1.2 suggests a body size of up to 2312
+ bytes is allowed, which is a bit confusing, I suspect this
+ represents the 2304 bytes of real data, plus a possible 8 bytes of
+ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+#define IEEE80211_MAX_SSID_LEN 32
+
+struct ieee80211_hdr {
+ __le16 frame_control;
+ __le16 duration_id;
+ u8 addr1[6];
+ u8 addr2[6];
+ u8 addr3[6];
+ __le16 seq_ctrl;
+ u8 addr4[6];
+} __attribute__ ((packed));
+
+
+struct ieee80211_mgmt {
+ __le16 frame_control;
+ __le16 duration;
+ u8 da[6];
+ u8 sa[6];
+ u8 bssid[6];
+ __le16 seq_ctrl;
+ union {
+ struct {
+ __le16 auth_alg;
+ __le16 auth_transaction;
+ __le16 status_code;
+ /* possibly followed by Challenge text */
+ u8 variable[0];
+ } __attribute__ ((packed)) auth;
+ struct {
+ __le16 reason_code;
+ } __attribute__ ((packed)) deauth;
+ struct {
+ __le16 capab_info;
+ __le16 listen_interval;
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) assoc_req;
+ struct {
+ __le16 capab_info;
+ __le16 status_code;
+ __le16 aid;
+ /* followed by Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+ struct {
+ __le16 capab_info;
+ __le16 listen_interval;
+ u8 current_ap[6];
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) reassoc_req;
+ struct {
+ __le16 reason_code;
+ } __attribute__ ((packed)) disassoc;
+ struct {
+ __le64 timestamp;
+ __le16 beacon_int;
+ __le16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params, TIM */
+ u8 variable[0];
+ } __attribute__ ((packed)) beacon;
+ struct {
+ /* only variable items: SSID, Supported rates */
+ u8 variable[0];
+ } __attribute__ ((packed)) probe_req;
+ struct {
+ __le64 timestamp;
+ __le16 beacon_int;
+ __le16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params */
+ u8 variable[0];
+ } __attribute__ ((packed)) probe_resp;
+ struct {
+ u8 category;
+ union {
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 status_code;
+ u8 variable[0];
+ } __attribute__ ((packed)) wme_action;
+ struct{
+ u8 action_code;
+ u8 element_id;
+ u8 length;
+ u8 switch_mode;
+ u8 new_chan;
+ u8 switch_count;
+ } __attribute__((packed)) chan_switch;
+ } u;
+ } __attribute__ ((packed)) action;
+ } u;
+} __attribute__ ((packed));
+
+
+/* Control frames */
+struct ieee80211_rts {
+ __le16 frame_control;
+ __le16 duration;
+ u8 ra[6];
+ u8 ta[6];
+} __attribute__ ((packed));
+
+struct ieee80211_cts {
+ __le16 frame_control;
+ __le16 duration;
+ u8 ra[6];
+} __attribute__ ((packed));
+
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+#define WLAN_AUTH_FAST_BSS_TRANSITION 2
+#define WLAN_AUTH_LEAP 128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+/* 802.11h */
+#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8)
+#define WLAN_CAPABILITY_QOS (1<<9)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
+#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
+
+/* Status codes */
+enum ieee80211_statuscode {
+ WLAN_STATUS_SUCCESS = 0,
+ WLAN_STATUS_UNSPECIFIED_FAILURE = 1,
+ WLAN_STATUS_CAPS_UNSUPPORTED = 10,
+ WLAN_STATUS_REASSOC_NO_ASSOC = 11,
+ WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12,
+ WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13,
+ WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14,
+ WLAN_STATUS_CHALLENGE_FAIL = 15,
+ WLAN_STATUS_AUTH_TIMEOUT = 16,
+ WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17,
+ WLAN_STATUS_ASSOC_DENIED_RATES = 18,
+ /* 802.11b */
+ WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19,
+ WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20,
+ WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21,
+ /* 802.11h */
+ WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22,
+ WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23,
+ WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24,
+ /* 802.11g */
+ WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25,
+ WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26,
+ /* 802.11i */
+ WLAN_STATUS_INVALID_IE = 40,
+ WLAN_STATUS_INVALID_GROUP_CIPHER = 41,
+ WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42,
+ WLAN_STATUS_INVALID_AKMP = 43,
+ WLAN_STATUS_UNSUPP_RSN_VERSION = 44,
+ WLAN_STATUS_INVALID_RSN_IE_CAP = 45,
+ WLAN_STATUS_CIPHER_SUITE_REJECTED = 46,
+};
+
+
+/* Reason codes */
+enum ieee80211_reasoncode {
+ WLAN_REASON_UNSPECIFIED = 1,
+ WLAN_REASON_PREV_AUTH_NOT_VALID = 2,
+ WLAN_REASON_DEAUTH_LEAVING = 3,
+ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4,
+ WLAN_REASON_DISASSOC_AP_BUSY = 5,
+ WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7,
+ WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8,
+ WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9,
+ /* 802.11h */
+ WLAN_REASON_DISASSOC_BAD_POWER = 10,
+ WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11,
+ /* 802.11i */
+ WLAN_REASON_INVALID_IE = 13,
+ WLAN_REASON_MIC_FAILURE = 14,
+ WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15,
+ WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16,
+ WLAN_REASON_IE_DIFFERENT = 17,
+ WLAN_REASON_INVALID_GROUP_CIPHER = 18,
+ WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19,
+ WLAN_REASON_INVALID_AKMP = 20,
+ WLAN_REASON_UNSUPP_RSN_VERSION = 21,
+ WLAN_REASON_INVALID_RSN_IE_CAP = 22,
+ WLAN_REASON_IEEE8021X_FAILED = 23,
+ WLAN_REASON_CIPHER_SUITE_REJECTED = 24,
+};
+
+
+/* Information Element IDs */
+enum ieee80211_eid {
+ WLAN_EID_SSID = 0,
+ WLAN_EID_SUPP_RATES = 1,
+ WLAN_EID_FH_PARAMS = 2,
+ WLAN_EID_DS_PARAMS = 3,
+ WLAN_EID_CF_PARAMS = 4,
+ WLAN_EID_TIM = 5,
+ WLAN_EID_IBSS_PARAMS = 6,
+ WLAN_EID_CHALLENGE = 16,
+ /* 802.11d */
+ WLAN_EID_COUNTRY = 7,
+ WLAN_EID_HP_PARAMS = 8,
+ WLAN_EID_HP_TABLE = 9,
+ WLAN_EID_REQUEST = 10,
+ /* 802.11h */
+ WLAN_EID_PWR_CONSTRAINT = 32,
+ WLAN_EID_PWR_CAPABILITY = 33,
+ WLAN_EID_TPC_REQUEST = 34,
+ WLAN_EID_TPC_REPORT = 35,
+ WLAN_EID_SUPPORTED_CHANNELS = 36,
+ WLAN_EID_CHANNEL_SWITCH = 37,
+ WLAN_EID_MEASURE_REQUEST = 38,
+ WLAN_EID_MEASURE_REPORT = 39,
+ WLAN_EID_QUIET = 40,
+ WLAN_EID_IBSS_DFS = 41,
+ /* 802.11g */
+ WLAN_EID_ERP_INFO = 42,
+ WLAN_EID_EXT_SUPP_RATES = 50,
+ /* 802.11i */
+ WLAN_EID_RSN = 48,
+ WLAN_EID_WPA = 221,
+ WLAN_EID_GENERIC = 221,
+ WLAN_EID_VENDOR_SPECIFIC = 221,
+ WLAN_EID_QOS_PARAMETER = 222
+};
+
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
+/* reserved: 0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
+
+#define WLAN_MAX_KEY_LEN 32
+
+#endif /* IEEE80211_H */
diff --git a/include/linux/init.h b/include/linux/init.h
index e290a010e3f..8bc32bb2fce 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -52,9 +52,14 @@
#endif
/* For assembly routines */
+#ifdef CONFIG_HOTPLUG_CPU
+#define __INIT .section ".text","ax"
+#define __INITDATA .section ".data","aw"
+#else
#define __INIT .section ".init.text","ax"
-#define __FINIT .previous
#define __INITDATA .section ".init.data","aw"
+#endif
+#define __FINIT .previous
#ifndef __ASSEMBLY__
/*
@@ -72,7 +77,8 @@ extern char *saved_command_line;
extern unsigned int reset_devices;
/* used by init/main.c */
-extern void setup_arch(char **);
+void setup_arch(char **);
+void prepare_namespace(void);
#endif
@@ -228,7 +234,7 @@ void __init parse_early_param(void);
#define __obsolete_setup(str) /* nothing */
#endif
-/* Data marked not to be saved by software_suspend() */
+/* Data marked not to be saved by software suspend */
#define __nosavedata __attribute__ ((__section__ (".data.nosave")))
/* This means "can be init if no module support, otherwise module load
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index a2d95ff50e9..45170b2fa25 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -95,7 +95,7 @@ extern struct group_info init_groups;
#define INIT_TASK(tsk) \
{ \
.state = 0, \
- .thread_info = &init_thread_info, \
+ .stack = &init_thread_info, \
.usage = ATOMIC_INIT(2), \
.flags = 0, \
.lock_depth = -1, \
@@ -138,7 +138,7 @@ extern struct group_info init_groups;
.journal_info = NULL, \
.cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
.fs_excl = ATOMIC_INIT(0), \
- .pi_lock = SPIN_LOCK_UNLOCKED, \
+ .pi_lock = __SPIN_LOCK_UNLOCKED(tsk.pi_lock), \
INIT_TRACE_IRQFLAGS \
INIT_LOCKDEP \
}
diff --git a/include/linux/input-polldev.h b/include/linux/input-polldev.h
new file mode 100644
index 00000000000..597a0077b3c
--- /dev/null
+++ b/include/linux/input-polldev.h
@@ -0,0 +1,46 @@
+#ifndef _INPUT_POLLDEV_H
+#define _INPUT_POLLDEV_H
+
+/*
+ * Copyright (c) 2007 Dmitry Torokhov
+ *
+ * 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/input.h>
+#include <linux/workqueue.h>
+
+/**
+ * struct input_polled_dev - simple polled input device
+ * @private: private driver data
+ * @flush: driver-supplied method that flushes device's state upon
+ * opening (optional)
+ * @poll: driver-supplied method that polls the device and posts
+ * input events (mandatory).
+ * @poll_interval: specifies how often the poll() method shoudl be called.
+ * @input: input device structire associated with the polled device.
+ * Must be properly initialized by the driver (id, name, phys, bits).
+ *
+ * Polled input device provides a skeleton for supporting simple input
+ * devices that do not raise interrupts but have to be periodically
+ * scanned or polled to detect changes in their state.
+ */
+struct input_polled_dev {
+ void *private;
+
+ void (*flush)(struct input_polled_dev *dev);
+ void (*poll)(struct input_polled_dev *dev);
+ unsigned int poll_interval; /* msec */
+
+ struct input_dev *input;
+ struct delayed_work work;
+};
+
+struct input_polled_dev *input_allocate_polled_device(void);
+void input_free_polled_device(struct input_polled_dev *dev);
+int input_register_polled_device(struct input_polled_dev *dev);
+void input_unregister_polled_device(struct input_polled_dev *dev);
+
+#endif
diff --git a/include/linux/input.h b/include/linux/input.h
index bde65c8a351..be2bf3a2b03 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -506,6 +506,7 @@ struct input_absinfo {
#define KEY_VOICEMAIL 0x1ac
#define KEY_ADDRESSBOOK 0x1ad
#define KEY_MESSENGER 0x1ae
+#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
#define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1
@@ -676,6 +677,7 @@ struct input_absinfo {
#define BUS_I2C 0x18
#define BUS_HOST 0x19
#define BUS_GSC 0x1A
+#define BUS_ATARI 0x1B
/*
* Values describing the status of a force-feedback effect
@@ -913,33 +915,6 @@ struct ff_effect {
#define BIT(x) (1UL<<((x)%BITS_PER_LONG))
#define LONG(x) ((x)/BITS_PER_LONG)
-#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
- ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
-
-#define SET_INPUT_KEYCODE(dev, scancode, val) \
- ({ unsigned __old; \
- switch (dev->keycodesize) { \
- case 1: { \
- u8 *k = (u8 *)dev->keycode; \
- __old = k[scancode]; \
- k[scancode] = val; \
- break; \
- } \
- case 2: { \
- u16 *k = (u16 *)dev->keycode; \
- __old = k[scancode]; \
- k[scancode] = val; \
- break; \
- } \
- default: { \
- u32 *k = (u32 *)dev->keycode; \
- __old = k[scancode]; \
- k[scancode] = val; \
- break; \
- } \
- } \
- __old; })
-
struct input_dev {
void *private;
@@ -962,6 +937,8 @@ struct input_dev {
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
+ int (*setkeycode)(struct input_dev *dev, int scancode, int keycode);
+ int (*getkeycode)(struct input_dev *dev, int scancode, int *keycode);
struct ff_device *ff;
@@ -996,6 +973,9 @@ struct input_dev {
unsigned int users;
struct class_device cdev;
+ union { /* temporarily so while we switching to struct device */
+ struct device *parent;
+ } dev;
struct list_head h_list;
struct list_head node;
@@ -1010,6 +990,10 @@ struct input_dev {
#error "EV_MAX and INPUT_DEVICE_ID_EV_MAX do not match"
#endif
+#if KEY_MIN_INTERESTING != INPUT_DEVICE_ID_KEY_MIN_INTERESTING
+#error "KEY_MIN_INTERESTING and INPUT_DEVICE_ID_KEY_MIN_INTERESTING do not match"
+#endif
+
#if KEY_MAX != INPUT_DEVICE_ID_KEY_MAX
#error "KEY_MAX and INPUT_DEVICE_ID_KEY_MAX do not match"
#endif
@@ -1074,7 +1058,7 @@ struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
- struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
+ int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
@@ -1104,7 +1088,7 @@ struct input_handle {
};
#define to_dev(n) container_of(n,struct input_dev,node)
-#define to_handler(n) container_of(n,struct input_handler,node);
+#define to_handler(n) container_of(n,struct input_handler,node)
#define to_handle(n) container_of(n,struct input_handle,d_node)
#define to_handle_h(n) container_of(n,struct input_handle,h_node)
@@ -1121,12 +1105,25 @@ static inline void input_put_device(struct input_dev *dev)
class_device_put(&dev->cdev);
}
+static inline void *input_get_drvdata(struct input_dev *dev)
+{
+ return dev->private;
+}
+
+static inline void input_set_drvdata(struct input_dev *dev, void *data)
+{
+ dev->private = data;
+}
+
int input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
int input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
+int input_register_handle(struct input_handle *);
+void input_unregister_handle(struct input_handle *);
+
int input_grab_device(struct input_handle *);
void input_release_device(struct input_handle *);
@@ -1168,6 +1165,8 @@ static inline void input_sync(struct input_dev *dev)
input_event(dev, EV_SYN, SYN_REPORT, 0);
}
+void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code);
+
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
{
dev->absmin[axis] = min;
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 838cf5a5bd7..f7b01b9a35b 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -44,6 +44,9 @@
* IRQF_TIMER - Flag to mark this interrupt as timer interrupt
* IRQF_PERCPU - Interrupt is per cpu
* IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing
+ * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is
+ * registered first in an shared interrupt is considered for
+ * performance reasons)
*/
#define IRQF_DISABLED 0x00000020
#define IRQF_SAMPLE_RANDOM 0x00000040
@@ -52,22 +55,29 @@
#define IRQF_TIMER 0x00000200
#define IRQF_PERCPU 0x00000400
#define IRQF_NOBALANCING 0x00000800
+#define IRQF_IRQPOLL 0x00001000
/*
- * Migration helpers. Scheduled for removal in 1/2007
+ * Migration helpers. Scheduled for removal in 9/2007
* Do not use for new code !
*/
-#define SA_INTERRUPT IRQF_DISABLED
-#define SA_SAMPLE_RANDOM IRQF_SAMPLE_RANDOM
-#define SA_SHIRQ IRQF_SHARED
-#define SA_PROBEIRQ IRQF_PROBE_SHARED
-#define SA_PERCPU IRQF_PERCPU
-
-#define SA_TRIGGER_LOW IRQF_TRIGGER_LOW
-#define SA_TRIGGER_HIGH IRQF_TRIGGER_HIGH
-#define SA_TRIGGER_FALLING IRQF_TRIGGER_FALLING
-#define SA_TRIGGER_RISING IRQF_TRIGGER_RISING
-#define SA_TRIGGER_MASK IRQF_TRIGGER_MASK
+static inline
+unsigned long __deprecated deprecated_irq_flag(unsigned long flag)
+{
+ return flag;
+}
+
+#define SA_INTERRUPT deprecated_irq_flag(IRQF_DISABLED)
+#define SA_SAMPLE_RANDOM deprecated_irq_flag(IRQF_SAMPLE_RANDOM)
+#define SA_SHIRQ deprecated_irq_flag(IRQF_SHARED)
+#define SA_PROBEIRQ deprecated_irq_flag(IRQF_PROBE_SHARED)
+#define SA_PERCPU deprecated_irq_flag(IRQF_PERCPU)
+
+#define SA_TRIGGER_LOW deprecated_irq_flag(IRQF_TRIGGER_LOW)
+#define SA_TRIGGER_HIGH deprecated_irq_flag(IRQF_TRIGGER_HIGH)
+#define SA_TRIGGER_FALLING deprecated_irq_flag(IRQF_TRIGGER_FALLING)
+#define SA_TRIGGER_RISING deprecated_irq_flag(IRQF_TRIGGER_RISING)
+#define SA_TRIGGER_MASK deprecated_irq_flag(IRQF_TRIGGER_MASK)
typedef irqreturn_t (*irq_handler_t)(int, void *);
@@ -83,11 +93,11 @@ struct irqaction {
};
extern irqreturn_t no_action(int cpl, void *dev_id);
-extern int request_irq(unsigned int, irq_handler_t handler,
+extern int __must_check request_irq(unsigned int, irq_handler_t handler,
unsigned long, const char *, void *);
extern void free_irq(unsigned int, void *);
-extern int devm_request_irq(struct device *dev, unsigned int irq,
+extern int __must_check devm_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, unsigned long irqflags,
const char *devname, void *dev_id);
extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
@@ -185,10 +195,14 @@ static inline int disable_irq_wake(unsigned int irq)
* validator need to define the methods below in their asm/irq.h
* files, under an #ifdef CONFIG_LOCKDEP section.
*/
-# ifndef CONFIG_LOCKDEP
+#ifndef CONFIG_LOCKDEP
# define disable_irq_nosync_lockdep(irq) disable_irq_nosync(irq)
+# define disable_irq_nosync_lockdep_irqsave(irq, flags) \
+ disable_irq_nosync(irq)
# define disable_irq_lockdep(irq) disable_irq(irq)
# define enable_irq_lockdep(irq) enable_irq(irq)
+# define enable_irq_lockdep_irqrestore(irq, flags) \
+ enable_irq(irq)
# endif
#endif /* CONFIG_GENERIC_HARDIRQS */
diff --git a/include/linux/ioctl32.h b/include/linux/ioctl32.h
deleted file mode 100644
index 948809d9991..00000000000
--- a/include/linux/ioctl32.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef IOCTL32_H
-#define IOCTL32_H 1
-
-#include <linux/compiler.h> /* for __deprecated */
-
-struct file;
-
-typedef int (*ioctl_trans_handler_t)(unsigned int, unsigned int,
- unsigned long, struct file *);
-
-struct ioctl_trans {
- unsigned long cmd;
- ioctl_trans_handler_t handler;
- struct ioctl_trans *next;
-};
-
-#endif
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 6859a3b1408..71ea9231924 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -99,7 +99,6 @@ extern struct resource ioport_resource;
extern struct resource iomem_resource;
extern int request_resource(struct resource *root, struct resource *new);
-extern struct resource * ____request_resource(struct resource *root, struct resource *new);
extern int release_resource(struct resource *new);
extern int insert_resource(struct resource *parent, struct resource *new);
extern int allocate_resource(struct resource *root, struct resource *new,
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 6da6772c19f..1980867a64a 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -92,16 +92,19 @@ extern struct ipc_namespace init_ipc_ns;
#ifdef CONFIG_SYSVIPC
#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
-extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
+extern struct ipc_namespace *copy_ipcs(unsigned long flags,
+ struct ipc_namespace *ns);
#else
#define INIT_IPC_NS(ns)
-static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk)
-{ return 0; }
+static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
+ struct ipc_namespace *ns)
+{
+ return ns;
+}
#endif
#ifdef CONFIG_IPC_NS
extern void free_ipc_ns(struct kref *kref);
-extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
#endif
static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
diff --git a/include/linux/irda.h b/include/linux/irda.h
index 09d8f105a5a..945ba311087 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/linux/irq.h b/include/linux/irq.h
index a6899402b52..1695054e8c6 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -147,8 +147,6 @@ struct irq_chip {
* @dir: /proc/irq/ procfs entry
* @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
* @name: flow handler name for /proc/interrupts output
- *
- * Pad this out to 32 bytes for cache and indexing reasons.
*/
struct irq_desc {
irq_flow_handler_t handle_irq;
@@ -175,7 +173,7 @@ struct irq_desc {
struct proc_dir_entry *dir;
#endif
const char *name;
-} ____cacheline_aligned;
+} ____cacheline_internodealigned_in_smp;
extern struct irq_desc irq_desc[NR_IRQS];
diff --git a/include/linux/isdn/capiutil.h b/include/linux/isdn/capiutil.h
index 63bd9cf821a..5a52f2c94f3 100644
--- a/include/linux/isdn/capiutil.h
+++ b/include/linux/isdn/capiutil.h
@@ -187,7 +187,6 @@ typedef struct {
#define CDEBUG_SIZE 1024
#define CDEBUG_GSIZE 4096
-_cdebbuf *cdebbuf_alloc(void);
void cdebbuf_free(_cdebbuf *cdb);
int cdebug_init(void);
void cdebug_exit(void);
diff --git a/include/linux/isdn_divertif.h b/include/linux/isdn_divertif.h
index 0e7e44ce830..07821ca5955 100644
--- a/include/linux/isdn_divertif.h
+++ b/include/linux/isdn_divertif.h
@@ -24,6 +24,10 @@
#define DIVERT_REL_ERR 0x04 /* module not registered */
#define DIVERT_REG_NAME isdn_register_divert
+#ifdef __KERNEL__
+#include <linux/isdnif.h>
+#include <linux/types.h>
+
/***************************************************************/
/* structure exchanging data between isdn hl and divert module */
/***************************************************************/
@@ -40,3 +44,4 @@ typedef struct
/* function register */
/*********************/
extern int DIVERT_REG_NAME(isdn_divert_if *);
+#endif
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 1cebcbc28b4..12178d2c882 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -7,6 +7,8 @@
#define KSYM_NAME_LEN 127
+#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN + \
+ 2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1)
#ifdef CONFIG_KALLSYMS
/* Lookup the address for a symbol. Returns 0 if not found. */
@@ -22,9 +24,15 @@ const char *kallsyms_lookup(unsigned long addr,
unsigned long *offset,
char **modname, char *namebuf);
-/* Replace "%s" in format with address, if found */
+/* Look up a kernel symbol and return it in a text buffer. */
+extern int sprint_symbol(char *buffer, unsigned long address);
+
+/* Look up a kernel symbol and print it to the kernel messages. */
extern void __print_symbol(const char *fmt, unsigned long address);
+int lookup_symbol_name(unsigned long addr, char *symname);
+int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
+
#else /* !CONFIG_KALLSYMS */
static inline unsigned long kallsyms_lookup_name(const char *name)
@@ -47,6 +55,22 @@ static inline const char *kallsyms_lookup(unsigned long addr,
return NULL;
}
+static inline int sprint_symbol(char *buffer, unsigned long addr)
+{
+ *buffer = '\0';
+ return 0;
+}
+
+static inline int lookup_symbol_name(unsigned long addr, char *symname)
+{
+ return -ERANGE;
+}
+
+static inline int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name)
+{
+ return -ERANGE;
+}
+
/* Stupid that this does nothing, but I didn't create this mess. */
#define __print_symbol(fmt, addr)
#endif /*CONFIG_KALLSYMS*/
diff --git a/include/linux/kdebug.h b/include/linux/kdebug.h
new file mode 100644
index 00000000000..5db38d6d8b9
--- /dev/null
+++ b/include/linux/kdebug.h
@@ -0,0 +1,20 @@
+#ifndef _LINUX_KDEBUG_H
+#define _LINUX_KDEBUG_H
+
+#include <asm/kdebug.h>
+
+struct die_args {
+ struct pt_regs *regs;
+ const char *str;
+ long err;
+ int trapnr;
+ int signr;
+};
+
+int register_die_notifier(struct notifier_block *nb);
+int unregister_die_notifier(struct notifier_block *nb);
+
+int notify_die(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig);
+
+#endif /* _LINUX_KDEBUG_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 9ddf25c2153..144b615f3a8 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -35,7 +35,8 @@ extern const char linux_proc_banner[];
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
+
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
@@ -121,6 +122,7 @@ extern int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
__attribute__ ((format (printf, 3, 0)));
extern char *kasprintf(gfp_t gfp, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
+extern char *kvasprintf(gfp_t gfp, const char *fmt, va_list args);
extern int sscanf(const char *, const char *, ...)
__attribute__ ((format (scanf, 2, 3)));
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 696e5ec63f7..8c2c7fcd58c 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -7,6 +7,8 @@
#include <linux/linkage.h>
#include <linux/compat.h>
#include <linux/ioport.h>
+#include <linux/elfcore.h>
+#include <linux/elf.h>
#include <asm/kexec.h>
/* Verify architecture specific macros are defined */
@@ -31,6 +33,19 @@
#error KEXEC_ARCH not defined
#endif
+#define KEXEC_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4)
+#define KEXEC_CORE_NOTE_NAME "CORE"
+#define KEXEC_CORE_NOTE_NAME_BYTES ALIGN(sizeof(KEXEC_CORE_NOTE_NAME), 4)
+#define KEXEC_CORE_NOTE_DESC_BYTES ALIGN(sizeof(struct elf_prstatus), 4)
+/*
+ * The per-cpu notes area is a list of notes terminated by a "NULL"
+ * note header. For kdump, the code in vmcore.c runs in the context
+ * of the second kernel to combine them into one note.
+ */
+#define KEXEC_NOTE_BYTES ( (KEXEC_NOTE_HEAD_BYTES * 2) + \
+ KEXEC_CORE_NOTE_NAME_BYTES + \
+ KEXEC_CORE_NOTE_DESC_BYTES )
+
/*
* This structure is used to hold the arguments that are used when loading
* kernel binaries.
@@ -136,7 +151,7 @@ extern struct kimage *kexec_crash_image;
/* Location of a reserved region to hold the crash kernel.
*/
extern struct resource crashk_res;
-typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4];
extern note_buf_t *crash_notes;
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index eb0e63ef297..c288e41ba33 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -124,7 +124,6 @@ struct kset_uevent_ops {
};
struct kset {
- struct subsystem * subsys;
struct kobj_type * ktype;
struct list_head list;
spinlock_t list_lock;
@@ -171,32 +170,23 @@ extern struct kobject * kset_find_obj(struct kset *, const char *);
#define set_kset_name(str) .kset = { .kobj = { .name = str } }
-
-struct subsystem {
- struct kset kset;
-};
-
#define decl_subsys(_name,_type,_uevent_ops) \
-struct subsystem _name##_subsys = { \
- .kset = { \
- .kobj = { .name = __stringify(_name) }, \
- .ktype = _type, \
- .uevent_ops =_uevent_ops, \
- } \
+struct kset _name##_subsys = { \
+ .kobj = { .name = __stringify(_name) }, \
+ .ktype = _type, \
+ .uevent_ops =_uevent_ops, \
}
#define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
-struct subsystem _varname##_subsys = { \
- .kset = { \
- .kobj = { .name = __stringify(_name) }, \
- .ktype = _type, \
- .uevent_ops =_uevent_ops, \
- } \
+struct kset _varname##_subsys = { \
+ .kobj = { .name = __stringify(_name) }, \
+ .ktype = _type, \
+ .uevent_ops =_uevent_ops, \
}
/* The global /sys/kernel/ subsystem for people to chain off of */
-extern struct subsystem kernel_subsys;
+extern struct kset kernel_subsys;
/* The global /sys/hypervisor/ subsystem */
-extern struct subsystem hypervisor_subsys;
+extern struct kset hypervisor_subsys;
/**
* Helpers for setting the kset of registered objects.
@@ -214,7 +204,7 @@ extern struct subsystem hypervisor_subsys;
*/
#define kobj_set_kset_s(obj,subsys) \
- (obj)->kobj.kset = &(subsys).kset
+ (obj)->kobj.kset = &(subsys)
/**
* kset_set_kset_s(obj,subsys) - set kset for embedded kset.
@@ -228,7 +218,7 @@ extern struct subsystem hypervisor_subsys;
*/
#define kset_set_kset_s(obj,subsys) \
- (obj)->kset.kobj.kset = &(subsys).kset
+ (obj)->kset.kobj.kset = &(subsys)
/**
* subsys_set_kset(obj,subsys) - set kset for subsystem
@@ -241,29 +231,31 @@ extern struct subsystem hypervisor_subsys;
*/
#define subsys_set_kset(obj,_subsys) \
- (obj)->subsys.kset.kobj.kset = &(_subsys).kset
+ (obj)->subsys.kobj.kset = &(_subsys)
-extern void subsystem_init(struct subsystem *);
-extern int __must_check subsystem_register(struct subsystem *);
-extern void subsystem_unregister(struct subsystem *);
+extern void subsystem_init(struct kset *);
+extern int __must_check subsystem_register(struct kset *);
+extern void subsystem_unregister(struct kset *);
-static inline struct subsystem * subsys_get(struct subsystem * s)
+static inline struct kset *subsys_get(struct kset *s)
{
- return s ? container_of(kset_get(&s->kset),struct subsystem,kset) : NULL;
+ if (s)
+ return kset_get(s);
+ return NULL;
}
-static inline void subsys_put(struct subsystem * s)
+static inline void subsys_put(struct kset *s)
{
- kset_put(&s->kset);
+ kset_put(s);
}
struct subsys_attribute {
struct attribute attr;
- ssize_t (*show)(struct subsystem *, char *);
- ssize_t (*store)(struct subsystem *, const char *, size_t);
+ ssize_t (*show)(struct kset *, char *);
+ ssize_t (*store)(struct kset *, const char *, size_t);
};
-extern int __must_check subsys_create_file(struct subsystem * ,
+extern int __must_check subsys_create_file(struct kset *,
struct subsys_attribute *);
#if defined(CONFIG_HOTPLUG)
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 769be39b968..23adf6075ae 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -78,7 +78,7 @@ struct kprobe {
kprobe_opcode_t *addr;
/* Allow user to indicate symbol name of the probe point */
- char *symbol_name;
+ const char *symbol_name;
/* Offset into the symbol */
unsigned int offset;
@@ -123,12 +123,18 @@ DECLARE_PER_CPU(struct kprobe *, current_kprobe);
DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
#ifdef ARCH_SUPPORTS_KRETPROBES
-extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs);
+extern void arch_prepare_kretprobe(struct kretprobe_instance *ri,
+ struct pt_regs *regs);
+extern int arch_trampoline_kprobe(struct kprobe *p);
#else /* ARCH_SUPPORTS_KRETPROBES */
static inline void arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs)
{
}
+static inline int arch_trampoline_kprobe(struct kprobe *p)
+{
+ return 0;
+}
#endif /* ARCH_SUPPORTS_KRETPROBES */
/*
* Function-return probe -
@@ -157,6 +163,16 @@ struct kretprobe_instance {
struct task_struct *task;
};
+static inline void kretprobe_assert(struct kretprobe_instance *ri,
+ unsigned long orig_ret_address, unsigned long trampoline_address)
+{
+ if (!orig_ret_address || (orig_ret_address == trampoline_address)) {
+ printk("kretprobe BUG!: Processing kretprobe %p @ %p\n",
+ ri->rp, ri->rp->kp.addr);
+ BUG();
+ }
+}
+
extern spinlock_t kretprobe_lock;
extern struct mutex kprobe_mutex;
extern int arch_prepare_kprobe(struct kprobe *p);
@@ -199,8 +215,6 @@ void jprobe_return(void);
int register_kretprobe(struct kretprobe *rp);
void unregister_kretprobe(struct kretprobe *rp);
-struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
-void add_rp_inst(struct kretprobe_instance *ri);
void kprobe_flush_task(struct task_struct *tk);
void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
#else /* CONFIG_KPROBES */
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 1c65e7a9f18..00dd957e245 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -30,4 +30,7 @@ void kthread_bind(struct task_struct *k, unsigned int cpu);
int kthread_stop(struct task_struct *k);
int kthread_should_stop(void);
+int kthreadd(void *unused);
+extern struct task_struct *kthreadd_task;
+
#endif /* _LINUX_KTHREAD_H */
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 81bb9c7a4eb..c762954bda1 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -43,7 +43,7 @@
* plain scalar nanosecond based representation can be selected by the
* config switch CONFIG_KTIME_SCALAR.
*/
-typedef union {
+union ktime {
s64 tv64;
#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
struct {
@@ -54,7 +54,9 @@ typedef union {
# endif
} tv;
#endif
-} ktime_t;
+};
+
+typedef union ktime ktime_t; /* Kill this */
#define KTIME_MAX ((s64)~((u64)1 << 63))
#if (BITS_PER_LONG == 64)
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 275354ffa1c..e6edca81ab8 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -11,7 +11,7 @@
#include <asm/types.h>
#include <linux/ioctl.h>
-#define KVM_API_VERSION 4
+#define KVM_API_VERSION 12
/*
* Architectural interrupt line count, and the size of the bitmap needed
@@ -33,37 +33,39 @@ struct kvm_memory_region {
/* for kvm_memory_region::flags */
#define KVM_MEM_LOG_DIRTY_PAGES 1UL
-
-#define KVM_EXIT_TYPE_FAIL_ENTRY 1
-#define KVM_EXIT_TYPE_VM_EXIT 2
+struct kvm_memory_alias {
+ __u32 slot; /* this has a different namespace than memory slots */
+ __u32 flags;
+ __u64 guest_phys_addr;
+ __u64 memory_size;
+ __u64 target_phys_addr;
+};
enum kvm_exit_reason {
KVM_EXIT_UNKNOWN = 0,
KVM_EXIT_EXCEPTION = 1,
KVM_EXIT_IO = 2,
- KVM_EXIT_CPUID = 3,
+ KVM_EXIT_HYPERCALL = 3,
KVM_EXIT_DEBUG = 4,
KVM_EXIT_HLT = 5,
KVM_EXIT_MMIO = 6,
KVM_EXIT_IRQ_WINDOW_OPEN = 7,
KVM_EXIT_SHUTDOWN = 8,
+ KVM_EXIT_FAIL_ENTRY = 9,
+ KVM_EXIT_INTR = 10,
};
-/* for KVM_RUN */
+/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
/* in */
- __u32 emulated; /* skip current instruction */
- __u32 mmio_completed; /* mmio request completed */
__u8 request_interrupt_window;
__u8 padding1[7];
/* out */
- __u32 exit_type;
__u32 exit_reason;
- __u32 instruction_length;
__u8 ready_for_interrupt_injection;
__u8 if_flag;
- __u16 padding2;
+ __u8 padding2[2];
/* in (pre_kvm_run), out (post_kvm_run) */
__u64 cr8;
@@ -72,29 +74,26 @@ struct kvm_run {
union {
/* KVM_EXIT_UNKNOWN */
struct {
- __u32 hardware_exit_reason;
+ __u64 hardware_exit_reason;
} hw;
+ /* KVM_EXIT_FAIL_ENTRY */
+ struct {
+ __u64 hardware_entry_failure_reason;
+ } fail_entry;
/* KVM_EXIT_EXCEPTION */
struct {
__u32 exception;
__u32 error_code;
} ex;
/* KVM_EXIT_IO */
- struct {
+ struct kvm_io {
#define KVM_EXIT_IO_IN 0
#define KVM_EXIT_IO_OUT 1
__u8 direction;
__u8 size; /* bytes */
- __u8 string;
- __u8 string_down;
- __u8 rep;
- __u8 pad;
__u16 port;
- __u64 count;
- union {
- __u64 address;
- __u32 value;
- };
+ __u32 count;
+ __u64 data_offset; /* relative to kvm_run start */
} io;
struct {
} debug;
@@ -105,6 +104,13 @@ struct kvm_run {
__u32 len;
__u8 is_write;
} mmio;
+ /* KVM_EXIT_HYPERCALL */
+ struct {
+ __u64 args[6];
+ __u64 ret;
+ __u32 longmode;
+ __u32 pad;
+ } hypercall;
};
};
@@ -118,6 +124,21 @@ struct kvm_regs {
__u64 rip, rflags;
};
+/* for KVM_GET_FPU and KVM_SET_FPU */
+struct kvm_fpu {
+ __u8 fpr[8][16];
+ __u16 fcw;
+ __u16 fsw;
+ __u8 ftwx; /* in fxsave format */
+ __u8 pad1;
+ __u16 last_opcode;
+ __u64 last_ip;
+ __u64 last_dp;
+ __u8 xmm[16][16];
+ __u32 mxcsr;
+ __u32 pad2;
+};
+
struct kvm_segment {
__u64 base;
__u32 limit;
@@ -210,38 +231,74 @@ struct kvm_dirty_log {
};
};
+struct kvm_cpuid_entry {
+ __u32 function;
+ __u32 eax;
+ __u32 ebx;
+ __u32 ecx;
+ __u32 edx;
+ __u32 padding;
+};
+
+/* for KVM_SET_CPUID */
+struct kvm_cpuid {
+ __u32 nent;
+ __u32 padding;
+ struct kvm_cpuid_entry entries[0];
+};
+
+/* for KVM_SET_SIGNAL_MASK */
+struct kvm_signal_mask {
+ __u32 len;
+ __u8 sigset[0];
+};
+
#define KVMIO 0xAE
/*
* ioctls for /dev/kvm fds:
*/
-#define KVM_GET_API_VERSION _IO(KVMIO, 1)
-#define KVM_CREATE_VM _IO(KVMIO, 2) /* returns a VM fd */
-#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 15, struct kvm_msr_list)
+#define KVM_GET_API_VERSION _IO(KVMIO, 0x00)
+#define KVM_CREATE_VM _IO(KVMIO, 0x01) /* returns a VM fd */
+#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list)
+/*
+ * Check if a kvm extension is available. Argument is extension number,
+ * return is 1 (yes) or 0 (no, sorry).
+ */
+#define KVM_CHECK_EXTENSION _IO(KVMIO, 0x03)
+/*
+ * Get size for mmap(vcpu_fd)
+ */
+#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
/*
* ioctls for VM fds
*/
-#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 10, struct kvm_memory_region)
+#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region)
/*
* KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
* a vcpu fd.
*/
-#define KVM_CREATE_VCPU _IOW(KVMIO, 11, int)
-#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 12, struct kvm_dirty_log)
+#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
+#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
+#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)
/*
* ioctls for vcpu fds
*/
-#define KVM_RUN _IOWR(KVMIO, 2, struct kvm_run)
-#define KVM_GET_REGS _IOR(KVMIO, 3, struct kvm_regs)
-#define KVM_SET_REGS _IOW(KVMIO, 4, struct kvm_regs)
-#define KVM_GET_SREGS _IOR(KVMIO, 5, struct kvm_sregs)
-#define KVM_SET_SREGS _IOW(KVMIO, 6, struct kvm_sregs)
-#define KVM_TRANSLATE _IOWR(KVMIO, 7, struct kvm_translation)
-#define KVM_INTERRUPT _IOW(KVMIO, 8, struct kvm_interrupt)
-#define KVM_DEBUG_GUEST _IOW(KVMIO, 9, struct kvm_debug_guest)
-#define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs)
-#define KVM_SET_MSRS _IOW(KVMIO, 14, struct kvm_msrs)
+#define KVM_RUN _IO(KVMIO, 0x80)
+#define KVM_GET_REGS _IOR(KVMIO, 0x81, struct kvm_regs)
+#define KVM_SET_REGS _IOW(KVMIO, 0x82, struct kvm_regs)
+#define KVM_GET_SREGS _IOR(KVMIO, 0x83, struct kvm_sregs)
+#define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs)
+#define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation)
+#define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt)
+#define KVM_DEBUG_GUEST _IOW(KVMIO, 0x87, struct kvm_debug_guest)
+#define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs)
+#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs)
+#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid)
+#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask)
+#define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu)
+#define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu)
#endif
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 0cfbcb6f08e..7906d750aa7 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -210,6 +210,7 @@ enum {
/* host set flags */
ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
+ ATA_HOST_STARTED = (1 << 1), /* Host started */
/* various lengths of time */
ATA_TMOUT_BOOT = 30 * HZ, /* heuristic */
@@ -281,11 +282,13 @@ enum {
ATA_EHI_NO_AUTOPSY = (1 << 2), /* no autopsy */
ATA_EHI_QUIET = (1 << 3), /* be quiet */
- ATA_EHI_DID_RESET = (1 << 16), /* already reset this port */
- ATA_EHI_PRINTINFO = (1 << 17), /* print configuration info */
- ATA_EHI_SETMODE = (1 << 18), /* configure transfer mode */
- ATA_EHI_POST_SETMODE = (1 << 19), /* revaildating after setmode */
+ ATA_EHI_DID_SOFTRESET = (1 << 16), /* already soft-reset this port */
+ ATA_EHI_DID_HARDRESET = (1 << 17), /* already soft-reset this port */
+ ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */
+ ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */
+ ATA_EHI_POST_SETMODE = (1 << 20), /* revaildating after setmode */
+ ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
ATA_EHI_RESET_MODIFIER_MASK = ATA_EHI_RESUME_LINK,
/* max repeat if error condition is still set after ->error_handler */
@@ -293,18 +296,8 @@ enum {
/* how hard are we gonna try to probe/recover devices */
ATA_PROBE_MAX_TRIES = 3,
- ATA_EH_RESET_TRIES = 3,
ATA_EH_DEV_TRIES = 3,
- /* Drive spinup time (time from power-on to the first D2H FIS)
- * in msecs - 8s currently. Failing to get ready in this time
- * isn't critical. It will result in reset failure for
- * controllers which can't wait for the first D2H FIS. libata
- * will retry, so it just has to be long enough to spin up
- * most devices.
- */
- ATA_SPINUP_WAIT = 8000,
-
/* Horkage types. May be set by libata or controller on drives
(some horkage may be drive/controller pair dependant */
@@ -345,8 +338,9 @@ struct ata_queued_cmd;
/* typedefs */
typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
-typedef int (*ata_prereset_fn_t)(struct ata_port *ap);
-typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes);
+typedef int (*ata_prereset_fn_t)(struct ata_port *ap, unsigned long deadline);
+typedef int (*ata_reset_fn_t)(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline);
typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *classes);
struct ata_ioports {
@@ -367,34 +361,6 @@ struct ata_ioports {
void __iomem *scr_addr;
};
-struct ata_probe_ent {
- struct list_head node;
- struct device *dev;
- const struct ata_port_operations *port_ops;
- struct scsi_host_template *sht;
- struct ata_ioports port[ATA_MAX_PORTS];
- unsigned int n_ports;
- unsigned int dummy_port_mask;
- unsigned int pio_mask;
- unsigned int mwdma_mask;
- unsigned int udma_mask;
- unsigned long irq;
- unsigned long irq2;
- unsigned int irq_flags;
- unsigned long port_flags;
- unsigned long _host_flags;
- void __iomem * const *iomap;
- void *private_data;
-
- /* port_info for the secondary port. Together with irq2, it's
- * used to implement non-uniform secondary port. Currently,
- * the only user is ata_piix combined mode. This workaround
- * will be removed together with ata_probe_ent when init model
- * is updated.
- */
- const struct ata_port_info *pinfo2;
-};
-
struct ata_host {
spinlock_t lock;
struct device *dev;
@@ -427,6 +393,7 @@ struct ata_queued_cmd {
int dma_dir;
unsigned int pad_len;
+ unsigned int sect_size;
unsigned int nbytes;
unsigned int curbytes;
@@ -472,6 +439,7 @@ struct ata_device {
struct scsi_device *sdev; /* attached SCSI device */
/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
u64 n_sectors; /* size of device, if ATA */
+ u64 n_sectors_boot; /* size of ATA device at startup */
unsigned int class; /* ATA_DEV_xxx */
u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
u8 pio_mode;
@@ -517,7 +485,6 @@ struct ata_eh_info {
unsigned int dev_action[ATA_MAX_DEVICES]; /* dev EH action */
unsigned int flags; /* ATA_EHI_* flags */
- unsigned long hotplug_timestamp;
unsigned int probe_mask;
char desc[ATA_EH_DESC_LEN];
@@ -597,11 +564,11 @@ struct ata_port {
struct ata_port_operations {
void (*port_disable) (struct ata_port *);
- void (*dev_config) (struct ata_port *, struct ata_device *);
+ void (*dev_config) (struct ata_device *);
void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (struct ata_port *, struct ata_device *);
- unsigned long (*mode_filter) (const struct ata_port *, struct ata_device *, unsigned long);
+ unsigned long (*mode_filter) (struct ata_device *, unsigned long);
void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf);
void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
@@ -616,6 +583,8 @@ struct ata_port_operations {
void (*post_set_mode) (struct ata_port *ap);
+ int (*cable_detect) (struct ata_port *ap);
+
int (*check_atapi_dma) (struct ata_queued_cmd *qc);
void (*bmdma_setup) (struct ata_queued_cmd *qc);
@@ -664,6 +633,7 @@ struct ata_port_info {
unsigned long mwdma_mask;
unsigned long udma_mask;
const struct ata_port_operations *port_ops;
+ irq_handler_t irq_handler;
void *private_data;
};
@@ -686,6 +656,7 @@ extern const unsigned long sata_deb_timing_hotplug[];
extern const unsigned long sata_deb_timing_long[];
extern const struct ata_port_operations ata_dummy_port_ops;
+extern const struct ata_port_info ata_dummy_port_info;
static inline const unsigned long *
sata_ehc_deb_timing(struct ata_eh_context *ehc)
@@ -701,18 +672,23 @@ static inline int ata_port_is_dummy(struct ata_port *ap)
return ap->ops == &ata_dummy_port_ops;
}
+extern void sata_print_link_status(struct ata_port *ap);
extern void ata_port_probe(struct ata_port *);
extern void __sata_phy_reset(struct ata_port *ap);
extern void sata_phy_reset(struct ata_port *ap);
extern void ata_bus_reset(struct ata_port *ap);
extern int sata_set_spd(struct ata_port *ap);
-extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param);
-extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param);
-extern int ata_std_prereset(struct ata_port *ap);
-extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes);
-extern int sata_port_hardreset(struct ata_port *ap,
- const unsigned long *timing);
-extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class);
+extern int sata_phy_debounce(struct ata_port *ap, const unsigned long *param,
+ unsigned long deadline);
+extern int sata_phy_resume(struct ata_port *ap, const unsigned long *param,
+ unsigned long deadline);
+extern int ata_std_prereset(struct ata_port *ap, unsigned long deadline);
+extern int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+ unsigned long deadline);
+extern int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+ unsigned long deadline);
+extern int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline);
extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
extern void ata_port_disable(struct ata_port *);
extern void ata_std_ports(struct ata_ioports *ioaddr);
@@ -728,7 +704,15 @@ extern int ata_pci_device_resume(struct pci_dev *pdev);
#endif
extern int ata_pci_clear_simplex(struct pci_dev *pdev);
#endif /* CONFIG_PCI */
-extern int ata_device_add(const struct ata_probe_ent *ent);
+extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
+extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
+ const struct ata_port_info * const * ppi, int n_ports);
+extern int ata_host_start(struct ata_host *host);
+extern int ata_host_register(struct ata_host *host,
+ struct scsi_host_template *sht);
+extern int ata_host_activate(struct ata_host *host, int irq,
+ irq_handler_t irq_handler, unsigned long irq_flags,
+ struct scsi_host_template *sht);
extern void ata_host_detach(struct ata_host *host);
extern void ata_host_init(struct ata_host *, struct device *,
unsigned long, const struct ata_port_operations *);
@@ -760,6 +744,7 @@ extern void ata_host_resume(struct ata_host *host);
extern int ata_ratelimit(void);
extern int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout_pat, unsigned long timeout);
+extern int ata_wait_ready(struct ata_port *ap, unsigned long deadline);
extern void ata_port_queue_task(struct ata_port *ap, work_func_t fn,
void *data, unsigned long delay);
extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
@@ -828,11 +813,17 @@ extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
int queue_depth);
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
+extern int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
extern u8 ata_irq_on(struct ata_port *ap);
extern u8 ata_dummy_irq_on(struct ata_port *ap);
extern u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq);
extern u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq);
+extern int ata_cable_40wire(struct ata_port *ap);
+extern int ata_cable_80wire(struct ata_port *ap);
+extern int ata_cable_sata(struct ata_port *ap);
+extern int ata_cable_unknown(struct ata_port *ap);
+
/*
* Timing helpers
*/
@@ -870,10 +861,13 @@ struct pci_bits {
unsigned long val;
};
-extern struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask);
+extern int ata_pci_init_native_host(struct ata_host *host,
+ unsigned int port_mask);
+extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi,
+ int n_ports, struct ata_host **r_host);
extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
-extern unsigned long ata_pci_default_filter(const struct ata_port *, struct ata_device *, unsigned long);
+extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
#endif /* CONFIG_PCI */
/*
@@ -920,12 +914,7 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
- if (ehi->flags & ATA_EHI_HOTPLUGGED)
- return;
-
ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
- ehi->hotplug_timestamp = jiffies;
-
ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
}
@@ -1173,6 +1162,7 @@ static inline void ata_qc_reinit(struct ata_queued_cmd *qc)
qc->n_elem = 0;
qc->err_mask = 0;
qc->pad_len = 0;
+ qc->sect_size = ATA_SECT_SIZE;
ata_tf_init(qc->dev, &qc->tf);
@@ -1220,7 +1210,7 @@ static inline void ata_pad_free(struct ata_port *ap, struct device *dev)
static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
{
- return (struct ata_port *) &host->hostdata[0];
+ return *(struct ata_port **)&host->hostdata[0];
}
#endif /* __LINUX_LIBATA_H__ */
diff --git a/include/linux/list.h b/include/linux/list.h
index f9d71eab05e..9202703be2a 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -426,6 +426,17 @@ static inline void list_splice_init_rcu(struct list_head *list,
container_of(ptr, type, member)
/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index ac25b5649c5..05707e2fcca 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -88,7 +88,7 @@ struct nlm_wait;
/*
* Memory chunk for NLM client RPC request.
*/
-#define NLMCLNT_OHSIZE (sizeof(utsname()->nodename)+10)
+#define NLMCLNT_OHSIZE ((__NEW_UTS_LEN) + 10u)
struct nlm_rqst {
unsigned int a_flags; /* initial RPC task flags */
struct nlm_host * a_host; /* host handle */
@@ -119,6 +119,9 @@ struct nlm_file {
* couldn't be granted because of a conflicting lock).
*/
#define NLM_NEVER (~(unsigned long) 0)
+/* timeout on non-blocking call: */
+#define NLM_TIMEOUT (7 * HZ)
+
struct nlm_block {
struct kref b_count; /* Reference count */
struct list_head b_list; /* linked list of all blocks */
@@ -130,6 +133,13 @@ struct nlm_block {
unsigned int b_id; /* block id */
unsigned char b_granted; /* VFS granted lock */
struct nlm_file * b_file; /* file in question */
+ struct cache_req * b_cache_req; /* deferred request handling */
+ struct file_lock * b_fl; /* set for GETLK */
+ struct cache_deferred_req * b_deferred_req;
+ unsigned int b_flags; /* block flags */
+#define B_QUEUED 1 /* lock queued */
+#define B_GOT_CALLBACK 2 /* got lock or conflicting lock */
+#define B_TIMED_OUT 4 /* filesystem too slow to respond */
};
/*
@@ -185,8 +195,8 @@ typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref)
__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_lock *, int, struct nlm_cookie *);
__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
-__be32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
- struct nlm_lock *);
+__be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
+ struct nlm_lock *, struct nlm_lock *, struct nlm_cookie *);
__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
unsigned long nlmsvc_retry_blocked(void);
void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
diff --git a/include/linux/loop.h b/include/linux/loop.h
index 191a595055f..0b99b31f017 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -64,6 +64,8 @@ struct loop_device {
wait_queue_head_t lo_event;
request_queue_t *lo_queue;
+ struct gendisk *lo_disk;
+ struct list_head lo_list;
};
#endif /* __KERNEL__ */
diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h
index bdc01127dce..580b3f4956e 100644
--- a/include/linux/mc146818rtc.h
+++ b/include/linux/mc146818rtc.h
@@ -22,8 +22,15 @@ extern spinlock_t rtc_lock; /* serialize CMOS RAM access */
/* Some RTCs extend the mc146818 register set to support alarms of more
* than 24 hours in the future; or dates that include a century code.
* This platform_data structure can pass this information to the driver.
+ *
+ * Also, some platforms need suspend()/resume() hooks to kick in special
+ * handling of wake alarms, e.g. activating ACPI BIOS hooks or setting up
+ * a separate wakeup alarm used by some almost-clone chips.
*/
struct cmos_rtc_board_info {
+ void (*wake_on)(struct device *dev);
+ void (*wake_off)(struct device *dev);
+
u8 rtc_day_alarm; /* zero, or register index */
u8 rtc_mon_alarm; /* zero, or register index */
u8 rtc_century; /* zero, or register index */
diff --git a/include/linux/mca.h b/include/linux/mca.h
index 5cff2923092..37972704617 100644
--- a/include/linux/mca.h
+++ b/include/linux/mca.h
@@ -94,6 +94,7 @@ struct mca_bus {
struct mca_driver {
const short *id_table;
void *driver_data;
+ int integrated_id;
struct device_driver driver;
};
#define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
@@ -125,6 +126,7 @@ extern enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev);
extern struct bus_type mca_bus_type;
extern int mca_register_driver(struct mca_driver *drv);
+extern int mca_register_driver_integrated(struct mca_driver *, int);
extern void mca_unregister_driver(struct mca_driver *drv);
/* WARNING: only called by the boot time device setup */
diff --git a/include/linux/meye.h b/include/linux/meye.h
index 11ec45e9a13..39fd9c8ddd4 100644
--- a/include/linux/meye.h
+++ b/include/linux/meye.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001-2003 Stelian Pop <stelian@popies.net>
*
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
*
* Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
*
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 75e55dcdeb1..e10a90a93b5 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -2,18 +2,29 @@
#define _LINUX_MIGRATE_H
#include <linux/mm.h>
+#include <linux/mempolicy.h>
+#include <linux/pagemap.h>
typedef struct page *new_page_t(struct page *, unsigned long private, int **);
+#ifdef CONFIG_MIGRATION
/* Check if a vma is migratable */
static inline int vma_migratable(struct vm_area_struct *vma)
{
if (vma->vm_flags & (VM_IO|VM_HUGETLB|VM_PFNMAP|VM_RESERVED))
return 0;
+ /*
+ * Migration allocates pages in the highest zone. If we cannot
+ * do so then migration (at least from node to node) is not
+ * possible.
+ */
+ if (vma->vm_file &&
+ gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping))
+ < policy_zone)
+ return 0;
return 1;
}
-#ifdef CONFIG_MIGRATION
extern int isolate_lru_page(struct page *p, struct list_head *pagelist);
extern int putback_lru_pages(struct list_head *l);
extern int migrate_page(struct address_space *,
@@ -28,6 +39,8 @@ extern int migrate_vmas(struct mm_struct *mm,
const nodemask_t *from, const nodemask_t *to,
unsigned long flags);
#else
+static inline int vma_migratable(struct vm_area_struct *vma)
+ { return 0; }
static inline int isolate_lru_page(struct page *p, struct list_head *list)
{ return -ENOSYS; }
diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h
index 326da7d500c..dff9ea32606 100644
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -29,6 +29,7 @@
#define TUN_MINOR 200
#define HPET_MINOR 228
+#define KVM_MINOR 232
struct device;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 60e0e4a592d..4670ebd1f62 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -267,21 +267,31 @@ static inline int get_page_unless_zero(struct page *page)
return atomic_inc_not_zero(&page->_count);
}
+static inline struct page *compound_head(struct page *page)
+{
+ if (unlikely(PageTail(page)))
+ return page->first_page;
+ return page;
+}
+
static inline int page_count(struct page *page)
{
- if (unlikely(PageCompound(page)))
- page = (struct page *)page_private(page);
- return atomic_read(&page->_count);
+ return atomic_read(&compound_head(page)->_count);
}
static inline void get_page(struct page *page)
{
- if (unlikely(PageCompound(page)))
- page = (struct page *)page_private(page);
+ page = compound_head(page);
VM_BUG_ON(atomic_read(&page->_count) == 0);
atomic_inc(&page->_count);
}
+static inline struct page *virt_to_head_page(const void *x)
+{
+ struct page *page = virt_to_page(x);
+ return compound_head(page);
+}
+
/*
* Setup the page count before being freed into the page allocator for
* the first time (boot or memory hotplug)
@@ -314,6 +324,18 @@ static inline compound_page_dtor *get_compound_page_dtor(struct page *page)
return (compound_page_dtor *)page[1].lru.next;
}
+static inline int compound_order(struct page *page)
+{
+ if (!PageHead(page))
+ return 0;
+ return (unsigned long)page[1].lru.prev;
+}
+
+static inline void set_compound_order(struct page *page, unsigned long order)
+{
+ page[1].lru.prev = (void *)order;
+}
+
/*
* Multiple processes may "see" the same page. E.g. for untouched
* mappings of /dev/null, all processes see the same page full of
@@ -850,8 +872,26 @@ static inline int vma_wants_writenotify(struct vm_area_struct *vma)
extern pte_t *FASTCALL(get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl));
+#ifdef __PAGETABLE_PUD_FOLDED
+static inline int __pud_alloc(struct mm_struct *mm, pgd_t *pgd,
+ unsigned long address)
+{
+ return 0;
+}
+#else
int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address);
+#endif
+
+#ifdef __PAGETABLE_PMD_FOLDED
+static inline int __pmd_alloc(struct mm_struct *mm, pud_t *pud,
+ unsigned long address)
+{
+ return 0;
+}
+#else
int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address);
+#endif
+
int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address);
int __pte_alloc_kernel(pmd_t *pmd, unsigned long address);
@@ -1130,6 +1170,11 @@ struct page *follow_page(struct vm_area_struct *, unsigned long address,
#define FOLL_GET 0x04 /* do get_page on page */
#define FOLL_ANON 0x08 /* give ZERO_PAGE if no pgtable */
+typedef int (*pte_fn_t)(pte_t *pte, struct page *pmd_page, unsigned long addr,
+ void *data);
+extern int apply_to_page_range(struct mm_struct *mm, unsigned long address,
+ unsigned long size, pte_fn_t fn, void *data);
+
#ifdef CONFIG_PROC_FS
void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
#else
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index c3852fd4a1c..e30687bad07 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -19,10 +19,16 @@ struct page {
unsigned long flags; /* Atomic flags, some possibly
* updated asynchronously */
atomic_t _count; /* Usage count, see below. */
- atomic_t _mapcount; /* Count of ptes mapped in mms,
+ union {
+ atomic_t _mapcount; /* Count of ptes mapped in mms,
* to show when page is mapped
* & limit reverse map searches.
*/
+ struct { /* SLUB uses */
+ short unsigned int inuse;
+ short unsigned int offset;
+ };
+ };
union {
struct {
unsigned long private; /* Mapping-private opaque data:
@@ -43,8 +49,15 @@ struct page {
#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
spinlock_t ptl;
#endif
+ struct { /* SLUB uses */
+ struct page *first_page; /* Compound pages */
+ struct kmem_cache *slab; /* Pointer to slab */
+ };
+ };
+ union {
+ pgoff_t index; /* Our offset within mapping. */
+ void *freelist; /* SLUB: pointer to free object */
};
- pgoff_t index; /* Our offset within mapping. */
struct list_head lru; /* Pageout list, eg. active_list
* protected by zone->lru_lock !
*/
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index e45712acfac..badf702fcff 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -10,7 +10,7 @@
#ifndef LINUX_MMC_CARD_H
#define LINUX_MMC_CARD_H
-#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
struct mmc_cid {
unsigned int manfid;
@@ -41,6 +41,7 @@ struct mmc_csd {
struct mmc_ext_csd {
unsigned int hs_max_dtr;
+ unsigned int sectors;
};
struct sd_scr {
@@ -60,18 +61,17 @@ struct mmc_host;
* MMC device
*/
struct mmc_card {
- struct list_head node; /* node in hosts devices list */
struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */
unsigned int rca; /* relative card address of device */
+ unsigned int type; /* card type */
+#define MMC_TYPE_MMC 0 /* MMC card */
+#define MMC_TYPE_SD 1 /* SD card */
unsigned int state; /* (our) card state */
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
-#define MMC_STATE_DEAD (1<<1) /* device no longer in stack */
-#define MMC_STATE_BAD (1<<2) /* unrecognised device */
-#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
-#define MMC_STATE_READONLY (1<<4) /* card is read-only */
-#define MMC_STATE_HIGHSPEED (1<<5) /* card is in high speed mode */
-#define MMC_STATE_BLOCKADDR (1<<6) /* card uses block-addressing */
+#define MMC_STATE_READONLY (1<<1) /* card is read-only */
+#define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
@@ -82,18 +82,15 @@ struct mmc_card {
struct sd_switch_caps sw_caps; /* switch (CMD6) caps */
};
+#define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC)
+#define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD)
+
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
-#define mmc_card_dead(c) ((c)->state & MMC_STATE_DEAD)
-#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
-#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
-#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
-#define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD)
-#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
@@ -119,11 +116,4 @@ struct mmc_driver {
extern int mmc_register_driver(struct mmc_driver *);
extern void mmc_unregister_driver(struct mmc_driver *);
-static inline int mmc_card_claim_host(struct mmc_card *card)
-{
- return __mmc_claim_host(card->host, card);
-}
-
-#define mmc_card_release_host(c) mmc_release_host((c)->host)
-
#endif
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
new file mode 100644
index 00000000000..04bbe12fae8
--- /dev/null
+++ b/include/linux/mmc/core.h
@@ -0,0 +1,112 @@
+/*
+ * linux/include/linux/mmc/core.h
+ *
+ * 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.
+ */
+#ifndef LINUX_MMC_CORE_H
+#define LINUX_MMC_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+
+struct request;
+struct mmc_data;
+struct mmc_request;
+
+struct mmc_command {
+ u32 opcode;
+ u32 arg;
+ u32 resp[4];
+ unsigned int flags; /* expected response type */
+#define MMC_RSP_PRESENT (1 << 0)
+#define MMC_RSP_136 (1 << 1) /* 136 bit response */
+#define MMC_RSP_CRC (1 << 2) /* expect valid crc */
+#define MMC_RSP_BUSY (1 << 3) /* card may send busy */
+#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */
+#define MMC_CMD_MASK (3 << 5) /* command type */
+#define MMC_CMD_AC (0 << 5)
+#define MMC_CMD_ADTC (1 << 5)
+#define MMC_CMD_BC (2 << 5)
+#define MMC_CMD_BCR (3 << 5)
+
+/*
+ * These are the response types, and correspond to valid bit
+ * patterns of the above flags. One additional valid pattern
+ * is all zeros, which means we don't expect a response.
+ */
+#define MMC_RSP_NONE (0)
+#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
+#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+#define MMC_RSP_R3 (MMC_RSP_PRESENT)
+#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+
+#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
+
+/*
+ * These are the command types.
+ */
+#define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK)
+
+ unsigned int retries; /* max number of retries */
+ unsigned int error; /* command error */
+
+#define MMC_ERR_NONE 0
+#define MMC_ERR_TIMEOUT 1
+#define MMC_ERR_BADCRC 2
+#define MMC_ERR_FIFO 3
+#define MMC_ERR_FAILED 4
+#define MMC_ERR_INVALID 5
+
+ struct mmc_data *data; /* data segment associated with cmd */
+ struct mmc_request *mrq; /* associated request */
+};
+
+struct mmc_data {
+ unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
+ unsigned int timeout_clks; /* data timeout (in clocks) */
+ unsigned int blksz; /* data block size */
+ unsigned int blocks; /* number of blocks */
+ unsigned int error; /* data error */
+ unsigned int flags;
+
+#define MMC_DATA_WRITE (1 << 8)
+#define MMC_DATA_READ (1 << 9)
+#define MMC_DATA_STREAM (1 << 10)
+#define MMC_DATA_MULTI (1 << 11)
+
+ unsigned int bytes_xfered;
+
+ struct mmc_command *stop; /* stop command */
+ struct mmc_request *mrq; /* associated request */
+
+ unsigned int sg_len; /* size of scatter list */
+ struct scatterlist *sg; /* I/O scatter list */
+};
+
+struct mmc_request {
+ struct mmc_command *cmd;
+ struct mmc_data *data;
+ struct mmc_command *stop;
+
+ void *done_data; /* completion data */
+ void (*done)(struct mmc_request *);/* completion function */
+};
+
+struct mmc_host;
+struct mmc_card;
+
+extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
+extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
+extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
+ struct mmc_command *, int);
+
+extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int);
+
+extern void mmc_claim_host(struct mmc_host *host);
+extern void mmc_release_host(struct mmc_host *host);
+
+#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index bfcef8a1ad8..b1350dfd3e9 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -10,36 +10,13 @@
#ifndef LINUX_MMC_HOST_H
#define LINUX_MMC_HOST_H
-#include <linux/mmc/mmc.h>
+#include <linux/mmc/core.h>
struct mmc_ios {
unsigned int clock; /* clock rate */
unsigned short vdd;
-#define MMC_VDD_150 0
-#define MMC_VDD_155 1
-#define MMC_VDD_160 2
-#define MMC_VDD_165 3
-#define MMC_VDD_170 4
-#define MMC_VDD_180 5
-#define MMC_VDD_190 6
-#define MMC_VDD_200 7
-#define MMC_VDD_210 8
-#define MMC_VDD_220 9
-#define MMC_VDD_230 10
-#define MMC_VDD_240 11
-#define MMC_VDD_250 12
-#define MMC_VDD_260 13
-#define MMC_VDD_270 14
-#define MMC_VDD_280 15
-#define MMC_VDD_290 16
-#define MMC_VDD_300 17
-#define MMC_VDD_310 18
-#define MMC_VDD_320 19
-#define MMC_VDD_330 20
-#define MMC_VDD_340 21
-#define MMC_VDD_350 22
-#define MMC_VDD_360 23
+/* vdd stores the bit number of the selected voltage range from below. */
unsigned char bus_mode; /* command output mode */
@@ -88,6 +65,24 @@ struct mmc_host {
unsigned int f_max;
u32 ocr_avail;
+#define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
+#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
+#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
+#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
+#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
+#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
+#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
+#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
+#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
+#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
+#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
+#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
+#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
+#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
+#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
+#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
+#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
+
unsigned long caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
@@ -106,6 +101,8 @@ struct mmc_host {
unsigned int max_blk_count; /* maximum number of blocks in one req */
/* private data */
+ spinlock_t lock; /* lock for claim and bus ops */
+
struct mmc_ios ios; /* current io bus settings */
u32 ocr; /* the current OCR setting */
@@ -113,15 +110,19 @@ struct mmc_host {
#define MMC_MODE_MMC 0
#define MMC_MODE_SD 1
- struct list_head cards; /* devices attached to this host */
+ struct mmc_card *card; /* device attached to this host */
wait_queue_head_t wq;
- spinlock_t lock; /* claimed lock */
unsigned int claimed:1; /* host exclusively claimed */
- struct mmc_card *card_selected; /* the selected MMC card */
-
struct delayed_work detect;
+#ifdef CONFIG_MMC_DEBUG
+ unsigned int removed:1; /* host is being removed */
+#endif
+
+ const struct mmc_bus_ops *bus_ops; /* current bus driver */
+ unsigned int bus_refs; /* reference counter */
+ unsigned int bus_dead:1; /* bus has been released */
unsigned long private[0] ____cacheline_aligned;
};
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index cdc54be804f..e3ed9b95040 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -1,119 +1,257 @@
/*
- * linux/include/linux/mmc/mmc.h
+ * Header for MultiMediaCard (MMC)
*
- * 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.
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/18 12:37:30 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
*/
-#ifndef MMC_H
-#define MMC_H
-
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-
-struct request;
-struct mmc_data;
-struct mmc_request;
-
-struct mmc_command {
- u32 opcode;
- u32 arg;
- u32 resp[4];
- unsigned int flags; /* expected response type */
-#define MMC_RSP_PRESENT (1 << 0)
-#define MMC_RSP_136 (1 << 1) /* 136 bit response */
-#define MMC_RSP_CRC (1 << 2) /* expect valid crc */
-#define MMC_RSP_BUSY (1 << 3) /* card may send busy */
-#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */
-#define MMC_CMD_MASK (3 << 5) /* command type */
-#define MMC_CMD_AC (0 << 5)
-#define MMC_CMD_ADTC (1 << 5)
-#define MMC_CMD_BC (2 << 5)
-#define MMC_CMD_BCR (3 << 5)
+
+#ifndef MMC_MMC_H
+#define MMC_MMC_H
+
+/* Standard MMC commands (4.1) type argument response */
+ /* class 1 */
+#define MMC_GO_IDLE_STATE 0 /* bc */
+#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
+#define MMC_ALL_SEND_CID 2 /* bcr R2 */
+#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
+#define MMC_SET_DSR 4 /* bc [31:16] RCA */
+#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
+#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
+#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
+#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
+#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
+#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
+#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
+#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
+#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
+
+ /* class 2 */
+#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
+#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
+#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
+
+ /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
+
+ /* class 4 */
+#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
+#define MMC_PROGRAM_CID 26 /* adtc R1 */
+#define MMC_PROGRAM_CSD 27 /* adtc R1 */
+
+ /* class 6 */
+#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
+#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
+#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
+
+ /* class 5 */
+#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
+#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
+#define MMC_ERASE 38 /* ac R1b */
+
+ /* class 9 */
+#define MMC_FAST_IO 39 /* ac <Complex> R4 */
+#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
+
+ /* class 7 */
+#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
+
+ /* class 8 */
+#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
+#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
/*
- * These are the response types, and correspond to valid bit
- * patterns of the above flags. One additional valid pattern
- * is all zeros, which means we don't expect a response.
+ * MMC_SWITCH argument format:
+ *
+ * [31:26] Always 0
+ * [25:24] Access Mode
+ * [23:16] Location of target Byte in EXT_CSD
+ * [15:08] Value Byte
+ * [07:03] Always 0
+ * [02:00] Command Set
*/
-#define MMC_RSP_NONE (0)
-#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
-#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
-#define MMC_RSP_R3 (MMC_RSP_PRESENT)
-#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-#define MMC_RSP_R7 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-
-#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
/*
- * These are the command types.
+ MMC status in R1
+ Type
+ e : error bit
+ s : status bit
+ r : detected and set for the actual command response
+ x : detected and set during command execution. the host must poll
+ the card by sending status command in order to read these bits.
+ Clear condition
+ a : according to the card state
+ b : always related to the previous command. Reception of
+ a valid command will clear it (with a delay of one command)
+ c : clear by read
*/
-#define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK)
- unsigned int retries; /* max number of retries */
- unsigned int error; /* command error */
+#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
+#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
+#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
+#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
+#define R1_ERASE_PARAM (1 << 27) /* ex, c */
+#define R1_WP_VIOLATION (1 << 26) /* erx, c */
+#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
+#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
+#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
+#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
+#define R1_CC_ERROR (1 << 20) /* erx, c */
+#define R1_ERROR (1 << 19) /* erx, c */
+#define R1_UNDERRUN (1 << 18) /* ex, c */
+#define R1_OVERRUN (1 << 17) /* ex, c */
+#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
+#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
+#define R1_ERASE_RESET (1 << 13) /* sr, c */
+#define R1_STATUS(x) (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
+#define R1_APP_CMD (1 << 5) /* sr, c */
-#define MMC_ERR_NONE 0
-#define MMC_ERR_TIMEOUT 1
-#define MMC_ERR_BADCRC 2
-#define MMC_ERR_FIFO 3
-#define MMC_ERR_FAILED 4
-#define MMC_ERR_INVALID 5
+/* These are unpacked versions of the actual responses */
- struct mmc_data *data; /* data segment associated with cmd */
- struct mmc_request *mrq; /* associated request */
+struct _mmc_csd {
+ u8 csd_structure;
+ u8 spec_vers;
+ u8 taac;
+ u8 nsac;
+ u8 tran_speed;
+ u16 ccc;
+ u8 read_bl_len;
+ u8 read_bl_partial;
+ u8 write_blk_misalign;
+ u8 read_blk_misalign;
+ u8 dsr_imp;
+ u16 c_size;
+ u8 vdd_r_curr_min;
+ u8 vdd_r_curr_max;
+ u8 vdd_w_curr_min;
+ u8 vdd_w_curr_max;
+ u8 c_size_mult;
+ union {
+ struct { /* MMC system specification version 3.1 */
+ u8 erase_grp_size;
+ u8 erase_grp_mult;
+ } v31;
+ struct { /* MMC system specification version 2.2 */
+ u8 sector_size;
+ u8 erase_grp_size;
+ } v22;
+ } erase;
+ u8 wp_grp_size;
+ u8 wp_grp_enable;
+ u8 default_ecc;
+ u8 r2w_factor;
+ u8 write_bl_len;
+ u8 write_bl_partial;
+ u8 file_format_grp;
+ u8 copy;
+ u8 perm_write_protect;
+ u8 tmp_write_protect;
+ u8 file_format;
+ u8 ecc;
};
-struct mmc_data {
- unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
- unsigned int timeout_clks; /* data timeout (in clocks) */
- unsigned int blksz; /* data block size */
- unsigned int blocks; /* number of blocks */
- unsigned int error; /* data error */
- unsigned int flags;
+/*
+ * OCR bits are mostly in host.h
+ */
+#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
-#define MMC_DATA_WRITE (1 << 8)
-#define MMC_DATA_READ (1 << 9)
-#define MMC_DATA_STREAM (1 << 10)
-#define MMC_DATA_MULTI (1 << 11)
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
+ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */
+ /* (CMD11) */
+#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */
+ /* (CMD16,17,18) */
+#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */
+ /* (CMD20) */
+#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */
+ /* (CMD16,24,25,26,27) */
+#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */
+ /* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */
+ /* (CMD28,29,30) */
+#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */
+ /* (CMD16,CMD42) */
+#define CCC_APP_SPEC (1<<8) /* (8) Application specific */
+ /* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE (1<<9) /* (9) I/O mode */
+ /* (CMD5,39,40,52,53) */
+#define CCC_SWITCH (1<<10) /* (10) High speed switch */
+ /* (CMD6,34,35,36,37,50) */
+ /* (11) Reserved */
+ /* (CMD?) */
- unsigned int bytes_xfered;
+/*
+ * CSD field definitions
+ */
- struct mmc_command *stop; /* stop command */
- struct mmc_request *mrq; /* associated request */
+#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
- unsigned int sg_len; /* size of scatter list */
- struct scatterlist *sg; /* I/O scatter list */
-};
+#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
-struct mmc_request {
- struct mmc_command *cmd;
- struct mmc_data *data;
- struct mmc_command *stop;
+/*
+ * EXT_CSD fields
+ */
- void *done_data; /* completion data */
- void (*done)(struct mmc_request *);/* completion function */
-};
+#define EXT_CSD_BUS_WIDTH 183 /* R/W */
+#define EXT_CSD_HS_TIMING 185 /* R/W */
+#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+
+/*
+ * EXT_CSD field definitions
+ */
-struct mmc_host;
-struct mmc_card;
+#define EXT_CSD_CMD_SET_NORMAL (1<<0)
+#define EXT_CSD_CMD_SET_SECURE (1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
-extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
-extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
-extern int mmc_wait_for_app_cmd(struct mmc_host *, unsigned int,
- struct mmc_command *, int);
+#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
-extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *, int);
+#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
-extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
+/*
+ * MMC_SWITCH access modes
+ */
-static inline void mmc_claim_host(struct mmc_host *host)
-{
- __mmc_claim_host(host, (struct mmc_card *)-1);
-}
+#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
+#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
+#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
-extern void mmc_release_host(struct mmc_host *host);
+#endif /* MMC_MMC_PROTOCOL_H */
-#endif
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
deleted file mode 100644
index c90b6768329..00000000000
--- a/include/linux/mmc/protocol.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Header for MultiMediaCard (MMC)
- *
- * Copyright 2002 Hewlett-Packard Company
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Many thanks to Alessandro Rubini and Jonathan Corbet!
- *
- * Based strongly on code by:
- *
- * Author: Yong-iL Joh <tolkien@mizi.com>
- * Date : $Date: 2002/06/18 12:37:30 $
- *
- * Author: Andrew Christian
- * 15 May 2002
- */
-
-#ifndef MMC_MMC_PROTOCOL_H
-#define MMC_MMC_PROTOCOL_H
-
-/* Standard MMC commands (4.1) type argument response */
- /* class 1 */
-#define MMC_GO_IDLE_STATE 0 /* bc */
-#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
-#define MMC_ALL_SEND_CID 2 /* bcr R2 */
-#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
-#define MMC_SET_DSR 4 /* bc [31:16] RCA */
-#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
-#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
-#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
-#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
-#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
-#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
-#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
-#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
-#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
-
- /* class 2 */
-#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
-#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
-#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
-
- /* class 3 */
-#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
-
- /* class 4 */
-#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
-#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
-#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
-#define MMC_PROGRAM_CID 26 /* adtc R1 */
-#define MMC_PROGRAM_CSD 27 /* adtc R1 */
-
- /* class 6 */
-#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
-#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
-#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
-
- /* class 5 */
-#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
-#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
-#define MMC_ERASE 38 /* ac R1b */
-
- /* class 9 */
-#define MMC_FAST_IO 39 /* ac <Complex> R4 */
-#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
-
- /* class 7 */
-#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
-
- /* class 8 */
-#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
-#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
-
-/* SD commands type argument response */
- /* class 0 */
-/* This is basically the same command as for MMC with some quirks. */
-#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
-#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
-
- /* class 10 */
-#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
-
- /* Application commands */
-#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
-#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
-#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
-#define SD_APP_SEND_SCR 51 /* adtc R1 */
-
-/*
- * MMC_SWITCH argument format:
- *
- * [31:26] Always 0
- * [25:24] Access Mode
- * [23:16] Location of target Byte in EXT_CSD
- * [15:08] Value Byte
- * [07:03] Always 0
- * [02:00] Command Set
- */
-
-/*
- * SD_SWITCH argument format:
- *
- * [31] Check (0) or switch (1)
- * [30:24] Reserved (0)
- * [23:20] Function group 6
- * [19:16] Function group 5
- * [15:12] Function group 4
- * [11:8] Function group 3
- * [7:4] Function group 2
- * [3:0] Function group 1
- */
-
-/*
- * SD_SEND_IF_COND argument format:
- *
- * [31:12] Reserved (0)
- * [11:8] Host Voltage Supply Flags
- * [7:0] Check Pattern (0xAA)
- */
-
-/*
- MMC status in R1
- Type
- e : error bit
- s : status bit
- r : detected and set for the actual command response
- x : detected and set during command execution. the host must poll
- the card by sending status command in order to read these bits.
- Clear condition
- a : according to the card state
- b : always related to the previous command. Reception of
- a valid command will clear it (with a delay of one command)
- c : clear by read
- */
-
-#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
-#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
-#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
-#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
-#define R1_ERASE_PARAM (1 << 27) /* ex, c */
-#define R1_WP_VIOLATION (1 << 26) /* erx, c */
-#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
-#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
-#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
-#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
-#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
-#define R1_CC_ERROR (1 << 20) /* erx, c */
-#define R1_ERROR (1 << 19) /* erx, c */
-#define R1_UNDERRUN (1 << 18) /* ex, c */
-#define R1_OVERRUN (1 << 17) /* ex, c */
-#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
-#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
-#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
-#define R1_ERASE_RESET (1 << 13) /* sr, c */
-#define R1_STATUS(x) (x & 0xFFFFE000)
-#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
-#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
-#define R1_APP_CMD (1 << 5) /* sr, c */
-
-/* These are unpacked versions of the actual responses */
-
-struct _mmc_csd {
- u8 csd_structure;
- u8 spec_vers;
- u8 taac;
- u8 nsac;
- u8 tran_speed;
- u16 ccc;
- u8 read_bl_len;
- u8 read_bl_partial;
- u8 write_blk_misalign;
- u8 read_blk_misalign;
- u8 dsr_imp;
- u16 c_size;
- u8 vdd_r_curr_min;
- u8 vdd_r_curr_max;
- u8 vdd_w_curr_min;
- u8 vdd_w_curr_max;
- u8 c_size_mult;
- union {
- struct { /* MMC system specification version 3.1 */
- u8 erase_grp_size;
- u8 erase_grp_mult;
- } v31;
- struct { /* MMC system specification version 2.2 */
- u8 sector_size;
- u8 erase_grp_size;
- } v22;
- } erase;
- u8 wp_grp_size;
- u8 wp_grp_enable;
- u8 default_ecc;
- u8 r2w_factor;
- u8 write_bl_len;
- u8 write_bl_partial;
- u8 file_format_grp;
- u8 copy;
- u8 perm_write_protect;
- u8 tmp_write_protect;
- u8 file_format;
- u8 ecc;
-};
-
-#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */
-#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */
-#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */
-#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */
-#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */
-#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */
-#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */
-#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */
-#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
-#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
-#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
-#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
-#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
-#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
-#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
-#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
-#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
-#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
-#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
-#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
-#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
-#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
-#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
-#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
-#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
-
-/*
- * Card Command Classes (CCC)
- */
-#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
- /* (CMD0,1,2,3,4,7,9,10,12,13,15) */
-#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */
- /* (CMD11) */
-#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */
- /* (CMD16,17,18) */
-#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */
- /* (CMD20) */
-#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */
- /* (CMD16,24,25,26,27) */
-#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */
- /* (CMD32,33,34,35,36,37,38,39) */
-#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */
- /* (CMD28,29,30) */
-#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */
- /* (CMD16,CMD42) */
-#define CCC_APP_SPEC (1<<8) /* (8) Application specific */
- /* (CMD55,56,57,ACMD*) */
-#define CCC_IO_MODE (1<<9) /* (9) I/O mode */
- /* (CMD5,39,40,52,53) */
-#define CCC_SWITCH (1<<10) /* (10) High speed switch */
- /* (CMD6,34,35,36,37,50) */
- /* (11) Reserved */
- /* (CMD?) */
-
-/*
- * CSD field definitions
- */
-
-#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
-#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
-#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
-#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
-
-#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
-#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
-#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
-#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
-#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
-
-/*
- * EXT_CSD fields
- */
-
-#define EXT_CSD_BUS_WIDTH 183 /* R/W */
-#define EXT_CSD_HS_TIMING 185 /* R/W */
-#define EXT_CSD_CARD_TYPE 196 /* RO */
-
-/*
- * EXT_CSD field definitions
- */
-
-#define EXT_CSD_CMD_SET_NORMAL (1<<0)
-#define EXT_CSD_CMD_SET_SECURE (1<<1)
-#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
-
-#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
-#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
-
-#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
-#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
-#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
-
-/*
- * MMC_SWITCH access modes
- */
-
-#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
-#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
-#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
-#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
-
-/*
- * SCR field definitions
- */
-
-#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
-#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
-#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
-
-/*
- * SD bus widths
- */
-#define SD_BUS_WIDTH_1 0
-#define SD_BUS_WIDTH_4 2
-
-#endif /* MMC_MMC_PROTOCOL_H */
-
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
new file mode 100644
index 00000000000..f310062cffb
--- /dev/null
+++ b/include/linux/mmc/sd.h
@@ -0,0 +1,83 @@
+/*
+ * include/linux/mmc/sd.h
+ *
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef MMC_SD_H
+#define MMC_SD_H
+
+/* SD commands type argument response */
+ /* class 0 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
+#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
+
+ /* class 10 */
+#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
+
+ /* Application commands */
+#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
+#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
+#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
+#define SD_APP_SEND_SCR 51 /* adtc R1 */
+
+/*
+ * SD_SWITCH argument format:
+ *
+ * [31] Check (0) or switch (1)
+ * [30:24] Reserved (0)
+ * [23:20] Function group 6
+ * [19:16] Function group 5
+ * [15:12] Function group 4
+ * [11:8] Function group 3
+ * [7:4] Function group 2
+ * [3:0] Function group 1
+ */
+
+/*
+ * SD_SEND_IF_COND argument format:
+ *
+ * [31:12] Reserved (0)
+ * [11:8] Host Voltage Supply Flags
+ * [7:0] Check Pattern (0xAA)
+ */
+
+/*
+ * SCR field definitions
+ */
+
+#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
+#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
+#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1 0
+#define SD_BUS_WIDTH_4 2
+
+/*
+ * SD_SWITCH mode
+ */
+#define SD_SWITCH_CHECK 0
+#define SD_SWITCH_SET 1
+
+/*
+ * SD_SWITCH function groups
+ */
+#define SD_SWITCH_GRP_ACCESS 0
+
+/*
+ * SD_SWITCH access modes
+ */
+#define SD_SWITCH_ACCESS_DEF 0
+#define SD_SWITCH_ACCESS_HS 1
+
+#endif
+
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ee9e3143df4..d09b1345a3a 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -83,6 +83,9 @@ struct per_cpu_pages {
struct per_cpu_pageset {
struct per_cpu_pages pcp[2]; /* 0: hot. 1: cold */
+#ifdef CONFIG_NUMA
+ s8 expire;
+#endif
#ifdef CONFIG_SMP
s8 stat_threshold;
s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS];
@@ -784,6 +787,18 @@ void sparse_init(void);
void memory_present(int nid, unsigned long start, unsigned long end);
unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long);
+/*
+ * If it is possible to have holes within a MAX_ORDER_NR_PAGES, then we
+ * need to check pfn validility within that MAX_ORDER_NR_PAGES block.
+ * pfn_valid_within() should be used in this case; we optimise this away
+ * when we have no holes within a MAX_ORDER_NR_PAGES block.
+ */
+#ifdef CONFIG_HOLES_IN_ZONE
+#define pfn_valid_within(pfn) pfn_valid(pfn)
+#else
+#define pfn_valid_within(pfn) (1)
+#endif
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _LINUX_MMZONE_H */
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
index 4af0b1fc282..1fa4d9813b3 100644
--- a/include/linux/mnt_namespace.h
+++ b/include/linux/mnt_namespace.h
@@ -14,10 +14,9 @@ struct mnt_namespace {
int event;
};
-extern int copy_mnt_ns(int, struct task_struct *);
-extern void __put_mnt_ns(struct mnt_namespace *ns);
-extern struct mnt_namespace *dup_mnt_ns(struct task_struct *,
+extern struct mnt_namespace *copy_mnt_ns(int, struct mnt_namespace *,
struct fs_struct *);
+extern void __put_mnt_ns(struct mnt_namespace *ns);
static inline void put_mnt_ns(struct mnt_namespace *ns)
{
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index e96b2dee10b..af04a555b52 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -262,6 +262,7 @@ struct i2c_device_id {
/* Input */
#define INPUT_DEVICE_ID_EV_MAX 0x1f
+#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71
#define INPUT_DEVICE_ID_KEY_MAX 0x1ff
#define INPUT_DEVICE_ID_REL_MAX 0x0f
#define INPUT_DEVICE_ID_ABS_MAX 0x3f
diff --git a/include/linux/module.h b/include/linux/module.h
index 95679eb8571..792d483c9af 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -356,6 +356,9 @@ struct module
keeping pointers to this stuff */
char *args;
};
+#ifndef MODULE_ARCH_INIT
+#define MODULE_ARCH_INIT {}
+#endif
/* FIXME: It'd be nice to isolate modules during init, too, so they
aren't used before they (may) fail. But presently too much code
@@ -370,16 +373,14 @@ struct module *module_text_address(unsigned long addr);
struct module *__module_text_address(unsigned long addr);
int is_module_address(unsigned long addr);
-/* Returns module and fills in value, defined and namebuf, or NULL if
+/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
symnum out of range. */
-struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
- char *type, char *name, size_t namelen);
+int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
+ char *name, char *module_name, int *exported);
/* Look for this name: can be of form module:name. */
unsigned long module_kallsyms_lookup_name(const char *name);
-int is_exported(const char *name, const struct module *mod);
-
extern void __module_put_and_exit(struct module *mod, long code)
__attribute__((noreturn));
#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code);
@@ -456,6 +457,8 @@ const char *module_address_lookup(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset,
char **modname);
+int lookup_module_symbol_name(unsigned long addr, char *symname);
+int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
/* For extable.c to search modules' exception tables. */
const struct exception_table_entry *search_module_extables(unsigned long addr);
@@ -527,20 +530,24 @@ static inline const char *module_address_lookup(unsigned long addr,
return NULL;
}
-static inline struct module *module_get_kallsym(unsigned int symnum,
- unsigned long *value,
- char *type, char *name,
- size_t namelen)
+static inline int lookup_module_symbol_name(unsigned long addr, char *symname)
{
- return NULL;
+ return -ERANGE;
}
-static inline unsigned long module_kallsyms_lookup_name(const char *name)
+static inline int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name)
{
- return 0;
+ return -ERANGE;
}
-static inline int is_exported(const char *name, const struct module *mod)
+static inline int module_get_kallsym(unsigned int symnum, unsigned long *value,
+ char *type, char *name,
+ char *module_name, int *exported)
+{
+ return -ERANGE;
+}
+
+static inline unsigned long module_kallsyms_lookup_name(const char *name)
{
return 0;
}
@@ -568,7 +575,7 @@ struct device_driver;
#ifdef CONFIG_SYSFS
struct module;
-extern struct subsystem module_subsys;
+extern struct kset module_subsys;
int mod_sysfs_init(struct module *mod);
int mod_sysfs_setup(struct module *mod,
diff --git a/include/linux/mount.h b/include/linux/mount.h
index dab69afee2f..6d3047d8c91 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -33,7 +33,7 @@ struct mnt_namespace;
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
-#define MNT_PNODE_MASK 0x3000 /* propogation flag mask */
+#define MNT_PNODE_MASK 0x3000 /* propagation flag mask */
struct vfsmount {
struct list_head mnt_hash;
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index fa253fa73aa..0e09c005dda 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -205,7 +205,8 @@ struct fat_mount_options {
numtail:1, /* Does first alias have a numeric '~1' type tail? */
atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */
flush:1, /* write things quickly */
- nocase:1; /* Does this need case conversion? 0=need case conversion*/
+ nocase:1, /* Does this need case conversion? 0=need case conversion*/
+ usefree:1; /* Use free_clusters for FAT32 */
};
#define FAT_HASH_BITS 8
diff --git a/include/linux/msi.h b/include/linux/msi.h
index e38fe6822cb..94bb46d82ef 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -1,6 +1,8 @@
#ifndef LINUX_MSI_H
#define LINUX_MSI_H
+#include <linux/list.h>
+
struct msi_msg {
u32 address_lo; /* low 32 bits of msi message address */
u32 address_hi; /* high 32 bits of msi message address */
@@ -24,10 +26,8 @@ struct msi_desc {
unsigned default_irq; /* default pre-assigned irq */
}msi_attrib;
- struct {
- __u16 head;
- __u16 tail;
- }link;
+ unsigned int irq;
+ struct list_head list;
void __iomem *mask_base;
struct pci_dev *dev;
@@ -41,6 +41,9 @@ struct msi_desc {
*/
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
void arch_teardown_msi_irq(unsigned int irq);
+extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
+extern void arch_teardown_msi_irqs(struct pci_dev *dev);
+extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
#endif /* LINUX_MSI_H */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index b81bc2adaef..0d50ea3df68 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -121,11 +121,12 @@ static inline int fastcall mutex_is_locked(struct mutex *lock)
* Also see Documentation/mutex-design.txt.
*/
extern void fastcall mutex_lock(struct mutex *lock);
-extern int fastcall mutex_lock_interruptible(struct mutex *lock);
+extern int __must_check fastcall mutex_lock_interruptible(struct mutex *lock);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass);
-extern int mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass);
+extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock,
+ unsigned int subclass);
#else
# define mutex_lock_nested(lock, subclass) mutex_lock(lock)
# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e027a3750a7..30446222b39 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -304,7 +304,7 @@ struct net_device
unsigned long state;
- struct net_device *next;
+ struct list_head dev_list;
/* The device initialization function. Called only once. */
int (*init)(struct net_device *dev);
@@ -325,7 +325,6 @@ struct net_device
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
#define NETIF_F_GSO 2048 /* Enable software GSO. */
#define NETIF_F_LLTX 4096 /* LockLess TX */
-#define NETIF_F_INTERNAL_STATS 8192 /* Use stats structure in net_device */
/* Segmentation offload features */
#define NETIF_F_GSO_SHIFT 16
@@ -576,13 +575,36 @@ struct packet_type {
#include <linux/notifier.h>
extern struct net_device loopback_dev; /* The loopback */
-extern struct net_device *dev_base; /* All devices */
+extern struct list_head dev_base_head; /* All devices */
extern rwlock_t dev_base_lock; /* Device list lock */
+#define for_each_netdev(d) \
+ list_for_each_entry(d, &dev_base_head, dev_list)
+#define for_each_netdev_safe(d, n) \
+ list_for_each_entry_safe(d, n, &dev_base_head, dev_list)
+#define for_each_netdev_continue(d) \
+ list_for_each_entry_continue(d, &dev_base_head, dev_list)
+#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list)
+
+static inline struct net_device *next_net_device(struct net_device *dev)
+{
+ struct list_head *lh;
+
+ lh = dev->dev_list.next;
+ return lh == &dev_base_head ? NULL : net_device_entry(lh);
+}
+
+static inline struct net_device *first_net_device(void)
+{
+ return list_empty(&dev_base_head) ? NULL :
+ net_device_entry(dev_base_head.next);
+}
+
extern int netdev_boot_setup_check(struct net_device *dev);
extern unsigned long netdev_boot_base(const char *prefix, int unit);
extern struct net_device *dev_getbyhwaddr(unsigned short type, char *hwaddr);
extern struct net_device *dev_getfirstbyhwtype(unsigned short type);
+extern struct net_device *__dev_getfirstbyhwtype(unsigned short type);
extern void dev_add_pack(struct packet_type *pt);
extern void dev_remove_pack(struct packet_type *pt);
extern void __dev_remove_pack(struct packet_type *pt);
@@ -654,8 +676,10 @@ static inline void netif_start_queue(struct net_device *dev)
static inline void netif_wake_queue(struct net_device *dev)
{
#ifdef CONFIG_NETPOLL_TRAP
- if (netpoll_trap())
+ if (netpoll_trap()) {
+ clear_bit(__LINK_STATE_XOFF, &dev->state);
return;
+ }
#endif
if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
__netif_schedule(dev);
@@ -663,10 +687,6 @@ static inline void netif_wake_queue(struct net_device *dev)
static inline void netif_stop_queue(struct net_device *dev)
{
-#ifdef CONFIG_NETPOLL_TRAP
- if (netpoll_trap())
- return;
-#endif
set_bit(__LINK_STATE_XOFF, &dev->state);
}
diff --git a/include/linux/netfilter/nf_conntrack_proto_gre.h b/include/linux/netfilter/nf_conntrack_proto_gre.h
index 4e6bbce04ff..535e4219d2b 100644
--- a/include/linux/netfilter/nf_conntrack_proto_gre.h
+++ b/include/linux/netfilter/nf_conntrack_proto_gre.h
@@ -87,24 +87,6 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
/* delete keymap entries */
void nf_ct_gre_keymap_destroy(struct nf_conn *ct);
-/* get pointer to gre key, if present */
-static inline __be32 *gre_key(struct gre_hdr *greh)
-{
- if (!greh->key)
- return NULL;
- if (greh->csum || greh->routing)
- return (__be32 *)(greh+sizeof(*greh)+4);
- return (__be32 *)(greh+sizeof(*greh));
-}
-
-/* get pointer ot gre csum, if present */
-static inline __sum16 *gre_csum(struct gre_hdr *greh)
-{
- if (!greh->csum)
- return NULL;
- return (__sum16 *)(greh+sizeof(*greh));
-}
-
extern void nf_ct_gre_keymap_flush(void);
extern void nf_nat_need_gre(void);
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
index 19060030bac..533ee351a27 100644
--- a/include/linux/netfilter_bridge.h
+++ b/include/linux/netfilter_bridge.h
@@ -55,18 +55,25 @@ static inline int nf_bridge_maybe_copy_header(struct sk_buff *skb)
return 0;
}
+static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb)
+{
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_8021Q):
+ return VLAN_HLEN;
+ case __constant_htons(ETH_P_PPP_SES):
+ return PPPOE_SES_HLEN;
+ default:
+ return 0;
+ }
+}
+
/* This is called by the IP fragmenting code and it ensures there is
* enough room for the encapsulating header (if there is one). */
-static inline int nf_bridge_pad(const struct sk_buff *skb)
+static inline unsigned int nf_bridge_pad(const struct sk_buff *skb)
{
- int padding = 0;
-
- if (skb->nf_bridge && skb->protocol == htons(ETH_P_8021Q))
- padding = VLAN_HLEN;
- else if (skb->nf_bridge && skb->protocol == htons(ETH_P_PPP_SES))
- padding = PPPOE_SES_HLEN;
-
- return padding;
+ if (skb->nf_bridge)
+ return nf_bridge_encap_header_len(skb);
+ return 0;
}
struct bridge_skb_cb {
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index f41688f5663..2e23353c28a 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -31,7 +31,7 @@ struct sockaddr_nl
{
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
- __u32 nl_pid; /* process pid */
+ __u32 nl_pid; /* port ID */
__u32 nl_groups; /* multicast groups mask */
};
@@ -41,7 +41,7 @@ struct nlmsghdr
__u16 nlmsg_type; /* Message content */
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
- __u32 nlmsg_pid; /* Sending process PID */
+ __u32 nlmsg_pid; /* Sending process port ID */
};
/* Flags values */
diff --git a/include/linux/nfs4_acl.h b/include/linux/nfs4_acl.h
index 409b6e02f33..c9c05a78e9b 100644
--- a/include/linux/nfs4_acl.h
+++ b/include/linux/nfs4_acl.h
@@ -44,7 +44,6 @@
#define NFS4_ACL_MAX 170
struct nfs4_acl *nfs4_acl_new(int);
-void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
int nfs4_acl_get_whotype(char *, u32);
int nfs4_acl_write_who(int who, char *p);
int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index e9ae0c6e2c6..0543439a97a 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -455,7 +455,7 @@ nfs_have_writebacks(struct inode *inode)
/*
* Allocate nfs_write_data structures
*/
-extern struct nfs_write_data *nfs_writedata_alloc(size_t len);
+extern struct nfs_write_data *nfs_writedata_alloc(unsigned int npages);
/*
* linux/fs/nfs/read.c
@@ -469,7 +469,7 @@ extern void nfs_readdata_release(void *data);
/*
* Allocate nfs_read_data structures
*/
-extern struct nfs_read_data *nfs_readdata_alloc(size_t len);
+extern struct nfs_read_data *nfs_readdata_alloc(unsigned int npages);
/*
* linux/fs/nfs3proc.c
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c95d5e64254..52b4378311c 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -82,7 +82,7 @@ struct nfs_server {
struct rpc_clnt * client_acl; /* ACL RPC client handle */
struct nfs_iostats * io_stats; /* I/O statistics */
struct backing_dev_info backing_dev_info;
- atomic_t writeback; /* number of writeback pages */
+ atomic_long_t writeback; /* number of writeback pages */
int flags; /* various flags */
unsigned int caps; /* server capabilities */
unsigned int rsize; /* read size */
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index 659c7543845..cc8b9c59acb 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -61,6 +61,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_NOACL 0x0800 /* 4 */
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
+#define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */
#define NFS_MOUNT_FLAGMASK 0xFFFF
#endif
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 16b0266b14f..41afab6b5f0 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -21,8 +21,7 @@
/*
* Valid flags for the radix tree
*/
-#define NFS_PAGE_TAG_DIRTY 0
-#define NFS_PAGE_TAG_WRITEBACK 1
+#define NFS_PAGE_TAG_WRITEBACK 0
/*
* Valid flags for a dirty buffer
@@ -39,7 +38,7 @@ struct nfs_page {
struct page *wb_page; /* page to read in/write out */
struct nfs_open_context *wb_context; /* File state context info */
atomic_t wb_complete; /* i/os we're waiting for */
- unsigned long wb_index; /* Offset >> PAGE_CACHE_SHIFT */
+ pgoff_t wb_index; /* Offset >> PAGE_CACHE_SHIFT */
unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */
wb_pgbase, /* Start of page data */
wb_bytes; /* Length of request */
@@ -48,6 +47,19 @@ struct nfs_page {
struct nfs_writeverf wb_verf; /* Commit cookie */
};
+struct nfs_pageio_descriptor {
+ struct list_head pg_list;
+ unsigned long pg_bytes_written;
+ size_t pg_count;
+ size_t pg_bsize;
+ unsigned int pg_base;
+
+ struct inode *pg_inode;
+ int (*pg_doio)(struct inode *, struct list_head *, unsigned int, size_t, int);
+ int pg_ioflags;
+ int pg_error;
+};
+
#define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags))
extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
@@ -59,13 +71,16 @@ extern void nfs_clear_request(struct nfs_page *req);
extern void nfs_release_request(struct nfs_page *req);
-extern long nfs_scan_dirty(struct address_space *mapping,
- struct writeback_control *wbc,
- struct list_head *dst);
extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
- unsigned long idx_start, unsigned int npages);
-extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
- unsigned int);
+ pgoff_t idx_start, unsigned int npages);
+extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
+ struct inode *inode,
+ int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
+ size_t bsize,
+ int how);
+extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *,
+ struct nfs_page *);
+extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
extern int nfs_wait_on_request(struct nfs_page *);
extern void nfs_unlock_request(struct nfs_page *req);
extern int nfs_set_page_writeback_locked(struct nfs_page *req);
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 10a43ed0527..9431101bf87 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -112,32 +112,40 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
#ifdef __KERNEL__
-extern int atomic_notifier_chain_register(struct atomic_notifier_head *,
- struct notifier_block *);
-extern int blocking_notifier_chain_register(struct blocking_notifier_head *,
- struct notifier_block *);
-extern int raw_notifier_chain_register(struct raw_notifier_head *,
- struct notifier_block *);
-extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
- struct notifier_block *);
-
-extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
- struct notifier_block *);
-extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *,
- struct notifier_block *);
-extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
- struct notifier_block *);
-extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
- struct notifier_block *);
-
-extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
+extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
+ struct notifier_block *nb);
+extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
+ struct notifier_block *nb);
+extern int raw_notifier_chain_register(struct raw_notifier_head *nh,
+ struct notifier_block *nb);
+extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+ struct notifier_block *nb);
+
+extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
+ struct notifier_block *nb);
+extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
+ struct notifier_block *nb);
+extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
+ struct notifier_block *nb);
+extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+ struct notifier_block *nb);
+
+extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v);
-extern int blocking_notifier_call_chain(struct blocking_notifier_head *,
+extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+ unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
unsigned long val, void *v);
-extern int raw_notifier_call_chain(struct raw_notifier_head *,
+extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+ unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v);
-extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+extern int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+ unsigned long val, void *v, int nr_to_call, int *nr_calls);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
unsigned long val, void *v);
+extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+ unsigned long val, void *v, int nr_to_call, int *nr_calls);
#define NOTIFY_DONE 0x0000 /* Don't care */
#define NOTIFY_OK 0x0001 /* Suits me */
@@ -186,6 +194,20 @@ extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */
#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */
#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */
+#define CPU_LOCK_ACQUIRE 0x0008 /* Acquire all hotcpu locks */
+#define CPU_LOCK_RELEASE 0x0009 /* Release all hotcpu locks */
+
+/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
+ * operation in progress
+ */
+#define CPU_TASKS_FROZEN 0x0010
+
+#define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN)
+#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN)
+#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN)
+#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
+#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
+#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN)
#endif /* __KERNEL__ */
#endif /* _LINUX_NOTIFIER_H */
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 0b9f0dc30d6..189e0dc993a 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -31,10 +31,11 @@ struct nsproxy {
};
extern struct nsproxy init_nsproxy;
-struct nsproxy *dup_namespaces(struct nsproxy *orig);
int copy_namespaces(int flags, struct task_struct *tsk);
void get_task_namespaces(struct task_struct *tsk);
void free_nsproxy(struct nsproxy *ns);
+int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
+ struct fs_struct *);
static inline void put_nsproxy(struct nsproxy *ns)
{
diff --git a/include/linux/nubus.h b/include/linux/nubus.h
index 870e66a9628..cdb3e9b8db5 100644
--- a/include/linux/nubus.h
+++ b/include/linux/nubus.h
@@ -28,18 +28,18 @@ enum nubus_category {
};
enum nubus_type_network {
- NUBUS_TYPE_ETHERNET = 0x0001,
- NUBUS_TYPE_RS232 = 0x0002
+ NUBUS_TYPE_ETHERNET = 0x0001,
+ NUBUS_TYPE_RS232 = 0x0002
};
enum nubus_type_display {
- NUBUS_TYPE_VIDEO = 0x0001
+ NUBUS_TYPE_VIDEO = 0x0001
};
enum nubus_type_cpu {
- NUBUS_TYPE_68020 = 0x0003,
- NUBUS_TYPE_68030 = 0x0004,
- NUBUS_TYPE_68040 = 0x0005
+ NUBUS_TYPE_68020 = 0x0003,
+ NUBUS_TYPE_68030 = 0x0004,
+ NUBUS_TYPE_68040 = 0x0005
};
/* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots)
@@ -56,6 +56,7 @@ enum nubus_type_cpu {
*
* SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272>
* SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271>
+ * Apple SONIC LC-PDS Ethernet ("Apple Ethernet LC Twisted-Pair Card"): <4,1,0,281>
* Sonic Systems Ethernet A-Series Card: <4,1,268,256>
* Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision)
* ROM on the above card: <2,1,0,0>
@@ -80,24 +81,26 @@ enum nubus_type_cpu {
/* Add known DrSW values here */
enum nubus_drsw {
/* NUBUS_CAT_DISPLAY */
- NUBUS_DRSW_APPLE = 0x0001,
- NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
+ NUBUS_DRSW_APPLE = 0x0001,
+ NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */
/* NUBUS_CAT_NETWORK */
- NUBUS_DRSW_CABLETRON = 0x0001,
- NUBUS_DRSW_SONIC_LC = 0x0001,
- NUBUS_DRSW_KINETICS = 0x0103,
- NUBUS_DRSW_ASANTE = 0x0104,
- NUBUS_DRSW_DAYNA = 0x010b,
- NUBUS_DRSW_FARALLON = 0x010c,
- NUBUS_DRSW_APPLE_SN = 0x010f,
- NUBUS_DRSW_DAYNA2 = 0x0115,
+ NUBUS_DRSW_3COM = 0x0000,
+ NUBUS_DRSW_CABLETRON = 0x0001,
+ NUBUS_DRSW_SONIC_LC = 0x0001,
+ NUBUS_DRSW_KINETICS = 0x0103,
+ NUBUS_DRSW_ASANTE = 0x0104,
+ NUBUS_DRSW_TECHWORKS = 0x0109,
+ NUBUS_DRSW_DAYNA = 0x010b,
+ NUBUS_DRSW_FARALLON = 0x010c,
+ NUBUS_DRSW_APPLE_SN = 0x010f,
+ NUBUS_DRSW_DAYNA2 = 0x0115,
NUBUS_DRSW_FOCUS = 0x011a,
NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */
- NUBUS_DRSW_DAYNA_LC = 0x011e,
+ NUBUS_DRSW_DAYNA_LC = 0x011e,
/* NUBUS_CAT_CPU */
- NUBUS_DRSW_NONE = 0x0000,
+ NUBUS_DRSW_NONE = 0x0000,
};
/* DrHW: Uniquely identifies the hardware interface to a board (or at
@@ -107,27 +110,48 @@ enum nubus_drsw {
/* Add known DrHW values here */
enum nubus_drhw {
/* NUBUS_CAT_DISPLAY */
- NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */
- NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High Res Video card */
- NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */
- NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */
- NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
- NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */
+ NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */
+ NUBUS_DRHW_APPLE_WVC = 0x0006, /* Apple Workstation Video Card */
+ NUBUS_DRHW_SIGMA_CLRMAX = 0x0007, /* Sigma Design ColorMax */
+ NUBUS_DRHW_APPLE_SE30 = 0x0009, /* Apple SE/30 video */
+ NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High-Res Video Card */
+ NUBUS_DRHW_APPLE_PVC = 0x0017, /* Mac II Portrait Video Card */
+ NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */
+ NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */
+ NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */
+ NUBUS_DRHW_APPLE_24AC = 0x002b, /* Mac 24AC Video Card */
NUBUS_DRHW_APPLE_VALKYRIE = 0x002e,
- NUBUS_DRHW_THUNDER24 = 0x02cb, /* SuperMac Thunder/24 */
+ NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */
+ NUBUS_DRHW_SMAC_GFX = 0x0105, /* SuperMac GFX */
+ NUBUS_DRHW_RASTER_CB264 = 0x013B, /* RasterOps ColorBoard 264 */
+ NUBUS_DRHW_MICRON_XCEED = 0x0146, /* Micron Exceed color */
+ NUBUS_DRHW_RDIUS_GSC = 0x0153, /* Radius GS/C */
+ NUBUS_DRHW_SMAC_SPEC8 = 0x017B, /* SuperMac Spectrum/8 */
+ NUBUS_DRHW_SMAC_SPEC24 = 0x017C, /* SuperMac Spectrum/24 */
+ NUBUS_DRHW_RASTER_CB364 = 0x026F, /* RasterOps ColorBoard 364 */
+ NUBUS_DRHW_RDIUS_DCGX = 0x027C, /* Radius DirectColor/GX */
+ NUBUS_DRHW_RDIUS_PC8 = 0x0291, /* Radius PrecisionColor 8 */
+ NUBUS_DRHW_LAPIS_PCS8 = 0x0292, /* Lapis ProColorServer 8 */
+ NUBUS_DRHW_RASTER_24LXI = 0x02A0, /* RasterOps 8/24 XLi */
+ NUBUS_DRHW_RASTER_PBPGT = 0x02A5, /* RasterOps PaintBoard Prism GT */
+ NUBUS_DRHW_EMACH_FSX = 0x02AE, /* E-Machines Futura SX */
+ NUBUS_DRHW_SMAC_THUND24 = 0x02CB, /* SuperMac Thunder/24 */
+ NUBUS_DRHW_RDIUS_PC24XP = 0x0406, /* Radius PrecisionColor 24Xp */
+ NUBUS_DRHW_RDIUS_PC24X = 0x040A, /* Radius PrecisionColor 24X */
+ NUBUS_DRHW_RDIUS_PC8XJ = 0x040B, /* Radius PrecisionColor 8XJ */
/* NUBUS_CAT_NETWORK */
- NUBUS_DRHW_INTERLAN = 0x0100,
- NUBUS_DRHW_SMC9194 = 0x0101,
- NUBUS_DRHW_KINETICS = 0x0106,
- NUBUS_DRHW_CABLETRON = 0x0109,
- NUBUS_DRHW_ASANTE_LC = 0x010f,
- NUBUS_DRHW_SONIC = 0x0110,
- NUBUS_DRHW_SONIC_NB = 0x0118,
- NUBUS_DRHW_SONIC_LC = 0x0119,
-
- /* NUBUS_CAT_COMMUNICATIONS */
- NUBUS_DRHW_DOVEFAX = 0x0100,
+ NUBUS_DRHW_INTERLAN = 0x0100,
+ NUBUS_DRHW_SMC9194 = 0x0101,
+ NUBUS_DRHW_KINETICS = 0x0106,
+ NUBUS_DRHW_CABLETRON = 0x0109,
+ NUBUS_DRHW_ASANTE_LC = 0x010f,
+ NUBUS_DRHW_SONIC = 0x0110,
+ NUBUS_DRHW_TECHWORKS = 0x0112,
+ NUBUS_DRHW_APPLE_SONIC_NB = 0x0118,
+ NUBUS_DRHW_APPLE_SONIC_LC = 0x0119,
+ NUBUS_DRHW_FOCUS = 0x011c,
+ NUBUS_DRHW_SONNET = 0x011d,
};
/* Resource IDs: These are the identifiers for the various weird and
@@ -153,17 +177,17 @@ enum nubus_res_id {
/* Category-specific resources. */
enum nubus_board_res_id {
- NUBUS_RESID_BOARDID = 0x0020,
+ NUBUS_RESID_BOARDID = 0x0020,
NUBUS_RESID_PRAMINITDATA = 0x0021,
- NUBUS_RESID_PRIMARYINIT = 0x0022,
+ NUBUS_RESID_PRIMARYINIT = 0x0022,
NUBUS_RESID_TIMEOUTCONST = 0x0023,
- NUBUS_RESID_VENDORINFO = 0x0024,
- NUBUS_RESID_BOARDFLAGS = 0x0025,
- NUBUS_RESID_SECONDINIT = 0x0026,
+ NUBUS_RESID_VENDORINFO = 0x0024,
+ NUBUS_RESID_BOARDFLAGS = 0x0025,
+ NUBUS_RESID_SECONDINIT = 0x0026,
/* Not sure why Apple put these next two in here */
- NUBUS_RESID_VIDNAMES = 0x0041,
- NUBUS_RESID_VIDMODES = 0x007e
+ NUBUS_RESID_VIDNAMES = 0x0041,
+ NUBUS_RESID_VIDMODES = 0x007e
};
/* Fields within the vendor info directory */
@@ -185,13 +209,13 @@ enum nubus_cpu_res_id {
};
enum nubus_display_res_id {
- NUBUS_RESID_GAMMADIR = 0x0040,
- NUBUS_RESID_FIRSTMODE = 0x0080,
- NUBUS_RESID_SECONDMODE = 0x0081,
- NUBUS_RESID_THIRDMODE = 0x0082,
- NUBUS_RESID_FOURTHMODE = 0x0083,
- NUBUS_RESID_FIFTHMODE = 0x0084,
- NUBUS_RESID_SIXTHMODE = 0x0085
+ NUBUS_RESID_GAMMADIR = 0x0040,
+ NUBUS_RESID_FIRSTMODE = 0x0080,
+ NUBUS_RESID_SECONDMODE = 0x0081,
+ NUBUS_RESID_THIRDMODE = 0x0082,
+ NUBUS_RESID_FOURTHMODE = 0x0083,
+ NUBUS_RESID_FIFTHMODE = 0x0084,
+ NUBUS_RESID_SIXTHMODE = 0x0085
};
struct nubus_dir
@@ -214,7 +238,7 @@ struct nubus_board {
struct nubus_board* next;
struct nubus_dev* first_dev;
- /* Only 9-E actually exist, though 0-8 are also theoretically
+ /* Only 9-E actually exist, though 0-8 are also theoretically
possible, and 0 is a special case which represents the
motherboard and onboard peripherals (Ethernet, video) */
int slot;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 96326594e55..ae2d79f2107 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -6,6 +6,7 @@
#define PAGE_FLAGS_H
#include <linux/types.h>
+#include <linux/mm_types.h>
/*
* Various page->flags bits:
@@ -82,13 +83,11 @@
#define PG_private 11 /* If pagecache, has fs-private data */
#define PG_writeback 12 /* Page is under writeback */
-#define PG_nosave 13 /* Used for system suspend/resume */
#define PG_compound 14 /* Part of a compound page */
#define PG_swapcache 15 /* Swap page: swp_entry_t in private */
#define PG_mappedtodisk 16 /* Has blocks allocated on-disk */
#define PG_reclaim 17 /* To be reclaimed asap */
-#define PG_nosave_free 18 /* Used for system suspend/resume */
#define PG_buddy 19 /* Page is free, on buddy lists */
/* PG_owner_priv_1 users should have descriptive aliases */
@@ -214,16 +213,6 @@ static inline void SetPageUptodate(struct page *page)
ret; \
})
-#define PageNosave(page) test_bit(PG_nosave, &(page)->flags)
-#define SetPageNosave(page) set_bit(PG_nosave, &(page)->flags)
-#define TestSetPageNosave(page) test_and_set_bit(PG_nosave, &(page)->flags)
-#define ClearPageNosave(page) clear_bit(PG_nosave, &(page)->flags)
-#define TestClearPageNosave(page) test_and_clear_bit(PG_nosave, &(page)->flags)
-
-#define PageNosaveFree(page) test_bit(PG_nosave_free, &(page)->flags)
-#define SetPageNosaveFree(page) set_bit(PG_nosave_free, &(page)->flags)
-#define ClearPageNosaveFree(page) clear_bit(PG_nosave_free, &(page)->flags)
-
#define PageBuddy(page) test_bit(PG_buddy, &(page)->flags)
#define __SetPageBuddy(page) __set_bit(PG_buddy, &(page)->flags)
#define __ClearPageBuddy(page) __clear_bit(PG_buddy, &(page)->flags)
@@ -241,6 +230,34 @@ static inline void SetPageUptodate(struct page *page)
#define __SetPageCompound(page) __set_bit(PG_compound, &(page)->flags)
#define __ClearPageCompound(page) __clear_bit(PG_compound, &(page)->flags)
+/*
+ * PG_reclaim is used in combination with PG_compound to mark the
+ * head and tail of a compound page
+ *
+ * PG_compound & PG_reclaim => Tail page
+ * PG_compound & ~PG_reclaim => Head page
+ */
+
+#define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim))
+
+#define PageTail(page) ((page->flags & PG_head_tail_mask) \
+ == PG_head_tail_mask)
+
+static inline void __SetPageTail(struct page *page)
+{
+ page->flags |= PG_head_tail_mask;
+}
+
+static inline void __ClearPageTail(struct page *page)
+{
+ page->flags &= ~PG_head_tail_mask;
+}
+
+#define PageHead(page) ((page->flags & PG_head_tail_mask) \
+ == (1L << PG_compound))
+#define __SetPageHead(page) __SetPageCompound(page)
+#define __ClearPageHead(page) __ClearPageCompound(page)
+
#ifdef CONFIG_SWAP
#define PageSwapCache(page) test_bit(PG_swapcache, &(page)->flags)
#define SetPageSwapCache(page) set_bit(PG_swapcache, &(page)->flags)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 7a8dcb82a69..8a83537d697 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -11,6 +11,7 @@
#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <linux/gfp.h>
+#include <linux/bitops.h>
/*
* Bits in mapping->flags. The lower __GFP_BITS_SHIFT bits are the page
@@ -19,6 +20,16 @@
#define AS_EIO (__GFP_BITS_SHIFT + 0) /* IO error on async write */
#define AS_ENOSPC (__GFP_BITS_SHIFT + 1) /* ENOSPC on async write */
+static inline void mapping_set_error(struct address_space *mapping, int error)
+{
+ if (error) {
+ if (error == -ENOSPC)
+ set_bit(AS_ENOSPC, &mapping->flags);
+ else
+ set_bit(AS_EIO, &mapping->flags);
+ }
+}
+
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
{
return (__force gfp_t)mapping->flags & __GFP_BITS_MASK;
@@ -95,12 +106,23 @@ static inline struct page *grab_cache_page(struct address_space *mapping, unsign
extern struct page * grab_cache_page_nowait(struct address_space *mapping,
unsigned long index);
+extern struct page * read_cache_page_async(struct address_space *mapping,
+ unsigned long index, filler_t *filler,
+ void *data);
extern struct page * read_cache_page(struct address_space *mapping,
unsigned long index, filler_t *filler,
void *data);
extern int read_cache_pages(struct address_space *mapping,
struct list_head *pages, filler_t *filler, void *data);
+static inline struct page *read_mapping_page_async(
+ struct address_space *mapping,
+ unsigned long index, void *data)
+{
+ filler_t *filler = (filler_t *)mapping->a_ops->readpage;
+ return read_cache_page_async(mapping, index, filler, data);
+}
+
static inline struct page *read_mapping_page(struct address_space *mapping,
unsigned long index, void *data)
{
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 80682aaa8f1..9cdd6943e01 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -279,6 +279,10 @@ struct parport {
int dma;
int muxport; /* which muxport (if any) this is */
int portnum; /* which physical parallel port (not mux) */
+ struct device *dev; /* Physical device associated with IO/DMA.
+ * This may unfortulately be null if the
+ * port has a legacy driver.
+ */
struct parport *physport;
/* If this is a non-default mux
@@ -289,7 +293,7 @@ struct parport {
following structure members are
meaningless: devices, cad, muxsel,
waithead, waittail, flags, pdir,
- ieee1284, *_lock.
+ dev, ieee1284, *_lock.
It this is a default mux parport, or
there is no mux involved, this points to
@@ -302,7 +306,7 @@ struct parport {
struct pardevice *waithead;
struct pardevice *waittail;
-
+
struct list_head list;
unsigned int flags;
diff --git a/include/linux/parport_pc.h b/include/linux/parport_pc.h
index 1cc0f6b1a49..ea8c6d84996 100644
--- a/include/linux/parport_pc.h
+++ b/include/linux/parport_pc.h
@@ -38,7 +38,6 @@ struct parport_pc_private {
/* buffer suitable for DMA, if DMA enabled */
char *dma_buf;
dma_addr_t dma_handle;
- struct pci_dev *dev;
struct list_head list;
struct parport *port;
};
@@ -232,7 +231,7 @@ extern int parport_pc_claim_resources(struct parport *p);
extern struct parport *parport_pc_probe_port (unsigned long base,
unsigned long base_hi,
int irq, int dma,
- struct pci_dev *dev);
+ struct device *dev);
extern void parport_pc_unregister_port (struct parport *p);
#endif
diff --git a/include/linux/parser.h b/include/linux/parser.h
index fa3332861a0..26b2bdfcaf0 100644
--- a/include/linux/parser.h
+++ b/include/linux/parser.h
@@ -11,7 +11,7 @@
/* associates an integer enumerator with a pattern string. */
struct match_token {
int token;
- char *pattern;
+ const char *pattern;
};
typedef struct match_token match_table_t[];
@@ -29,5 +29,5 @@ int match_token(char *, match_table_t table, substring_t args[]);
int match_int(substring_t *, int *result);
int match_octal(substring_t *, int *result);
int match_hex(substring_t *, int *result);
-void match_strcpy(char *, substring_t *);
-char *match_strdup(substring_t *);
+void match_strcpy(char *, const substring_t *);
+char *match_strdup(const substring_t *);
diff --git a/include/linux/pci.h b/include/linux/pci.h
index a3ad76221c6..fbf3766dac1 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -96,6 +96,19 @@ enum pci_channel_state {
pci_channel_io_perm_failure = (__force pci_channel_state_t) 3,
};
+typedef unsigned int __bitwise pcie_reset_state_t;
+
+enum pcie_reset_state {
+ /* Reset is NOT asserted (Use to deassert reset) */
+ pcie_deassert_reset = (__force pcie_reset_state_t) 1,
+
+ /* Use #PERST to reset PCI-E device */
+ pcie_warm_reset = (__force pcie_reset_state_t) 2,
+
+ /* Use PCI-E Hot Reset to reset device */
+ pcie_hot_reset = (__force pcie_reset_state_t) 3
+};
+
typedef unsigned short __bitwise pci_bus_flags_t;
enum pci_bus_flags {
PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
@@ -176,10 +189,12 @@ struct pci_dev {
int rom_attr_enabled; /* has display of the rom attribute been enabled? */
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
#ifdef CONFIG_PCI_MSI
- unsigned int first_msi_irq;
+ struct list_head msi_list;
#endif
};
+extern struct pci_dev *alloc_pci_dev(void);
+
#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
@@ -392,12 +407,6 @@ struct pci_driver {
.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
-/*
- * pci_module_init is obsolete, this stays here till we fix up all usages of it
- * in the tree.
- */
-#define pci_module_init pci_register_driver
-
/**
* PCI_VDEVICE - macro used to describe a specific pci device in short form
* @vend: the vendor name
@@ -532,6 +541,7 @@ static inline int pci_is_managed(struct pci_dev *pdev)
void pci_disable_device(struct pci_dev *dev);
void pci_set_master(struct pci_dev *dev);
+int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
#define HAVE_PCI_SET_MWI
int __must_check pci_set_mwi(struct pci_dev *dev);
void pci_clear_mwi(struct pci_dev *dev);
@@ -730,6 +740,9 @@ static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) {
static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
+static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) { return -EIO; }
+static inline void pci_release_regions(struct pci_dev *dev) { }
+
#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
@@ -838,6 +851,7 @@ void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen);
void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr);
void __iomem * const * pcim_iomap_table(struct pci_dev *pdev);
int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name);
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask);
extern int pci_pci_problems;
#define PCIPCI_FAIL 1 /* No PCI PCI DMA */
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
index a675a05c409..ab4cb6ecd47 100644
--- a/include/linux/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -174,7 +174,7 @@ extern int pci_hp_register (struct hotplug_slot *slot);
extern int pci_hp_deregister (struct hotplug_slot *slot);
extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
struct hotplug_slot_info *info);
-extern struct subsystem pci_hotplug_slots_subsys;
+extern struct kset pci_hotplug_slots_subsys;
/* PCI Setting Record (Type 0) */
struct hpp_type0 {
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 600308fdf9c..ae849f0d443 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -368,7 +368,6 @@
#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379
#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a
#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380
-#define PCI_DEVICE_ID_ATI_IXP600_SRAID 0x4381
#define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385
#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
@@ -1214,11 +1213,13 @@
#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5
#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC
#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE
#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448
#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450
#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451
@@ -1459,6 +1460,8 @@
#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031
+#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105
#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108
#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
@@ -1923,6 +1926,7 @@
#define PCI_DEVICE_ID_TIGON3_5752 0x1600
#define PCI_DEVICE_ID_TIGON3_5752M 0x1601
#define PCI_DEVICE_ID_NX2_5709 0x1639
+#define PCI_DEVICE_ID_NX2_5709S 0x163a
#define PCI_DEVICE_ID_TIGON3_5700 0x1644
#define PCI_DEVICE_ID_TIGON3_5701 0x1645
#define PCI_DEVICE_ID_TIGON3_5702 0x1646
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 600e3d387ff..b72be2f79e6 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -11,9 +11,16 @@
/* Enough to cover all DEFINE_PER_CPUs in kernel, including modules. */
#ifndef PERCPU_ENOUGH_ROOM
-#define PERCPU_ENOUGH_ROOM 32768
+#ifdef CONFIG_MODULES
+#define PERCPU_MODULE_RESERVE 8192
+#else
+#define PERCPU_MODULE_RESERVE 0
#endif
+#define PERCPU_ENOUGH_ROOM \
+ (__per_cpu_end - __per_cpu_start + PERCPU_MODULE_RESERVE)
+#endif /* PERCPU_ENOUGH_ROOM */
+
/*
* Must be an lvalue. Since @var must be a simple identifier,
* we force a syntax error here if it isn't.
diff --git a/include/linux/phantom.h b/include/linux/phantom.h
new file mode 100644
index 00000000000..d3ebbfae690
--- /dev/null
+++ b/include/linux/phantom.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2005-2007 Jiri Slaby <jirislaby@gmail.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.
+ */
+
+#ifndef __PHANTOM_H
+#define __PHANTOM_H
+
+#include <asm/types.h>
+
+/* PHN_(G/S)ET_REG param */
+struct phm_reg {
+ __u32 reg;
+ __u32 value;
+};
+
+/* PHN_(G/S)ET_REGS param */
+struct phm_regs {
+ __u32 count;
+ __u32 mask;
+ __u32 values[8];
+};
+
+#define PH_IOC_MAGIC 'p'
+#define PHN_GET_REG _IOWR(PH_IOC_MAGIC, 0, struct phm_reg *)
+#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *)
+#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *)
+#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
+#define PH_IOC_MAXNR 3
+
+#define PHN_CONTROL 0x6 /* control byte in iaddr space */
+#define PHN_CTL_AMP 0x1 /* switch after torques change */
+#define PHN_CTL_BUT 0x2 /* is button switched */
+#define PHN_CTL_IRQ 0x10 /* is irq enabled */
+
+#define PHN_ZERO_FORCE 2048 /* zero torque on motor */
+
+#endif
diff --git a/include/linux/phy.h b/include/linux/phy.h
index edd4c88ca7d..2a659789f9c 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -55,6 +55,7 @@ typedef enum {
PHY_INTERFACE_MODE_TBI,
PHY_INTERFACE_MODE_RMII,
PHY_INTERFACE_MODE_RGMII,
+ PHY_INTERFACE_MODE_RGMII_ID,
PHY_INTERFACE_MODE_RTBI
} phy_interface_t;
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 2833806d42c..169c6c24209 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -29,7 +29,7 @@ static inline void get_pid_ns(struct pid_namespace *ns)
kref_get(&ns->kref);
}
-extern int copy_pid_ns(int flags, struct task_struct *tsk);
+extern struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *ns);
extern void free_pid_ns(struct kref *kref);
static inline void put_pid_ns(struct pid_namespace *ns)
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 9bd86db4d39..87545e0f0b5 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -107,26 +107,15 @@ typedef int __bitwise suspend_state_t;
#define PM_SUSPEND_ON ((__force suspend_state_t) 0)
#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 1)
#define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
-#define PM_SUSPEND_DISK ((__force suspend_state_t) 4)
-#define PM_SUSPEND_MAX ((__force suspend_state_t) 5)
-
-typedef int __bitwise suspend_disk_method_t;
-
-#define PM_DISK_FIRMWARE ((__force suspend_disk_method_t) 1)
-#define PM_DISK_PLATFORM ((__force suspend_disk_method_t) 2)
-#define PM_DISK_SHUTDOWN ((__force suspend_disk_method_t) 3)
-#define PM_DISK_REBOOT ((__force suspend_disk_method_t) 4)
-#define PM_DISK_TEST ((__force suspend_disk_method_t) 5)
-#define PM_DISK_TESTPROC ((__force suspend_disk_method_t) 6)
-#define PM_DISK_MAX ((__force suspend_disk_method_t) 7)
+#define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
/**
* struct pm_ops - Callbacks for managing platform dependent suspend states.
* @valid: Callback to determine whether the given state can be entered.
- * If %CONFIG_SOFTWARE_SUSPEND is set then %PM_SUSPEND_DISK is
- * always valid and never passed to this call.
- * If not assigned, all suspend states are advertised as valid
- * in /sys/power/state (but can still be rejected by prepare or enter.)
+ * Valid states are advertised in /sys/power/state but can still
+ * be rejected by prepare or enter if the conditions aren't right.
+ * There is a %pm_valid_only_mem function available that can be assigned
+ * to this if you only implement mem sleep.
*
* @prepare: Prepare the platform for the given suspend state. Can return a
* negative error code if necessary.
@@ -136,25 +125,12 @@ typedef int __bitwise suspend_disk_method_t;
*
* @finish: Called when the system has left the given state and all devices
* are resumed. The return value is ignored.
- *
- * @pm_disk_mode: Set to the disk method that the user should be able to
- * configure for suspend-to-disk. Since %PM_DISK_SHUTDOWN,
- * %PM_DISK_REBOOT, %PM_DISK_TEST and %PM_DISK_TESTPROC
- * are always allowed, currently only %PM_DISK_PLATFORM
- * makes sense. If the user then choses %PM_DISK_PLATFORM,
- * the @prepare call will be called before suspending to disk
- * (if present), the @enter call should be present and will
- * be called after all state has been saved and the machine
- * is ready to be shut down/suspended/..., and the @finish
- * callback is called after state has been restored. All
- * these calls are called with %PM_SUSPEND_DISK as the state.
*/
struct pm_ops {
int (*valid)(suspend_state_t state);
int (*prepare)(suspend_state_t state);
int (*enter)(suspend_state_t state);
int (*finish)(suspend_state_t state);
- suspend_disk_method_t pm_disk_mode;
};
/**
@@ -165,6 +141,7 @@ extern void pm_set_ops(struct pm_ops *pm_ops);
extern struct pm_ops *pm_ops;
extern int pm_suspend(suspend_state_t state);
+extern int pm_valid_only_mem(suspend_state_t state);
/**
* arch_suspend_disable_irqs - disable IRQs for suspend
@@ -272,8 +249,6 @@ extern void device_power_up(void);
extern void device_resume(void);
#ifdef CONFIG_PM
-extern suspend_disk_method_t pm_disk_mode;
-
extern int device_suspend(pm_message_t state);
extern int device_prepare_suspend(pm_message_t state);
@@ -328,7 +303,7 @@ static inline void dpm_runtime_resume(struct device * dev)
static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
{
- return -EIO;
+ return 0;
}
#endif
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 783177387ac..37ca57392ad 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -168,24 +168,16 @@ extern int pmu_get_model(void);
struct pmu_sleep_notifier
{
- int (*notifier_call)(struct pmu_sleep_notifier *self, int when);
+ void (*notifier_call)(struct pmu_sleep_notifier *self, int when);
int priority;
struct list_head list;
};
/* Code values for calling sleep/wakeup handlers
- *
- * Note: If a sleep request got cancelled, all drivers will get
- * the PBOOK_SLEEP_REJECT, even those who didn't get the PBOOK_SLEEP_REQUEST.
*/
#define PBOOK_SLEEP_REQUEST 1
#define PBOOK_SLEEP_NOW 2
-#define PBOOK_SLEEP_REJECT 3
-#define PBOOK_WAKE 4
-
-/* Result codes returned by the notifiers */
-#define PBOOK_SLEEP_OK 0
-#define PBOOK_SLEEP_REFUSE -1
+#define PBOOK_WAKE 3
/* priority levels in notifiers */
#define SLEEP_LEVEL_VIDEO 100 /* Video driver (first wake) */
@@ -233,4 +225,12 @@ extern unsigned int pmu_power_flags;
/* Backlight */
extern void pmu_backlight_init(void);
+/* some code needs to know if the PMU was suspended for hibernation */
+#ifdef CONFIG_PM
+extern int pmu_sys_suspended;
+#else
+/* if power management is not configured it can't be suspended */
+#define pmu_sys_suspended 0
+#endif
+
#endif /* __KERNEL__ */
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index 9a5226f0f16..2a1897e6f93 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -177,6 +177,7 @@ static inline void pnp_set_card_drvdata (struct pnp_card_link *pcard, void *data
struct pnp_dev {
struct device dev; /* Driver Model device interface */
+ u64 dma_mask;
unsigned char number; /* used as an index, must be unique */
int status;
@@ -363,6 +364,7 @@ int pnp_add_device(struct pnp_dev *dev);
int pnp_device_attach(struct pnp_dev *pnp_dev);
void pnp_device_detach(struct pnp_dev *pnp_dev);
extern struct list_head pnp_global;
+extern int pnp_platform_devices;
/* multidevice card support */
int pnp_add_card(struct pnp_card *card);
@@ -410,6 +412,7 @@ static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; }
static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; }
+#define pnp_platform_devices 0
/* multidevice card support */
static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; }
diff --git a/include/linux/poison.h b/include/linux/poison.h
index 3e628f990fd..d93c300a344 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -15,8 +15,11 @@
* Magic nums for obj red zoning.
* Placed in the first word before and the first word after an obj.
*/
-#define RED_INACTIVE 0x5A2CF071UL /* when obj is inactive */
-#define RED_ACTIVE 0x170FC2A5UL /* when obj is active */
+#define RED_INACTIVE 0x09F911029D74E35BULL /* when obj is inactive */
+#define RED_ACTIVE 0xD84156C5635688C0ULL /* when obj is active */
+
+#define SLUB_RED_INACTIVE 0xbb
+#define SLUB_RED_ACTIVE 0xcc
/* ...and for poisoning */
#define POISON_INUSE 0x5a /* for use-uninitialised poisoning */
@@ -26,9 +29,6 @@
/********** arch/$ARCH/mm/init.c **********/
#define POISON_FREE_INITMEM 0xcc
-/********** arch/x86_64/mm/init.c **********/
-#define POISON_FREE_INITDATA 0xba
-
/********** arch/ia64/hp/common/sba_iommu.c **********/
/*
* arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index be4652a0545..3469f96bc8b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -104,6 +104,10 @@ int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir);
unsigned long task_vsize(struct mm_struct *);
int task_statm(struct mm_struct *, int *, int *, int *, int *);
char *task_mem(struct mm_struct *, char *);
+void clear_refs_smap(struct mm_struct *mm);
+
+struct proc_dir_entry *de_get(struct proc_dir_entry *de);
+void de_put(struct proc_dir_entry *de);
extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);
diff --git a/include/linux/quicklist.h b/include/linux/quicklist.h
new file mode 100644
index 00000000000..9371c6116df
--- /dev/null
+++ b/include/linux/quicklist.h
@@ -0,0 +1,94 @@
+#ifndef LINUX_QUICKLIST_H
+#define LINUX_QUICKLIST_H
+/*
+ * Fast allocations and disposal of pages. Pages must be in the condition
+ * as needed after allocation when they are freed. Per cpu lists of pages
+ * are kept that only contain node local pages.
+ *
+ * (C) 2007, SGI. Christoph Lameter <clameter@sgi.com>
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/percpu.h>
+
+#ifdef CONFIG_QUICKLIST
+
+struct quicklist {
+ void *page;
+ int nr_pages;
+};
+
+DECLARE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
+
+/*
+ * The two key functions quicklist_alloc and quicklist_free are inline so
+ * that they may be custom compiled for the platform.
+ * Specifying a NULL ctor can remove constructor support. Specifying
+ * a constant quicklist allows the determination of the exact address
+ * in the per cpu area.
+ *
+ * The fast patch in quicklist_alloc touched only a per cpu cacheline and
+ * the first cacheline of the page itself. There is minmal overhead involved.
+ */
+static inline void *quicklist_alloc(int nr, gfp_t flags, void (*ctor)(void *))
+{
+ struct quicklist *q;
+ void **p = NULL;
+
+ q =&get_cpu_var(quicklist)[nr];
+ p = q->page;
+ if (likely(p)) {
+ q->page = p[0];
+ p[0] = NULL;
+ q->nr_pages--;
+ }
+ put_cpu_var(quicklist);
+ if (likely(p))
+ return p;
+
+ p = (void *)__get_free_page(flags | __GFP_ZERO);
+ if (ctor && p)
+ ctor(p);
+ return p;
+}
+
+static inline void __quicklist_free(int nr, void (*dtor)(void *), void *p,
+ struct page *page)
+{
+ struct quicklist *q;
+ int nid = page_to_nid(page);
+
+ if (unlikely(nid != numa_node_id())) {
+ if (dtor)
+ dtor(p);
+ __free_page(page);
+ return;
+ }
+
+ q = &get_cpu_var(quicklist)[nr];
+ *(void **)p = q->page;
+ q->page = p;
+ q->nr_pages++;
+ put_cpu_var(quicklist);
+}
+
+static inline void quicklist_free(int nr, void (*dtor)(void *), void *pp)
+{
+ __quicklist_free(nr, dtor, pp, virt_to_page(pp));
+}
+
+static inline void quicklist_free_page(int nr, void (*dtor)(void *),
+ struct page *page)
+{
+ __quicklist_free(nr, dtor, page_address(page), page);
+}
+
+void quicklist_trim(int nr, void (*dtor)(void *),
+ unsigned long min_pages, unsigned long max_free);
+
+unsigned long quicklist_total_size(void);
+
+#endif
+
+#endif /* LINUX_QUICKLIST_H */
+
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 77db80a953d..62439828395 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -44,8 +44,6 @@
typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
typedef __u64 qsize_t; /* Type in which we store sizes */
-extern spinlock_t dq_data_lock;
-
/* Size of blocks in which are counted size limits */
#define QUOTABLOCK_BITS 10
#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
@@ -139,6 +137,8 @@ struct if_dqinfo {
#include <linux/dqblk_v1.h>
#include <linux/dqblk_v2.h>
+extern spinlock_t dq_data_lock;
+
/* Maximal numbers of writes for quota operation (insert/delete/update)
* (over VFS all formats) */
#define DQUOT_INIT_ALLOC max(V1_INIT_ALLOC, V2_INIT_ALLOC)
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 90c23f690c0..5110201a415 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -37,9 +37,6 @@ extern int dquot_release(struct dquot *dquot);
extern int dquot_commit_info(struct super_block *sb, int type);
extern int dquot_mark_dquot_dirty(struct dquot *dquot);
-int remove_inode_dquot_ref(struct inode *inode, int type,
- struct list_head *tofree_head);
-
extern int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path);
extern int vfs_quota_on_mount(struct super_block *sb, char *qf_name,
int format_id, int type);
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 0deb842541a..f9e77d2ee32 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -87,10 +87,10 @@ do { \
* management of their lifetimes must be completely managed by API users.
*
* For API usage, in general,
- * - any function _modifying_ the the tree or tags (inserting or deleting
+ * - any function _modifying_ the tree or tags (inserting or deleting
* items, setting or clearing tags must exclude other modifications, and
* exclude any functions reading the tree.
- * - any function _reading_ the the tree or tags (looking up items or tags,
+ * - any function _reading_ the tree or tags (looking up items or tags,
* gang lookups) must exclude modifications to the tree, but may occur
* concurrently with other readers.
*
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index de72c49747c..a121f36f443 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -201,7 +201,6 @@ struct mddev_s
struct mutex reconfig_mutex;
atomic_t active;
- int changed; /* true if we might need to reread partition info */
int degraded; /* whether md should consider
* adding a spare
*/
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 3a28742d86f..1e5488ede03 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -401,9 +401,10 @@ struct reiserfs_sb_info {
int reserved_blocks; /* amount of blocks reserved for further allocations */
spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
struct dentry *priv_root; /* root of /.reiserfs_priv */
+#ifdef CONFIG_REISERFS_FS_XATTR
struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
struct rw_semaphore xattr_dir_sem;
-
+#endif
int j_errno;
#ifdef CONFIG_QUOTA
char *s_qf_names[MAXQUOTAS];
diff --git a/include/linux/relay.h b/include/linux/relay.h
index 759a0f97bec..6cd8c4425fc 100644
--- a/include/linux/relay.h
+++ b/include/linux/relay.h
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/sched.h>
+#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/list.h>
#include <linux/fs.h>
@@ -38,7 +39,7 @@ struct rchan_buf
size_t subbufs_consumed; /* count of sub-buffers consumed */
struct rchan *chan; /* associated channel */
wait_queue_head_t read_wait; /* reader wait queue */
- struct delayed_work wake_readers; /* reader wake-up work struct */
+ struct timer_list timer; /* reader wake-up timer */
struct dentry *dentry; /* channel file dentry */
struct kref kref; /* channel buffer refcount */
struct page **page_array; /* array of current buffer pages */
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
new file mode 100644
index 00000000000..7c1ffbab786
--- /dev/null
+++ b/include/linux/rfkill.h
@@ -0,0 +1,89 @@
+#ifndef __RFKILL_H
+#define __RFKILL_H
+
+/*
+ * Copyright (C) 2006 Ivo van Doorn
+ * Copyright (C) 2007 Dmitry Torokhov
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/device.h>
+
+/**
+ * enum rfkill_type - type of rfkill switch.
+ * RFKILL_TYPE_WLAN: switch is no a Wireless network devices.
+ * RFKILL_TYPE_BlUETOOTH: switch is on a bluetooth device.
+ * RFKILL_TYPE_IRDA: switch is on an infrared devices.
+ */
+enum rfkill_type {
+ RFKILL_TYPE_WLAN = 0,
+ RFKILL_TYPE_BLUETOOTH = 1,
+ RFKILL_TYPE_IRDA = 2,
+ RFKILL_TYPE_MAX = 3,
+};
+
+enum rfkill_state {
+ RFKILL_STATE_OFF = 0,
+ RFKILL_STATE_ON = 1,
+};
+
+/**
+ * struct rfkill - rfkill control structure.
+ * @name: Name of the switch.
+ * @type: Radio type which the button controls, the value stored
+ * here should be a value from enum rfkill_type.
+ * @state: State of the switch (on/off).
+ * @user_claim: Set when the switch is controlled exlusively by userspace.
+ * @mutex: Guards switch state transitions
+ * @data: Pointer to the RF button drivers private data which will be
+ * passed along when toggling radio state.
+ * @toggle_radio(): Mandatory handler to control state of the radio.
+ * @dev: Device structure integrating the switch into device tree.
+ * @node: Used to place switch into list of all switches known to the
+ * the system.
+ *
+ * This structure represents a RF switch located on a network device.
+ */
+struct rfkill {
+ char *name;
+ enum rfkill_type type;
+
+ enum rfkill_state state;
+ bool user_claim;
+
+ struct mutex mutex;
+
+ void *data;
+ int (*toggle_radio)(void *data, enum rfkill_state state);
+
+ struct device dev;
+ struct list_head node;
+};
+#define to_rfkill(d) container_of(d, struct rfkill, dev)
+
+struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type);
+void rfkill_free(struct rfkill *rfkill);
+int rfkill_register(struct rfkill *rfkill);
+void rfkill_unregister(struct rfkill *rfkill);
+
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
+
+#endif /* RFKILL_H */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 5e22d4510d1..6d5e4a46781 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -4,7 +4,7 @@
* service. It is used with both the legacy mc146818 and also EFI
* Struct rtc_time and first 12 ioctl by Paul Gortmaker, 1996 - separated out
* from <linux/mc146818rtc.h> to this file for 2.4 kernels.
- *
+ *
* Copyright (C) 1999 Hewlett-Packard Co.
* Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
*/
@@ -13,7 +13,7 @@
/*
* The struct used to pass data via the following ioctl. Similar to the
- * struct tm in <time.h>, but it needs to be here so that the kernel
+ * struct tm in <time.h>, but it needs to be here so that the kernel
* source is self contained, allowing cross-compiles, etc. etc.
*/
@@ -50,7 +50,7 @@ struct rtc_wkalrm {
* pll_value*pll_posmult/pll_clock
* -ve pll_value means clock will run slower by
* pll_value*pll_negmult/pll_clock
- */
+ */
struct rtc_pll_info {
int pll_ctrl; /* placeholder for fancier control */
@@ -106,7 +106,6 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year
extern int rtc_valid_tm(struct rtc_time *tm);
extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
-extern void rtc_merge_alarm(struct rtc_time *now, struct rtc_time *alarm);
#include <linux/device.h>
#include <linux/seq_file.h>
@@ -136,7 +135,7 @@ struct rtc_task;
struct rtc_device
{
- struct class_device class_dev;
+ struct device dev;
struct module *owner;
int id;
@@ -145,7 +144,6 @@ struct rtc_device
const struct rtc_class_ops *ops;
struct mutex ops_lock;
- struct class_device *rtc_dev;
struct cdev char_dev;
struct mutex char_lock;
@@ -169,35 +167,34 @@ struct rtc_device
unsigned int uie_timer_active:1;
#endif
};
-#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
+#define to_rtc_device(d) container_of(d, struct rtc_device, dev)
extern struct rtc_device *rtc_device_register(const char *name,
struct device *dev,
const struct rtc_class_ops *ops,
struct module *owner);
-extern void rtc_device_unregister(struct rtc_device *rdev);
-extern int rtc_interface_register(struct class_interface *intf);
+extern void rtc_device_unregister(struct rtc_device *rtc);
-extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
-extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
-extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs);
-extern int rtc_read_alarm(struct class_device *class_dev,
+extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm);
+extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm);
+extern int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs);
+extern int rtc_read_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
-extern int rtc_set_alarm(struct class_device *class_dev,
+extern int rtc_set_alarm(struct rtc_device *rtc,
struct rtc_wkalrm *alrm);
-extern void rtc_update_irq(struct class_device *class_dev,
+extern void rtc_update_irq(struct rtc_device *rtc,
unsigned long num, unsigned long events);
-extern struct class_device *rtc_class_open(char *name);
-extern void rtc_class_close(struct class_device *class_dev);
+extern struct rtc_device *rtc_class_open(char *name);
+extern void rtc_class_close(struct rtc_device *rtc);
-extern int rtc_irq_register(struct class_device *class_dev,
+extern int rtc_irq_register(struct rtc_device *rtc,
struct rtc_task *task);
-extern void rtc_irq_unregister(struct class_device *class_dev,
+extern void rtc_irq_unregister(struct rtc_device *rtc,
struct rtc_task *task);
-extern int rtc_irq_set_state(struct class_device *class_dev,
+extern int rtc_irq_set_state(struct rtc_device *rtc,
struct rtc_task *task, int enabled);
-extern int rtc_irq_set_freq(struct class_device *class_dev,
+extern int rtc_irq_set_freq(struct rtc_device *rtc,
struct rtc_task *task, int freq);
typedef struct rtc_task {
diff --git a/include/linux/sched.h b/include/linux/sched.h
index a1707583de4..17b72d88c4c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -194,6 +194,14 @@ extern void sched_init_smp(void);
extern void init_idle(struct task_struct *idle, int cpu);
extern cpumask_t nohz_cpu_mask;
+#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ)
+extern int select_nohz_load_balancer(int cpu);
+#else
+static inline int select_nohz_load_balancer(int cpu)
+{
+ return 0;
+}
+#endif
/*
* Only dump TASK_* tasks. (0 for all tasks)
@@ -226,6 +234,7 @@ extern void scheduler_tick(void);
extern void softlockup_tick(void);
extern void spawn_softlockup_task(void);
extern void touch_softlockup_watchdog(void);
+extern void touch_all_softlockup_watchdogs(void);
#else
static inline void softlockup_tick(void)
{
@@ -236,6 +245,9 @@ static inline void spawn_softlockup_task(void)
static inline void touch_softlockup_watchdog(void)
{
}
+static inline void touch_all_softlockup_watchdogs(void)
+{
+}
#endif
@@ -668,8 +680,14 @@ struct sched_group {
/*
* CPU power of this group, SCHED_LOAD_SCALE being max power for a
* single CPU. This is read only (except for setup, hotplug CPU).
+ * Note : Never change cpu_power without recompute its reciprocal
+ */
+ unsigned int __cpu_power;
+ /*
+ * reciprocal value of cpu_power to avoid expensive divides
+ * (see include/linux/reciprocal_div.h)
*/
- unsigned long cpu_power;
+ u32 reciprocal_cpu_power;
};
struct sched_domain {
@@ -799,10 +817,10 @@ struct prio_array;
struct task_struct {
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
- struct thread_info *thread_info;
+ void *stack;
atomic_t usage;
- unsigned long flags; /* per process flags, defined below */
- unsigned long ptrace;
+ unsigned int flags; /* per process flags, defined below */
+ unsigned int ptrace;
int lock_depth; /* BKL lock depth */
@@ -825,7 +843,7 @@ struct task_struct {
unsigned long long sched_time; /* sched_clock time spent running */
enum sleep_type sleep_type;
- unsigned long policy;
+ unsigned int policy;
cpumask_t cpus_allowed;
unsigned int time_slice, first_time_slice;
@@ -845,11 +863,11 @@ struct task_struct {
/* task state */
struct linux_binfmt *binfmt;
- long exit_state;
+ int exit_state;
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
/* ??? */
- unsigned long personality;
+ unsigned int personality;
unsigned did_exec:1;
pid_t pid;
pid_t tgid;
@@ -881,7 +899,7 @@ struct task_struct {
int __user *set_child_tid; /* CLONE_CHILD_SETTID */
int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */
- unsigned long rt_priority;
+ unsigned int rt_priority;
cputime_t utime, stime;
unsigned long nvcsw, nivcsw; /* context switch counts */
struct timespec start_time;
@@ -1299,6 +1317,7 @@ extern int in_egroup_p(gid_t);
extern void proc_caches_init(void);
extern void flush_signals(struct task_struct *);
+extern void ignore_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
@@ -1494,8 +1513,8 @@ static inline void unlock_task_sighand(struct task_struct *tsk,
#ifndef __HAVE_THREAD_FUNCTIONS
-#define task_thread_info(task) (task)->thread_info
-#define task_stack_page(task) ((void*)((task)->thread_info))
+#define task_thread_info(task) ((struct thread_info *)(task)->stack)
+#define task_stack_page(task) ((task)->stack)
static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
{
@@ -1505,7 +1524,7 @@ static inline void setup_thread_stack(struct task_struct *p, struct task_struct
static inline unsigned long *end_of_stack(struct task_struct *p)
{
- return (unsigned long *)(p->thread_info + 1);
+ return (unsigned long *)(task_thread_info(p) + 1);
}
#endif
@@ -1641,10 +1660,7 @@ static inline void arch_pick_mmap_layout(struct mm_struct *mm)
extern long sched_setaffinity(pid_t pid, cpumask_t new_mask);
extern long sched_getaffinity(pid_t pid, cpumask_t *mask);
-#include <linux/sysdev.h>
extern int sched_mc_power_savings, sched_smt_power_savings;
-extern struct sysdev_attribute attr_sched_mc_power_savings, attr_sched_smt_power_savings;
-extern int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls);
extern void normalize_rt_tasks(void);
diff --git a/include/linux/security.h b/include/linux/security.h
index 47e82c120f9..9eb9e0fe033 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -322,7 +322,7 @@ struct request_sock;
* @dir contains the inode structure of parent of the new file.
* @dentry contains the dentry structure of the new file.
* @mode contains the mode of the new file.
- * @dev contains the the device number.
+ * @dev contains the device number.
* Return 0 if permission is granted.
* @inode_rename:
* Check for permission to rename a file or directory.
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 586aaba9172..aa2653a159f 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -39,7 +39,8 @@
#define PORT_RSA 13
#define PORT_NS16550A 14
#define PORT_XSCALE 15
-#define PORT_MAX_8250 15 /* max port ID */
+#define PORT_RM9000 16 /* PMC-Sierra RM9xxx internal UART */
+#define PORT_MAX_8250 16 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
@@ -135,6 +136,9 @@
/* Xilinx uartlite */
#define PORT_UARTLITE 74
+/* Blackfin bf5xx */
+#define PORT_BFIN 75
+
#ifdef __KERNEL__
#include <linux/compiler.h>
@@ -230,6 +234,8 @@ struct uart_port {
#define UPIO_MEM32 (3)
#define UPIO_AU (4) /* Au1x00 type IO */
#define UPIO_TSI (5) /* Tsi108/109 type IO */
+#define UPIO_DWAPB (6) /* DesignWare APB UART */
+#define UPIO_RM9000 (7) /* RM9000 type IO */
unsigned int read_status_mask; /* driver specific */
unsigned int ignore_status_mask; /* driver specific */
@@ -260,6 +266,7 @@ struct uart_port {
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
#define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
+#define UPF_FIXED_PORT ((__force upf_t) (1 << 29))
#define UPF_DEAD ((__force upf_t) (1 << 30))
#define UPF_IOREMAP ((__force upf_t) (1 << 31))
@@ -276,6 +283,7 @@ struct uart_port {
struct device *dev; /* parent device */
unsigned char hub6; /* this should be in the 8250 driver */
unsigned char unused[3];
+ void *private_data; /* generic platform data pointer */
};
/*
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 3c8a6aa7741..1c5ed7d92b0 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -38,6 +38,8 @@
#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
+#define UART_IIR_BUSY 0x07 /* DesignWare APB Busy Detect */
+
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 14749056dd6..3fa0fab4a04 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -243,6 +243,131 @@ extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
extern struct kmem_cache *sighand_cachep;
+/*
+ * In POSIX a signal is sent either to a specific thread (Linux task)
+ * or to the process as a whole (Linux thread group). How the signal
+ * is sent determines whether it's to one thread or the whole group,
+ * which determines which signal mask(s) are involved in blocking it
+ * from being delivered until later. When the signal is delivered,
+ * either it's caught or ignored by a user handler or it has a default
+ * effect that applies to the whole thread group (POSIX process).
+ *
+ * The possible effects an unblocked signal set to SIG_DFL can have are:
+ * ignore - Nothing Happens
+ * terminate - kill the process, i.e. all threads in the group,
+ * similar to exit_group. The group leader (only) reports
+ * WIFSIGNALED status to its parent.
+ * coredump - write a core dump file describing all threads using
+ * the same mm and then kill all those threads
+ * stop - stop all the threads in the group, i.e. TASK_STOPPED state
+ *
+ * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
+ * Other signals when not blocked and set to SIG_DFL behaves as follows.
+ * The job control signals also have other special effects.
+ *
+ * +--------------------+------------------+
+ * | POSIX signal | default action |
+ * +--------------------+------------------+
+ * | SIGHUP | terminate |
+ * | SIGINT | terminate |
+ * | SIGQUIT | coredump |
+ * | SIGILL | coredump |
+ * | SIGTRAP | coredump |
+ * | SIGABRT/SIGIOT | coredump |
+ * | SIGBUS | coredump |
+ * | SIGFPE | coredump |
+ * | SIGKILL | terminate(+) |
+ * | SIGUSR1 | terminate |
+ * | SIGSEGV | coredump |
+ * | SIGUSR2 | terminate |
+ * | SIGPIPE | terminate |
+ * | SIGALRM | terminate |
+ * | SIGTERM | terminate |
+ * | SIGCHLD | ignore |
+ * | SIGCONT | ignore(*) |
+ * | SIGSTOP | stop(*)(+) |
+ * | SIGTSTP | stop(*) |
+ * | SIGTTIN | stop(*) |
+ * | SIGTTOU | stop(*) |
+ * | SIGURG | ignore |
+ * | SIGXCPU | coredump |
+ * | SIGXFSZ | coredump |
+ * | SIGVTALRM | terminate |
+ * | SIGPROF | terminate |
+ * | SIGPOLL/SIGIO | terminate |
+ * | SIGSYS/SIGUNUSED | coredump |
+ * | SIGSTKFLT | terminate |
+ * | SIGWINCH | ignore |
+ * | SIGPWR | terminate |
+ * | SIGRTMIN-SIGRTMAX | terminate |
+ * +--------------------+------------------+
+ * | non-POSIX signal | default action |
+ * +--------------------+------------------+
+ * | SIGEMT | coredump |
+ * +--------------------+------------------+
+ *
+ * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
+ * (*) Special job control effects:
+ * When SIGCONT is sent, it resumes the process (all threads in the group)
+ * from TASK_STOPPED state and also clears any pending/queued stop signals
+ * (any of those marked with "stop(*)"). This happens regardless of blocking,
+ * catching, or ignoring SIGCONT. When any stop signal is sent, it clears
+ * any pending/queued SIGCONT signals; this happens regardless of blocking,
+ * catching, or ignored the stop signal, though (except for SIGSTOP) the
+ * default action of stopping the process may happen later or never.
+ */
+
+#ifdef SIGEMT
+#define SIGEMT_MASK rt_sigmask(SIGEMT)
+#else
+#define SIGEMT_MASK 0
+#endif
+
+#if SIGRTMIN > BITS_PER_LONG
+#define rt_sigmask(sig) (1ULL << ((sig)-1))
+#else
+#define rt_sigmask(sig) sigmask(sig)
+#endif
+#define siginmask(sig, mask) (rt_sigmask(sig) & (mask))
+
+#define SIG_KERNEL_ONLY_MASK (\
+ rt_sigmask(SIGKILL) | rt_sigmask(SIGSTOP))
+
+#define SIG_KERNEL_STOP_MASK (\
+ rt_sigmask(SIGSTOP) | rt_sigmask(SIGTSTP) | \
+ rt_sigmask(SIGTTIN) | rt_sigmask(SIGTTOU) )
+
+#define SIG_KERNEL_COREDUMP_MASK (\
+ rt_sigmask(SIGQUIT) | rt_sigmask(SIGILL) | \
+ rt_sigmask(SIGTRAP) | rt_sigmask(SIGABRT) | \
+ rt_sigmask(SIGFPE) | rt_sigmask(SIGSEGV) | \
+ rt_sigmask(SIGBUS) | rt_sigmask(SIGSYS) | \
+ rt_sigmask(SIGXCPU) | rt_sigmask(SIGXFSZ) | \
+ SIGEMT_MASK )
+
+#define SIG_KERNEL_IGNORE_MASK (\
+ rt_sigmask(SIGCONT) | rt_sigmask(SIGCHLD) | \
+ rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) )
+
+#define sig_kernel_only(sig) \
+ (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_ONLY_MASK))
+#define sig_kernel_coredump(sig) \
+ (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_COREDUMP_MASK))
+#define sig_kernel_ignore(sig) \
+ (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_IGNORE_MASK))
+#define sig_kernel_stop(sig) \
+ (((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_STOP_MASK))
+
+#define sig_needs_tasklist(sig) ((sig) == SIGCONT)
+
+#define sig_user_defined(t, signr) \
+ (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \
+ ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
+
+#define sig_fatal(t, signr) \
+ (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
+ (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SIGNAL_H */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2694cb3ca76..e7367c74e1b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -197,7 +197,7 @@ typedef unsigned char *sk_buff_data_t;
* @tstamp: Time we arrived
* @dev: Device we arrived on/are leaving by
* @iif: ifindex of device we arrived on
- * @h: Transport layer header
+ * @transport_header: Transport layer header
* @network_header: Network layer header
* @mac_header: Link layer header
* @dst: destination entry
@@ -1471,6 +1471,11 @@ static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len)
prefetch(skb->next), (skb != (struct sk_buff *)(queue)); \
skb = skb->next)
+#define skb_queue_walk_safe(queue, skb, tmp) \
+ for (skb = (queue)->next, tmp = skb->next; \
+ skb != (struct sk_buff *)(queue); \
+ skb = tmp, tmp = skb->next)
+
#define skb_queue_reverse_walk(queue, skb) \
for (skb = (queue)->prev; \
prefetch(skb->prev), (skb != (struct sk_buff *)(queue)); \
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 1ef822e31c7..71829efc40b 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -21,28 +21,25 @@ typedef struct kmem_cache kmem_cache_t __deprecated;
* The ones marked DEBUG are only valid if CONFIG_SLAB_DEBUG is set.
*/
#define SLAB_DEBUG_FREE 0x00000100UL /* DEBUG: Perform (expensive) checks on free */
-#define SLAB_DEBUG_INITIAL 0x00000200UL /* DEBUG: Call constructor (as verifier) */
#define SLAB_RED_ZONE 0x00000400UL /* DEBUG: Red zone objs in a cache */
#define SLAB_POISON 0x00000800UL /* DEBUG: Poison objects */
#define SLAB_HWCACHE_ALIGN 0x00002000UL /* Align objs on cache lines */
#define SLAB_CACHE_DMA 0x00004000UL /* Use GFP_DMA memory */
-#define SLAB_MUST_HWCACHE_ALIGN 0x00008000UL /* Force alignment even if debuggin is active */
#define SLAB_STORE_USER 0x00010000UL /* DEBUG: Store the last owner for bug hunting */
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
#define SLAB_PANIC 0x00040000UL /* Panic if kmem_cache_create() fails */
#define SLAB_DESTROY_BY_RCU 0x00080000UL /* Defer freeing slabs to RCU */
#define SLAB_MEM_SPREAD 0x00100000UL /* Spread some memory over cpuset */
+#define SLAB_TRACE 0x00200000UL /* Trace allocations and frees */
/* Flags passed to a constructor functions */
#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* If not set, then deconstructor */
-#define SLAB_CTOR_ATOMIC 0x002UL /* Tell constructor it can't sleep */
-#define SLAB_CTOR_VERIFY 0x004UL /* Tell constructor it's a verify call */
/*
* struct kmem_cache related prototypes
*/
void __init kmem_cache_init(void);
-extern int slab_is_available(void);
+int slab_is_available(void);
struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
unsigned long,
@@ -57,6 +54,18 @@ unsigned int kmem_cache_size(struct kmem_cache *);
const char *kmem_cache_name(struct kmem_cache *);
int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
+/*
+ * Please use this macro to create slab caches. Simply specify the
+ * name of the structure and maybe some flags that are listed above.
+ *
+ * The alignment of the struct determines object alignment. If you
+ * f.e. add ____cacheline_aligned_in_smp to the struct declaration
+ * then the objects will be properly aligned in SMP configurations.
+ */
+#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
+ sizeof(struct __struct), __alignof__(struct __struct),\
+ (__flags), NULL, NULL)
+
#ifdef CONFIG_NUMA
extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
#else
@@ -72,8 +81,9 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
*/
void *__kmalloc(size_t, gfp_t);
void *__kzalloc(size_t, gfp_t);
+void * __must_check krealloc(const void *, size_t, gfp_t);
void kfree(const void *);
-unsigned int ksize(const void *);
+size_t ksize(const void *);
/**
* kcalloc - allocate memory for an array. The memory is set to zero.
@@ -94,9 +104,14 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
* the appropriate general cache at compile time.
*/
-#ifdef CONFIG_SLAB
+#if defined(CONFIG_SLAB) || defined(CONFIG_SLUB)
+#ifdef CONFIG_SLUB
+#include <linux/slub_def.h>
+#else
#include <linux/slab_def.h>
+#endif /* !CONFIG_SLUB */
#else
+
/*
* Fallback definitions for an allocator not wanting to provide
* its own optimized kmalloc definitions (like SLOB).
@@ -183,7 +198,7 @@ static inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
* allocator where we care about the real place the memory allocation
* request comes from.
*/
-#ifdef CONFIG_DEBUG_SLAB
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
#define kmalloc_track_caller(size, flags) \
__kmalloc_track_caller(size, flags, __builtin_return_address(0))
@@ -201,7 +216,7 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
* standard allocator where we care about the real place the memory
* allocation request comes from.
*/
-#ifdef CONFIG_DEBUG_SLAB
+#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB)
extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
#define kmalloc_node_track_caller(size, flags, node) \
__kmalloc_node_track_caller(size, flags, node, \
@@ -218,6 +233,9 @@ extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
#endif /* DEBUG_SLAB */
+extern const struct seq_operations slabinfo_op;
+ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SLAB_H */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
new file mode 100644
index 00000000000..ea27065e80e
--- /dev/null
+++ b/include/linux/slub_def.h
@@ -0,0 +1,206 @@
+#ifndef _LINUX_SLUB_DEF_H
+#define _LINUX_SLUB_DEF_H
+
+/*
+ * SLUB : A Slab allocator without object queues.
+ *
+ * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
+ */
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/workqueue.h>
+#include <linux/kobject.h>
+
+struct kmem_cache_node {
+ spinlock_t list_lock; /* Protect partial list and nr_partial */
+ unsigned long nr_partial;
+ atomic_long_t nr_slabs;
+ struct list_head partial;
+ struct list_head full;
+};
+
+/*
+ * Slab cache management.
+ */
+struct kmem_cache {
+ /* Used for retriving partial slabs etc */
+ unsigned long flags;
+ int size; /* The size of an object including meta data */
+ int objsize; /* The size of an object without meta data */
+ int offset; /* Free pointer offset. */
+ unsigned int order;
+
+ /*
+ * Avoid an extra cache line for UP, SMP and for the node local to
+ * struct kmem_cache.
+ */
+ struct kmem_cache_node local_node;
+
+ /* Allocation and freeing of slabs */
+ int objects; /* Number of objects in slab */
+ int refcount; /* Refcount for slab cache destroy */
+ void (*ctor)(void *, struct kmem_cache *, unsigned long);
+ void (*dtor)(void *, struct kmem_cache *, unsigned long);
+ int inuse; /* Offset to metadata */
+ int align; /* Alignment */
+ const char *name; /* Name (only for display!) */
+ struct list_head list; /* List of slab caches */
+ struct kobject kobj; /* For sysfs */
+
+#ifdef CONFIG_NUMA
+ int defrag_ratio;
+ struct kmem_cache_node *node[MAX_NUMNODES];
+#endif
+ struct page *cpu_slab[NR_CPUS];
+};
+
+/*
+ * Kmalloc subsystem.
+ */
+#define KMALLOC_SHIFT_LOW 3
+
+#ifdef CONFIG_LARGE_ALLOCS
+#define KMALLOC_SHIFT_HIGH 25
+#else
+#if !defined(CONFIG_MMU) || NR_CPUS > 512 || MAX_NUMNODES > 256
+#define KMALLOC_SHIFT_HIGH 20
+#else
+#define KMALLOC_SHIFT_HIGH 18
+#endif
+#endif
+
+/*
+ * We keep the general caches in an array of slab caches that are used for
+ * 2^x bytes of allocations.
+ */
+extern struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_HIGH + 1];
+
+/*
+ * Sorry that the following has to be that ugly but some versions of GCC
+ * have trouble with constant propagation and loops.
+ */
+static inline int kmalloc_index(int size)
+{
+ /*
+ * We should return 0 if size == 0 but we use the smallest object
+ * here for SLAB legacy reasons.
+ */
+ WARN_ON_ONCE(size == 0);
+
+ if (size > 64 && size <= 96)
+ return 1;
+ if (size > 128 && size <= 192)
+ return 2;
+ if (size <= 8) return 3;
+ if (size <= 16) return 4;
+ if (size <= 32) return 5;
+ if (size <= 64) return 6;
+ if (size <= 128) return 7;
+ if (size <= 256) return 8;
+ if (size <= 512) return 9;
+ if (size <= 1024) return 10;
+ if (size <= 2 * 1024) return 11;
+ if (size <= 4 * 1024) return 12;
+ if (size <= 8 * 1024) return 13;
+ if (size <= 16 * 1024) return 14;
+ if (size <= 32 * 1024) return 15;
+ if (size <= 64 * 1024) return 16;
+ if (size <= 128 * 1024) return 17;
+ if (size <= 256 * 1024) return 18;
+#if KMALLOC_SHIFT_HIGH > 18
+ if (size <= 512 * 1024) return 19;
+ if (size <= 1024 * 1024) return 20;
+#endif
+#if KMALLOC_SHIFT_HIGH > 20
+ if (size <= 2 * 1024 * 1024) return 21;
+ if (size <= 4 * 1024 * 1024) return 22;
+ if (size <= 8 * 1024 * 1024) return 23;
+ if (size <= 16 * 1024 * 1024) return 24;
+ if (size <= 32 * 1024 * 1024) return 25;
+#endif
+ return -1;
+
+/*
+ * What we really wanted to do and cannot do because of compiler issues is:
+ * int i;
+ * for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
+ * if (size <= (1 << i))
+ * return i;
+ */
+}
+
+/*
+ * Find the slab cache for a given combination of allocation flags and size.
+ *
+ * This ought to end up with a global pointer to the right cache
+ * in kmalloc_caches.
+ */
+static inline struct kmem_cache *kmalloc_slab(size_t size)
+{
+ int index = kmalloc_index(size);
+
+ if (index == 0)
+ return NULL;
+
+ if (index < 0) {
+ /*
+ * Generate a link failure. Would be great if we could
+ * do something to stop the compile here.
+ */
+ extern void __kmalloc_size_too_large(void);
+ __kmalloc_size_too_large();
+ }
+ return &kmalloc_caches[index];
+}
+
+#ifdef CONFIG_ZONE_DMA
+#define SLUB_DMA __GFP_DMA
+#else
+/* Disable DMA functionality */
+#define SLUB_DMA 0
+#endif
+
+static inline void *kmalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
+ struct kmem_cache *s = kmalloc_slab(size);
+
+ if (!s)
+ return NULL;
+
+ return kmem_cache_alloc(s, flags);
+ } else
+ return __kmalloc(size, flags);
+}
+
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+ if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
+ struct kmem_cache *s = kmalloc_slab(size);
+
+ if (!s)
+ return NULL;
+
+ return kmem_cache_zalloc(s, flags);
+ } else
+ return __kzalloc(size, flags);
+}
+
+#ifdef CONFIG_NUMA
+extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
+
+static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
+ struct kmem_cache *s = kmalloc_slab(size);
+
+ if (!s)
+ return NULL;
+
+ return kmem_cache_alloc_node(s, flags, node);
+ } else
+ return __kmalloc_node(size, flags, node);
+}
+#endif
+
+#endif /* _LINUX_SLUB_DEF_H */
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 7ba23ec8211..3f70149eabb 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -83,7 +83,6 @@ void smp_prepare_boot_cpu(void);
* These macros fold the SMP functionality into a single CPU system
*/
#define raw_smp_processor_id() 0
-#define hard_smp_processor_id() 0
static inline int up_smp_call_function(void)
{
return 0;
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 854aa6b543f..802b3a38b04 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -40,6 +40,8 @@ enum
IPSTATS_MIB_FRAGCREATES, /* FragCreates */
IPSTATS_MIB_INMCASTPKTS, /* InMcastPkts */
IPSTATS_MIB_OUTMCASTPKTS, /* OutMcastPkts */
+ IPSTATS_MIB_INBCASTPKTS, /* InBcastPkts */
+ IPSTATS_MIB_OUTBCASTPKTS, /* OutBcastPkts */
__IPSTATS_MIB_MAX
};
diff --git a/include/linux/sony-laptop.h b/include/linux/sony-laptop.h
new file mode 100644
index 00000000000..e2e036d94e4
--- /dev/null
+++ b/include/linux/sony-laptop.h
@@ -0,0 +1,34 @@
+#ifndef _SONYLAPTOP_H_
+#define _SONYLAPTOP_H_
+
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+
+/* used only for communication between v4l and sony-laptop */
+
+#define SONY_PIC_COMMAND_GETCAMERA 1 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERA 2
+#define SONY_PIC_COMMAND_GETCAMERABRIGHTNESS 3 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERABRIGHTNESS 4
+#define SONY_PIC_COMMAND_GETCAMERACONTRAST 5 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACONTRAST 6
+#define SONY_PIC_COMMAND_GETCAMERAHUE 7 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAHUE 8
+#define SONY_PIC_COMMAND_GETCAMERACOLOR 9 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERACOLOR 10
+#define SONY_PIC_COMMAND_GETCAMERASHARPNESS 11 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERASHARPNESS 12
+#define SONY_PIC_COMMAND_GETCAMERAPICTURE 13 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAPICTURE 14
+#define SONY_PIC_COMMAND_GETCAMERAAGC 15 /* obsolete */
+#define SONY_PIC_COMMAND_SETCAMERAAGC 16
+#define SONY_PIC_COMMAND_GETCAMERADIRECTION 17 /* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAROMVERSION 18 /* obsolete */
+#define SONY_PIC_COMMAND_GETCAMERAREVISION 19 /* obsolete */
+
+int sony_pic_camera_command(int command, u8 value);
+
+#endif /* __KERNEL__ */
+
+#endif /* _SONYLAPTOP_H_ */
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index f56d2473495..34d4b075f7b 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -5,7 +5,7 @@
*
* Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
*
* Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
*
diff --git a/include/linux/spi/Kbuild b/include/linux/spi/Kbuild
new file mode 100644
index 00000000000..d375a082986
--- /dev/null
+++ b/include/linux/spi/Kbuild
@@ -0,0 +1 @@
+header-y += spidev.h
diff --git a/include/linux/spi/ad7877.h b/include/linux/spi/ad7877.h
new file mode 100644
index 00000000000..cdbed816f25
--- /dev/null
+++ b/include/linux/spi/ad7877.h
@@ -0,0 +1,24 @@
+/* linux/spi/ad7877.h */
+
+/* Touchscreen characteristics vary between boards and models. The
+ * platform_data for the device's "struct device" holds this information.
+ *
+ * It's OK if the min/max values are zero.
+ */
+struct ad7877_platform_data {
+ u16 model; /* 7877 */
+ u16 vref_delay_usecs; /* 0 for external vref; etc */
+ u16 x_plate_ohms;
+ u16 y_plate_ohms;
+
+ u16 x_min, x_max;
+ u16 y_min, y_max;
+ u16 pressure_min, pressure_max;
+
+ u8 stopacq_polarity; /* 1 = Active HIGH, 0 = Active LOW */
+ u8 first_conversion_delay; /* 0 = 0.5us, 1 = 128us, 2 = 1ms, 3 = 8ms */
+ u8 acquisition_time; /* 0 = 2us, 1 = 4us, 2 = 8us, 3 = 16us */
+ u8 averaging; /* 0 = 1, 1 = 4, 2 = 8, 3 = 16 */
+ u8 pen_down_acc_interval; /* 0 = covert once, 1 = every 0.5 ms,
+ 2 = ever 1 ms, 3 = every 8 ms,*/
+};
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 4f0f8c2e58a..b6bedc3ee95 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -32,11 +32,12 @@ extern struct bus_type spi_bus_type;
* @max_speed_hz: Maximum clock rate to be used with this chip
* (on this board); may be changed by the device's driver.
* The spi_transfer.speed_hz can override this for each transfer.
- * @chip-select: Chipselect, distinguishing chips handled by "master".
+ * @chip_select: Chipselect, distinguishing chips handled by @master.
* @mode: The spi mode defines how data is clocked out and in.
* This may be changed by the device's driver.
- * The "active low" default for chipselect mode can be overridden,
- * as can the "MSB first" default for each word in a transfer.
+ * The "active low" default for chipselect mode can be overridden
+ * (by specifying SPI_CS_HIGH) as can the "MSB first" default for
+ * each word in a transfer (by specifying SPI_LSB_FIRST).
* @bits_per_word: Data transfers involve one or more words; word sizes
* like eight or 12 bits are common. In-memory wordsizes are
* powers of two bytes (e.g. 20 bit samples use 32 bits).
@@ -48,14 +49,18 @@ extern struct bus_type spi_bus_type;
* @controller_state: Controller's runtime state
* @controller_data: Board-specific definitions for controller, such as
* FIFO initialization parameters; from board_info.controller_data
+ * @modalias: Name of the driver to use with this device, or an alias
+ * for that name. This appears in the sysfs "modalias" attribute
+ * for driver coldplugging, and in uevents used for hotplugging
*
- * An spi_device is used to interchange data between an SPI slave
+ * A @spi_device is used to interchange data between an SPI slave
* (usually a discrete chip) and CPU memory.
*
- * In "dev", the platform_data is used to hold information about this
+ * In @dev, the platform_data is used to hold information about this
* device that's meaningful to the device's protocol driver, but not
* to its controller. One example might be an identifier for a chip
- * variant with slightly different functionality.
+ * variant with slightly different functionality; another might be
+ * information about how this particular board wires the chip's pins.
*/
struct spi_device {
struct device dev;
@@ -77,13 +82,15 @@ struct spi_device {
void *controller_data;
const char *modalias;
- // likely need more hooks for more protocol options affecting how
- // the controller talks to each chip, like:
- // - memory packing (12 bit samples into low bits, others zeroed)
- // - priority
- // - drop chipselect after each word
- // - chipselect delays
- // - ...
+ /*
+ * likely need more hooks for more protocol options affecting how
+ * the controller talks to each chip, like:
+ * - memory packing (12 bit samples into low bits, others zeroed)
+ * - priority
+ * - drop chipselect after each word
+ * - chipselect delays
+ * - ...
+ */
};
static inline struct spi_device *to_spi_device(struct device *dev)
@@ -146,6 +153,11 @@ static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
extern int spi_register_driver(struct spi_driver *sdrv);
+/**
+ * spi_unregister_driver - reverse effect of spi_register_driver
+ * @sdrv: the driver to unregister
+ * Context: can sleep
+ */
static inline void spi_unregister_driver(struct spi_driver *sdrv)
{
if (sdrv)
@@ -165,18 +177,20 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @setup: updates the device mode and clocking records used by a
* device's SPI controller; protocol code may call this. This
* must fail if an unrecognized or unsupported mode is requested.
+ * It's always safe to call this unless transfers are pending on
+ * the device whose settings are being modified.
* @transfer: adds a message to the controller's transfer queue.
* @cleanup: frees controller-specific state
*
- * Each SPI master controller can communicate with one or more spi_device
+ * Each SPI master controller can communicate with one or more @spi_device
* children. These make a small bus, sharing MOSI, MISO and SCK signals
* but not chip select signals. Each device may be configured to use a
* different clock rate, since those shared signals are ignored unless
* the chip is selected.
*
* The driver for an SPI controller manages access to those devices through
- * a queue of spi_message transactions, copyin data between CPU memory and
- * an SPI slave device). For each such message it queues, it calls the
+ * a queue of spi_message transactions, copying data between CPU memory and
+ * an SPI slave device. For each such message it queues, it calls the
* message's completion function when the transaction completes.
*/
struct spi_master {
@@ -280,27 +294,27 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* struct spi_transfer - a read/write buffer pair
* @tx_buf: data to be written (dma-safe memory), or NULL
* @rx_buf: data to be read (dma-safe memory), or NULL
- * @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped
- * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped
+ * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
+ * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
* @len: size of rx and tx buffers (in bytes)
* @speed_hz: Select a speed other then the device default for this
- * transfer. If 0 the default (from spi_device) is used.
+ * transfer. If 0 the default (from @spi_device) is used.
* @bits_per_word: select a bits_per_word other then the device default
- * for this transfer. If 0 the default (from spi_device) is used.
+ * for this transfer. If 0 the default (from @spi_device) is used.
* @cs_change: affects chipselect after this transfer completes
* @delay_usecs: microseconds to delay after this transfer before
* (optionally) changing the chipselect status, then starting
- * the next transfer or completing this spi_message.
- * @transfer_list: transfers are sequenced through spi_message.transfers
+ * the next transfer or completing this @spi_message.
+ * @transfer_list: transfers are sequenced through @spi_message.transfers
*
* SPI transfers always write the same number of bytes as they read.
- * Protocol drivers should always provide rx_buf and/or tx_buf.
+ * Protocol drivers should always provide @rx_buf and/or @tx_buf.
* In some cases, they may also want to provide DMA addresses for
* the data being transferred; that may reduce overhead, when the
* underlying driver uses dma.
*
* If the transmit buffer is null, zeroes will be shifted out
- * while filling rx_buf. If the receive buffer is null, the data
+ * while filling @rx_buf. If the receive buffer is null, the data
* shifted in will be discarded. Only "len" bytes shift out (or in).
* It's an error to try to shift out a partial word. (For example, by
* shifting out three bytes with word size of sixteen or twenty bits;
@@ -309,7 +323,7 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
* In-memory data values are always in native CPU byte order, translated
* from the wire byte order (big-endian except with SPI_LSB_FIRST). So
* for example when bits_per_word is sixteen, buffers are 2N bytes long
- * and hold N sixteen bit words in CPU byte order.
+ * (@len = 2N) and hold N sixteen bit words in CPU byte order.
*
* When the word size of the SPI transfer is not a power-of-two multiple
* of eight bits, those in-memory words include extra bits. In-memory
@@ -318,7 +332,7 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
*
* All SPI transfers start with the relevant chipselect active. Normally
* it stays selected until after the last transfer in a message. Drivers
- * can affect the chipselect signal using cs_change:
+ * can affect the chipselect signal using cs_change.
*
* (i) If the transfer isn't the last one in the message, this flag is
* used to make the chipselect briefly go inactive in the middle of the
@@ -372,7 +386,7 @@ struct spi_transfer {
* @queue: for use by whichever driver currently owns the message
* @state: for use by whichever driver currently owns the message
*
- * An spi_message is used to execute an atomic sequence of data transfers,
+ * A @spi_message is used to execute an atomic sequence of data transfers,
* each represented by a struct spi_transfer. The sequence is "atomic"
* in the sense that no other spi_message may use that SPI bus until that
* sequence completes. On some systems, many such sequences can execute as
@@ -464,8 +478,9 @@ static inline void spi_message_free(struct spi_message *m)
}
/**
- * spi_setup -- setup SPI mode and clock rate
+ * spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
+ * Context: can sleep
*
* SPI protocol drivers may need to update the transfer mode if the
* device doesn't work with the mode 0 default. They may likewise need
@@ -474,7 +489,7 @@ static inline void spi_message_free(struct spi_message *m)
* The changes take effect the next time the device is selected and data
* is transferred to or from it.
*
- * Note that this call wil fail if the protocol driver specifies an option
+ * Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support. For
* example, not all hardware supports wire transfers using nine bit words,
* LSB-first wire encoding, or active-high chipselects.
@@ -487,9 +502,10 @@ spi_setup(struct spi_device *spi)
/**
- * spi_async -- asynchronous SPI transfer
+ * spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
+ * Context: any (irqs may be blocked, etc)
*
* This call may be used in_irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
@@ -535,6 +551,7 @@ extern int spi_sync(struct spi_device *spi, struct spi_message *message);
* @spi: device to which data will be written
* @buf: data buffer
* @len: data buffer size
+ * Context: can sleep
*
* This writes the buffer and returns zero or a negative error code.
* Callable only from contexts that can sleep.
@@ -558,8 +575,9 @@ spi_write(struct spi_device *spi, const u8 *buf, size_t len)
* @spi: device from which data will be read
* @buf: data buffer
* @len: data buffer size
+ * Context: can sleep
*
- * This writes the buffer and returns zero or a negative error code.
+ * This reads the buffer and returns zero or a negative error code.
* Callable only from contexts that can sleep.
*/
static inline int
@@ -585,6 +603,7 @@ extern int spi_write_then_read(struct spi_device *spi,
* spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
* @spi: device with which data will be exchanged
* @cmd: command to be written before data is read back
+ * Context: can sleep
*
* This returns the (unsigned) eight bit number returned by the
* device, or else a negative error code. Callable only from
@@ -605,6 +624,7 @@ static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
* spi_w8r16 - SPI synchronous 8 bit write followed by 16 bit read
* @spi: device with which data will be exchanged
* @cmd: command to be written before data is read back
+ * Context: can sleep
*
* This returns the (unsigned) sixteen bit number returned by the
* device, or else a negative error code. Callable only from
diff --git a/include/linux/spi/spidev.h b/include/linux/spi/spidev.h
new file mode 100644
index 00000000000..7d700be5749
--- /dev/null
+++ b/include/linux/spi/spidev.h
@@ -0,0 +1,124 @@
+/*
+ * include/linux/spi/spidev.h
+ *
+ * Copyright (C) 2006 SWAPP
+ * Andrea Paterniani <a.paterniani@swapp-eng.it>
+ *
+ * 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 SPIDEV_H
+#define SPIDEV_H
+
+
+/* User space versions of kernel symbols for SPI clocking modes,
+ * matching <linux/spi/spi.h>
+ */
+
+#define SPI_CPHA 0x01
+#define SPI_CPOL 0x02
+
+#define SPI_MODE_0 (0|0)
+#define SPI_MODE_1 (0|SPI_CPHA)
+#define SPI_MODE_2 (SPI_CPOL|0)
+#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
+
+
+/*---------------------------------------------------------------------------*/
+
+/* IOCTL commands */
+
+#define SPI_IOC_MAGIC 'k'
+
+/**
+ * struct spi_ioc_transfer - describes a single SPI transfer
+ * @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
+ * If no data is provided, zeroes are shifted out.
+ * @rx_buf: Holds pointer to userspace buffer for receive data, or null.
+ * @len: Length of tx and rx buffers, in bytes.
+ * @speed_hz: Temporary override of the device's bitrate.
+ * @bits_per_word: Temporary override of the device's wordsize.
+ * @delay_usecs: If nonzero, how long to delay after the last bit transfer
+ * before optionally deselecting the device before the next transfer.
+ * @cs_change: True to deselect device before starting the next transfer.
+ *
+ * This structure is mapped directly to the kernel spi_transfer structure;
+ * the fields have the same meanings, except of course that the pointers
+ * are in a different address space (and may be of different sizes in some
+ * cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
+ * Zero-initialize the structure, including currently unused fields, to
+ * accomodate potential future updates.
+ *
+ * SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
+ * Pass it an array of related transfers, they'll execute together.
+ * Each transfer may be half duplex (either direction) or full duplex.
+ *
+ * struct spi_ioc_transfer mesg[4];
+ * ...
+ * status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
+ *
+ * So for example one transfer might send a nine bit command (right aligned
+ * in a 16-bit word), the next could read a block of 8-bit data before
+ * terminating that command by temporarily deselecting the chip; the next
+ * could send a different nine bit command (re-selecting the chip), and the
+ * last transfer might write some register values.
+ */
+struct spi_ioc_transfer {
+ __u64 tx_buf;
+ __u64 rx_buf;
+
+ __u32 len;
+ __u32 speed_hz;
+
+ __u16 delay_usecs;
+ __u8 bits_per_word;
+ __u8 cs_change;
+ __u32 pad;
+
+ /* If the contents of 'struct spi_ioc_transfer' ever change
+ * incompatibly, then the ioctl number (currently 0) must change;
+ * ioctls with constant size fields get a bit more in the way of
+ * error checking than ones (like this) where that field varies.
+ *
+ * NOTE: struct layout is the same in 64bit and 32bit userspace.
+ */
+};
+
+/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
+#define SPI_MSGSIZE(N) \
+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
+ ? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
+#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+
+
+/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
+#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
+#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
+
+/* Read / Write SPI bit justification */
+#define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8)
+#define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8)
+
+/* Read / Write SPI device word length (1..N) */
+#define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC, 3, __u8)
+#define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC, 3, __u8)
+
+/* Read / Write SPI device default max speed hz */
+#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32)
+#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32)
+
+
+
+#endif /* SPIDEV_H */
diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h
index dc5fb69e4de..210549ba4ef 100644
--- a/include/linux/spinlock_types.h
+++ b/include/linux/spinlock_types.h
@@ -85,6 +85,12 @@ typedef struct {
RW_DEP_MAP_INIT(lockname) }
#endif
+/*
+ * SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and
+ * are hence deprecated.
+ * Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or
+ * __SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate.
+ */
#define SPIN_LOCK_UNLOCKED __SPIN_LOCK_UNLOCKED(old_style_spin_init)
#define RW_LOCK_UNLOCKED __RW_LOCK_UNLOCKED(old_style_rw_init)
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 50e2b01e517..1d2b084c018 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -6,15 +6,13 @@ struct stack_trace {
unsigned int nr_entries, max_entries;
unsigned long *entries;
int skip; /* input argument: How many entries to skip */
- int all_contexts; /* input argument: if true do than one stack */
};
-extern void save_stack_trace(struct stack_trace *trace,
- struct task_struct *task);
+extern void save_stack_trace(struct stack_trace *trace);
extern void print_stack_trace(struct stack_trace *trace, int spaces);
#else
-# define save_stack_trace(trace, task) do { } while (0)
+# define save_stack_trace(trace) do { } while (0)
# define print_stack_trace(trace) do { } while (0)
#endif
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 679ef0d70b6..611c398dab7 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -53,6 +53,9 @@
#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH)
#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)
+#define UTIME_NOW ((1l << 30) - 1l)
+#define UTIME_OMIT ((1l << 30) - 2l)
+
#include <linux/types.h>
#include <linux/time.h>
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index c7a78eef2b4..66611423c8e 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -84,7 +84,8 @@ struct rpc_procinfo {
u32 p_proc; /* RPC procedure number */
kxdrproc_t p_encode; /* XDR encode function */
kxdrproc_t p_decode; /* XDR decode function */
- unsigned int p_bufsiz; /* req. buffer size */
+ unsigned int p_arglen; /* argument hdr length (u32) */
+ unsigned int p_replen; /* reply hdr length (u32) */
unsigned int p_count; /* call count */
unsigned int p_timer; /* Which RTT timer to use */
u32 p_statidx; /* Which procedure to account */
@@ -121,8 +122,8 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
int rpc_shutdown_client(struct rpc_clnt *);
int rpc_destroy_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
-void rpc_getport(struct rpc_task *);
-int rpc_register(u32, u32, int, unsigned short, int *);
+int rpcb_register(u32, u32, int, unsigned short, int *);
+void rpcb_getport(struct rpc_task *);
void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
@@ -144,7 +145,7 @@ char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
/*
* Helper function for NFSroot support
*/
-int rpc_getport_external(struct sockaddr_in *, __u32, __u32, int);
+int rpcb_getport_external(struct sockaddr_in *, __u32, __u32, int);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_CLNT_H */
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index b7c7307ceec..3912cf16361 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -17,7 +17,7 @@
#define RPCDBG_DEBUG 0x0004
#define RPCDBG_NFS 0x0008
#define RPCDBG_AUTH 0x0010
-#define RPCDBG_PMAP 0x0020
+#define RPCDBG_BIND 0x0020
#define RPCDBG_SCHED 0x0040
#define RPCDBG_TRANS 0x0080
#define RPCDBG_SVCSOCK 0x0100
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 606cb216523..784d4c3ef65 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -78,10 +78,6 @@ enum rpc_auth_stat {
RPCSEC_GSS_CTXPROBLEM = 14
};
-#define RPC_PMAP_PROGRAM 100000
-#define RPC_PMAP_VERSION 2
-#define RPC_PMAP_PORT 111
-
#define RPC_MAXNETNAMELEN 256
/*
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 3069ecca012..2047fb202a1 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -264,7 +264,7 @@ struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
void rpc_wake_up_status(struct rpc_wait_queue *, int);
void rpc_delay(struct rpc_task *, unsigned long);
void * rpc_malloc(struct rpc_task *, size_t);
-void rpc_free(struct rpc_task *);
+void rpc_free(void *);
int rpciod_up(void);
void rpciod_down(void);
int __rpc_wait_for_completion_task(struct rpc_task *task, int (*)(void *));
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 35fa4d5aadd..4a7ae8ab6eb 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -396,4 +396,23 @@ char * svc_print_addr(struct svc_rqst *, char *, size_t);
#define RPC_MAX_ADDRBUFLEN (63U)
+/*
+ * When we want to reduce the size of the reserved space in the response
+ * buffer, we need to take into account the size of any checksum data that
+ * may be at the end of the packet. This is difficult to determine exactly
+ * for all cases without actually generating the checksum, so we just use a
+ * static value.
+ */
+static inline void
+svc_reserve_auth(struct svc_rqst *rqstp, int space)
+{
+ int added_space = 0;
+
+ switch(rqstp->rq_authop->flavour) {
+ case RPC_AUTH_GSS:
+ added_space = RPC_MAX_AUTH_SIZE;
+ }
+ return svc_reserve(rqstp, space + added_space);
+}
+
#endif /* SUNRPC_SVC_H */
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 7909687557b..e21dd93ac4b 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -37,7 +37,8 @@ struct svc_sock {
atomic_t sk_reserved; /* space on outq that is reserved */
- spinlock_t sk_defer_lock; /* protects sk_deferred */
+ spinlock_t sk_lock; /* protects sk_deferred and
+ * sk_info_authunix */
struct list_head sk_deferred; /* deferred requests that need to
* be revisted */
struct mutex sk_mutex; /* to serialize sending data */
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index f780e72fc41..fa89ce6ce07 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -84,7 +84,9 @@ struct rpc_rqst {
struct list_head rq_list;
__u32 * rq_buffer; /* XDR encode buffer */
- size_t rq_bufsize;
+ size_t rq_bufsize,
+ rq_callsize,
+ rq_rcvsize;
struct xdr_buf rq_private_buf; /* The receive buffer
* used in the softirq.
@@ -112,7 +114,7 @@ struct rpc_xprt_ops {
void (*set_port)(struct rpc_xprt *xprt, unsigned short port);
void (*connect)(struct rpc_task *task);
void * (*buf_alloc)(struct rpc_task *task, size_t size);
- void (*buf_free)(struct rpc_task *task);
+ void (*buf_free)(void *buffer);
int (*send_request)(struct rpc_task *task);
void (*set_retrans_timeout)(struct rpc_task *task);
void (*timer)(struct rpc_task *task);
@@ -150,6 +152,7 @@ struct rpc_xprt {
unsigned long state; /* transport state */
unsigned char shutdown : 1, /* being shut down */
resvport : 1; /* use a reserved port */
+ unsigned int bind_index; /* bind function index */
/*
* Connection of transports
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index bf99bd49f8e..9c7cb643066 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -1,13 +1,14 @@
#ifndef _LINUX_SWSUSP_H
#define _LINUX_SWSUSP_H
-#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32)
+#if defined(CONFIG_X86) || defined(CONFIG_FRV) || defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
#include <asm/suspend.h>
#endif
#include <linux/swap.h>
#include <linux/notifier.h>
#include <linux/init.h>
#include <linux/pm.h>
+#include <linux/mm.h>
/* struct pbe is used for creating lists of pages that should be restored
* atomically during the resume from disk, because the page frames they have
@@ -23,36 +24,65 @@ struct pbe {
extern void drain_local_pages(void);
extern void mark_free_pages(struct zone *zone);
-#ifdef CONFIG_PM
-/* kernel/power/swsusp.c */
-extern int software_suspend(void);
-
-#if defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
+#if defined(CONFIG_PM) && defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE)
extern int pm_prepare_console(void);
extern void pm_restore_console(void);
#else
static inline int pm_prepare_console(void) { return 0; }
static inline void pm_restore_console(void) {}
-#endif /* defined(CONFIG_VT) && defined(CONFIG_VT_CONSOLE) */
-#else
-static inline int software_suspend(void)
+#endif
+
+/**
+ * struct hibernation_ops - hibernation platform support
+ *
+ * The methods in this structure allow a platform to override the default
+ * mechanism of shutting down the machine during a hibernation transition.
+ *
+ * All three methods must be assigned.
+ *
+ * @prepare: prepare system for hibernation
+ * @enter: shut down system after state has been saved to disk
+ * @finish: finish/clean up after state has been reloaded
+ */
+struct hibernation_ops {
+ int (*prepare)(void);
+ int (*enter)(void);
+ void (*finish)(void);
+};
+
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+/* kernel/power/snapshot.c */
+extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
+static inline void register_nosave_region(unsigned long b, unsigned long e)
{
- printk("Warning: fake suspend called\n");
- return -ENOSYS;
+ __register_nosave_region(b, e, 0);
}
-#endif /* CONFIG_PM */
+static inline void register_nosave_region_late(unsigned long b, unsigned long e)
+{
+ __register_nosave_region(b, e, 1);
+}
+extern int swsusp_page_is_forbidden(struct page *);
+extern void swsusp_set_page_free(struct page *);
+extern void swsusp_unset_page_free(struct page *);
+extern unsigned long get_safe_page(gfp_t gfp_mask);
+
+extern void hibernation_set_ops(struct hibernation_ops *ops);
+extern int hibernate(void);
+#else
+static inline void register_nosave_region(unsigned long b, unsigned long e) {}
+static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
+static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
+static inline void swsusp_set_page_free(struct page *p) {}
+static inline void swsusp_unset_page_free(struct page *p) {}
+
+static inline void hibernation_set_ops(struct hibernation_ops *ops) {}
+static inline int hibernate(void) { return -ENOSYS; }
+#endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
void save_processor_state(void);
void restore_processor_state(void);
struct saved_context;
void __save_processor_state(struct saved_context *ctxt);
void __restore_processor_state(struct saved_context *ctxt);
-unsigned long get_safe_page(gfp_t gfp_mask);
-
-/*
- * XXX: We try to keep some more pages free so that I/O operations succeed
- * without paging. Might this be more?
- */
-#define PAGES_FOR_IO 1024
#endif /* _LINUX_SWSUSP_H */
diff --git a/include/linux/svga.h b/include/linux/svga.h
index eadb981bb37..13ad0b82ac2 100644
--- a/include/linux/svga.h
+++ b/include/linux/svga.h
@@ -112,6 +112,9 @@ void svga_tilecopy(struct fb_info *info, struct fb_tilearea *area);
void svga_tilefill(struct fb_info *info, struct fb_tilerect *rect);
void svga_tileblit(struct fb_info *info, struct fb_tileblit *blit);
void svga_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor);
+int svga_get_tilemax(struct fb_info *info);
+void svga_get_caps(struct fb_info *info, struct fb_blit_caps *caps,
+ struct fb_var_screeninfo *var);
int svga_compute_pll(const struct svga_pll *pll, u32 f_wanted, u16 *m, u16 *n, u16 *r, int node);
int svga_check_timings(const struct svga_timing_regs *tm, struct fb_var_screeninfo *var, int node);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 1912c6cbef5..3139f441229 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -576,6 +576,8 @@ asmlinkage long sys_fstatat64(int dfd, char __user *filename,
struct stat64 __user *statbuf, int flag);
asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf,
int bufsiz);
+asmlinkage long sys_utimensat(int dfd, char __user *filename,
+ struct timespec __user *utimes, int flags);
asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename,
struct compat_timeval __user *t);
asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
index 389ccf858d3..e699ab279c2 100644
--- a/include/linux/sysdev.h
+++ b/include/linux/sysdev.h
@@ -22,6 +22,7 @@
#define _SYSDEV_H_
#include <linux/kobject.h>
+#include <linux/module.h>
#include <linux/pm.h>
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
index 3deb0a6c137..6b3a31805c7 100644
--- a/include/linux/tifm.h
+++ b/include/linux/tifm.h
@@ -14,16 +14,16 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
-#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/pci.h>
-#include <linux/kthread.h>
+#include <linux/workqueue.h>
/* Host registers (relative to pci base address): */
enum {
FM_SET_INTERRUPT_ENABLE = 0x008,
FM_CLEAR_INTERRUPT_ENABLE = 0x00c,
- FM_INTERRUPT_STATUS = 0x014 };
+ FM_INTERRUPT_STATUS = 0x014
+};
/* Socket registers (relative to socket base address): */
enum {
@@ -58,78 +58,86 @@ enum {
SOCK_MS_DATA = 0x188,
SOCK_MS_STATUS = 0x18c,
SOCK_MS_SYSTEM = 0x190,
- SOCK_FIFO_ACCESS = 0x200 };
-
-
-#define TIFM_IRQ_ENABLE 0x80000000
-#define TIFM_IRQ_SOCKMASK(x) (x)
-#define TIFM_IRQ_CARDMASK(x) ((x) << 8)
-#define TIFM_IRQ_FIFOMASK(x) ((x) << 16)
-#define TIFM_IRQ_SETALL 0xffffffff
+ SOCK_FIFO_ACCESS = 0x200
+};
#define TIFM_CTRL_LED 0x00000040
#define TIFM_CTRL_FAST_CLK 0x00000100
+#define TIFM_CTRL_POWER_MASK 0x00000007
#define TIFM_SOCK_STATE_OCCUPIED 0x00000008
#define TIFM_SOCK_STATE_POWERED 0x00000080
-#define TIFM_FIFO_ENABLE 0x00000001 /* Meaning of this constant is unverified */
+#define TIFM_FIFO_ENABLE 0x00000001
+#define TIFM_FIFO_READY 0x00000001
#define TIFM_FIFO_INT_SETALL 0x0000ffff
-#define TIFM_FIFO_INTMASK 0x00000005 /* Meaning of this constant is unverified */
+#define TIFM_FIFO_INTMASK 0x00000005
+
+#define TIFM_DMA_RESET 0x00000002
+#define TIFM_DMA_TX 0x00008000
+#define TIFM_DMA_EN 0x00000001
+#define TIFM_DMA_TSIZE 0x0000007f
-#define TIFM_DMA_RESET 0x00000002 /* Meaning of this constant is unverified */
-#define TIFM_DMA_TX 0x00008000 /* Meaning of this constant is unverified */
-#define TIFM_DMA_EN 0x00000001 /* Meaning of this constant is unverified */
+#define TIFM_TYPE_XD 1
+#define TIFM_TYPE_MS 2
+#define TIFM_TYPE_SD 3
-typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id;
+struct tifm_device_id {
+ unsigned char type;
+};
struct tifm_driver;
struct tifm_dev {
- char __iomem *addr;
- spinlock_t lock;
- tifm_media_id media_id;
- unsigned int socket_id;
+ char __iomem *addr;
+ spinlock_t lock;
+ unsigned char type;
+ unsigned int socket_id;
- void (*signal_irq)(struct tifm_dev *sock,
- unsigned int sock_irq_status);
+ void (*card_event)(struct tifm_dev *sock);
+ void (*data_event)(struct tifm_dev *sock);
- struct tifm_driver *drv;
- struct device dev;
+ struct device dev;
};
struct tifm_driver {
- tifm_media_id *id_table;
- int (*probe)(struct tifm_dev *dev);
- void (*remove)(struct tifm_dev *dev);
- int (*suspend)(struct tifm_dev *dev,
- pm_message_t state);
- int (*resume)(struct tifm_dev *dev);
-
- struct device_driver driver;
+ struct tifm_device_id *id_table;
+ int (*probe)(struct tifm_dev *dev);
+ void (*remove)(struct tifm_dev *dev);
+ int (*suspend)(struct tifm_dev *dev,
+ pm_message_t state);
+ int (*resume)(struct tifm_dev *dev);
+
+ struct device_driver driver;
};
struct tifm_adapter {
- char __iomem *addr;
- spinlock_t lock;
- unsigned int irq_status;
- unsigned int socket_change_set;
- wait_queue_head_t change_set_notify;
- unsigned int id;
- unsigned int num_sockets;
- struct tifm_dev **sockets;
- struct task_struct *media_switcher;
- struct class_device cdev;
- struct device *dev;
-
- void (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock);
+ char __iomem *addr;
+ spinlock_t lock;
+ unsigned int irq_status;
+ unsigned int socket_change_set;
+ unsigned int id;
+ unsigned int num_sockets;
+ struct completion *finish_me;
+
+ struct work_struct media_switcher;
+ struct class_device cdev;
+
+ void (*eject)(struct tifm_adapter *fm,
+ struct tifm_dev *sock);
+
+ struct tifm_dev *sockets[0];
};
-struct tifm_adapter *tifm_alloc_adapter(void);
-void tifm_free_device(struct device *dev);
-void tifm_free_adapter(struct tifm_adapter *fm);
-int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
+struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
+ struct device *dev);
+int tifm_add_adapter(struct tifm_adapter *fm);
void tifm_remove_adapter(struct tifm_adapter *fm);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
+void tifm_free_adapter(struct tifm_adapter *fm);
+
+void tifm_free_device(struct device *dev);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
+ unsigned char type);
+
int tifm_register_driver(struct tifm_driver *drv);
void tifm_unregister_driver(struct tifm_driver *drv);
void tifm_eject(struct tifm_dev *sock);
@@ -137,11 +145,11 @@ int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
int direction);
void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
int direction);
-
+void tifm_queue_work(struct work_struct *work);
static inline void *tifm_get_drvdata(struct tifm_dev *dev)
{
- return dev_get_drvdata(&dev->dev);
+ return dev_get_drvdata(&dev->dev);
}
static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
@@ -149,8 +157,4 @@ static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
dev_set_drvdata(&dev->dev, data);
}
-struct tifm_device_id {
- tifm_media_id media_id;
-};
-
#endif
diff --git a/include/linux/time.h b/include/linux/time.h
index 8ea8dea713c..dda9be685ab 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -109,7 +109,7 @@ extern void do_gettimeofday(struct timeval *tv);
extern int do_settimeofday(struct timespec *tv);
extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
#define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
-extern long do_utimes(int dfd, char __user *filename, struct timeval *times);
+extern long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags);
struct itimerval;
extern int do_setitimer(int which, struct itimerval *value,
struct itimerval *ovalue);
@@ -119,6 +119,7 @@ extern void getnstimeofday(struct timespec *tv);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_is_continuous(void);
+extern void update_wall_time(void);
/**
* timespec_to_ns - Convert timespec to nanoseconds
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 719113b652d..e0c5c16c992 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -37,6 +37,7 @@ extern struct tvec_t_base_s boot_tvec_bases;
TIMER_INITIALIZER(_function, _expires, _data)
void fastcall init_timer(struct timer_list * timer);
+void fastcall init_timer_deferrable(struct timer_list *timer);
static inline void setup_timer(struct timer_list * timer,
void (*function)(unsigned long),
diff --git a/include/linux/tty.h b/include/linux/tty.h
index dee72b9a20f..bb457608520 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -313,6 +313,7 @@ extern int tty_hung_up_p(struct file * filp);
extern void do_SAK(struct tty_struct *tty);
extern void __do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
+extern void no_tty(void);
extern void tty_flip_buffer_push(struct tty_struct *tty);
extern speed_t tty_get_baud_rate(struct tty_struct *tty);
extern speed_t tty_termios_baud_rate(struct ktermios *termios);
@@ -333,7 +334,6 @@ extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
extern dev_t tty_devnum(struct tty_struct *tty);
extern void proc_clear_tty(struct task_struct *p);
-extern void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
extern struct tty_struct *get_current_tty(void);
extern struct mutex tty_mutex;
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 1fd61eeed66..a6c1e8eed22 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -32,6 +32,8 @@
* - first public version
*/
+#include <linux/input.h>
+
#define UINPUT_VERSION 3
#ifdef __KERNEL__
diff --git a/include/linux/usb.h b/include/linux/usb.h
index cfbd2bb8fa2..94bd38a6d94 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -126,7 +126,7 @@ enum usb_interface_condition {
* Each interface may have alternate settings. The initial configuration
* of a device sets altsetting 0, but the device driver can change
* that setting using usb_set_interface(). Alternate settings are often
- * used to control the the use of periodic endpoints, such as by having
+ * used to control the use of periodic endpoints, such as by having
* different endpoints use different amounts of reserved USB bandwidth.
* All standards-conformant USB devices that use isochronous endpoints
* will use them in non-default settings.
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
new file mode 100644
index 00000000000..4f2d012d730
--- /dev/null
+++ b/include/linux/usb_sl811.h
@@ -0,0 +1,26 @@
+
+/*
+ * board initialization should put one of these into dev->platform_data
+ * and place the sl811hs onto platform_bus named "sl811-hcd".
+ */
+
+struct sl811_platform_data {
+ unsigned can_wakeup:1;
+
+ /* given port_power, msec/2 after power on till power good */
+ u8 potpg;
+
+ /* mA/2 power supplied on this port (max = default = 250) */
+ u8 power;
+
+ /* sl811 relies on an external source of VBUS current */
+ void (*port_power)(struct device *dev, int is_on);
+
+ /* pulse sl811 nRST (probably with a GPIO) */
+ void (*reset)(struct device *dev);
+
+ // some boards need something like these:
+ // int (*check_overcurrent)(struct device *dev);
+ // void (*clock_enable)(struct device *dev, int is_on);
+};
+
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index e10267d402c..f8d3b326e93 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -49,9 +49,7 @@ static inline void get_uts_ns(struct uts_namespace *ns)
}
#ifdef CONFIG_UTS_NS
-extern int unshare_utsname(unsigned long unshare_flags,
- struct uts_namespace **new_uts);
-extern int copy_utsname(int flags, struct task_struct *tsk);
+extern struct uts_namespace *copy_utsname(int flags, struct uts_namespace *ns);
extern void free_uts_ns(struct kref *kref);
static inline void put_uts_ns(struct uts_namespace *ns)
@@ -59,21 +57,12 @@ static inline void put_uts_ns(struct uts_namespace *ns)
kref_put(&ns->kref, free_uts_ns);
}
#else
-static inline int unshare_utsname(unsigned long unshare_flags,
- struct uts_namespace **new_uts)
+static inline struct uts_namespace *copy_utsname(int flags,
+ struct uts_namespace *ns)
{
- if (unshare_flags & CLONE_NEWUTS)
- return -EINVAL;
-
- return 0;
+ return ns;
}
-static inline int copy_utsname(int flags, struct task_struct *tsk)
-{
- if (flags & CLONE_NEWUTS)
- return -EINVAL;
- return 0;
-}
static inline void put_uts_ns(struct uts_namespace *ns)
{
}
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 924e502905d..4b7ee83787c 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -53,6 +53,7 @@ extern void vunmap(void *addr);
extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
unsigned long pgoff);
+void vmalloc_sync_all(void);
/*
* Lowlevel-APIs (not for driver use!)
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index acb1f105870..d9325cf8a13 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -212,8 +212,6 @@ extern void dec_zone_state(struct zone *, enum zone_stat_item);
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
void refresh_cpu_vm_stats(int);
-void refresh_vm_stats(void);
-
#else /* CONFIG_SMP */
/*
@@ -260,7 +258,6 @@ static inline void __dec_zone_page_state(struct page *page,
#define mod_zone_page_state __mod_zone_page_state
static inline void refresh_cpu_vm_stats(int cpu) { }
-static inline void refresh_vm_stats(void) { }
#endif
#endif /* _LINUX_VMSTAT_H */
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index e0db669998f..d961635d0e6 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -9,6 +9,7 @@
#include <linux/vt.h>
#include <linux/kd.h>
#include <linux/tty.h>
+#include <linux/mutex.h>
#include <linux/console_struct.h>
#include <linux/mm.h>
@@ -82,7 +83,7 @@ void reset_vc(struct vc_data *vc);
#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
extern char con_buf[CON_BUF_SIZE];
-extern struct semaphore con_buf_sem;
+extern struct mutex con_buf_mtx;
extern char vt_dont_switch;
struct vt_spawn_console {
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 48759b2f57d..0987aa7a6cf 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -186,7 +186,7 @@
* - Wireless Event capability in struct iw_range
* - Add support for relative TxPower (yick !)
*
- * V17 to V18 (From Jouni Malinen <jkmaline@cc.hut.fi>)
+ * V17 to V18 (From Jouni Malinen <j@w1.fi>)
* ----------
* - Add support for WPA/WPA2
* - Add extended encoding configuration (SIOCSIWENCODEEXT and
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index b8abfc74d03..d555f31c074 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -24,15 +24,13 @@ typedef void (*work_func_t)(struct work_struct *work);
struct work_struct {
atomic_long_t data;
#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */
-#define WORK_STRUCT_NOAUTOREL 1 /* F if work item automatically released on exec */
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
struct list_head entry;
work_func_t func;
};
-#define WORK_DATA_INIT(autorelease) \
- ATOMIC_LONG_INIT((autorelease) << WORK_STRUCT_NOAUTOREL)
+#define WORK_DATA_INIT() ATOMIC_LONG_INIT(0)
struct delayed_work {
struct work_struct work;
@@ -44,14 +42,8 @@ struct execute_work {
};
#define __WORK_INITIALIZER(n, f) { \
- .data = WORK_DATA_INIT(0), \
- .entry = { &(n).entry, &(n).entry }, \
- .func = (f), \
- }
-
-#define __WORK_INITIALIZER_NAR(n, f) { \
- .data = WORK_DATA_INIT(1), \
- .entry = { &(n).entry, &(n).entry }, \
+ .data = WORK_DATA_INIT(), \
+ .entry = { &(n).entry, &(n).entry }, \
.func = (f), \
}
@@ -60,23 +52,12 @@ struct execute_work {
.timer = TIMER_INITIALIZER(NULL, 0, 0), \
}
-#define __DELAYED_WORK_INITIALIZER_NAR(n, f) { \
- .work = __WORK_INITIALIZER_NAR((n).work, (f)), \
- .timer = TIMER_INITIALIZER(NULL, 0, 0), \
- }
-
#define DECLARE_WORK(n, f) \
struct work_struct n = __WORK_INITIALIZER(n, f)
-#define DECLARE_WORK_NAR(n, f) \
- struct work_struct n = __WORK_INITIALIZER_NAR(n, f)
-
#define DECLARE_DELAYED_WORK(n, f) \
struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f)
-#define DECLARE_DELAYED_WORK_NAR(n, f) \
- struct dwork_struct n = __DELAYED_WORK_INITIALIZER_NAR(n, f)
-
/*
* initialize a work item's function pointer
*/
@@ -95,16 +76,9 @@ struct execute_work {
* assignment of the work data initializer allows the compiler
* to generate better code.
*/
-#define INIT_WORK(_work, _func) \
- do { \
- (_work)->data = (atomic_long_t) WORK_DATA_INIT(0); \
- INIT_LIST_HEAD(&(_work)->entry); \
- PREPARE_WORK((_work), (_func)); \
- } while (0)
-
-#define INIT_WORK_NAR(_work, _func) \
+#define INIT_WORK(_work, _func) \
do { \
- (_work)->data = (atomic_long_t) WORK_DATA_INIT(1); \
+ (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \
INIT_LIST_HEAD(&(_work)->entry); \
PREPARE_WORK((_work), (_func)); \
} while (0)
@@ -115,10 +89,10 @@ struct execute_work {
init_timer(&(_work)->timer); \
} while (0)
-#define INIT_DELAYED_WORK_NAR(_work, _func) \
+#define INIT_DELAYED_WORK_DEFERRABLE(_work, _func) \
do { \
- INIT_WORK_NAR(&(_work)->work, (_func)); \
- init_timer(&(_work)->timer); \
+ INIT_WORK(&(_work)->work, (_func)); \
+ init_timer_deferrable(&(_work)->timer); \
} while (0)
/**
@@ -137,24 +111,10 @@ struct execute_work {
work_pending(&(w)->work)
/**
- * work_release - Release a work item under execution
- * @work: The work item to release
- *
- * This is used to release a work item that has been initialised with automatic
- * release mode disabled (WORK_STRUCT_NOAUTOREL is set). This gives the work
- * function the opportunity to grab auxiliary data from the container of the
- * work_struct before clearing the pending bit as the work_struct may be
- * subject to deallocation the moment the pending bit is cleared.
- *
- * In such a case, this should be called in the work function after it has
- * fetched any data it may require from the containter of the work_struct.
- * After this function has been called, the work_struct may be scheduled for
- * further execution or it may be deallocated unless other precautions are
- * taken.
- *
- * This should also be used to release a delayed work item.
+ * work_clear_pending - for internal use only, mark a work item as not pending
+ * @work: The work item in question
*/
-#define work_release(work) \
+#define work_clear_pending(work) \
clear_bit(WORK_STRUCT_PENDING, work_data_bits(work))
@@ -168,27 +128,28 @@ extern struct workqueue_struct *__create_workqueue(const char *name,
extern void destroy_workqueue(struct workqueue_struct *wq);
extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work));
-extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay));
+extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq,
+ struct delayed_work *work, unsigned long delay));
extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
- struct delayed_work *work, unsigned long delay);
+ struct delayed_work *work, unsigned long delay);
+
extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq));
+extern void flush_scheduled_work(void);
extern int FASTCALL(schedule_work(struct work_struct *work));
-extern int FASTCALL(run_scheduled_work(struct work_struct *work));
-extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, unsigned long delay));
-
-extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay);
+extern int FASTCALL(schedule_delayed_work(struct delayed_work *work,
+ unsigned long delay));
+extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,
+ unsigned long delay);
extern int schedule_on_each_cpu(work_func_t func);
-extern void flush_scheduled_work(void);
extern int current_is_keventd(void);
extern int keventd_up(void);
extern void init_workqueues(void);
-void cancel_rearming_delayed_work(struct delayed_work *work);
-void cancel_rearming_delayed_workqueue(struct workqueue_struct *,
- struct delayed_work *);
int execute_in_process_context(work_func_t fn, struct execute_work *);
+extern void cancel_work_sync(struct work_struct *work);
+
/*
* Kill off a pending schedule_delayed_work(). Note that the work callback
* function may still be running on return from cancel_delayed_work(), unless
@@ -201,8 +162,18 @@ static inline int cancel_delayed_work(struct delayed_work *work)
ret = del_timer(&work->timer);
if (ret)
- work_release(&work->work);
+ work_clear_pending(&work->work);
return ret;
}
+extern void cancel_rearming_delayed_work(struct delayed_work *work);
+
+/* Obsolete. use cancel_rearming_delayed_work() */
+static inline
+void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
+ struct delayed_work *work)
+{
+ cancel_rearming_delayed_work(work);
+}
+
#endif
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 0c78f7f4a97..daa6c125f66 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -59,6 +59,8 @@ struct writeback_control {
unsigned for_reclaim:1; /* Invoked from the page allocator */
unsigned for_writepages:1; /* This is a writepages() call */
unsigned range_cyclic:1; /* range_start is cyclic */
+
+ void *fs_private; /* For use by ->writepages() */
};
/*
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 9c656a5cf84..b58adc52448 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -185,6 +185,11 @@ enum {
#define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO
XFRM_MSG_GETSADINFO,
#define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO
+
+ XFRM_MSG_NEWSPDINFO,
+#define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
+ XFRM_MSG_GETSPDINFO,
+#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
__XFRM_MSG_MAX
};
#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
@@ -238,17 +243,6 @@ enum xfrm_ae_ftype_t {
#define XFRM_AE_MAX (__XFRM_AE_MAX - 1)
};
-/* SAD Table filter flags */
-enum xfrm_sad_ftype_t {
- XFRM_SAD_UNSPEC,
- XFRM_SAD_HMASK=1,
- XFRM_SAD_HMAX=2,
- XFRM_SAD_CNT=4,
- __XFRM_SAD_MAX
-
-#define XFRM_SAD_MAX (__XFRM_SAD_MAX - 1)
-};
-
struct xfrm_userpolicy_type {
__u8 type;
__u16 reserved1;
@@ -282,14 +276,41 @@ enum xfrm_attr_type_t {
enum xfrm_sadattr_type_t {
XFRMA_SAD_UNSPEC,
- XFRMA_SADHMASK,
- XFRMA_SADHMAX,
- XFRMA_SADCNT,
+ XFRMA_SAD_CNT,
+ XFRMA_SAD_HINFO,
__XFRMA_SAD_MAX
#define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1)
};
+struct xfrmu_sadhinfo {
+ __u32 sadhcnt; /* current hash bkts */
+ __u32 sadhmcnt; /* max allowed hash bkts */
+};
+
+enum xfrm_spdattr_type_t {
+ XFRMA_SPD_UNSPEC,
+ XFRMA_SPD_INFO,
+ XFRMA_SPD_HINFO,
+ __XFRMA_SPD_MAX
+
+#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
+};
+
+struct xfrmu_spdinfo {
+ __u32 incnt;
+ __u32 outcnt;
+ __u32 fwdcnt;
+ __u32 inscnt;
+ __u32 outscnt;
+ __u32 fwdscnt;
+};
+
+struct xfrmu_spdhinfo {
+ __u32 spdhcnt;
+ __u32 spdhmcnt;
+};
+
struct xfrm_usersa_info {
struct xfrm_selector sel;
struct xfrm_id id;
diff --git a/include/math-emu/extended.h b/include/math-emu/extended.h
deleted file mode 100644
index 84770fceb53..00000000000
--- a/include/math-emu/extended.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/* Software floating-point emulation.
- Definitions for IEEE Extended Precision.
- Copyright (C) 1999 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Jakub Jelinek (jj@ultra.linux.cz).
-
- The GNU C Library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Library General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- The GNU C Library 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
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with the GNU C Library; see the file COPYING.LIB. If
- not, write to the Free Software Foundation, Inc.,
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-
-#ifndef __MATH_EMU_EXTENDED_H__
-#define __MATH_EMU_EXTENDED_H__
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel, kid. Go buy yourself a real computer."
-#endif
-
-#if _FP_W_TYPE_SIZE < 64
-#define _FP_FRACTBITS_E (4*_FP_W_TYPE_SIZE)
-#else
-#define _FP_FRACTBITS_E (2*_FP_W_TYPE_SIZE)
-#endif
-
-#define _FP_FRACBITS_E 64
-#define _FP_FRACXBITS_E (_FP_FRACTBITS_E - _FP_FRACBITS_E)
-#define _FP_WFRACBITS_E (_FP_WORKBITS + _FP_FRACBITS_E)
-#define _FP_WFRACXBITS_E (_FP_FRACTBITS_E - _FP_WFRACBITS_E)
-#define _FP_EXPBITS_E 15
-#define _FP_EXPBIAS_E 16383
-#define _FP_EXPMAX_E 32767
-
-#define _FP_QNANBIT_E \
- ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-2) % _FP_W_TYPE_SIZE)
-#define _FP_IMPLBIT_E \
- ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-1) % _FP_W_TYPE_SIZE)
-#define _FP_OVERFLOW_E \
- ((_FP_W_TYPE)1 << (_FP_WFRACBITS_E % _FP_W_TYPE_SIZE))
-
-#if _FP_W_TYPE_SIZE < 64
-
-union _FP_UNION_E
-{
- long double flt;
- struct
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- unsigned long pad1 : _FP_W_TYPE_SIZE;
- unsigned long pad2 : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
- unsigned long sign : 1;
- unsigned long exp : _FP_EXPBITS_E;
- unsigned long frac1 : _FP_W_TYPE_SIZE;
- unsigned long frac0 : _FP_W_TYPE_SIZE;
-#else
- unsigned long frac0 : _FP_W_TYPE_SIZE;
- unsigned long frac1 : _FP_W_TYPE_SIZE;
- unsigned exp : _FP_EXPBITS_E;
- unsigned sign : 1;
-#endif /* not bigendian */
- } bits __attribute__((packed));
-};
-
-
-#define FP_DECL_E(X) _FP_DECL(4,X)
-
-#define FP_UNPACK_RAW_E(X, val) \
- do { \
- union _FP_UNION_E _flo; _flo.flt = (val); \
- \
- X##_f[2] = 0; X##_f[3] = 0; \
- X##_f[0] = _flo.bits.frac0; \
- X##_f[1] = _flo.bits.frac1; \
- X##_e = _flo.bits.exp; \
- X##_s = _flo.bits.sign; \
- if (!X##_e && (X##_f[1] || X##_f[0]) \
- && !(X##_f[1] & _FP_IMPLBIT_E)) \
- { \
- X##_e++; \
- FP_SET_EXCEPTION(FP_EX_DENORM); \
- } \
- } while (0)
-
-#define FP_UNPACK_RAW_EP(X, val) \
- do { \
- union _FP_UNION_E *_flo = \
- (union _FP_UNION_E *)(val); \
- \
- X##_f[2] = 0; X##_f[3] = 0; \
- X##_f[0] = _flo->bits.frac0; \
- X##_f[1] = _flo->bits.frac1; \
- X##_e = _flo->bits.exp; \
- X##_s = _flo->bits.sign; \
- if (!X##_e && (X##_f[1] || X##_f[0]) \
- && !(X##_f[1] & _FP_IMPLBIT_E)) \
- { \
- X##_e++; \
- FP_SET_EXCEPTION(FP_EX_DENORM); \
- } \
- } while (0)
-
-#define FP_PACK_RAW_E(val, X) \
- do { \
- union _FP_UNION_E _flo; \
- \
- if (X##_e) X##_f[1] |= _FP_IMPLBIT_E; \
- else X##_f[1] &= ~(_FP_IMPLBIT_E); \
- _flo.bits.frac0 = X##_f[0]; \
- _flo.bits.frac1 = X##_f[1]; \
- _flo.bits.exp = X##_e; \
- _flo.bits.sign = X##_s; \
- \
- (val) = _flo.flt; \
- } while (0)
-
-#define FP_PACK_RAW_EP(val, X) \
- do { \
- if (!FP_INHIBIT_RESULTS) \
- { \
- union _FP_UNION_E *_flo = \
- (union _FP_UNION_E *)(val); \
- \
- if (X##_e) X##_f[1] |= _FP_IMPLBIT_E; \
- else X##_f[1] &= ~(_FP_IMPLBIT_E); \
- _flo->bits.frac0 = X##_f[0]; \
- _flo->bits.frac1 = X##_f[1]; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } \
- } while (0)
-
-#define FP_UNPACK_E(X,val) \
- do { \
- FP_UNPACK_RAW_E(X,val); \
- _FP_UNPACK_CANONICAL(E,4,X); \
- } while (0)
-
-#define FP_UNPACK_EP(X,val) \
- do { \
- FP_UNPACK_RAW_2_P(X,val); \
- _FP_UNPACK_CANONICAL(E,4,X); \
- } while (0)
-
-#define FP_PACK_E(val,X) \
- do { \
- _FP_PACK_CANONICAL(E,4,X); \
- FP_PACK_RAW_E(val,X); \
- } while (0)
-
-#define FP_PACK_EP(val,X) \
- do { \
- _FP_PACK_CANONICAL(E,4,X); \
- FP_PACK_RAW_EP(val,X); \
- } while (0)
-
-#define FP_ISSIGNAN_E(X) _FP_ISSIGNAN(E,4,X)
-#define FP_NEG_E(R,X) _FP_NEG(E,4,R,X)
-#define FP_ADD_E(R,X,Y) _FP_ADD(E,4,R,X,Y)
-#define FP_SUB_E(R,X,Y) _FP_SUB(E,4,R,X,Y)
-#define FP_MUL_E(R,X,Y) _FP_MUL(E,4,R,X,Y)
-#define FP_DIV_E(R,X,Y) _FP_DIV(E,4,R,X,Y)
-#define FP_SQRT_E(R,X) _FP_SQRT(E,4,R,X)
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- * This has special _E version because standard _4 square
- * root would not work (it has to start normally with the
- * second word and not the first), but as we have to do it
- * anyway, we optimize it by doing most of the calculations
- * in two UWtype registers instead of four.
- */
-
-#define _FP_SQRT_MEAT_E(R, S, T, X, q) \
- do { \
- q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \
- _FP_FRAC_SRL_4(X, (_FP_WORKBITS)); \
- while (q) \
- { \
- T##_f[1] = S##_f[1] + q; \
- if (T##_f[1] <= X##_f[1]) \
- { \
- S##_f[1] = T##_f[1] + q; \
- X##_f[1] -= T##_f[1]; \
- R##_f[1] += q; \
- } \
- _FP_FRAC_SLL_2(X, 1); \
- q >>= 1; \
- } \
- q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \
- while (q) \
- { \
- T##_f[0] = S##_f[0] + q; \
- T##_f[1] = S##_f[1]; \
- if (T##_f[1] < X##_f[1] || \
- (T##_f[1] == X##_f[1] && \
- T##_f[0] <= X##_f[0])) \
- { \
- S##_f[0] = T##_f[0] + q; \
- S##_f[1] += (T##_f[0] > S##_f[0]); \
- _FP_FRAC_DEC_2(X, T); \
- R##_f[0] += q; \
- } \
- _FP_FRAC_SLL_2(X, 1); \
- q >>= 1; \
- } \
- _FP_FRAC_SLL_4(R, (_FP_WORKBITS)); \
- if (X##_f[0] | X##_f[1]) \
- { \
- if (S##_f[1] < X##_f[1] || \
- (S##_f[1] == X##_f[1] && \
- S##_f[0] < X##_f[0])) \
- R##_f[0] |= _FP_WORK_ROUND; \
- R##_f[0] |= _FP_WORK_STICKY; \
- } \
- } while (0)
-
-#define FP_CMP_E(r,X,Y,un) _FP_CMP(E,4,r,X,Y,un)
-#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,4,r,X,Y)
-
-#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,4,r,X,rsz,rsg)
-#define FP_TO_INT_ROUND_E(r,X,rsz,rsg) _FP_TO_INT_ROUND(E,4,r,X,rsz,rsg)
-#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,4,X,r,rs,rt)
-
-#define _FP_FRAC_HIGH_E(X) (X##_f[2])
-#define _FP_FRAC_HIGH_RAW_E(X) (X##_f[1])
-
-#else /* not _FP_W_TYPE_SIZE < 64 */
-union _FP_UNION_E
-{
- long double flt /* __attribute__((mode(TF))) */ ;
- struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
- unsigned long pad : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E);
- unsigned sign : 1;
- unsigned exp : _FP_EXPBITS_E;
- unsigned long frac : _FP_W_TYPE_SIZE;
-#else
- unsigned long frac : _FP_W_TYPE_SIZE;
- unsigned exp : _FP_EXPBITS_E;
- unsigned sign : 1;
-#endif
- } bits;
-};
-
-#define FP_DECL_E(X) _FP_DECL(2,X)
-
-#define FP_UNPACK_RAW_E(X, val) \
- do { \
- union _FP_UNION_E _flo; _flo.flt = (val); \
- \
- X##_f0 = _flo.bits.frac; \
- X##_f1 = 0; \
- X##_e = _flo.bits.exp; \
- X##_s = _flo.bits.sign; \
- if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E)) \
- { \
- X##_e++; \
- FP_SET_EXCEPTION(FP_EX_DENORM); \
- } \
- } while (0)
-
-#define FP_UNPACK_RAW_EP(X, val) \
- do { \
- union _FP_UNION_E *_flo = \
- (union _FP_UNION_E *)(val); \
- \
- X##_f0 = _flo->bits.frac; \
- X##_f1 = 0; \
- X##_e = _flo->bits.exp; \
- X##_s = _flo->bits.sign; \
- if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E)) \
- { \
- X##_e++; \
- FP_SET_EXCEPTION(FP_EX_DENORM); \
- } \
- } while (0)
-
-#define FP_PACK_RAW_E(val, X) \
- do { \
- union _FP_UNION_E _flo; \
- \
- if (X##_e) X##_f0 |= _FP_IMPLBIT_E; \
- else X##_f0 &= ~(_FP_IMPLBIT_E); \
- _flo.bits.frac = X##_f0; \
- _flo.bits.exp = X##_e; \
- _flo.bits.sign = X##_s; \
- \
- (val) = _flo.flt; \
- } while (0)
-
-#define FP_PACK_RAW_EP(fs, val, X) \
- do { \
- if (!FP_INHIBIT_RESULTS) \
- { \
- union _FP_UNION_E *_flo = \
- (union _FP_UNION_E *)(val); \
- \
- if (X##_e) X##_f0 |= _FP_IMPLBIT_E; \
- else X##_f0 &= ~(_FP_IMPLBIT_E); \
- _flo->bits.frac = X##_f0; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } \
- } while (0)
-
-
-#define FP_UNPACK_E(X,val) \
- do { \
- FP_UNPACK_RAW_E(X,val); \
- _FP_UNPACK_CANONICAL(E,2,X); \
- } while (0)
-
-#define FP_UNPACK_EP(X,val) \
- do { \
- FP_UNPACK_RAW_EP(X,val); \
- _FP_UNPACK_CANONICAL(E,2,X); \
- } while (0)
-
-#define FP_PACK_E(val,X) \
- do { \
- _FP_PACK_CANONICAL(E,2,X); \
- FP_PACK_RAW_E(val,X); \
- } while (0)
-
-#define FP_PACK_EP(val,X) \
- do { \
- _FP_PACK_CANONICAL(E,2,X); \
- FP_PACK_RAW_EP(val,X); \
- } while (0)
-
-#define FP_ISSIGNAN_E(X) _FP_ISSIGNAN(E,2,X)
-#define FP_NEG_E(R,X) _FP_NEG(E,2,R,X)
-#define FP_ADD_E(R,X,Y) _FP_ADD(E,2,R,X,Y)
-#define FP_SUB_E(R,X,Y) _FP_SUB(E,2,R,X,Y)
-#define FP_MUL_E(R,X,Y) _FP_MUL(E,2,R,X,Y)
-#define FP_DIV_E(R,X,Y) _FP_DIV(E,2,R,X,Y)
-#define FP_SQRT_E(R,X) _FP_SQRT(E,2,R,X)
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- * We optimize it by doing most of the calculations
- * in one UWtype registers instead of two, although we don't
- * have to.
- */
-#define _FP_SQRT_MEAT_E(R, S, T, X, q) \
- do { \
- q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \
- _FP_FRAC_SRL_2(X, (_FP_WORKBITS)); \
- while (q) \
- { \
- T##_f0 = S##_f0 + q; \
- if (T##_f0 <= X##_f0) \
- { \
- S##_f0 = T##_f0 + q; \
- X##_f0 -= T##_f0; \
- R##_f0 += q; \
- } \
- _FP_FRAC_SLL_1(X, 1); \
- q >>= 1; \
- } \
- _FP_FRAC_SLL_2(R, (_FP_WORKBITS)); \
- if (X##_f0) \
- { \
- if (S##_f0 < X##_f0) \
- R##_f0 |= _FP_WORK_ROUND; \
- R##_f0 |= _FP_WORK_STICKY; \
- } \
- } while (0)
-
-#define FP_CMP_E(r,X,Y,un) _FP_CMP(E,2,r,X,Y,un)
-#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,2,r,X,Y)
-
-#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,2,r,X,rsz,rsg)
-#define FP_TO_INT_ROUND_E(r,X,rsz,rsg) _FP_TO_INT_ROUND(E,2,r,X,rsz,rsg)
-#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,2,X,r,rs,rt)
-
-#define _FP_FRAC_HIGH_E(X) (X##_f1)
-#define _FP_FRAC_HIGH_RAW_E(X) (X##_f0)
-
-#endif /* not _FP_W_TYPE_SIZE < 64 */
-
-#endif /* __MATH_EMU_EXTENDED_H__ */
diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h
index 0f43451f8bb..05b9569ef1c 100644
--- a/include/media/ovcamchip.h
+++ b/include/media/ovcamchip.h
@@ -16,7 +16,6 @@
#include <linux/videodev.h>
#include <media/v4l2-common.h>
-#include <linux/i2c.h>
/* --------------------------------- */
/* ENUMERATIONS */
diff --git a/include/media/tuner.h b/include/media/tuner.h
index a41ac41113a..6dcf3c45707 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -23,6 +23,7 @@
#define _TUNER_H
#include <linux/videodev2.h>
+#include <linux/i2c.h>
#include <media/tuner-types.h>
extern int tuner_debug;
diff --git a/include/net/flow.h b/include/net/flow.h
index ce4b10d8b41..f3cc1f81261 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -97,4 +97,10 @@ extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
extern void flow_cache_flush(void);
extern atomic_t flow_cache_genid;
+static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2)
+{
+ return (fl1->proto == fl2->proto &&
+ !memcmp(&fl1->uli_u, &fl2->uli_u, sizeof(fl1->uli_u)));
+}
+
#endif
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index e02d85f56e6..d56b2923d61 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -6,8 +6,8 @@
* LAN access point) driver for Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
*
* Adaption to a generic IEEE 802.11 stack by James Ketrenos
* <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_crypt.h b/include/net/ieee80211_crypt.h
index eb476414fd7..b3d65e0bedd 100644
--- a/include/net/ieee80211_crypt.h
+++ b/include/net/ieee80211_crypt.h
@@ -3,8 +3,8 @@
* for Intersil Prism2/2.5/3.
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
*
* Adaption to a generic IEEE 802.11 stack by James Ketrenos
* <jketreno@linux.intel.com>
diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h
index 429b73892a5..a0c2b41a24d 100644
--- a/include/net/ieee80211_radiotap.h
+++ b/include/net/ieee80211_radiotap.h
@@ -66,7 +66,9 @@
*/
#define IEEE80211_RADIOTAP_HDRLEN 64
-/* The radio capture header precedes the 802.11 header. */
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
struct ieee80211_radiotap_header {
u8 it_version; /* Version 0. Only increases
* for drastic changes,
@@ -74,12 +76,12 @@ struct ieee80211_radiotap_header {
* new fields does not count.
*/
u8 it_pad;
- u16 it_len; /* length of the whole
+ __le16 it_len; /* length of the whole
* header in bytes, including
* it_version, it_pad,
* it_len, and data fields.
*/
- u32 it_present; /* A bitmap telling which
+ __le32 it_present; /* A bitmap telling which
* fields are present. Set bit 31
* (0x80000000) to extend the
* bitmap by another 32 bits.
@@ -88,89 +90,102 @@ struct ieee80211_radiotap_header {
*/
};
-/* Name Data type Units
- * ---- --------- -----
+/* Name Data type Units
+ * ---- --------- -----
*
- * IEEE80211_RADIOTAP_TSFT u64 microseconds
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
*
* Value in microseconds of the MAC's 64-bit 802.11 Time
* Synchronization Function timer when the first bit of the
* MPDU arrived at the MAC. For received frames, only.
*
- * IEEE80211_RADIOTAP_CHANNEL 2 x u16 MHz, bitmap
+ * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
*
* Tx/Rx frequency in MHz, followed by flags (see below).
*
- * IEEE80211_RADIOTAP_FHSS u16 see below
+ * IEEE80211_RADIOTAP_FHSS __le16 see below
*
* For frequency-hopping radios, the hop set (first byte)
* and pattern (second byte).
*
- * IEEE80211_RADIOTAP_RATE u8 500kb/s
+ * IEEE80211_RADIOTAP_RATE u8 500kb/s
*
* Tx/Rx data rate
*
- * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from
- * one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
*
* RF signal power at the antenna, decibel difference from
* one milliwatt.
*
- * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from
- * one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
*
* RF noise power at the antenna, decibel difference from one
* milliwatt.
*
- * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
*
* RF signal power at the antenna, decibel difference from an
* arbitrary, fixed reference.
*
- * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
*
* RF noise power at the antenna, decibel difference from an
* arbitrary, fixed reference point.
*
- * IEEE80211_RADIOTAP_LOCK_QUALITY u16 unitless
+ * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
*
* Quality of Barker code lock. Unitless. Monotonically
* nondecreasing with "better" lock strength. Called "Signal
* Quality" in datasheets. (Is there a standard way to measure
* this?)
*
- * IEEE80211_RADIOTAP_TX_ATTENUATION u16 unitless
+ * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
*
* Transmit power expressed as unitless distance from max
* power set at factory calibration. 0 is max power.
* Monotonically nondecreasing with lower power levels.
*
- * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u16 decibels (dB)
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
*
* Transmit power expressed as decibel distance from max power
* set at factory calibration. 0 is max power. Monotonically
* nondecreasing with lower power levels.
*
- * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from
- * one milliwatt (dBm)
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
*
* Transmit power expressed as dBm (decibels from a 1 milliwatt
* reference). This is the absolute power level measured at
* the antenna port.
*
- * IEEE80211_RADIOTAP_FLAGS u8 bitmap
+ * IEEE80211_RADIOTAP_FLAGS u8 bitmap
*
* Properties of transmitted and received frames. See flags
* defined below.
*
- * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
*
* Unitless indication of the Rx/Tx antenna for this packet.
* The first antenna is antenna 0.
*
- * IEEE80211_RADIOTAP_FCS u32 data
+ * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
+ *
+ * Number of unicast retries a transmitted frame used.
*
- * FCS from frame in network byte order.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
@@ -187,7 +202,11 @@ enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_ANTENNA = 11,
IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
- IEEE80211_RADIOTAP_EXT = 31,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
};
/* Channel flags. */
@@ -219,6 +238,14 @@ enum ieee80211_radiotap_type {
* 802.11 header and payload
* (to 32-bit boundary)
*/
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
/* Ugly macro to convert literal channel numbers into their mhz equivalents
* There are certianly some conditions that will break this (like feeding it '30')
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index f70afef9c3c..4fa5dfe886c 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -204,9 +204,9 @@ struct ip6_flowlabel
{
struct ip6_flowlabel *next;
__be32 label;
+ atomic_t users;
struct in6_addr dst;
struct ipv6_txoptions *opt;
- atomic_t users;
unsigned long linger;
u8 share;
u32 owner;
@@ -291,7 +291,7 @@ static inline int ipv6_addr_src_scope(const struct in6_addr *addr)
static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2)
{
- return memcmp((const void *) a1, (const void *) a2, sizeof(struct in6_addr));
+ return memcmp(a1, a2, sizeof(struct in6_addr));
}
static inline int
@@ -308,7 +308,7 @@ ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m,
static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2)
{
- memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr));
+ memcpy(a1, a2, sizeof(struct in6_addr));
}
static inline void ipv6_addr_prefix(struct in6_addr *pfx,
@@ -319,16 +319,12 @@ static inline void ipv6_addr_prefix(struct in6_addr *pfx,
int o = plen >> 3,
b = plen & 0x7;
+ memset(pfx->s6_addr, 0, sizeof(pfx->s6_addr));
memcpy(pfx->s6_addr, addr, o);
- if (b != 0) {
+ if (b != 0)
pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b);
- o++;
- }
- if (o < 16)
- memset(pfx->s6_addr + o, 0, 16 - o);
}
-#ifndef __HAVE_ARCH_ADDR_SET
static inline void ipv6_addr_set(struct in6_addr *addr,
__be32 w1, __be32 w2,
__be32 w3, __be32 w4)
@@ -338,7 +334,6 @@ static inline void ipv6_addr_set(struct in6_addr *addr,
addr->s6_addr32[2] = w3;
addr->s6_addr32[3] = w4;
}
-#endif
static inline int ipv6_addr_equal(const struct in6_addr *a1,
const struct in6_addr *a2)
diff --git a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h
index 7a209f61c48..0df57493152 100644
--- a/include/net/irda/af_irda.h
+++ b/include/net/irda/af_irda.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 89fe534045f..36bee441aa5 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h
index 2007c5a0a43..fcc896491a9 100644
--- a/include/net/irda/iriap.h
+++ b/include/net/irda/iriap.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/iriap_event.h b/include/net/irda/iriap_event.h
index 4ca3d2071b0..89747f06d9e 100644
--- a/include/net/irda/iriap_event.h
+++ b/include/net/irda/iriap_event.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irias_object.h b/include/net/irda/irias_object.h
index c41196b8795..83f78081799 100644
--- a/include/net/irda/irias_object.h
+++ b/include/net/irda/irias_object.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlan_client.h b/include/net/irda/irlan_client.h
index 736dabe211e..fa8455eda28 100644
--- a/include/net/irda/irlan_client.h
+++ b/include/net/irda/irlan_client.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
index 9592c374b41..73cacb3ac16 100644
--- a/include/net/irda/irlan_common.h
+++ b/include/net/irda/irlan_common.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlan_eth.h b/include/net/irda/irlan_eth.h
index 9a9b3619d30..0062347600b 100644
--- a/include/net/irda/irlan_eth.h
+++ b/include/net/irda/irlan_eth.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlan_event.h b/include/net/irda/irlan_event.h
index b9baac9eb8b..6d9539f0580 100644
--- a/include/net/irda/irlan_event.h
+++ b/include/net/irda/irlan_event.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlan_filter.h b/include/net/irda/irlan_filter.h
index 1720539ac2c..a5a2539485b 100644
--- a/include/net/irda/irlan_filter.h
+++ b/include/net/irda/irlan_filter.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlan_provider.h b/include/net/irda/irlan_provider.h
index ca51d5b7c99..92f3b0e1029 100644
--- a/include/net/irda/irlan_provider.h
+++ b/include/net/irda/irlan_provider.h
@@ -16,7 +16,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h
index e77eb88d922..f0248fb8e19 100644
--- a/include/net/irda/irlap.h
+++ b/include/net/irda/irlap.h
@@ -18,7 +18,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
index e212b9bc250..3ffc1d0f93d 100644
--- a/include/net/irda/irlmp.h
+++ b/include/net/irda/irlmp.h
@@ -18,7 +18,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlmp_event.h b/include/net/irda/irlmp_event.h
index 03c6f81a502..e03ae4ae396 100644
--- a/include/net/irda/irlmp_event.h
+++ b/include/net/irda/irlmp_event.h
@@ -18,7 +18,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irlmp_frame.h b/include/net/irda/irlmp_frame.h
index c463f8bca85..1906eb71422 100644
--- a/include/net/irda/irlmp_frame.h
+++ b/include/net/irda/irlmp_frame.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irmod.h b/include/net/irda/irmod.h
index 72b446c1e22..86f0dbb8ee5 100644
--- a/include/net/irda/irmod.h
+++ b/include/net/irda/irmod.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charg.
*
diff --git a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h
index 335b0ace966..37f512bd673 100644
--- a/include/net/irda/irqueue.h
+++ b/include/net/irda/irqueue.h
@@ -21,7 +21,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h
index a899e5837be..cf80c1af585 100644
--- a/include/net/irda/irttp.h
+++ b/include/net/irda/irttp.h
@@ -18,7 +18,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/parameters.h b/include/net/irda/parameters.h
index 3a605d37ddb..c0d938847bd 100644
--- a/include/net/irda/parameters.h
+++ b/include/net/irda/parameters.h
@@ -26,7 +26,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
- * Michel Dänzer <daenzer@debian.org>, 10/2001
+ * Michel Dänzer <daenzer@debian.org>, 10/2001
* - simplify irda_pv_t to avoid endianness issues
*
********************************************************************/
diff --git a/include/net/irda/timer.h b/include/net/irda/timer.h
index cb61568547d..cb2615ccf76 100644
--- a/include/net/irda/timer.h
+++ b/include/net/irda/timer.h
@@ -18,7 +18,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/irda/wrapper.h b/include/net/irda/wrapper.h
index 98768b3f9e3..2942ad6ab93 100644
--- a/include/net/irda/wrapper.h
+++ b/include/net/irda/wrapper.h
@@ -17,7 +17,7 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * Neither Dag Brattli nor University of Tromsø admit liability nor
+ * Neither Dag Brattli nor University of Tromsø admit liability nor
* provide warranty for any of this software. This material is
* provided "AS-IS" and at no charge.
*
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
index 04d1abb72d2..f9bd11be189 100644
--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -28,6 +28,7 @@ enum {
IUCV_LISTEN,
IUCV_SEVERED,
IUCV_DISCONN,
+ IUCV_CLOSING,
IUCV_CLOSED
};
@@ -62,6 +63,7 @@ struct iucv_sock {
struct sock *parent;
struct iucv_path *path;
struct sk_buff_head send_skb_q;
+ struct sk_buff_head backlog_skb_q;
unsigned int send_tag;
};
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h
index 746e7416261..fd70adbb356 100644
--- a/include/net/iucv/iucv.h
+++ b/include/net/iucv/iucv.h
@@ -16,7 +16,7 @@
* completed a register, it can exploit the other functions.
* For furthur reference on all IUCV functionality, refer to the
* CP Programming Services book, also available on the web thru
- * www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ * www.vm.ibm.com/pubs, manual # SC24-6084
*
* Definition of Return Codes
* - All positive return codes including zero are reflected back
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
new file mode 100644
index 00000000000..a7f122b7994
--- /dev/null
+++ b/include/net/mac80211.h
@@ -0,0 +1,1045 @@
+/*
+ * Low-level hardware driver -- IEEE 802.11 driver (80211.o) interface
+ * Copyright 2002-2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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.
+ */
+
+#ifndef MAC80211_H
+#define MAC80211_H
+
+#include <linux/kernel.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <linux/device.h>
+#include <linux/ieee80211.h>
+#include <net/wireless.h>
+#include <net/cfg80211.h>
+
+/* Note! Only ieee80211_tx_status_irqsafe() and ieee80211_rx_irqsafe() can be
+ * called in hardware interrupt context. The low-level driver must not call any
+ * other functions in hardware interrupt context. If there is a need for such
+ * call, the low-level driver should first ACK the interrupt and perform the
+ * IEEE 802.11 code call after this, e.g., from a scheduled tasklet (in
+ * software interrupt context).
+ */
+
+/*
+ * Frame format used when passing frame between low-level hardware drivers
+ * and IEEE 802.11 driver the same as used in the wireless media, i.e.,
+ * buffers start with IEEE 802.11 header and include the same octets that
+ * are sent over air.
+ *
+ * If hardware uses IEEE 802.3 headers (and perform 802.3 <-> 802.11
+ * conversion in firmware), upper layer 802.11 code needs to be changed to
+ * support this.
+ *
+ * If the receive frame format is not the same as the real frame sent
+ * on the wireless media (e.g., due to padding etc.), upper layer 802.11 code
+ * could be updated to provide support for such format assuming this would
+ * optimize the performance, e.g., by removing need to re-allocation and
+ * copying of the data.
+ */
+
+#define IEEE80211_CHAN_W_SCAN 0x00000001
+#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002
+#define IEEE80211_CHAN_W_IBSS 0x00000004
+
+/* Channel information structure. Low-level driver is expected to fill in chan,
+ * freq, and val fields. Other fields will be filled in by 80211.o based on
+ * hostapd information and low-level driver does not need to use them. The
+ * limits for each channel will be provided in 'struct ieee80211_conf' when
+ * configuring the low-level driver with hw->config callback. If a device has
+ * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED
+ * can be set to let the driver configure all fields */
+struct ieee80211_channel {
+ short chan; /* channel number (IEEE 802.11) */
+ short freq; /* frequency in MHz */
+ int val; /* hw specific value for the channel */
+ int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+ unsigned char power_level;
+ unsigned char antenna_max;
+};
+
+#define IEEE80211_RATE_ERP 0x00000001
+#define IEEE80211_RATE_BASIC 0x00000002
+#define IEEE80211_RATE_PREAMBLE2 0x00000004
+#define IEEE80211_RATE_SUPPORTED 0x00000010
+#define IEEE80211_RATE_OFDM 0x00000020
+#define IEEE80211_RATE_CCK 0x00000040
+#define IEEE80211_RATE_TURBO 0x00000080
+#define IEEE80211_RATE_MANDATORY 0x00000100
+
+#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2)
+#define IEEE80211_RATE_MODULATION(f) \
+ (f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM))
+
+/* Low-level driver should set PREAMBLE2, OFDM, CCK, and TURBO flags.
+ * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the
+ * configuration. */
+struct ieee80211_rate {
+ int rate; /* rate in 100 kbps */
+ int val; /* hw specific value for the rate */
+ int flags; /* IEEE80211_RATE_ flags */
+ int val2; /* hw specific value for the rate when using short preamble
+ * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for
+ * 2, 5.5, and 11 Mbps) */
+ signed char min_rssi_ack;
+ unsigned char min_rssi_ack_delta;
+
+ /* following fields are set by 80211.o and need not be filled by the
+ * low-level driver */
+ int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for
+ * optimizing channel utilization estimates */
+};
+
+/* 802.11g is backwards-compatible with 802.11b, so a wlan card can
+ * actually be both in 11b and 11g modes at the same time. */
+enum {
+ MODE_IEEE80211A, /* IEEE 802.11a */
+ MODE_IEEE80211B, /* IEEE 802.11b only */
+ MODE_ATHEROS_TURBO, /* Atheros Turbo mode (2x.11a at 5 GHz) */
+ MODE_IEEE80211G, /* IEEE 802.11g (and 802.11b compatibility) */
+ MODE_ATHEROS_TURBOG, /* Atheros Turbo mode (2x.11g at 2.4 GHz) */
+
+ /* keep last */
+ NUM_IEEE80211_MODES
+};
+
+struct ieee80211_hw_mode {
+ int mode; /* MODE_IEEE80211... */
+ int num_channels; /* Number of channels (below) */
+ struct ieee80211_channel *channels; /* Array of supported channels */
+ int num_rates; /* Number of rates (below) */
+ struct ieee80211_rate *rates; /* Array of supported rates */
+
+ struct list_head list; /* Internal, don't touch */
+};
+
+struct ieee80211_tx_queue_params {
+ int aifs; /* 0 .. 255; -1 = use default */
+ int cw_min; /* 2^n-1: 1, 3, 7, .. , 1023; 0 = use default */
+ int cw_max; /* 2^n-1: 1, 3, 7, .. , 1023; 0 = use default */
+ int burst_time; /* maximum burst time in 0.1 ms (i.e., 10 = 1 ms);
+ * 0 = disabled */
+};
+
+struct ieee80211_tx_queue_stats_data {
+ unsigned int len; /* num packets in queue */
+ unsigned int limit; /* queue len (soft) limit */
+ unsigned int count; /* total num frames sent */
+};
+
+enum {
+ IEEE80211_TX_QUEUE_DATA0,
+ IEEE80211_TX_QUEUE_DATA1,
+ IEEE80211_TX_QUEUE_DATA2,
+ IEEE80211_TX_QUEUE_DATA3,
+ IEEE80211_TX_QUEUE_DATA4,
+ IEEE80211_TX_QUEUE_SVP,
+
+ NUM_TX_DATA_QUEUES,
+
+/* due to stupidity in the sub-ioctl userspace interface, the items in
+ * this struct need to have fixed values. As soon as it is removed, we can
+ * fix these entries. */
+ IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+ IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+struct ieee80211_tx_queue_stats {
+ struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES];
+};
+
+struct ieee80211_low_level_stats {
+ unsigned int dot11ACKFailureCount;
+ unsigned int dot11RTSFailureCount;
+ unsigned int dot11FCSErrorCount;
+ unsigned int dot11RTSSuccessCount;
+};
+
+/* Transmit control fields. This data structure is passed to low-level driver
+ * with each TX frame. The low-level driver is responsible for configuring
+ * the hardware to use given values (depending on what is supported). */
+#define HW_KEY_IDX_INVALID -1
+
+struct ieee80211_tx_control {
+ int tx_rate; /* Transmit rate, given as the hw specific value for the
+ * rate (from struct ieee80211_rate) */
+ int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw
+ * specific value for the rate (from
+ * struct ieee80211_rate) */
+
+#define IEEE80211_TXCTL_REQ_TX_STATUS (1<<0)/* request TX status callback for
+ * this frame */
+#define IEEE80211_TXCTL_DO_NOT_ENCRYPT (1<<1) /* send this frame without
+ * encryption; e.g., for EAPOL
+ * frames */
+#define IEEE80211_TXCTL_USE_RTS_CTS (1<<2) /* use RTS-CTS before sending
+ * frame */
+#define IEEE80211_TXCTL_USE_CTS_PROTECT (1<<3) /* use CTS protection for the
+ * frame (e.g., for combined
+ * 802.11g / 802.11b networks) */
+#define IEEE80211_TXCTL_NO_ACK (1<<4) /* tell the low level not to
+ * wait for an ack */
+#define IEEE80211_TXCTL_RATE_CTRL_PROBE (1<<5)
+#define IEEE80211_TXCTL_CLEAR_DST_MASK (1<<6)
+#define IEEE80211_TXCTL_REQUEUE (1<<7)
+#define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of
+ * the frame */
+#define IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY (1<<9)
+ u32 flags; /* tx control flags defined
+ * above */
+ u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. */
+ u8 power_level; /* per-packet transmit power level, in dBm */
+ u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
+ s8 key_idx; /* -1 = do not encrypt, >= 0 keyidx from
+ * hw->set_key() */
+ u8 icv_len; /* length of the ICV/MIC field in octets */
+ u8 iv_len; /* length of the IV field in octets */
+ u8 tkip_key[16]; /* generated phase2/phase1 key for hw TKIP */
+ u8 queue; /* hardware queue to use for this frame;
+ * 0 = highest, hw->queues-1 = lowest */
+ u8 sw_retry_attempt; /* number of times hw has tried to
+ * transmit frame (not incl. hw retries) */
+
+ struct ieee80211_rate *rate; /* internal 80211.o rate */
+ struct ieee80211_rate *rts_rate; /* internal 80211.o rate
+ * for RTS/CTS */
+ int alt_retry_rate; /* retry rate for the last retries, given as the
+ * hw specific value for the rate (from
+ * struct ieee80211_rate). To be used to limit
+ * packet dropping when probing higher rates, if hw
+ * supports multiple retry rates. -1 = not used */
+ int type; /* internal */
+ int ifindex; /* internal */
+};
+
+/* Receive status. The low-level driver should provide this information
+ * (the subset supported by hardware) to the 802.11 code with each received
+ * frame. */
+struct ieee80211_rx_status {
+ u64 mactime;
+ int freq; /* receive frequency in Mhz */
+ int channel;
+ int phymode;
+ int ssi;
+ int signal; /* used as qual in statistics reporting */
+ int noise;
+ int antenna;
+ int rate;
+#define RX_FLAG_MMIC_ERROR (1<<0)
+#define RX_FLAG_DECRYPTED (1<<1)
+#define RX_FLAG_RADIOTAP (1<<2)
+ int flag;
+};
+
+/* Transmit status. The low-level driver should provide this information
+ * (the subset supported by hardware) to the 802.11 code for each transmit
+ * frame. */
+struct ieee80211_tx_status {
+ /* copied ieee80211_tx_control structure */
+ struct ieee80211_tx_control control;
+
+#define IEEE80211_TX_STATUS_TX_FILTERED (1<<0)
+#define IEEE80211_TX_STATUS_ACK (1<<1) /* whether the TX frame was ACKed */
+ u32 flags; /* tx staus flags defined above */
+
+ int ack_signal; /* measured signal strength of the ACK frame */
+ int excessive_retries;
+ int retry_count;
+
+ int queue_length; /* information about TX queue */
+ int queue_number;
+};
+
+
+/**
+ * struct ieee80211_conf - configuration of the device
+ *
+ * This struct indicates how the driver shall configure the hardware.
+ *
+ * @radio_enabled: when zero, driver is required to switch off the radio.
+ */
+struct ieee80211_conf {
+ int channel; /* IEEE 802.11 channel number */
+ int freq; /* MHz */
+ int channel_val; /* hw specific value for the channel */
+
+ int phymode; /* MODE_IEEE80211A, .. */
+ struct ieee80211_channel *chan;
+ struct ieee80211_hw_mode *mode;
+ unsigned int regulatory_domain;
+ int radio_enabled;
+
+ int beacon_int;
+
+#define IEEE80211_CONF_SHORT_SLOT_TIME (1<<0) /* use IEEE 802.11g Short Slot
+ * Time */
+#define IEEE80211_CONF_SSID_HIDDEN (1<<1) /* do not broadcast the ssid */
+#define IEEE80211_CONF_RADIOTAP (1<<2) /* use radiotap if supported
+ check this bit at RX time */
+ u32 flags; /* configuration flags defined above */
+
+ u8 power_level; /* transmit power limit for current
+ * regulatory domain; in dBm */
+ u8 antenna_max; /* maximum antenna gain */
+ short tx_power_reduction; /* in 0.1 dBm */
+
+ /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */
+ u8 antenna_sel_tx;
+ u8 antenna_sel_rx;
+
+ int antenna_def;
+ int antenna_mode;
+
+ /* Following five fields are used for IEEE 802.11H */
+ unsigned int radar_detect;
+ unsigned int spect_mgmt;
+ /* All following fields are currently unused. */
+ unsigned int quiet_duration; /* duration of quiet period */
+ unsigned int quiet_offset; /* how far into the beacon is the quiet
+ * period */
+ unsigned int quiet_period;
+ u8 radar_firpwr_threshold;
+ u8 radar_rssi_threshold;
+ u8 pulse_height_threshold;
+ u8 pulse_rssi_threshold;
+ u8 pulse_inband_threshold;
+};
+
+/**
+ * enum ieee80211_if_types - types of 802.11 network interfaces
+ *
+ * @IEEE80211_IF_TYPE_AP: interface in AP mode.
+ * @IEEE80211_IF_TYPE_MGMT: special interface for communication with hostap
+ * daemon. Drivers should never see this type.
+ * @IEEE80211_IF_TYPE_STA: interface in STA (client) mode.
+ * @IEEE80211_IF_TYPE_IBSS: interface in IBSS (ad-hoc) mode.
+ * @IEEE80211_IF_TYPE_MNTR: interface in monitor (rfmon) mode.
+ * @IEEE80211_IF_TYPE_WDS: interface in WDS mode.
+ * @IEEE80211_IF_TYPE_VLAN: not used.
+ */
+enum ieee80211_if_types {
+ IEEE80211_IF_TYPE_AP = 0x00000000,
+ IEEE80211_IF_TYPE_MGMT = 0x00000001,
+ IEEE80211_IF_TYPE_STA = 0x00000002,
+ IEEE80211_IF_TYPE_IBSS = 0x00000003,
+ IEEE80211_IF_TYPE_MNTR = 0x00000004,
+ IEEE80211_IF_TYPE_WDS = 0x5A580211,
+ IEEE80211_IF_TYPE_VLAN = 0x00080211,
+};
+
+/**
+ * struct ieee80211_if_init_conf - initial configuration of an interface
+ *
+ * @if_id: internal interface ID. This number has no particular meaning to
+ * drivers and the only allowed usage is to pass it to
+ * ieee80211_beacon_get() and ieee80211_get_buffered_bc() functions.
+ * This field is not valid for monitor interfaces
+ * (interfaces of %IEEE80211_IF_TYPE_MNTR type).
+ * @type: one of &enum ieee80211_if_types constants. Determines the type of
+ * added/removed interface.
+ * @mac_addr: pointer to MAC address of the interface. This pointer is valid
+ * until the interface is removed (i.e. it cannot be used after
+ * remove_interface() callback was called for this interface).
+ *
+ * This structure is used in add_interface() and remove_interface()
+ * callbacks of &struct ieee80211_hw.
+ */
+struct ieee80211_if_init_conf {
+ int if_id;
+ int type;
+ void *mac_addr;
+};
+
+/**
+ * struct ieee80211_if_conf - configuration of an interface
+ *
+ * @type: type of the interface. This is always the same as was specified in
+ * &struct ieee80211_if_init_conf. The type of an interface never changes
+ * during the life of the interface; this field is present only for
+ * convenience.
+ * @bssid: BSSID of the network we are associated to/creating.
+ * @ssid: used (together with @ssid_len) by drivers for hardware that
+ * generate beacons independently. The pointer is valid only during the
+ * config_interface() call, so copy the value somewhere if you need
+ * it.
+ * @ssid_len: length of the @ssid field.
+ * @generic_elem: used (together with @generic_elem_len) by drivers for
+ * hardware that generate beacons independently. The pointer is valid
+ * only during the config_interface() call, so copy the value somewhere
+ * if you need it.
+ * @generic_elem_len: length of the generic element.
+ * @beacon: beacon template. Valid only if @host_gen_beacon_template in
+ * &struct ieee80211_hw is set. The driver is responsible of freeing
+ * the sk_buff.
+ * @beacon_control: tx_control for the beacon template, this field is only
+ * valid when the @beacon field was set.
+ *
+ * This structure is passed to the config_interface() callback of
+ * &struct ieee80211_hw.
+ */
+struct ieee80211_if_conf {
+ int type;
+ u8 *bssid;
+ u8 *ssid;
+ size_t ssid_len;
+ u8 *generic_elem;
+ size_t generic_elem_len;
+ struct sk_buff *beacon;
+ struct ieee80211_tx_control *beacon_control;
+};
+
+typedef enum { ALG_NONE, ALG_WEP, ALG_TKIP, ALG_CCMP, ALG_NULL }
+ieee80211_key_alg;
+
+
+struct ieee80211_key_conf {
+
+ int hw_key_idx; /* filled + used by low-level driver */
+ ieee80211_key_alg alg;
+ int keylen;
+
+#define IEEE80211_KEY_FORCE_SW_ENCRYPT (1<<0) /* to be cleared by low-level
+ driver */
+#define IEEE80211_KEY_DEFAULT_TX_KEY (1<<1) /* This key is the new default TX
+ key (used only for broadcast
+ keys). */
+#define IEEE80211_KEY_DEFAULT_WEP_ONLY (1<<2) /* static WEP is the only
+ configured security policy;
+ this allows some low-level
+ drivers to determine when
+ hwaccel can be used */
+ u32 flags; /* key configuration flags defined above */
+
+ s8 keyidx; /* WEP key index */
+ u8 key[0];
+};
+
+#define IEEE80211_SEQ_COUNTER_RX 0
+#define IEEE80211_SEQ_COUNTER_TX 1
+
+typedef enum {
+ SET_KEY, DISABLE_KEY, REMOVE_ALL_KEYS,
+} set_key_cmd;
+
+/* This is driver-visible part of the per-hw state the stack keeps. */
+struct ieee80211_hw {
+ /* points to the cfg80211 wiphy for this piece. Note
+ * that you must fill in the perm_addr and dev fields
+ * of this structure, use the macros provided below. */
+ struct wiphy *wiphy;
+
+ /* assigned by mac80211, don't write */
+ struct ieee80211_conf conf;
+
+ /* Single thread workqueue available for driver use
+ * Allocated by mac80211 on registration */
+ struct workqueue_struct *workqueue;
+
+ /* Pointer to the private area that was
+ * allocated with this struct for you. */
+ void *priv;
+
+ /* The rest is information about your hardware */
+
+ /* TODO: frame_type 802.11/802.3, sw_encryption requirements */
+
+ /* Some wireless LAN chipsets generate beacons in the hardware/firmware
+ * and others rely on host generated beacons. This option is used to
+ * configure the upper layer IEEE 802.11 module to generate beacons.
+ * The low-level driver can use ieee80211_beacon_get() to fetch the
+ * next beacon frame. */
+#define IEEE80211_HW_HOST_GEN_BEACON (1<<0)
+
+ /* The device needs to be supplied with a beacon template only. */
+#define IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE (1<<1)
+
+ /* Some devices handle decryption internally and do not
+ * indicate whether the frame was encrypted (unencrypted frames
+ * will be dropped by the hardware, unless specifically allowed
+ * through) */
+#define IEEE80211_HW_DEVICE_HIDES_WEP (1<<2)
+
+ /* Whether RX frames passed to ieee80211_rx() include FCS in the end */
+#define IEEE80211_HW_RX_INCLUDES_FCS (1<<3)
+
+ /* Some wireless LAN chipsets buffer broadcast/multicast frames for
+ * power saving stations in the hardware/firmware and others rely on
+ * the host system for such buffering. This option is used to
+ * configure the IEEE 802.11 upper layer to buffer broadcast/multicast
+ * frames when there are power saving stations so that low-level driver
+ * can fetch them with ieee80211_get_buffered_bc(). */
+#define IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING (1<<4)
+
+#define IEEE80211_HW_WEP_INCLUDE_IV (1<<5)
+
+ /* will data nullfunc frames get proper TX status callback */
+#define IEEE80211_HW_DATA_NULLFUNC_ACK (1<<6)
+
+ /* Force software encryption for TKIP packets if WMM is enabled. */
+#define IEEE80211_HW_NO_TKIP_WMM_HWACCEL (1<<7)
+
+ /* Some devices handle Michael MIC internally and do not include MIC in
+ * the received packets passed up. device_strips_mic must be set
+ * for such devices. The 'encryption' frame control bit is expected to
+ * be still set in the IEEE 802.11 header with this option unlike with
+ * the device_hides_wep configuration option.
+ */
+#define IEEE80211_HW_DEVICE_STRIPS_MIC (1<<8)
+
+ /* Device is capable of performing full monitor mode even during
+ * normal operation. */
+#define IEEE80211_HW_MONITOR_DURING_OPER (1<<9)
+
+ /* Device does not need BSSID filter set to broadcast in order to
+ * receive all probe responses while scanning */
+#define IEEE80211_HW_NO_PROBE_FILTERING (1<<10)
+
+ /* Channels are already configured to the default regulatory domain
+ * specified in the device's EEPROM */
+#define IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED (1<<11)
+
+ /* calculate Michael MIC for an MSDU when doing hwcrypto */
+#define IEEE80211_HW_TKIP_INCLUDE_MMIC (1<<12)
+ /* Do TKIP phase1 key mixing in stack to support cards only do
+ * phase2 key mixing when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE1_KEY (1<<13)
+ /* Do TKIP phase1 and phase2 key mixing in stack and send the generated
+ * per-packet RC4 key with each TX frame when doing hwcrypto */
+#define IEEE80211_HW_TKIP_REQ_PHASE2_KEY (1<<14)
+
+ u32 flags; /* hardware flags defined above */
+
+ /* Set to the size of a needed device specific skb headroom for TX skbs. */
+ unsigned int extra_tx_headroom;
+
+ /* This is the time in us to change channels
+ */
+ int channel_change_time;
+ /* Maximum values for various statistics.
+ * Leave at 0 to indicate no support. Use negative numbers for dBm. */
+ s8 max_rssi;
+ s8 max_signal;
+ s8 max_noise;
+
+ /* Number of available hardware TX queues for data packets.
+ * WMM requires at least four queues. */
+ int queues;
+};
+
+static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev)
+{
+ set_wiphy_dev(hw->wiphy, dev);
+}
+
+static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
+{
+ memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
+}
+
+/* Configuration block used by the low-level driver to tell the 802.11 code
+ * about supported hardware features and to pass function pointers to callback
+ * functions. */
+struct ieee80211_ops {
+ /* Handler that 802.11 module calls for each transmitted frame.
+ * skb contains the buffer starting from the IEEE 802.11 header.
+ * The low-level driver should send the frame out based on
+ * configuration in the TX control data.
+ * Must be atomic. */
+ int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+ /* Handler for performing hardware reset. */
+ int (*reset)(struct ieee80211_hw *hw);
+
+ /* Handler that is called when any netdevice attached to the hardware
+ * device is set UP for the first time. This can be used, e.g., to
+ * enable interrupts and beacon sending. */
+ int (*open)(struct ieee80211_hw *hw);
+
+ /* Handler that is called when the last netdevice attached to the
+ * hardware device is set DOWN. This can be used, e.g., to disable
+ * interrupts and beacon sending. */
+ int (*stop)(struct ieee80211_hw *hw);
+
+ /* Handler for asking a driver if a new interface can be added (or,
+ * more exactly, set UP). If the handler returns zero, the interface
+ * is added. Driver should perform any initialization it needs prior
+ * to returning zero. By returning non-zero addition of the interface
+ * is inhibited. Unless monitor_during_oper is set, it is guaranteed
+ * that monitor interfaces and normal interfaces are mutually
+ * exclusive. The open() handler is called after add_interface()
+ * if this is the first device added. At least one of the open()
+ * open() and add_interface() callbacks has to be assigned. If
+ * add_interface() is NULL, one STA interface is permitted only. */
+ int (*add_interface)(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+
+ /* Notify a driver that an interface is going down. The stop() handler
+ * is called prior to this if this is a last interface. */
+ void (*remove_interface)(struct ieee80211_hw *hw,
+ struct ieee80211_if_init_conf *conf);
+
+ /* Handler for configuration requests. IEEE 802.11 code calls this
+ * function to change hardware configuration, e.g., channel. */
+ int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+
+ /* Handler for configuration requests related to interfaces (e.g.
+ * BSSID). */
+ int (*config_interface)(struct ieee80211_hw *hw,
+ int if_id, struct ieee80211_if_conf *conf);
+
+ /* ieee80211 drivers do not have access to the &struct net_device
+ * that is (are) connected with their device. Hence (and because
+ * we need to combine the multicast lists and flags for multiple
+ * virtual interfaces), they cannot assign set_multicast_list.
+ * The parameters here replace dev->flags and dev->mc_count,
+ * dev->mc_list is replaced by calling ieee80211_get_mc_list_item.
+ * Must be atomic. */
+ void (*set_multicast_list)(struct ieee80211_hw *hw,
+ unsigned short flags, int mc_count);
+
+ /* Set TIM bit handler. If the hardware/firmware takes care of beacon
+ * generation, IEEE 802.11 code uses this function to tell the
+ * low-level to set (or clear if set==0) TIM bit for the given aid. If
+ * host system is used to generate beacons, this handler is not used
+ * and low-level driver should set it to NULL.
+ * Must be atomic. */
+ int (*set_tim)(struct ieee80211_hw *hw, int aid, int set);
+
+ /* Set encryption key. IEEE 802.11 module calls this function to set
+ * encryption keys. addr is ff:ff:ff:ff:ff:ff for default keys and
+ * station hwaddr for individual keys. aid of the station is given
+ * to help low-level driver in selecting which key->hw_key_idx to use
+ * for this key. TX control data will use the hw_key_idx selected by
+ * the low-level driver.
+ * Must be atomic. */
+ int (*set_key)(struct ieee80211_hw *hw, set_key_cmd cmd,
+ u8 *addr, struct ieee80211_key_conf *key, int aid);
+
+ /* Set TX key index for default/broadcast keys. This is needed in cases
+ * where wlan card is doing full WEP/TKIP encapsulation (wep_include_iv
+ * is not set), in other cases, this function pointer can be set to
+ * NULL since the IEEE 802. 11 module takes care of selecting the key
+ * index for each TX frame. */
+ int (*set_key_idx)(struct ieee80211_hw *hw, int idx);
+
+ /* Enable/disable IEEE 802.1X. This item requests wlan card to pass
+ * unencrypted EAPOL-Key frames even when encryption is configured.
+ * If the wlan card does not require such a configuration, this
+ * function pointer can be set to NULL. */
+ int (*set_ieee8021x)(struct ieee80211_hw *hw, int use_ieee8021x);
+
+ /* Set port authorization state (IEEE 802.1X PAE) to be authorized
+ * (authorized=1) or unauthorized (authorized=0). This function can be
+ * used if the wlan hardware or low-level driver implements PAE.
+ * 80211.o module will anyway filter frames based on authorization
+ * state, so this function pointer can be NULL if low-level driver does
+ * not require event notification about port state changes.
+ * Currently unused. */
+ int (*set_port_auth)(struct ieee80211_hw *hw, u8 *addr,
+ int authorized);
+
+ /* Ask the hardware to service the scan request, no need to start
+ * the scan state machine in stack. */
+ int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
+
+ /* return low-level statistics */
+ int (*get_stats)(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats);
+
+ /* For devices that generate their own beacons and probe response
+ * or association responses this updates the state of privacy_invoked
+ * returns 0 for success or an error number */
+ int (*set_privacy_invoked)(struct ieee80211_hw *hw,
+ int privacy_invoked);
+
+ /* For devices that have internal sequence counters, allow 802.11
+ * code to access the current value of a counter */
+ int (*get_sequence_counter)(struct ieee80211_hw *hw,
+ u8* addr, u8 keyidx, u8 txrx,
+ u32* iv32, u16* iv16);
+
+ /* Configuration of RTS threshold (if device needs it) */
+ int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
+
+ /* Configuration of fragmentation threshold.
+ * Assign this if the device does fragmentation by itself,
+ * if this method is assigned then the stack will not do
+ * fragmentation. */
+ int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
+
+ /* Configuration of retry limits (if device needs it) */
+ int (*set_retry_limit)(struct ieee80211_hw *hw,
+ u32 short_retry, u32 long_retr);
+
+ /* Number of STAs in STA table notification (NULL = disabled).
+ * Must be atomic. */
+ void (*sta_table_notification)(struct ieee80211_hw *hw,
+ int num_sta);
+
+ /* Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
+ * bursting) for a hardware TX queue.
+ * queue = IEEE80211_TX_QUEUE_*.
+ * Must be atomic. */
+ int (*conf_tx)(struct ieee80211_hw *hw, int queue,
+ const struct ieee80211_tx_queue_params *params);
+
+ /* Get statistics of the current TX queue status. This is used to get
+ * number of currently queued packets (queue length), maximum queue
+ * size (limit), and total number of packets sent using each TX queue
+ * (count).
+ * Currently unused. */
+ int (*get_tx_stats)(struct ieee80211_hw *hw,
+ struct ieee80211_tx_queue_stats *stats);
+
+ /* Get the current TSF timer value from firmware/hardware. Currently,
+ * this is only used for IBSS mode debugging and, as such, is not a
+ * required function.
+ * Must be atomic. */
+ u64 (*get_tsf)(struct ieee80211_hw *hw);
+
+ /* Reset the TSF timer and allow firmware/hardware to synchronize with
+ * other STAs in the IBSS. This is only used in IBSS mode. This
+ * function is optional if the firmware/hardware takes full care of
+ * TSF synchronization. */
+ void (*reset_tsf)(struct ieee80211_hw *hw);
+
+ /* Setup beacon data for IBSS beacons. Unlike access point (Master),
+ * IBSS uses a fixed beacon frame which is configured using this
+ * function. This handler is required only for IBSS mode. */
+ int (*beacon_update)(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *control);
+
+ /* Determine whether the last IBSS beacon was sent by us. This is
+ * needed only for IBSS mode and the result of this function is used to
+ * determine whether to reply to Probe Requests. */
+ int (*tx_last_beacon)(struct ieee80211_hw *hw);
+};
+
+/* Allocate a new hardware device. This must be called once for each
+ * hardware device. The returned pointer must be used to refer to this
+ * device when calling other functions. 802.11 code allocates a private data
+ * area for the low-level driver. The size of this area is given as
+ * priv_data_len.
+ */
+struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
+ const struct ieee80211_ops *ops);
+
+/* Register hardware device to the IEEE 802.11 code and kernel. Low-level
+ * drivers must call this function before using any other IEEE 802.11
+ * function except ieee80211_register_hwmode. */
+int ieee80211_register_hw(struct ieee80211_hw *hw);
+
+/* driver can use this and ieee80211_get_rx_led_name to get the
+ * name of the registered LEDs after ieee80211_register_hw
+ * was called.
+ * This is useful to set the default trigger on the LED class
+ * device that your driver should export for each LED the device
+ * has, that way the default behaviour will be as expected but
+ * the user can still change it/turn off the LED etc.
+ */
+#ifdef CONFIG_MAC80211_LEDS
+extern char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw);
+extern char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw);
+#endif
+static inline char *ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+ return __ieee80211_get_tx_led_name(hw);
+#else
+ return NULL;
+#endif
+}
+
+static inline char *ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+{
+#ifdef CONFIG_MAC80211_LEDS
+ return __ieee80211_get_rx_led_name(hw);
+#else
+ return NULL;
+#endif
+}
+
+/* Register a new hardware PHYMODE capability to the stack. */
+int ieee80211_register_hwmode(struct ieee80211_hw *hw,
+ struct ieee80211_hw_mode *mode);
+
+/* Unregister a hardware device. This function instructs 802.11 code to free
+ * allocated resources and unregister netdevices from the kernel. */
+void ieee80211_unregister_hw(struct ieee80211_hw *hw);
+
+/* Free everything that was allocated including private data of a driver. */
+void ieee80211_free_hw(struct ieee80211_hw *hw);
+
+/* Receive frame callback function. The low-level driver uses this function to
+ * send received frames to the IEEE 802.11 code. Receive buffer (skb) must
+ * start with IEEE 802.11 header. */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_rx_status *status);
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_rx_status *status);
+
+/* Transmit status callback function. The low-level driver must call this
+ * function to report transmit status for all the TX frames that had
+ * req_tx_status set in the transmit control fields. In addition, this should
+ * be called at least for all unicast frames to provide information for TX rate
+ * control algorithm. In order to maintain all statistics, this function is
+ * recommended to be called after each frame, including multicast/broadcast, is
+ * sent. */
+void ieee80211_tx_status(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status);
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status);
+
+/**
+ * ieee80211_beacon_get - beacon generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @control: will be filled with information needed to send this beacon.
+ *
+ * If the beacon frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next beacon frame from the 802.11 code. The low-level is responsible
+ * for calling this function before beacon data is needed (e.g., based on
+ * hardware interrupt). Returned skb is used only once and low-level driver
+ * is responsible of freeing it.
+ */
+struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
+ int if_id,
+ struct ieee80211_tx_control *control);
+
+/**
+ * ieee80211_rts_get - RTS frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame: pointer to the frame that is going to be protected by the RTS.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @rts: The buffer where to store the RTS frame.
+ *
+ * If the RTS frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next RTS frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and RTS frame is needed.
+ */
+void ieee80211_rts_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_rts *rts);
+
+/**
+ * ieee80211_rts_duration - Get the duration field for an RTS frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame_len: the length of the frame that is going to be protected by the RTS.
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ *
+ * If the RTS is generated in firmware, but the host system must provide
+ * the duration field, the low-level driver uses this function to receive
+ * the duration field value in little-endian byteorder.
+ */
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+ size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl);
+
+/**
+ * ieee80211_ctstoself_get - CTS-to-self frame generation function
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame: pointer to the frame that is going to be protected by the CTS-to-self.
+ * @frame_len: the frame length (in octets).
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ * @cts: The buffer where to store the CTS-to-self frame.
+ *
+ * If the CTS-to-self frames are generated by the host system (i.e., not in
+ * hardware/firmware), the low-level driver uses this function to receive
+ * the next CTS-to-self frame from the 802.11 code. The low-level is responsible
+ * for calling this function before and CTS-to-self frame is needed.
+ */
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_cts *cts);
+
+/**
+ * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame_len: the length of the frame that is going to be protected by the CTS-to-self.
+ * @frame_txctl: &struct ieee80211_tx_control of the frame.
+ *
+ * If the CTS-to-self is generated in firmware, but the host system must provide
+ * the duration field, the low-level driver uses this function to receive
+ * the duration field value in little-endian byteorder.
+ */
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+ size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl);
+
+/**
+ * ieee80211_generic_frame_duration - Calculate the duration field for a frame
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @frame_len: the length of the frame.
+ * @rate: the rate (in 100kbps) at which the frame is going to be transmitted.
+ *
+ * Calculate the duration field of some generic frame, given its
+ * length and transmission rate (in 100kbps).
+ */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+ size_t frame_len,
+ int rate);
+
+/**
+ * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @if_id: interface ID from &struct ieee80211_if_init_conf.
+ * @control: will be filled with information needed to send returned frame.
+ *
+ * Function for accessing buffered broadcast and multicast frames. If
+ * hardware/firmware does not implement buffering of broadcast/multicast
+ * frames when power saving is used, 802.11 code buffers them in the host
+ * memory. The low-level driver uses this function to fetch next buffered
+ * frame. In most cases, this is used when generating beacon frame. This
+ * function returns a pointer to the next buffered skb or NULL if no more
+ * buffered frames are available.
+ *
+ * Note: buffered frames are returned only after DTIM beacon frame was
+ * generated with ieee80211_beacon_get() and the low-level driver must thus
+ * call ieee80211_beacon_get() first. ieee80211_get_buffered_bc() returns
+ * NULL if the previous generated beacon was not DTIM, so the low-level driver
+ * does not need to check for DTIM beacons separately and should be able to
+ * use common code for all beacons.
+ */
+struct sk_buff *
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_tx_control *control);
+
+/* Low level drivers that have their own MLME and MAC indicate
+ * the aid for an associating station with this call */
+int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw,
+ u8 *peer_address, u16 aid);
+
+
+/* Given an sk_buff with a raw 802.11 header at the data pointer this function
+ * returns the 802.11 header length in bytes (not including encryption
+ * headers). If the data in the sk_buff is too short to contain a valid 802.11
+ * header the function returns 0.
+ */
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
+
+/* Like ieee80211_get_hdrlen_from_skb() but takes a FC in CPU order. */
+int ieee80211_get_hdrlen(u16 fc);
+
+/**
+ * ieee80211_wake_queue - wake specific queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue);
+
+/**
+ * ieee80211_stop_queue - stop specific queue
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @queue: queue number (counted from zero).
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue);
+
+/**
+ * ieee80211_start_queues - start all queues
+ * @hw: pointer to as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_start_queue.
+ */
+void ieee80211_start_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_stop_queues - stop all queues
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_stop_queue.
+ */
+void ieee80211_stop_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_wake_queues - wake all queues
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ *
+ * Drivers should use this function instead of netif_wake_queue.
+ */
+void ieee80211_wake_queues(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_get_mc_list_item - iteration over items in multicast list
+ * @hw: pointer as obtained from ieee80211_alloc_hw().
+ * @prev: value returned by previous call to ieee80211_get_mc_list_item() or
+ * NULL to start a new iteration.
+ * @ptr: pointer to buffer of void * type for internal usage of
+ * ieee80211_get_mc_list_item().
+ *
+ * Iterates over items in multicast list of given device. To get the first
+ * item, pass NULL in @prev and in *@ptr. In subsequent calls, pass the
+ * value returned by previous call in @prev. Don't alter *@ptr during
+ * iteration. When there are no more items, NULL is returned.
+ */
+struct dev_mc_list *
+ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
+ struct dev_mc_list *prev,
+ void **ptr);
+
+/* called by driver to notify scan status completed */
+void ieee80211_scan_completed(struct ieee80211_hw *hw);
+
+/* Function to indicate Radar Detection. The low level driver must call this
+ * function to indicate the presence of radar in the current channel.
+ * Additionally the radar type also could be sent */
+int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
+ int radar, int radar_type);
+
+/* return a pointer to the source address (SA) */
+static inline u8 *ieee80211_get_SA(struct ieee80211_hdr *hdr)
+{
+ u8 *raw = (u8 *) hdr;
+ u8 tofrom = (*(raw+1)) & 3; /* get the TODS and FROMDS bits */
+
+ switch (tofrom) {
+ case 2:
+ return hdr->addr3;
+ case 3:
+ return hdr->addr4;
+ }
+ return hdr->addr2;
+}
+
+/* return a pointer to the destination address (DA) */
+static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr)
+{
+ u8 *raw = (u8 *) hdr;
+ u8 to_ds = (*(raw+1)) & 1; /* get the TODS bit */
+
+ if (to_ds)
+ return hdr->addr3;
+ return hdr->addr1;
+}
+
+static inline int ieee80211_get_morefrag(struct ieee80211_hdr *hdr)
+{
+ return (le16_to_cpu(hdr->frame_control) &
+ IEEE80211_FCTL_MOREFRAGS) != 0;
+}
+
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \
+ ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5]
+
+#endif /* MAC80211_H */
diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h
index 6114c4f54b0..f56c8d695a8 100644
--- a/include/net/sctp/command.h
+++ b/include/net/sctp/command.h
@@ -100,6 +100,8 @@ typedef enum {
SCTP_CMD_T3_RTX_TIMERS_STOP, /* Stops T3-rtx pending timers */
SCTP_CMD_FORCE_PRIM_RETRAN, /* Forces retrans. over primary path. */
SCTP_CMD_SET_SK_ERR, /* Set sk_err */
+ SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
+ SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
SCTP_CMD_LAST
} sctp_verb_t;
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 28af6805952..dda72bf5b9b 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -378,11 +378,15 @@ static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int
int sctp_v6_init(void);
void sctp_v6_exit(void);
+int sctp_v6_add_protocol(void);
+void sctp_v6_del_protocol(void);
#else /* #ifdef defined(CONFIG_IPV6) */
static inline int sctp_v6_init(void) { return 0; }
static inline void sctp_v6_exit(void) { return; }
+static inline int sctp_v6_add_protocol(void) { return 0; }
+static inline void sctp_v6_del_protocol(void) { return; }
#endif /* #if defined(CONFIG_IPV6) */
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 7b4fff93ba7..5e81984b847 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1857,6 +1857,7 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *,
int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
struct sctp_cookie*,
gfp_t gfp);
+int sctp_assoc_set_id(struct sctp_association *, gfp_t);
int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const union sctp_addr *ss2);
diff --git a/include/net/sock.h b/include/net/sock.h
index 25c37e34bfd..689b886038d 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1361,15 +1361,6 @@ static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool)
extern __u32 sysctl_wmem_max;
extern __u32 sysctl_rmem_max;
-#ifdef CONFIG_NET
-int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-#else
-static inline int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- return -ENODEV;
-}
-#endif
-
extern void sk_init(void);
#ifdef CONFIG_SYSCTL
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a385797f160..e22b4f0305a 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -736,9 +736,8 @@ static inline __u32 tcp_current_ssthresh(const struct sock *sk)
static inline void tcp_sync_left_out(struct tcp_sock *tp)
{
- if (tp->rx_opt.sack_ok &&
- (tp->sacked_out >= tp->packets_out - tp->lost_out))
- tp->sacked_out = tp->packets_out - tp->lost_out;
+ BUG_ON(tp->rx_opt.sack_ok &&
+ (tp->sacked_out + tp->lost_out > tp->packets_out));
tp->left_out = tp->sacked_out + tp->lost_out;
}
@@ -1201,9 +1200,14 @@ static inline struct sk_buff *tcp_send_head(struct sock *sk)
static inline void tcp_advance_send_head(struct sock *sk, struct sk_buff *skb)
{
+ struct tcp_sock *tp = tcp_sk(sk);
+
sk->sk_send_head = skb->next;
if (sk->sk_send_head == (struct sk_buff *)&sk->sk_write_queue)
sk->sk_send_head = NULL;
+ /* Don't override Nagle indefinately with F-RTO */
+ if (tp->frto_counter == 2)
+ tp->frto_counter = 3;
}
static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked)
diff --git a/include/net/wext.h b/include/net/wext.h
index 55741836a67..c02b8decf3a 100644
--- a/include/net/wext.h
+++ b/include/net/wext.h
@@ -10,7 +10,7 @@ extern int wext_proc_init(void);
extern int wext_handle_ioctl(struct ifreq *ifr, unsigned int cmd,
void __user *arg);
#else
-static inline int wext_proc_init()
+static inline int wext_proc_init(void)
{
return 0;
}
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 8287081d77f..39ef925d39d 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -416,13 +416,6 @@ struct xfrm_audit
u32 secid;
};
-/* SAD metadata, add more later */
-struct xfrm_sadinfo
-{
- u32 sadhcnt; /* current hash bkts */
- u32 sadhmcnt; /* max allowed hash bkts */
- u32 sadcnt; /* current running count */
-};
#ifdef CONFIG_AUDITSYSCALL
extern void xfrm_audit_log(uid_t auid, u32 secid, int type, int result,
struct xfrm_policy *xp, struct xfrm_state *x);
@@ -591,6 +584,10 @@ struct xfrm_dst
struct rt6_info rt6;
} u;
struct dst_entry *route;
+#ifdef CONFIG_XFRM_SUB_POLICY
+ struct flowi *origin;
+ struct xfrm_selector *partner;
+#endif
u32 genid;
u32 route_mtu_cached;
u32 child_mtu_cached;
@@ -603,6 +600,12 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst)
dst_release(xdst->route);
if (likely(xdst->u.dst.xfrm))
xfrm_state_put(xdst->u.dst.xfrm);
+#ifdef CONFIG_XFRM_SUB_POLICY
+ kfree(xdst->origin);
+ xdst->origin = NULL;
+ kfree(xdst->partner);
+ xdst->partner = NULL;
+#endif
}
extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev);
@@ -942,10 +945,29 @@ static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **s
return -ENOSYS;
}
#endif
+
+struct xfrmk_sadinfo {
+ u32 sadhcnt; /* current hash bkts */
+ u32 sadhmcnt; /* max allowed hash bkts */
+ u32 sadcnt; /* current running count */
+};
+
+struct xfrmk_spdinfo {
+ u32 incnt;
+ u32 outcnt;
+ u32 fwdcnt;
+ u32 inscnt;
+ u32 outscnt;
+ u32 fwdscnt;
+ u32 spdhcnt;
+ u32 spdhmcnt;
+};
+
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
extern int xfrm_state_delete(struct xfrm_state *x);
extern void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info);
-extern void xfrm_sad_getinfo(struct xfrm_sadinfo *si);
+extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si);
+extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si);
extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq);
extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq);
extern void xfrm_replay_notify(struct xfrm_state *x, int event);
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 8c339f5678c..90ef552c42d 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -108,6 +108,11 @@ typedef struct dev_node_t {
struct pcmcia_socket;
struct config_t;
+struct pcmcia_dynids {
+ spinlock_t lock;
+ struct list_head list;
+};
+
struct pcmcia_driver {
int (*probe) (struct pcmcia_device *dev);
void (*remove) (struct pcmcia_device *dev);
@@ -118,6 +123,7 @@ struct pcmcia_driver {
struct module *owner;
struct pcmcia_device_id *id_table;
struct device_driver drv;
+ struct pcmcia_dynids dynids;
};
/* driver registration */
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h
index 585d28e960d..739fa4d0e53 100644
--- a/include/rdma/ib_mad.h
+++ b/include/rdma/ib_mad.h
@@ -39,8 +39,6 @@
#if !defined( IB_MAD_H )
#define IB_MAD_H
-#include <linux/pci.h>
-
#include <rdma/ib_verbs.h>
/* Management base version */
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 765589f4d16..5342ac64ed1 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -431,9 +431,11 @@ struct ib_wc {
u8 port_num; /* valid only for DR SMPs on switches */
};
-enum ib_cq_notify {
- IB_CQ_SOLICITED,
- IB_CQ_NEXT_COMP
+enum ib_cq_notify_flags {
+ IB_CQ_SOLICITED = 1 << 0,
+ IB_CQ_NEXT_COMP = 1 << 1,
+ IB_CQ_SOLICITED_MASK = IB_CQ_SOLICITED | IB_CQ_NEXT_COMP,
+ IB_CQ_REPORT_MISSED_EVENTS = 1 << 2,
};
enum ib_srq_attr_mask {
@@ -912,6 +914,8 @@ struct ib_device {
u32 flags;
+ int num_comp_vectors;
+
struct iw_cm_verbs *iwcm;
int (*query_device)(struct ib_device *device,
@@ -978,6 +982,7 @@ struct ib_device {
struct ib_recv_wr *recv_wr,
struct ib_recv_wr **bad_recv_wr);
struct ib_cq * (*create_cq)(struct ib_device *device, int cqe,
+ int comp_vector,
struct ib_ucontext *context,
struct ib_udata *udata);
int (*destroy_cq)(struct ib_cq *cq);
@@ -987,7 +992,7 @@ struct ib_device {
struct ib_wc *wc);
int (*peek_cq)(struct ib_cq *cq, int wc_cnt);
int (*req_notify_cq)(struct ib_cq *cq,
- enum ib_cq_notify cq_notify);
+ enum ib_cq_notify_flags flags);
int (*req_ncomp_notif)(struct ib_cq *cq,
int wc_cnt);
struct ib_mr * (*get_dma_mr)(struct ib_pd *pd,
@@ -1358,13 +1363,15 @@ static inline int ib_post_recv(struct ib_qp *qp,
* @cq_context: Context associated with the CQ returned to the user via
* the associated completion and event handlers.
* @cqe: The minimum size of the CQ.
+ * @comp_vector - Completion vector used to signal completion events.
+ * Must be >= 0 and < context->num_comp_vectors.
*
* Users can examine the cq structure to determine the actual CQ size.
*/
struct ib_cq *ib_create_cq(struct ib_device *device,
ib_comp_handler comp_handler,
void (*event_handler)(struct ib_event *, void *),
- void *cq_context, int cqe);
+ void *cq_context, int cqe, int comp_vector);
/**
* ib_resize_cq - Modifies the capacity of the CQ.
@@ -1414,14 +1421,34 @@ int ib_peek_cq(struct ib_cq *cq, int wc_cnt);
/**
* ib_req_notify_cq - Request completion notification on a CQ.
* @cq: The CQ to generate an event for.
- * @cq_notify: If set to %IB_CQ_SOLICITED, completion notification will
- * occur on the next solicited event. If set to %IB_CQ_NEXT_COMP,
- * notification will occur on the next completion.
+ * @flags:
+ * Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP
+ * to request an event on the next solicited event or next work
+ * completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS
+ * may also be |ed in to request a hint about missed events, as
+ * described below.
+ *
+ * Return Value:
+ * < 0 means an error occurred while requesting notification
+ * == 0 means notification was requested successfully, and if
+ * IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events
+ * were missed and it is safe to wait for another event. In
+ * this case is it guaranteed that any work completions added
+ * to the CQ since the last CQ poll will trigger a completion
+ * notification event.
+ * > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed
+ * in. It means that the consumer must poll the CQ again to
+ * make sure it is empty to avoid missing an event because of a
+ * race between requesting notification and an entry being
+ * added to the CQ. This return value means it is possible
+ * (but not guaranteed) that a work completion has been added
+ * to the CQ since the last poll without triggering a
+ * completion notification event.
*/
static inline int ib_req_notify_cq(struct ib_cq *cq,
- enum ib_cq_notify cq_notify)
+ enum ib_cq_notify_flags flags)
{
- return cq->device->req_notify_cq(cq, cq_notify);
+ return cq->device->req_notify_cq(cq, flags);
}
/**
diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h
index 4a44278ed76..8d1e4e8026f 100644
--- a/include/scsi/iscsi_proto.h
+++ b/include/scsi/iscsi_proto.h
@@ -588,7 +588,17 @@ struct iscsi_reject {
#define VALUE_MAXLEN 255
#define TARGET_NAME_MAXLEN VALUE_MAXLEN
-#define DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH 8192
+#define ISCSI_DEF_MAX_RECV_SEG_LEN 8192
+#define ISCSI_MIN_MAX_RECV_SEG_LEN 512
+#define ISCSI_MAX_MAX_RECV_SEG_LEN 16777215
+
+#define ISCSI_DEF_FIRST_BURST_LEN 65536
+#define ISCSI_MIN_FIRST_BURST_LEN 512
+#define ISCSI_MAX_FIRST_BURST_LEN 16777215
+
+#define ISCSI_DEF_MAX_BURST_LEN 262144
+#define ISCSI_MIN_MAX_BURST_LEN 512
+#define ISCSI_MAX_MAX_BURST_LEN 16777215
/************************* RFC 3720 End *****************************/
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index ad0182ef780..2e6bdc4e7a0 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -314,8 +314,7 @@ struct scsi_core {
struct list_head task_queue;
int task_queue_size;
- struct semaphore queue_thread_sema;
- int queue_thread_kill;
+ struct task_struct *queue_thread;
};
struct sas_ha_event {
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 5c0e9791441..9f8f80ab0c8 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -203,6 +203,7 @@ static inline int scsi_status_is_good(int status)
/*
* DEVICE TYPES
+ * Please keep them in 0x%02x format for $MODALIAS to work
*/
#define TYPE_DISK 0x00
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index d6948d0e8cd..a2e0c103249 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -73,9 +73,6 @@ struct scsi_cmnd {
unsigned short use_sg; /* Number of pieces of scatter-gather */
unsigned short sglist_len; /* size of malloc'd scatter-gather list */
- /* offset in cmd we are at (for multi-transfer tgt cmds) */
- unsigned offset;
-
unsigned underflow; /* Return error if less than
this amount is transferred */
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index 3bbbfbe8cbf..5a43a4cd96c 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -5,14 +5,16 @@ struct scsi_cmnd;
struct scsi_sense_hdr;
extern void scsi_print_command(struct scsi_cmnd *);
-extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
extern void __scsi_print_command(unsigned char *);
-extern void scsi_print_sense(const char *, struct scsi_cmnd *);
+extern void scsi_show_extd_sense(unsigned char, unsigned char);
+extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
+extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
+extern void scsi_print_sense(char *, struct scsi_cmnd *);
extern void __scsi_print_sense(const char *name,
const unsigned char *sense_buffer,
int sense_len);
-extern void scsi_print_driverbyte(int);
-extern void scsi_print_hostbyte(int);
+extern void scsi_show_result(int);
+extern void scsi_print_result(struct scsi_cmnd *);
extern void scsi_print_status(unsigned char);
extern const char *scsi_sense_key_string(unsigned char);
extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 9dd37e2f5a8..2f3c5b8b1d6 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -5,6 +5,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/blkdev.h>
#include <asm/atomic.h>
struct request_queue;
@@ -119,6 +120,7 @@ struct scsi_device {
unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
unsigned no_start_on_add:1; /* do not issue start on add */
unsigned allow_restart:1; /* issue START_UNIT in error handler */
+ unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */
unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
unsigned select_no_atn:1;
unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */
@@ -154,8 +156,11 @@ struct scsi_device {
#define sdev_printk(prefix, sdev, fmt, a...) \
dev_printk(prefix, &(sdev)->sdev_gendev, fmt, ##a)
-#define scmd_printk(prefix, scmd, fmt, a...) \
- dev_printk(prefix, &(scmd)->device->sdev_gendev, fmt, ##a)
+#define scmd_printk(prefix, scmd, fmt, a...) \
+ (scmd)->request->rq_disk ? \
+ sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \
+ (scmd)->request->rq_disk->disk_name, ##a) : \
+ sdev_printk(prefix, (scmd)->device, fmt, ##a)
enum scsi_target_state {
STARGET_RUNNING = 1,
@@ -353,4 +358,9 @@ static inline int scsi_device_qas(struct scsi_device *sdev)
return 0;
return sdev->inquiry[56] & 0x02;
}
+
+#define MODULE_ALIAS_SCSI_DEVICE(type) \
+ MODULE_ALIAS("scsi:t-" __stringify(type) "*")
+#define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x"
+
#endif /* _SCSI_SCSI_DEVICE_H */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 7f1f411d07a..68f461b7a83 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -129,6 +129,11 @@ struct scsi_host_template {
* the LLD. When the driver is finished processing the command
* the done callback is invoked.
*
+ * This is called to inform the LLD to transfer
+ * cmd->request_bufflen bytes. The cmd->use_sg speciefies the
+ * number of scatterlist entried in the command and
+ * cmd->request_buffer contains the scatterlist.
+ *
* return values: see queuecommand
*
* If the LLD accepts the cmd, it should set the result to an
@@ -139,20 +144,6 @@ struct scsi_host_template {
/* TODO: rename */
int (* transfer_response)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
- /*
- * This is called to inform the LLD to transfer cmd->request_bufflen
- * bytes of the cmd at cmd->offset in the cmd. The cmd->use_sg
- * speciefies the number of scatterlist entried in the command
- * and cmd->request_buffer contains the scatterlist.
- *
- * If the command cannot be processed in one transfer_data call
- * becuase a scatterlist within the LLD's limits cannot be
- * created then transfer_data will be called multiple times.
- * It is initially called from process context, and later
- * calls are from the interrup context.
- */
- int (* transfer_data)(struct scsi_cmnd *,
- void (*done)(struct scsi_cmnd *));
/* Used as callback for the completion of task management request. */
int (* tsk_mgmt_response)(u64 mid, int result);
@@ -335,6 +326,19 @@ struct scsi_host_template {
int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
/*
+ * This is an optional routine that allows the transport to become
+ * involved when a scsi io timer fires. The return value tells the
+ * timer routine how to finish the io timeout handling:
+ * EH_HANDLED: I fixed the error, please complete the command
+ * EH_RESET_TIMER: I need more time, reset the timer and
+ * begin counting again
+ * EH_NOT_HANDLED Begin normal error recovery
+ *
+ * Status: OPTIONAL
+ */
+ enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
+
+ /*
* suspend support
*/
int (*resume)(struct scsi_device *);
diff --git a/include/scsi/scsi_tgt_if.h b/include/scsi/scsi_tgt_if.h
index 07d6e77ae89..4cf9dff29a2 100644
--- a/include/scsi/scsi_tgt_if.h
+++ b/include/scsi/scsi_tgt_if.h
@@ -45,11 +45,13 @@ struct tgt_event {
/* user-> kernel */
struct {
int host_no;
- uint32_t len;
int result;
+ aligned_u64 tag;
aligned_u64 uaddr;
+ aligned_u64 sense_uaddr;
+ uint32_t len;
+ uint32_t sense_len;
uint8_t rw;
- aligned_u64 tag;
} cmd_rsp;
struct {
int host_no;
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 798f7c7ee42..1e797308640 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -108,6 +108,8 @@ enum fc_port_state {
#define FC_PORTSPEED_2GBIT 2
#define FC_PORTSPEED_4GBIT 4
#define FC_PORTSPEED_10GBIT 8
+#define FC_PORTSPEED_8GBIT 0x10
+#define FC_PORTSPEED_16GBIT 0x20
#define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */
/*
diff --git a/include/scsi/sd.h b/include/scsi/sd.h
new file mode 100644
index 00000000000..5261488e110
--- /dev/null
+++ b/include/scsi/sd.h
@@ -0,0 +1,72 @@
+#ifndef _SCSI_DISK_H
+#define _SCSI_DISK_H
+
+/*
+ * More than enough for everybody ;) The huge number of majors
+ * is a leftover from 16bit dev_t days, we don't really need that
+ * much numberspace.
+ */
+#define SD_MAJORS 16
+
+/*
+ * This is limited by the naming scheme enforced in sd_probe,
+ * add another character to it if you really need more disks.
+ */
+#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
+
+/*
+ * Time out in seconds for disks and Magneto-opticals (which are slower).
+ */
+#define SD_TIMEOUT (30 * HZ)
+#define SD_MOD_TIMEOUT (75 * HZ)
+
+/*
+ * Number of allowed retries
+ */
+#define SD_MAX_RETRIES 5
+#define SD_PASSTHROUGH_RETRIES 1
+
+/*
+ * Size of the initial data buffer for mode and read capacity data
+ */
+#define SD_BUF_SIZE 512
+
+struct scsi_disk {
+ struct scsi_driver *driver; /* always &sd_template */
+ struct scsi_device *device;
+ struct class_device cdev;
+ struct gendisk *disk;
+ unsigned int openers; /* protected by BKL for now, yuck */
+ sector_t capacity; /* size in 512-byte sectors */
+ u32 index;
+ u8 media_present;
+ u8 write_prot;
+ unsigned WCE : 1; /* state of disk WCE bit */
+ unsigned RCD : 1; /* state of disk RCD bit, unused */
+ unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
+};
+#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
+
+static int sd_revalidate_disk(struct gendisk *disk);
+static void sd_rw_intr(struct scsi_cmnd * SCpnt);
+static int sd_probe(struct device *);
+static int sd_remove(struct device *);
+static void sd_shutdown(struct device *dev);
+static int sd_suspend(struct device *dev, pm_message_t state);
+static int sd_resume(struct device *dev);
+static void sd_rescan(struct device *);
+static int sd_init_command(struct scsi_cmnd *);
+static int sd_issue_flush(struct device *, sector_t *);
+static void sd_prepare_flush(request_queue_t *, struct request *);
+static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
+static void scsi_disk_release(struct class_device *cdev);
+static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
+static void sd_print_result(struct scsi_disk *, int);
+
+#define sd_printk(prefix, sdsk, fmt, a...) \
+ (sdsk)->disk ? \
+ sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \
+ (sdsk)->disk->disk_name, ##a) : \
+ sdev_printk(prefix, (sdsk)->device, fmt, ##a)
+
+#endif /* _SCSI_DISK_H */
diff --git a/include/video/mach64.h b/include/video/mach64.h
index 09a7f4a7289..a8332e528ec 100644
--- a/include/video/mach64.h
+++ b/include/video/mach64.h
@@ -885,6 +885,7 @@
#define SDRAM 4
#define SGRAM 5
#define WRAM 6
+#define SDRAM32 6
#define DAC_INTERNAL 0x00
#define DAC_IBMRGB514 0x01
diff --git a/include/video/permedia2.h b/include/video/permedia2.h
index b95d3628933..9e49c9571ec 100644
--- a/include/video/permedia2.h
+++ b/include/video/permedia2.h
@@ -154,6 +154,10 @@
#define PM2VI_RD_CLK1_PRESCALE 0x204
#define PM2VI_RD_CLK1_FEEDBACK 0x205
#define PM2VI_RD_CLK1_POSTSCALE 0x206
+#define PM2VI_RD_MCLK_CONTROL 0x20D
+#define PM2VI_RD_MCLK_PRESCALE 0x20E
+#define PM2VI_RD_MCLK_FEEDBACK 0x20F
+#define PM2VI_RD_MCLK_POSTSCALE 0x210
#define PM2VI_RD_CURSOR_PALETTE 0x303
#define PM2VI_RD_CURSOR_PATTERN 0x400
diff --git a/include/video/tgafb.h b/include/video/tgafb.h
index be2b3e94e25..03d0dbe293a 100644
--- a/include/video/tgafb.h
+++ b/include/video/tgafb.h
@@ -39,6 +39,7 @@
#define TGA_RASTEROP_REG 0x0034
#define TGA_PIXELSHIFT_REG 0x0038
#define TGA_DEEP_REG 0x0050
+#define TGA_START_REG 0x0054
#define TGA_PIXELMASK_REG 0x005c
#define TGA_CURSOR_BASE_REG 0x0060
#define TGA_HORIZ_REG 0x0064
@@ -140,7 +141,7 @@
/*
- * Useful defines for managing the BT463 on the 24-plane TGAs
+ * Useful defines for managing the BT463 on the 24-plane TGAs/SFB+s
*/
#define BT463_ADDR_LO 0x0
@@ -168,12 +169,35 @@
#define BT463_WINDOW_TYPE_BASE 0x0300
/*
+ * Useful defines for managing the BT459 on the 8-plane SFB+s
+ */
+
+#define BT459_ADDR_LO 0x0
+#define BT459_ADDR_HI 0x1
+#define BT459_REG_ACC 0x2
+#define BT459_PALETTE 0x3
+
+#define BT459_CUR_CLR_1 0x0181
+#define BT459_CUR_CLR_2 0x0182
+#define BT459_CUR_CLR_3 0x0183
+
+#define BT459_CMD_REG_0 0x0201
+#define BT459_CMD_REG_1 0x0202
+#define BT459_CMD_REG_2 0x0203
+
+#define BT459_READ_MASK 0x0204
+
+#define BT459_BLINK_MASK 0x0206
+
+#define BT459_CUR_CMD_REG 0x0300
+
+/*
* The framebuffer driver private data.
*/
struct tga_par {
- /* PCI device. */
- struct pci_dev *pdev;
+ /* PCI/TC device. */
+ struct device *dev;
/* Device dependent information. */
void __iomem *tga_mem_base;
@@ -235,4 +259,21 @@ BT463_WRITE(struct tga_par *par, u32 m, u16 a, u8 v)
TGA_WRITE_REG(par, m << 10 | v, TGA_RAMDAC_REG);
}
+static inline void
+BT459_LOAD_ADDR(struct tga_par *par, u16 a)
+{
+ TGA_WRITE_REG(par, BT459_ADDR_LO << 2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, a & 0xff, TGA_RAMDAC_REG);
+ TGA_WRITE_REG(par, BT459_ADDR_HI << 2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, a >> 8, TGA_RAMDAC_REG);
+}
+
+static inline void
+BT459_WRITE(struct tga_par *par, u32 m, u16 a, u8 v)
+{
+ BT459_LOAD_ADDR(par, a);
+ TGA_WRITE_REG(par, m << 2, TGA_RAMDAC_SETUP_REG);
+ TGA_WRITE_REG(par, v, TGA_RAMDAC_REG);
+}
+
#endif /* TGAFB_H */
diff --git a/init/Kconfig b/init/Kconfig
index b170aa1d43b..e63a017c391 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -80,16 +80,20 @@ config LOCALVERSION_AUTO
default y
help
This will try to automatically determine if the current tree is a
- release tree by looking for git tags that
- belong to the current top of tree revision.
+ release tree by looking for git tags that belong to the current
+ top of tree revision.
A string of the format -gxxxxxxxx will be added to the localversion
- if a git based tree is found. The string generated by this will be
+ if a git-based tree is found. The string generated by this will be
appended after any matching localversion* files, and after the value
- set in CONFIG_LOCALVERSION
+ set in CONFIG_LOCALVERSION.
- Note: This requires Perl, and a git repository, but not necessarily
- the git or cogito tools to be installed.
+ (The actual string used here is the first eight characters produced
+ by running the command:
+
+ $ git rev-parse --verify HEAD
+
+ which is done within the script "scripts/setlocalversion".)
config SWAP
bool "Support for paging of anonymous memory (swap)"
@@ -139,9 +143,7 @@ config POSIX_MQUEUE
queues every message has a priority which decides about succession
of receiving it by a process. If you want to compile and run
programs written e.g. for Solaris with use of its POSIX message
- queues (functions mq_*) say Y here. To use this feature you will
- also need mqueue library, available from
- <http://www.mat.uni.torun.pl/~wrona/posix_ipc/>
+ queues (functions mq_*) say Y here.
POSIX message queues are visible as a filesystem called 'mqueue'
and can be mounted somewhere if you want to do filesystem
@@ -262,6 +264,23 @@ config IKCONFIG_PROC
This option enables access to the kernel configuration file
through /proc/config.gz.
+config LOG_BUF_SHIFT
+ int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
+ range 12 21
+ default 17 if S390 || LOCKDEP
+ default 16 if X86_NUMAQ || IA64
+ default 15 if SMP
+ default 14
+ help
+ Select kernel log buffer size as a power of 2.
+ Defaults and Examples:
+ 17 => 128 KB for S/390
+ 16 => 64 KB for x86 NUMAQ or IA-64
+ 15 => 32 KB for SMP
+ 14 => 16 KB for uniprocessor
+ 13 => 8 KB
+ 12 => 4 KB
+
config CPUSETS
bool "Cpuset support"
depends on SMP
@@ -287,7 +306,7 @@ config SYSFS_DEPRECATED
releases.
If enabled, this option will also move any device structures
- that belong to a class, back into the /sys/class heirachy, in
+ that belong to a class, back into the /sys/class hierarchy, in
order to support older versions of udev.
If you are using a distro that was released in 2006 or later,
@@ -352,7 +371,7 @@ menuconfig EMBEDDED
config UID16
bool "Enable 16-bit UID system calls" if EMBEDDED
- depends on ARM || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && SPARC32_COMPAT) || UML || (X86_64 && IA32_EMULATION)
+ depends on ARM || BFIN || CRIS || FRV || H8300 || X86_32 || M68K || (S390 && !64BIT) || SUPERH || SPARC32 || (SPARC64 && SPARC32_COMPAT) || UML || (X86_64 && IA32_EMULATION)
default y
help
This enables the legacy 16-bit UID syscall wrappers.
@@ -474,15 +493,6 @@ config SHMEM
option replaces shmem and tmpfs with the much simpler ramfs code,
which may be appropriate on small systems without swap.
-config SLAB
- default y
- bool "Use full SLAB allocator" if (EMBEDDED && !SMP && !SPARSEMEM)
- help
- Disabling this replaces the advanced SLAB allocator and
- kmalloc support with the drastically simpler SLOB allocator.
- SLOB is more space efficient but does not scale well and is
- more susceptible to fragmentation.
-
config VM_EVENT_COUNTERS
default y
bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
@@ -492,6 +502,54 @@ config VM_EVENT_COUNTERS
on EMBEDDED systems. /proc/vmstat will only show page counts
if VM event counters are disabled.
+config SLUB_DEBUG
+ default y
+ bool "Enable SLUB debugging support" if EMBEDDED
+ help
+ SLUB has extensive debug support features. Disabling these can
+ result in significant savings in code size. This also disables
+ SLUB sysfs support. /sys/slab will not exist and there will be
+ no support for cache validation etc.
+
+choice
+ prompt "Choose SLAB allocator"
+ default SLAB
+ help
+ This option allows to select a slab allocator.
+
+config SLAB
+ bool "SLAB"
+ help
+ The regular slab allocator that is established and known to work
+ well in all environments. It organizes cache hot objects in
+ per cpu and per node queues. SLAB is the default choice for
+ a slab allocator.
+
+config SLUB
+ depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
+ bool "SLUB (Unqueued Allocator)"
+ help
+ SLUB is a slab allocator that minimizes cache line usage
+ instead of managing queues of cached objects (SLAB approach).
+ Per cpu caching is realized using slabs of objects instead
+ of queues of objects. SLUB can use memory efficiently
+ and has enhanced diagnostics.
+
+config SLOB
+#
+# SLOB does not support SMP because SLAB_DESTROY_BY_RCU is unsupported
+#
+ depends on EMBEDDED && !SMP && !SPARSEMEM
+ bool "SLOB (Simple Allocator)"
+ help
+ SLOB replaces the SLAB allocator with a drastically simpler
+ allocator. SLOB is more space efficient that SLAB but does not
+ scale well (single lock for all operations) and is also highly
+ susceptible to fragmentation. SLUB can accomplish a higher object
+ density. It is usually better to use SLUB instead of SLOB.
+
+endchoice
+
endmenu # General setup
config RT_MUTEXES
@@ -507,10 +565,6 @@ config BASE_SMALL
default 0 if BASE_FULL
default 1 if !BASE_FULL
-config SLOB
- default !SLAB
- bool
-
menu "Loadable module support"
config MODULES
diff --git a/init/do_mounts.c b/init/do_mounts.c
index dc1ec0803ef..46fe407fb03 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -7,8 +7,10 @@
#include <linux/root_dev.h>
#include <linux/security.h>
#include <linux/delay.h>
+#include <linux/genhd.h>
#include <linux/mount.h>
#include <linux/device.h>
+#include <linux/init.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
@@ -307,17 +309,21 @@ retry:
/*
* Allow the user to distinguish between failed sys_open
* and bad superblock on root device.
+ * and give them a list of the available devices
*/
#ifdef CONFIG_BLOCK
__bdevname(ROOT_DEV, b);
#endif
printk("VFS: Cannot open root device \"%s\" or %s\n",
root_device_name, b);
- printk("Please append a correct \"root=\" boot option\n");
+ printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
+ printk_all_partitions();
panic("VFS: Unable to mount root fs on %s", b);
}
+ printk("List of all partitions:\n");
+ printk_all_partitions();
printk("No filesystem could mount root, tried: ");
for (p = fs_names; *p; p += strlen(p)+1)
printk(" %s", p);
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index 2cfd7cb36e7..b222ce9e1c8 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -55,11 +55,12 @@ static void __init handle_initrd(void)
sys_mount(".", "/", NULL, MS_MOVE, NULL);
sys_chroot(".");
- current->flags |= PF_NOFREEZE;
pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
if (pid > 0) {
- while (pid != sys_wait4(-1, NULL, 0, NULL))
+ while (pid != sys_wait4(-1, NULL, 0, NULL)) {
+ try_to_freeze();
yield();
+ }
}
/* move initrd to rootfs' /old */
diff --git a/init/main.c b/init/main.c
index a92989e7836..e8d080cab44 100644
--- a/init/main.c
+++ b/init/main.c
@@ -54,6 +54,7 @@
#include <linux/lockdep.h>
#include <linux/pid_namespace.h>
#include <linux/device.h>
+#include <linux/kthread.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -82,7 +83,7 @@
#warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended.
#endif
-static int init(void *);
+static int kernel_init(void *);
extern void init_IRQ(void);
extern void fork_init(unsigned long);
@@ -94,7 +95,6 @@ extern void pidmap_init(void);
extern void prio_tree_init(void);
extern void radix_tree_init(void);
extern void free_initmem(void);
-extern void prepare_namespace(void);
#ifdef CONFIG_ACPI
extern void acpi_early_init(void);
#else
@@ -369,12 +369,8 @@ static void __init setup_per_cpu_areas(void)
unsigned long nr_possible_cpus = num_possible_cpus();
/* Copy section for each CPU (we discard the original) */
- size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
-#ifdef CONFIG_MODULES
- if (size < PERCPU_ENOUGH_ROOM)
- size = PERCPU_ENOUGH_ROOM;
-#endif
- ptr = alloc_bootmem(size * nr_possible_cpus);
+ size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
+ ptr = alloc_bootmem_pages(size * nr_possible_cpus);
for_each_possible_cpu(i) {
__per_cpu_offset[i] = ptr - __per_cpu_start;
@@ -388,11 +384,6 @@ static void __init setup_per_cpu_areas(void)
static void __init smp_init(void)
{
unsigned int cpu;
- unsigned highest = 0;
-
- for_each_cpu_mask(cpu, cpu_possible_map)
- highest = cpu;
- nr_cpu_ids = highest + 1;
/* FIXME: This should be done in userspace --RR */
for_each_present_cpu(cpu) {
@@ -435,8 +426,12 @@ static void __init setup_command_line(char *command_line)
static void noinline rest_init(void)
__releases(kernel_lock)
{
- kernel_thread(init, NULL, CLONE_FS | CLONE_SIGHAND);
+ int pid;
+
+ kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
+ pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
+ kthreadd_task = find_task_by_pid(pid);
unlock_kernel();
/*
@@ -658,6 +653,7 @@ static void __init do_initcalls(void)
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
+ ktime_t t0, t1, delta;
char *msg = NULL;
char msgbuf[40];
int result;
@@ -667,10 +663,26 @@ static void __init do_initcalls(void)
print_fn_descriptor_symbol(": %s()",
(unsigned long) *call);
printk("\n");
+ t0 = ktime_get();
}
result = (*call)();
+ if (initcall_debug) {
+ t1 = ktime_get();
+ delta = ktime_sub(t1, t0);
+
+ printk("initcall 0x%p", *call);
+ print_fn_descriptor_symbol(": %s()",
+ (unsigned long) *call);
+ printk(" returned %d.\n", result);
+
+ printk("initcall 0x%p ran for %Ld msecs: ",
+ *call, (unsigned long long)delta.tv64 >> 20);
+ print_fn_descriptor_symbol("%s()\n",
+ (unsigned long) *call);
+ }
+
if (result && result != -ENODEV && initcall_debug) {
sprintf(msgbuf, "error code %d", result);
msg = msgbuf;
@@ -772,7 +784,7 @@ static int noinline init_post(void)
panic("No init found. Try passing init= option to kernel.");
}
-static int __init init(void * unused)
+static int __init kernel_init(void * unused)
{
lock_kernel();
/*
diff --git a/ipc/compat.c b/ipc/compat.c
index fa18141539f..8b44aa9a7c9 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -542,6 +542,8 @@ static inline int put_compat_shminfo64(struct shminfo64 *smi,
if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64)))
return -EFAULT;
+ if (smi->shmmax > INT_MAX)
+ smi->shmmax = INT_MAX;
err = __put_user(smi->shmmax, &up64->shmmax);
err |= __put_user(smi->shmmin, &up64->shmmin);
err |= __put_user(smi->shmmni, &up64->shmmni);
@@ -557,6 +559,8 @@ static inline int put_compat_shminfo(struct shminfo64 *smi,
if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
return -EFAULT;
+ if (smi->shmmax > INT_MAX)
+ smi->shmmax = INT_MAX;
err = __put_user(smi->shmmax, &up->shmmax);
err |= __put_user(smi->shmmin, &up->shmmin);
err |= __put_user(smi->shmmni, &up->shmmni);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 554ac368be7..d17821d3f48 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -215,8 +215,7 @@ static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags
{
struct mqueue_inode_info *p = (struct mqueue_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&p->vfs_inode);
}
diff --git a/ipc/sem.c b/ipc/sem.c
index d3e12efd55c..9964b2224c7 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -75,7 +75,6 @@
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/time.h>
-#include <linux/smp_lock.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/audit.h>
diff --git a/ipc/util.c b/ipc/util.c
index 0b652387d16..7536a7292d4 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -21,7 +21,6 @@
#include <linux/shm.h>
#include <linux/init.h>
#include <linux/msg.h>
-#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/capability.h>
@@ -85,53 +84,20 @@ err_mem:
return ERR_PTR(err);
}
-int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc)
+struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
{
- struct ipc_namespace *new;
-
- if (unshare_flags & CLONE_NEWIPC) {
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- new = clone_ipc_ns(current->nsproxy->ipc_ns);
- if (IS_ERR(new))
- return PTR_ERR(new);
-
- *new_ipc = new;
- }
-
- return 0;
-}
-
-int copy_ipcs(unsigned long flags, struct task_struct *tsk)
-{
- struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns;
struct ipc_namespace *new_ns;
- int err = 0;
- if (!old_ns)
- return 0;
-
- get_ipc_ns(old_ns);
+ BUG_ON(!ns);
+ get_ipc_ns(ns);
if (!(flags & CLONE_NEWIPC))
- return 0;
+ return ns;
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto out;
- }
+ new_ns = clone_ipc_ns(ns);
- new_ns = clone_ipc_ns(old_ns);
- if (!new_ns) {
- err = -ENOMEM;
- goto out;
- }
-
- tsk->nsproxy->ipc_ns = new_ns;
-out:
- put_ipc_ns(old_ns);
- return err;
+ put_ipc_ns(ns);
+ return new_ns;
}
void free_ipc_ns(struct kref *kref)
@@ -145,11 +111,11 @@ void free_ipc_ns(struct kref *kref)
kfree(ns);
}
#else
-int copy_ipcs(unsigned long flags, struct task_struct *tsk)
+struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
{
if (flags & CLONE_NEWIPC)
- return -EINVAL;
- return 0;
+ return ERR_PTR(-EINVAL);
+ return ns;
}
#endif
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
index 0b46a5dff4c..c64ce9c1420 100644
--- a/kernel/Kconfig.preempt
+++ b/kernel/Kconfig.preempt
@@ -23,7 +23,7 @@ config PREEMPT_VOLUNTARY
"explicit preemption points" to the kernel code. These new
preemption points have been selected to reduce the maximum
latency of rescheduling, providing faster application reactions,
- at the cost of slighly lower throughput.
+ at the cost of slightly lower throughput.
This allows reaction to interactive events by allowing a
low priority process to voluntarily preempt itself even if it
@@ -43,7 +43,7 @@ config PREEMPT
even if it is in kernel mode executing a system call and would
otherwise not be about to reach a natural preemption point.
This allows applications to run more 'smoothly' even when the
- system is under load, at the cost of slighly lower throughput
+ system is under load, at the cost of slightly lower throughput
and a slight runtime overhead to kernel code.
Select this if you are building a kernel for a desktop or
diff --git a/kernel/Makefile b/kernel/Makefile
index ac6b27abb1a..642d4277c2e 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
- hrtimer.o rwsem.o latency.o nsproxy.o srcu.o
+ hrtimer.o rwsem.o latency.o nsproxy.o srcu.o die_notifier.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += time/
diff --git a/kernel/audit.c b/kernel/audit.c
index 4e9d2082968..d13276d4141 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -515,8 +515,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
err = -EPERM;
break;
case AUDIT_USER:
- case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
- case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
+ case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
+ case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
if (security_netlink_recv(skb, CAP_AUDIT_WRITE))
err = -EPERM;
break;
@@ -614,8 +614,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
loginuid, sid);
break;
case AUDIT_USER:
- case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
- case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
+ case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
+ case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
if (!audit_enabled && msg_type != AUDIT_USER_AVC)
return 0;
diff --git a/kernel/configs.c b/kernel/configs.c
index 8fa1fb28f8a..e84d3f9c6c7 100644
--- a/kernel/configs.c
+++ b/kernel/configs.c
@@ -61,18 +61,9 @@ static ssize_t
ikconfig_read_current(struct file *file, char __user *buf,
size_t len, loff_t * offset)
{
- loff_t pos = *offset;
- ssize_t count;
-
- if (pos >= kernel_config_data_size)
- return 0;
-
- count = min(len, (size_t)(kernel_config_data_size - pos));
- if (copy_to_user(buf, kernel_config_data + MAGIC_SIZE + pos, count))
- return -EFAULT;
-
- *offset += count;
- return count;
+ return simple_read_from_buffer(buf, len, offset,
+ kernel_config_data + MAGIC_SIZE,
+ kernel_config_data_size);
}
static const struct file_operations ikconfig_file_ops = {
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 36e70845cfc..208cf3497c1 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -97,7 +97,7 @@ static inline void check_for_tasks(int cpu)
(!cputime_eq(p->utime, cputime_zero) ||
!cputime_eq(p->stime, cputime_zero)))
printk(KERN_WARNING "Task %s (pid = %d) is on cpu %d\
- (state = %ld, flags = %lx) \n",
+ (state = %ld, flags = %x) \n",
p->comm, p->pid, cpu, p->state, p->flags);
}
write_unlock_irq(&tasklist_lock);
@@ -120,11 +120,13 @@ static int take_cpu_down(void *unused)
}
/* Requires cpu_add_remove_lock to be held */
-static int _cpu_down(unsigned int cpu)
+static int _cpu_down(unsigned int cpu, int tasks_frozen)
{
- int err;
+ int err, nr_calls = 0;
struct task_struct *p;
cpumask_t old_allowed, tmp;
+ void *hcpu = (void *)(long)cpu;
+ unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
if (num_online_cpus() == 1)
return -EBUSY;
@@ -132,12 +134,16 @@ static int _cpu_down(unsigned int cpu)
if (!cpu_online(cpu))
return -EINVAL;
- err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
- (void *)(long)cpu);
+ raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+ err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
+ hcpu, -1, &nr_calls);
if (err == NOTIFY_BAD) {
+ __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
+ hcpu, nr_calls, NULL);
printk("%s: attempt to take down CPU %u failed\n",
__FUNCTION__, cpu);
- return -EINVAL;
+ err = -EINVAL;
+ goto out_release;
}
/* Ensure that we are not runnable on dying cpu */
@@ -152,8 +158,8 @@ static int _cpu_down(unsigned int cpu)
if (IS_ERR(p) || cpu_online(cpu)) {
/* CPU didn't die: tell everyone. Can't complain. */
- if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
- (void *)(long)cpu) == NOTIFY_BAD)
+ if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
+ hcpu) == NOTIFY_BAD)
BUG();
if (IS_ERR(p)) {
@@ -170,13 +176,9 @@ static int _cpu_down(unsigned int cpu)
/* This actually kills the CPU. */
__cpu_die(cpu);
- /* Move it here so it can run. */
- kthread_bind(p, get_cpu());
- put_cpu();
-
/* CPU is completely dead: tell everyone. Too late to complain. */
- if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD,
- (void *)(long)cpu) == NOTIFY_BAD)
+ if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD | mod,
+ hcpu) == NOTIFY_BAD)
BUG();
check_for_tasks(cpu);
@@ -185,6 +187,8 @@ out_thread:
err = kthread_stop(p);
out_allowed:
set_cpus_allowed(current, old_allowed);
+out_release:
+ raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
return err;
}
@@ -196,7 +200,7 @@ int cpu_down(unsigned int cpu)
if (cpu_hotplug_disabled)
err = -EBUSY;
else
- err = _cpu_down(cpu);
+ err = _cpu_down(cpu, 0);
mutex_unlock(&cpu_add_remove_lock);
return err;
@@ -204,15 +208,18 @@ int cpu_down(unsigned int cpu)
#endif /*CONFIG_HOTPLUG_CPU*/
/* Requires cpu_add_remove_lock to be held */
-static int __cpuinit _cpu_up(unsigned int cpu)
+static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
{
- int ret;
+ int ret, nr_calls = 0;
void *hcpu = (void *)(long)cpu;
+ unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
if (cpu_online(cpu) || !cpu_present(cpu))
return -EINVAL;
- ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
+ raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
+ ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
+ -1, &nr_calls);
if (ret == NOTIFY_BAD) {
printk("%s: attempt to bring up CPU %u failed\n",
__FUNCTION__, cpu);
@@ -229,12 +236,13 @@ static int __cpuinit _cpu_up(unsigned int cpu)
BUG_ON(!cpu_online(cpu));
/* Now call notifier in preparation. */
- raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
+ raw_notifier_call_chain(&cpu_chain, CPU_ONLINE | mod, hcpu);
out_notify:
if (ret != 0)
- raw_notifier_call_chain(&cpu_chain,
- CPU_UP_CANCELED, hcpu);
+ __raw_notifier_call_chain(&cpu_chain,
+ CPU_UP_CANCELED | mod, hcpu, nr_calls, NULL);
+ raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
return ret;
}
@@ -247,19 +255,13 @@ int __cpuinit cpu_up(unsigned int cpu)
if (cpu_hotplug_disabled)
err = -EBUSY;
else
- err = _cpu_up(cpu);
+ err = _cpu_up(cpu, 0);
mutex_unlock(&cpu_add_remove_lock);
return err;
}
#ifdef CONFIG_SUSPEND_SMP
-/* Needed to prevent the microcode driver from requesting firmware in its CPU
- * hotplug notifier during the suspend/resume.
- */
-int suspend_cpu_hotplug;
-EXPORT_SYMBOL(suspend_cpu_hotplug);
-
static cpumask_t frozen_cpus;
int disable_nonboot_cpus(void)
@@ -267,7 +269,6 @@ int disable_nonboot_cpus(void)
int cpu, first_cpu, error = 0;
mutex_lock(&cpu_add_remove_lock);
- suspend_cpu_hotplug = 1;
first_cpu = first_cpu(cpu_online_map);
/* We take down all of the non-boot CPUs in one shot to avoid races
* with the userspace trying to use the CPU hotplug at the same time
@@ -277,7 +278,7 @@ int disable_nonboot_cpus(void)
for_each_online_cpu(cpu) {
if (cpu == first_cpu)
continue;
- error = _cpu_down(cpu);
+ error = _cpu_down(cpu, 1);
if (!error) {
cpu_set(cpu, frozen_cpus);
printk("CPU%d is down\n", cpu);
@@ -294,7 +295,6 @@ int disable_nonboot_cpus(void)
} else {
printk(KERN_ERR "Non-boot CPUs are not disabled\n");
}
- suspend_cpu_hotplug = 0;
mutex_unlock(&cpu_add_remove_lock);
return error;
}
@@ -309,10 +309,9 @@ void enable_nonboot_cpus(void)
if (cpus_empty(frozen_cpus))
goto out;
- suspend_cpu_hotplug = 1;
printk("Enabling non-boot CPUs ...\n");
for_each_cpu_mask(cpu, frozen_cpus) {
- error = _cpu_up(cpu);
+ error = _cpu_up(cpu, 1);
if (!error) {
printk("CPU%d is up\n", cpu);
continue;
@@ -320,7 +319,6 @@ void enable_nonboot_cpus(void)
printk(KERN_WARNING "Error taking CPU%d up: %d\n", cpu, error);
}
cpus_clear(frozen_cpus);
- suspend_cpu_hotplug = 0;
out:
mutex_unlock(&cpu_add_remove_lock);
}
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index f382b0f775e..f57854b0892 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -42,7 +42,6 @@
#include <linux/seq_file.h>
#include <linux/security.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
#include <linux/string.h>
@@ -822,11 +821,22 @@ static int update_cpumask(struct cpuset *cs, char *buf)
return -EACCES;
trialcs = *cs;
- retval = cpulist_parse(buf, trialcs.cpus_allowed);
- if (retval < 0)
- return retval;
+
+ /*
+ * We allow a cpuset's cpus_allowed to be empty; if it has attached
+ * tasks, we'll catch it later when we validate the change and return
+ * -ENOSPC.
+ */
+ if (!buf[0] || (buf[0] == '\n' && !buf[1])) {
+ cpus_clear(trialcs.cpus_allowed);
+ } else {
+ retval = cpulist_parse(buf, trialcs.cpus_allowed);
+ if (retval < 0)
+ return retval;
+ }
cpus_and(trialcs.cpus_allowed, trialcs.cpus_allowed, cpu_online_map);
- if (cpus_empty(trialcs.cpus_allowed))
+ /* cpus_allowed cannot be empty for a cpuset with attached tasks. */
+ if (atomic_read(&cs->count) && cpus_empty(trialcs.cpus_allowed))
return -ENOSPC;
retval = validate_change(cs, &trialcs);
if (retval < 0)
@@ -919,16 +929,27 @@ static int update_nodemask(struct cpuset *cs, char *buf)
return -EACCES;
trialcs = *cs;
- retval = nodelist_parse(buf, trialcs.mems_allowed);
- if (retval < 0)
- goto done;
+
+ /*
+ * We allow a cpuset's mems_allowed to be empty; if it has attached
+ * tasks, we'll catch it later when we validate the change and return
+ * -ENOSPC.
+ */
+ if (!buf[0] || (buf[0] == '\n' && !buf[1])) {
+ nodes_clear(trialcs.mems_allowed);
+ } else {
+ retval = nodelist_parse(buf, trialcs.mems_allowed);
+ if (retval < 0)
+ goto done;
+ }
nodes_and(trialcs.mems_allowed, trialcs.mems_allowed, node_online_map);
oldmem = cs->mems_allowed;
if (nodes_equal(oldmem, trialcs.mems_allowed)) {
retval = 0; /* Too easy - nothing to do */
goto done;
}
- if (nodes_empty(trialcs.mems_allowed)) {
+ /* mems_allowed cannot be empty for a cpuset with attached tasks. */
+ if (atomic_read(&cs->count) && nodes_empty(trialcs.mems_allowed)) {
retval = -ENOSPC;
goto done;
}
@@ -1751,12 +1772,7 @@ static ssize_t cpuset_tasks_read(struct file *file, char __user *buf,
{
struct ctr_struct *ctr = file->private_data;
- if (*ppos + nbytes > ctr->bufsz)
- nbytes = ctr->bufsz - *ppos;
- if (copy_to_user(buf, ctr->buf + *ppos, nbytes))
- return -EFAULT;
- *ppos += nbytes;
- return nbytes;
+ return simple_read_from_buffer(buf, nbytes, ppos, ctr->buf, ctr->bufsz);
}
static int cpuset_tasks_release(struct inode *unused_inode, struct file *file)
@@ -2200,10 +2216,6 @@ void cpuset_fork(struct task_struct *child)
* it is holding that mutex while calling check_for_release(),
* which calls kmalloc(), so can't be called holding callback_mutex().
*
- * We don't need to task_lock() this reference to tsk->cpuset,
- * because tsk is already marked PF_EXITING, so attach_task() won't
- * mess with it, or task is a failed fork, never visible to attach_task.
- *
* the_top_cpuset_hack:
*
* Set the exiting tasks cpuset to the root cpuset (top_cpuset).
@@ -2242,8 +2254,10 @@ void cpuset_exit(struct task_struct *tsk)
{
struct cpuset *cs;
+ task_lock(current);
cs = tsk->cpuset;
tsk->cpuset = &top_cpuset; /* the_top_cpuset_hack - see above */
+ task_unlock(current);
if (notify_on_release(cs)) {
char *pathbuf = NULL;
@@ -2351,6 +2365,8 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
* z's node is in our tasks mems_allowed, yes. If it's not a
* __GFP_HARDWALL request and this zone's nodes is in the nearest
* mem_exclusive cpuset ancestor to this tasks cpuset, yes.
+ * If the task has been OOM killed and has access to memory reserves
+ * as specified by the TIF_MEMDIE flag, yes.
* Otherwise, no.
*
* If __GFP_HARDWALL is set, cpuset_zone_allowed_softwall()
@@ -2368,7 +2384,8 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
* calls get to this routine, we should just shut up and say 'yes'.
*
* GFP_USER allocations are marked with the __GFP_HARDWALL bit,
- * and do not allow allocations outside the current tasks cpuset.
+ * and do not allow allocations outside the current tasks cpuset
+ * unless the task has been OOM killed as is marked TIF_MEMDIE.
* GFP_KERNEL allocations are not so marked, so can escape to the
* nearest enclosing mem_exclusive ancestor cpuset.
*
@@ -2392,6 +2409,7 @@ static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
* affect that:
* in_interrupt - any node ok (current task context irrelevant)
* GFP_ATOMIC - any node ok
+ * TIF_MEMDIE - any node ok
* GFP_KERNEL - any node in enclosing mem_exclusive cpuset ok
* GFP_USER - only nodes in current tasks mems allowed ok.
*
@@ -2413,6 +2431,12 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
might_sleep_if(!(gfp_mask & __GFP_HARDWALL));
if (node_isset(node, current->mems_allowed))
return 1;
+ /*
+ * Allow tasks that have access to memory reserves because they have
+ * been OOM killed to get memory anywhere.
+ */
+ if (unlikely(test_thread_flag(TIF_MEMDIE)))
+ return 1;
if (gfp_mask & __GFP_HARDWALL) /* If hardwall request, stop here */
return 0;
@@ -2438,7 +2462,9 @@ int __cpuset_zone_allowed_softwall(struct zone *z, gfp_t gfp_mask)
*
* If we're in interrupt, yes, we can always allocate.
* If __GFP_THISNODE is set, yes, we can always allocate. If zone
- * z's node is in our tasks mems_allowed, yes. Otherwise, no.
+ * z's node is in our tasks mems_allowed, yes. If the task has been
+ * OOM killed and has access to memory reserves as specified by the
+ * TIF_MEMDIE flag, yes. Otherwise, no.
*
* The __GFP_THISNODE placement logic is really handled elsewhere,
* by forcibly using a zonelist starting at a specified node, and by
@@ -2462,6 +2488,12 @@ int __cpuset_zone_allowed_hardwall(struct zone *z, gfp_t gfp_mask)
node = zone_to_nid(z);
if (node_isset(node, current->mems_allowed))
return 1;
+ /*
+ * Allow tasks that have access to memory reserves because they have
+ * been OOM killed to get memory anywhere.
+ */
+ if (unlikely(test_thread_flag(TIF_MEMDIE)))
+ return 1;
return 0;
}
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index 766d5912b26..c0148ae992c 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -31,11 +31,7 @@ __setup("nodelayacct", delayacct_setup_disable);
void delayacct_init(void)
{
- delayacct_cache = kmem_cache_create("delayacct_cache",
- sizeof(struct task_delay_info),
- 0,
- SLAB_PANIC,
- NULL, NULL);
+ delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC);
delayacct_tsk_init(&init_task);
}
diff --git a/kernel/die_notifier.c b/kernel/die_notifier.c
new file mode 100644
index 00000000000..0d98827887a
--- /dev/null
+++ b/kernel/die_notifier.c
@@ -0,0 +1,38 @@
+
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/vmalloc.h>
+#include <linux/kdebug.h>
+
+
+static ATOMIC_NOTIFIER_HEAD(die_chain);
+
+int notify_die(enum die_val val, const char *str,
+ struct pt_regs *regs, long err, int trap, int sig)
+{
+ struct die_args args = {
+ .regs = regs,
+ .str = str,
+ .err = err,
+ .trapnr = trap,
+ .signr = sig,
+
+ };
+
+ return atomic_notifier_call_chain(&die_chain, val, &args);
+}
+
+int register_die_notifier(struct notifier_block *nb)
+{
+ vmalloc_sync_all();
+ return atomic_notifier_chain_register(&die_chain, nb);
+}
+EXPORT_SYMBOL_GPL(register_die_notifier);
+
+int unregister_die_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_unregister(&die_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_die_notifier);
+
+
diff --git a/kernel/exit.c b/kernel/exit.c
index b55ed4cc910..b0c6f0c3a2d 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -7,7 +7,6 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/capability.h>
#include <linux/completion.h>
@@ -27,6 +26,7 @@
#include <linux/profile.h>
#include <linux/mount.h>
#include <linux/proc_fs.h>
+#include <linux/kthread.h>
#include <linux/mempolicy.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
@@ -255,26 +255,25 @@ static int has_stopped_jobs(struct pid *pgrp)
}
/**
- * reparent_to_init - Reparent the calling kernel thread to the init task of the pid space that the thread belongs to.
+ * reparent_to_kthreadd - Reparent the calling kernel thread to kthreadd
*
* If a kernel thread is launched as a result of a system call, or if
- * it ever exits, it should generally reparent itself to init so that
- * it is correctly cleaned up on exit.
+ * it ever exits, it should generally reparent itself to kthreadd so it
+ * isn't in the way of other processes and is correctly cleaned up on exit.
*
* The various task state such as scheduling policy and priority may have
* been inherited from a user process, so we reset them to sane values here.
*
- * NOTE that reparent_to_init() gives the caller full capabilities.
+ * NOTE that reparent_to_kthreadd() gives the caller full capabilities.
*/
-static void reparent_to_init(void)
+static void reparent_to_kthreadd(void)
{
write_lock_irq(&tasklist_lock);
ptrace_unlink(current);
/* Reparent to init */
remove_parent(current);
- current->parent = child_reaper(current);
- current->real_parent = child_reaper(current);
+ current->real_parent = current->parent = kthreadd_task;
add_parent(current);
/* Set the exit signal to SIGCHLD so we signal init on exit */
@@ -348,7 +347,7 @@ int disallow_signal(int sig)
return -EINVAL;
spin_lock_irq(&current->sighand->siglock);
- sigaddset(&current->blocked, sig);
+ current->sighand->action[(sig)-1].sa.sa_handler = SIG_IGN;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
return 0;
@@ -401,7 +400,7 @@ void daemonize(const char *name, ...)
current->files = init_task.files;
atomic_inc(&current->files->count);
- reparent_to_init();
+ reparent_to_kthreadd();
}
EXPORT_SYMBOL(daemonize);
@@ -1033,6 +1032,8 @@ asmlinkage void sys_exit_group(int error_code)
static int eligible_child(pid_t pid, int options, struct task_struct *p)
{
+ int err;
+
if (pid > 0) {
if (p->pid != pid)
return 0;
@@ -1066,8 +1067,9 @@ static int eligible_child(pid_t pid, int options, struct task_struct *p)
if (delay_group_leader(p))
return 2;
- if (security_task_wait(p))
- return 0;
+ err = security_task_wait(p);
+ if (err)
+ return err;
return 1;
}
@@ -1449,6 +1451,7 @@ static long do_wait(pid_t pid, int options, struct siginfo __user *infop,
DECLARE_WAITQUEUE(wait, current);
struct task_struct *tsk;
int flag, retval;
+ int allowed, denied;
add_wait_queue(&current->signal->wait_chldexit,&wait);
repeat:
@@ -1457,6 +1460,7 @@ repeat:
* match our criteria, even if we are not able to reap it yet.
*/
flag = 0;
+ allowed = denied = 0;
current->state = TASK_INTERRUPTIBLE;
read_lock(&tasklist_lock);
tsk = current;
@@ -1472,6 +1476,12 @@ repeat:
if (!ret)
continue;
+ if (unlikely(ret < 0)) {
+ denied = ret;
+ continue;
+ }
+ allowed = 1;
+
switch (p->state) {
case TASK_TRACED:
/*
@@ -1570,6 +1580,8 @@ check_continued:
goto repeat;
}
retval = -ECHILD;
+ if (unlikely(denied) && !allowed)
+ retval = denied;
end:
current->state = TASK_RUNNING;
remove_wait_queue(&current->signal->wait_chldexit,&wait);
diff --git a/kernel/fork.c b/kernel/fork.c
index 6af959c034d..5dd3979747f 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/unistd.h>
-#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/completion.h>
@@ -106,7 +105,7 @@ static struct kmem_cache *mm_cachep;
void free_task(struct task_struct *tsk)
{
- free_thread_info(tsk->thread_info);
+ free_thread_info(tsk->stack);
rt_mutex_debug_task_free(tsk);
free_task_struct(tsk);
}
@@ -176,7 +175,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
}
*tsk = *orig;
- tsk->thread_info = ti;
+ tsk->stack = ti;
setup_thread_stack(tsk, orig);
#ifdef CONFIG_CC_STACKPROTECTOR
@@ -286,6 +285,8 @@ static inline int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
if (retval)
goto out;
}
+ /* a new mm has just been created */
+ arch_dup_mmap(oldmm, mm);
retval = 0;
out:
up_write(&mm->mmap_sem);
@@ -1423,8 +1424,7 @@ static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long fl
{
struct sighand_struct *sighand = data;
- if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
spin_lock_init(&sighand->siglock);
}
@@ -1515,26 +1515,6 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
}
/*
- * Unshare the mnt_namespace structure if it is being shared
- */
-static int unshare_mnt_namespace(unsigned long unshare_flags,
- struct mnt_namespace **new_nsp, struct fs_struct *new_fs)
-{
- struct mnt_namespace *ns = current->nsproxy->mnt_ns;
-
- if ((unshare_flags & CLONE_NEWNS) && ns) {
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- *new_nsp = dup_mnt_ns(current, new_fs ? new_fs : current->fs);
- if (!*new_nsp)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/*
* Unsharing of sighand is not supported yet
*/
static int unshare_sighand(unsigned long unshare_flags, struct sighand_struct **new_sighp)
@@ -1592,16 +1572,6 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n
return 0;
}
-#ifndef CONFIG_IPC_NS
-static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns)
-{
- if (flags & CLONE_NEWIPC)
- return -EINVAL;
-
- return 0;
-}
-#endif
-
/*
* unshare allows a process to 'unshare' part of the process
* context which was originally shared using clone. copy_*
@@ -1614,14 +1584,11 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
{
int err = 0;
struct fs_struct *fs, *new_fs = NULL;
- struct mnt_namespace *ns, *new_ns = NULL;
struct sighand_struct *new_sigh = NULL;
struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
struct files_struct *fd, *new_fd = NULL;
struct sem_undo_list *new_ulist = NULL;
struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
- struct uts_namespace *uts, *new_uts = NULL;
- struct ipc_namespace *ipc, *new_ipc = NULL;
check_unshare_flags(&unshare_flags);
@@ -1636,36 +1603,24 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
goto bad_unshare_out;
if ((err = unshare_fs(unshare_flags, &new_fs)))
goto bad_unshare_cleanup_thread;
- if ((err = unshare_mnt_namespace(unshare_flags, &new_ns, new_fs)))
- goto bad_unshare_cleanup_fs;
if ((err = unshare_sighand(unshare_flags, &new_sigh)))
- goto bad_unshare_cleanup_ns;
+ goto bad_unshare_cleanup_fs;
if ((err = unshare_vm(unshare_flags, &new_mm)))
goto bad_unshare_cleanup_sigh;
if ((err = unshare_fd(unshare_flags, &new_fd)))
goto bad_unshare_cleanup_vm;
if ((err = unshare_semundo(unshare_flags, &new_ulist)))
goto bad_unshare_cleanup_fd;
- if ((err = unshare_utsname(unshare_flags, &new_uts)))
+ if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
+ new_fs)))
goto bad_unshare_cleanup_semundo;
- if ((err = unshare_ipcs(unshare_flags, &new_ipc)))
- goto bad_unshare_cleanup_uts;
-
- if (new_ns || new_uts || new_ipc) {
- old_nsproxy = current->nsproxy;
- new_nsproxy = dup_namespaces(old_nsproxy);
- if (!new_nsproxy) {
- err = -ENOMEM;
- goto bad_unshare_cleanup_ipc;
- }
- }
- if (new_fs || new_ns || new_mm || new_fd || new_ulist ||
- new_uts || new_ipc) {
+ if (new_fs || new_mm || new_fd || new_ulist || new_nsproxy) {
task_lock(current);
if (new_nsproxy) {
+ old_nsproxy = current->nsproxy;
current->nsproxy = new_nsproxy;
new_nsproxy = old_nsproxy;
}
@@ -1676,12 +1631,6 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
new_fs = fs;
}
- if (new_ns) {
- ns = current->nsproxy->mnt_ns;
- current->nsproxy->mnt_ns = new_ns;
- new_ns = ns;
- }
-
if (new_mm) {
mm = current->mm;
active_mm = current->active_mm;
@@ -1697,32 +1646,12 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
new_fd = fd;
}
- if (new_uts) {
- uts = current->nsproxy->uts_ns;
- current->nsproxy->uts_ns = new_uts;
- new_uts = uts;
- }
-
- if (new_ipc) {
- ipc = current->nsproxy->ipc_ns;
- current->nsproxy->ipc_ns = new_ipc;
- new_ipc = ipc;
- }
-
task_unlock(current);
}
if (new_nsproxy)
put_nsproxy(new_nsproxy);
-bad_unshare_cleanup_ipc:
- if (new_ipc)
- put_ipc_ns(new_ipc);
-
-bad_unshare_cleanup_uts:
- if (new_uts)
- put_uts_ns(new_uts);
-
bad_unshare_cleanup_semundo:
bad_unshare_cleanup_fd:
if (new_fd)
@@ -1737,10 +1666,6 @@ bad_unshare_cleanup_sigh:
if (atomic_dec_and_test(&new_sigh->count))
kmem_cache_free(sighand_cachep, new_sigh);
-bad_unshare_cleanup_ns:
- if (new_ns)
- put_mnt_ns(new_ns);
-
bad_unshare_cleanup_fs:
if (new_fs)
put_fs_struct(new_fs);
diff --git a/kernel/futex.c b/kernel/futex.c
index 5a270b5e3f9..b7ce15c67e3 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -16,6 +16,9 @@
* Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
* Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com>
*
+ * PRIVATE futexes by Eric Dumazet
+ * Copyright (C) 2007 Eric Dumazet <dada1@cosmosbay.com>
+ *
* Thanks to Ben LaHaise for yelling "hashed waitqueues" loudly
* enough at me, Linus for the original (flawed) idea, Matthew
* Kirkwood for proof-of-concept implementation.
@@ -48,37 +51,18 @@
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/signal.h>
+#include <linux/module.h>
#include <asm/futex.h>
#include "rtmutex_common.h"
-#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
-/*
- * Futexes are matched on equal values of this key.
- * The key type depends on whether it's a shared or private mapping.
- * Don't rearrange members without looking at hash_futex().
- *
- * offset is aligned to a multiple of sizeof(u32) (== 4) by definition.
- * We set bit 0 to indicate if it's an inode-based key.
- */
-union futex_key {
- struct {
- unsigned long pgoff;
- struct inode *inode;
- int offset;
- } shared;
- struct {
- unsigned long address;
- struct mm_struct *mm;
- int offset;
- } private;
- struct {
- unsigned long word;
- void *ptr;
- int offset;
- } both;
-};
+#define FUTEX_HASHBITS (CONFIG_BASE_SMALL ? 4 : 8)
/*
* Priority Inheritance state:
@@ -106,12 +90,12 @@ struct futex_pi_state {
* we can wake only the relevant ones (hashed queues may be shared).
*
* A futex_q has a woken state, just like tasks have TASK_RUNNING.
- * It is considered woken when list_empty(&q->list) || q->lock_ptr == 0.
+ * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
* The order of wakup is always to make the first condition true, then
* wake up q->waiters, then make the second condition true.
*/
struct futex_q {
- struct list_head list;
+ struct plist_node list;
wait_queue_head_t waiters;
/* Which hash list lock to use: */
@@ -127,14 +111,20 @@ struct futex_q {
/* Optional priority inheritance state: */
struct futex_pi_state *pi_state;
struct task_struct *task;
+
+ /*
+ * This waiter is used in case of requeue from a
+ * normal futex to a PI-futex
+ */
+ struct rt_mutex_waiter waiter;
};
/*
* Split the global futex_lock into every hash list lock.
*/
struct futex_hash_bucket {
- spinlock_t lock;
- struct list_head chain;
+ spinlock_t lock;
+ struct plist_head chain;
};
static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
@@ -163,19 +153,26 @@ static inline int match_futex(union futex_key *key1, union futex_key *key2)
&& key1->both.offset == key2->both.offset);
}
-/*
- * Get parameters which are the keys for a futex.
+/**
+ * get_futex_key - Get parameters which are the keys for a futex.
+ * @uaddr: virtual address of the futex
+ * @shared: NULL for a PROCESS_PRIVATE futex,
+ * &current->mm->mmap_sem for a PROCESS_SHARED futex
+ * @key: address where result is stored.
+ *
+ * Returns a negative error code or 0
+ * The key words are stored in *key on success.
*
* For shared mappings, it's (page->index, vma->vm_file->f_path.dentry->d_inode,
* offset_within_page). For private mappings, it's (uaddr, current->mm).
* We can usually work out the index without swapping in the page.
*
- * Returns: 0, or negative error code.
- * The key words are stored in *key on success.
- *
- * Should be called with &current->mm->mmap_sem but NOT any spinlocks.
+ * fshared is NULL for PROCESS_PRIVATE futexes
+ * For other futexes, it points to &current->mm->mmap_sem and
+ * caller must have taken the reader lock. but NOT any spinlocks.
*/
-static int get_futex_key(u32 __user *uaddr, union futex_key *key)
+int get_futex_key(u32 __user *uaddr, struct rw_semaphore *fshared,
+ union futex_key *key)
{
unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm;
@@ -187,11 +184,25 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
* The futex address must be "naturally" aligned.
*/
key->both.offset = address % PAGE_SIZE;
- if (unlikely((key->both.offset % sizeof(u32)) != 0))
+ if (unlikely((address % sizeof(u32)) != 0))
return -EINVAL;
address -= key->both.offset;
/*
+ * PROCESS_PRIVATE futexes are fast.
+ * As the mm cannot disappear under us and the 'key' only needs
+ * virtual address, we dont even have to find the underlying vma.
+ * Note : We do have to check 'uaddr' is a valid user address,
+ * but access_ok() should be faster than find_vma()
+ */
+ if (!fshared) {
+ if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
+ return -EFAULT;
+ key->private.mm = mm;
+ key->private.address = address;
+ return 0;
+ }
+ /*
* The futex is hashed differently depending on whether
* it's in a shared or private mapping. So check vma first.
*/
@@ -205,6 +216,9 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
if (unlikely((vma->vm_flags & (VM_IO|VM_READ)) != VM_READ))
return (vma->vm_flags & VM_IO) ? -EPERM : -EACCES;
+ /* Save the user address in the ley */
+ key->uaddr = uaddr;
+
/*
* Private mappings are handled in a simple way.
*
@@ -215,6 +229,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
* mappings of _writable_ handles.
*/
if (likely(!(vma->vm_flags & VM_MAYSHARE))) {
+ key->both.offset |= FUT_OFF_MMSHARED; /* reference taken on mm */
key->private.mm = mm;
key->private.address = address;
return 0;
@@ -224,7 +239,7 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
* Linear file mappings are also simple.
*/
key->shared.inode = vma->vm_file->f_path.dentry->d_inode;
- key->both.offset++; /* Bit 0 of offset indicates inode-based key. */
+ key->both.offset |= FUT_OFF_INODE; /* inode-based key. */
if (likely(!(vma->vm_flags & VM_NONLINEAR))) {
key->shared.pgoff = (((address - vma->vm_start) >> PAGE_SHIFT)
+ vma->vm_pgoff);
@@ -246,37 +261,46 @@ static int get_futex_key(u32 __user *uaddr, union futex_key *key)
}
return err;
}
+EXPORT_SYMBOL_GPL(get_futex_key);
/*
* Take a reference to the resource addressed by a key.
* Can be called while holding spinlocks.
*
- * NOTE: mmap_sem MUST be held between get_futex_key() and calling this
- * function, if it is called at all. mmap_sem keeps key->shared.inode valid.
*/
-static inline void get_key_refs(union futex_key *key)
+inline void get_futex_key_refs(union futex_key *key)
{
- if (key->both.ptr != 0) {
- if (key->both.offset & 1)
+ if (key->both.ptr == 0)
+ return;
+ switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+ case FUT_OFF_INODE:
atomic_inc(&key->shared.inode->i_count);
- else
+ break;
+ case FUT_OFF_MMSHARED:
atomic_inc(&key->private.mm->mm_count);
+ break;
}
}
+EXPORT_SYMBOL_GPL(get_futex_key_refs);
/*
* Drop a reference to the resource addressed by a key.
* The hash bucket spinlock must not be held.
*/
-static void drop_key_refs(union futex_key *key)
+void drop_futex_key_refs(union futex_key *key)
{
- if (key->both.ptr != 0) {
- if (key->both.offset & 1)
+ if (key->both.ptr == 0)
+ return;
+ switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) {
+ case FUT_OFF_INODE:
iput(key->shared.inode);
- else
+ break;
+ case FUT_OFF_MMSHARED:
mmdrop(key->private.mm);
+ break;
}
}
+EXPORT_SYMBOL_GPL(drop_futex_key_refs);
static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
{
@@ -290,28 +314,38 @@ static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
}
/*
- * Fault handling. Called with current->mm->mmap_sem held.
+ * Fault handling.
+ * if fshared is non NULL, current->mm->mmap_sem is already held
*/
-static int futex_handle_fault(unsigned long address, int attempt)
+static int futex_handle_fault(unsigned long address,
+ struct rw_semaphore *fshared, int attempt)
{
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
+ int ret = -EFAULT;
- if (attempt > 2 || !(vma = find_vma(mm, address)) ||
- vma->vm_start > address || !(vma->vm_flags & VM_WRITE))
- return -EFAULT;
+ if (attempt > 2)
+ return ret;
- switch (handle_mm_fault(mm, vma, address, 1)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- default:
- return -EFAULT;
+ if (!fshared)
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, address);
+ if (vma && address >= vma->vm_start &&
+ (vma->vm_flags & VM_WRITE)) {
+ switch (handle_mm_fault(mm, vma, address, 1)) {
+ case VM_FAULT_MINOR:
+ ret = 0;
+ current->min_flt++;
+ break;
+ case VM_FAULT_MAJOR:
+ ret = 0;
+ current->maj_flt++;
+ break;
+ }
}
- return 0;
+ if (!fshared)
+ up_read(&mm->mmap_sem);
+ return ret;
}
/*
@@ -461,18 +495,19 @@ void exit_pi_state_list(struct task_struct *curr)
}
static int
-lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
+lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
+ union futex_key *key, struct futex_pi_state **ps)
{
struct futex_pi_state *pi_state = NULL;
struct futex_q *this, *next;
- struct list_head *head;
+ struct plist_head *head;
struct task_struct *p;
pid_t pid;
head = &hb->chain;
- list_for_each_entry_safe(this, next, head, list) {
- if (match_futex(&this->key, &me->key)) {
+ plist_for_each_entry_safe(this, next, head, list) {
+ if (match_futex(&this->key, key)) {
/*
* Another waiter already exists - bump up
* the refcount and return its pi_state:
@@ -487,7 +522,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
WARN_ON(!atomic_read(&pi_state->refcount));
atomic_inc(&pi_state->refcount);
- me->pi_state = pi_state;
+ *ps = pi_state;
return 0;
}
@@ -514,7 +549,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
/* Store the key for possible exit cleanups: */
- pi_state->key = me->key;
+ pi_state->key = *key;
spin_lock_irq(&p->pi_lock);
WARN_ON(!list_empty(&pi_state->list));
@@ -524,7 +559,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
put_task_struct(p);
- me->pi_state = pi_state;
+ *ps = pi_state;
return 0;
}
@@ -535,12 +570,12 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, struct futex_q *me)
*/
static void wake_futex(struct futex_q *q)
{
- list_del_init(&q->list);
+ plist_del(&q->list, &q->list.plist);
if (q->filp)
send_sigio(&q->filp->f_owner, q->fd, POLL_IN);
/*
* The lock in wake_up_all() is a crucial memory barrier after the
- * list_del_init() and also before assigning to q->lock_ptr.
+ * plist_del() and also before assigning to q->lock_ptr.
*/
wake_up_all(&q->waiters);
/*
@@ -584,6 +619,8 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
*/
if (!(uval & FUTEX_OWNER_DIED)) {
newval = FUTEX_WAITERS | new_owner->pid;
+ /* Keep the FUTEX_WAITER_REQUEUED flag if it was set */
+ newval |= (uval & FUTEX_WAITER_REQUEUED);
pagefault_disable();
curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -651,17 +688,19 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
* Wake up all waiters hashed on the physical page that is mapped
* to this virtual address:
*/
-static int futex_wake(u32 __user *uaddr, int nr_wake)
+static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
+ int nr_wake)
{
struct futex_hash_bucket *hb;
struct futex_q *this, *next;
- struct list_head *head;
+ struct plist_head *head;
union futex_key key;
int ret;
- down_read(&current->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
- ret = get_futex_key(uaddr, &key);
+ ret = get_futex_key(uaddr, fshared, &key);
if (unlikely(ret != 0))
goto out;
@@ -669,7 +708,7 @@ static int futex_wake(u32 __user *uaddr, int nr_wake)
spin_lock(&hb->lock);
head = &hb->chain;
- list_for_each_entry_safe(this, next, head, list) {
+ plist_for_each_entry_safe(this, next, head, list) {
if (match_futex (&this->key, &key)) {
if (this->pi_state) {
ret = -EINVAL;
@@ -683,7 +722,261 @@ static int futex_wake(u32 __user *uaddr, int nr_wake)
spin_unlock(&hb->lock);
out:
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
+ return ret;
+}
+
+/*
+ * Called from futex_requeue_pi.
+ * Set FUTEX_WAITERS and FUTEX_WAITER_REQUEUED flags on the
+ * PI-futex value; search its associated pi_state if an owner exist
+ * or create a new one without owner.
+ */
+static inline int
+lookup_pi_state_for_requeue(u32 __user *uaddr, struct futex_hash_bucket *hb,
+ union futex_key *key,
+ struct futex_pi_state **pi_state)
+{
+ u32 curval, uval, newval;
+
+retry:
+ /*
+ * We can't handle a fault cleanly because we can't
+ * release the locks here. Simply return the fault.
+ */
+ if (get_futex_value_locked(&curval, uaddr))
+ return -EFAULT;
+
+ /* set the flags FUTEX_WAITERS and FUTEX_WAITER_REQUEUED */
+ if ((curval & (FUTEX_WAITERS | FUTEX_WAITER_REQUEUED))
+ != (FUTEX_WAITERS | FUTEX_WAITER_REQUEUED)) {
+ /*
+ * No waiters yet, we prepare the futex to have some waiters.
+ */
+
+ uval = curval;
+ newval = uval | FUTEX_WAITERS | FUTEX_WAITER_REQUEUED;
+
+ pagefault_disable();
+ curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+ pagefault_enable();
+
+ if (unlikely(curval == -EFAULT))
+ return -EFAULT;
+ if (unlikely(curval != uval))
+ goto retry;
+ }
+
+ if (!(curval & FUTEX_TID_MASK)
+ || lookup_pi_state(curval, hb, key, pi_state)) {
+ /* the futex has no owner (yet) or the lookup failed:
+ allocate one pi_state without owner */
+
+ *pi_state = alloc_pi_state();
+
+ /* Already stores the key: */
+ (*pi_state)->key = *key;
+
+ /* init the mutex without owner */
+ __rt_mutex_init(&(*pi_state)->pi_mutex, NULL);
+ }
+
+ return 0;
+}
+
+/*
+ * Keep the first nr_wake waiter from futex1, wake up one,
+ * and requeue the next nr_requeue waiters following hashed on
+ * one physical page to another physical page (PI-futex uaddr2)
+ */
+static int futex_requeue_pi(u32 __user *uaddr1,
+ struct rw_semaphore *fshared,
+ u32 __user *uaddr2,
+ int nr_wake, int nr_requeue, u32 *cmpval)
+{
+ union futex_key key1, key2;
+ struct futex_hash_bucket *hb1, *hb2;
+ struct plist_head *head1;
+ struct futex_q *this, *next;
+ struct futex_pi_state *pi_state2 = NULL;
+ struct rt_mutex_waiter *waiter, *top_waiter = NULL;
+ struct rt_mutex *lock2 = NULL;
+ int ret, drop_count = 0;
+
+ if (refill_pi_state_cache())
+ return -ENOMEM;
+
+retry:
+ /*
+ * First take all the futex related locks:
+ */
+ if (fshared)
+ down_read(fshared);
+
+ ret = get_futex_key(uaddr1, fshared, &key1);
+ if (unlikely(ret != 0))
+ goto out;
+ ret = get_futex_key(uaddr2, fshared, &key2);
+ if (unlikely(ret != 0))
+ goto out;
+
+ hb1 = hash_futex(&key1);
+ hb2 = hash_futex(&key2);
+
+ double_lock_hb(hb1, hb2);
+
+ if (likely(cmpval != NULL)) {
+ u32 curval;
+
+ ret = get_futex_value_locked(&curval, uaddr1);
+
+ if (unlikely(ret)) {
+ spin_unlock(&hb1->lock);
+ if (hb1 != hb2)
+ spin_unlock(&hb2->lock);
+
+ /*
+ * If we would have faulted, release mmap_sem, fault
+ * it in and start all over again.
+ */
+ if (fshared)
+ up_read(fshared);
+
+ ret = get_user(curval, uaddr1);
+
+ if (!ret)
+ goto retry;
+
+ return ret;
+ }
+ if (curval != *cmpval) {
+ ret = -EAGAIN;
+ goto out_unlock;
+ }
+ }
+
+ head1 = &hb1->chain;
+ plist_for_each_entry_safe(this, next, head1, list) {
+ if (!match_futex (&this->key, &key1))
+ continue;
+ if (++ret <= nr_wake) {
+ wake_futex(this);
+ } else {
+ /*
+ * FIRST: get and set the pi_state
+ */
+ if (!pi_state2) {
+ int s;
+ /* do this only the first time we requeue someone */
+ s = lookup_pi_state_for_requeue(uaddr2, hb2,
+ &key2, &pi_state2);
+ if (s) {
+ ret = s;
+ goto out_unlock;
+ }
+
+ lock2 = &pi_state2->pi_mutex;
+ spin_lock(&lock2->wait_lock);
+
+ /* Save the top waiter of the wait_list */
+ if (rt_mutex_has_waiters(lock2))
+ top_waiter = rt_mutex_top_waiter(lock2);
+ } else
+ atomic_inc(&pi_state2->refcount);
+
+
+ this->pi_state = pi_state2;
+
+ /*
+ * SECOND: requeue futex_q to the correct hashbucket
+ */
+
+ /*
+ * If key1 and key2 hash to the same bucket, no need to
+ * requeue.
+ */
+ if (likely(head1 != &hb2->chain)) {
+ plist_del(&this->list, &hb1->chain);
+ plist_add(&this->list, &hb2->chain);
+ this->lock_ptr = &hb2->lock;
+#ifdef CONFIG_DEBUG_PI_LIST
+ this->list.plist.lock = &hb2->lock;
+#endif
+ }
+ this->key = key2;
+ get_futex_key_refs(&key2);
+ drop_count++;
+
+
+ /*
+ * THIRD: queue it to lock2
+ */
+ spin_lock_irq(&this->task->pi_lock);
+ waiter = &this->waiter;
+ waiter->task = this->task;
+ waiter->lock = lock2;
+ plist_node_init(&waiter->list_entry, this->task->prio);
+ plist_node_init(&waiter->pi_list_entry, this->task->prio);
+ plist_add(&waiter->list_entry, &lock2->wait_list);
+ this->task->pi_blocked_on = waiter;
+ spin_unlock_irq(&this->task->pi_lock);
+
+ if (ret - nr_wake >= nr_requeue)
+ break;
+ }
+ }
+
+ /* If we've requeued some tasks and the top_waiter of the rt_mutex
+ has changed, we must adjust the priority of the owner, if any */
+ if (drop_count) {
+ struct task_struct *owner = rt_mutex_owner(lock2);
+ if (owner &&
+ (top_waiter != (waiter = rt_mutex_top_waiter(lock2)))) {
+ int chain_walk = 0;
+
+ spin_lock_irq(&owner->pi_lock);
+ if (top_waiter)
+ plist_del(&top_waiter->pi_list_entry, &owner->pi_waiters);
+ else
+ /*
+ * There was no waiters before the requeue,
+ * the flag must be updated
+ */
+ mark_rt_mutex_waiters(lock2);
+
+ plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
+ __rt_mutex_adjust_prio(owner);
+ if (owner->pi_blocked_on) {
+ chain_walk = 1;
+ get_task_struct(owner);
+ }
+
+ spin_unlock_irq(&owner->pi_lock);
+ spin_unlock(&lock2->wait_lock);
+
+ if (chain_walk)
+ rt_mutex_adjust_prio_chain(owner, 0, lock2, NULL,
+ current);
+ } else {
+ /* No owner or the top_waiter does not change */
+ mark_rt_mutex_waiters(lock2);
+ spin_unlock(&lock2->wait_lock);
+ }
+ }
+
+out_unlock:
+ spin_unlock(&hb1->lock);
+ if (hb1 != hb2)
+ spin_unlock(&hb2->lock);
+
+ /* drop_futex_key_refs() must be called outside the spinlocks. */
+ while (--drop_count >= 0)
+ drop_futex_key_refs(&key1);
+
+out:
+ if (fshared)
+ up_read(fshared);
return ret;
}
@@ -692,22 +985,24 @@ out:
* to this virtual address:
*/
static int
-futex_wake_op(u32 __user *uaddr1, u32 __user *uaddr2,
+futex_wake_op(u32 __user *uaddr1, struct rw_semaphore *fshared,
+ u32 __user *uaddr2,
int nr_wake, int nr_wake2, int op)
{
union futex_key key1, key2;
struct futex_hash_bucket *hb1, *hb2;
- struct list_head *head;
+ struct plist_head *head;
struct futex_q *this, *next;
int ret, op_ret, attempt = 0;
retryfull:
- down_read(&current->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
- ret = get_futex_key(uaddr1, &key1);
+ ret = get_futex_key(uaddr1, fshared, &key1);
if (unlikely(ret != 0))
goto out;
- ret = get_futex_key(uaddr2, &key2);
+ ret = get_futex_key(uaddr2, fshared, &key2);
if (unlikely(ret != 0))
goto out;
@@ -747,11 +1042,10 @@ retry:
* still holding the mmap_sem.
*/
if (attempt++) {
- if (futex_handle_fault((unsigned long)uaddr2,
- attempt)) {
- ret = -EFAULT;
+ ret = futex_handle_fault((unsigned long)uaddr2,
+ fshared, attempt);
+ if (ret)
goto out;
- }
goto retry;
}
@@ -759,7 +1053,8 @@ retry:
* If we would have faulted, release mmap_sem,
* fault it in and start all over again.
*/
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
ret = get_user(dummy, uaddr2);
if (ret)
@@ -770,7 +1065,7 @@ retry:
head = &hb1->chain;
- list_for_each_entry_safe(this, next, head, list) {
+ plist_for_each_entry_safe(this, next, head, list) {
if (match_futex (&this->key, &key1)) {
wake_futex(this);
if (++ret >= nr_wake)
@@ -782,7 +1077,7 @@ retry:
head = &hb2->chain;
op_ret = 0;
- list_for_each_entry_safe(this, next, head, list) {
+ plist_for_each_entry_safe(this, next, head, list) {
if (match_futex (&this->key, &key2)) {
wake_futex(this);
if (++op_ret >= nr_wake2)
@@ -796,7 +1091,8 @@ retry:
if (hb1 != hb2)
spin_unlock(&hb2->lock);
out:
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
return ret;
}
@@ -804,22 +1100,24 @@ out:
* Requeue all waiters hashed on one physical page to another
* physical page.
*/
-static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
+static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
+ u32 __user *uaddr2,
int nr_wake, int nr_requeue, u32 *cmpval)
{
union futex_key key1, key2;
struct futex_hash_bucket *hb1, *hb2;
- struct list_head *head1;
+ struct plist_head *head1;
struct futex_q *this, *next;
int ret, drop_count = 0;
retry:
- down_read(&current->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
- ret = get_futex_key(uaddr1, &key1);
+ ret = get_futex_key(uaddr1, fshared, &key1);
if (unlikely(ret != 0))
goto out;
- ret = get_futex_key(uaddr2, &key2);
+ ret = get_futex_key(uaddr2, fshared, &key2);
if (unlikely(ret != 0))
goto out;
@@ -842,7 +1140,8 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
* If we would have faulted, release mmap_sem, fault
* it in and start all over again.
*/
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
ret = get_user(curval, uaddr1);
@@ -858,7 +1157,7 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
}
head1 = &hb1->chain;
- list_for_each_entry_safe(this, next, head1, list) {
+ plist_for_each_entry_safe(this, next, head1, list) {
if (!match_futex (&this->key, &key1))
continue;
if (++ret <= nr_wake) {
@@ -869,11 +1168,15 @@ static int futex_requeue(u32 __user *uaddr1, u32 __user *uaddr2,
* requeue.
*/
if (likely(head1 != &hb2->chain)) {
- list_move_tail(&this->list, &hb2->chain);
+ plist_del(&this->list, &hb1->chain);
+ plist_add(&this->list, &hb2->chain);
this->lock_ptr = &hb2->lock;
- }
+#ifdef CONFIG_DEBUG_PI_LIST
+ this->list.plist.lock = &hb2->lock;
+#endif
+ }
this->key = key2;
- get_key_refs(&key2);
+ get_futex_key_refs(&key2);
drop_count++;
if (ret - nr_wake >= nr_requeue)
@@ -886,12 +1189,13 @@ out_unlock:
if (hb1 != hb2)
spin_unlock(&hb2->lock);
- /* drop_key_refs() must be called outside the spinlocks. */
+ /* drop_futex_key_refs() must be called outside the spinlocks. */
while (--drop_count >= 0)
- drop_key_refs(&key1);
+ drop_futex_key_refs(&key1);
out:
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
return ret;
}
@@ -906,7 +1210,7 @@ queue_lock(struct futex_q *q, int fd, struct file *filp)
init_waitqueue_head(&q->waiters);
- get_key_refs(&q->key);
+ get_futex_key_refs(&q->key);
hb = hash_futex(&q->key);
q->lock_ptr = &hb->lock;
@@ -916,7 +1220,23 @@ queue_lock(struct futex_q *q, int fd, struct file *filp)
static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
{
- list_add_tail(&q->list, &hb->chain);
+ int prio;
+
+ /*
+ * The priority used to register this element is
+ * - either the real thread-priority for the real-time threads
+ * (i.e. threads with a priority lower than MAX_RT_PRIO)
+ * - or MAX_RT_PRIO for non-RT threads.
+ * Thus, all RT-threads are woken first in priority order, and
+ * the others are woken last, in FIFO order.
+ */
+ prio = min(current->normal_prio, MAX_RT_PRIO);
+
+ plist_node_init(&q->list, prio);
+#ifdef CONFIG_DEBUG_PI_LIST
+ q->list.plist.lock = &hb->lock;
+#endif
+ plist_add(&q->list, &hb->chain);
q->task = current;
spin_unlock(&hb->lock);
}
@@ -925,7 +1245,7 @@ static inline void
queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
{
spin_unlock(&hb->lock);
- drop_key_refs(&q->key);
+ drop_futex_key_refs(&q->key);
}
/*
@@ -971,8 +1291,8 @@ static int unqueue_me(struct futex_q *q)
spin_unlock(lock_ptr);
goto retry;
}
- WARN_ON(list_empty(&q->list));
- list_del(&q->list);
+ WARN_ON(plist_node_empty(&q->list));
+ plist_del(&q->list, &q->list.plist);
BUG_ON(q->pi_state);
@@ -980,29 +1300,94 @@ static int unqueue_me(struct futex_q *q)
ret = 1;
}
- drop_key_refs(&q->key);
+ drop_futex_key_refs(&q->key);
return ret;
}
/*
* PI futexes can not be requeued and must remove themself from the
- * hash bucket. The hash bucket lock is held on entry and dropped here.
+ * hash bucket. The hash bucket lock (i.e. lock_ptr) is held on entry
+ * and dropped here.
*/
-static void unqueue_me_pi(struct futex_q *q, struct futex_hash_bucket *hb)
+static void unqueue_me_pi(struct futex_q *q)
{
- WARN_ON(list_empty(&q->list));
- list_del(&q->list);
+ WARN_ON(plist_node_empty(&q->list));
+ plist_del(&q->list, &q->list.plist);
BUG_ON(!q->pi_state);
free_pi_state(q->pi_state);
q->pi_state = NULL;
- spin_unlock(&hb->lock);
+ spin_unlock(q->lock_ptr);
- drop_key_refs(&q->key);
+ drop_futex_key_refs(&q->key);
}
-static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
+/*
+ * Fixup the pi_state owner with current.
+ *
+ * The cur->mm semaphore must be held, it is released at return of this
+ * function.
+ */
+static int fixup_pi_state_owner(u32 __user *uaddr, struct rw_semaphore *fshared,
+ struct futex_q *q,
+ struct futex_hash_bucket *hb,
+ struct task_struct *curr)
+{
+ u32 newtid = curr->pid | FUTEX_WAITERS;
+ struct futex_pi_state *pi_state = q->pi_state;
+ u32 uval, curval, newval;
+ int ret;
+
+ /* Owner died? */
+ if (pi_state->owner != NULL) {
+ spin_lock_irq(&pi_state->owner->pi_lock);
+ WARN_ON(list_empty(&pi_state->list));
+ list_del_init(&pi_state->list);
+ spin_unlock_irq(&pi_state->owner->pi_lock);
+ } else
+ newtid |= FUTEX_OWNER_DIED;
+
+ pi_state->owner = curr;
+
+ spin_lock_irq(&curr->pi_lock);
+ WARN_ON(!list_empty(&pi_state->list));
+ list_add(&pi_state->list, &curr->pi_state_list);
+ spin_unlock_irq(&curr->pi_lock);
+
+ /* Unqueue and drop the lock */
+ unqueue_me_pi(q);
+ if (fshared)
+ up_read(fshared);
+ /*
+ * We own it, so we have to replace the pending owner
+ * TID. This must be atomic as we have preserve the
+ * owner died bit here.
+ */
+ ret = get_user(uval, uaddr);
+ while (!ret) {
+ newval = (uval & FUTEX_OWNER_DIED) | newtid;
+ newval |= (uval & FUTEX_WAITER_REQUEUED);
+ curval = futex_atomic_cmpxchg_inatomic(uaddr,
+ uval, newval);
+ if (curval == -EFAULT)
+ ret = -EFAULT;
+ if (curval == uval)
+ break;
+ uval = curval;
+ }
+ return ret;
+}
+
+/*
+ * In case we must use restart_block to restart a futex_wait,
+ * we encode in the 'arg3' shared capability
+ */
+#define ARG3_SHARED 1
+
+static long futex_wait_restart(struct restart_block *restart);
+static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
+ u32 val, ktime_t *abs_time)
{
struct task_struct *curr = current;
DECLARE_WAITQUEUE(wait, curr);
@@ -1010,12 +1395,15 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
struct futex_q q;
u32 uval;
int ret;
+ struct hrtimer_sleeper t, *to = NULL;
+ int rem = 0;
q.pi_state = NULL;
retry:
- down_read(&curr->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
- ret = get_futex_key(uaddr, &q.key);
+ ret = get_futex_key(uaddr, fshared, &q.key);
if (unlikely(ret != 0))
goto out_release_sem;
@@ -1038,8 +1426,8 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
* a wakeup when *uaddr != val on entry to the syscall. This is
* rare, but normal.
*
- * We hold the mmap semaphore, so the mapping cannot have changed
- * since we looked it up in get_futex_key.
+ * for shared futexes, we hold the mmap semaphore, so the mapping
+ * cannot have changed since we looked it up in get_futex_key.
*/
ret = get_futex_value_locked(&uval, uaddr);
@@ -1050,7 +1438,8 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
* If we would have faulted, release mmap_sem, fault it in and
* start all over again.
*/
- up_read(&curr->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
ret = get_user(uval, uaddr);
@@ -1062,6 +1451,14 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
if (uval != val)
goto out_unlock_release_sem;
+ /*
+ * This rt_mutex_waiter structure is prepared here and will
+ * be used only if this task is requeued from a normal futex to
+ * a PI-futex with futex_requeue_pi.
+ */
+ debug_rt_mutex_init_waiter(&q.waiter);
+ q.waiter.task = NULL;
+
/* Only actually queue if *uaddr contained val. */
__queue_me(&q, hb);
@@ -1069,7 +1466,8 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
* Now the futex is queued and we have checked the data, we
* don't want to hold mmap_sem while we sleep.
*/
- up_read(&curr->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
/*
* There might have been scheduling since the queue_me(), as we
@@ -1084,11 +1482,34 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
__set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&q.waiters, &wait);
/*
- * !list_empty() is safe here without any lock.
+ * !plist_node_empty() is safe here without any lock.
* q.lock_ptr != 0 is not safe, because of ordering against wakeup.
*/
- if (likely(!list_empty(&q.list)))
- time = schedule_timeout(time);
+ if (likely(!plist_node_empty(&q.list))) {
+ if (!abs_time)
+ schedule();
+ else {
+ to = &t;
+ hrtimer_init(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ hrtimer_init_sleeper(&t, current);
+ t.timer.expires = *abs_time;
+
+ hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
+
+ /*
+ * the timer could have already expired, in which
+ * case current would be flagged for rescheduling.
+ * Don't bother calling schedule.
+ */
+ if (likely(t.task))
+ schedule();
+
+ hrtimer_cancel(&t.timer);
+
+ /* Flag if a timeout occured */
+ rem = (t.task == NULL);
+ }
+ }
__set_current_state(TASK_RUNNING);
/*
@@ -1096,62 +1517,203 @@ static int futex_wait(u32 __user *uaddr, u32 val, unsigned long time)
* we are the only user of it.
*/
+ if (q.pi_state) {
+ /*
+ * We were woken but have been requeued on a PI-futex.
+ * We have to complete the lock acquisition by taking
+ * the rtmutex.
+ */
+
+ struct rt_mutex *lock = &q.pi_state->pi_mutex;
+
+ spin_lock(&lock->wait_lock);
+ if (unlikely(q.waiter.task)) {
+ remove_waiter(lock, &q.waiter);
+ }
+ spin_unlock(&lock->wait_lock);
+
+ if (rem)
+ ret = -ETIMEDOUT;
+ else
+ ret = rt_mutex_timed_lock(lock, to, 1);
+
+ if (fshared)
+ down_read(fshared);
+ spin_lock(q.lock_ptr);
+
+ /*
+ * Got the lock. We might not be the anticipated owner if we
+ * did a lock-steal - fix up the PI-state in that case.
+ */
+ if (!ret && q.pi_state->owner != curr) {
+ /*
+ * We MUST play with the futex we were requeued on,
+ * NOT the current futex.
+ * We can retrieve it from the key of the pi_state
+ */
+ uaddr = q.pi_state->key.uaddr;
+
+ /* mmap_sem and hash_bucket lock are unlocked at
+ return of this function */
+ ret = fixup_pi_state_owner(uaddr, fshared,
+ &q, hb, curr);
+ } else {
+ /*
+ * Catch the rare case, where the lock was released
+ * when we were on the way back before we locked
+ * the hash bucket.
+ */
+ if (ret && q.pi_state->owner == curr) {
+ if (rt_mutex_trylock(&q.pi_state->pi_mutex))
+ ret = 0;
+ }
+ /* Unqueue and drop the lock */
+ unqueue_me_pi(&q);
+ if (fshared)
+ up_read(fshared);
+ }
+
+ debug_rt_mutex_free_waiter(&q.waiter);
+
+ return ret;
+ }
+
+ debug_rt_mutex_free_waiter(&q.waiter);
+
/* If we were woken (and unqueued), we succeeded, whatever. */
if (!unqueue_me(&q))
return 0;
- if (time == 0)
+ if (rem)
return -ETIMEDOUT;
+
/*
* We expect signal_pending(current), but another thread may
* have handled it for us already.
*/
- return -EINTR;
+ if (!abs_time)
+ return -ERESTARTSYS;
+ else {
+ struct restart_block *restart;
+ restart = &current_thread_info()->restart_block;
+ restart->fn = futex_wait_restart;
+ restart->arg0 = (unsigned long)uaddr;
+ restart->arg1 = (unsigned long)val;
+ restart->arg2 = (unsigned long)abs_time;
+ restart->arg3 = 0;
+ if (fshared)
+ restart->arg3 |= ARG3_SHARED;
+ return -ERESTART_RESTARTBLOCK;
+ }
out_unlock_release_sem:
queue_unlock(&q, hb);
out_release_sem:
- up_read(&curr->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
return ret;
}
+
+static long futex_wait_restart(struct restart_block *restart)
+{
+ u32 __user *uaddr = (u32 __user *)restart->arg0;
+ u32 val = (u32)restart->arg1;
+ ktime_t *abs_time = (ktime_t *)restart->arg2;
+ struct rw_semaphore *fshared = NULL;
+
+ restart->fn = do_no_restart_syscall;
+ if (restart->arg3 & ARG3_SHARED)
+ fshared = &current->mm->mmap_sem;
+ return (long)futex_wait(uaddr, fshared, val, abs_time);
+}
+
+
+static void set_pi_futex_owner(struct futex_hash_bucket *hb,
+ union futex_key *key, struct task_struct *p)
+{
+ struct plist_head *head;
+ struct futex_q *this, *next;
+ struct futex_pi_state *pi_state = NULL;
+ struct rt_mutex *lock;
+
+ /* Search a waiter that should already exists */
+
+ head = &hb->chain;
+
+ plist_for_each_entry_safe(this, next, head, list) {
+ if (match_futex (&this->key, key)) {
+ pi_state = this->pi_state;
+ break;
+ }
+ }
+
+ BUG_ON(!pi_state);
+
+ /* set p as pi_state's owner */
+ lock = &pi_state->pi_mutex;
+
+ spin_lock(&lock->wait_lock);
+ spin_lock_irq(&p->pi_lock);
+
+ list_add(&pi_state->list, &p->pi_state_list);
+ pi_state->owner = p;
+
+
+ /* set p as pi_mutex's owner */
+ debug_rt_mutex_proxy_lock(lock, p);
+ WARN_ON(rt_mutex_owner(lock));
+ rt_mutex_set_owner(lock, p, 0);
+ rt_mutex_deadlock_account_lock(lock, p);
+
+ plist_add(&rt_mutex_top_waiter(lock)->pi_list_entry,
+ &p->pi_waiters);
+ __rt_mutex_adjust_prio(p);
+
+ spin_unlock_irq(&p->pi_lock);
+ spin_unlock(&lock->wait_lock);
+}
+
/*
* Userspace tried a 0 -> TID atomic transition of the futex value
* and failed. The kernel side here does the whole locking operation:
* if there are waiters then it will block, it does PI, etc. (Due to
* races the kernel might see a 0 value of the futex too.)
*/
-static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
- long nsec, int trylock)
+static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
+ int detect, ktime_t *time, int trylock)
{
struct hrtimer_sleeper timeout, *to = NULL;
struct task_struct *curr = current;
struct futex_hash_bucket *hb;
u32 uval, newval, curval;
struct futex_q q;
- int ret, attempt = 0;
+ int ret, lock_held, attempt = 0;
if (refill_pi_state_cache())
return -ENOMEM;
- if (sec != MAX_SCHEDULE_TIMEOUT) {
+ if (time) {
to = &timeout;
hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current);
- to->timer.expires = ktime_set(sec, nsec);
+ to->timer.expires = *time;
}
q.pi_state = NULL;
retry:
- down_read(&curr->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
- ret = get_futex_key(uaddr, &q.key);
+ ret = get_futex_key(uaddr, fshared, &q.key);
if (unlikely(ret != 0))
goto out_release_sem;
hb = queue_lock(&q, -1, NULL);
retry_locked:
+ lock_held = 0;
+
/*
* To avoid races, we attempt to take the lock here again
* (by doing a 0 -> TID atomic cmpxchg), while holding all
@@ -1170,7 +1732,16 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
if (unlikely((curval & FUTEX_TID_MASK) == current->pid)) {
if (!detect && 0)
force_sig(SIGKILL, current);
- ret = -EDEADLK;
+ /*
+ * Normally, this check is done in user space.
+ * In case of requeue, the owner may attempt to lock this futex,
+ * even if the ownership has already been given by the previous
+ * waker.
+ * In the usual case, this is a case of deadlock, but not in case
+ * of REQUEUE_PI.
+ */
+ if (!(curval & FUTEX_WAITER_REQUEUED))
+ ret = -EDEADLK;
goto out_unlock_release_sem;
}
@@ -1182,7 +1753,18 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
goto out_unlock_release_sem;
uval = curval;
- newval = uval | FUTEX_WAITERS;
+ /*
+ * In case of a requeue, check if there already is an owner
+ * If not, just take the futex.
+ */
+ if ((curval & FUTEX_WAITER_REQUEUED) && !(curval & FUTEX_TID_MASK)) {
+ /* set current as futex owner */
+ newval = curval | current->pid;
+ lock_held = 1;
+ } else
+ /* Set the WAITERS flag, so the owner will know it has someone
+ to wake at next unlock */
+ newval = curval | FUTEX_WAITERS;
pagefault_disable();
curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
@@ -1193,11 +1775,16 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
if (unlikely(curval != uval))
goto retry_locked;
+ if (lock_held) {
+ set_pi_futex_owner(hb, &q.key, curr);
+ goto out_unlock_release_sem;
+ }
+
/*
* We dont have the lock. Look up the PI state (or create it if
* we are the first waiter):
*/
- ret = lookup_pi_state(uval, hb, &q);
+ ret = lookup_pi_state(uval, hb, &q.key, &q.pi_state);
if (unlikely(ret)) {
/*
@@ -1239,7 +1826,8 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
* Now the futex is queued and we have checked the data, we
* don't want to hold mmap_sem while we sleep.
*/
- up_read(&curr->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
WARN_ON(!q.pi_state);
/*
@@ -1253,52 +1841,18 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
ret = ret ? 0 : -EWOULDBLOCK;
}
- down_read(&curr->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
spin_lock(q.lock_ptr);
/*
* Got the lock. We might not be the anticipated owner if we
* did a lock-steal - fix up the PI-state in that case.
*/
- if (!ret && q.pi_state->owner != curr) {
- u32 newtid = current->pid | FUTEX_WAITERS;
-
- /* Owner died? */
- if (q.pi_state->owner != NULL) {
- spin_lock_irq(&q.pi_state->owner->pi_lock);
- WARN_ON(list_empty(&q.pi_state->list));
- list_del_init(&q.pi_state->list);
- spin_unlock_irq(&q.pi_state->owner->pi_lock);
- } else
- newtid |= FUTEX_OWNER_DIED;
-
- q.pi_state->owner = current;
-
- spin_lock_irq(&current->pi_lock);
- WARN_ON(!list_empty(&q.pi_state->list));
- list_add(&q.pi_state->list, &current->pi_state_list);
- spin_unlock_irq(&current->pi_lock);
-
- /* Unqueue and drop the lock */
- unqueue_me_pi(&q, hb);
- up_read(&curr->mm->mmap_sem);
- /*
- * We own it, so we have to replace the pending owner
- * TID. This must be atomic as we have preserve the
- * owner died bit here.
- */
- ret = get_user(uval, uaddr);
- while (!ret) {
- newval = (uval & FUTEX_OWNER_DIED) | newtid;
- curval = futex_atomic_cmpxchg_inatomic(uaddr,
- uval, newval);
- if (curval == -EFAULT)
- ret = -EFAULT;
- if (curval == uval)
- break;
- uval = curval;
- }
- } else {
+ if (!ret && q.pi_state->owner != curr)
+ /* mmap_sem is unlocked at return of this function */
+ ret = fixup_pi_state_owner(uaddr, fshared, &q, hb, curr);
+ else {
/*
* Catch the rare case, where the lock was released
* when we were on the way back before we locked
@@ -1309,8 +1863,9 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
ret = 0;
}
/* Unqueue and drop the lock */
- unqueue_me_pi(&q, hb);
- up_read(&curr->mm->mmap_sem);
+ unqueue_me_pi(&q);
+ if (fshared)
+ up_read(fshared);
}
if (!detect && ret == -EDEADLK && 0)
@@ -1322,7 +1877,8 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
queue_unlock(&q, hb);
out_release_sem:
- up_read(&curr->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
return ret;
uaddr_faulted:
@@ -1333,15 +1889,16 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
* still holding the mmap_sem.
*/
if (attempt++) {
- if (futex_handle_fault((unsigned long)uaddr, attempt)) {
- ret = -EFAULT;
+ ret = futex_handle_fault((unsigned long)uaddr, fshared,
+ attempt);
+ if (ret)
goto out_unlock_release_sem;
- }
goto retry_locked;
}
queue_unlock(&q, hb);
- up_read(&curr->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
ret = get_user(uval, uaddr);
if (!ret && (uval != -EFAULT))
@@ -1355,12 +1912,12 @@ static int futex_lock_pi(u32 __user *uaddr, int detect, unsigned long sec,
* This is the in-kernel slowpath: we look up the PI state (if any),
* and do the rt-mutex unlock.
*/
-static int futex_unlock_pi(u32 __user *uaddr)
+static int futex_unlock_pi(u32 __user *uaddr, struct rw_semaphore *fshared)
{
struct futex_hash_bucket *hb;
struct futex_q *this, *next;
u32 uval;
- struct list_head *head;
+ struct plist_head *head;
union futex_key key;
int ret, attempt = 0;
@@ -1375,9 +1932,10 @@ retry:
/*
* First take all the futex related locks:
*/
- down_read(&current->mm->mmap_sem);
+ if (fshared)
+ down_read(fshared);
- ret = get_futex_key(uaddr, &key);
+ ret = get_futex_key(uaddr, fshared, &key);
if (unlikely(ret != 0))
goto out;
@@ -1411,7 +1969,7 @@ retry_locked:
*/
head = &hb->chain;
- list_for_each_entry_safe(this, next, head, list) {
+ plist_for_each_entry_safe(this, next, head, list) {
if (!match_futex (&this->key, &key))
continue;
ret = wake_futex_pi(uaddr, uval, this);
@@ -1436,7 +1994,8 @@ retry_locked:
out_unlock:
spin_unlock(&hb->lock);
out:
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
return ret;
@@ -1448,15 +2007,16 @@ pi_faulted:
* still holding the mmap_sem.
*/
if (attempt++) {
- if (futex_handle_fault((unsigned long)uaddr, attempt)) {
- ret = -EFAULT;
+ ret = futex_handle_fault((unsigned long)uaddr, fshared,
+ attempt);
+ if (ret)
goto out_unlock;
- }
goto retry_locked;
}
spin_unlock(&hb->lock);
- up_read(&current->mm->mmap_sem);
+ if (fshared)
+ up_read(fshared);
ret = get_user(uval, uaddr);
if (!ret && (uval != -EFAULT))
@@ -1485,10 +2045,10 @@ static unsigned int futex_poll(struct file *filp,
poll_wait(filp, &q->waiters, wait);
/*
- * list_empty() is safe here without any lock.
+ * plist_node_empty() is safe here without any lock.
* q->lock_ptr != 0 is not safe, because of ordering against wakeup.
*/
- if (list_empty(&q->list))
+ if (plist_node_empty(&q->list))
ret = POLLIN | POLLRDNORM;
return ret;
@@ -1508,6 +2068,7 @@ static int futex_fd(u32 __user *uaddr, int signal)
struct futex_q *q;
struct file *filp;
int ret, err;
+ struct rw_semaphore *fshared;
static unsigned long printk_interval;
if (printk_timed_ratelimit(&printk_interval, 60 * 60 * 1000)) {
@@ -1549,11 +2110,12 @@ static int futex_fd(u32 __user *uaddr, int signal)
}
q->pi_state = NULL;
- down_read(&current->mm->mmap_sem);
- err = get_futex_key(uaddr, &q->key);
+ fshared = &current->mm->mmap_sem;
+ down_read(fshared);
+ err = get_futex_key(uaddr, fshared, &q->key);
if (unlikely(err != 0)) {
- up_read(&current->mm->mmap_sem);
+ up_read(fshared);
kfree(q);
goto error;
}
@@ -1565,7 +2127,7 @@ static int futex_fd(u32 __user *uaddr, int signal)
filp->private_data = q;
queue_me(q, ret, filp);
- up_read(&current->mm->mmap_sem);
+ up_read(fshared);
/* Now we map fd to filp, so userspace can access it */
fd_install(ret, filp);
@@ -1678,6 +2240,8 @@ retry:
* userspace.
*/
mval = (uval & FUTEX_WAITERS) | FUTEX_OWNER_DIED;
+ /* Also keep the FUTEX_WAITER_REQUEUED flag if set */
+ mval |= (uval & FUTEX_WAITER_REQUEUED);
nval = futex_atomic_cmpxchg_inatomic(uaddr, uval, mval);
if (nval == -EFAULT)
@@ -1692,7 +2256,7 @@ retry:
*/
if (!pi) {
if (uval & FUTEX_WAITERS)
- futex_wake(uaddr, 1);
+ futex_wake(uaddr, &curr->mm->mmap_sem, 1);
}
}
return 0;
@@ -1748,7 +2312,8 @@ void exit_robust_list(struct task_struct *curr)
return;
if (pending)
- handle_futex_death((void __user *)pending + futex_offset, curr, pip);
+ handle_futex_death((void __user *)pending + futex_offset,
+ curr, pip);
while (entry != &head->list) {
/*
@@ -1774,39 +2339,47 @@ void exit_robust_list(struct task_struct *curr)
}
}
-long do_futex(u32 __user *uaddr, int op, u32 val, unsigned long timeout,
+long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
u32 __user *uaddr2, u32 val2, u32 val3)
{
int ret;
+ int cmd = op & FUTEX_CMD_MASK;
+ struct rw_semaphore *fshared = NULL;
- switch (op) {
+ if (!(op & FUTEX_PRIVATE_FLAG))
+ fshared = &current->mm->mmap_sem;
+
+ switch (cmd) {
case FUTEX_WAIT:
- ret = futex_wait(uaddr, val, timeout);
+ ret = futex_wait(uaddr, fshared, val, timeout);
break;
case FUTEX_WAKE:
- ret = futex_wake(uaddr, val);
+ ret = futex_wake(uaddr, fshared, val);
break;
case FUTEX_FD:
/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
ret = futex_fd(uaddr, val);
break;
case FUTEX_REQUEUE:
- ret = futex_requeue(uaddr, uaddr2, val, val2, NULL);
+ ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, NULL);
break;
case FUTEX_CMP_REQUEUE:
- ret = futex_requeue(uaddr, uaddr2, val, val2, &val3);
+ ret = futex_requeue(uaddr, fshared, uaddr2, val, val2, &val3);
break;
case FUTEX_WAKE_OP:
- ret = futex_wake_op(uaddr, uaddr2, val, val2, val3);
+ ret = futex_wake_op(uaddr, fshared, uaddr2, val, val2, val3);
break;
case FUTEX_LOCK_PI:
- ret = futex_lock_pi(uaddr, val, timeout, val2, 0);
+ ret = futex_lock_pi(uaddr, fshared, val, timeout, 0);
break;
case FUTEX_UNLOCK_PI:
- ret = futex_unlock_pi(uaddr);
+ ret = futex_unlock_pi(uaddr, fshared);
break;
case FUTEX_TRYLOCK_PI:
- ret = futex_lock_pi(uaddr, 0, timeout, val2, 1);
+ ret = futex_lock_pi(uaddr, fshared, 0, timeout, 1);
+ break;
+ case FUTEX_CMP_REQUEUE_PI:
+ ret = futex_requeue_pi(uaddr, fshared, uaddr2, val, val2, &val3);
break;
default:
ret = -ENOSYS;
@@ -1819,29 +2392,30 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
struct timespec __user *utime, u32 __user *uaddr2,
u32 val3)
{
- struct timespec t;
- unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+ struct timespec ts;
+ ktime_t t, *tp = NULL;
u32 val2 = 0;
+ int cmd = op & FUTEX_CMD_MASK;
- if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
- if (copy_from_user(&t, utime, sizeof(t)) != 0)
+ if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+ if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
return -EFAULT;
- if (!timespec_valid(&t))
+ if (!timespec_valid(&ts))
return -EINVAL;
- if (op == FUTEX_WAIT)
- timeout = timespec_to_jiffies(&t) + 1;
- else {
- timeout = t.tv_sec;
- val2 = t.tv_nsec;
- }
+
+ t = timespec_to_ktime(ts);
+ if (cmd == FUTEX_WAIT)
+ t = ktime_add(ktime_get(), t);
+ tp = &t;
}
/*
- * requeue parameter in 'utime' if op == FUTEX_REQUEUE.
+ * requeue parameter in 'utime' if cmd == FUTEX_REQUEUE.
*/
- if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+ if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE
+ || cmd == FUTEX_CMP_REQUEUE_PI)
val2 = (u32) (unsigned long) utime;
- return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
+ return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
static int futexfs_get_sb(struct file_system_type *fs_type,
@@ -1871,7 +2445,7 @@ static int __init init(void)
}
for (i = 0; i < ARRAY_SIZE(futex_queues); i++) {
- INIT_LIST_HEAD(&futex_queues[i].chain);
+ plist_head_init(&futex_queues[i].chain, &futex_queues[i].lock);
spin_lock_init(&futex_queues[i].lock);
}
return 0;
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 50f24eea6cd..338a9b489fb 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -141,24 +141,24 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
struct compat_timespec __user *utime, u32 __user *uaddr2,
u32 val3)
{
- struct timespec t;
- unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+ struct timespec ts;
+ ktime_t t, *tp = NULL;
int val2 = 0;
if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
- if (get_compat_timespec(&t, utime))
+ if (get_compat_timespec(&ts, utime))
return -EFAULT;
- if (!timespec_valid(&t))
+ if (!timespec_valid(&ts))
return -EINVAL;
+
+ t = timespec_to_ktime(ts);
if (op == FUTEX_WAIT)
- timeout = timespec_to_jiffies(&t) + 1;
- else {
- timeout = t.tv_sec;
- val2 = t.tv_nsec;
- }
+ t = ktime_add(ktime_get(), t);
+ tp = &t;
}
- if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
+ if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE
+ || op == FUTEX_CMP_REQUEUE_PI)
val2 = (int) (unsigned long) utime;
- return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
+ return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index f5cfde8c902..23c03f43e19 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -279,6 +279,8 @@ ktime_t ktime_add_ns(const ktime_t kt, u64 nsec)
return ktime_add(kt, tmp);
}
+
+EXPORT_SYMBOL_GPL(ktime_add_ns);
# endif /* !CONFIG_KTIME_SCALAR */
/*
@@ -667,6 +669,7 @@ hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval)
return orun;
}
+EXPORT_SYMBOL_GPL(hrtimer_forward);
/*
* enqueue_hrtimer - internal function to (re)start a timer
@@ -1408,11 +1411,13 @@ static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
init_hrtimers_cpu(cpu);
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &cpu);
migrate_hrtimers(cpu);
break;
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 0133f4f9e9f..615ce97c6cf 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -11,6 +11,7 @@
*/
#include <linux/irq.h>
+#include <linux/msi.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
@@ -185,6 +186,8 @@ int set_irq_msi(unsigned int irq, struct msi_desc *entry)
desc = irq_desc + irq;
spin_lock_irqsave(&desc->lock, flags);
desc->msi_desc = entry;
+ if (entry)
+ entry->irq = irq;
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
}
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index aff1f0fabb0..e391cbb1f56 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -22,7 +22,6 @@
* handle_bad_irq - handle spurious and unhandled irqs
* @irq: the interrupt number
* @desc: description of the interrupt
- * @regs: pointer to a register structure
*
* Handles spurious and unhandled IRQ's. It also prints a debugmessage.
*/
@@ -48,7 +47,7 @@ handle_bad_irq(unsigned int irq, struct irq_desc *desc)
*
* Controller mappings for all interrupt sources:
*/
-struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned = {
+struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
@@ -180,6 +179,8 @@ fastcall unsigned int __do_IRQ(unsigned int irq)
if (desc->chip->ack)
desc->chip->ack(irq);
action_ret = handle_IRQ_event(irq, desc->action);
+ if (!noirqdebug)
+ note_interrupt(irq, desc, action_ret);
desc->chip->end(irq);
return 1;
}
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 5597c157442..203a518b6f1 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -317,10 +317,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
}
*p = new;
-#if defined(CONFIG_IRQ_PER_CPU)
- if (new->flags & IRQF_PERCPU)
- desc->status |= IRQ_PER_CPU;
-#endif
+
/* Exclude IRQ from balancing */
if (new->flags & IRQF_NOBALANCING)
desc->status |= IRQ_NO_BALANCING;
@@ -328,6 +325,11 @@ int setup_irq(unsigned int irq, struct irqaction *new)
if (!shared) {
irq_chip_set_defaults(desc->chip);
+#if defined(CONFIG_IRQ_PER_CPU)
+ if (new->flags & IRQF_PERCPU)
+ desc->status |= IRQ_PER_CPU;
+#endif
+
/* Setup the type (level, edge polarity) if configured: */
if (new->flags & IRQF_TRIGGER_MASK) {
if (desc->chip && desc->chip->set_type)
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 2db91eb54ad..ddde0ef9ccd 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -66,12 +66,19 @@ static int name_unique(unsigned int irq, struct irqaction *new_action)
{
struct irq_desc *desc = irq_desc + irq;
struct irqaction *action;
+ unsigned long flags;
+ int ret = 1;
- for (action = desc->action ; action; action = action->next)
+ spin_lock_irqsave(&desc->lock, flags);
+ for (action = desc->action ; action; action = action->next) {
if ((action != new_action) && action->name &&
- !strcmp(new_action->name, action->name))
- return 0;
- return 1;
+ !strcmp(new_action->name, action->name)) {
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return ret;
}
void register_handler_proc(unsigned int irq, struct irqaction *action)
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 9d8c79b4882..b0d81aae472 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -146,7 +146,9 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
if (unlikely(irqfixup)) {
/* Don't punish working computers */
- if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
+ if ((irqfixup == 2 && ((irq == 0) ||
+ (desc->action->flags & IRQF_IRQPOLL))) ||
+ action_ret == IRQ_NONE) {
int ok = misrouted_irq(irq);
if (action_ret == IRQ_NONE)
desc->irqs_unhandled -= ok;
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 307c6a632ef..3205e8e114f 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -7,7 +7,6 @@
/* These are all the functions necessary to implement itimers */
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/syscalls.h>
#include <linux/time.h>
@@ -139,59 +138,11 @@ enum hrtimer_restart it_real_fn(struct hrtimer *timer)
}
/*
- * We do not care about correctness. We just sanitize the values so
- * the ktime_t operations which expect normalized values do not
- * break. This converts negative values to long timeouts similar to
- * the code in kernel versions < 2.6.16
- *
- * Print a limited number of warning messages when an invalid timeval
- * is detected.
- */
-static void fixup_timeval(struct timeval *tv, int interval)
-{
- static int warnlimit = 10;
- unsigned long tmp;
-
- if (warnlimit > 0) {
- warnlimit--;
- printk(KERN_WARNING
- "setitimer: %s (pid = %d) provided "
- "invalid timeval %s: tv_sec = %ld tv_usec = %ld\n",
- current->comm, current->pid,
- interval ? "it_interval" : "it_value",
- tv->tv_sec, (long) tv->tv_usec);
- }
-
- tmp = tv->tv_usec;
- if (tmp >= USEC_PER_SEC) {
- tv->tv_usec = tmp % USEC_PER_SEC;
- tv->tv_sec += tmp / USEC_PER_SEC;
- }
-
- tmp = tv->tv_sec;
- if (tmp > LONG_MAX)
- tv->tv_sec = LONG_MAX;
-}
-
-/*
* Returns true if the timeval is in canonical form
*/
#define timeval_valid(t) \
(((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
-/*
- * Check for invalid timevals, sanitize them and print a limited
- * number of warnings.
- */
-static void check_itimerval(struct itimerval *value) {
-
- if (unlikely(!timeval_valid(&value->it_value)))
- fixup_timeval(&value->it_value, 0);
-
- if (unlikely(!timeval_valid(&value->it_interval)))
- fixup_timeval(&value->it_interval, 1);
-}
-
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
struct task_struct *tsk = current;
@@ -201,15 +152,10 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
/*
* Validate the timevals in value.
- *
- * Note: Although the spec requires that invalid values shall
- * return -EINVAL, we just fixup the value and print a limited
- * number of warnings in order not to break users of this
- * historical misfeature.
- *
- * Scheduled for replacement in March 2007
*/
- check_itimerval(value);
+ if (!timeval_valid(&value->it_value) ||
+ !timeval_valid(&value->it_interval))
+ return -EINVAL;
switch (which) {
case ITIMER_REAL:
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 6f294ff4f9e..f1bda23140b 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -214,8 +214,10 @@ static unsigned long get_symbol_pos(unsigned long addr,
symbol_end = (unsigned long)_etext;
}
- *symbolsize = symbol_end - symbol_start;
- *offset = addr - symbol_start;
+ if (symbolsize)
+ *symbolsize = symbol_end - symbol_start;
+ if (offset)
+ *offset = addr - symbol_start;
return low;
}
@@ -267,27 +269,69 @@ const char *kallsyms_lookup(unsigned long addr,
return NULL;
}
-/* Replace "%s" in format with address, or returns -errno. */
-void __print_symbol(const char *fmt, unsigned long address)
+int lookup_symbol_name(unsigned long addr, char *symname)
+{
+ symname[0] = '\0';
+ symname[KSYM_NAME_LEN] = '\0';
+
+ if (is_ksym_addr(addr)) {
+ unsigned long pos;
+
+ pos = get_symbol_pos(addr, NULL, NULL);
+ /* Grab name */
+ kallsyms_expand_symbol(get_symbol_offset(pos), symname);
+ return 0;
+ }
+ /* see if it's in a module */
+ return lookup_module_symbol_name(addr, symname);
+}
+
+int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
+ unsigned long *offset, char *modname, char *name)
+{
+ name[0] = '\0';
+ name[KSYM_NAME_LEN] = '\0';
+
+ if (is_ksym_addr(addr)) {
+ unsigned long pos;
+
+ pos = get_symbol_pos(addr, size, offset);
+ /* Grab name */
+ kallsyms_expand_symbol(get_symbol_offset(pos), name);
+ modname[0] = '\0';
+ return 0;
+ }
+ /* see if it's in a module */
+ return lookup_module_symbol_attrs(addr, size, offset, modname, name);
+}
+
+/* Look up a kernel symbol and return it in a text buffer. */
+int sprint_symbol(char *buffer, unsigned long address)
{
char *modname;
const char *name;
unsigned long offset, size;
char namebuf[KSYM_NAME_LEN+1];
- char buffer[sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN +
- 2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1];
name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
-
if (!name)
- sprintf(buffer, "0x%lx", address);
+ return sprintf(buffer, "0x%lx", address);
else {
if (modname)
- sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
+ return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
size, modname);
else
- sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+ return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
}
+}
+
+/* Look up a kernel symbol and print it to the kernel messages. */
+void __print_symbol(const char *fmt, unsigned long address)
+{
+ char buffer[KSYM_SYMBOL_LEN];
+
+ sprint_symbol(buffer, address);
+
printk(fmt, buffer);
}
@@ -295,25 +339,20 @@ void __print_symbol(const char *fmt, unsigned long address)
struct kallsym_iter
{
loff_t pos;
- struct module *owner;
unsigned long value;
unsigned int nameoff; /* If iterating in core kernel symbols */
char type;
char name[KSYM_NAME_LEN+1];
+ char module_name[MODULE_NAME_LEN + 1];
+ int exported;
};
static int get_ksymbol_mod(struct kallsym_iter *iter)
{
- iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms,
- &iter->value, &iter->type,
- iter->name, sizeof(iter->name));
- if (iter->owner == NULL)
+ if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value,
+ &iter->type, iter->name, iter->module_name,
+ &iter->exported) < 0)
return 0;
-
- /* Label it "global" if it is exported, "local" if not exported. */
- iter->type = is_exported(iter->name, iter->owner)
- ? toupper(iter->type) : tolower(iter->type);
-
return 1;
}
@@ -322,7 +361,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
{
unsigned off = iter->nameoff;
- iter->owner = NULL;
+ iter->module_name[0] = '\0';
iter->value = kallsyms_addresses[iter->pos];
iter->type = kallsyms_get_symbol_type(off);
@@ -386,12 +425,17 @@ static int s_show(struct seq_file *m, void *p)
if (!iter->name[0])
return 0;
- if (iter->owner)
+ if (iter->module_name[0]) {
+ char type;
+
+ /* Label it "global" if it is exported,
+ * "local" if not exported. */
+ type = iter->exported ? toupper(iter->type) :
+ tolower(iter->type);
seq_printf(m, "%0*lx %c %s\t[%s]\n",
(int)(2*sizeof(void*)),
- iter->value, iter->type, iter->name,
- module_name(iter->owner));
- else
+ iter->value, type, iter->name, iter->module_name);
+ } else
seq_printf(m, "%0*lx %c %s\n",
(int)(2*sizeof(void*)),
iter->value, iter->type, iter->name);
@@ -426,18 +470,11 @@ static int kallsyms_open(struct inode *inode, struct file *file)
return ret;
}
-static int kallsyms_release(struct inode *inode, struct file *file)
-{
- struct seq_file *m = (struct seq_file *)file->private_data;
- kfree(m->private);
- return seq_release(inode, file);
-}
-
static const struct file_operations kallsyms_operations = {
.open = kallsyms_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = kallsyms_release,
+ .release = seq_release_private,
};
static int __init kallsyms_init(void)
@@ -452,3 +489,4 @@ static int __init kallsyms_init(void)
__initcall(kallsyms_init);
EXPORT_SYMBOL(__print_symbol);
+EXPORT_SYMBOL_GPL(sprint_symbol);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 2a59c8a01ae..25db14b89e8 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1118,8 +1118,8 @@ void crash_save_cpu(struct pt_regs *regs, int cpu)
memset(&prstatus, 0, sizeof(prstatus));
prstatus.pr_pid = current->pid;
elf_core_copy_regs(&prstatus.pr_reg, regs);
- buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
- sizeof(prstatus));
+ buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS,
+ &prstatus, sizeof(prstatus));
final_note(buf);
}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 796276141e5..4d32eb07717 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -23,7 +23,6 @@
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/kmod.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/mnt_namespace.h>
#include <linux/completion.h>
@@ -136,7 +135,6 @@ static int ____call_usermodehelper(void *data)
/* Unblock all signals and set the session keyring. */
new_session = key_get(sub_info->ring);
- flush_signals(current);
spin_lock_irq(&current->sighand->siglock);
old_session = __install_session_keyring(current, new_session);
flush_signal_handlers(current, 1);
@@ -166,6 +164,12 @@ static int ____call_usermodehelper(void *data)
/* We can run anywhere, unlike our parent keventd(). */
set_cpus_allowed(current, CPU_MASK_ALL);
+ /*
+ * Our parent is keventd, which runs with elevated scheduling priority.
+ * Avoid propagating that into the userspace child.
+ */
+ set_user_nice(current, 0);
+
retval = -EPERM;
if (current->fs->root)
retval = kernel_execve(sub_info->path,
@@ -181,14 +185,9 @@ static int wait_for_helper(void *data)
{
struct subprocess_info *sub_info = data;
pid_t pid;
- struct k_sigaction sa;
/* Install a handler: if SIGCLD isn't handled sys_wait4 won't
* populate the status, but will return -ECHILD. */
- sa.sa.sa_handler = SIG_IGN;
- sa.sa.sa_flags = 0;
- siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
- do_sigaction(SIGCHLD, &sa, NULL);
allow_signal(SIGCHLD);
pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index d25a9ada3f8..9e47d8c493f 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -35,16 +35,19 @@
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/moduleloader.h>
#include <linux/kallsyms.h>
#include <linux/freezer.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <linux/kdebug.h>
+
#include <asm-generic/sections.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
-#include <asm/kdebug.h>
+#include <asm/uaccess.h>
#define KPROBE_HASH_BITS 6
#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
@@ -63,6 +66,9 @@ static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
static atomic_t kprobe_count;
+/* NOTE: change this value only with kprobe_mutex held */
+static bool kprobe_enabled;
+
DEFINE_MUTEX(kprobe_mutex); /* Protects kprobe_table */
DEFINE_SPINLOCK(kretprobe_lock); /* Protects kretprobe_inst_table */
static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
@@ -132,9 +138,8 @@ kprobe_opcode_t __kprobes *get_insn_slot(void)
struct kprobe_insn_page *kip;
struct hlist_node *pos;
- retry:
- hlist_for_each(pos, &kprobe_insn_pages) {
- kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+ retry:
+ hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
if (kip->nused < INSNS_PER_PAGE) {
int i;
for (i = 0; i < INSNS_PER_PAGE; i++) {
@@ -155,9 +160,8 @@ kprobe_opcode_t __kprobes *get_insn_slot(void)
}
/* All out of space. Need to allocate a new page. Use slot 0. */
kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
- if (!kip) {
+ if (!kip)
return NULL;
- }
/*
* Use module_alloc so this page is within +/- 2GB of where the
@@ -213,9 +217,8 @@ static int __kprobes collect_garbage_slots(void)
if (check_safety() != 0)
return -EAGAIN;
- hlist_for_each_safe(pos, next, &kprobe_insn_pages) {
+ hlist_for_each_entry_safe(kip, pos, next, &kprobe_insn_pages, hlist) {
int i;
- kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
if (kip->ngarbage == 0)
continue;
kip->ngarbage = 0; /* we will collect all garbages */
@@ -234,8 +237,7 @@ void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
struct kprobe_insn_page *kip;
struct hlist_node *pos;
- hlist_for_each(pos, &kprobe_insn_pages) {
- kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+ hlist_for_each_entry(kip, pos, &kprobe_insn_pages, hlist) {
if (kip->insns <= slot &&
slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
int i = (slot - kip->insns) / MAX_INSN_SIZE;
@@ -248,9 +250,9 @@ void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
break;
}
}
- if (dirty && (++kprobe_garbage_slots > INSNS_PER_PAGE)) {
+
+ if (dirty && ++kprobe_garbage_slots > INSNS_PER_PAGE)
collect_garbage_slots();
- }
}
#endif
@@ -316,7 +318,6 @@ static void __kprobes aggr_post_handler(struct kprobe *p, struct pt_regs *regs,
reset_kprobe_instance();
}
}
- return;
}
static int __kprobes aggr_fault_handler(struct kprobe *p, struct pt_regs *regs,
@@ -362,46 +363,6 @@ void __kprobes kprobes_inc_nmissed_count(struct kprobe *p)
}
/* Called with kretprobe_lock held */
-struct kretprobe_instance __kprobes *get_free_rp_inst(struct kretprobe *rp)
-{
- struct hlist_node *node;
- struct kretprobe_instance *ri;
- hlist_for_each_entry(ri, node, &rp->free_instances, uflist)
- return ri;
- return NULL;
-}
-
-/* Called with kretprobe_lock held */
-static struct kretprobe_instance __kprobes *get_used_rp_inst(struct kretprobe
- *rp)
-{
- struct hlist_node *node;
- struct kretprobe_instance *ri;
- hlist_for_each_entry(ri, node, &rp->used_instances, uflist)
- return ri;
- return NULL;
-}
-
-/* Called with kretprobe_lock held */
-void __kprobes add_rp_inst(struct kretprobe_instance *ri)
-{
- /*
- * Remove rp inst off the free list -
- * Add it back when probed function returns
- */
- hlist_del(&ri->uflist);
-
- /* Add rp inst onto table */
- INIT_HLIST_NODE(&ri->hlist);
- hlist_add_head(&ri->hlist,
- &kretprobe_inst_table[hash_ptr(ri->task, KPROBE_HASH_BITS)]);
-
- /* Also add this rp inst to the used list. */
- INIT_HLIST_NODE(&ri->uflist);
- hlist_add_head(&ri->uflist, &ri->rp->used_instances);
-}
-
-/* Called with kretprobe_lock held */
void __kprobes recycle_rp_inst(struct kretprobe_instance *ri,
struct hlist_head *head)
{
@@ -454,7 +415,9 @@ void __kprobes kprobe_flush_task(struct task_struct *tk)
static inline void free_rp_inst(struct kretprobe *rp)
{
struct kretprobe_instance *ri;
- while ((ri = get_free_rp_inst(rp)) != NULL) {
+ struct hlist_node *pos, *next;
+
+ hlist_for_each_entry_safe(ri, pos, next, &rp->free_instances, uflist) {
hlist_del(&ri->uflist);
kfree(ri);
}
@@ -535,8 +498,8 @@ static int __kprobes register_aggr_kprobe(struct kprobe *old_p,
static int __kprobes in_kprobes_functions(unsigned long addr)
{
- if (addr >= (unsigned long)__kprobes_text_start
- && addr < (unsigned long)__kprobes_text_end)
+ if (addr >= (unsigned long)__kprobes_text_start &&
+ addr < (unsigned long)__kprobes_text_end)
return -EINVAL;
return 0;
}
@@ -563,19 +526,24 @@ static int __kprobes __register_kprobe(struct kprobe *p,
return -EINVAL;
p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset);
- if ((!kernel_text_address((unsigned long) p->addr)) ||
- in_kprobes_functions((unsigned long) p->addr))
+ if (!kernel_text_address((unsigned long) p->addr) ||
+ in_kprobes_functions((unsigned long) p->addr))
return -EINVAL;
p->mod_refcounted = 0;
- /* Check are we probing a module */
- if ((probed_mod = module_text_address((unsigned long) p->addr))) {
+
+ /*
+ * Check if are we probing a module.
+ */
+ probed_mod = module_text_address((unsigned long) p->addr);
+ if (probed_mod) {
struct module *calling_mod = module_text_address(called_from);
- /* We must allow modules to probe themself and
- * in this case avoid incrementing the module refcount,
- * so as to allow unloading of self probing modules.
+ /*
+ * We must allow modules to probe themself and in this case
+ * avoid incrementing the module refcount, so as to allow
+ * unloading of self probing modules.
*/
- if (calling_mod && (calling_mod != probed_mod)) {
+ if (calling_mod && calling_mod != probed_mod) {
if (unlikely(!try_module_get(probed_mod)))
return -EINVAL;
p->mod_refcounted = 1;
@@ -593,19 +561,21 @@ static int __kprobes __register_kprobe(struct kprobe *p,
goto out;
}
- if ((ret = arch_prepare_kprobe(p)) != 0)
+ ret = arch_prepare_kprobe(p);
+ if (ret)
goto out;
INIT_HLIST_NODE(&p->hlist);
hlist_add_head_rcu(&p->hlist,
&kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
- if (atomic_add_return(1, &kprobe_count) == \
+ if (kprobe_enabled) {
+ if (atomic_add_return(1, &kprobe_count) == \
(ARCH_INACTIVE_KPROBE_COUNT + 1))
- register_page_fault_notifier(&kprobe_page_fault_nb);
-
- arch_arm_kprobe(p);
+ register_page_fault_notifier(&kprobe_page_fault_nb);
+ arch_arm_kprobe(p);
+ }
out:
mutex_unlock(&kprobe_mutex);
@@ -616,8 +586,7 @@ out:
int __kprobes register_kprobe(struct kprobe *p)
{
- return __register_kprobe(p,
- (unsigned long)__builtin_return_address(0));
+ return __register_kprobe(p, (unsigned long)__builtin_return_address(0));
}
void __kprobes unregister_kprobe(struct kprobe *p)
@@ -641,11 +610,16 @@ void __kprobes unregister_kprobe(struct kprobe *p)
return;
}
valid_p:
- if ((old_p == p) || ((old_p->pre_handler == aggr_pre_handler) &&
- (p->list.next == &old_p->list) &&
- (p->list.prev == &old_p->list))) {
- /* Only probe on the hash list */
- arch_disarm_kprobe(p);
+ if (old_p == p ||
+ (old_p->pre_handler == aggr_pre_handler &&
+ p->list.next == &old_p->list && p->list.prev == &old_p->list)) {
+ /*
+ * Only probe on the hash list. Disarm only if kprobes are
+ * enabled - otherwise, the breakpoint would already have
+ * been removed. We save on flushing icache.
+ */
+ if (kprobe_enabled)
+ arch_disarm_kprobe(p);
hlist_del_rcu(&old_p->hlist);
cleanup_p = 1;
} else {
@@ -656,9 +630,11 @@ valid_p:
mutex_unlock(&kprobe_mutex);
synchronize_sched();
- if (p->mod_refcounted &&
- (mod = module_text_address((unsigned long)p->addr)))
- module_put(mod);
+ if (p->mod_refcounted) {
+ mod = module_text_address((unsigned long)p->addr);
+ if (mod)
+ module_put(mod);
+ }
if (cleanup_p) {
if (p != old_p) {
@@ -729,7 +705,21 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p,
/*TODO: consider to only swap the RA after the last pre_handler fired */
spin_lock_irqsave(&kretprobe_lock, flags);
- arch_prepare_kretprobe(rp, regs);
+ if (!hlist_empty(&rp->free_instances)) {
+ struct kretprobe_instance *ri;
+
+ ri = hlist_entry(rp->free_instances.first,
+ struct kretprobe_instance, uflist);
+ ri->rp = rp;
+ ri->task = current;
+ arch_prepare_kretprobe(ri, regs);
+
+ /* XXX(hch): why is there no hlist_move_head? */
+ hlist_del(&ri->uflist);
+ hlist_add_head(&ri->uflist, &ri->rp->used_instances);
+ hlist_add_head(&ri->hlist, kretprobe_inst_table_head(ri->task));
+ } else
+ rp->nmissed++;
spin_unlock_irqrestore(&kretprobe_lock, flags);
return 0;
}
@@ -792,11 +782,13 @@ void __kprobes unregister_kretprobe(struct kretprobe *rp)
{
unsigned long flags;
struct kretprobe_instance *ri;
+ struct hlist_node *pos, *next;
unregister_kprobe(&rp->kp);
+
/* No race here */
spin_lock_irqsave(&kretprobe_lock, flags);
- while ((ri = get_used_rp_inst(rp)) != NULL) {
+ hlist_for_each_entry_safe(ri, pos, next, &rp->used_instances, uflist) {
ri->rp = NULL;
hlist_del(&ri->uflist);
}
@@ -816,6 +808,9 @@ static int __init init_kprobes(void)
}
atomic_set(&kprobe_count, 0);
+ /* By default, kprobes are enabled */
+ kprobe_enabled = true;
+
err = arch_init_kprobes();
if (!err)
err = register_die_notifier(&kprobe_exceptions_nb);
@@ -825,7 +820,7 @@ static int __init init_kprobes(void)
#ifdef CONFIG_DEBUG_FS
static void __kprobes report_probe(struct seq_file *pi, struct kprobe *p,
- const char *sym, int offset,char *modname)
+ const char *sym, int offset,char *modname)
{
char *kprobe_type;
@@ -867,13 +862,13 @@ static int __kprobes show_kprobe_addr(struct seq_file *pi, void *v)
struct kprobe *p, *kp;
const char *sym = NULL;
unsigned int i = *(loff_t *) v;
- unsigned long size, offset = 0;
+ unsigned long offset = 0;
char *modname, namebuf[128];
head = &kprobe_table[i];
preempt_disable();
hlist_for_each_entry_rcu(p, node, head, hlist) {
- sym = kallsyms_lookup((unsigned long)p->addr, &size,
+ sym = kallsyms_lookup((unsigned long)p->addr, NULL,
&offset, &modname, namebuf);
if (p->pre_handler == aggr_pre_handler) {
list_for_each_entry_rcu(kp, &p->list, list)
@@ -904,21 +899,149 @@ static struct file_operations debugfs_kprobes_operations = {
.release = seq_release,
};
+static void __kprobes enable_all_kprobes(void)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct kprobe *p;
+ unsigned int i;
+
+ mutex_lock(&kprobe_mutex);
+
+ /* If kprobes are already enabled, just return */
+ if (kprobe_enabled)
+ goto already_enabled;
+
+ /*
+ * Re-register the page fault notifier only if there are any
+ * active probes at the time of enabling kprobes globally
+ */
+ if (atomic_read(&kprobe_count) > ARCH_INACTIVE_KPROBE_COUNT)
+ register_page_fault_notifier(&kprobe_page_fault_nb);
+
+ for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
+ head = &kprobe_table[i];
+ hlist_for_each_entry_rcu(p, node, head, hlist)
+ arch_arm_kprobe(p);
+ }
+
+ kprobe_enabled = true;
+ printk(KERN_INFO "Kprobes globally enabled\n");
+
+already_enabled:
+ mutex_unlock(&kprobe_mutex);
+ return;
+}
+
+static void __kprobes disable_all_kprobes(void)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct kprobe *p;
+ unsigned int i;
+
+ mutex_lock(&kprobe_mutex);
+
+ /* If kprobes are already disabled, just return */
+ if (!kprobe_enabled)
+ goto already_disabled;
+
+ kprobe_enabled = false;
+ printk(KERN_INFO "Kprobes globally disabled\n");
+ for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
+ head = &kprobe_table[i];
+ hlist_for_each_entry_rcu(p, node, head, hlist) {
+ if (!arch_trampoline_kprobe(p))
+ arch_disarm_kprobe(p);
+ }
+ }
+
+ mutex_unlock(&kprobe_mutex);
+ /* Allow all currently running kprobes to complete */
+ synchronize_sched();
+
+ mutex_lock(&kprobe_mutex);
+ /* Unconditionally unregister the page_fault notifier */
+ unregister_page_fault_notifier(&kprobe_page_fault_nb);
+
+already_disabled:
+ mutex_unlock(&kprobe_mutex);
+ return;
+}
+
+/*
+ * XXX: The debugfs bool file interface doesn't allow for callbacks
+ * when the bool state is switched. We can reuse that facility when
+ * available
+ */
+static ssize_t read_enabled_file_bool(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[3];
+
+ if (kprobe_enabled)
+ buf[0] = '1';
+ else
+ buf[0] = '0';
+ buf[1] = '\n';
+ buf[2] = 0x00;
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_enabled_file_bool(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buf[32];
+ int buf_size;
+
+ buf_size = min(count, (sizeof(buf)-1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ switch (buf[0]) {
+ case 'y':
+ case 'Y':
+ case '1':
+ enable_all_kprobes();
+ break;
+ case 'n':
+ case 'N':
+ case '0':
+ disable_all_kprobes();
+ break;
+ }
+
+ return count;
+}
+
+static struct file_operations fops_kp = {
+ .read = read_enabled_file_bool,
+ .write = write_enabled_file_bool,
+};
+
static int __kprobes debugfs_kprobe_init(void)
{
struct dentry *dir, *file;
+ unsigned int value = 1;
dir = debugfs_create_dir("kprobes", NULL);
if (!dir)
return -ENOMEM;
- file = debugfs_create_file("list", 0444, dir , 0 ,
+ file = debugfs_create_file("list", 0444, dir, NULL,
&debugfs_kprobes_operations);
if (!file) {
debugfs_remove(dir);
return -ENOMEM;
}
+ file = debugfs_create_file("enabled", 0600, dir,
+ &value, &fops_kp);
+ if (!file) {
+ debugfs_remove(dir);
+ return -ENOMEM;
+ }
+
return 0;
}
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index e0ffe4ab091..559deca5ed1 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -24,18 +24,18 @@ static struct subsys_attribute _name##_attr = \
#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
/* current uevent sequence number */
-static ssize_t uevent_seqnum_show(struct subsystem *subsys, char *page)
+static ssize_t uevent_seqnum_show(struct kset *kset, char *page)
{
return sprintf(page, "%llu\n", (unsigned long long)uevent_seqnum);
}
KERNEL_ATTR_RO(uevent_seqnum);
/* uevent helper program, used during early boo */
-static ssize_t uevent_helper_show(struct subsystem *subsys, char *page)
+static ssize_t uevent_helper_show(struct kset *kset, char *page)
{
return sprintf(page, "%s\n", uevent_helper);
}
-static ssize_t uevent_helper_store(struct subsystem *subsys, const char *page, size_t count)
+static ssize_t uevent_helper_store(struct kset *kset, const char *page, size_t count)
{
if (count+1 > UEVENT_HELPER_PATH_LEN)
return -ENOENT;
@@ -49,13 +49,13 @@ KERNEL_ATTR_RW(uevent_helper);
#endif
#ifdef CONFIG_KEXEC
-static ssize_t kexec_loaded_show(struct subsystem *subsys, char *page)
+static ssize_t kexec_loaded_show(struct kset *kset, char *page)
{
return sprintf(page, "%d\n", !!kexec_image);
}
KERNEL_ATTR_RO(kexec_loaded);
-static ssize_t kexec_crash_loaded_show(struct subsystem *subsys, char *page)
+static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page)
{
return sprintf(page, "%d\n", !!kexec_crash_image);
}
@@ -85,7 +85,7 @@ static int __init ksysfs_init(void)
{
int error = subsystem_register(&kernel_subsys);
if (!error)
- error = sysfs_create_group(&kernel_subsys.kset.kobj,
+ error = sysfs_create_group(&kernel_subsys.kobj,
&kernel_attr_group);
return error;
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 87c50ccd1d4..df8a8e8f6ca 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -1,7 +1,7 @@
/* Kernel thread helper functions.
* Copyright (C) 2004 IBM Corporation, Rusty Russell.
*
- * Creation is done via keventd, so that we get a clean environment
+ * Creation is done via kthreadd, so that we get a clean environment
* even if we're invoked from userspace (think modprobe, hotplug cpu,
* etc.).
*/
@@ -15,24 +15,22 @@
#include <linux/mutex.h>
#include <asm/semaphore.h>
-/*
- * We dont want to execute off keventd since it might
- * hold a semaphore our callers hold too:
- */
-static struct workqueue_struct *helper_wq;
+static DEFINE_SPINLOCK(kthread_create_lock);
+static LIST_HEAD(kthread_create_list);
+struct task_struct *kthreadd_task;
struct kthread_create_info
{
- /* Information passed to kthread() from keventd. */
+ /* Information passed to kthread() from kthreadd. */
int (*threadfn)(void *data);
void *data;
struct completion started;
- /* Result passed back to kthread_create() from keventd. */
+ /* Result passed back to kthread_create() from kthreadd. */
struct task_struct *result;
struct completion done;
- struct work_struct work;
+ struct list_head list;
};
struct kthread_stop_info
@@ -60,42 +58,17 @@ int kthread_should_stop(void)
}
EXPORT_SYMBOL(kthread_should_stop);
-static void kthread_exit_files(void)
-{
- struct fs_struct *fs;
- struct task_struct *tsk = current;
-
- exit_fs(tsk); /* current->fs->count--; */
- fs = init_task.fs;
- tsk->fs = fs;
- atomic_inc(&fs->count);
- exit_files(tsk);
- current->files = init_task.files;
- atomic_inc(&tsk->files->count);
-}
-
static int kthread(void *_create)
{
struct kthread_create_info *create = _create;
int (*threadfn)(void *data);
void *data;
- sigset_t blocked;
int ret = -EINTR;
- kthread_exit_files();
-
- /* Copy data: it's on keventd's stack */
+ /* Copy data: it's on kthread's stack */
threadfn = create->threadfn;
data = create->data;
- /* Block and flush all signals (in case we're not from keventd). */
- sigfillset(&blocked);
- sigprocmask(SIG_BLOCK, &blocked, NULL);
- flush_signals(current);
-
- /* By default we can run anywhere, unlike keventd. */
- set_cpus_allowed(current, CPU_MASK_ALL);
-
/* OK, tell user we're spawned, wait for stop or wakeup */
__set_current_state(TASK_INTERRUPTIBLE);
complete(&create->started);
@@ -112,11 +85,8 @@ static int kthread(void *_create)
return 0;
}
-/* We are keventd: create a thread. */
-static void keventd_create_kthread(struct work_struct *work)
+static void create_kthread(struct kthread_create_info *create)
{
- struct kthread_create_info *create =
- container_of(work, struct kthread_create_info, work);
int pid;
/* We want our own signal handler (we take no signals by default). */
@@ -162,17 +132,14 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
create.data = data;
init_completion(&create.started);
init_completion(&create.done);
- INIT_WORK(&create.work, keventd_create_kthread);
-
- /*
- * The workqueue needs to start up first:
- */
- if (!helper_wq)
- create.work.func(&create.work);
- else {
- queue_work(helper_wq, &create.work);
- wait_for_completion(&create.done);
- }
+
+ spin_lock(&kthread_create_lock);
+ list_add_tail(&create.list, &kthread_create_list);
+ wake_up_process(kthreadd_task);
+ spin_unlock(&kthread_create_lock);
+
+ wait_for_completion(&create.done);
+
if (!IS_ERR(create.result)) {
va_list args;
va_start(args, namefmt);
@@ -180,7 +147,6 @@ struct task_struct *kthread_create(int (*threadfn)(void *data),
namefmt, args);
va_end(args);
}
-
return create.result;
}
EXPORT_SYMBOL(kthread_create);
@@ -245,12 +211,47 @@ int kthread_stop(struct task_struct *k)
}
EXPORT_SYMBOL(kthread_stop);
-static __init int helper_init(void)
+
+static __init void kthreadd_setup(void)
{
- helper_wq = create_singlethread_workqueue("kthread");
- BUG_ON(!helper_wq);
+ struct task_struct *tsk = current;
- return 0;
+ set_task_comm(tsk, "kthreadd");
+
+ ignore_signals(tsk);
+
+ set_user_nice(tsk, -5);
+ set_cpus_allowed(tsk, CPU_MASK_ALL);
}
-core_initcall(helper_init);
+int kthreadd(void *unused)
+{
+ /* Setup a clean context for our children to inherit. */
+ kthreadd_setup();
+
+ current->flags |= PF_NOFREEZE;
+
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (list_empty(&kthread_create_list))
+ schedule();
+ __set_current_state(TASK_RUNNING);
+
+ spin_lock(&kthread_create_lock);
+ while (!list_empty(&kthread_create_list)) {
+ struct kthread_create_info *create;
+
+ create = list_entry(kthread_create_list.next,
+ struct kthread_create_info, list);
+ list_del_init(&create->list);
+ spin_unlock(&kthread_create_lock);
+
+ create_kthread(create);
+
+ spin_lock(&kthread_create_lock);
+ }
+ spin_unlock(&kthread_create_lock);
+ }
+
+ return 0;
+}
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 7065a687ac5..1a5ff2211d8 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -257,9 +257,8 @@ static int save_trace(struct stack_trace *trace)
trace->entries = stack_trace + nr_stack_trace_entries;
trace->skip = 3;
- trace->all_contexts = 0;
- save_stack_trace(trace, NULL);
+ save_stack_trace(trace);
trace->max_entries = trace->nr_entries;
@@ -341,10 +340,7 @@ static const char *usage_str[] =
const char * __get_key_name(struct lockdep_subclass_key *key, char *str)
{
- unsigned long offs, size;
- char *modname;
-
- return kallsyms_lookup((unsigned long)key, &size, &offs, &modname, str);
+ return kallsyms_lookup((unsigned long)key, NULL, NULL, NULL, str);
}
void
@@ -1313,8 +1309,9 @@ out_unlock_set:
/*
* Look up a dependency chain. If the key is not present yet then
- * add it and return 0 - in this case the new dependency chain is
- * validated. If the key is already hashed, return 1.
+ * add it and return 1 - in this case the new dependency chain is
+ * validated. If the key is already hashed, return 0.
+ * (On return with 1 graph_lock is held.)
*/
static inline int lookup_chain_cache(u64 chain_key, struct lock_class *class)
{
@@ -1577,7 +1574,7 @@ valid_state(struct task_struct *curr, struct held_lock *this,
* Mark a lock with a usage bit, and validate the state transition:
*/
static int mark_lock(struct task_struct *curr, struct held_lock *this,
- enum lock_usage_bit new_bit, unsigned long ip)
+ enum lock_usage_bit new_bit)
{
unsigned int new_mask = 1 << new_bit, ret = 1;
@@ -1600,14 +1597,6 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
this->class->usage_mask |= new_mask;
-#ifdef CONFIG_TRACE_IRQFLAGS
- if (new_bit == LOCK_ENABLED_HARDIRQS ||
- new_bit == LOCK_ENABLED_HARDIRQS_READ)
- ip = curr->hardirq_enable_ip;
- else if (new_bit == LOCK_ENABLED_SOFTIRQS ||
- new_bit == LOCK_ENABLED_SOFTIRQS_READ)
- ip = curr->softirq_enable_ip;
-#endif
if (!save_trace(this->class->usage_traces + new_bit))
return 0;
@@ -1806,7 +1795,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
* Mark all held locks with a usage bit:
*/
static int
-mark_held_locks(struct task_struct *curr, int hardirq, unsigned long ip)
+mark_held_locks(struct task_struct *curr, int hardirq)
{
enum lock_usage_bit usage_bit;
struct held_lock *hlock;
@@ -1826,7 +1815,7 @@ mark_held_locks(struct task_struct *curr, int hardirq, unsigned long ip)
else
usage_bit = LOCK_ENABLED_SOFTIRQS;
}
- if (!mark_lock(curr, hlock, usage_bit, ip))
+ if (!mark_lock(curr, hlock, usage_bit))
return 0;
}
@@ -1879,7 +1868,7 @@ void trace_hardirqs_on(void)
* We are going to turn hardirqs on, so set the
* usage bit for all held locks:
*/
- if (!mark_held_locks(curr, 1, ip))
+ if (!mark_held_locks(curr, 1))
return;
/*
* If we have softirqs enabled, then set the usage
@@ -1887,7 +1876,7 @@ void trace_hardirqs_on(void)
* this bit from being set before)
*/
if (curr->softirqs_enabled)
- if (!mark_held_locks(curr, 0, ip))
+ if (!mark_held_locks(curr, 0))
return;
curr->hardirq_enable_ip = ip;
@@ -1955,7 +1944,7 @@ void trace_softirqs_on(unsigned long ip)
* enabled too:
*/
if (curr->hardirqs_enabled)
- mark_held_locks(curr, 0, ip);
+ mark_held_locks(curr, 0);
}
/*
@@ -2093,43 +2082,43 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
if (read) {
if (curr->hardirq_context)
if (!mark_lock(curr, hlock,
- LOCK_USED_IN_HARDIRQ_READ, ip))
+ LOCK_USED_IN_HARDIRQ_READ))
return 0;
if (curr->softirq_context)
if (!mark_lock(curr, hlock,
- LOCK_USED_IN_SOFTIRQ_READ, ip))
+ LOCK_USED_IN_SOFTIRQ_READ))
return 0;
} else {
if (curr->hardirq_context)
- if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ, ip))
+ if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
return 0;
if (curr->softirq_context)
- if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ, ip))
+ if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ))
return 0;
}
}
if (!hardirqs_off) {
if (read) {
if (!mark_lock(curr, hlock,
- LOCK_ENABLED_HARDIRQS_READ, ip))
+ LOCK_ENABLED_HARDIRQS_READ))
return 0;
if (curr->softirqs_enabled)
if (!mark_lock(curr, hlock,
- LOCK_ENABLED_SOFTIRQS_READ, ip))
+ LOCK_ENABLED_SOFTIRQS_READ))
return 0;
} else {
if (!mark_lock(curr, hlock,
- LOCK_ENABLED_HARDIRQS, ip))
+ LOCK_ENABLED_HARDIRQS))
return 0;
if (curr->softirqs_enabled)
if (!mark_lock(curr, hlock,
- LOCK_ENABLED_SOFTIRQS, ip))
+ LOCK_ENABLED_SOFTIRQS))
return 0;
}
}
#endif
/* mark it as used: */
- if (!mark_lock(curr, hlock, LOCK_USED, ip))
+ if (!mark_lock(curr, hlock, LOCK_USED))
return 0;
out_calc_hash:
/*
diff --git a/kernel/module.c b/kernel/module.c
index 9da5af668a2..9bd93de01f4 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/moduleloader.h>
#include <linux/init.h>
+#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
@@ -45,6 +46,8 @@
#include <asm/cacheflush.h>
#include <linux/license.h>
+extern int module_sysfs_initialized;
+
#if 0
#define DEBUGP printk
#else
@@ -93,9 +96,9 @@ static inline void add_taint_module(struct module *mod, unsigned flag)
mod->taints |= flag;
}
-/* A thread that wants to hold a reference to a module only while it
- * is running can call ths to safely exit.
- * nfsd and lockd use this.
+/*
+ * A thread that wants to hold a reference to a module only while it
+ * is running can call this to safely exit. nfsd and lockd use this.
*/
void __module_put_and_exit(struct module *mod, long code)
{
@@ -308,14 +311,14 @@ static int split_block(unsigned int i, unsigned short size)
{
/* Reallocation required? */
if (pcpu_num_used + 1 > pcpu_num_allocated) {
- int *new = kmalloc(sizeof(new[0]) * pcpu_num_allocated*2,
- GFP_KERNEL);
+ int *new;
+
+ new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,
+ GFP_KERNEL);
if (!new)
return 0;
- memcpy(new, pcpu_size, sizeof(new[0])*pcpu_num_allocated);
pcpu_num_allocated *= 2;
- kfree(pcpu_size);
pcpu_size = new;
}
@@ -346,10 +349,10 @@ static void *percpu_modalloc(unsigned long size, unsigned long align,
unsigned int i;
void *ptr;
- if (align > SMP_CACHE_BYTES) {
- printk(KERN_WARNING "%s: per-cpu alignment %li > %i\n",
- name, align, SMP_CACHE_BYTES);
- align = SMP_CACHE_BYTES;
+ if (align > PAGE_SIZE) {
+ printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
+ name, align, PAGE_SIZE);
+ align = PAGE_SIZE;
}
ptr = __per_cpu_start;
@@ -430,7 +433,7 @@ static int percpu_modinit(void)
pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
GFP_KERNEL);
/* Static in-kernel percpu data (used). */
- pcpu_size[0] = -ALIGN(__per_cpu_end-__per_cpu_start, SMP_CACHE_BYTES);
+ pcpu_size[0] = -(__per_cpu_end-__per_cpu_start);
/* Free room. */
pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];
if (pcpu_size[1] < 0) {
@@ -1117,8 +1120,8 @@ int mod_sysfs_init(struct module *mod)
{
int err;
- if (!module_subsys.kset.subsys) {
- printk(KERN_ERR "%s: module_subsys not initialized\n",
+ if (!module_sysfs_initialized) {
+ printk(KERN_ERR "%s: module sysfs not initialized\n",
mod->name);
err = -EINVAL;
goto out;
@@ -1196,7 +1199,7 @@ static int __unlink_module(void *_mod)
return 0;
}
-/* Free a module, remove from lists, etc (must hold module mutex). */
+/* Free a module, remove from lists, etc (must hold module_mutex). */
static void free_module(struct module *mod)
{
/* Delete from various lists */
@@ -1243,7 +1246,7 @@ EXPORT_SYMBOL_GPL(__symbol_get);
/*
* Ensure that an exported symbol [global namespace] does not already exist
- * in the Kernel or in some other modules exported symbol table.
+ * in the kernel or in some other module's exported symbol table.
*/
static int verify_export_symbols(struct module *mod)
{
@@ -1469,7 +1472,7 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
}
#ifdef CONFIG_KALLSYMS
-int is_exported(const char *name, const struct module *mod)
+static int is_exported(const char *name, const struct module *mod)
{
if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
return 1;
@@ -2095,8 +2098,10 @@ static const char *get_ksymbol(struct module *mod,
if (!best)
return NULL;
- *size = nextval - mod->symtab[best].st_value;
- *offset = addr - mod->symtab[best].st_value;
+ if (size)
+ *size = nextval - mod->symtab[best].st_value;
+ if (offset)
+ *offset = addr - mod->symtab[best].st_value;
return mod->strtab + mod->symtab[best].st_name;
}
@@ -2121,8 +2126,58 @@ const char *module_address_lookup(unsigned long addr,
return NULL;
}
-struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
- char *type, char *name, size_t namelen)
+int lookup_module_symbol_name(unsigned long addr, char *symname)
+{
+ struct module *mod;
+
+ mutex_lock(&module_mutex);
+ list_for_each_entry(mod, &modules, list) {
+ if (within(addr, mod->module_init, mod->init_size) ||
+ within(addr, mod->module_core, mod->core_size)) {
+ const char *sym;
+
+ sym = get_ksymbol(mod, addr, NULL, NULL);
+ if (!sym)
+ goto out;
+ strlcpy(symname, sym, KSYM_NAME_LEN + 1);
+ mutex_unlock(&module_mutex);
+ return 0;
+ }
+ }
+out:
+ mutex_unlock(&module_mutex);
+ return -ERANGE;
+}
+
+int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
+ unsigned long *offset, char *modname, char *name)
+{
+ struct module *mod;
+
+ mutex_lock(&module_mutex);
+ list_for_each_entry(mod, &modules, list) {
+ if (within(addr, mod->module_init, mod->init_size) ||
+ within(addr, mod->module_core, mod->core_size)) {
+ const char *sym;
+
+ sym = get_ksymbol(mod, addr, size, offset);
+ if (!sym)
+ goto out;
+ if (modname)
+ strlcpy(modname, mod->name, MODULE_NAME_LEN + 1);
+ if (name)
+ strlcpy(name, sym, KSYM_NAME_LEN + 1);
+ mutex_unlock(&module_mutex);
+ return 0;
+ }
+ }
+out:
+ mutex_unlock(&module_mutex);
+ return -ERANGE;
+}
+
+int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
+ char *name, char *module_name, int *exported)
{
struct module *mod;
@@ -2132,14 +2187,16 @@ struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
*value = mod->symtab[symnum].st_value;
*type = mod->symtab[symnum].st_info;
strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
- namelen);
+ KSYM_NAME_LEN + 1);
+ strlcpy(module_name, mod->name, MODULE_NAME_LEN + 1);
+ *exported = is_exported(name, mod);
mutex_unlock(&module_mutex);
- return mod;
+ return 0;
}
symnum -= mod->num_symtab;
}
mutex_unlock(&module_mutex);
- return NULL;
+ return -ERANGE;
}
static unsigned long mod_find_symname(struct module *mod, const char *name)
@@ -2385,7 +2442,7 @@ void module_add_driver(struct module *mod, struct device_driver *drv)
struct kobject *mkobj;
/* Lookup built-in module entry in /sys/modules */
- mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name);
+ mkobj = kset_find_obj(&module_subsys, drv->mod_name);
if (mkobj) {
mk = container_of(mkobj, struct module_kobject, kobj);
/* remember our module structure */
diff --git a/kernel/mutex.c b/kernel/mutex.c
index e7cbbb82765..303eab18484 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -133,7 +133,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
debug_mutex_lock_common(lock, &waiter);
mutex_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
- debug_mutex_add_waiter(lock, &waiter, task->thread_info);
+ debug_mutex_add_waiter(lock, &waiter, task_thread_info(task));
/* add waiting tasks to the end of the waitqueue (FIFO): */
list_add_tail(&waiter.list, &lock->wait_list);
@@ -159,7 +159,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
*/
if (unlikely(state == TASK_INTERRUPTIBLE &&
signal_pending(task))) {
- mutex_remove_waiter(lock, &waiter, task->thread_info);
+ mutex_remove_waiter(lock, &waiter, task_thread_info(task));
mutex_release(&lock->dep_map, 1, _RET_IP_);
spin_unlock_mutex(&lock->wait_lock, flags);
@@ -175,8 +175,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
}
/* got the lock - rejoice! */
- mutex_remove_waiter(lock, &waiter, task->thread_info);
- debug_mutex_set_owner(lock, task->thread_info);
+ mutex_remove_waiter(lock, &waiter, task_thread_info(task));
+ debug_mutex_set_owner(lock, task_thread_info(task));
/* set it to 0 if there are no waiters left: */
if (likely(list_empty(&lock->wait_list)))
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index f5b9ee6f6bb..1bc4b55241a 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -38,10 +38,8 @@ void get_task_namespaces(struct task_struct *tsk)
/*
* creates a copy of "orig" with refcount 1.
- * This does not grab references to the contained namespaces,
- * so that needs to be done by dup_namespaces.
*/
-static inline struct nsproxy *clone_namespaces(struct nsproxy *orig)
+static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig)
{
struct nsproxy *ns;
@@ -52,26 +50,49 @@ static inline struct nsproxy *clone_namespaces(struct nsproxy *orig)
}
/*
- * copies the nsproxy, setting refcount to 1, and grabbing a
- * reference to all contained namespaces. Called from
- * sys_unshare()
+ * Create new nsproxy and all of its the associated namespaces.
+ * Return the newly created nsproxy. Do not attach this to the task,
+ * leave it to the caller to do proper locking and attach it to task.
*/
-struct nsproxy *dup_namespaces(struct nsproxy *orig)
+static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk,
+ struct fs_struct *new_fs)
{
- struct nsproxy *ns = clone_namespaces(orig);
+ struct nsproxy *new_nsp;
- if (ns) {
- if (ns->mnt_ns)
- get_mnt_ns(ns->mnt_ns);
- if (ns->uts_ns)
- get_uts_ns(ns->uts_ns);
- if (ns->ipc_ns)
- get_ipc_ns(ns->ipc_ns);
- if (ns->pid_ns)
- get_pid_ns(ns->pid_ns);
- }
+ new_nsp = clone_nsproxy(tsk->nsproxy);
+ if (!new_nsp)
+ return ERR_PTR(-ENOMEM);
- return ns;
+ new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs);
+ if (IS_ERR(new_nsp->mnt_ns))
+ goto out_ns;
+
+ new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns);
+ if (IS_ERR(new_nsp->uts_ns))
+ goto out_uts;
+
+ new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
+ if (IS_ERR(new_nsp->ipc_ns))
+ goto out_ipc;
+
+ new_nsp->pid_ns = copy_pid_ns(flags, tsk->nsproxy->pid_ns);
+ if (IS_ERR(new_nsp->pid_ns))
+ goto out_pid;
+
+ return new_nsp;
+
+out_pid:
+ if (new_nsp->ipc_ns)
+ put_ipc_ns(new_nsp->ipc_ns);
+out_ipc:
+ if (new_nsp->uts_ns)
+ put_uts_ns(new_nsp->uts_ns);
+out_uts:
+ if (new_nsp->mnt_ns)
+ put_mnt_ns(new_nsp->mnt_ns);
+out_ns:
+ kfree(new_nsp);
+ return ERR_PTR(-ENOMEM);
}
/*
@@ -92,47 +113,21 @@ int copy_namespaces(int flags, struct task_struct *tsk)
if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
return 0;
- new_ns = clone_namespaces(old_ns);
- if (!new_ns) {
- err = -ENOMEM;
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
goto out;
}
- tsk->nsproxy = new_ns;
-
- err = copy_mnt_ns(flags, tsk);
- if (err)
- goto out_ns;
-
- err = copy_utsname(flags, tsk);
- if (err)
- goto out_uts;
-
- err = copy_ipcs(flags, tsk);
- if (err)
- goto out_ipc;
-
- err = copy_pid_ns(flags, tsk);
- if (err)
- goto out_pid;
+ new_ns = create_new_namespaces(flags, tsk, tsk->fs);
+ if (IS_ERR(new_ns)) {
+ err = PTR_ERR(new_ns);
+ goto out;
+ }
+ tsk->nsproxy = new_ns;
out:
put_nsproxy(old_ns);
return err;
-
-out_pid:
- if (new_ns->ipc_ns)
- put_ipc_ns(new_ns->ipc_ns);
-out_ipc:
- if (new_ns->uts_ns)
- put_uts_ns(new_ns->uts_ns);
-out_uts:
- if (new_ns->mnt_ns)
- put_mnt_ns(new_ns->mnt_ns);
-out_ns:
- tsk->nsproxy = old_ns;
- kfree(new_ns);
- goto out;
}
void free_nsproxy(struct nsproxy *ns)
@@ -147,3 +142,41 @@ void free_nsproxy(struct nsproxy *ns)
put_pid_ns(ns->pid_ns);
kfree(ns);
}
+
+/*
+ * Called from unshare. Unshare all the namespaces part of nsproxy.
+ * On sucess, returns the new nsproxy and a reference to old nsproxy
+ * to make sure it stays around.
+ */
+int unshare_nsproxy_namespaces(unsigned long unshare_flags,
+ struct nsproxy **new_nsp, struct fs_struct *new_fs)
+{
+ struct nsproxy *old_ns = current->nsproxy;
+ int err = 0;
+
+ if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
+ return 0;
+
+#ifndef CONFIG_IPC_NS
+ if (unshare_flags & CLONE_NEWIPC)
+ return -EINVAL;
+#endif
+
+#ifndef CONFIG_UTS_NS
+ if (unshare_flags & CLONE_NEWUTS)
+ return -EINVAL;
+#endif
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ get_nsproxy(old_ns);
+
+ *new_nsp = create_new_namespaces(unshare_flags, current,
+ new_fs ? new_fs : current->fs);
+ if (IS_ERR(*new_nsp)) {
+ err = PTR_ERR(*new_nsp);
+ put_nsproxy(old_ns);
+ }
+ return err;
+}
diff --git a/kernel/params.c b/kernel/params.c
index 1fc4ac746cd..e61c46c97ce 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -269,7 +269,7 @@ int param_get_invbool(char *buffer, struct kernel_param *kp)
return param_get_bool(buffer, &dummy);
}
-/* We cheat here and temporarily mangle the string. */
+/* We break the rule and mangle the string. */
static int param_array(const char *name,
const char *val,
unsigned int min, unsigned int max,
@@ -691,6 +691,7 @@ static struct kset_uevent_ops module_uevent_ops = {
};
decl_subsys(module, &module_ktype, &module_uevent_ops);
+int module_sysfs_initialized;
static struct kobj_type module_ktype = {
.sysfs_ops = &module_sysfs_ops,
@@ -709,6 +710,7 @@ static int __init param_sysfs_init(void)
__FILE__, __LINE__, ret);
return ret;
}
+ module_sysfs_initialized = 1;
param_sysfs_builtin();
diff --git a/kernel/pid.c b/kernel/pid.c
index 78f2aee90f5..d3ad724afa8 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -360,16 +360,11 @@ struct pid *find_ge_pid(int nr)
}
EXPORT_SYMBOL_GPL(find_get_pid);
-int copy_pid_ns(int flags, struct task_struct *tsk)
+struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *old_ns)
{
- struct pid_namespace *old_ns = tsk->nsproxy->pid_ns;
- int err = 0;
-
- if (!old_ns)
- return 0;
-
+ BUG_ON(!old_ns);
get_pid_ns(old_ns);
- return err;
+ return old_ns;
}
void free_pid_ns(struct kref *kref)
@@ -412,7 +407,5 @@ void __init pidmap_init(void)
set_bit(0, init_pid_ns.pidmap[0].page);
atomic_dec(&init_pid_ns.pidmap[0].nr_free);
- pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
- __alignof__(struct pid),
- SLAB_PANIC, NULL, NULL);
+ pid_cachep = KMEM_CACHE(pid, SLAB_PANIC);
}
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 657f7769741..1de710e1837 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -971,7 +971,7 @@ static void check_thread_timers(struct task_struct *tsk,
maxfire = 20;
tsk->it_prof_expires = cputime_zero;
while (!list_empty(timers)) {
- struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list *t = list_first_entry(timers,
struct cpu_timer_list,
entry);
if (!--maxfire || cputime_lt(prof_ticks(tsk), t->expires.cpu)) {
@@ -986,7 +986,7 @@ static void check_thread_timers(struct task_struct *tsk,
maxfire = 20;
tsk->it_virt_expires = cputime_zero;
while (!list_empty(timers)) {
- struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list *t = list_first_entry(timers,
struct cpu_timer_list,
entry);
if (!--maxfire || cputime_lt(virt_ticks(tsk), t->expires.cpu)) {
@@ -1001,7 +1001,7 @@ static void check_thread_timers(struct task_struct *tsk,
maxfire = 20;
tsk->it_sched_expires = 0;
while (!list_empty(timers)) {
- struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list *t = list_first_entry(timers,
struct cpu_timer_list,
entry);
if (!--maxfire || tsk->sched_time < t->expires.sched) {
@@ -1057,7 +1057,7 @@ static void check_process_timers(struct task_struct *tsk,
maxfire = 20;
prof_expires = cputime_zero;
while (!list_empty(timers)) {
- struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list *t = list_first_entry(timers,
struct cpu_timer_list,
entry);
if (!--maxfire || cputime_lt(ptime, t->expires.cpu)) {
@@ -1072,7 +1072,7 @@ static void check_process_timers(struct task_struct *tsk,
maxfire = 20;
virt_expires = cputime_zero;
while (!list_empty(timers)) {
- struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list *t = list_first_entry(timers,
struct cpu_timer_list,
entry);
if (!--maxfire || cputime_lt(utime, t->expires.cpu)) {
@@ -1087,7 +1087,7 @@ static void check_process_timers(struct task_struct *tsk,
maxfire = 20;
sched_expires = 0;
while (!list_empty(timers)) {
- struct cpu_timer_list *t = list_entry(timers->next,
+ struct cpu_timer_list *t = list_first_entry(timers,
struct cpu_timer_list,
entry);
if (!--maxfire || sched_time < t->expires.sched) {
@@ -1400,7 +1400,7 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
*/
head = &tsk->signal->cpu_timers[clock_idx];
if (list_empty(head) ||
- cputime_ge(list_entry(head->next,
+ cputime_ge(list_first_entry(head,
struct cpu_timer_list, entry)->expires.cpu,
*newval)) {
/*
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 44318ca7197..588c99da030 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -31,7 +31,6 @@
* POSIX clocks & timers
*/
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/time.h>
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 51a4dd0f1b7..495b7d4dd33 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -78,17 +78,22 @@ config PM_SYSFS_DEPRECATED
are likely to be bus or driver specific.
config SOFTWARE_SUSPEND
- bool "Software Suspend"
- depends on PM && SWAP && ((X86 && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
+ bool "Software Suspend (Hibernation)"
+ depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
---help---
- Enable the suspend to disk (STD) functionality.
+ Enable the suspend to disk (STD) functionality, which is usually
+ called "hibernation" in user interfaces. STD checkpoints the
+ system and powers it off; and restores that checkpoint on reboot.
You can suspend your machine with 'echo disk > /sys/power/state'.
Alternatively, you can use the additional userland tools available
from <http://suspend.sf.net>.
In principle it does not require ACPI or APM, although for example
- ACPI will be used if available.
+ ACPI will be used for the final steps when it is available. One
+ of the reasons to use software suspend is that the firmware hooks
+ for suspend states like suspend-to-RAM (STR) often don't work very
+ well with Linux.
It creates an image which is saved in your active swap. Upon the next
boot, pass the 'resume=/dev/swappartition' argument to the kernel to
@@ -134,7 +139,7 @@ config PM_STD_PARTITION
config SUSPEND_SMP
bool
- depends on HOTPLUG_CPU && X86 && PM
+ depends on HOTPLUG_CPU && (X86 || PPC64) && PM
default y
config APM_EMULATION
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index aec19b063e3..b5f0543ed84 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -30,63 +30,102 @@ char resume_file[256] = CONFIG_PM_STD_PARTITION;
dev_t swsusp_resume_device;
sector_t swsusp_resume_block;
+enum {
+ HIBERNATION_INVALID,
+ HIBERNATION_PLATFORM,
+ HIBERNATION_TEST,
+ HIBERNATION_TESTPROC,
+ HIBERNATION_SHUTDOWN,
+ HIBERNATION_REBOOT,
+ /* keep last */
+ __HIBERNATION_AFTER_LAST
+};
+#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1)
+#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1)
+
+static int hibernation_mode = HIBERNATION_SHUTDOWN;
+
+struct hibernation_ops *hibernation_ops;
+
+/**
+ * hibernation_set_ops - set the global hibernate operations
+ * @ops: the hibernation operations to use in subsequent hibernation transitions
+ */
+
+void hibernation_set_ops(struct hibernation_ops *ops)
+{
+ if (ops && !(ops->prepare && ops->enter && ops->finish)) {
+ WARN_ON(1);
+ return;
+ }
+ mutex_lock(&pm_mutex);
+ hibernation_ops = ops;
+ if (ops)
+ hibernation_mode = HIBERNATION_PLATFORM;
+ else if (hibernation_mode == HIBERNATION_PLATFORM)
+ hibernation_mode = HIBERNATION_SHUTDOWN;
+
+ mutex_unlock(&pm_mutex);
+}
+
+
/**
* platform_prepare - prepare the machine for hibernation using the
* platform driver if so configured and return an error code if it fails
*/
-static inline int platform_prepare(void)
+static int platform_prepare(void)
{
- int error = 0;
+ return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ?
+ hibernation_ops->prepare() : 0;
+}
- if (pm_disk_mode == PM_DISK_PLATFORM) {
- if (pm_ops && pm_ops->prepare)
- error = pm_ops->prepare(PM_SUSPEND_DISK);
- }
- return error;
+/**
+ * platform_finish - switch the machine to the normal mode of operation
+ * using the platform driver (must be called after platform_prepare())
+ */
+
+static void platform_finish(void)
+{
+ if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops)
+ hibernation_ops->finish();
}
/**
- * power_down - Shut machine down for hibernate.
- * @mode: Suspend-to-disk mode
+ * power_down - Shut the machine down for hibernation.
*
- * Use the platform driver, if configured so, and return gracefully if it
- * fails.
- * Otherwise, try to power off and reboot. If they fail, halt the machine,
- * there ain't no turning back.
+ * Use the platform driver, if configured so; otherwise try
+ * to power off or reboot.
*/
-static void power_down(suspend_disk_method_t mode)
+static void power_down(void)
{
- switch(mode) {
- case PM_DISK_PLATFORM:
- if (pm_ops && pm_ops->enter) {
- kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
- pm_ops->enter(PM_SUSPEND_DISK);
- break;
- }
- case PM_DISK_SHUTDOWN:
+ switch (hibernation_mode) {
+ case HIBERNATION_TEST:
+ case HIBERNATION_TESTPROC:
+ break;
+ case HIBERNATION_SHUTDOWN:
kernel_power_off();
break;
- case PM_DISK_REBOOT:
+ case HIBERNATION_REBOOT:
kernel_restart(NULL);
break;
+ case HIBERNATION_PLATFORM:
+ if (hibernation_ops) {
+ kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+ hibernation_ops->enter();
+ break;
+ }
}
kernel_halt();
- /* Valid image is on the disk, if we continue we risk serious data corruption
- after resume. */
+ /*
+ * Valid image is on the disk, if we continue we risk serious data
+ * corruption after resume.
+ */
printk(KERN_CRIT "Please power me down manually\n");
while(1);
}
-static inline void platform_finish(void)
-{
- if (pm_disk_mode == PM_DISK_PLATFORM) {
- if (pm_ops && pm_ops->finish)
- pm_ops->finish(PM_SUSPEND_DISK);
- }
-}
-
static void unprepare_processes(void)
{
thaw_processes();
@@ -106,27 +145,33 @@ static int prepare_processes(void)
}
/**
- * pm_suspend_disk - The granpappy of hibernation power management.
- *
- * If we're going through the firmware, then get it over with quickly.
- *
- * If not, then call swsusp to do its thing, then figure out how
- * to power down the system.
+ * hibernate - The granpappy of the built-in hibernation management
*/
-int pm_suspend_disk(void)
+int hibernate(void)
{
int error;
+ /* The snapshot device should not be opened while we're running */
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0))
+ return -EBUSY;
+
+ /* Allocate memory management structures */
+ error = create_basic_memory_bitmaps();
+ if (error)
+ goto Exit;
+
error = prepare_processes();
if (error)
- return error;
+ goto Finish;
- if (pm_disk_mode == PM_DISK_TESTPROC) {
+ mutex_lock(&pm_mutex);
+ if (hibernation_mode == HIBERNATION_TESTPROC) {
printk("swsusp debug: Waiting for 5 seconds.\n");
mdelay(5000);
goto Thaw;
}
+
/* Free memory before shutting down devices. */
error = swsusp_shrink_memory();
if (error)
@@ -146,7 +191,7 @@ int pm_suspend_disk(void)
if (error)
goto Enable_cpus;
- if (pm_disk_mode == PM_DISK_TEST) {
+ if (hibernation_mode == HIBERNATION_TEST) {
printk("swsusp debug: Waiting for 5 seconds.\n");
mdelay(5000);
goto Enable_cpus;
@@ -166,7 +211,7 @@ int pm_suspend_disk(void)
pr_debug("PM: writing image.\n");
error = swsusp_write();
if (!error)
- power_down(pm_disk_mode);
+ power_down();
else {
swsusp_free();
goto Thaw;
@@ -183,7 +228,12 @@ int pm_suspend_disk(void)
device_resume();
resume_console();
Thaw:
+ mutex_unlock(&pm_mutex);
unprepare_processes();
+ Finish:
+ free_basic_memory_bitmaps();
+ Exit:
+ atomic_inc(&snapshot_device_available);
return error;
}
@@ -194,7 +244,7 @@ int pm_suspend_disk(void)
* Called as a late_initcall (so all devices are discovered and
* initialized), we call swsusp to see if we have a saved image or not.
* If so, we quiesce devices, the restore the saved image. We will
- * return above (in pm_suspend_disk() ) if everything goes well.
+ * return above (in hibernate() ) if everything goes well.
* Otherwise, we fail gracefully and return to the normally
* scheduled program.
*
@@ -227,13 +277,21 @@ static int software_resume(void)
}
pr_debug("PM: Checking swsusp image.\n");
-
error = swsusp_check();
if (error)
- goto Done;
+ goto Unlock;
- pr_debug("PM: Preparing processes for restore.\n");
+ /* The snapshot device should not be opened while we're running */
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+ error = -EBUSY;
+ goto Unlock;
+ }
+ error = create_basic_memory_bitmaps();
+ if (error)
+ goto Finish;
+
+ pr_debug("PM: Preparing processes for restore.\n");
error = prepare_processes();
if (error) {
swsusp_close();
@@ -268,7 +326,11 @@ static int software_resume(void)
printk(KERN_ERR "PM: Restore failed, recovering.\n");
unprepare_processes();
Done:
+ free_basic_memory_bitmaps();
+ Finish:
+ atomic_inc(&snapshot_device_available);
/* For success case, the suspend path will release the lock */
+ Unlock:
mutex_unlock(&pm_mutex);
pr_debug("PM: Resume from disk failed.\n");
return 0;
@@ -277,96 +339,121 @@ static int software_resume(void)
late_initcall(software_resume);
-static const char * const pm_disk_modes[] = {
- [PM_DISK_FIRMWARE] = "firmware",
- [PM_DISK_PLATFORM] = "platform",
- [PM_DISK_SHUTDOWN] = "shutdown",
- [PM_DISK_REBOOT] = "reboot",
- [PM_DISK_TEST] = "test",
- [PM_DISK_TESTPROC] = "testproc",
+static const char * const hibernation_modes[] = {
+ [HIBERNATION_PLATFORM] = "platform",
+ [HIBERNATION_SHUTDOWN] = "shutdown",
+ [HIBERNATION_REBOOT] = "reboot",
+ [HIBERNATION_TEST] = "test",
+ [HIBERNATION_TESTPROC] = "testproc",
};
/**
- * disk - Control suspend-to-disk mode
+ * disk - Control hibernation mode
*
- * Suspend-to-disk can be handled in several ways. The greatest
- * distinction is who writes memory to disk - the firmware or the OS.
- * If the firmware does it, we assume that it also handles suspending
- * the system.
- * If the OS does it, then we have three options for putting the system
- * to sleep - using the platform driver (e.g. ACPI or other PM registers),
- * powering off the system or rebooting the system (for testing).
+ * Suspend-to-disk can be handled in several ways. We have a few options
+ * for putting the system to sleep - using the platform driver (e.g. ACPI
+ * or other hibernation_ops), powering off the system or rebooting the
+ * system (for testing) as well as the two test modes.
*
- * The system will support either 'firmware' or 'platform', and that is
- * known a priori (and encoded in pm_ops). But, the user may choose
- * 'shutdown' or 'reboot' as alternatives.
+ * The system can support 'platform', and that is known a priori (and
+ * encoded by the presence of hibernation_ops). However, the user may
+ * choose 'shutdown' or 'reboot' as alternatives, as well as one fo the
+ * test modes, 'test' or 'testproc'.
*
* show() will display what the mode is currently set to.
* store() will accept one of
*
- * 'firmware'
* 'platform'
* 'shutdown'
* 'reboot'
+ * 'test'
+ * 'testproc'
*
- * It will only change to 'firmware' or 'platform' if the system
- * supports it (as determined from pm_ops->pm_disk_mode).
+ * It will only change to 'platform' if the system
+ * supports it (as determined by having hibernation_ops).
*/
-static ssize_t disk_show(struct subsystem * subsys, char * buf)
+static ssize_t disk_show(struct kset *kset, char *buf)
{
- return sprintf(buf, "%s\n", pm_disk_modes[pm_disk_mode]);
+ int i;
+ char *start = buf;
+
+ for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+ if (!hibernation_modes[i])
+ continue;
+ switch (i) {
+ case HIBERNATION_SHUTDOWN:
+ case HIBERNATION_REBOOT:
+ case HIBERNATION_TEST:
+ case HIBERNATION_TESTPROC:
+ break;
+ case HIBERNATION_PLATFORM:
+ if (hibernation_ops)
+ break;
+ /* not a valid mode, continue with loop */
+ continue;
+ }
+ if (i == hibernation_mode)
+ buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
+ else
+ buf += sprintf(buf, "%s ", hibernation_modes[i]);
+ }
+ buf += sprintf(buf, "\n");
+ return buf-start;
}
-static ssize_t disk_store(struct subsystem * s, const char * buf, size_t n)
+static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)
{
int error = 0;
int i;
int len;
char *p;
- suspend_disk_method_t mode = 0;
+ int mode = HIBERNATION_INVALID;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
mutex_lock(&pm_mutex);
- for (i = PM_DISK_FIRMWARE; i < PM_DISK_MAX; i++) {
- if (!strncmp(buf, pm_disk_modes[i], len)) {
+ for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
+ if (!strncmp(buf, hibernation_modes[i], len)) {
mode = i;
break;
}
}
- if (mode) {
- if (mode == PM_DISK_SHUTDOWN || mode == PM_DISK_REBOOT ||
- mode == PM_DISK_TEST || mode == PM_DISK_TESTPROC) {
- pm_disk_mode = mode;
- } else {
- if (pm_ops && pm_ops->enter &&
- (mode == pm_ops->pm_disk_mode))
- pm_disk_mode = mode;
+ if (mode != HIBERNATION_INVALID) {
+ switch (mode) {
+ case HIBERNATION_SHUTDOWN:
+ case HIBERNATION_REBOOT:
+ case HIBERNATION_TEST:
+ case HIBERNATION_TESTPROC:
+ hibernation_mode = mode;
+ break;
+ case HIBERNATION_PLATFORM:
+ if (hibernation_ops)
+ hibernation_mode = mode;
else
error = -EINVAL;
}
- } else {
+ } else
error = -EINVAL;
- }
- pr_debug("PM: suspend-to-disk mode set to '%s'\n",
- pm_disk_modes[mode]);
+ if (!error)
+ pr_debug("PM: suspend-to-disk mode set to '%s'\n",
+ hibernation_modes[mode]);
mutex_unlock(&pm_mutex);
return error ? error : n;
}
power_attr(disk);
-static ssize_t resume_show(struct subsystem * subsys, char *buf)
+static ssize_t resume_show(struct kset *kset, char *buf)
{
return sprintf(buf,"%d:%d\n", MAJOR(swsusp_resume_device),
MINOR(swsusp_resume_device));
}
-static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n)
+static ssize_t resume_store(struct kset *kset, const char *buf, size_t n)
{
unsigned int maj, min;
dev_t res;
@@ -392,12 +479,12 @@ static ssize_t resume_store(struct subsystem *subsys, const char *buf, size_t n)
power_attr(resume);
-static ssize_t image_size_show(struct subsystem * subsys, char *buf)
+static ssize_t image_size_show(struct kset *kset, char *buf)
{
return sprintf(buf, "%lu\n", image_size);
}
-static ssize_t image_size_store(struct subsystem * subsys, const char * buf, size_t n)
+static ssize_t image_size_store(struct kset *kset, const char *buf, size_t n)
{
unsigned long size;
@@ -426,7 +513,7 @@ static struct attribute_group attr_group = {
static int __init pm_disk_init(void)
{
- return sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+ return sysfs_create_group(&power_subsys.kobj, &attr_group);
}
core_initcall(pm_disk_init);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 3062e940d1f..40d56a31245 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -30,7 +30,6 @@
DEFINE_MUTEX(pm_mutex);
struct pm_ops *pm_ops;
-suspend_disk_method_t pm_disk_mode = PM_DISK_PLATFORM;
/**
* pm_set_ops - Set the global power method table.
@@ -44,6 +43,19 @@ void pm_set_ops(struct pm_ops * ops)
mutex_unlock(&pm_mutex);
}
+/**
+ * pm_valid_only_mem - generic memory-only valid callback
+ *
+ * pm_ops drivers that implement mem suspend only and only need
+ * to check for that in their .valid callback can use this instead
+ * of rolling their own .valid callback.
+ */
+int pm_valid_only_mem(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM;
+}
+
+
static inline void pm_finish(suspend_state_t state)
{
if (pm_ops->finish)
@@ -167,22 +179,14 @@ static void suspend_finish(suspend_state_t state)
static const char * const pm_states[PM_SUSPEND_MAX] = {
[PM_SUSPEND_STANDBY] = "standby",
[PM_SUSPEND_MEM] = "mem",
-#ifdef CONFIG_SOFTWARE_SUSPEND
- [PM_SUSPEND_DISK] = "disk",
-#endif
};
static inline int valid_state(suspend_state_t state)
{
- /* Suspend-to-disk does not really need low-level support.
- * It can work with reboot if needed. */
- if (state == PM_SUSPEND_DISK)
- return 1;
-
- /* all other states need lowlevel support and need to be
- * valid to the lowlevel implementation, no valid callback
- * implies that all are valid. */
- if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state)))
+ /* All states need lowlevel support and need to be valid
+ * to the lowlevel implementation, no valid callback
+ * implies that none are valid. */
+ if (!pm_ops || !pm_ops->valid || !pm_ops->valid(state))
return 0;
return 1;
}
@@ -208,11 +212,6 @@ static int enter_state(suspend_state_t state)
if (!mutex_trylock(&pm_mutex))
return -EBUSY;
- if (state == PM_SUSPEND_DISK) {
- error = pm_suspend_disk();
- goto Unlock;
- }
-
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
if ((error = suspend_prepare(state)))
goto Unlock;
@@ -227,19 +226,10 @@ static int enter_state(suspend_state_t state)
return error;
}
-/*
- * This is main interface to the outside world. It needs to be
- * called from process context.
- */
-int software_suspend(void)
-{
- return enter_state(PM_SUSPEND_DISK);
-}
-
/**
* pm_suspend - Externally visible function for suspending system.
- * @state: Enumarted value of state to enter.
+ * @state: Enumerated value of state to enter.
*
* Determine whether or not value is within range, get state
* structure, and enter (above).
@@ -268,7 +258,7 @@ decl_subsys(power,NULL,NULL);
* proper enumerated value, and initiates a suspend transition.
*/
-static ssize_t state_show(struct subsystem * subsys, char * buf)
+static ssize_t state_show(struct kset *kset, char *buf)
{
int i;
char * s = buf;
@@ -277,11 +267,17 @@ static ssize_t state_show(struct subsystem * subsys, char * buf)
if (pm_states[i] && valid_state(i))
s += sprintf(s,"%s ", pm_states[i]);
}
- s += sprintf(s,"\n");
+#ifdef CONFIG_SOFTWARE_SUSPEND
+ s += sprintf(s, "%s\n", "disk");
+#else
+ if (s != buf)
+ /* convert the last space to a newline */
+ *(s-1) = '\n';
+#endif
return (s - buf);
}
-static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n)
+static ssize_t state_store(struct kset *kset, const char *buf, size_t n)
{
suspend_state_t state = PM_SUSPEND_STANDBY;
const char * const *s;
@@ -292,6 +288,12 @@ static ssize_t state_store(struct subsystem * subsys, const char * buf, size_t n
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
+ /* First, check if we are requested to hibernate */
+ if (!strncmp(buf, "disk", len)) {
+ error = hibernate();
+ return error ? error : n;
+ }
+
for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
if (*s && !strncmp(buf, *s, len))
break;
@@ -308,13 +310,13 @@ power_attr(state);
#ifdef CONFIG_PM_TRACE
int pm_trace_enabled;
-static ssize_t pm_trace_show(struct subsystem * subsys, char * buf)
+static ssize_t pm_trace_show(struct kset *kset, char *buf)
{
return sprintf(buf, "%d\n", pm_trace_enabled);
}
static ssize_t
-pm_trace_store(struct subsystem * subsys, const char * buf, size_t n)
+pm_trace_store(struct kset *kset, const char *buf, size_t n)
{
int val;
@@ -348,7 +350,7 @@ static int __init pm_init(void)
{
int error = subsystem_register(&power_subsys);
if (!error)
- error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group);
+ error = sysfs_create_group(&power_subsys.kobj,&attr_group);
return error;
}
diff --git a/kernel/power/power.h b/kernel/power/power.h
index eb461b816bf..51381487103 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -14,15 +14,22 @@ struct swsusp_info {
#ifdef CONFIG_SOFTWARE_SUSPEND
-extern int pm_suspend_disk(void);
+/*
+ * Keep some memory free so that I/O operations can succeed without paging
+ * [Might this be more than 4 MB?]
+ */
+#define PAGES_FOR_IO ((4096 * 1024) >> PAGE_SHIFT)
+/*
+ * Keep 1 MB of memory free so that device drivers can allocate some pages in
+ * their .suspend() routines without breaking the suspend to disk.
+ */
+#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
-#else
-static inline int pm_suspend_disk(void)
-{
- return -EPERM;
-}
+extern struct hibernation_ops *hibernation_ops;
#endif
+extern int pfn_is_nosave(unsigned long);
+
extern struct mutex pm_mutex;
#define power_attr(_name) \
@@ -35,10 +42,7 @@ static struct subsys_attribute _name##_attr = { \
.store = _name##_store, \
}
-extern struct subsystem power_subsys;
-
-/* References to section boundaries */
-extern const void __nosave_begin, __nosave_end;
+extern struct kset power_subsys;
/* Preferred image size in bytes (default 500 MB) */
extern unsigned long image_size;
@@ -49,6 +53,8 @@ extern sector_t swsusp_resume_block;
extern asmlinkage int swsusp_arch_suspend(void);
extern asmlinkage int swsusp_arch_resume(void);
+extern int create_basic_memory_bitmaps(void);
+extern void free_basic_memory_bitmaps(void);
extern unsigned int count_data_pages(void);
/**
@@ -139,30 +145,12 @@ struct resume_swap_area {
#define PMOPS_ENTER 2
#define PMOPS_FINISH 3
-/**
- * The bitmap is used for tracing allocated swap pages
- *
- * The entire bitmap consists of a number of bitmap_page
- * structures linked with the help of the .next member.
- * Thus each page can be allocated individually, so we only
- * need to make 0-order memory allocations to create
- * the bitmap.
- */
-
-#define BITMAP_PAGE_SIZE (PAGE_SIZE - sizeof(void *))
-#define BITMAP_PAGE_CHUNKS (BITMAP_PAGE_SIZE / sizeof(long))
-#define BITS_PER_CHUNK (sizeof(long) * 8)
-#define BITMAP_PAGE_BITS (BITMAP_PAGE_CHUNKS * BITS_PER_CHUNK)
-
-struct bitmap_page {
- unsigned long chunks[BITMAP_PAGE_CHUNKS];
- struct bitmap_page *next;
-};
+/* If unset, the snapshot device cannot be open. */
+extern atomic_t snapshot_device_available;
-extern void free_bitmap(struct bitmap_page *bitmap);
-extern struct bitmap_page *alloc_bitmap(unsigned int nr_bits);
-extern sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap);
-extern void free_all_swap_pages(int swap, struct bitmap_page *bitmap);
+extern sector_t alloc_swapdev_block(int swap);
+extern void free_all_swap_pages(int swap);
+extern int swsusp_swap_in_use(void);
extern int swsusp_check(void);
extern int swsusp_shrink_memory(void);
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 6d566bf7085..08841938738 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -8,7 +8,6 @@
#undef DEBUG
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/suspend.h>
#include <linux/module.h>
@@ -25,10 +24,9 @@
static inline int freezeable(struct task_struct * p)
{
- if ((p == current) ||
+ if ((p == current) ||
(p->flags & PF_NOFREEZE) ||
- (p->exit_state == EXIT_ZOMBIE) ||
- (p->exit_state == EXIT_DEAD))
+ (p->exit_state != 0))
return 0;
return 1;
}
@@ -47,8 +45,10 @@ void refrigerator(void)
recalc_sigpending(); /* We sent fake signal, clean it up */
spin_unlock_irq(&current->sighand->siglock);
- while (frozen(current)) {
- current->state = TASK_UNINTERRUPTIBLE;
+ for (;;) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if (!frozen(current))
+ break;
schedule();
}
pr_debug("%s left refrigerator\n", current->comm);
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index fc53ad06812..a3b7854b8f7 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -14,13 +14,13 @@
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/suspend.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/pm.h>
#include <linux/device.h>
+#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/syscalls.h>
#include <linux/console.h>
@@ -34,6 +34,10 @@
#include "power.h"
+static int swsusp_page_is_free(struct page *);
+static void swsusp_set_page_forbidden(struct page *);
+static void swsusp_unset_page_forbidden(struct page *);
+
/* List of PBEs needed for restoring the pages that were allocated before
* the suspend and included in the suspend image, but have also been
* allocated by the "resume" kernel, so their contents cannot be written
@@ -67,15 +71,15 @@ static void *get_image_page(gfp_t gfp_mask, int safe_needed)
res = (void *)get_zeroed_page(gfp_mask);
if (safe_needed)
- while (res && PageNosaveFree(virt_to_page(res))) {
+ while (res && swsusp_page_is_free(virt_to_page(res))) {
/* The page is unsafe, mark it for swsusp_free() */
- SetPageNosave(virt_to_page(res));
+ swsusp_set_page_forbidden(virt_to_page(res));
allocated_unsafe_pages++;
res = (void *)get_zeroed_page(gfp_mask);
}
if (res) {
- SetPageNosave(virt_to_page(res));
- SetPageNosaveFree(virt_to_page(res));
+ swsusp_set_page_forbidden(virt_to_page(res));
+ swsusp_set_page_free(virt_to_page(res));
}
return res;
}
@@ -91,8 +95,8 @@ static struct page *alloc_image_page(gfp_t gfp_mask)
page = alloc_page(gfp_mask);
if (page) {
- SetPageNosave(page);
- SetPageNosaveFree(page);
+ swsusp_set_page_forbidden(page);
+ swsusp_set_page_free(page);
}
return page;
}
@@ -110,9 +114,9 @@ static inline void free_image_page(void *addr, int clear_nosave_free)
page = virt_to_page(addr);
- ClearPageNosave(page);
+ swsusp_unset_page_forbidden(page);
if (clear_nosave_free)
- ClearPageNosaveFree(page);
+ swsusp_unset_page_free(page);
__free_page(page);
}
@@ -224,11 +228,6 @@ static void chain_free(struct chain_allocator *ca, int clear_page_nosave)
* of type unsigned long each). It also contains the pfns that
* correspond to the start and end of the represented memory area and
* the number of bit chunks in the block.
- *
- * NOTE: Memory bitmaps are used for two types of operations only:
- * "set a bit" and "find the next bit set". Moreover, the searching
- * is always carried out after all of the "set a bit" operations
- * on given bitmap.
*/
#define BM_END_OF_MAP (~0UL)
@@ -443,15 +442,13 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
}
/**
- * memory_bm_set_bit - set the bit in the bitmap @bm that corresponds
+ * memory_bm_find_bit - find the bit in the bitmap @bm that corresponds
* to given pfn. The cur_zone_bm member of @bm and the cur_block member
* of @bm->cur_zone_bm are updated.
- *
- * If the bit cannot be set, the function returns -EINVAL .
*/
-static int
-memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
+static void memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
+ void **addr, unsigned int *bit_nr)
{
struct zone_bitmap *zone_bm;
struct bm_block *bb;
@@ -463,8 +460,8 @@ memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
/* We don't assume that the zones are sorted by pfns */
while (pfn < zone_bm->start_pfn || pfn >= zone_bm->end_pfn) {
zone_bm = zone_bm->next;
- if (unlikely(!zone_bm))
- return -EINVAL;
+
+ BUG_ON(!zone_bm);
}
bm->cur.zone_bm = zone_bm;
}
@@ -475,13 +472,40 @@ memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
while (pfn >= bb->end_pfn) {
bb = bb->next;
- if (unlikely(!bb))
- return -EINVAL;
+
+ BUG_ON(!bb);
}
zone_bm->cur_block = bb;
pfn -= bb->start_pfn;
- set_bit(pfn % BM_BITS_PER_CHUNK, bb->data + pfn / BM_BITS_PER_CHUNK);
- return 0;
+ *bit_nr = pfn % BM_BITS_PER_CHUNK;
+ *addr = bb->data + pfn / BM_BITS_PER_CHUNK;
+}
+
+static void memory_bm_set_bit(struct memory_bitmap *bm, unsigned long pfn)
+{
+ void *addr;
+ unsigned int bit;
+
+ memory_bm_find_bit(bm, pfn, &addr, &bit);
+ set_bit(bit, addr);
+}
+
+static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
+{
+ void *addr;
+ unsigned int bit;
+
+ memory_bm_find_bit(bm, pfn, &addr, &bit);
+ clear_bit(bit, addr);
+}
+
+static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
+{
+ void *addr;
+ unsigned int bit;
+
+ memory_bm_find_bit(bm, pfn, &addr, &bit);
+ return test_bit(bit, addr);
}
/* Two auxiliary functions for memory_bm_next_pfn */
@@ -564,6 +588,205 @@ static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm)
}
/**
+ * This structure represents a range of page frames the contents of which
+ * should not be saved during the suspend.
+ */
+
+struct nosave_region {
+ struct list_head list;
+ unsigned long start_pfn;
+ unsigned long end_pfn;
+};
+
+static LIST_HEAD(nosave_regions);
+
+/**
+ * register_nosave_region - register a range of page frames the contents
+ * of which should not be saved during the suspend (to be used in the early
+ * initialization code)
+ */
+
+void __init
+__register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
+ int use_kmalloc)
+{
+ struct nosave_region *region;
+
+ if (start_pfn >= end_pfn)
+ return;
+
+ if (!list_empty(&nosave_regions)) {
+ /* Try to extend the previous region (they should be sorted) */
+ region = list_entry(nosave_regions.prev,
+ struct nosave_region, list);
+ if (region->end_pfn == start_pfn) {
+ region->end_pfn = end_pfn;
+ goto Report;
+ }
+ }
+ if (use_kmalloc) {
+ /* during init, this shouldn't fail */
+ region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
+ BUG_ON(!region);
+ } else
+ /* This allocation cannot fail */
+ region = alloc_bootmem_low(sizeof(struct nosave_region));
+ region->start_pfn = start_pfn;
+ region->end_pfn = end_pfn;
+ list_add_tail(&region->list, &nosave_regions);
+ Report:
+ printk("swsusp: Registered nosave memory region: %016lx - %016lx\n",
+ start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
+}
+
+/*
+ * Set bits in this map correspond to the page frames the contents of which
+ * should not be saved during the suspend.
+ */
+static struct memory_bitmap *forbidden_pages_map;
+
+/* Set bits in this map correspond to free page frames. */
+static struct memory_bitmap *free_pages_map;
+
+/*
+ * Each page frame allocated for creating the image is marked by setting the
+ * corresponding bits in forbidden_pages_map and free_pages_map simultaneously
+ */
+
+void swsusp_set_page_free(struct page *page)
+{
+ if (free_pages_map)
+ memory_bm_set_bit(free_pages_map, page_to_pfn(page));
+}
+
+static int swsusp_page_is_free(struct page *page)
+{
+ return free_pages_map ?
+ memory_bm_test_bit(free_pages_map, page_to_pfn(page)) : 0;
+}
+
+void swsusp_unset_page_free(struct page *page)
+{
+ if (free_pages_map)
+ memory_bm_clear_bit(free_pages_map, page_to_pfn(page));
+}
+
+static void swsusp_set_page_forbidden(struct page *page)
+{
+ if (forbidden_pages_map)
+ memory_bm_set_bit(forbidden_pages_map, page_to_pfn(page));
+}
+
+int swsusp_page_is_forbidden(struct page *page)
+{
+ return forbidden_pages_map ?
+ memory_bm_test_bit(forbidden_pages_map, page_to_pfn(page)) : 0;
+}
+
+static void swsusp_unset_page_forbidden(struct page *page)
+{
+ if (forbidden_pages_map)
+ memory_bm_clear_bit(forbidden_pages_map, page_to_pfn(page));
+}
+
+/**
+ * mark_nosave_pages - set bits corresponding to the page frames the
+ * contents of which should not be saved in a given bitmap.
+ */
+
+static void mark_nosave_pages(struct memory_bitmap *bm)
+{
+ struct nosave_region *region;
+
+ if (list_empty(&nosave_regions))
+ return;
+
+ list_for_each_entry(region, &nosave_regions, list) {
+ unsigned long pfn;
+
+ printk("swsusp: Marking nosave pages: %016lx - %016lx\n",
+ region->start_pfn << PAGE_SHIFT,
+ region->end_pfn << PAGE_SHIFT);
+
+ for (pfn = region->start_pfn; pfn < region->end_pfn; pfn++)
+ memory_bm_set_bit(bm, pfn);
+ }
+}
+
+/**
+ * create_basic_memory_bitmaps - create bitmaps needed for marking page
+ * frames that should not be saved and free page frames. The pointers
+ * forbidden_pages_map and free_pages_map are only modified if everything
+ * goes well, because we don't want the bits to be used before both bitmaps
+ * are set up.
+ */
+
+int create_basic_memory_bitmaps(void)
+{
+ struct memory_bitmap *bm1, *bm2;
+ int error = 0;
+
+ BUG_ON(forbidden_pages_map || free_pages_map);
+
+ bm1 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
+ if (!bm1)
+ return -ENOMEM;
+
+ error = memory_bm_create(bm1, GFP_KERNEL, PG_ANY);
+ if (error)
+ goto Free_first_object;
+
+ bm2 = kzalloc(sizeof(struct memory_bitmap), GFP_KERNEL);
+ if (!bm2)
+ goto Free_first_bitmap;
+
+ error = memory_bm_create(bm2, GFP_KERNEL, PG_ANY);
+ if (error)
+ goto Free_second_object;
+
+ forbidden_pages_map = bm1;
+ free_pages_map = bm2;
+ mark_nosave_pages(forbidden_pages_map);
+
+ printk("swsusp: Basic memory bitmaps created\n");
+
+ return 0;
+
+ Free_second_object:
+ kfree(bm2);
+ Free_first_bitmap:
+ memory_bm_free(bm1, PG_UNSAFE_CLEAR);
+ Free_first_object:
+ kfree(bm1);
+ return -ENOMEM;
+}
+
+/**
+ * free_basic_memory_bitmaps - free memory bitmaps allocated by
+ * create_basic_memory_bitmaps(). The auxiliary pointers are necessary
+ * so that the bitmaps themselves are not referred to while they are being
+ * freed.
+ */
+
+void free_basic_memory_bitmaps(void)
+{
+ struct memory_bitmap *bm1, *bm2;
+
+ BUG_ON(!(forbidden_pages_map && free_pages_map));
+
+ bm1 = forbidden_pages_map;
+ bm2 = free_pages_map;
+ forbidden_pages_map = NULL;
+ free_pages_map = NULL;
+ memory_bm_free(bm1, PG_UNSAFE_CLEAR);
+ kfree(bm1);
+ memory_bm_free(bm2, PG_UNSAFE_CLEAR);
+ kfree(bm2);
+
+ printk("swsusp: Basic memory bitmaps freed\n");
+}
+
+/**
* snapshot_additional_pages - estimate the number of additional pages
* be needed for setting up the suspend image data structures for given
* zone (usually the returned value is greater than the exact number)
@@ -615,7 +838,8 @@ static struct page *saveable_highmem_page(unsigned long pfn)
BUG_ON(!PageHighMem(page));
- if (PageNosave(page) || PageReserved(page) || PageNosaveFree(page))
+ if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page) ||
+ PageReserved(page))
return NULL;
return page;
@@ -651,17 +875,6 @@ static inline unsigned int count_highmem_pages(void) { return 0; }
#endif /* CONFIG_HIGHMEM */
/**
- * pfn_is_nosave - check if given pfn is in the 'nosave' section
- */
-
-static inline int pfn_is_nosave(unsigned long pfn)
-{
- unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
- unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end)) >> PAGE_SHIFT;
- return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn);
-}
-
-/**
* saveable - Determine whether a non-highmem page should be included in
* the suspend image.
*
@@ -681,7 +894,7 @@ static struct page *saveable_page(unsigned long pfn)
BUG_ON(PageHighMem(page));
- if (PageNosave(page) || PageNosaveFree(page))
+ if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
return NULL;
if (PageReserved(page) && pfn_is_nosave(pfn))
@@ -821,9 +1034,10 @@ void swsusp_free(void)
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
- if (PageNosave(page) && PageNosaveFree(page)) {
- ClearPageNosave(page);
- ClearPageNosaveFree(page);
+ if (swsusp_page_is_forbidden(page) &&
+ swsusp_page_is_free(page)) {
+ swsusp_unset_page_forbidden(page);
+ swsusp_unset_page_free(page);
__free_page(page);
}
}
@@ -1019,7 +1233,7 @@ asmlinkage int swsusp_save(void)
nr_copy_pages = nr_pages;
nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
- printk("swsusp: critical section/: done (%d pages copied)\n", nr_pages);
+ printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);
return 0;
}
@@ -1146,7 +1360,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm)
max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
if (pfn_valid(pfn))
- ClearPageNosaveFree(pfn_to_page(pfn));
+ swsusp_unset_page_free(pfn_to_page(pfn));
}
/* Mark pages that correspond to the "original" pfns as "unsafe" */
@@ -1155,7 +1369,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm)
pfn = memory_bm_next_pfn(bm);
if (likely(pfn != BM_END_OF_MAP)) {
if (likely(pfn_valid(pfn)))
- SetPageNosaveFree(pfn_to_page(pfn));
+ swsusp_set_page_free(pfn_to_page(pfn));
else
return -EFAULT;
}
@@ -1321,14 +1535,14 @@ prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p)
struct page *page;
page = alloc_page(__GFP_HIGHMEM);
- if (!PageNosaveFree(page)) {
+ if (!swsusp_page_is_free(page)) {
/* The page is "safe", set its bit the bitmap */
memory_bm_set_bit(bm, page_to_pfn(page));
safe_highmem_pages++;
}
/* Mark the page as allocated */
- SetPageNosave(page);
- SetPageNosaveFree(page);
+ swsusp_set_page_forbidden(page);
+ swsusp_set_page_free(page);
}
memory_bm_position_reset(bm);
safe_highmem_bm = bm;
@@ -1360,7 +1574,7 @@ get_highmem_page_buffer(struct page *page, struct chain_allocator *ca)
struct highmem_pbe *pbe;
void *kaddr;
- if (PageNosave(page) && PageNosaveFree(page)) {
+ if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) {
/* We have allocated the "original" page frame and we can
* use it directly to store the loaded page.
*/
@@ -1522,14 +1736,14 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
error = -ENOMEM;
goto Free;
}
- if (!PageNosaveFree(virt_to_page(lp))) {
+ if (!swsusp_page_is_free(virt_to_page(lp))) {
/* The page is "safe", add it to the list */
lp->next = safe_pages_list;
safe_pages_list = lp;
}
/* Mark the page as allocated */
- SetPageNosave(virt_to_page(lp));
- SetPageNosaveFree(virt_to_page(lp));
+ swsusp_set_page_forbidden(virt_to_page(lp));
+ swsusp_set_page_free(virt_to_page(lp));
nr_pages--;
}
/* Free the reserved safe pages so that chain_alloc() can use them */
@@ -1558,7 +1772,7 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
if (PageHighMem(page))
return get_highmem_page_buffer(page, ca);
- if (PageNosave(page) && PageNosaveFree(page))
+ if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page))
/* We have allocated the "original" page frame and we can
* use it directly to store the loaded page.
*/
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 3581f8f86ac..b8b235cc19d 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/version.h>
@@ -33,12 +32,14 @@ extern char resume_file[];
#define SWSUSP_SIG "S1SUSPEND"
-static struct swsusp_header {
+struct swsusp_header {
char reserved[PAGE_SIZE - 20 - sizeof(sector_t)];
sector_t image;
char orig_sig[10];
char sig[10];
-} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
+} __attribute__((packed));
+
+static struct swsusp_header *swsusp_header;
/*
* General things
@@ -141,14 +142,14 @@ static int mark_swapfiles(sector_t start)
{
int error;
- bio_read_page(swsusp_resume_block, &swsusp_header, NULL);
- if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
- !memcmp("SWAPSPACE2",swsusp_header.sig, 10)) {
- memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
- memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
- swsusp_header.image = start;
+ bio_read_page(swsusp_resume_block, swsusp_header, NULL);
+ if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
+ !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
+ memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
+ memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
+ swsusp_header->image = start;
error = bio_write_page(swsusp_resume_block,
- &swsusp_header, NULL);
+ swsusp_header, NULL);
} else {
printk(KERN_ERR "swsusp: Swap header not found!\n");
error = -ENODEV;
@@ -241,7 +242,6 @@ struct swap_map_page {
struct swap_map_handle {
struct swap_map_page *cur;
sector_t cur_swap;
- struct bitmap_page *bitmap;
unsigned int k;
};
@@ -250,9 +250,6 @@ static void release_swap_writer(struct swap_map_handle *handle)
if (handle->cur)
free_page((unsigned long)handle->cur);
handle->cur = NULL;
- if (handle->bitmap)
- free_bitmap(handle->bitmap);
- handle->bitmap = NULL;
}
static int get_swap_writer(struct swap_map_handle *handle)
@@ -260,12 +257,7 @@ static int get_swap_writer(struct swap_map_handle *handle)
handle->cur = (struct swap_map_page *)get_zeroed_page(GFP_KERNEL);
if (!handle->cur)
return -ENOMEM;
- handle->bitmap = alloc_bitmap(count_swap_pages(root_swap, 0));
- if (!handle->bitmap) {
- release_swap_writer(handle);
- return -ENOMEM;
- }
- handle->cur_swap = alloc_swapdev_block(root_swap, handle->bitmap);
+ handle->cur_swap = alloc_swapdev_block(root_swap);
if (!handle->cur_swap) {
release_swap_writer(handle);
return -ENOSPC;
@@ -282,7 +274,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
if (!handle->cur)
return -EINVAL;
- offset = alloc_swapdev_block(root_swap, handle->bitmap);
+ offset = alloc_swapdev_block(root_swap);
error = write_page(buf, offset, bio_chain);
if (error)
return error;
@@ -291,7 +283,7 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
error = wait_on_bio_chain(bio_chain);
if (error)
goto out;
- offset = alloc_swapdev_block(root_swap, handle->bitmap);
+ offset = alloc_swapdev_block(root_swap);
if (!offset)
return -ENOSPC;
handle->cur->next_swap = offset;
@@ -428,7 +420,8 @@ int swsusp_write(void)
}
}
if (error)
- free_all_swap_pages(root_swap, handle.bitmap);
+ free_all_swap_pages(root_swap);
+
release_swap_writer(&handle);
out:
swsusp_close();
@@ -564,7 +557,7 @@ int swsusp_read(void)
if (error < PAGE_SIZE)
return error < 0 ? error : -EFAULT;
header = (struct swsusp_info *)data_of(snapshot);
- error = get_swap_reader(&handle, swsusp_header.image);
+ error = get_swap_reader(&handle, swsusp_header->image);
if (!error)
error = swap_read_page(&handle, header, NULL);
if (!error)
@@ -591,17 +584,17 @@ int swsusp_check(void)
resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
if (!IS_ERR(resume_bdev)) {
set_blocksize(resume_bdev, PAGE_SIZE);
- memset(&swsusp_header, 0, sizeof(swsusp_header));
+ memset(swsusp_header, 0, sizeof(PAGE_SIZE));
error = bio_read_page(swsusp_resume_block,
- &swsusp_header, NULL);
+ swsusp_header, NULL);
if (error)
return error;
- if (!memcmp(SWSUSP_SIG, swsusp_header.sig, 10)) {
- memcpy(swsusp_header.sig, swsusp_header.orig_sig, 10);
+ if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
+ memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
/* Reset swap signature now */
error = bio_write_page(swsusp_resume_block,
- &swsusp_header, NULL);
+ swsusp_header, NULL);
} else {
return -EINVAL;
}
@@ -632,3 +625,13 @@ void swsusp_close(void)
blkdev_put(resume_bdev);
}
+
+static int swsusp_header_init(void)
+{
+ swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL);
+ if (!swsusp_header)
+ panic("Could not allocate memory for swsusp_header\n");
+ return 0;
+}
+
+core_initcall(swsusp_header_init);
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 175370824f3..5da304c8f1f 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -50,6 +50,7 @@
#include <linux/syscalls.h>
#include <linux/highmem.h>
#include <linux/time.h>
+#include <linux/rbtree.h>
#include "power.h"
@@ -74,72 +75,69 @@ static inline unsigned int count_highmem_pages(void) { return 0; }
/**
* The following functions are used for tracing the allocated
* swap pages, so that they can be freed in case of an error.
- *
- * The functions operate on a linked bitmap structure defined
- * in power.h
*/
-void free_bitmap(struct bitmap_page *bitmap)
-{
- struct bitmap_page *bp;
+struct swsusp_extent {
+ struct rb_node node;
+ unsigned long start;
+ unsigned long end;
+};
- while (bitmap) {
- bp = bitmap->next;
- free_page((unsigned long)bitmap);
- bitmap = bp;
- }
-}
+static struct rb_root swsusp_extents = RB_ROOT;
-struct bitmap_page *alloc_bitmap(unsigned int nr_bits)
+static int swsusp_extents_insert(unsigned long swap_offset)
{
- struct bitmap_page *bitmap, *bp;
- unsigned int n;
-
- if (!nr_bits)
- return NULL;
-
- bitmap = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL);
- bp = bitmap;
- for (n = BITMAP_PAGE_BITS; n < nr_bits; n += BITMAP_PAGE_BITS) {
- bp->next = (struct bitmap_page *)get_zeroed_page(GFP_KERNEL);
- bp = bp->next;
- if (!bp) {
- free_bitmap(bitmap);
- return NULL;
+ struct rb_node **new = &(swsusp_extents.rb_node);
+ struct rb_node *parent = NULL;
+ struct swsusp_extent *ext;
+
+ /* Figure out where to put the new node */
+ while (*new) {
+ ext = container_of(*new, struct swsusp_extent, node);
+ parent = *new;
+ if (swap_offset < ext->start) {
+ /* Try to merge */
+ if (swap_offset == ext->start - 1) {
+ ext->start--;
+ return 0;
+ }
+ new = &((*new)->rb_left);
+ } else if (swap_offset > ext->end) {
+ /* Try to merge */
+ if (swap_offset == ext->end + 1) {
+ ext->end++;
+ return 0;
+ }
+ new = &((*new)->rb_right);
+ } else {
+ /* It already is in the tree */
+ return -EINVAL;
}
}
- return bitmap;
-}
-
-static int bitmap_set(struct bitmap_page *bitmap, unsigned long bit)
-{
- unsigned int n;
-
- n = BITMAP_PAGE_BITS;
- while (bitmap && n <= bit) {
- n += BITMAP_PAGE_BITS;
- bitmap = bitmap->next;
- }
- if (!bitmap)
- return -EINVAL;
- n -= BITMAP_PAGE_BITS;
- bit -= n;
- n = 0;
- while (bit >= BITS_PER_CHUNK) {
- bit -= BITS_PER_CHUNK;
- n++;
- }
- bitmap->chunks[n] |= (1UL << bit);
+ /* Add the new node and rebalance the tree. */
+ ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL);
+ if (!ext)
+ return -ENOMEM;
+
+ ext->start = swap_offset;
+ ext->end = swap_offset;
+ rb_link_node(&ext->node, parent, new);
+ rb_insert_color(&ext->node, &swsusp_extents);
return 0;
}
-sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap)
+/**
+ * alloc_swapdev_block - allocate a swap page and register that it has
+ * been allocated, so that it can be freed in case of an error.
+ */
+
+sector_t alloc_swapdev_block(int swap)
{
unsigned long offset;
offset = swp_offset(get_swap_page_of_type(swap));
if (offset) {
- if (bitmap_set(bitmap, offset))
+ if (swsusp_extents_insert(offset))
swap_free(swp_entry(swap, offset));
else
return swapdev_block(swap, offset);
@@ -147,23 +145,34 @@ sector_t alloc_swapdev_block(int swap, struct bitmap_page *bitmap)
return 0;
}
-void free_all_swap_pages(int swap, struct bitmap_page *bitmap)
+/**
+ * free_all_swap_pages - free swap pages allocated for saving image data.
+ * It also frees the extents used to register which swap entres had been
+ * allocated.
+ */
+
+void free_all_swap_pages(int swap)
{
- unsigned int bit, n;
- unsigned long test;
-
- bit = 0;
- while (bitmap) {
- for (n = 0; n < BITMAP_PAGE_CHUNKS; n++)
- for (test = 1UL; test; test <<= 1) {
- if (bitmap->chunks[n] & test)
- swap_free(swp_entry(swap, bit));
- bit++;
- }
- bitmap = bitmap->next;
+ struct rb_node *node;
+
+ while ((node = swsusp_extents.rb_node)) {
+ struct swsusp_extent *ext;
+ unsigned long offset;
+
+ ext = container_of(node, struct swsusp_extent, node);
+ rb_erase(node, &swsusp_extents);
+ for (offset = ext->start; offset <= ext->end; offset++)
+ swap_free(swp_entry(swap, offset));
+
+ kfree(ext);
}
}
+int swsusp_swap_in_use(void)
+{
+ return (swsusp_extents.rb_node != NULL);
+}
+
/**
* swsusp_show_speed - print the time elapsed between two events represented by
* @start and @stop
@@ -224,7 +233,7 @@ int swsusp_shrink_memory(void)
long size, highmem_size;
highmem_size = count_highmem_pages();
- size = count_data_pages() + PAGES_FOR_IO;
+ size = count_data_pages() + PAGES_FOR_IO + SPARE_PAGES;
tmp = size;
size += highmem_size;
for_each_zone (zone)
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 7cf6713b232..24d7d78e6f4 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -33,25 +33,29 @@
static struct snapshot_data {
struct snapshot_handle handle;
int swap;
- struct bitmap_page *bitmap;
int mode;
char frozen;
char ready;
char platform_suspend;
} snapshot_state;
-static atomic_t device_available = ATOMIC_INIT(1);
+atomic_t snapshot_device_available = ATOMIC_INIT(1);
static int snapshot_open(struct inode *inode, struct file *filp)
{
struct snapshot_data *data;
- if (!atomic_add_unless(&device_available, -1, 0))
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0))
return -EBUSY;
- if ((filp->f_flags & O_ACCMODE) == O_RDWR)
+ if ((filp->f_flags & O_ACCMODE) == O_RDWR) {
+ atomic_inc(&snapshot_device_available);
return -ENOSYS;
-
+ }
+ if(create_basic_memory_bitmaps()) {
+ atomic_inc(&snapshot_device_available);
+ return -ENOMEM;
+ }
nonseekable_open(inode, filp);
data = &snapshot_state;
filp->private_data = data;
@@ -64,7 +68,6 @@ static int snapshot_open(struct inode *inode, struct file *filp)
data->swap = -1;
data->mode = O_WRONLY;
}
- data->bitmap = NULL;
data->frozen = 0;
data->ready = 0;
data->platform_suspend = 0;
@@ -77,16 +80,15 @@ static int snapshot_release(struct inode *inode, struct file *filp)
struct snapshot_data *data;
swsusp_free();
+ free_basic_memory_bitmaps();
data = filp->private_data;
- free_all_swap_pages(data->swap, data->bitmap);
- free_bitmap(data->bitmap);
+ free_all_swap_pages(data->swap);
if (data->frozen) {
mutex_lock(&pm_mutex);
thaw_processes();
- enable_nonboot_cpus();
mutex_unlock(&pm_mutex);
}
- atomic_inc(&device_available);
+ atomic_inc(&snapshot_device_available);
return 0;
}
@@ -128,16 +130,16 @@ static inline int platform_prepare(void)
{
int error = 0;
- if (pm_ops && pm_ops->prepare)
- error = pm_ops->prepare(PM_SUSPEND_DISK);
+ if (hibernation_ops)
+ error = hibernation_ops->prepare();
return error;
}
static inline void platform_finish(void)
{
- if (pm_ops && pm_ops->finish)
- pm_ops->finish(PM_SUSPEND_DISK);
+ if (hibernation_ops)
+ hibernation_ops->finish();
}
static inline int snapshot_suspend(int platform_suspend)
@@ -294,14 +296,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -ENODEV;
break;
}
- if (!data->bitmap) {
- data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0));
- if (!data->bitmap) {
- error = -ENOMEM;
- break;
- }
- }
- offset = alloc_swapdev_block(data->swap, data->bitmap);
+ offset = alloc_swapdev_block(data->swap);
if (offset) {
offset <<= PAGE_SHIFT;
error = put_user(offset, (sector_t __user *)arg);
@@ -315,13 +310,11 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -ENODEV;
break;
}
- free_all_swap_pages(data->swap, data->bitmap);
- free_bitmap(data->bitmap);
- data->bitmap = NULL;
+ free_all_swap_pages(data->swap);
break;
case SNAPSHOT_SET_SWAP_FILE:
- if (!data->bitmap) {
+ if (!swsusp_swap_in_use()) {
/*
* User space encodes device types as two-byte values,
* so we need to recode them
@@ -391,7 +384,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
switch (arg) {
case PMOPS_PREPARE:
- if (pm_ops && pm_ops->enter) {
+ if (hibernation_ops) {
data->platform_suspend = 1;
error = 0;
} else {
@@ -402,8 +395,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
case PMOPS_ENTER:
if (data->platform_suspend) {
kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
- error = pm_ops->enter(PM_SUSPEND_DISK);
- error = 0;
+ error = hibernation_ops->enter();
}
break;
@@ -420,7 +412,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
break;
case SNAPSHOT_SET_SWAP_AREA:
- if (data->bitmap) {
+ if (swsusp_swap_in_use()) {
error = -EPERM;
} else {
struct resume_swap_area swap_area;
diff --git a/kernel/printk.c b/kernel/printk.c
index 4b47e59248d..0bbdeac2810 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -20,7 +20,6 @@
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
-#include <linux/smp_lock.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -931,8 +930,16 @@ void register_console(struct console *console)
{
int i;
unsigned long flags;
+ struct console *bootconsole = NULL;
- if (preferred_console < 0)
+ if (console_drivers) {
+ if (console->flags & CON_BOOT)
+ return;
+ if (console_drivers->flags & CON_BOOT)
+ bootconsole = console_drivers;
+ }
+
+ if (preferred_console < 0 || bootconsole || !console_drivers)
preferred_console = selected_console;
/*
@@ -978,8 +985,11 @@ void register_console(struct console *console)
if (!(console->flags & CON_ENABLED))
return;
- if (console_drivers && (console_drivers->flags & CON_BOOT)) {
- unregister_console(console_drivers);
+ if (bootconsole) {
+ printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n",
+ bootconsole->name, bootconsole->index,
+ console->name, console->index);
+ unregister_console(bootconsole);
console->flags &= ~CON_PRINTBUFFER;
}
@@ -1030,16 +1040,11 @@ int unregister_console(struct console *console)
}
}
- /* If last console is removed, we re-enable picking the first
- * one that gets registered. Without that, pmac early boot console
- * would prevent fbcon from taking over.
- *
+ /*
* If this isn't the last console and it has CON_CONSDEV set, we
* need to set it on the next preferred console.
*/
- if (console_drivers == NULL)
- preferred_console = selected_console;
- else if (console->flags & CON_CONSDEV)
+ if (console_drivers != NULL && console->flags & CON_CONSDEV)
console_drivers->flags |= CON_CONSDEV;
release_console_sem();
diff --git a/kernel/profile.c b/kernel/profile.c
index 9bfadb248dd..cc91b9bf759 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -340,6 +340,7 @@ static int __devinit profile_cpu_callback(struct notifier_block *info,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
node = cpu_to_node(cpu);
per_cpu(cpu_profile_flip, cpu) = 0;
if (!per_cpu(cpu_profile_hits, cpu)[1]) {
@@ -365,10 +366,13 @@ static int __devinit profile_cpu_callback(struct notifier_block *info,
__free_page(page);
return NOTIFY_BAD;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
cpu_set(cpu, prof_cpu_mask);
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
cpu_clear(cpu, prof_cpu_mask);
if (per_cpu(cpu_profile_hits, cpu)[0]) {
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 3554b76da84..2c2dd8410dc 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -558,9 +558,11 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
long cpu = (long)hcpu;
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
rcu_online_cpu(cpu);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
rcu_offline_cpu(cpu);
break;
default:
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index bcd14e83ef3..55ba82a85a6 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -502,10 +502,6 @@ static struct rcu_torture_ops sched_ops = {
.name = "sched"
};
-static struct rcu_torture_ops *torture_ops[] =
- { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops,
- &sched_ops, NULL };
-
/*
* RCU torture writer kthread. Repeatedly substitutes a new structure
* for that pointed to by rcu_torture_current, freeing the old structure
@@ -534,7 +530,7 @@ rcu_torture_writer(void *arg)
rp->rtort_mbtest = 1;
rcu_assign_pointer(rcu_torture_current, rp);
smp_wmb();
- if (old_rp != NULL) {
+ if (old_rp) {
i = old_rp->rtort_pipe_count;
if (i > RCU_TORTURE_PIPE_LEN)
i = RCU_TORTURE_PIPE_LEN;
@@ -685,7 +681,7 @@ rcu_torture_printk(char *page)
atomic_read(&rcu_torture_wcount[i]));
}
cnt += sprintf(&page[cnt], "\n");
- if (cur_ops->stats != NULL)
+ if (cur_ops->stats)
cnt += cur_ops->stats(&page[cnt]);
return cnt;
}
@@ -749,13 +745,13 @@ static void rcu_torture_shuffle_tasks(void)
set_cpus_allowed(current, tmp_mask);
- if (reader_tasks != NULL) {
+ if (reader_tasks) {
for (i = 0; i < nrealreaders; i++)
if (reader_tasks[i])
set_cpus_allowed(reader_tasks[i], tmp_mask);
}
- if (fakewriter_tasks != NULL) {
+ if (fakewriter_tasks) {
for (i = 0; i < nfakewriters; i++)
if (fakewriter_tasks[i])
set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
@@ -808,21 +804,21 @@ rcu_torture_cleanup(void)
int i;
fullstop = 1;
- if (shuffler_task != NULL) {
+ if (shuffler_task) {
VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
kthread_stop(shuffler_task);
}
shuffler_task = NULL;
- if (writer_task != NULL) {
+ if (writer_task) {
VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
kthread_stop(writer_task);
}
writer_task = NULL;
- if (reader_tasks != NULL) {
+ if (reader_tasks) {
for (i = 0; i < nrealreaders; i++) {
- if (reader_tasks[i] != NULL) {
+ if (reader_tasks[i]) {
VERBOSE_PRINTK_STRING(
"Stopping rcu_torture_reader task");
kthread_stop(reader_tasks[i]);
@@ -834,9 +830,9 @@ rcu_torture_cleanup(void)
}
rcu_torture_current = NULL;
- if (fakewriter_tasks != NULL) {
+ if (fakewriter_tasks) {
for (i = 0; i < nfakewriters; i++) {
- if (fakewriter_tasks[i] != NULL) {
+ if (fakewriter_tasks[i]) {
VERBOSE_PRINTK_STRING(
"Stopping rcu_torture_fakewriter task");
kthread_stop(fakewriter_tasks[i]);
@@ -847,7 +843,7 @@ rcu_torture_cleanup(void)
fakewriter_tasks = NULL;
}
- if (stats_task != NULL) {
+ if (stats_task) {
VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
kthread_stop(stats_task);
}
@@ -858,7 +854,7 @@ rcu_torture_cleanup(void)
rcu_torture_stats_print(); /* -After- the stats thread is stopped! */
- if (cur_ops->cleanup != NULL)
+ if (cur_ops->cleanup)
cur_ops->cleanup();
if (atomic_read(&n_rcu_torture_error))
rcu_torture_print_module_parms("End of test: FAILURE");
@@ -866,27 +862,28 @@ rcu_torture_cleanup(void)
rcu_torture_print_module_parms("End of test: SUCCESS");
}
-static int
+static int __init
rcu_torture_init(void)
{
int i;
int cpu;
int firsterr = 0;
+ static struct rcu_torture_ops *torture_ops[] =
+ { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
+ &srcu_ops, &sched_ops, };
/* Process args and tell the world that the torturer is on the job. */
-
- for (i = 0; cur_ops = torture_ops[i], cur_ops != NULL; i++) {
+ for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
cur_ops = torture_ops[i];
- if (strcmp(torture_type, cur_ops->name) == 0) {
+ if (strcmp(torture_type, cur_ops->name) == 0)
break;
- }
}
- if (cur_ops == NULL) {
+ if (i == ARRAY_SIZE(torture_ops)) {
printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
torture_type);
return (-EINVAL);
}
- if (cur_ops->init != NULL)
+ if (cur_ops->init)
cur_ops->init(); /* no "goto unwind" prior to this point!!! */
if (nreaders >= 0)
@@ -899,7 +896,7 @@ rcu_torture_init(void)
/* Set up the freelist. */
INIT_LIST_HEAD(&rcu_torture_freelist);
- for (i = 0; i < sizeof(rcu_tortures) / sizeof(rcu_tortures[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(rcu_tortures); i++) {
rcu_tortures[i].rtort_mbtest = 0;
list_add_tail(&rcu_tortures[i].rtort_free,
&rcu_torture_freelist);
diff --git a/kernel/relay.c b/kernel/relay.c
index 577f251c7e2..4311101b0ca 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -310,16 +310,13 @@ static struct rchan_callbacks default_channel_callbacks = {
/**
* wakeup_readers - wake up readers waiting on a channel
- * @work: work struct that contains the the channel buffer
+ * @data: contains the channel buffer
*
- * This is the work function used to defer reader waking. The
- * reason waking is deferred is that calling directly from write
- * causes problems if you're writing from say the scheduler.
+ * This is the timer function used to defer reader waking.
*/
-static void wakeup_readers(struct work_struct *work)
+static void wakeup_readers(unsigned long data)
{
- struct rchan_buf *buf =
- container_of(work, struct rchan_buf, wake_readers.work);
+ struct rchan_buf *buf = (struct rchan_buf *)data;
wake_up_interruptible(&buf->read_wait);
}
@@ -337,11 +334,9 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init)
if (init) {
init_waitqueue_head(&buf->read_wait);
kref_init(&buf->kref);
- INIT_DELAYED_WORK(&buf->wake_readers, NULL);
- } else {
- cancel_delayed_work(&buf->wake_readers);
- flush_scheduled_work();
- }
+ setup_timer(&buf->timer, wakeup_readers, (unsigned long)buf);
+ } else
+ del_timer_sync(&buf->timer);
buf->subbufs_produced = 0;
buf->subbufs_consumed = 0;
@@ -447,8 +442,7 @@ end:
static void relay_close_buf(struct rchan_buf *buf)
{
buf->finalized = 1;
- cancel_delayed_work(&buf->wake_readers);
- flush_scheduled_work();
+ del_timer_sync(&buf->timer);
kref_put(&buf->kref, relay_remove_buf);
}
@@ -490,6 +484,7 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
switch(action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
mutex_lock(&relay_channels_mutex);
list_for_each_entry(chan, &relay_channels, list) {
if (chan->buf[hotcpu])
@@ -506,6 +501,7 @@ static int __cpuinit relay_hotcpu_callback(struct notifier_block *nb,
mutex_unlock(&relay_channels_mutex);
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
/* No need to flush the cpu : will be flushed upon
* final relay_flush() call. */
break;
@@ -608,11 +604,14 @@ size_t relay_switch_subbuf(struct rchan_buf *buf, size_t length)
buf->dentry->d_inode->i_size += buf->chan->subbuf_size -
buf->padding[old_subbuf];
smp_mb();
- if (waitqueue_active(&buf->read_wait)) {
- PREPARE_DELAYED_WORK(&buf->wake_readers,
- wakeup_readers);
- schedule_delayed_work(&buf->wake_readers, 1);
- }
+ if (waitqueue_active(&buf->read_wait))
+ /*
+ * Calling wake_up_interruptible() from here
+ * will deadlock if we happen to be logging
+ * from the scheduler (trying to re-grab
+ * rq->lock), so defer it.
+ */
+ __mod_timer(&buf->timer, jiffies + 1);
}
old = buf->data;
diff --git a/kernel/resource.c b/kernel/resource.c
index bdb55a33f96..9bd14fd3e6d 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -213,27 +213,6 @@ int request_resource(struct resource *root, struct resource *new)
EXPORT_SYMBOL(request_resource);
/**
- * ____request_resource - reserve a resource, with resource conflict returned
- * @root: root resource descriptor
- * @new: resource descriptor desired by caller
- *
- * Returns:
- * On success, NULL is returned.
- * On error, a pointer to the conflicting resource is returned.
- */
-struct resource *____request_resource(struct resource *root, struct resource *new)
-{
- struct resource *conflict;
-
- write_lock(&resource_lock);
- conflict = __request_resource(root, new);
- write_unlock(&resource_lock);
- return conflict;
-}
-
-EXPORT_SYMBOL(____request_resource);
-
-/**
* release_resource - release a previously reserved resource
* @old: resource pointer
*/
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
index 180978cb2f7..12879f6c1ec 100644
--- a/kernel/rtmutex.c
+++ b/kernel/rtmutex.c
@@ -56,7 +56,7 @@
* state.
*/
-static void
+void
rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
unsigned long mask)
{
@@ -81,29 +81,6 @@ static void fixup_rt_mutex_waiters(struct rt_mutex *lock)
}
/*
- * We can speed up the acquire/release, if the architecture
- * supports cmpxchg and if there's no debugging state to be set up
- */
-#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
-# define rt_mutex_cmpxchg(l,c,n) (cmpxchg(&l->owner, c, n) == c)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
- unsigned long owner, *p = (unsigned long *) &lock->owner;
-
- do {
- owner = *p;
- } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
-}
-#else
-# define rt_mutex_cmpxchg(l,c,n) (0)
-static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
-{
- lock->owner = (struct task_struct *)
- ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
-}
-#endif
-
-/*
* Calculate task priority from the waiter list priority
*
* Return task->normal_prio when the waiter list is empty or when
@@ -123,7 +100,7 @@ int rt_mutex_getprio(struct task_struct *task)
*
* This can be both boosting and unboosting. task->pi_lock must be held.
*/
-static void __rt_mutex_adjust_prio(struct task_struct *task)
+void __rt_mutex_adjust_prio(struct task_struct *task)
{
int prio = rt_mutex_getprio(task);
@@ -159,11 +136,11 @@ int max_lock_depth = 1024;
* Decreases task's usage by one - may thus free the task.
* Returns 0 or -EDEADLK.
*/
-static int rt_mutex_adjust_prio_chain(struct task_struct *task,
- int deadlock_detect,
- struct rt_mutex *orig_lock,
- struct rt_mutex_waiter *orig_waiter,
- struct task_struct *top_task)
+int rt_mutex_adjust_prio_chain(struct task_struct *task,
+ int deadlock_detect,
+ struct rt_mutex *orig_lock,
+ struct rt_mutex_waiter *orig_waiter,
+ struct task_struct *top_task)
{
struct rt_mutex *lock;
struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter;
@@ -524,8 +501,8 @@ static void wakeup_next_waiter(struct rt_mutex *lock)
*
* Must be called with lock->wait_lock held
*/
-static void remove_waiter(struct rt_mutex *lock,
- struct rt_mutex_waiter *waiter)
+void remove_waiter(struct rt_mutex *lock,
+ struct rt_mutex_waiter *waiter)
{
int first = (waiter == rt_mutex_top_waiter(lock));
struct task_struct *owner = rt_mutex_owner(lock);
diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h
index 9c75856e791..242ec7ee740 100644
--- a/kernel/rtmutex_common.h
+++ b/kernel/rtmutex_common.h
@@ -113,6 +113,29 @@ static inline unsigned long rt_mutex_owner_pending(struct rt_mutex *lock)
}
/*
+ * We can speed up the acquire/release, if the architecture
+ * supports cmpxchg and if there's no debugging state to be set up
+ */
+#if defined(__HAVE_ARCH_CMPXCHG) && !defined(CONFIG_DEBUG_RT_MUTEXES)
+# define rt_mutex_cmpxchg(l,c,n) (cmpxchg(&l->owner, c, n) == c)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+ unsigned long owner, *p = (unsigned long *) &lock->owner;
+
+ do {
+ owner = *p;
+ } while (cmpxchg(p, owner, owner | RT_MUTEX_HAS_WAITERS) != owner);
+}
+#else
+# define rt_mutex_cmpxchg(l,c,n) (0)
+static inline void mark_rt_mutex_waiters(struct rt_mutex *lock)
+{
+ lock->owner = (struct task_struct *)
+ ((unsigned long)lock->owner | RT_MUTEX_HAS_WAITERS);
+}
+#endif
+
+/*
* PI-futex support (proxy locking functions, etc.):
*/
extern struct task_struct *rt_mutex_next_owner(struct rt_mutex *lock);
@@ -120,4 +143,15 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
struct task_struct *proxy_owner);
extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
struct task_struct *proxy_owner);
+
+extern void rt_mutex_set_owner(struct rt_mutex *lock, struct task_struct *owner,
+ unsigned long mask);
+extern void __rt_mutex_adjust_prio(struct task_struct *task);
+extern int rt_mutex_adjust_prio_chain(struct task_struct *task,
+ int deadlock_detect,
+ struct rt_mutex *orig_lock,
+ struct rt_mutex_waiter *orig_waiter,
+ struct task_struct *top_task);
+extern void remove_waiter(struct rt_mutex *lock,
+ struct rt_mutex_waiter *waiter);
#endif
diff --git a/kernel/rwsem.c b/kernel/rwsem.c
index 291ded556aa..9a87886b022 100644
--- a/kernel/rwsem.c
+++ b/kernel/rwsem.c
@@ -60,7 +60,7 @@ int down_write_trylock(struct rw_semaphore *sem)
int ret = __down_write_trylock(sem);
if (ret == 1)
- rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
+ rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
return ret;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 960d7c5fca3..799d23b4e35 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -52,8 +52,9 @@
#include <linux/tsacct_kern.h>
#include <linux/kprobes.h>
#include <linux/delayacct.h>
-#include <asm/tlb.h>
+#include <linux/reciprocal_div.h>
+#include <asm/tlb.h>
#include <asm/unistd.h>
/*
@@ -181,6 +182,27 @@ static unsigned int static_prio_timeslice(int static_prio)
return SCALE_PRIO(DEF_TIMESLICE, static_prio);
}
+#ifdef CONFIG_SMP
+/*
+ * Divide a load by a sched group cpu_power : (load / sg->__cpu_power)
+ * Since cpu_power is a 'constant', we can use a reciprocal divide.
+ */
+static inline u32 sg_div_cpu_power(const struct sched_group *sg, u32 load)
+{
+ return reciprocal_divide(load, sg->reciprocal_cpu_power);
+}
+
+/*
+ * Each time a sched group cpu_power is changed,
+ * we must compute its reciprocal value
+ */
+static inline void sg_inc_cpu_power(struct sched_group *sg, u32 val)
+{
+ sg->__cpu_power += val;
+ sg->reciprocal_cpu_power = reciprocal_value(sg->__cpu_power);
+}
+#endif
+
/*
* task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
* to time slice values: [800ms ... 100ms ... 5ms]
@@ -223,6 +245,10 @@ struct rq {
unsigned long raw_weighted_load;
#ifdef CONFIG_SMP
unsigned long cpu_load[3];
+ unsigned char idle_at_tick;
+#ifdef CONFIG_NO_HZ
+ unsigned char in_nohz_recently;
+#endif
#endif
unsigned long long nr_switches;
@@ -278,7 +304,8 @@ struct rq {
struct lock_class_key rq_lock_key;
};
-static DEFINE_PER_CPU(struct rq, runqueues);
+static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
+static DEFINE_MUTEX(sched_hotcpu_mutex);
static inline int cpu_of(struct rq *rq)
{
@@ -1049,6 +1076,17 @@ static void resched_task(struct task_struct *p)
if (!tsk_is_polling(p))
smp_send_reschedule(cpu);
}
+
+static void resched_cpu(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long flags;
+
+ if (!spin_trylock_irqsave(&rq->lock, flags))
+ return;
+ resched_task(cpu_curr(cpu));
+ spin_unlock_irqrestore(&rq->lock, flags);
+}
#else
static inline void resched_task(struct task_struct *p)
{
@@ -1241,7 +1279,8 @@ find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
}
/* Adjust by relative CPU power of the group */
- avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
+ avg_load = sg_div_cpu_power(group,
+ avg_load * SCHED_LOAD_SCALE);
if (local_group) {
this_load = avg_load;
@@ -1368,7 +1407,16 @@ static int wake_idle(int cpu, struct task_struct *p)
struct sched_domain *sd;
int i;
- if (idle_cpu(cpu))
+ /*
+ * If it is idle, then it is the best cpu to run this task.
+ *
+ * This cpu is also the best, if it has more than one task already.
+ * Siblings must be also busy(in most cases) as they didn't already
+ * pickup the extra load from this cpu and hence we need not check
+ * sibling runqueue info. This will avoid the checks and cache miss
+ * penalities associated with that.
+ */
+ if (idle_cpu(cpu) || cpu_rq(cpu)->nr_running > 1)
return cpu;
for_each_domain(cpu, sd) {
@@ -2352,12 +2400,13 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
}
total_load += avg_load;
- total_pwr += group->cpu_power;
+ total_pwr += group->__cpu_power;
/* Adjust by relative CPU power of the group */
- avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
+ avg_load = sg_div_cpu_power(group,
+ avg_load * SCHED_LOAD_SCALE);
- group_capacity = group->cpu_power / SCHED_LOAD_SCALE;
+ group_capacity = group->__cpu_power / SCHED_LOAD_SCALE;
if (local_group) {
this_load = avg_load;
@@ -2468,8 +2517,8 @@ group_next:
max_pull = min(max_load - avg_load, max_load - busiest_load_per_task);
/* How much load to actually move to equalise the imbalance */
- *imbalance = min(max_pull * busiest->cpu_power,
- (avg_load - this_load) * this->cpu_power)
+ *imbalance = min(max_pull * busiest->__cpu_power,
+ (avg_load - this_load) * this->__cpu_power)
/ SCHED_LOAD_SCALE;
/*
@@ -2503,28 +2552,29 @@ small_imbalance:
* moving them.
*/
- pwr_now += busiest->cpu_power *
- min(busiest_load_per_task, max_load);
- pwr_now += this->cpu_power *
- min(this_load_per_task, this_load);
+ pwr_now += busiest->__cpu_power *
+ min(busiest_load_per_task, max_load);
+ pwr_now += this->__cpu_power *
+ min(this_load_per_task, this_load);
pwr_now /= SCHED_LOAD_SCALE;
/* Amount of load we'd subtract */
- tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
- busiest->cpu_power;
+ tmp = sg_div_cpu_power(busiest,
+ busiest_load_per_task * SCHED_LOAD_SCALE);
if (max_load > tmp)
- pwr_move += busiest->cpu_power *
+ pwr_move += busiest->__cpu_power *
min(busiest_load_per_task, max_load - tmp);
/* Amount of load we'd add */
- if (max_load * busiest->cpu_power <
+ if (max_load * busiest->__cpu_power <
busiest_load_per_task * SCHED_LOAD_SCALE)
- tmp = max_load * busiest->cpu_power / this->cpu_power;
+ tmp = sg_div_cpu_power(this,
+ max_load * busiest->__cpu_power);
else
- tmp = busiest_load_per_task * SCHED_LOAD_SCALE /
- this->cpu_power;
- pwr_move += this->cpu_power *
- min(this_load_per_task, this_load + tmp);
+ tmp = sg_div_cpu_power(this,
+ busiest_load_per_task * SCHED_LOAD_SCALE);
+ pwr_move += this->__cpu_power *
+ min(this_load_per_task, this_load + tmp);
pwr_move /= SCHED_LOAD_SCALE;
/* Move if we gain throughput */
@@ -2657,6 +2707,12 @@ redo:
double_rq_unlock(this_rq, busiest);
local_irq_restore(flags);
+ /*
+ * some other cpu did the load balance for us.
+ */
+ if (nr_moved && this_cpu != smp_processor_id())
+ resched_cpu(this_cpu);
+
/* All tasks on this runqueue were pinned by CPU affinity */
if (unlikely(all_pinned)) {
cpu_clear(cpu_of(busiest), cpus);
@@ -2927,32 +2983,98 @@ static void update_load(struct rq *this_rq)
}
}
+#ifdef CONFIG_NO_HZ
+static struct {
+ atomic_t load_balancer;
+ cpumask_t cpu_mask;
+} nohz ____cacheline_aligned = {
+ .load_balancer = ATOMIC_INIT(-1),
+ .cpu_mask = CPU_MASK_NONE,
+};
+
/*
- * run_rebalance_domains is triggered when needed from the scheduler tick.
+ * This routine will try to nominate the ilb (idle load balancing)
+ * owner among the cpus whose ticks are stopped. ilb owner will do the idle
+ * load balancing on behalf of all those cpus. If all the cpus in the system
+ * go into this tickless mode, then there will be no ilb owner (as there is
+ * no need for one) and all the cpus will sleep till the next wakeup event
+ * arrives...
*
+ * For the ilb owner, tick is not stopped. And this tick will be used
+ * for idle load balancing. ilb owner will still be part of
+ * nohz.cpu_mask..
+ *
+ * While stopping the tick, this cpu will become the ilb owner if there
+ * is no other owner. And will be the owner till that cpu becomes busy
+ * or if all cpus in the system stop their ticks at which point
+ * there is no need for ilb owner.
+ *
+ * When the ilb owner becomes busy, it nominates another owner, during the
+ * next busy scheduler_tick()
+ */
+int select_nohz_load_balancer(int stop_tick)
+{
+ int cpu = smp_processor_id();
+
+ if (stop_tick) {
+ cpu_set(cpu, nohz.cpu_mask);
+ cpu_rq(cpu)->in_nohz_recently = 1;
+
+ /*
+ * If we are going offline and still the leader, give up!
+ */
+ if (cpu_is_offline(cpu) &&
+ atomic_read(&nohz.load_balancer) == cpu) {
+ if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
+ BUG();
+ return 0;
+ }
+
+ /* time for ilb owner also to sleep */
+ if (cpus_weight(nohz.cpu_mask) == num_online_cpus()) {
+ if (atomic_read(&nohz.load_balancer) == cpu)
+ atomic_set(&nohz.load_balancer, -1);
+ return 0;
+ }
+
+ if (atomic_read(&nohz.load_balancer) == -1) {
+ /* make me the ilb owner */
+ if (atomic_cmpxchg(&nohz.load_balancer, -1, cpu) == -1)
+ return 1;
+ } else if (atomic_read(&nohz.load_balancer) == cpu)
+ return 1;
+ } else {
+ if (!cpu_isset(cpu, nohz.cpu_mask))
+ return 0;
+
+ cpu_clear(cpu, nohz.cpu_mask);
+
+ if (atomic_read(&nohz.load_balancer) == cpu)
+ if (atomic_cmpxchg(&nohz.load_balancer, cpu, -1) != cpu)
+ BUG();
+ }
+ return 0;
+}
+#endif
+
+static DEFINE_SPINLOCK(balancing);
+
+/*
* It checks each scheduling domain to see if it is due to be balanced,
* and initiates a balancing operation if so.
*
* Balancing parameters are set up in arch_init_sched_domains.
*/
-static DEFINE_SPINLOCK(balancing);
-
-static void run_rebalance_domains(struct softirq_action *h)
+static inline void rebalance_domains(int cpu, enum idle_type idle)
{
- int this_cpu = smp_processor_id(), balance = 1;
- struct rq *this_rq = cpu_rq(this_cpu);
+ int balance = 1;
+ struct rq *rq = cpu_rq(cpu);
unsigned long interval;
struct sched_domain *sd;
- /*
- * We are idle if there are no processes running. This
- * is valid even if we are the idle process (SMT).
- */
- enum idle_type idle = !this_rq->nr_running ?
- SCHED_IDLE : NOT_IDLE;
- /* Earliest time when we have to call run_rebalance_domains again */
+ /* Earliest time when we have to do rebalance again */
unsigned long next_balance = jiffies + 60*HZ;
- for_each_domain(this_cpu, sd) {
+ for_each_domain(cpu, sd) {
if (!(sd->flags & SD_LOAD_BALANCE))
continue;
@@ -2971,7 +3093,7 @@ static void run_rebalance_domains(struct softirq_action *h)
}
if (time_after_eq(jiffies, sd->last_balance + interval)) {
- if (load_balance(this_cpu, this_rq, sd, idle, &balance)) {
+ if (load_balance(cpu, rq, sd, idle, &balance)) {
/*
* We've pulled tasks over so either we're no
* longer idle, or one of our SMT siblings is
@@ -2995,7 +3117,114 @@ out:
if (!balance)
break;
}
- this_rq->next_balance = next_balance;
+ rq->next_balance = next_balance;
+}
+
+/*
+ * run_rebalance_domains is triggered when needed from the scheduler tick.
+ * In CONFIG_NO_HZ case, the idle load balance owner will do the
+ * rebalancing for all the cpus for whom scheduler ticks are stopped.
+ */
+static void run_rebalance_domains(struct softirq_action *h)
+{
+ int local_cpu = smp_processor_id();
+ struct rq *local_rq = cpu_rq(local_cpu);
+ enum idle_type idle = local_rq->idle_at_tick ? SCHED_IDLE : NOT_IDLE;
+
+ rebalance_domains(local_cpu, idle);
+
+#ifdef CONFIG_NO_HZ
+ /*
+ * If this cpu is the owner for idle load balancing, then do the
+ * balancing on behalf of the other idle cpus whose ticks are
+ * stopped.
+ */
+ if (local_rq->idle_at_tick &&
+ atomic_read(&nohz.load_balancer) == local_cpu) {
+ cpumask_t cpus = nohz.cpu_mask;
+ struct rq *rq;
+ int balance_cpu;
+
+ cpu_clear(local_cpu, cpus);
+ for_each_cpu_mask(balance_cpu, cpus) {
+ /*
+ * If this cpu gets work to do, stop the load balancing
+ * work being done for other cpus. Next load
+ * balancing owner will pick it up.
+ */
+ if (need_resched())
+ break;
+
+ rebalance_domains(balance_cpu, SCHED_IDLE);
+
+ rq = cpu_rq(balance_cpu);
+ if (time_after(local_rq->next_balance, rq->next_balance))
+ local_rq->next_balance = rq->next_balance;
+ }
+ }
+#endif
+}
+
+/*
+ * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing.
+ *
+ * In case of CONFIG_NO_HZ, this is the place where we nominate a new
+ * idle load balancing owner or decide to stop the periodic load balancing,
+ * if the whole system is idle.
+ */
+static inline void trigger_load_balance(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+#ifdef CONFIG_NO_HZ
+ /*
+ * If we were in the nohz mode recently and busy at the current
+ * scheduler tick, then check if we need to nominate new idle
+ * load balancer.
+ */
+ if (rq->in_nohz_recently && !rq->idle_at_tick) {
+ rq->in_nohz_recently = 0;
+
+ if (atomic_read(&nohz.load_balancer) == cpu) {
+ cpu_clear(cpu, nohz.cpu_mask);
+ atomic_set(&nohz.load_balancer, -1);
+ }
+
+ if (atomic_read(&nohz.load_balancer) == -1) {
+ /*
+ * simple selection for now: Nominate the
+ * first cpu in the nohz list to be the next
+ * ilb owner.
+ *
+ * TBD: Traverse the sched domains and nominate
+ * the nearest cpu in the nohz.cpu_mask.
+ */
+ int ilb = first_cpu(nohz.cpu_mask);
+
+ if (ilb != NR_CPUS)
+ resched_cpu(ilb);
+ }
+ }
+
+ /*
+ * If this cpu is idle and doing idle load balancing for all the
+ * cpus with ticks stopped, is it time for that to stop?
+ */
+ if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) == cpu &&
+ cpus_weight(nohz.cpu_mask) == num_online_cpus()) {
+ resched_cpu(cpu);
+ return;
+ }
+
+ /*
+ * If this cpu is idle and the idle load balancing is done by
+ * someone else, then no need raise the SCHED_SOFTIRQ
+ */
+ if (rq->idle_at_tick && atomic_read(&nohz.load_balancer) != cpu &&
+ cpu_isset(cpu, nohz.cpu_mask))
+ return;
+#endif
+ if (time_after_eq(jiffies, rq->next_balance))
+ raise_softirq(SCHED_SOFTIRQ);
}
#else
/*
@@ -3218,16 +3447,17 @@ void scheduler_tick(void)
unsigned long long now = sched_clock();
struct task_struct *p = current;
int cpu = smp_processor_id();
+ int idle_at_tick = idle_cpu(cpu);
struct rq *rq = cpu_rq(cpu);
update_cpu_clock(p, rq, now);
- if (p != rq->idle)
+ if (!idle_at_tick)
task_running_tick(rq, p);
#ifdef CONFIG_SMP
update_load(rq);
- if (time_after_eq(jiffies, rq->next_balance))
- raise_softirq(SCHED_SOFTIRQ);
+ rq->idle_at_tick = idle_at_tick;
+ trigger_load_balance(cpu);
#endif
}
@@ -4291,13 +4521,13 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
struct task_struct *p;
int retval;
- lock_cpu_hotplug();
+ mutex_lock(&sched_hotcpu_mutex);
read_lock(&tasklist_lock);
p = find_process_by_pid(pid);
if (!p) {
read_unlock(&tasklist_lock);
- unlock_cpu_hotplug();
+ mutex_unlock(&sched_hotcpu_mutex);
return -ESRCH;
}
@@ -4324,7 +4554,7 @@ long sched_setaffinity(pid_t pid, cpumask_t new_mask)
out_unlock:
put_task_struct(p);
- unlock_cpu_hotplug();
+ mutex_unlock(&sched_hotcpu_mutex);
return retval;
}
@@ -4381,7 +4611,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
struct task_struct *p;
int retval;
- lock_cpu_hotplug();
+ mutex_lock(&sched_hotcpu_mutex);
read_lock(&tasklist_lock);
retval = -ESRCH;
@@ -4397,7 +4627,7 @@ long sched_getaffinity(pid_t pid, cpumask_t *mask)
out_unlock:
read_unlock(&tasklist_lock);
- unlock_cpu_hotplug();
+ mutex_unlock(&sched_hotcpu_mutex);
if (retval)
return retval;
@@ -4750,6 +4980,8 @@ void show_state_filter(unsigned long state_filter)
show_task(p);
} while_each_thread(g, p);
+ touch_all_softlockup_watchdogs();
+
read_unlock(&tasklist_lock);
/*
* Only show locks if all tasks are dumped:
@@ -5157,7 +5389,12 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
struct rq *rq;
switch (action) {
+ case CPU_LOCK_ACQUIRE:
+ mutex_lock(&sched_hotcpu_mutex);
+ break;
+
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
p = kthread_create(migration_thread, hcpu, "migration/%d",cpu);
if (IS_ERR(p))
return NOTIFY_BAD;
@@ -5171,12 +5408,14 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
/* Strictly unneccessary, as first user will wake it. */
wake_up_process(cpu_rq(cpu)->migration_thread);
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
if (!cpu_rq(cpu)->migration_thread)
break;
/* Unbind it from offline cpu so it can run. Fall thru. */
@@ -5187,6 +5426,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
migrate_live_tasks(cpu);
rq = cpu_rq(cpu);
kthread_stop(rq->migration_thread);
@@ -5202,7 +5442,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
BUG_ON(rq->nr_running != 0);
/* No need to migrate the tasks: it was best-effort if
- * they didn't do lock_cpu_hotplug(). Just wake up
+ * they didn't take sched_hotcpu_mutex. Just wake up
* the requestors. */
spin_lock_irq(&rq->lock);
while (!list_empty(&rq->migration_queue)) {
@@ -5216,6 +5456,9 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
spin_unlock_irq(&rq->lock);
break;
#endif
+ case CPU_LOCK_RELEASE:
+ mutex_unlock(&sched_hotcpu_mutex);
+ break;
}
return NOTIFY_OK;
}
@@ -5244,6 +5487,11 @@ int __init migration_init(void)
#endif
#ifdef CONFIG_SMP
+
+/* Number of possible processor ids */
+int nr_cpu_ids __read_mostly = NR_CPUS;
+EXPORT_SYMBOL(nr_cpu_ids);
+
#undef SCHED_DOMAIN_DEBUG
#ifdef SCHED_DOMAIN_DEBUG
static void sched_domain_debug(struct sched_domain *sd, int cpu)
@@ -5299,7 +5547,7 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
break;
}
- if (!group->cpu_power) {
+ if (!group->__cpu_power) {
printk("\n");
printk(KERN_ERR "ERROR: domain->cpu_power not "
"set\n");
@@ -5476,7 +5724,7 @@ init_sched_build_groups(cpumask_t span, const cpumask_t *cpu_map,
continue;
sg->cpumask = CPU_MASK_NONE;
- sg->cpu_power = 0;
+ sg->__cpu_power = 0;
for_each_cpu_mask(j, span) {
if (group_fn(j, cpu_map, NULL) != group)
@@ -6165,7 +6413,7 @@ next_sg:
continue;
}
- sg->cpu_power += sd->groups->cpu_power;
+ sg_inc_cpu_power(sg, sd->groups->__cpu_power);
}
sg = sg->next;
if (sg != group_head)
@@ -6240,6 +6488,8 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
child = sd->child;
+ sd->groups->__cpu_power = 0;
+
/*
* For perf policy, if the groups in child domain share resources
* (for example cores sharing some portions of the cache hierarchy
@@ -6250,18 +6500,16 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd)
if (!child || (!(sd->flags & SD_POWERSAVINGS_BALANCE) &&
(child->flags &
(SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES)))) {
- sd->groups->cpu_power = SCHED_LOAD_SCALE;
+ sg_inc_cpu_power(sd->groups, SCHED_LOAD_SCALE);
return;
}
- sd->groups->cpu_power = 0;
-
/*
* add cpu_power of each child group to this groups cpu_power
*/
group = child->groups;
do {
- sd->groups->cpu_power += group->cpu_power;
+ sg_inc_cpu_power(sd->groups, group->__cpu_power);
group = group->next;
} while (group != child->groups);
}
@@ -6421,7 +6669,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
sd = &per_cpu(node_domains, j);
sd->groups = sg;
}
- sg->cpu_power = 0;
+ sg->__cpu_power = 0;
sg->cpumask = nodemask;
sg->next = sg;
cpus_or(covered, covered, nodemask);
@@ -6449,7 +6697,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
"Can not alloc domain group for node %d\n", j);
goto error;
}
- sg->cpu_power = 0;
+ sg->__cpu_power = 0;
sg->cpumask = tmp;
sg->next = prev->next;
cpus_or(covered, covered, tmp);
@@ -6586,10 +6834,10 @@ int arch_reinit_sched_domains(void)
{
int err;
- lock_cpu_hotplug();
+ mutex_lock(&sched_hotcpu_mutex);
detach_destroy_domains(&cpu_online_map);
err = arch_init_sched_domains(&cpu_online_map);
- unlock_cpu_hotplug();
+ mutex_unlock(&sched_hotcpu_mutex);
return err;
}
@@ -6668,14 +6916,20 @@ static int update_sched_domains(struct notifier_block *nfb,
{
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
detach_destroy_domains(&cpu_online_map);
return NOTIFY_OK;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
/*
* Fall through and re-initialise the domains.
*/
@@ -6694,12 +6948,12 @@ void __init sched_init_smp(void)
{
cpumask_t non_isolated_cpus;
- lock_cpu_hotplug();
+ mutex_lock(&sched_hotcpu_mutex);
arch_init_sched_domains(&cpu_online_map);
cpus_andnot(non_isolated_cpus, cpu_possible_map, cpu_isolated_map);
if (cpus_empty(non_isolated_cpus))
cpu_set(smp_processor_id(), non_isolated_cpus);
- unlock_cpu_hotplug();
+ mutex_unlock(&sched_hotcpu_mutex);
/* XXX: Theoretical race here - CPU may be hotplugged now */
hotcpu_notifier(update_sched_domains, 0);
@@ -6726,6 +6980,7 @@ int in_sched_functions(unsigned long addr)
void __init sched_init(void)
{
int i, j, k;
+ int highest_cpu = 0;
for_each_possible_cpu(i) {
struct prio_array *array;
@@ -6760,11 +7015,13 @@ void __init sched_init(void)
// delimiter for bitsearch
__set_bit(MAX_PRIO, array->bitmap);
}
+ highest_cpu = i;
}
set_load_weight(&init_task);
#ifdef CONFIG_SMP
+ nr_cpu_ids = highest_cpu + 1;
open_softirq(SCHED_SOFTIRQ, run_rebalance_domains, NULL);
#endif
diff --git a/kernel/signal.c b/kernel/signal.c
index 3670225ecbc..2ac3a668d9d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
@@ -39,125 +38,6 @@
static struct kmem_cache *sigqueue_cachep;
-/*
- * In POSIX a signal is sent either to a specific thread (Linux task)
- * or to the process as a whole (Linux thread group). How the signal
- * is sent determines whether it's to one thread or the whole group,
- * which determines which signal mask(s) are involved in blocking it
- * from being delivered until later. When the signal is delivered,
- * either it's caught or ignored by a user handler or it has a default
- * effect that applies to the whole thread group (POSIX process).
- *
- * The possible effects an unblocked signal set to SIG_DFL can have are:
- * ignore - Nothing Happens
- * terminate - kill the process, i.e. all threads in the group,
- * similar to exit_group. The group leader (only) reports
- * WIFSIGNALED status to its parent.
- * coredump - write a core dump file describing all threads using
- * the same mm and then kill all those threads
- * stop - stop all the threads in the group, i.e. TASK_STOPPED state
- *
- * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
- * Other signals when not blocked and set to SIG_DFL behaves as follows.
- * The job control signals also have other special effects.
- *
- * +--------------------+------------------+
- * | POSIX signal | default action |
- * +--------------------+------------------+
- * | SIGHUP | terminate |
- * | SIGINT | terminate |
- * | SIGQUIT | coredump |
- * | SIGILL | coredump |
- * | SIGTRAP | coredump |
- * | SIGABRT/SIGIOT | coredump |
- * | SIGBUS | coredump |
- * | SIGFPE | coredump |
- * | SIGKILL | terminate(+) |
- * | SIGUSR1 | terminate |
- * | SIGSEGV | coredump |
- * | SIGUSR2 | terminate |
- * | SIGPIPE | terminate |
- * | SIGALRM | terminate |
- * | SIGTERM | terminate |
- * | SIGCHLD | ignore |
- * | SIGCONT | ignore(*) |
- * | SIGSTOP | stop(*)(+) |
- * | SIGTSTP | stop(*) |
- * | SIGTTIN | stop(*) |
- * | SIGTTOU | stop(*) |
- * | SIGURG | ignore |
- * | SIGXCPU | coredump |
- * | SIGXFSZ | coredump |
- * | SIGVTALRM | terminate |
- * | SIGPROF | terminate |
- * | SIGPOLL/SIGIO | terminate |
- * | SIGSYS/SIGUNUSED | coredump |
- * | SIGSTKFLT | terminate |
- * | SIGWINCH | ignore |
- * | SIGPWR | terminate |
- * | SIGRTMIN-SIGRTMAX | terminate |
- * +--------------------+------------------+
- * | non-POSIX signal | default action |
- * +--------------------+------------------+
- * | SIGEMT | coredump |
- * +--------------------+------------------+
- *
- * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
- * (*) Special job control effects:
- * When SIGCONT is sent, it resumes the process (all threads in the group)
- * from TASK_STOPPED state and also clears any pending/queued stop signals
- * (any of those marked with "stop(*)"). This happens regardless of blocking,
- * catching, or ignoring SIGCONT. When any stop signal is sent, it clears
- * any pending/queued SIGCONT signals; this happens regardless of blocking,
- * catching, or ignored the stop signal, though (except for SIGSTOP) the
- * default action of stopping the process may happen later or never.
- */
-
-#ifdef SIGEMT
-#define M_SIGEMT M(SIGEMT)
-#else
-#define M_SIGEMT 0
-#endif
-
-#if SIGRTMIN > BITS_PER_LONG
-#define M(sig) (1ULL << ((sig)-1))
-#else
-#define M(sig) (1UL << ((sig)-1))
-#endif
-#define T(sig, mask) (M(sig) & (mask))
-
-#define SIG_KERNEL_ONLY_MASK (\
- M(SIGKILL) | M(SIGSTOP) )
-
-#define SIG_KERNEL_STOP_MASK (\
- M(SIGSTOP) | M(SIGTSTP) | M(SIGTTIN) | M(SIGTTOU) )
-
-#define SIG_KERNEL_COREDUMP_MASK (\
- M(SIGQUIT) | M(SIGILL) | M(SIGTRAP) | M(SIGABRT) | \
- M(SIGFPE) | M(SIGSEGV) | M(SIGBUS) | M(SIGSYS) | \
- M(SIGXCPU) | M(SIGXFSZ) | M_SIGEMT )
-
-#define SIG_KERNEL_IGNORE_MASK (\
- M(SIGCONT) | M(SIGCHLD) | M(SIGWINCH) | M(SIGURG) )
-
-#define sig_kernel_only(sig) \
- (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_ONLY_MASK))
-#define sig_kernel_coredump(sig) \
- (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_COREDUMP_MASK))
-#define sig_kernel_ignore(sig) \
- (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_IGNORE_MASK))
-#define sig_kernel_stop(sig) \
- (((sig) < SIGRTMIN) && T(sig, SIG_KERNEL_STOP_MASK))
-
-#define sig_needs_tasklist(sig) ((sig) == SIGCONT)
-
-#define sig_user_defined(t, signr) \
- (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \
- ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
-
-#define sig_fatal(t, signr) \
- (!T(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
- (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL)
static int sig_ignored(struct task_struct *t, int sig)
{
@@ -329,6 +209,16 @@ void flush_signals(struct task_struct *t)
spin_unlock_irqrestore(&t->sighand->siglock, flags);
}
+void ignore_signals(struct task_struct *t)
+{
+ int i;
+
+ for (i = 0; i < _NSIG; ++i)
+ t->sighand->action[i].sa.sa_handler = SIG_IGN;
+
+ flush_signals(t);
+}
+
/*
* Flush all handlers for a task.
*/
@@ -1033,17 +923,6 @@ void zap_other_threads(struct task_struct *p)
if (t->exit_state)
continue;
- /*
- * We don't want to notify the parent, since we are
- * killed as part of a thread group due to another
- * thread doing an execve() or similar. So set the
- * exit signal to -1 to allow immediate reaping of
- * the process. But don't detach the thread group
- * leader.
- */
- if (t != p->group_leader)
- t->exit_signal = -1;
-
/* SIGKILL will be handled before any pending SIGSTOP */
sigaddset(&t->pending.signal, SIGKILL);
signal_wake_up(t, 1);
@@ -2636,9 +2515,5 @@ __attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
void __init signals_init(void)
{
- sigqueue_cachep =
- kmem_cache_create("sigqueue",
- sizeof(struct sigqueue),
- __alignof__(struct sigqueue),
- SLAB_PANIC, NULL, NULL);
+ sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 8b75008e2bd..0b9886a00e7 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -593,6 +593,7 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
if (IS_ERR(p)) {
printk("ksoftirqd for %i failed\n", hotcpu);
@@ -602,16 +603,19 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
per_cpu(ksoftirqd, hotcpu) = p;
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
wake_up_process(per_cpu(ksoftirqd, hotcpu));
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
if (!per_cpu(ksoftirqd, hotcpu))
break;
/* Unbind so it can run. Fall thru. */
kthread_bind(per_cpu(ksoftirqd, hotcpu),
any_online_cpu(cpu_online_map));
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
p = per_cpu(ksoftirqd, hotcpu);
per_cpu(ksoftirqd, hotcpu) = NULL;
kthread_stop(p);
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 50afeb81330..0131e296ffb 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -34,12 +34,32 @@ static struct notifier_block panic_block = {
.notifier_call = softlock_panic,
};
+/*
+ * Returns seconds, approximately. We don't need nanosecond
+ * resolution, and we don't need to waste time with a big divide when
+ * 2^30ns == 1.074s.
+ */
+static unsigned long get_timestamp(void)
+{
+ return sched_clock() >> 30; /* 2^30 ~= 10^9 */
+}
+
void touch_softlockup_watchdog(void)
{
- __raw_get_cpu_var(touch_timestamp) = jiffies;
+ __raw_get_cpu_var(touch_timestamp) = get_timestamp();
}
EXPORT_SYMBOL(touch_softlockup_watchdog);
+void touch_all_softlockup_watchdogs(void)
+{
+ int cpu;
+
+ /* Cause each CPU to re-update its timestamp rather than complain */
+ for_each_online_cpu(cpu)
+ per_cpu(touch_timestamp, cpu) = 0;
+}
+EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
+
/*
* This callback runs from the timer interrupt, and checks
* whether the watchdog thread has hung or not:
@@ -48,9 +68,18 @@ void softlockup_tick(void)
{
int this_cpu = smp_processor_id();
unsigned long touch_timestamp = per_cpu(touch_timestamp, this_cpu);
+ unsigned long print_timestamp;
+ unsigned long now;
+
+ if (touch_timestamp == 0) {
+ touch_softlockup_watchdog();
+ return;
+ }
+
+ print_timestamp = per_cpu(print_timestamp, this_cpu);
- /* prevent double reports: */
- if (per_cpu(print_timestamp, this_cpu) == touch_timestamp ||
+ /* report at most once a second */
+ if (print_timestamp < (touch_timestamp + 1) ||
did_panic ||
!per_cpu(watchdog_task, this_cpu))
return;
@@ -61,12 +90,14 @@ void softlockup_tick(void)
return;
}
+ now = get_timestamp();
+
/* Wake up the high-prio watchdog task every second: */
- if (time_after(jiffies, touch_timestamp + HZ))
+ if (now > (touch_timestamp + 1))
wake_up_process(per_cpu(watchdog_task, this_cpu));
/* Warn about unreasonable 10+ seconds delays: */
- if (time_after(jiffies, touch_timestamp + 10*HZ)) {
+ if (now > (touch_timestamp + 10)) {
per_cpu(print_timestamp, this_cpu) = touch_timestamp;
spin_lock(&print_lock);
@@ -82,11 +113,14 @@ void softlockup_tick(void)
*/
static int watchdog(void * __bind_cpu)
{
- struct sched_param param = { .sched_priority = 99 };
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
sched_setscheduler(current, SCHED_FIFO, &param);
current->flags |= PF_NOFREEZE;
+ /* initialize timestamp */
+ touch_softlockup_watchdog();
+
/*
* Run briefly once per second to reset the softlockup timestamp.
* If this gets delayed for more than 10 seconds then the
@@ -112,27 +146,31 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
BUG_ON(per_cpu(watchdog_task, hotcpu));
p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
if (IS_ERR(p)) {
printk("watchdog for %i failed\n", hotcpu);
return NOTIFY_BAD;
}
- per_cpu(touch_timestamp, hotcpu) = jiffies;
+ per_cpu(touch_timestamp, hotcpu) = 0;
per_cpu(watchdog_task, hotcpu) = p;
kthread_bind(p, hotcpu);
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
wake_up_process(per_cpu(watchdog_task, hotcpu));
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
if (!per_cpu(watchdog_task, hotcpu))
break;
/* Unbind so it can run. Fall thru. */
kthread_bind(per_cpu(watchdog_task, hotcpu),
any_online_cpu(cpu_online_map));
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
p = per_cpu(watchdog_task, hotcpu);
per_cpu(watchdog_task, hotcpu) = NULL;
kthread_stop(p);
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 12458040e66..daabb74ee0b 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -1,11 +1,12 @@
/* Copyright 2005 Rusty Russell rusty@rustcorp.com.au IBM Corporation.
* GPL v2 and any later version.
*/
-#include <linux/stop_machine.h>
-#include <linux/kthread.h>
-#include <linux/sched.h>
#include <linux/cpu.h>
#include <linux/err.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stop_machine.h>
#include <linux/syscalls.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
@@ -208,3 +209,4 @@ int stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu)
return ret;
}
+EXPORT_SYMBOL_GPL(stop_machine_run);
diff --git a/kernel/sys.c b/kernel/sys.c
index 123b165080e..cdb7e9457ba 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -134,19 +134,39 @@ static int notifier_chain_unregister(struct notifier_block **nl,
return -ENOENT;
}
+/**
+ * notifier_call_chain - Informs the registered notifiers about an event.
+ * @nl: Pointer to head of the blocking notifier chain
+ * @val: Value passed unmodified to notifier function
+ * @v: Pointer passed unmodified to notifier function
+ * @nr_to_call: Number of notifier functions to be called. Don't care
+ * value of this parameter is -1.
+ * @nr_calls: Records the number of notifications sent. Don't care
+ * value of this field is NULL.
+ * @returns: notifier_call_chain returns the value returned by the
+ * last notifier function called.
+ */
+
static int __kprobes notifier_call_chain(struct notifier_block **nl,
- unsigned long val, void *v)
+ unsigned long val, void *v,
+ int nr_to_call, int *nr_calls)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb, *next_nb;
nb = rcu_dereference(*nl);
- while (nb) {
+
+ while (nb && nr_to_call) {
next_nb = rcu_dereference(nb->next);
ret = nb->notifier_call(nb, val, v);
+
+ if (nr_calls)
+ (*nr_calls)++;
+
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
nb = next_nb;
+ nr_to_call--;
}
return ret;
}
@@ -205,10 +225,12 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
/**
- * atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ * __atomic_notifier_call_chain - Call functions in an atomic notifier chain
* @nh: Pointer to head of the atomic notifier chain
* @val: Value passed unmodified to notifier function
* @v: Pointer passed unmodified to notifier function
+ * @nr_to_call: See the comment for notifier_call_chain.
+ * @nr_calls: See the comment for notifier_call_chain.
*
* Calls each function in a notifier chain in turn. The functions
* run in an atomic context, so they must not block.
@@ -222,19 +244,27 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
* of the last notifier function called.
*/
-int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
- unsigned long val, void *v)
+int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+ unsigned long val, void *v,
+ int nr_to_call, int *nr_calls)
{
int ret;
rcu_read_lock();
- ret = notifier_call_chain(&nh->head, val, v);
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
rcu_read_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
+EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+ unsigned long val, void *v)
+{
+ return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
+}
+
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
/*
* Blocking notifier chain routines. All access to the chain is
* synchronized by an rwsem.
@@ -304,10 +334,12 @@ int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
/**
- * blocking_notifier_call_chain - Call functions in a blocking notifier chain
+ * __blocking_notifier_call_chain - Call functions in a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
* @val: Value passed unmodified to notifier function
* @v: Pointer passed unmodified to notifier function
+ * @nr_to_call: See comment for notifier_call_chain.
+ * @nr_calls: See comment for notifier_call_chain.
*
* Calls each function in a notifier chain in turn. The functions
* run in a process context, so they are allowed to block.
@@ -320,8 +352,9 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
* of the last notifier function called.
*/
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
- unsigned long val, void *v)
+int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+ unsigned long val, void *v,
+ int nr_to_call, int *nr_calls)
{
int ret = NOTIFY_DONE;
@@ -332,12 +365,19 @@ int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
*/
if (rcu_dereference(nh->head)) {
down_read(&nh->rwsem);
- ret = notifier_call_chain(&nh->head, val, v);
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
+ nr_calls);
up_read(&nh->rwsem);
}
return ret;
}
+EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+ unsigned long val, void *v)
+{
+ return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
+}
EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
/*
@@ -383,10 +423,12 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
/**
- * raw_notifier_call_chain - Call functions in a raw notifier chain
+ * __raw_notifier_call_chain - Call functions in a raw notifier chain
* @nh: Pointer to head of the raw notifier chain
* @val: Value passed unmodified to notifier function
* @v: Pointer passed unmodified to notifier function
+ * @nr_to_call: See comment for notifier_call_chain.
+ * @nr_calls: See comment for notifier_call_chain
*
* Calls each function in a notifier chain in turn. The functions
* run in an undefined context.
@@ -400,10 +442,19 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
* of the last notifier function called.
*/
+int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+ unsigned long val, void *v,
+ int nr_to_call, int *nr_calls)
+{
+ return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+}
+
+EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
+
int raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v)
{
- return notifier_call_chain(&nh->head, val, v);
+ return __raw_notifier_call_chain(nh, val, v, -1, NULL);
}
EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
@@ -478,10 +529,12 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
/**
- * srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
* @nh: Pointer to head of the SRCU notifier chain
* @val: Value passed unmodified to notifier function
* @v: Pointer passed unmodified to notifier function
+ * @nr_to_call: See comment for notifier_call_chain.
+ * @nr_calls: See comment for notifier_call_chain
*
* Calls each function in a notifier chain in turn. The functions
* run in a process context, so they are allowed to block.
@@ -494,18 +547,25 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
* of the last notifier function called.
*/
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
- unsigned long val, void *v)
+int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+ unsigned long val, void *v,
+ int nr_to_call, int *nr_calls)
{
int ret;
int idx;
idx = srcu_read_lock(&nh->srcu);
- ret = notifier_call_chain(&nh->head, val, v);
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
srcu_read_unlock(&nh->srcu, idx);
return ret;
}
+EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+ unsigned long val, void *v)
+{
+ return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
+}
EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
/**
@@ -881,7 +941,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
#ifdef CONFIG_SOFTWARE_SUSPEND
case LINUX_REBOOT_CMD_SW_SUSPEND:
{
- int ret = software_suspend();
+ int ret = hibernate();
unlock_kernel();
return ret;
}
@@ -1292,7 +1352,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
}
/*
- * Samma på svenska..
+ * Samma på svenska..
*/
asmlinkage long sys_setfsgid(gid_t gid)
{
@@ -1923,6 +1983,16 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
if (retval)
return retval;
+ if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) {
+ /*
+ * The caller is asking for an immediate RLIMIT_CPU
+ * expiry. But we use the zero value to mean "it was
+ * never set". So let's cheat and make it one second
+ * instead
+ */
+ new_rlim.rlim_cur = 1;
+ }
+
task_lock(current->group_leader);
*old_rlim = new_rlim;
task_unlock(current->group_leader);
@@ -1944,15 +2014,6 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
unsigned long rlim_cur = new_rlim.rlim_cur;
cputime_t cputime;
- if (rlim_cur == 0) {
- /*
- * The caller is asking for an immediate RLIMIT_CPU
- * expiry. But we use the zero value to mean "it was
- * never set". So let's cheat and make it one second
- * instead
- */
- rlim_cur = 1;
- }
cputime = secs_to_cputime(rlim_cur);
read_lock(&tasklist_lock);
spin_lock_irq(&current->sighand->siglock);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c904748f229..4073353abd4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,8 @@ extern int pid_max_min, pid_max_max;
extern int sysctl_drop_caches;
extern int percpu_pagelist_fraction;
extern int compat_log;
+extern int maps_protect;
+extern int sysctl_stat_interval;
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
static int maxolduid = 65535;
@@ -603,6 +605,16 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
+#ifdef CONFIG_PROC_FS
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "maps_protect",
+ .data = &maps_protect,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
{ .ctl_name = 0 }
};
@@ -846,6 +858,17 @@ static ctl_table vm_table[] = {
.extra2 = &one_hundred,
},
#endif
+#ifdef CONFIG_SMP
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "stat_interval",
+ .data = &sysctl_stat_interval,
+ .maxlen = sizeof(sysctl_stat_interval),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ .strategy = &sysctl_jiffies,
+ },
+#endif
#if defined(CONFIG_X86_32) || \
(defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
{
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index ad7d2392cb0..906cae77158 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -524,9 +524,7 @@ void __init taskstats_init_early(void)
{
unsigned int i;
- taskstats_cache = kmem_cache_create("taskstats_cache",
- sizeof(struct taskstats),
- 0, SLAB_PANIC, NULL, NULL);
+ taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
for_each_possible_cpu(i) {
INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));
init_rwsem(&(per_cpu(listener_array, i).sem));
diff --git a/kernel/time.c b/kernel/time.c
index ba18ec4899b..f04791f6940 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -31,7 +31,6 @@
#include <linux/timex.h>
#include <linux/capability.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/security.h>
#include <linux/fs.h>
@@ -247,6 +246,36 @@ struct timespec current_fs_time(struct super_block *sb)
}
EXPORT_SYMBOL(current_fs_time);
+/*
+ * Convert jiffies to milliseconds and back.
+ *
+ * Avoid unnecessary multiplications/divisions in the
+ * two most common HZ cases:
+ */
+unsigned int inline jiffies_to_msecs(const unsigned long j)
+{
+#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
+ return (MSEC_PER_SEC / HZ) * j;
+#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
+ return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
+#else
+ return (j * MSEC_PER_SEC) / HZ;
+#endif
+}
+EXPORT_SYMBOL(jiffies_to_msecs);
+
+unsigned int inline jiffies_to_usecs(const unsigned long j)
+{
+#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
+ return (USEC_PER_SEC / HZ) * j;
+#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC)
+ return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC);
+#else
+ return (j * USEC_PER_SEC) / HZ;
+#endif
+}
+EXPORT_SYMBOL(jiffies_to_usecs);
+
/**
* timespec_trunc - Truncate timespec to a granularity
* @t: Timespec
@@ -473,36 +502,6 @@ struct timeval ns_to_timeval(const s64 nsec)
EXPORT_SYMBOL(ns_to_timeval);
/*
- * Convert jiffies to milliseconds and back.
- *
- * Avoid unnecessary multiplications/divisions in the
- * two most common HZ cases:
- */
-unsigned int jiffies_to_msecs(const unsigned long j)
-{
-#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
- return (MSEC_PER_SEC / HZ) * j;
-#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
- return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
-#else
- return (j * MSEC_PER_SEC) / HZ;
-#endif
-}
-EXPORT_SYMBOL(jiffies_to_msecs);
-
-unsigned int jiffies_to_usecs(const unsigned long j)
-{
-#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
- return (USEC_PER_SEC / HZ) * j;
-#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC)
- return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC);
-#else
- return (j * USEC_PER_SEC) / HZ;
-#endif
-}
-EXPORT_SYMBOL(jiffies_to_usecs);
-
-/*
* When we convert to jiffies then we interpret incoming values
* the following way:
*
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 93bccba1f26..99b6034fc86 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,4 +1,4 @@
-obj-y += ntp.o clocksource.o jiffies.o timer_list.o
+obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index fe5c7db2424..3db5c3c460d 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -74,15 +74,17 @@ static struct clocksource *watchdog;
static struct timer_list watchdog_timer;
static DEFINE_SPINLOCK(watchdog_lock);
static cycle_t watchdog_last;
+static int watchdog_resumed;
+
/*
- * Interval: 0.5sec Treshold: 0.0625s
+ * Interval: 0.5sec Threshold: 0.0625s
*/
#define WATCHDOG_INTERVAL (HZ >> 1)
-#define WATCHDOG_TRESHOLD (NSEC_PER_SEC >> 4)
+#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4)
static void clocksource_ratewd(struct clocksource *cs, int64_t delta)
{
- if (delta > -WATCHDOG_TRESHOLD && delta < WATCHDOG_TRESHOLD)
+ if (delta > -WATCHDOG_THRESHOLD && delta < WATCHDOG_THRESHOLD)
return;
printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n",
@@ -98,15 +100,26 @@ static void clocksource_watchdog(unsigned long data)
struct clocksource *cs, *tmp;
cycle_t csnow, wdnow;
int64_t wd_nsec, cs_nsec;
+ int resumed;
spin_lock(&watchdog_lock);
+ resumed = watchdog_resumed;
+ if (unlikely(resumed))
+ watchdog_resumed = 0;
+
wdnow = watchdog->read();
wd_nsec = cyc2ns(watchdog, (wdnow - watchdog_last) & watchdog->mask);
watchdog_last = wdnow;
list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) {
csnow = cs->read();
+
+ if (unlikely(resumed)) {
+ cs->wd_last = csnow;
+ continue;
+ }
+
/* Initialized ? */
if (!(cs->flags & CLOCK_SOURCE_WATCHDOG)) {
if ((cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) &&
@@ -136,6 +149,13 @@ static void clocksource_watchdog(unsigned long data)
}
spin_unlock(&watchdog_lock);
}
+static void clocksource_resume_watchdog(void)
+{
+ spin_lock(&watchdog_lock);
+ watchdog_resumed = 1;
+ spin_unlock(&watchdog_lock);
+}
+
static void clocksource_check_watchdog(struct clocksource *cs)
{
struct clocksource *cse;
@@ -182,9 +202,34 @@ static void clocksource_check_watchdog(struct clocksource *cs)
if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS)
cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES;
}
+
+static inline void clocksource_resume_watchdog(void) { }
#endif
/**
+ * clocksource_resume - resume the clocksource(s)
+ */
+void clocksource_resume(void)
+{
+ struct list_head *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clocksource_lock, flags);
+
+ list_for_each(tmp, &clocksource_list) {
+ struct clocksource *cs;
+
+ cs = list_entry(tmp, struct clocksource, list);
+ if (cs->resume)
+ cs->resume();
+ }
+
+ clocksource_resume_watchdog();
+
+ spin_unlock_irqrestore(&clocksource_lock, flags);
+}
+
+/**
* clocksource_get_next - Returns the selected clocksource
*
*/
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index bfda3f7f071..a96ec9ab345 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -31,7 +31,7 @@ DEFINE_PER_CPU(struct tick_device, tick_cpu_device);
*/
ktime_t tick_next_period;
ktime_t tick_period;
-static int tick_do_timer_cpu = -1;
+int tick_do_timer_cpu __read_mostly = -1;
DEFINE_SPINLOCK(tick_device_lock);
/*
@@ -295,6 +295,12 @@ static void tick_shutdown(unsigned int *cpup)
clockevents_exchange_device(dev, NULL);
td->evtdev = NULL;
}
+ /* Transfer the do_timer job away from this cpu */
+ if (*cpup == tick_do_timer_cpu) {
+ int cpu = first_cpu(cpu_online_map);
+
+ tick_do_timer_cpu = (cpu != NR_CPUS) ? cpu : -1;
+ }
spin_unlock_irqrestore(&tick_device_lock, flags);
}
diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h
index c9d203bde51..bb13f272490 100644
--- a/kernel/time/tick-internal.h
+++ b/kernel/time/tick-internal.h
@@ -5,6 +5,7 @@ DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
extern spinlock_t tick_device_lock;
extern ktime_t tick_next_period;
extern ktime_t tick_period;
+extern int tick_do_timer_cpu __read_mostly;
extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast);
extern void tick_handle_periodic(struct clock_event_device *dev);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 51556b95f60..3483e6cb954 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -217,10 +217,30 @@ void tick_nohz_stop_sched_tick(void)
* the scheduler tick in nohz_restart_sched_tick.
*/
if (!ts->tick_stopped) {
+ if (select_nohz_load_balancer(1)) {
+ /*
+ * sched tick not stopped!
+ */
+ cpu_clear(cpu, nohz_cpu_mask);
+ goto out;
+ }
+
ts->idle_tick = ts->sched_timer.expires;
ts->tick_stopped = 1;
ts->idle_jiffies = last_jiffies;
}
+
+ /*
+ * If this cpu is the one which updates jiffies, then
+ * give up the assignment and let it be taken by the
+ * cpu which runs the tick timer next, which might be
+ * this cpu as well. If we don't drop this here the
+ * jiffies might be stale and do_timer() never
+ * invoked.
+ */
+ if (cpu == tick_do_timer_cpu)
+ tick_do_timer_cpu = -1;
+
/*
* calculate the expiry time for the next timer wheel
* timer
@@ -273,6 +293,7 @@ void tick_nohz_restart_sched_tick(void)
now = ktime_get();
local_irq_disable();
+ select_nohz_load_balancer(0);
tick_do_update_jiffies64(now);
cpu_clear(cpu, nohz_cpu_mask);
@@ -338,12 +359,24 @@ static void tick_nohz_handler(struct clock_event_device *dev)
{
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
struct pt_regs *regs = get_irq_regs();
+ int cpu = smp_processor_id();
ktime_t now = ktime_get();
dev->next_event.tv64 = KTIME_MAX;
+ /*
+ * Check if the do_timer duty was dropped. We don't care about
+ * concurrency: This happens only when the cpu in charge went
+ * into a long sleep. If two cpus happen to assign themself to
+ * this duty, then the jiffies update is still serialized by
+ * xtime_lock.
+ */
+ if (unlikely(tick_do_timer_cpu == -1))
+ tick_do_timer_cpu = cpu;
+
/* Check, if the jiffies need an update */
- tick_do_update_jiffies64(now);
+ if (tick_do_timer_cpu == cpu)
+ tick_do_update_jiffies64(now);
/*
* When we are idle and the tick is stopped, we have to touch
@@ -431,9 +464,23 @@ static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer)
struct hrtimer_cpu_base *base = timer->base->cpu_base;
struct pt_regs *regs = get_irq_regs();
ktime_t now = ktime_get();
+ int cpu = smp_processor_id();
+
+#ifdef CONFIG_NO_HZ
+ /*
+ * Check if the do_timer duty was dropped. We don't care about
+ * concurrency: This happens only when the cpu in charge went
+ * into a long sleep. If two cpus happen to assign themself to
+ * this duty, then the jiffies update is still serialized by
+ * xtime_lock.
+ */
+ if (unlikely(tick_do_timer_cpu == -1))
+ tick_do_timer_cpu = cpu;
+#endif
/* Check, if the jiffies need an update */
- tick_do_update_jiffies64(now);
+ if (tick_do_timer_cpu == cpu)
+ tick_do_update_jiffies64(now);
/*
* Do not call, when we are not in irq context and have
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
new file mode 100644
index 00000000000..f9217bf644f
--- /dev/null
+++ b/kernel/time/timekeeping.c
@@ -0,0 +1,476 @@
+/*
+ * linux/kernel/time/timekeeping.c
+ *
+ * Kernel timekeeping code and accessor functions
+ *
+ * This code was moved from linux/kernel/timer.c.
+ * Please see that file for copyright and history logs.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sysdev.h>
+#include <linux/clocksource.h>
+#include <linux/jiffies.h>
+#include <linux/time.h>
+#include <linux/tick.h>
+
+
+/*
+ * This read-write spinlock protects us from races in SMP while
+ * playing with xtime and avenrun.
+ */
+__attribute__((weak)) __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
+
+EXPORT_SYMBOL(xtime_lock);
+
+
+/*
+ * The current time
+ * wall_to_monotonic is what we need to add to xtime (or xtime corrected
+ * for sub jiffie times) to get to monotonic time. Monotonic is pegged
+ * at zero at system boot time, so wall_to_monotonic will be negative,
+ * however, we will ALWAYS keep the tv_nsec part positive so we can use
+ * the usual normalization.
+ */
+struct timespec xtime __attribute__ ((aligned (16)));
+struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
+
+EXPORT_SYMBOL(xtime);
+
+
+static struct clocksource *clock; /* pointer to current clocksource */
+
+
+#ifdef CONFIG_GENERIC_TIME
+/**
+ * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook
+ *
+ * private function, must hold xtime_lock lock when being
+ * called. Returns the number of nanoseconds since the
+ * last call to update_wall_time() (adjusted by NTP scaling)
+ */
+static inline s64 __get_nsec_offset(void)
+{
+ cycle_t cycle_now, cycle_delta;
+ s64 ns_offset;
+
+ /* read clocksource: */
+ cycle_now = clocksource_read(clock);
+
+ /* calculate the delta since the last update_wall_time: */
+ cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
+
+ /* convert to nanoseconds: */
+ ns_offset = cyc2ns(clock, cycle_delta);
+
+ return ns_offset;
+}
+
+/**
+ * __get_realtime_clock_ts - Returns the time of day in a timespec
+ * @ts: pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec. Used by
+ * do_gettimeofday() and get_realtime_clock_ts().
+ */
+static inline void __get_realtime_clock_ts(struct timespec *ts)
+{
+ unsigned long seq;
+ s64 nsecs;
+
+ do {
+ seq = read_seqbegin(&xtime_lock);
+
+ *ts = xtime;
+ nsecs = __get_nsec_offset();
+
+ } while (read_seqretry(&xtime_lock, seq));
+
+ timespec_add_ns(ts, nsecs);
+}
+
+/**
+ * getnstimeofday - Returns the time of day in a timespec
+ * @ts: pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec.
+ */
+void getnstimeofday(struct timespec *ts)
+{
+ __get_realtime_clock_ts(ts);
+}
+
+EXPORT_SYMBOL(getnstimeofday);
+
+/**
+ * do_gettimeofday - Returns the time of day in a timeval
+ * @tv: pointer to the timeval to be set
+ *
+ * NOTE: Users should be converted to using get_realtime_clock_ts()
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+ struct timespec now;
+
+ __get_realtime_clock_ts(&now);
+ tv->tv_sec = now.tv_sec;
+ tv->tv_usec = now.tv_nsec/1000;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+/**
+ * do_settimeofday - Sets the time of day
+ * @tv: pointer to the timespec variable containing the new time
+ *
+ * Sets the time of day to the new time and update NTP and notify hrtimers
+ */
+int do_settimeofday(struct timespec *tv)
+{
+ unsigned long flags;
+ time_t wtm_sec, sec = tv->tv_sec;
+ long wtm_nsec, nsec = tv->tv_nsec;
+
+ if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
+ return -EINVAL;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+
+ nsec -= __get_nsec_offset();
+
+ wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+ wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+ set_normalized_timespec(&xtime, sec, nsec);
+ set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+
+ clock->error = 0;
+ ntp_clear();
+
+ update_vsyscall(&xtime, clock);
+
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ /* signal hrtimers about time change */
+ clock_was_set();
+
+ return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+/**
+ * change_clocksource - Swaps clocksources if a new one is available
+ *
+ * Accumulates current time interval and initializes new clocksource
+ */
+static void change_clocksource(void)
+{
+ struct clocksource *new;
+ cycle_t now;
+ u64 nsec;
+
+ new = clocksource_get_next();
+
+ if (clock == new)
+ return;
+
+ now = clocksource_read(new);
+ nsec = __get_nsec_offset();
+ timespec_add_ns(&xtime, nsec);
+
+ clock = new;
+ clock->cycle_last = now;
+
+ clock->error = 0;
+ clock->xtime_nsec = 0;
+ clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
+
+ tick_clock_notify();
+
+ printk(KERN_INFO "Time: %s clocksource has been installed.\n",
+ clock->name);
+}
+#else
+static inline void change_clocksource(void) { }
+#endif
+
+/**
+ * timekeeping_is_continuous - check to see if timekeeping is free running
+ */
+int timekeeping_is_continuous(void)
+{
+ unsigned long seq;
+ int ret;
+
+ do {
+ seq = read_seqbegin(&xtime_lock);
+
+ ret = clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
+
+ } while (read_seqretry(&xtime_lock, seq));
+
+ return ret;
+}
+
+/**
+ * read_persistent_clock - Return time in seconds from the persistent clock.
+ *
+ * Weak dummy function for arches that do not yet support it.
+ * Returns seconds from epoch using the battery backed persistent clock.
+ * Returns zero if unsupported.
+ *
+ * XXX - Do be sure to remove it once all arches implement it.
+ */
+unsigned long __attribute__((weak)) read_persistent_clock(void)
+{
+ return 0;
+}
+
+/*
+ * timekeeping_init - Initializes the clocksource and common timekeeping values
+ */
+void __init timekeeping_init(void)
+{
+ unsigned long flags;
+ unsigned long sec = read_persistent_clock();
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+
+ ntp_clear();
+
+ clock = clocksource_get_next();
+ clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
+ clock->cycle_last = clocksource_read(clock);
+
+ xtime.tv_sec = sec;
+ xtime.tv_nsec = 0;
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
+/* flag for if timekeeping is suspended */
+static int timekeeping_suspended;
+/* time in seconds when suspend began */
+static unsigned long timekeeping_suspend_time;
+
+/**
+ * timekeeping_resume - Resumes the generic timekeeping subsystem.
+ * @dev: unused
+ *
+ * This is for the generic clocksource timekeeping.
+ * xtime/wall_to_monotonic/jiffies/etc are
+ * still managed by arch specific suspend/resume code.
+ */
+static int timekeeping_resume(struct sys_device *dev)
+{
+ unsigned long flags;
+ unsigned long now = read_persistent_clock();
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+
+ if (now && (now > timekeeping_suspend_time)) {
+ unsigned long sleep_length = now - timekeeping_suspend_time;
+
+ xtime.tv_sec += sleep_length;
+ wall_to_monotonic.tv_sec -= sleep_length;
+ }
+ /* re-base the last cycle value */
+ clock->cycle_last = clocksource_read(clock);
+ clock->error = 0;
+ timekeeping_suspended = 0;
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ touch_softlockup_watchdog();
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+
+ /* Resume hrtimers */
+ hres_timers_resume();
+
+ return 0;
+}
+
+static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
+{
+ unsigned long flags;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+ timekeeping_suspended = 1;
+ timekeeping_suspend_time = read_persistent_clock();
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+
+ return 0;
+}
+
+/* sysfs resume/suspend bits for timekeeping */
+static struct sysdev_class timekeeping_sysclass = {
+ .resume = timekeeping_resume,
+ .suspend = timekeeping_suspend,
+ set_kset_name("timekeeping"),
+};
+
+static struct sys_device device_timer = {
+ .id = 0,
+ .cls = &timekeeping_sysclass,
+};
+
+static int __init timekeeping_init_device(void)
+{
+ int error = sysdev_class_register(&timekeeping_sysclass);
+ if (!error)
+ error = sysdev_register(&device_timer);
+ return error;
+}
+
+device_initcall(timekeeping_init_device);
+
+/*
+ * If the error is already larger, we look ahead even further
+ * to compensate for late or lost adjustments.
+ */
+static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
+ s64 *offset)
+{
+ s64 tick_error, i;
+ u32 look_ahead, adj;
+ s32 error2, mult;
+
+ /*
+ * Use the current error value to determine how much to look ahead.
+ * The larger the error the slower we adjust for it to avoid problems
+ * with losing too many ticks, otherwise we would overadjust and
+ * produce an even larger error. The smaller the adjustment the
+ * faster we try to adjust for it, as lost ticks can do less harm
+ * here. This is tuned so that an error of about 1 msec is adusted
+ * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
+ */
+ error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
+ error2 = abs(error2);
+ for (look_ahead = 0; error2 > 0; look_ahead++)
+ error2 >>= 2;
+
+ /*
+ * Now calculate the error in (1 << look_ahead) ticks, but first
+ * remove the single look ahead already included in the error.
+ */
+ tick_error = current_tick_length() >>
+ (TICK_LENGTH_SHIFT - clock->shift + 1);
+ tick_error -= clock->xtime_interval >> 1;
+ error = ((error - tick_error) >> look_ahead) + tick_error;
+
+ /* Finally calculate the adjustment shift value. */
+ i = *interval;
+ mult = 1;
+ if (error < 0) {
+ error = -error;
+ *interval = -*interval;
+ *offset = -*offset;
+ mult = -1;
+ }
+ for (adj = 0; error > i; adj++)
+ error >>= 1;
+
+ *interval <<= adj;
+ *offset <<= adj;
+ return mult << adj;
+}
+
+/*
+ * Adjust the multiplier to reduce the error value,
+ * this is optimized for the most common adjustments of -1,0,1,
+ * for other values we can do a bit more work.
+ */
+static void clocksource_adjust(struct clocksource *clock, s64 offset)
+{
+ s64 error, interval = clock->cycle_interval;
+ int adj;
+
+ error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
+ if (error > interval) {
+ error >>= 2;
+ if (likely(error <= interval))
+ adj = 1;
+ else
+ adj = clocksource_bigadjust(error, &interval, &offset);
+ } else if (error < -interval) {
+ error >>= 2;
+ if (likely(error >= -interval)) {
+ adj = -1;
+ interval = -interval;
+ offset = -offset;
+ } else
+ adj = clocksource_bigadjust(error, &interval, &offset);
+ } else
+ return;
+
+ clock->mult += adj;
+ clock->xtime_interval += interval;
+ clock->xtime_nsec -= offset;
+ clock->error -= (interval - offset) <<
+ (TICK_LENGTH_SHIFT - clock->shift);
+}
+
+/**
+ * update_wall_time - Uses the current clocksource to increment the wall time
+ *
+ * Called from the timer interrupt, must hold a write on xtime_lock.
+ */
+void update_wall_time(void)
+{
+ cycle_t offset;
+
+ /* Make sure we're fully resumed: */
+ if (unlikely(timekeeping_suspended))
+ return;
+
+#ifdef CONFIG_GENERIC_TIME
+ offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
+#else
+ offset = clock->cycle_interval;
+#endif
+ clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
+
+ /* normally this loop will run just once, however in the
+ * case of lost or late ticks, it will accumulate correctly.
+ */
+ while (offset >= clock->cycle_interval) {
+ /* accumulate one interval */
+ clock->xtime_nsec += clock->xtime_interval;
+ clock->cycle_last += clock->cycle_interval;
+ offset -= clock->cycle_interval;
+
+ if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {
+ clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;
+ xtime.tv_sec++;
+ second_overflow();
+ }
+
+ /* interpolator bits */
+ time_interpolator_update(clock->xtime_interval
+ >> clock->shift);
+
+ /* accumulate error between NTP and clock interval */
+ clock->error += current_tick_length();
+ clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
+ }
+
+ /* correct the clock when NTP error is too big */
+ clocksource_adjust(clock, offset);
+
+ /* store full nanoseconds into xtime */
+ xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
+ clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
+
+ /* check to see if there is a new clocksource to use */
+ change_clocksource();
+ update_vsyscall(&xtime, clock);
+}
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 59df5e8555a..8bbcfb77f7d 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -38,17 +38,12 @@ DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases);
static void print_name_offset(struct seq_file *m, void *sym)
{
- unsigned long addr = (unsigned long)sym;
- char namebuf[KSYM_NAME_LEN+1];
- unsigned long size, offset;
- const char *sym_name;
- char *modname;
-
- sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf);
- if (sym_name)
- SEQ_printf(m, "%s", sym_name);
- else
+ char symname[KSYM_NAME_LEN+1];
+
+ if (lookup_symbol_name((unsigned long)sym, symname) < 0)
SEQ_printf(m, "<%p>", sym);
+ else
+ SEQ_printf(m, "%s", symname);
}
static void
@@ -70,7 +65,7 @@ print_timer(struct seq_file *m, struct hrtimer *timer, int idx, u64 now)
SEQ_printf(m, ", %s/%d", tmp, timer->start_pid);
#endif
SEQ_printf(m, "\n");
- SEQ_printf(m, " # expires at %Ld nsecs [in %Ld nsecs]\n",
+ SEQ_printf(m, " # expires at %Lu nsecs [in %Lu nsecs]\n",
(unsigned long long)ktime_to_ns(timer->expires),
(unsigned long long)(ktime_to_ns(timer->expires) - now));
}
@@ -116,14 +111,14 @@ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
{
SEQ_printf(m, " .index: %d\n",
base->index);
- SEQ_printf(m, " .resolution: %Ld nsecs\n",
+ SEQ_printf(m, " .resolution: %Lu nsecs\n",
(unsigned long long)ktime_to_ns(base->resolution));
SEQ_printf(m, " .get_time: ");
print_name_offset(m, base->get_time);
SEQ_printf(m, "\n");
#ifdef CONFIG_HIGH_RES_TIMERS
- SEQ_printf(m, " .offset: %Ld nsecs\n",
- ktime_to_ns(base->offset));
+ SEQ_printf(m, " .offset: %Lu nsecs\n",
+ (unsigned long long) ktime_to_ns(base->offset));
#endif
SEQ_printf(m, "active timers:\n");
print_active_timers(m, base, now);
@@ -140,10 +135,11 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
print_base(m, cpu_base->clock_base + i, now);
}
#define P(x) \
- SEQ_printf(m, " .%-15s: %Ld\n", #x, (u64)(cpu_base->x))
+ SEQ_printf(m, " .%-15s: %Lu\n", #x, \
+ (unsigned long long)(cpu_base->x))
#define P_ns(x) \
- SEQ_printf(m, " .%-15s: %Ld nsecs\n", #x, \
- (u64)(ktime_to_ns(cpu_base->x)))
+ SEQ_printf(m, " .%-15s: %Lu nsecs\n", #x, \
+ (unsigned long long)(ktime_to_ns(cpu_base->x)))
#ifdef CONFIG_HIGH_RES_TIMERS
P_ns(expires_next);
@@ -155,10 +151,11 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
#ifdef CONFIG_TICK_ONESHOT
# define P(x) \
- SEQ_printf(m, " .%-15s: %Ld\n", #x, (u64)(ts->x))
+ SEQ_printf(m, " .%-15s: %Lu\n", #x, \
+ (unsigned long long)(ts->x))
# define P_ns(x) \
- SEQ_printf(m, " .%-15s: %Ld nsecs\n", #x, \
- (u64)(ktime_to_ns(ts->x)))
+ SEQ_printf(m, " .%-15s: %Lu nsecs\n", #x, \
+ (unsigned long long)(ktime_to_ns(ts->x)))
{
struct tick_sched *ts = tick_get_tick_sched(cpu);
P(nohz_mode);
@@ -172,7 +169,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
P(last_jiffies);
P(next_jiffies);
P_ns(idle_expires);
- SEQ_printf(m, "jiffies: %Ld\n", (u64)jiffies);
+ SEQ_printf(m, "jiffies: %Lu\n",
+ (unsigned long long)jiffies);
}
#endif
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c
index 1bc4882e28e..868f1bceb07 100644
--- a/kernel/time/timer_stats.c
+++ b/kernel/time/timer_stats.c
@@ -257,16 +257,12 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
static void print_name_offset(struct seq_file *m, unsigned long addr)
{
- char namebuf[KSYM_NAME_LEN+1];
- unsigned long size, offset;
- const char *sym_name;
- char *modname;
-
- sym_name = kallsyms_lookup(addr, &size, &offset, &modname, namebuf);
- if (sym_name)
- seq_printf(m, "%s", sym_name);
- else
+ char symname[KSYM_NAME_LEN+1];
+
+ if (lookup_symbol_name(addr, symname) < 0)
seq_printf(m, "<%p>", (void *)addr);
+ else
+ seq_printf(m, "%s", symname);
}
static int tstats_show(struct seq_file *m, void *v)
diff --git a/kernel/timer.c b/kernel/timer.c
index b22bd39740d..59a28b1752f 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1,7 +1,7 @@
/*
* linux/kernel/timer.c
*
- * Kernel internal timers, kernel timekeeping, basic process system calls
+ * Kernel internal timers, basic process system calls
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
@@ -74,7 +74,7 @@ struct tvec_t_base_s {
tvec_t tv3;
tvec_t tv4;
tvec_t tv5;
-} ____cacheline_aligned_in_smp;
+} ____cacheline_aligned;
typedef struct tvec_t_base_s tvec_base_t;
@@ -82,6 +82,37 @@ tvec_base_t boot_tvec_bases;
EXPORT_SYMBOL(boot_tvec_bases);
static DEFINE_PER_CPU(tvec_base_t *, tvec_bases) = &boot_tvec_bases;
+/*
+ * Note that all tvec_bases is 2 byte aligned and lower bit of
+ * base in timer_list is guaranteed to be zero. Use the LSB for
+ * the new flag to indicate whether the timer is deferrable
+ */
+#define TBASE_DEFERRABLE_FLAG (0x1)
+
+/* Functions below help us manage 'deferrable' flag */
+static inline unsigned int tbase_get_deferrable(tvec_base_t *base)
+{
+ return (unsigned int)((unsigned long)base & TBASE_DEFERRABLE_FLAG);
+}
+
+static inline tvec_base_t *tbase_get_base(tvec_base_t *base)
+{
+ return (tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG);
+}
+
+static inline void timer_set_deferrable(struct timer_list *timer)
+{
+ timer->base = (tvec_base_t *)((unsigned long)timer->base |
+ TBASE_DEFERRABLE_FLAG);
+}
+
+static inline void
+timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
+{
+ timer->base = (tvec_base_t *)((unsigned long)new_base |
+ tbase_get_deferrable(timer->base));
+}
+
/**
* __round_jiffies - function to round jiffies to a full second
* @j: the time in (absolute) jiffies that should be rounded
@@ -295,6 +326,13 @@ void fastcall init_timer(struct timer_list *timer)
}
EXPORT_SYMBOL(init_timer);
+void fastcall init_timer_deferrable(struct timer_list *timer)
+{
+ init_timer(timer);
+ timer_set_deferrable(timer);
+}
+EXPORT_SYMBOL(init_timer_deferrable);
+
static inline void detach_timer(struct timer_list *timer,
int clear_pending)
{
@@ -325,10 +363,11 @@ static tvec_base_t *lock_timer_base(struct timer_list *timer,
tvec_base_t *base;
for (;;) {
- base = timer->base;
+ tvec_base_t *prelock_base = timer->base;
+ base = tbase_get_base(prelock_base);
if (likely(base != NULL)) {
spin_lock_irqsave(&base->lock, *flags);
- if (likely(base == timer->base))
+ if (likely(prelock_base == timer->base))
return base;
/* The timer has migrated to another CPU */
spin_unlock_irqrestore(&base->lock, *flags);
@@ -365,11 +404,11 @@ int __mod_timer(struct timer_list *timer, unsigned long expires)
*/
if (likely(base->running_timer != timer)) {
/* See the comment in lock_timer_base() */
- timer->base = NULL;
+ timer_set_base(timer, NULL);
spin_unlock(&base->lock);
base = new_base;
spin_lock(&base->lock);
- timer->base = base;
+ timer_set_base(timer, base);
}
}
@@ -397,7 +436,7 @@ void add_timer_on(struct timer_list *timer, int cpu)
timer_stats_timer_set_start_info(timer);
BUG_ON(timer_pending(timer) || !timer->function);
spin_lock_irqsave(&base->lock, flags);
- timer->base = base;
+ timer_set_base(timer, base);
internal_add_timer(base, timer);
spin_unlock_irqrestore(&base->lock, flags);
}
@@ -550,7 +589,7 @@ static int cascade(tvec_base_t *base, tvec_t *tv, int index)
* don't have to detach them individually.
*/
list_for_each_entry_safe(timer, tmp, &tv_list, entry) {
- BUG_ON(timer->base != base);
+ BUG_ON(tbase_get_base(timer->base) != base);
internal_add_timer(base, timer);
}
@@ -590,7 +629,7 @@ static inline void __run_timers(tvec_base_t *base)
void (*fn)(unsigned long);
unsigned long data;
- timer = list_entry(head->next,struct timer_list,entry);
+ timer = list_first_entry(head, struct timer_list,entry);
fn = timer->function;
data = timer->data;
@@ -636,6 +675,9 @@ static unsigned long __next_timer_interrupt(tvec_base_t *base)
index = slot = timer_jiffies & TVR_MASK;
do {
list_for_each_entry(nte, base->tv1.vec + slot, entry) {
+ if (tbase_get_deferrable(nte->base))
+ continue;
+
found = 1;
expires = nte->expires;
/* Look at the cascade bucket(s)? */
@@ -752,455 +794,6 @@ unsigned long next_timer_interrupt(void)
#endif
-/******************************************************************/
-
-/*
- * The current time
- * wall_to_monotonic is what we need to add to xtime (or xtime corrected
- * for sub jiffie times) to get to monotonic time. Monotonic is pegged
- * at zero at system boot time, so wall_to_monotonic will be negative,
- * however, we will ALWAYS keep the tv_nsec part positive so we can use
- * the usual normalization.
- */
-struct timespec xtime __attribute__ ((aligned (16)));
-struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
-
-EXPORT_SYMBOL(xtime);
-
-
-/* XXX - all of this timekeeping code should be later moved to time.c */
-#include <linux/clocksource.h>
-static struct clocksource *clock; /* pointer to current clocksource */
-
-#ifdef CONFIG_GENERIC_TIME
-/**
- * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook
- *
- * private function, must hold xtime_lock lock when being
- * called. Returns the number of nanoseconds since the
- * last call to update_wall_time() (adjusted by NTP scaling)
- */
-static inline s64 __get_nsec_offset(void)
-{
- cycle_t cycle_now, cycle_delta;
- s64 ns_offset;
-
- /* read clocksource: */
- cycle_now = clocksource_read(clock);
-
- /* calculate the delta since the last update_wall_time: */
- cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
-
- /* convert to nanoseconds: */
- ns_offset = cyc2ns(clock, cycle_delta);
-
- return ns_offset;
-}
-
-/**
- * __get_realtime_clock_ts - Returns the time of day in a timespec
- * @ts: pointer to the timespec to be set
- *
- * Returns the time of day in a timespec. Used by
- * do_gettimeofday() and get_realtime_clock_ts().
- */
-static inline void __get_realtime_clock_ts(struct timespec *ts)
-{
- unsigned long seq;
- s64 nsecs;
-
- do {
- seq = read_seqbegin(&xtime_lock);
-
- *ts = xtime;
- nsecs = __get_nsec_offset();
-
- } while (read_seqretry(&xtime_lock, seq));
-
- timespec_add_ns(ts, nsecs);
-}
-
-/**
- * getnstimeofday - Returns the time of day in a timespec
- * @ts: pointer to the timespec to be set
- *
- * Returns the time of day in a timespec.
- */
-void getnstimeofday(struct timespec *ts)
-{
- __get_realtime_clock_ts(ts);
-}
-
-EXPORT_SYMBOL(getnstimeofday);
-
-/**
- * do_gettimeofday - Returns the time of day in a timeval
- * @tv: pointer to the timeval to be set
- *
- * NOTE: Users should be converted to using get_realtime_clock_ts()
- */
-void do_gettimeofday(struct timeval *tv)
-{
- struct timespec now;
-
- __get_realtime_clock_ts(&now);
- tv->tv_sec = now.tv_sec;
- tv->tv_usec = now.tv_nsec/1000;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-/**
- * do_settimeofday - Sets the time of day
- * @tv: pointer to the timespec variable containing the new time
- *
- * Sets the time of day to the new time and update NTP and notify hrtimers
- */
-int do_settimeofday(struct timespec *tv)
-{
- unsigned long flags;
- time_t wtm_sec, sec = tv->tv_sec;
- long wtm_nsec, nsec = tv->tv_nsec;
-
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irqsave(&xtime_lock, flags);
-
- nsec -= __get_nsec_offset();
-
- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
- set_normalized_timespec(&xtime, sec, nsec);
- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
- clock->error = 0;
- ntp_clear();
-
- update_vsyscall(&xtime, clock);
-
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- /* signal hrtimers about time change */
- clock_was_set();
-
- return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
-/**
- * change_clocksource - Swaps clocksources if a new one is available
- *
- * Accumulates current time interval and initializes new clocksource
- */
-static void change_clocksource(void)
-{
- struct clocksource *new;
- cycle_t now;
- u64 nsec;
-
- new = clocksource_get_next();
-
- if (clock == new)
- return;
-
- now = clocksource_read(new);
- nsec = __get_nsec_offset();
- timespec_add_ns(&xtime, nsec);
-
- clock = new;
- clock->cycle_last = now;
-
- clock->error = 0;
- clock->xtime_nsec = 0;
- clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
-
- tick_clock_notify();
-
- printk(KERN_INFO "Time: %s clocksource has been installed.\n",
- clock->name);
-}
-#else
-static inline void change_clocksource(void) { }
-#endif
-
-/**
- * timekeeping_is_continuous - check to see if timekeeping is free running
- */
-int timekeeping_is_continuous(void)
-{
- unsigned long seq;
- int ret;
-
- do {
- seq = read_seqbegin(&xtime_lock);
-
- ret = clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
-
- } while (read_seqretry(&xtime_lock, seq));
-
- return ret;
-}
-
-/**
- * read_persistent_clock - Return time in seconds from the persistent clock.
- *
- * Weak dummy function for arches that do not yet support it.
- * Returns seconds from epoch using the battery backed persistent clock.
- * Returns zero if unsupported.
- *
- * XXX - Do be sure to remove it once all arches implement it.
- */
-unsigned long __attribute__((weak)) read_persistent_clock(void)
-{
- return 0;
-}
-
-/*
- * timekeeping_init - Initializes the clocksource and common timekeeping values
- */
-void __init timekeeping_init(void)
-{
- unsigned long flags;
- unsigned long sec = read_persistent_clock();
-
- write_seqlock_irqsave(&xtime_lock, flags);
-
- ntp_clear();
-
- clock = clocksource_get_next();
- clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
- clock->cycle_last = clocksource_read(clock);
-
- xtime.tv_sec = sec;
- xtime.tv_nsec = 0;
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
-
- write_sequnlock_irqrestore(&xtime_lock, flags);
-}
-
-/* flag for if timekeeping is suspended */
-static int timekeeping_suspended;
-/* time in seconds when suspend began */
-static unsigned long timekeeping_suspend_time;
-
-/**
- * timekeeping_resume - Resumes the generic timekeeping subsystem.
- * @dev: unused
- *
- * This is for the generic clocksource timekeeping.
- * xtime/wall_to_monotonic/jiffies/etc are
- * still managed by arch specific suspend/resume code.
- */
-static int timekeeping_resume(struct sys_device *dev)
-{
- unsigned long flags;
- unsigned long now = read_persistent_clock();
-
- write_seqlock_irqsave(&xtime_lock, flags);
-
- if (now && (now > timekeeping_suspend_time)) {
- unsigned long sleep_length = now - timekeeping_suspend_time;
-
- xtime.tv_sec += sleep_length;
- wall_to_monotonic.tv_sec -= sleep_length;
- }
- /* re-base the last cycle value */
- clock->cycle_last = clocksource_read(clock);
- clock->error = 0;
- timekeeping_suspended = 0;
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- touch_softlockup_watchdog();
-
- clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
-
- /* Resume hrtimers */
- hres_timers_resume();
-
- return 0;
-}
-
-static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
-{
- unsigned long flags;
-
- write_seqlock_irqsave(&xtime_lock, flags);
- timekeeping_suspended = 1;
- timekeeping_suspend_time = read_persistent_clock();
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
-
- return 0;
-}
-
-/* sysfs resume/suspend bits for timekeeping */
-static struct sysdev_class timekeeping_sysclass = {
- .resume = timekeeping_resume,
- .suspend = timekeeping_suspend,
- set_kset_name("timekeeping"),
-};
-
-static struct sys_device device_timer = {
- .id = 0,
- .cls = &timekeeping_sysclass,
-};
-
-static int __init timekeeping_init_device(void)
-{
- int error = sysdev_class_register(&timekeeping_sysclass);
- if (!error)
- error = sysdev_register(&device_timer);
- return error;
-}
-
-device_initcall(timekeeping_init_device);
-
-/*
- * If the error is already larger, we look ahead even further
- * to compensate for late or lost adjustments.
- */
-static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
- s64 *offset)
-{
- s64 tick_error, i;
- u32 look_ahead, adj;
- s32 error2, mult;
-
- /*
- * Use the current error value to determine how much to look ahead.
- * The larger the error the slower we adjust for it to avoid problems
- * with losing too many ticks, otherwise we would overadjust and
- * produce an even larger error. The smaller the adjustment the
- * faster we try to adjust for it, as lost ticks can do less harm
- * here. This is tuned so that an error of about 1 msec is adusted
- * within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
- */
- error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
- error2 = abs(error2);
- for (look_ahead = 0; error2 > 0; look_ahead++)
- error2 >>= 2;
-
- /*
- * Now calculate the error in (1 << look_ahead) ticks, but first
- * remove the single look ahead already included in the error.
- */
- tick_error = current_tick_length() >>
- (TICK_LENGTH_SHIFT - clock->shift + 1);
- tick_error -= clock->xtime_interval >> 1;
- error = ((error - tick_error) >> look_ahead) + tick_error;
-
- /* Finally calculate the adjustment shift value. */
- i = *interval;
- mult = 1;
- if (error < 0) {
- error = -error;
- *interval = -*interval;
- *offset = -*offset;
- mult = -1;
- }
- for (adj = 0; error > i; adj++)
- error >>= 1;
-
- *interval <<= adj;
- *offset <<= adj;
- return mult << adj;
-}
-
-/*
- * Adjust the multiplier to reduce the error value,
- * this is optimized for the most common adjustments of -1,0,1,
- * for other values we can do a bit more work.
- */
-static void clocksource_adjust(struct clocksource *clock, s64 offset)
-{
- s64 error, interval = clock->cycle_interval;
- int adj;
-
- error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
- if (error > interval) {
- error >>= 2;
- if (likely(error <= interval))
- adj = 1;
- else
- adj = clocksource_bigadjust(error, &interval, &offset);
- } else if (error < -interval) {
- error >>= 2;
- if (likely(error >= -interval)) {
- adj = -1;
- interval = -interval;
- offset = -offset;
- } else
- adj = clocksource_bigadjust(error, &interval, &offset);
- } else
- return;
-
- clock->mult += adj;
- clock->xtime_interval += interval;
- clock->xtime_nsec -= offset;
- clock->error -= (interval - offset) <<
- (TICK_LENGTH_SHIFT - clock->shift);
-}
-
-/**
- * update_wall_time - Uses the current clocksource to increment the wall time
- *
- * Called from the timer interrupt, must hold a write on xtime_lock.
- */
-static void update_wall_time(void)
-{
- cycle_t offset;
-
- /* Make sure we're fully resumed: */
- if (unlikely(timekeeping_suspended))
- return;
-
-#ifdef CONFIG_GENERIC_TIME
- offset = (clocksource_read(clock) - clock->cycle_last) & clock->mask;
-#else
- offset = clock->cycle_interval;
-#endif
- clock->xtime_nsec += (s64)xtime.tv_nsec << clock->shift;
-
- /* normally this loop will run just once, however in the
- * case of lost or late ticks, it will accumulate correctly.
- */
- while (offset >= clock->cycle_interval) {
- /* accumulate one interval */
- clock->xtime_nsec += clock->xtime_interval;
- clock->cycle_last += clock->cycle_interval;
- offset -= clock->cycle_interval;
-
- if (clock->xtime_nsec >= (u64)NSEC_PER_SEC << clock->shift) {
- clock->xtime_nsec -= (u64)NSEC_PER_SEC << clock->shift;
- xtime.tv_sec++;
- second_overflow();
- }
-
- /* interpolator bits */
- time_interpolator_update(clock->xtime_interval
- >> clock->shift);
-
- /* accumulate error between NTP and clock interval */
- clock->error += current_tick_length();
- clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
- }
-
- /* correct the clock when NTP error is too big */
- clocksource_adjust(clock, offset);
-
- /* store full nanoseconds into xtime */
- xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
- clock->xtime_nsec -= (s64)xtime.tv_nsec << clock->shift;
-
- /* check to see if there is a new clocksource to use */
- change_clocksource();
- update_vsyscall(&xtime, clock);
-}
-
/*
* Called from the timer interrupt handler to charge one tick to the current
* process. user_tick is 1 if the tick is user time, 0 for system.
@@ -1264,14 +857,6 @@ static inline void calc_load(unsigned long ticks)
}
/*
- * This read-write spinlock protects us from races in SMP while
- * playing with xtime and avenrun.
- */
-__attribute__((weak)) __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
-
-EXPORT_SYMBOL(xtime_lock);
-
-/*
* This function runs timers and the timer-tq in bottom half context.
*/
static void run_timer_softirq(struct softirq_action *h)
@@ -1617,6 +1202,13 @@ static int __devinit init_timers_cpu(int cpu)
cpu_to_node(cpu));
if (!base)
return -ENOMEM;
+
+ /* Make sure that tvec_base is 2 byte aligned */
+ if (tbase_get_deferrable(base)) {
+ WARN_ON(1);
+ kfree(base);
+ return -ENOMEM;
+ }
memset(base, 0, sizeof(*base));
per_cpu(tvec_bases, cpu) = base;
} else {
@@ -1656,9 +1248,9 @@ static void migrate_timer_list(tvec_base_t *new_base, struct list_head *head)
struct timer_list *timer;
while (!list_empty(head)) {
- timer = list_entry(head->next, struct timer_list, entry);
+ timer = list_first_entry(head, struct timer_list, entry);
detach_timer(timer, 0);
- timer->base = new_base;
+ timer_set_base(timer, new_base);
internal_add_timer(new_base, timer);
}
}
@@ -1701,11 +1293,13 @@ static int __cpuinit timer_cpu_notify(struct notifier_block *self,
long cpu = (long)hcpu;
switch(action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
if (init_timers_cpu(cpu) < 0)
return NOTIFY_BAD;
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
migrate_timers(cpu);
break;
#endif
@@ -1905,6 +1499,8 @@ unregister_time_interpolator(struct time_interpolator *ti)
prev = &curr->next;
}
+ clocksource_resume();
+
write_seqlock_irqsave(&xtime_lock, flags);
if (ti == time_interpolator) {
/* we lost the best time-interpolator: */
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 187e2a42387..dd308ba4e03 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -6,7 +6,6 @@
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/mman.h>
-#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/prctl.h>
diff --git a/kernel/utsname.c b/kernel/utsname.c
index c859164a699..160c8c5136b 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -32,58 +32,25 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
}
/*
- * unshare the current process' utsname namespace.
- * called only in sys_unshare()
- */
-int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts)
-{
- if (unshare_flags & CLONE_NEWUTS) {
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- *new_uts = clone_uts_ns(current->nsproxy->uts_ns);
- if (!*new_uts)
- return -ENOMEM;
- }
-
- return 0;
-}
-
-/*
* Copy task tsk's utsname namespace, or clone it if flags
* specifies CLONE_NEWUTS. In latter case, changes to the
* utsname of this process won't be seen by parent, and vice
* versa.
*/
-int copy_utsname(int flags, struct task_struct *tsk)
+struct uts_namespace *copy_utsname(int flags, struct uts_namespace *old_ns)
{
- struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
struct uts_namespace *new_ns;
- int err = 0;
-
- if (!old_ns)
- return 0;
+ BUG_ON(!old_ns);
get_uts_ns(old_ns);
if (!(flags & CLONE_NEWUTS))
- return 0;
-
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto out;
- }
+ return old_ns;
new_ns = clone_uts_ns(old_ns);
- if (!new_ns) {
- err = -ENOMEM;
- goto out;
- }
- tsk->nsproxy->uts_ns = new_ns;
-out:
put_uts_ns(old_ns);
- return err;
+ return new_ns;
}
void free_uts_ns(struct kref *kref)
diff --git a/kernel/wait.c b/kernel/wait.c
index 59a82f63275..444ddbfaefc 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -61,7 +61,7 @@ EXPORT_SYMBOL(remove_wait_queue);
* The spin_unlock() itself is semi-permeable and only protects
* one way (it only protects stuff inside the critical region and
* stops them from bleeding out - it would still allow subsequent
- * loads to move into the the critical region).
+ * loads to move into the critical region).
*/
void fastcall
prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index b6fa5e63085..fb56fedd5c0 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -36,30 +36,20 @@
/*
* The per-CPU workqueue (if single thread, we always use the first
* possible cpu).
- *
- * The sequence counters are for flush_scheduled_work(). It wants to wait
- * until all currently-scheduled works are completed, but it doesn't
- * want to be livelocked by new, incoming ones. So it waits until
- * remove_sequence is >= the insert_sequence which pertained when
- * flush_scheduled_work() was called.
*/
struct cpu_workqueue_struct {
spinlock_t lock;
- long remove_sequence; /* Least-recently added (next to run) */
- long insert_sequence; /* Next to add */
-
struct list_head worklist;
wait_queue_head_t more_work;
- wait_queue_head_t work_done;
+ struct work_struct *current_work;
struct workqueue_struct *wq;
struct task_struct *thread;
+ int should_stop;
int run_depth; /* Detect run_workqueue() recursion depth */
-
- int freezeable; /* Freeze the thread during suspend */
} ____cacheline_aligned;
/*
@@ -68,8 +58,10 @@ struct cpu_workqueue_struct {
*/
struct workqueue_struct {
struct cpu_workqueue_struct *cpu_wq;
+ struct list_head list;
const char *name;
- struct list_head list; /* Empty if single thread */
+ int singlethread;
+ int freezeable; /* Freeze threads during suspend */
};
/* All the per-cpu workqueues on the system, for hotplug cpu to add/remove
@@ -77,106 +69,68 @@ struct workqueue_struct {
static DEFINE_MUTEX(workqueue_mutex);
static LIST_HEAD(workqueues);
-static int singlethread_cpu;
+static int singlethread_cpu __read_mostly;
+static cpumask_t cpu_singlethread_map __read_mostly;
+/* optimization, we could use cpu_possible_map */
+static cpumask_t cpu_populated_map __read_mostly;
/* If it's single threaded, it isn't in the list of workqueues. */
static inline int is_single_threaded(struct workqueue_struct *wq)
{
- return list_empty(&wq->list);
+ return wq->singlethread;
+}
+
+static const cpumask_t *wq_cpu_map(struct workqueue_struct *wq)
+{
+ return is_single_threaded(wq)
+ ? &cpu_singlethread_map : &cpu_populated_map;
+}
+
+static
+struct cpu_workqueue_struct *wq_per_cpu(struct workqueue_struct *wq, int cpu)
+{
+ if (unlikely(is_single_threaded(wq)))
+ cpu = singlethread_cpu;
+ return per_cpu_ptr(wq->cpu_wq, cpu);
}
/*
* Set the workqueue on which a work item is to be run
* - Must *only* be called if the pending flag is set
*/
-static inline void set_wq_data(struct work_struct *work, void *wq)
+static inline void set_wq_data(struct work_struct *work,
+ struct cpu_workqueue_struct *cwq)
{
unsigned long new;
BUG_ON(!work_pending(work));
- new = (unsigned long) wq | (1UL << WORK_STRUCT_PENDING);
+ new = (unsigned long) cwq | (1UL << WORK_STRUCT_PENDING);
new |= WORK_STRUCT_FLAG_MASK & *work_data_bits(work);
atomic_long_set(&work->data, new);
}
-static inline void *get_wq_data(struct work_struct *work)
+static inline
+struct cpu_workqueue_struct *get_wq_data(struct work_struct *work)
{
return (void *) (atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
}
-static int __run_work(struct cpu_workqueue_struct *cwq, struct work_struct *work)
+static void insert_work(struct cpu_workqueue_struct *cwq,
+ struct work_struct *work, int tail)
{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&cwq->lock, flags);
+ set_wq_data(work, cwq);
/*
- * We need to re-validate the work info after we've gotten
- * the cpu_workqueue lock. We can run the work now iff:
- *
- * - the wq_data still matches the cpu_workqueue_struct
- * - AND the work is still marked pending
- * - AND the work is still on a list (which will be this
- * workqueue_struct list)
- *
- * All these conditions are important, because we
- * need to protect against the work being run right
- * now on another CPU (all but the last one might be
- * true if it's currently running and has not been
- * released yet, for example).
+ * Ensure that we get the right work->data if we see the
+ * result of list_add() below, see try_to_grab_pending().
*/
- if (get_wq_data(work) == cwq
- && work_pending(work)
- && !list_empty(&work->entry)) {
- work_func_t f = work->func;
- list_del_init(&work->entry);
- spin_unlock_irqrestore(&cwq->lock, flags);
-
- if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
- work_release(work);
- f(work);
-
- spin_lock_irqsave(&cwq->lock, flags);
- cwq->remove_sequence++;
- wake_up(&cwq->work_done);
- ret = 1;
- }
- spin_unlock_irqrestore(&cwq->lock, flags);
- return ret;
-}
-
-/**
- * run_scheduled_work - run scheduled work synchronously
- * @work: work to run
- *
- * This checks if the work was pending, and runs it
- * synchronously if so. It returns a boolean to indicate
- * whether it had any scheduled work to run or not.
- *
- * NOTE! This _only_ works for normal work_structs. You
- * CANNOT use this for delayed work, because the wq data
- * for delayed work will not point properly to the per-
- * CPU workqueue struct, but will change!
- */
-int fastcall run_scheduled_work(struct work_struct *work)
-{
- for (;;) {
- struct cpu_workqueue_struct *cwq;
-
- if (!work_pending(work))
- return 0;
- if (list_empty(&work->entry))
- return 0;
- /* NOTE! This depends intimately on __queue_work! */
- cwq = get_wq_data(work);
- if (!cwq)
- return 0;
- if (__run_work(cwq, work))
- return 1;
- }
+ smp_wmb();
+ if (tail)
+ list_add_tail(&work->entry, &cwq->worklist);
+ else
+ list_add(&work->entry, &cwq->worklist);
+ wake_up(&cwq->more_work);
}
-EXPORT_SYMBOL(run_scheduled_work);
/* Preempt must be disabled. */
static void __queue_work(struct cpu_workqueue_struct *cwq,
@@ -185,10 +139,7 @@ static void __queue_work(struct cpu_workqueue_struct *cwq,
unsigned long flags;
spin_lock_irqsave(&cwq->lock, flags);
- set_wq_data(work, cwq);
- list_add_tail(&work->entry, &cwq->worklist);
- cwq->insert_sequence++;
- wake_up(&cwq->more_work);
+ insert_work(cwq, work, 1);
spin_unlock_irqrestore(&cwq->lock, flags);
}
@@ -204,16 +155,14 @@ static void __queue_work(struct cpu_workqueue_struct *cwq,
*/
int fastcall queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
- int ret = 0, cpu = get_cpu();
+ int ret = 0;
if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
- if (unlikely(is_single_threaded(wq)))
- cpu = singlethread_cpu;
BUG_ON(!list_empty(&work->entry));
- __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
+ __queue_work(wq_per_cpu(wq, get_cpu()), work);
+ put_cpu();
ret = 1;
}
- put_cpu();
return ret;
}
EXPORT_SYMBOL_GPL(queue_work);
@@ -221,13 +170,10 @@ EXPORT_SYMBOL_GPL(queue_work);
void delayed_work_timer_fn(unsigned long __data)
{
struct delayed_work *dwork = (struct delayed_work *)__data;
- struct workqueue_struct *wq = get_wq_data(&dwork->work);
- int cpu = smp_processor_id();
+ struct cpu_workqueue_struct *cwq = get_wq_data(&dwork->work);
+ struct workqueue_struct *wq = cwq->wq;
- if (unlikely(is_single_threaded(wq)))
- cpu = singlethread_cpu;
-
- __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), &dwork->work);
+ __queue_work(wq_per_cpu(wq, smp_processor_id()), &dwork->work);
}
/**
@@ -241,27 +187,11 @@ void delayed_work_timer_fn(unsigned long __data)
int fastcall queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay)
{
- int ret = 0;
- struct timer_list *timer = &dwork->timer;
- struct work_struct *work = &dwork->work;
-
- timer_stats_timer_set_start_info(timer);
+ timer_stats_timer_set_start_info(&dwork->timer);
if (delay == 0)
- return queue_work(wq, work);
-
- if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
- BUG_ON(timer_pending(timer));
- BUG_ON(!list_empty(&work->entry));
+ return queue_work(wq, &dwork->work);
- /* This stores wq for the moment, for the timer_fn */
- set_wq_data(work, wq);
- timer->expires = jiffies + delay;
- timer->data = (unsigned long)dwork;
- timer->function = delayed_work_timer_fn;
- add_timer(timer);
- ret = 1;
- }
- return ret;
+ return queue_delayed_work_on(-1, wq, dwork, delay);
}
EXPORT_SYMBOL_GPL(queue_delayed_work);
@@ -285,12 +215,16 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
BUG_ON(timer_pending(timer));
BUG_ON(!list_empty(&work->entry));
- /* This stores wq for the moment, for the timer_fn */
- set_wq_data(work, wq);
+ /* This stores cwq for the moment, for the timer_fn */
+ set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
timer->expires = jiffies + delay;
timer->data = (unsigned long)dwork;
timer->function = delayed_work_timer_fn;
- add_timer_on(timer, cpu);
+
+ if (unlikely(cpu >= 0))
+ add_timer_on(timer, cpu);
+ else
+ add_timer(timer);
ret = 1;
}
return ret;
@@ -299,13 +233,7 @@ EXPORT_SYMBOL_GPL(queue_delayed_work_on);
static void run_workqueue(struct cpu_workqueue_struct *cwq)
{
- unsigned long flags;
-
- /*
- * Keep taking off work from the queue until
- * done.
- */
- spin_lock_irqsave(&cwq->lock, flags);
+ spin_lock_irq(&cwq->lock);
cwq->run_depth++;
if (cwq->run_depth > 3) {
/* morton gets to eat his hat */
@@ -318,12 +246,12 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
struct work_struct, entry);
work_func_t f = work->func;
+ cwq->current_work = work;
list_del_init(cwq->worklist.next);
- spin_unlock_irqrestore(&cwq->lock, flags);
+ spin_unlock_irq(&cwq->lock);
BUG_ON(get_wq_data(work) != cwq);
- if (!test_bit(WORK_STRUCT_NOAUTOREL, work_data_bits(work)))
- work_release(work);
+ work_clear_pending(work);
f(work);
if (unlikely(in_atomic() || lockdep_depth(current) > 0)) {
@@ -337,63 +265,81 @@ static void run_workqueue(struct cpu_workqueue_struct *cwq)
dump_stack();
}
- spin_lock_irqsave(&cwq->lock, flags);
- cwq->remove_sequence++;
- wake_up(&cwq->work_done);
+ spin_lock_irq(&cwq->lock);
+ cwq->current_work = NULL;
}
cwq->run_depth--;
- spin_unlock_irqrestore(&cwq->lock, flags);
+ spin_unlock_irq(&cwq->lock);
+}
+
+/*
+ * NOTE: the caller must not touch *cwq if this func returns true
+ */
+static int cwq_should_stop(struct cpu_workqueue_struct *cwq)
+{
+ int should_stop = cwq->should_stop;
+
+ if (unlikely(should_stop)) {
+ spin_lock_irq(&cwq->lock);
+ should_stop = cwq->should_stop && list_empty(&cwq->worklist);
+ if (should_stop)
+ cwq->thread = NULL;
+ spin_unlock_irq(&cwq->lock);
+ }
+
+ return should_stop;
}
static int worker_thread(void *__cwq)
{
struct cpu_workqueue_struct *cwq = __cwq;
- DECLARE_WAITQUEUE(wait, current);
- struct k_sigaction sa;
- sigset_t blocked;
+ DEFINE_WAIT(wait);
- if (!cwq->freezeable)
+ if (!cwq->wq->freezeable)
current->flags |= PF_NOFREEZE;
set_user_nice(current, -5);
- /* Block and flush all signals */
- sigfillset(&blocked);
- sigprocmask(SIG_BLOCK, &blocked, NULL);
- flush_signals(current);
-
- /*
- * We inherited MPOL_INTERLEAVE from the booting kernel.
- * Set MPOL_DEFAULT to insure node local allocations.
- */
- numa_default_policy();
-
- /* SIG_IGN makes children autoreap: see do_notify_parent(). */
- sa.sa.sa_handler = SIG_IGN;
- sa.sa.sa_flags = 0;
- siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
- do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+ for (;;) {
+ prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE);
+ if (!freezing(current) && !cwq->should_stop
+ && list_empty(&cwq->worklist))
+ schedule();
+ finish_wait(&cwq->more_work, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
- while (!kthread_should_stop()) {
- if (cwq->freezeable)
- try_to_freeze();
+ try_to_freeze();
- add_wait_queue(&cwq->more_work, &wait);
- if (list_empty(&cwq->worklist))
- schedule();
- else
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&cwq->more_work, &wait);
+ if (cwq_should_stop(cwq))
+ break;
- if (!list_empty(&cwq->worklist))
- run_workqueue(cwq);
- set_current_state(TASK_INTERRUPTIBLE);
+ run_workqueue(cwq);
}
- __set_current_state(TASK_RUNNING);
+
return 0;
}
+struct wq_barrier {
+ struct work_struct work;
+ struct completion done;
+};
+
+static void wq_barrier_func(struct work_struct *work)
+{
+ struct wq_barrier *barr = container_of(work, struct wq_barrier, work);
+ complete(&barr->done);
+}
+
+static void insert_wq_barrier(struct cpu_workqueue_struct *cwq,
+ struct wq_barrier *barr, int tail)
+{
+ INIT_WORK(&barr->work, wq_barrier_func);
+ __set_bit(WORK_STRUCT_PENDING, work_data_bits(&barr->work));
+
+ init_completion(&barr->done);
+
+ insert_work(cwq, &barr->work, tail);
+}
+
static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
{
if (cwq->thread == current) {
@@ -403,21 +349,18 @@ static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
*/
run_workqueue(cwq);
} else {
- DEFINE_WAIT(wait);
- long sequence_needed;
+ struct wq_barrier barr;
+ int active = 0;
spin_lock_irq(&cwq->lock);
- sequence_needed = cwq->insert_sequence;
-
- while (sequence_needed - cwq->remove_sequence > 0) {
- prepare_to_wait(&cwq->work_done, &wait,
- TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&cwq->lock);
- schedule();
- spin_lock_irq(&cwq->lock);
+ if (!list_empty(&cwq->worklist) || cwq->current_work != NULL) {
+ insert_wq_barrier(cwq, &barr, 1);
+ active = 1;
}
- finish_wait(&cwq->work_done, &wait);
spin_unlock_irq(&cwq->lock);
+
+ if (active)
+ wait_for_completion(&barr.done);
}
}
@@ -428,151 +371,145 @@ static void flush_cpu_workqueue(struct cpu_workqueue_struct *cwq)
* Forces execution of the workqueue and blocks until its completion.
* This is typically used in driver shutdown handlers.
*
- * This function will sample each workqueue's current insert_sequence number and
- * will sleep until the head sequence is greater than or equal to that. This
- * means that we sleep until all works which were queued on entry have been
- * handled, but we are not livelocked by new incoming ones.
+ * We sleep until all works which were queued on entry have been handled,
+ * but we are not livelocked by new incoming ones.
*
* This function used to run the workqueues itself. Now we just wait for the
* helper threads to do it.
*/
void fastcall flush_workqueue(struct workqueue_struct *wq)
{
+ const cpumask_t *cpu_map = wq_cpu_map(wq);
+ int cpu;
+
might_sleep();
+ for_each_cpu_mask(cpu, *cpu_map)
+ flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
+}
+EXPORT_SYMBOL_GPL(flush_workqueue);
- if (is_single_threaded(wq)) {
- /* Always use first cpu's area. */
- flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, singlethread_cpu));
- } else {
- int cpu;
+/*
+ * Upon a successful return, the caller "owns" WORK_STRUCT_PENDING bit,
+ * so this work can't be re-armed in any way.
+ */
+static int try_to_grab_pending(struct work_struct *work)
+{
+ struct cpu_workqueue_struct *cwq;
+ int ret = 0;
- mutex_lock(&workqueue_mutex);
- for_each_online_cpu(cpu)
- flush_cpu_workqueue(per_cpu_ptr(wq->cpu_wq, cpu));
- mutex_unlock(&workqueue_mutex);
+ if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work)))
+ return 1;
+
+ /*
+ * The queueing is in progress, or it is already queued. Try to
+ * steal it from ->worklist without clearing WORK_STRUCT_PENDING.
+ */
+
+ cwq = get_wq_data(work);
+ if (!cwq)
+ return ret;
+
+ spin_lock_irq(&cwq->lock);
+ if (!list_empty(&work->entry)) {
+ /*
+ * This work is queued, but perhaps we locked the wrong cwq.
+ * In that case we must see the new value after rmb(), see
+ * insert_work()->wmb().
+ */
+ smp_rmb();
+ if (cwq == get_wq_data(work)) {
+ list_del_init(&work->entry);
+ ret = 1;
+ }
}
+ spin_unlock_irq(&cwq->lock);
+
+ return ret;
}
-EXPORT_SYMBOL_GPL(flush_workqueue);
-static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq,
- int cpu, int freezeable)
+static void wait_on_cpu_work(struct cpu_workqueue_struct *cwq,
+ struct work_struct *work)
{
- struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
- struct task_struct *p;
+ struct wq_barrier barr;
+ int running = 0;
- spin_lock_init(&cwq->lock);
- cwq->wq = wq;
- cwq->thread = NULL;
- cwq->insert_sequence = 0;
- cwq->remove_sequence = 0;
- cwq->freezeable = freezeable;
- INIT_LIST_HEAD(&cwq->worklist);
- init_waitqueue_head(&cwq->more_work);
- init_waitqueue_head(&cwq->work_done);
+ spin_lock_irq(&cwq->lock);
+ if (unlikely(cwq->current_work == work)) {
+ insert_wq_barrier(cwq, &barr, 0);
+ running = 1;
+ }
+ spin_unlock_irq(&cwq->lock);
- if (is_single_threaded(wq))
- p = kthread_create(worker_thread, cwq, "%s", wq->name);
- else
- p = kthread_create(worker_thread, cwq, "%s/%d", wq->name, cpu);
- if (IS_ERR(p))
- return NULL;
- cwq->thread = p;
- return p;
+ if (unlikely(running))
+ wait_for_completion(&barr.done);
}
-struct workqueue_struct *__create_workqueue(const char *name,
- int singlethread, int freezeable)
+static void wait_on_work(struct work_struct *work)
{
- int cpu, destroy = 0;
+ struct cpu_workqueue_struct *cwq;
struct workqueue_struct *wq;
- struct task_struct *p;
+ const cpumask_t *cpu_map;
+ int cpu;
- wq = kzalloc(sizeof(*wq), GFP_KERNEL);
- if (!wq)
- return NULL;
+ might_sleep();
- wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
- if (!wq->cpu_wq) {
- kfree(wq);
- return NULL;
- }
+ cwq = get_wq_data(work);
+ if (!cwq)
+ return;
- wq->name = name;
- mutex_lock(&workqueue_mutex);
- if (singlethread) {
- INIT_LIST_HEAD(&wq->list);
- p = create_workqueue_thread(wq, singlethread_cpu, freezeable);
- if (!p)
- destroy = 1;
- else
- wake_up_process(p);
- } else {
- list_add(&wq->list, &workqueues);
- for_each_online_cpu(cpu) {
- p = create_workqueue_thread(wq, cpu, freezeable);
- if (p) {
- kthread_bind(p, cpu);
- wake_up_process(p);
- } else
- destroy = 1;
- }
- }
- mutex_unlock(&workqueue_mutex);
+ wq = cwq->wq;
+ cpu_map = wq_cpu_map(wq);
- /*
- * Was there any error during startup? If yes then clean up:
- */
- if (destroy) {
- destroy_workqueue(wq);
- wq = NULL;
- }
- return wq;
+ for_each_cpu_mask(cpu, *cpu_map)
+ wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
}
-EXPORT_SYMBOL_GPL(__create_workqueue);
-static void cleanup_workqueue_thread(struct workqueue_struct *wq, int cpu)
+/**
+ * cancel_work_sync - block until a work_struct's callback has terminated
+ * @work: the work which is to be flushed
+ *
+ * cancel_work_sync() will cancel the work if it is queued. If the work's
+ * callback appears to be running, cancel_work_sync() will block until it
+ * has completed.
+ *
+ * It is possible to use this function if the work re-queues itself. It can
+ * cancel the work even if it migrates to another workqueue, however in that
+ * case it only guarantees that work->func() has completed on the last queued
+ * workqueue.
+ *
+ * cancel_work_sync(&delayed_work->work) should be used only if ->timer is not
+ * pending, otherwise it goes into a busy-wait loop until the timer expires.
+ *
+ * The caller must ensure that workqueue_struct on which this work was last
+ * queued can't be destroyed before this function returns.
+ */
+void cancel_work_sync(struct work_struct *work)
{
- struct cpu_workqueue_struct *cwq;
- unsigned long flags;
- struct task_struct *p;
-
- cwq = per_cpu_ptr(wq->cpu_wq, cpu);
- spin_lock_irqsave(&cwq->lock, flags);
- p = cwq->thread;
- cwq->thread = NULL;
- spin_unlock_irqrestore(&cwq->lock, flags);
- if (p)
- kthread_stop(p);
+ while (!try_to_grab_pending(work))
+ cpu_relax();
+ wait_on_work(work);
+ work_clear_pending(work);
}
+EXPORT_SYMBOL_GPL(cancel_work_sync);
/**
- * destroy_workqueue - safely terminate a workqueue
- * @wq: target workqueue
+ * cancel_rearming_delayed_work - reliably kill off a delayed work.
+ * @dwork: the delayed work struct
*
- * Safely destroy a workqueue. All work currently pending will be done first.
+ * It is possible to use this function if @dwork rearms itself via queue_work()
+ * or queue_delayed_work(). See also the comment for cancel_work_sync().
*/
-void destroy_workqueue(struct workqueue_struct *wq)
+void cancel_rearming_delayed_work(struct delayed_work *dwork)
{
- int cpu;
-
- flush_workqueue(wq);
-
- /* We don't need the distraction of CPUs appearing and vanishing. */
- mutex_lock(&workqueue_mutex);
- if (is_single_threaded(wq))
- cleanup_workqueue_thread(wq, singlethread_cpu);
- else {
- for_each_online_cpu(cpu)
- cleanup_workqueue_thread(wq, cpu);
- list_del(&wq->list);
- }
- mutex_unlock(&workqueue_mutex);
- free_percpu(wq->cpu_wq);
- kfree(wq);
+ while (!del_timer(&dwork->timer) &&
+ !try_to_grab_pending(&dwork->work))
+ cpu_relax();
+ wait_on_work(&dwork->work);
+ work_clear_pending(&dwork->work);
}
-EXPORT_SYMBOL_GPL(destroy_workqueue);
+EXPORT_SYMBOL(cancel_rearming_delayed_work);
-static struct workqueue_struct *keventd_wq;
+static struct workqueue_struct *keventd_wq __read_mostly;
/**
* schedule_work - put work task in global workqueue
@@ -638,7 +575,7 @@ int schedule_on_each_cpu(work_func_t func)
if (!works)
return -ENOMEM;
- mutex_lock(&workqueue_mutex);
+ preempt_disable(); /* CPU hotplug */
for_each_online_cpu(cpu) {
struct work_struct *work = per_cpu_ptr(works, cpu);
@@ -646,7 +583,7 @@ int schedule_on_each_cpu(work_func_t func)
set_bit(WORK_STRUCT_PENDING, work_data_bits(work));
__queue_work(per_cpu_ptr(keventd_wq->cpu_wq, cpu), work);
}
- mutex_unlock(&workqueue_mutex);
+ preempt_enable();
flush_workqueue(keventd_wq);
free_percpu(works);
return 0;
@@ -659,29 +596,6 @@ void flush_scheduled_work(void)
EXPORT_SYMBOL(flush_scheduled_work);
/**
- * cancel_rearming_delayed_workqueue - reliably kill off a delayed work whose handler rearms the delayed work.
- * @wq: the controlling workqueue structure
- * @dwork: the delayed work struct
- */
-void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
- struct delayed_work *dwork)
-{
- while (!cancel_delayed_work(dwork))
- flush_workqueue(wq);
-}
-EXPORT_SYMBOL(cancel_rearming_delayed_workqueue);
-
-/**
- * cancel_rearming_delayed_work - reliably kill off a delayed keventd work whose handler rearms the delayed work.
- * @dwork: the delayed work struct
- */
-void cancel_rearming_delayed_work(struct delayed_work *dwork)
-{
- cancel_rearming_delayed_workqueue(keventd_wq, dwork);
-}
-EXPORT_SYMBOL(cancel_rearming_delayed_work);
-
-/**
* execute_in_process_context - reliably execute the routine with user context
* @fn: the function to execute
* @ew: guaranteed storage for the execute work structure (must
@@ -728,94 +642,209 @@ int current_is_keventd(void)
}
-/* Take the work from this (downed) CPU. */
-static void take_over_work(struct workqueue_struct *wq, unsigned int cpu)
+static struct cpu_workqueue_struct *
+init_cpu_workqueue(struct workqueue_struct *wq, int cpu)
{
struct cpu_workqueue_struct *cwq = per_cpu_ptr(wq->cpu_wq, cpu);
- struct list_head list;
- struct work_struct *work;
- spin_lock_irq(&cwq->lock);
- list_replace_init(&cwq->worklist, &list);
+ cwq->wq = wq;
+ spin_lock_init(&cwq->lock);
+ INIT_LIST_HEAD(&cwq->worklist);
+ init_waitqueue_head(&cwq->more_work);
+
+ return cwq;
+}
+
+static int create_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+ struct workqueue_struct *wq = cwq->wq;
+ const char *fmt = is_single_threaded(wq) ? "%s" : "%s/%d";
+ struct task_struct *p;
+
+ p = kthread_create(worker_thread, cwq, fmt, wq->name, cpu);
+ /*
+ * Nobody can add the work_struct to this cwq,
+ * if (caller is __create_workqueue)
+ * nobody should see this wq
+ * else // caller is CPU_UP_PREPARE
+ * cpu is not on cpu_online_map
+ * so we can abort safely.
+ */
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ cwq->thread = p;
+ cwq->should_stop = 0;
+
+ return 0;
+}
+
+static void start_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+ struct task_struct *p = cwq->thread;
- while (!list_empty(&list)) {
- printk("Taking work for %s\n", wq->name);
- work = list_entry(list.next,struct work_struct,entry);
- list_del(&work->entry);
- __queue_work(per_cpu_ptr(wq->cpu_wq, smp_processor_id()), work);
+ if (p != NULL) {
+ if (cpu >= 0)
+ kthread_bind(p, cpu);
+ wake_up_process(p);
}
- spin_unlock_irq(&cwq->lock);
}
-/* We're holding the cpucontrol mutex here */
-static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
- unsigned long action,
- void *hcpu)
+struct workqueue_struct *__create_workqueue(const char *name,
+ int singlethread, int freezeable)
{
- unsigned int hotcpu = (unsigned long)hcpu;
struct workqueue_struct *wq;
+ struct cpu_workqueue_struct *cwq;
+ int err = 0, cpu;
- switch (action) {
- case CPU_UP_PREPARE:
- mutex_lock(&workqueue_mutex);
- /* Create a new workqueue thread for it. */
- list_for_each_entry(wq, &workqueues, list) {
- if (!create_workqueue_thread(wq, hotcpu, 0)) {
- printk("workqueue for %i failed\n", hotcpu);
- return NOTIFY_BAD;
- }
- }
- break;
+ wq = kzalloc(sizeof(*wq), GFP_KERNEL);
+ if (!wq)
+ return NULL;
- case CPU_ONLINE:
- /* Kick off worker threads. */
- list_for_each_entry(wq, &workqueues, list) {
- struct cpu_workqueue_struct *cwq;
+ wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
+ if (!wq->cpu_wq) {
+ kfree(wq);
+ return NULL;
+ }
- cwq = per_cpu_ptr(wq->cpu_wq, hotcpu);
- kthread_bind(cwq->thread, hotcpu);
- wake_up_process(cwq->thread);
- }
- mutex_unlock(&workqueue_mutex);
- break;
+ wq->name = name;
+ wq->singlethread = singlethread;
+ wq->freezeable = freezeable;
+ INIT_LIST_HEAD(&wq->list);
- case CPU_UP_CANCELED:
- list_for_each_entry(wq, &workqueues, list) {
- if (!per_cpu_ptr(wq->cpu_wq, hotcpu)->thread)
+ if (singlethread) {
+ cwq = init_cpu_workqueue(wq, singlethread_cpu);
+ err = create_workqueue_thread(cwq, singlethread_cpu);
+ start_workqueue_thread(cwq, -1);
+ } else {
+ mutex_lock(&workqueue_mutex);
+ list_add(&wq->list, &workqueues);
+
+ for_each_possible_cpu(cpu) {
+ cwq = init_cpu_workqueue(wq, cpu);
+ if (err || !cpu_online(cpu))
continue;
- /* Unbind so it can run. */
- kthread_bind(per_cpu_ptr(wq->cpu_wq, hotcpu)->thread,
- any_online_cpu(cpu_online_map));
- cleanup_workqueue_thread(wq, hotcpu);
+ err = create_workqueue_thread(cwq, cpu);
+ start_workqueue_thread(cwq, cpu);
}
mutex_unlock(&workqueue_mutex);
- break;
+ }
+
+ if (err) {
+ destroy_workqueue(wq);
+ wq = NULL;
+ }
+ return wq;
+}
+EXPORT_SYMBOL_GPL(__create_workqueue);
+
+static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+{
+ struct wq_barrier barr;
+ int alive = 0;
+
+ spin_lock_irq(&cwq->lock);
+ if (cwq->thread != NULL) {
+ insert_wq_barrier(cwq, &barr, 1);
+ cwq->should_stop = 1;
+ alive = 1;
+ }
+ spin_unlock_irq(&cwq->lock);
+
+ if (alive) {
+ wait_for_completion(&barr.done);
- case CPU_DOWN_PREPARE:
+ while (unlikely(cwq->thread != NULL))
+ cpu_relax();
+ /*
+ * Wait until cwq->thread unlocks cwq->lock,
+ * it won't touch *cwq after that.
+ */
+ smp_rmb();
+ spin_unlock_wait(&cwq->lock);
+ }
+}
+
+/**
+ * destroy_workqueue - safely terminate a workqueue
+ * @wq: target workqueue
+ *
+ * Safely destroy a workqueue. All work currently pending will be done first.
+ */
+void destroy_workqueue(struct workqueue_struct *wq)
+{
+ const cpumask_t *cpu_map = wq_cpu_map(wq);
+ struct cpu_workqueue_struct *cwq;
+ int cpu;
+
+ mutex_lock(&workqueue_mutex);
+ list_del(&wq->list);
+ mutex_unlock(&workqueue_mutex);
+
+ for_each_cpu_mask(cpu, *cpu_map) {
+ cwq = per_cpu_ptr(wq->cpu_wq, cpu);
+ cleanup_workqueue_thread(cwq, cpu);
+ }
+
+ free_percpu(wq->cpu_wq);
+ kfree(wq);
+}
+EXPORT_SYMBOL_GPL(destroy_workqueue);
+
+static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct cpu_workqueue_struct *cwq;
+ struct workqueue_struct *wq;
+
+ action &= ~CPU_TASKS_FROZEN;
+
+ switch (action) {
+ case CPU_LOCK_ACQUIRE:
mutex_lock(&workqueue_mutex);
- break;
+ return NOTIFY_OK;
- case CPU_DOWN_FAILED:
+ case CPU_LOCK_RELEASE:
mutex_unlock(&workqueue_mutex);
- break;
+ return NOTIFY_OK;
- case CPU_DEAD:
- list_for_each_entry(wq, &workqueues, list)
- cleanup_workqueue_thread(wq, hotcpu);
- list_for_each_entry(wq, &workqueues, list)
- take_over_work(wq, hotcpu);
- mutex_unlock(&workqueue_mutex);
- break;
+ case CPU_UP_PREPARE:
+ cpu_set(cpu, cpu_populated_map);
+ }
+
+ list_for_each_entry(wq, &workqueues, list) {
+ cwq = per_cpu_ptr(wq->cpu_wq, cpu);
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ if (!create_workqueue_thread(cwq, cpu))
+ break;
+ printk(KERN_ERR "workqueue for %i failed\n", cpu);
+ return NOTIFY_BAD;
+
+ case CPU_ONLINE:
+ start_workqueue_thread(cwq, cpu);
+ break;
+
+ case CPU_UP_CANCELED:
+ start_workqueue_thread(cwq, -1);
+ case CPU_DEAD:
+ cleanup_workqueue_thread(cwq, cpu);
+ break;
+ }
}
return NOTIFY_OK;
}
-void init_workqueues(void)
+void __init init_workqueues(void)
{
+ cpu_populated_map = cpu_online_map;
singlethread_cpu = first_cpu(cpu_possible_map);
+ cpu_singlethread_map = cpumask_of_cpu(singlethread_cpu);
hotcpu_notifier(workqueue_cpu_callback, 0);
keventd_wq = create_workqueue("events");
BUG_ON(!keventd_wq);
}
-
diff --git a/lib/Kconfig b/lib/Kconfig
index 38424991504..96d6e8ca8b7 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -111,4 +111,9 @@ config HAS_IOPORT
depends on HAS_IOMEM && !NO_IOPORT
default y
+config HAS_DMA
+ boolean
+ depends on !NO_DMA
+ default y
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 79afd00bbe5..ee05b8a061b 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -86,23 +86,6 @@ config DEBUG_SHIRQ
Drivers ought to be able to handle interrupts coming in at those
points; some don't and need to be caught.
-config LOG_BUF_SHIFT
- int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
- range 12 21
- default 17 if S390 || LOCKDEP
- default 16 if X86_NUMAQ || IA64
- default 15 if SMP
- default 14
- help
- Select kernel log buffer size as a power of 2.
- Defaults and Examples:
- 17 => 128 KB for S/390
- 16 => 64 KB for x86 NUMAQ or IA-64
- 15 => 32 KB for SMP
- 14 => 16 KB for uniprocessor
- 13 => 8 KB
- 12 => 4 KB
-
config DETECT_SOFTLOCKUP
bool "Detect Soft Lockups"
depends on DEBUG_KERNEL && !S390
@@ -201,6 +184,16 @@ config DEBUG_MUTEXES
This feature allows mutex semantics violations to be detected and
reported.
+config DEBUG_SEMAPHORE
+ bool "Semaphore debugging"
+ depends on DEBUG_KERNEL
+ depends on ALPHA || FRV
+ default n
+ help
+ If you say Y here then semaphore processing will issue lots of
+ verbose debugging messages. If you suspect a semaphore problem or a
+ kernel hacker asks for this option then say Y. Otherwise say N.
+
config DEBUG_LOCK_ALLOC
bool "Lock debugging: detect incorrect freeing of live locks"
depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
@@ -320,7 +313,7 @@ config DEBUG_HIGHMEM
config DEBUG_BUGVERBOSE
bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
depends on BUG
- depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG
+ depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || FRV || SUPERH || GENERIC_BUG || BFIN
default !EMBEDDED
help
Say Y here to make BUG() panics output the file name and line number
@@ -333,6 +326,9 @@ config DEBUG_INFO
help
If you say Y here the resulting kernel image will include
debugging info resulting in a larger kernel image.
+ This adds debug symbols to the kernel and modules (gcc -g), and
+ is needed if you intend to use kernel crashdump or binary object
+ tools like crash, kgdb, LKCD, gdb, etc on the kernel.
Say Y here only if you plan to debug the kernel.
If unsure, say N.
@@ -357,7 +353,7 @@ config DEBUG_LIST
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
- depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH)
+ depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH || BFIN)
default y if DEBUG_INFO && UML
help
If you say Y here the resulting kernel image will be slightly larger
diff --git a/lib/cpumask.c b/lib/cpumask.c
index 1ea2c184315..bb4f76d3c3e 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -15,9 +15,6 @@ int __next_cpu(int n, const cpumask_t *srcp)
}
EXPORT_SYMBOL(__next_cpu);
-int nr_cpu_ids;
-EXPORT_SYMBOL(nr_cpu_ids);
-
int __any_online_cpu(const cpumask_t *mask)
{
int cpu;
diff --git a/lib/devres.c b/lib/devres.c
index eb38849aa71..b1d336ce7f3 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -296,5 +296,31 @@ int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
return rc;
}
EXPORT_SYMBOL(pcim_iomap_regions);
+
+/**
+ * pcim_iounmap_regions - Unmap and release PCI BARs
+ * @pdev: PCI device to map IO resources for
+ * @mask: Mask of BARs to unmap and release
+ *
+ * Unamp and release regions specified by @mask.
+ */
+void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
+{
+ void __iomem * const *iomap;
+ int i;
+
+ iomap = pcim_iomap_table(pdev);
+ if (!iomap)
+ return;
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (!(mask & (1 << i)))
+ continue;
+
+ pcim_iounmap(pdev, iomap[i]);
+ pci_release_region(pdev, i);
+ }
+}
+EXPORT_SYMBOL(pcim_iounmap_regions);
#endif
#endif
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index 0fabd12c39d..b18fc2ff9ff 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -72,9 +72,8 @@ static bool fail_stacktrace(struct fault_attr *attr)
trace.entries = entries;
trace.max_entries = depth;
trace.skip = 1;
- trace.all_contexts = 0;
- save_stack_trace(&trace, NULL);
+ save_stack_trace(&trace);
for (n = 0; n < trace.nr_entries; n++) {
if (attr->reject_start <= entries[n] &&
entries[n] < attr->reject_end)
diff --git a/lib/inflate.c b/lib/inflate.c
index 6db6e98d163..845f91d3ac1 100644
--- a/lib/inflate.c
+++ b/lib/inflate.c
@@ -292,7 +292,6 @@ STATIC int INIT huft_build(
oversubscribed set of lengths), and three if not enough memory. */
{
unsigned a; /* counter for codes of length k */
- unsigned c[BMAX+1]; /* bit length count table */
unsigned f; /* i repeats in table every f entries */
int g; /* maximum code length */
int h; /* table level */
@@ -303,18 +302,33 @@ STATIC int INIT huft_build(
register unsigned *p; /* pointer into c[], b[], or v[] */
register struct huft *q; /* points to current table */
struct huft r; /* table entry for structure assignment */
- struct huft *u[BMAX]; /* table stack */
- unsigned v[N_MAX]; /* values in order of bit length */
register int w; /* bits before this table == (l * h) */
- unsigned x[BMAX+1]; /* bit offsets, then code stack */
unsigned *xp; /* pointer into x */
int y; /* number of dummy codes added */
unsigned z; /* number of entries in current table */
+ struct {
+ unsigned c[BMAX+1]; /* bit length count table */
+ struct huft *u[BMAX]; /* table stack */
+ unsigned v[N_MAX]; /* values in order of bit length */
+ unsigned x[BMAX+1]; /* bit offsets, then code stack */
+ } *stk;
+ unsigned *c, *v, *x;
+ struct huft **u;
+ int ret;
DEBG("huft1 ");
+ stk = malloc(sizeof(*stk));
+ if (stk == NULL)
+ return 3; /* out of memory */
+
+ c = stk->c;
+ v = stk->v;
+ x = stk->x;
+ u = stk->u;
+
/* Generate counts for each bit length */
- memzero(c, sizeof(c));
+ memzero(stk->c, sizeof(stk->c));
p = b; i = n;
do {
Tracecv(*p, (stderr, (n-i >= ' ' && n-i <= '~' ? "%c %d\n" : "0x%x %d\n"),
@@ -326,7 +340,8 @@ DEBG("huft1 ");
{
*t = (struct huft *)NULL;
*m = 0;
- return 2;
+ ret = 2;
+ goto out;
}
DEBG("huft2 ");
@@ -351,10 +366,14 @@ DEBG("huft3 ");
/* Adjust last length count to fill out codes, if needed */
for (y = 1 << j; j < i; j++, y <<= 1)
- if ((y -= c[j]) < 0)
- return 2; /* bad input: more codes than bits */
- if ((y -= c[i]) < 0)
- return 2;
+ if ((y -= c[j]) < 0) {
+ ret = 2; /* bad input: more codes than bits */
+ goto out;
+ }
+ if ((y -= c[i]) < 0) {
+ ret = 2;
+ goto out;
+ }
c[i] += y;
DEBG("huft4 ");
@@ -428,7 +447,8 @@ DEBG1("3 ");
{
if (h)
huft_free(u[0]);
- return 3; /* not enough memory */
+ ret = 3; /* not enough memory */
+ goto out;
}
DEBG1("4 ");
hufts += z + 1; /* track memory usage */
@@ -492,7 +512,11 @@ DEBG("h6f ");
DEBG("huft7 ");
/* Return true (1) if we were given an incomplete table */
- return y != 0 && g != 1;
+ ret = y != 0 && g != 1;
+
+ out:
+ free(stk);
+ return ret;
}
@@ -705,10 +729,14 @@ STATIC int noinline INIT inflate_fixed(void)
struct huft *td; /* distance code table */
int bl; /* lookup bits for tl */
int bd; /* lookup bits for td */
- unsigned l[288]; /* length list for huft_build */
+ unsigned *l; /* length list for huft_build */
DEBG("<fix");
+ l = malloc(sizeof(*l) * 288);
+ if (l == NULL)
+ return 3; /* out of memory */
+
/* set up literal table */
for (i = 0; i < 144; i++)
l[i] = 8;
@@ -719,9 +747,10 @@ DEBG("<fix");
for (; i < 288; i++) /* make a complete, but wrong code set */
l[i] = 8;
bl = 7;
- if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+ if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0) {
+ free(l);
return i;
-
+ }
/* set up distance table */
for (i = 0; i < 30; i++) /* make an incomplete code set */
@@ -730,6 +759,7 @@ DEBG("<fix");
if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
{
huft_free(tl);
+ free(l);
DEBG(">");
return i;
@@ -737,11 +767,13 @@ DEBG("<fix");
/* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
+ if (inflate_codes(tl, td, bl, bd)) {
+ free(l);
return 1;
-
+ }
/* free the decoding tables, return */
+ free(l);
huft_free(tl);
huft_free(td);
return 0;
@@ -766,16 +798,19 @@ STATIC int noinline INIT inflate_dynamic(void)
unsigned nb; /* number of bit length codes */
unsigned nl; /* number of literal/length codes */
unsigned nd; /* number of distance codes */
-#ifdef PKZIP_BUG_WORKAROUND
- unsigned ll[288+32]; /* literal/length and distance code lengths */
-#else
- unsigned ll[286+30]; /* literal/length and distance code lengths */
-#endif
+ unsigned *ll; /* literal/length and distance code lengths */
register ulg b; /* bit buffer */
register unsigned k; /* number of bits in bit buffer */
+ int ret;
DEBG("<dyn");
+#ifdef PKZIP_BUG_WORKAROUND
+ ll = malloc(sizeof(*ll) * (288+32)); /* literal/length and distance code lengths */
+#else
+ ll = malloc(sizeof(*ll) * (286+30)); /* literal/length and distance code lengths */
+#endif
+
/* make local bit buffer */
b = bb;
k = bk;
@@ -796,7 +831,10 @@ DEBG("<dyn");
#else
if (nl > 286 || nd > 30)
#endif
- return 1; /* bad lengths */
+ {
+ ret = 1; /* bad lengths */
+ goto out;
+ }
DEBG("dyn1 ");
@@ -818,7 +856,8 @@ DEBG("dyn2 ");
{
if (i == 1)
huft_free(tl);
- return i; /* incomplete code set */
+ ret = i; /* incomplete code set */
+ goto out;
}
DEBG("dyn3 ");
@@ -840,8 +879,10 @@ DEBG("dyn3 ");
NEEDBITS(2)
j = 3 + ((unsigned)b & 3);
DUMPBITS(2)
- if ((unsigned)i + j > n)
- return 1;
+ if ((unsigned)i + j > n) {
+ ret = 1;
+ goto out;
+ }
while (j--)
ll[i++] = l;
}
@@ -850,8 +891,10 @@ DEBG("dyn3 ");
NEEDBITS(3)
j = 3 + ((unsigned)b & 7);
DUMPBITS(3)
- if ((unsigned)i + j > n)
- return 1;
+ if ((unsigned)i + j > n) {
+ ret = 1;
+ goto out;
+ }
while (j--)
ll[i++] = 0;
l = 0;
@@ -861,8 +904,10 @@ DEBG("dyn3 ");
NEEDBITS(7)
j = 11 + ((unsigned)b & 0x7f);
DUMPBITS(7)
- if ((unsigned)i + j > n)
- return 1;
+ if ((unsigned)i + j > n) {
+ ret = 1;
+ goto out;
+ }
while (j--)
ll[i++] = 0;
l = 0;
@@ -891,7 +936,8 @@ DEBG("dyn5b ");
error("incomplete literal tree");
huft_free(tl);
}
- return i; /* incomplete code set */
+ ret = i; /* incomplete code set */
+ goto out;
}
DEBG("dyn5c ");
bd = dbits;
@@ -907,15 +953,18 @@ DEBG("dyn5d ");
huft_free(td);
}
huft_free(tl);
- return i; /* incomplete code set */
+ ret = i; /* incomplete code set */
+ goto out;
#endif
}
DEBG("dyn6 ");
/* decompress until an end-of-block code */
- if (inflate_codes(tl, td, bl, bd))
- return 1;
+ if (inflate_codes(tl, td, bl, bd)) {
+ ret = 1;
+ goto out;
+ }
DEBG("dyn7 ");
@@ -924,10 +973,14 @@ DEBG("dyn7 ");
huft_free(td);
DEBG(">");
- return 0;
-
- underrun:
- return 4; /* Input underrun */
+ ret = 0;
+out:
+ free(ll);
+ return ret;
+
+underrun:
+ ret = 4; /* Input underrun */
+ goto out;
}
diff --git a/lib/iomap.c b/lib/iomap.c
index 4d43f37c015..a57d262a5ed 100644
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -35,20 +35,28 @@
#define PIO_RESERVED 0x40000UL
#endif
+static void bad_io_access(unsigned long port, const char *access)
+{
+ static int count = 10;
+ if (count) {
+ count--;
+ printk(KERN_ERR "Bad IO access at port %lx (%s)\n", port, access);
+ WARN_ON(1);
+ }
+}
+
/*
* Ugly macros are a way of life.
*/
-#define VERIFY_PIO(port) BUG_ON((port & ~PIO_MASK) != PIO_OFFSET)
-
#define IO_COND(addr, is_pio, is_mmio) do { \
unsigned long port = (unsigned long __force)addr; \
- if (port < PIO_RESERVED) { \
- VERIFY_PIO(port); \
+ if (port >= PIO_RESERVED) { \
+ is_mmio; \
+ } else if (port > PIO_OFFSET) { \
port &= PIO_MASK; \
is_pio; \
- } else { \
- is_mmio; \
- } \
+ } else \
+ bad_io_access(port, #is_pio ); \
} while (0)
#ifndef pio_read16be
@@ -64,22 +72,27 @@
unsigned int fastcall ioread8(void __iomem *addr)
{
IO_COND(addr, return inb(port), return readb(addr));
+ return 0xff;
}
unsigned int fastcall ioread16(void __iomem *addr)
{
IO_COND(addr, return inw(port), return readw(addr));
+ return 0xffff;
}
unsigned int fastcall ioread16be(void __iomem *addr)
{
IO_COND(addr, return pio_read16be(port), return mmio_read16be(addr));
+ return 0xffff;
}
unsigned int fastcall ioread32(void __iomem *addr)
{
IO_COND(addr, return inl(port), return readl(addr));
+ return 0xffffffff;
}
unsigned int fastcall ioread32be(void __iomem *addr)
{
IO_COND(addr, return pio_read32be(port), return mmio_read32be(addr));
+ return 0xffffffff;
}
EXPORT_SYMBOL(ioread8);
EXPORT_SYMBOL(ioread16);
diff --git a/lib/kobject.c b/lib/kobject.c
index cecf2fbede3..fc5f3f6e732 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -582,22 +582,10 @@ void kset_init(struct kset * k)
/**
* kset_add - add a kset object to the hierarchy.
* @k: kset.
- *
- * Simply, this adds the kset's embedded kobject to the
- * hierarchy.
- * We also try to make sure that the kset's embedded kobject
- * has a parent before it is added. We only care if the embedded
- * kobject is not part of a kset itself, since kobject_add()
- * assigns a parent in that case.
- * If that is the case, and the kset has a controlling subsystem,
- * then we set the kset's parent to be said subsystem.
*/
int kset_add(struct kset * k)
{
- if (!k->kobj.parent && !k->kobj.kset && k->subsys)
- k->kobj.parent = &k->subsys->kset.kobj;
-
return kobject_add(&k->kobj);
}
@@ -656,53 +644,28 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name)
return ret;
}
-
-void subsystem_init(struct subsystem * s)
+void subsystem_init(struct kset *s)
{
- kset_init(&s->kset);
+ kset_init(s);
}
-/**
- * subsystem_register - register a subsystem.
- * @s: the subsystem we're registering.
- *
- * Once we register the subsystem, we want to make sure that
- * the kset points back to this subsystem.
- */
-
-int subsystem_register(struct subsystem * s)
+int subsystem_register(struct kset *s)
{
- int error;
-
- if (!s)
- return -EINVAL;
-
- subsystem_init(s);
- pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
-
- if (!(error = kset_add(&s->kset))) {
- if (!s->kset.subsys)
- s->kset.subsys = s;
- }
- return error;
+ return kset_register(s);
}
-void subsystem_unregister(struct subsystem * s)
+void subsystem_unregister(struct kset *s)
{
- if (!s)
- return;
- pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
- kset_unregister(&s->kset);
+ kset_unregister(s);
}
-
/**
* subsystem_create_file - export sysfs attribute file.
* @s: subsystem.
* @a: subsystem attribute descriptor.
*/
-int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
+int subsys_create_file(struct kset *s, struct subsys_attribute *a)
{
int error = 0;
@@ -710,28 +673,12 @@ int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
return -EINVAL;
if (subsys_get(s)) {
- error = sysfs_create_file(&s->kset.kobj,&a->attr);
+ error = sysfs_create_file(&s->kobj, &a->attr);
subsys_put(s);
}
return error;
}
-
-/**
- * subsystem_remove_file - remove sysfs attribute file.
- * @s: subsystem.
- * @a: attribute desciptor.
- */
-#if 0
-void subsys_remove_file(struct subsystem * s, struct subsys_attribute * a)
-{
- if (subsys_get(s)) {
- sysfs_remove_file(&s->kset.kobj,&a->attr);
- subsys_put(s);
- }
-}
-#endif /* 0 */
-
EXPORT_SYMBOL(kobject_init);
EXPORT_SYMBOL(kobject_register);
EXPORT_SYMBOL(kobject_unregister);
diff --git a/lib/parser.c b/lib/parser.c
index 7ad2a48abc5..703c8c13b34 100644
--- a/lib/parser.c
+++ b/lib/parser.c
@@ -22,7 +22,7 @@
* match extremely simple token=arg style patterns. If the pattern is found,
* the location(s) of the arguments will be returned in the @args array.
*/
-static int match_one(char *s, char *p, substring_t args[])
+static int match_one(char *s, const char *p, substring_t args[])
{
char *meta;
int argc = 0;
@@ -43,7 +43,7 @@ static int match_one(char *s, char *p, substring_t args[])
p = meta + 1;
if (isdigit(*p))
- len = simple_strtoul(p, &p, 10);
+ len = simple_strtoul(p, (char **) &p, 10);
else if (*p == '%') {
if (*s++ != '%')
return 0;
@@ -102,7 +102,7 @@ static int match_one(char *s, char *p, substring_t args[])
*/
int match_token(char *s, match_table_t table, substring_t args[])
{
- struct match_token *p;
+ const struct match_token *p;
for (p = table; !match_one(s, p->pattern, args) ; p++)
;
@@ -190,7 +190,7 @@ int match_hex(substring_t *s, int *result)
* &substring_t @s to the c-style string @to. Caller guarantees that @to is
* large enough to hold the characters of @s.
*/
-void match_strcpy(char *to, substring_t *s)
+void match_strcpy(char *to, const substring_t *s)
{
memcpy(to, s->from, s->to - s->from);
to[s->to - s->from] = '\0';
@@ -204,7 +204,7 @@ void match_strcpy(char *to, substring_t *s)
* the &substring_t @s. The caller is responsible for freeing the returned
* string with kfree().
*/
-char *match_strdup(substring_t *s)
+char *match_strdup(const substring_t *s)
{
char *p = kmalloc(s->to - s->from + 1, GFP_KERNEL);
if (p)
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index d69ddbe4386..402eb4eb6b2 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1004,7 +1004,7 @@ static int radix_tree_callback(struct notifier_block *nfb,
struct radix_tree_preload *rtp;
/* Free per-cpu pool of perloaded nodes */
- if (action == CPU_DEAD) {
+ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
rtp = &per_cpu(radix_tree_preloads, cpu);
while (rtp->nr) {
kmem_cache_free(radix_tree_node_cachep,
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 9970e55c90b..10c13ad0d82 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -778,7 +778,6 @@ swiotlb_dma_supported(struct device *hwdev, u64 mask)
return virt_to_bus(io_tlb_end - 1) <= mask;
}
-EXPORT_SYMBOL(swiotlb_init);
EXPORT_SYMBOL(swiotlb_map_single);
EXPORT_SYMBOL(swiotlb_unmap_single);
EXPORT_SYMBOL(swiotlb_map_sg);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index b025864d2e4..01729024126 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -825,6 +825,17 @@ int vsscanf(const char * buf, const char * fmt, va_list args)
break;
str = next;
}
+
+ /*
+ * Now we've come all the way through so either the input string or the
+ * format ended. In the former case, there can be a %n at the current
+ * position in the format that needs to be filled.
+ */
+ if (*fmt == '%' && *(fmt + 1) == 'n') {
+ int *p = (int *)va_arg(args, int *);
+ *p = str - buf;
+ }
+
return num;
}
@@ -851,23 +862,35 @@ EXPORT_SYMBOL(sscanf);
/* Simplified asprintf. */
-char *kasprintf(gfp_t gfp, const char *fmt, ...)
+char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
{
- va_list ap;
unsigned int len;
char *p;
+ va_list aq;
- va_start(ap, fmt);
- len = vsnprintf(NULL, 0, fmt, ap);
- va_end(ap);
+ va_copy(aq, ap);
+ len = vsnprintf(NULL, 0, fmt, aq);
+ va_end(aq);
p = kmalloc(len+1, gfp);
if (!p)
return NULL;
- va_start(ap, fmt);
+
vsnprintf(p, len+1, fmt, ap);
- va_end(ap);
+
return p;
}
+EXPORT_SYMBOL(kvasprintf);
+char *kasprintf(gfp_t gfp, const char *fmt, ...)
+{
+ va_list ap;
+ char *p;
+
+ va_start(ap, fmt);
+ p = kvasprintf(gfp, fmt, ap);
+ va_end(ap);
+
+ return p;
+}
EXPORT_SYMBOL(kasprintf);
diff --git a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c
index fceb97c3aff..7e1e3114a73 100644
--- a/lib/zlib_inflate/inflate.c
+++ b/lib/zlib_inflate/inflate.c
@@ -743,12 +743,14 @@ int zlib_inflate(z_streamp strm, int flush)
strm->data_type = state->bits + (state->last ? 64 : 0) +
(state->mode == TYPE ? 128 : 0);
- if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
- ret = Z_BUF_ERROR;
if (flush == Z_PACKET_FLUSH && ret == Z_OK &&
- (strm->avail_out != 0 || strm->avail_in == 0))
+ strm->avail_out != 0 && strm->avail_in == 0)
return zlib_inflateSyncPacket(strm);
+
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+
return ret;
}
diff --git a/mm/Kconfig b/mm/Kconfig
index 7942b333e46..a17da8bafe6 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -163,3 +163,8 @@ config ZONE_DMA_FLAG
default "0" if !ZONE_DMA
default "1"
+config NR_QUICK
+ int
+ depends on QUICKLIST
+ default "2" if SUPERH
+ default "1"
diff --git a/mm/Makefile b/mm/Makefile
index f3c077eb0b8..a9148ea329a 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -25,7 +25,10 @@ obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_SLAB) += slab.o
+obj-$(CONFIG_SLUB) += slub.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
obj-$(CONFIG_SMP) += allocpercpu.o
+obj-$(CONFIG_QUICKLIST) += quicklist.o
+
diff --git a/mm/filemap.c b/mm/filemap.c
index 5dfc093ceb3..7b48b2ad00e 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -750,6 +750,7 @@ unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index,
read_unlock_irq(&mapping->tree_lock);
return i;
}
+EXPORT_SYMBOL(find_get_pages_contig);
/**
* find_get_pages_tag - find and return pages that match @tag
@@ -778,6 +779,7 @@ unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index,
read_unlock_irq(&mapping->tree_lock);
return ret;
}
+EXPORT_SYMBOL(find_get_pages_tag);
/**
* grab_cache_page_nowait - returns locked page at given index in given cache
@@ -868,6 +870,7 @@ void do_generic_mapping_read(struct address_space *mapping,
unsigned long last_index;
unsigned long next_index;
unsigned long prev_index;
+ unsigned int prev_offset;
loff_t isize;
struct page *cached_page;
int error;
@@ -876,7 +879,8 @@ void do_generic_mapping_read(struct address_space *mapping,
cached_page = NULL;
index = *ppos >> PAGE_CACHE_SHIFT;
next_index = index;
- prev_index = ra.prev_page;
+ prev_index = ra.prev_index;
+ prev_offset = ra.prev_offset;
last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
offset = *ppos & ~PAGE_CACHE_MASK;
@@ -924,10 +928,10 @@ page_ok:
flush_dcache_page(page);
/*
- * When (part of) the same page is read multiple times
- * in succession, only mark it as accessed the first time.
+ * When a sequential read accesses a page several times,
+ * only mark it as accessed the first time.
*/
- if (prev_index != index)
+ if (prev_index != index || offset != prev_offset)
mark_page_accessed(page);
prev_index = index;
@@ -945,6 +949,8 @@ page_ok:
offset += ret;
index += offset >> PAGE_CACHE_SHIFT;
offset &= ~PAGE_CACHE_MASK;
+ prev_offset = offset;
+ ra.prev_offset = offset;
page_cache_release(page);
if (ret == nr && desc->count)
@@ -1106,6 +1112,45 @@ success:
return size;
}
+/*
+ * Performs necessary checks before doing a write
+ * @iov: io vector request
+ * @nr_segs: number of segments in the iovec
+ * @count: number of bytes to write
+ * @access_flags: type of access: %VERIFY_READ or %VERIFY_WRITE
+ *
+ * Adjust number of segments and amount of bytes to write (nr_segs should be
+ * properly initialized first). Returns appropriate error code that caller
+ * should return or zero in case that write should be allowed.
+ */
+int generic_segment_checks(const struct iovec *iov,
+ unsigned long *nr_segs, size_t *count, int access_flags)
+{
+ unsigned long seg;
+ size_t cnt = 0;
+ for (seg = 0; seg < *nr_segs; seg++) {
+ const struct iovec *iv = &iov[seg];
+
+ /*
+ * If any segment has a negative length, or the cumulative
+ * length ever wraps negative then return -EINVAL.
+ */
+ cnt += iv->iov_len;
+ if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
+ return -EINVAL;
+ if (access_ok(access_flags, iv->iov_base, iv->iov_len))
+ continue;
+ if (seg == 0)
+ return -EFAULT;
+ *nr_segs = seg;
+ cnt -= iv->iov_len; /* This segment is no good */
+ break;
+ }
+ *count = cnt;
+ return 0;
+}
+EXPORT_SYMBOL(generic_segment_checks);
+
/**
* generic_file_aio_read - generic filesystem read routine
* @iocb: kernel I/O control block
@@ -1127,24 +1172,9 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
loff_t *ppos = &iocb->ki_pos;
count = 0;
- for (seg = 0; seg < nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
-
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- count += iv->iov_len;
- if (unlikely((ssize_t)(count|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- nr_segs = seg;
- count -= iv->iov_len; /* This segment is no good */
- break;
- }
+ retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE);
+ if (retval)
+ return retval;
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
if (filp->f_flags & O_DIRECT) {
@@ -1446,30 +1476,6 @@ page_not_uptodate:
majmin = VM_FAULT_MAJOR;
count_vm_event(PGMAJFAULT);
}
- lock_page(page);
-
- /* Did it get unhashed while we waited for it? */
- if (!page->mapping) {
- unlock_page(page);
- page_cache_release(page);
- goto retry_all;
- }
-
- /* Did somebody else get it up-to-date? */
- if (PageUptodate(page)) {
- unlock_page(page);
- goto success;
- }
-
- error = mapping->a_ops->readpage(file, page);
- if (!error) {
- wait_on_page_locked(page);
- if (PageUptodate(page))
- goto success;
- } else if (error == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- goto retry_find;
- }
/*
* Umm, take care of errors if the page isn't up-to-date.
@@ -1726,7 +1732,7 @@ int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma)
EXPORT_SYMBOL(generic_file_mmap);
EXPORT_SYMBOL(generic_file_readonly_mmap);
-static inline struct page *__read_cache_page(struct address_space *mapping,
+static struct page *__read_cache_page(struct address_space *mapping,
unsigned long index,
int (*filler)(void *,struct page*),
void *data)
@@ -1763,17 +1769,11 @@ repeat:
return page;
}
-/**
- * read_cache_page - read into page cache, fill it if needed
- * @mapping: the page's address_space
- * @index: the page index
- * @filler: function to perform the read
- * @data: destination for read data
- *
- * Read into the page cache. If a page already exists,
- * and PageUptodate() is not set, try to fill the page.
+/*
+ * Same as read_cache_page, but don't wait for page to become unlocked
+ * after submitting it to the filler.
*/
-struct page *read_cache_page(struct address_space *mapping,
+struct page *read_cache_page_async(struct address_space *mapping,
unsigned long index,
int (*filler)(void *,struct page*),
void *data)
@@ -1784,7 +1784,7 @@ struct page *read_cache_page(struct address_space *mapping,
retry:
page = __read_cache_page(mapping, index, filler, data);
if (IS_ERR(page))
- goto out;
+ return page;
mark_page_accessed(page);
if (PageUptodate(page))
goto out;
@@ -1802,7 +1802,40 @@ retry:
err = filler(data, page);
if (err < 0) {
page_cache_release(page);
- page = ERR_PTR(err);
+ return ERR_PTR(err);
+ }
+out:
+ mark_page_accessed(page);
+ return page;
+}
+EXPORT_SYMBOL(read_cache_page_async);
+
+/**
+ * read_cache_page - read into page cache, fill it if needed
+ * @mapping: the page's address_space
+ * @index: the page index
+ * @filler: function to perform the read
+ * @data: destination for read data
+ *
+ * Read into the page cache. If a page already exists, and PageUptodate() is
+ * not set, try to fill the page then wait for it to become unlocked.
+ *
+ * If the page does not get brought uptodate, return -EIO.
+ */
+struct page *read_cache_page(struct address_space *mapping,
+ unsigned long index,
+ int (*filler)(void *,struct page*),
+ void *data)
+{
+ struct page *page;
+
+ page = read_cache_page_async(mapping, index, filler, data);
+ if (IS_ERR(page))
+ goto out;
+ wait_on_page_locked(page);
+ if (!PageUptodate(page)) {
+ page_cache_release(page);
+ page = ERR_PTR(-EIO);
}
out:
return page;
@@ -2211,30 +2244,14 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
size_t ocount; /* original count */
size_t count; /* after file limit checks */
struct inode *inode = mapping->host;
- unsigned long seg;
loff_t pos;
ssize_t written;
ssize_t err;
ocount = 0;
- for (seg = 0; seg < nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
-
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- ocount += iv->iov_len;
- if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- nr_segs = seg;
- ocount -= iv->iov_len; /* This segment is no good */
- break;
- }
+ err = generic_segment_checks(iov, &nr_segs, &ocount, VERIFY_READ);
+ if (err)
+ return err;
count = ocount;
pos = *ppos;
@@ -2294,10 +2311,10 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
* semantics.
*/
endbyte = pos + written_buffered - written - 1;
- err = do_sync_file_range(file, pos, endbyte,
- SYNC_FILE_RANGE_WAIT_BEFORE|
- SYNC_FILE_RANGE_WRITE|
- SYNC_FILE_RANGE_WAIT_AFTER);
+ err = do_sync_mapping_range(file->f_mapping, pos, endbyte,
+ SYNC_FILE_RANGE_WAIT_BEFORE|
+ SYNC_FILE_RANGE_WRITE|
+ SYNC_FILE_RANGE_WAIT_AFTER);
if (err == 0) {
written = written_buffered;
invalidate_mapping_pages(mapping,
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index cbb335813ec..1b49dab9b25 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -434,7 +434,6 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
unsigned blocksize;
unsigned length;
struct page *page;
- void *kaddr;
BUG_ON(!mapping->a_ops->get_xip_page);
@@ -458,11 +457,7 @@ xip_truncate_page(struct address_space *mapping, loff_t from)
else
return PTR_ERR(page);
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- kunmap_atomic(kaddr, KM_USER0);
-
- flush_dcache_page(page);
+ zero_user_page(page, offset, length, KM_USER0);
return 0;
}
EXPORT_SYMBOL_GPL(xip_truncate_page);
diff --git a/mm/highmem.c b/mm/highmem.c
index 51e1c1995fe..be8f8d36a8b 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -99,6 +99,15 @@ static void flush_all_zero_pkmaps(void)
flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
}
+/* Flush all unused kmap mappings in order to remove stray
+ mappings. */
+void kmap_flush_unused(void)
+{
+ spin_lock(&kmap_lock);
+ flush_all_zero_pkmaps();
+ spin_unlock(&kmap_lock);
+}
+
static inline unsigned long map_new_virtual(struct page *page)
{
unsigned long vaddr;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 36db012b38d..eb7180db303 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -140,6 +140,8 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
return page;
fail:
+ if (vma->vm_flags & VM_MAYSHARE)
+ resv_huge_pages++;
spin_unlock(&hugetlb_lock);
return NULL;
}
@@ -172,6 +174,17 @@ static int __init hugetlb_setup(char *s)
}
__setup("hugepages=", hugetlb_setup);
+static unsigned int cpuset_mems_nr(unsigned int *array)
+{
+ int node;
+ unsigned int nr = 0;
+
+ for_each_node_mask(node, cpuset_current_mems_allowed)
+ nr += array[node];
+
+ return nr;
+}
+
#ifdef CONFIG_SYSCTL
static void update_and_free_page(struct page *page)
{
@@ -817,6 +830,26 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to)
chg = region_chg(&inode->i_mapping->private_list, from, to);
if (chg < 0)
return chg;
+ /*
+ * When cpuset is configured, it breaks the strict hugetlb page
+ * reservation as the accounting is done on a global variable. Such
+ * reservation is completely rubbish in the presence of cpuset because
+ * the reservation is not checked against page availability for the
+ * current cpuset. Application can still potentially OOM'ed by kernel
+ * with lack of free htlb page in cpuset that the task is in.
+ * Attempt to enforce strict accounting with cpuset is almost
+ * impossible (or too ugly) because cpuset is too fluid that
+ * task or memory node can be dynamically moved between cpusets.
+ *
+ * The change of semantics for shared hugetlb mapping with cpuset is
+ * undesirable. However, in order to preserve some of the semantics,
+ * we fall back to check against current free page availability as
+ * a best attempt and hopefully to minimize the impact of changing
+ * semantics that cpuset has.
+ */
+ if (chg > cpuset_mems_nr(free_huge_pages_node))
+ return -ENOMEM;
+
ret = hugetlb_acct_memory(chg);
if (ret < 0)
return ret;
diff --git a/mm/internal.h b/mm/internal.h
index d527b80b292..a3110c02aea 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -24,7 +24,7 @@ static inline void set_page_count(struct page *page, int v)
*/
static inline void set_page_refcounted(struct page *page)
{
- VM_BUG_ON(PageCompound(page) && page_private(page) != (unsigned long)page);
+ VM_BUG_ON(PageCompound(page) && PageTail(page));
VM_BUG_ON(atomic_read(&page->_count));
set_page_count(page, 1);
}
diff --git a/mm/madvise.c b/mm/madvise.c
index 603c5257ed6..e75096b5a6d 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -12,6 +12,24 @@
#include <linux/hugetlb.h>
/*
+ * Any behaviour which results in changes to the vma->vm_flags needs to
+ * take mmap_sem for writing. Others, which simply traverse vmas, need
+ * to only take it for reading.
+ */
+static int madvise_need_mmap_write(int behavior)
+{
+ switch (behavior) {
+ case MADV_REMOVE:
+ case MADV_WILLNEED:
+ case MADV_DONTNEED:
+ return 0;
+ default:
+ /* be safe, default to 1. list exceptions explicitly */
+ return 1;
+ }
+}
+
+/*
* We can potentially split a vm area into separate
* areas, each area with its own behavior.
*/
@@ -183,9 +201,9 @@ static long madvise_remove(struct vm_area_struct *vma,
+ ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
/* vmtruncate_range needs to take i_mutex and i_alloc_sem */
- up_write(&current->mm->mmap_sem);
+ up_read(&current->mm->mmap_sem);
error = vmtruncate_range(mapping->host, offset, endoff);
- down_write(&current->mm->mmap_sem);
+ down_read(&current->mm->mmap_sem);
return error;
}
@@ -270,7 +288,10 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
int error = -EINVAL;
size_t len;
- down_write(&current->mm->mmap_sem);
+ if (madvise_need_mmap_write(behavior))
+ down_write(&current->mm->mmap_sem);
+ else
+ down_read(&current->mm->mmap_sem);
if (start & ~PAGE_MASK)
goto out;
@@ -332,6 +353,10 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
vma = find_vma(current->mm, start);
}
out:
- up_write(&current->mm->mmap_sem);
+ if (madvise_need_mmap_write(behavior))
+ up_write(&current->mm->mmap_sem);
+ else
+ up_read(&current->mm->mmap_sem);
+
return error;
}
diff --git a/mm/memory.c b/mm/memory.c
index e7066e71dfa..1d647ab0ee7 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1448,6 +1448,100 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
}
EXPORT_SYMBOL(remap_pfn_range);
+static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ pte_fn_t fn, void *data)
+{
+ pte_t *pte;
+ int err;
+ struct page *pmd_page;
+ spinlock_t *uninitialized_var(ptl);
+
+ pte = (mm == &init_mm) ?
+ pte_alloc_kernel(pmd, addr) :
+ pte_alloc_map_lock(mm, pmd, addr, &ptl);
+ if (!pte)
+ return -ENOMEM;
+
+ BUG_ON(pmd_huge(*pmd));
+
+ pmd_page = pmd_page(*pmd);
+
+ do {
+ err = fn(pte, pmd_page, addr, data);
+ if (err)
+ break;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+
+ if (mm != &init_mm)
+ pte_unmap_unlock(pte-1, ptl);
+ return err;
+}
+
+static int apply_to_pmd_range(struct mm_struct *mm, pud_t *pud,
+ unsigned long addr, unsigned long end,
+ pte_fn_t fn, void *data)
+{
+ pmd_t *pmd;
+ unsigned long next;
+ int err;
+
+ pmd = pmd_alloc(mm, pud, addr);
+ if (!pmd)
+ return -ENOMEM;
+ do {
+ next = pmd_addr_end(addr, end);
+ err = apply_to_pte_range(mm, pmd, addr, next, fn, data);
+ if (err)
+ break;
+ } while (pmd++, addr = next, addr != end);
+ return err;
+}
+
+static int apply_to_pud_range(struct mm_struct *mm, pgd_t *pgd,
+ unsigned long addr, unsigned long end,
+ pte_fn_t fn, void *data)
+{
+ pud_t *pud;
+ unsigned long next;
+ int err;
+
+ pud = pud_alloc(mm, pgd, addr);
+ if (!pud)
+ return -ENOMEM;
+ do {
+ next = pud_addr_end(addr, end);
+ err = apply_to_pmd_range(mm, pud, addr, next, fn, data);
+ if (err)
+ break;
+ } while (pud++, addr = next, addr != end);
+ return err;
+}
+
+/*
+ * Scan a region of virtual memory, filling in page tables as necessary
+ * and calling a provided function on each leaf page table.
+ */
+int apply_to_page_range(struct mm_struct *mm, unsigned long addr,
+ unsigned long size, pte_fn_t fn, void *data)
+{
+ pgd_t *pgd;
+ unsigned long next;
+ unsigned long end = addr + size;
+ int err;
+
+ BUG_ON(addr >= end);
+ pgd = pgd_offset(mm, addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ err = apply_to_pud_range(mm, pgd, addr, next, fn, data);
+ if (err)
+ break;
+ } while (pgd++, addr = next, addr != end);
+ return err;
+}
+EXPORT_SYMBOL_GPL(apply_to_page_range);
+
/*
* handle_pte_fault chooses page fault handler according to an entry
* which was read non-atomically. Before making any commitment, on
@@ -2539,12 +2633,6 @@ int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
spin_unlock(&mm->page_table_lock);
return 0;
}
-#else
-/* Workaround for gcc 2.96 */
-int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address)
-{
- return 0;
-}
#endif /* __PAGETABLE_PUD_FOLDED */
#ifndef __PAGETABLE_PMD_FOLDED
@@ -2573,12 +2661,6 @@ int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
spin_unlock(&mm->page_table_lock);
return 0;
}
-#else
-/* Workaround for gcc 2.96 */
-int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
-{
- return 0;
-}
#endif /* __PAGETABLE_PMD_FOLDED */
int make_pages_present(unsigned long addr, unsigned long end)
diff --git a/mm/mmap.c b/mm/mmap.c
index 84f997da78d..68b9ad2ef1d 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -29,6 +29,7 @@
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/tlb.h>
+#include <asm/mmu_context.h>
#ifndef arch_mmap_check
#define arch_mmap_check(addr, len, flags) (0)
@@ -1199,6 +1200,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
if (len > TASK_SIZE)
return -ENOMEM;
+ if (flags & MAP_FIXED)
+ return addr;
+
if (addr) {
addr = PAGE_ALIGN(addr);
vma = find_vma(mm, addr);
@@ -1272,6 +1276,9 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
if (len > TASK_SIZE)
return -ENOMEM;
+ if (flags & MAP_FIXED)
+ return addr;
+
/* requesting a specific address */
if (addr) {
addr = PAGE_ALIGN(addr);
@@ -1359,39 +1366,21 @@ unsigned long
get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
- unsigned long ret;
-
- if (!(flags & MAP_FIXED)) {
- unsigned long (*get_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
-
- get_area = current->mm->get_unmapped_area;
- if (file && file->f_op && file->f_op->get_unmapped_area)
- get_area = file->f_op->get_unmapped_area;
- addr = get_area(file, addr, len, pgoff, flags);
- if (IS_ERR_VALUE(addr))
- return addr;
- }
+ unsigned long (*get_area)(struct file *, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+
+ get_area = current->mm->get_unmapped_area;
+ if (file && file->f_op && file->f_op->get_unmapped_area)
+ get_area = file->f_op->get_unmapped_area;
+ addr = get_area(file, addr, len, pgoff, flags);
+ if (IS_ERR_VALUE(addr))
+ return addr;
if (addr > TASK_SIZE - len)
return -ENOMEM;
if (addr & ~PAGE_MASK)
return -EINVAL;
- if (file && is_file_hugepages(file)) {
- /*
- * Check if the given range is hugepage aligned, and
- * can be made suitable for hugepages.
- */
- ret = prepare_hugepage_range(addr, len, pgoff);
- } else {
- /*
- * Ensure that a normal request is not falling in a
- * reserved hugepage range. For some archs like IA-64,
- * there is a separate region for hugepages.
- */
- ret = is_hugepage_only_range(current->mm, addr, len);
- }
- if (ret)
- return -EINVAL;
+
return addr;
}
@@ -1731,7 +1720,7 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
/*
* Split a vma into two pieces at address 'addr', a new vma is allocated
- * either for the first part or the the tail.
+ * either for the first part or the tail.
*/
int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
unsigned long addr, int new_below)
@@ -1979,6 +1968,9 @@ void exit_mmap(struct mm_struct *mm)
unsigned long nr_accounted = 0;
unsigned long end;
+ /* mm's last user has gone, and its about to be pulled down */
+ arch_exit_mmap(mm);
+
lru_add_drain();
flush_cache_mm(mm);
tlb = tlb_gather_mmu(mm, 1);
diff --git a/mm/nommu.c b/mm/nommu.c
index 1f60194d9b9..2b16b00a5b1 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -262,6 +262,14 @@ void vunmap(void *addr)
}
/*
+ * Implement a stub for vmalloc_sync_all() if the architecture chose not to
+ * have one.
+ */
+void __attribute__((weak)) vmalloc_sync_all(void)
+{
+}
+
+/*
* sys_brk() for the most part doesn't need the global kernel
* lock, except when an application is doing something nasty
* like trying to un-brk an area that has already been mapped
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 3791edfffee..a7001410ab1 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -147,9 +147,11 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
* Adjust the score by oomkilladj.
*/
if (p->oomkilladj) {
- if (p->oomkilladj > 0)
+ if (p->oomkilladj > 0) {
+ if (!points)
+ points = 1;
points <<= p->oomkilladj;
- else
+ } else
points >>= -(p->oomkilladj);
}
@@ -397,6 +399,7 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
struct task_struct *p;
unsigned long points = 0;
unsigned long freed = 0;
+ int constraint;
blocking_notifier_call_chain(&oom_notify_list, 0, &freed);
if (freed > 0)
@@ -411,14 +414,18 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order)
show_mem();
}
- cpuset_lock();
- read_lock(&tasklist_lock);
+ if (sysctl_panic_on_oom == 2)
+ panic("out of memory. Compulsory panic_on_oom is selected.\n");
/*
* Check if there were limitations on the allocation (only relevant for
* NUMA) that may require different handling.
*/
- switch (constrained_alloc(zonelist, gfp_mask)) {
+ constraint = constrained_alloc(zonelist, gfp_mask);
+ cpuset_lock();
+ read_lock(&tasklist_lock);
+
+ switch (constraint) {
case CONSTRAINT_MEMORY_POLICY:
oom_kill_process(current, points,
"No available memory (MPOL_BIND)");
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index a794945fd19..63cd88840eb 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -119,6 +119,44 @@ static void background_writeout(unsigned long _min_pages);
* We make sure that the background writeout level is below the adjusted
* clamping level.
*/
+
+static unsigned long highmem_dirtyable_memory(unsigned long total)
+{
+#ifdef CONFIG_HIGHMEM
+ int node;
+ unsigned long x = 0;
+
+ for_each_online_node(node) {
+ struct zone *z =
+ &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
+
+ x += zone_page_state(z, NR_FREE_PAGES)
+ + zone_page_state(z, NR_INACTIVE)
+ + zone_page_state(z, NR_ACTIVE);
+ }
+ /*
+ * Make sure that the number of highmem pages is never larger
+ * than the number of the total dirtyable memory. This can only
+ * occur in very strange VM situations but we want to make sure
+ * that this does not occur.
+ */
+ return min(x, total);
+#else
+ return 0;
+#endif
+}
+
+static unsigned long determine_dirtyable_memory(void)
+{
+ unsigned long x;
+
+ x = global_page_state(NR_FREE_PAGES)
+ + global_page_state(NR_INACTIVE)
+ + global_page_state(NR_ACTIVE);
+ x -= highmem_dirtyable_memory(x);
+ return x + 1; /* Ensure that we never return 0 */
+}
+
static void
get_dirty_limits(long *pbackground, long *pdirty,
struct address_space *mapping)
@@ -128,20 +166,12 @@ get_dirty_limits(long *pbackground, long *pdirty,
int unmapped_ratio;
long background;
long dirty;
- unsigned long available_memory = vm_total_pages;
+ unsigned long available_memory = determine_dirtyable_memory();
struct task_struct *tsk;
-#ifdef CONFIG_HIGHMEM
- /*
- * We always exclude high memory from our count.
- */
- available_memory -= totalhigh_pages;
-#endif
-
-
unmapped_ratio = 100 - ((global_page_state(NR_FILE_MAPPED) +
global_page_state(NR_ANON_PAGES)) * 100) /
- vm_total_pages;
+ available_memory;
dirty_ratio = vm_dirty_ratio;
if (dirty_ratio > unmapped_ratio / 2)
@@ -653,12 +683,7 @@ retry:
}
ret = (*writepage)(page, wbc);
- if (ret) {
- if (ret == -ENOSPC)
- set_bit(AS_ENOSPC, &mapping->flags);
- else
- set_bit(AS_EIO, &mapping->flags);
- }
+ mapping_set_error(mapping, ret);
if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
unlock_page(page);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 353ce9039a8..f9b5d6d5f4d 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -103,7 +103,7 @@ int min_free_kbytes = 1024;
unsigned long __meminitdata nr_kernel_pages;
unsigned long __meminitdata nr_all_pages;
-static unsigned long __initdata dma_reserve;
+static unsigned long __meminitdata dma_reserve;
#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
/*
@@ -126,10 +126,10 @@ static unsigned long __initdata dma_reserve;
#endif
#endif
- struct node_active_region __initdata early_node_map[MAX_ACTIVE_REGIONS];
- int __initdata nr_nodemap_entries;
- unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
- unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
+ struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS];
+ int __meminitdata nr_nodemap_entries;
+ unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
+ unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
unsigned long __initdata node_boundary_start_pfn[MAX_NUMNODES];
unsigned long __initdata node_boundary_end_pfn[MAX_NUMNODES];
@@ -156,10 +156,8 @@ static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
static int page_is_consistent(struct zone *zone, struct page *page)
{
-#ifdef CONFIG_HOLES_IN_ZONE
- if (!pfn_valid(page_to_pfn(page)))
+ if (!pfn_valid_within(page_to_pfn(page)))
return 0;
-#endif
if (zone != page_zone(page))
return 0;
@@ -227,7 +225,7 @@ static void bad_page(struct page *page)
static void free_compound_page(struct page *page)
{
- __free_pages_ok(page, (unsigned long)page[1].lru.prev);
+ __free_pages_ok(page, compound_order(page));
}
static void prep_compound_page(struct page *page, unsigned long order)
@@ -236,12 +234,13 @@ static void prep_compound_page(struct page *page, unsigned long order)
int nr_pages = 1 << order;
set_compound_page_dtor(page, free_compound_page);
- page[1].lru.prev = (void *)order;
- for (i = 0; i < nr_pages; i++) {
+ set_compound_order(page, order);
+ __SetPageHead(page);
+ for (i = 1; i < nr_pages; i++) {
struct page *p = page + i;
- __SetPageCompound(p);
- set_page_private(p, (unsigned long)page);
+ __SetPageTail(p);
+ p->first_page = page;
}
}
@@ -250,16 +249,19 @@ static void destroy_compound_page(struct page *page, unsigned long order)
int i;
int nr_pages = 1 << order;
- if (unlikely((unsigned long)page[1].lru.prev != order))
+ if (unlikely(compound_order(page) != order))
bad_page(page);
- for (i = 0; i < nr_pages; i++) {
+ if (unlikely(!PageHead(page)))
+ bad_page(page);
+ __ClearPageHead(page);
+ for (i = 1; i < nr_pages; i++) {
struct page *p = page + i;
- if (unlikely(!PageCompound(p) |
- (page_private(p) != (unsigned long)page)))
+ if (unlikely(!PageTail(p) |
+ (p->first_page != page)))
bad_page(page);
- __ClearPageCompound(p);
+ __ClearPageTail(p);
}
}
@@ -346,10 +348,8 @@ __find_combined_index(unsigned long page_idx, unsigned int order)
static inline int page_is_buddy(struct page *page, struct page *buddy,
int order)
{
-#ifdef CONFIG_HOLES_IN_ZONE
- if (!pfn_valid(page_to_pfn(buddy)))
+ if (!pfn_valid_within(page_to_pfn(buddy)))
return 0;
-#endif
if (page_zone_id(page) != page_zone_id(buddy))
return 0;
@@ -433,13 +433,18 @@ static inline int free_pages_check(struct page *page)
1 << PG_private |
1 << PG_locked |
1 << PG_active |
- 1 << PG_reclaim |
1 << PG_slab |
1 << PG_swapcache |
1 << PG_writeback |
1 << PG_reserved |
1 << PG_buddy ))))
bad_page(page);
+ /*
+ * PageReclaim == PageTail. It is only an error
+ * for PageReclaim to be set if PageCompound is clear.
+ */
+ if (unlikely(!PageCompound(page) && PageReclaim(page)))
+ bad_page(page);
if (PageDirty(page))
__ClearPageDirty(page);
/*
@@ -665,7 +670,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
}
#if MAX_NUMNODES > 1
-int nr_node_ids __read_mostly;
+int nr_node_ids __read_mostly = MAX_NUMNODES;
EXPORT_SYMBOL(nr_node_ids);
/*
@@ -686,43 +691,26 @@ static void __init setup_nr_node_ids(void) {}
#ifdef CONFIG_NUMA
/*
- * Called from the slab reaper to drain pagesets on a particular node that
- * belongs to the currently executing processor.
+ * Called from the vmstat counter updater to drain pagesets of this
+ * currently executing processor on remote nodes after they have
+ * expired.
+ *
* Note that this function must be called with the thread pinned to
* a single processor.
*/
-void drain_node_pages(int nodeid)
+void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
{
- int i;
- enum zone_type z;
unsigned long flags;
+ int to_drain;
- for (z = 0; z < MAX_NR_ZONES; z++) {
- struct zone *zone = NODE_DATA(nodeid)->node_zones + z;
- struct per_cpu_pageset *pset;
-
- if (!populated_zone(zone))
- continue;
-
- pset = zone_pcp(zone, smp_processor_id());
- for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
- struct per_cpu_pages *pcp;
-
- pcp = &pset->pcp[i];
- if (pcp->count) {
- int to_drain;
-
- local_irq_save(flags);
- if (pcp->count >= pcp->batch)
- to_drain = pcp->batch;
- else
- to_drain = pcp->count;
- free_pages_bulk(zone, to_drain, &pcp->list, 0);
- pcp->count -= to_drain;
- local_irq_restore(flags);
- }
- }
- }
+ local_irq_save(flags);
+ if (pcp->count >= pcp->batch)
+ to_drain = pcp->batch;
+ else
+ to_drain = pcp->count;
+ free_pages_bulk(zone, to_drain, &pcp->list, 0);
+ pcp->count -= to_drain;
+ local_irq_restore(flags);
}
#endif
@@ -770,8 +758,8 @@ void mark_free_pages(struct zone *zone)
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
- if (!PageNosave(page))
- ClearPageNosaveFree(page);
+ if (!swsusp_page_is_forbidden(page))
+ swsusp_unset_page_free(page);
}
for (order = MAX_ORDER - 1; order >= 0; --order)
@@ -780,7 +768,7 @@ void mark_free_pages(struct zone *zone)
pfn = page_to_pfn(list_entry(curr, struct page, lru));
for (i = 0; i < (1UL << order); i++)
- SetPageNosaveFree(pfn_to_page(pfn + i));
+ swsusp_set_page_free(pfn_to_page(pfn + i));
}
spin_unlock_irqrestore(&zone->lock, flags);
@@ -2143,11 +2131,14 @@ static int __cpuinit pageset_cpuup_callback(struct notifier_block *nfb,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
if (process_zones(cpu))
ret = NOTIFY_BAD;
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
free_zone_pagesets(cpu);
break;
default:
@@ -2174,7 +2165,7 @@ void __init setup_per_cpu_pageset(void)
#endif
-static __meminit
+static __meminit noinline
int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
{
int i;
@@ -2262,7 +2253,7 @@ __meminit int init_currently_empty_zone(struct zone *zone,
* Basic iterator support. Return the first range of PFNs for a node
* Note: nid == MAX_NUMNODES returns first region regardless of node
*/
-static int __init first_active_region_index_in_nid(int nid)
+static int __meminit first_active_region_index_in_nid(int nid)
{
int i;
@@ -2277,7 +2268,7 @@ static int __init first_active_region_index_in_nid(int nid)
* Basic iterator support. Return the next active range of PFNs for a node
* Note: nid == MAX_NUMNODES returns next region regardles of node
*/
-static int __init next_active_region_index_in_nid(int index, int nid)
+static int __meminit next_active_region_index_in_nid(int index, int nid)
{
for (index = index + 1; index < nr_nodemap_entries; index++)
if (nid == MAX_NUMNODES || early_node_map[index].nid == nid)
@@ -2430,7 +2421,7 @@ static void __init account_node_boundary(unsigned int nid,
* with no available memory, a warning is printed and the start and end
* PFNs will be 0.
*/
-void __init get_pfn_range_for_nid(unsigned int nid,
+void __meminit get_pfn_range_for_nid(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn)
{
int i;
@@ -2455,7 +2446,7 @@ void __init get_pfn_range_for_nid(unsigned int nid,
* Return the number of pages a zone spans in a node, including holes
* present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node()
*/
-unsigned long __init zone_spanned_pages_in_node(int nid,
+unsigned long __meminit zone_spanned_pages_in_node(int nid,
unsigned long zone_type,
unsigned long *ignored)
{
@@ -2483,7 +2474,7 @@ unsigned long __init zone_spanned_pages_in_node(int nid,
* Return the number of holes in a range on a node. If nid is MAX_NUMNODES,
* then all holes in the requested range will be accounted for.
*/
-unsigned long __init __absent_pages_in_range(int nid,
+unsigned long __meminit __absent_pages_in_range(int nid,
unsigned long range_start_pfn,
unsigned long range_end_pfn)
{
@@ -2543,7 +2534,7 @@ unsigned long __init absent_pages_in_range(unsigned long start_pfn,
}
/* Return the number of page frames in holes in a zone on a node */
-unsigned long __init zone_absent_pages_in_node(int nid,
+unsigned long __meminit zone_absent_pages_in_node(int nid,
unsigned long zone_type,
unsigned long *ignored)
{
@@ -2579,7 +2570,7 @@ static inline unsigned long zone_absent_pages_in_node(int nid,
#endif
-static void __init calculate_node_totalpages(struct pglist_data *pgdat,
+static void __meminit calculate_node_totalpages(struct pglist_data *pgdat,
unsigned long *zones_size, unsigned long *zholes_size)
{
unsigned long realtotalpages, totalpages = 0;
@@ -2687,7 +2678,7 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat,
}
}
-static void __init alloc_node_mem_map(struct pglist_data *pgdat)
+static void __meminit alloc_node_mem_map(struct pglist_data *pgdat)
{
/* Skip empty nodes */
if (!pgdat->node_spanned_pages)
@@ -3007,7 +2998,7 @@ static int page_alloc_cpu_notify(struct notifier_block *self,
{
int cpu = (unsigned long)hcpu;
- if (action == CPU_DEAD) {
+ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
local_irq_disable();
__drain_pages(cpu);
vm_events_fold_cpu(cpu);
@@ -3203,7 +3194,8 @@ int min_free_kbytes_sysctl_handler(ctl_table *table, int write,
struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
{
proc_dointvec(table, write, file, buffer, length, ppos);
- setup_per_zone_pages_min();
+ if (write)
+ setup_per_zone_pages_min();
return 0;
}
diff --git a/mm/quicklist.c b/mm/quicklist.c
new file mode 100644
index 00000000000..ae8189c2799
--- /dev/null
+++ b/mm/quicklist.c
@@ -0,0 +1,88 @@
+/*
+ * Quicklist support.
+ *
+ * Quicklists are light weight lists of pages that have a defined state
+ * on alloc and free. Pages must be in the quicklist specific defined state
+ * (zero by default) when the page is freed. It seems that the initial idea
+ * for such lists first came from Dave Miller and then various other people
+ * improved on it.
+ *
+ * Copyright (C) 2007 SGI,
+ * Christoph Lameter <clameter@sgi.com>
+ * Generalized, added support for multiple lists and
+ * constructors / destructors.
+ */
+#include <linux/kernel.h>
+
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <linux/module.h>
+#include <linux/quicklist.h>
+
+DEFINE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK];
+
+#define FRACTION_OF_NODE_MEM 16
+
+static unsigned long max_pages(unsigned long min_pages)
+{
+ unsigned long node_free_pages, max;
+
+ node_free_pages = node_page_state(numa_node_id(),
+ NR_FREE_PAGES);
+ max = node_free_pages / FRACTION_OF_NODE_MEM;
+ return max(max, min_pages);
+}
+
+static long min_pages_to_free(struct quicklist *q,
+ unsigned long min_pages, long max_free)
+{
+ long pages_to_free;
+
+ pages_to_free = q->nr_pages - max_pages(min_pages);
+
+ return min(pages_to_free, max_free);
+}
+
+/*
+ * Trim down the number of pages in the quicklist
+ */
+void quicklist_trim(int nr, void (*dtor)(void *),
+ unsigned long min_pages, unsigned long max_free)
+{
+ long pages_to_free;
+ struct quicklist *q;
+
+ q = &get_cpu_var(quicklist)[nr];
+ if (q->nr_pages > min_pages) {
+ pages_to_free = min_pages_to_free(q, min_pages, max_free);
+
+ while (pages_to_free > 0) {
+ /*
+ * We pass a gfp_t of 0 to quicklist_alloc here
+ * because we will never call into the page allocator.
+ */
+ void *p = quicklist_alloc(nr, 0, NULL);
+
+ if (dtor)
+ dtor(p);
+ free_page((unsigned long)p);
+ pages_to_free--;
+ }
+ }
+ put_cpu_var(quicklist);
+}
+
+unsigned long quicklist_total_size(void)
+{
+ unsigned long count = 0;
+ int cpu;
+ struct quicklist *ql, *q;
+
+ for_each_online_cpu(cpu) {
+ ql = per_cpu(quicklist, cpu);
+ for (q = ql; q < ql + CONFIG_NR_QUICK; q++)
+ count += q->nr_pages;
+ }
+ return count;
+}
+
diff --git a/mm/readahead.c b/mm/readahead.c
index 93d9ee692fd..9861e883fe5 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -37,7 +37,7 @@ void
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
{
ra->ra_pages = mapping->backing_dev_info->ra_pages;
- ra->prev_page = -1;
+ ra->prev_index = -1;
}
EXPORT_SYMBOL_GPL(file_ra_state_init);
@@ -202,17 +202,19 @@ out:
* size: Number of pages in that read
* Together, these form the "current window".
* Together, start and size represent the `readahead window'.
- * prev_page: The page which the readahead algorithm most-recently inspected.
+ * prev_index: The page which the readahead algorithm most-recently inspected.
* It is mainly used to detect sequential file reading.
* If page_cache_readahead sees that it is again being called for
* a page which it just looked at, it can return immediately without
* making any state changes.
+ * offset: Offset in the prev_index where the last read ended - used for
+ * detection of sequential file reading.
* ahead_start,
* ahead_size: Together, these form the "ahead window".
* ra_pages: The externally controlled max readahead for this fd.
*
* When readahead is in the off state (size == 0), readahead is disabled.
- * In this state, prev_page is used to detect the resumption of sequential I/O.
+ * In this state, prev_index is used to detect the resumption of sequential I/O.
*
* The readahead code manages two windows - the "current" and the "ahead"
* windows. The intent is that while the application is walking the pages
@@ -415,7 +417,7 @@ static int make_ahead_window(struct address_space *mapping, struct file *filp,
ra->ahead_size = get_next_ra_size(ra);
ra->ahead_start = ra->start + ra->size;
- block = force || (ra->prev_page >= ra->ahead_start);
+ block = force || (ra->prev_index >= ra->ahead_start);
ret = blockable_page_cache_readahead(mapping, filp,
ra->ahead_start, ra->ahead_size, ra, block);
@@ -467,12 +469,13 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra,
* We avoid doing extra work and bogusly perturbing the readahead
* window expansion logic.
*/
- if (offset == ra->prev_page && --req_size)
+ if (offset == ra->prev_index && --req_size)
++offset;
- /* Note that prev_page == -1 if it is a first read */
- sequential = (offset == ra->prev_page + 1);
- ra->prev_page = offset;
+ /* Note that prev_index == -1 if it is a first read */
+ sequential = (offset == ra->prev_index + 1);
+ ra->prev_index = offset;
+ ra->prev_offset = 0;
max = get_max_readahead(ra);
newsize = min(req_size, max);
@@ -481,7 +484,7 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra,
if (newsize == 0 || (ra->flags & RA_FLAG_INCACHE))
goto out;
- ra->prev_page += newsize - 1;
+ ra->prev_index += newsize - 1;
/*
* Special case - first read at start of file. We'll assume it's
@@ -537,18 +540,18 @@ page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra,
* we get called back on the first page of the ahead window which
* will allow us to submit more IO.
*/
- if (ra->prev_page >= ra->ahead_start) {
+ if (ra->prev_index >= ra->ahead_start) {
ra->start = ra->ahead_start;
ra->size = ra->ahead_size;
make_ahead_window(mapping, filp, ra, 0);
recheck:
- /* prev_page shouldn't overrun the ahead window */
- ra->prev_page = min(ra->prev_page,
+ /* prev_index shouldn't overrun the ahead window */
+ ra->prev_index = min(ra->prev_index,
ra->ahead_start + ra->ahead_size - 1);
}
out:
- return ra->prev_page + 1;
+ return ra->prev_index + 1;
}
EXPORT_SYMBOL_GPL(page_cache_readahead);
diff --git a/mm/rmap.c b/mm/rmap.c
index 59da5b734c8..304f51985c7 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -162,8 +162,7 @@ void anon_vma_unlink(struct vm_area_struct *vma)
static void anon_vma_ctor(void *data, struct kmem_cache *cachep,
unsigned long flags)
{
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
struct anon_vma *anon_vma = data;
spin_lock_init(&anon_vma->lock);
@@ -506,6 +505,7 @@ int page_mkclean(struct page *page)
return ret;
}
+EXPORT_SYMBOL_GPL(page_mkclean);
/**
* page_set_anon_rmap - setup new anonymous rmap
diff --git a/mm/shmem.c b/mm/shmem.c
index b2a35ebf071..f01e8deed64 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2358,8 +2358,7 @@ static void init_once(void *foo, struct kmem_cache *cachep,
{
struct shmem_inode_info *p = (struct shmem_inode_info *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&p->vfs_inode);
#ifdef CONFIG_TMPFS_POSIX_ACL
p->i_acl = NULL;
diff --git a/mm/slab.c b/mm/slab.c
index 4cbac24ae2f..944b20581f8 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -116,8 +116,7 @@
#include <asm/page.h>
/*
- * DEBUG - 1 for kmem_cache_create() to honour; SLAB_DEBUG_INITIAL,
- * SLAB_RED_ZONE & SLAB_POISON.
+ * DEBUG - 1 for kmem_cache_create() to honour; SLAB_RED_ZONE & SLAB_POISON.
* 0 for faster, smaller code (especially in the critical paths).
*
* STATS - 1 to collect stats for /proc/slabinfo.
@@ -149,10 +148,11 @@
* Usually, the kmalloc caches are cache_line_size() aligned, except when
* DEBUG and FORCED_DEBUG are enabled, then they are BYTES_PER_WORD aligned.
* Some archs want to perform DMA into kmalloc caches and need a guaranteed
- * alignment larger than BYTES_PER_WORD. ARCH_KMALLOC_MINALIGN allows that.
- * Note that this flag disables some debug features.
+ * alignment larger than the alignment of a 64-bit integer.
+ * ARCH_KMALLOC_MINALIGN allows that.
+ * Note that increasing this value may disable some debug features.
*/
-#define ARCH_KMALLOC_MINALIGN 0
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
#endif
#ifndef ARCH_SLAB_MINALIGN
@@ -172,15 +172,15 @@
/* Legal flag mask for kmem_cache_create(). */
#if DEBUG
-# define CREATE_MASK (SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \
+# define CREATE_MASK (SLAB_RED_ZONE | \
SLAB_POISON | SLAB_HWCACHE_ALIGN | \
SLAB_CACHE_DMA | \
- SLAB_MUST_HWCACHE_ALIGN | SLAB_STORE_USER | \
+ SLAB_STORE_USER | \
SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
#else
# define CREATE_MASK (SLAB_HWCACHE_ALIGN | \
- SLAB_CACHE_DMA | SLAB_MUST_HWCACHE_ALIGN | \
+ SLAB_CACHE_DMA | \
SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
#endif
@@ -389,7 +389,6 @@ struct kmem_cache {
unsigned int buffer_size;
u32 reciprocal_buffer_size;
/* 3) touched by every alloc & free from the backend */
- struct kmem_list3 *nodelists[MAX_NUMNODES];
unsigned int flags; /* constant flags */
unsigned int num; /* # of objs per slab */
@@ -444,6 +443,17 @@ struct kmem_cache {
int obj_offset;
int obj_size;
#endif
+ /*
+ * We put nodelists[] at the end of kmem_cache, because we want to size
+ * this array to nr_node_ids slots instead of MAX_NUMNODES
+ * (see kmem_cache_init())
+ * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache
+ * is statically defined, so we reserve the max number of nodes.
+ */
+ struct kmem_list3 *nodelists[MAX_NUMNODES];
+ /*
+ * Do not add fields after nodelists[]
+ */
};
#define CFLGS_OFF_SLAB (0x80000000UL)
@@ -527,19 +537,22 @@ static int obj_size(struct kmem_cache *cachep)
return cachep->obj_size;
}
-static unsigned long *dbg_redzone1(struct kmem_cache *cachep, void *objp)
+static unsigned long long *dbg_redzone1(struct kmem_cache *cachep, void *objp)
{
BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
- return (unsigned long*) (objp+obj_offset(cachep)-BYTES_PER_WORD);
+ return (unsigned long long*) (objp + obj_offset(cachep) -
+ sizeof(unsigned long long));
}
-static unsigned long *dbg_redzone2(struct kmem_cache *cachep, void *objp)
+static unsigned long long *dbg_redzone2(struct kmem_cache *cachep, void *objp)
{
BUG_ON(!(cachep->flags & SLAB_RED_ZONE));
if (cachep->flags & SLAB_STORE_USER)
- return (unsigned long *)(objp + cachep->buffer_size -
- 2 * BYTES_PER_WORD);
- return (unsigned long *)(objp + cachep->buffer_size - BYTES_PER_WORD);
+ return (unsigned long long *)(objp + cachep->buffer_size -
+ sizeof(unsigned long long) -
+ BYTES_PER_WORD);
+ return (unsigned long long *) (objp + cachep->buffer_size -
+ sizeof(unsigned long long));
}
static void **dbg_userword(struct kmem_cache *cachep, void *objp)
@@ -552,8 +565,8 @@ static void **dbg_userword(struct kmem_cache *cachep, void *objp)
#define obj_offset(x) 0
#define obj_size(cachep) (cachep->buffer_size)
-#define dbg_redzone1(cachep, objp) ({BUG(); (unsigned long *)NULL;})
-#define dbg_redzone2(cachep, objp) ({BUG(); (unsigned long *)NULL;})
+#define dbg_redzone1(cachep, objp) ({BUG(); (unsigned long long *)NULL;})
+#define dbg_redzone2(cachep, objp) ({BUG(); (unsigned long long *)NULL;})
#define dbg_userword(cachep, objp) ({BUG(); (void **)NULL;})
#endif
@@ -592,8 +605,7 @@ static inline void page_set_cache(struct page *page, struct kmem_cache *cache)
static inline struct kmem_cache *page_get_cache(struct page *page)
{
- if (unlikely(PageCompound(page)))
- page = (struct page *)page_private(page);
+ page = compound_head(page);
BUG_ON(!PageSlab(page));
return (struct kmem_cache *)page->lru.next;
}
@@ -605,21 +617,19 @@ static inline void page_set_slab(struct page *page, struct slab *slab)
static inline struct slab *page_get_slab(struct page *page)
{
- if (unlikely(PageCompound(page)))
- page = (struct page *)page_private(page);
BUG_ON(!PageSlab(page));
return (struct slab *)page->lru.prev;
}
static inline struct kmem_cache *virt_to_cache(const void *obj)
{
- struct page *page = virt_to_page(obj);
+ struct page *page = virt_to_head_page(obj);
return page_get_cache(page);
}
static inline struct slab *virt_to_slab(const void *obj)
{
- struct page *page = virt_to_page(obj);
+ struct page *page = virt_to_head_page(obj);
return page_get_slab(page);
}
@@ -678,9 +688,6 @@ static struct kmem_cache cache_cache = {
.shared = 1,
.buffer_size = sizeof(struct kmem_cache),
.name = "kmem_cache",
-#if DEBUG
- .obj_size = sizeof(struct kmem_cache),
-#endif
};
#define BAD_ALIEN_MAGIC 0x01020304ul
@@ -921,12 +928,6 @@ static void next_reap_node(void)
{
int node = __get_cpu_var(reap_node);
- /*
- * Also drain per cpu pages on remote zones
- */
- if (node != numa_node_id())
- drain_node_pages(node);
-
node = next_node(node, node_online_map);
if (unlikely(node >= MAX_NUMNODES))
node = first_node(node_online_map);
@@ -1146,7 +1147,7 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
* Make sure we are not freeing a object from another node to the array
* cache on this cpu.
*/
- if (likely(slabp->nodeid == node) || unlikely(!use_alien_caches))
+ if (likely(slabp->nodeid == node))
return 0;
l3 = cachep->nodelists[node];
@@ -1179,8 +1180,11 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
int memsize = sizeof(struct kmem_list3);
switch (action) {
- case CPU_UP_PREPARE:
+ case CPU_LOCK_ACQUIRE:
mutex_lock(&cache_chain_mutex);
+ break;
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
/*
* We need to do this right in the beginning since
* alloc_arraycache's are going to use this list.
@@ -1223,19 +1227,20 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
*/
list_for_each_entry(cachep, &cache_chain, next) {
struct array_cache *nc;
- struct array_cache *shared;
+ struct array_cache *shared = NULL;
struct array_cache **alien = NULL;
nc = alloc_arraycache(node, cachep->limit,
cachep->batchcount);
if (!nc)
goto bad;
- shared = alloc_arraycache(node,
+ if (cachep->shared) {
+ shared = alloc_arraycache(node,
cachep->shared * cachep->batchcount,
0xbaadf00d);
- if (!shared)
- goto bad;
-
+ if (!shared)
+ goto bad;
+ }
if (use_alien_caches) {
alien = alloc_alien_cache(node, cachep->limit);
if (!alien)
@@ -1266,17 +1271,28 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
}
break;
case CPU_ONLINE:
- mutex_unlock(&cache_chain_mutex);
+ case CPU_ONLINE_FROZEN:
start_cpu_timer(cpu);
break;
#ifdef CONFIG_HOTPLUG_CPU
- case CPU_DOWN_PREPARE:
- mutex_lock(&cache_chain_mutex);
- break;
- case CPU_DOWN_FAILED:
- mutex_unlock(&cache_chain_mutex);
- break;
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ /*
+ * Shutdown cache reaper. Note that the cache_chain_mutex is
+ * held so that if cache_reap() is invoked it cannot do
+ * anything expensive but will only modify reap_work
+ * and reschedule the timer.
+ */
+ cancel_rearming_delayed_work(&per_cpu(reap_work, cpu));
+ /* Now the cache_reaper is guaranteed to be not running. */
+ per_cpu(reap_work, cpu).work.func = NULL;
+ break;
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ start_cpu_timer(cpu);
+ break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
/*
* Even if all the cpus of a node are down, we don't free the
* kmem_list3 of any cache. This to avoid a race between
@@ -1288,6 +1304,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
/* fall thru */
#endif
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
list_for_each_entry(cachep, &cache_chain, next) {
struct array_cache *nc;
struct array_cache *shared;
@@ -1317,8 +1334,8 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
shared = l3->shared;
if (shared) {
- free_block(cachep, l3->shared->entry,
- l3->shared->avail, node);
+ free_block(cachep, shared->entry,
+ shared->avail, node);
l3->shared = NULL;
}
@@ -1346,6 +1363,8 @@ free_array_cache:
continue;
drain_freelist(cachep, l3, l3->free_objects);
}
+ break;
+ case CPU_LOCK_RELEASE:
mutex_unlock(&cache_chain_mutex);
break;
}
@@ -1394,6 +1413,9 @@ void __init kmem_cache_init(void)
int order;
int node;
+ if (num_possible_nodes() == 1)
+ use_alien_caches = 0;
+
for (i = 0; i < NUM_INIT_LISTS; i++) {
kmem_list3_init(&initkmem_list3[i]);
if (i < MAX_NUMNODES)
@@ -1436,6 +1458,15 @@ void __init kmem_cache_init(void)
cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];
+ /*
+ * struct kmem_cache size depends on nr_node_ids, which
+ * can be less than MAX_NUMNODES.
+ */
+ cache_cache.buffer_size = offsetof(struct kmem_cache, nodelists) +
+ nr_node_ids * sizeof(struct kmem_list3 *);
+#if DEBUG
+ cache_cache.obj_size = cache_cache.buffer_size;
+#endif
cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
cache_line_size());
cache_cache.reciprocal_buffer_size =
@@ -1760,7 +1791,7 @@ static void print_objinfo(struct kmem_cache *cachep, void *objp, int lines)
char *realobj;
if (cachep->flags & SLAB_RED_ZONE) {
- printk(KERN_ERR "Redzone: 0x%lx/0x%lx.\n",
+ printk(KERN_ERR "Redzone: 0x%llx/0x%llx.\n",
*dbg_redzone1(cachep, objp),
*dbg_redzone2(cachep, objp));
}
@@ -1929,7 +1960,7 @@ static void slab_destroy(struct kmem_cache *cachep, struct slab *slabp)
* For setting up all the kmem_list3s for cache whose buffer_size is same as
* size of kmem_list3.
*/
-static void set_up_list3s(struct kmem_cache *cachep, int index)
+static void __init set_up_list3s(struct kmem_cache *cachep, int index)
{
int node;
@@ -2151,13 +2182,15 @@ kmem_cache_create (const char *name, size_t size, size_t align,
*/
res = probe_kernel_address(pc->name, tmp);
if (res) {
- printk("SLAB: cache with size %d has lost its name\n",
+ printk(KERN_ERR
+ "SLAB: cache with size %d has lost its name\n",
pc->buffer_size);
continue;
}
if (!strcmp(pc->name, name)) {
- printk("kmem_cache_create: duplicate cache %s\n", name);
+ printk(KERN_ERR
+ "kmem_cache_create: duplicate cache %s\n", name);
dump_stack();
goto oops;
}
@@ -2165,12 +2198,6 @@ kmem_cache_create (const char *name, size_t size, size_t align,
#if DEBUG
WARN_ON(strchr(name, ' ')); /* It confuses parsers */
- if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
- /* No constructor, but inital state check requested */
- printk(KERN_ERR "%s: No con, but init state check "
- "requested - %s\n", __FUNCTION__, name);
- flags &= ~SLAB_DEBUG_INITIAL;
- }
#if FORCED_DEBUG
/*
* Enable redzoning and last user accounting, except for caches with
@@ -2227,7 +2254,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
* is greater than BYTES_PER_WORD.
*/
if (flags & SLAB_RED_ZONE || flags & SLAB_STORE_USER)
- ralign = BYTES_PER_WORD;
+ ralign = __alignof__(unsigned long long);
/* 2) arch mandated alignment */
if (ralign < ARCH_SLAB_MINALIGN) {
@@ -2238,7 +2265,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
ralign = align;
}
/* disable debug if necessary */
- if (ralign > BYTES_PER_WORD)
+ if (ralign > __alignof__(unsigned long long))
flags &= ~(SLAB_RED_ZONE | SLAB_STORE_USER);
/*
* 4) Store it.
@@ -2259,8 +2286,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
*/
if (flags & SLAB_RED_ZONE) {
/* add space for red zone words */
- cachep->obj_offset += BYTES_PER_WORD;
- size += 2 * BYTES_PER_WORD;
+ cachep->obj_offset += sizeof(unsigned long long);
+ size += 2 * sizeof(unsigned long long);
}
if (flags & SLAB_STORE_USER) {
/* user store requires one word storage behind the end of
@@ -2294,7 +2321,8 @@ kmem_cache_create (const char *name, size_t size, size_t align,
left_over = calculate_slab_order(cachep, size, align, flags);
if (!cachep->num) {
- printk("kmem_cache_create: couldn't create cache %s.\n", name);
+ printk(KERN_ERR
+ "kmem_cache_create: couldn't create cache %s.\n", name);
kmem_cache_free(&cache_cache, cachep);
cachep = NULL;
goto oops;
@@ -2733,19 +2761,10 @@ static int cache_grow(struct kmem_cache *cachep,
* Be lazy and only check for valid flags here, keeping it out of the
* critical path in kmem_cache_alloc().
*/
- BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK | __GFP_NO_GROW));
- if (flags & __GFP_NO_GROW)
- return 0;
+ BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK));
ctor_flags = SLAB_CTOR_CONSTRUCTOR;
local_flags = (flags & GFP_LEVEL_MASK);
- if (!(local_flags & __GFP_WAIT))
- /*
- * Not allowed to sleep. Need to tell a constructor about
- * this - it might need to know...
- */
- ctor_flags |= SLAB_CTOR_ATOMIC;
-
/* Take the l3 list lock to change the colour_next on this node */
check_irq_off();
l3 = cachep->nodelists[nodeid];
@@ -2829,7 +2848,7 @@ static void kfree_debugcheck(const void *objp)
static inline void verify_redzone_free(struct kmem_cache *cache, void *obj)
{
- unsigned long redzone1, redzone2;
+ unsigned long long redzone1, redzone2;
redzone1 = *dbg_redzone1(cache, obj);
redzone2 = *dbg_redzone2(cache, obj);
@@ -2845,7 +2864,7 @@ static inline void verify_redzone_free(struct kmem_cache *cache, void *obj)
else
slab_error(cache, "memory outside object was overwritten");
- printk(KERN_ERR "%p: redzone 1:0x%lx, redzone 2:0x%lx.\n",
+ printk(KERN_ERR "%p: redzone 1:0x%llx, redzone 2:0x%llx.\n",
obj, redzone1, redzone2);
}
@@ -2858,7 +2877,7 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
objp -= obj_offset(cachep);
kfree_debugcheck(objp);
- page = virt_to_page(objp);
+ page = virt_to_head_page(objp);
slabp = page_get_slab(page);
@@ -2875,15 +2894,6 @@ static void *cache_free_debugcheck(struct kmem_cache *cachep, void *objp,
BUG_ON(objnr >= cachep->num);
BUG_ON(objp != index_to_obj(cachep, slabp, objnr));
- if (cachep->flags & SLAB_DEBUG_INITIAL) {
- /*
- * Need to call the slab's constructor so the caller can
- * perform a verify of its state (debugging). Called without
- * the cache-lock held.
- */
- cachep->ctor(objp + obj_offset(cachep),
- cachep, SLAB_CTOR_CONSTRUCTOR | SLAB_CTOR_VERIFY);
- }
if (cachep->flags & SLAB_POISON && cachep->dtor) {
/* we want to cache poison the object,
* call the destruction callback
@@ -2987,6 +2997,14 @@ retry:
slabp = list_entry(entry, struct slab, list);
check_slabp(cachep, slabp);
check_spinlock_acquired(cachep);
+
+ /*
+ * The slab was either on partial or free list so
+ * there must be at least one object available for
+ * allocation.
+ */
+ BUG_ON(slabp->inuse < 0 || slabp->inuse >= cachep->num);
+
while (slabp->inuse < cachep->num && batchcount--) {
STATS_INC_ALLOCED(cachep);
STATS_INC_ACTIVE(cachep);
@@ -3062,7 +3080,7 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
slab_error(cachep, "double free, or memory outside"
" object was overwritten");
printk(KERN_ERR
- "%p: redzone 1:0x%lx, redzone 2:0x%lx\n",
+ "%p: redzone 1:0x%llx, redzone 2:0x%llx\n",
objp, *dbg_redzone1(cachep, objp),
*dbg_redzone2(cachep, objp));
}
@@ -3074,20 +3092,14 @@ static void *cache_alloc_debugcheck_after(struct kmem_cache *cachep,
struct slab *slabp;
unsigned objnr;
- slabp = page_get_slab(virt_to_page(objp));
+ slabp = page_get_slab(virt_to_head_page(objp));
objnr = (unsigned)(objp - slabp->s_mem) / cachep->buffer_size;
slab_bufctl(slabp)[objnr] = BUFCTL_ACTIVE;
}
#endif
objp += obj_offset(cachep);
- if (cachep->ctor && cachep->flags & SLAB_POISON) {
- unsigned long ctor_flags = SLAB_CTOR_CONSTRUCTOR;
-
- if (!(flags & __GFP_WAIT))
- ctor_flags |= SLAB_CTOR_ATOMIC;
-
- cachep->ctor(objp, cachep, ctor_flags);
- }
+ if (cachep->ctor && cachep->flags & SLAB_POISON)
+ cachep->ctor(objp, cachep, SLAB_CTOR_CONSTRUCTOR);
#if ARCH_SLAB_MINALIGN
if ((u32)objp & (ARCH_SLAB_MINALIGN-1)) {
printk(KERN_ERR "0x%p: not aligned to ARCH_SLAB_MINALIGN=%d\n",
@@ -3142,7 +3154,7 @@ static int __init failslab_debugfs(void)
struct dentry *dir;
int err;
- err = init_fault_attr_dentries(&failslab.attr, "failslab");
+ err = init_fault_attr_dentries(&failslab.attr, "failslab");
if (err)
return err;
dir = failslab.attr.dentries.dir;
@@ -3180,9 +3192,6 @@ static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
check_irq_off();
- if (should_failslab(cachep, flags))
- return NULL;
-
ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
STATS_INC_ALLOCHIT(cachep);
@@ -3256,7 +3265,7 @@ retry:
flags | GFP_THISNODE, nid);
}
- if (!obj && !(flags & __GFP_NO_GROW)) {
+ if (!obj) {
/*
* This allocation will be performed within the constraints
* of the current cpuset / memory policy requirements.
@@ -3374,6 +3383,9 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
unsigned long save_flags;
void *ptr;
+ if (should_failslab(cachep, flags))
+ return NULL;
+
cache_alloc_debugcheck_before(cachep, flags);
local_irq_save(save_flags);
@@ -3444,6 +3456,9 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
unsigned long save_flags;
void *objp;
+ if (should_failslab(cachep, flags))
+ return NULL;
+
cache_alloc_debugcheck_before(cachep, flags);
local_irq_save(save_flags);
objp = __do_cache_alloc(cachep, flags);
@@ -3563,7 +3578,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp)
check_irq_off();
objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
- if (cache_free_alien(cachep, objp))
+ if (use_alien_caches && cache_free_alien(cachep, objp))
return;
if (likely(ac->avail < ac->limit)) {
@@ -3737,6 +3752,52 @@ EXPORT_SYMBOL(__kmalloc);
#endif
/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes. If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc(). If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ struct kmem_cache *cache, *new_cache;
+ void *ret;
+
+ if (unlikely(!p))
+ return kmalloc_track_caller(new_size, flags);
+
+ if (unlikely(!new_size)) {
+ kfree(p);
+ return NULL;
+ }
+
+ cache = virt_to_cache(p);
+ new_cache = __find_general_cachep(new_size, flags);
+
+ /*
+ * If new size fits in the current cache, bail out.
+ */
+ if (likely(cache == new_cache))
+ return (void *)p;
+
+ /*
+ * We are on the slow-path here so do not use __cache_alloc
+ * because it bloats kernel text.
+ */
+ ret = kmalloc_track_caller(new_size, flags);
+ if (ret) {
+ memcpy(ret, p, min(new_size, ksize(p)));
+ kfree(p);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
+/**
* kmem_cache_free - Deallocate an object
* @cachep: The cache the allocation was from.
* @objp: The previously allocated object.
@@ -3812,12 +3873,15 @@ static int alloc_kmemlist(struct kmem_cache *cachep)
goto fail;
}
- new_shared = alloc_arraycache(node,
+ new_shared = NULL;
+ if (cachep->shared) {
+ new_shared = alloc_arraycache(node,
cachep->shared*cachep->batchcount,
0xbaadf00d);
- if (!new_shared) {
- free_alien_cache(new_alien);
- goto fail;
+ if (!new_shared) {
+ free_alien_cache(new_alien);
+ goto fail;
+ }
}
l3 = cachep->nodelists[node];
@@ -3975,10 +4039,8 @@ static int enable_cpucache(struct kmem_cache *cachep)
* to a larger limit. Thus disabled by default.
*/
shared = 0;
-#ifdef CONFIG_SMP
- if (cachep->buffer_size <= PAGE_SIZE)
+ if (cachep->buffer_size <= PAGE_SIZE && num_possible_cpus() > 1)
shared = 8;
-#endif
#if DEBUG
/*
@@ -4088,7 +4150,6 @@ next:
check_irq_on();
mutex_unlock(&cache_chain_mutex);
next_reap_node();
- refresh_cpu_vm_stats(smp_processor_id());
out:
/* Set up the next iteration */
schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_CPUC));
@@ -4380,16 +4441,12 @@ static void handle_slab(unsigned long *n, struct kmem_cache *c, struct slab *s)
static void show_symbol(struct seq_file *m, unsigned long address)
{
#ifdef CONFIG_KALLSYMS
- char *modname;
- const char *name;
unsigned long offset, size;
- char namebuf[KSYM_NAME_LEN+1];
-
- name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
+ char modname[MODULE_NAME_LEN + 1], name[KSYM_NAME_LEN + 1];
- if (name) {
+ if (lookup_symbol_attrs(address, &size, &offset, modname, name) == 0) {
seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
- if (modname)
+ if (modname[0])
seq_printf(m, " [%s]", modname);
return;
}
@@ -4478,7 +4535,7 @@ const struct seq_operations slabstats_op = {
* allocated with either kmalloc() or kmem_cache_alloc(). The object
* must not be freed during the duration of the call.
*/
-unsigned int ksize(const void *objp)
+size_t ksize(const void *objp)
{
if (unlikely(objp == NULL))
return 0;
diff --git a/mm/slob.c b/mm/slob.c
index 5adc29cb58d..c6933bc19bc 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -21,7 +21,7 @@
*
* SLAB is emulated on top of SLOB by simply calling constructors and
* destructors for every SLAB allocation. Objects are returned with
- * the 8-byte alignment unless the SLAB_MUST_HWCACHE_ALIGN flag is
+ * the 8-byte alignment unless the SLAB_HWCACHE_ALIGN flag is
* set, in which case the low-level allocator will fragment blocks to
* create the proper alignment. Again, objects of page-size or greater
* are allocated by calling __get_free_pages. As SLAB objects know
@@ -150,15 +150,6 @@ static void slob_free(void *block, int size)
spin_unlock_irqrestore(&slob_lock, flags);
}
-static int FASTCALL(find_order(int size));
-static int fastcall find_order(int size)
-{
- int order = 0;
- for ( ; size > 4096 ; size >>=1)
- order++;
- return order;
-}
-
void *__kmalloc(size_t size, gfp_t gfp)
{
slob_t *m;
@@ -174,7 +165,7 @@ void *__kmalloc(size_t size, gfp_t gfp)
if (!bb)
return 0;
- bb->order = find_order(size);
+ bb->order = get_order(size);
bb->pages = (void *)__get_free_pages(gfp, bb->order);
if (bb->pages) {
@@ -190,6 +181,39 @@ void *__kmalloc(size_t size, gfp_t gfp)
}
EXPORT_SYMBOL(__kmalloc);
+/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ *
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes. If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc(). If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+
+ if (unlikely(!p))
+ return kmalloc_track_caller(new_size, flags);
+
+ if (unlikely(!new_size)) {
+ kfree(p);
+ return NULL;
+ }
+
+ ret = kmalloc_track_caller(new_size, flags);
+ if (ret) {
+ memcpy(ret, p, min(new_size, ksize(p)));
+ kfree(p);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
void kfree(const void *block)
{
bigblock_t *bb, **last = &bigblocks;
@@ -219,7 +243,7 @@ void kfree(const void *block)
EXPORT_SYMBOL(kfree);
-unsigned int ksize(const void *block)
+size_t ksize(const void *block)
{
bigblock_t *bb;
unsigned long flags;
@@ -262,10 +286,11 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
c->ctor = ctor;
c->dtor = dtor;
/* ignore alignment unless it's forced */
- c->align = (flags & SLAB_MUST_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
+ c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
if (c->align < align)
c->align = align;
- }
+ } else if (flags & SLAB_PANIC)
+ panic("Cannot create slab cache %s\n", name);
return c;
}
@@ -284,7 +309,7 @@ void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)
if (c->size < PAGE_SIZE)
b = slob_alloc(c->size, flags, c->align);
else
- b = (void *)__get_free_pages(flags, find_order(c->size));
+ b = (void *)__get_free_pages(flags, get_order(c->size));
if (c->ctor)
c->ctor(b, c, SLAB_CTOR_CONSTRUCTOR);
@@ -311,7 +336,7 @@ void kmem_cache_free(struct kmem_cache *c, void *b)
if (c->size < PAGE_SIZE)
slob_free(b, c->size);
else
- free_pages((unsigned long)b, find_order(c->size));
+ free_pages((unsigned long)b, get_order(c->size));
}
EXPORT_SYMBOL(kmem_cache_free);
diff --git a/mm/slub.c b/mm/slub.c
new file mode 100644
index 00000000000..bd2efae02bc
--- /dev/null
+++ b/mm/slub.c
@@ -0,0 +1,3588 @@
+/*
+ * SLUB: A slab allocator that limits cache line use instead of queuing
+ * objects in per cpu and per node lists.
+ *
+ * The allocator synchronizes using per slab locks and only
+ * uses a centralized lock to manage a pool of partial slabs.
+ *
+ * (C) 2007 SGI, Christoph Lameter <clameter@sgi.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/bit_spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/cpu.h>
+#include <linux/cpuset.h>
+#include <linux/mempolicy.h>
+#include <linux/ctype.h>
+#include <linux/kallsyms.h>
+
+/*
+ * Lock order:
+ * 1. slab_lock(page)
+ * 2. slab->list_lock
+ *
+ * The slab_lock protects operations on the object of a particular
+ * slab and its metadata in the page struct. If the slab lock
+ * has been taken then no allocations nor frees can be performed
+ * on the objects in the slab nor can the slab be added or removed
+ * from the partial or full lists since this would mean modifying
+ * the page_struct of the slab.
+ *
+ * The list_lock protects the partial and full list on each node and
+ * the partial slab counter. If taken then no new slabs may be added or
+ * removed from the lists nor make the number of partial slabs be modified.
+ * (Note that the total number of slabs is an atomic value that may be
+ * modified without taking the list lock).
+ *
+ * The list_lock is a centralized lock and thus we avoid taking it as
+ * much as possible. As long as SLUB does not have to handle partial
+ * slabs, operations can continue without any centralized lock. F.e.
+ * allocating a long series of objects that fill up slabs does not require
+ * the list lock.
+ *
+ * The lock order is sometimes inverted when we are trying to get a slab
+ * off a list. We take the list_lock and then look for a page on the list
+ * to use. While we do that objects in the slabs may be freed. We can
+ * only operate on the slab if we have also taken the slab_lock. So we use
+ * a slab_trylock() on the slab. If trylock was successful then no frees
+ * can occur anymore and we can use the slab for allocations etc. If the
+ * slab_trylock() does not succeed then frees are in progress in the slab and
+ * we must stay away from it for a while since we may cause a bouncing
+ * cacheline if we try to acquire the lock. So go onto the next slab.
+ * If all pages are busy then we may allocate a new slab instead of reusing
+ * a partial slab. A new slab has noone operating on it and thus there is
+ * no danger of cacheline contention.
+ *
+ * Interrupts are disabled during allocation and deallocation in order to
+ * make the slab allocator safe to use in the context of an irq. In addition
+ * interrupts are disabled to ensure that the processor does not change
+ * while handling per_cpu slabs, due to kernel preemption.
+ *
+ * SLUB assigns one slab for allocation to each processor.
+ * Allocations only occur from these slabs called cpu slabs.
+ *
+ * Slabs with free elements are kept on a partial list and during regular
+ * operations no list for full slabs is used. If an object in a full slab is
+ * freed then the slab will show up again on the partial lists.
+ * We track full slabs for debugging purposes though because otherwise we
+ * cannot scan all objects.
+ *
+ * Slabs are freed when they become empty. Teardown and setup is
+ * minimal so we rely on the page allocators per cpu caches for
+ * fast frees and allocs.
+ *
+ * Overloading of page flags that are otherwise used for LRU management.
+ *
+ * PageActive The slab is used as a cpu cache. Allocations
+ * may be performed from the slab. The slab is not
+ * on any slab list and cannot be moved onto one.
+ *
+ * PageError Slab requires special handling due to debug
+ * options set. This moves slab handling out of
+ * the fast path.
+ */
+
+static inline int SlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+ return PageError(page);
+#else
+ return 0;
+#endif
+}
+
+static inline void SetSlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+ SetPageError(page);
+#endif
+}
+
+static inline void ClearSlabDebug(struct page *page)
+{
+#ifdef CONFIG_SLUB_DEBUG
+ ClearPageError(page);
+#endif
+}
+
+/*
+ * Issues still to be resolved:
+ *
+ * - The per cpu array is updated for each new slab and and is a remote
+ * cacheline for most nodes. This could become a bouncing cacheline given
+ * enough frequent updates. There are 16 pointers in a cacheline, so at
+ * max 16 cpus could compete for the cacheline which may be okay.
+ *
+ * - Support PAGE_ALLOC_DEBUG. Should be easy to do.
+ *
+ * - Variable sizing of the per node arrays
+ */
+
+/* Enable to test recovery from slab corruption on boot */
+#undef SLUB_RESILIENCY_TEST
+
+#if PAGE_SHIFT <= 12
+
+/*
+ * Small page size. Make sure that we do not fragment memory
+ */
+#define DEFAULT_MAX_ORDER 1
+#define DEFAULT_MIN_OBJECTS 4
+
+#else
+
+/*
+ * Large page machines are customarily able to handle larger
+ * page orders.
+ */
+#define DEFAULT_MAX_ORDER 2
+#define DEFAULT_MIN_OBJECTS 8
+
+#endif
+
+/*
+ * Mininum number of partial slabs. These will be left on the partial
+ * lists even if they are empty. kmem_cache_shrink may reclaim them.
+ */
+#define MIN_PARTIAL 2
+
+/*
+ * Maximum number of desirable partial slabs.
+ * The existence of more partial slabs makes kmem_cache_shrink
+ * sort the partial list by the number of objects in the.
+ */
+#define MAX_PARTIAL 10
+
+#define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \
+ SLAB_POISON | SLAB_STORE_USER)
+
+/*
+ * Set of flags that will prevent slab merging
+ */
+#define SLUB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \
+ SLAB_TRACE | SLAB_DESTROY_BY_RCU)
+
+#define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
+ SLAB_CACHE_DMA)
+
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
+/* Internal SLUB flags */
+#define __OBJECT_POISON 0x80000000 /* Poison object */
+
+/* Not all arches define cache_line_size */
+#ifndef cache_line_size
+#define cache_line_size() L1_CACHE_BYTES
+#endif
+
+static int kmem_size = sizeof(struct kmem_cache);
+
+#ifdef CONFIG_SMP
+static struct notifier_block slab_notifier;
+#endif
+
+static enum {
+ DOWN, /* No slab functionality available */
+ PARTIAL, /* kmem_cache_open() works but kmalloc does not */
+ UP, /* Everything works but does not show up in sysfs */
+ SYSFS /* Sysfs up */
+} slab_state = DOWN;
+
+/* A list of all slab caches on the system */
+static DECLARE_RWSEM(slub_lock);
+LIST_HEAD(slab_caches);
+
+/*
+ * Tracking user of a slab.
+ */
+struct track {
+ void *addr; /* Called from address */
+ int cpu; /* Was running on cpu */
+ int pid; /* Pid context */
+ unsigned long when; /* When did the operation occur */
+};
+
+enum track_item { TRACK_ALLOC, TRACK_FREE };
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
+static int sysfs_slab_add(struct kmem_cache *);
+static int sysfs_slab_alias(struct kmem_cache *, const char *);
+static void sysfs_slab_remove(struct kmem_cache *);
+#else
+static int sysfs_slab_add(struct kmem_cache *s) { return 0; }
+static int sysfs_slab_alias(struct kmem_cache *s, const char *p) { return 0; }
+static void sysfs_slab_remove(struct kmem_cache *s) {}
+#endif
+
+/********************************************************************
+ * Core slab cache functions
+ *******************************************************************/
+
+int slab_is_available(void)
+{
+ return slab_state >= UP;
+}
+
+static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
+{
+#ifdef CONFIG_NUMA
+ return s->node[node];
+#else
+ return &s->local_node;
+#endif
+}
+
+static inline int check_valid_pointer(struct kmem_cache *s,
+ struct page *page, const void *object)
+{
+ void *base;
+
+ if (!object)
+ return 1;
+
+ base = page_address(page);
+ if (object < base || object >= base + s->objects * s->size ||
+ (object - base) % s->size) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Slow version of get and set free pointer.
+ *
+ * This version requires touching the cache lines of kmem_cache which
+ * we avoid to do in the fast alloc free paths. There we obtain the offset
+ * from the page struct.
+ */
+static inline void *get_freepointer(struct kmem_cache *s, void *object)
+{
+ return *(void **)(object + s->offset);
+}
+
+static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
+{
+ *(void **)(object + s->offset) = fp;
+}
+
+/* Loop over all objects in a slab */
+#define for_each_object(__p, __s, __addr) \
+ for (__p = (__addr); __p < (__addr) + (__s)->objects * (__s)->size;\
+ __p += (__s)->size)
+
+/* Scan freelist */
+#define for_each_free_object(__p, __s, __free) \
+ for (__p = (__free); __p; __p = get_freepointer((__s), __p))
+
+/* Determine object index from a given position */
+static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
+{
+ return (p - addr) / s->size;
+}
+
+#ifdef CONFIG_SLUB_DEBUG
+/*
+ * Debug settings:
+ */
+static int slub_debug;
+
+static char *slub_debug_slabs;
+
+/*
+ * Object debugging
+ */
+static void print_section(char *text, u8 *addr, unsigned int length)
+{
+ int i, offset;
+ int newline = 1;
+ char ascii[17];
+
+ ascii[16] = 0;
+
+ for (i = 0; i < length; i++) {
+ if (newline) {
+ printk(KERN_ERR "%10s 0x%p: ", text, addr + i);
+ newline = 0;
+ }
+ printk(" %02x", addr[i]);
+ offset = i % 16;
+ ascii[offset] = isgraph(addr[i]) ? addr[i] : '.';
+ if (offset == 15) {
+ printk(" %s\n",ascii);
+ newline = 1;
+ }
+ }
+ if (!newline) {
+ i %= 16;
+ while (i < 16) {
+ printk(" ");
+ ascii[i] = ' ';
+ i++;
+ }
+ printk(" %s\n", ascii);
+ }
+}
+
+static struct track *get_track(struct kmem_cache *s, void *object,
+ enum track_item alloc)
+{
+ struct track *p;
+
+ if (s->offset)
+ p = object + s->offset + sizeof(void *);
+ else
+ p = object + s->inuse;
+
+ return p + alloc;
+}
+
+static void set_track(struct kmem_cache *s, void *object,
+ enum track_item alloc, void *addr)
+{
+ struct track *p;
+
+ if (s->offset)
+ p = object + s->offset + sizeof(void *);
+ else
+ p = object + s->inuse;
+
+ p += alloc;
+ if (addr) {
+ p->addr = addr;
+ p->cpu = smp_processor_id();
+ p->pid = current ? current->pid : -1;
+ p->when = jiffies;
+ } else
+ memset(p, 0, sizeof(struct track));
+}
+
+static void init_tracking(struct kmem_cache *s, void *object)
+{
+ if (s->flags & SLAB_STORE_USER) {
+ set_track(s, object, TRACK_FREE, NULL);
+ set_track(s, object, TRACK_ALLOC, NULL);
+ }
+}
+
+static void print_track(const char *s, struct track *t)
+{
+ if (!t->addr)
+ return;
+
+ printk(KERN_ERR "%s: ", s);
+ __print_symbol("%s", (unsigned long)t->addr);
+ printk(" jiffies_ago=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid);
+}
+
+static void print_trailer(struct kmem_cache *s, u8 *p)
+{
+ unsigned int off; /* Offset of last byte */
+
+ if (s->flags & SLAB_RED_ZONE)
+ print_section("Redzone", p + s->objsize,
+ s->inuse - s->objsize);
+
+ printk(KERN_ERR "FreePointer 0x%p -> 0x%p\n",
+ p + s->offset,
+ get_freepointer(s, p));
+
+ if (s->offset)
+ off = s->offset + sizeof(void *);
+ else
+ off = s->inuse;
+
+ if (s->flags & SLAB_STORE_USER) {
+ print_track("Last alloc", get_track(s, p, TRACK_ALLOC));
+ print_track("Last free ", get_track(s, p, TRACK_FREE));
+ off += 2 * sizeof(struct track);
+ }
+
+ if (off != s->size)
+ /* Beginning of the filler is the free pointer */
+ print_section("Filler", p + off, s->size - off);
+}
+
+static void object_err(struct kmem_cache *s, struct page *page,
+ u8 *object, char *reason)
+{
+ u8 *addr = page_address(page);
+
+ printk(KERN_ERR "*** SLUB %s: %s@0x%p slab 0x%p\n",
+ s->name, reason, object, page);
+ printk(KERN_ERR " offset=%tu flags=0x%04lx inuse=%u freelist=0x%p\n",
+ object - addr, page->flags, page->inuse, page->freelist);
+ if (object > addr + 16)
+ print_section("Bytes b4", object - 16, 16);
+ print_section("Object", object, min(s->objsize, 128));
+ print_trailer(s, object);
+ dump_stack();
+}
+
+static void slab_err(struct kmem_cache *s, struct page *page, char *reason, ...)
+{
+ va_list args;
+ char buf[100];
+
+ va_start(args, reason);
+ vsnprintf(buf, sizeof(buf), reason, args);
+ va_end(args);
+ printk(KERN_ERR "*** SLUB %s: %s in slab @0x%p\n", s->name, buf,
+ page);
+ dump_stack();
+}
+
+static void init_object(struct kmem_cache *s, void *object, int active)
+{
+ u8 *p = object;
+
+ if (s->flags & __OBJECT_POISON) {
+ memset(p, POISON_FREE, s->objsize - 1);
+ p[s->objsize -1] = POISON_END;
+ }
+
+ if (s->flags & SLAB_RED_ZONE)
+ memset(p + s->objsize,
+ active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE,
+ s->inuse - s->objsize);
+}
+
+static int check_bytes(u8 *start, unsigned int value, unsigned int bytes)
+{
+ while (bytes) {
+ if (*start != (u8)value)
+ return 0;
+ start++;
+ bytes--;
+ }
+ return 1;
+}
+
+/*
+ * Object layout:
+ *
+ * object address
+ * Bytes of the object to be managed.
+ * If the freepointer may overlay the object then the free
+ * pointer is the first word of the object.
+ *
+ * Poisoning uses 0x6b (POISON_FREE) and the last byte is
+ * 0xa5 (POISON_END)
+ *
+ * object + s->objsize
+ * Padding to reach word boundary. This is also used for Redzoning.
+ * Padding is extended by another word if Redzoning is enabled and
+ * objsize == inuse.
+ *
+ * We fill with 0xbb (RED_INACTIVE) for inactive objects and with
+ * 0xcc (RED_ACTIVE) for objects in use.
+ *
+ * object + s->inuse
+ * Meta data starts here.
+ *
+ * A. Free pointer (if we cannot overwrite object on free)
+ * B. Tracking data for SLAB_STORE_USER
+ * C. Padding to reach required alignment boundary or at mininum
+ * one word if debuggin is on to be able to detect writes
+ * before the word boundary.
+ *
+ * Padding is done using 0x5a (POISON_INUSE)
+ *
+ * object + s->size
+ * Nothing is used beyond s->size.
+ *
+ * If slabcaches are merged then the objsize and inuse boundaries are mostly
+ * ignored. And therefore no slab options that rely on these boundaries
+ * may be used with merged slabcaches.
+ */
+
+static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
+ void *from, void *to)
+{
+ printk(KERN_ERR "@@@ SLUB %s: Restoring %s (0x%x) from 0x%p-0x%p\n",
+ s->name, message, data, from, to - 1);
+ memset(from, data, to - from);
+}
+
+static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
+{
+ unsigned long off = s->inuse; /* The end of info */
+
+ if (s->offset)
+ /* Freepointer is placed after the object. */
+ off += sizeof(void *);
+
+ if (s->flags & SLAB_STORE_USER)
+ /* We also have user information there */
+ off += 2 * sizeof(struct track);
+
+ if (s->size == off)
+ return 1;
+
+ if (check_bytes(p + off, POISON_INUSE, s->size - off))
+ return 1;
+
+ object_err(s, page, p, "Object padding check fails");
+
+ /*
+ * Restore padding
+ */
+ restore_bytes(s, "object padding", POISON_INUSE, p + off, p + s->size);
+ return 0;
+}
+
+static int slab_pad_check(struct kmem_cache *s, struct page *page)
+{
+ u8 *p;
+ int length, remainder;
+
+ if (!(s->flags & SLAB_POISON))
+ return 1;
+
+ p = page_address(page);
+ length = s->objects * s->size;
+ remainder = (PAGE_SIZE << s->order) - length;
+ if (!remainder)
+ return 1;
+
+ if (!check_bytes(p + length, POISON_INUSE, remainder)) {
+ slab_err(s, page, "Padding check failed");
+ restore_bytes(s, "slab padding", POISON_INUSE, p + length,
+ p + length + remainder);
+ return 0;
+ }
+ return 1;
+}
+
+static int check_object(struct kmem_cache *s, struct page *page,
+ void *object, int active)
+{
+ u8 *p = object;
+ u8 *endobject = object + s->objsize;
+
+ if (s->flags & SLAB_RED_ZONE) {
+ unsigned int red =
+ active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE;
+
+ if (!check_bytes(endobject, red, s->inuse - s->objsize)) {
+ object_err(s, page, object,
+ active ? "Redzone Active" : "Redzone Inactive");
+ restore_bytes(s, "redzone", red,
+ endobject, object + s->inuse);
+ return 0;
+ }
+ } else {
+ if ((s->flags & SLAB_POISON) && s->objsize < s->inuse &&
+ !check_bytes(endobject, POISON_INUSE,
+ s->inuse - s->objsize)) {
+ object_err(s, page, p, "Alignment padding check fails");
+ /*
+ * Fix it so that there will not be another report.
+ *
+ * Hmmm... We may be corrupting an object that now expects
+ * to be longer than allowed.
+ */
+ restore_bytes(s, "alignment padding", POISON_INUSE,
+ endobject, object + s->inuse);
+ }
+ }
+
+ if (s->flags & SLAB_POISON) {
+ if (!active && (s->flags & __OBJECT_POISON) &&
+ (!check_bytes(p, POISON_FREE, s->objsize - 1) ||
+ p[s->objsize - 1] != POISON_END)) {
+
+ object_err(s, page, p, "Poison check failed");
+ restore_bytes(s, "Poison", POISON_FREE,
+ p, p + s->objsize -1);
+ restore_bytes(s, "Poison", POISON_END,
+ p + s->objsize - 1, p + s->objsize);
+ return 0;
+ }
+ /*
+ * check_pad_bytes cleans up on its own.
+ */
+ check_pad_bytes(s, page, p);
+ }
+
+ if (!s->offset && active)
+ /*
+ * Object and freepointer overlap. Cannot check
+ * freepointer while object is allocated.
+ */
+ return 1;
+
+ /* Check free pointer validity */
+ if (!check_valid_pointer(s, page, get_freepointer(s, p))) {
+ object_err(s, page, p, "Freepointer corrupt");
+ /*
+ * No choice but to zap it and thus loose the remainder
+ * of the free objects in this slab. May cause
+ * another error because the object count is now wrong.
+ */
+ set_freepointer(s, p, NULL);
+ return 0;
+ }
+ return 1;
+}
+
+static int check_slab(struct kmem_cache *s, struct page *page)
+{
+ VM_BUG_ON(!irqs_disabled());
+
+ if (!PageSlab(page)) {
+ slab_err(s, page, "Not a valid slab page flags=%lx "
+ "mapping=0x%p count=%d", page->flags, page->mapping,
+ page_count(page));
+ return 0;
+ }
+ if (page->offset * sizeof(void *) != s->offset) {
+ slab_err(s, page, "Corrupted offset %lu flags=0x%lx "
+ "mapping=0x%p count=%d",
+ (unsigned long)(page->offset * sizeof(void *)),
+ page->flags,
+ page->mapping,
+ page_count(page));
+ return 0;
+ }
+ if (page->inuse > s->objects) {
+ slab_err(s, page, "inuse %u > max %u @0x%p flags=%lx "
+ "mapping=0x%p count=%d",
+ s->name, page->inuse, s->objects, page->flags,
+ page->mapping, page_count(page));
+ return 0;
+ }
+ /* Slab_pad_check fixes things up after itself */
+ slab_pad_check(s, page);
+ return 1;
+}
+
+/*
+ * Determine if a certain object on a page is on the freelist. Must hold the
+ * slab lock to guarantee that the chains are in a consistent state.
+ */
+static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
+{
+ int nr = 0;
+ void *fp = page->freelist;
+ void *object = NULL;
+
+ while (fp && nr <= s->objects) {
+ if (fp == search)
+ return 1;
+ if (!check_valid_pointer(s, page, fp)) {
+ if (object) {
+ object_err(s, page, object,
+ "Freechain corrupt");
+ set_freepointer(s, object, NULL);
+ break;
+ } else {
+ slab_err(s, page, "Freepointer 0x%p corrupt",
+ fp);
+ page->freelist = NULL;
+ page->inuse = s->objects;
+ printk(KERN_ERR "@@@ SLUB %s: Freelist "
+ "cleared. Slab 0x%p\n",
+ s->name, page);
+ return 0;
+ }
+ break;
+ }
+ object = fp;
+ fp = get_freepointer(s, object);
+ nr++;
+ }
+
+ if (page->inuse != s->objects - nr) {
+ slab_err(s, page, "Wrong object count. Counter is %d but "
+ "counted were %d", s, page, page->inuse,
+ s->objects - nr);
+ page->inuse = s->objects - nr;
+ printk(KERN_ERR "@@@ SLUB %s: Object count adjusted. "
+ "Slab @0x%p\n", s->name, page);
+ }
+ return search == NULL;
+}
+
+/*
+ * Tracking of fully allocated slabs for debugging purposes.
+ */
+static void add_full(struct kmem_cache_node *n, struct page *page)
+{
+ spin_lock(&n->list_lock);
+ list_add(&page->lru, &n->full);
+ spin_unlock(&n->list_lock);
+}
+
+static void remove_full(struct kmem_cache *s, struct page *page)
+{
+ struct kmem_cache_node *n;
+
+ if (!(s->flags & SLAB_STORE_USER))
+ return;
+
+ n = get_node(s, page_to_nid(page));
+
+ spin_lock(&n->list_lock);
+ list_del(&page->lru);
+ spin_unlock(&n->list_lock);
+}
+
+static int alloc_object_checks(struct kmem_cache *s, struct page *page,
+ void *object)
+{
+ if (!check_slab(s, page))
+ goto bad;
+
+ if (object && !on_freelist(s, page, object)) {
+ slab_err(s, page, "Object 0x%p already allocated", object);
+ goto bad;
+ }
+
+ if (!check_valid_pointer(s, page, object)) {
+ object_err(s, page, object, "Freelist Pointer check fails");
+ goto bad;
+ }
+
+ if (!object)
+ return 1;
+
+ if (!check_object(s, page, object, 0))
+ goto bad;
+
+ return 1;
+bad:
+ if (PageSlab(page)) {
+ /*
+ * If this is a slab page then lets do the best we can
+ * to avoid issues in the future. Marking all objects
+ * as used avoids touching the remaining objects.
+ */
+ printk(KERN_ERR "@@@ SLUB: %s slab 0x%p. Marking all objects used.\n",
+ s->name, page);
+ page->inuse = s->objects;
+ page->freelist = NULL;
+ /* Fix up fields that may be corrupted */
+ page->offset = s->offset / sizeof(void *);
+ }
+ return 0;
+}
+
+static int free_object_checks(struct kmem_cache *s, struct page *page,
+ void *object)
+{
+ if (!check_slab(s, page))
+ goto fail;
+
+ if (!check_valid_pointer(s, page, object)) {
+ slab_err(s, page, "Invalid object pointer 0x%p", object);
+ goto fail;
+ }
+
+ if (on_freelist(s, page, object)) {
+ slab_err(s, page, "Object 0x%p already free", object);
+ goto fail;
+ }
+
+ if (!check_object(s, page, object, 1))
+ return 0;
+
+ if (unlikely(s != page->slab)) {
+ if (!PageSlab(page))
+ slab_err(s, page, "Attempt to free object(0x%p) "
+ "outside of slab", object);
+ else
+ if (!page->slab) {
+ printk(KERN_ERR
+ "SLUB <none>: no slab for object 0x%p.\n",
+ object);
+ dump_stack();
+ }
+ else
+ slab_err(s, page, "object at 0x%p belongs "
+ "to slab %s", object, page->slab->name);
+ goto fail;
+ }
+ return 1;
+fail:
+ printk(KERN_ERR "@@@ SLUB: %s slab 0x%p object at 0x%p not freed.\n",
+ s->name, page, object);
+ return 0;
+}
+
+static void trace(struct kmem_cache *s, struct page *page, void *object, int alloc)
+{
+ if (s->flags & SLAB_TRACE) {
+ printk(KERN_INFO "TRACE %s %s 0x%p inuse=%d fp=0x%p\n",
+ s->name,
+ alloc ? "alloc" : "free",
+ object, page->inuse,
+ page->freelist);
+
+ if (!alloc)
+ print_section("Object", (void *)object, s->objsize);
+
+ dump_stack();
+ }
+}
+
+static int __init setup_slub_debug(char *str)
+{
+ if (!str || *str != '=')
+ slub_debug = DEBUG_DEFAULT_FLAGS;
+ else {
+ str++;
+ if (*str == 0 || *str == ',')
+ slub_debug = DEBUG_DEFAULT_FLAGS;
+ else
+ for( ;*str && *str != ','; str++)
+ switch (*str) {
+ case 'f' : case 'F' :
+ slub_debug |= SLAB_DEBUG_FREE;
+ break;
+ case 'z' : case 'Z' :
+ slub_debug |= SLAB_RED_ZONE;
+ break;
+ case 'p' : case 'P' :
+ slub_debug |= SLAB_POISON;
+ break;
+ case 'u' : case 'U' :
+ slub_debug |= SLAB_STORE_USER;
+ break;
+ case 't' : case 'T' :
+ slub_debug |= SLAB_TRACE;
+ break;
+ default:
+ printk(KERN_ERR "slub_debug option '%c' "
+ "unknown. skipped\n",*str);
+ }
+ }
+
+ if (*str == ',')
+ slub_debug_slabs = str + 1;
+ return 1;
+}
+
+__setup("slub_debug", setup_slub_debug);
+
+static void kmem_cache_open_debug_check(struct kmem_cache *s)
+{
+ /*
+ * The page->offset field is only 16 bit wide. This is an offset
+ * in units of words from the beginning of an object. If the slab
+ * size is bigger then we cannot move the free pointer behind the
+ * object anymore.
+ *
+ * On 32 bit platforms the limit is 256k. On 64bit platforms
+ * the limit is 512k.
+ *
+ * Debugging or ctor/dtors may create a need to move the free
+ * pointer. Fail if this happens.
+ */
+ if (s->size >= 65535 * sizeof(void *)) {
+ BUG_ON(s->flags & (SLAB_RED_ZONE | SLAB_POISON |
+ SLAB_STORE_USER | SLAB_DESTROY_BY_RCU));
+ BUG_ON(s->ctor || s->dtor);
+ }
+ else
+ /*
+ * Enable debugging if selected on the kernel commandline.
+ */
+ if (slub_debug && (!slub_debug_slabs ||
+ strncmp(slub_debug_slabs, s->name,
+ strlen(slub_debug_slabs)) == 0))
+ s->flags |= slub_debug;
+}
+#else
+
+static inline int alloc_object_checks(struct kmem_cache *s,
+ struct page *page, void *object) { return 0; }
+
+static inline int free_object_checks(struct kmem_cache *s,
+ struct page *page, void *object) { return 0; }
+
+static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
+static inline void remove_full(struct kmem_cache *s, struct page *page) {}
+static inline void trace(struct kmem_cache *s, struct page *page,
+ void *object, int alloc) {}
+static inline void init_object(struct kmem_cache *s,
+ void *object, int active) {}
+static inline void init_tracking(struct kmem_cache *s, void *object) {}
+static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
+ { return 1; }
+static inline int check_object(struct kmem_cache *s, struct page *page,
+ void *object, int active) { return 1; }
+static inline void set_track(struct kmem_cache *s, void *object,
+ enum track_item alloc, void *addr) {}
+static inline void kmem_cache_open_debug_check(struct kmem_cache *s) {}
+#define slub_debug 0
+#endif
+/*
+ * Slab allocation and freeing
+ */
+static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
+{
+ struct page * page;
+ int pages = 1 << s->order;
+
+ if (s->order)
+ flags |= __GFP_COMP;
+
+ if (s->flags & SLAB_CACHE_DMA)
+ flags |= SLUB_DMA;
+
+ if (node == -1)
+ page = alloc_pages(flags, s->order);
+ else
+ page = alloc_pages_node(node, flags, s->order);
+
+ if (!page)
+ return NULL;
+
+ mod_zone_page_state(page_zone(page),
+ (s->flags & SLAB_RECLAIM_ACCOUNT) ?
+ NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+ pages);
+
+ return page;
+}
+
+static void setup_object(struct kmem_cache *s, struct page *page,
+ void *object)
+{
+ if (SlabDebug(page)) {
+ init_object(s, object, 0);
+ init_tracking(s, object);
+ }
+
+ if (unlikely(s->ctor))
+ s->ctor(object, s, SLAB_CTOR_CONSTRUCTOR);
+}
+
+static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
+{
+ struct page *page;
+ struct kmem_cache_node *n;
+ void *start;
+ void *end;
+ void *last;
+ void *p;
+
+ BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK));
+
+ if (flags & __GFP_WAIT)
+ local_irq_enable();
+
+ page = allocate_slab(s, flags & GFP_LEVEL_MASK, node);
+ if (!page)
+ goto out;
+
+ n = get_node(s, page_to_nid(page));
+ if (n)
+ atomic_long_inc(&n->nr_slabs);
+ page->offset = s->offset / sizeof(void *);
+ page->slab = s;
+ page->flags |= 1 << PG_slab;
+ if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
+ SLAB_STORE_USER | SLAB_TRACE))
+ SetSlabDebug(page);
+
+ start = page_address(page);
+ end = start + s->objects * s->size;
+
+ if (unlikely(s->flags & SLAB_POISON))
+ memset(start, POISON_INUSE, PAGE_SIZE << s->order);
+
+ last = start;
+ for_each_object(p, s, start) {
+ setup_object(s, page, last);
+ set_freepointer(s, last, p);
+ last = p;
+ }
+ setup_object(s, page, last);
+ set_freepointer(s, last, NULL);
+
+ page->freelist = start;
+ page->inuse = 0;
+out:
+ if (flags & __GFP_WAIT)
+ local_irq_disable();
+ return page;
+}
+
+static void __free_slab(struct kmem_cache *s, struct page *page)
+{
+ int pages = 1 << s->order;
+
+ if (unlikely(SlabDebug(page) || s->dtor)) {
+ void *p;
+
+ slab_pad_check(s, page);
+ for_each_object(p, s, page_address(page)) {
+ if (s->dtor)
+ s->dtor(p, s, 0);
+ check_object(s, page, p, 0);
+ }
+ }
+
+ mod_zone_page_state(page_zone(page),
+ (s->flags & SLAB_RECLAIM_ACCOUNT) ?
+ NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+ - pages);
+
+ page->mapping = NULL;
+ __free_pages(page, s->order);
+}
+
+static void rcu_free_slab(struct rcu_head *h)
+{
+ struct page *page;
+
+ page = container_of((struct list_head *)h, struct page, lru);
+ __free_slab(page->slab, page);
+}
+
+static void free_slab(struct kmem_cache *s, struct page *page)
+{
+ if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) {
+ /*
+ * RCU free overloads the RCU head over the LRU
+ */
+ struct rcu_head *head = (void *)&page->lru;
+
+ call_rcu(head, rcu_free_slab);
+ } else
+ __free_slab(s, page);
+}
+
+static void discard_slab(struct kmem_cache *s, struct page *page)
+{
+ struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+
+ atomic_long_dec(&n->nr_slabs);
+ reset_page_mapcount(page);
+ ClearSlabDebug(page);
+ __ClearPageSlab(page);
+ free_slab(s, page);
+}
+
+/*
+ * Per slab locking using the pagelock
+ */
+static __always_inline void slab_lock(struct page *page)
+{
+ bit_spin_lock(PG_locked, &page->flags);
+}
+
+static __always_inline void slab_unlock(struct page *page)
+{
+ bit_spin_unlock(PG_locked, &page->flags);
+}
+
+static __always_inline int slab_trylock(struct page *page)
+{
+ int rc = 1;
+
+ rc = bit_spin_trylock(PG_locked, &page->flags);
+ return rc;
+}
+
+/*
+ * Management of partially allocated slabs
+ */
+static void add_partial_tail(struct kmem_cache_node *n, struct page *page)
+{
+ spin_lock(&n->list_lock);
+ n->nr_partial++;
+ list_add_tail(&page->lru, &n->partial);
+ spin_unlock(&n->list_lock);
+}
+
+static void add_partial(struct kmem_cache_node *n, struct page *page)
+{
+ spin_lock(&n->list_lock);
+ n->nr_partial++;
+ list_add(&page->lru, &n->partial);
+ spin_unlock(&n->list_lock);
+}
+
+static void remove_partial(struct kmem_cache *s,
+ struct page *page)
+{
+ struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+
+ spin_lock(&n->list_lock);
+ list_del(&page->lru);
+ n->nr_partial--;
+ spin_unlock(&n->list_lock);
+}
+
+/*
+ * Lock slab and remove from the partial list.
+ *
+ * Must hold list_lock.
+ */
+static int lock_and_del_slab(struct kmem_cache_node *n, struct page *page)
+{
+ if (slab_trylock(page)) {
+ list_del(&page->lru);
+ n->nr_partial--;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Try to allocate a partial slab from a specific node.
+ */
+static struct page *get_partial_node(struct kmem_cache_node *n)
+{
+ struct page *page;
+
+ /*
+ * Racy check. If we mistakenly see no partial slabs then we
+ * just allocate an empty slab. If we mistakenly try to get a
+ * partial slab and there is none available then get_partials()
+ * will return NULL.
+ */
+ if (!n || !n->nr_partial)
+ return NULL;
+
+ spin_lock(&n->list_lock);
+ list_for_each_entry(page, &n->partial, lru)
+ if (lock_and_del_slab(n, page))
+ goto out;
+ page = NULL;
+out:
+ spin_unlock(&n->list_lock);
+ return page;
+}
+
+/*
+ * Get a page from somewhere. Search in increasing NUMA distances.
+ */
+static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags)
+{
+#ifdef CONFIG_NUMA
+ struct zonelist *zonelist;
+ struct zone **z;
+ struct page *page;
+
+ /*
+ * The defrag ratio allows a configuration of the tradeoffs between
+ * inter node defragmentation and node local allocations. A lower
+ * defrag_ratio increases the tendency to do local allocations
+ * instead of attempting to obtain partial slabs from other nodes.
+ *
+ * If the defrag_ratio is set to 0 then kmalloc() always
+ * returns node local objects. If the ratio is higher then kmalloc()
+ * may return off node objects because partial slabs are obtained
+ * from other nodes and filled up.
+ *
+ * If /sys/slab/xx/defrag_ratio is set to 100 (which makes
+ * defrag_ratio = 1000) then every (well almost) allocation will
+ * first attempt to defrag slab caches on other nodes. This means
+ * scanning over all nodes to look for partial slabs which may be
+ * expensive if we do it every time we are trying to find a slab
+ * with available objects.
+ */
+ if (!s->defrag_ratio || get_cycles() % 1024 > s->defrag_ratio)
+ return NULL;
+
+ zonelist = &NODE_DATA(slab_node(current->mempolicy))
+ ->node_zonelists[gfp_zone(flags)];
+ for (z = zonelist->zones; *z; z++) {
+ struct kmem_cache_node *n;
+
+ n = get_node(s, zone_to_nid(*z));
+
+ if (n && cpuset_zone_allowed_hardwall(*z, flags) &&
+ n->nr_partial > MIN_PARTIAL) {
+ page = get_partial_node(n);
+ if (page)
+ return page;
+ }
+ }
+#endif
+ return NULL;
+}
+
+/*
+ * Get a partial page, lock it and return it.
+ */
+static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
+{
+ struct page *page;
+ int searchnode = (node == -1) ? numa_node_id() : node;
+
+ page = get_partial_node(get_node(s, searchnode));
+ if (page || (flags & __GFP_THISNODE))
+ return page;
+
+ return get_any_partial(s, flags);
+}
+
+/*
+ * Move a page back to the lists.
+ *
+ * Must be called with the slab lock held.
+ *
+ * On exit the slab lock will have been dropped.
+ */
+static void putback_slab(struct kmem_cache *s, struct page *page)
+{
+ struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+
+ if (page->inuse) {
+
+ if (page->freelist)
+ add_partial(n, page);
+ else if (SlabDebug(page) && (s->flags & SLAB_STORE_USER))
+ add_full(n, page);
+ slab_unlock(page);
+
+ } else {
+ if (n->nr_partial < MIN_PARTIAL) {
+ /*
+ * Adding an empty slab to the partial slabs in order
+ * to avoid page allocator overhead. This slab needs
+ * to come after the other slabs with objects in
+ * order to fill them up. That way the size of the
+ * partial list stays small. kmem_cache_shrink can
+ * reclaim empty slabs from the partial list.
+ */
+ add_partial_tail(n, page);
+ slab_unlock(page);
+ } else {
+ slab_unlock(page);
+ discard_slab(s, page);
+ }
+ }
+}
+
+/*
+ * Remove the cpu slab
+ */
+static void deactivate_slab(struct kmem_cache *s, struct page *page, int cpu)
+{
+ s->cpu_slab[cpu] = NULL;
+ ClearPageActive(page);
+
+ putback_slab(s, page);
+}
+
+static void flush_slab(struct kmem_cache *s, struct page *page, int cpu)
+{
+ slab_lock(page);
+ deactivate_slab(s, page, cpu);
+}
+
+/*
+ * Flush cpu slab.
+ * Called from IPI handler with interrupts disabled.
+ */
+static void __flush_cpu_slab(struct kmem_cache *s, int cpu)
+{
+ struct page *page = s->cpu_slab[cpu];
+
+ if (likely(page))
+ flush_slab(s, page, cpu);
+}
+
+static void flush_cpu_slab(void *d)
+{
+ struct kmem_cache *s = d;
+ int cpu = smp_processor_id();
+
+ __flush_cpu_slab(s, cpu);
+}
+
+static void flush_all(struct kmem_cache *s)
+{
+#ifdef CONFIG_SMP
+ on_each_cpu(flush_cpu_slab, s, 1, 1);
+#else
+ unsigned long flags;
+
+ local_irq_save(flags);
+ flush_cpu_slab(s);
+ local_irq_restore(flags);
+#endif
+}
+
+/*
+ * slab_alloc is optimized to only modify two cachelines on the fast path
+ * (aside from the stack):
+ *
+ * 1. The page struct
+ * 2. The first cacheline of the object to be allocated.
+ *
+ * The only other cache lines that are read (apart from code) is the
+ * per cpu array in the kmem_cache struct.
+ *
+ * Fastpath is not possible if we need to get a new slab or have
+ * debugging enabled (which means all slabs are marked with SlabDebug)
+ */
+static void *slab_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, int node, void *addr)
+{
+ struct page *page;
+ void **object;
+ unsigned long flags;
+ int cpu;
+
+ local_irq_save(flags);
+ cpu = smp_processor_id();
+ page = s->cpu_slab[cpu];
+ if (!page)
+ goto new_slab;
+
+ slab_lock(page);
+ if (unlikely(node != -1 && page_to_nid(page) != node))
+ goto another_slab;
+redo:
+ object = page->freelist;
+ if (unlikely(!object))
+ goto another_slab;
+ if (unlikely(SlabDebug(page)))
+ goto debug;
+
+have_object:
+ page->inuse++;
+ page->freelist = object[page->offset];
+ slab_unlock(page);
+ local_irq_restore(flags);
+ return object;
+
+another_slab:
+ deactivate_slab(s, page, cpu);
+
+new_slab:
+ page = get_partial(s, gfpflags, node);
+ if (likely(page)) {
+have_slab:
+ s->cpu_slab[cpu] = page;
+ SetPageActive(page);
+ goto redo;
+ }
+
+ page = new_slab(s, gfpflags, node);
+ if (page) {
+ cpu = smp_processor_id();
+ if (s->cpu_slab[cpu]) {
+ /*
+ * Someone else populated the cpu_slab while we
+ * enabled interrupts, or we have gotten scheduled
+ * on another cpu. The page may not be on the
+ * requested node even if __GFP_THISNODE was
+ * specified. So we need to recheck.
+ */
+ if (node == -1 ||
+ page_to_nid(s->cpu_slab[cpu]) == node) {
+ /*
+ * Current cpuslab is acceptable and we
+ * want the current one since its cache hot
+ */
+ discard_slab(s, page);
+ page = s->cpu_slab[cpu];
+ slab_lock(page);
+ goto redo;
+ }
+ /* New slab does not fit our expectations */
+ flush_slab(s, s->cpu_slab[cpu], cpu);
+ }
+ slab_lock(page);
+ goto have_slab;
+ }
+ local_irq_restore(flags);
+ return NULL;
+debug:
+ if (!alloc_object_checks(s, page, object))
+ goto another_slab;
+ if (s->flags & SLAB_STORE_USER)
+ set_track(s, object, TRACK_ALLOC, addr);
+ trace(s, page, object, 1);
+ init_object(s, object, 1);
+ goto have_object;
+}
+
+void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
+{
+ return slab_alloc(s, gfpflags, -1, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kmem_cache_alloc);
+
+#ifdef CONFIG_NUMA
+void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node)
+{
+ return slab_alloc(s, gfpflags, node, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kmem_cache_alloc_node);
+#endif
+
+/*
+ * The fastpath only writes the cacheline of the page struct and the first
+ * cacheline of the object.
+ *
+ * We read the cpu_slab cacheline to check if the slab is the per cpu
+ * slab for this processor.
+ */
+static void slab_free(struct kmem_cache *s, struct page *page,
+ void *x, void *addr)
+{
+ void *prior;
+ void **object = (void *)x;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ slab_lock(page);
+
+ if (unlikely(SlabDebug(page)))
+ goto debug;
+checks_ok:
+ prior = object[page->offset] = page->freelist;
+ page->freelist = object;
+ page->inuse--;
+
+ if (unlikely(PageActive(page)))
+ /*
+ * Cpu slabs are never on partial lists and are
+ * never freed.
+ */
+ goto out_unlock;
+
+ if (unlikely(!page->inuse))
+ goto slab_empty;
+
+ /*
+ * Objects left in the slab. If it
+ * was not on the partial list before
+ * then add it.
+ */
+ if (unlikely(!prior))
+ add_partial(get_node(s, page_to_nid(page)), page);
+
+out_unlock:
+ slab_unlock(page);
+ local_irq_restore(flags);
+ return;
+
+slab_empty:
+ if (prior)
+ /*
+ * Slab still on the partial list.
+ */
+ remove_partial(s, page);
+
+ slab_unlock(page);
+ discard_slab(s, page);
+ local_irq_restore(flags);
+ return;
+
+debug:
+ if (!free_object_checks(s, page, x))
+ goto out_unlock;
+ if (!PageActive(page) && !page->freelist)
+ remove_full(s, page);
+ if (s->flags & SLAB_STORE_USER)
+ set_track(s, x, TRACK_FREE, addr);
+ trace(s, page, object, 0);
+ init_object(s, object, 0);
+ goto checks_ok;
+}
+
+void kmem_cache_free(struct kmem_cache *s, void *x)
+{
+ struct page *page;
+
+ page = virt_to_head_page(x);
+
+ slab_free(s, page, x, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kmem_cache_free);
+
+/* Figure out on which slab object the object resides */
+static struct page *get_object_page(const void *x)
+{
+ struct page *page = virt_to_head_page(x);
+
+ if (!PageSlab(page))
+ return NULL;
+
+ return page;
+}
+
+/*
+ * Object placement in a slab is made very easy because we always start at
+ * offset 0. If we tune the size of the object to the alignment then we can
+ * get the required alignment by putting one properly sized object after
+ * another.
+ *
+ * Notice that the allocation order determines the sizes of the per cpu
+ * caches. Each processor has always one slab available for allocations.
+ * Increasing the allocation order reduces the number of times that slabs
+ * must be moved on and off the partial lists and is therefore a factor in
+ * locking overhead.
+ */
+
+/*
+ * Mininum / Maximum order of slab pages. This influences locking overhead
+ * and slab fragmentation. A higher order reduces the number of partial slabs
+ * and increases the number of allocations possible without having to
+ * take the list_lock.
+ */
+static int slub_min_order;
+static int slub_max_order = DEFAULT_MAX_ORDER;
+static int slub_min_objects = DEFAULT_MIN_OBJECTS;
+
+/*
+ * Merge control. If this is set then no merging of slab caches will occur.
+ * (Could be removed. This was introduced to pacify the merge skeptics.)
+ */
+static int slub_nomerge;
+
+/*
+ * Calculate the order of allocation given an slab object size.
+ *
+ * The order of allocation has significant impact on performance and other
+ * system components. Generally order 0 allocations should be preferred since
+ * order 0 does not cause fragmentation in the page allocator. Larger objects
+ * be problematic to put into order 0 slabs because there may be too much
+ * unused space left. We go to a higher order if more than 1/8th of the slab
+ * would be wasted.
+ *
+ * In order to reach satisfactory performance we must ensure that a minimum
+ * number of objects is in one slab. Otherwise we may generate too much
+ * activity on the partial lists which requires taking the list_lock. This is
+ * less a concern for large slabs though which are rarely used.
+ *
+ * slub_max_order specifies the order where we begin to stop considering the
+ * number of objects in a slab as critical. If we reach slub_max_order then
+ * we try to keep the page order as low as possible. So we accept more waste
+ * of space in favor of a small page order.
+ *
+ * Higher order allocations also allow the placement of more objects in a
+ * slab and thereby reduce object handling overhead. If the user has
+ * requested a higher mininum order then we start with that one instead of
+ * the smallest order which will fit the object.
+ */
+static inline int slab_order(int size, int min_objects,
+ int max_order, int fract_leftover)
+{
+ int order;
+ int rem;
+
+ for (order = max(slub_min_order,
+ fls(min_objects * size - 1) - PAGE_SHIFT);
+ order <= max_order; order++) {
+
+ unsigned long slab_size = PAGE_SIZE << order;
+
+ if (slab_size < min_objects * size)
+ continue;
+
+ rem = slab_size % size;
+
+ if (rem <= slab_size / fract_leftover)
+ break;
+
+ }
+
+ return order;
+}
+
+static inline int calculate_order(int size)
+{
+ int order;
+ int min_objects;
+ int fraction;
+
+ /*
+ * Attempt to find best configuration for a slab. This
+ * works by first attempting to generate a layout with
+ * the best configuration and backing off gradually.
+ *
+ * First we reduce the acceptable waste in a slab. Then
+ * we reduce the minimum objects required in a slab.
+ */
+ min_objects = slub_min_objects;
+ while (min_objects > 1) {
+ fraction = 8;
+ while (fraction >= 4) {
+ order = slab_order(size, min_objects,
+ slub_max_order, fraction);
+ if (order <= slub_max_order)
+ return order;
+ fraction /= 2;
+ }
+ min_objects /= 2;
+ }
+
+ /*
+ * We were unable to place multiple objects in a slab. Now
+ * lets see if we can place a single object there.
+ */
+ order = slab_order(size, 1, slub_max_order, 1);
+ if (order <= slub_max_order)
+ return order;
+
+ /*
+ * Doh this slab cannot be placed using slub_max_order.
+ */
+ order = slab_order(size, 1, MAX_ORDER, 1);
+ if (order <= MAX_ORDER)
+ return order;
+ return -ENOSYS;
+}
+
+/*
+ * Figure out what the alignment of the objects will be.
+ */
+static unsigned long calculate_alignment(unsigned long flags,
+ unsigned long align, unsigned long size)
+{
+ /*
+ * If the user wants hardware cache aligned objects then
+ * follow that suggestion if the object is sufficiently
+ * large.
+ *
+ * The hardware cache alignment cannot override the
+ * specified alignment though. If that is greater
+ * then use it.
+ */
+ if ((flags & SLAB_HWCACHE_ALIGN) &&
+ size > cache_line_size() / 2)
+ return max_t(unsigned long, align, cache_line_size());
+
+ if (align < ARCH_SLAB_MINALIGN)
+ return ARCH_SLAB_MINALIGN;
+
+ return ALIGN(align, sizeof(void *));
+}
+
+static void init_kmem_cache_node(struct kmem_cache_node *n)
+{
+ n->nr_partial = 0;
+ atomic_long_set(&n->nr_slabs, 0);
+ spin_lock_init(&n->list_lock);
+ INIT_LIST_HEAD(&n->partial);
+ INIT_LIST_HEAD(&n->full);
+}
+
+#ifdef CONFIG_NUMA
+/*
+ * No kmalloc_node yet so do it by hand. We know that this is the first
+ * slab on the node for this slabcache. There are no concurrent accesses
+ * possible.
+ *
+ * Note that this function only works on the kmalloc_node_cache
+ * when allocating for the kmalloc_node_cache.
+ */
+static struct kmem_cache_node * __init early_kmem_cache_node_alloc(gfp_t gfpflags,
+ int node)
+{
+ struct page *page;
+ struct kmem_cache_node *n;
+
+ BUG_ON(kmalloc_caches->size < sizeof(struct kmem_cache_node));
+
+ page = new_slab(kmalloc_caches, gfpflags | GFP_THISNODE, node);
+ /* new_slab() disables interupts */
+ local_irq_enable();
+
+ BUG_ON(!page);
+ n = page->freelist;
+ BUG_ON(!n);
+ page->freelist = get_freepointer(kmalloc_caches, n);
+ page->inuse++;
+ kmalloc_caches->node[node] = n;
+ init_object(kmalloc_caches, n, 1);
+ init_kmem_cache_node(n);
+ atomic_long_inc(&n->nr_slabs);
+ add_partial(n, page);
+ return n;
+}
+
+static void free_kmem_cache_nodes(struct kmem_cache *s)
+{
+ int node;
+
+ for_each_online_node(node) {
+ struct kmem_cache_node *n = s->node[node];
+ if (n && n != &s->local_node)
+ kmem_cache_free(kmalloc_caches, n);
+ s->node[node] = NULL;
+ }
+}
+
+static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
+{
+ int node;
+ int local_node;
+
+ if (slab_state >= UP)
+ local_node = page_to_nid(virt_to_page(s));
+ else
+ local_node = 0;
+
+ for_each_online_node(node) {
+ struct kmem_cache_node *n;
+
+ if (local_node == node)
+ n = &s->local_node;
+ else {
+ if (slab_state == DOWN) {
+ n = early_kmem_cache_node_alloc(gfpflags,
+ node);
+ continue;
+ }
+ n = kmem_cache_alloc_node(kmalloc_caches,
+ gfpflags, node);
+
+ if (!n) {
+ free_kmem_cache_nodes(s);
+ return 0;
+ }
+
+ }
+ s->node[node] = n;
+ init_kmem_cache_node(n);
+ }
+ return 1;
+}
+#else
+static void free_kmem_cache_nodes(struct kmem_cache *s)
+{
+}
+
+static int init_kmem_cache_nodes(struct kmem_cache *s, gfp_t gfpflags)
+{
+ init_kmem_cache_node(&s->local_node);
+ return 1;
+}
+#endif
+
+/*
+ * calculate_sizes() determines the order and the distribution of data within
+ * a slab object.
+ */
+static int calculate_sizes(struct kmem_cache *s)
+{
+ unsigned long flags = s->flags;
+ unsigned long size = s->objsize;
+ unsigned long align = s->align;
+
+ /*
+ * Determine if we can poison the object itself. If the user of
+ * the slab may touch the object after free or before allocation
+ * then we should never poison the object itself.
+ */
+ if ((flags & SLAB_POISON) && !(flags & SLAB_DESTROY_BY_RCU) &&
+ !s->ctor && !s->dtor)
+ s->flags |= __OBJECT_POISON;
+ else
+ s->flags &= ~__OBJECT_POISON;
+
+ /*
+ * Round up object size to the next word boundary. We can only
+ * place the free pointer at word boundaries and this determines
+ * the possible location of the free pointer.
+ */
+ size = ALIGN(size, sizeof(void *));
+
+#ifdef CONFIG_SLUB_DEBUG
+ /*
+ * If we are Redzoning then check if there is some space between the
+ * end of the object and the free pointer. If not then add an
+ * additional word to have some bytes to store Redzone information.
+ */
+ if ((flags & SLAB_RED_ZONE) && size == s->objsize)
+ size += sizeof(void *);
+#endif
+
+ /*
+ * With that we have determined the number of bytes in actual use
+ * by the object. This is the potential offset to the free pointer.
+ */
+ s->inuse = size;
+
+#ifdef CONFIG_SLUB_DEBUG
+ if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) ||
+ s->ctor || s->dtor)) {
+ /*
+ * Relocate free pointer after the object if it is not
+ * permitted to overwrite the first word of the object on
+ * kmem_cache_free.
+ *
+ * This is the case if we do RCU, have a constructor or
+ * destructor or are poisoning the objects.
+ */
+ s->offset = size;
+ size += sizeof(void *);
+ }
+
+ if (flags & SLAB_STORE_USER)
+ /*
+ * Need to store information about allocs and frees after
+ * the object.
+ */
+ size += 2 * sizeof(struct track);
+
+ if (flags & SLAB_RED_ZONE)
+ /*
+ * Add some empty padding so that we can catch
+ * overwrites from earlier objects rather than let
+ * tracking information or the free pointer be
+ * corrupted if an user writes before the start
+ * of the object.
+ */
+ size += sizeof(void *);
+#endif
+
+ /*
+ * Determine the alignment based on various parameters that the
+ * user specified and the dynamic determination of cache line size
+ * on bootup.
+ */
+ align = calculate_alignment(flags, align, s->objsize);
+
+ /*
+ * SLUB stores one object immediately after another beginning from
+ * offset 0. In order to align the objects we have to simply size
+ * each object to conform to the alignment.
+ */
+ size = ALIGN(size, align);
+ s->size = size;
+
+ s->order = calculate_order(size);
+ if (s->order < 0)
+ return 0;
+
+ /*
+ * Determine the number of objects per slab
+ */
+ s->objects = (PAGE_SIZE << s->order) / size;
+
+ /*
+ * Verify that the number of objects is within permitted limits.
+ * The page->inuse field is only 16 bit wide! So we cannot have
+ * more than 64k objects per slab.
+ */
+ if (!s->objects || s->objects > 65535)
+ return 0;
+ return 1;
+
+}
+
+static int kmem_cache_open(struct kmem_cache *s, gfp_t gfpflags,
+ const char *name, size_t size,
+ size_t align, unsigned long flags,
+ void (*ctor)(void *, struct kmem_cache *, unsigned long),
+ void (*dtor)(void *, struct kmem_cache *, unsigned long))
+{
+ memset(s, 0, kmem_size);
+ s->name = name;
+ s->ctor = ctor;
+ s->dtor = dtor;
+ s->objsize = size;
+ s->flags = flags;
+ s->align = align;
+ kmem_cache_open_debug_check(s);
+
+ if (!calculate_sizes(s))
+ goto error;
+
+ s->refcount = 1;
+#ifdef CONFIG_NUMA
+ s->defrag_ratio = 100;
+#endif
+
+ if (init_kmem_cache_nodes(s, gfpflags & ~SLUB_DMA))
+ return 1;
+error:
+ if (flags & SLAB_PANIC)
+ panic("Cannot create slab %s size=%lu realsize=%u "
+ "order=%u offset=%u flags=%lx\n",
+ s->name, (unsigned long)size, s->size, s->order,
+ s->offset, flags);
+ return 0;
+}
+EXPORT_SYMBOL(kmem_cache_open);
+
+/*
+ * Check if a given pointer is valid
+ */
+int kmem_ptr_validate(struct kmem_cache *s, const void *object)
+{
+ struct page * page;
+
+ page = get_object_page(object);
+
+ if (!page || s != page->slab)
+ /* No slab or wrong slab */
+ return 0;
+
+ if (!check_valid_pointer(s, page, object))
+ return 0;
+
+ /*
+ * We could also check if the object is on the slabs freelist.
+ * But this would be too expensive and it seems that the main
+ * purpose of kmem_ptr_valid is to check if the object belongs
+ * to a certain slab.
+ */
+ return 1;
+}
+EXPORT_SYMBOL(kmem_ptr_validate);
+
+/*
+ * Determine the size of a slab object
+ */
+unsigned int kmem_cache_size(struct kmem_cache *s)
+{
+ return s->objsize;
+}
+EXPORT_SYMBOL(kmem_cache_size);
+
+const char *kmem_cache_name(struct kmem_cache *s)
+{
+ return s->name;
+}
+EXPORT_SYMBOL(kmem_cache_name);
+
+/*
+ * Attempt to free all slabs on a node. Return the number of slabs we
+ * were unable to free.
+ */
+static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
+ struct list_head *list)
+{
+ int slabs_inuse = 0;
+ unsigned long flags;
+ struct page *page, *h;
+
+ spin_lock_irqsave(&n->list_lock, flags);
+ list_for_each_entry_safe(page, h, list, lru)
+ if (!page->inuse) {
+ list_del(&page->lru);
+ discard_slab(s, page);
+ } else
+ slabs_inuse++;
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ return slabs_inuse;
+}
+
+/*
+ * Release all resources used by a slab cache.
+ */
+static int kmem_cache_close(struct kmem_cache *s)
+{
+ int node;
+
+ flush_all(s);
+
+ /* Attempt to free all objects */
+ for_each_online_node(node) {
+ struct kmem_cache_node *n = get_node(s, node);
+
+ n->nr_partial -= free_list(s, n, &n->partial);
+ if (atomic_long_read(&n->nr_slabs))
+ return 1;
+ }
+ free_kmem_cache_nodes(s);
+ return 0;
+}
+
+/*
+ * Close a cache and release the kmem_cache structure
+ * (must be used for caches created using kmem_cache_create)
+ */
+void kmem_cache_destroy(struct kmem_cache *s)
+{
+ down_write(&slub_lock);
+ s->refcount--;
+ if (!s->refcount) {
+ list_del(&s->list);
+ if (kmem_cache_close(s))
+ WARN_ON(1);
+ sysfs_slab_remove(s);
+ kfree(s);
+ }
+ up_write(&slub_lock);
+}
+EXPORT_SYMBOL(kmem_cache_destroy);
+
+/********************************************************************
+ * Kmalloc subsystem
+ *******************************************************************/
+
+struct kmem_cache kmalloc_caches[KMALLOC_SHIFT_HIGH + 1] __cacheline_aligned;
+EXPORT_SYMBOL(kmalloc_caches);
+
+#ifdef CONFIG_ZONE_DMA
+static struct kmem_cache *kmalloc_caches_dma[KMALLOC_SHIFT_HIGH + 1];
+#endif
+
+static int __init setup_slub_min_order(char *str)
+{
+ get_option (&str, &slub_min_order);
+
+ return 1;
+}
+
+__setup("slub_min_order=", setup_slub_min_order);
+
+static int __init setup_slub_max_order(char *str)
+{
+ get_option (&str, &slub_max_order);
+
+ return 1;
+}
+
+__setup("slub_max_order=", setup_slub_max_order);
+
+static int __init setup_slub_min_objects(char *str)
+{
+ get_option (&str, &slub_min_objects);
+
+ return 1;
+}
+
+__setup("slub_min_objects=", setup_slub_min_objects);
+
+static int __init setup_slub_nomerge(char *str)
+{
+ slub_nomerge = 1;
+ return 1;
+}
+
+__setup("slub_nomerge", setup_slub_nomerge);
+
+static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s,
+ const char *name, int size, gfp_t gfp_flags)
+{
+ unsigned int flags = 0;
+
+ if (gfp_flags & SLUB_DMA)
+ flags = SLAB_CACHE_DMA;
+
+ down_write(&slub_lock);
+ if (!kmem_cache_open(s, gfp_flags, name, size, ARCH_KMALLOC_MINALIGN,
+ flags, NULL, NULL))
+ goto panic;
+
+ list_add(&s->list, &slab_caches);
+ up_write(&slub_lock);
+ if (sysfs_slab_add(s))
+ goto panic;
+ return s;
+
+panic:
+ panic("Creation of kmalloc slab %s size=%d failed.\n", name, size);
+}
+
+static struct kmem_cache *get_slab(size_t size, gfp_t flags)
+{
+ int index = kmalloc_index(size);
+
+ if (!index)
+ return NULL;
+
+ /* Allocation too large? */
+ BUG_ON(index < 0);
+
+#ifdef CONFIG_ZONE_DMA
+ if ((flags & SLUB_DMA)) {
+ struct kmem_cache *s;
+ struct kmem_cache *x;
+ char *text;
+ size_t realsize;
+
+ s = kmalloc_caches_dma[index];
+ if (s)
+ return s;
+
+ /* Dynamically create dma cache */
+ x = kmalloc(kmem_size, flags & ~SLUB_DMA);
+ if (!x)
+ panic("Unable to allocate memory for dma cache\n");
+
+ if (index <= KMALLOC_SHIFT_HIGH)
+ realsize = 1 << index;
+ else {
+ if (index == 1)
+ realsize = 96;
+ else
+ realsize = 192;
+ }
+
+ text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d",
+ (unsigned int)realsize);
+ s = create_kmalloc_cache(x, text, realsize, flags);
+ kmalloc_caches_dma[index] = s;
+ return s;
+ }
+#endif
+ return &kmalloc_caches[index];
+}
+
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ struct kmem_cache *s = get_slab(size, flags);
+
+ if (s)
+ return slab_alloc(s, flags, -1, __builtin_return_address(0));
+ return NULL;
+}
+EXPORT_SYMBOL(__kmalloc);
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ struct kmem_cache *s = get_slab(size, flags);
+
+ if (s)
+ return slab_alloc(s, flags, node, __builtin_return_address(0));
+ return NULL;
+}
+EXPORT_SYMBOL(__kmalloc_node);
+#endif
+
+size_t ksize(const void *object)
+{
+ struct page *page = get_object_page(object);
+ struct kmem_cache *s;
+
+ BUG_ON(!page);
+ s = page->slab;
+ BUG_ON(!s);
+
+ /*
+ * Debugging requires use of the padding between object
+ * and whatever may come after it.
+ */
+ if (s->flags & (SLAB_RED_ZONE | SLAB_POISON))
+ return s->objsize;
+
+ /*
+ * If we have the need to store the freelist pointer
+ * back there or track user information then we can
+ * only use the space before that information.
+ */
+ if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER))
+ return s->inuse;
+
+ /*
+ * Else we can use all the padding etc for the allocation
+ */
+ return s->size;
+}
+EXPORT_SYMBOL(ksize);
+
+void kfree(const void *x)
+{
+ struct kmem_cache *s;
+ struct page *page;
+
+ if (!x)
+ return;
+
+ page = virt_to_head_page(x);
+ s = page->slab;
+
+ slab_free(s, page, (void *)x, __builtin_return_address(0));
+}
+EXPORT_SYMBOL(kfree);
+
+/*
+ * kmem_cache_shrink removes empty slabs from the partial lists and sorts
+ * the remaining slabs by the number of items in use. The slabs with the
+ * most items in use come first. New allocations will then fill those up
+ * and thus they can be removed from the partial lists.
+ *
+ * The slabs with the least items are placed last. This results in them
+ * being allocated from last increasing the chance that the last objects
+ * are freed in them.
+ */
+int kmem_cache_shrink(struct kmem_cache *s)
+{
+ int node;
+ int i;
+ struct kmem_cache_node *n;
+ struct page *page;
+ struct page *t;
+ struct list_head *slabs_by_inuse =
+ kmalloc(sizeof(struct list_head) * s->objects, GFP_KERNEL);
+ unsigned long flags;
+
+ if (!slabs_by_inuse)
+ return -ENOMEM;
+
+ flush_all(s);
+ for_each_online_node(node) {
+ n = get_node(s, node);
+
+ if (!n->nr_partial)
+ continue;
+
+ for (i = 0; i < s->objects; i++)
+ INIT_LIST_HEAD(slabs_by_inuse + i);
+
+ spin_lock_irqsave(&n->list_lock, flags);
+
+ /*
+ * Build lists indexed by the items in use in each slab.
+ *
+ * Note that concurrent frees may occur while we hold the
+ * list_lock. page->inuse here is the upper limit.
+ */
+ list_for_each_entry_safe(page, t, &n->partial, lru) {
+ if (!page->inuse && slab_trylock(page)) {
+ /*
+ * Must hold slab lock here because slab_free
+ * may have freed the last object and be
+ * waiting to release the slab.
+ */
+ list_del(&page->lru);
+ n->nr_partial--;
+ slab_unlock(page);
+ discard_slab(s, page);
+ } else {
+ if (n->nr_partial > MAX_PARTIAL)
+ list_move(&page->lru,
+ slabs_by_inuse + page->inuse);
+ }
+ }
+
+ if (n->nr_partial <= MAX_PARTIAL)
+ goto out;
+
+ /*
+ * Rebuild the partial list with the slabs filled up most
+ * first and the least used slabs at the end.
+ */
+ for (i = s->objects - 1; i >= 0; i--)
+ list_splice(slabs_by_inuse + i, n->partial.prev);
+
+ out:
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ }
+
+ kfree(slabs_by_inuse);
+ return 0;
+}
+EXPORT_SYMBOL(kmem_cache_shrink);
+
+/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes. If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc(). If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+ size_t ks;
+
+ if (unlikely(!p))
+ return kmalloc(new_size, flags);
+
+ if (unlikely(!new_size)) {
+ kfree(p);
+ return NULL;
+ }
+
+ ks = ksize(p);
+ if (ks >= new_size)
+ return (void *)p;
+
+ ret = kmalloc(new_size, flags);
+ if (ret) {
+ memcpy(ret, p, min(new_size, ks));
+ kfree(p);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
+/********************************************************************
+ * Basic setup of slabs
+ *******************************************************************/
+
+void __init kmem_cache_init(void)
+{
+ int i;
+
+#ifdef CONFIG_NUMA
+ /*
+ * Must first have the slab cache available for the allocations of the
+ * struct kmem_cache_node's. There is special bootstrap code in
+ * kmem_cache_open for slab_state == DOWN.
+ */
+ create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
+ sizeof(struct kmem_cache_node), GFP_KERNEL);
+#endif
+
+ /* Able to allocate the per node structures */
+ slab_state = PARTIAL;
+
+ /* Caches that are not of the two-to-the-power-of size */
+ create_kmalloc_cache(&kmalloc_caches[1],
+ "kmalloc-96", 96, GFP_KERNEL);
+ create_kmalloc_cache(&kmalloc_caches[2],
+ "kmalloc-192", 192, GFP_KERNEL);
+
+ for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
+ create_kmalloc_cache(&kmalloc_caches[i],
+ "kmalloc", 1 << i, GFP_KERNEL);
+
+ slab_state = UP;
+
+ /* Provide the correct kmalloc names now that the caches are up */
+ for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++)
+ kmalloc_caches[i]. name =
+ kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i);
+
+#ifdef CONFIG_SMP
+ register_cpu_notifier(&slab_notifier);
+#endif
+
+ if (nr_cpu_ids) /* Remove when nr_cpu_ids is fixed upstream ! */
+ kmem_size = offsetof(struct kmem_cache, cpu_slab)
+ + nr_cpu_ids * sizeof(struct page *);
+
+ printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
+ " Processors=%d, Nodes=%d\n",
+ KMALLOC_SHIFT_HIGH, cache_line_size(),
+ slub_min_order, slub_max_order, slub_min_objects,
+ nr_cpu_ids, nr_node_ids);
+}
+
+/*
+ * Find a mergeable slab cache
+ */
+static int slab_unmergeable(struct kmem_cache *s)
+{
+ if (slub_nomerge || (s->flags & SLUB_NEVER_MERGE))
+ return 1;
+
+ if (s->ctor || s->dtor)
+ return 1;
+
+ return 0;
+}
+
+static struct kmem_cache *find_mergeable(size_t size,
+ size_t align, unsigned long flags,
+ void (*ctor)(void *, struct kmem_cache *, unsigned long),
+ void (*dtor)(void *, struct kmem_cache *, unsigned long))
+{
+ struct list_head *h;
+
+ if (slub_nomerge || (flags & SLUB_NEVER_MERGE))
+ return NULL;
+
+ if (ctor || dtor)
+ return NULL;
+
+ size = ALIGN(size, sizeof(void *));
+ align = calculate_alignment(flags, align, size);
+ size = ALIGN(size, align);
+
+ list_for_each(h, &slab_caches) {
+ struct kmem_cache *s =
+ container_of(h, struct kmem_cache, list);
+
+ if (slab_unmergeable(s))
+ continue;
+
+ if (size > s->size)
+ continue;
+
+ if (((flags | slub_debug) & SLUB_MERGE_SAME) !=
+ (s->flags & SLUB_MERGE_SAME))
+ continue;
+ /*
+ * Check if alignment is compatible.
+ * Courtesy of Adrian Drzewiecki
+ */
+ if ((s->size & ~(align -1)) != s->size)
+ continue;
+
+ if (s->size - size >= sizeof(void *))
+ continue;
+
+ return s;
+ }
+ return NULL;
+}
+
+struct kmem_cache *kmem_cache_create(const char *name, size_t size,
+ size_t align, unsigned long flags,
+ void (*ctor)(void *, struct kmem_cache *, unsigned long),
+ void (*dtor)(void *, struct kmem_cache *, unsigned long))
+{
+ struct kmem_cache *s;
+
+ down_write(&slub_lock);
+ s = find_mergeable(size, align, flags, dtor, ctor);
+ if (s) {
+ s->refcount++;
+ /*
+ * Adjust the object sizes so that we clear
+ * the complete object on kzalloc.
+ */
+ s->objsize = max(s->objsize, (int)size);
+ s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
+ if (sysfs_slab_alias(s, name))
+ goto err;
+ } else {
+ s = kmalloc(kmem_size, GFP_KERNEL);
+ if (s && kmem_cache_open(s, GFP_KERNEL, name,
+ size, align, flags, ctor, dtor)) {
+ if (sysfs_slab_add(s)) {
+ kfree(s);
+ goto err;
+ }
+ list_add(&s->list, &slab_caches);
+ } else
+ kfree(s);
+ }
+ up_write(&slub_lock);
+ return s;
+
+err:
+ up_write(&slub_lock);
+ if (flags & SLAB_PANIC)
+ panic("Cannot create slabcache %s\n", name);
+ else
+ s = NULL;
+ return s;
+}
+EXPORT_SYMBOL(kmem_cache_create);
+
+void *kmem_cache_zalloc(struct kmem_cache *s, gfp_t flags)
+{
+ void *x;
+
+ x = slab_alloc(s, flags, -1, __builtin_return_address(0));
+ if (x)
+ memset(x, 0, s->objsize);
+ return x;
+}
+EXPORT_SYMBOL(kmem_cache_zalloc);
+
+#ifdef CONFIG_SMP
+static void for_all_slabs(void (*func)(struct kmem_cache *, int), int cpu)
+{
+ struct list_head *h;
+
+ down_read(&slub_lock);
+ list_for_each(h, &slab_caches) {
+ struct kmem_cache *s =
+ container_of(h, struct kmem_cache, list);
+
+ func(s, cpu);
+ }
+ up_read(&slub_lock);
+}
+
+/*
+ * Use the cpu notifier to insure that the cpu slabs are flushed when
+ * necessary.
+ */
+static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ long cpu = (long)hcpu;
+
+ switch (action) {
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ for_all_slabs(__flush_cpu_slab, cpu);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata slab_notifier =
+ { &slab_cpuup_callback, NULL, 0 };
+
+#endif
+
+void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
+{
+ struct kmem_cache *s = get_slab(size, gfpflags);
+
+ if (!s)
+ return NULL;
+
+ return slab_alloc(s, gfpflags, -1, caller);
+}
+
+void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
+ int node, void *caller)
+{
+ struct kmem_cache *s = get_slab(size, gfpflags);
+
+ if (!s)
+ return NULL;
+
+ return slab_alloc(s, gfpflags, node, caller);
+}
+
+#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
+static int validate_slab(struct kmem_cache *s, struct page *page)
+{
+ void *p;
+ void *addr = page_address(page);
+ DECLARE_BITMAP(map, s->objects);
+
+ if (!check_slab(s, page) ||
+ !on_freelist(s, page, NULL))
+ return 0;
+
+ /* Now we know that a valid freelist exists */
+ bitmap_zero(map, s->objects);
+
+ for_each_free_object(p, s, page->freelist) {
+ set_bit(slab_index(p, s, addr), map);
+ if (!check_object(s, page, p, 0))
+ return 0;
+ }
+
+ for_each_object(p, s, addr)
+ if (!test_bit(slab_index(p, s, addr), map))
+ if (!check_object(s, page, p, 1))
+ return 0;
+ return 1;
+}
+
+static void validate_slab_slab(struct kmem_cache *s, struct page *page)
+{
+ if (slab_trylock(page)) {
+ validate_slab(s, page);
+ slab_unlock(page);
+ } else
+ printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
+ s->name, page);
+
+ if (s->flags & DEBUG_DEFAULT_FLAGS) {
+ if (!SlabDebug(page))
+ printk(KERN_ERR "SLUB %s: SlabDebug not set "
+ "on slab 0x%p\n", s->name, page);
+ } else {
+ if (SlabDebug(page))
+ printk(KERN_ERR "SLUB %s: SlabDebug set on "
+ "slab 0x%p\n", s->name, page);
+ }
+}
+
+static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
+{
+ unsigned long count = 0;
+ struct page *page;
+ unsigned long flags;
+
+ spin_lock_irqsave(&n->list_lock, flags);
+
+ list_for_each_entry(page, &n->partial, lru) {
+ validate_slab_slab(s, page);
+ count++;
+ }
+ if (count != n->nr_partial)
+ printk(KERN_ERR "SLUB %s: %ld partial slabs counted but "
+ "counter=%ld\n", s->name, count, n->nr_partial);
+
+ if (!(s->flags & SLAB_STORE_USER))
+ goto out;
+
+ list_for_each_entry(page, &n->full, lru) {
+ validate_slab_slab(s, page);
+ count++;
+ }
+ if (count != atomic_long_read(&n->nr_slabs))
+ printk(KERN_ERR "SLUB: %s %ld slabs counted but "
+ "counter=%ld\n", s->name, count,
+ atomic_long_read(&n->nr_slabs));
+
+out:
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ return count;
+}
+
+static unsigned long validate_slab_cache(struct kmem_cache *s)
+{
+ int node;
+ unsigned long count = 0;
+
+ flush_all(s);
+ for_each_online_node(node) {
+ struct kmem_cache_node *n = get_node(s, node);
+
+ count += validate_slab_node(s, n);
+ }
+ return count;
+}
+
+#ifdef SLUB_RESILIENCY_TEST
+static void resiliency_test(void)
+{
+ u8 *p;
+
+ printk(KERN_ERR "SLUB resiliency testing\n");
+ printk(KERN_ERR "-----------------------\n");
+ printk(KERN_ERR "A. Corruption after allocation\n");
+
+ p = kzalloc(16, GFP_KERNEL);
+ p[16] = 0x12;
+ printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
+ " 0x12->0x%p\n\n", p + 16);
+
+ validate_slab_cache(kmalloc_caches + 4);
+
+ /* Hmmm... The next two are dangerous */
+ p = kzalloc(32, GFP_KERNEL);
+ p[32 + sizeof(void *)] = 0x34;
+ printk(KERN_ERR "\n2. kmalloc-32: Clobber next pointer/next slab"
+ " 0x34 -> -0x%p\n", p);
+ printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+
+ validate_slab_cache(kmalloc_caches + 5);
+ p = kzalloc(64, GFP_KERNEL);
+ p += 64 + (get_cycles() & 0xff) * sizeof(void *);
+ *p = 0x56;
+ printk(KERN_ERR "\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n",
+ p);
+ printk(KERN_ERR "If allocated object is overwritten then not detectable\n\n");
+ validate_slab_cache(kmalloc_caches + 6);
+
+ printk(KERN_ERR "\nB. Corruption after free\n");
+ p = kzalloc(128, GFP_KERNEL);
+ kfree(p);
+ *p = 0x78;
+ printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
+ validate_slab_cache(kmalloc_caches + 7);
+
+ p = kzalloc(256, GFP_KERNEL);
+ kfree(p);
+ p[50] = 0x9a;
+ printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p);
+ validate_slab_cache(kmalloc_caches + 8);
+
+ p = kzalloc(512, GFP_KERNEL);
+ kfree(p);
+ p[512] = 0xab;
+ printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
+ validate_slab_cache(kmalloc_caches + 9);
+}
+#else
+static void resiliency_test(void) {};
+#endif
+
+/*
+ * Generate lists of code addresses where slabcache objects are allocated
+ * and freed.
+ */
+
+struct location {
+ unsigned long count;
+ void *addr;
+ long long sum_time;
+ long min_time;
+ long max_time;
+ long min_pid;
+ long max_pid;
+ cpumask_t cpus;
+ nodemask_t nodes;
+};
+
+struct loc_track {
+ unsigned long max;
+ unsigned long count;
+ struct location *loc;
+};
+
+static void free_loc_track(struct loc_track *t)
+{
+ if (t->max)
+ free_pages((unsigned long)t->loc,
+ get_order(sizeof(struct location) * t->max));
+}
+
+static int alloc_loc_track(struct loc_track *t, unsigned long max)
+{
+ struct location *l;
+ int order;
+
+ if (!max)
+ max = PAGE_SIZE / sizeof(struct location);
+
+ order = get_order(sizeof(struct location) * max);
+
+ l = (void *)__get_free_pages(GFP_KERNEL, order);
+
+ if (!l)
+ return 0;
+
+ if (t->count) {
+ memcpy(l, t->loc, sizeof(struct location) * t->count);
+ free_loc_track(t);
+ }
+ t->max = max;
+ t->loc = l;
+ return 1;
+}
+
+static int add_location(struct loc_track *t, struct kmem_cache *s,
+ const struct track *track)
+{
+ long start, end, pos;
+ struct location *l;
+ void *caddr;
+ unsigned long age = jiffies - track->when;
+
+ start = -1;
+ end = t->count;
+
+ for ( ; ; ) {
+ pos = start + (end - start + 1) / 2;
+
+ /*
+ * There is nothing at "end". If we end up there
+ * we need to add something to before end.
+ */
+ if (pos == end)
+ break;
+
+ caddr = t->loc[pos].addr;
+ if (track->addr == caddr) {
+
+ l = &t->loc[pos];
+ l->count++;
+ if (track->when) {
+ l->sum_time += age;
+ if (age < l->min_time)
+ l->min_time = age;
+ if (age > l->max_time)
+ l->max_time = age;
+
+ if (track->pid < l->min_pid)
+ l->min_pid = track->pid;
+ if (track->pid > l->max_pid)
+ l->max_pid = track->pid;
+
+ cpu_set(track->cpu, l->cpus);
+ }
+ node_set(page_to_nid(virt_to_page(track)), l->nodes);
+ return 1;
+ }
+
+ if (track->addr < caddr)
+ end = pos;
+ else
+ start = pos;
+ }
+
+ /*
+ * Not found. Insert new tracking element.
+ */
+ if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max))
+ return 0;
+
+ l = t->loc + pos;
+ if (pos < t->count)
+ memmove(l + 1, l,
+ (t->count - pos) * sizeof(struct location));
+ t->count++;
+ l->count = 1;
+ l->addr = track->addr;
+ l->sum_time = age;
+ l->min_time = age;
+ l->max_time = age;
+ l->min_pid = track->pid;
+ l->max_pid = track->pid;
+ cpus_clear(l->cpus);
+ cpu_set(track->cpu, l->cpus);
+ nodes_clear(l->nodes);
+ node_set(page_to_nid(virt_to_page(track)), l->nodes);
+ return 1;
+}
+
+static void process_slab(struct loc_track *t, struct kmem_cache *s,
+ struct page *page, enum track_item alloc)
+{
+ void *addr = page_address(page);
+ DECLARE_BITMAP(map, s->objects);
+ void *p;
+
+ bitmap_zero(map, s->objects);
+ for_each_free_object(p, s, page->freelist)
+ set_bit(slab_index(p, s, addr), map);
+
+ for_each_object(p, s, addr)
+ if (!test_bit(slab_index(p, s, addr), map))
+ add_location(t, s, get_track(s, p, alloc));
+}
+
+static int list_locations(struct kmem_cache *s, char *buf,
+ enum track_item alloc)
+{
+ int n = 0;
+ unsigned long i;
+ struct loc_track t;
+ int node;
+
+ t.count = 0;
+ t.max = 0;
+
+ /* Push back cpu slabs */
+ flush_all(s);
+
+ for_each_online_node(node) {
+ struct kmem_cache_node *n = get_node(s, node);
+ unsigned long flags;
+ struct page *page;
+
+ if (!atomic_read(&n->nr_slabs))
+ continue;
+
+ spin_lock_irqsave(&n->list_lock, flags);
+ list_for_each_entry(page, &n->partial, lru)
+ process_slab(&t, s, page, alloc);
+ list_for_each_entry(page, &n->full, lru)
+ process_slab(&t, s, page, alloc);
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ }
+
+ for (i = 0; i < t.count; i++) {
+ struct location *l = &t.loc[i];
+
+ if (n > PAGE_SIZE - 100)
+ break;
+ n += sprintf(buf + n, "%7ld ", l->count);
+
+ if (l->addr)
+ n += sprint_symbol(buf + n, (unsigned long)l->addr);
+ else
+ n += sprintf(buf + n, "<not-available>");
+
+ if (l->sum_time != l->min_time) {
+ unsigned long remainder;
+
+ n += sprintf(buf + n, " age=%ld/%ld/%ld",
+ l->min_time,
+ div_long_long_rem(l->sum_time, l->count, &remainder),
+ l->max_time);
+ } else
+ n += sprintf(buf + n, " age=%ld",
+ l->min_time);
+
+ if (l->min_pid != l->max_pid)
+ n += sprintf(buf + n, " pid=%ld-%ld",
+ l->min_pid, l->max_pid);
+ else
+ n += sprintf(buf + n, " pid=%ld",
+ l->min_pid);
+
+ if (num_online_cpus() > 1 && !cpus_empty(l->cpus)) {
+ n += sprintf(buf + n, " cpus=");
+ n += cpulist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+ l->cpus);
+ }
+
+ if (num_online_nodes() > 1 && !nodes_empty(l->nodes)) {
+ n += sprintf(buf + n, " nodes=");
+ n += nodelist_scnprintf(buf + n, PAGE_SIZE - n - 50,
+ l->nodes);
+ }
+
+ n += sprintf(buf + n, "\n");
+ }
+
+ free_loc_track(&t);
+ if (!t.count)
+ n += sprintf(buf, "No data\n");
+ return n;
+}
+
+static unsigned long count_partial(struct kmem_cache_node *n)
+{
+ unsigned long flags;
+ unsigned long x = 0;
+ struct page *page;
+
+ spin_lock_irqsave(&n->list_lock, flags);
+ list_for_each_entry(page, &n->partial, lru)
+ x += page->inuse;
+ spin_unlock_irqrestore(&n->list_lock, flags);
+ return x;
+}
+
+enum slab_stat_type {
+ SL_FULL,
+ SL_PARTIAL,
+ SL_CPU,
+ SL_OBJECTS
+};
+
+#define SO_FULL (1 << SL_FULL)
+#define SO_PARTIAL (1 << SL_PARTIAL)
+#define SO_CPU (1 << SL_CPU)
+#define SO_OBJECTS (1 << SL_OBJECTS)
+
+static unsigned long slab_objects(struct kmem_cache *s,
+ char *buf, unsigned long flags)
+{
+ unsigned long total = 0;
+ int cpu;
+ int node;
+ int x;
+ unsigned long *nodes;
+ unsigned long *per_cpu;
+
+ nodes = kzalloc(2 * sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
+ per_cpu = nodes + nr_node_ids;
+
+ for_each_possible_cpu(cpu) {
+ struct page *page = s->cpu_slab[cpu];
+ int node;
+
+ if (page) {
+ node = page_to_nid(page);
+ if (flags & SO_CPU) {
+ int x = 0;
+
+ if (flags & SO_OBJECTS)
+ x = page->inuse;
+ else
+ x = 1;
+ total += x;
+ nodes[node] += x;
+ }
+ per_cpu[node]++;
+ }
+ }
+
+ for_each_online_node(node) {
+ struct kmem_cache_node *n = get_node(s, node);
+
+ if (flags & SO_PARTIAL) {
+ if (flags & SO_OBJECTS)
+ x = count_partial(n);
+ else
+ x = n->nr_partial;
+ total += x;
+ nodes[node] += x;
+ }
+
+ if (flags & SO_FULL) {
+ int full_slabs = atomic_read(&n->nr_slabs)
+ - per_cpu[node]
+ - n->nr_partial;
+
+ if (flags & SO_OBJECTS)
+ x = full_slabs * s->objects;
+ else
+ x = full_slabs;
+ total += x;
+ nodes[node] += x;
+ }
+ }
+
+ x = sprintf(buf, "%lu", total);
+#ifdef CONFIG_NUMA
+ for_each_online_node(node)
+ if (nodes[node])
+ x += sprintf(buf + x, " N%d=%lu",
+ node, nodes[node]);
+#endif
+ kfree(nodes);
+ return x + sprintf(buf + x, "\n");
+}
+
+static int any_slab_objects(struct kmem_cache *s)
+{
+ int node;
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ if (s->cpu_slab[cpu])
+ return 1;
+
+ for_each_node(node) {
+ struct kmem_cache_node *n = get_node(s, node);
+
+ if (n->nr_partial || atomic_read(&n->nr_slabs))
+ return 1;
+ }
+ return 0;
+}
+
+#define to_slab_attr(n) container_of(n, struct slab_attribute, attr)
+#define to_slab(n) container_of(n, struct kmem_cache, kobj);
+
+struct slab_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kmem_cache *s, char *buf);
+ ssize_t (*store)(struct kmem_cache *s, const char *x, size_t count);
+};
+
+#define SLAB_ATTR_RO(_name) \
+ static struct slab_attribute _name##_attr = __ATTR_RO(_name)
+
+#define SLAB_ATTR(_name) \
+ static struct slab_attribute _name##_attr = \
+ __ATTR(_name, 0644, _name##_show, _name##_store)
+
+static ssize_t slab_size_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->size);
+}
+SLAB_ATTR_RO(slab_size);
+
+static ssize_t align_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->align);
+}
+SLAB_ATTR_RO(align);
+
+static ssize_t object_size_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->objsize);
+}
+SLAB_ATTR_RO(object_size);
+
+static ssize_t objs_per_slab_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->objects);
+}
+SLAB_ATTR_RO(objs_per_slab);
+
+static ssize_t order_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->order);
+}
+SLAB_ATTR_RO(order);
+
+static ssize_t ctor_show(struct kmem_cache *s, char *buf)
+{
+ if (s->ctor) {
+ int n = sprint_symbol(buf, (unsigned long)s->ctor);
+
+ return n + sprintf(buf + n, "\n");
+ }
+ return 0;
+}
+SLAB_ATTR_RO(ctor);
+
+static ssize_t dtor_show(struct kmem_cache *s, char *buf)
+{
+ if (s->dtor) {
+ int n = sprint_symbol(buf, (unsigned long)s->dtor);
+
+ return n + sprintf(buf + n, "\n");
+ }
+ return 0;
+}
+SLAB_ATTR_RO(dtor);
+
+static ssize_t aliases_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->refcount - 1);
+}
+SLAB_ATTR_RO(aliases);
+
+static ssize_t slabs_show(struct kmem_cache *s, char *buf)
+{
+ return slab_objects(s, buf, SO_FULL|SO_PARTIAL|SO_CPU);
+}
+SLAB_ATTR_RO(slabs);
+
+static ssize_t partial_show(struct kmem_cache *s, char *buf)
+{
+ return slab_objects(s, buf, SO_PARTIAL);
+}
+SLAB_ATTR_RO(partial);
+
+static ssize_t cpu_slabs_show(struct kmem_cache *s, char *buf)
+{
+ return slab_objects(s, buf, SO_CPU);
+}
+SLAB_ATTR_RO(cpu_slabs);
+
+static ssize_t objects_show(struct kmem_cache *s, char *buf)
+{
+ return slab_objects(s, buf, SO_FULL|SO_PARTIAL|SO_CPU|SO_OBJECTS);
+}
+SLAB_ATTR_RO(objects);
+
+static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_DEBUG_FREE));
+}
+
+static ssize_t sanity_checks_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ s->flags &= ~SLAB_DEBUG_FREE;
+ if (buf[0] == '1')
+ s->flags |= SLAB_DEBUG_FREE;
+ return length;
+}
+SLAB_ATTR(sanity_checks);
+
+static ssize_t trace_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_TRACE));
+}
+
+static ssize_t trace_store(struct kmem_cache *s, const char *buf,
+ size_t length)
+{
+ s->flags &= ~SLAB_TRACE;
+ if (buf[0] == '1')
+ s->flags |= SLAB_TRACE;
+ return length;
+}
+SLAB_ATTR(trace);
+
+static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT));
+}
+
+static ssize_t reclaim_account_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ s->flags &= ~SLAB_RECLAIM_ACCOUNT;
+ if (buf[0] == '1')
+ s->flags |= SLAB_RECLAIM_ACCOUNT;
+ return length;
+}
+SLAB_ATTR(reclaim_account);
+
+static ssize_t hwcache_align_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_HWCACHE_ALIGN));
+}
+SLAB_ATTR_RO(hwcache_align);
+
+#ifdef CONFIG_ZONE_DMA
+static ssize_t cache_dma_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_CACHE_DMA));
+}
+SLAB_ATTR_RO(cache_dma);
+#endif
+
+static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU));
+}
+SLAB_ATTR_RO(destroy_by_rcu);
+
+static ssize_t red_zone_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_RED_ZONE));
+}
+
+static ssize_t red_zone_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ if (any_slab_objects(s))
+ return -EBUSY;
+
+ s->flags &= ~SLAB_RED_ZONE;
+ if (buf[0] == '1')
+ s->flags |= SLAB_RED_ZONE;
+ calculate_sizes(s);
+ return length;
+}
+SLAB_ATTR(red_zone);
+
+static ssize_t poison_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_POISON));
+}
+
+static ssize_t poison_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ if (any_slab_objects(s))
+ return -EBUSY;
+
+ s->flags &= ~SLAB_POISON;
+ if (buf[0] == '1')
+ s->flags |= SLAB_POISON;
+ calculate_sizes(s);
+ return length;
+}
+SLAB_ATTR(poison);
+
+static ssize_t store_user_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", !!(s->flags & SLAB_STORE_USER));
+}
+
+static ssize_t store_user_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ if (any_slab_objects(s))
+ return -EBUSY;
+
+ s->flags &= ~SLAB_STORE_USER;
+ if (buf[0] == '1')
+ s->flags |= SLAB_STORE_USER;
+ calculate_sizes(s);
+ return length;
+}
+SLAB_ATTR(store_user);
+
+static ssize_t validate_show(struct kmem_cache *s, char *buf)
+{
+ return 0;
+}
+
+static ssize_t validate_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ if (buf[0] == '1')
+ validate_slab_cache(s);
+ else
+ return -EINVAL;
+ return length;
+}
+SLAB_ATTR(validate);
+
+static ssize_t shrink_show(struct kmem_cache *s, char *buf)
+{
+ return 0;
+}
+
+static ssize_t shrink_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ if (buf[0] == '1') {
+ int rc = kmem_cache_shrink(s);
+
+ if (rc)
+ return rc;
+ } else
+ return -EINVAL;
+ return length;
+}
+SLAB_ATTR(shrink);
+
+static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return -ENOSYS;
+ return list_locations(s, buf, TRACK_ALLOC);
+}
+SLAB_ATTR_RO(alloc_calls);
+
+static ssize_t free_calls_show(struct kmem_cache *s, char *buf)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return -ENOSYS;
+ return list_locations(s, buf, TRACK_FREE);
+}
+SLAB_ATTR_RO(free_calls);
+
+#ifdef CONFIG_NUMA
+static ssize_t defrag_ratio_show(struct kmem_cache *s, char *buf)
+{
+ return sprintf(buf, "%d\n", s->defrag_ratio / 10);
+}
+
+static ssize_t defrag_ratio_store(struct kmem_cache *s,
+ const char *buf, size_t length)
+{
+ int n = simple_strtoul(buf, NULL, 10);
+
+ if (n < 100)
+ s->defrag_ratio = n * 10;
+ return length;
+}
+SLAB_ATTR(defrag_ratio);
+#endif
+
+static struct attribute * slab_attrs[] = {
+ &slab_size_attr.attr,
+ &object_size_attr.attr,
+ &objs_per_slab_attr.attr,
+ &order_attr.attr,
+ &objects_attr.attr,
+ &slabs_attr.attr,
+ &partial_attr.attr,
+ &cpu_slabs_attr.attr,
+ &ctor_attr.attr,
+ &dtor_attr.attr,
+ &aliases_attr.attr,
+ &align_attr.attr,
+ &sanity_checks_attr.attr,
+ &trace_attr.attr,
+ &hwcache_align_attr.attr,
+ &reclaim_account_attr.attr,
+ &destroy_by_rcu_attr.attr,
+ &red_zone_attr.attr,
+ &poison_attr.attr,
+ &store_user_attr.attr,
+ &validate_attr.attr,
+ &shrink_attr.attr,
+ &alloc_calls_attr.attr,
+ &free_calls_attr.attr,
+#ifdef CONFIG_ZONE_DMA
+ &cache_dma_attr.attr,
+#endif
+#ifdef CONFIG_NUMA
+ &defrag_ratio_attr.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group slab_attr_group = {
+ .attrs = slab_attrs,
+};
+
+static ssize_t slab_attr_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buf)
+{
+ struct slab_attribute *attribute;
+ struct kmem_cache *s;
+ int err;
+
+ attribute = to_slab_attr(attr);
+ s = to_slab(kobj);
+
+ if (!attribute->show)
+ return -EIO;
+
+ err = attribute->show(s, buf);
+
+ return err;
+}
+
+static ssize_t slab_attr_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct slab_attribute *attribute;
+ struct kmem_cache *s;
+ int err;
+
+ attribute = to_slab_attr(attr);
+ s = to_slab(kobj);
+
+ if (!attribute->store)
+ return -EIO;
+
+ err = attribute->store(s, buf, len);
+
+ return err;
+}
+
+static struct sysfs_ops slab_sysfs_ops = {
+ .show = slab_attr_show,
+ .store = slab_attr_store,
+};
+
+static struct kobj_type slab_ktype = {
+ .sysfs_ops = &slab_sysfs_ops,
+};
+
+static int uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+ struct kobj_type *ktype = get_ktype(kobj);
+
+ if (ktype == &slab_ktype)
+ return 1;
+ return 0;
+}
+
+static struct kset_uevent_ops slab_uevent_ops = {
+ .filter = uevent_filter,
+};
+
+decl_subsys(slab, &slab_ktype, &slab_uevent_ops);
+
+#define ID_STR_LENGTH 64
+
+/* Create a unique string id for a slab cache:
+ * format
+ * :[flags-]size:[memory address of kmemcache]
+ */
+static char *create_unique_id(struct kmem_cache *s)
+{
+ char *name = kmalloc(ID_STR_LENGTH, GFP_KERNEL);
+ char *p = name;
+
+ BUG_ON(!name);
+
+ *p++ = ':';
+ /*
+ * First flags affecting slabcache operations. We will only
+ * get here for aliasable slabs so we do not need to support
+ * too many flags. The flags here must cover all flags that
+ * are matched during merging to guarantee that the id is
+ * unique.
+ */
+ if (s->flags & SLAB_CACHE_DMA)
+ *p++ = 'd';
+ if (s->flags & SLAB_RECLAIM_ACCOUNT)
+ *p++ = 'a';
+ if (s->flags & SLAB_DEBUG_FREE)
+ *p++ = 'F';
+ if (p != name + 1)
+ *p++ = '-';
+ p += sprintf(p, "%07d", s->size);
+ BUG_ON(p > name + ID_STR_LENGTH - 1);
+ return name;
+}
+
+static int sysfs_slab_add(struct kmem_cache *s)
+{
+ int err;
+ const char *name;
+ int unmergeable;
+
+ if (slab_state < SYSFS)
+ /* Defer until later */
+ return 0;
+
+ unmergeable = slab_unmergeable(s);
+ if (unmergeable) {
+ /*
+ * Slabcache can never be merged so we can use the name proper.
+ * This is typically the case for debug situations. In that
+ * case we can catch duplicate names easily.
+ */
+ sysfs_remove_link(&slab_subsys.kobj, s->name);
+ name = s->name;
+ } else {
+ /*
+ * Create a unique name for the slab as a target
+ * for the symlinks.
+ */
+ name = create_unique_id(s);
+ }
+
+ kobj_set_kset_s(s, slab_subsys);
+ kobject_set_name(&s->kobj, name);
+ kobject_init(&s->kobj);
+ err = kobject_add(&s->kobj);
+ if (err)
+ return err;
+
+ err = sysfs_create_group(&s->kobj, &slab_attr_group);
+ if (err)
+ return err;
+ kobject_uevent(&s->kobj, KOBJ_ADD);
+ if (!unmergeable) {
+ /* Setup first alias */
+ sysfs_slab_alias(s, s->name);
+ kfree(name);
+ }
+ return 0;
+}
+
+static void sysfs_slab_remove(struct kmem_cache *s)
+{
+ kobject_uevent(&s->kobj, KOBJ_REMOVE);
+ kobject_del(&s->kobj);
+}
+
+/*
+ * Need to buffer aliases during bootup until sysfs becomes
+ * available lest we loose that information.
+ */
+struct saved_alias {
+ struct kmem_cache *s;
+ const char *name;
+ struct saved_alias *next;
+};
+
+struct saved_alias *alias_list;
+
+static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
+{
+ struct saved_alias *al;
+
+ if (slab_state == SYSFS) {
+ /*
+ * If we have a leftover link then remove it.
+ */
+ sysfs_remove_link(&slab_subsys.kobj, name);
+ return sysfs_create_link(&slab_subsys.kobj,
+ &s->kobj, name);
+ }
+
+ al = kmalloc(sizeof(struct saved_alias), GFP_KERNEL);
+ if (!al)
+ return -ENOMEM;
+
+ al->s = s;
+ al->name = name;
+ al->next = alias_list;
+ alias_list = al;
+ return 0;
+}
+
+static int __init slab_sysfs_init(void)
+{
+ struct list_head *h;
+ int err;
+
+ err = subsystem_register(&slab_subsys);
+ if (err) {
+ printk(KERN_ERR "Cannot register slab subsystem.\n");
+ return -ENOSYS;
+ }
+
+ slab_state = SYSFS;
+
+ list_for_each(h, &slab_caches) {
+ struct kmem_cache *s =
+ container_of(h, struct kmem_cache, list);
+
+ err = sysfs_slab_add(s);
+ BUG_ON(err);
+ }
+
+ while (alias_list) {
+ struct saved_alias *al = alias_list;
+
+ alias_list = alias_list->next;
+ err = sysfs_slab_alias(al->s, al->name);
+ BUG_ON(err);
+ kfree(al);
+ }
+
+ resiliency_test();
+ return 0;
+}
+
+__initcall(slab_sysfs_init);
+#endif
diff --git a/mm/sparse.c b/mm/sparse.c
index ac26eb0d73c..6f3fff907bc 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -44,7 +44,7 @@ EXPORT_SYMBOL(page_to_nid);
#endif
#ifdef CONFIG_SPARSEMEM_EXTREME
-static struct mem_section *sparse_index_alloc(int nid)
+static struct mem_section noinline *sparse_index_alloc(int nid)
{
struct mem_section *section = NULL;
unsigned long array_size = SECTIONS_PER_ROOT *
@@ -61,7 +61,7 @@ static struct mem_section *sparse_index_alloc(int nid)
return section;
}
-static int sparse_index_init(unsigned long section_nr, int nid)
+static int __meminit sparse_index_init(unsigned long section_nr, int nid)
{
static DEFINE_SPINLOCK(index_init_lock);
unsigned long root = SECTION_NR_TO_ROOT(section_nr);
@@ -138,7 +138,7 @@ static inline int sparse_early_nid(struct mem_section *section)
}
/* Record a memory area against a node. */
-void memory_present(int nid, unsigned long start, unsigned long end)
+void __init memory_present(int nid, unsigned long start, unsigned long end)
{
unsigned long pfn;
@@ -197,7 +197,7 @@ struct page *sparse_decode_mem_map(unsigned long coded_mem_map, unsigned long pn
return ((struct page *)coded_mem_map) + section_nr_to_pfn(pnum);
}
-static int sparse_init_one_section(struct mem_section *ms,
+static int __meminit sparse_init_one_section(struct mem_section *ms,
unsigned long pnum, struct page *mem_map)
{
if (!valid_section(ms))
@@ -209,7 +209,7 @@ static int sparse_init_one_section(struct mem_section *ms,
return 1;
}
-static struct page *sparse_early_mem_map_alloc(unsigned long pnum)
+static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
{
struct page *map;
struct mem_section *ms = __nr_to_section(pnum);
@@ -272,7 +272,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
* Allocate the accumulated non-linear sections, allocate a mem_map
* for each and record the physical to section mapping.
*/
-void sparse_init(void)
+void __init sparse_init(void)
{
unsigned long pnum;
struct page *map;
@@ -288,6 +288,7 @@ void sparse_init(void)
}
}
+#ifdef CONFIG_MEMORY_HOTPLUG
/*
* returns the number of sections whose mem_maps were properly
* set. If this is <=0, then that means that the passed-in
@@ -327,3 +328,4 @@ out:
__kfree_section_memmap(memmap, nr_pages);
return ret;
}
+#endif
diff --git a/mm/swap.c b/mm/swap.c
index 2ed7be39795..d3cb966fe99 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -55,7 +55,7 @@ static void fastcall __page_cache_release(struct page *page)
static void put_compound_page(struct page *page)
{
- page = (struct page *)page_private(page);
+ page = compound_head(page);
if (put_page_testzero(page)) {
compound_page_dtor *dtor;
@@ -488,7 +488,7 @@ static int cpu_swap_callback(struct notifier_block *nfb,
long *committed;
committed = &per_cpu(committed_space, (long)hcpu);
- if (action == CPU_DEAD) {
+ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
atomic_add(*committed, &vm_committed_space);
*committed = 0;
__lru_add_drain((long)hcpu);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index a2d9bb4e80d..acc172cbe3a 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1531,9 +1531,6 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
error = PTR_ERR(page);
goto bad_swap;
}
- wait_on_page_locked(page);
- if (!PageUptodate(page))
- goto bad_swap;
kmap(page);
swap_header = page_address(page);
diff --git a/mm/truncate.c b/mm/truncate.c
index 0f4b6d18ab0..4fbe1a2da5f 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -12,6 +12,7 @@
#include <linux/swap.h>
#include <linux/module.h>
#include <linux/pagemap.h>
+#include <linux/highmem.h>
#include <linux/pagevec.h>
#include <linux/task_io_accounting_ops.h>
#include <linux/buffer_head.h> /* grr. try_to_release_page,
@@ -46,7 +47,7 @@ void do_invalidatepage(struct page *page, unsigned long offset)
static inline void truncate_partial_page(struct page *page, unsigned partial)
{
- memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
+ zero_user_page(page, partial, PAGE_CACHE_SIZE - partial, KM_USER0);
if (PagePrivate(page))
do_invalidatepage(page, partial);
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9eef486da90..faa2a521dea 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -431,7 +431,7 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
area->flags |= VM_VPAGES;
} else {
pages = kmalloc_node(array_size,
- (gfp_mask & ~(__GFP_HIGHMEM | __GFP_ZERO)),
+ (gfp_mask & GFP_LEVEL_MASK),
node);
}
area->pages = pages;
@@ -577,6 +577,14 @@ void *vmalloc_exec(unsigned long size)
return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
}
+#if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
+#define GFP_VMALLOC32 GFP_DMA32
+#elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)
+#define GFP_VMALLOC32 GFP_DMA
+#else
+#define GFP_VMALLOC32 GFP_KERNEL
+#endif
+
/**
* vmalloc_32 - allocate virtually contiguous memory (32bit addressable)
* @size: allocation size
@@ -586,7 +594,7 @@ void *vmalloc_exec(unsigned long size)
*/
void *vmalloc_32(unsigned long size)
{
- return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
+ return __vmalloc(size, GFP_VMALLOC32, PAGE_KERNEL);
}
EXPORT_SYMBOL(vmalloc_32);
@@ -602,7 +610,7 @@ void *vmalloc_32_user(unsigned long size)
struct vm_struct *area;
void *ret;
- ret = __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+ ret = __vmalloc(size, GFP_VMALLOC32 | __GFP_ZERO, PAGE_KERNEL);
if (ret) {
write_lock(&vmlist_lock);
area = __find_vm_area(ret);
@@ -747,3 +755,10 @@ out_einval_locked:
}
EXPORT_SYMBOL(remap_vmalloc_range);
+/*
+ * Implement a stub for vmalloc_sync_all() if the architecture chose not to
+ * have one.
+ */
+void __attribute__((weak)) vmalloc_sync_all(void)
+{
+}
diff --git a/mm/vmscan.c b/mm/vmscan.c
index db023e2ff38..1be5a6376ef 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -284,12 +284,8 @@ static void handle_write_error(struct address_space *mapping,
struct page *page, int error)
{
lock_page(page);
- if (page_mapping(page) == mapping) {
- if (error == -ENOSPC)
- set_bit(AS_ENOSPC, &mapping->flags);
- else
- set_bit(AS_EIO, &mapping->flags);
- }
+ if (page_mapping(page) == mapping)
+ mapping_set_error(mapping, error);
unlock_page(page);
}
@@ -1323,8 +1319,6 @@ static int kswapd(void *p)
for ( ; ; ) {
unsigned long new_order;
- try_to_freeze();
-
prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
new_order = pgdat->kswapd_max_order;
pgdat->kswapd_max_order = 0;
@@ -1335,12 +1329,19 @@ static int kswapd(void *p)
*/
order = new_order;
} else {
- schedule();
+ if (!freezing(current))
+ schedule();
+
order = pgdat->kswapd_max_order;
}
finish_wait(&pgdat->kswapd_wait, &wait);
- balance_pgdat(pgdat, order);
+ if (!try_to_freeze()) {
+ /* We can speed up thawing tasks if we don't call
+ * balance_pgdat after returning from the refrigerator
+ */
+ balance_pgdat(pgdat, order);
+ }
}
return 0;
}
@@ -1527,7 +1528,7 @@ static int __devinit cpu_callback(struct notifier_block *nfb,
pg_data_t *pgdat;
cpumask_t mask;
- if (action == CPU_ONLINE) {
+ if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) {
for_each_online_pgdat(pgdat) {
mask = node_to_cpumask(pgdat->node_id);
if (any_online_cpu(mask) != NR_CPUS)
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 6c488d6ac42..9832d9a41d8 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -281,6 +281,17 @@ EXPORT_SYMBOL(dec_zone_page_state);
/*
* Update the zone counters for one cpu.
+ *
+ * Note that refresh_cpu_vm_stats strives to only access
+ * node local memory. The per cpu pagesets on remote zones are placed
+ * in the memory local to the processor using that pageset. So the
+ * loop over all zones will access a series of cachelines local to
+ * the processor.
+ *
+ * The call to zone_page_state_add updates the cachelines with the
+ * statistics in the remote zone struct as well as the global cachelines
+ * with the global counters. These could cause remote node cache line
+ * bouncing and will have to be only done when necessary.
*/
void refresh_cpu_vm_stats(int cpu)
{
@@ -289,21 +300,54 @@ void refresh_cpu_vm_stats(int cpu)
unsigned long flags;
for_each_zone(zone) {
- struct per_cpu_pageset *pcp;
+ struct per_cpu_pageset *p;
if (!populated_zone(zone))
continue;
- pcp = zone_pcp(zone, cpu);
+ p = zone_pcp(zone, cpu);
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
- if (pcp->vm_stat_diff[i]) {
+ if (p->vm_stat_diff[i]) {
local_irq_save(flags);
- zone_page_state_add(pcp->vm_stat_diff[i],
+ zone_page_state_add(p->vm_stat_diff[i],
zone, i);
- pcp->vm_stat_diff[i] = 0;
+ p->vm_stat_diff[i] = 0;
+#ifdef CONFIG_NUMA
+ /* 3 seconds idle till flush */
+ p->expire = 3;
+#endif
local_irq_restore(flags);
}
+#ifdef CONFIG_NUMA
+ /*
+ * Deal with draining the remote pageset of this
+ * processor
+ *
+ * Check if there are pages remaining in this pageset
+ * if not then there is nothing to expire.
+ */
+ if (!p->expire || (!p->pcp[0].count && !p->pcp[1].count))
+ continue;
+
+ /*
+ * We never drain zones local to this processor.
+ */
+ if (zone_to_nid(zone) == numa_node_id()) {
+ p->expire = 0;
+ continue;
+ }
+
+ p->expire--;
+ if (p->expire)
+ continue;
+
+ if (p->pcp[0].count)
+ drain_zone_pages(zone, p->pcp + 0);
+
+ if (p->pcp[1].count)
+ drain_zone_pages(zone, p->pcp + 1);
+#endif
}
}
@@ -640,6 +684,24 @@ const struct seq_operations vmstat_op = {
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SMP
+static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
+int sysctl_stat_interval __read_mostly = HZ;
+
+static void vmstat_update(struct work_struct *w)
+{
+ refresh_cpu_vm_stats(smp_processor_id());
+ schedule_delayed_work(&__get_cpu_var(vmstat_work),
+ sysctl_stat_interval);
+}
+
+static void __devinit start_cpu_timer(int cpu)
+{
+ struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
+
+ INIT_DELAYED_WORK(vmstat_work, vmstat_update);
+ schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
+}
+
/*
* Use the cpu notifier to insure that the thresholds are recalculated
* when necessary.
@@ -648,10 +710,24 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
+ long cpu = (long)hcpu;
+
switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_CANCELED:
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ start_cpu_timer(cpu);
+ break;
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
+ cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu));
+ per_cpu(vmstat_work, cpu).work.func = NULL;
+ break;
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ start_cpu_timer(cpu);
+ break;
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
refresh_zone_stat_thresholds();
break;
default:
@@ -665,8 +741,13 @@ static struct notifier_block __cpuinitdata vmstat_notifier =
int __init setup_vmstat(void)
{
+ int cpu;
+
refresh_zone_stat_thresholds();
register_cpu_notifier(&vmstat_notifier);
+
+ for_each_online_cpu(cpu)
+ start_cpu_timer(cpu);
return 0;
}
module_init(setup_vmstat)
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index c0c7bb8e9f0..bd93c45778d 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -117,8 +117,7 @@ static void __exit vlan_cleanup_devices(void)
struct net_device *dev, *nxt;
rtnl_lock();
- for (dev = dev_base; dev; dev = nxt) {
- nxt = dev->next;
+ for_each_netdev_safe(dev, nxt) {
if (dev->priv_flags & IFF_802_1Q_VLAN) {
unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
VLAN_DEV_INFO(dev)->vlan_id);
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index 5e24f72602a..d216a64421c 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -237,13 +237,9 @@ int vlan_proc_rem_dev(struct net_device *vlandev)
* The following few functions build the content of /proc/net/vlan/config
*/
-/* starting at dev, find a VLAN device */
-static struct net_device *vlan_skip(struct net_device *dev)
+static inline int is_vlan_dev(struct net_device *dev)
{
- while (dev && !(dev->priv_flags & IFF_802_1Q_VLAN))
- dev = dev->next;
-
- return dev;
+ return dev->priv_flags & IFF_802_1Q_VLAN;
}
/* start read of /proc/net/vlan/config */
@@ -257,19 +253,35 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos)
if (*pos == 0)
return SEQ_START_TOKEN;
- for (dev = vlan_skip(dev_base); dev && i < *pos;
- dev = vlan_skip(dev->next), ++i);
+ for_each_netdev(dev) {
+ if (!is_vlan_dev(dev))
+ continue;
+
+ if (i++ == *pos)
+ return dev;
+ }
- return (i == *pos) ? dev : NULL;
+ return NULL;
}
static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
+ struct net_device *dev;
+
++*pos;
- return vlan_skip((v == SEQ_START_TOKEN)
- ? dev_base
- : ((struct net_device *)v)->next);
+ dev = (struct net_device *)v;
+ if (v == SEQ_START_TOKEN)
+ dev = net_device_entry(&dev_base_head);
+
+ for_each_netdev_continue(dev) {
+ if (!is_vlan_dev(dev))
+ continue;
+
+ return dev;
+ }
+
+ return NULL;
}
static void vlan_seq_stop(struct seq_file *seq, void *v)
diff --git a/net/Kconfig b/net/Kconfig
index 2fc8e77b1e6..caeacd16656 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -220,10 +220,13 @@ config FIB_RULES
menu "Wireless"
source "net/wireless/Kconfig"
+source "net/mac80211/Kconfig"
source "net/ieee80211/Kconfig"
endmenu
+source "net/rfkill/Kconfig"
+
endif # if NET
endmenu # Networking
diff --git a/net/Makefile b/net/Makefile
index 6b74d4118c5..34e5b2d7f87 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -45,13 +45,14 @@ obj-$(CONFIG_ECONET) += econet/
obj-$(CONFIG_VLAN_8021Q) += 8021q/
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
+obj-y += wireless/
+obj-$(CONFIG_MAC80211) += mac80211/
obj-$(CONFIG_IEEE80211) += ieee80211/
obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
+obj-$(CONFIG_RFKILL) += rfkill/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
endif
-
-obj-y += wireless/
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 16eda21fb38..fbdfb1224ae 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -937,11 +937,11 @@ static unsigned long atalk_sum_partial(const unsigned char *data,
static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
int len, unsigned long sum)
{
- int end = skb_headlen(skb);
+ int start = skb_headlen(skb);
int i, copy;
/* checksum stuff in header space */
- if ((copy = end - offset) > 0) {
+ if ( (copy = start - offset) > 0) {
if (copy > len)
copy = len;
sum = atalk_sum_partial(skb->data + offset, copy, sum);
@@ -953,9 +953,11 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
/* checksum stuff in frags */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
u8 *vaddr;
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -963,31 +965,36 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
if (copy > len)
copy = len;
vaddr = kmap_skb_frag(frag);
- sum = atalk_sum_partial(vaddr + frag->page_offset,
- copy, sum);
+ sum = atalk_sum_partial(vaddr + frag->page_offset +
+ offset - start, copy, sum);
kunmap_skb_frag(vaddr);
if (!(len -= copy))
return sum;
offset += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- sum = atalk_sum_skb(list, 0, copy, sum);
+ sum = atalk_sum_skb(list, offset - start,
+ copy, sum);
if ((len -= copy) == 0)
return sum;
offset += copy;
}
+ start = end;
}
}
@@ -1837,7 +1844,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(atalk_dgram_ops) = {
.sendpage = sock_no_sendpage,
};
-#include <linux/smp_lock.h>
SOCKOPS_WRAP(atalk_dgram, PF_APPLETALK);
static struct notifier_block ddp_notifier = {
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 6ded95272a5..429e13a6c6a 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -23,7 +23,6 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
-#include <linux/smp_lock.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <net/ax25.h>
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index ab2db55982c..1c8f4a0c5f4 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -37,7 +37,6 @@
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/errno.h>
-#include <linux/smp_lock.h>
#include <linux/net.h>
#include <net/sock.h>
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 832b5f44be5..bfc9a35bad3 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -499,6 +499,15 @@ static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char
break;
case HCI_FILTER:
+ {
+ struct hci_filter *f = &hci_pi(sk)->filter;
+
+ uf.type_mask = f->type_mask;
+ uf.opcode = f->opcode;
+ uf.event_mask[0] = *((u32 *) f->event_mask + 0);
+ uf.event_mask[1] = *((u32 *) f->event_mask + 1);
+ }
+
len = min_t(unsigned int, len, sizeof(uf));
if (copy_from_user(&uf, optval, len)) {
err = -EFAULT;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 801d687ea4e..25835403d65 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -305,7 +305,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- dev->class = bt_class;
+ dev->bus = &bt_bus;
dev->parent = hdev->parent;
strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
@@ -322,6 +322,10 @@ int hci_register_sysfs(struct hci_dev *hdev)
if (device_create_file(dev, bt_attrs[i]) < 0)
BT_ERR("Failed to create device attribute");
+ if (sysfs_create_link(&bt_class->subsys.kobj,
+ &dev->kobj, kobject_name(&dev->kobj)) < 0)
+ BT_ERR("Failed to create class symlink");
+
return 0;
}
@@ -329,6 +333,9 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
{
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+ sysfs_remove_link(&bt_class->subsys.kobj,
+ kobject_name(&hdev->dev.kobj));
+
device_del(&hdev->dev);
}
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index a5867879b61..a59b1fb63b7 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -954,11 +954,17 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
switch (optname) {
case L2CAP_OPTIONS:
+ opts.imtu = l2cap_pi(sk)->imtu;
+ opts.omtu = l2cap_pi(sk)->omtu;
+ opts.flush_to = l2cap_pi(sk)->flush_to;
+ opts.mode = 0x00;
+
len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *) &opts, optval, len)) {
err = -EFAULT;
break;
}
+
l2cap_pi(sk)->imtu = opts.imtu;
l2cap_pi(sk)->omtu = opts.omtu;
break;
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index fe7df90eb70..52e04df323e 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -622,7 +622,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
bacpy(&addr.l2_bdaddr, src);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = 0;
- *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ *err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (*err < 0)
goto failed;
@@ -643,7 +643,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
bacpy(&addr.l2_bdaddr, dst);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM);
- *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
+ *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
if (*err == 0 || *err == -EINPROGRESS)
return s;
@@ -1058,6 +1058,12 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
case BT_DISCONN:
d->state = BT_CLOSED;
__rfcomm_dlc_close(d, 0);
+
+ if (list_empty(&s->dlcs)) {
+ s->state = BT_DISCONN;
+ rfcomm_send_disc(s, 0);
+ }
+
break;
}
} else {
@@ -1067,6 +1073,10 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
s->state = BT_CONNECTED;
rfcomm_process_connect(s);
break;
+
+ case BT_DISCONN:
+ rfcomm_session_put(s);
+ break;
}
}
return 0;
@@ -1757,19 +1767,12 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
BT_DBG("session %p", s);
- if (sock_create_lite(PF_BLUETOOTH, sock->type, BTPROTO_L2CAP, &nsock))
+ err = kernel_accept(sock, &nsock, O_NONBLOCK);
+ if (err < 0)
return;
- nsock->ops = sock->ops;
-
__module_get(nsock->ops->owner);
- err = sock->ops->accept(sock, nsock, O_NONBLOCK);
- if (err < 0) {
- sock_release(nsock);
- return;
- }
-
/* Set our callbacks */
nsock->sk->sk_data_ready = rfcomm_l2data_ready;
nsock->sk->sk_state_change = rfcomm_l2state_change;
@@ -1885,7 +1888,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
bacpy(&addr.l2_bdaddr, ba);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM);
- err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+ err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0) {
BT_ERR("Bind failed %d", err);
goto failed;
@@ -1898,7 +1901,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
release_sock(sk);
/* Start listening on the socket */
- err = sock->ops->listen(sock, 10);
+ err = kernel_listen(sock, 10);
if (err) {
BT_ERR("Listen failed %d", err);
goto failed;
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 9a7a44fc721..b2b1cceb102 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -517,9 +517,10 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
if (dlc->state == BT_CLOSED) {
if (!dev->tty) {
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
- rfcomm_dev_hold(dev);
- rfcomm_dev_del(dev);
+ if (rfcomm_dev_get(dev->id) == NULL)
+ return;
+ rfcomm_dev_del(dev);
/* We have to drop DLC lock here, otherwise
rfcomm_dev_put() will dead lock if it's
the last reference. */
@@ -974,8 +975,12 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
rfcomm_tty_flush_buffer(tty);
- if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+ if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
+ if (rfcomm_dev_get(dev->id) == NULL)
+ return;
rfcomm_dev_del(dev);
+ rfcomm_dev_put(dev);
+ }
}
static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 690573bbf01..849deaf1410 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -475,11 +475,9 @@ void __exit br_cleanup_bridges(void)
struct net_device *dev, *nxt;
rtnl_lock();
- for (dev = dev_base; dev; dev = nxt) {
- nxt = dev->next;
+ for_each_netdev_safe(dev, nxt)
if (dev->priv_flags & IFF_EBRIDGE)
del_br(dev->priv);
- }
rtnl_unlock();
}
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index eda0fbfc923..bb15e9e259b 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -27,7 +27,9 @@ static int get_bridge_ifindices(int *indices, int num)
struct net_device *dev;
int i = 0;
- for (dev = dev_base; dev && i < num; dev = dev->next) {
+ for_each_netdev(dev) {
+ if (i >= num)
+ break;
if (dev->priv_flags & IFF_EBRIDGE)
indices[i++] = dev->ifindex;
}
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 9b2986b182b..fa779874b9d 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -142,14 +142,33 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
return skb->nf_bridge;
}
-static inline void nf_bridge_save_header(struct sk_buff *skb)
+static inline void nf_bridge_push_encap_header(struct sk_buff *skb)
+{
+ unsigned int len = nf_bridge_encap_header_len(skb);
+
+ skb_push(skb, len);
+ skb->network_header -= len;
+}
+
+static inline void nf_bridge_pull_encap_header(struct sk_buff *skb)
{
- int header_size = ETH_HLEN;
+ unsigned int len = nf_bridge_encap_header_len(skb);
+
+ skb_pull(skb, len);
+ skb->network_header += len;
+}
- if (skb->protocol == htons(ETH_P_8021Q))
- header_size += VLAN_HLEN;
- else if (skb->protocol == htons(ETH_P_PPP_SES))
- header_size += PPPOE_SES_HLEN;
+static inline void nf_bridge_pull_encap_header_rcsum(struct sk_buff *skb)
+{
+ unsigned int len = nf_bridge_encap_header_len(skb);
+
+ skb_pull_rcsum(skb, len);
+ skb->network_header += len;
+}
+
+static inline void nf_bridge_save_header(struct sk_buff *skb)
+{
+ int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
skb_copy_from_linear_data_offset(skb, -header_size,
skb->nf_bridge->data, header_size);
@@ -162,12 +181,7 @@ static inline void nf_bridge_save_header(struct sk_buff *skb)
int nf_bridge_copy_header(struct sk_buff *skb)
{
int err;
- int header_size = ETH_HLEN;
-
- if (skb->protocol == htons(ETH_P_8021Q))
- header_size += VLAN_HLEN;
- else if (skb->protocol == htons(ETH_P_PPP_SES))
- header_size += PPPOE_SES_HLEN;
+ int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
err = skb_cow(skb, header_size);
if (err)
@@ -175,11 +189,7 @@ int nf_bridge_copy_header(struct sk_buff *skb)
skb_copy_to_linear_data_offset(skb, -header_size,
skb->nf_bridge->data, header_size);
-
- if (skb->protocol == htons(ETH_P_8021Q))
- __skb_push(skb, VLAN_HLEN);
- else if (skb->protocol == htons(ETH_P_PPP_SES))
- __skb_push(skb, PPPOE_SES_HLEN);
+ __skb_push(skb, nf_bridge_encap_header_len(skb));
return 0;
}
@@ -200,13 +210,7 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
dst_hold(skb->dst);
skb->dev = nf_bridge->physindev;
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->network_header -= VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_push(skb, PPPOE_SES_HLEN);
- skb->network_header -= PPPOE_SES_HLEN;
- }
+ nf_bridge_push_encap_header(skb);
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish, 1);
@@ -284,13 +288,7 @@ static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
if (!skb->dev)
kfree_skb(skb);
else {
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_pull(skb, VLAN_HLEN);
- skb->network_header += VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_pull(skb, PPPOE_SES_HLEN);
- skb->network_header += PPPOE_SES_HLEN;
- }
+ nf_bridge_pull_encap_header(skb);
skb->dst->output(skb);
}
return 0;
@@ -356,15 +354,7 @@ bridged_dnat:
* bridged frame */
nf_bridge->mask |= BRNF_BRIDGED_DNAT;
skb->dev = nf_bridge->physindev;
- if (skb->protocol ==
- htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->network_header -= VLAN_HLEN;
- } else if(skb->protocol ==
- htons(ETH_P_PPP_SES)) {
- skb_push(skb, PPPOE_SES_HLEN);
- skb->network_header -= PPPOE_SES_HLEN;
- }
+ nf_bridge_push_encap_header(skb);
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING,
skb, skb->dev, NULL,
br_nf_pre_routing_finish_bridge,
@@ -380,13 +370,7 @@ bridged_dnat:
}
skb->dev = nf_bridge->physindev;
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->network_header -= VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_push(skb, PPPOE_SES_HLEN);
- skb->network_header -= PPPOE_SES_HLEN;
- }
+ nf_bridge_push_encap_header(skb);
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
br_handle_frame_finish, 1);
@@ -536,14 +520,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
#endif
if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
goto out;
-
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_pull_rcsum(skb, VLAN_HLEN);
- skb->network_header += VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_pull_rcsum(skb, PPPOE_SES_HLEN);
- skb->network_header += PPPOE_SES_HLEN;
- }
+ nf_bridge_pull_encap_header_rcsum(skb);
return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
}
#ifdef CONFIG_SYSCTL
@@ -557,14 +534,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
goto out;
-
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_pull_rcsum(skb, VLAN_HLEN);
- skb->network_header += VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_pull_rcsum(skb, PPPOE_SES_HLEN);
- skb->network_header += PPPOE_SES_HLEN;
- }
+ nf_bridge_pull_encap_header_rcsum(skb);
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto inhdr_error;
@@ -642,13 +612,7 @@ static int br_nf_forward_finish(struct sk_buff *skb)
} else {
in = *((struct net_device **)(skb->cb));
}
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->network_header -= VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_push(skb, PPPOE_SES_HLEN);
- skb->network_header -= PPPOE_SES_HLEN;
- }
+ nf_bridge_push_encap_header(skb);
NF_HOOK_THRESH(PF_BRIDGE, NF_BR_FORWARD, skb, in,
skb->dev, br_forward_finish, 1);
return 0;
@@ -682,13 +646,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
else
pf = PF_INET6;
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_pull(*pskb, VLAN_HLEN);
- (*pskb)->network_header += VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_pull(*pskb, PPPOE_SES_HLEN);
- (*pskb)->network_header += PPPOE_SES_HLEN;
- }
+ nf_bridge_pull_encap_header(*pskb);
nf_bridge = skb->nf_bridge;
if (skb->pkt_type == PACKET_OTHERHOST) {
@@ -722,15 +680,12 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
if (skb->protocol != htons(ETH_P_ARP)) {
if (!IS_VLAN_ARP(skb))
return NF_ACCEPT;
- skb_pull(*pskb, VLAN_HLEN);
- (*pskb)->network_header += VLAN_HLEN;
+ nf_bridge_pull_encap_header(*pskb);
}
if (arp_hdr(skb)->ar_pln != 4) {
- if (IS_VLAN_ARP(skb)) {
- skb_push(*pskb, VLAN_HLEN);
- (*pskb)->network_header -= VLAN_HLEN;
- }
+ if (IS_VLAN_ARP(skb))
+ nf_bridge_push_encap_header(*pskb);
return NF_ACCEPT;
}
*d = (struct net_device *)in;
@@ -777,13 +732,7 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
skb->pkt_type = PACKET_OTHERHOST;
nf_bridge->mask ^= BRNF_PKT_TYPE;
}
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_push(skb, VLAN_HLEN);
- skb->network_header -= VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_push(skb, PPPOE_SES_HLEN);
- skb->network_header -= PPPOE_SES_HLEN;
- }
+ nf_bridge_push_encap_header(skb);
NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, realindev, skb->dev,
br_forward_finish);
@@ -848,14 +797,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
nf_bridge->mask |= BRNF_PKT_TYPE;
}
- if (skb->protocol == htons(ETH_P_8021Q)) {
- skb_pull(skb, VLAN_HLEN);
- skb->network_header += VLAN_HLEN;
- } else if (skb->protocol == htons(ETH_P_PPP_SES)) {
- skb_pull(skb, PPPOE_SES_HLEN);
- skb->network_header += PPPOE_SES_HLEN;
- }
-
+ nf_bridge_pull_encap_header(skb);
nf_bridge_save_header(skb);
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index 35facc0c11c..0fcf6f07306 100644
--- a/net/bridge/br_netlink.c
+++ b/net/bridge/br_netlink.c
@@ -109,7 +109,8 @@ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
struct net_device *dev;
int idx;
- for (dev = dev_base, idx = 0; dev; dev = dev->next) {
+ idx = 0;
+ for_each_netdev(dev) {
/* not a bridge port */
if (dev->br_port == NULL || idx < cb->args[0])
goto skip;
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index ebb0861e9bd..0e035d6162c 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -13,7 +13,6 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include "br_private.h"
#include "br_private_stp.h"
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 3e246b37020..a786e786320 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -14,7 +14,6 @@
*/
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index 030aa798fea..24e0ca4a313 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/times.h>
-#include <linux/smp_lock.h>
#include "br_private.h"
#include "br_private_stp.h"
diff --git a/net/core/datagram.c b/net/core/datagram.c
index e1afa767944..cb056f47612 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -247,8 +247,8 @@ EXPORT_SYMBOL(skb_kill_datagram);
int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
struct iovec *to, int len)
{
- int end = skb_headlen(skb);
- int i, copy = end - offset;
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
/* Copy header. */
if (copy > 0) {
@@ -263,9 +263,11 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
/* Copy paged appendix. Hmm... why does this look so complicated? */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
int err;
u8 *vaddr;
@@ -275,8 +277,8 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
if (copy > len)
copy = len;
vaddr = kmap(page);
- err = memcpy_toiovec(to, vaddr + frag->page_offset,
- copy);
+ err = memcpy_toiovec(to, vaddr + frag->page_offset +
+ offset - start, copy);
kunmap(page);
if (err)
goto fault;
@@ -284,24 +286,30 @@ int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
return 0;
offset += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (skb_copy_datagram_iovec(list, 0, to, copy))
+ if (skb_copy_datagram_iovec(list,
+ offset - start,
+ to, copy))
goto fault;
if ((len -= copy) == 0)
return 0;
offset += copy;
}
+ start = end;
}
}
if (!len)
@@ -315,9 +323,9 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
u8 __user *to, int len,
__wsum *csump)
{
- int end = skb_headlen(skb);
+ int start = skb_headlen(skb);
int pos = 0;
- int i, copy = end - offset;
+ int i, copy = start - offset;
/* Copy header. */
if (copy > 0) {
@@ -336,9 +344,11 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
__wsum csum2;
int err = 0;
@@ -350,7 +360,8 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
copy = len;
vaddr = kmap(page);
csum2 = csum_and_copy_to_user(vaddr +
- frag->page_offset,
+ frag->page_offset +
+ offset - start,
to, copy, 0, &err);
kunmap(page);
if (err)
@@ -362,20 +373,24 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
to += copy;
pos += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list=list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
__wsum csum2 = 0;
if (copy > len)
copy = len;
- if (skb_copy_and_csum_datagram(list, 0,
+ if (skb_copy_and_csum_datagram(list,
+ offset - start,
to, copy,
&csum2))
goto fault;
@@ -386,6 +401,7 @@ static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
to += copy;
pos += copy;
}
+ start = end;
}
}
if (!len)
diff --git a/net/core/dev.c b/net/core/dev.c
index d5e42d13bd6..8301e2ac747 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -156,13 +156,13 @@ static spinlock_t net_dma_event_lock;
#endif
/*
- * The @dev_base list is protected by @dev_base_lock and the rtnl
+ * The @dev_base_head list is protected by @dev_base_lock and the rtnl
* semaphore.
*
* Pure readers hold dev_base_lock for reading.
*
* Writers must hold the rtnl semaphore while they loop through the
- * dev_base list, and hold dev_base_lock for writing when they do the
+ * dev_base_head list, and hold dev_base_lock for writing when they do the
* actual updates. This allows pure readers to access the list even
* while a writer is preparing to update it.
*
@@ -174,11 +174,10 @@ static spinlock_t net_dma_event_lock;
* unregister_netdevice(), which must be called with the rtnl
* semaphore held.
*/
-struct net_device *dev_base;
-static struct net_device **dev_tail = &dev_base;
+LIST_HEAD(dev_base_head);
DEFINE_RWLOCK(dev_base_lock);
-EXPORT_SYMBOL(dev_base);
+EXPORT_SYMBOL(dev_base_head);
EXPORT_SYMBOL(dev_base_lock);
#define NETDEV_HASHBITS 8
@@ -567,26 +566,38 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)
ASSERT_RTNL();
- for (dev = dev_base; dev; dev = dev->next)
+ for_each_netdev(dev)
if (dev->type == type &&
!memcmp(dev->dev_addr, ha, dev->addr_len))
- break;
- return dev;
+ return dev;
+
+ return NULL;
}
EXPORT_SYMBOL(dev_getbyhwaddr);
+struct net_device *__dev_getfirstbyhwtype(unsigned short type)
+{
+ struct net_device *dev;
+
+ ASSERT_RTNL();
+ for_each_netdev(dev)
+ if (dev->type == type)
+ return dev;
+
+ return NULL;
+}
+
+EXPORT_SYMBOL(__dev_getfirstbyhwtype);
+
struct net_device *dev_getfirstbyhwtype(unsigned short type)
{
struct net_device *dev;
rtnl_lock();
- for (dev = dev_base; dev; dev = dev->next) {
- if (dev->type == type) {
- dev_hold(dev);
- break;
- }
- }
+ dev = __dev_getfirstbyhwtype(type);
+ if (dev)
+ dev_hold(dev);
rtnl_unlock();
return dev;
}
@@ -606,17 +617,19 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)
{
- struct net_device *dev;
+ struct net_device *dev, *ret;
+ ret = NULL;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if (((dev->flags ^ if_flags) & mask) == 0) {
dev_hold(dev);
+ ret = dev;
break;
}
}
read_unlock(&dev_base_lock);
- return dev;
+ return ret;
}
/**
@@ -682,7 +695,7 @@ int dev_alloc_name(struct net_device *dev, const char *name)
if (!inuse)
return -ENOMEM;
- for (d = dev_base; d; d = d->next) {
+ for_each_netdev(d) {
if (!sscanf(d->name, name, &i))
continue;
if (i < 0 || i >= max_netdevices)
@@ -964,7 +977,7 @@ int register_netdevice_notifier(struct notifier_block *nb)
rtnl_lock();
err = raw_notifier_chain_register(&netdev_chain, nb);
if (!err) {
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
nb->notifier_call(nb, NETDEV_REGISTER, dev);
if (dev->flags & IFF_UP)
@@ -2038,7 +2051,7 @@ static int dev_ifconf(char __user *arg)
*/
total = 0;
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
for (i = 0; i < NPROTO; i++) {
if (gifconf_list[i]) {
int done;
@@ -2070,26 +2083,28 @@ static int dev_ifconf(char __user *arg)
* This is invoked by the /proc filesystem handler to display a device
* in detail.
*/
-static struct net_device *dev_get_idx(loff_t pos)
+void *dev_seq_start(struct seq_file *seq, loff_t *pos)
{
+ loff_t off;
struct net_device *dev;
- loff_t i;
- for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next);
+ read_lock(&dev_base_lock);
+ if (!*pos)
+ return SEQ_START_TOKEN;
- return i == pos ? dev : NULL;
-}
+ off = 1;
+ for_each_netdev(dev)
+ if (off++ == *pos)
+ return dev;
-void *dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
- read_lock(&dev_base_lock);
- return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
+ return NULL;
}
void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
- return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next;
+ return v == SEQ_START_TOKEN ?
+ first_net_device() : next_net_device((struct net_device *)v);
}
void dev_seq_stop(struct seq_file *seq, void *v)
@@ -2101,26 +2116,23 @@ static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
struct net_device_stats *stats = dev->get_stats(dev);
- if (stats) {
- seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
- "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
- dev->name, stats->rx_bytes, stats->rx_packets,
- stats->rx_errors,
- stats->rx_dropped + stats->rx_missed_errors,
- stats->rx_fifo_errors,
- stats->rx_length_errors + stats->rx_over_errors +
- stats->rx_crc_errors + stats->rx_frame_errors,
- stats->rx_compressed, stats->multicast,
- stats->tx_bytes, stats->tx_packets,
- stats->tx_errors, stats->tx_dropped,
- stats->tx_fifo_errors, stats->collisions,
- stats->tx_carrier_errors +
- stats->tx_aborted_errors +
- stats->tx_window_errors +
- stats->tx_heartbeat_errors,
- stats->tx_compressed);
- } else
- seq_printf(seq, "%6s: No statistics available.\n", dev->name);
+ seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
+ "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+ dev->name, stats->rx_bytes, stats->rx_packets,
+ stats->rx_errors,
+ stats->rx_dropped + stats->rx_missed_errors,
+ stats->rx_fifo_errors,
+ stats->rx_length_errors + stats->rx_over_errors +
+ stats->rx_crc_errors + stats->rx_frame_errors,
+ stats->rx_compressed, stats->multicast,
+ stats->tx_bytes, stats->tx_packets,
+ stats->tx_errors, stats->tx_dropped,
+ stats->tx_fifo_errors, stats->collisions,
+ stats->tx_carrier_errors +
+ stats->tx_aborted_errors +
+ stats->tx_window_errors +
+ stats->tx_heartbeat_errors,
+ stats->tx_compressed);
}
/*
@@ -2365,9 +2377,9 @@ static int __init dev_proc_init(void)
out:
return rc;
out_softnet:
- proc_net_remove("softnet_stat");
-out_dev2:
proc_net_remove("ptype");
+out_dev2:
+ proc_net_remove("softnet_stat");
out_dev:
proc_net_remove("dev");
goto out;
@@ -3074,11 +3086,9 @@ int register_netdevice(struct net_device *dev)
set_bit(__LINK_STATE_PRESENT, &dev->state);
- dev->next = NULL;
dev_init_scheduler(dev);
write_lock_bh(&dev_base_lock);
- *dev_tail = dev;
- dev_tail = &dev->next;
+ list_add_tail(&dev->dev_list, &dev_base_head);
hlist_add_head(&dev->name_hlist, head);
hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
dev_hold(dev);
@@ -3257,11 +3267,9 @@ out:
mutex_unlock(&net_todo_run_mutex);
}
-static struct net_device_stats *maybe_internal_stats(struct net_device *dev)
+static struct net_device_stats *internal_stats(struct net_device *dev)
{
- if (dev->features & NETIF_F_INTERNAL_STATS)
- return &dev->stats;
- return NULL;
+ return &dev->stats;
}
/**
@@ -3299,7 +3307,7 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
if (sizeof_priv)
dev->priv = netdev_priv(dev);
- dev->get_stats = maybe_internal_stats;
+ dev->get_stats = internal_stats;
setup(dev);
strcpy(dev->name, name);
return dev;
@@ -3354,8 +3362,6 @@ void synchronize_net(void)
void unregister_netdevice(struct net_device *dev)
{
- struct net_device *d, **dp;
-
BUG_ON(dev_boot_phase);
ASSERT_RTNL();
@@ -3375,19 +3381,11 @@ void unregister_netdevice(struct net_device *dev)
dev_close(dev);
/* And unlink it from device chain. */
- for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
- if (d == dev) {
- write_lock_bh(&dev_base_lock);
- hlist_del(&dev->name_hlist);
- hlist_del(&dev->index_hlist);
- if (dev_tail == &dev->next)
- dev_tail = dp;
- *dp = d->next;
- write_unlock_bh(&dev_base_lock);
- break;
- }
- }
- BUG_ON(!d);
+ write_lock_bh(&dev_base_lock);
+ list_del(&dev->dev_list);
+ hlist_del(&dev->name_hlist);
+ hlist_del(&dev->index_hlist);
+ write_unlock_bh(&dev_base_lock);
dev->reg_state = NETREG_UNREGISTERING;
@@ -3452,7 +3450,7 @@ static int dev_cpu_callback(struct notifier_block *nfb,
unsigned int cpu, oldcpu = (unsigned long)ocpu;
struct softnet_data *sd, *oldsd;
- if (action != CPU_DEAD)
+ if (action != CPU_DEAD && action != CPU_DEAD_FROZEN)
return NOTIFY_OK;
local_irq_disable();
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 7d57bf77f3a..5a54053386c 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -223,7 +223,7 @@ static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
loff_t off = 0;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if (off++ == *pos)
return dev;
}
@@ -232,9 +232,8 @@ static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct net_device *dev = v;
++*pos;
- return dev->next;
+ return next_net_device((struct net_device *)v);
}
static void dev_mc_seq_stop(struct seq_file *seq, void *v)
diff --git a/net/core/flow.c b/net/core/flow.c
index 5d25697920b..051430545a0 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -338,7 +338,7 @@ static int flow_cache_cpu(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
{
- if (action == CPU_DEAD)
+ if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)
__flow_cache_shrink((unsigned long)hcpu, 0);
return NOTIFY_OK;
}
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index b316435b0e2..758dafe284c 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -9,7 +9,6 @@
* Copyright (C) 2002 Red Hat, Inc.
*/
-#include <linux/smp_lock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/string.h>
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index b92a322872a..9cd3a1cb60e 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -117,7 +117,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/slab.h>
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index cec11110915..8c971a2efe2 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -539,13 +539,16 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
int s_idx = cb->args[0];
struct net_device *dev;
- for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (rtnl_fill_ifinfo(skb, dev, NULL, 0, RTM_NEWLINK,
NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)
break;
+cont:
+ idx++;
}
cb->args[0] = idx;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 32f087b5233..142257307fa 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1045,13 +1045,13 @@ pull_pages:
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
{
int i, copy;
- int end = skb_headlen(skb);
+ int start = skb_headlen(skb);
if (offset > (int)skb->len - len)
goto fault;
/* Copy header. */
- if ((copy = end - offset) > 0) {
+ if ((copy = start - offset) > 0) {
if (copy > len)
copy = len;
skb_copy_from_linear_data_offset(skb, offset, to, copy);
@@ -1062,9 +1062,11 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
u8 *vaddr;
@@ -1073,8 +1075,8 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
memcpy(to,
- vaddr + skb_shinfo(skb)->frags[i].page_offset,
- copy);
+ vaddr + skb_shinfo(skb)->frags[i].page_offset+
+ offset - start, copy);
kunmap_skb_frag(vaddr);
if ((len -= copy) == 0)
@@ -1082,25 +1084,30 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
offset += copy;
to += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (skb_copy_bits(list, 0, to, copy))
+ if (skb_copy_bits(list, offset - start,
+ to, copy))
goto fault;
if ((len -= copy) == 0)
return 0;
offset += copy;
to += copy;
}
+ start = end;
}
}
if (!len)
@@ -1125,12 +1132,12 @@ fault:
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
{
int i, copy;
- int end = skb_headlen(skb);
+ int start = skb_headlen(skb);
if (offset > (int)skb->len - len)
goto fault;
- if ((copy = end - offset) > 0) {
+ if ((copy = start - offset) > 0) {
if (copy > len)
copy = len;
skb_copy_to_linear_data_offset(skb, offset, from, copy);
@@ -1142,9 +1149,11 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + frag->size;
+ end = start + frag->size;
if ((copy = end - offset) > 0) {
u8 *vaddr;
@@ -1152,7 +1161,8 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
copy = len;
vaddr = kmap_skb_frag(frag);
- memcpy(vaddr + frag->page_offset, from, copy);
+ memcpy(vaddr + frag->page_offset + offset - start,
+ from, copy);
kunmap_skb_frag(vaddr);
if ((len -= copy) == 0)
@@ -1160,25 +1170,30 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
offset += copy;
from += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + list->len;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- if (skb_store_bits(list, 0, from, copy))
+ if (skb_store_bits(list, offset - start,
+ from, copy))
goto fault;
if ((len -= copy) == 0)
return 0;
offset += copy;
from += copy;
}
+ start = end;
}
}
if (!len)
@@ -1195,8 +1210,8 @@ EXPORT_SYMBOL(skb_store_bits);
__wsum skb_checksum(const struct sk_buff *skb, int offset,
int len, __wsum csum)
{
- int end = skb_headlen(skb);
- int i, copy = end - offset;
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
int pos = 0;
/* Checksum header. */
@@ -1211,9 +1226,11 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
__wsum csum2;
u8 *vaddr;
@@ -1222,8 +1239,8 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
if (copy > len)
copy = len;
vaddr = kmap_skb_frag(frag);
- csum2 = csum_partial(vaddr + frag->page_offset,
- copy, 0);
+ csum2 = csum_partial(vaddr + frag->page_offset +
+ offset - start, copy, 0);
kunmap_skb_frag(vaddr);
csum = csum_block_add(csum, csum2, pos);
if (!(len -= copy))
@@ -1231,26 +1248,31 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
offset += copy;
pos += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + list->len;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + list->len;
if ((copy = end - offset) > 0) {
__wsum csum2;
if (copy > len)
copy = len;
- csum2 = skb_checksum(list, 0, copy, 0);
+ csum2 = skb_checksum(list, offset - start,
+ copy, 0);
csum = csum_block_add(csum, csum2, pos);
if ((len -= copy) == 0)
return csum;
offset += copy;
pos += copy;
}
+ start = end;
}
}
BUG_ON(len);
@@ -1263,8 +1285,8 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
u8 *to, int len, __wsum csum)
{
- int end = skb_headlen(skb);
- int i, copy = end - offset;
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
int pos = 0;
/* Copy header. */
@@ -1281,9 +1303,11 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + skb_shinfo(skb)->frags[i].size;
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
__wsum csum2;
u8 *vaddr;
@@ -1293,8 +1317,9 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
copy = len;
vaddr = kmap_skb_frag(frag);
csum2 = csum_partial_copy_nocheck(vaddr +
- frag->page_offset,
- to, copy, 0);
+ frag->page_offset +
+ offset - start, to,
+ copy, 0);
kunmap_skb_frag(vaddr);
csum = csum_block_add(csum, csum2, pos);
if (!(len -= copy))
@@ -1303,6 +1328,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
to += copy;
pos += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
@@ -1310,13 +1336,16 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
for (; list; list = list->next) {
__wsum csum2;
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- csum2 = skb_copy_and_csum_bits(list, 0,
+ csum2 = skb_copy_and_csum_bits(list,
+ offset - start,
to, copy, 0);
csum = csum_block_add(csum, csum2, pos);
if ((len -= copy) == 0)
@@ -1325,6 +1354,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
to += copy;
pos += copy;
}
+ start = end;
}
}
BUG_ON(len);
@@ -1996,8 +2026,8 @@ void __init skb_init(void)
int
skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
{
- int end = skb_headlen(skb);
- int i, copy = end - offset;
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
int elt = 0;
if (copy > 0) {
@@ -2013,39 +2043,45 @@ skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
if (copy > len)
copy = len;
sg[elt].page = frag->page;
- sg[elt].offset = frag->page_offset;
+ sg[elt].offset = frag->page_offset+offset-start;
sg[elt].length = copy;
elt++;
if (!(len -= copy))
return elt;
offset += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- elt += skb_to_sgvec(list, sg+elt, 0, copy);
+ elt += skb_to_sgvec(list, sg+elt, offset - start, copy);
if ((len -= copy) == 0)
return elt;
offset += copy;
}
+ start = end;
}
}
BUG_ON(len);
diff --git a/net/core/user_dma.c b/net/core/user_dma.c
index 89241cdeea3..0ad1cd57bc3 100644
--- a/net/core/user_dma.c
+++ b/net/core/user_dma.c
@@ -49,8 +49,8 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
struct sk_buff *skb, int offset, struct iovec *to,
size_t len, struct dma_pinned_list *pinned_list)
{
- int end = skb_headlen(skb);
- int i, copy = end - offset;
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
dma_cookie_t cookie = 0;
/* Copy header. */
@@ -69,9 +69,11 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
/* Copy paged appendix. Hmm... why does this look so complicated? */
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
copy = end - offset;
if ((copy = end - offset) > 0) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -80,8 +82,8 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
if (copy > len)
copy = len;
- cookie = dma_memcpy_pg_to_iovec(chan, to, pinned_list,
- page, frag->page_offset, copy);
+ cookie = dma_memcpy_pg_to_iovec(chan, to, pinned_list, page,
+ frag->page_offset + offset - start, copy);
if (cookie < 0)
goto fault;
len -= copy;
@@ -89,21 +91,25 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
goto end;
offset += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
copy = end - offset;
if (copy > 0) {
if (copy > len)
copy = len;
cookie = dma_skb_copy_datagram_iovec(chan, list,
- 0, to, copy, pinned_list);
+ offset - start, to, copy,
+ pinned_list);
if (cookie < 0)
goto fault;
len -= copy;
@@ -111,6 +117,7 @@ int dma_skb_copy_datagram_iovec(struct dma_chan *chan,
goto end;
offset += copy;
}
+ start = end;
}
}
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index a205eaa87f5..bfa910b6ad2 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -721,7 +721,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
- struct net_device *dev;
+ struct net_device *dev, *ldev;
int rv;
if (addr_len != sizeof(struct sockaddr_dn))
@@ -746,14 +746,17 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if (!(saddr->sdn_flags & SDF_WILD)) {
if (dn_ntohs(saddr->sdn_nodeaddrl)) {
read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
+ ldev = NULL;
+ for_each_netdev(dev) {
if (!dev->dn_ptr)
continue;
- if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
+ if (dn_dev_islocal(dev, dn_saddr2dn(saddr))) {
+ ldev = dev;
break;
+ }
}
read_unlock(&dev_base_lock);
- if (dev == NULL)
+ if (ldev == NULL)
return -EADDRNOTAVAIL;
}
}
@@ -1836,7 +1839,7 @@ static inline int dn_queue_too_long(struct dn_scp *scp, struct sk_buff_head *que
}
/*
- * The DECnet spec requires the the "routing layer" accepts packets which
+ * The DECnet spec requires that the "routing layer" accepts packets which
* are at least 230 bytes in size. This excludes any headers which the NSP
* layer might add, so we always assume that we'll be using the maximal
* length header on data packets. The variation in length is due to the
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 5c2a9951b63..764a56a13e3 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -799,9 +799,10 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
skip_ndevs = cb->args[0];
skip_naddr = cb->args[1];
- for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < skip_ndevs)
- continue;
+ goto cont;
else if (idx > skip_ndevs) {
/* Only skip over addresses for first dev dumped
* in this iteration (idx == skip_ndevs) */
@@ -809,18 +810,20 @@ static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
}
if ((dn_db = dev->dn_ptr) == NULL)
- continue;
+ goto cont;
for (ifa = dn_db->ifa_list, dn_idx = 0; ifa;
ifa = ifa->ifa_next, dn_idx++) {
if (dn_idx < skip_naddr)
- continue;
+ goto cont;
if (dn_nl_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWADDR,
NLM_F_MULTI) < 0)
goto done;
}
+cont:
+ idx++;
}
done:
cb->args[0] = idx;
@@ -1296,7 +1299,7 @@ void dn_dev_devices_off(void)
struct net_device *dev;
rtnl_lock();
- for(dev = dev_base; dev; dev = dev->next)
+ for_each_netdev(dev)
dn_dev_down(dev);
rtnl_unlock();
@@ -1307,7 +1310,7 @@ void dn_dev_devices_on(void)
struct net_device *dev;
rtnl_lock();
- for(dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if (dev->flags & IFF_UP)
dn_dev_up(dev);
}
@@ -1325,62 +1328,56 @@ int unregister_dnaddr_notifier(struct notifier_block *nb)
}
#ifdef CONFIG_PROC_FS
-static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
+static inline int is_dn_dev(struct net_device *dev)
{
- do {
- dev = dev->next;
- } while(dev && !dev->dn_ptr);
-
- return dev;
+ return dev->dn_ptr != NULL;
}
-static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
+static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
{
+ int i;
struct net_device *dev;
- dev = dev_base;
- if (dev && !dev->dn_ptr)
- dev = dn_dev_get_next(seq, dev);
- if (pos) {
- while(dev && (dev = dn_dev_get_next(seq, dev)))
- --pos;
- }
- return dev;
-}
+ read_lock(&dev_base_lock);
-static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
-{
- if (*pos) {
- struct net_device *dev;
- read_lock(&dev_base_lock);
- dev = dn_dev_get_idx(seq, *pos - 1);
- if (dev == NULL)
- read_unlock(&dev_base_lock);
- return dev;
+ if (*pos == 0)
+ return SEQ_START_TOKEN;
+
+ i = 1;
+ for_each_netdev(dev) {
+ if (!is_dn_dev(dev))
+ continue;
+
+ if (i++ == *pos)
+ return dev;
}
- return SEQ_START_TOKEN;
+
+ return NULL;
}
static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct net_device *dev = v;
- loff_t one = 1;
+ struct net_device *dev;
- if (v == SEQ_START_TOKEN) {
- dev = dn_dev_seq_start(seq, &one);
- } else {
- dev = dn_dev_get_next(seq, dev);
- if (dev == NULL)
- read_unlock(&dev_base_lock);
- }
++*pos;
- return dev;
+
+ dev = (struct net_device *)v;
+ if (v == SEQ_START_TOKEN)
+ dev = net_device_entry(&dev_base_head);
+
+ for_each_netdev_continue(dev) {
+ if (!is_dn_dev(dev))
+ continue;
+
+ return dev;
+ }
+
+ return NULL;
}
static void dn_dev_seq_stop(struct seq_file *seq, void *v)
{
- if (v && v != SEQ_START_TOKEN)
- read_unlock(&dev_base_lock);
+ read_unlock(&dev_base_lock);
}
static char *dn_type2asc(char type)
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index 310a86268d2..d2bc19d4795 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -602,7 +602,7 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
/* Scan device list */
read_lock(&dev_base_lock);
- for(dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
dn_db = dev->dn_ptr;
if (dn_db == NULL)
continue;
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 5d7337bcf0f..a8bf106b7a6 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -886,7 +886,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
.iif = loopback_dev.ifindex,
.oif = oldflp->oif };
struct dn_route *rt = NULL;
- struct net_device *dev_out = NULL;
+ struct net_device *dev_out = NULL, *dev;
struct neighbour *neigh = NULL;
unsigned hash;
unsigned flags = 0;
@@ -925,15 +925,17 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
goto out;
}
read_lock(&dev_base_lock);
- for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
- if (!dev_out->dn_ptr)
+ for_each_netdev(dev) {
+ if (!dev->dn_ptr)
continue;
- if (!dn_dev_islocal(dev_out, oldflp->fld_src))
+ if (!dn_dev_islocal(dev, oldflp->fld_src))
continue;
- if ((dev_out->flags & IFF_LOOPBACK) &&
+ if ((dev->flags & IFF_LOOPBACK) &&
oldflp->fld_dst &&
- !dn_dev_islocal(dev_out, oldflp->fld_dst))
+ !dn_dev_islocal(dev, oldflp->fld_dst))
continue;
+
+ dev_out = dev;
break;
}
read_unlock(&dev_base_lock);
diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c
index 5ed0a98b2d7..df5592c9339 100644
--- a/net/ieee80211/ieee80211_crypt.c
+++ b/net/ieee80211/ieee80211_crypt.c
@@ -1,7 +1,7 @@
/*
* Host AP crypto routines
*
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Portions Copyright (C) 2004, Intel Corporation <jketreno@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/ieee80211/ieee80211_crypt_ccmp.c
index 35aa3426c3f..b016b4104de 100644
--- a/net/ieee80211/ieee80211_crypt_ccmp.c
+++ b/net/ieee80211/ieee80211_crypt_ccmp.c
@@ -1,7 +1,7 @@
/*
* Host AP crypt: host-based CCMP encryption implementation for Host AP driver
*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
*
* 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
@@ -338,7 +338,7 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (ccmp_replay_check(pn, key->rx_pn)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
+ IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=" MAC_FMT
" previous PN %02x%02x%02x%02x%02x%02x "
"received PN %02x%02x%02x%02x%02x%02x\n",
MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/ieee80211/ieee80211_crypt_tkip.c
index fc1f99a5973..5a48d8e0aec 100644
--- a/net/ieee80211/ieee80211_crypt_tkip.c
+++ b/net/ieee80211/ieee80211_crypt_tkip.c
@@ -1,7 +1,7 @@
/*
* Host AP crypt: host-based TKIP encryption implementation for Host AP driver
*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
*
* 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
@@ -465,7 +465,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
+ IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=" MAC_FMT
" previous TSC %08x%04x received TSC "
"%08x%04x\n", MAC_ARG(hdr->addr2),
tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
@@ -507,7 +507,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
tkey->rx_phase1_done = 0;
}
if (net_ratelimit()) {
- printk(KERN_DEBUG "TKIP: ICV error detected: STA="
+ IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA="
MAC_FMT "\n", MAC_ARG(hdr->addr2));
}
tkey->dot11RSNAStatsTKIPICVErrors++;
diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/ieee80211/ieee80211_crypt_wep.c
index 4eb35079e43..8d182459344 100644
--- a/net/ieee80211/ieee80211_crypt_wep.c
+++ b/net/ieee80211/ieee80211_crypt_wep.c
@@ -1,7 +1,7 @@
/*
* Host AP crypt: host-based WEP encryption implementation for Host AP driver
*
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
*
* 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
diff --git a/net/ieee80211/ieee80211_module.c b/net/ieee80211/ieee80211_module.c
index b1c6d1f717d..7ec6610841b 100644
--- a/net/ieee80211/ieee80211_module.c
+++ b/net/ieee80211/ieee80211_module.c
@@ -5,8 +5,8 @@
Portions of this file are based on the WEP enablement code provided by the
Host AP project hostap-drivers v0.1.3
Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
@@ -229,6 +229,7 @@ void free_ieee80211(struct net_device *dev)
static int debug = 0;
u32 ieee80211_debug_level = 0;
+EXPORT_SYMBOL_GPL(ieee80211_debug_level);
static struct proc_dir_entry *ieee80211_proc = NULL;
static int show_debug_level(char *page, char **start, off_t offset,
diff --git a/net/ieee80211/ieee80211_rx.c b/net/ieee80211/ieee80211_rx.c
index 6ae036b1920..f2de2e48b02 100644
--- a/net/ieee80211/ieee80211_rx.c
+++ b/net/ieee80211/ieee80211_rx.c
@@ -3,8 +3,8 @@
* for Intersil Prism2/2.5/3 - hostap.o module, common routines
*
* Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <jkmaline@cc.hut.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * <j@w1.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2005, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 40d7a55fe03..cee5e13bc42 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -5,8 +5,8 @@
Portions of this file are based on the WEP enablement code provided by the
Host AP project hostap-drivers v0.1.3
Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <jkmaline@cc.hut.fi>
- Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ <j@w1.fi>
+ Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
This program is free software; you can redistribute it and/or modify it
under the terms of version 2 of the GNU General Public License as
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index e62aee0ec4c..c68196cc56a 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -130,7 +130,7 @@ config IP_ROUTE_MULTIPATH_RR
tristate "MULTIPATH: round robin algorithm"
depends on IP_ROUTE_MULTIPATH_CACHED
help
- Mulitpath routes are chosen according to Round Robin
+ Multipath routes are chosen according to Round Robin
config IP_ROUTE_MULTIPATH_RANDOM
tristate "MULTIPATH: random algorithm"
@@ -651,7 +651,7 @@ config TCP_MD5SIG
select CRYPTO
select CRYPTO_MD5
---help---
- RFC2385 specifices a method of giving MD5 protection to TCP sessions.
+ RFC2385 specifies a method of giving MD5 protection to TCP sessions.
Its main (only?) use is to protect BGP sessions between core routers
on the Internet.
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 16aae8ef555..041fba3fa0a 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -92,7 +92,6 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <linux/smp_lock.h>
#include <linux/inet.h>
#include <linux/igmp.h>
#include <linux/inetdevice.h>
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index e1f18489db1..86a2b52aad3 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -629,7 +629,7 @@ doi_walk_return:
* @domain: the domain to add
*
* Description:
- * Adds the @domain to the the DOI specified by @doi_def, this function
+ * Adds the @domain to the DOI specified by @doi_def, this function
* should only be called by external functions (i.e. NetLabel). This function
* does allocate memory. Returns zero on success, negative values on failure.
*
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 088888db8b3..7f95e6e9bee 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -910,7 +910,7 @@ no_in_dev:
*/
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
continue;
@@ -989,7 +989,7 @@ __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local,
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if ((in_dev = __in_dev_get_rcu(dev))) {
addr = confirm_addr_indev(in_dev, dst, local, scope);
if (addr)
@@ -1182,23 +1182,26 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
int s_ip_idx, s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
- for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (idx > s_idx)
s_ip_idx = 0;
if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
- continue;
+ goto cont;
for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
ifa = ifa->ifa_next, ip_idx++) {
if (ip_idx < s_ip_idx)
- continue;
+ goto cont;
if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
RTM_NEWADDR, NLM_F_MULTI) <= 0)
goto done;
}
+cont:
+ idx++;
}
done:
@@ -1243,7 +1246,7 @@ void inet_forward_change(void)
ipv4_devconf_dflt.forwarding = on;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 2506021c293..f4dd4745310 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -2288,9 +2288,8 @@ static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
struct ip_mc_list *im = NULL;
struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
- for (state->dev = dev_base, state->in_dev = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->in_dev = NULL;
+ for_each_netdev(state->dev) {
struct in_device *in_dev;
in_dev = in_dev_get(state->dev);
if (!in_dev)
@@ -2316,7 +2315,7 @@ static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_li
read_unlock(&state->in_dev->mc_list_lock);
in_dev_put(state->in_dev);
}
- state->dev = state->dev->next;
+ state->dev = next_net_device(state->dev);
if (!state->dev) {
state->in_dev = NULL;
break;
@@ -2450,9 +2449,9 @@ static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
struct ip_mc_list *im = NULL;
struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->idev = NULL;
+ state->im = NULL;
+ for_each_netdev(state->dev) {
struct in_device *idev;
idev = in_dev_get(state->dev);
if (unlikely(idev == NULL))
@@ -2488,7 +2487,7 @@ static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_l
read_unlock(&state->idev->mc_list_lock);
in_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_net_device(state->dev);
if (!state->dev) {
state->idev = NULL;
goto out;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 324e7e0fdb2..97069399d86 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -329,6 +329,7 @@ drop:
static inline int ip_rcv_finish(struct sk_buff *skb)
{
const struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt;
/*
* Initialise the virtual path cache for the packet. It describes
@@ -340,6 +341,8 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
if (unlikely(err)) {
if (err == -EHOSTUNREACH)
IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+ else if (err == -ENETUNREACH)
+ IP_INC_STATS_BH(IPSTATS_MIB_INNOROUTES);
goto drop;
}
}
@@ -358,6 +361,12 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
if (iph->ihl > 5 && ip_rcv_options(skb))
goto drop;
+ rt = (struct rtable*)skb->dst;
+ if (rt->rt_type == RTN_MULTICAST)
+ IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
+ else if (rt->rt_type == RTN_BROADCAST)
+ IP_INC_STATS_BH(IPSTATS_MIB_INBCASTPKTS);
+
return dst_input(skb);
drop:
@@ -414,7 +423,10 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt,
goto inhdr_error;
len = ntohs(iph->tot_len);
- if (skb->len < len || len < (iph->ihl*4))
+ if (skb->len < len) {
+ IP_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
+ goto drop;
+ } else if (len < (iph->ihl*4))
goto inhdr_error;
/* Our transport medium may have padded the buffer out. Now we know it
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 534650cad3a..d6427d91851 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -160,9 +160,15 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
static inline int ip_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
+ struct rtable *rt = (struct rtable *)dst;
struct net_device *dev = dst->dev;
int hh_len = LL_RESERVED_SPACE(dev);
+ if (rt->rt_type == RTN_MULTICAST)
+ IP_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
+ else if (rt->rt_type == RTN_BROADCAST)
+ IP_INC_STATS(IPSTATS_MIB_OUTBCASTPKTS);
+
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->hard_header)) {
struct sk_buff *skb2;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 597c800b2fd..342ca8d8945 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -192,7 +192,7 @@ static int __init ic_open_devs(void)
if (dev_change_flags(&loopback_dev, loopback_dev.flags | IFF_UP) < 0)
printk(KERN_ERR "IP-Config: Failed to open %s\n", loopback_dev.name);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
if (dev == &loopback_dev)
continue;
if (user_dev_name[0] ? !strcmp(dev->name, user_dev_name) :
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index b3050a6817e..68fe1d4d021 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -2387,6 +2387,7 @@ void ip_vs_control_cleanup(void)
EnterFunction(2);
ip_vs_trash_cleanup();
cancel_rearming_delayed_work(&defense_work);
+ cancel_work_sync(&defense_work.work);
ip_vs_kill_estimator(&ip_vs_stats);
unregister_sysctl_table(sysctl_header);
proc_net_remove("ip_vs_stats");
diff --git a/net/ipv4/ipvs/ip_vs_sed.c b/net/ipv4/ipvs/ip_vs_sed.c
index ff366f7390d..dd7c128f9db 100644
--- a/net/ipv4/ipvs/ip_vs_sed.c
+++ b/net/ipv4/ipvs/ip_vs_sed.c
@@ -18,7 +18,7 @@
* The SED algorithm attempts to minimize each job's expected delay until
* completion. The expected delay that the job will experience is
* (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of
- * jobs on the the ith server and Ui is the fixed service rate (weight) of
+ * jobs on the ith server and Ui is the fixed service rate (weight) of
* the ith server. The SED algorithm adopts a greedy policy that each does
* what is in its own best interest, i.e. to join the queue which would
* minimize its expected delay of completion.
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index e5a34c17d92..c3908bc5a70 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -72,6 +72,11 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
__be16 *keyptr;
unsigned int min, i, range_size;
+ /* If there is no master conntrack we are not PPTP,
+ do not change tuples */
+ if (!conntrack->master)
+ return 0;
+
if (maniptype == IP_NAT_MANIP_SRC)
keyptr = &tuple->src.u.gre.key;
else
@@ -122,18 +127,9 @@ gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff,
if (maniptype != IP_NAT_MANIP_DST)
return 1;
switch (greh->version) {
- case 0:
- if (!greh->key) {
- DEBUGP("can't nat GRE w/o key\n");
- break;
- }
- if (greh->csum) {
- /* FIXME: Never tested this code... */
- nf_proto_csum_replace4(gre_csum(greh), *pskb,
- *(gre_key(greh)),
- tuple->dst.u.gre.key, 0);
- }
- *(gre_key(greh)) = tuple->dst.u.gre.key;
+ case GRE_VERSION_1701:
+ /* We do not currently NAT any GREv0 packets.
+ * Try to behave like "nf_nat_proto_unknown" */
break;
case GRE_VERSION_PPTP:
DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 2a283397a8b..2534f718ab9 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -226,10 +226,6 @@ static int ipt_dnat_checkentry(const char *tablename,
printk("DNAT: multiple ranges no longer supported\n");
return 0;
}
- if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) {
- printk("DNAT: port randomization not supported\n");
- return 0;
- }
return 1;
}
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index bfd88e4e068..fac97cf51ae 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -222,6 +222,29 @@ static unsigned int mangle_sdp(struct sk_buff **pskb,
return mangle_content_len(pskb, ctinfo, ct, dptr);
}
+static void ip_nat_sdp_expect(struct nf_conn *ct,
+ struct nf_conntrack_expect *exp)
+{
+ struct nf_nat_range range;
+
+ /* This must be a fresh one. */
+ BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+
+ /* Change src to where master sends to */
+ range.flags = IP_NAT_RANGE_MAP_IPS;
+ range.min_ip = range.max_ip
+ = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+ /* hook doesn't matter, but it has to do source manip */
+ nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+
+ /* For DST manip, map port here to where it's expected. */
+ range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+ range.min = range.max = exp->saved_proto;
+ range.min_ip = range.max_ip = exp->saved_ip;
+ /* hook doesn't matter, but it has to do destination manip */
+ nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+}
+
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff **pskb,
@@ -239,13 +262,14 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
/* Connection will come from reply */
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+ exp->saved_ip = exp->tuple.dst.u3.ip;
exp->tuple.dst.u3.ip = newip;
exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
exp->dir = !dir;
/* When you see the packet, we need to NAT it the same as the
this one. */
- exp->expectfn = nf_nat_follow_master;
+ exp->expectfn = ip_nat_sdp_expect;
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 2cf9a898ce5..bd4c295f5d7 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -252,7 +252,6 @@
#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/fs.h>
#include <linux/random.h>
#include <linux/bootmem.h>
@@ -1573,14 +1572,12 @@ void tcp_close(struct sock *sk, long timeout)
sk_stream_mem_reclaim(sk);
- /* As outlined in draft-ietf-tcpimpl-prob-03.txt, section
- * 3.10, we send a RST here because data was lost. To
- * witness the awful effects of the old behavior of always
- * doing a FIN, run an older 2.1.x kernel or 2.0.x, start
- * a bulk GET in an FTP client, suspend the process, wait
- * for the client to advertise a zero window, then kill -9
- * the FTP client, wheee... Note: timeout is always zero
- * in such a case.
+ /* As outlined in RFC 2525, section 2.17, we send a RST here because
+ * data was lost. To witness the awful effects of the old behavior of
+ * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
+ * GET in an FTP client, suspend the process, wait for the client to
+ * advertise a zero window, then kill -9 the FTP client, wheee...
+ * Note: timeout is always zero in such a case.
*/
if (data_was_unread) {
/* Unread data was tossed, zap the connection. */
@@ -1762,8 +1759,7 @@ int tcp_disconnect(struct sock *sk, int flags)
tcp_clear_retrans(tp);
inet_csk_delack_init(sk);
tcp_init_send_head(sk);
- tp->rx_opt.saw_tstamp = 0;
- tcp_sack_reset(&tp->rx_opt);
+ memset(&tp->rx_opt, 0, sizeof(tp->rx_opt));
__sk_dst_reset(sk);
BUG_TRAP(!inet->num || icsk->icsk_bind_hash);
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index a291097fcc0..43d624e5043 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -97,10 +97,6 @@ struct hstcp {
u32 ai;
};
-static int max_ssthresh = 100;
-module_param(max_ssthresh, int, 0644);
-MODULE_PARM_DESC(max_ssthresh, "limited slow start threshold (RFC3742)");
-
static void hstcp_init(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -122,23 +118,9 @@ static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
if (!tcp_is_cwnd_limited(sk, in_flight))
return;
- if (tp->snd_cwnd <= tp->snd_ssthresh) {
- /* RFC3742: limited slow start
- * the window is increased by 1/K MSS for each arriving ACK,
- * for K = int(cwnd/(0.5 max_ssthresh))
- */
- if (max_ssthresh > 0 && tp->snd_cwnd > max_ssthresh) {
- u32 k = max(tp->snd_cwnd / (max_ssthresh >> 1), 1U);
- if (++tp->snd_cwnd_cnt >= k) {
- if (tp->snd_cwnd < tp->snd_cwnd_clamp)
- tp->snd_cwnd++;
- tp->snd_cwnd_cnt = 0;
- }
- } else {
- if (tp->snd_cwnd < tp->snd_cwnd_clamp)
- tp->snd_cwnd++;
- }
- } else {
+ if (tp->snd_cwnd <= tp->snd_ssthresh)
+ tcp_slow_start(tp);
+ else {
/* Update AIMD parameters.
*
* We want to guarantee that:
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 051f0f815f1..7641b2761a1 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1265,20 +1265,15 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
return flag;
}
-/* F-RTO can only be used if these conditions are satisfied:
- * - there must be some unsent new data
- * - the advertised window should allow sending it
- * - TCP has never retransmitted anything other than head (SACK enhanced
- * variant from Appendix B of RFC4138 is more robust here)
+/* F-RTO can only be used if TCP has never retransmitted anything other than
+ * head (SACK enhanced variant from Appendix B of RFC4138 is more robust here)
*/
int tcp_use_frto(struct sock *sk)
{
const struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
- if (!sysctl_tcp_frto || !tcp_send_head(sk) ||
- after(TCP_SKB_CB(tcp_send_head(sk))->end_seq,
- tp->snd_una + tp->snd_wnd))
+ if (!sysctl_tcp_frto)
return 0;
if (IsSackFrto())
@@ -2642,7 +2637,9 @@ static void tcp_undo_spur_to_response(struct sock *sk, int flag)
* algorithm is not part of the F-RTO detection algorithm
* given in RFC4138 but can be selected separately).
* Otherwise (basically on duplicate ACK), RTO was (likely) caused by a loss
- * and TCP falls back to conventional RTO recovery.
+ * and TCP falls back to conventional RTO recovery. F-RTO allows overriding
+ * of Nagle, this is done using frto_counter states 2 and 3, when a new data
+ * segment of any size sent during F-RTO, state 2 is upgraded to 3.
*
* Rationale: if the RTO was spurious, new ACKs should arrive from the
* original window even after we transmit two new data segments.
@@ -2671,7 +2668,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
inet_csk(sk)->icsk_retransmits = 0;
if (!before(tp->snd_una, tp->frto_highmark)) {
- tcp_enter_frto_loss(sk, tp->frto_counter + 1, flag);
+ tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3), flag);
return 1;
}
@@ -2697,7 +2694,7 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
return 1;
}
- if ((tp->frto_counter == 2) &&
+ if ((tp->frto_counter >= 2) &&
(!(flag&FLAG_FORWARD_PROGRESS) ||
((flag&FLAG_DATA_SACKED) && !(flag&FLAG_ONLY_ORIG_SACKED)))) {
/* RFC4138 shortcoming (see comment above) */
@@ -2710,10 +2707,19 @@ static int tcp_process_frto(struct sock *sk, u32 prior_snd_una, int flag)
}
if (tp->frto_counter == 1) {
+ /* Sending of the next skb must be allowed or no FRTO */
+ if (!tcp_send_head(sk) ||
+ after(TCP_SKB_CB(tcp_send_head(sk))->end_seq,
+ tp->snd_una + tp->snd_wnd)) {
+ tcp_enter_frto_loss(sk, (tp->frto_counter == 1 ? 2 : 3),
+ flag);
+ return 1;
+ }
+
tp->snd_cwnd = tcp_packets_in_flight(tp) + 2;
tp->frto_counter = 2;
return 1;
- } else /* frto_counter == 2 */ {
+ } else {
switch (sysctl_tcp_frto_response) {
case 2:
tcp_undo_spur_to_response(sk, flag);
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e70a6840cb6..53232dd6fb4 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -40,7 +40,6 @@
#include <linux/compiler.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
/* People can turn this off for buggy TCP's found in printers etc. */
int sysctl_tcp_retrans_collapse __read_mostly = 1;
@@ -1035,8 +1034,10 @@ static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
if (nonagle & TCP_NAGLE_PUSH)
return 1;
- /* Don't use the nagle rule for urgent data (or for the final FIN). */
- if (tp->urg_mode ||
+ /* Don't use the nagle rule for urgent data (or for the final FIN).
+ * Nagle can be ignored during F-RTO too (see RFC4138).
+ */
+ if (tp->urg_mode || (tp->frto_counter == 2) ||
(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
return 1;
@@ -2035,7 +2036,7 @@ void tcp_send_fin(struct sock *sk)
/* We get here when a process closes a file descriptor (either due to
* an explicit close() or as a byproduct of exit()'ing) and there
* was unread data in the receive queue. This behavior is recommended
- * by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM
+ * by RFC 2525, section 2.17. -DaveM
*/
void tcp_send_active_reset(struct sock *sk, gfp_t priority)
{
diff --git a/net/ipv4/tcp_yeah.h b/net/ipv4/tcp_yeah.h
deleted file mode 100644
index ed3b7198f23..00000000000
--- a/net/ipv4/tcp_yeah.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/skbuff.h>
-#include <linux/inet_diag.h>
-#include <asm/div64.h>
-
-#include <net/tcp.h>
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index cec0f2cc49b..66026df1cc7 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -114,14 +114,33 @@ DEFINE_RWLOCK(udp_hash_lock);
static int udp_port_rover;
-static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])
+/*
+ * Note about this hash function :
+ * Typical use is probably daddr = 0, only dport is going to vary hash
+ */
+static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr)
+{
+ addr ^= addr >> 16;
+ addr ^= addr >> 8;
+ return port ^ addr;
+}
+
+static inline int __udp_lib_port_inuse(unsigned int hash, int port,
+ __be32 daddr, struct hlist_head udptable[])
{
struct sock *sk;
struct hlist_node *node;
+ struct inet_sock *inet;
- sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
- if (sk->sk_hash == num)
+ sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
+ if (sk->sk_hash != hash)
+ continue;
+ inet = inet_sk(sk);
+ if (inet->num != port)
+ continue;
+ if (inet->rcv_saddr == daddr)
return 1;
+ }
return 0;
}
@@ -142,6 +161,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_node *node;
struct hlist_head *head;
struct sock *sk2;
+ unsigned int hash;
int error = 1;
write_lock_bh(&udp_hash_lock);
@@ -156,7 +176,9 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
int size;
- head = &udptable[result & (UDP_HTABLE_SIZE - 1)];
+ hash = hash_port_and_addr(result,
+ inet_sk(sk)->rcv_saddr);
+ head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
if (hlist_empty(head)) {
if (result > sysctl_local_port_range[1])
result = sysctl_local_port_range[0] +
@@ -181,7 +203,17 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
result = sysctl_local_port_range[0]
+ ((result - sysctl_local_port_range[0]) &
(UDP_HTABLE_SIZE - 1));
- if (! __udp_lib_lport_inuse(result, udptable))
+ hash = hash_port_and_addr(result, 0);
+ if (__udp_lib_port_inuse(hash, result,
+ 0, udptable))
+ continue;
+ if (!inet_sk(sk)->rcv_saddr)
+ break;
+
+ hash = hash_port_and_addr(result,
+ inet_sk(sk)->rcv_saddr);
+ if (! __udp_lib_port_inuse(hash, result,
+ inet_sk(sk)->rcv_saddr, udptable))
break;
}
if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@@ -189,21 +221,41 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
gotit:
*port_rover = snum = result;
} else {
- head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
+ hash = hash_port_and_addr(snum, 0);
+ head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head)
- if (sk2->sk_hash == snum &&
- sk2 != sk &&
- (!sk2->sk_reuse || !sk->sk_reuse) &&
- (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
- || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
- (*saddr_comp)(sk, sk2) )
+ if (sk2->sk_hash == hash &&
+ sk2 != sk &&
+ inet_sk(sk2)->num == snum &&
+ (!sk2->sk_reuse || !sk->sk_reuse) &&
+ (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
+ sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
+ (*saddr_comp)(sk, sk2))
goto fail;
+
+ if (inet_sk(sk)->rcv_saddr) {
+ hash = hash_port_and_addr(snum,
+ inet_sk(sk)->rcv_saddr);
+ head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
+
+ sk_for_each(sk2, node, head)
+ if (sk2->sk_hash == hash &&
+ sk2 != sk &&
+ inet_sk(sk2)->num == snum &&
+ (!sk2->sk_reuse || !sk->sk_reuse) &&
+ (!sk2->sk_bound_dev_if ||
+ !sk->sk_bound_dev_if ||
+ sk2->sk_bound_dev_if ==
+ sk->sk_bound_dev_if) &&
+ (*saddr_comp)(sk, sk2))
+ goto fail;
+ }
}
inet_sk(sk)->num = snum;
- sk->sk_hash = snum;
+ sk->sk_hash = hash;
if (sk_unhashed(sk)) {
- head = &udptable[snum & (UDP_HTABLE_SIZE - 1)];
+ head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_add_node(sk, head);
sock_prot_inc_use(sk->sk_prot);
}
@@ -242,63 +294,77 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
{
struct sock *sk, *result = NULL;
struct hlist_node *node;
- unsigned short hnum = ntohs(dport);
- int badness = -1;
+ unsigned int hash, hashwild;
+ int score, best = -1, hport = ntohs(dport);
+
+ hash = hash_port_and_addr(hport, daddr);
+ hashwild = hash_port_and_addr(hport, 0);
read_lock(&udp_hash_lock);
- sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
+
+lookup:
+
+ sk_for_each(sk, node, &udptable[hash & (UDP_HTABLE_SIZE - 1)]) {
struct inet_sock *inet = inet_sk(sk);
- if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) {
- int score = (sk->sk_family == PF_INET ? 1 : 0);
- if (inet->rcv_saddr) {
- if (inet->rcv_saddr != daddr)
- continue;
- score+=2;
- }
- if (inet->daddr) {
- if (inet->daddr != saddr)
- continue;
- score+=2;
- }
- if (inet->dport) {
- if (inet->dport != sport)
- continue;
- score+=2;
- }
- if (sk->sk_bound_dev_if) {
- if (sk->sk_bound_dev_if != dif)
- continue;
- score+=2;
- }
- if (score == 9) {
- result = sk;
- break;
- } else if (score > badness) {
- result = sk;
- badness = score;
- }
+ if (sk->sk_hash != hash || ipv6_only_sock(sk) ||
+ inet->num != hport)
+ continue;
+
+ score = (sk->sk_family == PF_INET ? 1 : 0);
+ if (inet->rcv_saddr) {
+ if (inet->rcv_saddr != daddr)
+ continue;
+ score+=2;
+ }
+ if (inet->daddr) {
+ if (inet->daddr != saddr)
+ continue;
+ score+=2;
+ }
+ if (inet->dport) {
+ if (inet->dport != sport)
+ continue;
+ score+=2;
+ }
+ if (sk->sk_bound_dev_if) {
+ if (sk->sk_bound_dev_if != dif)
+ continue;
+ score+=2;
+ }
+ if (score == 9) {
+ result = sk;
+ goto found;
+ } else if (score > best) {
+ result = sk;
+ best = score;
}
}
+
+ if (hash != hashwild) {
+ hash = hashwild;
+ goto lookup;
+ }
+found:
if (result)
sock_hold(result);
read_unlock(&udp_hash_lock);
return result;
}
-static inline struct sock *udp_v4_mcast_next(struct sock *sk,
- __be16 loc_port, __be32 loc_addr,
+static inline struct sock *udp_v4_mcast_next(struct sock *sk, unsigned int hnum,
+ int hport, __be32 loc_addr,
__be16 rmt_port, __be32 rmt_addr,
int dif)
{
struct hlist_node *node;
struct sock *s = sk;
- unsigned short hnum = ntohs(loc_port);
sk_for_each_from(s, node) {
struct inet_sock *inet = inet_sk(s);
if (s->sk_hash != hnum ||
+ inet->num != hport ||
(inet->daddr && inet->daddr != rmt_addr) ||
(inet->dport != rmt_port && inet->dport) ||
(inet->rcv_saddr && inet->rcv_saddr != loc_addr) ||
@@ -917,7 +983,7 @@ int udp_disconnect(struct sock *sk, int flags)
}
/* return:
- * 1 if the the UDP system should process it
+ * 1 if the UDP system should process it
* 0 if we should drop this packet
* -1 if it should get processed by xfrm4_rcv_encap
*/
@@ -1129,29 +1195,45 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb,
__be32 saddr, __be32 daddr,
struct hlist_head udptable[])
{
- struct sock *sk;
+ struct sock *sk, *skw, *sknext;
int dif;
+ int hport = ntohs(uh->dest);
+ unsigned int hash = hash_port_and_addr(hport, daddr);
+ unsigned int hashwild = hash_port_and_addr(hport, 0);
- read_lock(&udp_hash_lock);
- sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]);
dif = skb->dev->ifindex;
- sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif);
- if (sk) {
- struct sock *sknext = NULL;
+ read_lock(&udp_hash_lock);
+
+ sk = sk_head(&udptable[hash & (UDP_HTABLE_SIZE - 1)]);
+ skw = sk_head(&udptable[hashwild & (UDP_HTABLE_SIZE - 1)]);
+
+ sk = udp_v4_mcast_next(sk, hash, hport, daddr, uh->source, saddr, dif);
+ if (!sk) {
+ hash = hashwild;
+ sk = udp_v4_mcast_next(skw, hash, hport, daddr, uh->source,
+ saddr, dif);
+ }
+ if (sk) {
do {
struct sk_buff *skb1 = skb;
-
- sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr,
- uh->source, saddr, dif);
+ sknext = udp_v4_mcast_next(sk_next(sk), hash, hport,
+ daddr, uh->source, saddr, dif);
+ if (!sknext && hash != hashwild) {
+ hash = hashwild;
+ sknext = udp_v4_mcast_next(skw, hash, hport,
+ daddr, uh->source, saddr, dif);
+ }
if (sknext)
skb1 = skb_clone(skb, GFP_ATOMIC);
if (skb1) {
int ret = udp_queue_rcv_skb(sk, skb1);
if (ret > 0)
- /* we should probably re-process instead
- * of dropping packets here. */
+ /*
+ * we should probably re-process
+ * instead of dropping packets here.
+ */
kfree_skb(skb1);
}
sk = sknext;
@@ -1238,7 +1320,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest,
- skb->dev->ifindex, udptable );
+ skb->dev->ifindex, udptable);
if (sk != NULL) {
int ret = udp_queue_rcv_skb(sk, skb);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e04e4937350..d02685c6bc6 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -449,7 +449,7 @@ static void addrconf_forward_change(void)
struct inet6_dev *idev;
read_lock(&dev_base_lock);
- for (dev=dev_base; dev; dev=dev->next) {
+ for_each_netdev(dev) {
rcu_read_lock();
idev = __in6_dev_get(dev);
if (idev) {
@@ -911,7 +911,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
read_lock(&dev_base_lock);
rcu_read_lock();
- for (dev = dev_base; dev; dev=dev->next) {
+ for_each_netdev(dev) {
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
@@ -2064,7 +2064,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
return;
}
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
struct in_device * in_dev = __in_dev_get_rtnl(dev);
if (in_dev && (dev->flags & IFF_UP)) {
struct in_ifaddr * ifa;
@@ -2225,7 +2225,7 @@ static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
return;
}
/* then try to inherit it from any device */
- for (link_dev = dev_base; link_dev; link_dev = link_dev->next) {
+ for_each_netdev(link_dev) {
if (!ipv6_inherit_linklocal(idev, link_dev))
return;
}
@@ -2359,8 +2359,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
break;
case NETDEV_CHANGENAME:
-#ifdef CONFIG_SYSCTL
if (idev) {
+ snmp6_unregister_dev(idev);
+#ifdef CONFIG_SYSCTL
addrconf_sysctl_unregister(&idev->cnf);
neigh_sysctl_unregister(idev->nd_parms);
neigh_sysctl_register(dev, idev->nd_parms,
@@ -2368,8 +2369,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
&ndisc_ifinfo_sysctl_change,
NULL);
addrconf_sysctl_register(idev, &idev->cnf);
- }
#endif
+ snmp6_register_dev(idev);
+ }
break;
}
@@ -3255,14 +3257,15 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
- for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (idx > s_idx)
s_ip_idx = 0;
ip_idx = 0;
if ((idev = in6_dev_get(dev)) == NULL)
- continue;
+ goto cont;
read_lock_bh(&idev->lock);
switch (type) {
case UNICAST_ADDR:
@@ -3309,6 +3312,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
}
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
+cont:
+ idx++;
}
done:
if (err <= 0) {
@@ -3573,16 +3578,19 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
struct inet6_dev *idev;
read_lock(&dev_base_lock);
- for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if ((idev = in6_dev_get(dev)) == NULL)
- continue;
+ goto cont;
err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
in6_dev_put(idev);
if (err <= 0)
break;
+cont:
+ idx++;
}
read_unlock(&dev_base_lock);
cb->args[0] = idx;
@@ -4245,7 +4253,7 @@ void __exit addrconf_cleanup(void)
* clean dev list.
*/
- for (dev=dev_base; dev; dev=dev->next) {
+ for_each_netdev(dev) {
if ((idev = __in6_dev_get(dev)) == NULL)
continue;
addrconf_ifdown(dev, 1);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 18cb928c8d9..6dd377253cf 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -42,7 +42,6 @@
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/icmpv6.h>
-#include <linux/smp_lock.h>
#include <linux/netfilter_ipv6.h>
#include <net/ip.h>
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 09117d63256..9b81264eb78 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -423,14 +423,18 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr)
*/
int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr)
{
+ int found = 0;
+
if (dev)
return ipv6_chk_acast_dev(dev, addr);
read_lock(&dev_base_lock);
- for (dev=dev_base; dev; dev=dev->next)
- if (ipv6_chk_acast_dev(dev, addr))
+ for_each_netdev(dev)
+ if (ipv6_chk_acast_dev(dev, addr)) {
+ found = 1;
break;
+ }
read_unlock(&dev_base_lock);
- return dev != 0;
+ return found;
}
@@ -447,9 +451,8 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
struct ifacaddr6 *im = NULL;
struct ac6_iter_state *state = ac6_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->idev = NULL;
+ for_each_netdev(state->dev) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
@@ -476,7 +479,7 @@ static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_net_device(state->dev);
if (!state->dev) {
state->idev = NULL;
break;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 6c2758951d6..3e308fb41b4 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2331,9 +2331,8 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
struct ifmcaddr6 *im = NULL;
struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->idev = NULL;
+ for_each_netdev(state->dev) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (!idev)
@@ -2360,7 +2359,7 @@ static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_net_device(state->dev);
if (!state->dev) {
state->idev = NULL;
break;
@@ -2475,9 +2474,9 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
struct ifmcaddr6 *im = NULL;
struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
- for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
- state->dev;
- state->dev = state->dev->next) {
+ state->idev = NULL;
+ state->im = NULL;
+ for_each_netdev(state->dev) {
struct inet6_dev *idev;
idev = in6_dev_get(state->dev);
if (unlikely(idev == NULL))
@@ -2513,7 +2512,7 @@ static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_s
read_unlock_bh(&state->idev->lock);
in6_dev_put(state->idev);
}
- state->dev = state->dev->next;
+ state->dev = next_net_device(state->dev);
if (!state->dev) {
state->idev = NULL;
goto out;
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index da07e9a88ee..838b8ddee8c 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -28,7 +28,7 @@ config IP6_NF_QUEUE
packets which enables users to receive the filtered packets
with QUEUE target using libipq.
- THis option enables the old IPv6-only "ip6_queue" implementation
+ This option enables the old IPv6-only "ip6_queue" implementation
which has been obsoleted by the new "nfnetlink_queue" code (see
CONFIG_NETFILTER_NETLINK_QUEUE).
@@ -198,7 +198,7 @@ config IP6_NF_RAW
and OUTPUT chains.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
endmenu
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index acb306a5dd5..920dc9cf6a8 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -223,6 +223,7 @@ int snmp6_unregister_dev(struct inet6_dev *idev)
return -EINVAL;
remove_proc_entry(idev->stats.proc_dir_entry->name,
proc_net_devsnmp6);
+ idev->stats.proc_dir_entry = NULL;
return 0;
}
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 538499a8997..5502cc948df 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -261,7 +261,7 @@ static int xfrm6_tunnel_rcv(struct sk_buff *skb)
__be32 spi;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
- return xfrm6_rcv_spi(skb, spi);
+ return xfrm6_rcv_spi(skb, spi) > 0 ? : 0;
}
static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 392f8bc9269..15419dd682f 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -1961,7 +1961,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
.sendpage = sock_no_sendpage,
};
-#include <linux/smp_lock.h>
SOCKOPS_WRAP(ipx_dgram, PF_IPX);
static struct packet_type ipx_8023_packet_type = {
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 06c97c60d54..dcd7e325b28 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2538,7 +2538,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(irda_ultra_ops) = {
};
#endif /* CONFIG_IRDA_ULTRA */
-#include <linux/smp_lock.h>
SOCKOPS_WRAP(irda_stream, PF_IRDA);
SOCKOPS_WRAP(irda_seqpacket, PF_IRDA);
SOCKOPS_WRAP(irda_dgram, PF_IRDA);
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index e84c924a81e..d9e9ddb8eac 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -45,7 +45,8 @@ static struct proto iucv_proto = {
static void iucv_callback_rx(struct iucv_path *, struct iucv_message *);
static void iucv_callback_txdone(struct iucv_path *, struct iucv_message *);
static void iucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
-static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]);
+static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8],
+ u8 ipuser[16]);
static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
static struct iucv_sock_list iucv_sk_list = {
@@ -147,11 +148,12 @@ static void iucv_sock_close(struct sock *sk)
unsigned char user_data[16];
struct iucv_sock *iucv = iucv_sk(sk);
int err;
+ unsigned long timeo;
iucv_sock_clear_timer(sk);
lock_sock(sk);
- switch(sk->sk_state) {
+ switch (sk->sk_state) {
case IUCV_LISTEN:
iucv_sock_cleanup_listen(sk);
break;
@@ -159,6 +161,21 @@ static void iucv_sock_close(struct sock *sk)
case IUCV_CONNECTED:
case IUCV_DISCONN:
err = 0;
+
+ sk->sk_state = IUCV_CLOSING;
+ sk->sk_state_change(sk);
+
+ if (!skb_queue_empty(&iucv->send_skb_q)) {
+ if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
+ timeo = sk->sk_lingertime;
+ else
+ timeo = IUCV_DISCONN_TIMEOUT;
+ err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0, timeo);
+ }
+
+ sk->sk_state = IUCV_CLOSED;
+ sk->sk_state_change(sk);
+
if (iucv->path) {
low_nmcpy(user_data, iucv->src_name);
high_nmcpy(user_data, iucv->dst_name);
@@ -168,12 +185,11 @@ static void iucv_sock_close(struct sock *sk)
iucv->path = NULL;
}
- sk->sk_state = IUCV_CLOSED;
- sk->sk_state_change(sk);
sk->sk_err = ECONNRESET;
sk->sk_state_change(sk);
skb_queue_purge(&iucv->send_skb_q);
+ skb_queue_purge(&iucv->backlog_skb_q);
sock_set_flag(sk, SOCK_ZAPPED);
break;
@@ -204,6 +220,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio)
sock_init_data(sock, sk);
INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
+ skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
iucv_sk(sk)->send_tag = 0;
sk->sk_destruct = iucv_sock_destruct;
@@ -276,7 +293,7 @@ struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock)
struct iucv_sock *isk, *n;
struct sock *sk;
- list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+ list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q) {
sk = (struct sock *) isk;
lock_sock(sk);
@@ -510,7 +527,7 @@ static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
long timeo;
int err = 0;
- lock_sock(sk);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
if (sk->sk_state != IUCV_LISTEN) {
err = -EBADFD;
@@ -521,7 +538,7 @@ static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
/* Wait for an incoming connection */
add_wait_queue_exclusive(sk->sk_sleep, &wait);
- while (!(nsk = iucv_accept_dequeue(sk, newsock))){
+ while (!(nsk = iucv_accept_dequeue(sk, newsock))) {
set_current_state(TASK_INTERRUPTIBLE);
if (!timeo) {
err = -EAGAIN;
@@ -530,7 +547,7 @@ static int iucv_sock_accept(struct socket *sock, struct socket *newsock,
release_sock(sk);
timeo = schedule_timeout(timeo);
- lock_sock(sk);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
if (sk->sk_state != IUCV_LISTEN) {
err = -EBADFD;
@@ -602,13 +619,13 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
- if (sk->sk_state == IUCV_CONNECTED){
- if(!(skb = sock_alloc_send_skb(sk, len,
- msg->msg_flags & MSG_DONTWAIT,
- &err)))
- return err;
+ if (sk->sk_state == IUCV_CONNECTED) {
+ if (!(skb = sock_alloc_send_skb(sk, len,
+ msg->msg_flags & MSG_DONTWAIT,
+ &err)))
+ goto out;
- if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)){
+ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
err = -EFAULT;
goto fail;
}
@@ -647,10 +664,16 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
{
int noblock = flags & MSG_DONTWAIT;
struct sock *sk = sock->sk;
+ struct iucv_sock *iucv = iucv_sk(sk);
int target, copied = 0;
- struct sk_buff *skb;
+ struct sk_buff *skb, *rskb, *cskb;
int err = 0;
+ if ((sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED) &&
+ skb_queue_empty(&iucv->backlog_skb_q) &&
+ skb_queue_empty(&sk->sk_receive_queue))
+ return 0;
+
if (flags & (MSG_OOB))
return -EOPNOTSUPP;
@@ -665,10 +688,12 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
copied = min_t(unsigned int, skb->len, len);
- if (memcpy_toiovec(msg->msg_iov, skb->data, copied)) {
+ cskb = skb;
+ if (memcpy_toiovec(msg->msg_iov, cskb->data, copied)) {
skb_queue_head(&sk->sk_receive_queue, skb);
if (copied == 0)
return -EFAULT;
+ goto done;
}
len -= copied;
@@ -683,6 +708,18 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
}
kfree_skb(skb);
+
+ /* Queue backlog skbs */
+ rskb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
+ while (rskb) {
+ if (sock_queue_rcv_skb(sk, rskb)) {
+ skb_queue_head(&iucv_sk(sk)->backlog_skb_q,
+ rskb);
+ break;
+ } else {
+ rskb = skb_dequeue(&iucv_sk(sk)->backlog_skb_q);
+ }
+ }
} else
skb_queue_head(&sk->sk_receive_queue, skb);
@@ -695,7 +732,7 @@ static inline unsigned int iucv_accept_poll(struct sock *parent)
struct iucv_sock *isk, *n;
struct sock *sk;
- list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q){
+ list_for_each_entry_safe(isk, n, &iucv_sk(parent)->accept_q, accept_q) {
sk = (struct sock *) isk;
if (sk->sk_state == IUCV_CONNECTED)
@@ -726,12 +763,15 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
mask |= POLLHUP;
if (!skb_queue_empty(&sk->sk_receive_queue) ||
- (sk->sk_shutdown & RCV_SHUTDOWN))
+ (sk->sk_shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM;
if (sk->sk_state == IUCV_CLOSED)
mask |= POLLHUP;
+ if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED)
+ mask |= POLLIN;
+
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
@@ -754,7 +794,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
return -EINVAL;
lock_sock(sk);
- switch(sk->sk_state) {
+ switch (sk->sk_state) {
case IUCV_CLOSED:
err = -ENOTCONN;
goto fail;
@@ -770,7 +810,7 @@ static int iucv_sock_shutdown(struct socket *sock, int how)
err = iucv_message_send(iucv->path, &txmsg, IUCV_IPRMDATA, 0,
(void *) prmmsg, 8);
if (err) {
- switch(err) {
+ switch (err) {
case 1:
err = -ENOTCONN;
break;
@@ -817,13 +857,6 @@ static int iucv_sock_release(struct socket *sock)
iucv_sk(sk)->path = NULL;
}
- if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime){
- lock_sock(sk);
- err = iucv_sock_wait_state(sk, IUCV_CLOSED, 0,
- sk->sk_lingertime);
- release_sock(sk);
- }
-
sock_orphan(sk);
iucv_sock_kill(sk);
return err;
@@ -880,7 +913,7 @@ static int iucv_callback_connreq(struct iucv_path *path,
/* Create the new socket */
nsk = iucv_sock_alloc(NULL, SOCK_STREAM, GFP_ATOMIC);
- if (!nsk){
+ if (!nsk) {
err = iucv_path_sever(path, user_data);
goto fail;
}
@@ -903,7 +936,7 @@ static int iucv_callback_connreq(struct iucv_path *path,
path->msglim = IUCV_QUEUELEN_DEFAULT;
err = iucv_path_accept(path, &af_iucv_handler, nuser_data, nsk);
- if (err){
+ if (err) {
err = iucv_path_sever(path, user_data);
goto fail;
}
@@ -927,18 +960,53 @@ static void iucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
sk->sk_state_change(sk);
}
+static int iucv_fragment_skb(struct sock *sk, struct sk_buff *skb, int len,
+ struct sk_buff_head *fragmented_skb_q)
+{
+ int dataleft, size, copied = 0;
+ struct sk_buff *nskb;
+
+ dataleft = len;
+ while (dataleft) {
+ if (dataleft >= sk->sk_rcvbuf / 4)
+ size = sk->sk_rcvbuf / 4;
+ else
+ size = dataleft;
+
+ nskb = alloc_skb(size, GFP_ATOMIC | GFP_DMA);
+ if (!nskb)
+ return -ENOMEM;
+
+ memcpy(nskb->data, skb->data + copied, size);
+ copied += size;
+ dataleft -= size;
+
+ skb_reset_transport_header(nskb);
+ skb_reset_network_header(nskb);
+ nskb->len = size;
+
+ skb_queue_tail(fragmented_skb_q, nskb);
+ }
+
+ return 0;
+}
+
static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
{
struct sock *sk = path->private;
- struct sk_buff *skb;
+ struct iucv_sock *iucv = iucv_sk(sk);
+ struct sk_buff *skb, *fskb;
+ struct sk_buff_head fragmented_skb_q;
int rc;
+ skb_queue_head_init(&fragmented_skb_q);
+
if (sk->sk_shutdown & RCV_SHUTDOWN)
return;
skb = alloc_skb(msg->length, GFP_ATOMIC | GFP_DMA);
if (!skb) {
- iucv_message_reject(path, msg);
+ iucv_path_sever(path, NULL);
return;
}
@@ -952,14 +1020,39 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
kfree_skb(skb);
return;
}
+ if (skb->truesize >= sk->sk_rcvbuf / 4) {
+ rc = iucv_fragment_skb(sk, skb, msg->length,
+ &fragmented_skb_q);
+ kfree_skb(skb);
+ skb = NULL;
+ if (rc) {
+ iucv_path_sever(path, NULL);
+ return;
+ }
+ } else {
+ skb_reset_transport_header(skb);
+ skb_reset_network_header(skb);
+ skb->len = msg->length;
+ }
+ }
+ /* Queue the fragmented skb */
+ fskb = skb_dequeue(&fragmented_skb_q);
+ while (fskb) {
+ if (!skb_queue_empty(&iucv->backlog_skb_q))
+ skb_queue_tail(&iucv->backlog_skb_q, fskb);
+ else if (sock_queue_rcv_skb(sk, fskb))
+ skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, fskb);
+ fskb = skb_dequeue(&fragmented_skb_q);
+ }
- skb_reset_transport_header(skb);
- skb_reset_network_header(skb);
- skb->len = msg->length;
+ /* Queue the original skb if it exists (was not fragmented) */
+ if (skb) {
+ if (!skb_queue_empty(&iucv->backlog_skb_q))
+ skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb);
+ else if (sock_queue_rcv_skb(sk, skb))
+ skb_queue_tail(&iucv_sk(sk)->backlog_skb_q, skb);
}
- if (sock_queue_rcv_skb(sk, skb))
- kfree_skb(skb);
}
static void iucv_callback_txdone(struct iucv_path *path,
@@ -971,17 +1064,27 @@ static void iucv_callback_txdone(struct iucv_path *path,
struct sk_buff *list_skb = list->next;
unsigned long flags;
- spin_lock_irqsave(&list->lock, flags);
+ if (list_skb) {
+ spin_lock_irqsave(&list->lock, flags);
+
+ do {
+ this = list_skb;
+ list_skb = list_skb->next;
+ } while (memcmp(&msg->tag, this->cb, 4) && list_skb);
+
+ spin_unlock_irqrestore(&list->lock, flags);
- do {
- this = list_skb;
- list_skb = list_skb->next;
- } while (memcmp(&msg->tag, this->cb, 4));
+ skb_unlink(this, &iucv_sk(sk)->send_skb_q);
+ kfree_skb(this);
+ }
- spin_unlock_irqrestore(&list->lock, flags);
+ if (sk->sk_state == IUCV_CLOSING) {
+ if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
+ sk->sk_state = IUCV_CLOSED;
+ sk->sk_state_change(sk);
+ }
+ }
- skb_unlink(this, &iucv_sk(sk)->send_skb_q);
- kfree_skb(this);
}
static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
@@ -1022,7 +1125,7 @@ static struct net_proto_family iucv_sock_family_ops = {
.create = iucv_sock_create,
};
-static int afiucv_init(void)
+static int __init afiucv_init(void)
{
int err;
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index 60f293842a3..b7333061016 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -69,7 +68,7 @@
#define IUCV_IPNORPY 0x10
#define IUCV_IPALL 0x80
-static int iucv_bus_match (struct device *dev, struct device_driver *drv)
+static int iucv_bus_match(struct device *dev, struct device_driver *drv)
{
return 0;
}
@@ -78,8 +77,11 @@ struct bus_type iucv_bus = {
.name = "iucv",
.match = iucv_bus_match,
};
+EXPORT_SYMBOL(iucv_bus);
struct device *iucv_root;
+EXPORT_SYMBOL(iucv_root);
+
static int iucv_available;
/* General IUCV interrupt structure */
@@ -90,20 +92,43 @@ struct iucv_irq_data {
u32 res2[8];
};
-struct iucv_work {
+struct iucv_irq_list {
struct list_head list;
struct iucv_irq_data data;
};
-static LIST_HEAD(iucv_work_queue);
-static DEFINE_SPINLOCK(iucv_work_lock);
-
static struct iucv_irq_data *iucv_irq_data;
static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE;
static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE;
-static void iucv_tasklet_handler(unsigned long);
-static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_handler,0);
+/*
+ * Queue of interrupt buffers lock for delivery via the tasklet
+ * (fast but can't call smp_call_function).
+ */
+static LIST_HEAD(iucv_task_queue);
+
+/*
+ * The tasklet for fast delivery of iucv interrupts.
+ */
+static void iucv_tasklet_fn(unsigned long);
+static DECLARE_TASKLET(iucv_tasklet, iucv_tasklet_fn,0);
+
+/*
+ * Queue of interrupt buffers for delivery via a work queue
+ * (slower but can call smp_call_function).
+ */
+static LIST_HEAD(iucv_work_queue);
+
+/*
+ * The work element to deliver path pending interrupts.
+ */
+static void iucv_work_fn(struct work_struct *work);
+static DECLARE_WORK(iucv_work, iucv_work_fn);
+
+/*
+ * Spinlock protecting task and work queue.
+ */
+static DEFINE_SPINLOCK(iucv_queue_lock);
enum iucv_command_codes {
IUCV_QUERY = 0,
@@ -147,10 +172,10 @@ static unsigned long iucv_max_pathid;
static DEFINE_SPINLOCK(iucv_table_lock);
/*
- * iucv_tasklet_cpu: contains the number of the cpu executing the tasklet.
- * Needed for iucv_path_sever called from tasklet.
+ * iucv_active_cpu: contains the number of the cpu executing the tasklet
+ * or the work handler. Needed for iucv_path_sever called from tasklet.
*/
-static int iucv_tasklet_cpu = -1;
+static int iucv_active_cpu = -1;
/*
* Mutex and wait queue for iucv_register/iucv_unregister.
@@ -382,7 +407,7 @@ static void iucv_declare_cpu(void *data)
rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm);
if (rc) {
char *err = "Unknown";
- switch(rc) {
+ switch (rc) {
case 0x03:
err = "Directory error";
break;
@@ -449,17 +474,19 @@ static void iucv_setmask_mp(void)
{
int cpu;
+ preempt_disable();
for_each_online_cpu(cpu)
/* Enable all cpus with a declared buffer. */
if (cpu_isset(cpu, iucv_buffer_cpumask) &&
!cpu_isset(cpu, iucv_irq_cpumask))
smp_call_function_on(iucv_allow_cpu, NULL, 0, 1, cpu);
+ preempt_enable();
}
/**
* iucv_setmask_up
*
- * Allow iucv interrupts on a single cpus.
+ * Allow iucv interrupts on a single cpu.
*/
static void iucv_setmask_up(void)
{
@@ -493,8 +520,10 @@ static int iucv_enable(void)
goto out;
/* Declare per cpu buffers. */
rc = -EIO;
+ preempt_disable();
for_each_online_cpu(cpu)
smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
+ preempt_enable();
if (cpus_empty(iucv_buffer_cpumask))
/* No cpu could declare an iucv buffer. */
goto out_path;
@@ -527,6 +556,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
switch (action) {
case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
if (!percpu_populate(iucv_irq_data,
sizeof(struct iucv_irq_data),
GFP_KERNEL|GFP_DMA, cpu))
@@ -538,15 +568,20 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
}
break;
case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
percpu_depopulate(iucv_param, cpu);
percpu_depopulate(iucv_irq_data, cpu);
break;
case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
smp_call_function_on(iucv_declare_cpu, NULL, 0, 1, cpu);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
cpumask = iucv_buffer_cpumask;
cpu_clear(cpu, cpumask);
if (cpus_empty(cpumask))
@@ -561,7 +596,7 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block iucv_cpu_notifier = {
+static struct notifier_block __cpuinitdata iucv_cpu_notifier = {
.notifier_call = iucv_cpu_notify,
};
@@ -584,48 +619,49 @@ static int iucv_sever_pathid(u16 pathid, u8 userdata[16])
return iucv_call_b2f0(IUCV_SEVER, parm);
}
+#ifdef CONFIG_SMP
/**
- * __iucv_cleanup_pathid
+ * __iucv_cleanup_queue
* @dummy: unused dummy argument
*
* Nop function called via smp_call_function to force work items from
* pending external iucv interrupts to the work queue.
*/
-static void __iucv_cleanup_pathid(void *dummy)
+static void __iucv_cleanup_queue(void *dummy)
{
}
+#endif
/**
- * iucv_cleanup_pathid
- * @pathid: 16 bit pathid
+ * iucv_cleanup_queue
*
* Function called after a path has been severed to find all remaining
* work items for the now stale pathid. The caller needs to hold the
* iucv_table_lock.
*/
-static void iucv_cleanup_pathid(u16 pathid)
+static void iucv_cleanup_queue(void)
{
- struct iucv_work *p, *n;
+ struct iucv_irq_list *p, *n;
/*
- * Path is severed, the pathid can be reused immediatly on
- * a iucv connect or a connection pending interrupt.
- * iucv_path_connect and connection pending interrupt will
- * wait until the iucv_table_lock is released before the
- * recycled pathid enters the system.
- * Force remaining interrupts to the work queue, then
- * scan the work queue for items of this path.
+ * When a path is severed, the pathid can be reused immediatly
+ * on a iucv connect or a connection pending interrupt. Remove
+ * all entries from the task queue that refer to a stale pathid
+ * (iucv_path_table[ix] == NULL). Only then do the iucv connect
+ * or deliver the connection pending interrupt. To get all the
+ * pending interrupts force them to the work queue by calling
+ * an empty function on all cpus.
*/
- smp_call_function(__iucv_cleanup_pathid, NULL, 0, 1);
- spin_lock_irq(&iucv_work_lock);
- list_for_each_entry_safe(p, n, &iucv_work_queue, list) {
- /* Remove work items for pathid except connection pending */
- if (p->data.ippathid == pathid && p->data.iptype != 0x01) {
+ smp_call_function(__iucv_cleanup_queue, NULL, 0, 1);
+ spin_lock_irq(&iucv_queue_lock);
+ list_for_each_entry_safe(p, n, &iucv_task_queue, list) {
+ /* Remove stale work items from the task queue. */
+ if (iucv_path_table[p->data.ippathid] == NULL) {
list_del(&p->list);
kfree(p);
}
}
- spin_unlock_irq(&iucv_work_lock);
+ spin_unlock_irq(&iucv_queue_lock);
}
/**
@@ -663,6 +699,7 @@ out_mutex:
mutex_unlock(&iucv_register_mutex);
return rc;
}
+EXPORT_SYMBOL(iucv_register);
/**
* iucv_unregister
@@ -684,7 +721,6 @@ void iucv_unregister(struct iucv_handler *handler, int smp)
iucv_sever_pathid(p->pathid, NULL);
iucv_path_table[p->pathid] = NULL;
list_del(&p->list);
- iucv_cleanup_pathid(p->pathid);
iucv_path_free(p);
}
spin_unlock_bh(&iucv_table_lock);
@@ -696,6 +732,7 @@ void iucv_unregister(struct iucv_handler *handler, int smp)
iucv_setmask_mp();
mutex_unlock(&iucv_register_mutex);
}
+EXPORT_SYMBOL(iucv_unregister);
/**
* iucv_path_accept
@@ -734,6 +771,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_path_accept);
/**
* iucv_path_connect
@@ -757,9 +795,9 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
union iucv_param *parm;
int rc;
- preempt_disable();
- if (iucv_tasklet_cpu != smp_processor_id())
- spin_lock_bh(&iucv_table_lock);
+ BUG_ON(in_atomic());
+ spin_lock_bh(&iucv_table_lock);
+ iucv_cleanup_queue();
parm = percpu_ptr(iucv_param, smp_processor_id());
memset(parm, 0, sizeof(union iucv_param));
parm->ctrl.ipmsglim = path->msglim;
@@ -794,11 +832,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
rc = -EIO;
}
}
- if (iucv_tasklet_cpu != smp_processor_id())
- spin_unlock_bh(&iucv_table_lock);
- preempt_enable();
+ spin_unlock_bh(&iucv_table_lock);
return rc;
}
+EXPORT_SYMBOL(iucv_path_connect);
/**
* iucv_path_quiesce:
@@ -825,6 +862,7 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_path_quiesce);
/**
* iucv_path_resume:
@@ -865,21 +903,20 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
{
int rc;
-
preempt_disable();
- if (iucv_tasklet_cpu != smp_processor_id())
+ if (iucv_active_cpu != smp_processor_id())
spin_lock_bh(&iucv_table_lock);
rc = iucv_sever_pathid(path->pathid, userdata);
if (!rc) {
iucv_path_table[path->pathid] = NULL;
list_del_init(&path->list);
- iucv_cleanup_pathid(path->pathid);
}
- if (iucv_tasklet_cpu != smp_processor_id())
+ if (iucv_active_cpu != smp_processor_id())
spin_unlock_bh(&iucv_table_lock);
preempt_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_path_sever);
/**
* iucv_message_purge
@@ -912,6 +949,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_message_purge);
/**
* iucv_message_receive
@@ -982,6 +1020,7 @@ int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_message_receive);
/**
* iucv_message_reject
@@ -1010,6 +1049,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_message_reject);
/**
* iucv_message_reply
@@ -1053,6 +1093,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_message_reply);
/**
* iucv_message_send
@@ -1101,6 +1142,7 @@ int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_message_send);
/**
* iucv_message_send2way
@@ -1157,6 +1199,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
local_bh_enable();
return rc;
}
+EXPORT_SYMBOL(iucv_message_send2way);
/**
* iucv_path_pending
@@ -1244,8 +1287,7 @@ static void iucv_path_complete(struct iucv_irq_data *data)
struct iucv_path_complete *ipc = (void *) data;
struct iucv_path *path = iucv_path_table[ipc->ippathid];
- BUG_ON(!path || !path->handler);
- if (path->handler->path_complete)
+ if (path && path->handler && path->handler->path_complete)
path->handler->path_complete(path, ipc->ipuser);
}
@@ -1273,14 +1315,14 @@ static void iucv_path_severed(struct iucv_irq_data *data)
struct iucv_path_severed *ips = (void *) data;
struct iucv_path *path = iucv_path_table[ips->ippathid];
- BUG_ON(!path || !path->handler);
+ if (!path || !path->handler) /* Already severed */
+ return;
if (path->handler->path_severed)
path->handler->path_severed(path, ips->ipuser);
else {
iucv_sever_pathid(path->pathid, NULL);
iucv_path_table[path->pathid] = NULL;
list_del_init(&path->list);
- iucv_cleanup_pathid(path->pathid);
iucv_path_free(path);
}
}
@@ -1309,8 +1351,7 @@ static void iucv_path_quiesced(struct iucv_irq_data *data)
struct iucv_path_quiesced *ipq = (void *) data;
struct iucv_path *path = iucv_path_table[ipq->ippathid];
- BUG_ON(!path || !path->handler);
- if (path->handler->path_quiesced)
+ if (path && path->handler && path->handler->path_quiesced)
path->handler->path_quiesced(path, ipq->ipuser);
}
@@ -1338,8 +1379,7 @@ static void iucv_path_resumed(struct iucv_irq_data *data)
struct iucv_path_resumed *ipr = (void *) data;
struct iucv_path *path = iucv_path_table[ipr->ippathid];
- BUG_ON(!path || !path->handler);
- if (path->handler->path_resumed)
+ if (path && path->handler && path->handler->path_resumed)
path->handler->path_resumed(path, ipr->ipuser);
}
@@ -1371,8 +1411,7 @@ static void iucv_message_complete(struct iucv_irq_data *data)
struct iucv_path *path = iucv_path_table[imc->ippathid];
struct iucv_message msg;
- BUG_ON(!path || !path->handler);
- if (path->handler->message_complete) {
+ if (path && path->handler && path->handler->message_complete) {
msg.flags = imc->ipflags1;
msg.id = imc->ipmsgid;
msg.audit = imc->ipaudit;
@@ -1417,8 +1456,7 @@ static void iucv_message_pending(struct iucv_irq_data *data)
struct iucv_path *path = iucv_path_table[imp->ippathid];
struct iucv_message msg;
- BUG_ON(!path || !path->handler);
- if (path->handler->message_pending) {
+ if (path && path->handler && path->handler->message_pending) {
msg.flags = imp->ipflags1;
msg.id = imp->ipmsgid;
msg.class = imp->iptrgcls;
@@ -1433,17 +1471,16 @@ static void iucv_message_pending(struct iucv_irq_data *data)
}
/**
- * iucv_tasklet_handler:
+ * iucv_tasklet_fn:
*
* This tasklet loops over the queue of irq buffers created by
* iucv_external_interrupt, calls the appropriate action handler
* and then frees the buffer.
*/
-static void iucv_tasklet_handler(unsigned long ignored)
+static void iucv_tasklet_fn(unsigned long ignored)
{
typedef void iucv_irq_fn(struct iucv_irq_data *);
static iucv_irq_fn *irq_fn[] = {
- [0x01] = iucv_path_pending,
[0x02] = iucv_path_complete,
[0x03] = iucv_path_severed,
[0x04] = iucv_path_quiesced,
@@ -1453,38 +1490,70 @@ static void iucv_tasklet_handler(unsigned long ignored)
[0x08] = iucv_message_pending,
[0x09] = iucv_message_pending,
};
- struct iucv_work *p;
+ struct list_head task_queue = LIST_HEAD_INIT(task_queue);
+ struct iucv_irq_list *p, *n;
/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
spin_lock(&iucv_table_lock);
- iucv_tasklet_cpu = smp_processor_id();
+ iucv_active_cpu = smp_processor_id();
+
+ spin_lock_irq(&iucv_queue_lock);
+ list_splice_init(&iucv_task_queue, &task_queue);
+ spin_unlock_irq(&iucv_queue_lock);
- spin_lock_irq(&iucv_work_lock);
- while (!list_empty(&iucv_work_queue)) {
- p = list_entry(iucv_work_queue.next, struct iucv_work, list);
+ list_for_each_entry_safe(p, n, &task_queue, list) {
list_del_init(&p->list);
- spin_unlock_irq(&iucv_work_lock);
irq_fn[p->data.iptype](&p->data);
kfree(p);
- spin_lock_irq(&iucv_work_lock);
}
- spin_unlock_irq(&iucv_work_lock);
- iucv_tasklet_cpu = -1;
+ iucv_active_cpu = -1;
spin_unlock(&iucv_table_lock);
}
/**
+ * iucv_work_fn:
+ *
+ * This work function loops over the queue of path pending irq blocks
+ * created by iucv_external_interrupt, calls the appropriate action
+ * handler and then frees the buffer.
+ */
+static void iucv_work_fn(struct work_struct *work)
+{
+ typedef void iucv_irq_fn(struct iucv_irq_data *);
+ struct list_head work_queue = LIST_HEAD_INIT(work_queue);
+ struct iucv_irq_list *p, *n;
+
+ /* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
+ spin_lock_bh(&iucv_table_lock);
+ iucv_active_cpu = smp_processor_id();
+
+ spin_lock_irq(&iucv_queue_lock);
+ list_splice_init(&iucv_work_queue, &work_queue);
+ spin_unlock_irq(&iucv_queue_lock);
+
+ iucv_cleanup_queue();
+ list_for_each_entry_safe(p, n, &work_queue, list) {
+ list_del_init(&p->list);
+ iucv_path_pending(&p->data);
+ kfree(p);
+ }
+
+ iucv_active_cpu = -1;
+ spin_unlock_bh(&iucv_table_lock);
+}
+
+/**
* iucv_external_interrupt
* @code: irq code
*
* Handles external interrupts coming in from CP.
- * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
+ * Places the interrupt buffer on a queue and schedules iucv_tasklet_fn().
*/
static void iucv_external_interrupt(u16 code)
{
struct iucv_irq_data *p;
- struct iucv_work *work;
+ struct iucv_irq_list *work;
p = percpu_ptr(iucv_irq_data, smp_processor_id());
if (p->ippathid >= iucv_max_pathid) {
@@ -1498,16 +1567,23 @@ static void iucv_external_interrupt(u16 code)
printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n");
return;
}
- work = kmalloc(sizeof(struct iucv_work), GFP_ATOMIC);
+ work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC);
if (!work) {
printk(KERN_WARNING "iucv_external_interrupt: out of memory\n");
return;
}
memcpy(&work->data, p, sizeof(work->data));
- spin_lock(&iucv_work_lock);
- list_add_tail(&work->list, &iucv_work_queue);
- spin_unlock(&iucv_work_lock);
- tasklet_schedule(&iucv_tasklet);
+ spin_lock(&iucv_queue_lock);
+ if (p->iptype == 0x01) {
+ /* Path pending interrupt. */
+ list_add_tail(&work->list, &iucv_work_queue);
+ schedule_work(&iucv_work);
+ } else {
+ /* The other interrupts. */
+ list_add_tail(&work->list, &iucv_task_queue);
+ tasklet_schedule(&iucv_tasklet);
+ }
+ spin_unlock(&iucv_queue_lock);
}
/**
@@ -1515,7 +1591,7 @@ static void iucv_external_interrupt(u16 code)
*
* Allocates and initializes various data structures.
*/
-static int iucv_init(void)
+static int __init iucv_init(void)
{
int rc;
@@ -1526,7 +1602,7 @@ static int iucv_init(void)
rc = iucv_query_maxconn();
if (rc)
goto out;
- rc = register_external_interrupt (0x4000, iucv_external_interrupt);
+ rc = register_external_interrupt(0x4000, iucv_external_interrupt);
if (rc)
goto out;
rc = bus_register(&iucv_bus);
@@ -1537,7 +1613,7 @@ static int iucv_init(void)
rc = PTR_ERR(iucv_root);
goto out_bus;
}
- /* Note: GFP_DMA used used to get memory below 2G */
+ /* Note: GFP_DMA used to get memory below 2G */
iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data),
GFP_KERNEL|GFP_DMA);
if (!iucv_irq_data) {
@@ -1575,14 +1651,16 @@ out:
*
* Frees everything allocated from iucv_init.
*/
-static void iucv_exit(void)
+static void __exit iucv_exit(void)
{
- struct iucv_work *p, *n;
+ struct iucv_irq_list *p, *n;
- spin_lock_irq(&iucv_work_lock);
+ spin_lock_irq(&iucv_queue_lock);
+ list_for_each_entry_safe(p, n, &iucv_task_queue, list)
+ kfree(p);
list_for_each_entry_safe(p, n, &iucv_work_queue, list)
kfree(p);
- spin_unlock_irq(&iucv_work_lock);
+ spin_unlock_irq(&iucv_queue_lock);
unregister_hotcpu_notifier(&iucv_cpu_notifier);
percpu_free(iucv_param);
percpu_free(iucv_irq_data);
@@ -1594,24 +1672,6 @@ static void iucv_exit(void)
subsys_initcall(iucv_init);
module_exit(iucv_exit);
-/**
- * Export all public stuff
- */
-EXPORT_SYMBOL (iucv_bus);
-EXPORT_SYMBOL (iucv_root);
-EXPORT_SYMBOL (iucv_register);
-EXPORT_SYMBOL (iucv_unregister);
-EXPORT_SYMBOL (iucv_path_accept);
-EXPORT_SYMBOL (iucv_path_connect);
-EXPORT_SYMBOL (iucv_path_quiesce);
-EXPORT_SYMBOL (iucv_path_sever);
-EXPORT_SYMBOL (iucv_message_purge);
-EXPORT_SYMBOL (iucv_message_receive);
-EXPORT_SYMBOL (iucv_message_reject);
-EXPORT_SYMBOL (iucv_message_reply);
-EXPORT_SYMBOL (iucv_message_send);
-EXPORT_SYMBOL (iucv_message_send2way);
-
MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
MODULE_LICENSE("GPL");
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 7d9fa38b6a7..6b8a103cf9e 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -324,7 +324,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
memset(&laddr, 0, sizeof(laddr));
memset(&daddr, 0, sizeof(daddr));
/*
- * FIXME: check if the the address is multicast,
+ * FIXME: check if the address is multicast,
* only SOCK_DGRAM can do this.
*/
memcpy(laddr.mac, addr->sllc_mac, IFHWADDRLEN);
diff --git a/net/llc/llc_core.c b/net/llc/llc_core.c
index d12413cff5b..d4b13a031fd 100644
--- a/net/llc/llc_core.c
+++ b/net/llc/llc_core.c
@@ -160,8 +160,14 @@ static struct packet_type llc_tr_packet_type = {
static int __init llc_init(void)
{
- if (dev_base->next)
- memcpy(llc_station_mac_sa, dev_base->next->dev_addr, ETH_ALEN);
+ struct net_device *dev;
+
+ dev = first_net_device();
+ if (dev != NULL)
+ dev = next_net_device(dev);
+
+ if (dev != NULL)
+ memcpy(llc_station_mac_sa, dev->dev_addr, ETH_ALEN);
else
memset(llc_station_mac_sa, 0, ETH_ALEN);
dev_add_pack(&llc_packet_type);
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
new file mode 100644
index 00000000000..6fffb3845ab
--- /dev/null
+++ b/net/mac80211/Kconfig
@@ -0,0 +1,78 @@
+config MAC80211
+ tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
+ depends on EXPERIMENTAL
+ select CRYPTO
+ select CRYPTO_ECB
+ select CRYPTO_ARC4
+ select CRYPTO_AES
+ select CRC32
+ select WIRELESS_EXT
+ select CFG80211
+ select NET_SCH_FIFO
+ ---help---
+ This option enables the hardware independent IEEE 802.11
+ networking stack.
+
+config MAC80211_LEDS
+ bool "Enable LED triggers"
+ depends on MAC80211 && LEDS_TRIGGERS
+ ---help---
+ This option enables a few LED triggers for different
+ packet receive/transmit events.
+
+config MAC80211_DEBUGFS
+ bool "Export mac80211 internals in DebugFS"
+ depends on MAC80211 && DEBUG_FS
+ ---help---
+ Select this to see extensive information about
+ the internal state of mac80211 in debugfs.
+
+ Say N unless you know you need this.
+
+config MAC80211_DEBUG
+ bool "Enable debugging output"
+ depends on MAC80211
+ ---help---
+ This option will enable debug tracing output for the
+ ieee80211 network stack.
+
+ If you are not trying to debug or develop the ieee80211
+ subsystem, you most likely want to say N here.
+
+config MAC80211_VERBOSE_DEBUG
+ bool "Verbose debugging output"
+ depends on MAC80211_DEBUG
+
+config MAC80211_LOWTX_FRAME_DUMP
+ bool "Debug frame dumping"
+ depends on MAC80211_DEBUG
+ ---help---
+ Selecting this option will cause the stack to
+ print a message for each frame that is handed
+ to the lowlevel driver for transmission. This
+ message includes all MAC addresses and the
+ frame control field.
+
+ If unsure, say N and insert the debugging code
+ you require into the driver you are debugging.
+
+config TKIP_DEBUG
+ bool "TKIP debugging"
+ depends on MAC80211_DEBUG
+
+config MAC80211_DEBUG_COUNTERS
+ bool "Extra statistics for TX/RX debugging"
+ depends on MAC80211_DEBUG
+
+config MAC80211_IBSS_DEBUG
+ bool "Support for IBSS testing"
+ depends on MAC80211_DEBUG
+ ---help---
+ Say Y here if you intend to debug the IBSS code.
+
+config MAC80211_VERBOSE_PS_DEBUG
+ bool "Verbose powersave mode debugging"
+ depends on MAC80211_DEBUG
+ ---help---
+ Say Y here to print out verbose powersave
+ mode debug messages.
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
new file mode 100644
index 00000000000..e9738dad2d7
--- /dev/null
+++ b/net/mac80211/Makefile
@@ -0,0 +1,20 @@
+obj-$(CONFIG_MAC80211) += mac80211.o rc80211_simple.o
+
+mac80211-objs-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o
+mac80211-objs-$(CONFIG_MAC80211_DEBUGFS) += debugfs.o debugfs_sta.o debugfs_netdev.o debugfs_key.o
+
+mac80211-objs := \
+ ieee80211.o \
+ ieee80211_ioctl.o \
+ sta_info.o \
+ wep.o \
+ wpa.o \
+ ieee80211_sta.o \
+ ieee80211_iface.o \
+ ieee80211_rate.o \
+ michael.o \
+ tkip.o \
+ aes_ccm.o \
+ wme.o \
+ ieee80211_cfg.o \
+ $(mac80211-objs-y)
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
new file mode 100644
index 00000000000..e55569bee7d
--- /dev/null
+++ b/net/mac80211/aes_ccm.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <asm/scatterlist.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_key.h"
+#include "aes_ccm.h"
+
+
+static void ieee80211_aes_encrypt(struct crypto_cipher *tfm,
+ const u8 pt[16], u8 ct[16])
+{
+ crypto_cipher_encrypt_one(tfm, ct, pt);
+}
+
+
+static inline void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
+ u8 *b, u8 *s_0, u8 *a)
+{
+ int i;
+
+ ieee80211_aes_encrypt(tfm, b_0, b);
+
+ /* Extra Authenticate-only data (always two AES blocks) */
+ for (i = 0; i < AES_BLOCK_LEN; i++)
+ aad[i] ^= b[i];
+ ieee80211_aes_encrypt(tfm, aad, b);
+
+ aad += AES_BLOCK_LEN;
+
+ for (i = 0; i < AES_BLOCK_LEN; i++)
+ aad[i] ^= b[i];
+ ieee80211_aes_encrypt(tfm, aad, a);
+
+ /* Mask out bits from auth-only-b_0 */
+ b_0[0] &= 0x07;
+
+ /* S_0 is used to encrypt T (= MIC) */
+ b_0[14] = 0;
+ b_0[15] = 0;
+ ieee80211_aes_encrypt(tfm, b_0, s_0);
+}
+
+
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *b_0, u8 *aad, u8 *data, size_t data_len,
+ u8 *cdata, u8 *mic)
+{
+ int i, j, last_len, num_blocks;
+ u8 *pos, *cpos, *b, *s_0, *e;
+
+ b = scratch;
+ s_0 = scratch + AES_BLOCK_LEN;
+ e = scratch + 2 * AES_BLOCK_LEN;
+
+ num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+ last_len = data_len % AES_BLOCK_LEN;
+ aes_ccm_prepare(tfm, b_0, aad, b, s_0, b);
+
+ /* Process payload blocks */
+ pos = data;
+ cpos = cdata;
+ for (j = 1; j <= num_blocks; j++) {
+ int blen = (j == num_blocks && last_len) ?
+ last_len : AES_BLOCK_LEN;
+
+ /* Authentication followed by encryption */
+ for (i = 0; i < blen; i++)
+ b[i] ^= pos[i];
+ ieee80211_aes_encrypt(tfm, b, b);
+
+ b_0[14] = (j >> 8) & 0xff;
+ b_0[15] = j & 0xff;
+ ieee80211_aes_encrypt(tfm, b_0, e);
+ for (i = 0; i < blen; i++)
+ *cpos++ = *pos++ ^ e[i];
+ }
+
+ for (i = 0; i < CCMP_MIC_LEN; i++)
+ mic[i] = b[i] ^ s_0[i];
+}
+
+
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
+ u8 *mic, u8 *data)
+{
+ int i, j, last_len, num_blocks;
+ u8 *pos, *cpos, *b, *s_0, *a;
+
+ b = scratch;
+ s_0 = scratch + AES_BLOCK_LEN;
+ a = scratch + 2 * AES_BLOCK_LEN;
+
+ num_blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
+ last_len = data_len % AES_BLOCK_LEN;
+ aes_ccm_prepare(tfm, b_0, aad, b, s_0, a);
+
+ /* Process payload blocks */
+ cpos = cdata;
+ pos = data;
+ for (j = 1; j <= num_blocks; j++) {
+ int blen = (j == num_blocks && last_len) ?
+ last_len : AES_BLOCK_LEN;
+
+ /* Decryption followed by authentication */
+ b_0[14] = (j >> 8) & 0xff;
+ b_0[15] = j & 0xff;
+ ieee80211_aes_encrypt(tfm, b_0, b);
+ for (i = 0; i < blen; i++) {
+ *pos = *cpos++ ^ b[i];
+ a[i] ^= *pos++;
+ }
+
+ ieee80211_aes_encrypt(tfm, a, a);
+ }
+
+ for (i = 0; i < CCMP_MIC_LEN; i++) {
+ if ((mic[i] ^ s_0[i]) != a[i])
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[])
+{
+ struct crypto_cipher *tfm;
+
+ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm))
+ return NULL;
+
+ crypto_cipher_setkey(tfm, key, ALG_CCMP_KEY_LEN);
+
+ return tfm;
+}
+
+
+void ieee80211_aes_key_free(struct crypto_cipher *tfm)
+{
+ if (tfm)
+ crypto_free_cipher(tfm);
+}
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
new file mode 100644
index 00000000000..885f19030b2
--- /dev/null
+++ b/net/mac80211/aes_ccm.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef AES_CCM_H
+#define AES_CCM_H
+
+#include <linux/crypto.h>
+
+#define AES_BLOCK_LEN 16
+
+struct crypto_cipher * ieee80211_aes_key_setup_encrypt(const u8 key[]);
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *b_0, u8 *aad, u8 *data, size_t data_len,
+ u8 *cdata, u8 *mic);
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
+ u8 *b_0, u8 *aad, u8 *cdata, size_t data_len,
+ u8 *mic, u8 *data);
+void ieee80211_aes_key_free(struct crypto_cipher *tfm);
+
+#endif /* AES_CCM_H */
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
new file mode 100644
index 00000000000..bb6c0feb2d4
--- /dev/null
+++ b/net/mac80211/debugfs.c
@@ -0,0 +1,433 @@
+/*
+ * mac80211 debugfs for wireless PHYs
+ *
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * GPLv2
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/rtnetlink.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "debugfs.h"
+
+int mac80211_open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static const char *ieee80211_mode_str(int mode)
+{
+ switch (mode) {
+ case MODE_IEEE80211A:
+ return "IEEE 802.11a";
+ case MODE_IEEE80211B:
+ return "IEEE 802.11b";
+ case MODE_IEEE80211G:
+ return "IEEE 802.11g";
+ case MODE_ATHEROS_TURBO:
+ return "Atheros Turbo (5 GHz)";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static ssize_t modes_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ struct ieee80211_hw_mode *mode;
+ char buf[150], *p = buf;
+
+ /* FIXME: locking! */
+ list_for_each_entry(mode, &local->modes_list, list) {
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "%s\n", ieee80211_mode_str(mode->mode));
+ }
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
+}
+
+static const struct file_operations modes_ops = {
+ .read = modes_read,
+ .open = mac80211_open_file_generic,
+};
+
+#define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \
+static ssize_t name## _read(struct file *file, char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct ieee80211_local *local = file->private_data; \
+ char buf[buflen]; \
+ int res; \
+ \
+ res = scnprintf(buf, buflen, fmt "\n", ##value); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+} \
+ \
+static const struct file_operations name## _ops = { \
+ .read = name## _read, \
+ .open = mac80211_open_file_generic, \
+};
+
+#define DEBUGFS_ADD(name) \
+ local->debugfs.name = debugfs_create_file(#name, 0444, phyd, \
+ local, &name## _ops);
+
+#define DEBUGFS_DEL(name) \
+ debugfs_remove(local->debugfs.name); \
+ local->debugfs.name = NULL;
+
+
+DEBUGFS_READONLY_FILE(channel, 20, "%d",
+ local->hw.conf.channel);
+DEBUGFS_READONLY_FILE(frequency, 20, "%d",
+ local->hw.conf.freq);
+DEBUGFS_READONLY_FILE(radar_detect, 20, "%d",
+ local->hw.conf.radar_detect);
+DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d",
+ local->hw.conf.antenna_sel_tx);
+DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d",
+ local->hw.conf.antenna_sel_rx);
+DEBUGFS_READONLY_FILE(bridge_packets, 20, "%d",
+ local->bridge_packets);
+DEBUGFS_READONLY_FILE(key_tx_rx_threshold, 20, "%d",
+ local->key_tx_rx_threshold);
+DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
+ local->rts_threshold);
+DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
+ local->fragmentation_threshold);
+DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
+ local->short_retry_limit);
+DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
+ local->long_retry_limit);
+DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
+ local->total_ps_buffered);
+DEBUGFS_READONLY_FILE(mode, 20, "%s",
+ ieee80211_mode_str(local->hw.conf.phymode));
+DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x",
+ local->wep_iv & 0xffffff);
+DEBUGFS_READONLY_FILE(tx_power_reduction, 20, "%d.%d dBm",
+ local->hw.conf.tx_power_reduction / 10,
+ local->hw.conf.tx_power_reduction & 10);
+DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s",
+ local->rate_ctrl ? local->rate_ctrl->ops->name : "<unset>");
+
+/* statistics stuff */
+
+static inline int rtnl_lock_local(struct ieee80211_local *local)
+{
+ rtnl_lock();
+ if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+ return 0;
+}
+
+#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
+ DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
+
+static ssize_t format_devstat_counter(struct ieee80211_local *local,
+ char __user *userbuf,
+ size_t count, loff_t *ppos,
+ int (*printvalue)(struct ieee80211_low_level_stats *stats, char *buf,
+ int buflen))
+{
+ struct ieee80211_low_level_stats stats;
+ char buf[20];
+ int res;
+
+ if (!local->ops->get_stats)
+ return -EOPNOTSUPP;
+
+ res = rtnl_lock_local(local);
+ if (res)
+ return res;
+
+ res = local->ops->get_stats(local_to_hw(local), &stats);
+ rtnl_unlock();
+ if (!res)
+ res = printvalue(&stats, buf, sizeof(buf));
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+
+#define DEBUGFS_DEVSTATS_FILE(name) \
+static int print_devstats_##name(struct ieee80211_low_level_stats *stats,\
+ char *buf, int buflen) \
+{ \
+ return scnprintf(buf, buflen, "%u\n", stats->name); \
+} \
+static ssize_t stats_ ##name## _read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return format_devstat_counter(file->private_data, \
+ userbuf, \
+ count, \
+ ppos, \
+ print_devstats_##name); \
+} \
+ \
+static const struct file_operations stats_ ##name## _ops = { \
+ .read = stats_ ##name## _read, \
+ .open = mac80211_open_file_generic, \
+};
+
+#define DEBUGFS_STATS_ADD(name) \
+ local->debugfs.stats.name = debugfs_create_file(#name, 0444, statsd,\
+ local, &stats_ ##name## _ops);
+
+#define DEBUGFS_STATS_DEL(name) \
+ debugfs_remove(local->debugfs.stats.name); \
+ local->debugfs.stats.name = NULL;
+
+DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u",
+ local->dot11TransmittedFragmentCount);
+DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u",
+ local->dot11MulticastTransmittedFrameCount);
+DEBUGFS_STATS_FILE(failed_count, 20, "%u",
+ local->dot11FailedCount);
+DEBUGFS_STATS_FILE(retry_count, 20, "%u",
+ local->dot11RetryCount);
+DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u",
+ local->dot11MultipleRetryCount);
+DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u",
+ local->dot11FrameDuplicateCount);
+DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u",
+ local->dot11ReceivedFragmentCount);
+DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u",
+ local->dot11MulticastReceivedFrameCount);
+DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u",
+ local->dot11TransmittedFrameCount);
+DEBUGFS_STATS_FILE(wep_undecryptable_count, 20, "%u",
+ local->dot11WEPUndecryptableCount);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u",
+ local->tx_handlers_drop);
+DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u",
+ local->tx_handlers_queued);
+DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u",
+ local->tx_handlers_drop_unencrypted);
+DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u",
+ local->tx_handlers_drop_fragment);
+DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u",
+ local->tx_handlers_drop_wep);
+DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u",
+ local->tx_handlers_drop_not_assoc);
+DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u",
+ local->tx_handlers_drop_unauth_port);
+DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u",
+ local->rx_handlers_drop);
+DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u",
+ local->rx_handlers_queued);
+DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u",
+ local->rx_handlers_drop_nullfunc);
+DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u",
+ local->rx_handlers_drop_defrag);
+DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u",
+ local->rx_handlers_drop_short);
+DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u",
+ local->rx_handlers_drop_passive_scan);
+DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u",
+ local->tx_expand_skb_head);
+DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u",
+ local->tx_expand_skb_head_cloned);
+DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u",
+ local->rx_expand_skb_head);
+DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u",
+ local->rx_expand_skb_head2);
+DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
+ local->rx_handlers_fragments);
+DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
+ local->tx_status_drop);
+
+static ssize_t stats_wme_rx_queue_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ char buf[NUM_RX_DATA_QUEUES*15], *p = buf;
+ int i;
+
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "%u\n", local->wme_rx_queue[i]);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
+}
+
+static const struct file_operations stats_wme_rx_queue_ops = {
+ .read = stats_wme_rx_queue_read,
+ .open = mac80211_open_file_generic,
+};
+
+static ssize_t stats_wme_tx_queue_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ char buf[NUM_TX_DATA_QUEUES*15], *p = buf;
+ int i;
+
+ for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "%u\n", local->wme_tx_queue[i]);
+
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf);
+}
+
+static const struct file_operations stats_wme_tx_queue_ops = {
+ .read = stats_wme_tx_queue_read,
+ .open = mac80211_open_file_generic,
+};
+#endif
+
+DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
+DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
+DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
+DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
+
+
+void debugfs_hw_add(struct ieee80211_local *local)
+{
+ struct dentry *phyd = local->hw.wiphy->debugfsdir;
+ struct dentry *statsd;
+
+ if (!phyd)
+ return;
+
+ local->debugfs.stations = debugfs_create_dir("stations", phyd);
+ local->debugfs.keys = debugfs_create_dir("keys", phyd);
+
+ DEBUGFS_ADD(channel);
+ DEBUGFS_ADD(frequency);
+ DEBUGFS_ADD(radar_detect);
+ DEBUGFS_ADD(antenna_sel_tx);
+ DEBUGFS_ADD(antenna_sel_rx);
+ DEBUGFS_ADD(bridge_packets);
+ DEBUGFS_ADD(key_tx_rx_threshold);
+ DEBUGFS_ADD(rts_threshold);
+ DEBUGFS_ADD(fragmentation_threshold);
+ DEBUGFS_ADD(short_retry_limit);
+ DEBUGFS_ADD(long_retry_limit);
+ DEBUGFS_ADD(total_ps_buffered);
+ DEBUGFS_ADD(mode);
+ DEBUGFS_ADD(wep_iv);
+ DEBUGFS_ADD(tx_power_reduction);
+ DEBUGFS_ADD(modes);
+
+ statsd = debugfs_create_dir("statistics", phyd);
+ local->debugfs.statistics = statsd;
+
+ /* if the dir failed, don't put all the other things into the root! */
+ if (!statsd)
+ return;
+
+ DEBUGFS_STATS_ADD(transmitted_fragment_count);
+ DEBUGFS_STATS_ADD(multicast_transmitted_frame_count);
+ DEBUGFS_STATS_ADD(failed_count);
+ DEBUGFS_STATS_ADD(retry_count);
+ DEBUGFS_STATS_ADD(multiple_retry_count);
+ DEBUGFS_STATS_ADD(frame_duplicate_count);
+ DEBUGFS_STATS_ADD(received_fragment_count);
+ DEBUGFS_STATS_ADD(multicast_received_frame_count);
+ DEBUGFS_STATS_ADD(transmitted_frame_count);
+ DEBUGFS_STATS_ADD(wep_undecryptable_count);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ DEBUGFS_STATS_ADD(tx_handlers_drop);
+ DEBUGFS_STATS_ADD(tx_handlers_queued);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_fragment);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
+ DEBUGFS_STATS_ADD(rx_handlers_drop);
+ DEBUGFS_STATS_ADD(rx_handlers_queued);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_short);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan);
+ DEBUGFS_STATS_ADD(tx_expand_skb_head);
+ DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
+ DEBUGFS_STATS_ADD(rx_expand_skb_head);
+ DEBUGFS_STATS_ADD(rx_expand_skb_head2);
+ DEBUGFS_STATS_ADD(rx_handlers_fragments);
+ DEBUGFS_STATS_ADD(tx_status_drop);
+ DEBUGFS_STATS_ADD(wme_tx_queue);
+ DEBUGFS_STATS_ADD(wme_rx_queue);
+#endif
+ DEBUGFS_STATS_ADD(dot11ACKFailureCount);
+ DEBUGFS_STATS_ADD(dot11RTSFailureCount);
+ DEBUGFS_STATS_ADD(dot11FCSErrorCount);
+ DEBUGFS_STATS_ADD(dot11RTSSuccessCount);
+}
+
+void debugfs_hw_del(struct ieee80211_local *local)
+{
+ DEBUGFS_DEL(channel);
+ DEBUGFS_DEL(frequency);
+ DEBUGFS_DEL(radar_detect);
+ DEBUGFS_DEL(antenna_sel_tx);
+ DEBUGFS_DEL(antenna_sel_rx);
+ DEBUGFS_DEL(bridge_packets);
+ DEBUGFS_DEL(key_tx_rx_threshold);
+ DEBUGFS_DEL(rts_threshold);
+ DEBUGFS_DEL(fragmentation_threshold);
+ DEBUGFS_DEL(short_retry_limit);
+ DEBUGFS_DEL(long_retry_limit);
+ DEBUGFS_DEL(total_ps_buffered);
+ DEBUGFS_DEL(mode);
+ DEBUGFS_DEL(wep_iv);
+ DEBUGFS_DEL(tx_power_reduction);
+ DEBUGFS_DEL(modes);
+
+ DEBUGFS_STATS_DEL(transmitted_fragment_count);
+ DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
+ DEBUGFS_STATS_DEL(failed_count);
+ DEBUGFS_STATS_DEL(retry_count);
+ DEBUGFS_STATS_DEL(multiple_retry_count);
+ DEBUGFS_STATS_DEL(frame_duplicate_count);
+ DEBUGFS_STATS_DEL(received_fragment_count);
+ DEBUGFS_STATS_DEL(multicast_received_frame_count);
+ DEBUGFS_STATS_DEL(transmitted_frame_count);
+ DEBUGFS_STATS_DEL(wep_undecryptable_count);
+ DEBUGFS_STATS_DEL(num_scans);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ DEBUGFS_STATS_DEL(tx_handlers_drop);
+ DEBUGFS_STATS_DEL(tx_handlers_queued);
+ DEBUGFS_STATS_DEL(tx_handlers_drop_unencrypted);
+ DEBUGFS_STATS_DEL(tx_handlers_drop_fragment);
+ DEBUGFS_STATS_DEL(tx_handlers_drop_wep);
+ DEBUGFS_STATS_DEL(tx_handlers_drop_not_assoc);
+ DEBUGFS_STATS_DEL(tx_handlers_drop_unauth_port);
+ DEBUGFS_STATS_DEL(rx_handlers_drop);
+ DEBUGFS_STATS_DEL(rx_handlers_queued);
+ DEBUGFS_STATS_DEL(rx_handlers_drop_nullfunc);
+ DEBUGFS_STATS_DEL(rx_handlers_drop_defrag);
+ DEBUGFS_STATS_DEL(rx_handlers_drop_short);
+ DEBUGFS_STATS_DEL(rx_handlers_drop_passive_scan);
+ DEBUGFS_STATS_DEL(tx_expand_skb_head);
+ DEBUGFS_STATS_DEL(tx_expand_skb_head_cloned);
+ DEBUGFS_STATS_DEL(rx_expand_skb_head);
+ DEBUGFS_STATS_DEL(rx_expand_skb_head2);
+ DEBUGFS_STATS_DEL(rx_handlers_fragments);
+ DEBUGFS_STATS_DEL(tx_status_drop);
+ DEBUGFS_STATS_DEL(wme_tx_queue);
+ DEBUGFS_STATS_DEL(wme_rx_queue);
+#endif
+ DEBUGFS_STATS_DEL(dot11ACKFailureCount);
+ DEBUGFS_STATS_DEL(dot11RTSFailureCount);
+ DEBUGFS_STATS_DEL(dot11FCSErrorCount);
+ DEBUGFS_STATS_DEL(dot11RTSSuccessCount);
+
+ debugfs_remove(local->debugfs.statistics);
+ local->debugfs.statistics = NULL;
+ debugfs_remove(local->debugfs.stations);
+ local->debugfs.stations = NULL;
+ debugfs_remove(local->debugfs.keys);
+ local->debugfs.keys = NULL;
+}
diff --git a/net/mac80211/debugfs.h b/net/mac80211/debugfs.h
new file mode 100644
index 00000000000..dd2541935c2
--- /dev/null
+++ b/net/mac80211/debugfs.h
@@ -0,0 +1,16 @@
+#ifndef __MAC80211_DEBUGFS_H
+#define __MAC80211_DEBUGFS_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+extern void debugfs_hw_add(struct ieee80211_local *local);
+extern void debugfs_hw_del(struct ieee80211_local *local);
+extern int mac80211_open_file_generic(struct inode *inode, struct file *file);
+#else
+static inline void debugfs_hw_add(struct ieee80211_local *local)
+{
+ return;
+}
+static inline void debugfs_hw_del(struct ieee80211_local *local) {}
+#endif
+
+#endif /* __MAC80211_DEBUGFS_H */
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
new file mode 100644
index 00000000000..7d56dc9e732
--- /dev/null
+++ b/net/mac80211/debugfs_key.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2003-2005 Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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/kobject.h>
+#include "ieee80211_i.h"
+#include "ieee80211_key.h"
+#include "debugfs.h"
+#include "debugfs_key.h"
+
+#define KEY_READ(name, buflen, format_string) \
+static ssize_t key_##name##_read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ char buf[buflen]; \
+ struct ieee80211_key *key = file->private_data; \
+ int res = scnprintf(buf, buflen, format_string, key->name); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+}
+#define KEY_READ_D(name) KEY_READ(name, 20, "%d\n")
+
+#define KEY_OPS(name) \
+static const struct file_operations key_ ##name## _ops = { \
+ .read = key_##name##_read, \
+ .open = mac80211_open_file_generic, \
+}
+
+#define KEY_FILE(name, format) \
+ KEY_READ_##format(name) \
+ KEY_OPS(name)
+
+KEY_FILE(keylen, D);
+KEY_FILE(force_sw_encrypt, D);
+KEY_FILE(keyidx, D);
+KEY_FILE(hw_key_idx, D);
+KEY_FILE(tx_rx_count, D);
+
+static ssize_t key_algorithm_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char *alg;
+ struct ieee80211_key *key = file->private_data;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ alg = "WEP\n";
+ break;
+ case ALG_TKIP:
+ alg = "TKIP\n";
+ break;
+ case ALG_CCMP:
+ alg = "CCMP\n";
+ break;
+ default:
+ return 0;
+ }
+ return simple_read_from_buffer(userbuf, count, ppos, alg, strlen(alg));
+}
+KEY_OPS(algorithm);
+
+static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ const u8 *tpn;
+ char buf[20];
+ int len;
+ struct ieee80211_key *key = file->private_data;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ len = scnprintf(buf, sizeof(buf), "\n");
+ case ALG_TKIP:
+ len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
+ key->u.tkip.iv32,
+ key->u.tkip.iv16);
+ case ALG_CCMP:
+ tpn = key->u.ccmp.tx_pn;
+ len = scnprintf(buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x\n",
+ tpn[0], tpn[1], tpn[2], tpn[3], tpn[4], tpn[5]);
+ default:
+ return 0;
+ }
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(tx_spec);
+
+static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_key *key = file->private_data;
+ char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf;
+ int i, len;
+ const u8 *rpn;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ len = scnprintf(buf, sizeof(buf), "\n");
+ case ALG_TKIP:
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "%08x %04x\n",
+ key->u.tkip.iv32_rx[i],
+ key->u.tkip.iv16_rx[i]);
+ len = p - buf;
+ case ALG_CCMP:
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+ rpn = key->u.ccmp.rx_pn[i];
+ p += scnprintf(p, sizeof(buf)+buf-p,
+ "%02x%02x%02x%02x%02x%02x\n",
+ rpn[0], rpn[1], rpn[2],
+ rpn[3], rpn[4], rpn[5]);
+ }
+ len = p - buf;
+ default:
+ return 0;
+ }
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(rx_spec);
+
+static ssize_t key_replays_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_key *key = file->private_data;
+ char buf[20];
+ int len;
+
+ if (key->alg != ALG_CCMP)
+ return 0;
+ len = scnprintf(buf, sizeof(buf), "%u\n", key->u.ccmp.replays);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
+}
+KEY_OPS(replays);
+
+static ssize_t key_key_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_key *key = file->private_data;
+ int i, res, bufsize = 2*key->keylen+2;
+ char *buf = kmalloc(bufsize, GFP_KERNEL);
+ char *p = buf;
+
+ for (i = 0; i < key->keylen; i++)
+ p += scnprintf(p, bufsize+buf-p, "%02x", key->key[i]);
+ p += scnprintf(p, bufsize+buf-p, "\n");
+ res = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+ kfree(buf);
+ return res;
+}
+KEY_OPS(key);
+
+#define DEBUGFS_ADD(name) \
+ key->debugfs.name = debugfs_create_file(#name, 0400,\
+ key->debugfs.dir, key, &key_##name##_ops);
+
+void ieee80211_debugfs_key_add(struct ieee80211_local *local,
+ struct ieee80211_key *key)
+{
+ char buf[20];
+
+ if (!local->debugfs.keys)
+ return;
+
+ sprintf(buf, "%d", key->keyidx);
+ key->debugfs.dir = debugfs_create_dir(buf,
+ local->debugfs.keys);
+
+ if (!key->debugfs.dir)
+ return;
+
+ DEBUGFS_ADD(keylen);
+ DEBUGFS_ADD(force_sw_encrypt);
+ DEBUGFS_ADD(keyidx);
+ DEBUGFS_ADD(hw_key_idx);
+ DEBUGFS_ADD(tx_rx_count);
+ DEBUGFS_ADD(algorithm);
+ DEBUGFS_ADD(tx_spec);
+ DEBUGFS_ADD(rx_spec);
+ DEBUGFS_ADD(replays);
+ DEBUGFS_ADD(key);
+};
+
+#define DEBUGFS_DEL(name) \
+ debugfs_remove(key->debugfs.name); key->debugfs.name = NULL;
+
+void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
+{
+ if (!key)
+ return;
+
+ DEBUGFS_DEL(keylen);
+ DEBUGFS_DEL(force_sw_encrypt);
+ DEBUGFS_DEL(keyidx);
+ DEBUGFS_DEL(hw_key_idx);
+ DEBUGFS_DEL(tx_rx_count);
+ DEBUGFS_DEL(algorithm);
+ DEBUGFS_DEL(tx_spec);
+ DEBUGFS_DEL(rx_spec);
+ DEBUGFS_DEL(replays);
+ DEBUGFS_DEL(key);
+
+ debugfs_remove(key->debugfs.stalink);
+ key->debugfs.stalink = NULL;
+ debugfs_remove(key->debugfs.dir);
+ key->debugfs.dir = NULL;
+}
+void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata)
+{
+ char buf[50];
+
+ if (!sdata->debugfsdir)
+ return;
+
+ sprintf(buf, "../keys/%d", sdata->default_key->keyidx);
+ sdata->debugfs.default_key =
+ debugfs_create_symlink("default_key", sdata->debugfsdir, buf);
+}
+void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata)
+{
+ if (!sdata)
+ return;
+
+ debugfs_remove(sdata->debugfs.default_key);
+ sdata->debugfs.default_key = NULL;
+}
+void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
+ struct sta_info *sta)
+{
+ char buf[50];
+
+ if (!key->debugfs.dir)
+ return;
+
+ sprintf(buf, "../sta/" MAC_FMT, MAC_ARG(sta->addr));
+ key->debugfs.stalink =
+ debugfs_create_symlink("station", key->debugfs.dir, buf);
+}
+
+void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
+ struct sta_info *sta)
+{
+ debugfs_remove(key->debugfs.stalink);
+ key->debugfs.stalink = NULL;
+}
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h
new file mode 100644
index 00000000000..aecfce395da
--- /dev/null
+++ b/net/mac80211/debugfs_key.h
@@ -0,0 +1,34 @@
+#ifndef __MAC80211_DEBUGFS_KEY_H
+#define __MAC80211_DEBUGFS_KEY_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ieee80211_debugfs_key_add(struct ieee80211_local *local,
+ struct ieee80211_key *key);
+void ieee80211_debugfs_key_remove(struct ieee80211_key *key);
+void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
+ struct sta_info *sta);
+void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
+ struct sta_info *sta);
+#else
+static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local,
+ struct ieee80211_key *key)
+{}
+static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
+{}
+static inline void ieee80211_debugfs_key_add_default(
+ struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_key_remove_default(
+ struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_key_sta_link(
+ struct ieee80211_key *key, struct sta_info *sta)
+{}
+static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
+ struct sta_info *sta)
+{}
+#endif
+
+#endif /* __MAC80211_DEBUGFS_KEY_H */
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
new file mode 100644
index 00000000000..9e3964638ba
--- /dev/null
+++ b/net/mac80211/debugfs_netdev.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/if.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
+#include <net/mac80211.h>
+#include <net/cfg80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "debugfs.h"
+#include "debugfs_netdev.h"
+
+static ssize_t ieee80211_if_read(
+ struct ieee80211_sub_if_data *sdata,
+ char __user *userbuf,
+ size_t count, loff_t *ppos,
+ ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int))
+{
+ char buf[70];
+ ssize_t ret = -EINVAL;
+
+ read_lock(&dev_base_lock);
+ if (sdata->dev->reg_state == NETREG_REGISTERED) {
+ ret = (*format)(sdata, buf, sizeof(buf));
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+ }
+ read_unlock(&dev_base_lock);
+ return ret;
+}
+
+#define IEEE80211_IF_FMT(name, field, format_string) \
+static ssize_t ieee80211_if_fmt_##name( \
+ const struct ieee80211_sub_if_data *sdata, char *buf, \
+ int buflen) \
+{ \
+ return scnprintf(buf, buflen, format_string, sdata->field); \
+}
+#define IEEE80211_IF_FMT_DEC(name, field) \
+ IEEE80211_IF_FMT(name, field, "%d\n")
+#define IEEE80211_IF_FMT_HEX(name, field) \
+ IEEE80211_IF_FMT(name, field, "%#x\n")
+#define IEEE80211_IF_FMT_SIZE(name, field) \
+ IEEE80211_IF_FMT(name, field, "%zd\n")
+
+#define IEEE80211_IF_FMT_ATOMIC(name, field) \
+static ssize_t ieee80211_if_fmt_##name( \
+ const struct ieee80211_sub_if_data *sdata, \
+ char *buf, int buflen) \
+{ \
+ return scnprintf(buf, buflen, "%d\n", atomic_read(&sdata->field));\
+}
+
+#define IEEE80211_IF_FMT_MAC(name, field) \
+static ssize_t ieee80211_if_fmt_##name( \
+ const struct ieee80211_sub_if_data *sdata, char *buf, \
+ int buflen) \
+{ \
+ return scnprintf(buf, buflen, MAC_FMT "\n", MAC_ARG(sdata->field));\
+}
+
+#define __IEEE80211_IF_FILE(name) \
+static ssize_t ieee80211_if_read_##name(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ return ieee80211_if_read(file->private_data, \
+ userbuf, count, ppos, \
+ ieee80211_if_fmt_##name); \
+} \
+static const struct file_operations name##_ops = { \
+ .read = ieee80211_if_read_##name, \
+ .open = mac80211_open_file_generic, \
+}
+
+#define IEEE80211_IF_FILE(name, field, format) \
+ IEEE80211_IF_FMT_##format(name, field) \
+ __IEEE80211_IF_FILE(name)
+
+/* common attributes */
+IEEE80211_IF_FILE(channel_use, channel_use, DEC);
+IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
+IEEE80211_IF_FILE(eapol, eapol, DEC);
+IEEE80211_IF_FILE(ieee8021_x, ieee802_1x, DEC);
+
+/* STA/IBSS attributes */
+IEEE80211_IF_FILE(state, u.sta.state, DEC);
+IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC);
+IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC);
+IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE);
+IEEE80211_IF_FILE(aid, u.sta.aid, DEC);
+IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX);
+IEEE80211_IF_FILE(capab, u.sta.capab, HEX);
+IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE);
+IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC);
+IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
+IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
+IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
+IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
+
+static ssize_t ieee80211_if_fmt_flags(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
+ sdata->u.sta.ssid_set ? "SSID\n" : "",
+ sdata->u.sta.bssid_set ? "BSSID\n" : "",
+ sdata->u.sta.prev_bssid_set ? "prev BSSID\n" : "",
+ sdata->u.sta.authenticated ? "AUTH\n" : "",
+ sdata->u.sta.associated ? "ASSOC\n" : "",
+ sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "",
+ sdata->u.sta.use_protection ? "CTS prot\n" : "");
+}
+__IEEE80211_IF_FILE(flags);
+
+/* AP attributes */
+IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
+IEEE80211_IF_FILE(dtim_period, u.ap.dtim_period, DEC);
+IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
+IEEE80211_IF_FILE(num_beacons, u.ap.num_beacons, DEC);
+IEEE80211_IF_FILE(force_unicast_rateidx, u.ap.force_unicast_rateidx, DEC);
+IEEE80211_IF_FILE(max_ratectrl_rateidx, u.ap.max_ratectrl_rateidx, DEC);
+
+static ssize_t ieee80211_if_fmt_num_buffered_multicast(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ return scnprintf(buf, buflen, "%u\n",
+ skb_queue_len(&sdata->u.ap.ps_bc_buf));
+}
+__IEEE80211_IF_FILE(num_buffered_multicast);
+
+static ssize_t ieee80211_if_fmt_beacon_head_len(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ if (sdata->u.ap.beacon_head)
+ return scnprintf(buf, buflen, "%d\n",
+ sdata->u.ap.beacon_head_len);
+ return scnprintf(buf, buflen, "\n");
+}
+__IEEE80211_IF_FILE(beacon_head_len);
+
+static ssize_t ieee80211_if_fmt_beacon_tail_len(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ if (sdata->u.ap.beacon_tail)
+ return scnprintf(buf, buflen, "%d\n",
+ sdata->u.ap.beacon_tail_len);
+ return scnprintf(buf, buflen, "\n");
+}
+__IEEE80211_IF_FILE(beacon_tail_len);
+
+/* WDS attributes */
+IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
+
+/* VLAN attributes */
+IEEE80211_IF_FILE(vlan_id, u.vlan.id, DEC);
+
+/* MONITOR attributes */
+static ssize_t ieee80211_if_fmt_mode(
+ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+ struct ieee80211_local *local = sdata->local;
+
+ return scnprintf(buf, buflen, "%s\n",
+ ((local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) ||
+ local->open_count == local->monitors) ?
+ "hard" : "soft");
+}
+__IEEE80211_IF_FILE(mode);
+
+
+#define DEBUGFS_ADD(name, type)\
+ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\
+ sdata->debugfsdir, sdata, &name##_ops);
+
+static void add_sta_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_ADD(channel_use, sta);
+ DEBUGFS_ADD(drop_unencrypted, sta);
+ DEBUGFS_ADD(eapol, sta);
+ DEBUGFS_ADD(ieee8021_x, sta);
+ DEBUGFS_ADD(state, sta);
+ DEBUGFS_ADD(bssid, sta);
+ DEBUGFS_ADD(prev_bssid, sta);
+ DEBUGFS_ADD(ssid_len, sta);
+ DEBUGFS_ADD(aid, sta);
+ DEBUGFS_ADD(ap_capab, sta);
+ DEBUGFS_ADD(capab, sta);
+ DEBUGFS_ADD(extra_ie_len, sta);
+ DEBUGFS_ADD(auth_tries, sta);
+ DEBUGFS_ADD(assoc_tries, sta);
+ DEBUGFS_ADD(auth_algs, sta);
+ DEBUGFS_ADD(auth_alg, sta);
+ DEBUGFS_ADD(auth_transaction, sta);
+ DEBUGFS_ADD(flags, sta);
+}
+
+static void add_ap_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_ADD(channel_use, ap);
+ DEBUGFS_ADD(drop_unencrypted, ap);
+ DEBUGFS_ADD(eapol, ap);
+ DEBUGFS_ADD(ieee8021_x, ap);
+ DEBUGFS_ADD(num_sta_ps, ap);
+ DEBUGFS_ADD(dtim_period, ap);
+ DEBUGFS_ADD(dtim_count, ap);
+ DEBUGFS_ADD(num_beacons, ap);
+ DEBUGFS_ADD(force_unicast_rateidx, ap);
+ DEBUGFS_ADD(max_ratectrl_rateidx, ap);
+ DEBUGFS_ADD(num_buffered_multicast, ap);
+ DEBUGFS_ADD(beacon_head_len, ap);
+ DEBUGFS_ADD(beacon_tail_len, ap);
+}
+
+static void add_wds_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_ADD(channel_use, wds);
+ DEBUGFS_ADD(drop_unencrypted, wds);
+ DEBUGFS_ADD(eapol, wds);
+ DEBUGFS_ADD(ieee8021_x, wds);
+ DEBUGFS_ADD(peer, wds);
+}
+
+static void add_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_ADD(channel_use, vlan);
+ DEBUGFS_ADD(drop_unencrypted, vlan);
+ DEBUGFS_ADD(eapol, vlan);
+ DEBUGFS_ADD(ieee8021_x, vlan);
+ DEBUGFS_ADD(vlan_id, vlan);
+}
+
+static void add_monitor_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_ADD(mode, monitor);
+}
+
+static void add_files(struct ieee80211_sub_if_data *sdata)
+{
+ if (!sdata->debugfsdir)
+ return;
+
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ add_sta_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ add_ap_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ add_wds_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ add_monitor_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_VLAN:
+ add_vlan_files(sdata);
+ break;
+ default:
+ break;
+ }
+}
+
+#define DEBUGFS_DEL(name, type)\
+ debugfs_remove(sdata->debugfs.type.name);\
+ sdata->debugfs.type.name = NULL;
+
+static void del_sta_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_DEL(channel_use, sta);
+ DEBUGFS_DEL(drop_unencrypted, sta);
+ DEBUGFS_DEL(eapol, sta);
+ DEBUGFS_DEL(ieee8021_x, sta);
+ DEBUGFS_DEL(state, sta);
+ DEBUGFS_DEL(bssid, sta);
+ DEBUGFS_DEL(prev_bssid, sta);
+ DEBUGFS_DEL(ssid_len, sta);
+ DEBUGFS_DEL(aid, sta);
+ DEBUGFS_DEL(ap_capab, sta);
+ DEBUGFS_DEL(capab, sta);
+ DEBUGFS_DEL(extra_ie_len, sta);
+ DEBUGFS_DEL(auth_tries, sta);
+ DEBUGFS_DEL(assoc_tries, sta);
+ DEBUGFS_DEL(auth_algs, sta);
+ DEBUGFS_DEL(auth_alg, sta);
+ DEBUGFS_DEL(auth_transaction, sta);
+ DEBUGFS_DEL(flags, sta);
+}
+
+static void del_ap_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_DEL(channel_use, ap);
+ DEBUGFS_DEL(drop_unencrypted, ap);
+ DEBUGFS_DEL(eapol, ap);
+ DEBUGFS_DEL(ieee8021_x, ap);
+ DEBUGFS_DEL(num_sta_ps, ap);
+ DEBUGFS_DEL(dtim_period, ap);
+ DEBUGFS_DEL(dtim_count, ap);
+ DEBUGFS_DEL(num_beacons, ap);
+ DEBUGFS_DEL(force_unicast_rateidx, ap);
+ DEBUGFS_DEL(max_ratectrl_rateidx, ap);
+ DEBUGFS_DEL(num_buffered_multicast, ap);
+ DEBUGFS_DEL(beacon_head_len, ap);
+ DEBUGFS_DEL(beacon_tail_len, ap);
+}
+
+static void del_wds_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_DEL(channel_use, wds);
+ DEBUGFS_DEL(drop_unencrypted, wds);
+ DEBUGFS_DEL(eapol, wds);
+ DEBUGFS_DEL(ieee8021_x, wds);
+ DEBUGFS_DEL(peer, wds);
+}
+
+static void del_vlan_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_DEL(channel_use, vlan);
+ DEBUGFS_DEL(drop_unencrypted, vlan);
+ DEBUGFS_DEL(eapol, vlan);
+ DEBUGFS_DEL(ieee8021_x, vlan);
+ DEBUGFS_DEL(vlan_id, vlan);
+}
+
+static void del_monitor_files(struct ieee80211_sub_if_data *sdata)
+{
+ DEBUGFS_DEL(mode, monitor);
+}
+
+static void del_files(struct ieee80211_sub_if_data *sdata, int type)
+{
+ if (!sdata->debugfsdir)
+ return;
+
+ switch (type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ del_sta_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ del_ap_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ del_wds_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ del_monitor_files(sdata);
+ break;
+ case IEEE80211_IF_TYPE_VLAN:
+ del_vlan_files(sdata);
+ break;
+ default:
+ break;
+ }
+}
+
+static int notif_registered;
+
+void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata)
+{
+ char buf[10+IFNAMSIZ];
+
+ if (!notif_registered)
+ return;
+
+ sprintf(buf, "netdev:%s", sdata->dev->name);
+ sdata->debugfsdir = debugfs_create_dir(buf,
+ sdata->local->hw.wiphy->debugfsdir);
+}
+
+void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata)
+{
+ del_files(sdata, sdata->type);
+ debugfs_remove(sdata->debugfsdir);
+ sdata->debugfsdir = NULL;
+}
+
+void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
+ int oldtype)
+{
+ del_files(sdata, oldtype);
+ add_files(sdata);
+}
+
+static int netdev_notify(struct notifier_block * nb,
+ unsigned long state,
+ void *ndev)
+{
+ struct net_device *dev = ndev;
+ char buf[10+IFNAMSIZ];
+
+ if (state != NETDEV_CHANGENAME)
+ return 0;
+
+ if (!dev->ieee80211_ptr || !dev->ieee80211_ptr->wiphy)
+ return 0;
+
+ if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
+ return 0;
+
+ /* TODO
+ sprintf(buf, "netdev:%s", dev->name);
+ debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf);
+ */
+
+ return 0;
+}
+
+static struct notifier_block mac80211_debugfs_netdev_notifier = {
+ .notifier_call = netdev_notify,
+};
+
+void ieee80211_debugfs_netdev_init(void)
+{
+ int err;
+
+ err = register_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
+ if (err) {
+ printk(KERN_ERR
+ "mac80211: failed to install netdev notifier,"
+ " disabling per-netdev debugfs!\n");
+ } else
+ notif_registered = 1;
+}
+
+void ieee80211_debugfs_netdev_exit(void)
+{
+ unregister_netdevice_notifier(&mac80211_debugfs_netdev_notifier);
+ notif_registered = 0;
+}
diff --git a/net/mac80211/debugfs_netdev.h b/net/mac80211/debugfs_netdev.h
new file mode 100644
index 00000000000..a690071fde8
--- /dev/null
+++ b/net/mac80211/debugfs_netdev.h
@@ -0,0 +1,30 @@
+/* routines exported for debugfs handling */
+
+#ifndef __IEEE80211_DEBUGFS_NETDEV_H
+#define __IEEE80211_DEBUGFS_NETDEV_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ieee80211_debugfs_add_netdev(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_remove_netdev(struct ieee80211_sub_if_data *sdata);
+void ieee80211_debugfs_change_if_type(struct ieee80211_sub_if_data *sdata,
+ int oldtype);
+void ieee80211_debugfs_netdev_init(void);
+void ieee80211_debugfs_netdev_exit(void);
+#else
+static inline void ieee80211_debugfs_add_netdev(
+ struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_remove_netdev(
+ struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_debugfs_change_if_type(
+ struct ieee80211_sub_if_data *sdata, int oldtype)
+{}
+static inline void ieee80211_debugfs_netdev_init(void)
+{}
+
+static inline void ieee80211_debugfs_netdev_exit(void)
+{}
+#endif
+
+#endif /* __IEEE80211_DEBUGFS_NETDEV_H */
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
new file mode 100644
index 00000000000..d41e696f398
--- /dev/null
+++ b/net/mac80211/debugfs_sta.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2003-2005 Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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/debugfs.h>
+#include <linux/ieee80211.h>
+#include "ieee80211_i.h"
+#include "debugfs.h"
+#include "debugfs_sta.h"
+#include "sta_info.h"
+
+/* sta attributtes */
+
+#define STA_READ(name, buflen, field, format_string) \
+static ssize_t sta_ ##name## _read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ int res; \
+ struct sta_info *sta = file->private_data; \
+ char buf[buflen]; \
+ res = scnprintf(buf, buflen, format_string, sta->field); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+}
+#define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n")
+#define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n")
+#define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
+#define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
+
+#define STA_READ_RATE(name, field) \
+static ssize_t sta_##name##_read(struct file *file, \
+ char __user *userbuf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct sta_info *sta = file->private_data; \
+ struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode; \
+ char buf[20]; \
+ int res = scnprintf(buf, sizeof(buf), "%d\n", \
+ (sta->field >= 0 && \
+ sta->field < mode->num_rates) ? \
+ mode->rates[sta->field].rate : -1); \
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res); \
+}
+
+#define STA_OPS(name) \
+static const struct file_operations sta_ ##name## _ops = { \
+ .read = sta_##name##_read, \
+ .open = mac80211_open_file_generic, \
+}
+
+#define STA_FILE(name, field, format) \
+ STA_READ_##format(name, field) \
+ STA_OPS(name)
+
+STA_FILE(aid, aid, D);
+STA_FILE(key_idx_compression, key_idx_compression, D);
+STA_FILE(dev, dev->name, S);
+STA_FILE(vlan_id, vlan_id, D);
+STA_FILE(rx_packets, rx_packets, LU);
+STA_FILE(tx_packets, tx_packets, LU);
+STA_FILE(rx_bytes, rx_bytes, LU);
+STA_FILE(tx_bytes, tx_bytes, LU);
+STA_FILE(rx_duplicates, num_duplicates, LU);
+STA_FILE(rx_fragments, rx_fragments, LU);
+STA_FILE(rx_dropped, rx_dropped, LU);
+STA_FILE(tx_fragments, tx_fragments, LU);
+STA_FILE(tx_filtered, tx_filtered_count, LU);
+STA_FILE(txrate, txrate, RATE);
+STA_FILE(last_txrate, last_txrate, RATE);
+STA_FILE(tx_retry_failed, tx_retry_failed, LU);
+STA_FILE(tx_retry_count, tx_retry_count, LU);
+STA_FILE(last_rssi, last_rssi, D);
+STA_FILE(last_signal, last_signal, D);
+STA_FILE(last_noise, last_noise, D);
+STA_FILE(channel_use, channel_use, D);
+STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D);
+
+static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[100];
+ struct sta_info *sta = file->private_data;
+ int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s",
+ sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "",
+ sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "",
+ sta->flags & WLAN_STA_PS ? "PS\n" : "",
+ sta->flags & WLAN_STA_TIM ? "TIM\n" : "",
+ sta->flags & WLAN_STA_PERM ? "PERM\n" : "",
+ sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "",
+ sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "",
+ sta->flags & WLAN_STA_WME ? "WME\n" : "",
+ sta->flags & WLAN_STA_WDS ? "WDS\n" : "");
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(flags);
+
+static ssize_t sta_num_ps_buf_frames_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[20];
+ struct sta_info *sta = file->private_data;
+ int res = scnprintf(buf, sizeof(buf), "%u\n",
+ skb_queue_len(&sta->ps_tx_buf));
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(num_ps_buf_frames);
+
+static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[100];
+ struct sta_info *sta = file->private_data;
+ int res = scnprintf(buf, sizeof(buf), "%d %d %d\n",
+ sta->last_ack_rssi[0],
+ sta->last_ack_rssi[1],
+ sta->last_ack_rssi[2]);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(last_ack_rssi);
+
+static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[20];
+ struct sta_info *sta = file->private_data;
+ int res = scnprintf(buf, sizeof(buf), "%d\n",
+ sta->last_ack ?
+ jiffies_to_msecs(jiffies - sta->last_ack) : -1);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(last_ack_ms);
+
+static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[20];
+ struct sta_info *sta = file->private_data;
+ int res = scnprintf(buf, sizeof(buf), "%d\n",
+ jiffies_to_msecs(jiffies - sta->last_rx));
+ return simple_read_from_buffer(userbuf, count, ppos, buf, res);
+}
+STA_OPS(inactive_ms);
+
+static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
+ int i;
+ struct sta_info *sta = file->private_data;
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%x ",
+ sta->last_seq_ctrl[i]);
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(last_seq_ctrl);
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+static ssize_t sta_wme_rx_queue_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
+ int i;
+ struct sta_info *sta = file->private_data;
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
+ sta->wme_rx_queue[i]);
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(wme_rx_queue);
+
+static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[15*NUM_TX_DATA_QUEUES], *p = buf;
+ int i;
+ struct sta_info *sta = file->private_data;
+ for (i = 0; i < NUM_TX_DATA_QUEUES; i++)
+ p += scnprintf(p, sizeof(buf)+buf-p, "%u ",
+ sta->wme_tx_queue[i]);
+ p += scnprintf(p, sizeof(buf)+buf-p, "\n");
+ return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+STA_OPS(wme_tx_queue);
+#endif
+
+#define DEBUGFS_ADD(name) \
+ sta->debugfs.name = debugfs_create_file(#name, 0444, \
+ sta->debugfs.dir, sta, &sta_ ##name## _ops);
+
+#define DEBUGFS_DEL(name) \
+ debugfs_remove(sta->debugfs.name);\
+ sta->debugfs.name = NULL;
+
+
+void ieee80211_sta_debugfs_add(struct sta_info *sta)
+{
+ char buf[3*6];
+ struct dentry *stations_dir = sta->local->debugfs.stations;
+
+ if (!stations_dir)
+ return;
+
+ sprintf(buf, MAC_FMT, MAC_ARG(sta->addr));
+
+ sta->debugfs.dir = debugfs_create_dir(buf, stations_dir);
+ if (!sta->debugfs.dir)
+ return;
+
+ DEBUGFS_ADD(flags);
+ DEBUGFS_ADD(num_ps_buf_frames);
+ DEBUGFS_ADD(last_ack_rssi);
+ DEBUGFS_ADD(last_ack_ms);
+ DEBUGFS_ADD(inactive_ms);
+ DEBUGFS_ADD(last_seq_ctrl);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ DEBUGFS_ADD(wme_rx_queue);
+ DEBUGFS_ADD(wme_tx_queue);
+#endif
+}
+
+void ieee80211_sta_debugfs_remove(struct sta_info *sta)
+{
+ DEBUGFS_DEL(flags);
+ DEBUGFS_DEL(num_ps_buf_frames);
+ DEBUGFS_DEL(last_ack_rssi);
+ DEBUGFS_DEL(last_ack_ms);
+ DEBUGFS_DEL(inactive_ms);
+ DEBUGFS_DEL(last_seq_ctrl);
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ DEBUGFS_DEL(wme_rx_queue);
+ DEBUGFS_DEL(wme_tx_queue);
+#endif
+
+ debugfs_remove(sta->debugfs.dir);
+ sta->debugfs.dir = NULL;
+}
diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h
new file mode 100644
index 00000000000..574a1cd54b9
--- /dev/null
+++ b/net/mac80211/debugfs_sta.h
@@ -0,0 +1,12 @@
+#ifndef __MAC80211_DEBUGFS_STA_H
+#define __MAC80211_DEBUGFS_STA_H
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ieee80211_sta_debugfs_add(struct sta_info *sta);
+void ieee80211_sta_debugfs_remove(struct sta_info *sta);
+#else
+static inline void ieee80211_sta_debugfs_add(struct sta_info *sta) {}
+static inline void ieee80211_sta_debugfs_remove(struct sta_info *sta) {}
+#endif
+
+#endif /* __MAC80211_DEBUGFS_STA_H */
diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h
new file mode 100644
index 00000000000..34fa128e987
--- /dev/null
+++ b/net/mac80211/hostapd_ioctl.h
@@ -0,0 +1,108 @@
+/*
+ * Host AP (software wireless LAN access point) user space daemon for
+ * Host AP kernel driver
+ * Copyright 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef HOSTAPD_IOCTL_H
+#define HOSTAPD_IOCTL_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#endif /* __KERNEL__ */
+
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
+#define PRISM2_IOCTL_HOSTAPD (SIOCIWFIRSTPRIV + 3)
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes:
+ * This table is no longer added to, the whole sub-ioctl
+ * mess shall be deleted completely. */
+enum {
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+
+ /* Instant802 additions */
+ PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 1002,
+ PRISM2_PARAM_PREAMBLE = 1003,
+ PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
+ PRISM2_PARAM_NEXT_MODE = 1008,
+ PRISM2_PARAM_CLEAR_KEYS = 1009,
+ PRISM2_PARAM_RADIO_ENABLED = 1010,
+ PRISM2_PARAM_ANTENNA_MODE = 1013,
+ PRISM2_PARAM_STAT_TIME = 1016,
+ PRISM2_PARAM_STA_ANTENNA_SEL = 1017,
+ PRISM2_PARAM_FORCE_UNICAST_RATE = 1018,
+ PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019,
+ PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020,
+ PRISM2_PARAM_MAX_RATECTRL_RATE = 1021,
+ PRISM2_PARAM_TX_POWER_REDUCTION = 1022,
+ PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024,
+ PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026,
+ PRISM2_PARAM_WIFI_WME_NOACK_TEST = 1033,
+ PRISM2_PARAM_SCAN_FLAGS = 1035,
+ PRISM2_PARAM_HW_MODES = 1036,
+ PRISM2_PARAM_CREATE_IBSS = 1037,
+ PRISM2_PARAM_WMM_ENABLED = 1038,
+ PRISM2_PARAM_MIXED_CELL = 1039,
+ PRISM2_PARAM_RADAR_DETECT = 1043,
+ PRISM2_PARAM_SPECTRUM_MGMT = 1044,
+};
+
+enum {
+ IEEE80211_KEY_MGMT_NONE = 0,
+ IEEE80211_KEY_MGMT_IEEE8021X = 1,
+ IEEE80211_KEY_MGMT_WPA_PSK = 2,
+ IEEE80211_KEY_MGMT_WPA_EAP = 3,
+};
+
+
+/* Data structures used for get_hw_features ioctl */
+struct hostapd_ioctl_hw_modes_hdr {
+ int mode;
+ int num_channels;
+ int num_rates;
+};
+
+struct ieee80211_channel_data {
+ short chan; /* channel number (IEEE 802.11) */
+ short freq; /* frequency in MHz */
+ int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */
+};
+
+struct ieee80211_rate_data {
+ int rate; /* rate in 100 kbps */
+ int flags; /* IEEE80211_RATE_ flags */
+};
+
+
+/* ADD_IF, REMOVE_IF, and UPDATE_IF 'type' argument */
+enum {
+ HOSTAP_IF_WDS = 1, HOSTAP_IF_VLAN = 2, HOSTAP_IF_BSS = 3,
+ HOSTAP_IF_STA = 4
+};
+
+struct hostapd_if_wds {
+ u8 remote_addr[ETH_ALEN];
+};
+
+struct hostapd_if_vlan {
+ u8 id;
+};
+
+struct hostapd_if_bss {
+ u8 bssid[ETH_ALEN];
+};
+
+struct hostapd_if_sta {
+};
+
+#endif /* HOSTAPD_IOCTL_H */
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
new file mode 100644
index 00000000000..6e36df67f8d
--- /dev/null
+++ b/net/mac80211/ieee80211.c
@@ -0,0 +1,4984 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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 <net/mac80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/rtnetlink.h>
+#include <net/iw_handler.h>
+#include <linux/compiler.h>
+#include <linux/bitmap.h>
+#include <net/cfg80211.h>
+
+#include "ieee80211_common.h"
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "wep.h"
+#include "wpa.h"
+#include "tkip.h"
+#include "wme.h"
+#include "aes_ccm.h"
+#include "ieee80211_led.h"
+#include "ieee80211_cfg.h"
+#include "debugfs.h"
+#include "debugfs_netdev.h"
+#include "debugfs_key.h"
+
+/* privid for wiphys to determine whether they belong to us or not */
+void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
+
+/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
+/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
+static const unsigned char rfc1042_header[] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
+static const unsigned char bridge_tunnel_header[] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+
+/* No encapsulation header if EtherType < 0x600 (=length) */
+static const unsigned char eapol_header[] =
+ { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
+
+
+static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_hdr *hdr)
+{
+ /* Set the sequence number for this frame. */
+ hdr->seq_ctrl = cpu_to_le16(sdata->sequence);
+
+ /* Increase the sequence number. */
+ sdata->sequence = (sdata->sequence + 0x10) & IEEE80211_SCTL_SEQ;
+}
+
+struct ieee80211_key_conf *
+ieee80211_key_data2conf(struct ieee80211_local *local,
+ const struct ieee80211_key *data)
+{
+ struct ieee80211_key_conf *conf;
+
+ conf = kmalloc(sizeof(*conf) + data->keylen, GFP_ATOMIC);
+ if (!conf)
+ return NULL;
+
+ conf->hw_key_idx = data->hw_key_idx;
+ conf->alg = data->alg;
+ conf->keylen = data->keylen;
+ conf->flags = 0;
+ if (data->force_sw_encrypt)
+ conf->flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
+ conf->keyidx = data->keyidx;
+ if (data->default_tx_key)
+ conf->flags |= IEEE80211_KEY_DEFAULT_TX_KEY;
+ if (local->default_wep_only)
+ conf->flags |= IEEE80211_KEY_DEFAULT_WEP_ONLY;
+ memcpy(conf->key, data->key, data->keylen);
+
+ return conf;
+}
+
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+ int idx, size_t key_len, gfp_t flags)
+{
+ struct ieee80211_key *key;
+
+ key = kzalloc(sizeof(struct ieee80211_key) + key_len, flags);
+ if (!key)
+ return NULL;
+ kref_init(&key->kref);
+ return key;
+}
+
+static void ieee80211_key_release(struct kref *kref)
+{
+ struct ieee80211_key *key;
+
+ key = container_of(kref, struct ieee80211_key, kref);
+ if (key->alg == ALG_CCMP)
+ ieee80211_aes_key_free(key->u.ccmp.tfm);
+ ieee80211_debugfs_key_remove(key);
+ kfree(key);
+}
+
+void ieee80211_key_free(struct ieee80211_key *key)
+{
+ if (key)
+ kref_put(&key->kref, ieee80211_key_release);
+}
+
+static int rate_list_match(const int *rate_list, int rate)
+{
+ int i;
+
+ if (!rate_list)
+ return 0;
+
+ for (i = 0; rate_list[i] >= 0; i++)
+ if (rate_list[i] == rate)
+ return 1;
+
+ return 0;
+}
+
+
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+
+ rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
+ IEEE80211_RATE_BASIC);
+
+ if (local->supp_rates[mode->mode]) {
+ if (!rate_list_match(local->supp_rates[mode->mode],
+ rate->rate))
+ continue;
+ }
+
+ rate->flags |= IEEE80211_RATE_SUPPORTED;
+
+ /* Use configured basic rate set if it is available. If not,
+ * use defaults that are sane for most cases. */
+ if (local->basic_rates[mode->mode]) {
+ if (rate_list_match(local->basic_rates[mode->mode],
+ rate->rate))
+ rate->flags |= IEEE80211_RATE_BASIC;
+ } else switch (mode->mode) {
+ case MODE_IEEE80211A:
+ if (rate->rate == 60 || rate->rate == 120 ||
+ rate->rate == 240)
+ rate->flags |= IEEE80211_RATE_BASIC;
+ break;
+ case MODE_IEEE80211B:
+ if (rate->rate == 10 || rate->rate == 20)
+ rate->flags |= IEEE80211_RATE_BASIC;
+ break;
+ case MODE_ATHEROS_TURBO:
+ if (rate->rate == 120 || rate->rate == 240 ||
+ rate->rate == 480)
+ rate->flags |= IEEE80211_RATE_BASIC;
+ break;
+ case MODE_IEEE80211G:
+ if (rate->rate == 10 || rate->rate == 20 ||
+ rate->rate == 55 || rate->rate == 110)
+ rate->flags |= IEEE80211_RATE_BASIC;
+ break;
+ }
+
+ /* Set ERP and MANDATORY flags based on phymode */
+ switch (mode->mode) {
+ case MODE_IEEE80211A:
+ if (rate->rate == 60 || rate->rate == 120 ||
+ rate->rate == 240)
+ rate->flags |= IEEE80211_RATE_MANDATORY;
+ break;
+ case MODE_IEEE80211B:
+ if (rate->rate == 10)
+ rate->flags |= IEEE80211_RATE_MANDATORY;
+ break;
+ case MODE_ATHEROS_TURBO:
+ break;
+ case MODE_IEEE80211G:
+ if (rate->rate == 10 || rate->rate == 20 ||
+ rate->rate == 55 || rate->rate == 110 ||
+ rate->rate == 60 || rate->rate == 120 ||
+ rate->rate == 240)
+ rate->flags |= IEEE80211_RATE_MANDATORY;
+ break;
+ }
+ if (ieee80211_is_erp_rate(mode->mode, rate->rate))
+ rate->flags |= IEEE80211_RATE_ERP;
+ }
+}
+
+
+static void ieee80211_key_threshold_notify(struct net_device *dev,
+ struct ieee80211_key *key,
+ struct sta_info *sta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ struct ieee80211_msg_key_notification *msg;
+
+ /* if no one will get it anyway, don't even allocate it.
+ * unlikely because this is only relevant for APs
+ * where the device must be open... */
+ if (unlikely(!local->apdev))
+ return;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+ sizeof(struct ieee80211_msg_key_notification));
+ if (!skb)
+ return;
+
+ skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+ msg = (struct ieee80211_msg_key_notification *)
+ skb_put(skb, sizeof(struct ieee80211_msg_key_notification));
+ msg->tx_rx_count = key->tx_rx_count;
+ memcpy(msg->ifname, dev->name, IFNAMSIZ);
+ if (sta)
+ memcpy(msg->addr, sta->addr, ETH_ALEN);
+ else
+ memset(msg->addr, 0xff, ETH_ALEN);
+
+ key->tx_rx_count = 0;
+
+ ieee80211_rx_mgmt(local, skb, NULL,
+ ieee80211_msg_key_threshold_notification);
+}
+
+
+static u8 * ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len)
+{
+ u16 fc;
+
+ if (len < 24)
+ return NULL;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_DATA:
+ switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+ case IEEE80211_FCTL_TODS:
+ return hdr->addr1;
+ case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+ return NULL;
+ case IEEE80211_FCTL_FROMDS:
+ return hdr->addr2;
+ case 0:
+ return hdr->addr3;
+ }
+ break;
+ case IEEE80211_FTYPE_MGMT:
+ return hdr->addr3;
+ case IEEE80211_FTYPE_CTL:
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)
+ return hdr->addr1;
+ else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+int ieee80211_get_hdrlen(u16 fc)
+{
+ int hdrlen = 24;
+
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+ hdrlen = 30; /* Addr4 */
+ /*
+ * The QoS Control field is two bytes and its presence is
+ * indicated by the IEEE80211_STYPE_QOS_DATA bit. Add 2 to
+ * hdrlen if that bit is set.
+ * This works by masking out the bit and shifting it to
+ * bit position 1 so the result has the value 0 or 2.
+ */
+ hdrlen += (fc & IEEE80211_STYPE_QOS_DATA)
+ >> (ilog2(IEEE80211_STYPE_QOS_DATA)-1);
+ break;
+ case IEEE80211_FTYPE_CTL:
+ /*
+ * ACK and CTS are 10 bytes, all others 16. To see how
+ * to get this condition consider
+ * subtype mask: 0b0000000011110000 (0x00F0)
+ * ACK subtype: 0b0000000011010000 (0x00D0)
+ * CTS subtype: 0b0000000011000000 (0x00C0)
+ * bits that matter: ^^^ (0x00E0)
+ * value of those: 0b0000000011000000 (0x00C0)
+ */
+ if ((fc & 0xE0) == 0xC0)
+ hdrlen = 10;
+ else
+ hdrlen = 16;
+ break;
+ }
+
+ return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen);
+
+int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
+{
+ const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) skb->data;
+ int hdrlen;
+
+ if (unlikely(skb->len < 10))
+ return 0;
+ hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control));
+ if (unlikely(hdrlen > skb->len))
+ return 0;
+ return hdrlen;
+}
+EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
+
+static int ieee80211_get_radiotap_len(struct sk_buff *skb)
+{
+ struct ieee80211_radiotap_header *hdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+
+ return le16_to_cpu(hdr->it_len);
+}
+
+#ifdef CONFIG_MAC80211_LOWTX_FRAME_DUMP
+static void ieee80211_dump_frame(const char *ifname, const char *title,
+ const struct sk_buff *skb)
+{
+ const struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc;
+ int hdrlen;
+
+ printk(KERN_DEBUG "%s: %s (len=%d)", ifname, title, skb->len);
+ if (skb->len < 4) {
+ printk("\n");
+ return;
+ }
+
+ fc = le16_to_cpu(hdr->frame_control);
+ hdrlen = ieee80211_get_hdrlen(fc);
+ if (hdrlen > skb->len)
+ hdrlen = skb->len;
+ if (hdrlen >= 4)
+ printk(" FC=0x%04x DUR=0x%04x",
+ fc, le16_to_cpu(hdr->duration_id));
+ if (hdrlen >= 10)
+ printk(" A1=" MAC_FMT, MAC_ARG(hdr->addr1));
+ if (hdrlen >= 16)
+ printk(" A2=" MAC_FMT, MAC_ARG(hdr->addr2));
+ if (hdrlen >= 24)
+ printk(" A3=" MAC_FMT, MAC_ARG(hdr->addr3));
+ if (hdrlen >= 30)
+ printk(" A4=" MAC_FMT, MAC_ARG(hdr->addr4));
+ printk("\n");
+}
+#else /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
+static inline void ieee80211_dump_frame(const char *ifname, const char *title,
+ struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */
+
+
+static int ieee80211_is_eapol(const struct sk_buff *skb)
+{
+ const struct ieee80211_hdr *hdr;
+ u16 fc;
+ int hdrlen;
+
+ if (unlikely(skb->len < 10))
+ return 0;
+
+ hdr = (const struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+ return 0;
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ if (unlikely(skb->len >= hdrlen + sizeof(eapol_header) &&
+ memcmp(skb->data + hdrlen, eapol_header,
+ sizeof(eapol_header)) == 0))
+ return 1;
+
+ return 0;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
+{
+ struct rate_control_extra extra;
+
+ memset(&extra, 0, sizeof(extra));
+ extra.mode = tx->u.tx.mode;
+ extra.mgmt_data = tx->sdata &&
+ tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
+ extra.ethertype = tx->ethertype;
+
+ tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb,
+ &extra);
+ if (unlikely(extra.probe != NULL)) {
+ tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ tx->u.tx.probe_last_frag = 1;
+ tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val;
+ tx->u.tx.rate = extra.probe;
+ } else {
+ tx->u.tx.control->alt_retry_rate = -1;
+ }
+ if (!tx->u.tx.rate)
+ return TXRX_DROP;
+ if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
+ tx->local->cts_protect_erp_frames && tx->fragmented &&
+ extra.nonerp) {
+ tx->u.tx.last_frag_rate = tx->u.tx.rate;
+ tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
+
+ tx->u.tx.rate = extra.nonerp;
+ tx->u.tx.control->rate = extra.nonerp;
+ tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ } else {
+ tx->u.tx.last_frag_rate = tx->u.tx.rate;
+ tx->u.tx.control->rate = tx->u.tx.rate;
+ }
+ tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
+ if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
+ tx->local->short_preamble &&
+ (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) {
+ tx->u.tx.short_preamble = 1;
+ tx->u.tx.control->tx_rate = tx->u.tx.rate->val2;
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
+{
+ if (tx->sta)
+ tx->u.tx.control->key_idx = tx->sta->key_idx_compression;
+ else
+ tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
+
+ if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+ tx->key = NULL;
+ else if (tx->sta && tx->sta->key)
+ tx->key = tx->sta->key;
+ else if (tx->sdata->default_key)
+ tx->key = tx->sdata->default_key;
+ else if (tx->sdata->drop_unencrypted &&
+ !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
+ return TXRX_DROP;
+ } else
+ tx->key = NULL;
+
+ if (tx->key) {
+ tx->key->tx_rx_count++;
+ if (unlikely(tx->local->key_tx_rx_threshold &&
+ tx->key->tx_rx_count >
+ tx->local->key_tx_rx_threshold)) {
+ ieee80211_key_threshold_notify(tx->dev, tx->key,
+ tx->sta);
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ size_t hdrlen, per_fragm, num_fragm, payload_len, left;
+ struct sk_buff **frags, *first, *frag;
+ int i;
+ u16 seq;
+ u8 *pos;
+ int frag_threshold = tx->local->fragmentation_threshold;
+
+ if (!tx->fragmented)
+ return TXRX_CONTINUE;
+
+ first = tx->skb;
+
+ hdrlen = ieee80211_get_hdrlen(tx->fc);
+ payload_len = first->len - hdrlen;
+ per_fragm = frag_threshold - hdrlen - FCS_LEN;
+ num_fragm = (payload_len + per_fragm - 1) / per_fragm;
+
+ frags = kzalloc(num_fragm * sizeof(struct sk_buff *), GFP_ATOMIC);
+ if (!frags)
+ goto fail;
+
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS);
+ seq = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ;
+ pos = first->data + hdrlen + per_fragm;
+ left = payload_len - per_fragm;
+ for (i = 0; i < num_fragm - 1; i++) {
+ struct ieee80211_hdr *fhdr;
+ size_t copylen;
+
+ if (left <= 0)
+ goto fail;
+
+ /* reserve enough extra head and tail room for possible
+ * encryption */
+ frag = frags[i] =
+ dev_alloc_skb(tx->local->hw.extra_tx_headroom +
+ frag_threshold +
+ IEEE80211_ENCRYPT_HEADROOM +
+ IEEE80211_ENCRYPT_TAILROOM);
+ if (!frag)
+ goto fail;
+ /* Make sure that all fragments use the same priority so
+ * that they end up using the same TX queue */
+ frag->priority = first->priority;
+ skb_reserve(frag, tx->local->hw.extra_tx_headroom +
+ IEEE80211_ENCRYPT_HEADROOM);
+ fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
+ memcpy(fhdr, first->data, hdrlen);
+ if (i == num_fragm - 2)
+ fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS);
+ fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG));
+ copylen = left > per_fragm ? per_fragm : left;
+ memcpy(skb_put(frag, copylen), pos, copylen);
+
+ pos += copylen;
+ left -= copylen;
+ }
+ skb_trim(first, hdrlen + per_fragm);
+
+ tx->u.tx.num_extra_frag = num_fragm - 1;
+ tx->u.tx.extra_frag = frags;
+
+ return TXRX_CONTINUE;
+
+ fail:
+ printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name);
+ if (frags) {
+ for (i = 0; i < num_fragm - 1; i++)
+ if (frags[i])
+ dev_kfree_skb(frags[i]);
+ kfree(frags);
+ }
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment);
+ return TXRX_DROP;
+}
+
+
+static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb)
+{
+ if (tx->key->force_sw_encrypt) {
+ if (ieee80211_wep_encrypt(tx->local, skb, tx->key))
+ return -1;
+ } else {
+ tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+ if (tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+ if (ieee80211_wep_add_iv(tx->local, skb, tx->key) ==
+ NULL)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ if (tx->u.tx.extra_frag) {
+ struct ieee80211_hdr *fhdr;
+ int i;
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ fhdr = (struct ieee80211_hdr *)
+ tx->u.tx.extra_frag[i]->data;
+ fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ }
+ }
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_wep_encrypt(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ u16 fc;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+ if (!tx->key || tx->key->alg != ALG_WEP ||
+ ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+ ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+ (fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
+ return TXRX_CONTINUE;
+
+ tx->u.tx.control->iv_len = WEP_IV_LEN;
+ tx->u.tx.control->icv_len = WEP_ICV_LEN;
+ ieee80211_tx_set_iswep(tx);
+
+ if (wep_encrypt_skb(tx, tx->skb) < 0) {
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_wep);
+ return TXRX_DROP;
+ }
+
+ if (tx->u.tx.extra_frag) {
+ int i;
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) {
+ I802_DEBUG_INC(tx->local->
+ tx_handlers_drop_wep);
+ return TXRX_DROP;
+ }
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
+ int rate, int erp, int short_preamble)
+{
+ int dur;
+
+ /* calculate duration (in microseconds, rounded up to next higher
+ * integer if it includes a fractional microsecond) to send frame of
+ * len bytes (does not include FCS) at the given rate. Duration will
+ * also include SIFS.
+ *
+ * rate is in 100 kbps, so divident is multiplied by 10 in the
+ * DIV_ROUND_UP() operations.
+ */
+
+ if (local->hw.conf.phymode == MODE_IEEE80211A || erp ||
+ local->hw.conf.phymode == MODE_ATHEROS_TURBO) {
+ /*
+ * OFDM:
+ *
+ * N_DBPS = DATARATE x 4
+ * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
+ * (16 = SIGNAL time, 6 = tail bits)
+ * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
+ *
+ * T_SYM = 4 usec
+ * 802.11a - 17.5.2: aSIFSTime = 16 usec
+ * 802.11g - 19.8.4: aSIFSTime = 10 usec +
+ * signal ext = 6 usec
+ */
+ /* FIX: Atheros Turbo may have different (shorter) duration? */
+ dur = 16; /* SIFS + signal ext */
+ dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
+ dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
+ dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
+ 4 * rate); /* T_SYM x N_SYM */
+ } else {
+ /*
+ * 802.11b or 802.11g with 802.11b compatibility:
+ * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
+ * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
+ *
+ * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
+ * aSIFSTime = 10 usec
+ * aPreambleLength = 144 usec or 72 usec with short preamble
+ * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
+ */
+ dur = 10; /* aSIFSTime = 10 usec */
+ dur += short_preamble ? (72 + 24) : (144 + 48);
+
+ dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
+ }
+
+ return dur;
+}
+
+
+/* Exported duration function for driver use */
+__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
+ size_t frame_len, int rate)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ u16 dur;
+ int erp;
+
+ erp = ieee80211_is_erp_rate(hw->conf.phymode, rate);
+ dur = ieee80211_frame_duration(local, frame_len, rate,
+ erp, local->short_preamble);
+
+ return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_generic_frame_duration);
+
+
+static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr,
+ int next_frag_len)
+{
+ int rate, mrate, erp, dur, i;
+ struct ieee80211_rate *txrate = tx->u.tx.rate;
+ struct ieee80211_local *local = tx->local;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+
+ erp = txrate->flags & IEEE80211_RATE_ERP;
+
+ /*
+ * data and mgmt (except PS Poll):
+ * - during CFP: 32768
+ * - during contention period:
+ * if addr1 is group address: 0
+ * if more fragments = 0 and addr1 is individual address: time to
+ * transmit one ACK plus SIFS
+ * if more fragments = 1 and addr1 is individual address: time to
+ * transmit next fragment plus 2 x ACK plus 3 x SIFS
+ *
+ * IEEE 802.11, 9.6:
+ * - control response frame (CTS or ACK) shall be transmitted using the
+ * same rate as the immediately previous frame in the frame exchange
+ * sequence, if this rate belongs to the PHY mandatory rates, or else
+ * at the highest possible rate belonging to the PHY rates in the
+ * BSSBasicRateSet
+ */
+
+ if ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) {
+ /* TODO: These control frames are not currently sent by
+ * 80211.o, but should they be implemented, this function
+ * needs to be updated to support duration field calculation.
+ *
+ * RTS: time needed to transmit pending data/mgmt frame plus
+ * one CTS frame plus one ACK frame plus 3 x SIFS
+ * CTS: duration of immediately previous RTS minus time
+ * required to transmit CTS and its SIFS
+ * ACK: 0 if immediately previous directed data/mgmt had
+ * more=0, with more=1 duration in ACK frame is duration
+ * from previous frame minus time needed to transmit ACK
+ * and its SIFS
+ * PS Poll: BIT(15) | BIT(14) | aid
+ */
+ return 0;
+ }
+
+ /* data/mgmt */
+ if (0 /* FIX: data/mgmt during CFP */)
+ return 32768;
+
+ if (group_addr) /* Group address as the destination - no ACK */
+ return 0;
+
+ /* Individual destination address:
+ * IEEE 802.11, Ch. 9.6 (after IEEE 802.11g changes)
+ * CTS and ACK frames shall be transmitted using the highest rate in
+ * basic rate set that is less than or equal to the rate of the
+ * immediately previous frame and that is using the same modulation
+ * (CCK or OFDM). If no basic rate set matches with these requirements,
+ * the highest mandatory rate of the PHY that is less than or equal to
+ * the rate of the previous frame is used.
+ * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps
+ */
+ rate = -1;
+ mrate = 10; /* use 1 Mbps if everything fails */
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *r = &mode->rates[i];
+ if (r->rate > txrate->rate)
+ break;
+
+ if (IEEE80211_RATE_MODULATION(txrate->flags) !=
+ IEEE80211_RATE_MODULATION(r->flags))
+ continue;
+
+ if (r->flags & IEEE80211_RATE_BASIC)
+ rate = r->rate;
+ else if (r->flags & IEEE80211_RATE_MANDATORY)
+ mrate = r->rate;
+ }
+ if (rate == -1) {
+ /* No matching basic rate found; use highest suitable mandatory
+ * PHY rate */
+ rate = mrate;
+ }
+
+ /* Time needed to transmit ACK
+ * (10 bytes + 4-byte FCS = 112 bits) plus SIFS; rounded up
+ * to closest integer */
+
+ dur = ieee80211_frame_duration(local, 10, rate, erp,
+ local->short_preamble);
+
+ if (next_frag_len) {
+ /* Frame is fragmented: duration increases with time needed to
+ * transmit next fragment plus ACK and 2 x SIFS. */
+ dur *= 2; /* ACK + SIFS */
+ /* next fragment */
+ dur += ieee80211_frame_duration(local, next_frag_len,
+ txrate->rate, erp,
+ local->short_preamble);
+ }
+
+ return dur;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ u16 dur;
+ struct ieee80211_tx_control *control = tx->u.tx.control;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+
+ if (!is_multicast_ether_addr(hdr->addr1)) {
+ if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
+ tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD) {
+ control->flags |= IEEE80211_TXCTL_USE_RTS_CTS;
+ control->retry_limit =
+ tx->local->long_retry_limit;
+ } else {
+ control->retry_limit =
+ tx->local->short_retry_limit;
+ }
+ } else {
+ control->retry_limit = 1;
+ }
+
+ if (tx->fragmented) {
+ /* Do not use multiple retry rates when sending fragmented
+ * frames.
+ * TODO: The last fragment could still use multiple retry
+ * rates. */
+ control->alt_retry_rate = -1;
+ }
+
+ /* Use CTS protection for unicast frames sent using extended rates if
+ * there are associated non-ERP stations and RTS/CTS is not configured
+ * for the frame. */
+ if (mode->mode == MODE_IEEE80211G &&
+ (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
+ tx->u.tx.unicast &&
+ tx->local->cts_protect_erp_frames &&
+ !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
+ control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
+
+ /* Setup duration field for the first fragment of the frame. Duration
+ * for remaining fragments will be updated when they are being sent
+ * to low-level driver in ieee80211_tx(). */
+ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1),
+ tx->fragmented ? tx->u.tx.extra_frag[0]->len :
+ 0);
+ hdr->duration_id = cpu_to_le16(dur);
+
+ if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+ (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+ struct ieee80211_rate *rate;
+
+ /* Do not use multiple retry rates when using RTS/CTS */
+ control->alt_retry_rate = -1;
+
+ /* Use min(data rate, max base rate) as CTS/RTS rate */
+ rate = tx->u.tx.rate;
+ while (rate > mode->rates &&
+ !(rate->flags & IEEE80211_RATE_BASIC))
+ rate--;
+
+ control->rts_cts_rate = rate->val;
+ control->rts_rate = rate;
+ }
+
+ if (tx->sta) {
+ tx->sta->tx_packets++;
+ tx->sta->tx_fragments++;
+ tx->sta->tx_bytes += tx->skb->len;
+ if (tx->u.tx.extra_frag) {
+ int i;
+ tx->sta->tx_fragments += tx->u.tx.num_extra_frag;
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ tx->sta->tx_bytes +=
+ tx->u.tx.extra_frag[i]->len;
+ }
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ struct sk_buff *skb = tx->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ u32 sta_flags;
+
+ if (unlikely(tx->local->sta_scanning != 0) &&
+ ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+ (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ))
+ return TXRX_DROP;
+
+ if (tx->u.tx.ps_buffered)
+ return TXRX_CONTINUE;
+
+ sta_flags = tx->sta ? tx->sta->flags : 0;
+
+ if (likely(tx->u.tx.unicast)) {
+ if (unlikely(!(sta_flags & WLAN_STA_ASSOC) &&
+ tx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+ (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: dropped data frame to not "
+ "associated station " MAC_FMT "\n",
+ tx->dev->name, MAC_ARG(hdr->addr1));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc);
+ return TXRX_DROP;
+ }
+ } else {
+ if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ tx->local->num_sta == 0 &&
+ !tx->local->allow_broadcast_always &&
+ tx->sdata->type != IEEE80211_IF_TYPE_IBSS)) {
+ /*
+ * No associated STAs - no need to send multicast
+ * frames.
+ */
+ return TXRX_DROP;
+ }
+ return TXRX_CONTINUE;
+ }
+
+ if (unlikely(!tx->u.tx.mgmt_interface && tx->sdata->ieee802_1x &&
+ !(sta_flags & WLAN_STA_AUTHORIZED))) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: dropped frame to " MAC_FMT
+ " (unauthorized port)\n", tx->dev->name,
+ MAC_ARG(hdr->addr1));
+#endif
+ I802_DEBUG_INC(tx->local->tx_handlers_drop_unauth_port);
+ return TXRX_DROP;
+ }
+
+ return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
+
+ if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24)
+ ieee80211_include_sequence(tx->sdata, hdr);
+
+ return TXRX_CONTINUE;
+}
+
+/* This function is called whenever the AP is about to exceed the maximum limit
+ * of buffered frames for power saving STAs. This situation should not really
+ * happen often during normal operation, so dropping the oldest buffered packet
+ * from each queue should be OK to make some room for new frames. */
+static void purge_old_ps_buffers(struct ieee80211_local *local)
+{
+ int total = 0, purged = 0;
+ struct sk_buff *skb;
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ struct ieee80211_if_ap *ap;
+ if (sdata->dev == local->mdev ||
+ sdata->type != IEEE80211_IF_TYPE_AP)
+ continue;
+ ap = &sdata->u.ap;
+ skb = skb_dequeue(&ap->ps_bc_buf);
+ if (skb) {
+ purged++;
+ dev_kfree_skb(skb);
+ }
+ total += skb_queue_len(&ap->ps_bc_buf);
+ }
+ read_unlock(&local->sub_if_lock);
+
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ skb = skb_dequeue(&sta->ps_tx_buf);
+ if (skb) {
+ purged++;
+ dev_kfree_skb(skb);
+ }
+ total += skb_queue_len(&sta->ps_tx_buf);
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ local->total_ps_buffered = total;
+ printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n",
+ local->mdev->name, purged);
+}
+
+
+static inline ieee80211_txrx_result
+ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx)
+{
+ /* broadcast/multicast frame */
+ /* If any of the associated stations is in power save mode,
+ * the frame is buffered to be sent after DTIM beacon frame */
+ if ((tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) &&
+ tx->sdata->type != IEEE80211_IF_TYPE_WDS &&
+ tx->sdata->bss && atomic_read(&tx->sdata->bss->num_sta_ps) &&
+ !(tx->fc & IEEE80211_FCTL_ORDER)) {
+ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+ purge_old_ps_buffers(tx->local);
+ if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >=
+ AP_MAX_BC_BUFFER) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: BC TX buffer full - "
+ "dropping the oldest frame\n",
+ tx->dev->name);
+ }
+ dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf));
+ } else
+ tx->local->total_ps_buffered++;
+ skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb);
+ return TXRX_QUEUED;
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static inline ieee80211_txrx_result
+ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx)
+{
+ struct sta_info *sta = tx->sta;
+
+ if (unlikely(!sta ||
+ ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT &&
+ (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP)))
+ return TXRX_CONTINUE;
+
+ if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) {
+ struct ieee80211_tx_packet_data *pkt_data;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS buffer (entries "
+ "before %d)\n",
+ MAC_ARG(sta->addr), sta->aid,
+ skb_queue_len(&sta->ps_tx_buf));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ sta->flags |= WLAN_STA_TIM;
+ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
+ purge_old_ps_buffers(tx->local);
+ if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) {
+ struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf);
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " TX "
+ "buffer full - dropping oldest frame\n",
+ tx->dev->name, MAC_ARG(sta->addr));
+ }
+ dev_kfree_skb(old);
+ } else
+ tx->local->total_ps_buffered++;
+ /* Queue frame to be sent after STA sends an PS Poll frame */
+ if (skb_queue_empty(&sta->ps_tx_buf)) {
+ if (tx->local->ops->set_tim)
+ tx->local->ops->set_tim(local_to_hw(tx->local),
+ sta->aid, 1);
+ if (tx->sdata->bss)
+ bss_tim_set(tx->local, tx->sdata->bss, sta->aid);
+ }
+ pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb;
+ pkt_data->jiffies = jiffies;
+ skb_queue_tail(&sta->ps_tx_buf, tx->skb);
+ return TXRX_QUEUED;
+ }
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ else if (unlikely(sta->flags & WLAN_STA_PS)) {
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " in PS mode, but pspoll "
+ "set -> send frame\n", tx->dev->name,
+ MAC_ARG(sta->addr));
+ }
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ sta->pspoll = 0;
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
+{
+ if (unlikely(tx->u.tx.ps_buffered))
+ return TXRX_CONTINUE;
+
+ if (tx->u.tx.unicast)
+ return ieee80211_tx_h_unicast_ps_buf(tx);
+ else
+ return ieee80211_tx_h_multicast_ps_buf(tx);
+}
+
+
+static void inline
+__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb,
+ struct net_device *dev,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ int hdrlen;
+
+ memset(tx, 0, sizeof(*tx));
+ tx->skb = skb;
+ tx->dev = dev; /* use original interface */
+ tx->local = local;
+ tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ tx->sta = sta_info_get(local, hdr->addr1);
+ tx->fc = le16_to_cpu(hdr->frame_control);
+ control->power_level = local->hw.conf.power_level;
+ tx->u.tx.control = control;
+ tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
+ if (is_multicast_ether_addr(hdr->addr1))
+ control->flags |= IEEE80211_TXCTL_NO_ACK;
+ else
+ control->flags &= ~IEEE80211_TXCTL_NO_ACK;
+ tx->fragmented = local->fragmentation_threshold <
+ IEEE80211_MAX_FRAG_THRESHOLD && tx->u.tx.unicast &&
+ skb->len + FCS_LEN > local->fragmentation_threshold &&
+ (!local->ops->set_frag_threshold);
+ if (!tx->sta)
+ control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+ else if (tx->sta->clear_dst_mask) {
+ control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+ tx->sta->clear_dst_mask = 0;
+ }
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
+ control->antenna_sel_tx = tx->sta->antenna_sel_tx;
+ hdrlen = ieee80211_get_hdrlen(tx->fc);
+ if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
+ u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
+ tx->ethertype = (pos[0] << 8) | pos[1];
+ }
+ control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+
+}
+
+static int inline is_ieee80211_device(struct net_device *dev,
+ struct net_device *master)
+{
+ return (wdev_priv(dev->ieee80211_ptr) ==
+ wdev_priv(master->ieee80211_ptr));
+}
+
+/* Device in tx->dev has a reference added; use dev_put(tx->dev) when
+ * finished with it. */
+static int inline ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb,
+ struct net_device *mdev,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct net_device *dev;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ dev = dev_get_by_index(pkt_data->ifindex);
+ if (unlikely(dev && !is_ieee80211_device(dev, mdev))) {
+ dev_put(dev);
+ dev = NULL;
+ }
+ if (unlikely(!dev))
+ return -ENODEV;
+ __ieee80211_tx_prepare(tx, skb, dev, control);
+ return 0;
+}
+
+static inline int __ieee80211_queue_stopped(const struct ieee80211_local *local,
+ int queue)
+{
+ return test_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+
+static inline int __ieee80211_queue_pending(const struct ieee80211_local *local,
+ int queue)
+{
+ return test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue]);
+}
+
+#define IEEE80211_TX_OK 0
+#define IEEE80211_TX_AGAIN 1
+#define IEEE80211_TX_FRAG_AGAIN 2
+
+static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_tx_control *control = tx->u.tx.control;
+ int ret, i;
+
+ if (!ieee80211_qdisc_installed(local->mdev) &&
+ __ieee80211_queue_stopped(local, 0)) {
+ netif_stop_queue(local->mdev);
+ return IEEE80211_TX_AGAIN;
+ }
+ if (skb) {
+ ieee80211_dump_frame(local->mdev->name, "TX to low-level driver", skb);
+ ret = local->ops->tx(local_to_hw(local), skb, control);
+ if (ret)
+ return IEEE80211_TX_AGAIN;
+ local->mdev->trans_start = jiffies;
+ ieee80211_led_tx(local, 1);
+ }
+ if (tx->u.tx.extra_frag) {
+ control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT |
+ IEEE80211_TXCTL_CLEAR_DST_MASK |
+ IEEE80211_TXCTL_FIRST_FRAGMENT);
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ if (!tx->u.tx.extra_frag[i])
+ continue;
+ if (__ieee80211_queue_stopped(local, control->queue))
+ return IEEE80211_TX_FRAG_AGAIN;
+ if (i == tx->u.tx.num_extra_frag) {
+ control->tx_rate = tx->u.tx.last_frag_hwrate;
+ control->rate = tx->u.tx.last_frag_rate;
+ if (tx->u.tx.probe_last_frag)
+ control->flags |=
+ IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ else
+ control->flags &=
+ ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
+ }
+
+ ieee80211_dump_frame(local->mdev->name,
+ "TX to low-level driver",
+ tx->u.tx.extra_frag[i]);
+ ret = local->ops->tx(local_to_hw(local),
+ tx->u.tx.extra_frag[i],
+ control);
+ if (ret)
+ return IEEE80211_TX_FRAG_AGAIN;
+ local->mdev->trans_start = jiffies;
+ ieee80211_led_tx(local, 1);
+ tx->u.tx.extra_frag[i] = NULL;
+ }
+ kfree(tx->u.tx.extra_frag);
+ tx->u.tx.extra_frag = NULL;
+ }
+ return IEEE80211_TX_OK;
+}
+
+static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_tx_control *control, int mgmt)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ ieee80211_tx_handler *handler;
+ struct ieee80211_txrx_data tx;
+ ieee80211_txrx_result res = TXRX_DROP;
+ int ret, i;
+
+ WARN_ON(__ieee80211_queue_pending(local, control->queue));
+
+ if (unlikely(skb->len < 10)) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ __ieee80211_tx_prepare(&tx, skb, dev, control);
+ sta = tx.sta;
+ tx.u.tx.mgmt_interface = mgmt;
+ tx.u.tx.mode = local->hw.conf.mode;
+
+ for (handler = local->tx_handlers; *handler != NULL; handler++) {
+ res = (*handler)(&tx);
+ if (res != TXRX_CONTINUE)
+ break;
+ }
+
+ skb = tx.skb; /* handlers are allowed to change skb */
+
+ if (sta)
+ sta_info_put(sta);
+
+ if (unlikely(res == TXRX_DROP)) {
+ I802_DEBUG_INC(local->tx_handlers_drop);
+ goto drop;
+ }
+
+ if (unlikely(res == TXRX_QUEUED)) {
+ I802_DEBUG_INC(local->tx_handlers_queued);
+ return 0;
+ }
+
+ if (tx.u.tx.extra_frag) {
+ for (i = 0; i < tx.u.tx.num_extra_frag; i++) {
+ int next_len, dur;
+ struct ieee80211_hdr *hdr =
+ (struct ieee80211_hdr *)
+ tx.u.tx.extra_frag[i]->data;
+
+ if (i + 1 < tx.u.tx.num_extra_frag) {
+ next_len = tx.u.tx.extra_frag[i + 1]->len;
+ } else {
+ next_len = 0;
+ tx.u.tx.rate = tx.u.tx.last_frag_rate;
+ tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val;
+ }
+ dur = ieee80211_duration(&tx, 0, next_len);
+ hdr->duration_id = cpu_to_le16(dur);
+ }
+ }
+
+retry:
+ ret = __ieee80211_tx(local, skb, &tx);
+ if (ret) {
+ struct ieee80211_tx_stored_packet *store =
+ &local->pending_packet[control->queue];
+
+ if (ret == IEEE80211_TX_FRAG_AGAIN)
+ skb = NULL;
+ set_bit(IEEE80211_LINK_STATE_PENDING,
+ &local->state[control->queue]);
+ smp_mb();
+ /* When the driver gets out of buffers during sending of
+ * fragments and calls ieee80211_stop_queue, there is
+ * a small window between IEEE80211_LINK_STATE_XOFF and
+ * IEEE80211_LINK_STATE_PENDING flags are set. If a buffer
+ * gets available in that window (i.e. driver calls
+ * ieee80211_wake_queue), we would end up with ieee80211_tx
+ * called with IEEE80211_LINK_STATE_PENDING. Prevent this by
+ * continuing transmitting here when that situation is
+ * possible to have happened. */
+ if (!__ieee80211_queue_stopped(local, control->queue)) {
+ clear_bit(IEEE80211_LINK_STATE_PENDING,
+ &local->state[control->queue]);
+ goto retry;
+ }
+ memcpy(&store->control, control,
+ sizeof(struct ieee80211_tx_control));
+ store->skb = skb;
+ store->extra_frag = tx.u.tx.extra_frag;
+ store->num_extra_frag = tx.u.tx.num_extra_frag;
+ store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
+ store->last_frag_rate = tx.u.tx.last_frag_rate;
+ store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag;
+ }
+ return 0;
+
+ drop:
+ if (skb)
+ dev_kfree_skb(skb);
+ for (i = 0; i < tx.u.tx.num_extra_frag; i++)
+ if (tx.u.tx.extra_frag[i])
+ dev_kfree_skb(tx.u.tx.extra_frag[i]);
+ kfree(tx.u.tx.extra_frag);
+ return 0;
+}
+
+static void ieee80211_tx_pending(unsigned long data)
+{
+ struct ieee80211_local *local = (struct ieee80211_local *)data;
+ struct net_device *dev = local->mdev;
+ struct ieee80211_tx_stored_packet *store;
+ struct ieee80211_txrx_data tx;
+ int i, ret, reschedule = 0;
+
+ netif_tx_lock_bh(dev);
+ for (i = 0; i < local->hw.queues; i++) {
+ if (__ieee80211_queue_stopped(local, i))
+ continue;
+ if (!__ieee80211_queue_pending(local, i)) {
+ reschedule = 1;
+ continue;
+ }
+ store = &local->pending_packet[i];
+ tx.u.tx.control = &store->control;
+ tx.u.tx.extra_frag = store->extra_frag;
+ tx.u.tx.num_extra_frag = store->num_extra_frag;
+ tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
+ tx.u.tx.last_frag_rate = store->last_frag_rate;
+ tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe;
+ ret = __ieee80211_tx(local, store->skb, &tx);
+ if (ret) {
+ if (ret == IEEE80211_TX_FRAG_AGAIN)
+ store->skb = NULL;
+ } else {
+ clear_bit(IEEE80211_LINK_STATE_PENDING,
+ &local->state[i]);
+ reschedule = 1;
+ }
+ }
+ netif_tx_unlock_bh(dev);
+ if (reschedule) {
+ if (!ieee80211_qdisc_installed(dev)) {
+ if (!__ieee80211_queue_stopped(local, 0))
+ netif_wake_queue(dev);
+ } else
+ netif_schedule(dev);
+ }
+}
+
+static void ieee80211_clear_tx_pending(struct ieee80211_local *local)
+{
+ int i, j;
+ struct ieee80211_tx_stored_packet *store;
+
+ for (i = 0; i < local->hw.queues; i++) {
+ if (!__ieee80211_queue_pending(local, i))
+ continue;
+ store = &local->pending_packet[i];
+ kfree_skb(store->skb);
+ for (j = 0; j < store->num_extra_frag; j++)
+ kfree_skb(store->extra_frag[j]);
+ kfree(store->extra_frag);
+ clear_bit(IEEE80211_LINK_STATE_PENDING, &local->state[i]);
+ }
+}
+
+static int ieee80211_master_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ieee80211_tx_control control;
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct net_device *odev = NULL;
+ struct ieee80211_sub_if_data *osdata;
+ int headroom;
+ int ret;
+
+ /*
+ * copy control out of the skb so other people can use skb->cb
+ */
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(&control, 0, sizeof(struct ieee80211_tx_control));
+
+ if (pkt_data->ifindex)
+ odev = dev_get_by_index(pkt_data->ifindex);
+ if (unlikely(odev && !is_ieee80211_device(odev, dev))) {
+ dev_put(odev);
+ odev = NULL;
+ }
+ if (unlikely(!odev)) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Discarded packet with nonexistent "
+ "originating device\n", dev->name);
+#endif
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ osdata = IEEE80211_DEV_TO_SUB_IF(odev);
+
+ headroom = osdata->local->hw.extra_tx_headroom +
+ IEEE80211_ENCRYPT_HEADROOM;
+ if (skb_headroom(skb) < headroom) {
+ if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ control.ifindex = odev->ifindex;
+ control.type = osdata->type;
+ if (pkt_data->req_tx_status)
+ control.flags |= IEEE80211_TXCTL_REQ_TX_STATUS;
+ if (pkt_data->do_not_encrypt)
+ control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
+ if (pkt_data->requeue)
+ control.flags |= IEEE80211_TXCTL_REQUEUE;
+ control.queue = pkt_data->queue;
+
+ ret = ieee80211_tx(odev, skb, &control,
+ control.type == IEEE80211_IF_TYPE_MGMT);
+ dev_put(odev);
+
+ return ret;
+}
+
+
+/**
+ * ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
+ * subinterfaces (wlan#, WDS, and VLAN interfaces)
+ * @skb: packet to be sent
+ * @dev: incoming interface
+ *
+ * Returns: 0 on success (and frees skb in this case) or 1 on failure (skb will
+ * not be freed, and caller is responsible for either retrying later or freeing
+ * skb).
+ *
+ * This function takes in an Ethernet header and encapsulates it with suitable
+ * IEEE 802.11 header based on which interface the packet is coming in. The
+ * encapsulated packet will then be passed to master interface, wlan#.11, for
+ * transmission (through low-level driver).
+ */
+static int ieee80211_subif_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_sub_if_data *sdata;
+ int ret = 1, head_need;
+ u16 ethertype, hdrlen, fc;
+ struct ieee80211_hdr hdr;
+ const u8 *encaps_data;
+ int encaps_len, skip_header_bytes;
+ int nh_pos, h_pos, no_encrypt = 0;
+ struct sta_info *sta;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (unlikely(skb->len < ETH_HLEN)) {
+ printk(KERN_DEBUG "%s: short skb (len=%d)\n",
+ dev->name, skb->len);
+ ret = 0;
+ goto fail;
+ }
+
+ nh_pos = skb_network_header(skb) - skb->data;
+ h_pos = skb_transport_header(skb) - skb->data;
+
+ /* convert Ethernet header to proper 802.11 header (based on
+ * operation mode) */
+ ethertype = (skb->data[12] << 8) | skb->data[13];
+ /* TODO: handling for 802.1x authorized/unauthorized port */
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
+
+ if (likely(sdata->type == IEEE80211_IF_TYPE_AP ||
+ sdata->type == IEEE80211_IF_TYPE_VLAN)) {
+ fc |= IEEE80211_FCTL_FROMDS;
+ /* DA BSSID SA */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
+ hdrlen = 24;
+ } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+ fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
+ /* RA TA DA SA */
+ memcpy(hdr.addr1, sdata->u.wds.remote_addr, ETH_ALEN);
+ memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
+ memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
+ hdrlen = 30;
+ } else if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ fc |= IEEE80211_FCTL_TODS;
+ /* BSSID SA DA */
+ memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(hdr.addr3, skb->data, ETH_ALEN);
+ hdrlen = 24;
+ } else if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ /* DA SA BSSID */
+ memcpy(hdr.addr1, skb->data, ETH_ALEN);
+ memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
+ memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
+ hdrlen = 24;
+ } else {
+ ret = 0;
+ goto fail;
+ }
+
+ /* receiver is QoS enabled, use a QoS type frame */
+ sta = sta_info_get(local, hdr.addr1);
+ if (sta) {
+ if (sta->flags & WLAN_STA_WME) {
+ fc |= IEEE80211_STYPE_QOS_DATA;
+ hdrlen += 2;
+ }
+ sta_info_put(sta);
+ }
+
+ hdr.frame_control = cpu_to_le16(fc);
+ hdr.duration_id = 0;
+ hdr.seq_ctrl = 0;
+
+ skip_header_bytes = ETH_HLEN;
+ if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
+ encaps_data = bridge_tunnel_header;
+ encaps_len = sizeof(bridge_tunnel_header);
+ skip_header_bytes -= 2;
+ } else if (ethertype >= 0x600) {
+ encaps_data = rfc1042_header;
+ encaps_len = sizeof(rfc1042_header);
+ skip_header_bytes -= 2;
+ } else {
+ encaps_data = NULL;
+ encaps_len = 0;
+ }
+
+ skb_pull(skb, skip_header_bytes);
+ nh_pos -= skip_header_bytes;
+ h_pos -= skip_header_bytes;
+
+ /* TODO: implement support for fragments so that there is no need to
+ * reallocate and copy payload; it might be enough to support one
+ * extra fragment that would be copied in the beginning of the frame
+ * data.. anyway, it would be nice to include this into skb structure
+ * somehow
+ *
+ * There are few options for this:
+ * use skb->cb as an extra space for 802.11 header
+ * allocate new buffer if not enough headroom
+ * make sure that there is enough headroom in every skb by increasing
+ * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
+ * alloc_skb() (net/core/skbuff.c)
+ */
+ head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom;
+ head_need -= skb_headroom(skb);
+
+ /* We are going to modify skb data, so make a copy of it if happens to
+ * be cloned. This could happen, e.g., with Linux bridge code passing
+ * us broadcast frames. */
+
+ if (head_need > 0 || skb_cloned(skb)) {
+#if 0
+ printk(KERN_DEBUG "%s: need to reallocate buffer for %d bytes "
+ "of headroom\n", dev->name, head_need);
+#endif
+
+ if (skb_cloned(skb))
+ I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
+ else
+ I802_DEBUG_INC(local->tx_expand_skb_head);
+ /* Since we have to reallocate the buffer, make sure that there
+ * is enough room for possible WEP IV/ICV and TKIP (8 bytes
+ * before payload and 12 after). */
+ if (pskb_expand_head(skb, (head_need > 0 ? head_need + 8 : 8),
+ 12, GFP_ATOMIC)) {
+ printk(KERN_DEBUG "%s: failed to reallocate TX buffer"
+ "\n", dev->name);
+ goto fail;
+ }
+ }
+
+ if (encaps_data) {
+ memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
+ nh_pos += encaps_len;
+ h_pos += encaps_len;
+ }
+ memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
+ nh_pos += hdrlen;
+ h_pos += hdrlen;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+ pkt_data->do_not_encrypt = no_encrypt;
+
+ skb->dev = local->mdev;
+ sdata->stats.tx_packets++;
+ sdata->stats.tx_bytes += skb->len;
+
+ /* Update skb pointers to various headers since this modified frame
+ * is going to go through Linux networking code that may potentially
+ * need things like pointer to IP header. */
+ skb_set_mac_header(skb, 0);
+ skb_set_network_header(skb, nh_pos);
+ skb_set_transport_header(skb, h_pos);
+
+ dev->trans_start = jiffies;
+ dev_queue_xmit(skb);
+
+ return 0;
+
+ fail:
+ if (!ret)
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+
+/*
+ * This is the transmit routine for the 802.11 type interfaces
+ * called by upper layers of the linux networking
+ * stack when it has a frame to transmit
+ */
+static int
+ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (skb->len < 10) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
+ if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) {
+ if (pskb_expand_head(skb,
+ sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+
+ skb->priority = 20; /* use hardcoded priority for mgmt TX queue */
+ skb->dev = sdata->local->mdev;
+
+ /*
+ * We're using the protocol field of the the frame control header
+ * to request TX callback for hostapd. BIT(1) is checked.
+ */
+ if ((fc & BIT(1)) == BIT(1)) {
+ pkt_data->req_tx_status = 1;
+ fc &= ~BIT(1);
+ hdr->frame_control = cpu_to_le16(fc);
+ }
+
+ pkt_data->do_not_encrypt = !(fc & IEEE80211_FCTL_PROTECTED);
+
+ sdata->stats.tx_packets++;
+ sdata->stats.tx_bytes += skb->len;
+
+ dev_queue_xmit(skb);
+
+ return 0;
+}
+
+
+static void ieee80211_beacon_add_tim(struct ieee80211_local *local,
+ struct ieee80211_if_ap *bss,
+ struct sk_buff *skb)
+{
+ u8 *pos, *tim;
+ int aid0 = 0;
+ int i, have_bits = 0, n1, n2;
+
+ /* Generate bitmap for TIM only if there are any STAs in power save
+ * mode. */
+ spin_lock_bh(&local->sta_lock);
+ if (atomic_read(&bss->num_sta_ps) > 0)
+ /* in the hope that this is faster than
+ * checking byte-for-byte */
+ have_bits = !bitmap_empty((unsigned long*)bss->tim,
+ IEEE80211_MAX_AID+1);
+
+ if (bss->dtim_count == 0)
+ bss->dtim_count = bss->dtim_period - 1;
+ else
+ bss->dtim_count--;
+
+ tim = pos = (u8 *) skb_put(skb, 6);
+ *pos++ = WLAN_EID_TIM;
+ *pos++ = 4;
+ *pos++ = bss->dtim_count;
+ *pos++ = bss->dtim_period;
+
+ if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf))
+ aid0 = 1;
+
+ if (have_bits) {
+ /* Find largest even number N1 so that bits numbered 1 through
+ * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits
+ * (N2 + 1) x 8 through 2007 are 0. */
+ n1 = 0;
+ for (i = 0; i < IEEE80211_MAX_TIM_LEN; i++) {
+ if (bss->tim[i]) {
+ n1 = i & 0xfe;
+ break;
+ }
+ }
+ n2 = n1;
+ for (i = IEEE80211_MAX_TIM_LEN - 1; i >= n1; i--) {
+ if (bss->tim[i]) {
+ n2 = i;
+ break;
+ }
+ }
+
+ /* Bitmap control */
+ *pos++ = n1 | aid0;
+ /* Part Virt Bitmap */
+ memcpy(pos, bss->tim + n1, n2 - n1 + 1);
+
+ tim[1] = n2 - n1 + 4;
+ skb_put(skb, n2 - n1);
+ } else {
+ *pos++ = aid0; /* Bitmap control */
+ *pos++ = 0; /* Part Virt Bitmap */
+ }
+ spin_unlock_bh(&local->sta_lock);
+}
+
+
+struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sk_buff *skb;
+ struct net_device *bdev;
+ struct ieee80211_sub_if_data *sdata = NULL;
+ struct ieee80211_if_ap *ap = NULL;
+ struct ieee80211_rate *rate;
+ struct rate_control_extra extra;
+ u8 *b_head, *b_tail;
+ int bh_len, bt_len;
+
+ bdev = dev_get_by_index(if_id);
+ if (bdev) {
+ sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+ ap = &sdata->u.ap;
+ dev_put(bdev);
+ }
+
+ if (!ap || sdata->type != IEEE80211_IF_TYPE_AP ||
+ !ap->beacon_head) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ if (net_ratelimit())
+ printk(KERN_DEBUG "no beacon data avail for idx=%d "
+ "(%s)\n", if_id, bdev ? bdev->name : "N/A");
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ return NULL;
+ }
+
+ /* Assume we are generating the normal beacon locally */
+ b_head = ap->beacon_head;
+ b_tail = ap->beacon_tail;
+ bh_len = ap->beacon_head_len;
+ bt_len = ap->beacon_tail_len;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ bh_len + bt_len + 256 /* maximum TIM len */);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ memcpy(skb_put(skb, bh_len), b_head, bh_len);
+
+ ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
+
+ ieee80211_beacon_add_tim(local, ap, skb);
+
+ if (b_tail) {
+ memcpy(skb_put(skb, bt_len), b_tail, bt_len);
+ }
+
+ if (control) {
+ memset(&extra, 0, sizeof(extra));
+ extra.mode = local->oper_hw_mode;
+
+ rate = rate_control_get_rate(local, local->mdev, skb, &extra);
+ if (!rate) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: ieee80211_beacon_get: no rate "
+ "found\n", local->mdev->name);
+ }
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+
+ control->tx_rate = (local->short_preamble &&
+ (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+ rate->val2 : rate->val;
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ control->power_level = local->hw.conf.power_level;
+ control->flags |= IEEE80211_TXCTL_NO_ACK;
+ control->retry_limit = 1;
+ control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
+ }
+
+ ap->num_beacons++;
+ return skb;
+}
+EXPORT_SYMBOL(ieee80211_beacon_get);
+
+__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
+ size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_rate *rate;
+ int short_preamble = local->short_preamble;
+ int erp;
+ u16 dur;
+
+ rate = frame_txctl->rts_rate;
+ erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+ /* CTS duration */
+ dur = ieee80211_frame_duration(local, 10, rate->rate,
+ erp, short_preamble);
+ /* Data frame duration */
+ dur += ieee80211_frame_duration(local, frame_len, rate->rate,
+ erp, short_preamble);
+ /* ACK duration */
+ dur += ieee80211_frame_duration(local, 10, rate->rate,
+ erp, short_preamble);
+
+ return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_rts_duration);
+
+
+__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
+ size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_rate *rate;
+ int short_preamble = local->short_preamble;
+ int erp;
+ u16 dur;
+
+ rate = frame_txctl->rts_rate;
+ erp = !!(rate->flags & IEEE80211_RATE_ERP);
+
+ /* Data frame duration */
+ dur = ieee80211_frame_duration(local, frame_len, rate->rate,
+ erp, short_preamble);
+ if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) {
+ /* ACK duration */
+ dur += ieee80211_frame_duration(local, 10, rate->rate,
+ erp, short_preamble);
+ }
+
+ return cpu_to_le16(dur);
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_duration);
+
+void ieee80211_rts_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_rts *rts)
+{
+ const struct ieee80211_hdr *hdr = frame;
+ u16 fctl;
+
+ fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS;
+ rts->frame_control = cpu_to_le16(fctl);
+ rts->duration = ieee80211_rts_duration(hw, frame_len, frame_txctl);
+ memcpy(rts->ra, hdr->addr1, sizeof(rts->ra));
+ memcpy(rts->ta, hdr->addr2, sizeof(rts->ta));
+}
+EXPORT_SYMBOL(ieee80211_rts_get);
+
+void ieee80211_ctstoself_get(struct ieee80211_hw *hw,
+ const void *frame, size_t frame_len,
+ const struct ieee80211_tx_control *frame_txctl,
+ struct ieee80211_cts *cts)
+{
+ const struct ieee80211_hdr *hdr = frame;
+ u16 fctl;
+
+ fctl = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
+ cts->frame_control = cpu_to_le16(fctl);
+ cts->duration = ieee80211_ctstoself_duration(hw, frame_len, frame_txctl);
+ memcpy(cts->ra, hdr->addr1, sizeof(cts->ra));
+}
+EXPORT_SYMBOL(ieee80211_ctstoself_get);
+
+struct sk_buff *
+ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct sk_buff *skb;
+ struct sta_info *sta;
+ ieee80211_tx_handler *handler;
+ struct ieee80211_txrx_data tx;
+ ieee80211_txrx_result res = TXRX_DROP;
+ struct net_device *bdev;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_ap *bss = NULL;
+
+ bdev = dev_get_by_index(if_id);
+ if (bdev) {
+ sdata = IEEE80211_DEV_TO_SUB_IF(bdev);
+ bss = &sdata->u.ap;
+ dev_put(bdev);
+ }
+ if (!bss || sdata->type != IEEE80211_IF_TYPE_AP || !bss->beacon_head)
+ return NULL;
+
+ if (bss->dtim_count != 0)
+ return NULL; /* send buffered bc/mc only after DTIM beacon */
+ memset(control, 0, sizeof(*control));
+ while (1) {
+ skb = skb_dequeue(&bss->ps_bc_buf);
+ if (!skb)
+ return NULL;
+ local->total_ps_buffered--;
+
+ if (!skb_queue_empty(&bss->ps_bc_buf) && skb->len >= 2) {
+ struct ieee80211_hdr *hdr =
+ (struct ieee80211_hdr *) skb->data;
+ /* more buffered multicast/broadcast frames ==> set
+ * MoreData flag in IEEE 802.11 header to inform PS
+ * STAs */
+ hdr->frame_control |=
+ cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+ }
+
+ if (ieee80211_tx_prepare(&tx, skb, local->mdev, control) == 0)
+ break;
+ dev_kfree_skb_any(skb);
+ }
+ sta = tx.sta;
+ tx.u.tx.ps_buffered = 1;
+
+ for (handler = local->tx_handlers; *handler != NULL; handler++) {
+ res = (*handler)(&tx);
+ if (res == TXRX_DROP || res == TXRX_QUEUED)
+ break;
+ }
+ dev_put(tx.dev);
+ skb = tx.skb; /* handlers are allowed to change skb */
+
+ if (res == TXRX_DROP) {
+ I802_DEBUG_INC(local->tx_handlers_drop);
+ dev_kfree_skb(skb);
+ skb = NULL;
+ } else if (res == TXRX_QUEUED) {
+ I802_DEBUG_INC(local->tx_handlers_queued);
+ skb = NULL;
+ }
+
+ if (sta)
+ sta_info_put(sta);
+
+ return skb;
+}
+EXPORT_SYMBOL(ieee80211_get_buffered_bc);
+
+static int __ieee80211_if_config(struct net_device *dev,
+ struct sk_buff *beacon,
+ struct ieee80211_tx_control *control)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_if_conf conf;
+ static u8 scan_bssid[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ if (!local->ops->config_interface || !netif_running(dev))
+ return 0;
+
+ memset(&conf, 0, sizeof(conf));
+ conf.type = sdata->type;
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ if (local->sta_scanning &&
+ local->scan_dev == dev)
+ conf.bssid = scan_bssid;
+ else
+ conf.bssid = sdata->u.sta.bssid;
+ conf.ssid = sdata->u.sta.ssid;
+ conf.ssid_len = sdata->u.sta.ssid_len;
+ conf.generic_elem = sdata->u.sta.extra_ie;
+ conf.generic_elem_len = sdata->u.sta.extra_ie_len;
+ } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ conf.ssid = sdata->u.ap.ssid;
+ conf.ssid_len = sdata->u.ap.ssid_len;
+ conf.generic_elem = sdata->u.ap.generic_elem;
+ conf.generic_elem_len = sdata->u.ap.generic_elem_len;
+ conf.beacon = beacon;
+ conf.beacon_control = control;
+ }
+ return local->ops->config_interface(local_to_hw(local),
+ dev->ifindex, &conf);
+}
+
+int ieee80211_if_config(struct net_device *dev)
+{
+ return __ieee80211_if_config(dev, NULL, NULL);
+}
+
+int ieee80211_if_config_beacon(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_tx_control control;
+ struct sk_buff *skb;
+
+ if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
+ return 0;
+ skb = ieee80211_beacon_get(local_to_hw(local), dev->ifindex, &control);
+ if (!skb)
+ return -ENOMEM;
+ return __ieee80211_if_config(dev, skb, &control);
+}
+
+int ieee80211_hw_config(struct ieee80211_local *local)
+{
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_channel *chan;
+ int ret = 0;
+
+ if (local->sta_scanning) {
+ chan = local->scan_channel;
+ mode = local->scan_hw_mode;
+ } else {
+ chan = local->oper_channel;
+ mode = local->oper_hw_mode;
+ }
+
+ local->hw.conf.channel = chan->chan;
+ local->hw.conf.channel_val = chan->val;
+ local->hw.conf.power_level = chan->power_level;
+ local->hw.conf.freq = chan->freq;
+ local->hw.conf.phymode = mode->mode;
+ local->hw.conf.antenna_max = chan->antenna_max;
+ local->hw.conf.chan = chan;
+ local->hw.conf.mode = mode;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
+ "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq,
+ local->hw.conf.phymode);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+ if (local->ops->config)
+ ret = local->ops->config(local_to_hw(local), &local->hw.conf);
+
+ return ret;
+}
+
+
+static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+{
+ /* FIX: what would be proper limits for MTU?
+ * This interface uses 802.3 frames. */
+ if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) {
+ printk(KERN_WARNING "%s: invalid MTU %d\n",
+ dev->name, new_mtu);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+
+static int ieee80211_change_mtu_apdev(struct net_device *dev, int new_mtu)
+{
+ /* FIX: what would be proper limits for MTU?
+ * This interface uses 802.11 frames. */
+ if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN) {
+ printk(KERN_WARNING "%s: invalid MTU %d\n",
+ dev->name, new_mtu);
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+enum netif_tx_lock_class {
+ TX_LOCK_NORMAL,
+ TX_LOCK_MASTER,
+};
+
+static inline void netif_tx_lock_nested(struct net_device *dev, int subclass)
+{
+ spin_lock_nested(&dev->_xmit_lock, subclass);
+ dev->xmit_lock_owner = smp_processor_id();
+}
+
+static void ieee80211_set_multicast_list(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ unsigned short flags;
+
+ netif_tx_lock_nested(local->mdev, TX_LOCK_MASTER);
+ if (((dev->flags & IFF_ALLMULTI) != 0) ^ (sdata->allmulti != 0)) {
+ if (sdata->allmulti) {
+ sdata->allmulti = 0;
+ local->iff_allmultis--;
+ } else {
+ sdata->allmulti = 1;
+ local->iff_allmultis++;
+ }
+ }
+ if (((dev->flags & IFF_PROMISC) != 0) ^ (sdata->promisc != 0)) {
+ if (sdata->promisc) {
+ sdata->promisc = 0;
+ local->iff_promiscs--;
+ } else {
+ sdata->promisc = 1;
+ local->iff_promiscs++;
+ }
+ }
+ if (dev->mc_count != sdata->mc_count) {
+ local->mc_count = local->mc_count - sdata->mc_count +
+ dev->mc_count;
+ sdata->mc_count = dev->mc_count;
+ }
+ if (local->ops->set_multicast_list) {
+ flags = local->mdev->flags;
+ if (local->iff_allmultis)
+ flags |= IFF_ALLMULTI;
+ if (local->iff_promiscs)
+ flags |= IFF_PROMISC;
+ read_lock(&local->sub_if_lock);
+ local->ops->set_multicast_list(local_to_hw(local), flags,
+ local->mc_count);
+ read_unlock(&local->sub_if_lock);
+ }
+ netif_tx_unlock(local->mdev);
+}
+
+struct dev_mc_list *ieee80211_get_mc_list_item(struct ieee80211_hw *hw,
+ struct dev_mc_list *prev,
+ void **ptr)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata = *ptr;
+ struct dev_mc_list *mc;
+
+ if (!prev) {
+ WARN_ON(sdata);
+ sdata = NULL;
+ }
+ if (!prev || !prev->next) {
+ if (sdata)
+ sdata = list_entry(sdata->list.next,
+ struct ieee80211_sub_if_data, list);
+ else
+ sdata = list_entry(local->sub_if_list.next,
+ struct ieee80211_sub_if_data, list);
+ if (&sdata->list != &local->sub_if_list)
+ mc = sdata->dev->mc_list;
+ else
+ mc = NULL;
+ } else
+ mc = prev->next;
+
+ *ptr = sdata;
+ return mc;
+}
+EXPORT_SYMBOL(ieee80211_get_mc_list_item);
+
+static struct net_device_stats *ieee80211_get_stats(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ return &(sdata->stats);
+}
+
+static void ieee80211_if_shutdown(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ ASSERT_RTNL();
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ sdata->u.sta.state = IEEE80211_DISABLED;
+ del_timer_sync(&sdata->u.sta.timer);
+ skb_queue_purge(&sdata->u.sta.skb_queue);
+ if (!local->ops->hw_scan &&
+ local->scan_dev == sdata->dev) {
+ local->sta_scanning = 0;
+ cancel_delayed_work(&local->scan_work);
+ }
+ flush_workqueue(local->hw.workqueue);
+ break;
+ }
+}
+
+static inline int identical_mac_addr_allowed(int type1, int type2)
+{
+ return (type1 == IEEE80211_IF_TYPE_MNTR ||
+ type2 == IEEE80211_IF_TYPE_MNTR ||
+ (type1 == IEEE80211_IF_TYPE_AP &&
+ type2 == IEEE80211_IF_TYPE_WDS) ||
+ (type1 == IEEE80211_IF_TYPE_WDS &&
+ (type2 == IEEE80211_IF_TYPE_WDS ||
+ type2 == IEEE80211_IF_TYPE_AP)) ||
+ (type1 == IEEE80211_IF_TYPE_AP &&
+ type2 == IEEE80211_IF_TYPE_VLAN) ||
+ (type1 == IEEE80211_IF_TYPE_VLAN &&
+ (type2 == IEEE80211_IF_TYPE_AP ||
+ type2 == IEEE80211_IF_TYPE_VLAN)));
+}
+
+static int ieee80211_master_open(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ int res = -EOPNOTSUPP;
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ if (sdata->dev != dev && netif_running(sdata->dev)) {
+ res = 0;
+ break;
+ }
+ }
+ read_unlock(&local->sub_if_lock);
+ return res;
+}
+
+static int ieee80211_master_stop(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list)
+ if (sdata->dev != dev && netif_running(sdata->dev))
+ dev_close(sdata->dev);
+ read_unlock(&local->sub_if_lock);
+
+ return 0;
+}
+
+static int ieee80211_mgmt_open(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (!netif_running(local->mdev))
+ return -EOPNOTSUPP;
+ return 0;
+}
+
+static int ieee80211_mgmt_stop(struct net_device *dev)
+{
+ return 0;
+}
+
+/* Check if running monitor interfaces should go to a "soft monitor" mode
+ * and switch them if necessary. */
+static inline void ieee80211_start_soft_monitor(struct ieee80211_local *local)
+{
+ struct ieee80211_if_init_conf conf;
+
+ if (local->open_count && local->open_count == local->monitors &&
+ !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
+ local->ops->remove_interface) {
+ conf.if_id = -1;
+ conf.type = IEEE80211_IF_TYPE_MNTR;
+ conf.mac_addr = NULL;
+ local->ops->remove_interface(local_to_hw(local), &conf);
+ }
+}
+
+/* Check if running monitor interfaces should go to a "hard monitor" mode
+ * and switch them if necessary. */
+static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
+{
+ struct ieee80211_if_init_conf conf;
+
+ if (local->open_count && local->open_count == local->monitors &&
+ !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
+ local->ops->add_interface) {
+ conf.if_id = -1;
+ conf.type = IEEE80211_IF_TYPE_MNTR;
+ conf.mac_addr = NULL;
+ local->ops->add_interface(local_to_hw(local), &conf);
+ }
+}
+
+static int ieee80211_open(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata, *nsdata;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_if_init_conf conf;
+ int res;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(nsdata, &local->sub_if_list, list) {
+ struct net_device *ndev = nsdata->dev;
+
+ if (ndev != dev && ndev != local->mdev && netif_running(ndev) &&
+ compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0 &&
+ !identical_mac_addr_allowed(sdata->type, nsdata->type)) {
+ read_unlock(&local->sub_if_lock);
+ return -ENOTUNIQ;
+ }
+ }
+ read_unlock(&local->sub_if_lock);
+
+ if (sdata->type == IEEE80211_IF_TYPE_WDS &&
+ is_zero_ether_addr(sdata->u.wds.remote_addr))
+ return -ENOLINK;
+
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR && local->open_count &&
+ !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+ /* run the interface in a "soft monitor" mode */
+ local->monitors++;
+ local->open_count++;
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+ return 0;
+ }
+ ieee80211_start_soft_monitor(local);
+
+ if (local->ops->add_interface) {
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
+ res = local->ops->add_interface(local_to_hw(local), &conf);
+ if (res) {
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ ieee80211_start_hard_monitor(local);
+ return res;
+ }
+ } else {
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return -EOPNOTSUPP;
+ if (local->open_count > 0)
+ return -ENOBUFS;
+ }
+
+ if (local->open_count == 0) {
+ res = 0;
+ tasklet_enable(&local->tx_pending_tasklet);
+ tasklet_enable(&local->tasklet);
+ if (local->ops->open)
+ res = local->ops->open(local_to_hw(local));
+ if (res == 0) {
+ res = dev_open(local->mdev);
+ if (res) {
+ if (local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ } else {
+ res = ieee80211_hw_config(local);
+ if (res && local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ else if (!res && local->apdev)
+ dev_open(local->apdev);
+ }
+ }
+ if (res) {
+ if (local->ops->remove_interface)
+ local->ops->remove_interface(local_to_hw(local),
+ &conf);
+ return res;
+ }
+ }
+ local->open_count++;
+
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ local->monitors++;
+ local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP;
+ } else
+ ieee80211_if_config(dev);
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ !local->user_space_mlme)
+ netif_carrier_off(dev);
+
+ netif_start_queue(dev);
+ return 0;
+}
+
+
+static int ieee80211_stop(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR &&
+ local->open_count > 1 &&
+ !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
+ /* remove "soft monitor" interface */
+ local->open_count--;
+ local->monitors--;
+ if (!local->monitors)
+ local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+ return 0;
+ }
+
+ netif_stop_queue(dev);
+ ieee80211_if_shutdown(dev);
+
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ local->monitors--;
+ if (!local->monitors)
+ local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP;
+ }
+
+ local->open_count--;
+ if (local->open_count == 0) {
+ if (netif_running(local->mdev))
+ dev_close(local->mdev);
+ if (local->apdev)
+ dev_close(local->apdev);
+ if (local->ops->stop)
+ local->ops->stop(local_to_hw(local));
+ tasklet_disable(&local->tx_pending_tasklet);
+ tasklet_disable(&local->tasklet);
+ }
+ if (local->ops->remove_interface) {
+ struct ieee80211_if_init_conf conf;
+
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
+ local->ops->remove_interface(local_to_hw(local), &conf);
+ }
+
+ ieee80211_start_hard_monitor(local);
+
+ return 0;
+}
+
+
+static int header_parse_80211(struct sk_buff *skb, unsigned char *haddr)
+{
+ memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
+ return ETH_ALEN;
+}
+
+static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
+{
+ return compare_ether_addr(raddr, addr) == 0 ||
+ is_broadcast_ether_addr(raddr);
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
+{
+ struct net_device *dev = rx->dev;
+ struct ieee80211_local *local = rx->local;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+ u16 fc, hdrlen, ethertype;
+ u8 *payload;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ struct sk_buff *skb = rx->skb, *skb2;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ fc = rx->fc;
+ if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+ return TXRX_CONTINUE;
+
+ if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+ return TXRX_DROP;
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ /* convert IEEE 802.11 header + possible LLC headers into Ethernet
+ * header
+ * IEEE 802.11 address fields:
+ * ToDS FromDS Addr1 Addr2 Addr3 Addr4
+ * 0 0 DA SA BSSID n/a
+ * 0 1 DA BSSID SA n/a
+ * 1 0 BSSID SA DA n/a
+ * 1 1 RA TA DA SA
+ */
+
+ switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+ case IEEE80211_FCTL_TODS:
+ /* BSSID SA DA */
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+
+ if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
+ sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+ printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID="
+ MAC_FMT " SA=" MAC_FMT " DA=" MAC_FMT ")\n",
+ dev->name, MAC_ARG(hdr->addr1),
+ MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3));
+ return TXRX_DROP;
+ }
+ break;
+ case (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
+ /* RA TA DA SA */
+ memcpy(dst, hdr->addr3, ETH_ALEN);
+ memcpy(src, hdr->addr4, ETH_ALEN);
+
+ if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+ printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame (RA="
+ MAC_FMT " TA=" MAC_FMT " DA=" MAC_FMT " SA="
+ MAC_FMT ")\n",
+ rx->dev->name, MAC_ARG(hdr->addr1),
+ MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr3),
+ MAC_ARG(hdr->addr4));
+ return TXRX_DROP;
+ }
+ break;
+ case IEEE80211_FCTL_FROMDS:
+ /* DA BSSID SA */
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr3, ETH_ALEN);
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA) {
+ return TXRX_DROP;
+ }
+ break;
+ case 0:
+ /* DA SA BSSID */
+ memcpy(dst, hdr->addr1, ETH_ALEN);
+ memcpy(src, hdr->addr2, ETH_ALEN);
+
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: dropped IBSS frame (DA="
+ MAC_FMT " SA=" MAC_FMT " BSSID=" MAC_FMT
+ ")\n",
+ dev->name, MAC_ARG(hdr->addr1),
+ MAC_ARG(hdr->addr2),
+ MAC_ARG(hdr->addr3));
+ }
+ return TXRX_DROP;
+ }
+ break;
+ }
+
+ payload = skb->data + hdrlen;
+
+ if (unlikely(skb->len - hdrlen < 8)) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: RX too short data frame "
+ "payload\n", dev->name);
+ }
+ return TXRX_DROP;
+ }
+
+ ethertype = (payload[6] << 8) | payload[7];
+
+ if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+ ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+ compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
+ /* remove RFC1042 or Bridge-Tunnel encapsulation and
+ * replace EtherType */
+ skb_pull(skb, hdrlen + 6);
+ memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
+ memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
+ } else {
+ struct ethhdr *ehdr;
+ __be16 len;
+ skb_pull(skb, hdrlen);
+ len = htons(skb->len);
+ ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
+ memcpy(ehdr->h_dest, dst, ETH_ALEN);
+ memcpy(ehdr->h_source, src, ETH_ALEN);
+ ehdr->h_proto = len;
+ }
+ skb->dev = dev;
+
+ skb2 = NULL;
+
+ sdata->stats.rx_packets++;
+ sdata->stats.rx_bytes += skb->len;
+
+ if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
+ || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) {
+ if (is_multicast_ether_addr(skb->data)) {
+ /* send multicast frames both to higher layers in
+ * local net stack and back to the wireless media */
+ skb2 = skb_copy(skb, GFP_ATOMIC);
+ if (!skb2)
+ printk(KERN_DEBUG "%s: failed to clone "
+ "multicast frame\n", dev->name);
+ } else {
+ struct sta_info *dsta;
+ dsta = sta_info_get(local, skb->data);
+ if (dsta && !dsta->dev) {
+ printk(KERN_DEBUG "Station with null dev "
+ "structure!\n");
+ } else if (dsta && dsta->dev == dev) {
+ /* Destination station is associated to this
+ * AP, so send the frame directly to it and
+ * do not pass the frame to local net stack.
+ */
+ skb2 = skb;
+ skb = NULL;
+ }
+ if (dsta)
+ sta_info_put(dsta);
+ }
+ }
+
+ if (skb) {
+ /* deliver to local stack */
+ skb->protocol = eth_type_trans(skb, dev);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+ }
+
+ if (skb2) {
+ /* send to wireless media */
+ skb2->protocol = __constant_htons(ETH_P_802_3);
+ skb_set_network_header(skb2, 0);
+ skb_set_mac_header(skb2, 0);
+ dev_queue_xmit(skb2);
+ }
+
+ return TXRX_QUEUED;
+}
+
+
+static struct ieee80211_rate *
+ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate)
+{
+ struct ieee80211_hw_mode *mode;
+ int r;
+
+ list_for_each_entry(mode, &local->modes_list, list) {
+ if (mode->mode != phymode)
+ continue;
+ for (r = 0; r < mode->num_rates; r++) {
+ struct ieee80211_rate *rate = &mode->rates[r];
+ if (rate->val == hw_rate ||
+ (rate->flags & IEEE80211_RATE_PREAMBLE2 &&
+ rate->val2 == hw_rate))
+ return rate;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+ieee80211_fill_frame_info(struct ieee80211_local *local,
+ struct ieee80211_frame_info *fi,
+ struct ieee80211_rx_status *status)
+{
+ if (status) {
+ struct timespec ts;
+ struct ieee80211_rate *rate;
+
+ jiffies_to_timespec(jiffies, &ts);
+ fi->hosttime = cpu_to_be64((u64) ts.tv_sec * 1000000 +
+ ts.tv_nsec / 1000);
+ fi->mactime = cpu_to_be64(status->mactime);
+ switch (status->phymode) {
+ case MODE_IEEE80211A:
+ fi->phytype = htonl(ieee80211_phytype_ofdm_dot11_a);
+ break;
+ case MODE_IEEE80211B:
+ fi->phytype = htonl(ieee80211_phytype_dsss_dot11_b);
+ break;
+ case MODE_IEEE80211G:
+ fi->phytype = htonl(ieee80211_phytype_pbcc_dot11_g);
+ break;
+ case MODE_ATHEROS_TURBO:
+ fi->phytype =
+ htonl(ieee80211_phytype_dsss_dot11_turbo);
+ break;
+ default:
+ fi->phytype = htonl(0xAAAAAAAA);
+ break;
+ }
+ fi->channel = htonl(status->channel);
+ rate = ieee80211_get_rate(local, status->phymode,
+ status->rate);
+ if (rate) {
+ fi->datarate = htonl(rate->rate);
+ if (rate->flags & IEEE80211_RATE_PREAMBLE2) {
+ if (status->rate == rate->val)
+ fi->preamble = htonl(2); /* long */
+ else if (status->rate == rate->val2)
+ fi->preamble = htonl(1); /* short */
+ } else
+ fi->preamble = htonl(0);
+ } else {
+ fi->datarate = htonl(0);
+ fi->preamble = htonl(0);
+ }
+
+ fi->antenna = htonl(status->antenna);
+ fi->priority = htonl(0xffffffff); /* no clue */
+ fi->ssi_type = htonl(ieee80211_ssi_raw);
+ fi->ssi_signal = htonl(status->ssi);
+ fi->ssi_noise = 0x00000000;
+ fi->encoding = 0;
+ } else {
+ /* clear everything because we really don't know.
+ * the msg_type field isn't present on monitor frames
+ * so we don't know whether it will be present or not,
+ * but it's ok to not clear it since it'll be assigned
+ * anyway */
+ memset(fi, 0, sizeof(*fi) - sizeof(fi->msg_type));
+
+ fi->ssi_type = htonl(ieee80211_ssi_none);
+ }
+ fi->version = htonl(IEEE80211_FI_VERSION);
+ fi->length = cpu_to_be32(sizeof(*fi) - sizeof(fi->msg_type));
+}
+
+/* this routine is actually not just for this, but also
+ * for pushing fake 'management' frames into userspace.
+ * it shall be replaced by a netlink-based system. */
+void
+ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_rx_status *status, u32 msg_type)
+{
+ struct ieee80211_frame_info *fi;
+ const size_t hlen = sizeof(struct ieee80211_frame_info);
+ struct ieee80211_sub_if_data *sdata;
+
+ skb->dev = local->apdev;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(local->apdev);
+
+ if (skb_headroom(skb) < hlen) {
+ I802_DEBUG_INC(local->rx_expand_skb_head);
+ if (pskb_expand_head(skb, hlen, 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
+ fi = (struct ieee80211_frame_info *) skb_push(skb, hlen);
+
+ ieee80211_fill_frame_info(local, fi, status);
+ fi->msg_type = htonl(msg_type);
+
+ sdata->stats.rx_packets++;
+ sdata->stats.rx_bytes += skb->len;
+
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+static void
+ieee80211_rx_monitor(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *status)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_rate *rate;
+ struct ieee80211_rtap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ u8 flags;
+ u8 rate;
+ __le16 chan_freq;
+ __le16 chan_flags;
+ u8 antsignal;
+ } __attribute__ ((packed)) *rthdr;
+
+ skb->dev = dev;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (status->flag & RX_FLAG_RADIOTAP)
+ goto out;
+
+ if (skb_headroom(skb) < sizeof(*rthdr)) {
+ I802_DEBUG_INC(local->rx_expand_skb_head);
+ if (pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
+ rthdr = (struct ieee80211_rtap_hdr *) skb_push(skb, sizeof(*rthdr));
+ memset(rthdr, 0, sizeof(*rthdr));
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+ rthdr->hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL));
+ rthdr->flags = local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS ?
+ IEEE80211_RADIOTAP_F_FCS : 0;
+ rate = ieee80211_get_rate(local, status->phymode, status->rate);
+ if (rate)
+ rthdr->rate = rate->rate / 5;
+ rthdr->chan_freq = cpu_to_le16(status->freq);
+ rthdr->chan_flags =
+ status->phymode == MODE_IEEE80211A ?
+ cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ) :
+ cpu_to_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ);
+ rthdr->antsignal = status->ssi;
+
+ out:
+ sdata->stats.rx_packets++;
+ sdata->stats.rx_bytes += skb->len;
+
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+}
+
+int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
+ int radar, int radar_type)
+{
+ struct sk_buff *skb;
+ struct ieee80211_radar_info *msg;
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!local->apdev)
+ return 0;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+ sizeof(struct ieee80211_radar_info));
+
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+
+ msg = (struct ieee80211_radar_info *)
+ skb_put(skb, sizeof(struct ieee80211_radar_info));
+ msg->channel = channel;
+ msg->radar = radar;
+ msg->radar_type = radar_type;
+
+ ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_radar);
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_radar_status);
+
+int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw, u8 *peer_address,
+ u16 aid)
+{
+ struct sk_buff *skb;
+ struct ieee80211_msg_set_aid_for_sta *msg;
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ /* unlikely because if this event only happens for APs,
+ * which require an open ap device. */
+ if (unlikely(!local->apdev))
+ return 0;
+
+ skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
+ sizeof(struct ieee80211_msg_set_aid_for_sta));
+
+ if (!skb)
+ return -ENOMEM;
+ skb_reserve(skb, sizeof(struct ieee80211_frame_info));
+
+ msg = (struct ieee80211_msg_set_aid_for_sta *)
+ skb_put(skb, sizeof(struct ieee80211_msg_set_aid_for_sta));
+ memcpy(msg->sta_address, peer_address, ETH_ALEN);
+ msg->aid = aid;
+
+ ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta);
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_set_aid_for_sta);
+
+static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata;
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+ if (sdata->bss)
+ atomic_inc(&sdata->bss->num_sta_ps);
+ sta->flags |= WLAN_STA_PS;
+ sta->pspoll = 0;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d enters power "
+ "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+}
+
+
+static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ int sent = 0;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_tx_packet_data *pkt_data;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sdata->bss)
+ atomic_dec(&sdata->bss->num_sta_ps);
+ sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM);
+ sta->pspoll = 0;
+ if (!skb_queue_empty(&sta->ps_tx_buf)) {
+ if (local->ops->set_tim)
+ local->ops->set_tim(local_to_hw(local), sta->aid, 0);
+ if (sdata->bss)
+ bss_tim_clear(local, sdata->bss, sta->aid);
+ }
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d exits power "
+ "save mode\n", dev->name, MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ /* Send all buffered frames to the station */
+ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ sent++;
+ pkt_data->requeue = 1;
+ dev_queue_xmit(skb);
+ }
+ while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ local->total_ps_buffered--;
+ sent++;
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " aid %d send PS frame "
+ "since STA not sleeping anymore\n", dev->name,
+ MAC_ARG(sta->addr), sta->aid);
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+ pkt_data->requeue = 1;
+ dev_queue_xmit(skb);
+ }
+
+ return sent;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+{
+ struct sk_buff *skb;
+ int no_pending_pkts;
+
+ if (likely(!rx->sta ||
+ (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL ||
+ (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL ||
+ !rx->u.rx.ra_match))
+ return TXRX_CONTINUE;
+
+ skb = skb_dequeue(&rx->sta->tx_filtered);
+ if (!skb) {
+ skb = skb_dequeue(&rx->sta->ps_tx_buf);
+ if (skb)
+ rx->local->total_ps_buffered--;
+ }
+ no_pending_pkts = skb_queue_empty(&rx->sta->tx_filtered) &&
+ skb_queue_empty(&rx->sta->ps_tx_buf);
+
+ if (skb) {
+ struct ieee80211_hdr *hdr =
+ (struct ieee80211_hdr *) skb->data;
+
+ /* tell TX path to send one frame even though the STA may
+ * still remain is PS mode after this frame exchange */
+ rx->sta->pspoll = 1;
+
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ printk(KERN_DEBUG "STA " MAC_FMT " aid %d: PS Poll (entries "
+ "after %d)\n",
+ MAC_ARG(rx->sta->addr), rx->sta->aid,
+ skb_queue_len(&rx->sta->ps_tx_buf));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
+ /* Use MoreData flag to indicate whether there are more
+ * buffered frames for this STA */
+ if (no_pending_pkts) {
+ hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
+ rx->sta->flags &= ~WLAN_STA_TIM;
+ } else
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+
+ dev_queue_xmit(skb);
+
+ if (no_pending_pkts) {
+ if (rx->local->ops->set_tim)
+ rx->local->ops->set_tim(local_to_hw(rx->local),
+ rx->sta->aid, 0);
+ if (rx->sdata->bss)
+ bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid);
+ }
+#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
+ } else if (!rx->u.rx.sent_ps_buffered) {
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " sent PS Poll even "
+ "though there is no buffered frames for it\n",
+ rx->dev->name, MAC_ARG(rx->sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
+
+ }
+
+ /* Free PS Poll skb here instead of returning TXRX_DROP that would
+ * count as an dropped frame. */
+ dev_kfree_skb(rx->skb);
+
+ return TXRX_QUEUED;
+}
+
+
+static inline struct ieee80211_fragment_entry *
+ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
+ unsigned int frag, unsigned int seq, int rx_queue,
+ struct sk_buff **skb)
+{
+ struct ieee80211_fragment_entry *entry;
+ int idx;
+
+ idx = sdata->fragment_next;
+ entry = &sdata->fragments[sdata->fragment_next++];
+ if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
+ sdata->fragment_next = 0;
+
+ if (!skb_queue_empty(&entry->skb_list)) {
+#ifdef CONFIG_MAC80211_DEBUG
+ struct ieee80211_hdr *hdr =
+ (struct ieee80211_hdr *) entry->skb_list.next->data;
+ printk(KERN_DEBUG "%s: RX reassembly removed oldest "
+ "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
+ "addr1=" MAC_FMT " addr2=" MAC_FMT "\n",
+ sdata->dev->name, idx,
+ jiffies - entry->first_frag_time, entry->seq,
+ entry->last_frag, MAC_ARG(hdr->addr1),
+ MAC_ARG(hdr->addr2));
+#endif /* CONFIG_MAC80211_DEBUG */
+ __skb_queue_purge(&entry->skb_list);
+ }
+
+ __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
+ *skb = NULL;
+ entry->first_frag_time = jiffies;
+ entry->seq = seq;
+ entry->rx_queue = rx_queue;
+ entry->last_frag = frag;
+ entry->ccmp = 0;
+ entry->extra_len = 0;
+
+ return entry;
+}
+
+
+static inline struct ieee80211_fragment_entry *
+ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
+ u16 fc, unsigned int frag, unsigned int seq,
+ int rx_queue, struct ieee80211_hdr *hdr)
+{
+ struct ieee80211_fragment_entry *entry;
+ int i, idx;
+
+ idx = sdata->fragment_next;
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+ struct ieee80211_hdr *f_hdr;
+ u16 f_fc;
+
+ idx--;
+ if (idx < 0)
+ idx = IEEE80211_FRAGMENT_MAX - 1;
+
+ entry = &sdata->fragments[idx];
+ if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
+ entry->rx_queue != rx_queue ||
+ entry->last_frag + 1 != frag)
+ continue;
+
+ f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data;
+ f_fc = le16_to_cpu(f_hdr->frame_control);
+
+ if ((fc & IEEE80211_FCTL_FTYPE) != (f_fc & IEEE80211_FCTL_FTYPE) ||
+ compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 ||
+ compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
+ continue;
+
+ if (entry->first_frag_time + 2 * HZ < jiffies) {
+ __skb_queue_purge(&entry->skb_list);
+ continue;
+ }
+ return entry;
+ }
+
+ return NULL;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_hdr *hdr;
+ u16 sc;
+ unsigned int frag, seq;
+ struct ieee80211_fragment_entry *entry;
+ struct sk_buff *skb;
+
+ hdr = (struct ieee80211_hdr *) rx->skb->data;
+ sc = le16_to_cpu(hdr->seq_ctrl);
+ frag = sc & IEEE80211_SCTL_FRAG;
+
+ if (likely((!(rx->fc & IEEE80211_FCTL_MOREFRAGS) && frag == 0) ||
+ (rx->skb)->len < 24 ||
+ is_multicast_ether_addr(hdr->addr1))) {
+ /* not fragmented */
+ goto out;
+ }
+ I802_DEBUG_INC(rx->local->rx_handlers_fragments);
+
+ seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+
+ if (frag == 0) {
+ /* This is the first fragment of a new frame. */
+ entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
+ rx->u.rx.queue, &(rx->skb));
+ if (rx->key && rx->key->alg == ALG_CCMP &&
+ (rx->fc & IEEE80211_FCTL_PROTECTED)) {
+ /* Store CCMP PN so that we can verify that the next
+ * fragment has a sequential PN value. */
+ entry->ccmp = 1;
+ memcpy(entry->last_pn,
+ rx->key->u.ccmp.rx_pn[rx->u.rx.queue],
+ CCMP_PN_LEN);
+ }
+ return TXRX_QUEUED;
+ }
+
+ /* This is a fragment for a frame that should already be pending in
+ * fragment cache. Add this fragment to the end of the pending entry.
+ */
+ entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
+ rx->u.rx.queue, hdr);
+ if (!entry) {
+ I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+ return TXRX_DROP;
+ }
+
+ /* Verify that MPDUs within one MSDU have sequential PN values.
+ * (IEEE 802.11i, 8.3.3.4.5) */
+ if (entry->ccmp) {
+ int i;
+ u8 pn[CCMP_PN_LEN], *rpn;
+ if (!rx->key || rx->key->alg != ALG_CCMP)
+ return TXRX_DROP;
+ memcpy(pn, entry->last_pn, CCMP_PN_LEN);
+ for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
+ pn[i]++;
+ if (pn[i])
+ break;
+ }
+ rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue];
+ if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) {
+ printk(KERN_DEBUG "%s: defrag: CCMP PN not sequential"
+ " A2=" MAC_FMT " PN=%02x%02x%02x%02x%02x%02x "
+ "(expected %02x%02x%02x%02x%02x%02x)\n",
+ rx->dev->name, MAC_ARG(hdr->addr2),
+ rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5],
+ pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
+ return TXRX_DROP;
+ }
+ memcpy(entry->last_pn, pn, CCMP_PN_LEN);
+ }
+
+ skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc));
+ __skb_queue_tail(&entry->skb_list, rx->skb);
+ entry->last_frag = frag;
+ entry->extra_len += rx->skb->len;
+ if (rx->fc & IEEE80211_FCTL_MOREFRAGS) {
+ rx->skb = NULL;
+ return TXRX_QUEUED;
+ }
+
+ rx->skb = __skb_dequeue(&entry->skb_list);
+ if (skb_tailroom(rx->skb) < entry->extra_len) {
+ I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
+ if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
+ GFP_ATOMIC))) {
+ I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+ __skb_queue_purge(&entry->skb_list);
+ return TXRX_DROP;
+ }
+ }
+ while ((skb = __skb_dequeue(&entry->skb_list)))
+ memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len);
+
+ /* Complete frame has been reassembled - process it now */
+ rx->fragmented = 1;
+
+ out:
+ if (rx->sta)
+ rx->sta->rx_packets++;
+ if (is_multicast_ether_addr(hdr->addr1))
+ rx->local->dot11MulticastReceivedFrameCount++;
+ else
+ ieee80211_led_rx(rx->local);
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_monitor(struct ieee80211_txrx_data *rx)
+{
+ if (rx->sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ ieee80211_rx_monitor(rx->dev, rx->skb, rx->u.rx.status);
+ return TXRX_QUEUED;
+ }
+
+ if (rx->u.rx.status->flag & RX_FLAG_RADIOTAP)
+ skb_pull(rx->skb, ieee80211_get_radiotap_len(rx->skb));
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_check(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_hdr *hdr;
+ int always_sta_key;
+ hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+ /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
+ if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+ if (unlikely(rx->fc & IEEE80211_FCTL_RETRY &&
+ rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
+ hdr->seq_ctrl)) {
+ if (rx->u.rx.ra_match) {
+ rx->local->dot11FrameDuplicateCount++;
+ rx->sta->num_duplicates++;
+ }
+ return TXRX_DROP;
+ } else
+ rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
+ }
+
+ if ((rx->local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) &&
+ rx->skb->len > FCS_LEN)
+ skb_trim(rx->skb, rx->skb->len - FCS_LEN);
+
+ if (unlikely(rx->skb->len < 16)) {
+ I802_DEBUG_INC(rx->local->rx_handlers_drop_short);
+ return TXRX_DROP;
+ }
+
+ if (!rx->u.rx.ra_match)
+ rx->skb->pkt_type = PACKET_OTHERHOST;
+ else if (compare_ether_addr(rx->dev->dev_addr, hdr->addr1) == 0)
+ rx->skb->pkt_type = PACKET_HOST;
+ else if (is_multicast_ether_addr(hdr->addr1)) {
+ if (is_broadcast_ether_addr(hdr->addr1))
+ rx->skb->pkt_type = PACKET_BROADCAST;
+ else
+ rx->skb->pkt_type = PACKET_MULTICAST;
+ } else
+ rx->skb->pkt_type = PACKET_OTHERHOST;
+
+ /* Drop disallowed frame classes based on STA auth/assoc state;
+ * IEEE 802.11, Chap 5.5.
+ *
+ * 80211.o does filtering only based on association state, i.e., it
+ * drops Class 3 frames from not associated stations. hostapd sends
+ * deauth/disassoc frames when needed. In addition, hostapd is
+ * responsible for filtering on both auth and assoc states.
+ */
+ if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA ||
+ ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL &&
+ (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) &&
+ rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
+ (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
+ if ((!(rx->fc & IEEE80211_FCTL_FROMDS) &&
+ !(rx->fc & IEEE80211_FCTL_TODS) &&
+ (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
+ || !rx->u.rx.ra_match) {
+ /* Drop IBSS frames and frames for other hosts
+ * silently. */
+ return TXRX_DROP;
+ }
+
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_sta_not_assoc);
+ return TXRX_QUEUED;
+ }
+
+ if (rx->sdata->type == IEEE80211_IF_TYPE_STA)
+ always_sta_key = 0;
+ else
+ always_sta_key = 1;
+
+ if (rx->sta && rx->sta->key && always_sta_key) {
+ rx->key = rx->sta->key;
+ } else {
+ if (rx->sta && rx->sta->key)
+ rx->key = rx->sta->key;
+ else
+ rx->key = rx->sdata->default_key;
+
+ if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+ rx->fc & IEEE80211_FCTL_PROTECTED) {
+ int keyidx = ieee80211_wep_get_keyidx(rx->skb);
+
+ if (keyidx >= 0 && keyidx < NUM_DEFAULT_KEYS &&
+ (!rx->sta || !rx->sta->key || keyidx > 0))
+ rx->key = rx->sdata->keys[keyidx];
+
+ if (!rx->key) {
+ if (!rx->u.rx.ra_match)
+ return TXRX_DROP;
+ printk(KERN_DEBUG "%s: RX WEP frame with "
+ "unknown keyidx %d (A1=" MAC_FMT " A2="
+ MAC_FMT " A3=" MAC_FMT ")\n",
+ rx->dev->name, keyidx,
+ MAC_ARG(hdr->addr1),
+ MAC_ARG(hdr->addr2),
+ MAC_ARG(hdr->addr3));
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+ ieee80211_rx_mgmt(
+ rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_wep_frame_unknown_key);
+ return TXRX_QUEUED;
+ }
+ }
+ }
+
+ if (rx->fc & IEEE80211_FCTL_PROTECTED && rx->key && rx->u.rx.ra_match) {
+ rx->key->tx_rx_count++;
+ if (unlikely(rx->local->key_tx_rx_threshold &&
+ rx->key->tx_rx_count >
+ rx->local->key_tx_rx_threshold)) {
+ ieee80211_key_threshold_notify(rx->dev, rx->key,
+ rx->sta);
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx)
+{
+ struct sta_info *sta = rx->sta;
+ struct net_device *dev = rx->dev;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+
+ if (!sta)
+ return TXRX_CONTINUE;
+
+ /* Update last_rx only for IBSS packets which are for the current
+ * BSSID to avoid keeping the current IBSS network alive in cases where
+ * other STAs are using different BSSID. */
+ if (rx->sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len);
+ if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
+ sta->last_rx = jiffies;
+ } else
+ if (!is_multicast_ether_addr(hdr->addr1) ||
+ rx->sdata->type == IEEE80211_IF_TYPE_STA) {
+ /* Update last_rx only for unicast frames in order to prevent
+ * the Probe Request frames (the only broadcast frames from a
+ * STA in infrastructure mode) from keeping a connection alive.
+ */
+ sta->last_rx = jiffies;
+ }
+
+ if (!rx->u.rx.ra_match)
+ return TXRX_CONTINUE;
+
+ sta->rx_fragments++;
+ sta->rx_bytes += rx->skb->len;
+ sta->last_rssi = (sta->last_rssi * 15 +
+ rx->u.rx.status->ssi) / 16;
+ sta->last_signal = (sta->last_signal * 15 +
+ rx->u.rx.status->signal) / 16;
+ sta->last_noise = (sta->last_noise * 15 +
+ rx->u.rx.status->noise) / 16;
+
+ if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) {
+ /* Change STA power saving mode only in the end of a frame
+ * exchange sequence */
+ if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM))
+ rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta);
+ else if (!(sta->flags & WLAN_STA_PS) &&
+ (rx->fc & IEEE80211_FCTL_PM))
+ ap_sta_ps_start(dev, sta);
+ }
+
+ /* Drop data::nullfunc frames silently, since they are used only to
+ * control station power saving mode. */
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_NULLFUNC) {
+ I802_DEBUG_INC(rx->local->rx_handlers_drop_nullfunc);
+ /* Update counter and free packet here to avoid counting this
+ * as a dropped packed. */
+ sta->rx_packets++;
+ dev_kfree_skb(rx->skb);
+ return TXRX_QUEUED;
+ }
+
+ return TXRX_CONTINUE;
+} /* ieee80211_rx_h_sta_process */
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_wep_weak_iv_detection(struct ieee80211_txrx_data *rx)
+{
+ if (!rx->sta || !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+ (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+ !rx->key || rx->key->alg != ALG_WEP || !rx->u.rx.ra_match)
+ return TXRX_CONTINUE;
+
+ /* Check for weak IVs, if hwaccel did not remove IV from the frame */
+ if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) ||
+ rx->key->force_sw_encrypt) {
+ u8 *iv = ieee80211_wep_is_weak_iv(rx->skb, rx->key);
+ if (iv) {
+ rx->sta->wep_weak_iv_count++;
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_wep_decrypt(struct ieee80211_txrx_data *rx)
+{
+ /* If the device handles decryption totally, skip this test */
+ if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
+ return TXRX_CONTINUE;
+
+ if ((rx->key && rx->key->alg != ALG_WEP) ||
+ !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+ ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+ ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+ (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)))
+ return TXRX_CONTINUE;
+
+ if (!rx->key) {
+ printk(KERN_DEBUG "%s: RX WEP frame, but no key set\n",
+ rx->dev->name);
+ return TXRX_DROP;
+ }
+
+ if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED) ||
+ rx->key->force_sw_encrypt) {
+ if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) {
+ printk(KERN_DEBUG "%s: RX WEP frame, decrypt "
+ "failed\n", rx->dev->name);
+ return TXRX_DROP;
+ }
+ } else if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+ ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key);
+ /* remove ICV */
+ skb_trim(rx->skb, rx->skb->len - 4);
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
+{
+ if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
+ rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) {
+ /* Pass both encrypted and unencrypted EAPOL frames to user
+ * space for processing. */
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_normal);
+ return TXRX_QUEUED;
+ }
+
+ if (unlikely(rx->sdata->ieee802_1x &&
+ (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+ (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)) &&
+ !ieee80211_is_eapol(rx->skb))) {
+#ifdef CONFIG_MAC80211_DEBUG
+ struct ieee80211_hdr *hdr =
+ (struct ieee80211_hdr *) rx->skb->data;
+ printk(KERN_DEBUG "%s: dropped frame from " MAC_FMT
+ " (unauthorized port)\n", rx->dev->name,
+ MAC_ARG(hdr->addr2));
+#endif /* CONFIG_MAC80211_DEBUG */
+ return TXRX_DROP;
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
+{
+ /* If the device handles decryption totally, skip this test */
+ if (rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP)
+ return TXRX_CONTINUE;
+
+ /* Drop unencrypted frames if key is set. */
+ if (unlikely(!(rx->fc & IEEE80211_FCTL_PROTECTED) &&
+ (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_NULLFUNC &&
+ (rx->key || rx->sdata->drop_unencrypted) &&
+ (rx->sdata->eapol == 0 ||
+ !ieee80211_is_eapol(rx->skb)))) {
+ printk(KERN_DEBUG "%s: RX non-WEP frame, but expected "
+ "encryption\n", rx->dev->name);
+ return TXRX_DROP;
+ }
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ if (!rx->u.rx.ra_match)
+ return TXRX_DROP;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
+ if ((sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) &&
+ !rx->local->user_space_mlme) {
+ ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status);
+ } else {
+ /* Management frames are sent to hostapd for processing */
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_normal);
+ }
+ return TXRX_QUEUED;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_local *local = rx->local;
+ struct sk_buff *skb = rx->skb;
+
+ if (unlikely(local->sta_scanning != 0)) {
+ ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+ return TXRX_QUEUED;
+ }
+
+ if (unlikely(rx->u.rx.in_scan)) {
+ /* scanning finished during invoking of handlers */
+ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan);
+ return TXRX_DROP;
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+static void ieee80211_rx_michael_mic_report(struct net_device *dev,
+ struct ieee80211_hdr *hdr,
+ struct sta_info *sta,
+ struct ieee80211_txrx_data *rx)
+{
+ int keyidx, hdrlen;
+
+ hdrlen = ieee80211_get_hdrlen_from_skb(rx->skb);
+ if (rx->skb->len >= hdrlen + 4)
+ keyidx = rx->skb->data[hdrlen + 3] >> 6;
+ else
+ keyidx = -1;
+
+ /* TODO: verify that this is not triggered by fragmented
+ * frames (hw does not verify MIC for them). */
+ printk(KERN_DEBUG "%s: TKIP hwaccel reported Michael MIC "
+ "failure from " MAC_FMT " to " MAC_FMT " keyidx=%d\n",
+ dev->name, MAC_ARG(hdr->addr2), MAC_ARG(hdr->addr1), keyidx);
+
+ if (!sta) {
+ /* Some hardware versions seem to generate incorrect
+ * Michael MIC reports; ignore them to avoid triggering
+ * countermeasures. */
+ printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+ "error for unknown address " MAC_FMT "\n",
+ dev->name, MAC_ARG(hdr->addr2));
+ goto ignore;
+ }
+
+ if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) {
+ printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+ "error for a frame with no ISWEP flag (src "
+ MAC_FMT ")\n", dev->name, MAC_ARG(hdr->addr2));
+ goto ignore;
+ }
+
+ if ((rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+ rx->sdata->type == IEEE80211_IF_TYPE_AP) {
+ keyidx = ieee80211_wep_get_keyidx(rx->skb);
+ /* AP with Pairwise keys support should never receive Michael
+ * MIC errors for non-zero keyidx because these are reserved
+ * for group keys and only the AP is sending real multicast
+ * frames in BSS. */
+ if (keyidx) {
+ printk(KERN_DEBUG "%s: ignored Michael MIC error for "
+ "a frame with non-zero keyidx (%d) (src " MAC_FMT
+ ")\n", dev->name, keyidx, MAC_ARG(hdr->addr2));
+ goto ignore;
+ }
+ }
+
+ if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA &&
+ ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT ||
+ (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) {
+ printk(KERN_DEBUG "%s: ignored spurious Michael MIC "
+ "error for a frame that cannot be encrypted "
+ "(fc=0x%04x) (src " MAC_FMT ")\n",
+ dev->name, rx->fc, MAC_ARG(hdr->addr2));
+ goto ignore;
+ }
+
+ do {
+ union iwreq_data wrqu;
+ char *buf = kmalloc(128, GFP_ATOMIC);
+ if (!buf)
+ break;
+
+ /* TODO: needed parameters: count, key type, TSC */
+ sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+ "keyid=%d %scast addr=" MAC_FMT ")",
+ keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni",
+ MAC_ARG(hdr->addr2));
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf);
+ kfree(buf);
+ } while (0);
+
+ /* TODO: consider verifying the MIC error report with software
+ * implementation if we get too many spurious reports from the
+ * hardware. */
+ if (!rx->local->apdev)
+ goto ignore;
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_michael_mic_failure);
+ return;
+
+ ignore:
+ dev_kfree_skb(rx->skb);
+ rx->skb = NULL;
+}
+
+static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
+ struct ieee80211_local *local,
+ ieee80211_rx_handler *handlers,
+ struct ieee80211_txrx_data *rx,
+ struct sta_info *sta)
+{
+ ieee80211_rx_handler *handler;
+ ieee80211_txrx_result res = TXRX_DROP;
+
+ for (handler = handlers; *handler != NULL; handler++) {
+ res = (*handler)(rx);
+ if (res != TXRX_CONTINUE) {
+ if (res == TXRX_DROP) {
+ I802_DEBUG_INC(local->rx_handlers_drop);
+ if (sta)
+ sta->rx_dropped++;
+ }
+ if (res == TXRX_QUEUED)
+ I802_DEBUG_INC(local->rx_handlers_queued);
+ break;
+ }
+ }
+
+ if (res == TXRX_DROP) {
+ dev_kfree_skb(rx->skb);
+ }
+ return res;
+}
+
+static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
+ ieee80211_rx_handler *handlers,
+ struct ieee80211_txrx_data *rx,
+ struct sta_info *sta)
+{
+ if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
+ TXRX_CONTINUE)
+ dev_kfree_skb(rx->skb);
+}
+
+/*
+ * This is the receive path handler. It is called by a low level driver when an
+ * 802.11 MPDU is received from the hardware.
+ */
+void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_rx_status *status)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_txrx_data rx;
+ u16 type;
+ int multicast;
+ int radiotap_len = 0;
+
+ if (status->flag & RX_FLAG_RADIOTAP) {
+ radiotap_len = ieee80211_get_radiotap_len(skb);
+ skb_pull(skb, radiotap_len);
+ }
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ memset(&rx, 0, sizeof(rx));
+ rx.skb = skb;
+ rx.local = local;
+
+ rx.u.rx.status = status;
+ rx.fc = skb->len >= 2 ? le16_to_cpu(hdr->frame_control) : 0;
+ type = rx.fc & IEEE80211_FCTL_FTYPE;
+ if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT)
+ local->dot11ReceivedFragmentCount++;
+ multicast = is_multicast_ether_addr(hdr->addr1);
+
+ if (skb->len >= 16)
+ sta = rx.sta = sta_info_get(local, hdr->addr2);
+ else
+ sta = rx.sta = NULL;
+
+ if (sta) {
+ rx.dev = sta->dev;
+ rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
+ }
+
+ if ((status->flag & RX_FLAG_MMIC_ERROR)) {
+ ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx);
+ goto end;
+ }
+
+ if (unlikely(local->sta_scanning))
+ rx.u.rx.in_scan = 1;
+
+ if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
+ sta) != TXRX_CONTINUE)
+ goto end;
+ skb = rx.skb;
+
+ skb_push(skb, radiotap_len);
+ if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
+ !local->iff_promiscs && !multicast) {
+ rx.u.rx.ra_match = 1;
+ ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
+ sta);
+ } else {
+ struct ieee80211_sub_if_data *prev = NULL;
+ struct sk_buff *skb_new;
+ u8 *bssid = ieee80211_get_bssid(hdr, skb->len - radiotap_len);
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ rx.u.rx.ra_match = 1;
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_STA:
+ if (!bssid)
+ continue;
+ if (!ieee80211_bssid_match(bssid,
+ sdata->u.sta.bssid)) {
+ if (!rx.u.rx.in_scan)
+ continue;
+ rx.u.rx.ra_match = 0;
+ } else if (!multicast &&
+ compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr1) != 0) {
+ if (!sdata->promisc)
+ continue;
+ rx.u.rx.ra_match = 0;
+ }
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ if (!bssid)
+ continue;
+ if (!ieee80211_bssid_match(bssid,
+ sdata->u.sta.bssid)) {
+ if (!rx.u.rx.in_scan)
+ continue;
+ rx.u.rx.ra_match = 0;
+ } else if (!multicast &&
+ compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr1) != 0) {
+ if (!sdata->promisc)
+ continue;
+ rx.u.rx.ra_match = 0;
+ } else if (!sta)
+ sta = rx.sta =
+ ieee80211_ibss_add_sta(sdata->dev,
+ skb, bssid,
+ hdr->addr2);
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ if (!bssid) {
+ if (compare_ether_addr(sdata->dev->dev_addr,
+ hdr->addr1) != 0)
+ continue;
+ } else if (!ieee80211_bssid_match(bssid,
+ sdata->dev->dev_addr)) {
+ if (!rx.u.rx.in_scan)
+ continue;
+ rx.u.rx.ra_match = 0;
+ }
+ if (sdata->dev == local->mdev &&
+ !rx.u.rx.in_scan)
+ /* do not receive anything via
+ * master device when not scanning */
+ continue;
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ if (bssid ||
+ (rx.fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+ continue;
+ if (compare_ether_addr(sdata->u.wds.remote_addr,
+ hdr->addr2) != 0)
+ continue;
+ break;
+ }
+
+ if (prev) {
+ skb_new = skb_copy(skb, GFP_ATOMIC);
+ if (!skb_new) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: failed to copy "
+ "multicast frame for %s",
+ local->mdev->name, prev->dev->name);
+ continue;
+ }
+ rx.skb = skb_new;
+ rx.dev = prev->dev;
+ rx.sdata = prev;
+ ieee80211_invoke_rx_handlers(local,
+ local->rx_handlers,
+ &rx, sta);
+ }
+ prev = sdata;
+ }
+ if (prev) {
+ rx.skb = skb;
+ rx.dev = prev->dev;
+ rx.sdata = prev;
+ ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+ &rx, sta);
+ } else
+ dev_kfree_skb(skb);
+ read_unlock(&local->sub_if_lock);
+ }
+
+ end:
+ if (sta)
+ sta_info_put(sta);
+}
+EXPORT_SYMBOL(__ieee80211_rx);
+
+static ieee80211_txrx_result
+ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_local *local = tx->local;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
+ struct sk_buff *skb = tx->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u32 load = 0, hdrtime;
+
+ /* TODO: this could be part of tx_status handling, so that the number
+ * of retries would be known; TX rate should in that case be stored
+ * somewhere with the packet */
+
+ /* Estimate total channel use caused by this frame */
+
+ /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+ * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+ if (mode->mode == MODE_IEEE80211A ||
+ mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG ||
+ (mode->mode == MODE_IEEE80211G &&
+ tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
+ hdrtime = CHAN_UTIL_HDR_SHORT;
+ else
+ hdrtime = CHAN_UTIL_HDR_LONG;
+
+ load = hdrtime;
+ if (!is_multicast_ether_addr(hdr->addr1))
+ load += hdrtime;
+
+ if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ load += 2 * hdrtime;
+ else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+ load += hdrtime;
+
+ load += skb->len * tx->u.tx.rate->rate_inv;
+
+ if (tx->u.tx.extra_frag) {
+ int i;
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ load += 2 * hdrtime;
+ load += tx->u.tx.extra_frag[i]->len *
+ tx->u.tx.rate->rate;
+ }
+ }
+
+ /* Divide channel_use by 8 to avoid wrapping around the counter */
+ load >>= CHAN_UTIL_SHIFT;
+ local->channel_use_raw += load;
+ if (tx->sta)
+ tx->sta->channel_use_raw += load;
+ tx->sdata->channel_use_raw += load;
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result
+ieee80211_rx_h_load_stats(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_local *local = rx->local;
+ struct sk_buff *skb = rx->skb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u32 load = 0, hdrtime;
+ struct ieee80211_rate *rate;
+ struct ieee80211_hw_mode *mode = local->hw.conf.mode;
+ int i;
+
+ /* Estimate total channel use caused by this frame */
+
+ if (unlikely(mode->num_rates < 0))
+ return TXRX_CONTINUE;
+
+ rate = &mode->rates[0];
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].val == rx->u.rx.status->rate) {
+ rate = &mode->rates[i];
+ break;
+ }
+ }
+
+ /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
+ * 1 usec = 1/8 * (1080 / 10) = 13.5 */
+
+ if (mode->mode == MODE_IEEE80211A ||
+ mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG ||
+ (mode->mode == MODE_IEEE80211G &&
+ rate->flags & IEEE80211_RATE_ERP))
+ hdrtime = CHAN_UTIL_HDR_SHORT;
+ else
+ hdrtime = CHAN_UTIL_HDR_LONG;
+
+ load = hdrtime;
+ if (!is_multicast_ether_addr(hdr->addr1))
+ load += hdrtime;
+
+ load += skb->len * rate->rate_inv;
+
+ /* Divide channel_use by 8 to avoid wrapping around the counter */
+ load >>= CHAN_UTIL_SHIFT;
+ local->channel_use_raw += load;
+ if (rx->sta)
+ rx->sta->channel_use_raw += load;
+ rx->u.rx.load = load;
+
+ return TXRX_CONTINUE;
+}
+
+static ieee80211_txrx_result
+ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+{
+ rx->sdata->channel_use_raw += rx->u.rx.load;
+ return TXRX_CONTINUE;
+}
+
+static void ieee80211_stat_refresh(unsigned long data)
+{
+ struct ieee80211_local *local = (struct ieee80211_local *) data;
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata;
+
+ if (!local->stat_time)
+ return;
+
+ /* go through all stations */
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ sta->channel_use = (sta->channel_use_raw / local->stat_time) /
+ CHAN_UTIL_PER_10MS;
+ sta->channel_use_raw = 0;
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ /* go through all subinterfaces */
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ sdata->channel_use = (sdata->channel_use_raw /
+ local->stat_time) / CHAN_UTIL_PER_10MS;
+ sdata->channel_use_raw = 0;
+ }
+ read_unlock(&local->sub_if_lock);
+
+ /* hardware interface */
+ local->channel_use = (local->channel_use_raw /
+ local->stat_time) / CHAN_UTIL_PER_10MS;
+ local->channel_use_raw = 0;
+
+ local->stat_timer.expires = jiffies + HZ * local->stat_time / 100;
+ add_timer(&local->stat_timer);
+}
+
+
+/* This is a version of the rx handler that can be called from hard irq
+ * context. Post the skb on the queue and schedule the tasklet */
+void ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_rx_status *status)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ BUILD_BUG_ON(sizeof(struct ieee80211_rx_status) > sizeof(skb->cb));
+
+ skb->dev = local->mdev;
+ /* copy status into skb->cb for use by tasklet */
+ memcpy(skb->cb, status, sizeof(*status));
+ skb->pkt_type = IEEE80211_RX_MSG;
+ skb_queue_tail(&local->skb_queue, skb);
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_rx_irqsafe);
+
+void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_tx_status *saved;
+ int tmp;
+
+ skb->dev = local->mdev;
+ saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
+ if (unlikely(!saved)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "%s: Not enough memory, "
+ "dropping tx status", skb->dev->name);
+ /* should be dev_kfree_skb_irq, but due to this function being
+ * named _irqsafe instead of just _irq we can't be sure that
+ * people won't call it from non-irq contexts */
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ memcpy(saved, status, sizeof(struct ieee80211_tx_status));
+ /* copy pointer to saved status into skb->cb for use by tasklet */
+ memcpy(skb->cb, &saved, sizeof(saved));
+
+ skb->pkt_type = IEEE80211_TX_STATUS_MSG;
+ skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+ &local->skb_queue : &local->skb_queue_unreliable, skb);
+ tmp = skb_queue_len(&local->skb_queue) +
+ skb_queue_len(&local->skb_queue_unreliable);
+ while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
+ (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+ memcpy(&saved, skb->cb, sizeof(saved));
+ kfree(saved);
+ dev_kfree_skb_irq(skb);
+ tmp--;
+ I802_DEBUG_INC(local->tx_status_drop);
+ }
+ tasklet_schedule(&local->tasklet);
+}
+EXPORT_SYMBOL(ieee80211_tx_status_irqsafe);
+
+static void ieee80211_tasklet_handler(unsigned long data)
+{
+ struct ieee80211_local *local = (struct ieee80211_local *) data;
+ struct sk_buff *skb;
+ struct ieee80211_rx_status rx_status;
+ struct ieee80211_tx_status *tx_status;
+
+ while ((skb = skb_dequeue(&local->skb_queue)) ||
+ (skb = skb_dequeue(&local->skb_queue_unreliable))) {
+ switch (skb->pkt_type) {
+ case IEEE80211_RX_MSG:
+ /* status is in skb->cb */
+ memcpy(&rx_status, skb->cb, sizeof(rx_status));
+ /* Clear skb->type in order to not confuse kernel
+ * netstack. */
+ skb->pkt_type = 0;
+ __ieee80211_rx(local_to_hw(local), skb, &rx_status);
+ break;
+ case IEEE80211_TX_STATUS_MSG:
+ /* get pointer to saved status out of skb->cb */
+ memcpy(&tx_status, skb->cb, sizeof(tx_status));
+ skb->pkt_type = 0;
+ ieee80211_tx_status(local_to_hw(local),
+ skb, tx_status);
+ kfree(tx_status);
+ break;
+ default: /* should never get here! */
+ printk(KERN_ERR "%s: Unknown message type (%d)\n",
+ local->mdev->name, skb->pkt_type);
+ dev_kfree_skb(skb);
+ break;
+ }
+ }
+}
+
+
+/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
+ * make a prepared TX frame (one that has been given to hw) to look like brand
+ * new IEEE 802.11 frame that is ready to go through TX processing again.
+ * Also, tx_packet_data in cb is restored from tx_control. */
+static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
+ struct ieee80211_key *key,
+ struct sk_buff *skb,
+ struct ieee80211_tx_control *control)
+{
+ int hdrlen, iv_len, mic_len;
+ struct ieee80211_tx_packet_data *pkt_data;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ pkt_data->ifindex = control->ifindex;
+ pkt_data->mgmt_iface = (control->type == IEEE80211_IF_TYPE_MGMT);
+ pkt_data->req_tx_status = !!(control->flags & IEEE80211_TXCTL_REQ_TX_STATUS);
+ pkt_data->do_not_encrypt = !!(control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT);
+ pkt_data->requeue = !!(control->flags & IEEE80211_TXCTL_REQUEUE);
+ pkt_data->queue = control->queue;
+
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+
+ if (!key)
+ goto no_key;
+
+ switch (key->alg) {
+ case ALG_WEP:
+ iv_len = WEP_IV_LEN;
+ mic_len = WEP_ICV_LEN;
+ break;
+ case ALG_TKIP:
+ iv_len = TKIP_IV_LEN;
+ mic_len = TKIP_ICV_LEN;
+ break;
+ case ALG_CCMP:
+ iv_len = CCMP_HDR_LEN;
+ mic_len = CCMP_MIC_LEN;
+ break;
+ default:
+ goto no_key;
+ }
+
+ if (skb->len >= mic_len && key->force_sw_encrypt)
+ skb_trim(skb, skb->len - mic_len);
+ if (skb->len >= iv_len && skb->len > hdrlen) {
+ memmove(skb->data + iv_len, skb->data, hdrlen);
+ skb_pull(skb, iv_len);
+ }
+
+no_key:
+ {
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ if ((fc & 0x8C) == 0x88) /* QoS Control Field */ {
+ fc &= ~IEEE80211_STYPE_QOS_DATA;
+ hdr->frame_control = cpu_to_le16(fc);
+ memmove(skb->data + 2, skb->data, hdrlen - 2);
+ skb_pull(skb, 2);
+ }
+ }
+}
+
+
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+ struct sk_buff *skb2;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_local *local = hw_to_local(hw);
+ u16 frag, type;
+ u32 msg_type;
+
+ if (!status) {
+ printk(KERN_ERR
+ "%s: ieee80211_tx_status called with NULL status\n",
+ local->mdev->name);
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ if (status->excessive_retries) {
+ struct sta_info *sta;
+ sta = sta_info_get(local, hdr->addr1);
+ if (sta) {
+ if (sta->flags & WLAN_STA_PS) {
+ /* The STA is in power save mode, so assume
+ * that this TX packet failed because of that.
+ */
+ status->excessive_retries = 0;
+ status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
+ }
+ sta_info_put(sta);
+ }
+ }
+
+ if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
+ struct sta_info *sta;
+ sta = sta_info_get(local, hdr->addr1);
+ if (sta) {
+ sta->tx_filtered_count++;
+
+ /* Clear the TX filter mask for this STA when sending
+ * the next packet. If the STA went to power save mode,
+ * this will happen when it is waking up for the next
+ * time. */
+ sta->clear_dst_mask = 1;
+
+ /* TODO: Is the WLAN_STA_PS flag always set here or is
+ * the race between RX and TX status causing some
+ * packets to be filtered out before 80211.o gets an
+ * update for PS status? This seems to be the case, so
+ * no changes are likely to be needed. */
+ if (sta->flags & WLAN_STA_PS &&
+ skb_queue_len(&sta->tx_filtered) <
+ STA_MAX_TX_BUFFER) {
+ ieee80211_remove_tx_extra(local, sta->key,
+ skb,
+ &status->control);
+ skb_queue_tail(&sta->tx_filtered, skb);
+ } else if (!(sta->flags & WLAN_STA_PS) &&
+ !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+ /* Software retry the packet once */
+ status->control.flags |= IEEE80211_TXCTL_REQUEUE;
+ ieee80211_remove_tx_extra(local, sta->key,
+ skb,
+ &status->control);
+ dev_queue_xmit(skb);
+ } else {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: dropped TX "
+ "filtered frame queue_len=%d "
+ "PS=%d @%lu\n",
+ local->mdev->name,
+ skb_queue_len(
+ &sta->tx_filtered),
+ !!(sta->flags & WLAN_STA_PS),
+ jiffies);
+ }
+ dev_kfree_skb(skb);
+ }
+ sta_info_put(sta);
+ return;
+ }
+ } else {
+ /* FIXME: STUPID to call this with both local and local->mdev */
+ rate_control_tx_status(local, local->mdev, skb, status);
+ }
+
+ ieee80211_led_tx(local, 0);
+
+ /* SNMP counters
+ * Fragments are passed to low-level drivers as separate skbs, so these
+ * are actually fragments, not frames. Update frame counters only for
+ * the first fragment of the frame. */
+
+ frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
+ type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
+
+ if (status->flags & IEEE80211_TX_STATUS_ACK) {
+ if (frag == 0) {
+ local->dot11TransmittedFrameCount++;
+ if (is_multicast_ether_addr(hdr->addr1))
+ local->dot11MulticastTransmittedFrameCount++;
+ if (status->retry_count > 0)
+ local->dot11RetryCount++;
+ if (status->retry_count > 1)
+ local->dot11MultipleRetryCount++;
+ }
+
+ /* This counter shall be incremented for an acknowledged MPDU
+ * with an individual address in the address 1 field or an MPDU
+ * with a multicast address in the address 1 field of type Data
+ * or Management. */
+ if (!is_multicast_ether_addr(hdr->addr1) ||
+ type == IEEE80211_FTYPE_DATA ||
+ type == IEEE80211_FTYPE_MGMT)
+ local->dot11TransmittedFragmentCount++;
+ } else {
+ if (frag == 0)
+ local->dot11FailedCount++;
+ }
+
+ if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS)
+ || unlikely(!local->apdev)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
+ ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
+
+ /* skb was the original skb used for TX. Clone it and give the clone
+ * to netif_rx(). Free original skb. */
+ skb2 = skb_copy(skb, GFP_ATOMIC);
+ if (!skb2) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ dev_kfree_skb(skb);
+ skb = skb2;
+
+ /* Send frame to hostapd */
+ ieee80211_rx_mgmt(local, skb, NULL, msg_type);
+}
+EXPORT_SYMBOL(ieee80211_tx_status);
+
+/* TODO: implement register/unregister functions for adding TX/RX handlers
+ * into ordered list */
+
+/* rx_pre handlers don't have dev and sdata fields available in
+ * ieee80211_txrx_data */
+static ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
+{
+ ieee80211_rx_h_parse_qos,
+ ieee80211_rx_h_load_stats,
+ NULL
+};
+
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
+{
+ ieee80211_rx_h_if_stats,
+ ieee80211_rx_h_monitor,
+ ieee80211_rx_h_passive_scan,
+ ieee80211_rx_h_check,
+ ieee80211_rx_h_sta_process,
+ ieee80211_rx_h_ccmp_decrypt,
+ ieee80211_rx_h_tkip_decrypt,
+ ieee80211_rx_h_wep_weak_iv_detection,
+ ieee80211_rx_h_wep_decrypt,
+ ieee80211_rx_h_defragment,
+ ieee80211_rx_h_ps_poll,
+ ieee80211_rx_h_michael_mic_verify,
+ /* this must be after decryption - so header is counted in MPDU mic
+ * must be before pae and data, so QOS_DATA format frames
+ * are not passed to user space by these functions
+ */
+ ieee80211_rx_h_remove_qos_control,
+ ieee80211_rx_h_802_1x_pae,
+ ieee80211_rx_h_drop_unencrypted,
+ ieee80211_rx_h_data,
+ ieee80211_rx_h_mgmt,
+ NULL
+};
+
+static ieee80211_tx_handler ieee80211_tx_handlers[] =
+{
+ ieee80211_tx_h_check_assoc,
+ ieee80211_tx_h_sequence,
+ ieee80211_tx_h_ps_buf,
+ ieee80211_tx_h_select_key,
+ ieee80211_tx_h_michael_mic_add,
+ ieee80211_tx_h_fragment,
+ ieee80211_tx_h_tkip_encrypt,
+ ieee80211_tx_h_ccmp_encrypt,
+ ieee80211_tx_h_wep_encrypt,
+ ieee80211_tx_h_rate_ctrl,
+ ieee80211_tx_h_misc,
+ ieee80211_tx_h_load_stats,
+ NULL
+};
+
+
+int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta;
+
+ if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
+ return 0;
+
+ /* Create STA entry for the new peer */
+ sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+ sta_info_put(sta);
+
+ /* Remove STA entry for the old peer */
+ sta = sta_info_get(local, sdata->u.wds.remote_addr);
+ if (sta) {
+ sta_info_put(sta);
+ sta_info_free(sta, 0);
+ } else {
+ printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
+ "peer " MAC_FMT "\n",
+ dev->name, MAC_ARG(sdata->u.wds.remote_addr));
+ }
+
+ /* Update WDS link data */
+ memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
+
+ return 0;
+}
+
+/* Must not be called for mdev and apdev */
+void ieee80211_if_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->hard_start_xmit = ieee80211_subif_start_xmit;
+ dev->wireless_handlers = &ieee80211_iw_handler_def;
+ dev->set_multicast_list = ieee80211_set_multicast_list;
+ dev->change_mtu = ieee80211_change_mtu;
+ dev->get_stats = ieee80211_get_stats;
+ dev->open = ieee80211_open;
+ dev->stop = ieee80211_stop;
+ dev->uninit = ieee80211_if_reinit;
+ dev->destructor = ieee80211_if_free;
+}
+
+void ieee80211_if_mgmt_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->hard_start_xmit = ieee80211_mgmt_start_xmit;
+ dev->change_mtu = ieee80211_change_mtu_apdev;
+ dev->get_stats = ieee80211_get_stats;
+ dev->open = ieee80211_mgmt_open;
+ dev->stop = ieee80211_mgmt_stop;
+ dev->type = ARPHRD_IEEE80211_PRISM;
+ dev->hard_header_parse = header_parse_80211;
+ dev->uninit = ieee80211_if_reinit;
+ dev->destructor = ieee80211_if_free;
+}
+
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+ const char *name)
+{
+ struct rate_control_ref *ref, *old;
+
+ ASSERT_RTNL();
+ if (local->open_count || netif_running(local->mdev) ||
+ (local->apdev && netif_running(local->apdev)))
+ return -EBUSY;
+
+ ref = rate_control_alloc(name, local);
+ if (!ref) {
+ printk(KERN_WARNING "%s: Failed to select rate control "
+ "algorithm\n", local->mdev->name);
+ return -ENOENT;
+ }
+
+ old = local->rate_ctrl;
+ local->rate_ctrl = ref;
+ if (old) {
+ rate_control_put(old);
+ sta_info_flush(local, NULL);
+ }
+
+ printk(KERN_DEBUG "%s: Selected rate control "
+ "algorithm '%s'\n", local->mdev->name,
+ ref->ops->name);
+
+
+ return 0;
+}
+
+static void rate_control_deinitialize(struct ieee80211_local *local)
+{
+ struct rate_control_ref *ref;
+
+ ref = local->rate_ctrl;
+ local->rate_ctrl = NULL;
+ rate_control_put(ref);
+}
+
+struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
+ const struct ieee80211_ops *ops)
+{
+ struct net_device *mdev;
+ struct ieee80211_local *local;
+ struct ieee80211_sub_if_data *sdata;
+ int priv_size;
+ struct wiphy *wiphy;
+
+ /* Ensure 32-byte alignment of our private data and hw private data.
+ * We use the wiphy priv data for both our ieee80211_local and for
+ * the driver's private data
+ *
+ * In memory it'll be like this:
+ *
+ * +-------------------------+
+ * | struct wiphy |
+ * +-------------------------+
+ * | struct ieee80211_local |
+ * +-------------------------+
+ * | driver's private data |
+ * +-------------------------+
+ *
+ */
+ priv_size = ((sizeof(struct ieee80211_local) +
+ NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
+ priv_data_len;
+
+ wiphy = wiphy_new(&mac80211_config_ops, priv_size);
+
+ if (!wiphy)
+ return NULL;
+
+ wiphy->privid = mac80211_wiphy_privid;
+
+ local = wiphy_priv(wiphy);
+ local->hw.wiphy = wiphy;
+
+ local->hw.priv = (char *)local +
+ ((sizeof(struct ieee80211_local) +
+ NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+
+ local->ops = ops;
+
+ /* for now, mdev needs sub_if_data :/ */
+ mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+ "wmaster%d", ether_setup);
+ if (!mdev) {
+ wiphy_free(wiphy);
+ return NULL;
+ }
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
+ mdev->ieee80211_ptr = &sdata->wdev;
+ sdata->wdev.wiphy = wiphy;
+
+ local->hw.queues = 1; /* default */
+
+ local->mdev = mdev;
+ local->rx_pre_handlers = ieee80211_rx_pre_handlers;
+ local->rx_handlers = ieee80211_rx_handlers;
+ local->tx_handlers = ieee80211_tx_handlers;
+
+ local->bridge_packets = 1;
+
+ local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+ local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+ local->short_retry_limit = 7;
+ local->long_retry_limit = 4;
+ local->hw.conf.radio_enabled = 1;
+ local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP;
+ local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN;
+
+ local->enabled_modes = (unsigned int) -1;
+
+ INIT_LIST_HEAD(&local->modes_list);
+
+ rwlock_init(&local->sub_if_lock);
+ INIT_LIST_HEAD(&local->sub_if_list);
+
+ INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work);
+ init_timer(&local->stat_timer);
+ local->stat_timer.function = ieee80211_stat_refresh;
+ local->stat_timer.data = (unsigned long) local;
+ ieee80211_rx_bss_list_init(mdev);
+
+ sta_info_init(local);
+
+ mdev->hard_start_xmit = ieee80211_master_start_xmit;
+ mdev->open = ieee80211_master_open;
+ mdev->stop = ieee80211_master_stop;
+ mdev->type = ARPHRD_IEEE80211;
+ mdev->hard_header_parse = header_parse_80211;
+
+ sdata->type = IEEE80211_IF_TYPE_AP;
+ sdata->dev = mdev;
+ sdata->local = local;
+ sdata->u.ap.force_unicast_rateidx = -1;
+ sdata->u.ap.max_ratectrl_rateidx = -1;
+ ieee80211_if_sdata_init(sdata);
+ list_add_tail(&sdata->list, &local->sub_if_list);
+
+ tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
+ (unsigned long)local);
+ tasklet_disable(&local->tx_pending_tasklet);
+
+ tasklet_init(&local->tasklet,
+ ieee80211_tasklet_handler,
+ (unsigned long) local);
+ tasklet_disable(&local->tasklet);
+
+ skb_queue_head_init(&local->skb_queue);
+ skb_queue_head_init(&local->skb_queue_unreliable);
+
+ return local_to_hw(local);
+}
+EXPORT_SYMBOL(ieee80211_alloc_hw);
+
+int ieee80211_register_hw(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ const char *name;
+ int result;
+
+ result = wiphy_register(local->hw.wiphy);
+ if (result < 0)
+ return result;
+
+ name = wiphy_dev(local->hw.wiphy)->driver->name;
+ local->hw.workqueue = create_singlethread_workqueue(name);
+ if (!local->hw.workqueue) {
+ result = -ENOMEM;
+ goto fail_workqueue;
+ }
+
+ debugfs_hw_add(local);
+
+ local->hw.conf.beacon_int = 1000;
+
+ local->wstats_flags |= local->hw.max_rssi ?
+ IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
+ local->wstats_flags |= local->hw.max_signal ?
+ IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
+ local->wstats_flags |= local->hw.max_noise ?
+ IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
+ if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+ local->wstats_flags |= IW_QUAL_DBM;
+
+ result = sta_info_start(local);
+ if (result < 0)
+ goto fail_sta_info;
+
+ rtnl_lock();
+ result = dev_alloc_name(local->mdev, local->mdev->name);
+ if (result < 0)
+ goto fail_dev;
+
+ memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
+
+ result = register_netdevice(local->mdev);
+ if (result < 0)
+ goto fail_dev;
+
+ ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
+
+ result = ieee80211_init_rate_ctrl_alg(local, NULL);
+ if (result < 0) {
+ printk(KERN_DEBUG "%s: Failed to initialize rate control "
+ "algorithm\n", local->mdev->name);
+ goto fail_rate;
+ }
+
+ result = ieee80211_wep_init(local);
+
+ if (result < 0) {
+ printk(KERN_DEBUG "%s: Failed to initialize wep\n",
+ local->mdev->name);
+ goto fail_wep;
+ }
+
+ ieee80211_install_qdisc(local->mdev);
+
+ /* add one default STA interface */
+ result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
+ IEEE80211_IF_TYPE_STA);
+ if (result)
+ printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
+ local->mdev->name);
+
+ local->reg_state = IEEE80211_DEV_REGISTERED;
+ rtnl_unlock();
+
+ ieee80211_led_init(local);
+
+ return 0;
+
+fail_wep:
+ rate_control_deinitialize(local);
+fail_rate:
+ ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
+ unregister_netdevice(local->mdev);
+fail_dev:
+ rtnl_unlock();
+ sta_info_stop(local);
+fail_sta_info:
+ debugfs_hw_del(local);
+ destroy_workqueue(local->hw.workqueue);
+fail_workqueue:
+ wiphy_unregister(local->hw.wiphy);
+ return result;
+}
+EXPORT_SYMBOL(ieee80211_register_hw);
+
+int ieee80211_register_hwmode(struct ieee80211_hw *hw,
+ struct ieee80211_hw_mode *mode)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_rate *rate;
+ int i;
+
+ INIT_LIST_HEAD(&mode->list);
+ list_add_tail(&mode->list, &local->modes_list);
+
+ local->hw_modes |= (1 << mode->mode);
+ for (i = 0; i < mode->num_rates; i++) {
+ rate = &(mode->rates[i]);
+ rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
+ }
+ ieee80211_prepare_rates(local, mode);
+
+ if (!local->oper_hw_mode) {
+ /* Default to this mode */
+ local->hw.conf.phymode = mode->mode;
+ local->oper_hw_mode = local->scan_hw_mode = mode;
+ local->oper_channel = local->scan_channel = &mode->channels[0];
+ local->hw.conf.mode = local->oper_hw_mode;
+ local->hw.conf.chan = local->oper_channel;
+ }
+
+ if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
+ ieee80211_init_client(local->mdev);
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_register_hwmode);
+
+void ieee80211_unregister_hw(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_sub_if_data *sdata, *tmp;
+ struct list_head tmp_list;
+ int i;
+
+ tasklet_kill(&local->tx_pending_tasklet);
+ tasklet_kill(&local->tasklet);
+
+ rtnl_lock();
+
+ BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
+
+ local->reg_state = IEEE80211_DEV_UNREGISTERED;
+ if (local->apdev)
+ ieee80211_if_del_mgmt(local);
+
+ write_lock_bh(&local->sub_if_lock);
+ list_replace_init(&local->sub_if_list, &tmp_list);
+ write_unlock_bh(&local->sub_if_lock);
+
+ list_for_each_entry_safe(sdata, tmp, &tmp_list, list)
+ __ieee80211_if_del(local, sdata);
+
+ rtnl_unlock();
+
+ if (local->stat_time)
+ del_timer_sync(&local->stat_timer);
+
+ ieee80211_rx_bss_list_deinit(local->mdev);
+ ieee80211_clear_tx_pending(local);
+ sta_info_stop(local);
+ rate_control_deinitialize(local);
+ debugfs_hw_del(local);
+
+ for (i = 0; i < NUM_IEEE80211_MODES; i++) {
+ kfree(local->supp_rates[i]);
+ kfree(local->basic_rates[i]);
+ }
+
+ if (skb_queue_len(&local->skb_queue)
+ || skb_queue_len(&local->skb_queue_unreliable))
+ printk(KERN_WARNING "%s: skb_queue not empty\n",
+ local->mdev->name);
+ skb_queue_purge(&local->skb_queue);
+ skb_queue_purge(&local->skb_queue_unreliable);
+
+ destroy_workqueue(local->hw.workqueue);
+ wiphy_unregister(local->hw.wiphy);
+ ieee80211_wep_free(local);
+ ieee80211_led_exit(local);
+}
+EXPORT_SYMBOL(ieee80211_unregister_hw);
+
+void ieee80211_free_hw(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ ieee80211_if_free(local->mdev);
+ wiphy_free(local->hw.wiphy);
+}
+EXPORT_SYMBOL(ieee80211_free_hw);
+
+void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (test_and_clear_bit(IEEE80211_LINK_STATE_XOFF,
+ &local->state[queue])) {
+ if (test_bit(IEEE80211_LINK_STATE_PENDING,
+ &local->state[queue]))
+ tasklet_schedule(&local->tx_pending_tasklet);
+ else
+ if (!ieee80211_qdisc_installed(local->mdev)) {
+ if (queue == 0)
+ netif_wake_queue(local->mdev);
+ } else
+ __netif_schedule(local->mdev);
+ }
+}
+EXPORT_SYMBOL(ieee80211_wake_queue);
+
+void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!ieee80211_qdisc_installed(local->mdev) && queue == 0)
+ netif_stop_queue(local->mdev);
+ set_bit(IEEE80211_LINK_STATE_XOFF, &local->state[queue]);
+}
+EXPORT_SYMBOL(ieee80211_stop_queue);
+
+void ieee80211_start_queues(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ int i;
+
+ for (i = 0; i < local->hw.queues; i++)
+ clear_bit(IEEE80211_LINK_STATE_XOFF, &local->state[i]);
+ if (!ieee80211_qdisc_installed(local->mdev))
+ netif_start_queue(local->mdev);
+}
+EXPORT_SYMBOL(ieee80211_start_queues);
+
+void ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->queues; i++)
+ ieee80211_stop_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_stop_queues);
+
+void ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+ int i;
+
+ for (i = 0; i < hw->queues; i++)
+ ieee80211_wake_queue(hw, i);
+}
+EXPORT_SYMBOL(ieee80211_wake_queues);
+
+struct net_device_stats *ieee80211_dev_stats(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ return &sdata->stats;
+}
+
+static int __init ieee80211_init(void)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+
+ ret = ieee80211_wme_register();
+ if (ret) {
+ printk(KERN_DEBUG "ieee80211_init: failed to "
+ "initialize WME (err=%d)\n", ret);
+ return ret;
+ }
+
+ ieee80211_debugfs_netdev_init();
+
+ return 0;
+}
+
+
+static void __exit ieee80211_exit(void)
+{
+ ieee80211_wme_unregister();
+ ieee80211_debugfs_netdev_exit();
+}
+
+
+module_init(ieee80211_init);
+module_exit(ieee80211_exit);
+
+MODULE_DESCRIPTION("IEEE 802.11 subsystem");
+MODULE_LICENSE("GPL");
diff --git a/net/mac80211/ieee80211_cfg.c b/net/mac80211/ieee80211_cfg.c
new file mode 100644
index 00000000000..509096edb32
--- /dev/null
+++ b/net/mac80211/ieee80211_cfg.c
@@ -0,0 +1,66 @@
+/*
+ * mac80211 configuration hooks for cfg80211
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This file is GPLv2 as found in COPYING.
+ */
+
+#include <linux/nl80211.h>
+#include <linux/rtnetlink.h>
+#include <net/cfg80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_cfg.h"
+
+static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
+ unsigned int type)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ int itype;
+
+ if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+ return -ENODEV;
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ itype = IEEE80211_IF_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ itype = IEEE80211_IF_TYPE_IBSS;
+ break;
+ case NL80211_IFTYPE_STATION:
+ itype = IEEE80211_IF_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_MONITOR:
+ itype = IEEE80211_IF_TYPE_MNTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ieee80211_if_add(local->mdev, name, NULL, itype);
+}
+
+static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct net_device *dev;
+ char *name;
+
+ if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED))
+ return -ENODEV;
+
+ dev = dev_get_by_index(ifindex);
+ if (!dev)
+ return 0;
+
+ name = dev->name;
+ dev_put(dev);
+
+ return ieee80211_if_remove(local->mdev, name, -1);
+}
+
+struct cfg80211_ops mac80211_config_ops = {
+ .add_virtual_intf = ieee80211_add_iface,
+ .del_virtual_intf = ieee80211_del_iface,
+};
diff --git a/net/mac80211/ieee80211_cfg.h b/net/mac80211/ieee80211_cfg.h
new file mode 100644
index 00000000000..85ed2c92487
--- /dev/null
+++ b/net/mac80211/ieee80211_cfg.h
@@ -0,0 +1,9 @@
+/*
+ * mac80211 configuration hooks for cfg80211
+ */
+#ifndef __IEEE80211_CFG_H
+#define __IEEE80211_CFG_H
+
+extern struct cfg80211_ops mac80211_config_ops;
+
+#endif /* __IEEE80211_CFG_H */
diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h
new file mode 100644
index 00000000000..b9a73e7f5f7
--- /dev/null
+++ b/net/mac80211/ieee80211_common.h
@@ -0,0 +1,98 @@
+/*
+ * IEEE 802.11 driver (80211.o) -- hostapd interface
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ *
+ * 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.
+ */
+
+#ifndef IEEE80211_COMMON_H
+#define IEEE80211_COMMON_H
+
+#include <linux/types.h>
+
+/*
+ * This is common header information with user space. It is used on all
+ * frames sent to wlan#ap interface.
+ */
+
+#define IEEE80211_FI_VERSION 0x80211001
+
+struct ieee80211_frame_info {
+ __be32 version;
+ __be32 length;
+ __be64 mactime;
+ __be64 hosttime;
+ __be32 phytype;
+ __be32 channel;
+ __be32 datarate;
+ __be32 antenna;
+ __be32 priority;
+ __be32 ssi_type;
+ __be32 ssi_signal;
+ __be32 ssi_noise;
+ __be32 preamble;
+ __be32 encoding;
+
+ /* Note: this structure is otherwise identical to capture format used
+ * in linux-wlan-ng, but this additional field is used to provide meta
+ * data about the frame to hostapd. This was the easiest method for
+ * providing this information, but this might change in the future. */
+ __be32 msg_type;
+} __attribute__ ((packed));
+
+
+enum ieee80211_msg_type {
+ ieee80211_msg_normal = 0,
+ ieee80211_msg_tx_callback_ack = 1,
+ ieee80211_msg_tx_callback_fail = 2,
+ ieee80211_msg_passive_scan = 3,
+ ieee80211_msg_wep_frame_unknown_key = 4,
+ ieee80211_msg_michael_mic_failure = 5,
+ /* hole at 6, was monitor but never sent to userspace */
+ ieee80211_msg_sta_not_assoc = 7,
+ ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */,
+ ieee80211_msg_key_threshold_notification = 9,
+ ieee80211_msg_radar = 11,
+};
+
+struct ieee80211_msg_set_aid_for_sta {
+ char sta_address[ETH_ALEN];
+ u16 aid;
+};
+
+struct ieee80211_msg_key_notification {
+ int tx_rx_count;
+ char ifname[IFNAMSIZ];
+ u8 addr[ETH_ALEN]; /* ff:ff:ff:ff:ff:ff for broadcast keys */
+};
+
+
+enum ieee80211_phytype {
+ ieee80211_phytype_fhss_dot11_97 = 1,
+ ieee80211_phytype_dsss_dot11_97 = 2,
+ ieee80211_phytype_irbaseband = 3,
+ ieee80211_phytype_dsss_dot11_b = 4,
+ ieee80211_phytype_pbcc_dot11_b = 5,
+ ieee80211_phytype_ofdm_dot11_g = 6,
+ ieee80211_phytype_pbcc_dot11_g = 7,
+ ieee80211_phytype_ofdm_dot11_a = 8,
+ ieee80211_phytype_dsss_dot11_turbog = 255,
+ ieee80211_phytype_dsss_dot11_turbo = 256,
+};
+
+enum ieee80211_ssi_type {
+ ieee80211_ssi_none = 0,
+ ieee80211_ssi_norm = 1, /* normalized, 0-1000 */
+ ieee80211_ssi_dbm = 2,
+ ieee80211_ssi_raw = 3, /* raw SSI */
+};
+
+struct ieee80211_radar_info {
+ int channel;
+ int radar;
+ int radar_type;
+};
+
+#endif /* IEEE80211_COMMON_H */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
new file mode 100644
index 00000000000..af4d14d0b96
--- /dev/null
+++ b/net/mac80211/ieee80211_i.h
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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.
+ */
+
+#ifndef IEEE80211_I_H
+#define IEEE80211_I_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/if_ether.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <net/wireless.h>
+#include "ieee80211_key.h"
+#include "sta_info.h"
+
+/* ieee80211.o internal definitions, etc. These are not included into
+ * low-level drivers. */
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define WLAN_FC_DATA_PRESENT(fc) (((fc) & 0x4c) == 0x08)
+
+struct ieee80211_local;
+
+#define BIT(x) (1 << (x))
+
+#define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3)
+
+/* Maximum number of broadcast/multicast frames to buffer when some of the
+ * associated stations are using power saving. */
+#define AP_MAX_BC_BUFFER 128
+
+/* Maximum number of frames buffered to all STAs, including multicast frames.
+ * Note: increasing this limit increases the potential memory requirement. Each
+ * frame can be up to about 2 kB long. */
+#define TOTAL_MAX_TX_BUFFER 512
+
+/* Required encryption head and tailroom */
+#define IEEE80211_ENCRYPT_HEADROOM 8
+#define IEEE80211_ENCRYPT_TAILROOM 12
+
+/* IEEE 802.11 (Ch. 9.5 Defragmentation) requires support for concurrent
+ * reception of at least three fragmented frames. This limit can be increased
+ * by changing this define, at the cost of slower frame reassembly and
+ * increased memory use (about 2 kB of RAM per entry). */
+#define IEEE80211_FRAGMENT_MAX 4
+
+struct ieee80211_fragment_entry {
+ unsigned long first_frag_time;
+ unsigned int seq;
+ unsigned int rx_queue;
+ unsigned int last_frag;
+ unsigned int extra_len;
+ struct sk_buff_head skb_list;
+ int ccmp; /* Whether fragments were encrypted with CCMP */
+ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
+};
+
+
+struct ieee80211_sta_bss {
+ struct list_head list;
+ struct ieee80211_sta_bss *hnext;
+ atomic_t users;
+
+ u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ size_t ssid_len;
+ u16 capability; /* host byte order */
+ int hw_mode;
+ int channel;
+ int freq;
+ int rssi, signal, noise;
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+ u8 *rsn_ie;
+ size_t rsn_ie_len;
+ u8 *wmm_ie;
+ size_t wmm_ie_len;
+#define IEEE80211_MAX_SUPP_RATES 32
+ u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+ size_t supp_rates_len;
+ int beacon_int;
+ u64 timestamp;
+
+ int probe_resp;
+ unsigned long last_update;
+
+};
+
+
+typedef enum {
+ TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED
+} ieee80211_txrx_result;
+
+struct ieee80211_txrx_data {
+ struct sk_buff *skb;
+ struct net_device *dev;
+ struct ieee80211_local *local;
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+ u16 fc, ethertype;
+ struct ieee80211_key *key;
+ unsigned int fragmented:1; /* whether the MSDU was fragmented */
+ union {
+ struct {
+ struct ieee80211_tx_control *control;
+ unsigned int unicast:1;
+ unsigned int ps_buffered:1;
+ unsigned int short_preamble:1;
+ unsigned int probe_last_frag:1;
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_rate *rate;
+ /* use this rate (if set) for last fragment; rate can
+ * be set to lower rate for the first fragments, e.g.,
+ * when using CTS protection with IEEE 802.11g. */
+ struct ieee80211_rate *last_frag_rate;
+ int last_frag_hwrate;
+ int mgmt_interface;
+
+ /* Extra fragments (in addition to the first fragment
+ * in skb) */
+ int num_extra_frag;
+ struct sk_buff **extra_frag;
+ } tx;
+ struct {
+ struct ieee80211_rx_status *status;
+ int sent_ps_buffered;
+ int queue;
+ int load;
+ unsigned int in_scan:1;
+ /* frame is destined to interface currently processed
+ * (including multicast frames) */
+ unsigned int ra_match:1;
+ } rx;
+ } u;
+};
+
+/* Stored in sk_buff->cb */
+struct ieee80211_tx_packet_data {
+ int ifindex;
+ unsigned long jiffies;
+ unsigned int req_tx_status:1;
+ unsigned int do_not_encrypt:1;
+ unsigned int requeue:1;
+ unsigned int mgmt_iface:1;
+ unsigned int queue:4;
+};
+
+struct ieee80211_tx_stored_packet {
+ struct ieee80211_tx_control control;
+ struct sk_buff *skb;
+ int num_extra_frag;
+ struct sk_buff **extra_frag;
+ int last_frag_rateidx;
+ int last_frag_hwrate;
+ struct ieee80211_rate *last_frag_rate;
+ unsigned int last_frag_rate_ctrl_probe:1;
+};
+
+typedef ieee80211_txrx_result (*ieee80211_tx_handler)
+(struct ieee80211_txrx_data *tx);
+
+typedef ieee80211_txrx_result (*ieee80211_rx_handler)
+(struct ieee80211_txrx_data *rx);
+
+struct ieee80211_if_ap {
+ u8 *beacon_head, *beacon_tail;
+ int beacon_head_len, beacon_tail_len;
+
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ size_t ssid_len;
+ u8 *generic_elem;
+ size_t generic_elem_len;
+
+ /* yes, this looks ugly, but guarantees that we can later use
+ * bitmap_empty :)
+ * NB: don't ever use set_bit, use bss_tim_set/bss_tim_clear! */
+ u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
+ atomic_t num_sta_ps; /* number of stations in PS mode */
+ struct sk_buff_head ps_bc_buf;
+ int dtim_period, dtim_count;
+ int force_unicast_rateidx; /* forced TX rateidx for unicast frames */
+ int max_ratectrl_rateidx; /* max TX rateidx for rate control */
+ int num_beacons; /* number of TXed beacon frames for this BSS */
+};
+
+struct ieee80211_if_wds {
+ u8 remote_addr[ETH_ALEN];
+ struct sta_info *sta;
+};
+
+struct ieee80211_if_vlan {
+ u8 id;
+};
+
+struct ieee80211_if_sta {
+ enum {
+ IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
+ IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
+ IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
+ } state;
+ struct timer_list timer;
+ struct work_struct work;
+ u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ size_t ssid_len;
+ u16 aid;
+ u16 ap_capab, capab;
+ u8 *extra_ie; /* to be added to the end of AssocReq */
+ size_t extra_ie_len;
+
+ /* The last AssocReq/Resp IEs */
+ u8 *assocreq_ies, *assocresp_ies;
+ size_t assocreq_ies_len, assocresp_ies_len;
+
+ int auth_tries, assoc_tries;
+
+ unsigned int ssid_set:1;
+ unsigned int bssid_set:1;
+ unsigned int prev_bssid_set:1;
+ unsigned int authenticated:1;
+ unsigned int associated:1;
+ unsigned int probereq_poll:1;
+ unsigned int use_protection:1;
+ unsigned int create_ibss:1;
+ unsigned int mixed_cell:1;
+ unsigned int wmm_enabled:1;
+ unsigned int auto_ssid_sel:1;
+ unsigned int auto_bssid_sel:1;
+ unsigned int auto_channel_sel:1;
+#define IEEE80211_STA_REQ_SCAN 0
+#define IEEE80211_STA_REQ_AUTH 1
+#define IEEE80211_STA_REQ_RUN 2
+ unsigned long request;
+ struct sk_buff_head skb_queue;
+
+ int key_mgmt;
+ unsigned long last_probe;
+
+#define IEEE80211_AUTH_ALG_OPEN BIT(0)
+#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
+#define IEEE80211_AUTH_ALG_LEAP BIT(2)
+ unsigned int auth_algs; /* bitfield of allowed auth algs */
+ int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
+ int auth_transaction;
+
+ unsigned long ibss_join_req;
+ struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
+ u32 supp_rates_bits;
+
+ int wmm_last_param_set;
+};
+
+
+struct ieee80211_sub_if_data {
+ struct list_head list;
+ unsigned int type;
+
+ struct wireless_dev wdev;
+
+ struct net_device *dev;
+ struct ieee80211_local *local;
+
+ int mc_count;
+ unsigned int allmulti:1;
+ unsigned int promisc:1;
+
+ struct net_device_stats stats;
+ int drop_unencrypted;
+ int eapol; /* 0 = process EAPOL frames as normal data frames,
+ * 1 = send EAPOL frames through wlan#ap to hostapd
+ * (default) */
+ int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
+ * port */
+
+ u16 sequence;
+
+ /* Fragment table for host-based reassembly */
+ struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
+ unsigned int fragment_next;
+
+#define NUM_DEFAULT_KEYS 4
+ struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
+ struct ieee80211_key *default_key;
+
+ struct ieee80211_if_ap *bss; /* BSS that this device belongs to */
+
+ union {
+ struct ieee80211_if_ap ap;
+ struct ieee80211_if_wds wds;
+ struct ieee80211_if_vlan vlan;
+ struct ieee80211_if_sta sta;
+ } u;
+ int channel_use;
+ int channel_use_raw;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *debugfsdir;
+ union {
+ struct {
+ struct dentry *channel_use;
+ struct dentry *drop_unencrypted;
+ struct dentry *eapol;
+ struct dentry *ieee8021_x;
+ struct dentry *state;
+ struct dentry *bssid;
+ struct dentry *prev_bssid;
+ struct dentry *ssid_len;
+ struct dentry *aid;
+ struct dentry *ap_capab;
+ struct dentry *capab;
+ struct dentry *extra_ie_len;
+ struct dentry *auth_tries;
+ struct dentry *assoc_tries;
+ struct dentry *auth_algs;
+ struct dentry *auth_alg;
+ struct dentry *auth_transaction;
+ struct dentry *flags;
+ } sta;
+ struct {
+ struct dentry *channel_use;
+ struct dentry *drop_unencrypted;
+ struct dentry *eapol;
+ struct dentry *ieee8021_x;
+ struct dentry *num_sta_ps;
+ struct dentry *dtim_period;
+ struct dentry *dtim_count;
+ struct dentry *num_beacons;
+ struct dentry *force_unicast_rateidx;
+ struct dentry *max_ratectrl_rateidx;
+ struct dentry *num_buffered_multicast;
+ struct dentry *beacon_head_len;
+ struct dentry *beacon_tail_len;
+ } ap;
+ struct {
+ struct dentry *channel_use;
+ struct dentry *drop_unencrypted;
+ struct dentry *eapol;
+ struct dentry *ieee8021_x;
+ struct dentry *peer;
+ } wds;
+ struct {
+ struct dentry *channel_use;
+ struct dentry *drop_unencrypted;
+ struct dentry *eapol;
+ struct dentry *ieee8021_x;
+ struct dentry *vlan_id;
+ } vlan;
+ struct {
+ struct dentry *mode;
+ } monitor;
+ struct dentry *default_key;
+ } debugfs;
+#endif
+};
+
+#define IEEE80211_DEV_TO_SUB_IF(dev) netdev_priv(dev)
+
+enum {
+ IEEE80211_RX_MSG = 1,
+ IEEE80211_TX_STATUS_MSG = 2,
+};
+
+struct ieee80211_local {
+ /* embed the driver visible part.
+ * don't cast (use the static inlines below), but we keep
+ * it first anyway so they become a no-op */
+ struct ieee80211_hw hw;
+
+ const struct ieee80211_ops *ops;
+
+ /* List of registered struct ieee80211_hw_mode */
+ struct list_head modes_list;
+
+ struct net_device *mdev; /* wmaster# - "master" 802.11 device */
+ struct net_device *apdev; /* wlan#ap - management frames (hostapd) */
+ int open_count;
+ int monitors;
+ struct iw_statistics wstats;
+ u8 wstats_flags;
+
+ enum {
+ IEEE80211_DEV_UNINITIALIZED = 0,
+ IEEE80211_DEV_REGISTERED,
+ IEEE80211_DEV_UNREGISTERED,
+ } reg_state;
+
+ /* Tasklet and skb queue to process calls from IRQ mode. All frames
+ * added to skb_queue will be processed, but frames in
+ * skb_queue_unreliable may be dropped if the total length of these
+ * queues increases over the limit. */
+#define IEEE80211_IRQSAFE_QUEUE_LIMIT 128
+ struct tasklet_struct tasklet;
+ struct sk_buff_head skb_queue;
+ struct sk_buff_head skb_queue_unreliable;
+
+ /* Station data structures */
+ spinlock_t sta_lock; /* mutex for STA data structures */
+ int num_sta; /* number of stations in sta_list */
+ struct list_head sta_list;
+ struct list_head deleted_sta_list;
+ struct sta_info *sta_hash[STA_HASH_SIZE];
+ struct timer_list sta_cleanup;
+
+ unsigned long state[NUM_TX_DATA_QUEUES];
+ struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES];
+ struct tasklet_struct tx_pending_tasklet;
+
+ int mc_count; /* total count of multicast entries in all interfaces */
+ int iff_allmultis, iff_promiscs;
+ /* number of interfaces with corresponding IFF_ flags */
+
+ struct rate_control_ref *rate_ctrl;
+
+ int next_mode; /* MODE_IEEE80211*
+ * The mode preference for next channel change. This is
+ * used to select .11g vs. .11b channels (or 4.9 GHz vs.
+ * .11a) when the channel number is not unique. */
+
+ /* Supported and basic rate filters for different modes. These are
+ * pointers to -1 terminated lists and rates in 100 kbps units. */
+ int *supp_rates[NUM_IEEE80211_MODES];
+ int *basic_rates[NUM_IEEE80211_MODES];
+
+ int rts_threshold;
+ int cts_protect_erp_frames;
+ int fragmentation_threshold;
+ int short_retry_limit; /* dot11ShortRetryLimit */
+ int long_retry_limit; /* dot11LongRetryLimit */
+ int short_preamble; /* use short preamble with IEEE 802.11b */
+
+ struct crypto_blkcipher *wep_tx_tfm;
+ struct crypto_blkcipher *wep_rx_tfm;
+ u32 wep_iv;
+ int key_tx_rx_threshold; /* number of times any key can be used in TX
+ * or RX before generating a rekey
+ * notification; 0 = notification disabled. */
+
+ int bridge_packets; /* bridge packets between associated stations and
+ * deliver multicast frames both back to wireless
+ * media and to the local net stack */
+
+ ieee80211_rx_handler *rx_pre_handlers;
+ ieee80211_rx_handler *rx_handlers;
+ ieee80211_tx_handler *tx_handlers;
+
+ rwlock_t sub_if_lock; /* Protects sub_if_list. Cannot be taken under
+ * sta_bss_lock or sta_lock. */
+ struct list_head sub_if_list;
+ int sta_scanning;
+ int scan_channel_idx;
+ enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
+ unsigned long last_scan_completed;
+ struct delayed_work scan_work;
+ struct net_device *scan_dev;
+ struct ieee80211_channel *oper_channel, *scan_channel;
+ struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode;
+ u8 scan_ssid[IEEE80211_MAX_SSID_LEN];
+ size_t scan_ssid_len;
+ struct list_head sta_bss_list;
+ struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
+ spinlock_t sta_bss_lock;
+#define IEEE80211_SCAN_MATCH_SSID BIT(0)
+#define IEEE80211_SCAN_WPA_ONLY BIT(1)
+#define IEEE80211_SCAN_EXTRA_INFO BIT(2)
+ int scan_flags;
+
+ /* SNMP counters */
+ /* dot11CountersTable */
+ u32 dot11TransmittedFragmentCount;
+ u32 dot11MulticastTransmittedFrameCount;
+ u32 dot11FailedCount;
+ u32 dot11RetryCount;
+ u32 dot11MultipleRetryCount;
+ u32 dot11FrameDuplicateCount;
+ u32 dot11ReceivedFragmentCount;
+ u32 dot11MulticastReceivedFrameCount;
+ u32 dot11TransmittedFrameCount;
+ u32 dot11WEPUndecryptableCount;
+
+#ifdef CONFIG_MAC80211_LEDS
+ int tx_led_counter, rx_led_counter;
+ struct led_trigger *tx_led, *rx_led;
+ char tx_led_name[32], rx_led_name[32];
+#endif
+
+ u32 channel_use;
+ u32 channel_use_raw;
+ u32 stat_time;
+ struct timer_list stat_timer;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct work_struct sta_debugfs_add;
+#endif
+
+ enum {
+ STA_ANTENNA_SEL_AUTO = 0,
+ STA_ANTENNA_SEL_SW_CTRL = 1,
+ STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2
+ } sta_antenna_sel;
+
+ int rate_ctrl_num_up, rate_ctrl_num_down;
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ /* TX/RX handler statistics */
+ unsigned int tx_handlers_drop;
+ unsigned int tx_handlers_queued;
+ unsigned int tx_handlers_drop_unencrypted;
+ unsigned int tx_handlers_drop_fragment;
+ unsigned int tx_handlers_drop_wep;
+ unsigned int tx_handlers_drop_not_assoc;
+ unsigned int tx_handlers_drop_unauth_port;
+ unsigned int rx_handlers_drop;
+ unsigned int rx_handlers_queued;
+ unsigned int rx_handlers_drop_nullfunc;
+ unsigned int rx_handlers_drop_defrag;
+ unsigned int rx_handlers_drop_short;
+ unsigned int rx_handlers_drop_passive_scan;
+ unsigned int tx_expand_skb_head;
+ unsigned int tx_expand_skb_head_cloned;
+ unsigned int rx_expand_skb_head;
+ unsigned int rx_expand_skb_head2;
+ unsigned int rx_handlers_fragments;
+ unsigned int tx_status_drop;
+ unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
+ unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
+#define I802_DEBUG_INC(c) (c)++
+#else /* CONFIG_MAC80211_DEBUG_COUNTERS */
+#define I802_DEBUG_INC(c) do { } while (0)
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+
+ int default_wep_only; /* only default WEP keys are used with this
+ * interface; this is used to decide when hwaccel
+ * can be used with default keys */
+ int total_ps_buffered; /* total number of all buffered unicast and
+ * multicast packets for power saving stations
+ */
+ int allow_broadcast_always; /* whether to allow TX of broadcast frames
+ * even when there are no associated STAs
+ */
+
+ int wifi_wme_noack_test;
+ unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
+
+ unsigned int enabled_modes; /* bitfield of allowed modes;
+ * (1 << MODE_*) */
+ unsigned int hw_modes; /* bitfield of supported hardware modes;
+ * (1 << MODE_*) */
+
+ int user_space_mlme;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct local_debugfsdentries {
+ struct dentry *channel;
+ struct dentry *frequency;
+ struct dentry *radar_detect;
+ struct dentry *antenna_sel_tx;
+ struct dentry *antenna_sel_rx;
+ struct dentry *bridge_packets;
+ struct dentry *key_tx_rx_threshold;
+ struct dentry *rts_threshold;
+ struct dentry *fragmentation_threshold;
+ struct dentry *short_retry_limit;
+ struct dentry *long_retry_limit;
+ struct dentry *total_ps_buffered;
+ struct dentry *mode;
+ struct dentry *wep_iv;
+ struct dentry *tx_power_reduction;
+ struct dentry *modes;
+ struct dentry *statistics;
+ struct local_debugfsdentries_statsdentries {
+ struct dentry *transmitted_fragment_count;
+ struct dentry *multicast_transmitted_frame_count;
+ struct dentry *failed_count;
+ struct dentry *retry_count;
+ struct dentry *multiple_retry_count;
+ struct dentry *frame_duplicate_count;
+ struct dentry *received_fragment_count;
+ struct dentry *multicast_received_frame_count;
+ struct dentry *transmitted_frame_count;
+ struct dentry *wep_undecryptable_count;
+ struct dentry *num_scans;
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ struct dentry *tx_handlers_drop;
+ struct dentry *tx_handlers_queued;
+ struct dentry *tx_handlers_drop_unencrypted;
+ struct dentry *tx_handlers_drop_fragment;
+ struct dentry *tx_handlers_drop_wep;
+ struct dentry *tx_handlers_drop_not_assoc;
+ struct dentry *tx_handlers_drop_unauth_port;
+ struct dentry *rx_handlers_drop;
+ struct dentry *rx_handlers_queued;
+ struct dentry *rx_handlers_drop_nullfunc;
+ struct dentry *rx_handlers_drop_defrag;
+ struct dentry *rx_handlers_drop_short;
+ struct dentry *rx_handlers_drop_passive_scan;
+ struct dentry *tx_expand_skb_head;
+ struct dentry *tx_expand_skb_head_cloned;
+ struct dentry *rx_expand_skb_head;
+ struct dentry *rx_expand_skb_head2;
+ struct dentry *rx_handlers_fragments;
+ struct dentry *tx_status_drop;
+ struct dentry *wme_tx_queue;
+ struct dentry *wme_rx_queue;
+#endif
+ struct dentry *dot11ACKFailureCount;
+ struct dentry *dot11RTSFailureCount;
+ struct dentry *dot11FCSErrorCount;
+ struct dentry *dot11RTSSuccessCount;
+ } stats;
+ struct dentry *stations;
+ struct dentry *keys;
+ } debugfs;
+#endif
+};
+
+static inline struct ieee80211_local *hw_to_local(
+ struct ieee80211_hw *hw)
+{
+ return container_of(hw, struct ieee80211_local, hw);
+}
+
+static inline struct ieee80211_hw *local_to_hw(
+ struct ieee80211_local *local)
+{
+ return &local->hw;
+}
+
+enum ieee80211_link_state_t {
+ IEEE80211_LINK_STATE_XOFF = 0,
+ IEEE80211_LINK_STATE_PENDING,
+};
+
+struct sta_attribute {
+ struct attribute attr;
+ ssize_t (*show)(const struct sta_info *, char *buf);
+ ssize_t (*store)(struct sta_info *, const char *buf, size_t count);
+};
+
+static inline void __bss_tim_set(struct ieee80211_if_ap *bss, int aid)
+{
+ /*
+ * This format has ben mandated by the IEEE specifications,
+ * so this line may not be changed to use the __set_bit() format.
+ */
+ bss->tim[(aid)/8] |= 1<<((aid) % 8);
+}
+
+static inline void bss_tim_set(struct ieee80211_local *local,
+ struct ieee80211_if_ap *bss, int aid)
+{
+ spin_lock_bh(&local->sta_lock);
+ __bss_tim_set(bss, aid);
+ spin_unlock_bh(&local->sta_lock);
+}
+
+static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, int aid)
+{
+ /*
+ * This format has ben mandated by the IEEE specifications,
+ * so this line may not be changed to use the __clear_bit() format.
+ */
+ bss->tim[(aid)/8] &= !(1<<((aid) % 8));
+}
+
+static inline void bss_tim_clear(struct ieee80211_local *local,
+ struct ieee80211_if_ap *bss, int aid)
+{
+ spin_lock_bh(&local->sta_lock);
+ __bss_tim_clear(bss, aid);
+ spin_unlock_bh(&local->sta_lock);
+}
+
+/**
+ * ieee80211_is_erp_rate - Check if a rate is an ERP rate
+ * @phymode: The PHY-mode for this rate (MODE_IEEE80211...)
+ * @rate: Transmission rate to check, in 100 kbps
+ *
+ * Check if a given rate is an Extended Rate PHY (ERP) rate.
+ */
+static inline int ieee80211_is_erp_rate(int phymode, int rate)
+{
+ if (phymode == MODE_IEEE80211G) {
+ if (rate != 10 && rate != 20 &&
+ rate != 55 && rate != 110)
+ return 1;
+ }
+ return 0;
+}
+
+/* ieee80211.c */
+int ieee80211_hw_config(struct ieee80211_local *local);
+int ieee80211_if_config(struct net_device *dev);
+int ieee80211_if_config_beacon(struct net_device *dev);
+struct ieee80211_key_conf *
+ieee80211_key_data2conf(struct ieee80211_local *local,
+ const struct ieee80211_key *data);
+struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
+ int idx, size_t key_len, gfp_t flags);
+void ieee80211_key_free(struct ieee80211_key *key);
+void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_rx_status *status, u32 msg_type);
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode);
+void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
+int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+void ieee80211_if_setup(struct net_device *dev);
+void ieee80211_if_mgmt_setup(struct net_device *dev);
+int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
+ const char *name);
+struct net_device_stats *ieee80211_dev_stats(struct net_device *dev);
+
+/* ieee80211_ioctl.c */
+extern const struct iw_handler_def ieee80211_iw_handler_def;
+
+void ieee80211_update_default_wep_only(struct ieee80211_local *local);
+
+
+/* Least common multiple of the used rates (in 100 kbps). This is used to
+ * calculate rate_inv values for each rate so that only integers are needed. */
+#define CHAN_UTIL_RATE_LCM 95040
+/* 1 usec is 1/8 * (95040/10) = 1188 */
+#define CHAN_UTIL_PER_USEC 1188
+/* Amount of bits to shift the result right to scale the total utilization
+ * to values that will not wrap around 32-bit integers. */
+#define CHAN_UTIL_SHIFT 9
+/* Theoretical maximum of channel utilization counter in 10 ms (stat_time=1):
+ * (CHAN_UTIL_PER_USEC * 10000) >> CHAN_UTIL_SHIFT = 23203. So dividing the
+ * raw value with about 23 should give utilization in 10th of a percentage
+ * (1/1000). However, utilization is only estimated and not all intervals
+ * between frames etc. are calculated. 18 seems to give numbers that are closer
+ * to the real maximum. */
+#define CHAN_UTIL_PER_10MS 18
+#define CHAN_UTIL_HDR_LONG (202 * CHAN_UTIL_PER_USEC)
+#define CHAN_UTIL_HDR_SHORT (40 * CHAN_UTIL_PER_USEC)
+
+
+/* ieee80211_ioctl.c */
+int ieee80211_set_compression(struct ieee80211_local *local,
+ struct net_device *dev, struct sta_info *sta);
+int ieee80211_init_client(struct net_device *dev);
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
+/* ieee80211_sta.c */
+void ieee80211_sta_timer(unsigned long data);
+void ieee80211_sta_work(struct work_struct *work);
+void ieee80211_sta_scan_work(struct work_struct *work);
+void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status);
+int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len);
+int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len);
+int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid);
+int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len);
+void ieee80211_sta_req_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta);
+int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len);
+void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status);
+void ieee80211_rx_bss_list_init(struct net_device *dev);
+void ieee80211_rx_bss_list_deinit(struct net_device *dev);
+int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len);
+struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr);
+int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason);
+int ieee80211_sta_disassociate(struct net_device *dev, u16 reason);
+
+/* ieee80211_iface.c */
+int ieee80211_if_add(struct net_device *dev, const char *name,
+ struct net_device **new_dev, int type);
+void ieee80211_if_set_type(struct net_device *dev, int type);
+void ieee80211_if_reinit(struct net_device *dev);
+void __ieee80211_if_del(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata);
+int ieee80211_if_remove(struct net_device *dev, const char *name, int id);
+void ieee80211_if_free(struct net_device *dev);
+void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
+int ieee80211_if_add_mgmt(struct ieee80211_local *local);
+void ieee80211_if_del_mgmt(struct ieee80211_local *local);
+
+/* for wiphy privid */
+extern void *mac80211_wiphy_privid;
+
+#endif /* IEEE80211_I_H */
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
new file mode 100644
index 00000000000..cf0f32e8c2a
--- /dev/null
+++ b/net/mac80211/ieee80211_iface.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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/kernel.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+#include "debugfs_netdev.h"
+
+void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
+{
+ int i;
+
+ /* Default values for sub-interface parameters */
+ sdata->drop_unencrypted = 0;
+ sdata->eapol = 1;
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+ skb_queue_head_init(&sdata->fragments[i].skb_list);
+}
+
+static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
+{
+ int i;
+
+ for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+ __skb_queue_purge(&sdata->fragments[i].skb_list);
+ }
+}
+
+/* Must be called with rtnl lock held. */
+int ieee80211_if_add(struct net_device *dev, const char *name,
+ struct net_device **new_dev, int type)
+{
+ struct net_device *ndev;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = NULL;
+ int ret;
+
+ ASSERT_RTNL();
+ ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
+ name, ieee80211_if_setup);
+ if (!ndev)
+ return -ENOMEM;
+
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0)
+ goto fail;
+
+ memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ ndev->base_addr = dev->base_addr;
+ ndev->irq = dev->irq;
+ ndev->mem_start = dev->mem_start;
+ ndev->mem_end = dev->mem_end;
+ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ ndev->ieee80211_ptr = &sdata->wdev;
+ sdata->wdev.wiphy = local->hw.wiphy;
+ sdata->type = IEEE80211_IF_TYPE_AP;
+ sdata->dev = ndev;
+ sdata->local = local;
+ ieee80211_if_sdata_init(sdata);
+
+ ret = register_netdevice(ndev);
+ if (ret)
+ goto fail;
+
+ ieee80211_debugfs_add_netdev(sdata);
+ ieee80211_if_set_type(ndev, type);
+
+ write_lock_bh(&local->sub_if_lock);
+ if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
+ write_unlock_bh(&local->sub_if_lock);
+ __ieee80211_if_del(local, sdata);
+ return -ENODEV;
+ }
+ list_add(&sdata->list, &local->sub_if_list);
+ if (new_dev)
+ *new_dev = ndev;
+ write_unlock_bh(&local->sub_if_lock);
+
+ ieee80211_update_default_wep_only(local);
+
+ return 0;
+
+fail:
+ free_netdev(ndev);
+ return ret;
+}
+
+int ieee80211_if_add_mgmt(struct ieee80211_local *local)
+{
+ struct net_device *ndev;
+ struct ieee80211_sub_if_data *nsdata;
+ int ret;
+
+ ASSERT_RTNL();
+
+ ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
+ ieee80211_if_mgmt_setup);
+ if (!ndev)
+ return -ENOMEM;
+ ret = dev_alloc_name(ndev, ndev->name);
+ if (ret < 0)
+ goto fail;
+
+ memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
+ SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+
+ nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+ ndev->ieee80211_ptr = &nsdata->wdev;
+ nsdata->wdev.wiphy = local->hw.wiphy;
+ nsdata->type = IEEE80211_IF_TYPE_MGMT;
+ nsdata->dev = ndev;
+ nsdata->local = local;
+ ieee80211_if_sdata_init(nsdata);
+
+ ret = register_netdevice(ndev);
+ if (ret)
+ goto fail;
+
+ ieee80211_debugfs_add_netdev(nsdata);
+
+ if (local->open_count > 0)
+ dev_open(ndev);
+ local->apdev = ndev;
+ return 0;
+
+fail:
+ free_netdev(ndev);
+ return ret;
+}
+
+void ieee80211_if_del_mgmt(struct ieee80211_local *local)
+{
+ struct net_device *apdev;
+
+ ASSERT_RTNL();
+ apdev = local->apdev;
+ ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
+ local->apdev = NULL;
+ unregister_netdevice(apdev);
+}
+
+void ieee80211_if_set_type(struct net_device *dev, int type)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ int oldtype = sdata->type;
+
+ sdata->type = type;
+ switch (type) {
+ case IEEE80211_IF_TYPE_WDS:
+ sdata->bss = NULL;
+ break;
+ case IEEE80211_IF_TYPE_VLAN:
+ break;
+ case IEEE80211_IF_TYPE_AP:
+ sdata->u.ap.dtim_period = 2;
+ sdata->u.ap.force_unicast_rateidx = -1;
+ sdata->u.ap.max_ratectrl_rateidx = -1;
+ skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
+ sdata->bss = &sdata->u.ap;
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS: {
+ struct ieee80211_sub_if_data *msdata;
+ struct ieee80211_if_sta *ifsta;
+
+ ifsta = &sdata->u.sta;
+ INIT_WORK(&ifsta->work, ieee80211_sta_work);
+ setup_timer(&ifsta->timer, ieee80211_sta_timer,
+ (unsigned long) sdata);
+ skb_queue_head_init(&ifsta->skb_queue);
+
+ ifsta->capab = WLAN_CAPABILITY_ESS;
+ ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+ IEEE80211_AUTH_ALG_SHARED_KEY;
+ ifsta->create_ibss = 1;
+ ifsta->wmm_enabled = 1;
+ ifsta->auto_channel_sel = 1;
+ ifsta->auto_bssid_sel = 1;
+
+ msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
+ sdata->bss = &msdata->u.ap;
+ break;
+ }
+ case IEEE80211_IF_TYPE_MNTR:
+ dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ break;
+ default:
+ printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
+ dev->name, __FUNCTION__, type);
+ }
+ ieee80211_debugfs_change_if_type(sdata, oldtype);
+ ieee80211_update_default_wep_only(local);
+}
+
+/* Must be called with rtnl lock held. */
+void ieee80211_if_reinit(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta;
+ int i;
+
+ ASSERT_RTNL();
+ ieee80211_if_sdata_deinit(sdata);
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (!sdata->keys[i])
+ continue;
+#if 0
+ /* The interface is down at the moment, so there is not
+ * really much point in disabling the keys at this point. */
+ memset(addr, 0xff, ETH_ALEN);
+ if (local->ops->set_key)
+ local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
+ local->keys[i], 0);
+#endif
+ ieee80211_key_free(sdata->keys[i]);
+ sdata->keys[i] = NULL;
+ }
+
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_AP: {
+ /* Remove all virtual interfaces that use this BSS
+ * as their sdata->bss */
+ struct ieee80211_sub_if_data *tsdata, *n;
+ LIST_HEAD(tmp_list);
+
+ write_lock_bh(&local->sub_if_lock);
+ list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) {
+ if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
+ printk(KERN_DEBUG "%s: removing virtual "
+ "interface %s because its BSS interface"
+ " is being removed\n",
+ sdata->dev->name, tsdata->dev->name);
+ list_move_tail(&tsdata->list, &tmp_list);
+ }
+ }
+ write_unlock_bh(&local->sub_if_lock);
+
+ list_for_each_entry_safe(tsdata, n, &tmp_list, list)
+ __ieee80211_if_del(local, tsdata);
+
+ kfree(sdata->u.ap.beacon_head);
+ kfree(sdata->u.ap.beacon_tail);
+ kfree(sdata->u.ap.generic_elem);
+
+ if (dev != local->mdev) {
+ struct sk_buff *skb;
+ while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+ local->total_ps_buffered--;
+ dev_kfree_skb(skb);
+ }
+ }
+
+ break;
+ }
+ case IEEE80211_IF_TYPE_WDS:
+ sta = sta_info_get(local, sdata->u.wds.remote_addr);
+ if (sta) {
+ sta_info_put(sta);
+ sta_info_free(sta, 0);
+ } else {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Someone had deleted my STA "
+ "entry for the WDS link\n", dev->name);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ }
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ case IEEE80211_IF_TYPE_IBSS:
+ kfree(sdata->u.sta.extra_ie);
+ sdata->u.sta.extra_ie = NULL;
+ kfree(sdata->u.sta.assocreq_ies);
+ sdata->u.sta.assocreq_ies = NULL;
+ kfree(sdata->u.sta.assocresp_ies);
+ sdata->u.sta.assocresp_ies = NULL;
+ if (sdata->u.sta.probe_resp) {
+ dev_kfree_skb(sdata->u.sta.probe_resp);
+ sdata->u.sta.probe_resp = NULL;
+ }
+
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ dev->type = ARPHRD_ETHER;
+ break;
+ }
+
+ /* remove all STAs that are bound to this virtual interface */
+ sta_info_flush(local, dev);
+
+ memset(&sdata->u, 0, sizeof(sdata->u));
+ ieee80211_if_sdata_init(sdata);
+}
+
+/* Must be called with rtnl lock held. */
+void __ieee80211_if_del(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct net_device *dev = sdata->dev;
+
+ ieee80211_debugfs_remove_netdev(sdata);
+ unregister_netdevice(dev);
+ /* Except master interface, the net_device will be freed by
+ * net_device->destructor (i. e. ieee80211_if_free). */
+}
+
+/* Must be called with rtnl lock held. */
+int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata, *n;
+
+ ASSERT_RTNL();
+
+ write_lock_bh(&local->sub_if_lock);
+ list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
+ if ((sdata->type == id || id == -1) &&
+ strcmp(name, sdata->dev->name) == 0 &&
+ sdata->dev != local->mdev) {
+ list_del(&sdata->list);
+ write_unlock_bh(&local->sub_if_lock);
+ __ieee80211_if_del(local, sdata);
+ ieee80211_update_default_wep_only(local);
+ return 0;
+ }
+ }
+ write_unlock_bh(&local->sub_if_lock);
+ return -ENODEV;
+}
+
+void ieee80211_if_free(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ /* local->apdev must be NULL when freeing management interface */
+ BUG_ON(dev == local->apdev);
+ ieee80211_if_sdata_deinit(sdata);
+ free_netdev(dev);
+}
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
new file mode 100644
index 00000000000..352f03bd8a3
--- /dev/null
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <asm/uaccess.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "hostapd_ioctl.h"
+#include "ieee80211_rate.h"
+#include "wpa.h"
+#include "aes_ccm.h"
+#include "debugfs_key.h"
+
+static int ieee80211_regdom = 0x10; /* FCC */
+module_param(ieee80211_regdom, int, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
+
+/*
+ * If firmware is upgraded by the vendor, additional channels can be used based
+ * on the new Japanese regulatory rules. This is indicated by setting
+ * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
+ * module.
+ */
+static int ieee80211_japan_5ghz /* = 0 */;
+module_param(ieee80211_japan_5ghz, int, 0444);
+MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
+
+static void ieee80211_set_hw_encryption(struct net_device *dev,
+ struct sta_info *sta, u8 addr[ETH_ALEN],
+ struct ieee80211_key *key)
+{
+ struct ieee80211_key_conf *keyconf = NULL;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ /* default to sw encryption; this will be cleared by low-level
+ * driver if the hw supports requested encryption */
+ if (key)
+ key->force_sw_encrypt = 1;
+
+ if (key && local->ops->set_key &&
+ (keyconf = ieee80211_key_data2conf(local, key))) {
+ if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
+ keyconf, sta ? sta->aid : 0)) {
+ key->force_sw_encrypt = 1;
+ key->hw_key_idx = HW_KEY_IDX_INVALID;
+ } else {
+ key->force_sw_encrypt =
+ !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
+ key->hw_key_idx =
+ keyconf->hw_key_idx;
+
+ }
+ }
+ kfree(keyconf);
+}
+
+
+static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
+ int idx, int alg, int set_tx_key,
+ const u8 *_key, size_t key_len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ int ret = 0;
+ struct sta_info *sta;
+ struct ieee80211_key *key, *old_key;
+ int try_hwaccel = 1;
+ struct ieee80211_key_conf *keyconf;
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (is_broadcast_ether_addr(sta_addr)) {
+ sta = NULL;
+ if (idx >= NUM_DEFAULT_KEYS) {
+ printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
+ dev->name, idx);
+ return -EINVAL;
+ }
+ key = sdata->keys[idx];
+
+ /* TODO: consider adding hwaccel support for these; at least
+ * Atheros key cache should be able to handle this since AP is
+ * only transmitting frames with default keys. */
+ /* FIX: hw key cache can be used when only one virtual
+ * STA is associated with each AP. If more than one STA
+ * is associated to the same AP, software encryption
+ * must be used. This should be done automatically
+ * based on configured station devices. For the time
+ * being, this can be only set at compile time. */
+ } else {
+ set_tx_key = 0;
+ if (idx != 0) {
+ printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
+ "individual key\n", dev->name);
+ return -EINVAL;
+ }
+
+ sta = sta_info_get(local, sta_addr);
+ if (!sta) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
+ MAC_FMT "\n",
+ dev->name, MAC_ARG(sta_addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+ return -ENOENT;
+ }
+
+ key = sta->key;
+ }
+
+ /* FIX:
+ * Cannot configure default hwaccel keys with WEP algorithm, if
+ * any of the virtual interfaces is using static WEP
+ * configuration because hwaccel would otherwise try to decrypt
+ * these frames.
+ *
+ * For now, just disable WEP hwaccel for broadcast when there is
+ * possibility of conflict with default keys. This can maybe later be
+ * optimized by using non-default keys (at least with Atheros ar521x).
+ */
+ if (!sta && alg == ALG_WEP && !local->default_wep_only &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS &&
+ sdata->type != IEEE80211_IF_TYPE_AP) {
+ try_hwaccel = 0;
+ }
+
+ if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) {
+ /* Software encryption cannot be used with devices that hide
+ * encryption from the host system, so always try to use
+ * hardware acceleration with such devices. */
+ try_hwaccel = 1;
+ }
+
+ if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) &&
+ alg == ALG_TKIP) {
+ if (sta && (sta->flags & WLAN_STA_WME)) {
+ /* Hardware does not support hwaccel with TKIP when using WMM.
+ */
+ try_hwaccel = 0;
+ }
+ else if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ sta = sta_info_get(local, sdata->u.sta.bssid);
+ if (sta) {
+ if (sta->flags & WLAN_STA_WME) {
+ try_hwaccel = 0;
+ }
+ sta_info_put(sta);
+ sta = NULL;
+ }
+ }
+ }
+
+ if (alg == ALG_NONE) {
+ keyconf = NULL;
+ if (try_hwaccel && key &&
+ key->hw_key_idx != HW_KEY_IDX_INVALID &&
+ local->ops->set_key &&
+ (keyconf = ieee80211_key_data2conf(local, key)) != NULL &&
+ local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+ sta_addr, keyconf, sta ? sta->aid : 0)) {
+ printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
+ " failed\n", dev->name);
+ ret = -EINVAL;
+ }
+ kfree(keyconf);
+
+ if (set_tx_key || sdata->default_key == key) {
+ ieee80211_debugfs_key_remove_default(sdata);
+ sdata->default_key = NULL;
+ }
+ ieee80211_debugfs_key_remove(key);
+ if (sta)
+ sta->key = NULL;
+ else
+ sdata->keys[idx] = NULL;
+ ieee80211_key_free(key);
+ key = NULL;
+ } else {
+ old_key = key;
+ key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len,
+ GFP_KERNEL);
+ if (!key) {
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ /* default to sw encryption; low-level driver sets these if the
+ * requested encryption is supported */
+ key->hw_key_idx = HW_KEY_IDX_INVALID;
+ key->force_sw_encrypt = 1;
+
+ key->alg = alg;
+ key->keyidx = idx;
+ key->keylen = key_len;
+ memcpy(key->key, _key, key_len);
+ if (set_tx_key)
+ key->default_tx_key = 1;
+
+ if (alg == ALG_CCMP) {
+ /* Initialize AES key state here as an optimization
+ * so that it does not need to be initialized for every
+ * packet. */
+ key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
+ key->key);
+ if (!key->u.ccmp.tfm) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+ }
+
+ if (set_tx_key || sdata->default_key == old_key) {
+ ieee80211_debugfs_key_remove_default(sdata);
+ sdata->default_key = NULL;
+ }
+ ieee80211_debugfs_key_remove(old_key);
+ if (sta)
+ sta->key = key;
+ else
+ sdata->keys[idx] = key;
+ ieee80211_key_free(old_key);
+ ieee80211_debugfs_key_add(local, key);
+ if (sta)
+ ieee80211_debugfs_key_sta_link(key, sta);
+
+ if (try_hwaccel &&
+ (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP))
+ ieee80211_set_hw_encryption(dev, sta, sta_addr, key);
+ }
+
+ if (set_tx_key || (!sta && !sdata->default_key && key)) {
+ sdata->default_key = key;
+ if (key)
+ ieee80211_debugfs_key_add_default(sdata);
+
+ if (local->ops->set_key_idx &&
+ local->ops->set_key_idx(local_to_hw(local), idx))
+ printk(KERN_DEBUG "%s: failed to set TX key idx for "
+ "low-level driver\n", dev->name);
+ }
+
+ if (sta)
+ sta_info_put(sta);
+
+ return 0;
+
+err_free:
+ ieee80211_key_free(key);
+err_out:
+ if (sta)
+ sta_info_put(sta);
+ return ret;
+}
+
+static int ieee80211_ioctl_siwgenie(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (local->user_space_mlme)
+ return -EOPNOTSUPP;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
+ if (ret)
+ return ret;
+ sdata->u.sta.auto_bssid_sel = 0;
+ ieee80211_sta_req_auth(dev, &sdata->u.sta);
+ return 0;
+ }
+
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ kfree(sdata->u.ap.generic_elem);
+ sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL);
+ if (!sdata->u.ap.generic_elem)
+ return -ENOMEM;
+ memcpy(sdata->u.ap.generic_elem, extra, data->length);
+ sdata->u.ap.generic_elem_len = data->length;
+ return ieee80211_if_config(dev);
+ }
+ return -EOPNOTSUPP;
+}
+
+static int ieee80211_ioctl_set_radio_enabled(struct net_device *dev,
+ int val)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_conf *conf = &local->hw.conf;
+
+ conf->radio_enabled = val;
+ return ieee80211_hw_config(wdev_priv(dev->ieee80211_ptr));
+}
+
+static int ieee80211_ioctl_giwname(struct net_device *dev,
+ struct iw_request_info *info,
+ char *name, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ switch (local->hw.conf.phymode) {
+ case MODE_IEEE80211A:
+ strcpy(name, "IEEE 802.11a");
+ break;
+ case MODE_IEEE80211B:
+ strcpy(name, "IEEE 802.11b");
+ break;
+ case MODE_IEEE80211G:
+ strcpy(name, "IEEE 802.11g");
+ break;
+ case MODE_ATHEROS_TURBO:
+ strcpy(name, "5GHz Turbo");
+ break;
+ default:
+ strcpy(name, "IEEE 802.11");
+ break;
+ }
+
+ return 0;
+}
+
+
+static int ieee80211_ioctl_giwrange(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iw_range *range = (struct iw_range *) extra;
+
+ data->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 21;
+ range->retry_capa = IW_RETRY_LIMIT;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->min_retry = 0;
+ range->max_retry = 255;
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = 13;
+ range->num_encoding_sizes = 2;
+ range->max_encoding_tokens = NUM_DEFAULT_KEYS;
+
+ range->max_qual.qual = local->hw.max_signal;
+ range->max_qual.level = local->hw.max_rssi;
+ range->max_qual.noise = local->hw.max_noise;
+ range->max_qual.updated = local->wstats_flags;
+
+ range->avg_qual.qual = local->hw.max_signal/2;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = local->wstats_flags;
+
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+ IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+
+ return 0;
+}
+
+
+struct ieee80211_channel_range {
+ short start_freq;
+ short end_freq;
+ unsigned char power_level;
+ unsigned char antenna_max;
+};
+
+static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
+ { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
+ { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
+ { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
+ { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
+ { 0 }
+};
+
+static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
+ { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
+ { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
+ { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
+ { 0 }
+};
+
+
+static const struct ieee80211_channel_range *channel_range =
+ ieee80211_fcc_channels;
+
+
+static void ieee80211_unmask_channel(struct net_device *dev, int mode,
+ struct ieee80211_channel *chan)
+{
+ int i;
+
+ chan->flag = 0;
+
+ if (ieee80211_regdom == 64 &&
+ (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
+ /* Do not allow Turbo modes in Japan. */
+ return;
+ }
+
+ for (i = 0; channel_range[i].start_freq; i++) {
+ const struct ieee80211_channel_range *r = &channel_range[i];
+ if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
+ if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
+ chan->freq >= 5260 && chan->freq <= 5320) {
+ /*
+ * Skip new channels in Japan since the
+ * firmware was not marked having been upgraded
+ * by the vendor.
+ */
+ continue;
+ }
+
+ if (ieee80211_regdom == 0x10 &&
+ (chan->freq == 5190 || chan->freq == 5210 ||
+ chan->freq == 5230)) {
+ /* Skip MKK channels when in FCC domain. */
+ continue;
+ }
+
+ chan->flag |= IEEE80211_CHAN_W_SCAN |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_IBSS;
+ chan->power_level = r->power_level;
+ chan->antenna_max = r->antenna_max;
+
+ if (ieee80211_regdom == 64 &&
+ (chan->freq == 5170 || chan->freq == 5190 ||
+ chan->freq == 5210 || chan->freq == 5230)) {
+ /*
+ * New regulatory rules in Japan have backwards
+ * compatibility with old channels in 5.15-5.25
+ * GHz band, but the station is not allowed to
+ * use active scan on these old channels.
+ */
+ chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
+ }
+
+ if (ieee80211_regdom == 64 &&
+ (chan->freq == 5260 || chan->freq == 5280 ||
+ chan->freq == 5300 || chan->freq == 5320)) {
+ /*
+ * IBSS is not allowed on 5.25-5.35 GHz band
+ * due to radar detection requirements.
+ */
+ chan->flag &= ~IEEE80211_CHAN_W_IBSS;
+ }
+
+ break;
+ }
+ }
+}
+
+
+static int ieee80211_unmask_channels(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ int c;
+
+ list_for_each_entry(mode, &local->modes_list, list) {
+ for (c = 0; c < mode->num_channels; c++) {
+ ieee80211_unmask_channel(dev, mode->mode,
+ &mode->channels[c]);
+ }
+ }
+ return 0;
+}
+
+
+int ieee80211_init_client(struct net_device *dev)
+{
+ if (ieee80211_regdom == 0x40)
+ channel_range = ieee80211_mkk_channels;
+ ieee80211_unmask_channels(dev);
+ return 0;
+}
+
+
+static int ieee80211_ioctl_siwmode(struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int type;
+
+ if (sdata->type == IEEE80211_IF_TYPE_VLAN)
+ return -EOPNOTSUPP;
+
+ switch (*mode) {
+ case IW_MODE_INFRA:
+ type = IEEE80211_IF_TYPE_STA;
+ break;
+ case IW_MODE_ADHOC:
+ type = IEEE80211_IF_TYPE_IBSS;
+ break;
+ case IW_MODE_MONITOR:
+ type = IEEE80211_IF_TYPE_MNTR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (type == sdata->type)
+ return 0;
+ if (netif_running(dev))
+ return -EBUSY;
+
+ ieee80211_if_reinit(dev);
+ ieee80211_if_set_type(dev, type);
+
+ return 0;
+}
+
+
+static int ieee80211_ioctl_giwmode(struct net_device *dev,
+ struct iw_request_info *info,
+ __u32 *mode, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ switch (sdata->type) {
+ case IEEE80211_IF_TYPE_AP:
+ *mode = IW_MODE_MASTER;
+ break;
+ case IEEE80211_IF_TYPE_STA:
+ *mode = IW_MODE_INFRA;
+ break;
+ case IEEE80211_IF_TYPE_IBSS:
+ *mode = IW_MODE_ADHOC;
+ break;
+ case IEEE80211_IF_TYPE_MNTR:
+ *mode = IW_MODE_MONITOR;
+ break;
+ case IEEE80211_IF_TYPE_WDS:
+ *mode = IW_MODE_REPEAT;
+ break;
+ case IEEE80211_IF_TYPE_VLAN:
+ *mode = IW_MODE_SECOND; /* FIXME */
+ break;
+ default:
+ *mode = IW_MODE_AUTO;
+ break;
+ }
+ return 0;
+}
+
+int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
+{
+ struct ieee80211_hw_mode *mode;
+ int c, set = 0;
+ int ret = -EINVAL;
+
+ list_for_each_entry(mode, &local->modes_list, list) {
+ if (!(local->enabled_modes & (1 << mode->mode)))
+ continue;
+ for (c = 0; c < mode->num_channels; c++) {
+ struct ieee80211_channel *chan = &mode->channels[c];
+ if (chan->flag & IEEE80211_CHAN_W_SCAN &&
+ ((chan->chan == channel) || (chan->freq == freq))) {
+ /* Use next_mode as the mode preference to
+ * resolve non-unique channel numbers. */
+ if (set && mode->mode != local->next_mode)
+ continue;
+
+ local->oper_channel = chan;
+ local->oper_hw_mode = mode;
+ set++;
+ }
+ }
+ }
+
+ if (set) {
+ if (local->sta_scanning)
+ ret = 0;
+ else
+ ret = ieee80211_hw_config(local);
+
+ rate_control_clear(local);
+ }
+
+ return ret;
+}
+
+static int ieee80211_ioctl_siwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA)
+ sdata->u.sta.auto_channel_sel = 0;
+
+ /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
+ if (freq->e == 0) {
+ if (freq->m < 0) {
+ if (sdata->type == IEEE80211_IF_TYPE_STA)
+ sdata->u.sta.auto_channel_sel = 1;
+ return 0;
+ } else
+ return ieee80211_set_channel(local, freq->m, -1);
+ } else {
+ int i, div = 1000000;
+ for (i = 0; i < freq->e; i++)
+ div /= 10;
+ if (div > 0)
+ return ieee80211_set_channel(local, -1, freq->m / div);
+ else
+ return -EINVAL;
+ }
+}
+
+
+static int ieee80211_ioctl_giwfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *freq, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
+ * driver for the current channel with firmware-based management */
+
+ freq->m = local->hw.conf.freq;
+ freq->e = 6;
+
+ return 0;
+}
+
+
+static int ieee80211_ioctl_siwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ size_t len = data->length;
+
+ /* iwconfig uses nul termination in SSID.. */
+ if (len > 0 && ssid[len - 1] == '\0')
+ len--;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ int ret;
+ if (local->user_space_mlme) {
+ if (len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+ memcpy(sdata->u.sta.ssid, ssid, len);
+ sdata->u.sta.ssid_len = len;
+ return 0;
+ }
+ sdata->u.sta.auto_ssid_sel = !data->flags;
+ ret = ieee80211_sta_set_ssid(dev, ssid, len);
+ if (ret)
+ return ret;
+ ieee80211_sta_req_auth(dev, &sdata->u.sta);
+ return 0;
+ }
+
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ memcpy(sdata->u.ap.ssid, ssid, len);
+ memset(sdata->u.ap.ssid + len, 0,
+ IEEE80211_MAX_SSID_LEN - len);
+ sdata->u.ap.ssid_len = len;
+ return ieee80211_if_config(dev);
+ }
+ return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_giwessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *ssid)
+{
+ size_t len;
+
+ struct ieee80211_sub_if_data *sdata;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ int res = ieee80211_sta_get_ssid(dev, ssid, &len);
+ if (res == 0) {
+ data->length = len;
+ data->flags = 1;
+ } else
+ data->flags = 0;
+ return res;
+ }
+
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ len = sdata->u.ap.ssid_len;
+ if (len > IW_ESSID_MAX_SIZE)
+ len = IW_ESSID_MAX_SIZE;
+ memcpy(ssid, sdata->u.ap.ssid, len);
+ data->length = len;
+ data->flags = 1;
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_siwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ int ret;
+ if (local->user_space_mlme) {
+ memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
+ ETH_ALEN);
+ return 0;
+ }
+ if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) {
+ sdata->u.sta.auto_bssid_sel = 1;
+ sdata->u.sta.auto_channel_sel = 1;
+ } else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+ sdata->u.sta.auto_bssid_sel = 1;
+ else
+ sdata->u.sta.auto_bssid_sel = 0;
+ ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
+ if (ret)
+ return ret;
+ ieee80211_sta_req_auth(dev, &sdata->u.sta);
+ return 0;
+ } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+ if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
+ ETH_ALEN) == 0)
+ return 0;
+ return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
+ }
+
+ return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_giwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ ap_addr->sa_family = ARPHRD_ETHER;
+ memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
+ return 0;
+ } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
+ ap_addr->sa_family = ARPHRD_ETHER;
+ memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+
+static int ieee80211_ioctl_siwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ u8 *ssid = NULL;
+ size_t ssid_len = 0;
+
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
+ if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ ssid = sdata->u.sta.ssid;
+ ssid_len = sdata->u.sta.ssid_len;
+ } else if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ ssid = sdata->u.ap.ssid;
+ ssid_len = sdata->u.ap.ssid_len;
+ } else
+ return -EINVAL;
+ }
+ return ieee80211_sta_req_scan(dev, ssid, ssid_len);
+}
+
+
+static int ieee80211_ioctl_giwscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ int res;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ if (local->sta_scanning)
+ return -EAGAIN;
+ res = ieee80211_sta_scan_results(dev, extra, data->length);
+ if (res >= 0) {
+ data->length = res;
+ return 0;
+ }
+ data->length = 0;
+ return res;
+}
+
+
+static int ieee80211_ioctl_siwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (rts->disabled)
+ local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
+ else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
+ return -EINVAL;
+ else
+ local->rts_threshold = rts->value;
+
+ /* If the wlan card performs RTS/CTS in hardware/firmware,
+ * configure it here */
+
+ if (local->ops->set_rts_threshold)
+ local->ops->set_rts_threshold(local_to_hw(local),
+ local->rts_threshold);
+
+ return 0;
+}
+
+static int ieee80211_ioctl_giwrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rts, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ rts->value = local->rts_threshold;
+ rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
+ rts->fixed = 1;
+
+ return 0;
+}
+
+
+static int ieee80211_ioctl_siwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (frag->disabled)
+ local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
+ else if (frag->value < 256 ||
+ frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
+ return -EINVAL;
+ else {
+ /* Fragment length must be even, so strip LSB. */
+ local->fragmentation_threshold = frag->value & ~0x1;
+ }
+
+ /* If the wlan card performs fragmentation in hardware/firmware,
+ * configure it here */
+
+ if (local->ops->set_frag_threshold)
+ local->ops->set_frag_threshold(
+ local_to_hw(local),
+ local->fragmentation_threshold);
+
+ return 0;
+}
+
+static int ieee80211_ioctl_giwfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frag, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ frag->value = local->fragmentation_threshold;
+ frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
+ frag->fixed = 1;
+
+ return 0;
+}
+
+
+static int ieee80211_ioctl_siwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (retry->disabled ||
+ (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
+ return -EINVAL;
+
+ if (retry->flags & IW_RETRY_MAX)
+ local->long_retry_limit = retry->value;
+ else if (retry->flags & IW_RETRY_MIN)
+ local->short_retry_limit = retry->value;
+ else {
+ local->long_retry_limit = retry->value;
+ local->short_retry_limit = retry->value;
+ }
+
+ if (local->ops->set_retry_limit) {
+ return local->ops->set_retry_limit(
+ local_to_hw(local),
+ local->short_retry_limit,
+ local->long_retry_limit);
+ }
+
+ return 0;
+}
+
+
+static int ieee80211_ioctl_giwretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *retry, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ retry->disabled = 0;
+ if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
+ /* first return min value, iwconfig will ask max value
+ * later if needed */
+ retry->flags |= IW_RETRY_LIMIT;
+ retry->value = local->short_retry_limit;
+ if (local->long_retry_limit != local->short_retry_limit)
+ retry->flags |= IW_RETRY_MIN;
+ return 0;
+ }
+ if (retry->flags & IW_RETRY_MAX) {
+ retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ retry->value = local->long_retry_limit;
+ }
+
+ return 0;
+}
+
+static int ieee80211_ioctl_clear_keys(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_key_conf key;
+ int i;
+ u8 addr[ETH_ALEN];
+ struct ieee80211_key_conf *keyconf;
+ struct ieee80211_sub_if_data *sdata;
+ struct sta_info *sta;
+
+ memset(addr, 0xff, ETH_ALEN);
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ keyconf = NULL;
+ if (sdata->keys[i] &&
+ !sdata->keys[i]->force_sw_encrypt &&
+ local->ops->set_key &&
+ (keyconf = ieee80211_key_data2conf(local,
+ sdata->keys[i])))
+ local->ops->set_key(local_to_hw(local),
+ DISABLE_KEY, addr,
+ keyconf, 0);
+ kfree(keyconf);
+ ieee80211_key_free(sdata->keys[i]);
+ sdata->keys[i] = NULL;
+ }
+ sdata->default_key = NULL;
+ }
+ read_unlock(&local->sub_if_lock);
+
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ keyconf = NULL;
+ if (sta->key && !sta->key->force_sw_encrypt &&
+ local->ops->set_key &&
+ (keyconf = ieee80211_key_data2conf(local, sta->key)))
+ local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+ sta->addr, keyconf, sta->aid);
+ kfree(keyconf);
+ ieee80211_key_free(sta->key);
+ sta->key = NULL;
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ memset(&key, 0, sizeof(key));
+ if (local->ops->set_key &&
+ local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS,
+ NULL, &key, 0))
+ printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n",
+ dev->name);
+
+ return 0;
+}
+
+
+static int
+ieee80211_ioctl_force_unicast_rate(struct net_device *dev,
+ struct ieee80211_sub_if_data *sdata,
+ int rate)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ int i;
+
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ return -ENOENT;
+
+ if (rate == 0) {
+ sdata->u.ap.force_unicast_rateidx = -1;
+ return 0;
+ }
+
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].rate == rate) {
+ sdata->u.ap.force_unicast_rateidx = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static int
+ieee80211_ioctl_max_ratectrl_rate(struct net_device *dev,
+ struct ieee80211_sub_if_data *sdata,
+ int rate)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ int i;
+
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ return -ENOENT;
+
+ if (rate == 0) {
+ sdata->u.ap.max_ratectrl_rateidx = -1;
+ return 0;
+ }
+
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].rate == rate) {
+ sdata->u.ap.max_ratectrl_rateidx = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+
+static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
+ struct ieee80211_key *key)
+{
+ struct ieee80211_key_conf *keyconf;
+ u8 addr[ETH_ALEN];
+
+ if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt ||
+ (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
+ return;
+
+ memset(addr, 0xff, ETH_ALEN);
+ keyconf = ieee80211_key_data2conf(local, key);
+ if (keyconf && local->ops->set_key &&
+ local->ops->set_key(local_to_hw(local),
+ SET_KEY, addr, keyconf, 0) == 0) {
+ key->force_sw_encrypt =
+ !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
+ key->hw_key_idx = keyconf->hw_key_idx;
+ }
+ kfree(keyconf);
+}
+
+
+static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local,
+ struct ieee80211_key *key)
+{
+ struct ieee80211_key_conf *keyconf;
+ u8 addr[ETH_ALEN];
+
+ if (!key || key->alg != ALG_WEP || key->force_sw_encrypt ||
+ (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
+ return;
+
+ memset(addr, 0xff, ETH_ALEN);
+ keyconf = ieee80211_key_data2conf(local, key);
+ if (keyconf && local->ops->set_key)
+ local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+ addr, keyconf, 0);
+ kfree(keyconf);
+ key->force_sw_encrypt = 1;
+}
+
+
+static int ieee80211_ioctl_default_wep_only(struct ieee80211_local *local,
+ int value)
+{
+ int i;
+ struct ieee80211_sub_if_data *sdata;
+
+ local->default_wep_only = value;
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list)
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++)
+ if (value)
+ ieee80211_key_enable_hwaccel(local,
+ sdata->keys[i]);
+ else
+ ieee80211_key_disable_hwaccel(local,
+ sdata->keys[i]);
+ read_unlock(&local->sub_if_lock);
+
+ return 0;
+}
+
+
+void ieee80211_update_default_wep_only(struct ieee80211_local *local)
+{
+ int i = 0;
+ struct ieee80211_sub_if_data *sdata;
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+
+ if (sdata->dev == local->mdev)
+ continue;
+
+ /* If there is an AP interface then depend on userspace to
+ set default_wep_only correctly. */
+ if (sdata->type == IEEE80211_IF_TYPE_AP) {
+ read_unlock(&local->sub_if_lock);
+ return;
+ }
+
+ i++;
+ }
+
+ read_unlock(&local->sub_if_lock);
+
+ if (i <= 1)
+ ieee80211_ioctl_default_wep_only(local, 1);
+ else
+ ieee80211_ioctl_default_wep_only(local, 0);
+}
+
+
+static int ieee80211_ioctl_prism2_param(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ int *i = (int *) extra;
+ int param = *i;
+ int value = *(i + 1);
+ int ret = 0;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (param) {
+ case PRISM2_PARAM_IEEE_802_1X:
+ if (local->ops->set_ieee8021x)
+ ret = local->ops->set_ieee8021x(local_to_hw(local),
+ value);
+ if (ret)
+ printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
+ "for low-level driver\n", dev->name, value);
+ else
+ sdata->ieee802_1x = value;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_TX:
+ local->hw.conf.antenna_sel_tx = value;
+ if (ieee80211_hw_config(local))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_RX:
+ local->hw.conf.antenna_sel_rx = value;
+ if (ieee80211_hw_config(local))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
+ local->cts_protect_erp_frames = value;
+ break;
+
+ case PRISM2_PARAM_DROP_UNENCRYPTED:
+ sdata->drop_unencrypted = value;
+ break;
+
+ case PRISM2_PARAM_PREAMBLE:
+ local->short_preamble = value;
+ break;
+
+ case PRISM2_PARAM_STAT_TIME:
+ if (!local->stat_time && value) {
+ local->stat_timer.expires = jiffies + HZ * value / 100;
+ add_timer(&local->stat_timer);
+ } else if (local->stat_time && !value) {
+ del_timer_sync(&local->stat_timer);
+ }
+ local->stat_time = value;
+ break;
+ case PRISM2_PARAM_SHORT_SLOT_TIME:
+ if (value)
+ local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
+ else
+ local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
+ if (ieee80211_hw_config(local))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_NEXT_MODE:
+ local->next_mode = value;
+ break;
+
+ case PRISM2_PARAM_CLEAR_KEYS:
+ ret = ieee80211_ioctl_clear_keys(dev);
+ break;
+
+ case PRISM2_PARAM_RADIO_ENABLED:
+ ret = ieee80211_ioctl_set_radio_enabled(dev, value);
+ break;
+
+ case PRISM2_PARAM_ANTENNA_MODE:
+ local->hw.conf.antenna_mode = value;
+ if (ieee80211_hw_config(local))
+ ret = -EINVAL;
+ break;
+
+ case PRISM2_PARAM_STA_ANTENNA_SEL:
+ local->sta_antenna_sel = value;
+ break;
+
+ case PRISM2_PARAM_FORCE_UNICAST_RATE:
+ ret = ieee80211_ioctl_force_unicast_rate(dev, sdata, value);
+ break;
+
+ case PRISM2_PARAM_MAX_RATECTRL_RATE:
+ ret = ieee80211_ioctl_max_ratectrl_rate(dev, sdata, value);
+ break;
+
+ case PRISM2_PARAM_RATE_CTRL_NUM_UP:
+ local->rate_ctrl_num_up = value;
+ break;
+
+ case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
+ local->rate_ctrl_num_down = value;
+ break;
+
+ case PRISM2_PARAM_TX_POWER_REDUCTION:
+ if (value < 0)
+ ret = -EINVAL;
+ else
+ local->hw.conf.tx_power_reduction = value;
+ break;
+
+ case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
+ local->key_tx_rx_threshold = value;
+ break;
+
+ case PRISM2_PARAM_DEFAULT_WEP_ONLY:
+ ret = ieee80211_ioctl_default_wep_only(local, value);
+ break;
+
+ case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
+ local->wifi_wme_noack_test = value;
+ break;
+
+ case PRISM2_PARAM_SCAN_FLAGS:
+ local->scan_flags = value;
+ break;
+
+ case PRISM2_PARAM_MIXED_CELL:
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS)
+ ret = -EINVAL;
+ else
+ sdata->u.sta.mixed_cell = !!value;
+ break;
+
+ case PRISM2_PARAM_HW_MODES:
+ local->enabled_modes = value;
+ break;
+
+ case PRISM2_PARAM_CREATE_IBSS:
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS)
+ ret = -EINVAL;
+ else
+ sdata->u.sta.create_ibss = !!value;
+ break;
+ case PRISM2_PARAM_WMM_ENABLED:
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS)
+ ret = -EINVAL;
+ else
+ sdata->u.sta.wmm_enabled = !!value;
+ break;
+ case PRISM2_PARAM_RADAR_DETECT:
+ local->hw.conf.radar_detect = value;
+ break;
+ case PRISM2_PARAM_SPECTRUM_MGMT:
+ local->hw.conf.spect_mgmt = value;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+
+static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ int *param = (int *) extra;
+ int ret = 0;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (*param) {
+ case PRISM2_PARAM_IEEE_802_1X:
+ *param = sdata->ieee802_1x;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_TX:
+ *param = local->hw.conf.antenna_sel_tx;
+ break;
+
+ case PRISM2_PARAM_ANTSEL_RX:
+ *param = local->hw.conf.antenna_sel_rx;
+ break;
+
+ case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
+ *param = local->cts_protect_erp_frames;
+ break;
+
+ case PRISM2_PARAM_DROP_UNENCRYPTED:
+ *param = sdata->drop_unencrypted;
+ break;
+
+ case PRISM2_PARAM_PREAMBLE:
+ *param = local->short_preamble;
+ break;
+
+ case PRISM2_PARAM_STAT_TIME:
+ *param = local->stat_time;
+ break;
+ case PRISM2_PARAM_SHORT_SLOT_TIME:
+ *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
+ break;
+
+ case PRISM2_PARAM_NEXT_MODE:
+ *param = local->next_mode;
+ break;
+
+ case PRISM2_PARAM_ANTENNA_MODE:
+ *param = local->hw.conf.antenna_mode;
+ break;
+
+ case PRISM2_PARAM_STA_ANTENNA_SEL:
+ *param = local->sta_antenna_sel;
+ break;
+
+ case PRISM2_PARAM_RATE_CTRL_NUM_UP:
+ *param = local->rate_ctrl_num_up;
+ break;
+
+ case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
+ *param = local->rate_ctrl_num_down;
+ break;
+
+ case PRISM2_PARAM_TX_POWER_REDUCTION:
+ *param = local->hw.conf.tx_power_reduction;
+ break;
+
+ case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
+ *param = local->key_tx_rx_threshold;
+ break;
+
+ case PRISM2_PARAM_DEFAULT_WEP_ONLY:
+ *param = local->default_wep_only;
+ break;
+
+ case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
+ *param = local->wifi_wme_noack_test;
+ break;
+
+ case PRISM2_PARAM_SCAN_FLAGS:
+ *param = local->scan_flags;
+ break;
+
+ case PRISM2_PARAM_HW_MODES:
+ *param = local->enabled_modes;
+ break;
+
+ case PRISM2_PARAM_CREATE_IBSS:
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS)
+ ret = -EINVAL;
+ else
+ *param = !!sdata->u.sta.create_ibss;
+ break;
+
+ case PRISM2_PARAM_MIXED_CELL:
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS)
+ ret = -EINVAL;
+ else
+ *param = !!sdata->u.sta.mixed_cell;
+ break;
+ case PRISM2_PARAM_WMM_ENABLED:
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS)
+ ret = -EINVAL;
+ else
+ *param = !!sdata->u.sta.wmm_enabled;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int ieee80211_ioctl_siwmlme(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct iw_mlme *mlme = (struct iw_mlme *) extra;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS)
+ return -EINVAL;
+
+ switch (mlme->cmd) {
+ case IW_MLME_DEAUTH:
+ /* TODO: mlme->addr.sa_data */
+ return ieee80211_sta_deauthenticate(dev, mlme->reason_code);
+ case IW_MLME_DISASSOC:
+ /* TODO: mlme->addr.sa_data */
+ return ieee80211_sta_disassociate(dev, mlme->reason_code);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
+static int ieee80211_ioctl_siwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int idx, i, alg = ALG_WEP;
+ u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx == 0) {
+ if (sdata->default_key)
+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (sdata->default_key == sdata->keys[i]) {
+ idx = i;
+ break;
+ }
+ }
+ } else if (idx < 1 || idx > 4)
+ return -EINVAL;
+ else
+ idx--;
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ alg = ALG_NONE;
+ else if (erq->length == 0) {
+ /* No key data - just set the default TX key index */
+ if (sdata->default_key != sdata->keys[idx]) {
+ ieee80211_debugfs_key_remove_default(sdata);
+ sdata->default_key = sdata->keys[idx];
+ if (sdata->default_key)
+ ieee80211_debugfs_key_add_default(sdata);
+ }
+ return 0;
+ }
+
+ return ieee80211_set_encryption(
+ dev, bcaddr,
+ idx, alg,
+ !sdata->default_key,
+ keybuf, erq->length);
+}
+
+
+static int ieee80211_ioctl_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *key)
+{
+ struct ieee80211_sub_if_data *sdata;
+ int idx, i;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx < 1 || idx > 4) {
+ idx = -1;
+ if (!sdata->default_key)
+ idx = 0;
+ else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (sdata->default_key == sdata->keys[i]) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+
+ erq->flags = idx + 1;
+
+ if (!sdata->keys[idx]) {
+ erq->length = 0;
+ erq->flags |= IW_ENCODE_DISABLED;
+ return 0;
+ }
+
+ memcpy(key, sdata->keys[idx]->key,
+ min((int)erq->length, sdata->keys[idx]->keylen));
+ erq->length = sdata->keys[idx]->keylen;
+ erq->flags |= IW_ENCODE_ENABLED;
+
+ return 0;
+}
+
+static int ieee80211_ioctl_siwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int ret = 0;
+
+ switch (data->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_WPA_VERSION:
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_WPA_ENABLED:
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ break;
+ case IW_AUTH_KEY_MGMT:
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ ret = -EINVAL;
+ else {
+ /*
+ * TODO: sdata->u.sta.key_mgmt does not match with WE18
+ * value completely; could consider modifying this to
+ * be closer to WE18. For now, this value is not really
+ * used for anything else than Privacy matching, so the
+ * current code here should be more or less OK.
+ */
+ if (data->value & IW_AUTH_KEY_MGMT_802_1X) {
+ sdata->u.sta.key_mgmt =
+ IEEE80211_KEY_MGMT_WPA_EAP;
+ } else if (data->value & IW_AUTH_KEY_MGMT_PSK) {
+ sdata->u.sta.key_mgmt =
+ IEEE80211_KEY_MGMT_WPA_PSK;
+ } else {
+ sdata->u.sta.key_mgmt =
+ IEEE80211_KEY_MGMT_NONE;
+ }
+ }
+ break;
+ case IW_AUTH_80211_AUTH_ALG:
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS)
+ sdata->u.sta.auth_algs = data->value;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+ case IW_AUTH_PRIVACY_INVOKED:
+ if (local->ops->set_privacy_invoked)
+ ret = local->ops->set_privacy_invoked(
+ local_to_hw(local), data->value);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
+static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iw_statistics *wstats = &local->wstats;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct sta_info *sta = NULL;
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS)
+ sta = sta_info_get(local, sdata->u.sta.bssid);
+ if (!sta) {
+ wstats->discard.fragment = 0;
+ wstats->discard.misc = 0;
+ wstats->qual.qual = 0;
+ wstats->qual.level = 0;
+ wstats->qual.noise = 0;
+ wstats->qual.updated = IW_QUAL_ALL_INVALID;
+ } else {
+ wstats->qual.level = sta->last_rssi;
+ wstats->qual.qual = sta->last_signal;
+ wstats->qual.noise = sta->last_noise;
+ wstats->qual.updated = local->wstats_flags;
+ sta_info_put(sta);
+ }
+ return wstats;
+}
+
+static int ieee80211_ioctl_giwauth(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *data, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int ret = 0;
+
+ switch (data->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_80211_AUTH_ALG:
+ if (sdata->type == IEEE80211_IF_TYPE_STA ||
+ sdata->type == IEEE80211_IF_TYPE_IBSS)
+ data->value = sdata->u.sta.auth_algs;
+ else
+ ret = -EOPNOTSUPP;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+
+static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ int alg, idx, i;
+
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_NONE:
+ alg = ALG_NONE;
+ break;
+ case IW_ENCODE_ALG_WEP:
+ alg = ALG_WEP;
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ alg = ALG_TKIP;
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ alg = ALG_CCMP;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ alg = ALG_NONE;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx < 1 || idx > 4) {
+ idx = -1;
+ if (!sdata->default_key)
+ idx = 0;
+ else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
+ if (sdata->default_key == sdata->keys[i]) {
+ idx = i;
+ break;
+ }
+ }
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+
+ return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
+ ext->ext_flags &
+ IW_ENCODE_EXT_SET_TX_KEY,
+ ext->key, ext->key_len);
+}
+
+
+static const struct iw_priv_args ieee80211_ioctl_priv[] = {
+ { PRISM2_IOCTL_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
+ { PRISM2_IOCTL_GET_PRISM2_PARAM,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
+};
+
+/* Structures to export the Wireless Handlers */
+
+static const iw_handler ieee80211_handler[] =
+{
+ (iw_handler) NULL, /* SIOCSIWCOMMIT */
+ (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */
+ (iw_handler) NULL, /* SIOCSIWNWID */
+ (iw_handler) NULL, /* SIOCGIWNWID */
+ (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
+ (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
+ (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */
+ (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */
+ (iw_handler) NULL, /* SIOCSIWSENS */
+ (iw_handler) NULL, /* SIOCGIWSENS */
+ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
+ (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */
+ (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
+ (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
+ (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
+ (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
+ iw_handler_set_spy, /* SIOCSIWSPY */
+ iw_handler_get_spy, /* SIOCGIWSPY */
+ iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
+ iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
+ (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
+ (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
+ (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
+ (iw_handler) NULL, /* SIOCGIWAPLIST */
+ (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */
+ (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */
+ (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
+ (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
+ (iw_handler) NULL, /* SIOCSIWNICKN */
+ (iw_handler) NULL, /* SIOCGIWNICKN */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* SIOCSIWRATE */
+ (iw_handler) NULL, /* SIOCGIWRATE */
+ (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
+ (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
+ (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
+ (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
+ (iw_handler) NULL, /* SIOCSIWTXPOW */
+ (iw_handler) NULL, /* SIOCGIWTXPOW */
+ (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
+ (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
+ (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
+ (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
+ (iw_handler) NULL, /* SIOCSIWPOWER */
+ (iw_handler) NULL, /* SIOCGIWPOWER */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) NULL, /* -- hole -- */
+ (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
+ (iw_handler) NULL, /* SIOCGIWGENIE */
+ (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */
+ (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */
+ (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCGIWENCODEEXT */
+ (iw_handler) NULL, /* SIOCSIWPMKSA */
+ (iw_handler) NULL, /* -- hole -- */
+};
+
+static const iw_handler ieee80211_private_handler[] =
+{ /* SIOCIWFIRSTPRIV + */
+ (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */
+ (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */
+};
+
+const struct iw_handler_def ieee80211_iw_handler_def =
+{
+ .num_standard = ARRAY_SIZE(ieee80211_handler),
+ .num_private = ARRAY_SIZE(ieee80211_private_handler),
+ .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
+ .standard = (iw_handler *) ieee80211_handler,
+ .private = (iw_handler *) ieee80211_private_handler,
+ .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv,
+ .get_wireless_stats = ieee80211_get_wireless_stats,
+};
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h
new file mode 100644
index 00000000000..c3338491278
--- /dev/null
+++ b/net/mac80211/ieee80211_key.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef IEEE80211_KEY_H
+#define IEEE80211_KEY_H
+
+#include <linux/types.h>
+#include <linux/kref.h>
+#include <linux/crypto.h>
+#include <net/mac80211.h>
+
+/* ALG_TKIP
+ * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block:
+ * Temporal Encryption Key (128 bits)
+ * Temporal Authenticator Tx MIC Key (64 bits)
+ * Temporal Authenticator Rx MIC Key (64 bits)
+ */
+
+#define WEP_IV_LEN 4
+#define WEP_ICV_LEN 4
+
+#define ALG_TKIP_KEY_LEN 32
+/* Starting offsets for each key */
+#define ALG_TKIP_TEMP_ENCR_KEY 0
+#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16
+#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24
+#define TKIP_IV_LEN 8
+#define TKIP_ICV_LEN 4
+
+#define ALG_CCMP_KEY_LEN 16
+#define CCMP_HDR_LEN 8
+#define CCMP_MIC_LEN 8
+#define CCMP_TK_LEN 16
+#define CCMP_PN_LEN 6
+
+#define NUM_RX_DATA_QUEUES 17
+
+struct ieee80211_key {
+ struct kref kref;
+
+ int hw_key_idx; /* filled and used by low-level driver */
+ ieee80211_key_alg alg;
+ union {
+ struct {
+ /* last used TSC */
+ u32 iv32;
+ u16 iv16;
+ u16 p1k[5];
+ int tx_initialized;
+
+ /* last received RSC */
+ u32 iv32_rx[NUM_RX_DATA_QUEUES];
+ u16 iv16_rx[NUM_RX_DATA_QUEUES];
+ u16 p1k_rx[NUM_RX_DATA_QUEUES][5];
+ int rx_initialized[NUM_RX_DATA_QUEUES];
+ } tkip;
+ struct {
+ u8 tx_pn[6];
+ u8 rx_pn[NUM_RX_DATA_QUEUES][6];
+ struct crypto_cipher *tfm;
+ u32 replays; /* dot11RSNAStatsCCMPReplays */
+ /* scratch buffers for virt_to_page() (crypto API) */
+#ifndef AES_BLOCK_LEN
+#define AES_BLOCK_LEN 16
+#endif
+ u8 tx_crypto_buf[6 * AES_BLOCK_LEN];
+ u8 rx_crypto_buf[6 * AES_BLOCK_LEN];
+ } ccmp;
+ } u;
+ int tx_rx_count; /* number of times this key has been used */
+ int keylen;
+
+ /* if the low level driver can provide hardware acceleration it should
+ * clear this flag */
+ unsigned int force_sw_encrypt:1;
+ unsigned int default_tx_key:1; /* This key is the new default TX key
+ * (used only for broadcast keys). */
+ s8 keyidx; /* WEP key index */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct {
+ struct dentry *stalink;
+ struct dentry *dir;
+ struct dentry *keylen;
+ struct dentry *force_sw_encrypt;
+ struct dentry *keyidx;
+ struct dentry *hw_key_idx;
+ struct dentry *tx_rx_count;
+ struct dentry *algorithm;
+ struct dentry *tx_spec;
+ struct dentry *rx_spec;
+ struct dentry *replays;
+ struct dentry *key;
+ } debugfs;
+#endif
+
+ u8 key[0];
+};
+
+#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/ieee80211_led.c b/net/mac80211/ieee80211_led.c
new file mode 100644
index 00000000000..719d75b2070
--- /dev/null
+++ b/net/mac80211/ieee80211_led.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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.
+ */
+
+/* just for IFNAMSIZ */
+#include <linux/if.h>
+#include "ieee80211_led.h"
+
+void ieee80211_led_rx(struct ieee80211_local *local)
+{
+ if (unlikely(!local->rx_led))
+ return;
+ if (local->rx_led_counter++ % 2 == 0)
+ led_trigger_event(local->rx_led, LED_OFF);
+ else
+ led_trigger_event(local->rx_led, LED_FULL);
+}
+
+/* q is 1 if a packet was enqueued, 0 if it has been transmitted */
+void ieee80211_led_tx(struct ieee80211_local *local, int q)
+{
+ if (unlikely(!local->tx_led))
+ return;
+ /* not sure how this is supposed to work ... */
+ local->tx_led_counter += 2*q-1;
+ if (local->tx_led_counter % 2 == 0)
+ led_trigger_event(local->tx_led, LED_OFF);
+ else
+ led_trigger_event(local->tx_led, LED_FULL);
+}
+
+void ieee80211_led_init(struct ieee80211_local *local)
+{
+ local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+ if (!local->rx_led)
+ return;
+ snprintf(local->rx_led_name, sizeof(local->rx_led_name),
+ "%srx", wiphy_name(local->hw.wiphy));
+ local->rx_led->name = local->rx_led_name;
+ if (led_trigger_register(local->rx_led)) {
+ kfree(local->rx_led);
+ local->rx_led = NULL;
+ }
+
+ local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+ if (!local->tx_led)
+ return;
+ snprintf(local->tx_led_name, sizeof(local->tx_led_name),
+ "%stx", wiphy_name(local->hw.wiphy));
+ local->tx_led->name = local->tx_led_name;
+ if (led_trigger_register(local->tx_led)) {
+ kfree(local->tx_led);
+ local->tx_led = NULL;
+ }
+}
+
+void ieee80211_led_exit(struct ieee80211_local *local)
+{
+ if (local->tx_led) {
+ led_trigger_unregister(local->tx_led);
+ kfree(local->tx_led);
+ }
+ if (local->rx_led) {
+ led_trigger_unregister(local->rx_led);
+ kfree(local->rx_led);
+ }
+}
+
+char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (local->tx_led)
+ return local->tx_led_name;
+ return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
+
+char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (local->rx_led)
+ return local->rx_led_name;
+ return NULL;
+}
+EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
diff --git a/net/mac80211/ieee80211_led.h b/net/mac80211/ieee80211_led.h
new file mode 100644
index 00000000000..5c8ab826387
--- /dev/null
+++ b/net/mac80211/ieee80211_led.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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/list.h>
+#include <linux/spinlock.h>
+#include <linux/leds.h>
+#include "ieee80211_i.h"
+
+#ifdef CONFIG_MAC80211_LEDS
+extern void ieee80211_led_rx(struct ieee80211_local *local);
+extern void ieee80211_led_tx(struct ieee80211_local *local, int q);
+extern void ieee80211_led_init(struct ieee80211_local *local);
+extern void ieee80211_led_exit(struct ieee80211_local *local);
+#else
+static inline void ieee80211_led_rx(struct ieee80211_local *local)
+{
+}
+static inline void ieee80211_led_tx(struct ieee80211_local *local, int q)
+{
+}
+static inline void ieee80211_led_init(struct ieee80211_local *local)
+{
+}
+static inline void ieee80211_led_exit(struct ieee80211_local *local)
+{
+}
+#endif
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c
new file mode 100644
index 00000000000..16e850864b8
--- /dev/null
+++ b/net/mac80211/ieee80211_rate.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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/kernel.h>
+#include "ieee80211_rate.h"
+#include "ieee80211_i.h"
+
+struct rate_control_alg {
+ struct list_head list;
+ struct rate_control_ops *ops;
+};
+
+static LIST_HEAD(rate_ctrl_algs);
+static DEFINE_MUTEX(rate_ctrl_mutex);
+
+int ieee80211_rate_control_register(struct rate_control_ops *ops)
+{
+ struct rate_control_alg *alg;
+
+ alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+ if (alg == NULL) {
+ return -ENOMEM;
+ }
+ memset(alg, 0, sizeof(*alg));
+ alg->ops = ops;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_add_tail(&alg->list, &rate_ctrl_algs);
+ mutex_unlock(&rate_ctrl_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_rate_control_register);
+
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops)
+{
+ struct rate_control_alg *alg;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_for_each_entry(alg, &rate_ctrl_algs, list) {
+ if (alg->ops == ops) {
+ list_del(&alg->list);
+ break;
+ }
+ }
+ mutex_unlock(&rate_ctrl_mutex);
+ kfree(alg);
+}
+EXPORT_SYMBOL(ieee80211_rate_control_unregister);
+
+static struct rate_control_ops *
+ieee80211_try_rate_control_ops_get(const char *name)
+{
+ struct rate_control_alg *alg;
+ struct rate_control_ops *ops = NULL;
+
+ mutex_lock(&rate_ctrl_mutex);
+ list_for_each_entry(alg, &rate_ctrl_algs, list) {
+ if (!name || !strcmp(alg->ops->name, name))
+ if (try_module_get(alg->ops->module)) {
+ ops = alg->ops;
+ break;
+ }
+ }
+ mutex_unlock(&rate_ctrl_mutex);
+ return ops;
+}
+
+/* Get the rate control algorithm. If `name' is NULL, get the first
+ * available algorithm. */
+static struct rate_control_ops *
+ieee80211_rate_control_ops_get(const char *name)
+{
+ struct rate_control_ops *ops;
+
+ ops = ieee80211_try_rate_control_ops_get(name);
+ if (!ops) {
+ request_module("rc80211_%s", name ? name : "default");
+ ops = ieee80211_try_rate_control_ops_get(name);
+ }
+ return ops;
+}
+
+static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops)
+{
+ module_put(ops->module);
+}
+
+struct rate_control_ref *rate_control_alloc(const char *name,
+ struct ieee80211_local *local)
+{
+ struct rate_control_ref *ref;
+
+ ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL);
+ if (!ref)
+ goto fail_ref;
+ kref_init(&ref->kref);
+ ref->ops = ieee80211_rate_control_ops_get(name);
+ if (!ref->ops)
+ goto fail_ops;
+ ref->priv = ref->ops->alloc(local);
+ if (!ref->priv)
+ goto fail_priv;
+ return ref;
+
+fail_priv:
+ ieee80211_rate_control_ops_put(ref->ops);
+fail_ops:
+ kfree(ref);
+fail_ref:
+ return NULL;
+}
+
+static void rate_control_release(struct kref *kref)
+{
+ struct rate_control_ref *ctrl_ref;
+
+ ctrl_ref = container_of(kref, struct rate_control_ref, kref);
+ ctrl_ref->ops->free(ctrl_ref->priv);
+ ieee80211_rate_control_ops_put(ctrl_ref->ops);
+ kfree(ctrl_ref);
+}
+
+struct rate_control_ref *rate_control_get(struct rate_control_ref *ref)
+{
+ kref_get(&ref->kref);
+ return ref;
+}
+
+void rate_control_put(struct rate_control_ref *ref)
+{
+ kref_put(&ref->kref, rate_control_release);
+}
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h
new file mode 100644
index 00000000000..f021a028d9d
--- /dev/null
+++ b/net/mac80211/ieee80211_rate.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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.
+ */
+
+#ifndef IEEE80211_RATE_H
+#define IEEE80211_RATE_H
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+
+#define RATE_CONTROL_NUM_DOWN 20
+#define RATE_CONTROL_NUM_UP 15
+
+
+struct rate_control_extra {
+ /* values from rate_control_get_rate() to the caller: */
+ struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
+ * probing */
+ struct ieee80211_rate *nonerp;
+
+ /* parameters from the caller to rate_control_get_rate(): */
+ struct ieee80211_hw_mode *mode;
+ int mgmt_data; /* this is data frame that is used for management
+ * (e.g., IEEE 802.1X EAPOL) */
+ u16 ethertype;
+};
+
+
+struct rate_control_ops {
+ struct module *module;
+ const char *name;
+ void (*tx_status)(void *priv, struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status);
+ struct ieee80211_rate *(*get_rate)(void *priv, struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra *extra);
+ void (*rate_init)(void *priv, void *priv_sta,
+ struct ieee80211_local *local, struct sta_info *sta);
+ void (*clear)(void *priv);
+
+ void *(*alloc)(struct ieee80211_local *local);
+ void (*free)(void *priv);
+ void *(*alloc_sta)(void *priv, gfp_t gfp);
+ void (*free_sta)(void *priv, void *priv_sta);
+
+ int (*add_attrs)(void *priv, struct kobject *kobj);
+ void (*remove_attrs)(void *priv, struct kobject *kobj);
+ void (*add_sta_debugfs)(void *priv, void *priv_sta,
+ struct dentry *dir);
+ void (*remove_sta_debugfs)(void *priv, void *priv_sta);
+};
+
+struct rate_control_ref {
+ struct rate_control_ops *ops;
+ void *priv;
+ struct kref kref;
+};
+
+int ieee80211_rate_control_register(struct rate_control_ops *ops);
+void ieee80211_rate_control_unregister(struct rate_control_ops *ops);
+
+/* Get a reference to the rate control algorithm. If `name' is NULL, get the
+ * first available algorithm. */
+struct rate_control_ref *rate_control_alloc(const char *name,
+ struct ieee80211_local *local);
+struct rate_control_ref *rate_control_get(struct rate_control_ref *ref);
+void rate_control_put(struct rate_control_ref *ref);
+
+static inline void rate_control_tx_status(struct ieee80211_local *local,
+ struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+ struct rate_control_ref *ref = local->rate_ctrl;
+ ref->ops->tx_status(ref->priv, dev, skb, status);
+}
+
+
+static inline struct ieee80211_rate *
+rate_control_get_rate(struct ieee80211_local *local, struct net_device *dev,
+ struct sk_buff *skb, struct rate_control_extra *extra)
+{
+ struct rate_control_ref *ref = local->rate_ctrl;
+ return ref->ops->get_rate(ref->priv, dev, skb, extra);
+}
+
+
+static inline void rate_control_rate_init(struct sta_info *sta,
+ struct ieee80211_local *local)
+{
+ struct rate_control_ref *ref = sta->rate_ctrl;
+ ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta);
+}
+
+
+static inline void rate_control_clear(struct ieee80211_local *local)
+{
+ struct rate_control_ref *ref = local->rate_ctrl;
+ ref->ops->clear(ref->priv);
+}
+
+static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
+ gfp_t gfp)
+{
+ return ref->ops->alloc_sta(ref->priv, gfp);
+}
+
+static inline void rate_control_free_sta(struct rate_control_ref *ref,
+ void *priv)
+{
+ ref->ops->free_sta(ref->priv, priv);
+}
+
+static inline void rate_control_add_sta_debugfs(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct rate_control_ref *ref = sta->rate_ctrl;
+ if (sta->debugfs.dir && ref->ops->add_sta_debugfs)
+ ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv,
+ sta->debugfs.dir);
+#endif
+}
+
+static inline void rate_control_remove_sta_debugfs(struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct rate_control_ref *ref = sta->rate_ctrl;
+ if (ref->ops->remove_sta_debugfs)
+ ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv);
+#endif
+}
+
+#endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
new file mode 100644
index 00000000000..822917debef
--- /dev/null
+++ b/net/mac80211/ieee80211_sta.c
@@ -0,0 +1,3060 @@
+/*
+ * BSS client mode implementation
+ * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ *
+ * 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.
+ */
+
+/* TODO:
+ * BSS table: use <BSSID,SSID> as the key to support multi-SSID APs
+ * order BSS list by RSSI(?) ("quality of AP")
+ * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
+ * SSID)
+ */
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#include <linux/random.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/iw_handler.h>
+#include <asm/types.h>
+#include <asm/delay.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "hostapd_ioctl.h"
+
+#define IEEE80211_AUTH_TIMEOUT (HZ / 5)
+#define IEEE80211_AUTH_MAX_TRIES 3
+#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
+#define IEEE80211_ASSOC_MAX_TRIES 3
+#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
+#define IEEE80211_PROBE_INTERVAL (60 * HZ)
+#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
+#define IEEE80211_SCAN_INTERVAL (2 * HZ)
+#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ)
+
+#define IEEE80211_PROBE_DELAY (HZ / 33)
+#define IEEE80211_CHANNEL_TIME (HZ / 33)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
+#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ)
+#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
+#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+
+#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+
+#define ERP_INFO_USE_PROTECTION BIT(1)
+
+static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
+ u8 *ssid, size_t ssid_len);
+static struct ieee80211_sta_bss *
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid);
+static void ieee80211_rx_bss_put(struct net_device *dev,
+ struct ieee80211_sta_bss *bss);
+static int ieee80211_sta_find_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta);
+static int ieee80211_sta_wep_configured(struct net_device *dev);
+static int ieee80211_sta_start_scan(struct net_device *dev,
+ u8 *ssid, size_t ssid_len);
+static int ieee80211_sta_config_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta);
+
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ u8 *ssid;
+ u8 ssid_len;
+ u8 *supp_rates;
+ u8 supp_rates_len;
+ u8 *fh_params;
+ u8 fh_params_len;
+ u8 *ds_params;
+ u8 ds_params_len;
+ u8 *cf_params;
+ u8 cf_params_len;
+ u8 *tim;
+ u8 tim_len;
+ u8 *ibss_params;
+ u8 ibss_params_len;
+ u8 *challenge;
+ u8 challenge_len;
+ u8 *wpa;
+ u8 wpa_len;
+ u8 *rsn;
+ u8 rsn_len;
+ u8 *erp_info;
+ u8 erp_info_len;
+ u8 *ext_supp_rates;
+ u8 ext_supp_rates_len;
+ u8 *wmm_info;
+ u8 wmm_info_len;
+ u8 *wmm_param;
+ u8 wmm_param_len;
+};
+
+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+
+
+static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems)
+{
+ size_t left = len;
+ u8 *pos = start;
+ int unknown = 0;
+
+ memset(elems, 0, sizeof(*elems));
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left) {
+#if 0
+ if (net_ratelimit())
+ printk(KERN_DEBUG "IEEE 802.11 element parse "
+ "failed (id=%d elen=%d left=%d)\n",
+ id, elen, left);
+#endif
+ return ParseFailed;
+ }
+
+ switch (id) {
+ case WLAN_EID_SSID:
+ elems->ssid = pos;
+ elems->ssid_len = elen;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ elems->supp_rates = pos;
+ elems->supp_rates_len = elen;
+ break;
+ case WLAN_EID_FH_PARAMS:
+ elems->fh_params = pos;
+ elems->fh_params_len = elen;
+ break;
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = pos;
+ elems->ds_params_len = elen;
+ break;
+ case WLAN_EID_CF_PARAMS:
+ elems->cf_params = pos;
+ elems->cf_params_len = elen;
+ break;
+ case WLAN_EID_TIM:
+ elems->tim = pos;
+ elems->tim_len = elen;
+ break;
+ case WLAN_EID_IBSS_PARAMS:
+ elems->ibss_params = pos;
+ elems->ibss_params_len = elen;
+ break;
+ case WLAN_EID_CHALLENGE:
+ elems->challenge = pos;
+ elems->challenge_len = elen;
+ break;
+ case WLAN_EID_WPA:
+ if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+ pos[2] == 0xf2) {
+ /* Microsoft OUI (00:50:F2) */
+ if (pos[3] == 1) {
+ /* OUI Type 1 - WPA IE */
+ elems->wpa = pos;
+ elems->wpa_len = elen;
+ } else if (elen >= 5 && pos[3] == 2) {
+ if (pos[4] == 0) {
+ elems->wmm_info = pos;
+ elems->wmm_info_len = elen;
+ } else if (pos[4] == 1) {
+ elems->wmm_param = pos;
+ elems->wmm_param_len = elen;
+ }
+ }
+ }
+ break;
+ case WLAN_EID_RSN:
+ elems->rsn = pos;
+ elems->rsn_len = elen;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = pos;
+ elems->erp_info_len = elen;
+ break;
+ case WLAN_EID_EXT_SUPP_RATES:
+ elems->ext_supp_rates = pos;
+ elems->ext_supp_rates_len = elen;
+ break;
+ default:
+#if 0
+ printk(KERN_DEBUG "IEEE 802.11 element parse ignored "
+ "unknown element (id=%d elen=%d)\n",
+ id, elen);
+#endif
+ unknown++;
+ break;
+ }
+
+ left -= elen;
+ pos += elen;
+ }
+
+ /* Do not trigger error if left == 1 as Apple Airport base stations
+ * send AssocResps that are one spurious byte too long. */
+
+ return unknown ? ParseUnknown : ParseOK;
+}
+
+
+
+
+static int ecw2cw(int ecw)
+{
+ int cw = 1;
+ while (ecw > 0) {
+ cw <<= 1;
+ ecw--;
+ }
+ return cw - 1;
+}
+
+
+static void ieee80211_sta_wmm_params(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ u8 *wmm_param, size_t wmm_param_len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_tx_queue_params params;
+ size_t left;
+ int count;
+ u8 *pos;
+
+ if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
+ return;
+ count = wmm_param[6] & 0x0f;
+ if (count == ifsta->wmm_last_param_set)
+ return;
+ ifsta->wmm_last_param_set = count;
+
+ pos = wmm_param + 8;
+ left = wmm_param_len - 8;
+
+ memset(&params, 0, sizeof(params));
+
+ if (!local->ops->conf_tx)
+ return;
+
+ local->wmm_acm = 0;
+ for (; left >= 4; left -= 4, pos += 4) {
+ int aci = (pos[0] >> 5) & 0x03;
+ int acm = (pos[0] >> 4) & 0x01;
+ int queue;
+
+ switch (aci) {
+ case 1:
+ queue = IEEE80211_TX_QUEUE_DATA3;
+ if (acm) {
+ local->wmm_acm |= BIT(0) | BIT(3);
+ }
+ break;
+ case 2:
+ queue = IEEE80211_TX_QUEUE_DATA1;
+ if (acm) {
+ local->wmm_acm |= BIT(4) | BIT(5);
+ }
+ break;
+ case 3:
+ queue = IEEE80211_TX_QUEUE_DATA0;
+ if (acm) {
+ local->wmm_acm |= BIT(6) | BIT(7);
+ }
+ break;
+ case 0:
+ default:
+ queue = IEEE80211_TX_QUEUE_DATA2;
+ if (acm) {
+ local->wmm_acm |= BIT(1) | BIT(2);
+ }
+ break;
+ }
+
+ params.aifs = pos[0] & 0x0f;
+ params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+ params.cw_min = ecw2cw(pos[1] & 0x0f);
+ /* TXOP is in units of 32 usec; burst_time in 0.1 ms */
+ params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+ printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
+ "cWmin=%d cWmax=%d burst=%d\n",
+ dev->name, queue, aci, acm, params.aifs, params.cw_min,
+ params.cw_max, params.burst_time);
+ /* TODO: handle ACM (block TX, fallback to next lowest allowed
+ * AC for now) */
+ if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
+ printk(KERN_DEBUG "%s: failed to set TX queue "
+ "parameters for queue %d\n", dev->name, queue);
+ }
+ }
+}
+
+
+static void ieee80211_sta_send_associnfo(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ char *buf;
+ size_t len;
+ int i;
+ union iwreq_data wrqu;
+
+ if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
+ return;
+
+ buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
+ ifsta->assocresp_ies_len), GFP_ATOMIC);
+ if (!buf)
+ return;
+
+ len = sprintf(buf, "ASSOCINFO(");
+ if (ifsta->assocreq_ies) {
+ len += sprintf(buf + len, "ReqIEs=");
+ for (i = 0; i < ifsta->assocreq_ies_len; i++) {
+ len += sprintf(buf + len, "%02x",
+ ifsta->assocreq_ies[i]);
+ }
+ }
+ if (ifsta->assocresp_ies) {
+ if (ifsta->assocreq_ies)
+ len += sprintf(buf + len, " ");
+ len += sprintf(buf + len, "RespIEs=");
+ for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+ len += sprintf(buf + len, "%02x",
+ ifsta->assocresp_ies[i]);
+ }
+ }
+ len += sprintf(buf + len, ")");
+
+ if (len > IW_CUSTOM_MAX) {
+ len = sprintf(buf, "ASSOCRESPIE=");
+ for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+ len += sprintf(buf + len, "%02x",
+ ifsta->assocresp_ies[i]);
+ }
+ }
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = len;
+ wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
+
+ kfree(buf);
+}
+
+
+static void ieee80211_set_associated(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta, int assoc)
+{
+ union iwreq_data wrqu;
+
+ if (ifsta->associated == assoc)
+ return;
+
+ ifsta->associated = assoc;
+
+ if (assoc) {
+ struct ieee80211_sub_if_data *sdata;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return;
+ netif_carrier_on(dev);
+ ifsta->prev_bssid_set = 1;
+ memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
+ ieee80211_sta_send_associnfo(dev, ifsta);
+ } else {
+ netif_carrier_off(dev);
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ }
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+ ifsta->last_probe = jiffies;
+}
+
+static void ieee80211_set_disassoc(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta, int deauth)
+{
+ if (deauth)
+ ifsta->auth_tries = 0;
+ ifsta->assoc_tries = 0;
+ ieee80211_set_associated(dev, ifsta, 0);
+}
+
+static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb,
+ int encrypt)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_tx_packet_data *pkt_data;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ skb->dev = sdata->local->mdev;
+ skb_set_mac_header(skb, 0);
+ skb_set_network_header(skb, 0);
+ skb_set_transport_header(skb, 0);
+
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+ memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
+ pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
+ pkt_data->do_not_encrypt = !encrypt;
+
+ dev_queue_xmit(skb);
+}
+
+
+static void ieee80211_send_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ int transaction, u8 *extra, size_t extra_len,
+ int encrypt)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ sizeof(*mgmt) + 6 + extra_len);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
+ "frame\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
+ memset(mgmt, 0, 24 + 6);
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_AUTH);
+ if (encrypt)
+ mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
+ mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
+ ifsta->auth_transaction = transaction + 1;
+ mgmt->u.auth.status_code = cpu_to_le16(0);
+ if (extra)
+ memcpy(skb_put(skb, extra_len), extra, extra_len);
+
+ ieee80211_sta_tx(dev, skb, encrypt);
+}
+
+
+static void ieee80211_authenticate(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ ifsta->auth_tries++;
+ if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+ printk(KERN_DEBUG "%s: authentication with AP " MAC_FMT
+ " timed out\n",
+ dev->name, MAC_ARG(ifsta->bssid));
+ ifsta->state = IEEE80211_DISABLED;
+ return;
+ }
+
+ ifsta->state = IEEE80211_AUTHENTICATE;
+ printk(KERN_DEBUG "%s: authenticate with AP " MAC_FMT "\n",
+ dev->name, MAC_ARG(ifsta->bssid));
+
+ ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0);
+
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+}
+
+
+static void ieee80211_send_assoc(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos, *ies;
+ int i, len;
+ u16 capab;
+ struct ieee80211_sta_bss *bss;
+ int wmm = 0;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
+ ifsta->ssid_len);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
+ "frame\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mode = local->oper_hw_mode;
+ capab = ifsta->capab;
+ if (mode->mode == MODE_IEEE80211G) {
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
+ WLAN_CAPABILITY_SHORT_PREAMBLE;
+ }
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+ capab |= WLAN_CAPABILITY_PRIVACY;
+ if (bss->wmm_ie) {
+ wmm = 1;
+ }
+ ieee80211_rx_bss_put(dev, bss);
+ }
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+
+ if (ifsta->prev_bssid_set) {
+ skb_put(skb, 10);
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_REASSOC_REQ);
+ mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
+ mgmt->u.reassoc_req.listen_interval = cpu_to_le16(1);
+ memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
+ ETH_ALEN);
+ } else {
+ skb_put(skb, 4);
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ASSOC_REQ);
+ mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
+ mgmt->u.assoc_req.listen_interval = cpu_to_le16(1);
+ }
+
+ /* SSID */
+ ies = pos = skb_put(skb, 2 + ifsta->ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ifsta->ssid_len;
+ memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+ len = mode->num_rates;
+ if (len > 8)
+ len = 8;
+ pos = skb_put(skb, len + 2);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = len;
+ for (i = 0; i < len; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ rate /= 2;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ if (mode->num_rates > len) {
+ pos = skb_put(skb, mode->num_rates - len + 2);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = mode->num_rates - len;
+ for (i = len; i < mode->num_rates; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ rate /= 2;
+ *pos++ = (u8) (rate / 5);
+ }
+ }
+
+ if (ifsta->extra_ie) {
+ pos = skb_put(skb, ifsta->extra_ie_len);
+ memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
+ }
+
+ if (wmm && ifsta->wmm_enabled) {
+ pos = skb_put(skb, 9);
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+ *pos++ = 0x50;
+ *pos++ = 0xf2;
+ *pos++ = 2; /* WME */
+ *pos++ = 0; /* WME info */
+ *pos++ = 1; /* WME ver */
+ *pos++ = 0;
+ }
+
+ kfree(ifsta->assocreq_ies);
+ ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
+ ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_ATOMIC);
+ if (ifsta->assocreq_ies)
+ memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static void ieee80211_send_deauth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta, u16 reason)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for deauth "
+ "frame\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_DEAUTH);
+ skb_put(skb, 2);
+ mgmt->u.deauth.reason_code = cpu_to_le16(reason);
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static void ieee80211_send_disassoc(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta, u16 reason)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt));
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc "
+ "frame\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_DISASSOC);
+ skb_put(skb, 2);
+ mgmt->u.disassoc.reason_code = cpu_to_le16(reason);
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static int ieee80211_privacy_mismatch(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_sta_bss *bss;
+ int res = 0;
+
+ if (!ifsta || ifsta->mixed_cell ||
+ ifsta->key_mgmt != IEEE80211_KEY_MGMT_NONE)
+ return 0;
+
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (!bss)
+ return 0;
+
+ if (ieee80211_sta_wep_configured(dev) !=
+ !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
+ res = 1;
+
+ ieee80211_rx_bss_put(dev, bss);
+
+ return res;
+}
+
+
+static void ieee80211_associate(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ ifsta->assoc_tries++;
+ if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+ printk(KERN_DEBUG "%s: association with AP " MAC_FMT
+ " timed out\n",
+ dev->name, MAC_ARG(ifsta->bssid));
+ ifsta->state = IEEE80211_DISABLED;
+ return;
+ }
+
+ ifsta->state = IEEE80211_ASSOCIATE;
+ printk(KERN_DEBUG "%s: associate with AP " MAC_FMT "\n",
+ dev->name, MAC_ARG(ifsta->bssid));
+ if (ieee80211_privacy_mismatch(dev, ifsta)) {
+ printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
+ "mixed-cell disabled - abort association\n", dev->name);
+ ifsta->state = IEEE80211_DISABLED;
+ return;
+ }
+
+ ieee80211_send_assoc(dev, ifsta);
+
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+}
+
+
+static void ieee80211_associated(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ int disassoc;
+
+ /* TODO: start monitoring current AP signal quality and number of
+ * missed beacons. Scan other channels every now and then and search
+ * for better APs. */
+ /* TODO: remove expired BSSes */
+
+ ifsta->state = IEEE80211_ASSOCIATED;
+
+ sta = sta_info_get(local, ifsta->bssid);
+ if (!sta) {
+ printk(KERN_DEBUG "%s: No STA entry for own AP " MAC_FMT "\n",
+ dev->name, MAC_ARG(ifsta->bssid));
+ disassoc = 1;
+ } else {
+ disassoc = 0;
+ if (time_after(jiffies,
+ sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
+ if (ifsta->probereq_poll) {
+ printk(KERN_DEBUG "%s: No ProbeResp from "
+ "current AP " MAC_FMT " - assume out of "
+ "range\n",
+ dev->name, MAC_ARG(ifsta->bssid));
+ disassoc = 1;
+ sta_info_free(sta, 0);
+ ifsta->probereq_poll = 0;
+ } else {
+ ieee80211_send_probe_req(dev, ifsta->bssid,
+ local->scan_ssid,
+ local->scan_ssid_len);
+ ifsta->probereq_poll = 1;
+ }
+ } else {
+ ifsta->probereq_poll = 0;
+ if (time_after(jiffies, ifsta->last_probe +
+ IEEE80211_PROBE_INTERVAL)) {
+ ifsta->last_probe = jiffies;
+ ieee80211_send_probe_req(dev, ifsta->bssid,
+ ifsta->ssid,
+ ifsta->ssid_len);
+ }
+ }
+ sta_info_put(sta);
+ }
+ if (disassoc) {
+ union iwreq_data wrqu;
+ memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_MONITORING_INTERVAL + 30 * HZ);
+ } else {
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_MONITORING_INTERVAL);
+ }
+}
+
+
+static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst,
+ u8 *ssid, size_t ssid_len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos, *supp_rates, *esupp_rates = NULL;
+ int i;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+ "request\n", dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+ memset(mgmt, 0, 24);
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_PROBE_REQ);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ if (dst) {
+ memcpy(mgmt->da, dst, ETH_ALEN);
+ memcpy(mgmt->bssid, dst, ETH_ALEN);
+ } else {
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memset(mgmt->bssid, 0xff, ETH_ALEN);
+ }
+ pos = skb_put(skb, 2 + ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ssid_len;
+ memcpy(pos, ssid, ssid_len);
+
+ supp_rates = skb_put(skb, 2);
+ supp_rates[0] = WLAN_EID_SUPP_RATES;
+ supp_rates[1] = 0;
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+ if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
+ continue;
+ if (esupp_rates) {
+ pos = skb_put(skb, 1);
+ esupp_rates[1]++;
+ } else if (supp_rates[1] == 8) {
+ esupp_rates = skb_put(skb, 3);
+ esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
+ esupp_rates[1] = 1;
+ pos = &esupp_rates[2];
+ } else {
+ pos = skb_put(skb, 1);
+ supp_rates[1]++;
+ }
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ *pos = rate->rate / 10;
+ else
+ *pos = rate->rate / 5;
+ }
+
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+static int ieee80211_sta_wep_configured(struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!sdata || !sdata->default_key ||
+ sdata->default_key->alg != ALG_WEP)
+ return 0;
+ return 1;
+}
+
+
+static void ieee80211_auth_completed(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ printk(KERN_DEBUG "%s: authenticated\n", dev->name);
+ ifsta->authenticated = 1;
+ ieee80211_associate(dev, ifsta);
+}
+
+
+static void ieee80211_auth_challenge(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u8 *pos;
+ struct ieee802_11_elems elems;
+
+ printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name);
+ pos = mgmt->u.auth.variable;
+ if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+ == ParseFailed) {
+ printk(KERN_DEBUG "%s: failed to parse Auth(challenge)\n",
+ dev->name);
+ return;
+ }
+ if (!elems.challenge) {
+ printk(KERN_DEBUG "%s: no challenge IE in shared key auth "
+ "frame\n", dev->name);
+ return;
+ }
+ ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2,
+ elems.challenge_len + 2, 1);
+}
+
+
+static void ieee80211_rx_mgmt_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ u16 auth_alg, auth_transaction, status_code;
+
+ if (ifsta->state != IEEE80211_AUTHENTICATE &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS) {
+ printk(KERN_DEBUG "%s: authentication frame received from "
+ MAC_FMT ", but not in authenticate state - ignored\n",
+ dev->name, MAC_ARG(mgmt->sa));
+ return;
+ }
+
+ if (len < 24 + 6) {
+ printk(KERN_DEBUG "%s: too short (%zd) authentication frame "
+ "received from " MAC_FMT " - ignored\n",
+ dev->name, len, MAC_ARG(mgmt->sa));
+ return;
+ }
+
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+ memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ printk(KERN_DEBUG "%s: authentication frame received from "
+ "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+ "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+ MAC_ARG(mgmt->bssid));
+ return;
+ }
+
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS &&
+ memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) {
+ printk(KERN_DEBUG "%s: authentication frame received from "
+ "unknown BSSID (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+ "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+ MAC_ARG(mgmt->bssid));
+ return;
+ }
+
+ auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+ auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+ status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+ printk(KERN_DEBUG "%s: RX authentication from " MAC_FMT " (alg=%d "
+ "transaction=%d status=%d)\n",
+ dev->name, MAC_ARG(mgmt->sa), auth_alg,
+ auth_transaction, status_code);
+
+ if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ /* IEEE 802.11 standard does not require authentication in IBSS
+ * networks and most implementations do not seem to use it.
+ * However, try to reply to authentication attempts if someone
+ * has actually implemented this.
+ * TODO: Could implement shared key authentication. */
+ if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
+ printk(KERN_DEBUG "%s: unexpected IBSS authentication "
+ "frame (alg=%d transaction=%d)\n",
+ dev->name, auth_alg, auth_transaction);
+ return;
+ }
+ ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0);
+ }
+
+ if (auth_alg != ifsta->auth_alg ||
+ auth_transaction != ifsta->auth_transaction) {
+ printk(KERN_DEBUG "%s: unexpected authentication frame "
+ "(alg=%d transaction=%d)\n",
+ dev->name, auth_alg, auth_transaction);
+ return;
+ }
+
+ if (status_code != WLAN_STATUS_SUCCESS) {
+ printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d "
+ "code=%d)\n", dev->name, ifsta->auth_alg, status_code);
+ if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
+ u8 algs[3];
+ const int num_algs = ARRAY_SIZE(algs);
+ int i, pos;
+ algs[0] = algs[1] = algs[2] = 0xff;
+ if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
+ algs[0] = WLAN_AUTH_OPEN;
+ if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+ algs[1] = WLAN_AUTH_SHARED_KEY;
+ if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
+ algs[2] = WLAN_AUTH_LEAP;
+ if (ifsta->auth_alg == WLAN_AUTH_OPEN)
+ pos = 0;
+ else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY)
+ pos = 1;
+ else
+ pos = 2;
+ for (i = 0; i < num_algs; i++) {
+ pos++;
+ if (pos >= num_algs)
+ pos = 0;
+ if (algs[pos] == ifsta->auth_alg ||
+ algs[pos] == 0xff)
+ continue;
+ if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
+ !ieee80211_sta_wep_configured(dev))
+ continue;
+ ifsta->auth_alg = algs[pos];
+ printk(KERN_DEBUG "%s: set auth_alg=%d for "
+ "next try\n",
+ dev->name, ifsta->auth_alg);
+ break;
+ }
+ }
+ return;
+ }
+
+ switch (ifsta->auth_alg) {
+ case WLAN_AUTH_OPEN:
+ case WLAN_AUTH_LEAP:
+ ieee80211_auth_completed(dev, ifsta);
+ break;
+ case WLAN_AUTH_SHARED_KEY:
+ if (ifsta->auth_transaction == 4)
+ ieee80211_auth_completed(dev, ifsta);
+ else
+ ieee80211_auth_challenge(dev, ifsta, mgmt, len);
+ break;
+ }
+}
+
+
+static void ieee80211_rx_mgmt_deauth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u16 reason_code;
+
+ if (len < 24 + 2) {
+ printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame "
+ "received from " MAC_FMT " - ignored\n",
+ dev->name, len, MAC_ARG(mgmt->sa));
+ return;
+ }
+
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ printk(KERN_DEBUG "%s: deauthentication frame received from "
+ "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+ "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+ MAC_ARG(mgmt->bssid));
+ return;
+ }
+
+ reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
+
+ printk(KERN_DEBUG "%s: RX deauthentication from " MAC_FMT
+ " (reason=%d)\n",
+ dev->name, MAC_ARG(mgmt->sa), reason_code);
+
+ if (ifsta->authenticated) {
+ printk(KERN_DEBUG "%s: deauthenticated\n", dev->name);
+ }
+
+ if (ifsta->state == IEEE80211_AUTHENTICATE ||
+ ifsta->state == IEEE80211_ASSOCIATE ||
+ ifsta->state == IEEE80211_ASSOCIATED) {
+ ifsta->state = IEEE80211_AUTHENTICATE;
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_RETRY_AUTH_INTERVAL);
+ }
+
+ ieee80211_set_disassoc(dev, ifsta, 1);
+ ifsta->authenticated = 0;
+}
+
+
+static void ieee80211_rx_mgmt_disassoc(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ u16 reason_code;
+
+ if (len < 24 + 2) {
+ printk(KERN_DEBUG "%s: too short (%zd) disassociation frame "
+ "received from " MAC_FMT " - ignored\n",
+ dev->name, len, MAC_ARG(mgmt->sa));
+ return;
+ }
+
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ printk(KERN_DEBUG "%s: disassociation frame received from "
+ "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+ "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+ MAC_ARG(mgmt->bssid));
+ return;
+ }
+
+ reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
+
+ printk(KERN_DEBUG "%s: RX disassociation from " MAC_FMT
+ " (reason=%d)\n",
+ dev->name, MAC_ARG(mgmt->sa), reason_code);
+
+ if (ifsta->associated)
+ printk(KERN_DEBUG "%s: disassociated\n", dev->name);
+
+ if (ifsta->state == IEEE80211_ASSOCIATED) {
+ ifsta->state = IEEE80211_ASSOCIATE;
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_RETRY_AUTH_INTERVAL);
+ }
+
+ ieee80211_set_disassoc(dev, ifsta, 0);
+}
+
+
+static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ int reassoc)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ struct sta_info *sta;
+ u32 rates;
+ u16 capab_info, status_code, aid;
+ struct ieee802_11_elems elems;
+ u8 *pos;
+ int i, j;
+
+ /* AssocResp and ReassocResp have identical structure, so process both
+ * of them in this function. */
+
+ if (ifsta->state != IEEE80211_ASSOCIATE) {
+ printk(KERN_DEBUG "%s: association frame received from "
+ MAC_FMT ", but not in associate state - ignored\n",
+ dev->name, MAC_ARG(mgmt->sa));
+ return;
+ }
+
+ if (len < 24 + 6) {
+ printk(KERN_DEBUG "%s: too short (%zd) association frame "
+ "received from " MAC_FMT " - ignored\n",
+ dev->name, len, MAC_ARG(mgmt->sa));
+ return;
+ }
+
+ if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ printk(KERN_DEBUG "%s: association frame received from "
+ "unknown AP (SA=" MAC_FMT " BSSID=" MAC_FMT ") - "
+ "ignored\n", dev->name, MAC_ARG(mgmt->sa),
+ MAC_ARG(mgmt->bssid));
+ return;
+ }
+
+ capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
+ status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+ if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+ printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
+ "set\n", dev->name, aid);
+ aid &= ~(BIT(15) | BIT(14));
+
+ printk(KERN_DEBUG "%s: RX %sssocResp from " MAC_FMT " (capab=0x%x "
+ "status=%d aid=%d)\n",
+ dev->name, reassoc ? "Rea" : "A", MAC_ARG(mgmt->sa),
+ capab_info, status_code, aid);
+
+ if (status_code != WLAN_STATUS_SUCCESS) {
+ printk(KERN_DEBUG "%s: AP denied association (code=%d)\n",
+ dev->name, status_code);
+ return;
+ }
+
+ pos = mgmt->u.assoc_resp.variable;
+ if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+ == ParseFailed) {
+ printk(KERN_DEBUG "%s: failed to parse AssocResp\n",
+ dev->name);
+ return;
+ }
+
+ if (!elems.supp_rates) {
+ printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n",
+ dev->name);
+ return;
+ }
+
+ printk(KERN_DEBUG "%s: associated\n", dev->name);
+ ifsta->aid = aid;
+ ifsta->ap_capab = capab_info;
+
+ kfree(ifsta->assocresp_ies);
+ ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt);
+ ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_ATOMIC);
+ if (ifsta->assocresp_ies)
+ memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
+
+ ieee80211_set_associated(dev, ifsta, 1);
+
+ /* Add STA entry for the AP */
+ sta = sta_info_get(local, ifsta->bssid);
+ if (!sta) {
+ struct ieee80211_sta_bss *bss;
+ sta = sta_info_add(local, dev, ifsta->bssid, GFP_ATOMIC);
+ if (!sta) {
+ printk(KERN_DEBUG "%s: failed to add STA entry for the"
+ " AP\n", dev->name);
+ return;
+ }
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ sta->last_rssi = bss->rssi;
+ sta->last_signal = bss->signal;
+ sta->last_noise = bss->noise;
+ ieee80211_rx_bss_put(dev, bss);
+ }
+ }
+
+ sta->dev = dev;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ sta->assoc_ap = 1;
+
+ rates = 0;
+ mode = local->oper_hw_mode;
+ for (i = 0; i < elems.supp_rates_len; i++) {
+ int rate = (elems.supp_rates[i] & 0x7f) * 5;
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ rate *= 2;
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == rate)
+ rates |= BIT(j);
+ }
+ for (i = 0; i < elems.ext_supp_rates_len; i++) {
+ int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ rate *= 2;
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == rate)
+ rates |= BIT(j);
+ }
+ sta->supp_rates = rates;
+
+ rate_control_rate_init(sta, local);
+
+ if (elems.wmm_param && ifsta->wmm_enabled) {
+ sta->flags |= WLAN_STA_WME;
+ ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+ elems.wmm_param_len);
+ }
+
+
+ sta_info_put(sta);
+
+ ieee80211_associated(dev, ifsta);
+}
+
+
+/* Caller must hold local->sta_bss_lock */
+static void __ieee80211_rx_bss_hash_add(struct net_device *dev,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)];
+ local->sta_bss_hash[STA_HASH(bss->bssid)] = bss;
+}
+
+
+/* Caller must hold local->sta_bss_lock */
+static void __ieee80211_rx_bss_hash_del(struct net_device *dev,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *b, *prev = NULL;
+ b = local->sta_bss_hash[STA_HASH(bss->bssid)];
+ while (b) {
+ if (b == bss) {
+ if (!prev)
+ local->sta_bss_hash[STA_HASH(bss->bssid)] =
+ bss->hnext;
+ else
+ prev->hnext = bss->hnext;
+ break;
+ }
+ prev = b;
+ b = b->hnext;
+ }
+}
+
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+
+ bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ if (!bss)
+ return NULL;
+ memset(bss, 0, sizeof(*bss));
+ atomic_inc(&bss->users);
+ atomic_inc(&bss->users);
+ memcpy(bss->bssid, bssid, ETH_ALEN);
+
+ spin_lock_bh(&local->sta_bss_lock);
+ /* TODO: order by RSSI? */
+ list_add_tail(&bss->list, &local->sta_bss_list);
+ __ieee80211_rx_bss_hash_add(dev, bss);
+ spin_unlock_bh(&local->sta_bss_lock);
+ return bss;
+}
+
+
+static struct ieee80211_sta_bss *
+ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+
+ spin_lock_bh(&local->sta_bss_lock);
+ bss = local->sta_bss_hash[STA_HASH(bssid)];
+ while (bss) {
+ if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) {
+ atomic_inc(&bss->users);
+ break;
+ }
+ bss = bss->hnext;
+ }
+ spin_unlock_bh(&local->sta_bss_lock);
+ return bss;
+}
+
+
+static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss)
+{
+ kfree(bss->wpa_ie);
+ kfree(bss->rsn_ie);
+ kfree(bss->wmm_ie);
+ kfree(bss);
+}
+
+
+static void ieee80211_rx_bss_put(struct net_device *dev,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ if (!atomic_dec_and_test(&bss->users))
+ return;
+
+ spin_lock_bh(&local->sta_bss_lock);
+ __ieee80211_rx_bss_hash_del(dev, bss);
+ list_del(&bss->list);
+ spin_unlock_bh(&local->sta_bss_lock);
+ ieee80211_rx_bss_free(bss);
+}
+
+
+void ieee80211_rx_bss_list_init(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ spin_lock_init(&local->sta_bss_lock);
+ INIT_LIST_HEAD(&local->sta_bss_list);
+}
+
+
+void ieee80211_rx_bss_list_deinit(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss, *tmp;
+
+ list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list)
+ ieee80211_rx_bss_put(dev, bss);
+}
+
+
+static void ieee80211_rx_bss_info(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status,
+ int beacon)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee802_11_elems elems;
+ size_t baselen;
+ int channel, invalid = 0, clen;
+ struct ieee80211_sta_bss *bss;
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ u64 timestamp;
+
+ if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN))
+ return; /* ignore ProbeResp to foreign address */
+
+#if 0
+ printk(KERN_DEBUG "%s: RX %s from " MAC_FMT " to " MAC_FMT "\n",
+ dev->name, beacon ? "Beacon" : "Probe Response",
+ MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da));
+#endif
+
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ timestamp = le64_to_cpu(mgmt->u.beacon.timestamp);
+
+ if (sdata->type == IEEE80211_IF_TYPE_IBSS && beacon &&
+ memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ static unsigned long last_tsf_debug = 0;
+ u64 tsf;
+ if (local->ops->get_tsf)
+ tsf = local->ops->get_tsf(local_to_hw(local));
+ else
+ tsf = -1LLU;
+ if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
+ printk(KERN_DEBUG "RX beacon SA=" MAC_FMT " BSSID="
+ MAC_FMT " TSF=0x%llx BCN=0x%llx diff=%lld "
+ "@%lu\n",
+ MAC_ARG(mgmt->sa), MAC_ARG(mgmt->bssid),
+ (unsigned long long)tsf,
+ (unsigned long long)timestamp,
+ (unsigned long long)(tsf - timestamp),
+ jiffies);
+ last_tsf_debug = jiffies;
+ }
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ }
+
+ if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
+ &elems) == ParseFailed)
+ invalid = 1;
+
+ if (sdata->type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates &&
+ memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 &&
+ (sta = sta_info_get(local, mgmt->sa))) {
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_rate *rates;
+ size_t num_rates;
+ u32 supp_rates, prev_rates;
+ int i, j;
+
+ mode = local->sta_scanning ?
+ local->scan_hw_mode : local->oper_hw_mode;
+ rates = mode->rates;
+ num_rates = mode->num_rates;
+
+ supp_rates = 0;
+ for (i = 0; i < elems.supp_rates_len +
+ elems.ext_supp_rates_len; i++) {
+ u8 rate = 0;
+ int own_rate;
+ if (i < elems.supp_rates_len)
+ rate = elems.supp_rates[i];
+ else if (elems.ext_supp_rates)
+ rate = elems.ext_supp_rates
+ [i - elems.supp_rates_len];
+ own_rate = 5 * (rate & 0x7f);
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ own_rate *= 2;
+ for (j = 0; j < num_rates; j++)
+ if (rates[j].rate == own_rate)
+ supp_rates |= BIT(j);
+ }
+
+ prev_rates = sta->supp_rates;
+ sta->supp_rates &= supp_rates;
+ if (sta->supp_rates == 0) {
+ /* No matching rates - this should not really happen.
+ * Make sure that at least one rate is marked
+ * supported to avoid issues with TX rate ctrl. */
+ sta->supp_rates = sdata->u.sta.supp_rates_bits;
+ }
+ if (sta->supp_rates != prev_rates) {
+ printk(KERN_DEBUG "%s: updated supp_rates set for "
+ MAC_FMT " based on beacon info (0x%x & 0x%x -> "
+ "0x%x)\n",
+ dev->name, MAC_ARG(sta->addr), prev_rates,
+ supp_rates, sta->supp_rates);
+ }
+ sta_info_put(sta);
+ }
+
+ if (!elems.ssid)
+ return;
+
+ if (elems.ds_params && elems.ds_params_len == 1)
+ channel = elems.ds_params[0];
+ else
+ channel = rx_status->channel;
+
+ bss = ieee80211_rx_bss_get(dev, mgmt->bssid);
+ if (!bss) {
+ bss = ieee80211_rx_bss_add(dev, mgmt->bssid);
+ if (!bss)
+ return;
+ } else {
+#if 0
+ /* TODO: order by RSSI? */
+ spin_lock_bh(&local->sta_bss_lock);
+ list_move_tail(&bss->list, &local->sta_bss_list);
+ spin_unlock_bh(&local->sta_bss_lock);
+#endif
+ }
+
+ if (bss->probe_resp && beacon) {
+ /* Do not allow beacon to override data from Probe Response. */
+ ieee80211_rx_bss_put(dev, bss);
+ return;
+ }
+
+ bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
+ bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
+ if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
+ memcpy(bss->ssid, elems.ssid, elems.ssid_len);
+ bss->ssid_len = elems.ssid_len;
+ }
+
+ bss->supp_rates_len = 0;
+ if (elems.supp_rates) {
+ clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+ if (clen > elems.supp_rates_len)
+ clen = elems.supp_rates_len;
+ memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates,
+ clen);
+ bss->supp_rates_len += clen;
+ }
+ if (elems.ext_supp_rates) {
+ clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+ if (clen > elems.ext_supp_rates_len)
+ clen = elems.ext_supp_rates_len;
+ memcpy(&bss->supp_rates[bss->supp_rates_len],
+ elems.ext_supp_rates, clen);
+ bss->supp_rates_len += clen;
+ }
+
+ if (elems.wpa &&
+ (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len ||
+ memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC);
+ if (bss->wpa_ie) {
+ memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2);
+ bss->wpa_ie_len = elems.wpa_len + 2;
+ } else
+ bss->wpa_ie_len = 0;
+ } else if (!elems.wpa && bss->wpa_ie) {
+ kfree(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ bss->wpa_ie_len = 0;
+ }
+
+ if (elems.rsn &&
+ (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len ||
+ memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC);
+ if (bss->rsn_ie) {
+ memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2);
+ bss->rsn_ie_len = elems.rsn_len + 2;
+ } else
+ bss->rsn_ie_len = 0;
+ } else if (!elems.rsn && bss->rsn_ie) {
+ kfree(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ bss->rsn_ie_len = 0;
+ }
+
+ if (elems.wmm_param &&
+ (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len ||
+ memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
+ kfree(bss->wmm_ie);
+ bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC);
+ if (bss->wmm_ie) {
+ memcpy(bss->wmm_ie, elems.wmm_param - 2,
+ elems.wmm_param_len + 2);
+ bss->wmm_ie_len = elems.wmm_param_len + 2;
+ } else
+ bss->wmm_ie_len = 0;
+ } else if (!elems.wmm_param && bss->wmm_ie) {
+ kfree(bss->wmm_ie);
+ bss->wmm_ie = NULL;
+ bss->wmm_ie_len = 0;
+ }
+
+
+ bss->hw_mode = rx_status->phymode;
+ bss->channel = channel;
+ bss->freq = rx_status->freq;
+ if (channel != rx_status->channel &&
+ (bss->hw_mode == MODE_IEEE80211G ||
+ bss->hw_mode == MODE_IEEE80211B) &&
+ channel >= 1 && channel <= 14) {
+ static const int freq_list[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+ };
+ /* IEEE 802.11g/b mode can receive packets from neighboring
+ * channels, so map the channel into frequency. */
+ bss->freq = freq_list[channel - 1];
+ }
+ bss->timestamp = timestamp;
+ bss->last_update = jiffies;
+ bss->rssi = rx_status->ssi;
+ bss->signal = rx_status->signal;
+ bss->noise = rx_status->noise;
+ if (!beacon)
+ bss->probe_resp++;
+ ieee80211_rx_bss_put(dev, bss);
+}
+
+
+static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0);
+}
+
+
+static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_sta *ifsta;
+ int use_protection;
+ size_t baselen;
+ struct ieee802_11_elems elems;
+
+ ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return;
+ ifsta = &sdata->u.sta;
+
+ if (!ifsta->associated ||
+ memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
+ return;
+
+ /* Process beacon from the current BSS */
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
+ &elems) == ParseFailed)
+ return;
+
+ use_protection = 0;
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ use_protection =
+ (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
+ }
+
+ if (use_protection != !!ifsta->use_protection) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+ MAC_FMT ")\n",
+ dev->name,
+ use_protection ? "enabled" : "disabled",
+ MAC_ARG(ifsta->bssid));
+ }
+ ifsta->use_protection = use_protection ? 1 : 0;
+ local->cts_protect_erp_frames = use_protection;
+ }
+
+ if (elems.wmm_param && ifsta->wmm_enabled) {
+ ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
+ elems.wmm_param_len);
+ }
+}
+
+
+static void ieee80211_rx_mgmt_probe_req(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ int tx_last_beacon;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *resp;
+ u8 *pos, *end;
+
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS ||
+ ifsta->state != IEEE80211_IBSS_JOINED ||
+ len < 24 + 2 || !ifsta->probe_resp)
+ return;
+
+ if (local->ops->tx_last_beacon)
+ tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));
+ else
+ tx_last_beacon = 1;
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG "%s: RX ProbeReq SA=" MAC_FMT " DA=" MAC_FMT " BSSID="
+ MAC_FMT " (tx_last_beacon=%d)\n",
+ dev->name, MAC_ARG(mgmt->sa), MAC_ARG(mgmt->da),
+ MAC_ARG(mgmt->bssid), tx_last_beacon);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+ if (!tx_last_beacon)
+ return;
+
+ if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 &&
+ memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+ return;
+
+ end = ((u8 *) mgmt) + len;
+ pos = mgmt->u.probe_req.variable;
+ if (pos[0] != WLAN_EID_SSID ||
+ pos + 2 + pos[1] > end) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
+ "from " MAC_FMT "\n",
+ dev->name, MAC_ARG(mgmt->sa));
+ }
+ return;
+ }
+ if (pos[1] != 0 &&
+ (pos[1] != ifsta->ssid_len ||
+ memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) {
+ /* Ignore ProbeReq for foreign SSID */
+ return;
+ }
+
+ /* Reply with ProbeResp */
+ skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ resp = (struct ieee80211_mgmt *) skb->data;
+ memcpy(resp->da, mgmt->sa, ETH_ALEN);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG "%s: Sending ProbeResp to " MAC_FMT "\n",
+ dev->name, MAC_ARG(resp->da));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ ieee80211_sta_tx(dev, skb, 0);
+}
+
+
+void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_sta *ifsta;
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ if (skb->len < 24)
+ goto fail;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ fc = le16_to_cpu(mgmt->frame_control);
+
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_REQ:
+ case IEEE80211_STYPE_PROBE_RESP:
+ case IEEE80211_STYPE_BEACON:
+ memcpy(skb->cb, rx_status, sizeof(*rx_status));
+ case IEEE80211_STYPE_AUTH:
+ case IEEE80211_STYPE_ASSOC_RESP:
+ case IEEE80211_STYPE_REASSOC_RESP:
+ case IEEE80211_STYPE_DEAUTH:
+ case IEEE80211_STYPE_DISASSOC:
+ skb_queue_tail(&ifsta->skb_queue, skb);
+ queue_work(local->hw.workqueue, &ifsta->work);
+ return;
+ default:
+ printk(KERN_DEBUG "%s: received unknown management frame - "
+ "stype=%d\n", dev->name,
+ (fc & IEEE80211_FCTL_STYPE) >> 4);
+ break;
+ }
+
+ fail:
+ kfree_skb(skb);
+}
+
+
+static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ struct ieee80211_rx_status *rx_status;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_sta *ifsta;
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+
+ rx_status = (struct ieee80211_rx_status *) skb->cb;
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ fc = le16_to_cpu(mgmt->frame_control);
+
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PROBE_REQ:
+ ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len,
+ rx_status);
+ break;
+ case IEEE80211_STYPE_PROBE_RESP:
+ ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status);
+ break;
+ case IEEE80211_STYPE_BEACON:
+ ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status);
+ break;
+ case IEEE80211_STYPE_AUTH:
+ ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_ASSOC_RESP:
+ ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 0);
+ break;
+ case IEEE80211_STYPE_REASSOC_RESP:
+ ieee80211_rx_mgmt_assoc_resp(dev, ifsta, mgmt, skb->len, 1);
+ break;
+ case IEEE80211_STYPE_DEAUTH:
+ ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len);
+ break;
+ case IEEE80211_STYPE_DISASSOC:
+ ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len);
+ break;
+ }
+
+ kfree_skb(skb);
+}
+
+
+void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ if (skb->len < 24) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
+ mgmt = (struct ieee80211_mgmt *) skb->data;
+ fc = le16_to_cpu(mgmt->frame_control);
+
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+ if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
+ ieee80211_rx_mgmt_probe_resp(dev, mgmt,
+ skb->len, rx_status);
+ } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
+ ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
+ rx_status);
+ }
+ }
+
+ dev_kfree_skb(skb);
+}
+
+
+static int ieee80211_sta_active_ibss(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ int active = 0;
+ struct sta_info *sta;
+
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ if (sta->dev == dev &&
+ time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
+ jiffies)) {
+ active++;
+ break;
+ }
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ return active;
+}
+
+
+static void ieee80211_sta_expire(struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta, *tmp;
+
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
+ if (time_after(jiffies, sta->last_rx +
+ IEEE80211_IBSS_INACTIVITY_LIMIT)) {
+ printk(KERN_DEBUG "%s: expiring inactive STA " MAC_FMT
+ "\n", dev->name, MAC_ARG(sta->addr));
+ sta_info_free(sta, 1);
+ }
+ spin_unlock_bh(&local->sta_lock);
+}
+
+
+static void ieee80211_sta_merge_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+ ieee80211_sta_expire(dev);
+ if (ieee80211_sta_active_ibss(dev))
+ return;
+
+ printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
+ "IBSS networks with same SSID (merge)\n", dev->name);
+ ieee80211_sta_req_scan(dev, ifsta->ssid, ifsta->ssid_len);
+}
+
+
+void ieee80211_sta_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_local *local = wdev_priv(&sdata->wdev);
+
+ set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+ queue_work(local->hw.workqueue, &ifsta->work);
+}
+
+
+void ieee80211_sta_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, u.sta.work);
+ struct net_device *dev = sdata->dev;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_if_sta *ifsta;
+ struct sk_buff *skb;
+
+ if (!netif_running(dev))
+ return;
+
+ if (local->sta_scanning)
+ return;
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS) {
+ printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface "
+ "(type=%d)\n", dev->name, sdata->type);
+ return;
+ }
+ ifsta = &sdata->u.sta;
+
+ while ((skb = skb_dequeue(&ifsta->skb_queue)))
+ ieee80211_sta_rx_queued_mgmt(dev, skb);
+
+ if (ifsta->state != IEEE80211_AUTHENTICATE &&
+ ifsta->state != IEEE80211_ASSOCIATE &&
+ test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
+ ieee80211_sta_start_scan(dev, NULL, 0);
+ return;
+ }
+
+ if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
+ if (ieee80211_sta_config_auth(dev, ifsta))
+ return;
+ clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
+ } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
+ return;
+
+ switch (ifsta->state) {
+ case IEEE80211_DISABLED:
+ break;
+ case IEEE80211_AUTHENTICATE:
+ ieee80211_authenticate(dev, ifsta);
+ break;
+ case IEEE80211_ASSOCIATE:
+ ieee80211_associate(dev, ifsta);
+ break;
+ case IEEE80211_ASSOCIATED:
+ ieee80211_associated(dev, ifsta);
+ break;
+ case IEEE80211_IBSS_SEARCH:
+ ieee80211_sta_find_ibss(dev, ifsta);
+ break;
+ case IEEE80211_IBSS_JOINED:
+ ieee80211_sta_merge_ibss(dev, ifsta);
+ break;
+ default:
+ printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n",
+ ifsta->state);
+ break;
+ }
+
+ if (ieee80211_privacy_mismatch(dev, ifsta)) {
+ printk(KERN_DEBUG "%s: privacy configuration mismatch and "
+ "mixed-cell disabled - disassociate\n", dev->name);
+
+ ieee80211_send_disassoc(dev, ifsta, WLAN_REASON_UNSPECIFIED);
+ ieee80211_set_disassoc(dev, ifsta, 0);
+ }
+}
+
+
+static void ieee80211_sta_reset_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+
+ ifsta->wmm_last_param_set = -1; /* allow any WMM update */
+
+
+ if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
+ ifsta->auth_alg = WLAN_AUTH_OPEN;
+ else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+ ifsta->auth_alg = WLAN_AUTH_SHARED_KEY;
+ else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
+ ifsta->auth_alg = WLAN_AUTH_LEAP;
+ else
+ ifsta->auth_alg = WLAN_AUTH_OPEN;
+ printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name,
+ ifsta->auth_alg);
+ ifsta->auth_transaction = -1;
+ ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0;
+ netif_carrier_off(dev);
+}
+
+
+void ieee80211_sta_req_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return;
+
+ if ((ifsta->bssid_set || ifsta->auto_bssid_sel) &&
+ (ifsta->ssid_set || ifsta->auto_ssid_sel)) {
+ set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+ queue_work(local->hw.workqueue, &ifsta->work);
+ }
+}
+
+static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta,
+ const char *ssid, int ssid_len)
+{
+ int tmp, hidden_ssid;
+
+ if (!memcmp(ifsta->ssid, ssid, ssid_len))
+ return 1;
+
+ if (ifsta->auto_bssid_sel)
+ return 0;
+
+ hidden_ssid = 1;
+ tmp = ssid_len;
+ while (tmp--) {
+ if (ssid[tmp] != '\0') {
+ hidden_ssid = 0;
+ break;
+ }
+ }
+
+ if (hidden_ssid && ifsta->ssid_len == ssid_len)
+ return 1;
+
+ if (ssid_len == 1 && ssid[0] == ' ')
+ return 1;
+
+ return 0;
+}
+
+static int ieee80211_sta_config_auth(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sta_bss *bss, *selected = NULL;
+ int top_rssi = 0, freq;
+
+ rtnl_lock();
+
+ if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
+ !ifsta->auto_ssid_sel) {
+ ifsta->state = IEEE80211_AUTHENTICATE;
+ rtnl_unlock();
+ ieee80211_sta_reset_auth(dev, ifsta);
+ return 0;
+ }
+
+ spin_lock_bh(&local->sta_bss_lock);
+ freq = local->oper_channel->freq;
+ list_for_each_entry(bss, &local->sta_bss_list, list) {
+ if (!(bss->capability & WLAN_CAPABILITY_ESS))
+ continue;
+
+ if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^
+ !!sdata->default_key)
+ continue;
+
+ if (!ifsta->auto_channel_sel && bss->freq != freq)
+ continue;
+
+ if (!ifsta->auto_bssid_sel &&
+ memcmp(bss->bssid, ifsta->bssid, ETH_ALEN))
+ continue;
+
+ if (!ifsta->auto_ssid_sel &&
+ !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len))
+ continue;
+
+ if (!selected || top_rssi < bss->rssi) {
+ selected = bss;
+ top_rssi = bss->rssi;
+ }
+ }
+ if (selected)
+ atomic_inc(&selected->users);
+ spin_unlock_bh(&local->sta_bss_lock);
+
+ if (selected) {
+ ieee80211_set_channel(local, -1, selected->freq);
+ if (!ifsta->ssid_set)
+ ieee80211_sta_set_ssid(dev, selected->ssid,
+ selected->ssid_len);
+ ieee80211_sta_set_bssid(dev, selected->bssid);
+ ieee80211_rx_bss_put(dev, selected);
+ ifsta->state = IEEE80211_AUTHENTICATE;
+ rtnl_unlock();
+ ieee80211_sta_reset_auth(dev, ifsta);
+ return 0;
+ } else {
+ if (ifsta->state != IEEE80211_AUTHENTICATE) {
+ ieee80211_sta_start_scan(dev, NULL, 0);
+ ifsta->state = IEEE80211_AUTHENTICATE;
+ set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+ } else
+ ifsta->state = IEEE80211_DISABLED;
+ }
+ rtnl_unlock();
+ return -1;
+}
+
+static int ieee80211_sta_join_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ int res, rates, i, j;
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_tx_control control;
+ struct ieee80211_rate *rate;
+ struct ieee80211_hw_mode *mode;
+ struct rate_control_extra extra;
+ u8 *pos;
+ struct ieee80211_sub_if_data *sdata;
+
+ /* Remove possible STA entries from other IBSS networks. */
+ sta_info_flush(local, NULL);
+
+ if (local->ops->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->ops->reset_tsf(local_to_hw(local));
+ }
+ memcpy(ifsta->bssid, bss->bssid, ETH_ALEN);
+ res = ieee80211_if_config(dev);
+ if (res)
+ return res;
+
+ local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ sdata->drop_unencrypted = bss->capability &
+ WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+ res = ieee80211_set_channel(local, -1, bss->freq);
+
+ if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) {
+ printk(KERN_DEBUG "%s: IBSS not allowed on channel %d "
+ "(%d MHz)\n", dev->name, local->hw.conf.channel,
+ local->hw.conf.freq);
+ return -1;
+ }
+
+ /* Set beacon template based on scan results */
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ do {
+ if (!skb)
+ break;
+
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+ memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_BEACON);
+ memset(mgmt->da, 0xff, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+ mgmt->u.beacon.beacon_int =
+ cpu_to_le16(local->hw.conf.beacon_int);
+ mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability);
+
+ pos = skb_put(skb, 2 + ifsta->ssid_len);
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ifsta->ssid_len;
+ memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+
+ rates = bss->supp_rates_len;
+ if (rates > 8)
+ rates = 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, bss->supp_rates, rates);
+
+ pos = skb_put(skb, 2 + 1);
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = bss->channel;
+
+ pos = skb_put(skb, 2 + 2);
+ *pos++ = WLAN_EID_IBSS_PARAMS;
+ *pos++ = 2;
+ /* FIX: set ATIM window based on scan results */
+ *pos++ = 0;
+ *pos++ = 0;
+
+ if (bss->supp_rates_len > 8) {
+ rates = bss->supp_rates_len - 8;
+ pos = skb_put(skb, 2 + rates);
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = rates;
+ memcpy(pos, &bss->supp_rates[8], rates);
+ }
+
+ memset(&control, 0, sizeof(control));
+ memset(&extra, 0, sizeof(extra));
+ extra.mode = local->oper_hw_mode;
+ rate = rate_control_get_rate(local, dev, skb, &extra);
+ if (!rate) {
+ printk(KERN_DEBUG "%s: Failed to determine TX rate "
+ "for IBSS beacon\n", dev->name);
+ break;
+ }
+ control.tx_rate = (local->short_preamble &&
+ (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+ rate->val2 : rate->val;
+ control.antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ control.power_level = local->hw.conf.power_level;
+ control.flags |= IEEE80211_TXCTL_NO_ACK;
+ control.retry_limit = 1;
+
+ ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC);
+ if (ifsta->probe_resp) {
+ mgmt = (struct ieee80211_mgmt *)
+ ifsta->probe_resp->data;
+ mgmt->frame_control =
+ IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_PROBE_RESP);
+ } else {
+ printk(KERN_DEBUG "%s: Could not allocate ProbeResp "
+ "template for IBSS\n", dev->name);
+ }
+
+ if (local->ops->beacon_update &&
+ local->ops->beacon_update(local_to_hw(local),
+ skb, &control) == 0) {
+ printk(KERN_DEBUG "%s: Configured IBSS beacon "
+ "template based on scan results\n", dev->name);
+ skb = NULL;
+ }
+
+ rates = 0;
+ mode = local->oper_hw_mode;
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ bitrate *= 2;
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == bitrate)
+ rates |= BIT(j);
+ }
+ ifsta->supp_rates_bits = rates;
+ } while (0);
+
+ if (skb) {
+ printk(KERN_DEBUG "%s: Failed to configure IBSS beacon "
+ "template\n", dev->name);
+ dev_kfree_skb(skb);
+ }
+
+ ifsta->state = IEEE80211_IBSS_JOINED;
+ mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+ ieee80211_rx_bss_put(dev, bss);
+
+ return res;
+}
+
+
+static int ieee80211_sta_create_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
+ u8 bssid[ETH_ALEN], *pos;
+ int i;
+
+#if 0
+ /* Easier testing, use fixed BSSID. */
+ memset(bssid, 0xfe, ETH_ALEN);
+#else
+ /* Generate random, not broadcast, locally administered BSSID. Mix in
+ * own MAC address to make sure that devices that do not have proper
+ * random number generator get different BSSID. */
+ get_random_bytes(bssid, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++)
+ bssid[i] ^= dev->dev_addr[i];
+ bssid[0] &= ~0x01;
+ bssid[0] |= 0x02;
+#endif
+
+ printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID " MAC_FMT "\n",
+ dev->name, MAC_ARG(bssid));
+
+ bss = ieee80211_rx_bss_add(dev, bssid);
+ if (!bss)
+ return -ENOMEM;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ mode = local->oper_hw_mode;
+
+ if (local->hw.conf.beacon_int == 0)
+ local->hw.conf.beacon_int = 100;
+ bss->beacon_int = local->hw.conf.beacon_int;
+ bss->hw_mode = local->hw.conf.phymode;
+ bss->channel = local->hw.conf.channel;
+ bss->freq = local->hw.conf.freq;
+ bss->last_update = jiffies;
+ bss->capability = WLAN_CAPABILITY_IBSS;
+ if (sdata->default_key) {
+ bss->capability |= WLAN_CAPABILITY_PRIVACY;
+ } else
+ sdata->drop_unencrypted = 0;
+ bss->supp_rates_len = mode->num_rates;
+ pos = bss->supp_rates;
+ for (i = 0; i < mode->num_rates; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
+ rate /= 2;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ return ieee80211_sta_join_ibss(dev, ifsta, bss);
+}
+
+
+static int ieee80211_sta_find_ibss(struct net_device *dev,
+ struct ieee80211_if_sta *ifsta)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sta_bss *bss;
+ int found = 0;
+ u8 bssid[ETH_ALEN];
+ int active_ibss;
+
+ if (ifsta->ssid_len == 0)
+ return -EINVAL;
+
+ active_ibss = ieee80211_sta_active_ibss(dev);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
+ dev->name, active_ibss);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ spin_lock_bh(&local->sta_bss_lock);
+ list_for_each_entry(bss, &local->sta_bss_list, list) {
+ if (ifsta->ssid_len != bss->ssid_len ||
+ memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0
+ || !(bss->capability & WLAN_CAPABILITY_IBSS))
+ continue;
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG " bssid=" MAC_FMT " found\n",
+ MAC_ARG(bss->bssid));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ memcpy(bssid, bss->bssid, ETH_ALEN);
+ found = 1;
+ if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0)
+ break;
+ }
+ spin_unlock_bh(&local->sta_bss_lock);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG " sta_find_ibss: selected " MAC_FMT " current "
+ MAC_FMT "\n", MAC_ARG(bssid), MAC_ARG(ifsta->bssid));
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 &&
+ (bss = ieee80211_rx_bss_get(dev, bssid))) {
+ printk(KERN_DEBUG "%s: Selected IBSS BSSID " MAC_FMT
+ " based on configured SSID\n",
+ dev->name, MAC_ARG(bssid));
+ return ieee80211_sta_join_ibss(dev, ifsta, bss);
+ }
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+ printk(KERN_DEBUG " did not try to join ibss\n");
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+ /* Selected IBSS not found in current scan results - try to scan */
+ if (ifsta->state == IEEE80211_IBSS_JOINED &&
+ !ieee80211_sta_active_ibss(dev)) {
+ mod_timer(&ifsta->timer, jiffies +
+ IEEE80211_IBSS_MERGE_INTERVAL);
+ } else if (time_after(jiffies, local->last_scan_completed +
+ IEEE80211_SCAN_INTERVAL)) {
+ printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
+ "join\n", dev->name);
+ return ieee80211_sta_req_scan(dev, ifsta->ssid,
+ ifsta->ssid_len);
+ } else if (ifsta->state != IEEE80211_IBSS_JOINED) {
+ int interval = IEEE80211_SCAN_INTERVAL;
+
+ if (time_after(jiffies, ifsta->ibss_join_req +
+ IEEE80211_IBSS_JOIN_TIMEOUT)) {
+ if (ifsta->create_ibss &&
+ local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)
+ return ieee80211_sta_create_ibss(dev, ifsta);
+ if (ifsta->create_ibss) {
+ printk(KERN_DEBUG "%s: IBSS not allowed on the"
+ " configured channel %d (%d MHz)\n",
+ dev->name, local->hw.conf.channel,
+ local->hw.conf.freq);
+ }
+
+ /* No IBSS found - decrease scan interval and continue
+ * scanning. */
+ interval = IEEE80211_SCAN_INTERVAL_SLOW;
+ }
+
+ ifsta->state = IEEE80211_IBSS_SEARCH;
+ mod_timer(&ifsta->timer, jiffies + interval);
+ return 0;
+ }
+
+ return 0;
+}
+
+
+int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_sta *ifsta;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+
+ /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
+ * not defined. */
+ if (local->ops->conf_tx) {
+ struct ieee80211_tx_queue_params qparam;
+ int i;
+
+ memset(&qparam, 0, sizeof(qparam));
+ /* TODO: are these ok defaults for all hw_modes? */
+ qparam.aifs = 2;
+ qparam.cw_min =
+ local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15;
+ qparam.cw_max = 1023;
+ qparam.burst_time = 0;
+ for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
+ {
+ local->ops->conf_tx(local_to_hw(local),
+ i + IEEE80211_TX_QUEUE_DATA0,
+ &qparam);
+ }
+ /* IBSS uses different parameters for Beacon sending */
+ qparam.cw_min++;
+ qparam.cw_min *= 2;
+ qparam.cw_min--;
+ local->ops->conf_tx(local_to_hw(local),
+ IEEE80211_TX_QUEUE_BEACON, &qparam);
+ }
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+
+ if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0)
+ ifsta->prev_bssid_set = 0;
+ memcpy(ifsta->ssid, ssid, len);
+ memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len);
+ ifsta->ssid_len = len;
+
+ ifsta->ssid_set = len ? 1 : 0;
+ if (sdata->type == IEEE80211_IF_TYPE_IBSS && !ifsta->bssid_set) {
+ ifsta->ibss_join_req = jiffies;
+ ifsta->state = IEEE80211_IBSS_SEARCH;
+ return ieee80211_sta_find_ibss(dev, ifsta);
+ }
+ return 0;
+}
+
+
+int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ memcpy(ssid, ifsta->ssid, ifsta->ssid_len);
+ *len = ifsta->ssid_len;
+ return 0;
+}
+
+
+int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_sta *ifsta;
+ int res;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ ifsta = &sdata->u.sta;
+
+ if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) {
+ memcpy(ifsta->bssid, bssid, ETH_ALEN);
+ res = ieee80211_if_config(dev);
+ if (res) {
+ printk(KERN_DEBUG "%s: Failed to config new BSSID to "
+ "the low-level driver\n", dev->name);
+ return res;
+ }
+ }
+
+ if (!is_valid_ether_addr(bssid))
+ ifsta->bssid_set = 0;
+ else
+ ifsta->bssid_set = 1;
+ return 0;
+}
+
+
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int powersave)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *nullfunc;
+ u16 fc;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS;
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+ nullfunc->frame_control = cpu_to_le16(fc);
+ memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+ ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
+void ieee80211_scan_completed(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct net_device *dev = local->scan_dev;
+ struct ieee80211_sub_if_data *sdata;
+ union iwreq_data wrqu;
+
+ local->last_scan_completed = jiffies;
+ wmb();
+ local->sta_scanning = 0;
+
+ if (ieee80211_hw_config(local))
+ printk(KERN_DEBUG "%s: failed to restore operational"
+ "channel after scan\n", dev->name);
+
+ if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
+ ieee80211_if_config(dev))
+ printk(KERN_DEBUG "%s: failed to restore operational"
+ "BSSID after scan\n", dev->name);
+
+ memset(&wrqu, 0, sizeof(wrqu));
+ wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 0);
+ ieee80211_sta_timer((unsigned long)sdata);
+ }
+ netif_wake_queue(sdata->dev);
+ }
+ read_unlock(&local->sub_if_lock);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ if (!ifsta->bssid_set ||
+ (!ifsta->state == IEEE80211_IBSS_JOINED &&
+ !ieee80211_sta_active_ibss(dev)))
+ ieee80211_sta_find_ibss(dev, ifsta);
+ }
+}
+EXPORT_SYMBOL(ieee80211_scan_completed);
+
+void ieee80211_sta_scan_work(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local, scan_work.work);
+ struct net_device *dev = local->scan_dev;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_hw_mode *mode;
+ struct ieee80211_channel *chan;
+ int skip;
+ unsigned long next_delay = 0;
+
+ if (!local->sta_scanning)
+ return;
+
+ switch (local->scan_state) {
+ case SCAN_SET_CHANNEL:
+ mode = local->scan_hw_mode;
+ if (local->scan_hw_mode->list.next == &local->modes_list &&
+ local->scan_channel_idx >= mode->num_channels) {
+ ieee80211_scan_completed(local_to_hw(local));
+ return;
+ }
+ skip = !(local->enabled_modes & (1 << mode->mode));
+ chan = &mode->channels[local->scan_channel_idx];
+ if (!(chan->flag & IEEE80211_CHAN_W_SCAN) ||
+ (sdata->type == IEEE80211_IF_TYPE_IBSS &&
+ !(chan->flag & IEEE80211_CHAN_W_IBSS)) ||
+ (local->hw_modes & local->enabled_modes &
+ (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+ skip = 1;
+
+ if (!skip) {
+#if 0
+ printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n",
+ dev->name, chan->chan, chan->freq);
+#endif
+
+ local->scan_channel = chan;
+ if (ieee80211_hw_config(local)) {
+ printk(KERN_DEBUG "%s: failed to set channel "
+ "%d (%d MHz) for scan\n", dev->name,
+ chan->chan, chan->freq);
+ skip = 1;
+ }
+ }
+
+ local->scan_channel_idx++;
+ if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) {
+ if (local->scan_hw_mode->list.next != &local->modes_list) {
+ local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next,
+ struct ieee80211_hw_mode,
+ list);
+ local->scan_channel_idx = 0;
+ }
+ }
+
+ if (skip)
+ break;
+
+ next_delay = IEEE80211_PROBE_DELAY +
+ usecs_to_jiffies(local->hw.channel_change_time);
+ local->scan_state = SCAN_SEND_PROBE;
+ break;
+ case SCAN_SEND_PROBE:
+ if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) {
+ ieee80211_send_probe_req(dev, NULL, local->scan_ssid,
+ local->scan_ssid_len);
+ next_delay = IEEE80211_CHANNEL_TIME;
+ } else
+ next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ local->scan_state = SCAN_SET_CHANNEL;
+ break;
+ }
+
+ if (local->sta_scanning)
+ queue_delayed_work(local->hw.workqueue, &local->scan_work,
+ next_delay);
+}
+
+
+static int ieee80211_sta_start_scan(struct net_device *dev,
+ u8 *ssid, size_t ssid_len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+
+ if (ssid_len > IEEE80211_MAX_SSID_LEN)
+ return -EINVAL;
+
+ /* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
+ * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
+ * BSSID: MACAddress
+ * SSID
+ * ScanType: ACTIVE, PASSIVE
+ * ProbeDelay: delay (in microseconds) to be used prior to transmitting
+ * a Probe frame during active scanning
+ * ChannelList
+ * MinChannelTime (>= ProbeDelay), in TU
+ * MaxChannelTime: (>= MinChannelTime), in TU
+ */
+
+ /* MLME-SCAN.confirm
+ * BSSDescriptionSet
+ * ResultCode: SUCCESS, INVALID_PARAMETERS
+ */
+
+ if (local->sta_scanning) {
+ if (local->scan_dev == dev)
+ return 0;
+ return -EBUSY;
+ }
+
+ if (local->ops->hw_scan) {
+ int rc = local->ops->hw_scan(local_to_hw(local),
+ ssid, ssid_len);
+ if (!rc) {
+ local->sta_scanning = 1;
+ local->scan_dev = dev;
+ }
+ return rc;
+ }
+
+ local->sta_scanning = 1;
+
+ read_lock(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ netif_stop_queue(sdata->dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ }
+ read_unlock(&local->sub_if_lock);
+
+ if (ssid) {
+ local->scan_ssid_len = ssid_len;
+ memcpy(local->scan_ssid, ssid, ssid_len);
+ } else
+ local->scan_ssid_len = 0;
+ local->scan_state = SCAN_SET_CHANNEL;
+ local->scan_hw_mode = list_entry(local->modes_list.next,
+ struct ieee80211_hw_mode,
+ list);
+ local->scan_channel_idx = 0;
+ local->scan_dev = dev;
+
+ if (!(local->hw.flags & IEEE80211_HW_NO_PROBE_FILTERING) &&
+ ieee80211_if_config(dev))
+ printk(KERN_DEBUG "%s: failed to set BSSID for scan\n",
+ dev->name);
+
+ /* TODO: start scan as soon as all nullfunc frames are ACKed */
+ queue_delayed_work(local->hw.workqueue, &local->scan_work,
+ IEEE80211_CHANNEL_TIME);
+
+ return 0;
+}
+
+
+int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return ieee80211_sta_start_scan(dev, ssid, ssid_len);
+
+ if (local->sta_scanning) {
+ if (local->scan_dev == dev)
+ return 0;
+ return -EBUSY;
+ }
+
+ set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
+ queue_work(local->hw.workqueue, &ifsta->work);
+ return 0;
+}
+
+static char *
+ieee80211_sta_scan_result(struct net_device *dev,
+ struct ieee80211_sta_bss *bss,
+ char *current_ev, char *end_buf)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct iw_event iwe;
+
+ if (time_after(jiffies,
+ bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE))
+ return current_ev;
+
+ if (!(local->enabled_modes & (1 << bss->hw_mode)))
+ return current_ev;
+
+ if (local->scan_flags & IEEE80211_SCAN_WPA_ONLY &&
+ !bss->wpa_ie && !bss->rsn_ie)
+ return current_ev;
+
+ if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID &&
+ (local->scan_ssid_len != bss->ssid_len ||
+ memcmp(local->scan_ssid, bss->ssid, bss->ssid_len) != 0))
+ return current_ev;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_ADDR_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.length = bss->ssid_len;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->ssid);
+
+ if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWMODE;
+ if (bss->capability & WLAN_CAPABILITY_ESS)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_UINT_LEN);
+ }
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = bss->channel;
+ iwe.u.freq.e = 0;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+ iwe.u.freq.m = bss->freq * 100000;
+ iwe.u.freq.e = 1;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_FREQ_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.qual = bss->signal;
+ iwe.u.qual.level = bss->rssi;
+ iwe.u.qual.noise = bss->noise;
+ iwe.u.qual.updated = local->wstats_flags;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe,
+ IW_EV_QUAL_LEN);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWENCODE;
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, "");
+
+ if (bss && bss->wpa_ie) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->wpa_ie_len;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->wpa_ie);
+ }
+
+ if (bss && bss->rsn_ie) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = bss->rsn_ie_len;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ bss->rsn_ie);
+ }
+
+ if (bss && bss->supp_rates_len > 0) {
+ /* display all supported rates in readable format */
+ char *p = current_ev + IW_EV_LCP_LEN;
+ int i;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ iwe.u.bitrate.value = ((bss->supp_rates[i] &
+ 0x7f) * 500000);
+ p = iwe_stream_add_value(current_ev, p,
+ end_buf, &iwe, IW_EV_PARAM_LEN);
+ }
+ current_ev = p;
+ }
+
+ if (bss) {
+ char *buf;
+ buf = kmalloc(30, GFP_ATOMIC);
+ if (buf) {
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp));
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, buf);
+ kfree(buf);
+ }
+ }
+
+ do {
+ char *buf;
+
+ if (!(local->scan_flags & IEEE80211_SCAN_EXTRA_INFO))
+ break;
+
+ buf = kmalloc(100, GFP_ATOMIC);
+ if (!buf)
+ break;
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "bcn_int=%d", bss->beacon_int);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ buf);
+
+ memset(&iwe, 0, sizeof(iwe));
+ iwe.cmd = IWEVCUSTOM;
+ sprintf(buf, "capab=0x%04x", bss->capability);
+ iwe.u.data.length = strlen(buf);
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe,
+ buf);
+
+ kfree(buf);
+ break;
+ } while (0);
+
+ return current_ev;
+}
+
+
+int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ char *current_ev = buf;
+ char *end_buf = buf + len;
+ struct ieee80211_sta_bss *bss;
+
+ spin_lock_bh(&local->sta_bss_lock);
+ list_for_each_entry(bss, &local->sta_bss_list, list) {
+ if (buf + len - current_ev <= IW_EV_ADDR_LEN) {
+ spin_unlock_bh(&local->sta_bss_lock);
+ return -E2BIG;
+ }
+ current_ev = ieee80211_sta_scan_result(dev, bss, current_ev,
+ end_buf);
+ }
+ spin_unlock_bh(&local->sta_bss_lock);
+ return current_ev - buf;
+}
+
+
+int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ kfree(ifsta->extra_ie);
+ if (len == 0) {
+ ifsta->extra_ie = NULL;
+ ifsta->extra_ie_len = 0;
+ return 0;
+ }
+ ifsta->extra_ie = kmalloc(len, GFP_KERNEL);
+ if (!ifsta->extra_ie) {
+ ifsta->extra_ie_len = 0;
+ return -ENOMEM;
+ }
+ memcpy(ifsta->extra_ie, ie, len);
+ ifsta->extra_ie_len = len;
+ return 0;
+}
+
+
+struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata = NULL;
+
+ /* TODO: Could consider removing the least recently used entry and
+ * allow new one to be added. */
+ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: No room for a new IBSS STA "
+ "entry " MAC_FMT "\n", dev->name, MAC_ARG(addr));
+ }
+ return NULL;
+ }
+
+ printk(KERN_DEBUG "%s: Adding new IBSS station " MAC_FMT " (dev=%s)\n",
+ local->mdev->name, MAC_ARG(addr), dev->name);
+
+ sta = sta_info_add(local, dev, addr, GFP_ATOMIC);
+ if (!sta)
+ return NULL;
+
+ sta->supp_rates = sdata->u.sta.supp_rates_bits;
+
+ rate_control_rate_init(sta, local);
+
+ return sta; /* caller will call sta_info_put() */
+}
+
+
+int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+ printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n",
+ dev->name, reason);
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA &&
+ sdata->type != IEEE80211_IF_TYPE_IBSS)
+ return -EINVAL;
+
+ ieee80211_send_deauth(dev, ifsta, reason);
+ ieee80211_set_disassoc(dev, ifsta, 1);
+ return 0;
+}
+
+
+int ieee80211_sta_disassociate(struct net_device *dev, u16 reason)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+ printk(KERN_DEBUG "%s: disassociate(reason=%d)\n",
+ dev->name, reason);
+
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return -EINVAL;
+
+ if (!ifsta->associated)
+ return -1;
+
+ ieee80211_send_disassoc(dev, ifsta, reason);
+ ieee80211_set_disassoc(dev, ifsta, 0);
+ return 0;
+}
diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c
new file mode 100644
index 00000000000..0f844f7895f
--- /dev/null
+++ b/net/mac80211/michael.c
@@ -0,0 +1,104 @@
+/*
+ * Michael MIC implementation - optimized for TKIP MIC operations
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ *
+ * 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/types.h>
+
+#include "michael.h"
+
+static inline u32 rotr(u32 val, int bits)
+{
+ return (val >> bits) | (val << (32 - bits));
+}
+
+
+static inline u32 rotl(u32 val, int bits)
+{
+ return (val << bits) | (val >> (32 - bits));
+}
+
+
+static inline u32 xswap(u32 val)
+{
+ return ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8);
+}
+
+
+#define michael_block(l, r) \
+do { \
+ r ^= rotl(l, 17); \
+ l += r; \
+ r ^= xswap(l); \
+ l += r; \
+ r ^= rotl(l, 3); \
+ l += r; \
+ r ^= rotr(l, 2); \
+ l += r; \
+} while (0)
+
+
+static inline u32 michael_get32(u8 *data)
+{
+ return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+
+static inline void michael_put32(u32 val, u8 *data)
+{
+ data[0] = val & 0xff;
+ data[1] = (val >> 8) & 0xff;
+ data[2] = (val >> 16) & 0xff;
+ data[3] = (val >> 24) & 0xff;
+}
+
+
+void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
+ u8 *data, size_t data_len, u8 *mic)
+{
+ u32 l, r, val;
+ size_t block, blocks, left;
+
+ l = michael_get32(key);
+ r = michael_get32(key + 4);
+
+ /* A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC
+ * calculation, but it is _not_ transmitted */
+ l ^= michael_get32(da);
+ michael_block(l, r);
+ l ^= da[4] | (da[5] << 8) | (sa[0] << 16) | (sa[1] << 24);
+ michael_block(l, r);
+ l ^= michael_get32(&sa[2]);
+ michael_block(l, r);
+ l ^= priority;
+ michael_block(l, r);
+
+ /* Real data */
+ blocks = data_len / 4;
+ left = data_len % 4;
+
+ for (block = 0; block < blocks; block++) {
+ l ^= michael_get32(&data[block * 4]);
+ michael_block(l, r);
+ }
+
+ /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make
+ * total length a multiple of 4. */
+ val = 0x5a;
+ while (left > 0) {
+ val <<= 8;
+ left--;
+ val |= data[blocks * 4 + left];
+ }
+ l ^= val;
+ michael_block(l, r);
+ /* last block is zero, so l ^ 0 = l */
+ michael_block(l, r);
+
+ michael_put32(l, mic);
+ michael_put32(r, mic + 4);
+}
diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h
new file mode 100644
index 00000000000..2e6aebabeea
--- /dev/null
+++ b/net/mac80211/michael.h
@@ -0,0 +1,20 @@
+/*
+ * Michael MIC implementation - optimized for TKIP MIC operations
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ *
+ * 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.
+ */
+
+#ifndef MICHAEL_H
+#define MICHAEL_H
+
+#include <linux/types.h>
+
+#define MICHAEL_MIC_LEN 8
+
+void michael_mic(u8 *key, u8 *da, u8 *sa, u8 priority,
+ u8 *data, size_t data_len, u8 *mic);
+
+#endif /* MICHAEL_H */
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
new file mode 100644
index 00000000000..2048cfd1ca7
--- /dev/null
+++ b/net/mac80211/rc80211_simple.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/compiler.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "debugfs.h"
+
+
+/* This is a minimal implementation of TX rate controlling that can be used
+ * as the default when no improved mechanisms are available. */
+
+
+#define RATE_CONTROL_EMERG_DEC 2
+#define RATE_CONTROL_INTERVAL (HZ / 20)
+#define RATE_CONTROL_MIN_TX 10
+
+MODULE_ALIAS("rc80211_default");
+
+static void rate_control_rate_inc(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
+ int i = sta->txrate;
+ int maxrate;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+ /* forced unicast rate - do not change STA rate */
+ return;
+ }
+
+ mode = local->oper_hw_mode;
+ maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
+
+ if (i > mode->num_rates)
+ i = mode->num_rates - 2;
+
+ while (i + 1 < mode->num_rates) {
+ i++;
+ if (sta->supp_rates & BIT(i) &&
+ mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+ (maxrate < 0 || i <= maxrate)) {
+ sta->txrate = i;
+ break;
+ }
+ }
+}
+
+
+static void rate_control_rate_dec(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
+ int i = sta->txrate;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) {
+ /* forced unicast rate - do not change STA rate */
+ return;
+ }
+
+ mode = local->oper_hw_mode;
+ if (i > mode->num_rates)
+ i = mode->num_rates;
+
+ while (i > 0) {
+ i--;
+ if (sta->supp_rates & BIT(i) &&
+ mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
+ sta->txrate = i;
+ break;
+ }
+ }
+}
+
+
+static struct ieee80211_rate *
+rate_control_lowest_rate(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode)
+{
+ int i;
+
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
+
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
+ return rate;
+ }
+
+ printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
+ "found\n");
+ return &mode->rates[0];
+}
+
+
+struct global_rate_control {
+ int dummy;
+};
+
+struct sta_rate_control {
+ unsigned long last_rate_change;
+ u32 tx_num_failures;
+ u32 tx_num_xmit;
+
+ unsigned long avg_rate_update;
+ u32 tx_avg_rate_sum;
+ u32 tx_avg_rate_num;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *tx_avg_rate_sum_dentry;
+ struct dentry *tx_avg_rate_num_dentry;
+#endif
+};
+
+
+static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
+ struct sk_buff *skb,
+ struct ieee80211_tx_status *status)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct sta_info *sta;
+ struct sta_rate_control *srctrl;
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta)
+ return;
+
+ srctrl = sta->rate_ctrl_priv;
+ srctrl->tx_num_xmit++;
+ if (status->excessive_retries) {
+ sta->antenna_sel_tx = sta->antenna_sel_tx == 1 ? 2 : 1;
+ sta->antenna_sel_rx = sta->antenna_sel_rx == 1 ? 2 : 1;
+ if (local->sta_antenna_sel == STA_ANTENNA_SEL_SW_CTRL_DEBUG) {
+ printk(KERN_DEBUG "%s: " MAC_FMT " TX antenna --> %d "
+ "RX antenna --> %d (@%lu)\n",
+ dev->name, MAC_ARG(hdr->addr1),
+ sta->antenna_sel_tx, sta->antenna_sel_rx, jiffies);
+ }
+ srctrl->tx_num_failures++;
+ sta->tx_retry_failed++;
+ sta->tx_num_consecutive_failures++;
+ sta->tx_num_mpdu_fail++;
+ } else {
+ sta->last_ack_rssi[0] = sta->last_ack_rssi[1];
+ sta->last_ack_rssi[1] = sta->last_ack_rssi[2];
+ sta->last_ack_rssi[2] = status->ack_signal;
+ sta->tx_num_consecutive_failures = 0;
+ sta->tx_num_mpdu_ok++;
+ }
+ sta->tx_retry_count += status->retry_count;
+ sta->tx_num_mpdu_fail += status->retry_count;
+
+ if (time_after(jiffies,
+ srctrl->last_rate_change + RATE_CONTROL_INTERVAL) &&
+ srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) {
+ u32 per_failed;
+ srctrl->last_rate_change = jiffies;
+
+ per_failed = (100 * sta->tx_num_mpdu_fail) /
+ (sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok);
+ /* TODO: calculate average per_failed to make adjusting
+ * parameters easier */
+#if 0
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n",
+ sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok,
+ per_failed);
+ }
+#endif
+
+ if (per_failed > local->rate_ctrl_num_down) {
+ rate_control_rate_dec(local, sta);
+ } else if (per_failed < local->rate_ctrl_num_up) {
+ rate_control_rate_inc(local, sta);
+ }
+ srctrl->tx_avg_rate_sum += status->control.rate->rate;
+ srctrl->tx_avg_rate_num++;
+ srctrl->tx_num_failures = 0;
+ srctrl->tx_num_xmit = 0;
+ } else if (sta->tx_num_consecutive_failures >=
+ RATE_CONTROL_EMERG_DEC) {
+ rate_control_rate_dec(local, sta);
+ }
+
+ if (srctrl->avg_rate_update + 60 * HZ < jiffies) {
+ srctrl->avg_rate_update = jiffies;
+ if (srctrl->tx_avg_rate_num > 0) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: STA " MAC_FMT " Average rate: "
+ "%d (%d/%d)\n",
+ dev->name, MAC_ARG(sta->addr),
+ srctrl->tx_avg_rate_sum /
+ srctrl->tx_avg_rate_num,
+ srctrl->tx_avg_rate_sum,
+ srctrl->tx_avg_rate_num);
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+ srctrl->tx_avg_rate_sum = 0;
+ srctrl->tx_avg_rate_num = 0;
+ }
+ }
+
+ sta_info_put(sta);
+}
+
+
+static struct ieee80211_rate *
+rate_control_simple_get_rate(void *priv, struct net_device *dev,
+ struct sk_buff *skb,
+ struct rate_control_extra *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hw_mode *mode = extra->mode;
+ struct sta_info *sta;
+ int rateidx, nonerp_idx;
+ u16 fc;
+
+ memset(extra, 0, sizeof(*extra));
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA ||
+ (hdr->addr1[0] & 0x01)) {
+ /* Send management frames and broadcast/multicast data using
+ * lowest rate. */
+ /* TODO: this could probably be improved.. */
+ return rate_control_lowest_rate(local, mode);
+ }
+
+ sta = sta_info_get(local, hdr->addr1);
+
+ if (!sta)
+ return rate_control_lowest_rate(local, mode);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
+ sta->txrate = sdata->bss->force_unicast_rateidx;
+
+ rateidx = sta->txrate;
+
+ if (rateidx >= mode->num_rates)
+ rateidx = mode->num_rates - 1;
+
+ sta->last_txrate = rateidx;
+ nonerp_idx = rateidx;
+ while (nonerp_idx > 0 &&
+ ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
+ !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
+ !(sta->supp_rates & BIT(nonerp_idx))))
+ nonerp_idx--;
+ extra->nonerp = &mode->rates[nonerp_idx];
+
+ sta_info_put(sta);
+
+ return &mode->rates[rateidx];
+}
+
+
+static void rate_control_simple_rate_init(void *priv, void *priv_sta,
+ struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct ieee80211_hw_mode *mode;
+ int i;
+ sta->txrate = 0;
+ mode = local->oper_hw_mode;
+ /* TODO: what is a good starting rate for STA? About middle? Maybe not
+ * the lowest or the highest rate.. Could consider using RSSI from
+ * previous packets? Need to have IEEE 802.1X auth succeed immediately
+ * after assoc.. */
+ for (i = 0; i < mode->num_rates; i++) {
+ if ((sta->supp_rates & BIT(i)) &&
+ (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ sta->txrate = i;
+ }
+}
+
+
+static void * rate_control_simple_alloc(struct ieee80211_local *local)
+{
+ struct global_rate_control *rctrl;
+
+ rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC);
+
+ return rctrl;
+}
+
+
+static void rate_control_simple_free(void *priv)
+{
+ struct global_rate_control *rctrl = priv;
+ kfree(rctrl);
+}
+
+
+static void rate_control_simple_clear(void *priv)
+{
+}
+
+
+static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp)
+{
+ struct sta_rate_control *rctrl;
+
+ rctrl = kzalloc(sizeof(*rctrl), gfp);
+
+ return rctrl;
+}
+
+
+static void rate_control_simple_free_sta(void *priv, void *priv_sta)
+{
+ struct sta_rate_control *rctrl = priv_sta;
+ kfree(rctrl);
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t sta_tx_avg_rate_sum_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct sta_rate_control *srctrl = file->private_data;
+ char buf[20];
+
+ sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations sta_tx_avg_rate_sum_ops = {
+ .read = sta_tx_avg_rate_sum_read,
+ .open = open_file_generic,
+};
+
+static ssize_t sta_tx_avg_rate_num_read(struct file *file,
+ char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct sta_rate_control *srctrl = file->private_data;
+ char buf[20];
+
+ sprintf(buf, "%d\n", srctrl->tx_avg_rate_num);
+ return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
+}
+
+static const struct file_operations sta_tx_avg_rate_num_ops = {
+ .read = sta_tx_avg_rate_num_read,
+ .open = open_file_generic,
+};
+
+static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta,
+ struct dentry *dir)
+{
+ struct sta_rate_control *srctrl = priv_sta;
+
+ srctrl->tx_avg_rate_num_dentry =
+ debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400,
+ dir, srctrl, &sta_tx_avg_rate_num_ops);
+ srctrl->tx_avg_rate_sum_dentry =
+ debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400,
+ dir, srctrl, &sta_tx_avg_rate_sum_ops);
+}
+
+static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+ struct sta_rate_control *srctrl = priv_sta;
+
+ debugfs_remove(srctrl->tx_avg_rate_sum_dentry);
+ debugfs_remove(srctrl->tx_avg_rate_num_dentry);
+}
+#endif
+
+static struct rate_control_ops rate_control_simple = {
+ .module = THIS_MODULE,
+ .name = "simple",
+ .tx_status = rate_control_simple_tx_status,
+ .get_rate = rate_control_simple_get_rate,
+ .rate_init = rate_control_simple_rate_init,
+ .clear = rate_control_simple_clear,
+ .alloc = rate_control_simple_alloc,
+ .free = rate_control_simple_free,
+ .alloc_sta = rate_control_simple_alloc_sta,
+ .free_sta = rate_control_simple_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = rate_control_simple_add_sta_debugfs,
+ .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs,
+#endif
+};
+
+
+static int __init rate_control_simple_init(void)
+{
+ return ieee80211_rate_control_register(&rate_control_simple);
+}
+
+
+static void __exit rate_control_simple_exit(void)
+{
+ ieee80211_rate_control_unregister(&rate_control_simple);
+}
+
+
+module_init(rate_control_simple_init);
+module_exit(rate_control_simple_exit);
+
+MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
+MODULE_LICENSE("GPL");
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
new file mode 100644
index 00000000000..ab7b1f067c6
--- /dev/null
+++ b/net/mac80211/sta_info.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "ieee80211_rate.h"
+#include "sta_info.h"
+#include "debugfs_key.h"
+#include "debugfs_sta.h"
+
+/* Caller must hold local->sta_lock */
+static void sta_info_hash_add(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ sta->hnext = local->sta_hash[STA_HASH(sta->addr)];
+ local->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+
+/* Caller must hold local->sta_lock */
+static void sta_info_hash_del(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ struct sta_info *s;
+
+ s = local->sta_hash[STA_HASH(sta->addr)];
+ if (!s)
+ return;
+ if (memcmp(s->addr, sta->addr, ETH_ALEN) == 0) {
+ local->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+ return;
+ }
+
+ while (s->hnext && memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
+ s = s->hnext;
+ if (s->hnext)
+ s->hnext = s->hnext->hnext;
+ else
+ printk(KERN_ERR "%s: could not remove STA " MAC_FMT " from "
+ "hash table\n", local->mdev->name, MAC_ARG(sta->addr));
+}
+
+static inline void __sta_info_get(struct sta_info *sta)
+{
+ kref_get(&sta->kref);
+}
+
+struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr)
+{
+ struct sta_info *sta;
+
+ spin_lock_bh(&local->sta_lock);
+ sta = local->sta_hash[STA_HASH(addr)];
+ while (sta) {
+ if (memcmp(sta->addr, addr, ETH_ALEN) == 0) {
+ __sta_info_get(sta);
+ break;
+ }
+ sta = sta->hnext;
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ return sta;
+}
+EXPORT_SYMBOL(sta_info_get);
+
+int sta_info_min_txrate_get(struct ieee80211_local *local)
+{
+ struct sta_info *sta;
+ struct ieee80211_hw_mode *mode;
+ int min_txrate = 9999999;
+ int i;
+
+ spin_lock_bh(&local->sta_lock);
+ mode = local->oper_hw_mode;
+ for (i = 0; i < STA_HASH_SIZE; i++) {
+ sta = local->sta_hash[i];
+ while (sta) {
+ if (sta->txrate < min_txrate)
+ min_txrate = sta->txrate;
+ sta = sta->hnext;
+ }
+ }
+ spin_unlock_bh(&local->sta_lock);
+ if (min_txrate == 9999999)
+ min_txrate = 0;
+
+ return mode->rates[min_txrate].rate;
+}
+
+
+static void sta_info_release(struct kref *kref)
+{
+ struct sta_info *sta = container_of(kref, struct sta_info, kref);
+ struct ieee80211_local *local = sta->local;
+ struct sk_buff *skb;
+
+ /* free sta structure; it has already been removed from
+ * hash table etc. external structures. Make sure that all
+ * buffered frames are release (one might have been added
+ * after sta_info_free() was called). */
+ while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+ local->total_ps_buffered--;
+ dev_kfree_skb_any(skb);
+ }
+ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+ dev_kfree_skb_any(skb);
+ }
+ rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv);
+ rate_control_put(sta->rate_ctrl);
+ if (sta->key)
+ ieee80211_debugfs_key_sta_del(sta->key, sta);
+ kfree(sta);
+}
+
+
+void sta_info_put(struct sta_info *sta)
+{
+ kref_put(&sta->kref, sta_info_release);
+}
+EXPORT_SYMBOL(sta_info_put);
+
+
+struct sta_info * sta_info_add(struct ieee80211_local *local,
+ struct net_device *dev, u8 *addr, gfp_t gfp)
+{
+ struct sta_info *sta;
+
+ sta = kzalloc(sizeof(*sta), gfp);
+ if (!sta)
+ return NULL;
+
+ kref_init(&sta->kref);
+
+ sta->rate_ctrl = rate_control_get(local->rate_ctrl);
+ sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp);
+ if (!sta->rate_ctrl_priv) {
+ rate_control_put(sta->rate_ctrl);
+ kref_put(&sta->kref, sta_info_release);
+ kfree(sta);
+ return NULL;
+ }
+
+ memcpy(sta->addr, addr, ETH_ALEN);
+ sta->local = local;
+ sta->dev = dev;
+ skb_queue_head_init(&sta->ps_tx_buf);
+ skb_queue_head_init(&sta->tx_filtered);
+ __sta_info_get(sta); /* sta used by caller, decremented by
+ * sta_info_put() */
+ spin_lock_bh(&local->sta_lock);
+ list_add(&sta->list, &local->sta_list);
+ local->num_sta++;
+ sta_info_hash_add(local, sta);
+ spin_unlock_bh(&local->sta_lock);
+ if (local->ops->sta_table_notification)
+ local->ops->sta_table_notification(local_to_hw(local),
+ local->num_sta);
+ sta->key_idx_compression = HW_KEY_IDX_INVALID;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Added STA " MAC_FMT "\n",
+ local->mdev->name, MAC_ARG(addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ if (!in_interrupt()) {
+ sta->debugfs_registered = 1;
+ ieee80211_sta_debugfs_add(sta);
+ rate_control_add_sta_debugfs(sta);
+ } else {
+ /* debugfs entry adding might sleep, so schedule process
+ * context task for adding entry for STAs that do not yet
+ * have one. */
+ queue_work(local->hw.workqueue, &local->sta_debugfs_add);
+ }
+#endif
+
+ return sta;
+}
+
+static void finish_sta_info_free(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ printk(KERN_DEBUG "%s: Removed STA " MAC_FMT "\n",
+ local->mdev->name, MAC_ARG(sta->addr));
+#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
+
+ if (sta->key) {
+ ieee80211_debugfs_key_remove(sta->key);
+ ieee80211_key_free(sta->key);
+ sta->key = NULL;
+ }
+
+ rate_control_remove_sta_debugfs(sta);
+ ieee80211_sta_debugfs_remove(sta);
+
+ sta_info_put(sta);
+}
+
+static void sta_info_remove(struct sta_info *sta)
+{
+ struct ieee80211_local *local = sta->local;
+ struct ieee80211_sub_if_data *sdata;
+
+ sta_info_hash_del(local, sta);
+ list_del(&sta->list);
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+ if (sta->flags & WLAN_STA_PS) {
+ sta->flags &= ~WLAN_STA_PS;
+ if (sdata->bss)
+ atomic_dec(&sdata->bss->num_sta_ps);
+ }
+ local->num_sta--;
+ sta_info_remove_aid_ptr(sta);
+}
+
+void sta_info_free(struct sta_info *sta, int locked)
+{
+ struct sk_buff *skb;
+ struct ieee80211_local *local = sta->local;
+
+ if (!locked) {
+ spin_lock_bh(&local->sta_lock);
+ sta_info_remove(sta);
+ spin_unlock_bh(&local->sta_lock);
+ } else {
+ sta_info_remove(sta);
+ }
+ if (local->ops->sta_table_notification)
+ local->ops->sta_table_notification(local_to_hw(local),
+ local->num_sta);
+
+ while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
+ local->total_ps_buffered--;
+ dev_kfree_skb_any(skb);
+ }
+ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
+ dev_kfree_skb_any(skb);
+ }
+
+ if (sta->key) {
+ if (local->ops->set_key) {
+ struct ieee80211_key_conf *key;
+ key = ieee80211_key_data2conf(local, sta->key);
+ if (key) {
+ local->ops->set_key(local_to_hw(local),
+ DISABLE_KEY,
+ sta->addr, key, sta->aid);
+ kfree(key);
+ }
+ }
+ } else if (sta->key_idx_compression != HW_KEY_IDX_INVALID) {
+ struct ieee80211_key_conf conf;
+ memset(&conf, 0, sizeof(conf));
+ conf.hw_key_idx = sta->key_idx_compression;
+ conf.alg = ALG_NULL;
+ conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
+ local->ops->set_key(local_to_hw(local), DISABLE_KEY,
+ sta->addr, &conf, sta->aid);
+ sta->key_idx_compression = HW_KEY_IDX_INVALID;
+ }
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ if (in_atomic()) {
+ list_add(&sta->list, &local->deleted_sta_list);
+ queue_work(local->hw.workqueue, &local->sta_debugfs_add);
+ } else
+#endif
+ finish_sta_info_free(local, sta);
+}
+
+
+static inline int sta_info_buffer_expired(struct ieee80211_local *local,
+ struct sta_info *sta,
+ struct sk_buff *skb)
+{
+ struct ieee80211_tx_packet_data *pkt_data;
+ int timeout;
+
+ if (!skb)
+ return 0;
+
+ pkt_data = (struct ieee80211_tx_packet_data *) skb->cb;
+
+ /* Timeout: (2 * listen_interval * beacon_int * 1024 / 1000000) sec */
+ timeout = (sta->listen_interval * local->hw.conf.beacon_int * 32 /
+ 15625) * HZ;
+ if (timeout < STA_TX_BUFFER_EXPIRE)
+ timeout = STA_TX_BUFFER_EXPIRE;
+ return time_after(jiffies, pkt_data->jiffies + timeout);
+}
+
+
+static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
+ struct sta_info *sta)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+
+ if (skb_queue_empty(&sta->ps_tx_buf))
+ return;
+
+ for (;;) {
+ spin_lock_irqsave(&sta->ps_tx_buf.lock, flags);
+ skb = skb_peek(&sta->ps_tx_buf);
+ if (sta_info_buffer_expired(local, sta, skb)) {
+ skb = __skb_dequeue(&sta->ps_tx_buf);
+ if (skb_queue_empty(&sta->ps_tx_buf))
+ sta->flags &= ~WLAN_STA_TIM;
+ } else
+ skb = NULL;
+ spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags);
+
+ if (skb) {
+ local->total_ps_buffered--;
+ printk(KERN_DEBUG "Buffered frame expired (STA "
+ MAC_FMT ")\n", MAC_ARG(sta->addr));
+ dev_kfree_skb(skb);
+ } else
+ break;
+ }
+}
+
+
+static void sta_info_cleanup(unsigned long data)
+{
+ struct ieee80211_local *local = (struct ieee80211_local *) data;
+ struct sta_info *sta;
+
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ __sta_info_get(sta);
+ sta_info_cleanup_expire_buffered(local, sta);
+ sta_info_put(sta);
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+ add_timer(&local->sta_cleanup);
+}
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void sta_info_debugfs_add_task(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local, sta_debugfs_add);
+ struct sta_info *sta, *tmp;
+
+ while (1) {
+ spin_lock_bh(&local->sta_lock);
+ if (!list_empty(&local->deleted_sta_list)) {
+ sta = list_entry(local->deleted_sta_list.next,
+ struct sta_info, list);
+ list_del(local->deleted_sta_list.next);
+ } else
+ sta = NULL;
+ spin_unlock_bh(&local->sta_lock);
+ if (!sta)
+ break;
+ finish_sta_info_free(local, sta);
+ }
+
+ while (1) {
+ sta = NULL;
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry(tmp, &local->sta_list, list) {
+ if (!tmp->debugfs_registered) {
+ sta = tmp;
+ __sta_info_get(sta);
+ break;
+ }
+ }
+ spin_unlock_bh(&local->sta_lock);
+
+ if (!sta)
+ break;
+
+ sta->debugfs_registered = 1;
+ ieee80211_sta_debugfs_add(sta);
+ rate_control_add_sta_debugfs(sta);
+ sta_info_put(sta);
+ }
+}
+#endif
+
+void sta_info_init(struct ieee80211_local *local)
+{
+ spin_lock_init(&local->sta_lock);
+ INIT_LIST_HEAD(&local->sta_list);
+ INIT_LIST_HEAD(&local->deleted_sta_list);
+
+ init_timer(&local->sta_cleanup);
+ local->sta_cleanup.expires = jiffies + STA_INFO_CLEANUP_INTERVAL;
+ local->sta_cleanup.data = (unsigned long) local;
+ local->sta_cleanup.function = sta_info_cleanup;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task);
+#endif
+}
+
+int sta_info_start(struct ieee80211_local *local)
+{
+ add_timer(&local->sta_cleanup);
+ return 0;
+}
+
+void sta_info_stop(struct ieee80211_local *local)
+{
+ struct sta_info *sta, *tmp;
+
+ del_timer(&local->sta_cleanup);
+
+ list_for_each_entry_safe(sta, tmp, &local->sta_list, list) {
+ /* sta_info_free must be called with 0 as the last
+ * parameter to ensure all debugfs sta entries are
+ * unregistered. We don't need locking at this
+ * point. */
+ sta_info_free(sta, 0);
+ }
+}
+
+void sta_info_remove_aid_ptr(struct sta_info *sta)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ if (sta->aid <= 0)
+ return;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
+
+ if (sdata->local->ops->set_tim)
+ sdata->local->ops->set_tim(local_to_hw(sdata->local),
+ sta->aid, 0);
+ if (sdata->bss)
+ __bss_tim_clear(sdata->bss, sta->aid);
+}
+
+
+/**
+ * sta_info_flush - flush matching STA entries from the STA table
+ * @local: local interface data
+ * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs
+ */
+void sta_info_flush(struct ieee80211_local *local, struct net_device *dev)
+{
+ struct sta_info *sta, *tmp;
+
+ spin_lock_bh(&local->sta_lock);
+ list_for_each_entry_safe(sta, tmp, &local->sta_list, list)
+ if (!dev || dev == sta->dev)
+ sta_info_free(sta, 1);
+ spin_unlock_bh(&local->sta_lock);
+}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
new file mode 100644
index 00000000000..b5591d2f60a
--- /dev/null
+++ b/net/mac80211/sta_info.h
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2002-2005, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef STA_INFO_H
+#define STA_INFO_H
+
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/kref.h>
+#include "ieee80211_key.h"
+
+/* Stations flags (struct sta_info::flags) */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
+#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
+#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
+ * controlling whether STA is authorized to
+ * send and receive non-IEEE 802.1X frames
+ */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_WDS BIT(27)
+
+
+struct sta_info {
+ struct kref kref;
+ struct list_head list;
+ struct sta_info *hnext; /* next entry in hash table list */
+
+ struct ieee80211_local *local;
+
+ u8 addr[ETH_ALEN];
+ u16 aid; /* STA's unique AID (1..2007), 0 = not yet assigned */
+ u32 flags; /* WLAN_STA_ */
+
+ struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in
+ * power saving state */
+ int pspoll; /* whether STA has send a PS Poll frame */
+ struct sk_buff_head tx_filtered; /* buffer of TX frames that were
+ * already given to low-level driver,
+ * but were filtered */
+ int clear_dst_mask;
+
+ unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */
+ unsigned long rx_bytes, tx_bytes;
+ unsigned long tx_retry_failed, tx_retry_count;
+ unsigned long tx_filtered_count;
+
+ unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */
+
+ unsigned long last_rx;
+ u32 supp_rates; /* bitmap of supported rates in local->curr_rates */
+ int txrate; /* index in local->curr_rates */
+ int last_txrate; /* last rate used to send a frame to this STA */
+ int last_nonerp_idx;
+
+ struct net_device *dev; /* which net device is this station associated
+ * to */
+
+ struct ieee80211_key *key;
+
+ u32 tx_num_consecutive_failures;
+ u32 tx_num_mpdu_ok;
+ u32 tx_num_mpdu_fail;
+
+ struct rate_control_ref *rate_ctrl;
+ void *rate_ctrl_priv;
+
+ /* last received seq/frag number from this STA (per RX queue) */
+ __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES];
+ unsigned long num_duplicates; /* number of duplicate frames received
+ * from this STA */
+ unsigned long tx_fragments; /* number of transmitted MPDUs */
+ unsigned long rx_fragments; /* number of received MPDUs */
+ unsigned long rx_dropped; /* number of dropped MPDUs from this STA */
+
+ int last_rssi; /* RSSI of last received frame from this STA */
+ int last_signal; /* signal of last received frame from this STA */
+ int last_noise; /* noise of last received frame from this STA */
+ int last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */
+ unsigned long last_ack;
+ int channel_use;
+ int channel_use_raw;
+
+ u8 antenna_sel_tx;
+ u8 antenna_sel_rx;
+
+
+ int key_idx_compression; /* key table index for compression and TX
+ * filtering; used only if sta->key is not
+ * set */
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ int debugfs_registered;
+#endif
+ int assoc_ap; /* whether this is an AP that we are
+ * associated with as a client */
+
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES];
+ unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES];
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+ int vlan_id;
+
+ u16 listen_interval;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct sta_info_debugfsdentries {
+ struct dentry *dir;
+ struct dentry *flags;
+ struct dentry *num_ps_buf_frames;
+ struct dentry *last_ack_rssi;
+ struct dentry *last_ack_ms;
+ struct dentry *inactive_ms;
+ struct dentry *last_seq_ctrl;
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ struct dentry *wme_rx_queue;
+ struct dentry *wme_tx_queue;
+#endif
+ } debugfs;
+#endif
+};
+
+
+/* Maximum number of concurrently registered stations */
+#define MAX_STA_COUNT 2007
+
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+
+
+/* Maximum number of frames to buffer per power saving station */
+#define STA_MAX_TX_BUFFER 128
+
+/* Minimum buffered frame expiry time. If STA uses listen interval that is
+ * smaller than this value, the minimum value here is used instead. */
+#define STA_TX_BUFFER_EXPIRE (10 * HZ)
+
+/* How often station data is cleaned up (e.g., expiration of buffered frames)
+ */
+#define STA_INFO_CLEANUP_INTERVAL (10 * HZ)
+
+struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr);
+int sta_info_min_txrate_get(struct ieee80211_local *local);
+void sta_info_put(struct sta_info *sta);
+struct sta_info * sta_info_add(struct ieee80211_local *local,
+ struct net_device *dev, u8 *addr, gfp_t gfp);
+void sta_info_free(struct sta_info *sta, int locked);
+void sta_info_init(struct ieee80211_local *local);
+int sta_info_start(struct ieee80211_local *local);
+void sta_info_stop(struct ieee80211_local *local);
+void sta_info_remove_aid_ptr(struct sta_info *sta);
+void sta_info_flush(struct ieee80211_local *local, struct net_device *dev);
+
+#endif /* STA_INFO_H */
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
new file mode 100644
index 00000000000..41621720e56
--- /dev/null
+++ b/net/mac80211/tkip.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_key.h"
+#include "tkip.h"
+#include "wep.h"
+
+
+/* TKIP key mixing functions */
+
+
+#define PHASE1_LOOP_COUNT 8
+
+
+/* 2-byte by 2-byte subset of the full AES S-box table; second part of this
+ * table is identical to first part but byte-swapped */
+static const u16 tkip_sbox[256] =
+{
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+};
+
+
+static inline u16 Mk16(u8 x, u8 y)
+{
+ return ((u16) x << 8) | (u16) y;
+}
+
+
+static inline u8 Hi8(u16 v)
+{
+ return v >> 8;
+}
+
+
+static inline u8 Lo8(u16 v)
+{
+ return v & 0xff;
+}
+
+
+static inline u16 Hi16(u32 v)
+{
+ return v >> 16;
+}
+
+
+static inline u16 Lo16(u32 v)
+{
+ return v & 0xffff;
+}
+
+
+static inline u16 RotR1(u16 v)
+{
+ return (v >> 1) | ((v & 0x0001) << 15);
+}
+
+
+static inline u16 tkip_S(u16 val)
+{
+ u16 a = tkip_sbox[Hi8(val)];
+
+ return tkip_sbox[Lo8(val)] ^ Hi8(a) ^ (Lo8(a) << 8);
+}
+
+
+
+/* P1K := Phase1(TA, TK, TSC)
+ * TA = transmitter address (48 bits)
+ * TK = dot11DefaultKeyValue or dot11KeyMappingValue (128 bits)
+ * TSC = TKIP sequence counter (48 bits, only 32 msb bits used)
+ * P1K: 80 bits
+ */
+static void tkip_mixing_phase1(const u8 *ta, const u8 *tk, u32 tsc_IV32,
+ u16 *p1k)
+{
+ int i, j;
+
+ p1k[0] = Lo16(tsc_IV32);
+ p1k[1] = Hi16(tsc_IV32);
+ p1k[2] = Mk16(ta[1], ta[0]);
+ p1k[3] = Mk16(ta[3], ta[2]);
+ p1k[4] = Mk16(ta[5], ta[4]);
+
+ for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
+ j = 2 * (i & 1);
+ p1k[0] += tkip_S(p1k[4] ^ Mk16(tk[ 1 + j], tk[ 0 + j]));
+ p1k[1] += tkip_S(p1k[0] ^ Mk16(tk[ 5 + j], tk[ 4 + j]));
+ p1k[2] += tkip_S(p1k[1] ^ Mk16(tk[ 9 + j], tk[ 8 + j]));
+ p1k[3] += tkip_S(p1k[2] ^ Mk16(tk[13 + j], tk[12 + j]));
+ p1k[4] += tkip_S(p1k[3] ^ Mk16(tk[ 1 + j], tk[ 0 + j])) + i;
+ }
+}
+
+
+static void tkip_mixing_phase2(const u16 *p1k, const u8 *tk, u16 tsc_IV16,
+ u8 *rc4key)
+{
+ u16 ppk[6];
+ int i;
+
+ ppk[0] = p1k[0];
+ ppk[1] = p1k[1];
+ ppk[2] = p1k[2];
+ ppk[3] = p1k[3];
+ ppk[4] = p1k[4];
+ ppk[5] = p1k[4] + tsc_IV16;
+
+ ppk[0] += tkip_S(ppk[5] ^ Mk16(tk[ 1], tk[ 0]));
+ ppk[1] += tkip_S(ppk[0] ^ Mk16(tk[ 3], tk[ 2]));
+ ppk[2] += tkip_S(ppk[1] ^ Mk16(tk[ 5], tk[ 4]));
+ ppk[3] += tkip_S(ppk[2] ^ Mk16(tk[ 7], tk[ 6]));
+ ppk[4] += tkip_S(ppk[3] ^ Mk16(tk[ 9], tk[ 8]));
+ ppk[5] += tkip_S(ppk[4] ^ Mk16(tk[11], tk[10]));
+ ppk[0] += RotR1(ppk[5] ^ Mk16(tk[13], tk[12]));
+ ppk[1] += RotR1(ppk[0] ^ Mk16(tk[15], tk[14]));
+ ppk[2] += RotR1(ppk[1]);
+ ppk[3] += RotR1(ppk[2]);
+ ppk[4] += RotR1(ppk[3]);
+ ppk[5] += RotR1(ppk[4]);
+
+ rc4key[0] = Hi8(tsc_IV16);
+ rc4key[1] = (Hi8(tsc_IV16) | 0x20) & 0x7f;
+ rc4key[2] = Lo8(tsc_IV16);
+ rc4key[3] = Lo8((ppk[5] ^ Mk16(tk[1], tk[0])) >> 1);
+
+ for (i = 0; i < 6; i++) {
+ rc4key[4 + 2 * i] = Lo8(ppk[i]);
+ rc4key[5 + 2 * i] = Hi8(ppk[i]);
+ }
+}
+
+
+/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
+ * of the IV. Returns pointer to the octet following IVs (i.e., beginning of
+ * the packet payload). */
+u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+ u8 iv0, u8 iv1, u8 iv2)
+{
+ *pos++ = iv0;
+ *pos++ = iv1;
+ *pos++ = iv2;
+ *pos++ = (key->keyidx << 6) | (1 << 5) /* Ext IV */;
+ *pos++ = key->u.tkip.iv32 & 0xff;
+ *pos++ = (key->u.tkip.iv32 >> 8) & 0xff;
+ *pos++ = (key->u.tkip.iv32 >> 16) & 0xff;
+ *pos++ = (key->u.tkip.iv32 >> 24) & 0xff;
+ return pos;
+}
+
+
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+ u16 *phase1key)
+{
+ tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+ key->u.tkip.iv32, phase1key);
+}
+
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+ u8 *rc4key)
+{
+ /* Calculate per-packet key */
+ if (key->u.tkip.iv16 == 0 || !key->u.tkip.tx_initialized) {
+ /* IV16 wrapped around - perform TKIP phase 1 */
+ tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+ key->u.tkip.iv32, key->u.tkip.p1k);
+ key->u.tkip.tx_initialized = 1;
+ }
+
+ tkip_mixing_phase2(key->u.tkip.p1k, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+ key->u.tkip.iv16, rc4key);
+}
+
+/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the
+ * beginning of the buffer containing payload. This payload must include
+ * headroom of eight octets for IV and Ext. IV and taildroom of four octets
+ * for ICV. @payload_len is the length of payload (_not_ including extra
+ * headroom and tailroom). @ta is the transmitter addresses. */
+void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+ struct ieee80211_key *key,
+ u8 *pos, size_t payload_len, u8 *ta)
+{
+ u8 rc4key[16];
+
+ ieee80211_tkip_gen_rc4key(key, ta, rc4key);
+ pos = ieee80211_tkip_add_iv(pos, key, rc4key[0], rc4key[1], rc4key[2]);
+ ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len);
+}
+
+
+/* Decrypt packet payload with TKIP using @key. @pos is a pointer to the
+ * beginning of the buffer containing IEEE 802.11 header payload, i.e.,
+ * including IV, Ext. IV, real data, Michael MIC, ICV. @payload_len is the
+ * length of payload, including IV, Ext. IV, MIC, ICV. */
+int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+ struct ieee80211_key *key,
+ u8 *payload, size_t payload_len, u8 *ta,
+ int only_iv, int queue)
+{
+ u32 iv32;
+ u32 iv16;
+ u8 rc4key[16], keyid, *pos = payload;
+ int res;
+
+ if (payload_len < 12)
+ return -1;
+
+ iv16 = (pos[0] << 8) | pos[2];
+ keyid = pos[3];
+ iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
+ pos += 8;
+#ifdef CONFIG_TKIP_DEBUG
+ {
+ int i;
+ printk(KERN_DEBUG "TKIP decrypt: data(len=%zd)", payload_len);
+ for (i = 0; i < payload_len; i++)
+ printk(" %02x", payload[i]);
+ printk("\n");
+ printk(KERN_DEBUG "TKIP decrypt: iv16=%04x iv32=%08x\n",
+ iv16, iv32);
+ }
+#endif /* CONFIG_TKIP_DEBUG */
+
+ if (!(keyid & (1 << 5)))
+ return TKIP_DECRYPT_NO_EXT_IV;
+
+ if ((keyid >> 6) != key->keyidx)
+ return TKIP_DECRYPT_INVALID_KEYIDX;
+
+ if (key->u.tkip.rx_initialized[queue] &&
+ (iv32 < key->u.tkip.iv32_rx[queue] ||
+ (iv32 == key->u.tkip.iv32_rx[queue] &&
+ iv16 <= key->u.tkip.iv16_rx[queue]))) {
+#ifdef CONFIG_TKIP_DEBUG
+ printk(KERN_DEBUG "TKIP replay detected for RX frame from "
+ MAC_FMT " (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n",
+ MAC_ARG(ta),
+ iv32, iv16, key->u.tkip.iv32_rx[queue],
+ key->u.tkip.iv16_rx[queue]);
+#endif /* CONFIG_TKIP_DEBUG */
+ return TKIP_DECRYPT_REPLAY;
+ }
+
+ if (only_iv) {
+ res = TKIP_DECRYPT_OK;
+ key->u.tkip.rx_initialized[queue] = 1;
+ goto done;
+ }
+
+ if (!key->u.tkip.rx_initialized[queue] ||
+ key->u.tkip.iv32_rx[queue] != iv32) {
+ key->u.tkip.rx_initialized[queue] = 1;
+ /* IV16 wrapped around - perform TKIP phase 1 */
+ tkip_mixing_phase1(ta, &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+ iv32, key->u.tkip.p1k_rx[queue]);
+#ifdef CONFIG_TKIP_DEBUG
+ {
+ int i;
+ printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=" MAC_FMT
+ " TK=", MAC_ARG(ta));
+ for (i = 0; i < 16; i++)
+ printk("%02x ",
+ key->key[ALG_TKIP_TEMP_ENCR_KEY + i]);
+ printk("\n");
+ printk(KERN_DEBUG "TKIP decrypt: P1K=");
+ for (i = 0; i < 5; i++)
+ printk("%04x ", key->u.tkip.p1k_rx[queue][i]);
+ printk("\n");
+ }
+#endif /* CONFIG_TKIP_DEBUG */
+ }
+
+ tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
+ &key->key[ALG_TKIP_TEMP_ENCR_KEY],
+ iv16, rc4key);
+#ifdef CONFIG_TKIP_DEBUG
+ {
+ int i;
+ printk(KERN_DEBUG "TKIP decrypt: Phase2 rc4key=");
+ for (i = 0; i < 16; i++)
+ printk("%02x ", rc4key[i]);
+ printk("\n");
+ }
+#endif /* CONFIG_TKIP_DEBUG */
+
+ res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
+ done:
+ if (res == TKIP_DECRYPT_OK) {
+ /* FIX: these should be updated only after Michael MIC has been
+ * verified */
+ /* Record previously received IV */
+ key->u.tkip.iv32_rx[queue] = iv32;
+ key->u.tkip.iv16_rx[queue] = iv16;
+ }
+
+ return res;
+}
+
+
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
new file mode 100644
index 00000000000..a0d181a1804
--- /dev/null
+++ b/net/mac80211/tkip.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ *
+ * 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.
+ */
+
+#ifndef TKIP_H
+#define TKIP_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include "ieee80211_key.h"
+
+u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key,
+ u8 iv0, u8 iv1, u8 iv2);
+void ieee80211_tkip_gen_phase1key(struct ieee80211_key *key, u8 *ta,
+ u16 *phase1key);
+void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
+ u8 *rc4key);
+void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
+ struct ieee80211_key *key,
+ u8 *pos, size_t payload_len, u8 *ta);
+enum {
+ TKIP_DECRYPT_OK = 0,
+ TKIP_DECRYPT_NO_EXT_IV = -1,
+ TKIP_DECRYPT_INVALID_KEYIDX = -2,
+ TKIP_DECRYPT_REPLAY = -3,
+};
+int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
+ struct ieee80211_key *key,
+ u8 *payload, size_t payload_len, u8 *ta,
+ int only_iv, int queue);
+
+#endif /* TKIP_H */
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
new file mode 100644
index 00000000000..1ad3d75281c
--- /dev/null
+++ b/net/mac80211/wep.c
@@ -0,0 +1,328 @@
+/*
+ * Software WEP encryption implementation
+ * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2003, Instant802 Networks, Inc.
+ *
+ * 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/netdevice.h>
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/crc32.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wep.h"
+
+
+int ieee80211_wep_init(struct ieee80211_local *local)
+{
+ /* start WEP IV from a random value */
+ get_random_bytes(&local->wep_iv, WEP_IV_LEN);
+
+ local->wep_tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(local->wep_tx_tfm))
+ return -ENOMEM;
+
+ local->wep_rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0,
+ CRYPTO_ALG_ASYNC);
+ if (IS_ERR(local->wep_rx_tfm)) {
+ crypto_free_blkcipher(local->wep_tx_tfm);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ieee80211_wep_free(struct ieee80211_local *local)
+{
+ crypto_free_blkcipher(local->wep_tx_tfm);
+ crypto_free_blkcipher(local->wep_rx_tfm);
+}
+
+static inline int ieee80211_wep_weak_iv(u32 iv, int keylen)
+{
+ /* Fluhrer, Mantin, and Shamir have reported weaknesses in the
+ * key scheduling algorithm of RC4. At least IVs (KeyByte + 3,
+ * 0xff, N) can be used to speedup attacks, so avoid using them. */
+ if ((iv & 0xff00) == 0xff00) {
+ u8 B = (iv >> 16) & 0xff;
+ if (B >= 3 && B < 3 + keylen)
+ return 1;
+ }
+ return 0;
+}
+
+
+void ieee80211_wep_get_iv(struct ieee80211_local *local,
+ struct ieee80211_key *key, u8 *iv)
+{
+ local->wep_iv++;
+ if (ieee80211_wep_weak_iv(local->wep_iv, key->keylen))
+ local->wep_iv += 0x0100;
+
+ if (!iv)
+ return;
+
+ *iv++ = (local->wep_iv >> 16) & 0xff;
+ *iv++ = (local->wep_iv >> 8) & 0xff;
+ *iv++ = local->wep_iv & 0xff;
+ *iv++ = key->keyidx << 6;
+}
+
+
+u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_key *key)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc;
+ int hdrlen;
+ u8 *newhdr;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ fc |= IEEE80211_FCTL_PROTECTED;
+ hdr->frame_control = cpu_to_le16(fc);
+
+ if ((skb_headroom(skb) < WEP_IV_LEN ||
+ skb_tailroom(skb) < WEP_ICV_LEN)) {
+ I802_DEBUG_INC(local->tx_expand_skb_head);
+ if (unlikely(pskb_expand_head(skb, WEP_IV_LEN, WEP_ICV_LEN,
+ GFP_ATOMIC)))
+ return NULL;
+ }
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+ newhdr = skb_push(skb, WEP_IV_LEN);
+ memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
+ ieee80211_wep_get_iv(local, key, newhdr + hdrlen);
+ return newhdr + hdrlen;
+}
+
+
+void ieee80211_wep_remove_iv(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_key *key)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc;
+ int hdrlen;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ hdrlen = ieee80211_get_hdrlen(fc);
+ memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
+ skb_pull(skb, WEP_IV_LEN);
+}
+
+
+/* Perform WEP encryption using given key. data buffer must have tailroom
+ * for 4-byte ICV. data_len must not include this ICV. Note: this function
+ * does _not_ add IV. data = RC4(data | CRC32(data)) */
+void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+ size_t klen, u8 *data, size_t data_len)
+{
+ struct blkcipher_desc desc = { .tfm = tfm };
+ struct scatterlist sg;
+ __le32 *icv;
+
+ icv = (__le32 *)(data + data_len);
+ *icv = cpu_to_le32(~crc32_le(~0, data, data_len));
+
+ crypto_blkcipher_setkey(tfm, rc4key, klen);
+ sg.page = virt_to_page(data);
+ sg.offset = offset_in_page(data);
+ sg.length = data_len + WEP_ICV_LEN;
+ crypto_blkcipher_encrypt(&desc, &sg, &sg, sg.length);
+}
+
+
+/* Perform WEP encryption on given skb. 4 bytes of extra space (IV) in the
+ * beginning of the buffer 4 bytes of extra space (ICV) in the end of the
+ * buffer will be added. Both IV and ICV will be transmitted, so the
+ * payload length increases with 8 bytes.
+ *
+ * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
+ */
+int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_key *key)
+{
+ u32 klen;
+ u8 *rc4key, *iv;
+ size_t len;
+
+ if (!key || key->alg != ALG_WEP)
+ return -1;
+
+ klen = 3 + key->keylen;
+ rc4key = kmalloc(klen, GFP_ATOMIC);
+ if (!rc4key)
+ return -1;
+
+ iv = ieee80211_wep_add_iv(local, skb, key);
+ if (!iv) {
+ kfree(rc4key);
+ return -1;
+ }
+
+ len = skb->len - (iv + WEP_IV_LEN - skb->data);
+
+ /* Prepend 24-bit IV to RC4 key */
+ memcpy(rc4key, iv, 3);
+
+ /* Copy rest of the WEP key (the secret part) */
+ memcpy(rc4key + 3, key->key, key->keylen);
+
+ /* Add room for ICV */
+ skb_put(skb, WEP_ICV_LEN);
+
+ ieee80211_wep_encrypt_data(local->wep_tx_tfm, rc4key, klen,
+ iv + WEP_IV_LEN, len);
+
+ kfree(rc4key);
+
+ return 0;
+}
+
+
+/* Perform WEP decryption using given key. data buffer includes encrypted
+ * payload, including 4-byte ICV, but _not_ IV. data_len must not include ICV.
+ * Return 0 on success and -1 on ICV mismatch. */
+int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+ size_t klen, u8 *data, size_t data_len)
+{
+ struct blkcipher_desc desc = { .tfm = tfm };
+ struct scatterlist sg;
+ __le32 crc;
+
+ crypto_blkcipher_setkey(tfm, rc4key, klen);
+ sg.page = virt_to_page(data);
+ sg.offset = offset_in_page(data);
+ sg.length = data_len + WEP_ICV_LEN;
+ crypto_blkcipher_decrypt(&desc, &sg, &sg, sg.length);
+
+ crc = cpu_to_le32(~crc32_le(~0, data, data_len));
+ if (memcmp(&crc, data + data_len, WEP_ICV_LEN) != 0)
+ /* ICV mismatch */
+ return -1;
+
+ return 0;
+}
+
+
+/* Perform WEP decryption on given skb. Buffer includes whole WEP part of
+ * the frame: IV (4 bytes), encrypted payload (including SNAP header),
+ * ICV (4 bytes). skb->len includes both IV and ICV.
+ *
+ * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on
+ * failure. If frame is OK, IV and ICV will be removed, i.e., decrypted payload
+ * is moved to the beginning of the skb and skb length will be reduced.
+ */
+int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_key *key)
+{
+ u32 klen;
+ u8 *rc4key;
+ u8 keyidx;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc;
+ int hdrlen;
+ size_t len;
+ int ret = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return -1;
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ if (skb->len < 8 + hdrlen)
+ return -1;
+
+ len = skb->len - hdrlen - 8;
+
+ keyidx = skb->data[hdrlen + 3] >> 6;
+
+ if (!key || keyidx != key->keyidx || key->alg != ALG_WEP)
+ return -1;
+
+ klen = 3 + key->keylen;
+
+ rc4key = kmalloc(klen, GFP_ATOMIC);
+ if (!rc4key)
+ return -1;
+
+ /* Prepend 24-bit IV to RC4 key */
+ memcpy(rc4key, skb->data + hdrlen, 3);
+
+ /* Copy rest of the WEP key (the secret part) */
+ memcpy(rc4key + 3, key->key, key->keylen);
+
+ if (ieee80211_wep_decrypt_data(local->wep_rx_tfm, rc4key, klen,
+ skb->data + hdrlen + WEP_IV_LEN,
+ len)) {
+ printk(KERN_DEBUG "WEP decrypt failed (ICV)\n");
+ ret = -1;
+ }
+
+ kfree(rc4key);
+
+ /* Trim ICV */
+ skb_trim(skb, skb->len - WEP_ICV_LEN);
+
+ /* Remove IV */
+ memmove(skb->data + WEP_IV_LEN, skb->data, hdrlen);
+ skb_pull(skb, WEP_IV_LEN);
+
+ return ret;
+}
+
+
+int ieee80211_wep_get_keyidx(struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc;
+ int hdrlen;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return -1;
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ if (skb->len < 8 + hdrlen)
+ return -1;
+
+ return skb->data[hdrlen + 3] >> 6;
+}
+
+
+u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u16 fc;
+ int hdrlen;
+ u8 *ivpos;
+ u32 iv;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ if (!(fc & IEEE80211_FCTL_PROTECTED))
+ return NULL;
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+ ivpos = skb->data + hdrlen;
+ iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2];
+
+ if (ieee80211_wep_weak_iv(iv, key->keylen))
+ return ivpos;
+
+ return NULL;
+}
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
new file mode 100644
index 00000000000..bfe29e8e10a
--- /dev/null
+++ b/net/mac80211/wep.h
@@ -0,0 +1,40 @@
+/*
+ * Software WEP encryption implementation
+ * Copyright 2002, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright 2003, Instant802 Networks, Inc.
+ *
+ * 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.
+ */
+
+#ifndef WEP_H
+#define WEP_H
+
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include "ieee80211_i.h"
+#include "ieee80211_key.h"
+
+int ieee80211_wep_init(struct ieee80211_local *local);
+void ieee80211_wep_free(struct ieee80211_local *local);
+void ieee80211_wep_get_iv(struct ieee80211_local *local,
+ struct ieee80211_key *key, u8 *iv);
+u8 * ieee80211_wep_add_iv(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_key *key);
+void ieee80211_wep_remove_iv(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ struct ieee80211_key *key);
+void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+ size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
+ size_t klen, u8 *data, size_t data_len);
+int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_key *key);
+int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb,
+ struct ieee80211_key *key);
+int ieee80211_wep_get_keyidx(struct sk_buff *skb);
+u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
+
+#endif /* WEP_H */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
new file mode 100644
index 00000000000..89ce8152969
--- /dev/null
+++ b/net/mac80211/wme.c
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2004, Instant802 Networks, Inc.
+ *
+ * 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/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/module.h>
+#include <linux/if_arp.h>
+#include <linux/types.h>
+#include <net/ip.h>
+#include <net/pkt_sched.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "wme.h"
+
+static inline int WLAN_FC_IS_QOS_DATA(u16 fc)
+{
+ return (fc & 0x8C) == 0x88;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
+{
+ u8 *data = rx->skb->data;
+ int tid;
+
+ /* does the frame have a qos control field? */
+ if (WLAN_FC_IS_QOS_DATA(rx->fc)) {
+ u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
+ /* frame has qos control */
+ tid = qc[0] & QOS_CONTROL_TID_MASK;
+ } else {
+ if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
+ /* Separate TID for management frames */
+ tid = NUM_RX_DATA_QUEUES - 1;
+ } else {
+ /* no qos control present */
+ tid = 0; /* 802.1d - Best Effort */
+ }
+ }
+#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
+ I802_DEBUG_INC(rx->local->wme_rx_queue[tid]);
+ if (rx->sta) {
+ I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]);
+ }
+#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */
+
+ rx->u.rx.queue = tid;
+ /* Set skb->priority to 1d tag if highest order bit of TID is not set.
+ * For now, set skb->priority to 0 for other cases. */
+ rx->skb->priority = (tid > 7) ? 0 : tid;
+
+ return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx)
+{
+ u16 fc = rx->fc;
+ u8 *data = rx->skb->data;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data;
+
+ if (!WLAN_FC_IS_QOS_DATA(fc))
+ return TXRX_CONTINUE;
+
+ /* remove the qos control field, update frame type and meta-data */
+ memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2);
+ hdr = (struct ieee80211_hdr *) skb_pull(rx->skb, 2);
+ /* change frame type to non QOS */
+ rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA;
+ hdr->frame_control = cpu_to_le16(fc);
+
+ return TXRX_CONTINUE;
+}
+
+
+#ifdef CONFIG_NET_SCHED
+/* maximum number of hardware queues we support. */
+#define TC_80211_MAX_QUEUES 8
+
+struct ieee80211_sched_data
+{
+ struct tcf_proto *filter_list;
+ struct Qdisc *queues[TC_80211_MAX_QUEUES];
+ struct sk_buff_head requeued[TC_80211_MAX_QUEUES];
+};
+
+
+/* given a data frame determine the 802.1p/1d tag to use */
+static inline unsigned classify_1d(struct sk_buff *skb, struct Qdisc *qd)
+{
+ struct iphdr *ip;
+ int dscp;
+ int offset;
+
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct tcf_result res = { -1, 0 };
+
+ /* if there is a user set filter list, call out to that */
+ if (q->filter_list) {
+ tc_classify(skb, q->filter_list, &res);
+ if (res.class != -1)
+ return res.class;
+ }
+
+ /* skb->priority values from 256->263 are magic values to
+ * directly indicate a specific 802.1d priority.
+ * This is used to allow 802.1d priority to be passed directly in
+ * from VLAN tags, etc. */
+ if (skb->priority >= 256 && skb->priority <= 263)
+ return skb->priority - 256;
+
+ /* check there is a valid IP header present */
+ offset = ieee80211_get_hdrlen_from_skb(skb) + 8 /* LLC + proto */;
+ if (skb->protocol != __constant_htons(ETH_P_IP) ||
+ skb->len < offset + sizeof(*ip))
+ return 0;
+
+ ip = (struct iphdr *) (skb->data + offset);
+
+ dscp = ip->tos & 0xfc;
+ if (dscp & 0x1c)
+ return 0;
+ return dscp >> 5;
+}
+
+
+static inline int wme_downgrade_ac(struct sk_buff *skb)
+{
+ switch (skb->priority) {
+ case 6:
+ case 7:
+ skb->priority = 5; /* VO -> VI */
+ return 0;
+ case 4:
+ case 5:
+ skb->priority = 3; /* VI -> BE */
+ return 0;
+ case 0:
+ case 3:
+ skb->priority = 2; /* BE -> BK */
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+
+/* positive return value indicates which queue to use
+ * negative return value indicates to drop the frame */
+static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd)
+{
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_tx_packet_data *pkt_data =
+ (struct ieee80211_tx_packet_data *) skb->cb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ unsigned short fc = le16_to_cpu(hdr->frame_control);
+ int qos;
+ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
+
+ /* see if frame is data or non data frame */
+ if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) {
+ /* management frames go on AC_VO queue, but are sent
+ * without QoS control fields */
+ return IEEE80211_TX_QUEUE_DATA0;
+ }
+
+ if (unlikely(pkt_data->mgmt_iface)) {
+ /* Data frames from hostapd (mainly, EAPOL) use AC_VO
+ * and they will include QoS control fields if
+ * the target STA is using WME. */
+ skb->priority = 7;
+ return ieee802_1d_to_ac[skb->priority];
+ }
+
+ /* is this a QoS frame? */
+ qos = fc & IEEE80211_STYPE_QOS_DATA;
+
+ if (!qos) {
+ skb->priority = 0; /* required for correct WPA/11i MIC */
+ return ieee802_1d_to_ac[skb->priority];
+ }
+
+ /* use the data classifier to determine what 802.1d tag the
+ * data frame has */
+ skb->priority = classify_1d(skb, qd);
+
+ /* incase we are a client verify acm is not set for this ac */
+ while (unlikely(local->wmm_acm & BIT(skb->priority))) {
+ if (wme_downgrade_ac(skb)) {
+ /* No AC with lower priority has acm=0,
+ * drop packet. */
+ return -1;
+ }
+ }
+
+ /* look up which queue to use for frames with this 1d tag */
+ return ieee802_1d_to_ac[skb->priority];
+}
+
+
+static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd)
+{
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_tx_packet_data *pkt_data =
+ (struct ieee80211_tx_packet_data *) skb->cb;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ unsigned short fc = le16_to_cpu(hdr->frame_control);
+ struct Qdisc *qdisc;
+ int err, queue;
+
+ if (pkt_data->requeue) {
+ skb_queue_tail(&q->requeued[pkt_data->queue], skb);
+ qd->q.qlen++;
+ return 0;
+ }
+
+ queue = classify80211(skb, qd);
+
+ /* now we know the 1d priority, fill in the QoS header if there is one
+ */
+ if (WLAN_FC_IS_QOS_DATA(fc)) {
+ u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2;
+ u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK;
+ if (local->wifi_wme_noack_test)
+ qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK <<
+ QOS_CONTROL_ACK_POLICY_SHIFT;
+ /* qos header is 2 bytes, second reserved */
+ *p = qos_hdr;
+ p++;
+ *p = 0;
+ }
+
+ if (unlikely(queue >= local->hw.queues)) {
+#if 0
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s - queue=%d (hw does not "
+ "support) -> %d\n",
+ __func__, queue, local->hw.queues - 1);
+ }
+#endif
+ queue = local->hw.queues - 1;
+ }
+
+ if (unlikely(queue < 0)) {
+ kfree_skb(skb);
+ err = NET_XMIT_DROP;
+ } else {
+ pkt_data->queue = (unsigned int) queue;
+ qdisc = q->queues[queue];
+ err = qdisc->enqueue(skb, qdisc);
+ if (err == NET_XMIT_SUCCESS) {
+ qd->q.qlen++;
+ qd->bstats.bytes += skb->len;
+ qd->bstats.packets++;
+ return NET_XMIT_SUCCESS;
+ }
+ }
+ qd->qstats.drops++;
+ return err;
+}
+
+
+/* TODO: clean up the cases where master_hard_start_xmit
+ * returns non 0 - it shouldn't ever do that. Once done we
+ * can remove this function */
+static int wme_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_tx_packet_data *pkt_data =
+ (struct ieee80211_tx_packet_data *) skb->cb;
+ struct Qdisc *qdisc;
+ int err;
+
+ /* we recorded which queue to use earlier! */
+ qdisc = q->queues[pkt_data->queue];
+
+ if ((err = qdisc->ops->requeue(skb, qdisc)) == 0) {
+ qd->q.qlen++;
+ return 0;
+ }
+ qd->qstats.drops++;
+ return err;
+}
+
+
+static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct net_device *dev = qd->dev;
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ struct sk_buff *skb;
+ struct Qdisc *qdisc;
+ int queue;
+
+ /* check all the h/w queues in numeric/priority order */
+ for (queue = 0; queue < hw->queues; queue++) {
+ /* see if there is room in this hardware queue */
+ if (test_bit(IEEE80211_LINK_STATE_XOFF,
+ &local->state[queue]) ||
+ test_bit(IEEE80211_LINK_STATE_PENDING,
+ &local->state[queue]))
+ continue;
+
+ /* there is space - try and get a frame */
+ skb = skb_dequeue(&q->requeued[queue]);
+ if (skb) {
+ qd->q.qlen--;
+ return skb;
+ }
+
+ qdisc = q->queues[queue];
+ skb = qdisc->dequeue(qdisc);
+ if (skb) {
+ qd->q.qlen--;
+ return skb;
+ }
+ }
+ /* returning a NULL here when all the h/w queues are full means we
+ * never need to call netif_stop_queue in the driver */
+ return NULL;
+}
+
+
+static void wme_qdiscop_reset(struct Qdisc* qd)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ int queue;
+
+ /* QUESTION: should we have some hardware flush functionality here? */
+
+ for (queue = 0; queue < hw->queues; queue++) {
+ skb_queue_purge(&q->requeued[queue]);
+ qdisc_reset(q->queues[queue]);
+ }
+ qd->q.qlen = 0;
+}
+
+
+static void wme_qdiscop_destroy(struct Qdisc* qd)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ int queue;
+
+ tcf_destroy_chain(q->filter_list);
+ q->filter_list = NULL;
+
+ for (queue=0; queue < hw->queues; queue++) {
+ skb_queue_purge(&q->requeued[queue]);
+ qdisc_destroy(q->queues[queue]);
+ q->queues[queue] = &noop_qdisc;
+ }
+}
+
+
+/* called whenever parameters are updated on existing qdisc */
+static int wme_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt)
+{
+/* struct ieee80211_sched_data *q = qdisc_priv(qd);
+*/
+ /* check our options block is the right size */
+ /* copy any options to our local structure */
+/* Ignore options block for now - always use static mapping
+ struct tc_ieee80211_qopt *qopt = RTA_DATA(opt);
+
+ if (opt->rta_len < RTA_LENGTH(sizeof(*qopt)))
+ return -EINVAL;
+ memcpy(q->tag2queue, qopt->tag2queue, sizeof(qopt->tag2queue));
+*/
+ return 0;
+}
+
+
+/* called during initial creation of qdisc on device */
+static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct net_device *dev = qd->dev;
+ struct ieee80211_local *local;
+ int queues;
+ int err = 0, i;
+
+ /* check that device is a mac80211 device */
+ if (!dev->ieee80211_ptr ||
+ dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
+ return -EINVAL;
+
+ /* check this device is an ieee80211 master type device */
+ if (dev->type != ARPHRD_IEEE80211)
+ return -EINVAL;
+
+ /* check that there is no qdisc currently attached to device
+ * this ensures that we will be the root qdisc. (I can't find a better
+ * way to test this explicitly) */
+ if (dev->qdisc_sleeping != &noop_qdisc)
+ return -EINVAL;
+
+ if (qd->flags & TCQ_F_INGRESS)
+ return -EINVAL;
+
+ local = wdev_priv(dev->ieee80211_ptr);
+ queues = local->hw.queues;
+
+ /* if options were passed in, set them */
+ if (opt) {
+ err = wme_qdiscop_tune(qd, opt);
+ }
+
+ /* create child queues */
+ for (i = 0; i < queues; i++) {
+ skb_queue_head_init(&q->requeued[i]);
+ q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
+ qd->handle);
+ if (q->queues[i] == 0) {
+ q->queues[i] = &noop_qdisc;
+ printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i);
+ }
+ }
+
+ return err;
+}
+
+static int wme_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb)
+{
+/* struct ieee80211_sched_data *q = qdisc_priv(qd);
+ unsigned char *p = skb->tail;
+ struct tc_ieee80211_qopt opt;
+
+ memcpy(&opt.tag2queue, q->tag2queue, TC_80211_MAX_TAG + 1);
+ RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+*/ return skb->len;
+/*
+rtattr_failure:
+ skb_trim(skb, p - skb->data);*/
+ return -1;
+}
+
+
+static int wme_classop_graft(struct Qdisc *qd, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ unsigned long queue = arg - 1;
+
+ if (queue >= hw->queues)
+ return -EINVAL;
+
+ if (!new)
+ new = &noop_qdisc;
+
+ sch_tree_lock(qd);
+ *old = q->queues[queue];
+ q->queues[queue] = new;
+ qdisc_reset(*old);
+ sch_tree_unlock(qd);
+
+ return 0;
+}
+
+
+static struct Qdisc *
+wme_classop_leaf(struct Qdisc *qd, unsigned long arg)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ unsigned long queue = arg - 1;
+
+ if (queue >= hw->queues)
+ return NULL;
+
+ return q->queues[queue];
+}
+
+
+static unsigned long wme_classop_get(struct Qdisc *qd, u32 classid)
+{
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ unsigned long queue = TC_H_MIN(classid);
+
+ if (queue - 1 >= hw->queues)
+ return 0;
+
+ return queue;
+}
+
+
+static unsigned long wme_classop_bind(struct Qdisc *qd, unsigned long parent,
+ u32 classid)
+{
+ return wme_classop_get(qd, classid);
+}
+
+
+static void wme_classop_put(struct Qdisc *q, unsigned long cl)
+{
+}
+
+
+static int wme_classop_change(struct Qdisc *qd, u32 handle, u32 parent,
+ struct rtattr **tca, unsigned long *arg)
+{
+ unsigned long cl = *arg;
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+
+ if (cl - 1 > hw->queues)
+ return -ENOENT;
+
+ /* TODO: put code to program hardware queue parameters here,
+ * to allow programming from tc command line */
+
+ return 0;
+}
+
+
+/* we don't support deleting hardware queues
+ * when we add WMM-SA support - TSPECs may be deleted here */
+static int wme_classop_delete(struct Qdisc *qd, unsigned long cl)
+{
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+
+ if (cl - 1 > hw->queues)
+ return -ENOENT;
+ return 0;
+}
+
+
+static int wme_classop_dump_class(struct Qdisc *qd, unsigned long cl,
+ struct sk_buff *skb, struct tcmsg *tcm)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+
+ if (cl - 1 > hw->queues)
+ return -ENOENT;
+ tcm->tcm_handle = TC_H_MIN(cl);
+ tcm->tcm_parent = qd->handle;
+ tcm->tcm_info = q->queues[cl-1]->handle; /* do we need this? */
+ return 0;
+}
+
+
+static void wme_classop_walk(struct Qdisc *qd, struct qdisc_walker *arg)
+{
+ struct ieee80211_local *local = wdev_priv(qd->dev->ieee80211_ptr);
+ struct ieee80211_hw *hw = &local->hw;
+ int queue;
+
+ if (arg->stop)
+ return;
+
+ for (queue = 0; queue < hw->queues; queue++) {
+ if (arg->count < arg->skip) {
+ arg->count++;
+ continue;
+ }
+ /* we should return classids for our internal queues here
+ * as well as the external ones */
+ if (arg->fn(qd, queue+1, arg) < 0) {
+ arg->stop = 1;
+ break;
+ }
+ arg->count++;
+ }
+}
+
+
+static struct tcf_proto ** wme_classop_find_tcf(struct Qdisc *qd,
+ unsigned long cl)
+{
+ struct ieee80211_sched_data *q = qdisc_priv(qd);
+
+ if (cl)
+ return NULL;
+
+ return &q->filter_list;
+}
+
+
+/* this qdisc is classful (i.e. has classes, some of which may have leaf qdiscs attached)
+ * - these are the operations on the classes */
+static struct Qdisc_class_ops class_ops =
+{
+ .graft = wme_classop_graft,
+ .leaf = wme_classop_leaf,
+
+ .get = wme_classop_get,
+ .put = wme_classop_put,
+ .change = wme_classop_change,
+ .delete = wme_classop_delete,
+ .walk = wme_classop_walk,
+
+ .tcf_chain = wme_classop_find_tcf,
+ .bind_tcf = wme_classop_bind,
+ .unbind_tcf = wme_classop_put,
+
+ .dump = wme_classop_dump_class,
+};
+
+
+/* queueing discipline operations */
+static struct Qdisc_ops wme_qdisc_ops =
+{
+ .next = NULL,
+ .cl_ops = &class_ops,
+ .id = "ieee80211",
+ .priv_size = sizeof(struct ieee80211_sched_data),
+
+ .enqueue = wme_qdiscop_enqueue,
+ .dequeue = wme_qdiscop_dequeue,
+ .requeue = wme_qdiscop_requeue,
+ .drop = NULL, /* drop not needed since we are always the root qdisc */
+
+ .init = wme_qdiscop_init,
+ .reset = wme_qdiscop_reset,
+ .destroy = wme_qdiscop_destroy,
+ .change = wme_qdiscop_tune,
+
+ .dump = wme_qdiscop_dump,
+};
+
+
+void ieee80211_install_qdisc(struct net_device *dev)
+{
+ struct Qdisc *qdisc;
+
+ qdisc = qdisc_create_dflt(dev, &wme_qdisc_ops, TC_H_ROOT);
+ if (!qdisc) {
+ printk(KERN_ERR "%s: qdisc installation failed\n", dev->name);
+ return;
+ }
+
+ /* same handle as would be allocated by qdisc_alloc_handle() */
+ qdisc->handle = 0x80010000;
+
+ qdisc_lock_tree(dev);
+ list_add_tail(&qdisc->list, &dev->qdisc_list);
+ dev->qdisc_sleeping = qdisc;
+ qdisc_unlock_tree(dev);
+}
+
+
+int ieee80211_qdisc_installed(struct net_device *dev)
+{
+ return dev->qdisc_sleeping->ops == &wme_qdisc_ops;
+}
+
+
+int ieee80211_wme_register(void)
+{
+ return register_qdisc(&wme_qdisc_ops);
+}
+
+
+void ieee80211_wme_unregister(void)
+{
+ unregister_qdisc(&wme_qdisc_ops);
+}
+#endif /* CONFIG_NET_SCHED */
diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h
new file mode 100644
index 00000000000..f0bff10f0e0
--- /dev/null
+++ b/net/mac80211/wme.h
@@ -0,0 +1,57 @@
+/*
+ * IEEE 802.11 driver (80211.o) - QoS datatypes
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef _WME_H
+#define _WME_H
+
+#include <linux/netdevice.h>
+#include "ieee80211_i.h"
+
+#define QOS_CONTROL_LEN 2
+
+#define QOS_CONTROL_ACK_POLICY_NORMAL 0
+#define QOS_CONTROL_ACK_POLICY_NOACK 1
+
+#define QOS_CONTROL_TID_MASK 0x0f
+#define QOS_CONTROL_ACK_POLICY_SHIFT 5
+
+#define QOS_CONTROL_TAG1D_MASK 0x07
+
+ieee80211_txrx_result
+ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx);
+
+ieee80211_txrx_result
+ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx);
+
+#ifdef CONFIG_NET_SCHED
+void ieee80211_install_qdisc(struct net_device *dev);
+int ieee80211_qdisc_installed(struct net_device *dev);
+
+int ieee80211_wme_register(void);
+void ieee80211_wme_unregister(void);
+#else
+static inline void ieee80211_install_qdisc(struct net_device *dev)
+{
+}
+static inline int ieee80211_qdisc_installed(struct net_device *dev)
+{
+ return 0;
+}
+
+static inline int ieee80211_wme_register(void)
+{
+ return 0;
+}
+static inline void ieee80211_wme_unregister(void)
+{
+}
+#endif /* CONFIG_NET_SCHED */
+
+#endif /* _WME_H */
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
new file mode 100644
index 00000000000..783af32c691
--- /dev/null
+++ b/net/mac80211/wpa.c
@@ -0,0 +1,660 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ *
+ * 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/netdevice.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <linux/compiler.h>
+#include <net/iw_handler.h>
+
+#include <net/mac80211.h>
+#include "ieee80211_common.h"
+#include "ieee80211_i.h"
+#include "michael.h"
+#include "tkip.h"
+#include "aes_ccm.h"
+#include "wpa.h"
+
+static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da,
+ u8 *qos_tid, u8 **data, size_t *data_len)
+{
+ struct ieee80211_hdr *hdr;
+ size_t hdrlen;
+ u16 fc;
+ int a4_included;
+ u8 *pos;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ hdrlen = 24;
+ if ((fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) ==
+ (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
+ hdrlen += ETH_ALEN;
+ *sa = hdr->addr4;
+ *da = hdr->addr3;
+ } else if (fc & IEEE80211_FCTL_FROMDS) {
+ *sa = hdr->addr3;
+ *da = hdr->addr1;
+ } else if (fc & IEEE80211_FCTL_TODS) {
+ *sa = hdr->addr2;
+ *da = hdr->addr3;
+ } else {
+ *sa = hdr->addr2;
+ *da = hdr->addr1;
+ }
+
+ if (fc & 0x80)
+ hdrlen += 2;
+
+ *data = skb->data + hdrlen;
+ *data_len = skb->len - hdrlen;
+
+ a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA &&
+ fc & IEEE80211_STYPE_QOS_DATA) {
+ pos = (u8 *) &hdr->addr4;
+ if (a4_included)
+ pos += 6;
+ *qos_tid = pos[0] & 0x0f;
+ *qos_tid |= 0x80; /* qos_included flag */
+ } else
+ *qos_tid = 0;
+
+ return skb->len < hdrlen ? -1 : 0;
+}
+
+
+ieee80211_txrx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx)
+{
+ u8 *data, *sa, *da, *key, *mic, qos_tid;
+ size_t data_len;
+ u16 fc;
+ struct sk_buff *skb = tx->skb;
+ int authenticator;
+ int wpa_test = 0;
+
+ fc = tx->fc;
+
+ if (!tx->key || tx->key->alg != ALG_TKIP || skb->len < 24 ||
+ !WLAN_FC_DATA_PRESENT(fc))
+ return TXRX_CONTINUE;
+
+ if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len))
+ return TXRX_DROP;
+
+ if (!tx->key->force_sw_encrypt &&
+ !tx->fragmented &&
+ !(tx->local->hw.flags & IEEE80211_HW_TKIP_INCLUDE_MMIC) &&
+ !wpa_test) {
+ /* hwaccel - with no need for preallocated room for Michael MIC
+ */
+ return TXRX_CONTINUE;
+ }
+
+ if (skb_tailroom(skb) < MICHAEL_MIC_LEN) {
+ I802_DEBUG_INC(tx->local->tx_expand_skb_head);
+ if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN,
+ MICHAEL_MIC_LEN + TKIP_ICV_LEN,
+ GFP_ATOMIC))) {
+ printk(KERN_DEBUG "%s: failed to allocate more memory "
+ "for Michael MIC\n", tx->dev->name);
+ return TXRX_DROP;
+ }
+ }
+
+#if 0
+ authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */
+#else
+ authenticator = 1;
+#endif
+ key = &tx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_TX_MIC_KEY :
+ ALG_TKIP_TEMP_AUTH_RX_MIC_KEY];
+ mic = skb_put(skb, MICHAEL_MIC_LEN);
+ michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
+
+ return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx)
+{
+ u8 *data, *sa, *da, *key = NULL, qos_tid;
+ size_t data_len;
+ u16 fc;
+ u8 mic[MICHAEL_MIC_LEN];
+ struct sk_buff *skb = rx->skb;
+ int authenticator = 1, wpa_test = 0;
+
+ fc = rx->fc;
+
+ /* If device handles decryption totally, skip this check */
+ if ((rx->local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) ||
+ (rx->local->hw.flags & IEEE80211_HW_DEVICE_STRIPS_MIC))
+ return TXRX_CONTINUE;
+
+ if (!rx->key || rx->key->alg != ALG_TKIP ||
+ !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc))
+ return TXRX_CONTINUE;
+
+ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+ !rx->key->force_sw_encrypt) {
+ if (rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) {
+ if (skb->len < MICHAEL_MIC_LEN)
+ return TXRX_DROP;
+ }
+ /* Need to verify Michael MIC sometimes in software even when
+ * hwaccel is used. Atheros ar5212: fragmented frames and QoS
+ * frames. */
+ if (!rx->fragmented && !wpa_test)
+ goto remove_mic;
+ }
+
+ if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)
+ || data_len < MICHAEL_MIC_LEN)
+ return TXRX_DROP;
+
+ data_len -= MICHAEL_MIC_LEN;
+
+#if 0
+ authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */
+#else
+ authenticator = 1;
+#endif
+ key = &rx->key->key[authenticator ? ALG_TKIP_TEMP_AUTH_RX_MIC_KEY :
+ ALG_TKIP_TEMP_AUTH_TX_MIC_KEY];
+ michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic);
+ if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) {
+ if (!rx->u.rx.ra_match)
+ return TXRX_DROP;
+
+ printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
+ MAC_FMT "\n", rx->dev->name, MAC_ARG(sa));
+
+ do {
+ struct ieee80211_hdr *hdr;
+ union iwreq_data wrqu;
+ char *buf = kmalloc(128, GFP_ATOMIC);
+ if (!buf)
+ break;
+
+ /* TODO: needed parameters: count, key type, TSC */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
+ "keyid=%d %scast addr=" MAC_FMT ")",
+ rx->key->keyidx,
+ hdr->addr1[0] & 0x01 ? "broad" : "uni",
+ MAC_ARG(hdr->addr2));
+ memset(&wrqu, 0, sizeof(wrqu));
+ wrqu.data.length = strlen(buf);
+ wireless_send_event(rx->dev, IWEVCUSTOM, &wrqu, buf);
+ kfree(buf);
+ } while (0);
+
+ if (!rx->local->apdev)
+ return TXRX_DROP;
+
+ ieee80211_rx_mgmt(rx->local, rx->skb, rx->u.rx.status,
+ ieee80211_msg_michael_mic_failure);
+
+ return TXRX_QUEUED;
+ }
+
+ remove_mic:
+ /* remove Michael MIC from payload */
+ skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+
+ return TXRX_CONTINUE;
+}
+
+
+static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb, int test)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_key *key = tx->key;
+ int hdrlen, len, tailneed;
+ u16 fc;
+ u8 *pos;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ hdrlen = ieee80211_get_hdrlen(fc);
+ len = skb->len - hdrlen;
+
+ tailneed = !tx->key->force_sw_encrypt ? 0 : TKIP_ICV_LEN;
+ if ((skb_headroom(skb) < TKIP_IV_LEN ||
+ skb_tailroom(skb) < tailneed)) {
+ I802_DEBUG_INC(tx->local->tx_expand_skb_head);
+ if (unlikely(pskb_expand_head(skb, TKIP_IV_LEN, tailneed,
+ GFP_ATOMIC)))
+ return -1;
+ }
+
+ pos = skb_push(skb, TKIP_IV_LEN);
+ memmove(pos, pos + TKIP_IV_LEN, hdrlen);
+ pos += hdrlen;
+
+ /* Increase IV for the frame */
+ key->u.tkip.iv16++;
+ if (key->u.tkip.iv16 == 0)
+ key->u.tkip.iv32++;
+
+ if (!tx->key->force_sw_encrypt) {
+ u32 flags = tx->local->hw.flags;
+ hdr = (struct ieee80211_hdr *)skb->data;
+
+ /* hwaccel - with preallocated room for IV */
+ ieee80211_tkip_add_iv(pos, key,
+ (u8) (key->u.tkip.iv16 >> 8),
+ (u8) (((key->u.tkip.iv16 >> 8) | 0x20) &
+ 0x7f),
+ (u8) key->u.tkip.iv16);
+
+ if (flags & IEEE80211_HW_TKIP_REQ_PHASE2_KEY)
+ ieee80211_tkip_gen_rc4key(key, hdr->addr2,
+ tx->u.tx.control->tkip_key);
+ else if (flags & IEEE80211_HW_TKIP_REQ_PHASE1_KEY) {
+ if (key->u.tkip.iv16 == 0 ||
+ !key->u.tkip.tx_initialized) {
+ ieee80211_tkip_gen_phase1key(key, hdr->addr2,
+ (u16 *)tx->u.tx.control->tkip_key);
+ key->u.tkip.tx_initialized = 1;
+ tx->u.tx.control->flags |=
+ IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
+ } else
+ tx->u.tx.control->flags &=
+ ~IEEE80211_TXCTL_TKIP_NEW_PHASE1_KEY;
+ }
+
+ tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+ return 0;
+ }
+
+ /* Add room for ICV */
+ skb_put(skb, TKIP_ICV_LEN);
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ ieee80211_tkip_encrypt_data(tx->local->wep_tx_tfm,
+ key, pos, len, hdr->addr2);
+ return 0;
+}
+
+
+ieee80211_txrx_result
+ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ u16 fc;
+ struct ieee80211_key *key = tx->key;
+ struct sk_buff *skb = tx->skb;
+ int wpa_test = 0, test = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+ if (!key || key->alg != ALG_TKIP || !WLAN_FC_DATA_PRESENT(fc))
+ return TXRX_CONTINUE;
+
+ tx->u.tx.control->icv_len = TKIP_ICV_LEN;
+ tx->u.tx.control->iv_len = TKIP_IV_LEN;
+ ieee80211_tx_set_iswep(tx);
+
+ if (!tx->key->force_sw_encrypt &&
+ !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV) &&
+ !wpa_test) {
+ /* hwaccel - with no need for preallocated room for IV/ICV */
+ tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+ return TXRX_CONTINUE;
+ }
+
+ if (tkip_encrypt_skb(tx, skb, test) < 0)
+ return TXRX_DROP;
+
+ if (tx->u.tx.extra_frag) {
+ int i;
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+ < 0)
+ return TXRX_DROP;
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+ u16 fc;
+ int hdrlen, res, hwaccel = 0, wpa_test = 0;
+ struct ieee80211_key *key = rx->key;
+ struct sk_buff *skb = rx->skb;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ if (!rx->key || rx->key->alg != ALG_TKIP ||
+ !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+ (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+ return TXRX_CONTINUE;
+
+ if (!rx->sta || skb->len - hdrlen < 12)
+ return TXRX_DROP;
+
+ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+ !rx->key->force_sw_encrypt) {
+ if (!(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
+ /* Hardware takes care of all processing, including
+ * replay protection, so no need to continue here. */
+ return TXRX_CONTINUE;
+ }
+
+ /* let TKIP code verify IV, but skip decryption */
+ hwaccel = 1;
+ }
+
+ res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
+ key, skb->data + hdrlen,
+ skb->len - hdrlen, rx->sta->addr,
+ hwaccel, rx->u.rx.queue);
+ if (res != TKIP_DECRYPT_OK || wpa_test) {
+ printk(KERN_DEBUG "%s: TKIP decrypt failed for RX frame from "
+ MAC_FMT " (res=%d)\n",
+ rx->dev->name, MAC_ARG(rx->sta->addr), res);
+ return TXRX_DROP;
+ }
+
+ /* Trim ICV */
+ skb_trim(skb, skb->len - TKIP_ICV_LEN);
+
+ /* Remove IV */
+ memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen);
+ skb_pull(skb, TKIP_IV_LEN);
+
+ return TXRX_CONTINUE;
+}
+
+
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
+ int encrypted)
+{
+ u16 fc;
+ int a4_included, qos_included;
+ u8 qos_tid, *fc_pos, *data, *sa, *da;
+ int len_a;
+ size_t data_len;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+ fc_pos = (u8 *) &hdr->frame_control;
+ fc = fc_pos[0] ^ (fc_pos[1] << 8);
+ a4_included = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
+ (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS);
+
+ ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len);
+ data_len -= CCMP_HDR_LEN + (encrypted ? CCMP_MIC_LEN : 0);
+ if (qos_tid & 0x80) {
+ qos_included = 1;
+ qos_tid &= 0x0f;
+ } else
+ qos_included = 0;
+ /* First block, b_0 */
+
+ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
+ /* Nonce: QoS Priority | A2 | PN */
+ b_0[1] = qos_tid;
+ memcpy(&b_0[2], hdr->addr2, 6);
+ memcpy(&b_0[8], pn, CCMP_PN_LEN);
+ /* l(m) */
+ b_0[14] = (data_len >> 8) & 0xff;
+ b_0[15] = data_len & 0xff;
+
+
+ /* AAD (extra authenticate-only data) / masked 802.11 header
+ * FC | A1 | A2 | A3 | SC | [A4] | [QC] */
+
+ len_a = a4_included ? 28 : 22;
+ if (qos_included)
+ len_a += 2;
+
+ aad[0] = 0; /* (len_a >> 8) & 0xff; */
+ aad[1] = len_a & 0xff;
+ /* Mask FC: zero subtype b4 b5 b6 */
+ aad[2] = fc_pos[0] & ~(BIT(4) | BIT(5) | BIT(6));
+ /* Retry, PwrMgt, MoreData; set Protected */
+ aad[3] = (fc_pos[1] & ~(BIT(3) | BIT(4) | BIT(5))) | BIT(6);
+ memcpy(&aad[4], &hdr->addr1, 18);
+
+ /* Mask Seq#, leave Frag# */
+ aad[22] = *((u8 *) &hdr->seq_ctrl) & 0x0f;
+ aad[23] = 0;
+ if (a4_included) {
+ memcpy(&aad[24], hdr->addr4, 6);
+ aad[30] = 0;
+ aad[31] = 0;
+ } else
+ memset(&aad[24], 0, 8);
+ if (qos_included) {
+ u8 *dpos = &aad[a4_included ? 30 : 24];
+
+ /* Mask QoS Control field */
+ dpos[0] = qos_tid;
+ dpos[1] = 0;
+ }
+}
+
+
+static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id)
+{
+ hdr[0] = pn[5];
+ hdr[1] = pn[4];
+ hdr[2] = 0;
+ hdr[3] = 0x20 | (key_id << 6);
+ hdr[4] = pn[3];
+ hdr[5] = pn[2];
+ hdr[6] = pn[1];
+ hdr[7] = pn[0];
+}
+
+
+static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr)
+{
+ pn[0] = hdr[7];
+ pn[1] = hdr[6];
+ pn[2] = hdr[5];
+ pn[3] = hdr[4];
+ pn[4] = hdr[1];
+ pn[5] = hdr[0];
+ return (hdr[3] >> 6) & 0x03;
+}
+
+
+static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb, int test)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_key *key = tx->key;
+ int hdrlen, len, tailneed;
+ u16 fc;
+ u8 *pos, *pn, *b_0, *aad, *scratch;
+ int i;
+
+ scratch = key->u.ccmp.tx_crypto_buf;
+ b_0 = scratch + 3 * AES_BLOCK_LEN;
+ aad = scratch + 4 * AES_BLOCK_LEN;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ hdrlen = ieee80211_get_hdrlen(fc);
+ len = skb->len - hdrlen;
+
+ tailneed = !key->force_sw_encrypt ? 0 : CCMP_MIC_LEN;
+
+ if ((skb_headroom(skb) < CCMP_HDR_LEN ||
+ skb_tailroom(skb) < tailneed)) {
+ I802_DEBUG_INC(tx->local->tx_expand_skb_head);
+ if (unlikely(pskb_expand_head(skb, CCMP_HDR_LEN, tailneed,
+ GFP_ATOMIC)))
+ return -1;
+ }
+
+ pos = skb_push(skb, CCMP_HDR_LEN);
+ memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
+ hdr = (struct ieee80211_hdr *) pos;
+ pos += hdrlen;
+
+ /* PN = PN + 1 */
+ pn = key->u.ccmp.tx_pn;
+
+ for (i = CCMP_PN_LEN - 1; i >= 0; i--) {
+ pn[i]++;
+ if (pn[i])
+ break;
+ }
+
+ ccmp_pn2hdr(pos, pn, key->keyidx);
+
+ if (!key->force_sw_encrypt) {
+ /* hwaccel - with preallocated room for CCMP header */
+ tx->u.tx.control->key_idx = key->hw_key_idx;
+ return 0;
+ }
+
+ pos += CCMP_HDR_LEN;
+ ccmp_special_blocks(skb, pn, b_0, aad, 0);
+ ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, scratch, b_0, aad, pos, len,
+ pos, skb_put(skb, CCMP_MIC_LEN));
+
+ return 0;
+}
+
+
+ieee80211_txrx_result
+ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
+ struct ieee80211_key *key = tx->key;
+ u16 fc;
+ struct sk_buff *skb = tx->skb;
+ int test = 0;
+
+ fc = le16_to_cpu(hdr->frame_control);
+
+ if (!key || key->alg != ALG_CCMP || !WLAN_FC_DATA_PRESENT(fc))
+ return TXRX_CONTINUE;
+
+ tx->u.tx.control->icv_len = CCMP_MIC_LEN;
+ tx->u.tx.control->iv_len = CCMP_HDR_LEN;
+ ieee80211_tx_set_iswep(tx);
+
+ if (!tx->key->force_sw_encrypt &&
+ !(tx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV)) {
+ /* hwaccel - with no need for preallocated room for CCMP "
+ * header or MIC fields */
+ tx->u.tx.control->key_idx = tx->key->hw_key_idx;
+ return TXRX_CONTINUE;
+ }
+
+ if (ccmp_encrypt_skb(tx, skb, test) < 0)
+ return TXRX_DROP;
+
+ if (tx->u.tx.extra_frag) {
+ int i;
+
+ for (i = 0; i < tx->u.tx.num_extra_frag; i++) {
+ if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test)
+ < 0)
+ return TXRX_DROP;
+ }
+ }
+
+ return TXRX_CONTINUE;
+}
+
+
+ieee80211_txrx_result
+ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+ u16 fc;
+ int hdrlen;
+ struct ieee80211_key *key = rx->key;
+ struct sk_buff *skb = rx->skb;
+ u8 pn[CCMP_PN_LEN];
+ int data_len;
+
+ fc = le16_to_cpu(hdr->frame_control);
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ if (!key || key->alg != ALG_CCMP ||
+ !(rx->fc & IEEE80211_FCTL_PROTECTED) ||
+ (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+ return TXRX_CONTINUE;
+
+ data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN;
+ if (!rx->sta || data_len < 0)
+ return TXRX_DROP;
+
+ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+ !key->force_sw_encrypt &&
+ !(rx->local->hw.flags & IEEE80211_HW_WEP_INCLUDE_IV))
+ return TXRX_CONTINUE;
+
+ (void) ccmp_hdr2pn(pn, skb->data + hdrlen);
+
+ if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) {
+#ifdef CONFIG_MAC80211_DEBUG
+ u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue];
+ printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from "
+ MAC_FMT " (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN "
+ "%02x%02x%02x%02x%02x%02x)\n", rx->dev->name,
+ MAC_ARG(rx->sta->addr),
+ pn[0], pn[1], pn[2], pn[3], pn[4], pn[5],
+ ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]);
+#endif /* CONFIG_MAC80211_DEBUG */
+ key->u.ccmp.replays++;
+ return TXRX_DROP;
+ }
+
+ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) &&
+ !key->force_sw_encrypt) {
+ /* hwaccel has already decrypted frame and verified MIC */
+ } else {
+ u8 *scratch, *b_0, *aad;
+
+ scratch = key->u.ccmp.rx_crypto_buf;
+ b_0 = scratch + 3 * AES_BLOCK_LEN;
+ aad = scratch + 4 * AES_BLOCK_LEN;
+
+ ccmp_special_blocks(skb, pn, b_0, aad, 1);
+
+ if (ieee80211_aes_ccm_decrypt(
+ key->u.ccmp.tfm, scratch, b_0, aad,
+ skb->data + hdrlen + CCMP_HDR_LEN, data_len,
+ skb->data + skb->len - CCMP_MIC_LEN,
+ skb->data + hdrlen + CCMP_HDR_LEN)) {
+ printk(KERN_DEBUG "%s: CCMP decrypt failed for RX "
+ "frame from " MAC_FMT "\n", rx->dev->name,
+ MAC_ARG(rx->sta->addr));
+ return TXRX_DROP;
+ }
+ }
+
+ memcpy(key->u.ccmp.rx_pn[rx->u.rx.queue], pn, CCMP_PN_LEN);
+
+ /* Remove CCMP header and MIC */
+ skb_trim(skb, skb->len - CCMP_MIC_LEN);
+ memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen);
+ skb_pull(skb, CCMP_HDR_LEN);
+
+ return TXRX_CONTINUE;
+}
+
diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h
new file mode 100644
index 00000000000..da3b9594f9c
--- /dev/null
+++ b/net/mac80211/wpa.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2002-2004, Instant802 Networks, Inc.
+ *
+ * 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.
+ */
+
+#ifndef WPA_H
+#define WPA_H
+
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include "ieee80211_i.h"
+
+ieee80211_txrx_result
+ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx);
+ieee80211_txrx_result
+ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx);
+
+ieee80211_txrx_result
+ieee80211_tx_h_tkip_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_txrx_result
+ieee80211_rx_h_tkip_decrypt(struct ieee80211_txrx_data *rx);
+
+ieee80211_txrx_result
+ieee80211_tx_h_ccmp_encrypt(struct ieee80211_txrx_data *tx);
+ieee80211_txrx_result
+ieee80211_rx_h_ccmp_decrypt(struct ieee80211_txrx_data *rx);
+
+#endif /* WPA_H */
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c558f321425..a567dae8e5f 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -100,7 +100,7 @@ config NF_CT_PROTO_SCTP
tracking code will be able to do state tracking on SCTP connections.
If you want to compile it as a module, say M here and read
- Documentation/modules.txt. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NF_CONNTRACK_AMANDA
tristate "Amanda backup protocol support"
@@ -197,7 +197,7 @@ config NF_CONNTRACK_PPTP
Please note that not all PPTP modes of operation are supported yet.
Specifically these limitations exist:
- - Blindy assumes that control connections are always established
+ - Blindly assumes that control connections are always established
in PNS->PAC direction. This is a violation of RFC2637.
- Only supports a single call within each session
@@ -279,8 +279,8 @@ config NETFILTER_XT_TARGET_CONNMARK
affects the connection mark value rather than the packet mark value.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. The module will be called
- ipt_CONNMARK.o. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. The module will be called
+ ipt_CONNMARK.ko. If unsure, say `N'.
config NETFILTER_XT_TARGET_DSCP
tristate '"DSCP" target support'
@@ -341,7 +341,7 @@ config NETFILTER_XT_TARGET_NOTRACK
no protocol helpers for the selected packets).
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_TARGET_SECMARK
tristate '"SECMARK" target support'
@@ -397,7 +397,7 @@ config NETFILTER_XT_MATCH_COMMENT
comments in your iptables ruleset.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_MATCH_CONNBYTES
tristate '"connbytes" per-connection counter match support'
@@ -409,7 +409,7 @@ config NETFILTER_XT_MATCH_CONNBYTES
number of bytes and/or packets for each direction within a connection.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_MATCH_CONNMARK
tristate '"connmark" connection mark match support'
@@ -421,8 +421,8 @@ config NETFILTER_XT_MATCH_CONNMARK
connection mark value previously set for the session by `CONNMARK'.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. The module will be called
- ipt_connmark.o. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. The module will be called
+ ipt_connmark.ko. If unsure, say `N'.
config NETFILTER_XT_MATCH_CONNTRACK
tristate '"conntrack" connection tracking match support'
@@ -446,7 +446,7 @@ config NETFILTER_XT_MATCH_DCCP
and DCCP flags.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_MATCH_DSCP
tristate '"DSCP" match support'
@@ -565,7 +565,7 @@ config NETFILTER_XT_MATCH_QUOTA
byte counter.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_MATCH_REALM
tristate '"realm" match support'
@@ -579,7 +579,7 @@ config NETFILTER_XT_MATCH_REALM
in tc world.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_MATCH_SCTP
tristate '"sctp" protocol match support (EXPERIMENTAL)'
@@ -590,7 +590,7 @@ config NETFILTER_XT_MATCH_SCTP
and SCTP chunk types.
If you want to compile it as a module, say M here and read
- <file:Documentation/modules.txt>. If unsure, say `N'.
+ <file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
config NETFILTER_XT_MATCH_STATE
tristate '"state" match support'
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index c31af29a443..117cbfdb910 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -177,7 +177,7 @@ void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp)
struct nf_conntrack_expect *i;
write_lock_bh(&nf_conntrack_lock);
- /* choose the the oldest expectation to evict */
+ /* choose the oldest expectation to evict */
list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
if (expect_matches(i, exp) && del_timer(&i->timeout)) {
nf_ct_unlink_expect(i);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 42d2fb94eff..1f15821c8da 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -45,7 +45,6 @@
#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/security.h>
#include <linux/jhash.h>
@@ -140,6 +139,14 @@ static struct hlist_head *nl_pid_hashfn(struct nl_pid_hash *hash, u32 pid)
static void netlink_sock_destruct(struct sock *sk)
{
+ struct netlink_sock *nlk = nlk_sk(sk);
+
+ if (nlk->cb) {
+ if (nlk->cb->done)
+ nlk->cb->done(nlk->cb);
+ netlink_destroy_callback(nlk->cb);
+ }
+
skb_queue_purge(&sk->sk_receive_queue);
if (!sock_flag(sk, SOCK_DEAD)) {
@@ -148,7 +155,6 @@ static void netlink_sock_destruct(struct sock *sk)
}
BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc));
BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc));
- BUG_TRAP(!nlk_sk(sk)->cb);
BUG_TRAP(!nlk_sk(sk)->groups);
}
@@ -456,17 +462,10 @@ static int netlink_release(struct socket *sock)
sock_orphan(sk);
nlk = nlk_sk(sk);
- mutex_lock(nlk->cb_mutex);
- if (nlk->cb) {
- if (nlk->cb->done)
- nlk->cb->done(nlk->cb);
- netlink_destroy_callback(nlk->cb);
- nlk->cb = NULL;
- }
- mutex_unlock(nlk->cb_mutex);
-
- /* OK. Socket is unlinked, and, therefore,
- no new packets will arrive */
+ /*
+ * OK. Socket is unlinked, any packets that arrive now
+ * will be purged.
+ */
sock->sk = NULL;
wake_up_interruptible_all(&nlk->wait);
@@ -1245,16 +1244,14 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
siocb->scm = &scm;
}
siocb->scm->creds = *NETLINK_CREDS(skb);
+ if (flags & MSG_TRUNC)
+ copied = skb->len;
skb_free_datagram(sk, skb);
if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2)
netlink_dump(sk);
scm_recv(sock, msg, siocb->scm, flags);
-
- if (flags & MSG_TRUNC)
- copied = skb->len;
-
out:
netlink_rcv_wake(sk);
return err ? : copied;
@@ -1426,9 +1423,9 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
return -ECONNREFUSED;
}
nlk = nlk_sk(sk);
- /* A dump or destruction is in progress... */
+ /* A dump is in progress... */
mutex_lock(nlk->cb_mutex);
- if (nlk->cb || sock_flag(sk, SOCK_DEAD)) {
+ if (nlk->cb) {
mutex_unlock(nlk->cb_mutex);
netlink_destroy_callback(cb);
sock_put(sk);
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 8e6bd4e9d82..2f76e062609 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -598,7 +598,7 @@ struct net_device *nr_dev_first(void)
struct net_device *dev, *first = NULL;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
@@ -618,12 +618,13 @@ struct net_device *nr_dev_get(ax25_address *addr)
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
dev_hold(dev);
goto out;
}
}
+ dev = NULL;
out:
read_unlock(&dev_base_lock);
return dev;
diff --git a/net/rfkill/Kconfig b/net/rfkill/Kconfig
new file mode 100644
index 00000000000..8b31759ee8b
--- /dev/null
+++ b/net/rfkill/Kconfig
@@ -0,0 +1,24 @@
+#
+# RF switch subsystem configuration
+#
+menuconfig RFKILL
+ tristate "RF switch subsystem support"
+ help
+ Say Y here if you want to have control over RF switches
+ found on many WiFi, Bluetooth and IRDA cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rfkill.
+
+config RFKILL_INPUT
+ tristate "Input layer to RF switch connector"
+ depends on RFKILL && INPUT
+ help
+ Say Y here if you want kernel automatically toggle state
+ of RF switches on and off when user presses appropriate
+ button or a key on the keyboard. Without this module you
+ need a some kind of userspace application to control
+ state of the switches.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rfkill-input.
diff --git a/net/rfkill/Makefile b/net/rfkill/Makefile
new file mode 100644
index 00000000000..b38c430be05
--- /dev/null
+++ b/net/rfkill/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the RF switch subsystem.
+#
+
+obj-$(CONFIG_RFKILL) += rfkill.o
+obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
new file mode 100644
index 00000000000..e5c840c3028
--- /dev/null
+++ b/net/rfkill/rfkill-input.c
@@ -0,0 +1,174 @@
+/*
+ * Input layer to RF Kill interface connector
+ *
+ * Copyright (c) 2007 Dmitry Torokhov
+ */
+
+/*
+ * 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/module.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/init.h>
+#include <linux/rfkill.h>
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("Input layer to RF switch connector");
+MODULE_LICENSE("GPL");
+
+struct rfkill_task {
+ struct work_struct work;
+ enum rfkill_type type;
+ struct mutex mutex; /* ensures that task is serialized */
+ spinlock_t lock; /* for accessing last and desired state */
+ unsigned long last; /* last schedule */
+ enum rfkill_state desired_state; /* on/off */
+ enum rfkill_state current_state; /* on/off */
+};
+
+static void rfkill_task_handler(struct work_struct *work)
+{
+ struct rfkill_task *task = container_of(work, struct rfkill_task, work);
+ enum rfkill_state state;
+
+ mutex_lock(&task->mutex);
+
+ /*
+ * Use temp variable to fetch desired state to keep it
+ * consistent even if rfkill_schedule_toggle() runs in
+ * another thread or interrupts us.
+ */
+ state = task->desired_state;
+
+ if (state != task->current_state) {
+ rfkill_switch_all(task->type, state);
+ task->current_state = state;
+ }
+
+ mutex_unlock(&task->mutex);
+}
+
+static void rfkill_schedule_toggle(struct rfkill_task *task)
+{
+ unsigned int flags;
+
+ spin_lock_irqsave(&task->lock, flags);
+
+ if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
+ task->desired_state = !task->desired_state;
+ task->last = jiffies;
+ schedule_work(&task->work);
+ }
+
+ spin_unlock_irqrestore(&task->lock, flags);
+}
+
+#define DEFINE_RFKILL_TASK(n, t) \
+ struct rfkill_task n = { \
+ .work = __WORK_INITIALIZER(n.work, \
+ rfkill_task_handler), \
+ .type = t, \
+ .mutex = __MUTEX_INITIALIZER(n.mutex), \
+ .lock = __SPIN_LOCK_UNLOCKED(n.lock), \
+ .desired_state = RFKILL_STATE_ON, \
+ .current_state = RFKILL_STATE_ON, \
+ }
+
+static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
+static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
+
+static void rfkill_event(struct input_handle *handle, unsigned int type,
+ unsigned int code, int down)
+{
+ if (type == EV_KEY && down == 1) {
+ switch (code) {
+ case KEY_WLAN:
+ rfkill_schedule_toggle(&rfkill_wlan);
+ break;
+ case KEY_BLUETOOTH:
+ rfkill_schedule_toggle(&rfkill_bt);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
+{
+ struct input_handle *handle;
+ int error;
+
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ handle->dev = dev;
+ handle->handler = handler;
+ handle->name = "rfkill";
+
+ error = input_register_handle(handle);
+ if (error)
+ goto err_free_handle;
+
+ error = input_open_device(handle);
+ if (error)
+ goto err_unregister_handle;
+
+ return 0;
+
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_handle:
+ kfree(handle);
+ return error;
+}
+
+static void rfkill_disconnect(struct input_handle *handle)
+{
+ input_close_device(handle);
+ input_unregister_handle(handle);
+ kfree(handle);
+}
+
+static const struct input_device_id rfkill_ids[] = {
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT(EV_KEY) },
+ .keybit = { [LONG(KEY_WLAN)] = BIT(KEY_WLAN) },
+ },
+ {
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
+ .evbit = { BIT(EV_KEY) },
+ .keybit = { [LONG(KEY_BLUETOOTH)] = BIT(KEY_BLUETOOTH) },
+ },
+ { }
+};
+
+static struct input_handler rfkill_handler = {
+ .event = rfkill_event,
+ .connect = rfkill_connect,
+ .disconnect = rfkill_disconnect,
+ .name = "rfkill",
+ .id_table = rfkill_ids,
+};
+
+static int __init rfkill_handler_init(void)
+{
+ return input_register_handler(&rfkill_handler);
+}
+
+static void __exit rfkill_handler_exit(void)
+{
+ input_unregister_handler(&rfkill_handler);
+ flush_scheduled_work();
+}
+
+module_init(rfkill_handler_init);
+module_exit(rfkill_handler_exit);
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
new file mode 100644
index 00000000000..a973603e388
--- /dev/null
+++ b/net/rfkill/rfkill.c
@@ -0,0 +1,407 @@
+/*
+ * Copyright (C) 2006 Ivo van Doorn
+ * Copyright (C) 2007 Dmitry Torokhov
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/capability.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/rfkill.h>
+
+MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("RF switch support");
+MODULE_LICENSE("GPL");
+
+static LIST_HEAD(rfkill_list); /* list of registered rf switches */
+static DEFINE_MUTEX(rfkill_mutex);
+
+static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
+
+static int rfkill_toggle_radio(struct rfkill *rfkill,
+ enum rfkill_state state)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&rfkill->mutex);
+ if (retval)
+ return retval;
+
+ if (state != rfkill->state) {
+ retval = rfkill->toggle_radio(rfkill->data, state);
+ if (!retval)
+ rfkill->state = state;
+ }
+
+ mutex_unlock(&rfkill->mutex);
+ return retval;
+}
+
+/**
+ * rfkill_switch_all - Toggle state of all switches of given type
+ * @type: type of interfaces to be affeceted
+ * @state: the new state
+ *
+ * This function toggles state of all switches of given type unless
+ * a specific switch is claimed by userspace in which case it is
+ * left alone.
+ */
+
+void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
+{
+ struct rfkill *rfkill;
+
+ mutex_lock(&rfkill_mutex);
+
+ rfkill_states[type] = state;
+
+ list_for_each_entry(rfkill, &rfkill_list, node) {
+ if (!rfkill->user_claim)
+ rfkill_toggle_radio(rfkill, state);
+ }
+
+ mutex_unlock(&rfkill_mutex);
+}
+EXPORT_SYMBOL(rfkill_switch_all);
+
+static ssize_t rfkill_name_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+
+ return sprintf(buf, "%s\n", rfkill->name);
+}
+
+static ssize_t rfkill_type_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+ const char *type;
+
+ switch (rfkill->type) {
+ case RFKILL_TYPE_WLAN:
+ type = "wlan";
+ break;
+ case RFKILL_TYPE_BLUETOOTH:
+ type = "bluetooth";
+ break;
+ case RFKILL_TYPE_IRDA:
+ type = "irda";
+ break;
+ default:
+ BUG();
+ }
+
+ return sprintf(buf, "%s\n", type);
+}
+
+static ssize_t rfkill_state_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+
+ return sprintf(buf, "%d\n", rfkill->state);
+}
+
+static ssize_t rfkill_state_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+ unsigned int state = simple_strtoul(buf, NULL, 0);
+ int error;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ error = rfkill_toggle_radio(rfkill,
+ state ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
+ if (error)
+ return error;
+
+ return count;
+}
+
+static ssize_t rfkill_claim_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+
+ return sprintf(buf, "%d", rfkill->user_claim);
+}
+
+static ssize_t rfkill_claim_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+ bool claim = !!simple_strtoul(buf, NULL, 0);
+ int error;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /*
+ * Take the global lock to make sure the kernel is not in
+ * the middle of rfkill_switch_all
+ */
+ error = mutex_lock_interruptible(&rfkill_mutex);
+ if (error)
+ return error;
+
+ if (rfkill->user_claim != claim) {
+ if (!claim)
+ rfkill_toggle_radio(rfkill,
+ rfkill_states[rfkill->type]);
+ rfkill->user_claim = claim;
+ }
+
+ mutex_unlock(&rfkill_mutex);
+
+ return count;
+}
+
+static struct device_attribute rfkill_dev_attrs[] = {
+ __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
+ __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
+ __ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store),
+ __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
+ __ATTR_NULL
+};
+
+static void rfkill_release(struct device *dev)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+
+ kfree(rfkill);
+ module_put(THIS_MODULE);
+}
+
+#ifdef CONFIG_PM
+static int rfkill_suspend(struct device *dev, pm_message_t state)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+
+ if (dev->power.power_state.event != state.event) {
+ if (state.event == PM_EVENT_SUSPEND) {
+ mutex_lock(&rfkill->mutex);
+
+ if (rfkill->state == RFKILL_STATE_ON)
+ rfkill->toggle_radio(rfkill->data,
+ RFKILL_STATE_OFF);
+
+ mutex_unlock(&rfkill->mutex);
+ }
+
+ dev->power.power_state = state;
+ }
+
+ return 0;
+}
+
+static int rfkill_resume(struct device *dev)
+{
+ struct rfkill *rfkill = to_rfkill(dev);
+
+ if (dev->power.power_state.event != PM_EVENT_ON) {
+ mutex_lock(&rfkill->mutex);
+
+ if (rfkill->state == RFKILL_STATE_ON)
+ rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON);
+
+ mutex_unlock(&rfkill->mutex);
+ }
+
+ dev->power.power_state = PMSG_ON;
+ return 0;
+}
+#else
+#define rfkill_suspend NULL
+#define rfkill_resume NULL
+#endif
+
+static struct class rfkill_class = {
+ .name = "rfkill",
+ .dev_release = rfkill_release,
+ .dev_attrs = rfkill_dev_attrs,
+ .suspend = rfkill_suspend,
+ .resume = rfkill_resume,
+};
+
+static int rfkill_add_switch(struct rfkill *rfkill)
+{
+ int retval;
+
+ retval = mutex_lock_interruptible(&rfkill_mutex);
+ if (retval)
+ return retval;
+
+ retval = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]);
+ if (retval)
+ goto out;
+
+ list_add_tail(&rfkill->node, &rfkill_list);
+
+ out:
+ mutex_unlock(&rfkill_mutex);
+ return retval;
+}
+
+static void rfkill_remove_switch(struct rfkill *rfkill)
+{
+ mutex_lock(&rfkill_mutex);
+ list_del_init(&rfkill->node);
+ rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF);
+ mutex_unlock(&rfkill_mutex);
+}
+
+/**
+ * rfkill_allocate - allocate memory for rfkill structure.
+ * @parent: device that has rf switch on it
+ * @type: type of the switch (wlan, bluetooth, irda)
+ *
+ * This function should be called by the network driver when it needs
+ * rfkill structure. Once the structure is allocated the driver shoud
+ * finish its initialization by setting name, private data, enable_radio
+ * and disable_radio methods and then register it with rfkill_register().
+ * NOTE: If registration fails the structure shoudl be freed by calling
+ * rfkill_free() otherwise rfkill_unregister() should be used.
+ */
+struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type)
+{
+ struct rfkill *rfkill;
+ struct device *dev;
+
+ rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
+ if (rfkill)
+ return NULL;
+
+ mutex_init(&rfkill->mutex);
+ INIT_LIST_HEAD(&rfkill->node);
+ rfkill->type = type;
+
+ dev = &rfkill->dev;
+ dev->class = &rfkill_class;
+ dev->parent = parent;
+ device_initialize(dev);
+
+ __module_get(THIS_MODULE);
+
+ return rfkill;
+}
+EXPORT_SYMBOL(rfkill_allocate);
+
+/**
+ * rfkill_free - Mark rfkill structure for deletion
+ * @rfkill: rfkill structure to be destroyed
+ *
+ * Decrements reference count of rfkill structure so it is destoryed.
+ * Note that rfkill_free() should _not_ be called after rfkill_unregister().
+ */
+void rfkill_free(struct rfkill *rfkill)
+{
+ if (rfkill)
+ put_device(&rfkill->dev);
+}
+EXPORT_SYMBOL(rfkill_free);
+
+/**
+ * rfkill_register - Register a rfkill structure.
+ * @rfkill: rfkill structure to be registered
+ *
+ * This function should be called by the network driver when the rfkill
+ * structure needs to be registered. Immediately from registration the
+ * switch driver should be able to service calls to toggle_radio.
+ */
+int rfkill_register(struct rfkill *rfkill)
+{
+ static atomic_t rfkill_no = ATOMIC_INIT(0);
+ struct device *dev = &rfkill->dev;
+ int error;
+
+ if (!rfkill->toggle_radio)
+ return -EINVAL;
+
+ error = rfkill_add_switch(rfkill);
+ if (error)
+ return error;
+
+ snprintf(dev->bus_id, sizeof(dev->bus_id),
+ "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
+
+ error = device_add(dev);
+ if (error) {
+ rfkill_remove_switch(rfkill);
+ return error;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(rfkill_register);
+
+/**
+ * rfkill_unregister - Uegister a rfkill structure.
+ * @rfkill: rfkill structure to be unregistered
+ *
+ * This function should be called by the network driver during device
+ * teardown to destroy rfkill structure. Note that rfkill_free() should
+ * _not_ be called after rfkill_unregister().
+ */
+void rfkill_unregister(struct rfkill *rfkill)
+{
+ device_del(&rfkill->dev);
+ rfkill_remove_switch(rfkill);
+ put_device(&rfkill->dev);
+}
+EXPORT_SYMBOL(rfkill_unregister);
+
+/*
+ * Rfkill module initialization/deinitialization.
+ */
+static int __init rfkill_init(void)
+{
+ int error;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
+ rfkill_states[i] = RFKILL_STATE_ON;
+
+ error = class_register(&rfkill_class);
+ if (error) {
+ printk(KERN_ERR "rfkill: unable to register rfkill class\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void __exit rfkill_exit(void)
+{
+ class_unregister(&rfkill_class);
+}
+
+module_init(rfkill_init);
+module_exit(rfkill_exit);
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 1f9aefd95a9..929a784a86d 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -596,7 +596,7 @@ struct net_device *rose_dev_first(void)
struct net_device *dev, *first = NULL;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
first = dev;
@@ -614,12 +614,13 @@ struct net_device *rose_dev_get(rose_address *addr)
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {
dev_hold(dev);
goto out;
}
}
+ dev = NULL;
out:
read_unlock(&dev_base_lock);
return dev;
@@ -630,10 +631,11 @@ static int rose_dev_exists(rose_address *addr)
struct net_device *dev;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev != NULL; dev = dev->next) {
+ for_each_netdev(dev) {
if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
goto out;
}
+ dev = NULL;
out:
read_unlock(&dev_base_lock);
return dev != NULL;
diff --git a/net/rxrpc/Kconfig b/net/rxrpc/Kconfig
index d72380e304a..91b3d52f6f1 100644
--- a/net/rxrpc/Kconfig
+++ b/net/rxrpc/Kconfig
@@ -5,6 +5,7 @@
config AF_RXRPC
tristate "RxRPC session sockets"
depends on EXPERIMENTAL
+ select KEYS
help
Say Y or M here to include support for RxRPC session sockets (just
the transport part, not the presentation part: (un)marshalling is
@@ -29,7 +30,12 @@ config AF_RXRPC_DEBUG
config RXKAD
tristate "RxRPC Kerberos security"
- depends on AF_RXRPC && KEYS
+ depends on AF_RXRPC
+ select CRYPTO
+ select CRYPTO_MANAGER
+ select CRYPTO_BLKCIPHER
+ select CRYPTO_PCBC
+ select CRYPTO_FCRYPT
help
Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC
through the use of the key retention service.
diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c
index fc07a926df5..657ee69f213 100644
--- a/net/rxrpc/ar-ack.c
+++ b/net/rxrpc/ar-ack.c
@@ -543,6 +543,38 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call)
}
/*
+ * process the extra information that may be appended to an ACK packet
+ */
+static void rxrpc_extract_ackinfo(struct rxrpc_call *call, struct sk_buff *skb,
+ unsigned latest, int nAcks)
+{
+ struct rxrpc_ackinfo ackinfo;
+ struct rxrpc_peer *peer;
+ unsigned mtu;
+
+ if (skb_copy_bits(skb, nAcks + 3, &ackinfo, sizeof(ackinfo)) < 0) {
+ _leave(" [no ackinfo]");
+ return;
+ }
+
+ _proto("Rx ACK %%%u Info { rx=%u max=%u rwin=%u jm=%u }",
+ latest,
+ ntohl(ackinfo.rxMTU), ntohl(ackinfo.maxMTU),
+ ntohl(ackinfo.rwind), ntohl(ackinfo.jumbo_max));
+
+ mtu = min(ntohl(ackinfo.rxMTU), ntohl(ackinfo.maxMTU));
+
+ peer = call->conn->trans->peer;
+ if (mtu < peer->maxdata) {
+ spin_lock_bh(&peer->lock);
+ peer->maxdata = mtu;
+ peer->mtu = mtu + peer->hdrsize;
+ spin_unlock_bh(&peer->lock);
+ _net("Net MTU %u (maxdata %u)", peer->mtu, peer->maxdata);
+ }
+}
+
+/*
* process packets in the reception queue
*/
static int rxrpc_process_rx_queue(struct rxrpc_call *call,
@@ -606,6 +638,8 @@ process_further:
rxrpc_acks[ack.reason],
ack.nAcks);
+ rxrpc_extract_ackinfo(call, skb, latest, ack.nAcks);
+
if (ack.reason == RXRPC_ACK_PING) {
_proto("Rx ACK %%%u PING Request", latest);
rxrpc_propose_ACK(call, RXRPC_ACK_PING_RESPONSE,
@@ -801,9 +835,9 @@ void rxrpc_process_call(struct work_struct *work)
struct msghdr msg;
struct kvec iov[5];
unsigned long bits;
- __be32 data;
+ __be32 data, pad;
size_t len;
- int genbit, loop, nbit, ioc, ret;
+ int genbit, loop, nbit, ioc, ret, mtu;
u32 abort_code = RX_PROTOCOL_ERROR;
u8 *acks = NULL;
@@ -899,9 +933,30 @@ void rxrpc_process_call(struct work_struct *work)
}
if (test_bit(RXRPC_CALL_ACK_FINAL, &call->events)) {
- hdr.type = RXRPC_PACKET_TYPE_ACKALL;
genbit = RXRPC_CALL_ACK_FINAL;
- goto send_message;
+
+ ack.bufferSpace = htons(8);
+ ack.maxSkew = 0;
+ ack.serial = 0;
+ ack.reason = RXRPC_ACK_IDLE;
+ ack.nAcks = 0;
+ call->ackr_reason = 0;
+
+ spin_lock_bh(&call->lock);
+ ack.serial = call->ackr_serial;
+ ack.previousPacket = call->ackr_prev_seq;
+ ack.firstPacket = htonl(call->rx_data_eaten + 1);
+ spin_unlock_bh(&call->lock);
+
+ pad = 0;
+
+ iov[1].iov_base = &ack;
+ iov[1].iov_len = sizeof(ack);
+ iov[2].iov_base = &pad;
+ iov[2].iov_len = 3;
+ iov[3].iov_base = &ackinfo;
+ iov[3].iov_len = sizeof(ackinfo);
+ goto send_ACK;
}
if (call->events & ((1 << RXRPC_CALL_RCVD_BUSY) |
@@ -971,8 +1026,6 @@ void rxrpc_process_call(struct work_struct *work)
/* consider sending an ordinary ACK */
if (test_bit(RXRPC_CALL_ACK, &call->events)) {
- __be32 pad;
-
_debug("send ACK: window: %d - %d { %lx }",
call->rx_data_eaten, call->ackr_win_top,
call->ackr_window[0]);
@@ -997,12 +1050,6 @@ void rxrpc_process_call(struct work_struct *work)
ack.serial = 0;
ack.reason = 0;
- ackinfo.rxMTU = htonl(5692);
-// ackinfo.rxMTU = htonl(call->conn->trans->peer->maxdata);
- ackinfo.maxMTU = htonl(call->conn->trans->peer->maxdata);
- ackinfo.rwind = htonl(32);
- ackinfo.jumbo_max = htonl(4);
-
spin_lock_bh(&call->lock);
ack.reason = call->ackr_reason;
ack.serial = call->ackr_serial;
@@ -1116,6 +1163,15 @@ send_ACK_with_skew:
ack.maxSkew = htons(atomic_read(&call->conn->hi_serial) -
ntohl(ack.serial));
send_ACK:
+ mtu = call->conn->trans->peer->if_mtu;
+ mtu -= call->conn->trans->peer->hdrsize;
+ ackinfo.maxMTU = htonl(mtu);
+ ackinfo.rwind = htonl(32);
+
+ /* permit the peer to send us jumbo packets if it wants to */
+ ackinfo.rxMTU = htonl(5692);
+ ackinfo.jumbo_max = htonl(4);
+
hdr.serial = htonl(atomic_inc_return(&call->conn->serial));
_proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }",
ntohl(hdr.serial),
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c
index 2c27df1ffa1..6cb3e8890e7 100644
--- a/net/rxrpc/ar-error.c
+++ b/net/rxrpc/ar-error.c
@@ -100,8 +100,10 @@ void rxrpc_UDP_error_report(struct sock *sk)
}
if (mtu < peer->mtu) {
+ spin_lock_bh(&peer->lock);
peer->mtu = mtu;
peer->maxdata = peer->mtu - peer->hdrsize;
+ spin_unlock_bh(&peer->lock);
_net("Net MTU %u (maxdata %u)",
peer->mtu, peer->maxdata);
}
diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c
index 5cdde4a48ed..591c4422205 100644
--- a/net/rxrpc/ar-output.c
+++ b/net/rxrpc/ar-output.c
@@ -582,7 +582,7 @@ static int rxrpc_send_data(struct kiocb *iocb,
max &= ~(call->conn->size_align - 1UL);
chunk = max;
- if (chunk > len)
+ if (chunk > len && !more)
chunk = len;
space = chunk + call->conn->size_align;
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
index d399de4a7fe..ce08b78647c 100644
--- a/net/rxrpc/ar-peer.c
+++ b/net/rxrpc/ar-peer.c
@@ -19,6 +19,7 @@
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <net/ip.h>
+#include <net/route.h>
#include "ar-internal.h"
static LIST_HEAD(rxrpc_peers);
@@ -28,6 +29,47 @@ static DECLARE_WAIT_QUEUE_HEAD(rxrpc_peer_wq);
static void rxrpc_destroy_peer(struct work_struct *work);
/*
+ * assess the MTU size for the network interface through which this peer is
+ * reached
+ */
+static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
+{
+ struct rtable *rt;
+ struct flowi fl;
+ int ret;
+
+ peer->if_mtu = 1500;
+
+ memset(&fl, 0, sizeof(fl));
+
+ switch (peer->srx.transport.family) {
+ case AF_INET:
+ fl.oif = 0;
+ fl.proto = IPPROTO_UDP,
+ fl.nl_u.ip4_u.saddr = 0;
+ fl.nl_u.ip4_u.daddr = peer->srx.transport.sin.sin_addr.s_addr;
+ fl.nl_u.ip4_u.tos = 0;
+ /* assume AFS.CM talking to AFS.FS */
+ fl.uli_u.ports.sport = htons(7001);
+ fl.uli_u.ports.dport = htons(7000);
+ break;
+ default:
+ BUG();
+ }
+
+ ret = ip_route_output_key(&rt, &fl);
+ if (ret < 0) {
+ kleave(" [route err %d]", ret);
+ return;
+ }
+
+ peer->if_mtu = dst_mtu(&rt->u.dst);
+ dst_release(&rt->u.dst);
+
+ kleave(" [if_mtu %u]", peer->if_mtu);
+}
+
+/*
* allocate a new peer
*/
static struct rxrpc_peer *rxrpc_alloc_peer(struct sockaddr_rxrpc *srx,
@@ -47,7 +89,8 @@ static struct rxrpc_peer *rxrpc_alloc_peer(struct sockaddr_rxrpc *srx,
peer->debug_id = atomic_inc_return(&rxrpc_debug_id);
memcpy(&peer->srx, srx, sizeof(*srx));
- peer->mtu = peer->if_mtu = 65535;
+ rxrpc_assess_MTU_size(peer);
+ peer->mtu = peer->if_mtu;
if (srx->transport.family == AF_INET) {
peer->hdrsize = sizeof(struct iphdr);
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 1eaf529efac..5ec705144e1 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -18,6 +18,7 @@
#include <linux/ctype.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
+#define rxrpc_debug rxkad_debug
#include "ar-internal.h"
#define RXKAD_VERSION 2
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 8699e7006d8..bec600af03c 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -894,9 +894,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
s_idx = cb->args[0];
s_q_idx = q_idx = cb->args[1];
read_lock(&dev_base_lock);
- for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+ idx = 0;
+ for_each_netdev(dev) {
if (idx < s_idx)
- continue;
+ goto cont;
if (idx > s_idx)
s_q_idx = 0;
q_idx = 0;
@@ -910,6 +911,8 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
goto done;
q_idx++;
}
+cont:
+ idx++;
}
done:
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index db73ef97485..df94e3cdfba 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -1103,6 +1103,13 @@ void sctp_assoc_update(struct sctp_association *asoc,
asoc->ssnmap = new->ssnmap;
new->ssnmap = NULL;
}
+
+ if (!asoc->assoc_id) {
+ /* get a new association id since we don't have one
+ * yet.
+ */
+ sctp_assoc_set_id(asoc, GFP_ATOMIC);
+ }
}
}
@@ -1375,3 +1382,25 @@ out:
sctp_read_unlock(&asoc->base.addr_lock);
return found;
}
+
+/* Set an association id for a given association */
+int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
+{
+ int assoc_id;
+ int error = 0;
+retry:
+ if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+ return -ENOMEM;
+
+ spin_lock_bh(&sctp_assocs_id_lock);
+ error = idr_get_new_above(&sctp_assocs_id, (void *)asoc,
+ 1, &assoc_id);
+ spin_unlock_bh(&sctp_assocs_id_lock);
+ if (error == -EAGAIN)
+ goto retry;
+ else if (error)
+ return error;
+
+ asoc->assoc_id = (sctp_assoc_t) assoc_id;
+ return error;
+}
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 83ef411772f..77fb7b06a9c 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -3,7 +3,7 @@
*
* This file is part of the SCTP kernel reference Implementation
*
- * This file contains the code relating the the chunk abstraction.
+ * This file contains the code relating the chunk abstraction.
*
* The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index ca527a27dd0..84cd53635fe 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -992,45 +992,52 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.af = &sctp_ipv6_specific,
};
-/* Initialize IPv6 support and register with inet6 stack. */
+/* Initialize IPv6 support and register with socket layer. */
int sctp_v6_init(void)
{
- int rc = proto_register(&sctpv6_prot, 1);
+ int rc;
+ /* Register the SCTP specific PF_INET6 functions. */
+ sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
+
+ /* Register the SCTP specific AF_INET6 functions. */
+ sctp_register_af(&sctp_ipv6_specific);
+
+ rc = proto_register(&sctpv6_prot, 1);
if (rc)
- goto out;
- /* Register inet6 protocol. */
- rc = -EAGAIN;
- if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
- goto out_unregister_sctp_proto;
+ return rc;
/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_seqpacket_protosw);
inet6_register_protosw(&sctpv6_stream_protosw);
- /* Register the SCTP specific PF_INET6 functions. */
- sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
-
- /* Register the SCTP specific AF_INET6 functions. */
- sctp_register_af(&sctp_ipv6_specific);
+ return 0;
+}
+/* Register with inet6 layer. */
+int sctp_v6_add_protocol(void)
+{
/* Register notifier for inet6 address additions/deletions. */
register_inet6addr_notifier(&sctp_inet6addr_notifier);
- rc = 0;
-out:
- return rc;
-out_unregister_sctp_proto:
- proto_unregister(&sctpv6_prot);
- goto out;
+
+ if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
+ return -EAGAIN;
+
+ return 0;
}
/* IPv6 specific exit support. */
void sctp_v6_exit(void)
{
- list_del(&sctp_ipv6_specific.list);
- inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
inet6_unregister_protosw(&sctpv6_stream_protosw);
- unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
proto_unregister(&sctpv6_prot);
+ list_del(&sctp_ipv6_specific.list);
+}
+
+/* Unregister with inet6 layer. */
+void sctp_v6_del_protocol(void)
+{
+ inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
+ unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index c361deb6cea..34bab36637a 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -170,7 +170,7 @@ static void sctp_get_local_addr_list(void)
struct sctp_af *af;
read_lock(&dev_base_lock);
- for (dev = dev_base; dev; dev = dev->next) {
+ for_each_netdev(dev) {
__list_for_each(pos, &sctp_address_families) {
af = list_entry(pos, struct sctp_af, list);
af->copy_addrlist(&sctp_local_addr_list, dev);
@@ -975,28 +975,14 @@ SCTP_STATIC __init int sctp_init(void)
if (!sctp_sanity_check())
goto out;
- status = proto_register(&sctp_prot, 1);
- if (status)
- goto out;
-
- /* Add SCTP to inet_protos hash table. */
- status = -EAGAIN;
- if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0)
- goto err_add_protocol;
-
- /* Add SCTP(TCP and UDP style) to inetsw linked list. */
- inet_register_protosw(&sctp_seqpacket_protosw);
- inet_register_protosw(&sctp_stream_protosw);
-
- /* Allocate a cache pools. */
+ /* Allocate bind_bucket and chunk caches. */
status = -ENOBUFS;
sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
sizeof(struct sctp_bind_bucket),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
-
if (!sctp_bucket_cachep)
- goto err_bucket_cachep;
+ goto out;
sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
sizeof(struct sctp_chunk),
@@ -1153,6 +1139,14 @@ SCTP_STATIC __init int sctp_init(void)
INIT_LIST_HEAD(&sctp_address_families);
sctp_register_af(&sctp_ipv4_specific);
+ status = proto_register(&sctp_prot, 1);
+ if (status)
+ goto err_proto_register;
+
+ /* Register SCTP(UDP and TCP style) with socket layer. */
+ inet_register_protosw(&sctp_seqpacket_protosw);
+ inet_register_protosw(&sctp_stream_protosw);
+
status = sctp_v6_init();
if (status)
goto err_v6_init;
@@ -1166,19 +1160,39 @@ SCTP_STATIC __init int sctp_init(void)
/* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list);
-
sctp_get_local_addr_list();
/* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier(&sctp_inetaddr_notifier);
+ /* Register SCTP with inet layer. */
+ if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) {
+ status = -EAGAIN;
+ goto err_add_protocol;
+ }
+
+ /* Register SCTP with inet6 layer. */
+ status = sctp_v6_add_protocol();
+ if (status)
+ goto err_v6_add_protocol;
+
__unsafe(THIS_MODULE);
status = 0;
out:
return status;
+err_v6_add_protocol:
+ inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
+ unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+err_add_protocol:
+ sctp_free_local_addr_list();
+ sock_release(sctp_ctl_socket);
err_ctl_sock_init:
sctp_v6_exit();
err_v6_init:
+ inet_unregister_protosw(&sctp_stream_protosw);
+ inet_unregister_protosw(&sctp_seqpacket_protosw);
+ proto_unregister(&sctp_prot);
+err_proto_register:
sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);
free_pages((unsigned long)sctp_port_hashtable,
@@ -1192,19 +1206,13 @@ err_ehash_alloc:
sizeof(struct sctp_hashbucket)));
err_ahash_alloc:
sctp_dbg_objcnt_exit();
-err_init_proc:
sctp_proc_exit();
+err_init_proc:
cleanup_sctp_mibs();
err_init_mibs:
kmem_cache_destroy(sctp_chunk_cachep);
err_chunk_cachep:
kmem_cache_destroy(sctp_bucket_cachep);
-err_bucket_cachep:
- inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
- inet_unregister_protosw(&sctp_seqpacket_protosw);
- inet_unregister_protosw(&sctp_stream_protosw);
-err_add_protocol:
- proto_unregister(&sctp_prot);
goto out;
}
@@ -1215,8 +1223,9 @@ SCTP_STATIC __exit void sctp_exit(void)
* up all the remaining associations and all that memory.
*/
- /* Unregister notifier for inet address additions/deletions. */
- unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+ /* Unregister with inet6/inet layers. */
+ sctp_v6_del_protocol();
+ inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
/* Free the local address list. */
sctp_free_local_addr_list();
@@ -1224,7 +1233,16 @@ SCTP_STATIC __exit void sctp_exit(void)
/* Free the control endpoint. */
sock_release(sctp_ctl_socket);
+ /* Cleanup v6 initializations. */
sctp_v6_exit();
+
+ /* Unregister with socket layer. */
+ inet_unregister_protosw(&sctp_stream_protosw);
+ inet_unregister_protosw(&sctp_seqpacket_protosw);
+
+ /* Unregister notifier for inet address additions/deletions. */
+ unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
+
sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);
@@ -1236,16 +1254,13 @@ SCTP_STATIC __exit void sctp_exit(void)
get_order(sctp_port_hashsize *
sizeof(struct sctp_bind_hashbucket)));
- kmem_cache_destroy(sctp_chunk_cachep);
- kmem_cache_destroy(sctp_bucket_cachep);
-
sctp_dbg_objcnt_exit();
sctp_proc_exit();
cleanup_sctp_mibs();
- inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
- inet_unregister_protosw(&sctp_seqpacket_protosw);
- inet_unregister_protosw(&sctp_stream_protosw);
+ kmem_cache_destroy(sctp_chunk_cachep);
+ kmem_cache_destroy(sctp_bucket_cachep);
+
proto_unregister(&sctp_prot);
}
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index be783a3761c..8d18f570c2e 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1939,7 +1939,6 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
* association.
*/
if (!asoc->temp) {
- int assoc_id;
int error;
asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
@@ -1947,19 +1946,9 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
if (!asoc->ssnmap)
goto clean_up;
- retry:
- if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+ error = sctp_assoc_set_id(asoc, gfp);
+ if (error)
goto clean_up;
- spin_lock_bh(&sctp_assocs_id_lock);
- error = idr_get_new_above(&sctp_assocs_id, (void *)asoc, 1,
- &assoc_id);
- spin_unlock_bh(&sctp_assocs_id_lock);
- if (error == -EAGAIN)
- goto retry;
- else if (error)
- goto clean_up;
-
- asoc->assoc_id = (sctp_assoc_t) assoc_id;
}
/* ADDIP Section 4.1 ASCONF Chunk Procedures
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index b37a7adeb15..d9fad4f6ffc 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -862,6 +862,33 @@ static void sctp_cmd_set_sk_err(struct sctp_association *asoc, int error)
sk->sk_err = error;
}
+/* Helper function to generate an association change event */
+static void sctp_cmd_assoc_change(sctp_cmd_seq_t *commands,
+ struct sctp_association *asoc,
+ u8 state)
+{
+ struct sctp_ulpevent *ev;
+
+ ev = sctp_ulpevent_make_assoc_change(asoc, 0, state, 0,
+ asoc->c.sinit_num_ostreams,
+ asoc->c.sinit_max_instreams,
+ NULL, GFP_ATOMIC);
+ if (ev)
+ sctp_ulpq_tail_event(&asoc->ulpq, ev);
+}
+
+/* Helper function to generate an adaptation indication event */
+static void sctp_cmd_adaptation_ind(sctp_cmd_seq_t *commands,
+ struct sctp_association *asoc)
+{
+ struct sctp_ulpevent *ev;
+
+ ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
+
+ if (ev)
+ sctp_ulpq_tail_event(&asoc->ulpq, ev);
+}
+
/* These three macros allow us to pull the debugging code out of the
* main flow of sctp_do_sm() to keep attention focused on the real
* functionality there.
@@ -1485,6 +1512,14 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
case SCTP_CMD_SET_SK_ERR:
sctp_cmd_set_sk_err(asoc, cmd->obj.error);
break;
+ case SCTP_CMD_ASSOC_CHANGE:
+ sctp_cmd_assoc_change(commands, asoc,
+ cmd->obj.u8);
+ break;
+ case SCTP_CMD_ADAPTATION_IND:
+ sctp_cmd_adaptation_ind(commands, asoc);
+ break;
+
default:
printk(KERN_WARNING "Impossible command: %u, %p\n",
cmd->verb, cmd->obj.ptr);
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 9e28a5d5120..f02ce3dddb7 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1656,7 +1656,6 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
struct sctp_association *new_asoc)
{
sctp_init_chunk_t *peer_init;
- struct sctp_ulpevent *ev;
struct sctp_chunk *repl;
/* new_asoc is a brand-new association, so these are not yet
@@ -1687,34 +1686,28 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
* D) IMPLEMENTATION NOTE: An implementation may choose to
* send the Communication Up notification to the SCTP user
* upon reception of a valid COOKIE ECHO chunk.
+ *
+ * Sadly, this needs to be implemented as a side-effect, because
+ * we are not guaranteed to have set the association id of the real
+ * association and so these notifications need to be delayed until
+ * the association id is allocated.
*/
- ev = sctp_ulpevent_make_assoc_change(asoc, 0, SCTP_COMM_UP, 0,
- new_asoc->c.sinit_num_ostreams,
- new_asoc->c.sinit_max_instreams,
- NULL, GFP_ATOMIC);
- if (!ev)
- goto nomem_ev;
- sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
+ sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_CHANGE, SCTP_U8(SCTP_COMM_UP));
/* Sockets API Draft Section 5.3.1.6
* When a peer sends a Adaptation Layer Indication parameter , SCTP
* delivers this notification to inform the application that of the
* peers requested adaptation layer.
+ *
+ * This also needs to be done as a side effect for the same reason as
+ * above.
*/
- if (asoc->peer.adaptation_ind) {
- ev = sctp_ulpevent_make_adaptation_indication(asoc, GFP_ATOMIC);
- if (!ev)
- goto nomem_ev;
-
- sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
- SCTP_ULPEVENT(ev));
- }
+ if (asoc->peer.adaptation_ind)
+ sctp_add_cmd_sf(commands, SCTP_CMD_ADAPTATION_IND, SCTP_NULL());
return SCTP_DISPOSITION_CONSUME;
-nomem_ev:
- sctp_chunk_free(repl);
nomem:
return SCTP_DISPOSITION_NOMEM;
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 11938fb2039..83a76ba9d7b 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -972,6 +972,7 @@ static int __sctp_connect(struct sock* sk,
int walk_size = 0;
union sctp_addr *sa_addr;
void *addr_buf;
+ unsigned short port;
sp = sctp_sk(sk);
ep = sp->ep;
@@ -992,6 +993,7 @@ static int __sctp_connect(struct sock* sk,
while (walk_size < addrs_size) {
sa_addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(sa_addr->sa.sa_family);
+ port = ntohs(sa_addr->v4.sin_port);
/* If the address family is not supported or if this address
* causes the address buffer to overflow return EINVAL.
@@ -1005,6 +1007,12 @@ static int __sctp_connect(struct sock* sk,
if (err)
goto out_free;
+ /* Make sure the destination port is correctly set
+ * in all addresses.
+ */
+ if (asoc && asoc->peer.port && asoc->peer.port != port)
+ goto out_free;
+
memcpy(&to, sa_addr, af->sockaddr_len);
/* Check if there already is a matching association on the
@@ -2578,7 +2586,7 @@ static int sctp_setsockopt_rtoinfo(struct sock *sk, char __user *optval, int opt
*
* 7.1.2 SCTP_ASSOCINFO
*
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
* of the association.
* Returns an error if the new association retransmission value is
* greater than the sum of the retransmission value of the peer.
@@ -3987,7 +3995,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
- if(space_left < addrlen)
+ if (space_left < addrlen)
return -ENOMEM;
if (copy_to_user(to, &temp, addrlen))
return -EFAULT;
@@ -4076,8 +4084,9 @@ done:
/* Helper function that copies local addresses to user and returns the number
* of addresses copied.
*/
-static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
- void __user *to)
+static int sctp_copy_laddrs_old(struct sock *sk, __u16 port,
+ int max_addrs, void *to,
+ int *bytes_copied)
{
struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr;
@@ -4094,10 +4103,10 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- if (copy_to_user(to, &temp, addrlen))
- return -EFAULT;
+ memcpy(to, &temp, addrlen);
to += addrlen;
+ *bytes_copied += addrlen;
cnt ++;
if (cnt >= max_addrs) break;
}
@@ -4105,8 +4114,8 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
return cnt;
}
-static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
- void __user **to, size_t space_left)
+static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
+ size_t space_left, int *bytes_copied)
{
struct list_head *pos, *next;
struct sctp_sockaddr_entry *addr;
@@ -4123,14 +4132,14 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- if(space_left<addrlen)
+ if (space_left < addrlen)
return -ENOMEM;
- if (copy_to_user(*to, &temp, addrlen))
- return -EFAULT;
+ memcpy(to, &temp, addrlen);
- *to += addrlen;
+ to += addrlen;
cnt ++;
space_left -= addrlen;
+ bytes_copied += addrlen;
}
return cnt;
@@ -4154,6 +4163,8 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
int addrlen;
rwlock_t *addr_lock;
int err = 0;
+ void *addrs;
+ int bytes_copied = 0;
if (len != sizeof(struct sctp_getaddrs_old))
return -EINVAL;
@@ -4181,6 +4192,15 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
to = getaddrs.addrs;
+ /* Allocate space for a local instance of packed array to hold all
+ * the data. We store addresses here first and then put write them
+ * to the user in one shot.
+ */
+ addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num,
+ GFP_KERNEL);
+ if (!addrs)
+ return -ENOMEM;
+
sctp_read_lock(addr_lock);
/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
@@ -4190,13 +4210,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) {
- cnt = sctp_copy_laddrs_to_user_old(sk, bp->port,
- getaddrs.addr_num,
- to);
- if (cnt < 0) {
- err = cnt;
- goto unlock;
- }
+ cnt = sctp_copy_laddrs_old(sk, bp->port,
+ getaddrs.addr_num,
+ addrs, &bytes_copied);
goto copy_getaddrs;
}
}
@@ -4206,22 +4222,29 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len,
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- if (copy_to_user(to, &temp, addrlen)) {
- err = -EFAULT;
- goto unlock;
- }
+ memcpy(addrs, &temp, addrlen);
to += addrlen;
+ bytes_copied += addrlen;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
}
copy_getaddrs:
+ sctp_read_unlock(addr_lock);
+
+ /* copy the entire address list into the user provided space */
+ if (copy_to_user(to, addrs, bytes_copied)) {
+ err = -EFAULT;
+ goto error;
+ }
+
+ /* copy the leading structure back to user */
getaddrs.addr_num = cnt;
if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old)))
err = -EFAULT;
-unlock:
- sctp_read_unlock(addr_lock);
+error:
+ kfree(addrs);
return err;
}
@@ -4241,7 +4264,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
rwlock_t *addr_lock;
int err = 0;
size_t space_left;
- int bytes_copied;
+ int bytes_copied = 0;
+ void *addrs;
if (len <= sizeof(struct sctp_getaddrs))
return -EINVAL;
@@ -4269,6 +4293,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
to = optval + offsetof(struct sctp_getaddrs,addrs);
space_left = len - sizeof(struct sctp_getaddrs) -
offsetof(struct sctp_getaddrs,addrs);
+ addrs = kmalloc(space_left, GFP_KERNEL);
+ if (!addrs)
+ return -ENOMEM;
sctp_read_lock(addr_lock);
@@ -4279,11 +4306,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) {
- cnt = sctp_copy_laddrs_to_user(sk, bp->port,
- &to, space_left);
+ cnt = sctp_copy_laddrs(sk, bp->port, addrs,
+ space_left, &bytes_copied);
if (cnt < 0) {
err = cnt;
- goto unlock;
+ goto error;
}
goto copy_getaddrs;
}
@@ -4294,26 +4321,31 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- if(space_left < addrlen)
- return -ENOMEM; /*fixme: right error?*/
- if (copy_to_user(to, &temp, addrlen)) {
- err = -EFAULT;
- goto unlock;
+ if (space_left < addrlen) {
+ err = -ENOMEM; /*fixme: right error?*/
+ goto error;
}
+ memcpy(addrs, &temp, addrlen);
to += addrlen;
+ bytes_copied += addrlen;
cnt ++;
space_left -= addrlen;
}
copy_getaddrs:
+ sctp_read_unlock(addr_lock);
+
+ if (copy_to_user(to, addrs, bytes_copied)) {
+ err = -EFAULT;
+ goto error;
+ }
if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num))
return -EFAULT;
- bytes_copied = ((char __user *)to) - optval;
if (put_user(bytes_copied, optlen))
return -EFAULT;
-unlock:
- sctp_read_unlock(addr_lock);
+error:
+ kfree(addrs);
return err;
}
@@ -4515,7 +4547,7 @@ static int sctp_getsockopt_rtoinfo(struct sock *sk, int len,
*
* 7.1.2 SCTP_ASSOCINFO
*
- * This option is used to tune the the maximum retransmission attempts
+ * This option is used to tune the maximum retransmission attempts
* of the association.
* Returns an error if the new association retransmission value is
* greater than the sum of the retransmission value of the peer.
@@ -4988,7 +5020,8 @@ pp_found:
struct hlist_node *node;
SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n");
- if (pp->fastreuse && sk->sk_reuse)
+ if (pp->fastreuse && sk->sk_reuse &&
+ sk->sk_state != SCTP_SS_LISTENING)
goto success;
/* Run through the list of sockets bound to the port
@@ -5005,7 +5038,8 @@ pp_found:
struct sctp_endpoint *ep2;
ep2 = sctp_sk(sk2)->ep;
- if (reuse && sk2->sk_reuse)
+ if (reuse && sk2->sk_reuse &&
+ sk2->sk_state != SCTP_SS_LISTENING)
continue;
if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
@@ -5026,9 +5060,13 @@ pp_not_found:
* if sk->sk_reuse is too (that is, if the caller requested
* SO_REUSEADDR on this socket -sk-).
*/
- if (hlist_empty(&pp->owner))
- pp->fastreuse = sk->sk_reuse ? 1 : 0;
- else if (pp->fastreuse && !sk->sk_reuse)
+ if (hlist_empty(&pp->owner)) {
+ if (sk->sk_reuse && sk->sk_state != SCTP_SS_LISTENING)
+ pp->fastreuse = 1;
+ else
+ pp->fastreuse = 0;
+ } else if (pp->fastreuse &&
+ (!sk->sk_reuse || sk->sk_state == SCTP_SS_LISTENING))
pp->fastreuse = 0;
/* We are set, so fill up all the data in the hash table
@@ -5036,8 +5074,8 @@ pp_not_found:
* sockets FIXME: Blurry, NPI (ipg).
*/
success:
- inet_sk(sk)->num = snum;
if (!sctp_sk(sk)->bind_hash) {
+ inet_sk(sk)->num = snum;
sk_add_bind_node(sk, &pp->owner);
sctp_sk(sk)->bind_hash = pp;
}
@@ -5110,12 +5148,16 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
* This is not currently spelled out in the SCTP sockets
* extensions draft, but follows the practice as seen in TCP
* sockets.
+ *
+ * Additionally, turn off fastreuse flag since we are not listening
*/
+ sk->sk_state = SCTP_SS_LISTENING;
if (!ep->base.bind_addr.port) {
if (sctp_autobind(sk))
return -EAGAIN;
- }
- sk->sk_state = SCTP_SS_LISTENING;
+ } else
+ sctp_sk(sk)->bind_hash->fastreuse = 0;
+
sctp_hash_endpoint(ep);
return 0;
}
@@ -5153,11 +5195,13 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
* extensions draft, but follows the practice as seen in TCP
* sockets.
*/
+ sk->sk_state = SCTP_SS_LISTENING;
if (!ep->base.bind_addr.port) {
if (sctp_autobind(sk))
return -EAGAIN;
- }
- sk->sk_state = SCTP_SS_LISTENING;
+ } else
+ sctp_sk(sk)->bind_hash->fastreuse = 0;
+
sk->sk_max_ack_backlog = backlog;
sctp_hash_endpoint(ep);
return 0;
diff --git a/net/socket.c b/net/socket.c
index 1ad62c08377..98a8f67abbf 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -261,8 +261,7 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct socket_alloc *ei = (struct socket_alloc *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR))
- == SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR)
inode_init_once(&ei->vfs_inode);
}
@@ -314,8 +313,19 @@ static int sockfs_delete_dentry(struct dentry *dentry)
dentry->d_flags |= DCACHE_UNHASHED;
return 0;
}
+
+/*
+ * sockfs_dname() is called from d_path().
+ */
+static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
+{
+ return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
+ dentry->d_inode->i_ino);
+}
+
static struct dentry_operations sockfs_dentry_operations = {
.d_delete = sockfs_delete_dentry,
+ .d_dname = sockfs_dname,
};
/*
@@ -355,14 +365,9 @@ static int sock_alloc_fd(struct file **filep)
static int sock_attach_fd(struct socket *sock, struct file *file)
{
- struct qstr this;
- char name[32];
-
- this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino);
- this.name = name;
- this.hash = 0;
+ struct qstr name = { .name = "" };
- file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this);
+ file->f_path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
if (unlikely(!file->f_path.dentry))
return -ENOMEM;
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index cdcab9ca4c6..8ebfc4db7f5 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -9,7 +9,7 @@ obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
auth.o auth_null.o auth_unix.o \
svc.o svcsock.o svcauth.o svcauth_unix.o \
- pmap_clnt.o timer.o xdr.o \
+ rpcb_clnt.o timer.o xdr.o \
sunrpc_syms.o cache.o rpc_pipe.o
sunrpc-$(CONFIG_PROC_FS) += stats.o
sunrpc-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/sunrpc/auth_gss/gss_spkm3_seal.c b/net/sunrpc/auth_gss/gss_spkm3_seal.c
index 104cbf4f769..d158635de6c 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_seal.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_seal.c
@@ -123,9 +123,6 @@ spkm3_make_token(struct spkm3_ctx *ctx,
return GSS_S_COMPLETE;
out_err:
- if (md5cksum.data)
- kfree(md5cksum.data);
-
token->data = NULL;
token->len = 0;
return GSS_S_FAILURE;
@@ -152,7 +149,7 @@ make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
switch (cksumtype) {
case CKSUMTYPE_HMAC_MD5:
- cksumname = "md5";
+ cksumname = "hmac(md5)";
break;
default:
dprintk("RPC: spkm3_make_checksum:"
@@ -172,8 +169,12 @@ make_spkm3_checksum(s32 cksumtype, struct xdr_netobj *key, char *header,
if (err)
goto out;
+ err = crypto_hash_init(&desc);
+ if (err)
+ goto out;
+
sg_set_buf(sg, header, hdrlen);
- crypto_hash_update(&desc, sg, 1);
+ crypto_hash_update(&desc, sg, sg->length);
xdr_process_buf(body, body_offset, body->len - body_offset,
spkm3_checksummer, &desc);
@@ -184,5 +185,3 @@ out:
return err ? GSS_S_FAILURE : 0;
}
-
-EXPORT_SYMBOL(make_spkm3_checksum);
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index db298b501c8..099a983797d 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -924,6 +924,7 @@ static inline int
gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
{
struct rsc *rsci;
+ int rc;
if (rsip->major_status != GSS_S_COMPLETE)
return gss_write_null_verf(rqstp);
@@ -932,7 +933,9 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
rsip->major_status = GSS_S_NO_CONTEXT;
return gss_write_null_verf(rqstp);
}
- return gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+ rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
+ cache_put(&rsci->h, &rsc_cache);
+ return rc;
}
/*
@@ -1089,6 +1092,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
}
goto complete;
case RPC_GSS_PROC_DESTROY:
+ if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
+ goto auth_err;
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
@@ -1196,13 +1201,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
integ_len))
BUG();
- if (resbuf->page_len == 0
- && resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE
- < PAGE_SIZE) {
- BUG_ON(resbuf->tail[0].iov_len);
- /* Use head for everything */
- resv = &resbuf->head[0];
- } else if (resbuf->tail[0].iov_base == NULL) {
+ if (resbuf->tail[0].iov_base == NULL) {
if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
goto out_err;
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 396cdbe249d..d8fbee40a19 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -36,8 +36,6 @@
#include <linux/sunrpc/metrics.h>
-#define RPC_SLACK_SPACE (1024) /* total overkill */
-
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_CALL
#endif
@@ -747,21 +745,38 @@ call_reserveresult(struct rpc_task *task)
static void
call_allocate(struct rpc_task *task)
{
+ unsigned int slack = task->tk_auth->au_cslack;
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = task->tk_xprt;
- unsigned int bufsiz;
+ struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
dprint_status(task);
+ task->tk_status = 0;
task->tk_action = call_bind;
+
if (req->rq_buffer)
return;
- /* FIXME: compute buffer requirements more exactly using
- * auth->au_wslack */
- bufsiz = task->tk_msg.rpc_proc->p_bufsiz + RPC_SLACK_SPACE;
+ if (proc->p_proc != 0) {
+ BUG_ON(proc->p_arglen == 0);
+ if (proc->p_decode != NULL)
+ BUG_ON(proc->p_replen == 0);
+ }
- if (xprt->ops->buf_alloc(task, bufsiz << 1) != NULL)
+ /*
+ * Calculate the size (in quads) of the RPC call
+ * and reply headers, and convert both values
+ * to byte sizes.
+ */
+ req->rq_callsize = RPC_CALLHDRSIZE + (slack << 1) + proc->p_arglen;
+ req->rq_callsize <<= 2;
+ req->rq_rcvsize = RPC_REPHDRSIZE + slack + proc->p_replen;
+ req->rq_rcvsize <<= 2;
+
+ req->rq_buffer = xprt->ops->buf_alloc(task,
+ req->rq_callsize + req->rq_rcvsize);
+ if (req->rq_buffer != NULL)
return;
dprintk("RPC: %5u rpc_buffer allocation failed\n", task->tk_pid);
@@ -788,6 +803,17 @@ rpc_task_force_reencode(struct rpc_task *task)
task->tk_rqstp->rq_snd_buf.len = 0;
}
+static inline void
+rpc_xdr_buf_init(struct xdr_buf *buf, void *start, size_t len)
+{
+ buf->head[0].iov_base = start;
+ buf->head[0].iov_len = len;
+ buf->tail[0].iov_len = 0;
+ buf->page_len = 0;
+ buf->len = 0;
+ buf->buflen = len;
+}
+
/*
* 3. Encode arguments of an RPC call
*/
@@ -795,28 +821,17 @@ static void
call_encode(struct rpc_task *task)
{
struct rpc_rqst *req = task->tk_rqstp;
- struct xdr_buf *sndbuf = &req->rq_snd_buf;
- struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
- unsigned int bufsiz;
kxdrproc_t encode;
__be32 *p;
dprint_status(task);
- /* Default buffer setup */
- bufsiz = req->rq_bufsize >> 1;
- sndbuf->head[0].iov_base = (void *)req->rq_buffer;
- sndbuf->head[0].iov_len = bufsiz;
- sndbuf->tail[0].iov_len = 0;
- sndbuf->page_len = 0;
- sndbuf->len = 0;
- sndbuf->buflen = bufsiz;
- rcvbuf->head[0].iov_base = (void *)((char *)req->rq_buffer + bufsiz);
- rcvbuf->head[0].iov_len = bufsiz;
- rcvbuf->tail[0].iov_len = 0;
- rcvbuf->page_len = 0;
- rcvbuf->len = 0;
- rcvbuf->buflen = bufsiz;
+ rpc_xdr_buf_init(&req->rq_snd_buf,
+ req->rq_buffer,
+ req->rq_callsize);
+ rpc_xdr_buf_init(&req->rq_rcv_buf,
+ (char *)req->rq_buffer + req->rq_callsize,
+ req->rq_rcvsize);
/* Encode header and provided arguments */
encode = task->tk_msg.rpc_proc->p_encode;
@@ -887,9 +902,11 @@ call_bind_status(struct rpc_task *task)
task->tk_pid);
break;
case -EPROTONOSUPPORT:
- dprintk("RPC: %5u remote rpcbind version 2 unavailable\n",
+ dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
task->tk_pid);
- break;
+ task->tk_status = 0;
+ task->tk_action = call_bind;
+ return;
default:
dprintk("RPC: %5u unrecognized rpcbind error (%d)\n",
task->tk_pid, -task->tk_status);
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
deleted file mode 100644
index d9f76534458..00000000000
--- a/net/sunrpc/pmap_clnt.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * linux/net/sunrpc/pmap_clnt.c
- *
- * In-kernel RPC portmapper client.
- *
- * Portmapper supports version 2 of the rpcbind protocol (RFC 1833).
- *
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
- */
-
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/uio.h>
-#include <linux/in.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/sched.h>
-
-#ifdef RPC_DEBUG
-# define RPCDBG_FACILITY RPCDBG_PMAP
-#endif
-
-#define PMAP_SET 1
-#define PMAP_UNSET 2
-#define PMAP_GETPORT 3
-
-struct portmap_args {
- u32 pm_prog;
- u32 pm_vers;
- u32 pm_prot;
- unsigned short pm_port;
- struct rpc_xprt * pm_xprt;
-};
-
-static struct rpc_procinfo pmap_procedures[];
-static struct rpc_clnt * pmap_create(char *, struct sockaddr_in *, int, int);
-static void pmap_getport_done(struct rpc_task *, void *);
-static struct rpc_program pmap_program;
-
-static void pmap_getport_prepare(struct rpc_task *task, void *calldata)
-{
- struct portmap_args *map = calldata;
- struct rpc_message msg = {
- .rpc_proc = &pmap_procedures[PMAP_GETPORT],
- .rpc_argp = map,
- .rpc_resp = &map->pm_port,
- };
-
- rpc_call_setup(task, &msg, 0);
-}
-
-static inline struct portmap_args *pmap_map_alloc(void)
-{
- return kmalloc(sizeof(struct portmap_args), GFP_NOFS);
-}
-
-static inline void pmap_map_free(struct portmap_args *map)
-{
- kfree(map);
-}
-
-static void pmap_map_release(void *data)
-{
- struct portmap_args *map = data;
-
- xprt_put(map->pm_xprt);
- pmap_map_free(map);
-}
-
-static const struct rpc_call_ops pmap_getport_ops = {
- .rpc_call_prepare = pmap_getport_prepare,
- .rpc_call_done = pmap_getport_done,
- .rpc_release = pmap_map_release,
-};
-
-static inline void pmap_wake_portmap_waiters(struct rpc_xprt *xprt, int status)
-{
- xprt_clear_binding(xprt);
- rpc_wake_up_status(&xprt->binding, status);
-}
-
-/**
- * rpc_getport - obtain the port for a given RPC service on a given host
- * @task: task that is waiting for portmapper request
- *
- * This one can be called for an ongoing RPC request, and can be used in
- * an async (rpciod) context.
- */
-void rpc_getport(struct rpc_task *task)
-{
- struct rpc_clnt *clnt = task->tk_client;
- struct rpc_xprt *xprt = task->tk_xprt;
- struct sockaddr_in addr;
- struct portmap_args *map;
- struct rpc_clnt *pmap_clnt;
- struct rpc_task *child;
- int status;
-
- dprintk("RPC: %5u rpc_getport(%s, %u, %u, %d)\n",
- task->tk_pid, clnt->cl_server,
- clnt->cl_prog, clnt->cl_vers, xprt->prot);
-
- /* Autobind on cloned rpc clients is discouraged */
- BUG_ON(clnt->cl_parent != clnt);
-
- status = -EACCES; /* tell caller to check again */
- if (xprt_test_and_set_binding(xprt))
- goto bailout_nowake;
-
- /* Put self on queue before sending rpcbind request, in case
- * pmap_getport_done completes before we return from rpc_run_task */
- rpc_sleep_on(&xprt->binding, task, NULL, NULL);
-
- /* Someone else may have bound if we slept */
- status = 0;
- if (xprt_bound(xprt))
- goto bailout_nofree;
-
- status = -ENOMEM;
- map = pmap_map_alloc();
- if (!map)
- goto bailout_nofree;
- map->pm_prog = clnt->cl_prog;
- map->pm_vers = clnt->cl_vers;
- map->pm_prot = xprt->prot;
- map->pm_port = 0;
- map->pm_xprt = xprt_get(xprt);
-
- rpc_peeraddr(clnt, (struct sockaddr *) &addr, sizeof(addr));
- pmap_clnt = pmap_create(clnt->cl_server, &addr, map->pm_prot, 0);
- status = PTR_ERR(pmap_clnt);
- if (IS_ERR(pmap_clnt))
- goto bailout;
-
- status = -EIO;
- child = rpc_run_task(pmap_clnt, RPC_TASK_ASYNC, &pmap_getport_ops, map);
- if (IS_ERR(child))
- goto bailout_nofree;
- rpc_put_task(child);
-
- task->tk_xprt->stat.bind_count++;
- return;
-
-bailout:
- pmap_map_free(map);
- xprt_put(xprt);
-bailout_nofree:
- pmap_wake_portmap_waiters(xprt, status);
-bailout_nowake:
- task->tk_status = status;
-}
-
-#ifdef CONFIG_ROOT_NFS
-/**
- * rpc_getport_external - obtain the port for a given RPC service on a given host
- * @sin: address of remote peer
- * @prog: RPC program number to bind
- * @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
- *
- * This one is called from outside the RPC client in a synchronous task context.
- */
-int rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
-{
- struct portmap_args map = {
- .pm_prog = prog,
- .pm_vers = vers,
- .pm_prot = prot,
- .pm_port = 0
- };
- struct rpc_message msg = {
- .rpc_proc = &pmap_procedures[PMAP_GETPORT],
- .rpc_argp = &map,
- .rpc_resp = &map.pm_port,
- };
- struct rpc_clnt *pmap_clnt;
- char hostname[32];
- int status;
-
- dprintk("RPC: rpc_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
- NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
-
- sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
- pmap_clnt = pmap_create(hostname, sin, prot, 0);
- if (IS_ERR(pmap_clnt))
- return PTR_ERR(pmap_clnt);
-
- /* Setup the call info struct */
- status = rpc_call_sync(pmap_clnt, &msg, 0);
-
- if (status >= 0) {
- if (map.pm_port != 0)
- return map.pm_port;
- status = -EACCES;
- }
- return status;
-}
-#endif
-
-/*
- * Portmapper child task invokes this callback via tk_exit.
- */
-static void pmap_getport_done(struct rpc_task *child, void *data)
-{
- struct portmap_args *map = data;
- struct rpc_xprt *xprt = map->pm_xprt;
- int status = child->tk_status;
-
- if (status < 0) {
- /* Portmapper not available */
- xprt->ops->set_port(xprt, 0);
- } else if (map->pm_port == 0) {
- /* Requested RPC service wasn't registered */
- xprt->ops->set_port(xprt, 0);
- status = -EACCES;
- } else {
- /* Succeeded */
- xprt->ops->set_port(xprt, map->pm_port);
- xprt_set_bound(xprt);
- status = 0;
- }
-
- dprintk("RPC: %5u pmap_getport_done(status %d, port %u)\n",
- child->tk_pid, status, map->pm_port);
-
- pmap_wake_portmap_waiters(xprt, status);
-}
-
-/**
- * rpc_register - set or unset a port registration with the local portmapper
- * @prog: RPC program number to bind
- * @vers: RPC version number to bind
- * @prot: transport protocol to use to make this request
- * @port: port value to register
- * @okay: result code
- *
- * port == 0 means unregister, port != 0 means register.
- */
-int rpc_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
-{
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
- .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
- };
- struct portmap_args map = {
- .pm_prog = prog,
- .pm_vers = vers,
- .pm_prot = prot,
- .pm_port = port,
- };
- struct rpc_message msg = {
- .rpc_proc = &pmap_procedures[port ? PMAP_SET : PMAP_UNSET],
- .rpc_argp = &map,
- .rpc_resp = okay,
- };
- struct rpc_clnt *pmap_clnt;
- int error = 0;
-
- dprintk("RPC: registering (%u, %u, %d, %u) with portmapper.\n",
- prog, vers, prot, port);
-
- pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP, 1);
- if (IS_ERR(pmap_clnt)) {
- error = PTR_ERR(pmap_clnt);
- dprintk("RPC: couldn't create pmap client. Error = %d\n",
- error);
- return error;
- }
-
- error = rpc_call_sync(pmap_clnt, &msg, 0);
-
- if (error < 0) {
- printk(KERN_WARNING
- "RPC: failed to contact portmap (errno %d).\n",
- error);
- }
- dprintk("RPC: registration status %d/%d\n", error, *okay);
-
- /* Client deleted automatically because cl_oneshot == 1 */
- return error;
-}
-
-static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileged)
-{
- struct rpc_create_args args = {
- .protocol = proto,
- .address = (struct sockaddr *)srvaddr,
- .addrsize = sizeof(*srvaddr),
- .servername = hostname,
- .program = &pmap_program,
- .version = RPC_PMAP_VERSION,
- .authflavor = RPC_AUTH_UNIX,
- .flags = (RPC_CLNT_CREATE_ONESHOT |
- RPC_CLNT_CREATE_NOPING),
- };
-
- srvaddr->sin_port = htons(RPC_PMAP_PORT);
- if (!privileged)
- args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
- return rpc_create(&args);
-}
-
-/*
- * XDR encode/decode functions for PMAP
- */
-static int xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct portmap_args *map)
-{
- dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n",
- map->pm_prog, map->pm_vers,
- map->pm_prot, map->pm_port);
- *p++ = htonl(map->pm_prog);
- *p++ = htonl(map->pm_vers);
- *p++ = htonl(map->pm_prot);
- *p++ = htonl(map->pm_port);
-
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
-}
-
-static int xdr_decode_port(struct rpc_rqst *req, __be32 *p, unsigned short *portp)
-{
- *portp = (unsigned short) ntohl(*p++);
- return 0;
-}
-
-static int xdr_decode_bool(struct rpc_rqst *req, __be32 *p, unsigned int *boolp)
-{
- *boolp = (unsigned int) ntohl(*p++);
- return 0;
-}
-
-static struct rpc_procinfo pmap_procedures[] = {
-[PMAP_SET] = {
- .p_proc = PMAP_SET,
- .p_encode = (kxdrproc_t) xdr_encode_mapping,
- .p_decode = (kxdrproc_t) xdr_decode_bool,
- .p_bufsiz = 4,
- .p_count = 1,
- .p_statidx = PMAP_SET,
- .p_name = "SET",
- },
-[PMAP_UNSET] = {
- .p_proc = PMAP_UNSET,
- .p_encode = (kxdrproc_t) xdr_encode_mapping,
- .p_decode = (kxdrproc_t) xdr_decode_bool,
- .p_bufsiz = 4,
- .p_count = 1,
- .p_statidx = PMAP_UNSET,
- .p_name = "UNSET",
- },
-[PMAP_GETPORT] = {
- .p_proc = PMAP_GETPORT,
- .p_encode = (kxdrproc_t) xdr_encode_mapping,
- .p_decode = (kxdrproc_t) xdr_decode_port,
- .p_bufsiz = 4,
- .p_count = 1,
- .p_statidx = PMAP_GETPORT,
- .p_name = "GETPORT",
- },
-};
-
-static struct rpc_version pmap_version2 = {
- .number = 2,
- .nrprocs = 4,
- .procs = pmap_procedures
-};
-
-static struct rpc_version * pmap_version[] = {
- NULL,
- NULL,
- &pmap_version2
-};
-
-static struct rpc_stat pmap_stats;
-
-static struct rpc_program pmap_program = {
- .name = "portmap",
- .number = RPC_PMAP_PROGRAM,
- .nrvers = ARRAY_SIZE(pmap_version),
- .version = pmap_version,
- .stats = &pmap_stats,
-};
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9b9ea504556..a2f1893bde5 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -828,8 +828,7 @@ init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
{
struct rpc_inode *rpci = (struct rpc_inode *) foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
- SLAB_CTOR_CONSTRUCTOR) {
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&rpci->vfs_inode);
rpci->private = NULL;
rpci->nreaders = 0;
@@ -846,6 +845,8 @@ init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
int register_rpc_pipefs(void)
{
+ int err;
+
rpc_inode_cachep = kmem_cache_create("rpc_inode_cache",
sizeof(struct rpc_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
@@ -853,7 +854,12 @@ int register_rpc_pipefs(void)
init_once, NULL);
if (!rpc_inode_cachep)
return -ENOMEM;
- register_filesystem(&rpc_pipe_fs_type);
+ err = register_filesystem(&rpc_pipe_fs_type);
+ if (err) {
+ kmem_cache_destroy(rpc_inode_cachep);
+ return err;
+ }
+
return 0;
}
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
new file mode 100644
index 00000000000..6c7aa8a1f0c
--- /dev/null
+++ b/net/sunrpc/rpcb_clnt.c
@@ -0,0 +1,625 @@
+/*
+ * In-kernel rpcbind client supporting versions 2, 3, and 4 of the rpcbind
+ * protocol
+ *
+ * Based on RFC 1833: "Binding Protocols for ONC RPC Version 2" and
+ * RFC 3530: "Network File System (NFS) version 4 Protocol"
+ *
+ * Original: Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net>
+ * Updated: Chuck Lever, Oracle Corporation, 2007 <chuck.lever@oracle.com>
+ *
+ * Descended from net/sunrpc/pmap_clnt.c,
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY RPCDBG_BIND
+#endif
+
+#define RPCBIND_PROGRAM (100000u)
+#define RPCBIND_PORT (111u)
+
+enum {
+ RPCBPROC_NULL,
+ RPCBPROC_SET,
+ RPCBPROC_UNSET,
+ RPCBPROC_GETPORT,
+ RPCBPROC_GETADDR = 3, /* alias for GETPORT */
+ RPCBPROC_DUMP,
+ RPCBPROC_CALLIT,
+ RPCBPROC_BCAST = 5, /* alias for CALLIT */
+ RPCBPROC_GETTIME,
+ RPCBPROC_UADDR2TADDR,
+ RPCBPROC_TADDR2UADDR,
+ RPCBPROC_GETVERSADDR,
+ RPCBPROC_INDIRECT,
+ RPCBPROC_GETADDRLIST,
+ RPCBPROC_GETSTAT,
+};
+
+#define RPCB_HIGHPROC_2 RPCBPROC_CALLIT
+#define RPCB_HIGHPROC_3 RPCBPROC_TADDR2UADDR
+#define RPCB_HIGHPROC_4 RPCBPROC_GETSTAT
+
+/*
+ * r_addr
+ *
+ * Quoting RFC 3530, section 2.2:
+ *
+ * For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the
+ * US-ASCII string:
+ *
+ * h1.h2.h3.h4.p1.p2
+ *
+ * The prefix, "h1.h2.h3.h4", is the standard textual form for
+ * representing an IPv4 address, which is always four octets long.
+ * Assuming big-endian ordering, h1, h2, h3, and h4, are respectively,
+ * the first through fourth octets each converted to ASCII-decimal.
+ * Assuming big-endian ordering, p1 and p2 are, respectively, the first
+ * and second octets each converted to ASCII-decimal. For example, if a
+ * host, in big-endian order, has an address of 0x0A010307 and there is
+ * a service listening on, in big endian order, port 0x020F (decimal
+ * 527), then the complete universal address is "10.1.3.7.2.15".
+ *
+ * ...
+ *
+ * For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the
+ * US-ASCII string:
+ *
+ * x1:x2:x3:x4:x5:x6:x7:x8.p1.p2
+ *
+ * The suffix "p1.p2" is the service port, and is computed the same way
+ * as with universal addresses for TCP and UDP over IPv4. The prefix,
+ * "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for
+ * representing an IPv6 address as defined in Section 2.2 of [RFC2373].
+ * Additionally, the two alternative forms specified in Section 2.2 of
+ * [RFC2373] are also acceptable.
+ *
+ * XXX: Currently this implementation does not explicitly convert the
+ * stored address to US-ASCII on non-ASCII systems.
+ */
+#define RPCB_MAXADDRLEN (128u)
+
+/*
+ * r_netid
+ *
+ * Quoting RFC 3530, section 2.2:
+ *
+ * For TCP over IPv4 the value of r_netid is the string "tcp". For UDP
+ * over IPv4 the value of r_netid is the string "udp".
+ *
+ * ...
+ *
+ * For TCP over IPv6 the value of r_netid is the string "tcp6". For UDP
+ * over IPv6 the value of r_netid is the string "udp6".
+ */
+#define RPCB_NETID_UDP "\165\144\160" /* "udp" */
+#define RPCB_NETID_TCP "\164\143\160" /* "tcp" */
+#define RPCB_NETID_UDP6 "\165\144\160\066" /* "udp6" */
+#define RPCB_NETID_TCP6 "\164\143\160\066" /* "tcp6" */
+
+#define RPCB_MAXNETIDLEN (4u)
+
+/*
+ * r_owner
+ *
+ * The "owner" is allowed to unset a service in the rpcbind database.
+ * We always use the following (arbitrary) fixed string.
+ */
+#define RPCB_OWNER_STRING "rpcb"
+#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
+
+static void rpcb_getport_done(struct rpc_task *, void *);
+extern struct rpc_program rpcb_program;
+
+struct rpcbind_args {
+ struct rpc_xprt * r_xprt;
+
+ u32 r_prog;
+ u32 r_vers;
+ u32 r_prot;
+ unsigned short r_port;
+ char * r_netid;
+ char r_addr[RPCB_MAXADDRLEN];
+ char * r_owner;
+};
+
+static struct rpc_procinfo rpcb_procedures2[];
+static struct rpc_procinfo rpcb_procedures3[];
+
+static struct rpcb_info {
+ int rpc_vers;
+ struct rpc_procinfo * rpc_proc;
+} rpcb_next_version[];
+
+static void rpcb_getport_prepare(struct rpc_task *task, void *calldata)
+{
+ struct rpcbind_args *map = calldata;
+ struct rpc_xprt *xprt = map->r_xprt;
+ struct rpc_message msg = {
+ .rpc_proc = rpcb_next_version[xprt->bind_index].rpc_proc,
+ .rpc_argp = map,
+ .rpc_resp = &map->r_port,
+ };
+
+ rpc_call_setup(task, &msg, 0);
+}
+
+static void rpcb_map_release(void *data)
+{
+ struct rpcbind_args *map = data;
+
+ xprt_put(map->r_xprt);
+ kfree(map);
+}
+
+static const struct rpc_call_ops rpcb_getport_ops = {
+ .rpc_call_prepare = rpcb_getport_prepare,
+ .rpc_call_done = rpcb_getport_done,
+ .rpc_release = rpcb_map_release,
+};
+
+static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
+{
+ xprt_clear_binding(xprt);
+ rpc_wake_up_status(&xprt->binding, status);
+}
+
+static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
+ int proto, int version, int privileged)
+{
+ struct rpc_create_args args = {
+ .protocol = proto,
+ .address = srvaddr,
+ .addrsize = sizeof(struct sockaddr_in),
+ .servername = hostname,
+ .program = &rpcb_program,
+ .version = version,
+ .authflavor = RPC_AUTH_UNIX,
+ .flags = (RPC_CLNT_CREATE_ONESHOT |
+ RPC_CLNT_CREATE_NOPING),
+ };
+
+ ((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
+ if (!privileged)
+ args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
+ return rpc_create(&args);
+}
+
+/**
+ * rpcb_register - set or unset a port registration with the local rpcbind svc
+ * @prog: RPC program number to bind
+ * @vers: RPC version number to bind
+ * @prot: transport protocol to use to make this request
+ * @port: port value to register
+ * @okay: result code
+ *
+ * port == 0 means unregister, port != 0 means register.
+ *
+ * This routine supports only rpcbind version 2.
+ */
+int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+ struct rpcbind_args map = {
+ .r_prog = prog,
+ .r_vers = vers,
+ .r_prot = prot,
+ .r_port = port,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &rpcb_procedures2[port ?
+ RPCBPROC_SET : RPCBPROC_UNSET],
+ .rpc_argp = &map,
+ .rpc_resp = okay,
+ };
+ struct rpc_clnt *rpcb_clnt;
+ int error = 0;
+
+ dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
+ "rpcbind\n", (port ? "" : "un"),
+ prog, vers, prot, port);
+
+ rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
+ IPPROTO_UDP, 2, 1);
+ if (IS_ERR(rpcb_clnt))
+ return PTR_ERR(rpcb_clnt);
+
+ error = rpc_call_sync(rpcb_clnt, &msg, 0);
+
+ if (error < 0)
+ printk(KERN_WARNING "RPC: failed to contact local rpcbind "
+ "server (errno %d).\n", -error);
+ dprintk("RPC: registration status %d/%d\n", error, *okay);
+
+ return error;
+}
+
+#ifdef CONFIG_ROOT_NFS
+/**
+ * rpcb_getport_external - obtain the port for an RPC service on a given host
+ * @sin: address of remote peer
+ * @prog: RPC program number to bind
+ * @vers: RPC version number to bind
+ * @prot: transport protocol to use to make this request
+ *
+ * Called from outside the RPC client in a synchronous task context.
+ *
+ * For now, this supports only version 2 queries, but is used only by
+ * mount_clnt for NFS_ROOT.
+ */
+int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog,
+ __u32 vers, int prot)
+{
+ struct rpcbind_args map = {
+ .r_prog = prog,
+ .r_vers = vers,
+ .r_prot = prot,
+ .r_port = 0,
+ };
+ struct rpc_message msg = {
+ .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT],
+ .rpc_argp = &map,
+ .rpc_resp = &map.r_port,
+ };
+ struct rpc_clnt *rpcb_clnt;
+ char hostname[40];
+ int status;
+
+ dprintk("RPC: rpcb_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
+ NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+
+ sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
+ rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
+ if (IS_ERR(rpcb_clnt))
+ return PTR_ERR(rpcb_clnt);
+
+ status = rpc_call_sync(rpcb_clnt, &msg, 0);
+
+ if (status >= 0) {
+ if (map.r_port != 0)
+ return map.r_port;
+ status = -EACCES;
+ }
+ return status;
+}
+#endif
+
+/**
+ * rpcb_getport - obtain the port for a given RPC service on a given host
+ * @task: task that is waiting for portmapper request
+ *
+ * This one can be called for an ongoing RPC request, and can be used in
+ * an async (rpciod) context.
+ */
+void rpcb_getport(struct rpc_task *task)
+{
+ struct rpc_clnt *clnt = task->tk_client;
+ int bind_version;
+ struct rpc_xprt *xprt = task->tk_xprt;
+ struct rpc_clnt *rpcb_clnt;
+ static struct rpcbind_args *map;
+ struct rpc_task *child;
+ struct sockaddr addr;
+ int status;
+
+ dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d)\n",
+ task->tk_pid, clnt->cl_server,
+ clnt->cl_prog, clnt->cl_vers, xprt->prot);
+
+ /* Autobind on cloned rpc clients is discouraged */
+ BUG_ON(clnt->cl_parent != clnt);
+
+ if (xprt_test_and_set_binding(xprt)) {
+ status = -EACCES; /* tell caller to check again */
+ dprintk("RPC: %5u rpcb_getport waiting for another binder\n",
+ task->tk_pid);
+ goto bailout_nowake;
+ }
+
+ /* Put self on queue before sending rpcbind request, in case
+ * rpcb_getport_done completes before we return from rpc_run_task */
+ rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+
+ /* Someone else may have bound if we slept */
+ if (xprt_bound(xprt)) {
+ status = 0;
+ dprintk("RPC: %5u rpcb_getport already bound\n", task->tk_pid);
+ goto bailout_nofree;
+ }
+
+ if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) {
+ xprt->bind_index = 0;
+ status = -EACCES; /* tell caller to try again later */
+ dprintk("RPC: %5u rpcb_getport no more getport versions "
+ "available\n", task->tk_pid);
+ goto bailout_nofree;
+ }
+ bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
+
+ dprintk("RPC: %5u rpcb_getport trying rpcbind version %u\n",
+ task->tk_pid, bind_version);
+
+ map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
+ if (!map) {
+ status = -ENOMEM;
+ dprintk("RPC: %5u rpcb_getport no memory available\n",
+ task->tk_pid);
+ goto bailout_nofree;
+ }
+ map->r_prog = clnt->cl_prog;
+ map->r_vers = clnt->cl_vers;
+ map->r_prot = xprt->prot;
+ map->r_port = 0;
+ map->r_xprt = xprt_get(xprt);
+ map->r_netid = (xprt->prot == IPPROTO_TCP) ? RPCB_NETID_TCP :
+ RPCB_NETID_UDP;
+ memcpy(&map->r_addr, rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR),
+ sizeof(map->r_addr));
+ map->r_owner = RPCB_OWNER_STRING; /* ignored for GETADDR */
+
+ rpc_peeraddr(clnt, (void *)&addr, sizeof(addr));
+ rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
+ if (IS_ERR(rpcb_clnt)) {
+ status = PTR_ERR(rpcb_clnt);
+ dprintk("RPC: %5u rpcb_getport rpcb_create failed, error %ld\n",
+ task->tk_pid, PTR_ERR(rpcb_clnt));
+ goto bailout;
+ }
+
+ child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
+ if (IS_ERR(child)) {
+ status = -EIO;
+ dprintk("RPC: %5u rpcb_getport rpc_run_task failed\n",
+ task->tk_pid);
+ goto bailout_nofree;
+ }
+ rpc_put_task(child);
+
+ task->tk_xprt->stat.bind_count++;
+ return;
+
+bailout:
+ kfree(map);
+ xprt_put(xprt);
+bailout_nofree:
+ rpcb_wake_rpcbind_waiters(xprt, status);
+bailout_nowake:
+ task->tk_status = status;
+}
+
+/*
+ * Rpcbind child task calls this callback via tk_exit.
+ */
+static void rpcb_getport_done(struct rpc_task *child, void *data)
+{
+ struct rpcbind_args *map = data;
+ struct rpc_xprt *xprt = map->r_xprt;
+ int status = child->tk_status;
+
+ /* rpcbind server doesn't support this rpcbind protocol version */
+ if (status == -EPROTONOSUPPORT)
+ xprt->bind_index++;
+
+ if (status < 0) {
+ /* rpcbind server not available on remote host? */
+ xprt->ops->set_port(xprt, 0);
+ } else if (map->r_port == 0) {
+ /* Requested RPC service wasn't registered on remote host */
+ xprt->ops->set_port(xprt, 0);
+ status = -EACCES;
+ } else {
+ /* Succeeded */
+ xprt->ops->set_port(xprt, map->r_port);
+ xprt_set_bound(xprt);
+ status = 0;
+ }
+
+ dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
+ child->tk_pid, status, map->r_port);
+
+ rpcb_wake_rpcbind_waiters(xprt, status);
+}
+
+static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
+ struct rpcbind_args *rpcb)
+{
+ dprintk("RPC: rpcb_encode_mapping(%u, %u, %d, %u)\n",
+ rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
+ *p++ = htonl(rpcb->r_prog);
+ *p++ = htonl(rpcb->r_vers);
+ *p++ = htonl(rpcb->r_prot);
+ *p++ = htonl(rpcb->r_port);
+
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
+ unsigned short *portp)
+{
+ *portp = (unsigned short) ntohl(*p++);
+ dprintk("RPC: rpcb_decode_getport result %u\n",
+ *portp);
+ return 0;
+}
+
+static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
+ unsigned int *boolp)
+{
+ *boolp = (unsigned int) ntohl(*p++);
+ dprintk("RPC: rpcb_decode_set result %u\n",
+ *boolp);
+ return 0;
+}
+
+static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
+ struct rpcbind_args *rpcb)
+{
+ dprintk("RPC: rpcb_encode_getaddr(%u, %u, %s)\n",
+ rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
+ *p++ = htonl(rpcb->r_prog);
+ *p++ = htonl(rpcb->r_vers);
+
+ p = xdr_encode_string(p, rpcb->r_netid);
+ p = xdr_encode_string(p, rpcb->r_addr);
+ p = xdr_encode_string(p, rpcb->r_owner);
+
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+ return 0;
+}
+
+static int rpcb_decode_getaddr(struct rpc_rqst *req, __be32 *p,
+ unsigned short *portp)
+{
+ char *addr;
+ int addr_len, c, i, f, first, val;
+
+ *portp = 0;
+ addr_len = (unsigned int) ntohl(*p++);
+ if (addr_len > RPCB_MAXADDRLEN) /* sanity */
+ return -EINVAL;
+
+ dprintk("RPC: rpcb_decode_getaddr returned string: '%s'\n",
+ (char *) p);
+
+ addr = (char *)p;
+ val = 0;
+ first = 1;
+ f = 1;
+ for (i = addr_len - 1; i > 0; i--) {
+ c = addr[i];
+ if (c >= '0' && c <= '9') {
+ val += (c - '0') * f;
+ f *= 10;
+ } else if (c == '.') {
+ if (first) {
+ *portp = val;
+ val = first = 0;
+ f = 1;
+ } else {
+ *portp |= (val << 8);
+ break;
+ }
+ }
+ }
+
+ dprintk("RPC: rpcb_decode_getaddr port=%u\n", *portp);
+ return 0;
+}
+
+#define RPCB_program_sz (1u)
+#define RPCB_version_sz (1u)
+#define RPCB_protocol_sz (1u)
+#define RPCB_port_sz (1u)
+#define RPCB_boolean_sz (1u)
+
+#define RPCB_netid_sz (1+XDR_QUADLEN(RPCB_MAXNETIDLEN))
+#define RPCB_addr_sz (1+XDR_QUADLEN(RPCB_MAXADDRLEN))
+#define RPCB_ownerstring_sz (1+XDR_QUADLEN(RPCB_MAXOWNERLEN))
+
+#define RPCB_mappingargs_sz RPCB_program_sz+RPCB_version_sz+ \
+ RPCB_protocol_sz+RPCB_port_sz
+#define RPCB_getaddrargs_sz RPCB_program_sz+RPCB_version_sz+ \
+ RPCB_netid_sz+RPCB_addr_sz+ \
+ RPCB_ownerstring_sz
+
+#define RPCB_setres_sz RPCB_boolean_sz
+#define RPCB_getportres_sz RPCB_port_sz
+
+/*
+ * Note that RFC 1833 does not put any size restrictions on the
+ * address string returned by the remote rpcbind database.
+ */
+#define RPCB_getaddrres_sz RPCB_addr_sz
+
+#define PROC(proc, argtype, restype) \
+ [RPCBPROC_##proc] = { \
+ .p_proc = RPCBPROC_##proc, \
+ .p_encode = (kxdrproc_t) rpcb_encode_##argtype, \
+ .p_decode = (kxdrproc_t) rpcb_decode_##restype, \
+ .p_arglen = RPCB_##argtype##args_sz, \
+ .p_replen = RPCB_##restype##res_sz, \
+ .p_statidx = RPCBPROC_##proc, \
+ .p_timer = 0, \
+ .p_name = #proc, \
+ }
+
+/*
+ * Not all rpcbind procedures described in RFC 1833 are implemented
+ * since the Linux kernel RPC code requires only these.
+ */
+static struct rpc_procinfo rpcb_procedures2[] = {
+ PROC(SET, mapping, set),
+ PROC(UNSET, mapping, set),
+ PROC(GETADDR, mapping, getport),
+};
+
+static struct rpc_procinfo rpcb_procedures3[] = {
+ PROC(SET, mapping, set),
+ PROC(UNSET, mapping, set),
+ PROC(GETADDR, getaddr, getaddr),
+};
+
+static struct rpc_procinfo rpcb_procedures4[] = {
+ PROC(SET, mapping, set),
+ PROC(UNSET, mapping, set),
+ PROC(GETVERSADDR, getaddr, getaddr),
+};
+
+static struct rpcb_info rpcb_next_version[] = {
+#ifdef CONFIG_SUNRPC_BIND34
+ { 4, &rpcb_procedures4[RPCBPROC_GETVERSADDR] },
+ { 3, &rpcb_procedures3[RPCBPROC_GETADDR] },
+#endif
+ { 2, &rpcb_procedures2[RPCBPROC_GETPORT] },
+ { 0, NULL },
+};
+
+static struct rpc_version rpcb_version2 = {
+ .number = 2,
+ .nrprocs = RPCB_HIGHPROC_2,
+ .procs = rpcb_procedures2
+};
+
+static struct rpc_version rpcb_version3 = {
+ .number = 3,
+ .nrprocs = RPCB_HIGHPROC_3,
+ .procs = rpcb_procedures3
+};
+
+static struct rpc_version rpcb_version4 = {
+ .number = 4,
+ .nrprocs = RPCB_HIGHPROC_4,
+ .procs = rpcb_procedures4
+};
+
+static struct rpc_version *rpcb_version[] = {
+ NULL,
+ NULL,
+ &rpcb_version2,
+ &rpcb_version3,
+ &rpcb_version4
+};
+
+static struct rpc_stat rpcb_stats;
+
+struct rpc_program rpcb_program = {
+ .name = "rpcbind",
+ .number = RPCBIND_PROGRAM,
+ .nrvers = ARRAY_SIZE(rpcb_version),
+ .version = rpcb_version,
+ .stats = &rpcb_stats,
+};
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 6d87320074b..99014516b73 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -741,50 +741,53 @@ static void rpc_async_schedule(struct work_struct *work)
* @task: RPC task that will use this buffer
* @size: requested byte size
*
- * We try to ensure that some NFS reads and writes can always proceed
- * by using a mempool when allocating 'small' buffers.
+ * To prevent rpciod from hanging, this allocator never sleeps,
+ * returning NULL if the request cannot be serviced immediately.
+ * The caller can arrange to sleep in a way that is safe for rpciod.
+ *
+ * Most requests are 'small' (under 2KiB) and can be serviced from a
+ * mempool, ensuring that NFS reads and writes can always proceed,
+ * and that there is good locality of reference for these buffers.
+ *
* In order to avoid memory starvation triggering more writebacks of
- * NFS requests, we use GFP_NOFS rather than GFP_KERNEL.
+ * NFS requests, we avoid using GFP_KERNEL.
*/
-void * rpc_malloc(struct rpc_task *task, size_t size)
+void *rpc_malloc(struct rpc_task *task, size_t size)
{
- struct rpc_rqst *req = task->tk_rqstp;
- gfp_t gfp;
+ size_t *buf;
+ gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
- if (task->tk_flags & RPC_TASK_SWAPPER)
- gfp = GFP_ATOMIC;
+ size += sizeof(size_t);
+ if (size <= RPC_BUFFER_MAXSIZE)
+ buf = mempool_alloc(rpc_buffer_mempool, gfp);
else
- gfp = GFP_NOFS;
-
- if (size > RPC_BUFFER_MAXSIZE) {
- req->rq_buffer = kmalloc(size, gfp);
- if (req->rq_buffer)
- req->rq_bufsize = size;
- } else {
- req->rq_buffer = mempool_alloc(rpc_buffer_mempool, gfp);
- if (req->rq_buffer)
- req->rq_bufsize = RPC_BUFFER_MAXSIZE;
- }
- return req->rq_buffer;
+ buf = kmalloc(size, gfp);
+ *buf = size;
+ dprintk("RPC: %5u allocated buffer of size %zu at %p\n",
+ task->tk_pid, size, buf);
+ return ++buf;
}
/**
* rpc_free - free buffer allocated via rpc_malloc
- * @task: RPC task with a buffer to be freed
+ * @buffer: buffer to free
*
*/
-void rpc_free(struct rpc_task *task)
+void rpc_free(void *buffer)
{
- struct rpc_rqst *req = task->tk_rqstp;
+ size_t size, *buf = buffer;
- if (req->rq_buffer) {
- if (req->rq_bufsize == RPC_BUFFER_MAXSIZE)
- mempool_free(req->rq_buffer, rpc_buffer_mempool);
- else
- kfree(req->rq_buffer);
- req->rq_buffer = NULL;
- req->rq_bufsize = 0;
- }
+ if (!buffer)
+ return;
+ size = *buf;
+ buf--;
+
+ dprintk("RPC: freeing buffer of size %zu at %p\n",
+ size, buf);
+ if (size <= RPC_BUFFER_MAXSIZE)
+ mempool_free(buf, rpc_buffer_mempool);
+ else
+ kfree(buf);
}
/*
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 43ecf62f12e..0d35bc796d0 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -146,9 +146,11 @@ init_sunrpc(void)
int err = register_rpc_pipefs();
if (err)
goto out;
- err = rpc_init_mempool() != 0;
- if (err)
+ err = rpc_init_mempool();
+ if (err) {
+ unregister_rpc_pipefs();
goto out;
+ }
#ifdef RPC_DEBUG
rpc_register_sysctl();
#endif
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b4db53ff143..e673ef99390 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -757,7 +757,7 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
if (progp->pg_vers[i]->vs_hidden)
continue;
- error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+ error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
if (error < 0)
break;
if (port && !dummy) {
@@ -907,7 +907,7 @@ svc_process(struct svc_rqst *rqstp)
* better idea of reply size
*/
if (procp->pc_xdrressize)
- svc_reserve(rqstp, procp->pc_xdrressize<<2);
+ svc_reserve_auth(rqstp, procp->pc_xdrressize<<2);
/* Call the function that processes the request. */
if (!versp->vs_dispatch) {
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index f5c3808bf85..af7c5f05c6e 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -64,7 +64,7 @@ int svc_set_client(struct svc_rqst *rqstp)
}
/* A request, which was authenticated, has now executed.
- * Time to finalise the the credentials and verifier
+ * Time to finalise the credentials and verifier
* and release and resources
*/
int svc_authorise(struct svc_rqst *rqstp)
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 2bd23ea2aa8..07dcd20cbee 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -385,7 +385,7 @@ ip_map_cached_get(struct svc_rqst *rqstp)
{
struct ip_map *ipm;
struct svc_sock *svsk = rqstp->rq_sock;
- spin_lock_bh(&svsk->sk_defer_lock);
+ spin_lock(&svsk->sk_lock);
ipm = svsk->sk_info_authunix;
if (ipm != NULL) {
if (!cache_valid(&ipm->h)) {
@@ -395,13 +395,13 @@ ip_map_cached_get(struct svc_rqst *rqstp)
* same IP address.
*/
svsk->sk_info_authunix = NULL;
- spin_unlock_bh(&svsk->sk_defer_lock);
+ spin_unlock(&svsk->sk_lock);
cache_put(&ipm->h, &ip_map_cache);
return NULL;
}
cache_get(&ipm->h);
}
- spin_unlock_bh(&svsk->sk_defer_lock);
+ spin_unlock(&svsk->sk_lock);
return ipm;
}
@@ -410,14 +410,14 @@ ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
{
struct svc_sock *svsk = rqstp->rq_sock;
- spin_lock_bh(&svsk->sk_defer_lock);
+ spin_lock(&svsk->sk_lock);
if (svsk->sk_sock->type == SOCK_STREAM &&
svsk->sk_info_authunix == NULL) {
/* newly cached, keep the reference */
svsk->sk_info_authunix = ipm;
ipm = NULL;
}
- spin_unlock_bh(&svsk->sk_defer_lock);
+ spin_unlock(&svsk->sk_lock);
if (ipm)
cache_put(&ipm->h, &ip_map_cache);
}
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 22f61aee482..5baf48de255 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -53,7 +53,8 @@
* svc_serv->sv_lock protects sv_tempsocks, sv_permsocks, sv_tmpcnt.
* when both need to be taken (rare), svc_serv->sv_lock is first.
* BKL protects svc_serv->sv_nrthread.
- * svc_sock->sk_defer_lock protects the svc_sock->sk_deferred list
+ * svc_sock->sk_lock protects the svc_sock->sk_deferred list
+ * and the ->sk_info_authunix cache.
* svc_sock->sk_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
*
* Some flags can be set to certain values at any time
@@ -787,15 +788,20 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
}
clear_bit(SK_DATA, &svsk->sk_flags);
- while ((err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
- 0, 0, MSG_PEEK | MSG_DONTWAIT)) < 0 ||
- (skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
- if (err == -EAGAIN) {
- svc_sock_received(svsk);
- return err;
+ skb = NULL;
+ err = kernel_recvmsg(svsk->sk_sock, &msg, NULL,
+ 0, 0, MSG_PEEK | MSG_DONTWAIT);
+ if (err >= 0)
+ skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err);
+
+ if (skb == NULL) {
+ if (err != -EAGAIN) {
+ /* possibly an icmp error */
+ dprintk("svc: recvfrom returned error %d\n", -err);
+ set_bit(SK_DATA, &svsk->sk_flags);
}
- /* possibly an icmp error */
- dprintk("svc: recvfrom returned error %d\n", -err);
+ svc_sock_received(svsk);
+ return -EAGAIN;
}
rqstp->rq_addrlen = sizeof(rqstp->rq_addr);
if (skb->tstamp.tv64 == 0) {
@@ -1633,7 +1639,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
svsk->sk_server = serv;
atomic_set(&svsk->sk_inuse, 1);
svsk->sk_lastrecv = get_seconds();
- spin_lock_init(&svsk->sk_defer_lock);
+ spin_lock_init(&svsk->sk_lock);
INIT_LIST_HEAD(&svsk->sk_deferred);
INIT_LIST_HEAD(&svsk->sk_ready);
mutex_init(&svsk->sk_mutex);
@@ -1857,9 +1863,9 @@ static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
dprintk("revisit queued\n");
svsk = dr->svsk;
dr->svsk = NULL;
- spin_lock_bh(&svsk->sk_defer_lock);
+ spin_lock(&svsk->sk_lock);
list_add(&dr->handle.recent, &svsk->sk_deferred);
- spin_unlock_bh(&svsk->sk_defer_lock);
+ spin_unlock(&svsk->sk_lock);
set_bit(SK_DEFERRED, &svsk->sk_flags);
svc_sock_enqueue(svsk);
svc_sock_put(svsk);
@@ -1925,7 +1931,7 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
return NULL;
- spin_lock_bh(&svsk->sk_defer_lock);
+ spin_lock(&svsk->sk_lock);
clear_bit(SK_DEFERRED, &svsk->sk_flags);
if (!list_empty(&svsk->sk_deferred)) {
dr = list_entry(svsk->sk_deferred.next,
@@ -1934,6 +1940,6 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
list_del_init(&dr->handle.recent);
set_bit(SK_DEFERRED, &svsk->sk_flags);
}
- spin_unlock_bh(&svsk->sk_defer_lock);
+ spin_unlock(&svsk->sk_lock);
return dr;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 456a1451030..5b05b73e4c1 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -823,7 +823,6 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
req->rq_task = task;
req->rq_xprt = xprt;
req->rq_buffer = NULL;
- req->rq_bufsize = 0;
req->rq_xid = xprt_alloc_xid(xprt);
req->rq_release_snd_buf = NULL;
xprt_reset_majortimeo(req);
@@ -855,7 +854,7 @@ void xprt_release(struct rpc_task *task)
mod_timer(&xprt->timer,
xprt->last_used + xprt->idle_timeout);
spin_unlock_bh(&xprt->transport_lock);
- xprt->ops->buf_free(task);
+ xprt->ops->buf_free(req->rq_buffer);
task->tk_rqstp = NULL;
if (req->rq_release_snd_buf)
req->rq_release_snd_buf(req);
@@ -928,6 +927,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si
xprt->timer.data = (unsigned long) xprt;
xprt->last_used = jiffies;
xprt->cwnd = RPC_INITCWND;
+ xprt->bind_index = 0;
rpc_init_wait_queue(&xprt->binding, "xprt_binding");
rpc_init_wait_queue(&xprt->pending, "xprt_pending");
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index a5a32029e72..cc33c5880ab 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1476,7 +1476,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
.set_buffer_size = xs_udp_set_buffer_size,
.reserve_xprt = xprt_reserve_xprt_cong,
.release_xprt = xprt_release_xprt_cong,
- .rpcbind = rpc_getport,
+ .rpcbind = rpcb_getport,
.set_port = xs_set_port,
.connect = xs_connect,
.buf_alloc = rpc_malloc,
@@ -1493,7 +1493,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
static struct rpc_xprt_ops xs_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt,
.release_xprt = xs_tcp_release_xprt,
- .rpcbind = rpc_getport,
+ .rpcbind = rpcb_getport,
.set_port = xs_set_port,
.connect = xs_connect,
.buf_alloc = rpc_malloc,
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
index 3891cc00087..f9e367d946e 100644
--- a/net/tipc/Kconfig
+++ b/net/tipc/Kconfig
@@ -18,7 +18,7 @@ config TIPC
This protocol support is also available as a module ( = code which
can be inserted in and removed from the running kernel whenever you
want). The module will be called tipc. If you want to compile it
- as a module, say M here and read <file:Documentation/modules.txt>.
+ as a module, say M here and read <file:Documentation/kbuild/modules.txt>.
If in doubt, say N.
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 67bb29b44d1..0ee6ded18f3 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -120,16 +120,18 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
static int enable_bearer(struct tipc_bearer *tb_ptr)
{
- struct net_device *dev = dev_base;
+ struct net_device *dev, *pdev;
struct eth_bearer *eb_ptr = &eth_bearers[0];
struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
/* Find device with specified name */
-
- while (dev && dev->name && strncmp(dev->name, driver_name, IFNAMSIZ)) {
- dev = dev->next;
- }
+ dev = NULL;
+ for_each_netdev(pdev)
+ if (!strncmp(dev->name, driver_name, IFNAMSIZ)) {
+ dev = pdev;
+ break;
+ }
if (!dev)
return -ENODEV;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index aec8cf165e1..fc12ba51c1f 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -111,7 +111,6 @@
#include <net/scm.h>
#include <linux/init.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/rtnetlink.h>
#include <linux/mount.h>
#include <net/checksum.h>
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index 0d6002fc77b..479927cb45c 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1605,7 +1605,6 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
.sendpage = sock_no_sendpage,
};
-#include <linux/smp_lock.h>
SOCKOPS_WRAP(x25_proto, AF_X25);
static struct packet_type x25_packet_type = {
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index be529c4241a..6249a9405bb 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -532,8 +532,8 @@ EXPORT_SYMBOL_GPL(xfrm_count_enc_supported);
int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
int offset, int len, icv_update_fn_t icv_update)
{
- int end = skb_headlen(skb);
- int i, copy = end - offset;
+ int start = skb_headlen(skb);
+ int i, copy = start - offset;
int err;
struct scatterlist sg;
@@ -556,9 +556,11 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
}
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- BUG_TRAP(len >= 0);
+ int end;
- end = offset + skb_shinfo(skb)->frags[i].size;
+ BUG_TRAP(start <= offset + len);
+
+ end = start + skb_shinfo(skb)->frags[i].size;
if ((copy = end - offset) > 0) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
@@ -566,7 +568,7 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
copy = len;
sg.page = frag->page;
- sg.offset = frag->page_offset;
+ sg.offset = frag->page_offset + offset-start;
sg.length = copy;
err = icv_update(desc, &sg, copy);
@@ -577,19 +579,22 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
return 0;
offset += copy;
}
+ start = end;
}
if (skb_shinfo(skb)->frag_list) {
struct sk_buff *list = skb_shinfo(skb)->frag_list;
for (; list; list = list->next) {
- BUG_TRAP(len >= 0);
+ int end;
+
+ BUG_TRAP(start <= offset + len);
- end = offset + list->len;
+ end = start + list->len;
if ((copy = end - offset) > 0) {
if (copy > len)
copy = len;
- err = skb_icv_walk(list, desc, 0,
+ err = skb_icv_walk(list, desc, offset-start,
copy, icv_update);
if (unlikely(err))
return err;
@@ -597,6 +602,7 @@ int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
return 0;
offset += copy;
}
+ start = end;
}
}
BUG_ON(len);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 762926009c0..95271e8426a 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -579,8 +579,22 @@ static inline int xfrm_byidx_should_resize(int total)
return 0;
}
-static DEFINE_MUTEX(hash_resize_mutex);
+void xfrm_spd_getinfo(struct xfrmk_spdinfo *si)
+{
+ read_lock_bh(&xfrm_policy_lock);
+ si->incnt = xfrm_policy_count[XFRM_POLICY_IN];
+ si->outcnt = xfrm_policy_count[XFRM_POLICY_OUT];
+ si->fwdcnt = xfrm_policy_count[XFRM_POLICY_FWD];
+ si->inscnt = xfrm_policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX];
+ si->outscnt = xfrm_policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX];
+ si->fwdscnt = xfrm_policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX];
+ si->spdhcnt = xfrm_idx_hmask;
+ si->spdhmcnt = xfrm_policy_hashmax;
+ read_unlock_bh(&xfrm_policy_lock);
+}
+EXPORT_SYMBOL(xfrm_spd_getinfo);
+static DEFINE_MUTEX(hash_resize_mutex);
static void xfrm_hash_resize(struct work_struct *__unused)
{
int dir, total;
@@ -1330,6 +1344,40 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
return err;
}
+static int inline
+xfrm_dst_alloc_copy(void **target, void *src, int size)
+{
+ if (!*target) {
+ *target = kmalloc(size, GFP_ATOMIC);
+ if (!*target)
+ return -ENOMEM;
+ }
+ memcpy(*target, src, size);
+ return 0;
+}
+
+static int inline
+xfrm_dst_update_parent(struct dst_entry *dst, struct xfrm_selector *sel)
+{
+#ifdef CONFIG_XFRM_SUB_POLICY
+ struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+ return xfrm_dst_alloc_copy((void **)&(xdst->partner),
+ sel, sizeof(*sel));
+#else
+ return 0;
+#endif
+}
+
+static int inline
+xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
+{
+#ifdef CONFIG_XFRM_SUB_POLICY
+ struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+ return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
+#else
+ return 0;
+#endif
+}
static int stale_bundle(struct dst_entry *dst);
@@ -1518,6 +1566,18 @@ restart:
err = -EHOSTUNREACH;
goto error;
}
+
+ if (npols > 1)
+ err = xfrm_dst_update_parent(dst, &pols[1]->selector);
+ else
+ err = xfrm_dst_update_origin(dst, fl);
+ if (unlikely(err)) {
+ write_unlock_bh(&policy->lock);
+ if (dst)
+ dst_free(dst);
+ goto error;
+ }
+
dst->next = policy->bundles;
policy->bundles = dst;
dst_hold(dst);
@@ -1933,6 +1993,15 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
(dst->dev && !netif_running(dst->dev)))
return 0;
+#ifdef CONFIG_XFRM_SUB_POLICY
+ if (fl) {
+ if (first->origin && !flow_cache_uli_match(first->origin, fl))
+ return 0;
+ if (first->partner &&
+ !xfrm_selector_match(first->partner, fl, family))
+ return 0;
+ }
+#endif
last = NULL;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f3a61ebd8d6..9955ff4da0a 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -421,7 +421,7 @@ restart:
}
EXPORT_SYMBOL(xfrm_state_flush);
-void xfrm_sad_getinfo(struct xfrm_sadinfo *si)
+void xfrm_sad_getinfo(struct xfrmk_sadinfo *si)
{
spin_lock_bh(&xfrm_state_lock);
si->sadcnt = xfrm_state_num;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 69110fed64b..b14c7e590c3 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -672,9 +672,66 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
return skb;
}
+static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
+{
+ struct xfrmk_spdinfo si;
+ struct xfrmu_spdinfo spc;
+ struct xfrmu_spdhinfo sph;
+ struct nlmsghdr *nlh;
+ u32 *f;
+
+ nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);
+ if (nlh == NULL) /* shouldnt really happen ... */
+ return -EMSGSIZE;
+
+ f = nlmsg_data(nlh);
+ *f = flags;
+ xfrm_spd_getinfo(&si);
+ spc.incnt = si.incnt;
+ spc.outcnt = si.outcnt;
+ spc.fwdcnt = si.fwdcnt;
+ spc.inscnt = si.inscnt;
+ spc.outscnt = si.outscnt;
+ spc.fwdscnt = si.fwdscnt;
+ sph.spdhcnt = si.spdhcnt;
+ sph.spdhmcnt = si.spdhmcnt;
+
+ NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);
+ NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);
+
+ return nlmsg_end(skb, nlh);
+
+nla_put_failure:
+ nlmsg_cancel(skb, nlh);
+ return -EMSGSIZE;
+}
+
+static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
+ struct rtattr **xfrma)
+{
+ struct sk_buff *r_skb;
+ u32 *flags = NLMSG_DATA(nlh);
+ u32 spid = NETLINK_CB(skb).pid;
+ u32 seq = nlh->nlmsg_seq;
+ int len = NLMSG_LENGTH(sizeof(u32));
+
+ len += RTA_SPACE(sizeof(struct xfrmu_spdinfo));
+ len += RTA_SPACE(sizeof(struct xfrmu_spdhinfo));
+
+ r_skb = alloc_skb(len, GFP_ATOMIC);
+ if (r_skb == NULL)
+ return -ENOMEM;
+
+ if (build_spdinfo(r_skb, spid, seq, *flags) < 0)
+ BUG();
+
+ return nlmsg_unicast(xfrm_nl, r_skb, spid);
+}
+
static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
{
- struct xfrm_sadinfo si;
+ struct xfrmk_sadinfo si;
+ struct xfrmu_sadhinfo sh;
struct nlmsghdr *nlh;
u32 *f;
@@ -686,12 +743,11 @@ static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags)
*f = flags;
xfrm_sad_getinfo(&si);
- if (flags & XFRM_SAD_HMASK)
- NLA_PUT_U32(skb, XFRMA_SADHMASK, si.sadhcnt);
- if (flags & XFRM_SAD_HMAX)
- NLA_PUT_U32(skb, XFRMA_SADHMAX, si.sadhmcnt);
- if (flags & XFRM_SAD_CNT)
- NLA_PUT_U32(skb, XFRMA_SADCNT, si.sadcnt);
+ sh.sadhmcnt = si.sadhmcnt;
+ sh.sadhcnt = si.sadhcnt;
+
+ NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt);
+ NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);
return nlmsg_end(skb, nlh);
@@ -709,12 +765,8 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,
u32 seq = nlh->nlmsg_seq;
int len = NLMSG_LENGTH(sizeof(u32));
- if (*flags & XFRM_SAD_HMASK)
- len += RTA_SPACE(sizeof(u32));
- if (*flags & XFRM_SAD_HMAX)
- len += RTA_SPACE(sizeof(u32));
- if (*flags & XFRM_SAD_CNT)
- len += RTA_SPACE(sizeof(u32));
+ len += RTA_SPACE(sizeof(struct xfrmu_sadhinfo));
+ len += RTA_SPACE(sizeof(u32));
r_skb = alloc_skb(len, GFP_ATOMIC);
@@ -1879,6 +1931,7 @@ static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = {
[XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report),
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id),
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
+ [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = NLMSG_LENGTH(sizeof(u32)),
};
#undef XMSGSIZE
@@ -1907,6 +1960,7 @@ static struct xfrm_link {
[XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae },
[XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate },
[XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo },
+ [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo },
};
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index e2ad2dccccd..a525112847f 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -131,13 +131,13 @@ $(multi-objs-y:.o=.lst) : modname = $(modname-multi)
quiet_cmd_cc_s_c = CC $(quiet_modtag) $@
cmd_cc_s_c = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<
-%.s: %.c FORCE
+$(obj)/%.s: $(src)/%.c FORCE
$(call if_changed_dep,cc_s_c)
quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@
cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $<
-%.i: %.c FORCE
+$(obj)/%.i: $(src)/%.c FORCE
$(call if_changed_dep,cc_i_c)
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
@@ -146,7 +146,7 @@ cmd_cc_symtypes_c = \
| $(GENKSYMS) -T $@ >/dev/null; \
test -s $@ || rm -f $@
-%.symtypes : %.c FORCE
+$(obj)/%.symtypes : $(src)/%.c FORCE
$(call if_changed_dep,cc_symtypes_c)
# C (.c) files
@@ -198,14 +198,13 @@ define rule_cc_o_c
endef
# Built-in and composite module parts
-
-%.o: %.c FORCE
+$(obj)/%.o: $(src)/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
# Single-part modules are special since we need to mark them in $(MODVERDIR)
-$(single-used-m): %.o: %.c FORCE
+$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
@{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
@@ -215,7 +214,7 @@ quiet_cmd_cc_lst_c = MKLST $@
$(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
System.map $(OBJDUMP) > $@
-%.lst: %.c FORCE
+$(obj)/%.lst: $(src)/%.c FORCE
$(call if_changed_dep,cc_lst_c)
# Compile assembler sources (.S)
@@ -229,13 +228,13 @@ $(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
cmd_as_s_S = $(CPP) $(a_flags) -o $@ $<
-%.s: %.S FORCE
+$(obj)/%.s: $(src)/%.S FORCE
$(call if_changed_dep,as_s_S)
quiet_cmd_as_o_S = AS $(quiet_modtag) $@
cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
-%.o: %.S FORCE
+$(obj)/%.o: $(src)/%.S FORCE
$(call if_changed_dep,as_o_S)
targets += $(real-objs-y) $(real-objs-m) $(lib-y)
@@ -246,7 +245,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(always)
quiet_cmd_cpp_lds_S = LDS $@
cmd_cpp_lds_S = $(CPP) $(cpp_flags) -D__ASSEMBLY__ -o $@ $<
-%.lds: %.lds.S FORCE
+$(obj)/%.lds: $(src)/%.lds.S FORCE
$(call if_changed_dep,cpp_lds_S)
# Build the compiled-in targets
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
index 575afbe5e37..6943a7a5bb9 100644
--- a/scripts/Makefile.host
+++ b/scripts/Makefile.host
@@ -114,7 +114,7 @@ hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags)
quiet_cmd_host-csingle = HOSTCC $@
cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-csingle): %: %.c FORCE
+$(host-csingle): $(obj)/%: $(src)/%.c FORCE
$(call if_changed_dep,host-csingle)
# Link an executable based on list of .o files, all plain c
@@ -123,14 +123,14 @@ quiet_cmd_host-cmulti = HOSTLD $@
cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
$(addprefix $(obj)/,$($(@F)-objs)) \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cmulti): %: $(host-cobjs) $(host-cshlib) FORCE
+$(host-cmulti): $(obj)/%: $(host-cobjs) $(host-cshlib) FORCE
$(call if_changed,host-cmulti)
# Create .o file from a single .c file
# host-cobjs -> .o
quiet_cmd_host-cobjs = HOSTCC $@
cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $<
-$(host-cobjs): %.o: %.c FORCE
+$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
$(call if_changed_dep,host-cobjs)
# Link an executable based on list of .o files, a mixture of .c and .cc
@@ -140,20 +140,20 @@ quiet_cmd_host-cxxmulti = HOSTLD $@
$(foreach o,objs cxxobjs,\
$(addprefix $(obj)/,$($(@F)-$(o)))) \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cxxmulti): %: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
+$(host-cxxmulti): $(obj)/%: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
$(call if_changed,host-cxxmulti)
# Create .o file from a single .cc (C++) file
quiet_cmd_host-cxxobjs = HOSTCXX $@
cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
-$(host-cxxobjs): %.o: %.cc FORCE
+$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
$(call if_changed_dep,host-cxxobjs)
# Compile .c file, create position independent .o file
# host-cshobjs -> .o
quiet_cmd_host-cshobjs = HOSTCC -fPIC $@
cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
-$(host-cshobjs): %.o: %.c FORCE
+$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
$(call if_changed_dep,host-cshobjs)
# Link a shared library, based on position independent .o files
@@ -162,7 +162,7 @@ quiet_cmd_host-cshlib = HOSTLLD -shared $@
cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
$(addprefix $(obj)/,$($(@F:.so=-objs))) \
$(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
-$(host-cshlib): %: $(host-cshobjs) FORCE
+$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
$(call if_changed,host-cshlib)
targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 65e0a79c36c..d5bbbcce31e 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -63,16 +63,16 @@ quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
- $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
- $(wildcard vmlinux) $(filter-out FORCE,$^)
+ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w)
PHONY += __modpost
__modpost: $(modules:.ko=.o) FORCE
- $(call cmd,modpost)
+ $(call cmd,modpost) $(wildcard vmlinux) $(filter-out FORCE,$^)
quiet_cmd_kernel-mod = MODPOST $@
- cmd_kernel-mod = $(cmd_modpost)
+ cmd_kernel-mod = $(cmd_modpost) $(KBUILD_VMLINUX_OBJS)
+PHONY += vmlinux
vmlinux: FORCE
$(call cmd,kernel-mod)
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index d6071cbf13d..f4d2f68452b 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -211,7 +211,7 @@ void find_export_symbols(char * filename)
* Document all external or internal functions in a file.
* Call kernel-doc with following parameters:
* kernel-doc -docbook -nofunction function_name1 filename
- * function names are obtained from all the the src files
+ * function names are obtained from all the src files
* by find_export_symbols.
* intfunc uses -nofunction
* extfunc uses -function
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 6bc7e7cfccf..8912c0f5460 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -249,6 +249,8 @@ void parse_config_file(char *map, size_t len)
found:
if (!memcmp(q - 7, "_MODULE", 7))
q -= 7;
+ if( (q-p-7) < 0 )
+ continue;
use_config(p+7, q-p-7);
}
}
diff --git a/scripts/checksyscalls.sh b/scripts/checksyscalls.sh
new file mode 100755
index 00000000000..f98171f5a3d
--- /dev/null
+++ b/scripts/checksyscalls.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+#
+# Check if current architecture are missing any function calls compared
+# to i386.
+# i386 define a number of legacy system calls that are i386 specific
+# and listed below so they are ignored.
+#
+# Usage:
+# syscallchk gcc gcc-options
+#
+
+ignore_list() {
+cat << EOF
+#include <asm/types.h>
+#include <asm/unistd.h>
+
+/* System calls for 32-bit kernels only */
+#if BITS_PER_LONG == 64
+#define __IGNORE_sendfile64
+#define __IGNORE_ftruncate64
+#define __IGNORE_truncate64
+#define __IGNORE_stat64
+#define __IGNORE_lstat64
+#define __IGNORE_fstat64
+#define __IGNORE_fcntl64
+#define __IGNORE_fadvise64_64
+#define __IGNORE_fstatat64
+#define __IGNORE_fstatfs64
+#define __IGNORE_statfs64
+#endif
+
+/* i386-specific or historical system calls */
+#define __IGNORE_break
+#define __IGNORE_stty
+#define __IGNORE_gtty
+#define __IGNORE_ftime
+#define __IGNORE_prof
+#define __IGNORE_lock
+#define __IGNORE_mpx
+#define __IGNORE_ulimit
+#define __IGNORE_profil
+#define __IGNORE_ioperm
+#define __IGNORE_iopl
+#define __IGNORE_idle
+#define __IGNORE_modify_ldt
+#define __IGNORE_ugetrlimit
+#define __IGNORE_mmap2
+#define __IGNORE_vm86
+#define __IGNORE_vm86old
+#define __IGNORE_set_thread_area
+#define __IGNORE_get_thread_area
+#define __IGNORE_madvise1
+#define __IGNORE_oldstat
+#define __IGNORE_oldfstat
+#define __IGNORE_oldlstat
+#define __IGNORE_oldolduname
+#define __IGNORE_olduname
+#define __IGNORE_umount2
+#define __IGNORE_umount
+#define __IGNORE_waitpid
+#define __IGNORE_stime
+#define __IGNORE_nice
+#define __IGNORE_signal
+#define __IGNORE_sigaction
+#define __IGNORE_sgetmask
+#define __IGNORE_sigsuspend
+#define __IGNORE_sigpending
+#define __IGNORE_ssetmask
+#define __IGNORE_readdir
+#define __IGNORE_socketcall
+#define __IGNORE_ipc
+#define __IGNORE_sigreturn
+#define __IGNORE_sigprocmask
+#define __IGNORE_bdflush
+#define __IGNORE__llseek
+#define __IGNORE__newselect
+#define __IGNORE_create_module
+#define __IGNORE_delete_module
+#define __IGNORE_query_module
+#define __IGNORE_get_kernel_syms
+/* ... including the "new" 32-bit uid syscalls */
+#define __IGNORE_lchown32
+#define __IGNORE_getuid32
+#define __IGNORE_getgid32
+#define __IGNORE_geteuid32
+#define __IGNORE_getegid32
+#define __IGNORE_setreuid32
+#define __IGNORE_setregid32
+#define __IGNORE_getgroups32
+#define __IGNORE_setgroups32
+#define __IGNORE_fchown32
+#define __IGNORE_setresuid32
+#define __IGNORE_getresuid32
+#define __IGNORE_setresgid32
+#define __IGNORE_getresgid32
+#define __IGNORE_chown32
+#define __IGNORE_setuid32
+#define __IGNORE_setgid32
+#define __IGNORE_setfsuid32
+#define __IGNORE_setfsgid32
+
+/* Unmerged syscalls for AFS, STREAMS, etc. */
+#define __IGNORE_afs_syscall
+#define __IGNORE_getpmsg
+#define __IGNORE_putpmsg
+#define __IGNORE_vserver
+EOF
+}
+
+syscall_list() {
+sed -n -e '/^\#define/ { s/[^_]*__NR_\([^[:space:]]*\).*/\
+\#if !defined \(__NR_\1\) \&\& !defined \(__IGNORE_\1\)\
+\#warning syscall \1 not implemented\
+\#endif/p }' $1
+}
+
+(ignore_list && syscall_list ${srctree}/include/asm-i386/unistd.h) | \
+$* -E -x c - > /dev/null
diff --git a/scripts/cleanfile b/scripts/cleanfile
new file mode 100755
index 00000000000..f1ba8aa58a4
--- /dev/null
+++ b/scripts/cleanfile
@@ -0,0 +1,126 @@
+#!/usr/bin/perl -w
+#
+# Clean a text file -- or directory of text files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation. Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+#
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+ no bytes; # Tab alignment depends on characters
+
+ my($li) = @_;
+ my($lo) = '';
+ my $pos = 0;
+ my $nsp = 0;
+ my($i, $c);
+
+ for ($i = 0; $i < length($li); $i++) {
+ $c = substr($li, $i, 1);
+ if ($c eq "\t") {
+ my $npos = ($pos+$nsp+8) & ~7;
+ my $ntab = ($npos >> 3) - ($pos >> 3);
+ $lo .= "\t" x $ntab;
+ $pos = $npos;
+ $nsp = 0;
+ } elsif ($c eq "\n" || $c eq "\r") {
+ $lo .= " " x $nsp;
+ $pos += $nsp;
+ $nsp = 0;
+ $lo .= $c;
+ $pos = 0;
+ } elsif ($c eq " ") {
+ $nsp++;
+ } else {
+ $lo .= " " x $nsp;
+ $pos += $nsp;
+ $nsp = 0;
+ $lo .= $c;
+ $pos++;
+ }
+ }
+ $lo .= " " x $nsp;
+ return $lo;
+}
+
+$name = basename($0);
+
+foreach $f ( @ARGV ) {
+ print STDERR "$name: $f\n";
+
+ if (! -f $f) {
+ print STDERR "$f: not a file\n";
+ next;
+ }
+
+ if (!open(FILE, '+<', $f)) {
+ print STDERR "$name: Cannot open file: $f: $!\n";
+ next;
+ }
+
+ binmode FILE;
+
+ # First, verify that it is not a binary file; consider any file
+ # with a zero byte to be a binary file. Is there any better, or
+ # additional, heuristic that should be applied?
+ $is_binary = 0;
+
+ while (read(FILE, $data, 65536) > 0) {
+ if ($data =~ /\0/) {
+ $is_binary = 1;
+ last;
+ }
+ }
+
+ if ($is_binary) {
+ print STDERR "$name: $f: binary file\n";
+ next;
+ }
+
+ seek(FILE, 0, 0);
+
+ $in_bytes = 0;
+ $out_bytes = 0;
+ $blank_bytes = 0;
+
+ @blanks = ();
+ @lines = ();
+
+ while ( defined($line = <FILE>) ) {
+ $in_bytes += length($line);
+ $line =~ s/[ \t\r]*$//; # Remove trailing spaces
+ $line = clean_space_tabs($line);
+
+ if ( $line eq "\n" ) {
+ push(@blanks, $line);
+ $blank_bytes += length($line);
+ } else {
+ push(@lines, @blanks);
+ $out_bytes += $blank_bytes;
+ push(@lines, $line);
+ $out_bytes += length($line);
+ @blanks = ();
+ $blank_bytes = 0;
+ }
+ }
+
+ # Any blanks at the end of the file are discarded
+
+ if ($in_bytes != $out_bytes) {
+ # Only write to the file if changed
+ seek(FILE, 0, 0);
+ print FILE @lines;
+
+ if ( !defined($where = tell(FILE)) ||
+ !truncate(FILE, $where) ) {
+ die "$name: Failed to truncate modified file: $f: $!\n";
+ }
+ }
+
+ close(FILE);
+}
diff --git a/scripts/cleanpatch b/scripts/cleanpatch
new file mode 100755
index 00000000000..a53f987708f
--- /dev/null
+++ b/scripts/cleanpatch
@@ -0,0 +1,206 @@
+#!/usr/bin/perl -w
+#
+# Clean a patch file -- or directory of patch files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation. Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+#
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+ no bytes; # Tab alignment depends on characters
+
+ my($li) = @_;
+ my($lo) = '';
+ my $pos = 0;
+ my $nsp = 0;
+ my($i, $c);
+
+ for ($i = 0; $i < length($li); $i++) {
+ $c = substr($li, $i, 1);
+ if ($c eq "\t") {
+ my $npos = ($pos+$nsp+8) & ~7;
+ my $ntab = ($npos >> 3) - ($pos >> 3);
+ $lo .= "\t" x $ntab;
+ $pos = $npos;
+ $nsp = 0;
+ } elsif ($c eq "\n" || $c eq "\r") {
+ $lo .= " " x $nsp;
+ $pos += $nsp;
+ $nsp = 0;
+ $lo .= $c;
+ $pos = 0;
+ } elsif ($c eq " ") {
+ $nsp++;
+ } else {
+ $lo .= " " x $nsp;
+ $pos += $nsp;
+ $nsp = 0;
+ $lo .= $c;
+ $pos++;
+ }
+ }
+ $lo .= " " x $nsp;
+ return $lo;
+}
+
+$name = basename($0);
+
+foreach $f ( @ARGV ) {
+ print STDERR "$name: $f\n";
+
+ if (! -f $f) {
+ print STDERR "$f: not a file\n";
+ next;
+ }
+
+ if (!open(FILE, '+<', $f)) {
+ print STDERR "$name: Cannot open file: $f: $!\n";
+ next;
+ }
+
+ binmode FILE;
+
+ # First, verify that it is not a binary file; consider any file
+ # with a zero byte to be a binary file. Is there any better, or
+ # additional, heuristic that should be applied?
+ $is_binary = 0;
+
+ while (read(FILE, $data, 65536) > 0) {
+ if ($data =~ /\0/) {
+ $is_binary = 1;
+ last;
+ }
+ }
+
+ if ($is_binary) {
+ print STDERR "$name: $f: binary file\n";
+ next;
+ }
+
+ seek(FILE, 0, 0);
+
+ $in_bytes = 0;
+ $out_bytes = 0;
+
+ @lines = ();
+
+ $in_hunk = 0;
+ $err = 0;
+
+ while ( defined($line = <FILE>) ) {
+ $in_bytes += length($line);
+
+ if (!$in_hunk) {
+ if ($line =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
+ $minus_lines = $2;
+ $plus_lines = $4;
+ if ($minus_lines || $plus_lines) {
+ $in_hunk = 1;
+ @hunk_lines = ($line);
+ }
+ } else {
+ push(@lines, $line);
+ $out_bytes += length($line);
+ }
+ } else {
+ # We're in a hunk
+
+ if ($line =~ /^\+/) {
+ $plus_lines--;
+
+ $text = substr($line, 1);
+ $text =~ s/[ \t\r]*$//; # Remove trailing spaces
+ $text = clean_space_tabs($text);
+
+ push(@hunk_lines, '+'.$text);
+ } elsif ($line =~ /^\-/) {
+ $minus_lines--;
+ push(@hunk_lines, $line);
+ } elsif ($line =~ /^ /) {
+ $plus_lines--;
+ $minus_lines--;
+ push(@hunk_lines, $line);
+ } else {
+ print STDERR "$name: $f: malformed patch\n";
+ $err = 1;
+ last;
+ }
+
+ if ($plus_lines < 0 || $minus_lines < 0) {
+ print STDERR "$name: $f: malformed patch\n";
+ $err = 1;
+ last;
+ } elsif ($plus_lines == 0 && $minus_lines == 0) {
+ # End of a hunk. Process this hunk.
+ my $i;
+ my $l;
+ my @h = ();
+ my $adj = 0;
+ my $done = 0;
+
+ for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
+ $l = $hunk_lines[$i];
+ if (!$done && $l eq "+\n") {
+ $adj++; # Skip this line
+ } elsif ($l =~ /^[ +]/) {
+ $done = 1;
+ unshift(@h, $l);
+ } else {
+ unshift(@h, $l);
+ }
+ }
+
+ $l = $hunk_lines[0]; # Hunk header
+ undef @hunk_lines; # Free memory
+
+ if ($adj) {
+ die unless
+ ($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
+ my $mstart = $1;
+ my $mlin = $2;
+ my $pstart = $3;
+ my $plin = $4;
+ my $tail = $5; # doesn't include the final newline
+
+ $l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
+ $mstart, $mlin, $pstart, $plin-$adj,
+ $tail);
+ }
+ unshift(@h, $l);
+
+ # Transfer to the output array
+ foreach $l (@h) {
+ $out_bytes += length($l);
+ push(@lines, $l);
+ }
+
+ $in_hunk = 0;
+ }
+ }
+ }
+
+ if ($in_hunk) {
+ print STDERR "$name: $f: malformed patch\n";
+ $err = 1;
+ }
+
+ if (!$err) {
+ if ($in_bytes != $out_bytes) {
+ # Only write to the file if changed
+ seek(FILE, 0, 0);
+ print FILE @lines;
+
+ if ( !defined($where = tell(FILE)) ||
+ !truncate(FILE, $where) ) {
+ die "$name: Failed to truncate modified file: $f: $!\n";
+ }
+ }
+ }
+
+ close(FILE);
+}
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 43f75d6e4d9..683eb12babb 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -171,7 +171,7 @@ dir_filelist() {
${dep_list}header "$1"
srcdir=$(echo "$1" | sed -e 's://*:/:g')
- dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null)
+ dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n")
# If $dirlist is only one line, then the directory is empty
if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
@@ -191,9 +191,10 @@ input_file() {
source="$1"
if [ -f "$1" ]; then
${dep_list}header "$1"
- is_cpio="$(echo "$1" | sed 's/^.*\.cpio/cpio/')"
+ is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then
cpio_file=$1
+ echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
[ ! -z ${dep_list} ] && echo "$1"
return 0
fi
@@ -223,6 +224,7 @@ cpio_file=
cpio_list=
output="/dev/stdout"
output_file=""
+is_cpio_compressed=
arg="$1"
case "$arg" in
@@ -282,7 +284,11 @@ if [ ! -z ${output_file} ]; then
cpio_tfile=${cpio_file}
fi
rm ${cpio_list}
- cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
+ if [ "${is_cpio_compressed}" = "compressed" ]; then
+ cat ${cpio_tfile} > ${output_file}
+ else
+ cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
+ fi
[ -z ${cpio_file} ] && rm ${cpio_tfile}
fi
exit 0
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index b0381823e40..511023b430a 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -516,7 +516,8 @@ int main(int argc, char **argv)
genksyms_usage();
return 1;
}
- if ((strcmp(arch, "v850") == 0) || (strcmp(arch, "h8300") == 0))
+ if ((strcmp(arch, "v850") == 0) || (strcmp(arch, "h8300") == 0)
+ || (strcmp(arch, "blackfin") == 0))
mod_prefix = "_";
{
extern int yydebug;
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 7e7e147875b..fb2bb3099dd 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -140,6 +140,7 @@ endif
clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
.tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
+clean-files += mconf qconf gconf
# Needed for systems without gettext
KBUILD_HAVE_NLS := $(shell \
@@ -183,8 +184,8 @@ $(obj)/.tmp_qtcheck:
done; \
if [ -z "$$dir" ]; then \
echo "*"; \
- echo "* Unable to find the QT installation. Please make sure that"; \
- echo "* the QT development package is correctly installed and"; \
+ echo "* Unable to find the QT3 installation. Please make sure that"; \
+ echo "* the QT3 development package is correctly installed and"; \
echo "* either install pkg-config or set the QTDIR environment"; \
echo "* variable to the correct location."; \
echo "*"; \
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 124b341a18c..1199baf866c 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -558,6 +558,7 @@ int main(int ac, char **av)
if (stat(".config", &tmpstat)) {
printf(_("***\n"
"*** You have not yet configured your kernel!\n"
+ "*** (missing kernel .config file)\n"
"***\n"
"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
"*** \"make menuconfig\" or \"make xconfig\").\n"
diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped
index 800f8c71c40..0fdc9049296 100644
--- a/scripts/kconfig/lex.zconf.c_shipped
+++ b/scripts/kconfig/lex.zconf.c_shipped
@@ -2264,7 +2264,7 @@ FILE *zconf_fopen(const char *name)
FILE *f;
f = fopen(name, "r");
- if (!f && name[0] != '/') {
+ if (!f && name != NULL && name[0] != '/') {
env = getenv(SRCTREE);
if (env) {
sprintf(fullname, "%s/%s", env, name);
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index 9b2706a4154..8a07ee4f6bd 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -64,6 +64,7 @@ int zconf_lineno(void);
char *zconf_curname(void);
/* confdata.c */
+const char *conf_get_configname(void);
char *conf_get_default_confname(void);
void sym_set_change_count(int count);
void sym_add_change_count(int count);
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index fd695e1070f..7e17eba75ae 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -188,6 +188,7 @@ int on_key_esc(WINDOW *win);
int on_key_resize(void);
void init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
void reset_dialog(void);
void end_dialog(void);
void attr_clear(WINDOW * win, int height, int width, chtype attr);
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index d54440fc166..a1bddefe73d 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -272,6 +272,11 @@ void init_dialog(const char *backtitle)
color_setup(getenv("MENUCONFIG_COLOR"));
}
+void set_dialog_backtitle(const char *backtitle)
+{
+ dlg.backtitle = backtitle;
+}
+
void reset_dialog(void)
{
initscr(); /* Init curses */
@@ -336,7 +341,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
newl = 1;
word = tempstr;
while (word && *word) {
- sp = index(word, ' ');
+ sp = strchr(word, ' ');
if (sp)
*sp++ = 0;
@@ -348,7 +353,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
if (wlen > room ||
(newl && wlen < 4 && sp
&& wlen + 1 + strlen(sp) > room
- && (!(sp2 = index(sp, ' '))
+ && (!(sp2 = strchr(sp, ' '))
|| wlen + 1 + (sp2 - sp) > room))) {
cur_y++;
cur_x = x;
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 3f9a1321b3e..d0e4fa594fc 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -26,7 +26,6 @@
#include "lkc.h"
#include "lxdialog/dialog.h"
-static char menu_backtitle[128];
static const char mconf_readme[] = N_(
"Overview\n"
"--------\n"
@@ -271,7 +270,6 @@ search_help[] = N_(
" USB$ => find all CONFIG_ symbols ending with USB\n"
"\n");
-static char filename[PATH_MAX+1] = ".config";
static int indent;
static struct termios ios_org;
static int rows = 0, cols = 0;
@@ -395,6 +393,28 @@ static struct gstr get_relations_str(struct symbol **sym_arr)
return res;
}
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
+{
+ static char menu_backtitle[PATH_MAX+128];
+ int size;
+ struct symbol *sym;
+
+ sym = sym_lookup("KERNELVERSION", 0);
+ sym_calc_value(sym);
+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+ _("%s - Linux Kernel v%s Configuration"),
+ config_filename, sym_get_string_value(sym));
+ if (size >= sizeof(menu_backtitle))
+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+ set_dialog_backtitle(menu_backtitle);
+
+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
+ if (size >= sizeof(filename))
+ filename[sizeof(filename)-1] = '\0';
+}
+
+
static void search_conf(void)
{
struct symbol **sym_arr;
@@ -816,8 +836,10 @@ static void conf_load(void)
case 0:
if (!dialog_input_result[0])
return;
- if (!conf_read(dialog_input_result))
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
return;
+ }
show_textbox(NULL, _("File does not exist!"), 5, 38);
break;
case 1:
@@ -840,8 +862,10 @@ static void conf_save(void)
case 0:
if (!dialog_input_result[0])
return;
- if (!conf_write(dialog_input_result))
+ if (!conf_write(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
return;
+ }
show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
break;
case 1:
@@ -860,7 +884,6 @@ static void conf_cleanup(void)
int main(int ac, char **av)
{
- struct symbol *sym;
char *mode;
int res;
@@ -871,11 +894,6 @@ int main(int ac, char **av)
conf_parse(av[1]);
conf_read(NULL);
- sym = sym_lookup("KERNELVERSION", 0);
- sym_calc_value(sym);
- sprintf(menu_backtitle, _("Linux Kernel v%s Configuration"),
- sym_get_string_value(sym));
-
mode = getenv("MENUCONFIG_MODE");
if (mode) {
if (!strcasecmp(mode, "single_menu"))
@@ -886,7 +904,8 @@ int main(int ac, char **av)
atexit(conf_cleanup);
init_wsize();
reset_dialog();
- init_dialog(menu_backtitle);
+ init_dialog(NULL);
+ set_config_filename(conf_get_configname());
do {
conf(&rootmenu);
dialog_clear();
@@ -903,7 +922,7 @@ int main(int ac, char **av)
switch (res) {
case 0:
- if (conf_write(NULL)) {
+ if (conf_write(filename)) {
fprintf(stderr, _("\n\n"
"Error during writing of the kernel configuration.\n"
"Your kernel configuration changes were NOT saved."
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index c86c27f2c76..f14aeac67d4 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -203,7 +203,7 @@ void sym_check_prop(struct symbol *sym)
else if (sym2->type == S_UNKNOWN)
prop_warn(prop,
"'select' used by config symbol '%s' "
- "refer to undefined symbol '%s'",
+ "refers to undefined symbol '%s'",
sym->name, sym2->name);
else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
prop_warn(prop,
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 512c2f5c341..f2a23a9c393 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1182,7 +1182,7 @@ void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
Parent::contentsContextMenuEvent(e);
}
-ConfigSearchWindow::ConfigSearchWindow(QWidget* parent, const char *name)
+ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
: Parent(parent, name), result(NULL)
{
setCaption("Search Config");
@@ -1206,6 +1206,9 @@ ConfigSearchWindow::ConfigSearchWindow(QWidget* parent, const char *name)
info = new ConfigInfoView(split, name);
connect(list->list, SIGNAL(menuChanged(struct menu *)),
info, SLOT(setInfo(struct menu *)));
+ connect(list->list, SIGNAL(menuChanged(struct menu *)),
+ parent, SLOT(setMenuLink(struct menu *)));
+
layout1->addWidget(split);
if (name) {
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index 6fc1c5f1442..b3b5657b6b3 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -279,7 +279,7 @@ class ConfigSearchWindow : public QDialog {
Q_OBJECT
typedef class QDialog Parent;
public:
- ConfigSearchWindow(QWidget* parent, const char *name = 0);
+ ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
public slots:
void saveSettings(void);
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 8f06c474d80..c35dcc5d618 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -786,13 +786,15 @@ static struct symbol *sym_check_expr_deps(struct expr *e)
return NULL;
}
+/* return NULL when dependencies are OK */
struct symbol *sym_check_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
if (sym->flags & SYMBOL_CHECK) {
- printf("Warning! Found recursive dependency: %s", sym->name);
+ fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
+ sym->prop->file->name, sym->prop->lineno, sym->name);
return sym;
}
if (sym->flags & SYMBOL_CHECKED)
@@ -816,13 +818,8 @@ struct symbol *sym_check_deps(struct symbol *sym)
goto out;
}
out:
- if (sym2) {
- printf(" %s", sym->name);
- if (sym2 == sym) {
- printf("\n");
- sym2 = NULL;
- }
- }
+ if (sym2)
+ fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": "");
sym->flags &= ~SYMBOL_CHECK;
return sym2;
}
diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
index cfa46077c6b..187d38ccadd 100644
--- a/scripts/kconfig/zconf.l
+++ b/scripts/kconfig/zconf.l
@@ -265,7 +265,7 @@ FILE *zconf_fopen(const char *name)
FILE *f;
f = fopen(name, "r");
- if (!f && name[0] != '/') {
+ if (!f && name != NULL && name[0] != '/') {
env = getenv(SRCTREE);
if (env) {
sprintf(fullname, "%s/%s", env, name);
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index d777fe85627..9a06b6771ee 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -2132,9 +2132,11 @@ void conf_parse(const char *name)
}
menu_finalize(&rootmenu);
for_all_symbols(i, sym) {
- sym_check_deps(sym);
+ if (sym_check_deps(sym))
+ zconfnerrs++;
}
-
+ if (zconfnerrs)
+ exit(1);
sym_set_change_count(1);
}
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 04a5864c03b..92eb02bdf9c 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -501,9 +501,11 @@ void conf_parse(const char *name)
}
menu_finalize(&rootmenu);
for_all_symbols(i, sym) {
- sym_check_deps(sym);
+ if (sym_check_deps(sym))
+ zconfnerrs++;
}
-
+ if (zconfnerrs)
+ exit(1);
sym_set_change_count(1);
}
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 8be269ffbf9..e5bf649e516 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -159,7 +159,8 @@ my $warnings = 0;
my $type_constant = '\%([-_\w]+)';
my $type_func = '(\w+)\(\)';
my $type_param = '\@(\w+)';
-my $type_struct = '\&((struct\s*)?[_\w]+)';
+my $type_struct = '\&((struct\s*)*[_\w]+)';
+my $type_struct_xml = '\\\amp;((struct\s*)*[_\w]+)';
my $type_env = '(\$\w+)';
# Output conversion substitutions.
@@ -168,7 +169,8 @@ my $type_env = '(\$\w+)';
# these work fairly well
my %highlights_html = ( $type_constant, "<i>\$1</i>",
$type_func, "<b>\$1</b>",
- $type_struct, "<i>\$1</i>",
+ $type_struct_xml, "<i>\$1</i>",
+ $type_env, "<b><i>\$1</i></b>",
$type_param, "<tt><b>\$1</b></tt>" );
my $blankline_html = "<p>";
@@ -326,12 +328,22 @@ while ($ARGV[0] =~ m/^-(.*)/) {
}
}
+# get kernel version from env
+sub get_kernel_version() {
+ my $version;
+
+ if (defined($ENV{'KERNELVERSION'})) {
+ $version = $ENV{'KERNELVERSION'};
+ }
+ return $version;
+}
+my $kernelversion = get_kernel_version();
# generate a sequence of code that will splice in highlighting information
# using the s// operator.
my $dohighlight = "";
foreach my $pattern (keys %highlights) {
-# print "scanning pattern $pattern ($highlights{$pattern})\n";
+# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n";
$dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
}
@@ -378,13 +390,19 @@ sub output_highlight {
# confess "output_highlight got called with no args?\n";
# }
+# print STDERR "contents b4:$contents\n";
eval $dohighlight;
die $@ if $@;
+ if ($output_mode eq "html") {
+ $contents =~ s/\\\\//;
+ }
+# print STDERR "contents af:$contents\n";
+
foreach $line (split "\n", $contents) {
- if ($line eq ""){
+ if ($line eq ""){
print $lineprefix, $blankline;
} else {
- $line =~ s/\\\\\\/\&/g;
+ $line =~ s/\\\\\\/\&/g;
print $lineprefix, $line;
}
print "\n";
@@ -414,7 +432,7 @@ sub output_enum_html(%) {
print "<b>enum ".$args{'enum'}."</b> {<br>\n";
$count = 0;
foreach $parameter (@{$args{'parameterlist'}}) {
- print " <b>".$parameter."</b>";
+ print " <b>".$parameter."</b>";
if ($count != $#{$args{'parameterlist'}}) {
$count++;
print ",\n";
@@ -462,15 +480,16 @@ sub output_struct_html(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
# pointer-to-function
- print " <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
+ print "&nbsp; &nbsp; <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
- print " <i>$1</i> <b>$parameter</b>$2;<br>\n";
+ # bitfield
+ print "&nbsp; &nbsp; <i>$1</i> <b>$parameter</b>$2;<br>\n";
} else {
- print " <i>$type</i> <b>$parameter</b>;<br>\n";
+ print "&nbsp; &nbsp; <i>$type</i> <b>$parameter</b>;<br>\n";
}
}
print "};<br>\n";
@@ -483,7 +502,7 @@ sub output_struct_html(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
print "<dt><b>".$parameter."</b>\n";
print "<dd>";
output_highlight($args{'parameterdescs'}{$parameter_name});
@@ -525,7 +544,7 @@ sub output_function_html(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
print "<dt><b>".$parameter."</b>\n";
print "<dd>";
output_highlight($args{'parameterdescs'}{$parameter_name});
@@ -592,6 +611,7 @@ sub output_function_xml(%) {
print "<refmeta>\n";
print " <refentrytitle><phrase>".$args{'function'}."</phrase></refentrytitle>\n";
print " <manvolnum>9</manvolnum>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
print " <refname>".$args{'function'}."</refname>\n";
@@ -668,6 +688,7 @@ sub output_struct_xml(%) {
print "<refmeta>\n";
print " <refentrytitle><phrase>".$args{'type'}." ".$args{'struct'}."</phrase></refentrytitle>\n";
print " <manvolnum>9</manvolnum>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
print " <refname>".$args{'type'}." ".$args{'struct'}."</refname>\n";
@@ -691,7 +712,7 @@ sub output_struct_xml(%) {
$parameter_name =~ s/\[.*//;
defined($args{'parameterdescs'}{$parameter_name}) || next;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
# pointer-to-function
@@ -752,6 +773,7 @@ sub output_enum_xml(%) {
print "<refmeta>\n";
print " <refentrytitle><phrase>enum ".$args{'enum'}."</phrase></refentrytitle>\n";
print " <manvolnum>9</manvolnum>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
print "</refmeta>\n";
print "<refnamediv>\n";
print " <refname>enum ".$args{'enum'}."</refname>\n";
@@ -767,11 +789,11 @@ sub output_enum_xml(%) {
print "enum ".$args{'enum'}." {\n";
$count = 0;
foreach $parameter (@{$args{'parameterlist'}}) {
- print " $parameter";
- if ($count != $#{$args{'parameterlist'}}) {
+ print " $parameter";
+ if ($count != $#{$args{'parameterlist'}}) {
$count++;
print ",";
- }
+ }
print "\n";
}
print "};";
@@ -1007,7 +1029,7 @@ sub output_enum_man(%) {
print "enum ".$args{'enum'}." {\n";
$count = 0;
foreach my $parameter (@{$args{'parameterlist'}}) {
- print ".br\n.BI \" $parameter\"\n";
+ print ".br\n.BI \" $parameter\"\n";
if ($count == $#{$args{'parameterlist'}}) {
print "\n};\n";
last;
@@ -1054,7 +1076,7 @@ sub output_struct_man(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
# pointer-to-function
@@ -1077,7 +1099,7 @@ sub output_struct_man(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
print ".IP \"".$parameter."\" 12\n";
output_highlight($args{'parameterdescs'}{$parameter_name});
}
@@ -1187,7 +1209,7 @@ sub output_enum_text(%) {
print "enum ".$args{'enum'}." {\n";
$count = 0;
foreach $parameter (@{$args{'parameterlist'}}) {
- print "\t$parameter";
+ print "\t$parameter";
if ($count != $#{$args{'parameterlist'}}) {
$count++;
print ",";
@@ -1232,7 +1254,7 @@ sub output_struct_text(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
$type = $args{'parametertypes'}{$parameter};
if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
# pointer-to-function
@@ -1252,7 +1274,7 @@ sub output_struct_text(%) {
my $parameter_name = $parameter;
$parameter_name =~ s/\[.*//;
- ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
print "$parameter\n\t";
print $args{'parameterdescs'}{$parameter_name}."\n";
}
@@ -1284,7 +1306,7 @@ sub output_declaration {
( $function_only == 1 && defined($function_table{$name})) ||
( $function_only == 2 && !defined($function_table{$name})))
{
- &$func(@_);
+ &$func(@_);
$section_counter++;
}
}
@@ -1317,8 +1339,8 @@ sub dump_struct($$) {
my $file = shift;
if ($x =~/(struct|union)\s+(\w+)\s*{(.*)}/) {
- $declaration_name = $2;
- my $members = $3;
+ $declaration_name = $2;
+ my $members = $3;
# ignore embedded structs or unions
$members =~ s/{.*?}//g;
@@ -1345,7 +1367,7 @@ sub dump_struct($$) {
});
}
else {
- print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
+ print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
++$errors;
}
}
@@ -1356,15 +1378,15 @@ sub dump_enum($$) {
$x =~ s@/\*.*?\*/@@gos; # strip comments.
if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
- $declaration_name = $1;
- my $members = $2;
+ $declaration_name = $1;
+ my $members = $2;
foreach my $arg (split ',', $members) {
$arg =~ s/^\s*(\w+).*/$1/;
push @parameterlist, $arg;
if (!$parameterdescs{$arg}) {
- $parameterdescs{$arg} = $undescribed;
- print STDERR "Warning(${file}:$.): Enum value '$arg' ".
+ $parameterdescs{$arg} = $undescribed;
+ print STDERR "Warning(${file}:$.): Enum value '$arg' ".
"not described in enum '$declaration_name'\n";
}
@@ -1382,7 +1404,7 @@ sub dump_enum($$) {
});
}
else {
- print STDERR "Error(${file}:$.): Cannot parse enum!\n";
+ print STDERR "Error(${file}:$.): Cannot parse enum!\n";
++$errors;
}
}
@@ -1393,12 +1415,12 @@ sub dump_typedef($$) {
$x =~ s@/\*.*?\*/@@gos; # strip comments.
while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
- $x =~ s/\(*.\)\s*;$/;/;
+ $x =~ s/\(*.\)\s*;$/;/;
$x =~ s/\[*.\]\s*;$/;/;
}
if ($x =~ /typedef.*\s+(\w+)\s*;/) {
- $declaration_name = $1;
+ $declaration_name = $1;
output_declaration($declaration_name,
'typedef',
@@ -1410,7 +1432,7 @@ sub dump_typedef($$) {
});
}
else {
- print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
+ print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
++$errors;
}
}
@@ -1424,14 +1446,14 @@ sub create_parameterlist($$$) {
# temporarily replace commas inside function pointer definition
while ($args =~ /(\([^\),]+),/) {
- $args =~ s/(\([^\),]+),/$1#/g;
+ $args =~ s/(\([^\),]+),/$1#/g;
}
foreach my $arg (split($splitter, $args)) {
# strip comments
$arg =~ s/\/\*.*\*\///;
- # strip leading/trailing spaces
- $arg =~ s/^\s*//;
+ # strip leading/trailing spaces
+ $arg =~ s/^\s*//;
$arg =~ s/\s*$//;
$arg =~ s/\s+/ /;
@@ -1456,7 +1478,16 @@ sub create_parameterlist($$$) {
if ($args[0] =~ m/\*/) {
$args[0] =~ s/(\*+)\s*/ $1/;
}
- my @first_arg = split('\s+', shift @args);
+
+ my @first_arg;
+ if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) {
+ shift @args;
+ push(@first_arg, split('\s+', $1));
+ push(@first_arg, $2);
+ } else {
+ @first_arg = split('\s+', shift @args);
+ }
+
unshift(@args, pop @first_arg);
$type = join " ", @first_arg;
@@ -1514,15 +1545,15 @@ sub push_parameter($$$) {
$parameterdescs{$param_name} = $undescribed;
if (($type eq 'function') || ($type eq 'enum')) {
- print STDERR "Warning(${file}:$.): Function parameter ".
+ print STDERR "Warning(${file}:$.): Function parameter ".
"or member '$param' not " .
"described in '$declaration_name'\n";
}
print STDERR "Warning(${file}:$.):".
- " No description found for parameter '$param'\n";
+ " No description found for parameter '$param'\n";
++$warnings;
- }
- }
+ }
+ }
push @parameterlist, $param;
$parametertypes{$param} = $type;
@@ -1664,10 +1695,10 @@ sub process_state3_function($$) {
# do nothing
}
elsif ($x =~ /([^\{]*)/) {
- $prototype .= $1;
+ $prototype .= $1;
}
if (($x =~ /\{/) || ($x =~ /\#define/) || ($x =~ /;/)) {
- $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
+ $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
$prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
$prototype =~ s@^\s+@@gos; # strip leading spaces
dump_function($prototype,$file);
@@ -1688,17 +1719,17 @@ sub process_state3_type($$) {
}
while (1) {
- if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
+ if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
$prototype .= $1 . $2;
($2 eq '{') && $brcount++;
($2 eq '}') && $brcount--;
if (($2 eq ';') && ($brcount == 0)) {
- dump_declaration($prototype,$file);
+ dump_declaration($prototype,$file);
reset_state();
- last;
+ last;
}
$x = $3;
- } else {
+ } else {
$prototype .= $x;
last;
}
@@ -1756,7 +1787,7 @@ sub process_file($) {
} else {
$section = $1;
}
- }
+ }
elsif (/$doc_decl/o) {
$identifier = $1;
if (/\s*([\w\s]+?)\s*-/) {
@@ -1849,13 +1880,13 @@ sub process_file($) {
}
} elsif ($state == 3) { # scanning for function '{' (end of prototype)
if ($decl_type eq 'function') {
- process_state3_function($_, $file);
+ process_state3_function($_, $file);
} else {
- process_state3_type($_, $file);
+ process_state3_type($_, $file);
}
} elsif ($state == 4) {
# Documentation block
- if (/$doc_block/) {
+ if (/$doc_block/) {
dump_section($section, $contents);
output_intro({'sectionlist' => \@sectionlist,
'sections' => \%sections });
@@ -1873,7 +1904,7 @@ sub process_file($) {
} else {
$section = $1;
}
- }
+ }
elsif (/$doc_end/)
{
dump_section($section, $contents);
@@ -1900,8 +1931,8 @@ sub process_file($) {
{
$contents .= $1 . "\n";
}
- }
- }
+ }
+ }
}
if ($initial_section_counter == $section_counter) {
print STDERR "Warning(${file}): no structured comments found\n";
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index 82d0af46f0e..a8740df07b0 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -18,19 +18,32 @@ fi
# Do not expand names
set -f
-if [ -r .version ]; then
- VERSION=`cat .version`
+# Fix the language to get consistent output
+LC_ALL=C
+export LC_ALL
+
+if [ -z "$KBUILD_BUILD_VERSION" ]; then
+ if [ -r .version ]; then
+ VERSION=`cat .version`
+ else
+ VERSION=0
+ echo 0 > .version
+ fi
else
- VERSION=0
- echo 0 > .version
+ VERSION=$KBUILD_BUILD_VERSION
fi
+if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then
+ TIMESTAMP=`date`
+else
+ TIMESTAMP=$KBUILD_BUILD_TIMESTAMP
+fi
UTS_VERSION="#$VERSION"
CONFIG_FLAGS=""
if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi
if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi
-UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS `LC_ALL=C LANG=C date`"
+UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP"
# Truncate to maximum length
@@ -46,7 +59,7 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
- echo \#define LINUX_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\"
+ echo \#define LINUX_COMPILE_TIME \"`date +%T`\"
echo \#define LINUX_COMPILE_BY \"`whoami`\"
echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
@@ -58,7 +71,7 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
echo \#define LINUX_COMPILE_DOMAIN
fi
- echo \#define LINUX_COMPILER \"`LC_ALL=C LANG=C $CC -v 2>&1 | tail -n 1`\"
+ echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
) > .tmpcompile
# Only replace the real compile.h if the new one is different,
diff --git a/scripts/mkuboot.sh b/scripts/mkuboot.sh
index 4b06c5eea72..2e3d3cd916b 100755
--- a/scripts/mkuboot.sh
+++ b/scripts/mkuboot.sh
@@ -4,7 +4,7 @@
# Build U-Boot image when `mkimage' tool is available.
#
-MKIMAGE=$(type -path ${CROSS_COMPILE}mkimage)
+MKIMAGE=$(type -path "${CROSS_COMPILE}mkimage")
if [ -z "${MKIMAGE}" ]; then
MKIMAGE=$(type -path mkimage)
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index b2f73ffb40b..ed1244dd58d 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -37,7 +37,6 @@ typedef unsigned char __u8;
* even potentially has different endianness and word sizes, since
* we handle those differences explicitly below */
#include "../../include/linux/mod_devicetable.h"
-#include "../../include/linux/input.h"
#define ADD(str, sep, cond, field) \
do { \
@@ -416,31 +415,33 @@ static int do_input_entry(const char *filename, struct input_device_id *id,
sprintf(alias + strlen(alias), "-e*");
if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT)
- do_input(alias, id->evbit, 0, EV_MAX);
+ do_input(alias, id->evbit, 0, INPUT_DEVICE_ID_EV_MAX);
sprintf(alias + strlen(alias), "k*");
if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT)
- do_input(alias, id->keybit, KEY_MIN_INTERESTING, KEY_MAX);
+ do_input(alias, id->keybit,
+ INPUT_DEVICE_ID_KEY_MIN_INTERESTING,
+ INPUT_DEVICE_ID_KEY_MAX);
sprintf(alias + strlen(alias), "r*");
if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT)
- do_input(alias, id->relbit, 0, REL_MAX);
+ do_input(alias, id->relbit, 0, INPUT_DEVICE_ID_REL_MAX);
sprintf(alias + strlen(alias), "a*");
if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT)
- do_input(alias, id->absbit, 0, ABS_MAX);
+ do_input(alias, id->absbit, 0, INPUT_DEVICE_ID_ABS_MAX);
sprintf(alias + strlen(alias), "m*");
if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT)
- do_input(alias, id->mscbit, 0, MSC_MAX);
+ do_input(alias, id->mscbit, 0, INPUT_DEVICE_ID_MSC_MAX);
sprintf(alias + strlen(alias), "l*");
if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT)
- do_input(alias, id->ledbit, 0, LED_MAX);
+ do_input(alias, id->ledbit, 0, INPUT_DEVICE_ID_LED_MAX);
sprintf(alias + strlen(alias), "s*");
if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT)
- do_input(alias, id->sndbit, 0, SND_MAX);
+ do_input(alias, id->sndbit, 0, INPUT_DEVICE_ID_SND_MAX);
sprintf(alias + strlen(alias), "f*");
if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT)
- do_input(alias, id->ffbit, 0, FF_MAX);
+ do_input(alias, id->ffbit, 0, INPUT_DEVICE_ID_FF_MAX);
sprintf(alias + strlen(alias), "w*");
if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT)
- do_input(alias, id->swbit, 0, SW_MAX);
+ do_input(alias, id->swbit, 0, INPUT_DEVICE_ID_SW_MAX);
return 1;
}
diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c
index 725d61c0fb4..db3881f14c2 100644
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -55,7 +55,8 @@ main(int argc, char **argv)
else
exit(1);
- if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0))
+ if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0)
+ || (strcmp(argv[1], "blackfin") == 0))
printf("#define MODULE_SYMBOL_PREFIX \"_\"\n");
else
printf("#define MODULE_SYMBOL_PREFIX \"\"\n");
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 65bdfdb5687..113dc77b9f6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -55,6 +55,17 @@ void warn(const char *fmt, ...)
va_end(arglist);
}
+void merror(const char *fmt, ...)
+{
+ va_list arglist;
+
+ fprintf(stderr, "ERROR: ");
+
+ va_start(arglist, fmt);
+ vfprintf(stderr, fmt, arglist);
+ va_end(arglist);
+}
+
static int is_vmlinux(const char *modname)
{
const char *myname;
@@ -333,10 +344,10 @@ void release_file(void *file, unsigned long size)
munmap(file, size);
}
-static void parse_elf(struct elf_info *info, const char *filename)
+static int parse_elf(struct elf_info *info, const char *filename)
{
unsigned int i;
- Elf_Ehdr *hdr = info->hdr;
+ Elf_Ehdr *hdr;
Elf_Shdr *sechdrs;
Elf_Sym *sym;
@@ -346,9 +357,18 @@ static void parse_elf(struct elf_info *info, const char *filename)
exit(1);
}
info->hdr = hdr;
- if (info->size < sizeof(*hdr))
- goto truncated;
-
+ if (info->size < sizeof(*hdr)) {
+ /* file too small, assume this is an empty .o file */
+ return 0;
+ }
+ /* Is this a valid ELF file? */
+ if ((hdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (hdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (hdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (hdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ /* Not an ELF file - silently ignore it */
+ return 0;
+ }
/* Fix endianness in ELF header */
hdr->e_shoff = TO_NATIVE(hdr->e_shoff);
hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
@@ -371,8 +391,10 @@ static void parse_elf(struct elf_info *info, const char *filename)
= (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
const char *secname;
- if (sechdrs[i].sh_offset > info->size)
- goto truncated;
+ if (sechdrs[i].sh_offset > info->size) {
+ fatal("%s is truncated. sechdrs[i].sh_offset=%u > sizeof(*hrd)=%ul\n", filename, (unsigned int)sechdrs[i].sh_offset, sizeof(*hdr));
+ return 0;
+ }
secname = secstrings + sechdrs[i].sh_name;
if (strcmp(secname, ".modinfo") == 0) {
info->modinfo = (void *)hdr + sechdrs[i].sh_offset;
@@ -407,10 +429,7 @@ static void parse_elf(struct elf_info *info, const char *filename)
sym->st_value = TO_NATIVE(sym->st_value);
sym->st_size = TO_NATIVE(sym->st_size);
}
- return;
-
- truncated:
- fatal("%s is truncated.\n", filename);
+ return 1;
}
static void parse_elf_finish(struct elf_info *info)
@@ -581,9 +600,17 @@ static int strrcmp(const char *s, const char *sub)
* the pattern is identified by:
* tosec = .init.text | .exit.text | .init.data
* fromsec = .data
- * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one
+ * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console
*
* Pattern 3:
+ * Whitelist all references from .pci_fixup* section to .init.text
+ * This is part of the PCI init when built-in
+ *
+ * Pattern 4:
+ * Whitelist all refereces from .text.head to .init.data
+ * Whitelist all refereces from .text.head to .init.text
+ *
+ * Pattern 5:
* Some symbols belong to init section but still it is ok to reference
* these from non-init sections as these symbols don't have any memory
* allocated for them and symbol address and value are same. So even
@@ -591,6 +618,40 @@ static int strrcmp(const char *s, const char *sub)
* For ex. symbols marking the init section boundaries.
* This pattern is identified by
* refsymname = __init_begin, _sinittext, _einittext
+ *
+ * Pattern 6:
+ * During the early init phase we have references from .init.text to
+ * .text we have an intended section mismatch - do not warn about it.
+ * See kernel_init() in init/main.c
+ * tosec = .init.text
+ * fromsec = .text
+ * atsym = kernel_init
+ *
+ * Pattern 7:
+ * Logos used in drivers/video/logo reside in __initdata but the
+ * funtion that references them are EXPORT_SYMBOL() so cannot be
+ * marker __init. So we whitelist them here.
+ * The pattern is:
+ * tosec = .init.data
+ * fromsec = .text*
+ * refsymname = logo_
+ *
+ * Pattern 8:
+ * Symbols contained in .paravirtprobe may safely reference .init.text.
+ * The pattern is:
+ * tosec = .init.text
+ * fromsec = .paravirtprobe
+ *
+ * Pattern 9:
+ * Some of functions are common code between boot time and hotplug
+ * time. The bootmem allocater is called only boot time in its
+ * functions. So it's ok to reference.
+ * tosec = .init.text
+ *
+ * Pattern 10:
+ * ia64 has machvec table for each platform. It is mixture of function
+ * pointer of .init.text and .text.
+ * fromsec = .machvec
**/
static int secref_whitelist(const char *modname, const char *tosec,
const char *fromsec, const char *atsym,
@@ -606,6 +667,7 @@ static int secref_whitelist(const char *modname, const char *tosec,
"_probe",
"_probe_one",
"_console",
+ "apic_es7000",
NULL
};
@@ -616,6 +678,12 @@ static int secref_whitelist(const char *modname, const char *tosec,
NULL
};
+ const char *pat4sym[] = {
+ "sparse_index_alloc",
+ "zone_wait_table_init",
+ NULL
+ };
+
/* Check for pattern 1 */
if (strcmp(tosec, ".init.data") != 0)
f1 = 0;
@@ -641,25 +709,50 @@ static int secref_whitelist(const char *modname, const char *tosec,
if (f1 && f2)
return 1;
- /* Whitelist all references from .pci_fixup section if vmlinux
- * Whitelist all refereces from .text.head to .init.data if vmlinux
- * Whitelist all refereces from .text.head to .init.text if vmlinux
- */
- if (is_vmlinux(modname)) {
- if ((strcmp(fromsec, ".pci_fixup") == 0) &&
- (strcmp(tosec, ".init.text") == 0))
+ /* Check for pattern 3 */
+ if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) &&
+ (strcmp(tosec, ".init.text") == 0))
+ return 1;
+
+ /* Check for pattern 4 */
+ if ((strcmp(fromsec, ".text.head") == 0) &&
+ ((strcmp(tosec, ".init.data") == 0) ||
+ (strcmp(tosec, ".init.text") == 0)))
+ return 1;
+
+ /* Check for pattern 5 */
+ for (s = pat3refsym; *s; s++)
+ if (strcmp(refsymname, *s) == 0)
+ return 1;
+
+ /* Check for pattern 6 */
+ if ((strcmp(tosec, ".init.text") == 0) &&
+ (strcmp(fromsec, ".text") == 0) &&
+ (strcmp(refsymname, "kernel_init") == 0))
return 1;
- if ((strcmp(fromsec, ".text.head") == 0) &&
- ((strcmp(tosec, ".init.data") == 0) ||
- (strcmp(tosec, ".init.text") == 0)))
+ /* Check for pattern 7 */
+ if ((strcmp(tosec, ".init.data") == 0) &&
+ (strncmp(fromsec, ".text", strlen(".text")) == 0) &&
+ (strncmp(refsymname, "logo_", strlen("logo_")) == 0))
return 1;
- /* Check for pattern 3 */
- for (s = pat3refsym; *s; s++)
- if (strcmp(refsymname, *s) == 0)
+ /* Check for pattern 8 */
+ if ((strcmp(tosec, ".init.text") == 0) &&
+ (strcmp(fromsec, ".paravirtprobe") == 0))
+ return 1;
+
+ /* Check for pattern 9 */
+ if ((strcmp(tosec, ".init.text") == 0) &&
+ (strcmp(fromsec, ".text") == 0))
+ for (s = pat4sym; *s; s++)
+ if (strcmp(atsym, *s) == 0)
return 1;
- }
+
+ /* Check for pattern 10 */
+ if (strcmp(fromsec, ".machvec") == 0)
+ return 1;
+
return 0;
}
@@ -1089,7 +1182,8 @@ static void read_symbols(char *modname)
struct elf_info info = { };
Elf_Sym *sym;
- parse_elf(&info, modname);
+ if (!parse_elf(&info, modname))
+ return;
mod = new_module(modname);
@@ -1249,6 +1343,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
" .exit = cleanup_module,\n"
"#endif\n");
+ buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
buf_printf(b, "};\n");
}
@@ -1264,9 +1359,14 @@ static int add_versions(struct buffer *b, struct module *mod)
exp = find_symbol(s->name);
if (!exp || exp->module == mod) {
if (have_vmlinux && !s->weak) {
- warn("\"%s\" [%s.ko] undefined!\n",
- s->name, mod->name);
- err = warn_unresolved ? 0 : 1;
+ if (warn_unresolved) {
+ warn("\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
+ } else {
+ merror("\"%s\" [%s.ko] undefined!\n",
+ s->name, mod->name);
+ err = 1;
+ }
}
continue;
}
@@ -1317,6 +1417,7 @@ static void add_depends(struct buffer *b, struct module *mod,
buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n");
buf_printf(b, "\"depends=");
for (s = mod->unres; s; s = s->next) {
+ const char *p;
if (!s->module)
continue;
@@ -1324,8 +1425,11 @@ static void add_depends(struct buffer *b, struct module *mod,
continue;
s->module->seen = 1;
- buf_printf(b, "%s%s", first ? "" : ",",
- strrchr(s->module->name, '/') + 1);
+ if ((p = strrchr(s->module->name, '/')) != NULL)
+ p++;
+ else
+ p = s->module->name;
+ buf_printf(b, "%s%s", first ? "" : ",", p);
first = 0;
}
buf_printf(b, "\";\n");
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index d398c61e55e..0858caa9c03 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -145,3 +145,4 @@ void release_file(void *file, unsigned long size);
void fatal(const char *fmt, ...);
void warn(const char *fmt, ...);
+void merror(const char *fmt, ...);
diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c
index 8a2875689e4..6873d5af80d 100644
--- a/scripts/mod/sumversion.c
+++ b/scripts/mod/sumversion.c
@@ -397,10 +397,9 @@ void get_src_version(const char *modname, char sum[], unsigned sumlen)
(int) strlen(basename) - 2, basename);
file = grab_file(filelist, &len);
- if (!file) {
- warn("could not find versions for %s\n", filelist);
+ if (!file)
+ /* not a module or .mod file missing - ignore */
return;
- }
sources = strchr(file, '\n');
if (!sources) {
diff --git a/security/capability.c b/security/capability.c
index b868e7eda5f..38296a00546 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -17,7 +17,6 @@
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
-#include <linux/smp_lock.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/ptrace.h>
diff --git a/security/commoncap.c b/security/commoncap.c
index 5a5ef5ca7ea..384379ede4f 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -17,7 +17,6 @@
#include <linux/mman.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
-#include <linux/smp_lock.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/ptrace.h>
diff --git a/security/inode.c b/security/inode.c
index d7ecf89fbc7..307211ac734 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -321,7 +321,7 @@ static int __init securityfs_init(void)
{
int retval;
- kset_set_kset_s(&security_subsys, kernel_subsys);
+ kobj_set_kset_s(&security_subsys, kernel_subsys);
retval = subsystem_register(&security_subsys);
if (retval)
return retval;
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 23b51047494..b32a459c068 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -137,7 +137,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
Examples:
For the Fedora Core 3 or 4 Linux distributions, enable this option
- and set the value via the next option. For Fedore Core 5 and later,
+ and set the value via the next option. For Fedora Core 5 and later,
do not enable this option.
If you are unsure how to answer this question, answer N.
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 885a9a958b8..ad8dd4e8657 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -35,7 +35,6 @@
#include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/swap.h>
-#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/file.h>
@@ -1758,12 +1757,11 @@ static inline void flush_unauthorized_files(struct files_struct * files)
}
}
file_list_unlock();
-
- /* Reset controlling tty. */
- if (drop_tty)
- proc_set_tty(current, NULL);
}
mutex_unlock(&tty_mutex);
+ /* Reset controlling tty. */
+ if (drop_tty)
+ no_tty();
/* Revalidate access to inherited open files. */
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index b00fc4842c9..e91f9f66f39 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -1061,10 +1061,10 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter)
busnode = pmac_i2c_get_bus_node(bus);
while ((dev = of_get_next_child(busnode, dev)) != NULL) {
- if (device_is_compatible(dev, "pcm3052")) {
- u32 *addr;
+ if (of_device_is_compatible(dev, "pcm3052")) {
+ const u32 *addr;
printk(KERN_DEBUG PFX "found pcm3052\n");
- addr = (u32 *) get_property(dev, "reg", NULL);
+ addr = of_get_property(dev, "reg", NULL);
if (!addr)
return -ENODEV;
return onyx_create(adapter, dev, (*addr)>>1);
@@ -1074,7 +1074,7 @@ static int onyx_i2c_attach(struct i2c_adapter *adapter)
/* if that didn't work, try desperate mode for older
* machines that have stuff missing from the device tree */
- if (!device_is_compatible(busnode, "k2-i2c"))
+ if (!of_device_is_compatible(busnode, "k2-i2c"))
return -ENODEV;
printk(KERN_DEBUG PFX "found k2-i2c, checking if onyx chip is on it\n");
diff --git a/sound/aoa/codecs/snd-aoa-codec-tas.c b/sound/aoa/codecs/snd-aoa-codec-tas.c
index 2cd81fa07ce..041fe52cbf2 100644
--- a/sound/aoa/codecs/snd-aoa-codec-tas.c
+++ b/sound/aoa/codecs/snd-aoa-codec-tas.c
@@ -938,10 +938,10 @@ static int tas_i2c_attach(struct i2c_adapter *adapter)
busnode = pmac_i2c_get_bus_node(bus);
while ((dev = of_get_next_child(busnode, dev)) != NULL) {
- if (device_is_compatible(dev, "tas3004")) {
- u32 *addr;
+ if (of_device_is_compatible(dev, "tas3004")) {
+ const u32 *addr;
printk(KERN_DEBUG PFX "found tas3004\n");
- addr = (u32 *) get_property(dev, "reg", NULL);
+ addr = of_get_property(dev, "reg", NULL);
if (!addr)
continue;
return tas_create(adapter, dev, ((*addr) >> 1) & 0x7f);
@@ -950,9 +950,10 @@ static int tas_i2c_attach(struct i2c_adapter *adapter)
* property that says 'tas3004', they just have a 'deq'
* node without any such property... */
if (strcmp(dev->name, "deq") == 0) {
- u32 *_addr, addr;
+ const u32 *_addr;
+ u32 addr;
printk(KERN_DEBUG PFX "found 'deq' node\n");
- _addr = (u32 *) get_property(dev, "i2c-address", NULL);
+ _addr = of_get_property(dev, "i2c-address", NULL);
if (!_addr)
continue;
addr = ((*_addr) >> 1) & 0x7f;
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
index 2b03bc798bc..805dcbff225 100644
--- a/sound/aoa/core/snd-aoa-gpio-feature.c
+++ b/sound/aoa/core/snd-aoa-gpio-feature.c
@@ -55,7 +55,7 @@ static struct device_node *get_gpio(char *name,
int *gpioactiveptr)
{
struct device_node *np, *gpio;
- u32 *reg;
+ const u32 *reg;
const char *audio_gpio;
*gpioptr = -1;
@@ -71,7 +71,7 @@ static struct device_node *get_gpio(char *name,
if (!gpio)
return NULL;
while ((np = of_get_next_child(gpio, np))) {
- audio_gpio = get_property(np, "audio-gpio", NULL);
+ audio_gpio = of_get_property(np, "audio-gpio", NULL);
if (!audio_gpio)
continue;
if (strcmp(audio_gpio, name) == 0)
@@ -84,7 +84,7 @@ static struct device_node *get_gpio(char *name,
return NULL;
}
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
if (!reg)
return NULL;
@@ -96,7 +96,7 @@ static struct device_node *get_gpio(char *name,
if (*gpioptr < 0x50)
*gpioptr += 0x50;
- reg = (u32 *)get_property(np, "audio-gpio-active-state", NULL);
+ reg = of_get_property(np, "audio-gpio-active-state", NULL);
if (!reg)
/* Apple seems to default to 1, but
* that doesn't seem right at least on most
diff --git a/sound/aoa/fabrics/snd-aoa-fabric-layout.c b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
index 1b94ba6dd27..98806283d1b 100644
--- a/sound/aoa/fabrics/snd-aoa-fabric-layout.c
+++ b/sound/aoa/fabrics/snd-aoa-fabric-layout.c
@@ -724,7 +724,7 @@ static int check_codec(struct aoa_codec *codec,
struct layout_dev *ldev,
struct codec_connect_info *cci)
{
- u32 *ref;
+ const u32 *ref;
char propname[32];
struct codec_connection *cc;
@@ -732,7 +732,7 @@ static int check_codec(struct aoa_codec *codec,
if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
snprintf(propname, sizeof(propname),
"platform-%s-codec-ref", codec->name);
- ref = (u32*)get_property(ldev->sound, propname, NULL);
+ ref = of_get_property(ldev->sound, propname, NULL);
if (!ref) {
printk(KERN_INFO "snd-aoa-fabric-layout: "
"required property %s not present\n", propname);
@@ -946,7 +946,7 @@ static struct aoa_fabric layout_fabric = {
static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
{
struct device_node *sound = NULL;
- unsigned int *layout_id;
+ const unsigned int *layout_id;
struct layout *layout;
struct layout_dev *ldev = NULL;
int err;
@@ -962,7 +962,7 @@ static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
}
if (!sound) return -ENODEV;
- layout_id = (unsigned int *) get_property(sound, "layout-id", NULL);
+ layout_id = of_get_property(sound, "layout-id", NULL);
if (!layout_id)
goto outnodev;
printk(KERN_INFO "snd-aoa-fabric-layout: found bus with layout %d\n",
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 418a98a10c7..8b2e9b905cd 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -61,7 +61,7 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
{
struct soundbus_dev * soundbus_dev;
struct of_device * of;
- char *compat;
+ const char *compat;
int retval = 0, i = 0, length = 0;
int cplen, seen = 0;
@@ -91,7 +91,7 @@ static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
* it's not really legal to split it out with commas. We split it
* up using a number of environment variables instead. */
- compat = (char *) get_property(of->node, "compatible", &cplen);
+ compat = of_get_property(of->node, "compatible", &cplen);
while (compat && cplen > 0) {
int tmp = length;
retval = add_uevent_var(envp, num_envp, &i,
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index e36f6aa448d..0fccdbf5166 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -122,7 +122,7 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
{
struct device_node *parent;
int pindex, rc = -ENXIO;
- u32 *reg;
+ const u32 *reg;
/* Machines with layout 76 and 36 (K2 based) have a weird device
* tree what we need to special case.
@@ -141,7 +141,7 @@ static int i2sbus_get_and_fixup_rsrc(struct device_node *np, int index,
rc = of_address_to_resource(parent, pindex, res);
if (rc)
goto bail;
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = of_get_property(np, "reg", NULL);
if (reg == NULL) {
rc = -ENXIO;
goto bail;
@@ -188,8 +188,8 @@ static int i2sbus_add_dev(struct macio_dev *macio,
}
}
if (i == 1) {
- u32 *layout_id;
- layout_id = (u32*) get_property(sound, "layout-id", NULL);
+ const u32 *layout_id =
+ of_get_property(sound, "layout-id", NULL);
if (layout_id) {
layout = *layout_id;
snprintf(dev->sound.modalias, 32,
@@ -336,8 +336,8 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
}
while ((np = of_get_next_child(dev->ofdev.node, np))) {
- if (device_is_compatible(np, "i2sbus") ||
- device_is_compatible(np, "i2s-modem")) {
+ if (of_device_is_compatible(np, "i2sbus") ||
+ of_device_is_compatible(np, "i2s-modem")) {
got += i2sbus_add_dev(dev, control, np);
}
}
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 28db4be7a16..19c65a8d86a 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -260,7 +260,7 @@ static int pxa2xx_ac97_do_suspend(struct snd_card *card, pm_message_t state)
if (platform_ops && platform_ops->suspend)
platform_ops->suspend(platform_ops->priv);
GCR |= GCR_ACLINK_OFF;
- pxa_set_cken(CKEN2_AC97, 0);
+ pxa_set_cken(CKEN_AC97, 0);
return 0;
}
@@ -269,7 +269,7 @@ static int pxa2xx_ac97_do_resume(struct snd_card *card)
{
pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
- pxa_set_cken(CKEN2_AC97, 1);
+ pxa_set_cken(CKEN_AC97, 1);
if (platform_ops && platform_ops->resume)
platform_ops->resume(platform_ops->priv);
snd_ac97_resume(pxa2xx_ac97_ac97);
@@ -337,7 +337,7 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
/* Use GPIO 113 as AC97 Reset on Bulverde */
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
#endif
- pxa_set_cken(CKEN2_AC97, 1);
+ pxa_set_cken(CKEN_AC97, 1);
ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
if (ret)
@@ -361,10 +361,10 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev)
err:
if (card)
snd_card_free(card);
- if (CKEN & CKEN2_AC97) {
+ if (CKEN & CKEN_AC97) {
GCR |= GCR_ACLINK_OFF;
free_irq(IRQ_AC97, NULL);
- pxa_set_cken(CKEN2_AC97, 0);
+ pxa_set_cken(CKEN_AC97, 0);
}
return ret;
}
@@ -378,7 +378,7 @@ static int __devexit pxa2xx_ac97_remove(struct platform_device *dev)
platform_set_drvdata(dev, NULL);
GCR |= GCR_ACLINK_OFF;
free_irq(IRQ_AC97, NULL);
- pxa_set_cken(CKEN2_AC97, 0);
+ pxa_set_cken(CKEN_AC97, 0);
}
return 0;
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index b2927523d79..829ca38b595 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -146,7 +146,7 @@ config SND_VERBOSE_PROCFS
default y
help
Say Y here to include code for verbose procfs contents (provides
- usefull information to developers when a problem occurs). On the
+ useful information to developers when a problem occurs). On the
other side, it makes the ALSA subsystem larger.
config SND_VERBOSE_PRINTK
diff --git a/sound/core/control.c b/sound/core/control.c
index 86de7258b76..1f1ab9c1b66 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -22,7 +22,6 @@
#include <sound/driver.h>
#include <linux/threads.h>
#include <linux/interrupt.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/time.h>
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 96ffdf18c3f..51ad95b7c89 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -22,7 +22,6 @@
#include <sound/driver.h>
#include <linux/major.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/mutex.h>
diff --git a/sound/core/init.c b/sound/core/init.c
index 4a431e3ea3a..f2fe3573718 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/ctype.h>
-#include <linux/pci.h>
#include <linux/pm.h>
#include <sound/core.h>
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 74a2923eb40..fccad8f0a6b 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -21,7 +21,6 @@
#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/string.h>
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index c4744bb07f4..fc11572c48c 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -28,7 +28,6 @@
#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 3e276fcf333..905234817c8 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -21,7 +21,6 @@
#include <sound/driver.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index d14dcbb6dbc..e470c3c7d61 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -23,7 +23,6 @@
#include <sound/core.h>
#include <linux/major.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/time.h>
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c
index 2eb987308b5..bc099239846 100644
--- a/sound/core/seq/oss/seq_oss.c
+++ b/sound/core/seq/oss/seq_oss.c
@@ -22,7 +22,6 @@
#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <sound/core.h>
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 694efe832b6..b31b5282a2c 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -23,7 +23,6 @@
#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/minors.h>
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 160e40ede72..67520b3c004 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -22,7 +22,6 @@
#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/mutex.h>
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 4c419300305..4b30ae6d8ba 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -5,23 +5,22 @@
#
# Prompt user for primary drivers.
-config OBSOLETE_OSS
+config OSS_OBSOLETE
bool "Obsolete OSS drivers"
depends on SOUND_PRIME
help
This option enables support for obsolete OSS drivers that
- are scheduled for removal in the near future since there
- are ALSA drivers for the same hardware.
+ are scheduled for removal in the near future.
Please contact Adrian Bunk <bunk@stusta.de> if you had to
- say Y here because your soundcard is not properly supported
+ say Y here because your hardware is not properly supported
by ALSA.
If unsure, say N.
config SOUND_BT878
tristate "BT878 audio dma"
- depends on SOUND_PRIME && PCI
+ depends on SOUND_PRIME && PCI && OSS_OBSOLETE
---help---
Audio DMA support for bt878 based grabber boards. As you might have
already noticed, bt878 is listed with two functions in /proc/pci.
@@ -45,22 +44,9 @@ config SOUND_BCM_CS4297A
note that CONFIG_KGDB should not be enabled at the same
time, since it also attempts to use this UART port.
-config SOUND_ES1371
- tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
- depends on SOUND_PRIME && PCI && OBSOLETE_OSS
- help
- Say Y or M if you have a PCI sound card utilizing the Ensoniq
- ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
- your sound card uses an ES1371 without removing your computer's
- cover, use lspci -n and look for the PCI ID 1274:1371. Since
- Ensoniq was bought by Creative Labs, Sound Blaster 64/PCI
- models are either ES1370 or ES1371 based. This driver differs
- slightly from OSS/Free, so PLEASE READ
- <file:Documentation/sound/oss/es1371>.
-
config SOUND_ICH
tristate "Intel ICH (i8xx) audio support"
- depends on SOUND_PRIME && PCI
+ depends on SOUND_PRIME && PCI && OSS_OBSOLETE
help
Support for integral audio in Intel's I/O Controller Hub (ICH)
chipset, as used on the 810/820/840 motherboards.
@@ -362,7 +348,7 @@ config MSND_FIFOSIZE
config SOUND_VIA82CXXX
tristate "VIA 82C686 Audio Codec"
- depends on SOUND_PRIME && PCI
+ depends on SOUND_PRIME && PCI && OSS_OBSOLETE
help
Say Y here to include support for the audio codec found on VIA
82Cxxx-based chips. Typically these are built into a motherboard.
@@ -416,7 +402,7 @@ config SOUND_DMAP
config SOUND_CS4232
tristate "Crystal CS4232 based (PnP) cards"
- depends on SOUND_OSS
+ depends on SOUND_OSS && OSS_OBSOLETE
help
Say Y here if you have a card based on the Crystal CS4232 chip set,
which uses its own Plug and Play protocol.
@@ -735,7 +721,7 @@ config SOUND_WAVEARTIST
config SOUND_TVMIXER
tristate "TV card (bt848) mixer support"
- depends on SOUND_PRIME && I2C && VIDEO_V4L1
+ depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE
help
Support for audio mixer facilities on the BT848 TV frame-grabber
card.
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c
index a339f0c0d51..23018a7c063 100644
--- a/sound/oss/au1550_ac97.c
+++ b/sound/oss/au1550_ac97.c
@@ -47,7 +47,6 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/poll.h>
-#include <linux/pci.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/smp_lock.h>
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
index f813ae9c213..4d5cf05b892 100644
--- a/sound/oss/btaudio.c
+++ b/sound/oss/btaudio.c
@@ -344,7 +344,7 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
memset(&info,0,sizeof(info));
- strlcpy(info.id,"bt878",sizeof(info.id)-1);
+ strlcpy(info.id, "bt878", sizeof(info.id));
strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
if (copy_to_user(argp, &info, sizeof(info)))
return -EFAULT;
diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig
index 18e149f52a8..71b313479f8 100644
--- a/sound/oss/dmasound/Kconfig
+++ b/sound/oss/dmasound/Kconfig
@@ -12,20 +12,6 @@ config DMASOUND_ATARI
want). If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>.
-config DMASOUND_PMAC
- tristate "PowerMac DMA sound support"
- depends on PPC32 && PPC_PMAC && SOUND && I2C && OBSOLETE_OSS
- select DMASOUND
- help
- If you want to use the internal audio of your PowerMac in Linux,
- answer Y to this question. This will provide a Sun-like /dev/audio,
- compatible with the Linux/i386 sound system. Otherwise, say N.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you
- want). If you want to compile it as a module, say M here and read
- <file:Documentation/kbuild/modules.txt>.
-
config DMASOUND_PAULA
tristate "Amiga DMA sound support"
depends on (AMIGA || APUS) && SOUND
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 37773b1deea..8f6388004f4 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -257,7 +257,7 @@ static volatile struct dbdma_cmd *emergency_dbdma_cmd;
/*
* Stuff for restoring after a sleep.
*/
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
struct pmu_sleep_notifier awacs_sleep_notifier = {
awacs_sleep_notify, SLEEP_LEVEL_SOUND,
};
@@ -346,36 +346,42 @@ int gpio_headphone_irq;
int
setup_audio_gpio(const char *name, const char* compatible, int *gpio_addr, int* gpio_pol)
{
+ struct device_node *gpiop;
struct device_node *np;
const u32* pp;
+ int ret = -ENODEV;
- np = find_devices("gpio");
- if (!np)
- return -ENODEV;
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (!gpiop)
+ goto done;
- np = np->child;
+ np = of_get_next_child(gpiop, NULL);
while(np != 0) {
if (name) {
const char *property =
- get_property(np,"audio-gpio",NULL);
+ of_get_property(np,"audio-gpio",NULL);
if (property != 0 && strcmp(property,name) == 0)
break;
- } else if (compatible && device_is_compatible(np, compatible))
+ } else if (compatible && of_device_is_compatible(np, compatible))
break;
- np = np->sibling;
+ np = of_get_next_child(gpiop, np);
}
if (!np)
- return -ENODEV;
- pp = get_property(np, "AAPL,address", NULL);
+ goto done;
+ pp = of_get_property(np, "AAPL,address", NULL);
if (!pp)
- return -ENODEV;
+ goto done;
*gpio_addr = (*pp) & 0x0000ffff;
- pp = get_property(np, "audio-gpio-active-state", NULL);
+ pp = of_get_property(np, "audio-gpio-active-state", NULL);
if (pp)
*gpio_pol = *pp;
else
*gpio_pol = 1;
- return irq_of_parse_and_map(np, 0);
+ ret = irq_of_parse_and_map(np, 0);
+done:
+ of_node_put(np);
+ of_node_put(gpiop);
+ return ret;
}
static inline void
@@ -578,7 +584,7 @@ tas_mixer_ioctl(u_int cmd, u_long arg)
}
static void __init
-tas_init_frame_rates(unsigned int *prop, unsigned int l)
+tas_init_frame_rates(const unsigned int *prop, unsigned int l)
{
int i ;
if (prop) {
@@ -1419,7 +1425,7 @@ load_awacs(void)
* Save state when going to sleep, restore it afterwards.
*/
/* FIXME: sort out disabling/re-enabling of read stuff as well */
-static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
+static void awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
{
unsigned long flags;
@@ -1548,7 +1554,6 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
spin_unlock_irqrestore(&dmasound.lock, flags);
UNLOCK();
}
- return PBOOK_SLEEP_OK;
}
#endif /* CONFIG_PM */
@@ -2553,32 +2558,33 @@ set_model(void)
static struct device_node* __init
get_snd_io_node(void)
{
- struct device_node *np = NULL;
+ struct device_node *np;
/* set up awacs_node for early OF which doesn't have a full set of
* properties on davbus
- */
-
- awacs_node = find_devices("awacs");
+ */
+ awacs_node = of_find_node_by_name(NULL, "awacs");
if (awacs_node)
awacs_revision = AWACS_AWACS;
/* powermac models after 9500 (other than those which use DACA or
* Tumbler) have a node called "davbus".
*/
- np = find_devices("davbus");
+ np = of_find_node_by_name(NULL, "davbus");
/*
* if we didn't find a davbus device, try 'i2s-a' since
* this seems to be what iBooks (& Tumbler) have.
*/
- if (np == NULL)
- np = i2s_node = find_devices("i2s-a");
+ if (np == NULL) {
+ i2s_node = of_find_node_by_name(NULL, "i2s-a");
+ np = of_node_get(i2s_node);
+ }
/* if we didn't find this - perhaps we are on an early model
* which _only_ has an 'awacs' node
*/
if (np == NULL && awacs_node)
- np = awacs_node ;
+ np = of_node_get(awacs_node);
/* if we failed all these return null - this will cause the
* driver to give up...
@@ -2597,9 +2603,9 @@ get_snd_info_node(struct device_node *io)
{
struct device_node *info;
- info = find_devices("sound");
- while (info && info->parent != io)
- info = info->next;
+ for_each_node_by_name(info, "sound")
+ if (info->parent == io)
+ break;
return info;
}
@@ -2614,17 +2620,17 @@ get_codec_type(struct device_node *info)
if (info) {
/* must do awacs first to allow screamer to overide it */
- if (device_is_compatible(info, "awacs"))
+ if (of_device_is_compatible(info, "awacs"))
codec = AWACS_AWACS ;
- if (device_is_compatible(info, "screamer"))
+ if (of_device_is_compatible(info, "screamer"))
codec = AWACS_SCREAMER;
- if (device_is_compatible(info, "burgundy"))
+ if (of_device_is_compatible(info, "burgundy"))
codec = AWACS_BURGUNDY ;
- if (device_is_compatible(info, "daca"))
+ if (of_device_is_compatible(info, "daca"))
codec = AWACS_DACA;
- if (device_is_compatible(info, "tumbler"))
+ if (of_device_is_compatible(info, "tumbler"))
codec = AWACS_TUMBLER;
- if (device_is_compatible(info, "snapper"))
+ if (of_device_is_compatible(info, "snapper"))
codec = AWACS_SNAPPER;
}
return codec ;
@@ -2635,11 +2641,17 @@ get_codec_type(struct device_node *info)
static void __init
get_expansion_type(void)
{
- if (find_devices("perch") != NULL)
+ struct device_node *dn;
+
+ dn = of_find_node_by_name(NULL, "perch");
+ if (dn != NULL)
has_perch = 1;
+ of_node_put(dn);
- if (find_devices("pb-ziva-pc") != NULL)
+ dn = of_find_node_by_name(NULL, "pb-ziva-pc");
+ if (dn != NULL)
has_ziva = 1;
+ of_node_put(dn);
/* need to work out how we deal with iMac SRS module */
}
@@ -2652,7 +2664,7 @@ get_expansion_type(void)
*/
static void __init
-awacs_init_frame_rates(unsigned int *prop, unsigned int l)
+awacs_init_frame_rates(const unsigned int *prop, unsigned int l)
{
int i ;
if (prop) {
@@ -2675,7 +2687,7 @@ awacs_init_frame_rates(unsigned int *prop, unsigned int l)
}
static void __init
-burgundy_init_frame_rates(unsigned int *prop, unsigned int l)
+burgundy_init_frame_rates(const unsigned int *prop, unsigned int l)
{
int temp[9] ;
int i = 0 ;
@@ -2701,7 +2713,7 @@ if (i > 1){
}
static void __init
-daca_init_frame_rates(unsigned int *prop, unsigned int l)
+daca_init_frame_rates(const unsigned int *prop, unsigned int l)
{
int temp[9] ;
int i = 0 ;
@@ -2728,7 +2740,7 @@ if (i > 1){
}
static void __init
-init_frame_rates(unsigned int *prop, unsigned int l)
+init_frame_rates(const unsigned int *prop, unsigned int l)
{
switch (awacs_revision) {
case AWACS_TUMBLER:
@@ -2760,7 +2772,7 @@ set_hw_byteswap(struct device_node *io)
for (mio = io->parent; mio ; mio = mio->parent) {
if (strcmp(mio->name, "mac-io") == 0) {
- if (device_is_compatible(mio, "Keylargo"))
+ if (of_device_is_compatible(mio, "Keylargo"))
kl = 1;
break;
}
@@ -2828,7 +2840,7 @@ int __init dmasound_awacs_init(void)
#ifdef DEBUG_DMASOUND
printk("dmasound_pmac: couldn't find sound io OF node\n");
#endif
- return -ENODEV ;
+ goto no_device;
}
/* find the OF node that tells us about the sound sub-system
@@ -2840,7 +2852,7 @@ printk("dmasound_pmac: couldn't find sound io OF node\n");
#ifdef DEBUG_DMASOUND
printk("dmasound_pmac: couldn't find 'sound' OF node\n");
#endif
- return -ENODEV ;
+ goto no_device;
}
}
@@ -2849,7 +2861,7 @@ printk("dmasound_pmac: couldn't find 'sound' OF node\n");
#ifdef DEBUG_DMASOUND
printk("dmasound_pmac: couldn't find a Codec we can handle\n");
#endif
- return -ENODEV ; /* we don't know this type of h/w */
+ goto no_device; /* we don't know this type of h/w */
}
/* set up perch, ziva, SRS or whatever else we have as sound
@@ -2867,11 +2879,12 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
* machines).
*/
if (awacs_node) {
- io = awacs_node ;
+ of_node_put(io);
+ io = of_node_get(awacs_node);
if (of_get_address(io, 2, NULL, NULL) == NULL) {
printk("dmasound_pmac: can't use %s\n",
io->full_name);
- return -ENODEV;
+ goto no_device;
}
} else
printk("dmasound_pmac: can't use %s\n", io->full_name);
@@ -2882,7 +2895,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
awacs_rsrc[0].end - awacs_rsrc[0].start + 1,
" (IO)") == NULL) {
printk(KERN_ERR "dmasound: can't request IO resource !\n");
- return -ENODEV;
+ goto no_device;
}
if (of_address_to_resource(io, 1, &awacs_rsrc[1]) ||
request_mem_region(awacs_rsrc[1].start,
@@ -2891,7 +2904,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
release_mem_region(awacs_rsrc[0].start,
awacs_rsrc[0].end - awacs_rsrc[0].start + 1);
printk(KERN_ERR "dmasound: can't request Tx DMA resource !\n");
- return -ENODEV;
+ goto no_device;
}
if (of_address_to_resource(io, 2, &awacs_rsrc[2]) ||
request_mem_region(awacs_rsrc[2].start,
@@ -2902,7 +2915,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
release_mem_region(awacs_rsrc[1].start,
awacs_rsrc[1].end - awacs_rsrc[1].start + 1);
printk(KERN_ERR "dmasound: can't request Rx DMA resource !\n");
- return -ENODEV;
+ goto no_device;
}
awacs_beep_dev = input_allocate_device();
@@ -2914,7 +2927,7 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
release_mem_region(awacs_rsrc[2].start,
awacs_rsrc[2].end - awacs_rsrc[2].start + 1);
printk(KERN_ERR "dmasound: can't allocate input device !\n");
- return -ENOMEM;
+ goto no_device;
}
awacs_beep_dev->name = "dmasound beeper";
@@ -2942,7 +2955,8 @@ printk("dmasound_pmac: couldn't find a Codec we can handle\n");
awacs_rx_irq = irq_of_parse_and_map(io, 2);
/* Hack for legacy crap that will be killed someday */
- awacs_node = io;
+ of_node_put(awacs_node);
+ awacs_node = of_node_get(io);
/* if we have an awacs or screamer - probe the chip to make
* sure we have the right revision.
@@ -2973,24 +2987,26 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
*/
if (info) {
- unsigned int *prop, l;
+ const unsigned int *prop;
+ unsigned int l;
sound_device_id = 0;
/* device ID appears post g3 b&w */
- prop = (unsigned int *)get_property(info, "device-id", NULL);
+ prop = of_get_property(info, "device-id", NULL);
if (prop != 0)
sound_device_id = *prop;
/* look for a property saying what sample rates
are available */
- prop = (unsigned int *)get_property(info, "sample-rates", &l);
+ prop = of_get_property(info, "sample-rates", &l);
if (prop == 0)
- prop = (unsigned int *) get_property
- (info, "output-frame-rates", &l);
+ prop = of_get_property(info, "output-frame-rates", &l);
/* if it's there use it to set up frame rates */
init_frame_rates(prop, l) ;
+ of_node_put(info);
+ info = NULL;
}
if (awacs)
@@ -3160,7 +3176,16 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
*/
input_register_device(awacs_beep_dev);
+ of_node_put(io);
+
return dmasound_init();
+
+no_device:
+ of_node_put(info);
+ of_node_put(awacs_node);
+ of_node_put(i2s_node);
+ of_node_put(io);
+ return -ENODEV ;
}
static void __exit dmasound_awacs_cleanup(void)
@@ -3179,6 +3204,8 @@ static void __exit dmasound_awacs_cleanup(void)
}
dmasound_deinit();
+ of_node_put(awacs_node);
+ of_node_put(i2s_node);
}
MODULE_DESCRIPTION("PowerMac built-in audio driver.");
diff --git a/sound/oss/dmasound/tas_common.c b/sound/oss/dmasound/tas_common.c
index 665e85b5562..b295ef68219 100644
--- a/sound/oss/dmasound/tas_common.c
+++ b/sound/oss/dmasound/tas_common.c
@@ -41,7 +41,6 @@
static u8 tas_i2c_address = 0x34;
static struct i2c_client *tas_client;
-static struct device_node* tas_node;
static int tas_attach_adapter(struct i2c_adapter *);
static int tas_detach_client(struct i2c_client *);
@@ -190,17 +189,18 @@ tas_cleanup(void)
int __init
tas_init(int driver_id, const char *driver_name)
{
- u32* paddr;
+ const u32* paddr;
+ struct device_node *tas_node;
printk(KERN_INFO "tas driver [%s])\n", driver_name);
#ifndef CONFIG_I2C_POWERMAC
request_module("i2c-powermac");
#endif
- tas_node = find_devices("deq");
+ tas_node = of_find_node_by_name("deq");
if (tas_node == NULL)
return -ENODEV;
- paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+ paddr = of_get_property(tas_node, "i2c-address", NULL);
if (paddr) {
tas_i2c_address = (*paddr) >> 1;
printk(KERN_INFO "using i2c address: 0x%x from device-tree\n",
@@ -208,6 +208,7 @@ tas_init(int driver_id, const char *driver_name)
} else
printk(KERN_INFO "using i2c address: 0x%x (default)\n",
tas_i2c_address);
+ of_node_put(tas_node);
return i2c_add_driver(&tas_driver);
}
diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h
index dccae3a40e0..9d12b373b4a 100644
--- a/sound/oss/dmasound/tas_ioctl.h
+++ b/sound/oss/dmasound/tas_ioctl.h
@@ -1,7 +1,6 @@
#ifndef _TAS_IOCTL_H_
#define _TAS_IOCTL_H_
-#include <linux/i2c.h>
#include <linux/soundcard.h>
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
index 974dd732b14..593a3aac12c 100644
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -100,7 +100,7 @@
* Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
* 05.01.2001 0.29 Hopefully updates will not be required anymore when Creative bumps
* the CT5880 revision.
- * suggested by Stephan Müller <smueller@chronox.de>
+ * suggested by Stephan Müller <smueller@chronox.de>
* 31.01.2001 0.30 Register/Unregister gameport
* Fix SETTRIGGER non OSS API conformity
* 14.07.2001 0.31 Add list of laptops needing amplifier control
diff --git a/sound/oss/pas2_pcm.c b/sound/oss/pas2_pcm.c
index 4af6aafa3d8..36c3ea62086 100644
--- a/sound/oss/pas2_pcm.c
+++ b/sound/oss/pas2_pcm.c
@@ -85,7 +85,7 @@ static int pcm_set_speed(int arg)
* come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/.
*
* I cleared bit 5 of these values, since that bit controls the master
- * mute flag. (Olav Wölfelschneider)
+ * mute flag. (Olav Wölfelschneider)
*
*/
#if !defined NO_AUTO_FILTER_SET
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
index 7ea9accc2ba..b493660deb3 100644
--- a/sound/oss/sh_dac_audio.c
+++ b/sound/oss/sh_dac_audio.c
@@ -104,7 +104,7 @@ static void dac_audio_set_rate(void)
unsigned long interval;
struct clk *clk;
- clk = clk_get("module_clk");
+ clk = clk_get(NULL, "module_clk");
interval = (clk_get_rate(clk) / 4) / rate;
clk_put(clk);
ctrl_outl(interval, TMU1_TCOR);
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index dcd8d6d2f56..a9c23b2502a 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -44,6 +44,7 @@
#include <linux/smp_lock.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/device.h>
/*
* This ought to be moved into include/asm/dma.h
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index 016b918329a..a8057f25955 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -75,7 +75,6 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/poll.h>
-#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/kernel.h>
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 72a8a0ed36a..3bc1f6e9e4a 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -18,7 +18,7 @@
* Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
* Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support
* Matt Wu <mattwu@acersoftech.com.cn> ALi 5451 Audio Core Support
- * Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
+ * Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
* Muli Ben-Yehuda <mulix@mulix.org>
*
*
@@ -89,7 +89,7 @@
* use set_current_state, properly release resources on failure in
* trident_probe, get rid of check_region
* v0.14.9c
- * August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
+ * August 10 2001 Peter Wächtler <pwaechtler@loewe-komp.de>
* added support for Tvia (formerly Integraphics/IGST) CyberPro5050
* this chip is often found in settop boxes (combined video+audio)
* v0.14.9b
@@ -207,7 +207,6 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include <linux/ac97_codec.h>
#include <linux/bitops.h>
#include <linux/proc_fs.h>
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
index 7ab3a732e18..5d3c0372df3 100644
--- a/sound/oss/via82cxxx_audio.c
+++ b/sound/oss/via82cxxx_audio.c
@@ -32,7 +32,6 @@
#include <linux/poll.h>
#include <linux/soundcard.h>
#include <linux/ac97_codec.h>
-#include <linux/smp_lock.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index a9eec2a2357..3bfb2102fc5 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -1083,7 +1083,7 @@ static void check_volume_resolution(struct snd_ac97 *ac97, int reg, unsigned cha
unsigned short val;
snd_ac97_write(ac97, reg, 0x8080 | cbit[i] | (cbit[i] << 8));
/* Do the read twice due to buffers on some ac97 codecs.
- * e.g. The STAC9704 returns exactly what you wrote the the register
+ * e.g. The STAC9704 returns exactly what you wrote to the register
* if you read it immediately. This causes the detect routine to fail.
*/
val = snd_ac97_read(ac97, reg);
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index b913a1fb8c2..9c3a9c8d1dc 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -62,7 +62,6 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
@@ -71,6 +70,7 @@
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/tlv.h>
+#include <asm/io.h>
#include "ca0106.h"
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c
index 75ca421eb3a..ae80f51d8c4 100644
--- a/sound/pci/ca0106/ca0106_proc.c
+++ b/sound/pci/ca0106/ca0106_proc.c
@@ -64,7 +64,6 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
@@ -73,6 +72,7 @@
#include <sound/ac97_codec.h>
#include <sound/info.h>
#include <sound/asoundef.h>
+#include <asm/io.h>
#include "ca0106.h"
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 89c402770a1..336e77e2600 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -23,7 +23,6 @@
#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
-#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
index 343f51d5311..57e357de150 100644
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c
@@ -24,7 +24,6 @@
#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
-#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 1589d2f2917..1e5ff0cd370 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -23,7 +23,6 @@
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index 17df4d0fe13..e313e685f16 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -23,7 +23,6 @@
#include <sound/driver.h>
#include <linux/init.h>
-#include <linux/pci.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 7333f275dec..831469d3a92 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index ed5e45e3596..6fcda9bcf0c 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 4c839b03172..2b11ac8689b 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -35,7 +35,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/pci.h>
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
diff --git a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
index e65d669af63..e47861ccd6e 100644
--- a/sound/pci/ice1712/delta.h
+++ b/sound/pci/ice1712/delta.h
@@ -63,7 +63,7 @@ extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
/* look to CS8414 datasheet */
#define ICE1712_DELTA_SPDIF_OUT_STAT_CLOCK 0x04
/* S/PDIF output status clock */
- /* (writting on rising edge - 0->1) */
+ /* (writing on rising edge - 0->1) */
/* all except Delta44 */
/* look to CS8404A datasheet */
#define ICE1712_DELTA_SPDIF_OUT_STAT_DATA 0x08
@@ -100,7 +100,7 @@ extern const struct snd_ice1712_card_info snd_ice1712_delta_cards[];
/* AKM4524 serial data */
#define ICE1712_DELTA_CODEC_SERIAL_CLOCK 0x20
/* AKM4524 serial clock */
- /* (writting on rising edge - 0->1 */
+ /* (writing on rising edge - 0->1 */
#define ICE1712_DELTA_CODEC_CHIP_A 0x40
#define ICE1712_DELTA_CODEC_CHIP_B 0x80
/* 1 - select chip A or B */
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 21386da3bc8..ac007cec087 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -472,7 +472,7 @@ static int snd_mixart_prepare(struct snd_pcm_substream *subs)
struct snd_mixart *chip = snd_pcm_substream_chip(subs);
struct mixart_stream *stream = subs->runtime->private_data;
- /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
+ /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */
snd_printdd("snd_mixart_prepare\n");
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index c64af55865d..5a2bef44a2f 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -816,6 +816,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
if (chip->pdev)
pci_dev_put(chip->pdev);
+ of_node_put(chip->node);
kfree(chip);
return 0;
}
@@ -842,7 +843,7 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
/* if seems that Keylargo can't byte-swap */
for (mio = chip->node->parent; mio; mio = mio->parent) {
if (strcmp(mio->name, "mac-io") == 0) {
- if (device_is_compatible(mio, "Keylargo"))
+ if (of_device_is_compatible(mio, "Keylargo"))
chip->can_byte_swap = 0;
break;
}
@@ -863,8 +864,10 @@ static void __init detect_byte_swap(struct snd_pmac *chip)
*/
static int __init snd_pmac_detect(struct snd_pmac *chip)
{
- struct device_node *sound = NULL;
- unsigned int *prop, l;
+ struct device_node *sound;
+ struct device_node *dn;
+ const unsigned int *prop;
+ unsigned int l;
struct macio_chip* macio;
if (!machine_is(powermac))
@@ -890,25 +893,24 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
else if (machine_is_compatible("PowerBook1,1")
|| machine_is_compatible("AAPL,PowerBook1998"))
chip->is_pbook_G3 = 1;
- chip->node = find_devices("awacs");
- if (chip->node)
- sound = chip->node;
+ chip->node = of_find_node_by_name(NULL, "awacs");
+ sound = of_node_get(chip->node);
/*
* powermac G3 models have a node called "davbus"
* with a child called "sound".
*/
if (!chip->node)
- chip->node = find_devices("davbus");
+ chip->node = of_find_node_by_name(NULL, "davbus");
/*
* if we didn't find a davbus device, try 'i2s-a' since
* this seems to be what iBooks have
*/
if (! chip->node) {
- chip->node = find_devices("i2s-a");
+ chip->node = of_find_node_by_name(NULL, "i2s-a");
if (chip->node && chip->node->parent &&
chip->node->parent->parent) {
- if (device_is_compatible(chip->node->parent->parent,
+ if (of_device_is_compatible(chip->node->parent->parent,
"K2-Keylargo"))
chip->is_k2 = 1;
}
@@ -917,41 +919,44 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
return -ENODEV;
if (!sound) {
- sound = find_devices("sound");
+ sound = of_find_node_by_name(NULL, "sound");
while (sound && sound->parent != chip->node)
- sound = sound->next;
+ sound = of_find_node_by_name(sound, "sound");
}
- if (! sound)
+ if (! sound) {
+ of_node_put(chip->node);
return -ENODEV;
- prop = (unsigned int *) get_property(sound, "sub-frame", NULL);
+ }
+ prop = of_get_property(sound, "sub-frame", NULL);
if (prop && *prop < 16)
chip->subframe = *prop;
- prop = (unsigned int *) get_property(sound, "layout-id", NULL);
+ prop = of_get_property(sound, "layout-id", NULL);
if (prop) {
/* partly deprecate snd-powermac, for those machines
* that have a layout-id property for now */
printk(KERN_INFO "snd-powermac no longer handles any "
"machines with a layout-id property "
"in the device-tree, use snd-aoa.\n");
+ of_node_put(chip->node);
return -ENODEV;
}
/* This should be verified on older screamers */
- if (device_is_compatible(sound, "screamer")) {
+ if (of_device_is_compatible(sound, "screamer")) {
chip->model = PMAC_SCREAMER;
// chip->can_byte_swap = 0; /* FIXME: check this */
}
- if (device_is_compatible(sound, "burgundy")) {
+ if (of_device_is_compatible(sound, "burgundy")) {
chip->model = PMAC_BURGUNDY;
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
- if (device_is_compatible(sound, "daca")) {
+ if (of_device_is_compatible(sound, "daca")) {
chip->model = PMAC_DACA;
chip->can_capture = 0; /* no capture */
chip->can_duplex = 0;
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
- if (device_is_compatible(sound, "tumbler")) {
+ if (of_device_is_compatible(sound, "tumbler")) {
chip->model = PMAC_TUMBLER;
chip->can_capture = 0; /* no capture */
chip->can_duplex = 0;
@@ -960,17 +965,19 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
chip->freq_table = tumbler_freqs;
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
- if (device_is_compatible(sound, "snapper")) {
+ if (of_device_is_compatible(sound, "snapper")) {
chip->model = PMAC_SNAPPER;
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
chip->freq_table = tumbler_freqs;
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
- prop = (unsigned int *)get_property(sound, "device-id", NULL);
+ prop = of_get_property(sound, "device-id", NULL);
if (prop)
chip->device_id = *prop;
- chip->has_iic = (find_devices("perch") != NULL);
+ dn = of_find_node_by_name(NULL, "perch");
+ chip->has_iic = (dn != NULL);
+ of_node_put(dn);
/* We need the PCI device for DMA allocations, let's use a crude method
* for now ...
@@ -997,10 +1004,9 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
/* look for a property saying what sample rates
are available */
- prop = (unsigned int *) get_property(sound, "sample-rates", &l);
+ prop = of_get_property(sound, "sample-rates", &l);
if (! prop)
- prop = (unsigned int *) get_property(sound,
- "output-frame-rates", &l);
+ prop = of_get_property(sound, "output-frame-rates", &l);
if (prop) {
int i;
chip->freqs_ok = 0;
@@ -1021,6 +1027,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
chip->freqs_ok = 1;
}
+ of_node_put(sound);
return 0;
}
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 8f074c7936e..5821cdd0bec 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1031,32 +1031,40 @@ static irqreturn_t headphone_intr(int irq, void *devid)
/* look for audio-gpio device */
static struct device_node *find_audio_device(const char *name)
{
+ struct device_node *gpiop;
struct device_node *np;
- if (! (np = find_devices("gpio")))
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (! gpiop)
return NULL;
- for (np = np->child; np; np = np->sibling) {
- const char *property = get_property(np, "audio-gpio", NULL);
+ for (np = of_get_next_child(gpiop, NULL); np;
+ np = of_get_next_child(gpiop, np)) {
+ const char *property = of_get_property(np, "audio-gpio", NULL);
if (property && strcmp(property, name) == 0)
- return np;
+ break;
}
- return NULL;
+ of_node_put(gpiop);
+ return np;
}
/* look for audio-gpio device */
static struct device_node *find_compatible_audio_device(const char *name)
{
+ struct device_node *gpiop;
struct device_node *np;
- if (! (np = find_devices("gpio")))
+ gpiop = of_find_node_by_name(NULL, "gpio");
+ if (!gpiop)
return NULL;
- for (np = np->child; np; np = np->sibling) {
- if (device_is_compatible(np, name))
- return np;
+ for (np = of_get_next_child(gpiop, NULL); np;
+ np = of_get_next_child(gpiop, np)) {
+ if (of_device_is_compatible(np, name))
+ break;
}
- return NULL;
+ of_node_put(gpiop);
+ return np;
}
/* find an audio device and get its address */
@@ -1066,6 +1074,7 @@ static long tumbler_find_device(const char *device, const char *platform,
struct device_node *node;
const u32 *base;
u32 addr;
+ long ret;
if (is_compatible)
node = find_compatible_audio_device(device);
@@ -1077,12 +1086,13 @@ static long tumbler_find_device(const char *device, const char *platform,
return -ENODEV;
}
- base = get_property(node, "AAPL,address", NULL);
+ base = of_get_property(node, "AAPL,address", NULL);
if (! base) {
- base = get_property(node, "reg", NULL);
+ base = of_get_property(node, "reg", NULL);
if (!base) {
DBG("(E) cannot find address for device %s !\n", device);
snd_printd("cannot find address for device %s\n", device);
+ of_node_put(node);
return -ENODEV;
}
addr = *base;
@@ -1093,7 +1103,7 @@ static long tumbler_find_device(const char *device, const char *platform,
gp->addr = addr & 0x0000ffff;
/* Try to find the active state, default to 0 ! */
- base = get_property(node, "audio-gpio-active-state", NULL);
+ base = of_get_property(node, "audio-gpio-active-state", NULL);
if (base) {
gp->active_state = *base;
gp->active_val = (*base) ? 0x5 : 0x4;
@@ -1108,7 +1118,7 @@ static long tumbler_find_device(const char *device, const char *platform,
* as we don't yet have an interpreter for these things
*/
if (platform)
- prop = get_property(node, platform, NULL);
+ prop = of_get_property(node, platform, NULL);
if (prop) {
if (prop[3] == 0x9 && prop[4] == 0x9) {
gp->active_val = 0xd;
@@ -1124,7 +1134,9 @@ static long tumbler_find_device(const char *device, const char *platform,
DBG("(I) GPIO device %s found, offset: %x, active state: %d !\n",
device, gp->addr, gp->active_state);
- return irq_of_parse_and_map(node, 0);
+ ret = irq_of_parse_and_map(node, 0);
+ of_node_put(node);
+ return ret;
}
/* reset audio */
@@ -1310,7 +1322,7 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
{
int i, err;
struct pmac_tumbler *mix;
- u32 *paddr;
+ const u32 *paddr;
struct device_node *tas_node, *np;
char *chipname;
@@ -1331,9 +1343,9 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
for (np = chip->node->child; np; np = np->sibling) {
if (!strcmp(np->name, "sound")) {
- if (get_property(np, "has-anded-reset", NULL))
+ if (of_get_property(np, "has-anded-reset", NULL))
mix->anded_reset = 1;
- if (get_property(np, "layout-id", NULL))
+ if (of_get_property(np, "layout-id", NULL))
mix->reset_on_sleep = 0;
break;
}
@@ -1342,19 +1354,20 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip)
return err;
/* set up TAS */
- tas_node = find_devices("deq");
+ tas_node = of_find_node_by_name(NULL, "deq");
if (tas_node == NULL)
- tas_node = find_devices("codec");
+ tas_node = of_find_node_by_name(NULL, "codec");
if (tas_node == NULL)
return -ENODEV;
- paddr = (u32 *)get_property(tas_node, "i2c-address", NULL);
+ paddr = of_get_property(tas_node, "i2c-address", NULL);
if (paddr == NULL)
- paddr = (u32 *)get_property(tas_node, "reg", NULL);
+ paddr = of_get_property(tas_node, "reg", NULL);
if (paddr)
mix->i2c.addr = (*paddr) >> 1;
else
mix->i2c.addr = TAS_I2C_ADDR;
+ of_node_put(tas_node);
DBG("(I) TAS i2c address is: %x\n", mix->i2c.addr);
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 1bbbeff84ef..b222755763e 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -256,7 +256,7 @@ static int pxa2xx_ac97_suspend(struct platform_device *pdev,
struct snd_soc_cpu_dai *dai)
{
GCR |= GCR_ACLINK_OFF;
- pxa_set_cken(CKEN2_AC97, 0);
+ pxa_set_cken(CKEN_AC97, 0);
return 0;
}
@@ -271,7 +271,7 @@ static int pxa2xx_ac97_resume(struct platform_device *pdev,
/* Use GPIO 113 as AC97 Reset on Bulverde */
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
#endif
- pxa_set_cken(CKEN2_AC97, 1);
+ pxa_set_cken(CKEN_AC97, 1);
return 0;
}
@@ -296,14 +296,14 @@ static int pxa2xx_ac97_probe(struct platform_device *pdev)
/* Use GPIO 113 as AC97 Reset on Bulverde */
pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
#endif
- pxa_set_cken(CKEN2_AC97, 1);
+ pxa_set_cken(CKEN_AC97, 1);
return 0;
err:
- if (CKEN & CKEN2_AC97) {
+ if (CKEN & CKEN_AC97) {
GCR |= GCR_ACLINK_OFF;
free_irq(IRQ_AC97, NULL);
- pxa_set_cken(CKEN2_AC97, 0);
+ pxa_set_cken(CKEN_AC97, 0);
}
return ret;
}
@@ -312,7 +312,7 @@ static void pxa2xx_ac97_remove(struct platform_device *pdev)
{
GCR |= GCR_ACLINK_OFF;
free_irq(IRQ_AC97, NULL);
- pxa_set_cken(CKEN2_AC97, 0);
+ pxa_set_cken(CKEN_AC97, 0);
}
static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/pxa/pxa2xx-ac97.h b/sound/soc/pxa/pxa2xx-ac97.h
index 4c4b882316a..b8ccfee095c 100644
--- a/sound/soc/pxa/pxa2xx-ac97.h
+++ b/sound/soc/pxa/pxa2xx-ac97.h
@@ -1,5 +1,5 @@
/*
- * linux/sound/arm/pxa2xx-ac97.h
+ * linux/sound/soc/pxa/pxa2xx-ac97.h
*
* 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
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 575a6137c04..50c5c83f67d 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -149,7 +149,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
- pxa_set_cken(CKEN8_I2S, 1);
+ pxa_set_cken(CKEN_I2S, 1);
pxa_i2s_wait();
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -234,7 +234,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
SACR0 &= ~SACR0_ENB;
pxa_i2s_wait();
- pxa_set_cken(CKEN8_I2S, 0);
+ pxa_set_cken(CKEN_I2S, 0);
}
}
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
index a2484f0881f..4435bd9f884 100644
--- a/sound/soc/pxa/pxa2xx-i2s.h
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -1,5 +1,5 @@
/*
- * linux/sound/arm/pxa2xx-i2s.h
+ * linux/sound/soc/pxa/pxa2xx-i2s.h
*
* 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
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 25a2a733300..e07085a7cfc 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -673,7 +673,7 @@ static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len)
}
/*
- * Send prepared cmd string. It works by writting a JUMP cmd into
+ * Send prepared cmd string. It works by writing a JUMP cmd into
* the last WAIT cmd and force DBRI to reread the cmd.
* The JUMP cmd points to the new cmd string.
* It also releases the cmdlock spinlock.
diff --git a/usr/Kconfig b/usr/Kconfig
index 07727f3c7ce..86cecb59dd0 100644
--- a/usr/Kconfig
+++ b/usr/Kconfig
@@ -17,7 +17,7 @@ config INITRAMFS_SOURCE
When multiple directories and files are specified then the
initramfs image will be the aggregate of all of them.
- See <file:Documentation/early-userspace/README for more details.
+ See <file:Documentation/early-userspace/README> for more details.
If you are not sure, leave it blank.